Merge commit 'AU_LINUX_ANDROID_ICS.04.00.04.00.126' into msm-3.4

AU_LINUX_ANDROID_ICS.04.00.04.00.126 from msm-3.0.
First parent is from google/android-3.4.

* commit 'AU_LINUX_ANDROID_ICS.04.00.04.00.126': (8712 commits)
  PRNG: Device tree entry for qrng device.
  vidc:1080p: Set video core timeout value for Thumbnail mode
  msm: sps: improve the debugging support in SPS driver
  board-8064 msm: Overlap secure and non secure video firmware heaps.
  msm: clock: Add handoff ops for 7x30 and copper XO clocks
  msm_fb: display: Wait for external vsync before DTV IOMMU unmap
  msm: Fix ciruclar dependency in debug UART settings
  msm: gdsc: Add GDSC regulator driver for msm-copper
  defconfig: Enable Mobicore Driver.
  mobicore: Add mobicore driver.
  mobicore: rename variable to lower case.
  mobicore: rename folder.
  mobicore: add makefiles
  mobicore: initial import of kernel driver
  ASoC: msm: Add SLIMBUS_2_RX CPU DAI
  board-8064-gpio: Update FUNC for EPM SPI CS
  msm_fb: display: Remove chicken bit config during video playback
  mmc: msm_sdcc: enable the sanitize capability
  msm-fb: display: lm2 writeback support on mpq platfroms
  msm_fb: display: Disable LVDS phy & pll during panel off
  ...

Signed-off-by: Steve Muckle <smuckle@codeaurora.org>
diff --git a/arch/Kconfig b/arch/Kconfig
index 684eb5a..bba59d1 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -166,6 +166,13 @@
 	bool
 	depends on PERF_EVENTS
 
+config HAVE_HW_BRKPT_RESERVED_RW_ACCESS
+	bool
+	depends on HAVE_HW_BREAKPOINT
+	help
+	  Some of the hardware might not have r/w access beyond a certain number
+	  of breakpoint register access.
+
 config HAVE_MIXED_BREAKPOINTS_REGS
 	bool
 	depends on HAVE_HW_BREAKPOINT
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index c03eb3c..5e1cd06 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -27,7 +27,7 @@
 	select HAVE_PERF_EVENTS
 	select PERF_USE_VMALLOC
 	select HAVE_REGS_AND_STACK_ACCESS_API
-	select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7))
+	#select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7))
 	select HAVE_C_RECORDMCOUNT
 	select HAVE_GENERIC_HARDIRQS
 	select GENERIC_IRQ_SHOW
@@ -136,9 +136,18 @@
 
 config GENERIC_LOCKBREAK
 	bool
-	default y
+	default y if !ARM_TICKET_LOCKS
 	depends on SMP && PREEMPT
 
+config ARM_TICKET_LOCKS
+	bool
+	help
+	  Enable ticket locks, which help preserve fairness among
+	  contended locks and prevent livelock in multicore systems.
+	  Say 'y' if system stability is important.
+	default y if ARCH_MSM_SCORPIONMP || ARCH_MSM_KRAITMP
+	depends on SMP
+
 config RWSEM_GENERIC_SPINLOCK
 	bool
 	default y
@@ -732,6 +741,14 @@
 	select GENERIC_CLOCKEVENTS
 	select ARCH_REQUIRE_GPIOLIB
 	select CLKDEV_LOOKUP
+	select ARCH_HAS_CPUFREQ
+	select GENERIC_GPIO
+	select GENERIC_TIME
+	select GENERIC_ALLOCATOR
+	select HAVE_SCHED_CLOCK
+	select HAVE_CLK_PREPARE
+	select NEED_MACH_MEMORY_H
+	select NEED_MACH_IO_H
 	help
 	  Support for Qualcomm MSM/QSD based systems.  This runs on the
 	  apps processor of the MSM/QSD and depends on a shared memory
@@ -1158,6 +1175,15 @@
 	default 16 if ARCH_EP93XX
 	default 8
 
+config RESERVE_FIRST_PAGE
+	bool
+	default n
+	help
+	  Reserve the first page at PHYS_OFFSET. The first
+	  physical page is used by many platforms for warm
+	  boot operations. Reserve this page so that it is
+	  not allocated by the kernel.
+
 config IWMMXT
 	bool "Enable iWMMXt support"
 	depends on CPU_XSCALE || CPU_XSC3 || CPU_MOHAWK || CPU_PJ4
@@ -1405,6 +1431,29 @@
 	  on systems with an outer cache, the store buffer is drained
 	  explicitly.
 
+config PL310_ERRATA_727915
+	bool "Background Clean & Invalidate by Way operation can cause data corruption"
+	depends on CACHE_L2X0
+	help
+	  PL310 implements the Clean & Invalidate by Way L2 cache maintenance
+	  operation (offset 0x7FC). This operation runs in background so that
+	  PL310 can handle normal accesses while it is in progress. Under very
+	  rare circumstances, due to this erratum, write data can be lost when
+	  PL310 treats a cacheable write transaction during a Clean &
+	  Invalidate by Way operation.
+
+config KSAPI
+        tristate "KSAPI support (EXPERIMENTAL)"
+	depends on ARCH_MSM_SCORPION || ARCH_MSM_KRAIT
+        default n
+        help
+          KSAPI: Performance monitoring tool for linux.
+          KSAPI records performance statistics for Snapdragon linux platform.
+          It uses the /proc FS as a means to exchange configuration data and
+          counter statistics. It can monitor the counter statistics for
+          Scorpion processor supported hardware performance counters on a per
+          thread basis or AXI counters on an overall system basis.
+
 endmenu
 
 source "arch/arm/common/Kconfig"
@@ -1469,6 +1518,32 @@
 
 source "drivers/pcmcia/Kconfig"
 
+config ARM_ERRATA_764369
+	bool "ARM errata: Data cache line maintenance operation by MVA may not succeed"
+	depends on CPU_V7 && SMP
+	help
+	  This option enables the workaround for erratum 764369
+	  affecting Cortex-A9 MPCore with two or more processors (all
+	  current revisions). Under certain timing circumstances, a data
+	  cache line maintenance operation by MVA targeting an Inner
+	  Shareable memory region may fail to proceed up to either the
+	  Point of Coherency or to the Point of Unification of the
+	  system. This workaround adds a DSB instruction before the
+	  relevant cache maintenance functions and sets a specific bit
+	  in the diagnostic control register of the SCU.
+
+config PL310_ERRATA_769419
+	bool "PL310 errata: no automatic Store Buffer drain"
+	depends on CACHE_L2X0
+	help
+	  On revisions of the PL310 prior to r3p2, the Store Buffer does
+	  not automatically drain. This can cause normal, non-cacheable
+	  writes to be retained when the memory system is idle, leading
+	  to suboptimal I/O performance for drivers using coherent DMA.
+	  This option adds a write barrier to the cpu_idle loop so that,
+	  on systems with an outer cache, the store buffer is drained
+	  explicitly.
+
 endmenu
 
 menu "Kernel Features"
@@ -1491,7 +1566,7 @@
 	depends on HAVE_SMP
 	depends on MMU
 	select USE_GENERIC_SMP_HELPERS
-	select HAVE_ARM_SCU if !ARCH_MSM_SCORPIONMP
+	select HAVE_ARM_SCU
 	help
 	  This enables support for systems with more than one CPU. If you have
 	  a system with only one CPU, like most personal computers, say N. If
@@ -1552,6 +1627,13 @@
 	help
 	  This option enables support for the ARM system coherency unit
 
+config ARM_ARCH_TIMER
+	bool "Architected timer support"
+	depends on CPU_V7
+	select TICK_ONESHOT
+	help
+	  This option enables support for the ARM architected timer
+
 config HAVE_ARM_TWD
 	bool
 	depends on SMP
@@ -1599,7 +1681,7 @@
 	bool "Use local timer interrupts"
 	depends on SMP
 	default y
-	select HAVE_ARM_TWD if (!ARCH_MSM_SCORPIONMP && !EXYNOS4_MCT)
+	select HAVE_ARM_TWD if (!MSM_SMP && !EXYNOS4_MCT)
 	help
 	  Enable support for local timers on SMP platforms, rather then the
 	  legacy IPI broadcast method.  Local timers allows the system
@@ -1751,8 +1833,44 @@
 	  Enable hardware performance counter support for perf events. If
 	  disabled, perf events will use software events only.
 
+config VMALLOC_RESERVE
+	hex "Reserved vmalloc space"
+	default 0x08000000
+	depends on MMU
+	help
+	  Reserved vmalloc space if not specified on the kernel commandline.
+
 source "mm/Kconfig"
 
+config ARCH_MEMORY_PROBE
+	def_bool n
+
+config ARCH_MEMORY_REMOVE
+	def_bool n
+
+config ARCH_POPULATES_NODE_MAP
+	def_bool n
+
+config ENABLE_DMM
+	def_bool n
+
+config FIX_MOVABLE_ZONE
+	def_bool n
+
+config DONT_MAP_HOLE_AFTER_MEMBANK0
+	def_bool n
+	depends on SPARSEMEM
+
+config ARCH_ENABLE_MEMORY_HOTPLUG
+	def_bool n
+
+config ARCH_ENABLE_MEMORY_HOTREMOVE
+	def_bool n
+
+config HOLES_IN_ZONE
+	def_bool n
+	depends on SPARSEMEM
+
 config FORCE_MAX_ZONEORDER
 	int "Maximum zone order" if ARCH_SHMOBILE
 	range 11 64 if ARCH_SHMOBILE
@@ -1894,6 +2012,17 @@
 	  released if it failed to be acquired, which will cause all the
 	  pending messages to be flushed.
 
+config CP_ACCESS
+	tristate "CP register access tool"
+	default m
+	help
+	  Provide support for Coprocessor register access using /sys
+	  interface. Read and write to CP registers from userspace
+	  through sysfs interface. A sys file (cp_rw) will be created under
+	  /sys/devices/system/cpaccess/cpaccess0.
+
+	  If unsure, say N.
+
 endmenu
 
 menu "Boot options"
@@ -2201,6 +2330,14 @@
 
 endmenu
 
+config CPU_FREQ_MSM
+        bool
+        depends on CPU_FREQ && ARCH_MSM
+        default y
+        help
+          This enables the CPUFreq driver for Qualcomm CPUs.
+          If in doubt, say Y.
+
 menu "Floating point emulation"
 
 comment "At least one emulation must be selected"
@@ -2290,7 +2427,7 @@
 source "kernel/power/Kconfig"
 
 config ARCH_SUSPEND_POSSIBLE
-	depends on !ARCH_S5PC100
+	depends on !ARCH_S5PC100 && !ARCH_FSM9XXX
 	depends on CPU_ARM920T || CPU_ARM926T || CPU_SA1100 || \
 		CPU_V6 || CPU_V6K || CPU_V7 || CPU_XSC3 || CPU_XSCALE
 	def_bool y
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 037bd5a..ed18cae 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -208,43 +208,6 @@
 		  Say Y here if you want kernel low-level debugging support
 		  on i.MX6Q UART4.
 
-	config DEBUG_MSM_UART1
-		bool "Kernel low-level debugging messages via MSM UART1"
-		depends on ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50
-		help
-		  Say Y here if you want the debug print routines to direct
-		  their output to the first serial port on MSM devices.
-
-	config DEBUG_MSM_UART2
-		bool "Kernel low-level debugging messages via MSM UART2"
-		depends on ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50
-		help
-		  Say Y here if you want the debug print routines to direct
-		  their output to the second serial port on MSM devices.
-
-	config DEBUG_MSM_UART3
-		bool "Kernel low-level debugging messages via MSM UART3"
-		depends on ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50
-		help
-		  Say Y here if you want the debug print routines to direct
-		  their output to the third serial port on MSM devices.
-
-	config DEBUG_MSM8660_UART
-		bool "Kernel low-level debugging messages via MSM 8660 UART"
-		depends on ARCH_MSM8X60
-		select MSM_HAS_DEBUG_UART_HS
-		help
-		  Say Y here if you want the debug print routines to direct
-		  their output to the serial port on MSM 8660 devices.
-
-	config DEBUG_MSM8960_UART
-		bool "Kernel low-level debugging messages via MSM 8960 UART"
-		depends on ARCH_MSM8960
-		select MSM_HAS_DEBUG_UART_HS
-		help
-		  Say Y here if you want the debug print routines to direct
-		  their output to the serial port on MSM 8960 devices.
-
 	config DEBUG_REALVIEW_STD_PORT
 		bool "RealView Default UART"
 		depends on ARCH_REALVIEW
@@ -353,4 +316,13 @@
 	help
 	  Perform tests of kprobes API and instruction set simulation.
 
+config PID_IN_CONTEXTIDR
+	bool "Write the current PID to the CONTEXTIDR register"
+	depends on CPU_COPY_V6
+	help
+	  Enabling this option causes the kernel to write the current PID to
+	  the PROCID field of the CONTEXTIDR register, at the expense of some
+	  additional instructions during context switch. Say Y here only if you
+	  are planning to use hardware trace tools with this kernel.
+
 endmenu
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 047a207..81b5dc9 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -128,9 +128,6 @@
 ifeq ($(CONFIG_ARCH_SA1100),y)
 textofs-$(CONFIG_SA1111) := 0x00208000
 endif
-textofs-$(CONFIG_ARCH_MSM7X30) := 0x00208000
-textofs-$(CONFIG_ARCH_MSM8X60) := 0x00208000
-textofs-$(CONFIG_ARCH_MSM8960) := 0x00208000
 
 # Machine directory name.  This list is sorted alphanumerically
 # by CONFIG_* macro name.
@@ -257,6 +254,7 @@
 core-y				+= $(machdirs) $(platdirs)
 
 drivers-$(CONFIG_OPROFILE)      += arch/arm/oprofile/
+core-y				+= arch/arm/perfmon/
 
 libs-y				:= arch/arm/lib/ $(libs-y)
 
diff --git a/arch/arm/boot/dts/msm-gdsc.dtsi b/arch/arm/boot/dts/msm-gdsc.dtsi
new file mode 100644
index 0000000..f83fe76
--- /dev/null
+++ b/arch/arm/boot/dts/msm-gdsc.dtsi
@@ -0,0 +1,58 @@
+/*
+ * 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/ "skeleton.dtsi"
+
+/ {
+	gdsc_venus: qcom,gdsc@fd8c1024 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_venus";
+		reg = <0xfd8c1024 0x4>;
+	};
+
+	gdsc_mdss: qcom,gdsc@fd8c2304 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_mdss";
+		reg = <0xfd8c2304 0x4>;
+	};
+
+	gdsc_jpeg: qcom,gdsc@fd8c35a4 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_jpeg";
+		reg = <0xfd8c35a4 0x4>;
+	};
+
+	gdsc_vfe: qcom,gdsc@fd8c36a4 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_vfe";
+		reg = <0xfd8c36a4 0x4>;
+	};
+
+	gdsc_oxili_gx: qcom,gdsc@fd8c4024 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_oxili_gx";
+		reg = <0xfd8c4024 0x4>;
+	};
+
+	gdsc_oxili_cx: qcom,gdsc@fd8c4034 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_oxili_cx";
+		reg = <0xfd8c4034 0x4>;
+	};
+
+	gdsc_usb_hsic: qcom,gdsc@fc400404 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_usb_hsic";
+		reg = <0xfc400404 0x4>;
+	};
+};
diff --git a/arch/arm/boot/dts/msm-pm8841.dtsi b/arch/arm/boot/dts/msm-pm8841.dtsi
new file mode 100644
index 0000000..523c9b0
--- /dev/null
+++ b/arch/arm/boot/dts/msm-pm8841.dtsi
@@ -0,0 +1,187 @@
+/* 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.
+ */
+
+/ {
+	qcom,spmi@fc4c0000 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		interrupt-controller;
+		#interrupt-cells = <3>;
+
+		qcom,pm8841@5 {
+			spmi-slave-container;
+			reg = <0x5>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			regulator@1400 {
+				regulator-name = "8841_s1";
+				spmi-dev-container;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				compatible = "qcom,qpnp-regulator";
+				reg = <0x1400 0x300>;
+				status = "disabled";
+
+				qcom,ctl@1400 {
+					reg = <0x1400 0x100>;
+				};
+				qcom,ps@1500 {
+					reg = <0x1500 0x100>;
+				};
+				qcom,freq@1600 {
+					reg = <0x1600 0x100>;
+				};
+			};
+
+			regulator@1700 {
+				regulator-name = "8841_s2";
+				spmi-dev-container;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				compatible = "qcom,qpnp-regulator";
+				reg = <0x1700 0x300>;
+				status = "disabled";
+
+				qcom,ctl@1700 {
+					reg = <0x1700 0x100>;
+				};
+				qcom,ps@1800 {
+					reg = <0x1800 0x100>;
+				};
+				qcom,freq@1900 {
+					reg = <0x1900 0x100>;
+				};
+			};
+
+			regulator@1a00 {
+				regulator-name = "8841_s3";
+				spmi-dev-container;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				compatible = "qcom,qpnp-regulator";
+				reg = <0x1a00 0x300>;
+				status = "disabled";
+
+				qcom,ctl@1a00 {
+					reg = <0x1a00 0x100>;
+				};
+				qcom,ps@1b00 {
+					reg = <0x1b00 0x100>;
+				};
+				qcom,freq@1c00 {
+					reg = <0x1c00 0x100>;
+				};
+			};
+
+			regulator@1d00 {
+				regulator-name = "8841_s4";
+				spmi-dev-container;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				compatible = "qcom,qpnp-regulator";
+				reg = <0x1d00 0x300>;
+				status = "disabled";
+
+				qcom,ctl@1d00 {
+					reg = <0x1d00 0x100>;
+				};
+				qcom,ps@1e00 {
+					reg = <0x1e00 0x100>;
+				};
+				qcom,freq@1f00 {
+					reg = <0x1f00 0x100>;
+				};
+			};
+
+			regulator@2000 {
+				regulator-name = "8841_s5";
+				spmi-dev-container;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				compatible = "qcom,qpnp-regulator";
+				reg = <0x2000 0x300>;
+				status = "disabled";
+
+				qcom,ctl@0 {
+					reg = <0x2000 0x100>;
+				};
+				qcom,ps@100 {
+					reg = <0x2100 0x100>;
+				};
+				qcom,freq@200 {
+					reg = <0x2200 0x100>;
+				};
+			};
+
+			regulator@2300 {
+				regulator-name = "8841_s6";
+				spmi-dev-container;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				compatible = "qcom,qpnp-regulator";
+				reg = <0x2300 0x300>;
+				status = "disabled";
+
+				qcom,ctl@2300 {
+					reg = <0x2300 0x100>;
+				};
+				qcom,ps@2400 {
+					reg = <0x2400 0x100>;
+				};
+				qcom,freq@2500 {
+					reg = <0x2500 0x100>;
+				};
+			};
+
+			regulator@2600 {
+				regulator-name = "8841_s7";
+				spmi-dev-container;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				compatible = "qcom,qpnp-regulator";
+				reg = <0x2600 0x300>;
+				status = "disabled";
+
+				qcom,ctl@2600 {
+					reg = <0x2300 0x100>;
+				};
+				qcom,ps@2700 {
+					reg = <0x2400 0x100>;
+				};
+				qcom,freq@2800 {
+					reg = <0x2500 0x100>;
+				};
+			};
+
+			regulator@2900 {
+				regulator-name = "8841_s8";
+				spmi-dev-container;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				compatible = "qcom,qpnp-regulator";
+				reg = <0x2900 0x300>;
+				status = "disabled";
+
+				qcom,ctl@2900 {
+					reg = <0x2900 0x100>;
+				};
+				qcom,ps@2a000 {
+					reg = <0x2a00 0x100>;
+				};
+				qcom,freq@2b00 {
+					reg = <0x2b00 0x100>;
+				};
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
new file mode 100644
index 0000000..2698ea7
--- /dev/null
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -0,0 +1,529 @@
+/* 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.
+ */
+
+/ {
+	qcom,spmi@fc4c0000 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		interrupt-controller;
+		#interrupt-cells = <3>;
+
+		qcom,pm8941@0 {
+			spmi-slave-container;
+			reg = <0x0>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			pm8941_gpios {
+				spmi-dev-container;
+				compatible = "qcom,qpnp-gpio";
+				gpio-controller;
+				#gpio-cells = <2>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+
+				gpio@c000 {
+					reg = <0xc000 0x100>;
+					qcom,gpio-num = <1>;
+					status = "disabled";
+				};
+
+				gpio@c100 {
+					reg = <0xc100 0x100>;
+					qcom,gpio-num = <2>;
+					status = "disabled";
+				};
+
+				gpio@c200 {
+					reg = <0xc200 0x100>;
+					qcom,gpio-num = <3>;
+					status = "disabled";
+				};
+
+				gpio@c300 {
+					reg = <0xc300 0x100>;
+					qcom,gpio-num = <4>;
+					status = "disabled";
+				};
+
+				gpio@c400 {
+					reg = <0xc400 0x100>;
+					qcom,gpio-num = <5>;
+					status = "disabled";
+				};
+
+				gpio@c500 {
+					reg = <0xc500 0x100>;
+					qcom,gpio-num = <6>;
+					status = "disabled";
+				};
+
+				gpio@c600 {
+					reg = <0xc600 0x100>;
+					qcom,gpio-num = <7>;
+					status = "disabled";
+				};
+
+				gpio@c700 {
+					reg = <0xc700 0x100>;
+					qcom,gpio-num = <8>;
+					status = "disabled";
+				};
+
+				gpio@c800 {
+					reg = <0xc800 0x100>;
+					qcom,gpio-num = <9>;
+					status = "disabled";
+				};
+
+				gpio@c900 {
+					reg = <0xc900 0x100>;
+					qcom,gpio-num = <10>;
+					status = "disabled";
+				};
+
+				gpio@ca00 {
+					reg = <0xca00 0x100>;
+					qcom,gpio-num = <11>;
+					status = "disabled";
+				};
+
+				gpio@cb00 {
+					reg = <0xcb00 0x100>;
+					qcom,gpio-num = <12>;
+					status = "disabled";
+				};
+
+				gpio@cc00 {
+					reg = <0xcc00 0x100>;
+					qcom,gpio-num = <13>;
+					status = "disabled";
+				};
+
+				gpio@cd00 {
+					reg = <0xcd00 0x100>;
+					qcom,gpio-num = <14>;
+					status = "disabled";
+				};
+
+				gpio@ce00 {
+					reg = <0xce00 0x100>;
+					qcom,gpio-num = <15>;
+					status = "disabled";
+				};
+
+				gpio@cf00 {
+					reg = <0xcf00 0x100>;
+					qcom,gpio-num = <16>;
+					status = "disabled";
+				};
+
+				gpio@d000 {
+					reg = <0xd000 0x100>;
+					qcom,gpio-num = <17>;
+					status = "disabled";
+				};
+
+				gpio@d100 {
+					reg = <0xd100 0x100>;
+					qcom,gpio-num = <18>;
+					status = "disabled";
+				};
+
+				gpio@d200 {
+					reg = <0xd200 0x100>;
+					qcom,gpio-num = <19>;
+					status = "disabled";
+				};
+
+				gpio@d300 {
+					reg = <0xd300 0x100>;
+					qcom,gpio-num = <20>;
+					status = "disabled";
+				};
+
+				gpio@d400 {
+					reg = <0xd400 0x100>;
+					qcom,gpio-num = <21>;
+					status = "disabled";
+				};
+
+				gpio@d500 {
+					reg = <0xd500 0x100>;
+					qcom,gpio-num = <22>;
+					status = "disabled";
+				};
+
+				gpio@d600 {
+					reg = <0xd600 0x100>;
+					qcom,gpio-num = <23>;
+					status = "disabled";
+				};
+
+				gpio@d700 {
+					reg = <0xd700 0x100>;
+					qcom,gpio-num = <24>;
+					status = "disabled";
+				};
+
+				gpio@d800 {
+					reg = <0xd800 0x100>;
+					qcom,gpio-num = <25>;
+					status = "disabled";
+				};
+
+				gpio@d900 {
+					reg = <0xd900 0x100>;
+					qcom,gpio-num = <26>;
+					status = "disabled";
+				};
+
+				gpio@da00 {
+					reg = <0xda00 0x100>;
+					qcom,gpio-num = <27>;
+					status = "disabled";
+				};
+
+				gpio@db00 {
+					reg = <0xdb00 0x100>;
+					qcom,gpio-num = <28>;
+					status = "disabled";
+				};
+
+				gpio@dc00 {
+					reg = <0xdc00 0x100>;
+					qcom,gpio-num = <29>;
+					status = "disabled";
+				};
+
+				gpio@dd00 {
+					reg = <0xdd00 0x100>;
+					qcom,gpio-num = <30>;
+					status = "disabled";
+				};
+
+				gpio@de00 {
+					reg = <0xde00 0x100>;
+					qcom,gpio-num = <31>;
+					status = "disabled";
+				};
+
+				gpio@df00 {
+					reg = <0xdf00 0x100>;
+					qcom,gpio-num = <32>;
+					status = "disabled";
+				};
+
+				gpio@e000 {
+					reg = <0xe000 0x100>;
+					qcom,gpio-num = <33>;
+					status = "disabled";
+				};
+
+				gpio@e100 {
+					reg = <0xe100 0x100>;
+					qcom,gpio-num = <34>;
+					status = "disabled";
+				};
+
+				gpio@e200 {
+					reg = <0xe200 0x100>;
+					qcom,gpio-num = <35>;
+					status = "disabled";
+				};
+
+				gpio@e300 {
+					reg = <0xe300 0x100>;
+					qcom,gpio-num = <36>;
+					status = "disabled";
+				};
+			};
+		};
+
+		qcom,pm8941@1 {
+			spmi-slave-container;
+			reg = <0x1>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			regulator@1400 {
+				regulator-name = "8941_s1";
+				spmi-dev-container;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				compatible = "qcom,qpnp-regulator";
+				reg = <0x1400 0x300>;
+				status = "disabled";
+
+				qcom,ctl@1400 {
+					reg = <0x1400 0x100>;
+				};
+				qcom,ps@1500 {
+					reg = <0x1500 0x100>;
+				};
+				qcom,freq@1600 {
+					reg = <0x1600 0x100>;
+				};
+			};
+
+			regulator@1700 {
+				regulator-name = "8941_s2";
+				spmi-dev-container;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				compatible = "qcom,qpnp-regulator";
+				reg = <0x1700 0x300>;
+				status = "disabled";
+
+				qcom,ctl@1700 {
+					reg = <0x1700 0x100>;
+				};
+				qcom,ps@1800 {
+					reg = <0x1800 0x100>;
+				};
+				qcom,freq@1900 {
+					reg = <0x1900 0x100>;
+				};
+			};
+
+			regulator@1a00 {
+				regulator-name = "8941_s3";
+				spmi-dev-container;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				compatible = "qcom,qpnp-regulator";
+				reg = <0x1400 0x300>;
+				status = "disabled";
+
+				qcom,ctl@1a00 {
+					reg = <0x1a00 0x100>;
+				};
+				qcom,ps@1b00 {
+					reg = <0x1b00 0x100>;
+				};
+				qcom,freq@1c00 {
+					reg = <0x1c00 0x100>;
+				};
+			};
+
+			regulator@1d00 {
+				regulator-name = "8941_boost";
+				reg = <0x1d00 0x100>;
+				compatible = "qcom,qpnp-regulator";
+				status = "disabled";
+			};
+
+			regulator@4000 {
+				regulator-name = "8941_l1";
+				reg = <0x4000 0x100>;
+				compatible = "qcom,qpnp-regulator";
+				status = "disabled";
+			};
+
+			regulator@4100 {
+				regulator-name = "8941_l2";
+				reg = <0x4100 0x100>;
+				compatible = "qcom,qpnp-regulator";
+				status = "disabled";
+			};
+
+			regulator@4200 {
+				regulator-name = "8941_l3";
+				reg = <0x4200 0x100>;
+				compatible = "qcom,qpnp-regulator";
+				status = "disabled";
+			};
+
+			regulator@4300 {
+				regulator-name = "8941_l4";
+				reg = <0x4300 0x100>;
+				compatible = "qcom,qpnp-regulator";
+				status = "disabled";
+			};
+
+			regulator@4400 {
+				regulator-name = "8941_l5";
+				reg = <0x4400 0x100>;
+				compatible = "qcom,qpnp-regulator";
+				status = "disabled";
+			};
+
+			regulator@4500 {
+				regulator-name = "8941_l6";
+				reg = <0x4500 0x100>;
+				compatible = "qcom,qpnp-regulator";
+				status = "disabled";
+			};
+
+			regulator@4600 {
+				regulator-name = "8941_l7";
+				reg = <0x4600 0x100>;
+				compatible = "qcom,qpnp-regulator";
+				status = "disabled";
+			};
+
+			regulator@4700 {
+				regulator-name = "8941_l8";
+				reg = <0x4700 0x100>;
+				compatible = "qcom,qpnp-regulator";
+				status = "disabled";
+			};
+
+			regulator@4800 {
+				regulator-name = "8941_l9";
+				reg = <0x4800 0x100>;
+				compatible = "qcom,qpnp-regulator";
+				status = "disabled";
+			};
+
+			regulator@4900 {
+				regulator-name = "8941_l10";
+				reg = <0x4900 0x100>;
+				compatible = "qcom,qpnp-regulator";
+				status = "disabled";
+			};
+
+			regulator@4a00 {
+				regulator-name = "8941_l11";
+				reg = <0x4a00 0x100>;
+				compatible = "qcom,qpnp-regulator";
+				status = "disabled";
+			};
+
+			regulator@4b00 {
+				regulator-name = "8941_l12";
+				reg = <0x4b00 0x100>;
+				compatible = "qcom,qpnp-regulator";
+				status = "disabled";
+			};
+
+			regulator@4c00 {
+				regulator-name = "8941_l13";
+				reg = <0x4c00 0x100>;
+				compatible = "qcom,qpnp-regulator";
+				status = "disabled";
+			};
+
+			regulator@4d00 {
+				regulator-name = "8941_l14";
+				reg = <0x4d00 0x100>;
+				compatible = "qcom,qpnp-regulator";
+				status = "disabled";
+			};
+
+			regulator@4e00 {
+				regulator-name = "8941_l15";
+				reg = <0x4e00 0x100>;
+				compatible = "qcom,qpnp-regulator";
+				status = "disabled";
+			};
+
+			regulator@4f00 {
+				regulator-name = "8941_l16";
+				reg = <0x4f00 0x100>;
+				compatible = "qcom,qpnp-regulator";
+				status = "disabled";
+			};
+
+			regulator@5000 {
+				regulator-name = "8941_l17";
+				reg = <0x5000 0x100>;
+				compatible = "qcom,qpnp-regulator";
+				status = "disabled";
+			};
+
+			regulator@5100 {
+				regulator-name = "8941_l18";
+				reg = <0x5100 0x100>;
+				compatible = "qcom,qpnp-regulator";
+				status = "disabled";
+			};
+
+			regulator@5200 {
+				regulator-name = "8941_l19";
+				reg = <0x5200 0x100>;
+				compatible = "qcom,qpnp-regulator";
+				status = "disabled";
+			};
+
+			regulator@5300 {
+				regulator-name = "8941_l20";
+				reg = <0x5300 0x100>;
+				compatible = "qcom,qpnp-regulator";
+				status = "disabled";
+			};
+
+			regulator@5400 {
+				regulator-name = "8941_l21";
+				reg = <0x5400 0x100>;
+				compatible = "qcom,qpnp-regulator";
+				status = "disabled";
+			};
+
+			regulator@5500 {
+				regulator-name = "8941_l22";
+				reg = <0x5500 0x100>;
+				compatible = "qcom,qpnp-regulator";
+				status = "disabled";
+			};
+
+			regulator@5600 {
+				regulator-name = "8941_l23";
+				reg = <0x5600 0x100>;
+				compatible = "qcom,qpnp-regulator";
+				status = "disabled";
+			};
+
+			regulator@5700 {
+				regulator-name = "8941_l24";
+				reg = <0x5700 0x100>;
+				compatible = "qcom,qpnp-regulator";
+				status = "disabled";
+			};
+
+			regulator@8000 {
+				regulator-name = "8941_lvs1";
+				reg = <0x8000 0x100>;
+				compatible = "qcom,qpnp-regulator";
+				status = "disabled";
+			};
+
+			regulator@8100 {
+				regulator-name = "8941_lvs2";
+				reg = <0x8100 0x100>;
+				compatible = "qcom,qpnp-regulator";
+				status = "disabled";
+			};
+
+			regulator@8200 {
+				regulator-name = "8941_lvs3";
+				reg = <0x8200 0x100>;
+				compatible = "qcom,qpnp-regulator";
+				status = "disabled";
+			};
+
+			regulator@8300 {
+				regulator-name = "8941_mvs1";
+				reg = <0x8300 0x100>;
+				compatible = "qcom,qpnp-regulator";
+				status = "disabled";
+			};
+
+			regulator@8400 {
+				regulator-name = "8941_mvs2";
+				reg = <0x8400 0x100>;
+				compatible = "qcom,qpnp-regulator";
+				status = "disabled";
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/msm-pm8x41-rpm-regulator.dtsi b/arch/arm/boot/dts/msm-pm8x41-rpm-regulator.dtsi
new file mode 100644
index 0000000..019112a
--- /dev/null
+++ b/arch/arm/boot/dts/msm-pm8x41-rpm-regulator.dtsi
@@ -0,0 +1,587 @@
+/* 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.
+ */
+
+/ {
+	qcom,rpm-smd {
+		rpm-regulator-smpb1 {
+			qcom,resource-name = "smpb";
+			qcom,resource-id = <1>;
+			qcom,regulator-type = <1>;
+			qcom,hpm-min-load = <100000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-s1 {
+				regulator-name = "8841_s1";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-smpb2 {
+			qcom,resource-name = "smpb";
+			qcom,resource-id = <2>;
+			qcom,regulator-type = <1>;
+			qcom,hpm-min-load = <100000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-s2 {
+				regulator-name = "8841_s2";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-smpb3 {
+			qcom,resource-name = "smpb";
+			qcom,resource-id = <3>;
+			qcom,regulator-type = <1>;
+			qcom,hpm-min-load = <100000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-s3 {
+				regulator-name = "8841_s3";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-smpb4 {
+			qcom,resource-name = "smpb";
+			qcom,resource-id = <4>;
+			qcom,regulator-type = <1>;
+			qcom,hpm-min-load = <100000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-s4 {
+				regulator-name = "8841_s4";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-smpa1 {
+			qcom,resource-name = "smpa";
+			qcom,resource-id = <1>;
+			qcom,regulator-type = <1>;
+			qcom,hpm-min-load = <100000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-s1 {
+				regulator-name = "8941_s1";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-smpa2 {
+			qcom,resource-name = "smpa";
+			qcom,resource-id = <2>;
+			qcom,regulator-type = <1>;
+			qcom,hpm-min-load = <100000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-s2 {
+				regulator-name = "8941_s2";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-smpa3 {
+			qcom,resource-name = "smpa";
+			qcom,resource-id = <3>;
+			qcom,regulator-type = <1>;
+			qcom,hpm-min-load = <100000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-s3 {
+				regulator-name = "8941_s3";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa1 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <1>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l1 {
+				regulator-name = "8941_l1";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa2 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <2>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l2 {
+				regulator-name = "8941_l2";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa3 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <3>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l3 {
+				regulator-name = "8941_l3";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa4 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <4>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l4 {
+				regulator-name = "8941_l4";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa5 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <5>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l5 {
+				regulator-name = "8941_l5";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa6 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <6>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l6 {
+				regulator-name = "8941_l6";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa7 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <7>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l7 {
+				regulator-name = "8941_l7";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa8 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <8>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l8 {
+				regulator-name = "8941_l8";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa9 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <9>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l9 {
+				regulator-name = "8941_l9";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa10 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <10>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l10 {
+				regulator-name = "8941_l10";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa11 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <11>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l11 {
+				regulator-name = "8941_l11";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa12 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <12>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l12 {
+				regulator-name = "8941_l12";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa13 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <13>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l13 {
+				regulator-name = "8941_l13";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa14 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <14>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l14 {
+				regulator-name = "8941_l14";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa15 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <15>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l15 {
+				regulator-name = "8941_l15";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa16 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <16>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l16 {
+				regulator-name = "8941_l16";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa17 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <17>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l17 {
+				regulator-name = "8941_l17";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa18 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <18>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l18 {
+				regulator-name = "8941_l18";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa19 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <19>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l19 {
+				regulator-name = "8941_l19";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa20 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <20>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l20 {
+				regulator-name = "8941_l20";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa21 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <21>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l21 {
+				regulator-name = "8941_l21";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa22 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <22>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l22 {
+				regulator-name = "8941_l22";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa23 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <23>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l23 {
+				regulator-name = "8941_l23";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-ldoa24 {
+			qcom,resource-name = "ldoa";
+			qcom,resource-id = <24>;
+			qcom,regulator-type = <0>;
+			qcom,hpm-min-load = <10000>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-l24 {
+				regulator-name = "8941_l24";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		/* TODO: find out correct resource names for LVS vs MVS */
+		rpm-regulator-vsa1 {
+			qcom,resource-name = "vsa";
+			qcom,resource-id = <1>;
+			qcom,regulator-type = <2>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-lvs1 {
+				regulator-name = "8941_lvs1";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-vsa2 {
+			qcom,resource-name = "vsa";
+			qcom,resource-id = <2>;
+			qcom,regulator-type = <2>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-lvs2 {
+				regulator-name = "8941_lvs2";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-vsa3 {
+			qcom,resource-name = "vsa";
+			qcom,resource-id = <3>;
+			qcom,regulator-type = <2>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-lvs3 {
+				regulator-name = "8941_lvs3";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-vsa4 {
+			qcom,resource-name = "vsa";
+			qcom,resource-id = <4>;
+			qcom,regulator-type = <2>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-mvs1 {
+				regulator-name = "8941_mvs1";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+
+		rpm-regulator-vsa5 {
+			qcom,resource-name = "vsa";
+			qcom,resource-id = <5>;
+			qcom,regulator-type = <2>;
+			compatible = "qcom,rpm-regulator-smd-resource";
+			status = "disabled";
+
+			regulator-mvs2 {
+				regulator-name = "8941_mvs2";
+				qcom,set = <3>;
+				status = "disabled";
+				compatible = "qcom,rpm-regulator-smd";
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/msm9625.dts b/arch/arm/boot/dts/msm9625.dts
new file mode 100644
index 0000000..d5aed00
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625.dts
@@ -0,0 +1,47 @@
+/* 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.
+ */
+
+/dts-v1/;
+/include/ "skeleton.dtsi"
+
+/ {
+	model = "Qualcomm MSM 9625";
+	compatible = "qcom,msm9625";
+	interrupt-parent = <&intc>;
+
+	intc: interrupt-controller@F9000000 {
+		compatible = "qcom,msm-qgic2";
+		interrupt-controller;
+		#interrupt-cells = <3>;
+		reg = <0xF9000000 0x1000>,
+		      <0xF9002000 0x1000>;
+	};
+
+	msmgpio: gpio@fd510000 {
+		compatible = "qcom,msm-gpio";
+		interrupt-controller;
+		#interrupt-cells = <2>;
+		reg = <0xfd510000 0x4000>;
+	};
+
+	timer {
+		compatible = "qcom,msm-qtimer", "arm,armv7-timer";
+		interrupts = <0 7 0>;
+		clock-frequency = <5000000>;
+	};
+
+	serial@f991f000 {
+		compatible = "qcom,msm-lsuart-v14";
+		reg = <0xf991f000 0x1000>;
+		interrupts = <0 109 0>;
+	};
+};
diff --git a/arch/arm/boot/dts/msmcopper-gpio.dtsi b/arch/arm/boot/dts/msmcopper-gpio.dtsi
new file mode 100644
index 0000000..7c3f5ce
--- /dev/null
+++ b/arch/arm/boot/dts/msmcopper-gpio.dtsi
@@ -0,0 +1,214 @@
+/* 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.
+ */
+
+/ {
+	qcom,spmi@fc4c0000 {
+
+		qcom,pm8941@0 {
+
+			pm8941_gpios: pm8941_gpios {
+
+				gpio@c000 {
+					qcom,gpio-num = <1>;
+					status = "ok";
+				};
+
+				gpio@c100 {
+					qcom,gpio-num = <2>;
+					status = "ok";
+				};
+
+				gpio@c200 {
+					qcom,gpio-num = <3>;
+					status = "ok";
+				};
+
+				gpio@c300 {
+					qcom,gpio-num = <4>;
+					status = "ok";
+				};
+
+				gpio@c400 {
+					qcom,gpio-num = <5>;
+					status = "ok";
+				};
+
+				gpio@c500 {
+					qcom,gpio-num = <6>;
+					status = "ok";
+				};
+
+				gpio@c600 {
+					qcom,gpio-num = <7>;
+					status = "ok";
+				};
+
+				gpio@c700 {
+					qcom,gpio-num = <8>;
+					status = "ok";
+				};
+
+				gpio@c800 {
+					qcom,gpio-num = <9>;
+					status = "ok";
+				};
+
+				gpio@c900 {
+					qcom,gpio-num = <10>;
+					status = "ok";
+				};
+
+				gpio@ca00 {
+					qcom,gpio-num = <11>;
+					status = "ok";
+				};
+
+				gpio@cb00 {
+					qcom,gpio-num = <12>;
+					status = "ok";
+				};
+
+				gpio@cc00 {
+					qcom,gpio-num = <13>;
+					status = "ok";
+				};
+
+				gpio@cd00 {
+					qcom,gpio-num = <14>;
+					status = "ok";
+				};
+
+				gpio@ce00 {
+					qcom,gpio-num = <15>;
+					status = "ok";
+				};
+
+				gpio@cf00 {
+					qcom,gpio-num = <16>;
+					status = "ok";
+				};
+
+				gpio@d000 {
+					qcom,gpio-num = <17>;
+					status = "ok";
+				};
+
+				gpio@d100 {
+					qcom,gpio-num = <18>;
+					status = "ok";
+				};
+
+				gpio@d200 {
+					qcom,gpio-num = <19>;
+					status = "ok";
+				};
+
+				gpio@d300 {
+					qcom,gpio-num = <20>;
+					status = "ok";
+				};
+
+				gpio@d400 {
+					qcom,gpio-num = <21>;
+					status = "ok";
+				};
+
+				gpio@d500 {
+					qcom,gpio-num = <22>;
+					status = "ok";
+				};
+
+				gpio@d600 {
+					qcom,gpio-num = <23>;
+					status = "ok";
+				};
+
+				gpio@d700 {
+					qcom,gpio-num = <24>;
+					status = "ok";
+				};
+
+				gpio@d800 {
+					qcom,gpio-num = <25>;
+					qcom,out-strength = <1>;
+					status = "ok";
+				};
+
+				gpio@d900 {
+					qcom,gpio-num = <26>;
+					qcom,out-strength = <1>;
+					status = "ok";
+				};
+
+				gpio@da00 {
+					qcom,gpio-num = <27>;
+					qcom,out-strength = <1>;
+					status = "ok";
+				};
+
+				gpio@db00 {
+					qcom,gpio-num = <28>;
+					qcom,out-strength = <1>;
+					status = "ok";
+				};
+
+				gpio@dc00 {
+					qcom,gpio-num = <29>;
+					qcom,out-strength = <1>;
+					status = "ok";
+				};
+
+				gpio@dd00 {
+					qcom,gpio-num = <30>;
+					qcom,out-strength = <1>;
+					status = "ok";
+				};
+
+				gpio@de00 {
+					qcom,gpio-num = <31>;
+					qcom,out-strength = <1>;
+					status = "ok";
+				};
+
+				gpio@df00 {
+					qcom,gpio-num = <32>;
+					qcom,out-strength = <1>;
+					status = "ok";
+				};
+
+				gpio@e000 {
+					qcom,gpio-num = <33>;
+					qcom,out-strength = <1>;
+					status = "ok";
+				};
+
+				gpio@e100 {
+					qcom,gpio-num = <34>;
+					qcom,out-strength = <1>;
+					status = "ok";
+				};
+
+				gpio@e200 {
+					qcom,gpio-num = <35>;
+					qcom,out-strength = <1>;
+					status = "ok";
+				};
+
+				gpio@e300 {
+					qcom,gpio-num = <36>;
+					qcom,out-strength = <1>;
+					status = "ok";
+				};
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/msmcopper-iommu.dtsi b/arch/arm/boot/dts/msmcopper-iommu.dtsi
new file mode 100644
index 0000000..e0ce8ac
--- /dev/null
+++ b/arch/arm/boot/dts/msmcopper-iommu.dtsi
@@ -0,0 +1,88 @@
+/* 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.
+ */
+
+/ {
+	jpeg: qcom,iommu@fda64000 {
+		compatible = "qcom,msm-smmu-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		reg = <0xfda64000 0x10000>;
+
+		qcom,iommu-ctx@fda6c000 {
+			reg = <0xfda6c000 0x1000>;
+			interrupts = <0 69 0>;
+			qcom,iommu-ctx-sids = <0>;
+			qcom,iommu-ctx-name = "jpeg_enc0";
+		};
+		qcom,iommu-ctx@fda6d000 {
+			reg = <0xfda6d000 0x1000>;
+			interrupts = <0 70 0>;
+			qcom,iommu-ctx-sids = <1>;
+			qcom,iommu-ctx-name = "jpeg_enc1";
+		};
+		qcom,iommu-ctx@fda6e000 {
+			reg = <0xfda6e000 0x1000>;
+			interrupts = <0 71 0>;
+			qcom,iommu-ctx-sids = <2>;
+			qcom,iommu-ctx-name = "jpeg_dec";
+		};
+	};
+
+	mdp: qcom,iommu@fd928000 {
+		compatible = "qcom,msm-smmu-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		reg = <0xfd928000 0x10000>;
+
+		qcom,iommu-ctx@fd930000 {
+			reg = <0xfd930000 0x1000>;
+			interrupts = <0 74 0>;
+			qcom,iommu-ctx-sids = <0>;
+			qcom,iommu-ctx-name = "mdp_0";
+		};
+		qcom,iommu-ctx@fd931000 {
+			reg = <0xfd931000 0x1000>;
+			interrupts = <0 75 0>;
+			qcom,iommu-ctx-sids = <1>;
+			qcom,iommu-ctx-name = "mdp_1";
+		};
+	};
+
+	venus: qcom,iommu@fdc84000 {
+		compatible = "qcom,msm-smmu-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		reg = <0xfdc84000 0x10000>;
+
+		qcom,iommu-ctx@fdc8c000 {
+			reg = <0xfdc8c000 0x1000>;
+			interrupts = <0 43 0>;
+			qcom,iommu-ctx-sids = <0 1 2 3 4 5>;
+			qcom,iommu-ctx-name = "venus_ns";
+		};
+		qcom,iommu-ctx@fdc8d000 {
+			reg = <0xfdc8d000 0x1000>;
+			interrupts = <0 42 0>;
+			qcom,iommu-ctx-sids = <0x80 0x81 0x82 0x83 0x84 0x85>;
+			qcom,iommu-ctx-name = "venus_cp";
+		};
+		qcom,iommu-ctx@fdc8e000 {
+			reg = <0xfdc8e000 0x1000>;
+			interrupts = <0 41 0>;
+			qcom,iommu-ctx-sids = <0xc0 0xc6>;
+			qcom,iommu-ctx-name = "venus_fw";
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/msmcopper-regulator.dtsi b/arch/arm/boot/dts/msmcopper-regulator.dtsi
new file mode 100644
index 0000000..bb26e00
--- /dev/null
+++ b/arch/arm/boot/dts/msmcopper-regulator.dtsi
@@ -0,0 +1,394 @@
+/* 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.
+ */
+
+/ {
+	qcom,spmi@fc4c0000 {
+
+		qcom,pm8941@1 {
+
+			pm8941_s1: regulator@1400 {
+				regulator-min-microvolt = <1300000>;
+				regulator-max-microvolt = <1300000>;
+				qcom,enable-time = <500>;
+				qcom,pull-down-enable = <1>;
+				regulator-always-on;
+				status = "okay";
+			};
+
+			pm8941_s2: regulator@1700 {
+				regulator-min-microvolt = <2150000>;
+				regulator-max-microvolt = <2150000>;
+				qcom,enable-time = <500>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8941_s3: regulator@1a00 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				qcom,enable-time = <500>;
+				qcom,pull-down-enable = <1>;
+				regulator-always-on;
+				status = "okay";
+			};
+
+			pm8941_boost: regulator@1d00 {
+				regulator-min-microvolt = <5000000>;
+				regulator-max-microvolt = <5000000>;
+				qcom,enable-time = <500>;
+				status = "okay";
+			};
+
+			pm8941_l1: regulator@4000 {
+				parent-supply = <&pm8941_s1>;
+				regulator-min-microvolt = <1225000>;
+				regulator-max-microvolt = <1225000>;
+				qcom,enable-time = <200>;
+				qcom,pull-down-enable = <1>;
+				regulator-always-on;
+				status = "okay";
+			};
+
+			pm8941_l2: regulator@4100 {
+				parent-supply = <&pm8941_s3>;
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				qcom,enable-time = <200>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8941_l3: regulator@4200 {
+				parent-supply = <&pm8941_s1>;
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				qcom,enable-time = <200>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8941_l4: regulator@4300 {
+				parent-supply = <&pm8941_s1>;
+				regulator-min-microvolt = <1150000>;
+				regulator-max-microvolt = <1150000>;
+				qcom,enable-time = <200>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8941_l5: regulator@4400 {
+				parent-supply = <&pm8941_s2>;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				qcom,enable-time = <200>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8941_l6: regulator@4500 {
+				parent-supply = <&pm8941_s2>;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				qcom,enable-time = <200>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8941_l7: regulator@4600 {
+				parent-supply = <&pm8941_s2>;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				qcom,enable-time = <200>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8941_l8: regulator@4700 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				qcom,enable-time = <200>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8941_l9: regulator@4800 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <2950000>;
+				qcom,enable-time = <200>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8941_l10: regulator@4900 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <2950000>;
+				qcom,enable-time = <200>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8941_l11: regulator@4a00 {
+				parent-supply = <&pm8941_s1>;
+				regulator-min-microvolt = <1250000>;
+				regulator-max-microvolt = <1250000>;
+				qcom,enable-time = <200>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8941_l12: regulator@4b00 {
+				parent-supply = <&pm8941_s2>;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				qcom,enable-time = <200>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8941_l13: regulator@4c00 {
+				regulator-min-microvolt = <2950000>;
+				regulator-max-microvolt = <2950000>;
+				qcom,enable-time = <200>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8941_l14: regulator@4d00 {
+				parent-supply = <&pm8941_s2>;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				qcom,enable-time = <200>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8941_l15: regulator@4e00 {
+				parent-supply = <&pm8941_s2>;
+				regulator-min-microvolt = <2050000>;
+				regulator-max-microvolt = <2050000>;
+				qcom,enable-time = <200>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8941_l16: regulator@4f00 {
+				regulator-min-microvolt = <2700000>;
+				regulator-max-microvolt = <2700000>;
+				qcom,enable-time = <200>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8941_l17: regulator@5000 {
+				regulator-min-microvolt = <2850000>;
+				regulator-max-microvolt = <2850000>;
+				qcom,enable-time = <200>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8941_l18: regulator@5100 {
+				regulator-min-microvolt = <2850000>;
+				regulator-max-microvolt = <2850000>;
+				qcom,enable-time = <200>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8941_l19: regulator@5200 {
+				regulator-min-microvolt = <2900000>;
+				regulator-max-microvolt = <2900000>;
+				qcom,enable-time = <200>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8941_l20: regulator@5300 {
+				regulator-min-microvolt = <2950000>;
+				regulator-max-microvolt = <2950000>;
+				qcom,enable-time = <200>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8941_l21: regulator@5400 {
+				regulator-min-microvolt = <2950000>;
+				regulator-max-microvolt = <2950000>;
+				qcom,enable-time = <200>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8941_l22: regulator@5500 {
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3000000>;
+				qcom,enable-time = <200>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8941_l23: regulator@5600 {
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3000000>;
+				qcom,enable-time = <200>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8941_l24: regulator@5700 {
+				regulator-min-microvolt = <3075000>;
+				regulator-max-microvolt = <3075000>;
+				qcom,enable-time = <200>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8941_lvs1: regulator@8000 {
+				parent-supply = <&pm8941_s3>;
+				qcom,enable-time = <200>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8941_lvs2: regulator@8100 {
+				parent-supply = <&pm8941_s3>;
+				qcom,enable-time = <200>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8941_lvs3: regulator@8200 {
+				parent-supply = <&pm8941_s3>;
+				qcom,enable-time = <200>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8941_mvs1: regulator@8300 {
+				parent-supply = <&pm8941_boost>;
+				qcom,enable-time = <200>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8941_mvs2: regulator@8400 {
+				parent-supply = <&pm8941_boost>;
+				qcom,enable-time = <200>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+		};
+
+		qcom,pm8841@5 {
+
+			pm8841_s1: regulator@1400 {
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <1150000>;
+				qcom,enable-time = <500>;
+				qcom,pull-down-enable = <1>;
+				regulator-always-on;
+				status = "okay";
+			};
+
+			pm8841_s2: regulator@1700 {
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <1150000>;
+				qcom,enable-time = <500>;
+				qcom,pull-down-enable = <1>;
+				regulator-always-on;
+				status = "okay";
+			};
+
+			pm8841_s3: regulator@1a00 {
+				regulator-min-microvolt = <1150000>;
+				regulator-max-microvolt = <1150000>;
+				qcom,enable-time = <500>;
+				qcom,pull-down-enable = <1>;
+				regulator-always-on;
+				status = "okay";
+			};
+
+			pm8841_s4: regulator@1d00 {
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <900000>;
+				qcom,enable-time = <500>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8841_s5: regulator@2000 {
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <1100000>;
+				qcom,enable-time = <500>;
+				qcom,pull-down-enable = <1>;
+				regulator-always-on;
+				status = "okay";
+			};
+
+			pm8841_s6: regulator@2300 {
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <1100000>;
+				qcom,enable-time = <500>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8841_s7: regulator@2600 {
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <1100000>;
+				qcom,enable-time = <500>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+
+			pm8841_s8: regulator@2900 {
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <1100000>;
+				qcom,enable-time = <500>;
+				qcom,pull-down-enable = <1>;
+				status = "okay";
+			};
+		};
+	};
+
+	krait0_vreg: regulator@f9088000 {
+		compatible = "qcom,krait-regulator";
+		regulator-name = "krait0";
+		reg = <0xf9088000 0x1000>;
+		regulator-min-microvolt = <500000>;
+		regulator-max-microvolt = <1100000>;
+	};
+
+	krait1_vreg: regulator@f9098000 {
+		compatible = "qcom,krait-regulator";
+		regulator-name = "krait1";
+		reg = <0xf9098000 0x1000>;
+		regulator-min-microvolt = <500000>;
+		regulator-max-microvolt = <1100000>;
+	};
+
+	krait2_vreg: regulator@f90a8000 {
+		compatible = "qcom,krait-regulator";
+		regulator-name = "krait2";
+		reg = <0xf90a8000 0x1000>;
+		regulator-min-microvolt = <500000>;
+		regulator-max-microvolt = <1100000>;
+	};
+
+	krait3_vreg: regulator@f90b8000 {
+		compatible = "qcom,krait-regulator";
+		regulator-name = "krait3";
+		reg = <0xf90b8000 0x1000>;
+		regulator-min-microvolt = <500000>;
+		regulator-max-microvolt = <1100000>;
+	};
+};
diff --git a/arch/arm/boot/dts/msmcopper-rumi.dts b/arch/arm/boot/dts/msmcopper-rumi.dts
new file mode 100644
index 0000000..5bfb228
--- /dev/null
+++ b/arch/arm/boot/dts/msmcopper-rumi.dts
@@ -0,0 +1,114 @@
+/* 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.
+ */
+
+/dts-v1/;
+
+/include/ "msmcopper.dtsi"
+
+/ {
+	model = "Qualcomm MSM Copper RUMI";
+	compatible = "qcom,msmcopper-rumi", "qcom,msmcopper";
+
+	timer {
+		clock-frequency = <5000000>;
+	};
+
+	serial@f991f000 {
+		status = "disable";
+	};
+
+	usb@f9a55000 {
+		status = "disable";
+	};
+
+	qcom,sdcc@f9824000 {
+		status = "disable";
+	};
+
+	qcom,sdcc@f9864000 {
+		status = "disable";
+	};
+
+	qcom,sdcc@f98a4000 {
+		status = "disable";
+	};
+
+	qcom,sdcc@f98e4000 {
+		status = "disable";
+	};
+
+	qcom,sps@f998000 {
+		status = "disable";
+	};
+
+	spi@f9924000 {
+		status = "disable";
+	};
+
+	spi@f9923000 {
+		compatible = "qcom,spi-qup-v2";
+		reg = <0xf9923000 0x1000>;
+		interrupts = <0 95 0>;
+		spi-max-frequency = <24000000>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		gpios = <&msmgpio 3 0>, /* CLK  */
+			<&msmgpio 1 0>, /* MISO */
+			<&msmgpio 0 0>; /* MOSI */
+		cs-gpios = <&msmgpio 9 0>;
+
+		ethernet-switch@2 {
+			compatible = "simtec,ks8851";
+			reg = <2>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <90 0>;
+			spi-max-frequency = <5000000>;
+		};
+	};
+
+	i2c@f9966000 {
+		status = "disable";
+	};
+
+	i2c@f9967000 {
+		cell-index = <0>;
+		compatible = "qcom,i2c-qup";
+		reg = <0Xf9967000 0x1000>;
+		reg-names = "qup_phys_addr";
+		interrupts = <0 105 0>;
+		interrupt-names = "qup_err_intr";
+		qcom,i2c-bus-freq = <100000>;
+		qcom,i2c-src-freq = <24000000>;
+		gpios = <&msmgpio 83 0>, /* DAT  */
+			<&msmgpio 84 0>; /* CLK */
+	};
+
+	slim@fe12f000 {
+		status = "disable";
+	};
+
+	qcom,spmi@fc4c0000 {
+		status = "disable";
+	};
+
+	qcom,ssusb@F9200000 {
+		status = "disable";
+	};
+
+	qcom,lpass@fe200000 {
+		status = "disable";
+	};
+
+	qcom,pronto@fb21b000 {
+		status = "disable";
+	};
+};
diff --git a/arch/arm/boot/dts/msmcopper-sim.dts b/arch/arm/boot/dts/msmcopper-sim.dts
new file mode 100644
index 0000000..ae3f2dd
--- /dev/null
+++ b/arch/arm/boot/dts/msmcopper-sim.dts
@@ -0,0 +1,38 @@
+/* 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.
+ */
+
+/dts-v1/;
+
+/include/ "msmcopper.dtsi"
+
+/ {
+	model = "Qualcomm MSM Copper Simulator";
+	compatible = "qcom,msmcopper-sim", "qcom,msmcopper";
+
+	qcom,sdcc@f9824000 {
+		qcom,sdcc-disable_cmd23;
+	};
+
+	qcom,sdcc@f98a4000 {
+		status = "disable";
+	};
+
+	qcom,sdcc@f9864000 {
+		qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000 200000000>;
+		qcom,sdcc-sup-voltages = <2950 2950>;
+		qcom,sdcc-disable_cmd23;
+	};
+
+	qcom,sdcc@f98e4000 {
+		status = "disable";
+	};
+};
diff --git a/arch/arm/boot/dts/msmcopper.dtsi b/arch/arm/boot/dts/msmcopper.dtsi
new file mode 100644
index 0000000..60f59d3
--- /dev/null
+++ b/arch/arm/boot/dts/msmcopper.dtsi
@@ -0,0 +1,316 @@
+/* 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/ "skeleton.dtsi"
+/include/ "msmcopper_pm.dtsi"
+/include/ "msm-pm8x41-rpm-regulator.dtsi"
+/include/ "msm-pm8841.dtsi"
+/include/ "msm-pm8941.dtsi"
+/include/ "msmcopper-regulator.dtsi"
+/include/ "msmcopper-gpio.dtsi"
+/include/ "msmcopper-iommu.dtsi"
+/include/ "msm-gdsc.dtsi"
+
+/ {
+	model = "Qualcomm MSM Copper";
+	compatible = "qcom,msmcopper";
+	interrupt-parent = <&intc>;
+
+	intc: interrupt-controller@F9000000 {
+		compatible = "qcom,msm-qgic2";
+		interrupt-controller;
+		#interrupt-cells = <3>;
+		reg = <0xF9000000 0x1000>,
+		      <0xF9002000 0x1000>;
+	};
+
+	msmgpio: gpio@fd510000 {
+		compatible = "qcom,msm-gpio";
+		interrupt-controller;
+		#interrupt-cells = <2>;
+		reg = <0xfd510000 0x4000>;
+		#gpio-cells = <2>;
+	};
+
+	timer {
+		compatible = "qcom,msm-qtimer", "arm,armv7-timer";
+		interrupts = <1 2 0 1 3 0>;
+		clock-frequency = <19200000>;
+	};
+
+	qcom,vidc@fdc00000 {
+		compatible = "qcom,msm-vidc";
+		reg = <0xfdc00000 0xff000>;
+		interrupts = <0 44 0>;
+	};
+
+	serial@f991f000 {
+		compatible = "qcom,msm-lsuart-v14";
+		reg = <0xf991f000 0x1000>;
+		interrupts = <0 109 0>;
+	};
+
+	serial@f995e000 {
+		compatible = "qcom,msm-lsuart-v14";
+		reg = <0xf995e000 0x1000>;
+		interrupts = <0 114 0>;
+	};
+
+	usb@f9a55000 {
+		compatible = "qcom,hsusb-otg";
+		reg = <0xf9a55000 0x400>;
+		interrupts = <0 134 0>;
+		HSUSB_VDDCX-supply = <&pm8841_s2>;
+		HSUSB_1p8-supply = <&pm8941_l6>;
+		HSUSB_3p3-supply = <&pm8941_l24>;
+
+		qcom,hsusb-otg-phy-type = <2>;
+		qcom,hsusb-otg-mode = <1>;
+		qcom,hsusb-otg-otg-control = <1>;
+	};
+
+	qcom,sdcc@f9824000 {
+		cell-index = <1>;
+		compatible = "qcom,msm-sdcc";
+		reg = <0xf9824000 0x1000>;
+		interrupts = <0 123 0>;
+
+		qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000 200000000>;
+		qcom,sdcc-sup-voltages = <2950 2950>;
+		qcom,sdcc-bus-width = <8>;
+		qcom,sdcc-hs200;
+		qcom,sdcc-nonremovable;
+	};
+
+	qcom,sdcc@f98a4000 {
+		cell-index = <2>;
+		compatible = "qcom,msm-sdcc";
+		reg = <0xf98a4000 0x1000>;
+		interrupts = <0 125 0>;
+
+		qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000 200000000>;
+		qcom,sdcc-sup-voltages = <2950 2950>;
+		qcom,sdcc-bus-width = <4>;
+	};
+
+	qcom,sdcc@f9864000 {
+		cell-index = <3>;
+		compatible = "qcom,msm-sdcc";
+		reg = <0xf9864000 0x1000>;
+		interrupts = <0 127 0>;
+
+		qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000>;
+		qcom,sdcc-sup-voltages = <1800 1800>;
+		qcom,sdcc-bus-width = <4>;
+	};
+
+	qcom,sdcc@f98e4000 {
+		cell-index = <4>;
+		compatible = "qcom,msm-sdcc";
+		reg = <0xf98e4000 0x1000>;
+		interrupts = <0 129 0>;
+
+		qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000>;
+		qcom,sdcc-sup-voltages = <1800 1800>;
+		qcom,sdcc-bus-width = <4>;
+	};
+
+	qcom,sps@f9980000 {
+		compatible = "qcom,msm_sps";
+		reg = <0xf9984000 0x15000>,
+		      <0xf9999000 0xb000>;
+		interrupts = <0 94 0>;
+
+		qcom,bam-dma-res-pipes = <6>;
+	};
+
+
+	spi@f9924000 {
+		compatible = "qcom,spi-qup-v2";
+		reg = <0xf9924000 0x1000>;
+		interrupts = <0 96 0>;
+		spi-max-frequency = <25000000>;
+	};
+
+	slim@fe12f000 {
+		cell-index = <1>;
+		compatible = "qcom,slim-msm";
+		reg = <0xfe12f000 0x35000>,
+		      <0xfe104000 0x20000>;
+		reg-names = "slimbus_physical", "slimbus_bam_physical";
+		interrupts = <0 163 0 0 164 0>;
+		interrupt-names = "slimbus_irq", "slimbus_bam_irq";
+		qcom,min-clk-gear = <10>;
+	};
+
+	qcom,spmi@fc4c0000 {
+		cell-index = <0>;
+		compatible = "qcom,spmi-pmic-arb";
+		reg = <0xfc4cf000 0x1000>,
+		      <0Xfc4cb000 0x1000>;
+		/* 190,ee0_krait_hlos_spmi_periph_irq */
+		/* 187,channel_0_krait_hlos_trans_done_irq */
+		interrupts = <0 190 0 0 187 0>;
+		qcom,pmic-arb-ee = <0>;
+		qcom,pmic-arb-channel = <0>;
+		qcom,pmic-arb-ppid-map = <0x13000000>, /* PM8941_LDO1 */
+					 <0x13100001>, /* PM8941_LDO2 */
+					 <0x13200002>, /* PM8941_LDO3 */
+					 <0x13300003>, /* PM8941_LDO4 */
+					 <0x13400004>, /* PM8941_LDO5 */
+					 <0x13500005>, /* PM8941_LDO6 */
+					 <0x13600006>, /* PM8941_LDO7 */
+					 <0x13700007>, /* PM8941_LDO8 */
+					 <0x13800008>, /* PM8941_LDO9 */
+					 <0x13900009>, /* PM8941_LDO10 */
+					 <0x13a0000a>, /* PM8941_LDO11 */
+					 <0x13b0000b>, /* PM8941_LDO12 */
+					 <0x13c0000c>, /* PM8941_LDO13 */
+					 <0x13d0000d>, /* PM8941_LDO14 */
+					 <0x13e0000e>, /* PM8941_LDO15 */
+					 <0x13f0000f>, /* PM8941_LDO16 */
+					 <0x14000010>, /* PM8941_LDO17 */
+					 <0x14100011>, /* PM8941_LDO18 */
+					 <0x14200012>, /* PM8941_LDO19 */
+					 <0x14300013>, /* PM8941_LDO20 */
+					 <0x14400014>, /* PM8941_LDO21 */
+					 <0x14500015>, /* PM8941_LDO22 */
+					 <0x14600016>, /* PM8941_LDO23 */
+					 <0x14700017>, /* PM8941_LDO24 */
+					 <0x14800018>, /* PM8941_LDO25 */
+					 <0x14900019>, /* PM8941_LDO26 */
+					 <0x0c00001a>, /* PM8941_GPIO1 */
+					 <0x0c10001b>, /* PM8941_GPIO2 */
+					 <0x0c20001c>, /* PM8941_GPIO3 */
+					 <0x0c30001d>, /* PM8941_GPIO4 */
+					 <0x0c40001e>, /* PM8941_GPIO5 */
+					 <0x0c50001f>, /* PM8941_GPIO6 */
+					 <0x0c600020>, /* PM8941_GPIO7 */
+					 <0x0c700021>, /* PM8941_GPIO8 */
+					 <0x0c800022>, /* PM8941_GPIO9 */
+					 <0x0c900023>, /* PM8941_GPIO10 */
+					 <0x0ca00024>, /* PM8941_GPIO11 */
+					 <0x0cb00025>, /* PM8941_GPIO12 */
+					 <0x0cc00026>, /* PM8941_GPIO13 */
+					 <0x0cd00027>, /* PM8941_GPIO14 */
+					 <0x0ce00028>, /* PM8941_GPIO15 */
+					 <0x0cf00029>, /* PM8941_GPIO16 */
+					 <0x0d00002a>, /* PM8941_GPIO17 */
+					 <0x0d10002b>, /* PM8941_GPIO18 */
+					 <0x0d20002c>, /* PM8941_GPIO19 */
+					 <0x0d30002d>, /* PM8941_GPIO20 */
+					 <0x0d40002e>, /* PM8941_GPIO21 */
+					 <0x0d50002f>, /* PM8941_GPIO22 */
+					 <0x0d600030>, /* PM8941_GPIO23 */
+					 <0x0d700031>, /* PM8941_GPIO24 */
+					 <0x0d800032>, /* PM8941_GPIO25 */
+					 <0x0d900033>, /* PM8941_GPIO26 */
+					 <0x0da00034>, /* PM8941_GPIO27 */
+					 <0x0db00035>, /* PM8941_GPIO28 */
+					 <0x0dc00036>, /* PM8941_GPIO29 */
+					 <0x0dd00037>, /* PM8941_GPIO30 */
+					 <0x0de00038>, /* PM8941_GPIO31 */
+					 <0x0df00039>, /* PM8941_GPIO32 */
+					 <0x0e00003a>, /* PM8941_GPIO33 */
+					 <0x0e10003b>, /* PM8941_GPIO34 */
+					 <0x0e20003c>, /* PM8941_GPIO35 */
+					 <0x0e30003d>, /* PM8941_GPIO36 */
+					 <0x0280003e>, /* COINCELL */
+					 <0x0100003f>, /* SMBC_OVP */
+					 <0x01100040>, /* SMBC_CHG */
+					 <0x01200041>, /* SMBC_BIF */
+					 <0x00500042>, /* INTERRUPT */
+					 <0x00100043>, /* PM8941_0 */
+					 <0x20100044>, /* PM8841_0 */
+					 <0x10100045>, /* PM8941_1 */
+					 <0x30100046>, /* PM8841_1 */
+					 <0x00800047>, /* PON0 */
+					 <0x20800048>, /* PON1 */
+					 <0x11000049>, /* PM8941_SMPS1 */
+					 <0x1110004a>, /* PM8941_SMPS2 */
+					 <0x1120004b>, /* PM8941_SMPS3 */
+					 <0x3100004c>, /* PM8841_SMPS1 */
+					 <0x3110004d>, /* PM8841_SMPS2 */
+					 <0x3120004e>, /* PM8841_SMPS3 */
+					 <0x3130004f>, /* PM8841_SMPS4 */
+					 <0x31400050>, /* PM8841_SMPS5 */
+					 <0x31500051>, /* PM8841_SMPS6 */
+					 <0x31600052>, /* PM8841_SMPS7 */
+					 <0x31700053>, /* PM8841_SMPS8 */
+					 <0x05000054>, /* SHARED_XO */
+					 <0x05100055>, /* BB_CLK1 */
+					 <0x05200056>, /* BB_CLK2 */
+					 <0x05900057>, /* SLEEP_CLK */
+					 <0x07000058>, /* PBS_CORE */
+					 <0x07100059>, /* PBS_CLIENT1 */
+					 <0x0720005a>; /* PBS_CLIENT2 */
+	};
+
+	i2c@f9966000 {
+		cell-index = <0>;
+		compatible = "qcom,i2c-qup";
+		reg = <0Xf9966000 0x1000>;
+		reg-names = "qup_phys_addr";
+		interrupts = <0 104 0>;
+		interrupt-names = "qup_err_intr";
+		qcom,i2c-bus-freq = <100000>;
+		qcom,i2c-src-freq = <24000000>;
+	};
+
+	qcom,acpuclk@f9000000 {
+		compatible = "qcom,acpuclk-copper";
+	};
+
+	qcom,ssusb@F9200000 {
+		compatible = "qcom,dwc-usb3-msm";
+		reg = <0xF9200000 0xCCFF>;
+		interrupts = <0 131 0>;
+		qcom,dwc-usb3-msm-dbm-eps = <4>;
+	};
+
+	gdsc_oxili_gx: qcom,gdsc@fd8c4024 {
+		parent-supply = <&pm8841_s4>;
+	};
+
+	qcom,lpass@fe200000 {
+		compatible = "qcom,pil-q6v5-lpass";
+		reg = <0xfe200000 0x00100>,
+		      <0xfd485100 0x00010>;
+
+		qcom,firmware-name = "adsp";
+	};
+
+	qcom,pronto@fb21b000 {
+		compatible = "qcom,pil-pronto";
+		reg = <0xfb21b000 0x3000>,
+		      <0xfc401700 0x4>,
+		      <0xfd485300 0xc>;
+		vdd_pronto_pll-supply = <&pm8941_l12>;
+
+		qcom,firmware-name = "wcnss";
+	};
+
+	qcom,ocmem@fdd00000 {
+		compatible = "qcom,msm_ocmem";
+	};
+
+	qcom,rpm-smd {
+		compatible = "qcom,rpm-smd";
+		rpm-channel-name = "rpm_requests";
+		rpm-channel-type = <15>; /* SMD_APPS_RPM */
+	};
+
+        qcom,msm-rng@f9bff000 {
+               compatible = "qcom,msm-rng";
+               reg = <0xf9bff000 0x200>;
+        };
+};
diff --git a/arch/arm/boot/dts/msmcopper_pm.dtsi b/arch/arm/boot/dts/msmcopper_pm.dtsi
new file mode 100644
index 0000000..0da3200
--- /dev/null
+++ b/arch/arm/boot/dts/msmcopper_pm.dtsi
@@ -0,0 +1,280 @@
+/* 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/ "skeleton.dtsi"
+
+/ {
+	qcom,spm@f9089000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf9089000 0x1000>;
+		qcom,core-id = <0>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x1b>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x20000400>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,spm-cmd-wfi = [03 0b 0f];
+		qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+				a0 b0 03 68 70 3b 92 a0 b0
+				82 2b 50 10 30 02 22 30 0f];
+		qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+				a0 b0 82 10 30 02 22 30 0f];
+	};
+
+	qcom,spm@f9099000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf9099000 0x1000>;
+		qcom,core-id = <1>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x1b>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x20000400>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,spm-cmd-wfi = [03 0b 0f];
+		qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+				a0 b0 03 68 70 3b 92 a0 b0
+				82 2b 50 10 30 02 22 30 0f];
+		qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+				a0 b0 82 10 30 02 22 30 0f];
+	};
+
+	qcom,spm@f90a9000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf90a9000 0x1000>;
+		qcom,core-id = <2>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x1b>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x20000400>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,spm-cmd-wfi = [03 0b 0f];
+		qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+				a0 b0 03 68 70 3b 92 a0 b0
+				82 2b 50 10 30 02 22 30 0f];
+		qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+				a0 b0 82 10 30 02 22 30 0f];
+	};
+
+	qcom,spm@f90b9000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf90b9000 0x1000>;
+		qcom,core-id = <3>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x1b>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x20000400>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,spm-cmd-wfi = [03 0b 0f];
+		qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+				a0 b0 03 68 70 3b 92 a0 b0
+				82 2b 50 10 30 02 22 30 0f];
+		qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+				a0 b0 82 10 30 02 22 30 0f];
+	};
+
+	qcom,spm@f9012000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf9012000 0x1000>;
+		qcom,core-id = <0xffff>; /* L2/APCS SAW */
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x1a>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x20000400>;
+		qcom,saw2-spm-ctl = <0x0>; /* TODO: Enable L2 SPM */
+		qcom,saw2-pmic-dly = <0x02020204>;
+		qcom,saw2-pmic-data0 = <0x0400009c>;
+		qcom,saw2-pmic-data1 = <0x00000060>;
+		qcom,saw2-pmic-data2 = <0x0000001c>;
+		qcom,saw2-pmic-data3 = <0x04000000>;
+		qcom,vctl-timeout-us = <50>;
+		qcom,vctl-port = <0x0>; /* TODO: */
+		qcom,phase-port = <0x1>; /* TODO: */
+		qcom,spm-cmd-ret = [0b 00 20 03 22 00 0f];
+		qcom,spm-cmd-spc = [00 20 32 60 70 80 42 03
+				78 80 44 22 50 3b 60 02 32
+				50 0f];
+		qcom,spm-cmd-pc = [00 10 32 60 70 80 b0 11 42
+				07 01 b0 78 80 12 44 a0 50
+				3b 60 02 32 a0 50 0f];
+	};
+
+	qcom,lpm-levels {
+		compatible = "qcom,lpm-levels";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		qcom,lpm-level@0 {
+			reg = <0x0>;
+			qcom,mode = <0>;        /* MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT */
+			qcom,xo = <1>;          /* ON */
+			qcom,l2 = <3>;          /* ACTIVE */
+			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+			qcom,vdd-dig-upper-bound = <1150000>; /* MAX */
+			qcom,vdd-dig-lower-bound = <950000>;  /* ACTIVE */
+			qcom,latency-us = <100>;
+			qcom,ss-power = <650>;
+			qcom,energy-overhead = <801>;
+			qcom,time-overhead = <200>;
+		};
+
+		qcom,lpm-level@1 {
+			reg = <0x1>;
+			qcom,mode = <2>;        /* MSM_PM_SLEEP_MODE_STANDALONE_POWER_COLLAPSE */
+			qcom,xo = <1>;          /* ON */
+			qcom,l2 = <3>;          /* ACTIVE */
+			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+			qcom,vdd-dig-upper-bound = <1150000>; /* MAX */
+			qcom,vdd-dig-lower-bound = <950000>;  /* ACTIVE */
+			qcom,latency-us = <2000>;
+			qcom,ss-power = <200>;
+			qcom,energy-overhead = <576000>;
+			qcom,time-overhead = <2000>;
+		};
+
+		qcom,lpm-level@2 {
+			reg = <0x2>;
+			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+			qcom,xo = <1>;          /* ON */
+			qcom,l2 = <1>;          /* GDHS */
+			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+			qcom,vdd-dig-upper-bound = <1150000>; /* MAX */
+			qcom,vdd-dig-lower-bound = <950000>;  /* ACTIVE */
+			qcom,latency-us = <8500>;
+			qcom,ss-power = <51>;
+			qcom,energy-overhead = <1122000>;
+			qcom,time-overhead = <8500>;
+		};
+
+		qcom,lpm-level@3 {
+			reg = <0x3>;
+			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+			qcom,xo = <1>;          /* ON */
+			qcom,l2 = <0>;          /* OFF */
+			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+			qcom,vdd-dig-upper-bound = <1150000>; /* MAX */
+			qcom,vdd-dig-lower-bound = <950000>;  /* ACTIVE */
+			qcom,latency-us = <9000>;
+			qcom,ss-power = <51>;
+			qcom,energy-overhead = <1130300>;
+			qcom,time-overhead = <9000>;
+		};
+
+		qcom,lpm-level@4 {
+			reg = <0x4>;
+			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+			qcom,xo = <1>;          /* ON */
+			qcom,l2 = <0>;          /* OFF */
+			qcom,vdd-mem-upper-bound = <1050000>; /* ACTIVE */
+			qcom,vdd-mem-lower-bound = <750000>;  /* RETENTION HIGH */
+			qcom,vdd-dig-upper-bound = <950000>;  /* ACTIVE */
+			qcom,vdd-dig-lower-bound = <750000>;  /* RETENTION HIGH */
+			qcom,latency-us = <10000>;
+			qcom,ss-power = <51>;
+			qcom,energy-overhead = <1130300>;
+			qcom,time-overhead = <10000>;
+		};
+
+		qcom,lpm-level@5 {
+			reg = <0x5>;
+			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+			qcom,xo = <0>;          /* OFF */
+			qcom,l2 = <1>;          /* GDHS */
+			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+			qcom,vdd-dig-upper-bound = <1150000>; /* MAX */
+			qcom,vdd-dig-lower-bound = <950000>;  /* ACTIVE */
+			qcom,latency-us = <12000>;
+			qcom,ss-power = <14>;
+			qcom,energy-overhead = <2205900>;
+			qcom,time-overhead = <12000>;
+		};
+
+		qcom,lpm-level@6 {
+			reg = <0x6>;
+			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+			qcom,xo = <0>;          /* OFF */
+			qcom,l2 = <0>;          /* OFF */
+			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+			qcom,vdd-dig-upper-bound = <1150000>; /* MAX */
+			qcom,vdd-dig-lower-bound = <950000>;  /* ACTIVE */
+			qcom,latency-us = <18000>;
+			qcom,ss-power = <12>;
+			qcom,energy-overhead = <2364250>;
+			qcom,time-overhead = <18000>;
+		};
+
+		qcom,lpm-level@7 {
+			reg = <0x7>;
+			qcom,mode= <3>;         /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+			qcom,xo = <0>;          /* OFF */
+			qcom,l2 = <0>;          /* OFF */
+			qcom,vdd-mem-upper-bound = <1050000>; /* ACTIVE */
+			qcom,vdd-mem-lower-bound = <750000>;  /* RETENTION HIGH */
+			qcom,vdd-dig-upper-bound = <950000>;  /* ACTIVE */
+			qcom,vdd-dig-lower-bound = <750000>;  /* RETIONTION HIGH */
+			qcom,latency-us = <23500>;
+			qcom,ss-power = <10>;
+			qcom,energy-overhead = <2667000>;
+			qcom,time-overhead = <23500>;
+		};
+
+		qcom,lpm-level@8 {
+			reg = <0x8>;
+			qcom,mode= <3>;         /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+			qcom,xo = <0>;          /* OFF */
+			qcom,l2 = <0>;          /* OFF */
+			qcom,vdd-mem-upper-bound = <750000>; /* RETENTION HIGH */
+			qcom,vdd-mem-lower-bound = <750000>; /* RETENTION LOW */
+			qcom,vdd-dig-upper-bound = <750000>; /* RETENTION HIGH */
+			qcom,vdd-dig-lower-bound = <500000>; /* RETENTION LOW */
+			qcom,latency-us = <29700>;
+			qcom,ss-power = <5>;
+			qcom,energy-overhead = <2867000>;
+			qcom,time-overhead = <30000>;
+		};
+	};
+
+	qcom,pm-boot {
+		compatible = "qcom,pm-boot";
+		qcom,mode = <0>; /* MSM_PM_BOOT_CONFIG_TZ */
+	};
+};
diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig
index 271dd13..4ab36cd 100644
--- a/arch/arm/common/Kconfig
+++ b/arch/arm/common/Kconfig
@@ -1,11 +1,16 @@
 config ARM_GIC
 	select IRQ_DOMAIN
 	select MULTI_IRQ_HANDLER
+	select MSM_SHOW_RESUME_IRQ
 	bool
 
 config GIC_NON_BANKED
 	bool
 
+config GIC_SECURE
+	bool
+	depends on ARM_GIC
+
 config ARM_VIC
 	select IRQ_DOMAIN
 	select MULTI_IRQ_HANDLER
diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile
index 11670f9..6c24dce 100644
--- a/arch/arm/common/Makefile
+++ b/arch/arm/common/Makefile
@@ -17,3 +17,4 @@
 obj-$(CONFIG_ARM_TIMER_SP804)	+= timer-sp.o
 obj-$(CONFIG_FIQ_GLUE)		+= fiq_glue.o fiq_glue_setup.o
 obj-$(CONFIG_FIQ_DEBUGGER)	+= fiq_debugger.o
+obj-$(CONFIG_CP_ACCESS)         += cpaccess.o
diff --git a/arch/arm/common/cpaccess.c b/arch/arm/common/cpaccess.c
new file mode 100644
index 0000000..e71e318
--- /dev/null
+++ b/arch/arm/common/cpaccess.c
@@ -0,0 +1,351 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/sysrq.h>
+#include <linux/time.h>
+#include <linux/proc_fs.h>
+#include <linux/kernel_stat.h>
+#include <linux/uaccess.h>
+#include <linux/sysdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/semaphore.h>
+#include <linux/file.h>
+#include <linux/percpu.h>
+#include <linux/string.h>
+#include <linux/smp.h>
+#include <asm/cacheflush.h>
+#include <asm/smp_plat.h>
+#include <asm/mmu_writeable.h>
+
+#ifdef CONFIG_ARCH_MSM_KRAIT
+#include <mach/msm-krait-l2-accessors.h>
+#endif
+
+#define TYPE_MAX_CHARACTERS 10
+
+/*
+ * CP parameters
+ */
+struct cp_params {
+	unsigned long il2index;
+	unsigned long cp;
+	unsigned long op1;
+	unsigned long op2;
+	unsigned long crn;
+	unsigned long crm;
+	unsigned long write_value;
+	char rw;
+};
+
+static struct semaphore cp_sem;
+static unsigned long il2_output;
+static int cpu;
+char type[TYPE_MAX_CHARACTERS] = "C";
+
+static DEFINE_PER_CPU(struct cp_params, cp_param)
+	 = { 0, 15, 0, 0, 0, 0, 0, 'r' };
+
+static struct sysdev_class cpaccess_sysclass = {
+	.name = "cpaccess",
+};
+
+#ifdef CONFIG_ARCH_MSM_KRAIT
+/*
+ * do_read_il2 - Read indirect L2 registers
+ * @ret:	Pointer	to return value
+ *
+ */
+static void do_read_il2(void *ret)
+{
+	*(unsigned long *)ret =
+		get_l2_indirect_reg(per_cpu(cp_param.il2index, cpu));
+}
+
+/*
+ * do_write_il2 - Write indirect L2 registers
+ * @ret:	Pointer	to return value
+ *
+ */
+static void do_write_il2(void *ret)
+{
+	*(unsigned long *)ret =
+		set_get_l2_indirect_reg(per_cpu(cp_param.il2index, cpu),
+				per_cpu(cp_param.write_value, cpu));
+}
+
+/*
+ * do_il2_rw - Call Read/Write indirect L2 register functions
+ * @ret:	Pointer	to return value in case of CP register
+ *
+ */
+static int do_il2_rw(char *str_tmp)
+{
+	unsigned long write_value, il2index;
+	char rw;
+	int ret = 0;
+
+	il2index = 0;
+	sscanf(str_tmp, "%lx:%c:%lx:%d", &il2index, &rw, &write_value,
+								&cpu);
+	per_cpu(cp_param.il2index, cpu) = il2index;
+	per_cpu(cp_param.rw, cpu) = rw;
+	per_cpu(cp_param.write_value, cpu) = write_value;
+
+	if (per_cpu(cp_param.rw, cpu) == 'r') {
+		if (is_smp()) {
+			if (smp_call_function_single(cpu, do_read_il2,
+							&il2_output, 1))
+				pr_err("Error cpaccess smp call single\n");
+		} else
+			do_read_il2(&il2_output);
+	} else if (per_cpu(cp_param.rw, cpu) == 'w') {
+		if (is_smp()) {
+			if (smp_call_function_single(cpu, do_write_il2,
+							&il2_output, 1))
+				pr_err("Error cpaccess smp call single\n");
+		} else
+			do_write_il2(&il2_output);
+	} else {
+			pr_err("cpaccess: Wrong Entry for 'r' or 'w'.\n");
+			return -EINVAL;
+	}
+	return ret;
+}
+#else
+static void do_il2_rw(char *str_tmp)
+{
+	il2_output = 0;
+}
+#endif
+
+/*
+ * get_asm_value - Dummy fuction
+ * @write_val:	Write value incase of a CP register write operation.
+ *
+ * This function is just a placeholder. The first 2 instructions
+ * will be inserted to perform MRC/MCR instruction and a return.
+ * See do_cpregister_rw function. Value passed to function is
+ * accessed from r0 register.
+ */
+static noinline unsigned long cpaccess_dummy(unsigned long write_val)
+{
+	asm("mrc p15, 0, r0, c0, c0, 0\n\t");
+	asm("bx	lr\n\t");
+	return 0xBEEF;
+} __attribute__((aligned(32)))
+
+/*
+ * get_asm_value - Read/Write CP registers
+ * @ret:	Pointer	to return value in case of CP register
+ * read op.
+ *
+ */
+static void get_asm_value(void *ret)
+{
+	*(unsigned long *)ret =
+	 cpaccess_dummy(per_cpu(cp_param.write_value, cpu));
+}
+
+/*
+ * dp_cpregister_rw - Read/Write CP registers
+ * @write:		1 for Write and 0 for Read operation
+ *
+ * Returns value read from CP register
+ */
+static unsigned long do_cpregister_rw(int write)
+{
+	unsigned long opcode, ret, *p_opcode;
+
+	/*
+	 * Mask the crn, crm, op1, op2 and cp values so they do not
+	 * interfer with other fields of the op code.
+	 */
+	per_cpu(cp_param.cp, cpu)  &= 0xF;
+	per_cpu(cp_param.crn, cpu) &= 0xF;
+	per_cpu(cp_param.crm, cpu) &= 0xF;
+	per_cpu(cp_param.op1, cpu) &= 0x7;
+	per_cpu(cp_param.op2, cpu) &= 0x7;
+
+	/*
+	 * Base MRC opcode for MIDR is EE100010,
+	 * MCR is 0xEE000010
+	 */
+	opcode = (write == 1 ? 0xEE000010 : 0xEE100010);
+	opcode |= (per_cpu(cp_param.crn, cpu)<<16) |
+	(per_cpu(cp_param.crm, cpu)<<0) |
+	(per_cpu(cp_param.op1, cpu)<<21) |
+	(per_cpu(cp_param.op2, cpu)<<5) |
+	(per_cpu(cp_param.cp, cpu) << 8);
+
+	/*
+	 * Grab address of the Dummy function, write the MRC/MCR
+	 * instruction, ensuring cache coherency.
+	 */
+	p_opcode = (unsigned long *)&cpaccess_dummy;
+	mem_text_write_kernel_word(p_opcode, opcode);
+
+#ifdef CONFIG_SMP
+	/*
+	 * Use smp_call_function_single to do CPU core specific
+	 * get_asm_value function call.
+	 */
+	if (smp_call_function_single(cpu, get_asm_value, &ret, 1))
+		printk(KERN_ERR "Error cpaccess smp call single\n");
+#else
+		get_asm_value(&ret);
+#endif
+
+	return ret;
+}
+
+static int get_register_params(char *str_tmp)
+{
+	unsigned long op1, op2, crn, crm, cp = 15, write_value, il2index;
+	char rw;
+	int cnt = 0;
+
+	il2index = 0;
+	strncpy(type, strsep(&str_tmp, ":"), TYPE_MAX_CHARACTERS);
+
+	if (strncasecmp(type, "C", TYPE_MAX_CHARACTERS) == 0) {
+
+		sscanf(str_tmp, "%lu:%lu:%lu:%lu:%lu:%c:%lx:%d",
+			&cp, &op1, &crn, &crm, &op2, &rw, &write_value, &cpu);
+		per_cpu(cp_param.cp, cpu) = cp;
+		per_cpu(cp_param.op1, cpu) = op1;
+		per_cpu(cp_param.crn, cpu) = crn;
+		per_cpu(cp_param.crm, cpu) = crm;
+		per_cpu(cp_param.op2, cpu) = op2;
+		per_cpu(cp_param.rw, cpu) = rw;
+		per_cpu(cp_param.write_value, cpu) = write_value;
+
+		if ((per_cpu(cp_param.rw, cpu) != 'w') &&
+				(per_cpu(cp_param.rw, cpu) != 'r')) {
+			pr_err("cpaccess: Wrong entry for 'r' or 'w'.\n");
+			return -EINVAL;
+		}
+
+		if (per_cpu(cp_param.rw, cpu) == 'w')
+			do_cpregister_rw(1);
+	} else if (strncasecmp(type, "IL2", TYPE_MAX_CHARACTERS) == 0)
+		do_il2_rw(str_tmp);
+	else {
+		pr_err("cpaccess: Not a valid type. Entered: %s\n", type);
+		return -EINVAL;
+	}
+
+	return cnt;
+}
+
+/*
+ * cp_register_write_sysfs - sysfs interface for writing to
+ * CP register
+ * @dev:	sys device
+ * @attr:	device attribute
+ * @buf:	write value
+ * @cnt:	not used
+ *
+ */
+static ssize_t cp_register_write_sysfs(struct sys_device *dev,
+	struct sysdev_attribute *attr, const char *buf, size_t cnt)
+{
+	char *str_tmp = (char *)buf;
+
+	if (down_timeout(&cp_sem, 6000))
+		return -ERESTARTSYS;
+
+	get_register_params(str_tmp);
+
+	return cnt;
+}
+
+/*
+ * cp_register_read_sysfs - sysfs interface for reading CP registers
+ * @dev:        sys device
+ * @attr:       device attribute
+ * @buf:        write value
+ *
+ * Code to read in the CPxx crn, crm, op1, op2 variables, or into
+ * the base MRC opcode, store to executable memory, clean/invalidate
+ * caches and then execute the new instruction and provide the
+ * result to the caller.
+ */
+static ssize_t cp_register_read_sysfs(struct sys_device *dev,
+	struct sysdev_attribute *attr, char *buf)
+{
+	int ret;
+
+	if (strncasecmp(type, "C", TYPE_MAX_CHARACTERS) == 0)
+		ret = snprintf(buf, TYPE_MAX_CHARACTERS, "%lx\n",
+					do_cpregister_rw(0));
+	else if (strncasecmp(type, "IL2", TYPE_MAX_CHARACTERS) == 0)
+		ret = snprintf(buf, TYPE_MAX_CHARACTERS, "%lx\n", il2_output);
+	else
+		ret = -EINVAL;
+
+	if (cp_sem.count <= 0)
+		up(&cp_sem);
+
+	return ret;
+}
+
+/*
+ * Setup sysfs files
+ */
+SYSDEV_ATTR(cp_rw, 0644, cp_register_read_sysfs, cp_register_write_sysfs);
+
+static struct sys_device device_cpaccess = {
+	.id     = 0,
+	.cls    = &cpaccess_sysclass,
+};
+
+/*
+ * init_cpaccess_sysfs - initialize sys devices
+ */
+static int __init init_cpaccess_sysfs(void)
+{
+	int error = sysdev_class_register(&cpaccess_sysclass);
+
+	if (!error)
+		error = sysdev_register(&device_cpaccess);
+	else
+		pr_err("Error initializing cpaccess interface\n");
+
+	if (!error)
+		error = sysdev_create_file(&device_cpaccess,
+		 &attr_cp_rw);
+	else {
+		pr_err("Error initializing cpaccess interface\n");
+		sysdev_unregister(&device_cpaccess);
+		sysdev_class_unregister(&cpaccess_sysclass);
+	}
+
+	sema_init(&cp_sem, 1);
+
+	return error;
+}
+
+static void __exit exit_cpaccess_sysfs(void)
+{
+	sysdev_remove_file(&device_cpaccess, &attr_cp_rw);
+	sysdev_unregister(&device_cpaccess);
+	sysdev_class_unregister(&cpaccess_sysclass);
+}
+
+module_init(init_cpaccess_sysfs);
+module_exit(exit_cpaccess_sysfs);
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index aa52699..54a8392 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -38,12 +38,14 @@
 #include <linux/interrupt.h>
 #include <linux/percpu.h>
 #include <linux/slab.h>
+#include <linux/syscore_ops.h>
 
 #include <asm/irq.h>
 #include <asm/exception.h>
 #include <asm/smp_plat.h>
 #include <asm/mach/irq.h>
 #include <asm/hardware/gic.h>
+#include <asm/system.h>
 
 union gic_base {
 	void __iomem *common_base;
@@ -51,24 +53,37 @@
 };
 
 struct gic_chip_data {
+	unsigned int irq_offset;
 	union gic_base dist_base;
 	union gic_base cpu_base;
 #ifdef CONFIG_CPU_PM
 	u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)];
 	u32 saved_spi_conf[DIV_ROUND_UP(1020, 16)];
 	u32 saved_spi_target[DIV_ROUND_UP(1020, 4)];
+	u32 saved_dist_pri[DIV_ROUND_UP(1020, 4)];
 	u32 __percpu *saved_ppi_enable;
 	u32 __percpu *saved_ppi_conf;
 #endif
-	struct irq_domain *domain;
+#ifdef CONFIG_IRQ_DOMAIN
+	struct irq_domain domain;
+#endif
 	unsigned int gic_irqs;
 #ifdef CONFIG_GIC_NON_BANKED
 	void __iomem *(*get_base)(union gic_base *);
 #endif
+	unsigned int max_irq;
+#ifdef CONFIG_PM
+	unsigned int wakeup_irqs[32];
+	unsigned int enabled_irqs[32];
+#endif
 };
 
 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
 
+#ifdef CONFIG_CPU_PM
+static unsigned int saved_dist_ctrl, saved_cpu_ctrl;
+#endif
+
 /*
  * Supported arch specific GIC irq extension.
  * Default make them NULL.
@@ -80,6 +95,7 @@
 	.irq_retrigger	= NULL,
 	.irq_set_type	= NULL,
 	.irq_set_wake	= NULL,
+	.irq_disable	= NULL,
 };
 
 #ifndef MAX_GIC_NR
@@ -137,6 +153,26 @@
 	return d->hwirq;
 }
 
+#if defined(CONFIG_CPU_V7) && defined(CONFIG_GIC_SECURE)
+static const inline bool is_cpu_secure(void)
+{
+	unsigned int dscr;
+
+	asm volatile ("mrc p14, 0, %0, c0, c1, 0" : "=r" (dscr));
+
+	/* BIT(18) - NS bit; 1 = NS; 0 = S */
+	if (BIT(18) & dscr)
+		return false;
+	else
+		return true;
+}
+#else
+static const inline bool is_cpu_secure(void)
+{
+	return false;
+}
+#endif
+
 /*
  * Routines to acknowledge, disable and enable interrupts
  */
@@ -162,6 +198,132 @@
 	raw_spin_unlock(&irq_controller_lock);
 }
 
+static void gic_disable_irq(struct irq_data *d)
+{
+	if (gic_arch_extn.irq_disable)
+		gic_arch_extn.irq_disable(d);
+}
+
+#ifdef CONFIG_PM
+static int gic_suspend_one(struct gic_chip_data *gic)
+{
+	unsigned int i;
+	void __iomem *base = gic_data_dist_base(gic);
+#ifdef CONFIG_ARCH_MSM8625
+	unsigned long flags;
+#endif
+
+	for (i = 0; i * 32 < gic->max_irq; i++) {
+#ifdef CONFIG_ARCH_MSM8625
+		raw_spin_lock_irqsave(&irq_controller_lock, flags);
+#endif
+		gic->enabled_irqs[i]
+			= readl_relaxed(base + GIC_DIST_ENABLE_SET + i * 4);
+		/* disable all of them */
+		writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4);
+		/* enable the wakeup set */
+		writel_relaxed(gic->wakeup_irqs[i],
+			base + GIC_DIST_ENABLE_SET + i * 4);
+#ifdef CONFIG_ARCH_MSM8625
+		raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+#endif
+	}
+	mb();
+	return 0;
+}
+
+static int gic_suspend(void)
+{
+	int i;
+	for (i = 0; i < MAX_GIC_NR; i++)
+		gic_suspend_one(&gic_data[i]);
+	return 0;
+}
+
+extern int msm_show_resume_irq_mask;
+
+static void gic_show_resume_irq(struct gic_chip_data *gic)
+{
+	unsigned int i;
+	u32 enabled;
+	unsigned long pending[32];
+	void __iomem *base = gic_data_dist_base(gic);
+#ifdef CONFIG_ARCH_MSM8625
+	unsigned long flags;
+#endif
+
+	if (!msm_show_resume_irq_mask)
+		return;
+
+#ifdef CONFIG_ARCH_MSM8625
+	raw_spin_lock_irqsave(&irq_controller_lock, flags);
+#else
+	raw_spin_lock(&irq_controller_lock);
+#endif
+	for (i = 0; i * 32 < gic->max_irq; i++) {
+		enabled = readl_relaxed(base + GIC_DIST_ENABLE_CLEAR + i * 4);
+		pending[i] = readl_relaxed(base + GIC_DIST_PENDING_SET + i * 4);
+		pending[i] &= enabled;
+	}
+#ifdef CONFIG_ARCH_MSM8625
+	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+#else
+	raw_spin_lock(&irq_controller_lock);
+#endif
+
+	for (i = find_first_bit(pending, gic->max_irq);
+	     i < gic->max_irq;
+	     i = find_next_bit(pending, gic->max_irq, i+1)) {
+		pr_warning("%s: %d triggered", __func__,
+					i + gic->irq_offset);
+	}
+}
+
+static void gic_resume_one(struct gic_chip_data *gic)
+{
+	unsigned int i;
+	void __iomem *base = gic_data_dist_base(gic);
+#ifdef CONFIG_ARCH_MSM8625
+	unsigned long flags;
+#endif
+	gic_show_resume_irq(gic);
+	for (i = 0; i * 32 < gic->max_irq; i++) {
+#ifdef CONFIG_ARCH_MSM8625
+		raw_spin_lock_irqsave(&irq_controller_lock, flags);
+#endif
+		/* disable all of them */
+		writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4);
+		/* enable the enabled set */
+		writel_relaxed(gic->enabled_irqs[i],
+			base + GIC_DIST_ENABLE_SET + i * 4);
+#ifdef CONFIG_ARCH_MSM8625
+		raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+#endif
+	}
+	mb();
+}
+
+static void gic_resume(void)
+{
+	int i;
+	for (i = 0; i < MAX_GIC_NR; i++)
+		gic_resume_one(&gic_data[i]);
+}
+
+static struct syscore_ops gic_syscore_ops = {
+	.suspend = gic_suspend,
+	.resume = gic_resume,
+};
+
+static int __init gic_init_sys(void)
+{
+	register_syscore_ops(&gic_syscore_ops);
+	return 0;
+}
+arch_initcall(gic_init_sys);
+
+#endif
+
 static void gic_eoi_irq(struct irq_data *d)
 {
 	if (gic_arch_extn.irq_eoi) {
@@ -169,8 +331,13 @@
 		gic_arch_extn.irq_eoi(d);
 		raw_spin_unlock(&irq_controller_lock);
 	}
-
+#ifdef CONFIG_ARCH_MSM8625
+	raw_spin_lock(&irq_controller_lock);
+#endif
 	writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
+#ifdef CONFIG_ARCH_MSM8625
+	raw_spin_unlock(&irq_controller_lock);
+#endif
 }
 
 static int gic_set_type(struct irq_data *d, unsigned int type)
@@ -257,6 +424,20 @@
 static int gic_set_wake(struct irq_data *d, unsigned int on)
 {
 	int ret = -ENXIO;
+	unsigned int reg_offset, bit_offset;
+	unsigned int gicirq = gic_irq(d);
+	struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
+
+	/* per-cpu interrupts cannot be wakeup interrupts */
+	WARN_ON(gicirq < 32);
+
+	reg_offset = gicirq / 32;
+	bit_offset = gicirq % 32;
+
+	if (on)
+		gic_data->wakeup_irqs[reg_offset] |=  1 << bit_offset;
+	else
+		gic_data->wakeup_irqs[reg_offset] &=  ~(1 << bit_offset);
 
 	if (gic_arch_extn.irq_set_wake)
 		ret = gic_arch_extn.irq_set_wake(d, on);
@@ -275,16 +456,28 @@
 	void __iomem *cpu_base = gic_data_cpu_base(gic);
 
 	do {
+#ifdef CONFIG_ARCH_MSM8625
+		raw_spin_lock(&irq_controller_lock);
+#endif
 		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+#ifdef CONFIG_ARCH_MSM8625
+		raw_spin_unlock(&irq_controller_lock);
+#endif
 		irqnr = irqstat & ~0x1c00;
 
 		if (likely(irqnr > 15 && irqnr < 1021)) {
-			irqnr = irq_find_mapping(gic->domain, irqnr);
+			irqnr = irq_domain_to_irq(&gic->domain, irqnr);
 			handle_IRQ(irqnr, regs);
 			continue;
 		}
 		if (irqnr < 16) {
+#ifdef CONFIG_ARCH_MSM8625
+			raw_spin_lock(&irq_controller_lock);
+#endif
 			writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+#ifdef CONFIG_ARCH_MSM8625
+			raw_spin_unlock(&irq_controller_lock);
+#endif
 #ifdef CONFIG_SMP
 			handle_IPI(irqnr, regs);
 #endif
@@ -311,8 +504,8 @@
 	if (gic_irq == 1023)
 		goto out;
 
-	cascade_irq = irq_find_mapping(chip_data->domain, gic_irq);
-	if (unlikely(gic_irq < 32 || gic_irq > 1020))
+	cascade_irq = irq_domain_to_irq(&chip_data->domain, gic_irq);
+	if (unlikely(gic_irq < 32 || gic_irq > 1020 || cascade_irq >= NR_IRQS))
 		do_bad_IRQ(cascade_irq, desc);
 	else
 		generic_handle_irq(cascade_irq);
@@ -331,6 +524,7 @@
 #ifdef CONFIG_SMP
 	.irq_set_affinity	= gic_set_affinity,
 #endif
+	.irq_disable		= gic_disable_irq,
 	.irq_set_wake		= gic_set_wake,
 };
 
@@ -345,9 +539,10 @@
 
 static void __init gic_dist_init(struct gic_chip_data *gic)
 {
-	unsigned int i;
+	unsigned int i, irq;
 	u32 cpumask;
 	unsigned int gic_irqs = gic->gic_irqs;
+	struct irq_domain *domain = &gic->domain;
 	void __iomem *base = gic_data_dist_base(gic);
 	u32 cpu = cpu_logical_map(smp_processor_id());
 
@@ -370,6 +565,14 @@
 		writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
 
 	/*
+	 * Set NS/S.
+	 */
+	if (is_cpu_secure())
+		for (i = 32; i < gic_irqs; i += 32)
+			writel_relaxed(0xFFFFFFFF,
+					base + GIC_DIST_ISR + i * 4 / 32);
+
+	/*
 	 * Set priority on all global interrupts.
 	 */
 	for (i = 32; i < gic_irqs; i += 4)
@@ -382,7 +585,31 @@
 	for (i = 32; i < gic_irqs; i += 32)
 		writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
 
-	writel_relaxed(1, base + GIC_DIST_CTRL);
+	/*
+	 * Setup the Linux IRQ subsystem.
+	 */
+	irq_domain_for_each_irq(domain, i, irq) {
+		if (i < 32) {
+			irq_set_percpu_devid(irq);
+			irq_set_chip_and_handler(irq, &gic_chip,
+						 handle_percpu_devid_irq);
+			set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
+		} else {
+			irq_set_chip_and_handler(irq, &gic_chip,
+						 handle_fasteoi_irq);
+			set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+		}
+		irq_set_chip_data(irq, gic);
+	}
+
+	gic->max_irq = gic_irqs;
+
+	if (is_cpu_secure())
+		writel_relaxed(3, base + GIC_DIST_CTRL);
+	else
+		writel_relaxed(1, base + GIC_DIST_CTRL);
+
+	mb();
 }
 
 static void __cpuinit gic_cpu_init(struct gic_chip_data *gic)
@@ -395,9 +622,16 @@
 	 * Deal with the banked PPI and SGI interrupts - disable all
 	 * PPI interrupts, ensure all SGI interrupts are enabled.
 	 */
+#ifdef CONFIG_ARCH_MSM8625
+	raw_spin_lock(&irq_controller_lock);
+#endif
 	writel_relaxed(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR);
 	writel_relaxed(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET);
 
+	/* Set NS/S */
+	if (is_cpu_secure())
+		writel_relaxed(0xFFFFFFFF, dist_base + GIC_DIST_ISR);
+
 	/*
 	 * Set priority on PPI and SGI interrupts
 	 */
@@ -405,7 +639,15 @@
 		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
 
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, base + GIC_CPU_CTRL);
+
+	if (is_cpu_secure())
+		writel_relaxed(0xF, base + GIC_CPU_CTRL);
+	else
+		writel_relaxed(1, base + GIC_CPU_CTRL);
+#ifdef CONFIG_ARCH_MSM8625
+	raw_spin_unlock(&irq_controller_lock);
+#endif
+    mb();
 }
 
 #ifdef CONFIG_CPU_PM
@@ -430,6 +672,8 @@
 	if (!dist_base)
 		return;
 
+	saved_dist_ctrl = readl_relaxed(dist_base + GIC_DIST_CTRL);
+
 	for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++)
 		gic_data[gic_nr].saved_spi_conf[i] =
 			readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
@@ -438,6 +682,10 @@
 		gic_data[gic_nr].saved_spi_target[i] =
 			readl_relaxed(dist_base + GIC_DIST_TARGET + i * 4);
 
+	for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
+		gic_data[gic_nr].saved_dist_pri[i] =
+			readl_relaxed(dist_base + GIC_DIST_PRI + i * 4);
+
 	for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
 		gic_data[gic_nr].saved_spi_enable[i] =
 			readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
@@ -472,7 +720,7 @@
 			dist_base + GIC_DIST_CONFIG + i * 4);
 
 	for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
-		writel_relaxed(0xa0a0a0a0,
+		writel_relaxed(gic_data[gic_nr].saved_dist_pri[i],
 			dist_base + GIC_DIST_PRI + i * 4);
 
 	for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
@@ -483,7 +731,7 @@
 		writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
 			dist_base + GIC_DIST_ENABLE_SET + i * 4);
 
-	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+	writel_relaxed(saved_dist_ctrl, dist_base + GIC_DIST_CTRL);
 }
 
 static void gic_cpu_save(unsigned int gic_nr)
@@ -502,6 +750,12 @@
 	if (!dist_base || !cpu_base)
 		return;
 
+	saved_cpu_ctrl = readl_relaxed(cpu_base + GIC_CPU_CTRL);
+
+	for (i = 0; i < DIV_ROUND_UP(32, 4); i++)
+		gic_data[gic_nr].saved_dist_pri[i] = readl_relaxed(dist_base +
+							GIC_DIST_PRI + i * 4);
+
 	ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_enable);
 	for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
 		ptr[i] = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
@@ -537,10 +791,11 @@
 		writel_relaxed(ptr[i], dist_base + GIC_DIST_CONFIG + i * 4);
 
 	for (i = 0; i < DIV_ROUND_UP(32, 4); i++)
-		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
+		writel_relaxed(gic_data[gic_nr].saved_dist_pri[i],
+			dist_base + GIC_DIST_PRI + i * 4);
 
 	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
+	writel_relaxed(saved_cpu_ctrl, cpu_base + GIC_CPU_CTRL);
 }
 
 static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
@@ -597,27 +852,11 @@
 }
 #endif
 
-static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
-				irq_hw_number_t hw)
-{
-	if (hw < 32) {
-		irq_set_percpu_devid(irq);
-		irq_set_chip_and_handler(irq, &gic_chip,
-					 handle_percpu_devid_irq);
-		set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
-	} else {
-		irq_set_chip_and_handler(irq, &gic_chip,
-					 handle_fasteoi_irq);
-		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
-	}
-	irq_set_chip_data(irq, d->host_data);
-	return 0;
-}
-
-static int gic_irq_domain_xlate(struct irq_domain *d,
-				struct device_node *controller,
-				const u32 *intspec, unsigned int intsize,
-				unsigned long *out_hwirq, unsigned int *out_type)
+#ifdef CONFIG_OF
+static int gic_irq_domain_dt_translate(struct irq_domain *d,
+				       struct device_node *controller,
+				       const u32 *intspec, unsigned int intsize,
+				       unsigned long *out_hwirq, unsigned int *out_type)
 {
 	if (d->of_node != controller)
 		return -EINVAL;
@@ -634,23 +873,26 @@
 	*out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
 	return 0;
 }
+#endif
 
 const struct irq_domain_ops gic_irq_domain_ops = {
-	.map = gic_irq_domain_map,
-	.xlate = gic_irq_domain_xlate,
+#ifdef CONFIG_OF
+	.dt_translate = gic_irq_domain_dt_translate,
+#endif
 };
 
 void __init gic_init_bases(unsigned int gic_nr, int irq_start,
 			   void __iomem *dist_base, void __iomem *cpu_base,
-			   u32 percpu_offset, struct device_node *node)
+			   u32 percpu_offset)
 {
-	irq_hw_number_t hwirq_base;
 	struct gic_chip_data *gic;
-	int gic_irqs, irq_base;
+	struct irq_domain *domain;
+	int gic_irqs, rc;
 
 	BUG_ON(gic_nr >= MAX_GIC_NR);
 
 	gic = &gic_data[gic_nr];
+	domain = &gic->domain;
 #ifdef CONFIG_GIC_NON_BANKED
 	if (percpu_offset) { /* Frankein-GIC without banked registers... */
 		unsigned int cpu;
@@ -658,11 +900,8 @@
 		gic->dist_base.percpu_base = alloc_percpu(void __iomem *);
 		gic->cpu_base.percpu_base = alloc_percpu(void __iomem *);
 		if (WARN_ON(!gic->dist_base.percpu_base ||
-			    !gic->cpu_base.percpu_base)) {
-			free_percpu(gic->dist_base.percpu_base);
-			free_percpu(gic->cpu_base.percpu_base);
-			return;
-		}
+			    !gic->cpu_base.percpu_base))
+			goto init_bases_err;
 
 		for_each_possible_cpu(cpu) {
 			unsigned long offset = percpu_offset * cpu_logical_map(cpu);
@@ -686,12 +925,13 @@
 	 * For primary GICs, skip over SGIs.
 	 * For secondary GICs, skip over PPIs, too.
 	 */
-	if (gic_nr == 0 && (irq_start & 31) > 0) {
-		hwirq_base = 16;
-		if (irq_start != -1)
-			irq_start = (irq_start & ~31) + 16;
-	} else {
-		hwirq_base = 32;
+	domain->hwirq_base = 32;
+	if (gic_nr == 0) {
+		if ((irq_start & 31) > 0) {
+			domain->hwirq_base = 16;
+			if (irq_start != -1)
+				irq_start = (irq_start & ~31) + 16;
+		}
 	}
 
 	/*
@@ -704,22 +944,33 @@
 		gic_irqs = 1020;
 	gic->gic_irqs = gic_irqs;
 
-	gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
-	irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, numa_node_id());
-	if (IS_ERR_VALUE(irq_base)) {
+	domain->nr_irq = gic_irqs - domain->hwirq_base;
+	domain->irq_base = irq_alloc_descs(irq_start, 16, domain->nr_irq,
+					   numa_node_id());
+	if (IS_ERR_VALUE(domain->irq_base)) {
 		WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
 		     irq_start);
-		irq_base = irq_start;
+		domain->irq_base = irq_start;
 	}
-	gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
-				    hwirq_base, &gic_irq_domain_ops, gic);
-	if (WARN_ON(!gic->domain))
-		return;
+	domain->priv = gic;
+	domain->ops = &gic_irq_domain_ops;
+	rc = irq_domain_add(domain);
+	if (rc) {
+		WARN(1, "Unable to create irq_domain\n");
+		goto init_bases_err;
+	}
+	irq_domain_register(domain);
 
 	gic_chip.flags |= gic_arch_extn.flags;
 	gic_dist_init(gic);
 	gic_cpu_init(gic);
 	gic_pm_init(gic);
+
+	return;
+
+init_bases_err:
+	free_percpu(gic->dist_base.percpu_base);
+	free_percpu(gic->cpu_base.percpu_base);
 }
 
 void __cpuinit gic_secondary_init(unsigned int gic_nr)
@@ -733,23 +984,68 @@
 void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 {
 	int cpu;
+	unsigned long sgir;
 	unsigned long map = 0;
+#ifdef CONFIG_ARCH_MSM8625
+	unsigned long flags;
+#endif
 
 	/* Convert our logical CPU mask into a physical one. */
 	for_each_cpu(cpu, mask)
 		map |= 1 << cpu_logical_map(cpu);
 
+	sgir = (map << 16) | irq;
+	if (is_cpu_secure())
+		sgir |= (1 << 15);
+
 	/*
 	 * Ensure that stores to Normal memory are visible to the
 	 * other CPUs before issuing the IPI.
 	 */
 	dsb();
 
+#ifdef CONFIG_ARCH_MSM8625
+	raw_spin_lock_irqsave(&irq_controller_lock, flags);
+#endif
 	/* this always happens on GIC0 */
-	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+
+	writel_relaxed(sgir,
+			gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+#ifdef CONFIG_ARCH_MSM8625
+	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+#endif
+	mb();
 }
 #endif
 
+void gic_set_irq_secure(unsigned int irq)
+{
+	unsigned int gicd_isr_reg, gicd_pri_reg;
+	unsigned int mask = 0xFFFFFF00;
+	struct gic_chip_data *gic_data = &gic_data[0];
+	struct irq_data *d = irq_get_irq_data(irq);
+
+	if (is_cpu_secure()) {
+		raw_spin_lock(&irq_controller_lock);
+		gicd_isr_reg = readl_relaxed(gic_dist_base(d) +
+				GIC_DIST_ISR + gic_irq(d) / 32 * 4);
+		gicd_isr_reg &= ~BIT(gic_irq(d) % 32);
+		writel_relaxed(gicd_isr_reg, gic_dist_base(d) +
+				GIC_DIST_ISR + gic_irq(d) / 32 * 4);
+		/* Also increase the priority of that irq */
+		gicd_pri_reg = readl_relaxed(gic_dist_base(d) +
+					GIC_DIST_PRI + (gic_irq(d) * 4 / 4));
+		gicd_pri_reg &= mask;
+		gicd_pri_reg |= 0x80; /* Priority of 0x80 > 0xA0 */
+		writel_relaxed(gicd_pri_reg, gic_dist_base(d) + GIC_DIST_PRI +
+				gic_irq(d) * 4 / 4);
+		mb();
+		raw_spin_unlock(&irq_controller_lock);
+	} else {
+		WARN(1, "Trying to run secure operation from Non-secure mode");
+	}
+}
+
 #ifdef CONFIG_OF
 static int gic_cnt __initdata = 0;
 
@@ -759,6 +1055,7 @@
 	void __iomem *dist_base;
 	u32 percpu_offset;
 	int irq;
+	struct irq_domain *domain = &gic_data[gic_cnt].domain;
 
 	if (WARN_ON(!node))
 		return -ENODEV;
@@ -772,7 +1069,9 @@
 	if (of_property_read_u32(node, "cpu-offset", &percpu_offset))
 		percpu_offset = 0;
 
-	gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node);
+	domain->of_node = of_node_get(node);
+
+	gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset);
 
 	if (parent) {
 		irq = irq_of_parse_and_map(node, 0);
@@ -782,3 +1081,156 @@
 	return 0;
 }
 #endif
+/* before calling this function the interrupts should be disabled
+ * and the irq must be disabled at gic to avoid spurious interrupts */
+bool gic_is_spi_pending(unsigned int irq)
+{
+	struct irq_data *d = irq_get_irq_data(irq);
+	struct gic_chip_data *gic_data = &gic_data[0];
+	u32 mask, val;
+
+	WARN_ON(!irqs_disabled());
+	raw_spin_lock(&irq_controller_lock);
+	mask = 1 << (gic_irq(d) % 32);
+	val = readl(gic_dist_base(d) +
+			GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
+	/* warn if the interrupt is enabled */
+	WARN_ON(val & mask);
+	val = readl(gic_dist_base(d) +
+			GIC_DIST_PENDING_SET + (gic_irq(d) / 32) * 4);
+	raw_spin_unlock(&irq_controller_lock);
+	return (bool) (val & mask);
+}
+
+/* before calling this function the interrupts should be disabled
+ * and the irq must be disabled at gic to avoid spurious interrupts */
+void gic_clear_spi_pending(unsigned int irq)
+{
+	struct gic_chip_data *gic_data = &gic_data[0];
+	struct irq_data *d = irq_get_irq_data(irq);
+
+	u32 mask, val;
+	WARN_ON(!irqs_disabled());
+	raw_spin_lock(&irq_controller_lock);
+	mask = 1 << (gic_irq(d) % 32);
+	val = readl(gic_dist_base(d) +
+			GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
+	/* warn if the interrupt is enabled */
+	WARN_ON(val & mask);
+	writel(mask, gic_dist_base(d) +
+			GIC_DIST_PENDING_CLEAR + (gic_irq(d) / 32) * 4);
+	raw_spin_unlock(&irq_controller_lock);
+}
+
+#ifdef CONFIG_ARCH_MSM8625
+ /*
+  *  Check for any interrupts which are enabled are pending
+  *  in the pending set or not.
+  *  Return :
+  *       0 : No pending interrupts
+  *       1 : Pending interrupts other than A9_M2A_5
+  */
+unsigned int msm_gic_spi_ppi_pending(void)
+{
+	unsigned int i, bit = 0;
+	unsigned int pending_enb = 0, pending = 0;
+	unsigned long value = 0;
+	struct gic_chip_data *gic = &gic_data[0];
+	void __iomem *base = gic_data_dist_base(gic);
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&irq_controller_lock, flags);
+	/*
+	 * PPI and SGI to be included.
+	 * MSM8625_INT_A9_M2A_5 needs to be ignored, as A9_M2A_5
+	 * requesting sleep triggers it
+	 */
+	for (i = 0; (i * 32) < gic->max_irq; i++) {
+		pending = readl_relaxed(base +
+				GIC_DIST_PENDING_SET + i * 4);
+		pending_enb = readl_relaxed(base +
+				GIC_DIST_ENABLE_SET + i * 4);
+		value = pending & pending_enb;
+
+		if (value) {
+			for (bit = 0; bit < 32; bit++) {
+				bit = find_next_bit(&value, 32, bit);
+				if ((bit + 32 * i) != MSM8625_INT_A9_M2A_5) {
+					raw_spin_unlock_irqrestore(
+						&irq_controller_lock, flags);
+					return 1;
+				}
+			}
+		}
+	}
+	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+
+	return 0;
+}
+
+void msm_gic_save(bool modem_wake, int from_idle)
+{
+	unsigned int i;
+	struct gic_chip_data *gic = &gic_data[0];
+	void __iomem *base = gic_data_dist_base(gic);
+
+	gic_cpu_save(0);
+	gic_dist_save(0);
+
+	/* Disable all the Interrupts, before we enter pc */
+	for (i = 0; (i * 32) < gic->max_irq; i++) {
+		raw_spin_lock(&irq_controller_lock);
+		writel_relaxed(0xffffffff, base
+				+ GIC_DIST_ENABLE_CLEAR + i * 4);
+		raw_spin_unlock(&irq_controller_lock);
+	}
+}
+
+void msm_gic_restore(void)
+{
+	gic_dist_restore(0);
+	gic_cpu_restore(0);
+}
+
+/*
+ * 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.
+ */
+void core1_gic_configure_and_raise(void)
+{
+	struct gic_chip_data *gic = &gic_data[0];
+	void __iomem *base = gic_data_dist_base(gic);
+	unsigned int value = 0;
+	unsigned long flags;
+
+	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);
+	mb();
+
+	value = __raw_readl(base + GIC_DIST_TARGET + 0x24);
+	value |= BIT(13);
+	__raw_writel(value, base + GIC_DIST_TARGET + 0x24);
+	mb();
+
+	value = __raw_readl(base + GIC_DIST_TARGET + 0x28);
+	value |= BIT(1);
+	__raw_writel(value, base + GIC_DIST_TARGET + 0x28);
+	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);
+}
+#endif
diff --git a/arch/arm/configs/fsm9xxx-perf_defconfig b/arch/arm/configs/fsm9xxx-perf_defconfig
new file mode 100644
index 0000000..18f6d7f
--- /dev/null
+++ b/arch/arm/configs/fsm9xxx-perf_defconfig
@@ -0,0 +1,184 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCALVERSION="$(KERNEL_LOCAL_VERSION)"
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_ASHMEM=y
+CONFIG_EMBEDDED=y
+# CONFIG_PERF_EVENTS is not set
+CONFIG_SLAB=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_FSM9XXX=y
+# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_MSM7X00A_USE_DG_TIMER=y
+CONFIG_MSM7X00A_SLEEP_WAIT_FOR_INTERRUPT=y
+CONFIG_MSM7X00A_IDLE_SLEEP_WAIT_FOR_INTERRUPT=y
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG3=y
+# CONFIG_MSM_SMD_DEBUG is not set
+CONFIG_MSM_ONCRPCROUTER=y
+# CONFIG_MSM_ONCRPCROUTER_DEBUG is not set
+# CONFIG_MSM_HW3D is not set
+# CONFIG_QSD_AUDIO is not set
+# CONFIG_SURF_FFA_GPIO_KEYPAD is not set
+CONFIG_MSM_WATCHDOG=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_VMSPLIT_2G=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="init=/sbin/init root=/dev/ram rw initrd=0x11000000,16M console=ttyDCC0 mem=88M ip=dhcp"
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=y
+CONFIG_IPV6_TUNNEL=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_MROUTE=y
+CONFIG_IPV6_PIMSM_V2=y
+# CONFIG_NET_ACTIVITY_STATS is not set
+CONFIG_RFKILL=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_MTD=y
+CONFIG_MTD_TESTS=m
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=8
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_PMIC8058_XOADC=y
+CONFIG_QFP_FUSE=y
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+# CONFIG_MSM_RMNET is not set
+CONFIG_QFEC=y
+CONFIG_SMC91X=y
+CONFIG_SMSC911X=y
+CONFIG_SLIP=y
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+# CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_CONSOLE=y
+# CONFIG_DIAG_OVER_USB is not set
+# CONFIG_HW_RANDOM is not set
+CONFIG_DCC_TTY=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_SSBI=y
+CONFIG_SPI=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_SENSORS_MSM_ADC=y
+CONFIG_PMIC8058=y
+# CONFIG_MFD_PM8XXX_PWM is not set
+# CONFIG_MFD_PM8XXX_MISC is not set
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_PM8058_XO=y
+# CONFIG_USB_SUPPORT is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_SWITCH=y
+CONFIG_SWITCH_GPIO=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DEBUG=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_MSM_SSBI=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_DISABLE_TAGS_ECC=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+# CONFIG_STACKTRACE is not set
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set
+CONFIG_CRYPTO_NULL=y
+CONFIG_CRYPTO_CRYPTD=y
+CONFIG_CRYPTO_TEST=m
+CONFIG_CRYPTO_CTR=y
+CONFIG_CRYPTO_CTS=y
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_DEV_QCRYPTO=y
+CONFIG_CRYPTO_DEV_QCE=y
+CONFIG_CRYPTO_DEV_OTA_CRYPTO=y
+CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/fsm9xxx_defconfig b/arch/arm/configs/fsm9xxx_defconfig
new file mode 100644
index 0000000..4707556
--- /dev/null
+++ b/arch/arm/configs/fsm9xxx_defconfig
@@ -0,0 +1,186 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCALVERSION="$(KERNEL_LOCAL_VERSION)"
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_KALLSYMS_ALL=y
+CONFIG_ASHMEM=y
+CONFIG_EMBEDDED=y
+# CONFIG_PERF_EVENTS is not set
+CONFIG_SLAB=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_FSM9XXX=y
+# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_MSM7X00A_USE_DG_TIMER=y
+CONFIG_MSM7X00A_SLEEP_WAIT_FOR_INTERRUPT=y
+CONFIG_MSM7X00A_IDLE_SLEEP_WAIT_FOR_INTERRUPT=y
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG3=y
+CONFIG_MSM_ONCRPCROUTER=y
+# CONFIG_MSM_HW3D is not set
+# CONFIG_QSD_AUDIO is not set
+# CONFIG_SURF_FFA_GPIO_KEYPAD is not set
+CONFIG_MSM_WATCHDOG=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_VMSPLIT_2G=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="init=/sbin/init root=/dev/ram rw initrd=0x11000000,16M console=ttyDCC0 mem=88M ip=dhcp"
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=y
+CONFIG_IPV6_TUNNEL=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_MROUTE=y
+CONFIG_IPV6_PIMSM_V2=y
+# CONFIG_NET_ACTIVITY_STATS is not set
+CONFIG_RFKILL=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_MTD=y
+CONFIG_MTD_TESTS=m
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=8
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_PMIC8058_XOADC=y
+CONFIG_QFP_FUSE=y
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+# CONFIG_MSM_RMNET is not set
+CONFIG_QFEC=y
+CONFIG_SMC91X=y
+CONFIG_SMSC911X=y
+CONFIG_SLIP=y
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+# CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_CONSOLE=y
+# CONFIG_DIAG_OVER_USB is not set
+# CONFIG_HW_RANDOM is not set
+CONFIG_DCC_TTY=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_SSBI=y
+CONFIG_SPI=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_SENSORS_MSM_ADC=y
+CONFIG_PMIC8058=y
+# CONFIG_MFD_PM8XXX_PWM is not set
+# CONFIG_MFD_PM8XXX_MISC is not set
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_PM8058_XO=y
+# CONFIG_USB_SUPPORT is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_SWITCH=y
+CONFIG_SWITCH_GPIO=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DEBUG=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_MSM_SSBI=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_DISABLE_TAGS_ECC=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+CONFIG_SCHEDSTATS=y
+# CONFIG_STACKTRACE is not set
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set
+CONFIG_CRYPTO_NULL=y
+CONFIG_CRYPTO_CRYPTD=y
+CONFIG_CRYPTO_TEST=m
+CONFIG_CRYPTO_CTR=y
+CONFIG_CRYPTO_CTS=y
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_DEV_QCRYPTO=y
+CONFIG_CRYPTO_DEV_QCE=y
+CONFIG_CRYPTO_DEV_OTA_CRYPTO=y
+CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/msm-copper_defconfig b/arch/arm/configs/msm-copper_defconfig
new file mode 100644
index 0000000..e0811ac
--- /dev/null
+++ b/arch/arm/configs/msm-copper_defconfig
@@ -0,0 +1,201 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+# CONFIG_FAIR_GROUP_SCHED is not set
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_ASHMEM=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MSMCOPPER=y
+CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y
+# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_KERNEL_PMEM_EBI_REGION=y
+CONFIG_CPU_HAS_L2_PMU=y
+# CONFIG_MSM_FIQ_SUPPORT is not set
+# CONFIG_MSM_PROC_COMM is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_IPC_ROUTER=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+# CONFIG_MSM_HW3D is not set
+CONFIG_MSM_PIL_LPASS_QDSP6V5=y
+CONFIG_MSM_TZ_LOG=y
+CONFIG_MSM_PIL_PRONTO=y
+CONFIG_MSM_DIRECT_SCLK_ACCESS=y
+CONFIG_MSM_OCMEM=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+# CONFIG_SMP_ON_UP is not set
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_VMALLOC_RESERVE=0x19000000
+CONFIG_USE_OF=y
+CONFIG_ARM_APPENDED_DTB=y
+CONFIG_ARM_ATAG_DTB_COMPAT=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_SUSPEND is not set
+CONFIG_NET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_NETDEVICES=y
+# CONFIG_MSM_RMNET is not set
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_SERIAL_MSM_HSL=y
+CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_DIAG_CHAR=y
+CONFIG_HW_RANDOM=y
+CONFIG_DCC_TTY=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_QUP=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=m
+CONFIG_SPMI=y
+CONFIG_SPMI_MSM_PMIC_ARB=y
+CONFIG_MSM_QPNP=y
+CONFIG_SLIMBUS=y
+CONFIG_SLIMBUS_MSM_CTRL=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_SUPPLY=y
+# CONFIG_BATTERY_MSM is not set
+# CONFIG_HWMON is not set
+CONFIG_REGULATOR_STUB=y
+CONFIG_REGULATOR_QPNP=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+# CONFIG_RC_CORE is not set
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+CONFIG_VIDEOBUF2_MSM_MEM=y
+# CONFIG_VIDEO_CAPTURE_DRIVERS is not set
+# CONFIG_RADIO_ADAPTERS is not set
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_FB=y
+CONFIG_FB_VIRTUAL=y
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB_GADGET=y
+CONFIG_USB_CI13XXX_MSM=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
+CONFIG_MMC_MSM=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_SWITCH=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_MSM_SSBI=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_BAMDMA=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_LL=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_KEYS=y
+CONFIG_CRYPTO_AUTHENC=y
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRC_CCITT=y
+CONFIG_LIBCRC32C=y
+CONFIG_HW_RANDOM_MSM=y
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
new file mode 100644
index 0000000..afea042
--- /dev/null
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -0,0 +1,343 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCALVERSION="$(KERNEL_LOCAL_VERSION)-perf"
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_ASHMEM=y
+CONFIG_EMBEDDED=y
+CONFIG_SLAB=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MSM7X27=y
+CONFIG_ARCH_MSM8625=y
+CONFIG_MSM_SOC_REV_A=y
+# CONFIG_MACH_MSM7X27_SURF is not set
+# CONFIG_MACH_MSM7X27_FFA is not set
+# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_MSM7X00A_USE_DG_TIMER=y
+# CONFIG_MSM_FIQ_SUPPORT is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG4=y
+# CONFIG_MSM_SMD_DEBUG is not set
+# CONFIG_MSM_RESET_MODEM is not set
+# CONFIG_MSM_SMD_NMEA is not set
+# CONFIG_MSM_SMD_QMI is not set
+CONFIG_MSM_ONCRPCROUTER=y
+# CONFIG_MSM_RPCSERVER_TIME_REMOTE is not set
+CONFIG_MSM_RMT_STORAGE_CLIENT=y
+# CONFIG_MSM_HW3D is not set
+CONFIG_MSM7X27A_AUDIO=y
+CONFIG_MSM_DMA_TEST=y
+CONFIG_MSM_SLEEP_STATS_DEVICE=y
+CONFIG_BT_MSM_PINTEST=y
+CONFIG_MSM_RPC_VIBRATOR=y
+CONFIG_PM8XXX_RPC_VIBRATOR=y
+CONFIG_MSM_SPM_V2=y
+CONFIG_ARM_THUMBEE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_VMALLOC_RESERVE=0xC800000
+CONFIG_CP_ACCESS=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="init=/sbin/init root=/dev/ram rw initrd=0x11000000,16M console=ttyDCC0 mem=88M"
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_WAKELOCK=y
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_TUNNEL=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_BT=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_IBS=y
+CONFIG_MSM_BT_POWER=y
+CONFIG_CFG80211=m
+# CONFIG_CFG80211_WEXT is not set
+CONFIG_RFKILL=y
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
+CONFIG_MTD=y
+CONFIG_MTD_TESTS=m
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_NETDEVICES=y
+CONFIG_SMC91X=y
+CONFIG_SMSC911X=y
+CONFIG_LIBRA_SDIOIF=m
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH=y
+CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C=y
+CONFIG_TOUCHSCREEN_FT5X06=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+# CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_CONSOLE=y
+CONFIG_SERIAL_MSM_HS=y
+# CONFIG_SERIAL_MSM_CLOCK_CONTROL is not set
+CONFIG_DIAG_CHAR=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_MSM is not set
+CONFIG_I2C_QUP=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_SX150X=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_BATTERY_MSM=y
+CONFIG_SENSORS_MSM_ADC=y
+CONFIG_MARIMBA_CORE=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+# CONFIG_RC_CORE is not set
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+CONFIG_VIDEOBUF2_MSM_MEM=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_MSM_CAMERA_V4L2=y
+CONFIG_OV5647=y
+CONFIG_AD5046_ACT=y
+CONFIG_WEBCAM_OV9726=y
+CONFIG_MT9E013=y
+CONFIG_S5K4E1=y
+CONFIG_DW9712_ACT=y
+CONFIG_MSM_CAMERA_FLASH_SC628A=y
+CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_ACTUATOR=y
+CONFIG_OV7692=y
+CONFIG_RADIO_TAVARUA=y
+CONFIG_MSM_KGSL=y
+CONFIG_FB=y
+CONFIG_FB_MSM=y
+# CONFIG_FB_MSM_BACKLIGHT is not set
+CONFIG_FB_MSM_TRIPLE_BUFFER=y
+CONFIG_FB_MSM_MDP30=y
+CONFIG_FB_MSM_MDP303=y
+CONFIG_FB_MSM_LCDC_TRULY_HVGA_IPS3P2335_PT_PANEL=y
+CONFIG_FB_MSM_MIPI_PANEL_DETECT=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_MSM_SOC=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_EHSET=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_EHCI_MSM_72K=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
+CONFIG_USB_EHSET_TEST_FIXTURE=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_MSM_72K=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_RMNET_SMD_CTL_CHANNEL="DATA40_CNTL"
+CONFIG_RMNET_SMD_DATA_CHANNEL="DATA40"
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
+CONFIG_MMC_MSM=y
+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_LEDS_PMIC_MPP=y
+CONFIG_SWITCH=y
+CONFIG_SWITCH_GPIO=y
+CONFIG_RTC_CLASS=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_DISABLE_TAGS_ECC=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_SHIRQ=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUG_INFO=y
+CONFIG_ENABLE_DEFAULT_TRACERS=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
new file mode 100644
index 0000000..7e24b0d
--- /dev/null
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -0,0 +1,351 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCALVERSION="$(KERNEL_LOCAL_VERSION)"
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_ASHMEM=y
+CONFIG_EMBEDDED=y
+CONFIG_SLAB=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MSM7X27=y
+CONFIG_ARCH_MSM8625=y
+CONFIG_MSM_SOC_REV_A=y
+# CONFIG_MACH_MSM7X27_SURF is not set
+# CONFIG_MACH_MSM7X27_FFA is not set
+# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_MSM7X00A_USE_DG_TIMER=y
+# CONFIG_MSM_FIQ_SUPPORT is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG4=y
+# CONFIG_MSM_SMD_DEBUG is not set
+# CONFIG_MSM_RESET_MODEM is not set
+# CONFIG_MSM_SMD_NMEA is not set
+# CONFIG_MSM_SMD_QMI is not set
+CONFIG_MSM_ONCRPCROUTER=y
+# CONFIG_MSM_RPCSERVER_TIME_REMOTE is not set
+CONFIG_MSM_RMT_STORAGE_CLIENT=y
+# CONFIG_MSM_HW3D is not set
+CONFIG_MSM7X27A_AUDIO=y
+CONFIG_MSM_DMA_TEST=y
+CONFIG_MSM_SLEEP_STATS_DEVICE=y
+CONFIG_BT_MSM_PINTEST=y
+CONFIG_MSM_RPC_VIBRATOR=y
+CONFIG_PM8XXX_RPC_VIBRATOR=y
+CONFIG_MSM_SPM_V2=y
+CONFIG_ARM_THUMBEE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_VMALLOC_RESERVE=0xC800000
+CONFIG_CP_ACCESS=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="init=/sbin/init root=/dev/ram rw initrd=0x11000000,16M console=ttyDCC0 mem=88M"
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_WAKELOCK=y
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_TUNNEL=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_BT=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_IBS=y
+CONFIG_MSM_BT_POWER=y
+CONFIG_CFG80211=m
+# CONFIG_CFG80211_WEXT is not set
+CONFIG_RFKILL=y
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
+CONFIG_MTD=y
+CONFIG_MTD_TESTS=m
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_NETDEVICES=y
+CONFIG_SMC91X=y
+CONFIG_SMSC911X=y
+CONFIG_LIBRA_SDIOIF=m
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH=y
+CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C=y
+CONFIG_TOUCHSCREEN_FT5X06=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+# CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_CONSOLE=y
+CONFIG_SERIAL_MSM_HS=y
+# CONFIG_SERIAL_MSM_CLOCK_CONTROL is not set
+CONFIG_DIAG_CHAR=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_DCC_TTY=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_MSM is not set
+CONFIG_I2C_QUP=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_SX150X=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_BATTERY_MSM=y
+CONFIG_SENSORS_MSM_ADC=y
+CONFIG_MARIMBA_CORE=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+# CONFIG_RC_CORE is not set
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+CONFIG_VIDEOBUF2_MSM_MEM=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_MSM_CAMERA_V4L2=y
+CONFIG_OV5647=y
+CONFIG_AD5046_ACT=y
+CONFIG_WEBCAM_OV9726=y
+CONFIG_MT9E013=y
+CONFIG_S5K4E1=y
+CONFIG_DW9712_ACT=y
+CONFIG_MSM_CAMERA_FLASH_SC628A=y
+CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_ACTUATOR=y
+CONFIG_OV7692=y
+CONFIG_RADIO_TAVARUA=y
+CONFIG_MSM_KGSL=y
+CONFIG_FB=y
+CONFIG_FB_MSM=y
+# CONFIG_FB_MSM_BACKLIGHT is not set
+CONFIG_FB_MSM_TRIPLE_BUFFER=y
+CONFIG_FB_MSM_MDP30=y
+CONFIG_FB_MSM_MDP303=y
+CONFIG_FB_MSM_LCDC_TRULY_HVGA_IPS3P2335_PT_PANEL=y
+CONFIG_FB_MSM_MIPI_PANEL_DETECT=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_MSM_SOC=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_EHSET=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_EHCI_MSM_72K=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
+CONFIG_USB_EHSET_TEST_FIXTURE=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_MSM_72K=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_RMNET_SMD_CTL_CHANNEL="DATA40_CNTL"
+CONFIG_RMNET_SMD_DATA_CHANNEL="DATA40"
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
+CONFIG_MMC_MSM=y
+CONFIG_MMC_MSM_CARD_HW_DETECTION=y
+CONFIG_MMC_MSM_SDC3_SUPPORT=y
+CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT=y
+CONFIG_LEDS_MSM_PDM=y
+CONFIG_LEDS_PMIC_MPP=y
+CONFIG_SWITCH=y
+CONFIG_SWITCH_GPIO=y
+CONFIG_RTC_CLASS=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_DISABLE_TAGS_ECC=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_SHIRQ=y
+CONFIG_LOCKUP_DETECTOR=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_SLAB=y
+CONFIG_DEBUG_SLAB_LEAK=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_LIST=y
+CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_ENABLE_DEFAULT_TRACERS=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/msm7630-perf_defconfig b/arch/arm/configs/msm7630-perf_defconfig
new file mode 100644
index 0000000..4000a0f
--- /dev/null
+++ b/arch/arm/configs/msm7630-perf_defconfig
@@ -0,0 +1,377 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCALVERSION="-perf"
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_ASHMEM=y
+CONFIG_EMBEDDED=y
+CONFIG_SLAB=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MSM7X30=y
+# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG3=y
+CONFIG_MSM_SDIO_DMUX=y
+CONFIG_MSM_SDIO_CMUX=y
+CONFIG_MSM_SDIO_CTL=y
+CONFIG_MSM_ONCRPCROUTER=y
+CONFIG_MSM_RPC_WATCHDOG=y
+CONFIG_MSM_RMT_STORAGE_CLIENT=y
+# CONFIG_MSM_HW3D is not set
+# CONFIG_QSD_AUDIO is not set
+CONFIG_MSM_MEMORY_LOW_POWER_MODE=y
+CONFIG_MSM_MEMORY_LOW_POWER_MODE_IDLE_RETENTION=y
+CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_DEEP_POWER_DOWN=y
+CONFIG_MSM_IDLE_WAIT_ON_MODEM=2000
+CONFIG_MSM_STANDALONE_POWER_COLLAPSE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_VMALLOC_RESERVE=0x1A000000
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="init=/sbin/init root=/dev/ram rw initrd=0x11000000,16M console=ttyDCC0 mem=88M ip=dhcp"
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_WAKELOCK=y
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_TUNNEL=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_SCH_SFQ=y
+CONFIG_NET_SCH_TBF=y
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_INGRESS=y
+CONFIG_NET_CLS_BASIC=y
+CONFIG_NET_CLS_TCINDEX=y
+CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=m
+CONFIG_NET_EMATCH=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_MIRRED=y
+CONFIG_BT=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_IBS=y
+CONFIG_MSM_BT_POWER=y
+CONFIG_CFG80211=y
+# CONFIG_CFG80211_WEXT is not set
+CONFIG_RFKILL=y
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
+CONFIG_MTD=y
+CONFIG_MTD_TESTS=m
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=8
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_HAPTIC_ISA1200=y
+CONFIG_PMIC8XXX_UPL=y
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_MSM_RMNET_SDIO=y
+CONFIG_SMC91X=y
+CONFIG_SMSC911X=y
+CONFIG_SLIP=y
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_LIBRA_SDIOIF=m
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_PMIC8XXX=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_MSM=y
+CONFIG_TOUCHSCREEN_TSC2007=y
+CONFIG_TOUCHSCREEN_CY8C_TS=y
+CONFIG_TOUCHSCREEN_CYTTSP_I2C_QC=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+CONFIG_BOSCH_BMA150=y
+# CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_HS=y
+CONFIG_DIAG_CHAR=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_QUP=y
+CONFIG_I2C_SSBI=y
+CONFIG_SPI=y
+CONFIG_SPI_QSD=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_BATTERY_MSM=y
+CONFIG_SENSORS_MSM_ADC=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_MSM_POPMEM=y
+CONFIG_PMIC8058=y
+CONFIG_MARIMBA_CORE=y
+CONFIG_MARIMBA_CODEC=y
+CONFIG_TIMPANI_CODEC=y
+# CONFIG_MFD_PM8XXX_DEBUG is not set
+# CONFIG_MFD_PM8XXX_PWM is not set
+# CONFIG_MFD_PM8XXX_MISC is not set
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+CONFIG_VIDEOBUF2_MSM_MEM=y
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+CONFIG_RADIO_TAVARUA=y
+CONFIG_MSM_KGSL=y
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+CONFIG_FB_MSM=y
+# CONFIG_FB_MSM_BACKLIGHT is not set
+CONFIG_FB_MSM_LOGO=y
+CONFIG_FB_MSM_TRIPLE_BUFFER=y
+CONFIG_FB_MSM_MDP40=y
+CONFIG_FB_MSM_OVERLAY=y
+CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM=y
+CONFIG_FB_MSM_HDMI_ADV7520_PANEL=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+# CONFIG_SND_DRIVERS is not set
+# CONFIG_SND_ARM is not set
+# CONFIG_SND_SPI is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_MSM7KV2_SOC=y
+CONFIG_SND_MVS_SOC=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_EHSET=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_EHCI_MSM_72K=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
+CONFIG_USB_EHSET_TEST_FIXTURE=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_MSM_72K=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_RMNET_SMD_CTL_CHANNEL="DATA40_CNTL"
+CONFIG_RMNET_SMD_DATA_CHANNEL="DATA40"
+CONFIG_RMNET_SDIO_SMD_DATA_CHANNEL=""
+CONFIG_USB_MSM_ACA=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
+CONFIG_MMC_MSM=y
+CONFIG_MMC_MSM_CARD_HW_DETECTION=y
+# CONFIG_MMC_MSM_SDC1_SUPPORT is not set
+CONFIG_MMC_MSM_SDC2_8_BIT_SUPPORT=y
+CONFIG_MMC_MSM_SDC3_SUPPORT=y
+CONFIG_MMC_MSM_SDC4_SUPPORT=y
+CONFIG_LEDS_PMIC8058=y
+CONFIG_SWITCH=y
+CONFIG_SWITCH_GPIO=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DEBUG=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_MSM_SSBI=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_DISABLE_TAGS_ECC=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCE=m
+CONFIG_CRYPTO_DEV_QCEDEV=m
+CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/msm7630_defconfig b/arch/arm/configs/msm7630_defconfig
new file mode 100644
index 0000000..fdcd566
--- /dev/null
+++ b/arch/arm/configs/msm7630_defconfig
@@ -0,0 +1,385 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_ASHMEM=y
+CONFIG_EMBEDDED=y
+CONFIG_SLAB=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MSM7X30=y
+# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG3=y
+CONFIG_MSM_SDIO_DMUX=y
+CONFIG_MSM_SDIO_CMUX=y
+CONFIG_MSM_SDIO_CTL=y
+CONFIG_MSM_ONCRPCROUTER=y
+CONFIG_MSM_RPC_WATCHDOG=y
+CONFIG_MSM_RMT_STORAGE_CLIENT=y
+# CONFIG_MSM_HW3D is not set
+# CONFIG_QSD_AUDIO is not set
+CONFIG_MSM_MEMORY_LOW_POWER_MODE=y
+CONFIG_MSM_MEMORY_LOW_POWER_MODE_IDLE_RETENTION=y
+CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_DEEP_POWER_DOWN=y
+CONFIG_MSM_IDLE_WAIT_ON_MODEM=2000
+CONFIG_MSM_STANDALONE_POWER_COLLAPSE=y
+CONFIG_STRICT_MEMORY_RWX=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_VMALLOC_RESERVE=0x1A000000
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="init=/sbin/init root=/dev/ram rw initrd=0x11000000,16M console=ttyDCC0 mem=88M ip=dhcp"
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_WAKELOCK=y
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_TUNNEL=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_SCH_SFQ=y
+CONFIG_NET_SCH_TBF=y
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_INGRESS=y
+CONFIG_NET_CLS_BASIC=y
+CONFIG_NET_CLS_TCINDEX=y
+CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=m
+CONFIG_NET_EMATCH=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_MIRRED=y
+CONFIG_BT=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_IBS=y
+CONFIG_MSM_BT_POWER=y
+CONFIG_CFG80211=y
+# CONFIG_CFG80211_WEXT is not set
+CONFIG_RFKILL=y
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
+CONFIG_MTD=y
+CONFIG_MTD_TESTS=m
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=8
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_HAPTIC_ISA1200=y
+CONFIG_PMIC8XXX_UPL=y
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_MSM_RMNET_SDIO=y
+CONFIG_SMC91X=y
+CONFIG_SMSC911X=y
+CONFIG_SLIP=y
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_LIBRA_SDIOIF=m
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_PMIC8XXX=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_MSM=y
+CONFIG_TOUCHSCREEN_TSC2007=y
+CONFIG_TOUCHSCREEN_CY8C_TS=y
+CONFIG_TOUCHSCREEN_CYTTSP_I2C_QC=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+CONFIG_BOSCH_BMA150=y
+# CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_HS=y
+CONFIG_DIAG_CHAR=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_DCC_TTY=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_QUP=y
+CONFIG_I2C_SSBI=y
+CONFIG_SPI=y
+CONFIG_SPI_QSD=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_BATTERY_MSM=y
+CONFIG_SENSORS_MSM_ADC=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_MSM_POPMEM=y
+CONFIG_PMIC8058=y
+CONFIG_MARIMBA_CORE=y
+CONFIG_MARIMBA_CODEC=y
+CONFIG_TIMPANI_CODEC=y
+# CONFIG_MFD_PM8XXX_DEBUG is not set
+# CONFIG_MFD_PM8XXX_PWM is not set
+# CONFIG_MFD_PM8XXX_MISC is not set
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+CONFIG_VIDEOBUF2_MSM_MEM=y
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+CONFIG_RADIO_TAVARUA=y
+CONFIG_MSM_KGSL=y
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+CONFIG_FB_MSM=y
+# CONFIG_FB_MSM_BACKLIGHT is not set
+CONFIG_FB_MSM_LOGO=y
+CONFIG_FB_MSM_TRIPLE_BUFFER=y
+CONFIG_FB_MSM_MDP40=y
+CONFIG_FB_MSM_OVERLAY=y
+CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM=y
+CONFIG_FB_MSM_HDMI_ADV7520_PANEL=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+# CONFIG_SND_DRIVERS is not set
+# CONFIG_SND_ARM is not set
+# CONFIG_SND_SPI is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_MSM7KV2_SOC=y
+CONFIG_SND_MVS_SOC=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_EHSET=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_EHCI_MSM_72K=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
+CONFIG_USB_EHSET_TEST_FIXTURE=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_MSM_72K=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_RMNET_SMD_CTL_CHANNEL="DATA40_CNTL"
+CONFIG_RMNET_SMD_DATA_CHANNEL="DATA40"
+CONFIG_RMNET_SDIO_SMD_DATA_CHANNEL=""
+CONFIG_USB_MSM_ACA=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
+CONFIG_MMC_MSM=y
+CONFIG_MMC_MSM_CARD_HW_DETECTION=y
+# CONFIG_MMC_MSM_SDC1_SUPPORT is not set
+CONFIG_MMC_MSM_SDC2_8_BIT_SUPPORT=y
+CONFIG_MMC_MSM_SDC3_SUPPORT=y
+CONFIG_MMC_MSM_SDC4_SUPPORT=y
+CONFIG_LEDS_PMIC8058=y
+CONFIG_SWITCH=y
+CONFIG_SWITCH_GPIO=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DEBUG=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_MSM_SSBI=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_DISABLE_TAGS_ECC=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+CONFIG_LOCKUP_DETECTOR=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_SLAB=y
+CONFIG_DEBUG_SLAB_LEAK=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_PROVE_LOCKING=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_LIST=y
+CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCE=m
+CONFIG_CRYPTO_DEV_QCEDEV=m
+CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
new file mode 100644
index 0000000..d5b4007
--- /dev/null
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -0,0 +1,450 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCALVERSION="-perf"
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_ASHMEM=y
+CONFIG_EMBEDDED=y
+# CONFIG_SLUB_DEBUG is not set
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_DEFAULT_DEADLINE=y
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MSM8X60=y
+CONFIG_MACH_MSM8X60_RUMI3=y
+CONFIG_MACH_MSM8X60_SIM=y
+CONFIG_MACH_MSM8X60_SURF=y
+CONFIG_MACH_MSM8X60_FFA=y
+CONFIG_MACH_MSM8X60_FLUID=y
+CONFIG_MACH_MSM8X60_FUSION=y
+CONFIG_MACH_MSM8X60_FUSN_FFA=y
+CONFIG_MACH_MSM8X60_DRAGON=y
+CONFIG_MSM7X00A_USE_DG_TIMER=y
+CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE=y
+CONFIG_MSM7X00A_IDLE_SLEEP_WAIT_FOR_INTERRUPT=y
+# CONFIG_MSM_FIQ_SUPPORT is not set
+# CONFIG_MSM_PROC_COMM is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SDIO_DMUX=y
+# CONFIG_MSM_RESET_MODEM is not set
+# CONFIG_MSM_SMD_NMEA is not set
+CONFIG_MSM_SDIO_TTY=y
+# CONFIG_MSM_SMD_QMI is not set
+CONFIG_MSM_SDIO_CMUX=y
+CONFIG_MSM_DSPS=y
+CONFIG_MSM_SDIO_CTL=y
+CONFIG_MSM_ONCRPCROUTER=y
+# CONFIG_MSM_RPCSERVER_TIME_REMOTE is not set
+# CONFIG_MSM_RPCSERVER_WATCHDOG is not set
+# CONFIG_MSM_RPCSERVER_HANDSET is not set
+CONFIG_MSM_RMT_STORAGE_CLIENT=y
+CONFIG_MSM_SDIO_SMEM=y
+# CONFIG_MSM_HW3D is not set
+CONFIG_MSM_PIL_MODEM=y
+CONFIG_MSM_PIL_QDSP6V3=y
+CONFIG_MSM_PIL_TZAPPS=y
+CONFIG_MSM_PIL_DSPS=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_TZ_LOG=y
+CONFIG_MSM_RPM_LOG=y
+CONFIG_MSM_RPM_STATS_LOG=y
+CONFIG_MSM_WATCHDOG=y
+CONFIG_MSM_DLOAD_MODE=y
+CONFIG_MSM_ETM=y
+CONFIG_MSM_GSBI9_UART=y
+CONFIG_STRICT_MEMORY_RWX=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_VMALLOC_RESERVE=0x19000000
+CONFIG_CP_ACCESS=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_WAKELOCK=y
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_TUNNEL=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_SCH_SFQ=y
+CONFIG_NET_SCH_TBF=y
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_INGRESS=y
+CONFIG_NET_CLS_BASIC=y
+CONFIG_NET_CLS_TCINDEX=y
+CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=m
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=y
+CONFIG_NET_EMATCH_NBYTE=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_EMATCH_META=y
+CONFIG_NET_EMATCH_TEXT=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_MIRRED=y
+CONFIG_BT=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_IBS=y
+CONFIG_MSM_BT_POWER=y
+CONFIG_CFG80211=y
+# CONFIG_CFG80211_WEXT is not set
+CONFIG_RFKILL=y
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_UID_STAT=y
+CONFIG_TSIF=m
+CONFIG_TSIF_CHRDEV=m
+CONFIG_HAPTIC_ISA1200=y
+CONFIG_PMIC8XXX_VIBRATOR=y
+CONFIG_PMIC8XXX_UPL=y
+CONFIG_PMIC8058_XOADC=y
+CONFIG_QSEECOM=y
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_UEVENT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_MSM_RMNET_SDIO=y
+CONFIG_SMC91X=y
+CONFIG_SMC911X=y
+CONFIG_SMSC911X=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_ASYNC=y
+CONFIG_SLIP=y
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_LIBRA_SDIOIF=m
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+CONFIG_INPUT_KEYRESET=y
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_KEYBOARD_MATRIX=y
+CONFIG_KEYBOARD_PMIC8XXX=y
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_CY8C_TS=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_PMIC8XXX_PWRKEY=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_PMIC8058_OTHC=y
+CONFIG_SERIAL_MSM_HS=y
+CONFIG_SERIAL_MSM_HSL=y
+CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_DIAG_CHAR=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_MSM is not set
+CONFIG_I2C_QUP=y
+CONFIG_I2C_SSBI=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=m
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_SX150X=y
+CONFIG_POWER_SUPPLY=y
+# CONFIG_BATTERY_MSM is not set
+CONFIG_BATTERY_MSM8X60=y
+CONFIG_PM8058_CHARGER=y
+CONFIG_ISL9519_CHARGER=y
+CONFIG_SMB137B_CHARGER=y
+CONFIG_BATTERY_BQ27520=y
+CONFIG_BATTERY_BQ27541=y
+CONFIG_SENSORS_MSM_ADC=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_TSENS=y
+CONFIG_THERMAL_PM8XXX=y
+CONFIG_PMIC8058=y
+CONFIG_PMIC8901=y
+CONFIG_MARIMBA_CORE=y
+CONFIG_TIMPANI_CODEC=y
+# CONFIG_MFD_PM8XXX_PWM is not set
+CONFIG_MFD_PM8XXX_BATT_ALARM=y
+CONFIG_REGULATOR_MSM_GPIO=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_DEV=y
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+CONFIG_VIDEOBUF2_MSM_MEM=y
+CONFIG_USB_VIDEO_CLASS=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_MSM_CAMERA_V4L2=y
+CONFIG_IMX074=y
+CONFIG_WEBCAM_OV9726=y
+CONFIG_MT9E013=y
+CONFIG_IMX074_ACT=y
+CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_ACTUATOR=y
+CONFIG_MSM_GEMINI=y
+CONFIG_OV7692=y
+CONFIG_RADIO_TAVARUA=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_MSM_KGSL=y
+CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y
+CONFIG_MSM_KGSL_PAGE_TABLE_COUNT=24
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_FB_MSM=y
+# CONFIG_FB_MSM_BACKLIGHT is not set
+CONFIG_FB_MSM_TRIPLE_BUFFER=y
+CONFIG_FB_MSM_MDP40=y
+CONFIG_FB_MSM_OVERLAY=y
+CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y
+CONFIG_FB_MSM_OVERLAY1_WRITEBACK=y
+CONFIG_FB_MSM_WRITEBACK_MSM_PANEL=y
+CONFIG_FB_MSM_LCDC_MIPI_PANEL_AUTO_DETECT=y
+CONFIG_FB_MSM_HDMI_MSM_PANEL=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_SOC=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_EHSET=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_EHCI_MSM_72K=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
+CONFIG_USB_EHSET_TEST_FIXTURE=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_MSM_72K=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_RMNET_SMD_CTL_CHANNEL="DATA40_CNTL"
+CONFIG_RMNET_SMD_DATA_CHANNEL="DATA40"
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_EMBEDDED_SDIO=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
+CONFIG_MMC_MSM=y
+CONFIG_MMC_MSM_CARD_HW_DETECTION=y
+CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT=y
+CONFIG_MMC_MSM_SDC2_8_BIT_SUPPORT=y
+CONFIG_MMC_MSM_SDC3_SUPPORT=y
+CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT=y
+CONFIG_MMC_MSM_SDC4_SUPPORT=y
+CONFIG_MMC_MSM_SDC5_SUPPORT=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_PMIC8058=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_SLEEP=y
+CONFIG_SWITCH=y
+CONFIG_SWITCH_GPIO=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_MSM is not set
+CONFIG_RTC_DRV_PM8XXX=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_MSM_SSBI=y
+CONFIG_MSM_IOMMU=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_CIFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_ENABLE_DEFAULT_TRACERS=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCE=m
+CONFIG_CRYPTO_DEV_QCEDEV=m
diff --git a/arch/arm/configs/msm8660_defconfig b/arch/arm/configs/msm8660_defconfig
new file mode 100644
index 0000000..5e2c1a8
--- /dev/null
+++ b/arch/arm/configs/msm8660_defconfig
@@ -0,0 +1,462 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_ASHMEM=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_DEFAULT_DEADLINE=y
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MSM8X60=y
+CONFIG_MACH_MSM8X60_RUMI3=y
+CONFIG_MACH_MSM8X60_SIM=y
+CONFIG_MACH_MSM8X60_SURF=y
+CONFIG_MACH_MSM8X60_FFA=y
+CONFIG_MACH_MSM8X60_FLUID=y
+CONFIG_MACH_MSM8X60_FUSION=y
+CONFIG_MACH_MSM8X60_FUSN_FFA=y
+CONFIG_MACH_MSM8X60_DRAGON=y
+CONFIG_MSM7X00A_USE_DG_TIMER=y
+CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE=y
+CONFIG_MSM7X00A_IDLE_SLEEP_WAIT_FOR_INTERRUPT=y
+# CONFIG_MSM_FIQ_SUPPORT is not set
+# CONFIG_MSM_PROC_COMM is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SDIO_DMUX=y
+# CONFIG_MSM_RESET_MODEM is not set
+# CONFIG_MSM_SMD_NMEA is not set
+CONFIG_MSM_SDIO_TTY=y
+# CONFIG_MSM_SMD_QMI is not set
+CONFIG_MSM_SDIO_CMUX=y
+CONFIG_MSM_DSPS=y
+CONFIG_MSM_SDIO_CTL=y
+CONFIG_MSM_ONCRPCROUTER=y
+# CONFIG_MSM_RPCSERVER_TIME_REMOTE is not set
+# CONFIG_MSM_RPCSERVER_WATCHDOG is not set
+# CONFIG_MSM_RPCSERVER_HANDSET is not set
+CONFIG_MSM_RMT_STORAGE_CLIENT=y
+CONFIG_MSM_SDIO_SMEM=y
+# CONFIG_MSM_HW3D is not set
+CONFIG_MSM_PIL_MODEM=y
+CONFIG_MSM_PIL_QDSP6V3=y
+CONFIG_MSM_PIL_TZAPPS=y
+CONFIG_MSM_PIL_DSPS=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_TZ_LOG=y
+CONFIG_MSM_RPM_LOG=y
+CONFIG_MSM_RPM_STATS_LOG=y
+CONFIG_MSM_WATCHDOG=y
+CONFIG_MSM_DLOAD_MODE=y
+CONFIG_MSM_ETM=y
+CONFIG_MSM_SLEEP_STATS=y
+CONFIG_MSM_GSBI9_UART=y
+CONFIG_STRICT_MEMORY_RWX=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_VMALLOC_RESERVE=0x19000000
+CONFIG_CP_ACCESS=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_WAKELOCK=y
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_TUNNEL=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_SCH_SFQ=y
+CONFIG_NET_SCH_TBF=y
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_INGRESS=y
+CONFIG_NET_CLS_BASIC=y
+CONFIG_NET_CLS_TCINDEX=y
+CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=m
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=y
+CONFIG_NET_EMATCH_NBYTE=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_EMATCH_META=y
+CONFIG_NET_EMATCH_TEXT=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_MIRRED=y
+CONFIG_BT=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_IBS=y
+CONFIG_MSM_BT_POWER=y
+CONFIG_CFG80211=y
+# CONFIG_CFG80211_WEXT is not set
+CONFIG_RFKILL=y
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_UID_STAT=y
+CONFIG_TSIF=m
+CONFIG_TSIF_CHRDEV=m
+CONFIG_HAPTIC_ISA1200=y
+CONFIG_PMIC8XXX_VIBRATOR=y
+CONFIG_PMIC8XXX_UPL=y
+CONFIG_PMIC8058_XOADC=y
+CONFIG_QSEECOM=y
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_DEBUG=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_UEVENT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_MSM_RMNET_SDIO=y
+CONFIG_SMC91X=y
+CONFIG_SMC911X=y
+CONFIG_SMSC911X=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_ASYNC=y
+CONFIG_SLIP=y
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_LIBRA_SDIOIF=m
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+CONFIG_INPUT_KEYRESET=y
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_KEYBOARD_MATRIX=y
+CONFIG_KEYBOARD_PMIC8XXX=y
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_CY8C_TS=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_PMIC8XXX_PWRKEY=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_PMIC8058_OTHC=y
+CONFIG_SERIAL_MSM_HS=y
+CONFIG_SERIAL_MSM_HSL=y
+CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_DIAG_CHAR=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM=y
+CONFIG_DCC_TTY=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_MSM is not set
+CONFIG_I2C_QUP=y
+CONFIG_I2C_SSBI=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=m
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_SX150X=y
+CONFIG_POWER_SUPPLY=y
+# CONFIG_BATTERY_MSM is not set
+CONFIG_BATTERY_MSM8X60=y
+CONFIG_PM8058_CHARGER=y
+CONFIG_ISL9519_CHARGER=y
+CONFIG_SMB137B_CHARGER=y
+CONFIG_BATTERY_BQ27520=y
+CONFIG_BATTERY_BQ27541=y
+CONFIG_SENSORS_MSM_ADC=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_TSENS=y
+CONFIG_THERMAL_PM8XXX=y
+CONFIG_PMIC8058=y
+CONFIG_PMIC8901=y
+CONFIG_MARIMBA_CORE=y
+CONFIG_TIMPANI_CODEC=y
+# CONFIG_MFD_PM8XXX_PWM is not set
+CONFIG_MFD_PM8XXX_BATT_ALARM=y
+CONFIG_REGULATOR_MSM_GPIO=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_DEV=y
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+CONFIG_VIDEOBUF2_MSM_MEM=y
+CONFIG_USB_VIDEO_CLASS=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_MSM_CAMERA_V4L2=y
+CONFIG_IMX074=y
+CONFIG_WEBCAM_OV9726=y
+CONFIG_MT9E013=y
+CONFIG_IMX074_ACT=y
+CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_ACTUATOR=y
+CONFIG_MSM_GEMINI=y
+CONFIG_OV7692=y
+CONFIG_RADIO_TAVARUA=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_MSM_KGSL=y
+CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y
+CONFIG_MSM_KGSL_PAGE_TABLE_COUNT=24
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_FB_MSM=y
+# CONFIG_FB_MSM_BACKLIGHT is not set
+CONFIG_FB_MSM_TRIPLE_BUFFER=y
+CONFIG_FB_MSM_MDP40=y
+CONFIG_FB_MSM_OVERLAY=y
+CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y
+CONFIG_FB_MSM_OVERLAY1_WRITEBACK=y
+CONFIG_FB_MSM_WRITEBACK_MSM_PANEL=y
+CONFIG_FB_MSM_LCDC_MIPI_PANEL_AUTO_DETECT=y
+CONFIG_FB_MSM_HDMI_MSM_PANEL=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_SOC=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_EHSET=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_EHCI_MSM_72K=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
+CONFIG_USB_EHSET_TEST_FIXTURE=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_MSM_72K=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_RMNET_SMD_CTL_CHANNEL="DATA40_CNTL"
+CONFIG_RMNET_SMD_DATA_CHANNEL="DATA40"
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_EMBEDDED_SDIO=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
+CONFIG_MMC_MSM=y
+CONFIG_MMC_MSM_CARD_HW_DETECTION=y
+CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT=y
+CONFIG_MMC_MSM_SDC2_8_BIT_SUPPORT=y
+CONFIG_MMC_MSM_SDC3_SUPPORT=y
+CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT=y
+CONFIG_MMC_MSM_SDC4_SUPPORT=y
+CONFIG_MMC_MSM_SDC5_SUPPORT=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_PMIC8058=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_SLEEP=y
+CONFIG_SWITCH=y
+CONFIG_SWITCH_GPIO=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_MSM is not set
+CONFIG_RTC_DRV_PM8XXX=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_MSM_SSBI=y
+CONFIG_MSM_IOMMU=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_CIFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_SLUB_DEBUG_ON=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_VM=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_LIST=y
+CONFIG_DEBUG_SG=y
+CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_ENABLE_DEFAULT_TRACERS=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_LL=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCE=m
+CONFIG_CRYPTO_DEV_QCEDEV=m
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
new file mode 100644
index 0000000..74d31b3
--- /dev/null
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -0,0 +1,483 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCALVERSION="-perf"
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_KALLSYMS_ALL=y
+CONFIG_ASHMEM=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MSM8960=y
+CONFIG_ARCH_MSM8930=y
+CONFIG_ARCH_APQ8064=y
+CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y
+CONFIG_MACH_MSM8960_SIM=y
+CONFIG_MACH_MSM8960_RUMI3=y
+CONFIG_MACH_MSM8960_CDP=y
+CONFIG_MACH_MSM8960_MTP=y
+CONFIG_MACH_MSM8960_FLUID=y
+CONFIG_MACH_MSM8960_LIQUID=y
+CONFIG_MACH_MSM8930_CDP=y
+CONFIG_MACH_MSM8930_MTP=y
+CONFIG_MACH_MSM8930_FLUID=y
+CONFIG_MACH_MSM8627_CDP=y
+CONFIG_MACH_MSM8627_MTP=y
+CONFIG_MACH_APQ8064_SIM=y
+CONFIG_MACH_APQ8064_RUMI3=y
+CONFIG_MACH_APQ8064_CDP=y
+CONFIG_MACH_APQ8064_MTP=y
+CONFIG_MACH_APQ8064_LIQUID=y
+CONFIG_MACH_MPQ8064_CDP=y
+CONFIG_MACH_MPQ8064_HRD=y
+CONFIG_MACH_MPQ8064_DTV=y
+# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_KERNEL_PMEM_EBI_REGION=y
+# CONFIG_MSM_FIQ_SUPPORT is not set
+# CONFIG_MSM_PROC_COMM is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_PCIE=y
+CONFIG_MSM_BAM_DMUX=y
+CONFIG_MSM_RMNET_SMUX=y
+CONFIG_MSM_DSPS=y
+CONFIG_MSM_IPC_ROUTER=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+# CONFIG_MSM_HW3D is not set
+CONFIG_MSM_PIL_QDSP6V4=y
+CONFIG_MSM_PIL_RIVA=y
+CONFIG_MSM_PIL_TZAPPS=y
+CONFIG_MSM_PIL_DSPS=y
+CONFIG_MSM_PIL_VIDC=y
+CONFIG_MSM_PIL_GSS=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_MODEM_8960=y
+CONFIG_MSM_LPASS_8960=y
+CONFIG_MSM_WCNSS_SSR_8960=y
+CONFIG_MSM_GSS_SSR_8064=y
+CONFIG_MSM_TZ_LOG=y
+CONFIG_MSM_RPM_LOG=y
+CONFIG_MSM_RPM_STATS_LOG=y
+CONFIG_MSM_BUS_SCALING=y
+CONFIG_MSM_BUS_RPM_MULTI_TIER_ENABLED=y
+CONFIG_MSM_WATCHDOG=y
+CONFIG_MSM_DLOAD_MODE=y
+CONFIG_MSM_QDSS=y
+CONFIG_MSM_SLEEP_STATS=y
+CONFIG_MSM_CACHE_ERP=y
+CONFIG_MSM_L2_ERP_2BIT_PANIC=y
+CONFIG_MSM_DCVS=y
+CONFIG_MSM_HSIC_SYSMON=y
+CONFIG_STRICT_MEMORY_RWX=y
+CONFIG_PCI=y
+CONFIG_PCI_MSI=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+# CONFIG_SMP_ON_UP is not set
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_VMALLOC_RESERVE=0x19000000
+CONFIG_CC_STACKPROTECTOR=y
+CONFIG_CP_ACCESS=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_WAKELOCK=y
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=y
+CONFIG_NET_EMATCH_NBYTE=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_EMATCH_META=y
+CONFIG_NET_EMATCH_TEXT=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_BT=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCISMD=y
+CONFIG_CFG80211=m
+# CONFIG_CFG80211_WEXT is not set
+CONFIG_RFKILL=y
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_HAPTIC_ISA1200=y
+CONFIG_PMIC8XXX_VIBRATOR=y
+CONFIG_QSEECOM=y
+CONFIG_USB_HSIC_SMSC_HUB=y
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_KS8851=m
+# CONFIG_MSM_RMNET is not set
+CONFIG_MSM_RMNET_BAM=y
+CONFIG_SMC91X=y
+CONFIG_SMC911X=y
+CONFIG_SMSC911X=y
+CONFIG_SLIP=y
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_USB_USBNET=y
+CONFIG_MSM_RMNET_USB=y
+CONFIG_WCNSS_CORE=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_KEYBOARD_MATRIX=y
+CONFIG_KEYBOARD_PMIC8XXX=y
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_JOYSTICK_XPAD=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_TOUCHSCREEN_CYTTSP_I2C_QC=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_PMIC8XXX_PWRKEY=y
+CONFIG_INPUT_UINPUT=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_N_SMUX=y
+CONFIG_N_SMUX_LOOPBACK=y
+CONFIG_SMUX_CTL=y
+CONFIG_SERIAL_MSM_HS=y
+CONFIG_SERIAL_MSM_HSL=y
+CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_DIAG_CHAR=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_MSM is not set
+CONFIG_I2C_QUP=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=m
+CONFIG_SLIMBUS_MSM_CTRL=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_SX150X=y
+CONFIG_POWER_SUPPLY=y
+# CONFIG_BATTERY_MSM is not set
+CONFIG_ISL9519_CHARGER=y
+CONFIG_SMB349_CHARGER=y
+CONFIG_PM8921_CHARGER=y
+CONFIG_PM8921_BMS=y
+CONFIG_PM8921_BCL=y
+CONFIG_SENSORS_PM8XXX_ADC=y
+CONFIG_SENSORS_EPM_ADC=y
+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
+CONFIG_MFD_PM8XXX_SPK=y
+CONFIG_MFD_PM8XXX_BATT_ALARM=y
+CONFIG_WCD9304_CODEC=y
+CONFIG_WCD9310_CODEC=y
+CONFIG_REGULATOR_PM8XXX=y
+CONFIG_REGULATOR_MSM_GPIO=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_USER_RC_INPUT=y
+CONFIG_IR_GPIO_CIR=y
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+CONFIG_VIDEOBUF2_MSM_MEM=y
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+CONFIG_USB_VIDEO_CLASS=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_MSM_CAMERA_V4L2=y
+CONFIG_IMX074=y
+CONFIG_MT9M114=y
+CONFIG_IMX074_ACT=y
+CONFIG_MSM_CAMERA_FLASH_SC628A=y
+CONFIG_MSM_CAMERA_FLASH_TPS61310=y
+CONFIG_OV2720=y
+CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_ACTUATOR=y
+CONFIG_MSM_EEPROM=y
+CONFIG_IMX074_EEPROM=y
+CONFIG_IMX091_EEPROM=y
+CONFIG_MSM_GEMINI=y
+CONFIG_S5K3L1YX=y
+CONFIG_IMX091=y
+CONFIG_RADIO_IRIS=y
+CONFIG_RADIO_IRIS_TRANSPORT=m
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_MSM_KGSL=y
+CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y
+CONFIG_MSM_KGSL_PAGE_TABLE_COUNT=24
+CONFIG_FB=y
+CONFIG_FB_VIRTUAL=y
+CONFIG_FB_MSM=y
+# CONFIG_FB_MSM_BACKLIGHT is not set
+CONFIG_FB_MSM_TRIPLE_BUFFER=y
+CONFIG_FB_MSM_MDP40=y
+CONFIG_FB_MSM_OVERLAY=y
+CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y
+CONFIG_FB_MSM_OVERLAY1_WRITEBACK=y
+CONFIG_FB_MSM_WRITEBACK_MSM_PANEL=y
+CONFIG_FB_MSM_LVDS_MIPI_PANEL_DETECT=y
+CONFIG_FB_MSM_HDMI_MSM_PANEL=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_DYNAMIC_MINORS=y
+# CONFIG_SND_ARM is not set
+# CONFIG_SND_SPI is not set
+CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_MSM8960=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_EHSET=y
+CONFIG_USB_EHCI_MSM=y
+CONFIG_USB_EHCI_MSM_HSIC=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DEBUG=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_QUALCOMM=y
+CONFIG_USB_SERIAL_CSVT=y
+CONFIG_USB_EHSET_TEST_FIXTURE=y
+CONFIG_USB_QCOM_DIAG_BRIDGE=y
+CONFIG_USB_QCOM_MDM_BRIDGE=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_CI13XXX_MSM=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_USB_ANDROID_RMNET_CTRL_SMD=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
+CONFIG_MMC_MSM=y
+CONFIG_MMC_MSM_CARD_HW_DETECTION=y
+CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT=y
+# CONFIG_MMC_MSM_SDC2_SUPPORT is not set
+CONFIG_MMC_MSM_SDC3_SUPPORT=y
+CONFIG_MMC_MSM_SDC3_WP_SUPPORT=y
+CONFIG_MMC_MSM_SPS_SUPPORT=y
+CONFIG_LEDS_PM8XXX=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_SWITCH=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_MSM is not set
+CONFIG_RTC_DRV_PM8XXX=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_MSM_SSBI=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_BAMDMA=y
+CONFIG_MSM_IOMMU=y
+CONFIG_MOBICORE_SUPPORT=m
+CONFIG_MOBICORE_API=m
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_CIFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_ENABLE_DEFAULT_TRACERS=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+CONFIG_PID_IN_CONTEXTIDR=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCE=m
+CONFIG_CRYPTO_DEV_QCEDEV=m
+CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
new file mode 100644
index 0000000..07a3f91
--- /dev/null
+++ b/arch/arm/configs/msm8960_defconfig
@@ -0,0 +1,500 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_KALLSYMS_ALL=y
+CONFIG_ASHMEM=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MSM8960=y
+CONFIG_ARCH_MSM8930=y
+CONFIG_ARCH_APQ8064=y
+CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y
+CONFIG_MACH_MSM8960_SIM=y
+CONFIG_MACH_MSM8960_RUMI3=y
+CONFIG_MACH_MSM8960_CDP=y
+CONFIG_MACH_MSM8960_MTP=y
+CONFIG_MACH_MSM8960_FLUID=y
+CONFIG_MACH_MSM8960_LIQUID=y
+CONFIG_MACH_MSM8930_CDP=y
+CONFIG_MACH_MSM8930_MTP=y
+CONFIG_MACH_MSM8930_FLUID=y
+CONFIG_MACH_MSM8627_CDP=y
+CONFIG_MACH_MSM8627_MTP=y
+CONFIG_MACH_APQ8064_SIM=y
+CONFIG_MACH_APQ8064_RUMI3=y
+CONFIG_MACH_APQ8064_CDP=y
+CONFIG_MACH_APQ8064_MTP=y
+CONFIG_MACH_APQ8064_LIQUID=y
+CONFIG_MACH_MPQ8064_CDP=y
+CONFIG_MACH_MPQ8064_HRD=y
+CONFIG_MACH_MPQ8064_DTV=y
+# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_KERNEL_PMEM_EBI_REGION=y
+# CONFIG_MSM_FIQ_SUPPORT is not set
+# CONFIG_MSM_PROC_COMM is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_PCIE=y
+CONFIG_MSM_BAM_DMUX=y
+CONFIG_MSM_DSPS=y
+CONFIG_MSM_IPC_ROUTER=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+# CONFIG_MSM_HW3D is not set
+CONFIG_MSM_PIL_QDSP6V4=y
+CONFIG_MSM_PIL_RIVA=y
+CONFIG_MSM_PIL_TZAPPS=y
+CONFIG_MSM_PIL_DSPS=y
+CONFIG_MSM_PIL_VIDC=y
+CONFIG_MSM_PIL_GSS=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_MODEM_8960=y
+CONFIG_MSM_LPASS_8960=y
+CONFIG_MSM_WCNSS_SSR_8960=y
+CONFIG_MSM_GSS_SSR_8064=y
+CONFIG_MSM_TZ_LOG=y
+CONFIG_MSM_RPM_LOG=y
+CONFIG_MSM_RPM_STATS_LOG=y
+CONFIG_MSM_BUS_SCALING=y
+CONFIG_MSM_BUS_RPM_MULTI_TIER_ENABLED=y
+CONFIG_MSM_WATCHDOG=y
+CONFIG_MSM_DLOAD_MODE=y
+CONFIG_MSM_QDSS=y
+CONFIG_MSM_QDSS_ETM_DEFAULT_ENABLE=y
+CONFIG_MSM_RTB=y
+CONFIG_MSM_RTB_SEPARATE_CPUS=y
+CONFIG_MSM_CACHE_ERP=y
+CONFIG_MSM_L1_ERR_PANIC=y
+CONFIG_MSM_L2_ERP_PRINT_ACCESS_ERRORS=y
+CONFIG_MSM_L2_ERP_1BIT_PANIC=y
+CONFIG_MSM_L2_ERP_2BIT_PANIC=y
+CONFIG_MSM_DCVS=y
+CONFIG_MSM_CACHE_DUMP=y
+CONFIG_MSM_CACHE_DUMP_ON_PANIC=y
+CONFIG_MSM_HSIC_SYSMON=y
+CONFIG_STRICT_MEMORY_RWX=y
+CONFIG_PCI=y
+CONFIG_PCI_MSI=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+# CONFIG_SMP_ON_UP is not set
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_VMALLOC_RESERVE=0x19000000
+CONFIG_CC_STACKPROTECTOR=y
+CONFIG_CP_ACCESS=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_WAKELOCK=y
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=y
+CONFIG_NET_EMATCH_NBYTE=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_EMATCH_META=y
+CONFIG_NET_EMATCH_TEXT=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_BT=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCISMD=y
+CONFIG_CFG80211=m
+# CONFIG_CFG80211_WEXT is not set
+CONFIG_RFKILL=y
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_HAPTIC_ISA1200=y
+CONFIG_PMIC8XXX_VIBRATOR=y
+CONFIG_QSEECOM=y
+CONFIG_USB_HSIC_SMSC_HUB=y
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_KS8851=m
+# CONFIG_MSM_RMNET is not set
+CONFIG_MSM_RMNET_BAM=y
+CONFIG_MSM_RMNET_SMUX=y
+CONFIG_SMC91X=y
+CONFIG_SMC911X=y
+CONFIG_SMSC911X=y
+CONFIG_SLIP=y
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_USB_USBNET=y
+CONFIG_MSM_RMNET_USB=y
+CONFIG_WCNSS_CORE=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_KEYBOARD_MATRIX=y
+CONFIG_KEYBOARD_PMIC8XXX=y
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_JOYSTICK_XPAD=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_TOUCHSCREEN_CYTTSP_I2C_QC=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_PMIC8XXX_PWRKEY=y
+CONFIG_INPUT_UINPUT=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_N_SMUX=y
+CONFIG_N_SMUX_LOOPBACK=y
+CONFIG_SMUX_CTL=y
+CONFIG_SERIAL_MSM_HS=y
+CONFIG_SERIAL_MSM_HSL=y
+CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_DIAG_CHAR=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_MSM is not set
+CONFIG_I2C_QUP=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=m
+CONFIG_SLIMBUS_MSM_CTRL=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_SX150X=y
+CONFIG_POWER_SUPPLY=y
+# CONFIG_BATTERY_MSM is not set
+CONFIG_ISL9519_CHARGER=y
+CONFIG_SMB349_CHARGER=y
+CONFIG_PM8921_CHARGER=y
+CONFIG_PM8921_BMS=y
+CONFIG_SENSORS_PM8XXX_ADC=y
+CONFIG_SENSORS_EPM_ADC=y
+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
+CONFIG_MFD_PM8XXX_SPK=y
+CONFIG_MFD_PM8XXX_BATT_ALARM=y
+CONFIG_WCD9304_CODEC=y
+CONFIG_WCD9310_CODEC=y
+CONFIG_REGULATOR_PM8XXX=y
+CONFIG_REGULATOR_MSM_GPIO=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_USER_RC_INPUT=y
+CONFIG_IR_GPIO_CIR=y
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+CONFIG_VIDEOBUF2_MSM_MEM=y
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_MSM_CAMERA_V4L2=y
+CONFIG_IMX074=y
+CONFIG_MT9M114=y
+CONFIG_IMX074_ACT=y
+CONFIG_MSM_CAMERA_FLASH_SC628A=y
+CONFIG_OV2720=y
+CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_ACTUATOR=y
+CONFIG_MSM_EEPROM=y
+CONFIG_IMX074_EEPROM=y
+CONFIG_IMX091_EEPROM=y
+CONFIG_MSM_GEMINI=y
+CONFIG_S5K3L1YX=y
+CONFIG_IMX091=y
+CONFIG_RADIO_IRIS=y
+CONFIG_RADIO_IRIS_TRANSPORT=m
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_MSM_KGSL=y
+CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y
+CONFIG_MSM_KGSL_PAGE_TABLE_COUNT=24
+CONFIG_FB=y
+CONFIG_FB_VIRTUAL=y
+CONFIG_FB_MSM=y
+# CONFIG_FB_MSM_BACKLIGHT is not set
+CONFIG_FB_MSM_TRIPLE_BUFFER=y
+CONFIG_FB_MSM_MDP40=y
+CONFIG_FB_MSM_OVERLAY=y
+CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y
+CONFIG_FB_MSM_OVERLAY1_WRITEBACK=y
+CONFIG_FB_MSM_WRITEBACK_MSM_PANEL=y
+CONFIG_FB_MSM_LVDS_MIPI_PANEL_DETECT=y
+CONFIG_FB_MSM_HDMI_MSM_PANEL=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_MSM8960=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_MON=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_EHSET=y
+CONFIG_USB_EHCI_MSM=y
+CONFIG_USB_EHCI_MSM_HSIC=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DEBUG=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_QUALCOMM=y
+CONFIG_USB_SERIAL_CSVT=y
+CONFIG_USB_EHSET_TEST_FIXTURE=y
+CONFIG_USB_QCOM_DIAG_BRIDGE=y
+CONFIG_USB_QCOM_MDM_BRIDGE=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_CI13XXX_MSM=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_USB_ANDROID_RMNET_CTRL_SMD=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
+CONFIG_MMC_MSM=y
+CONFIG_MMC_MSM_CARD_HW_DETECTION=y
+CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT=y
+# CONFIG_MMC_MSM_SDC2_SUPPORT is not set
+CONFIG_MMC_MSM_SDC3_SUPPORT=y
+CONFIG_MMC_MSM_SDC3_WP_SUPPORT=y
+CONFIG_MMC_MSM_SPS_SUPPORT=y
+CONFIG_LEDS_PM8XXX=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_SWITCH=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_MSM is not set
+CONFIG_RTC_DRV_PM8XXX=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_MSM_SSBI=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_BAMDMA=y
+CONFIG_MSM_IOMMU=y
+CONFIG_MOBICORE_SUPPORT=m
+CONFIG_MOBICORE_API=m
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_CIFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_SECTION_MISMATCH=y
+CONFIG_LOCKUP_DETECTOR=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_LIST=y
+CONFIG_FAULT_INJECTION=y
+CONFIG_FAILSLAB=y
+CONFIG_FAIL_PAGE_ALLOC=y
+CONFIG_FAULT_INJECTION_DEBUG_FS=y
+CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
+CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_ENABLE_DEFAULT_TRACERS=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+CONFIG_PID_IN_CONTEXTIDR=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCE=m
+CONFIG_CRYPTO_DEV_QCEDEV=m
+CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
new file mode 100644
index 0000000..37bc416
--- /dev/null
+++ b/arch/arm/configs/msm9615_defconfig
@@ -0,0 +1,297 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+# CONFIG_FAIR_GROUP_SCHED is not set
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+# CONFIG_PERF_EVENTS is not set
+CONFIG_PROFILING=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MSM9615=y
+CONFIG_MACH_MSM9615_CDP=y
+CONFIG_MACH_MSM9615_MTP=y
+# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_CPU_HAS_L2_PMU=y
+# CONFIG_MSM_FIQ_SUPPORT is not set
+# CONFIG_MSM_PROC_COMM is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_BAM_DMUX=y
+# CONFIG_MSM_RESET_MODEM is not set
+CONFIG_MSM_IPC_ROUTER=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+# CONFIG_MSM_SYSMON_COMM is not set
+CONFIG_MSM_MODEM_8960=y
+CONFIG_MSM_LPASS_8960=y
+CONFIG_MSM_RPM_LOG=y
+CONFIG_MSM_RPM_STATS_LOG=y
+CONFIG_MSM_DIRECT_SCLK_ACCESS=y
+CONFIG_MSM_BUS_SCALING=y
+CONFIG_MSM_BUS_RPM_MULTI_TIER_ENABLED=y
+CONFIG_MSM_WATCHDOG=y
+CONFIG_MSM_DLOAD_MODE=y
+CONFIG_SWP_EMULATE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_VMALLOC_RESERVE=0x19000000
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+CONFIG_IPV6=y
+# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET6_XFRM_MODE_BEET is not set
+# CONFIG_IPV6_SIT is not set
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+# CONFIG_ANDROID_PARANOID_NETWORK is not set
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_DEBUG=y
+CONFIG_NETFILTER_NETLINK_QUEUE=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CONNTRACK_TIMESTAMP=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NETFILTER_XT_MARK=y
+CONFIG_NETFILTER_XT_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_IP_SET=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_REJECT_SKERR=y
+CONFIG_IP_NF_TARGET_ULOG=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_TARGET_ECN=y
+CONFIG_IP_NF_TARGET_TTL=y
+CONFIG_IP_NF_RAW=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_MATCH_AH=y
+CONFIG_IP6_NF_MATCH_FRAG=y
+CONFIG_IP6_NF_MATCH_OPTS=y
+CONFIG_IP6_NF_MATCH_HL=y
+CONFIG_IP6_NF_MATCH_IPV6HEADER=y
+CONFIG_IP6_NF_MATCH_MH=y
+CONFIG_IP6_NF_MATCH_RT=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_TARGET_REJECT_SKERR=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_MTD=y
+CONFIG_MTD_TESTS=m
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_ANDROID_PMEM is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_NETDEVICES=y
+# CONFIG_MSM_RMNET is not set
+CONFIG_MSM_RMNET_BAM=y
+CONFIG_ATH6K_LEGACY_EXT=y
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_PMIC8XXX_PWRKEY=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_SERIO_LIBPS2=y
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_CONSOLE=y
+# CONFIG_SERIAL_MSM_CLOCK_CONTROL is not set
+CONFIG_SERIAL_MSM_HSL=y
+CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_DIAG_CHAR=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_MSM is not set
+CONFIG_I2C_QUP=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=m
+CONFIG_SLIMBUS_MSM_CTRL=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_SUPPLY=y
+# CONFIG_BATTERY_MSM is not set
+CONFIG_SENSORS_PM8XXX_ADC=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_TSENS8960=y
+CONFIG_THERMAL_PM8XXX=y
+CONFIG_MFD_PM8018_CORE=y
+CONFIG_WCD9310_CODEC=y
+CONFIG_REGULATOR_PM8XXX=y
+CONFIG_REGULATOR_MSM_GPIO=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_MDM9615=y
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_EHSET=y
+CONFIG_USB_EHCI_MSM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DEBUG=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
+CONFIG_USB_EHSET_TEST_FIXTURE=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_CI13XXX_MSM=m
+CONFIG_USB_CI13XXX_MSM_HSIC=m
+CONFIG_USB_G_ANDROID=y
+CONFIG_RMNET_SMD_CTL_CHANNEL="DATA36_CNTL"
+CONFIG_RMNET_SMD_DATA_CHANNEL="DATA36"
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_EMBEDDED_SDIO=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
+CONFIG_MMC_MSM=y
+CONFIG_MMC_MSM_CARD_HW_DETECTION=y
+CONFIG_MMC_MSM_SPS_SUPPORT=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_PM8XXX=y
+CONFIG_SWITCH=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_INTF_ALARM is not set
+# CONFIG_RTC_DRV_MSM is not set
+CONFIG_RTC_DRV_PM8XXX=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_MSM_SSBI=y
+CONFIG_SPS=y
+CONFIG_USB_BAM=y
+CONFIG_SPS_SUPPORT_BAMDMA=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_DISABLE_TAGS_ECC=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+CONFIG_KEYS=y
+CONFIG_CRYPTO_AUTHENC=y
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCE=m
+CONFIG_CRYPTO_DEV_QCEDEV=m
+CONFIG_CRC_CCITT=y
+CONFIG_LIBCRC32C=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
new file mode 100644
index 0000000..89fb888
--- /dev/null
+++ b/arch/arm/configs/msm9625_defconfig
@@ -0,0 +1,107 @@
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+# CONFIG_FAIR_GROUP_SCHED is not set
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MSM9625=y
+# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_CPU_HAS_L2_PMU=y
+# CONFIG_MSM_FIQ_SUPPORT is not set
+# CONFIG_MSM_PROC_COMM is not set
+CONFIG_MSM_DIRECT_SCLK_ACCESS=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_VMALLOC_RESERVE=0x19000000
+CONFIG_USE_OF=y
+CONFIG_ARM_APPENDED_DTB=y
+CONFIG_ARM_ATAG_DTB_COMPAT=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_SUSPEND is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_MISC_DEVICES=y
+# CONFIG_ANDROID_PMEM is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=m
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_MSM_HSL=y
+CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_HW_RANDOM=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+# CONFIG_HWMON is not set
+# CONFIG_MFD_SUPPORT is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+CONFIG_KEYS=y
+CONFIG_CRYPTO_AUTHENC=y
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+CONFIG_LIBCRC32C=y
diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h
new file mode 100644
index 0000000..2098288
--- /dev/null
+++ b/arch/arm/include/asm/arch_timer.h
@@ -0,0 +1,25 @@
+#ifndef __ASMARM_ARCH_TIMER_H
+#define __ASMARM_ARCH_TIMER_H
+
+#include <linux/ioport.h>
+
+struct arch_timer {
+	struct resource	res[2];
+};
+
+#ifdef CONFIG_ARM_ARCH_TIMER
+int arch_timer_register(struct arch_timer *);
+int arch_timer_of_register(void);
+#else
+static inline int arch_timer_register(struct arch_timer *at)
+{
+	return -ENXIO;
+}
+
+static inline int arch_timer_of_register(void)
+{
+	return -ENXIO;
+}
+#endif
+
+#endif
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index 5684cbc..d021905 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -88,6 +88,21 @@
  *	DMA Cache Coherency
  *	===================
  *
+ *	dma_inv_range(start, end)
+ *
+ *		Invalidate (discard) the specified virtual address range.
+ *		May not write back any entries.  If 'start' or 'end'
+ *		are not cache line aligned, those lines must be written
+ *		back.
+ *		- start  - virtual start address
+ *		- end    - virtual end address
+ *
+ *	dma_clean_range(start, end)
+ *
+ *		Clean (write back) the specified virtual address range.
+ *		- start  - virtual start address
+ *		- end    - virtual end address
+ *
  *	dma_flush_range(start, end)
  *
  *		Clean and invalidate the specified virtual address range.
@@ -108,6 +123,8 @@
 	void (*dma_map_area)(const void *, size_t, int);
 	void (*dma_unmap_area)(const void *, size_t, int);
 
+	void (*dma_inv_range)(const void *, const void *);
+	void (*dma_clean_range)(const void *, const void *);
 	void (*dma_flush_range)(const void *, const void *);
 };
 
@@ -134,6 +151,8 @@
  */
 #define dmac_map_area			cpu_cache.dma_map_area
 #define dmac_unmap_area			cpu_cache.dma_unmap_area
+#define dmac_inv_range			cpu_cache.dma_inv_range
+#define dmac_clean_range		cpu_cache.dma_clean_range
 #define dmac_flush_range		cpu_cache.dma_flush_range
 
 #else
@@ -154,6 +173,8 @@
  */
 extern void dmac_map_area(const void *, size_t, int);
 extern void dmac_unmap_area(const void *, size_t, int);
+extern void dmac_inv_range(const void *, const void *);
+extern void dmac_clean_range(const void *, const void *);
 extern void dmac_flush_range(const void *, const void *);
 
 #endif
diff --git a/arch/arm/include/asm/delay.h b/arch/arm/include/asm/delay.h
index b2deda1..5c6b9a3 100644
--- a/arch/arm/include/asm/delay.h
+++ b/arch/arm/include/asm/delay.h
@@ -8,7 +8,7 @@
 
 #include <asm/param.h>	/* HZ */
 
-extern void __delay(int loops);
+extern void __delay(unsigned long loops);
 
 /*
  * This function intentionally does not exist; if you see references to
@@ -40,5 +40,8 @@
 			__const_udelay((n) * ((2199023U*HZ)>>11))) :	\
 	  __udelay(n))
 
+extern void set_delay_fn(void (*fn)(unsigned long));
+extern void read_current_timer_delay_loop(unsigned long loops);
+
 #endif /* defined(_ARM_DELAY_H) */
 
diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index cb3b7c9..dc988ff 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -141,6 +141,46 @@
 {
 }
 
+
+/*
+ * dma_coherent_pre_ops - barrier functions for coherent memory before DMA.
+ * A barrier is required to ensure memory operations are complete before the
+ * initiation of a DMA xfer.
+ * If the coherent memory is Strongly Ordered
+ * - pre ARMv7 and 8x50 guarantees ordering wrt other mem accesses
+ * - ARMv7 guarantees ordering only within a 1KB block, so we need a barrier
+ * If coherent memory is normal then we need a barrier to prevent
+ * reordering
+ */
+static inline void dma_coherent_pre_ops(void)
+{
+#if COHERENT_IS_NORMAL == 1
+	dmb();
+#else
+	if (arch_is_coherent())
+		dmb();
+	else
+		barrier();
+#endif
+}
+/*
+ * dma_post_coherent_ops - barrier functions for coherent memory after DMA.
+ * If the coherent memory is Strongly Ordered we dont need a barrier since
+ * there are no speculative fetches to Strongly Ordered memory.
+ * If coherent memory is normal then we need a barrier to prevent reordering
+ */
+static inline void dma_coherent_post_ops(void)
+{
+#if COHERENT_IS_NORMAL == 1
+	dmb();
+#else
+	if (arch_is_coherent())
+		dmb();
+	else
+		barrier();
+#endif
+}
+
 /**
  * dma_alloc_coherent - allocate consistent memory for DMA
  * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
@@ -331,6 +371,58 @@
 }
 
 /**
+ * dma_cache_pre_ops - clean or invalidate cache before dma transfer is
+ *                     initiated and perform a barrier operation.
+ * @virtual_addr: A kernel logical or kernel virtual address
+ * @size: size of buffer to map
+ * @dir: DMA transfer direction
+ *
+ * Ensure that any data held in the cache is appropriately discarded
+ * or written back.
+ *
+ */
+static inline void dma_cache_pre_ops(void *virtual_addr,
+		size_t size, enum dma_data_direction dir)
+{
+	extern void ___dma_single_cpu_to_dev(const void *, size_t,
+		enum dma_data_direction);
+
+	BUG_ON(!valid_dma_direction(dir));
+
+	if (!arch_is_coherent())
+		___dma_single_cpu_to_dev(virtual_addr, size, dir);
+}
+
+/**
+ * dma_cache_post_ops - clean or invalidate cache after dma transfer is
+ *                     initiated and perform a barrier operation.
+ * @virtual_addr: A kernel logical or kernel virtual address
+ * @size: size of buffer to map
+ * @dir: DMA transfer direction
+ *
+ * Ensure that any data held in the cache is appropriately discarded
+ * or written back.
+ *
+ */
+static inline void dma_cache_post_ops(void *virtual_addr,
+		size_t size, enum dma_data_direction dir)
+{
+	extern void ___dma_single_cpu_to_dev(const void *, size_t,
+		enum dma_data_direction);
+
+	BUG_ON(!valid_dma_direction(dir));
+
+	if (arch_has_speculative_dfetch() && !arch_is_coherent()
+	 && dir != DMA_TO_DEVICE)
+		/*
+		 * Treat DMA_BIDIRECTIONAL and DMA_FROM_DEVICE
+		 * identically: invalidate
+		 */
+		___dma_single_cpu_to_dev(virtual_addr,
+					 size, DMA_FROM_DEVICE);
+}
+
+/**
  * dma_map_page - map a portion of a page for streaming DMA
  * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
  * @page: page that buffer resides in
diff --git a/arch/arm/include/asm/domain.h b/arch/arm/include/asm/domain.h
index 3d22204..b216a00 100644
--- a/arch/arm/include/asm/domain.h
+++ b/arch/arm/include/asm/domain.h
@@ -2,6 +2,7 @@
  *  arch/arm/include/asm/domain.h
  *
  *  Copyright (C) 1999 Russell King.
+ *  Copyright (c) 2009, 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 as
@@ -31,8 +32,13 @@
  *
  * 36-bit addressing and supersections are only available on
  * CPUs based on ARMv6+ or the Intel XSC3 core.
+ *
+ * We cannot use domain 0 for the kernel on QSD8x50 since the kernel domain
+ * is set to manager mode when set_fs(KERNEL_DS) is called. Setting domain 0
+ * to manager mode will disable the workaround for a cpu bug that can cause an
+ * invalid fault status and/or tlb corruption (CONFIG_VERIFY_PERMISSION_FAULT).
  */
-#ifndef CONFIG_IO_36
+#if !defined(CONFIG_IO_36) && !defined(CONFIG_VERIFY_PERMISSION_FAULT)
 #define DOMAIN_KERNEL	0
 #define DOMAIN_TABLE	0
 #define DOMAIN_USER	1
@@ -60,6 +66,17 @@
 #ifndef __ASSEMBLY__
 
 #ifdef CONFIG_CPU_USE_DOMAINS
+#ifdef CONFIG_EMULATE_DOMAIN_MANAGER_V7
+void emulate_domain_manager_set(u32 domain);
+int emulate_domain_manager_data_abort(u32 dfsr, u32 dfar);
+int emulate_domain_manager_prefetch_abort(u32 ifsr, u32 ifar);
+void emulate_domain_manager_switch_mm(
+	unsigned long pgd_phys,
+	struct mm_struct *mm,
+	void (*switch_mm)(unsigned long pgd_phys, struct mm_struct *));
+
+#define set_domain(x) emulate_domain_manager_set(x)
+#else
 #define set_domain(x)					\
 	do {						\
 	__asm__ __volatile__(				\
@@ -67,6 +84,7 @@
 	  : : "r" (x));					\
 	isb();						\
 	} while (0)
+#endif
 
 #define modify_domain(dom,type)					\
 	do {							\
diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
index d493d0b..ec4b8b8 100644
--- a/arch/arm/include/asm/fiq.h
+++ b/arch/arm/include/asm/fiq.h
@@ -33,11 +33,22 @@
 	void *dev_id;
 };
 
+#ifdef CONFIG_FIQ
 extern int claim_fiq(struct fiq_handler *f);
 extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
+#else
+static inline int claim_fiq(struct fiq_handler *f)
+{
+	return 0;
+}
+static inline void release_fiq(struct fiq_handler *f) { }
+static inline void set_fiq_handler(void *start, unsigned int length) { }
+static inline void enable_fiq(int fiq) { }
+static inline void disable_fiq(int fiq) { }
+#endif
 
 /* helpers defined in fiqasm.S: */
 extern void __set_fiq_regs(unsigned long const *regs);
diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h
index 2740c2a..3d7351c 100644
--- a/arch/arm/include/asm/hardirq.h
+++ b/arch/arm/include/asm/hardirq.h
@@ -5,7 +5,7 @@
 #include <linux/threads.h>
 #include <asm/irq.h>
 
-#define NR_IPI	6
+#define NR_IPI	7
 
 typedef struct {
 	unsigned int __softirq_pending;
diff --git a/arch/arm/include/asm/hardware/cache-l2x0.h b/arch/arm/include/asm/hardware/cache-l2x0.h
index bd2c6a5..a244039 100644
--- a/arch/arm/include/asm/hardware/cache-l2x0.h
+++ b/arch/arm/include/asm/hardware/cache-l2x0.h
@@ -91,6 +91,7 @@
 #define L2X0_AUX_CTRL_WAY_SIZE_SHIFT		17
 #define L2X0_AUX_CTRL_WAY_SIZE_MASK		(0x7 << 17)
 #define L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT	22
+#define L2X0_AUX_CTRL_L2_FORCE_NWA_SHIFT	23
 #define L2X0_AUX_CTRL_NS_LOCKDOWN_SHIFT		26
 #define L2X0_AUX_CTRL_NS_INT_CTRL_SHIFT		27
 #define L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT	28
@@ -105,7 +106,18 @@
 
 #define REV_PL310_R2P0				4
 
+#define L2X0_LATENCY_CTRL_SETUP_SHIFT	0
+#define L2X0_LATENCY_CTRL_RD_SHIFT	4
+#define L2X0_LATENCY_CTRL_WR_SHIFT	8
+
+#define L2X0_PREFETCH_CTRL_OFFSET_SHIFT		0
+#define L2X0_PREFETCH_CTRL_WRAP8_INC_SHIFT	23
+#define L2X0_PREFETCH_CTRL_WRAP8_SHIFT		30
+
 #ifndef __ASSEMBLY__
+extern void l2cc_suspend(void);
+extern void l2cc_resume(void);
+extern void l2x0_cache_sync(void);
 extern void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask);
 #if defined(CONFIG_CACHE_L2X0) && defined(CONFIG_OF)
 extern int l2x0_of_init(u32 aux_val, u32 aux_mask);
diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h
index 4b1ce6c..3fb0a1c 100644
--- a/arch/arm/include/asm/hardware/gic.h
+++ b/arch/arm/include/asm/hardware/gic.h
@@ -22,6 +22,7 @@
 
 #define GIC_DIST_CTRL			0x000
 #define GIC_DIST_CTR			0x004
+#define GIC_DIST_ISR			0x080
 #define GIC_DIST_ENABLE_SET		0x100
 #define GIC_DIST_ENABLE_CLEAR		0x180
 #define GIC_DIST_PENDING_SET		0x200
@@ -39,19 +40,31 @@
 extern struct irq_chip gic_arch_extn;
 
 void gic_init_bases(unsigned int, int, void __iomem *, void __iomem *,
-		    u32 offset, struct device_node *);
+		    u32 offset);
 int gic_of_init(struct device_node *node, struct device_node *parent);
 void gic_secondary_init(unsigned int);
 void gic_handle_irq(struct pt_regs *regs);
 void gic_cascade_irq(unsigned int gic_nr, unsigned int irq);
 void gic_raise_softirq(const struct cpumask *mask, unsigned int irq);
-
+#ifdef CONFIG_ARM_GIC
+void gic_set_irq_secure(unsigned int irq);
+#else
+static inline void gic_set_irq_secure(unsigned int irq) { }
+#endif
 static inline void gic_init(unsigned int nr, int start,
 			    void __iomem *dist , void __iomem *cpu)
 {
-	gic_init_bases(nr, start, dist, cpu, 0, NULL);
+	gic_init_bases(nr, start, dist, cpu, 0);
 }
+bool gic_is_spi_pending(unsigned int irq);
+void gic_clear_spi_pending(unsigned int irq);
+void gic_set_irq_secure(unsigned int irq);
+#endif
 
+#ifdef CONFIG_ARCH_MSM8625
+void msm_gic_save(bool modem_wake, int from_idle);
+void msm_gic_restore(void);
+void core1_gic_configure_and_raise(void);
 #endif
 
 #endif
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index 9af5563..42fef7c 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -27,6 +27,7 @@
 #include <asm/byteorder.h>
 #include <asm/memory.h>
 #include <asm-generic/pci_iomap.h>
+#include <mach/msm_rtb.h>
 
 /*
  * ISA I/O bus memory addresses are 1:1 with the physical address.
@@ -47,13 +48,52 @@
 extern void __raw_readsw(const void __iomem *addr, void *data, int wordlen);
 extern void __raw_readsl(const void __iomem *addr, void *data, int longlen);
 
-#define __raw_writeb(v,a)	(__chk_io_ptr(a), *(volatile unsigned char __force  *)(a) = (v))
-#define __raw_writew(v,a)	(__chk_io_ptr(a), *(volatile unsigned short __force *)(a) = (v))
-#define __raw_writel(v,a)	(__chk_io_ptr(a), *(volatile unsigned int __force   *)(a) = (v))
+/*
+ * There may be cases when clients don't want to support or can't support the
+ * logging. The appropriate functions can be used but clients should carefully
+ * consider why they can't support the logging.
+ */
 
-#define __raw_readb(a)		(__chk_io_ptr(a), *(volatile unsigned char __force  *)(a))
-#define __raw_readw(a)		(__chk_io_ptr(a), *(volatile unsigned short __force *)(a))
-#define __raw_readl(a)		(__chk_io_ptr(a), *(volatile unsigned int __force   *)(a))
+#define __raw_write_logged(v, a, _t)	({ \
+	int _ret; \
+	void *_addr = (void *)(a); \
+	_ret = uncached_logk(LOGK_WRITEL, _addr); \
+	ETB_WAYPOINT; \
+	__raw_write##_t##_no_log((v), _addr); \
+	if (_ret) \
+		LOG_BARRIER; \
+	})
+
+
+#define __raw_writeb_no_log(v, a)	(__chk_io_ptr(a), *(volatile unsigned char __force  *)(a) = (v))
+#define __raw_writew_no_log(v, a)	(__chk_io_ptr(a), *(volatile unsigned short __force *)(a) = (v))
+#define __raw_writel_no_log(v, a)	(__chk_io_ptr(a), *(volatile unsigned int __force *)(a) = (v))
+
+
+#define __raw_writeb(v, a)	__raw_write_logged((v), (a), b)
+#define __raw_writew(v, a)	__raw_write_logged((v), (a), w)
+#define __raw_writel(v, a)	__raw_write_logged((v), (a), l)
+
+#define __raw_readb_no_log(a)		(__chk_io_ptr(a), *(volatile unsigned char __force  *)(a))
+#define __raw_readw_no_log(a)		(__chk_io_ptr(a), *(volatile unsigned short __force *)(a))
+#define __raw_readl_no_log(a)		(__chk_io_ptr(a), *(volatile unsigned int __force *)(a))
+
+#define __raw_read_logged(a, _l, _t)		({ \
+	unsigned _t __a; \
+	void *_addr = (void *)(a); \
+	int _ret; \
+	_ret = uncached_logk(LOGK_READL, _addr); \
+	ETB_WAYPOINT; \
+	__a = __raw_read##_l##_no_log(_addr);\
+	if (_ret) \
+		LOG_BARRIER; \
+	__a; \
+	})
+
+
+#define __raw_readb(a)		__raw_read_logged((a), b, char)
+#define __raw_readw(a)		__raw_read_logged((a), w, short)
+#define __raw_readl(a)		__raw_read_logged((a), l, int)
 
 /*
  * Architecture ioremap implementation.
diff --git a/arch/arm/include/asm/localtimer.h b/arch/arm/include/asm/localtimer.h
index f77ffc1..87de915 100644
--- a/arch/arm/include/asm/localtimer.h
+++ b/arch/arm/include/asm/localtimer.h
@@ -14,6 +14,11 @@
 
 struct clock_event_device;
 
+/*
+ * Setup a per-cpu timer, whether it be a local timer or dummy broadcast
+ */
+void percpu_timer_setup(void);
+
 struct local_timer_ops {
 	int  (*setup)(struct clock_event_device *);
 	void (*stop)(struct clock_event_device *);
diff --git a/arch/arm/include/asm/mach/arch.h b/arch/arm/include/asm/mach/arch.h
index d7692ca..0a45dee 100644
--- a/arch/arm/include/asm/mach/arch.h
+++ b/arch/arm/include/asm/mach/arch.h
@@ -22,7 +22,7 @@
 	const char *const 	*dt_compat;	/* array of device tree
 						 * 'compatible' strings	*/
 
-	unsigned int		nr_irqs;	/* number of IRQs */
+	int			nr_irqs;	/* number of IRQs */
 
 #ifdef CONFIG_ZONE_DMA
 	unsigned long		dma_zone_size;	/* size of DMA-able area */
@@ -39,6 +39,7 @@
 					 struct meminfo *);
 	void			(*reserve)(void);/* reserve mem blocks	*/
 	void			(*map_io)(void);/* IO mapping function	*/
+	void			(*init_very_early)(void);
 	void			(*init_early)(void);
 	void			(*init_irq)(void);
 	struct sys_timer	*timer;		/* system tick timer	*/
diff --git a/arch/arm/include/asm/mach/flash.h b/arch/arm/include/asm/mach/flash.h
index 4ca69fe..36938ea 100644
--- a/arch/arm/include/asm/mach/flash.h
+++ b/arch/arm/include/asm/mach/flash.h
@@ -17,6 +17,7 @@
  * map_name:	the map probe function name
  * name:	flash device name (eg, as used with mtdparts=)
  * width:	width of mapped device
+ * interleave:  interleave mode feature support
  * init:	method called at driver/device initialisation
  * exit:	method called at driver/device removal
  * set_vpp:	method called to enable or disable VPP
@@ -28,6 +29,7 @@
 	const char	*map_name;
 	const char	*name;
 	unsigned int	width;
+	unsigned int    interleave;
 	int		(*init)(void);
 	void		(*exit)(void);
 	void		(*set_vpp)(int on);
diff --git a/arch/arm/include/asm/mach/map.h b/arch/arm/include/asm/mach/map.h
index b36f365..5f731df 100644
--- a/arch/arm/include/asm/mach/map.h
+++ b/arch/arm/include/asm/mach/map.h
@@ -9,6 +9,9 @@
  *
  *  Page table mapping constructs and function prototypes
  */
+#ifndef __ASM_ARM_MACH_MAP_H
+#define __ASM_ARM_MACH_MAP_H
+
 #include <asm/io.h>
 
 struct map_desc {
@@ -30,6 +33,9 @@
 #define MT_MEMORY_DTCM		12
 #define MT_MEMORY_ITCM		13
 #define MT_MEMORY_SO		14
+#define MT_MEMORY_R		15
+#define MT_MEMORY_RW		16
+#define MT_MEMORY_RX		17
 
 #ifdef CONFIG_MMU
 extern void iotable_init(struct map_desc *, int);
@@ -41,6 +47,11 @@
  */
 extern int ioremap_page(unsigned long virt, unsigned long phys,
 			const struct mem_type *mtype);
+
+extern int ioremap_pages(unsigned long virt, unsigned long phys,
+			unsigned long size, const struct mem_type *mtype);
 #else
 #define iotable_init(map,num)	do { } while (0)
 #endif
+
+#endif
diff --git a/arch/arm/include/asm/mach/mmc.h b/arch/arm/include/asm/mach/mmc.h
index bca864a..745a3a4 100644
--- a/arch/arm/include/asm/mach/mmc.h
+++ b/arch/arm/include/asm/mach/mmc.h
@@ -7,6 +7,13 @@
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/sdio_func.h>
+#include <mach/gpio.h>
+#include <mach/msm_bus.h>
+
+#define SDC_DAT1_DISABLE 0
+#define SDC_DAT1_ENABLE  1
+#define SDC_DAT1_ENWAKE  2
+#define SDC_DAT1_DISWAKE 3
 
 struct embedded_sdio_data {
         struct sdio_cis cis;
@@ -15,6 +22,103 @@
         int num_funcs;
 };
 
+/* This structure keeps information per regulator */
+struct msm_mmc_reg_data {
+	/* voltage regulator handle */
+	struct regulator *reg;
+	/* regulator name */
+	const char *name;
+	/* voltage level to be set */
+	unsigned int low_vol_level;
+	unsigned int high_vol_level;
+	/* Load values for low power and high power mode */
+	unsigned int lpm_uA;
+	unsigned int hpm_uA;
+	/*
+	 * is set voltage supported for this regulator?
+	 * false => set voltage is not supported
+	 * true  => set voltage is supported
+	 *
+	 * Some regulators (like gpio-regulators, LVS (low voltage swtiches)
+	 * PMIC regulators) dont have the capability to call
+	 * regulator_set_voltage or regulator_set_optimum_mode
+	 * Use this variable to indicate if its a such regulator or not
+	 */
+	bool set_voltage_sup;
+	/* is this regulator enabled? */
+	bool is_enabled;
+	/* is this regulator needs to be always on? */
+	bool always_on;
+	/* is low power mode setting required for this regulator? */
+	bool lpm_sup;
+};
+
+/*
+ * This structure keeps information for all the
+ * regulators required for a SDCC slot.
+ */
+struct msm_mmc_slot_reg_data {
+	struct msm_mmc_reg_data *vdd_data; /* keeps VDD/VCC regulator info */
+	struct msm_mmc_reg_data *vccq_data; /* keeps VCCQ regulator info */
+	struct msm_mmc_reg_data *vddp_data; /* keeps VDD Pad regulator info */
+};
+
+struct msm_mmc_gpio {
+	u32 no;
+	const char *name;
+	bool is_always_on;
+	bool is_enabled;
+};
+
+struct msm_mmc_gpio_data {
+	struct msm_mmc_gpio *gpio;
+	u8 size;
+};
+
+struct msm_mmc_pad_pull {
+	enum msm_tlmm_pull_tgt no;
+	u32 val;
+};
+
+struct msm_mmc_pad_pull_data {
+	struct msm_mmc_pad_pull *on;
+	struct msm_mmc_pad_pull *off;
+	u8 size;
+};
+
+struct msm_mmc_pad_drv {
+	enum msm_tlmm_hdrive_tgt no;
+	u32 val;
+};
+
+struct msm_mmc_pad_drv_data {
+	struct msm_mmc_pad_drv *on;
+	struct msm_mmc_pad_drv *off;
+	u8 size;
+};
+
+struct msm_mmc_pad_data {
+	struct msm_mmc_pad_pull_data *pull;
+	struct msm_mmc_pad_drv_data *drv;
+};
+
+struct msm_mmc_pin_data {
+	/*
+	 * = 1 if controller pins are using gpios
+	 * = 0 if controller has dedicated MSM pads
+	 */
+	u8 is_gpio;
+	u8 cfg_sts;
+	struct msm_mmc_gpio_data *gpio_data;
+	struct msm_mmc_pad_data *pad_data;
+};
+
+struct msm_mmc_bus_voting_data {
+	struct msm_bus_scale_pdata *use_cases;
+	unsigned int *bw_vecs;
+	unsigned int bw_vecs_size;
+};
+
 struct mmc_platform_data {
 	unsigned int ocr_mask;			/* available voltages */
 	int built_in;				/* built-in device flag */
@@ -23,6 +127,40 @@
 	unsigned int (*status)(struct device *);
 	struct embedded_sdio_data *embedded_sdio;
 	int (*register_status_notify)(void (*callback)(int card_present, void *dev_id), void *dev_id);
+	/*
+	 * XPC controls the maximum current in the
+	 * default speed mode of SDXC card.
+	 */
+	unsigned int xpc_cap;
+	/* Supported UHS-I Modes */
+	unsigned int uhs_caps;
+	void (*sdio_lpm_gpio_setup)(struct device *, unsigned int);
+        unsigned int status_irq;
+	unsigned int status_gpio;
+	/* Indicates the polarity of the GPIO line when card is inserted */
+	bool is_status_gpio_active_low;
+        unsigned int sdiowakeup_irq;
+        unsigned long irq_flags;
+        unsigned long mmc_bus_width;
+        int (*wpswitch) (struct device *);
+	unsigned int msmsdcc_fmin;
+	unsigned int msmsdcc_fmid;
+	unsigned int msmsdcc_fmax;
+	bool nonremovable;
+	bool pclk_src_dfab;
+	unsigned int mpm_sdiowakeup_int;
+	unsigned int wpswitch_gpio;
+	unsigned char wpswitch_polarity;
+	struct msm_mmc_slot_reg_data *vreg_data;
+	int is_sdio_al_client;
+	unsigned int *sup_clk_table;
+	unsigned char sup_clk_cnt;
+	struct msm_mmc_pin_data *pin_data;
+	bool disable_bam;
+	bool disable_runtime_pm;
+	bool disable_cmd23;
+	u32 cpu_dma_latency;
+	struct msm_mmc_bus_voting_data *msm_bus_voting_data;
 };
 
 #endif
diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index fcb5757..17b7b31 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -280,6 +280,13 @@
 #define arch_is_coherent()		0
 #endif
 
+/*
+ * Set if the architecture speculatively fetches data into cache.
+ */
+#ifndef arch_has_speculative_dfetch
+#define arch_has_speculative_dfetch()	0
+#endif
+
 #endif
 
 #include <asm-generic/memory_model.h>
diff --git a/arch/arm/include/asm/mmu_writeable.h b/arch/arm/include/asm/mmu_writeable.h
new file mode 100644
index 0000000..96d348c
--- /dev/null
+++ b/arch/arm/include/asm/mmu_writeable.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef _MMU_WRITEABLE_H
+#define _MMU_WRITEABLE_H
+
+#ifdef CONFIG_STRICT_MEMORY_RWX
+void mem_text_writeable_spinlock(unsigned long *flags);
+void mem_text_address_writeable(unsigned long);
+void mem_text_address_restore(void);
+void mem_text_writeable_spinunlock(unsigned long *flags);
+#else
+static inline void mem_text_writeable_spinlock(unsigned long *flags) {};
+static inline void mem_text_address_writeable(unsigned long addr) {};
+static inline void mem_text_address_restore(void) {};
+static inline void mem_text_writeable_spinunlock(unsigned long *flags) {};
+#endif
+
+void mem_text_write_kernel_word(unsigned long *addr, unsigned long word);
+
+#endif
diff --git a/arch/arm/include/asm/mutex.h b/arch/arm/include/asm/mutex.h
index 93226cf..fd3f17e 100644
--- a/arch/arm/include/asm/mutex.h
+++ b/arch/arm/include/asm/mutex.h
@@ -41,6 +41,8 @@
 	__res |= __ex_flag;
 	if (unlikely(__res != 0))
 		fail_fn(count);
+	else
+		smp_rmb();
 }
 
 static inline int
@@ -61,6 +63,9 @@
 	__res |= __ex_flag;
 	if (unlikely(__res != 0))
 		__res = fail_fn(count);
+	else
+		smp_rmb();
+
 	return __res;
 }
 
@@ -74,6 +79,7 @@
 {
 	int __ex_flag, __res, __orig;
 
+	smp_wmb();
 	__asm__ (
 
 		"ldrex	%0, [%3]	\n\t"
@@ -119,6 +125,8 @@
 		: "=&r" (__orig), "=&r" (__res), "=&r" (__ex_flag)
 		: "r" (&count->counter)
 		: "cc", "memory" );
+	if (__orig)
+		smp_rmb();
 
 	return __orig;
 }
diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h
index 5838361..afc1ca7 100644
--- a/arch/arm/include/asm/page.h
+++ b/arch/arm/include/asm/page.h
@@ -167,6 +167,11 @@
 extern int pfn_valid(unsigned long);
 #endif
 
+#ifdef CONFIG_MEMORY_HOTPLUG_SPARSE
+extern int _early_pfn_valid(unsigned long);
+#define early_pfn_valid(pfn) (_early_pfn_valid(pfn))
+#endif
+
 #include <asm/memory.h>
 
 #endif /* !__ASSEMBLY__ */
diff --git a/arch/arm/include/asm/perf_event.h b/arch/arm/include/asm/perf_event.h
index 00cbe10..2fecc60 100644
--- a/arch/arm/include/asm/perf_event.h
+++ b/arch/arm/include/asm/perf_event.h
@@ -23,6 +23,9 @@
 	ARM_PERF_PMU_ID_CA5,
 	ARM_PERF_PMU_ID_CA15,
 	ARM_PERF_PMU_ID_CA7,
+	ARM_PERF_PMU_ID_SCORPION,
+	ARM_PERF_PMU_ID_SCORPIONMP,
+	ARM_PERF_PMU_ID_KRAIT,
 	ARM_NUM_PMU_IDS,
 };
 
diff --git a/arch/arm/include/asm/perftypes.h b/arch/arm/include/asm/perftypes.h
new file mode 100644
index 0000000..8d21dcd
--- /dev/null
+++ b/arch/arm/include/asm/perftypes.h
@@ -0,0 +1,33 @@
+/* Copyright (c) 2010, 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.
+ *
+ */
+
+/*
+**  perftypes.h
+**  DESCRIPTION
+**  ksapi.ko function hooks header file
+*/
+
+#ifndef __PERFTYPES_H__
+#define __PERFTYPES_H__
+
+typedef void (*VPVF)(void);
+typedef void (*VPULF)(unsigned long);
+typedef void (*VPULULF)(unsigned long, unsigned long);
+
+extern VPVF pp_interrupt_out_ptr;
+extern VPVF pp_interrupt_in_ptr;
+extern VPULF pp_process_remove_ptr;
+extern void perf_mon_interrupt_in(void);
+extern void perf_mon_interrupt_out(void);
+
+#endif
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index f66626d..7b6f42a 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -103,16 +103,30 @@
 #define pgprot_stronglyordered(prot) \
 	__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED)
 
+#define pgprot_device(prot) \
+	__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_DEV_NONSHARED)
+
+#define pgprot_writethroughcache(prot) \
+	__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_WRITETHROUGH)
+
+#define pgprot_writebackcache(prot) \
+	__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_WRITEBACK)
+
+#define pgprot_writebackwacache(prot) \
+	__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_WRITEALLOC)
+
 #ifdef CONFIG_ARM_DMA_MEM_BUFFERABLE
 #define pgprot_dmacoherent(prot) \
 	__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BUFFERABLE | L_PTE_XN)
 #define __HAVE_PHYS_MEM_ACCESS_PROT
+#define COHERENT_IS_NORMAL 1
 struct file;
 extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
 				     unsigned long size, pgprot_t vma_prot);
 #else
 #define pgprot_dmacoherent(prot) \
 	__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED | L_PTE_XN)
+#define COHERENT_IS_NORMAL 0
 #endif
 
 #endif /* __ASSEMBLY__ */
@@ -306,7 +320,7 @@
  * into virtual address `from'
  */
 #define io_remap_pfn_range(vma,from,pfn,size,prot) \
-		remap_pfn_range(vma, from, pfn, size, prot)
+	remap_pfn_range(vma,from,pfn,size,prot)
 
 #define pgtable_cache_init() do { } while (0)
 
diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h
index 90114fa..1e54b58 100644
--- a/arch/arm/include/asm/pmu.h
+++ b/arch/arm/include/asm/pmu.h
@@ -21,6 +21,7 @@
  */
 enum arm_pmu_type {
 	ARM_PMU_DEVICE_CPU	= 0,
+	ARM_PMU_DEVICE_L2	= 1,
 	ARM_NUM_PMU_DEVICES,
 };
 
@@ -108,7 +109,9 @@
 	cpumask_t	active_irqs;
 	const char	*name;
 	irqreturn_t	(*handle_irq)(int irq_num, void *dev);
-	void		(*enable)(struct hw_perf_event *evt, int idx);
+	int     	(*request_pmu_irq)(int irq, irq_handler_t *irq_h);
+	void    	(*free_pmu_irq)(int irq);
+	void		(*enable)(struct hw_perf_event *evt, int idx, int cpu);
 	void		(*disable)(struct hw_perf_event *evt, int idx);
 	int		(*get_event_idx)(struct pmu_hw_events *hw_events,
 					 struct hw_perf_event *hwc);
diff --git a/arch/arm/include/asm/processor.h b/arch/arm/include/asm/processor.h
index 5ac8d3d..07209d7 100644
--- a/arch/arm/include/asm/processor.h
+++ b/arch/arm/include/asm/processor.h
@@ -29,6 +29,8 @@
 #define STACK_TOP_MAX	TASK_SIZE
 #endif
 
+extern unsigned int boot_reason;
+
 struct debug_info {
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
 	struct perf_event	*hbp[ARM_MAX_HBP_SLOTS];
diff --git a/arch/arm/include/asm/remote_spinlock.h b/arch/arm/include/asm/remote_spinlock.h
new file mode 100644
index 0000000..702b669
--- /dev/null
+++ b/arch/arm/include/asm/remote_spinlock.h
@@ -0,0 +1,18 @@
+/* Copyright (c) 2009, 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 __ASM_REMOTE_SPINLOCK_H
+#define __ASM_REMOTE_SPINLOCK_H
+
+#include <mach/remote_spinlock.h>
+
+#endif /* __ASM_REMOTE_SPINLOCK_H */
diff --git a/arch/arm/include/asm/setup.h b/arch/arm/include/asm/setup.h
index 23ebc0c..d1f9709 100644
--- a/arch/arm/include/asm/setup.h
+++ b/arch/arm/include/asm/setup.h
@@ -211,7 +211,8 @@
 	for (iter = 0; iter < (mi)->nr_banks; iter++)
 
 #define bank_pfn_start(bank)	__phys_to_pfn((bank)->start)
-#define bank_pfn_end(bank)	__phys_to_pfn((bank)->start + (bank)->size)
+#define bank_pfn_end(bank)	(__phys_to_pfn((bank)->start) + \
+						__phys_to_pfn((bank)->size))
 #define bank_pfn_size(bank)	((bank)->size >> PAGE_SHIFT)
 #define bank_phys_start(bank)	(bank)->start
 #define bank_phys_end(bank)	((bank)->start + (bank)->size)
@@ -221,6 +222,18 @@
 extern void early_print(const char *str, ...);
 extern void dump_machine_table(void);
 
+/*
+ * Early command line parameters.
+ */
+struct early_params {
+	const char *arg;
+	void (*fn)(char **p);
+};
+
+#define __early_param(name,fn)					\
+static struct early_params __early_##fn __used			\
+__attribute__((__section__(".early_param.init"))) = { name, fn }
+
 #endif  /*  __KERNEL__  */
 
 #endif
diff --git a/arch/arm/include/asm/spinlock.h b/arch/arm/include/asm/spinlock.h
index 65fa3c8..582c9b3 100644
--- a/arch/arm/include/asm/spinlock.h
+++ b/arch/arm/include/asm/spinlock.h
@@ -58,6 +58,7 @@
 #endif
 }
 
+#ifndef CONFIG_ARM_TICKET_LOCKS
 /*
  * ARMv6 Spin-locking.
  *
@@ -126,6 +127,131 @@
 
 	dsb_sev();
 }
+#else
+/*
+ * ARM Ticket spin-locking
+ *
+ * Ticket locks are conceptually two parts, one indicating the current head of
+ * the queue, and the other indicating the current tail. The lock is acquired
+ * by atomically noting the tail and incrementing it by one (thus adding
+ * ourself to the queue and noting our position), then waiting until the head
+ * becomes equal to the the initial value of the tail.
+ *
+ * Unlocked value: 0
+ * Locked value: now_serving != next_ticket
+ *
+ *   31             17  16    15  14                    0
+ *  +----------------------------------------------------+
+ *  |  now_serving          |     next_ticket            |
+ *  +----------------------------------------------------+
+ */
+
+#define TICKET_SHIFT	16
+#define TICKET_BITS	16
+#define	TICKET_MASK	0xFFFF
+
+#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
+
+static inline void arch_spin_lock(arch_spinlock_t *lock)
+{
+	unsigned long tmp, ticket, next_ticket;
+
+	/* Grab the next ticket and wait for it to be "served" */
+	__asm__ __volatile__(
+"1:	ldrex	%[ticket], [%[lockaddr]]\n"
+"	uadd16	%[next_ticket], %[ticket], %[val1]\n"
+"	strex	%[tmp], %[next_ticket], [%[lockaddr]]\n"
+"	teq	%[tmp], #0\n"
+"	bne	1b\n"
+"	uxth	%[ticket], %[ticket]\n"
+"2:\n"
+#ifdef CONFIG_CPU_32v6K
+"	wfene\n"
+#endif
+"	ldr	%[tmp], [%[lockaddr]]\n"
+"	cmp	%[ticket], %[tmp], lsr #16\n"
+"	bne	2b"
+	: [ticket]"=&r" (ticket), [tmp]"=&r" (tmp), [next_ticket]"=&r" (next_ticket)
+	: [lockaddr]"r" (&lock->lock), [val1]"r" (1)
+	: "cc");
+	smp_mb();
+}
+
+static inline int arch_spin_trylock(arch_spinlock_t *lock)
+{
+	unsigned long tmp, ticket, next_ticket;
+
+	/* Grab lock if now_serving == next_ticket and access is exclusive */
+	__asm__ __volatile__(
+"	ldrex	%[ticket], [%[lockaddr]]\n"
+"	ror	%[tmp], %[ticket], #16\n"
+"	eors	%[tmp], %[tmp], %[ticket]\n"
+"	bne	1f\n"
+"	uadd16	%[next_ticket], %[ticket], %[val1]\n"
+"	strex	%[tmp], %[next_ticket], [%[lockaddr]]\n"
+"1:"
+	: [ticket]"=&r" (ticket), [tmp]"=&r" (tmp),
+	  [next_ticket]"=&r" (next_ticket)
+	: [lockaddr]"r" (&lock->lock), [val1]"r" (1)
+	: "cc");
+	if (!tmp)
+		smp_mb();
+	return !tmp;
+}
+
+static inline void arch_spin_unlock(arch_spinlock_t *lock)
+{
+	unsigned long ticket, tmp;
+
+	smp_mb();
+
+	/* Bump now_serving by 1 */
+	__asm__ __volatile__(
+"1:	ldrex	%[ticket], [%[lockaddr]]\n"
+"	uadd16	%[ticket], %[ticket], %[serving1]\n"
+"	strex	%[tmp], %[ticket], [%[lockaddr]]\n"
+"	teq	%[tmp], #0\n"
+"	bne	1b"
+	: [ticket]"=&r" (ticket), [tmp]"=&r" (tmp)
+	: [lockaddr]"r" (&lock->lock), [serving1]"r" (0x00010000)
+	: "cc");
+	dsb_sev();
+}
+
+static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
+{
+	unsigned long ticket;
+
+	/* Wait for now_serving == next_ticket */
+	__asm__ __volatile__(
+#ifdef CONFIG_CPU_32v6K
+"	cmpne	%[lockaddr], %[lockaddr]\n"
+"1:	wfene\n"
+#else
+"1:\n"
+#endif
+"	ldr	%[ticket], [%[lockaddr]]\n"
+"	eor	%[ticket], %[ticket], %[ticket], lsr #16\n"
+"	uxth	%[ticket], %[ticket]\n"
+"	cmp	%[ticket], #0\n"
+"	bne	1b"
+	: [ticket]"=&r" (ticket)
+	: [lockaddr]"r" (&lock->lock)
+	: "cc");
+}
+
+static inline int arch_spin_is_locked(arch_spinlock_t *lock)
+{
+	unsigned long tmp = ACCESS_ONCE(lock->lock);
+	return (((tmp >> TICKET_SHIFT) ^ tmp) & TICKET_MASK) != 0;
+}
+
+static inline int arch_spin_is_contended(arch_spinlock_t *lock)
+{
+	unsigned long tmp = ACCESS_ONCE(lock->lock);
+	return ((tmp - (tmp >> TICKET_SHIFT)) & TICKET_MASK) > 1;
+}
+#endif
 
 /*
  * RWLOCKS
diff --git a/arch/arm/include/asm/tlbflush.h b/arch/arm/include/asm/tlbflush.h
index 85fe61e..d44d33f 100644
--- a/arch/arm/include/asm/tlbflush.h
+++ b/arch/arm/include/asm/tlbflush.h
@@ -409,7 +409,7 @@
 	tlb_op(TLB_V6_U_PAGE, "c8, c7, 1", uaddr);
 	tlb_op(TLB_V6_D_PAGE, "c8, c6, 1", uaddr);
 	tlb_op(TLB_V6_I_PAGE, "c8, c5, 1", uaddr);
-#ifdef CONFIG_ARM_ERRATA_720789
+#if defined(CONFIG_ARM_ERRATA_720789) || defined(CONFIG_ARCH_MSM8X60)
 	tlb_op(TLB_V7_UIS_PAGE, "c8, c3, 3", uaddr & PAGE_MASK);
 #else
 	tlb_op(TLB_V7_UIS_PAGE, "c8, c3, 1", uaddr);
@@ -439,7 +439,11 @@
 	tlb_op(TLB_V6_U_PAGE, "c8, c7, 1", kaddr);
 	tlb_op(TLB_V6_D_PAGE, "c8, c6, 1", kaddr);
 	tlb_op(TLB_V6_I_PAGE, "c8, c5, 1", kaddr);
+#ifdef CONFIG_ARCH_MSM8X60
+	tlb_op(TLB_V7_UIS_PAGE, "c8, c3, 3", kaddr);
+#else
 	tlb_op(TLB_V7_UIS_PAGE, "c8, c3, 1", kaddr);
+#endif
 
 	if (tlb_flag(TLB_BARRIER)) {
 		dsb();
diff --git a/arch/arm/include/asm/vfp.h b/arch/arm/include/asm/vfp.h
index f4ab34f..5a1e789 100644
--- a/arch/arm/include/asm/vfp.h
+++ b/arch/arm/include/asm/vfp.h
@@ -21,7 +21,7 @@
 #define FPSID_FORMAT_MASK	(0x3  << FPSID_FORMAT_BIT)
 #define FPSID_NODOUBLE		(1<<20)
 #define FPSID_ARCH_BIT		(16)
-#define FPSID_ARCH_MASK		(0xF  << FPSID_ARCH_BIT)
+#define FPSID_ARCH_MASK		(0x7F  << FPSID_ARCH_BIT)
 #define FPSID_PART_BIT		(8)
 #define FPSID_PART_MASK		(0xFF << FPSID_PART_BIT)
 #define FPSID_VARIANT_BIT	(4)
@@ -82,3 +82,8 @@
 #define VFPOPDESC_UNUSED_BIT	(24)
 #define VFPOPDESC_UNUSED_MASK	(0xFF << VFPOPDESC_UNUSED_BIT)
 #define VFPOPDESC_OPDESC_MASK	(~(VFPOPDESC_LENGTH_MASK | VFPOPDESC_UNUSED_MASK))
+
+#ifndef __ASSEMBLY__
+int vfp_pm_suspend(void);
+void vfp_pm_resume(void);
+#endif
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 7b787d6..22b0f1e 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -34,6 +34,7 @@
 obj-$(CONFIG_SMP)		+= smp.o smp_tlb.o
 obj-$(CONFIG_HAVE_ARM_SCU)	+= smp_scu.o
 obj-$(CONFIG_HAVE_ARM_TWD)	+= smp_twd.o
+obj-$(CONFIG_ARM_ARCH_TIMER)	+= arch_timer.o
 obj-$(CONFIG_DYNAMIC_FTRACE)	+= ftrace.o insn.o
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER)	+= ftrace.o insn.o
 obj-$(CONFIG_JUMP_LABEL)	+= jump_label.o insn.o patch.o
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
new file mode 100644
index 0000000..81a9a71
--- /dev/null
+++ b/arch/arm/kernel/arch_timer.c
@@ -0,0 +1,378 @@
+/*
+ *  linux/arch/arm/kernel/arch_timer.c
+ *
+ *  Copyright (C) 2011 ARM Ltd.
+ *  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 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timex.h>
+#include <linux/device.h>
+#include <linux/smp.h>
+#include <linux/cpu.h>
+#include <linux/jiffies.h>
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/of_irq.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include <asm/cputype.h>
+#include <asm/localtimer.h>
+#include <asm/arch_timer.h>
+#include <asm/sched_clock.h>
+#include <asm/hardware/gic.h>
+#include <asm/system_info.h>
+
+static unsigned long arch_timer_rate;
+static int arch_timer_ppi;
+static int arch_timer_ppi2;
+
+static struct clock_event_device __percpu **arch_timer_evt;
+
+/*
+ * Architected system timer support.
+ */
+
+#define ARCH_TIMER_CTRL_ENABLE		(1 << 0)
+#define ARCH_TIMER_CTRL_IT_MASK		(1 << 1)
+#define ARCH_TIMER_CTRL_IT_STAT		(1 << 2)
+
+#define ARCH_TIMER_REG_CTRL		0
+#define ARCH_TIMER_REG_FREQ		1
+#define ARCH_TIMER_REG_TVAL		2
+
+static void arch_timer_reg_write(int reg, u32 val)
+{
+	switch (reg) {
+	case ARCH_TIMER_REG_CTRL:
+		asm volatile("mcr p15, 0, %0, c14, c2, 1" : : "r" (val));
+		break;
+	case ARCH_TIMER_REG_TVAL:
+		asm volatile("mcr p15, 0, %0, c14, c2, 0" : : "r" (val));
+		break;
+	}
+
+	isb();
+}
+
+static u32 arch_timer_reg_read(int reg)
+{
+	u32 val;
+
+	switch (reg) {
+	case ARCH_TIMER_REG_CTRL:
+		asm volatile("mrc p15, 0, %0, c14, c2, 1" : "=r" (val));
+		break;
+	case ARCH_TIMER_REG_FREQ:
+		asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (val));
+		break;
+	case ARCH_TIMER_REG_TVAL:
+		asm volatile("mrc p15, 0, %0, c14, c2, 0" : "=r" (val));
+		break;
+	default:
+		BUG();
+	}
+
+	return val;
+}
+
+static irqreturn_t arch_timer_handler(int irq, void *dev_id)
+{
+	struct clock_event_device *evt;
+	unsigned long ctrl;
+
+	ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL);
+	if (ctrl & ARCH_TIMER_CTRL_IT_STAT) {
+		ctrl |= ARCH_TIMER_CTRL_IT_MASK;
+		arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl);
+		evt = *__this_cpu_ptr(arch_timer_evt);
+		evt->event_handler(evt);
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+static void arch_timer_disable(void)
+{
+	unsigned long ctrl;
+
+	ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL);
+	ctrl &= ~ARCH_TIMER_CTRL_ENABLE;
+	arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl);
+}
+
+static void arch_timer_set_mode(enum clock_event_mode mode,
+				struct clock_event_device *clk)
+{
+	switch (mode) {
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		arch_timer_disable();
+		break;
+	default:
+		break;
+	}
+}
+
+static int arch_timer_set_next_event(unsigned long evt,
+				     struct clock_event_device *unused)
+{
+	unsigned long ctrl;
+
+	ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL);
+	ctrl |= ARCH_TIMER_CTRL_ENABLE;
+	ctrl &= ~ARCH_TIMER_CTRL_IT_MASK;
+
+	arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl);
+	arch_timer_reg_write(ARCH_TIMER_REG_TVAL, evt);
+
+	return 0;
+}
+
+static int __cpuinit arch_timer_setup(struct clock_event_device *clk)
+{
+	/* setup clock event only once for CPU 0 */
+	if (!smp_processor_id() && clk->irq == arch_timer_ppi)
+		return 0;
+
+	/* Be safe... */
+	arch_timer_disable();
+
+	clk->features = CLOCK_EVT_FEAT_ONESHOT;
+	clk->name = "arch_sys_timer";
+	clk->rating = 450;
+	clk->set_mode = arch_timer_set_mode;
+	clk->set_next_event = arch_timer_set_next_event;
+	clk->irq = arch_timer_ppi;
+
+	clockevents_config_and_register(clk, arch_timer_rate,
+					0xf, 0x7fffffff);
+
+	*__this_cpu_ptr(arch_timer_evt) = clk;
+
+	enable_percpu_irq(clk->irq, 0);
+	if (arch_timer_ppi2)
+		enable_percpu_irq(arch_timer_ppi2, 0);
+
+	return 0;
+}
+
+/* Is the optional system timer available? */
+static int local_timer_is_architected(void)
+{
+	return (cpu_architecture() >= CPU_ARCH_ARMv7) &&
+	       ((read_cpuid_ext(CPUID_EXT_PFR1) >> 16) & 0xf) == 1;
+}
+
+static int arch_timer_available(void)
+{
+	unsigned long freq;
+
+	if (!local_timer_is_architected())
+		return -ENXIO;
+
+	if (arch_timer_rate == 0) {
+		arch_timer_reg_write(ARCH_TIMER_REG_CTRL, 0);
+		freq = arch_timer_reg_read(ARCH_TIMER_REG_FREQ);
+
+		/* Check the timer frequency. */
+		if (freq == 0) {
+			pr_warn("Architected timer frequency not available\n");
+			return -EINVAL;
+		}
+
+		arch_timer_rate = freq;
+		pr_info("Architected local timer running at %lu.%02luMHz.\n",
+			freq / 1000000, (freq / 10000) % 100);
+	}
+
+	return 0;
+}
+
+static inline cycle_t arch_counter_get_cntpct(void)
+{
+	u32 cvall, cvalh;
+
+	asm volatile("mrrc p15, 0, %0, %1, c14" : "=r" (cvall), "=r" (cvalh));
+
+	return ((cycle_t) cvalh << 32) | cvall;
+}
+
+static inline cycle_t arch_counter_get_cntvct(void)
+{
+	u32 cvall, cvalh;
+
+	asm volatile("mrrc p15, 1, %0, %1, c14" : "=r" (cvall), "=r" (cvalh));
+
+	return ((cycle_t) cvalh << 32) | cvall;
+}
+
+static cycle_t arch_counter_read(struct clocksource *cs)
+{
+	return arch_counter_get_cntpct();
+}
+
+#ifdef ARCH_HAS_READ_CURRENT_TIMER
+int read_current_timer(unsigned long *timer_val)
+{
+	*timer_val = (unsigned long)arch_counter_get_cntpct();
+	return 0;
+}
+#endif
+
+static struct clocksource clocksource_counter = {
+	.name	= "arch_sys_counter",
+	.rating	= 400,
+	.read	= arch_counter_read,
+	.mask	= CLOCKSOURCE_MASK(56),
+	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static u32 arch_counter_get_cntvct32(void)
+{
+	cycle_t cntvct;
+
+	cntvct = arch_counter_get_cntvct();
+
+	/*
+	 * The sched_clock infrastructure only knows about counters
+	 * with at most 32bits. Forget about the upper 24 bits for the
+	 * time being...
+	 */
+	return (u32)(cntvct & (u32)~0);
+}
+
+static u32 notrace arch_timer_update_sched_clock(void)
+{
+	return arch_counter_get_cntvct32();
+}
+
+static void __cpuinit arch_timer_stop(struct clock_event_device *clk)
+{
+	pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n",
+		 clk->irq, smp_processor_id());
+	disable_percpu_irq(clk->irq);
+	if (arch_timer_ppi2)
+		disable_percpu_irq(arch_timer_ppi2);
+	arch_timer_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
+}
+
+static struct local_timer_ops arch_timer_ops __cpuinitdata = {
+	.setup	= arch_timer_setup,
+	.stop	= arch_timer_stop,
+};
+
+static int __init arch_timer_common_register(void)
+{
+	int err;
+
+	err = arch_timer_available();
+	if (err)
+		return err;
+
+	arch_timer_evt = alloc_percpu(struct clock_event_device *);
+	if (!arch_timer_evt)
+		return -ENOMEM;
+
+	clocksource_register_hz(&clocksource_counter, arch_timer_rate);
+
+	setup_sched_clock(arch_timer_update_sched_clock, 32, arch_timer_rate);
+
+#ifdef ARCH_HAS_READ_CURRENT_TIMER
+	set_delay_fn(read_current_timer_delay_loop);
+#endif
+
+	err = request_percpu_irq(arch_timer_ppi, arch_timer_handler,
+				 "arch_timer", arch_timer_evt);
+	if (err) {
+		pr_err("arch_timer: can't register interrupt %d (%d)\n",
+		       arch_timer_ppi, err);
+		goto out_free;
+	}
+
+	if (arch_timer_ppi2) {
+		err = request_percpu_irq(arch_timer_ppi2, arch_timer_handler,
+					 "arch_timer", arch_timer_evt);
+		if (err) {
+			pr_err("arch_timer: can't register interrupt %d (%d)\n",
+			       arch_timer_ppi2, err);
+			arch_timer_ppi2 = 0;
+			goto out_free_irq;
+		}
+	}
+
+	err = local_timer_register(&arch_timer_ops);
+	if (err)
+		goto out_free_irq;
+	percpu_timer_setup();
+
+	return 0;
+
+out_free_irq:
+	free_percpu_irq(arch_timer_ppi, arch_timer_evt);
+	if (arch_timer_ppi2)
+		free_percpu_irq(arch_timer_ppi2, arch_timer_evt);
+
+out_free:
+	free_percpu(arch_timer_evt);
+
+	return err;
+}
+
+int __init arch_timer_register(struct arch_timer *at)
+{
+	if (at->res[0].start <= 0 || !(at->res[0].flags & IORESOURCE_IRQ))
+		return -EINVAL;
+
+	arch_timer_ppi = at->res[0].start;
+
+	if (at->res[1].start > 0 && (at->res[1].flags & IORESOURCE_IRQ))
+		arch_timer_ppi2 = at->res[1].start;
+
+	return arch_timer_common_register();
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id arch_timer_of_match[] __initconst = {
+	{ .compatible	= "arm,armv7-timer",	},
+	{},
+};
+
+int __init arch_timer_of_register(void)
+{
+	struct device_node *np;
+	u32 freq;
+	int ret;
+
+	np = of_find_matching_node(NULL, arch_timer_of_match);
+	if (!np) {
+		pr_err("arch_timer: can't find DT node\n");
+		return -ENODEV;
+	}
+
+	/* Try to determine the frequency from the device tree or CNTFRQ */
+	if (!of_property_read_u32(np, "clock-frequency", &freq))
+		arch_timer_rate = freq;
+
+	ret = irq_of_parse_and_map(np, 0);
+	if (ret <= 0) {
+		pr_err("arch_timer: interrupt not specified in timer node\n");
+		return -ENODEV;
+	}
+	arch_timer_ppi = ret;
+	ret = irq_of_parse_and_map(np, 1);
+	if (ret > 0)
+		arch_timer_ppi2 = ret;
+	pr_info("arch_timer: found %s irqs %d %d\n",
+		np->name, arch_timer_ppi, arch_timer_ppi2);
+
+	return arch_timer_common_register();
+}
+#endif
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
index b57c75e..f1a50f3 100644
--- a/arch/arm/kernel/armksyms.c
+++ b/arch/arm/kernel/armksyms.c
@@ -48,10 +48,6 @@
 
 extern void fpundefinstr(void);
 
-	/* platform dependent support */
-EXPORT_SYMBOL(__udelay);
-EXPORT_SYMBOL(__const_udelay);
-
 	/* networking */
 EXPORT_SYMBOL(csum_partial);
 EXPORT_SYMBOL(csum_partial_copy_from_user);
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 7fd3ad0..7c44acd 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -713,8 +713,15 @@
 	ldr	r7, [r7, #TSK_STACK_CANARY]
 #endif
 #ifdef CONFIG_CPU_USE_DOMAINS
+#ifdef CONFIG_EMULATE_DOMAIN_MANAGER_V7
+	stmdb	r13!, {r0-r3, lr}
+	mov	r0, r6
+	bl	emulate_domain_manager_set
+	ldmia	r13!, {r0-r3, lr}
+#else
 	mcr	p15, 0, r6, c3, c0, 0		@ Set domain register
 #endif
+#endif
 	mov	r5, r0
 	add	r4, r2, #TI_CPU_SAVE
 	ldr	r0, =thread_notify_head
diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c
index bf17145..1ef5022 100644
--- a/arch/arm/kernel/ftrace.c
+++ b/arch/arm/kernel/ftrace.c
@@ -78,6 +78,20 @@
 	return 0;
 }
 
+int ftrace_arch_code_modify_prepare(void)
+{
+	set_kernel_text_rw();
+	set_all_modules_text_rw();
+	return 0;
+}
+
+int ftrace_arch_code_modify_post_process(void)
+{
+	set_all_modules_text_ro();
+	set_kernel_text_ro();
+	return 0;
+}
+
 static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr)
 {
 	return arm_gen_branch_link(pc, addr);
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index 3bf0c7f..313ff0b 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -337,7 +337,6 @@
 	.long	__turn_mmu_on_end
 
 #if defined(CONFIG_SMP)
-	__CPUINIT
 ENTRY(secondary_startup)
 	/*
 	 * Common entry point for secondary CPUs.
@@ -422,10 +421,17 @@
 	mov	r5, #0
 	mcrr	p15, 0, r4, r5, c2		@ load TTBR0
 #else
-	mov	r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \
-		      domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \
-		      domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \
+#ifdef CONFIG_EMULATE_DOMAIN_MANAGER_V7
+	mov	r5, #(domain_val(DOMAIN_USER, DOMAIN_CLIENT) | \
+		      domain_val(DOMAIN_KERNEL, DOMAIN_CLIENT) | \
+		      domain_val(DOMAIN_TABLE, DOMAIN_CLIENT) | \
 		      domain_val(DOMAIN_IO, DOMAIN_CLIENT))
+#else
+	mov	r5, #(domain_val(DOMAIN_USER, DOMAIN_CLIENT) | \
+		      domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \
+		      domain_val(DOMAIN_TABLE, DOMAIN_CLIENT) | \
+		      domain_val(DOMAIN_IO, DOMAIN_CLIENT))
+#endif
 	mcr	p15, 0, r5, c3, c0, 0		@ load domain access register
 	mcr	p15, 0, r4, c2, c0, 0		@ load page table pointer
 #endif
@@ -455,6 +461,15 @@
 	mrc	p15, 0, r3, c0, c0, 0		@ read id reg
 	instr_sync
 	mov	r3, r3
+#ifdef CONFIG_ARCH_MSM_KRAIT
+	ldr	r3, =0xff00fc00
+	and	r3, r9, r3
+	ldr 	r4, =0x51000400
+	cmp	r3, r4
+	mrceq	p15, 7, r3, c15, c0, 2
+	biceq	r3, r3, #0x400
+	mcreq	p15, 7, r3, c15, c0, 2
+#endif
 	mov	r3, r13
 	mov	pc, r3
 __turn_mmu_on_end:
diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c
index ba386bd..ff2c0ad 100644
--- a/arch/arm/kernel/hw_breakpoint.c
+++ b/arch/arm/kernel/hw_breakpoint.c
@@ -853,6 +853,18 @@
 	return ret;
 }
 
+static void reset_brps_reserved_reg(int n)
+{
+	int i;
+
+	/* we must also reset any reserved registers. */
+	for (i = 0; i < n; ++i) {
+		write_wb_reg(ARM_BASE_BCR + i, 0UL);
+		write_wb_reg(ARM_BASE_BVR + i, 0UL);
+	}
+
+}
+
 /*
  * One-time initialisation.
  */
@@ -938,12 +950,11 @@
 	if (enable_monitor_mode())
 		return;
 
-	/* We must also reset any reserved registers. */
-	raw_num_brps = get_num_brp_resources();
-	for (i = 0; i < raw_num_brps; ++i) {
-		write_wb_reg(ARM_BASE_BCR + i, 0UL);
-		write_wb_reg(ARM_BASE_BVR + i, 0UL);
-	}
+#ifdef CONFIG_HAVE_HW_BRKPT_RESERVED_RW_ACCESS
+	reset_brps_reserved_reg(core_num_brps);
+#else
+	reset_brps_reserved_reg(core_num_brps + core_num_reserved_brps);
+#endif
 
 	for (i = 0; i < core_num_wrps; ++i) {
 		write_wb_reg(ARM_BASE_WCR + i, 0UL);
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index 8349d4e..bc48bff 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -40,6 +40,8 @@
 #include <asm/mach/irq.h>
 #include <asm/mach/time.h>
 
+#include <asm/perftypes.h>
+
 /*
  * No architecture-specific irq_finish function defined in arm/arch/irqs.h.
  */
@@ -71,6 +73,7 @@
 {
 	struct pt_regs *old_regs = set_irq_regs(regs);
 
+	perf_mon_interrupt_in();
 	irq_enter();
 
 	/*
@@ -90,6 +93,7 @@
 
 	irq_exit();
 	set_irq_regs(old_regs);
+	perf_mon_interrupt_out();
 }
 
 /*
@@ -128,8 +132,18 @@
 #ifdef CONFIG_SPARSE_IRQ
 int __init arch_probe_nr_irqs(void)
 {
-	nr_irqs = machine_desc->nr_irqs ? machine_desc->nr_irqs : NR_IRQS;
-	return nr_irqs;
+	/*
+	 * machine_desc->nr_irqs < 0 is a special case that
+	 * specifies not to preallocate any irq_descs.
+	 */
+	if (machine_desc->nr_irqs < 0) {
+		nr_irqs = 0;
+		return nr_irqs;
+	} else {
+		nr_irqs = machine_desc->nr_irqs ?
+			  machine_desc->nr_irqs : NR_IRQS;
+		return nr_irqs;
+	}
 }
 #endif
 
diff --git a/arch/arm/kernel/patch.c b/arch/arm/kernel/patch.c
index 07314af..7a27c47 100644
--- a/arch/arm/kernel/patch.c
+++ b/arch/arm/kernel/patch.c
@@ -5,6 +5,7 @@
 #include <asm/cacheflush.h>
 #include <asm/smp_plat.h>
 #include <asm/opcodes.h>
+#include <asm/mmu_writeable.h>
 
 #include "patch.h"
 
@@ -17,6 +18,10 @@
 {
 	bool thumb2 = IS_ENABLED(CONFIG_THUMB2_KERNEL);
 	int size;
+	unsigned long flags;
+
+	mem_text_writeable_spinlock(&flags);
+	mem_text_address_writeable((unsigned long)addr);
 
 	if (thumb2 && __opcode_is_thumb16(insn)) {
 		*(u16 *)addr = __opcode_to_mem_thumb16(insn);
@@ -42,6 +47,9 @@
 
 	flush_icache_range((uintptr_t)(addr),
 			   (uintptr_t)(addr) + size);
+
+	mem_text_address_restore();
+	mem_text_writeable_spinunlock(&flags);
 }
 
 static int __kprobes patch_text_stop_machine(void *data)
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 186c8cb..af6e7e6 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -20,6 +20,7 @@
 #include <linux/platform_device.h>
 #include <linux/spinlock.h>
 #include <linux/uaccess.h>
+#include <linux/irq.h>
 
 #include <asm/cputype.h>
 #include <asm/irq.h>
@@ -78,7 +79,7 @@
 #define CACHE_OP_UNSUPPORTED		0xFFFF
 
 static int
-armpmu_map_cache_event(const unsigned (*cache_map)
+armpmu_map_cache_event(unsigned (*cache_map)
 				      [PERF_COUNT_HW_CACHE_MAX]
 				      [PERF_COUNT_HW_CACHE_OP_MAX]
 				      [PERF_COUNT_HW_CACHE_RESULT_MAX],
@@ -121,7 +122,7 @@
 
 static int map_cpu_event(struct perf_event *event,
 			 const unsigned (*event_map)[PERF_COUNT_HW_MAX],
-			 const unsigned (*cache_map)
+			 unsigned (*cache_map)
 					[PERF_COUNT_HW_CACHE_MAX]
 					[PERF_COUNT_HW_CACHE_OP_MAX]
 					[PERF_COUNT_HW_CACHE_RESULT_MAX],
@@ -253,7 +254,7 @@
 	 * happened since disabling.
 	 */
 	armpmu_event_set_period(event, hwc, hwc->idx);
-	armpmu->enable(hwc, hwc->idx);
+	armpmu->enable(hwc, hwc->idx, event->cpu);
 }
 
 static void
@@ -362,25 +363,44 @@
 	return plat->handle_irq(irq, dev, armpmu->handle_irq);
 }
 
+int
+armpmu_generic_request_irq(int irq, irq_handler_t *handle_irq)
+{
+        return request_irq(irq, *handle_irq,
+                        IRQF_DISABLED | IRQF_NOBALANCING,
+                        "armpmu", NULL);
+}
+
+void
+armpmu_generic_free_irq(int irq)
+{
+        if (irq >= 0)
+                free_irq(irq, NULL);
+}
+
 static void
 armpmu_release_hardware(struct arm_pmu *armpmu)
 {
 	int i, irq, irqs;
 	struct platform_device *pmu_device = armpmu->plat_device;
+#if 0
 	struct arm_pmu_platdata *plat =
 		dev_get_platdata(&pmu_device->dev);
-
+#endif
 	irqs = min(pmu_device->num_resources, num_possible_cpus());
 
 	for (i = 0; i < irqs; ++i) {
 		if (!cpumask_test_and_clear_cpu(i, &armpmu->active_irqs))
 			continue;
 		irq = platform_get_irq(pmu_device, i);
+		armpmu->free_pmu_irq(irq);
+#if 0
 		if (irq >= 0) {
 			if (plat && plat->disable_irq)
 				plat->disable_irq(irq);
 			free_irq(irq, armpmu);
 		}
+#endif
 	}
 
 	release_pmu(armpmu->type);
@@ -432,6 +452,17 @@
 			continue;
 		}
 
+		err = armpmu->request_pmu_irq(irq, &handle_irq);
+
+                if (err) {
+                        pr_warning("unable to request IRQ%d for %s perf "
+                                "counters\n", irq, armpmu->name);
+
+			armpmu_release_hardware(cpu_pmu);
+                        return err;
+                }
+
+#if 0
 		err = request_irq(irq, handle_irq,
 				  IRQF_DISABLED | IRQF_NOBALANCING,
 				  "arm-pmu", armpmu);
@@ -442,6 +473,7 @@
 			return err;
 		} else if (plat && plat->enable_irq)
 			plat->enable_irq(irq);
+#endif
 
 		cpumask_set_cpu(i, &armpmu->active_irqs);
 	}
@@ -611,6 +643,7 @@
 #include "perf_event_xscale.c"
 #include "perf_event_v6.c"
 #include "perf_event_v7.c"
+#include "perf_event_msm_krait.c"
 
 /*
  * Ensure the PMU has sane values out of reset.
@@ -637,7 +670,7 @@
 };
 
 static struct platform_device_id armpmu_plat_device_ids[] = {
-	{.name = "arm-pmu"},
+	{.name = "cpu-arm-pmu"},
 	{},
 };
 
@@ -652,7 +685,7 @@
 
 static struct platform_driver armpmu_driver = {
 	.driver		= {
-		.name	= "arm-pmu",
+		.name	= "cpu-arm-pmu",
 		.of_match_table = armpmu_of_device_ids,
 	},
 	.probe		= armpmu_device_probe,
@@ -753,8 +786,28 @@
 			cpu_pmu = xscale2pmu_init();
 			break;
 		}
+	/* Qualcomm CPUs */
+	} else if (0x51 == implementor) {
+		switch (part_number) {
+		case 0x00F0:    /* 8x50 & 7x30*/
+//			cpu_pmu = armv7_scorpion_pmu_init();
+			break;
+		case 0x02D0:    /* 8x60 */
+//			fabricmon_pmu_init();
+//			cpu_pmu = armv7_scorpionmp_pmu_init();
+//			scorpionmp_l2_pmu_init();
+			break;
+		case 0x0490:    /* 8960 sim */
+		case 0x04D0:    /* 8960 */
+		case 0x06F0:    /* 8064 */
+//			fabricmon_pmu_init();
+			cpu_pmu = armv7_krait_pmu_init();
+//			krait_l2_pmu_init();
+			break;
+		}
 	}
 
+
 	if (cpu_pmu) {
 		pr_info("enabled with %s PMU driver, %d counters available\n",
 			cpu_pmu->name, cpu_pmu->num_events);
diff --git a/arch/arm/kernel/perf_event_msm.c b/arch/arm/kernel/perf_event_msm.c
new file mode 100644
index 0000000..0ca5164
--- /dev/null
+++ b/arch/arm/kernel/perf_event_msm.c
@@ -0,0 +1,792 @@
+/*
+ * 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
+ * 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/cpumask.h>
+
+#include <asm/vfp.h>
+#include <asm/system.h>
+#include "../vfp/vfpinstr.h"
+
+#ifdef CONFIG_CPU_V7
+#define SCORPION_EVT_PREFIX 1
+#define SCORPION_MAX_L1_REG 4
+
+#define SCORPION_EVTYPE_EVENT 0xfffff
+
+static u32 scorpion_evt_type_base[] = {0x4c, 0x50, 0x54, 0x58, 0x5c};
+
+enum scorpion_perf_common {
+	SCORPION_EVT_START_IDX			= 0x4c,
+	SCORPION_ICACHE_EXPL_INV		= 0x4c,
+	SCORPION_ICACHE_MISS			= 0x4d,
+	SCORPION_ICACHE_ACCESS			= 0x4e,
+	SCORPION_ICACHE_CACHEREQ_L2		= 0x4f,
+	SCORPION_ICACHE_NOCACHE_L2		= 0x50,
+	SCORPION_HIQUP_NOPED			= 0x51,
+	SCORPION_DATA_ABORT			= 0x52,
+	SCORPION_IRQ				= 0x53,
+	SCORPION_FIQ				= 0x54,
+	SCORPION_ALL_EXCPT			= 0x55,
+	SCORPION_UNDEF				= 0x56,
+	SCORPION_SVC				= 0x57,
+	SCORPION_SMC				= 0x58,
+	SCORPION_PREFETCH_ABORT			= 0x59,
+	SCORPION_INDEX_CHECK			= 0x5a,
+	SCORPION_NULL_CHECK			= 0x5b,
+	SCORPION_ICIMVAU_IMPL_ICIALLU		= 0x5c,
+	SCORPION_NONICIALLU_BTAC_INV		= 0x5d,
+	SCORPION_IMPL_ICIALLU			= 0x5e,
+	SCORPION_EXPL_ICIALLU			= 0x5f,
+	SCORPION_SPIPE_ONLY_CYCLES		= 0x60,
+	SCORPION_XPIPE_ONLY_CYCLES		= 0x61,
+	SCORPION_DUAL_CYCLES			= 0x62,
+	SCORPION_DISPATCH_ANY_CYCLES		= 0x63,
+	SCORPION_FIFO_FULLBLK_CMT		= 0x64,
+	SCORPION_FAIL_COND_INST			= 0x65,
+	SCORPION_PASS_COND_INST			= 0x66,
+	SCORPION_ALLOW_VU_CLK			= 0x67,
+	SCORPION_VU_IDLE			= 0x68,
+	SCORPION_ALLOW_L2_CLK			= 0x69,
+	SCORPION_L2_IDLE			= 0x6a,
+	SCORPION_DTLB_IMPL_INV_SCTLR_DACR	= 0x6b,
+	SCORPION_DTLB_EXPL_INV			= 0x6c,
+	SCORPION_DTLB_MISS			= 0x6d,
+	SCORPION_DTLB_ACCESS			= 0x6e,
+	SCORPION_ITLB_MISS			= 0x6f,
+	SCORPION_ITLB_IMPL_INV			= 0x70,
+	SCORPION_ITLB_EXPL_INV			= 0x71,
+	SCORPION_UTLB_D_MISS			= 0x72,
+	SCORPION_UTLB_D_ACCESS			= 0x73,
+	SCORPION_UTLB_I_MISS			= 0x74,
+	SCORPION_UTLB_I_ACCESS			= 0x75,
+	SCORPION_UTLB_INV_ASID			= 0x76,
+	SCORPION_UTLB_INV_MVA			= 0x77,
+	SCORPION_UTLB_INV_ALL			= 0x78,
+	SCORPION_S2_HOLD_RDQ_UNAVAIL		= 0x79,
+	SCORPION_S2_HOLD			= 0x7a,
+	SCORPION_S2_HOLD_DEV_OP			= 0x7b,
+	SCORPION_S2_HOLD_ORDER			= 0x7c,
+	SCORPION_S2_HOLD_BARRIER		= 0x7d,
+	SCORPION_VIU_DUAL_CYCLE			= 0x7e,
+	SCORPION_VIU_SINGLE_CYCLE		= 0x7f,
+	SCORPION_VX_PIPE_WAR_STALL_CYCLES	= 0x80,
+	SCORPION_VX_PIPE_WAW_STALL_CYCLES	= 0x81,
+	SCORPION_VX_PIPE_RAW_STALL_CYCLES	= 0x82,
+	SCORPION_VX_PIPE_LOAD_USE_STALL		= 0x83,
+	SCORPION_VS_PIPE_WAR_STALL_CYCLES	= 0x84,
+	SCORPION_VS_PIPE_WAW_STALL_CYCLES	= 0x85,
+	SCORPION_VS_PIPE_RAW_STALL_CYCLES	= 0x86,
+	SCORPION_EXCEPTIONS_INV_OPERATION	= 0x87,
+	SCORPION_EXCEPTIONS_DIV_BY_ZERO		= 0x88,
+	SCORPION_COND_INST_FAIL_VX_PIPE		= 0x89,
+	SCORPION_COND_INST_FAIL_VS_PIPE		= 0x8a,
+	SCORPION_EXCEPTIONS_OVERFLOW		= 0x8b,
+	SCORPION_EXCEPTIONS_UNDERFLOW		= 0x8c,
+	SCORPION_EXCEPTIONS_DENORM		= 0x8d,
+};
+
+enum scorpion_perf_smp {
+	SCORPIONMP_NUM_BARRIERS			= 0x8e,
+	SCORPIONMP_BARRIER_CYCLES		= 0x8f,
+};
+
+enum scorpion_perf_up {
+	SCORPION_BANK_AB_HIT			= 0x8e,
+	SCORPION_BANK_AB_ACCESS			= 0x8f,
+	SCORPION_BANK_CD_HIT			= 0x90,
+	SCORPION_BANK_CD_ACCESS			= 0x91,
+	SCORPION_BANK_AB_DSIDE_HIT		= 0x92,
+	SCORPION_BANK_AB_DSIDE_ACCESS		= 0x93,
+	SCORPION_BANK_CD_DSIDE_HIT		= 0x94,
+	SCORPION_BANK_CD_DSIDE_ACCESS		= 0x95,
+	SCORPION_BANK_AB_ISIDE_HIT		= 0x96,
+	SCORPION_BANK_AB_ISIDE_ACCESS		= 0x97,
+	SCORPION_BANK_CD_ISIDE_HIT		= 0x98,
+	SCORPION_BANK_CD_ISIDE_ACCESS		= 0x99,
+	SCORPION_ISIDE_RD_WAIT			= 0x9a,
+	SCORPION_DSIDE_RD_WAIT			= 0x9b,
+	SCORPION_BANK_BYPASS_WRITE		= 0x9c,
+	SCORPION_BANK_AB_NON_CASTOUT		= 0x9d,
+	SCORPION_BANK_AB_L2_CASTOUT		= 0x9e,
+	SCORPION_BANK_CD_NON_CASTOUT		= 0x9f,
+	SCORPION_BANK_CD_L2_CASTOUT		= 0xa0,
+};
+
+static const unsigned armv7_scorpion_perf_map[PERF_COUNT_HW_MAX] = {
+	[PERF_COUNT_HW_CPU_CYCLES]	    = ARMV7_PERFCTR_CPU_CYCLES,
+	[PERF_COUNT_HW_INSTRUCTIONS]	    = ARMV7_PERFCTR_INSTR_EXECUTED,
+	[PERF_COUNT_HW_CACHE_REFERENCES]    = HW_OP_UNSUPPORTED,
+	[PERF_COUNT_HW_CACHE_MISSES]	    = HW_OP_UNSUPPORTED,
+	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_PERFCTR_PC_WRITE,
+	[PERF_COUNT_HW_BRANCH_MISSES]	    = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
+	[PERF_COUNT_HW_BUS_CYCLES]	    = ARMV7_PERFCTR_CLOCK_CYCLES,
+};
+
+static unsigned armv7_scorpion_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
+					  [PERF_COUNT_HW_CACHE_OP_MAX]
+					  [PERF_COUNT_HW_CACHE_RESULT_MAX] = {
+	[C(L1D)] = {
+		/*
+		 * The performance counters don't differentiate between read
+		 * and write accesses/misses so this isn't strictly correct,
+		 * but it's the best we can do. Writes and reads get
+		 * combined.
+		 */
+		[C(OP_READ)] = {
+			[C(RESULT_ACCESS)]	= ARMV7_PERFCTR_DCACHE_ACCESS,
+			[C(RESULT_MISS)]	= ARMV7_PERFCTR_DCACHE_REFILL,
+		},
+		[C(OP_WRITE)] = {
+			[C(RESULT_ACCESS)]	= ARMV7_PERFCTR_DCACHE_ACCESS,
+			[C(RESULT_MISS)]	= ARMV7_PERFCTR_DCACHE_REFILL,
+		},
+		[C(OP_PREFETCH)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+	},
+	[C(L1I)] = {
+		[C(OP_READ)] = {
+			[C(RESULT_ACCESS)]	= SCORPION_ICACHE_ACCESS,
+			[C(RESULT_MISS)]	= SCORPION_ICACHE_MISS,
+		},
+		[C(OP_WRITE)] = {
+			[C(RESULT_ACCESS)]	= SCORPION_ICACHE_ACCESS,
+			[C(RESULT_MISS)]	= SCORPION_ICACHE_MISS,
+		},
+		[C(OP_PREFETCH)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+	},
+	[C(LL)] = {
+		[C(OP_READ)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+		[C(OP_WRITE)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+		[C(OP_PREFETCH)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+	},
+	[C(DTLB)] = {
+		/*
+		 * Only ITLB misses and DTLB refills are supported.
+		 * If users want the DTLB refills misses a raw counter
+		 * must be used.
+		 */
+		[C(OP_READ)] = {
+			[C(RESULT_ACCESS)]	= SCORPION_DTLB_ACCESS,
+			[C(RESULT_MISS)]	= SCORPION_DTLB_MISS,
+		},
+		[C(OP_WRITE)] = {
+			[C(RESULT_ACCESS)]	= SCORPION_DTLB_ACCESS,
+			[C(RESULT_MISS)]	= SCORPION_DTLB_MISS,
+		},
+		[C(OP_PREFETCH)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+	},
+	[C(ITLB)] = {
+		[C(OP_READ)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= SCORPION_ITLB_MISS,
+		},
+		[C(OP_WRITE)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= SCORPION_ITLB_MISS,
+		},
+		[C(OP_PREFETCH)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+	},
+	[C(BPU)] = {
+		[C(OP_READ)] = {
+			[C(RESULT_ACCESS)]
+					= ARMV7_PERFCTR_PC_BRANCH_PRED,
+			[C(RESULT_MISS)]
+					= ARMV7_PERFCTR_PC_BRANCH_PRED,
+		},
+		[C(OP_WRITE)] = {
+			[C(RESULT_ACCESS)]
+					= ARMV7_PERFCTR_PC_BRANCH_PRED,
+			[C(RESULT_MISS)]
+					= ARMV7_PERFCTR_PC_BRANCH_PRED,
+		},
+		[C(OP_PREFETCH)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+	},
+};
+
+struct scorpion_evt {
+	/*
+	 * The scorpion_evt_type field corresponds to the actual Scorpion
+	 * event codes. These map many-to-one to the armv7 defined codes
+	 */
+	u32 scorpion_evt_type;
+
+	/*
+	 * The group_setval field corresponds to the value that the group
+	 * register needs to be set to. This value is deduced from the row
+	 * and column that the event belongs to in the event table
+	 */
+	u32 group_setval;
+
+	/*
+	 * The groupcode corresponds to the group that the event belongs to.
+	 * Scorpion has 5 groups of events LPM0, LPM1, LPM2, L2LPM and VLPM
+	 * going from 0 to 4 in terms of the codes used
+	 */
+	u8 groupcode;
+
+	/*
+	 * The armv7_evt_type field corresponds to the armv7 defined event
+	 * code that the Scorpion events map to
+	 */
+	u32 armv7_evt_type;
+};
+
+static const struct scorpion_evt scorpion_event[] = {
+	{SCORPION_ICACHE_EXPL_INV,		0x80000500, 0, 0x4d},
+	{SCORPION_ICACHE_MISS,			0x80050000, 0, 0x4e},
+	{SCORPION_ICACHE_ACCESS,		0x85000000, 0, 0x4f},
+	{SCORPION_ICACHE_CACHEREQ_L2,		0x86000000, 0, 0x4f},
+	{SCORPION_ICACHE_NOCACHE_L2,		0x87000000, 0, 0x4f},
+	{SCORPION_HIQUP_NOPED,			0x80080000, 0, 0x4e},
+	{SCORPION_DATA_ABORT,			0x8000000a, 0, 0x4c},
+	{SCORPION_IRQ,				0x80000a00, 0, 0x4d},
+	{SCORPION_FIQ,				0x800a0000, 0, 0x4e},
+	{SCORPION_ALL_EXCPT,			0x8a000000, 0, 0x4f},
+	{SCORPION_UNDEF,			0x8000000b, 0, 0x4c},
+	{SCORPION_SVC,				0x80000b00, 0, 0x4d},
+	{SCORPION_SMC,				0x800b0000, 0, 0x4e},
+	{SCORPION_PREFETCH_ABORT,		0x8b000000, 0, 0x4f},
+	{SCORPION_INDEX_CHECK,			0x8000000c, 0, 0x4c},
+	{SCORPION_NULL_CHECK,			0x80000c00, 0, 0x4d},
+	{SCORPION_ICIMVAU_IMPL_ICIALLU,		0x8000000d, 0, 0x4c},
+	{SCORPION_NONICIALLU_BTAC_INV,		0x80000d00, 0, 0x4d},
+	{SCORPION_IMPL_ICIALLU,			0x800d0000, 0, 0x4e},
+	{SCORPION_EXPL_ICIALLU,			0x8d000000, 0, 0x4f},
+
+	{SCORPION_SPIPE_ONLY_CYCLES,		0x80000600, 1, 0x51},
+	{SCORPION_XPIPE_ONLY_CYCLES,		0x80060000, 1, 0x52},
+	{SCORPION_DUAL_CYCLES,			0x86000000, 1, 0x53},
+	{SCORPION_DISPATCH_ANY_CYCLES,		0x89000000, 1, 0x53},
+	{SCORPION_FIFO_FULLBLK_CMT,		0x8000000d, 1, 0x50},
+	{SCORPION_FAIL_COND_INST,		0x800d0000, 1, 0x52},
+	{SCORPION_PASS_COND_INST,		0x8d000000, 1, 0x53},
+	{SCORPION_ALLOW_VU_CLK,			0x8000000e, 1, 0x50},
+	{SCORPION_VU_IDLE,			0x80000e00, 1, 0x51},
+	{SCORPION_ALLOW_L2_CLK,			0x800e0000, 1, 0x52},
+	{SCORPION_L2_IDLE,			0x8e000000, 1, 0x53},
+
+	{SCORPION_DTLB_IMPL_INV_SCTLR_DACR,	0x80000001, 2, 0x54},
+	{SCORPION_DTLB_EXPL_INV,		0x80000100, 2, 0x55},
+	{SCORPION_DTLB_MISS,			0x80010000, 2, 0x56},
+	{SCORPION_DTLB_ACCESS,			0x81000000, 2, 0x57},
+	{SCORPION_ITLB_MISS,			0x80000200, 2, 0x55},
+	{SCORPION_ITLB_IMPL_INV,		0x80020000, 2, 0x56},
+	{SCORPION_ITLB_EXPL_INV,		0x82000000, 2, 0x57},
+	{SCORPION_UTLB_D_MISS,			0x80000003, 2, 0x54},
+	{SCORPION_UTLB_D_ACCESS,		0x80000300, 2, 0x55},
+	{SCORPION_UTLB_I_MISS,			0x80030000, 2, 0x56},
+	{SCORPION_UTLB_I_ACCESS,		0x83000000, 2, 0x57},
+	{SCORPION_UTLB_INV_ASID,		0x80000400, 2, 0x55},
+	{SCORPION_UTLB_INV_MVA,			0x80040000, 2, 0x56},
+	{SCORPION_UTLB_INV_ALL,			0x84000000, 2, 0x57},
+	{SCORPION_S2_HOLD_RDQ_UNAVAIL,		0x80000800, 2, 0x55},
+	{SCORPION_S2_HOLD,			0x88000000, 2, 0x57},
+	{SCORPION_S2_HOLD_DEV_OP,		0x80000900, 2, 0x55},
+	{SCORPION_S2_HOLD_ORDER,		0x80090000, 2, 0x56},
+	{SCORPION_S2_HOLD_BARRIER,		0x89000000, 2, 0x57},
+
+	{SCORPION_VIU_DUAL_CYCLE,		0x80000001, 4, 0x5c},
+	{SCORPION_VIU_SINGLE_CYCLE,		0x80000100, 4, 0x5d},
+	{SCORPION_VX_PIPE_WAR_STALL_CYCLES,	0x80000005, 4, 0x5c},
+	{SCORPION_VX_PIPE_WAW_STALL_CYCLES,	0x80000500, 4, 0x5d},
+	{SCORPION_VX_PIPE_RAW_STALL_CYCLES,	0x80050000, 4, 0x5e},
+	{SCORPION_VX_PIPE_LOAD_USE_STALL,	0x80000007, 4, 0x5c},
+	{SCORPION_VS_PIPE_WAR_STALL_CYCLES,	0x80000008, 4, 0x5c},
+	{SCORPION_VS_PIPE_WAW_STALL_CYCLES,	0x80000800, 4, 0x5d},
+	{SCORPION_VS_PIPE_RAW_STALL_CYCLES,	0x80080000, 4, 0x5e},
+	{SCORPION_EXCEPTIONS_INV_OPERATION,	0x8000000b, 4, 0x5c},
+	{SCORPION_EXCEPTIONS_DIV_BY_ZERO,	0x80000b00, 4, 0x5d},
+	{SCORPION_COND_INST_FAIL_VX_PIPE,	0x800b0000, 4, 0x5e},
+	{SCORPION_COND_INST_FAIL_VS_PIPE,	0x8b000000, 4, 0x5f},
+	{SCORPION_EXCEPTIONS_OVERFLOW,		0x8000000c, 4, 0x5c},
+	{SCORPION_EXCEPTIONS_UNDERFLOW,		0x80000c00, 4, 0x5d},
+	{SCORPION_EXCEPTIONS_DENORM,		0x8c000000, 4, 0x5f},
+
+#ifdef CONFIG_MSM_SMP
+	{SCORPIONMP_NUM_BARRIERS,		0x80000e00, 3, 0x59},
+	{SCORPIONMP_BARRIER_CYCLES,		0x800e0000, 3, 0x5a},
+#else
+	{SCORPION_BANK_AB_HIT,			0x80000001, 3, 0x58},
+	{SCORPION_BANK_AB_ACCESS,		0x80000100, 3, 0x59},
+	{SCORPION_BANK_CD_HIT,			0x80010000, 3, 0x5a},
+	{SCORPION_BANK_CD_ACCESS,		0x81000000, 3, 0x5b},
+	{SCORPION_BANK_AB_DSIDE_HIT,		0x80000002, 3, 0x58},
+	{SCORPION_BANK_AB_DSIDE_ACCESS,		0x80000200, 3, 0x59},
+	{SCORPION_BANK_CD_DSIDE_HIT,		0x80020000, 3, 0x5a},
+	{SCORPION_BANK_CD_DSIDE_ACCESS,		0x82000000, 3, 0x5b},
+	{SCORPION_BANK_AB_ISIDE_HIT,		0x80000003, 3, 0x58},
+	{SCORPION_BANK_AB_ISIDE_ACCESS,		0x80000300, 3, 0x59},
+	{SCORPION_BANK_CD_ISIDE_HIT,		0x80030000, 3, 0x5a},
+	{SCORPION_BANK_CD_ISIDE_ACCESS,		0x83000000, 3, 0x5b},
+	{SCORPION_ISIDE_RD_WAIT,		0x80000009, 3, 0x58},
+	{SCORPION_DSIDE_RD_WAIT,		0x80090000, 3, 0x5a},
+	{SCORPION_BANK_BYPASS_WRITE,		0x8000000a, 3, 0x58},
+	{SCORPION_BANK_AB_NON_CASTOUT,		0x8000000c, 3, 0x58},
+	{SCORPION_BANK_AB_L2_CASTOUT,		0x80000c00, 3, 0x59},
+	{SCORPION_BANK_CD_NON_CASTOUT,		0x800c0000, 3, 0x5a},
+	{SCORPION_BANK_CD_L2_CASTOUT,		0x8c000000, 3, 0x5b},
+#endif
+};
+
+static unsigned int get_scorpion_evtinfo(unsigned int scorpion_evt_type,
+					struct scorpion_evt *evtinfo)
+{
+	u32 idx;
+	u8 prefix;
+	u8 reg;
+	u8 code;
+	u8 group;
+
+	prefix = (scorpion_evt_type & 0xF0000) >> 16;
+	if (prefix == SCORPION_EVT_PREFIX) {
+		reg   = (scorpion_evt_type & 0x0F000) >> 12;
+		code  = (scorpion_evt_type & 0x00FF0) >> 4;
+		group =  scorpion_evt_type & 0x0000F;
+
+		if ((group > 3) || (reg > SCORPION_MAX_L1_REG))
+			return -EINVAL;
+
+		evtinfo->group_setval = 0x80000000 | (code << (group * 8));
+		evtinfo->groupcode = reg;
+		evtinfo->armv7_evt_type = scorpion_evt_type_base[reg] | group;
+
+		return evtinfo->armv7_evt_type;
+	}
+
+	if (scorpion_evt_type < SCORPION_EVT_START_IDX || scorpion_evt_type >=
+		(ARRAY_SIZE(scorpion_event) + SCORPION_EVT_START_IDX))
+		return -EINVAL;
+
+	idx = scorpion_evt_type - SCORPION_EVT_START_IDX;
+	if (scorpion_event[idx].scorpion_evt_type == scorpion_evt_type) {
+		evtinfo->group_setval = scorpion_event[idx].group_setval;
+		evtinfo->groupcode = scorpion_event[idx].groupcode;
+		evtinfo->armv7_evt_type = scorpion_event[idx].armv7_evt_type;
+		return scorpion_event[idx].armv7_evt_type;
+	}
+	return -EINVAL;
+}
+
+static u32 scorpion_read_lpm0(void)
+{
+	u32 val;
+
+	asm volatile("mrc p15, 0, %0, c15, c0, 0" : "=r" (val));
+	return val;
+}
+
+static void scorpion_write_lpm0(u32 val)
+{
+	asm volatile("mcr p15, 0, %0, c15, c0, 0" : : "r" (val));
+}
+
+static u32 scorpion_read_lpm1(void)
+{
+	u32 val;
+
+	asm volatile("mrc p15, 1, %0, c15, c0, 0" : "=r" (val));
+	return val;
+}
+
+static void scorpion_write_lpm1(u32 val)
+{
+	asm volatile("mcr p15, 1, %0, c15, c0, 0" : : "r" (val));
+}
+
+static u32 scorpion_read_lpm2(void)
+{
+	u32 val;
+
+	asm volatile("mrc p15, 2, %0, c15, c0, 0" : "=r" (val));
+	return val;
+}
+
+static void scorpion_write_lpm2(u32 val)
+{
+	asm volatile("mcr p15, 2, %0, c15, c0, 0" : : "r" (val));
+}
+
+static u32 scorpion_read_l2lpm(void)
+{
+	u32 val;
+
+	asm volatile("mrc p15, 3, %0, c15, c2, 0" : "=r" (val));
+	return val;
+}
+
+static void scorpion_write_l2lpm(u32 val)
+{
+	asm volatile("mcr p15, 3, %0, c15, c2, 0" : : "r" (val));
+}
+
+static u32 scorpion_read_vlpm(void)
+{
+	u32 val;
+
+	asm volatile("mrc p10, 7, %0, c11, c0, 0" : "=r" (val));
+	return val;
+}
+
+static void scorpion_write_vlpm(u32 val)
+{
+	asm volatile("mcr p10, 7, %0, c11, c0, 0" : : "r" (val));
+}
+
+/*
+ * The Scorpion processor supports performance monitoring for Venum unit.
+ * In order to access the performance monitor registers corresponding to
+ * VFP, CPACR and FPEXC registers need to be set up beforehand.
+ * Also, they need to be recovered once the access is done.
+ * This is the reason for having pre and post functions
+ */
+
+static DEFINE_PER_CPU(u32, venum_orig_val);
+static DEFINE_PER_CPU(u32, fp_orig_val);
+
+static void scorpion_pre_vlpm(void)
+{
+	u32 venum_new_val;
+	u32 fp_new_val;
+	u32 v_orig_val;
+	u32 f_orig_val;
+
+	/* CPACR Enable CP10 access */
+	v_orig_val = get_copro_access();
+	venum_new_val = v_orig_val | CPACC_SVC(10);
+	set_copro_access(venum_new_val);
+	/* Store orig venum val */
+	__get_cpu_var(venum_orig_val) = v_orig_val;
+
+	/* Enable FPEXC */
+	f_orig_val = fmrx(FPEXC);
+	fp_new_val = f_orig_val | FPEXC_EN;
+	fmxr(FPEXC, fp_new_val);
+	/* Store orig fp val */
+	__get_cpu_var(fp_orig_val) = f_orig_val;
+}
+
+static void scorpion_post_vlpm(void)
+{
+	/* Restore FPEXC */
+	fmxr(FPEXC, __get_cpu_var(fp_orig_val));
+	isb();
+	/* Restore CPACR */
+	set_copro_access(__get_cpu_var(venum_orig_val));
+}
+
+struct scorpion_access_funcs {
+	u32 (*read) (void);
+	void (*write) (u32);
+	void (*pre) (void);
+	void (*post) (void);
+};
+
+/*
+ * The scorpion_functions array is used to set up the event register codes
+ * based on the group to which an event belongs to.
+ * Having the following array modularizes the code for doing that.
+ */
+struct scorpion_access_funcs scorpion_functions[] = {
+	{scorpion_read_lpm0, scorpion_write_lpm0, NULL, NULL},
+	{scorpion_read_lpm1, scorpion_write_lpm1, NULL, NULL},
+	{scorpion_read_lpm2, scorpion_write_lpm2, NULL, NULL},
+	{scorpion_read_l2lpm, scorpion_write_l2lpm, NULL, NULL},
+	{scorpion_read_vlpm, scorpion_write_vlpm, scorpion_pre_vlpm,
+		scorpion_post_vlpm},
+};
+
+static inline u32 scorpion_get_columnmask(u32 evt_code)
+{
+	const u32 columnmasks[] = {0xffffff00, 0xffff00ff, 0xff00ffff,
+					0x80ffffff};
+
+	return columnmasks[evt_code & 0x3];
+}
+
+static void scorpion_evt_setup(u32 gr, u32 setval, u32 evt_code)
+{
+	u32 val;
+
+	if (scorpion_functions[gr].pre)
+		scorpion_functions[gr].pre();
+	val = scorpion_get_columnmask(evt_code) & scorpion_functions[gr].read();
+	val = val | setval;
+	scorpion_functions[gr].write(val);
+	if (scorpion_functions[gr].post)
+		scorpion_functions[gr].post();
+}
+
+static void scorpion_clear_pmuregs(void)
+{
+	unsigned long flags;
+
+	scorpion_write_lpm0(0);
+	scorpion_write_lpm1(0);
+	scorpion_write_lpm2(0);
+	scorpion_write_l2lpm(0);
+	raw_spin_lock_irqsave(&pmu_lock, flags);
+	scorpion_pre_vlpm();
+	scorpion_write_vlpm(0);
+	scorpion_post_vlpm();
+	raw_spin_unlock_irqrestore(&pmu_lock, flags);
+}
+
+static void scorpion_clearpmu(u32 grp, u32 val, u32 evt_code)
+{
+	u32 orig_pmuval, new_pmuval;
+
+	if (scorpion_functions[grp].pre)
+		scorpion_functions[grp].pre();
+	orig_pmuval = scorpion_functions[grp].read();
+	val = val & ~scorpion_get_columnmask(evt_code);
+	new_pmuval = orig_pmuval & ~val;
+	scorpion_functions[grp].write(new_pmuval);
+	if (scorpion_functions[grp].post)
+		scorpion_functions[grp].post();
+}
+
+static void scorpion_pmu_disable_event(struct hw_perf_event *hwc, int idx)
+{
+	unsigned long flags;
+	u32 val = 0;
+	u32 gr;
+	unsigned long event;
+	struct scorpion_evt evtinfo;
+
+	/* Disable counter and interrupt */
+	raw_spin_lock_irqsave(&pmu_lock, flags);
+
+	/* Disable counter */
+	armv7_pmnc_disable_counter(idx);
+
+	/*
+	 * Clear lpm code (if destined for PMNx counters)
+	 * We don't need to set the event if it's a cycle count
+	 */
+	if (idx != ARMV7_CYCLE_COUNTER) {
+		val = hwc->config_base;
+		val &= SCORPION_EVTYPE_EVENT;
+
+		if (val > 0x40) {
+			event = get_scorpion_evtinfo(val, &evtinfo);
+			if (event == -EINVAL)
+				goto scorpion_dis_out;
+			val = evtinfo.group_setval;
+			gr = evtinfo.groupcode;
+			scorpion_clearpmu(gr, val, evtinfo.armv7_evt_type);
+		}
+	}
+	/* Disable interrupt for this counter */
+	armv7_pmnc_disable_intens(idx);
+
+scorpion_dis_out:
+	raw_spin_unlock_irqrestore(&pmu_lock, flags);
+}
+
+static void scorpion_pmu_enable_event(struct hw_perf_event *hwc, int idx)
+{
+	unsigned long flags;
+	u32 val = 0;
+	u32 gr;
+	unsigned long event;
+	struct scorpion_evt evtinfo;
+	unsigned long long prev_count = local64_read(&hwc->prev_count);
+
+	/*
+	 * Enable counter and interrupt, and set the counter to count
+	 * the event that we're interested in.
+	 */
+	raw_spin_lock_irqsave(&pmu_lock, flags);
+
+	/* Disable counter */
+	armv7_pmnc_disable_counter(idx);
+
+	/*
+	 * Set event (if destined for PMNx counters)
+	 * We don't need to set the event if it's a cycle count
+	 */
+	if (idx != ARMV7_CYCLE_COUNTER) {
+		val = hwc->config_base;
+		val &= SCORPION_EVTYPE_EVENT;
+
+		if (val < 0x40) {
+			armv7_pmnc_write_evtsel(idx, hwc->config_base);
+		} else {
+			event = get_scorpion_evtinfo(val, &evtinfo);
+
+			if (event == -EINVAL)
+				goto scorpion_out;
+			/*
+			 * Set event (if destined for PMNx counters)
+			 * We don't need to set the event if it's a cycle count
+			 */
+			armv7_pmnc_write_evtsel(idx, event);
+			val = 0x0;
+			asm volatile("mcr p15, 0, %0, c9, c15, 0" : :
+				"r" (val));
+			val = evtinfo.group_setval;
+			gr = evtinfo.groupcode;
+			scorpion_evt_setup(gr, val, evtinfo.armv7_evt_type);
+		}
+	}
+
+	/* Enable interrupt for this counter */
+	armv7_pmnc_enable_intens(idx);
+
+	/* Restore prev val */
+	armv7pmu_write_counter(idx, prev_count & COUNT_MASK);
+
+	/* Enable counter */
+	armv7_pmnc_enable_counter(idx);
+
+scorpion_out:
+	raw_spin_unlock_irqrestore(&pmu_lock, flags);
+}
+
+static void enable_irq_callback(void *info)
+{
+	int irq = *(unsigned int *)info;
+
+	enable_percpu_irq(irq, IRQ_TYPE_EDGE_RISING);
+}
+
+static void disable_irq_callback(void *info)
+{
+	int irq = *(unsigned int *)info;
+
+	disable_percpu_irq(irq);
+}
+
+static int
+msm_request_irq(int irq, irq_handler_t *handle_irq)
+{
+	int err = 0;
+	int cpu;
+
+	err = request_percpu_irq(irq, *handle_irq, "armpmu",
+			&cpu_hw_events);
+
+	if (!err) {
+		for_each_cpu(cpu, cpu_online_mask) {
+			smp_call_function_single(cpu,
+					enable_irq_callback, &irq, 1);
+		}
+	}
+
+	return err;
+}
+
+static void
+msm_free_irq(int irq)
+{
+	int cpu;
+
+	if (irq >= 0) {
+		for_each_cpu(cpu, cpu_online_mask) {
+			smp_call_function_single(cpu,
+					disable_irq_callback, &irq, 1);
+		}
+		free_percpu_irq(irq, &cpu_hw_events);
+	}
+}
+
+static void scorpion_pmu_reset(void *info)
+{
+	u32 idx, nb_cnt = armpmu->num_events;
+
+	/* Stop all counters and their interrupts */
+	for (idx = 1; idx < nb_cnt; ++idx) {
+		armv7_pmnc_disable_counter(idx);
+		armv7_pmnc_disable_intens(idx);
+	}
+
+	/* Clear all pmresrs */
+	scorpion_clear_pmuregs();
+
+	/* Reset irq stat reg */
+	armv7_pmnc_getreset_flags();
+
+	/* Reset all ctrs to 0 */
+	armv7_pmnc_write(ARMV7_PMNC_P | ARMV7_PMNC_C);
+}
+
+static struct arm_pmu scorpion_pmu = {
+	.handle_irq		= armv7pmu_handle_irq,
+	.request_pmu_irq	= msm_request_irq,
+	.free_pmu_irq		= msm_free_irq,
+	.enable			= scorpion_pmu_enable_event,
+	.disable		= scorpion_pmu_disable_event,
+	.read_counter		= armv7pmu_read_counter,
+	.write_counter		= armv7pmu_write_counter,
+	.raw_event_mask		= 0xFFFFF,
+	.get_event_idx		= armv7pmu_get_event_idx,
+	.start			= armv7pmu_start,
+	.stop			= armv7pmu_stop,
+	.reset			= scorpion_pmu_reset,
+	.max_period		= (1LLU << 32) - 1,
+};
+
+static const struct arm_pmu *__init armv7_scorpion_pmu_init(void)
+{
+	scorpion_pmu.id		= ARM_PERF_PMU_ID_SCORPION;
+	scorpion_pmu.name	= "ARMv7 Scorpion";
+	scorpion_pmu.cache_map	= &armv7_scorpion_perf_cache_map;
+	scorpion_pmu.event_map	= &armv7_scorpion_perf_map;
+	scorpion_pmu.num_events	= armv7_read_num_pmnc_events();
+	scorpion_clear_pmuregs();
+	return &scorpion_pmu;
+}
+
+static const struct arm_pmu *__init armv7_scorpionmp_pmu_init(void)
+{
+	scorpion_pmu.id		= ARM_PERF_PMU_ID_SCORPIONMP;
+	scorpion_pmu.name	= "ARMv7 Scorpion-MP";
+	scorpion_pmu.cache_map	= &armv7_scorpion_perf_cache_map;
+	scorpion_pmu.event_map	= &armv7_scorpion_perf_map;
+	scorpion_pmu.num_events	= armv7_read_num_pmnc_events();
+	scorpion_clear_pmuregs();
+	return &scorpion_pmu;
+}
+#else
+static const struct arm_pmu *__init armv7_scorpion_pmu_init(void)
+{
+	return NULL;
+}
+static const struct arm_pmu *__init armv7_scorpionmp_pmu_init(void)
+{
+	return NULL;
+}
+#endif	/* CONFIG_CPU_V7 */
diff --git a/arch/arm/kernel/perf_event_msm_krait.c b/arch/arm/kernel/perf_event_msm_krait.c
new file mode 100644
index 0000000..8dbd047
--- /dev/null
+++ b/arch/arm/kernel/perf_event_msm_krait.c
@@ -0,0 +1,640 @@
+/*
+ * 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
+ * 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 <asm/cp15.h>
+#include <asm/vfp.h>
+#include "../vfp/vfpinstr.h"
+
+#ifdef CONFIG_CPU_V7
+#define KRAIT_EVT_PREFIX 1
+#define KRAIT_VENUMEVT_PREFIX 2
+/*
+   event encoding:                prccg
+   p  = prefix (1 for Krait L1) (2 for Krait VeNum events)
+   r  = register
+   cc = code
+   g  = group
+*/
+
+#define KRAIT_L1_ICACHE_ACCESS 0x10011
+#define KRAIT_L1_ICACHE_MISS 0x10010
+
+#define KRAIT_P1_L1_ITLB_ACCESS 0x121b2
+#define KRAIT_P1_L1_DTLB_ACCESS 0x121c0
+
+#define KRAIT_P2_L1_ITLB_ACCESS 0x12222
+#define KRAIT_P2_L1_DTLB_ACCESS 0x12210
+
+#define KRAIT_EVENT_MASK 0xfffff
+#define KRAIT_MODE_EXCL_MASK 0xc0000000
+
+#define COUNT_MASK	0xffffffff
+
+u32 evt_type_base[][4] = {
+	{0x4c, 0x50, 0x54},		/* Pass 1 */
+	{0xcc, 0xd0, 0xd4, 0xd8},	/* Pass 2 */
+};
+
+#define KRAIT_MIDR_PASS1 0x510F04D0
+#define KRAIT_MIDR_MASK 0xfffffff0
+
+/*
+ * This offset is used to calculate the index
+ * into evt_type_base[][] and krait_functions[]
+ */
+#define VENUM_BASE_OFFSET 3
+
+/* Krait Pass 1 has 3 groups, Pass 2 has 4 */
+static u32 krait_ver, evt_index;
+static u32 krait_max_l1_reg;
+
+static const unsigned armv7_krait_perf_map[PERF_COUNT_HW_MAX] = {
+	[PERF_COUNT_HW_CPU_CYCLES]	    = ARMV7_PERFCTR_CPU_CYCLES,
+	[PERF_COUNT_HW_INSTRUCTIONS]	    = ARMV7_PERFCTR_INSTR_EXECUTED,
+	[PERF_COUNT_HW_CACHE_REFERENCES]    = HW_OP_UNSUPPORTED,
+	[PERF_COUNT_HW_CACHE_MISSES]	    = HW_OP_UNSUPPORTED,
+	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_PERFCTR_PC_WRITE,
+	[PERF_COUNT_HW_BRANCH_MISSES]	    = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
+	[PERF_COUNT_HW_BUS_CYCLES]	    = ARMV7_PERFCTR_CLOCK_CYCLES,
+};
+
+static unsigned armv7_krait_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
+					  [PERF_COUNT_HW_CACHE_OP_MAX]
+					  [PERF_COUNT_HW_CACHE_RESULT_MAX] = {
+	[C(L1D)] = {
+		/*
+		 * The performance counters don't differentiate between read
+		 * and write accesses/misses so this isn't strictly correct,
+		 * but it's the best we can do. Writes and reads get
+		 * combined.
+		 */
+		[C(OP_READ)] = {
+			[C(RESULT_ACCESS)]	= ARMV7_PERFCTR_L1_DCACHE_ACCESS,
+			[C(RESULT_MISS)]	= ARMV7_PERFCTR_L1_DCACHE_REFILL,
+		},
+		[C(OP_WRITE)] = {
+			[C(RESULT_ACCESS)]	= ARMV7_PERFCTR_L1_DCACHE_ACCESS,
+			[C(RESULT_MISS)]	= ARMV7_PERFCTR_L1_DCACHE_REFILL,
+		},
+		[C(OP_PREFETCH)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+	},
+	[C(L1I)] = {
+		[C(OP_READ)] = {
+			[C(RESULT_ACCESS)]	= KRAIT_L1_ICACHE_ACCESS,
+			[C(RESULT_MISS)]	= KRAIT_L1_ICACHE_MISS,
+		},
+		[C(OP_WRITE)] = {
+			[C(RESULT_ACCESS)]	= KRAIT_L1_ICACHE_ACCESS,
+			[C(RESULT_MISS)]	= KRAIT_L1_ICACHE_MISS,
+		},
+		[C(OP_PREFETCH)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+	},
+	[C(LL)] = {
+		[C(OP_READ)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+		[C(OP_WRITE)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+		[C(OP_PREFETCH)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+	},
+	[C(DTLB)] = {
+		[C(OP_READ)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+		[C(OP_WRITE)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+		[C(OP_PREFETCH)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+	},
+	[C(ITLB)] = {
+		[C(OP_READ)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+		[C(OP_WRITE)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+		[C(OP_PREFETCH)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+	},
+	[C(BPU)] = {
+		[C(OP_READ)] = {
+			[C(RESULT_ACCESS)]
+					= ARMV7_PERFCTR_PC_BRANCH_PRED,
+			[C(RESULT_MISS)]
+					= ARMV7_PERFCTR_PC_BRANCH_PRED,
+		},
+		[C(OP_WRITE)] = {
+			[C(RESULT_ACCESS)]
+					= ARMV7_PERFCTR_PC_BRANCH_PRED,
+			[C(RESULT_MISS)]
+					= ARMV7_PERFCTR_PC_BRANCH_PRED,
+		},
+		[C(OP_PREFETCH)] = {
+			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
+			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
+		},
+	},
+};
+
+static int krait_8960_map_event(struct perf_event *event)
+{
+	return map_cpu_event(event, &armv7_krait_perf_map,
+			&armv7_krait_perf_cache_map, 0xfffff);
+}
+
+struct krait_evt {
+	/*
+	 * The group_setval field corresponds to the value that the group
+	 * register needs to be set to. This value is calculated from the row
+	 * and column that the event belongs to in the event table
+	 */
+	u32 group_setval;
+
+	/*
+	 * The groupcode corresponds to the group that the event belongs to.
+	 * Krait has 3 groups of events PMRESR0, 1, 2
+	 * going from 0 to 2 in terms of the codes used
+	 */
+	u8 groupcode;
+
+	/*
+	 * The armv7_evt_type field corresponds to the armv7 defined event
+	 * code that the Krait events map to
+	 */
+	u32 armv7_evt_type;
+};
+
+static unsigned int get_krait_evtinfo(unsigned int krait_evt_type,
+					struct krait_evt *evtinfo)
+{
+	u8 prefix;
+	u8 reg;
+	u8 code;
+	u8 group;
+
+	prefix = (krait_evt_type & 0xF0000) >> 16;
+	reg = (krait_evt_type & 0x0F000) >> 12;
+	code = (krait_evt_type & 0x00FF0) >> 4;
+	group = krait_evt_type & 0x0000F;
+
+	if ((group > 3) || (reg > krait_max_l1_reg))
+		return -EINVAL;
+
+	if (prefix != KRAIT_EVT_PREFIX && prefix != KRAIT_VENUMEVT_PREFIX)
+		return -EINVAL;
+
+	if (prefix == KRAIT_VENUMEVT_PREFIX) {
+		if ((code & 0xe0) || krait_ver != 2)
+			return -EINVAL;
+		else
+			reg += VENUM_BASE_OFFSET;
+	}
+
+	evtinfo->group_setval = 0x80000000 | (code << (group * 8));
+	evtinfo->groupcode = reg;
+	evtinfo->armv7_evt_type = evt_type_base[evt_index][reg] | group;
+
+	return evtinfo->armv7_evt_type;
+}
+
+static u32 krait_read_pmresr0(void)
+{
+	u32 val;
+
+	asm volatile("mrc p15, 1, %0, c9, c15, 0" : "=r" (val));
+	return val;
+}
+
+static void krait_write_pmresr0(u32 val)
+{
+	asm volatile("mcr p15, 1, %0, c9, c15, 0" : : "r" (val));
+}
+
+static u32 krait_read_pmresr1(void)
+{
+	u32 val;
+
+	asm volatile("mrc p15, 1, %0, c9, c15, 1" : "=r" (val));
+	return val;
+}
+
+static void krait_write_pmresr1(u32 val)
+{
+	asm volatile("mcr p15, 1, %0, c9, c15, 1" : : "r" (val));
+}
+
+static u32 krait_read_pmresr2(void)
+{
+	u32 val;
+
+	asm volatile("mrc p15, 1, %0, c9, c15, 2" : "=r" (val));
+	return val;
+}
+
+static void krait_write_pmresr2(u32 val)
+{
+	asm volatile("mcr p15, 1, %0, c9, c15, 2" : : "r" (val));
+}
+
+static u32 krait_read_vmresr0(void)
+{
+	u32 val;
+
+	asm volatile ("mrc p10, 7, %0, c11, c0, 0" : "=r" (val));
+	return val;
+}
+
+static void krait_write_vmresr0(u32 val)
+{
+	asm volatile ("mcr p10, 7, %0, c11, c0, 0" : : "r" (val));
+}
+
+static DEFINE_PER_CPU(u32, venum_orig_val);
+static DEFINE_PER_CPU(u32, fp_orig_val);
+
+static void krait_pre_vmresr0(void)
+{
+	u32 venum_new_val;
+	u32 fp_new_val;
+	u32 v_orig_val;
+	u32 f_orig_val;
+
+	/* CPACR Enable CP10 and CP11 access */
+	v_orig_val = get_copro_access();
+	venum_new_val = v_orig_val | CPACC_SVC(10) | CPACC_SVC(11);
+	set_copro_access(venum_new_val);
+	/* Store orig venum val */
+	__get_cpu_var(venum_orig_val) = v_orig_val;
+
+	/* Enable FPEXC */
+	f_orig_val = fmrx(FPEXC);
+	fp_new_val = f_orig_val | FPEXC_EN;
+	fmxr(FPEXC, fp_new_val);
+	/* Store orig fp val */
+	__get_cpu_var(fp_orig_val) = f_orig_val;
+
+}
+
+static void krait_post_vmresr0(void)
+{
+	/* Restore FPEXC */
+	fmxr(FPEXC, __get_cpu_var(fp_orig_val));
+	isb();
+	/* Restore CPACR */
+	set_copro_access(__get_cpu_var(venum_orig_val));
+}
+
+struct krait_access_funcs {
+	u32 (*read) (void);
+	void (*write) (u32);
+	void (*pre) (void);
+	void (*post) (void);
+};
+
+/*
+ * The krait_functions array is used to set up the event register codes
+ * based on the group to which an event belongs.
+ * Having the following array modularizes the code for doing that.
+ */
+struct krait_access_funcs krait_functions[] = {
+	{krait_read_pmresr0, krait_write_pmresr0, NULL, NULL},
+	{krait_read_pmresr1, krait_write_pmresr1, NULL, NULL},
+	{krait_read_pmresr2, krait_write_pmresr2, NULL, NULL},
+	{krait_read_vmresr0, krait_write_vmresr0, krait_pre_vmresr0,
+	 krait_post_vmresr0},
+};
+
+static inline u32 krait_get_columnmask(u32 evt_code)
+{
+	const u32 columnmasks[] = {0xffffff00, 0xffff00ff, 0xff00ffff,
+					0x80ffffff};
+
+	return columnmasks[evt_code & 0x3];
+}
+
+static void krait_evt_setup(u32 gr, u32 setval, u32 evt_code)
+{
+	u32 val;
+
+	if (krait_functions[gr].pre)
+		krait_functions[gr].pre();
+
+	val = krait_get_columnmask(evt_code) & krait_functions[gr].read();
+	val = val | setval;
+	krait_functions[gr].write(val);
+
+	if (krait_functions[gr].post)
+		krait_functions[gr].post();
+}
+
+static void krait_clear_pmuregs(void)
+{
+	krait_write_pmresr0(0);
+	krait_write_pmresr1(0);
+	krait_write_pmresr2(0);
+
+	krait_pre_vmresr0();
+	krait_write_vmresr0(0);
+	krait_post_vmresr0();
+}
+
+static void krait_clearpmu(u32 grp, u32 val, u32 evt_code)
+{
+	u32 new_pmuval;
+
+	if (krait_functions[grp].pre)
+		krait_functions[grp].pre();
+
+	new_pmuval = krait_functions[grp].read() &
+		krait_get_columnmask(evt_code);
+	krait_functions[grp].write(new_pmuval);
+
+	if (krait_functions[grp].post)
+		krait_functions[grp].post();
+}
+
+static void krait_pmu_disable_event(struct hw_perf_event *hwc, int idx)
+{
+	unsigned long flags;
+	u32 val = 0;
+	u32 gr;
+	unsigned long event;
+	struct krait_evt evtinfo;
+	struct pmu_hw_events *events = cpu_pmu->get_hw_events();
+
+
+	/* Disable counter and interrupt */
+	raw_spin_lock_irqsave(&events->pmu_lock, flags);
+
+	/* Disable counter */
+	armv7_pmnc_disable_counter(idx);
+
+	/*
+	 * Clear pmresr code (if destined for PMNx counters)
+	 * We don't need to set the event if it's a cycle count
+	 */
+	if (idx != ARMV7_IDX_CYCLE_COUNTER) {
+		val = hwc->config_base;
+		val &= KRAIT_EVENT_MASK;
+
+		if (val > 0x40) {
+			event = get_krait_evtinfo(val, &evtinfo);
+			if (event == -EINVAL)
+				goto krait_dis_out;
+			val = evtinfo.group_setval;
+			gr = evtinfo.groupcode;
+			krait_clearpmu(gr, val, evtinfo.armv7_evt_type);
+		}
+	}
+	/* Disable interrupt for this counter */
+	armv7_pmnc_disable_intens(idx);
+
+krait_dis_out:
+	raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
+}
+
+static void krait_pmu_enable_event(struct hw_perf_event *hwc, int idx, int cpu)
+{
+	unsigned long flags;
+	u32 val = 0;
+	u32 gr;
+	unsigned long event;
+	struct krait_evt evtinfo;
+	unsigned long long prev_count = local64_read(&hwc->prev_count);
+	struct pmu_hw_events *events = cpu_pmu->get_hw_events();
+
+	/*
+	 * Enable counter and interrupt, and set the counter to count
+	 * the event that we're interested in.
+	 */
+	raw_spin_lock_irqsave(&events->pmu_lock, flags);
+
+	/* Disable counter */
+	armv7_pmnc_disable_counter(idx);
+
+	/*
+	 * Set event (if destined for PMNx counters)
+	 * We don't need to set the event if it's a cycle count
+	 */
+	if (idx != ARMV7_IDX_CYCLE_COUNTER) {
+		val = hwc->config_base;
+		val &= KRAIT_EVENT_MASK;
+
+		if (val < 0x40) {
+			armv7_pmnc_write_evtsel(idx, hwc->config_base);
+		} else {
+			event = get_krait_evtinfo(val, &evtinfo);
+
+			if (event == -EINVAL)
+				goto krait_out;
+
+			/* Restore Mode-exclusion bits */
+			event |= (hwc->config_base & KRAIT_MODE_EXCL_MASK);
+
+			/*
+			 * Set event (if destined for PMNx counters)
+			 * We don't need to set the event if it's a cycle count
+			 */
+			armv7_pmnc_write_evtsel(idx, event);
+			val = 0x0;
+			asm volatile("mcr p15, 0, %0, c9, c15, 0" : :
+				"r" (val));
+			val = evtinfo.group_setval;
+			gr = evtinfo.groupcode;
+			krait_evt_setup(gr, val, evtinfo.armv7_evt_type);
+		}
+	}
+
+	/* Enable interrupt for this counter */
+	armv7_pmnc_enable_intens(idx);
+
+	/* Restore prev val */
+	armv7pmu_write_counter(idx, prev_count & COUNT_MASK);
+
+	/* Enable counter */
+	armv7_pmnc_enable_counter(idx);
+
+krait_out:
+	raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
+}
+
+static void krait_pmu_reset(void *info)
+{
+	u32 idx, nb_cnt = cpu_pmu->num_events;
+
+	/* Stop all counters and their interrupts */
+	for (idx = 1; idx < nb_cnt; ++idx) {
+		armv7_pmnc_disable_counter(idx);
+		armv7_pmnc_disable_intens(idx);
+	}
+
+	/* Clear all pmresrs */
+	krait_clear_pmuregs();
+
+	/* Reset irq stat reg */
+	armv7_pmnc_getreset_flags();
+
+	/* Reset all ctrs to 0 */
+	armv7_pmnc_write(ARMV7_PMNC_P | ARMV7_PMNC_C);
+}
+
+static void enable_irq_callback(void *info)
+{
+        int irq = *(unsigned int *)info;
+
+        enable_percpu_irq(irq, IRQ_TYPE_EDGE_RISING);
+}
+
+static void disable_irq_callback(void *info)
+{
+        int irq = *(unsigned int *)info;
+
+        disable_percpu_irq(irq);
+}
+
+static int
+msm_request_irq(int irq, irq_handler_t *handle_irq)
+{
+        int err = 0;
+        int cpu;
+
+        err = request_percpu_irq(irq, *handle_irq, "krait-l1-armpmu",
+                        &cpu_hw_events);
+
+        if (!err) {
+                for_each_cpu(cpu, cpu_online_mask) {
+                        smp_call_function_single(cpu,
+                                        enable_irq_callback, &irq, 1);
+                }
+        }
+
+        return err;
+}
+
+static void
+msm_free_irq(int irq)
+{
+        int cpu;
+
+        if (irq >= 0) {
+                for_each_cpu(cpu, cpu_online_mask) {
+                        smp_call_function_single(cpu,
+                                        disable_irq_callback, &irq, 1);
+                }
+                free_percpu_irq(irq, &cpu_hw_events);
+        }
+}
+
+static struct arm_pmu krait_pmu = {
+	.handle_irq		= armv7pmu_handle_irq,
+	.request_pmu_irq	= msm_request_irq,
+	.free_pmu_irq		= msm_free_irq,
+	.enable			= krait_pmu_enable_event,
+	.disable		= krait_pmu_disable_event,
+	.read_counter		= armv7pmu_read_counter,
+	.write_counter		= armv7pmu_write_counter,
+	.get_event_idx		= armv7pmu_get_event_idx,
+	.start			= armv7pmu_start,
+	.stop			= armv7pmu_stop,
+	.reset			= krait_pmu_reset,
+	.max_period		= (1LLU << 32) - 1,
+};
+
+int get_krait_ver(void)
+{
+	int ver = 0;
+	int midr = read_cpuid_id();
+
+	if ((midr & KRAIT_MIDR_MASK) != KRAIT_MIDR_PASS1)
+		ver = 2;
+
+	pr_debug("krait_ver: %d, midr: %x\n", ver, midr);
+
+	return ver;
+}
+
+static struct arm_pmu *__init armv7_krait_pmu_init(void)
+{
+	krait_pmu.id		= ARM_PERF_PMU_ID_KRAIT;
+	krait_pmu.name	        = "ARMv7 Krait";
+	krait_pmu.map_event	= krait_8960_map_event;
+	krait_pmu.num_events	= armv7_read_num_pmnc_events();
+	krait_clear_pmuregs();
+
+	krait_ver = get_krait_ver();
+
+	if (krait_ver > 0) {
+		evt_index = 1;
+		krait_max_l1_reg = 3;
+
+		krait_pmu.set_event_filter = armv7pmu_set_event_filter,
+
+		armv7_krait_perf_cache_map[C(ITLB)]
+			[C(OP_READ)]
+			[C(RESULT_ACCESS)] = KRAIT_P2_L1_ITLB_ACCESS;
+		armv7_krait_perf_cache_map[C(ITLB)]
+			[C(OP_WRITE)]
+			[C(RESULT_ACCESS)] = KRAIT_P2_L1_ITLB_ACCESS;
+		armv7_krait_perf_cache_map[C(DTLB)]
+			[C(OP_READ)]
+			[C(RESULT_ACCESS)] = KRAIT_P2_L1_DTLB_ACCESS;
+		armv7_krait_perf_cache_map[C(DTLB)]
+			[C(OP_WRITE)]
+			[C(RESULT_ACCESS)] = KRAIT_P2_L1_DTLB_ACCESS;
+	} else {
+		evt_index = 0;
+		krait_max_l1_reg = 2;
+		armv7_krait_perf_cache_map[C(ITLB)]
+			[C(OP_READ)]
+			[C(RESULT_ACCESS)] = KRAIT_P1_L1_ITLB_ACCESS;
+		armv7_krait_perf_cache_map[C(ITLB)]
+			[C(OP_WRITE)]
+			[C(RESULT_ACCESS)] = KRAIT_P1_L1_ITLB_ACCESS;
+		armv7_krait_perf_cache_map[C(DTLB)]
+			[C(OP_READ)]
+			[C(RESULT_ACCESS)] = KRAIT_P1_L1_DTLB_ACCESS;
+		armv7_krait_perf_cache_map[C(DTLB)]
+			[C(OP_WRITE)]
+			[C(RESULT_ACCESS)] = KRAIT_P1_L1_DTLB_ACCESS;
+	}
+
+	return &krait_pmu;
+}
+
+#else
+static const struct arm_pmu *__init armv7_krait_pmu_init(void)
+{
+	return NULL;
+}
+#endif	/* CONFIG_CPU_V7 */
diff --git a/arch/arm/kernel/perf_event_msm_krait_l2.c b/arch/arm/kernel/perf_event_msm_krait_l2.c
new file mode 100644
index 0000000..baa05ac
--- /dev/null
+++ b/arch/arm/kernel/perf_event_msm_krait_l2.c
@@ -0,0 +1,667 @@
+/*
+ * 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
+ * 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.
+ */
+#ifdef CONFIG_ARCH_MSM_KRAIT
+
+#include <linux/irq.h>
+
+#include <mach/msm-krait-l2-accessors.h>
+
+#define MAX_L2_PERIOD	((1ULL << 32) - 1)
+#define MAX_KRAIT_L2_CTRS 5
+
+#define L2PMCCNTR 0x409
+#define L2PMCCNTCR 0x408
+#define L2PMCCNTSR 0x40A
+#define L2CYCLE_CTR_BIT 31
+#define L2CYCLE_CTR_EVENT_IDX 4
+#define L2CYCLE_CTR_RAW_CODE 0xfe
+
+#define L2PMOVSR	0x406
+
+#define L2PMCR	0x400
+#define L2PMCR_RESET_ALL	0x6
+#define L2PMCR_GLOBAL_ENABLE	0x1
+#define L2PMCR_GLOBAL_DISABLE	0x0
+
+#define L2PMCNTENSET	0x403
+#define L2PMCNTENCLR	0x402
+
+#define L2PMINTENSET	0x405
+#define L2PMINTENCLR	0x404
+
+#define IA_L2PMXEVCNTCR_BASE	0x420
+#define IA_L2PMXEVTYPER_BASE	0x424
+#define IA_L2PMRESX_BASE	0x410
+#define IA_L2PMXEVFILTER_BASE	0x423
+#define IA_L2PMXEVCNTR_BASE	0x421
+
+/* event format is -e rsRCCG See get_event_desc() */
+
+#define EVENT_REG_MASK		0xf000
+#define EVENT_GROUPSEL_MASK	0x000f
+#define	EVENT_GROUPCODE_MASK	0x0ff0
+#define EVENT_REG_SHIFT		12
+#define EVENT_GROUPCODE_SHIFT	4
+
+#define	RESRX_VALUE_EN	0x80000000
+
+static struct platform_device *l2_pmu_device;
+
+struct hw_krait_l2_pmu {
+	struct perf_event *events[MAX_KRAIT_L2_CTRS];
+	unsigned long active_mask[BITS_TO_LONGS(MAX_KRAIT_L2_CTRS)];
+	raw_spinlock_t lock;
+};
+
+struct hw_krait_l2_pmu hw_krait_l2_pmu;
+
+struct event_desc {
+	int event_groupsel;
+	int event_reg;
+	int event_group_code;
+};
+
+void get_event_desc(u64 config, struct event_desc *evdesc)
+{
+	/* L2PMEVCNTRX */
+	evdesc->event_reg = (config & EVENT_REG_MASK) >> EVENT_REG_SHIFT;
+	/* Group code (row ) */
+	evdesc->event_group_code =
+	    (config & EVENT_GROUPCODE_MASK) >> EVENT_GROUPCODE_SHIFT;
+	/* Group sel (col) */
+	evdesc->event_groupsel = (config & EVENT_GROUPSEL_MASK);
+
+	pr_debug("%s: reg: %x, group_code: %x, groupsel: %x\n", __func__,
+		 evdesc->event_reg, evdesc->event_group_code,
+		 evdesc->event_groupsel);
+}
+
+static void set_evcntcr(int ctr)
+{
+	u32 evtcr_reg = (ctr * 16) + IA_L2PMXEVCNTCR_BASE;
+
+	set_l2_indirect_reg(evtcr_reg, 0x0);
+}
+
+static void set_evtyper(int event_groupsel, int event_reg, int ctr)
+{
+	u32 evtype_reg = (ctr * 16) + IA_L2PMXEVTYPER_BASE;
+	u32 evtype_val = event_groupsel + (4 * event_reg);
+
+	set_l2_indirect_reg(evtype_reg, evtype_val);
+}
+
+static void set_evres(int event_groupsel, int event_reg, int event_group_code)
+{
+	u32 group_reg = event_reg + IA_L2PMRESX_BASE;
+	u32 group_val =
+		RESRX_VALUE_EN | (event_group_code << (8 * event_groupsel));
+	u32 resr_val;
+	u32 group_byte = 0xff;
+	u32 group_mask = ~(group_byte << (8 * event_groupsel));
+
+	resr_val = get_l2_indirect_reg(group_reg);
+	resr_val &= group_mask;
+	resr_val |= group_val;
+
+	set_l2_indirect_reg(group_reg, resr_val);
+}
+
+static void set_evfilter_task_mode(int ctr)
+{
+	u32 filter_reg = (ctr * 16) + IA_L2PMXEVFILTER_BASE;
+	u32 filter_val = 0x000f0030 | 1 << smp_processor_id();
+
+	set_l2_indirect_reg(filter_reg, filter_val);
+}
+
+static void set_evfilter_sys_mode(int ctr)
+{
+	u32 filter_reg = (ctr * 16) + IA_L2PMXEVFILTER_BASE;
+	u32 filter_val = 0x000f003f;
+
+	set_l2_indirect_reg(filter_reg, filter_val);
+}
+
+static void enable_intenset(u32 idx)
+{
+	if (idx == L2CYCLE_CTR_EVENT_IDX)
+		set_l2_indirect_reg(L2PMINTENSET, 1 << L2CYCLE_CTR_BIT);
+	else
+		set_l2_indirect_reg(L2PMINTENSET, 1 << idx);
+}
+
+static void disable_intenclr(u32 idx)
+{
+	if (idx == L2CYCLE_CTR_EVENT_IDX)
+		set_l2_indirect_reg(L2PMINTENCLR, 1 << L2CYCLE_CTR_BIT);
+	else
+		set_l2_indirect_reg(L2PMINTENCLR, 1 << idx);
+}
+
+static void enable_counter(u32 idx)
+{
+	if (idx == L2CYCLE_CTR_EVENT_IDX)
+		set_l2_indirect_reg(L2PMCNTENSET, 1 << L2CYCLE_CTR_BIT);
+	else
+		set_l2_indirect_reg(L2PMCNTENSET, 1 << idx);
+}
+
+static void disable_counter(u32 idx)
+{
+	if (idx == L2CYCLE_CTR_EVENT_IDX)
+		set_l2_indirect_reg(L2PMCNTENCLR, 1 << L2CYCLE_CTR_BIT);
+	else
+		set_l2_indirect_reg(L2PMCNTENCLR, 1 << idx);
+}
+
+static u64 read_counter(u32 idx)
+{
+	u32 val;
+	u32 counter_reg = (idx * 16) + IA_L2PMXEVCNTR_BASE;
+
+	if (idx == L2CYCLE_CTR_EVENT_IDX)
+		val = get_l2_indirect_reg(L2PMCCNTR);
+	else
+		val = get_l2_indirect_reg(counter_reg);
+
+	return val;
+}
+
+static void write_counter(u32 idx, u32 val)
+{
+	u32 counter_reg = (idx * 16) + IA_L2PMXEVCNTR_BASE;
+
+	if (idx == L2CYCLE_CTR_EVENT_IDX)
+		set_l2_indirect_reg(L2PMCCNTR, val);
+	else
+		set_l2_indirect_reg(counter_reg, val);
+}
+
+static int
+pmu_event_set_period(struct perf_event *event,
+		     struct hw_perf_event *hwc, int idx)
+{
+	s64 left = local64_read(&hwc->period_left);
+	s64 period = hwc->sample_period;
+	int ret = 0;
+
+	if (unlikely(left <= -period)) {
+		left = period;
+		local64_set(&hwc->period_left, left);
+		hwc->last_period = period;
+		ret = 1;
+	}
+
+	if (unlikely(left <= 0)) {
+		left += period;
+		local64_set(&hwc->period_left, left);
+		hwc->last_period = period;
+		ret = 1;
+	}
+
+	if (left > (s64) MAX_L2_PERIOD)
+		left = MAX_L2_PERIOD;
+
+	local64_set(&hwc->prev_count, (u64)-left);
+
+	write_counter(idx, (u64) (-left) & 0xffffffff);
+
+	perf_event_update_userpage(event);
+
+	return ret;
+}
+
+static u64
+pmu_event_update(struct perf_event *event, struct hw_perf_event *hwc, int idx,
+		 int overflow)
+{
+	u64 prev_raw_count, new_raw_count;
+	u64 delta;
+
+again:
+	prev_raw_count = local64_read(&hwc->prev_count);
+	new_raw_count = read_counter(idx);
+
+	if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
+			    new_raw_count) != prev_raw_count)
+		goto again;
+
+	new_raw_count &= MAX_L2_PERIOD;
+	prev_raw_count &= MAX_L2_PERIOD;
+
+	if (overflow)
+		delta = MAX_L2_PERIOD - prev_raw_count + new_raw_count;
+	else
+		delta = new_raw_count - prev_raw_count;
+
+	local64_add(delta, &event->count);
+	local64_sub(delta, &hwc->period_left);
+
+	pr_debug("%s: new: %lld, prev: %lld, event: %ld count: %lld\n",
+		 __func__, new_raw_count, prev_raw_count,
+		 hwc->config_base, local64_read(&event->count));
+
+	return new_raw_count;
+}
+
+static void krait_l2_read(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+
+	pmu_event_update(event, hwc, hwc->idx, 0);
+}
+
+static void krait_l2_stop_counter(struct perf_event *event, int flags)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	int idx = hwc->idx;
+
+	if (!(hwc->state & PERF_HES_STOPPED)) {
+		disable_intenclr(idx);
+		disable_counter(idx);
+
+		pmu_event_update(event, hwc, idx, 0);
+		hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
+	}
+
+	pr_debug("%s: event: %ld ctr: %d stopped\n", __func__, hwc->config_base,
+		 idx);
+}
+
+static void krait_l2_start_counter(struct perf_event *event, int flags)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	int idx = hwc->idx;
+	struct event_desc evdesc;
+
+	if (flags & PERF_EF_RELOAD)
+		WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
+
+	hwc->state = 0;
+
+	pmu_event_set_period(event, hwc, idx);
+
+	if (hwc->config_base == L2CYCLE_CTR_RAW_CODE)
+		goto out;
+
+	set_evcntcr(idx);
+
+	memset(&evdesc, 0, sizeof(evdesc));
+
+	get_event_desc(hwc->config_base, &evdesc);
+
+	set_evtyper(evdesc.event_groupsel, evdesc.event_reg, idx);
+
+	set_evres(evdesc.event_groupsel, evdesc.event_reg,
+		  evdesc.event_group_code);
+
+	if (event->cpu < 0)
+		set_evfilter_task_mode(idx);
+	else
+		set_evfilter_sys_mode(idx);
+
+out:
+	enable_intenset(idx);
+	enable_counter(idx);
+
+	pr_debug
+	    ("%s: ctr: %d group: %ld group_code: %lld started from cpu:%d\n",
+	     __func__, idx, hwc->config_base, hwc->config, smp_processor_id());
+}
+
+static void krait_l2_del_event(struct perf_event *event, int flags)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	int idx = hwc->idx;
+	unsigned long iflags;
+
+	raw_spin_lock_irqsave(&hw_krait_l2_pmu.lock, iflags);
+
+	clear_bit(idx, (long unsigned int *)(&hw_krait_l2_pmu.active_mask));
+
+	krait_l2_stop_counter(event, PERF_EF_UPDATE);
+	hw_krait_l2_pmu.events[idx] = NULL;
+	hwc->idx = -1;
+
+	raw_spin_unlock_irqrestore(&hw_krait_l2_pmu.lock, iflags);
+
+	pr_debug("%s: event: %ld deleted\n", __func__, hwc->config_base);
+
+	perf_event_update_userpage(event);
+}
+
+static int krait_l2_add_event(struct perf_event *event, int flags)
+{
+	int ctr = 0;
+	struct hw_perf_event *hwc = &event->hw;
+	unsigned long iflags;
+	int err = 0;
+
+	perf_pmu_disable(event->pmu);
+
+	raw_spin_lock_irqsave(&hw_krait_l2_pmu.lock, iflags);
+
+	/* Cycle counter has a resrvd index */
+	if (hwc->config_base == L2CYCLE_CTR_RAW_CODE) {
+		if (hw_krait_l2_pmu.events[L2CYCLE_CTR_EVENT_IDX]) {
+			pr_err("%s: Stale cycle ctr event ptr !\n", __func__);
+			err = -EINVAL;
+			goto out;
+		}
+		hwc->idx = L2CYCLE_CTR_EVENT_IDX;
+		hw_krait_l2_pmu.events[L2CYCLE_CTR_EVENT_IDX] = event;
+		set_bit(L2CYCLE_CTR_EVENT_IDX,
+			(long unsigned int *)&hw_krait_l2_pmu.active_mask);
+		goto skip_ctr_loop;
+	}
+
+	for (ctr = 0; ctr < MAX_KRAIT_L2_CTRS - 1; ctr++) {
+		if (!hw_krait_l2_pmu.events[ctr]) {
+			hwc->idx = ctr;
+			hw_krait_l2_pmu.events[ctr] = event;
+			set_bit(ctr,
+				(long unsigned int *)
+				&hw_krait_l2_pmu.active_mask);
+			break;
+		}
+	}
+
+	if (hwc->idx < 0) {
+		err = -ENOSPC;
+		pr_err("%s: No space for event: %llx!!\n", __func__,
+		       event->attr.config);
+		goto out;
+	}
+
+skip_ctr_loop:
+
+	disable_counter(hwc->idx);
+
+	hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
+
+	if (flags & PERF_EF_START)
+		krait_l2_start_counter(event, PERF_EF_RELOAD);
+
+	perf_event_update_userpage(event);
+
+	pr_debug("%s: event: %ld, ctr: %d added from cpu:%d\n",
+		 __func__, hwc->config_base, hwc->idx, smp_processor_id());
+out:
+	raw_spin_unlock_irqrestore(&hw_krait_l2_pmu.lock, iflags);
+
+	/* Resume the PMU even if this event could not be added */
+	perf_pmu_enable(event->pmu);
+
+	return err;
+}
+
+static void krait_l2_pmu_enable(struct pmu *pmu)
+{
+	isb();
+	set_l2_indirect_reg(L2PMCR, L2PMCR_GLOBAL_ENABLE);
+}
+
+static void krait_l2_pmu_disable(struct pmu *pmu)
+{
+	set_l2_indirect_reg(L2PMCR, L2PMCR_GLOBAL_DISABLE);
+	isb();
+}
+
+u32 get_reset_pmovsr(void)
+{
+	int val;
+
+	val = get_l2_indirect_reg(L2PMOVSR);
+	/* reset it */
+	val &= 0xffffffff;
+	set_l2_indirect_reg(L2PMOVSR, val);
+
+	return val;
+}
+
+static irqreturn_t krait_l2_handle_irq(int irq_num, void *dev)
+{
+	unsigned long pmovsr;
+	struct perf_sample_data data;
+	struct pt_regs *regs;
+	struct perf_event *event;
+	struct hw_perf_event *hwc;
+	int bitp;
+	int idx = 0;
+
+	pmovsr = get_reset_pmovsr();
+
+	if (!(pmovsr & 0xffffffff))
+		return IRQ_NONE;
+
+	regs = get_irq_regs();
+
+	perf_sample_data_init(&data, 0);
+
+	raw_spin_lock(&hw_krait_l2_pmu.lock);
+
+	while (pmovsr) {
+		bitp = __ffs(pmovsr);
+
+		if (bitp == L2CYCLE_CTR_BIT)
+			idx = L2CYCLE_CTR_EVENT_IDX;
+		else
+			idx = bitp;
+
+		event = hw_krait_l2_pmu.events[idx];
+
+		if (!event)
+			goto next;
+
+		if (!test_bit(idx, hw_krait_l2_pmu.active_mask))
+			goto next;
+
+		hwc = &event->hw;
+		pmu_event_update(event, hwc, idx, 1);
+		data.period = event->hw.last_period;
+
+		if (!pmu_event_set_period(event, hwc, idx))
+			goto next;
+
+		if (perf_event_overflow(event, 0, &data, regs))
+			disable_counter(hwc->idx);
+next:
+		pmovsr &= (pmovsr - 1);
+	}
+
+	raw_spin_unlock(&hw_krait_l2_pmu.lock);
+
+	irq_work_run();
+
+	return IRQ_HANDLED;
+}
+
+static atomic_t active_l2_events = ATOMIC_INIT(0);
+static DEFINE_MUTEX(krait_pmu_reserve_mutex);
+
+static int pmu_reserve_hardware(void)
+{
+	int i, err = -ENODEV, irq;
+
+	l2_pmu_device = reserve_pmu(ARM_PMU_DEVICE_L2);
+
+	if (IS_ERR(l2_pmu_device)) {
+		pr_warning("unable to reserve pmu\n");
+		return PTR_ERR(l2_pmu_device);
+	}
+
+	if (l2_pmu_device->num_resources < 1) {
+		pr_err("no irqs for PMUs defined\n");
+		return -ENODEV;
+	}
+
+	if (strncmp(l2_pmu_device->name, "l2-arm-pmu", 6)) {
+		pr_err("Incorrect pdev reserved !\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < l2_pmu_device->num_resources; ++i) {
+		irq = platform_get_irq(l2_pmu_device, i);
+		if (irq < 0)
+			continue;
+
+		err = request_irq(irq, krait_l2_handle_irq,
+				  IRQF_DISABLED | IRQF_NOBALANCING,
+				  "krait-l2-pmu", NULL);
+		if (err) {
+			pr_warning("unable to request IRQ%d for Krait L2 perf "
+				   "counters\n", irq);
+			break;
+		}
+
+		irq_get_chip(irq)->irq_unmask(irq_get_irq_data(irq));
+	}
+
+	if (err) {
+		for (i = i - 1; i >= 0; --i) {
+			irq = platform_get_irq(l2_pmu_device, i);
+			if (irq >= 0)
+				free_irq(irq, NULL);
+		}
+		release_pmu(l2_pmu_device);
+		l2_pmu_device = NULL;
+	}
+
+	return err;
+}
+
+static void pmu_release_hardware(void)
+{
+	int i, irq;
+
+	for (i = l2_pmu_device->num_resources - 1; i >= 0; --i) {
+		irq = platform_get_irq(l2_pmu_device, i);
+		if (irq >= 0)
+			free_irq(irq, NULL);
+	}
+
+	krait_l2_pmu_disable(NULL);
+
+	release_pmu(l2_pmu_device);
+	l2_pmu_device = NULL;
+}
+
+static void pmu_perf_event_destroy(struct perf_event *event)
+{
+	if (atomic_dec_and_mutex_lock
+	    (&active_l2_events, &krait_pmu_reserve_mutex)) {
+		pmu_release_hardware();
+		mutex_unlock(&krait_pmu_reserve_mutex);
+	}
+}
+
+static int krait_l2_event_init(struct perf_event *event)
+{
+	int err = 0;
+	struct hw_perf_event *hwc = &event->hw;
+	int status = 0;
+
+	switch (event->attr.type) {
+	case PERF_TYPE_SHARED:
+		break;
+
+	default:
+		return -ENOENT;
+	}
+
+	hwc->idx = -1;
+
+	event->destroy = pmu_perf_event_destroy;
+
+	if (!atomic_inc_not_zero(&active_l2_events)) {
+		/* 0 active events */
+		mutex_lock(&krait_pmu_reserve_mutex);
+		err = pmu_reserve_hardware();
+		mutex_unlock(&krait_pmu_reserve_mutex);
+		if (!err)
+			atomic_inc(&active_l2_events);
+		else
+			return err;
+	}
+
+	hwc->config = 0;
+	hwc->event_base = 0;
+
+	/* Check if we came via perf default syms */
+	if (event->attr.config == PERF_COUNT_HW_L2_CYCLES)
+		hwc->config_base = L2CYCLE_CTR_RAW_CODE;
+	else
+		hwc->config_base = event->attr.config;
+
+	/* Only one CPU can control the cycle counter */
+	if (hwc->config_base == L2CYCLE_CTR_RAW_CODE) {
+		/* Check if its already running */
+		status = get_l2_indirect_reg(L2PMCCNTSR);
+		if (status == 0x2) {
+			err = -ENOSPC;
+			goto out;
+		}
+	}
+
+	if (!hwc->sample_period) {
+		hwc->sample_period = MAX_L2_PERIOD;
+		hwc->last_period = hwc->sample_period;
+		local64_set(&hwc->period_left, hwc->sample_period);
+	}
+
+	pr_debug("%s: event: %lld init'd\n", __func__, event->attr.config);
+
+out:
+	if (err < 0)
+		pmu_perf_event_destroy(event);
+
+	return err;
+}
+
+static struct pmu krait_l2_pmu = {
+	.pmu_enable = krait_l2_pmu_enable,
+	.pmu_disable = krait_l2_pmu_disable,
+	.event_init = krait_l2_event_init,
+	.add = krait_l2_add_event,
+	.del = krait_l2_del_event,
+	.start = krait_l2_start_counter,
+	.stop = krait_l2_stop_counter,
+	.read = krait_l2_read,
+};
+
+static const struct arm_pmu *__init krait_l2_pmu_init(void)
+{
+	/* Register our own PMU here */
+	perf_pmu_register(&krait_l2_pmu, "Krait L2", PERF_TYPE_SHARED);
+
+	memset(&hw_krait_l2_pmu, 0, sizeof(hw_krait_l2_pmu));
+
+	/* Reset all ctrs */
+	set_l2_indirect_reg(L2PMCR, L2PMCR_RESET_ALL);
+
+	/* Avoid spurious interrupt if any */
+	get_reset_pmovsr();
+
+	raw_spin_lock_init(&hw_krait_l2_pmu.lock);
+
+	/* Don't return an arm_pmu here */
+	return NULL;
+}
+#else
+
+static const struct arm_pmu *__init krait_l2_pmu_init(void)
+{
+	return NULL;
+}
+#endif
diff --git a/arch/arm/kernel/perf_event_msm_l2.c b/arch/arm/kernel/perf_event_msm_l2.c
new file mode 100644
index 0000000..26753d8
--- /dev/null
+++ b/arch/arm/kernel/perf_event_msm_l2.c
@@ -0,0 +1,1013 @@
+/*
+ * 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
+ * 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.
+ */
+#ifdef CONFIG_ARCH_MSM8X60
+
+#include <linux/irq.h>
+
+#define MAX_BB_L2_PERIOD	((1ULL << 32) - 1)
+#define MAX_BB_L2_CTRS 5
+#define BB_L2CYCLE_CTR_BIT 31
+#define BB_L2CYCLE_CTR_EVENT_IDX 4
+#define BB_L2CYCLE_CTR_RAW_CODE 0xfe
+#define SCORPIONL2_PMNC_E       (1 << 0)	/* Enable all counters */
+#define SCORPION_L2_EVT_PREFIX 3
+#define SCORPION_MAX_L2_REG 4
+
+/*
+ * Lock to protect r/m/w sequences to the L2 PMU.
+ */
+DEFINE_RAW_SPINLOCK(bb_l2_pmu_lock);
+
+static struct platform_device *bb_l2_pmu_device;
+
+struct hw_bb_l2_pmu {
+	struct perf_event *events[MAX_BB_L2_CTRS];
+	unsigned long active_mask[BITS_TO_LONGS(MAX_BB_L2_CTRS)];
+	raw_spinlock_t lock;
+};
+
+struct hw_bb_l2_pmu hw_bb_l2_pmu;
+
+struct bb_l2_scorp_evt {
+	u32 evt_type;
+	u32 val;
+	u8 grp;
+	u32 evt_type_act;
+};
+
+enum scorpion_perf_types {
+	SCORPIONL2_TOTAL_BANK_REQ = 0x90,
+	SCORPIONL2_DSIDE_READ = 0x91,
+	SCORPIONL2_DSIDE_WRITE = 0x92,
+	SCORPIONL2_ISIDE_READ = 0x93,
+	SCORPIONL2_L2CACHE_ISIDE_READ = 0x94,
+	SCORPIONL2_L2CACHE_BANK_REQ = 0x95,
+	SCORPIONL2_L2CACHE_DSIDE_READ = 0x96,
+	SCORPIONL2_L2CACHE_DSIDE_WRITE = 0x97,
+	SCORPIONL2_L2NOCACHE_DSIDE_WRITE = 0x98,
+	SCORPIONL2_L2NOCACHE_ISIDE_READ = 0x99,
+	SCORPIONL2_L2NOCACHE_TOTAL_REQ = 0x9a,
+	SCORPIONL2_L2NOCACHE_DSIDE_READ = 0x9b,
+	SCORPIONL2_DSIDE_READ_NOL1 = 0x9c,
+	SCORPIONL2_L2CACHE_WRITETHROUGH = 0x9d,
+	SCORPIONL2_BARRIERS = 0x9e,
+	SCORPIONL2_HARDWARE_TABLE_WALKS = 0x9f,
+	SCORPIONL2_MVA_POC = 0xa0,
+	SCORPIONL2_L2CACHE_HW_TABLE_WALKS = 0xa1,
+	SCORPIONL2_SETWAY_CACHE_OPS = 0xa2,
+	SCORPIONL2_DSIDE_WRITE_HITS = 0xa3,
+	SCORPIONL2_ISIDE_READ_HITS = 0xa4,
+	SCORPIONL2_CACHE_DSIDE_READ_NOL1 = 0xa5,
+	SCORPIONL2_TOTAL_CACHE_HITS = 0xa6,
+	SCORPIONL2_CACHE_MATCH_MISS = 0xa7,
+	SCORPIONL2_DREAD_HIT_L1_DATA = 0xa8,
+	SCORPIONL2_L2LINE_LOCKED = 0xa9,
+	SCORPIONL2_HW_TABLE_WALK_HIT = 0xaa,
+	SCORPIONL2_CACHE_MVA_POC = 0xab,
+	SCORPIONL2_L2ALLOC_DWRITE_MISS = 0xac,
+	SCORPIONL2_CORRECTED_TAG_ARRAY = 0xad,
+	SCORPIONL2_CORRECTED_DATA_ARRAY = 0xae,
+	SCORPIONL2_CORRECTED_REPLACEMENT_ARRAY = 0xaf,
+	SCORPIONL2_PMBUS_MPAAF = 0xb0,
+	SCORPIONL2_PMBUS_MPWDAF = 0xb1,
+	SCORPIONL2_PMBUS_MPBRT = 0xb2,
+	SCORPIONL2_CPU0_GRANT = 0xb3,
+	SCORPIONL2_CPU1_GRANT = 0xb4,
+	SCORPIONL2_CPU0_NOGRANT = 0xb5,
+	SCORPIONL2_CPU1_NOGRANT = 0xb6,
+	SCORPIONL2_CPU0_LOSING_ARB = 0xb7,
+	SCORPIONL2_CPU1_LOSING_ARB = 0xb8,
+	SCORPIONL2_SLAVEPORT_NOGRANT = 0xb9,
+	SCORPIONL2_SLAVEPORT_BPQ_FULL = 0xba,
+	SCORPIONL2_SLAVEPORT_LOSING_ARB = 0xbb,
+	SCORPIONL2_SLAVEPORT_GRANT = 0xbc,
+	SCORPIONL2_SLAVEPORT_GRANTLOCK = 0xbd,
+	SCORPIONL2_L2EM_STREX_PASS = 0xbe,
+	SCORPIONL2_L2EM_STREX_FAIL = 0xbf,
+	SCORPIONL2_LDREX_RESERVE_L2EM = 0xc0,
+	SCORPIONL2_SLAVEPORT_LDREX = 0xc1,
+	SCORPIONL2_CPU0_L2EM_CLEARED = 0xc2,
+	SCORPIONL2_CPU1_L2EM_CLEARED = 0xc3,
+	SCORPIONL2_SLAVEPORT_L2EM_CLEARED = 0xc4,
+	SCORPIONL2_CPU0_CLAMPED = 0xc5,
+	SCORPIONL2_CPU1_CLAMPED = 0xc6,
+	SCORPIONL2_CPU0_WAIT = 0xc7,
+	SCORPIONL2_CPU1_WAIT = 0xc8,
+	SCORPIONL2_CPU0_NONAMBAS_WAIT = 0xc9,
+	SCORPIONL2_CPU1_NONAMBAS_WAIT = 0xca,
+	SCORPIONL2_CPU0_DSB_WAIT = 0xcb,
+	SCORPIONL2_CPU1_DSB_WAIT = 0xcc,
+	SCORPIONL2_AXI_READ = 0xcd,
+	SCORPIONL2_AXI_WRITE = 0xce,
+
+	SCORPIONL2_1BEAT_WRITE = 0xcf,
+	SCORPIONL2_2BEAT_WRITE = 0xd0,
+	SCORPIONL2_4BEAT_WRITE = 0xd1,
+	SCORPIONL2_8BEAT_WRITE = 0xd2,
+	SCORPIONL2_12BEAT_WRITE = 0xd3,
+	SCORPIONL2_16BEAT_WRITE = 0xd4,
+	SCORPIONL2_1BEAT_DSIDE_READ = 0xd5,
+	SCORPIONL2_2BEAT_DSIDE_READ = 0xd6,
+	SCORPIONL2_4BEAT_DSIDE_READ = 0xd7,
+	SCORPIONL2_8BEAT_DSIDE_READ = 0xd8,
+	SCORPIONL2_CSYS_READ_1BEAT = 0xd9,
+	SCORPIONL2_CSYS_READ_2BEAT = 0xda,
+	SCORPIONL2_CSYS_READ_4BEAT = 0xdb,
+	SCORPIONL2_CSYS_READ_8BEAT = 0xdc,
+	SCORPIONL2_4BEAT_IFETCH_READ = 0xdd,
+	SCORPIONL2_8BEAT_IFETCH_READ = 0xde,
+	SCORPIONL2_CSYS_WRITE_1BEAT = 0xdf,
+	SCORPIONL2_CSYS_WRITE_2BEAT = 0xe0,
+	SCORPIONL2_AXI_READ_DATA_BEAT = 0xe1,
+	SCORPIONL2_AXI_WRITE_EVT1 = 0xe2,
+	SCORPIONL2_AXI_WRITE_EVT2 = 0xe3,
+	SCORPIONL2_LDREX_REQ = 0xe4,
+	SCORPIONL2_STREX_PASS = 0xe5,
+	SCORPIONL2_STREX_FAIL = 0xe6,
+	SCORPIONL2_CPREAD = 0xe7,
+	SCORPIONL2_CPWRITE = 0xe8,
+	SCORPIONL2_BARRIER_REQ = 0xe9,
+	SCORPIONL2_AXI_READ_SLVPORT = 0xea,
+	SCORPIONL2_AXI_WRITE_SLVPORT = 0xeb,
+	SCORPIONL2_AXI_READ_SLVPORT_DATABEAT = 0xec,
+	SCORPIONL2_AXI_WRITE_SLVPORT_DATABEAT = 0xed,
+	SCORPIONL2_SNOOPKILL_PREFILTER = 0xee,
+	SCORPIONL2_SNOOPKILL_FILTEROUT = 0xef,
+	SCORPIONL2_SNOOPED_IC = 0xf0,
+	SCORPIONL2_SNOOPED_BP = 0xf1,
+	SCORPIONL2_SNOOPED_BARRIERS = 0xf2,
+	SCORPIONL2_SNOOPED_TLB = 0xf3,
+	BB_L2_MAX_EVT,
+};
+
+static const struct bb_l2_scorp_evt sc_evt[] = {
+	{SCORPIONL2_TOTAL_BANK_REQ, 0x80000001, 0, 0x00},
+	{SCORPIONL2_DSIDE_READ, 0x80000100, 0, 0x01},
+	{SCORPIONL2_DSIDE_WRITE, 0x80010000, 0, 0x02},
+	{SCORPIONL2_ISIDE_READ, 0x81000000, 0, 0x03},
+	{SCORPIONL2_L2CACHE_ISIDE_READ, 0x80000002, 0, 0x00},
+	{SCORPIONL2_L2CACHE_BANK_REQ, 0x80000200, 0, 0x01},
+	{SCORPIONL2_L2CACHE_DSIDE_READ, 0x80020000, 0, 0x02},
+	{SCORPIONL2_L2CACHE_DSIDE_WRITE, 0x82000000, 0, 0x03},
+	{SCORPIONL2_L2NOCACHE_DSIDE_WRITE, 0x80000003, 0, 0x00},
+	{SCORPIONL2_L2NOCACHE_ISIDE_READ, 0x80000300, 0, 0x01},
+	{SCORPIONL2_L2NOCACHE_TOTAL_REQ, 0x80030000, 0, 0x02},
+	{SCORPIONL2_L2NOCACHE_DSIDE_READ, 0x83000000, 0, 0x03},
+	{SCORPIONL2_DSIDE_READ_NOL1, 0x80000004, 0, 0x00},
+	{SCORPIONL2_L2CACHE_WRITETHROUGH, 0x80000400, 0, 0x01},
+	{SCORPIONL2_BARRIERS, 0x84000000, 0, 0x03},
+	{SCORPIONL2_HARDWARE_TABLE_WALKS, 0x80000005, 0, 0x00},
+	{SCORPIONL2_MVA_POC, 0x80000500, 0, 0x01},
+	{SCORPIONL2_L2CACHE_HW_TABLE_WALKS, 0x80050000, 0, 0x02},
+	{SCORPIONL2_SETWAY_CACHE_OPS, 0x85000000, 0, 0x03},
+	{SCORPIONL2_DSIDE_WRITE_HITS, 0x80000006, 0, 0x00},
+	{SCORPIONL2_ISIDE_READ_HITS, 0x80000600, 0, 0x01},
+	{SCORPIONL2_CACHE_DSIDE_READ_NOL1, 0x80060000, 0, 0x02},
+	{SCORPIONL2_TOTAL_CACHE_HITS, 0x86000000, 0, 0x03},
+	{SCORPIONL2_CACHE_MATCH_MISS, 0x80000007, 0, 0x00},
+	{SCORPIONL2_DREAD_HIT_L1_DATA, 0x87000000, 0, 0x03},
+	{SCORPIONL2_L2LINE_LOCKED, 0x80000008, 0, 0x00},
+	{SCORPIONL2_HW_TABLE_WALK_HIT, 0x80000800, 0, 0x01},
+	{SCORPIONL2_CACHE_MVA_POC, 0x80080000, 0, 0x02},
+	{SCORPIONL2_L2ALLOC_DWRITE_MISS, 0x88000000, 0, 0x03},
+	{SCORPIONL2_CORRECTED_TAG_ARRAY, 0x80001A00, 0, 0x01},
+	{SCORPIONL2_CORRECTED_DATA_ARRAY, 0x801A0000, 0, 0x02},
+	{SCORPIONL2_CORRECTED_REPLACEMENT_ARRAY, 0x9A000000, 0, 0x03},
+	{SCORPIONL2_PMBUS_MPAAF, 0x80001C00, 0, 0x01},
+	{SCORPIONL2_PMBUS_MPWDAF, 0x801C0000, 0, 0x02},
+	{SCORPIONL2_PMBUS_MPBRT, 0x9C000000, 0, 0x03},
+
+	{SCORPIONL2_CPU0_GRANT, 0x80000001, 1, 0x04},
+	{SCORPIONL2_CPU1_GRANT, 0x80000100, 1, 0x05},
+	{SCORPIONL2_CPU0_NOGRANT, 0x80020000, 1, 0x06},
+	{SCORPIONL2_CPU1_NOGRANT, 0x82000000, 1, 0x07},
+	{SCORPIONL2_CPU0_LOSING_ARB, 0x80040000, 1, 0x06},
+	{SCORPIONL2_CPU1_LOSING_ARB, 0x84000000, 1, 0x07},
+	{SCORPIONL2_SLAVEPORT_NOGRANT, 0x80000007, 1, 0x04},
+	{SCORPIONL2_SLAVEPORT_BPQ_FULL, 0x80000700, 1, 0x05},
+	{SCORPIONL2_SLAVEPORT_LOSING_ARB, 0x80070000, 1, 0x06},
+	{SCORPIONL2_SLAVEPORT_GRANT, 0x87000000, 1, 0x07},
+	{SCORPIONL2_SLAVEPORT_GRANTLOCK, 0x80000008, 1, 0x04},
+	{SCORPIONL2_L2EM_STREX_PASS, 0x80000009, 1, 0x04},
+	{SCORPIONL2_L2EM_STREX_FAIL, 0x80000900, 1, 0x05},
+	{SCORPIONL2_LDREX_RESERVE_L2EM, 0x80090000, 1, 0x06},
+	{SCORPIONL2_SLAVEPORT_LDREX, 0x89000000, 1, 0x07},
+	{SCORPIONL2_CPU0_L2EM_CLEARED, 0x800A0000, 1, 0x06},
+	{SCORPIONL2_CPU1_L2EM_CLEARED, 0x8A000000, 1, 0x07},
+	{SCORPIONL2_SLAVEPORT_L2EM_CLEARED, 0x80000B00, 1, 0x05},
+	{SCORPIONL2_CPU0_CLAMPED, 0x8000000E, 1, 0x04},
+	{SCORPIONL2_CPU1_CLAMPED, 0x80000E00, 1, 0x05},
+	{SCORPIONL2_CPU0_WAIT, 0x800F0000, 1, 0x06},
+	{SCORPIONL2_CPU1_WAIT, 0x8F000000, 1, 0x07},
+	{SCORPIONL2_CPU0_NONAMBAS_WAIT, 0x80000010, 1, 0x04},
+	{SCORPIONL2_CPU1_NONAMBAS_WAIT, 0x80001000, 1, 0x05},
+	{SCORPIONL2_CPU0_DSB_WAIT, 0x80000014, 1, 0x04},
+	{SCORPIONL2_CPU1_DSB_WAIT, 0x80001400, 1, 0x05},
+
+	{SCORPIONL2_AXI_READ, 0x80000001, 2, 0x08},
+	{SCORPIONL2_AXI_WRITE, 0x80000100, 2, 0x09},
+	{SCORPIONL2_1BEAT_WRITE, 0x80010000, 2, 0x0a},
+	{SCORPIONL2_2BEAT_WRITE, 0x80010000, 2, 0x0b},
+	{SCORPIONL2_4BEAT_WRITE, 0x80000002, 2, 0x08},
+	{SCORPIONL2_8BEAT_WRITE, 0x80000200, 2, 0x09},
+	{SCORPIONL2_12BEAT_WRITE, 0x80020000, 2, 0x0a},
+	{SCORPIONL2_16BEAT_WRITE, 0x82000000, 2, 0x0b},
+	{SCORPIONL2_1BEAT_DSIDE_READ, 0x80000003, 2, 0x08},
+	{SCORPIONL2_2BEAT_DSIDE_READ, 0x80000300, 2, 0x09},
+	{SCORPIONL2_4BEAT_DSIDE_READ, 0x80030000, 2, 0x0a},
+	{SCORPIONL2_8BEAT_DSIDE_READ, 0x83000000, 2, 0x0b},
+	{SCORPIONL2_CSYS_READ_1BEAT, 0x80000004, 2, 0x08},
+	{SCORPIONL2_CSYS_READ_2BEAT, 0x80000400, 2, 0x09},
+	{SCORPIONL2_CSYS_READ_4BEAT, 0x80040000, 2, 0x0a},
+	{SCORPIONL2_CSYS_READ_8BEAT, 0x84000000, 2, 0x0b},
+	{SCORPIONL2_4BEAT_IFETCH_READ, 0x80000005, 2, 0x08},
+	{SCORPIONL2_8BEAT_IFETCH_READ, 0x80000500, 2, 0x09},
+	{SCORPIONL2_CSYS_WRITE_1BEAT, 0x80050000, 2, 0x0a},
+	{SCORPIONL2_CSYS_WRITE_2BEAT, 0x85000000, 2, 0x0b},
+	{SCORPIONL2_AXI_READ_DATA_BEAT, 0x80000600, 2, 0x09},
+	{SCORPIONL2_AXI_WRITE_EVT1, 0x80060000, 2, 0x0a},
+	{SCORPIONL2_AXI_WRITE_EVT2, 0x86000000, 2, 0x0b},
+	{SCORPIONL2_LDREX_REQ, 0x80000007, 2, 0x08},
+	{SCORPIONL2_STREX_PASS, 0x80000700, 2, 0x09},
+	{SCORPIONL2_STREX_FAIL, 0x80070000, 2, 0x0a},
+	{SCORPIONL2_CPREAD, 0x80000008, 2, 0x08},
+	{SCORPIONL2_CPWRITE, 0x80000800, 2, 0x09},
+	{SCORPIONL2_BARRIER_REQ, 0x88000000, 2, 0x0b},
+
+	{SCORPIONL2_AXI_READ_SLVPORT, 0x80000001, 3, 0x0c},
+	{SCORPIONL2_AXI_WRITE_SLVPORT, 0x80000100, 3, 0x0d},
+	{SCORPIONL2_AXI_READ_SLVPORT_DATABEAT, 0x80010000, 3, 0x0e},
+	{SCORPIONL2_AXI_WRITE_SLVPORT_DATABEAT, 0x81000000, 3, 0x0f},
+
+	{SCORPIONL2_SNOOPKILL_PREFILTER, 0x80000001, 4, 0x10},
+	{SCORPIONL2_SNOOPKILL_FILTEROUT, 0x80000100, 4, 0x11},
+	{SCORPIONL2_SNOOPED_IC, 0x80000002, 4, 0x10},
+	{SCORPIONL2_SNOOPED_BP, 0x80000200, 4, 0x11},
+	{SCORPIONL2_SNOOPED_BARRIERS, 0x80020000, 4, 0x12},
+	{SCORPIONL2_SNOOPED_TLB, 0x82000000, 4, 0x13},
+};
+
+static u32 bb_l2_read_l2pm0(void)
+{
+	u32 val;
+	asm volatile ("mrc p15, 3, %0, c15, c7, 0" : "=r" (val));
+	return val;
+}
+
+static void bb_l2_write_l2pm0(u32 val)
+{
+	asm volatile ("mcr p15, 3, %0, c15, c7, 0" : : "r" (val));
+}
+
+static u32 bb_l2_read_l2pm1(void)
+{
+	u32 val;
+	asm volatile ("mrc p15, 3, %0, c15, c7, 1" : "=r" (val));
+	return val;
+}
+
+static void bb_l2_write_l2pm1(u32 val)
+{
+	asm volatile ("mcr p15, 3, %0, c15, c7, 1" : : "r" (val));
+}
+
+static u32 bb_l2_read_l2pm2(void)
+{
+	u32 val;
+	asm volatile ("mrc p15, 3, %0, c15, c7, 2" : "=r" (val));
+	return val;
+}
+
+static void bb_l2_write_l2pm2(u32 val)
+{
+	asm volatile ("mcr p15, 3, %0, c15, c7, 2" : : "r" (val));
+}
+
+static u32 bb_l2_read_l2pm3(void)
+{
+	u32 val;
+	asm volatile ("mrc p15, 3, %0, c15, c7, 3" : "=r" (val));
+	return val;
+}
+
+static void bb_l2_write_l2pm3(u32 val)
+{
+	asm volatile ("mcr p15, 3, %0, c15, c7, 3" : : "r" (val));
+}
+
+static u32 bb_l2_read_l2pm4(void)
+{
+	u32 val;
+	asm volatile ("mrc p15, 3, %0, c15, c7, 4" : "=r" (val));
+	return val;
+}
+
+static void bb_l2_write_l2pm4(u32 val)
+{
+	asm volatile ("mcr p15, 3, %0, c15, c7, 4" : : "r" (val));
+}
+
+struct bb_scorpion_access_funcs {
+	u32(*read) (void);
+	void (*write) (u32);
+	void (*pre) (void);
+	void (*post) (void);
+};
+
+struct bb_scorpion_access_funcs bb_l2_func[] = {
+	{bb_l2_read_l2pm0, bb_l2_write_l2pm0, NULL, NULL},
+	{bb_l2_read_l2pm1, bb_l2_write_l2pm1, NULL, NULL},
+	{bb_l2_read_l2pm2, bb_l2_write_l2pm2, NULL, NULL},
+	{bb_l2_read_l2pm3, bb_l2_write_l2pm3, NULL, NULL},
+	{bb_l2_read_l2pm4, bb_l2_write_l2pm4, NULL, NULL},
+};
+
+#define COLMN0MASK 0x000000ff
+#define COLMN1MASK 0x0000ff00
+#define COLMN2MASK 0x00ff0000
+
+static u32 bb_l2_get_columnmask(u32 setval)
+{
+	if (setval & COLMN0MASK)
+		return 0xffffff00;
+	else if (setval & COLMN1MASK)
+		return 0xffff00ff;
+	else if (setval & COLMN2MASK)
+		return 0xff00ffff;
+	else
+		return 0x80ffffff;
+}
+
+static void bb_l2_evt_setup(u32 gr, u32 setval)
+{
+	u32 val;
+	if (bb_l2_func[gr].pre)
+		bb_l2_func[gr].pre();
+	val = bb_l2_get_columnmask(setval) & bb_l2_func[gr].read();
+	val = val | setval;
+	bb_l2_func[gr].write(val);
+	if (bb_l2_func[gr].post)
+		bb_l2_func[gr].post();
+}
+
+#define BB_L2_EVT_START_IDX 0x90
+#define BB_L2_INV_EVTYPE 0
+
+static unsigned int get_bb_l2_evtinfo(unsigned int evt_type,
+				      struct bb_l2_scorp_evt *evtinfo)
+{
+	u32 idx;
+	u8 prefix;
+	u8 reg;
+	u8 code;
+	u8 group;
+
+	prefix = (evt_type & 0xF0000) >> 16;
+	if (prefix == SCORPION_L2_EVT_PREFIX) {
+		reg   = (evt_type & 0x0F000) >> 12;
+		code  = (evt_type & 0x00FF0) >> 4;
+		group =  evt_type & 0x0000F;
+
+		if ((group > 3) || (reg > SCORPION_MAX_L2_REG))
+			return BB_L2_INV_EVTYPE;
+
+		evtinfo->val = 0x80000000 | (code << (group * 8));
+		evtinfo->grp = reg;
+		evtinfo->evt_type_act = group | (reg << 2);
+		return evtinfo->evt_type_act;
+	}
+
+	if (evt_type < BB_L2_EVT_START_IDX || evt_type >= BB_L2_MAX_EVT)
+		return BB_L2_INV_EVTYPE;
+	idx = evt_type - BB_L2_EVT_START_IDX;
+	if (sc_evt[idx].evt_type == evt_type) {
+		evtinfo->val = sc_evt[idx].val;
+		evtinfo->grp = sc_evt[idx].grp;
+		evtinfo->evt_type_act = sc_evt[idx].evt_type_act;
+		return sc_evt[idx].evt_type_act;
+	}
+	return BB_L2_INV_EVTYPE;
+}
+
+static inline void bb_l2_pmnc_write(unsigned long val)
+{
+	val &= 0xff;
+	asm volatile ("mcr p15, 3, %0, c15, c4, 0" : : "r" (val));
+}
+
+static inline unsigned long bb_l2_pmnc_read(void)
+{
+	u32 val;
+	asm volatile ("mrc p15, 3, %0, c15, c4, 0" : "=r" (val));
+	return val;
+}
+
+static void bb_l2_set_evcntcr(void)
+{
+	u32 val = 0x0;
+	asm volatile ("mcr p15, 3, %0, c15, c6, 4" : : "r" (val));
+}
+
+static inline void bb_l2_set_evtyper(int ctr, int val)
+{
+	/* select ctr */
+	asm volatile ("mcr p15, 3, %0, c15, c6, 0" : : "r" (ctr));
+
+	/* write into EVTYPER */
+	asm volatile ("mcr p15, 3, %0, c15, c6, 7" : : "r" (val));
+}
+
+static void bb_l2_set_evfilter_task_mode(void)
+{
+	u32 filter_val = 0x000f0030 | 1 << smp_processor_id();
+
+	asm volatile ("mcr p15, 3, %0, c15, c6, 3" : : "r" (filter_val));
+}
+
+static void bb_l2_set_evfilter_sys_mode(void)
+{
+	u32 filter_val = 0x000f003f;
+
+	asm volatile ("mcr p15, 3, %0, c15, c6, 3" : : "r" (filter_val));
+}
+
+static void bb_l2_enable_intenset(u32 idx)
+{
+	if (idx == BB_L2CYCLE_CTR_EVENT_IDX) {
+		asm volatile ("mcr p15, 3, %0, c15, c5, 1" : : "r"
+			      (1 << BB_L2CYCLE_CTR_BIT));
+	} else {
+		asm volatile ("mcr p15, 3, %0, c15, c5, 1" : : "r" (1 << idx));
+	}
+}
+
+static void bb_l2_disable_intenclr(u32 idx)
+{
+	if (idx == BB_L2CYCLE_CTR_EVENT_IDX) {
+		asm volatile ("mcr p15, 3, %0, c15, c5, 0" : : "r"
+			      (1 << BB_L2CYCLE_CTR_BIT));
+	} else {
+		asm volatile ("mcr p15, 3, %0, c15, c5, 0" : : "r" (1 << idx));
+	}
+}
+
+static void bb_l2_enable_counter(u32 idx)
+{
+	if (idx == BB_L2CYCLE_CTR_EVENT_IDX) {
+		asm volatile ("mcr p15, 3, %0, c15, c4, 3" : : "r"
+			      (1 << BB_L2CYCLE_CTR_BIT));
+	} else {
+		asm volatile ("mcr p15, 3, %0, c15, c4, 3" : : "r" (1 << idx));
+	}
+}
+
+static void bb_l2_disable_counter(u32 idx)
+{
+	if (idx == BB_L2CYCLE_CTR_EVENT_IDX) {
+		asm volatile ("mcr p15, 3, %0, c15, c4, 2" : : "r"
+			      (1 << BB_L2CYCLE_CTR_BIT));
+
+	} else {
+		asm volatile ("mcr p15, 3, %0, c15, c4, 2" : : "r" (1 << idx));
+	}
+}
+
+static u64 bb_l2_read_counter(u32 idx)
+{
+	u32 val;
+	unsigned long flags;
+
+	if (idx == BB_L2CYCLE_CTR_EVENT_IDX) {
+		asm volatile ("mrc p15, 3, %0, c15, c4, 5" : "=r" (val));
+	} else {
+		raw_spin_lock_irqsave(&bb_l2_pmu_lock, flags);
+		asm volatile ("mcr p15, 3, %0, c15, c6, 0" : : "r" (idx));
+
+		/* read val from counter */
+		asm volatile ("mrc p15, 3, %0, c15, c6, 5" : "=r" (val));
+		raw_spin_unlock_irqrestore(&bb_l2_pmu_lock, flags);
+	}
+
+	return val;
+}
+
+static void bb_l2_write_counter(u32 idx, u32 val)
+{
+	unsigned long flags;
+
+	if (idx == BB_L2CYCLE_CTR_EVENT_IDX) {
+		asm volatile ("mcr p15, 3, %0, c15, c4, 5" : : "r" (val));
+	} else {
+		raw_spin_lock_irqsave(&bb_l2_pmu_lock, flags);
+		/* select counter */
+		asm volatile ("mcr p15, 3, %0, c15, c6, 0" : : "r" (idx));
+
+		/* write val into counter */
+		asm volatile ("mcr p15, 3, %0, c15, c6, 5" : : "r" (val));
+		raw_spin_unlock_irqrestore(&bb_l2_pmu_lock, flags);
+	}
+}
+
+static int
+bb_pmu_event_set_period(struct perf_event *event,
+			struct hw_perf_event *hwc, int idx)
+{
+	s64 left = local64_read(&hwc->period_left);
+	s64 period = hwc->sample_period;
+	int ret = 0;
+
+	if (unlikely(left <= -period)) {
+		left = period;
+		local64_set(&hwc->period_left, left);
+		hwc->last_period = period;
+		ret = 1;
+	}
+
+	if (unlikely(left <= 0)) {
+		left += period;
+		local64_set(&hwc->period_left, left);
+		hwc->last_period = period;
+		ret = 1;
+	}
+
+	if (left > (s64) MAX_BB_L2_PERIOD)
+		left = MAX_BB_L2_PERIOD;
+
+	local64_set(&hwc->prev_count, (u64)-left);
+
+	bb_l2_write_counter(idx, (u64) (-left) & 0xffffffff);
+
+	perf_event_update_userpage(event);
+
+	return ret;
+}
+
+static u64
+bb_pmu_event_update(struct perf_event *event, struct hw_perf_event *hwc,
+		    int idx, int overflow)
+{
+	u64 prev_raw_count, new_raw_count;
+	u64 delta;
+
+again:
+	prev_raw_count = local64_read(&hwc->prev_count);
+	new_raw_count = bb_l2_read_counter(idx);
+
+	if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
+			    new_raw_count) != prev_raw_count)
+		goto again;
+
+	new_raw_count &= MAX_BB_L2_PERIOD;
+	prev_raw_count &= MAX_BB_L2_PERIOD;
+
+	if (overflow) {
+		delta = MAX_BB_L2_PERIOD - prev_raw_count + new_raw_count;
+		pr_err("%s: delta: %lld\n", __func__, delta);
+	} else
+		delta = new_raw_count - prev_raw_count;
+
+	local64_add(delta, &event->count);
+	local64_sub(delta, &hwc->period_left);
+
+	pr_debug("%s: new: %lld, prev: %lld, event: %ld count: %lld\n",
+		 __func__, new_raw_count, prev_raw_count,
+		 hwc->config_base, local64_read(&event->count));
+
+	return new_raw_count;
+}
+
+static void bb_l2_read(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+
+	bb_pmu_event_update(event, hwc, hwc->idx, 0);
+}
+
+static void bb_l2_stop_counter(struct perf_event *event, int flags)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	int idx = hwc->idx;
+
+	if (!(hwc->state & PERF_HES_STOPPED)) {
+		bb_l2_disable_intenclr(idx);
+		bb_l2_disable_counter(idx);
+
+		bb_pmu_event_update(event, hwc, idx, 0);
+		hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
+	}
+
+	pr_debug("%s: event: %ld ctr: %d stopped\n", __func__, hwc->config_base,
+		 idx);
+}
+
+static void bb_l2_start_counter(struct perf_event *event, int flags)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	int idx = hwc->idx;
+	struct bb_l2_scorp_evt evtinfo;
+	int evtype = hwc->config_base;
+	int ev_typer;
+	unsigned long iflags;
+	int cpu_id = smp_processor_id();
+
+	if (flags & PERF_EF_RELOAD)
+		WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
+
+	hwc->state = 0;
+
+	bb_pmu_event_set_period(event, hwc, idx);
+
+	if (hwc->config_base == BB_L2CYCLE_CTR_RAW_CODE)
+		goto out;
+
+	memset(&evtinfo, 0, sizeof(evtinfo));
+
+	ev_typer = get_bb_l2_evtinfo(evtype, &evtinfo);
+
+	raw_spin_lock_irqsave(&bb_l2_pmu_lock, iflags);
+
+	bb_l2_set_evtyper(idx, ev_typer);
+
+	bb_l2_set_evcntcr();
+
+	if (event->cpu < 0)
+		bb_l2_set_evfilter_task_mode();
+	else
+		bb_l2_set_evfilter_sys_mode();
+
+	bb_l2_evt_setup(evtinfo.grp, evtinfo.val);
+
+	raw_spin_unlock_irqrestore(&bb_l2_pmu_lock, iflags);
+
+out:
+
+	bb_l2_enable_intenset(idx);
+
+	bb_l2_enable_counter(idx);
+
+	pr_debug("%s: idx: %d, event: %d, val: %x, cpu: %d\n",
+		 __func__, idx, evtype, evtinfo.val, cpu_id);
+}
+
+static void bb_l2_del_event(struct perf_event *event, int flags)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	int idx = hwc->idx;
+	unsigned long iflags;
+
+	raw_spin_lock_irqsave(&hw_bb_l2_pmu.lock, iflags);
+
+	clear_bit(idx, (long unsigned int *)(&hw_bb_l2_pmu.active_mask));
+
+	bb_l2_stop_counter(event, PERF_EF_UPDATE);
+	hw_bb_l2_pmu.events[idx] = NULL;
+	hwc->idx = -1;
+
+	raw_spin_unlock_irqrestore(&hw_bb_l2_pmu.lock, iflags);
+
+	pr_debug("%s: event: %ld deleted\n", __func__, hwc->config_base);
+
+	perf_event_update_userpage(event);
+}
+
+static int bb_l2_add_event(struct perf_event *event, int flags)
+{
+	int ctr = 0;
+	struct hw_perf_event *hwc = &event->hw;
+	unsigned long iflags;
+	int err = 0;
+
+	perf_pmu_disable(event->pmu);
+
+	raw_spin_lock_irqsave(&hw_bb_l2_pmu.lock, iflags);
+
+	/* Cycle counter has a resrvd index */
+	if (hwc->config_base == BB_L2CYCLE_CTR_RAW_CODE) {
+		if (hw_bb_l2_pmu.events[BB_L2CYCLE_CTR_EVENT_IDX]) {
+			pr_err("%s: Stale cycle ctr event ptr !\n", __func__);
+			err = -EINVAL;
+			goto out;
+		}
+		hwc->idx = BB_L2CYCLE_CTR_EVENT_IDX;
+		hw_bb_l2_pmu.events[BB_L2CYCLE_CTR_EVENT_IDX] = event;
+		set_bit(BB_L2CYCLE_CTR_EVENT_IDX,
+			(long unsigned int *)&hw_bb_l2_pmu.active_mask);
+		goto skip_ctr_loop;
+	}
+
+	for (ctr = 0; ctr < MAX_BB_L2_CTRS - 1; ctr++) {
+		if (!hw_bb_l2_pmu.events[ctr]) {
+			hwc->idx = ctr;
+			hw_bb_l2_pmu.events[ctr] = event;
+			set_bit(ctr, (long unsigned int *)
+				&hw_bb_l2_pmu.active_mask);
+			break;
+		}
+	}
+
+	if (hwc->idx < 0) {
+		err = -ENOSPC;
+		pr_err("%s: No space for event: %llx!!\n", __func__,
+		       event->attr.config);
+		goto out;
+	}
+
+skip_ctr_loop:
+
+	bb_l2_disable_counter(hwc->idx);
+
+	hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
+
+	if (flags & PERF_EF_START)
+		bb_l2_start_counter(event, PERF_EF_RELOAD);
+
+	perf_event_update_userpage(event);
+
+	pr_debug("%s: event: %ld, ctr: %d added from cpu:%d\n",
+		 __func__, hwc->config_base, hwc->idx, smp_processor_id());
+out:
+	raw_spin_unlock_irqrestore(&hw_bb_l2_pmu.lock, iflags);
+
+	/* Resume the PMU even if this event could not be added */
+	perf_pmu_enable(event->pmu);
+
+	return err;
+}
+
+static void bb_l2_pmu_enable(struct pmu *pmu)
+{
+	unsigned long flags;
+	isb();
+	raw_spin_lock_irqsave(&bb_l2_pmu_lock, flags);
+	/* Enable all counters */
+	bb_l2_pmnc_write(bb_l2_pmnc_read() | SCORPIONL2_PMNC_E);
+	raw_spin_unlock_irqrestore(&bb_l2_pmu_lock, flags);
+}
+
+static void bb_l2_pmu_disable(struct pmu *pmu)
+{
+	unsigned long flags;
+	raw_spin_lock_irqsave(&bb_l2_pmu_lock, flags);
+	/* Disable all counters */
+	bb_l2_pmnc_write(bb_l2_pmnc_read() & ~SCORPIONL2_PMNC_E);
+	raw_spin_unlock_irqrestore(&bb_l2_pmu_lock, flags);
+	isb();
+}
+
+static inline u32 bb_l2_get_reset_pmovsr(void)
+{
+	u32 val;
+
+	/* Read */
+	asm volatile ("mrc p15, 3, %0, c15, c4, 1" : "=r" (val));
+
+	/* Write to clear flags */
+	val &= 0xffffffff;
+	asm volatile ("mcr p15, 3, %0, c15, c4, 1" : : "r" (val));
+
+	return val;
+}
+
+static irqreturn_t bb_l2_handle_irq(int irq_num, void *dev)
+{
+	unsigned long pmovsr;
+	struct perf_sample_data data;
+	struct pt_regs *regs;
+	struct perf_event *event;
+	struct hw_perf_event *hwc;
+	int bitp;
+	int idx = 0;
+
+	pmovsr = bb_l2_get_reset_pmovsr();
+
+	if (!(pmovsr & 0xffffffff))
+		return IRQ_NONE;
+
+	regs = get_irq_regs();
+
+	perf_sample_data_init(&data, 0);
+
+	raw_spin_lock(&hw_bb_l2_pmu.lock);
+
+	while (pmovsr) {
+		bitp = __ffs(pmovsr);
+
+		if (bitp == BB_L2CYCLE_CTR_BIT)
+			idx = BB_L2CYCLE_CTR_EVENT_IDX;
+		else
+			idx = bitp;
+
+		event = hw_bb_l2_pmu.events[idx];
+
+		if (!event)
+			goto next;
+
+		if (!test_bit(idx, hw_bb_l2_pmu.active_mask))
+			goto next;
+
+		hwc = &event->hw;
+		bb_pmu_event_update(event, hwc, idx, 1);
+		data.period = event->hw.last_period;
+
+		if (!bb_pmu_event_set_period(event, hwc, idx))
+			goto next;
+
+		if (perf_event_overflow(event, 0, &data, regs))
+			bb_l2_disable_counter(hwc->idx);
+next:
+		pmovsr &= (pmovsr - 1);
+	}
+
+	raw_spin_unlock(&hw_bb_l2_pmu.lock);
+
+	irq_work_run();
+
+	return IRQ_HANDLED;
+}
+
+static atomic_t active_bb_l2_events = ATOMIC_INIT(0);
+static DEFINE_MUTEX(bb_pmu_reserve_mutex);
+
+static int bb_pmu_reserve_hardware(void)
+{
+	int i, err = -ENODEV, irq;
+
+	bb_l2_pmu_device = reserve_pmu(ARM_PMU_DEVICE_L2);
+
+	if (IS_ERR(bb_l2_pmu_device)) {
+		pr_warning("unable to reserve pmu\n");
+		return PTR_ERR(bb_l2_pmu_device);
+	}
+
+	if (bb_l2_pmu_device->num_resources < 1) {
+		pr_err("no irqs for PMUs defined\n");
+		return -ENODEV;
+	}
+
+	if (strncmp(bb_l2_pmu_device->name, "l2-arm-pmu", 6)) {
+		pr_err("Incorrect pdev reserved !\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < bb_l2_pmu_device->num_resources; ++i) {
+		irq = platform_get_irq(bb_l2_pmu_device, i);
+		if (irq < 0)
+			continue;
+
+		err = request_irq(irq, bb_l2_handle_irq,
+				  IRQF_DISABLED | IRQF_NOBALANCING,
+				  "bb-l2-pmu", NULL);
+		if (err) {
+			pr_warning("unable to request IRQ%d for Krait L2 perf "
+				   "counters\n", irq);
+			break;
+		}
+
+		irq_get_chip(irq)->irq_unmask(irq_get_irq_data(irq));
+	}
+
+	if (err) {
+		for (i = i - 1; i >= 0; --i) {
+			irq = platform_get_irq(bb_l2_pmu_device, i);
+			if (irq >= 0)
+				free_irq(irq, NULL);
+		}
+		release_pmu(bb_l2_pmu_device);
+		bb_l2_pmu_device = NULL;
+	}
+
+	return err;
+}
+
+static void bb_pmu_release_hardware(void)
+{
+	int i, irq;
+
+	for (i = bb_l2_pmu_device->num_resources - 1; i >= 0; --i) {
+		irq = platform_get_irq(bb_l2_pmu_device, i);
+		if (irq >= 0)
+			free_irq(irq, NULL);
+	}
+
+	bb_l2_pmu_disable(NULL);
+
+	release_pmu(bb_l2_pmu_device);
+	bb_l2_pmu_device = NULL;
+}
+
+static void bb_pmu_perf_event_destroy(struct perf_event *event)
+{
+	if (atomic_dec_and_mutex_lock
+	    (&active_bb_l2_events, &bb_pmu_reserve_mutex)) {
+		bb_pmu_release_hardware();
+		mutex_unlock(&bb_pmu_reserve_mutex);
+	}
+}
+
+static int bb_l2_event_init(struct perf_event *event)
+{
+	int err = 0;
+	struct hw_perf_event *hwc = &event->hw;
+	int status = 0;
+
+	switch (event->attr.type) {
+	case PERF_TYPE_SHARED:
+		break;
+
+	default:
+		return -ENOENT;
+	}
+
+	hwc->idx = -1;
+
+	event->destroy = bb_pmu_perf_event_destroy;
+
+	if (!atomic_inc_not_zero(&active_bb_l2_events)) {
+		/* 0 active events */
+		mutex_lock(&bb_pmu_reserve_mutex);
+		err = bb_pmu_reserve_hardware();
+		mutex_unlock(&bb_pmu_reserve_mutex);
+		if (!err)
+			atomic_inc(&active_bb_l2_events);
+		else
+			return err;
+	}
+
+	hwc->config = 0;
+	hwc->event_base = 0;
+
+	/* Check if we came via perf default syms */
+	if (event->attr.config == PERF_COUNT_HW_L2_CYCLES)
+		hwc->config_base = BB_L2CYCLE_CTR_RAW_CODE;
+	else
+		hwc->config_base = event->attr.config;
+
+	/* Only one CPU can control the cycle counter */
+	if (hwc->config_base == BB_L2CYCLE_CTR_RAW_CODE) {
+		/* Check if its already running */
+		asm volatile ("mrc p15, 3, %0, c15, c4, 6" : "=r" (status));
+		if (status == 0x2) {
+			err = -ENOSPC;
+			goto out;
+		}
+	}
+
+	if (!hwc->sample_period) {
+		hwc->sample_period = MAX_BB_L2_PERIOD;
+		hwc->last_period = hwc->sample_period;
+		local64_set(&hwc->period_left, hwc->sample_period);
+	}
+
+	pr_debug("%s: event: %lld init'd\n", __func__, event->attr.config);
+
+out:
+	if (err < 0)
+		bb_pmu_perf_event_destroy(event);
+
+	return err;
+}
+
+static struct pmu bb_l2_pmu = {
+	.pmu_enable = bb_l2_pmu_enable,
+	.pmu_disable = bb_l2_pmu_disable,
+	.event_init = bb_l2_event_init,
+	.add = bb_l2_add_event,
+	.del = bb_l2_del_event,
+	.start = bb_l2_start_counter,
+	.stop = bb_l2_stop_counter,
+	.read = bb_l2_read,
+};
+
+static const struct arm_pmu *__init scorpionmp_l2_pmu_init(void)
+{
+	/* Register our own PMU here */
+	perf_pmu_register(&bb_l2_pmu, "BB L2", PERF_TYPE_SHARED);
+
+	memset(&hw_bb_l2_pmu, 0, sizeof(hw_bb_l2_pmu));
+
+	/* Avoid spurious interrupts at startup */
+	bb_l2_get_reset_pmovsr();
+
+	raw_spin_lock_init(&hw_bb_l2_pmu.lock);
+
+	/* Don't return an arm_pmu here */
+	return NULL;
+}
+#else
+
+static const struct arm_pmu *__init scorpionmp_l2_pmu_init(void)
+{
+	return NULL;
+}
+
+#endif
diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c
index b78af0c..b5ba783 100644
--- a/arch/arm/kernel/perf_event_v6.c
+++ b/arch/arm/kernel/perf_event_v6.c
@@ -76,7 +76,7 @@
 	[PERF_COUNT_HW_STALLED_CYCLES_BACKEND]	= ARMV6_PERFCTR_LSU_FULL_STALL,
 };
 
-static const unsigned armv6_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
+static unsigned armv6_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
 					  [PERF_COUNT_HW_CACHE_OP_MAX]
 					  [PERF_COUNT_HW_CACHE_RESULT_MAX] = {
 	[C(L1D)] = {
@@ -231,7 +231,7 @@
 	[PERF_COUNT_HW_STALLED_CYCLES_BACKEND]	= ARMV6MPCORE_PERFCTR_LSU_FULL_STALL,
 };
 
-static const unsigned armv6mpcore_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
+static unsigned armv6mpcore_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
 					[PERF_COUNT_HW_CACHE_OP_MAX]
 					[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
 	[C(L1D)] = {
@@ -655,6 +655,8 @@
 	.id			= ARM_PERF_PMU_ID_V6,
 	.name			= "v6",
 	.handle_irq		= armv6pmu_handle_irq,
+	.request_pmu_irq	= armpmu_generic_request_irq,
+	.free_pmu_irq		= armpmu_generic_free_irq,
 	.enable			= armv6pmu_enable_event,
 	.disable		= armv6pmu_disable_event,
 	.read_counter		= armv6pmu_read_counter,
@@ -690,6 +692,8 @@
 	.id			= ARM_PERF_PMU_ID_V6MP,
 	.name			= "v6mpcore",
 	.handle_irq		= armv6pmu_handle_irq,
+	.request_pmu_irq	= armpmu_generic_request_irq,
+	.free_pmu_irq		= armpmu_generic_free_irq,
 	.enable			= armv6pmu_enable_event,
 	.disable		= armv6mpcore_pmu_disable_event,
 	.read_counter		= armv6pmu_read_counter,
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index 00755d8..678c55d 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -130,7 +130,7 @@
 	[PERF_COUNT_HW_STALLED_CYCLES_BACKEND]	= HW_OP_UNSUPPORTED,
 };
 
-static const unsigned armv7_a8_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
+static unsigned armv7_a8_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
 					  [PERF_COUNT_HW_CACHE_OP_MAX]
 					  [PERF_COUNT_HW_CACHE_RESULT_MAX] = {
 	[C(L1D)] = {
@@ -254,7 +254,7 @@
 	[PERF_COUNT_HW_STALLED_CYCLES_BACKEND]	= ARMV7_A9_PERFCTR_STALL_DISPATCH,
 };
 
-static const unsigned armv7_a9_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
+static unsigned armv7_a9_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
 					  [PERF_COUNT_HW_CACHE_OP_MAX]
 					  [PERF_COUNT_HW_CACHE_RESULT_MAX] = {
 	[C(L1D)] = {
@@ -378,7 +378,7 @@
 	[PERF_COUNT_HW_STALLED_CYCLES_BACKEND]	= HW_OP_UNSUPPORTED,
 };
 
-static const unsigned armv7_a5_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
+static unsigned armv7_a5_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
 					[PERF_COUNT_HW_CACHE_OP_MAX]
 					[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
 	[C(L1D)] = {
@@ -500,7 +500,7 @@
 	[PERF_COUNT_HW_STALLED_CYCLES_BACKEND]	= HW_OP_UNSUPPORTED,
 };
 
-static const unsigned armv7_a15_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
+static unsigned armv7_a15_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
 					[PERF_COUNT_HW_CACHE_OP_MAX]
 					[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
 	[C(L1D)] = {
@@ -624,7 +624,7 @@
 	[PERF_COUNT_HW_STALLED_CYCLES_BACKEND]	= HW_OP_UNSUPPORTED,
 };
 
-static const unsigned armv7_a7_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
+static unsigned armv7_a7_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
 					[PERF_COUNT_HW_CACHE_OP_MAX]
 					[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
 	[C(L1D)] = {
@@ -993,7 +993,7 @@
 }
 #endif
 
-static void armv7pmu_enable_event(struct hw_perf_event *hwc, int idx)
+static void armv7pmu_enable_event(struct hw_perf_event *hwc, int idx, int cpu)
 {
 	unsigned long flags;
 	struct pmu_hw_events *events = cpu_pmu->get_hw_events();
diff --git a/arch/arm/kernel/perf_event_xscale.c b/arch/arm/kernel/perf_event_xscale.c
index 71a21e6..1a751f7 100644
--- a/arch/arm/kernel/perf_event_xscale.c
+++ b/arch/arm/kernel/perf_event_xscale.c
@@ -59,7 +59,7 @@
 	[PERF_COUNT_HW_STALLED_CYCLES_BACKEND]	= HW_OP_UNSUPPORTED,
 };
 
-static const unsigned xscale_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
+static unsigned xscale_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
 					   [PERF_COUNT_HW_CACHE_OP_MAX]
 					   [PERF_COUNT_HW_CACHE_RESULT_MAX] = {
 	[C(L1D)] = {
@@ -810,6 +810,8 @@
 	.id		= ARM_PERF_PMU_ID_XSCALE2,
 	.name		= "xscale2",
 	.handle_irq	= xscale2pmu_handle_irq,
+	.request_pmu_irq = armpmu_generic_request_irq,
+	.free_pmu_irq	= armpmu_generic_free_irq,
 	.enable		= xscale2pmu_enable_event,
 	.disable	= xscale2pmu_disable_event,
 	.read_counter	= xscale2pmu_read_counter,
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 014f090..a9582f9 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -154,6 +154,9 @@
 	/* Push out any further dirty data, and ensure cache is empty */
 	flush_cache_all();
 
+	/* Push out the dirty data from external caches */
+	outer_disable();
+
 	/* Switch to the identity mapping. */
 	phys_reset = (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset);
 	phys_reset((unsigned long)addr);
@@ -218,7 +221,8 @@
  * This is our default idle handler.
  */
 
-void (*arm_pm_idle)(void);
+extern void arch_idle(void);
+void (*arm_pm_idle)(void) = arch_idle;
 
 static void default_idle(void)
 {
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index ebfac78..e30f1d8 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -103,6 +103,8 @@
 unsigned int elf_hwcap __read_mostly;
 EXPORT_SYMBOL(elf_hwcap);
 
+unsigned int boot_reason;
+EXPORT_SYMBOL(boot_reason);
 
 #ifdef MULTI_CPU
 struct processor processor __read_mostly;
@@ -959,6 +961,9 @@
 
 	parse_early_param();
 
+	if (mdesc->init_very_early)
+		mdesc->init_very_early();
+
 	sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank[0]), meminfo_cmp, NULL);
 	sanity_check_meminfo();
 	arm_memblock_init(&meminfo, mdesc);
@@ -1054,7 +1059,7 @@
 		   cpu_name, read_cpuid_id() & 15, elf_platform);
 
 #if defined(CONFIG_SMP)
-	for_each_online_cpu(i) {
+	for_each_present_cpu(i) {
 		/*
 		 * glibc reads /proc/cpuinfo to determine the number of
 		 * online processors, looking for lines beginning with
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index f30d683..4738d71 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -51,6 +51,7 @@
 struct secondary_data secondary_data;
 
 enum ipi_msg_type {
+	IPI_CPU_START = 1,
 	IPI_TIMER = 2,
 	IPI_RESCHEDULE,
 	IPI_CALL_FUNC,
@@ -183,7 +184,7 @@
 		pr_err("CPU%u: cpu didn't die\n", cpu);
 		return;
 	}
-	printk(KERN_NOTICE "CPU%u: shutdown\n", cpu);
+	pr_debug("CPU%u: shutdown\n", cpu);
 
 	if (!platform_cpu_kill(cpu))
 		printk("CPU%u: unable to kill\n", cpu);
@@ -241,8 +242,6 @@
 	store_cpu_topology(cpuid);
 }
 
-static void percpu_timer_setup(void);
-
 /*
  * This is the secondary CPU boot entry.  We're using this CPUs
  * idle thread stack, but a set of temporary page tables.
@@ -263,7 +262,7 @@
 	enter_lazy_tlb(mm, current);
 	local_flush_tlb_all();
 
-	printk("CPU%u: Booted secondary processor\n", cpu);
+	pr_debug("CPU%u: Booted secondary processor\n", cpu);
 
 	cpu_init();
 	preempt_disable();
@@ -378,7 +377,8 @@
 }
 
 static const char *ipi_types[NR_IPI] = {
-#define S(x,s)	[x - IPI_TIMER] = s
+#define S(x,s)	[x - IPI_CPU_START] = s
+	S(IPI_CPU_START, "CPU start interrupts"),
 	S(IPI_TIMER, "Timer broadcast interrupts"),
 	S(IPI_RESCHEDULE, "Rescheduling interrupts"),
 	S(IPI_CALL_FUNC, "Function call interrupts"),
@@ -464,7 +464,7 @@
 }
 #endif
 
-static void __cpuinit percpu_timer_setup(void)
+void __cpuinit percpu_timer_setup(void)
 {
 	unsigned int cpu = smp_processor_id();
 	struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu);
@@ -581,10 +581,13 @@
 	unsigned int cpu = smp_processor_id();
 	struct pt_regs *old_regs = set_irq_regs(regs);
 
-	if (ipinr >= IPI_TIMER && ipinr < IPI_TIMER + NR_IPI)
-		__inc_irq_stat(cpu, ipi_irqs[ipinr - IPI_TIMER]);
+	if (ipinr >= IPI_CPU_START && ipinr < IPI_CPU_START + NR_IPI)
+		__inc_irq_stat(cpu, ipi_irqs[ipinr - IPI_CPU_START]);
 
 	switch (ipinr) {
+	case IPI_CPU_START:
+		/* Wake up from WFI/WFE using SGI */
+		break;
 	case IPI_TIMER:
 		irq_enter();
 		ipi_timer();
diff --git a/arch/arm/kernel/swp_emulate.c b/arch/arm/kernel/swp_emulate.c
index df74518..5d14485 100644
--- a/arch/arm/kernel/swp_emulate.c
+++ b/arch/arm/kernel/swp_emulate.c
@@ -174,6 +174,57 @@
 	return res;
 }
 
+static int check_condition(struct pt_regs *regs, unsigned int insn)
+{
+	unsigned int base_cond, neg, cond = 0;
+	unsigned int cpsr_z, cpsr_c, cpsr_n, cpsr_v;
+
+	cpsr_n = (regs->ARM_cpsr & PSR_N_BIT) ? 1 : 0;
+	cpsr_z = (regs->ARM_cpsr & PSR_Z_BIT) ? 1 : 0;
+	cpsr_c = (regs->ARM_cpsr & PSR_C_BIT) ? 1 : 0;
+	cpsr_v = (regs->ARM_cpsr & PSR_V_BIT) ? 1 : 0;
+
+	/* Upper 3 bits indicate condition, lower bit incicates negation */
+	base_cond = insn >> 29;
+	neg = insn & BIT(28) ? 1 : 0;
+
+	switch (base_cond) {
+	case 0x0:	/* equal */
+		cond = cpsr_z;
+		break;
+
+	case 0x1:	/* carry set */
+		cond = cpsr_c;
+		break;
+
+	case 0x2:	/* minus / negative */
+		cond = cpsr_n;
+		break;
+
+	case 0x3:	/* overflow */
+		cond = cpsr_v;
+		break;
+
+	case 0x4:	/* unsigned higher */
+		cond = (cpsr_c == 1) && (cpsr_z == 0);
+		break;
+
+	case 0x5:	/* signed greater / equal */
+		cond = (cpsr_n == cpsr_v);
+		break;
+
+	case 0x6:	/* signed greater */
+		cond = (cpsr_z == 0) && (cpsr_n == cpsr_v);
+		break;
+
+	case 0x7:	/* always */
+		cond = 1;
+		break;
+	};
+
+	return cond && !neg;
+}
+
 /*
  * swp_handler logs the id of calling process, dissects the instruction, sanity
  * checks the memory location, calls emulate_swpX for the actual operation and
@@ -207,6 +258,12 @@
 		previous_pid = current->pid;
 	}
 
+	/* Ignore the instruction if it fails its condition code check */
+	if (!check_condition(regs, instr)) {
+		regs->ARM_pc += 4;
+		return 0;
+	}
+
 	address = regs->uregs[EXTRACT_REG_NUM(instr, RN_OFFSET)];
 	data	= regs->uregs[EXTRACT_REG_NUM(instr, RT2_OFFSET)];
 	destreg = EXTRACT_REG_NUM(instr, RT_OFFSET);
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index 43a31fb..89f7f23 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -8,7 +8,10 @@
 #include <asm/thread_info.h>
 #include <asm/memory.h>
 #include <asm/page.h>
-	
+#ifdef CONFIG_STRICT_MEMORY_RWX
+#include <asm/pgtable.h>
+#endif
+
 #define PROC_INFO							\
 	. = ALIGN(4);							\
 	VMLINUX_SYMBOL(__proc_info_begin) = .;				\
@@ -90,6 +93,7 @@
 		_text = .;
 		HEAD_TEXT
 	}
+
 	.text : {			/* Real text segment		*/
 		_stext = .;		/* Text and read-only data	*/
 			__exception_text_start = .;
@@ -111,6 +115,9 @@
 		*(.got)			/* Global offset table		*/
 			ARM_CPU_KEEP(PROC_INFO)
 	}
+#ifdef CONFIG_STRICT_MEMORY_RWX
+	. = ALIGN(1<<SECTION_SHIFT);
+#endif
 
 	RO_DATA(PAGE_SIZE)
 
@@ -134,7 +141,11 @@
 	_etext = .;			/* End of text and rodata section */
 
 #ifndef CONFIG_XIP_KERNEL
+#ifdef CONFIG_STRICT_MEMORY_RWX
+	. = ALIGN(1<<SECTION_SHIFT);
+#else
 	. = ALIGN(PAGE_SIZE);
+#endif
 	__init_begin = .;
 #endif
 
@@ -178,6 +189,10 @@
 		INIT_RAM_FS
 	}
 #ifndef CONFIG_XIP_KERNEL
+#ifdef CONFIG_STRICT_MEMORY_RWX
+	. = ALIGN(1<<SECTION_SHIFT);
+#endif
+	__init_data = .;
 	.exit.data : {
 		ARM_EXIT_KEEP(EXIT_DATA)
 	}
@@ -220,7 +235,7 @@
 		/*
 		 * The exception fixup table (might need resorting at runtime)
 		 */
-		. = ALIGN(4);
+		. = ALIGN(L1_CACHE_BYTES);
 		__start___ex_table = .;
 #ifdef CONFIG_MMU
 		*(__ex_table)
diff --git a/arch/arm/lib/delay.S b/arch/arm/lib/delay.S
deleted file mode 100644
index 3c9a05c..0000000
--- a/arch/arm/lib/delay.S
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- *  linux/arch/arm/lib/delay.S
- *
- *  Copyright (C) 1995, 1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/linkage.h>
-#include <asm/assembler.h>
-#include <asm/param.h>
-		.text
-
-.LC0:		.word	loops_per_jiffy
-.LC1:		.word	(2199023*HZ)>>11
-
-/*
- * r0  <= 2000
- * lpj <= 0x01ffffff (max. 3355 bogomips)
- * HZ  <= 1000
- */
-
-ENTRY(__udelay)
-		ldr	r2, .LC1
-		mul	r0, r2, r0
-ENTRY(__const_udelay)				@ 0 <= r0 <= 0x7fffff06
-		mov	r1, #-1
-		ldr	r2, .LC0
-		ldr	r2, [r2]		@ max = 0x01ffffff
-		add	r0, r0, r1, lsr #32-14
-		mov	r0, r0, lsr #14		@ max = 0x0001ffff
-		add	r2, r2, r1, lsr #32-10
-		mov	r2, r2, lsr #10		@ max = 0x00007fff
-		mul	r0, r2, r0		@ max = 2^32-1
-		add	r0, r0, r1, lsr #32-6
-		movs	r0, r0, lsr #6
-		moveq	pc, lr
-
-/*
- * loops = r0 * HZ * loops_per_jiffy / 1000000
- *
- * Oh, if only we had a cycle counter...
- */
-
-@ Delay routine
-ENTRY(__delay)
-		subs	r0, r0, #1
-#if 0
-		movls	pc, lr
-		subs	r0, r0, #1
-		movls	pc, lr
-		subs	r0, r0, #1
-		movls	pc, lr
-		subs	r0, r0, #1
-		movls	pc, lr
-		subs	r0, r0, #1
-		movls	pc, lr
-		subs	r0, r0, #1
-		movls	pc, lr
-		subs	r0, r0, #1
-		movls	pc, lr
-		subs	r0, r0, #1
-#endif
-		bhi	__delay
-		mov	pc, lr
-ENDPROC(__udelay)
-ENDPROC(__const_udelay)
-ENDPROC(__delay)
diff --git a/arch/arm/lib/delay.c b/arch/arm/lib/delay.c
new file mode 100644
index 0000000..fc9a37c
--- /dev/null
+++ b/arch/arm/lib/delay.c
@@ -0,0 +1,90 @@
+/*
+ *  Originally from linux/arch/arm/lib/delay.S
+ *
+ *  Copyright (C) 1995, 1996 Russell King
+ *  Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *  Copyright (C) 1993 Linus Torvalds
+ *  Copyright (C) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *  Copyright (C) 2005-2006 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/timex.h>
+
+/*
+ * Oh, if only we had a cycle counter...
+ */
+void delay_loop(unsigned long loops)
+{
+	asm volatile(
+	"1:	subs %0, %0, #1 \n"
+	"	bhi 1b		\n"
+	: /* No output */
+	: "r" (loops)
+	);
+}
+
+#ifdef ARCH_HAS_READ_CURRENT_TIMER
+/*
+ * Assuming read_current_timer() is monotonically increasing
+ * across calls.
+ */
+void read_current_timer_delay_loop(unsigned long loops)
+{
+	unsigned long bclock, now;
+
+	read_current_timer(&bclock);
+	do {
+		read_current_timer(&now);
+	} while ((now - bclock) < loops);
+}
+#endif
+
+static void (*delay_fn)(unsigned long) = delay_loop;
+
+void set_delay_fn(void (*fn)(unsigned long))
+{
+	delay_fn = fn;
+}
+
+/*
+ * loops = usecs * HZ * loops_per_jiffy / 1000000
+ */
+void __delay(unsigned long loops)
+{
+	delay_fn(loops);
+}
+EXPORT_SYMBOL(__delay);
+
+/*
+ * 0 <= xloops <= 0x7fffff06
+ * loops_per_jiffy <= 0x01ffffff (max. 3355 bogomips)
+ */
+void __const_udelay(unsigned long xloops)
+{
+	unsigned long lpj;
+	unsigned long loops;
+
+	xloops >>= 14;			/* max = 0x01ffffff */
+	lpj = loops_per_jiffy >> 10;	/* max = 0x0001ffff */
+	loops = lpj * xloops;		/* max = 0x00007fff */
+	loops >>= 6;			/* max = 2^32-1 */
+
+	if (loops)
+		__delay(loops);
+}
+EXPORT_SYMBOL(__const_udelay);
+
+/*
+ * usecs  <= 2000
+ * HZ  <= 1000
+ */
+void __udelay(unsigned long usecs)
+{
+	__const_udelay(usecs * ((2199023UL*HZ)>>11));
+}
+EXPORT_SYMBOL(__udelay);
diff --git a/arch/arm/lib/lib1funcs.S b/arch/arm/lib/lib1funcs.S
index c562f64..63b75df 100644
--- a/arch/arm/lib/lib1funcs.S
+++ b/arch/arm/lib/lib1funcs.S
@@ -351,7 +351,7 @@
 
 #endif
 
-Ldiv0:
+ENTRY(Ldiv0)
 UNWIND(.fnstart)
 UNWIND(.pad #4)
 UNWIND(.save {lr})
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 1cd40ad..cbdb51a 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -1,141 +1,714 @@
 if ARCH_MSM
 
-choice
-	prompt "Qualcomm MSM SoC Type"
-	default ARCH_MSM7X00A
+menu "MSM SoC Type"
 
-config ARCH_MSM7X00A
+config ARCH_MSM7X01A
 	bool "MSM7x00A / MSM7x01A"
-	select MACH_TROUT if !MACH_HALIBUT
 	select ARCH_MSM_ARM11
-	select MSM_SMD
-	select MSM_SMD_PKG3
+	select MSM_VIC
 	select CPU_V6
 	select GPIO_MSM_V1
-	select MSM_PROC_COMM
+	select MSM_REMOTE_SPINLOCK_SWP
+
+config ARCH_MSM7X25
+	bool "MSM7x25"
+	select ARCH_MSM_ARM11
+	select MSM_VIC
+	select CPU_V6
+	select GPIO_MSM_V1
+	select MSM_REMOTE_SPINLOCK_SWP
+	select MULTI_IRQ_HANDLER
+
+config ARCH_MSM7X27
+	bool "MSM7x27"
+	select ARCH_MSM_ARM11 if MSM_SOC_REV_NONE
+	select ARCH_HAS_BARRIERS if MSM_SOC_REV_NONE
+	select ARCH_MSM_CORTEX_A5 if MSM_SOC_REV_A
+	select MSM_VIC
+	select CPU_V6 if MSM_SOC_REV_NONE
+	select CPU_V7 if MSM_SOC_REV_A
+	select GPIO_MSM_V1
+	select MSM_REMOTE_SPINLOCK_SWP if MSM_SOC_REV_NONE
+	select MSM_GPIOMUX
+	select REGULATOR
+	select MULTI_IRQ_HANDLER
+	select MSM_PROC_COMM_REGULATOR
+	select CLEANCACHE
+	select QCACHE
+	select MSM_PM2 if PM
+	select MSM_RUN_QUEUE_STATS if MSM_SOC_REV_A
+	select DONT_MAP_HOLE_AFTER_MEMBANK0
 
 config ARCH_MSM7X30
 	bool "MSM7x30"
-	select MACH_MSM7X30_SURF # if !
 	select ARCH_MSM_SCORPION
-	select MSM_SMD
 	select MSM_VIC
 	select CPU_V7
-	select MSM_GPIOMUX
 	select GPIO_MSM_V1
-	select MSM_PROC_COMM
+	select MSM_REMOTE_SPINLOCK_DEKKERS
+	select ARCH_SPARSEMEM_ENABLE
+	select ARCH_HAS_HOLES_MEMORYMODEL
+	select MEMORY_HOTPLUG
+	select MEMORY_HOTREMOVE
+	select ARCH_ENABLE_MEMORY_HOTPLUG
+	select ARCH_ENABLE_MEMORY_HOTREMOVE
+	select MIGRATION
+	select ARCH_MEMORY_PROBE
+	select ARCH_MEMORY_REMOVE
+	select MSM_GPIOMUX
+	select RESERVE_FIRST_PAGE
+	select MSM_DALRPC
+	select MSM_SPM_V1
+	select REGULATOR
+	select MSM_PROC_COMM_REGULATOR
+	select MULTI_IRQ_HANDLER
+	select MSM_PM2 if PM
 
 config ARCH_QSD8X50
 	bool "QSD8X50"
-	select MACH_QSD8X50_SURF if !MACH_QSD8X50A_ST1_5
 	select ARCH_MSM_SCORPION
-	select MSM_SMD
 	select MSM_VIC
 	select CPU_V7
-	select MSM_GPIOMUX
 	select GPIO_MSM_V1
-	select MSM_PROC_COMM
+	select MSM_REMOTE_SPINLOCK_LDREX
+	select CPU_USE_DOMAINS
+	select EMULATE_DOMAIN_MANAGER_V7
+	select MSM_GPIOMUX
+	select MSM_DALRPC
+	select MSM_PM2 if PM
 
 config ARCH_MSM8X60
 	bool "MSM8X60"
-	select MACH_MSM8X60_SURF if (!MACH_MSM8X60_RUMI3 && !MACH_MSM8X60_SIM \
-				  && !MACH_MSM8X60_FFA)
 	select ARCH_MSM_SCORPIONMP
+	select SMP_PARALLEL_START if SMP
 	select ARM_GIC
 	select CPU_V7
-	select MSM_V2_TLMM
+	select MSM_REMOTE_SPINLOCK_LDREX
+	select ARCH_REQUIRE_GPIOLIB
+	select MSM_ADM3
+	select REGULATOR
+	select MSM_RPM_REGULATOR
 	select GPIO_MSM_V2
+	select MSM_PIL
+	select ARCH_HAS_CPU_IDLE_WAIT
+	select MSM_DIRECT_SCLK_ACCESS
+	select MSM_RPM
+	select MSM_XO
 	select MSM_GPIOMUX
+	select MSM_BUS_SCALING
+	select MSM_SECURE_IO
+	select MSM_DALRPC
+	select MSM_QDSP6_APR
+	select MSM_QDSP6_CODECS
+	select MSM_NATIVE_RESTART
+	select ARCH_INLINE_SPIN_TRYLOCK
+	select ARCH_INLINE_SPIN_TRYLOCK_BH
+	select ARCH_INLINE_SPIN_LOCK
+	select ARCH_INLINE_SPIN_LOCK_BH
+	select ARCH_INLINE_SPIN_LOCK_IRQ
+	select ARCH_INLINE_SPIN_LOCK_IRQSAVE
+	select ARCH_INLINE_SPIN_UNLOCK
+	select ARCH_INLINE_SPIN_UNLOCK_BH
+	select ARCH_INLINE_SPIN_UNLOCK_IRQ
+	select ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE
+	select ARCH_INLINE_READ_TRYLOCK
+	select ARCH_INLINE_READ_LOCK
+	select ARCH_INLINE_READ_LOCK_BH
+	select ARCH_INLINE_READ_LOCK_IRQ
+	select ARCH_INLINE_READ_LOCK_IRQSAVE
+	select ARCH_INLINE_READ_UNLOCK
+	select ARCH_INLINE_READ_UNLOCK_BH
+	select ARCH_INLINE_READ_UNLOCK_IRQ
+	select ARCH_INLINE_READ_UNLOCK_IRQRESTORE
+	select ARCH_INLINE_WRITE_TRYLOCK
+	select ARCH_INLINE_WRITE_LOCK
+	select ARCH_INLINE_WRITE_LOCK_BH
+	select ARCH_INLINE_WRITE_LOCK_IRQ
+	select ARCH_INLINE_WRITE_LOCK_IRQSAVE
+	select ARCH_INLINE_WRITE_UNLOCK
+	select ARCH_INLINE_WRITE_UNLOCK_BH
+	select ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE
+	select CPU_HAS_L2_PMU
+	select MSM_SPM_V1
 	select MSM_SCM if SMP
+	select MULTI_IRQ_HANDLER
+	select MSM_MULTIMEDIA_USE_ION
+	select MSM_PM8X60 if PM
+	select MSM_RUN_QUEUE_STATS
 
 config ARCH_MSM8960
 	bool "MSM8960"
-	select ARCH_MSM_SCORPIONMP
-	select MACH_MSM8960_SIM if (!MACH_MSM8960_RUMI3)
+	select ARCH_MSM_KRAITMP
 	select ARM_GIC
 	select CPU_V7
-	select MSM_V2_TLMM
+	select GPIO_MSM_V2
 	select MSM_GPIOMUX
 	select MSM_SCM if SMP
+	select MSM_DIRECT_SCLK_ACCESS
+	select REGULATOR
+	select MSM_RPM_REGULATOR
+	select MSM_RPM
+	select MSM_XO
+	select MSM_QDSP6_APR
+	select MSM_QDSP6_CODECS
+	select MSM_PIL
+	select MSM_AUDIO_QDSP6 if SND_SOC
+	select CPU_HAS_L2_PMU
+	select MSM_SPM_V2
+	select MSM_L2_SPM
+	select MSM_NATIVE_RESTART
+	select DONT_MAP_HOLE_AFTER_MEMBANK0
+	select MSM_REMOTE_SPINLOCK_SFPB
+	select ARCH_SPARSEMEM_ENABLE
+	select ARCH_HAS_HOLES_MEMORYMODEL
+	select CLEANCACHE
+	select QCACHE
+	select MSM_MULTIMEDIA_USE_ION
+	select MULTI_IRQ_HANDLER
+	select MSM_PM8X60 if PM
+	select HOLES_IN_ZONE if SPARSEMEM
+	select MSM_RUN_QUEUE_STATS
 
+config ARCH_MSM8930
+	bool "MSM8930"
+	select ARCH_MSM_KRAITMP
+	select ARM_GIC
+	select CPU_V7
+	select GPIO_MSM_V2
+	select MSM_GPIOMUX
+	select MSM_SCM if SMP
+	select MSM_DIRECT_SCLK_ACCESS
+	select REGULATOR
+	select MSM_RPM_REGULATOR
+	select MSM_RPM
+	select MSM_XO
+	select MSM_QDSP6_APR
+	select MSM_QDSP6_CODECS
+	select MSM_PIL
+	select MSM_AUDIO_QDSP6 if SND_SOC
+	select CPU_HAS_L2_PMU
+	select MSM_SPM_V2
+	select MSM_L2_SPM
+	select MSM_NATIVE_RESTART
+	select DONT_MAP_HOLE_AFTER_MEMBANK0
+	select MSM_REMOTE_SPINLOCK_SFPB
+	select ARCH_SPARSEMEM_ENABLE
+	select ARCH_HAS_HOLES_MEMORYMODEL
+	select MSM_ULTRASOUND
+	select MULTI_IRQ_HANDLER
+	select MSM_PM8X60 if PM
+	select HOLES_IN_ZONE if SPARSEMEM
+
+config ARCH_APQ8064
+	bool "APQ8064"
+	select ARCH_MSM_KRAITMP
+	select GPIO_MSM_V2
+	select ARM_GIC
+	select CPU_V7
+	select MSM_SCM if SMP
+	select MSM_GPIOMUX
+	select MSM_REMOTE_SPINLOCK_SFPB
+	select MSM_PIL
+	select MSM_QDSP6_APR
+	select MSM_QDSP6_CODECS
+	select MSM_AUDIO_QDSP6 if SND_SOC
+	select MULTI_IRQ_HANDLER
+	select MSM_RPM
+	select MSM_SPM_V2
+	select MSM_L2_SPM
+	select MSM_PM8X60 if PM
+	select CPU_HAS_L2_PMU
+	select HOLES_IN_ZONE if SPARSEMEM
+	select CLEANCACHE
+	select QCACHE
+	select MIGHT_HAVE_PCI
+	select ARCH_SUPPORTS_MSI
+
+config ARCH_MSMCOPPER
+	bool "MSM Copper"
+	select ARCH_MSM_KRAITMP
+	select GPIO_MSM_V2
+	select ARM_GIC
+	select CPU_V7
+	select MSM_SCM if SMP
+	select MSM_GPIOMUX
+	select MULTI_IRQ_HANDLER
+	select MSM_MULTIMEDIA_USE_ION
+	select MSM_PIL
+	select MSM_SPM_V2
+	select MSM_L2_SPM
+	select MSM_PM8X60 if PM
+	select MAY_HAVE_SPARSE_IRQ
+	select SPARSE_IRQ
+	select MSM_RPM_SMD
+	select REGULATOR
+
+config ARCH_FSM9XXX
+	bool "FSM9XXX"
+	select ARCH_MSM_SCORPION
+	select MSM_VIC
+	select CPU_V7
+	select MSM_REMOTE_SPINLOCK_LDREX
+	select GPIO_FSM9XXX
+	select MULTI_IRQ_HANDLER
+	select MSM_DALRPC
+
+config ARCH_MSM9615
+	bool "MSM9615"
+	select ARM_GIC
+	select GIC_SECURE
+	select ARCH_MSM_CORTEX_A5
+	select CPU_V7
+	select GPIO_MSM_V2
+	select MSM_GPIOMUX
+	select MSM_RPM
+	select MSM_SPM_V2
+	select MSM_NATIVE_RESTART
+	select REGULATOR
+	select MSM_RPM_REGULATOR
+	select MULTI_IRQ_HANDLER
+	select MSM_PM8X60 if PM
+	select MSM_XO
+	select MSM_MULTIMEDIA_USE_ION
+	select MSM_QDSP6_APR
+	select MSM_AUDIO_QDSP6 if SND_SOC
+	select FIQ
+
+config ARCH_MSM8625
+	bool "MSM8625"
+	select ARCH_MSM_CORTEX_A5
+	select CPU_V7
+	select GPIO_MSM_V1
+	select MSM_GPIOMUX
+	select ARM_GIC
+	select ARCH_MSM_CORTEXMP
+	select MULTI_IRQ_HANDLER
+	select ARM_TICKET_LOCKS
+	select MSM_RUN_QUEUE_STATS
+
+config ARCH_MSM9625
+	bool "MSM9625"
+	select ARM_GIC
+	select GIC_SECURE
+	select ARCH_MSM_CORTEX_A5
+	select SMP
+	select MSM_SMP
+	select CPU_V7
+	select MSM_GPIOMUX
+	select MULTI_IRQ_HANDLER
+	select GPIO_MSM_V2
+
+endmenu
+
+choice
+	prompt "MSM SoC Revision"
+	default MSM_SOC_REV_NONE
+config MSM_SOC_REV_NONE
+	bool "N/A"
+	select EMULATE_DOMAIN_MANAGER_V7 if ARCH_QSD8X50
+	select VERIFY_PERMISSION_FAULT if ARCH_QSD8X50
+config MSM_SOC_REV_A
+	bool "Rev. A"
+	select ARCH_MSM7X27A if ARCH_MSM7X27
 endchoice
 
-config MSM_HAS_DEBUG_UART_HS
-	bool
+config MSM_KRAIT_TBB_ABORT_HANDLER
+	bool "Krait TBB/TBH data abort handler"
+	depends on ARCH_MSM_KRAIT
+	depends on ARM_THUMB
+	help
+	  Certain early samples of the Krait processor may generate data
+	  aborts for TBB / TBH instructions that fail their condition code
+	  checks. Enabling this option will ignore these erroneous data aborts,
+	  at the expense of a very small performance penalty.
 
-config MSM_SOC_REV_A
-	bool
-config  ARCH_MSM_SCORPIONMP
-	bool
-	select HAVE_SMP
+	  If unsure, say N.
 
 config  ARCH_MSM_ARM11
 	bool
+
 config  ARCH_MSM_SCORPION
 	bool
 
+config  ARCH_MSM_KRAIT
+	bool
+	select ARM_L1_CACHE_SHIFT_6
+
+config  MSM_SMP
+	select HAVE_SMP
+	bool
+
+config  ARCH_MSM_SCORPIONMP
+	select ARCH_MSM_SCORPION
+	select MSM_SMP
+	select HAVE_ARCH_HAS_CURRENT_TIMER
+	bool
+
+config  ARCH_MSM_KRAITMP
+	select ARCH_MSM_KRAIT
+	select MSM_SMP
+	select HAVE_ARCH_HAS_CURRENT_TIMER
+	bool
+	select HAVE_HW_BRKPT_RESERVED_RW_ACCESS
+
+config  ARCH_MSM_CORTEXMP
+	select MSM_SMP
+	bool
+
+config  ARCH_MSM_CORTEX_A5
+	bool
+	select HAVE_HW_BRKPT_RESERVED_RW_ACCESS
+
+config ARCH_MSM7X27A
+	bool
+	select MSM_DALRPC
+	select MSM_PROC_COMM_REGULATOR
+	select MULTI_IRQ_HANDLER
+	select ARM_GIC
+	select ARCH_MSM_CORTEXMP
+
 config  MSM_VIC
 	bool
 
-menu "Qualcomm MSM Board Type"
+config MSM_RPM
+	bool "Resource Power Manager"
+	select MSM_MPM
+
+config MSM_RPM_SMD
+	depends on MSM_SMD
+	bool "Support for using SMD as the transport layer for communicatons with RPM"
+
+config MSM_MPM
+	bool "Modem Power Manager"
+
+config MSM_XO
+	bool
+
+config MSM_REMOTE_SPINLOCK_DEKKERS
+	bool
+config MSM_REMOTE_SPINLOCK_SWP
+	bool
+config MSM_REMOTE_SPINLOCK_LDREX
+	bool
+config MSM_REMOTE_SPINLOCK_SFPB
+	bool
+config MSM_ADM3
+	bool
+
+menu "MSM Board Selection"
 
 config MACH_HALIBUT
-	depends on ARCH_MSM
-	depends on ARCH_MSM7X00A
+	depends on ARCH_MSM7X01A
+	depends on MSM_STACKED_MEMORY
+	default y
 	bool "Halibut Board (QCT SURF7201A)"
 	help
 	  Support for the Qualcomm SURF7201A eval board.
 
-config MACH_TROUT
-	depends on ARCH_MSM
-	depends on ARCH_MSM7X00A
-	bool "HTC Dream (aka trout)"
+config MACH_MSM7201A_SURF
+	depends on ARCH_MSM7X01A
+	depends on MSM_STACKED_MEMORY
+	default y
+	bool "MSM7201A SURF"
 	help
-	  Support for the HTC Dream, T-Mobile G1, Android ADP1 devices.
+	  Support for the Qualcomm MSM7201A SURF eval board.
+
+config MACH_MSM7201A_FFA
+	depends on ARCH_MSM7X01A
+	depends on MSM_STACKED_MEMORY
+	default y
+	bool "MSM7201A FFA"
+	help
+	  Support for the Qualcomm MSM7201A FFA eval board.
+
+config MACH_TROUT
+	depends on ARCH_MSM7X01A
+	depends on MSM_STACKED_MEMORY
+	default y
+	bool "Trout"
+
+config MACH_MSM7X27_SURF
+	depends on ARCH_MSM7X27
+	depends on !MSM_STACKED_MEMORY
+	default y
+	bool "MSM7x27 SURF"
+	help
+	  Support for the Qualcomm MSM7x27 SURF eval board.
+
+config MACH_MSM7X27_FFA
+	depends on ARCH_MSM7X27
+	depends on !MSM_STACKED_MEMORY
+	default y
+	bool "MSM7x27 FFA"
+	help
+	  Support for the Qualcomm MSM7x27 FFA eval board.
+
+config MACH_MSM7X27A_RUMI3
+        depends on ARCH_MSM7X27A
+        depends on !MSM_STACKED_MEMORY
+        default y
+        bool "MSM7x27A RUMI3"
+        help
+          Support for the Qualcomm MSM7x27A RUMI3 Emulation Platform.
+
+config MACH_MSM7X27A_SURF
+        depends on ARCH_MSM7X27A
+        depends on !MSM_STACKED_MEMORY
+        default y
+        bool "MSM7x27A SURF"
+        help
+          Support for the Qualcomm MSM7x27A SURF.
+
+config MACH_MSM7X27A_FFA
+        depends on ARCH_MSM7X27A
+        depends on !MSM_STACKED_MEMORY
+        default y
+        bool "MSM7x27A FFA"
+        help
+          Support for the Qualcomm MSM7x27A FFA.
+
+config MACH_MSM7625A_SURF
+        depends on ARCH_MSM7X27A
+        depends on !MSM_STACKED_MEMORY
+        default y
+        bool "MSM7625A SURF"
+        help
+          Support for the Qualcomm MSM7625A SURF.
+
+config MACH_MSM7625A_FFA
+        depends on ARCH_MSM7X27A
+        depends on !MSM_STACKED_MEMORY
+        default y
+        bool "MSM7625A FFA"
+        help
+          Support for the Qualcomm MSM7625A FFA.
+
+config MACH_MSM7627A_QRD1
+        depends on ARCH_MSM7X27A
+        depends on !MSM_STACKED_MEMORY
+        default y
+        bool "MSM7627A QRD1"
+        help
+          Support for the Qualcomm MSM7627A Reference Design.
+
+config MACH_MSM7627A_QRD3
+        depends on ARCH_MSM7X27A
+        depends on !MSM_STACKED_MEMORY
+        default y
+        bool "MSM7627A QRD3"
+        help
+          Support for the Qualcomm MSM7627A Reference Design.
+
+config MACH_MSM7627A_EVB
+        depends on ARCH_MSM7X27A
+        depends on !MSM_STACKED_MEMORY
+        default y
+        bool "MSM7627A EVB"
+        help
+          Support for the Qualcomm MSM7627A Reference Design.
+
+config MACH_MSM8625_RUMI3
+	depends on ARCH_MSM8625
+	depends on !MSM_STACKED_MEMORY
+	default y
+	bool "MSM8625 RUMI3"
+	help
+	  Support for the Qualcomm MSM8625 RUMI3 Emulation Platform.
+
+config MACH_MSM8625_SURF
+	depends on ARCH_MSM8625
+	depends on !MSM_STACKED_MEMORY
+	default y
+	bool "MSM8625 SURF"
+	help
+	  Support for the Qualcomm MSM8625 SURF.
+
+config MACH_MSM8625_FFA
+	depends on ARCH_MSM8625
+	depends on !MSM_STACKED_MEMORY
+	default y
+	bool "MSM8625 FFA"
+	help
+	  Support for the Qualcomm MSM8625 FFA.
+
+config MACH_MSM8625_EVB
+	depends on ARCH_MSM8625
+	depends on !MSM_STACKED_MEMORY
+	default y
+	bool "MSM8625 EVB"
+	help
+	  Support for the Qualcomm MSM8625 Reference Design.
+
+config MACH_MSM8625_QRD7
+	depends on ARCH_MSM8625
+	depends on !MSM_STACKED_MEMORY
+	default y
+	bool "MSM8625 QRD7"
+	help
+	  Support for the Qualcomm MSM8625 Reference Design.
+
+config MACH_MSM8625_EVT
+	depends on ARCH_MSM8625
+	depends on !MSM_STACKED_MEMORY
+	default y
+	bool "MSM8625 EVT"
+	help
+	  Support for the Qualcomm MSM8625 Reference Design.
 
 config MACH_MSM7X30_SURF
-	depends on ARCH_MSM7X30
-	bool "MSM7x30 SURF"
-	help
-	  Support for the Qualcomm MSM7x30 SURF eval board.
+       depends on ARCH_MSM7X30
+       depends on !MSM_STACKED_MEMORY
+       default y
+       bool "MSM7x30 SURF"
+       help
+         Support for the Qualcomm MSM7x30 SURF eval board.
+
+config MACH_MSM7X30_FFA
+       depends on ARCH_MSM7X30
+       depends on !MSM_STACKED_MEMORY
+       default y
+       bool "MSM7x30 FFA"
+       help
+         Support for the Qualcomm MSM7x30 FFA eval board.
+
+config MACH_MSM7X30_FLUID
+       depends on ARCH_MSM7X30
+       depends on !MSM_STACKED_MEMORY
+       default y
+       bool "MSM7x30 FLUID"
+       help
+         Support for the Qualcomm MSM7x30 FLUID eval board.
+
+config MACH_SAPPHIRE
+	depends on ARCH_MSM7X01A
+	default n
+	bool "Sapphire"
 
 config MACH_QSD8X50_SURF
 	depends on ARCH_QSD8X50
+	depends on MSM_SOC_REV_NONE
+	depends on MSM_STACKED_MEMORY
+	default y
 	bool "QSD8x50 SURF"
 	help
 	  Support for the Qualcomm QSD8x50 SURF eval board.
 
-config MACH_QSD8X50A_ST1_5
+config MACH_QSD8X50_FFA
 	depends on ARCH_QSD8X50
-	select MSM_SOC_REV_A
-	bool "QSD8x50A ST1.5"
+	depends on MSM_SOC_REV_NONE
+	depends on MSM_STACKED_MEMORY
+	default y
+	bool "QSD8x50 FFA"
 	help
-	  Support for the Qualcomm ST1.5.
+	  Support for the Qualcomm QSD8x50 FFA eval board.
+
+config MACH_MSM7X25_SURF
+	depends on ARCH_MSM7X25
+	depends on !MSM_STACKED_MEMORY
+	default y
+	bool "MSM7x25 SURF"
+	help
+	  Support for the Qualcomm MSM7x25 SURF eval board.
+
+config MACH_MSM7X25_FFA
+	depends on ARCH_MSM7X25
+	depends on !MSM_STACKED_MEMORY
+	default y
+	bool "MSM7x25 FFA"
+	help
+	  Support for the Qualcomm MSM7x25 FFA eval board.
+
+config MACH_MSM8X55_SURF
+       depends on ARCH_MSM7X30
+       depends on !MSM_STACKED_MEMORY
+       default y
+       bool "MSM8X55 SURF"
+       help
+         Support for the Qualcomm MSM8x55 SURF eval board.
+
+config MACH_MSM8X55_FFA
+       depends on ARCH_MSM7X30
+       depends on !MSM_STACKED_MEMORY
+       default y
+       bool "MSM8X55 FFA"
+       help
+         Support for the Qualcomm MSM8x55 FFA eval board.
+
+config MACH_MSM8X55_SVLTE_FFA
+       depends on ARCH_MSM7X30
+       depends on !MSM_STACKED_MEMORY
+       default y
+       bool "MSM8X55 SVLTE FFA"
+       help
+         Support for the Qualcomm MSM8x55 SVLTE FFA eval board.
+
+config MACH_MSM8X55_SVLTE_SURF
+       depends on ARCH_MSM7X30
+       depends on !MSM_STACKED_MEMORY
+       default y
+       bool "MSM8X55 SVLTE SURF"
+       help
+         Support for the Qualcomm MSM8x55 SVLTE SURF eval board.
 
 config MACH_MSM8X60_RUMI3
 	depends on ARCH_MSM8X60
+	default n
 	bool "MSM8x60 RUMI3"
 	help
 	  Support for the Qualcomm MSM8x60 RUMI3 emulator.
 
-config MACH_MSM8X60_SURF
-	depends on ARCH_MSM8X60
-	bool "MSM8x60 SURF"
-	help
-	  Support for the Qualcomm MSM8x60 SURF eval board.
-
 config MACH_MSM8X60_SIM
 	depends on ARCH_MSM8X60
+	default n
 	bool "MSM8x60 Simulator"
 	help
 	  Support for the Qualcomm MSM8x60 simulator.
 
+config MACH_MSM8X60_SURF
+	depends on ARCH_MSM8X60
+	default n
+	bool "MSM8x60 SURF"
+	help
+	  Support for the Qualcomm MSM8x60 SURF eval board.
+
 config MACH_MSM8X60_FFA
 	depends on ARCH_MSM8X60
+	default n
 	bool "MSM8x60 FFA"
 	help
 	  Support for the Qualcomm MSM8x60 FFA eval board.
 
+config MACH_MSM8X60_FLUID
+	depends on ARCH_MSM8X60
+	default n
+	bool "MSM8x60 FLUID"
+	help
+	  Support for the Qualcomm MSM8x60 FLUID platform. The FLUID is an
+	  8x60 target which has a form factor that is much closer to that
+	  of a phone than other targets. It also has a new display and
+	  touchscreen controller.
+
+config MACH_MSM8X60_FUSION
+	depends on ARCH_MSM8X60
+	default n
+	bool "MSM8x60 FUSION"
+	help
+	  Support for the Qualcomm MSM8x60 Fusion SURF device.
+
+config MACH_MSM8X60_FUSN_FFA
+	depends on ARCH_MSM8X60
+	default n
+	bool "MSM8x60 FUSN FFA"
+	help
+	  Support for the Qualcomm MSM8x60 Fusion FFA device.
+
+config MACH_MSM8X60_DRAGON
+	depends on ARCH_MSM8X60
+	default n
+	bool "MSM8x60 DRAGON"
+	help
+	  Support for the Qualcomm MSM8x60 Dragon board.
+
 config MACH_MSM8960_SIM
 	depends on ARCH_MSM8960
 	bool "MSM8960 Simulator"
@@ -148,23 +721,1640 @@
 	help
 	  Support for the Qualcomm MSM8960 RUMI3 emulator.
 
+config MACH_MSM8960_CDP
+	depends on ARCH_MSM8960
+	bool "MSM8960 CDP"
+	help
+	  Support for the Qualcomm MSM8960 CDP device.
+
+config MACH_MSM8960_MTP
+	depends on ARCH_MSM8960
+	bool "MSM8960 MTP"
+	help
+	  Support for the Qualcomm MSM8960 MTP device.
+
+config MACH_MSM8960_FLUID
+	depends on ARCH_MSM8960
+	bool "MSM8960 FLUID"
+	help
+	  Support for the Qualcomm MSM8960 FLUID device.
+
+config MACH_MSM8960_LIQUID
+	depends on ARCH_MSM8960
+	bool "MSM8960 LIQUID"
+	help
+	  Support for the Qualcomm MSM8960 LIQUID device.
+
+config MACH_MSM8930_CDP
+	depends on ARCH_MSM8930
+	bool "MSM8930 CDP"
+	help
+	  Support for the Qualcomm MSM8930 CDP device.
+
+config MACH_MSM8930_MTP
+	depends on ARCH_MSM8930
+	bool "MSM8930 MTP"
+	help
+	  Support for the Qualcomm MSM8930 MTP device.
+
+config MACH_MSM8930_FLUID
+	depends on ARCH_MSM8930
+	bool "MSM8930 FLUID"
+	help
+	  Support for the Qualcomm MSM8930 FLUID device.
+
+config MACH_MSM8627_CDP
+	depends on ARCH_MSM8930
+	bool "MSM8627 CDP"
+	help
+	  Support for the Qualcomm MSM8627 CDP device.
+
+config MACH_MSM8627_MTP
+	depends on ARCH_MSM8930
+	bool "MSM8627 MTP"
+	help
+	  Support for the Qualcomm MSM8627 MTP device.
+
+config MACH_MSM9615_CDP
+	depends on ARCH_MSM9615
+	bool "MSM9615 CDP"
+	help
+	  Support for the Qualcomm MSM9615 CDP device.
+
+config MACH_MSM9615_MTP
+	depends on ARCH_MSM9615
+	bool "MSM9615 MTP"
+	help
+	  Support for the Qualcomm MSM9615 MTP device.
+
+config MSM_USE_TSIF1
+	depends on ARCH_MSM8X60
+	bool "MSM8x60 use TSIF1"
+	help
+	  Selects TSIF1 core to be used rather than TSIF0.
+	  The two TSIF cores share the same DM configuration
+	  so they cannot be used simultaneously.
+
+config MACH_APQ8064_SIM
+	depends on ARCH_APQ8064
+	bool "APQ8064 Simulator"
+	help
+	  Support for the Qualcomm APQ8064 simulator.
+
+config MACH_APQ8064_RUMI3
+	depends on ARCH_APQ8064
+	bool "APQ8064 RUMI3"
+	help
+	  Support for the Qualcomm APQ8064 RUMI3 emulator.
+
+config MACH_APQ8064_CDP
+	depends on ARCH_APQ8064
+	bool "APQ8064 CDP"
+	help
+	  Support for the Qualcomm APQ8064 CDP device.
+
+config MACH_APQ8064_MTP
+	depends on ARCH_APQ8064
+	bool "APQ8064 MTP"
+	help
+	  Support for the Qualcomm APQ8064 MTP device.
+
+config MACH_APQ8064_LIQUID
+	depends on ARCH_APQ8064
+	bool "APQ8064 LIQUID"
+	help
+	  Support for the Qualcomm APQ8064 LIQUID device.
+
+config MACH_MPQ8064_CDP
+	depends on ARCH_APQ8064
+	bool "MPQ8064 CDP"
+	help
+	  Support for the Qualcomm MPQ8064 CDP device.
+
+config MACH_MPQ8064_HRD
+	depends on ARCH_APQ8064
+	bool "MPQ8064 HRD"
+	help
+	  Support for the Qualcomm MPQ8064 HRD device.
+
+config MACH_MPQ8064_DTV
+	depends on ARCH_APQ8064
+	bool "MPQ8064 DTV"
+	help
+	  Support for the Qualcomm MPQ8064 DTV device.
+
+config MACH_FSM9XXX_SURF
+	depends on ARCH_FSM9XXX
+	depends on !MSM_STACKED_MEMORY
+	default y
+	bool "FSM9XXX SURF"
+	help
+	  Support for the Qualcomm FSM9xxx femtocell
+	  chipset based SURF evaluation board and
+	  FFA board.
+
 endmenu
 
-config MSM_SMD_PKG3
+config MSM_STACKED_MEMORY
+	bool "Stacked Memory"
+	default y
+	help
+	  This option is used to indicate the presence of on-die stacked
+	  memory.  When present this memory bank is used for a high speed
+	  shared memory interface.  When not present regular RAM is used.
+
+config PHYS_OFFSET
+	hex
+	default "0x40800000" if ARCH_MSM9615
+	default "0x80200000" if ARCH_APQ8064
+	default "0x80200000" if ARCH_MSM8960
+	default "0x80200000" if ARCH_MSM8930
+	default "0x00000000" if ARCH_MSMCOPPER
+	default "0x10000000" if ARCH_FSM9XXX
+	default "0x20200000" if ARCH_MSM9625
+	default "0x00200000" if !MSM_STACKED_MEMORY
+	default "0x00000000" if ARCH_QSD8X50 && MSM_SOC_REV_A
+	default "0x20000000" if ARCH_QSD8X50
+	default "0x40200000" if ARCH_MSM8X60
+	default "0x10000000"
+
+config KERNEL_PMEM_EBI_REGION
+	bool "Enable in-kernel PMEM region for EBI"
+	default y if ARCH_MSM8X60
+	depends on ANDROID_PMEM && (ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_MSMCOPPER)
+	help
+	   Enable the in-kernel PMEM allocator to use EBI memory.
+
+config KERNEL_PMEM_SMI_REGION
+	bool "Enable in-kernel PMEM region for SMI"
+	default y if ARCH_MSM8X60
+	depends on ANDROID_PMEM && ((ARCH_QSD8X50 && !PMEM_GPU0) || (ARCH_MSM8X60 && !VCM))
+	help
+	   Enable the in-kernel PMEM allocator to use SMI memory.
+
+config PMEM_GPU0
+	bool "Enable PMEM GPU0 region"
+	default y
+	depends on ARCH_QSD8X50 && ANDROID_PMEM
+	help
+	  Enable the PMEM GPU0 device on SMI Memory.
+
+config MSM_AMSS_VERSION
+	int
+	default 6210 if MSM_AMSS_VERSION_6210
+	default 6220 if MSM_AMSS_VERSION_6220
+	default 6225 if MSM_AMSS_VERSION_6225
+
+choice
+	prompt "AMSS modem firmware version"
+
+	default MSM_AMSS_VERSION_6225
+
+	config MSM_AMSS_VERSION_6210
+		bool "6.2.10"
+
+	config MSM_AMSS_VERSION_6220
+		bool "6.2.20"
+
+	config MSM_AMSS_VERSION_6225
+		bool "6.2.20 + New ADSP"
+endchoice
+
+config MSM_HAS_DEBUG_UART_HS
 	bool
+	help
+	  Say Y here if high speed MSM UART is present.
+
+config MSM_HAS_DEBUG_UART_HS_V14
+	bool
+	select MSM_HAS_DEBUG_UART_HS
+	help
+	  Say Y here if high speed MSM UART v1.4 is present.
+
+config MSM_DEBUG_UART_PHYS
+	hex
+	default 0xA9A00000 if (ARCH_MSM7X27 || ARCH_QSD8X50) && DEBUG_MSM_UART1
+	default 0xACA00000 if ARCH_MSM7X30 && DEBUG_MSM_UART1
+	default 0x94000000 if ARCH_FSM9XXX && DEBUG_MSM_UART1
+	default 0xA9B00000 if (ARCH_MSM7X27 || ARCH_QSD8X50) && DEBUG_MSM_UART2
+	default 0xACB00000 if ARCH_MSM7X30 && DEBUG_MSM_UART2
+	default 0x94100000 if ARCH_FSM9XXX && DEBUG_MSM_UART2
+	default 0xA9C00000 if (ARCH_MSM7X27 || ARCH_QSD8X50) && DEBUG_MSM_UART3
+	default 0xACC00000 if ARCH_MSM7X30 && DEBUG_MSM_UART3
+
+choice
+	prompt "Debug UART"
+	depends on DEBUG_LL
+
+	config DEBUG_MSM_UART1
+		bool "Kernel low-level debugging messages via MSM UART1"
+		depends on ARCH_MSM7X27 || ARCH_MSM7X30 || ARCH_QSD8X50 || ARCH_FSM9XXX
+		help
+		  Say Y here if you want the debug print routines to direct
+		  their output to the first serial port on MSM devices.
+
+	config DEBUG_MSM_UART2
+		bool "Kernel low-level debugging messages via MSM UART2"
+		depends on ARCH_MSM7X27 || ARCH_MSM7X30 || ARCH_QSD8X50 || ARCH_FSM9XXX
+		help
+		  Say Y here if you want the debug print routines to direct
+		  their output to the second serial port on MSM devices.
+
+	config DEBUG_MSM_UART3
+		bool "Kernel low-level debugging messages via MSM UART3"
+		depends on ARCH_MSM7X27 || ARCH_MSM7X30 || ARCH_QSD8X50
+		help
+		  Say Y here if you want the debug print routines to direct
+		  their output to the third serial port on MSM devices.
+
+	config DEBUG_MSM8660_UART
+		bool "Kernel low-level debugging messages via MSM 8660 UART"
+		depends on ARCH_MSM8X60
+		select MSM_HAS_DEBUG_UART_HS
+		help
+		  Say Y here if you want the debug print routines to direct
+		  their output to the serial port on MSM 8660 devices.
+
+	config DEBUG_MSM8960_UART
+		bool "Kernel low-level debugging messages via MSM 8960 UART"
+		depends on ARCH_MSM8960 && DEBUG_LL
+		select MSM_HAS_DEBUG_UART_HS
+		help
+		  Say Y here if you want the debug print routines to direct
+		  their output to the serial port on MSM 8960 devices.
+
+	config DEBUG_MSM8930_UART
+		bool "Kernel low-level debugging messages via MSM 8930 UART"
+		depends on ARCH_MSM8930 && DEBUG_LL
+		select MSM_HAS_DEBUG_UART_HS
+		help
+		Say Y here if you want the debug print routines to direct
+		their output to the serial port on MSM 8930 devices.
+
+	config DEBUG_APQ8064_UART
+		bool "Kernel low-level debugging messages via APQ 8064 UART"
+		depends on ARCH_APQ8064 && DEBUG_LL
+		select MSM_HAS_DEBUG_UART_HS
+		help
+		Say Y here if you want the debug print routines to direct
+		their output to the serial port on APQ 8064 devices.
+
+	config DEBUG_MSMCOPPER_UART
+		bool "Kernel low-level debugging messages via MSM Copper UART"
+		depends on ARCH_MSMCOPPER
+		select MSM_HAS_DEBUG_UART_HS_V14
+		help
+		  Say Y here if you want the debug print routines to direct
+		  their output to the serial port on MSM Copper devices.
+endchoice
+
+choice
+	prompt "Default Timer"
+	default MSM7X00A_USE_GP_TIMER
+
+	config MSM7X00A_USE_GP_TIMER
+		bool "GP Timer"
+	help
+	  Low resolution timer that allows power collapse from idle.
+
+	config MSM7X00A_USE_DG_TIMER
+		bool "DG Timer"
+	help
+	  High resolution timer.
+endchoice
+
+choice
+	prompt "Suspend sleep mode"
+	default MSM7X00A_SLEEP_MODE_POWER_COLLAPSE_SUSPEND
+	help
+	  Allows overriding the sleep mode used. Leave at power
+	  collapse suspend unless the arm9 image has problems.
+
+	config MSM7X00A_SLEEP_MODE_POWER_COLLAPSE_SUSPEND
+		bool "Power collapse suspend"
+	help
+	  Lowest sleep state. Returns through reset vector.
+
+	config MSM7X00A_SLEEP_MODE_POWER_COLLAPSE
+		bool "Power collapse"
+	help
+	  Sleep state that returns through reset vector.
+
+	config MSM7X00A_SLEEP_MODE_APPS_SLEEP
+		bool "Apps Sleep"
+
+	config MSM7X00A_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT
+		bool "Ramp down cpu clock and wait for interrupt"
+
+	config MSM7X00A_SLEEP_WAIT_FOR_INTERRUPT
+		bool "Wait for interrupt"
+endchoice
+
+config MSM7X00A_SLEEP_MODE
+	int
+	default 0 if MSM7X00A_SLEEP_MODE_POWER_COLLAPSE_SUSPEND
+	default 1 if MSM7X00A_SLEEP_MODE_POWER_COLLAPSE
+	default 2 if MSM7X00A_SLEEP_MODE_APPS_SLEEP
+	default 3 if MSM7X00A_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT
+	default 4 if MSM7X00A_SLEEP_WAIT_FOR_INTERRUPT
+
+choice
+	prompt "Idle sleep mode"
+	default MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE
+	help
+	  Allows overriding the sleep mode used from idle. Leave at power
+	  collapse suspend unless the arm9 image has problems.
+
+	config MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE_SUSPEND
+		bool "Power collapse suspend"
+	help
+	  Lowest sleep state. Returns through reset vector.
+
+	config MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE
+		bool "Power collapse"
+	help
+	  Sleep state that returns through reset vector.
+
+	config MSM7X00A_IDLE_SLEEP_MODE_APPS_SLEEP
+		bool "Apps Sleep"
+
+	config MSM7X00A_IDLE_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT
+		bool "Ramp down cpu clock and wait for interrupt"
+
+	config MSM7X00A_IDLE_SLEEP_WAIT_FOR_INTERRUPT
+		bool "Wait for interrupt"
+endchoice
+
+config MSM7X00A_IDLE_SLEEP_MODE
+	int
+	default 0 if MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE_SUSPEND
+	default 1 if MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE
+	default 2 if MSM7X00A_IDLE_SLEEP_MODE_APPS_SLEEP
+	default 3 if MSM7X00A_IDLE_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT
+	default 4 if MSM7X00A_IDLE_SLEEP_WAIT_FOR_INTERRUPT
+
+config MSM7X00A_IDLE_SLEEP_MIN_TIME
+	int "Minimum idle time before sleep"
+	default 20000000
+	help
+	  Minimum idle time in nanoseconds before entering low power mode.
+
+config MSM7X00A_IDLE_SPIN_TIME
+	int "Idle spin time before cpu ramp down"
+	default 80000
+	help
+	  Spin time in nanoseconds before ramping down cpu clock and entering
+	  any low power state.
+
+menuconfig MSM_IDLE_STATS
+	bool "Collect idle statistics"
+	default y
+	help
+	  Collect idle statistics and export them in proc/msm_pm_stats.
+
+if MSM_IDLE_STATS
+
+config MSM_IDLE_STATS_FIRST_BUCKET
+	int "First bucket time"
+	default 62500
+	help
+	  Upper time limit in nanoseconds of first bucket.
+
+config MSM_IDLE_STATS_BUCKET_SHIFT
+	int "Bucket shift"
+	default 2
+
+config MSM_IDLE_STATS_BUCKET_COUNT
+	int "Bucket count"
+	default 10
+
+config MSM_SUSPEND_STATS_FIRST_BUCKET
+	int "First bucket time for suspend"
+	default 1000000000
+	help
+	  Upper time limit in nanoseconds of first bucket of the
+	  histogram.  This is for collecting statistics on suspend.
+
+endif # MSM_IDLE_STATS
+
+config CPU_HAS_L2_PMU
+	bool "L2CC PMU Support"
+	help
+	 Select this if the L2 cache controller has a Performance Monitoring Unit.
+
+config HTC_HEADSET
+	tristate "HTC 2 Wire detection driver"
+	default n
+	help
+	 Provides support for detecting HTC 2 wire devices, such as wired
+	 headset, on the trout platform. Can be used with the msm serial
+	 debugger, but not with serial console.
+
+config TROUT_BATTCHG
+	depends on MACH_TROUT && POWER_SUPPLY
+	default y
+	bool "Trout battery / charger driver"
+
+config HTC_PWRSINK
+	depends on MSM_SMD
+	default n
+	bool "HTC Power Sink Driver"
+
+config QSD_SVS
+	bool "QSD Static Voltage Scaling"
+	depends on (MACH_QSD8X50_SURF || MACH_QSD8X50_FFA)
+	default y
+	select TPS65023
+	help
+	  Enables static voltage scaling using the TPS65023 PMIC.
+
+config QSD_PMIC_DEFAULT_DCDC1
+	int "PMIC default output voltage"
+	depends on (MACH_QSD8X50_SURF || MACH_QSD8X50_FFA)
+	default 1250
+	help
+	  This is the PMIC voltage at Linux kernel boot.
+
+config MSM_FIQ_SUPPORT
+	default y
+	bool "Enable installation of an FIQ handler."
+
+config MSM_SERIAL_DEBUGGER
+	select MSM_FIQ_SUPPORT
+	select KERNEL_DEBUGGER_CORE
+	default n
+	bool "FIQ Mode Serial Debugger"
+	help
+	  The FIQ serial debugger can accept commands even when the
+	  kernel is unresponsive due to being stuck with interrupts
+	  disabled.  Depends on the kernel debugger core in drivers/misc.
+
+config MSM_SERIAL_DEBUGGER_CONSOLE
+	depends on MSM_SERIAL_DEBUGGER
+	default n
+	bool "Console on FIQ Serial Debugger port"
+	help
+	  Enables a console so that printk messages are displayed on
+	  the debugger serial port as the occur.
 
 config MSM_PROC_COMM
-	bool
+	default y
+	bool "Proc-Comm RPC Interface"
+	help
+	  Enables a lightweight communications interface to the
+	  baseband processor.
 
 config MSM_SMD
+	bool "MSM Shared Memory Driver (SMD)"
+	help
+	  Support for the shared memory interface between the apps
+	  processor and the baseband processor.  Provides access to
+	  the "shared heap", as well as virtual serial channels
+	  used to communicate with various services on the baseband
+	  processor.
+
+choice
+	prompt "MSM Shared memory interface version"
+	depends on MSM_SMD
+	default MSM_SMD_PKG3 if ARCH_MSM_ARM11
+	default MSM_SMD_PKG4 if ARCH_MSM_SCORPION
+
+	config MSM_SMD_PKG3
+	  bool
+	    prompt "Package 3"
+
+	config MSM_SMD_PKG4
+	  bool
+	    prompt "Package 4"
+endchoice
+
+config MSM_PCIE
+	bool "MSM PCIe Controller driver"
+	depends on PCI && PCI_MSI
+	help
+	  Enables the PCIe functionality by configures PCIe core on
+	  MSM chipset and by enabling the ARM PCI framework extension.
+
+config MSM_RPC_SDIO_XPRT
+	depends on MSM_SDIO_AL
+	default y
+	bool "MSM SDIO XPRT Layer"
+	help
+	  SDIO Transport Layer for RPC Rouer
+
+config MSM_RPC_SDIO_DEBUG
+	depends on MSM_RPC_SDIO_XPRT
+	default y
+	bool "MSM SDIO XPRT debug support"
+	help
+	  Support for debugging SDIO XPRT
+
+config MSM_SMD_DEBUG
+	depends on MSM_SMD
+	default y
+	bool "MSM SMD debug support"
+	help
+	  Support for debugging the SMD for communication
+	  between the ARM9 and ARM11
+
+config MSM_SDIO_AL
+	depends on ((ARCH_MSM7X30 || MACH_MSM8X60_FUSN_FFA || MACH_TYPE_MSM8X60_FUSION) && HAS_WAKELOCK)
+	default y
+	tristate "SDIO-Abstraction-Layer"
+	help
+	  Support MSM<->MDM Communication over SDIO bus.
+	  MDM SDIO-Client should have pipes support.
+
+config MSM_SDIO_DMUX
+	bool "SDIO Data Mux Driver"
+	depends on MSM_SDIO_AL
+	default n
+	help
+	  Support Muxed Data Channels over SDIO interface.
+
+config MSM_BAM_DMUX
+	bool "BAM Data Mux Driver"
+	depends on SPS
+	default n
+	help
+	  Support Muxed Data Channels over BAM interface.
+	  BAM has a limited number of pipes.  This driver
+	  provides a means to support more logical channels
+	  via muxing than BAM could without muxing.
+
+config MSM_N_WAY_SMD
+	depends on (MSM_SMD && !(ARCH_MSM7X01A))
+	default y
+	bool "MSM N-WAY SMD support"
+	help
+	  Supports APPS-QDSP SMD communication along with
+	  normal APPS-MODEM SMD communication.
+
+config MSM_N_WAY_SMSM
+	depends on (MSM_SMD && !(ARCH_MSM7X01A))
+	default y
+	bool "MSM N-WAY SMSM support"
+	help
+	  Supports APPS-QDSP SMSM communication along with
+	  normal APPS-MODEM SMSM communication.
+
+config MSM_RESET_MODEM
+	tristate "Reset Modem Driver"
+	depends on MSM_SMD
+	default m
+	help
+	  Allows the user to reset the modem through a device node.
+
+config MSM_SMD_LOGGING
+	depends on MSM_SMD
+	default y
+	bool "MSM Shared Memory Logger"
+	help
+	  This option exposes the shared memory logger at /dev/smem_log
+	  and a debugfs node named smem_log.
+
+	  If in doubt, say yes.
+
+config MSM_IPC_LOGGING
+	bool "MSM Debug Logging for IPC Drivers"
+	help
+	  This option allows the debug logging for IPC Drivers.
+
+	  If in doubt, say no.
+
+config MSM_SMD_NMEA
+	bool "NMEA GPS Driver"
+	depends on MSM_SMD
+	default y
+	help
+	  Enable this to support the NMEA GPS device.
+
+	  If in doubt, say yes.
+
+config MSM_SDIO_TTY
+	bool "SDIO TTY Driver"
+	depends on MSM_SDIO_AL
+	default n
+	help
+	  Provides a TTY driver SDIO TTY
+	  This driver can be used by user space
+	  applications for passing data through the
+	  SDIO interface.
+
+config MSM_SMD_TTY
+	bool "SMD TTY Driver"
+	depends on MSM_SMD
+	default y
+	help
+	  Provides TTY interfaces to interact with the modem.
+
+	  If in doubt, say yes.
+
+config MSM_SMD_QMI
+	bool "SMD QMI Driver"
+	depends on MSM_SMD
+	default y
+	help
+	  Manages network data connections.
+
+	  If in doubt, say yes.
+
+config MSM_SMD_PKT
+	bool "SMD Packet Driver"
+	depends on MSM_SMD
+	default y
+	help
+	  Provides a binary SMD non-muxed packet port interface.
+
+	  If in doubt, say yes.
+
+config MSM_SDIO_CMUX
+	bool "SDIO CMUX Driver"
+	depends on MSM_SDIO_AL
+	default n
+	help
+	  Provides a Muxed port interface over SDIO QMI
+
+config MSM_DSPS
+	bool "Sensors DSPS driver"
+	depends on (MSM_PIL && (ARCH_MSM8X60 || ARCH_MSM8960))
+	default n
+	help
+	  Provides user-space interface to the sensors manager
+	  to turn on/off the Sensors Processor system clocks.
+	  It is the DSPS responsibility to turn on/off the sensors
+	  themself.
+	  The number of clocks and their name may vary between targets.
+	  It also triggers the PIL to load the DSPS firmware.
+
+config MSM_SDIO_CTL
+	bool "SDIO CTL Driver"
+	depends on MSM_SDIO_CMUX
+	default n
+	help
+	  Provides a binary SDIO control port interface.
+
+config MSM_ONCRPCROUTER
+	depends on MSM_SMD
+	default n
+	bool "MSM ONCRPC router support"
+	help
+	  Support for the MSM ONCRPC router for communication between
+	  the ARM9 and ARM11
+
+config MSM_IPC_ROUTER
+	depends on NET
+	default n
+	bool "MSM IPC Router support"
+	help
+	  Support for the MSM IPC Router for communication between
+	  the APPs and the MODEM
+
+config MSM_IPC_ROUTER_SMD_XPRT
+	depends on MSM_SMD
+	depends on MSM_IPC_ROUTER
+	default n
+	bool "MSM SMD XPRT Layer"
+	help
+	  SMD Transport Layer for IPC Router
+
+config MSM_ONCRPCROUTER_DEBUG
+	depends on MSM_ONCRPCROUTER
+	default y
+	bool "MSM debug ONCRPC router support"
+	help
+	  Support for debugging the ONCRPC router for communication
+	  between the ARM9 and ARM11
+
+config MSM_RPC_LOOPBACK_XPRT
+	depends on MSM_ONCRPCROUTER
+	default n
+	bool "MSM RPC local routing support"
+	help
+	  Support for routing RPC messages between APPS clients
+	  and APPS servers.  Helps in testing APPS RPC framework.
+
+config MSM_RPCSERVER_TIME_REMOTE
+	depends on MSM_ONCRPCROUTER && RTC_HCTOSYS
+	default y
+	bool "Time remote RPC server"
+	help
+	  The time remote server receives notification of time bases and
+	  reports these events to registered callback functions.
+
+config MSM_RPCSERVER_WATCHDOG
+	depends on MSM_ONCRPCROUTER
+	default y
+	bool "Watchdog RPC server"
+	help
+	  The dog_keepalive server handles watchdog events.
+
+config MSM_RPC_WATCHDOG
+	depends on MSM_ONCRPCROUTER
+	default n
+	bool "Watchdog RPC client"
+	help
+	  The dog_keepalive client module.
+
+config MSM_RPC_PING
+	depends on MSM_ONCRPCROUTER && DEBUG_FS
+	default m
+	bool "MSM rpc ping"
+	help
+	  Implements MSM rpc ping test module.
+
+config MSM_RPC_PROC_COMM_TEST
+	depends on DEBUG_FS && MSM_PROC_COMM
+	default m
+	bool "MSM rpc proc comm test"
+	help
+	  Implements MSM rpc proc comm test module.
+
+config MSM_RPC_OEM_RAPI
+	depends on MSM_ONCRPCROUTER
+	default m
+	bool "MSM oem rapi"
+	help
+	  Implements MSM oem rapi client module.
+
+config MSM_RPCSERVER_HANDSET
+	depends on MSM_ONCRPCROUTER
+	default y
+	bool "Handset events RPC server"
+	help
+	  Support for receiving handset events like headset detect,
+	  headset switch and clamshell state.
+
+config MSM_RMT_STORAGE_CLIENT
+	depends on (ARCH_MSM && MSM_ONCRPCROUTER)
+	default n
+	bool "Remote Storage RPC client"
+	help
+	  Provide RPC mechanism for remote processors to access storage
+	  device on apps processor.
+
+config MSM_RMT_STORAGE_CLIENT_STATS
+	depends on (MSM_RMT_STORAGE_CLIENT && DEBUG_FS)
+	default n
+	bool "Remote storage RPC client performance statistics"
+	help
+	  Collects performance statistics and shows this information
+	  through a debugfs file rmt_storage_stats.
+
+config MSM_SDIO_SMEM
+        depends on MSM_SDIO_AL
+        default n
+        bool "SDIO SMEM for remote storage"
+        help
+          Copies data from remote MDM9K memory to local MSM8x60
+	  memory. Used by remote storage client to shadow
+	  MDM9K filesystem.
+
+config MSM_DALRPC
+	bool "DAL RPC support"
+	default n
+	help
+	  Supports RPC calls to DAL devices on remote processor cores.
+
+config MSM_DALRPC_TEST
+	tristate "DAL RPC test module"
+	depends on (MSM_DALRPC && DEBUG_FS)
+	default m
+	help
+	  Exercises DAL RPC calls to QDSP6.
+
+if CPU_FREQ_MSM
+
+config MSM_CPU_FREQ_SET_MIN_MAX
+	bool "Set Min/Max CPU frequencies."
+	default n
+	help
+	  Allow setting min and max CPU frequencies. Sysfs can be used
+	  to override these values.
+
+config MSM_CPU_FREQ_MAX
+	int "Max CPU Frequency"
+	depends on MSM_CPU_FREQ_SET_MIN_MAX
+	default 384000
+
+config MSM_CPU_FREQ_MIN
+	int "Min CPU Frequency"
+	depends on MSM_CPU_FREQ_SET_MIN_MAX
+	default 245760
+
+endif # CPU_FREQ_MSM
+
+config MSM_CPU_AVS
+	bool "Enable software controlled Adaptive Voltage Scaling (AVS)"
+	depends on (ARCH_MSM_SCORPION && QSD_SVS)
+	depends on ARCH_QSD8X50
+	default n
+	select MSM_AVS_HW
+	help
+	  This enables the s/w control of Adaptive Voltage Scaling feature
+	  in Qualcomm ARMv7 CPUs. It adjusts the voltage for each frequency
+	  based on feedback from three ring oscillators in the CPU.
+
+config MSM_AVS_HW
+	bool "Enable Adaptive Voltage Scaling (AVS)"
+	default n
+	help
+	  Enable AVS hardware to fine tune voltage at each frequency. The
+	  AVS hardware blocks associated with each Qualcomm ARMv7 cores can
+	  fine tune the voltages based on the feedback from the ring
+	  oscillators.
+
+config MSM_HW3D
+	tristate "MSM Hardware 3D Register Driver"
+	depends on ANDROID_PMEM
+	default y
+	help
+	  Provides access to registers needed by the userspace OpenGL|ES
+	  library.
+
+config MSM_ADSP
+	depends on (ARCH_MSM7X01A || ARCH_MSM7X25 || ARCH_MSM7X27)
+	tristate "MSM ADSP driver"
+	depends on ANDROID_PMEM
+	default y
+	help
+	  Provides access to registers needed by the userspace aDSP library.
+
+config ADSP_RPC_VER
+	hex
+	default 0x30002 if (ARCH_MSM7X27 || (ARCH_MSM7X25 && AMSS_7X25_VERSION_2009))
+	default 0x30001 if (ARCH_MSM7X01A || (ARCH_MSM7X25 && AMSS_7X25_VERSION_2008))
+	depends on MSM_ADSP
+	help
+	 Select proper ADSP RPC version
+choice
+	prompt "ADSP RPC version"
+
+	default AMSS_7X25_VERSION_2009
+
+	config AMSS_7X25_VERSION_2009
+		bool "2.0.09"
+
+	config AMSS_7X25_VERSION_2008
+		bool "2.0.08"
+endchoice
+
+config MSM7KV2_AUDIO
+	bool "MSM7K v2 audio"
+	depends on (ARCH_MSM7X30 && ANDROID_PMEM)
+	default y
+	help
+	  Enables QDSP5V2-based audio drivers for audio playbacks and
+	  voice call.
+
+config MSM_ADSP_REPORT_EVENTS
+	bool "Report modem events from the DSP"
+	default y
+	depends on (MSM_ADSP || MSM7KV2_AUDIO)
+	help
+	  Normally, only messages from the aDSP are reported to userspace.
+	  With this option, we report events from the aDSP as well.
+
+config MSM_QDSP6
+	tristate "QDSP6 support"
+	depends on ARCH_QSD8X50 && ANDROID_PMEM
+	default y
+	help
+	  Enable support for qdsp6. This provides audio and video functionality.
+
+config MSM8X60_AUDIO
+	tristate "MSM8X60 audio support"
+	depends on ARCH_MSM8X60 && ANDROID_PMEM
+	default y
+	help
+	  Enable support for qdsp6v2. This provides audio functionality.
+
+config MSM8X60_FTM_AUDIO_DEVICES
+	bool "MSM8X60 audio factory test mode support"
+	depends on MSM8X60_AUDIO
+	help
+	  Enable support audio factory test mode devices.  This is used
+	  in a production line environment.
+
+config RTAC
+	bool "MSM8K real-time audio calibration support"
+	default y
+	help
+	  Enable support for rtac. This enables calibration during
+	  audio operation
+
+config MSM7X27A_AUDIO
+	bool "MSM7X27A audio support"
+	depends on ARCH_MSM7X27A && MSM_ADSP
+	default n
+	help
+	  Enable support for 7x27a. This provides audio functionality.
+
+config MSM_PROC_COMM_REGULATOR
 	bool
+	depends on MSM_PROC_COMM && REGULATOR
+	help
+	  Enable regulator framework support for regulators managed by PMLIB
+	  on the modem, and controlled through proccomm calls.
+
+config MSM_VREG_SWITCH_INVERTED
+	bool "Reverse vreg switch polarity"
+	default n
+	help
+	  Reverses the enable and disable for vreg switch.
+
+config MSM_DMA_TEST
+	tristate "MSM DMA test module"
+	default m
+	help
+	  Intended to be compiled as a module.  Provides a device node
+	  and ioctls for testing the MSM dma system.
+
+config WIFI_CONTROL_FUNC
+	bool "Enable WiFi control function abstraction"
+	help
+	  Enables Power/Reset/Carddetect function abstraction
+
+config WIFI_MEM_PREALLOC
+	depends on WIFI_CONTROL_FUNC
+	bool "Preallocate memory for WiFi buffers"
+	help
+	  Preallocates memory buffers for WiFi driver
+
+config QSD_AUDIO
+	bool "QSD audio"
+	depends on ARCH_MSM_SCORPION && MSM_DALRPC && ANDROID_PMEM && !MSM_SMP
+	default y
+	help
+	  Provides PCM, MP3, and AAC audio playback.
+
+config AUDIO_AAC_PLUS
+	depends on (MSM_ADSP || QSD_AUDIO || MSM7KV2_AUDIO)
+	bool "AAC+ Audio"
+	default y
+	help
+	  Provides AAC+ decoding
+
+config AUDIO_ENHANCED_AAC_PLUS
+	depends on AUDIO_AAC_PLUS
+	bool "Enhanced AAC+ Audio"
+	default y
+	help
+	  Provides Enhanced AAC+ decoding
+
+config SURF_FFA_GPIO_KEYPAD
+	bool "MSM SURF/FFA GPIO keypad"
+	depends on INPUT_GPIO = "y"
+	default y
+	help
+	  Select if the GPIO keypad is attached.
+
+config MSM_SLEEP_TIME_OVERRIDE
+	bool "Allow overriding suspend/sleep time with PM module parameter"
+	default y
+	help
+	  Enable the module parameter sleep_time_override. Specified
+	  in units of seconds, it overwrites the normal sleep time of
+	  suspend. The feature is required for automated power management
+	  testing.
+
+config MSM_MEMORY_LOW_POWER_MODE
+	bool "Control the low power modes of memory"
+	default n
+	help
+	  The application processor controls whether memory should enter
+	  which low power mode.
+
+choice
+	prompt "Default Memory Low Power Mode during Idle"
+	depends on MSM_MEMORY_LOW_POWER_MODE
+	default MSM_MEMORY_LOW_POWER_MODE_IDLE_ACTIVE
+	help
+	  Selects the default low power mode of the memory during idle
+	  sleep.
+
+	config MSM_MEMORY_LOW_POWER_MODE_IDLE_ACTIVE
+		bool "Memory active"
+
+	config MSM_MEMORY_LOW_POWER_MODE_IDLE_RETENTION
+		bool "Memory in retention"
+
+	config MSM_MEMORY_LOW_POWER_MODE_IDLE_DEEP_POWER_DOWN
+		bool "Memory in deep power down"
+endchoice
+
+choice
+	prompt "Default Memory Low Power Mode during Suspend"
+	depends on MSM_MEMORY_LOW_POWER_MODE
+	default MSM_MEMORY_LOW_POWER_MODE_SUSPEND_ACTIVE
+	help
+	  Selects the default low power mode of the memory during suspend
+	  sleep.
+
+	config MSM_MEMORY_LOW_POWER_MODE_SUSPEND_ACTIVE
+		bool "Memory active"
+
+	config MSM_MEMORY_LOW_POWER_MODE_SUSPEND_RETENTION
+		bool "Memory in retention"
+
+	config MSM_MEMORY_LOW_POWER_MODE_SUSPEND_DEEP_POWER_DOWN
+		bool "Memory in deep power down"
+endchoice
+
+choice
+	prompt "Power management timeout action"
+	default MSM_PM_TIMEOUT_HALT
+	help
+	  Selects the Application Processor's action when Power Management
+	  times out waiting for Modem's handshake.
+
+	config MSM_PM_TIMEOUT_HALT
+		bool "Halt the Application Processor"
+
+	config MSM_PM_TIMEOUT_RESET_MODEM
+		bool "Reset the Modem Processor"
+
+	config MSM_PM_TIMEOUT_RESET_CHIP
+		bool "Reset the entire chip"
+endchoice
+
+config MSM_IDLE_WAIT_ON_MODEM
+	int "Wait for Modem to become ready for idle power collapse"
+	default 0
+	help
+	  If Modem is not ready to handle Application Processor's request
+	  for idle power collapse, wait the number of microseconds in case
+	  Modem becomes ready soon.
+
+config MSM_RPM_REGULATOR
+	bool "RPM regulator driver"
+	depends on MSM_RPM && REGULATOR
+	help
+	  Compile in support for the RPM regulator driver, used for setting
+	  voltages and other parameters of the various power rails supplied
+	  by some Qualcomm PMICs.
+
+config MSM_RPM_REGULATOR_SMD
+	bool "SMD RPM regulator driver"
+	depends on REGULATOR
+	depends on OF
+	depends on MSM_RPM_SMD
+	help
+	  Compile in support for the SMD RPM regulator driver which is used for
+	  setting voltages and other parameters of the various power rails
+	  supplied by some Qualcomm PMICs.  The SMD RPM regulator driver should
+	  be used on systems which contain an RPM which communicates with the
+	  application processor over SMD.
+
+config MSM_PIL
+	bool "Peripheral image loading"
+	select FW_LOADER
+	default n
+	help
+	  Some peripherals need to be loaded into memory before they can be
+	  brought out of reset.
+
+	  Say yes to support these devices.
+
+config MSM_PIL_MODEM
+	tristate "Modem (ARM11) Boot Support"
+	depends on MSM_PIL
+	help
+	  Support for booting and shutting down ARM11 Modem processors.
+
+config MSM_PIL_QDSP6V3
+	tristate "QDSP6v3 (Hexagon) Boot Support"
+	depends on MSM_PIL
+	help
+	  Support for booting and shutting down QDSP6v3 processors (hexagon).
+	  The QDSP6 is a low power DSP used in audio software applications.
+
+config MSM_PIL_QDSP6V4
+	tristate "QDSP6v4 (Hexagon) Boot Support"
+	depends on MSM_PIL
+	help
+	  Support for booting and shutting down QDSP6v4 processors (hexagon).
+	  The QDSP6 is a low power DSP used in audio, modem firmware, and modem
+	  software applications.
+
+config MSM_PIL_LPASS_QDSP6V5
+       tristate "LPASS QDSP6v5 (Hexagon) Boot Support"
+       depends on MSM_PIL
+       help
+         Support for booting and shutting down QDSP6v5 processors (Hexagon)
+	 processors in low power audio subsystems.
+
+config MSM_PIL_RIVA
+	tristate "RIVA (WCNSS) Boot Support"
+	depends on MSM_PIL
+	help
+	  Support for booting and shutting down the RIVA processor (WCNSS).
+	  Riva is the wireless subsystem processor used in bluetooth, wireless
+	  LAN, and FM software applications.
+
+config MSM_PIL_TZAPPS
+	tristate "TZApps Boot Support"
+	depends on MSM_PIL
+	help
+	  Support for booting and shutting down TZApps.
+
+	  TZApps is an image that runs in the secure processor state. It is
+	  used to decrypt data and perform secure operations on the behalf of
+	  the kernel.
+
+config MSM_PIL_DSPS
+	tristate "DSPS Boot Support"
+	depends on MSM_PIL
+	help
+	  Support for booting and shutting down ARM7 DSPS processors.
+
+	  DSPS is a sensors offloading processor used for applications such
+	  as rotation detection, temperature, etc.
+
+config MSM_PIL_VIDC
+	tristate "Video Core Secure Boot Support"
+	depends on MSM_PIL
+	help
+	  Support for authenticating the video core image.
+
+config MSM_PIL_GSS
+	tristate "GSS (Coretx A5) Boot Support"
+	depends on MSM_PIL
+	help
+	  Support for booting and shutting down Cortex A5 processors which run
+	  GPS subsystem firmware.
+
+config MSM_PIL_PRONTO
+	tristate "PRONTO (WCNSS) Boot Support"
+	depends on MSM_PIL
+	help
+	  Support for booting and shutting down the PRONTO processor (WCNSS).
+	  PRONTO is the wireless subsystem processor used in bluetooth, wireless
+	  LAN, and FM software applications.
+
+config MSM_SCM
+	bool "Secure Channel Manager (SCM) support"
+	default n
+
+config MSM_SUBSYSTEM_RESTART
+	bool "MSM Subsystem Restart Driver"
+	depends on (ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_MSM9615)
+	default n
+	help
+	  This option enables the MSM subsystem restart driver, which provides
+	  a framework to handle subsystem crashes.
+
+config MSM_SYSMON_COMM
+	bool "MSM System Monitor communication support"
+	depends on MSM_SMD && MSM_SUBSYSTEM_RESTART
+	default y
+	help
+	  This option adds support for MSM System Monitor library, which
+	  provides an API that may be used for notifying subsystems within
+	  the SoC about other subsystems' power-up/down state-changes.
+
+config MSM_MODEM_8960
+	bool "MSM 8960 Modem driver"
+	depends on (ARCH_MSM8960 || ARCH_MSM9615)
+	help
+	 This option enables the modem driver for the MSM8960 and MSM9615, which monitors
+	 modem hardware watchdog interrupt lines and plugs into the subsystem
+	 restart and PIL drivers. For MSM9615, it only supports a full chip reset.
+
+config MSM_LPASS_8960
+	tristate "MSM 8960 Lpass driver"
+	depends on (ARCH_MSM8960 || ARCH_MSM9615)
+	help
+	 This option enables the lpass driver for the MSM8960 and MSM9615. This monitors
+	 lpass hardware watchdog interrupt lines and plugs into the subsystem
+	 restart and PIL drivers. For MSM9615, it only supports a full chip reset.
+
+config MSM_WCNSS_SSR_8960
+	tristate "MSM 8960 WCNSS restart module"
+	depends on (ARCH_MSM8960)
+	help
+	 This option enables the WCNSS restart module for MSM8960, which
+	 monitors WCNSS hardware watchdog interrupt lines and plugs WCNSS
+	 into the subsystem restart framework.
+
+config MSM_GSS_SSR_8064
+	bool "MSM 8064 GSS restart driver"
+	depends on (ARCH_APQ8064)
+	help
+	 This option enables the gps subsystem restart driver for APQ8064, which monitors
+	 gss hardware watchdog interrupt lines and plugs into the subsystem
+	 restart and PIL drivers.
+
+config SCORPION_Uni_45nm_BUG
+	bool "Scorpion Uni 45nm(SC45U): Workaround for ICIMVAU and BPIMVA"
+	depends on ARCH_MSM7X30 || (ARCH_QSD8X50 && MSM_SOC_REV_A)
+	default y
+	help
+	  Invalidating the Instruction Cache by Modified Virtual Address to PoU and
+	  invalidating the Branch Predictor Array by Modified Virtual Address can
+	  create invalid entries in the TLB with the wrong ASID values on Scorpion
+	  Uniprocessor 45nm (SC45U) cores. This option enables the recommended software
+	  workaround for Scorpion Uniprocessor 45nm cores.
+
+	  This bug is not applicable to any ScorpionMP or Scorpion Uni 65nm(SC65U) cores.
+
+config MSM_BUSPM_DEV
+	tristate "MSM Bus Performance Monitor Kernel Module"
+	depends on (ARCH_MSM8X60 || ARCH_MSM8960)
+	default m
+	help
+	  This kernel module is used to mmap() hardware registers for the
+	  performance monitors, counters, etc. The module can also be used to
+	  allocate physical memory which is used by bus performance hardware to
+	  dump performance data.
+
+config MSM_TZ_LOG
+	tristate "MSM Trust Zone (TZ) Log Driver"
+	depends on DEBUG_FS
+	help
+	  This option enables a driver with a debugfs interface for messages
+	  produced by the Secure code (Trust zone). These messages provide
+	  diagnostic information about TZ operation.
+
+config MSM_RPM_LOG
+	tristate "MSM Resource Power Manager Log Driver"
+	depends on DEBUG_FS
+	depends on MSM_RPM
+	default n
+	help
+	  This option enables a driver which can read from a circular buffer
+	  of messages produced by the RPM. These messages provide diagnostic
+	  information about RPM operation. The driver outputs the messages
+	  via a debugfs node.
+
+config MSM_RPM_STATS_LOG
+	tristate "MSM Resource Power Manager Stat Driver"
+	depends on DEBUG_FS
+	depends on MSM_RPM
+	default n
+	  help
+	  This option enables a driver which reads RPM messages from a shared
+	  memory location. These messages provide statistical information about
+	  the low power modes that RPM enters. The drivers outputs the message
+	  via a debugfs node.
+
+config MSM_DIRECT_SCLK_ACCESS
+	bool "Direct access to the SCLK timer"
+	default n
+
+config IOMMU_API
+       bool
 
 config MSM_GPIOMUX
 	bool
 
-config MSM_V2_TLMM
+config MSM_SECURE_IO
 	bool
 
-config MSM_SCM
+config MSM_NATIVE_RESTART
 	bool
+
+config MSM_PM2
+	depends on PM
+	bool
+
+config MSM_PM8X60
+	depends on PM
+	bool
+
+config MSM_NOPM
+	default y if !PM
+	bool
+
+config MSM_BUS_SCALING
+	bool "Bus scaling driver"
+	default n
+
+config MSM_BUS_RPM_MULTI_TIER_ENABLED
+	bool "RPM Multi-tiering Configuration"
+	depends on MSM_BUS_SCALING
+
+config MSM_WATCHDOG
+	bool "MSM Watchdog Support"
+	depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_MSM9615 || ARCH_FSM9XXX
+	help
+		This enables the watchdog as is present on 8x60. Currently we use
+		core 0's watchdog, and reset the entire SoC if it times out. It does
+		not run during the bootup process, so it will not catch any early
+		lockups.
+
+config MSM_DLOAD_MODE
+	bool "Enable download mode on crashes"
+	depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_MSM9615
+	default n
+	help
+		This makes the SoC enter download mode when it resets
+		due to a kernel panic. Note that this doesn't by itself
+		make the kernel reboot on a kernel panic - that must be
+		enabled via another mechanism.
+
+config MSM_JTAG
+        bool "JTAG debug and trace support"
+	help
+          Add additional support for JTAG kernel debugging and tracing.
+
+config MSM_ETM
+	tristate "Enable MSM ETM and ETB"
+	depends on ARCH_MSM8X60
+	select MSM_JTAG
+	help
+	  Enables embedded trace collection on MSM8660
+
+config MSM_QDSS
+	bool "Qualcomm Debug Subsystem"
+	select MSM_JTAG
+	help
+	  Enables support for Qualcomm Debug Subsystem.
+
+config MSM_QDSS_ETM_DEFAULT_ENABLE
+	bool "Turn on QDSS ETM Tracing by Default"
+	depends on MSM_QDSS
+	help
+	  Turns on QDSS ETM tracing by default. Otherwise, tracing is
+	  disabled by default but can be enabled by other means.
+
+config MSM_SLEEP_STATS
+	bool "Enable exporting of MSM sleep stats to userspace"
+	depends on CPU_IDLE
+	default n
+
+config MSM_SLEEP_STATS_DEVICE
+	bool "Enable exporting of MSM sleep device stats to userspace"
+
+config MSM_RUN_QUEUE_STATS
+	bool "Enable collection and exporting of MSM Run Queue stats to userspace"
+	depends on (MSM_SOC_REV_A || ARCH_MSM8X60 || ARCH_MSM8960)
+	help
+	 This option enalbes statistics collection on Run Queue. A daemon
+         in user mode, called MPDecision will be using this data to decide
+         on when to switch off/on the other cores.
+
+config MSM_STANDALONE_POWER_COLLAPSE
+       bool "Enable standalone power collapse"
+       default n
+
+config MSM_GSBI9_UART
+	bool "Enable GSBI9 UART device"
+	default n
+	help
+	  This enables GSBI9 configured into UART.
+
+config MSM_SHARED_GPIO_FOR_UART2DM
+	bool "Use shared GPIOs into UART mode"
+	depends on (ARCH_MSM7X27A && !MMC_MSM_SDC3_8_BIT_SUPPORT && !MMC_MSM_SDC4_SUPPORT)
+	help
+	  This option configures GPIO muxed with SDC4/MMC3
+	  8-bit mode into UART mode. It is used for serial
+	  console on UART2DM. Say Y if you want to have
+	  serial console on UART2DM.
+
+config MSM_SHOW_RESUME_IRQ
+	bool "Enable logging of interrupts that could have caused resume"
+	depends on (ARM_GIC || PMIC8058)
+	default y if PMIC8058
+	default n
+	help
+		This option logs wake up interrupts that have triggered just before
+		the resume loop unrolls. Say Y if you want to debug why the system
+		resumed.
+
+config BT_MSM_PINTEST
+	tristate "MSM Bluetooth Pin Connectivity Test"
+	depends on ((ARCH_MSM8X60 || ARCH_MSM7X27A) && DEBUG_FS)
+        default n
+	help
+	  Bluetooth MSM Pin Connectivity test module.
+	  This driver provides support for verifying the MSM to BT pin
+	  connectivity.
+
+config MSM_FAKE_BATTERY
+		depends on POWER_SUPPLY
+		default n
+		bool "MSM Fake Battery"
+		help
+		 Enables MSM fake battery driver.
+
+config MSM_QDSP6_APR
+	bool "Audio QDSP6 APR support"
+	depends on MSM_SMD
+	default n
+	help
+	  Enable APR IPC protocol support between
+	  application processor and QDSP6. APR is
+	  used by audio driver to configure QDSP6's
+	  ASM, ADM and AFE.
+
+config MSM_QDSP6_CODECS
+	bool "Audio Codecs on QDSP6 APR "
+	depends on MSM_SMD
+	default n
+	help
+	  Enable Audio codecs with APR IPC protocol support between
+	  application processor and QDSP6. APR is
+	  used by audio driver to configure QDSP6's
+	  ASM, ADM and AFE.
+
+config MSM_AUDIO_QDSP6
+        bool "QDSP6 HW Audio support"
+        select SND_SOC_MSM_QDSP6_INTF
+        default n
+        help
+          Enable HW audio support in QDSP6.
+          QDSP6 can support HW encoder & decoder and audio processing
+
+config MSM_ULTRASOUND
+	bool "MSM ultrasound support"
+	depends on MSM_AUDIO_QDSP6
+	help
+	  Enable support for qdsp6/ultrasound.
+
+config MSM_RPC_VIBRATOR
+	bool "RPC based MSM Vibrator Support"
+	depends on MSM_ONCRPCROUTER
+	help
+	  Enable the vibrator support on MSM over RPC. The vibrator
+	  is connected on the PMIC. Say Y if you want to enable this
+	  feature.
+
+config PM8XXX_RPC_VIBRATOR
+	bool "RPC based Vibrator on PM8xxx PMICs"
+	depends on MSM_RPC_VIBRATOR
+	help
+	  Enable the vibrator support on MSM over RPC. The vibrator
+	  is connected on the PM8XXX PMIC. Say Y if you want to enable
+	  this feature.
+
+config MSM_SPM_V1
+	bool "Driver support for SPM Version 1"
+	help
+	  Enables the support for Version 1 of the SPM driver. SPM hardware is
+	  used to manage the processor power during sleep. The driver allows
+	  configuring SPM to allow different power modes.
+
+config MSM_SPM_V2
+	bool "Driver support for SPM Version 2"
+	help
+	  Enables the support for Version 2 of the SPM driver. SPM hardware is
+	  used to manage the processor power during sleep. The driver allows
+	  configuring SPM to allow different power modes.
+
+config MSM_L2_SPM
+	bool "SPM support for L2 cache"
+	depends on MSM_SPM_V2
+	help
+	  Enable SPM driver support for L2 cache. Some MSM chipsets allow
+	  control of L2 cache low power mode with a Subsystem Power manager.
+	  Enabling this driver allows configuring L2 SPM for low power modes
+	  on supported chipsets.
+
+config MSM_MULTIMEDIA_USE_ION
+	bool "Multimedia suport using Ion"
+	depends on ION_MSM
+	help
+	  Enable support for multimedia drivers using Ion for buffer management
+	  instead of pmem. Selecting this may also involve userspace
+	  dependencies as well.
+
+config MSM_OCMEM
+	bool "MSM On-Chip memory driver (OCMEM)"
+	help
+	  Enable support for On-Chip Memory available on certain MSM chipsets.
+	  OCMEM is a low latency, high performance pool shared by subsystems.
+
+config MSM_RTB
+	bool "Register tracing"
+	help
+	  Add support for logging different events to a small uncached
+	  region. This is designed to aid in debugging reset cases where the
+	  caches may not be flushed before the target resets.
+
+config MSM_RTB_SEPARATE_CPUS
+	bool "Separate entries for each cpu"
+	depends on MSM_RTB
+	depends on SMP
+	help
+	  Under some circumstances, it may be beneficial to give dedicated space
+	  for each cpu to log accesses. Selecting this option will log each cpu
+	  separately. This will guarantee that the last acesses for each cpu
+	  will be logged but there will be fewer entries per cpu
+
+config MSM_CACHE_ERP
+	bool "Cache / CPU error reporting"
+	depends on ARCH_MSM_KRAIT
+	help
+	  Say 'Y' here to enable reporting of cache and TLB errors to the kernel
+	  log. Enabling this feature can be used as a system debugging technique
+	  if cache corruption is suspected. Cache error statistics will also be
+	  reported in /proc/cpu/msm_cache_erp.
+
+	  For production builds, you should probably say 'N' here.
+
+config MSM_L1_ERR_PANIC
+	bool "Panic on L1 cache errors"
+	depends on MSM_CACHE_ERP
+	help
+	  To cause the kernel to panic whenever an L1 cache error is detected, say
+	  'Y' here. This may be useful as a debugging technique if general system
+	  instability is suspected.
+
+	  For production builds, you should probably say 'N' here.
+
+config MSM_L2_ERP_PRINT_ACCESS_ERRORS
+	bool "Report L2 master port slave/decode errors in kernel log"
+	depends on MSM_CACHE_ERP
+	help
+	  Master port errors can occur when a memory request is not properly
+	  handled by the destination slave. This can occur if the destination
+	  register does not exist or is inaccessible due to security
+	  restrictions or (in some cases) clock configuration. Enabling this
+	  option will cause a backtrace to be printed to the kernel log whenever
+	  such an error is encountered. Note that the error is reported as an
+	  interrupt rather than as an exception, meaning that the backtrace may
+	  have some skid. This option may help with debugging, though production
+	  builds should probably say 'N' here.
+
+config MSM_L2_ERP_PORT_PANIC
+	bool "Panic on L2 master port errors"
+	depends on MSM_CACHE_ERP && MSM_L2_ERP_PRINT_ACCESS_ERRORS
+	help
+	  Master port errors can occur when a memory request is not properly
+	  handled by the destination slave. Enable this option to catch drivers
+	  which attempt to access bad areas of the address space, or access
+	  hardware registers in an improper state (such as certain clocks not
+	  being on). This option may help with debugging, though production
+	  builds should probably say 'N' here.
+
+config MSM_L2_ERP_1BIT_PANIC
+	bool "Panic on recoverable L2 soft errors"
+	depends on MSM_CACHE_ERP
+	help
+	  Enable this option to cause a kernel panic whenever the L2 cache
+	  encounters a single-bit (correctable) soft error. This option should
+	  only be enabled when doing low-level debugging where cache corruption
+	  is suspected.
+
+	  For production builds, you should definitely say 'N' here.
+
+config MSM_L2_ERP_2BIT_PANIC
+	bool "Panic on unrecoverable L2 soft errors"
+	depends on MSM_CACHE_ERP
+	help
+	  Enable this option to cause a kernel panic whenever the L2 cache
+	  encounters a double-bit (non-correctable) soft error. Debug builds
+	  will likely benefit from having this option enabled to catch cache
+	  problems as soon as possible.
+
+	  For production builds, it may be acceptable to say 'N' here, since
+	  an uncorrectable error might not necessarily cause further problems.
+
+config MSM_DCVS
+	bool "Use MSM DCVS for CPU/GPU Frequency control"
+	depends on MSM_SCM
+	help
+	  Enable support for MSM DCVS to control all CPU and GPU core frequencies.
+	  The DCVS manager allows idle driver to feed the idle information to the
+	  algorithm and the algorithm returns a frequency for the core which is
+	  passed to the frequency change driver.
+
+config HAVE_ARCH_HAS_CURRENT_TIMER
+	bool
+
+config MSM_CACHE_DUMP
+	bool "Cache dumping support"
+	help
+	  Add infrastructure to dump the L1 and L2 caches to an allocated buffer.
+	  This allows for analysis of the caches in case cache corruption is
+	  suspected.
+
+config MSM_CACHE_DUMP_ON_PANIC
+	bool "Dump caches on panic"
+	depends on MSM_CACHE_DUMP
+	help
+	  By default, the caches are flushed on panic. This means that trying to
+	  look at them in a RAM dump will give useless data. Select this if you
+	  want to dump the L1 and L2 caches on panic before any flush occurs.
+	  If unsure, say N
+
+config MSM_HSIC_SYSMON
+	tristate "MSM HSIC system monitor driver"
+	depends on USB
+	help
+	  Add support for bridging with the system monitor interface of MDM
+	  over HSIC. This driver allows the local system monitor to
+	  communicate with the remote system monitor interface.
+
+config MSM_HSIC_SYSMON_TEST
+	tristate "MSM HSIC system monitor bridge test"
+	depends on USB && MSM_HSIC_SYSMON && DEBUG_FS
+	help
+	  Enable the test hook for the Qualcomm system monitor HSIC driver.
+	  This will create a debugfs file entry named "hsic_sysmon_test" which
+	  can be read and written to send character data to the sysmon port of
+	  the modem over USB.
+
 endif
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 4ad3969..975c1798 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -1,33 +1,368 @@
-obj-y += io.o idle.o timer.o
-obj-y += clock.o
-obj-$(CONFIG_DEBUG_FS) += clock-debug.o
-
-obj-$(CONFIG_MSM_VIC) += irq-vic.o
-obj-$(CONFIG_MSM_IOMMU) += devices-iommu.o
-
-obj-$(CONFIG_ARCH_MSM7X00A) += dma.o irq.o acpuclock-arm11.o
-obj-$(CONFIG_ARCH_MSM7X30) += dma.o
-obj-$(CONFIG_ARCH_QSD8X50) += dma.o sirc.o
-
-obj-$(CONFIG_MSM_PROC_COMM) += proc_comm.o clock-pcom.o vreg.o
-
-obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o
-obj-$(CONFIG_MSM_SMD) += last_radio_log.o
-obj-$(CONFIG_MSM_SCM) += scm.o scm-boot.o
-
 CFLAGS_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1)
 
+obj-y += io.o dma.o memory.o
+ifndef CONFIG_ARM_ARCH_TIMER
+obj-y += timer.o
+endif
+obj-y += clock.o clock-voter.o clock-dummy.o
+obj-y += modem_notifier.o subsystem_map.o
+obj-$(CONFIG_CPU_FREQ_MSM) += cpufreq.o
+obj-$(CONFIG_DEBUG_FS) += nohlt.o clock-debug.o
+obj-$(CONFIG_KEXEC) += msm_kexec.o
+
+obj-$(CONFIG_MSM_PROC_COMM) += proc_comm.o
+ifndef CONFIG_ARCH_MSM8X60
+	obj-$(CONFIG_MSM_PROC_COMM) += clock-pcom.o
+	obj-$(CONFIG_MSM_PROC_COMM) += vreg.o mpp.o
+	ifdef CONFIG_MSM_PROC_COMM
+ifndef CONFIG_ARCH_FSM9XXX
+		obj-$(CONFIG_REGULATOR) += footswitch-pcom.o
+endif
+		obj-$(CONFIG_DEBUG_FS) += pmic_debugfs.o
+	endif
+endif
+
+obj-y += acpuclock.o
+obj-$(CONFIG_ARCH_MSM7X27) += acpuclock-7627.o clock-pll.o
+obj-$(CONFIG_ARCH_MSM_SCORPION) += pmu.o
+obj-$(CONFIG_ARCH_MSM_KRAIT) += msm-krait-l2-accessors.o pmu.o
+obj-$(CONFIG_ARCH_MSM7X27A) += pmu.o
+
+ifndef CONFIG_MSM_SMP
+obj-$(CONFIG_ARCH_MSM_SCORPION) += msm_fault_handlers.o
+endif
+
+obj-$(CONFIG_MSM_VIC) += irq-vic.o
+
+ifdef CONFIG_ARCH_QSD8X50
+	obj-$(CONFIG_MSM_SOC_REV_NONE) += acpuclock-8x50.o
+endif
+
+obj-$(CONFIG_SMP) += headsmp.o
+ifdef CONFIG_ARCH_MSM8625
+	obj-$(CONFIG_SMP) += platsmp-8625.o
+else
+	obj-$(CONFIG_SMP) += platsmp.o
+endif
 obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
-obj-$(CONFIG_SMP) += headsmp.o platsmp.o
 
-obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o board-trout-mmc.o devices-msm7x00.o
-obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o board-trout-mmc.o board-trout-panel.o devices-msm7x00.o
-obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o devices-msm7x00.o
-obj-$(CONFIG_ARCH_MSM7X30) += board-msm7x30.o devices-msm7x30.o
-obj-$(CONFIG_ARCH_QSD8X50) += board-qsd8x50.o devices-qsd8x50.o
-obj-$(CONFIG_ARCH_MSM8X60) += board-msm8x60.o
-obj-$(CONFIG_ARCH_MSM8960) += board-msm8960.o devices-msm8960.o
+obj-$(CONFIG_MSM_CPU_AVS) += avs.o
+obj-$(CONFIG_MSM_AVS_HW) += avs_hw.o
+obj-$(CONFIG_CPU_V6) += idle-v6.o
+obj-$(CONFIG_CPU_V7) += idle-v7.o
+obj-$(CONFIG_MSM_JTAG) += jtag.o
 
-obj-$(CONFIG_ARCH_MSM7X30) += gpiomux-v1.o gpiomux.o
+msm-etm-objs := etm.o
+obj-$(CONFIG_MSM_ETM) += msm-etm.o
+obj-$(CONFIG_MSM_QDSS) += qdss.o qdss-etb.o qdss-tpiu.o qdss-funnel.o qdss-etm.o
+
+quiet_cmd_mkrpcsym = MKCAP   $@
+      cmd_mkrpcsym = $(PERL) $(srctree)/$(src)/mkrpcsym.pl $< $@
+
+target += smd_rpc_sym.c
+$(obj)/smd_rpc_sym.c: $(src)/smd_rpc_sym $(src)/mkrpcsym.pl
+	$(call if_changed,mkrpcsym)
+
+obj-$(CONFIG_MSM_SCM) += scm.o scm-boot.o
+obj-$(CONFIG_MSM_SECURE_IO) += scm-io.o
+obj-$(CONFIG_MSM_PIL) += peripheral-loader.o
+obj-$(CONFIG_MSM_PIL) += scm-pas.o
+obj-$(CONFIG_MSM_PIL_QDSP6V3) += pil-q6v3.o
+obj-$(CONFIG_MSM_PIL_QDSP6V4) += pil-q6v4.o
+obj-$(CONFIG_MSM_PIL_LPASS_QDSP6V5) += pil-q6v5.o pil-q6v5-lpass.o
+obj-$(CONFIG_MSM_PIL_RIVA) += pil-riva.o
+obj-$(CONFIG_MSM_PIL_TZAPPS) += pil-tzapps.o
+obj-$(CONFIG_MSM_PIL_VIDC) += pil-vidc.o
+obj-$(CONFIG_MSM_PIL_MODEM) += pil-modem.o
+obj-$(CONFIG_MSM_PIL_DSPS) += pil-dsps.o
+obj-$(CONFIG_MSM_PIL_GSS) += pil-gss.o
+obj-$(CONFIG_MSM_PIL_PRONTO) += pil-pronto.o
+obj-$(CONFIG_ARCH_QSD8X50) += sirc.o
+obj-$(CONFIG_ARCH_FSM9XXX) += sirc-fsm9xxx.o
+obj-$(CONFIG_MSM_FIQ_SUPPORT) += fiq_glue.o
+obj-$(CONFIG_MACH_TROUT) += board-trout-rfkill.o
+obj-$(CONFIG_MSM_SDIO_AL) += sdio_al.o
+obj-$(CONFIG_MSM_SDIO_AL) += sdio_al_test.o
+obj-$(CONFIG_MSM_SDIO_AL) += sdio_al_dloader.o
+obj-$(CONFIG_MSM_SDIO_DMUX) += sdio_dmux.o
+obj-$(CONFIG_MSM_BAM_DMUX) += bam_dmux.o
+obj-$(CONFIG_MSM_SMD_LOGGING) += smem_log.o
+obj-$(CONFIG_MSM_IPC_LOGGING) += ipc_logging.o
+ifdef CONFIG_DEBUG_FS
+obj-$(CONFIG_MSM_IPC_LOGGING) += ipc_logging_debug.o
+endif
+obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o remote_spinlock.o smd_private.o
+obj-y += socinfo.o
+ifndef CONFIG_ARCH_MSM9615
+ifndef CONFIG_ARCH_APQ8064
+ifndef CONFIG_ARCH_MSM8960
+ifndef CONFIG_ARCH_MSM8X60
+ifndef CONFIG_ARCH_MSMCOPPER
+	obj-$(CONFIG_MSM_SMD) += pmic.o
+	obj-$(CONFIG_MSM_ONCRPCROUTER) += rpc_hsusb.o rpc_pmapp.o rpc_fsusb.o
+endif
+endif
+endif
+endif
+endif
+ifndef CONFIG_ARCH_MSM8960
+ifndef CONFIG_ARCH_MSM8X60
+ifndef CONFIG_ARCH_APQ8064
+ifndef CONFIG_ARCH_MSMCOPPER
+ifndef CONFIG_ARCH_MSM9625
+	obj-y += nand_partitions.o
+endif
+endif
+endif
+endif
+endif
+obj-$(CONFIG_MSM_SDIO_TTY) += sdio_tty.o
+obj-$(CONFIG_MSM_SMD_TTY) += smd_tty.o
+obj-$(CONFIG_MSM_SMD_QMI) += smd_qmi.o
+obj-$(CONFIG_MSM_SMD_PKT) += smd_pkt.o
+obj-$(CONFIG_MSM_SDIO_CMUX) += sdio_cmux.o
+obj-$(CONFIG_MSM_DSPS) += msm_dsps.o
+obj-$(CONFIG_MSM_SDIO_CTL) += sdio_ctl.o
+obj-$(CONFIG_MSM_SMD_NMEA) += smd_nmea.o
+obj-$(CONFIG_MSM_RESET_MODEM) += reset_modem.o
+obj-$(CONFIG_MSM_IPC_ROUTER_SMD_XPRT) += ipc_router_smd_xprt.o
+obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter.o
+obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_device.o
+obj-$(CONFIG_MSM_IPC_ROUTER) += ipc_router.o
+obj-$(CONFIG_MSM_IPC_ROUTER)+= ipc_socket.o
+obj-$(CONFIG_DEBUG_FS) += smd_rpc_sym.o
+obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_servers.o
+obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_clients.o
+obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_xdr.o
+obj-$(CONFIG_MSM_ONCRPCROUTER) += rpcrouter_smd_xprt.o
+obj-$(CONFIG_MSM_RPC_SDIO_XPRT) += rpcrouter_sdio_xprt.o
+obj-$(CONFIG_MSM_RPC_PING) += ping_mdm_rpc_client.o
+obj-$(CONFIG_MSM_RPC_PROC_COMM_TEST) += proc_comm_test.o
+obj-$(CONFIG_MSM_RPC_PING) += ping_mdm_rpc_client.o ping_apps_server.o
+obj-$(CONFIG_MSM_RPC_OEM_RAPI) += oem_rapi_client.o
+obj-$(CONFIG_MSM_RPC_WATCHDOG) += rpc_dog_keepalive.o
+obj-$(CONFIG_MSM_RPCSERVER_WATCHDOG) += rpc_server_dog_keepalive.o
+obj-$(CONFIG_MSM_RPCSERVER_TIME_REMOTE) += rpc_server_time_remote.o
+obj-$(CONFIG_MSM_DALRPC) += dal.o
+obj-$(CONFIG_MSM_DALRPC_TEST) += dal_remotetest.o
+obj-$(CONFIG_ARCH_MSM7X30) += dal_axi.o
+obj-$(CONFIG_ARCH_MSM7X27A) += dal_axi.o
+obj-$(CONFIG_MSM_ADSP) += qdsp5/
+obj-$(CONFIG_MSM7KV2_AUDIO) += qdsp5v2/
+obj-$(CONFIG_MSM_RPCSERVER_HANDSET) += rpc_server_handset.o
+obj-$(CONFIG_MSM_QDSP6) += qdsp6/
+obj-$(CONFIG_MSM8X60_AUDIO) += qdsp6v2/
+obj-$(CONFIG_MSM_AUDIO_QDSP6) += qdsp6v2/
+obj-$(CONFIG_MSM_HW3D) += hw3d.o
+obj-$(CONFIG_PM) += pm-boot.o
+obj-$(CONFIG_MSM_PM8X60) += pm-8x60.o pm-data.o
+obj-$(CONFIG_MSM_IDLE_STATS) += pm-stats.o
+obj-$(CONFIG_MSM_PM2) += pm2.o
+obj-$(CONFIG_MSM_NOPM) += no-pm.o
+
+obj-$(CONFIG_MSM_PCIE) += pcie.o pcie_irq.o
+
+obj-$(CONFIG_MSM_SPM_V1) += spm.o
+obj-$(CONFIG_MSM_SPM_V2) += spm-v2.o spm_devices.o
+
+obj-$(CONFIG_MSM_DMA_TEST) += dma_test.o
+obj-$(CONFIG_SURF_FFA_GPIO_KEYPAD) += keypad-surf-ffa.o
+
+obj-$(CONFIG_ARCH_MSM7X01A) += board-halibut.o devices-msm7x01a.o clock-pcom-lookup.o
+obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o
+obj-$(CONFIG_MACH_TROUT) += board-trout-keypad.o board-trout-panel.o
+obj-$(CONFIG_MACH_TROUT) += htc_akm_cal.o htc_wifi_nvs.o htc_acoustic.o
+obj-$(CONFIG_MACH_TROUT) += board-trout-mmc.o board-trout-wifi.o
+obj-$(CONFIG_ARCH_QSD8X50) += devices-qsd8x50.o clock-pcom-lookup.o
+obj-$(CONFIG_MACH_QSD8X50_SURF) += board-qsd8x50.o
+obj-$(CONFIG_MACH_QSD8X50_FFA) += board-qsd8x50.o
+obj-$(CONFIG_ARCH_MSM8X60) += devices-msm8x60.o clock-local.o clock-8x60.o acpuclock-8x60.o clock-pll.o
+obj-$(CONFIG_ARCH_MSM8X60) += clock-rpm.o
+obj-$(CONFIG_ARCH_MSM8X60) += saw-regulator.o
+obj-$(CONFIG_ARCH_MSM8X60) += footswitch-8x60.o
+
+ifdef CONFIG_MSM_RPM_REGULATOR
+obj-y += rpm-regulator.o
+obj-$(CONFIG_ARCH_MSM8X60) += rpm-regulator-8660.o
+obj-$(CONFIG_ARCH_MSM8960) += rpm-regulator-8960.o
+obj-$(CONFIG_ARCH_MSM9615) += rpm-regulator-9615.o
+obj-$(CONFIG_ARCH_MSM8930) += rpm-regulator-8930.o
+obj-$(CONFIG_ARCH_APQ8064) += rpm-regulator-8960.o
+endif
+
+obj-$(CONFIG_MSM_RPM_REGULATOR_SMD) += rpm-regulator-smd.o
+
+ifdef CONFIG_MSM_SUBSYSTEM_RESTART
+	obj-y += subsystem_notif.o
+	obj-y += subsystem_restart.o
+	obj-y += ramdump.o
+	obj-$(CONFIG_ARCH_MSM8X60) += modem-8660.o lpass-8660.o
+endif
+obj-$(CONFIG_MSM_SYSMON_COMM) += sysmon.o
+obj-$(CONFIG_MSM_MODEM_8960) += modem-8960.o
+obj-$(CONFIG_MSM_LPASS_8960) += lpass-8960.o
+obj-$(CONFIG_MSM_WCNSS_SSR_8960) += wcnss-ssr-8960.o
+obj-$(CONFIG_MSM_GSS_SSR_8064) += gss-8064.o
+
+ifdef CONFIG_CPU_IDLE
+	obj-$(CONFIG_ARCH_APQ8064) += cpuidle.o
+	obj-$(CONFIG_ARCH_MSM8960) += cpuidle.o
+	obj-$(CONFIG_ARCH_MSM8X60) += cpuidle.o
+	obj-$(CONFIG_ARCH_MSM9615) += cpuidle.o
+	obj-$(CONFIG_ARCH_MSMCOPPER) += cpuidle.o
+endif
+
+ifdef CONFIG_MSM_CAMERA_V4L2
+	obj-$(CONFIG_ARCH_MSM8X60) += board-msm8x60-camera.o
+endif
+obj-$(CONFIG_ARCH_FSM9XXX) += devices-fsm9xxx.o
+obj-$(CONFIG_ARCH_FSM9XXX) += clock-fsm9xxx.o clock-local.o acpuclock-fsm9xxx.o
+obj-$(CONFIG_ARCH_FSM9XXX) += dfe-fsm9xxx.o rfic-fsm9xxx.o
+obj-$(CONFIG_ARCH_FSM9XXX) += restart-fsm9xxx.o xo-fsm9xxx.o
+
+obj-$(CONFIG_MSM_WATCHDOG) += msm_watchdog.o
+obj-$(CONFIG_MSM_WATCHDOG) += msm_watchdog_asm.o
+obj-$(CONFIG_MACH_MSM8X60_RUMI3) += board-msm8x60.o
+obj-$(CONFIG_MACH_MSM8X60_SIM) += board-msm8x60.o
+obj-$(CONFIG_MACH_MSM8X60_SURF) += board-msm8x60.o
+obj-$(CONFIG_MACH_MSM8X60_FFA) += board-msm8x60.o
+obj-$(CONFIG_MACH_MSM8X60_FLUID) += board-msm8x60.o
+obj-$(CONFIG_MACH_MSM8X60_DRAGON) += board-msm8x60.o
+obj-$(CONFIG_MACH_TYPE_MSM8X60_FUSION) += board-msm8x60.o mdm.o
+obj-$(CONFIG_MACH_MSM8X60_FUSN_FFA) += board-msm8x60.o mdm.o
+obj-$(CONFIG_TROUT_H2W) += board-trout-h2w.o
+obj-$(CONFIG_TROUT_BATTCHG) += htc_battery.o
+obj-$(CONFIG_TROUT_PWRSINK) += htc_pwrsink.o
+obj-$(CONFIG_ARCH_MSM7X27) += clock-pcom-lookup.o
+obj-$(CONFIG_MACH_MSM7X27_SURF) += board-msm7x27.o devices-msm7x27.o
+obj-$(CONFIG_MACH_MSM7X27_FFA) += board-msm7x27.o devices-msm7x27.o
+obj-$(CONFIG_ARCH_MSM7X27A) += clock-pcom-lookup.o devices-msm7x27a.o
+board-7627a-all-objs += board-msm7627a-storage.o board-msm7627a-bt.o board-msm7627a-camera.o
+board-7627a-all-objs += board-msm7627a-display.o board-msm7627a-wlan.o board-msm7627a-io.o
+obj-$(CONFIG_MACH_MSM7X27A_RUMI3) += board-msm7x27a.o board-7627a-all.o
+obj-$(CONFIG_MACH_MSM7X27A_SURF) += board-msm7x27a.o board-7627a-all.o
+obj-$(CONFIG_MACH_MSM7X27A_FFA) += board-msm7x27a.o board-7627a-all.o
+obj-$(CONFIG_MACH_MSM7627A_QRD1) += board-qrd7627a.o board-7627a-all.o
+obj-$(CONFIG_MACH_MSM7627A_QRD3) += board-qrd7627a.o board-7627a-all.o
+obj-$(CONFIG_MACH_MSM7627A_EVB) += board-qrd7627a.o board-7627a-all.o
+obj-$(CONFIG_ARCH_MSM8625) += devices-msm7x27a.o clock-pcom-lookup.o mpm-8625.o
+obj-$(CONFIG_MACH_MSM8625_RUMI3) += board-msm7x27a.o
+obj-$(CONFIG_MACH_MSM8625_SURF) +=  board-msm7x27a.o board-7627a-all.o
+obj-$(CONFIG_MACH_MSM8625_EVB) +=  board-qrd7627a.o board-7627a-all.o
+obj-$(CONFIG_MACH_MSM8625_QRD7) +=  board-qrd7627a.o board-7627a-all.o
+obj-$(CONFIG_MACH_MSM8625_FFA) += board-msm7x27a.o board-7627a-all.o
+obj-$(CONFIG_MACH_MSM8625_EVT) += board-msm7x27a.o board-7627a-all.o
+obj-$(CONFIG_ARCH_MSM7X30) += board-msm7x30.o devices-msm7x30.o memory_topology.o
+obj-$(CONFIG_ARCH_MSM7X30) += clock-local.o clock-7x30.o acpuclock-7x30.o clock-pll.o
+obj-$(CONFIG_MACH_MSM7X25_SURF) += board-msm7x27.o devices-msm7x25.o
+obj-$(CONFIG_MACH_MSM7X25_FFA) += board-msm7x27.o devices-msm7x25.o
+obj-$(CONFIG_ARCH_MSM8960) += clock-local.o clock-dss-8960.o clock-8960.o clock-rpm.o clock-pll.o
+obj-$(CONFIG_ARCH_MSM8960) += footswitch-8x60.o
+obj-$(CONFIG_ARCH_MSM8960) += acpuclock-8960.o
+obj-$(CONFIG_ARCH_MSM8960) += memory_topology.o
+obj-$(CONFIG_ARCH_MSM8960) += saw-regulator.o
+obj-$(CONFIG_ARCH_MSM8960) += devices-8960.o
+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-8930-gpu.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 board-8064-gpu.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
+obj-$(CONFIG_MACH_MSM8960_MTP) += board-8960-all.o board-8960-regulator.o
+obj-$(CONFIG_MACH_MSM8960_FLUID) += board-8960-all.o board-8960-regulator.o
+obj-$(CONFIG_MACH_MSM8930_CDP) += board-8930-all.o board-8930-regulator.o
+obj-$(CONFIG_MACH_MSM8930_MTP) += board-8930-all.o board-8930-regulator.o
+obj-$(CONFIG_MACH_MSM8930_FLUID) += board-8930-all.o board-8930-regulator.o
+obj-$(CONFIG_PM8921_BMS) += bms-batterydata.o bms-batterydata-desay.o
+obj-$(CONFIG_MACH_APQ8064_SIM) += board-8064-all.o board-8064-regulator.o
+obj-$(CONFIG_MACH_APQ8064_RUMI3) += board-8064-all.o board-8064-regulator.o
+obj-$(CONFIG_MACH_APQ8064_CDP) += board-8064-all.o board-8064-regulator.o
+obj-$(CONFIG_MACH_APQ8064_MTP) += board-8064-all.o board-8064-regulator.o
+obj-$(CONFIG_MACH_APQ8064_LIQUID) += board-8064-all.o board-8064-regulator.o
+obj-$(CONFIG_MACH_MPQ8064_HRD) += board-8064-all.o board-8064-regulator.o
+obj-$(CONFIG_MACH_MPQ8064_DTV) += board-8064-all.o board-8064-regulator.o
+obj-$(CONFIG_ARCH_MSM9615) += board-9615.o devices-9615.o board-9615-regulator.o board-9615-gpiomux.o board-9615-storage.o board-9615-display.o
+obj-$(CONFIG_ARCH_MSM9615) += clock-local.o clock-9615.o acpuclock-9615.o clock-rpm.o clock-pll.o
+obj-$(CONFIG_ARCH_MSMCOPPER) += board-copper.o board-dt.o board-copper-regulator.o board-copper-gpiomux.o
+obj-$(CONFIG_ARCH_MSMCOPPER) += acpuclock-krait.o acpuclock-copper.o
+obj-$(CONFIG_ARCH_MSMCOPPER) += clock-local2.o clock-pll.o clock-copper.o
+obj-$(CONFIG_ARCH_MSMCOPPER) += gdsc.o
+obj-$(CONFIG_ARCH_MSM9625) += board-9625.o board-9625-gpiomux.o
+
+obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
+obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o
+obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-mmc.o board-sapphire-wifi.o
+obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-rfkill.o msm_vibrator.o
+
+CFLAGS_msm_vibrator.o += -Idrivers/staging/android
+
+obj-$(CONFIG_ARCH_FSM9XXX) += board-fsm9xxx.o
+
+obj-$(CONFIG_TROUT_BATTCHG) += htc_battery.o
+
+obj-$(CONFIG_HTC_PWRSINK) += htc_pwrsink.o
+obj-$(CONFIG_HTC_HEADSET) += htc_headset.o
+obj-$(CONFIG_MSM_RMT_STORAGE_CLIENT) += rmt_storage_client.o
+obj-$(CONFIG_MSM_SDIO_SMEM) += sdio_smem.o
+obj-$(CONFIG_MSM_RPM) += rpm.o
+ifdef CONFIG_MSM_RPM
+	obj-$(CONFIG_ARCH_APQ8064) += rpm_resources.o
+	obj-$(CONFIG_ARCH_MSM8960) += rpm_resources.o
+	obj-$(CONFIG_ARCH_MSM8X60) += rpm_resources.o
+	obj-$(CONFIG_ARCH_MSM9615) += rpm_resources.o
+	obj-$(CONFIG_ARCH_MSMCOPPER) += lpm_levels.o
+endif
+obj-$(CONFIG_MSM_MPM) += mpm.o
+obj-$(CONFIG_MSM_RPM_STATS_LOG) += rpm_stats.o
+obj-$(CONFIG_MSM_RPM_LOG) += rpm_log.o
+obj-$(CONFIG_MSM_TZ_LOG) += tz_log.o
+obj-$(CONFIG_MSM_XO) += msm_xo.o
+obj-$(CONFIG_MSM_BUS_SCALING) += msm_bus/
+obj-$(CONFIG_MSM_BUSPM_DEV) += msm-buspm-dev.o
+
+obj-$(CONFIG_MSM_IOMMU)		+= devices-iommu.o iommu_domains.o
+
+ifdef CONFIG_VCM
+obj-$(CONFIG_ARCH_MSM8X60) += board-msm8x60-vcm.o
+endif
+obj-$(CONFIG_MSM_OCMEM) += ocmem.o ocmem_allocator.o
+
+obj-$(CONFIG_ARCH_MSM7X27) += gpiomux-7x27.o gpiomux-v1.o gpiomux.o
+obj-$(CONFIG_ARCH_MSM7X30) += gpiomux-7x30.o gpiomux-v1.o gpiomux.o
 obj-$(CONFIG_ARCH_QSD8X50) += gpiomux-8x50.o gpiomux-v1.o gpiomux.o
 obj-$(CONFIG_ARCH_MSM8X60) += gpiomux-8x60.o gpiomux-v2.o gpiomux.o
+obj-$(CONFIG_ARCH_MSM8960) += gpiomux-v2.o gpiomux.o
+obj-$(CONFIG_ARCH_APQ8064) += gpiomux-v2.o gpiomux.o
+obj-$(CONFIG_ARCH_MSM9615) += gpiomux-v2.o gpiomux.o
+obj-$(CONFIG_ARCH_MSMCOPPER) += gpiomux-v2.o gpiomux.o
+obj-$(CONFIG_ARCH_MSM9625) += gpiomux-v2.o gpiomux.o
+
+
+obj-$(CONFIG_MSM_SLEEP_STATS) += idle_stats.o
+obj-$(CONFIG_MSM_SLEEP_STATS_DEVICE) += idle_stats_device.o
+obj-$(CONFIG_MSM_DCVS) += msm_dcvs_scm.o msm_dcvs.o msm_dcvs_idle.o
+obj-$(CONFIG_MSM_RUN_QUEUE_STATS) += msm_rq_stats.o
+obj-$(CONFIG_MSM_SHOW_RESUME_IRQ) += msm_show_resume_irq.o
+obj-$(CONFIG_BT_MSM_PINTEST)  += btpintest.o
+obj-$(CONFIG_MSM_FAKE_BATTERY) += fish_battery.o
+obj-$(CONFIG_MSM_RPC_VIBRATOR) += msm_vibrator.o
+obj-$(CONFIG_MSM_NATIVE_RESTART) += restart.o
+
+obj-$(CONFIG_MSM_PROC_COMM_REGULATOR) += proccomm-regulator.o
+ifdef CONFIG_MSM_PROC_COMM_REGULATOR
+obj-$(CONFIG_MACH_MSM7X27_SURF) += board-msm7627-regulator.o
+obj-$(CONFIG_MACH_MSM7X27_FFA) += board-msm7627-regulator.o
+obj-$(CONFIG_ARCH_MSM7X30) += board-msm7x30-regulator.o
+obj-$(CONFIG_ARCH_MSM7X27A) += board-msm7x27a-regulator.o
+endif
+
+obj-$(CONFIG_ARCH_MSM8960) += mdm2.o mdm_common.o
+obj-$(CONFIG_MSM_RTB) += msm_rtb.o
+obj-$(CONFIG_MSM_CACHE_ERP) += cache_erp.o
+obj-$(CONFIG_MSM_CACHE_DUMP) += msm_cache_dump.o
+
+obj-$(CONFIG_MSM_HSIC_SYSMON) += hsic_sysmon.o
+obj-$(CONFIG_MSM_HSIC_SYSMON_TEST) += hsic_sysmon_test.o
+
+obj-$(CONFIG_MSM_RPM_SMD) += rpm-smd.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 9b803a5..bd8d153 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -1,3 +1,60 @@
-  zreladdr-y		+= 0x10008000
-params_phys-y		:= 0x10000100
-initrd_phys-y		:= 0x10800000
+# MSM7x01A
+   zreladdr-$(CONFIG_ARCH_MSM7X01A)	:= 0x10008000
+params_phys-$(CONFIG_ARCH_MSM7X01A)	:= 0x10000100
+initrd_phys-$(CONFIG_ARCH_MSM7X01A)	:= 0x10800000
+
+# MSM7x25
+   zreladdr-$(CONFIG_ARCH_MSM7X25)	:= 0x00208000
+params_phys-$(CONFIG_ARCH_MSM7X25)	:= 0x00200100
+initrd_phys-$(CONFIG_ARCH_MSM7X25)	:= 0x0A000000
+
+# MSM7x27
+   zreladdr-$(CONFIG_ARCH_MSM7X27)	:= 0x00208000
+params_phys-$(CONFIG_ARCH_MSM7X27)	:= 0x00200100
+initrd_phys-$(CONFIG_ARCH_MSM7X27)	:= 0x0A000000
+
+# MSM7x27A
+   zreladdr-$(CONFIG_ARCH_MSM7X27A)	:= 0x00208000
+params_phys-$(CONFIG_ARCH_MSM7X27A)	:= 0x00200100
+
+# MSM8625
+   zreladdr-$(CONFIG_ARCH_MSM8625)	:= 0x00208000
+params_phys-$(CONFIG_ARCH_MSM8625)	:= 0x00200100
+
+# MSM7x30
+   zreladdr-$(CONFIG_ARCH_MSM7X30)	:= 0x00208000
+params_phys-$(CONFIG_ARCH_MSM7X30)	:= 0x00200100
+initrd_phys-$(CONFIG_ARCH_MSM7X30)	:= 0x01200000
+
+ifeq ($(CONFIG_MSM_SOC_REV_A),y)
+# QSD8x50
+   zreladdr-$(CONFIG_ARCH_QSD8X50)	:= 0x20008000
+params_phys-$(CONFIG_ARCH_QSD8X50)	:= 0x20000100
+initrd_phys-$(CONFIG_ARCH_QSD8X50)	:= 0x24000000
+endif
+
+# MSM8x60
+   zreladdr-$(CONFIG_ARCH_MSM8X60)	:= 0x40208000
+
+# MSM8960
+   zreladdr-$(CONFIG_ARCH_MSM8960)	:= 0x80208000
+
+# MSM8930
+   zreladdr-$(CONFIG_ARCH_MSM8930)	:= 0x80208000
+
+# APQ8064
+   zreladdr-$(CONFIG_ARCH_APQ8064)	:= 0x80208000
+
+# MSMCOPPER
+   zreladdr-$(CONFIG_ARCH_MSMCOPPER)	:= 0x00008000
+
+# MSM9615
+   zreladdr-$(CONFIG_ARCH_MSM9615)	:= 0x40808000
+
+# MSM9625
+   zreladdr-$(CONFIG_ARCH_MSM9625)	:= 0x20208000
+
+# FSM9XXX
+   zreladdr-$(CONFIG_ARCH_FSM9XXX)	:= 0x10008000
+params_phys-$(CONFIG_ARCH_FSM9XXX)	:= 0x10000100
+initrd_phys-$(CONFIG_ARCH_FSM9XXX)	:= 0x12000000
diff --git a/arch/arm/mach-msm/acpuclock-7627.c b/arch/arm/mach-msm/acpuclock-7627.c
new file mode 100644
index 0000000..7c2c556
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock-7627.c
@@ -0,0 +1,992 @@
+/*
+ * MSM architecture clock driver
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2012, Code Aurora Forum. All rights reserved.
+ * Author: San Mehat <san@android.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/sort.h>
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+#include <mach/socinfo.h>
+#include <asm/mach-types.h>
+#include <asm/cpu.h>
+
+#include "smd_private.h"
+#include "acpuclock.h"
+
+#define A11S_CLK_CNTL_ADDR (MSM_CSR_BASE + 0x100)
+#define A11S_CLK_SEL_ADDR (MSM_CSR_BASE + 0x104)
+#define A11S_VDD_SVS_PLEVEL_ADDR (MSM_CSR_BASE + 0x124)
+
+
+#define POWER_COLLAPSE_KHZ 19200
+
+/* Max CPU frequency allowed by hardware while in standby waiting for an irq. */
+#define MAX_WAIT_FOR_IRQ_KHZ 128000
+
+/**
+ * enum - For acpuclock PLL IDs
+ */
+enum {
+	ACPU_PLL_0	= 0,
+	ACPU_PLL_1,
+	ACPU_PLL_2,
+	ACPU_PLL_3,
+	ACPU_PLL_4,
+	ACPU_PLL_TCXO,
+	ACPU_PLL_END,
+};
+
+struct acpu_clk_src {
+	struct clk *clk;
+	const char *name;
+};
+
+static struct acpu_clk_src pll_clk[ACPU_PLL_END] = {
+	[ACPU_PLL_0] = { .name = "pll0_clk" },
+	[ACPU_PLL_1] = { .name = "pll1_clk" },
+	[ACPU_PLL_2] = { .name = "pll2_clk" },
+	[ACPU_PLL_4] = { .name = "pll4_clk" },
+};
+
+struct clock_state {
+	struct clkctl_acpu_speed	*current_speed;
+	struct mutex			lock;
+	uint32_t			max_speed_delta_khz;
+	struct clk			*ebi1_clk;
+};
+
+struct clkctl_acpu_speed {
+	unsigned int	use_for_scaling;
+	unsigned int	a11clk_khz;
+	int		pll;
+	unsigned int	a11clk_src_sel;
+	unsigned int	a11clk_src_div;
+	unsigned int	ahbclk_khz;
+	unsigned int	ahbclk_div;
+	int		vdd;
+	unsigned int	axiclk_khz;
+	unsigned long   lpj; /* loops_per_jiffy */
+	/* Pointers in acpu_freq_tbl[] for max up/down steppings. */
+	struct clkctl_acpu_speed *down[ACPU_PLL_END];
+	struct clkctl_acpu_speed *up[ACPU_PLL_END];
+};
+
+static struct clock_state drv_state = { 0 };
+static struct clkctl_acpu_speed *acpu_freq_tbl;
+
+/*
+ * ACPU freq tables used for different PLLs frequency combinations. The
+ * correct table is selected during init.
+ *
+ * Table stepping up/down entries are calculated during boot to choose the
+ * largest frequency jump that's less than max_speed_delta_khz on each PLL.
+ */
+
+/* 7627 with GSM capable modem */
+static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_1200_pll4_0[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 30720 },
+	{ 0, 120000, ACPU_PLL_0, 4, 7,  60000, 1, 3,  61440 },
+	{ 1, 122880, ACPU_PLL_1, 1, 1,  61440, 1, 3,  61440 },
+	{ 0, 200000, ACPU_PLL_2, 2, 5,  66667, 2, 4,  61440 },
+	{ 1, 245760, ACPU_PLL_1, 1, 0, 122880, 1, 4,  61440 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 160000, 1, 5, 160000 },
+	{ 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 160000 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 160000 },
+	{ 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 200000 },
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+};
+
+/* 7627 with CDMA capable modem */
+static struct clkctl_acpu_speed pll0_960_pll1_196_pll2_1200_pll4_0[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 24576 },
+	{ 1,  98304, ACPU_PLL_1, 1, 1,  98304, 0, 3,  49152 },
+	{ 0, 120000, ACPU_PLL_0, 4, 7,  60000, 1, 3,  49152 },
+	{ 1, 196608, ACPU_PLL_1, 1, 0,  65536, 2, 4,  98304 },
+	{ 0, 200000, ACPU_PLL_2, 2, 5,  66667, 2, 4,  98304 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 160000, 1, 5, 160000 },
+	{ 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 160000 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 160000 },
+	{ 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 200000 },
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+};
+
+/* 7627 with GSM capable modem - PLL2 @ 800 */
+static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_800_pll4_0[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 30720 },
+	{ 0, 120000, ACPU_PLL_0, 4, 7,  60000, 1, 3,  61440 },
+	{ 1, 122880, ACPU_PLL_1, 1, 1,  61440, 1, 3,  61440 },
+	{ 0, 200000, ACPU_PLL_2, 2, 3,  66667, 2, 4,  61440 },
+	{ 1, 245760, ACPU_PLL_1, 1, 0, 122880, 1, 4,  61440 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 160000, 1, 5, 160000 },
+	{ 0, 400000, ACPU_PLL_2, 2, 1, 133333, 2, 5, 160000 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 160000 },
+	{ 1, 800000, ACPU_PLL_2, 2, 0, 200000, 3, 7, 200000 },
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+};
+
+/* 7627 with CDMA capable modem - PLL2 @ 800 */
+static struct clkctl_acpu_speed pll0_960_pll1_196_pll2_800_pll4_0[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 24576 },
+	{ 1,  98304, ACPU_PLL_1, 1, 1,  98304, 0, 3,  49152 },
+	{ 0, 120000, ACPU_PLL_0, 4, 7,  60000, 1, 3,  49152 },
+	{ 1, 196608, ACPU_PLL_1, 1, 0,  65536, 2, 4,  98304 },
+	{ 0, 200000, ACPU_PLL_2, 2, 3,  66667, 2, 4,  98304 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 160000, 1, 5, 160000 },
+	{ 0, 400000, ACPU_PLL_2, 2, 1, 133333, 2, 5, 160000 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 160000 },
+	{ 1, 800000, ACPU_PLL_2, 2, 0, 200000, 3, 7, 200000 },
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+};
+
+/* 7627a PLL2 @ 1200MHz with GSM capable modem */
+static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_1200_pll4_800[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
+	{ 0, 61440, ACPU_PLL_1, 1, 3,  7680, 3, 1,  61440 },
+	{ 1, 122880, ACPU_PLL_1, 1, 1,  15360, 3, 2,  61440 },
+	{ 1, 245760, ACPU_PLL_1, 1, 0, 30720, 3, 3,  61440 },
+	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
+	{ 0, 400000, ACPU_PLL_4, 6, 1, 50000, 3, 4, 122880 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
+	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
+	{ 1, 800000, ACPU_PLL_4, 6, 0, 100000, 3, 7, 200000 },
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+};
+
+/* 7627a PLL2 @ 1200MHz with CDMA capable modem */
+static struct clkctl_acpu_speed pll0_960_pll1_196_pll2_1200_pll4_800[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 24576 },
+	{ 0, 65536, ACPU_PLL_1, 1, 3,  8192, 3, 1,  49152 },
+	{ 1, 98304, ACPU_PLL_1, 1, 1,  12288, 3, 2,  49152 },
+	{ 1, 196608, ACPU_PLL_1, 1, 0, 24576, 3, 3,  98304 },
+	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 120000 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 120000 },
+	{ 0, 400000, ACPU_PLL_4, 6, 1, 50000, 3, 4, 120000 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 120000 },
+	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
+	{ 1, 800000, ACPU_PLL_4, 6, 0, 100000, 3, 7, 200000 },
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+};
+
+/* 7627aa PLL4 @ 1008MHz with GSM capable modem */
+static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_1200_pll4_1008[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
+	{ 0, 61440, ACPU_PLL_1, 1, 3,  7680, 3, 1, 61440 },
+	{ 1, 122880, ACPU_PLL_1, 1, 1,  15360, 3, 2, 61440 },
+	{ 1, 245760, ACPU_PLL_1, 1, 0, 30720, 3, 3, 61440 },
+	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
+	{ 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 160000 },
+	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
+	{ 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, 7, 200000},
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+};
+
+/* 7627aa PLL4 @ 1008MHz with CDMA capable modem */
+static struct clkctl_acpu_speed pll0_960_pll1_196_pll2_1200_pll4_1008[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 24576 },
+	{ 0, 65536, ACPU_PLL_1, 1, 3,  8192, 3, 1, 49152 },
+	{ 1, 98304, ACPU_PLL_1, 1, 1,  12288, 3, 2, 49152 },
+	{ 1, 196608, ACPU_PLL_1, 1, 0, 24576, 3, 3, 98304 },
+	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
+	{ 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 160000 },
+	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
+	{ 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, 7, 200000},
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+};
+
+/* 8625 PLL4 @ 1209MHz with GSM capable modem */
+static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_1200_pll4_1209[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
+	{ 0, 61440, ACPU_PLL_1, 1, 3,  7680, 3, 1, 61440 },
+	{ 1, 122880, ACPU_PLL_1, 1, 1,  15360, 3, 2, 61440 },
+	{ 1, 245760, ACPU_PLL_1, 1, 0, 30720, 3, 3, 61440 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
+	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
+	{ 0, 604800, ACPU_PLL_4, 6, 1, 75600, 3, 6, 160000 },
+	{ 1, 1209600, ACPU_PLL_4, 6, 0, 151200, 3, 7, 200000},
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+};
+
+/* 8625 PLL4 @ 1209MHz with CDMA capable modem */
+static struct clkctl_acpu_speed pll0_960_pll1_196_pll2_1200_pll4_1209[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 24576 },
+	{ 0, 65536, ACPU_PLL_1, 1, 3,  8192, 3, 1, 49152 },
+	{ 1, 98304, ACPU_PLL_1, 1, 1,  12288, 3, 2, 49152 },
+	{ 1, 196608, ACPU_PLL_1, 1, 0, 24576, 3, 3, 98304 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
+	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
+	{ 0, 604800, ACPU_PLL_4, 6, 1, 75600, 3, 6, 160000 },
+	{ 1, 1209600, ACPU_PLL_4, 6, 0, 151200, 3, 7, 200000},
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+};
+
+/* 8625 PLL4 @ 1152MHz with GSM capable modem */
+static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_1200_pll4_1152[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
+	{ 0, 61440, ACPU_PLL_1, 1, 3,  7680, 3, 1, 61440 },
+	{ 1, 122880, ACPU_PLL_1, 1, 1,  15360, 3, 2, 61440 },
+	{ 1, 245760, ACPU_PLL_1, 1, 0, 30720, 3, 3, 61440 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
+	{ 0, 576000, ACPU_PLL_4, 6, 1, 72000, 3, 6, 160000 },
+	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
+	{ 1, 1152000, ACPU_PLL_4, 6, 0, 144000, 3, 7, 200000},
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+};
+
+/* 8625 PLL4 @ 1115MHz with CDMA capable modem */
+static struct clkctl_acpu_speed pll0_960_pll1_196_pll2_1200_pll4_1152[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 24576 },
+	{ 0, 65536, ACPU_PLL_1, 1, 3,  8192, 3, 1, 49152 },
+	{ 1, 98304, ACPU_PLL_1, 1, 1,  12288, 3, 2, 49152 },
+	{ 1, 196608, ACPU_PLL_1, 1, 0, 24576, 3, 3, 98304 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
+	{ 0, 576000, ACPU_PLL_4, 6, 1, 72000, 3, 6, 160000 },
+	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
+	{ 1, 1152000, ACPU_PLL_4, 6, 0, 144000, 3, 7, 200000},
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+};
+
+
+/* 7625a PLL2 @ 1200MHz with GSM capable modem */
+static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_1200_25a[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
+	{ 0, 61440, ACPU_PLL_1, 1, 3,  7680, 3, 1,  61440 },
+	{ 1, 122880, ACPU_PLL_1, 1, 1,  15360, 3, 2,  61440 },
+	{ 1, 245760, ACPU_PLL_1, 1, 0, 30720, 3, 3,  61440 },
+	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
+	{ 0, 400000, ACPU_PLL_2, 2, 2, 50000, 3, 4, 122880 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
+	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+};
+
+/* 7627a PLL2 @ 1200MHz with GSM capable modem */
+static struct clkctl_acpu_speed pll0_960_pll1_737_pll2_1200_pll4_800[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
+	{ 0, 61440, ACPU_PLL_1, 1, 11,  7680, 3, 1,  61440 },
+	{ 1, 122880, ACPU_PLL_1, 1, 5,  15360, 3, 2,  61440 },
+	{ 1, 245760, ACPU_PLL_1, 1, 2, 30720, 3, 3,  61440 },
+	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
+	{ 0, 400000, ACPU_PLL_4, 6, 1, 50000, 3, 4, 122880 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
+	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
+	{ 1, 800000, ACPU_PLL_4, 6, 0, 100000, 3, 7, 200000 },
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+};
+
+/* 7627a PLL2 @ 1200MHz with CDMA capable modem */
+static struct clkctl_acpu_speed pll0_960_pll1_589_pll2_1200_pll4_800[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 24576 },
+	{ 0, 65536, ACPU_PLL_1, 1, 8,  8192, 3, 1,  49152 },
+	{ 1, 98304, ACPU_PLL_1, 1, 5,  12288, 3, 2,  49152 },
+	{ 1, 196608, ACPU_PLL_1, 1, 2, 24576, 3, 3,  98304 },
+	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 120000 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 120000 },
+	{ 0, 400000, ACPU_PLL_4, 6, 1, 50000, 3, 4, 120000 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 120000 },
+	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
+	{ 1, 800000, ACPU_PLL_4, 6, 0, 100000, 3, 7, 200000 },
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+};
+
+/* 7627aa PLL4 @ 1008MHz with GSM capable modem */
+static struct clkctl_acpu_speed pll0_960_pll1_737_pll2_1200_pll4_1008[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
+	{ 0, 61440, ACPU_PLL_1, 1, 11,  7680, 3, 1, 61440 },
+	{ 1, 122880, ACPU_PLL_1, 1, 5,  15360, 3, 2, 61440 },
+	{ 1, 245760, ACPU_PLL_1, 1, 2, 30720, 3, 3, 61440 },
+	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
+	{ 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 160000 },
+	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
+	{ 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, 7, 200000},
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+};
+
+/* 7627aa PLL4 @ 1008MHz with CDMA capable modem */
+static struct clkctl_acpu_speed pll0_960_pll1_589_pll2_1200_pll4_1008[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 24576 },
+	{ 0, 65536, ACPU_PLL_1, 1, 8,  8192, 3, 1, 49152 },
+	{ 1, 98304, ACPU_PLL_1, 1, 5,  12288, 3, 2, 49152 },
+	{ 1, 196608, ACPU_PLL_1, 1, 2, 24576, 3, 3, 98304 },
+	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
+	{ 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 160000 },
+	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
+	{ 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, 7, 200000},
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+};
+
+/* 7625a PLL2 @ 1200MHz with GSM capable modem */
+static struct clkctl_acpu_speed pll0_960_pll1_737_pll2_1200_25a[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
+	{ 0, 61440, ACPU_PLL_1, 1, 11,  7680, 3, 1,  61440 },
+	{ 1, 122880, ACPU_PLL_1, 1, 5,  15360, 3, 2,  61440 },
+	{ 1, 245760, ACPU_PLL_1, 1, 2, 30720, 3, 3,  61440 },
+	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
+	{ 0, 400000, ACPU_PLL_2, 2, 2, 50000, 3, 4, 122880 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
+	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+};
+
+#define PLL_CONFIG(m0, m1, m2, m4) { \
+	m0, m1, m2, m4, \
+	pll0_##m0##_pll1_##m1##_pll2_##m2##_pll4_##m4 \
+}
+
+struct pll_freq_tbl_map {
+	unsigned int	pll0_rate;
+	unsigned int	pll1_rate;
+	unsigned int	pll2_rate;
+	unsigned int	pll4_rate;
+	struct clkctl_acpu_speed *tbl;
+};
+
+static struct pll_freq_tbl_map acpu_freq_tbl_list[] = {
+	PLL_CONFIG(960, 196, 1200, 0),
+	PLL_CONFIG(960, 245, 1200, 0),
+	PLL_CONFIG(960, 196, 800, 0),
+	PLL_CONFIG(960, 245, 800, 0),
+	PLL_CONFIG(960, 245, 1200, 800),
+	PLL_CONFIG(960, 196, 1200, 800),
+	PLL_CONFIG(960, 245, 1200, 1008),
+	PLL_CONFIG(960, 196, 1200, 1008),
+	PLL_CONFIG(960, 737, 1200, 800),
+	PLL_CONFIG(960, 589, 1200, 800),
+	PLL_CONFIG(960, 737, 1200, 1008),
+	PLL_CONFIG(960, 589, 1200, 1008),
+	PLL_CONFIG(960, 245, 1200, 1209),
+	PLL_CONFIG(960, 196, 1200, 1209),
+	PLL_CONFIG(960, 245, 1200, 1152),
+	PLL_CONFIG(960, 196, 1200, 1152),
+	{ 0, 0, 0, 0, 0 }
+};
+
+#ifdef CONFIG_CPU_FREQ_MSM
+static struct cpufreq_frequency_table freq_table[NR_CPUS][20];
+
+static void __init cpufreq_table_init(void)
+{
+	int cpu;
+	for_each_possible_cpu(cpu) {
+		unsigned int i, freq_cnt = 0;
+
+		/* Construct the freq_table table from acpu_freq_tbl since
+		 * the freq_table values need to match frequencies specified
+		 * in acpu_freq_tbl and acpu_freq_tbl needs to be fixed up
+		 * during init.
+		 */
+		for (i = 0; acpu_freq_tbl[i].a11clk_khz != 0
+				&& freq_cnt < ARRAY_SIZE(*freq_table)-1; i++) {
+			if (acpu_freq_tbl[i].use_for_scaling) {
+				freq_table[cpu][freq_cnt].index = freq_cnt;
+				freq_table[cpu][freq_cnt].frequency
+					= acpu_freq_tbl[i].a11clk_khz;
+				freq_cnt++;
+			}
+		}
+
+		/* freq_table not big enough to store all usable freqs. */
+		BUG_ON(acpu_freq_tbl[i].a11clk_khz != 0);
+
+		freq_table[cpu][freq_cnt].index = freq_cnt;
+		freq_table[cpu][freq_cnt].frequency = CPUFREQ_TABLE_END;
+		/* Register table with CPUFreq. */
+		cpufreq_frequency_table_get_attr(freq_table[cpu], cpu);
+		pr_info("CPU%d: %d scaling frequencies supported.\n",
+			cpu, freq_cnt);
+	}
+}
+#endif
+
+static int acpuclk_set_vdd_level(int vdd)
+{
+	uint32_t current_vdd;
+
+	/*
+	* NOTE: v1.0 of 7x27a/7x25a chip doesn't have working
+	* VDD switching support.
+	*/
+	if ((cpu_is_msm7x27a() || cpu_is_msm7x25a()) &&
+		(SOCINFO_VERSION_MINOR(socinfo_get_version()) < 1))
+		return 0;
+
+	current_vdd = readl_relaxed(A11S_VDD_SVS_PLEVEL_ADDR) & 0x07;
+
+	pr_debug("Switching VDD from %u mV -> %d mV\n",
+	       current_vdd, vdd);
+
+	writel_relaxed((1 << 7) | (vdd << 3), A11S_VDD_SVS_PLEVEL_ADDR);
+	mb();
+	udelay(62);
+	if ((readl_relaxed(A11S_VDD_SVS_PLEVEL_ADDR) & 0x7) != vdd) {
+		pr_err("VDD set failed\n");
+		return -EIO;
+	}
+
+	pr_debug("VDD switched\n");
+
+	return 0;
+}
+
+/* Set proper dividers for the given clock speed. */
+static void acpuclk_set_div(const struct clkctl_acpu_speed *hunt_s)
+{
+	uint32_t reg_clkctl, reg_clksel, clk_div, src_sel;
+
+	reg_clksel = readl_relaxed(A11S_CLK_SEL_ADDR);
+
+	/* AHB_CLK_DIV */
+	clk_div = (reg_clksel >> 1) & 0x03;
+	/* CLK_SEL_SRC1NO */
+	src_sel = reg_clksel & 1;
+
+	/*
+	 * If the new clock divider is higher than the previous, then
+	 * program the divider before switching the clock
+	 */
+	if (hunt_s->ahbclk_div > clk_div) {
+		reg_clksel &= ~(0x3 << 1);
+		reg_clksel |= (hunt_s->ahbclk_div << 1);
+		writel_relaxed(reg_clksel, A11S_CLK_SEL_ADDR);
+	}
+
+	/* Program clock source and divider */
+	reg_clkctl = readl_relaxed(A11S_CLK_CNTL_ADDR);
+	reg_clkctl &= ~(0xFF << (8 * src_sel));
+	reg_clkctl |= hunt_s->a11clk_src_sel << (4 + 8 * src_sel);
+	reg_clkctl |= hunt_s->a11clk_src_div << (0 + 8 * src_sel);
+	writel_relaxed(reg_clkctl, A11S_CLK_CNTL_ADDR);
+
+	/* Program clock source selection */
+	reg_clksel ^= 1;
+	writel_relaxed(reg_clksel, A11S_CLK_SEL_ADDR);
+
+	/* Wait for the clock switch to complete */
+	mb();
+	udelay(50);
+
+	/*
+	 * If the new clock divider is lower than the previous, then
+	 * program the divider after switching the clock
+	 */
+	if (hunt_s->ahbclk_div < clk_div) {
+		reg_clksel &= ~(0x3 << 1);
+		reg_clksel |= (hunt_s->ahbclk_div << 1);
+		writel_relaxed(reg_clksel, A11S_CLK_SEL_ADDR);
+	}
+}
+
+static int acpuclk_7627_set_rate(int cpu, unsigned long rate,
+				 enum setrate_reason reason)
+{
+	uint32_t reg_clkctl;
+	struct clkctl_acpu_speed *cur_s, *tgt_s, *strt_s;
+	int res, rc = 0;
+	unsigned int plls_enabled = 0, pll;
+
+	if (reason == SETRATE_CPUFREQ)
+		mutex_lock(&drv_state.lock);
+
+	strt_s = cur_s = drv_state.current_speed;
+
+	WARN_ONCE(cur_s == NULL, "%s: not initialized\n", __func__);
+	if (cur_s == NULL) {
+		rc = -ENOENT;
+		goto out;
+	}
+
+	if (rate == cur_s->a11clk_khz)
+		goto out;
+
+	for (tgt_s = acpu_freq_tbl; tgt_s->a11clk_khz != 0; tgt_s++) {
+		if (tgt_s->a11clk_khz == rate)
+			break;
+	}
+
+	if (tgt_s->a11clk_khz == 0) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	/* Choose the highest speed at or below 'rate' with same PLL. */
+	if (reason != SETRATE_CPUFREQ
+	    && tgt_s->a11clk_khz < cur_s->a11clk_khz) {
+		while (tgt_s->pll != ACPU_PLL_TCXO && tgt_s->pll != cur_s->pll)
+			tgt_s--;
+	}
+
+	if (strt_s->pll != ACPU_PLL_TCXO)
+		plls_enabled |= 1 << strt_s->pll;
+
+	if (reason == SETRATE_CPUFREQ) {
+		if (strt_s->pll != tgt_s->pll && tgt_s->pll != ACPU_PLL_TCXO) {
+			rc = clk_enable(pll_clk[tgt_s->pll].clk);
+			if (rc < 0) {
+				pr_err("PLL%d enable failed (%d)\n",
+					tgt_s->pll, rc);
+				goto out;
+			}
+			plls_enabled |= 1 << tgt_s->pll;
+		}
+	}
+	/* Need to do this when coming out of power collapse since some modem
+	 * firmwares reset the VDD when the application processor enters power
+	 * collapse. */
+	if (reason == SETRATE_CPUFREQ || reason == SETRATE_PC) {
+		/* Increase VDD if needed. */
+		if (tgt_s->vdd > cur_s->vdd) {
+			rc = acpuclk_set_vdd_level(tgt_s->vdd);
+			if (rc < 0) {
+				pr_err("Unable to switch ACPU vdd (%d)\n", rc);
+				goto out;
+			}
+		}
+	}
+
+	/* Set wait states for CPU inbetween frequency changes */
+	reg_clkctl = readl_relaxed(A11S_CLK_CNTL_ADDR);
+	reg_clkctl |= (100 << 16); /* set WT_ST_CNT */
+	writel_relaxed(reg_clkctl, A11S_CLK_CNTL_ADDR);
+
+	pr_debug("Switching from ACPU rate %u KHz -> %u KHz\n",
+		       strt_s->a11clk_khz, tgt_s->a11clk_khz);
+
+	while (cur_s != tgt_s) {
+		/*
+		 * Always jump to target freq if within max_speed_delta_khz,
+		 * regardless of PLL. If differnece is greater, use the
+		 * predefined steppings in the table.
+		 */
+		int d = abs((int)(cur_s->a11clk_khz - tgt_s->a11clk_khz));
+		if (d > drv_state.max_speed_delta_khz) {
+
+			if (tgt_s->a11clk_khz > cur_s->a11clk_khz) {
+				/* Step up: jump to target PLL as early as
+				 * possible so indexing using TCXO (up[-1])
+				 * never occurs. */
+				if (likely(cur_s->up[tgt_s->pll]))
+					cur_s = cur_s->up[tgt_s->pll];
+				else
+					cur_s = cur_s->up[cur_s->pll];
+			} else {
+				/* Step down: stay on current PLL as long as
+				 * possible so indexing using TCXO (down[-1])
+				 * never occurs. */
+				if (likely(cur_s->down[cur_s->pll]))
+					cur_s = cur_s->down[cur_s->pll];
+				else
+					cur_s = cur_s->down[tgt_s->pll];
+			}
+
+			if (cur_s == NULL) { /* This should not happen. */
+				pr_err("No stepping frequencies found. "
+					"strt_s:%u tgt_s:%u\n",
+					strt_s->a11clk_khz, tgt_s->a11clk_khz);
+				rc = -EINVAL;
+				goto out;
+			}
+
+		} else {
+			cur_s = tgt_s;
+		}
+
+		pr_debug("STEP khz = %u, pll = %d\n",
+				cur_s->a11clk_khz, cur_s->pll);
+
+		if (cur_s->pll != ACPU_PLL_TCXO
+		    && !(plls_enabled & (1 << cur_s->pll))) {
+			rc = clk_enable(pll_clk[cur_s->pll].clk);
+			if (rc < 0) {
+				pr_err("PLL%d enable failed (%d)\n",
+					cur_s->pll, rc);
+				goto out;
+			}
+			plls_enabled |= 1 << cur_s->pll;
+		}
+
+		acpuclk_set_div(cur_s);
+		drv_state.current_speed = cur_s;
+		/* Re-adjust lpj for the new clock speed. */
+#ifdef CONFIG_SMP
+		for_each_possible_cpu(cpu) {
+			per_cpu(cpu_data, cpu).loops_per_jiffy =
+							cur_s->lpj;
+		}
+#endif
+		/* Adjust the global one */
+		loops_per_jiffy = cur_s->lpj;
+
+	}
+
+	/* Nothing else to do for SWFI. */
+	if (reason == SETRATE_SWFI)
+		goto out;
+
+	/* Change the AXI bus frequency if we can. */
+	if (strt_s->axiclk_khz != tgt_s->axiclk_khz) {
+		res = clk_set_rate(drv_state.ebi1_clk,
+				tgt_s->axiclk_khz * 1000);
+		if (res < 0)
+			pr_warning("Setting AXI min rate failed (%d)\n", res);
+	}
+
+	/* Disable PLLs we are not using anymore. */
+	if (tgt_s->pll != ACPU_PLL_TCXO)
+		plls_enabled &= ~(1 << tgt_s->pll);
+	for (pll = ACPU_PLL_0; pll < ACPU_PLL_END; pll++)
+		if (plls_enabled & (1 << pll))
+			clk_disable(pll_clk[pll].clk);
+
+	/* Nothing else to do for power collapse. */
+	if (reason == SETRATE_PC)
+		goto out;
+
+	/* Drop VDD level if we can. */
+	if (tgt_s->vdd < strt_s->vdd) {
+		res = acpuclk_set_vdd_level(tgt_s->vdd);
+		if (res < 0)
+			pr_warning("Unable to drop ACPU vdd (%d)\n", res);
+	}
+
+	pr_debug("ACPU speed change complete\n");
+out:
+	if (reason == SETRATE_CPUFREQ)
+		mutex_unlock(&drv_state.lock);
+	return rc;
+}
+
+static void __init acpuclk_hw_init(void)
+{
+	struct clkctl_acpu_speed *speed;
+	uint32_t div, sel, reg_clksel;
+	int res;
+
+	/*
+	 * Prepare all the PLLs because we enable/disable them
+	 * from atomic context and can't always ensure they're
+	 * all prepared in non-atomic context. Same goes for
+	 * ebi1_acpu_clk.
+	 */
+	BUG_ON(clk_prepare(pll_clk[ACPU_PLL_0].clk));
+	BUG_ON(clk_prepare(pll_clk[ACPU_PLL_1].clk));
+	BUG_ON(clk_prepare(pll_clk[ACPU_PLL_2].clk));
+	BUG_ON(clk_prepare(pll_clk[ACPU_PLL_4].clk));
+	BUG_ON(clk_prepare(drv_state.ebi1_clk));
+
+	/*
+	 * Determine the rate of ACPU clock
+	 */
+
+	if (!(readl_relaxed(A11S_CLK_SEL_ADDR) & 0x01)) { /* CLK_SEL_SRC1N0 */
+		/* CLK_SRC0_SEL */
+		sel = (readl_relaxed(A11S_CLK_CNTL_ADDR) >> 12) & 0x7;
+		/* CLK_SRC0_DIV */
+		div = (readl_relaxed(A11S_CLK_CNTL_ADDR) >> 8) & 0x0f;
+	} else {
+		/* CLK_SRC1_SEL */
+		sel = (readl_relaxed(A11S_CLK_CNTL_ADDR) >> 4) & 0x07;
+		/* CLK_SRC1_DIV */
+		div = readl_relaxed(A11S_CLK_CNTL_ADDR) & 0x0f;
+	}
+
+	for (speed = acpu_freq_tbl; speed->a11clk_khz != 0; speed++) {
+		if (speed->a11clk_src_sel == sel
+		 && (speed->a11clk_src_div == div))
+			break;
+	}
+	if (speed->a11clk_khz == 0) {
+		pr_err("Error - ACPU clock reports invalid speed\n");
+		return;
+	}
+
+	drv_state.current_speed = speed;
+	if (speed->pll != ACPU_PLL_TCXO) {
+		if (clk_enable(pll_clk[speed->pll].clk))
+			pr_warning("Failed to vote for boot PLL\n");
+	}
+
+	/* Fix div2 to 2 for 7x27/5a(aa) targets */
+	if (!cpu_is_msm7x27()) {
+		reg_clksel = readl_relaxed(A11S_CLK_SEL_ADDR);
+		reg_clksel &= ~(0x3 << 14);
+		reg_clksel |= (0x1 << 14);
+		writel_relaxed(reg_clksel, A11S_CLK_SEL_ADDR);
+	}
+
+	res = clk_set_rate(drv_state.ebi1_clk, speed->axiclk_khz * 1000);
+	if (res < 0)
+		pr_warning("Setting AXI min rate failed (%d)\n", res);
+	res = clk_enable(drv_state.ebi1_clk);
+	if (res < 0)
+		pr_warning("Enabling AXI clock failed (%d)\n", res);
+
+	pr_info("ACPU running at %d KHz\n", speed->a11clk_khz);
+}
+
+static unsigned long acpuclk_7627_get_rate(int cpu)
+{
+	WARN_ONCE(drv_state.current_speed == NULL,
+		  "%s: not initialized\n", __func__);
+	if (drv_state.current_speed)
+		return drv_state.current_speed->a11clk_khz;
+	else
+		return 0;
+}
+
+/*----------------------------------------------------------------------------
+ * Clock driver initialization
+ *---------------------------------------------------------------------------*/
+#define MHZ 1000000
+static void __init select_freq_plan(void)
+{
+	unsigned long pll_mhz[ACPU_PLL_END];
+	struct pll_freq_tbl_map *t;
+	int i;
+
+	/* Get PLL clocks */
+	for (i = 0; i < ACPU_PLL_END; i++) {
+		if (pll_clk[i].name) {
+			pll_clk[i].clk = clk_get_sys("acpu", pll_clk[i].name);
+			if (IS_ERR(pll_clk[i].clk)) {
+				pll_mhz[i] = 0;
+				continue;
+			}
+			/* Get PLL's Rate */
+			pll_mhz[i] = clk_get_rate(pll_clk[i].clk)/MHZ;
+		}
+	}
+
+	/*
+	 * For the pll configuration used in acpuclock table e.g.
+	 * pll0_960_pll1_245_pll2_1200" is same for 7627 and
+	 * 7625a (as pll0,pll1,pll2) having same rates, but frequency
+	 * table is different for both targets.
+	 *
+	 * Hence below for loop will not be able to select correct
+	 * table based on PLL rates as rates are same. Hence we need
+	 * to add this cpu check for selecting the correct acpuclock table.
+	 */
+	if (cpu_is_msm7x25a()) {
+		if (pll_mhz[ACPU_PLL_1] == 245) {
+			acpu_freq_tbl =
+				pll0_960_pll1_245_pll2_1200_25a;
+		} else if (pll_mhz[ACPU_PLL_1] == 737) {
+			acpu_freq_tbl =
+				pll0_960_pll1_737_pll2_1200_25a;
+		}
+	} else {
+		/* Select the right table to use. */
+		for (t = acpu_freq_tbl_list; t->tbl != 0; t++) {
+			if (t->pll0_rate == pll_mhz[ACPU_PLL_0]
+				&& t->pll1_rate == pll_mhz[ACPU_PLL_1]
+				&& t->pll2_rate == pll_mhz[ACPU_PLL_2]
+				&& t->pll4_rate == pll_mhz[ACPU_PLL_4]) {
+				acpu_freq_tbl = t->tbl;
+				break;
+			}
+		}
+	}
+
+	if (acpu_freq_tbl == NULL) {
+		pr_crit("Unknown PLL configuration!\n");
+		BUG();
+	}
+}
+
+/*
+ * Hardware requires the CPU to be dropped to less than MAX_WAIT_FOR_IRQ_KHZ
+ * before entering a wait for irq low-power mode. Find a suitable rate.
+ */
+static unsigned long __init find_wait_for_irq_khz(void)
+{
+	unsigned long found_khz = 0;
+	int i;
+
+	for (i = 0; acpu_freq_tbl[i].a11clk_khz &&
+		    acpu_freq_tbl[i].a11clk_khz <= MAX_WAIT_FOR_IRQ_KHZ; i++)
+		found_khz = acpu_freq_tbl[i].a11clk_khz;
+
+	return found_khz;
+}
+
+static void __init lpj_init(void)
+{
+	int i = 0, cpu;
+	const struct clkctl_acpu_speed *base_clk = drv_state.current_speed;
+	unsigned long loops;
+
+	for_each_possible_cpu(cpu) {
+#ifdef CONFIG_SMP
+		loops = per_cpu(cpu_data, cpu).loops_per_jiffy;
+#else
+		loops = loops_per_jiffy;
+#endif
+		for (i = 0; acpu_freq_tbl[i].a11clk_khz; i++) {
+			acpu_freq_tbl[i].lpj = cpufreq_scale(
+				loops,
+				base_clk->a11clk_khz,
+				acpu_freq_tbl[i].a11clk_khz);
+		}
+	}
+}
+
+static void __init precompute_stepping(void)
+{
+	int i, step_idx;
+
+#define cur_freq acpu_freq_tbl[i].a11clk_khz
+#define step_freq acpu_freq_tbl[step_idx].a11clk_khz
+#define cur_pll acpu_freq_tbl[i].pll
+#define step_pll acpu_freq_tbl[step_idx].pll
+
+	for (i = 0; acpu_freq_tbl[i].a11clk_khz; i++) {
+
+		/* Calculate max "up" step for each destination PLL */
+		step_idx = i + 1;
+		while (step_freq && (step_freq - cur_freq)
+					<= drv_state.max_speed_delta_khz) {
+			acpu_freq_tbl[i].up[step_pll] =
+						&acpu_freq_tbl[step_idx];
+			step_idx++;
+		}
+		if (step_idx == (i + 1) && step_freq) {
+			pr_crit("Delta between freqs %u KHz and %u KHz is"
+				" too high!\n", cur_freq, step_freq);
+			BUG();
+		}
+
+		/* Calculate max "down" step for each destination PLL */
+		step_idx = i - 1;
+		while (step_idx >= 0 && (cur_freq - step_freq)
+					<= drv_state.max_speed_delta_khz) {
+			acpu_freq_tbl[i].down[step_pll] =
+						&acpu_freq_tbl[step_idx];
+			step_idx--;
+		}
+		if (step_idx == (i - 1) && i > 0) {
+			pr_crit("Delta between freqs %u KHz and %u KHz is"
+				" too high!\n", cur_freq, step_freq);
+			BUG();
+		}
+	}
+}
+
+static void __init print_acpu_freq_tbl(void)
+{
+	struct clkctl_acpu_speed *t;
+	short down_idx[ACPU_PLL_END];
+	short up_idx[ACPU_PLL_END];
+	int i, j;
+
+#define FREQ_IDX(freq_ptr) (freq_ptr - acpu_freq_tbl)
+	pr_info("Id CPU-KHz PLL DIV AHB-KHz ADIV AXI-KHz "
+		"D0 D1 D2 D4 U0 U1 U2 U4\n");
+
+	t = &acpu_freq_tbl[0];
+	for (i = 0; t->a11clk_khz != 0; i++) {
+
+		for (j = 0; j < ACPU_PLL_END; j++) {
+			down_idx[j] = t->down[j] ? FREQ_IDX(t->down[j]) : -1;
+			up_idx[j] = t->up[j] ? FREQ_IDX(t->up[j]) : -1;
+		}
+
+		pr_info("%2d %7d %3d %3d %7d %4d %7d "
+			"%2d %2d %2d %2d %2d %2d %2d %2d\n",
+			i, t->a11clk_khz, t->pll, t->a11clk_src_div + 1,
+			t->ahbclk_khz, t->ahbclk_div + 1, t->axiclk_khz,
+			down_idx[0], down_idx[1], down_idx[2], down_idx[4],
+			up_idx[0], up_idx[1], up_idx[2], up_idx[4]);
+
+		t++;
+	}
+}
+
+
+static struct acpuclk_data acpuclk_7627_data = {
+	.set_rate = acpuclk_7627_set_rate,
+	.get_rate = acpuclk_7627_get_rate,
+	.power_collapse_khz = POWER_COLLAPSE_KHZ,
+	.switch_time_us = 50,
+};
+
+static int __init acpuclk_7627_init(struct acpuclk_soc_data *soc_data)
+{
+	pr_info("%s()\n", __func__);
+
+	drv_state.ebi1_clk = clk_get(NULL, "ebi1_acpu_clk");
+	BUG_ON(IS_ERR(drv_state.ebi1_clk));
+
+	mutex_init(&drv_state.lock);
+	drv_state.max_speed_delta_khz = soc_data->max_speed_delta_khz;
+	select_freq_plan();
+	acpuclk_7627_data.wait_for_irq_khz = find_wait_for_irq_khz();
+	precompute_stepping();
+	acpuclk_hw_init();
+	lpj_init();
+	print_acpu_freq_tbl();
+	acpuclk_register(&acpuclk_7627_data);
+
+#ifdef CONFIG_CPU_FREQ_MSM
+	cpufreq_table_init();
+#endif
+	return 0;
+}
+
+struct acpuclk_soc_data acpuclk_7x27_soc_data __initdata = {
+	.max_speed_delta_khz = 400000,
+	.init = acpuclk_7627_init,
+};
+
+struct acpuclk_soc_data acpuclk_7x27a_soc_data __initdata = {
+	.max_speed_delta_khz = 400000,
+	.init = acpuclk_7627_init,
+};
+
+struct acpuclk_soc_data acpuclk_7x27aa_soc_data __initdata = {
+	.max_speed_delta_khz = 504000,
+	.init = acpuclk_7627_init,
+};
+
+struct acpuclk_soc_data acpuclk_8625_soc_data __initdata = {
+	/* TODO: Need to update speed delta from H/w Team */
+	.max_speed_delta_khz = 604800,
+	.init = acpuclk_7627_init,
+};
diff --git a/arch/arm/mach-msm/acpuclock-7x30.c b/arch/arm/mach-msm/acpuclock-7x30.c
new file mode 100644
index 0000000..29b0065
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock-7x30.c
@@ -0,0 +1,499 @@
+/*
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2012, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/sort.h>
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+#include <asm/mach-types.h>
+
+#include "smd_private.h"
+#include "clock.h"
+#include "acpuclock.h"
+#include "spm.h"
+
+#define SCSS_CLK_CTL_ADDR	(MSM_ACC0_BASE + 0x04)
+#define SCSS_CLK_SEL_ADDR	(MSM_ACC0_BASE + 0x08)
+
+#define PLL2_L_VAL_ADDR		(MSM_CLK_CTL_BASE + 0x33C)
+#define PLL2_M_VAL_ADDR		(MSM_CLK_CTL_BASE + 0x340)
+#define PLL2_N_VAL_ADDR		(MSM_CLK_CTL_BASE + 0x344)
+#define PLL2_CONFIG_ADDR	(MSM_CLK_CTL_BASE + 0x34C)
+
+#define VREF_SEL     1	/* 0: 0.625V (50mV step), 1: 0.3125V (25mV step). */
+#define V_STEP       (25 * (2 - VREF_SEL)) /* Minimum voltage step size. */
+#define VREG_DATA    (VREG_CONFIG | (VREF_SEL << 5))
+#define VREG_CONFIG  (BIT(7) | BIT(6)) /* Enable VREG, pull-down if disabled. */
+/* Cause a compile error if the voltage is not a multiple of the step size. */
+#define MV(mv)      ((mv) / (!((mv) % V_STEP)))
+/* mv = (750mV + (raw * 25mV)) * (2 - VREF_SEL) */
+#define VDD_RAW(mv) (((MV(mv) / V_STEP) - 30) | VREG_DATA)
+
+#define MAX_AXI_KHZ 192000
+
+struct clock_state {
+	struct clkctl_acpu_speed	*current_speed;
+	struct mutex			lock;
+	struct clk			*ebi1_clk;
+};
+
+struct pll {
+	unsigned int l;
+	unsigned int m;
+	unsigned int n;
+	unsigned int pre_div;
+};
+
+struct clkctl_acpu_speed {
+	unsigned int	use_for_scaling;
+	unsigned int	acpu_clk_khz;
+	int		src;
+	unsigned int	acpu_src_sel;
+	unsigned int	acpu_src_div;
+	unsigned int	axi_clk_hz;
+	unsigned int	vdd_mv;
+	unsigned int	vdd_raw;
+	struct pll	*pll_rate;
+	unsigned long	lpj; /* loops_per_jiffy */
+};
+
+static struct clock_state drv_state = { 0 };
+
+/* Switch to this when reprogramming PLL2 */
+static struct clkctl_acpu_speed *backup_s;
+
+static struct pll pll2_tbl[] = {
+	{  42, 0, 1, 0 }, /*  806 MHz */
+	{  53, 1, 3, 0 }, /* 1024 MHz */
+	{ 125, 0, 1, 1 }, /* 1200 MHz */
+	{  73, 0, 1, 0 }, /* 1401 MHz */
+};
+
+/* Use negative numbers for sources that can't be enabled/disabled */
+
+enum acpuclk_source {
+	LPXO	= -2,
+	AXI	= -1,
+	PLL_0	=  0,
+	PLL_1,
+	PLL_2,
+	PLL_3,
+	MAX_SOURCE
+};
+
+static struct clk *acpuclk_sources[MAX_SOURCE];
+
+/*
+ * Each ACPU frequency has a certain minimum MSMC1 voltage requirement
+ * that is implicitly met by voting for a specific minimum AXI frequency.
+ * Do NOT change the AXI frequency unless you are _absoulutely_ sure you
+ * know all the h/w requirements.
+ */
+static struct clkctl_acpu_speed acpu_freq_tbl[] = {
+	{ 0, 24576,  LPXO, 0, 0,  30720000,  900, VDD_RAW(900) },
+	{ 0, 61440,  PLL_3,    5, 11, 61440000,  900, VDD_RAW(900) },
+	{ 1, 122880, PLL_3,    5, 5,  61440000,  900, VDD_RAW(900) },
+	{ 0, 184320, PLL_3,    5, 4,  61440000,  900, VDD_RAW(900) },
+	{ 0, MAX_AXI_KHZ, AXI, 1, 0, 61440000, 900, VDD_RAW(900) },
+	{ 1, 245760, PLL_3,    5, 2,  61440000,  900, VDD_RAW(900) },
+	{ 1, 368640, PLL_3,    5, 1,  122800000, 900, VDD_RAW(900) },
+	/* AXI has MSMC1 implications. See above. */
+	{ 1, 768000, PLL_1,    2, 0,  153600000, 1050, VDD_RAW(1050) },
+	/*
+	 * AXI has MSMC1 implications. See above.
+	 */
+	{ 1, 806400,  PLL_2, 3, 0, UINT_MAX, 1100, VDD_RAW(1100), &pll2_tbl[0]},
+	{ 1, 1024000, PLL_2, 3, 0, UINT_MAX, 1200, VDD_RAW(1200), &pll2_tbl[1]},
+	{ 1, 1200000, PLL_2, 3, 0, UINT_MAX, 1200, VDD_RAW(1200), &pll2_tbl[2]},
+	{ 1, 1401600, PLL_2, 3, 0, UINT_MAX, 1250, VDD_RAW(1250), &pll2_tbl[3]},
+	{ 0 }
+};
+
+static int acpuclk_set_acpu_vdd(struct clkctl_acpu_speed *s)
+{
+	int ret = msm_spm_set_vdd(0, s->vdd_raw);
+	if (ret)
+		return ret;
+
+	/* Wait for voltage to stabilize. */
+	udelay(62);
+	return 0;
+}
+
+/* Assumes PLL2 is off and the acpuclock isn't sourced from PLL2 */
+static void acpuclk_config_pll2(struct pll *pll)
+{
+	uint32_t config = readl_relaxed(PLL2_CONFIG_ADDR);
+
+	/* Make sure write to disable PLL_2 has completed
+	 * before reconfiguring that PLL. */
+	mb();
+	writel_relaxed(pll->l, PLL2_L_VAL_ADDR);
+	writel_relaxed(pll->m, PLL2_M_VAL_ADDR);
+	writel_relaxed(pll->n, PLL2_N_VAL_ADDR);
+	if (pll->pre_div)
+		config |= BIT(15);
+	else
+		config &= ~BIT(15);
+	writel_relaxed(config, PLL2_CONFIG_ADDR);
+	/* Make sure PLL is programmed before returning. */
+	mb();
+}
+
+/* Set clock source and divider given a clock speed */
+static void acpuclk_set_src(const struct clkctl_acpu_speed *s)
+{
+	uint32_t reg_clksel, reg_clkctl, src_sel;
+
+	reg_clksel = readl_relaxed(SCSS_CLK_SEL_ADDR);
+
+	/* CLK_SEL_SRC1NO */
+	src_sel = reg_clksel & 1;
+
+	/* Program clock source and divider. */
+	reg_clkctl = readl_relaxed(SCSS_CLK_CTL_ADDR);
+	reg_clkctl &= ~(0xFF << (8 * src_sel));
+	reg_clkctl |= s->acpu_src_sel << (4 + 8 * src_sel);
+	reg_clkctl |= s->acpu_src_div << (0 + 8 * src_sel);
+	writel_relaxed(reg_clkctl, SCSS_CLK_CTL_ADDR);
+
+	/* Toggle clock source. */
+	reg_clksel ^= 1;
+
+	/* Program clock source selection. */
+	writel_relaxed(reg_clksel, SCSS_CLK_SEL_ADDR);
+
+	/* Make sure switch to new source is complete. */
+	mb();
+}
+
+static int acpuclk_7x30_set_rate(int cpu, unsigned long rate,
+				 enum setrate_reason reason)
+{
+	struct clkctl_acpu_speed *tgt_s, *strt_s;
+	int res, rc = 0;
+
+	if (reason == SETRATE_CPUFREQ)
+		mutex_lock(&drv_state.lock);
+
+	strt_s = drv_state.current_speed;
+
+	if (rate == strt_s->acpu_clk_khz)
+		goto out;
+
+	for (tgt_s = acpu_freq_tbl; tgt_s->acpu_clk_khz != 0; tgt_s++) {
+		if (tgt_s->acpu_clk_khz == rate)
+			break;
+	}
+	if (tgt_s->acpu_clk_khz == 0) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	if (reason == SETRATE_CPUFREQ) {
+		/* Increase VDD if needed. */
+		if (tgt_s->vdd_mv > strt_s->vdd_mv) {
+			rc = acpuclk_set_acpu_vdd(tgt_s);
+			if (rc < 0) {
+				pr_err("ACPU VDD increase to %d mV failed "
+					"(%d)\n", tgt_s->vdd_mv, rc);
+				goto out;
+			}
+		}
+	}
+
+	pr_debug("Switching from ACPU rate %u KHz -> %u KHz\n",
+	       strt_s->acpu_clk_khz, tgt_s->acpu_clk_khz);
+
+	/* Increase the AXI bus frequency if needed. This must be done before
+	 * increasing the ACPU frequency, since voting for high AXI rates
+	 * implicitly takes care of increasing the MSMC1 voltage, as needed. */
+	if (tgt_s->axi_clk_hz > strt_s->axi_clk_hz) {
+		rc = clk_set_rate(drv_state.ebi1_clk, tgt_s->axi_clk_hz);
+		if (rc < 0) {
+			pr_err("Setting AXI min rate failed (%d)\n", rc);
+			goto out;
+		}
+	}
+
+	/* Move off of PLL2 if we're reprogramming it */
+	if (tgt_s->src == PLL_2 && strt_s->src == PLL_2) {
+		clk_enable(acpuclk_sources[backup_s->src]);
+		acpuclk_set_src(backup_s);
+		clk_disable(acpuclk_sources[strt_s->src]);
+	}
+
+	/* Reconfigure PLL2 if we're moving to it */
+	if (tgt_s->src == PLL_2)
+		acpuclk_config_pll2(tgt_s->pll_rate);
+
+	/* Make sure target PLL is on. */
+	if ((strt_s->src != tgt_s->src && tgt_s->src >= 0) ||
+	    (tgt_s->src == PLL_2 && strt_s->src == PLL_2)) {
+		pr_debug("Enabling PLL %d\n", tgt_s->src);
+		clk_enable(acpuclk_sources[tgt_s->src]);
+	}
+
+	/* Perform the frequency switch */
+	acpuclk_set_src(tgt_s);
+	drv_state.current_speed = tgt_s;
+	loops_per_jiffy = tgt_s->lpj;
+
+	if (tgt_s->src == PLL_2 && strt_s->src == PLL_2)
+		clk_disable(acpuclk_sources[backup_s->src]);
+
+	/* Nothing else to do for SWFI. */
+	if (reason == SETRATE_SWFI)
+		goto out;
+
+	/* Turn off previous PLL if not used. */
+	if (strt_s->src != tgt_s->src && strt_s->src >= 0) {
+		pr_debug("Disabling PLL %d\n", strt_s->src);
+		clk_disable(acpuclk_sources[strt_s->src]);
+	}
+
+	/* Decrease the AXI bus frequency if we can. */
+	if (tgt_s->axi_clk_hz < strt_s->axi_clk_hz) {
+		res = clk_set_rate(drv_state.ebi1_clk, tgt_s->axi_clk_hz);
+		if (res < 0)
+			pr_warning("Setting AXI min rate failed (%d)\n", res);
+	}
+
+	/* Nothing else to do for power collapse. */
+	if (reason == SETRATE_PC)
+		goto out;
+
+	/* Drop VDD level if we can. */
+	if (tgt_s->vdd_mv < strt_s->vdd_mv) {
+		res = acpuclk_set_acpu_vdd(tgt_s);
+		if (res)
+			pr_warning("ACPU VDD decrease to %d mV failed (%d)\n",
+					tgt_s->vdd_mv, res);
+	}
+
+	pr_debug("ACPU speed change complete\n");
+out:
+	if (reason == SETRATE_CPUFREQ)
+		mutex_unlock(&drv_state.lock);
+
+	return rc;
+}
+
+static unsigned long acpuclk_7x30_get_rate(int cpu)
+{
+	WARN_ONCE(drv_state.current_speed == NULL,
+		  "acpuclk_get_rate: not initialized\n");
+	if (drv_state.current_speed)
+		return drv_state.current_speed->acpu_clk_khz;
+	else
+		return 0;
+}
+
+/*----------------------------------------------------------------------------
+ * Clock driver initialization
+ *---------------------------------------------------------------------------*/
+
+static void __init acpuclk_hw_init(void)
+{
+	struct clkctl_acpu_speed *s;
+	uint32_t div, sel, src_num;
+	uint32_t reg_clksel, reg_clkctl;
+	int res;
+	u8 pll2_l = readl_relaxed(PLL2_L_VAL_ADDR) & 0xFF;
+
+	drv_state.ebi1_clk = clk_get(NULL, "ebi1_clk");
+	BUG_ON(IS_ERR(drv_state.ebi1_clk));
+
+	reg_clksel = readl_relaxed(SCSS_CLK_SEL_ADDR);
+
+	/* Determine the ACPU clock rate. */
+	switch ((reg_clksel >> 1) & 0x3) {
+	case 0:	/* Running off the output of the raw clock source mux. */
+		reg_clkctl = readl_relaxed(SCSS_CLK_CTL_ADDR);
+		src_num = reg_clksel & 0x1;
+		sel = (reg_clkctl >> (12 - (8 * src_num))) & 0x7;
+		div = (reg_clkctl >> (8 -  (8 * src_num))) & 0xF;
+
+		/* Check frequency table for matching sel/div pair. */
+		for (s = acpu_freq_tbl; s->acpu_clk_khz != 0; s++) {
+			if (s->acpu_src_sel == sel && s->acpu_src_div == div)
+				break;
+		}
+		if (s->acpu_clk_khz == 0) {
+			pr_err("Error - ACPU clock reports invalid speed\n");
+			return;
+		}
+		break;
+	case 2:	/* Running off of the SCPLL selected through the core mux. */
+		/* Switch to run off of the SCPLL selected through the raw
+		 * clock source mux. */
+		for (s = acpu_freq_tbl; s->acpu_clk_khz != 0
+			&& s->src != PLL_2 && s->acpu_src_div == 0; s++)
+			;
+		if (s->acpu_clk_khz != 0) {
+			/* Program raw clock source mux. */
+			acpuclk_set_src(s);
+
+			/* Switch to raw clock source input of the core mux. */
+			reg_clksel = readl_relaxed(SCSS_CLK_SEL_ADDR);
+			reg_clksel &= ~(0x3 << 1);
+			writel_relaxed(reg_clksel, SCSS_CLK_SEL_ADDR);
+			break;
+		}
+		/* else fall through */
+	default:
+		pr_err("Error - ACPU clock reports invalid source\n");
+		return;
+	}
+
+	/* Look at PLL2's L val to determine what speed PLL2 is running at */
+	if (s->src == PLL_2)
+		for ( ; s->acpu_clk_khz; s++)
+			if (s->pll_rate && s->pll_rate->l == pll2_l)
+				break;
+
+	/* Set initial ACPU VDD. */
+	acpuclk_set_acpu_vdd(s);
+
+	drv_state.current_speed = s;
+
+	/* Initialize current PLL's reference count. */
+	if (s->src >= 0)
+		clk_enable(acpuclk_sources[s->src]);
+
+	res = clk_set_rate(drv_state.ebi1_clk, s->axi_clk_hz);
+	if (res < 0)
+		pr_warning("Setting AXI min rate failed!\n");
+
+	pr_info("ACPU running at %d KHz\n", s->acpu_clk_khz);
+
+	return;
+}
+
+/* Initalize the lpj field in the acpu_freq_tbl. */
+static void __init lpj_init(void)
+{
+	int i;
+	const struct clkctl_acpu_speed *base_clk = drv_state.current_speed;
+
+	for (i = 0; acpu_freq_tbl[i].acpu_clk_khz; i++) {
+		acpu_freq_tbl[i].lpj = cpufreq_scale(loops_per_jiffy,
+						base_clk->acpu_clk_khz,
+						acpu_freq_tbl[i].acpu_clk_khz);
+	}
+}
+
+#ifdef CONFIG_CPU_FREQ_MSM
+static struct cpufreq_frequency_table cpufreq_tbl[ARRAY_SIZE(acpu_freq_tbl)];
+
+static void setup_cpufreq_table(void)
+{
+	unsigned i = 0;
+	const struct clkctl_acpu_speed *speed;
+
+	for (speed = acpu_freq_tbl; speed->acpu_clk_khz; speed++)
+		if (speed->use_for_scaling) {
+			cpufreq_tbl[i].index = i;
+			cpufreq_tbl[i].frequency = speed->acpu_clk_khz;
+			i++;
+		}
+	cpufreq_tbl[i].frequency = CPUFREQ_TABLE_END;
+
+	cpufreq_frequency_table_get_attr(cpufreq_tbl, smp_processor_id());
+}
+#else
+static inline void setup_cpufreq_table(void) { }
+#endif
+
+/*
+ * Truncate the frequency table at the current PLL2 rate and determine the
+ * backup PLL to use when scaling PLL2.
+ */
+void __init pll2_fixup(void)
+{
+	struct clkctl_acpu_speed *speed = acpu_freq_tbl;
+	u8 pll2_l = readl_relaxed(PLL2_L_VAL_ADDR) & 0xFF;
+
+	for ( ; speed->acpu_clk_khz; speed++) {
+		if (speed->src != PLL_2)
+			backup_s = speed;
+		if (speed->pll_rate && speed->pll_rate->l == pll2_l) {
+			speed++;
+			speed->acpu_clk_khz = 0;
+			return;
+		}
+	}
+
+	pr_err("Unknown PLL2 lval %d\n", pll2_l);
+	BUG();
+}
+
+#define RPM_BYPASS_MASK	(1 << 3)
+#define PMIC_MODE_MASK	(1 << 4)
+
+static void __init populate_plls(void)
+{
+	acpuclk_sources[PLL_1] = clk_get_sys("acpu", "pll1_clk");
+	BUG_ON(IS_ERR(acpuclk_sources[PLL_1]));
+	acpuclk_sources[PLL_2] = clk_get_sys("acpu", "pll2_clk");
+	BUG_ON(IS_ERR(acpuclk_sources[PLL_2]));
+	acpuclk_sources[PLL_3] = clk_get_sys("acpu", "pll3_clk");
+	BUG_ON(IS_ERR(acpuclk_sources[PLL_3]));
+	/*
+	 * Prepare all the PLLs because we enable/disable them
+	 * from atomic context and can't always ensure they're
+	 * all prepared in non-atomic context.
+	 */
+	BUG_ON(clk_prepare(acpuclk_sources[PLL_1]));
+	BUG_ON(clk_prepare(acpuclk_sources[PLL_2]));
+	BUG_ON(clk_prepare(acpuclk_sources[PLL_3]));
+}
+
+static struct acpuclk_data acpuclk_7x30_data = {
+	.set_rate = acpuclk_7x30_set_rate,
+	.get_rate = acpuclk_7x30_get_rate,
+	.power_collapse_khz = MAX_AXI_KHZ,
+	.wait_for_irq_khz = MAX_AXI_KHZ,
+	.switch_time_us = 50,
+};
+
+static int __init acpuclk_7x30_init(struct acpuclk_soc_data *soc_data)
+{
+	pr_info("%s()\n", __func__);
+
+	mutex_init(&drv_state.lock);
+	pll2_fixup();
+	populate_plls();
+	acpuclk_hw_init();
+	lpj_init();
+	setup_cpufreq_table();
+	acpuclk_register(&acpuclk_7x30_data);
+
+	return 0;
+}
+
+struct acpuclk_soc_data acpuclk_7x30_soc_data __initdata = {
+	.init = acpuclk_7x30_init,
+};
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
new file mode 100644
index 0000000..f467aba
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -0,0 +1,1533 @@
+/* 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
+ * 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/cpufreq.h>
+#include <linux/cpu.h>
+#include <linux/regulator/consumer.h>
+
+#include <asm/mach-types.h>
+#include <asm/cpu.h>
+
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+#include <mach/rpm-regulator.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#include <mach/socinfo.h>
+#include <mach/msm-krait-l2-accessors.h>
+#include <mach/rpm-regulator.h>
+
+#include "acpuclock.h"
+#include "pm.h"
+
+/*
+ * Source IDs.
+ * These must be negative to not overlap with the source IDs
+ * used by the 8x60 local clock driver.
+ */
+#define PLL_8			 0
+#define HFPLL			-1
+#define QSB			-2
+
+/* Mux source selects. */
+#define PRI_SRC_SEL_SEC_SRC	0
+#define PRI_SRC_SEL_HFPLL	1
+#define PRI_SRC_SEL_HFPLL_DIV2	2
+#define SEC_SRC_SEL_QSB		0
+#define SEC_SRC_SEL_AUX		2
+
+/* HFPLL registers offsets. */
+#define HFPLL_MODE		0x00
+#define HFPLL_CONFIG_CTL	0x04
+#define HFPLL_L_VAL		0x08
+#define HFPLL_M_VAL		0x0C
+#define HFPLL_N_VAL		0x10
+#define HFPLL_DROOP_CTL		0x14
+
+/* CP15 L2 indirect addresses. */
+#define L2CPMR_IADDR		0x500
+#define L2CPUCPMR_IADDR		0x501
+
+#define STBY_KHZ		1
+
+#define HFPLL_LOW_VDD_PLL_L_MAX	0x28
+
+#define SECCLKAGD		BIT(4)
+
+/* PTE EFUSE register. */
+#define QFPROM_PTE_EFUSE_ADDR	(MSM_QFPROM_BASE + 0x00C0)
+
+/* Corner type vreg VDD values */
+#define LVL_NONE	RPM_VREG_CORNER_NONE
+#define LVL_LOW	RPM_VREG_CORNER_LOW
+#define LVL_NOM	RPM_VREG_CORNER_NOMINAL
+#define LVL_HIGH	RPM_VREG_CORNER_HIGH
+
+enum scalables {
+	CPU0 = 0,
+	CPU1,
+	CPU2,
+	CPU3,
+	L2,
+	NUM_SCALABLES
+};
+
+enum vregs {
+	VREG_CORE,
+	VREG_MEM,
+	VREG_DIG,
+	VREG_HFPLL_A,
+	VREG_HFPLL_B,
+	NUM_VREG
+};
+
+enum hfpll_vdd_levels {
+	HFPLL_VDD_NONE,
+	HFPLL_VDD_LOW,
+	HFPLL_VDD_NOM
+};
+
+struct vreg {
+	const char name[15];
+	const unsigned int max_vdd;
+	const int rpm_vreg_voter;
+	const int rpm_vreg_id;
+	struct regulator *reg;
+	unsigned int cur_vdd;
+};
+
+struct core_speed {
+	unsigned int		khz;
+	int			src;
+	unsigned int		pri_src_sel;
+	unsigned int		sec_src_sel;
+	unsigned int		pll_l_val;
+};
+
+struct l2_level {
+	struct core_speed	speed;
+	unsigned int		vdd_dig;
+	unsigned int		vdd_mem;
+	unsigned int		bw_level;
+};
+
+struct acpu_level {
+	unsigned int		use_for_scaling;
+	struct core_speed	speed;
+	struct l2_level		*l2_level;
+	unsigned int		vdd_core;
+};
+
+struct scalable {
+	void * __iomem const hfpll_base;
+	void * __iomem const aux_clk_sel;
+	const uint32_t l2cpmr_iaddr;
+	struct core_speed *current_speed;
+	struct l2_level *l2_vote;
+	struct vreg vreg[NUM_VREG];
+	unsigned int *hfpll_vdd_tbl;
+};
+
+static unsigned int hfpll_vdd_tbl_8960[] = {
+	[HFPLL_VDD_NONE] = 0,
+	[HFPLL_VDD_LOW]  = 850000,
+	[HFPLL_VDD_NOM]  = 1050000
+};
+
+static unsigned int hfpll_vdd_tbl_8064[] = {
+	[HFPLL_VDD_NONE] = 0,
+	[HFPLL_VDD_LOW]  = 945000,
+	[HFPLL_VDD_NOM]  = 1050000
+};
+
+static unsigned int hfpll_vdd_dig_tbl_8930[] = {
+	[HFPLL_VDD_NONE] = LVL_NONE,
+	[HFPLL_VDD_LOW]  = LVL_LOW,
+	[HFPLL_VDD_NOM]  = LVL_NOM
+};
+
+static struct scalable scalable_8960[] = {
+	[CPU0] = {
+			.hfpll_base      = MSM_HFPLL_BASE + 0x200,
+			.aux_clk_sel     = MSM_ACC0_BASE  + 0x014,
+			.l2cpmr_iaddr    = L2CPUCPMR_IADDR,
+			.vreg[VREG_CORE] = { "krait0",     1300000 },
+			.vreg[VREG_MEM]  = { "krait0_mem", 1150000,
+					     RPM_VREG_VOTER1,
+					     RPM_VREG_ID_PM8921_L24 },
+			.vreg[VREG_DIG]  = { "krait0_dig", 1150000,
+					     RPM_VREG_VOTER1,
+					     RPM_VREG_ID_PM8921_S3 },
+			.vreg[VREG_HFPLL_A] = { "hfpll0_s8", 2100000,
+					     RPM_VREG_VOTER1,
+					     RPM_VREG_ID_PM8921_S8 },
+			.vreg[VREG_HFPLL_B] = { "hfpll0_l23", 1800000,
+					     RPM_VREG_VOTER1,
+					     RPM_VREG_ID_PM8921_L23 },
+		},
+	[CPU1] = {
+			.hfpll_base      = MSM_HFPLL_BASE + 0x300,
+			.aux_clk_sel     = MSM_ACC1_BASE  + 0x014,
+			.l2cpmr_iaddr    = L2CPUCPMR_IADDR,
+			.vreg[VREG_CORE] = { "krait1",     1300000 },
+			.vreg[VREG_MEM]  = { "krait1_mem", 1150000,
+					     RPM_VREG_VOTER2,
+					     RPM_VREG_ID_PM8921_L24 },
+			.vreg[VREG_DIG]  = { "krait1_dig", 1150000,
+					     RPM_VREG_VOTER2,
+					     RPM_VREG_ID_PM8921_S3 },
+			.vreg[VREG_HFPLL_A] = { "hfpll1_s8", 2100000,
+					     RPM_VREG_VOTER2,
+					     RPM_VREG_ID_PM8921_S8 },
+			.vreg[VREG_HFPLL_B] = { "hfpll1_l23", 1800000,
+					     RPM_VREG_VOTER2,
+					     RPM_VREG_ID_PM8921_L23 },
+		},
+	[L2] = {
+			.hfpll_base   = MSM_HFPLL_BASE    + 0x400,
+			.hfpll_vdd_tbl = hfpll_vdd_tbl_8960,
+			.aux_clk_sel  = MSM_APCS_GCC_BASE + 0x028,
+			.l2cpmr_iaddr = L2CPMR_IADDR,
+			.vreg[VREG_HFPLL_A] = { "hfpll_l2_s8", 2100000,
+					     RPM_VREG_VOTER6,
+					     RPM_VREG_ID_PM8921_S8 },
+			.vreg[VREG_HFPLL_B] = { "hfpll_l2_l23", 1800000,
+					     RPM_VREG_VOTER6,
+					     RPM_VREG_ID_PM8921_L23 },
+		},
+};
+
+static DEFINE_MUTEX(driver_lock);
+static DEFINE_SPINLOCK(l2_lock);
+
+static struct scalable scalable_8064[] = {
+	[CPU0] = {
+			.hfpll_base      = MSM_HFPLL_BASE + 0x200,
+			.aux_clk_sel     = MSM_ACC0_BASE  + 0x014,
+			.l2cpmr_iaddr    = L2CPUCPMR_IADDR,
+			.vreg[VREG_CORE] = { "krait0",     1300000 },
+			.vreg[VREG_MEM]  = { "krait0_mem", 1150000,
+					     RPM_VREG_VOTER1,
+					     RPM_VREG_ID_PM8921_L24 },
+			.vreg[VREG_DIG]  = { "krait0_dig", 1150000,
+					     RPM_VREG_VOTER1,
+					     RPM_VREG_ID_PM8921_S3 },
+			.vreg[VREG_HFPLL_B] = { "hfpll0", 1800000,
+					     RPM_VREG_VOTER1,
+					     RPM_VREG_ID_PM8921_LVS7 },
+		},
+	[CPU1] = {
+			.hfpll_base      = MSM_HFPLL_BASE + 0x240,
+			.aux_clk_sel     = MSM_ACC1_BASE  + 0x014,
+			.l2cpmr_iaddr    = L2CPUCPMR_IADDR,
+			.vreg[VREG_CORE] = { "krait1",     1300000 },
+			.vreg[VREG_MEM]  = { "krait1_mem", 1150000,
+					     RPM_VREG_VOTER2,
+					     RPM_VREG_ID_PM8921_L24 },
+			.vreg[VREG_DIG]  = { "krait1_dig", 1150000,
+					     RPM_VREG_VOTER2,
+					     RPM_VREG_ID_PM8921_S3 },
+			.vreg[VREG_HFPLL_B] = { "hfpll1", 1800000,
+					     RPM_VREG_VOTER2,
+					     RPM_VREG_ID_PM8921_LVS7 },
+		},
+	[CPU2] = {
+			.hfpll_base      = MSM_HFPLL_BASE + 0x280,
+			.aux_clk_sel     = MSM_ACC2_BASE  + 0x014,
+			.l2cpmr_iaddr    = L2CPUCPMR_IADDR,
+			.vreg[VREG_CORE] = { "krait2",     1300000 },
+			.vreg[VREG_MEM]  = { "krait2_mem", 1150000,
+					     RPM_VREG_VOTER4,
+					     RPM_VREG_ID_PM8921_L24 },
+			.vreg[VREG_DIG]  = { "krait2_dig", 1150000,
+					     RPM_VREG_VOTER4,
+					     RPM_VREG_ID_PM8921_S3 },
+			.vreg[VREG_HFPLL_B] = { "hfpll2", 1800000,
+					     RPM_VREG_VOTER4,
+					     RPM_VREG_ID_PM8921_LVS7 },
+		},
+	[CPU3] = {
+			.hfpll_base      = MSM_HFPLL_BASE + 0x2C0,
+			.aux_clk_sel     = MSM_ACC3_BASE  + 0x014,
+			.l2cpmr_iaddr    = L2CPUCPMR_IADDR,
+			.vreg[VREG_CORE] = { "krait3",     1300000 },
+			.vreg[VREG_MEM]  = { "krait3_mem", 1150000,
+					     RPM_VREG_VOTER5,
+					     RPM_VREG_ID_PM8921_L24 },
+			.vreg[VREG_DIG]  = { "krait3_dig", 1150000,
+					     RPM_VREG_VOTER5,
+					     RPM_VREG_ID_PM8921_S3 },
+			.vreg[VREG_HFPLL_B] = { "hfpll3", 1800000,
+					     RPM_VREG_VOTER5,
+					     RPM_VREG_ID_PM8921_LVS7 },
+		},
+	[L2] = {
+			.hfpll_base   = MSM_HFPLL_BASE    + 0x300,
+			.hfpll_vdd_tbl = hfpll_vdd_tbl_8064,
+			.aux_clk_sel  = MSM_APCS_GCC_BASE + 0x028,
+			.l2cpmr_iaddr = L2CPMR_IADDR,
+			.vreg[VREG_HFPLL_B] = { "hfpll_l2", 1800000,
+					     RPM_VREG_VOTER6,
+					     RPM_VREG_ID_PM8921_LVS7 },
+		},
+};
+
+static struct scalable scalable_8930[] = {
+	[CPU0] = {
+			.hfpll_base      = MSM_HFPLL_BASE + 0x200,
+			.aux_clk_sel     = MSM_ACC0_BASE  + 0x014,
+			.l2cpmr_iaddr    = L2CPUCPMR_IADDR,
+			.vreg[VREG_CORE] = { "krait0",     1300000 },
+			.vreg[VREG_MEM]  = { "krait0_mem", 1150000,
+					     RPM_VREG_VOTER1,
+					     RPM_VREG_ID_PM8038_L24 },
+			.vreg[VREG_DIG]  = { "krait0_dig", LVL_HIGH,
+					     RPM_VREG_VOTER1,
+					     RPM_VREG_ID_PM8038_VDD_DIG_CORNER
+					   },
+			.vreg[VREG_HFPLL_B] = { "hfpll0", 1800000,
+					     RPM_VREG_VOTER1,
+					     RPM_VREG_ID_PM8038_L23 },
+		},
+	[CPU1] = {
+			.hfpll_base      = MSM_HFPLL_BASE + 0x300,
+			.aux_clk_sel     = MSM_ACC1_BASE  + 0x014,
+			.l2cpmr_iaddr    = L2CPUCPMR_IADDR,
+			.vreg[VREG_CORE] = { "krait1",     1300000 },
+			.vreg[VREG_MEM]  = { "krait1_mem", 1150000,
+					     RPM_VREG_VOTER2,
+					     RPM_VREG_ID_PM8038_L24 },
+			.vreg[VREG_DIG]  = { "krait1_dig", LVL_HIGH,
+					     RPM_VREG_VOTER2,
+					     RPM_VREG_ID_PM8038_VDD_DIG_CORNER
+					   },
+			.vreg[VREG_HFPLL_B] = { "hfpll1", 1800000,
+					     RPM_VREG_VOTER2,
+					     RPM_VREG_ID_PM8038_L23 },
+		},
+	[L2] = {
+			.hfpll_base   = MSM_HFPLL_BASE    + 0x400,
+			.hfpll_vdd_tbl = hfpll_vdd_dig_tbl_8930,
+			.aux_clk_sel  = MSM_APCS_GCC_BASE + 0x028,
+			.l2cpmr_iaddr = L2CPMR_IADDR,
+			.vreg[VREG_HFPLL_B] = { "hfpll_l2", 1800000,
+					     RPM_VREG_VOTER6,
+					     RPM_VREG_ID_PM8038_L23 },
+		},
+};
+
+/*TODO: Update the rpm vreg id when the rpm driver is ready */
+static struct scalable scalable_8627[] = {
+	[CPU0] = {
+			.hfpll_base      = MSM_HFPLL_BASE + 0x200,
+			.aux_clk_sel     = MSM_ACC0_BASE  + 0x014,
+			.l2cpmr_iaddr    = L2CPUCPMR_IADDR,
+			.vreg[VREG_CORE] = { "krait0",     1300000 },
+			.vreg[VREG_MEM]  = { "krait0_mem", 1150000,
+					     RPM_VREG_VOTER1,
+					     RPM_VREG_ID_PM8038_L24 },
+			.vreg[VREG_DIG]  = { "krait0_dig", LVL_HIGH,
+					     RPM_VREG_VOTER1,
+					     RPM_VREG_ID_PM8038_VDD_DIG_CORNER
+					   },
+			.vreg[VREG_HFPLL_B] = { "hfpll0", 1800000,
+					     RPM_VREG_VOTER1,
+					     RPM_VREG_ID_PM8038_L23 },
+		},
+	[CPU1] = {
+			.hfpll_base      = MSM_HFPLL_BASE + 0x300,
+			.aux_clk_sel     = MSM_ACC1_BASE  + 0x014,
+			.l2cpmr_iaddr    = L2CPUCPMR_IADDR,
+			.vreg[VREG_CORE] = { "krait1",     1300000 },
+			.vreg[VREG_MEM]  = { "krait1_mem", 1150000,
+					     RPM_VREG_VOTER2,
+					     RPM_VREG_ID_PM8038_L24 },
+			.vreg[VREG_DIG]  = { "krait1_dig", LVL_HIGH,
+					     RPM_VREG_VOTER2,
+					     RPM_VREG_ID_PM8038_VDD_DIG_CORNER
+					   },
+			.vreg[VREG_HFPLL_B] = { "hfpll1", 1800000,
+					     RPM_VREG_VOTER2,
+					     RPM_VREG_ID_PM8038_L23 },
+		},
+	[L2] = {
+			.hfpll_base   = MSM_HFPLL_BASE    + 0x400,
+			.hfpll_vdd_tbl = hfpll_vdd_dig_tbl_8930,
+			.aux_clk_sel  = MSM_APCS_GCC_BASE + 0x028,
+			.l2cpmr_iaddr = L2CPMR_IADDR,
+			.vreg[VREG_HFPLL_B] = { "hfpll_l2", 1800000,
+					     RPM_VREG_VOTER6,
+					     RPM_VREG_ID_PM8038_L23 },
+		},
+};
+
+static struct l2_level *l2_freq_tbl;
+static struct acpu_level *acpu_freq_tbl;
+static int l2_freq_tbl_size;
+static struct scalable *scalable;
+#define SCALABLE_TO_CPU(sc) ((sc) - scalable)
+
+/* Instantaneous bandwidth requests in MB/s. */
+#define BW_MBPS(_bw) \
+	{ \
+		.vectors = (struct msm_bus_vectors[]){ \
+			{\
+				.src = MSM_BUS_MASTER_AMPSS_M0, \
+				.dst = MSM_BUS_SLAVE_EBI_CH0, \
+				.ib = (_bw) * 1000000UL, \
+				.ab = (_bw) *  100000UL, \
+			}, \
+			{ \
+				.src = MSM_BUS_MASTER_AMPSS_M1, \
+				.dst = MSM_BUS_SLAVE_EBI_CH0, \
+				.ib = (_bw) * 1000000UL, \
+				.ab = (_bw) *  100000UL, \
+			}, \
+		}, \
+		.num_paths = 2, \
+	}
+static struct msm_bus_paths bw_level_tbl[] = {
+	[0] =  BW_MBPS(640), /* At least  80 MHz on bus. */
+	[1] = BW_MBPS(1064), /* At least 133 MHz on bus. */
+	[2] = BW_MBPS(1600), /* At least 200 MHz on bus. */
+	[3] = BW_MBPS(2128), /* At least 266 MHz on bus. */
+	[4] = BW_MBPS(3200), /* At least 400 MHz on bus. */
+	[5] = BW_MBPS(3600), /* At least 450 MHz on bus. */
+	[6] = BW_MBPS(3936), /* At least 492 MHz on bus. */
+	[7] = BW_MBPS(4264), /* At least 533 MHz on bus. */
+};
+
+static struct msm_bus_scale_pdata bus_client_pdata = {
+	.usecase = bw_level_tbl,
+	.num_usecases = ARRAY_SIZE(bw_level_tbl),
+	.active_only = 1,
+	.name = "acpuclock",
+};
+
+static uint32_t bus_perf_client;
+
+/* TODO: Update vdd_dig and vdd_mem when voltage data is available. */
+#define L2(x) (&l2_freq_tbl_8960_kraitv1[(x)])
+static struct l2_level l2_freq_tbl_8960_kraitv1[] = {
+	[0]  = { {STBY_KHZ, QSB,   0, 0, 0x00 }, 1050000, 1050000, 0 },
+	[1]  = { {  384000, PLL_8, 0, 2, 0x00 }, 1050000, 1050000, 1 },
+	[2]  = { {  432000, HFPLL, 2, 0, 0x20 }, 1050000, 1050000, 1 },
+	[3]  = { {  486000, HFPLL, 2, 0, 0x24 }, 1050000, 1050000, 1 },
+	[4]  = { {  540000, HFPLL, 2, 0, 0x28 }, 1050000, 1050000, 1 },
+	[5]  = { {  594000, HFPLL, 1, 0, 0x16 }, 1050000, 1050000, 2 },
+	[6]  = { {  648000, HFPLL, 1, 0, 0x18 }, 1050000, 1050000, 2 },
+	[7]  = { {  702000, HFPLL, 1, 0, 0x1A }, 1050000, 1050000, 2 },
+	[8]  = { {  756000, HFPLL, 1, 0, 0x1C }, 1150000, 1150000, 2 },
+	[9]  = { {  810000, HFPLL, 1, 0, 0x1E }, 1150000, 1150000, 3 },
+	[10] = { {  864000, HFPLL, 1, 0, 0x20 }, 1150000, 1150000, 3 },
+	[11] = { {  918000, HFPLL, 1, 0, 0x22 }, 1150000, 1150000, 3 },
+};
+
+static struct acpu_level acpu_freq_tbl_8960_kraitv1_slow[] = {
+	{ 0, {STBY_KHZ, QSB,   0, 0, 0x00 }, L2(0),   900000 },
+	{ 1, {  384000, PLL_8, 0, 2, 0x00 }, L2(1),   900000 },
+	{ 1, {  432000, HFPLL, 2, 0, 0x20 }, L2(6),   925000 },
+	{ 1, {  486000, HFPLL, 2, 0, 0x24 }, L2(6),   925000 },
+	{ 1, {  540000, HFPLL, 2, 0, 0x28 }, L2(6),   937500 },
+	{ 1, {  594000, HFPLL, 1, 0, 0x16 }, L2(6),   962500 },
+	{ 1, {  648000, HFPLL, 1, 0, 0x18 }, L2(6),   987500 },
+	{ 1, {  702000, HFPLL, 1, 0, 0x1A }, L2(6),  1000000 },
+	{ 1, {  756000, HFPLL, 1, 0, 0x1C }, L2(11), 1025000 },
+	{ 1, {  810000, HFPLL, 1, 0, 0x1E }, L2(11), 1062500 },
+	{ 1, {  864000, HFPLL, 1, 0, 0x20 }, L2(11), 1062500 },
+	{ 1, {  918000, HFPLL, 1, 0, 0x22 }, L2(11), 1087500 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_8960_kraitv1_nom_fast[] = {
+	{ 0, {STBY_KHZ, QSB,   0, 0, 0x00 }, L2(0),   862500 },
+	{ 1, {  384000, PLL_8, 0, 2, 0x00 }, L2(1),   862500 },
+	{ 1, {  432000, HFPLL, 2, 0, 0x20 }, L2(6),   862500 },
+	{ 1, {  486000, HFPLL, 2, 0, 0x24 }, L2(6),   887500 },
+	{ 1, {  540000, HFPLL, 2, 0, 0x28 }, L2(6),   900000 },
+	{ 1, {  594000, HFPLL, 1, 0, 0x16 }, L2(6),   925000 },
+	{ 1, {  648000, HFPLL, 1, 0, 0x18 }, L2(6),   925000 },
+	{ 1, {  702000, HFPLL, 1, 0, 0x1A }, L2(6),   937500 },
+	{ 1, {  756000, HFPLL, 1, 0, 0x1C }, L2(11),  962500 },
+	{ 1, {  810000, HFPLL, 1, 0, 0x1E }, L2(11), 1012500 },
+	{ 1, {  864000, HFPLL, 1, 0, 0x20 }, L2(11), 1025000 },
+	{ 1, {  918000, HFPLL, 1, 0, 0x22 }, L2(11), 1025000 },
+	{ 0, { 0 } }
+};
+
+#undef L2
+#define L2(x) (&l2_freq_tbl_8960_kraitv2[(x)])
+static struct l2_level l2_freq_tbl_8960_kraitv2[] = {
+	[0]  = { {STBY_KHZ, QSB,   0, 0, 0x00 }, 1050000, 1050000, 0 },
+	[1]  = { {  384000, PLL_8, 0, 2, 0x00 }, 1050000, 1050000, 1 },
+	[2]  = { {  432000, HFPLL, 2, 0, 0x20 }, 1050000, 1050000, 2 },
+	[3]  = { {  486000, HFPLL, 2, 0, 0x24 }, 1050000, 1050000, 2 },
+	[4]  = { {  540000, HFPLL, 2, 0, 0x28 }, 1050000, 1050000, 2 },
+	[5]  = { {  594000, HFPLL, 1, 0, 0x16 }, 1050000, 1050000, 2 },
+	[6]  = { {  648000, HFPLL, 1, 0, 0x18 }, 1050000, 1050000, 4 },
+	[7]  = { {  702000, HFPLL, 1, 0, 0x1A }, 1050000, 1050000, 4 },
+	[8]  = { {  756000, HFPLL, 1, 0, 0x1C }, 1150000, 1150000, 4 },
+	[9]  = { {  810000, HFPLL, 1, 0, 0x1E }, 1150000, 1150000, 4 },
+	[10] = { {  864000, HFPLL, 1, 0, 0x20 }, 1150000, 1150000, 4 },
+	[11] = { {  918000, HFPLL, 1, 0, 0x22 }, 1150000, 1150000, 6 },
+	[12] = { {  972000, HFPLL, 1, 0, 0x24 }, 1150000, 1150000, 6 },
+	[13] = { { 1026000, HFPLL, 1, 0, 0x26 }, 1150000, 1150000, 6 },
+	[14] = { { 1080000, HFPLL, 1, 0, 0x28 }, 1150000, 1150000, 6 },
+	[15] = { { 1134000, HFPLL, 1, 0, 0x2A }, 1150000, 1150000, 6 },
+	[16] = { { 1188000, HFPLL, 1, 0, 0x2C }, 1150000, 1150000, 6 },
+	[17] = { { 1242000, HFPLL, 1, 0, 0x2E }, 1150000, 1150000, 6 },
+	[18] = { { 1296000, HFPLL, 1, 0, 0x30 }, 1150000, 1150000, 6 },
+	[19] = { { 1350000, HFPLL, 1, 0, 0x32 }, 1150000, 1150000, 6 },
+};
+
+static struct acpu_level acpu_freq_tbl_8960_kraitv2_slow[] = {
+	{ 0, { STBY_KHZ, QSB,   0, 0, 0x00 }, L2(0),   950000 },
+	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(1),   950000 },
+	{ 0, {   432000, HFPLL, 2, 0, 0x20 }, L2(7),   975000 },
+	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(7),   975000 },
+	{ 0, {   540000, HFPLL, 2, 0, 0x28 }, L2(7),  1000000 },
+	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(7),  1000000 },
+	{ 0, {   648000, HFPLL, 1, 0, 0x18 }, L2(7),  1025000 },
+	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(7),  1025000 },
+	{ 0, {   756000, HFPLL, 1, 0, 0x1C }, L2(7),  1075000 },
+	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(7),  1075000 },
+	{ 0, {   864000, HFPLL, 1, 0, 0x20 }, L2(7),  1100000 },
+	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(7),  1100000 },
+	{ 0, {   972000, HFPLL, 1, 0, 0x24 }, L2(7),  1125000 },
+	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(7),  1125000 },
+	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(19), 1175000 },
+	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(19), 1175000 },
+	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(19), 1200000 },
+	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(19), 1200000 },
+	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(19), 1225000 },
+	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(19), 1225000 },
+	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(19), 1237500 },
+	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(19), 1237500 },
+	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(19), 1250000 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_8960_kraitv2_nom[] = {
+	{ 0, { STBY_KHZ, QSB,   0, 0, 0x00 }, L2(0),   900000 },
+	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(1),   900000 },
+	{ 0, {   432000, HFPLL, 2, 0, 0x20 }, L2(7),   925000 },
+	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(7),   925000 },
+	{ 0, {   540000, HFPLL, 2, 0, 0x28 }, L2(7),   950000 },
+	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(7),   950000 },
+	{ 0, {   648000, HFPLL, 1, 0, 0x18 }, L2(7),   975000 },
+	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(7),   975000 },
+	{ 0, {   756000, HFPLL, 1, 0, 0x1C }, L2(7),  1025000 },
+	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(7),  1025000 },
+	{ 0, {   864000, HFPLL, 1, 0, 0x20 }, L2(7),  1050000 },
+	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(7),  1050000 },
+	{ 0, {   972000, HFPLL, 1, 0, 0x24 }, L2(7),  1075000 },
+	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(7),  1075000 },
+	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(19), 1125000 },
+	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(19), 1125000 },
+	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(19), 1150000 },
+	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(19), 1150000 },
+	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(19), 1175000 },
+	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(19), 1175000 },
+	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(19), 1187500 },
+	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(19), 1187500 },
+	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(19), 1200000 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_8960_kraitv2_fast[] = {
+	{ 0, { STBY_KHZ, QSB,   0, 0, 0x00 }, L2(0),   850000 },
+	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(1),   850000 },
+	{ 0, {   432000, HFPLL, 2, 0, 0x20 }, L2(7),   875000 },
+	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(7),   875000 },
+	{ 0, {   540000, HFPLL, 2, 0, 0x28 }, L2(7),   900000 },
+	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(7),   900000 },
+	{ 0, {   648000, HFPLL, 1, 0, 0x18 }, L2(7),   925000 },
+	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(7),   925000 },
+	{ 0, {   756000, HFPLL, 1, 0, 0x1C }, L2(7),   975000 },
+	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(7),   975000 },
+	{ 0, {   864000, HFPLL, 1, 0, 0x20 }, L2(7),  1000000 },
+	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(7),  1000000 },
+	{ 0, {   972000, HFPLL, 1, 0, 0x24 }, L2(7),  1025000 },
+	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(7),  1025000 },
+	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(19), 1075000 },
+	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(19), 1075000 },
+	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(19), 1100000 },
+	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(19), 1100000 },
+	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(19), 1125000 },
+	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(19), 1125000 },
+	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(19), 1137500 },
+	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(19), 1137500 },
+	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(19), 1150000 },
+	{ 0, { 0 } }
+};
+
+/* TODO: Update vdd_dig and vdd_mem when voltage data is available. */
+#undef L2
+#define L2(x) (&l2_freq_tbl_8064[(x)])
+static struct l2_level l2_freq_tbl_8064[] = {
+	[0]  = { {STBY_KHZ, QSB,   0, 0, 0x00 }, 1050000, 1050000, 0 },
+	[1]  = { {  384000, PLL_8, 0, 2, 0x00 }, 1050000, 1050000, 1 },
+	[2]  = { {  432000, HFPLL, 2, 0, 0x20 }, 1050000, 1050000, 2 },
+	[3]  = { {  486000, HFPLL, 2, 0, 0x24 }, 1050000, 1050000, 2 },
+	[4]  = { {  540000, HFPLL, 2, 0, 0x28 }, 1050000, 1050000, 2 },
+	[5]  = { {  594000, HFPLL, 1, 0, 0x16 }, 1050000, 1050000, 2 },
+	[6]  = { {  648000, HFPLL, 1, 0, 0x18 }, 1050000, 1050000, 4 },
+	[7]  = { {  702000, HFPLL, 1, 0, 0x1A }, 1050000, 1050000, 4 },
+	[8]  = { {  756000, HFPLL, 1, 0, 0x1C }, 1150000, 1150000, 4 },
+	[9]  = { {  810000, HFPLL, 1, 0, 0x1E }, 1150000, 1150000, 4 },
+	[10] = { {  864000, HFPLL, 1, 0, 0x20 }, 1150000, 1150000, 4 },
+	[11] = { {  918000, HFPLL, 1, 0, 0x22 }, 1150000, 1150000, 7 },
+	[12] = { {  972000, HFPLL, 1, 0, 0x24 }, 1150000, 1150000, 7 },
+	[13] = { { 1026000, HFPLL, 1, 0, 0x26 }, 1150000, 1150000, 7 },
+	[14] = { { 1080000, HFPLL, 1, 0, 0x28 }, 1150000, 1150000, 7 },
+	[15] = { { 1134000, HFPLL, 1, 0, 0x2A }, 1150000, 1150000, 7 },
+};
+
+/* TODO: Update core voltages when data is available. */
+static struct acpu_level acpu_freq_tbl_8064[] = {
+	{ 0, { STBY_KHZ, QSB,   0, 0, 0x00 }, L2(0),   950000 },
+	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(1),   950000 },
+	{ 0, {   432000, HFPLL, 2, 0, 0x20 }, L2(7),   975000 },
+	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(7),   975000 },
+	{ 0, {   540000, HFPLL, 2, 0, 0x28 }, L2(7),  1000000 },
+	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(7),  1000000 },
+	{ 0, {   648000, HFPLL, 1, 0, 0x18 }, L2(7),  1025000 },
+	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(7),  1025000 },
+	{ 0, {   756000, HFPLL, 1, 0, 0x1C }, L2(7),  1075000 },
+	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(7),  1075000 },
+	{ 0, {   864000, HFPLL, 1, 0, 0x20 }, L2(7),  1100000 },
+	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(7),  1100000 },
+	{ 0, {   972000, HFPLL, 1, 0, 0x24 }, L2(7),  1125000 },
+	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(7),  1125000 },
+	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1175000 },
+	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1175000 },
+	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1200000 },
+	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1200000 },
+	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1225000 },
+	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1225000 },
+	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1237500 },
+	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(15), 1237500 },
+	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1250000 },
+	{ 0, { 0 } }
+};
+
+/* TODO: Update vdd_dig, vdd_mem and bw when data is available. */
+#undef L2
+#define L2(x) (&l2_freq_tbl_8930[(x)])
+static struct l2_level l2_freq_tbl_8930[] = {
+	[0]  = { {STBY_KHZ, QSB,   0, 0, 0x00 },  LVL_NOM, 1050000, 0 },
+	[1]  = { {  384000, PLL_8, 0, 2, 0x00 },  LVL_NOM, 1050000, 1 },
+	[2]  = { {  432000, HFPLL, 2, 0, 0x20 },  LVL_NOM, 1050000, 2 },
+	[3]  = { {  486000, HFPLL, 2, 0, 0x24 },  LVL_NOM, 1050000, 2 },
+	[4]  = { {  540000, HFPLL, 2, 0, 0x28 },  LVL_NOM, 1050000, 2 },
+	[5]  = { {  594000, HFPLL, 1, 0, 0x16 },  LVL_NOM, 1050000, 2 },
+	[6]  = { {  648000, HFPLL, 1, 0, 0x18 },  LVL_NOM, 1050000, 4 },
+	[7]  = { {  702000, HFPLL, 1, 0, 0x1A },  LVL_NOM, 1050000, 4 },
+	[8]  = { {  756000, HFPLL, 1, 0, 0x1C }, LVL_HIGH, 1150000, 4 },
+	[9]  = { {  810000, HFPLL, 1, 0, 0x1E }, LVL_HIGH, 1150000, 4 },
+	[10] = { {  864000, HFPLL, 1, 0, 0x20 }, LVL_HIGH, 1150000, 4 },
+	[11] = { {  918000, HFPLL, 1, 0, 0x22 }, LVL_HIGH, 1150000, 7 },
+	[12] = { {  972000, HFPLL, 1, 0, 0x24 }, LVL_HIGH, 1150000, 7 },
+	[13] = { { 1026000, HFPLL, 1, 0, 0x26 }, LVL_HIGH, 1150000, 7 },
+	[14] = { { 1080000, HFPLL, 1, 0, 0x28 }, LVL_HIGH, 1150000, 7 },
+	[15] = { { 1134000, HFPLL, 1, 0, 0x2A }, LVL_HIGH, 1150000, 7 },
+	[16] = { { 1188000, HFPLL, 1, 0, 0x2C }, LVL_HIGH, 1150000, 7 },
+};
+
+/* TODO: Update core voltages when data is available. */
+static struct acpu_level acpu_freq_tbl_8930[] = {
+	{ 0, { STBY_KHZ, QSB,   0, 0, 0x00 }, L2(0),   925000 },
+	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(1),   925000 },
+	{ 1, {   432000, HFPLL, 2, 0, 0x20 }, L2(6),   937500 },
+	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(6),   962500 },
+	{ 1, {   540000, HFPLL, 2, 0, 0x28 }, L2(6),   987500 },
+	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(6),  1000000 },
+	{ 1, {   648000, HFPLL, 1, 0, 0x18 }, L2(6),  1025000 },
+	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(6),  1037500 },
+	{ 1, {   756000, HFPLL, 1, 0, 0x1C }, L2(11), 1062500 },
+	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(11), 1087500 },
+	{ 1, {   864000, HFPLL, 1, 0, 0x20 }, L2(11), 1100000 },
+	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(11), 1125000 },
+	{ 1, {   972000, HFPLL, 1, 0, 0x24 }, L2(16), 1137500 },
+	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(16), 1162500 },
+	{ 1, {  1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1187500 },
+	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1200000 },
+	{ 1, {  1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1225000 },
+	{ 0, { 0 } }
+};
+
+/* TODO: Update vdd_dig, vdd_mem and bw when data is available. */
+#undef L2
+#define L2(x) (&l2_freq_tbl_8627[(x)])
+static struct l2_level l2_freq_tbl_8627[] = {
+	[0]  = { {STBY_KHZ, QSB,   0, 0, 0x00 },  LVL_NOM, 1050000, 0 },
+	[1]  = { {  384000, PLL_8, 0, 2, 0x00 },  LVL_NOM, 1050000, 1 },
+	[2]  = { {  432000, HFPLL, 2, 0, 0x20 },  LVL_NOM, 1050000, 1 },
+	[3]  = { {  486000, HFPLL, 2, 0, 0x24 },  LVL_NOM, 1050000, 1 },
+	[4]  = { {  540000, HFPLL, 2, 0, 0x28 },  LVL_NOM, 1050000, 2 },
+	[5]  = { {  594000, HFPLL, 1, 0, 0x16 },  LVL_NOM, 1050000, 2 },
+	[6]  = { {  648000, HFPLL, 1, 0, 0x18 },  LVL_NOM, 1050000, 2 },
+	[7]  = { {  702000, HFPLL, 1, 0, 0x1A },  LVL_NOM, 1050000, 3 },
+	[8]  = { {  756000, HFPLL, 1, 0, 0x1C }, LVL_HIGH, 1150000, 3 },
+	[9]  = { {  810000, HFPLL, 1, 0, 0x1E }, LVL_HIGH, 1150000, 3 },
+	[10] = { {  864000, HFPLL, 1, 0, 0x20 }, LVL_HIGH, 1150000, 4 },
+	[11] = { {  918000, HFPLL, 1, 0, 0x22 }, LVL_HIGH, 1150000, 4 },
+	[12] = { {  972000, HFPLL, 1, 0, 0x24 }, LVL_HIGH, 1150000, 4 },
+};
+
+/* TODO: Update core voltages when data is available. */
+static struct acpu_level acpu_freq_tbl_8627[] = {
+	{ 0, { STBY_KHZ, QSB,   0, 0, 0x00 }, L2(0),   900000 },
+	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(1),   900000 },
+	{ 1, {   432000, HFPLL, 2, 0, 0x20 }, L2(5),   925000 },
+	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(5),   925000 },
+	{ 1, {   540000, HFPLL, 2, 0, 0x28 }, L2(5),   937500 },
+	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(5),   962500 },
+	{ 1, {   648000, HFPLL, 1, 0, 0x18 }, L2(9),   987500 },
+	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(9),  1000000 },
+	{ 1, {   756000, HFPLL, 1, 0, 0x1C }, L2(9),  1025000 },
+	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(9),  1062500 },
+	{ 1, {   864000, HFPLL, 1, 0, 0x20 }, L2(12), 1062500 },
+	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(12), 1087500 },
+	{ 1, {   972000, HFPLL, 1, 0, 0x24 }, L2(12), 1100000 },
+	{ 0, { 0 } }
+};
+
+static unsigned long acpuclk_8960_get_rate(int cpu)
+{
+	return scalable[cpu].current_speed->khz;
+}
+
+/* Get the selected source on primary MUX. */
+static int get_pri_clk_src(struct scalable *sc)
+{
+	uint32_t regval;
+
+	regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
+	return regval & 0x3;
+}
+
+/* Set the selected source on primary MUX. */
+static void set_pri_clk_src(struct scalable *sc, uint32_t pri_src_sel)
+{
+	uint32_t regval;
+
+	regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
+	regval &= ~0x3;
+	regval |= (pri_src_sel & 0x3);
+	set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
+	/* Wait for switch to complete. */
+	mb();
+	udelay(1);
+}
+
+/* Get the selected source on secondary MUX. */
+static int get_sec_clk_src(struct scalable *sc)
+{
+	uint32_t regval;
+
+	regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
+	return (regval >> 2) & 0x3;
+}
+
+/* Set the selected source on secondary MUX. */
+static void set_sec_clk_src(struct scalable *sc, uint32_t sec_src_sel)
+{
+	uint32_t regval;
+
+	/* Disable secondary source clock gating during switch. */
+	regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
+	regval |= SECCLKAGD;
+	set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
+
+	/* Program the MUX. */
+	regval &= ~(0x3 << 2);
+	regval |= ((sec_src_sel & 0x3) << 2);
+	set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
+
+	/* Wait for switch to complete. */
+	mb();
+	udelay(1);
+
+	/* Re-enable secondary source clock gating. */
+	regval &= ~SECCLKAGD;
+	set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
+}
+
+/* Enable an already-configured HFPLL. */
+static void hfpll_enable(struct scalable *sc, bool skip_regulators)
+{
+	int rc;
+
+	if (!skip_regulators) {
+		if (cpu_is_msm8960()) {
+			rc = rpm_vreg_set_voltage(
+					sc->vreg[VREG_HFPLL_A].rpm_vreg_id,
+					sc->vreg[VREG_HFPLL_A].rpm_vreg_voter,
+					2050000,
+					sc->vreg[VREG_HFPLL_A].max_vdd, 0);
+			if (rc)
+				pr_err("%s regulator enable failed (%d)\n",
+					sc->vreg[VREG_HFPLL_A].name, rc);
+		}
+		rc = rpm_vreg_set_voltage(sc->vreg[VREG_HFPLL_B].rpm_vreg_id,
+				sc->vreg[VREG_HFPLL_B].rpm_vreg_voter, 1800000,
+				sc->vreg[VREG_HFPLL_B].max_vdd, 0);
+		if (rc)
+			pr_err("%s regulator enable failed (%d)\n",
+				sc->vreg[VREG_HFPLL_B].name, rc);
+	}
+	/* Disable PLL bypass mode. */
+	writel_relaxed(0x2, sc->hfpll_base + HFPLL_MODE);
+
+	/*
+	 * H/W requires a 5us delay between disabling the bypass and
+	 * de-asserting the reset. Delay 10us just to be safe.
+	 */
+	mb();
+	udelay(10);
+
+	/* De-assert active-low PLL reset. */
+	writel_relaxed(0x6, sc->hfpll_base + HFPLL_MODE);
+
+	/* Wait for PLL to lock. */
+	mb();
+	udelay(60);
+
+	/* Enable PLL output. */
+	writel_relaxed(0x7, sc->hfpll_base + HFPLL_MODE);
+}
+
+/* Disable a HFPLL for power-savings or while its being reprogrammed. */
+static void hfpll_disable(struct scalable *sc, bool skip_regulators)
+{
+	int rc;
+
+	/*
+	 * Disable the PLL output, disable test mode, enable
+	 * the bypass mode, and assert the reset.
+	 */
+	writel_relaxed(0, sc->hfpll_base + HFPLL_MODE);
+
+	if (!skip_regulators) {
+		rc = rpm_vreg_set_voltage(sc->vreg[VREG_HFPLL_B].rpm_vreg_id,
+				sc->vreg[VREG_HFPLL_B].rpm_vreg_voter, 0,
+				0, 0);
+		if (rc)
+			pr_err("%s regulator enable failed (%d)\n",
+				sc->vreg[VREG_HFPLL_B].name, rc);
+
+		if (cpu_is_msm8960()) {
+			rc = rpm_vreg_set_voltage(
+					sc->vreg[VREG_HFPLL_A].rpm_vreg_id,
+					sc->vreg[VREG_HFPLL_A].rpm_vreg_voter,
+					0, 0, 0);
+			if (rc)
+				pr_err("%s regulator enable failed (%d)\n",
+					sc->vreg[VREG_HFPLL_A].name, rc);
+		}
+	}
+}
+
+/* Program the HFPLL rate. Assumes HFPLL is already disabled. */
+static void hfpll_set_rate(struct scalable *sc, struct core_speed *tgt_s)
+{
+	writel_relaxed(tgt_s->pll_l_val, sc->hfpll_base + HFPLL_L_VAL);
+}
+
+/* Return the L2 speed that should be applied. */
+static struct l2_level *compute_l2_level(struct scalable *sc,
+					 struct l2_level *vote_l)
+{
+	struct l2_level *new_l;
+	int cpu;
+
+	/* Bounds check. */
+	BUG_ON(vote_l >= (l2_freq_tbl + l2_freq_tbl_size));
+
+	/* Find max L2 speed vote. */
+	sc->l2_vote = vote_l;
+	new_l = l2_freq_tbl;
+	for_each_present_cpu(cpu)
+		new_l = max(new_l, scalable[cpu].l2_vote);
+
+	return new_l;
+}
+
+/* Update the bus bandwidth request. */
+static void set_bus_bw(unsigned int bw)
+{
+	int ret;
+
+	/* Bounds check. */
+	if (bw >= ARRAY_SIZE(bw_level_tbl)) {
+		pr_err("invalid bandwidth request (%d)\n", bw);
+		return;
+	}
+
+	/* Update bandwidth if request has changed. This may sleep. */
+	ret = msm_bus_scale_client_update_request(bus_perf_client, bw);
+	if (ret)
+		pr_err("bandwidth request failed (%d)\n", ret);
+}
+
+/* Set the CPU or L2 clock speed. */
+static void set_speed(struct scalable *sc, struct core_speed *tgt_s,
+		      enum setrate_reason reason)
+{
+	struct core_speed *strt_s = sc->current_speed;
+
+	if (tgt_s == strt_s)
+		return;
+
+	if (strt_s->src == HFPLL && tgt_s->src == HFPLL) {
+		/*
+		 * Move to an always-on source running at a frequency that does
+		 * not require an elevated CPU voltage. PLL8 is used here.
+		 */
+		set_sec_clk_src(sc, SEC_SRC_SEL_AUX);
+		set_pri_clk_src(sc, PRI_SRC_SEL_SEC_SRC);
+
+		/* Program CPU HFPLL. */
+		hfpll_disable(sc, 1);
+		hfpll_set_rate(sc, tgt_s);
+		hfpll_enable(sc, 1);
+
+		/* Move CPU to HFPLL source. */
+		set_pri_clk_src(sc, tgt_s->pri_src_sel);
+	} else if (strt_s->src == HFPLL && tgt_s->src != HFPLL) {
+		/*
+		 * If responding to CPU_DEAD we must be running on another CPU.
+		 * Therefore, we can't access the downed CPU's clock MUX CP15
+		 * registers from here and can't change clock sources. If the
+		 * CPU is collapsed, however, it is still safe to turn off the
+		 * PLL without switching the MUX away from it.
+		 */
+		if (reason != SETRATE_HOTPLUG || sc == &scalable[L2]) {
+			set_sec_clk_src(sc, tgt_s->sec_src_sel);
+			set_pri_clk_src(sc, tgt_s->pri_src_sel);
+			hfpll_disable(sc, 0);
+		} else if (reason == SETRATE_HOTPLUG
+			   && msm_pm_verify_cpu_pc(SCALABLE_TO_CPU(sc))) {
+			hfpll_disable(sc, 0);
+		}
+	} else if (strt_s->src != HFPLL && tgt_s->src == HFPLL) {
+		/*
+		 * If responding to CPU_UP_PREPARE, we can't change CP15
+		 * registers for the CPU that's coming up since we're not
+		 * running on that CPU.  That's okay though, since the MUX
+		 * source was not changed on the way down, either.
+		 */
+		if (reason != SETRATE_HOTPLUG || sc == &scalable[L2]) {
+			hfpll_set_rate(sc, tgt_s);
+			hfpll_enable(sc, 0);
+			set_pri_clk_src(sc, tgt_s->pri_src_sel);
+		} else if (reason == SETRATE_HOTPLUG
+			   && msm_pm_verify_cpu_pc(SCALABLE_TO_CPU(sc))) {
+			/* PLL was disabled during hot-unplug. Re-enable it. */
+			hfpll_set_rate(sc, tgt_s);
+			hfpll_enable(sc, 0);
+		}
+	} else {
+		if (reason != SETRATE_HOTPLUG || sc == &scalable[L2])
+			set_sec_clk_src(sc, tgt_s->sec_src_sel);
+	}
+
+	sc->current_speed = tgt_s;
+}
+
+/* Apply any per-cpu voltage increases. */
+static int increase_vdd(int cpu, unsigned int vdd_core, unsigned int vdd_mem,
+			unsigned int vdd_dig, enum setrate_reason reason)
+{
+	struct scalable *sc = &scalable[cpu];
+	int rc = 0;
+
+	/*
+	 * Increase vdd_mem active-set before vdd_dig.
+	 * vdd_mem should be >= vdd_dig.
+	 */
+	if (vdd_mem > sc->vreg[VREG_MEM].cur_vdd) {
+		rc = rpm_vreg_set_voltage(sc->vreg[VREG_MEM].rpm_vreg_id,
+				sc->vreg[VREG_MEM].rpm_vreg_voter, vdd_mem,
+				sc->vreg[VREG_MEM].max_vdd, 0);
+		if (rc) {
+			pr_err("%s increase failed (%d)\n",
+				sc->vreg[VREG_MEM].name, rc);
+			return rc;
+		}
+		 sc->vreg[VREG_MEM].cur_vdd = vdd_mem;
+	}
+
+	/* Increase vdd_dig active-set vote. */
+	if (vdd_dig > sc->vreg[VREG_DIG].cur_vdd) {
+		rc = rpm_vreg_set_voltage(sc->vreg[VREG_DIG].rpm_vreg_id,
+				sc->vreg[VREG_DIG].rpm_vreg_voter, vdd_dig,
+				sc->vreg[VREG_DIG].max_vdd, 0);
+		if (rc) {
+			pr_err("%s increase failed (%d)\n",
+				sc->vreg[VREG_DIG].name, rc);
+			return rc;
+		}
+		sc->vreg[VREG_DIG].cur_vdd = vdd_dig;
+	}
+
+	/*
+	 * Update per-CPU core voltage. Don't do this for the hotplug path for
+	 * which it should already be correct. Attempting to set it is bad
+	 * because we don't know what CPU we are running on at this point, but
+	 * the CPU regulator API requires we call it from the affected CPU.
+	 */
+	if (vdd_core > sc->vreg[VREG_CORE].cur_vdd
+						&& reason != SETRATE_HOTPLUG) {
+		rc = regulator_set_voltage(sc->vreg[VREG_CORE].reg, vdd_core,
+					   sc->vreg[VREG_CORE].max_vdd);
+		if (rc) {
+			pr_err("%s increase failed (%d)\n",
+				sc->vreg[VREG_CORE].name, rc);
+			return rc;
+		}
+		sc->vreg[VREG_CORE].cur_vdd = vdd_core;
+	}
+
+	return rc;
+}
+
+/* Apply any per-cpu voltage decreases. */
+static void decrease_vdd(int cpu, unsigned int vdd_core, unsigned int vdd_mem,
+			 unsigned int vdd_dig, enum setrate_reason reason)
+{
+	struct scalable *sc = &scalable[cpu];
+	int ret;
+
+	/*
+	 * Update per-CPU core voltage. This must be called on the CPU
+	 * that's being affected. Don't do this in the hotplug remove path,
+	 * where the rail is off and we're executing on the other CPU.
+	 */
+	if (vdd_core < sc->vreg[VREG_CORE].cur_vdd
+					&& reason != SETRATE_HOTPLUG) {
+		ret = regulator_set_voltage(sc->vreg[VREG_CORE].reg, vdd_core,
+					    sc->vreg[VREG_CORE].max_vdd);
+		if (ret) {
+			pr_err("%s decrease failed (%d)\n",
+			       sc->vreg[VREG_CORE].name, ret);
+			return;
+		}
+		sc->vreg[VREG_CORE].cur_vdd = vdd_core;
+	}
+
+	/* Decrease vdd_dig active-set vote. */
+	if (vdd_dig < sc->vreg[VREG_DIG].cur_vdd) {
+		ret = rpm_vreg_set_voltage(sc->vreg[VREG_DIG].rpm_vreg_id,
+				sc->vreg[VREG_DIG].rpm_vreg_voter, vdd_dig,
+				sc->vreg[VREG_DIG].max_vdd, 0);
+		if (ret) {
+			pr_err("%s decrease failed (%d)\n",
+				sc->vreg[VREG_DIG].name, ret);
+			return;
+		}
+		sc->vreg[VREG_DIG].cur_vdd = vdd_dig;
+	}
+
+	/*
+	 * Decrease vdd_mem active-set after vdd_dig.
+	 * vdd_mem should be >= vdd_dig.
+	 */
+	if (vdd_mem < sc->vreg[VREG_MEM].cur_vdd) {
+		ret = rpm_vreg_set_voltage(sc->vreg[VREG_MEM].rpm_vreg_id,
+				sc->vreg[VREG_MEM].rpm_vreg_voter, vdd_mem,
+				sc->vreg[VREG_MEM].max_vdd, 0);
+		if (ret) {
+			pr_err("%s decrease failed (%d)\n",
+				sc->vreg[VREG_MEM].name, ret);
+			return;
+		}
+		 sc->vreg[VREG_MEM].cur_vdd = vdd_mem;
+	}
+}
+
+static unsigned int calculate_vdd_mem(struct acpu_level *tgt)
+{
+	return tgt->l2_level->vdd_mem;
+}
+
+static unsigned int calculate_vdd_dig(struct acpu_level *tgt)
+{
+	unsigned int pll_vdd_dig;
+
+	if (tgt->l2_level->speed.src != HFPLL)
+		pll_vdd_dig = scalable[L2].hfpll_vdd_tbl[HFPLL_VDD_NONE];
+	else if (tgt->l2_level->speed.pll_l_val > HFPLL_LOW_VDD_PLL_L_MAX)
+		pll_vdd_dig = scalable[L2].hfpll_vdd_tbl[HFPLL_VDD_NOM];
+	else
+		pll_vdd_dig = scalable[L2].hfpll_vdd_tbl[HFPLL_VDD_LOW];
+
+	return max(tgt->l2_level->vdd_dig, pll_vdd_dig);
+}
+
+static unsigned int calculate_vdd_core(struct acpu_level *tgt)
+{
+	return tgt->vdd_core;
+}
+
+/* Set the CPU's clock rate and adjust the L2 rate, if appropriate. */
+static int acpuclk_8960_set_rate(int cpu, unsigned long rate,
+				 enum setrate_reason reason)
+{
+	struct core_speed *strt_acpu_s, *tgt_acpu_s;
+	struct l2_level *tgt_l2_l;
+	struct acpu_level *tgt;
+	unsigned int vdd_mem, vdd_dig, vdd_core;
+	unsigned long flags;
+	int rc = 0;
+
+	if (cpu > num_possible_cpus()) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	if (reason == SETRATE_CPUFREQ || reason == SETRATE_HOTPLUG)
+		mutex_lock(&driver_lock);
+
+	strt_acpu_s = scalable[cpu].current_speed;
+
+	/* Return early if rate didn't change. */
+	if (rate == strt_acpu_s->khz)
+		goto out;
+
+	/* Find target frequency. */
+	for (tgt = acpu_freq_tbl; tgt->speed.khz != 0; tgt++) {
+		if (tgt->speed.khz == rate) {
+			tgt_acpu_s = &tgt->speed;
+			break;
+		}
+	}
+	if (tgt->speed.khz == 0) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	/* Calculate voltage requirements for the current CPU. */
+	vdd_mem  = calculate_vdd_mem(tgt);
+	vdd_dig  = calculate_vdd_dig(tgt);
+	vdd_core = calculate_vdd_core(tgt);
+
+	/* Increase VDD levels if needed. */
+	if (reason == SETRATE_CPUFREQ || reason == SETRATE_HOTPLUG) {
+		rc = increase_vdd(cpu, vdd_core, vdd_mem, vdd_dig, reason);
+		if (rc)
+			goto out;
+	}
+
+	pr_debug("Switching from ACPU%d rate %u KHz -> %u KHz\n",
+		cpu, strt_acpu_s->khz, tgt_acpu_s->khz);
+
+	/* Set the CPU speed. */
+	set_speed(&scalable[cpu], tgt_acpu_s, reason);
+
+	/*
+	 * Update the L2 vote and apply the rate change. A spinlock is
+	 * necessary to ensure L2 rate is calulated and set atomically,
+	 * even if acpuclk_8960_set_rate() is called from an atomic context
+	 * and the driver_lock mutex is not acquired.
+	 */
+	spin_lock_irqsave(&l2_lock, flags);
+	tgt_l2_l = compute_l2_level(&scalable[cpu], tgt->l2_level);
+	set_speed(&scalable[L2], &tgt_l2_l->speed, reason);
+	spin_unlock_irqrestore(&l2_lock, flags);
+
+	/* Nothing else to do for power collapse or SWFI. */
+	if (reason == SETRATE_PC || reason == SETRATE_SWFI)
+		goto out;
+
+	/* Update bus bandwith request. */
+	set_bus_bw(tgt_l2_l->bw_level);
+
+	/* Drop VDD levels if we can. */
+	decrease_vdd(cpu, vdd_core, vdd_mem, vdd_dig, reason);
+
+	pr_debug("ACPU%d speed change complete\n", cpu);
+
+out:
+	if (reason == SETRATE_CPUFREQ || reason == SETRATE_HOTPLUG)
+		mutex_unlock(&driver_lock);
+	return rc;
+}
+
+/* Initialize a HFPLL at a given rate and enable it. */
+static void __init hfpll_init(struct scalable *sc, struct core_speed *tgt_s)
+{
+	pr_debug("Initializing HFPLL%d\n", sc - scalable);
+
+	/* Disable the PLL for re-programming. */
+	hfpll_disable(sc, 1);
+
+	/* Configure PLL parameters for integer mode. */
+	writel_relaxed(0x7845C665, sc->hfpll_base + HFPLL_CONFIG_CTL);
+	writel_relaxed(0, sc->hfpll_base + HFPLL_M_VAL);
+	writel_relaxed(1, sc->hfpll_base + HFPLL_N_VAL);
+
+	/* Program droop controller. */
+	writel_relaxed(0x0108C000, sc->hfpll_base + HFPLL_DROOP_CTL);
+
+	/* Set an initial rate and enable the PLL. */
+	hfpll_set_rate(sc, tgt_s);
+	hfpll_enable(sc, 0);
+}
+
+/* Voltage regulator initialization. */
+static void __init regulator_init(struct acpu_level *lvl)
+{
+	int cpu, ret;
+	struct scalable *sc;
+	unsigned int vdd_mem, vdd_dig, vdd_core;
+
+	vdd_mem = calculate_vdd_mem(lvl);
+	vdd_dig = calculate_vdd_dig(lvl);
+
+	for_each_possible_cpu(cpu) {
+		sc = &scalable[cpu];
+
+		/* Set initial vdd_mem vote. */
+		ret = rpm_vreg_set_voltage(sc->vreg[VREG_MEM].rpm_vreg_id,
+				sc->vreg[VREG_MEM].rpm_vreg_voter, vdd_mem,
+				sc->vreg[VREG_MEM].max_vdd, 0);
+		if (ret) {
+			pr_err("%s initialization failed (%d)\n",
+				sc->vreg[VREG_MEM].name, ret);
+			BUG();
+		}
+		sc->vreg[VREG_MEM].cur_vdd  = vdd_mem;
+
+		/* Set initial vdd_dig vote. */
+		ret = rpm_vreg_set_voltage(sc->vreg[VREG_DIG].rpm_vreg_id,
+				sc->vreg[VREG_DIG].rpm_vreg_voter, vdd_dig,
+				sc->vreg[VREG_DIG].max_vdd, 0);
+		if (ret) {
+			pr_err("%s initialization failed (%d)\n",
+				sc->vreg[VREG_DIG].name, ret);
+			BUG();
+		}
+		sc->vreg[VREG_DIG].cur_vdd  = vdd_dig;
+
+		/* Setup Krait CPU regulators and initial core voltage. */
+		sc->vreg[VREG_CORE].reg = regulator_get(NULL,
+					  sc->vreg[VREG_CORE].name);
+		if (IS_ERR(sc->vreg[VREG_CORE].reg)) {
+			pr_err("regulator_get(%s) failed (%ld)\n",
+			       sc->vreg[VREG_CORE].name,
+			       PTR_ERR(sc->vreg[VREG_CORE].reg));
+			BUG();
+		}
+		vdd_core = calculate_vdd_core(lvl);
+		ret = regulator_set_voltage(sc->vreg[VREG_CORE].reg, vdd_core,
+					    sc->vreg[VREG_CORE].max_vdd);
+		if (ret) {
+			pr_err("%s initialization failed (%d)\n",
+				sc->vreg[VREG_CORE].name, ret);
+			BUG();
+		}
+		sc->vreg[VREG_CORE].cur_vdd = vdd_core;
+		ret = regulator_enable(sc->vreg[VREG_CORE].reg);
+		if (ret) {
+			pr_err("regulator_enable(%s) failed (%d)\n",
+			       sc->vreg[VREG_CORE].name, ret);
+			BUG();
+		}
+	}
+}
+
+/* Set initial rate for a given core. */
+static void __init init_clock_sources(struct scalable *sc,
+				      struct core_speed *tgt_s)
+{
+	uint32_t regval;
+
+	/* Select PLL8 as AUX source input to the secondary MUX. */
+	writel_relaxed(0x3, sc->aux_clk_sel);
+
+	/* Switch away from the HFPLL while it's re-initialized. */
+	set_sec_clk_src(sc, SEC_SRC_SEL_AUX);
+	set_pri_clk_src(sc, PRI_SRC_SEL_SEC_SRC);
+	hfpll_init(sc, tgt_s);
+
+	/* Set PRI_SRC_SEL_HFPLL_DIV2 divider to div-2. */
+	regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
+	regval &= ~(0x3 << 6);
+	set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
+
+	/* Switch to the target clock source. */
+	set_sec_clk_src(sc, tgt_s->sec_src_sel);
+	set_pri_clk_src(sc, tgt_s->pri_src_sel);
+	sc->current_speed = tgt_s;
+}
+
+static void __init per_cpu_init(void *data)
+{
+	struct acpu_level *max_acpu_level = data;
+	int cpu = smp_processor_id();
+
+	init_clock_sources(&scalable[cpu], &max_acpu_level->speed);
+	scalable[cpu].l2_vote = max_acpu_level->l2_level;
+}
+
+/* Register with bus driver. */
+static void __init bus_init(unsigned int init_bw)
+{
+	int ret;
+
+	bus_perf_client = msm_bus_scale_register_client(&bus_client_pdata);
+	if (!bus_perf_client) {
+		pr_err("unable to register bus client\n");
+		BUG();
+	}
+
+	ret = msm_bus_scale_client_update_request(bus_perf_client, init_bw);
+	if (ret)
+		pr_err("initial bandwidth request failed (%d)\n", ret);
+}
+
+#ifdef CONFIG_CPU_FREQ_MSM
+static struct cpufreq_frequency_table freq_table[NR_CPUS][30];
+
+static void __init cpufreq_table_init(void)
+{
+	int cpu;
+
+	for_each_possible_cpu(cpu) {
+		int i, freq_cnt = 0;
+		/* Construct the freq_table tables from acpu_freq_tbl. */
+		for (i = 0; acpu_freq_tbl[i].speed.khz != 0
+				&& freq_cnt < ARRAY_SIZE(*freq_table); i++) {
+			if (acpu_freq_tbl[i].use_for_scaling) {
+				freq_table[cpu][freq_cnt].index = freq_cnt;
+				freq_table[cpu][freq_cnt].frequency
+					= acpu_freq_tbl[i].speed.khz;
+				freq_cnt++;
+			}
+		}
+		/* freq_table not big enough to store all usable freqs. */
+		BUG_ON(acpu_freq_tbl[i].speed.khz != 0);
+
+		freq_table[cpu][freq_cnt].index = freq_cnt;
+		freq_table[cpu][freq_cnt].frequency = CPUFREQ_TABLE_END;
+
+		pr_info("CPU%d: %d scaling frequencies supported.\n",
+			cpu, freq_cnt);
+
+		/* Register table with CPUFreq. */
+		cpufreq_frequency_table_get_attr(freq_table[cpu], cpu);
+	}
+}
+#else
+static void __init cpufreq_table_init(void) {}
+#endif
+
+#define HOT_UNPLUG_KHZ STBY_KHZ
+static int __cpuinit acpuclock_cpu_callback(struct notifier_block *nfb,
+					    unsigned long action, void *hcpu)
+{
+	static int prev_khz[NR_CPUS];
+	static int prev_pri_src[NR_CPUS];
+	static int prev_sec_src[NR_CPUS];
+	int cpu = (int)hcpu;
+
+	switch (action) {
+	case CPU_DYING:
+	case CPU_DYING_FROZEN:
+		/*
+		 * On Krait v1 and 8064v1, the primary and secondary muxes must
+		 * be set to QSB before L2 power collapse and restored after.
+		 */
+		if (cpu_is_krait_v1() || cpu_is_apq8064()) {
+			prev_sec_src[cpu] = get_sec_clk_src(&scalable[cpu]);
+			prev_pri_src[cpu] = get_pri_clk_src(&scalable[cpu]);
+			set_sec_clk_src(&scalable[cpu], SEC_SRC_SEL_QSB);
+			set_pri_clk_src(&scalable[cpu], PRI_SRC_SEL_SEC_SRC);
+		}
+		break;
+	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
+		prev_khz[cpu] = acpuclk_8960_get_rate(cpu);
+		/* Fall through. */
+	case CPU_UP_CANCELED:
+	case CPU_UP_CANCELED_FROZEN:
+		acpuclk_8960_set_rate(cpu, HOT_UNPLUG_KHZ, SETRATE_HOTPLUG);
+		break;
+	case CPU_UP_PREPARE:
+	case CPU_UP_PREPARE_FROZEN:
+		if (WARN_ON(!prev_khz[cpu]))
+			return NOTIFY_BAD;
+		acpuclk_8960_set_rate(cpu, prev_khz[cpu], SETRATE_HOTPLUG);
+		break;
+	case CPU_STARTING:
+	case CPU_STARTING_FROZEN:
+		if (cpu_is_krait_v1() || cpu_is_apq8064()) {
+			set_sec_clk_src(&scalable[cpu], prev_sec_src[cpu]);
+			set_pri_clk_src(&scalable[cpu], prev_pri_src[cpu]);
+		}
+		break;
+	default:
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata acpuclock_cpu_notifier = {
+	.notifier_call = acpuclock_cpu_callback,
+};
+
+static const int krait_needs_vmin(void)
+{
+	switch (read_cpuid_id()) {
+	case 0x511F04D0:
+	case 0x511F04D1:
+	case 0x510F06F0:
+		return 1;
+	default:
+		return 0;
+	};
+}
+
+static void kraitv2_apply_vmin(struct acpu_level *tbl)
+{
+	for (; tbl->speed.khz != 0; tbl++)
+		if (tbl->vdd_core < 1150000)
+			tbl->vdd_core = 1150000;
+}
+
+static struct acpu_level * __init select_freq_plan(void)
+{
+	struct acpu_level *l, *max_acpu_level = NULL;
+
+	/* Select frequency tables. */
+	if (cpu_is_msm8960()) {
+		uint32_t pte_efuse, pvs;
+		struct acpu_level *v1, *v2;
+
+		pte_efuse = readl_relaxed(QFPROM_PTE_EFUSE_ADDR);
+		pvs = (pte_efuse >> 10) & 0x7;
+		if (pvs == 0x7)
+			pvs = (pte_efuse >> 13) & 0x7;
+
+		switch (pvs) {
+		case 0x0:
+		case 0x7:
+			pr_info("ACPU PVS: Slow\n");
+			v1 = acpu_freq_tbl_8960_kraitv1_slow;
+			v2 = acpu_freq_tbl_8960_kraitv2_slow;
+			break;
+		case 0x1:
+			pr_info("ACPU PVS: Nominal\n");
+			v1 = acpu_freq_tbl_8960_kraitv1_nom_fast;
+			v2 = acpu_freq_tbl_8960_kraitv2_nom;
+			break;
+		case 0x3:
+			pr_info("ACPU PVS: Fast\n");
+			v1 = acpu_freq_tbl_8960_kraitv1_nom_fast;
+			v2 = acpu_freq_tbl_8960_kraitv2_fast;
+			break;
+		default:
+			pr_warn("ACPU PVS: Unknown. Defaulting to slow.\n");
+			v1 = acpu_freq_tbl_8960_kraitv1_slow;
+			v2 = acpu_freq_tbl_8960_kraitv2_slow;
+			break;
+		}
+
+		scalable = scalable_8960;
+		if (cpu_is_krait_v1()) {
+			acpu_freq_tbl = v1;
+			l2_freq_tbl = l2_freq_tbl_8960_kraitv1;
+			l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8960_kraitv1);
+		} else {
+			acpu_freq_tbl = v2;
+			l2_freq_tbl = l2_freq_tbl_8960_kraitv2;
+			l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8960_kraitv2);
+		}
+	} else if (cpu_is_apq8064()) {
+		scalable = scalable_8064;
+		acpu_freq_tbl = acpu_freq_tbl_8064;
+		l2_freq_tbl = l2_freq_tbl_8064;
+		l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8064);
+	} else if (cpu_is_msm8627()) {
+		scalable = scalable_8627;
+		acpu_freq_tbl = acpu_freq_tbl_8627;
+		l2_freq_tbl = l2_freq_tbl_8627;
+		l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8627);
+	} else if (cpu_is_msm8930()) {
+		scalable = scalable_8930;
+		acpu_freq_tbl = acpu_freq_tbl_8930;
+		l2_freq_tbl = l2_freq_tbl_8930;
+		l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8930);
+	} else {
+		BUG();
+	}
+	if (krait_needs_vmin())
+		kraitv2_apply_vmin(acpu_freq_tbl);
+
+	/* Find the max supported scaling frequency. */
+	for (l = acpu_freq_tbl; l->speed.khz != 0; l++)
+		if (l->use_for_scaling)
+			max_acpu_level = l;
+	BUG_ON(!max_acpu_level);
+	pr_info("Max ACPU freq: %u KHz\n", max_acpu_level->speed.khz);
+
+	return max_acpu_level;
+}
+
+static struct acpuclk_data acpuclk_8960_data = {
+	.set_rate = acpuclk_8960_set_rate,
+	.get_rate = acpuclk_8960_get_rate,
+	.power_collapse_khz = STBY_KHZ,
+	.wait_for_irq_khz = STBY_KHZ,
+};
+
+static int __init acpuclk_8960_init(struct acpuclk_soc_data *soc_data)
+{
+	struct acpu_level *max_acpu_level = select_freq_plan();
+
+	regulator_init(max_acpu_level);
+	bus_init(max_acpu_level->l2_level->bw_level);
+
+	init_clock_sources(&scalable[L2], &max_acpu_level->l2_level->speed);
+	on_each_cpu(per_cpu_init, max_acpu_level, true);
+
+	cpufreq_table_init();
+
+	acpuclk_register(&acpuclk_8960_data);
+	register_hotcpu_notifier(&acpuclock_cpu_notifier);
+
+	return 0;
+}
+
+struct acpuclk_soc_data acpuclk_8960_soc_data __initdata = {
+	.init = acpuclk_8960_init,
+};
+
+struct acpuclk_soc_data acpuclk_8930_soc_data __initdata = {
+	.init = acpuclk_8960_init,
+};
+
+struct acpuclk_soc_data acpuclk_8064_soc_data __initdata = {
+	.init = acpuclk_8960_init,
+};
diff --git a/arch/arm/mach-msm/acpuclock-8x50.c b/arch/arm/mach-msm/acpuclock-8x50.c
new file mode 100644
index 0000000..cde5a14
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock-8x50.c
@@ -0,0 +1,741 @@
+/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/errno.h>
+#include <linux/cpufreq.h>
+#include <linux/clk.h>
+#include <linux/mfd/tps65023.h>
+
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+
+#include "acpuclock.h"
+#include "avs.h"
+
+#define SHOT_SWITCH 4
+#define HOP_SWITCH 5
+#define SIMPLE_SLEW 6
+#define COMPLEX_SLEW 7
+
+#define SPSS_CLK_CNTL_ADDR (MSM_CSR_BASE + 0x100)
+#define SPSS_CLK_SEL_ADDR (MSM_CSR_BASE + 0x104)
+
+/* Scorpion PLL registers */
+#define SCPLL_CTL_ADDR         (MSM_SCPLL_BASE + 0x4)
+#define SCPLL_STATUS_ADDR      (MSM_SCPLL_BASE + 0x18)
+#define SCPLL_FSM_CTL_EXT_ADDR (MSM_SCPLL_BASE + 0x10)
+
+#ifdef CONFIG_QSD_SVS
+#define TPS65023_MAX_DCDC1	1600
+#else
+#define TPS65023_MAX_DCDC1	CONFIG_QSD_PMIC_DEFAULT_DCDC1
+#endif
+
+enum {
+	ACPU_PLL_TCXO	= -1,
+	ACPU_PLL_0	= 0,
+	ACPU_PLL_1,
+	ACPU_PLL_2,
+	ACPU_PLL_3,
+	ACPU_PLL_END,
+};
+
+struct clkctl_acpu_speed {
+	unsigned int     use_for_scaling;
+	unsigned int     acpuclk_khz;
+	int              pll;
+	unsigned int     acpuclk_src_sel;
+	unsigned int     acpuclk_src_div;
+	unsigned int     ahbclk_khz;
+	unsigned int     ahbclk_div;
+	unsigned int     axiclk_khz;
+	unsigned int     sc_core_src_sel_mask;
+	unsigned int     sc_l_value;
+	int              vdd;
+	unsigned long    lpj; /* loops_per_jiffy */
+};
+
+struct clkctl_acpu_speed acpu_freq_tbl_998[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 0, 0, 14000, 0, 0, 1000},
+	{ 0, 128000, ACPU_PLL_1, 1, 5, 0, 0, 14000, 2, 0, 1000},
+	{ 1, 245760, ACPU_PLL_0, 4, 0, 0, 0, 29000, 0, 0, 1000},
+	/* Update AXI_S and PLL0_S macros if above row numbers change. */
+	{ 1, 384000, ACPU_PLL_3, 0, 0, 0, 0, 58000, 1, 0xA, 1000},
+	{ 0, 422400, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xB, 1000},
+	{ 0, 460800, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xC, 1000},
+	{ 0, 499200, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xD, 1050},
+	{ 0, 537600, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xE, 1050},
+	{ 1, 576000, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xF, 1050},
+	{ 0, 614400, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0x10, 1075},
+	{ 0, 652800, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0x11, 1100},
+	{ 0, 691200, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0x12, 1125},
+	{ 0, 729600, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0x13, 1150},
+	{ 1, 768000, ACPU_PLL_3, 0, 0, 0, 0, 128000, 1, 0x14, 1150},
+	{ 0, 806400, ACPU_PLL_3, 0, 0, 0, 0, 128000, 1, 0x15, 1175},
+	{ 0, 844800, ACPU_PLL_3, 0, 0, 0, 0, 128000, 1, 0x16, 1225},
+	{ 0, 883200, ACPU_PLL_3, 0, 0, 0, 0, 128000, 1, 0x17, 1250},
+	{ 0, 921600, ACPU_PLL_3, 0, 0, 0, 0, 128000, 1, 0x18, 1300},
+	{ 0, 960000, ACPU_PLL_3, 0, 0, 0, 0, 128000, 1, 0x19, 1300},
+	{ 1, 998400, ACPU_PLL_3, 0, 0, 0, 0, 128000, 1, 0x1A, 1300},
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+};
+
+struct clkctl_acpu_speed acpu_freq_tbl_768[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 0, 0, 14000, 0, 0, 1000},
+	{ 0, 128000, ACPU_PLL_1, 1, 5, 0, 0, 14000, 2, 0, 1000},
+	{ 1, 245760, ACPU_PLL_0, 4, 0, 0, 0, 29000, 0, 0, 1000},
+	/* Update AXI_S and PLL0_S macros if above row numbers change. */
+	{ 1, 384000, ACPU_PLL_3, 0, 0, 0, 0, 58000, 1, 0xA, 1075},
+	{ 0, 422400, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xB, 1100},
+	{ 0, 460800, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xC, 1125},
+	{ 0, 499200, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xD, 1150},
+	{ 0, 537600, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xE, 1150},
+	{ 1, 576000, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xF, 1150},
+	{ 0, 614400, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0x10, 1175},
+	{ 0, 652800, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0x11, 1200},
+	{ 0, 691200, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0x12, 1225},
+	{ 0, 729600, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0x13, 1250},
+	{ 1, 768000, ACPU_PLL_3, 0, 0, 0, 0, 128000, 1, 0x14, 1250},
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+};
+
+static struct clkctl_acpu_speed *acpu_freq_tbl = acpu_freq_tbl_998;
+#define AXI_S	(&acpu_freq_tbl[1])
+#define PLL0_S	(&acpu_freq_tbl[2])
+
+/* Use 128MHz for PC since ACPU will auto-switch to AXI (128MHz) before
+ * coming back up. This allows detection of return-from-PC, since 128MHz
+ * is only used for power collapse. */
+#define POWER_COLLAPSE_KHZ	128000
+/* Use 245MHz (not 128MHz) for SWFI to avoid unnecessary steps between
+ * 128MHz<->245MHz. Jumping to high frequencies from 128MHz directly
+ * is not allowed. */
+#define WAIT_FOR_IRQ_KHZ	245760
+
+#ifdef CONFIG_CPU_FREQ_MSM
+static struct cpufreq_frequency_table freq_table[20];
+
+static void __init cpufreq_table_init(void)
+{
+	unsigned int i;
+	unsigned int freq_cnt = 0;
+
+	/* Construct the freq_table table from acpu_freq_tbl since the
+	 * freq_table values need to match frequencies specified in
+	 * acpu_freq_tbl and acpu_freq_tbl needs to be fixed up during init.
+	 */
+	for (i = 0; acpu_freq_tbl[i].acpuclk_khz != 0
+			&& freq_cnt < ARRAY_SIZE(freq_table)-1; i++) {
+		if (acpu_freq_tbl[i].use_for_scaling) {
+			freq_table[freq_cnt].index = freq_cnt;
+			freq_table[freq_cnt].frequency
+				= acpu_freq_tbl[i].acpuclk_khz;
+			freq_cnt++;
+		}
+	}
+
+	/* freq_table not big enough to store all usable freqs. */
+	BUG_ON(acpu_freq_tbl[i].acpuclk_khz != 0);
+
+	freq_table[freq_cnt].index = freq_cnt;
+	freq_table[freq_cnt].frequency = CPUFREQ_TABLE_END;
+
+	pr_info("%d scaling frequencies supported.\n", freq_cnt);
+}
+#endif
+
+struct clock_state {
+	struct clkctl_acpu_speed	*current_speed;
+	struct mutex			lock;
+	struct clk			*ebi1_clk;
+	int (*acpu_set_vdd) (int mvolts);
+};
+
+static struct clock_state drv_state = { 0 };
+
+static void scpll_set_freq(uint32_t lval, unsigned freq_switch)
+{
+	uint32_t regval;
+
+	if (lval > 33)
+		lval = 33;
+	if (lval < 10)
+		lval = 10;
+
+	/* wait for any calibrations or frequency switches to finish */
+	while (readl(SCPLL_STATUS_ADDR) & 0x3)
+		;
+
+	/* write the new L val and switch mode */
+	regval = readl(SCPLL_FSM_CTL_EXT_ADDR);
+	regval &= ~(0x3f << 3);
+	regval |= (lval << 3);
+	if (freq_switch == SIMPLE_SLEW)
+		regval |= (0x1 << 9);
+
+	regval &= ~(0x3 << 0);
+	regval |= (freq_switch << 0);
+	writel(regval, SCPLL_FSM_CTL_EXT_ADDR);
+
+	dmb();
+
+	/* put in normal mode */
+	regval = readl(SCPLL_CTL_ADDR);
+	regval |= 0x7;
+	writel(regval, SCPLL_CTL_ADDR);
+
+	dmb();
+
+	/* wait for frequency switch to finish */
+	while (readl(SCPLL_STATUS_ADDR) & 0x1)
+		;
+
+	/* status bit seems to clear early, using
+	 * 100us to handle the worst case. */
+	udelay(100);
+}
+
+static void scpll_apps_enable(bool state)
+{
+	uint32_t regval;
+
+	if (state)
+		pr_debug("Enabling PLL 3\n");
+	else
+		pr_debug("Disabling PLL 3\n");
+
+	/* Wait for any frequency switches to finish. */
+	while (readl(SCPLL_STATUS_ADDR) & 0x1)
+		;
+
+	/* put the pll in standby mode */
+	regval = readl(SCPLL_CTL_ADDR);
+	regval &= ~(0x7);
+	regval |= (0x2);
+	writel(regval, SCPLL_CTL_ADDR);
+
+	dmb();
+
+	if (state) {
+		/* put the pll in normal mode */
+		regval = readl(SCPLL_CTL_ADDR);
+		regval |= (0x7);
+		writel(regval, SCPLL_CTL_ADDR);
+		udelay(200);
+	} else {
+		/* put the pll in power down mode */
+		regval = readl(SCPLL_CTL_ADDR);
+		regval &= ~(0x7);
+		writel(regval, SCPLL_CTL_ADDR);
+	}
+	udelay(62);
+
+	if (state)
+		pr_debug("PLL 3 Enabled\n");
+	else
+		pr_debug("PLL 3 Disabled\n");
+}
+
+static void scpll_init(void)
+{
+	uint32_t regval;
+#define L_VAL_384MHZ	0xA
+#define L_VAL_768MHZ	0x14
+
+	pr_debug("Initializing PLL 3\n");
+
+	/* power down scpll */
+	writel(0x0, SCPLL_CTL_ADDR);
+
+	dmb();
+
+	/* set bypassnl, put into standby */
+	writel(0x00400002, SCPLL_CTL_ADDR);
+
+	/* set bypassnl, reset_n, full calibration */
+	writel(0x00600004, SCPLL_CTL_ADDR);
+
+	/* Ensure register write to initiate calibration has taken
+	effect before reading status flag */
+	dmb();
+
+	/* wait for cal_all_done */
+	while (readl(SCPLL_STATUS_ADDR) & 0x2)
+		;
+
+	/* Start: Set of experimentally derived steps
+	 * to work around a h/w bug. */
+
+	/* Put the pll in normal mode */
+	scpll_apps_enable(1);
+
+	/* SHOT switch to 384 MHz */
+	regval = readl(SCPLL_FSM_CTL_EXT_ADDR);
+	regval &= ~(0x3f << 3);
+	regval |= (L_VAL_384MHZ << 3);
+
+	regval &= ~0x7;
+	regval |= SHOT_SWITCH;
+	writel(regval, SCPLL_FSM_CTL_EXT_ADDR);
+
+	/* Trigger the freq switch by putting pll in normal mode. */
+	regval = readl(SCPLL_CTL_ADDR);
+	regval |= (0x7);
+	writel(regval, SCPLL_CTL_ADDR);
+
+	/* Wait for frequency switch to finish */
+	while (readl(SCPLL_STATUS_ADDR) & 0x1)
+		;
+
+	/* Status bit seems to clear early, using
+	 * 800 microseconds for the worst case. */
+	udelay(800);
+
+	/* HOP switch to 768 MHz. */
+	regval = readl(SCPLL_FSM_CTL_EXT_ADDR);
+	regval &= ~(0x3f << 3);
+	regval |= (L_VAL_768MHZ << 3);
+
+	regval &= ~0x7;
+	regval |= HOP_SWITCH;
+	writel(regval, SCPLL_FSM_CTL_EXT_ADDR);
+
+	/* Trigger the freq switch by putting pll in normal mode. */
+	regval = readl(SCPLL_CTL_ADDR);
+	regval |= (0x7);
+	writel(regval, SCPLL_CTL_ADDR);
+
+	/* Wait for frequency switch to finish */
+	while (readl(SCPLL_STATUS_ADDR) & 0x1)
+		;
+
+	/* Status bit seems to clear early, using
+	 * 100 microseconds for the worst case. */
+	udelay(100);
+
+	/* End: Work around for h/w bug */
+
+	/* Power down scpll */
+	scpll_apps_enable(0);
+}
+
+static void config_pll(struct clkctl_acpu_speed *s)
+{
+	uint32_t regval;
+
+	if (s->pll == ACPU_PLL_3)
+		scpll_set_freq(s->sc_l_value, HOP_SWITCH);
+	/* Configure the PLL divider mux if we plan to use it. */
+	else if (s->sc_core_src_sel_mask == 0) {
+		/* get the current clock source selection */
+		regval = readl(SPSS_CLK_SEL_ADDR) & 0x1;
+
+		/* configure the other clock source, then switch to it,
+		 * using the glitch free mux */
+		switch (regval) {
+		case 0x0:
+			regval = readl(SPSS_CLK_CNTL_ADDR);
+			regval &= ~(0x7 << 4 | 0xf);
+			regval |= (s->acpuclk_src_sel << 4);
+			regval |= (s->acpuclk_src_div << 0);
+			writel(regval, SPSS_CLK_CNTL_ADDR);
+
+			regval = readl(SPSS_CLK_SEL_ADDR);
+			regval |= 0x1;
+			writel(regval, SPSS_CLK_SEL_ADDR);
+			break;
+
+		case 0x1:
+			regval = readl(SPSS_CLK_CNTL_ADDR);
+			regval &= ~(0x7 << 12 | 0xf << 8);
+			regval |= (s->acpuclk_src_sel << 12);
+			regval |= (s->acpuclk_src_div << 8);
+			writel(regval, SPSS_CLK_CNTL_ADDR);
+
+			regval = readl(SPSS_CLK_SEL_ADDR);
+			regval &= ~0x1;
+			writel(regval, SPSS_CLK_SEL_ADDR);
+			break;
+		}
+		dmb();
+	}
+
+	regval = readl(SPSS_CLK_SEL_ADDR);
+	regval &= ~(0x3 << 1);
+	regval |= (s->sc_core_src_sel_mask << 1);
+	writel(regval, SPSS_CLK_SEL_ADDR);
+}
+
+static int acpuclk_set_vdd_level(int vdd)
+{
+	if (drv_state.acpu_set_vdd) {
+		pr_debug("Switching VDD to %d mV\n", vdd);
+		return drv_state.acpu_set_vdd(vdd);
+	} else {
+		/* Assume that the PMIC supports scaling the processor
+		 * to its maximum frequency at its default voltage.
+		 */
+		return 0;
+	}
+}
+
+static int acpuclk_8x50_set_rate(int cpu, unsigned long rate,
+				 enum setrate_reason reason)
+{
+	struct clkctl_acpu_speed *tgt_s, *strt_s;
+	int res, rc = 0;
+	int freq_index = 0;
+
+	if (reason == SETRATE_CPUFREQ)
+		mutex_lock(&drv_state.lock);
+
+	strt_s = drv_state.current_speed;
+
+	if (rate == strt_s->acpuclk_khz)
+		goto out;
+
+	for (tgt_s = acpu_freq_tbl; tgt_s->acpuclk_khz != 0; tgt_s++) {
+		if (tgt_s->acpuclk_khz == rate)
+			break;
+		freq_index++;
+	}
+
+	if (tgt_s->acpuclk_khz == 0) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	if (reason == SETRATE_CPUFREQ) {
+#ifdef CONFIG_MSM_CPU_AVS
+		/* Notify avs before changing frequency */
+		rc = avs_adjust_freq(freq_index, 1);
+		if (rc) {
+			pr_err("Unable to increase ACPU vdd (%d)\n", rc);
+			goto out;
+		}
+#endif
+		/* Increase VDD if needed. */
+		if (tgt_s->vdd > strt_s->vdd) {
+			rc = acpuclk_set_vdd_level(tgt_s->vdd);
+			if (rc) {
+				pr_err("Unable to increase ACPU vdd (%d)\n",
+					rc);
+				goto out;
+			}
+		}
+	} else if (reason == SETRATE_PC
+		&& rate != POWER_COLLAPSE_KHZ) {
+		/* Returning from PC. ACPU is running on AXI source.
+		 * Step up to PLL0 before ramping up higher. */
+		config_pll(PLL0_S);
+	}
+
+	pr_debug("Switching from ACPU rate %u KHz -> %u KHz\n",
+		strt_s->acpuclk_khz, tgt_s->acpuclk_khz);
+
+	if (strt_s->pll != ACPU_PLL_3 && tgt_s->pll != ACPU_PLL_3) {
+		config_pll(tgt_s);
+	} else if (strt_s->pll != ACPU_PLL_3 && tgt_s->pll == ACPU_PLL_3) {
+		scpll_apps_enable(1);
+		config_pll(tgt_s);
+	} else if (strt_s->pll == ACPU_PLL_3 && tgt_s->pll != ACPU_PLL_3) {
+		config_pll(tgt_s);
+		scpll_apps_enable(0);
+	} else {
+		/* Temporarily switch to PLL0 while reconfiguring PLL3. */
+		config_pll(PLL0_S);
+		config_pll(tgt_s);
+	}
+
+	/* Update the driver state with the new clock freq */
+	drv_state.current_speed = tgt_s;
+
+	/* Re-adjust lpj for the new clock speed. */
+	loops_per_jiffy = tgt_s->lpj;
+
+	/* Nothing else to do for SWFI. */
+	if (reason == SETRATE_SWFI)
+		goto out;
+
+	if (strt_s->axiclk_khz != tgt_s->axiclk_khz) {
+		res = clk_set_rate(drv_state.ebi1_clk,
+				tgt_s->axiclk_khz * 1000);
+		if (res < 0)
+			pr_warning("Setting AXI min rate failed (%d)\n", res);
+	}
+
+	/* Nothing else to do for power collapse */
+	if (reason == SETRATE_PC)
+		goto out;
+
+#ifdef CONFIG_MSM_CPU_AVS
+	/* notify avs after changing frequency */
+	res = avs_adjust_freq(freq_index, 0);
+	if (res)
+		pr_warning("Unable to drop ACPU vdd (%d)\n", res);
+#endif
+
+	/* Drop VDD level if we can. */
+	if (tgt_s->vdd < strt_s->vdd) {
+		res = acpuclk_set_vdd_level(tgt_s->vdd);
+		if (res)
+			pr_warning("Unable to drop ACPU vdd (%d)\n", res);
+	}
+
+	pr_debug("ACPU speed change complete\n");
+out:
+	if (reason == SETRATE_CPUFREQ)
+		mutex_unlock(&drv_state.lock);
+	return rc;
+}
+
+static void __init acpuclk_hw_init(void)
+{
+	struct clkctl_acpu_speed *speed;
+	uint32_t div, sel, regval;
+	int res;
+
+	/* Determine the source of the Scorpion clock. */
+	regval = readl(SPSS_CLK_SEL_ADDR);
+	switch ((regval & 0x6) >> 1) {
+	case 0: /* raw source clock */
+	case 3: /* low jitter PLL1 (768Mhz) */
+		if (regval & 0x1) {
+			sel = ((readl(SPSS_CLK_CNTL_ADDR) >> 4) & 0x7);
+			div = ((readl(SPSS_CLK_CNTL_ADDR) >> 0) & 0xf);
+		} else {
+			sel = ((readl(SPSS_CLK_CNTL_ADDR) >> 12) & 0x7);
+			div = ((readl(SPSS_CLK_CNTL_ADDR) >> 8) & 0xf);
+		}
+
+		/* Find the matching clock rate. */
+		for (speed = acpu_freq_tbl; speed->acpuclk_khz != 0; speed++) {
+			if (speed->acpuclk_src_sel == sel &&
+			    speed->acpuclk_src_div == div)
+				break;
+		}
+		break;
+
+	case 1: /* unbuffered scorpion pll (384Mhz to 998.4Mhz) */
+		sel = ((readl(SCPLL_FSM_CTL_EXT_ADDR) >> 3) & 0x3f);
+
+		/* Find the matching clock rate. */
+		for (speed = acpu_freq_tbl; speed->acpuclk_khz != 0; speed++) {
+			if (speed->sc_l_value == sel &&
+			    speed->sc_core_src_sel_mask == 1)
+				break;
+		}
+		break;
+
+	case 2: /* AXI bus clock (128Mhz) */
+		speed = AXI_S;
+		break;
+	default:
+		BUG();
+	}
+
+	/* Initialize scpll only if it wasn't already initialized by the boot
+	 * loader. If the CPU is already running on scpll, then the scpll was
+	 * initialized by the boot loader. */
+	if (speed->pll != ACPU_PLL_3)
+		scpll_init();
+
+	if (speed->acpuclk_khz == 0) {
+		pr_err("Error - ACPU clock reports invalid speed\n");
+		return;
+	}
+
+	drv_state.current_speed = speed;
+	res = clk_set_rate(drv_state.ebi1_clk, speed->axiclk_khz * 1000);
+	if (res < 0)
+		pr_warning("Setting AXI min rate failed (%d)\n", res);
+	res = clk_enable(drv_state.ebi1_clk);
+	if (res < 0)
+		pr_warning("Enabling AXI clock failed (%d)\n", res);
+
+	pr_info("ACPU running at %d KHz\n", speed->acpuclk_khz);
+}
+
+static unsigned long acpuclk_8x50_get_rate(int cpu)
+{
+	return drv_state.current_speed->acpuclk_khz;
+}
+
+/* Spare register populated with efuse data on max ACPU freq. */
+#define CT_CSR_PHYS		0xA8700000
+#define TCSR_SPARE2_ADDR	(ct_csr_base + 0x60)
+
+#define PLL0_M_VAL_ADDR		(MSM_CLK_CTL_BASE + 0x308)
+
+static void __init acpu_freq_tbl_fixup(void)
+{
+	void __iomem *ct_csr_base;
+	uint32_t tcsr_spare2, pll0_m_val;
+	unsigned int max_acpu_khz;
+	unsigned int i;
+
+	ct_csr_base = ioremap(CT_CSR_PHYS, PAGE_SIZE);
+	BUG_ON(ct_csr_base == NULL);
+
+	tcsr_spare2 = readl(TCSR_SPARE2_ADDR);
+
+	/* Check if the register is supported and meaningful. */
+	if ((tcsr_spare2 & 0xF000) != 0xA000) {
+		pr_info("Efuse data on Max ACPU freq not present.\n");
+		goto skip_efuse_fixup;
+	}
+
+	switch (tcsr_spare2 & 0xF0) {
+	case 0x70:
+		acpu_freq_tbl = acpu_freq_tbl_768;
+		max_acpu_khz = 768000;
+		break;
+	case 0x30:
+	case 0x00:
+		max_acpu_khz = 998400;
+		break;
+	case 0x10:
+		max_acpu_khz = 1267200;
+		break;
+	default:
+		pr_warning("Invalid efuse data (%x) on Max ACPU freq!\n",
+				tcsr_spare2);
+		goto skip_efuse_fixup;
+	}
+
+	pr_info("Max ACPU freq from efuse data is %d KHz\n", max_acpu_khz);
+
+	for (i = 0; acpu_freq_tbl[i].acpuclk_khz != 0; i++) {
+		if (acpu_freq_tbl[i].acpuclk_khz > max_acpu_khz) {
+			acpu_freq_tbl[i].acpuclk_khz = 0;
+			break;
+		}
+	}
+
+skip_efuse_fixup:
+	iounmap(ct_csr_base);
+
+	/* pll0_m_val will be 36 when PLL0 is run at 235MHz
+	 * instead of the usual 245MHz. */
+	pll0_m_val = readl(PLL0_M_VAL_ADDR) & 0x7FFFF;
+	if (pll0_m_val == 36)
+		PLL0_S->acpuclk_khz = 235930;
+
+	for (i = 0; acpu_freq_tbl[i].acpuclk_khz != 0; i++) {
+		if (acpu_freq_tbl[i].vdd > TPS65023_MAX_DCDC1) {
+			acpu_freq_tbl[i].acpuclk_khz = 0;
+			break;
+		}
+	}
+}
+
+/* Initalize the lpj field in the acpu_freq_tbl. */
+static void __init lpj_init(void)
+{
+	int i;
+	const struct clkctl_acpu_speed *base_clk = drv_state.current_speed;
+	for (i = 0; acpu_freq_tbl[i].acpuclk_khz; i++) {
+		acpu_freq_tbl[i].lpj = cpufreq_scale(loops_per_jiffy,
+						base_clk->acpuclk_khz,
+						acpu_freq_tbl[i].acpuclk_khz);
+	}
+}
+
+#ifdef CONFIG_MSM_CPU_AVS
+static int __init acpu_avs_init(int (*set_vdd) (int), int khz)
+{
+	int i;
+	int freq_count = 0;
+	int freq_index = -1;
+
+	for (i = 0; acpu_freq_tbl[i].acpuclk_khz; i++) {
+		freq_count++;
+		if (acpu_freq_tbl[i].acpuclk_khz == khz)
+			freq_index = i;
+	}
+
+	return avs_init(set_vdd, freq_count, freq_index);
+}
+#endif
+
+static int qsd8x50_tps65023_set_dcdc1(int mVolts)
+{
+	int rc = 0;
+#ifdef CONFIG_QSD_SVS
+	rc = tps65023_set_dcdc1_level(mVolts);
+	/*
+	 * By default the TPS65023 will be initialized to 1.225V.
+	 * So we can safely switch to any frequency within this
+	 * voltage even if the device is not probed/ready.
+	 */
+	if (rc == -ENODEV && mVolts <= CONFIG_QSD_PMIC_DEFAULT_DCDC1)
+		rc = 0;
+#else
+	/*
+	 * Disallow frequencies not supported in the default PMIC
+	 * output voltage.
+	 */
+	if (mVolts > CONFIG_QSD_PMIC_DEFAULT_DCDC1)
+		rc = -EFAULT;
+#endif
+	return rc;
+}
+
+static struct acpuclk_data acpuclk_8x50_data = {
+	.set_rate = acpuclk_8x50_set_rate,
+	.get_rate = acpuclk_8x50_get_rate,
+	.power_collapse_khz = POWER_COLLAPSE_KHZ,
+	.wait_for_irq_khz = WAIT_FOR_IRQ_KHZ,
+	.switch_time_us = 20,
+};
+
+static int __init acpuclk_8x50_init(struct acpuclk_soc_data *soc_data)
+{
+	mutex_init(&drv_state.lock);
+	drv_state.acpu_set_vdd = qsd8x50_tps65023_set_dcdc1;
+
+	drv_state.ebi1_clk = clk_get(NULL, "ebi1_acpu_clk");
+	BUG_ON(IS_ERR(drv_state.ebi1_clk));
+
+	acpu_freq_tbl_fixup();
+	acpuclk_hw_init();
+	lpj_init();
+	/* Set a lower bound for ACPU rate for boot. This limits the
+	 * maximum frequency hop caused by the first CPUFREQ switch. */
+	if (drv_state.current_speed->acpuclk_khz < PLL0_S->acpuclk_khz)
+		acpuclk_set_rate(0, PLL0_S->acpuclk_khz, SETRATE_CPUFREQ);
+
+	acpuclk_register(&acpuclk_8x50_data);
+
+#ifdef CONFIG_CPU_FREQ_MSM
+	cpufreq_table_init();
+	cpufreq_frequency_table_get_attr(freq_table, smp_processor_id());
+#endif
+#ifdef CONFIG_MSM_CPU_AVS
+	if (!acpu_avs_init(drv_state.acpu_set_vdd,
+		drv_state.current_speed->acpuclk_khz)) {
+		/* avs init successful. avs will handle voltage changes */
+		drv_state.acpu_set_vdd = NULL;
+	}
+#endif
+	return 0;
+}
+
+struct acpuclk_soc_data acpuclk_8x50_soc_data __initdata = {
+	.init = acpuclk_8x50_init,
+};
diff --git a/arch/arm/mach-msm/acpuclock-8x60.c b/arch/arm/mach-msm/acpuclock-8x60.c
new file mode 100644
index 0000000..48efa18
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock-8x60.c
@@ -0,0 +1,1096 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/cpufreq.h>
+#include <linux/cpu.h>
+#include <linux/regulator/consumer.h>
+
+#include <asm/cpu.h>
+
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#include <mach/socinfo.h>
+#include <mach/rpm-regulator.h>
+
+#include "acpuclock.h"
+#include "avs.h"
+
+/* Frequency switch modes. */
+#define SHOT_SWITCH		4
+#define HOP_SWITCH		5
+#define SIMPLE_SLEW		6
+#define COMPLEX_SLEW		7
+
+/* PLL calibration limits.
+ * The PLL hardware has a minimum frequency of 384MHz.
+ * Calibration should respect this limit. */
+#define L_VAL_SCPLL_CAL_MIN	0x08 /* =  432 MHz with 27MHz source */
+
+#define MAX_VDD_SC		1325000 /* uV */
+#define MAX_VDD_MEM		1325000 /* uV */
+#define MAX_VDD_DIG		1200000 /* uV */
+#define MAX_AXI			 310500 /* KHz */
+#define SCPLL_LOW_VDD_FMAX	 594000 /* KHz */
+#define SCPLL_LOW_VDD		1000000 /* uV */
+#define SCPLL_NOMINAL_VDD	1100000 /* uV */
+
+/* SCPLL Modes. */
+#define SCPLL_POWER_DOWN	0
+#define SCPLL_BYPASS		1
+#define SCPLL_STANDBY		2
+#define SCPLL_FULL_CAL		4
+#define SCPLL_HALF_CAL		5
+#define SCPLL_STEP_CAL		6
+#define SCPLL_NORMAL		7
+
+#define SCPLL_DEBUG_NONE	0
+#define SCPLL_DEBUG_FULL	3
+
+/* SCPLL registers offsets. */
+#define SCPLL_DEBUG_OFFSET		0x0
+#define SCPLL_CTL_OFFSET		0x4
+#define SCPLL_CAL_OFFSET		0x8
+#define SCPLL_STATUS_OFFSET		0x10
+#define SCPLL_CFG_OFFSET		0x1C
+#define SCPLL_FSM_CTL_EXT_OFFSET	0x24
+#define SCPLL_LUT_OFFSET(l_val)		(0x38 + (((l_val) / 4) * 4))
+
+/* Clock registers. */
+#define SPSS0_CLK_CTL_ADDR		(MSM_ACC0_BASE + 0x04)
+#define SPSS0_CLK_SEL_ADDR		(MSM_ACC0_BASE + 0x08)
+#define SPSS1_CLK_CTL_ADDR		(MSM_ACC1_BASE + 0x04)
+#define SPSS1_CLK_SEL_ADDR		(MSM_ACC1_BASE + 0x08)
+#define SPSS_L2_CLK_SEL_ADDR		(MSM_GCC_BASE  + 0x38)
+
+/* PTE EFUSE register. */
+#define QFPROM_PTE_EFUSE_ADDR		(MSM_QFPROM_BASE + 0x00C0)
+
+static const void * const clk_ctl_addr[] = {SPSS0_CLK_CTL_ADDR,
+			SPSS1_CLK_CTL_ADDR};
+static const void * const clk_sel_addr[] = {SPSS0_CLK_SEL_ADDR,
+			SPSS1_CLK_SEL_ADDR, SPSS_L2_CLK_SEL_ADDR};
+
+static const int rpm_vreg_voter[] = { RPM_VREG_VOTER1, RPM_VREG_VOTER2 };
+static struct regulator *regulator_sc[NR_CPUS];
+
+enum scplls {
+	CPU0 = 0,
+	CPU1,
+	L2,
+};
+
+static const void * const sc_pll_base[] = {
+	[CPU0]	= MSM_SCPLL_BASE + 0x200,
+	[CPU1]	= MSM_SCPLL_BASE + 0x300,
+	[L2]	= MSM_SCPLL_BASE + 0x400,
+};
+
+enum sc_src {
+	ACPU_AFAB,
+	ACPU_PLL_8,
+	ACPU_SCPLL,
+};
+
+static struct clock_state {
+	struct clkctl_acpu_speed	*current_speed[NR_CPUS];
+	struct clkctl_l2_speed		*current_l2_speed;
+	spinlock_t			l2_lock;
+	struct mutex			lock;
+} drv_state;
+
+struct clkctl_l2_speed {
+	unsigned int     khz;
+	unsigned int     src_sel;
+	unsigned int     l_val;
+	unsigned int     vdd_dig;
+	unsigned int     vdd_mem;
+	unsigned int     bw_level;
+};
+
+static struct clkctl_l2_speed *l2_vote[NR_CPUS];
+
+struct clkctl_acpu_speed {
+	unsigned int     use_for_scaling[2]; /* One for each CPU. */
+	unsigned int     acpuclk_khz;
+	int              pll;
+	unsigned int     acpuclk_src_sel;
+	unsigned int     acpuclk_src_div;
+	unsigned int     core_src_sel;
+	unsigned int     l_val;
+	struct clkctl_l2_speed *l2_level;
+	unsigned int     vdd_sc;
+	unsigned int     avsdscr_setting;
+};
+
+/* Instantaneous bandwidth requests in MB/s. */
+#define BW_MBPS(_bw) \
+	{ \
+		.vectors = &(struct msm_bus_vectors){ \
+			.src = MSM_BUS_MASTER_AMPSS_M0, \
+			.dst = MSM_BUS_SLAVE_EBI_CH0, \
+			.ib = (_bw) * 1000000UL, \
+			.ab = 0, \
+		}, \
+		.num_paths = 1, \
+	}
+static struct msm_bus_paths bw_level_tbl[] = {
+	[0] =  BW_MBPS(824), /* At least 103 MHz on bus. */
+	[1] = BW_MBPS(1336), /* At least 167 MHz on bus. */
+	[2] = BW_MBPS(2008), /* At least 251 MHz on bus. */
+	[3] = BW_MBPS(2480), /* At least 310 MHz on bus. */
+};
+
+static struct msm_bus_scale_pdata bus_client_pdata = {
+	.usecase = bw_level_tbl,
+	.num_usecases = ARRAY_SIZE(bw_level_tbl),
+	.active_only = 1,
+	.name = "acpuclock",
+};
+
+static uint32_t bus_perf_client;
+
+/* L2 frequencies = 2 * 27 MHz * L_VAL */
+static struct clkctl_l2_speed l2_freq_tbl_v2[] = {
+	[0]  = { MAX_AXI, 0, 0,    1000000, 1100000, 0},
+	[1]  = { 432000,  1, 0x08, 1000000, 1100000, 0},
+	[2]  = { 486000,  1, 0x09, 1000000, 1100000, 0},
+	[3]  = { 540000,  1, 0x0A, 1000000, 1100000, 0},
+	[4]  = { 594000,  1, 0x0B, 1000000, 1100000, 0},
+	[5]  = { 648000,  1, 0x0C, 1000000, 1100000, 1},
+	[6]  = { 702000,  1, 0x0D, 1100000, 1100000, 1},
+	[7]  = { 756000,  1, 0x0E, 1100000, 1100000, 1},
+	[8]  = { 810000,  1, 0x0F, 1100000, 1100000, 1},
+	[9]  = { 864000,  1, 0x10, 1100000, 1100000, 1},
+	[10] = { 918000,  1, 0x11, 1100000, 1100000, 2},
+	[11] = { 972000,  1, 0x12, 1100000, 1100000, 2},
+	[12] = {1026000,  1, 0x13, 1100000, 1100000, 2},
+	[13] = {1080000,  1, 0x14, 1100000, 1200000, 2},
+	[14] = {1134000,  1, 0x15, 1100000, 1200000, 2},
+	[15] = {1188000,  1, 0x16, 1200000, 1200000, 3},
+	[16] = {1242000,  1, 0x17, 1200000, 1212500, 3},
+	[17] = {1296000,  1, 0x18, 1200000, 1225000, 3},
+	[18] = {1350000,  1, 0x19, 1200000, 1225000, 3},
+	[19] = {1404000,  1, 0x1A, 1200000, 1250000, 3},
+};
+
+#define L2(x) (&l2_freq_tbl_v2[(x)])
+/* SCPLL frequencies = 2 * 27 MHz * L_VAL */
+static struct clkctl_acpu_speed acpu_freq_tbl_1188mhz[] = {
+  { {1, 1},  192000,  ACPU_PLL_8, 3, 1, 0, 0,    L2(1),   812500, 0x03006000},
+  /* MAX_AXI row is used to source CPU cores and L2 from the AFAB clock. */
+  { {0, 0},  MAX_AXI, ACPU_AFAB,  1, 0, 0, 0,    L2(0),   875000, 0x03006000},
+  { {1, 1},  384000,  ACPU_PLL_8, 3, 0, 0, 0,    L2(1),   875000, 0x03006000},
+  { {1, 1},  432000,  ACPU_SCPLL, 0, 0, 1, 0x08, L2(1),   887500, 0x03006000},
+  { {1, 1},  486000,  ACPU_SCPLL, 0, 0, 1, 0x09, L2(2),   912500, 0x03006000},
+  { {1, 1},  540000,  ACPU_SCPLL, 0, 0, 1, 0x0A, L2(3),   925000, 0x03006000},
+  { {1, 1},  594000,  ACPU_SCPLL, 0, 0, 1, 0x0B, L2(4),   937500, 0x03006000},
+  { {1, 1},  648000,  ACPU_SCPLL, 0, 0, 1, 0x0C, L2(5),   950000, 0x03006000},
+  { {1, 1},  702000,  ACPU_SCPLL, 0, 0, 1, 0x0D, L2(6),   975000, 0x03006000},
+  { {1, 1},  756000,  ACPU_SCPLL, 0, 0, 1, 0x0E, L2(7),  1000000, 0x03006000},
+  { {1, 1},  810000,  ACPU_SCPLL, 0, 0, 1, 0x0F, L2(8),  1012500, 0x03006000},
+  { {1, 1},  864000,  ACPU_SCPLL, 0, 0, 1, 0x10, L2(9),  1037500, 0x03006000},
+  { {1, 1},  918000,  ACPU_SCPLL, 0, 0, 1, 0x11, L2(10), 1062500, 0x03006000},
+  { {1, 1},  972000,  ACPU_SCPLL, 0, 0, 1, 0x12, L2(11), 1087500, 0x03006000},
+  { {1, 1}, 1026000,  ACPU_SCPLL, 0, 0, 1, 0x13, L2(12), 1125000, 0x03006000},
+  { {1, 1}, 1080000,  ACPU_SCPLL, 0, 0, 1, 0x14, L2(13), 1137500, 0x03006000},
+  { {1, 1}, 1134000,  ACPU_SCPLL, 0, 0, 1, 0x15, L2(14), 1162500, 0x03006000},
+  { {1, 1}, 1188000,  ACPU_SCPLL, 0, 0, 1, 0x16, L2(15), 1187500, 0x03006000},
+  { {0, 0}, 0 },
+};
+
+/* SCPLL frequencies = 2 * 27 MHz * L_VAL */
+static struct clkctl_acpu_speed acpu_freq_tbl_1512mhz_slow[] = {
+  { {1, 1},  192000,  ACPU_PLL_8, 3, 1, 0, 0,    L2(1),   800000, 0x03006000},
+  /* MAX_AXI row is used to source CPU cores and L2 from the AFAB clock. */
+  { {0, 0},  MAX_AXI, ACPU_AFAB,  1, 0, 0, 0,    L2(0),   825000, 0x03006000},
+  { {1, 1},  384000,  ACPU_PLL_8, 3, 0, 0, 0,    L2(1),   825000, 0x03006000},
+  { {1, 1},  432000,  ACPU_SCPLL, 0, 0, 1, 0x08, L2(1),   850000, 0x03006000},
+  { {1, 1},  486000,  ACPU_SCPLL, 0, 0, 1, 0x09, L2(2),   850000, 0x03006000},
+  { {1, 1},  540000,  ACPU_SCPLL, 0, 0, 1, 0x0A, L2(3),   875000, 0x03006000},
+  { {1, 1},  594000,  ACPU_SCPLL, 0, 0, 1, 0x0B, L2(4),   875000, 0x03006000},
+  { {1, 1},  648000,  ACPU_SCPLL, 0, 0, 1, 0x0C, L2(5),   900000, 0x03006000},
+  { {1, 1},  702000,  ACPU_SCPLL, 0, 0, 1, 0x0D, L2(6),   900000, 0x03006000},
+  { {1, 1},  756000,  ACPU_SCPLL, 0, 0, 1, 0x0E, L2(7),   925000, 0x03006000},
+  { {1, 1},  810000,  ACPU_SCPLL, 0, 0, 1, 0x0F, L2(8),   975000, 0x03006000},
+  { {1, 1},  864000,  ACPU_SCPLL, 0, 0, 1, 0x10, L2(9),   975000, 0x03006000},
+  { {1, 1},  918000,  ACPU_SCPLL, 0, 0, 1, 0x11, L2(10), 1000000, 0x03006000},
+  { {1, 1},  972000,  ACPU_SCPLL, 0, 0, 1, 0x12, L2(11), 1025000, 0x03006000},
+  { {1, 1}, 1026000,  ACPU_SCPLL, 0, 0, 1, 0x13, L2(12), 1025000, 0x03006000},
+  { {1, 1}, 1080000,  ACPU_SCPLL, 0, 0, 1, 0x14, L2(13), 1050000, 0x03006000},
+  { {1, 1}, 1134000,  ACPU_SCPLL, 0, 0, 1, 0x15, L2(14), 1075000, 0x03006000},
+  { {1, 1}, 1188000,  ACPU_SCPLL, 0, 0, 1, 0x16, L2(15), 1100000, 0x03006000},
+  { {1, 1}, 1242000,  ACPU_SCPLL, 0, 0, 1, 0x17, L2(16), 1125000, 0x03006000},
+  { {1, 1}, 1296000,  ACPU_SCPLL, 0, 0, 1, 0x18, L2(17), 1150000, 0x03006000},
+  { {1, 1}, 1350000,  ACPU_SCPLL, 0, 0, 1, 0x19, L2(18), 1150000, 0x03006000},
+  { {1, 1}, 1404000,  ACPU_SCPLL, 0, 0, 1, 0x1A, L2(19), 1175000, 0x03006000},
+  { {1, 1}, 1458000,  ACPU_SCPLL, 0, 0, 1, 0x1B, L2(19), 1200000, 0x03006000},
+  { {1, 1}, 1512000,  ACPU_SCPLL, 0, 0, 1, 0x1C, L2(19), 1225000, 0x03006000},
+  { {0, 0}, 0 },
+};
+
+/* SCPLL frequencies = 2 * 27 MHz * L_VAL */
+static struct clkctl_acpu_speed acpu_freq_tbl_1512mhz_nom[] = {
+  { {1, 1},  192000,  ACPU_PLL_8, 3, 1, 0, 0,    L2(1),   800000, 0x03006000},
+  /* MAX_AXI row is used to source CPU cores and L2 from the AFAB clock. */
+  { {0, 0},  MAX_AXI, ACPU_AFAB,  1, 0, 0, 0,    L2(0),   825000, 0x03006000},
+  { {1, 1},  384000,  ACPU_PLL_8, 3, 0, 0, 0,    L2(1),   825000, 0x03006000},
+  { {1, 1},  432000,  ACPU_SCPLL, 0, 0, 1, 0x08, L2(1),   850000, 0x03006000},
+  { {1, 1},  486000,  ACPU_SCPLL, 0, 0, 1, 0x09, L2(2),   850000, 0x03006000},
+  { {1, 1},  540000,  ACPU_SCPLL, 0, 0, 1, 0x0A, L2(3),   875000, 0x03006000},
+  { {1, 1},  594000,  ACPU_SCPLL, 0, 0, 1, 0x0B, L2(4),   875000, 0x03006000},
+  { {1, 1},  648000,  ACPU_SCPLL, 0, 0, 1, 0x0C, L2(5),   900000, 0x03006000},
+  { {1, 1},  702000,  ACPU_SCPLL, 0, 0, 1, 0x0D, L2(6),   900000, 0x03006000},
+  { {1, 1},  756000,  ACPU_SCPLL, 0, 0, 1, 0x0E, L2(7),   925000, 0x03006000},
+  { {1, 1},  810000,  ACPU_SCPLL, 0, 0, 1, 0x0F, L2(8),   950000, 0x03006000},
+  { {1, 1},  864000,  ACPU_SCPLL, 0, 0, 1, 0x10, L2(9),   975000, 0x03006000},
+  { {1, 1},  918000,  ACPU_SCPLL, 0, 0, 1, 0x11, L2(10),  975000, 0x03006000},
+  { {1, 1},  972000,  ACPU_SCPLL, 0, 0, 1, 0x12, L2(11), 1000000, 0x03006000},
+  { {1, 1}, 1026000,  ACPU_SCPLL, 0, 0, 1, 0x13, L2(12), 1000000, 0x03006000},
+  { {1, 1}, 1080000,  ACPU_SCPLL, 0, 0, 1, 0x14, L2(13), 1025000, 0x03006000},
+  { {1, 1}, 1134000,  ACPU_SCPLL, 0, 0, 1, 0x15, L2(14), 1025000, 0x03006000},
+  { {1, 1}, 1188000,  ACPU_SCPLL, 0, 0, 1, 0x16, L2(15), 1050000, 0x03006000},
+  { {1, 1}, 1242000,  ACPU_SCPLL, 0, 0, 1, 0x17, L2(16), 1075000, 0x03006000},
+  { {1, 1}, 1296000,  ACPU_SCPLL, 0, 0, 1, 0x18, L2(17), 1100000, 0x03006000},
+  { {1, 1}, 1350000,  ACPU_SCPLL, 0, 0, 1, 0x19, L2(18), 1125000, 0x03006000},
+  { {1, 1}, 1404000,  ACPU_SCPLL, 0, 0, 1, 0x1A, L2(19), 1150000, 0x03006000},
+  { {1, 1}, 1458000,  ACPU_SCPLL, 0, 0, 1, 0x1B, L2(19), 1150000, 0x03006000},
+  { {1, 1}, 1512000,  ACPU_SCPLL, 0, 0, 1, 0x1C, L2(19), 1175000, 0x03006000},
+  { {0, 0}, 0 },
+};
+
+/* SCPLL frequencies = 2 * 27 MHz * L_VAL */
+static struct clkctl_acpu_speed acpu_freq_tbl_1512mhz_fast[] = {
+  { {1, 1},  192000,  ACPU_PLL_8, 3, 1, 0, 0,    L2(1),   800000, 0x03006000},
+  /* MAX_AXI row is used to source CPU cores and L2 from the AFAB clock. */
+  { {0, 0},  MAX_AXI, ACPU_AFAB,  1, 0, 0, 0,    L2(0),   825000, 0x03006000},
+  { {1, 1},  384000,  ACPU_PLL_8, 3, 0, 0, 0,    L2(1),   825000, 0x03006000},
+  { {1, 1},  432000,  ACPU_SCPLL, 0, 0, 1, 0x08, L2(1),   850000, 0x03006000},
+  { {1, 1},  486000,  ACPU_SCPLL, 0, 0, 1, 0x09, L2(2),   850000, 0x03006000},
+  { {1, 1},  540000,  ACPU_SCPLL, 0, 0, 1, 0x0A, L2(3),   875000, 0x03006000},
+  { {1, 1},  594000,  ACPU_SCPLL, 0, 0, 1, 0x0B, L2(4),   875000, 0x03006000},
+  { {1, 1},  648000,  ACPU_SCPLL, 0, 0, 1, 0x0C, L2(5),   900000, 0x03006000},
+  { {1, 1},  702000,  ACPU_SCPLL, 0, 0, 1, 0x0D, L2(6),   900000, 0x03006000},
+  { {1, 1},  756000,  ACPU_SCPLL, 0, 0, 1, 0x0E, L2(7),   925000, 0x03006000},
+  { {1, 1},  810000,  ACPU_SCPLL, 0, 0, 1, 0x0F, L2(8),   925000, 0x03006000},
+  { {1, 1},  864000,  ACPU_SCPLL, 0, 0, 1, 0x10, L2(9),   950000, 0x03006000},
+  { {1, 1},  918000,  ACPU_SCPLL, 0, 0, 1, 0x11, L2(10),  950000, 0x03006000},
+  { {1, 1},  972000,  ACPU_SCPLL, 0, 0, 1, 0x12, L2(11),  950000, 0x03006000},
+  { {1, 1}, 1026000,  ACPU_SCPLL, 0, 0, 1, 0x13, L2(12),  975000, 0x03006000},
+  { {1, 1}, 1080000,  ACPU_SCPLL, 0, 0, 1, 0x14, L2(13), 1000000, 0x03006000},
+  { {1, 1}, 1134000,  ACPU_SCPLL, 0, 0, 1, 0x15, L2(14), 1000000, 0x03006000},
+  { {1, 1}, 1188000,  ACPU_SCPLL, 0, 0, 1, 0x16, L2(15), 1025000, 0x03006000},
+  { {1, 1}, 1242000,  ACPU_SCPLL, 0, 0, 1, 0x17, L2(16), 1050000, 0x03006000},
+  { {1, 1}, 1296000,  ACPU_SCPLL, 0, 0, 1, 0x18, L2(17), 1075000, 0x03006000},
+  { {1, 1}, 1350000,  ACPU_SCPLL, 0, 0, 1, 0x19, L2(18), 1100000, 0x03006000},
+  { {1, 1}, 1404000,  ACPU_SCPLL, 0, 0, 1, 0x1A, L2(19), 1100000, 0x03006000},
+  { {1, 1}, 1458000,  ACPU_SCPLL, 0, 0, 1, 0x1B, L2(19), 1100000, 0x03006000},
+  { {1, 1}, 1512000,  ACPU_SCPLL, 0, 0, 1, 0x1C, L2(19), 1125000, 0x03006000},
+  { {0, 0}, 0 },
+};
+
+/* SCPLL frequencies = 2 * 27 MHz * L_VAL */
+static struct clkctl_acpu_speed acpu_freq_tbl_1674mhz_slower[] = {
+  { {1, 1},  192000,  ACPU_PLL_8, 3, 1, 0, 0,    L2(1),   775000, 0x03006000},
+  /* MAX_AXI row is used to source CPU cores and L2 from the AFAB clock. */
+  { {0, 0},  MAX_AXI, ACPU_AFAB,  1, 0, 0, 0,    L2(0),   775000, 0x03006000},
+  { {1, 1},  384000,  ACPU_PLL_8, 3, 0, 0, 0,    L2(1),   775000, 0x03006000},
+  { {1, 1},  432000,  ACPU_SCPLL, 0, 0, 1, 0x08, L2(1),   775000, 0x03006000},
+  { {1, 1},  486000,  ACPU_SCPLL, 0, 0, 1, 0x09, L2(2),   775000, 0x03006000},
+  { {1, 1},  540000,  ACPU_SCPLL, 0, 0, 1, 0x0A, L2(3),   787500, 0x03006000},
+  { {1, 1},  594000,  ACPU_SCPLL, 0, 0, 1, 0x0B, L2(4),   800000, 0x03006000},
+  { {1, 1},  648000,  ACPU_SCPLL, 0, 0, 1, 0x0C, L2(5),   825000, 0x03006000},
+  { {1, 1},  702000,  ACPU_SCPLL, 0, 0, 1, 0x0D, L2(6),   837500, 0x03006000},
+  { {1, 1},  756000,  ACPU_SCPLL, 0, 0, 1, 0x0E, L2(7),   850000, 0x03006000},
+  { {1, 1},  810000,  ACPU_SCPLL, 0, 0, 1, 0x0F, L2(8),   875000, 0x03006000},
+  { {1, 1},  864000,  ACPU_SCPLL, 0, 0, 1, 0x10, L2(9),   900000, 0x03006000},
+  { {1, 1},  918000,  ACPU_SCPLL, 0, 0, 1, 0x11, L2(10),  912500, 0x03006000},
+  { {1, 1},  972000,  ACPU_SCPLL, 0, 0, 1, 0x12, L2(11),  937500, 0x03006000},
+  { {1, 1}, 1026000,  ACPU_SCPLL, 0, 0, 1, 0x13, L2(12),  962500, 0x03006000},
+  { {1, 1}, 1080000,  ACPU_SCPLL, 0, 0, 1, 0x14, L2(13),  987500, 0x03006000},
+  { {1, 1}, 1134000,  ACPU_SCPLL, 0, 0, 1, 0x15, L2(14), 1012500, 0x03006000},
+  { {1, 1}, 1188000,  ACPU_SCPLL, 0, 0, 1, 0x16, L2(15), 1025000, 0x03006000},
+  { {1, 1}, 1242000,  ACPU_SCPLL, 0, 0, 1, 0x17, L2(16), 1062500, 0x03006000},
+  { {1, 1}, 1296000,  ACPU_SCPLL, 0, 0, 1, 0x18, L2(17), 1087500, 0x03006000},
+  { {1, 1}, 1350000,  ACPU_SCPLL, 0, 0, 1, 0x19, L2(18), 1100000, 0x03006000},
+  { {1, 1}, 1404000,  ACPU_SCPLL, 0, 0, 1, 0x1A, L2(19), 1125000, 0x03006000},
+  { {1, 1}, 1458000,  ACPU_SCPLL, 0, 0, 1, 0x1B, L2(19), 1150000, 0x03006000},
+  { {1, 1}, 1512000,  ACPU_SCPLL, 0, 0, 1, 0x1C, L2(19), 1187500, 0x03006000},
+  { {1, 1}, 1566000,  ACPU_SCPLL, 0, 0, 1, 0x1D, L2(19), 1225000, 0x03006000},
+  { {1, 1}, 1620000,  ACPU_SCPLL, 0, 0, 1, 0x1E, L2(19), 1262500, 0x03006000},
+  { {1, 1}, 1674000,  ACPU_SCPLL, 0, 0, 1, 0x1F, L2(19), 1300000, 0x03006000},
+  { {0, 0}, 0 },
+};
+
+/* SCPLL frequencies = 2 * 27 MHz * L_VAL */
+static struct clkctl_acpu_speed acpu_freq_tbl_1674mhz_slow[] = {
+  { {1, 1},  192000,  ACPU_PLL_8, 3, 1, 0, 0,    L2(1),   775000, 0x03006000},
+  /* MAX_AXI row is used to source CPU cores and L2 from the AFAB clock. */
+  { {0, 0},  MAX_AXI, ACPU_AFAB,  1, 0, 0, 0,    L2(0),   775000, 0x03006000},
+  { {1, 1},  384000,  ACPU_PLL_8, 3, 0, 0, 0,    L2(1),   775000, 0x03006000},
+  { {1, 1},  432000,  ACPU_SCPLL, 0, 0, 1, 0x08, L2(1),   775000, 0x03006000},
+  { {1, 1},  486000,  ACPU_SCPLL, 0, 0, 1, 0x09, L2(2),   775000, 0x03006000},
+  { {1, 1},  540000,  ACPU_SCPLL, 0, 0, 1, 0x0A, L2(3),   787500, 0x03006000},
+  { {1, 1},  594000,  ACPU_SCPLL, 0, 0, 1, 0x0B, L2(4),   800000, 0x03006000},
+  { {1, 1},  648000,  ACPU_SCPLL, 0, 0, 1, 0x0C, L2(5),   825000, 0x03006000},
+  { {1, 1},  702000,  ACPU_SCPLL, 0, 0, 1, 0x0D, L2(6),   837500, 0x03006000},
+  { {1, 1},  756000,  ACPU_SCPLL, 0, 0, 1, 0x0E, L2(7),   850000, 0x03006000},
+  { {1, 1},  810000,  ACPU_SCPLL, 0, 0, 1, 0x0F, L2(8),   862500, 0x03006000},
+  { {1, 1},  864000,  ACPU_SCPLL, 0, 0, 1, 0x10, L2(9),   887500, 0x03006000},
+  { {1, 1},  918000,  ACPU_SCPLL, 0, 0, 1, 0x11, L2(10),  900000, 0x03006000},
+  { {1, 1},  972000,  ACPU_SCPLL, 0, 0, 1, 0x12, L2(11),  925000, 0x03006000},
+  { {1, 1}, 1026000,  ACPU_SCPLL, 0, 0, 1, 0x13, L2(12),  937500, 0x03006000},
+  { {1, 1}, 1080000,  ACPU_SCPLL, 0, 0, 1, 0x14, L2(13),  962500, 0x03006000},
+  { {1, 1}, 1134000,  ACPU_SCPLL, 0, 0, 1, 0x15, L2(14),  987500, 0x03006000},
+  { {1, 1}, 1188000,  ACPU_SCPLL, 0, 0, 1, 0x16, L2(15), 1000000, 0x03006000},
+  { {1, 1}, 1242000,  ACPU_SCPLL, 0, 0, 1, 0x17, L2(16), 1025000, 0x03006000},
+  { {1, 1}, 1296000,  ACPU_SCPLL, 0, 0, 1, 0x18, L2(17), 1050000, 0x03006000},
+  { {1, 1}, 1350000,  ACPU_SCPLL, 0, 0, 1, 0x19, L2(18), 1062500, 0x03006000},
+  { {1, 1}, 1404000,  ACPU_SCPLL, 0, 0, 1, 0x1A, L2(19), 1087500, 0x03006000},
+  { {1, 1}, 1458000,  ACPU_SCPLL, 0, 0, 1, 0x1B, L2(19), 1112500, 0x03006000},
+  { {1, 1}, 1512000,  ACPU_SCPLL, 0, 0, 1, 0x1C, L2(19), 1150000, 0x03006000},
+  { {1, 1}, 1566000,  ACPU_SCPLL, 0, 0, 1, 0x1D, L2(19), 1175000, 0x03006000},
+  { {1, 1}, 1620000,  ACPU_SCPLL, 0, 0, 1, 0x1E, L2(19), 1212500, 0x03006000},
+  { {1, 1}, 1674000,  ACPU_SCPLL, 0, 0, 1, 0x1F, L2(19), 1250000, 0x03006000},
+  { {0, 0}, 0 },
+};
+
+/* SCPLL frequencies = 2 * 27 MHz * L_VAL */
+static struct clkctl_acpu_speed acpu_freq_tbl_1674mhz_nom[] = {
+  { {1, 1},  192000,  ACPU_PLL_8, 3, 1, 0, 0,    L2(1),   775000, 0x03006000},
+  /* MAX_AXI row is used to source CPU cores and L2 from the AFAB clock. */
+  { {0, 0},  MAX_AXI, ACPU_AFAB,  1, 0, 0, 0,    L2(0),   775000, 0x03006000},
+  { {1, 1},  384000,  ACPU_PLL_8, 3, 0, 0, 0,    L2(1),   775000, 0x03006000},
+  { {1, 1},  432000,  ACPU_SCPLL, 0, 0, 1, 0x08, L2(1),   775000, 0x03006000},
+  { {1, 1},  486000,  ACPU_SCPLL, 0, 0, 1, 0x09, L2(2),   775000, 0x03006000},
+  { {1, 1},  540000,  ACPU_SCPLL, 0, 0, 1, 0x0A, L2(3),   787500, 0x03006000},
+  { {1, 1},  594000,  ACPU_SCPLL, 0, 0, 1, 0x0B, L2(4),   800000, 0x03006000},
+  { {1, 1},  648000,  ACPU_SCPLL, 0, 0, 1, 0x0C, L2(5),   812500, 0x03006000},
+  { {1, 1},  702000,  ACPU_SCPLL, 0, 0, 1, 0x0D, L2(6),   825000, 0x03006000},
+  { {1, 1},  756000,  ACPU_SCPLL, 0, 0, 1, 0x0E, L2(7),   837500, 0x03006000},
+  { {1, 1},  810000,  ACPU_SCPLL, 0, 0, 1, 0x0F, L2(8),   850000, 0x03006000},
+  { {1, 1},  864000,  ACPU_SCPLL, 0, 0, 1, 0x10, L2(9),   875000, 0x03006000},
+  { {1, 1},  918000,  ACPU_SCPLL, 0, 0, 1, 0x11, L2(10),  887500, 0x03006000},
+  { {1, 1},  972000,  ACPU_SCPLL, 0, 0, 1, 0x12, L2(11),  900000, 0x03006000},
+  { {1, 1}, 1026000,  ACPU_SCPLL, 0, 0, 1, 0x13, L2(12),  912500, 0x03006000},
+  { {1, 1}, 1080000,  ACPU_SCPLL, 0, 0, 1, 0x14, L2(13),  937500, 0x03006000},
+  { {1, 1}, 1134000,  ACPU_SCPLL, 0, 0, 1, 0x15, L2(14),  950000, 0x03006000},
+  { {1, 1}, 1188000,  ACPU_SCPLL, 0, 0, 1, 0x16, L2(15),  975000, 0x03006000},
+  { {1, 1}, 1242000,  ACPU_SCPLL, 0, 0, 1, 0x17, L2(16),  987500, 0x03006000},
+  { {1, 1}, 1296000,  ACPU_SCPLL, 0, 0, 1, 0x18, L2(17), 1012500, 0x03006000},
+  { {1, 1}, 1350000,  ACPU_SCPLL, 0, 0, 1, 0x19, L2(18), 1025000, 0x03006000},
+  { {1, 1}, 1404000,  ACPU_SCPLL, 0, 0, 1, 0x1A, L2(19), 1050000, 0x03006000},
+  { {1, 1}, 1458000,  ACPU_SCPLL, 0, 0, 1, 0x1B, L2(19), 1075000, 0x03006000},
+  { {1, 1}, 1512000,  ACPU_SCPLL, 0, 0, 1, 0x1C, L2(19), 1112500, 0x03006000},
+  { {1, 1}, 1566000,  ACPU_SCPLL, 0, 0, 1, 0x1D, L2(19), 1137500, 0x03006000},
+  { {1, 1}, 1620000,  ACPU_SCPLL, 0, 0, 1, 0x1E, L2(19), 1175000, 0x03006000},
+  { {1, 1}, 1674000,  ACPU_SCPLL, 0, 0, 1, 0x1F, L2(19), 1200000, 0x03006000},
+  { {0, 0}, 0 },
+};
+
+/* SCPLL frequencies = 2 * 27 MHz * L_VAL */
+static struct clkctl_acpu_speed acpu_freq_tbl_1674mhz_fast[] = {
+  { {1, 1},  192000,  ACPU_PLL_8, 3, 1, 0, 0,    L2(1),   775000, 0x03006000},
+  /* MAX_AXI row is used to source CPU cores and L2 from the AFAB clock. */
+  { {0, 0},  MAX_AXI, ACPU_AFAB,  1, 0, 0, 0,    L2(0),   775000, 0x03006000},
+  { {1, 1},  384000,  ACPU_PLL_8, 3, 0, 0, 0,    L2(1),   775000, 0x03006000},
+  { {1, 1},  432000,  ACPU_SCPLL, 0, 0, 1, 0x08, L2(1),   775000, 0x03006000},
+  { {1, 1},  486000,  ACPU_SCPLL, 0, 0, 1, 0x09, L2(2),   775000, 0x03006000},
+  { {1, 1},  540000,  ACPU_SCPLL, 0, 0, 1, 0x0A, L2(3),   775000, 0x03006000},
+  { {1, 1},  594000,  ACPU_SCPLL, 0, 0, 1, 0x0B, L2(4),   787500, 0x03006000},
+  { {1, 1},  648000,  ACPU_SCPLL, 0, 0, 1, 0x0C, L2(5),   800000, 0x03006000},
+  { {1, 1},  702000,  ACPU_SCPLL, 0, 0, 1, 0x0D, L2(6),   812500, 0x03006000},
+  { {1, 1},  756000,  ACPU_SCPLL, 0, 0, 1, 0x0E, L2(7),   825000, 0x03006000},
+  { {1, 1},  810000,  ACPU_SCPLL, 0, 0, 1, 0x0F, L2(8),   837500, 0x03006000},
+  { {1, 1},  864000,  ACPU_SCPLL, 0, 0, 1, 0x10, L2(9),   862500, 0x03006000},
+  { {1, 1},  918000,  ACPU_SCPLL, 0, 0, 1, 0x11, L2(10),  875000, 0x03006000},
+  { {1, 1},  972000,  ACPU_SCPLL, 0, 0, 1, 0x12, L2(11),  887500, 0x03006000},
+  { {1, 1}, 1026000,  ACPU_SCPLL, 0, 0, 1, 0x13, L2(12),  900000, 0x03006000},
+  { {1, 1}, 1080000,  ACPU_SCPLL, 0, 0, 1, 0x14, L2(13),  925000, 0x03006000},
+  { {1, 1}, 1134000,  ACPU_SCPLL, 0, 0, 1, 0x15, L2(14),  937500, 0x03006000},
+  { {1, 1}, 1188000,  ACPU_SCPLL, 0, 0, 1, 0x16, L2(15),  950000, 0x03006000},
+  { {1, 1}, 1242000,  ACPU_SCPLL, 0, 0, 1, 0x17, L2(16),  962500, 0x03006000},
+  { {1, 1}, 1296000,  ACPU_SCPLL, 0, 0, 1, 0x18, L2(17),  975000, 0x03006000},
+  { {1, 1}, 1350000,  ACPU_SCPLL, 0, 0, 1, 0x19, L2(18), 1000000, 0x03006000},
+  { {1, 1}, 1404000,  ACPU_SCPLL, 0, 0, 1, 0x1A, L2(19), 1025000, 0x03006000},
+  { {1, 1}, 1458000,  ACPU_SCPLL, 0, 0, 1, 0x1B, L2(19), 1050000, 0x03006000},
+  { {1, 1}, 1512000,  ACPU_SCPLL, 0, 0, 1, 0x1C, L2(19), 1075000, 0x03006000},
+  { {1, 1}, 1566000,  ACPU_SCPLL, 0, 0, 1, 0x1D, L2(19), 1100000, 0x03006000},
+  { {1, 1}, 1620000,  ACPU_SCPLL, 0, 0, 1, 0x1E, L2(19), 1125000, 0x03006000},
+  { {1, 1}, 1674000,  ACPU_SCPLL, 0, 0, 1, 0x1F, L2(19), 1150000, 0x03006000},
+  { {0, 0}, 0 },
+};
+
+/* acpu_freq_tbl row to use when reconfiguring SC/L2 PLLs. */
+#define CAL_IDX 1
+
+static struct clkctl_acpu_speed *acpu_freq_tbl;
+static struct clkctl_l2_speed *l2_freq_tbl = l2_freq_tbl_v2;
+static unsigned int l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_v2);
+
+static unsigned long acpuclk_8x60_get_rate(int cpu)
+{
+	return drv_state.current_speed[cpu]->acpuclk_khz;
+}
+
+static void select_core_source(unsigned int id, unsigned int src)
+{
+	uint32_t regval;
+	int shift;
+
+	shift = (id == L2) ? 0 : 1;
+	regval = readl_relaxed(clk_sel_addr[id]);
+	regval &= ~(0x3 << shift);
+	regval |= (src << shift);
+	writel_relaxed(regval, clk_sel_addr[id]);
+}
+
+static void select_clk_source_div(unsigned int id, struct clkctl_acpu_speed *s)
+{
+	uint32_t reg_clksel, reg_clkctl, src_sel;
+
+	/* Configure the PLL divider mux if we plan to use it. */
+	if (s->core_src_sel == 0) {
+
+		reg_clksel = readl_relaxed(clk_sel_addr[id]);
+
+		/* CLK_SEL_SRC1N0 (bank) bit. */
+		src_sel = reg_clksel & 1;
+
+		/* Program clock source and divider. */
+		reg_clkctl = readl_relaxed(clk_ctl_addr[id]);
+		reg_clkctl &= ~(0xFF << (8 * src_sel));
+		reg_clkctl |= s->acpuclk_src_sel << (4 + 8 * src_sel);
+		reg_clkctl |= s->acpuclk_src_div << (0 + 8 * src_sel);
+		writel_relaxed(reg_clkctl, clk_ctl_addr[id]);
+
+		/* Toggle clock source. */
+		reg_clksel ^= 1;
+
+		/* Program clock source selection. */
+		writel_relaxed(reg_clksel, clk_sel_addr[id]);
+	}
+}
+
+static void scpll_enable(int sc_pll, uint32_t l_val)
+{
+	uint32_t regval;
+
+	/* Power-up SCPLL into standby mode. */
+	writel_relaxed(SCPLL_STANDBY, sc_pll_base[sc_pll] + SCPLL_CTL_OFFSET);
+	mb();
+	udelay(10);
+
+	/* Shot-switch to target frequency. */
+	regval = (l_val << 3) | SHOT_SWITCH;
+	writel_relaxed(regval, sc_pll_base[sc_pll] + SCPLL_FSM_CTL_EXT_OFFSET);
+	writel_relaxed(SCPLL_NORMAL, sc_pll_base[sc_pll] + SCPLL_CTL_OFFSET);
+	mb();
+	udelay(20);
+}
+
+static void scpll_disable(int sc_pll)
+{
+	/* Power down SCPLL. */
+	writel_relaxed(SCPLL_POWER_DOWN,
+		       sc_pll_base[sc_pll] + SCPLL_CTL_OFFSET);
+}
+
+static void scpll_change_freq(int sc_pll, uint32_t l_val)
+{
+	uint32_t regval;
+	const void *base_addr = sc_pll_base[sc_pll];
+
+	/* Complex-slew switch to target frequency. */
+	regval = (l_val << 3) | COMPLEX_SLEW;
+	writel_relaxed(regval, base_addr + SCPLL_FSM_CTL_EXT_OFFSET);
+	writel_relaxed(SCPLL_NORMAL, base_addr + SCPLL_CTL_OFFSET);
+
+	/* Wait for frequency switch to start. */
+	while (((readl_relaxed(base_addr + SCPLL_CTL_OFFSET) >> 3) & 0x3F)
+			!= l_val)
+		cpu_relax();
+	/* Wait for frequency switch to finish. */
+	while (readl_relaxed(base_addr + SCPLL_STATUS_OFFSET) & 0x1)
+		cpu_relax();
+}
+
+/* Vote for the L2 speed and return the speed that should be applied. */
+static struct clkctl_l2_speed *compute_l2_speed(unsigned int voting_cpu,
+						struct clkctl_l2_speed *tgt_s)
+{
+	struct clkctl_l2_speed *new_s;
+	int cpu;
+
+	/* Bounds check. */
+	BUG_ON(tgt_s >= (l2_freq_tbl + l2_freq_tbl_size));
+
+	/* Find max L2 speed vote. */
+	l2_vote[voting_cpu] = tgt_s;
+	new_s = l2_freq_tbl;
+	for_each_present_cpu(cpu)
+		new_s = max(new_s, l2_vote[cpu]);
+
+	return new_s;
+}
+
+/* Set the L2's clock speed. */
+static void set_l2_speed(struct clkctl_l2_speed *tgt_s)
+{
+	if (tgt_s == drv_state.current_l2_speed)
+		return;
+
+	if (drv_state.current_l2_speed->src_sel == 1
+				&& tgt_s->src_sel == 1)
+		scpll_change_freq(L2, tgt_s->l_val);
+	else {
+		if (tgt_s->src_sel == 1) {
+			scpll_enable(L2, tgt_s->l_val);
+			mb();
+			select_core_source(L2, tgt_s->src_sel);
+		} else {
+			select_core_source(L2, tgt_s->src_sel);
+			mb();
+			scpll_disable(L2);
+		}
+	}
+	drv_state.current_l2_speed = tgt_s;
+}
+
+/* Update the bus bandwidth request. */
+static void set_bus_bw(unsigned int bw)
+{
+	int ret;
+
+	/* Bounds check. */
+	if (bw >= ARRAY_SIZE(bw_level_tbl)) {
+		pr_err("%s: invalid bandwidth request (%d)\n", __func__, bw);
+		return;
+	}
+
+	/* Update bandwidth if requst has changed. This may sleep. */
+	ret = msm_bus_scale_client_update_request(bus_perf_client, bw);
+	if (ret)
+		pr_err("%s: bandwidth request failed (%d)\n", __func__, ret);
+
+	return;
+}
+
+/* Apply any per-cpu voltage increases. */
+static int increase_vdd(int cpu, unsigned int vdd_sc, unsigned int vdd_mem,
+			unsigned int vdd_dig, enum setrate_reason reason)
+{
+	int rc = 0;
+
+	/* Increase vdd_mem active-set before vdd_dig and vdd_sc.
+	 * vdd_mem should be >= both vdd_sc and vdd_dig. */
+	rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8058_S0, rpm_vreg_voter[cpu],
+				  vdd_mem, MAX_VDD_MEM, 0);
+	if (rc) {
+		pr_err("%s: vdd_mem (cpu%d) increase failed (%d)\n",
+			__func__, cpu, rc);
+		return rc;
+	}
+
+	/* Increase vdd_dig active-set vote. */
+	rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8058_S1, rpm_vreg_voter[cpu],
+				  vdd_dig, MAX_VDD_DIG, 0);
+	if (rc) {
+		pr_err("%s: vdd_dig (cpu%d) increase failed (%d)\n",
+			__func__, cpu, rc);
+		return rc;
+	}
+
+	 /* Don't update the Scorpion voltage in the hotplug path.  It should
+	  * already be correct.  Attempting to set it is bad because we don't
+	  * know what CPU we are running on at this point, but the Scorpion
+	  * regulator API requires we call it from the affected CPU.  */
+	if (reason == SETRATE_HOTPLUG)
+		return rc;
+
+	/* Update per-core Scorpion voltage. */
+	rc = regulator_set_voltage(regulator_sc[cpu], vdd_sc, MAX_VDD_SC);
+	if (rc) {
+		pr_err("%s: vdd_sc (cpu%d) increase failed (%d)\n",
+			__func__, cpu, rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+/* Apply any per-cpu voltage decreases. */
+static void decrease_vdd(int cpu, unsigned int vdd_sc, unsigned int vdd_mem,
+			 unsigned int vdd_dig, enum setrate_reason reason)
+{
+	int ret;
+
+	/* Update per-core Scorpion voltage. This must be called on the CPU
+	 * that's being affected. Don't do this in the hotplug remove path,
+	 * where the rail is off and we're executing on the other CPU. */
+	if (reason != SETRATE_HOTPLUG) {
+		ret = regulator_set_voltage(regulator_sc[cpu], vdd_sc,
+					    MAX_VDD_SC);
+		if (ret) {
+			pr_err("%s: vdd_sc (cpu%d) decrease failed (%d)\n",
+				__func__, cpu, ret);
+			return;
+		}
+	}
+
+	/* Decrease vdd_dig active-set vote. */
+	ret = rpm_vreg_set_voltage(RPM_VREG_ID_PM8058_S1, rpm_vreg_voter[cpu],
+				   vdd_dig, MAX_VDD_DIG, 0);
+	if (ret) {
+		pr_err("%s: vdd_dig (cpu%d) decrease failed (%d)\n",
+			__func__, cpu, ret);
+		return;
+	}
+
+	/* Decrease vdd_mem active-set after vdd_dig and vdd_sc.
+	 * vdd_mem should be >= both vdd_sc and vdd_dig. */
+	ret = rpm_vreg_set_voltage(RPM_VREG_ID_PM8058_S0, rpm_vreg_voter[cpu],
+				   vdd_mem, MAX_VDD_MEM, 0);
+	if (ret) {
+		pr_err("%s: vdd_mem (cpu%d) decrease failed (%d)\n",
+			__func__, cpu, ret);
+		return;
+	}
+}
+
+static void switch_sc_speed(int cpu, struct clkctl_acpu_speed *tgt_s)
+{
+	struct clkctl_acpu_speed *strt_s = drv_state.current_speed[cpu];
+
+	if (strt_s->pll != ACPU_SCPLL && tgt_s->pll != ACPU_SCPLL) {
+		select_clk_source_div(cpu, tgt_s);
+		/* Select core source because target may be AFAB. */
+		select_core_source(cpu, tgt_s->core_src_sel);
+	} else if (strt_s->pll != ACPU_SCPLL && tgt_s->pll == ACPU_SCPLL) {
+		scpll_enable(cpu, tgt_s->l_val);
+		mb();
+		select_core_source(cpu, tgt_s->core_src_sel);
+	} else if (strt_s->pll == ACPU_SCPLL && tgt_s->pll != ACPU_SCPLL) {
+		select_clk_source_div(cpu, tgt_s);
+		select_core_source(cpu, tgt_s->core_src_sel);
+		/* Core source switch must complete before disabling SCPLL. */
+		mb();
+		udelay(1);
+		scpll_disable(cpu);
+	} else
+		scpll_change_freq(cpu, tgt_s->l_val);
+
+	/* Update the driver state with the new clock freq */
+	drv_state.current_speed[cpu] = tgt_s;
+}
+
+static int acpuclk_8x60_set_rate(int cpu, unsigned long rate,
+				 enum setrate_reason reason)
+{
+	struct clkctl_acpu_speed *tgt_s, *strt_s;
+	struct clkctl_l2_speed *tgt_l2;
+	unsigned int vdd_mem, vdd_dig, pll_vdd_dig;
+	unsigned long flags;
+	int rc = 0;
+
+	if (cpu > num_possible_cpus()) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	if (reason == SETRATE_CPUFREQ || reason == SETRATE_HOTPLUG)
+		mutex_lock(&drv_state.lock);
+
+	strt_s = drv_state.current_speed[cpu];
+
+	/* Return early if rate didn't change. */
+	if (rate == strt_s->acpuclk_khz)
+		goto out;
+
+	/* Find target frequency. */
+	for (tgt_s = acpu_freq_tbl; tgt_s->acpuclk_khz != 0; tgt_s++)
+		if (tgt_s->acpuclk_khz == rate)
+			break;
+	if (tgt_s->acpuclk_khz == 0) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	/* AVS needs SAW_VCTL to be intitialized correctly, before enable,
+	 * and is not initialized at acpuclk_init().
+	 */
+	if (reason == SETRATE_CPUFREQ)
+		AVS_DISABLE(cpu);
+
+	/* Calculate vdd_mem and vdd_dig requirements.
+	 * vdd_mem must be >= vdd_sc */
+	vdd_mem = max(tgt_s->vdd_sc, tgt_s->l2_level->vdd_mem);
+	/* Factor-in PLL vdd_dig requirements. */
+	if ((tgt_s->l2_level->khz > SCPLL_LOW_VDD_FMAX) ||
+	    (tgt_s->pll == ACPU_SCPLL
+	     && tgt_s->acpuclk_khz > SCPLL_LOW_VDD_FMAX))
+		pll_vdd_dig = SCPLL_NOMINAL_VDD;
+	else
+		pll_vdd_dig = SCPLL_LOW_VDD;
+	vdd_dig = max(tgt_s->l2_level->vdd_dig, pll_vdd_dig);
+
+	/* Increase VDD levels if needed. */
+	if ((reason == SETRATE_CPUFREQ || reason == SETRATE_HOTPLUG
+	  || reason == SETRATE_INIT)
+			&& (tgt_s->acpuclk_khz > strt_s->acpuclk_khz)) {
+		rc = increase_vdd(cpu, tgt_s->vdd_sc, vdd_mem, vdd_dig, reason);
+		if (rc)
+			goto out;
+	}
+
+	pr_debug("Switching from ACPU%d rate %u KHz -> %u KHz\n",
+		cpu, strt_s->acpuclk_khz, tgt_s->acpuclk_khz);
+
+	/* Switch CPU speed. */
+	switch_sc_speed(cpu, tgt_s);
+
+	/* Update the L2 vote and apply the rate change. */
+	spin_lock_irqsave(&drv_state.l2_lock, flags);
+	tgt_l2 = compute_l2_speed(cpu, tgt_s->l2_level);
+	set_l2_speed(tgt_l2);
+	spin_unlock_irqrestore(&drv_state.l2_lock, flags);
+
+	/* Nothing else to do for SWFI. */
+	if (reason == SETRATE_SWFI)
+		goto out;
+
+	/* Nothing else to do for power collapse. */
+	if (reason == SETRATE_PC)
+		goto out;
+
+	/* Update bus bandwith request. */
+	set_bus_bw(tgt_l2->bw_level);
+
+	/* Drop VDD levels if we can. */
+	if (tgt_s->acpuclk_khz < strt_s->acpuclk_khz)
+		decrease_vdd(cpu, tgt_s->vdd_sc, vdd_mem, vdd_dig, reason);
+
+	pr_debug("ACPU%d speed change complete\n", cpu);
+
+	/* Re-enable AVS */
+	if (reason == SETRATE_CPUFREQ)
+		AVS_ENABLE(cpu, tgt_s->avsdscr_setting);
+
+out:
+	if (reason == SETRATE_CPUFREQ || reason == SETRATE_HOTPLUG)
+		mutex_unlock(&drv_state.lock);
+	return rc;
+}
+
+static void __init scpll_init(int pll, unsigned int max_l_val)
+{
+	uint32_t regval;
+
+	pr_debug("Initializing SCPLL%d\n", pll);
+
+	/* Clear calibration LUT registers containing max frequency entry.
+	 * LUT registers are only writeable in debug mode. */
+	writel_relaxed(SCPLL_DEBUG_FULL, sc_pll_base[pll] + SCPLL_DEBUG_OFFSET);
+	writel_relaxed(0x0, sc_pll_base[pll] + SCPLL_LUT_OFFSET(max_l_val));
+	writel_relaxed(SCPLL_DEBUG_NONE, sc_pll_base[pll] + SCPLL_DEBUG_OFFSET);
+
+	/* Power-up SCPLL into standby mode. */
+	writel_relaxed(SCPLL_STANDBY, sc_pll_base[pll] + SCPLL_CTL_OFFSET);
+	mb();
+	udelay(10);
+
+	/* Calibrate the SCPLL for the frequency range needed. */
+	regval = (max_l_val << 24) | (L_VAL_SCPLL_CAL_MIN << 16);
+	writel_relaxed(regval, sc_pll_base[pll] + SCPLL_CAL_OFFSET);
+
+	/* Start calibration */
+	writel_relaxed(SCPLL_FULL_CAL, sc_pll_base[pll] + SCPLL_CTL_OFFSET);
+
+	/* Wait for proof that calibration has started before checking the
+	 * 'calibration done' bit in the status register. Waiting for the
+	 * LUT register we cleared to contain data accomplishes this.
+	 * This is required since the 'calibration done' bit takes time to
+	 * transition from 'done' to 'not done' when starting a calibration.
+	 */
+	while (!readl_relaxed(sc_pll_base[pll] + SCPLL_LUT_OFFSET(max_l_val)))
+		cpu_relax();
+
+	/* Wait for calibration to complete. */
+	while (readl_relaxed(sc_pll_base[pll] + SCPLL_STATUS_OFFSET) & 0x2)
+		cpu_relax();
+
+	/* Power-down SCPLL. */
+	scpll_disable(pll);
+}
+
+/* Force ACPU core and L2 cache clocks to rates that don't require SCPLLs. */
+static void __init unselect_scplls(void)
+{
+	int cpu;
+
+	/* Ensure CAL_IDX frequency uses AFAB sources for CPU cores and L2. */
+	BUG_ON(acpu_freq_tbl[CAL_IDX].core_src_sel != 0);
+	BUG_ON(acpu_freq_tbl[CAL_IDX].l2_level->src_sel != 0);
+
+	for_each_possible_cpu(cpu) {
+		select_clk_source_div(cpu, &acpu_freq_tbl[CAL_IDX]);
+		select_core_source(cpu, acpu_freq_tbl[CAL_IDX].core_src_sel);
+		drv_state.current_speed[cpu] = &acpu_freq_tbl[CAL_IDX];
+		l2_vote[cpu] = acpu_freq_tbl[CAL_IDX].l2_level;
+	}
+
+	select_core_source(L2, acpu_freq_tbl[CAL_IDX].l2_level->src_sel);
+	drv_state.current_l2_speed = acpu_freq_tbl[CAL_IDX].l2_level;
+}
+
+/* Ensure SCPLLs use the 27MHz PXO. */
+static void __init scpll_set_refs(void)
+{
+	int cpu;
+	uint32_t regval;
+
+	/* Bit 4 = 0:PXO, 1:MXO. */
+	for_each_possible_cpu(cpu) {
+		regval = readl_relaxed(sc_pll_base[cpu] + SCPLL_CFG_OFFSET);
+		regval &= ~BIT(4);
+		writel_relaxed(regval, sc_pll_base[cpu] + SCPLL_CFG_OFFSET);
+	}
+	regval = readl_relaxed(sc_pll_base[L2] + SCPLL_CFG_OFFSET);
+	regval &= ~BIT(4);
+	writel_relaxed(regval, sc_pll_base[L2] + SCPLL_CFG_OFFSET);
+}
+
+/* Voltage regulator initialization. */
+static void __init regulator_init(void)
+{
+	struct clkctl_acpu_speed **freq = drv_state.current_speed;
+	const char *regulator_sc_name[] = {"8901_s0", "8901_s1"};
+	int cpu, ret;
+
+	for_each_possible_cpu(cpu) {
+		/* VDD_SC0, VDD_SC1 */
+		regulator_sc[cpu] = regulator_get(NULL, regulator_sc_name[cpu]);
+		if (IS_ERR(regulator_sc[cpu]))
+			goto err;
+		ret = regulator_set_voltage(regulator_sc[cpu],
+				freq[cpu]->vdd_sc, MAX_VDD_SC);
+		if (ret)
+			goto err;
+		ret = regulator_enable(regulator_sc[cpu]);
+		if (ret)
+			goto err;
+	}
+
+	return;
+
+err:
+	pr_err("%s: Failed to initialize voltage regulators\n", __func__);
+	BUG();
+}
+
+/* Register with bus driver. */
+static void __init bus_init(void)
+{
+	bus_perf_client = msm_bus_scale_register_client(&bus_client_pdata);
+	if (!bus_perf_client) {
+		pr_err("%s: unable register bus client\n", __func__);
+		BUG();
+	}
+}
+
+#ifdef CONFIG_CPU_FREQ_MSM
+static struct cpufreq_frequency_table freq_table[NR_CPUS][30];
+
+static void __init cpufreq_table_init(void)
+{
+	int cpu;
+
+	for_each_possible_cpu(cpu) {
+		int i, freq_cnt = 0;
+		/* Construct the freq_table tables from acpu_freq_tbl. */
+		for (i = 0; acpu_freq_tbl[i].acpuclk_khz != 0
+				&& freq_cnt < ARRAY_SIZE(*freq_table); i++) {
+			if (acpu_freq_tbl[i].use_for_scaling[cpu]) {
+				freq_table[cpu][freq_cnt].index = freq_cnt;
+				freq_table[cpu][freq_cnt].frequency
+					= acpu_freq_tbl[i].acpuclk_khz;
+				freq_cnt++;
+			}
+		}
+		/* freq_table not big enough to store all usable freqs. */
+		BUG_ON(acpu_freq_tbl[i].acpuclk_khz != 0);
+
+		freq_table[cpu][freq_cnt].index = freq_cnt;
+		freq_table[cpu][freq_cnt].frequency = CPUFREQ_TABLE_END;
+
+		pr_info("CPU%d: %d scaling frequencies supported.\n",
+			cpu, freq_cnt);
+
+		/* Register table with CPUFreq. */
+		cpufreq_frequency_table_get_attr(freq_table[cpu], cpu);
+	}
+}
+#else
+static void __init cpufreq_table_init(void) {}
+#endif
+
+#define HOT_UNPLUG_KHZ MAX_AXI
+static int __cpuinit acpuclock_cpu_callback(struct notifier_block *nfb,
+					    unsigned long action, void *hcpu)
+{
+	static int prev_khz[NR_CPUS];
+	int cpu = (int)hcpu;
+
+	switch (action) {
+	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
+		prev_khz[cpu] = acpuclk_8x60_get_rate(cpu);
+		/* Fall through. */
+	case CPU_UP_CANCELED:
+	case CPU_UP_CANCELED_FROZEN:
+		acpuclk_8x60_set_rate(cpu, HOT_UNPLUG_KHZ, SETRATE_HOTPLUG);
+		break;
+	case CPU_UP_PREPARE:
+	case CPU_UP_PREPARE_FROZEN:
+		if (WARN_ON(!prev_khz[cpu]))
+			return NOTIFY_BAD;
+		acpuclk_8x60_set_rate(cpu, prev_khz[cpu], SETRATE_HOTPLUG);
+		break;
+	default:
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata acpuclock_cpu_notifier = {
+	.notifier_call = acpuclock_cpu_callback,
+};
+
+static __init struct clkctl_acpu_speed *select_freq_plan(void)
+{
+	uint32_t pte_efuse, speed_bin, pvs;
+	struct clkctl_acpu_speed *f;
+
+	pte_efuse = readl_relaxed(QFPROM_PTE_EFUSE_ADDR);
+
+	speed_bin = pte_efuse & 0xF;
+	if (speed_bin == 0xF)
+		speed_bin = (pte_efuse >> 4) & 0xF;
+
+	pvs = (pte_efuse >> 10) & 0x7;
+	if (pvs == 0x7)
+		pvs = (pte_efuse >> 13) & 0x7;
+
+	if (speed_bin == 0x2) {
+		switch (pvs) {
+		case 0x7:
+		case 0x4:
+			acpu_freq_tbl = acpu_freq_tbl_1674mhz_slower;
+			pr_info("ACPU PVS: Slower\n");
+			break;
+		case 0x0:
+			acpu_freq_tbl = acpu_freq_tbl_1674mhz_slow;
+			pr_info("ACPU PVS: Slow\n");
+			break;
+		case 0x1:
+			acpu_freq_tbl = acpu_freq_tbl_1674mhz_nom;
+			pr_info("ACPU PVS: Nominal\n");
+			break;
+		case 0x3:
+			acpu_freq_tbl = acpu_freq_tbl_1674mhz_fast;
+			pr_info("ACPU PVS: Fast\n");
+			break;
+		default:
+			acpu_freq_tbl = acpu_freq_tbl_1674mhz_slower;
+			pr_warn("ACPU PVS: Unknown. Defaulting to slower.\n");
+			break;
+		}
+	} else if (speed_bin == 0x1) {
+		switch (pvs) {
+		case 0x0:
+		case 0x7:
+			acpu_freq_tbl = acpu_freq_tbl_1512mhz_slow;
+			pr_info("ACPU PVS: Slow\n");
+			break;
+		case 0x1:
+			acpu_freq_tbl = acpu_freq_tbl_1512mhz_nom;
+			pr_info("ACPU PVS: Nominal\n");
+			break;
+		case 0x3:
+			acpu_freq_tbl = acpu_freq_tbl_1512mhz_fast;
+			pr_info("ACPU PVS: Fast\n");
+			break;
+		default:
+			acpu_freq_tbl = acpu_freq_tbl_1512mhz_slow;
+			pr_warn("ACPU PVS: Unknown. Defaulting to slow.\n");
+			break;
+		}
+	} else {
+		acpu_freq_tbl = acpu_freq_tbl_1188mhz;
+	}
+
+	for (f = acpu_freq_tbl; f->acpuclk_khz != 0; f++)
+		;
+	f--;
+	pr_info("Max ACPU freq: %u KHz\n", f->acpuclk_khz);
+
+	return f;
+}
+
+static struct acpuclk_data acpuclk_8x60_data = {
+	.set_rate = acpuclk_8x60_set_rate,
+	.get_rate = acpuclk_8x60_get_rate,
+	.power_collapse_khz = MAX_AXI,
+	.wait_for_irq_khz = MAX_AXI,
+};
+
+static int __init acpuclk_8x60_init(struct acpuclk_soc_data *soc_data)
+{
+	struct clkctl_acpu_speed *max_freq;
+	int cpu;
+
+	mutex_init(&drv_state.lock);
+	spin_lock_init(&drv_state.l2_lock);
+
+	/* Configure hardware. */
+	max_freq = select_freq_plan();
+	unselect_scplls();
+	scpll_set_refs();
+	for_each_possible_cpu(cpu)
+		scpll_init(cpu, max_freq->l_val);
+	scpll_init(L2, max_freq->l2_level->l_val);
+	regulator_init();
+	bus_init();
+
+	/* Improve boot time by ramping up CPUs immediately. */
+	for_each_online_cpu(cpu)
+		acpuclk_8x60_set_rate(cpu, max_freq->acpuclk_khz, SETRATE_INIT);
+
+	acpuclk_register(&acpuclk_8x60_data);
+	cpufreq_table_init();
+	register_hotcpu_notifier(&acpuclock_cpu_notifier);
+
+	return 0;
+}
+
+struct acpuclk_soc_data acpuclk_8x60_soc_data __initdata = {
+	.init = acpuclk_8x60_init,
+};
diff --git a/arch/arm/mach-msm/acpuclock-9615.c b/arch/arm/mach-msm/acpuclock-9615.c
new file mode 100644
index 0000000..8882f41
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock-9615.c
@@ -0,0 +1,356 @@
+/*
+ * 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
+ * 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/cpufreq.h>
+#include <linux/clk.h>
+
+#include <asm/cpu.h>
+
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#include <mach/rpm-regulator.h>
+
+#include "acpuclock.h"
+
+#define REG_CLKSEL_0	(MSM_APCS_GLB_BASE + 0x08)
+#define REG_CLKDIV_0	(MSM_APCS_GLB_BASE + 0x0C)
+#define REG_CLKSEL_1	(MSM_APCS_GLB_BASE + 0x10)
+#define REG_CLKDIV_1	(MSM_APCS_GLB_BASE + 0x14)
+#define REG_CLKOUTSEL	(MSM_APCS_GLB_BASE + 0x18)
+
+#define MAX_VDD_CPU	1150000
+#define MAX_VDD_MEM	1150000
+
+enum clk_src {
+	SRC_CXO,
+	SRC_PLL0,
+	SRC_PLL8,
+	SRC_PLL9,
+	NUM_SRC,
+};
+
+struct src_clock {
+	struct clk *clk;
+	const char *name;
+};
+
+static struct src_clock clocks[NUM_SRC] = {
+	[SRC_PLL0].name = "pll0",
+	[SRC_PLL8].name = "pll8",
+	[SRC_PLL9].name = "pll9",
+};
+
+struct clkctl_acpu_speed {
+	bool		use_for_scaling;
+	unsigned int	khz;
+	int		src;
+	unsigned int	src_sel;
+	unsigned int	src_div;
+	unsigned int	vdd_cpu;
+	unsigned int	vdd_mem;
+	unsigned int	bw_level;
+};
+
+struct acpuclk_state {
+	struct mutex			lock;
+	struct clkctl_acpu_speed	*current_speed;
+};
+
+static struct acpuclk_state drv_state = {
+	.current_speed = &(struct clkctl_acpu_speed){ 0 },
+};
+
+/* Instantaneous bandwidth requests in MB/s. */
+#define BW_MBPS(_bw) \
+	{ \
+		.vectors = &(struct msm_bus_vectors){ \
+			.src = MSM_BUS_MASTER_AMPSS_M0, \
+			.dst = MSM_BUS_SLAVE_EBI_CH0, \
+			.ib = (_bw) * 1000000UL, \
+			.ab = 0, \
+		}, \
+		.num_paths = 1, \
+	}
+static struct msm_bus_paths bw_level_tbl[] = {
+	[0] =  BW_MBPS(152), /* At least  19 MHz on bus. */
+	[1] =  BW_MBPS(368), /* At least  46 MHz on bus. */
+	[2] =  BW_MBPS(552), /* At least  69 MHz on bus. */
+	[3] =  BW_MBPS(736), /* At least  92 MHz on bus. */
+	[4] = BW_MBPS(1064), /* At least 133 MHz on bus. */
+	[5] = BW_MBPS(1536), /* At least 192 MHz on bus. */
+};
+
+static struct msm_bus_scale_pdata bus_client_pdata = {
+	.usecase = bw_level_tbl,
+	.num_usecases = ARRAY_SIZE(bw_level_tbl),
+	.active_only = 1,
+	.name = "acpuclock",
+};
+
+static uint32_t bus_perf_client;
+
+static struct clkctl_acpu_speed acpu_freq_tbl[] = {
+	{ 0,  19200, SRC_CXO,  0, 0,  950000, 1050000, 0 },
+	{ 1, 138000, SRC_PLL0, 6, 1,  950000, 1050000, 2 },
+	{ 1, 276000, SRC_PLL0, 6, 0, 1050000, 1050000, 2 },
+	{ 1, 384000, SRC_PLL8, 3, 0, 1150000, 1150000, 4 },
+	/* The row below may be changed at runtime depending on hw rev. */
+	{ 1, 440000, SRC_PLL9, 2, 0, 1150000, 1150000, 4 },
+	{ 0 }
+};
+
+static void select_clk_source_div(struct clkctl_acpu_speed *s)
+{
+	static void * __iomem const sel_reg[] = {REG_CLKSEL_0, REG_CLKSEL_1};
+	static void * __iomem const div_reg[] = {REG_CLKDIV_0, REG_CLKDIV_1};
+	uint32_t next_bank;
+
+	next_bank = !(readl_relaxed(REG_CLKOUTSEL) & 1);
+	writel_relaxed(s->src_sel, sel_reg[next_bank]);
+	writel_relaxed(s->src_div, div_reg[next_bank]);
+	writel_relaxed(next_bank, REG_CLKOUTSEL);
+
+	/* Wait for switch to complete. */
+	mb();
+	udelay(1);
+}
+
+/* Update the bus bandwidth request. */
+static void set_bus_bw(unsigned int bw)
+{
+	int ret;
+
+	/* Bounds check. */
+	if (bw >= ARRAY_SIZE(bw_level_tbl)) {
+		pr_err("invalid bandwidth request (%d)\n", bw);
+		return;
+	}
+
+	/* Update bandwidth if request has changed. This may sleep. */
+	ret = msm_bus_scale_client_update_request(bus_perf_client, bw);
+	if (ret)
+		pr_err("bandwidth request failed (%d)\n", ret);
+
+	return;
+}
+
+/* Apply any per-cpu voltage increases. */
+static int increase_vdd(unsigned int vdd_cpu, unsigned int vdd_mem)
+{
+	int rc = 0;
+
+	/*
+	 * Increase vdd_mem active-set before vdd_cpu.
+	 * vdd_mem should be >= vdd_cpu.
+	 */
+	rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8018_L9, RPM_VREG_VOTER1,
+				  vdd_mem, MAX_VDD_MEM, 0);
+	if (rc) {
+		pr_err("vdd_mem increase failed (%d)\n", rc);
+		return rc;
+	}
+
+	rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8018_S1, RPM_VREG_VOTER1,
+				  vdd_cpu, MAX_VDD_CPU, 0);
+	if (rc)
+		pr_err("vdd_cpu increase failed (%d)\n", rc);
+
+	return rc;
+}
+
+/* Apply any per-cpu voltage decreases. */
+static void decrease_vdd(unsigned int vdd_cpu, unsigned int vdd_mem)
+{
+	int ret;
+
+	/* Update CPU voltage. */
+	ret = rpm_vreg_set_voltage(RPM_VREG_ID_PM8018_S1, RPM_VREG_VOTER1,
+				  vdd_cpu, MAX_VDD_CPU, 0);
+	if (ret) {
+		pr_err("vdd_cpu decrease failed (%d)\n", ret);
+		return;
+	}
+
+	/*
+	 * Decrease vdd_mem active-set after vdd_cpu.
+	 * vdd_mem should be >= vdd_cpu.
+	 */
+	ret = rpm_vreg_set_voltage(RPM_VREG_ID_PM8018_L9, RPM_VREG_VOTER1,
+				  vdd_mem, MAX_VDD_MEM, 0);
+	if (ret)
+		pr_err("vdd_mem decrease failed (%d)\n", ret);
+}
+
+static int acpuclk_9615_set_rate(int cpu, unsigned long rate,
+				 enum setrate_reason reason)
+{
+	struct clkctl_acpu_speed *tgt_s, *strt_s;
+	int rc = 0;
+
+	if (reason == SETRATE_CPUFREQ)
+		mutex_lock(&drv_state.lock);
+
+	strt_s = drv_state.current_speed;
+
+	/* Return early if rate didn't change. */
+	if (rate == strt_s->khz)
+		goto out;
+
+	/* Find target frequency. */
+	for (tgt_s = acpu_freq_tbl; tgt_s->khz != 0; tgt_s++)
+		if (tgt_s->khz == rate)
+			break;
+	if (tgt_s->khz == 0) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	/* Increase VDD levels if needed. */
+	if ((reason == SETRATE_CPUFREQ || reason == SETRATE_INIT)
+			&& (tgt_s->khz > strt_s->khz)) {
+		rc = increase_vdd(tgt_s->vdd_cpu, tgt_s->vdd_mem);
+		if (rc)
+			goto out;
+	}
+
+	pr_debug("Switching from CPU rate %u KHz -> %u KHz\n",
+		strt_s->khz, tgt_s->khz);
+
+	/* Switch CPU speed. */
+	clk_enable(clocks[tgt_s->src].clk);
+	select_clk_source_div(tgt_s);
+	clk_disable(clocks[strt_s->src].clk);
+
+	drv_state.current_speed = tgt_s;
+	pr_debug("CPU speed change complete\n");
+
+	/* Nothing else to do for SWFI or power-collapse. */
+	if (reason == SETRATE_SWFI || reason == SETRATE_PC)
+		goto out;
+
+	/* Update bus bandwith request. */
+	set_bus_bw(tgt_s->bw_level);
+
+	/* Drop VDD levels if we can. */
+	if (tgt_s->khz < strt_s->khz)
+		decrease_vdd(tgt_s->vdd_cpu, tgt_s->vdd_mem);
+
+out:
+	if (reason == SETRATE_CPUFREQ)
+		mutex_unlock(&drv_state.lock);
+	return rc;
+}
+
+static unsigned long acpuclk_9615_get_rate(int cpu)
+{
+	return drv_state.current_speed->khz;
+}
+
+#ifdef CONFIG_CPU_FREQ_MSM
+static struct cpufreq_frequency_table freq_table[30];
+
+static void __init cpufreq_table_init(void)
+{
+	int i, freq_cnt = 0;
+
+	/* Construct the freq_table tables from acpu_freq_tbl. */
+	for (i = 0; acpu_freq_tbl[i].khz != 0
+			&& freq_cnt < ARRAY_SIZE(freq_table); i++) {
+		if (acpu_freq_tbl[i].use_for_scaling) {
+			freq_table[freq_cnt].index = freq_cnt;
+			freq_table[freq_cnt].frequency
+				= acpu_freq_tbl[i].khz;
+			freq_cnt++;
+		}
+	}
+	/* freq_table not big enough to store all usable freqs. */
+	BUG_ON(acpu_freq_tbl[i].khz != 0);
+
+	freq_table[freq_cnt].index = freq_cnt;
+	freq_table[freq_cnt].frequency = CPUFREQ_TABLE_END;
+
+	pr_info("CPU: %d scaling frequencies supported.\n", freq_cnt);
+
+	/* Register table with CPUFreq. */
+	cpufreq_frequency_table_get_attr(freq_table, smp_processor_id());
+}
+#else
+static void __init cpufreq_table_init(void) {}
+#endif
+
+static struct acpuclk_data acpuclk_9615_data = {
+	.set_rate = acpuclk_9615_set_rate,
+	.get_rate = acpuclk_9615_get_rate,
+	.power_collapse_khz = 19200,
+	.wait_for_irq_khz = 19200,
+};
+
+static int __init acpuclk_9615_init(struct acpuclk_soc_data *soc_data)
+{
+	unsigned long max_cpu_khz = 0;
+	int i;
+
+	mutex_init(&drv_state.lock);
+
+	bus_perf_client = msm_bus_scale_register_client(&bus_client_pdata);
+	if (!bus_perf_client) {
+		pr_err("Unable to register bus client\n");
+		BUG();
+	}
+
+	for (i = 0; i < NUM_SRC; i++) {
+		if (clocks[i].name) {
+			clocks[i].clk = clk_get_sys("acpu", clocks[i].name);
+			BUG_ON(IS_ERR(clocks[i].clk));
+			/*
+			 * Prepare the PLLs because we enable/disable them
+			 * in atomic context during power collapse/restore.
+			 */
+			BUG_ON(clk_prepare(clocks[i].clk));
+		}
+	}
+
+	/* Determine the rate of PLL9 and fixup tables accordingly */
+	if (clk_get_rate(clocks[SRC_PLL9].clk) == 550000000) {
+		for (i = 0; i < ARRAY_SIZE(acpu_freq_tbl); i++)
+			if (acpu_freq_tbl[i].src == SRC_PLL9) {
+				acpu_freq_tbl[i].khz = 550000;
+				acpu_freq_tbl[i].bw_level = 5;
+			}
+	}
+
+	/* Improve boot time by ramping up CPU immediately. */
+	for (i = 0; acpu_freq_tbl[i].khz != 0; i++)
+		max_cpu_khz = acpu_freq_tbl[i].khz;
+	acpuclk_9615_set_rate(smp_processor_id(), max_cpu_khz, SETRATE_INIT);
+
+	acpuclk_register(&acpuclk_9615_data);
+	cpufreq_table_init();
+
+	return 0;
+}
+
+struct acpuclk_soc_data acpuclk_9615_soc_data __initdata = {
+	.init = acpuclk_9615_init,
+};
diff --git a/arch/arm/mach-msm/acpuclock-arm11.c b/arch/arm/mach-msm/acpuclock-arm11.c
index 805d4ee..6f900d3 100644
--- a/arch/arm/mach-msm/acpuclock-arm11.c
+++ b/arch/arm/mach-msm/acpuclock-arm11.c
@@ -17,6 +17,7 @@
  *
  */
 
+#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/list.h>
@@ -29,8 +30,8 @@
 #include <linux/io.h>
 #include <mach/board.h>
 #include <mach/msm_iomap.h>
+#include <mach/proc_comm.h>
 
-#include "proc_comm.h"
 #include "acpuclock.h"
 
 
@@ -97,7 +98,7 @@
 
 /*
  * ACPU speed table. Complete table is shown but certain speeds are commented
- * out to optimized speed switching. Initialize loops_per_jiffy to 0.
+ * out to optimized speed switching. Initalize loops_per_jiffy to 0.
  *
  * Table stepping up/down is optimized for 256mhz jumps while staying on the
  * same PLL.
@@ -493,7 +494,7 @@
  * Clock driver initialization
  *---------------------------------------------------------------------------*/
 
-/* Initialize the lpj field in the acpu_freq_tbl. */
+/* Initalize the lpj field in the acpu_freq_tbl. */
 static void __init lpj_init(void)
 {
 	int i;
diff --git a/arch/arm/mach-msm/acpuclock-copper.c b/arch/arm/mach-msm/acpuclock-copper.c
new file mode 100644
index 0000000..f0da74c
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock-copper.c
@@ -0,0 +1,211 @@
+/*
+ * 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <mach/rpm-regulator.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_bus.h>
+#include <mach/socinfo.h>
+
+#include "acpuclock.h"
+#include "acpuclock-krait.h"
+
+/* Corner type vreg VDD values */
+#define LVL_NONE	RPM_VREG_CORNER_NONE
+#define LVL_LOW		RPM_VREG_CORNER_LOW
+#define LVL_NOM		RPM_VREG_CORNER_NOMINAL
+#define LVL_HIGH	RPM_VREG_CORNER_HIGH
+
+static struct hfpll_data hfpll_data_cpu = {
+	.mode_offset = 0x00,
+	.l_offset = 0x04,
+	.m_offset = 0x08,
+	.n_offset = 0x0C,
+	.config_offset = 0x14,
+	/* TODO: Verify magic number for copper when available. */
+	.config_val = 0x7845C665,
+	.low_vdd_l_max = 52,
+	.vdd[HFPLL_VDD_NONE] = 0,
+	.vdd[HFPLL_VDD_LOW]  = 810000,
+	.vdd[HFPLL_VDD_NOM]  = 900000,
+};
+
+static struct hfpll_data hfpll_data_l2 = {
+	.mode_offset = 0x00,
+	.l_offset = 0x04,
+	.m_offset = 0x08,
+	.n_offset = 0x0C,
+	.config_offset = 0x14,
+	/* TODO: Verify magic number for copper when available. */
+	.config_val = 0x7845C665,
+	.low_vdd_l_max = 52,
+	.vdd[HFPLL_VDD_NONE] = LVL_NONE,
+	.vdd[HFPLL_VDD_LOW]  = LVL_LOW,
+	.vdd[HFPLL_VDD_NOM]  = LVL_NOM,
+};
+
+static struct scalable scalable[] = {
+	[CPU0] = {
+		.hfpll_phys_base = 0xF908A000,
+		.hfpll_data = &hfpll_data_cpu,
+		.l2cpmr_iaddr = 0x4501,
+		.vreg[VREG_CORE] = { "krait0",     1050000, 3200000 },
+		.vreg[VREG_MEM]  = { "krait0_mem", 1050000, 0,
+				     RPM_VREG_VOTER1,
+				     RPM_VREG_ID_PM8941_S1 },
+		.vreg[VREG_DIG]  = { "krait0_dig", 1050000, 0,
+				     RPM_VREG_VOTER1,
+				     RPM_VREG_ID_PM8941_S2 },
+		.vreg[VREG_HFPLL_A] = { "hfpll", 1800000, 0,
+				     RPM_VREG_VOTER1,
+				     RPM_VREG_ID_PM8941_L12 },
+	},
+	[CPU1] = {
+		.hfpll_phys_base = 0xF909A000,
+		.hfpll_data = &hfpll_data_cpu,
+		.l2cpmr_iaddr = 0x5501,
+		.vreg[VREG_CORE] = { "krait1",     1050000, 3200000 },
+		.vreg[VREG_MEM]  = { "krait1_mem", 1050000, 0,
+				     RPM_VREG_VOTER2,
+				     RPM_VREG_ID_PM8941_S1 },
+		.vreg[VREG_DIG]  = { "krait1_dig", 1050000, 0,
+				     RPM_VREG_VOTER2,
+				     RPM_VREG_ID_PM8941_S2 },
+		.vreg[VREG_HFPLL_A] = { "hfpll", 1800000, 0,
+				     RPM_VREG_VOTER2,
+				     RPM_VREG_ID_PM8941_L12 },
+	},
+	[CPU2] = {
+		.hfpll_phys_base = 0xF90AA000,
+		.hfpll_data = &hfpll_data_cpu,
+		.l2cpmr_iaddr = 0x6501,
+		.vreg[VREG_CORE] = { "krait2",     1050000, 3200000 },
+		.vreg[VREG_MEM]  = { "krait2_mem", 1050000, 0,
+				     RPM_VREG_VOTER4,
+				     RPM_VREG_ID_PM8921_S1 },
+		.vreg[VREG_DIG]  = { "krait2_dig", 1050000, 0,
+				     RPM_VREG_VOTER4,
+				     RPM_VREG_ID_PM8921_S2 },
+		.vreg[VREG_HFPLL_A] = { "hfpll", 1800000, 0,
+				     RPM_VREG_VOTER4,
+				     RPM_VREG_ID_PM8941_L12 },
+	},
+	[CPU3] = {
+		.hfpll_phys_base = 0xF90BA000,
+		.hfpll_data = &hfpll_data_cpu,
+		.l2cpmr_iaddr = 0x7501,
+		.vreg[VREG_CORE] = { "krait3",     1050000, 3200000 },
+		.vreg[VREG_MEM]  = { "krait3_mem", 1050000, 0,
+				     RPM_VREG_VOTER5,
+				     RPM_VREG_ID_PM8941_S1 },
+		.vreg[VREG_DIG]  = { "krait3_dig", 1050000, 0,
+				     RPM_VREG_VOTER5,
+				     RPM_VREG_ID_PM8941_S2 },
+		.vreg[VREG_HFPLL_A] = { "hfpll", 1800000, 0,
+				     RPM_VREG_VOTER5,
+				     RPM_VREG_ID_PM8941_L12 },
+	},
+	[L2] = {
+		.hfpll_phys_base = 0xF9016000,
+		.hfpll_data = &hfpll_data_l2,
+		.l2cpmr_iaddr = 0x0500,
+		.vreg[VREG_HFPLL_A] = { "hfpll", 1800000, 0,
+				     RPM_VREG_VOTER6,
+				     RPM_VREG_ID_PM8941_L12 },
+	},
+};
+
+static struct msm_bus_paths bw_level_tbl[] = {
+	[0] =  BW_MBPS(400), /* At least  50 MHz on bus. */
+	[1] =  BW_MBPS(800), /* At least 100 MHz on bus. */
+	[2] = BW_MBPS(1334), /* At least 167 MHz on bus. */
+	[3] = BW_MBPS(2666), /* At least 200 MHz on bus. */
+	[4] = BW_MBPS(3200), /* At least 333 MHz on bus. */
+};
+
+static struct msm_bus_scale_pdata bus_scale_data = {
+	.usecase = bw_level_tbl,
+	.num_usecases = ARRAY_SIZE(bw_level_tbl),
+	.active_only = 1,
+	.name = "acpuclk-copper",
+};
+
+#define L2(x) (&l2_freq_tbl[(x)])
+static struct l2_level l2_freq_tbl[] = {
+	[0]  = { {STBY_KHZ, QSB,   0, 0,   0 }, LVL_NOM, 1050000, 0 },
+	[1]  = { {  300000, PLL_0, 0, 2,   0 }, LVL_NOM, 1050000, 2 },
+	[2]  = { {  384000, HFPLL, 2, 0,  40 }, LVL_NOM, 1050000, 2 },
+	[3]  = { {  460800, HFPLL, 2, 0,  48 }, LVL_NOM, 1050000, 2 },
+	[4]  = { {  537600, HFPLL, 1, 0,  28 }, LVL_NOM, 1050000, 2 },
+	[5]  = { {  576000, HFPLL, 1, 0,  30 }, LVL_NOM, 1050000, 3 },
+	[6]  = { {  652800, HFPLL, 1, 0,  34 }, LVL_NOM, 1050000, 3 },
+	[7]  = { {  729600, HFPLL, 1, 0,  38 }, LVL_NOM, 1050000, 3 },
+	[8]  = { {  806400, HFPLL, 1, 0,  42 }, LVL_NOM, 1050000, 3 },
+	[9]  = { {  883200, HFPLL, 1, 0,  46 }, LVL_NOM, 1050000, 4 },
+	[10] = { {  960000, HFPLL, 1, 0,  50 }, LVL_NOM, 1050000, 4 },
+	[11] = { { 1036800, HFPLL, 1, 0,  54 }, LVL_NOM, 1050000, 4 },
+};
+
+static struct acpu_level acpu_freq_tbl[] = {
+	{ 0, {STBY_KHZ, QSB,   0, 0,   0 }, L2(0),  1050000 },
+	{ 1, {  300000, PLL_0, 0, 2,   0 }, L2(1),  1050000 },
+	{ 1, {  384000, HFPLL, 2, 0,  40 }, L2(2),  1050000 },
+	{ 1, {  460800, HFPLL, 2, 0,  48 }, L2(3),  1050000 },
+	{ 1, {  537600, HFPLL, 1, 0,  28 }, L2(4),  1050000 },
+	{ 1, {  576000, HFPLL, 1, 0,  30 }, L2(5),  1050000 },
+	{ 1, {  652800, HFPLL, 1, 0,  34 }, L2(6),  1050000 },
+	{ 1, {  729600, HFPLL, 1, 0,  38 }, L2(7),  1050000 },
+	{ 1, {  806400, HFPLL, 1, 0,  42 }, L2(8),  1050000 },
+	{ 1, {  883200, HFPLL, 1, 0,  46 }, L2(9),  1050000 },
+	{ 1, {  960000, HFPLL, 1, 0,  50 }, L2(10), 1050000 },
+	{ 1, { 1036800, HFPLL, 1, 0,  54 }, L2(11), 1050000 },
+	{ 0, { 0 } }
+};
+
+static struct acpuclk_krait_params acpuclk_copper_params = {
+	.scalable = scalable,
+	.pvs_acpu_freq_tbl[PVS_SLOW] = acpu_freq_tbl,
+	.pvs_acpu_freq_tbl[PVS_NOMINAL] = acpu_freq_tbl,
+	.pvs_acpu_freq_tbl[PVS_FAST] = acpu_freq_tbl,
+	.l2_freq_tbl = l2_freq_tbl,
+	.l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl),
+	.bus_scale_data = &bus_scale_data,
+	.qfprom_phys_base = 0xFC4A8000,
+};
+
+static int __init acpuclk_copper_probe(struct platform_device *pdev)
+{
+	return acpuclk_krait_init(&pdev->dev, &acpuclk_copper_params);
+}
+
+static struct of_device_id acpuclk_copper_match_table[] = {
+	{ .compatible = "qcom,acpuclk-copper" },
+	{}
+};
+
+static struct platform_driver acpuclk_copper_driver = {
+	.driver = {
+		.name = "acpuclk-copper",
+		.of_match_table = acpuclk_copper_match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init acpuclk_8960_init(void)
+{
+	return platform_driver_probe(&acpuclk_copper_driver,
+				     acpuclk_copper_probe);
+}
+device_initcall(acpuclk_8960_init);
diff --git a/arch/arm/mach-msm/acpuclock-fsm9xxx.c b/arch/arm/mach-msm/acpuclock-fsm9xxx.c
new file mode 100644
index 0000000..3cdc58d
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock-fsm9xxx.c
@@ -0,0 +1,52 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <mach/board.h>
+
+#include "acpuclock.h"
+
+/* Registers */
+#define PLL1_CTL_ADDR		(MSM_CLK_CTL_BASE + 0x604)
+
+static unsigned long acpuclk_9xxx_get_rate(int cpu)
+{
+	unsigned int pll1_ctl;
+	unsigned int pll1_l, pll1_div2;
+	unsigned int pll1_khz;
+
+	pll1_ctl = readl_relaxed(PLL1_CTL_ADDR);
+	pll1_l = ((pll1_ctl >> 3) & 0x3f) * 2;
+	pll1_div2 = pll1_ctl & 0x20000;
+	pll1_khz = 19200 * pll1_l;
+	if (pll1_div2)
+		pll1_khz >>= 1;
+
+	return pll1_khz;
+}
+
+static struct acpuclk_data acpuclk_9xxx_data = {
+	.get_rate = acpuclk_9xxx_get_rate,
+};
+
+static int __init acpuclk_9xxx_init(struct acpuclk_soc_data *soc_data)
+{
+	acpuclk_register(&acpuclk_9xxx_data);
+	pr_info("ACPU running at %lu KHz\n", acpuclk_get_rate(0));
+	return 0;
+}
+
+struct acpuclk_soc_data acpuclk_9xxx_soc_data __initdata = {
+	.init = acpuclk_9xxx_init,
+};
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
new file mode 100644
index 0000000..5682ac3
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock-krait.c
@@ -0,0 +1,784 @@
+/*
+ * 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
+ * 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/cpufreq.h>
+#include <linux/cpu.h>
+#include <linux/regulator/consumer.h>
+
+#include <asm/mach-types.h>
+#include <asm/cpu.h>
+
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+#include <mach/socinfo.h>
+#include <mach/msm-krait-l2-accessors.h>
+#include <mach/rpm-regulator.h>
+#include <mach/msm_bus.h>
+
+#include "acpuclock.h"
+#include "acpuclock-krait.h"
+
+/* MUX source selects. */
+#define PRI_SRC_SEL_SEC_SRC	0
+#define PRI_SRC_SEL_HFPLL	1
+#define PRI_SRC_SEL_HFPLL_DIV2	2
+#define SEC_SRC_SEL_QSB		0
+#define SEC_SRC_SEL_L2PLL	1
+#define SEC_SRC_SEL_AUX		2
+
+/* PTE EFUSE register offset. */
+#define PTE_EFUSE		0xC0
+
+static DEFINE_MUTEX(driver_lock);
+static DEFINE_SPINLOCK(l2_lock);
+
+static struct drv_data {
+	const struct acpu_level *acpu_freq_tbl;
+	const struct l2_level *l2_freq_tbl;
+	struct scalable *scalable;
+	u32 bus_perf_client;
+	struct device *dev;
+} drv;
+
+static unsigned long acpuclk_krait_get_rate(int cpu)
+{
+	return drv.scalable[cpu].cur_speed->khz;
+}
+
+/* Select a source on the primary MUX. */
+static void set_pri_clk_src(struct scalable *sc, u32 pri_src_sel)
+{
+	u32 regval;
+
+	regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
+	regval &= ~0x3;
+	regval |= (pri_src_sel & 0x3);
+	set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
+	/* Wait for switch to complete. */
+	mb();
+	udelay(1);
+}
+
+/* Select a source on the secondary MUX. */
+static void set_sec_clk_src(struct scalable *sc, u32 sec_src_sel)
+{
+	u32 regval;
+
+	regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
+	regval &= ~(0x3 << 2);
+	regval |= ((sec_src_sel & 0x3) << 2);
+	set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
+	/* Wait for switch to complete. */
+	mb();
+	udelay(1);
+}
+
+/* Enable an already-configured HFPLL. */
+static void hfpll_enable(struct scalable *sc, bool skip_regulators)
+{
+	int rc;
+
+	if (!skip_regulators) {
+		/* Enable regulators required by the HFPLL. */
+		if (sc->vreg[VREG_HFPLL_A].rpm_vreg_id) {
+			rc = rpm_vreg_set_voltage(
+				sc->vreg[VREG_HFPLL_A].rpm_vreg_id,
+				sc->vreg[VREG_HFPLL_A].rpm_vreg_voter,
+				sc->vreg[VREG_HFPLL_A].cur_vdd,
+				sc->vreg[VREG_HFPLL_A].max_vdd, 0);
+			if (rc)
+				dev_err(drv.dev,
+					"%s regulator enable failed (%d)\n",
+					sc->vreg[VREG_HFPLL_A].name, rc);
+		}
+		if (sc->vreg[VREG_HFPLL_B].rpm_vreg_id) {
+			rc = rpm_vreg_set_voltage(
+				sc->vreg[VREG_HFPLL_B].rpm_vreg_id,
+				sc->vreg[VREG_HFPLL_B].rpm_vreg_voter,
+				sc->vreg[VREG_HFPLL_B].cur_vdd,
+				sc->vreg[VREG_HFPLL_B].max_vdd, 0);
+			if (rc)
+				dev_err(drv.dev,
+					"%s regulator enable failed (%d)\n",
+					sc->vreg[VREG_HFPLL_B].name, rc);
+		}
+	}
+
+	/* Disable PLL bypass mode. */
+	writel_relaxed(0x2, sc->hfpll_base + sc->hfpll_data->mode_offset);
+
+	/*
+	 * H/W requires a 5us delay between disabling the bypass and
+	 * de-asserting the reset. Delay 10us just to be safe.
+	 */
+	mb();
+	udelay(10);
+
+	/* De-assert active-low PLL reset. */
+	writel_relaxed(0x6, sc->hfpll_base + sc->hfpll_data->mode_offset);
+
+	/* Wait for PLL to lock. */
+	mb();
+	udelay(60);
+
+	/* Enable PLL output. */
+	writel_relaxed(0x7, sc->hfpll_base + sc->hfpll_data->mode_offset);
+}
+
+/* Disable a HFPLL for power-savings or while it's being reprogrammed. */
+static void hfpll_disable(struct scalable *sc, bool skip_regulators)
+{
+	int rc;
+
+	/*
+	 * Disable the PLL output, disable test mode, enable the bypass mode,
+	 * and assert the reset.
+	 */
+	writel_relaxed(0, sc->hfpll_base + sc->hfpll_data->mode_offset);
+
+	if (!skip_regulators) {
+		/* Remove voltage votes required by the HFPLL. */
+		if (sc->vreg[VREG_HFPLL_B].rpm_vreg_id) {
+			rc = rpm_vreg_set_voltage(
+				sc->vreg[VREG_HFPLL_B].rpm_vreg_id,
+				sc->vreg[VREG_HFPLL_B].rpm_vreg_voter,
+				0, 0, 0);
+			if (rc)
+				dev_err(drv.dev,
+					"%s regulator enable failed (%d)\n",
+					sc->vreg[VREG_HFPLL_B].name, rc);
+		}
+		if (sc->vreg[VREG_HFPLL_A].rpm_vreg_id) {
+			rc = rpm_vreg_set_voltage(
+				sc->vreg[VREG_HFPLL_A].rpm_vreg_id,
+				sc->vreg[VREG_HFPLL_A].rpm_vreg_voter,
+				0, 0, 0);
+			if (rc)
+				dev_err(drv.dev,
+					"%s regulator enable failed (%d)\n",
+					sc->vreg[VREG_HFPLL_A].name, rc);
+		}
+	}
+}
+
+/* Program the HFPLL rate. Assumes HFPLL is already disabled. */
+static void hfpll_set_rate(struct scalable *sc, const struct core_speed *tgt_s)
+{
+	writel_relaxed(tgt_s->pll_l_val,
+		sc->hfpll_base + sc->hfpll_data->l_offset);
+}
+
+/* Return the L2 speed that should be applied. */
+static const struct l2_level *compute_l2_level(struct scalable *sc,
+					       const struct l2_level *vote_l)
+{
+	const struct l2_level *new_l;
+	int cpu;
+
+	/* Find max L2 speed vote. */
+	sc->l2_vote = vote_l;
+	new_l = drv.l2_freq_tbl;
+	for_each_present_cpu(cpu)
+		new_l = max(new_l, drv.scalable[cpu].l2_vote);
+
+	return new_l;
+}
+
+/* Update the bus bandwidth request. */
+static void set_bus_bw(unsigned int bw)
+{
+	int ret;
+
+	/* Update bandwidth if request has changed. This may sleep. */
+	ret = msm_bus_scale_client_update_request(drv.bus_perf_client, bw);
+	if (ret)
+		dev_err(drv.dev, "bandwidth request failed (%d)\n", ret);
+}
+
+/* Set the CPU or L2 clock speed. */
+static void set_speed(struct scalable *sc, const struct core_speed *tgt_s)
+{
+	const struct core_speed *strt_s = sc->cur_speed;
+
+	if (strt_s->src == HFPLL && tgt_s->src == HFPLL) {
+		/*
+		 * Move to an always-on source running at a frequency
+		 * that does not require an elevated CPU voltage.
+		 */
+		set_sec_clk_src(sc, SEC_SRC_SEL_AUX);
+		set_pri_clk_src(sc, PRI_SRC_SEL_SEC_SRC);
+
+		/* Re-program HFPLL. */
+		hfpll_disable(sc, 1);
+		hfpll_set_rate(sc, tgt_s);
+		hfpll_enable(sc, 1);
+
+		/* Move to HFPLL. */
+		set_pri_clk_src(sc, tgt_s->pri_src_sel);
+	} else if (strt_s->src == HFPLL && tgt_s->src != HFPLL) {
+		set_sec_clk_src(sc, tgt_s->sec_src_sel);
+		set_pri_clk_src(sc, tgt_s->pri_src_sel);
+		hfpll_disable(sc, 0);
+	} else if (strt_s->src != HFPLL && tgt_s->src == HFPLL) {
+		hfpll_set_rate(sc, tgt_s);
+		hfpll_enable(sc, 0);
+		set_pri_clk_src(sc, tgt_s->pri_src_sel);
+	} else {
+		set_sec_clk_src(sc, tgt_s->sec_src_sel);
+	}
+
+	sc->cur_speed = tgt_s;
+}
+
+/* Apply any per-cpu voltage increases. */
+static int increase_vdd(int cpu, int vdd_core, int vdd_mem, int vdd_dig,
+			enum setrate_reason reason)
+{
+	struct scalable *sc = &drv.scalable[cpu];
+	int rc = 0;
+
+	/*
+	 * Increase vdd_mem active-set before vdd_dig.
+	 * vdd_mem should be >= vdd_dig.
+	 */
+	if (vdd_mem > sc->vreg[VREG_MEM].cur_vdd) {
+		rc = rpm_vreg_set_voltage(sc->vreg[VREG_MEM].rpm_vreg_id,
+				sc->vreg[VREG_MEM].rpm_vreg_voter, vdd_mem,
+				sc->vreg[VREG_MEM].max_vdd, 0);
+		if (rc) {
+			dev_err(drv.dev,
+				"vdd_mem (cpu%d) increase failed (%d)\n",
+				cpu, rc);
+			return rc;
+		}
+		 sc->vreg[VREG_MEM].cur_vdd = vdd_mem;
+	}
+
+	/* Increase vdd_dig active-set vote. */
+	if (vdd_dig > sc->vreg[VREG_DIG].cur_vdd) {
+		rc = rpm_vreg_set_voltage(sc->vreg[VREG_DIG].rpm_vreg_id,
+				sc->vreg[VREG_DIG].rpm_vreg_voter, vdd_dig,
+				sc->vreg[VREG_DIG].max_vdd, 0);
+		if (rc) {
+			dev_err(drv.dev,
+				"vdd_dig (cpu%d) increase failed (%d)\n",
+				cpu, rc);
+			return rc;
+		}
+		sc->vreg[VREG_DIG].cur_vdd = vdd_dig;
+	}
+
+	/*
+	 * Update per-CPU core voltage. Don't do this for the hotplug path for
+	 * which it should already be correct. Attempting to set it is bad
+	 * because we don't know what CPU we are running on at this point, but
+	 * the CPU regulator API requires we call it from the affected CPU.
+	 */
+	if (vdd_core > sc->vreg[VREG_CORE].cur_vdd
+			&& reason != SETRATE_HOTPLUG) {
+		rc = regulator_set_voltage(sc->vreg[VREG_CORE].reg, vdd_core,
+					   sc->vreg[VREG_CORE].max_vdd);
+		if (rc) {
+			dev_err(drv.dev,
+				"vdd_core (cpu%d) increase failed (%d)\n",
+				cpu, rc);
+			return rc;
+		}
+		sc->vreg[VREG_CORE].cur_vdd = vdd_core;
+	}
+
+	return rc;
+}
+
+/* Apply any per-cpu voltage decreases. */
+static void decrease_vdd(int cpu, int vdd_core, int vdd_mem, int vdd_dig,
+			enum setrate_reason reason)
+{
+	struct scalable *sc = &drv.scalable[cpu];
+	int ret;
+
+	/*
+	 * Update per-CPU core voltage. This must be called on the CPU
+	 * that's being affected. Don't do this in the hotplug remove path,
+	 * where the rail is off and we're executing on the other CPU.
+	 */
+	if (vdd_core < sc->vreg[VREG_CORE].cur_vdd
+			&& reason != SETRATE_HOTPLUG) {
+		ret = regulator_set_voltage(sc->vreg[VREG_CORE].reg, vdd_core,
+					    sc->vreg[VREG_CORE].max_vdd);
+		if (ret) {
+			dev_err(drv.dev,
+				"vdd_core (cpu%d) decrease failed (%d)\n",
+				cpu, ret);
+			return;
+		}
+		sc->vreg[VREG_CORE].cur_vdd = vdd_core;
+	}
+
+	/* Decrease vdd_dig active-set vote. */
+	if (vdd_dig < sc->vreg[VREG_DIG].cur_vdd) {
+		ret = rpm_vreg_set_voltage(sc->vreg[VREG_DIG].rpm_vreg_id,
+				sc->vreg[VREG_DIG].rpm_vreg_voter, vdd_dig,
+				sc->vreg[VREG_DIG].max_vdd, 0);
+		if (ret) {
+			dev_err(drv.dev,
+				"vdd_dig (cpu%d) decrease failed (%d)\n",
+				cpu, ret);
+			return;
+		}
+		sc->vreg[VREG_DIG].cur_vdd = vdd_dig;
+	}
+
+	/*
+	 * Decrease vdd_mem active-set after vdd_dig.
+	 * vdd_mem should be >= vdd_dig.
+	 */
+	if (vdd_mem < sc->vreg[VREG_MEM].cur_vdd) {
+		ret = rpm_vreg_set_voltage(sc->vreg[VREG_MEM].rpm_vreg_id,
+				sc->vreg[VREG_MEM].rpm_vreg_voter, vdd_mem,
+				sc->vreg[VREG_MEM].max_vdd, 0);
+		if (ret) {
+			dev_err(drv.dev,
+				"vdd_mem (cpu%d) decrease failed (%d)\n",
+				cpu, ret);
+			return;
+		}
+		 sc->vreg[VREG_MEM].cur_vdd = vdd_mem;
+	}
+}
+
+static int calculate_vdd_mem(const struct acpu_level *tgt)
+{
+	return tgt->l2_level->vdd_mem;
+}
+
+static int calculate_vdd_dig(const struct acpu_level *tgt)
+{
+	int pll_vdd_dig;
+	const int *hfpll_vdd = drv.scalable[L2].hfpll_data->vdd;
+	const u32 low_vdd_l_max = drv.scalable[L2].hfpll_data->low_vdd_l_max;
+
+	if (tgt->l2_level->speed.src != HFPLL)
+		pll_vdd_dig = hfpll_vdd[HFPLL_VDD_NONE];
+	else if (tgt->l2_level->speed.pll_l_val > low_vdd_l_max)
+		pll_vdd_dig = hfpll_vdd[HFPLL_VDD_NOM];
+	else
+		pll_vdd_dig = hfpll_vdd[HFPLL_VDD_LOW];
+
+	return max(tgt->l2_level->vdd_dig, pll_vdd_dig);
+}
+
+static int calculate_vdd_core(const struct acpu_level *tgt)
+{
+	return tgt->vdd_core;
+}
+
+/* Set the CPU's clock rate and adjust the L2 rate, voltage and BW requests. */
+static int acpuclk_krait_set_rate(int cpu, unsigned long rate,
+				  enum setrate_reason reason)
+{
+	const struct core_speed *strt_acpu_s, *tgt_acpu_s;
+	const struct l2_level *tgt_l2_l;
+	const struct acpu_level *tgt;
+	int vdd_mem, vdd_dig, vdd_core;
+	unsigned long flags;
+	int rc = 0;
+
+	if (cpu > num_possible_cpus()) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	if (reason == SETRATE_CPUFREQ || reason == SETRATE_HOTPLUG)
+		mutex_lock(&driver_lock);
+
+	strt_acpu_s = drv.scalable[cpu].cur_speed;
+
+	/* Return early if rate didn't change. */
+	if (rate == strt_acpu_s->khz)
+		goto out;
+
+	/* Find target frequency. */
+	for (tgt = drv.acpu_freq_tbl; tgt->speed.khz != 0; tgt++) {
+		if (tgt->speed.khz == rate) {
+			tgt_acpu_s = &tgt->speed;
+			break;
+		}
+	}
+	if (tgt->speed.khz == 0) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	/* Calculate voltage requirements for the current CPU. */
+	vdd_mem  = calculate_vdd_mem(tgt);
+	vdd_dig  = calculate_vdd_dig(tgt);
+	vdd_core = calculate_vdd_core(tgt);
+
+	/* Increase VDD levels if needed. */
+	if (reason == SETRATE_CPUFREQ || reason == SETRATE_HOTPLUG) {
+		rc = increase_vdd(cpu, vdd_core, vdd_mem, vdd_dig, reason);
+		if (rc)
+			goto out;
+	}
+
+	pr_debug("Switching from ACPU%d rate %lu KHz -> %lu KHz\n",
+		 cpu, strt_acpu_s->khz, tgt_acpu_s->khz);
+
+	/* Set the new CPU speed. */
+	set_speed(&drv.scalable[cpu], tgt_acpu_s);
+
+	/*
+	 * Update the L2 vote and apply the rate change. A spinlock is
+	 * necessary to ensure L2 rate is calculated and set atomically
+	 * with the CPU frequency, even if acpuclk_krait_set_rate() is
+	 * called from an atomic context and the driver_lock mutex is not
+	 * acquired.
+	 */
+	spin_lock_irqsave(&l2_lock, flags);
+	tgt_l2_l = compute_l2_level(&drv.scalable[cpu], tgt->l2_level);
+	set_speed(&drv.scalable[L2], &tgt_l2_l->speed);
+	spin_unlock_irqrestore(&l2_lock, flags);
+
+	/* Nothing else to do for power collapse or SWFI. */
+	if (reason == SETRATE_PC || reason == SETRATE_SWFI)
+		goto out;
+
+	/* Update bus bandwith request. */
+	set_bus_bw(tgt_l2_l->bw_level);
+
+	/* Drop VDD levels if we can. */
+	decrease_vdd(cpu, vdd_core, vdd_mem, vdd_dig, reason);
+
+	pr_debug("ACPU%d speed change complete\n", cpu);
+
+out:
+	if (reason == SETRATE_CPUFREQ || reason == SETRATE_HOTPLUG)
+		mutex_unlock(&driver_lock);
+	return rc;
+}
+
+/* Initialize a HFPLL at a given rate and enable it. */
+static void __init hfpll_init(struct scalable *sc,
+			      const struct core_speed *tgt_s)
+{
+	pr_debug("Initializing HFPLL%d\n", sc - drv.scalable);
+
+	/* Disable the PLL for re-programming. */
+	hfpll_disable(sc, 1);
+
+	/* Configure PLL parameters for integer mode. */
+	writel_relaxed(sc->hfpll_data->config_val,
+		       sc->hfpll_base + sc->hfpll_data->config_offset);
+	writel_relaxed(0, sc->hfpll_base + sc->hfpll_data->m_offset);
+	writel_relaxed(1, sc->hfpll_base + sc->hfpll_data->n_offset);
+
+	/* Set an initial rate and enable the PLL. */
+	hfpll_set_rate(sc, tgt_s);
+	hfpll_enable(sc, 0);
+}
+
+/* Voltage regulator initialization. */
+static void __init regulator_init(const struct acpu_level *lvl)
+{
+	int cpu, ret;
+	struct scalable *sc;
+	int vdd_mem, vdd_dig, vdd_core;
+
+	vdd_mem = calculate_vdd_mem(lvl);
+	vdd_dig = calculate_vdd_dig(lvl);
+
+	for_each_possible_cpu(cpu) {
+		sc = &drv.scalable[cpu];
+
+		/* Set initial vdd_mem vote. */
+		ret = rpm_vreg_set_voltage(sc->vreg[VREG_MEM].rpm_vreg_id,
+				sc->vreg[VREG_MEM].rpm_vreg_voter, vdd_mem,
+				sc->vreg[VREG_MEM].max_vdd, 0);
+		if (ret) {
+			dev_err(drv.dev, "%s initialization failed (%d)\n",
+				sc->vreg[VREG_MEM].name, ret);
+			BUG();
+		}
+		sc->vreg[VREG_MEM].cur_vdd  = vdd_mem;
+
+		/* Set initial vdd_dig vote. */
+		ret = rpm_vreg_set_voltage(sc->vreg[VREG_DIG].rpm_vreg_id,
+				sc->vreg[VREG_DIG].rpm_vreg_voter, vdd_dig,
+				sc->vreg[VREG_DIG].max_vdd, 0);
+		if (ret) {
+			dev_err(drv.dev, "%s initialization failed (%d)\n",
+				sc->vreg[VREG_DIG].name, ret);
+			BUG();
+		}
+		sc->vreg[VREG_DIG].cur_vdd  = vdd_dig;
+
+		/* Setup Krait CPU regulators and initial core voltage. */
+		sc->vreg[VREG_CORE].reg = regulator_get(NULL,
+					  sc->vreg[VREG_CORE].name);
+		if (IS_ERR(sc->vreg[VREG_CORE].reg)) {
+			dev_err(drv.dev, "regulator_get(%s) failed (%ld)\n",
+				sc->vreg[VREG_CORE].name,
+				PTR_ERR(sc->vreg[VREG_CORE].reg));
+			BUG();
+		}
+		vdd_core = calculate_vdd_core(lvl);
+		ret = regulator_set_voltage(sc->vreg[VREG_CORE].reg, vdd_core,
+					    sc->vreg[VREG_CORE].max_vdd);
+		if (ret) {
+			dev_err(drv.dev, "regulator_set_voltage(%s) (%d)\n",
+				sc->vreg[VREG_CORE].name, ret);
+			BUG();
+		}
+		sc->vreg[VREG_CORE].cur_vdd = vdd_core;
+		ret = regulator_set_optimum_mode(sc->vreg[VREG_CORE].reg,
+						 sc->vreg[VREG_CORE].peak_ua);
+		if (ret < 0) {
+			dev_err(drv.dev, "regulator_set_optimum_mode(%s) failed"
+				" (%d)\n", sc->vreg[VREG_CORE].name, ret);
+			BUG();
+		}
+		ret = regulator_enable(sc->vreg[VREG_CORE].reg);
+		if (ret) {
+			dev_err(drv.dev, "regulator_enable(%s) failed (%d)\n",
+				sc->vreg[VREG_CORE].name, ret);
+			BUG();
+		}
+	}
+}
+
+/* Set initial rate for a given core. */
+static void __init init_clock_sources(struct scalable *sc,
+				      const struct core_speed *tgt_s)
+{
+	u32 regval;
+
+	/* Program AUX source input to the secondary MUX. */
+	if (sc->aux_clk_sel_addr)
+		writel_relaxed(sc->aux_clk_sel, sc->aux_clk_sel_addr);
+
+	/* Switch away from the HFPLL while it's re-initialized. */
+	set_sec_clk_src(sc, SEC_SRC_SEL_AUX);
+	set_pri_clk_src(sc, PRI_SRC_SEL_SEC_SRC);
+	hfpll_init(sc, tgt_s);
+
+	/* Set PRI_SRC_SEL_HFPLL_DIV2 divider to div-2. */
+	regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
+	regval &= ~(0x3 << 6);
+	set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
+
+	/* Switch to the target clock source. */
+	set_sec_clk_src(sc, tgt_s->sec_src_sel);
+	set_pri_clk_src(sc, tgt_s->pri_src_sel);
+	sc->cur_speed = tgt_s;
+}
+
+static void __init per_cpu_init(int cpu, const struct acpu_level *max_level)
+{
+	drv.scalable[cpu].hfpll_base =
+		ioremap(drv.scalable[cpu].hfpll_phys_base, SZ_32);
+	BUG_ON(!drv.scalable[cpu].hfpll_base);
+
+	init_clock_sources(&drv.scalable[cpu], &max_level->speed);
+	drv.scalable[cpu].l2_vote = max_level->l2_level;
+}
+
+/* Register with bus driver. */
+static void __init bus_init(struct msm_bus_scale_pdata *bus_scale_data,
+			    unsigned int init_bw)
+{
+	int ret;
+
+	drv.bus_perf_client = msm_bus_scale_register_client(bus_scale_data);
+	if (!drv.bus_perf_client) {
+		dev_err(drv.dev, "unable to register bus client\n");
+		BUG();
+	}
+
+	ret = msm_bus_scale_client_update_request(drv.bus_perf_client, init_bw);
+	if (ret)
+		dev_err(drv.dev, "initial bandwidth req failed (%d)\n", ret);
+}
+
+#ifdef CONFIG_CPU_FREQ_MSM
+static struct cpufreq_frequency_table freq_table[NR_CPUS][35];
+
+static void __init cpufreq_table_init(void)
+{
+	int cpu;
+
+	for_each_possible_cpu(cpu) {
+		int i, freq_cnt = 0;
+		/* Construct the freq_table tables from acpu_freq_tbl. */
+		for (i = 0; drv.acpu_freq_tbl[i].speed.khz != 0
+				&& freq_cnt < ARRAY_SIZE(*freq_table); i++) {
+			if (drv.acpu_freq_tbl[i].use_for_scaling) {
+				freq_table[cpu][freq_cnt].index = freq_cnt;
+				freq_table[cpu][freq_cnt].frequency
+					= drv.acpu_freq_tbl[i].speed.khz;
+				freq_cnt++;
+			}
+		}
+		/* freq_table not big enough to store all usable freqs. */
+		BUG_ON(drv.acpu_freq_tbl[i].speed.khz != 0);
+
+		freq_table[cpu][freq_cnt].index = freq_cnt;
+		freq_table[cpu][freq_cnt].frequency = CPUFREQ_TABLE_END;
+
+		dev_info(drv.dev, "CPU%d: %d frequencies supported\n",
+			cpu, freq_cnt);
+
+		/* Register table with CPUFreq. */
+		cpufreq_frequency_table_get_attr(freq_table[cpu], cpu);
+	}
+}
+#else
+static void __init cpufreq_table_init(void) {}
+#endif
+
+#define HOT_UNPLUG_KHZ STBY_KHZ
+static int __cpuinit acpuclk_cpu_callback(struct notifier_block *nfb,
+					    unsigned long action, void *hcpu)
+{
+	static int prev_khz[NR_CPUS];
+	int rc, cpu = (int)hcpu;
+	struct scalable *sc = &drv.scalable[cpu];
+
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_DEAD:
+		prev_khz[cpu] = acpuclk_krait_get_rate(cpu);
+		/* Fall through. */
+	case CPU_UP_CANCELED:
+		acpuclk_krait_set_rate(cpu, HOT_UNPLUG_KHZ, SETRATE_HOTPLUG);
+		regulator_set_optimum_mode(sc->vreg[VREG_CORE].reg, 0);
+		break;
+	case CPU_UP_PREPARE:
+		if (WARN_ON(!prev_khz[cpu]))
+			return NOTIFY_BAD;
+		rc = regulator_set_optimum_mode(sc->vreg[VREG_CORE].reg,
+						sc->vreg[VREG_CORE].peak_ua);
+		if (rc < 0)
+			return NOTIFY_BAD;
+		acpuclk_krait_set_rate(cpu, prev_khz[cpu], SETRATE_HOTPLUG);
+		break;
+	default:
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata acpuclk_cpu_notifier = {
+	.notifier_call = acpuclk_cpu_callback,
+};
+
+static const struct acpu_level __init *select_freq_plan(
+		const struct acpu_level *const *pvs_tbl, u32 qfprom_phys)
+{
+	const struct acpu_level *l, *max_acpu_level = NULL;
+	void __iomem *qfprom_base;
+	u32 pte_efuse, pvs, tbl_idx;
+	char *pvs_names[] = { "Slow", "Nominal", "Fast", "Unknown" };
+
+	qfprom_base = ioremap(qfprom_phys, SZ_256);
+	/* Select frequency tables. */
+	if (qfprom_base) {
+		pte_efuse = readl_relaxed(qfprom_base + PTE_EFUSE);
+		pvs = (pte_efuse >> 10) & 0x7;
+		iounmap(qfprom_base);
+		if (pvs == 0x7)
+			pvs = (pte_efuse >> 13) & 0x7;
+
+		switch (pvs) {
+		case 0x0:
+		case 0x7:
+			tbl_idx = PVS_SLOW;
+			break;
+		case 0x1:
+			tbl_idx = PVS_NOMINAL;
+			break;
+		case 0x3:
+			tbl_idx = PVS_FAST;
+			break;
+		default:
+			tbl_idx = PVS_UNKNOWN;
+			break;
+		}
+	} else {
+		tbl_idx = PVS_UNKNOWN;
+		dev_err(drv.dev, "Unable to map QFPROM base\n");
+	}
+	dev_info(drv.dev, "ACPU PVS: %s\n", pvs_names[tbl_idx]);
+	if (tbl_idx == PVS_UNKNOWN) {
+		tbl_idx = PVS_SLOW;
+		dev_warn(drv.dev, "ACPU PVS: Defaulting to %s\n",
+			 pvs_names[tbl_idx]);
+	}
+	drv.acpu_freq_tbl = pvs_tbl[tbl_idx];
+
+	/* Find the max supported scaling frequency. */
+	for (l = drv.acpu_freq_tbl; l->speed.khz != 0; l++)
+		if (l->use_for_scaling)
+			max_acpu_level = l;
+	BUG_ON(!max_acpu_level);
+	dev_info(drv.dev, "Max ACPU freq: %lu KHz\n",
+		 max_acpu_level->speed.khz);
+
+	return max_acpu_level;
+}
+
+static struct acpuclk_data acpuclk_krait_data = {
+	.set_rate = acpuclk_krait_set_rate,
+	.get_rate = acpuclk_krait_get_rate,
+	.power_collapse_khz = STBY_KHZ,
+	.wait_for_irq_khz = STBY_KHZ,
+};
+
+int __init acpuclk_krait_init(struct device *dev,
+			      const struct acpuclk_krait_params *params)
+{
+	const struct acpu_level *max_acpu_level;
+	int cpu;
+
+	drv.scalable = params->scalable;
+	drv.l2_freq_tbl = params->l2_freq_tbl;
+	drv.dev = dev;
+
+	drv.scalable[L2].hfpll_base =
+		ioremap(drv.scalable[L2].hfpll_phys_base, SZ_32);
+	BUG_ON(!drv.scalable[L2].hfpll_base);
+
+	max_acpu_level = select_freq_plan(params->pvs_acpu_freq_tbl,
+					  params->qfprom_phys_base);
+	regulator_init(max_acpu_level);
+	bus_init(params->bus_scale_data, max_acpu_level->l2_level->bw_level);
+	init_clock_sources(&drv.scalable[L2], &max_acpu_level->l2_level->speed);
+	for_each_online_cpu(cpu)
+		per_cpu_init(cpu, max_acpu_level);
+
+	cpufreq_table_init();
+
+	acpuclk_register(&acpuclk_krait_data);
+	register_hotcpu_notifier(&acpuclk_cpu_notifier);
+
+	return 0;
+}
diff --git a/arch/arm/mach-msm/acpuclock-krait.h b/arch/arm/mach-msm/acpuclock-krait.h
new file mode 100644
index 0000000..fbf1f5f
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock-krait.h
@@ -0,0 +1,222 @@
+/*
+ * 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
+ * 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 __ARCH_ARM_MACH_MSM_ACPUCLOCK_KRAIT_H
+#define __ARCH_ARM_MACH_MSM_ACPUCLOCK_KRAIT_H
+
+#define STBY_KHZ		1
+
+#define BW_MBPS(_bw) \
+	{ \
+		.vectors = (struct msm_bus_vectors[]){ \
+			{\
+				.src = MSM_BUS_MASTER_AMPSS_M0, \
+				.dst = MSM_BUS_SLAVE_EBI_CH0, \
+				.ib = (_bw) * 1000000UL, \
+			}, \
+			{ \
+				.src = MSM_BUS_MASTER_AMPSS_M1, \
+				.dst = MSM_BUS_SLAVE_EBI_CH0, \
+				.ib = (_bw) * 1000000UL, \
+			}, \
+		}, \
+		.num_paths = 2, \
+	}
+
+/**
+ * src_id - Clock source IDs.
+ */
+enum src_id {
+	PLL_0 = 0,
+	HFPLL,
+	QSB,
+};
+
+/**
+ * enum pvs - IDs to distinguish between CPU frequency tables.
+ */
+enum pvs {
+	PVS_SLOW = 0,
+	PVS_NOMINAL,
+	PVS_FAST,
+	PVS_UNKNOWN,
+	NUM_PVS
+};
+
+/**
+ * enum scalables - IDs of frequency scalable hardware blocks.
+ */
+enum scalables {
+	CPU0 = 0,
+	CPU1,
+	CPU2,
+	CPU3,
+	L2,
+};
+
+
+/**
+ * enum hfpll_vdd_level - IDs of HFPLL voltage levels.
+ */
+enum hfpll_vdd_levels {
+	HFPLL_VDD_NONE,
+	HFPLL_VDD_LOW,
+	HFPLL_VDD_NOM,
+	NUM_HFPLL_VDD
+};
+
+/**
+ * enum vregs - IDs of voltage regulators.
+ */
+enum vregs {
+	VREG_CORE,
+	VREG_MEM,
+	VREG_DIG,
+	VREG_HFPLL_A,
+	VREG_HFPLL_B,
+	NUM_VREG
+};
+
+/**
+ * struct vreg - Voltage regulator data.
+ * @name: Name of requlator.
+ * @max_vdd: Limit the maximum-settable voltage.
+ * @rpm_vreg_id: ID to use with rpm_vreg_*() APIs.
+ * @reg: Regulator handle.
+ * @cur_vdd: Last-set voltage in uV.
+ * @peak_ua: Maximum current draw expected in uA.
+ */
+struct vreg {
+	const char name[15];
+	const int max_vdd;
+	const int peak_ua;
+	const int rpm_vreg_voter;
+	const int rpm_vreg_id;
+	struct regulator *reg;
+	int cur_vdd;
+};
+
+/**
+ * struct core_speed - Clock tree and configuration parameters.
+ * @khz: Clock rate in KHz.
+ * @src: Clock source ID.
+ * @pri_src_sel: Input to select on the primary MUX.
+ * @sec_src_sel: Input to select on the secondary MUX.
+ * @pll_l_val: HFPLL "L" value to be applied when an HFPLL source is selected.
+ */
+struct core_speed {
+	const unsigned long khz;
+	const int src;
+	const u32 pri_src_sel;
+	const u32 sec_src_sel;
+	const u32 pll_l_val;
+};
+
+/**
+ * struct l2_level - L2 clock rate and associated voltage and b/w requirements.
+ * @speed: L2 clock configuration.
+ * @vdd_dig: vdd_dig voltage in uV.
+ * @vdd_mem: vdd_mem voltage in uV.
+ * @bw_level: Bandwidth performance level number.
+ */
+struct l2_level {
+	const struct core_speed speed;
+	const int vdd_dig;
+	const int vdd_mem;
+	const unsigned int bw_level;
+};
+
+/**
+ * struct acpu_level - CPU clock rate and L2 rate and voltage requirements.
+ * @use_for_scaling: Flag indicating whether or not the level should be used.
+ * @speed: CPU clock configuration.
+ * @l2_level: L2 configuration to use.
+ * @vdd_core: CPU core voltage in uV.
+ */
+struct acpu_level {
+	const int use_for_scaling;
+	const struct core_speed speed;
+	const struct l2_level *l2_level;
+	const int vdd_core;
+};
+
+/**
+ * struct hfpll_data - Descriptive data of HFPLL hardware.
+ * @mode_offset: Mode register offset from base address.
+ * @l_offset: "L" value register offset from base address.
+ * @m_offset: "M" value register offset from base address.
+ * @n_offset: "N" value register offset from base address.
+ * @config_offset: Configuration register offset from base address.
+ * @config_val: Value to initialize the @config_offset register to.
+ * @vdd: voltage requirements for each VDD level.
+ */
+struct hfpll_data {
+	const u32 mode_offset;
+	const u32 l_offset;
+	const u32 m_offset;
+	const u32 n_offset;
+	const u32 config_offset;
+	const u32 config_val;
+	const u32 low_vdd_l_max;
+	const int vdd[NUM_HFPLL_VDD];
+};
+
+/**
+ * struct scalable - Register locations and state associated with a scalable HW.
+ * @hfpll_phys_base: Physical base address of HFPLL register.
+ * @hfpll_base: Virtual base address of HFPLL registers.
+ * @aux_clk_sel_addr: Virtual address of auxiliary MUX.
+ * @aux_clk_sel: Auxiliary mux input to select at boot.
+ * @l2cpmr_iaddr: Indirect address of the CPMR MUX/divider CP15 register.
+ * @hfpll_data: Descriptive data of HFPLL hardware.
+ * @cur_speed: Pointer to currently-set speed.
+ * @l2_vote: L2 performance level vote associate with the current CPU speed.
+ * @vreg: Array of voltage regulators needed by the scalable.
+ */
+struct scalable {
+	const u32 hfpll_phys_base;
+	void __iomem *hfpll_base;
+	void __iomem *aux_clk_sel_addr;
+	const u32 aux_clk_sel;
+	const u32 l2cpmr_iaddr;
+	const struct hfpll_data *hfpll_data;
+	const struct core_speed *cur_speed;
+	const struct l2_level *l2_vote;
+	struct vreg vreg[NUM_VREG];
+};
+
+/**
+ * struct acpuclk_krait_params - SoC specific driver parameters.
+ * @scalable: Array of scalables.
+ * @pvs_acpu_freq_tbl: Array of CPU frequency tables.
+ * @l2_freq_tbl: L2 frequency table.
+ * @l2_freq_tbl_size: Number of rows in @l2_freq_tbl.
+ * @qfprom_phys_base: Physical base address of QFPROM.
+ * @bus_scale_data: MSM bus driver parameters.
+ */
+struct acpuclk_krait_params {
+	struct scalable *scalable;
+	const struct acpu_level *pvs_acpu_freq_tbl[NUM_PVS];
+	const struct l2_level *l2_freq_tbl;
+	const size_t l2_freq_tbl_size;
+	const u32 qfprom_phys_base;
+	struct msm_bus_scale_pdata *bus_scale_data;
+};
+
+/**
+ * acpuclk_krait_init - Initialize the Krait CPU clock driver give SoC params.
+ */
+extern int acpuclk_krait_init(struct device *dev,
+			      const struct acpuclk_krait_params *params);
+
+#endif
diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c
new file mode 100644
index 0000000..91071c4
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock.c
@@ -0,0 +1,76 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/cpu.h>
+#include <linux/smp.h>
+#include "acpuclock.h"
+
+static struct acpuclk_data *acpuclk_data;
+
+unsigned long acpuclk_get_rate(int cpu)
+{
+	if (!acpuclk_data->get_rate)
+		return 0;
+
+	return acpuclk_data->get_rate(cpu);
+}
+
+int acpuclk_set_rate(int cpu, unsigned long rate, enum setrate_reason reason)
+{
+	if (!acpuclk_data->set_rate)
+		return 0;
+
+	return acpuclk_data->set_rate(cpu, rate, reason);
+}
+
+uint32_t acpuclk_get_switch_time(void)
+{
+	return acpuclk_data->switch_time_us;
+}
+
+unsigned long acpuclk_power_collapse(void)
+{
+	unsigned long rate = acpuclk_get_rate(smp_processor_id());
+	acpuclk_set_rate(smp_processor_id(), acpuclk_data->power_collapse_khz,
+			 SETRATE_PC);
+	return rate;
+}
+
+unsigned long acpuclk_wait_for_irq(void)
+{
+	unsigned long rate = acpuclk_get_rate(smp_processor_id());
+	acpuclk_set_rate(smp_processor_id(), acpuclk_data->wait_for_irq_khz,
+			 SETRATE_SWFI);
+	return rate;
+}
+
+void __init acpuclk_register(struct acpuclk_data *data)
+{
+	acpuclk_data = data;
+}
+
+int __init acpuclk_init(struct acpuclk_soc_data *soc_data)
+{
+	int rc;
+
+	if (!soc_data->init)
+		return -EINVAL;
+
+	rc = soc_data->init(soc_data);
+	if (rc)
+		return rc;
+
+	if (!acpuclk_data)
+		return -ENODEV;
+
+	return 0;
+}
diff --git a/arch/arm/mach-msm/acpuclock.h b/arch/arm/mach-msm/acpuclock.h
index 415de2e..c5f0ee3 100644
--- a/arch/arm/mach-msm/acpuclock.h
+++ b/arch/arm/mach-msm/acpuclock.h
@@ -1,9 +1,8 @@
-/* arch/arm/mach-msm/acpuclock.h
- *
- * MSM architecture clock driver header
+/*
+ * MSM architecture CPU clock driver header
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007 QUALCOMM Incorporated
+ * Copyright (c) 2007-2012, Code Aurora Forum. All rights reserved.
  * Author: San Mehat <san@android.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -20,13 +19,97 @@
 #ifndef __ARCH_ARM_MACH_MSM_ACPUCLOCK_H
 #define __ARCH_ARM_MACH_MSM_ACPUCLOCK_H
 
-int acpuclk_set_rate(unsigned long rate, int for_power_collapse);
-unsigned long acpuclk_get_rate(void);
-uint32_t acpuclk_get_switch_time(void);
-unsigned long acpuclk_wait_for_irq(void);
-unsigned long acpuclk_power_collapse(void);
-unsigned long acpuclk_get_wfi_rate(void);
+/**
+ * enum setrate_reason - Reasons for use with acpuclk_set_rate()
+ */
+enum setrate_reason {
+	SETRATE_CPUFREQ = 0,
+	SETRATE_SWFI,
+	SETRATE_PC,
+	SETRATE_HOTPLUG,
+	SETRATE_INIT,
+};
 
+/**
+ * struct acpuclk_soc_data - SoC data for acpuclk_init()
+ */
+struct acpuclk_soc_data {
+	unsigned long max_speed_delta_khz;
+	unsigned int max_axi_khz;
+	int (*init)(struct acpuclk_soc_data *);
+};
+
+/**
+ * struct acpuclk_data - Function pointers and data for function implementations
+ */
+struct acpuclk_data {
+	unsigned long (*get_rate)(int cpu);
+	int (*set_rate)(int cpu, unsigned long rate, enum setrate_reason);
+	uint32_t switch_time_us;
+	unsigned long power_collapse_khz;
+	unsigned long wait_for_irq_khz;
+};
+
+/**
+ * acpulock_get_rate() - Get a CPU's clock rate in KHz
+ * @cpu: CPU to query the rate of
+ */
+unsigned long acpuclk_get_rate(int cpu);
+
+/**
+ * acpuclk_set_rate() - Set a CPU's clock rate
+ * @cpu: CPU to set rate of
+ * @rate: Desired rate in KHz
+ * @setrate_reason: Reason for the rate switch
+ *
+ * Returns 0 for success.
+ */
+int acpuclk_set_rate(int cpu, unsigned long rate, enum setrate_reason);
+
+/**
+ * acpuclk_get_switch_time() - Query estimated time in us for a CPU rate switch
+ */
+uint32_t acpuclk_get_switch_time(void);
+
+/**
+ * acpuclk_power_collapse() - Prepare current CPU clocks for power-collapse
+ *
+ * Returns the previous rate of the CPU in KHz.
+ */
+unsigned long acpuclk_power_collapse(void);
+
+/**
+ * acpuclk_wait_for_irq() - Prepare current CPU clocks for SWFI
+ *
+ * Returns the previous rate of the CPU in KHz.
+ */
+unsigned long acpuclk_wait_for_irq(void);
+
+/**
+ * acpuclk_register() - Register acpuclk_data function implementations
+ * @data: acpuclock API implementations and data
+ */
+void acpuclk_register(struct acpuclk_data *data);
+
+/**
+ * acpuclk_init() - acpuclock driver initialization function
+ *
+ * Return 0 for success.
+ */
+int acpuclk_init(struct acpuclk_soc_data *);
+
+/* SoC-specific acpuclock initialization functions. */
+extern struct acpuclk_soc_data acpuclk_7x27_soc_data;
+extern struct acpuclk_soc_data acpuclk_7x27a_soc_data;
+extern struct acpuclk_soc_data acpuclk_7x27aa_soc_data;
+extern struct acpuclk_soc_data acpuclk_7x30_soc_data;
+extern struct acpuclk_soc_data acpuclk_8x50_soc_data;
+extern struct acpuclk_soc_data acpuclk_8x60_soc_data;
+extern struct acpuclk_soc_data acpuclk_8960_soc_data;
+extern struct acpuclk_soc_data acpuclk_9xxx_soc_data;
+extern struct acpuclk_soc_data acpuclk_9615_soc_data;
+extern struct acpuclk_soc_data acpuclk_8930_soc_data;
+extern struct acpuclk_soc_data acpuclk_8064_soc_data;
+extern struct acpuclk_soc_data acpuclk_8625_soc_data;
 
 #endif
-
diff --git a/arch/arm/mach-msm/arch-init-scorpion.S b/arch/arm/mach-msm/arch-init-scorpion.S
new file mode 100644
index 0000000..82a6db8
--- /dev/null
+++ b/arch/arm/mach-msm/arch-init-scorpion.S
@@ -0,0 +1,483 @@
+/*
+ * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+/* TODO:
+ * - style cleanup
+ * - do we need to do *all* of this at boot?
+ */
+
+.text		
+.code 32
+
+#define DSB .byte 0x4f, 0xf0, 0x7f, 0xf5
+#define ISB .byte 0x6f, 0xf0, 0x7f, 0xf5
+
+.equ TCSR_SPARE2,      0xA8700060
+
+SET_SA:
+	ldr r0, =TCSR_SPARE2
+	ldr r12, [r0]
+
+	/* pack bits 8,2,0 into 2,1,0 */
+	and r0, r12, #0x001
+	and r1, r12, #0x004
+	and r2, r12, #0x100
+	orr r0, r1, lsr #1
+	orr r0, r2, lsr #6
+
+	adr r1, table_l1_acc
+	mov r0, r0, lsl #2
+	ldr r3, [r1, r0]
+
+	/* write 3800XXXX to PVR0F0 */
+	orr r0, r3, #0x38000000
+	mcr p15, 0, r0, c15, c15, 0
+
+	/* write XXXX0000 to PVR2F0 */
+	mov r1, r3, lsl #16
+	mcr p15, 2, r1, c15, c15, 0
+
+	adr r1, table_l2_acc
+	and r0, r12, #0x008
+	and r2, r12, #0x002
+	orr r0, r0, r2, lsl #1
+	ldr r2, [r1, r0]
+
+	/* write to L2VR3F1 */
+	mcr p15, 3, r2, c15, c15, 1
+
+	bx lr
+
+table_l1_acc:
+	.word 0xFC00
+	.word 0xFC00
+	.word 0x7C00
+	.word 0xFC00
+	.word 0x3C00
+	.word 0x0400
+	.word 0x0C00
+	.word 0x1C00
+
+table_l2_acc:
+	.word 0x010102
+	.word 0x010102
+	.word 0x010101
+	.word 0x212102
+
+.globl __cpu_early_init
+__cpu_early_init:
+        //; Zero out r0 for use throughout this code. All other GPRs
+        //; (r1-r3) are set throughout this code to help establish
+        //; a consistent startup state for any code that follows.
+        //; Users should add code at the end of this routine to establish
+        //; their own stack address (r13), add translation page tables, enable
+        //; the caches, etc.
+        MOV    r0,  #0x0
+
+
+        //; Remove hardcoded cache settings. appsbl_handler.s calls Set_SA
+        //;   API to dynamically configure cache for slow/nominal/fast parts
+
+        //; DCIALL to invalidate L2 cache bank (needs to be run 4 times, once per bank)
+        //; This must be done early in code (prior to enabling the caches)
+        MOV    r1, #0x2
+        MCR    p15, 0, r1, c9, c0, 6   //; DCIALL bank D ([15:14] == 2'b00)
+        ORR    r1, r1, #0x00004000
+        MCR    p15, 0, r1, c9, c0, 6   //; DCIALL bank C ([15:14] == 2'b01)
+        ADD    r1, r1, #0x00004000
+        MCR    p15, 0, r1, c9, c0, 6   //; DCIALL bank B ([15:14] == 2'b10)
+        ADD    r1, r1, #0x00004000
+        MCR    p15, 0, r1, c9, c0, 6   //; DCIALL bank A ([15:14] == 2'b11)
+
+        //; Initialize the BPCR - setup Global History Mask (GHRM) to all 1's
+        //; and have all address bits (AM) participate.
+        //; Different settings can be used to improve performance
+        // MOVW   r1, #0x01FF
+.word 0xe30011ff  // hardcoded MOVW instruction due to lack of compiler support
+        // MOVT   r1, #0x01FF
+.word 0xe34011ff  // hardcoded MOVT instruction due to lack of compiler support
+        MCR    p15, 7, r1, c15, c0, 2   //; WCP15_BPCR
+
+
+        //; Initialize all I$ Victim Registers to 0 for startup
+        MCR    p15, 0, r0, c9, c1, 0    //; WCP15_ICVIC0    r0
+        MCR    p15, 0, r0, c9, c1, 1    //; WCP15_ICVIC1    r0
+        MCR    p15, 0, r0, c9, c1, 2    //; WCP15_ICVIC2    r0
+        MCR    p15, 0, r0, c9, c1, 3    //; WCP15_ICVIC3    r0
+        MCR    p15, 0, r0, c9, c1, 4    //; WCP15_ICVIC4    r0
+        MCR    p15, 0, r0, c9, c1, 5    //; WCP15_ICVIC5    r0
+        MCR    p15, 0, r0, c9, c1, 6    //; WCP15_ICVIC5    r0
+        MCR    p15, 0, r0, c9, c1, 7    //; WCP15_ICVIC7    r0
+
+        //; Initialize all I$ Locked Victim Registers (Unlocked Floors) to 0
+        MCR    p15, 1, r0, c9, c1, 0    //; WCP15_ICFLOOR0  r0
+        MCR    p15, 1, r0, c9, c1, 1    //; WCP15_ICFLOOR1  r0
+        MCR    p15, 1, r0, c9, c1, 2    //; WCP15_ICFLOOR2  r0
+        MCR    p15, 1, r0, c9, c1, 3    //; WCP15_ICFLOOR3  r0
+        MCR    p15, 1, r0, c9, c1, 4    //; WCP15_ICFLOOR4  r0
+        MCR    p15, 1, r0, c9, c1, 5    //; WCP15_ICFLOOR5  r0
+        MCR    p15, 1, r0, c9, c1, 6    //; WCP15_ICFLOOR6  r0
+        MCR    p15, 1, r0, c9, c1, 7    //; WCP15_ICFLOOR7  r0
+
+        //; Initialize all D$ Victim Registers to 0
+        MCR    p15, 2, r0, c9, c1, 0    //; WP15_DCVIC0    r0
+        MCR    p15, 2, r0, c9, c1, 1    //; WP15_DCVIC1    r0
+        MCR    p15, 2, r0, c9, c1, 2    //; WP15_DCVIC2    r0
+        MCR    p15, 2, r0, c9, c1, 3    //; WP15_DCVIC3    r0
+        MCR    p15, 2, r0, c9, c1, 4    //; WP15_DCVIC4    r0
+        MCR    p15, 2, r0, c9, c1, 5    //; WP15_DCVIC5    r0
+        MCR    p15, 2, r0, c9, c1, 6    //; WP15_DCVIC6    r0
+        MCR    p15, 2, r0, c9, c1, 7    //; WP15_DCVIC7    r0
+
+        //; Initialize all D$ Locked VDCtim Registers (Unlocked Floors) to 0
+        MCR    p15, 3, r0, c9, c1, 0    //; WCP15_DCFLOOR0  r0
+        MCR    p15, 3, r0, c9, c1, 1    //; WCP15_DCFLOOR1  r0
+        MCR    p15, 3, r0, c9, c1, 2    //; WCP15_DCFLOOR2  r0
+        MCR    p15, 3, r0, c9, c1, 3    //; WCP15_DCFLOOR3  r0
+        MCR    p15, 3, r0, c9, c1, 4    //; WCP15_DCFLOOR4  r0
+        MCR    p15, 3, r0, c9, c1, 5    //; WCP15_DCFLOOR5  r0
+        MCR    p15, 3, r0, c9, c1, 6    //; WCP15_DCFLOOR6  r0
+        MCR    p15, 3, r0, c9, c1, 7    //; WCP15_DCFLOOR7  r0
+
+        //; Initialize ASID to zero
+        MCR    p15, 0, r0, c13, c0, 1   //; WCP15_CONTEXTIDR r0
+
+        //; ICIALL to invalidate entire I-Cache
+        MCR    p15, 0, r0, c7, c5, 0    //; ICIALLU
+
+        //; DCIALL to invalidate entire D-Cache
+        MCR    p15, 0, r0, c9, c0, 6    //; DCIALL  r0
+
+
+        //; The VBAR (Vector Base Address Register) should be initialized
+        //; early in your code. We are setting it to zero
+        MCR    p15, 0, r0, c12, c0, 0   //; WCP15_VBAR  r0
+
+        //; Ensure the MCR's above have completed their operation before continuing
+        DSB
+        ISB
+
+        //;-------------------------------------------------------------------
+        //; There are a number of registers that must be set prior to enabling
+        //; the MMU. The DCAR is one of these registers. We are setting
+        //; it to zero (no access) to easily detect improper setup in subsequent
+        //; code sequences
+        //;-------------------------------------------------------------------
+        //; Setup DACR (Domain Access Control Register) to zero
+        MCR    p15, 0, r0, c3, c0, 0    //; WCP15_DACR  r0
+
+        //; Setup DCLKCR to allow normal D-Cache line fills
+        MCR    p15, 1, r0, c9, c0, 7    //; WCP15_DCLKCR r0
+
+        //; Initialize the ADFSR and EFSR registers.
+        MCR    p15, 0, r0,  c5, c1, 0   //; ADFSR
+        MCR    p15, 7, r0, c15, c0, 1   //; EFSR
+
+        //; Setup the TLBLKCR
+        //; Victim = 6'b000000; Floor = 6'b000000;
+        //; IASIDCFG = 2'b00 (State-Machine); IALLCFG = 2'b01 (Flash); BNA = 1'b0;
+        MOV    r1, #0x02
+        MCR    p15, 0, r1, c10, c1, 3     //; WCP15_TLBLKCR  r1
+
+        //;Make sure TLBLKCR is complete before continuing
+        ISB
+
+        //; Invalidate the UTLB
+        MCR    p15, 0, r0, c8, c7, 0      //; UTLBIALL
+
+        //; Make sure UTLB request has been presented to macro before continuing
+        ISB
+
+        //; setup L2CR1 to some default Instruction and data prefetching values
+        //; Users may want specific settings for various performance enhancements
+        //; In Halcyon we do not have broadcasting barriers. So we need to turn
+        //  ; on bit 8 of L2CR1; which DBB:( Disable barrier broadcast )
+        MOV r2, #0x100
+        MCR    p15, 3, r2, c15, c0, 3     //; WCP15_L2CR1  r0
+
+
+        //; Enable Z bit to enable branch prediction (default is off)
+        MRC    p15, 0, r2, c1, c0, 0      //; RCP15_SCTLR  r2
+        ORR    r2, r2, #0x00000800
+        MCR    p15, 0, r2, c1, c0, 0      //; WCP15_SCTLR  r2
+
+#ifdef CONFIG_ARCH_QSD8X50
+        /* disable predecode repair cache for thumb2 (DPRC, set bit 4 in PVR0F2) */
+        mrc p15, 0, r2, c15, c15, 2
+        orr r2, r2, #0x10
+        mcr p15, 0, r2, c15, c15, 2
+#endif
+
+        mov r1, lr
+        //; Make sure Link stack is initialized with branch and links to sequential addresses
+        //; This aids in creating a predictable startup environment
+       BL      SEQ1
+SEQ1:  BL      SEQ2
+SEQ2:  BL      SEQ3
+SEQ3:  BL      SEQ4
+SEQ4:  BL      SEQ5
+SEQ5:  BL      SEQ6
+SEQ6:  BL      SEQ7
+SEQ7:  BL      SEQ8
+SEQ8:
+        mov lr, r1
+
+        //; REMOVE FOLLOWING THREE INSTRUCTIONS WHEN POWER COLLAPSE IS ENA
+        //;Make sure the DBGOSLSR[LOCK] bit is cleared to allow access to the debug registers
+        //; Writing anything but the "secret code" to the DBGOSLAR clears the DBGOSLSR[LOCK] bit
+        MCR    p14, 0, r0, c1, c0, 4       //; WCP14_DBGOSLAR r0
+
+
+        //; Read the DBGPRSR to clear the DBGPRSR[STICKYPD]
+        //; Any read to DBGPRSR clear the STICKYPD bit
+        //; ISB guarantees the read completes before attempting to
+        //; execute a CP14 instruction.
+        MRC    p14, 0, r3, c1, c5, 4       //; RCP14_DBGPRSR r3
+        ISB
+
+        //; Initialize the Watchpoint Control Registers to zero (optional)
+        //;;; MCR    p14, 0, r0, c0, c0, 7       ; WCP14_DBGWCR0  r0
+        //;;; MCR    p14, 0, r0, c0, c1, 7       ; WCP14_DBGWCR1  r0
+
+
+        //;----------------------------------------------------------------------
+        //; The saved Program Status Registers (SPSRs) should be setup
+        //; prior to any automatic mode switches. The following
+        //; code sets these registers up to a known state. Users will need to
+        //; customize these settings to meet their needs.
+        //;----------------------------------------------------------------------
+        MOV    r2,  #0x1f
+        MOV    r1,  #0x17                 //;ABT mode
+        msr    cpsr_c, r1                 //;ABT mode
+        msr    spsr_cxfs, r2              //;clear the spsr
+        MOV    r1,  #0x1b                 //;UND mode
+        msr    cpsr_c, r1                 //;UND mode
+        msr    spsr_cxfs, r2              //;clear the spsr
+        MOV    r1,  #0x11                 //;FIQ mode
+        msr    cpsr_c, r1                 //;FIQ mode
+        msr    spsr_cxfs, r2              //;clear the spsr
+        MOV    r1,  #0x12                 //;IRQ mode
+        msr    cpsr_c, r1                 //;IRQ mode
+        msr    spsr_cxfs, r2              //;clear the spsr
+        MOV    r1,  #0x16                 //;Monitor mode
+        msr    cpsr_c, r1                 //;Monitor mode
+        msr    spsr_cxfs, r2              //;clear the spsr
+        MOV    r1,  #0x13                 //;SVC mode
+        msr    cpsr_c, r1                 //;SVC mode
+        msr    spsr_cxfs, r2              //;clear the spsr
+
+
+        //;----------------------------------------------------------------------
+        //; Enabling Error reporting is something users may want to do at
+        //; some other point in time. We have chosen some default settings
+        //; that should be reviewed. Most of these registers come up in an
+        //; unpredictable state after reset.
+        //;----------------------------------------------------------------------
+//;Start of error and control setting
+
+        //; setup L2CR0 with various L2/TCM control settings
+        //; enable out of order bus attributes and error reporting
+        //; this register comes up unpredictable after reset
+        // MOVW   r1, #0x0F0F
+.word 0xe3001f0f  // hardcoded MOVW instruction due to lack of compiler support
+        // MOVT   r1, #0xC005
+.word 0xe34c1005  // hardcoded MOVW instruction due to lack of compiler support
+        MCR    p15, 3, r1, c15, c0, 1    //; WCP15_L2CR0  r1
+
+        //; setup L2CPUCR
+        //; MOV    r2, #0xFF
+        //; Enable I and D cache parity
+        //;L2CPUCR[7:5] = 3~Rh7 ~V enable parity error reporting for modified,
+        //;tag, and data parity errors
+        MOV    r2, #0xe0
+        MCR    p15, 3, r2, c15, c0, 2    //; WCP15_L2CPUCR  r2
+
+        //; setup SPCR
+        //; enable all error reporting (reset value is unpredicatble for most bits)
+        MOV    r3, #0x0F
+        MCR    p15, 0, r3, c9, c7, 0     //; WCP15_SPCR  r3
+
+        //; setup DMACHCRs (reset value unpredictable)
+        //; control setting and enable all error reporting
+        MOV   r1, #0x0F
+
+        //; DMACHCR0 = 0000000F
+        MOV   r2, #0x00                  //; channel 0
+        MCR   p15, 0, r2, c11, c0, 0     //; WCP15_DMASELR  r2
+        MCR   p15, 0, r1, c11, c0, 2     //; WCP15_DMACHCR  r1
+
+        //; DMACHCR1 = 0000000F
+        MOV   r2, #0x01                  //; channel 1
+        MCR   p15, 0, r2, c11, c0, 0     //; WCP15_DMASELR  r2
+        MCR   p15, 0, r1, c11, c0, 2     //; WCP15_DMACHCR  r1
+
+        //; DMACHCR2 = 0000000F
+        MOV   r2, #0x02                  //; channel 2
+        MCR   p15, 0, r2, c11, c0, 0     //; WCP15_DMASELR  r2
+        MCR   p15, 0, r1, c11, c0, 2     //; WCP15_DMACHCR  r1
+
+        //; DMACHCR3 = 0000000F
+        MOV   r2, #0x03                  //; channel 3
+        MCR   p15, 0, r2, c11, c0, 0     //; WCP15_DMASELR  r2
+        MCR   p15, 0, r1, c11, c0, 2     //; WCP15_DMACHCR  r1
+
+        //; Set ACTLR (reset unpredictable)
+        //; Set AVIVT control, error reporting, etc.
+        //; MOV   r3, #0x07
+        //; Enable I and D cache parity
+        //;ACTLR[2:0] = 3'h7 - enable parity error reporting from L2/I$/D$)
+        //;ACTLR[5:4] = 2'h3 - enable parity
+        //;ACTLR[19:18] =2'h3 - always generate and check parity(when MMU disabled).
+        //;Value to be written #0xC0037
+        // MOVW   r3, #0x0037
+.word 0xe3003037  // hardcoded MOVW instruction due to lack of compiler support
+        // MOVT   r3, #0x000C
+.word 0xe340300c  // hardcoded MOVW instruction due to lack of compiler support
+            //; read the version_id to determine if d-cache should be disabled
+            LDR r2, = 0xa8e00270  //;Read HW_REVISION_NUMBER, HWIO_HW_REVISION_NUMBER_ADDR
+            LDR r2,[r2]
+            AND r2,r2,#0xf0000000 //;hw_revision mask off bits 28-31
+                //;if HW_revision is 1.0 or older, (revision==0)
+                CMP r2,#0
+        //; Disable d-cache on older QSD8650 (Rev 1.0) silicon
+        orreq   r3, r3, #0x4000          //;disable dcache
+        MCR   p15, 0, r3, c1, c0, 1      //; WCP15_ACTLR  r3
+
+//;End of error and control setting
+
+        //;----------------------------------------------------------------------
+        //; Unlock ETM and read StickyPD to halt the ETM clocks from running.
+        //; This is required for power saving whether the ETM is used or not.
+        //;----------------------------------------------------------------------
+
+        //;Clear ETMOSLSR[LOCK] bit
+        MOV   r1, #0x00000000
+        MCR   p14, 1, r1, c1, c0, 4        //; WCP14_ETMOSLAR      r1
+
+        //;Clear ETMPDSR[STICKYPD] bit
+        MRC   p14, 1, r2, c1, c5, 4        //; RCP14_ETMPDSR       r2
+
+/*
+#ifdef APPSBL_ETM_ENABLE
+        ;----------------------------------------------------------------------
+        ; Optionally Enable the ETM (Embedded Trace Macro) which is used for debug
+        ;----------------------------------------------------------------------
+
+        ; enable ETM clock if disabled
+        MRC   p15, 7, r1, c15, c0, 5       ; RCP15_CPMR           r1
+        ORR   r1, r1, #0x00000008
+        MCR   p15, 7, r1, c15, c0, 5       ; WCP15_CPMR           r1
+        ISB
+
+        ; set trigger event to counter1 being zero
+        MOV   r3, #0x00000040
+        MCR   p14, 1, r3, c0, c2, 0        ; WCP14_ETMTRIGGER     r3
+
+        ; clear ETMSR
+        MOV   r2, #0x00000000
+        MCR   p14, 1, r2, c0, c4, 0        ; WCP14_ETMSR          r2
+
+        ; clear trace enable single address comparator usage
+        MCR   p14, 1, r2, c0, c7, 0        ; WCP14_ETMTECR2       r2
+
+        ; set trace enable to always
+        MOV   r2, #0x0000006F
+        MCR   p14, 1, r2, c0, c8, 0        ; WCP14_ETMTEEVR       r2
+
+        ; clear trace enable address range comparator usage and exclude nothing
+        MOV   r2, #0x01000000
+        MCR   p14, 1, r2, c0, c9, 0        ; WCP14_ETMTECR1       r2
+
+        ; set view data to always
+        MOV   r2, #0x0000006F
+        MCR   p14, 1, r2, c0, c12, 0       ; WCP14_ETMVDEVR       r2
+
+        ; clear view data single address comparator usage
+        MOV   r2, #0x00000000
+        MCR   p14, 1, r2, c0, c13, 0       ;  WCP14_ETMVDCR1       r2
+
+        ; clear view data address range comparator usage and exclude nothing
+        MOV   r2, #0x00010000
+        MCR   p14, 1, r2, c0, c15, 0       ;  WCP14_ETMVDCR3       r2
+
+        ; set counter1 to 194
+        MOV   r2, #0x000000C2
+        MCR   p14, 1, r2, c0, c0, 5        ;  WCP14_ETMCNTRLDVR1   r2
+
+        ; set counter1 to never reload
+        MOV   r2, #0x0000406F
+        MCR   p14, 1, r2, c0, c8, 5        ;  WCP14_ETMCNTRLDEVR1  r2
+
+        ; set counter1 to decrement every cycle
+        MOV   r2, #0x0000006F
+        MCR   p14, 1, r2, c0, c4, 5        ; WCP14_ETMCNTENR1     r2
+
+        ; Set trace synchronization frequency 1024 bytes
+        MOV   r2, #0x00000400
+        MCR   p14, 1, r2, c0, c8, 7        ; WCP14_ETMSYNCFR      r2
+
+        ; Program etm control register
+        ;  - Set the CPU to ETM clock ratio to 1:1
+        ;  - Set the ETM to perform data address tracing
+        MOV   r2, #0x00002008
+        MCR   p14, 1, r2, c0, c0, 0        ; WCP14_ETMCR          r2
+        ISB
+#endif *//* APPSBL_ETM_ENABLE */
+
+/*
+#ifdef APPSBL_VFP_ENABLE
+       ;----------------------------------------------------------------------
+       ; Perform the following operations if you intend to make use of
+       ; the VFP/Neon unit. Note that the FMXR instruction requires a CPU ID
+       ; indicating the VFP unit is present (i.e.Cortex-A8). .
+       ; Some tools will require full double precision floating point support
+       ; which will become available in Scorpion pass 2
+       ;----------------------------------------------------------------------
+       ; allow full access to CP 10 and 11 space for VFP/NEON use
+        MRC   p15, 0, r1, c1, c0, 2        ; Read CP Access Control Register
+        ORR   r1, r1, #0x00F00000          ; enable full access for p10,11
+        MCR   p15, 0, r1, c1, c0, 2        ; Write CPACR
+
+        ;make sure the CPACR is complete before continuing
+        ISB
+
+       ; Enable VFP itself (certain OSes may want to dynamically set/clear
+       ; the enable bit based on the application being executed
+        MOV   r1, #0x40000000
+        FMXR  FPEXC, r1
+#endif *//* APPSBL_VFP_ENABLE */
+
+	/* we have no stack, so just tail-call into the SET_SA routine... */
+	b SET_SA
+
+.ltorg
diff --git a/arch/arm/mach-msm/avs.c b/arch/arm/mach-msm/avs.c
new file mode 100644
index 0000000..827adab
--- /dev/null
+++ b/arch/arm/mach-msm/avs.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2009, 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/kernel_stat.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+
+#include "avs.h"
+
+#define AVSDSCR_INPUT 0x01004860 /* magic # from circuit designer */
+#define TSCSR_INPUT   0x00000001 /* enable temperature sense */
+
+#define TEMPRS 16                /* total number of temperature regions */
+#define GET_TEMPR() (avs_get_tscsr() >> 28) /* scale TSCSR[CTEMP] to regions */
+
+struct mutex avs_lock;
+
+static struct avs_state_s
+{
+	u32 freq_cnt;		/* Frequencies supported list */
+	short *avs_v;		/* Dyanmically allocated storage for
+				 * 2D table of voltages over temp &
+				 * freq.  Used as a set of 1D tables.
+				 * Each table is for a single temp.
+				 * For usage see avs_get_voltage
+				 */
+	int (*set_vdd) (int);	/* Function Ptr for setting voltage */
+	int changing;		/* Clock frequency is changing */
+	u32 freq_idx;		/* Current frequency index */
+	int vdd;		/* Current ACPU voltage */
+} avs_state;
+
+/*
+ *  Update the AVS voltage vs frequency table, for current temperature
+ *  Adjust based on the AVS delay circuit hardware status
+ */
+static void avs_update_voltage_table(short *vdd_table)
+{
+	u32 avscsr;
+	int cpu;
+	int vu;
+	int l2;
+	int i;
+	u32 cur_freq_idx;
+	short cur_voltage;
+
+	cur_freq_idx = avs_state.freq_idx;
+	cur_voltage = avs_state.vdd;
+
+	avscsr = avs_test_delays();
+	AVSDEBUG("avscsr=%x, avsdscr=%x\n", avscsr, avs_get_avsdscr());
+
+	/*
+	 * Read the results for the various unit's AVS delay circuits
+	 * 2=> up, 1=>down, 0=>no-change
+	 */
+	cpu = ((avscsr >> 23) & 2) + ((avscsr >> 16) & 1);
+	vu  = ((avscsr >> 28) & 2) + ((avscsr >> 21) & 1);
+	l2  = ((avscsr >> 29) & 2) + ((avscsr >> 22) & 1);
+
+	if ((cpu == 3) || (vu == 3) || (l2 == 3)) {
+		printk(KERN_ERR "AVS: Dly Synth O/P error\n");
+	} else if ((cpu == 2) || (l2 == 2) || (vu == 2)) {
+		/*
+		 * even if one oscillator asks for up, increase the voltage,
+		 * as its an indication we are running outside the
+		 * critical acceptable range of v-f combination.
+		 */
+		AVSDEBUG("cpu=%d l2=%d vu=%d\n", cpu, l2, vu);
+		AVSDEBUG("Voltage up at %d\n", cur_freq_idx);
+
+		if (cur_voltage >= VOLTAGE_MAX)
+			printk(KERN_ERR
+				"AVS: Voltage can not get high enough!\n");
+
+		/* Raise the voltage for all frequencies */
+		for (i = 0; i < avs_state.freq_cnt; i++) {
+			vdd_table[i] = cur_voltage + VOLTAGE_STEP;
+			if (vdd_table[i] > VOLTAGE_MAX)
+				vdd_table[i] = VOLTAGE_MAX;
+		}
+	} else if ((cpu == 1) && (l2 == 1) && (vu == 1)) {
+		if ((cur_voltage - VOLTAGE_STEP >= VOLTAGE_MIN) &&
+		    (cur_voltage <= vdd_table[cur_freq_idx])) {
+			vdd_table[cur_freq_idx] = cur_voltage - VOLTAGE_STEP;
+			AVSDEBUG("Voltage down for %d and lower levels\n",
+				cur_freq_idx);
+
+			/* clamp to this voltage for all lower levels */
+			for (i = 0; i < cur_freq_idx; i++) {
+				if (vdd_table[i] > vdd_table[cur_freq_idx])
+					vdd_table[i] = vdd_table[cur_freq_idx];
+			}
+		}
+	}
+}
+
+/*
+ * Return the voltage for the target performance freq_idx and optionally
+ * use AVS hardware to check the present voltage freq_idx
+ */
+static short avs_get_target_voltage(int freq_idx, bool update_table)
+{
+	unsigned cur_tempr = GET_TEMPR();
+	unsigned temp_index = cur_tempr*avs_state.freq_cnt;
+
+	/* Table of voltages vs frequencies for this temp */
+	short *vdd_table = avs_state.avs_v + temp_index;
+
+	if (update_table)
+		avs_update_voltage_table(vdd_table);
+
+	return vdd_table[freq_idx];
+}
+
+
+/*
+ * Set the voltage for the freq_idx and optionally
+ * use AVS hardware to update the voltage
+ */
+static int avs_set_target_voltage(int freq_idx, bool update_table)
+{
+	int rc = 0;
+	int new_voltage = avs_get_target_voltage(freq_idx, update_table);
+	if (avs_state.vdd != new_voltage) {
+		AVSDEBUG("AVS setting V to %d mV @%d\n",
+			new_voltage, freq_idx);
+		rc = avs_state.set_vdd(new_voltage);
+		if (rc)
+			return rc;
+		avs_state.vdd = new_voltage;
+	}
+	return rc;
+}
+
+/*
+ * Notify avs of clk frquency transition begin & end
+ */
+int avs_adjust_freq(u32 freq_idx, int begin)
+{
+	int rc = 0;
+
+	if (!avs_state.set_vdd) {
+		/* AVS not initialized */
+		return 0;
+	}
+
+	if (freq_idx >= avs_state.freq_cnt) {
+		AVSDEBUG("Out of range :%d\n", freq_idx);
+		return -EINVAL;
+	}
+
+	mutex_lock(&avs_lock);
+	if ((begin && (freq_idx > avs_state.freq_idx)) ||
+	    (!begin && (freq_idx < avs_state.freq_idx))) {
+		/* Update voltage before increasing frequency &
+		 * after decreasing frequency
+		 */
+		rc = avs_set_target_voltage(freq_idx, 0);
+		if (rc)
+			goto aaf_out;
+
+		avs_state.freq_idx = freq_idx;
+	}
+	avs_state.changing = begin;
+aaf_out:
+	mutex_unlock(&avs_lock);
+
+	return rc;
+}
+
+
+static struct delayed_work avs_work;
+static struct workqueue_struct  *kavs_wq;
+#define AVS_DELAY ((CONFIG_HZ * 50 + 999) / 1000)
+
+static void do_avs_timer(struct work_struct *work)
+{
+	int cur_freq_idx;
+
+	mutex_lock(&avs_lock);
+	if (!avs_state.changing) {
+		/* Only adjust the voltage if clk is stable */
+		cur_freq_idx = avs_state.freq_idx;
+		avs_set_target_voltage(cur_freq_idx, 1);
+	}
+	mutex_unlock(&avs_lock);
+	queue_delayed_work_on(0, kavs_wq, &avs_work, AVS_DELAY);
+}
+
+
+static void __init avs_timer_init(void)
+{
+	INIT_DELAYED_WORK_DEFERRABLE(&avs_work, do_avs_timer);
+	queue_delayed_work_on(0, kavs_wq, &avs_work, AVS_DELAY);
+}
+
+static void __exit avs_timer_exit(void)
+{
+	cancel_delayed_work(&avs_work);
+}
+
+static int __init avs_work_init(void)
+{
+	kavs_wq = create_workqueue("avs");
+	if (!kavs_wq) {
+		printk(KERN_ERR "AVS initialization failed\n");
+		return -EFAULT;
+	}
+	avs_timer_init();
+
+	return 1;
+}
+
+static void __exit avs_work_exit(void)
+{
+	avs_timer_exit();
+	destroy_workqueue(kavs_wq);
+}
+
+int __init avs_init(int (*set_vdd)(int), u32 freq_cnt, u32 freq_idx)
+{
+	int i;
+
+	mutex_init(&avs_lock);
+
+	if (freq_cnt == 0)
+		return -EINVAL;
+
+	avs_state.freq_cnt = freq_cnt;
+
+	if (freq_idx >= avs_state.freq_cnt)
+		return -EINVAL;
+
+	avs_state.avs_v = kmalloc(TEMPRS * avs_state.freq_cnt *
+		sizeof(avs_state.avs_v[0]), GFP_KERNEL);
+
+	if (avs_state.avs_v == 0)
+		return -ENOMEM;
+
+	for (i = 0; i < TEMPRS*avs_state.freq_cnt; i++)
+		avs_state.avs_v[i] = VOLTAGE_MAX;
+
+	avs_reset_delays(AVSDSCR_INPUT);
+	avs_set_tscsr(TSCSR_INPUT);
+
+	avs_state.set_vdd = set_vdd;
+	avs_state.changing = 0;
+	avs_state.freq_idx = -1;
+	avs_state.vdd = -1;
+	avs_adjust_freq(freq_idx, 0);
+
+	avs_work_init();
+
+	return 0;
+}
+
+void __exit avs_exit()
+{
+	avs_work_exit();
+
+	kfree(avs_state.avs_v);
+}
+
+
diff --git a/arch/arm/mach-msm/avs.h b/arch/arm/mach-msm/avs.h
new file mode 100644
index 0000000..a549e9d
--- /dev/null
+++ b/arch/arm/mach-msm/avs.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2009, 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 AVS_H
+#define AVS_H
+
+#define VOLTAGE_MIN  1000 /* mV */
+#define VOLTAGE_MAX  1250
+#define VOLTAGE_STEP 25
+
+int __init avs_init(int (*set_vdd)(int), u32 freq_cnt, u32 freq_idx);
+void __exit avs_exit(void);
+
+int avs_adjust_freq(u32 freq_index, int begin);
+
+/* Routines exported from avs_hw.S */
+#ifdef CONFIG_MSM_CPU_AVS
+u32 avs_test_delays(void);
+#else
+static inline u32 avs_test_delays(void)
+{ return 0; }
+#endif
+
+#ifdef CONFIG_MSM_AVS_HW
+u32 avs_reset_delays(u32 avsdscr);
+u32 avs_get_avscsr(void);
+u32 avs_get_avsdscr(void);
+u32 avs_get_tscsr(void);
+void avs_set_tscsr(u32 to_tscsr);
+void avs_disable(void);
+#else
+static inline u32 avs_reset_delays(u32 avsdscr)
+{ return 0; }
+static inline u32 avs_get_avscsr(void)
+{ return 0; }
+static inline u32 avs_get_avsdscr(void)
+{ return 0; }
+static inline u32 avs_get_tscsr(void)
+{ return 0; }
+static inline void avs_set_tscsr(u32 to_tscsr) {}
+static inline void avs_disable(void) {}
+#endif
+
+/*#define AVSDEBUG(x...) pr_info("AVS: " x);*/
+#define AVSDEBUG(...)
+
+#define AVS_DISABLE(cpu) do {			\
+		if (get_cpu() == (cpu))		\
+			avs_disable();		\
+		put_cpu();			\
+	} while (0);
+
+#define AVS_ENABLE(cpu, x) do {			\
+		if (get_cpu() == (cpu))		\
+			avs_reset_delays((x));	\
+		put_cpu();			\
+	} while (0);
+
+#endif /* AVS_H */
diff --git a/arch/arm/mach-msm/avs_hw.S b/arch/arm/mach-msm/avs_hw.S
new file mode 100644
index 0000000..1cc3ce0
--- /dev/null
+++ b/arch/arm/mach-msm/avs_hw.S
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2009, 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.
+ */
+
+	.text
+
+#ifdef CONFIG_MSM_CPU_AVS
+	.global avs_test_delays
+avs_test_delays:
+
+/*      Read r1=CPMR and enable Never Sleep for VSLPDLY */
+		mrc  p15, 7, r1, c15, c0, 5
+		orr  r12, r1, #3, 24
+		mcr  p15, 7, r12, c15, c0, 5
+
+/*      Read r2=CPACR and enable full access to CP10 and CP11 space */
+		mrc p15, 0, r2, c1, c0, 2
+		orr r12, r2, #(0xf << 20)
+		mcr p15, 0, r12, c1, c0, 2
+		isb
+
+/*      Read r3=FPEXC and or in FP enable, VFP/ASE enable = FPEXC[30]; */
+		fmrx r3, fpexc
+		orr  r12, r3, #1, 2
+		fmxr fpexc, r12
+
+/*
+ *      Do floating-point operations to prime the VFP pipeline.   Use
+ *      fcpyd d0, d0 as a floating point nop.  This avoids changing VFP
+ *      state.
+ */
+		fcpyd d0, d0
+		fcpyd d0, d0
+		fcpyd d0, d0
+
+/*      Read r0=AVSCSR to get status from CPU, VFP, and L2 ring oscillators */
+		mrc p15, 7, r0, c15, c1, 7
+
+/*      Restore FPEXC */
+		fmxr fpexc, r3
+
+/*      Restore CPACR */
+                MCR p15, 0, r2, c1, c0, 2
+
+/*      Restore CPMR */
+		mcr p15, 7, r1, c15, c0, 5
+                isb
+
+		bx lr
+#endif
+
+
+	.global avs_get_avscsr
+/*      Read r0=AVSCSR to get status from CPU, VFP, and L2 ring oscillators */
+
+avs_get_avscsr:
+		mrc p15, 7, r0, c15, c1, 7
+                bx lr
+
+        .global avs_get_avsdscr
+/*      Read r0=AVSDSCR to get the AVS Delay Synthesizer control settings */
+
+avs_get_avsdscr:
+		mrc p15, 7, r0, c15, c0, 6
+                bx lr
+
+
+
+
+	.global avs_get_tscsr
+/*      Read r0=TSCSR to get temperature sensor control and status */
+
+avs_get_tscsr:
+		mrc p15, 7, r0, c15, c1, 0
+                bx lr
+
+        .global avs_set_tscsr
+/*      Write TSCSR=r0 to set temperature sensor control and status  */
+
+avs_set_tscsr:
+		mcr p15, 7, r0, c15, c1, 0
+                bx lr
+
+
+
+
+
+	.global avs_reset_delays
+avs_reset_delays:
+
+/*      AVSDSCR(dly) to program delay */
+		mcr p15, 7, r0, c15, c0, 6
+
+/*      Read r0=AVSDSCR */
+		mrc p15, 7, r0, c15, c0, 6
+
+/*      AVSCSR(0x61) to enable CPU, V and L2 AVS module  */
+		mov r3, #0x61
+		mcr p15, 7, r3, c15, c1, 7
+
+		bx lr
+
+
+
+        .global avs_disable
+avs_disable:
+
+/*      Clear AVSCSR */
+		mov r0, #0
+
+/*      Write AVSCSR */
+		mcr p15, 7, r0, c15, c1, 7
+
+		bx lr
+
+	.end
+
+
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
new file mode 100644
index 0000000..d53e471
--- /dev/null
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -0,0 +1,2326 @@
+/* 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
+ * 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.
+ *
+ */
+
+/*
+ *  BAM DMUX module.
+ */
+
+#define DEBUG
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/skbuff.h>
+#include <linux/debugfs.h>
+#include <linux/clk.h>
+#include <linux/wakelock.h>
+#include <linux/kfifo.h>
+
+#include <mach/sps.h>
+#include <mach/bam_dmux.h>
+#include <mach/msm_smsm.h>
+#include <mach/subsystem_notif.h>
+#include <mach/socinfo.h>
+#include <mach/subsystem_restart.h>
+
+#define BAM_CH_LOCAL_OPEN       0x1
+#define BAM_CH_REMOTE_OPEN      0x2
+#define BAM_CH_IN_RESET         0x4
+
+#define BAM_MUX_HDR_MAGIC_NO    0x33fc
+
+#define BAM_MUX_HDR_CMD_DATA		0
+#define BAM_MUX_HDR_CMD_OPEN		1
+#define BAM_MUX_HDR_CMD_CLOSE		2
+#define BAM_MUX_HDR_CMD_STATUS		3 /* unused */
+#define BAM_MUX_HDR_CMD_OPEN_NO_A2_PC	4
+
+#define POLLING_MIN_SLEEP	950	/* 0.95 ms */
+#define POLLING_MAX_SLEEP	1050	/* 1.05 ms */
+#define POLLING_INACTIVITY	40	/* cycles before switch to intr mode */
+
+#define LOW_WATERMARK		2
+#define HIGH_WATERMARK		4
+
+static int msm_bam_dmux_debug_enable;
+module_param_named(debug_enable, msm_bam_dmux_debug_enable,
+		   int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#if defined(DEBUG)
+static uint32_t bam_dmux_read_cnt;
+static uint32_t bam_dmux_write_cnt;
+static uint32_t bam_dmux_write_cpy_cnt;
+static uint32_t bam_dmux_write_cpy_bytes;
+static uint32_t bam_dmux_tx_sps_failure_cnt;
+static uint32_t bam_dmux_tx_stall_cnt;
+static atomic_t bam_dmux_ack_out_cnt = ATOMIC_INIT(0);
+static atomic_t bam_dmux_ack_in_cnt = ATOMIC_INIT(0);
+static atomic_t bam_dmux_a2_pwr_cntl_in_cnt = ATOMIC_INIT(0);
+
+#define DBG(x...) do {		                 \
+		if (msm_bam_dmux_debug_enable)  \
+			pr_debug(x);	         \
+	} while (0)
+
+#define DBG_INC_READ_CNT(x) do {	                               \
+		bam_dmux_read_cnt += (x);                             \
+		if (msm_bam_dmux_debug_enable)                        \
+			pr_debug("%s: total read bytes %u\n",          \
+				 __func__, bam_dmux_read_cnt);        \
+	} while (0)
+
+#define DBG_INC_WRITE_CNT(x)  do {	                               \
+		bam_dmux_write_cnt += (x);                            \
+		if (msm_bam_dmux_debug_enable)                        \
+			pr_debug("%s: total written bytes %u\n",       \
+				 __func__, bam_dmux_write_cnt);       \
+	} while (0)
+
+#define DBG_INC_WRITE_CPY(x)  do {	                                     \
+		bam_dmux_write_cpy_bytes += (x);                            \
+		bam_dmux_write_cpy_cnt++;                                   \
+		if (msm_bam_dmux_debug_enable)                              \
+			pr_debug("%s: total write copy cnt %u, bytes %u\n",  \
+				 __func__, bam_dmux_write_cpy_cnt,          \
+				 bam_dmux_write_cpy_bytes);                 \
+	} while (0)
+
+#define DBG_INC_TX_SPS_FAILURE_CNT() do {	\
+		bam_dmux_tx_sps_failure_cnt++;		\
+} while (0)
+
+#define DBG_INC_TX_STALL_CNT() do { \
+	bam_dmux_tx_stall_cnt++; \
+} while (0)
+
+#define DBG_INC_ACK_OUT_CNT() \
+	atomic_inc(&bam_dmux_ack_out_cnt)
+
+#define DBG_INC_A2_POWER_CONTROL_IN_CNT() \
+	atomic_inc(&bam_dmux_a2_pwr_cntl_in_cnt)
+
+#define DBG_INC_ACK_IN_CNT() \
+	atomic_inc(&bam_dmux_ack_in_cnt)
+#else
+#define DBG(x...) do { } while (0)
+#define DBG_INC_READ_CNT(x...) do { } while (0)
+#define DBG_INC_WRITE_CNT(x...) do { } while (0)
+#define DBG_INC_WRITE_CPY(x...) do { } while (0)
+#define DBG_INC_TX_SPS_FAILURE_CNT() do { } while (0)
+#define DBG_INC_TX_STALL_CNT() do { } while (0)
+#define DBG_INC_ACK_OUT_CNT() do { } while (0)
+#define DBG_INC_A2_POWER_CONTROL_IN_CNT() \
+	do { } while (0)
+#define DBG_INC_ACK_IN_CNT() do { } while (0)
+#endif
+
+struct bam_ch_info {
+	uint32_t status;
+	void (*notify)(void *, int, unsigned long);
+	void *priv;
+	spinlock_t lock;
+	struct platform_device *pdev;
+	char name[BAM_DMUX_CH_NAME_MAX_LEN];
+	int num_tx_pkts;
+	int use_wm;
+};
+
+struct tx_pkt_info {
+	struct sk_buff *skb;
+	dma_addr_t dma_address;
+	char is_cmd;
+	uint32_t len;
+	struct work_struct work;
+	struct list_head list_node;
+	unsigned ts_sec;
+	unsigned long ts_nsec;
+};
+
+struct rx_pkt_info {
+	struct sk_buff *skb;
+	dma_addr_t dma_address;
+	struct work_struct work;
+	struct list_head list_node;
+};
+
+#define A2_NUM_PIPES		6
+#define A2_SUMMING_THRESHOLD	4096
+#define A2_DEFAULT_DESCRIPTORS	32
+#define A2_PHYS_BASE		0x124C2000
+#define A2_PHYS_SIZE		0x2000
+#define BUFFER_SIZE		2048
+#define NUM_BUFFERS		32
+static struct sps_bam_props a2_props;
+static u32 a2_device_handle;
+static struct sps_pipe *bam_tx_pipe;
+static struct sps_pipe *bam_rx_pipe;
+static struct sps_connect tx_connection;
+static struct sps_connect rx_connection;
+static struct sps_mem_buffer tx_desc_mem_buf;
+static struct sps_mem_buffer rx_desc_mem_buf;
+static struct sps_register_event tx_register_event;
+static struct sps_register_event rx_register_event;
+
+static struct bam_ch_info bam_ch[BAM_DMUX_NUM_CHANNELS];
+static int bam_mux_initialized;
+
+static int polling_mode;
+
+static LIST_HEAD(bam_rx_pool);
+static DEFINE_MUTEX(bam_rx_pool_mutexlock);
+static int bam_rx_pool_len;
+static LIST_HEAD(bam_tx_pool);
+static DEFINE_SPINLOCK(bam_tx_pool_spinlock);
+
+struct bam_mux_hdr {
+	uint16_t magic_num;
+	uint8_t reserved;
+	uint8_t cmd;
+	uint8_t pad_len;
+	uint8_t ch_id;
+	uint16_t pkt_len;
+};
+
+static void notify_all(int event, unsigned long data);
+static void bam_mux_write_done(struct work_struct *work);
+static void handle_bam_mux_cmd(struct work_struct *work);
+static void rx_timer_work_func(struct work_struct *work);
+
+static DECLARE_WORK(rx_timer_work, rx_timer_work_func);
+
+static struct workqueue_struct *bam_mux_rx_workqueue;
+static struct workqueue_struct *bam_mux_tx_workqueue;
+
+/* A2 power collaspe */
+#define UL_TIMEOUT_DELAY 1000	/* in ms */
+#define ENABLE_DISCONNECT_ACK	0x1
+static void toggle_apps_ack(void);
+static void reconnect_to_bam(void);
+static void disconnect_to_bam(void);
+static void ul_wakeup(void);
+static void ul_timeout(struct work_struct *work);
+static void vote_dfab(void);
+static void unvote_dfab(void);
+static void kickoff_ul_wakeup_func(struct work_struct *work);
+static void grab_wakelock(void);
+static void release_wakelock(void);
+
+static int bam_is_connected;
+static DEFINE_MUTEX(wakeup_lock);
+static struct completion ul_wakeup_ack_completion;
+static struct completion bam_connection_completion;
+static struct delayed_work ul_timeout_work;
+static int ul_packet_written;
+static atomic_t ul_ondemand_vote = ATOMIC_INIT(0);
+static struct clk *dfab_clk, *xo_clk;
+static DEFINE_RWLOCK(ul_wakeup_lock);
+static DECLARE_WORK(kickoff_ul_wakeup, kickoff_ul_wakeup_func);
+static int bam_connection_is_active;
+static int wait_for_ack;
+static struct wake_lock bam_wakelock;
+static int a2_pc_disabled;
+static DEFINE_MUTEX(dfab_status_lock);
+static int dfab_is_on;
+static int wait_for_dfab;
+static struct completion dfab_unvote_completion;
+static DEFINE_SPINLOCK(wakelock_reference_lock);
+static int wakelock_reference_count;
+static int a2_pc_disabled_wakelock_skipped;
+static int disconnect_ack;
+static LIST_HEAD(bam_other_notify_funcs);
+static DEFINE_MUTEX(smsm_cb_lock);
+static DEFINE_MUTEX(delayed_ul_vote_lock);
+static int need_delayed_ul_vote;
+
+struct outside_notify_func {
+	void (*notify)(void *, int, unsigned long);
+	void *priv;
+	struct list_head list_node;
+};
+/* End A2 power collaspe */
+
+/* subsystem restart */
+static int restart_notifier_cb(struct notifier_block *this,
+				unsigned long code,
+				void *data);
+
+static struct notifier_block restart_notifier = {
+	.notifier_call = restart_notifier_cb,
+};
+static int in_global_reset;
+/* end subsystem restart */
+
+#define bam_ch_is_open(x)						\
+	(bam_ch[(x)].status == (BAM_CH_LOCAL_OPEN | BAM_CH_REMOTE_OPEN))
+
+#define bam_ch_is_local_open(x)			\
+	(bam_ch[(x)].status & BAM_CH_LOCAL_OPEN)
+
+#define bam_ch_is_remote_open(x)			\
+	(bam_ch[(x)].status & BAM_CH_REMOTE_OPEN)
+
+#define bam_ch_is_in_reset(x)			\
+	(bam_ch[(x)].status & BAM_CH_IN_RESET)
+
+#define LOG_MESSAGE_MAX_SIZE 80
+struct kfifo bam_dmux_state_log;
+static uint32_t bam_dmux_state_logging_disabled;
+static DEFINE_SPINLOCK(bam_dmux_logging_spinlock);
+static int bam_dmux_uplink_vote;
+static int bam_dmux_power_state;
+
+
+#define DMUX_LOG_KERR(fmt...) \
+do { \
+	bam_dmux_log(fmt); \
+	pr_err(fmt); \
+} while (0)
+
+/**
+ * Log a state change along with a small message.
+ *
+ * Complete size of messsage is limited to @todo.
+ */
+static void bam_dmux_log(const char *fmt, ...)
+{
+	char buff[LOG_MESSAGE_MAX_SIZE];
+	unsigned long flags;
+	va_list arg_list;
+	unsigned long long t_now;
+	unsigned long nanosec_rem;
+	int len = 0;
+
+	if (bam_dmux_state_logging_disabled)
+		return;
+
+	t_now = sched_clock();
+	nanosec_rem = do_div(t_now, 1000000000U);
+
+	/*
+	 * States
+	 * D: 1 = Power collapse disabled
+	 * R: 1 = in global reset
+	 * P: 1 = BAM is powered up
+	 * A: 1 = BAM initialized and ready for data
+	 *
+	 * V: 1 = Uplink vote for power
+	 * U: 1 = Uplink active
+	 * W: 1 = Uplink Wait-for-ack
+	 * A: 1 = Uplink ACK received
+	 * #: >=1 On-demand uplink vote
+	 * D: 1 = Disconnect ACK active
+	 */
+	len += scnprintf(buff, sizeof(buff),
+		"<DMUX> %u.%09lu %c%c%c%c %c%c%c%c%d%c ",
+		(unsigned)t_now, nanosec_rem,
+		a2_pc_disabled ? 'D' : 'd',
+		in_global_reset ? 'R' : 'r',
+		bam_dmux_power_state ? 'P' : 'p',
+		bam_connection_is_active ? 'A' : 'a',
+		bam_dmux_uplink_vote ? 'V' : 'v',
+		bam_is_connected ?  'U' : 'u',
+		wait_for_ack ? 'W' : 'w',
+		ul_wakeup_ack_completion.done ? 'A' : 'a',
+		atomic_read(&ul_ondemand_vote),
+		disconnect_ack ? 'D' : 'd'
+		);
+
+	va_start(arg_list, fmt);
+	len += vscnprintf(buff + len, sizeof(buff) - len, fmt, arg_list);
+	va_end(arg_list);
+	memset(buff + len, 0x0, sizeof(buff) - len);
+
+	spin_lock_irqsave(&bam_dmux_logging_spinlock, flags);
+	if (kfifo_avail(&bam_dmux_state_log) < LOG_MESSAGE_MAX_SIZE) {
+		char junk[LOG_MESSAGE_MAX_SIZE];
+		int ret;
+
+		ret = kfifo_out(&bam_dmux_state_log, junk, sizeof(junk));
+		if (ret != LOG_MESSAGE_MAX_SIZE) {
+			pr_err("%s: unable to empty log %d\n", __func__, ret);
+			spin_unlock_irqrestore(&bam_dmux_logging_spinlock,
+					flags);
+			return;
+		}
+	}
+	kfifo_in(&bam_dmux_state_log, buff, sizeof(buff));
+	spin_unlock_irqrestore(&bam_dmux_logging_spinlock, flags);
+}
+
+static inline void set_tx_timestamp(struct tx_pkt_info *pkt)
+{
+	unsigned long long t_now;
+
+	t_now = sched_clock();
+	pkt->ts_nsec = do_div(t_now, 1000000000U);
+	pkt->ts_sec = (unsigned)t_now;
+}
+
+static inline void verify_tx_queue_is_empty(const char *func)
+{
+	unsigned long flags;
+	struct tx_pkt_info *info;
+	int reported = 0;
+
+	spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
+	list_for_each_entry(info, &bam_tx_pool, list_node) {
+		if (!reported) {
+			bam_dmux_log("%s: tx pool not empty\n", func);
+			if (!in_global_reset)
+				pr_err("%s: tx pool not empty\n", func);
+			reported = 1;
+		}
+		bam_dmux_log("%s: node=%p ts=%u.%09lu\n", __func__,
+			&info->list_node, info->ts_sec, info->ts_nsec);
+		if (!in_global_reset)
+			pr_err("%s: node=%p ts=%u.%09lu\n", __func__,
+			&info->list_node, info->ts_sec, info->ts_nsec);
+	}
+	spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+}
+
+static void queue_rx(void)
+{
+	void *ptr;
+	struct rx_pkt_info *info;
+	int ret;
+	int rx_len_cached;
+
+	mutex_lock(&bam_rx_pool_mutexlock);
+	rx_len_cached = bam_rx_pool_len;
+	mutex_unlock(&bam_rx_pool_mutexlock);
+
+	while (rx_len_cached < NUM_BUFFERS) {
+		if (in_global_reset)
+			goto fail;
+
+		info = kmalloc(sizeof(struct rx_pkt_info), GFP_KERNEL);
+		if (!info) {
+			pr_err("%s: unable to alloc rx_pkt_info\n", __func__);
+			goto fail;
+		}
+
+		INIT_WORK(&info->work, handle_bam_mux_cmd);
+
+		info->skb = __dev_alloc_skb(BUFFER_SIZE, GFP_KERNEL);
+		if (info->skb == NULL) {
+			DMUX_LOG_KERR("%s: unable to alloc skb\n", __func__);
+			goto fail_info;
+		}
+		ptr = skb_put(info->skb, BUFFER_SIZE);
+
+		info->dma_address = dma_map_single(NULL, ptr, BUFFER_SIZE,
+							DMA_FROM_DEVICE);
+		if (info->dma_address == 0 || info->dma_address == ~0) {
+			DMUX_LOG_KERR("%s: dma_map_single failure %p for %p\n",
+				__func__, (void *)info->dma_address, ptr);
+			goto fail_skb;
+		}
+
+		mutex_lock(&bam_rx_pool_mutexlock);
+		list_add_tail(&info->list_node, &bam_rx_pool);
+		rx_len_cached = ++bam_rx_pool_len;
+		mutex_unlock(&bam_rx_pool_mutexlock);
+
+		ret = sps_transfer_one(bam_rx_pipe, info->dma_address,
+			BUFFER_SIZE, info,
+			SPS_IOVEC_FLAG_INT | SPS_IOVEC_FLAG_EOT);
+
+		if (ret) {
+			DMUX_LOG_KERR("%s: sps_transfer_one failed %d\n",
+				__func__, ret);
+			goto fail_transfer;
+		}
+	}
+	return;
+
+fail_transfer:
+	mutex_lock(&bam_rx_pool_mutexlock);
+	list_del(&info->list_node);
+	--bam_rx_pool_len;
+	rx_len_cached = bam_rx_pool_len;
+	mutex_unlock(&bam_rx_pool_mutexlock);
+
+	dma_unmap_single(NULL, info->dma_address, BUFFER_SIZE,
+				DMA_FROM_DEVICE);
+
+fail_skb:
+	dev_kfree_skb_any(info->skb);
+
+fail_info:
+	kfree(info);
+
+fail:
+	if (rx_len_cached == 0) {
+		DMUX_LOG_KERR("%s: RX queue failure\n", __func__);
+		in_global_reset = 1;
+	}
+}
+
+static void bam_mux_process_data(struct sk_buff *rx_skb)
+{
+	unsigned long flags;
+	struct bam_mux_hdr *rx_hdr;
+	unsigned long event_data;
+
+	rx_hdr = (struct bam_mux_hdr *)rx_skb->data;
+
+	rx_skb->data = (unsigned char *)(rx_hdr + 1);
+	rx_skb->tail = rx_skb->data + rx_hdr->pkt_len;
+	rx_skb->len = rx_hdr->pkt_len;
+	rx_skb->truesize = rx_hdr->pkt_len + sizeof(struct sk_buff);
+
+	event_data = (unsigned long)(rx_skb);
+
+	spin_lock_irqsave(&bam_ch[rx_hdr->ch_id].lock, flags);
+	if (bam_ch[rx_hdr->ch_id].notify)
+		bam_ch[rx_hdr->ch_id].notify(
+			bam_ch[rx_hdr->ch_id].priv, BAM_DMUX_RECEIVE,
+							event_data);
+	else
+		dev_kfree_skb_any(rx_skb);
+	spin_unlock_irqrestore(&bam_ch[rx_hdr->ch_id].lock, flags);
+
+	queue_rx();
+}
+
+static inline void handle_bam_mux_cmd_open(struct bam_mux_hdr *rx_hdr)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&bam_ch[rx_hdr->ch_id].lock, flags);
+	bam_ch[rx_hdr->ch_id].status |= BAM_CH_REMOTE_OPEN;
+	bam_ch[rx_hdr->ch_id].num_tx_pkts = 0;
+	spin_unlock_irqrestore(&bam_ch[rx_hdr->ch_id].lock, flags);
+	queue_rx();
+	ret = platform_device_add(bam_ch[rx_hdr->ch_id].pdev);
+	if (ret)
+		pr_err("%s: platform_device_add() error: %d\n",
+				__func__, ret);
+}
+
+static void handle_bam_mux_cmd(struct work_struct *work)
+{
+	unsigned long flags;
+	struct bam_mux_hdr *rx_hdr;
+	struct rx_pkt_info *info;
+	struct sk_buff *rx_skb;
+
+	info = container_of(work, struct rx_pkt_info, work);
+	rx_skb = info->skb;
+	dma_unmap_single(NULL, info->dma_address, BUFFER_SIZE, DMA_FROM_DEVICE);
+	kfree(info);
+
+	rx_hdr = (struct bam_mux_hdr *)rx_skb->data;
+
+	DBG_INC_READ_CNT(sizeof(struct bam_mux_hdr));
+	DBG("%s: magic %x reserved %d cmd %d pad %d ch %d len %d\n", __func__,
+			rx_hdr->magic_num, rx_hdr->reserved, rx_hdr->cmd,
+			rx_hdr->pad_len, rx_hdr->ch_id, rx_hdr->pkt_len);
+	if (rx_hdr->magic_num != BAM_MUX_HDR_MAGIC_NO) {
+		DMUX_LOG_KERR("%s: dropping invalid hdr. magic %x"
+			" reserved %d cmd %d"
+			" pad %d ch %d len %d\n", __func__,
+			rx_hdr->magic_num, rx_hdr->reserved, rx_hdr->cmd,
+			rx_hdr->pad_len, rx_hdr->ch_id, rx_hdr->pkt_len);
+		dev_kfree_skb_any(rx_skb);
+		queue_rx();
+		return;
+	}
+
+	if (rx_hdr->ch_id >= BAM_DMUX_NUM_CHANNELS) {
+		DMUX_LOG_KERR("%s: dropping invalid LCID %d"
+			" reserved %d cmd %d"
+			" pad %d ch %d len %d\n", __func__,
+			rx_hdr->ch_id, rx_hdr->reserved, rx_hdr->cmd,
+			rx_hdr->pad_len, rx_hdr->ch_id, rx_hdr->pkt_len);
+		dev_kfree_skb_any(rx_skb);
+		queue_rx();
+		return;
+	}
+
+	switch (rx_hdr->cmd) {
+	case BAM_MUX_HDR_CMD_DATA:
+		DBG_INC_READ_CNT(rx_hdr->pkt_len);
+		bam_mux_process_data(rx_skb);
+		break;
+	case BAM_MUX_HDR_CMD_OPEN:
+		bam_dmux_log("%s: opening cid %d PC enabled\n", __func__,
+				rx_hdr->ch_id);
+		handle_bam_mux_cmd_open(rx_hdr);
+		if (rx_hdr->reserved & ENABLE_DISCONNECT_ACK) {
+			bam_dmux_log("%s: activating disconnect ack\n");
+			disconnect_ack = 1;
+		}
+		dev_kfree_skb_any(rx_skb);
+		break;
+	case BAM_MUX_HDR_CMD_OPEN_NO_A2_PC:
+		bam_dmux_log("%s: opening cid %d PC disabled\n", __func__,
+				rx_hdr->ch_id);
+
+		if (!a2_pc_disabled) {
+			a2_pc_disabled = 1;
+			ul_wakeup();
+		}
+
+		handle_bam_mux_cmd_open(rx_hdr);
+		dev_kfree_skb_any(rx_skb);
+		break;
+	case BAM_MUX_HDR_CMD_CLOSE:
+		/* probably should drop pending write */
+		bam_dmux_log("%s: closing cid %d\n", __func__,
+				rx_hdr->ch_id);
+		spin_lock_irqsave(&bam_ch[rx_hdr->ch_id].lock, flags);
+		bam_ch[rx_hdr->ch_id].status &= ~BAM_CH_REMOTE_OPEN;
+		spin_unlock_irqrestore(&bam_ch[rx_hdr->ch_id].lock, flags);
+		queue_rx();
+		platform_device_unregister(bam_ch[rx_hdr->ch_id].pdev);
+		bam_ch[rx_hdr->ch_id].pdev =
+			platform_device_alloc(bam_ch[rx_hdr->ch_id].name, 2);
+		if (!bam_ch[rx_hdr->ch_id].pdev)
+			pr_err("%s: platform_device_alloc failed\n", __func__);
+		dev_kfree_skb_any(rx_skb);
+		break;
+	default:
+		DMUX_LOG_KERR("%s: dropping invalid hdr. magic %x"
+			   " reserved %d cmd %d pad %d ch %d len %d\n",
+			__func__, rx_hdr->magic_num, rx_hdr->reserved,
+			rx_hdr->cmd, rx_hdr->pad_len, rx_hdr->ch_id,
+			rx_hdr->pkt_len);
+		dev_kfree_skb_any(rx_skb);
+		queue_rx();
+		return;
+	}
+}
+
+static int bam_mux_write_cmd(void *data, uint32_t len)
+{
+	int rc;
+	struct tx_pkt_info *pkt;
+	dma_addr_t dma_address;
+	unsigned long flags;
+
+	pkt = kmalloc(sizeof(struct tx_pkt_info), GFP_ATOMIC);
+	if (pkt == NULL) {
+		pr_err("%s: mem alloc for tx_pkt_info failed\n", __func__);
+		rc = -ENOMEM;
+		return rc;
+	}
+
+	dma_address = dma_map_single(NULL, data, len,
+					DMA_TO_DEVICE);
+	if (!dma_address) {
+		pr_err("%s: dma_map_single() failed\n", __func__);
+		kfree(pkt);
+		rc = -ENOMEM;
+		return rc;
+	}
+	pkt->skb = (struct sk_buff *)(data);
+	pkt->len = len;
+	pkt->dma_address = dma_address;
+	pkt->is_cmd = 1;
+	set_tx_timestamp(pkt);
+	INIT_WORK(&pkt->work, bam_mux_write_done);
+	spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
+	list_add_tail(&pkt->list_node, &bam_tx_pool);
+	rc = sps_transfer_one(bam_tx_pipe, dma_address, len,
+				pkt, SPS_IOVEC_FLAG_INT | SPS_IOVEC_FLAG_EOT);
+	if (rc) {
+		DMUX_LOG_KERR("%s sps_transfer_one failed rc=%d\n",
+			__func__, rc);
+		list_del(&pkt->list_node);
+		DBG_INC_TX_SPS_FAILURE_CNT();
+		spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+		dma_unmap_single(NULL, pkt->dma_address,
+					pkt->len,
+					DMA_TO_DEVICE);
+		kfree(pkt);
+	} else {
+		spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+	}
+
+	ul_packet_written = 1;
+	return rc;
+}
+
+static void bam_mux_write_done(struct work_struct *work)
+{
+	struct sk_buff *skb;
+	struct bam_mux_hdr *hdr;
+	struct tx_pkt_info *info;
+	struct tx_pkt_info *info_expected;
+	unsigned long event_data;
+	unsigned long flags;
+
+	if (in_global_reset)
+		return;
+
+	info = container_of(work, struct tx_pkt_info, work);
+
+	spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
+	info_expected = list_first_entry(&bam_tx_pool,
+			struct tx_pkt_info, list_node);
+	if (unlikely(info != info_expected)) {
+		struct tx_pkt_info *errant_pkt;
+
+		DMUX_LOG_KERR("%s: bam_tx_pool mismatch .next=%p,"
+				" list_node=%p, ts=%u.%09lu\n",
+				__func__, bam_tx_pool.next, &info->list_node,
+				info->ts_sec, info->ts_nsec
+				);
+
+		list_for_each_entry(errant_pkt, &bam_tx_pool, list_node) {
+			DMUX_LOG_KERR("%s: node=%p ts=%u.%09lu\n", __func__,
+			&errant_pkt->list_node, errant_pkt->ts_sec,
+			errant_pkt->ts_nsec);
+
+		}
+		spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+		BUG();
+	}
+	list_del(&info->list_node);
+	spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+
+	if (info->is_cmd) {
+		kfree(info->skb);
+		kfree(info);
+		return;
+	}
+	skb = info->skb;
+	kfree(info);
+	hdr = (struct bam_mux_hdr *)skb->data;
+	DBG_INC_WRITE_CNT(skb->len);
+	event_data = (unsigned long)(skb);
+	spin_lock_irqsave(&bam_ch[hdr->ch_id].lock, flags);
+	bam_ch[hdr->ch_id].num_tx_pkts--;
+	spin_unlock_irqrestore(&bam_ch[hdr->ch_id].lock, flags);
+	if (bam_ch[hdr->ch_id].notify)
+		bam_ch[hdr->ch_id].notify(
+			bam_ch[hdr->ch_id].priv, BAM_DMUX_WRITE_DONE,
+							event_data);
+	else
+		dev_kfree_skb_any(skb);
+}
+
+int msm_bam_dmux_write(uint32_t id, struct sk_buff *skb)
+{
+	int rc = 0;
+	struct bam_mux_hdr *hdr;
+	unsigned long flags;
+	struct sk_buff *new_skb = NULL;
+	dma_addr_t dma_address;
+	struct tx_pkt_info *pkt;
+
+	if (id >= BAM_DMUX_NUM_CHANNELS)
+		return -EINVAL;
+	if (!skb)
+		return -EINVAL;
+	if (!bam_mux_initialized)
+		return -ENODEV;
+
+	DBG("%s: writing to ch %d len %d\n", __func__, id, skb->len);
+	spin_lock_irqsave(&bam_ch[id].lock, flags);
+	if (!bam_ch_is_open(id)) {
+		spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+		pr_err("%s: port not open: %d\n", __func__, bam_ch[id].status);
+		return -ENODEV;
+	}
+
+	if (bam_ch[id].use_wm &&
+	    (bam_ch[id].num_tx_pkts >= HIGH_WATERMARK)) {
+		spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+		pr_err("%s: watermark exceeded: %d\n", __func__, id);
+		return -EAGAIN;
+	}
+	spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+
+	read_lock(&ul_wakeup_lock);
+	if (!bam_is_connected) {
+		read_unlock(&ul_wakeup_lock);
+		ul_wakeup();
+		if (unlikely(in_global_reset == 1))
+			return -EFAULT;
+		read_lock(&ul_wakeup_lock);
+		notify_all(BAM_DMUX_UL_CONNECTED, (unsigned long)(NULL));
+	}
+
+	/* if skb do not have any tailroom for padding,
+	   copy the skb into a new expanded skb */
+	if ((skb->len & 0x3) && (skb_tailroom(skb) < (4 - (skb->len & 0x3)))) {
+		/* revisit, probably dev_alloc_skb and memcpy is effecient */
+		new_skb = skb_copy_expand(skb, skb_headroom(skb),
+					  4 - (skb->len & 0x3), GFP_ATOMIC);
+		if (new_skb == NULL) {
+			pr_err("%s: cannot allocate skb\n", __func__);
+			goto write_fail;
+		}
+		dev_kfree_skb_any(skb);
+		skb = new_skb;
+		DBG_INC_WRITE_CPY(skb->len);
+	}
+
+	hdr = (struct bam_mux_hdr *)skb_push(skb, sizeof(struct bam_mux_hdr));
+
+	/* caller should allocate for hdr and padding
+	   hdr is fine, padding is tricky */
+	hdr->magic_num = BAM_MUX_HDR_MAGIC_NO;
+	hdr->cmd = BAM_MUX_HDR_CMD_DATA;
+	hdr->reserved = 0;
+	hdr->ch_id = id;
+	hdr->pkt_len = skb->len - sizeof(struct bam_mux_hdr);
+	if (skb->len & 0x3)
+		skb_put(skb, 4 - (skb->len & 0x3));
+
+	hdr->pad_len = skb->len - (sizeof(struct bam_mux_hdr) + hdr->pkt_len);
+
+	DBG("%s: data %p, tail %p skb len %d pkt len %d pad len %d\n",
+	    __func__, skb->data, skb->tail, skb->len,
+	    hdr->pkt_len, hdr->pad_len);
+
+	pkt = kmalloc(sizeof(struct tx_pkt_info), GFP_ATOMIC);
+	if (pkt == NULL) {
+		pr_err("%s: mem alloc for tx_pkt_info failed\n", __func__);
+		goto write_fail2;
+	}
+
+	dma_address = dma_map_single(NULL, skb->data, skb->len,
+					DMA_TO_DEVICE);
+	if (!dma_address) {
+		pr_err("%s: dma_map_single() failed\n", __func__);
+		goto write_fail3;
+	}
+	pkt->skb = skb;
+	pkt->dma_address = dma_address;
+	pkt->is_cmd = 0;
+	set_tx_timestamp(pkt);
+	INIT_WORK(&pkt->work, bam_mux_write_done);
+	spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
+	list_add_tail(&pkt->list_node, &bam_tx_pool);
+	rc = sps_transfer_one(bam_tx_pipe, dma_address, skb->len,
+				pkt, SPS_IOVEC_FLAG_INT | SPS_IOVEC_FLAG_EOT);
+	if (rc) {
+		DMUX_LOG_KERR("%s sps_transfer_one failed rc=%d\n",
+			__func__, rc);
+		list_del(&pkt->list_node);
+		DBG_INC_TX_SPS_FAILURE_CNT();
+		spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+		dma_unmap_single(NULL, pkt->dma_address,
+					pkt->skb->len,	DMA_TO_DEVICE);
+		kfree(pkt);
+		if (new_skb)
+			dev_kfree_skb_any(new_skb);
+	} else {
+		spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+		spin_lock_irqsave(&bam_ch[id].lock, flags);
+		bam_ch[id].num_tx_pkts++;
+		spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+	}
+	ul_packet_written = 1;
+	read_unlock(&ul_wakeup_lock);
+	return rc;
+
+write_fail3:
+	kfree(pkt);
+write_fail2:
+	if (new_skb)
+		dev_kfree_skb_any(new_skb);
+write_fail:
+	read_unlock(&ul_wakeup_lock);
+	return -ENOMEM;
+}
+
+int msm_bam_dmux_open(uint32_t id, void *priv,
+			void (*notify)(void *, int, unsigned long))
+{
+	struct bam_mux_hdr *hdr;
+	unsigned long flags;
+	int rc = 0;
+
+	DBG("%s: opening ch %d\n", __func__, id);
+	if (!bam_mux_initialized) {
+		DBG("%s: not inititialized\n", __func__);
+		return -ENODEV;
+	}
+	if (id >= BAM_DMUX_NUM_CHANNELS) {
+		pr_err("%s: invalid channel id %d\n", __func__, id);
+		return -EINVAL;
+	}
+	if (notify == NULL) {
+		pr_err("%s: notify function is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	hdr = kmalloc(sizeof(struct bam_mux_hdr), GFP_KERNEL);
+	if (hdr == NULL) {
+		pr_err("%s: hdr kmalloc failed. ch: %d\n", __func__, id);
+		return -ENOMEM;
+	}
+	spin_lock_irqsave(&bam_ch[id].lock, flags);
+	if (bam_ch_is_open(id)) {
+		DBG("%s: Already opened %d\n", __func__, id);
+		spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+		kfree(hdr);
+		goto open_done;
+	}
+	if (!bam_ch_is_remote_open(id)) {
+		DBG("%s: Remote not open; ch: %d\n", __func__, id);
+		spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+		kfree(hdr);
+		return -ENODEV;
+	}
+
+	bam_ch[id].notify = notify;
+	bam_ch[id].priv = priv;
+	bam_ch[id].status |= BAM_CH_LOCAL_OPEN;
+	bam_ch[id].num_tx_pkts = 0;
+	bam_ch[id].use_wm = 0;
+	spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+
+	read_lock(&ul_wakeup_lock);
+	if (!bam_is_connected) {
+		read_unlock(&ul_wakeup_lock);
+		ul_wakeup();
+		if (unlikely(in_global_reset == 1))
+			return -EFAULT;
+		read_lock(&ul_wakeup_lock);
+		notify_all(BAM_DMUX_UL_CONNECTED, (unsigned long)(NULL));
+	}
+
+	hdr->magic_num = BAM_MUX_HDR_MAGIC_NO;
+	hdr->cmd = BAM_MUX_HDR_CMD_OPEN;
+	hdr->reserved = 0;
+	hdr->ch_id = id;
+	hdr->pkt_len = 0;
+	hdr->pad_len = 0;
+
+	rc = bam_mux_write_cmd((void *)hdr, sizeof(struct bam_mux_hdr));
+	read_unlock(&ul_wakeup_lock);
+
+open_done:
+	DBG("%s: opened ch %d\n", __func__, id);
+	return rc;
+}
+
+int msm_bam_dmux_close(uint32_t id)
+{
+	struct bam_mux_hdr *hdr;
+	unsigned long flags;
+	int rc;
+
+	if (id >= BAM_DMUX_NUM_CHANNELS)
+		return -EINVAL;
+	DBG("%s: closing ch %d\n", __func__, id);
+	if (!bam_mux_initialized)
+		return -ENODEV;
+
+	read_lock(&ul_wakeup_lock);
+	if (!bam_is_connected && !bam_ch_is_in_reset(id)) {
+		read_unlock(&ul_wakeup_lock);
+		ul_wakeup();
+		if (unlikely(in_global_reset == 1))
+			return -EFAULT;
+		read_lock(&ul_wakeup_lock);
+		notify_all(BAM_DMUX_UL_CONNECTED, (unsigned long)(NULL));
+	}
+
+	spin_lock_irqsave(&bam_ch[id].lock, flags);
+	bam_ch[id].notify = NULL;
+	bam_ch[id].priv = NULL;
+	bam_ch[id].status &= ~BAM_CH_LOCAL_OPEN;
+	spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+
+	if (bam_ch_is_in_reset(id)) {
+		read_unlock(&ul_wakeup_lock);
+		bam_ch[id].status &= ~BAM_CH_IN_RESET;
+		return 0;
+	}
+
+	hdr = kmalloc(sizeof(struct bam_mux_hdr), GFP_ATOMIC);
+	if (hdr == NULL) {
+		pr_err("%s: hdr kmalloc failed. ch: %d\n", __func__, id);
+		read_unlock(&ul_wakeup_lock);
+		return -ENOMEM;
+	}
+	hdr->magic_num = BAM_MUX_HDR_MAGIC_NO;
+	hdr->cmd = BAM_MUX_HDR_CMD_CLOSE;
+	hdr->reserved = 0;
+	hdr->ch_id = id;
+	hdr->pkt_len = 0;
+	hdr->pad_len = 0;
+
+	rc = bam_mux_write_cmd((void *)hdr, sizeof(struct bam_mux_hdr));
+	read_unlock(&ul_wakeup_lock);
+
+	DBG("%s: closed ch %d\n", __func__, id);
+	return rc;
+}
+
+int msm_bam_dmux_is_ch_full(uint32_t id)
+{
+	unsigned long flags;
+	int ret;
+
+	if (id >= BAM_DMUX_NUM_CHANNELS)
+		return -EINVAL;
+
+	spin_lock_irqsave(&bam_ch[id].lock, flags);
+	bam_ch[id].use_wm = 1;
+	ret = bam_ch[id].num_tx_pkts >= HIGH_WATERMARK;
+	DBG("%s: ch %d num tx pkts=%d, HWM=%d\n", __func__,
+	     id, bam_ch[id].num_tx_pkts, ret);
+	if (!bam_ch_is_local_open(id)) {
+		ret = -ENODEV;
+		pr_err("%s: port not open: %d\n", __func__, bam_ch[id].status);
+	}
+	spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+
+	return ret;
+}
+
+int msm_bam_dmux_is_ch_low(uint32_t id)
+{
+	unsigned long flags;
+	int ret;
+
+	if (id >= BAM_DMUX_NUM_CHANNELS)
+		return -EINVAL;
+
+	spin_lock_irqsave(&bam_ch[id].lock, flags);
+	bam_ch[id].use_wm = 1;
+	ret = bam_ch[id].num_tx_pkts <= LOW_WATERMARK;
+	DBG("%s: ch %d num tx pkts=%d, LWM=%d\n", __func__,
+	     id, bam_ch[id].num_tx_pkts, ret);
+	if (!bam_ch_is_local_open(id)) {
+		ret = -ENODEV;
+		pr_err("%s: port not open: %d\n", __func__, bam_ch[id].status);
+	}
+	spin_unlock_irqrestore(&bam_ch[id].lock, flags);
+
+	return ret;
+}
+
+static void rx_switch_to_interrupt_mode(void)
+{
+	struct sps_connect cur_rx_conn;
+	struct sps_iovec iov;
+	struct rx_pkt_info *info;
+	int ret;
+
+	/*
+	 * Attempt to enable interrupts - if this fails,
+	 * continue polling and we will retry later.
+	 */
+	ret = sps_get_config(bam_rx_pipe, &cur_rx_conn);
+	if (ret) {
+		pr_err("%s: sps_get_config() failed %d\n", __func__, ret);
+		goto fail;
+	}
+
+	rx_register_event.options = SPS_O_EOT;
+	ret = sps_register_event(bam_rx_pipe, &rx_register_event);
+	if (ret) {
+		pr_err("%s: sps_register_event() failed %d\n", __func__, ret);
+		goto fail;
+	}
+
+	cur_rx_conn.options = SPS_O_AUTO_ENABLE |
+		SPS_O_EOT | SPS_O_ACK_TRANSFERS;
+	ret = sps_set_config(bam_rx_pipe, &cur_rx_conn);
+	if (ret) {
+		pr_err("%s: sps_set_config() failed %d\n", __func__, ret);
+		goto fail;
+	}
+	polling_mode = 0;
+	release_wakelock();
+
+	/* handle any rx packets before interrupt was enabled */
+	while (bam_connection_is_active && !polling_mode) {
+		ret = sps_get_iovec(bam_rx_pipe, &iov);
+		if (ret) {
+			pr_err("%s: sps_get_iovec failed %d\n",
+					__func__, ret);
+			break;
+		}
+		if (iov.addr == 0)
+			break;
+
+		mutex_lock(&bam_rx_pool_mutexlock);
+		if (unlikely(list_empty(&bam_rx_pool))) {
+			mutex_unlock(&bam_rx_pool_mutexlock);
+			continue;
+		}
+		info = list_first_entry(&bam_rx_pool, struct rx_pkt_info,
+							list_node);
+		list_del(&info->list_node);
+		--bam_rx_pool_len;
+		mutex_unlock(&bam_rx_pool_mutexlock);
+		if (info->dma_address != iov.addr)
+			DMUX_LOG_KERR("%s: iovec %p != dma %p\n",
+				__func__,
+				(void *)info->dma_address, (void *)iov.addr);
+		handle_bam_mux_cmd(&info->work);
+	}
+	return;
+
+fail:
+	pr_err("%s: reverting to polling\n", __func__);
+	queue_work_on(0, bam_mux_rx_workqueue, &rx_timer_work);
+}
+
+static void rx_timer_work_func(struct work_struct *work)
+{
+	struct sps_iovec iov;
+	struct rx_pkt_info *info;
+	int inactive_cycles = 0;
+	int ret;
+
+	while (bam_connection_is_active) { /* timer loop */
+		++inactive_cycles;
+		while (bam_connection_is_active) { /* deplete queue loop */
+			if (in_global_reset)
+				return;
+
+			ret = sps_get_iovec(bam_rx_pipe, &iov);
+			if (ret) {
+				pr_err("%s: sps_get_iovec failed %d\n",
+						__func__, ret);
+				break;
+			}
+			if (iov.addr == 0)
+				break;
+			inactive_cycles = 0;
+			mutex_lock(&bam_rx_pool_mutexlock);
+			if (unlikely(list_empty(&bam_rx_pool))) {
+				mutex_unlock(&bam_rx_pool_mutexlock);
+				continue;
+			}
+			info = list_first_entry(&bam_rx_pool,
+					struct rx_pkt_info,	list_node);
+			--bam_rx_pool_len;
+			list_del(&info->list_node);
+			mutex_unlock(&bam_rx_pool_mutexlock);
+			handle_bam_mux_cmd(&info->work);
+		}
+
+		if (inactive_cycles == POLLING_INACTIVITY) {
+			rx_switch_to_interrupt_mode();
+			break;
+		}
+
+		usleep_range(POLLING_MIN_SLEEP, POLLING_MAX_SLEEP);
+	}
+}
+
+static void bam_mux_tx_notify(struct sps_event_notify *notify)
+{
+	struct tx_pkt_info *pkt;
+
+	DBG("%s: event %d notified\n", __func__, notify->event_id);
+
+	if (in_global_reset)
+		return;
+
+	switch (notify->event_id) {
+	case SPS_EVENT_EOT:
+		pkt = notify->data.transfer.user;
+		if (!pkt->is_cmd)
+			dma_unmap_single(NULL, pkt->dma_address,
+						pkt->skb->len,
+						DMA_TO_DEVICE);
+		else
+			dma_unmap_single(NULL, pkt->dma_address,
+						pkt->len,
+						DMA_TO_DEVICE);
+		queue_work(bam_mux_tx_workqueue, &pkt->work);
+		break;
+	default:
+		pr_err("%s: recieved unexpected event id %d\n", __func__,
+			notify->event_id);
+	}
+}
+
+static void bam_mux_rx_notify(struct sps_event_notify *notify)
+{
+	int ret;
+	struct sps_connect cur_rx_conn;
+
+	DBG("%s: event %d notified\n", __func__, notify->event_id);
+
+	if (in_global_reset)
+		return;
+
+	switch (notify->event_id) {
+	case SPS_EVENT_EOT:
+		/* attempt to disable interrupts in this pipe */
+		if (!polling_mode) {
+			ret = sps_get_config(bam_rx_pipe, &cur_rx_conn);
+			if (ret) {
+				pr_err("%s: sps_get_config() failed %d, interrupts"
+					" not disabled\n", __func__, ret);
+				break;
+			}
+			cur_rx_conn.options = SPS_O_AUTO_ENABLE |
+				SPS_O_ACK_TRANSFERS | SPS_O_POLL;
+			ret = sps_set_config(bam_rx_pipe, &cur_rx_conn);
+			if (ret) {
+				pr_err("%s: sps_set_config() failed %d, interrupts"
+					" not disabled\n", __func__, ret);
+				break;
+			}
+			grab_wakelock();
+			polling_mode = 1;
+			/*
+			 * run on core 0 so that netif_rx() in rmnet uses only
+			 * one queue
+			 */
+			queue_work_on(0, bam_mux_rx_workqueue, &rx_timer_work);
+		}
+		break;
+	default:
+		pr_err("%s: recieved unexpected event id %d\n", __func__,
+			notify->event_id);
+	}
+}
+
+#ifdef CONFIG_DEBUG_FS
+
+static int debug_tbl(char *buf, int max)
+{
+	int i = 0;
+	int j;
+
+	for (j = 0; j < BAM_DMUX_NUM_CHANNELS; ++j) {
+		i += scnprintf(buf + i, max - i,
+			"ch%02d  local open=%s  remote open=%s\n",
+			j, bam_ch_is_local_open(j) ? "Y" : "N",
+			bam_ch_is_remote_open(j) ? "Y" : "N");
+	}
+
+	return i;
+}
+
+static int debug_ul_pkt_cnt(char *buf, int max)
+{
+	struct list_head *p;
+	unsigned long flags;
+	int n = 0;
+
+	spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
+	__list_for_each(p, &bam_tx_pool) {
+		++n;
+	}
+	spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+
+	return scnprintf(buf, max, "Number of UL packets in flight: %d\n", n);
+}
+
+static int debug_stats(char *buf, int max)
+{
+	int i = 0;
+
+	i += scnprintf(buf + i, max - i,
+			"skb read cnt:    %u\n"
+			"skb write cnt:   %u\n"
+			"skb copy cnt:    %u\n"
+			"skb copy bytes:  %u\n"
+			"sps tx failures: %u\n"
+			"sps tx stalls:   %u\n"
+			"rx queue len:    %d\n"
+			"a2 ack out cnt:  %d\n"
+			"a2 ack in cnt:   %d\n"
+			"a2 pwr cntl in:  %d\n",
+			bam_dmux_read_cnt,
+			bam_dmux_write_cnt,
+			bam_dmux_write_cpy_cnt,
+			bam_dmux_write_cpy_bytes,
+			bam_dmux_tx_sps_failure_cnt,
+			bam_dmux_tx_stall_cnt,
+			bam_rx_pool_len,
+			atomic_read(&bam_dmux_ack_out_cnt),
+			atomic_read(&bam_dmux_ack_in_cnt),
+			atomic_read(&bam_dmux_a2_pwr_cntl_in_cnt)
+			);
+
+	return i;
+}
+
+static int debug_log(char *buff, int max, loff_t *ppos)
+{
+	unsigned long flags;
+	int i = 0;
+
+	if (bam_dmux_state_logging_disabled) {
+		i += scnprintf(buff - i, max - i, "Logging disabled\n");
+		return i;
+	}
+
+	if (*ppos == 0) {
+		i += scnprintf(buff - i, max - i,
+			"<DMUX> timestamp FLAGS [Message]\n"
+			"FLAGS:\n"
+			"\tD: 1 = Power collapse disabled\n"
+			"\tR: 1 = in global reset\n"
+			"\tP: 1 = BAM is powered up\n"
+			"\tA: 1 = BAM initialized and ready for data\n"
+			"\n"
+			"\tV: 1 = Uplink vote for power\n"
+			"\tU: 1 = Uplink active\n"
+			"\tW: 1 = Uplink Wait-for-ack\n"
+			"\tA: 1 = Uplink ACK received\n"
+			"\t#: >=1 On-demand uplink vote\n"
+			"\tD: 1 = Disconnect ACK active\n"
+				);
+		buff += i;
+	}
+
+	spin_lock_irqsave(&bam_dmux_logging_spinlock, flags);
+	while (kfifo_len(&bam_dmux_state_log)
+			&& (i + LOG_MESSAGE_MAX_SIZE) < max) {
+		int k_len;
+		k_len = kfifo_out(&bam_dmux_state_log,
+				buff, LOG_MESSAGE_MAX_SIZE);
+		if (k_len != LOG_MESSAGE_MAX_SIZE) {
+			pr_err("%s: retrieve failure %d\n", __func__, k_len);
+			break;
+		}
+
+		/* keep non-null portion of string and add line break */
+		k_len = strnlen(buff, LOG_MESSAGE_MAX_SIZE);
+		buff += k_len;
+		i += k_len;
+		if (k_len && *(buff - 1) != '\n') {
+			*buff++ = '\n';
+			++i;
+		}
+	}
+	spin_unlock_irqrestore(&bam_dmux_logging_spinlock, flags);
+
+	return i;
+}
+
+#define DEBUG_BUFMAX 4096
+static char debug_buffer[DEBUG_BUFMAX];
+
+static ssize_t debug_read(struct file *file, char __user *buf,
+				size_t count, loff_t *ppos)
+{
+	int (*fill)(char *buf, int max) = file->private_data;
+	int bsize = fill(debug_buffer, DEBUG_BUFMAX);
+	return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
+}
+
+static ssize_t debug_read_multiple(struct file *file, char __user *buff,
+				size_t count, loff_t *ppos)
+{
+	int (*util_func)(char *buf, int max, loff_t *) = file->private_data;
+	char *buffer;
+	int bsize;
+
+	buffer = kmalloc(count, GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	bsize = util_func(buffer, count, ppos);
+
+	if (bsize >= 0) {
+		if (copy_to_user(buff, buffer, bsize)) {
+			kfree(buffer);
+			return -EFAULT;
+		}
+		*ppos += bsize;
+	}
+	kfree(buffer);
+	return bsize;
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+
+static const struct file_operations debug_ops = {
+	.read = debug_read,
+	.open = debug_open,
+};
+
+static const struct file_operations debug_ops_multiple = {
+	.read = debug_read_multiple,
+	.open = debug_open,
+};
+
+static void debug_create(const char *name, mode_t mode,
+				struct dentry *dent,
+				int (*fill)(char *buf, int max))
+{
+	struct dentry *file;
+
+	file = debugfs_create_file(name, mode, dent, fill, &debug_ops);
+	if (IS_ERR(file))
+		pr_err("%s: debugfs create failed %d\n", __func__,
+				(int)PTR_ERR(file));
+}
+
+static void debug_create_multiple(const char *name, mode_t mode,
+				struct dentry *dent,
+				int (*fill)(char *buf, int max, loff_t *ppos))
+{
+	struct dentry *file;
+
+	file = debugfs_create_file(name, mode, dent, fill, &debug_ops_multiple);
+	if (IS_ERR(file))
+		pr_err("%s: debugfs create failed %d\n", __func__,
+				(int)PTR_ERR(file));
+}
+#endif
+
+static void notify_all(int event, unsigned long data)
+{
+	int i;
+	struct list_head *temp;
+	struct outside_notify_func *func;
+
+	for (i = 0; i < BAM_DMUX_NUM_CHANNELS; ++i) {
+		if (bam_ch_is_open(i)) {
+			bam_ch[i].notify(bam_ch[i].priv, event, data);
+			bam_dmux_log("%s: cid=%d, event=%d, data=%lu\n",
+					__func__, i, event, data);
+		}
+	}
+
+	__list_for_each(temp, &bam_other_notify_funcs) {
+		func = container_of(temp, struct outside_notify_func,
+								list_node);
+		func->notify(func->priv, event, data);
+	}
+}
+
+static void kickoff_ul_wakeup_func(struct work_struct *work)
+{
+	read_lock(&ul_wakeup_lock);
+	if (!bam_is_connected) {
+		read_unlock(&ul_wakeup_lock);
+		ul_wakeup();
+		if (unlikely(in_global_reset == 1))
+			return;
+		read_lock(&ul_wakeup_lock);
+		ul_packet_written = 1;
+		notify_all(BAM_DMUX_UL_CONNECTED, (unsigned long)(NULL));
+	}
+	read_unlock(&ul_wakeup_lock);
+}
+
+int msm_bam_dmux_kickoff_ul_wakeup(void)
+{
+	int is_connected;
+
+	read_lock(&ul_wakeup_lock);
+	ul_packet_written = 1;
+	is_connected = bam_is_connected;
+	if (!is_connected)
+		queue_work(bam_mux_tx_workqueue, &kickoff_ul_wakeup);
+	read_unlock(&ul_wakeup_lock);
+
+	return is_connected;
+}
+
+static void power_vote(int vote)
+{
+	bam_dmux_log("%s: curr=%d, vote=%d\n", __func__,
+			bam_dmux_uplink_vote, vote);
+
+	if (bam_dmux_uplink_vote == vote)
+		bam_dmux_log("%s: warning - duplicate power vote\n", __func__);
+
+	bam_dmux_uplink_vote = vote;
+	if (vote)
+		smsm_change_state(SMSM_APPS_STATE, 0, SMSM_A2_POWER_CONTROL);
+	else
+		smsm_change_state(SMSM_APPS_STATE, SMSM_A2_POWER_CONTROL, 0);
+}
+
+/*
+ * @note:  Must be called with ul_wakeup_lock locked.
+ */
+static inline void ul_powerdown(void)
+{
+	bam_dmux_log("%s: powerdown\n", __func__);
+	verify_tx_queue_is_empty(__func__);
+
+	if (a2_pc_disabled) {
+		wait_for_dfab = 1;
+		INIT_COMPLETION(dfab_unvote_completion);
+		release_wakelock();
+	} else {
+		wait_for_ack = 1;
+		INIT_COMPLETION(ul_wakeup_ack_completion);
+		power_vote(0);
+	}
+	bam_is_connected = 0;
+	notify_all(BAM_DMUX_UL_DISCONNECTED, (unsigned long)(NULL));
+}
+
+static inline void ul_powerdown_finish(void)
+{
+	if (a2_pc_disabled && wait_for_dfab) {
+		unvote_dfab();
+		complete_all(&dfab_unvote_completion);
+		wait_for_dfab = 0;
+	}
+}
+
+/*
+ * Votes for UL power and returns current power state.
+ *
+ * @returns true if currently connected
+ */
+int msm_bam_dmux_ul_power_vote(void)
+{
+	int is_connected;
+
+	read_lock(&ul_wakeup_lock);
+	atomic_inc(&ul_ondemand_vote);
+	is_connected = bam_is_connected;
+	if (!is_connected)
+		queue_work(bam_mux_tx_workqueue, &kickoff_ul_wakeup);
+	read_unlock(&ul_wakeup_lock);
+
+	return is_connected;
+}
+
+/*
+ * Unvotes for UL power.
+ *
+ * @returns true if vote count is 0 (UL shutdown possible)
+ */
+int msm_bam_dmux_ul_power_unvote(void)
+{
+	int vote;
+
+	read_lock(&ul_wakeup_lock);
+	vote = atomic_dec_return(&ul_ondemand_vote);
+	if (unlikely(vote) < 0)
+		DMUX_LOG_KERR("%s: invalid power vote %d\n", __func__, vote);
+	read_unlock(&ul_wakeup_lock);
+
+	return vote == 0;
+}
+
+int msm_bam_dmux_reg_notify(void *priv,
+			void (*notify)(void *priv, int event_type,
+						unsigned long data))
+{
+	struct outside_notify_func *func;
+
+	if (!notify)
+		return -EINVAL;
+
+	func = kmalloc(sizeof(struct outside_notify_func), GFP_KERNEL);
+	if (!func)
+		return -ENOMEM;
+
+	func->notify = notify;
+	func->priv = priv;
+	list_add(&func->list_node, &bam_other_notify_funcs);
+
+	return 0;
+}
+
+static void ul_timeout(struct work_struct *work)
+{
+	unsigned long flags;
+	int ret;
+
+	if (in_global_reset)
+		return;
+	ret = write_trylock_irqsave(&ul_wakeup_lock, flags);
+	if (!ret) { /* failed to grab lock, reschedule and bail */
+		schedule_delayed_work(&ul_timeout_work,
+				msecs_to_jiffies(UL_TIMEOUT_DELAY));
+		return;
+	}
+	if (bam_is_connected) {
+		if (!ul_packet_written) {
+			spin_lock(&bam_tx_pool_spinlock);
+			if (!list_empty(&bam_tx_pool)) {
+				struct tx_pkt_info *info;
+
+				info = list_first_entry(&bam_tx_pool,
+						struct tx_pkt_info, list_node);
+				DMUX_LOG_KERR("%s: UL delayed ts=%u.%09lu\n",
+					__func__, info->ts_sec, info->ts_nsec);
+				DBG_INC_TX_STALL_CNT();
+				ul_packet_written = 1;
+			}
+			spin_unlock(&bam_tx_pool_spinlock);
+		}
+
+		if (ul_packet_written || atomic_read(&ul_ondemand_vote)) {
+			bam_dmux_log("%s: pkt written %d\n",
+				__func__, ul_packet_written);
+			ul_packet_written = 0;
+			schedule_delayed_work(&ul_timeout_work,
+					msecs_to_jiffies(UL_TIMEOUT_DELAY));
+		} else {
+			ul_powerdown();
+		}
+	}
+	write_unlock_irqrestore(&ul_wakeup_lock, flags);
+	ul_powerdown_finish();
+}
+
+static int ssrestart_check(void)
+{
+	DMUX_LOG_KERR("%s: modem timeout: BAM DMUX disabled\n", __func__);
+	in_global_reset = 1;
+	if (get_restart_level() <= RESET_SOC)
+		DMUX_LOG_KERR("%s: ssrestart not enabled\n", __func__);
+	return 1;
+}
+
+static void ul_wakeup(void)
+{
+	int ret;
+	int do_vote_dfab = 0;
+
+	mutex_lock(&wakeup_lock);
+	if (bam_is_connected) { /* bam got connected before lock grabbed */
+		bam_dmux_log("%s Already awake\n", __func__);
+		mutex_unlock(&wakeup_lock);
+		return;
+	}
+
+	/*
+	 * if someone is voting for UL before bam is inited (modem up first
+	 * time), set flag for init to kickoff ul wakeup once bam is inited
+	 */
+	mutex_lock(&delayed_ul_vote_lock);
+	if (unlikely(!bam_mux_initialized)) {
+		need_delayed_ul_vote = 1;
+		mutex_unlock(&delayed_ul_vote_lock);
+		mutex_unlock(&wakeup_lock);
+		return;
+	}
+	mutex_unlock(&delayed_ul_vote_lock);
+
+	if (a2_pc_disabled) {
+		/*
+		 * don't grab the wakelock the first time because it is
+		 * already grabbed when a2 powers on
+		 */
+		if (likely(a2_pc_disabled_wakelock_skipped)) {
+			grab_wakelock();
+			do_vote_dfab = 1; /* vote must occur after wait */
+		} else {
+			a2_pc_disabled_wakelock_skipped = 1;
+		}
+		if (wait_for_dfab) {
+			ret = wait_for_completion_timeout(
+					&dfab_unvote_completion, HZ);
+			BUG_ON(ret == 0);
+		}
+		if (likely(do_vote_dfab))
+			vote_dfab();
+		schedule_delayed_work(&ul_timeout_work,
+				msecs_to_jiffies(UL_TIMEOUT_DELAY));
+		bam_is_connected = 1;
+		mutex_unlock(&wakeup_lock);
+		return;
+	}
+
+	/*
+	 * must wait for the previous power down request to have been acked
+	 * chances are it already came in and this will just fall through
+	 * instead of waiting
+	 */
+	if (wait_for_ack) {
+		bam_dmux_log("%s waiting for previous ack\n", __func__);
+		ret = wait_for_completion_timeout(
+					&ul_wakeup_ack_completion, HZ);
+		wait_for_ack = 0;
+		if (unlikely(ret == 0) && ssrestart_check()) {
+			mutex_unlock(&wakeup_lock);
+			bam_dmux_log("%s timeout previous ack\n", __func__);
+			return;
+		}
+	}
+	INIT_COMPLETION(ul_wakeup_ack_completion);
+	power_vote(1);
+	bam_dmux_log("%s waiting for wakeup ack\n", __func__);
+	ret = wait_for_completion_timeout(&ul_wakeup_ack_completion, HZ);
+	if (unlikely(ret == 0) && ssrestart_check()) {
+		mutex_unlock(&wakeup_lock);
+		bam_dmux_log("%s timeout wakeup ack\n", __func__);
+		return;
+	}
+	bam_dmux_log("%s waiting completion\n", __func__);
+	ret = wait_for_completion_timeout(&bam_connection_completion, HZ);
+	if (unlikely(ret == 0) && ssrestart_check()) {
+		mutex_unlock(&wakeup_lock);
+		bam_dmux_log("%s timeout power on\n", __func__);
+		return;
+	}
+
+	bam_is_connected = 1;
+	bam_dmux_log("%s complete\n", __func__);
+	schedule_delayed_work(&ul_timeout_work,
+				msecs_to_jiffies(UL_TIMEOUT_DELAY));
+	mutex_unlock(&wakeup_lock);
+}
+
+static void reconnect_to_bam(void)
+{
+	int i;
+
+	in_global_reset = 0;
+	vote_dfab();
+	i = sps_device_reset(a2_device_handle);
+	if (i)
+		pr_err("%s: device reset failed rc = %d\n", __func__, i);
+	i = sps_connect(bam_tx_pipe, &tx_connection);
+	if (i)
+		pr_err("%s: tx connection failed rc = %d\n", __func__, i);
+	i = sps_connect(bam_rx_pipe, &rx_connection);
+	if (i)
+		pr_err("%s: rx connection failed rc = %d\n", __func__, i);
+	i = sps_register_event(bam_tx_pipe, &tx_register_event);
+	if (i)
+		pr_err("%s: tx event reg failed rc = %d\n", __func__, i);
+	i = sps_register_event(bam_rx_pipe, &rx_register_event);
+	if (i)
+		pr_err("%s: rx event reg failed rc = %d\n", __func__, i);
+
+	bam_connection_is_active = 1;
+
+	if (polling_mode)
+		rx_switch_to_interrupt_mode();
+
+	toggle_apps_ack();
+	complete_all(&bam_connection_completion);
+	queue_rx();
+}
+
+static void disconnect_to_bam(void)
+{
+	struct list_head *node;
+	struct rx_pkt_info *info;
+	unsigned long flags;
+
+	bam_connection_is_active = 0;
+
+	/* handle disconnect during active UL */
+	write_lock_irqsave(&ul_wakeup_lock, flags);
+	if (bam_is_connected) {
+		bam_dmux_log("%s: UL active - forcing powerdown\n", __func__);
+		ul_powerdown();
+	}
+	write_unlock_irqrestore(&ul_wakeup_lock, flags);
+	ul_powerdown_finish();
+
+	/* tear down BAM connection */
+	INIT_COMPLETION(bam_connection_completion);
+	sps_disconnect(bam_tx_pipe);
+	sps_disconnect(bam_rx_pipe);
+	unvote_dfab();
+	__memzero(rx_desc_mem_buf.base, rx_desc_mem_buf.size);
+	__memzero(tx_desc_mem_buf.base, tx_desc_mem_buf.size);
+
+	mutex_lock(&bam_rx_pool_mutexlock);
+	while (!list_empty(&bam_rx_pool)) {
+		node = bam_rx_pool.next;
+		list_del(node);
+		info = container_of(node, struct rx_pkt_info, list_node);
+		dma_unmap_single(NULL, info->dma_address, BUFFER_SIZE,
+							DMA_FROM_DEVICE);
+		dev_kfree_skb_any(info->skb);
+		kfree(info);
+	}
+	bam_rx_pool_len = 0;
+	mutex_unlock(&bam_rx_pool_mutexlock);
+
+	if (disconnect_ack)
+		toggle_apps_ack();
+
+	verify_tx_queue_is_empty(__func__);
+}
+
+static void vote_dfab(void)
+{
+	int rc;
+
+	bam_dmux_log("%s\n", __func__);
+	mutex_lock(&dfab_status_lock);
+	if (dfab_is_on) {
+		bam_dmux_log("%s: dfab is already on\n", __func__);
+		mutex_unlock(&dfab_status_lock);
+		return;
+	}
+	rc = clk_prepare_enable(dfab_clk);
+	if (rc)
+		DMUX_LOG_KERR("bam_dmux vote for dfab failed rc = %d\n", rc);
+	rc = clk_prepare_enable(xo_clk);
+	if (rc)
+		DMUX_LOG_KERR("bam_dmux vote for xo failed rc = %d\n", rc);
+	dfab_is_on = 1;
+	mutex_unlock(&dfab_status_lock);
+}
+
+static void unvote_dfab(void)
+{
+	bam_dmux_log("%s\n", __func__);
+	mutex_lock(&dfab_status_lock);
+	if (!dfab_is_on) {
+		DMUX_LOG_KERR("%s: dfab is already off\n", __func__);
+		dump_stack();
+		mutex_unlock(&dfab_status_lock);
+		return;
+	}
+	clk_disable_unprepare(dfab_clk);
+	clk_disable_unprepare(xo_clk);
+	dfab_is_on = 0;
+	mutex_unlock(&dfab_status_lock);
+}
+
+/* reference counting wrapper around wakelock */
+static void grab_wakelock(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&wakelock_reference_lock, flags);
+	bam_dmux_log("%s: ref count = %d\n", __func__,
+						wakelock_reference_count);
+	if (wakelock_reference_count == 0)
+		wake_lock(&bam_wakelock);
+	++wakelock_reference_count;
+	spin_unlock_irqrestore(&wakelock_reference_lock, flags);
+}
+
+static void release_wakelock(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&wakelock_reference_lock, flags);
+	if (wakelock_reference_count == 0) {
+		DMUX_LOG_KERR("%s: bam_dmux wakelock not locked\n", __func__);
+		dump_stack();
+		spin_unlock_irqrestore(&wakelock_reference_lock, flags);
+		return;
+	}
+	bam_dmux_log("%s: ref count = %d\n", __func__,
+						wakelock_reference_count);
+	--wakelock_reference_count;
+	if (wakelock_reference_count == 0)
+		wake_unlock(&bam_wakelock);
+	spin_unlock_irqrestore(&wakelock_reference_lock, flags);
+}
+
+static int restart_notifier_cb(struct notifier_block *this,
+				unsigned long code,
+				void *data)
+{
+	int i;
+	struct list_head *node;
+	struct tx_pkt_info *info;
+	int temp_remote_status;
+	unsigned long flags;
+
+	if (code != SUBSYS_AFTER_SHUTDOWN)
+		return NOTIFY_DONE;
+
+	bam_dmux_log("%s: begin\n", __func__);
+	in_global_reset = 1;
+
+	/* Handle uplink Powerdown */
+	write_lock_irqsave(&ul_wakeup_lock, flags);
+	if (bam_is_connected) {
+		ul_powerdown();
+		wait_for_ack = 0;
+	}
+	/*
+	 * if modem crash during ul_wakeup(), power_vote is 1, needs to be
+	 * reset to 0.  harmless if bam_is_connected check above passes
+	 */
+	power_vote(0);
+	write_unlock_irqrestore(&ul_wakeup_lock, flags);
+	ul_powerdown_finish();
+	a2_pc_disabled = 0;
+	a2_pc_disabled_wakelock_skipped = 0;
+	disconnect_ack = 0;
+
+	/* Cleanup Channel States */
+	for (i = 0; i < BAM_DMUX_NUM_CHANNELS; ++i) {
+		temp_remote_status = bam_ch_is_remote_open(i);
+		bam_ch[i].status &= ~BAM_CH_REMOTE_OPEN;
+		bam_ch[i].num_tx_pkts = 0;
+		if (bam_ch_is_local_open(i))
+			bam_ch[i].status |= BAM_CH_IN_RESET;
+		if (temp_remote_status) {
+			platform_device_unregister(bam_ch[i].pdev);
+			bam_ch[i].pdev = platform_device_alloc(
+						bam_ch[i].name, 2);
+		}
+	}
+
+	/* Cleanup pending UL data */
+	spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
+	while (!list_empty(&bam_tx_pool)) {
+		node = bam_tx_pool.next;
+		list_del(node);
+		info = container_of(node, struct tx_pkt_info,
+							list_node);
+		if (!info->is_cmd) {
+			dma_unmap_single(NULL, info->dma_address,
+						info->skb->len,
+						DMA_TO_DEVICE);
+			dev_kfree_skb_any(info->skb);
+		} else {
+			dma_unmap_single(NULL, info->dma_address,
+						info->len,
+						DMA_TO_DEVICE);
+			kfree(info->skb);
+		}
+		kfree(info);
+	}
+	spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+
+	bam_dmux_log("%s: complete\n", __func__);
+	return NOTIFY_DONE;
+}
+
+static int bam_init(void)
+{
+	u32 h;
+	dma_addr_t dma_addr;
+	int ret;
+	void *a2_virt_addr;
+	int skip_iounmap = 0;
+
+	vote_dfab();
+	/* init BAM */
+	a2_virt_addr = ioremap_nocache(A2_PHYS_BASE, A2_PHYS_SIZE);
+	if (!a2_virt_addr) {
+		pr_err("%s: ioremap failed\n", __func__);
+		ret = -ENOMEM;
+		goto ioremap_failed;
+	}
+	a2_props.phys_addr = A2_PHYS_BASE;
+	a2_props.virt_addr = a2_virt_addr;
+	a2_props.virt_size = A2_PHYS_SIZE;
+	a2_props.irq = A2_BAM_IRQ;
+	a2_props.options = SPS_BAM_OPT_IRQ_WAKEUP;
+	a2_props.num_pipes = A2_NUM_PIPES;
+	a2_props.summing_threshold = A2_SUMMING_THRESHOLD;
+	if (cpu_is_msm9615())
+		a2_props.manage = SPS_BAM_MGR_DEVICE_REMOTE;
+	/* need to free on tear down */
+	ret = sps_register_bam_device(&a2_props, &h);
+	if (ret < 0) {
+		pr_err("%s: register bam error %d\n", __func__, ret);
+		goto register_bam_failed;
+	}
+	a2_device_handle = h;
+
+	bam_tx_pipe = sps_alloc_endpoint();
+	if (bam_tx_pipe == NULL) {
+		pr_err("%s: tx alloc endpoint failed\n", __func__);
+		ret = -ENOMEM;
+		goto tx_alloc_endpoint_failed;
+	}
+	ret = sps_get_config(bam_tx_pipe, &tx_connection);
+	if (ret) {
+		pr_err("%s: tx get config failed %d\n", __func__, ret);
+		goto tx_get_config_failed;
+	}
+
+	tx_connection.source = SPS_DEV_HANDLE_MEM;
+	tx_connection.src_pipe_index = 0;
+	tx_connection.destination = h;
+	tx_connection.dest_pipe_index = 4;
+	tx_connection.mode = SPS_MODE_DEST;
+	tx_connection.options = SPS_O_AUTO_ENABLE | SPS_O_EOT;
+	tx_desc_mem_buf.size = 0x800; /* 2k */
+	tx_desc_mem_buf.base = dma_alloc_coherent(NULL, tx_desc_mem_buf.size,
+							&dma_addr, 0);
+	if (tx_desc_mem_buf.base == NULL) {
+		pr_err("%s: tx memory alloc failed\n", __func__);
+		ret = -ENOMEM;
+		goto tx_get_config_failed;
+	}
+	tx_desc_mem_buf.phys_base = dma_addr;
+	memset(tx_desc_mem_buf.base, 0x0, tx_desc_mem_buf.size);
+	tx_connection.desc = tx_desc_mem_buf;
+	tx_connection.event_thresh = 0x10;
+
+	ret = sps_connect(bam_tx_pipe, &tx_connection);
+	if (ret < 0) {
+		pr_err("%s: tx connect error %d\n", __func__, ret);
+		goto tx_connect_failed;
+	}
+
+	bam_rx_pipe = sps_alloc_endpoint();
+	if (bam_rx_pipe == NULL) {
+		pr_err("%s: rx alloc endpoint failed\n", __func__);
+		ret = -ENOMEM;
+		goto rx_alloc_endpoint_failed;
+	}
+	ret = sps_get_config(bam_rx_pipe, &rx_connection);
+	if (ret) {
+		pr_err("%s: rx get config failed %d\n", __func__, ret);
+		goto rx_get_config_failed;
+	}
+
+	rx_connection.source = h;
+	rx_connection.src_pipe_index = 5;
+	rx_connection.destination = SPS_DEV_HANDLE_MEM;
+	rx_connection.dest_pipe_index = 1;
+	rx_connection.mode = SPS_MODE_SRC;
+	rx_connection.options = SPS_O_AUTO_ENABLE | SPS_O_EOT |
+					SPS_O_ACK_TRANSFERS;
+	rx_desc_mem_buf.size = 0x800; /* 2k */
+	rx_desc_mem_buf.base = dma_alloc_coherent(NULL, rx_desc_mem_buf.size,
+							&dma_addr, 0);
+	if (rx_desc_mem_buf.base == NULL) {
+		pr_err("%s: rx memory alloc failed\n", __func__);
+		ret = -ENOMEM;
+		goto rx_mem_failed;
+	}
+	rx_desc_mem_buf.phys_base = dma_addr;
+	memset(rx_desc_mem_buf.base, 0x0, rx_desc_mem_buf.size);
+	rx_connection.desc = rx_desc_mem_buf;
+	rx_connection.event_thresh = 0x10;
+
+	ret = sps_connect(bam_rx_pipe, &rx_connection);
+	if (ret < 0) {
+		pr_err("%s: rx connect error %d\n", __func__, ret);
+		goto rx_connect_failed;
+	}
+
+	tx_register_event.options = SPS_O_EOT;
+	tx_register_event.mode = SPS_TRIGGER_CALLBACK;
+	tx_register_event.xfer_done = NULL;
+	tx_register_event.callback = bam_mux_tx_notify;
+	tx_register_event.user = NULL;
+	ret = sps_register_event(bam_tx_pipe, &tx_register_event);
+	if (ret < 0) {
+		pr_err("%s: tx register event error %d\n", __func__, ret);
+		goto rx_event_reg_failed;
+	}
+
+	rx_register_event.options = SPS_O_EOT;
+	rx_register_event.mode = SPS_TRIGGER_CALLBACK;
+	rx_register_event.xfer_done = NULL;
+	rx_register_event.callback = bam_mux_rx_notify;
+	rx_register_event.user = NULL;
+	ret = sps_register_event(bam_rx_pipe, &rx_register_event);
+	if (ret < 0) {
+		pr_err("%s: tx register event error %d\n", __func__, ret);
+		goto rx_event_reg_failed;
+	}
+
+	mutex_lock(&delayed_ul_vote_lock);
+	bam_mux_initialized = 1;
+	if (need_delayed_ul_vote) {
+		need_delayed_ul_vote = 0;
+		msm_bam_dmux_kickoff_ul_wakeup();
+	}
+	mutex_unlock(&delayed_ul_vote_lock);
+	toggle_apps_ack();
+	bam_connection_is_active = 1;
+	complete_all(&bam_connection_completion);
+	queue_rx();
+	return 0;
+
+rx_event_reg_failed:
+	sps_disconnect(bam_rx_pipe);
+rx_connect_failed:
+	dma_free_coherent(NULL, rx_desc_mem_buf.size, rx_desc_mem_buf.base,
+				rx_desc_mem_buf.phys_base);
+rx_mem_failed:
+rx_get_config_failed:
+	sps_free_endpoint(bam_rx_pipe);
+rx_alloc_endpoint_failed:
+	sps_disconnect(bam_tx_pipe);
+tx_connect_failed:
+	dma_free_coherent(NULL, tx_desc_mem_buf.size, tx_desc_mem_buf.base,
+				tx_desc_mem_buf.phys_base);
+tx_get_config_failed:
+	sps_free_endpoint(bam_tx_pipe);
+tx_alloc_endpoint_failed:
+	sps_deregister_bam_device(h);
+	/*
+	 * sps_deregister_bam_device() calls iounmap.  calling iounmap on the
+	 * same handle below will cause a crash, so skip it if we've freed
+	 * the handle here.
+	 */
+	skip_iounmap = 1;
+register_bam_failed:
+	if (!skip_iounmap)
+		iounmap(a2_virt_addr);
+ioremap_failed:
+	/*destroy_workqueue(bam_mux_workqueue);*/
+	return ret;
+}
+
+static int bam_init_fallback(void)
+{
+	u32 h;
+	int ret;
+	void *a2_virt_addr;
+
+	unvote_dfab();
+	/* init BAM */
+	a2_virt_addr = ioremap_nocache(A2_PHYS_BASE, A2_PHYS_SIZE);
+	if (!a2_virt_addr) {
+		pr_err("%s: ioremap failed\n", __func__);
+		ret = -ENOMEM;
+		goto ioremap_failed;
+	}
+	a2_props.phys_addr = A2_PHYS_BASE;
+	a2_props.virt_addr = a2_virt_addr;
+	a2_props.virt_size = A2_PHYS_SIZE;
+	a2_props.irq = A2_BAM_IRQ;
+	a2_props.options = SPS_BAM_OPT_IRQ_WAKEUP;
+	a2_props.num_pipes = A2_NUM_PIPES;
+	a2_props.summing_threshold = A2_SUMMING_THRESHOLD;
+	if (cpu_is_msm9615())
+		a2_props.manage = SPS_BAM_MGR_DEVICE_REMOTE;
+	ret = sps_register_bam_device(&a2_props, &h);
+	if (ret < 0) {
+		pr_err("%s: register bam error %d\n", __func__, ret);
+		goto register_bam_failed;
+	}
+	a2_device_handle = h;
+
+	mutex_lock(&delayed_ul_vote_lock);
+	bam_mux_initialized = 1;
+	if (need_delayed_ul_vote) {
+		need_delayed_ul_vote = 0;
+		msm_bam_dmux_kickoff_ul_wakeup();
+	}
+	mutex_unlock(&delayed_ul_vote_lock);
+	toggle_apps_ack();
+
+	return 0;
+
+register_bam_failed:
+	iounmap(a2_virt_addr);
+ioremap_failed:
+	return ret;
+}
+
+static void msm9615_bam_init(void)
+{
+	int ret = 0;
+
+	ret = bam_init();
+	if (ret) {
+		ret = bam_init_fallback();
+		if (ret)
+			pr_err("%s: bam init fallback failed: %d",
+					__func__, ret);
+	}
+}
+
+static void toggle_apps_ack(void)
+{
+	static unsigned int clear_bit; /* 0 = set the bit, else clear bit */
+
+	bam_dmux_log("%s: apps ack %d->%d\n", __func__,
+			clear_bit & 0x1, ~clear_bit & 0x1);
+	smsm_change_state(SMSM_APPS_STATE,
+				clear_bit & SMSM_A2_POWER_CONTROL_ACK,
+				~clear_bit & SMSM_A2_POWER_CONTROL_ACK);
+	clear_bit = ~clear_bit;
+	DBG_INC_ACK_OUT_CNT();
+}
+
+static void bam_dmux_smsm_cb(void *priv, uint32_t old_state, uint32_t new_state)
+{
+	static int last_processed_state;
+
+	mutex_lock(&smsm_cb_lock);
+	bam_dmux_power_state = new_state & SMSM_A2_POWER_CONTROL ? 1 : 0;
+	DBG_INC_A2_POWER_CONTROL_IN_CNT();
+	bam_dmux_log("%s: 0x%08x -> 0x%08x\n", __func__, old_state,
+			new_state);
+	if (last_processed_state == (new_state & SMSM_A2_POWER_CONTROL)) {
+		bam_dmux_log("%s: already processed this state\n", __func__);
+		mutex_unlock(&smsm_cb_lock);
+		return;
+	}
+
+	last_processed_state = new_state & SMSM_A2_POWER_CONTROL;
+
+	if (bam_mux_initialized && new_state & SMSM_A2_POWER_CONTROL) {
+		bam_dmux_log("%s: reconnect\n", __func__);
+		grab_wakelock();
+		reconnect_to_bam();
+	} else if (bam_mux_initialized &&
+					!(new_state & SMSM_A2_POWER_CONTROL)) {
+		bam_dmux_log("%s: disconnect\n", __func__);
+		disconnect_to_bam();
+		release_wakelock();
+	} else if (new_state & SMSM_A2_POWER_CONTROL) {
+		bam_dmux_log("%s: init\n", __func__);
+		grab_wakelock();
+		if (cpu_is_msm9615())
+			msm9615_bam_init();
+		else
+			bam_init();
+	} else {
+		bam_dmux_log("%s: bad state change\n", __func__);
+		pr_err("%s: unsupported state change\n", __func__);
+	}
+	mutex_unlock(&smsm_cb_lock);
+
+}
+
+static void bam_dmux_smsm_ack_cb(void *priv, uint32_t old_state,
+						uint32_t new_state)
+{
+	DBG_INC_ACK_IN_CNT();
+	bam_dmux_log("%s: 0x%08x -> 0x%08x\n", __func__, old_state,
+			new_state);
+	complete_all(&ul_wakeup_ack_completion);
+}
+
+static int bam_dmux_probe(struct platform_device *pdev)
+{
+	int rc;
+
+	DBG("%s probe called\n", __func__);
+	if (bam_mux_initialized)
+		return 0;
+
+	xo_clk = clk_get(&pdev->dev, "xo");
+	if (IS_ERR(xo_clk)) {
+		pr_err("%s: did not get xo clock\n", __func__);
+		return PTR_ERR(xo_clk);
+	}
+	dfab_clk = clk_get(&pdev->dev, "bus_clk");
+	if (IS_ERR(dfab_clk)) {
+		pr_err("%s: did not get dfab clock\n", __func__);
+		return -EFAULT;
+	}
+
+	rc = clk_set_rate(dfab_clk, 64000000);
+	if (rc)
+		pr_err("%s: unable to set dfab clock rate\n", __func__);
+
+	/*
+	 * setup the workqueue so that it can be pinned to core 0 and not
+	 * block the watchdog pet function, so that netif_rx() in rmnet
+	 * only uses one queue.
+	 */
+	bam_mux_rx_workqueue = alloc_workqueue("bam_dmux_rx",
+					WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE, 1);
+	if (!bam_mux_rx_workqueue)
+		return -ENOMEM;
+
+	bam_mux_tx_workqueue = create_singlethread_workqueue("bam_dmux_tx");
+	if (!bam_mux_tx_workqueue) {
+		destroy_workqueue(bam_mux_rx_workqueue);
+		return -ENOMEM;
+	}
+
+	for (rc = 0; rc < BAM_DMUX_NUM_CHANNELS; ++rc) {
+		spin_lock_init(&bam_ch[rc].lock);
+		scnprintf(bam_ch[rc].name, BAM_DMUX_CH_NAME_MAX_LEN,
+					"bam_dmux_ch_%d", rc);
+		/* bus 2, ie a2 stream 2 */
+		bam_ch[rc].pdev = platform_device_alloc(bam_ch[rc].name, 2);
+		if (!bam_ch[rc].pdev) {
+			pr_err("%s: platform device alloc failed\n", __func__);
+			destroy_workqueue(bam_mux_rx_workqueue);
+			destroy_workqueue(bam_mux_tx_workqueue);
+			return -ENOMEM;
+		}
+	}
+
+	init_completion(&ul_wakeup_ack_completion);
+	init_completion(&bam_connection_completion);
+	init_completion(&dfab_unvote_completion);
+	INIT_DELAYED_WORK(&ul_timeout_work, ul_timeout);
+	wake_lock_init(&bam_wakelock, WAKE_LOCK_SUSPEND, "bam_dmux_wakelock");
+
+	rc = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_A2_POWER_CONTROL,
+					bam_dmux_smsm_cb, NULL);
+
+	if (rc) {
+		destroy_workqueue(bam_mux_rx_workqueue);
+		destroy_workqueue(bam_mux_tx_workqueue);
+		pr_err("%s: smsm cb register failed, rc: %d\n", __func__, rc);
+		return -ENOMEM;
+	}
+
+	rc = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_A2_POWER_CONTROL_ACK,
+					bam_dmux_smsm_ack_cb, NULL);
+
+	if (rc) {
+		destroy_workqueue(bam_mux_rx_workqueue);
+		destroy_workqueue(bam_mux_tx_workqueue);
+		smsm_state_cb_deregister(SMSM_MODEM_STATE,
+					SMSM_A2_POWER_CONTROL,
+					bam_dmux_smsm_cb, NULL);
+		pr_err("%s: smsm ack cb register failed, rc: %d\n", __func__,
+				rc);
+		for (rc = 0; rc < BAM_DMUX_NUM_CHANNELS; ++rc)
+			platform_device_put(bam_ch[rc].pdev);
+		return -ENOMEM;
+	}
+
+	if (smsm_get_state(SMSM_MODEM_STATE) & SMSM_A2_POWER_CONTROL)
+		bam_dmux_smsm_cb(NULL, 0, smsm_get_state(SMSM_MODEM_STATE));
+
+	return 0;
+}
+
+static struct platform_driver bam_dmux_driver = {
+	.probe		= bam_dmux_probe,
+	.driver		= {
+		.name	= "BAM_RMNT",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init bam_dmux_init(void)
+{
+	int ret;
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dent;
+
+	dent = debugfs_create_dir("bam_dmux", 0);
+	if (!IS_ERR(dent)) {
+		debug_create("tbl", 0444, dent, debug_tbl);
+		debug_create("ul_pkt_cnt", 0444, dent, debug_ul_pkt_cnt);
+		debug_create("stats", 0444, dent, debug_stats);
+		debug_create_multiple("log", 0444, dent, debug_log);
+	}
+#endif
+	ret = kfifo_alloc(&bam_dmux_state_log, PAGE_SIZE, GFP_KERNEL);
+	if (ret) {
+		pr_err("%s: failed to allocate log %d\n", __func__, ret);
+		bam_dmux_state_logging_disabled = 1;
+	}
+
+	subsys_notif_register_notifier("modem", &restart_notifier);
+	return platform_driver_register(&bam_dmux_driver);
+}
+
+late_initcall(bam_dmux_init); /* needs to init after SMD */
+MODULE_DESCRIPTION("MSM BAM DMUX");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/bms-batterydata-desay.c b/arch/arm/mach-msm/bms-batterydata-desay.c
new file mode 100644
index 0000000..f362a72
--- /dev/null
+++ b/arch/arm/mach-msm/bms-batterydata-desay.c
@@ -0,0 +1,86 @@
+/* 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
+ * 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/mfd/pm8xxx/pm8921-bms.h>
+
+static struct single_row_lut desay_5200_fcc_temp = {
+	.x		= {-20, 0, 25, 40},
+	.y		= {5690, 5722, 5722, 5727},
+	.cols	= 4
+};
+
+static struct single_row_lut desay_5200_fcc_sf = {
+	.x		= {0},
+	.y		= {100},
+	.cols	= 1
+};
+
+static struct pc_temp_ocv_lut desay_5200_pc_temp_ocv = {
+	.rows		= 29,
+	.cols		= 4,
+	.temp		= {-20, 0, 25, 40},
+	.percent	= {100, 95, 90, 85, 80, 75, 70, 65, 60, 55,
+				50, 45, 40, 35, 30, 25, 20, 15, 10, 9, 8,
+				7, 6, 5, 4, 3, 2, 1, 0
+	},
+	.ocv		= {
+				{4185, 4184, 4181, 4178},
+				{4103, 4117, 4120, 4119},
+				{4044, 4067, 4074, 4073},
+				{3987, 4019, 4031, 4030},
+				{3941, 3974, 3992, 3992},
+				{3902, 3936, 3958, 3957},
+				{3866, 3901, 3926, 3926},
+				{3835, 3870, 3891, 3896},
+				{3811, 3842, 3855, 3858},
+				{3792, 3818, 3827, 3827},
+				{3776, 3795, 3806, 3806},
+				{3762, 3778, 3789, 3790},
+				{3748, 3765, 3777, 3777},
+				{3735, 3752, 3767, 3765},
+				{3720, 3739, 3756, 3754},
+				{3704, 3726, 3743, 3736},
+				{3685, 3712, 3723, 3716},
+				{3664, 3697, 3695, 3689},
+				{3623, 3672, 3669, 3664},
+				{3611, 3666, 3666, 3661},
+				{3597, 3659, 3662, 3658},
+				{3579, 3648, 3657, 3653},
+				{3559, 3630, 3644, 3639},
+				{3532, 3600, 3612, 3606},
+				{3497, 3558, 3565, 3559},
+				{3450, 3500, 3504, 3498},
+				{3380, 3417, 3421, 3416},
+				{3265, 3287, 3296, 3293},
+				{3000, 3000, 3000, 3000}
+	},
+};
+
+static struct sf_lut desay_5200_pc_sf = {
+	.rows		= 1,
+	.cols		= 1,
+	/* row_entries are cycles here */
+	.row_entries		= {0},
+	.percent	= {100},
+	.sf			= {
+				{100}
+	},
+};
+
+struct pm8921_bms_battery_data desay_5200_data = {
+	.fcc			= 5200,
+	.fcc_temp_lut		= &desay_5200_fcc_temp,
+	.fcc_sf_lut		= &desay_5200_fcc_sf,
+	.pc_temp_ocv_lut	= &desay_5200_pc_temp_ocv,
+	.pc_sf_lut		= &desay_5200_pc_sf,
+	.default_rbatt_mohm	= 156,
+};
diff --git a/arch/arm/mach-msm/bms-batterydata.c b/arch/arm/mach-msm/bms-batterydata.c
new file mode 100644
index 0000000..77e7dab
--- /dev/null
+++ b/arch/arm/mach-msm/bms-batterydata.c
@@ -0,0 +1,127 @@
+/* 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
+ * 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/mfd/pm8xxx/pm8921-bms.h>
+
+static struct single_row_lut palladium_1500_fcc_temp = {
+	.x	= {-30, -20, -10, 0, 10, 25, 40, 60},
+	.y	= {1103, 1179, 1284, 1330, 1420, 1511, 1541, 1571},
+	.cols	= 8,
+};
+
+static struct single_row_lut palladium_1500_fcc_sf = {
+	.x	= {100, 200, 300, 400, 500},
+	.y	= {97, 93, 93, 90, 87},
+	.cols	= 5,
+};
+
+static struct sf_lut palladium_1500_pc_sf = {
+	.rows		= 10,
+	.cols		= 5,
+	/* row_entries are chargecycles */
+	.row_entries	= {100, 200, 300, 400, 500},
+	.percent	= {100, 90, 80, 70, 60, 50, 40, 30, 20, 10},
+	.sf		= {
+			{97, 93, 93, 90, 87},
+			{97, 93, 93, 90, 87},
+			{98, 94, 92, 89, 86},
+			{98, 94, 92, 89, 86},
+			{99, 94, 92, 88, 86},
+			{99, 95, 92, 88, 87},
+			{99, 95, 92, 88, 87},
+			{99, 95, 92, 88, 87},
+			{99, 95, 92, 88, 87},
+			{99, 95, 92, 88, 87}
+	},
+};
+
+static struct sf_lut palladium_1500_rbatt_sf = {
+	.rows		= 19,
+	.cols		= 5,
+	/* row_entries are temperature */
+	.row_entries	= {-20, 0, 20, 40, 65},
+	.percent	= {100, 95, 90, 85, 80, 75, 70, 65, 60, 55, 50,
+				45, 40, 35, 30, 25, 20, 15, 10
+	},
+	.sf		= {
+					{645, 301, 100, 80, 69},
+					{616, 290, 100, 79, 69},
+					{586, 279, 100, 78, 68},
+					{564, 270, 100, 78, 68},
+					{546, 262, 100, 78, 68},
+					{537, 256, 100, 79, 68},
+					{536, 253, 100, 79, 69},
+					{552, 258, 100, 81, 71},
+					{618, 284, 100, 80, 72},
+					{643, 290, 100, 77, 68},
+					{673, 294, 100, 77, 68},
+					{720, 296, 100, 77, 69},
+					{769, 294, 100, 76, 68},
+					{821, 288, 100, 74, 67},
+					{892, 284, 100, 74, 61},
+					{1003, 290, 100, 71, 58},
+					{1192, 307, 100, 70, 58},
+					{1579, 345, 100, 68, 57},
+					{1261, 324, 100, 68, 57},
+	}
+};
+static struct pc_temp_ocv_lut palladium_1500_pc_temp_ocv = {
+	.rows		= 29,
+	.cols		= 8,
+	.temp		= {-30, -20, -10, 0, 10, 25, 40, 60},
+	.percent	= {100, 95, 90, 85, 80, 75, 70, 65, 60, 55,
+				50, 45, 40, 35, 30, 25, 20, 15, 10, 9,
+				8, 7, 6, 5, 4, 3, 2, 1, 0
+	},
+	.ocv		= {
+			{3673, 3814, 3945, 4025, 4106, 4176, 4218, 4260},
+			{3613, 3751, 3880, 3959, 4038, 4107, 4149, 4190},
+			{3573, 3710, 3837, 3916, 3994, 4062, 4103, 4144},
+			{3534, 3670, 3796, 3873, 3951, 4019, 4059, 4099},
+			{3491, 3625, 3749, 3826, 3902, 3969, 4009, 4049},
+			{3464, 3597, 3721, 3796, 3872, 3939, 3978, 4018},
+			{3436, 3568, 3691, 3766, 3841, 3907, 3946, 3985},
+			{3407, 3537, 3659, 3733, 3808, 3873, 3912, 3951},
+			{3377, 3507, 3627, 3701, 3775, 3840, 3878, 3917},
+			{3355, 3484, 3604, 3677, 3751, 3815, 3853, 3891},
+			{3339, 3467, 3586, 3659, 3732, 3796, 3834, 3872},
+			{3324, 3452, 3570, 3643, 3716, 3780, 3818, 3855},
+			{3312, 3440, 3558, 3630, 3703, 3766, 3804, 3842},
+			{3303, 3430, 3548, 3620, 3692, 3756, 3793, 3831},
+			{3297, 3424, 3541, 3614, 3686, 3749, 3787, 3824},
+			{3288, 3414, 3531, 3603, 3675, 3738, 3776, 3813},
+			{3272, 3398, 3514, 3586, 3658, 3720, 3757, 3795},
+			{3240, 3365, 3480, 3551, 3622, 3684, 3721, 3758},
+			{3224, 3348, 3463, 3533, 3604, 3666, 3702, 3739},
+			{3221, 3344, 3459, 3530, 3600, 3662, 3695, 3728},
+			{3216, 3340, 3454, 3525, 3595, 3657, 3686, 3715},
+			{3212, 3335, 3449, 3520, 3590, 3652, 3677, 3703},
+			{3203, 3326, 3440, 3510, 3580, 3642, 3664, 3686},
+			{3185, 3307, 3420, 3490, 3560, 3621, 3639, 3657},
+			{3176, 3298, 3411, 3481, 3550, 3611, 3626, 3640},
+			{3151, 3272, 3384, 3453, 3522, 3583, 3593, 3604},
+			{3106, 3225, 3335, 3446, 3472, 3531, 3538, 3545},
+			{3021, 3217, 3245, 3417, 3429, 3435, 3439, 3442},
+			{3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000}
+	},
+};
+
+struct pm8921_bms_battery_data palladium_1500_data = {
+	.fcc			= 1500,
+	.fcc_temp_lut		= &palladium_1500_fcc_temp,
+	.fcc_sf_lut		= &palladium_1500_fcc_sf,
+	.pc_temp_ocv_lut	= &palladium_1500_pc_temp_ocv,
+	.pc_sf_lut		= &palladium_1500_pc_sf,
+	.rbatt_sf_lut		= &palladium_1500_rbatt_sf,
+	.default_rbatt_mohm	= 254,
+	.delta_rbatt_mohm	= 60,
+};
diff --git a/arch/arm/mach-msm/board-8064-camera.c b/arch/arm/mach-msm/board-8064-camera.c
new file mode 100644
index 0000000..2d1f787
--- /dev/null
+++ b/arch/arm/mach-msm/board-8064-camera.c
@@ -0,0 +1,697 @@
+/* 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/i2c.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-types.h>
+
+#include <mach/board.h>
+#include <mach/msm_bus_board.h>
+#include <mach/gpiomux.h>
+
+#include "devices.h"
+#include "board-8064.h"
+
+#ifdef CONFIG_MSM_CAMERA
+
+static struct gpiomux_setting cam_settings[] = {
+	{
+		.func = GPIOMUX_FUNC_GPIO, /*suspend*/
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_DOWN,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_1, /*active 1*/
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_GPIO, /*active 2*/
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_2, /*active 3*/
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_5, /*active 4*/
+		.drv = GPIOMUX_DRV_8MA,
+		.pull = GPIOMUX_PULL_UP,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_6, /*active 5*/
+		.drv = GPIOMUX_DRV_8MA,
+		.pull = GPIOMUX_PULL_UP,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_2, /*active 6*/
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_UP,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_3, /*active 7*/
+		.drv = GPIOMUX_DRV_8MA,
+		.pull = GPIOMUX_PULL_UP,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_GPIO, /*i2c suspend*/
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_KEEPER,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_9, /*active 9*/
+		.drv = GPIOMUX_DRV_8MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+	{
+		.func = GPIOMUX_FUNC_A, /*active 10*/
+		.drv = GPIOMUX_DRV_8MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+	{
+		.func = GPIOMUX_FUNC_6, /*active 11*/
+		.drv = GPIOMUX_DRV_8MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+	{
+		.func = GPIOMUX_FUNC_4, /*active 12*/
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+
+};
+
+static struct msm_gpiomux_config apq8064_cam_common_configs[] = {
+	{
+		.gpio = 1,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[2],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
+		},
+	},
+	{
+		.gpio = 2,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[12],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
+		},
+	},
+	{
+		.gpio = 3,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[2],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
+		},
+	},
+	{
+		.gpio = 4,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
+		},
+	},
+	{
+		.gpio = 5,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[1],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
+		},
+	},
+	{
+		.gpio = 34,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[2],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
+		},
+	},
+	{
+		.gpio = 107,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[2],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
+		},
+	},
+	{
+		.gpio = 10,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[9],
+			[GPIOMUX_SUSPENDED] = &cam_settings[8],
+		},
+	},
+	{
+		.gpio = 11,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[10],
+			[GPIOMUX_SUSPENDED] = &cam_settings[8],
+		},
+	},
+	{
+		.gpio = 12,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[11],
+			[GPIOMUX_SUSPENDED] = &cam_settings[8],
+		},
+	},
+	{
+		.gpio = 13,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[11],
+			[GPIOMUX_SUSPENDED] = &cam_settings[8],
+		},
+	},
+};
+
+
+#define VFE_CAMIF_TIMER1_GPIO 3
+#define VFE_CAMIF_TIMER2_GPIO 1
+
+static struct msm_camera_sensor_flash_src msm_flash_src = {
+	.flash_sr_type = MSM_CAMERA_FLASH_SRC_EXT,
+	._fsrc.ext_driver_src.led_en = VFE_CAMIF_TIMER1_GPIO,
+	._fsrc.ext_driver_src.led_flash_en = VFE_CAMIF_TIMER2_GPIO,
+	._fsrc.ext_driver_src.flash_id = MAM_CAMERA_EXT_LED_FLASH_SC628A,
+};
+
+static struct msm_gpiomux_config apq8064_cam_2d_configs[] = {
+};
+
+static struct msm_bus_vectors cam_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+};
+
+static struct msm_bus_vectors cam_preview_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 27648000,
+		.ib  = 110592000,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+};
+
+static struct msm_bus_vectors cam_video_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 140451840,
+		.ib  = 561807360,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 206807040,
+		.ib  = 488816640,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+};
+
+static struct msm_bus_vectors cam_snapshot_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 274423680,
+		.ib  = 1097694720,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 540000000,
+		.ib  = 1350000000,
+	},
+};
+
+static struct msm_bus_vectors cam_zsl_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 302071680,
+		.ib  = 1208286720,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 540000000,
+		.ib  = 1350000000,
+	},
+};
+
+static struct msm_bus_paths cam_bus_client_config[] = {
+	{
+		ARRAY_SIZE(cam_init_vectors),
+		cam_init_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_preview_vectors),
+		cam_preview_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_video_vectors),
+		cam_video_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_snapshot_vectors),
+		cam_snapshot_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_zsl_vectors),
+		cam_zsl_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata cam_bus_client_pdata = {
+		cam_bus_client_config,
+		ARRAY_SIZE(cam_bus_client_config),
+		.name = "msm_camera",
+};
+
+static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
+	{
+		.csid_core = 0,
+		.is_csiphy = 1,
+		.is_csid   = 1,
+		.is_ispif  = 1,
+		.is_vpe    = 1,
+		.cam_bus_scale_table = &cam_bus_client_pdata,
+	},
+	{
+		.csid_core = 1,
+		.is_csiphy = 1,
+		.is_csid   = 1,
+		.is_ispif  = 1,
+		.is_vpe    = 1,
+		.cam_bus_scale_table = &cam_bus_client_pdata,
+	},
+};
+
+static struct camera_vreg_t apq_8064_back_cam_vreg[] = {
+	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
+	{"cam_vio", REG_VS, 0, 0, 0},
+	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
+	{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
+};
+
+static struct camera_vreg_t apq_8064_front_cam_vreg[] = {
+	{"cam_vio", REG_VS, 0, 0, 0},
+	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
+	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
+	{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
+};
+
+#define CAML_RSTN PM8921_GPIO_PM_TO_SYS(28)
+#define CAMR_RSTN 34
+
+static struct gpio apq8064_common_cam_gpio[] = {
+};
+
+static struct gpio apq8064_back_cam_gpio[] = {
+	{5, GPIOF_DIR_IN, "CAMIF_MCLK"},
+	{CAML_RSTN, GPIOF_DIR_OUT, "CAM_RESET"},
+};
+
+static struct msm_gpio_set_tbl apq8064_back_cam_gpio_set_tbl[] = {
+	{CAML_RSTN, GPIOF_OUT_INIT_LOW, 10000},
+	{CAML_RSTN, GPIOF_OUT_INIT_HIGH, 10000},
+};
+
+static struct msm_camera_gpio_conf apq8064_back_cam_gpio_conf = {
+	.cam_gpiomux_conf_tbl = apq8064_cam_2d_configs,
+	.cam_gpiomux_conf_tbl_size = ARRAY_SIZE(apq8064_cam_2d_configs),
+	.cam_gpio_common_tbl = apq8064_common_cam_gpio,
+	.cam_gpio_common_tbl_size = ARRAY_SIZE(apq8064_common_cam_gpio),
+	.cam_gpio_req_tbl = apq8064_back_cam_gpio,
+	.cam_gpio_req_tbl_size = ARRAY_SIZE(apq8064_back_cam_gpio),
+	.cam_gpio_set_tbl = apq8064_back_cam_gpio_set_tbl,
+	.cam_gpio_set_tbl_size = ARRAY_SIZE(apq8064_back_cam_gpio_set_tbl),
+};
+
+static struct gpio apq8064_front_cam_gpio[] = {
+	{4, GPIOF_DIR_IN, "CAMIF_MCLK"},
+	{12, GPIOF_DIR_IN, "CAMIF_I2C_DATA"},
+	{13, GPIOF_DIR_IN, "CAMIF_I2C_CLK"},
+	{CAMR_RSTN, GPIOF_DIR_OUT, "CAM_RESET"},
+};
+
+static struct msm_gpio_set_tbl apq8064_front_cam_gpio_set_tbl[] = {
+	{CAMR_RSTN, GPIOF_OUT_INIT_LOW, 10000},
+	{CAMR_RSTN, GPIOF_OUT_INIT_HIGH, 10000},
+};
+
+static struct msm_camera_gpio_conf apq8064_front_cam_gpio_conf = {
+	.cam_gpiomux_conf_tbl = apq8064_cam_2d_configs,
+	.cam_gpiomux_conf_tbl_size = ARRAY_SIZE(apq8064_cam_2d_configs),
+	.cam_gpio_common_tbl = apq8064_common_cam_gpio,
+	.cam_gpio_common_tbl_size = ARRAY_SIZE(apq8064_common_cam_gpio),
+	.cam_gpio_req_tbl = apq8064_front_cam_gpio,
+	.cam_gpio_req_tbl_size = ARRAY_SIZE(apq8064_front_cam_gpio),
+	.cam_gpio_set_tbl = apq8064_front_cam_gpio_set_tbl,
+	.cam_gpio_set_tbl_size = ARRAY_SIZE(apq8064_front_cam_gpio_set_tbl),
+};
+
+static struct msm_camera_i2c_conf apq8064_back_cam_i2c_conf = {
+	.use_i2c_mux = 1,
+	.mux_dev = &msm8960_device_i2c_mux_gsbi4,
+	.i2c_mux_mode = MODE_L,
+};
+
+static struct i2c_board_info msm_act_main_cam_i2c_info = {
+	I2C_BOARD_INFO("msm_actuator", 0x11),
+};
+
+static struct msm_actuator_info msm_act_main_cam_0_info = {
+	.board_info     = &msm_act_main_cam_i2c_info,
+	.cam_name   = MSM_ACTUATOR_MAIN_CAM_0,
+	.bus_id         = APQ_8064_GSBI4_QUP_I2C_BUS_ID,
+	.vcm_pwd        = 0,
+	.vcm_enable     = 0,
+};
+
+static struct i2c_board_info msm_act_main_cam1_i2c_info = {
+	I2C_BOARD_INFO("msm_actuator", 0x18),
+};
+
+static struct msm_actuator_info msm_act_main_cam_1_info = {
+	.board_info     = &msm_act_main_cam1_i2c_info,
+	.cam_name       = MSM_ACTUATOR_MAIN_CAM_1,
+	.bus_id         = APQ_8064_GSBI4_QUP_I2C_BUS_ID,
+	.vcm_pwd        = 0,
+	.vcm_enable     = 0,
+};
+
+
+static struct msm_camera_i2c_conf apq8064_front_cam_i2c_conf = {
+	.use_i2c_mux = 1,
+	.mux_dev = &msm8960_device_i2c_mux_gsbi4,
+	.i2c_mux_mode = MODE_L,
+};
+
+static struct msm_camera_sensor_flash_data flash_imx074 = {
+	.flash_type	= MSM_CAMERA_FLASH_LED,
+	.flash_src	= &msm_flash_src
+};
+
+static struct msm_camera_csi_lane_params imx074_csi_lane_params = {
+	.csi_lane_assign = 0xE4,
+	.csi_lane_mask = 0xF,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_imx074 = {
+	.mount_angle	= 90,
+	.cam_vreg = apq_8064_back_cam_vreg,
+	.num_vreg = ARRAY_SIZE(apq_8064_back_cam_vreg),
+	.gpio_conf = &apq8064_back_cam_gpio_conf,
+	.i2c_conf = &apq8064_back_cam_i2c_conf,
+	.csi_lane_params = &imx074_csi_lane_params,
+};
+
+static struct i2c_board_info imx074_eeprom_i2c_info = {
+	I2C_BOARD_INFO("imx074_eeprom", 0x34 << 1),
+};
+
+static struct msm_eeprom_info imx074_eeprom_info = {
+	.board_info     = &imx074_eeprom_i2c_info,
+	.bus_id         = APQ_8064_GSBI4_QUP_I2C_BUS_ID,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_imx074_data = {
+	.sensor_name	= "imx074",
+	.pdata	= &msm_camera_csi_device_data[0],
+	.flash_data	= &flash_imx074,
+	.sensor_platform_info = &sensor_board_info_imx074,
+	.csi_if	= 1,
+	.camera_type = BACK_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
+	.actuator_info = &msm_act_main_cam_0_info,
+	.eeprom_info = &imx074_eeprom_info,
+};
+
+static struct msm_camera_csi_lane_params imx091_csi_lane_params = {
+	.csi_lane_assign = 0xE4,
+	.csi_lane_mask = 0xF,
+};
+
+static struct camera_vreg_t apq_8064_imx091_vreg[] = {
+	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
+	{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
+	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
+	{"cam_vio", REG_VS, 0, 0, 0},
+};
+
+static struct msm_camera_sensor_flash_data flash_imx091 = {
+	.flash_type	= MSM_CAMERA_FLASH_NONE,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_imx091 = {
+	.mount_angle	= 0,
+	.cam_vreg = apq_8064_imx091_vreg,
+	.num_vreg = ARRAY_SIZE(apq_8064_imx091_vreg),
+	.gpio_conf = &apq8064_back_cam_gpio_conf,
+	.i2c_conf = &apq8064_back_cam_i2c_conf,
+	.csi_lane_params = &imx091_csi_lane_params,
+};
+
+static struct i2c_board_info imx091_eeprom_i2c_info = {
+	I2C_BOARD_INFO("imx091_eeprom", 0x21),
+};
+
+static struct msm_eeprom_info imx091_eeprom_info = {
+	.board_info     = &imx091_eeprom_i2c_info,
+	.bus_id         = APQ_8064_GSBI4_QUP_I2C_BUS_ID,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_imx091_data = {
+	.sensor_name	= "imx091",
+	.pdata	= &msm_camera_csi_device_data[0],
+	.flash_data	= &flash_imx091,
+	.sensor_platform_info = &sensor_board_info_imx091,
+	.csi_if	= 1,
+	.camera_type = BACK_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
+	.actuator_info = &msm_act_main_cam_1_info,
+	.eeprom_info = &imx091_eeprom_info,
+};
+
+static struct camera_vreg_t apq_8064_s5k3l1yx_vreg[] = {
+	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
+	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
+	{"cam_vio", REG_VS, 0, 0, 0},
+	{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
+};
+
+static struct msm_camera_sensor_flash_data flash_s5k3l1yx = {
+	.flash_type	= MSM_CAMERA_FLASH_NONE,
+};
+
+static struct msm_camera_csi_lane_params s5k3l1yx_csi_lane_params = {
+	.csi_lane_assign = 0xE4,
+	.csi_lane_mask = 0xF,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_s5k3l1yx = {
+	.mount_angle	= 90,
+	.cam_vreg = apq_8064_s5k3l1yx_vreg,
+	.num_vreg = ARRAY_SIZE(apq_8064_s5k3l1yx_vreg),
+	.gpio_conf = &apq8064_back_cam_gpio_conf,
+	.i2c_conf = &apq8064_back_cam_i2c_conf,
+	.csi_lane_params = &s5k3l1yx_csi_lane_params,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_s5k3l1yx_data = {
+	.sensor_name	= "s5k3l1yx",
+	.pdata	= &msm_camera_csi_device_data[0],
+	.flash_data	= &flash_s5k3l1yx,
+	.sensor_platform_info = &sensor_board_info_s5k3l1yx,
+	.csi_if	= 1,
+	.camera_type = BACK_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
+};
+
+static struct camera_vreg_t apq_8064_mt9m114_vreg[] = {
+	{"cam_vio", REG_VS, 0, 0, 0},
+	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
+	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
+	{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
+};
+
+static struct msm_camera_sensor_flash_data flash_mt9m114 = {
+	.flash_type = MSM_CAMERA_FLASH_NONE
+};
+
+static struct msm_camera_csi_lane_params mt9m114_csi_lane_params = {
+	.csi_lane_assign = 0xE4,
+	.csi_lane_mask = 0x1,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_mt9m114 = {
+	.mount_angle = 90,
+	.cam_vreg = apq_8064_mt9m114_vreg,
+	.num_vreg = ARRAY_SIZE(apq_8064_mt9m114_vreg),
+	.gpio_conf = &apq8064_front_cam_gpio_conf,
+	.i2c_conf = &apq8064_front_cam_i2c_conf,
+	.csi_lane_params = &mt9m114_csi_lane_params,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_mt9m114_data = {
+	.sensor_name = "mt9m114",
+	.pdata = &msm_camera_csi_device_data[1],
+	.flash_data = &flash_mt9m114,
+	.sensor_platform_info = &sensor_board_info_mt9m114,
+	.csi_if = 1,
+	.camera_type = FRONT_CAMERA_2D,
+	.sensor_type = YUV_SENSOR,
+};
+
+static struct msm_camera_sensor_flash_data flash_ov2720 = {
+	.flash_type	= MSM_CAMERA_FLASH_NONE,
+};
+
+static struct msm_camera_csi_lane_params ov2720_csi_lane_params = {
+	.csi_lane_assign = 0xE4,
+	.csi_lane_mask = 0x3,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_ov2720 = {
+	.mount_angle	= 0,
+	.cam_vreg = apq_8064_front_cam_vreg,
+	.num_vreg = ARRAY_SIZE(apq_8064_front_cam_vreg),
+	.gpio_conf = &apq8064_front_cam_gpio_conf,
+	.i2c_conf = &apq8064_front_cam_i2c_conf,
+	.csi_lane_params = &ov2720_csi_lane_params,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_ov2720_data = {
+	.sensor_name	= "ov2720",
+	.pdata	= &msm_camera_csi_device_data[1],
+	.flash_data	= &flash_ov2720,
+	.sensor_platform_info = &sensor_board_info_ov2720,
+	.csi_if	= 1,
+	.camera_type = FRONT_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
+};
+
+static struct platform_device msm_camera_server = {
+	.name = "msm_cam_server",
+	.id = 0,
+};
+
+void __init apq8064_init_cam(void)
+{
+	msm_gpiomux_install(apq8064_cam_common_configs,
+			ARRAY_SIZE(apq8064_cam_common_configs));
+
+	if (machine_is_apq8064_cdp()) {
+		sensor_board_info_imx074.mount_angle = 0;
+		sensor_board_info_mt9m114.mount_angle = 0;
+	} else if (machine_is_apq8064_liquid())
+		sensor_board_info_imx074.mount_angle = 180;
+
+	platform_device_register(&msm_camera_server);
+	platform_device_register(&msm8960_device_i2c_mux_gsbi4);
+	platform_device_register(&msm8960_device_csiphy0);
+	platform_device_register(&msm8960_device_csiphy1);
+	platform_device_register(&msm8960_device_csid0);
+	platform_device_register(&msm8960_device_csid1);
+	platform_device_register(&msm8960_device_ispif);
+	platform_device_register(&msm8960_device_vfe);
+	platform_device_register(&msm8960_device_vpe);
+}
+
+#ifdef CONFIG_I2C
+static struct i2c_board_info apq8064_camera_i2c_boardinfo[] = {
+	{
+	I2C_BOARD_INFO("imx074", 0x1A),
+	.platform_data = &msm_camera_sensor_imx074_data,
+	},
+	{
+	I2C_BOARD_INFO("mt9m114", 0x48),
+	.platform_data = &msm_camera_sensor_mt9m114_data,
+	},
+	{
+	I2C_BOARD_INFO("ov2720", 0x6C),
+	.platform_data = &msm_camera_sensor_ov2720_data,
+	},
+	{
+	I2C_BOARD_INFO("sc628a", 0x6E),
+	},
+	{
+	I2C_BOARD_INFO("imx091", 0x34),
+	.platform_data = &msm_camera_sensor_imx091_data,
+	},
+	{
+	I2C_BOARD_INFO("s5k3l1yx", 0x20),
+	.platform_data = &msm_camera_sensor_s5k3l1yx_data,
+	},
+};
+
+struct msm_camera_board_info apq8064_camera_board_info = {
+	.board_info = apq8064_camera_i2c_boardinfo,
+	.num_i2c_board_info = ARRAY_SIZE(apq8064_camera_i2c_boardinfo),
+};
+#endif
+#endif
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..55e8123
--- /dev/null
+++ b/arch/arm/mach-msm/board-8064-display.c
@@ -0,0 +1,995 @@
+/* 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/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/bootmem.h>
+#include <linux/ion.h>
+#include <asm/mach-types.h>
+#include <mach/msm_memtypes.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
+#include <mach/ion.h>
+#include <mach/msm_bus_board.h>
+#include <mach/socinfo.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(1920 * 1088 * 4 * 3, 0x10000)
+#else
+/* prim = 1366 x 768 x 3(bpp) x 2(pages) */
+#define MSM_FB_PRIM_BUF_SIZE roundup(1920 * 1088 * 4 * 2, 0x10000)
+#endif
+
+#define MSM_FB_SIZE roundup(MSM_FB_PRIM_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 LVDS_CHIMEI_PANEL_NAME "lvds_chimei_wxga"
+#define MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME "mipi_video_toshiba_wsvga"
+#define MIPI_VIDEO_CHIMEI_WXGA_PANEL_NAME "mipi_video_chimei_wxga"
+#define HDMI_PANEL_NAME "hdmi_msm"
+#define TVOUT_PANEL_NAME "tvout_msm"
+
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+static unsigned char hdmi_is_primary = 1;
+#else
+static unsigned char hdmi_is_primary;
+#endif
+
+unsigned char apq8064_hdmi_as_primary_selected(void)
+{
+	return hdmi_is_primary;
+}
+
+static void set_mdp_clocks_for_wuxga(void);
+
+static int msm_fb_detect_panel(const char *name)
+{
+	u32 version;
+	if (machine_is_apq8064_liquid()) {
+		version = socinfo_get_platform_version();
+		if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
+			(SOCINFO_VERSION_MINOR(version) == 1)) {
+			if (!strncmp(name, MIPI_VIDEO_CHIMEI_WXGA_PANEL_NAME,
+				strnlen(MIPI_VIDEO_CHIMEI_WXGA_PANEL_NAME,
+					PANEL_NAME_MAX_LEN)))
+				return 0;
+		} else {
+			if (!strncmp(name, LVDS_CHIMEI_PANEL_NAME,
+				strnlen(LVDS_CHIMEI_PANEL_NAME,
+					PANEL_NAME_MAX_LEN)))
+				return 0;
+		}
+	} else if (machine_is_apq8064_mtp()) {
+		if (!strncmp(name, MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME,
+			strnlen(MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME,
+				PANEL_NAME_MAX_LEN)))
+			return 0;
+	} else if (machine_is_apq8064_cdp() ||
+		       machine_is_mpq8064_dtv()) {
+		if (!strncmp(name, LVDS_CHIMEI_PANEL_NAME,
+			strnlen(LVDS_CHIMEI_PANEL_NAME,
+				PANEL_NAME_MAX_LEN)))
+			return 0;
+	}
+
+	if (!strncmp(name, HDMI_PANEL_NAME,
+			strnlen(HDMI_PANEL_NAME,
+				PANEL_NAME_MAX_LEN))) {
+		if (apq8064_hdmi_as_primary_selected())
+			set_mdp_clocks_for_wuxga();
+		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 struct msm_bus_vectors mdp_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+static struct msm_bus_vectors mdp_ui_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 216000000 * 2,
+		.ib = 270000000 * 2,
+	},
+};
+
+static struct msm_bus_vectors mdp_vga_vectors[] = {
+	/* VGA and less video */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 216000000 * 2,
+		.ib = 270000000 * 2,
+	},
+};
+
+static struct msm_bus_vectors mdp_720p_vectors[] = {
+	/* 720p and less video */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 230400000 * 2,
+		.ib = 288000000 * 2,
+	},
+};
+
+static struct msm_bus_vectors mdp_1080p_vectors[] = {
+	/* 1080p and less video */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 334080000 * 2,
+		.ib = 417600000 * 2,
+	},
+};
+
+static struct msm_bus_paths mdp_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(mdp_init_vectors),
+		mdp_init_vectors,
+	},
+	{
+		ARRAY_SIZE(mdp_ui_vectors),
+		mdp_ui_vectors,
+	},
+	{
+		ARRAY_SIZE(mdp_ui_vectors),
+		mdp_ui_vectors,
+	},
+	{
+		ARRAY_SIZE(mdp_vga_vectors),
+		mdp_vga_vectors,
+	},
+	{
+		ARRAY_SIZE(mdp_720p_vectors),
+		mdp_720p_vectors,
+	},
+	{
+		ARRAY_SIZE(mdp_1080p_vectors),
+		mdp_1080p_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata mdp_bus_scale_pdata = {
+	mdp_bus_scale_usecases,
+	ARRAY_SIZE(mdp_bus_scale_usecases),
+	.name = "mdp",
+};
+
+static int mdp_core_clk_rate_table[] = {
+	85330000,
+	128000000,
+	160000000,
+	200000000,
+};
+
+static struct msm_panel_common_pdata mdp_pdata = {
+	.gpio = MDP_VSYNC_GPIO,
+	.mdp_core_clk_rate = 85330000,
+	.mdp_core_clk_table = mdp_core_clk_rate_table,
+	.num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
+	.mdp_bus_scale_table = &mdp_bus_scale_pdata,
+	.mdp_rev = MDP_REV_44,
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	.mem_hid = BIT(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
+}
+
+static struct resource hdmi_msm_resources[] = {
+	{
+		.name  = "hdmi_msm_qfprom_addr",
+		.start = 0x00700000,
+		.end   = 0x007060FF,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name  = "hdmi_msm_hdmi_addr",
+		.start = 0x04A00000,
+		.end   = 0x04A00FFF,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name  = "hdmi_msm_irq",
+		.start = HDMI_IRQ,
+		.end   = HDMI_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static int hdmi_enable_5v(int on);
+static int hdmi_core_power(int on, int show);
+static int hdmi_cec_power(int on);
+
+static struct msm_hdmi_platform_data hdmi_msm_data = {
+	.irq = HDMI_IRQ,
+	.enable_5v = hdmi_enable_5v,
+	.core_power = hdmi_core_power,
+	.cec_power = hdmi_cec_power,
+};
+
+static struct platform_device hdmi_msm_device = {
+	.name = "hdmi_msm",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(hdmi_msm_resources),
+	.resource = hdmi_msm_resources,
+	.dev.platform_data = &hdmi_msm_data,
+};
+
+#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
+static struct platform_device wfd_panel_device = {
+	.name = "wfd_panel",
+	.id = 0,
+	.dev.platform_data = NULL,
+};
+
+static struct platform_device wfd_device = {
+	.name          = "msm_wfd",
+	.id            = -1,
+};
+#endif
+
+/* HDMI related GPIOs */
+#define HDMI_CEC_VAR_GPIO	69
+#define HDMI_DDC_CLK_GPIO	70
+#define HDMI_DDC_DATA_GPIO	71
+#define HDMI_HPD_GPIO		72
+
+static bool dsi_power_on;
+static int mipi_dsi_panel_power(int on)
+{
+	static struct regulator *reg_lvs7, *reg_l2, *reg_l11, *reg_ext_3p3v;
+	static int gpio36, gpio25, gpio26, mpp3;
+	int rc;
+
+	pr_debug("%s: on=%d\n", __func__, on);
+
+	if (!dsi_power_on) {
+		reg_lvs7 = regulator_get(&msm_mipi_dsi1_device.dev,
+				"dsi1_vddio");
+		if (IS_ERR_OR_NULL(reg_lvs7)) {
+			pr_err("could not get 8921_lvs7, rc = %ld\n",
+				PTR_ERR(reg_lvs7));
+			return -ENODEV;
+		}
+
+		reg_l2 = regulator_get(&msm_mipi_dsi1_device.dev,
+				"dsi1_pll_vdda");
+		if (IS_ERR_OR_NULL(reg_l2)) {
+			pr_err("could not get 8921_l2, rc = %ld\n",
+				PTR_ERR(reg_l2));
+			return -ENODEV;
+		}
+
+		rc = regulator_set_voltage(reg_l2, 1200000, 1200000);
+		if (rc) {
+			pr_err("set_voltage l2 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+		reg_l11 = regulator_get(&msm_mipi_dsi1_device.dev,
+						"dsi1_avdd");
+		if (IS_ERR(reg_l11)) {
+				pr_err("could not get 8921_l11, rc = %ld\n",
+						PTR_ERR(reg_l11));
+				return -ENODEV;
+		}
+		rc = regulator_set_voltage(reg_l11, 3000000, 3000000);
+		if (rc) {
+				pr_err("set_voltage l11 failed, rc=%d\n", rc);
+				return -EINVAL;
+		}
+
+		if (machine_is_apq8064_liquid()) {
+			reg_ext_3p3v = regulator_get(&msm_mipi_dsi1_device.dev,
+				"dsi1_vccs_3p3v");
+			if (IS_ERR_OR_NULL(reg_ext_3p3v)) {
+				pr_err("could not get reg_ext_3p3v, rc = %ld\n",
+					PTR_ERR(reg_ext_3p3v));
+				reg_ext_3p3v = NULL;
+				return -ENODEV;
+			}
+			mpp3 = PM8921_MPP_PM_TO_SYS(3);
+			rc = gpio_request(mpp3, "backlight_en");
+			if (rc) {
+				pr_err("request mpp3 failed, rc=%d\n", rc);
+				return -ENODEV;
+			}
+		}
+
+		gpio25 = PM8921_GPIO_PM_TO_SYS(25);
+		rc = gpio_request(gpio25, "disp_rst_n");
+		if (rc) {
+			pr_err("request gpio 25 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+
+		gpio26 = PM8921_GPIO_PM_TO_SYS(26);
+		rc = gpio_request(gpio26, "pwm_backlight_ctrl");
+		if (rc) {
+			pr_err("request gpio 26 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+
+		gpio36 = PM8921_GPIO_PM_TO_SYS(36); /* lcd1_pwr_en_n */
+		rc = gpio_request(gpio36, "lcd1_pwr_en_n");
+		if (rc) {
+			pr_err("request gpio 36 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+
+		dsi_power_on = true;
+	}
+
+	if (on) {
+		rc = regulator_enable(reg_lvs7);
+		if (rc) {
+			pr_err("enable lvs7 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+
+		rc = regulator_set_optimum_mode(reg_l11, 110000);
+		if (rc < 0) {
+			pr_err("set_optimum_mode l11 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+		rc = regulator_enable(reg_l11);
+		if (rc) {
+			pr_err("enable l11 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+
+		rc = regulator_set_optimum_mode(reg_l2, 100000);
+		if (rc < 0) {
+			pr_err("set_optimum_mode l2 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+		rc = regulator_enable(reg_l2);
+		if (rc) {
+			pr_err("enable l2 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+
+		if (machine_is_apq8064_liquid()) {
+			rc = regulator_enable(reg_ext_3p3v);
+			if (rc) {
+				pr_err("enable reg_ext_3p3v failed, rc=%d\n",
+					rc);
+				return -ENODEV;
+			}
+			gpio_set_value_cansleep(mpp3, 1);
+		}
+
+		gpio_set_value_cansleep(gpio36, 0);
+		gpio_set_value_cansleep(gpio25, 1);
+	} else {
+		gpio_set_value_cansleep(gpio25, 0);
+		gpio_set_value_cansleep(gpio36, 1);
+
+		if (machine_is_apq8064_liquid()) {
+			gpio_set_value_cansleep(mpp3, 0);
+
+			rc = regulator_disable(reg_ext_3p3v);
+			if (rc) {
+				pr_err("disable reg_ext_3p3v failed, rc=%d\n",
+					rc);
+				return -ENODEV;
+			}
+		}
+
+		rc = regulator_disable(reg_lvs7);
+		if (rc) {
+			pr_err("disable reg_lvs7 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		rc = regulator_disable(reg_l2);
+		if (rc) {
+			pr_err("disable reg_l2 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+	}
+
+	return 0;
+}
+
+static struct mipi_dsi_platform_data mipi_dsi_pdata = {
+	.dsi_power_save = mipi_dsi_panel_power,
+};
+
+static bool lvds_power_on;
+static int lvds_panel_power(int on)
+{
+	static struct regulator *reg_lvs7, *reg_l2, *reg_ext_3p3v;
+	static int gpio36, gpio26, mpp3;
+	int rc;
+
+	pr_debug("%s: on=%d\n", __func__, on);
+
+	if (!lvds_power_on) {
+		reg_lvs7 = regulator_get(&msm_lvds_device.dev,
+				"lvds_vdda");
+		if (IS_ERR_OR_NULL(reg_lvs7)) {
+			pr_err("could not get 8921_lvs7, rc = %ld\n",
+				PTR_ERR(reg_lvs7));
+			return -ENODEV;
+		}
+
+		reg_l2 = regulator_get(&msm_lvds_device.dev,
+				"lvds_pll_vdda");
+		if (IS_ERR_OR_NULL(reg_l2)) {
+			pr_err("could not get 8921_l2, rc = %ld\n",
+				PTR_ERR(reg_l2));
+			return -ENODEV;
+		}
+
+		rc = regulator_set_voltage(reg_l2, 1200000, 1200000);
+		if (rc) {
+			pr_err("set_voltage l2 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+
+		reg_ext_3p3v = regulator_get(&msm_lvds_device.dev,
+			"lvds_vccs_3p3v");
+		if (IS_ERR_OR_NULL(reg_ext_3p3v)) {
+			pr_err("could not get reg_ext_3p3v, rc = %ld\n",
+			       PTR_ERR(reg_ext_3p3v));
+		    return -ENODEV;
+		}
+
+		gpio26 = PM8921_GPIO_PM_TO_SYS(26);
+		rc = gpio_request(gpio26, "pwm_backlight_ctrl");
+		if (rc) {
+			pr_err("request gpio 26 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+
+		gpio36 = PM8921_GPIO_PM_TO_SYS(36); /* lcd1_pwr_en_n */
+		rc = gpio_request(gpio36, "lcd1_pwr_en_n");
+		if (rc) {
+			pr_err("request gpio 36 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+
+		mpp3 = PM8921_MPP_PM_TO_SYS(3);
+		rc = gpio_request(mpp3, "backlight_en");
+		if (rc) {
+			pr_err("request mpp3 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+
+		lvds_power_on = true;
+	}
+
+	if (on) {
+		rc = regulator_enable(reg_lvs7);
+		if (rc) {
+			pr_err("enable lvs7 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+
+		rc = regulator_set_optimum_mode(reg_l2, 100000);
+		if (rc < 0) {
+			pr_err("set_optimum_mode l2 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+		rc = regulator_enable(reg_l2);
+		if (rc) {
+			pr_err("enable l2 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+
+		rc = regulator_enable(reg_ext_3p3v);
+		if (rc) {
+			pr_err("enable reg_ext_3p3v failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+
+		gpio_set_value_cansleep(gpio36, 0);
+		gpio_set_value_cansleep(mpp3, 1);
+	} else {
+		gpio_set_value_cansleep(mpp3, 0);
+		gpio_set_value_cansleep(gpio36, 1);
+
+		rc = regulator_disable(reg_lvs7);
+		if (rc) {
+			pr_err("disable reg_lvs7 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		rc = regulator_disable(reg_l2);
+		if (rc) {
+			pr_err("disable reg_l2 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		rc = regulator_disable(reg_ext_3p3v);
+		if (rc) {
+			pr_err("disable reg_ext_3p3v failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+	}
+
+	return 0;
+}
+
+static int lvds_pixel_remap(void)
+{
+	if (machine_is_apq8064_cdp() ||
+	    machine_is_apq8064_liquid()) {
+		u32 ver = socinfo_get_version();
+		if ((SOCINFO_VERSION_MAJOR(ver) == 1) &&
+		    (SOCINFO_VERSION_MINOR(ver) == 0))
+			return 1;
+	}
+	return 0;
+}
+
+static struct lcdc_platform_data lvds_pdata = {
+	.lcdc_power_save = lvds_panel_power,
+	.lvds_pixel_remap = lvds_pixel_remap
+};
+
+#define LPM_CHANNEL 2
+static int lvds_chimei_gpio[] = {LPM_CHANNEL};
+
+static struct lvds_panel_platform_data lvds_chimei_pdata = {
+	.gpio = lvds_chimei_gpio,
+};
+
+static struct platform_device lvds_chimei_panel_device = {
+	.name = "lvds_chimei_wxga",
+	.id = 0,
+	.dev = {
+		.platform_data = &lvds_chimei_pdata,
+	}
+};
+
+static int dsi2lvds_gpio[2] = {
+	LPM_CHANNEL,/* Backlight PWM-ID=0 for PMIC-GPIO#24 */
+	0x1F08 /* DSI2LVDS Bridge GPIO Output, mask=0x1f, out=0x08 */
+};
+static struct msm_panel_common_pdata mipi_dsi2lvds_pdata = {
+	.gpio_num = dsi2lvds_gpio,
+};
+
+static struct platform_device mipi_dsi2lvds_bridge_device = {
+	.name = "mipi_tc358764",
+	.id = 0,
+	.dev.platform_data = &mipi_dsi2lvds_pdata,
+};
+
+static int toshiba_gpio[] = {LPM_CHANNEL};
+static struct mipi_dsi_panel_platform_data toshiba_pdata = {
+	.gpio = toshiba_gpio,
+};
+
+static struct platform_device mipi_dsi_toshiba_panel_device = {
+	.name = "mipi_toshiba",
+	.id = 0,
+	.dev = {
+			.platform_data = &toshiba_pdata,
+	}
+};
+
+static struct msm_bus_vectors dtv_bus_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+static struct msm_bus_vectors dtv_bus_def_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 566092800 * 2,
+		.ib = 707616000 * 2,
+	},
+};
+
+static struct msm_bus_paths dtv_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(dtv_bus_init_vectors),
+		dtv_bus_init_vectors,
+	},
+	{
+		ARRAY_SIZE(dtv_bus_def_vectors),
+		dtv_bus_def_vectors,
+	},
+};
+static struct msm_bus_scale_pdata dtv_bus_scale_pdata = {
+	dtv_bus_scale_usecases,
+	ARRAY_SIZE(dtv_bus_scale_usecases),
+	.name = "dtv",
+};
+
+static struct lcdc_platform_data dtv_pdata = {
+	.bus_scale_table = &dtv_bus_scale_pdata,
+};
+
+static int hdmi_enable_5v(int on)
+{
+	/* TBD: PM8921 regulator instead of 8901 */
+	static struct regulator *reg_8921_hdmi_mvs;	/* HDMI_5V */
+	static int prev_on;
+	int rc;
+
+	if (on == prev_on)
+		return 0;
+
+	if (!reg_8921_hdmi_mvs) {
+		reg_8921_hdmi_mvs = regulator_get(&hdmi_msm_device.dev,
+			"hdmi_mvs");
+		if (IS_ERR(reg_8921_hdmi_mvs)) {
+			pr_err("could not get reg_8921_hdmi_mvs, rc = %ld\n",
+				PTR_ERR(reg_8921_hdmi_mvs));
+			reg_8921_hdmi_mvs = NULL;
+			return -ENODEV;
+		}
+	}
+
+	if (on) {
+		rc = regulator_enable(reg_8921_hdmi_mvs);
+		if (rc) {
+			pr_err("'%s' regulator enable failed, rc=%d\n",
+				"8921_hdmi_mvs", rc);
+			return rc;
+		}
+		pr_debug("%s(on): success\n", __func__);
+	} else {
+		rc = regulator_disable(reg_8921_hdmi_mvs);
+		if (rc)
+			pr_warning("'%s' regulator disable failed, rc=%d\n",
+				"8921_hdmi_mvs", rc);
+		pr_debug("%s(off): success\n", __func__);
+	}
+
+	prev_on = on;
+
+	return 0;
+}
+
+static int hdmi_core_power(int on, int show)
+{
+	static struct regulator *reg_8921_lvs7, *reg_8921_s4, *reg_ext_3p3v;
+	static int prev_on;
+	int rc;
+	int pmic_gpio14 = PM8921_GPIO_PM_TO_SYS(14);
+
+	if (on == prev_on)
+		return 0;
+
+	/* TBD: PM8921 regulator instead of 8901 */
+	if (!reg_ext_3p3v) {
+		reg_ext_3p3v = regulator_get(&hdmi_msm_device.dev,
+					     "hdmi_mux_vdd");
+		if (IS_ERR_OR_NULL(reg_ext_3p3v)) {
+			pr_err("could not get reg_ext_3p3v, rc = %ld\n",
+			       PTR_ERR(reg_ext_3p3v));
+			reg_ext_3p3v = NULL;
+			return -ENODEV;
+		}
+	}
+
+	if (!reg_8921_lvs7) {
+		reg_8921_lvs7 = regulator_get(&hdmi_msm_device.dev,
+					      "hdmi_vdda");
+		if (IS_ERR(reg_8921_lvs7)) {
+			pr_err("could not get reg_8921_lvs7, rc = %ld\n",
+				PTR_ERR(reg_8921_lvs7));
+			reg_8921_lvs7 = NULL;
+			return -ENODEV;
+		}
+	}
+	if (!reg_8921_s4) {
+		reg_8921_s4 = regulator_get(&hdmi_msm_device.dev,
+					    "hdmi_lvl_tsl");
+		if (IS_ERR(reg_8921_s4)) {
+			pr_err("could not get reg_8921_s4, rc = %ld\n",
+				PTR_ERR(reg_8921_s4));
+			reg_8921_s4 = NULL;
+			return -ENODEV;
+		}
+		rc = regulator_set_voltage(reg_8921_s4, 1800000, 1800000);
+		if (rc) {
+			pr_err("set_voltage failed for 8921_s4, rc=%d\n", rc);
+			return -EINVAL;
+		}
+	}
+
+	if (on) {
+		/*
+		 * Configure 3P3V_BOOST_EN as GPIO, 8mA drive strength,
+		 * pull none, out-high
+		 */
+		rc = regulator_set_optimum_mode(reg_ext_3p3v, 290000);
+		if (rc < 0) {
+			pr_err("set_optimum_mode ext_3p3v failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+
+		rc = regulator_enable(reg_ext_3p3v);
+		if (rc) {
+			pr_err("enable reg_ext_3p3v failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		rc = regulator_enable(reg_8921_lvs7);
+		if (rc) {
+			pr_err("'%s' regulator enable failed, rc=%d\n",
+				"hdmi_vdda", rc);
+			return rc;
+		}
+		rc = regulator_enable(reg_8921_s4);
+		if (rc) {
+			pr_err("'%s' regulator enable failed, rc=%d\n",
+				"hdmi_lvl_tsl", rc);
+			return rc;
+		}
+		rc = gpio_request(HDMI_DDC_CLK_GPIO, "HDMI_DDC_CLK");
+		if (rc) {
+			pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+				"HDMI_DDC_CLK", HDMI_DDC_CLK_GPIO, rc);
+			goto error1;
+		}
+		rc = gpio_request(HDMI_DDC_DATA_GPIO, "HDMI_DDC_DATA");
+		if (rc) {
+			pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+				"HDMI_DDC_DATA", HDMI_DDC_DATA_GPIO, rc);
+			goto error2;
+		}
+		rc = gpio_request(HDMI_HPD_GPIO, "HDMI_HPD");
+		if (rc) {
+			pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+				"HDMI_HPD", HDMI_HPD_GPIO, rc);
+			goto error3;
+		}
+		if (machine_is_apq8064_liquid()) {
+			rc = gpio_request(pmic_gpio14, "PMIC_HDMI_MUX_SEL");
+			if (rc) {
+				pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+					"PMIC_HDMI_MUX_SEL", 14, rc);
+				goto error4;
+			}
+			gpio_set_value_cansleep(pmic_gpio14, 0);
+		}
+		pr_debug("%s(on): success\n", __func__);
+	} else {
+		gpio_free(HDMI_DDC_CLK_GPIO);
+		gpio_free(HDMI_DDC_DATA_GPIO);
+		gpio_free(HDMI_HPD_GPIO);
+
+		if (machine_is_apq8064_liquid()) {
+			gpio_set_value_cansleep(pmic_gpio14, 1);
+			gpio_free(pmic_gpio14);
+		}
+
+		rc = regulator_disable(reg_ext_3p3v);
+		if (rc) {
+			pr_err("disable reg_ext_3p3v failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		rc = regulator_disable(reg_8921_lvs7);
+		if (rc) {
+			pr_err("disable reg_8921_l23 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		rc = regulator_disable(reg_8921_s4);
+		if (rc) {
+			pr_err("disable reg_8921_s4 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		pr_debug("%s(off): success\n", __func__);
+	}
+
+	prev_on = on;
+
+	return 0;
+
+error4:
+	gpio_free(HDMI_HPD_GPIO);
+error3:
+	gpio_free(HDMI_DDC_DATA_GPIO);
+error2:
+	gpio_free(HDMI_DDC_CLK_GPIO);
+error1:
+	regulator_disable(reg_8921_lvs7);
+	regulator_disable(reg_8921_s4);
+	return rc;
+}
+
+static int hdmi_cec_power(int on)
+{
+	static int prev_on;
+	int rc;
+
+	if (on == prev_on)
+		return 0;
+
+	if (on) {
+		rc = gpio_request(HDMI_CEC_VAR_GPIO, "HDMI_CEC_VAR");
+		if (rc) {
+			pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+				"HDMI_CEC_VAR", HDMI_CEC_VAR_GPIO, rc);
+			goto error;
+		}
+		pr_debug("%s(on): success\n", __func__);
+	} else {
+		gpio_free(HDMI_CEC_VAR_GPIO);
+		pr_debug("%s(off): success\n", __func__);
+	}
+
+	prev_on = on;
+
+	return 0;
+error:
+	return rc;
+}
+
+void __init apq8064_init_fb(void)
+{
+	platform_device_register(&msm_fb_device);
+	platform_device_register(&lvds_chimei_panel_device);
+
+#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
+	platform_device_register(&wfd_panel_device);
+	platform_device_register(&wfd_device);
+#endif
+
+	if (machine_is_apq8064_liquid())
+		platform_device_register(&mipi_dsi2lvds_bridge_device);
+	if (machine_is_apq8064_mtp())
+		platform_device_register(&mipi_dsi_toshiba_panel_device);
+
+	msm_fb_register_device("mdp", &mdp_pdata);
+	msm_fb_register_device("lvds", &lvds_pdata);
+	msm_fb_register_device("mipi_dsi", &mipi_dsi_pdata);
+	platform_device_register(&hdmi_msm_device);
+	msm_fb_register_device("dtv", &dtv_pdata);
+}
+
+/**
+ * Set MDP clocks to high frequency to avoid DSI underflow
+ * when using high resolution 1200x1920 WUXGA panels
+ */
+static void set_mdp_clocks_for_wuxga(void)
+{
+	int i;
+
+	mdp_ui_vectors[0].ab = 2000000000;
+	mdp_ui_vectors[0].ib = 2000000000;
+	mdp_vga_vectors[0].ab = 2000000000;
+	mdp_vga_vectors[0].ib = 2000000000;
+	mdp_720p_vectors[0].ab = 2000000000;
+	mdp_720p_vectors[0].ib = 2000000000;
+	mdp_1080p_vectors[0].ab = 2000000000;
+	mdp_1080p_vectors[0].ib = 2000000000;
+
+	mdp_pdata.mdp_core_clk_rate = 200000000;
+
+	for (i = 0; i < ARRAY_SIZE(mdp_core_clk_rate_table); i++)
+		mdp_core_clk_rate_table[i] = 200000000;
+
+	if (apq8064_hdmi_as_primary_selected()) {
+		dtv_bus_def_vectors[0].ab = 2000000000;
+		dtv_bus_def_vectors[0].ib = 2000000000;
+	}
+}
+
+void __init apq8064_set_display_params(char *prim_panel, char *ext_panel)
+{
+	/*
+	 * For certain MPQ boards, HDMI should be set as primary display
+	 * by default, with the flexibility to specify any other panel
+	 * as a primary panel through boot parameters.
+	 */
+	if (machine_is_mpq8064_hrd() || machine_is_mpq8064_cdp()) {
+		pr_debug("HDMI is the primary display by default for MPQ\n");
+		if (!strnlen(prim_panel, PANEL_NAME_MAX_LEN))
+			strlcpy(msm_fb_pdata.prim_panel_name, HDMI_PANEL_NAME,
+				PANEL_NAME_MAX_LEN);
+	}
+
+	if (strnlen(prim_panel, PANEL_NAME_MAX_LEN)) {
+		strlcpy(msm_fb_pdata.prim_panel_name, prim_panel,
+			PANEL_NAME_MAX_LEN);
+		pr_debug("msm_fb_pdata.prim_panel_name %s\n",
+			msm_fb_pdata.prim_panel_name);
+
+		if (!strncmp((char *)msm_fb_pdata.prim_panel_name,
+			HDMI_PANEL_NAME, strnlen(HDMI_PANEL_NAME,
+				PANEL_NAME_MAX_LEN))) {
+			pr_debug("HDMI is the primary display by"
+				" boot parameter\n");
+			hdmi_is_primary = 1;
+			set_mdp_clocks_for_wuxga();
+		}
+	}
+	if (strnlen(ext_panel, PANEL_NAME_MAX_LEN)) {
+		strlcpy(msm_fb_pdata.ext_panel_name, ext_panel,
+			PANEL_NAME_MAX_LEN);
+		pr_debug("msm_fb_pdata.ext_panel_name %s\n",
+			msm_fb_pdata.ext_panel_name);
+	}
+}
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
new file mode 100644
index 0000000..b22c684
--- /dev/null
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -0,0 +1,1107 @@
+/* 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
+ * 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 <linux/gpio.h>
+#include <asm/mach-types.h>
+#include <asm/mach/mmc.h>
+#include <mach/msm_bus_board.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
+#include <mach/socinfo.h>
+#include "devices.h"
+#include "board-8064.h"
+
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+static struct gpiomux_setting gpio_eth_config = {
+	.pull = GPIOMUX_PULL_NONE,
+	.drv = GPIOMUX_DRV_8MA,
+	.func = GPIOMUX_FUNC_GPIO,
+};
+
+/* The SPI configurations apply to GSBI 5*/
+static struct gpiomux_setting gpio_spi_config = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_12MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+/* The SPI configurations apply to GSBI 5 chip select 2*/
+static struct gpiomux_setting gpio_spi_cs2_config = {
+	.func = GPIOMUX_FUNC_3,
+	.drv = GPIOMUX_DRV_12MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+/* Chip selects for SPI clients */
+static struct gpiomux_setting gpio_spi_cs_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_12MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+/* Chip selects for EPM SPI clients */
+static struct gpiomux_setting gpio_epm_spi_cs_config = {
+	.func = GPIOMUX_FUNC_6,
+	.drv = GPIOMUX_DRV_12MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+struct msm_gpiomux_config apq8064_ethernet_configs[] = {
+	{
+		.gpio = 43,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_eth_config,
+			[GPIOMUX_ACTIVE] = &gpio_eth_config,
+		}
+	},
+};
+#endif
+
+#ifdef CONFIG_MSM_VCAP
+static struct gpiomux_setting gpio_vcap_config[] = {
+	{
+		.func = GPIOMUX_FUNC_GPIO,
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_DOWN,
+	},
+	{
+		.func = GPIOMUX_FUNC_1,
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_DOWN,
+	},
+	{
+		.func = GPIOMUX_FUNC_2,
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_DOWN,
+	},
+	{
+		.func = GPIOMUX_FUNC_3,
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_DOWN,
+	},
+	{
+		.func = GPIOMUX_FUNC_4,
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_DOWN,
+	},
+	{
+		.func = GPIOMUX_FUNC_5,
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_DOWN,
+	},
+	{
+		.func = GPIOMUX_FUNC_6,
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_DOWN,
+	},
+	{
+		.func = GPIOMUX_FUNC_7,
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_DOWN,
+	},
+	{
+		.func = GPIOMUX_FUNC_8,
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_DOWN,
+	},
+	{
+		.func = GPIOMUX_FUNC_9,
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_DOWN,
+	},
+	{
+		.func = GPIOMUX_FUNC_A,
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_DOWN,
+	},
+};
+
+struct msm_gpiomux_config vcap_configs[] = {
+	{
+		.gpio = 20,
+		.settings = {
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[7],
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[7],
+		}
+	},
+	{
+		.gpio = 25,
+		.settings = {
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[2],
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[2],
+		}
+	},
+	{
+		.gpio = 24,
+		.settings = {
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[1],
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[1],
+		}
+	},
+	{
+		.gpio = 23,
+		.settings = {
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[2],
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[2],
+		}
+	},
+	{
+		.gpio = 19,
+		.settings = {
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[8],
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[8],
+		}
+	},
+	{
+		.gpio = 22,
+		.settings = {
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[2],
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[2],
+		}
+	},
+	{
+		.gpio = 21,
+		.settings = {
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[7],
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[7],
+		}
+	},
+	{
+		.gpio = 12,
+		.settings = {
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[6],
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[6],
+		}
+	},
+	{
+		.gpio = 18,
+		.settings = {
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[9],
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[9],
+		}
+	},
+	{
+		.gpio = 11,
+		.settings = {
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[10],
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[10],
+		}
+	},
+	{
+		.gpio = 10,
+		.settings = {
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[9],
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[9],
+		}
+	},
+	{
+		.gpio = 9,
+		.settings = {
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[2],
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[2],
+		}
+	},
+	{
+		.gpio = 26,
+		.settings = {
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[1],
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[1],
+		}
+	},
+	{
+		.gpio = 8,
+		.settings = {
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[3],
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[3],
+		}
+	},
+	{
+		.gpio = 7,
+		.settings = {
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[7],
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[7],
+		}
+	},
+	{
+		.gpio = 6,
+		.settings = {
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[7],
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[7],
+		}
+	},
+	{
+		.gpio = 80,
+		.settings = {
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[2],
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[2],
+		}
+	},
+	{
+		.gpio = 86,
+		.settings = {
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[1],
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[1],
+		}
+	},
+	{
+		.gpio = 85,
+		.settings = {
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[4],
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[4],
+		}
+	},
+	{
+		.gpio = 84,
+		.settings = {
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[3],
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[3],
+		}
+	},
+	{
+		.gpio = 5,
+		.settings = {
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[2],
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[2],
+		}
+	},
+	{
+		.gpio = 4,
+		.settings = {
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[3],
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[3],
+		}
+	},
+	{
+		.gpio = 3,
+		.settings = {
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[6],
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[6],
+		}
+	},
+	{
+		.gpio = 2,
+		.settings = {
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[5],
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[5],
+		}
+	},
+	{
+		.gpio = 82,
+		.settings = {
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[4],
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[4],
+		}
+	},
+	{
+		.gpio = 83,
+		.settings = {
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[4],
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[4],
+		}
+	},
+	{
+		.gpio = 87,
+		.settings = {
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[2],
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[2],
+		}
+	},
+	{
+		.gpio = 13,
+		.settings = {
+			[GPIOMUX_SUSPENDED] =	&gpio_vcap_config[6],
+			[GPIOMUX_ACTIVE] =		&gpio_vcap_config[6],
+		}
+	},
+};
+#endif
+
+static struct gpiomux_setting gpio_i2c_config = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gpio_i2c_config_sus = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_KEEPER,
+};
+
+static struct gpiomux_setting mbhc_hs_detect = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting cdc_mclk = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting wcnss_5wire_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv  = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting wcnss_5wire_active_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv  = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+
+static struct gpiomux_setting slimbus = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_KEEPER,
+};
+
+static struct gpiomux_setting gsbi1_uart_config = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_16MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting ext_regulator_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_OUT_LOW,
+};
+
+static struct gpiomux_setting gsbi7_func1_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi7_func2_cfg = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi3_suspended_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_KEEPER,
+};
+
+static struct gpiomux_setting gsbi3_active_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting hdmi_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting hdmi_active_1_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting hdmi_active_2_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_16MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting gsbi5_suspended_cfg = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_12MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi5_active_cfg = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_12MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting sx150x_suspended_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting sx150x_active_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+#ifdef CONFIG_USB_EHCI_MSM_HSIC
+static struct gpiomux_setting cyts_sleep_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting cyts_sleep_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting cyts_int_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting cyts_int_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct msm_gpiomux_config cyts_gpio_configs[] __initdata = {
+	{	/* TS INTERRUPT */
+		.gpio = 6,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cyts_int_act_cfg,
+			[GPIOMUX_SUSPENDED] = &cyts_int_sus_cfg,
+		},
+	},
+	{	/* TS SLEEP */
+		.gpio = 33,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cyts_sleep_act_cfg,
+			[GPIOMUX_SUSPENDED] = &cyts_sleep_sus_cfg,
+		},
+	},
+};
+
+static struct gpiomux_setting hsic_act_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting hsic_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+	.dir = GPIOMUX_OUT_LOW,
+};
+
+static struct gpiomux_setting hsic_wakeup_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_DOWN,
+	.dir = GPIOMUX_IN,
+};
+
+static struct gpiomux_setting hsic_wakeup_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+	.dir = GPIOMUX_IN,
+};
+
+static struct msm_gpiomux_config apq8064_hsic_configs[] = {
+	{
+		.gpio = 88,               /*HSIC_STROBE */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &hsic_act_cfg,
+			[GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
+		},
+	},
+	{
+		.gpio = 89,               /* HSIC_DATA */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &hsic_act_cfg,
+			[GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
+		},
+	},
+	{
+		.gpio = 47,              /* wake up */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &hsic_wakeup_act_cfg,
+			[GPIOMUX_SUSPENDED] = &hsic_wakeup_sus_cfg,
+		},
+	},
+};
+#endif
+
+static struct gpiomux_setting mxt_reset_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting mxt_reset_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting mxt_int_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting mxt_int_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config apq8064_hdmi_configs[] __initdata = {
+	{
+		.gpio = 69,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_1_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 70,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_1_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 71,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_1_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 72,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_2_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+};
+
+static struct msm_gpiomux_config apq8064_gsbi_configs[] __initdata = {
+	{
+		.gpio      = 8,			/* GSBI3 I2C QUP SDA */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi3_suspended_cfg,
+			[GPIOMUX_ACTIVE] = &gsbi3_active_cfg,
+		},
+	},
+	{
+		.gpio      = 9,			/* GSBI3 I2C QUP SCL */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi3_suspended_cfg,
+			[GPIOMUX_ACTIVE] = &gsbi3_active_cfg,
+		},
+	},
+	{
+		.gpio      = 18,		/* GSBI1 UART TX */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi1_uart_config,
+		},
+	},
+	{
+		.gpio      = 19,		/* GSBI1 UART RX */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi1_uart_config,
+		},
+	},
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+	{
+		.gpio      = 51,		/* GSBI5 QUP SPI_DATA_MOSI */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+		},
+	},
+	{
+		.gpio      = 52,		/* GSBI5 QUP SPI_DATA_MISO */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+		},
+	},
+	{
+		.gpio      = 53,		/* Funny CS0 */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+		},
+	},
+	{
+		.gpio      = 31,		/* GSBI5 QUP SPI_CS2_N */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_cs2_config,
+		},
+	},
+	{
+		.gpio      = 54,		/* GSBI5 QUP SPI_CLK */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+		},
+	},
+#endif
+	{
+		.gpio      = 30,		/* FP CS */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_cs_config,
+		},
+	},
+	{
+		.gpio      = 32,		/* EPM CS */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_epm_spi_cs_config,
+		},
+	},
+	{
+		.gpio      = 53,		/* NOR CS */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_cs_config,
+		},
+	},
+	{
+		.gpio      = 82,	/* GSBI7 UART2 TX */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi7_func2_cfg,
+		},
+	},
+	{
+		.gpio      = 83,	/* GSBI7 UART2 RX */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi7_func1_cfg,
+		},
+	},
+	{
+		.gpio      = 21,		/* GSBI1 QUP I2C_CLK */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_i2c_config_sus,
+			[GPIOMUX_ACTIVE] = &gpio_i2c_config,
+		},
+	},
+	{
+		.gpio      = 20,		/* GSBI1 QUP I2C_DATA */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_i2c_config_sus,
+			[GPIOMUX_ACTIVE] = &gpio_i2c_config,
+		},
+	},
+};
+
+static struct msm_gpiomux_config apq8064_slimbus_config[] __initdata = {
+	{
+		.gpio   = 40,           /* slimbus clk */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &slimbus,
+		},
+	},
+	{
+		.gpio   = 41,           /* slimbus data */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &slimbus,
+		},
+	},
+};
+
+static struct gpiomux_setting spkr_i2c = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_KEEPER,
+};
+
+static struct msm_gpiomux_config mpq8064_spkr_i2s_config[] __initdata = {
+	{
+		.gpio   = 47,           /* spkr i2c sck */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &spkr_i2c,
+		},
+	},
+	{
+		.gpio   = 48,           /* spkr_i2s_ws */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &spkr_i2c,
+		},
+	},
+	{
+		.gpio   = 49,           /* spkr_i2s_dout */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &spkr_i2c,
+		},
+	},
+	{
+		.gpio   = 50,           /* spkr_i2s_mclk */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &spkr_i2c,
+		},
+	},
+};
+
+static struct msm_gpiomux_config apq8064_audio_codec_configs[] __initdata = {
+	{
+		.gpio = 38,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &mbhc_hs_detect,
+		},
+	},
+	{
+		.gpio = 39,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &cdc_mclk,
+		},
+	},
+};
+
+/* External 3.3 V regulator enable */
+static struct msm_gpiomux_config apq8064_ext_regulator_configs[] __initdata = {
+	{
+		.gpio = APQ8064_EXT_3P3V_REG_EN_GPIO,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ext_regulator_config,
+		},
+	},
+};
+
+static struct gpiomux_setting ap2mdm_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting mdm2ap_status_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting mdm2ap_errfatal_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_16MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting ap2mdm_soft_reset_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting ap2mdm_wakeup = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct msm_gpiomux_config mdm_configs[] __initdata = {
+	/* AP2MDM_STATUS */
+	{
+		.gpio = 48,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
+		}
+	},
+	/* MDM2AP_STATUS */
+	{
+		.gpio = 49,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &mdm2ap_status_cfg,
+		}
+	},
+	/* MDM2AP_ERRFATAL */
+	{
+		.gpio = 19,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &mdm2ap_errfatal_cfg,
+		}
+	},
+	/* AP2MDM_ERRFATAL */
+	{
+		.gpio = 18,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
+		}
+	},
+	/* AP2MDM_SOFT_RESET, aka AP2MDM_PON_RESET_N */
+	{
+		.gpio = 27,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_soft_reset_cfg,
+		}
+	},
+	/* AP2MDM_WAKEUP */
+	{
+		.gpio = 35,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_wakeup,
+		}
+	},
+};
+
+static struct gpiomux_setting mi2s_act_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting mi2s_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct msm_gpiomux_config mpq8064_mi2s_configs[] __initdata = {
+	{
+		.gpio	= 27,		/* mi2s ws */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &mi2s_act_cfg,
+			[GPIOMUX_SUSPENDED] = &mi2s_sus_cfg,
+		},
+	},
+	{
+		.gpio	= 28,		/* mi2s sclk */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &mi2s_act_cfg,
+			[GPIOMUX_SUSPENDED] = &mi2s_sus_cfg,
+		},
+	},
+	{
+		.gpio	= 29,		/* mi2s dout3 */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &mi2s_act_cfg,
+			[GPIOMUX_SUSPENDED] = &mi2s_sus_cfg,
+		},
+	},
+	{
+		.gpio	= 30,		/* mi2s dout2 */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &mi2s_act_cfg,
+			[GPIOMUX_SUSPENDED] = &mi2s_sus_cfg,
+		},
+	},
+
+	{
+		.gpio	= 31,		/* mi2s dout1 */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &mi2s_act_cfg,
+			[GPIOMUX_SUSPENDED] = &mi2s_sus_cfg,
+		},
+	},
+	{
+		.gpio	= 32,		/* mi2s dout0 */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &mi2s_act_cfg,
+			[GPIOMUX_SUSPENDED] = &mi2s_sus_cfg,
+		},
+	},
+
+	{
+		.gpio	= 33,		/* mi2s mclk */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &mi2s_act_cfg,
+			[GPIOMUX_SUSPENDED] = &mi2s_sus_cfg,
+		},
+	},
+};
+static struct msm_gpiomux_config apq8064_mxt_configs[] __initdata = {
+	{	/* TS INTERRUPT */
+		.gpio = 6,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &mxt_int_act_cfg,
+			[GPIOMUX_SUSPENDED] = &mxt_int_sus_cfg,
+		},
+	},
+	{	/* TS RESET */
+		.gpio = 33,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &mxt_reset_act_cfg,
+			[GPIOMUX_SUSPENDED] = &mxt_reset_sus_cfg,
+		},
+	},
+};
+
+static struct msm_gpiomux_config wcnss_5wire_interface[] = {
+	{
+		.gpio = 64,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5wire_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 65,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5wire_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 66,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5wire_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 67,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5wire_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 68,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5wire_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+		},
+	},
+};
+
+static struct msm_gpiomux_config mpq8064_gsbi5_i2c_configs[] __initdata = {
+	{
+		.gpio      = 53,			/* GSBI5 I2C QUP SDA */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi5_suspended_cfg,
+			[GPIOMUX_ACTIVE] = &gsbi5_active_cfg,
+		},
+	},
+	{
+		.gpio      = 54,			/* GSBI5 I2C QUP SCL */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi5_suspended_cfg,
+			[GPIOMUX_ACTIVE] = &gsbi5_active_cfg,
+		},
+	},
+};
+
+static struct gpiomux_setting ir_suspended_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting ir_active_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config mpq8064_ir_configs[] __initdata = {
+	{
+		.gpio      = 88,			/* GPIO IR */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ir_suspended_cfg,
+			[GPIOMUX_ACTIVE] = &ir_active_cfg,
+		},
+	},
+};
+
+static struct msm_gpiomux_config sx150x_int_configs[] __initdata = {
+	{
+		.gpio      = 81,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &sx150x_suspended_cfg,
+			[GPIOMUX_ACTIVE] = &sx150x_active_cfg,
+		},
+	},
+};
+
+void __init apq8064_init_gpiomux(void)
+{
+	int rc;
+
+	rc = msm_gpiomux_init(NR_GPIO_IRQS);
+	if (rc) {
+		pr_err(KERN_ERR "msm_gpiomux_init failed %d\n", rc);
+		return;
+	}
+
+	msm_gpiomux_install(wcnss_5wire_interface,
+			ARRAY_SIZE(wcnss_5wire_interface));
+
+	if (machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
+		 machine_is_mpq8064_dtv()) {
+		msm_gpiomux_install(mpq8064_gsbi5_i2c_configs,
+				ARRAY_SIZE(mpq8064_gsbi5_i2c_configs));
+#ifdef CONFIG_MSM_VCAP
+		msm_gpiomux_install(vcap_configs,
+				ARRAY_SIZE(vcap_configs));
+#endif
+		msm_gpiomux_install(sx150x_int_configs,
+				ARRAY_SIZE(sx150x_int_configs));
+	} else {
+		#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+		msm_gpiomux_install(apq8064_ethernet_configs,
+				ARRAY_SIZE(apq8064_ethernet_configs));
+		#endif
+
+		msm_gpiomux_install(apq8064_gsbi_configs,
+				ARRAY_SIZE(apq8064_gsbi_configs));
+	}
+
+	msm_gpiomux_install(apq8064_slimbus_config,
+			ARRAY_SIZE(apq8064_slimbus_config));
+
+	msm_gpiomux_install(apq8064_audio_codec_configs,
+			ARRAY_SIZE(apq8064_audio_codec_configs));
+
+	if (machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
+		machine_is_mpq8064_dtv()) {
+		msm_gpiomux_install(mpq8064_spkr_i2s_config,
+			ARRAY_SIZE(mpq8064_spkr_i2s_config));
+	}
+
+	pr_debug("%s(): audio-auxpcm: Include GPIO configs"
+		" as audio is not the primary user"
+		" for these GPIO Pins\n", __func__);
+
+	if (machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
+		machine_is_mpq8064_dtv())
+		msm_gpiomux_install(mpq8064_mi2s_configs,
+			ARRAY_SIZE(mpq8064_mi2s_configs));
+
+	msm_gpiomux_install(apq8064_ext_regulator_configs,
+			ARRAY_SIZE(apq8064_ext_regulator_configs));
+
+	if (machine_is_apq8064_mtp())
+		msm_gpiomux_install(mdm_configs,
+			ARRAY_SIZE(mdm_configs));
+
+#ifdef CONFIG_USB_EHCI_MSM_HSIC
+	if (machine_is_apq8064_mtp())
+		msm_gpiomux_install(cyts_gpio_configs,
+				ARRAY_SIZE(cyts_gpio_configs));
+
+	if (machine_is_apq8064_mtp())
+		msm_gpiomux_install(apq8064_hsic_configs,
+				ARRAY_SIZE(apq8064_hsic_configs));
+#endif
+
+	if (machine_is_apq8064_cdp() || machine_is_apq8064_liquid())
+		msm_gpiomux_install(apq8064_mxt_configs,
+			ARRAY_SIZE(apq8064_mxt_configs));
+
+	msm_gpiomux_install(apq8064_hdmi_configs,
+			ARRAY_SIZE(apq8064_hdmi_configs));
+
+	 if (machine_is_mpq8064_cdp())
+		msm_gpiomux_install(mpq8064_ir_configs,
+				ARRAY_SIZE(mpq8064_ir_configs));
+}
diff --git a/arch/arm/mach-msm/board-8064-gpu.c b/arch/arm/mach-msm/board-8064-gpu.c
new file mode 100644
index 0000000..e24cac6
--- /dev/null
+++ b/arch/arm/mach-msm/board-8064-gpu.c
@@ -0,0 +1,251 @@
+/* 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/platform_device.h>
+#include <linux/msm_kgsl.h>
+#include <mach/msm_bus_board.h>
+#include <mach/board.h>
+#include <mach/msm_dcvs.h>
+
+#include "devices.h"
+#include "board-8064.h"
+
+#ifdef CONFIG_MSM_DCVS
+static struct msm_dcvs_freq_entry grp3d_freq[] = {
+	{0, 0, 333932},
+	{0, 0, 497532},
+	{0, 0, 707610},
+	{0, 0, 844545},
+};
+
+static struct msm_dcvs_core_info grp3d_core_info = {
+	.freq_tbl = &grp3d_freq[0],
+	.core_param = {
+		.max_time_us = 100000,
+		.num_freq = ARRAY_SIZE(grp3d_freq),
+	},
+	.algo_param = {
+		.slack_time_us = 39000,
+		.disable_pc_threshold = 86000,
+		.ss_window_size = 1000000,
+		.ss_util_pct = 95,
+		.em_max_util_pct = 97,
+		.ss_iobusy_conv = 100,
+	},
+};
+#endif /* CONFIG_MSM_DCVS */
+
+#ifdef CONFIG_MSM_BUS_SCALING
+static struct msm_bus_vectors grp3d_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+static struct msm_bus_vectors grp3d_low_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(1000),
+	},
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(1000),
+	},
+};
+
+static struct msm_bus_vectors grp3d_nominal_low_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(2000),
+	},
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(2000),
+	},
+};
+
+static struct msm_bus_vectors grp3d_nominal_high_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(3200),
+	},
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(3200),
+	},
+};
+
+static struct msm_bus_vectors grp3d_max_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(4264),
+	},
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(4264),
+	},
+};
+
+static struct msm_bus_paths grp3d_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(grp3d_init_vectors),
+		grp3d_init_vectors,
+	},
+	{
+		ARRAY_SIZE(grp3d_low_vectors),
+		grp3d_low_vectors,
+	},
+	{
+		ARRAY_SIZE(grp3d_nominal_low_vectors),
+		grp3d_nominal_low_vectors,
+	},
+	{
+		ARRAY_SIZE(grp3d_nominal_high_vectors),
+		grp3d_nominal_high_vectors,
+	},
+	{
+		ARRAY_SIZE(grp3d_max_vectors),
+		grp3d_max_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata grp3d_bus_scale_pdata = {
+	grp3d_bus_scale_usecases,
+	ARRAY_SIZE(grp3d_bus_scale_usecases),
+	.name = "grp3d",
+};
+#endif
+
+static struct resource kgsl_3d0_resources[] = {
+	{
+		.name = KGSL_3D0_REG_MEMORY,
+		.start = 0x04300000, /* GFX3D address */
+		.end = 0x0431ffff,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = KGSL_3D0_IRQ,
+		.start = GFX3D_IRQ,
+		.end = GFX3D_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static const struct kgsl_iommu_ctx kgsl_3d0_iommu0_ctxs[] = {
+	{ "gfx3d_user", 0 },
+	{ "gfx3d_priv", 1 },
+};
+
+static const struct kgsl_iommu_ctx kgsl_3d0_iommu1_ctxs[] = {
+	{ "gfx3d1_user", 0 },
+	{ "gfx3d1_priv", 1 },
+};
+
+static struct kgsl_device_iommu_data kgsl_3d0_iommu_data[] = {
+	{
+		.iommu_ctxs = kgsl_3d0_iommu0_ctxs,
+		.iommu_ctx_count = ARRAY_SIZE(kgsl_3d0_iommu0_ctxs),
+		.physstart = 0x07C00000,
+		.physend = 0x07C00000 + SZ_1M - 1,
+	},
+	{
+		.iommu_ctxs = kgsl_3d0_iommu1_ctxs,
+		.iommu_ctx_count = ARRAY_SIZE(kgsl_3d0_iommu1_ctxs),
+		.physstart = 0x07D00000,
+		.physend = 0x07D00000 + SZ_1M - 1,
+	},
+};
+
+static struct kgsl_device_platform_data kgsl_3d0_pdata = {
+	.pwrlevel = {
+		{
+			.gpu_freq = 400000000,
+			.bus_freq = 4,
+			.io_fraction = 0,
+		},
+		{
+			.gpu_freq = 325000000,
+			.bus_freq = 3,
+			.io_fraction = 33,
+		},
+		{
+			.gpu_freq = 200000000,
+			.bus_freq = 2,
+			.io_fraction = 100,
+		},
+		{
+			.gpu_freq = 128000000,
+			.bus_freq = 1,
+			.io_fraction = 100,
+		},
+		{
+			.gpu_freq = 27000000,
+			.bus_freq = 0,
+		},
+	},
+	.init_level = 1,
+	.num_levels = 5,
+	.set_grp_async = NULL,
+	.idle_timeout = HZ/10,
+	.nap_allowed = true,
+	.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM_IFACE,
+#ifdef CONFIG_MSM_BUS_SCALING
+	.bus_scale_table = &grp3d_bus_scale_pdata,
+#endif
+	.iommu_data = kgsl_3d0_iommu_data,
+	.iommu_count = ARRAY_SIZE(kgsl_3d0_iommu_data),
+#ifdef CONFIG_MSM_DCVS
+	.core_info = &grp3d_core_info,
+#endif
+};
+
+struct platform_device device_kgsl_3d0 = {
+	.name = "kgsl-3d0",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(kgsl_3d0_resources),
+	.resource = kgsl_3d0_resources,
+	.dev = {
+		.platform_data = &kgsl_3d0_pdata,
+	},
+};
+
+void __init apq8064_init_gpu(void)
+{
+	platform_device_register(&device_kgsl_3d0);
+}
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
new file mode 100644
index 0000000..877c9fc
--- /dev/null
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -0,0 +1,445 @@
+/* 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
+ * 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/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/bootmem.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/leds.h>
+#include <linux/leds-pm8xxx.h>
+#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
+#include <asm/mach-types.h>
+#include <asm/mach/mmc.h>
+#include <mach/msm_bus_board.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
+#include <mach/restart.h>
+#include "devices.h"
+#include "board-8064.h"
+
+struct pm8xxx_gpio_init {
+	unsigned			gpio;
+	struct pm_gpio			config;
+};
+
+struct pm8xxx_mpp_init {
+	unsigned			mpp;
+	struct pm8xxx_mpp_config_data	config;
+};
+
+#define PM8921_GPIO_INIT(_gpio, _dir, _buf, _val, _pull, _vin, _out_strength, \
+			_func, _inv, _disable) \
+{ \
+	.gpio	= PM8921_GPIO_PM_TO_SYS(_gpio), \
+	.config	= { \
+		.direction	= _dir, \
+		.output_buffer	= _buf, \
+		.output_value	= _val, \
+		.pull		= _pull, \
+		.vin_sel	= _vin, \
+		.out_strength	= _out_strength, \
+		.function	= _func, \
+		.inv_int_pol	= _inv, \
+		.disable_pin	= _disable, \
+	} \
+}
+
+#define PM8921_MPP_INIT(_mpp, _type, _level, _control) \
+{ \
+	.mpp	= PM8921_MPP_PM_TO_SYS(_mpp), \
+	.config	= { \
+		.type		= PM8XXX_MPP_TYPE_##_type, \
+		.level		= _level, \
+		.control	= PM8XXX_MPP_##_control, \
+	} \
+}
+
+#define PM8821_MPP_INIT(_mpp, _type, _level, _control) \
+{ \
+	.mpp	= PM8821_MPP_PM_TO_SYS(_mpp), \
+	.config	= { \
+		.type		= PM8XXX_MPP_TYPE_##_type, \
+		.level		= _level, \
+		.control	= PM8XXX_MPP_##_control, \
+	} \
+}
+
+#define PM8921_GPIO_DISABLE(_gpio) \
+	PM8921_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, 0, 0, 0, PM_GPIO_VIN_S4, \
+			 0, 0, 0, 1)
+
+#define PM8921_GPIO_OUTPUT(_gpio, _val, _strength) \
+	PM8921_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+			PM_GPIO_PULL_NO, PM_GPIO_VIN_S4, \
+			PM_GPIO_STRENGTH_##_strength, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
+#define PM8921_GPIO_OUTPUT_BUFCONF(_gpio, _val, _strength, _bufconf) \
+	PM8921_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT,\
+			PM_GPIO_OUT_BUF_##_bufconf, _val, \
+			PM_GPIO_PULL_NO, PM_GPIO_VIN_S4, \
+			PM_GPIO_STRENGTH_##_strength, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
+#define PM8921_GPIO_INPUT(_gpio, _pull) \
+	PM8921_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, PM_GPIO_OUT_BUF_CMOS, 0, \
+			_pull, PM_GPIO_VIN_S4, \
+			PM_GPIO_STRENGTH_NO, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
+#define PM8921_GPIO_OUTPUT_FUNC(_gpio, _val, _func) \
+	PM8921_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+			PM_GPIO_PULL_NO, PM_GPIO_VIN_S4, \
+			PM_GPIO_STRENGTH_HIGH, \
+			_func, 0, 0)
+
+#define PM8921_GPIO_OUTPUT_VIN(_gpio, _val, _vin) \
+	PM8921_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+			PM_GPIO_PULL_NO, _vin, \
+			PM_GPIO_STRENGTH_HIGH, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
+/* Initial PM8921 GPIO configurations */
+static struct pm8xxx_gpio_init pm8921_gpios[] __initdata = {
+	PM8921_GPIO_OUTPUT(14, 1, HIGH),	/* HDMI Mux Selector */
+	PM8921_GPIO_OUTPUT(23, 0, HIGH),	/* touchscreen power FET */
+	PM8921_GPIO_OUTPUT_BUFCONF(25, 0, LOW, CMOS), /* DISP_RESET_N */
+	PM8921_GPIO_OUTPUT_FUNC(26, 0, PM_GPIO_FUNC_2), /* Bl: Off, PWM mode */
+	PM8921_GPIO_OUTPUT_VIN(30, 1, PM_GPIO_VIN_VPH), /* SMB349 susp line */
+	PM8921_GPIO_OUTPUT_BUFCONF(36, 1, LOW, OPEN_DRAIN),
+	PM8921_GPIO_OUTPUT_FUNC(44, 0, PM_GPIO_FUNC_2),
+	PM8921_GPIO_OUTPUT(33, 0, HIGH),
+	PM8921_GPIO_OUTPUT(20, 0, HIGH),
+	PM8921_GPIO_INPUT(35, PM_GPIO_PULL_UP_30),
+	PM8921_GPIO_INPUT(38, PM_GPIO_PULL_UP_30),
+	/* TABLA CODEC RESET */
+	PM8921_GPIO_OUTPUT(34, 1, MED),
+	PM8921_GPIO_INPUT(31, PM_GPIO_PULL_NO),
+	PM8921_GPIO_OUTPUT(13, 0, HIGH),               /* PCIE_CLK_PWR_EN */
+};
+
+static struct pm8xxx_gpio_init pm8921_mtp_kp_gpios[] __initdata = {
+	PM8921_GPIO_INPUT(3, PM_GPIO_PULL_UP_30),
+	PM8921_GPIO_INPUT(4, PM_GPIO_PULL_UP_30),
+};
+
+static struct pm8xxx_gpio_init pm8921_cdp_kp_gpios[] __initdata = {
+	PM8921_GPIO_INPUT(27, PM_GPIO_PULL_UP_30),
+	PM8921_GPIO_INPUT(42, PM_GPIO_PULL_UP_30),
+	PM8921_GPIO_INPUT(17, PM_GPIO_PULL_UP_1P5),	/* SD_WP */
+};
+
+/* Initial PM8XXX MPP configurations */
+static struct pm8xxx_mpp_init pm8xxx_mpps[] __initdata = {
+	PM8921_MPP_INIT(3, D_OUTPUT, PM8921_MPP_DIG_LEVEL_VPH, DOUT_CTRL_LOW),
+	PM8921_MPP_INIT(8, D_OUTPUT, PM8921_MPP_DIG_LEVEL_S4, DOUT_CTRL_LOW),
+	/*MPP9 is used to detect docking station connection/removal on Liquid*/
+	PM8921_MPP_INIT(9, D_INPUT, PM8921_MPP_DIG_LEVEL_S4, DIN_TO_INT),
+	/* PCIE_RESET_N */
+	PM8921_MPP_INIT(1, D_OUTPUT, PM8921_MPP_DIG_LEVEL_VPH, DOUT_CTRL_HIGH),
+};
+
+void __init apq8064_pm8xxx_gpio_mpp_init(void)
+{
+	int i, rc;
+
+	for (i = 0; i < ARRAY_SIZE(pm8921_gpios); i++) {
+		rc = pm8xxx_gpio_config(pm8921_gpios[i].gpio,
+					&pm8921_gpios[i].config);
+		if (rc) {
+			pr_err("%s: pm8xxx_gpio_config: rc=%d\n", __func__, rc);
+			break;
+		}
+	}
+
+	if (machine_is_apq8064_cdp() || machine_is_apq8064_liquid())
+		for (i = 0; i < ARRAY_SIZE(pm8921_cdp_kp_gpios); i++) {
+			rc = pm8xxx_gpio_config(pm8921_cdp_kp_gpios[i].gpio,
+						&pm8921_cdp_kp_gpios[i].config);
+			if (rc) {
+				pr_err("%s: pm8xxx_gpio_config: rc=%d\n",
+					__func__, rc);
+				break;
+			}
+		}
+
+	if (machine_is_apq8064_mtp())
+		for (i = 0; i < ARRAY_SIZE(pm8921_mtp_kp_gpios); i++) {
+			rc = pm8xxx_gpio_config(pm8921_mtp_kp_gpios[i].gpio,
+						&pm8921_mtp_kp_gpios[i].config);
+			if (rc) {
+				pr_err("%s: pm8xxx_gpio_config: rc=%d\n",
+					__func__, rc);
+				break;
+			}
+		}
+
+	for (i = 0; i < ARRAY_SIZE(pm8xxx_mpps); i++) {
+		rc = pm8xxx_mpp_config(pm8xxx_mpps[i].mpp,
+					&pm8xxx_mpps[i].config);
+		if (rc) {
+			pr_err("%s: pm8xxx_mpp_config: rc=%d\n", __func__, rc);
+			break;
+		}
+	}
+}
+
+static struct pm8xxx_pwrkey_platform_data apq8064_pm8921_pwrkey_pdata = {
+	.pull_up		= 1,
+	.kpd_trigger_delay_us	= 15625,
+	.wakeup			= 1,
+};
+
+static struct pm8xxx_misc_platform_data apq8064_pm8921_misc_pdata = {
+	.priority		= 0,
+};
+
+#define PM8921_LC_LED_MAX_CURRENT	4	/* I = 4mA */
+#define PM8921_LC_LED_LOW_CURRENT	1	/* I = 1mA */
+#define PM8XXX_LED_PWM_PERIOD		1000
+#define PM8XXX_LED_PWM_DUTY_MS		20
+/**
+ * PM8XXX_PWM_CHANNEL_NONE shall be used when LED shall not be
+ * driven using PWM feature.
+ */
+#define PM8XXX_PWM_CHANNEL_NONE		-1
+
+static struct led_info pm8921_led_info[] = {
+	[0] = {
+		.name			= "led:red",
+		.default_trigger	= "ac-online",
+	},
+};
+
+static struct led_platform_data pm8921_led_core_pdata = {
+	.num_leds = ARRAY_SIZE(pm8921_led_info),
+	.leds = pm8921_led_info,
+};
+
+static int pm8921_led0_pwm_duty_pcts[56] = {
+	1, 4, 8, 12, 16, 20, 24, 28, 32, 36,
+	40, 44, 46, 52, 56, 60, 64, 68, 72, 76,
+	80, 84, 88, 92, 96, 100, 100, 100, 98, 95,
+	92, 88, 84, 82, 78, 74, 70, 66, 62, 58,
+	58, 54, 50, 48, 42, 38, 34, 30, 26, 22,
+	14, 10, 6, 4, 1
+};
+
+static struct pm8xxx_pwm_duty_cycles pm8921_led0_pwm_duty_cycles = {
+	.duty_pcts = (int *)&pm8921_led0_pwm_duty_pcts,
+	.num_duty_pcts = ARRAY_SIZE(pm8921_led0_pwm_duty_pcts),
+	.duty_ms = PM8XXX_LED_PWM_DUTY_MS,
+	.start_idx = 0,
+};
+
+static struct pm8xxx_led_config pm8921_led_configs[] = {
+	[0] = {
+		.id = PM8XXX_ID_LED_0,
+		.mode = PM8XXX_LED_MODE_PWM2,
+		.max_current = PM8921_LC_LED_MAX_CURRENT,
+		.pwm_channel = 5,
+		.pwm_period_us = PM8XXX_LED_PWM_PERIOD,
+		.pwm_duty_cycles = &pm8921_led0_pwm_duty_cycles,
+	},
+};
+
+static struct pm8xxx_led_platform_data apq8064_pm8921_leds_pdata = {
+		.led_core = &pm8921_led_core_pdata,
+		.configs = pm8921_led_configs,
+		.num_configs = ARRAY_SIZE(pm8921_led_configs),
+};
+
+static struct pm8xxx_adc_amux apq8064_pm8921_adc_channels_data[] = {
+	{"vcoin", CHANNEL_VCOIN, CHAN_PATH_SCALING2, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"vbat", CHANNEL_VBAT, CHAN_PATH_SCALING2, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"dcin", CHANNEL_DCIN, CHAN_PATH_SCALING4, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"ichg", CHANNEL_ICHG, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"vph_pwr", CHANNEL_VPH_PWR, CHAN_PATH_SCALING2, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"ibat", CHANNEL_IBAT, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"batt_therm", CHANNEL_BATT_THERM, CHAN_PATH_SCALING1, AMUX_RSV2,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_BATT_THERM},
+	{"batt_id", CHANNEL_BATT_ID, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"usbin", CHANNEL_USBIN, CHAN_PATH_SCALING3, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"pmic_therm", CHANNEL_DIE_TEMP, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_PMIC_THERM},
+	{"625mv", CHANNEL_625MV, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"125v", CHANNEL_125V, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"chg_temp", CHANNEL_CHG_TEMP, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"xo_therm", CHANNEL_MUXOFF, CHAN_PATH_SCALING1, AMUX_RSV0,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_XOTHERM},
+};
+
+static struct pm8xxx_adc_properties apq8064_pm8921_adc_data = {
+	.adc_vdd_reference	= 1800, /* milli-voltage for this adc */
+	.bitresolution		= 15,
+	.bipolar                = 0,
+};
+
+static struct pm8xxx_adc_platform_data apq8064_pm8921_adc_pdata = {
+	.adc_channel		= apq8064_pm8921_adc_channels_data,
+	.adc_num_board_channel	= ARRAY_SIZE(apq8064_pm8921_adc_channels_data),
+	.adc_prop		= &apq8064_pm8921_adc_data,
+	.adc_mpp_base		= PM8921_MPP_PM_TO_SYS(1),
+};
+
+static struct pm8xxx_mpp_platform_data
+apq8064_pm8921_mpp_pdata __devinitdata = {
+	.mpp_base	= PM8921_MPP_PM_TO_SYS(1),
+};
+
+static struct pm8xxx_gpio_platform_data
+apq8064_pm8921_gpio_pdata __devinitdata = {
+	.gpio_base	= PM8921_GPIO_PM_TO_SYS(1),
+};
+
+static struct pm8xxx_irq_platform_data
+apq8064_pm8921_irq_pdata __devinitdata = {
+	.irq_base		= PM8921_IRQ_BASE,
+	.devirq			= MSM_GPIO_TO_INT(74),
+	.irq_trigger_flag	= IRQF_TRIGGER_LOW,
+	.dev_id			= 0,
+};
+
+static struct pm8xxx_rtc_platform_data
+apq8064_pm8921_rtc_pdata = {
+	.rtc_write_enable       = false,
+	.rtc_alarm_powerup      = false,
+};
+
+static int apq8064_pm8921_therm_mitigation[] = {
+	1100,
+	700,
+	600,
+	325,
+};
+
+#define MAX_VOLTAGE_MV          4200
+static struct pm8921_charger_platform_data
+apq8064_pm8921_chg_pdata __devinitdata = {
+	.safety_time		= 180,
+	.update_time		= 60000,
+	.max_voltage		= MAX_VOLTAGE_MV,
+	.min_voltage		= 3200,
+	.resume_voltage_delta	= 100,
+	.term_current		= 100,
+	.cool_temp		= 10,
+	.warm_temp		= 40,
+	.temp_check_period	= 1,
+	.max_bat_chg_current	= 1100,
+	.cool_bat_chg_current	= 350,
+	.warm_bat_chg_current	= 350,
+	.cool_bat_voltage	= 4100,
+	.warm_bat_voltage	= 4100,
+	.thermal_mitigation	= apq8064_pm8921_therm_mitigation,
+	.thermal_levels		= ARRAY_SIZE(apq8064_pm8921_therm_mitigation),
+};
+
+static struct pm8xxx_ccadc_platform_data
+apq8064_pm8xxx_ccadc_pdata = {
+	.r_sense		= 10,
+};
+
+static struct pm8921_bms_platform_data
+apq8064_pm8921_bms_pdata __devinitdata = {
+	.battery_type	= BATT_UNKNOWN,
+	.r_sense		= 10,
+	.i_test			= 2500,
+	.v_failure		= 3000,
+	.calib_delay_ms		= 600000,
+	.max_voltage_uv		= MAX_VOLTAGE_MV * 1000,
+};
+
+static struct pm8921_platform_data
+apq8064_pm8921_platform_data __devinitdata = {
+	.regulator_pdatas	= msm8064_pm8921_regulator_pdata,
+	.irq_pdata		= &apq8064_pm8921_irq_pdata,
+	.gpio_pdata		= &apq8064_pm8921_gpio_pdata,
+	.mpp_pdata		= &apq8064_pm8921_mpp_pdata,
+	.rtc_pdata		= &apq8064_pm8921_rtc_pdata,
+	.pwrkey_pdata		= &apq8064_pm8921_pwrkey_pdata,
+	.misc_pdata		= &apq8064_pm8921_misc_pdata,
+	.leds_pdata		= &apq8064_pm8921_leds_pdata,
+	.adc_pdata		= &apq8064_pm8921_adc_pdata,
+	.charger_pdata		= &apq8064_pm8921_chg_pdata,
+	.bms_pdata		= &apq8064_pm8921_bms_pdata,
+	.ccadc_pdata		= &apq8064_pm8xxx_ccadc_pdata,
+};
+
+static struct pm8xxx_irq_platform_data
+apq8064_pm8821_irq_pdata __devinitdata = {
+	.irq_base		= PM8821_IRQ_BASE,
+	.devirq			= PM8821_SEC_IRQ_N,
+	.irq_trigger_flag	= IRQF_TRIGGER_HIGH,
+	.dev_id			= 1,
+};
+
+static struct pm8xxx_mpp_platform_data
+apq8064_pm8821_mpp_pdata __devinitdata = {
+	.mpp_base	= PM8821_MPP_PM_TO_SYS(1),
+};
+
+static struct pm8821_platform_data
+apq8064_pm8821_platform_data __devinitdata = {
+	.irq_pdata	= &apq8064_pm8821_irq_pdata,
+	.mpp_pdata	= &apq8064_pm8821_mpp_pdata,
+};
+
+static struct msm_ssbi_platform_data apq8064_ssbi_pm8921_pdata __devinitdata = {
+	.controller_type = MSM_SBI_CTRL_PMIC_ARBITER,
+	.slave	= {
+		.name		= "pm8921-core",
+		.platform_data	= &apq8064_pm8921_platform_data,
+	},
+};
+
+static struct msm_ssbi_platform_data apq8064_ssbi_pm8821_pdata __devinitdata = {
+	.controller_type = MSM_SBI_CTRL_PMIC_ARBITER,
+	.slave	= {
+		.name		= "pm8821-core",
+		.platform_data	= &apq8064_pm8821_platform_data,
+	},
+};
+
+void __init apq8064_init_pmic(void)
+{
+	pmic_reset_irq = PM8921_IRQ_BASE + PM8921_RESOUT_IRQ;
+
+	apq8064_device_ssbi_pmic1.dev.platform_data =
+						&apq8064_ssbi_pm8921_pdata;
+	apq8064_device_ssbi_pmic2.dev.platform_data =
+				&apq8064_ssbi_pm8821_pdata;
+	apq8064_pm8921_platform_data.num_regulators =
+					msm8064_pm8921_regulator_pdata_len;
+
+	if (machine_is_apq8064_rumi3()) {
+		apq8064_pm8921_irq_pdata.devirq = 0;
+		apq8064_pm8821_irq_pdata.devirq = 0;
+	} else if (machine_is_apq8064_mtp()) {
+		apq8064_pm8921_bms_pdata.battery_type = BATT_PALLADIUM;
+	} else if (machine_is_apq8064_liquid()) {
+		apq8064_pm8921_bms_pdata.battery_type = BATT_DESAY;
+	}
+}
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
new file mode 100644
index 0000000..40222b8
--- /dev/null
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -0,0 +1,619 @@
+/*
+ * 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
+ * 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/regulator/pm8xxx-regulator.h>
+
+#include "board-8064.h"
+
+#define VREG_CONSUMERS(_id) \
+	static struct regulator_consumer_supply vreg_consumers_##_id[]
+
+/*
+ * Consumer specific regulator names:
+ *			 regulator name		consumer dev_name
+ */
+VREG_CONSUMERS(L1) = {
+	REGULATOR_SUPPLY("8921_l1",		NULL),
+};
+VREG_CONSUMERS(L2) = {
+	REGULATOR_SUPPLY("8921_l2",		NULL),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.0"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.1"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.2"),
+	REGULATOR_SUPPLY("lvds_pll_vdda",	"lvds.0"),
+	REGULATOR_SUPPLY("dsi1_pll_vdda",	"mipi_dsi.1"),
+};
+VREG_CONSUMERS(L3) = {
+	REGULATOR_SUPPLY("8921_l3",		NULL),
+	REGULATOR_SUPPLY("HSUSB_3p3",		"msm_otg"),
+	REGULATOR_SUPPLY("HSUSB_3p3",		"msm_ehci_host.0"),
+	REGULATOR_SUPPLY("HSUSB_3p3",		"msm_ehci_host.1"),
+};
+VREG_CONSUMERS(L4) = {
+	REGULATOR_SUPPLY("8921_l4",		NULL),
+	REGULATOR_SUPPLY("HSUSB_1p8",		"msm_otg"),
+	REGULATOR_SUPPLY("iris_vddxo",		"wcnss_wlan.0"),
+};
+VREG_CONSUMERS(L5) = {
+	REGULATOR_SUPPLY("8921_l5",		NULL),
+	REGULATOR_SUPPLY("sdc_vdd",		"msm_sdcc.1"),
+};
+VREG_CONSUMERS(L6) = {
+	REGULATOR_SUPPLY("8921_l6",		NULL),
+	REGULATOR_SUPPLY("sdc_vdd",		"msm_sdcc.3"),
+};
+VREG_CONSUMERS(L7) = {
+	REGULATOR_SUPPLY("8921_l7",		NULL),
+	REGULATOR_SUPPLY("sdc_vddp",		"msm_sdcc.3"),
+};
+VREG_CONSUMERS(L8) = {
+	REGULATOR_SUPPLY("8921_l8",		NULL),
+	REGULATOR_SUPPLY("cam_vana",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vana",		"4-0048"),
+	REGULATOR_SUPPLY("cam_vana",		"4-006c"),
+	REGULATOR_SUPPLY("cam_vana",		"4-0034"),
+	REGULATOR_SUPPLY("cam_vana",		"4-0020"),
+};
+VREG_CONSUMERS(L9) = {
+	REGULATOR_SUPPLY("8921_l9",		NULL),
+	REGULATOR_SUPPLY("vdd",			"3-0024"),
+};
+VREG_CONSUMERS(L10) = {
+	REGULATOR_SUPPLY("8921_l10",		NULL),
+	REGULATOR_SUPPLY("iris_vddpa",		"wcnss_wlan.0"),
+};
+VREG_CONSUMERS(L11) = {
+	REGULATOR_SUPPLY("8921_l11",		NULL),
+	REGULATOR_SUPPLY("dsi1_avdd",		"mipi_dsi.1"),
+};
+VREG_CONSUMERS(L12) = {
+	REGULATOR_SUPPLY("cam_vdig",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vdig",		"4-0048"),
+	REGULATOR_SUPPLY("cam_vdig",		"4-006c"),
+	REGULATOR_SUPPLY("cam_vdig",		"4-0034"),
+	REGULATOR_SUPPLY("cam_vdig",		"4-0020"),
+	REGULATOR_SUPPLY("8921_l12",		NULL),
+};
+VREG_CONSUMERS(L14) = {
+	REGULATOR_SUPPLY("8921_l14",		NULL),
+};
+VREG_CONSUMERS(L15) = {
+	REGULATOR_SUPPLY("8921_l15",		NULL),
+};
+VREG_CONSUMERS(L16) = {
+	REGULATOR_SUPPLY("8921_l16",		NULL),
+	REGULATOR_SUPPLY("cam_vaf",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vaf",		"4-0048"),
+	REGULATOR_SUPPLY("cam_vaf",		"4-006c"),
+	REGULATOR_SUPPLY("cam_vaf",		"4-0034"),
+	REGULATOR_SUPPLY("cam_vaf",		"4-0020"),
+};
+VREG_CONSUMERS(L17) = {
+	REGULATOR_SUPPLY("8921_l17",		NULL),
+};
+VREG_CONSUMERS(L18) = {
+	REGULATOR_SUPPLY("8921_l18",		NULL),
+};
+VREG_CONSUMERS(L21) = {
+	REGULATOR_SUPPLY("8921_l21",		NULL),
+};
+VREG_CONSUMERS(L22) = {
+	REGULATOR_SUPPLY("8921_l22",		NULL),
+};
+VREG_CONSUMERS(L23) = {
+	REGULATOR_SUPPLY("8921_l23",		NULL),
+	REGULATOR_SUPPLY("pll_vdd",		"pil_qdsp6v4.1"),
+	REGULATOR_SUPPLY("pll_vdd",		"pil_qdsp6v4.2"),
+	REGULATOR_SUPPLY("HSUSB_1p8",		"msm_ehci_host.0"),
+	REGULATOR_SUPPLY("HSUSB_1p8",		"msm_ehci_host.1"),
+};
+VREG_CONSUMERS(L24) = {
+	REGULATOR_SUPPLY("8921_l24",		NULL),
+	REGULATOR_SUPPLY("riva_vddmx",		"wcnss_wlan.0"),
+};
+VREG_CONSUMERS(L25) = {
+	REGULATOR_SUPPLY("8921_l25",		NULL),
+	REGULATOR_SUPPLY("VDDD_CDC_D",		"tabla-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",	"tabla-slim"),
+	REGULATOR_SUPPLY("VDDD_CDC_D",		"tabla2x-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",	"tabla2x-slim"),
+};
+VREG_CONSUMERS(L26) = {
+	REGULATOR_SUPPLY("8921_l26",		NULL),
+	REGULATOR_SUPPLY("core_vdd",		"pil_qdsp6v4.0"),
+};
+VREG_CONSUMERS(L27) = {
+	REGULATOR_SUPPLY("8921_l27",		NULL),
+	REGULATOR_SUPPLY("core_vdd",		"pil_qdsp6v4.2"),
+};
+VREG_CONSUMERS(L28) = {
+	REGULATOR_SUPPLY("8921_l28",		NULL),
+	REGULATOR_SUPPLY("core_vdd",		"pil_qdsp6v4.1"),
+};
+VREG_CONSUMERS(L29) = {
+	REGULATOR_SUPPLY("8921_l29",		NULL),
+};
+VREG_CONSUMERS(S1) = {
+	REGULATOR_SUPPLY("8921_s1",		NULL),
+};
+VREG_CONSUMERS(S2) = {
+	REGULATOR_SUPPLY("8921_s2",		NULL),
+	REGULATOR_SUPPLY("iris_vddrfa",		"wcnss_wlan.0"),
+};
+VREG_CONSUMERS(S3) = {
+	REGULATOR_SUPPLY("8921_s3",		NULL),
+	REGULATOR_SUPPLY("HSUSB_VDDCX",		"msm_otg"),
+	REGULATOR_SUPPLY("HSUSB_VDDCX",		"msm_ehci_host.0"),
+	REGULATOR_SUPPLY("HSUSB_VDDCX",		"msm_ehci_host.1"),
+	REGULATOR_SUPPLY("HSIC_VDDCX",		"msm_hsic_host"),
+	REGULATOR_SUPPLY("riva_vddcx",		"wcnss_wlan.0"),
+	REGULATOR_SUPPLY("vp_pcie",             "msm_pcie"),
+	REGULATOR_SUPPLY("vptx_pcie",           "msm_pcie"),
+};
+VREG_CONSUMERS(S4) = {
+	REGULATOR_SUPPLY("8921_s4",		NULL),
+	REGULATOR_SUPPLY("sdc_vccq",		"msm_sdcc.1"),
+	REGULATOR_SUPPLY("VDDIO_CDC",		"tabla-slim"),
+	REGULATOR_SUPPLY("CDC_VDD_CP",		"tabla-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_TX",		"tabla-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_RX",		"tabla-slim"),
+	REGULATOR_SUPPLY("VDDIO_CDC",		"tabla2x-slim"),
+	REGULATOR_SUPPLY("CDC_VDD_CP",		"tabla2x-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_TX",		"tabla2x-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_RX",		"tabla2x-slim"),
+	REGULATOR_SUPPLY("riva_vddpx",		"wcnss_wlan.0"),
+	REGULATOR_SUPPLY("vcc_i2c",		"3-005b"),
+	REGULATOR_SUPPLY("vcc_i2c",		"3-0024"),
+	REGULATOR_SUPPLY("vddp",		"0-0048"),
+	REGULATOR_SUPPLY("hdmi_lvl_tsl",	"hdmi_msm.0"),
+};
+VREG_CONSUMERS(S5) = {
+	REGULATOR_SUPPLY("8921_s5",		NULL),
+	REGULATOR_SUPPLY("krait0",		NULL),
+};
+VREG_CONSUMERS(S6) = {
+	REGULATOR_SUPPLY("8921_s6",		NULL),
+	REGULATOR_SUPPLY("krait1",		NULL),
+};
+VREG_CONSUMERS(S7) = {
+	REGULATOR_SUPPLY("8921_s7",		NULL),
+};
+VREG_CONSUMERS(S8) = {
+	REGULATOR_SUPPLY("8921_s8",		NULL),
+};
+VREG_CONSUMERS(LVS1) = {
+	REGULATOR_SUPPLY("8921_lvs1",		NULL),
+	REGULATOR_SUPPLY("iris_vddio",		"wcnss_wlan.0"),
+};
+VREG_CONSUMERS(LVS2) = {
+	REGULATOR_SUPPLY("8921_lvs2",		NULL),
+	REGULATOR_SUPPLY("iris_vdddig",		"wcnss_wlan.0"),
+};
+VREG_CONSUMERS(LVS3) = {
+	REGULATOR_SUPPLY("8921_lvs3",		NULL),
+};
+VREG_CONSUMERS(LVS4) = {
+	REGULATOR_SUPPLY("8921_lvs4",		NULL),
+};
+VREG_CONSUMERS(LVS5) = {
+	REGULATOR_SUPPLY("8921_lvs5",		NULL),
+	REGULATOR_SUPPLY("cam_vio",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vio",		"4-0048"),
+	REGULATOR_SUPPLY("cam_vio",		"4-006c"),
+	REGULATOR_SUPPLY("cam_vio",		"4-0034"),
+	REGULATOR_SUPPLY("cam_vio",		"4-0020"),
+};
+VREG_CONSUMERS(LVS6) = {
+	REGULATOR_SUPPLY("8921_lvs6",		NULL),
+	REGULATOR_SUPPLY("vdd_pcie_vph",        "msm_pcie"),
+};
+VREG_CONSUMERS(LVS7) = {
+	REGULATOR_SUPPLY("8921_lvs7",		NULL),
+	REGULATOR_SUPPLY("pll_vdd",		"pil_riva"),
+	REGULATOR_SUPPLY("lvds_vdda",		"lvds.0"),
+	REGULATOR_SUPPLY("dsi1_vddio",		"mipi_dsi.1"),
+	REGULATOR_SUPPLY("hdmi_vdda",		"hdmi_msm.0"),
+};
+VREG_CONSUMERS(USB_OTG) = {
+	REGULATOR_SUPPLY("8921_usb_otg",	NULL),
+	REGULATOR_SUPPLY("vbus_otg",		"msm_otg"),
+};
+VREG_CONSUMERS(HDMI_MVS) = {
+	REGULATOR_SUPPLY("8921_hdmi_mvs",	NULL),
+	REGULATOR_SUPPLY("hdmi_mvs",		"hdmi_msm.0"),
+};
+VREG_CONSUMERS(NCP) = {
+	REGULATOR_SUPPLY("8921_ncp",		NULL),
+};
+VREG_CONSUMERS(8821_S0) = {
+	REGULATOR_SUPPLY("8821_s0",		NULL),
+	REGULATOR_SUPPLY("krait2",		NULL),
+};
+VREG_CONSUMERS(8821_S1) = {
+	REGULATOR_SUPPLY("8821_s1",		NULL),
+	REGULATOR_SUPPLY("krait3",		NULL),
+};
+VREG_CONSUMERS(EXT_5V) = {
+	REGULATOR_SUPPLY("ext_5v",		NULL),
+	REGULATOR_SUPPLY("ext_ddr3",		NULL),
+	REGULATOR_SUPPLY("vbus",		"msm_ehci_host.0"),
+};
+VREG_CONSUMERS(EXT_MPP8) = {
+	REGULATOR_SUPPLY("ext_mpp8",		NULL),
+	REGULATOR_SUPPLY("vbus",		"msm_ehci_host.1"),
+};
+VREG_CONSUMERS(EXT_3P3V) = {
+	REGULATOR_SUPPLY("ext_3p3v",		NULL),
+	REGULATOR_SUPPLY("vdd_io",		"spi0.2"),
+	REGULATOR_SUPPLY("mhl_ext_3p3v",	"msm_otg"),
+	REGULATOR_SUPPLY("lvds_vccs_3p3v",      "lvds.0"),
+	REGULATOR_SUPPLY("dsi1_vccs_3p3v",      "mipi_dsi.1"),
+	REGULATOR_SUPPLY("hdmi_mux_vdd",        "hdmi_msm.0"),
+	REGULATOR_SUPPLY("pcie_ext_3p3v",       "msm_pcie"),
+};
+VREG_CONSUMERS(EXT_TS_SW) = {
+	REGULATOR_SUPPLY("ext_ts_sw",		NULL),
+	REGULATOR_SUPPLY("vdd_ana",		"3-005b"),
+};
+VREG_CONSUMERS(FRC_5V) = {
+	REGULATOR_SUPPLY("frc_5v",	NULL),
+};
+VREG_CONSUMERS(AVC_1P2V) = {
+	REGULATOR_SUPPLY("avc_1p2v",	NULL),
+};
+VREG_CONSUMERS(AVC_1P8V) = {
+	REGULATOR_SUPPLY("avc_1p8v",	NULL),
+};
+VREG_CONSUMERS(AVC_2P2V) = {
+	REGULATOR_SUPPLY("avc_2p2v",	NULL),
+};
+VREG_CONSUMERS(AVC_5V) = {
+	REGULATOR_SUPPLY("avc_5v",	NULL),
+};
+VREG_CONSUMERS(AVC_3P3V) = {
+	REGULATOR_SUPPLY("avc_3p3v",	NULL),
+};
+
+#define PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
+			 _apply_uV, _pull_down, _always_on, _supply_regulator, \
+			 _system_uA, _enable_time, _reg_id) \
+	{ \
+		.init_data = { \
+			.constraints = { \
+				.valid_modes_mask	= _modes, \
+				.valid_ops_mask		= _ops, \
+				.min_uV			= _min_uV, \
+				.max_uV			= _max_uV, \
+				.input_uV		= _max_uV, \
+				.apply_uV		= _apply_uV, \
+				.always_on		= _always_on, \
+				.name			= _name, \
+			}, \
+			.num_consumer_supplies	= \
+					ARRAY_SIZE(vreg_consumers_##_id), \
+			.consumer_supplies	= vreg_consumers_##_id, \
+			.supply_regulator	= _supply_regulator, \
+		}, \
+		.id			= _reg_id, \
+		.pull_down_enable	= _pull_down, \
+		.system_uA		= _system_uA, \
+		.enable_time		= _enable_time, \
+	}
+
+#define PM8XXX_LDO(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+		_enable_time, _supply_regulator, _system_uA, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
+		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
+		REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
+
+#define PM8XXX_NLDO1200(_id, _name, _always_on, _pull_down, _min_uV, \
+		_max_uV, _enable_time, _supply_regulator, _system_uA, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
+		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
+		REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
+
+#define PM8XXX_SMPS(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+		_enable_time, _supply_regulator, _system_uA, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
+		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
+		REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
+
+#define PM8XXX_FTSMPS(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+		_enable_time, _supply_regulator, _system_uA, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL, \
+		REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS \
+		| REGULATOR_CHANGE_MODE, 0, _pull_down, _always_on, \
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
+
+#define PM8XXX_VS(_id, _name, _always_on, _pull_down, _enable_time, \
+		_supply_regulator, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, \
+		_pull_down, _always_on, _supply_regulator, 0, _enable_time, \
+		_reg_id)
+
+#define PM8XXX_VS300(_id, _name, _always_on, _pull_down, _enable_time, \
+		_supply_regulator, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, \
+		_pull_down, _always_on, _supply_regulator, 0, _enable_time, \
+		_reg_id)
+
+#define PM8XXX_NCP(_id, _name, _always_on, _min_uV, _max_uV, _enable_time, \
+		_supply_regulator, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, 0, \
+		REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, 0, 0, \
+		_always_on, _supply_regulator, 0, _enable_time, _reg_id)
+
+/* Pin control initialization */
+#define PM8XXX_PC(_id, _name, _always_on, _pin_fn, _pin_ctrl, \
+		  _supply_regulator, _reg_id) \
+	{ \
+		.init_data = { \
+			.constraints = { \
+				.valid_ops_mask	= REGULATOR_CHANGE_STATUS, \
+				.always_on	= _always_on, \
+				.name		= _name, \
+			}, \
+			.num_consumer_supplies	= \
+					ARRAY_SIZE(vreg_consumers_##_id##_PC), \
+			.consumer_supplies	= vreg_consumers_##_id##_PC, \
+			.supply_regulator  = _supply_regulator, \
+		}, \
+		.id		= _reg_id, \
+		.pin_fn		= PM8XXX_VREG_PIN_FN_##_pin_fn, \
+		.pin_ctrl	= _pin_ctrl, \
+	}
+
+#define GPIO_VREG(_id, _reg_name, _gpio_label, _gpio, _supply_regulator) \
+	[GPIO_VREG_ID_##_id] = { \
+		.init_data = { \
+			.constraints = { \
+				.valid_ops_mask	= REGULATOR_CHANGE_STATUS, \
+			}, \
+			.num_consumer_supplies	= \
+					ARRAY_SIZE(vreg_consumers_##_id), \
+			.consumer_supplies	= vreg_consumers_##_id, \
+			.supply_regulator	= _supply_regulator, \
+		}, \
+		.regulator_name = _reg_name, \
+		.gpio_label	= _gpio_label, \
+		.gpio		= _gpio, \
+	}
+
+#define SAW_VREG_INIT(_id, _name, _min_uV, _max_uV) \
+	{ \
+		.constraints = { \
+			.name		= _name, \
+			.valid_ops_mask	= REGULATOR_CHANGE_VOLTAGE, \
+			.min_uV		= _min_uV, \
+			.max_uV		= _max_uV, \
+		}, \
+		.num_consumer_supplies	= ARRAY_SIZE(vreg_consumers_##_id), \
+		.consumer_supplies	= vreg_consumers_##_id, \
+	}
+
+#define RPM_INIT(_id, _min_uV, _max_uV, _modes, _ops, _apply_uV, _default_uV, \
+		 _peak_uA, _avg_uA, _pull_down, _pin_ctrl, _freq, _pin_fn, \
+		 _force_mode, _sleep_set_force_mode, _power_mode, _state, \
+		 _sleep_selectable, _always_on, _supply_regulator, _system_uA) \
+	{ \
+		.init_data = { \
+			.constraints = { \
+				.valid_modes_mask	= _modes, \
+				.valid_ops_mask		= _ops, \
+				.min_uV			= _min_uV, \
+				.max_uV			= _max_uV, \
+				.input_uV		= _min_uV, \
+				.apply_uV		= _apply_uV, \
+				.always_on		= _always_on, \
+			}, \
+			.num_consumer_supplies	= \
+					ARRAY_SIZE(vreg_consumers_##_id), \
+			.consumer_supplies	= vreg_consumers_##_id, \
+			.supply_regulator	= _supply_regulator, \
+		}, \
+		.id			= RPM_VREG_ID_PM8921_##_id, \
+		.default_uV		= _default_uV, \
+		.peak_uA		= _peak_uA, \
+		.avg_uA			= _avg_uA, \
+		.pull_down_enable	= _pull_down, \
+		.pin_ctrl		= _pin_ctrl, \
+		.freq			= RPM_VREG_FREQ_##_freq, \
+		.pin_fn			= _pin_fn, \
+		.force_mode		= _force_mode, \
+		.sleep_set_force_mode	= _sleep_set_force_mode, \
+		.power_mode		= _power_mode, \
+		.state			= _state, \
+		.sleep_selectable	= _sleep_selectable, \
+		.system_uA		= _system_uA, \
+	}
+
+#define RPM_LDO(_id, _always_on, _pd, _sleep_selectable, _min_uV, _max_uV, \
+		_supply_regulator, _system_uA, _init_peak_uA) \
+	RPM_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+		 | REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE \
+		 | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE \
+		 | REGULATOR_CHANGE_DRMS, 0, _max_uV, _init_peak_uA, 0, _pd, \
+		 RPM_VREG_PIN_CTRL_NONE, NONE, RPM_VREG_PIN_FN_8960_NONE, \
+		 RPM_VREG_FORCE_MODE_8960_NONE, \
+		 RPM_VREG_FORCE_MODE_8960_NONE, RPM_VREG_POWER_MODE_8960_PWM, \
+		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
+		 _supply_regulator, _system_uA)
+
+#define RPM_SMPS(_id, _always_on, _pd, _sleep_selectable, _min_uV, _max_uV, \
+		 _supply_regulator, _system_uA, _freq, _force_mode, \
+		 _sleep_set_force_mode) \
+	RPM_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+		 | REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE \
+		 | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE \
+		 | REGULATOR_CHANGE_DRMS, 0, _max_uV, _system_uA, 0, _pd, \
+		 RPM_VREG_PIN_CTRL_NONE, _freq, RPM_VREG_PIN_FN_8960_NONE, \
+		 RPM_VREG_FORCE_MODE_8960_##_force_mode, \
+		 RPM_VREG_FORCE_MODE_8960_##_sleep_set_force_mode, \
+		 RPM_VREG_POWER_MODE_8960_PWM, RPM_VREG_STATE_OFF, \
+		 _sleep_selectable, _always_on, _supply_regulator, _system_uA)
+
+#define RPM_VS(_id, _always_on, _pd, _sleep_selectable, _supply_regulator) \
+	RPM_INIT(_id, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, 0, 1000, 1000, _pd, \
+		 RPM_VREG_PIN_CTRL_NONE, NONE, RPM_VREG_PIN_FN_8960_NONE, \
+		 RPM_VREG_FORCE_MODE_8960_NONE, \
+		 RPM_VREG_FORCE_MODE_8960_NONE, RPM_VREG_POWER_MODE_8960_PWM, \
+		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
+		 _supply_regulator, 0)
+
+#define RPM_NCP(_id, _always_on, _sleep_selectable, _min_uV, _max_uV, \
+		_supply_regulator, _freq) \
+	RPM_INIT(_id, _min_uV, _max_uV, 0, REGULATOR_CHANGE_VOLTAGE \
+		 | REGULATOR_CHANGE_STATUS, 0, _max_uV, 1000, 1000, 0, \
+		 RPM_VREG_PIN_CTRL_NONE, _freq, RPM_VREG_PIN_FN_8960_NONE, \
+		 RPM_VREG_FORCE_MODE_8960_NONE, \
+		 RPM_VREG_FORCE_MODE_8960_NONE, RPM_VREG_POWER_MODE_8960_PWM, \
+		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
+		 _supply_regulator, 0)
+
+/* Pin control initialization */
+#define RPM_PC_INIT(_id, _always_on, _pin_fn, _pin_ctrl, _supply_regulator) \
+	{ \
+		.init_data = { \
+			.constraints = { \
+				.valid_ops_mask	= REGULATOR_CHANGE_STATUS, \
+				.always_on	= _always_on, \
+			}, \
+			.num_consumer_supplies	= \
+					ARRAY_SIZE(vreg_consumers_##_id##_PC), \
+			.consumer_supplies	= vreg_consumers_##_id##_PC, \
+			.supply_regulator	= _supply_regulator, \
+		}, \
+		.id	  = RPM_VREG_ID_PM8921_##_id##_PC, \
+		.pin_fn	  = RPM_VREG_PIN_FN_8960_##_pin_fn, \
+		.pin_ctrl = _pin_ctrl, \
+	}
+
+/* GPIO regulator constraints */
+struct gpio_regulator_platform_data
+apq8064_gpio_regulator_pdata[] __devinitdata = {
+	/*        ID      vreg_name gpio_label   gpio                  supply */
+	GPIO_VREG(EXT_5V, "ext_5v", "ext_5v_en", PM8921_MPP_PM_TO_SYS(7), NULL),
+	GPIO_VREG(EXT_3P3V, "ext_3p3v", "ext_3p3v_en",
+		  APQ8064_EXT_3P3V_REG_EN_GPIO, NULL),
+	GPIO_VREG(EXT_TS_SW, "ext_ts_sw", "ext_ts_sw_en",
+		  PM8921_GPIO_PM_TO_SYS(23), "ext_3p3v"),
+	GPIO_VREG(EXT_MPP8, "ext_mpp8", "ext_mpp8_en",
+			PM8921_MPP_PM_TO_SYS(8), NULL),
+};
+
+struct gpio_regulator_platform_data
+mpq8064_gpio_regulator_pdata[] __devinitdata = {
+	GPIO_VREG(FRC_5V, "frc_5v", "frc_5v_en", SX150X_GPIO(4, 10), NULL),
+	GPIO_VREG(AVC_1P2V, "avc_1p2v", "avc_1p2v_en", SX150X_GPIO(4, 2), NULL),
+	GPIO_VREG(AVC_1P8V, "avc_1p8v", "avc_1p8v_en", SX150X_GPIO(4, 4), NULL),
+	GPIO_VREG(AVC_2P2V, "avc_2p2v", "avc_2p2v_en",
+						 SX150X_GPIO(4, 14), NULL),
+	GPIO_VREG(AVC_5V, "avc_5v", "avc_5v_en", SX150X_GPIO(4, 3), NULL),
+	GPIO_VREG(AVC_3P3V, "avc_3p3v", "avc_3p3v_en",
+					SX150X_GPIO(4, 15), "avc_5v"),
+};
+
+/* SAW regulator constraints */
+struct regulator_init_data msm8064_saw_regulator_pdata_8921_s5 =
+	/*	      ID  vreg_name	       min_uV   max_uV */
+	SAW_VREG_INIT(S5, "8921_s5",	       950000, 1300000);
+struct regulator_init_data msm8064_saw_regulator_pdata_8921_s6 =
+	SAW_VREG_INIT(S6, "8921_s6",	       950000, 1300000);
+
+struct regulator_init_data msm8064_saw_regulator_pdata_8821_s0 =
+	/*	      ID       vreg_name	min_uV  max_uV */
+	SAW_VREG_INIT(8821_S0, "8821_s0",       950000, 1300000);
+struct regulator_init_data msm8064_saw_regulator_pdata_8821_s1 =
+	SAW_VREG_INIT(8821_S1, "8821_s1",       950000, 1300000);
+
+/* PM8921 regulator constraints */
+struct pm8xxx_regulator_platform_data
+msm8064_pm8921_regulator_pdata[] __devinitdata = {
+	/*
+	 *		ID   name always_on pd min_uV   max_uV   en_t supply
+	 *	system_uA reg_ID
+	 */
+	PM8XXX_NLDO1200(L26, "8921_l26", 0, 1, 375000, 1050000, 200, "8921_s7",
+		0, 1),
+
+	/*           ID        name     always_on pd       en_t supply reg_ID */
+	PM8XXX_VS300(USB_OTG,  "8921_usb_otg",  0, 0,         0, "ext_5v", 2),
+	PM8XXX_VS300(HDMI_MVS, "8921_hdmi_mvs", 0, 1,         0, "ext_5v", 3),
+};
+
+static struct rpm_regulator_init_data
+apq8064_rpm_regulator_init_data[] __devinitdata = {
+	/*	ID a_on pd ss min_uV   max_uV  supply sys_uA  freq  fm  ss_fm */
+	RPM_SMPS(S1, 1, 1, 0, 1225000, 1225000, NULL, 100000, 3p20, NONE, NONE),
+	RPM_SMPS(S2, 0, 1, 0, 1300000, 1300000, NULL,      0, 1p60, NONE, NONE),
+	RPM_SMPS(S3, 0, 1, 1,  500000, 1150000, NULL, 100000, 4p80, NONE, NONE),
+	RPM_SMPS(S4, 1, 1, 0, 1800000, 1800000, NULL, 100000, 1p60, AUTO, AUTO),
+	RPM_SMPS(S7, 0, 1, 0, 1300000, 1300000, NULL, 100000, 3p20, NONE, NONE),
+	RPM_SMPS(S8, 0, 1, 0, 2200000, 2200000, NULL,      0, 1p60, NONE, NONE),
+
+	/*	ID a_on pd ss min_uV   max_uV   supply    sys_uA init_ip */
+	RPM_LDO(L1,  1, 1, 0, 1100000, 1100000, "8921_s4",     0,  1000),
+	RPM_LDO(L2,  0, 1, 0, 1200000, 1200000, "8921_s4",     0,     0),
+	RPM_LDO(L3,  0, 1, 0, 3075000, 3075000, NULL,          0,     0),
+	RPM_LDO(L4,  1, 1, 0, 1800000, 1800000, NULL,          0, 10000),
+	RPM_LDO(L5,  0, 1, 0, 2950000, 2950000, NULL,          0,     0),
+	RPM_LDO(L6,  0, 1, 0, 2950000, 2950000, NULL,          0,     0),
+	RPM_LDO(L7,  0, 1, 0, 1850000, 2950000, NULL,          0,     0),
+	RPM_LDO(L8,  0, 1, 0, 2800000, 2800000, NULL,          0,     0),
+	RPM_LDO(L9,  0, 1, 0, 3000000, 3000000, NULL,          0,     0),
+	RPM_LDO(L10, 0, 1, 0, 2900000, 2900000, NULL,          0,     0),
+	RPM_LDO(L11, 0, 1, 0, 3000000, 3000000, NULL,          0,     0),
+	RPM_LDO(L12, 0, 1, 0, 1200000, 1200000, "8921_s4",     0,     0),
+	RPM_LDO(L14, 0, 1, 0, 1800000, 1800000, NULL,          0,     0),
+	RPM_LDO(L15, 0, 1, 0, 1800000, 2950000, NULL,          0,     0),
+	RPM_LDO(L16, 0, 1, 0, 2800000, 2800000, NULL,          0,     0),
+	RPM_LDO(L17, 0, 1, 0, 2000000, 2000000, NULL,          0,     0),
+	RPM_LDO(L18, 0, 1, 0, 1300000, 1800000, "8921_s4",     0,     0),
+	RPM_LDO(L21, 0, 1, 0, 1050000, 1050000, NULL,          0,     0),
+	RPM_LDO(L22, 0, 1, 0, 2600000, 2600000, NULL,          0,     0),
+	RPM_LDO(L23, 0, 1, 0, 1800000, 1800000, NULL,          0,     0),
+	RPM_LDO(L24, 0, 1, 1,  750000, 1150000, "8921_s1", 10000, 10000),
+	RPM_LDO(L25, 1, 1, 0, 1225000, 1225000, "8921_s1", 10000, 10000),
+	RPM_LDO(L27, 0, 1, 0, 1100000, 1100000, "8921_s7",     0,     0),
+	RPM_LDO(L28, 0, 1, 0, 1050000, 1050000, "8921_s7",     0,     0),
+	RPM_LDO(L29, 0, 1, 0, 2000000, 2000000, NULL,          0,     0),
+
+	/*     ID  a_on pd ss                   supply */
+	RPM_VS(LVS1, 0, 1, 0,                   "8921_s4"),
+	RPM_VS(LVS2, 0, 1, 0,                   "8921_s1"),
+	RPM_VS(LVS3, 0, 1, 0,                   "8921_s4"),
+	RPM_VS(LVS4, 0, 1, 0,                   "8921_s4"),
+	RPM_VS(LVS5, 0, 1, 0,                   "8921_s4"),
+	RPM_VS(LVS6, 0, 1, 0,                   "8921_s4"),
+	RPM_VS(LVS7, 0, 1, 1,                   "8921_s4"),
+
+	/*	ID a_on    ss min_uV   max_uV   supply     freq */
+	RPM_NCP(NCP, 0,    0, 1800000, 1800000, "8921_l6", 1p60),
+};
+
+int msm8064_pm8921_regulator_pdata_len __devinitdata =
+	ARRAY_SIZE(msm8064_pm8921_regulator_pdata);
+
+struct rpm_regulator_platform_data apq8064_rpm_regulator_pdata __devinitdata = {
+	.init_data		= apq8064_rpm_regulator_init_data,
+	.num_regulators		= ARRAY_SIZE(apq8064_rpm_regulator_init_data),
+	.version		= RPM_VREG_VERSION_8960,
+	.vreg_id_vdd_mem	= RPM_VREG_ID_PM8921_L24,
+	.vreg_id_vdd_dig	= RPM_VREG_ID_PM8921_S3,
+};
diff --git a/arch/arm/mach-msm/board-8064-storage.c b/arch/arm/mach-msm/board-8064-storage.c
new file mode 100644
index 0000000..ed186c3
--- /dev/null
+++ b/arch/arm/mach-msm/board-8064-storage.c
@@ -0,0 +1,295 @@
+/* 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
+ * 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/gpio.h>
+#include <linux/bootmem.h>
+#include <asm/mach-types.h>
+#include <asm/mach/mmc.h>
+#include <mach/msm_bus_board.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
+#include "devices.h"
+#include "board-8064.h"
+#include "board-storage-common-a.h"
+
+
+/* APQ8064 has 4 SDCC controllers */
+enum sdcc_controllers {
+	SDCC1,
+	SDCC2,
+	SDCC3,
+	SDCC4,
+	MAX_SDCC_CONTROLLER
+};
+
+/* All SDCC controllers require VDD/VCC voltage */
+static struct msm_mmc_reg_data mmc_vdd_reg_data[MAX_SDCC_CONTROLLER] = {
+	/* SDCC1 : eMMC card connected */
+	[SDCC1] = {
+		.name = "sdc_vdd",
+		.high_vol_level = 2950000,
+		.low_vol_level = 2950000,
+		.always_on = 1,
+		.lpm_sup = 1,
+		.lpm_uA = 9000,
+		.hpm_uA = 200000, /* 200mA */
+	},
+	/* SDCC3 : External card slot connected */
+	[SDCC3] = {
+		.name = "sdc_vdd",
+		.high_vol_level = 2950000,
+		.low_vol_level = 2950000,
+		.hpm_uA = 800000, /* 800mA */
+	}
+};
+
+/* Only slots having eMMC card will require VCCQ voltage */
+static struct msm_mmc_reg_data mmc_vccq_reg_data[1] = {
+	/* SDCC1 : eMMC card connected */
+	[SDCC1] = {
+		.name = "sdc_vccq",
+		.always_on = 1,
+		.high_vol_level = 1800000,
+		.low_vol_level = 1800000,
+		.hpm_uA = 200000, /* 200mA */
+	}
+};
+
+/* All SDCC controllers may require voting for VDD PAD voltage */
+static struct msm_mmc_reg_data mmc_vddp_reg_data[MAX_SDCC_CONTROLLER] = {
+	/* SDCC3 : External card slot connected */
+	[SDCC3] = {
+		.name = "sdc_vddp",
+		.high_vol_level = 2950000,
+		.low_vol_level = 1850000,
+		.always_on = 1,
+		.lpm_sup = 1,
+		/* Max. Active current required is 16 mA */
+		.hpm_uA = 16000,
+		/*
+		 * Sleep current required is ~300 uA. But min. vote can be
+		 * in terms of mA (min. 1 mA). So let's vote for 2 mA
+		 * during sleep.
+		 */
+		.lpm_uA = 2000,
+	}
+};
+
+static struct msm_mmc_slot_reg_data mmc_slot_vreg_data[MAX_SDCC_CONTROLLER] = {
+	/* SDCC1 : eMMC card connected */
+	[SDCC1] = {
+		.vdd_data = &mmc_vdd_reg_data[SDCC1],
+		.vccq_data = &mmc_vccq_reg_data[SDCC1],
+	},
+	/* SDCC3 : External card slot connected */
+	[SDCC3] = {
+		.vdd_data = &mmc_vdd_reg_data[SDCC3],
+		.vddp_data = &mmc_vddp_reg_data[SDCC3],
+	}
+};
+
+/* SDC1 pad data */
+static struct msm_mmc_pad_drv sdc1_pad_drv_on_cfg[] = {
+	{TLMM_HDRV_SDC1_CLK, GPIO_CFG_16MA},
+	{TLMM_HDRV_SDC1_CMD, GPIO_CFG_10MA},
+	{TLMM_HDRV_SDC1_DATA, GPIO_CFG_10MA}
+};
+
+static struct msm_mmc_pad_drv sdc1_pad_drv_off_cfg[] = {
+	{TLMM_HDRV_SDC1_CLK, GPIO_CFG_2MA},
+	{TLMM_HDRV_SDC1_CMD, GPIO_CFG_2MA},
+	{TLMM_HDRV_SDC1_DATA, GPIO_CFG_2MA}
+};
+
+static struct msm_mmc_pad_pull sdc1_pad_pull_on_cfg[] = {
+	{TLMM_PULL_SDC1_CLK, GPIO_CFG_NO_PULL},
+	{TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_UP},
+	{TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_UP}
+};
+
+static struct msm_mmc_pad_pull sdc1_pad_pull_off_cfg[] = {
+	{TLMM_PULL_SDC1_CLK, GPIO_CFG_NO_PULL},
+	{TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_UP},
+	{TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_UP}
+};
+
+/* SDC3 pad data */
+static struct msm_mmc_pad_drv sdc3_pad_drv_on_cfg[] = {
+	{TLMM_HDRV_SDC3_CLK, GPIO_CFG_8MA},
+	{TLMM_HDRV_SDC3_CMD, GPIO_CFG_8MA},
+	{TLMM_HDRV_SDC3_DATA, GPIO_CFG_8MA}
+};
+
+static struct msm_mmc_pad_drv sdc3_pad_drv_off_cfg[] = {
+	{TLMM_HDRV_SDC3_CLK, GPIO_CFG_2MA},
+	{TLMM_HDRV_SDC3_CMD, GPIO_CFG_2MA},
+	{TLMM_HDRV_SDC3_DATA, GPIO_CFG_2MA}
+};
+
+static struct msm_mmc_pad_pull sdc3_pad_pull_on_cfg[] = {
+	{TLMM_PULL_SDC3_CLK, GPIO_CFG_NO_PULL},
+	{TLMM_PULL_SDC3_CMD, GPIO_CFG_PULL_UP},
+	{TLMM_PULL_SDC3_DATA, GPIO_CFG_PULL_UP}
+};
+
+static struct msm_mmc_pad_pull sdc3_pad_pull_off_cfg[] = {
+	{TLMM_PULL_SDC3_CLK, GPIO_CFG_NO_PULL},
+	{TLMM_PULL_SDC3_CMD, GPIO_CFG_PULL_UP},
+	{TLMM_PULL_SDC3_DATA, GPIO_CFG_PULL_UP}
+};
+
+static struct msm_mmc_pad_pull_data mmc_pad_pull_data[MAX_SDCC_CONTROLLER] = {
+	[SDCC1] = {
+		.on = sdc1_pad_pull_on_cfg,
+		.off = sdc1_pad_pull_off_cfg,
+		.size = ARRAY_SIZE(sdc1_pad_pull_on_cfg)
+	},
+	[SDCC3] = {
+		.on = sdc3_pad_pull_on_cfg,
+		.off = sdc3_pad_pull_off_cfg,
+		.size = ARRAY_SIZE(sdc3_pad_pull_on_cfg)
+	},
+};
+
+static struct msm_mmc_pad_drv_data mmc_pad_drv_data[MAX_SDCC_CONTROLLER] = {
+	[SDCC1] = {
+		.on = sdc1_pad_drv_on_cfg,
+		.off = sdc1_pad_drv_off_cfg,
+		.size = ARRAY_SIZE(sdc1_pad_drv_on_cfg)
+	},
+	[SDCC3] = {
+		.on = sdc3_pad_drv_on_cfg,
+		.off = sdc3_pad_drv_off_cfg,
+		.size = ARRAY_SIZE(sdc3_pad_drv_on_cfg)
+	},
+};
+
+static struct msm_mmc_pad_data mmc_pad_data[MAX_SDCC_CONTROLLER] = {
+	[SDCC1] = {
+		.pull = &mmc_pad_pull_data[SDCC1],
+		.drv = &mmc_pad_drv_data[SDCC1]
+	},
+	[SDCC3] = {
+		.pull = &mmc_pad_pull_data[SDCC3],
+		.drv = &mmc_pad_drv_data[SDCC3]
+	},
+};
+
+static struct msm_mmc_pin_data mmc_slot_pin_data[MAX_SDCC_CONTROLLER] = {
+	[SDCC1] = {
+		.pad_data = &mmc_pad_data[SDCC1],
+	},
+	[SDCC3] = {
+		.pad_data = &mmc_pad_data[SDCC3],
+	},
+};
+
+#define MSM_MPM_PIN_SDC1_DAT1	17
+#define MSM_MPM_PIN_SDC3_DAT1	21
+
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+static unsigned int sdc1_sup_clk_rates[] = {
+	400000, 24000000, 48000000, 96000000
+};
+
+static struct mmc_platform_data sdc1_data = {
+	.ocr_mask       = MMC_VDD_27_28 | MMC_VDD_28_29,
+#ifdef CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT
+	.mmc_bus_width  = MMC_CAP_8_BIT_DATA,
+#else
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+#endif
+	.sup_clk_table	= sdc1_sup_clk_rates,
+	.sup_clk_cnt	= ARRAY_SIZE(sdc1_sup_clk_rates),
+	.pclk_src_dfab	= 1,
+	.nonremovable	= 1,
+	.pin_data	= &mmc_slot_pin_data[SDCC1],
+	.vreg_data	= &mmc_slot_vreg_data[SDCC1],
+	.uhs_caps	= MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50,
+	.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC1_DAT1,
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
+};
+static struct mmc_platform_data *apq8064_sdc1_pdata = &sdc1_data;
+#else
+static struct mmc_platform_data *apq8064_sdc1_pdata;
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+static unsigned int sdc3_sup_clk_rates[] = {
+	400000, 24000000, 48000000, 96000000, 192000000
+};
+
+static struct mmc_platform_data sdc3_data = {
+	.ocr_mask       = MMC_VDD_27_28 | MMC_VDD_28_29,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.sup_clk_table	= sdc3_sup_clk_rates,
+	.sup_clk_cnt	= ARRAY_SIZE(sdc3_sup_clk_rates),
+	.pclk_src_dfab	= 1,
+	.pin_data	= &mmc_slot_pin_data[SDCC3],
+	.vreg_data	= &mmc_slot_vreg_data[SDCC3],
+	.wpswitch_gpio	= PM8921_GPIO_PM_TO_SYS(17),
+	.wpswitch_polarity = 1,
+	.status_gpio	= 26,
+	.status_irq	= MSM_GPIO_TO_INT(26),
+	.irq_flags	= IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+	.is_status_gpio_active_low = 1,
+	.xpc_cap	= 1,
+	.uhs_caps	= (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+			MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_DDR50 |
+			MMC_CAP_UHS_SDR104 | MMC_CAP_MAX_CURRENT_800),
+	.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC3_DAT1,
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
+};
+static struct mmc_platform_data *apq8064_sdc3_pdata = &sdc3_data;
+#else
+static struct mmc_platform_data *apq8064_sdc3_pdata;
+#endif
+
+void __init apq8064_init_mmc(void)
+{
+	if ((machine_is_apq8064_rumi3()) || machine_is_apq8064_sim()) {
+		if (apq8064_sdc1_pdata) {
+			if (machine_is_apq8064_sim())
+				apq8064_sdc1_pdata->disable_bam = true;
+			apq8064_sdc1_pdata->disable_runtime_pm = true;
+			apq8064_sdc1_pdata->disable_cmd23 = true;
+		}
+		if (apq8064_sdc3_pdata) {
+			if (machine_is_apq8064_sim())
+				apq8064_sdc3_pdata->disable_bam = true;
+			apq8064_sdc3_pdata->disable_runtime_pm = true;
+			apq8064_sdc3_pdata->disable_cmd23 = true;
+		}
+	}
+
+	if (apq8064_sdc1_pdata)
+		apq8064_add_sdcc(1, apq8064_sdc1_pdata);
+
+	if (apq8064_sdc3_pdata) {
+		if (!machine_is_apq8064_cdp()) {
+			apq8064_sdc3_pdata->wpswitch_gpio = 0;
+			apq8064_sdc3_pdata->wpswitch_polarity = 0;
+		}
+		if (machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
+			machine_is_mpq8064_dtv()) {
+			apq8064_sdc3_pdata->status_gpio =
+				PM8921_GPIO_PM_TO_SYS(31);
+			apq8064_sdc3_pdata->status_irq =
+				PM8921_GPIO_IRQ(PM8921_IRQ_BASE, 31);
+		}
+		apq8064_add_sdcc(3, apq8064_sdc3_pdata);
+	}
+}
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
new file mode 100644
index 0000000..cdc6b5a
--- /dev/null
+++ b/arch/arm/mach-msm/board-8064.c
@@ -0,0 +1,3070 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/i2c.h>
+#include <linux/i2c/smb349.h>
+#include <linux/i2c/sx150x.h>
+#include <linux/slimbus/slimbus.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/pdata.h>
+#include <linux/mfd/pm8xxx/misc.h>
+#include <linux/msm_ssbi.h>
+#include <linux/spi/spi.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_data/qcom_crypto_device.h>
+#include <linux/ion.h>
+#include <linux/memory.h>
+#include <linux/memblock.h>
+#include <linux/i2c/atmel_mxt_ts.h>
+#include <linux/cyttsp-qc.h>
+#include <linux/i2c/isa1200.h>
+#include <linux/gpio_keys.h>
+#include <linux/epm_adc.h>
+#include <linux/i2c/sx150x.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach/mmc.h>
+#include <linux/platform_data/qcom_wcnss_device.h>
+
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+#include <mach/ion.h>
+#include <linux/usb/msm_hsusb.h>
+#include <linux/usb/android.h>
+#include <mach/socinfo.h>
+#include <mach/msm_spi.h>
+#include "timer.h"
+#include "devices.h"
+#include <mach/gpiomux.h>
+#include <mach/rpm.h>
+#ifdef CONFIG_ANDROID_PMEM
+#include <linux/android_pmem.h>
+#endif
+#include <mach/msm_memtypes.h>
+#include <linux/bootmem.h>
+#include <asm/setup.h>
+#include <mach/dma.h>
+#include <mach/msm_dsps.h>
+#include <mach/msm_bus_board.h>
+#include <mach/cpuidle.h>
+#include <mach/mdm2.h>
+#include <linux/msm_tsens.h>
+#include <mach/msm_xo.h>
+#include <mach/msm_rtb.h>
+#include <sound/cs8427.h>
+#include <media/gpio-ir-recv.h>
+#include <linux/fmem.h>
+#include <mach/msm_pcie.h>
+
+#include "msm_watchdog.h"
+#include "board-8064.h"
+#include "acpuclock.h"
+#include "spm.h"
+#include <mach/mpm.h>
+#include "rpm_resources.h"
+#include "pm.h"
+#include "pm-boot.h"
+#include "devices-msm8x60.h"
+#include "smd_private.h"
+
+#define MSM_PMEM_ADSP_SIZE         0x7800000
+#define MSM_PMEM_AUDIO_SIZE        0x4CF000
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+#define MSM_PMEM_SIZE 0x4000000 /* 64 Mbytes */
+#else
+#define MSM_PMEM_SIZE 0x4000000 /* 64 Mbytes */
+#endif
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+#define HOLE_SIZE		0x20000
+#define MSM_PMEM_KERNEL_EBI1_SIZE  0x65000
+#ifdef CONFIG_MSM_IOMMU
+#define MSM_ION_MM_SIZE		0x3800000
+#define MSM_ION_SF_SIZE		0
+#define MSM_ION_QSECOM_SIZE	0x780000 /* (7.5MB) */
+#define MSM_ION_HEAP_NUM	7
+#else
+#define MSM_ION_MM_SIZE		MSM_PMEM_ADSP_SIZE
+#define MSM_ION_SF_SIZE		MSM_PMEM_SIZE
+#define MSM_ION_QSECOM_SIZE	0x600000 /* (6MB) */
+#define MSM_ION_HEAP_NUM	8
+#endif
+#define MSM_ION_MM_FW_SIZE	(0x200000 - HOLE_SIZE) /* (2MB - 128KB) */
+#define MSM_ION_MFC_SIZE	SZ_8K
+#define MSM_ION_AUDIO_SIZE	MSM_PMEM_AUDIO_SIZE
+#else
+#define MSM_PMEM_KERNEL_EBI1_SIZE  0x110C000
+#define MSM_ION_HEAP_NUM	1
+#endif
+
+#define APQ8064_FIXED_AREA_START (0xa0000000 - (MSM_ION_MM_FW_SIZE + \
+							HOLE_SIZE))
+#define MAX_FIXED_AREA_SIZE	0x10000000
+#define MSM_MM_FW_SIZE		(0x200000 - HOLE_SIZE)
+#define APQ8064_FW_START	APQ8064_FIXED_AREA_START
+
+/* PCIe power enable pmic gpio */
+#define PCIE_PWR_EN_PMIC_GPIO 13
+#define PCIE_RST_N_PMIC_MPP 1
+
+#ifdef CONFIG_KERNEL_PMEM_EBI_REGION
+static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE;
+static int __init pmem_kernel_ebi1_size_setup(char *p)
+{
+	pmem_kernel_ebi1_size = memparse(p, NULL);
+	return 0;
+}
+early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
+#endif
+
+#ifdef CONFIG_ANDROID_PMEM
+static unsigned pmem_size = MSM_PMEM_SIZE;
+static int __init pmem_size_setup(char *p)
+{
+	pmem_size = memparse(p, NULL);
+	return 0;
+}
+early_param("pmem_size", pmem_size_setup);
+
+static unsigned pmem_adsp_size = MSM_PMEM_ADSP_SIZE;
+
+static int __init pmem_adsp_size_setup(char *p)
+{
+	pmem_adsp_size = memparse(p, NULL);
+	return 0;
+}
+early_param("pmem_adsp_size", pmem_adsp_size_setup);
+
+static unsigned pmem_audio_size = MSM_PMEM_AUDIO_SIZE;
+
+static int __init pmem_audio_size_setup(char *p)
+{
+	pmem_audio_size = memparse(p, NULL);
+	return 0;
+}
+early_param("pmem_audio_size", pmem_audio_size_setup);
+#endif
+
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+static struct android_pmem_platform_data android_pmem_pdata = {
+	.name = "pmem",
+	.allocator_type = PMEM_ALLOCATORTYPE_ALLORNOTHING,
+	.cached = 1,
+	.memory_type = MEMTYPE_EBI1,
+};
+
+static struct platform_device apq8064_android_pmem_device = {
+	.name = "android_pmem",
+	.id = 0,
+	.dev = {.platform_data = &android_pmem_pdata},
+};
+
+static struct android_pmem_platform_data android_pmem_adsp_pdata = {
+	.name = "pmem_adsp",
+	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
+	.cached = 0,
+	.memory_type = MEMTYPE_EBI1,
+};
+static struct platform_device apq8064_android_pmem_adsp_device = {
+	.name = "android_pmem",
+	.id = 2,
+	.dev = { .platform_data = &android_pmem_adsp_pdata },
+};
+
+static struct android_pmem_platform_data android_pmem_audio_pdata = {
+	.name = "pmem_audio",
+	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
+	.cached = 0,
+	.memory_type = MEMTYPE_EBI1,
+};
+
+static struct platform_device apq8064_android_pmem_audio_device = {
+	.name = "android_pmem",
+	.id = 4,
+	.dev = { .platform_data = &android_pmem_audio_pdata },
+};
+#endif /* CONFIG_MSM_MULTIMEDIA_USE_ION */
+#endif /* CONFIG_ANDROID_PMEM */
+
+struct fmem_platform_data apq8064_fmem_pdata = {
+};
+
+static struct memtype_reserve apq8064_reserve_table[] __initdata = {
+	[MEMTYPE_SMI] = {
+	},
+	[MEMTYPE_EBI0] = {
+		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
+	},
+	[MEMTYPE_EBI1] = {
+		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
+	},
+};
+
+static void __init reserve_rtb_memory(void)
+{
+#if defined(CONFIG_MSM_RTB)
+	apq8064_reserve_table[MEMTYPE_EBI1].size += apq8064_rtb_pdata.size;
+#endif
+}
+
+
+static void __init size_pmem_devices(void)
+{
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+	android_pmem_adsp_pdata.size = pmem_adsp_size;
+	android_pmem_pdata.size = pmem_size;
+	android_pmem_audio_pdata.size = MSM_PMEM_AUDIO_SIZE;
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
+}
+
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+static void __init reserve_memory_for(struct android_pmem_platform_data *p)
+{
+	apq8064_reserve_table[p->memory_type].size += p->size;
+}
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
+
+static void __init reserve_pmem_memory(void)
+{
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+	reserve_memory_for(&android_pmem_adsp_pdata);
+	reserve_memory_for(&android_pmem_pdata);
+	reserve_memory_for(&android_pmem_audio_pdata);
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+	apq8064_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
+#endif /*CONFIG_ANDROID_PMEM*/
+}
+
+static int apq8064_paddr_to_memtype(unsigned int paddr)
+{
+	return MEMTYPE_EBI1;
+}
+
+#define FMEM_ENABLED 0
+
+#ifdef CONFIG_ION_MSM
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+static struct ion_cp_heap_pdata cp_mm_apq8064_ion_pdata = {
+	.permission_type = IPT_TYPE_MM_CARVEOUT,
+	.align = PAGE_SIZE,
+	.reusable = FMEM_ENABLED,
+	.mem_is_fmem = FMEM_ENABLED,
+	.fixed_position = FIXED_MIDDLE,
+};
+
+static struct ion_cp_heap_pdata cp_mfc_apq8064_ion_pdata = {
+	.permission_type = IPT_TYPE_MFC_SHAREDMEM,
+	.align = PAGE_SIZE,
+	.reusable = 0,
+	.mem_is_fmem = FMEM_ENABLED,
+	.fixed_position = FIXED_HIGH,
+};
+
+static struct ion_co_heap_pdata co_apq8064_ion_pdata = {
+	.adjacent_mem_id = INVALID_HEAP_ID,
+	.align = PAGE_SIZE,
+	.mem_is_fmem = 0,
+};
+
+static struct ion_co_heap_pdata fw_co_apq8064_ion_pdata = {
+	.adjacent_mem_id = ION_CP_MM_HEAP_ID,
+	.align = SZ_128K,
+	.mem_is_fmem = FMEM_ENABLED,
+	.fixed_position = FIXED_LOW,
+};
+#endif
+
+/**
+ * These heaps are listed in the order they will be allocated. Due to
+ * video hardware restrictions and content protection the FW heap has to
+ * be allocated adjacent (below) the MM heap and the MFC heap has to be
+ * allocated after the MM heap to ensure MFC heap is not more than 256MB
+ * away from the base address of the FW heap.
+ * However, the order of FW heap and MM heap doesn't matter since these
+ * two heaps are taken care of by separate code to ensure they are adjacent
+ * to each other.
+ * Don't swap the order unless you know what you are doing!
+ */
+static struct ion_platform_data apq8064_ion_pdata = {
+	.nr = MSM_ION_HEAP_NUM,
+	.heaps = {
+		{
+			.id	= ION_SYSTEM_HEAP_ID,
+			.type	= ION_HEAP_TYPE_SYSTEM,
+			.name	= ION_VMALLOC_HEAP_NAME,
+		},
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+		{
+			.id	= ION_CP_MM_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CP,
+			.name	= ION_MM_HEAP_NAME,
+			.size	= MSM_ION_MM_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &cp_mm_apq8064_ion_pdata,
+		},
+		{
+			.id	= ION_MM_FIRMWARE_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.name	= ION_MM_FIRMWARE_HEAP_NAME,
+			.size	= MSM_ION_MM_FW_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &fw_co_apq8064_ion_pdata,
+		},
+		{
+			.id	= ION_CP_MFC_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CP,
+			.name	= ION_MFC_HEAP_NAME,
+			.size	= MSM_ION_MFC_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &cp_mfc_apq8064_ion_pdata,
+		},
+#ifndef CONFIG_MSM_IOMMU
+		{
+			.id	= ION_SF_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.name	= ION_SF_HEAP_NAME,
+			.size	= MSM_ION_SF_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &co_apq8064_ion_pdata,
+		},
+#endif
+		{
+			.id	= ION_IOMMU_HEAP_ID,
+			.type	= ION_HEAP_TYPE_IOMMU,
+			.name	= ION_IOMMU_HEAP_NAME,
+		},
+		{
+			.id	= ION_QSECOM_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.name	= ION_QSECOM_HEAP_NAME,
+			.size	= MSM_ION_QSECOM_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &co_apq8064_ion_pdata,
+		},
+		{
+			.id	= ION_AUDIO_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.name	= ION_AUDIO_HEAP_NAME,
+			.size	= MSM_ION_AUDIO_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &co_apq8064_ion_pdata,
+		},
+#endif
+	}
+};
+
+static struct platform_device apq8064_ion_dev = {
+	.name = "ion-msm",
+	.id = 1,
+	.dev = { .platform_data = &apq8064_ion_pdata },
+};
+#endif
+
+static struct platform_device apq8064_fmem_device = {
+	.name = "fmem",
+	.id = 1,
+	.dev = { .platform_data = &apq8064_fmem_pdata },
+};
+
+static void __init reserve_mem_for_ion(enum ion_memory_types mem_type,
+				      unsigned long size)
+{
+	apq8064_reserve_table[mem_type].size += size;
+}
+
+static void __init apq8064_reserve_fixed_area(unsigned long fixed_area_size)
+{
+#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
+	int ret;
+
+	if (fixed_area_size > MAX_FIXED_AREA_SIZE)
+		panic("fixed area size is larger than %dM\n",
+			MAX_FIXED_AREA_SIZE >> 20);
+
+	reserve_info->fixed_area_size = fixed_area_size;
+	reserve_info->fixed_area_start = APQ8064_FW_START;
+
+	ret = memblock_remove(reserve_info->fixed_area_start,
+		reserve_info->fixed_area_size);
+	BUG_ON(ret);
+#endif
+}
+
+/**
+ * Reserve memory for ION and calculate amount of reusable memory for fmem.
+ * We only reserve memory for heaps that are not reusable. However, we only
+ * support one reusable heap at the moment so we ignore the reusable flag for
+ * other than the first heap with reusable flag set. Also handle special case
+ * for video heaps (MM,FW, and MFC). Video requires heaps MM and MFC to be
+ * at a higher address than FW in addition to not more than 256MB away from the
+ * base address of the firmware. This means that if MM is reusable the other
+ * two heaps must be allocated in the same region as FW. This is handled by the
+ * mem_is_fmem flag in the platform data. In addition the MM heap must be
+ * adjacent to the FW heap for content protection purposes.
+ */
+static void __init reserve_ion_memory(void)
+{
+#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
+	unsigned int i;
+	unsigned int reusable_count = 0;
+	unsigned int fixed_size = 0;
+	unsigned int fixed_low_size, fixed_middle_size, fixed_high_size;
+	unsigned long fixed_low_start, fixed_middle_start, fixed_high_start;
+
+	apq8064_fmem_pdata.size = 0;
+	apq8064_fmem_pdata.reserved_size_low = 0;
+	apq8064_fmem_pdata.reserved_size_high = 0;
+	apq8064_fmem_pdata.align = PAGE_SIZE;
+	fixed_low_size = 0;
+	fixed_middle_size = 0;
+	fixed_high_size = 0;
+
+	/* We only support 1 reusable heap. Check if more than one heap
+	 * is specified as reusable and set as non-reusable if found.
+	 */
+	for (i = 0; i < apq8064_ion_pdata.nr; ++i) {
+		const struct ion_platform_heap *heap =
+			&(apq8064_ion_pdata.heaps[i]);
+
+		if (heap->type == ION_HEAP_TYPE_CP && heap->extra_data) {
+			struct ion_cp_heap_pdata *data = heap->extra_data;
+
+			reusable_count += (data->reusable) ? 1 : 0;
+
+			if (data->reusable && reusable_count > 1) {
+				pr_err("%s: Too many heaps specified as "
+					"reusable. Heap %s was not configured "
+					"as reusable.\n", __func__, heap->name);
+				data->reusable = 0;
+			}
+		}
+	}
+
+	for (i = 0; i < apq8064_ion_pdata.nr; ++i) {
+		const struct ion_platform_heap *heap =
+			&(apq8064_ion_pdata.heaps[i]);
+
+		if (heap->extra_data) {
+			int fixed_position = NOT_FIXED;
+			int mem_is_fmem = 0;
+
+			switch (heap->type) {
+			case ION_HEAP_TYPE_CP:
+				mem_is_fmem = ((struct ion_cp_heap_pdata *)
+					heap->extra_data)->mem_is_fmem;
+				fixed_position = ((struct ion_cp_heap_pdata *)
+					heap->extra_data)->fixed_position;
+				break;
+			case ION_HEAP_TYPE_CARVEOUT:
+				mem_is_fmem = ((struct ion_co_heap_pdata *)
+					heap->extra_data)->mem_is_fmem;
+				fixed_position = ((struct ion_co_heap_pdata *)
+					heap->extra_data)->fixed_position;
+				break;
+			default:
+				break;
+			}
+
+			if (fixed_position != NOT_FIXED)
+				fixed_size += heap->size;
+			else
+				reserve_mem_for_ion(MEMTYPE_EBI1, heap->size);
+
+			if (fixed_position == FIXED_LOW)
+				fixed_low_size += heap->size;
+			else if (fixed_position == FIXED_MIDDLE)
+				fixed_middle_size += heap->size;
+			else if (fixed_position == FIXED_HIGH)
+				fixed_high_size += heap->size;
+
+			if (mem_is_fmem)
+				apq8064_fmem_pdata.size += heap->size;
+		}
+	}
+
+	if (!fixed_size)
+		return;
+
+	if (apq8064_fmem_pdata.size) {
+		apq8064_fmem_pdata.reserved_size_low = fixed_low_size +
+								HOLE_SIZE;
+		apq8064_fmem_pdata.reserved_size_high = fixed_high_size;
+	}
+
+	/* Since the fixed area may be carved out of lowmem,
+	 * make sure the length is a multiple of 1M.
+	 */
+	fixed_size = (fixed_size + HOLE_SIZE + SECTION_SIZE - 1)
+		& SECTION_MASK;
+	apq8064_reserve_fixed_area(fixed_size);
+
+	fixed_low_start = APQ8064_FIXED_AREA_START;
+	fixed_middle_start = fixed_low_start + fixed_low_size + HOLE_SIZE;
+	fixed_high_start = fixed_middle_start + fixed_middle_size;
+
+	for (i = 0; i < apq8064_ion_pdata.nr; ++i) {
+		struct ion_platform_heap *heap = &(apq8064_ion_pdata.heaps[i]);
+
+		if (heap->extra_data) {
+			int fixed_position = NOT_FIXED;
+			struct ion_cp_heap_pdata *pdata = NULL;
+
+			switch (heap->type) {
+			case ION_HEAP_TYPE_CP:
+				pdata =
+				(struct ion_cp_heap_pdata *)heap->extra_data;
+				fixed_position = pdata->fixed_position;
+				break;
+			case ION_HEAP_TYPE_CARVEOUT:
+				fixed_position = ((struct ion_co_heap_pdata *)
+					heap->extra_data)->fixed_position;
+				break;
+			default:
+				break;
+			}
+
+			switch (fixed_position) {
+			case FIXED_LOW:
+				heap->base = fixed_low_start;
+				break;
+			case FIXED_MIDDLE:
+				heap->base = fixed_middle_start;
+				pdata->secure_base = fixed_middle_start
+								- HOLE_SIZE;
+				pdata->secure_size = HOLE_SIZE + heap->size;
+				break;
+			case FIXED_HIGH:
+				heap->base = fixed_high_start;
+				break;
+			default:
+				break;
+			}
+		}
+	}
+#endif
+}
+
+static void __init reserve_mdp_memory(void)
+{
+	apq8064_mdp_writeback(apq8064_reserve_table);
+}
+
+static void __init reserve_cache_dump_memory(void)
+{
+#ifdef CONFIG_MSM_CACHE_DUMP
+	unsigned int total;
+
+	total = apq8064_cache_dump_pdata.l1_size +
+		apq8064_cache_dump_pdata.l2_size;
+	apq8064_reserve_table[MEMTYPE_EBI1].size += total;
+#endif
+}
+
+static void __init apq8064_calculate_reserve_sizes(void)
+{
+	size_pmem_devices();
+	reserve_pmem_memory();
+	reserve_ion_memory();
+	reserve_mdp_memory();
+	reserve_rtb_memory();
+	reserve_cache_dump_memory();
+}
+
+static struct reserve_info apq8064_reserve_info __initdata = {
+	.memtype_reserve_table = apq8064_reserve_table,
+	.calculate_reserve_sizes = apq8064_calculate_reserve_sizes,
+	.reserve_fixed_area = apq8064_reserve_fixed_area,
+	.paddr_to_memtype = apq8064_paddr_to_memtype,
+};
+
+static int apq8064_memory_bank_size(void)
+{
+	return 1<<29;
+}
+
+static void __init locate_unstable_memory(void)
+{
+	struct membank *mb = &meminfo.bank[meminfo.nr_banks - 1];
+	unsigned long bank_size;
+	unsigned long low, high;
+
+	bank_size = apq8064_memory_bank_size();
+	low = meminfo.bank[0].start;
+	high = mb->start + mb->size;
+
+	/* Check if 32 bit overflow occured */
+	if (high < mb->start)
+		high = -PAGE_SIZE;
+
+	low &= ~(bank_size - 1);
+
+	if (high - low <= bank_size)
+		goto no_dmm;
+
+#ifdef CONFIG_ENABLE_DMM
+	apq8064_reserve_info.low_unstable_address = mb->start -
+					MIN_MEMORY_BLOCK_SIZE + mb->size;
+	apq8064_reserve_info.max_unstable_size = MIN_MEMORY_BLOCK_SIZE;
+
+	apq8064_reserve_info.bank_size = bank_size;
+	pr_info("low unstable address %lx max size %lx bank size %lx\n",
+		apq8064_reserve_info.low_unstable_address,
+		apq8064_reserve_info.max_unstable_size,
+		apq8064_reserve_info.bank_size);
+	return;
+#endif
+no_dmm:
+	apq8064_reserve_info.low_unstable_address = high;
+	apq8064_reserve_info.max_unstable_size = 0;
+}
+
+static int apq8064_change_memory_power(u64 start, u64 size,
+	int change_type)
+{
+	return soc_change_memory_power(start, size, change_type);
+}
+
+static char prim_panel_name[PANEL_NAME_MAX_LEN];
+static char ext_panel_name[PANEL_NAME_MAX_LEN];
+static int __init prim_display_setup(char *param)
+{
+	if (strnlen(param, PANEL_NAME_MAX_LEN))
+		strlcpy(prim_panel_name, param, PANEL_NAME_MAX_LEN);
+	return 0;
+}
+early_param("prim_display", prim_display_setup);
+
+static int __init ext_display_setup(char *param)
+{
+	if (strnlen(param, PANEL_NAME_MAX_LEN))
+		strlcpy(ext_panel_name, param, PANEL_NAME_MAX_LEN);
+	return 0;
+}
+early_param("ext_display", ext_display_setup);
+
+static void __init apq8064_reserve(void)
+{
+	apq8064_set_display_params(prim_panel_name, ext_panel_name);
+	msm_reserve();
+	if (apq8064_fmem_pdata.size) {
+#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
+		if (reserve_info->fixed_area_size) {
+			apq8064_fmem_pdata.phys =
+				reserve_info->fixed_area_start + MSM_MM_FW_SIZE;
+			pr_info("mm fw at %lx (fixed) size %x\n",
+				reserve_info->fixed_area_start, MSM_MM_FW_SIZE);
+			pr_info("fmem start %lx (fixed) size %lx\n",
+				apq8064_fmem_pdata.phys,
+				apq8064_fmem_pdata.size);
+		}
+#endif
+	}
+}
+
+static void __init place_movable_zone(void)
+{
+#ifdef CONFIG_ENABLE_DMM
+	movable_reserved_start = apq8064_reserve_info.low_unstable_address;
+	movable_reserved_size = apq8064_reserve_info.max_unstable_size;
+	pr_info("movable zone start %lx size %lx\n",
+		movable_reserved_start, movable_reserved_size);
+#endif
+}
+
+static void __init apq8064_early_reserve(void)
+{
+	reserve_info = &apq8064_reserve_info;
+	locate_unstable_memory();
+	place_movable_zone();
+
+}
+#ifdef CONFIG_USB_EHCI_MSM_HSIC
+/* Bandwidth requests (zero) if no vote placed */
+static struct msm_bus_vectors hsic_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_SPS,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+/* Bus bandwidth requests in Bytes/sec */
+static struct msm_bus_vectors hsic_max_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 60000000,		/* At least 480Mbps on bus. */
+		.ib = 960000000,	/* MAX bursts rate */
+	},
+	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_SPS,
+		.ab = 0,
+		.ib = 512000000, /*vote for 64Mhz dfab clk rate*/
+	},
+};
+
+static struct msm_bus_paths hsic_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(hsic_init_vectors),
+		hsic_init_vectors,
+	},
+	{
+		ARRAY_SIZE(hsic_max_vectors),
+		hsic_max_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata hsic_bus_scale_pdata = {
+	hsic_bus_scale_usecases,
+	ARRAY_SIZE(hsic_bus_scale_usecases),
+	.name = "hsic",
+};
+
+static struct msm_hsic_host_platform_data msm_hsic_pdata = {
+	.strobe			= 88,
+	.data			= 89,
+	.bus_scale_table	= &hsic_bus_scale_pdata,
+};
+#else
+static struct msm_hsic_host_platform_data msm_hsic_pdata;
+#endif
+
+#define PID_MAGIC_ID		0x71432909
+#define SERIAL_NUM_MAGIC_ID	0x61945374
+#define SERIAL_NUMBER_LENGTH	127
+#define DLOAD_USB_BASE_ADD	0x2A03F0C8
+
+struct magic_num_struct {
+	uint32_t pid;
+	uint32_t serial_num;
+};
+
+struct dload_struct {
+	uint32_t	reserved1;
+	uint32_t	reserved2;
+	uint32_t	reserved3;
+	uint16_t	reserved4;
+	uint16_t	pid;
+	char		serial_number[SERIAL_NUMBER_LENGTH];
+	uint16_t	reserved5;
+	struct magic_num_struct magic_struct;
+};
+
+static int usb_diag_update_pid_and_serial_num(uint32_t pid, const char *snum)
+{
+	struct dload_struct __iomem *dload = 0;
+
+	dload = ioremap(DLOAD_USB_BASE_ADD, sizeof(*dload));
+	if (!dload) {
+		pr_err("%s: cannot remap I/O memory region: %08x\n",
+					__func__, DLOAD_USB_BASE_ADD);
+		return -ENXIO;
+	}
+
+	pr_debug("%s: dload:%p pid:%x serial_num:%s\n",
+				__func__, dload, pid, snum);
+	/* update pid */
+	dload->magic_struct.pid = PID_MAGIC_ID;
+	dload->pid = pid;
+
+	/* update serial number */
+	dload->magic_struct.serial_num = 0;
+	if (!snum) {
+		memset(dload->serial_number, 0, SERIAL_NUMBER_LENGTH);
+		goto out;
+	}
+
+	dload->magic_struct.serial_num = SERIAL_NUM_MAGIC_ID;
+	strlcpy(dload->serial_number, snum, SERIAL_NUMBER_LENGTH);
+out:
+	iounmap(dload);
+	return 0;
+}
+
+static struct android_usb_platform_data android_usb_pdata = {
+	.update_pid_and_serial_num = usb_diag_update_pid_and_serial_num,
+};
+
+static struct platform_device android_usb_device = {
+	.name	= "android_usb",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &android_usb_pdata,
+	},
+};
+
+/* Bandwidth requests (zero) if no vote placed */
+static struct msm_bus_vectors usb_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+/* Bus bandwidth requests in Bytes/sec */
+static struct msm_bus_vectors usb_max_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 60000000,		/* At least 480Mbps on bus. */
+		.ib = 960000000,	/* MAX bursts rate */
+	},
+};
+
+static struct msm_bus_paths usb_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(usb_init_vectors),
+		usb_init_vectors,
+	},
+	{
+		ARRAY_SIZE(usb_max_vectors),
+		usb_max_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata usb_bus_scale_pdata = {
+	usb_bus_scale_usecases,
+	ARRAY_SIZE(usb_bus_scale_usecases),
+	.name = "usb",
+};
+
+static int phy_init_seq[] = {
+	0x38, 0x81, /* update DC voltage level */
+	0x24, 0x82, /* set pre-emphasis and rise/fall time */
+	-1
+};
+
+static struct msm_otg_platform_data msm_otg_pdata = {
+	.mode			= USB_OTG,
+	.otg_control		= OTG_PMIC_CONTROL,
+	.phy_type		= SNPS_28NM_INTEGRATED_PHY,
+	.pmic_id_irq		= PM8921_USB_ID_IN_IRQ(PM8921_IRQ_BASE),
+	.power_budget		= 750,
+	.bus_scale_table	= &usb_bus_scale_pdata,
+	.phy_init_seq		= phy_init_seq,
+};
+
+static struct msm_usb_host_platform_data msm_ehci_host_pdata3 = {
+	.power_budget = 500,
+};
+
+#ifdef CONFIG_USB_EHCI_MSM_HOST4
+static struct msm_usb_host_platform_data msm_ehci_host_pdata4;
+#endif
+
+static void __init apq8064_ehci_host_init(void)
+{
+	if (machine_is_apq8064_liquid() || machine_is_mpq8064_cdp() ||
+		machine_is_mpq8064_hrd() || machine_is_mpq8064_dtv()) {
+		if (machine_is_apq8064_liquid())
+			msm_ehci_host_pdata3.dock_connect_irq =
+					PM8921_MPP_IRQ(PM8921_IRQ_BASE, 9);
+
+		apq8064_device_ehci_host3.dev.platform_data =
+				&msm_ehci_host_pdata3;
+		platform_device_register(&apq8064_device_ehci_host3);
+
+#ifdef CONFIG_USB_EHCI_MSM_HOST4
+		apq8064_device_ehci_host4.dev.platform_data =
+				&msm_ehci_host_pdata4;
+		platform_device_register(&apq8064_device_ehci_host4);
+#endif
+	}
+}
+
+static struct smb349_platform_data smb349_data __initdata = {
+	.en_n_gpio		= PM8921_GPIO_PM_TO_SYS(37),
+	.chg_susp_gpio		= PM8921_GPIO_PM_TO_SYS(30),
+	.chg_current_ma		= 2200,
+};
+
+static struct i2c_board_info smb349_charger_i2c_info[] __initdata = {
+	{
+		I2C_BOARD_INFO(SMB349_NAME, 0x1B),
+		.platform_data	= &smb349_data,
+	},
+};
+
+struct sx150x_platform_data apq8064_sx150x_data[] = {
+	[SX150X_EPM] = {
+		.gpio_base	= GPIO_EPM_EXPANDER_BASE,
+		.oscio_is_gpo	= false,
+		.io_pullup_ena	= 0x0,
+		.io_pulldn_ena	= 0x0,
+		.io_open_drain_ena = 0x0,
+		.io_polarity	= 0,
+		.irq_summary	= -1,
+	},
+};
+
+static struct epm_chan_properties ads_adc_channel_data[] = {
+	{10, 100}, {500, 50}, {1, 1}, {1, 1},
+	{20, 50}, {10, 100}, {1, 1}, {1, 1},
+	{10, 100}, {10, 100}, {100, 100}, {200, 100},
+	{100, 50}, {2000, 50}, {1000, 50}, {200, 50},
+	{200, 100}, {1, 1}, {20, 50}, {500, 50},
+	{50, 50}, {200, 100}, {500, 100}, {20, 50},
+	{200, 50}, {2000, 100}, {1000, 50}, {100, 50},
+	{200, 100}, {500, 50}, {1000, 100}, {200, 50},
+	{1000, 50}, {50, 50}, {100, 50}, {100, 50},
+	{1, 1}, {1, 1}, {20, 100}, {20, 50},
+	{500, 100}, {1000, 100}, {100, 50}, {1000, 50},
+	{100, 50}, {1000, 100}, {100, 50}, {100, 50},
+};
+
+static struct epm_adc_platform_data epm_adc_pdata = {
+	.channel		= ads_adc_channel_data,
+	.bus_id	= 0x0,
+	.epm_i2c_board_info = {
+		.type	= "sx1509q",
+		.addr = 0x3e,
+		.platform_data = &apq8064_sx150x_data[SX150X_EPM],
+	},
+	.gpio_expander_base_addr = GPIO_EPM_EXPANDER_BASE,
+};
+
+static struct platform_device epm_adc_device = {
+	.name   = "epm_adc",
+	.id = -1,
+	.dev = {
+		.platform_data = &epm_adc_pdata,
+	},
+};
+
+static void __init apq8064_epm_adc_init(void)
+{
+	epm_adc_pdata.num_channels = 32;
+	epm_adc_pdata.num_adc = 2;
+	epm_adc_pdata.chan_per_adc = 16;
+	epm_adc_pdata.chan_per_mux = 8;
+};
+
+/* Micbias setting is based on 8660 CDP/MTP/FLUID requirement
+ * 4 micbiases are used to power various analog and digital
+ * microphones operating at 1800 mV. Technically, all micbiases
+ * can source from single cfilter since all microphones operate
+ * at the same voltage level. The arrangement below is to make
+ * sure all cfilters are exercised. LDO_H regulator ouput level
+ * does not need to be as high as 2.85V. It is choosen for
+ * microphone sensitivity purpose.
+ */
+static struct wcd9xxx_pdata apq8064_tabla_platform_data = {
+	.slimbus_slave_device = {
+		.name = "tabla-slave",
+		.e_addr = {0, 0, 0x10, 0, 0x17, 2},
+	},
+	.irq = MSM_GPIO_TO_INT(42),
+	.irq_base = TABLA_INTERRUPT_BASE,
+	.num_irqs = NR_WCD9XXX_IRQS,
+	.reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
+	.micbias = {
+		.ldoh_v = TABLA_LDOH_2P85_V,
+		.cfilt1_mv = 1800,
+		.cfilt2_mv = 1800,
+		.cfilt3_mv = 1800,
+		.bias1_cfilt_sel = TABLA_CFILT1_SEL,
+		.bias2_cfilt_sel = TABLA_CFILT2_SEL,
+		.bias3_cfilt_sel = TABLA_CFILT3_SEL,
+		.bias4_cfilt_sel = TABLA_CFILT3_SEL,
+	},
+	.regulator = {
+	{
+		.name = "CDC_VDD_CP",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_RX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_RX_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_TX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_TX_CUR_MAX,
+	},
+	{
+		.name = "VDDIO_CDC",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_VDDIO_CDC_CUR_MAX,
+	},
+	{
+		.name = "VDDD_CDC_D",
+		.min_uV = 1225000,
+		.max_uV = 1225000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_A_1P2V",
+		.min_uV = 1225000,
+		.max_uV = 1225000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
+	},
+	},
+};
+
+static struct slim_device apq8064_slim_tabla = {
+	.name = "tabla-slim",
+	.e_addr = {0, 1, 0x10, 0, 0x17, 2},
+	.dev = {
+		.platform_data = &apq8064_tabla_platform_data,
+	},
+};
+
+static struct wcd9xxx_pdata apq8064_tabla20_platform_data = {
+	.slimbus_slave_device = {
+		.name = "tabla-slave",
+		.e_addr = {0, 0, 0x60, 0, 0x17, 2},
+	},
+	.irq = MSM_GPIO_TO_INT(42),
+	.irq_base = TABLA_INTERRUPT_BASE,
+	.num_irqs = NR_WCD9XXX_IRQS,
+	.reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
+	.micbias = {
+		.ldoh_v = TABLA_LDOH_2P85_V,
+		.cfilt1_mv = 1800,
+		.cfilt2_mv = 1800,
+		.cfilt3_mv = 1800,
+		.bias1_cfilt_sel = TABLA_CFILT1_SEL,
+		.bias2_cfilt_sel = TABLA_CFILT2_SEL,
+		.bias3_cfilt_sel = TABLA_CFILT3_SEL,
+		.bias4_cfilt_sel = TABLA_CFILT3_SEL,
+	},
+	.regulator = {
+	{
+		.name = "CDC_VDD_CP",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_RX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_RX_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_TX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_TX_CUR_MAX,
+	},
+	{
+		.name = "VDDIO_CDC",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_VDDIO_CDC_CUR_MAX,
+	},
+	{
+		.name = "VDDD_CDC_D",
+		.min_uV = 1225000,
+		.max_uV = 1225000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_A_1P2V",
+		.min_uV = 1225000,
+		.max_uV = 1225000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
+	},
+	},
+};
+
+static struct slim_device apq8064_slim_tabla20 = {
+	.name = "tabla2x-slim",
+	.e_addr = {0, 1, 0x60, 0, 0x17, 2},
+	.dev = {
+		.platform_data = &apq8064_tabla20_platform_data,
+	},
+};
+
+/* enable the level shifter for cs8427 to make sure the I2C
+ * clock is running at 100KHz and voltage levels are at 3.3
+ * and 5 volts
+ */
+static int enable_100KHz_ls(int enable)
+{
+	int ret = 0;
+	if (enable) {
+		ret = gpio_request(SX150X_GPIO(1, 10),
+					"cs8427_100KHZ_ENABLE");
+		if (ret) {
+			pr_err("%s: Failed to request gpio %d\n", __func__,
+				SX150X_GPIO(1, 10));
+			return ret;
+		}
+		gpio_direction_output(SX150X_GPIO(1, 10), 1);
+	} else
+		gpio_free(SX150X_GPIO(1, 10));
+	return ret;
+}
+
+static struct cs8427_platform_data cs8427_i2c_platform_data = {
+	.irq = SX150X_GPIO(1, 4),
+	.reset_gpio = SX150X_GPIO(1, 6),
+	.enable = enable_100KHz_ls,
+};
+
+static struct i2c_board_info cs8427_device_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("cs8427", CS8427_ADDR4),
+		.platform_data = &cs8427_i2c_platform_data,
+	},
+};
+
+#define HAP_SHIFT_LVL_OE_GPIO		PM8921_MPP_PM_TO_SYS(8)
+#define ISA1200_HAP_EN_GPIO		PM8921_GPIO_PM_TO_SYS(33)
+#define ISA1200_HAP_LEN_GPIO		PM8921_GPIO_PM_TO_SYS(20)
+#define ISA1200_HAP_CLK			PM8921_GPIO_PM_TO_SYS(44)
+
+static int isa1200_clk_enable(bool on)
+{
+	int rc = 0;
+
+	gpio_set_value_cansleep(ISA1200_HAP_CLK, on);
+
+	if (on) {
+		rc = pm8xxx_aux_clk_control(CLK_MP3_2, XO_DIV_1, true);
+		if (rc) {
+			pr_err("%s: unable to write aux clock register(%d)\n",
+				__func__, rc);
+			goto err_gpio_dis;
+		}
+	} else {
+		rc = pm8xxx_aux_clk_control(CLK_MP3_2, XO_DIV_NONE, true);
+		if (rc)
+			pr_err("%s: unable to write aux clock register(%d)\n",
+				__func__, rc);
+	}
+
+	return rc;
+
+err_gpio_dis:
+	gpio_set_value_cansleep(ISA1200_HAP_CLK, !on);
+	return rc;
+}
+
+static int isa1200_dev_setup(bool enable)
+{
+	int rc = 0;
+
+	if (!enable)
+		goto free_gpio;
+
+	rc = gpio_request(ISA1200_HAP_CLK, "haptics_clk");
+	if (rc) {
+		pr_err("%s: unable to request gpio %d config(%d)\n",
+			__func__, ISA1200_HAP_CLK, rc);
+		return rc;
+	}
+
+	rc = gpio_direction_output(ISA1200_HAP_CLK, 0);
+	if (rc) {
+		pr_err("%s: unable to set direction\n", __func__);
+		goto free_gpio;
+	}
+
+	return 0;
+
+free_gpio:
+	gpio_free(ISA1200_HAP_CLK);
+	return rc;
+}
+
+static struct isa1200_regulator isa1200_reg_data[] = {
+	{
+		.name = "vddp",
+		.min_uV = ISA_I2C_VTG_MIN_UV,
+		.max_uV = ISA_I2C_VTG_MAX_UV,
+		.load_uA = ISA_I2C_CURR_UA,
+	},
+};
+
+static struct isa1200_platform_data isa1200_1_pdata = {
+	.name = "vibrator",
+	.dev_setup = isa1200_dev_setup,
+	.clk_enable = isa1200_clk_enable,
+	.hap_en_gpio = ISA1200_HAP_EN_GPIO,
+	.hap_len_gpio = ISA1200_HAP_LEN_GPIO,
+	.max_timeout = 15000,
+	.mode_ctrl = PWM_GEN_MODE,
+	.pwm_fd = {
+		.pwm_div = 256,
+	},
+	.is_erm = false,
+	.smart_en = true,
+	.ext_clk_en = true,
+	.chip_en = 1,
+	.regulator_info = isa1200_reg_data,
+	.num_regulators = ARRAY_SIZE(isa1200_reg_data),
+};
+
+static struct i2c_board_info isa1200_board_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("isa1200_1", 0x90>>1),
+		.platform_data = &isa1200_1_pdata,
+	},
+};
+/* 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 */
+	14, 2, 0, 24, 5, 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, 10, 50,
+	/* T8 Object */
+	25, 0, 20, 20, 0, 0, 0, 0, 0, 0,
+	/* T9 Object */
+	139, 0, 0, 26, 42, 0, 32, 80, 2, 5,
+	0, 5, 5, 0, 10, 30, 10, 10, 255, 2,
+	85, 5, 0, 5, 9, 5, 12, 35, 70, 40,
+	20, 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 */
+	1, 0, 60, 115, 156, 99,
+	/* T27 Object */
+	0, 0, 0, 0, 0, 0, 0,
+	/* T40 Object */
+	0, 0, 0, 0, 0,
+	/* T42 Object */
+	0, 0, 255, 0, 255, 0, 0, 0, 0, 0,
+	/* T43 Object */
+	0, 0, 0, 0, 0, 0, 0, 64, 0, 8,
+	16,
+	/* T46 Object */
+	68, 0, 16, 16, 0, 0, 0, 0, 0,
+	/* T47 Object */
+	0, 0, 0, 0, 0, 0, 3, 64, 66, 0,
+	/* T48 Object */
+	1, 64, 64, 0, 0, 0, 0, 0, 0, 0,
+	32, 40, 0, 10, 10, 0, 0, 100, 10, 90,
+	0, 0, 0, 0, 0, 0, 0, 10, 1, 10,
+	52, 10, 12, 0, 33, 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,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0,
+};
+
+#define MXT_TS_GPIO_IRQ			6
+#define MXT_TS_PWR_EN_GPIO		PM8921_GPIO_PM_TO_SYS(23)
+#define MXT_TS_RESET_GPIO		33
+
+static struct mxt_config_info mxt_config_array[] = {
+	{
+		.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,
+		.bootldr_id	= MXT_BOOTLOADER_ID_1386E,
+		.fw_name	= "atmel_8064_liquid_v2_2_AA.hex",
+	},
+	{
+		/* The config data for V2.2.AA is the same as for V2.1.AA */
+		.config		= mxt1386e_config_data_v2_1,
+		.config_length	= ARRAY_SIZE(mxt1386e_config_data_v2_1),
+		.family_id	= 0xA0,
+		.variant_id	= 0x7,
+		.version	= 0x22,
+		.build		= 0xAA,
+		.bootldr_id	= MXT_BOOTLOADER_ID_1386E,
+	},
+};
+
+static struct mxt_platform_data mxt_platform_data = {
+	.config_array		= mxt_config_array,
+	.config_array_size	= ARRAY_SIZE(mxt_config_array),
+	.panel_minx		= 0,
+	.panel_maxx		= 1365,
+	.panel_miny		= 0,
+	.panel_maxy		= 767,
+	.disp_minx		= 0,
+	.disp_maxx		= 1365,
+	.disp_miny		= 0,
+	.disp_maxy		= 767,
+	.irqflags		= IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+	.i2c_pull_up		= true,
+	.reset_gpio		= MXT_TS_RESET_GPIO,
+	.irq_gpio		= MXT_TS_GPIO_IRQ,
+};
+
+static struct i2c_board_info mxt_device_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("atmel_mxt_ts", 0x5b),
+		.platform_data = &mxt_platform_data,
+		.irq = MSM_GPIO_TO_INT(MXT_TS_GPIO_IRQ),
+	},
+};
+#define CYTTSP_TS_GPIO_IRQ		6
+#define CYTTSP_TS_GPIO_SLEEP		33
+
+static ssize_t tma340_vkeys_show(struct kobject *kobj,
+			struct kobj_attribute *attr, char *buf)
+{
+	return snprintf(buf, 200,
+	__stringify(EV_KEY) ":" __stringify(KEY_BACK) ":73:1120:97:97"
+	":" __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":230:1120:97:97"
+	":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":389:1120:97:97"
+	":" __stringify(EV_KEY) ":" __stringify(KEY_SEARCH) ":544:1120:97:97"
+	"\n");
+}
+
+static struct kobj_attribute tma340_vkeys_attr = {
+	.attr = {
+		.mode = S_IRUGO,
+	},
+	.show = &tma340_vkeys_show,
+};
+
+static struct attribute *tma340_properties_attrs[] = {
+	&tma340_vkeys_attr.attr,
+	NULL
+};
+
+static struct attribute_group tma340_properties_attr_group = {
+	.attrs = tma340_properties_attrs,
+};
+
+static int cyttsp_platform_init(struct i2c_client *client)
+{
+	int rc = 0;
+	static struct kobject *tma340_properties_kobj;
+
+	tma340_vkeys_attr.attr.name = "virtualkeys.cyttsp-i2c";
+	tma340_properties_kobj = kobject_create_and_add("board_properties",
+								NULL);
+	if (tma340_properties_kobj)
+		rc = sysfs_create_group(tma340_properties_kobj,
+					&tma340_properties_attr_group);
+	if (!tma340_properties_kobj || rc)
+		pr_err("%s: failed to create board_properties\n",
+				__func__);
+
+	return 0;
+}
+
+static struct cyttsp_regulator cyttsp_regulator_data[] = {
+	{
+		.name = "vdd",
+		.min_uV = CY_TMA300_VTG_MIN_UV,
+		.max_uV = CY_TMA300_VTG_MAX_UV,
+		.hpm_load_uA = CY_TMA300_CURR_24HZ_UA,
+		.lpm_load_uA = CY_TMA300_CURR_24HZ_UA,
+	},
+	{
+		.name = "vcc_i2c",
+		.min_uV = CY_I2C_VTG_MIN_UV,
+		.max_uV = CY_I2C_VTG_MAX_UV,
+		.hpm_load_uA = CY_I2C_CURR_UA,
+		.lpm_load_uA = CY_I2C_CURR_UA,
+	},
+};
+
+static struct cyttsp_platform_data cyttsp_pdata = {
+	.panel_maxx = 634,
+	.panel_maxy = 1166,
+	.disp_maxx = 599,
+	.disp_maxy = 1023,
+	.disp_minx = 0,
+	.disp_miny = 0,
+	.flags = 0x01,
+	.gen = CY_GEN3,
+	.use_st = CY_USE_ST,
+	.use_mt = CY_USE_MT,
+	.use_hndshk = CY_SEND_HNDSHK,
+	.use_trk_id = CY_USE_TRACKING_ID,
+	.use_sleep = CY_USE_DEEP_SLEEP_SEL,
+	.use_gestures = CY_USE_GESTURES,
+	.fw_fname = "cyttsp_8064_mtp.hex",
+	/* change act_intrvl to customize the Active power state
+	 * scanning/processing refresh interval for Operating mode
+	 */
+	.act_intrvl = CY_ACT_INTRVL_DFLT,
+	/* change tch_tmout to customize the touch timeout for the
+	 * Active power state for Operating mode
+	 */
+	.tch_tmout = CY_TCH_TMOUT_DFLT,
+	/* change lp_intrvl to customize the Low Power power state
+	 * scanning/processing refresh interval for Operating mode
+	 */
+	.lp_intrvl = CY_LP_INTRVL_DFLT,
+	.sleep_gpio = CYTTSP_TS_GPIO_SLEEP,
+	.resout_gpio = -1,
+	.irq_gpio = CYTTSP_TS_GPIO_IRQ,
+	.regulator_info = cyttsp_regulator_data,
+	.num_regulators = ARRAY_SIZE(cyttsp_regulator_data),
+	.init = cyttsp_platform_init,
+	.correct_fw_ver = 17,
+};
+
+static struct i2c_board_info cyttsp_info[] __initdata = {
+	{
+		I2C_BOARD_INFO(CY_I2C_NAME, 0x24),
+		.platform_data = &cyttsp_pdata,
+		.irq = MSM_GPIO_TO_INT(CYTTSP_TS_GPIO_IRQ),
+	},
+};
+
+#define MSM_WCNSS_PHYS	0x03000000
+#define MSM_WCNSS_SIZE	0x280000
+
+static struct resource resources_wcnss_wlan[] = {
+	{
+		.start	= RIVA_APPS_WLAN_RX_DATA_AVAIL_IRQ,
+		.end	= RIVA_APPS_WLAN_RX_DATA_AVAIL_IRQ,
+		.name	= "wcnss_wlanrx_irq",
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= RIVA_APPS_WLAN_DATA_XFER_DONE_IRQ,
+		.end	= RIVA_APPS_WLAN_DATA_XFER_DONE_IRQ,
+		.name	= "wcnss_wlantx_irq",
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM_WCNSS_PHYS,
+		.end	= MSM_WCNSS_PHYS + MSM_WCNSS_SIZE - 1,
+		.name	= "wcnss_mmio",
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= 64,
+		.end	= 68,
+		.name	= "wcnss_gpios_5wire",
+		.flags	= IORESOURCE_IO,
+	},
+};
+
+static struct qcom_wcnss_opts qcom_wcnss_pdata = {
+	.has_48mhz_xo	= 1,
+};
+
+static struct platform_device msm_device_wcnss_wlan = {
+	.name		= "wcnss_wlan",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(resources_wcnss_wlan),
+	.resource	= resources_wcnss_wlan,
+	.dev		= {.platform_data = &qcom_wcnss_pdata},
+};
+
+static struct platform_device msm_device_iris_fm __devinitdata = {
+	.name = "iris_fm",
+	.id   = -1,
+};
+
+#ifdef CONFIG_QSEECOM
+/* qseecom bus scaling */
+static struct msm_bus_vectors qseecom_clks_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ib = 0,
+		.ab = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_SPDM,
+		.dst = MSM_BUS_SLAVE_SPDM,
+		.ib = 0,
+		.ab = 0,
+	},
+};
+
+static struct msm_bus_vectors qseecom_enable_dfab_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ib = (492 * 8) * 1000000UL,
+		.ab = (492 * 8) *  100000UL,
+	},
+	{
+		.src = MSM_BUS_MASTER_SPDM,
+		.dst = MSM_BUS_SLAVE_SPDM,
+		.ib = 0,
+		.ab = 0,
+	},
+};
+
+static struct msm_bus_vectors qseecom_enable_sfpb_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ib = 0,
+		.ab = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_SPDM,
+		.dst = MSM_BUS_SLAVE_SPDM,
+		.ib = (64 * 8) * 1000000UL,
+		.ab = (64 * 8) *  100000UL,
+	},
+};
+
+static struct msm_bus_paths qseecom_hw_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(qseecom_clks_init_vectors),
+		qseecom_clks_init_vectors,
+	},
+	{
+		ARRAY_SIZE(qseecom_enable_dfab_vectors),
+		qseecom_enable_sfpb_vectors,
+	},
+	{
+		ARRAY_SIZE(qseecom_enable_sfpb_vectors),
+		qseecom_enable_sfpb_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata qseecom_bus_pdata = {
+	qseecom_hw_bus_scale_usecases,
+	ARRAY_SIZE(qseecom_hw_bus_scale_usecases),
+	.name = "qsee",
+};
+
+static struct platform_device qseecom_device = {
+	.name		= "qseecom",
+	.id		= 0,
+	.dev		= {
+		.platform_data = &qseecom_bus_pdata,
+	},
+};
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+
+#define QCE_SIZE		0x10000
+#define QCE_0_BASE		0x11000000
+
+#define QCE_HW_KEY_SUPPORT	0
+#define QCE_SHA_HMAC_SUPPORT	1
+#define QCE_SHARE_CE_RESOURCE	3
+#define QCE_CE_SHARED		0
+
+static struct resource qcrypto_resources[] = {
+	[0] = {
+		.start = QCE_0_BASE,
+		.end = QCE_0_BASE + QCE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.name = "crypto_channels",
+		.start = DMOV8064_CE_IN_CHAN,
+		.end = DMOV8064_CE_OUT_CHAN,
+		.flags = IORESOURCE_DMA,
+	},
+	[2] = {
+		.name = "crypto_crci_in",
+		.start = DMOV8064_CE_IN_CRCI,
+		.end = DMOV8064_CE_IN_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+	[3] = {
+		.name = "crypto_crci_out",
+		.start = DMOV8064_CE_OUT_CRCI,
+		.end = DMOV8064_CE_OUT_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static struct resource qcedev_resources[] = {
+	[0] = {
+		.start = QCE_0_BASE,
+		.end = QCE_0_BASE + QCE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.name = "crypto_channels",
+		.start = DMOV8064_CE_IN_CHAN,
+		.end = DMOV8064_CE_OUT_CHAN,
+		.flags = IORESOURCE_DMA,
+	},
+	[2] = {
+		.name = "crypto_crci_in",
+		.start = DMOV8064_CE_IN_CRCI,
+		.end = DMOV8064_CE_IN_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+	[3] = {
+		.name = "crypto_crci_out",
+		.start = DMOV8064_CE_OUT_CRCI,
+		.end = DMOV8064_CE_OUT_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
+
+static struct msm_ce_hw_support qcrypto_ce_hw_suppport = {
+	.ce_shared = QCE_CE_SHARED,
+	.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
+	.hw_key_support = QCE_HW_KEY_SUPPORT,
+	.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+	.bus_scale_table = NULL,
+};
+
+static struct platform_device qcrypto_device = {
+	.name		= "qcrypto",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(qcrypto_resources),
+	.resource	= qcrypto_resources,
+	.dev		= {
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+		.platform_data = &qcrypto_ce_hw_suppport,
+	},
+};
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+
+static struct msm_ce_hw_support qcedev_ce_hw_suppport = {
+	.ce_shared = QCE_CE_SHARED,
+	.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
+	.hw_key_support = QCE_HW_KEY_SUPPORT,
+	.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+	.bus_scale_table = NULL,
+};
+
+static struct platform_device qcedev_device = {
+	.name		= "qce",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(qcedev_resources),
+	.resource	= qcedev_resources,
+	.dev		= {
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+		.platform_data = &qcedev_ce_hw_suppport,
+	},
+};
+#endif
+
+static struct mdm_platform_data mdm_platform_data = {
+	.mdm_version = "3.0",
+	.ramdump_delay_ms = 2000,
+	.early_power_on = 1,
+	.sfr_query = 1,
+	.peripheral_platform_device = &apq8064_device_hsic_host,
+};
+
+static struct tsens_platform_data apq_tsens_pdata  = {
+		.tsens_factor		= 1000,
+		.hw_type		= APQ_8064,
+		.tsens_num_sensor	= 11,
+		.slope = {1176, 1176, 1154, 1176, 1111,
+			1132, 1132, 1199, 1132, 1199, 1132},
+};
+
+static struct platform_device msm_tsens_device = {
+	.name   = "tsens8960-tm",
+	.id = -1,
+};
+
+#define MSM_SHARED_RAM_PHYS 0x80000000
+static void __init apq8064_map_io(void)
+{
+	msm_shared_ram_phys = MSM_SHARED_RAM_PHYS;
+	msm_map_apq8064_io();
+	if (socinfo_init() < 0)
+		pr_err("socinfo_init() failed!\n");
+}
+
+static void __init apq8064_init_irq(void)
+{
+	struct msm_mpm_device_data *data = NULL;
+
+#ifdef CONFIG_MSM_MPM
+	data = &apq8064_mpm_dev_data;
+#endif
+
+	msm_mpm_irq_extn_init(data);
+	gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE,
+						(void *)MSM_QGIC_CPU_BASE);
+}
+
+static struct platform_device msm8064_device_saw_regulator_core0 = {
+	.name	= "saw-regulator",
+	.id	= 0,
+	.dev	= {
+		.platform_data = &msm8064_saw_regulator_pdata_8921_s5,
+	},
+};
+
+static struct platform_device msm8064_device_saw_regulator_core1 = {
+	.name	= "saw-regulator",
+	.id	= 1,
+	.dev	= {
+		.platform_data = &msm8064_saw_regulator_pdata_8921_s6,
+	},
+};
+
+static struct platform_device msm8064_device_saw_regulator_core2 = {
+	.name	= "saw-regulator",
+	.id	= 2,
+	.dev	= {
+		.platform_data = &msm8064_saw_regulator_pdata_8821_s0,
+	},
+};
+
+static struct platform_device msm8064_device_saw_regulator_core3 = {
+	.name	= "saw-regulator",
+	.id	= 3,
+	.dev	= {
+		.platform_data = &msm8064_saw_regulator_pdata_8821_s1,
+
+	},
+};
+
+static struct msm_rpmrs_level msm_rpmrs_levels[] = {
+	{
+		MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT,
+		MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
+		true,
+		1, 784, 180000, 100,
+	},
+
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
+		MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
+		true,
+		1300, 228, 1200000, 2000,
+	},
+
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+		MSM_RPMRS_LIMITS(ON, GDHS, MAX, ACTIVE),
+		false,
+		2000, 138, 1208400, 3200,
+	},
+
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+		MSM_RPMRS_LIMITS(ON, HSFS_OPEN, ACTIVE, RET_HIGH),
+		false,
+		6000, 119, 1850300, 9000,
+	},
+
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+		MSM_RPMRS_LIMITS(OFF, GDHS, MAX, ACTIVE),
+		false,
+		9200, 68, 2839200, 16400,
+	},
+
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, MAX, ACTIVE),
+		false,
+		10300, 63, 3128000, 18200,
+	},
+
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, ACTIVE, RET_HIGH),
+		false,
+		18000, 10, 4602600, 27000,
+	},
+
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, RET_HIGH, RET_LOW),
+		false,
+		20000, 2, 5752000, 32000,
+	},
+};
+
+static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_TZ,
+};
+
+static struct msm_rpmrs_platform_data msm_rpmrs_data __initdata = {
+	.levels = &msm_rpmrs_levels[0],
+	.num_levels = ARRAY_SIZE(msm_rpmrs_levels),
+	.vdd_mem_levels  = {
+		[MSM_RPMRS_VDD_MEM_RET_LOW]	= 750000,
+		[MSM_RPMRS_VDD_MEM_RET_HIGH]	= 750000,
+		[MSM_RPMRS_VDD_MEM_ACTIVE]	= 1050000,
+		[MSM_RPMRS_VDD_MEM_MAX]		= 1150000,
+	},
+	.vdd_dig_levels = {
+		[MSM_RPMRS_VDD_DIG_RET_LOW]	= 500000,
+		[MSM_RPMRS_VDD_DIG_RET_HIGH]	= 750000,
+		[MSM_RPMRS_VDD_DIG_ACTIVE]	= 950000,
+		[MSM_RPMRS_VDD_DIG_MAX]		= 1150000,
+	},
+	.vdd_mask = 0x7FFFFF,
+	.rpmrs_target_id = {
+		[MSM_RPMRS_ID_PXO_CLK]		= MSM_RPM_ID_PXO_CLK,
+		[MSM_RPMRS_ID_L2_CACHE_CTL]	= MSM_RPM_ID_LAST,
+		[MSM_RPMRS_ID_VDD_DIG_0]	= MSM_RPM_ID_PM8921_S3_0,
+		[MSM_RPMRS_ID_VDD_DIG_1]	= MSM_RPM_ID_PM8921_S3_1,
+		[MSM_RPMRS_ID_VDD_MEM_0]	= MSM_RPM_ID_PM8921_L24_0,
+		[MSM_RPMRS_ID_VDD_MEM_1]	= MSM_RPM_ID_PM8921_L24_1,
+		[MSM_RPMRS_ID_RPM_CTL]		= MSM_RPM_ID_RPM_CTL,
+	},
+};
+
+static uint8_t spm_wfi_cmd_sequence[] __initdata = {
+	0x03, 0x0f,
+};
+
+static uint8_t spm_power_collapse_without_rpm[] __initdata = {
+	0x00, 0x24, 0x54, 0x10,
+	0x09, 0x03, 0x01,
+	0x10, 0x54, 0x30, 0x0C,
+	0x24, 0x30, 0x0f,
+};
+
+static uint8_t spm_power_collapse_with_rpm[] __initdata = {
+	0x00, 0x24, 0x54, 0x10,
+	0x09, 0x07, 0x01, 0x0B,
+	0x10, 0x54, 0x30, 0x0C,
+	0x24, 0x30, 0x0f,
+};
+
+static struct msm_spm_seq_entry msm_spm_seq_list[] __initdata = {
+	[0] = {
+		.mode = MSM_SPM_MODE_CLOCK_GATING,
+		.notify_rpm = false,
+		.cmd = spm_wfi_cmd_sequence,
+	},
+	[1] = {
+		.mode = MSM_SPM_MODE_POWER_COLLAPSE,
+		.notify_rpm = false,
+		.cmd = spm_power_collapse_without_rpm,
+	},
+	[2] = {
+		.mode = MSM_SPM_MODE_POWER_COLLAPSE,
+		.notify_rpm = true,
+		.cmd = spm_power_collapse_with_rpm,
+	},
+};
+
+static uint8_t l2_spm_wfi_cmd_sequence[] __initdata = {
+	0x00, 0x20, 0x03, 0x20,
+	0x00, 0x0f,
+};
+
+static uint8_t l2_spm_gdhs_cmd_sequence[] __initdata = {
+	0x00, 0x20, 0x34, 0x64,
+	0x48, 0x07, 0x48, 0x20,
+	0x50, 0x64, 0x04, 0x34,
+	0x50, 0x0f,
+};
+static uint8_t l2_spm_power_off_cmd_sequence[] __initdata = {
+	0x00, 0x10, 0x34, 0x64,
+	0x48, 0x07, 0x48, 0x10,
+	0x50, 0x64, 0x04, 0x34,
+	0x50, 0x0F,
+};
+
+static struct msm_spm_seq_entry msm_spm_l2_seq_list[] __initdata = {
+	[0] = {
+		.mode = MSM_SPM_L2_MODE_RETENTION,
+		.notify_rpm = false,
+		.cmd = l2_spm_wfi_cmd_sequence,
+	},
+	[1] = {
+		.mode = MSM_SPM_L2_MODE_GDHS,
+		.notify_rpm = true,
+		.cmd = l2_spm_gdhs_cmd_sequence,
+	},
+	[2] = {
+		.mode = MSM_SPM_L2_MODE_POWER_COLLAPSE,
+		.notify_rpm = true,
+		.cmd = l2_spm_power_off_cmd_sequence,
+	},
+};
+
+
+static struct msm_spm_platform_data msm_spm_l2_data[] __initdata = {
+	[0] = {
+		.reg_base_addr = MSM_SAW_L2_BASE,
+		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x00,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x00A000AE,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x00A00020,
+		.modes = msm_spm_l2_seq_list,
+		.num_modes = ARRAY_SIZE(msm_spm_l2_seq_list),
+	},
+};
+
+static struct msm_spm_platform_data msm_spm_data[] __initdata = {
+	[0] = {
+		.reg_base_addr = MSM_SAW0_BASE,
+		.reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F,
+#if defined(CONFIG_MSM_AVS_HW)
+		.reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x00,
+		.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
+#endif
+		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
+		.vctl_timeout_us = 50,
+		.num_modes = ARRAY_SIZE(msm_spm_seq_list),
+		.modes = msm_spm_seq_list,
+	},
+	[1] = {
+		.reg_base_addr = MSM_SAW1_BASE,
+		.reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F,
+#if defined(CONFIG_MSM_AVS_HW)
+		.reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x00,
+		.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
+#endif
+		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
+		.vctl_timeout_us = 50,
+		.num_modes = ARRAY_SIZE(msm_spm_seq_list),
+		.modes = msm_spm_seq_list,
+	},
+	[2] = {
+		.reg_base_addr = MSM_SAW2_BASE,
+		.reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F,
+#if defined(CONFIG_MSM_AVS_HW)
+		.reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x00,
+		.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
+#endif
+		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
+		.vctl_timeout_us = 50,
+		.num_modes = ARRAY_SIZE(msm_spm_seq_list),
+		.modes = msm_spm_seq_list,
+	},
+	[3] = {
+		.reg_base_addr = MSM_SAW3_BASE,
+		.reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F,
+#if defined(CONFIG_MSM_AVS_HW)
+		.reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x00,
+		.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
+#endif
+		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
+		.vctl_timeout_us = 50,
+		.num_modes = ARRAY_SIZE(msm_spm_seq_list),
+		.modes = msm_spm_seq_list,
+	},
+};
+
+static struct msm_pm_sleep_status_data msm_pm_slp_sts_data = {
+	.base_addr = MSM_ACC0_BASE + 0x08,
+	.cpu_offset = MSM_ACC1_BASE - MSM_ACC0_BASE,
+	.mask = 1UL << 13,
+};
+
+static void __init apq8064_init_buses(void)
+{
+	msm_bus_rpm_set_mt_mask();
+	msm_bus_8064_apps_fabric_pdata.rpm_enabled = 1;
+	msm_bus_8064_sys_fabric_pdata.rpm_enabled = 1;
+	msm_bus_8064_mm_fabric_pdata.rpm_enabled = 1;
+	msm_bus_8064_apps_fabric.dev.platform_data =
+		&msm_bus_8064_apps_fabric_pdata;
+	msm_bus_8064_sys_fabric.dev.platform_data =
+		&msm_bus_8064_sys_fabric_pdata;
+	msm_bus_8064_mm_fabric.dev.platform_data =
+		&msm_bus_8064_mm_fabric_pdata;
+	msm_bus_8064_sys_fpb.dev.platform_data = &msm_bus_8064_sys_fpb_pdata;
+	msm_bus_8064_cpss_fpb.dev.platform_data = &msm_bus_8064_cpss_fpb_pdata;
+}
+
+/* PCIe gpios */
+static struct msm_pcie_gpio_info_t msm_pcie_gpio_info[MSM_PCIE_MAX_GPIO] = {
+	{"rst_n", PM8921_MPP_PM_TO_SYS(PCIE_RST_N_PMIC_MPP), 0},
+	{"pwr_en", PM8921_GPIO_PM_TO_SYS(PCIE_PWR_EN_PMIC_GPIO), 1},
+};
+
+static struct msm_pcie_platform msm_pcie_platform_data = {
+	.gpio = msm_pcie_gpio_info,
+};
+
+static void __init mpq8064_pcie_init(void)
+{
+	msm_device_pcie.dev.platform_data = &msm_pcie_platform_data;
+	platform_device_register(&msm_device_pcie);
+}
+
+static struct platform_device apq8064_device_ext_5v_vreg __devinitdata = {
+	.name	= GPIO_REGULATOR_DEV_NAME,
+	.id	= PM8921_MPP_PM_TO_SYS(7),
+	.dev	= {
+		.platform_data
+			= &apq8064_gpio_regulator_pdata[GPIO_VREG_ID_EXT_5V],
+	},
+};
+
+static struct platform_device apq8064_device_ext_mpp8_vreg __devinitdata = {
+	.name	= GPIO_REGULATOR_DEV_NAME,
+	.id	= PM8921_MPP_PM_TO_SYS(8),
+	.dev	= {
+		.platform_data
+			= &apq8064_gpio_regulator_pdata[GPIO_VREG_ID_EXT_MPP8],
+	},
+};
+
+static struct platform_device apq8064_device_ext_3p3v_vreg __devinitdata = {
+	.name	= GPIO_REGULATOR_DEV_NAME,
+	.id	= APQ8064_EXT_3P3V_REG_EN_GPIO,
+	.dev	= {
+		.platform_data =
+			&apq8064_gpio_regulator_pdata[GPIO_VREG_ID_EXT_3P3V],
+	},
+};
+
+static struct platform_device apq8064_device_ext_ts_sw_vreg __devinitdata = {
+	.name	= GPIO_REGULATOR_DEV_NAME,
+	.id	= PM8921_GPIO_PM_TO_SYS(23),
+	.dev	= {
+		.platform_data
+			= &apq8064_gpio_regulator_pdata[GPIO_VREG_ID_EXT_TS_SW],
+	},
+};
+
+static struct platform_device apq8064_device_rpm_regulator __devinitdata = {
+	.name	= "rpm-regulator",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &apq8064_rpm_regulator_pdata,
+	},
+};
+
+static struct gpio_ir_recv_platform_data gpio_ir_recv_pdata = {
+	.gpio_nr = 88,
+	.active_low = 1,
+};
+
+static struct platform_device gpio_ir_recv_pdev = {
+	.name = "gpio-rc-recv",
+	.dev = {
+		.platform_data = &gpio_ir_recv_pdata,
+	},
+};
+
+static struct platform_device *common_not_mpq_devices[] __initdata = {
+	&apq8064_device_qup_i2c_gsbi1,
+	&apq8064_device_qup_i2c_gsbi3,
+	&apq8064_device_qup_i2c_gsbi4,
+};
+
+static struct platform_device *common_devices[] __initdata = {
+	&apq8064_device_dmov,
+	&apq8064_device_qup_spi_gsbi5,
+	&apq8064_device_ext_5v_vreg,
+	&apq8064_device_ext_mpp8_vreg,
+	&apq8064_device_ext_3p3v_vreg,
+	&apq8064_device_ssbi_pmic1,
+	&apq8064_device_ssbi_pmic2,
+	&apq8064_device_ext_ts_sw_vreg,
+	&msm_device_smd_apq8064,
+	&apq8064_device_otg,
+	&apq8064_device_gadget_peripheral,
+	&apq8064_device_hsusb_host,
+	&android_usb_device,
+	&msm_device_wcnss_wlan,
+	&msm_device_iris_fm,
+	&apq8064_fmem_device,
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+	&apq8064_android_pmem_device,
+	&apq8064_android_pmem_adsp_device,
+	&apq8064_android_pmem_audio_device,
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
+#ifdef CONFIG_ION_MSM
+	&apq8064_ion_dev,
+#endif
+	&msm8064_device_watchdog,
+	&msm8064_device_saw_regulator_core0,
+	&msm8064_device_saw_regulator_core1,
+	&msm8064_device_saw_regulator_core2,
+	&msm8064_device_saw_regulator_core3,
+#if defined(CONFIG_QSEECOM)
+	&qseecom_device,
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
+	&qcrypto_device,
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+	&qcedev_device,
+#endif
+
+#ifdef CONFIG_HW_RANDOM_MSM
+	&apq8064_device_rng,
+#endif
+	&apq_pcm,
+	&apq_pcm_routing,
+	&apq_cpudai0,
+	&apq_cpudai1,
+	&mpq_cpudai_sec_i2s_rx,
+	&mpq_cpudai_mi2s_tx,
+	&apq_cpudai_hdmi_rx,
+	&apq_cpudai_bt_rx,
+	&apq_cpudai_bt_tx,
+	&apq_cpudai_fm_rx,
+	&apq_cpudai_fm_tx,
+	&apq_cpu_fe,
+	&apq_stub_codec,
+	&apq_voice,
+	&apq_voip,
+	&apq_lpa_pcm,
+	&apq_compr_dsp,
+	&apq_multi_ch_pcm,
+	&apq_pcm_hostless,
+	&apq_cpudai_afe_01_rx,
+	&apq_cpudai_afe_01_tx,
+	&apq_cpudai_afe_02_rx,
+	&apq_cpudai_afe_02_tx,
+	&apq_pcm_afe,
+	&apq_cpudai_auxpcm_rx,
+	&apq_cpudai_auxpcm_tx,
+	&apq_cpudai_stub,
+	&apq_cpudai_slimbus_1_rx,
+	&apq_cpudai_slimbus_1_tx,
+	&apq_cpudai_slimbus_2_tx,
+	&apq_cpudai_slimbus_3_rx,
+	&apq8064_rpm_device,
+	&apq8064_rpm_log_device,
+	&apq8064_rpm_stat_device,
+	&msm_bus_8064_apps_fabric,
+	&msm_bus_8064_sys_fabric,
+	&msm_bus_8064_mm_fabric,
+	&msm_bus_8064_sys_fpb,
+	&msm_bus_8064_cpss_fpb,
+	&apq8064_msm_device_vidc,
+	&msm_pil_dsps,
+	&msm_8960_riva,
+	&msm_8960_q6_lpass,
+	&msm_pil_vidc,
+	&msm_gss,
+	&apq8064_rtb_device,
+	&apq8064_cpu_idle_device,
+	&apq8064_msm_gov_device,
+	&apq8064_device_cache_erp,
+	&epm_adc_device,
+	&apq8064_qdss_device,
+	&msm_etb_device,
+	&msm_tpiu_device,
+	&msm_funnel_device,
+	&apq8064_etm_device,
+	&apq_cpudai_slim_4_rx,
+	&apq_cpudai_slim_4_tx,
+#ifdef CONFIG_MSM_GEMINI
+	&msm8960_gemini_device,
+#endif
+	&apq8064_iommu_domain_device,
+	&msm_tsens_device,
+	&apq8064_cache_dump_device,
+};
+
+static struct platform_device *sim_devices[] __initdata = {
+	&apq8064_device_uart_gsbi3,
+	&msm_device_sps_apq8064,
+};
+
+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 = {
+	&apq8064_device_uart_gsbi1,
+	&apq8064_device_uart_gsbi7,
+	&msm_device_sps_apq8064,
+#ifdef CONFIG_MSM_ROTATOR
+	&msm_rotator_device,
+#endif
+};
+
+static struct platform_device
+mpq8064_device_ext_5v_frc_vreg __devinitdata = {
+	.name	= GPIO_REGULATOR_DEV_NAME,
+	.id	= SX150X_GPIO(4, 10),
+	.dev	= {
+		.platform_data =
+			&mpq8064_gpio_regulator_pdata[GPIO_VREG_ID_FRC_5V],
+	},
+};
+
+static struct platform_device
+mpq8064_device_ext_1p2_buck_vreg __devinitdata = {
+	.name	= GPIO_REGULATOR_DEV_NAME,
+	.id	= SX150X_GPIO(4, 2),
+	.dev	= {
+		.platform_data =
+		 &mpq8064_gpio_regulator_pdata[GPIO_VREG_ID_AVC_1P2V],
+	},
+};
+
+static struct platform_device
+mpq8064_device_ext_1p8_buck_vreg __devinitdata = {
+	.name	= GPIO_REGULATOR_DEV_NAME,
+	.id	= SX150X_GPIO(4, 4),
+	.dev	= {
+		.platform_data =
+		&mpq8064_gpio_regulator_pdata[GPIO_VREG_ID_AVC_1P8V],
+	},
+};
+
+static struct platform_device
+mpq8064_device_ext_2p2_buck_vreg __devinitdata = {
+	.name	= GPIO_REGULATOR_DEV_NAME,
+	.id	= SX150X_GPIO(4, 14),
+	.dev	= {
+		.platform_data =
+		&mpq8064_gpio_regulator_pdata[GPIO_VREG_ID_AVC_2P2V],
+	},
+};
+
+static struct platform_device
+mpq8064_device_ext_5v_buck_vreg __devinitdata = {
+	.name	= GPIO_REGULATOR_DEV_NAME,
+	.id	= SX150X_GPIO(4, 3),
+	.dev	= {
+		.platform_data =
+		 &mpq8064_gpio_regulator_pdata[GPIO_VREG_ID_AVC_5V],
+	},
+};
+
+static struct platform_device
+mpq8064_device_ext_3p3v_ldo_vreg __devinitdata = {
+	.name	= GPIO_REGULATOR_DEV_NAME,
+	.id	= SX150X_GPIO(4, 15),
+	.dev	= {
+		.platform_data =
+		&mpq8064_gpio_regulator_pdata[GPIO_VREG_ID_AVC_3P3V],
+	},
+};
+
+static struct platform_device rc_input_loopback_pdev = {
+	.name	= "rc-user-input",
+	.id	= -1,
+};
+
+static int rf4ce_gpio_init(void)
+{
+	if (!machine_is_mpq8064_cdp())
+		return -EINVAL;
+
+	/* CC2533 SRDY Input */
+	if (!gpio_request(SX150X_GPIO(4, 6), "rf4ce_srdy")) {
+		gpio_direction_input(SX150X_GPIO(4, 6));
+		gpio_export(SX150X_GPIO(4, 6), true);
+	}
+
+	/* CC2533 MRDY Output */
+	if (!gpio_request(SX150X_GPIO(4, 5), "rf4ce_mrdy")) {
+		gpio_direction_output(SX150X_GPIO(4, 5), 1);
+		gpio_export(SX150X_GPIO(4, 5), true);
+	}
+
+	/* CC2533 Reset Output */
+	if (!gpio_request(SX150X_GPIO(4, 7), "rf4ce_reset")) {
+		gpio_direction_output(SX150X_GPIO(4, 7), 0);
+		gpio_export(SX150X_GPIO(4, 7), true);
+	}
+
+	return 0;
+}
+late_initcall(rf4ce_gpio_init);
+
+static struct platform_device *mpq_devices[] __initdata = {
+	&msm_device_sps_apq8064,
+	&mpq8064_device_qup_i2c_gsbi5,
+#ifdef CONFIG_MSM_ROTATOR
+	&msm_rotator_device,
+#endif
+	&gpio_ir_recv_pdev,
+	&mpq8064_device_ext_5v_frc_vreg,
+	&mpq8064_device_ext_1p2_buck_vreg,
+	&mpq8064_device_ext_1p8_buck_vreg,
+	&mpq8064_device_ext_2p2_buck_vreg,
+	&mpq8064_device_ext_5v_buck_vreg,
+	&mpq8064_device_ext_3p3v_ldo_vreg,
+#ifdef CONFIG_MSM_VCAP
+	&msm8064_device_vcap,
+#endif
+	&rc_input_loopback_pdev,
+};
+
+static struct msm_spi_platform_data apq8064_qup_spi_gsbi5_pdata = {
+	.max_clock_speed = 1100000,
+};
+
+#define KS8851_IRQ_GPIO		43
+
+static struct spi_board_info spi_board_info[] __initdata = {
+	{
+		.modalias               = "ks8851",
+		.irq                    = MSM_GPIO_TO_INT(KS8851_IRQ_GPIO),
+		.max_speed_hz           = 19200000,
+		.bus_num                = 0,
+		.chip_select            = 2,
+		.mode                   = SPI_MODE_0,
+	},
+	{
+		.modalias		= "epm_adc",
+		.max_speed_hz		= 1100000,
+		.bus_num		= 0,
+		.chip_select		= 3,
+		.mode			= SPI_MODE_0,
+	},
+};
+
+static struct slim_boardinfo apq8064_slim_devices[] = {
+	{
+		.bus_num = 1,
+		.slim_slave = &apq8064_slim_tabla,
+	},
+	{
+		.bus_num = 1,
+		.slim_slave = &apq8064_slim_tabla20,
+	},
+	/* add more slimbus slaves as needed */
+};
+
+static struct msm_i2c_platform_data apq8064_i2c_qup_gsbi1_pdata = {
+	.clk_freq = 100000,
+	.src_clk_rate = 24000000,
+};
+
+static struct msm_i2c_platform_data apq8064_i2c_qup_gsbi3_pdata = {
+	.clk_freq = 384000,
+	.src_clk_rate = 24000000,
+};
+
+static struct msm_i2c_platform_data apq8064_i2c_qup_gsbi4_pdata = {
+	.clk_freq = 100000,
+	.src_clk_rate = 24000000,
+};
+
+static struct msm_i2c_platform_data mpq8064_i2c_qup_gsbi5_pdata = {
+	.clk_freq = 100000,
+	.src_clk_rate = 24000000,
+};
+
+#define GSBI_DUAL_MODE_CODE 0x60
+#define MSM_GSBI1_PHYS		0x12440000
+static void __init apq8064_i2c_init(void)
+{
+	void __iomem *gsbi_mem;
+
+	apq8064_device_qup_i2c_gsbi1.dev.platform_data =
+					&apq8064_i2c_qup_gsbi1_pdata;
+	gsbi_mem = ioremap_nocache(MSM_GSBI1_PHYS, 4);
+	writel_relaxed(GSBI_DUAL_MODE_CODE, gsbi_mem);
+	/* Ensure protocol code is written before proceeding */
+	wmb();
+	iounmap(gsbi_mem);
+	apq8064_i2c_qup_gsbi1_pdata.use_gsbi_shared_mode = 1;
+	apq8064_device_qup_i2c_gsbi3.dev.platform_data =
+					&apq8064_i2c_qup_gsbi3_pdata;
+	apq8064_device_qup_i2c_gsbi1.dev.platform_data =
+					&apq8064_i2c_qup_gsbi1_pdata;
+	apq8064_device_qup_i2c_gsbi4.dev.platform_data =
+					&apq8064_i2c_qup_gsbi4_pdata;
+	mpq8064_device_qup_i2c_gsbi5.dev.platform_data =
+					&mpq8064_i2c_qup_gsbi5_pdata;
+}
+
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+static int ethernet_init(void)
+{
+	int ret;
+	ret = gpio_request(KS8851_IRQ_GPIO, "ks8851_irq");
+	if (ret) {
+		pr_err("ks8851 gpio_request failed: %d\n", ret);
+		goto fail;
+	}
+
+	return 0;
+fail:
+	return ret;
+}
+#else
+static int ethernet_init(void)
+{
+	return 0;
+}
+#endif
+
+#define GPIO_KEY_HOME		PM8921_GPIO_PM_TO_SYS(27)
+#define GPIO_KEY_VOLUME_UP	PM8921_GPIO_PM_TO_SYS(35)
+#define GPIO_KEY_VOLUME_DOWN	PM8921_GPIO_PM_TO_SYS(38)
+#define GPIO_KEY_CAM_FOCUS	PM8921_GPIO_PM_TO_SYS(3)
+#define GPIO_KEY_CAM_SNAP	PM8921_GPIO_PM_TO_SYS(4)
+#define GPIO_KEY_ROTATION	PM8921_GPIO_PM_TO_SYS(42)
+
+static struct gpio_keys_button cdp_keys[] = {
+	{
+		.code           = KEY_HOME,
+		.gpio           = GPIO_KEY_HOME,
+		.desc           = "home_key",
+		.active_low     = 1,
+		.type		= EV_KEY,
+		.wakeup		= 1,
+		.debounce_interval = 15,
+	},
+	{
+		.code           = KEY_VOLUMEUP,
+		.gpio           = GPIO_KEY_VOLUME_UP,
+		.desc           = "volume_up_key",
+		.active_low     = 1,
+		.type		= EV_KEY,
+		.wakeup		= 1,
+		.debounce_interval = 15,
+	},
+	{
+		.code           = KEY_VOLUMEDOWN,
+		.gpio           = GPIO_KEY_VOLUME_DOWN,
+		.desc           = "volume_down_key",
+		.active_low     = 1,
+		.type		= EV_KEY,
+		.wakeup		= 1,
+		.debounce_interval = 15,
+	},
+	{
+		.code           = SW_ROTATE_LOCK,
+		.gpio           = GPIO_KEY_ROTATION,
+		.desc           = "rotate_key",
+		.active_low     = 1,
+		.type		= EV_SW,
+		.debounce_interval = 15,
+	},
+};
+
+static struct gpio_keys_platform_data cdp_keys_data = {
+	.buttons        = cdp_keys,
+	.nbuttons       = ARRAY_SIZE(cdp_keys),
+};
+
+static struct platform_device cdp_kp_pdev = {
+	.name           = "gpio-keys",
+	.id             = -1,
+	.dev            = {
+		.platform_data  = &cdp_keys_data,
+	},
+};
+
+static struct gpio_keys_button mtp_keys[] = {
+	{
+		.code           = KEY_CAMERA_FOCUS,
+		.gpio           = GPIO_KEY_CAM_FOCUS,
+		.desc           = "cam_focus_key",
+		.active_low     = 1,
+		.type		= EV_KEY,
+		.wakeup		= 1,
+		.debounce_interval = 15,
+	},
+	{
+		.code           = KEY_VOLUMEUP,
+		.gpio           = GPIO_KEY_VOLUME_UP,
+		.desc           = "volume_up_key",
+		.active_low     = 1,
+		.type		= EV_KEY,
+		.wakeup		= 1,
+		.debounce_interval = 15,
+	},
+	{
+		.code           = KEY_VOLUMEDOWN,
+		.gpio           = GPIO_KEY_VOLUME_DOWN,
+		.desc           = "volume_down_key",
+		.active_low     = 1,
+		.type		= EV_KEY,
+		.wakeup		= 1,
+		.debounce_interval = 15,
+	},
+	{
+		.code           = KEY_CAMERA_SNAPSHOT,
+		.gpio           = GPIO_KEY_CAM_SNAP,
+		.desc           = "cam_snap_key",
+		.active_low     = 1,
+		.type		= EV_KEY,
+		.debounce_interval = 15,
+	},
+};
+
+static struct gpio_keys_platform_data mtp_keys_data = {
+	.buttons        = mtp_keys,
+	.nbuttons       = ARRAY_SIZE(mtp_keys),
+};
+
+static struct platform_device mtp_kp_pdev = {
+	.name           = "gpio-keys",
+	.id             = -1,
+	.dev            = {
+		.platform_data  = &mtp_keys_data,
+	},
+};
+
+static struct gpio_keys_button mpq_keys[] = {
+	{
+		.code           = KEY_VOLUMEDOWN,
+		.gpio           = GPIO_KEY_VOLUME_DOWN,
+		.desc           = "volume_down_key",
+		.active_low     = 1,
+		.type		= EV_KEY,
+		.wakeup		= 1,
+		.debounce_interval = 15,
+	},
+	{
+		.code           = KEY_VOLUMEUP,
+		.gpio           = GPIO_KEY_VOLUME_UP,
+		.desc           = "volume_up_key",
+		.active_low     = 1,
+		.type		= EV_KEY,
+		.wakeup		= 1,
+		.debounce_interval = 15,
+	},
+};
+
+static struct gpio_keys_platform_data mpq_keys_data = {
+	.buttons        = mpq_keys,
+	.nbuttons       = ARRAY_SIZE(mpq_keys),
+};
+
+static struct platform_device mpq_gpio_keys_pdev = {
+	.name           = "gpio-keys",
+	.id             = -1,
+	.dev            = {
+		.platform_data  = &mpq_keys_data,
+	},
+};
+
+#define MPQ_KP_ROW_BASE		SX150X_EXP2_GPIO_BASE
+#define MPQ_KP_COL_BASE		(SX150X_EXP2_GPIO_BASE + 4)
+
+static unsigned int mpq_row_gpios[] = {MPQ_KP_ROW_BASE, MPQ_KP_ROW_BASE + 1,
+				MPQ_KP_ROW_BASE + 2, MPQ_KP_ROW_BASE + 3};
+static unsigned int mpq_col_gpios[] = {MPQ_KP_COL_BASE, MPQ_KP_COL_BASE + 1,
+				MPQ_KP_COL_BASE + 2};
+
+static const unsigned int mpq_keymap[] = {
+	KEY(0, 0, KEY_UP),
+	KEY(0, 1, KEY_ENTER),
+	KEY(0, 2, KEY_3),
+
+	KEY(1, 0, KEY_DOWN),
+	KEY(1, 1, KEY_EXIT),
+	KEY(1, 2, KEY_4),
+
+	KEY(2, 0, KEY_LEFT),
+	KEY(2, 1, KEY_1),
+	KEY(2, 2, KEY_5),
+
+	KEY(3, 0, KEY_RIGHT),
+	KEY(3, 1, KEY_2),
+	KEY(3, 2, KEY_6),
+};
+
+static struct matrix_keymap_data mpq_keymap_data = {
+	.keymap_size	= ARRAY_SIZE(mpq_keymap),
+	.keymap		= mpq_keymap,
+};
+
+static struct matrix_keypad_platform_data mpq_keypad_data = {
+	.keymap_data		= &mpq_keymap_data,
+	.row_gpios		= mpq_row_gpios,
+	.col_gpios		= mpq_col_gpios,
+	.num_row_gpios		= ARRAY_SIZE(mpq_row_gpios),
+	.num_col_gpios		= ARRAY_SIZE(mpq_col_gpios),
+	.col_scan_delay_us	= 32000,
+	.debounce_ms		= 20,
+	.wakeup			= 1,
+	.active_low		= 1,
+	.no_autorepeat		= 1,
+};
+
+static struct platform_device mpq_keypad_device = {
+	.name           = "matrix-keypad",
+	.id             = -1,
+	.dev            = {
+		.platform_data  = &mpq_keypad_data,
+	},
+};
+
+/* Sensors DSPS platform data */
+#define DSPS_PIL_GENERIC_NAME		"dsps"
+static void __init apq8064_init_dsps(void)
+{
+	struct msm_dsps_platform_data *pdata =
+		msm_dsps_device_8064.dev.platform_data;
+	pdata->pil_name = DSPS_PIL_GENERIC_NAME;
+	pdata->gpios = NULL;
+	pdata->gpios_num = 0;
+
+	platform_device_register(&msm_dsps_device_8064);
+}
+
+#define I2C_SURF 1
+#define I2C_FFA  (1 << 1)
+#define I2C_RUMI (1 << 2)
+#define I2C_SIM  (1 << 3)
+#define I2C_LIQUID (1 << 4)
+#define I2C_MPQ_CDP	BIT(5)
+#define I2C_MPQ_HRD	BIT(6)
+#define I2C_MPQ_DTV	BIT(7)
+
+struct i2c_registry {
+	u8                     machs;
+	int                    bus;
+	struct i2c_board_info *info;
+	int                    len;
+};
+
+static struct i2c_registry apq8064_i2c_devices[] __initdata = {
+	{
+		I2C_LIQUID,
+		APQ_8064_GSBI1_QUP_I2C_BUS_ID,
+		smb349_charger_i2c_info,
+		ARRAY_SIZE(smb349_charger_i2c_info)
+	},
+	{
+		I2C_SURF | I2C_LIQUID,
+		APQ_8064_GSBI3_QUP_I2C_BUS_ID,
+		mxt_device_info,
+		ARRAY_SIZE(mxt_device_info),
+	},
+	{
+		I2C_FFA,
+		APQ_8064_GSBI3_QUP_I2C_BUS_ID,
+		cyttsp_info,
+		ARRAY_SIZE(cyttsp_info),
+	},
+	{
+		I2C_FFA | I2C_LIQUID,
+		APQ_8064_GSBI1_QUP_I2C_BUS_ID,
+		isa1200_board_info,
+		ARRAY_SIZE(isa1200_board_info),
+	},
+	{
+		I2C_MPQ_CDP,
+		APQ_8064_GSBI5_QUP_I2C_BUS_ID,
+		cs8427_device_info,
+		ARRAY_SIZE(cs8427_device_info),
+	},
+};
+
+#define SX150X_EXP1_INT_N	PM8921_MPP_IRQ(PM8921_IRQ_BASE, 9)
+#define SX150X_EXP2_INT_N	MSM_GPIO_TO_INT(81)
+
+struct sx150x_platform_data mpq8064_sx150x_pdata[] = {
+	[SX150X_EXP1] = {
+		.gpio_base	= SX150X_EXP1_GPIO_BASE,
+		.oscio_is_gpo	= false,
+		.io_pullup_ena	= 0x0,
+		.io_pulldn_ena	= 0x0,
+		.io_open_drain_ena = 0x0,
+		.io_polarity	= 0,
+		.irq_summary	= SX150X_EXP1_INT_N,
+		.irq_base	= SX150X_EXP1_IRQ_BASE,
+	},
+	[SX150X_EXP2] = {
+		.gpio_base	= SX150X_EXP2_GPIO_BASE,
+		.oscio_is_gpo	= false,
+		.io_pullup_ena	= 0x0f,
+		.io_pulldn_ena	= 0x70,
+		.io_open_drain_ena = 0x0,
+		.io_polarity	= 0,
+		.irq_summary	= SX150X_EXP2_INT_N,
+		.irq_base	= SX150X_EXP2_IRQ_BASE,
+	},
+	[SX150X_EXP3] = {
+		.gpio_base	= SX150X_EXP3_GPIO_BASE,
+		.oscio_is_gpo	= false,
+		.io_pullup_ena	= 0x0,
+		.io_pulldn_ena	= 0x0,
+		.io_open_drain_ena = 0x0,
+		.io_polarity	= 0,
+		.irq_summary	= -1,
+	},
+	[SX150X_EXP4] = {
+		.gpio_base	= SX150X_EXP4_GPIO_BASE,
+		.oscio_is_gpo	= false,
+		.io_pullup_ena	= 0x0,
+		.io_pulldn_ena	= 0x0,
+		.io_open_drain_ena = 0x0,
+		.io_polarity	= 0,
+		.irq_summary	= -1,
+	},
+};
+
+static struct i2c_board_info sx150x_gpio_exp_info[] = {
+	{
+		I2C_BOARD_INFO("sx1509q", 0x70),
+		.platform_data = &mpq8064_sx150x_pdata[SX150X_EXP1],
+	},
+	{
+		I2C_BOARD_INFO("sx1508q", 0x23),
+		.platform_data = &mpq8064_sx150x_pdata[SX150X_EXP2],
+	},
+	{
+		I2C_BOARD_INFO("sx1508q", 0x22),
+		.platform_data = &mpq8064_sx150x_pdata[SX150X_EXP3],
+	},
+	{
+		I2C_BOARD_INFO("sx1509q", 0x3E),
+		.platform_data = &mpq8064_sx150x_pdata[SX150X_EXP4],
+	},
+};
+
+#define MPQ8064_I2C_GSBI5_BUS_ID	5
+
+static struct i2c_registry mpq8064_i2c_devices[] __initdata = {
+	{
+		I2C_MPQ_CDP,
+		MPQ8064_I2C_GSBI5_BUS_ID,
+		sx150x_gpio_exp_info,
+		ARRAY_SIZE(sx150x_gpio_exp_info),
+	},
+};
+
+static void __init register_i2c_devices(void)
+{
+	u8 mach_mask = 0;
+	int i;
+
+#ifdef CONFIG_MSM_CAMERA
+	struct i2c_registry apq8064_camera_i2c_devices = {
+		I2C_SURF | I2C_FFA | I2C_LIQUID | I2C_RUMI,
+		APQ_8064_GSBI4_QUP_I2C_BUS_ID,
+		apq8064_camera_board_info.board_info,
+		apq8064_camera_board_info.num_i2c_board_info,
+	};
+#endif
+	/* Build the matching 'supported_machs' bitmask */
+	if (machine_is_apq8064_cdp())
+		mach_mask = I2C_SURF;
+	else if (machine_is_apq8064_mtp())
+		mach_mask = I2C_FFA;
+	else if (machine_is_apq8064_liquid())
+		mach_mask = I2C_LIQUID;
+	else if (machine_is_apq8064_rumi3())
+		mach_mask = I2C_RUMI;
+	else if (machine_is_apq8064_sim())
+		mach_mask = I2C_SIM;
+	else if (PLATFORM_IS_MPQ8064())
+		mach_mask = I2C_MPQ_CDP;
+	else
+		pr_err("unmatched machine ID in register_i2c_devices\n");
+
+	/* Run the array and install devices as appropriate */
+	for (i = 0; i < ARRAY_SIZE(apq8064_i2c_devices); ++i) {
+		if (apq8064_i2c_devices[i].machs & mach_mask)
+			i2c_register_board_info(apq8064_i2c_devices[i].bus,
+						apq8064_i2c_devices[i].info,
+						apq8064_i2c_devices[i].len);
+	}
+#ifdef CONFIG_MSM_CAMERA
+	if (apq8064_camera_i2c_devices.machs & mach_mask)
+		i2c_register_board_info(apq8064_camera_i2c_devices.bus,
+			apq8064_camera_i2c_devices.info,
+			apq8064_camera_i2c_devices.len);
+#endif
+
+	for (i = 0; i < ARRAY_SIZE(mpq8064_i2c_devices); ++i) {
+		if (mpq8064_i2c_devices[i].machs & mach_mask)
+			i2c_register_board_info(
+					mpq8064_i2c_devices[i].bus,
+					mpq8064_i2c_devices[i].info,
+					mpq8064_i2c_devices[i].len);
+	}
+}
+
+static void enable_ddr3_regulator(void)
+{
+	static struct regulator *ext_ddr3;
+
+	/* Use MPP7 output state as a flag for PCDDR3 presence. */
+	if (gpio_get_value_cansleep(PM8921_MPP_PM_TO_SYS(7)) > 0) {
+		ext_ddr3 = regulator_get(NULL, "ext_ddr3");
+		if (IS_ERR(ext_ddr3) || ext_ddr3 == NULL)
+			pr_err("Could not get MPP7 regulator\n");
+		else
+			regulator_enable(ext_ddr3);
+	}
+}
+
+static void enable_avc_i2c_bus(void)
+{
+	int avc_i2c_en_mpp = PM8921_MPP_PM_TO_SYS(8);
+	int rc;
+
+	rc = gpio_request(avc_i2c_en_mpp, "avc_i2c_en");
+	if (rc)
+		pr_err("request for avc_i2c_en mpp failed,"
+						 "rc=%d\n", rc);
+	else
+		gpio_set_value_cansleep(avc_i2c_en_mpp, 1);
+}
+
+static void __init apq8064_common_init(void)
+{
+	msm_tsens_early_init(&apq_tsens_pdata);
+	if (socinfo_init() < 0)
+		pr_err("socinfo_init() failed!\n");
+	BUG_ON(msm_rpm_init(&apq8064_rpm_data));
+	BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
+	regulator_suppress_info_printing();
+	platform_device_register(&apq8064_device_rpm_regulator);
+	if (msm_xo_init())
+		pr_err("Failed to initialize XO votes\n");
+	msm_clock_init(&apq8064_clock_init_data);
+	apq8064_init_gpiomux();
+	apq8064_i2c_init();
+	register_i2c_devices();
+
+	apq8064_device_qup_spi_gsbi5.dev.platform_data =
+						&apq8064_qup_spi_gsbi5_pdata;
+	apq8064_init_pmic();
+	if (machine_is_apq8064_liquid())
+		msm_otg_pdata.mhl_enable = true;
+
+	android_usb_pdata.swfi_latency =
+		msm_rpmrs_levels[0].latency_us;
+
+	apq8064_device_otg.dev.platform_data = &msm_otg_pdata;
+	apq8064_ehci_host_init();
+	apq8064_init_buses();
+	platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
+	if (!(machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
+			machine_is_mpq8064_dtv()))
+		platform_add_devices(common_not_mpq_devices,
+			ARRAY_SIZE(common_not_mpq_devices));
+	enable_ddr3_regulator();
+	if (machine_is_apq8064_mtp()) {
+		apq8064_device_hsic_host.dev.platform_data = &msm_hsic_pdata;
+		device_initialize(&apq8064_device_hsic_host.dev);
+	}
+	apq8064_pm8xxx_gpio_mpp_init();
+	apq8064_init_mmc();
+
+	if (machine_is_apq8064_mtp()) {
+		mdm_8064_device.dev.platform_data = &mdm_platform_data;
+		platform_device_register(&mdm_8064_device);
+	}
+	platform_device_register(&apq8064_slim_ctrl);
+	slim_register_board_info(apq8064_slim_devices,
+		ARRAY_SIZE(apq8064_slim_devices));
+	apq8064_init_dsps();
+	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
+	acpuclk_init(&acpuclk_8064_soc_data);
+	msm_spm_l2_init(msm_spm_l2_data);
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+	msm_pm_init_sleep_status_data(&msm_pm_slp_sts_data);
+	apq8064_epm_adc_init();
+}
+
+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 *)
+		&msm8064_device_watchdog.dev.platform_data;
+
+	wdog_pdata->bark_time = 15000;
+	apq8064_common_init();
+	platform_add_devices(sim_devices, ARRAY_SIZE(sim_devices));
+}
+
+static void __init apq8064_rumi3_init(void)
+{
+	apq8064_common_init();
+	ethernet_init();
+	platform_add_devices(rumi3_devices, ARRAY_SIZE(rumi3_devices));
+	spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
+}
+
+static void __init apq8064_cdp_init(void)
+{
+	if (meminfo_init(SYS_MEMORY, SZ_256M) < 0)
+		pr_err("meminfo_init() failed!\n");
+	apq8064_common_init();
+	if (machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
+		machine_is_mpq8064_dtv()) {
+		enable_avc_i2c_bus();
+		platform_add_devices(mpq_devices, ARRAY_SIZE(mpq_devices));
+		mpq8064_pcie_init();
+	} else {
+		ethernet_init();
+		platform_add_devices(cdp_devices, ARRAY_SIZE(cdp_devices));
+		spi_register_board_info(spi_board_info,
+						ARRAY_SIZE(spi_board_info));
+	}
+	apq8064_init_fb();
+	apq8064_init_gpu();
+	platform_add_devices(apq8064_footswitch, apq8064_num_footswitch);
+#ifdef CONFIG_MSM_CAMERA
+	apq8064_init_cam();
+#endif
+
+	if (machine_is_apq8064_cdp() || machine_is_apq8064_liquid())
+		platform_device_register(&cdp_kp_pdev);
+
+	if (machine_is_apq8064_mtp())
+		platform_device_register(&mtp_kp_pdev);
+
+	change_memory_power = &apq8064_change_memory_power;
+
+	if (machine_is_mpq8064_cdp()) {
+		platform_device_register(&mpq_gpio_keys_pdev);
+		platform_device_register(&mpq_keypad_device);
+	}
+}
+
+MACHINE_START(APQ8064_SIM, "QCT APQ8064 SIMULATOR")
+	.map_io = apq8064_map_io,
+	.reserve = apq8064_reserve,
+	.init_irq = apq8064_init_irq,
+	.handle_irq = gic_handle_irq,
+	.timer = &msm_timer,
+	.init_machine = apq8064_sim_init,
+MACHINE_END
+
+MACHINE_START(APQ8064_RUMI3, "QCT APQ8064 RUMI3")
+	.map_io = apq8064_map_io,
+	.reserve = apq8064_reserve,
+	.init_irq = apq8064_init_irq,
+	.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")
+	.map_io = apq8064_map_io,
+	.reserve = apq8064_reserve,
+	.init_irq = apq8064_init_irq,
+	.handle_irq = gic_handle_irq,
+	.timer = &msm_timer,
+	.init_machine = apq8064_cdp_init,
+	.init_early = apq8064_allocate_memory_regions,
+	.init_very_early = apq8064_early_reserve,
+MACHINE_END
+
+MACHINE_START(APQ8064_MTP, "QCT APQ8064 MTP")
+	.map_io = apq8064_map_io,
+	.reserve = apq8064_reserve,
+	.init_irq = apq8064_init_irq,
+	.handle_irq = gic_handle_irq,
+	.timer = &msm_timer,
+	.init_machine = apq8064_cdp_init,
+	.init_early = apq8064_allocate_memory_regions,
+	.init_very_early = apq8064_early_reserve,
+MACHINE_END
+
+MACHINE_START(APQ8064_LIQUID, "QCT APQ8064 LIQUID")
+	.map_io = apq8064_map_io,
+	.reserve = apq8064_reserve,
+	.init_irq = apq8064_init_irq,
+	.handle_irq = gic_handle_irq,
+	.timer = &msm_timer,
+	.init_machine = apq8064_cdp_init,
+	.init_early = apq8064_allocate_memory_regions,
+	.init_very_early = apq8064_early_reserve,
+MACHINE_END
+
+MACHINE_START(MPQ8064_CDP, "QCT MPQ8064 CDP")
+	.map_io = apq8064_map_io,
+	.reserve = apq8064_reserve,
+	.init_irq = apq8064_init_irq,
+	.handle_irq = gic_handle_irq,
+	.timer = &msm_timer,
+	.init_machine = apq8064_cdp_init,
+	.init_early = apq8064_allocate_memory_regions,
+	.init_very_early = apq8064_early_reserve,
+MACHINE_END
+
+MACHINE_START(MPQ8064_HRD, "QCT MPQ8064 HRD")
+	.map_io = apq8064_map_io,
+	.reserve = apq8064_reserve,
+	.init_irq = apq8064_init_irq,
+	.handle_irq = gic_handle_irq,
+	.timer = &msm_timer,
+	.init_machine = apq8064_cdp_init,
+	.init_early = apq8064_allocate_memory_regions,
+	.init_very_early = apq8064_early_reserve,
+MACHINE_END
+
+MACHINE_START(MPQ8064_DTV, "QCT MPQ8064 DTV")
+	.map_io = apq8064_map_io,
+	.reserve = apq8064_reserve,
+	.init_irq = apq8064_init_irq,
+	.handle_irq = gic_handle_irq,
+	.timer = &msm_timer,
+	.init_machine = apq8064_cdp_init,
+	.init_early = apq8064_allocate_memory_regions,
+	.init_very_early = apq8064_early_reserve,
+MACHINE_END
+
diff --git a/arch/arm/mach-msm/board-8064.h b/arch/arm/mach-msm/board-8064.h
new file mode 100644
index 0000000..39c367f
--- /dev/null
+++ b/arch/arm/mach-msm/board-8064.h
@@ -0,0 +1,148 @@
+/* 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
+ * 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 __ARCH_ARM_MACH_MSM_BOARD_APQ8064_H
+#define __ARCH_ARM_MACH_MSM_BOARD_APQ8064_H
+
+#include <linux/regulator/msm-gpio-regulator.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/mfd/pm8xxx/pm8821.h>
+#include <mach/msm_memtypes.h>
+#include <mach/irqs.h>
+#include <mach/rpm-regulator.h>
+#include <mach/msm_rtb.h>
+#include <mach/msm_cache_dump.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)
+#define PM8921_MPP_BASE			(PM8921_GPIO_BASE + PM8921_NR_GPIOS)
+#define PM8921_MPP_PM_TO_SYS(pm_mpp)	(pm_mpp - 1 + PM8921_MPP_BASE)
+#define PM8921_IRQ_BASE			(NR_MSM_IRQS + NR_GPIO_IRQS)
+
+#define PM8821_MPP_BASE			(PM8921_MPP_BASE + PM8921_NR_MPPS)
+#define PM8821_MPP_PM_TO_SYS(pm_mpp)	(pm_mpp - 1 + PM8821_MPP_BASE)
+#define PM8821_IRQ_BASE			(PM8921_IRQ_BASE + PM8921_NR_IRQS)
+
+#define TABLA_INTERRUPT_BASE		(PM8821_IRQ_BASE + PM8821_NR_IRQS)
+
+extern struct pm8xxx_regulator_platform_data
+	msm8064_pm8921_regulator_pdata[] __devinitdata;
+
+extern int msm8064_pm8921_regulator_pdata_len __devinitdata;
+
+#define GPIO_VREG_ID_EXT_5V		0
+#define GPIO_VREG_ID_EXT_3P3V		1
+#define GPIO_VREG_ID_EXT_TS_SW		2
+#define GPIO_VREG_ID_EXT_MPP8		3
+
+#define GPIO_VREG_ID_FRC_5V		0
+#define GPIO_VREG_ID_AVC_1P2V		1
+#define GPIO_VREG_ID_AVC_1P8V		2
+#define GPIO_VREG_ID_AVC_2P2V		3
+#define GPIO_VREG_ID_AVC_5V		4
+#define GPIO_VREG_ID_AVC_3P3V		5
+
+#define APQ8064_EXT_3P3V_REG_EN_GPIO	77
+
+extern struct gpio_regulator_platform_data
+	apq8064_gpio_regulator_pdata[] __devinitdata;
+
+extern struct gpio_regulator_platform_data
+	mpq8064_gpio_regulator_pdata[] __devinitdata;
+
+extern struct rpm_regulator_platform_data
+	apq8064_rpm_regulator_pdata __devinitdata;
+
+extern struct regulator_init_data msm8064_saw_regulator_pdata_8921_s5;
+extern struct regulator_init_data msm8064_saw_regulator_pdata_8921_s6;
+extern struct regulator_init_data msm8064_saw_regulator_pdata_8821_s0;
+extern struct regulator_init_data msm8064_saw_regulator_pdata_8821_s1;
+
+struct mmc_platform_data;
+int __init apq8064_add_sdcc(unsigned int controller,
+		struct mmc_platform_data *plat);
+
+void apq8064_init_mmc(void);
+void apq8064_init_gpiomux(void);
+void apq8064_init_pmic(void);
+
+extern struct msm_camera_board_info apq8064_camera_board_info;
+void apq8064_init_cam(void);
+
+#define APQ_8064_GSBI1_QUP_I2C_BUS_ID 0
+#define APQ_8064_GSBI3_QUP_I2C_BUS_ID 3
+#define APQ_8064_GSBI4_QUP_I2C_BUS_ID 4
+#define APQ_8064_GSBI5_QUP_I2C_BUS_ID 5
+
+unsigned char apq8064_hdmi_as_primary_selected(void);
+void apq8064_init_fb(void);
+void apq8064_allocate_fb_region(void);
+void apq8064_mdp_writeback(struct memtype_reserve *reserve_table);
+void __init apq8064_set_display_params(char *prim_panel, char *ext_panel);
+
+void apq8064_init_gpu(void);
+void apq8064_pm8xxx_gpio_mpp_init(void);
+
+#define PLATFORM_IS_MPQ8064() \
+	(machine_is_mpq8064_hrd() || \
+	 machine_is_mpq8064_dtv() || \
+	 machine_is_mpq8064_cdp() \
+	)
+
+
+#define GPIO_EXPANDER_IRQ_BASE	(TABLA_INTERRUPT_BASE + \
+					NR_TABLA_IRQS)
+#define GPIO_EXPANDER_GPIO_BASE	(PM8821_MPP_BASE + PM8821_NR_MPPS)
+
+#define GPIO_EPM_EXPANDER_BASE	GPIO_EXPANDER_GPIO_BASE
+#define SX150X_EPM_NR_GPIOS	16
+#define SX150X_EPM_NR_IRQS	8
+
+#define SX150X_EXP1_GPIO_BASE	(GPIO_EPM_EXPANDER_BASE + \
+					SX150X_EPM_NR_GPIOS)
+#define SX150X_EXP1_IRQ_BASE	(GPIO_EXPANDER_IRQ_BASE + \
+				SX150X_EPM_NR_IRQS)
+#define SX150X_EXP1_NR_IRQS	16
+#define SX150X_EXP1_NR_GPIOS	16
+
+#define SX150X_EXP2_GPIO_BASE	(SX150X_EXP1_GPIO_BASE + \
+					SX150X_EXP1_NR_GPIOS)
+#define SX150X_EXP2_IRQ_BASE	(SX150X_EXP1_IRQ_BASE + SX150X_EXP1_NR_IRQS)
+#define SX150X_EXP2_NR_IRQS	8
+#define SX150X_EXP2_NR_GPIOS	8
+
+#define SX150X_EXP3_GPIO_BASE	(SX150X_EXP2_GPIO_BASE + \
+					SX150X_EXP2_NR_GPIOS)
+#define SX150X_EXP3_IRQ_BASE	(SX150X_EXP2_IRQ_BASE + SX150X_EXP2_NR_IRQS)
+#define SX150X_EXP3_NR_IRQS	8
+#define SX150X_EXP3_NR_GPIOS	8
+
+#define SX150X_EXP4_GPIO_BASE	(SX150X_EXP3_GPIO_BASE + \
+					SX150X_EXP3_NR_GPIOS)
+#define SX150X_EXP4_IRQ_BASE	(SX150X_EXP3_IRQ_BASE + SX150X_EXP3_NR_IRQS)
+#define SX150X_EXP4_NR_IRQS	16
+#define SX150X_EXP4_NR_GPIOS	16
+
+#define SX150X_GPIO(_expander, _pin) (SX150X_EXP##_expander##_GPIO_BASE + _pin)
+
+enum {
+	SX150X_EPM,
+	SX150X_EXP1,
+	SX150X_EXP2,
+	SX150X_EXP3,
+	SX150X_EXP4,
+};
+
+extern struct msm_rtb_platform_data apq8064_rtb_pdata;
+extern struct msm_cache_dump_platform_data apq8064_cache_dump_pdata;
+#endif
diff --git a/arch/arm/mach-msm/board-8930-camera.c b/arch/arm/mach-msm/board-8930-camera.c
new file mode 100644
index 0000000..e7f0e68
--- /dev/null
+++ b/arch/arm/mach-msm/board-8930-camera.c
@@ -0,0 +1,636 @@
+/* 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
+ * 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 <asm/mach-types.h>
+#include <linux/gpio.h>
+#include <mach/board.h>
+#include <mach/msm_bus_board.h>
+#include <mach/gpiomux.h>
+#include "devices.h"
+#include "board-8930.h"
+
+#ifdef CONFIG_MSM_CAMERA
+
+#if (defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)) && \
+	defined(CONFIG_I2C)
+
+static struct i2c_board_info cam_expander_i2c_info[] = {
+	{
+		I2C_BOARD_INFO("sx1508q", 0x22),
+		.platform_data = &msm8930_sx150x_data[SX150X_CAM]
+	},
+};
+
+static struct msm_cam_expander_info cam_expander_info[] = {
+	{
+		cam_expander_i2c_info,
+		MSM_8930_GSBI4_QUP_I2C_BUS_ID,
+	},
+};
+#endif
+
+static struct gpiomux_setting cam_settings[] = {
+	{
+		.func = GPIOMUX_FUNC_GPIO, /*suspend*/
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_DOWN,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_1, /*active 1*/
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_GPIO, /*active 2*/
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_1, /*active 3*/
+		.drv = GPIOMUX_DRV_8MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_5, /*active 4*/
+		.drv = GPIOMUX_DRV_8MA,
+		.pull = GPIOMUX_PULL_UP,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_6, /*active 5*/
+		.drv = GPIOMUX_DRV_8MA,
+		.pull = GPIOMUX_PULL_UP,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_2, /*active 6*/
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_UP,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_3, /*active 7*/
+		.drv = GPIOMUX_DRV_8MA,
+		.pull = GPIOMUX_PULL_UP,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_GPIO, /*i2c suspend*/
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_KEEPER,
+	},
+	{
+		.func = GPIOMUX_FUNC_2, /*active 9*/
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+
+};
+
+
+static struct msm_gpiomux_config msm8930_cam_common_configs[] = {
+	{
+		.gpio = 2,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[2],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
+		},
+	},
+	{
+		.gpio = 3,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[1],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
+		},
+	},
+	{
+		.gpio = 4,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[9],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
+		},
+	},
+	{
+		.gpio = 5,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[1],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
+		},
+	},
+	{
+		.gpio = 76,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[2],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
+		},
+	},
+	{
+		.gpio = 107,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[2],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
+		},
+	},
+	{
+		.gpio = 54,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[2],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8930_cam_2d_configs[] = {
+	{
+		.gpio = 18,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &cam_settings[8],
+		},
+	},
+	{
+		.gpio = 19,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &cam_settings[8],
+		},
+	},
+	{
+		.gpio = 20,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &cam_settings[8],
+		},
+	},
+	{
+		.gpio = 21,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &cam_settings[8],
+		},
+	},
+};
+
+#define VFE_CAMIF_TIMER1_GPIO 2
+#define VFE_CAMIF_TIMER2_GPIO 3
+#define VFE_CAMIF_TIMER3_GPIO_INT 4
+static struct msm_camera_sensor_strobe_flash_data strobe_flash_xenon = {
+	.flash_trigger = VFE_CAMIF_TIMER2_GPIO,
+	.flash_charge = VFE_CAMIF_TIMER1_GPIO,
+	.flash_charge_done = VFE_CAMIF_TIMER3_GPIO_INT,
+	.flash_recharge_duration = 50000,
+	.irq = MSM_GPIO_TO_INT(VFE_CAMIF_TIMER3_GPIO_INT),
+};
+
+#ifdef CONFIG_MSM_CAMERA_FLASH
+static struct msm_camera_sensor_flash_src msm_flash_src = {
+	.flash_sr_type = MSM_CAMERA_FLASH_SRC_EXT,
+	._fsrc.ext_driver_src.led_en = VFE_CAMIF_TIMER1_GPIO,
+	._fsrc.ext_driver_src.led_flash_en = VFE_CAMIF_TIMER2_GPIO,
+	._fsrc.ext_driver_src.flash_id = MAM_CAMERA_EXT_LED_FLASH_TPS61310,
+};
+#endif
+
+static struct msm_bus_vectors cam_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+};
+
+static struct msm_bus_vectors cam_preview_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 27648000,
+		.ib  = 110592000,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+};
+
+static struct msm_bus_vectors cam_video_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 140451840,
+		.ib  = 561807360,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 206807040,
+		.ib  = 488816640,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+};
+
+static struct msm_bus_vectors cam_snapshot_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 274423680,
+		.ib  = 1097694720,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 540000000,
+		.ib  = 1350000000,
+	},
+};
+
+static struct msm_bus_vectors cam_zsl_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 302071680,
+		.ib  = 1208286720,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 540000000,
+		.ib  = 1350000000,
+	},
+};
+
+static struct msm_bus_paths cam_bus_client_config[] = {
+	{
+		ARRAY_SIZE(cam_init_vectors),
+		cam_init_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_preview_vectors),
+		cam_preview_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_video_vectors),
+		cam_video_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_snapshot_vectors),
+		cam_snapshot_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_zsl_vectors),
+		cam_zsl_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata cam_bus_client_pdata = {
+		cam_bus_client_config,
+		ARRAY_SIZE(cam_bus_client_config),
+		.name = "msm_camera",
+};
+
+static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
+	{
+		.csid_core = 0,
+		.is_csiphy = 1,
+		.is_csid   = 1,
+		.is_ispif  = 1,
+		.is_vpe    = 1,
+		.cam_bus_scale_table = &cam_bus_client_pdata,
+	},
+	{
+		.csid_core = 1,
+		.is_csiphy = 1,
+		.is_csid   = 1,
+		.is_ispif  = 1,
+		.is_vpe    = 1,
+		.cam_bus_scale_table = &cam_bus_client_pdata,
+	},
+};
+
+static struct camera_vreg_t msm_8930_back_cam_vreg[] = {
+	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
+	{"cam_vio", REG_VS, 0, 0, 0},
+	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
+	{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
+};
+
+static struct camera_vreg_t msm_8930_front_cam_vreg[] = {
+	{"cam_vio", REG_VS, 0, 0, 0},
+	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
+	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
+};
+
+static struct gpio msm8930_common_cam_gpio[] = {
+	{20, GPIOF_DIR_IN, "CAMIF_I2C_DATA"},
+	{21, GPIOF_DIR_IN, "CAMIF_I2C_CLK"},
+};
+
+static struct gpio msm8930_front_cam_gpio[] = {
+	{4, GPIOF_DIR_IN, "CAMIF_MCLK"},
+	{76, GPIOF_DIR_OUT, "CAM_RESET"},
+};
+
+static struct gpio msm8930_back_cam_gpio[] = {
+	{5, GPIOF_DIR_IN, "CAMIF_MCLK"},
+	{107, GPIOF_DIR_OUT, "CAM_RESET"},
+	{54, GPIOF_DIR_OUT, "CAM_STBY_N"},
+};
+
+static struct msm_gpio_set_tbl msm8930_front_cam_gpio_set_tbl[] = {
+	{76, GPIOF_OUT_INIT_LOW, 1000},
+	{76, GPIOF_OUT_INIT_HIGH, 4000},
+};
+
+static struct msm_gpio_set_tbl msm8930_back_cam_gpio_set_tbl[] = {
+	{54, GPIOF_OUT_INIT_LOW, 1000},
+	{54, GPIOF_OUT_INIT_HIGH, 4000},
+	{107, GPIOF_OUT_INIT_LOW, 1000},
+	{107, GPIOF_OUT_INIT_HIGH, 4000},
+};
+
+static struct msm_camera_gpio_conf msm_8930_front_cam_gpio_conf = {
+	.cam_gpiomux_conf_tbl = msm8930_cam_2d_configs,
+	.cam_gpiomux_conf_tbl_size = ARRAY_SIZE(msm8930_cam_2d_configs),
+	.cam_gpio_common_tbl = msm8930_common_cam_gpio,
+	.cam_gpio_common_tbl_size = ARRAY_SIZE(msm8930_common_cam_gpio),
+	.cam_gpio_req_tbl = msm8930_front_cam_gpio,
+	.cam_gpio_req_tbl_size = ARRAY_SIZE(msm8930_front_cam_gpio),
+	.cam_gpio_set_tbl = msm8930_front_cam_gpio_set_tbl,
+	.cam_gpio_set_tbl_size = ARRAY_SIZE(msm8930_front_cam_gpio_set_tbl),
+};
+
+static struct msm_camera_gpio_conf msm_8930_back_cam_gpio_conf = {
+	.cam_gpiomux_conf_tbl = msm8930_cam_2d_configs,
+	.cam_gpiomux_conf_tbl_size = ARRAY_SIZE(msm8930_cam_2d_configs),
+	.cam_gpio_common_tbl = msm8930_common_cam_gpio,
+	.cam_gpio_common_tbl_size = ARRAY_SIZE(msm8930_common_cam_gpio),
+	.cam_gpio_req_tbl = msm8930_back_cam_gpio,
+	.cam_gpio_req_tbl_size = ARRAY_SIZE(msm8930_back_cam_gpio),
+	.cam_gpio_set_tbl = msm8930_back_cam_gpio_set_tbl,
+	.cam_gpio_set_tbl_size = ARRAY_SIZE(msm8930_back_cam_gpio_set_tbl),
+};
+
+static struct i2c_board_info msm_act_main_cam_i2c_info = {
+	I2C_BOARD_INFO("msm_actuator", 0x11),
+};
+
+static struct msm_actuator_info msm_act_main_cam_0_info = {
+	.board_info     = &msm_act_main_cam_i2c_info,
+	.cam_name   = MSM_ACTUATOR_MAIN_CAM_0,
+	.bus_id         = MSM_8930_GSBI4_QUP_I2C_BUS_ID,
+	.vcm_pwd        = 0,
+	.vcm_enable     = 0,
+};
+
+static struct msm_camera_sensor_flash_data flash_imx074 = {
+	.flash_type	= MSM_CAMERA_FLASH_LED,
+#ifdef CONFIG_MSM_CAMERA_FLASH
+	.flash_src	= &msm_flash_src
+#endif
+};
+
+static struct msm_camera_csi_lane_params imx074_csi_lane_params = {
+	.csi_lane_assign = 0xE4,
+	.csi_lane_mask = 0xF,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_imx074 = {
+	.mount_angle	= 90,
+	.cam_vreg = msm_8930_back_cam_vreg,
+	.num_vreg = ARRAY_SIZE(msm_8930_back_cam_vreg),
+	.gpio_conf = &msm_8930_back_cam_gpio_conf,
+	.csi_lane_params = &imx074_csi_lane_params,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_imx074_data = {
+	.sensor_name	= "imx074",
+	.pdata	= &msm_camera_csi_device_data[0],
+	.flash_data	= &flash_imx074,
+	.strobe_flash_data = &strobe_flash_xenon,
+	.sensor_platform_info = &sensor_board_info_imx074,
+	.csi_if	= 1,
+	.camera_type = BACK_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
+	.actuator_info = &msm_act_main_cam_0_info,
+};
+
+static struct camera_vreg_t msm_8930_mt9m114_vreg[] = {
+	{"cam_vio", REG_VS, 0, 0, 0},
+	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
+	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
+	{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
+};
+
+static struct msm_camera_sensor_flash_data flash_mt9m114 = {
+	.flash_type = MSM_CAMERA_FLASH_NONE
+};
+
+static struct msm_camera_csi_lane_params mt9m114_csi_lane_params = {
+	.csi_lane_assign = 0xE4,
+	.csi_lane_mask = 0x1,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_mt9m114 = {
+	.mount_angle = 90,
+	.cam_vreg = msm_8930_mt9m114_vreg,
+	.num_vreg = ARRAY_SIZE(msm_8930_mt9m114_vreg),
+	.gpio_conf = &msm_8930_front_cam_gpio_conf,
+	.csi_lane_params = &mt9m114_csi_lane_params,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_mt9m114_data = {
+	.sensor_name = "mt9m114",
+	.pdata = &msm_camera_csi_device_data[1],
+	.flash_data = &flash_mt9m114,
+	.sensor_platform_info = &sensor_board_info_mt9m114,
+	.csi_if = 1,
+	.camera_type = FRONT_CAMERA_2D,
+	.sensor_type = YUV_SENSOR,
+};
+
+static struct msm_camera_sensor_flash_data flash_ov2720 = {
+	.flash_type	= MSM_CAMERA_FLASH_NONE,
+};
+
+static struct msm_camera_csi_lane_params ov2720_csi_lane_params = {
+	.csi_lane_assign = 0xE4,
+	.csi_lane_mask = 0x3,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_ov2720 = {
+	.mount_angle	= 0,
+	.cam_vreg = msm_8930_front_cam_vreg,
+	.num_vreg = ARRAY_SIZE(msm_8930_front_cam_vreg),
+	.gpio_conf = &msm_8930_front_cam_gpio_conf,
+	.csi_lane_params = &ov2720_csi_lane_params,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_ov2720_data = {
+	.sensor_name	= "ov2720",
+	.pdata	= &msm_camera_csi_device_data[1],
+	.flash_data	= &flash_ov2720,
+	.sensor_platform_info = &sensor_board_info_ov2720,
+	.csi_if	= 1,
+	.camera_type = FRONT_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
+};
+
+static struct camera_vreg_t msm_8930_s5k3l1yx_vreg[] = {
+	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
+	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
+	{"cam_vio", REG_VS, 0, 0, 0},
+	{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
+};
+
+static struct msm_camera_sensor_flash_data flash_s5k3l1yx = {
+	.flash_type = MSM_CAMERA_FLASH_LED,
+	.flash_src = &msm_flash_src
+};
+
+static struct msm_camera_csi_lane_params s5k3l1yx_csi_lane_params = {
+	.csi_lane_assign = 0xE4,
+	.csi_lane_mask = 0xF,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_s5k3l1yx = {
+	.mount_angle  = 90,
+	.cam_vreg = msm_8930_s5k3l1yx_vreg,
+	.num_vreg = ARRAY_SIZE(msm_8930_s5k3l1yx_vreg),
+	.gpio_conf = &msm_8930_back_cam_gpio_conf,
+	.csi_lane_params = &s5k3l1yx_csi_lane_params,
+};
+
+static struct msm_actuator_info msm_act_main_cam_2_info = {
+	.board_info     = &msm_act_main_cam_i2c_info,
+	.cam_name   = MSM_ACTUATOR_MAIN_CAM_2,
+	.bus_id         = MSM_8930_GSBI4_QUP_I2C_BUS_ID,
+	.vcm_pwd        = 0,
+	.vcm_enable     = 0,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_s5k3l1yx_data = {
+	.sensor_name          = "s5k3l1yx",
+	.pdata                = &msm_camera_csi_device_data[0],
+	.flash_data           = &flash_s5k3l1yx,
+	.sensor_platform_info = &sensor_board_info_s5k3l1yx,
+	.csi_if               = 1,
+	.camera_type          = BACK_CAMERA_2D,
+	.sensor_type          = BAYER_SENSOR,
+	.actuator_info    = &msm_act_main_cam_2_info,
+};
+
+static struct platform_device msm_camera_server = {
+	.name = "msm_cam_server",
+	.id = 0,
+};
+
+void __init msm8930_init_cam(void)
+{
+	msm_gpiomux_install(msm8930_cam_common_configs,
+			ARRAY_SIZE(msm8930_cam_common_configs));
+
+	if (machine_is_msm8930_cdp()) {
+		struct msm_camera_sensor_info *s_info;
+		s_info = &msm_camera_sensor_s5k3l1yx_data;
+		s_info->sensor_platform_info->mount_angle = 0;
+		msm_flash_src._fsrc.ext_driver_src.led_en =
+			GPIO_CAM_GP_LED_EN1;
+		msm_flash_src._fsrc.ext_driver_src.led_flash_en =
+			GPIO_CAM_GP_LED_EN2;
+#if defined(CONFIG_I2C) && (defined(CONFIG_GPIO_SX150X) || \
+	defined(CONFIG_GPIO_SX150X_MODULE))
+		msm_flash_src._fsrc.ext_driver_src.expander_info =
+			cam_expander_info;
+#endif
+	}
+
+	platform_device_register(&msm_camera_server);
+	platform_device_register(&msm8960_device_csiphy0);
+	platform_device_register(&msm8960_device_csiphy1);
+	platform_device_register(&msm8960_device_csid0);
+	platform_device_register(&msm8960_device_csid1);
+	platform_device_register(&msm8960_device_ispif);
+	platform_device_register(&msm8960_device_vfe);
+	platform_device_register(&msm8960_device_vpe);
+}
+
+#ifdef CONFIG_I2C
+struct i2c_board_info msm8930_camera_i2c_boardinfo[] = {
+	{
+	I2C_BOARD_INFO("imx074", 0x1A),
+	.platform_data = &msm_camera_sensor_imx074_data,
+	},
+	{
+	I2C_BOARD_INFO("ov2720", 0x6C),
+	.platform_data = &msm_camera_sensor_ov2720_data,
+	},
+	{
+	I2C_BOARD_INFO("mt9m114", 0x48),
+	.platform_data = &msm_camera_sensor_mt9m114_data,
+	},
+	{
+	I2C_BOARD_INFO("s5k3l1yx", 0x20),
+	.platform_data = &msm_camera_sensor_s5k3l1yx_data,
+	},
+	{
+	I2C_BOARD_INFO("tps61310", 0x66),
+	},
+};
+
+struct msm_camera_board_info msm8930_camera_board_info = {
+	.board_info = msm8930_camera_i2c_boardinfo,
+	.num_i2c_board_info = ARRAY_SIZE(msm8930_camera_i2c_boardinfo),
+};
+#endif
+#endif
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
new file mode 100644
index 0000000..e18e40d
--- /dev/null
+++ b/arch/arm/mach-msm/board-8930-display.c
@@ -0,0 +1,791 @@
+/* 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
+ * 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 <linux/gpio.h>
+#include <asm/mach-types.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_memtypes.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
+#include <mach/socinfo.h>
+#include <linux/ion.h>
+#include <mach/ion.h>
+
+#include "devices.h"
+#include "board-8930.h"
+
+#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
+#define MSM_FB_PRIM_BUF_SIZE \
+		(roundup((1920 * 1088 * 4), 4096) * 3) /* 4 bpp x 3 pages */
+#else
+#define MSM_FB_PRIM_BUF_SIZE \
+		(roundup((1920 * 1088 * 4), 4096) * 2) /* 4 bpp x 2 pages */
+#endif
+/* Note: must be multiple of 4096 */
+#define MSM_FB_SIZE roundup(MSM_FB_PRIM_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 */
+
+#define MDP_VSYNC_GPIO 0
+
+#define MIPI_CMD_NOVATEK_QHD_PANEL_NAME	"mipi_cmd_novatek_qhd"
+#define MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME	"mipi_video_novatek_qhd"
+#define MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME	"mipi_video_toshiba_wsvga"
+#define MIPI_VIDEO_CHIMEI_WXGA_PANEL_NAME	"mipi_video_chimei_wxga"
+#define MIPI_VIDEO_SIMULATOR_VGA_PANEL_NAME	"mipi_video_simulator_vga"
+#define MIPI_CMD_RENESAS_FWVGA_PANEL_NAME	"mipi_cmd_renesas_fwvga"
+#define HDMI_PANEL_NAME	"hdmi_msm"
+#define TVOUT_PANEL_NAME	"tvout_msm"
+
+static struct resource msm_fb_resources[] = {
+	{
+		.flags = IORESOURCE_DMA,
+	}
+};
+
+static int msm_fb_detect_panel(const char *name)
+{
+	if (!strncmp(name, MIPI_CMD_NOVATEK_QHD_PANEL_NAME,
+			strnlen(MIPI_CMD_NOVATEK_QHD_PANEL_NAME,
+				PANEL_NAME_MAX_LEN)))
+		return 0;
+
+#if !defined(CONFIG_FB_MSM_LVDS_MIPI_PANEL_DETECT) && \
+	!defined(CONFIG_FB_MSM_MIPI_PANEL_DETECT)
+	if (!strncmp(name, MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME,
+			strnlen(MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME,
+				PANEL_NAME_MAX_LEN)))
+		return 0;
+
+	if (!strncmp(name, MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME,
+			strnlen(MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME,
+				PANEL_NAME_MAX_LEN)))
+		return 0;
+
+	if (!strncmp(name, MIPI_VIDEO_SIMULATOR_VGA_PANEL_NAME,
+			strnlen(MIPI_VIDEO_SIMULATOR_VGA_PANEL_NAME,
+				PANEL_NAME_MAX_LEN)))
+		return 0;
+
+	if (!strncmp(name, MIPI_CMD_RENESAS_FWVGA_PANEL_NAME,
+			strnlen(MIPI_CMD_RENESAS_FWVGA_PANEL_NAME,
+				PANEL_NAME_MAX_LEN)))
+		return 0;
+#endif
+
+	if (!strncmp(name, HDMI_PANEL_NAME,
+			strnlen(HDMI_PANEL_NAME,
+				PANEL_NAME_MAX_LEN)))
+		return 0;
+
+	if (!strncmp(name, TVOUT_PANEL_NAME,
+			strnlen(TVOUT_PANEL_NAME,
+				PANEL_NAME_MAX_LEN)))
+		return 0;
+
+	pr_warning("%s: not supported '%s'", __func__, name);
+	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,
+};
+
+static bool dsi_power_on;
+
+/*
+ * TODO: When physical 8930/PM8038 hardware becomes
+ * available, replace mipi_dsi_cdp_panel_power with
+ * appropriate function.
+ */
+#define DISP_RST_GPIO 58
+static int mipi_dsi_cdp_panel_power(int on)
+{
+	static struct regulator *reg_l8, *reg_l23, *reg_l2;
+	int rc;
+
+	pr_debug("%s: state : %d\n", __func__, on);
+
+	if (!dsi_power_on) {
+
+		reg_l8 = regulator_get(&msm_mipi_dsi1_device.dev,
+				"dsi_vdc");
+		if (IS_ERR(reg_l8)) {
+			pr_err("could not get 8038_l8, rc = %ld\n",
+				PTR_ERR(reg_l8));
+			return -ENODEV;
+		}
+		reg_l23 = regulator_get(&msm_mipi_dsi1_device.dev,
+				"dsi_vddio");
+		if (IS_ERR(reg_l23)) {
+			pr_err("could not get 8038_l23, rc = %ld\n",
+				PTR_ERR(reg_l23));
+			return -ENODEV;
+		}
+		reg_l2 = regulator_get(&msm_mipi_dsi1_device.dev,
+				"dsi_vdda");
+		if (IS_ERR(reg_l2)) {
+			pr_err("could not get 8038_l2, rc = %ld\n",
+				PTR_ERR(reg_l2));
+			return -ENODEV;
+		}
+		rc = regulator_set_voltage(reg_l8, 2800000, 3000000);
+		if (rc) {
+			pr_err("set_voltage l8 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+		rc = regulator_set_voltage(reg_l23, 1800000, 1800000);
+		if (rc) {
+			pr_err("set_voltage l23 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+		rc = regulator_set_voltage(reg_l2, 1200000, 1200000);
+		if (rc) {
+			pr_err("set_voltage l2 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+		rc = gpio_request(DISP_RST_GPIO, "disp_rst_n");
+		if (rc) {
+			pr_err("request gpio DISP_RST_GPIO failed, rc=%d\n",
+				rc);
+			gpio_free(DISP_RST_GPIO);
+			return -ENODEV;
+		}
+		dsi_power_on = true;
+	}
+	if (on) {
+		rc = regulator_set_optimum_mode(reg_l8, 100000);
+		if (rc < 0) {
+			pr_err("set_optimum_mode l8 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+		rc = regulator_set_optimum_mode(reg_l23, 100000);
+		if (rc < 0) {
+			pr_err("set_optimum_mode l23 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+		rc = regulator_set_optimum_mode(reg_l2, 100000);
+		if (rc < 0) {
+			pr_err("set_optimum_mode l2 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+		rc = regulator_enable(reg_l8);
+		if (rc) {
+			pr_err("enable l8 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		rc = regulator_enable(reg_l23);
+		if (rc) {
+			pr_err("enable l8 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		rc = regulator_enable(reg_l2);
+		if (rc) {
+			pr_err("enable l2 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		usleep(10000);
+		gpio_set_value(DISP_RST_GPIO, 1);
+		usleep(10);
+		gpio_set_value(DISP_RST_GPIO, 0);
+		usleep(20);
+		gpio_set_value(DISP_RST_GPIO, 1);
+	} else {
+
+		gpio_set_value(DISP_RST_GPIO, 0);
+
+		rc = regulator_disable(reg_l2);
+		if (rc) {
+			pr_err("disable reg_l2 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		rc = regulator_disable(reg_l8);
+		if (rc) {
+			pr_err("disable reg_l8 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		rc = regulator_disable(reg_l23);
+		if (rc) {
+			pr_err("disable reg_l23 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		rc = regulator_set_optimum_mode(reg_l8, 100);
+		if (rc < 0) {
+			pr_err("set_optimum_mode l8 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+		rc = regulator_set_optimum_mode(reg_l23, 100);
+		if (rc < 0) {
+			pr_err("set_optimum_mode l23 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+		rc = regulator_set_optimum_mode(reg_l2, 100);
+		if (rc < 0) {
+			pr_err("set_optimum_mode l2 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+
+static int mipi_dsi_panel_power(int on)
+{
+	pr_debug("%s: on=%d\n", __func__, on);
+
+	return mipi_dsi_cdp_panel_power(on);
+}
+
+static struct mipi_dsi_platform_data mipi_dsi_pdata = {
+	.vsync_gpio = MDP_VSYNC_GPIO,
+	.dsi_power_save = mipi_dsi_panel_power,
+};
+
+#ifdef CONFIG_MSM_BUS_SCALING
+
+static struct msm_bus_vectors mdp_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+static struct msm_bus_vectors hdmi_as_primary_vectors[] = {
+	/* If HDMI is used as primary */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 2000000000,
+		.ib = 2000000000,
+	},
+};
+static struct msm_bus_paths mdp_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(mdp_init_vectors),
+		mdp_init_vectors,
+	},
+	{
+		ARRAY_SIZE(hdmi_as_primary_vectors),
+		hdmi_as_primary_vectors,
+	},
+	{
+		ARRAY_SIZE(hdmi_as_primary_vectors),
+		hdmi_as_primary_vectors,
+	},
+	{
+		ARRAY_SIZE(hdmi_as_primary_vectors),
+		hdmi_as_primary_vectors,
+	},
+	{
+		ARRAY_SIZE(hdmi_as_primary_vectors),
+		hdmi_as_primary_vectors,
+	},
+	{
+		ARRAY_SIZE(hdmi_as_primary_vectors),
+		hdmi_as_primary_vectors,
+	},
+};
+#else
+static struct msm_bus_vectors mdp_ui_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 216000000 * 2,
+		.ib = 270000000 * 2,
+	},
+};
+
+static struct msm_bus_vectors mdp_vga_vectors[] = {
+	/* VGA and less video */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 216000000 * 2,
+		.ib = 270000000 * 2,
+	},
+};
+
+static struct msm_bus_vectors mdp_720p_vectors[] = {
+	/* 720p and less video */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 230400000 * 2,
+		.ib = 288000000 * 2,
+	},
+};
+
+static struct msm_bus_vectors mdp_1080p_vectors[] = {
+	/* 1080p and less video */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 334080000 * 2,
+		.ib = 417600000 * 2,
+	},
+};
+
+static struct msm_bus_paths mdp_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(mdp_init_vectors),
+		mdp_init_vectors,
+	},
+	{
+		ARRAY_SIZE(mdp_ui_vectors),
+		mdp_ui_vectors,
+	},
+	{
+		ARRAY_SIZE(mdp_ui_vectors),
+		mdp_ui_vectors,
+	},
+	{
+		ARRAY_SIZE(mdp_vga_vectors),
+		mdp_vga_vectors,
+	},
+	{
+		ARRAY_SIZE(mdp_720p_vectors),
+		mdp_720p_vectors,
+	},
+	{
+		ARRAY_SIZE(mdp_1080p_vectors),
+		mdp_1080p_vectors,
+	},
+};
+#endif
+
+static struct msm_bus_scale_pdata mdp_bus_scale_pdata = {
+	mdp_bus_scale_usecases,
+	ARRAY_SIZE(mdp_bus_scale_usecases),
+	.name = "mdp",
+};
+
+#endif
+
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+static int mdp_core_clk_rate_table[] = {
+	200000000,
+	200000000,
+	200000000,
+	200000000,
+};
+#else
+static int mdp_core_clk_rate_table[] = {
+	85330000,
+	128000000,
+	160000000,
+	200000000,
+};
+#endif
+
+static struct msm_panel_common_pdata mdp_pdata = {
+	.gpio = MDP_VSYNC_GPIO,
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+	.mdp_core_clk_rate = 200000000,
+#else
+	.mdp_core_clk_rate = 85330000,
+#endif
+	.mdp_core_clk_table = mdp_core_clk_rate_table,
+	.num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
+#ifdef CONFIG_MSM_BUS_SCALING
+	.mdp_bus_scale_table = &mdp_bus_scale_pdata,
+#endif
+	.mdp_rev = MDP_REV_42,
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	.mem_hid = BIT(ION_CP_MM_HEAP_ID),
+#else
+	.mem_hid = MEMTYPE_EBI1,
+#endif
+};
+
+void __init msm8930_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
+}
+
+#define LPM_CHANNEL0 0
+static int toshiba_gpio[] = {LPM_CHANNEL0};
+
+static struct mipi_dsi_panel_platform_data toshiba_pdata = {
+	.gpio = toshiba_gpio,
+};
+
+static struct platform_device mipi_dsi_toshiba_panel_device = {
+	.name = "mipi_toshiba",
+	.id = 0,
+	.dev = {
+		.platform_data = &toshiba_pdata,
+	}
+};
+
+#define FPGA_3D_GPIO_CONFIG_ADDR	0xB5
+
+static struct mipi_dsi_phy_ctrl dsi_novatek_cmd_mode_phy_db = {
+
+/* DSI_BIT_CLK at 500MHz, 2 lane, RGB888 */
+	{0x0F, 0x0a, 0x04, 0x00, 0x20},	/* regulator */
+	/* timing   */
+	{0xab, 0x8a, 0x18, 0x00, 0x92, 0x97, 0x1b, 0x8c,
+	0x0c, 0x03, 0x04, 0xa0},
+	{0x5f, 0x00, 0x00, 0x10},	/* phy ctrl */
+	{0xff, 0x00, 0x06, 0x00},	/* strength */
+	/* pll control */
+	{0x40, 0xf9, 0x30, 0xda, 0x00, 0x40, 0x03, 0x62,
+	0x40, 0x07, 0x03,
+	0x00, 0x1a, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0x01},
+};
+
+static struct mipi_dsi_panel_platform_data novatek_pdata = {
+	.fpga_3d_config_addr  = FPGA_3D_GPIO_CONFIG_ADDR,
+	.fpga_ctrl_mode = FPGA_SPI_INTF,
+	.phy_ctrl_settings = &dsi_novatek_cmd_mode_phy_db,
+	.dlane_swap = 0x1,
+	.enable_wled_bl_ctrl = 0x1,
+};
+
+static struct platform_device mipi_dsi_novatek_panel_device = {
+	.name = "mipi_novatek",
+	.id = 0,
+	.dev = {
+		.platform_data = &novatek_pdata,
+	}
+};
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+static struct resource hdmi_msm_resources[] = {
+	{
+		.name  = "hdmi_msm_qfprom_addr",
+		.start = 0x00700000,
+		.end   = 0x007060FF,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name  = "hdmi_msm_hdmi_addr",
+		.start = 0x04A00000,
+		.end   = 0x04A00FFF,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name  = "hdmi_msm_irq",
+		.start = HDMI_IRQ,
+		.end   = HDMI_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static int hdmi_enable_5v(int on);
+static int hdmi_core_power(int on, int show);
+static int hdmi_cec_power(int on);
+
+static struct msm_hdmi_platform_data hdmi_msm_data = {
+	.irq = HDMI_IRQ,
+	.enable_5v = hdmi_enable_5v,
+	.core_power = hdmi_core_power,
+	.cec_power = hdmi_cec_power,
+};
+
+static struct platform_device hdmi_msm_device = {
+	.name = "hdmi_msm",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(hdmi_msm_resources),
+	.resource = hdmi_msm_resources,
+	.dev.platform_data = &hdmi_msm_data,
+};
+#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL */
+
+#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
+static struct platform_device wfd_panel_device = {
+	.name = "wfd_panel",
+	.id = 0,
+	.dev.platform_data = NULL,
+};
+
+static struct platform_device wfd_device = {
+	.name          = "msm_wfd",
+	.id            = -1,
+};
+#endif
+
+#ifdef CONFIG_MSM_BUS_SCALING
+static struct msm_bus_vectors dtv_bus_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+static struct msm_bus_vectors dtv_bus_def_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 2000000000,
+		.ib = 2000000000,
+	},
+};
+#else
+static struct msm_bus_vectors dtv_bus_def_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 566092800 * 2,
+		.ib = 707616000 * 2,
+	},
+};
+#endif
+
+static struct msm_bus_paths dtv_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(dtv_bus_init_vectors),
+		dtv_bus_init_vectors,
+	},
+	{
+		ARRAY_SIZE(dtv_bus_def_vectors),
+		dtv_bus_def_vectors,
+	},
+};
+static struct msm_bus_scale_pdata dtv_bus_scale_pdata = {
+	dtv_bus_scale_usecases,
+	ARRAY_SIZE(dtv_bus_scale_usecases),
+	.name = "dtv",
+};
+
+static struct lcdc_platform_data dtv_pdata = {
+	.bus_scale_table = &dtv_bus_scale_pdata,
+};
+#endif
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+static int hdmi_enable_5v(int on)
+{
+	static struct regulator *reg_ext_5v;	/* HDMI_5V */
+	static int prev_on;
+	int rc;
+
+	if (on == prev_on)
+		return 0;
+
+	if (!reg_ext_5v) {
+		reg_ext_5v = regulator_get(&hdmi_msm_device.dev, "hdmi_mvs");
+		if (IS_ERR(reg_ext_5v)) {
+			pr_err("'%s' regulator not found, rc=%ld\n",
+				"hdmi_mvs", IS_ERR(reg_ext_5v));
+			reg_ext_5v = NULL;
+			return -ENODEV;
+		}
+	}
+
+	if (on) {
+		rc = regulator_enable(reg_ext_5v);
+		if (rc) {
+			pr_err("'%s' regulator enable failed, rc=%d\n",
+				"reg_ext_5v", rc);
+			return rc;
+		}
+		pr_debug("%s(on): success\n", __func__);
+	} else {
+		rc = regulator_disable(reg_ext_5v);
+		if (rc)
+			pr_warning("'%s' regulator disable failed, rc=%d\n",
+				"reg_ext_5v", rc);
+		pr_debug("%s(off): success\n", __func__);
+	}
+
+	prev_on = on;
+
+	return 0;
+}
+
+static int hdmi_core_power(int on, int show)
+{
+	/* Both HDMI "avdd" and "vcc" are powered by 8038_l23 regulator */
+	static struct regulator *reg_8038_l23;
+	static int prev_on;
+	int rc;
+
+	if (on == prev_on)
+		return 0;
+
+	if (!reg_8038_l23) {
+		reg_8038_l23 = regulator_get(&hdmi_msm_device.dev, "hdmi_avdd");
+		if (IS_ERR(reg_8038_l23)) {
+			pr_err("could not get reg_8038_l23, rc = %ld\n",
+				PTR_ERR(reg_8038_l23));
+			return -ENODEV;
+		}
+		rc = regulator_set_voltage(reg_8038_l23, 1800000, 1800000);
+		if (rc) {
+			pr_err("set_voltage failed for 8921_l23, rc=%d\n", rc);
+			return -EINVAL;
+		}
+	}
+
+	if (on) {
+		rc = regulator_set_optimum_mode(reg_8038_l23, 100000);
+		if (rc < 0) {
+			pr_err("set_optimum_mode l23 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+		rc = regulator_enable(reg_8038_l23);
+		if (rc) {
+			pr_err("'%s' regulator enable failed, rc=%d\n",
+				"hdmi_avdd", rc);
+			return rc;
+		}
+		rc = gpio_request(100, "HDMI_DDC_CLK");
+		if (rc) {
+			pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+				"HDMI_DDC_CLK", 100, rc);
+			goto error1;
+		}
+		rc = gpio_request(101, "HDMI_DDC_DATA");
+		if (rc) {
+			pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+				"HDMI_DDC_DATA", 101, rc);
+			goto error2;
+		}
+		rc = gpio_request(102, "HDMI_HPD");
+		if (rc) {
+			pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+				"HDMI_HPD", 102, rc);
+			goto error3;
+		}
+		pr_debug("%s(on): success\n", __func__);
+	} else {
+		gpio_free(100);
+		gpio_free(101);
+		gpio_free(102);
+
+		rc = regulator_disable(reg_8038_l23);
+		if (rc) {
+			pr_err("disable reg_8038_l23 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		rc = regulator_set_optimum_mode(reg_8038_l23, 100);
+		if (rc < 0) {
+			pr_err("set_optimum_mode l23 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+		pr_debug("%s(off): success\n", __func__);
+	}
+
+	prev_on = on;
+
+	return 0;
+
+error3:
+	gpio_free(101);
+error2:
+	gpio_free(100);
+error1:
+	regulator_disable(reg_8038_l23);
+	return rc;
+}
+
+static int hdmi_cec_power(int on)
+{
+	static int prev_on;
+	int rc;
+
+	if (on == prev_on)
+		return 0;
+
+	if (on) {
+		rc = gpio_request(99, "HDMI_CEC_VAR");
+		if (rc) {
+			pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+				"HDMI_CEC_VAR", 99, rc);
+			goto error;
+		}
+		pr_debug("%s(on): success\n", __func__);
+	} else {
+		gpio_free(99);
+		pr_debug("%s(off): success\n", __func__);
+	}
+
+	prev_on = on;
+
+	return 0;
+error:
+	return rc;
+}
+#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL */
+
+void __init msm8930_init_fb(void)
+{
+	platform_device_register(&msm_fb_device);
+
+#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
+	platform_device_register(&wfd_panel_device);
+	platform_device_register(&wfd_device);
+#endif
+
+	platform_device_register(&mipi_dsi_novatek_panel_device);
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+	platform_device_register(&hdmi_msm_device);
+#endif
+
+	platform_device_register(&mipi_dsi_toshiba_panel_device);
+
+	msm_fb_register_device("mdp", &mdp_pdata);
+	msm_fb_register_device("mipi_dsi", &mipi_dsi_pdata);
+#ifdef CONFIG_MSM_BUS_SCALING
+	msm_fb_register_device("dtv", &dtv_pdata);
+#endif
+}
+
+void __init msm8930_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));
+}
diff --git a/arch/arm/mach-msm/board-8930-gpiomux.c b/arch/arm/mach-msm/board-8930-gpiomux.c
new file mode 100644
index 0000000..c7ab260
--- /dev/null
+++ b/arch/arm/mach-msm/board-8930-gpiomux.c
@@ -0,0 +1,691 @@
+/* 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
+ * 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/gpio.h>
+#include <asm/mach-types.h>
+#include <mach/gpiomux.h>
+#include <mach/socinfo.h>
+#include "devices.h"
+#include "board-8930.h"
+
+/* The SPI configurations apply to GSBI 1*/
+static struct gpiomux_setting spi_active = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_12MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting spi_suspended_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting gsbi3_suspended_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_KEEPER,
+};
+
+static struct gpiomux_setting gsbi3_active_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi5 = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi9 = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi10 = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi12 = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting cdc_mclk = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting audio_auxpcm[] = {
+	/* Suspended state */
+	{
+		.func = GPIOMUX_FUNC_GPIO,
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+	/* Active state */
+	{
+		.func = GPIOMUX_FUNC_1,
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+};
+
+static struct gpiomux_setting audio_mbhc = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting audio_spkr_boost = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+static struct gpiomux_setting gpio_eth_config = {
+	.pull = GPIOMUX_PULL_NONE,
+	.drv = GPIOMUX_DRV_8MA,
+	.func = GPIOMUX_FUNC_GPIO,
+};
+#endif
+
+static struct gpiomux_setting slimbus = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_KEEPER,
+};
+
+static struct gpiomux_setting wcnss_5wire_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv  = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting wcnss_5wire_active_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv  = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting atmel_resout_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting atmel_resout_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting atmel_ldo_en_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting atmel_ldo_en_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting atmel_int_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting atmel_int_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+#ifdef MSM8930_PHASE_2
+static struct gpiomux_setting hsusb_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_OUT_LOW,
+};
+static struct msm_gpiomux_config msm8930_hsusb_configs[] = {
+	{
+		.gpio = 63,     /* HSUSB_EXTERNAL_5V_LDO_EN */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &hsusb_sus_cfg,
+		},
+	},
+	{
+		.gpio = 97,     /* HSUSB_5V_EN */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &hsusb_sus_cfg,
+		},
+	},
+};
+#endif
+
+static struct gpiomux_setting hap_lvl_shft_suspended_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting hap_lvl_shft_active_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting ap2mdm_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting mdm2ap_status_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting mdm2ap_errfatal_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_16MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting ap2mdm_kpdpwr_n_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting mdp_vsync_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting mdp_vsync_active_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+static struct gpiomux_setting hdmi_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting hdmi_active_1_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting hdmi_active_2_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+#endif
+
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+static struct msm_gpiomux_config msm8960_ethernet_configs[] = {
+	{
+		.gpio = 90,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_eth_config,
+		}
+	},
+	{
+		.gpio = 89,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_eth_config,
+		}
+	},
+};
+#endif
+
+static struct msm_gpiomux_config msm8960_gsbi_configs[] __initdata = {
+	{
+		.gpio      = 6,		/* GSBI1 QUP SPI_DATA_MOSI */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &spi_suspended_config,
+			[GPIOMUX_ACTIVE] = &spi_active,
+		},
+	},
+	{
+		.gpio      = 7,		/* GSBI1 QUP SPI_DATA_MISO */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &spi_suspended_config,
+			[GPIOMUX_ACTIVE] = &spi_active,
+		},
+	},
+	{
+		.gpio      = 8,		/* GSBI1 QUP SPI_CS_N */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &spi_suspended_config,
+			[GPIOMUX_ACTIVE] = &spi_active,
+		},
+	},
+	{
+		.gpio      = 9,		/* GSBI1 QUP SPI_CLK */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &spi_suspended_config,
+			[GPIOMUX_ACTIVE] = &spi_active,
+		},
+	},
+	{
+		.gpio      = 16,	/* GSBI3 I2C QUP SDA */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi3_suspended_cfg,
+			[GPIOMUX_ACTIVE] = &gsbi3_active_cfg,
+		},
+	},
+	{
+		.gpio      = 17,	/* GSBI3 I2C QUP SCL */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi3_suspended_cfg,
+			[GPIOMUX_ACTIVE] = &gsbi3_active_cfg,
+		},
+	},
+	{
+		.gpio      = 22,	/* GSBI5 UART2 */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi5,
+		},
+	},
+	{
+		.gpio      = 23,	/* GSBI5 UART2 */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi5,
+		},
+	},
+	{
+		.gpio      = 44,	/* GSBI12 I2C QUP SDA */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi12,
+		},
+	},
+	{
+		.gpio      = 95,	/* GSBI9 I2C QUP SDA */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi9,
+		},
+	},
+	{
+		.gpio      = 96,	/* GSBI12 I2C QUP SCL */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi9,
+		},
+	},
+	{
+		.gpio      = 45,	/* GSBI12 I2C QUP SCL */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi12,
+		},
+	},
+	{
+		.gpio      = 73,	/* GSBI10 I2C QUP SDA */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi10,
+		},
+	},
+	{
+		.gpio      = 74,	/* GSBI10 I2C QUP SCL */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi10,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8960_slimbus_config[] __initdata = {
+	{
+		.gpio	= 60,		/* slimbus data */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &slimbus,
+		},
+	},
+	{
+		.gpio	= 61,		/* slimbus clk */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &slimbus,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8960_audio_codec_configs[] __initdata = {
+	{
+		.gpio = 59,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &cdc_mclk,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8960_audio_mbhc_configs[] __initdata = {
+	{
+		.gpio = 37,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &audio_mbhc,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8960_audio_spkr_configs[] __initdata = {
+	{
+		.gpio = 15,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &audio_spkr_boost,
+		},
+	},
+};
+
+
+static struct msm_gpiomux_config msm8960_audio_auxpcm_configs[] __initdata = {
+	{
+		.gpio = 63,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+			[GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+		},
+	},
+	{
+		.gpio = 64,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+			[GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+		},
+	},
+	{
+		.gpio = 65,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+			[GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+		},
+	},
+	{
+		.gpio = 66,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+			[GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+		},
+	},
+};
+
+static struct msm_gpiomux_config wcnss_5wire_interface[] = {
+	{
+		.gpio = 84,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5wire_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 85,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5wire_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 86,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5wire_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 87,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5wire_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 88,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5wire_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8960_atmel_configs[] __initdata = {
+	{	/* TS INTERRUPT */
+		.gpio = 11,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &atmel_int_act_cfg,
+			[GPIOMUX_SUSPENDED] = &atmel_int_sus_cfg,
+		},
+	},
+	{	/* TS LDO ENABLE */
+		.gpio = 50,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &atmel_ldo_en_act_cfg,
+			[GPIOMUX_SUSPENDED] = &atmel_ldo_en_sus_cfg,
+		},
+	},
+	{	/* TS RESOUT */
+		.gpio = 52,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &atmel_resout_act_cfg,
+			[GPIOMUX_SUSPENDED] = &atmel_resout_sus_cfg,
+		},
+	},
+};
+
+static struct msm_gpiomux_config hap_lvl_shft_config[] __initdata = {
+	{
+		.gpio = 47,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &hap_lvl_shft_suspended_config,
+			[GPIOMUX_ACTIVE] = &hap_lvl_shft_active_config,
+		},
+	},
+};
+
+static struct msm_gpiomux_config mdm_configs[] __initdata = {
+	/* AP2MDM_STATUS */
+	{
+		.gpio = 94,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
+		}
+	},
+	/* MDM2AP_STATUS */
+	{
+		.gpio = 69,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &mdm2ap_status_cfg,
+		}
+	},
+	/* MDM2AP_ERRFATAL */
+	{
+		.gpio = 70,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &mdm2ap_errfatal_cfg,
+		}
+	},
+	/* AP2MDM_ERRFATAL */
+	{
+		.gpio = 95,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
+		}
+	},
+	/* AP2MDM_KPDPWR_N */
+	{
+		.gpio = 81,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_kpdpwr_n_cfg,
+		}
+	},
+	/* AP2MDM_PMIC_RESET_N */
+	{
+		.gpio = 80,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_kpdpwr_n_cfg,
+		}
+	}
+};
+
+static struct msm_gpiomux_config msm8960_mdp_vsync_configs[] __initdata = {
+	{
+		.gpio = 0,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &mdp_vsync_active_cfg,
+			[GPIOMUX_SUSPENDED] = &mdp_vsync_suspend_cfg,
+		},
+	}
+};
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+static struct msm_gpiomux_config msm8960_hdmi_configs[] __initdata = {
+	{
+		.gpio = 99,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_1_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 100,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_1_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 101,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_1_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 102,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_2_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+};
+#endif
+
+static struct gpiomux_setting haptics_active_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+static struct gpiomux_setting haptics_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct msm_gpiomux_config msm8930_haptics_configs[] __initdata = {
+	{
+		.gpio = 77,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &haptics_active_cfg,
+			[GPIOMUX_SUSPENDED] = &haptics_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 78,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &haptics_active_cfg,
+			[GPIOMUX_SUSPENDED] = &haptics_suspend_cfg,
+		},
+	},
+};
+
+int __init msm8930_init_gpiomux(void)
+{
+	int rc = msm_gpiomux_init(NR_GPIO_IRQS);
+	if (rc) {
+		pr_err(KERN_ERR "msm_gpiomux_init failed %d\n", rc);
+		return rc;
+	}
+
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+	msm_gpiomux_install(msm8960_ethernet_configs,
+			ARRAY_SIZE(msm8960_ethernet_configs));
+#endif
+
+	msm_gpiomux_install(msm8960_gsbi_configs,
+			ARRAY_SIZE(msm8960_gsbi_configs));
+
+	msm_gpiomux_install(msm8960_atmel_configs,
+			ARRAY_SIZE(msm8960_atmel_configs));
+
+	msm_gpiomux_install(msm8960_slimbus_config,
+			ARRAY_SIZE(msm8960_slimbus_config));
+
+	msm_gpiomux_install(msm8960_audio_codec_configs,
+			ARRAY_SIZE(msm8960_audio_codec_configs));
+
+	msm_gpiomux_install(msm8960_audio_mbhc_configs,
+			ARRAY_SIZE(msm8960_audio_mbhc_configs));
+
+	msm_gpiomux_install(msm8960_audio_spkr_configs,
+			ARRAY_SIZE(msm8960_audio_spkr_configs));
+
+	msm_gpiomux_install(msm8960_audio_auxpcm_configs,
+			ARRAY_SIZE(msm8960_audio_auxpcm_configs));
+
+	msm_gpiomux_install(wcnss_5wire_interface,
+			ARRAY_SIZE(wcnss_5wire_interface));
+
+	if (machine_is_msm8930_mtp() || machine_is_msm8930_fluid() ||
+		machine_is_msm8930_cdp()) {
+		msm_gpiomux_install(hap_lvl_shft_config,
+			ARRAY_SIZE(hap_lvl_shft_config));
+#ifdef MSM8930_PHASE_2
+		msm_gpiomux_install(msm8930_hsusb_configs,
+			ARRAY_SIZE(msm8930_hsusb_configs));
+#endif
+	}
+
+	if (PLATFORM_IS_CHARM25())
+		msm_gpiomux_install(mdm_configs,
+			ARRAY_SIZE(mdm_configs));
+
+	if (machine_is_msm8930_cdp() || machine_is_msm8930_mtp()
+		|| machine_is_msm8930_fluid())
+		msm_gpiomux_install(msm8930_haptics_configs,
+			ARRAY_SIZE(msm8930_haptics_configs));
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+	msm_gpiomux_install(msm8960_hdmi_configs,
+			ARRAY_SIZE(msm8960_hdmi_configs));
+#endif
+
+	msm_gpiomux_install(msm8960_mdp_vsync_configs,
+			ARRAY_SIZE(msm8960_mdp_vsync_configs));
+	return 0;
+}
diff --git a/arch/arm/mach-msm/board-8930-gpu.c b/arch/arm/mach-msm/board-8930-gpu.c
new file mode 100644
index 0000000..3c3843a
--- /dev/null
+++ b/arch/arm/mach-msm/board-8930-gpu.c
@@ -0,0 +1,163 @@
+/* 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/platform_device.h>
+#include <linux/msm_kgsl.h>
+#include <mach/msm_bus_board.h>
+#include <mach/board.h>
+
+#include "devices.h"
+#include "board-8930.h"
+
+#ifdef CONFIG_MSM_BUS_SCALING
+static struct msm_bus_vectors grp3d_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+static struct msm_bus_vectors grp3d_low_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(2000),
+	},
+};
+
+static struct msm_bus_vectors grp3d_nominal_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(3200),
+	},
+};
+
+static struct msm_bus_vectors grp3d_max_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(4264),
+	},
+};
+
+static struct msm_bus_paths grp3d_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(grp3d_init_vectors),
+		grp3d_init_vectors,
+	},
+	{
+		ARRAY_SIZE(grp3d_low_vectors),
+		grp3d_low_vectors,
+	},
+	{
+		ARRAY_SIZE(grp3d_nominal_vectors),
+		grp3d_nominal_vectors,
+	},
+	{
+		ARRAY_SIZE(grp3d_max_vectors),
+		grp3d_max_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata grp3d_bus_scale_pdata = {
+	grp3d_bus_scale_usecases,
+	ARRAY_SIZE(grp3d_bus_scale_usecases),
+	.name = "grp3d",
+};
+#endif
+
+static struct resource kgsl_3d0_resources[] = {
+	{
+		.name = KGSL_3D0_REG_MEMORY,
+		.start = 0x04300000, /* GFX3D address */
+		.end = 0x0431ffff,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = KGSL_3D0_IRQ,
+		.start = GFX3D_IRQ,
+		.end = GFX3D_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static const struct kgsl_iommu_ctx kgsl_3d0_iommu0_ctxs[] = {
+	{ "gfx3d_user", 0 },
+	{ "gfx3d_priv", 1 },
+};
+
+static struct kgsl_device_iommu_data kgsl_3d0_iommu_data[] = {
+	{
+		.iommu_ctxs = kgsl_3d0_iommu0_ctxs,
+		.iommu_ctx_count = ARRAY_SIZE(kgsl_3d0_iommu0_ctxs),
+		.physstart = 0x07C00000,
+		.physend = 0x07C00000 + SZ_1M - 1,
+	},
+};
+
+static struct kgsl_device_platform_data kgsl_3d0_pdata = {
+	.pwrlevel = {
+		{
+			.gpu_freq = 450000000,
+			.bus_freq = 3,
+			.io_fraction = 0,
+		},
+		{
+			.gpu_freq = 320000000,
+			.bus_freq = 2,
+			.io_fraction = 33,
+		},
+		{
+			.gpu_freq = 192000000,
+			.bus_freq = 1,
+			.io_fraction = 100,
+		},
+		{
+			.gpu_freq = 27000000,
+			.bus_freq = 0,
+		},
+	},
+	.init_level = 0,
+	.num_levels = 4,
+	.set_grp_async = NULL,
+	.idle_timeout = HZ/12,
+	.nap_allowed = true,
+	.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM_IFACE,
+#ifdef CONFIG_MSM_BUS_SCALING
+	.bus_scale_table = &grp3d_bus_scale_pdata,
+#endif
+	.iommu_data = kgsl_3d0_iommu_data,
+	.iommu_count = ARRAY_SIZE(kgsl_3d0_iommu_data),
+};
+
+static struct platform_device device_kgsl_3d0 = {
+	.name = "kgsl-3d0",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(kgsl_3d0_resources),
+	.resource = kgsl_3d0_resources,
+	.dev = {
+		.platform_data = &kgsl_3d0_pdata,
+	},
+};
+
+void __init msm8930_init_gpu(void)
+{
+	platform_device_register(&device_kgsl_3d0);
+}
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
new file mode 100644
index 0000000..cf7a829
--- /dev/null
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -0,0 +1,380 @@
+/* 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
+ * 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/interrupt.h>
+#include <linux/mfd/pm8xxx/pm8038.h>
+#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
+#include <linux/msm_ssbi.h>
+#include <asm/mach-types.h>
+#include <mach/msm_bus_board.h>
+#include <mach/restart.h>
+#include "devices.h"
+#include "board-8930.h"
+
+struct pm8xxx_gpio_init {
+	unsigned			gpio;
+	struct pm_gpio			config;
+};
+
+struct pm8xxx_mpp_init {
+	unsigned			mpp;
+	struct pm8xxx_mpp_config_data	config;
+};
+
+#define PM8XXX_GPIO_INIT(_gpio, _dir, _buf, _val, _pull, _vin, _out_strength, \
+			_func, _inv, _disable) \
+{ \
+	.gpio	= PM8038_GPIO_PM_TO_SYS(_gpio), \
+	.config	= { \
+		.direction	= _dir, \
+		.output_buffer	= _buf, \
+		.output_value	= _val, \
+		.pull		= _pull, \
+		.vin_sel	= _vin, \
+		.out_strength	= _out_strength, \
+		.function	= _func, \
+		.inv_int_pol	= _inv, \
+		.disable_pin	= _disable, \
+	} \
+}
+
+#define PM8XXX_MPP_INIT(_mpp, _type, _level, _control) \
+{ \
+	.mpp	= PM8038_MPP_PM_TO_SYS(_mpp), \
+	.config	= { \
+		.type		= PM8XXX_MPP_TYPE_##_type, \
+		.level		= _level, \
+		.control	= PM8XXX_MPP_##_control, \
+	} \
+}
+
+#define PM8XXX_GPIO_DISABLE(_gpio) \
+	PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, 0, 0, 0, PM8038_GPIO_VIN_L11, \
+			 0, 0, 0, 1)
+
+#define PM8XXX_GPIO_OUTPUT(_gpio, _val) \
+	PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+			PM_GPIO_PULL_NO, PM8038_GPIO_VIN_L11, \
+			PM_GPIO_STRENGTH_HIGH, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
+#define PM8XXX_GPIO_INPUT(_gpio, _pull) \
+	PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, PM_GPIO_OUT_BUF_CMOS, 0, \
+			_pull, PM8038_GPIO_VIN_L11, \
+			PM_GPIO_STRENGTH_NO, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
+#define PM8XXX_GPIO_OUTPUT_FUNC(_gpio, _val, _func) \
+	PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+			PM_GPIO_PULL_NO, PM8038_GPIO_VIN_L11, \
+			PM_GPIO_STRENGTH_HIGH, \
+			_func, 0, 0)
+
+#define PM8XXX_GPIO_OUTPUT_VIN(_gpio, _val, _vin) \
+	PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+			PM_GPIO_PULL_NO, _vin, \
+			PM_GPIO_STRENGTH_HIGH, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
+/* Initial pm8038 GPIO configurations */
+static struct pm8xxx_gpio_init pm8038_gpios[] __initdata = {
+	/* keys GPIOs */
+	PM8XXX_GPIO_INPUT(3, PM_GPIO_PULL_UP_30),
+	PM8XXX_GPIO_INPUT(8, PM_GPIO_PULL_UP_30),
+	PM8XXX_GPIO_INPUT(10, PM_GPIO_PULL_UP_30),
+	PM8XXX_GPIO_INPUT(11, PM_GPIO_PULL_UP_30),
+	/* haptics gpio */
+	PM8XXX_GPIO_OUTPUT_FUNC(7, 0, PM_GPIO_FUNC_1),
+};
+
+/* Initial pm8038 MPP configurations */
+static struct pm8xxx_mpp_init pm8038_mpps[] __initdata = {
+	/* External 5V regulator enable; shared by HDMI and USB_OTG switches. */
+	PM8XXX_MPP_INIT(3, D_INPUT, PM8038_MPP_DIG_LEVEL_VPH, DIN_TO_INT),
+};
+
+void __init msm8930_pm8038_gpio_mpp_init(void)
+{
+	int i, rc;
+
+	for (i = 0; i < ARRAY_SIZE(pm8038_gpios); i++) {
+		rc = pm8xxx_gpio_config(pm8038_gpios[i].gpio,
+					&pm8038_gpios[i].config);
+		if (rc) {
+			pr_err("%s: pm8xxx_gpio_config: rc=%d\n", __func__, rc);
+			break;
+		}
+	}
+
+	/* Initial MPP configuration. */
+	for (i = 0; i < ARRAY_SIZE(pm8038_mpps); i++) {
+		rc = pm8xxx_mpp_config(pm8038_mpps[i].mpp,
+					&pm8038_mpps[i].config);
+		if (rc) {
+			pr_err("%s: pm8xxx_mpp_config: rc=%d\n", __func__, rc);
+			break;
+		}
+	}
+}
+
+static struct pm8xxx_adc_amux pm8xxx_adc_channels_data[] = {
+	{"vcoin", CHANNEL_VCOIN, CHAN_PATH_SCALING2, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"vbat", CHANNEL_VBAT, CHAN_PATH_SCALING2, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"dcin", CHANNEL_DCIN, CHAN_PATH_SCALING4, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"ichg", CHANNEL_ICHG, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"vph_pwr", CHANNEL_VPH_PWR, CHAN_PATH_SCALING2, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"ibat", CHANNEL_IBAT, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"batt_therm", CHANNEL_BATT_THERM, CHAN_PATH_SCALING1, AMUX_RSV2,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_BATT_THERM},
+	{"batt_id", CHANNEL_BATT_ID, CHAN_PATH_SCALING1, AMUX_RSV2,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"usbin", CHANNEL_USBIN, CHAN_PATH_SCALING3, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"pmic_therm", CHANNEL_DIE_TEMP, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_PMIC_THERM},
+	{"625mv", CHANNEL_625MV, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"125v", CHANNEL_125V, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"chg_temp", CHANNEL_CHG_TEMP, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"pa_therm1", ADC_MPP_1_AMUX4, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_PA_THERM},
+	{"xo_therm", CHANNEL_MUXOFF, CHAN_PATH_SCALING1, AMUX_RSV0,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_XOTHERM},
+	{"pa_therm0", ADC_MPP_1_AMUX3, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_PA_THERM},
+};
+
+static struct pm8xxx_adc_properties pm8xxx_adc_data = {
+	.adc_vdd_reference	= 1800, /* milli-voltage for this adc */
+	.bitresolution		= 15,
+	.bipolar                = 0,
+};
+
+static struct pm8xxx_adc_platform_data pm8xxx_adc_pdata = {
+	.adc_channel            = pm8xxx_adc_channels_data,
+	.adc_num_board_channel  = ARRAY_SIZE(pm8xxx_adc_channels_data),
+	.adc_prop               = &pm8xxx_adc_data,
+	.adc_mpp_base		= PM8038_MPP_PM_TO_SYS(1),
+};
+
+static struct pm8xxx_irq_platform_data pm8xxx_irq_pdata __devinitdata = {
+	.irq_base		= PM8038_IRQ_BASE,
+	.devirq			= MSM_GPIO_TO_INT(104),
+	.irq_trigger_flag	= IRQF_TRIGGER_LOW,
+};
+
+static struct pm8xxx_gpio_platform_data pm8xxx_gpio_pdata __devinitdata = {
+	.gpio_base	= PM8038_GPIO_PM_TO_SYS(1),
+};
+
+static struct pm8xxx_mpp_platform_data pm8xxx_mpp_pdata __devinitdata = {
+	.mpp_base	= PM8038_MPP_PM_TO_SYS(1),
+};
+
+static struct pm8xxx_rtc_platform_data pm8xxx_rtc_pdata __devinitdata = {
+	.rtc_write_enable	= false,
+	.rtc_alarm_powerup	= false,
+};
+
+static struct pm8xxx_pwrkey_platform_data pm8xxx_pwrkey_pdata = {
+	.pull_up		= 1,
+	.kpd_trigger_delay_us	= 15625,
+	.wakeup			= 1,
+};
+
+static int pm8921_therm_mitigation[] = {
+	1100,
+	700,
+	600,
+	325,
+};
+
+#define MAX_VOLTAGE_MV		4200
+static struct pm8921_charger_platform_data pm8921_chg_pdata __devinitdata = {
+	.safety_time		= 180,
+	.update_time		= 60000,
+	.max_voltage		= MAX_VOLTAGE_MV,
+	.min_voltage		= 3200,
+	.resume_voltage_delta	= 100,
+	.term_current		= 100,
+	.cool_temp		= 10,
+	.warm_temp		= 40,
+	.temp_check_period	= 1,
+	.max_bat_chg_current	= 1100,
+	.cool_bat_chg_current	= 350,
+	.warm_bat_chg_current	= 350,
+	.cool_bat_voltage	= 4100,
+	.warm_bat_voltage	= 4100,
+	.thermal_mitigation	= pm8921_therm_mitigation,
+	.thermal_levels		= ARRAY_SIZE(pm8921_therm_mitigation),
+	.led_src_config		= LED_SRC_VPH_PWR,
+};
+
+#define PM8038_WLED_MAX_CURRENT		25
+#define PM8XXX_LED_PWM_PERIOD		1000
+#define PM8XXX_LED_PWM_DUTY_MS		20
+#define PM8038_RGB_LED_MAX_CURRENT	12
+
+static struct led_info pm8038_led_info[] = {
+	[0] = {
+		.name			= "wled",
+		.default_trigger	= "bkl_trigger",
+	},
+	[1] = {
+		.name			= "led:rgb_red",
+		.default_trigger	= "battery-charging",
+	},
+	[2] = {
+		.name			= "led:rgb_green",
+	},
+	[3] = {
+		.name			= "led:rgb_blue",
+	},
+};
+
+static struct led_platform_data pm8038_led_core_pdata = {
+	.num_leds = ARRAY_SIZE(pm8038_led_info),
+	.leds = pm8038_led_info,
+};
+
+static struct wled_config_data wled_cfg = {
+	.dig_mod_gen_en = true,
+	.cs_out_en = true,
+	.ctrl_delay_us = 0,
+	.op_fdbck = true,
+	.ovp_val = WLED_OVP_32V,
+	.boost_curr_lim = WLED_CURR_LIMIT_525mA,
+	.num_strings = 1,
+};
+
+static int pm8038_led0_pwm_duty_pcts[56] = {
+		1, 4, 8, 12, 16, 20, 24, 28, 32, 36,
+		40, 44, 46, 52, 56, 60, 64, 68, 72, 76,
+		80, 84, 88, 92, 96, 100, 100, 100, 98, 95,
+		92, 88, 84, 82, 78, 74, 70, 66, 62, 58,
+		58, 54, 50, 48, 42, 38, 34, 30, 26, 22,
+		14, 10, 6, 4, 1
+};
+
+static struct pm8xxx_pwm_duty_cycles pm8038_led0_pwm_duty_cycles = {
+	.duty_pcts = (int *)&pm8038_led0_pwm_duty_pcts,
+	.num_duty_pcts = ARRAY_SIZE(pm8038_led0_pwm_duty_pcts),
+	.duty_ms = PM8XXX_LED_PWM_DUTY_MS,
+	.start_idx = 0,
+};
+
+static struct pm8xxx_led_config pm8038_led_configs[] = {
+	[0] = {
+		.id = PM8XXX_ID_WLED,
+		.mode = PM8XXX_LED_MODE_MANUAL,
+		.max_current = PM8038_WLED_MAX_CURRENT,
+		.default_state = 0,
+		.wled_cfg = &wled_cfg,
+	},
+	[1] = {
+		.id = PM8XXX_ID_RGB_LED_RED,
+		.mode = PM8XXX_LED_MODE_PWM1,
+		.max_current = PM8038_RGB_LED_MAX_CURRENT,
+		.pwm_channel = 5,
+		.pwm_period_us = PM8XXX_LED_PWM_PERIOD,
+		.pwm_duty_cycles = &pm8038_led0_pwm_duty_cycles,
+	},
+	[2] = {
+		.id = PM8XXX_ID_RGB_LED_GREEN,
+		.mode = PM8XXX_LED_MODE_PWM1,
+		.max_current = PM8038_RGB_LED_MAX_CURRENT,
+		.pwm_channel = 4,
+		.pwm_period_us = PM8XXX_LED_PWM_PERIOD,
+		.pwm_duty_cycles = &pm8038_led0_pwm_duty_cycles,
+	},
+	[3] = {
+		.id = PM8XXX_ID_RGB_LED_BLUE,
+		.mode = PM8XXX_LED_MODE_PWM1,
+		.max_current = PM8038_RGB_LED_MAX_CURRENT,
+		.pwm_channel = 3,
+		.pwm_period_us = PM8XXX_LED_PWM_PERIOD,
+		.pwm_duty_cycles = &pm8038_led0_pwm_duty_cycles,
+	},
+};
+
+static struct pm8xxx_led_platform_data pm8xxx_leds_pdata = {
+	.led_core = &pm8038_led_core_pdata,
+	.configs = pm8038_led_configs,
+	.num_configs = ARRAY_SIZE(pm8038_led_configs),
+};
+
+static struct pm8xxx_ccadc_platform_data pm8xxx_ccadc_pdata = {
+	.r_sense		= 10,
+};
+
+static struct pm8xxx_misc_platform_data pm8xxx_misc_pdata = {
+	.priority		= 0,
+};
+
+static struct pm8xxx_spk_platform_data pm8xxx_spk_pdata = {
+	.spk_add_enable		= false,
+};
+
+static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = {
+	.battery_type	= BATT_UNKNOWN,
+	.r_sense		= 10,
+	.i_test			= 2500,
+	.v_failure		= 3000,
+	.calib_delay_ms		= 600000,
+	.max_voltage_uv		= MAX_VOLTAGE_MV * 1000,
+};
+
+static struct pm8038_platform_data pm8038_platform_data __devinitdata = {
+	.irq_pdata		= &pm8xxx_irq_pdata,
+	.gpio_pdata		= &pm8xxx_gpio_pdata,
+	.mpp_pdata		= &pm8xxx_mpp_pdata,
+	.rtc_pdata              = &pm8xxx_rtc_pdata,
+	.pwrkey_pdata		= &pm8xxx_pwrkey_pdata,
+	.misc_pdata		= &pm8xxx_misc_pdata,
+	.regulator_pdatas	= msm8930_pm8038_regulator_pdata,
+	.charger_pdata		= &pm8921_chg_pdata,
+	.bms_pdata		= &pm8921_bms_pdata,
+	.adc_pdata		= &pm8xxx_adc_pdata,
+	.leds_pdata		= &pm8xxx_leds_pdata,
+	.ccadc_pdata		= &pm8xxx_ccadc_pdata,
+	.spk_pdata		= &pm8xxx_spk_pdata,
+};
+
+static struct msm_ssbi_platform_data msm8930_ssbi_pm8038_pdata __devinitdata = {
+	.controller_type = MSM_SBI_CTRL_PMIC_ARBITER,
+	.slave	= {
+		.name			= "pm8038-core",
+		.platform_data		= &pm8038_platform_data,
+	},
+};
+
+void __init msm8930_init_pmic(void)
+{
+	pmic_reset_irq = PM8038_IRQ_BASE + PM8038_RESOUT_IRQ;
+	msm8960_device_ssbi_pmic.dev.platform_data =
+				&msm8930_ssbi_pm8038_pdata;
+	pm8038_platform_data.num_regulators
+		= msm8930_pm8038_regulator_pdata_len;
+	if (machine_is_apq8064_mtp())
+		pm8921_bms_pdata.battery_type = BATT_PALLADIUM;
+	else if (machine_is_apq8064_liquid())
+		pm8921_bms_pdata.battery_type = BATT_DESAY;
+}
diff --git a/arch/arm/mach-msm/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator.c
new file mode 100644
index 0000000..2f24c95
--- /dev/null
+++ b/arch/arm/mach-msm/board-8930-regulator.c
@@ -0,0 +1,513 @@
+/*
+ * 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
+ * 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/regulator/pm8xxx-regulator.h>
+
+#include "board-8930.h"
+
+#define VREG_CONSUMERS(_id) \
+	static struct regulator_consumer_supply vreg_consumers_##_id[]
+
+/*
+ * Consumer specific regulator names:
+ *			 regulator name		consumer dev_name
+ */
+VREG_CONSUMERS(L1) = {
+	REGULATOR_SUPPLY("8038_l1",		NULL),
+	REGULATOR_SUPPLY("iris_vddrfa",		"wcnss_wlan.0"),
+};
+VREG_CONSUMERS(L2) = {
+	REGULATOR_SUPPLY("8038_l2",		NULL),
+	REGULATOR_SUPPLY("iris_vdddig",		"wcnss_wlan.0"),
+	REGULATOR_SUPPLY("dsi_vdda",		"mipi_dsi.1"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.0"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.1"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.2"),
+};
+VREG_CONSUMERS(L3) = {
+	REGULATOR_SUPPLY("8038_l3",		NULL),
+	REGULATOR_SUPPLY("HSUSB_3p3",		"msm_otg"),
+};
+VREG_CONSUMERS(L4) = {
+	REGULATOR_SUPPLY("8038_l4",		NULL),
+	REGULATOR_SUPPLY("HSUSB_1p8",		"msm_otg"),
+	REGULATOR_SUPPLY("iris_vddxo",		"wcnss_wlan.0"),
+};
+VREG_CONSUMERS(L5) = {
+	REGULATOR_SUPPLY("8038_l5",		NULL),
+	REGULATOR_SUPPLY("sdc_vdd",		"msm_sdcc.1"),
+};
+VREG_CONSUMERS(L6) = {
+	REGULATOR_SUPPLY("8038_l6",		NULL),
+	REGULATOR_SUPPLY("sdc_vdd",		"msm_sdcc.3"),
+};
+VREG_CONSUMERS(L7) = {
+	REGULATOR_SUPPLY("8038_l7",		NULL),
+};
+VREG_CONSUMERS(L8) = {
+	REGULATOR_SUPPLY("8038_l8",		NULL),
+	REGULATOR_SUPPLY("dsi_vdc",		"mipi_dsi.1"),
+};
+VREG_CONSUMERS(L9) = {
+	REGULATOR_SUPPLY("8038_l9",		NULL),
+	REGULATOR_SUPPLY("vdd_ana",		"3-004a"),
+	REGULATOR_SUPPLY("vdd",			"3-0024"),
+	REGULATOR_SUPPLY("cam_vana",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vana",		"4-006c"),
+	REGULATOR_SUPPLY("cam_vana",		"4-0048"),
+	REGULATOR_SUPPLY("cam_vaf",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vaf",		"4-006c"),
+	REGULATOR_SUPPLY("cam_vaf",		"4-0048"),
+	REGULATOR_SUPPLY("cam_vana",            "4-0020"),
+	REGULATOR_SUPPLY("cam_vaf",             "4-0020"),
+};
+VREG_CONSUMERS(L10) = {
+	REGULATOR_SUPPLY("8038_l10",		NULL),
+	REGULATOR_SUPPLY("iris_vddpa",		"wcnss_wlan.0"),
+};
+VREG_CONSUMERS(L11) = {
+	REGULATOR_SUPPLY("8038_l11",		NULL),
+	REGULATOR_SUPPLY("vdd_dig",		"3-004a"),
+	REGULATOR_SUPPLY("iris_vddio",		"wcnss_wlan.0"),
+	REGULATOR_SUPPLY("riva_vddpx",		"wcnss_wlan.0"),
+	REGULATOR_SUPPLY("sdc_vccq",		"msm_sdcc.1"),
+	REGULATOR_SUPPLY("VDDIO_CDC",		"sitar-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_TX",		"sitar-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_RX",		"sitar-slim"),
+	REGULATOR_SUPPLY("VDDIO_CDC",		"sitar1p1-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_TX",		"sitar1p1-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_RX",		"sitar1p1-slim"),
+	REGULATOR_SUPPLY("vddp",		"0-0048"),
+};
+VREG_CONSUMERS(L12) = {
+	REGULATOR_SUPPLY("8038_l12",		NULL),
+	REGULATOR_SUPPLY("cam_vdig",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vdig",		"4-006c"),
+	REGULATOR_SUPPLY("cam_vdig",		"4-0048"),
+	REGULATOR_SUPPLY("cam_vdig",            "4-0020"),
+};
+VREG_CONSUMERS(L14) = {
+	REGULATOR_SUPPLY("8038_l14",		NULL),
+	REGULATOR_SUPPLY("pa_therm",		"pm8xxx-adc"),
+};
+VREG_CONSUMERS(L15) = {
+	REGULATOR_SUPPLY("8038_l15",		NULL),
+};
+VREG_CONSUMERS(L16) = {
+	REGULATOR_SUPPLY("8038_l16",		NULL),
+	REGULATOR_SUPPLY("core_vdd",		"pil_qdsp6v4.2"),
+};
+VREG_CONSUMERS(L17) = {
+	REGULATOR_SUPPLY("8038_l17",		NULL),
+};
+VREG_CONSUMERS(L18) = {
+	REGULATOR_SUPPLY("8038_l18",		NULL),
+};
+VREG_CONSUMERS(L19) = {
+	REGULATOR_SUPPLY("8038_l19",		NULL),
+	REGULATOR_SUPPLY("core_vdd",		"pil_qdsp6v4.1"),
+};
+VREG_CONSUMERS(L20) = {
+	REGULATOR_SUPPLY("8038_l20",		NULL),
+	REGULATOR_SUPPLY("VDDD_CDC_D",		"sitar-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",	"sitar-slim"),
+	REGULATOR_SUPPLY("VDDD_CDC_D",		"sitar1p1-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",	"sitar1p1-slim"),
+};
+VREG_CONSUMERS(L21) = {
+	REGULATOR_SUPPLY("8038_l21",		NULL),
+};
+VREG_CONSUMERS(L22) = {
+	REGULATOR_SUPPLY("8038_l22",		NULL),
+	REGULATOR_SUPPLY("sdc_vddp",		"msm_sdcc.3"),
+};
+VREG_CONSUMERS(L23) = {
+	REGULATOR_SUPPLY("8038_l23",		NULL),
+	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),
+	REGULATOR_SUPPLY("riva_vddmx",		"wcnss_wlan.0"),
+};
+VREG_CONSUMERS(L26) = {
+	REGULATOR_SUPPLY("8038_l26",		NULL),
+};
+VREG_CONSUMERS(L27) = {
+	REGULATOR_SUPPLY("8038_l27",		NULL),
+	REGULATOR_SUPPLY("core_vdd",		"pil_qdsp6v4.0"),
+};
+VREG_CONSUMERS(S1) = {
+	REGULATOR_SUPPLY("8038_s1",		NULL),
+	REGULATOR_SUPPLY("riva_vddcx",		"wcnss_wlan.0"),
+};
+VREG_CONSUMERS(S2) = {
+	REGULATOR_SUPPLY("8038_s2",		NULL),
+};
+VREG_CONSUMERS(S3) = {
+	REGULATOR_SUPPLY("8038_s3",		NULL),
+};
+VREG_CONSUMERS(S4) = {
+	REGULATOR_SUPPLY("8038_s4",		NULL),
+	REGULATOR_SUPPLY("CDC_VDD_CP",		"sitar-slim"),
+	REGULATOR_SUPPLY("CDC_VDD_CP",		"sitar1p1-slim"),
+};
+VREG_CONSUMERS(S5) = {
+	REGULATOR_SUPPLY("8038_s5",		NULL),
+	REGULATOR_SUPPLY("krait0",		NULL),
+};
+VREG_CONSUMERS(S6) = {
+	REGULATOR_SUPPLY("8038_s6",		NULL),
+	REGULATOR_SUPPLY("krait1",		NULL),
+};
+VREG_CONSUMERS(LVS1) = {
+	REGULATOR_SUPPLY("8038_lvs1",		NULL),
+	REGULATOR_SUPPLY("cam_vio",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vio",		"4-006c"),
+	REGULATOR_SUPPLY("cam_vio",		"4-0048"),
+	REGULATOR_SUPPLY("cam_vio",             "4-0020"),
+};
+VREG_CONSUMERS(LVS2) = {
+	REGULATOR_SUPPLY("8038_lvs2",		NULL),
+	REGULATOR_SUPPLY("vcc_i2c",		"3-004a"),
+	REGULATOR_SUPPLY("vcc_i2c",		"3-0024"),
+	REGULATOR_SUPPLY("vcc_i2c",		"0-0048"),
+};
+VREG_CONSUMERS(EXT_5V) = {
+	REGULATOR_SUPPLY("ext_5v",		NULL),
+	REGULATOR_SUPPLY("hdmi_mvs",		"hdmi_msm.0"),
+};
+VREG_CONSUMERS(EXT_OTG_SW) = {
+	REGULATOR_SUPPLY("ext_otg_sw",		NULL),
+	REGULATOR_SUPPLY("vbus_otg",		"msm_otg"),
+};
+VREG_CONSUMERS(VDD_DIG_CORNER) = {
+	REGULATOR_SUPPLY("vdd_dig_corner",	NULL),
+	REGULATOR_SUPPLY("hsusb_vdd_dig",	"msm_otg"),
+};
+
+#define PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
+			 _apply_uV, _pull_down, _always_on, _supply_regulator, \
+			 _system_uA, _enable_time, _reg_id) \
+	{ \
+		.init_data = { \
+			.constraints = { \
+				.valid_modes_mask	= _modes, \
+				.valid_ops_mask		= _ops, \
+				.min_uV			= _min_uV, \
+				.max_uV			= _max_uV, \
+				.input_uV		= _max_uV, \
+				.apply_uV		= _apply_uV, \
+				.always_on		= _always_on, \
+				.name			= _name, \
+			}, \
+			.num_consumer_supplies	= \
+					ARRAY_SIZE(vreg_consumers_##_id), \
+			.consumer_supplies	= vreg_consumers_##_id, \
+			.supply_regulator	= _supply_regulator, \
+		}, \
+		.id			= _reg_id, \
+		.pull_down_enable	= _pull_down, \
+		.system_uA		= _system_uA, \
+		.enable_time		= _enable_time, \
+	}
+
+#define PM8XXX_LDO(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+		_enable_time, _supply_regulator, _system_uA, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
+		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
+		REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
+
+#define PM8XXX_NLDO1200(_id, _name, _always_on, _pull_down, _min_uV, \
+		_max_uV, _enable_time, _supply_regulator, _system_uA, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
+		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
+		REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
+
+#define PM8XXX_SMPS(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+		_enable_time, _supply_regulator, _system_uA, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
+		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
+		REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
+
+#define PM8XXX_FTSMPS(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+		_enable_time, _supply_regulator, _system_uA, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL, \
+		REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS \
+		| REGULATOR_CHANGE_MODE, 0, _pull_down, _always_on, \
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
+
+#define PM8XXX_VS(_id, _name, _always_on, _pull_down, _enable_time, \
+		_supply_regulator, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, \
+		_pull_down, _always_on, _supply_regulator, 0, _enable_time, \
+		_reg_id)
+
+#define PM8XXX_VS300(_id, _name, _always_on, _pull_down, _enable_time, \
+		_supply_regulator, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, \
+		_pull_down, _always_on, _supply_regulator, 0, _enable_time, \
+		_reg_id)
+
+#define PM8XXX_NCP(_id, _name, _always_on, _min_uV, _max_uV, _enable_time, \
+		_supply_regulator, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, 0, \
+		REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, 0, 0, \
+		_always_on, _supply_regulator, 0, _enable_time, _reg_id)
+
+/* Pin control initialization */
+#define PM8XXX_PC(_id, _name, _always_on, _pin_fn, _pin_ctrl, \
+		  _supply_regulator, _reg_id) \
+	{ \
+		.init_data = { \
+			.constraints = { \
+				.valid_ops_mask	= REGULATOR_CHANGE_STATUS, \
+				.always_on	= _always_on, \
+				.name		= _name, \
+			}, \
+			.num_consumer_supplies	= \
+					ARRAY_SIZE(vreg_consumers_##_id##_PC), \
+			.consumer_supplies	= vreg_consumers_##_id##_PC, \
+			.supply_regulator  = _supply_regulator, \
+		}, \
+		.id		= _reg_id, \
+		.pin_fn		= PM8XXX_VREG_PIN_FN_##_pin_fn, \
+		.pin_ctrl	= _pin_ctrl, \
+	}
+
+#define RPM_INIT(_id, _min_uV, _max_uV, _modes, _ops, _apply_uV, _default_uV, \
+		 _peak_uA, _avg_uA, _pull_down, _pin_ctrl, _freq, _pin_fn, \
+		 _force_mode, _sleep_set_force_mode, _power_mode, _state, \
+		 _sleep_selectable, _always_on, _supply_regulator, _system_uA) \
+	{ \
+		.init_data = { \
+			.constraints = { \
+				.valid_modes_mask	= _modes, \
+				.valid_ops_mask		= _ops, \
+				.min_uV			= _min_uV, \
+				.max_uV			= _max_uV, \
+				.input_uV		= _min_uV, \
+				.apply_uV		= _apply_uV, \
+				.always_on		= _always_on, \
+			}, \
+			.num_consumer_supplies	= \
+					ARRAY_SIZE(vreg_consumers_##_id), \
+			.consumer_supplies	= vreg_consumers_##_id, \
+			.supply_regulator	= _supply_regulator, \
+		}, \
+		.id			= RPM_VREG_ID_PM8038_##_id, \
+		.default_uV		= _default_uV, \
+		.peak_uA		= _peak_uA, \
+		.avg_uA			= _avg_uA, \
+		.pull_down_enable	= _pull_down, \
+		.pin_ctrl		= _pin_ctrl, \
+		.freq			= RPM_VREG_FREQ_##_freq, \
+		.pin_fn			= _pin_fn, \
+		.force_mode		= _force_mode, \
+		.sleep_set_force_mode	= _sleep_set_force_mode, \
+		.power_mode		= _power_mode, \
+		.state			= _state, \
+		.sleep_selectable	= _sleep_selectable, \
+		.system_uA		= _system_uA, \
+	}
+
+#define RPM_LDO(_id, _always_on, _pd, _sleep_selectable, _min_uV, _max_uV, \
+		_supply_regulator, _system_uA, _init_peak_uA) \
+	RPM_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+		 | REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE \
+		 | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE \
+		 | REGULATOR_CHANGE_DRMS, 0, _max_uV, _init_peak_uA, 0, _pd, \
+		 RPM_VREG_PIN_CTRL_NONE, NONE, RPM_VREG_PIN_FN_8930_NONE, \
+		 RPM_VREG_FORCE_MODE_8930_NONE, \
+		 RPM_VREG_FORCE_MODE_8930_NONE, RPM_VREG_POWER_MODE_8930_PWM, \
+		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
+		 _supply_regulator, _system_uA)
+
+#define RPM_SMPS(_id, _always_on, _pd, _sleep_selectable, _min_uV, _max_uV, \
+		 _supply_regulator, _system_uA, _freq, _force_mode, \
+		 _sleep_set_force_mode) \
+	RPM_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+		 | REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE \
+		 | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE \
+		 | REGULATOR_CHANGE_DRMS, 0, _min_uV, _system_uA, 0, _pd, \
+		 RPM_VREG_PIN_CTRL_NONE, _freq, RPM_VREG_PIN_FN_8930_NONE, \
+		 RPM_VREG_FORCE_MODE_8930_##_force_mode, \
+		 RPM_VREG_FORCE_MODE_8930_##_sleep_set_force_mode, \
+		 RPM_VREG_POWER_MODE_8930_PWM, RPM_VREG_STATE_OFF, \
+		 _sleep_selectable, _always_on, _supply_regulator, _system_uA)
+
+#define RPM_VS(_id, _always_on, _pd, _sleep_selectable, _supply_regulator) \
+	RPM_INIT(_id, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, 0, 1000, 1000, _pd, \
+		 RPM_VREG_PIN_CTRL_NONE, NONE, RPM_VREG_PIN_FN_8930_NONE, \
+		 RPM_VREG_FORCE_MODE_8930_NONE, \
+		 RPM_VREG_FORCE_MODE_8930_NONE, RPM_VREG_POWER_MODE_8930_PWM, \
+		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
+		 _supply_regulator, 0)
+
+#define RPM_NCP(_id, _always_on, _sleep_selectable, _min_uV, _max_uV, \
+		_supply_regulator, _freq) \
+	RPM_INIT(_id, _min_uV, _max_uV, 0, REGULATOR_CHANGE_VOLTAGE \
+		 | REGULATOR_CHANGE_STATUS, 0, _max_uV, 1000, 1000, 0, \
+		 RPM_VREG_PIN_CTRL_NONE, _freq, RPM_VREG_PIN_FN_8930_NONE, \
+		 RPM_VREG_FORCE_MODE_8930_NONE, \
+		 RPM_VREG_FORCE_MODE_8930_NONE, RPM_VREG_POWER_MODE_8930_PWM, \
+		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
+		 _supply_regulator, 0)
+
+#define RPM_CORNER(_id, _always_on, _sleep_selectable, _min_uV, _max_uV, \
+		_supply_regulator) \
+	RPM_INIT(_id, _min_uV, _max_uV, 0, REGULATOR_CHANGE_VOLTAGE \
+		 | REGULATOR_CHANGE_STATUS, 0, _max_uV, 0, 0, 0, \
+		 RPM_VREG_PIN_CTRL_NONE, NONE, RPM_VREG_PIN_FN_8930_NONE, \
+		 RPM_VREG_FORCE_MODE_8930_NONE, \
+		 RPM_VREG_FORCE_MODE_8930_NONE, RPM_VREG_POWER_MODE_8930_PWM, \
+		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
+		 _supply_regulator, 0)
+
+/* Pin control initialization */
+#define RPM_PC_INIT(_id, _always_on, _pin_fn, _pin_ctrl, _supply_regulator) \
+	{ \
+		.init_data = { \
+			.constraints = { \
+				.valid_ops_mask	= REGULATOR_CHANGE_STATUS, \
+				.always_on	= _always_on, \
+			}, \
+			.num_consumer_supplies	= \
+					ARRAY_SIZE(vreg_consumers_##_id##_PC), \
+			.consumer_supplies	= vreg_consumers_##_id##_PC, \
+			.supply_regulator	= _supply_regulator, \
+		}, \
+		.id	  = RPM_VREG_ID_PM8038_##_id##_PC, \
+		.pin_fn	  = RPM_VREG_PIN_FN_8930_##_pin_fn, \
+		.pin_ctrl = _pin_ctrl, \
+	}
+
+#define GPIO_VREG(_id, _reg_name, _gpio_label, _gpio, _supply_regulator) \
+	[MSM8930_GPIO_VREG_ID_##_id] = { \
+		.init_data = { \
+			.constraints = { \
+				.valid_ops_mask	= REGULATOR_CHANGE_STATUS, \
+			}, \
+			.num_consumer_supplies	= \
+					ARRAY_SIZE(vreg_consumers_##_id), \
+			.consumer_supplies	= vreg_consumers_##_id, \
+			.supply_regulator	= _supply_regulator, \
+		}, \
+		.regulator_name = _reg_name, \
+		.gpio_label	= _gpio_label, \
+		.gpio		= _gpio, \
+	}
+
+#define SAW_VREG_INIT(_id, _name, _min_uV, _max_uV) \
+	{ \
+		.constraints = { \
+			.name		= _name, \
+			.valid_ops_mask	= REGULATOR_CHANGE_VOLTAGE, \
+			.min_uV		= _min_uV, \
+			.max_uV		= _max_uV, \
+		}, \
+		.num_consumer_supplies	= ARRAY_SIZE(vreg_consumers_##_id), \
+		.consumer_supplies	= vreg_consumers_##_id, \
+	}
+
+/* GPIO regulator constraints */
+struct gpio_regulator_platform_data
+msm8930_gpio_regulator_pdata[] __devinitdata = {
+	/*        ID          vreg_name     gpio_label     gpio  supply */
+	GPIO_VREG(EXT_5V,     "ext_5v",     "ext_5v_en",     63, NULL),
+	GPIO_VREG(EXT_OTG_SW, "ext_otg_sw", "ext_otg_sw_en", 97, "ext_5v"),
+};
+
+/* SAW regulator constraints */
+struct regulator_init_data msm8930_saw_regulator_core0_pdata =
+	/*	      ID  vreg_name	       min_uV   max_uV */
+	SAW_VREG_INIT(S5, "8038_s5",	       850000, 1300000);
+struct regulator_init_data msm8930_saw_regulator_core1_pdata =
+	SAW_VREG_INIT(S6, "8038_s6",	       850000, 1300000);
+
+/* PM8038 regulator constraints */
+struct pm8xxx_regulator_platform_data
+msm8930_pm8038_regulator_pdata[] __devinitdata = {
+	/*
+	 *	    ID  name always_on pd min_uV   max_uV   en_t supply
+	 *	system_uA reg_ID
+	 */
+	PM8XXX_NLDO1200(L16, "8038_l16", 0, 1, 375000, 1050000, 200, "8038_s3",
+		0, 0),
+	PM8XXX_NLDO1200(L19, "8038_l19", 0, 1, 375000, 1050000, 200, "8038_s3",
+		0, 1),
+	PM8XXX_NLDO1200(L27, "8038_l27", 0, 1, 375000, 1050000, 200, "8038_s3",
+		0, 2),
+};
+
+static struct rpm_regulator_init_data
+msm8930_rpm_regulator_init_data[] __devinitdata = {
+	/*	ID a_on pd ss min_uV   max_uV  supply sys_uA  freq  fm  ss_fm */
+	RPM_SMPS(S1, 0, 1, 1,  500000, 1150000, NULL, 100000, 4p80, AUTO, LPM),
+	RPM_SMPS(S2, 1, 1, 1, 1400000, 1400000, NULL, 100000, 1p60, AUTO, LPM),
+	RPM_SMPS(S3, 0, 1, 1, 1150000, 1150000, NULL, 100000, 3p20, AUTO, LPM),
+	RPM_SMPS(S4, 1, 1, 1, 1950000, 2200000, NULL, 100000, 1p60, AUTO, LPM),
+
+	/*	ID     a_on pd ss min_uV   max_uV  supply  sys_uA init_ip */
+	RPM_LDO(L1,	 0, 1, 0, 1300000, 1300000, "8038_s2", 0, 0),
+	RPM_LDO(L2,	 0, 1, 0, 1200000, 1200000, "8038_s2", 0, 0),
+	RPM_LDO(L3,	 0, 1, 0, 3075000, 3075000, NULL,      0, 0),
+	RPM_LDO(L4,	 1, 1, 0, 1800000, 1800000, NULL,      10000, 10000),
+	RPM_LDO(L5,	 0, 1, 0, 2950000, 2950000, NULL,      0, 0),
+	RPM_LDO(L6,	 0, 1, 0, 2950000, 2950000, NULL,      0, 0),
+	RPM_LDO(L7,	 0, 1, 0, 2050000, 2050000, "8038_s4", 0, 0),
+	RPM_LDO(L8,	 0, 1, 0, 2800000, 2800000, NULL,      0, 0),
+	RPM_LDO(L9,	 0, 1, 0, 2850000, 2850000, NULL,      0, 0),
+	RPM_LDO(L10,	 0, 1, 0, 2900000, 2900000, NULL,      0, 0),
+	RPM_LDO(L11,	 1, 1, 0, 1800000, 1800000, "8038_s4", 10000, 10000),
+	RPM_LDO(L12,	 0, 1, 0, 1200000, 1200000, "8038_s2", 0, 0),
+	RPM_LDO(L14,	 0, 1, 0, 1800000, 1800000, NULL,      0, 0),
+	RPM_LDO(L15,	 0, 1, 0, 1800000, 2950000, NULL,      0, 0),
+	RPM_LDO(L17,	 0, 1, 0, 1800000, 2950000, NULL,      0, 0),
+	RPM_LDO(L18,	 0, 1, 0, 1800000, 1800000, NULL,      0, 0),
+	RPM_LDO(L20,	 1, 1, 0, 1200000, 1200000, "8038_s2", 10000, 10000),
+	RPM_LDO(L21,	 0, 1, 0, 1900000, 1900000, "8038_s4", 0, 0),
+	RPM_LDO(L22,	 1, 1, 0, 1850000, 2950000, NULL,      10000, 10000),
+	RPM_LDO(L23,	 1, 1, 1, 1800000, 1800000, "8038_s4", 0, 0),
+	RPM_LDO(L24,	 0, 1, 1,  500000, 1150000, "8038_s2", 10000, 10000),
+	RPM_LDO(L26,     1, 1, 0, 1050000, 1050000, "8038_s2", 10000, 10000),
+
+	/*	ID     a_on pd ss		    supply */
+	RPM_VS(LVS1,	 0, 1, 0,		    "8038_l11"),
+	RPM_VS(LVS2,	 0, 1, 0,		    "8038_l11"),
+
+	/*	   ID            a_on ss min_corner  max_corner  supply */
+	RPM_CORNER(VDD_DIG_CORNER, 0, 1, RPM_VREG_CORNER_NONE,
+		RPM_VREG_CORNER_HIGH, NULL),
+};
+
+int msm8930_pm8038_regulator_pdata_len __devinitdata =
+	ARRAY_SIZE(msm8930_pm8038_regulator_pdata);
+
+struct rpm_regulator_platform_data msm8930_rpm_regulator_pdata __devinitdata = {
+	.init_data		= msm8930_rpm_regulator_init_data,
+	.num_regulators		= ARRAY_SIZE(msm8930_rpm_regulator_init_data),
+	.version		= RPM_VREG_VERSION_8930,
+	.vreg_id_vdd_mem	= RPM_VREG_ID_PM8038_L24,
+	.vreg_id_vdd_dig	= RPM_VREG_ID_PM8038_VDD_DIG_CORNER,
+};
diff --git a/arch/arm/mach-msm/board-8930-storage.c b/arch/arm/mach-msm/board-8930-storage.c
new file mode 100644
index 0000000..52a11bc
--- /dev/null
+++ b/arch/arm/mach-msm/board-8930-storage.c
@@ -0,0 +1,296 @@
+/* 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
+ * 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 <linux/gpio.h>
+#include <asm/mach-types.h>
+#include <asm/mach/mmc.h>
+#include <mach/msm_bus_board.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
+#include "devices.h"
+
+#include "board-8930.h"
+#include "board-storage-common-a.h"
+
+/* MSM8960 has 5 SDCC controllers */
+enum sdcc_controllers {
+	SDCC1,
+	SDCC2,
+	SDCC3,
+	SDCC4,
+	SDCC5,
+	MAX_SDCC_CONTROLLER
+};
+
+/* All SDCC controllers require VDD/VCC voltage */
+static struct msm_mmc_reg_data mmc_vdd_reg_data[MAX_SDCC_CONTROLLER] = {
+	/* SDCC1 : eMMC card connected */
+	[SDCC1] = {
+		.name = "sdc_vdd",
+		.high_vol_level = 2950000,
+		.low_vol_level = 2950000,
+		.always_on = 1,
+		.lpm_sup = 1,
+		.lpm_uA = 9000,
+		.hpm_uA = 200000, /* 200mA */
+	},
+	/* SDCC3 : External card slot connected */
+	[SDCC3] = {
+		.name = "sdc_vdd",
+		.high_vol_level = 2950000,
+		.low_vol_level = 2950000,
+		.hpm_uA = 800000, /* 800mA */
+	}
+};
+
+/* Only slots having eMMC card will require VCCQ voltage */
+static struct msm_mmc_reg_data mmc_vccq_reg_data[1] = {
+	/* SDCC1 : eMMC card connected */
+	[SDCC1] = {
+		.name = "sdc_vccq",
+		.always_on = 1,
+		.high_vol_level = 1800000,
+		.low_vol_level = 1800000,
+		.hpm_uA = 200000, /* 200mA */
+	}
+};
+
+/* All SDCC controllers may require voting for VDD PAD voltage */
+static struct msm_mmc_reg_data mmc_vddp_reg_data[MAX_SDCC_CONTROLLER] = {
+	/* SDCC3 : External card slot connected */
+	[SDCC3] = {
+		.name = "sdc_vddp",
+		.high_vol_level = 2950000,
+		.low_vol_level = 1850000,
+		.always_on = 1,
+		.lpm_sup = 1,
+		/* Max. Active current required is 16 mA */
+		.hpm_uA = 16000,
+		/*
+		 * Sleep current required is ~300 uA. But min. vote can be
+		 * in terms of mA (min. 1 mA). So let's vote for 2 mA
+		 * during sleep.
+		 */
+		.lpm_uA = 2000,
+	}
+};
+
+static struct msm_mmc_slot_reg_data mmc_slot_vreg_data[MAX_SDCC_CONTROLLER] = {
+	/* SDCC1 : eMMC card connected */
+	[SDCC1] = {
+		.vdd_data = &mmc_vdd_reg_data[SDCC1],
+		.vccq_data = &mmc_vccq_reg_data[SDCC1],
+	},
+	/* SDCC3 : External card slot connected */
+	[SDCC3] = {
+		.vdd_data = &mmc_vdd_reg_data[SDCC3],
+		.vddp_data = &mmc_vddp_reg_data[SDCC3],
+	}
+};
+
+/* SDC1 pad data */
+static struct msm_mmc_pad_drv sdc1_pad_drv_on_cfg[] = {
+	{TLMM_HDRV_SDC1_CLK, GPIO_CFG_16MA},
+	{TLMM_HDRV_SDC1_CMD, GPIO_CFG_10MA},
+	{TLMM_HDRV_SDC1_DATA, GPIO_CFG_10MA}
+};
+
+static struct msm_mmc_pad_drv sdc1_pad_drv_off_cfg[] = {
+	{TLMM_HDRV_SDC1_CLK, GPIO_CFG_2MA},
+	{TLMM_HDRV_SDC1_CMD, GPIO_CFG_2MA},
+	{TLMM_HDRV_SDC1_DATA, GPIO_CFG_2MA}
+};
+
+static struct msm_mmc_pad_pull sdc1_pad_pull_on_cfg[] = {
+	{TLMM_PULL_SDC1_CLK, GPIO_CFG_NO_PULL},
+	{TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_UP},
+	{TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_UP}
+};
+
+static struct msm_mmc_pad_pull sdc1_pad_pull_off_cfg[] = {
+	{TLMM_PULL_SDC1_CLK, GPIO_CFG_NO_PULL},
+	{TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_UP},
+	{TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_UP}
+};
+
+/* SDC3 pad data */
+static struct msm_mmc_pad_drv sdc3_pad_drv_on_cfg[] = {
+	{TLMM_HDRV_SDC3_CLK, GPIO_CFG_8MA},
+	{TLMM_HDRV_SDC3_CMD, GPIO_CFG_8MA},
+	{TLMM_HDRV_SDC3_DATA, GPIO_CFG_8MA}
+};
+
+static struct msm_mmc_pad_drv sdc3_pad_drv_off_cfg[] = {
+	{TLMM_HDRV_SDC3_CLK, GPIO_CFG_2MA},
+	{TLMM_HDRV_SDC3_CMD, GPIO_CFG_2MA},
+	{TLMM_HDRV_SDC3_DATA, GPIO_CFG_2MA}
+};
+
+static struct msm_mmc_pad_pull sdc3_pad_pull_on_cfg[] = {
+	{TLMM_PULL_SDC3_CLK, GPIO_CFG_NO_PULL},
+	{TLMM_PULL_SDC3_CMD, GPIO_CFG_PULL_UP},
+	{TLMM_PULL_SDC3_DATA, GPIO_CFG_PULL_UP}
+};
+
+static struct msm_mmc_pad_pull sdc3_pad_pull_off_cfg[] = {
+	{TLMM_PULL_SDC3_CLK, GPIO_CFG_NO_PULL},
+	/*
+	 * SDC3 CMD line should be PULLed UP otherwise fluid platform will
+	 * see transitions (1 -> 0 and 0 -> 1) on card detection line,
+	 * which would result in false card detection interrupts.
+	 */
+	{TLMM_PULL_SDC3_CMD, GPIO_CFG_PULL_UP},
+	/*
+	 * Keeping DATA lines status to PULL UP will make sure that
+	 * there is no current leak during sleep if external pull up
+	 * is connected to DATA lines.
+	 */
+	{TLMM_PULL_SDC3_DATA, GPIO_CFG_PULL_UP}
+};
+
+static struct msm_mmc_pad_pull_data mmc_pad_pull_data[MAX_SDCC_CONTROLLER] = {
+	[SDCC1] = {
+		.on = sdc1_pad_pull_on_cfg,
+		.off = sdc1_pad_pull_off_cfg,
+		.size = ARRAY_SIZE(sdc1_pad_pull_on_cfg)
+	},
+	[SDCC3] = {
+		.on = sdc3_pad_pull_on_cfg,
+		.off = sdc3_pad_pull_off_cfg,
+		.size = ARRAY_SIZE(sdc3_pad_pull_on_cfg)
+	},
+};
+
+static struct msm_mmc_pad_drv_data mmc_pad_drv_data[MAX_SDCC_CONTROLLER] = {
+	[SDCC1] = {
+		.on = sdc1_pad_drv_on_cfg,
+		.off = sdc1_pad_drv_off_cfg,
+		.size = ARRAY_SIZE(sdc1_pad_drv_on_cfg)
+	},
+	[SDCC3] = {
+		.on = sdc3_pad_drv_on_cfg,
+		.off = sdc3_pad_drv_off_cfg,
+		.size = ARRAY_SIZE(sdc3_pad_drv_on_cfg)
+	},
+};
+
+static struct msm_mmc_pad_data mmc_pad_data[MAX_SDCC_CONTROLLER] = {
+	[SDCC1] = {
+		.pull = &mmc_pad_pull_data[SDCC1],
+		.drv = &mmc_pad_drv_data[SDCC1]
+	},
+	[SDCC3] = {
+		.pull = &mmc_pad_pull_data[SDCC3],
+		.drv = &mmc_pad_drv_data[SDCC3]
+	},
+};
+
+static struct msm_mmc_pin_data mmc_slot_pin_data[MAX_SDCC_CONTROLLER] = {
+	[SDCC1] = {
+		.pad_data = &mmc_pad_data[SDCC1],
+	},
+	[SDCC3] = {
+		.pad_data = &mmc_pad_data[SDCC3],
+	},
+};
+
+#define MSM_MPM_PIN_SDC1_DAT1	17
+#define MSM_MPM_PIN_SDC3_DAT1	21
+
+static unsigned int sdc1_sup_clk_rates[] = {
+	400000, 24000000, 48000000,
+};
+
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+static unsigned int sdc3_sup_clk_rates[] = {
+	400000, 24000000, 48000000, 96000000, 192000000,
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+static struct mmc_platform_data msm8960_sdc1_data = {
+	.ocr_mask       = MMC_VDD_27_28 | MMC_VDD_28_29,
+#ifdef CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT
+	.mmc_bus_width  = MMC_CAP_8_BIT_DATA,
+#else
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+#endif
+	.sup_clk_table	= sdc1_sup_clk_rates,
+	.sup_clk_cnt	= ARRAY_SIZE(sdc1_sup_clk_rates),
+	.pclk_src_dfab	= 1,
+	.nonremovable	= 1,
+	.vreg_data	= &mmc_slot_vreg_data[SDCC1],
+	.pin_data	= &mmc_slot_pin_data[SDCC1],
+	.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC1_DAT1,
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+static struct mmc_platform_data msm8960_sdc3_data = {
+	.ocr_mask       = MMC_VDD_27_28 | MMC_VDD_28_29,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.sup_clk_table	= sdc3_sup_clk_rates,
+	.sup_clk_cnt	= ARRAY_SIZE(sdc3_sup_clk_rates),
+	.pclk_src_dfab	= 1,
+#ifdef CONFIG_MMC_MSM_SDC3_WP_SUPPORT
+/*TODO: Insert right replacement for PM8038 */
+#ifndef MSM8930_PHASE_2
+	.wpswitch_gpio	= PM8921_GPIO_PM_TO_SYS(16),
+#else
+	.wpswitch_gpio	= 66,
+	.wpswitch_polarity = 1,
+#endif
+#endif
+	.vreg_data	= &mmc_slot_vreg_data[SDCC3],
+	.pin_data	= &mmc_slot_pin_data[SDCC3],
+#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
+/*TODO: Insert right replacement for PM8038 */
+#ifndef MSM8930_PHASE_2
+	.status_gpio	= PM8921_GPIO_PM_TO_SYS(26),
+	.status_irq	= PM8921_GPIO_IRQ(PM8921_IRQ_BASE, 26),
+#else
+	.status_gpio	= 94,
+	.status_irq	= MSM_GPIO_TO_INT(94),
+#endif
+	.irq_flags	= IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+	.is_status_gpio_active_low = true,
+#endif
+	.xpc_cap	= 1,
+	.uhs_caps	= (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+			MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_DDR50 |
+			MMC_CAP_UHS_SDR104 | MMC_CAP_MAX_CURRENT_800),
+	.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC3_DAT1,
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
+};
+#endif
+
+void __init msm8930_init_mmc(void)
+{
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+	/* SDC1 : eMMC card connected */
+	msm_add_sdcc(1, &msm8960_sdc1_data);
+#endif
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+	/* SDC3: External card slot */
+	if (!machine_is_msm8930_cdp()) {
+		msm8960_sdc3_data.wpswitch_gpio = 0;
+		msm8960_sdc3_data.wpswitch_polarity = 0;
+	}
+	msm_add_sdcc(3, &msm8960_sdc3_data);
+#endif
+}
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
new file mode 100644
index 0000000..5781e3ed2
--- /dev/null
+++ b/arch/arm/mach-msm/board-8930.c
@@ -0,0 +1,2439 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/i2c.h>
+#include <linux/i2c/sx150x.h>
+#include <linux/i2c/isl9519.h>
+#include <linux/gpio.h>
+#include <linux/msm_ssbi.h>
+#include <linux/regulator/msm-gpio-regulator.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/slimbus/slimbus.h>
+#include <linux/bootmem.h>
+#include <linux/msm_kgsl.h>
+#ifdef CONFIG_ANDROID_PMEM
+#include <linux/android_pmem.h>
+#endif
+#include <linux/dma-mapping.h>
+#include <linux/platform_data/qcom_crypto_device.h>
+#include <linux/platform_data/qcom_wcnss_device.h>
+#include <linux/leds.h>
+#include <linux/leds-pm8xxx.h>
+#include <linux/i2c/atmel_mxt_ts.h>
+#include <linux/msm_tsens.h>
+#include <linux/ks8851.h>
+#include <linux/i2c/isa1200.h>
+#include <linux/gpio_keys.h>
+#include <linux/memory.h>
+#include <linux/memblock.h>
+
+#include <linux/slimbus/slimbus.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/pdata.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/setup.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach/mmc.h>
+
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_spi.h>
+#ifdef CONFIG_USB_MSM_OTG_72K
+#include <mach/msm_hsusb.h>
+#else
+#include <linux/usb/msm_hsusb.h>
+#endif
+#include <linux/usb/android.h>
+#include <mach/usbdiag.h>
+#include <mach/socinfo.h>
+#include <mach/rpm.h>
+#include <mach/gpiomux.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_memtypes.h>
+#include <mach/dma.h>
+#include <mach/msm_xo.h>
+#include <mach/restart.h>
+
+#include <linux/ion.h>
+#include <mach/ion.h>
+#include <mach/mdm2.h>
+#include <mach/msm_rtb.h>
+#include <linux/fmem.h>
+
+#include "timer.h"
+#include "devices.h"
+#include "devices-msm8x60.h"
+#include "spm.h"
+#include "pm.h"
+#include <mach/cpuidle.h>
+#include "rpm_resources.h"
+#include <mach/mpm.h>
+#include "acpuclock.h"
+#include "smd_private.h"
+#include "pm-boot.h"
+#include "msm_watchdog.h"
+#include "board-8930.h"
+
+static struct platform_device msm_fm_platform_init = {
+	.name = "iris_fm",
+	.id   = -1,
+};
+
+#define KS8851_RST_GPIO		89
+#define KS8851_IRQ_GPIO		90
+#define HAP_SHIFT_LVL_OE_GPIO	47
+
+#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
+
+struct sx150x_platform_data msm8930_sx150x_data[] = {
+	[SX150X_CAM] = {
+		.gpio_base         = GPIO_CAM_EXPANDER_BASE,
+		.oscio_is_gpo      = false,
+		.io_pullup_ena     = 0x0,
+		.io_pulldn_ena     = 0xc0,
+		.io_open_drain_ena = 0x0,
+		.irq_summary       = -1,
+	},
+};
+
+#endif
+
+#define MSM_PMEM_ADSP_SIZE         0x7800000
+#define MSM_PMEM_AUDIO_SIZE        0x4CF000
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+#define MSM_PMEM_SIZE 0x4000000 /* 64 Mbytes */
+#else
+#define MSM_PMEM_SIZE 0x2800000 /* 40 Mbytes */
+#endif
+#define MSM_LIQUID_PMEM_SIZE 0x4000000 /* 64 Mbytes */
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+#define MSM_PMEM_KERNEL_EBI1_SIZE  0x65000
+#ifdef CONFIG_MSM_IOMMU
+#define MSM_ION_MM_SIZE            0x3800000 /* Need to be multiple of 64K */
+#define MSM_ION_SF_SIZE            0x0
+#define MSM_ION_QSECOM_SIZE	0x780000 /* (7.5MB) */
+#define MSM_ION_HEAP_NUM	7
+#else
+#define MSM_ION_SF_SIZE		MSM_PMEM_SIZE
+#define MSM_ION_MM_SIZE		MSM_PMEM_ADSP_SIZE
+#define MSM_ION_QSECOM_SIZE	0x600000 /* (6MB) */
+#define MSM_ION_HEAP_NUM	8
+#endif
+#define MSM_ION_MM_FW_SIZE	0x200000 /* (2MB) */
+#define MSM_ION_MFC_SIZE	SZ_8K
+#define MSM_ION_AUDIO_SIZE	MSM_PMEM_AUDIO_SIZE
+
+#define MSM_LIQUID_ION_MM_SIZE (MSM_ION_MM_SIZE + 0x600000)
+#define MSM_LIQUID_ION_SF_SIZE MSM_LIQUID_PMEM_SIZE
+#define MSM_HDMI_PRIM_ION_SF_SIZE MSM_HDMI_PRIM_PMEM_SIZE
+
+#define MSM8930_FIXED_AREA_START 0xa0000000
+#define MAX_FIXED_AREA_SIZE	0x10000000
+#define MSM_MM_FW_SIZE		0x200000
+#define MSM8930_FW_START	(MSM8930_FIXED_AREA_START - MSM_MM_FW_SIZE)
+
+#else
+#define MSM_PMEM_KERNEL_EBI1_SIZE  0x110C000
+#define MSM_ION_HEAP_NUM	1
+#endif
+
+#ifdef CONFIG_KERNEL_PMEM_EBI_REGION
+static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE;
+static int __init pmem_kernel_ebi1_size_setup(char *p)
+{
+	pmem_kernel_ebi1_size = memparse(p, NULL);
+	return 0;
+}
+early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
+#endif
+
+#ifdef CONFIG_ANDROID_PMEM
+static unsigned pmem_size = MSM_PMEM_SIZE;
+static int __init pmem_size_setup(char *p)
+{
+	pmem_size = memparse(p, NULL);
+	return 0;
+}
+early_param("pmem_size", pmem_size_setup);
+
+static unsigned pmem_adsp_size = MSM_PMEM_ADSP_SIZE;
+
+static int __init pmem_adsp_size_setup(char *p)
+{
+	pmem_adsp_size = memparse(p, NULL);
+	return 0;
+}
+early_param("pmem_adsp_size", pmem_adsp_size_setup);
+
+static unsigned pmem_audio_size = MSM_PMEM_AUDIO_SIZE;
+
+static int __init pmem_audio_size_setup(char *p)
+{
+	pmem_audio_size = memparse(p, NULL);
+	return 0;
+}
+early_param("pmem_audio_size", pmem_audio_size_setup);
+#endif
+
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+static struct android_pmem_platform_data android_pmem_pdata = {
+	.name = "pmem",
+	.allocator_type = PMEM_ALLOCATORTYPE_ALLORNOTHING,
+	.cached = 1,
+	.memory_type = MEMTYPE_EBI1,
+};
+
+static struct platform_device msm8930_android_pmem_device = {
+	.name = "android_pmem",
+	.id = 0,
+	.dev = {.platform_data = &android_pmem_pdata},
+};
+
+static struct android_pmem_platform_data android_pmem_adsp_pdata = {
+	.name = "pmem_adsp",
+	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
+	.cached = 0,
+	.memory_type = MEMTYPE_EBI1,
+};
+static struct platform_device msm8930_android_pmem_adsp_device = {
+	.name = "android_pmem",
+	.id = 2,
+	.dev = { .platform_data = &android_pmem_adsp_pdata },
+};
+
+static struct android_pmem_platform_data android_pmem_audio_pdata = {
+	.name = "pmem_audio",
+	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
+	.cached = 0,
+	.memory_type = MEMTYPE_EBI1,
+};
+
+static struct platform_device msm8930_android_pmem_audio_device = {
+	.name = "android_pmem",
+	.id = 4,
+	.dev = { .platform_data = &android_pmem_audio_pdata },
+};
+#endif /* CONFIG_MSM_MULTIMEDIA_USE_ION */
+#endif /* CONFIG_ANDROID_PMEM */
+
+struct fmem_platform_data msm8930_fmem_pdata = {
+};
+
+#define DSP_RAM_BASE_8960 0x8da00000
+#define DSP_RAM_SIZE_8960 0x1800000
+static int dspcrashd_pdata_8960 = 0xDEADDEAD;
+
+static struct resource resources_dspcrashd_8960[] = {
+	{
+		.name   = "msm_dspcrashd",
+		.start  = DSP_RAM_BASE_8960,
+		.end    = DSP_RAM_BASE_8960 + DSP_RAM_SIZE_8960,
+		.flags  = IORESOURCE_DMA,
+	},
+};
+
+static struct platform_device msm_device_dspcrashd_8960 = {
+	.name           = "msm_dspcrashd",
+	.num_resources  = ARRAY_SIZE(resources_dspcrashd_8960),
+	.resource       = resources_dspcrashd_8960,
+	.dev = { .platform_data = &dspcrashd_pdata_8960 },
+};
+
+static struct memtype_reserve msm8930_reserve_table[] __initdata = {
+	[MEMTYPE_SMI] = {
+	},
+	[MEMTYPE_EBI0] = {
+		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
+	},
+	[MEMTYPE_EBI1] = {
+		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
+	},
+};
+
+
+static void __init reserve_rtb_memory(void)
+{
+#if defined(CONFIG_MSM_RTB)
+	msm8930_reserve_table[MEMTYPE_EBI1].size += msm8930_rtb_pdata.size;
+#endif
+}
+
+static void __init size_pmem_devices(void)
+{
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+	android_pmem_adsp_pdata.size = pmem_adsp_size;
+	android_pmem_pdata.size = pmem_size;
+	android_pmem_audio_pdata.size = MSM_PMEM_AUDIO_SIZE;
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
+}
+
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+static void __init reserve_memory_for(struct android_pmem_platform_data *p)
+{
+	msm8930_reserve_table[p->memory_type].size += p->size;
+}
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
+
+static void __init reserve_pmem_memory(void)
+{
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+	reserve_memory_for(&android_pmem_adsp_pdata);
+	reserve_memory_for(&android_pmem_pdata);
+	reserve_memory_for(&android_pmem_audio_pdata);
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+	msm8930_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
+#endif /*CONFIG_ANDROID_PMEM*/
+}
+
+static int msm8930_paddr_to_memtype(unsigned int paddr)
+{
+	return MEMTYPE_EBI1;
+}
+
+#define FMEM_ENABLED 0
+#ifdef CONFIG_ION_MSM
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+static struct ion_cp_heap_pdata cp_mm_msm8930_ion_pdata = {
+	.permission_type = IPT_TYPE_MM_CARVEOUT,
+	.align = PAGE_SIZE,
+	.reusable = FMEM_ENABLED,
+	.mem_is_fmem = FMEM_ENABLED,
+	.fixed_position = FIXED_MIDDLE,
+};
+
+static struct ion_cp_heap_pdata cp_mfc_msm8930_ion_pdata = {
+	.permission_type = IPT_TYPE_MFC_SHAREDMEM,
+	.align = PAGE_SIZE,
+	.reusable = 0,
+	.mem_is_fmem = FMEM_ENABLED,
+	.fixed_position = FIXED_HIGH,
+};
+
+static struct ion_co_heap_pdata co_msm8930_ion_pdata = {
+	.adjacent_mem_id = INVALID_HEAP_ID,
+	.align = PAGE_SIZE,
+	.mem_is_fmem = 0,
+};
+
+static struct ion_co_heap_pdata fw_co_msm8930_ion_pdata = {
+	.adjacent_mem_id = ION_CP_MM_HEAP_ID,
+	.align = SZ_128K,
+	.mem_is_fmem = FMEM_ENABLED,
+	.fixed_position = FIXED_LOW,
+};
+#endif
+
+/**
+ * These heaps are listed in the order they will be allocated. Due to
+ * video hardware restrictions and content protection the FW heap has to
+ * be allocated adjacent (below) the MM heap and the MFC heap has to be
+ * allocated after the MM heap to ensure MFC heap is not more than 256MB
+ * away from the base address of the FW heap.
+ * However, the order of FW heap and MM heap doesn't matter since these
+ * two heaps are taken care of by separate code to ensure they are adjacent
+ * to each other.
+ * Don't swap the order unless you know what you are doing!
+ */
+static struct ion_platform_data msm8930_ion_pdata = {
+	.nr = MSM_ION_HEAP_NUM,
+	.heaps = {
+		{
+			.id	= ION_SYSTEM_HEAP_ID,
+			.type	= ION_HEAP_TYPE_SYSTEM,
+			.name	= ION_VMALLOC_HEAP_NAME,
+		},
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+		{
+			.id	= ION_CP_MM_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CP,
+			.name	= ION_MM_HEAP_NAME,
+			.size	= MSM_ION_MM_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &cp_mm_msm8930_ion_pdata,
+		},
+		{
+			.id	= ION_MM_FIRMWARE_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.name	= ION_MM_FIRMWARE_HEAP_NAME,
+			.size	= MSM_ION_MM_FW_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &fw_co_msm8930_ion_pdata,
+		},
+		{
+			.id	= ION_CP_MFC_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CP,
+			.name	= ION_MFC_HEAP_NAME,
+			.size	= MSM_ION_MFC_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &cp_mfc_msm8930_ion_pdata,
+		},
+#ifndef CONFIG_MSM_IOMMU
+		{
+			.id	= ION_SF_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.name	= ION_SF_HEAP_NAME,
+			.size	= MSM_ION_SF_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &co_msm8930_ion_pdata,
+		},
+#endif
+		{
+			.id	= ION_IOMMU_HEAP_ID,
+			.type	= ION_HEAP_TYPE_IOMMU,
+			.name	= ION_IOMMU_HEAP_NAME,
+		},
+		{
+			.id	= ION_QSECOM_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.name	= ION_QSECOM_HEAP_NAME,
+			.size	= MSM_ION_QSECOM_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &co_msm8930_ion_pdata,
+		},
+		{
+			.id	= ION_AUDIO_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.name	= ION_AUDIO_HEAP_NAME,
+			.size	= MSM_ION_AUDIO_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &co_msm8930_ion_pdata,
+		},
+#endif
+	}
+};
+
+static struct platform_device msm8930_ion_dev = {
+	.name = "ion-msm",
+	.id = 1,
+	.dev = { .platform_data = &msm8930_ion_pdata },
+};
+#endif
+
+struct platform_device msm8930_fmem_device = {
+	.name = "fmem",
+	.id = 1,
+	.dev = { .platform_data = &msm8930_fmem_pdata },
+};
+
+static void __init reserve_mem_for_ion(enum ion_memory_types mem_type,
+				      unsigned long size)
+{
+	msm8930_reserve_table[mem_type].size += size;
+}
+
+static void __init msm8930_reserve_fixed_area(unsigned long fixed_area_size)
+{
+#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
+	int ret;
+
+	if (fixed_area_size > MAX_FIXED_AREA_SIZE)
+		panic("fixed area size is larger than %dM\n",
+			MAX_FIXED_AREA_SIZE >> 20);
+
+	reserve_info->fixed_area_size = fixed_area_size;
+	reserve_info->fixed_area_start = MSM8930_FW_START;
+
+	ret = memblock_remove(reserve_info->fixed_area_start,
+		reserve_info->fixed_area_size);
+	BUG_ON(ret);
+#endif
+}
+
+/**
+ * Reserve memory for ION and calculate amount of reusable memory for fmem.
+ * We only reserve memory for heaps that are not reusable. However, we only
+ * support one reusable heap at the moment so we ignore the reusable flag for
+ * other than the first heap with reusable flag set. Also handle special case
+ * for video heaps (MM,FW, and MFC). Video requires heaps MM and MFC to be
+ * at a higher address than FW in addition to not more than 256MB away from the
+ * base address of the firmware. This means that if MM is reusable the other
+ * two heaps must be allocated in the same region as FW. This is handled by the
+ * mem_is_fmem flag in the platform data. In addition the MM heap must be
+ * adjacent to the FW heap for content protection purposes.
+ */
+static void __init reserve_ion_memory(void)
+{
+#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
+	unsigned int i;
+	unsigned int reusable_count = 0;
+	unsigned int fixed_size = 0;
+	unsigned int fixed_low_size, fixed_middle_size, fixed_high_size;
+	unsigned long fixed_low_start, fixed_middle_start, fixed_high_start;
+
+	msm8930_fmem_pdata.size = 0;
+	msm8930_fmem_pdata.reserved_size_low = 0;
+	msm8930_fmem_pdata.reserved_size_high = 0;
+	msm8930_fmem_pdata.align = PAGE_SIZE;
+	fixed_low_size = 0;
+	fixed_middle_size = 0;
+	fixed_high_size = 0;
+
+	/* We only support 1 reusable heap. Check if more than one heap
+	 * is specified as reusable and set as non-reusable if found.
+	 */
+	for (i = 0; i < msm8930_ion_pdata.nr; ++i) {
+		const struct ion_platform_heap *heap =
+						&(msm8930_ion_pdata.heaps[i]);
+
+		if (heap->type == ION_HEAP_TYPE_CP && heap->extra_data) {
+			struct ion_cp_heap_pdata *data = heap->extra_data;
+
+			reusable_count += (data->reusable) ? 1 : 0;
+
+			if (data->reusable && reusable_count > 1) {
+				pr_err("%s: Too many heaps specified as "
+					"reusable. Heap %s was not configured "
+					"as reusable.\n", __func__, heap->name);
+				data->reusable = 0;
+			}
+		}
+	}
+
+	for (i = 0; i < msm8930_ion_pdata.nr; ++i) {
+		const struct ion_platform_heap *heap =
+						&(msm8930_ion_pdata.heaps[i]);
+
+		if (heap->extra_data) {
+			int fixed_position = NOT_FIXED;
+			int mem_is_fmem = 0;
+
+			switch (heap->type) {
+			case ION_HEAP_TYPE_CP:
+				mem_is_fmem = ((struct ion_cp_heap_pdata *)
+					heap->extra_data)->mem_is_fmem;
+				fixed_position = ((struct ion_cp_heap_pdata *)
+					heap->extra_data)->fixed_position;
+				break;
+			case ION_HEAP_TYPE_CARVEOUT:
+				mem_is_fmem = ((struct ion_co_heap_pdata *)
+					heap->extra_data)->mem_is_fmem;
+				fixed_position = ((struct ion_co_heap_pdata *)
+					heap->extra_data)->fixed_position;
+				break;
+			default:
+				break;
+			}
+
+			if (fixed_position != NOT_FIXED)
+				fixed_size += heap->size;
+			else
+				reserve_mem_for_ion(MEMTYPE_EBI1, heap->size);
+
+			if (fixed_position == FIXED_LOW)
+				fixed_low_size += heap->size;
+			else if (fixed_position == FIXED_MIDDLE)
+				fixed_middle_size += heap->size;
+			else if (fixed_position == FIXED_HIGH)
+				fixed_high_size += heap->size;
+
+			if (mem_is_fmem)
+				msm8930_fmem_pdata.size += heap->size;
+		}
+	}
+
+	if (!fixed_size)
+		return;
+
+	if (msm8930_fmem_pdata.size) {
+		msm8930_fmem_pdata.reserved_size_low = fixed_low_size;
+		msm8930_fmem_pdata.reserved_size_high = fixed_high_size;
+	}
+
+	/* Since the fixed area may be carved out of lowmem,
+	 * make sure the length is a multiple of 1M.
+	 */
+	fixed_size = (fixed_size + MSM_MM_FW_SIZE + SECTION_SIZE - 1)
+		& SECTION_MASK;
+	msm8930_reserve_fixed_area(fixed_size);
+
+	fixed_low_start = MSM8930_FIXED_AREA_START;
+	fixed_middle_start = fixed_low_start + fixed_low_size;
+	fixed_high_start = fixed_middle_start + fixed_middle_size;
+
+	for (i = 0; i < msm8930_ion_pdata.nr; ++i) {
+		struct ion_platform_heap *heap = &(msm8930_ion_pdata.heaps[i]);
+
+		if (heap->extra_data) {
+			int fixed_position = NOT_FIXED;
+
+			switch (heap->type) {
+			case ION_HEAP_TYPE_CP:
+				fixed_position = ((struct ion_cp_heap_pdata *)
+					heap->extra_data)->fixed_position;
+				break;
+			case ION_HEAP_TYPE_CARVEOUT:
+				fixed_position = ((struct ion_co_heap_pdata *)
+					heap->extra_data)->fixed_position;
+				break;
+			default:
+				break;
+			}
+
+			switch (fixed_position) {
+			case FIXED_LOW:
+				heap->base = fixed_low_start;
+				break;
+			case FIXED_MIDDLE:
+				heap->base = fixed_middle_start;
+				break;
+			case FIXED_HIGH:
+				heap->base = fixed_high_start;
+				break;
+			default:
+				break;
+			}
+		}
+	}
+#endif
+}
+
+static void __init reserve_mdp_memory(void)
+{
+	msm8930_mdp_writeback(msm8930_reserve_table);
+}
+
+static void __init msm8930_calculate_reserve_sizes(void)
+{
+	size_pmem_devices();
+	reserve_pmem_memory();
+	reserve_ion_memory();
+	reserve_mdp_memory();
+	reserve_rtb_memory();
+}
+
+static struct reserve_info msm8930_reserve_info __initdata = {
+	.memtype_reserve_table = msm8930_reserve_table,
+	.calculate_reserve_sizes = msm8930_calculate_reserve_sizes,
+	.reserve_fixed_area = msm8930_reserve_fixed_area,
+	.paddr_to_memtype = msm8930_paddr_to_memtype,
+};
+
+static int msm8930_memory_bank_size(void)
+{
+	return 1<<29;
+}
+
+static void __init locate_unstable_memory(void)
+{
+	struct membank *mb = &meminfo.bank[meminfo.nr_banks - 1];
+	unsigned long bank_size;
+	unsigned long low, high;
+
+	bank_size = msm8930_memory_bank_size();
+	low = meminfo.bank[0].start;
+	high = mb->start + mb->size;
+
+	/* Check if 32 bit overflow occured */
+	if (high < mb->start)
+		high -= PAGE_SIZE;
+
+	if (high < MAX_FIXED_AREA_SIZE + MSM8930_FIXED_AREA_START)
+		panic("fixed area extends beyond end of memory\n");
+
+	low &= ~(bank_size - 1);
+
+	if (high - low <= bank_size)
+		goto no_dmm;
+
+	msm8930_reserve_info.bank_size = bank_size;
+#ifdef CONFIG_ENABLE_DMM
+	msm8930_reserve_info.low_unstable_address = mb->start -
+					MIN_MEMORY_BLOCK_SIZE + mb->size;
+	msm8930_reserve_info.max_unstable_size = MIN_MEMORY_BLOCK_SIZE;
+	pr_info("low unstable address %lx max size %lx bank size %lx\n",
+		msm8930_reserve_info.low_unstable_address,
+		msm8930_reserve_info.max_unstable_size,
+		msm8930_reserve_info.bank_size);
+	return;
+#endif
+no_dmm:
+	msm8930_reserve_info.low_unstable_address = high;
+	msm8930_reserve_info.max_unstable_size = 0;
+}
+
+static void __init place_movable_zone(void)
+{
+#ifdef CONFIG_ENABLE_DMM
+	movable_reserved_start = msm8930_reserve_info.low_unstable_address;
+	movable_reserved_size = msm8930_reserve_info.max_unstable_size;
+	pr_info("movable zone start %lx size %lx\n",
+		movable_reserved_start, movable_reserved_size);
+#endif
+}
+
+static void __init msm8930_early_memory(void)
+{
+	reserve_info = &msm8930_reserve_info;
+	locate_unstable_memory();
+	place_movable_zone();
+}
+
+static void __init msm8930_reserve(void)
+{
+	msm_reserve();
+	if (msm8930_fmem_pdata.size) {
+#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
+		if (reserve_info->fixed_area_size) {
+			msm8930_fmem_pdata.phys =
+				reserve_info->fixed_area_start + MSM_MM_FW_SIZE;
+		pr_info("mm fw at %lx (fixed) size %x\n",
+			reserve_info->fixed_area_start, MSM_MM_FW_SIZE);
+		pr_info("fmem start %lx (fixed) size %lx\n",
+			msm8930_fmem_pdata.phys, msm8930_fmem_pdata.size);
+		}
+#endif
+	}
+}
+
+static int msm8930_change_memory_power(u64 start, u64 size,
+	int change_type)
+{
+	return soc_change_memory_power(start, size, change_type);
+}
+
+static void __init msm8930_allocate_memory_regions(void)
+{
+	msm8930_allocate_fb_region();
+}
+
+#ifdef CONFIG_WCD9304_CODEC
+
+#define SITAR_INTERRUPT_BASE (NR_MSM_IRQS + NR_GPIO_IRQS + NR_PM8921_IRQS)
+
+/* Micbias setting is based on 8660 CDP/MTP/FLUID requirement
+ * 4 micbiases are used to power various analog and digital
+ * microphones operating at 1800 mV. Technically, all micbiases
+ * can source from single cfilter since all microphones operate
+ * at the same voltage level. The arrangement below is to make
+ * sure all cfilters are exercised. LDO_H regulator ouput level
+ * does not need to be as high as 2.85V. It is choosen for
+ * microphone sensitivity purpose.
+ */
+static struct wcd9xxx_pdata sitar_platform_data = {
+		.slimbus_slave_device = {
+		.name = "sitar-slave",
+		.e_addr = {0, 0, 0x00, 0, 0x17, 2},
+	},
+	.irq = MSM_GPIO_TO_INT(62),
+	.irq_base = SITAR_INTERRUPT_BASE,
+	.num_irqs = NR_WCD9XXX_IRQS,
+	.reset_gpio = 42,
+	.micbias = {
+		.ldoh_v = SITAR_LDOH_2P85_V,
+		.cfilt1_mv = 1800,
+		.cfilt2_mv = 1800,
+		.bias1_cfilt_sel = SITAR_CFILT1_SEL,
+		.bias2_cfilt_sel = SITAR_CFILT2_SEL,
+	},
+	.regulator = {
+	{
+		.name = "CDC_VDD_CP",
+		.min_uV = 1950000,
+		.max_uV = 2200000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_RX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_RX_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_TX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_TX_CUR_MAX,
+	},
+	{
+		.name = "VDDIO_CDC",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_VDDIO_CDC_CUR_MAX,
+	},
+	{
+		.name = "VDDD_CDC_D",
+		.min_uV = 1200000,
+		.max_uV = 1200000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_A_1P2V",
+		.min_uV = 1200000,
+		.max_uV = 1200000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
+	},
+	},
+};
+
+static struct slim_device msm_slim_sitar = {
+	.name = "sitar-slim",
+	.e_addr = {0, 1, 0x00, 0, 0x17, 2},
+	.dev = {
+	.platform_data = &sitar_platform_data,
+	},
+};
+
+static struct wcd9xxx_pdata sitar1p1_platform_data = {
+		.slimbus_slave_device = {
+		.name = "sitar-slave",
+		.e_addr = {0, 0, 0x70, 0, 0x17, 2},
+	},
+	.irq = MSM_GPIO_TO_INT(62),
+	.irq_base = SITAR_INTERRUPT_BASE,
+	.num_irqs = NR_WCD9XXX_IRQS,
+	.reset_gpio = 42,
+	.micbias = {
+		.ldoh_v = SITAR_LDOH_2P85_V,
+		.cfilt1_mv = 1800,
+		.cfilt2_mv = 1800,
+		.bias1_cfilt_sel = SITAR_CFILT1_SEL,
+		.bias2_cfilt_sel = SITAR_CFILT2_SEL,
+	},
+	.regulator = {
+	{
+		.name = "CDC_VDD_CP",
+		.min_uV = 1950000,
+		.max_uV = 2200000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_RX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_RX_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_TX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_TX_CUR_MAX,
+	},
+	{
+		.name = "VDDIO_CDC",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_VDDIO_CDC_CUR_MAX,
+	},
+	{
+		.name = "VDDD_CDC_D",
+		.min_uV = 1200000,
+		.max_uV = 1200000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_A_1P2V",
+		.min_uV = 1200000,
+		.max_uV = 1200000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
+	},
+	},
+};
+
+static struct slim_device msm_slim_sitar1p1 = {
+	.name = "sitar1p1-slim",
+	.e_addr = {0, 1, 0x70, 0, 0x17, 2},
+	.dev = {
+	.platform_data = &sitar1p1_platform_data,
+	},
+};
+#endif
+
+
+static struct slim_boardinfo msm_slim_devices[] = {
+#ifdef CONFIG_WCD9304_CODEC
+	{
+		.bus_num = 1,
+		.slim_slave = &msm_slim_sitar,
+	},
+	{
+		.bus_num = 1,
+		.slim_slave = &msm_slim_sitar1p1,
+	},
+#endif
+	/* add more slimbus slaves as needed */
+};
+
+#define MSM_WCNSS_PHYS	0x03000000
+#define MSM_WCNSS_SIZE	0x280000
+
+static struct resource resources_wcnss_wlan[] = {
+	{
+		.start	= RIVA_APPS_WLAN_RX_DATA_AVAIL_IRQ,
+		.end	= RIVA_APPS_WLAN_RX_DATA_AVAIL_IRQ,
+		.name	= "wcnss_wlanrx_irq",
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= RIVA_APPS_WLAN_DATA_XFER_DONE_IRQ,
+		.end	= RIVA_APPS_WLAN_DATA_XFER_DONE_IRQ,
+		.name	= "wcnss_wlantx_irq",
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM_WCNSS_PHYS,
+		.end	= MSM_WCNSS_PHYS + MSM_WCNSS_SIZE - 1,
+		.name	= "wcnss_mmio",
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= 84,
+		.end	= 88,
+		.name	= "wcnss_gpios_5wire",
+		.flags	= IORESOURCE_IO,
+	},
+};
+
+static struct qcom_wcnss_opts qcom_wcnss_pdata = {
+	.has_48mhz_xo	= 1,
+};
+
+static struct platform_device msm_device_wcnss_wlan = {
+	.name		= "wcnss_wlan",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(resources_wcnss_wlan),
+	.resource	= resources_wcnss_wlan,
+	.dev		= {.platform_data = &qcom_wcnss_pdata},
+};
+
+#ifdef CONFIG_QSEECOM
+/* qseecom bus scaling */
+static struct msm_bus_vectors qseecom_clks_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ib = 0,
+		.ab = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_SPDM,
+		.dst = MSM_BUS_SLAVE_SPDM,
+		.ib = 0,
+		.ab = 0,
+	},
+};
+
+static struct msm_bus_vectors qseecom_enable_dfab_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ib = (492 * 8) * 1000000UL,
+		.ab = (492 * 8) *  100000UL,
+	},
+	{
+		.src = MSM_BUS_MASTER_SPDM,
+		.dst = MSM_BUS_SLAVE_SPDM,
+		.ib = 0,
+		.ab = 0,
+	},
+};
+
+static struct msm_bus_vectors qseecom_enable_sfpb_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ib = 0,
+		.ab = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_SPDM,
+		.dst = MSM_BUS_SLAVE_SPDM,
+		.ib = (64 * 8) * 1000000UL,
+		.ab = (64 * 8) *  100000UL,
+	},
+};
+
+static struct msm_bus_paths qseecom_hw_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(qseecom_clks_init_vectors),
+		qseecom_clks_init_vectors,
+	},
+	{
+		ARRAY_SIZE(qseecom_enable_dfab_vectors),
+		qseecom_enable_sfpb_vectors,
+	},
+	{
+		ARRAY_SIZE(qseecom_enable_sfpb_vectors),
+		qseecom_enable_sfpb_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata qseecom_bus_pdata = {
+	qseecom_hw_bus_scale_usecases,
+	ARRAY_SIZE(qseecom_hw_bus_scale_usecases),
+	.name = "qsee",
+};
+
+static struct platform_device qseecom_device = {
+	.name		= "qseecom",
+	.id		= 0,
+	.dev		= {
+		.platform_data = &qseecom_bus_pdata,
+	},
+};
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+
+#define QCE_SIZE		0x10000
+#define QCE_0_BASE		0x18500000
+
+#define QCE_HW_KEY_SUPPORT	0
+#define QCE_SHA_HMAC_SUPPORT	1
+#define QCE_SHARE_CE_RESOURCE	1
+#define QCE_CE_SHARED		0
+
+static struct resource qcrypto_resources[] = {
+	[0] = {
+		.start = QCE_0_BASE,
+		.end = QCE_0_BASE + QCE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.name = "crypto_channels",
+		.start = DMOV_CE_IN_CHAN,
+		.end = DMOV_CE_OUT_CHAN,
+		.flags = IORESOURCE_DMA,
+	},
+	[2] = {
+		.name = "crypto_crci_in",
+		.start = DMOV_CE_IN_CRCI,
+		.end = DMOV_CE_IN_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+	[3] = {
+		.name = "crypto_crci_out",
+		.start = DMOV_CE_OUT_CRCI,
+		.end = DMOV_CE_OUT_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static struct resource qcedev_resources[] = {
+	[0] = {
+		.start = QCE_0_BASE,
+		.end = QCE_0_BASE + QCE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.name = "crypto_channels",
+		.start = DMOV_CE_IN_CHAN,
+		.end = DMOV_CE_OUT_CHAN,
+		.flags = IORESOURCE_DMA,
+	},
+	[2] = {
+		.name = "crypto_crci_in",
+		.start = DMOV_CE_IN_CRCI,
+		.end = DMOV_CE_IN_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+	[3] = {
+		.name = "crypto_crci_out",
+		.start = DMOV_CE_OUT_CRCI,
+		.end = DMOV_CE_OUT_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
+
+static struct msm_ce_hw_support qcrypto_ce_hw_suppport = {
+	.ce_shared = QCE_CE_SHARED,
+	.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
+	.hw_key_support = QCE_HW_KEY_SUPPORT,
+	.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+};
+
+static struct platform_device qcrypto_device = {
+	.name		= "qcrypto",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(qcrypto_resources),
+	.resource	= qcrypto_resources,
+	.dev		= {
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+		.platform_data = &qcrypto_ce_hw_suppport,
+	},
+};
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+
+static struct msm_ce_hw_support qcedev_ce_hw_suppport = {
+	.ce_shared = QCE_CE_SHARED,
+	.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
+	.hw_key_support = QCE_HW_KEY_SUPPORT,
+	.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+};
+
+static struct platform_device qcedev_device = {
+	.name		= "qce",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(qcedev_resources),
+	.resource	= qcedev_resources,
+	.dev		= {
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+		.platform_data = &qcedev_ce_hw_suppport,
+	},
+};
+#endif
+
+#define MDM2AP_ERRFATAL			70
+#define AP2MDM_ERRFATAL			95
+#define MDM2AP_STATUS			69
+#define AP2MDM_STATUS			94
+#define AP2MDM_PMIC_RESET_N		80
+#define AP2MDM_KPDPWR_N			81
+
+static struct resource mdm_resources[] = {
+	{
+		.start	= MDM2AP_ERRFATAL,
+		.end	= MDM2AP_ERRFATAL,
+		.name	= "MDM2AP_ERRFATAL",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= AP2MDM_ERRFATAL,
+		.end	= AP2MDM_ERRFATAL,
+		.name	= "AP2MDM_ERRFATAL",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= MDM2AP_STATUS,
+		.end	= MDM2AP_STATUS,
+		.name	= "MDM2AP_STATUS",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= AP2MDM_STATUS,
+		.end	= AP2MDM_STATUS,
+		.name	= "AP2MDM_STATUS",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= AP2MDM_PMIC_RESET_N,
+		.end	= AP2MDM_PMIC_RESET_N,
+		.name	= "AP2MDM_PMIC_RESET_N",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= AP2MDM_KPDPWR_N,
+		.end	= AP2MDM_KPDPWR_N,
+		.name	= "AP2MDM_KPDPWR_N",
+		.flags	= IORESOURCE_IO,
+	},
+};
+
+static struct mdm_platform_data mdm_platform_data = {
+	.mdm_version = "2.5",
+};
+
+static struct platform_device mdm_device = {
+	.name		= "mdm2_modem",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(mdm_resources),
+	.resource	= mdm_resources,
+	.dev		= {
+		.platform_data = &mdm_platform_data,
+	},
+};
+
+static struct platform_device *mdm_devices[] __initdata = {
+	&mdm_device,
+};
+
+#ifdef CONFIG_MSM_MPM
+static uint16_t msm_mpm_irqs_m2a[MSM_MPM_NR_MPM_IRQS] __initdata = {
+	[1] = MSM_GPIO_TO_INT(46),
+	[2] = MSM_GPIO_TO_INT(150),
+	[4] = MSM_GPIO_TO_INT(103),
+	[5] = MSM_GPIO_TO_INT(104),
+	[6] = MSM_GPIO_TO_INT(105),
+	[7] = MSM_GPIO_TO_INT(106),
+	[8] = MSM_GPIO_TO_INT(107),
+	[9] = MSM_GPIO_TO_INT(7),
+	[10] = MSM_GPIO_TO_INT(11),
+	[11] = MSM_GPIO_TO_INT(15),
+	[12] = MSM_GPIO_TO_INT(19),
+	[13] = MSM_GPIO_TO_INT(23),
+	[14] = MSM_GPIO_TO_INT(27),
+	[15] = MSM_GPIO_TO_INT(31),
+	[16] = MSM_GPIO_TO_INT(35),
+	[19] = MSM_GPIO_TO_INT(90),
+	[20] = MSM_GPIO_TO_INT(92),
+	[23] = MSM_GPIO_TO_INT(85),
+	[24] = MSM_GPIO_TO_INT(83),
+	[25] = USB1_HS_IRQ,
+	[27] = HDMI_IRQ,
+	[29] = MSM_GPIO_TO_INT(10),
+	[30] = MSM_GPIO_TO_INT(102),
+	[31] = MSM_GPIO_TO_INT(81),
+	[32] = MSM_GPIO_TO_INT(78),
+	[33] = MSM_GPIO_TO_INT(94),
+	[34] = MSM_GPIO_TO_INT(72),
+	[35] = MSM_GPIO_TO_INT(39),
+	[36] = MSM_GPIO_TO_INT(43),
+	[37] = MSM_GPIO_TO_INT(61),
+	[38] = MSM_GPIO_TO_INT(50),
+	[39] = MSM_GPIO_TO_INT(42),
+	[41] = MSM_GPIO_TO_INT(62),
+	[42] = MSM_GPIO_TO_INT(76),
+	[43] = MSM_GPIO_TO_INT(75),
+	[44] = MSM_GPIO_TO_INT(70),
+	[45] = MSM_GPIO_TO_INT(69),
+	[46] = MSM_GPIO_TO_INT(67),
+	[47] = MSM_GPIO_TO_INT(65),
+	[48] = MSM_GPIO_TO_INT(58),
+	[49] = MSM_GPIO_TO_INT(54),
+	[50] = MSM_GPIO_TO_INT(52),
+	[51] = MSM_GPIO_TO_INT(49),
+	[52] = MSM_GPIO_TO_INT(40),
+	[53] = MSM_GPIO_TO_INT(37),
+	[54] = MSM_GPIO_TO_INT(24),
+	[55] = MSM_GPIO_TO_INT(14),
+};
+
+static uint16_t msm_mpm_bypassed_apps_irqs[] __initdata = {
+	TLMM_MSM_SUMMARY_IRQ,
+	RPM_APCC_CPU0_GP_HIGH_IRQ,
+	RPM_APCC_CPU0_GP_MEDIUM_IRQ,
+	RPM_APCC_CPU0_GP_LOW_IRQ,
+	RPM_APCC_CPU0_WAKE_UP_IRQ,
+	RPM_APCC_CPU1_GP_HIGH_IRQ,
+	RPM_APCC_CPU1_GP_MEDIUM_IRQ,
+	RPM_APCC_CPU1_GP_LOW_IRQ,
+	RPM_APCC_CPU1_WAKE_UP_IRQ,
+	MSS_TO_APPS_IRQ_0,
+	MSS_TO_APPS_IRQ_1,
+	MSS_TO_APPS_IRQ_2,
+	MSS_TO_APPS_IRQ_3,
+	MSS_TO_APPS_IRQ_4,
+	MSS_TO_APPS_IRQ_5,
+	MSS_TO_APPS_IRQ_6,
+	MSS_TO_APPS_IRQ_7,
+	MSS_TO_APPS_IRQ_8,
+	MSS_TO_APPS_IRQ_9,
+	LPASS_SCSS_GP_LOW_IRQ,
+	LPASS_SCSS_GP_MEDIUM_IRQ,
+	LPASS_SCSS_GP_HIGH_IRQ,
+	SPS_MTI_30,
+	SPS_MTI_31,
+	RIVA_APSS_SPARE_IRQ,
+	RIVA_APPS_WLAN_SMSM_IRQ,
+	RIVA_APPS_WLAN_RX_DATA_AVAIL_IRQ,
+	RIVA_APPS_WLAN_DATA_XFER_DONE_IRQ,
+};
+
+struct msm_mpm_device_data msm8930_mpm_dev_data __initdata = {
+	.irqs_m2a = msm_mpm_irqs_m2a,
+	.irqs_m2a_size = ARRAY_SIZE(msm_mpm_irqs_m2a),
+	.bypassed_apps_irqs = msm_mpm_bypassed_apps_irqs,
+	.bypassed_apps_irqs_size = ARRAY_SIZE(msm_mpm_bypassed_apps_irqs),
+	.mpm_request_reg_base = MSM_RPM_BASE + 0x9d8,
+	.mpm_status_reg_base = MSM_RPM_BASE + 0xdf8,
+	.mpm_apps_ipc_reg = MSM_APCS_GCC_BASE + 0x008,
+	.mpm_apps_ipc_val =  BIT(1),
+	.mpm_ipc_irq = RPM_APCC_CPU0_GP_MEDIUM_IRQ,
+
+};
+#endif
+
+#define MSM_SHARED_RAM_PHYS 0x80000000
+
+static void __init msm8930_map_io(void)
+{
+	msm_shared_ram_phys = MSM_SHARED_RAM_PHYS;
+	msm_map_msm8930_io();
+
+	if (socinfo_init() < 0)
+		pr_err("socinfo_init() failed!\n");
+}
+
+static void __init msm8930_init_irq(void)
+{
+	struct msm_mpm_device_data *data = NULL;
+#ifdef CONFIG_MSM_MPM
+	data = &msm8930_mpm_dev_data;
+#endif
+
+	msm_mpm_irq_extn_init(data);
+	gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE,
+						(void *)MSM_QGIC_CPU_BASE);
+}
+
+static void __init msm8930_init_buses(void)
+{
+#ifdef CONFIG_MSM_BUS_SCALING
+	msm_bus_rpm_set_mt_mask();
+	msm_bus_8930_apps_fabric_pdata.rpm_enabled = 1;
+	msm_bus_8930_sys_fabric_pdata.rpm_enabled = 1;
+	msm_bus_8930_mm_fabric_pdata.rpm_enabled = 1;
+	msm_bus_8930_apps_fabric.dev.platform_data =
+		&msm_bus_8930_apps_fabric_pdata;
+	msm_bus_8930_sys_fabric.dev.platform_data =
+		&msm_bus_8930_sys_fabric_pdata;
+	msm_bus_8930_mm_fabric.dev.platform_data =
+		&msm_bus_8930_mm_fabric_pdata;
+	msm_bus_8930_sys_fpb.dev.platform_data = &msm_bus_8930_sys_fpb_pdata;
+	msm_bus_8930_cpss_fpb.dev.platform_data = &msm_bus_8930_cpss_fpb_pdata;
+#endif
+}
+
+static struct msm_spi_platform_data msm8960_qup_spi_gsbi1_pdata = {
+	.max_clock_speed = 15060000,
+};
+
+#ifdef CONFIG_USB_MSM_OTG_72K
+static struct msm_otg_platform_data msm_otg_pdata;
+#else
+#ifdef CONFIG_MSM_BUS_SCALING
+/* Bandwidth requests (zero) if no vote placed */
+static struct msm_bus_vectors usb_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+/* Bus bandwidth requests in Bytes/sec */
+static struct msm_bus_vectors usb_max_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 60000000,		/* At least 480Mbps on bus. */
+		.ib = 960000000,	/* MAX bursts rate */
+	},
+};
+
+static struct msm_bus_paths usb_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(usb_init_vectors),
+		usb_init_vectors,
+	},
+	{
+		ARRAY_SIZE(usb_max_vectors),
+		usb_max_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata usb_bus_scale_pdata = {
+	usb_bus_scale_usecases,
+	ARRAY_SIZE(usb_bus_scale_usecases),
+	.name = "usb",
+};
+#endif
+
+static struct msm_otg_platform_data msm_otg_pdata = {
+	.mode			= USB_OTG,
+	.otg_control		= OTG_PMIC_CONTROL,
+	.phy_type		= SNPS_28NM_INTEGRATED_PHY,
+	.pmic_id_irq		= PM8038_USB_ID_IN_IRQ(PM8038_IRQ_BASE),
+	.power_budget		= 750,
+#ifdef CONFIG_MSM_BUS_SCALING
+	.bus_scale_table	= &usb_bus_scale_pdata,
+#endif
+};
+#endif
+
+#define PID_MAGIC_ID		0x71432909
+#define SERIAL_NUM_MAGIC_ID	0x61945374
+#define SERIAL_NUMBER_LENGTH	127
+#define DLOAD_USB_BASE_ADD	0x2A03F0C8
+
+struct magic_num_struct {
+	uint32_t pid;
+	uint32_t serial_num;
+};
+
+struct dload_struct {
+	uint32_t	reserved1;
+	uint32_t	reserved2;
+	uint32_t	reserved3;
+	uint16_t	reserved4;
+	uint16_t	pid;
+	char		serial_number[SERIAL_NUMBER_LENGTH];
+	uint16_t	reserved5;
+	struct magic_num_struct magic_struct;
+};
+
+static int usb_diag_update_pid_and_serial_num(uint32_t pid, const char *snum)
+{
+	struct dload_struct __iomem *dload = 0;
+
+	dload = ioremap(DLOAD_USB_BASE_ADD, sizeof(*dload));
+	if (!dload) {
+		pr_err("%s: cannot remap I/O memory region: %08x\n",
+					__func__, DLOAD_USB_BASE_ADD);
+		return -ENXIO;
+	}
+
+	pr_debug("%s: dload:%p pid:%x serial_num:%s\n",
+				__func__, dload, pid, snum);
+	/* update pid */
+	dload->magic_struct.pid = PID_MAGIC_ID;
+	dload->pid = pid;
+
+	/* update serial number */
+	dload->magic_struct.serial_num = 0;
+	if (!snum) {
+		memset(dload->serial_number, 0, SERIAL_NUMBER_LENGTH);
+		goto out;
+	}
+
+	dload->magic_struct.serial_num = SERIAL_NUM_MAGIC_ID;
+	strlcpy(dload->serial_number, snum, SERIAL_NUMBER_LENGTH);
+out:
+	iounmap(dload);
+	return 0;
+}
+
+static struct android_usb_platform_data android_usb_pdata = {
+	.update_pid_and_serial_num = usb_diag_update_pid_and_serial_num,
+};
+
+static struct platform_device android_usb_device = {
+	.name	= "android_usb",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &android_usb_pdata,
+	},
+};
+
+static uint8_t spm_wfi_cmd_sequence[] __initdata = {
+	0x03, 0x0f,
+};
+
+static uint8_t spm_power_collapse_without_rpm[] __initdata = {
+	0x00, 0x24, 0x54, 0x10,
+	0x09, 0x03, 0x01,
+	0x10, 0x54, 0x30, 0x0C,
+	0x24, 0x30, 0x0f,
+};
+
+static uint8_t spm_power_collapse_with_rpm[] __initdata = {
+	0x00, 0x24, 0x54, 0x10,
+	0x09, 0x07, 0x01, 0x0B,
+	0x10, 0x54, 0x30, 0x0C,
+	0x24, 0x30, 0x0f,
+};
+
+static struct msm_spm_seq_entry msm_spm_seq_list[] __initdata = {
+	[0] = {
+		.mode = MSM_SPM_MODE_CLOCK_GATING,
+		.notify_rpm = false,
+		.cmd = spm_wfi_cmd_sequence,
+	},
+	[1] = {
+		.mode = MSM_SPM_MODE_POWER_COLLAPSE,
+		.notify_rpm = false,
+		.cmd = spm_power_collapse_without_rpm,
+	},
+	[2] = {
+		.mode = MSM_SPM_MODE_POWER_COLLAPSE,
+		.notify_rpm = true,
+		.cmd = spm_power_collapse_with_rpm,
+	},
+};
+
+static struct msm_spm_platform_data msm_spm_data[] __initdata = {
+	[0] = {
+		.reg_base_addr = MSM_SAW0_BASE,
+		.reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F,
+#if defined(CONFIG_MSM_AVS_HW)
+		.reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x00,
+		.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
+#endif
+		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
+		.vctl_timeout_us = 50,
+		.num_modes = ARRAY_SIZE(msm_spm_seq_list),
+		.modes = msm_spm_seq_list,
+	},
+	[1] = {
+		.reg_base_addr = MSM_SAW1_BASE,
+		.reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F,
+#if defined(CONFIG_MSM_AVS_HW)
+		.reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x00,
+		.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
+#endif
+		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
+		.vctl_timeout_us = 50,
+		.num_modes = ARRAY_SIZE(msm_spm_seq_list),
+		.modes = msm_spm_seq_list,
+	},
+};
+
+static uint8_t l2_spm_wfi_cmd_sequence[] __initdata = {
+	0x00, 0x20, 0x03, 0x20,
+	0x00, 0x0f,
+};
+
+static uint8_t l2_spm_gdhs_cmd_sequence[] __initdata = {
+	0x00, 0x20, 0x34, 0x64,
+	0x48, 0x07, 0x48, 0x20,
+	0x50, 0x64, 0x04, 0x34,
+	0x50, 0x0f,
+};
+static uint8_t l2_spm_power_off_cmd_sequence[] __initdata = {
+	0x00, 0x10, 0x34, 0x64,
+	0x48, 0x07, 0x48, 0x10,
+	0x50, 0x64, 0x04, 0x34,
+	0x50, 0x0F,
+};
+
+static struct msm_spm_seq_entry msm_spm_l2_seq_list[] __initdata = {
+	[0] = {
+		.mode = MSM_SPM_L2_MODE_RETENTION,
+		.notify_rpm = false,
+		.cmd = l2_spm_wfi_cmd_sequence,
+	},
+	[1] = {
+		.mode = MSM_SPM_L2_MODE_GDHS,
+		.notify_rpm = true,
+		.cmd = l2_spm_gdhs_cmd_sequence,
+	},
+	[2] = {
+		.mode = MSM_SPM_L2_MODE_POWER_COLLAPSE,
+		.notify_rpm = true,
+		.cmd = l2_spm_power_off_cmd_sequence,
+	},
+};
+
+static struct msm_spm_platform_data msm_spm_l2_data[] __initdata = {
+	[0] = {
+		.reg_base_addr = MSM_SAW_L2_BASE,
+		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x00,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x00A000AE,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x00A00020,
+		.modes = msm_spm_l2_seq_list,
+		.num_modes = ARRAY_SIZE(msm_spm_l2_seq_list),
+	},
+};
+
+#define ISA1200_HAP_EN_GPIO	77
+#define ISA1200_HAP_LEN_GPIO	78
+#define ISA1200_HAP_CLK		PM8038_GPIO_PM_TO_SYS(7)
+
+static int isa1200_power(int on)
+{
+	int rc = 0;
+
+	gpio_set_value_cansleep(ISA1200_HAP_CLK, !!on);
+
+	if (on)
+		rc = pm8xxx_aux_clk_control(CLK_MP3_1, XO_DIV_1, true);
+	else
+		rc = pm8xxx_aux_clk_control(CLK_MP3_1, XO_DIV_NONE, true);
+
+	if (rc) {
+		pr_err("%s: unable to write aux clock register(%d)\n",
+			__func__, rc);
+	}
+
+	return rc;
+}
+
+static int isa1200_dev_setup(bool enable)
+{
+	int rc = 0;
+
+	if (!enable)
+		goto fail_gpio_dir;
+
+	rc = gpio_request(ISA1200_HAP_CLK, "haptics_clk");
+	if (rc) {
+		pr_err("%s: gpio_request for %d gpio failed rc(%d)\n",
+					__func__, ISA1200_HAP_CLK, rc);
+		goto fail_gpio_req;
+	}
+
+	rc = gpio_direction_output(ISA1200_HAP_CLK, 0);
+	if (rc) {
+		pr_err("%s: gpio_direction_output failed for %d gpio rc(%d)\n",
+						__func__, ISA1200_HAP_CLK, rc);
+		goto fail_gpio_dir;
+	}
+
+	return 0;
+
+fail_gpio_dir:
+	gpio_free(ISA1200_HAP_CLK);
+fail_gpio_req:
+	return rc;
+
+}
+
+static struct isa1200_regulator isa1200_reg_data[] = {
+	{
+		.name = "vddp",
+		.min_uV = ISA_I2C_VTG_MIN_UV,
+		.max_uV = ISA_I2C_VTG_MAX_UV,
+		.load_uA = ISA_I2C_CURR_UA,
+	},
+	{
+		.name = "vcc_i2c",
+		.min_uV = ISA_I2C_VTG_MIN_UV,
+		.max_uV = ISA_I2C_VTG_MAX_UV,
+		.load_uA = ISA_I2C_CURR_UA,
+	},
+};
+
+static struct isa1200_platform_data isa1200_1_pdata = {
+	.name = "vibrator",
+	.dev_setup = isa1200_dev_setup,
+	.power_on = isa1200_power,
+	.hap_en_gpio = ISA1200_HAP_EN_GPIO,
+	.hap_len_gpio = ISA1200_HAP_LEN_GPIO,
+	.max_timeout = 15000,
+	.mode_ctrl = PWM_GEN_MODE,
+	.pwm_fd = {
+		.pwm_div = 256,
+	},
+	.is_erm = false,
+	.smart_en = true,
+	.ext_clk_en = true,
+	.chip_en = 1,
+	.regulator_info = isa1200_reg_data,
+	.num_regulators = ARRAY_SIZE(isa1200_reg_data),
+};
+
+static struct i2c_board_info msm_isa1200_board_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("isa1200_1", 0x90>>1),
+		.platform_data = &isa1200_1_pdata,
+	},
+};
+
+#define MXT_TS_GPIO_IRQ			11
+#define MXT_TS_RESET_GPIO		52
+
+static const u8 mxt_config_data_8930[] = {
+	/* T6 Object */
+	 0, 0, 0, 0, 0, 0,
+	/* T38 Object */
+	 15, 3, 0, 15, 12, 11, 0, 0,
+	/* T7 Object */
+	32, 16, 50,
+	/* T8 Object */
+	 30, 0, 5, 1, 0, 0, 8, 8, 0, 0,
+	/* T9 Object */
+	 131, 0, 0, 19, 11, 0, 16, 43, 2, 3,
+	 10, 7, 2, 0, 4, 5, 35, 10, 43, 4,
+	 54, 2, 15, 32, 38, 38, 143, 40, 143, 80,
+	 7, 9, 50, 50, 2,
+	/* T15 Object */
+	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	 0,
+	/* T18 Object */
+	 0, 0,
+	/* T19 Object */
+	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	 0, 0, 0, 0, 0, 0,
+	/* T23 Object */
+	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	 0, 0, 0, 0, 0,
+	/* T25 Object */
+	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	 0, 0, 0, 0,
+	/* T40 Object */
+	 0, 0, 0, 0, 0,
+	/* T42 Object */
+	 0, 0, 0, 0, 0, 0, 0, 0,
+	/* T46 Object */
+	 0, 3, 8, 16, 0, 0, 1, 0, 0,
+	/* T47 Object */
+	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	/* T48 Object */
+	 0, 0, 8, 0, 0, 0, 0, 0, 0, 0,
+	 0, 0, 0, 0, 0, 0, 0, 100, 4, 64,
+	 0, 0, 5, 42, 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,
+};
+
+static ssize_t mxt224e_vkeys_show(struct kobject *kobj,
+			struct kobj_attribute *attr, char *buf)
+{
+	return snprintf(buf, 200,
+	__stringify(EV_KEY) ":" __stringify(KEY_BACK) ":57:1030:90:90"
+	":" __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":206:1030:90:90"
+	":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":366:1030:90:90"
+	":" __stringify(EV_KEY) ":" __stringify(KEY_SEARCH) ":503:1030:90:90"
+	"\n");
+}
+
+static struct kobj_attribute mxt224e_vkeys_attr = {
+	.attr = {
+		.mode = S_IRUGO,
+	},
+	.show = &mxt224e_vkeys_show,
+};
+
+static struct attribute *mxt224e_properties_attrs[] = {
+	&mxt224e_vkeys_attr.attr,
+	NULL
+};
+
+static struct attribute_group mxt224e_properties_attr_group = {
+	.attrs = mxt224e_properties_attrs,
+};
+
+static void mxt_init_vkeys_8930(void)
+{
+	int rc = 0;
+	static struct kobject *mxt224e_properties_kobj;
+
+	mxt224e_vkeys_attr.attr.name = "virtualkeys.atmel_mxt_ts";
+	mxt224e_properties_kobj = kobject_create_and_add("board_properties",
+								NULL);
+	if (mxt224e_properties_kobj)
+		rc = sysfs_create_group(mxt224e_properties_kobj,
+					&mxt224e_properties_attr_group);
+	if (!mxt224e_properties_kobj || rc)
+		pr_err("%s: failed to create board_properties\n",
+				__func__);
+
+	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_array		= mxt_config_array,
+	.config_array_size	= ARRAY_SIZE(mxt_config_array),
+	.panel_minx		= 0,
+	.panel_maxx		= 566,
+	.panel_miny		= 0,
+	.panel_maxy		= 1067,
+	.disp_minx		= 0,
+	.disp_maxx		= 540,
+	.disp_miny		= 0,
+	.disp_maxy		= 960,
+	.irqflags		= IRQF_TRIGGER_FALLING,
+#ifdef MSM8930_PHASE_2
+	.digital_pwr_regulator	= true,
+#endif
+	.i2c_pull_up		= true,
+	.reset_gpio		= MXT_TS_RESET_GPIO,
+	.irq_gpio		= MXT_TS_GPIO_IRQ,
+};
+
+static struct i2c_board_info mxt_device_info_8930[] __initdata = {
+	{
+		I2C_BOARD_INFO("atmel_mxt_ts", 0x4a),
+		.platform_data = &mxt_platform_data_8930,
+		.irq = MSM_GPIO_TO_INT(MXT_TS_GPIO_IRQ),
+	},
+};
+
+#ifdef MSM8930_PHASE_2
+
+#define GPIO_VOLUME_UP		PM8038_GPIO_PM_TO_SYS(3)
+#define GPIO_VOLUME_DOWN	PM8038_GPIO_PM_TO_SYS(8)
+#define GPIO_CAMERA_SNAPSHOT	PM8038_GPIO_PM_TO_SYS(10)
+#define GPIO_CAMERA_FOCUS	PM8038_GPIO_PM_TO_SYS(11)
+
+static struct gpio_keys_button keys_8930[] = {
+	{
+		.code = KEY_VOLUMEUP,
+		.type = EV_KEY,
+		.desc = "volume_up",
+		.gpio = GPIO_VOLUME_UP,
+		.wakeup = 1,
+		.active_low = 1,
+	},
+	{
+		.code = KEY_VOLUMEDOWN,
+		.type = EV_KEY,
+		.desc = "volume_down",
+		.gpio = GPIO_VOLUME_DOWN,
+		.wakeup = 1,
+		.active_low = 1,
+	},
+	{
+		.code = KEY_CAMERA_FOCUS,
+		.type = EV_KEY,
+		.desc = "camera_focus",
+		.gpio = GPIO_CAMERA_FOCUS,
+		.wakeup = 1,
+		.active_low = 1,
+	},
+	{
+		.code = KEY_CAMERA_SNAPSHOT,
+		.type = EV_KEY,
+		.desc = "camera_snapshot",
+		.gpio = GPIO_CAMERA_SNAPSHOT,
+		.wakeup = 1,
+		.active_low = 1,
+	},
+};
+
+/* Add GPIO keys for 8930 */
+static struct gpio_keys_platform_data gpio_keys_8930_pdata = {
+	.buttons = keys_8930,
+	.nbuttons = 4,
+};
+
+static struct platform_device gpio_keys_8930 = {
+	.name		= "gpio-keys",
+	.id		= -1,
+	.dev		= {
+		.platform_data  = &gpio_keys_8930_pdata,
+	},
+};
+#endif /* MSM8930_PHASE_2 */
+
+static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi4_pdata = {
+	.clk_freq = 100000,
+	.src_clk_rate = 24000000,
+};
+
+static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi3_pdata = {
+	.clk_freq = 100000,
+	.src_clk_rate = 24000000,
+};
+
+static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi9_pdata = {
+	.clk_freq = 100000,
+	.src_clk_rate = 24000000,
+};
+
+static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi10_pdata = {
+	.clk_freq = 100000,
+	.src_clk_rate = 24000000,
+};
+
+static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi12_pdata = {
+	.clk_freq = 100000,
+	.src_clk_rate = 24000000,
+};
+
+
+static struct ks8851_pdata spi_eth_pdata = {
+	.irq_gpio = KS8851_IRQ_GPIO,
+	.rst_gpio = KS8851_RST_GPIO,
+};
+
+static struct spi_board_info spi_board_info[] __initdata = {
+	{
+		.modalias               = "ks8851",
+		.irq                    = MSM_GPIO_TO_INT(KS8851_IRQ_GPIO),
+		.max_speed_hz           = 19200000,
+		.bus_num                = 0,
+		.chip_select            = 0,
+		.mode                   = SPI_MODE_0,
+		.platform_data		= &spi_eth_pdata
+	},
+	{
+		.modalias               = "dsi_novatek_3d_panel_spi",
+		.max_speed_hz           = 10800000,
+		.bus_num                = 0,
+		.chip_select            = 1,
+		.mode                   = SPI_MODE_0,
+	},
+};
+
+static struct platform_device msm_device_saw_core0 = {
+	.name	= "saw-regulator",
+	.id	= 0,
+	.dev	= {
+		.platform_data = &msm8930_saw_regulator_core0_pdata,
+	},
+};
+
+static struct platform_device msm_device_saw_core1 = {
+	.name	= "saw-regulator",
+	.id	= 1,
+	.dev	= {
+		.platform_data = &msm8930_saw_regulator_core1_pdata,
+	},
+};
+
+static struct tsens_platform_data msm_tsens_pdata  = {
+	.tsens_factor		= 1000,
+	.hw_type		= APQ_8064,
+	.tsens_num_sensor	= 10,
+	.slope = {1132, 1135, 1137, 1135, 1157,
+			1142, 1124, 1153, 1175, 1166},
+};
+
+static struct platform_device msm_tsens_device = {
+	.name   = "tsens8960-tm",
+	.id = -1,
+};
+
+#ifdef CONFIG_MSM_FAKE_BATTERY
+static struct platform_device fish_battery_device = {
+	.name = "fish_battery",
+};
+#endif
+
+#ifndef MSM8930_PHASE_2
+
+/* 8930 Phase 1 */
+static struct platform_device msm8930_device_ext_5v_vreg __devinitdata = {
+	.name	= GPIO_REGULATOR_DEV_NAME,
+	.id	= PM8921_MPP_PM_TO_SYS(7),
+	.dev	= {
+		.platform_data = &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_5V],
+	},
+};
+
+static struct platform_device msm8930_device_ext_l2_vreg __devinitdata = {
+	.name	= GPIO_REGULATOR_DEV_NAME,
+	.id	= 91,
+	.dev	= {
+		.platform_data = &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_L2],
+	},
+};
+
+#else
+
+/* 8930 Phase 2 */
+static struct platform_device msm8930_device_ext_5v_vreg __devinitdata = {
+	.name	= GPIO_REGULATOR_DEV_NAME,
+	.id	= 63,
+	.dev	= {
+		.platform_data =
+		     &msm8930_gpio_regulator_pdata[MSM8930_GPIO_VREG_ID_EXT_5V],
+	},
+};
+
+static struct platform_device msm8930_device_ext_otg_sw_vreg __devinitdata = {
+	.name	= GPIO_REGULATOR_DEV_NAME,
+	.id	= 97,
+	.dev	= {
+		.platform_data =
+		 &msm8930_gpio_regulator_pdata[MSM8930_GPIO_VREG_ID_EXT_OTG_SW],
+	},
+};
+
+#endif
+
+static struct platform_device msm8930_device_rpm_regulator __devinitdata = {
+	.name	= "rpm-regulator",
+	.id	= -1,
+	.dev	= {
+#ifndef MSM8930_PHASE_2
+		.platform_data = &msm_rpm_regulator_pdata,
+#else
+		.platform_data = &msm8930_rpm_regulator_pdata,
+#endif
+	},
+};
+
+static struct platform_device *common_devices[] __initdata = {
+	&msm8960_device_dmov,
+	&msm_device_smd,
+	&msm8960_device_uart_gsbi5,
+	&msm_device_uart_dm6,
+	&msm_device_saw_core0,
+	&msm_device_saw_core1,
+	&msm8930_device_ext_5v_vreg,
+#ifndef MSM8930_PHASE_2
+	&msm8930_device_ext_l2_vreg,
+#endif
+	&msm8960_device_ssbi_pmic,
+#ifdef MSM8930_PHASE_2
+	&msm8930_device_ext_otg_sw_vreg,
+#endif
+	&msm_8960_q6_lpass,
+	&msm_8960_q6_mss_fw,
+	&msm_8960_q6_mss_sw,
+	&msm_8960_riva,
+	&msm_pil_tzapps,
+	&msm_pil_vidc,
+	&msm8960_device_qup_spi_gsbi1,
+	&msm8960_device_qup_i2c_gsbi3,
+	&msm8960_device_qup_i2c_gsbi4,
+	&msm8960_device_qup_i2c_gsbi9,
+	&msm8960_device_qup_i2c_gsbi10,
+	&msm8960_device_qup_i2c_gsbi12,
+	&msm_slim_ctrl,
+	&msm_device_wcnss_wlan,
+#if defined(CONFIG_QSEECOM)
+		&qseecom_device,
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
+	&qcrypto_device,
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+	&qcedev_device,
+#endif
+#ifdef CONFIG_MSM_ROTATOR
+	&msm_rotator_device,
+#endif
+	&msm_device_sps,
+#ifdef CONFIG_MSM_FAKE_BATTERY
+	&fish_battery_device,
+#endif
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+	&msm8930_android_pmem_device,
+	&msm8930_android_pmem_adsp_device,
+	&msm8930_android_pmem_audio_device,
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
+	&msm8930_fmem_device,
+	&msm_device_bam_dmux,
+	&msm_fm_platform_init,
+
+#ifdef CONFIG_HW_RANDOM_MSM
+	&msm_device_rng,
+#endif
+	&msm8930_rpm_device,
+	&msm8930_rpm_log_device,
+	&msm8930_rpm_stat_device,
+#ifdef CONFIG_ION_MSM
+	&msm8930_ion_dev,
+#endif
+	&msm_device_tz_log,
+
+#ifdef CONFIG_MSM_QDSS
+	&msm_qdss_device,
+	&msm_etb_device,
+	&msm_tpiu_device,
+	&msm_funnel_device,
+	&msm_etm_device,
+#endif
+	&msm_device_dspcrashd_8960,
+	&msm8960_device_watchdog,
+#ifdef MSM8930_PHASE_2
+	&gpio_keys_8930,
+#endif
+	&msm8930_rtb_device,
+	&msm8930_cpu_idle_device,
+	&msm8930_msm_gov_device,
+	&msm_bus_8930_apps_fabric,
+	&msm_bus_8930_sys_fabric,
+	&msm_bus_8930_mm_fabric,
+	&msm_bus_8930_sys_fpb,
+	&msm_bus_8930_cpss_fpb,
+	&msm8960_device_cache_erp,
+	&msm8930_iommu_domain_device,
+	&msm_tsens_device,
+};
+
+static struct platform_device *cdp_devices[] __initdata = {
+	&msm8960_device_otg,
+	&msm8960_device_gadget_peripheral,
+	&msm_device_hsusb_host,
+	&android_usb_device,
+	&msm_pcm,
+	&msm_pcm_routing,
+	&msm_cpudai0,
+	&msm_cpudai1,
+	&msm_cpudai_hdmi_rx,
+	&msm_cpudai_bt_rx,
+	&msm_cpudai_bt_tx,
+	&msm_cpudai_fm_rx,
+	&msm_cpudai_fm_tx,
+	&msm_cpudai_auxpcm_rx,
+	&msm_cpudai_auxpcm_tx,
+	&msm_cpu_fe,
+	&msm_stub_codec,
+#ifdef CONFIG_MSM_GEMINI
+	&msm8960_gemini_device,
+#endif
+	&msm_voice,
+	&msm_voip,
+	&msm_lpa_pcm,
+	&msm_cpudai_afe_01_rx,
+	&msm_cpudai_afe_01_tx,
+	&msm_cpudai_afe_02_rx,
+	&msm_cpudai_afe_02_tx,
+	&msm_pcm_afe,
+	&msm_compr_dsp,
+	&msm_cpudai_incall_music_rx,
+	&msm_cpudai_incall_record_rx,
+	&msm_cpudai_incall_record_tx,
+	&msm_pcm_hostless,
+};
+
+static void __init msm8930_i2c_init(void)
+{
+	msm8960_device_qup_i2c_gsbi4.dev.platform_data =
+					&msm8960_i2c_qup_gsbi4_pdata;
+
+	msm8960_device_qup_i2c_gsbi3.dev.platform_data =
+					&msm8960_i2c_qup_gsbi3_pdata;
+
+	msm8960_device_qup_i2c_gsbi9.dev.platform_data =
+					&msm8960_i2c_qup_gsbi9_pdata;
+
+	msm8960_device_qup_i2c_gsbi10.dev.platform_data =
+					&msm8960_i2c_qup_gsbi10_pdata;
+
+	msm8960_device_qup_i2c_gsbi12.dev.platform_data =
+					&msm8960_i2c_qup_gsbi12_pdata;
+}
+
+static struct msm_rpmrs_level msm_rpmrs_levels[] __initdata = {
+	{
+		MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT,
+		MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
+		true,
+		1, 784, 180000, 100,
+	},
+
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
+		MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
+		true,
+		1300, 228, 1200000, 2000,
+	},
+
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+		MSM_RPMRS_LIMITS(ON, GDHS, MAX, ACTIVE),
+		false,
+		2000, 138, 1208400, 3200,
+	},
+
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+		MSM_RPMRS_LIMITS(ON, HSFS_OPEN, ACTIVE, RET_HIGH),
+		false,
+		6000, 119, 1850300, 9000,
+	},
+
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+		MSM_RPMRS_LIMITS(OFF, GDHS, MAX, ACTIVE),
+		false,
+		9200, 68, 2839200, 16400,
+	},
+
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, MAX, ACTIVE),
+		false,
+		10300, 63, 3128000, 18200,
+	},
+
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, ACTIVE, RET_HIGH),
+		false,
+		18000, 10, 4602600, 27000,
+	},
+
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, RET_HIGH, RET_LOW),
+		false,
+		20000, 2, 5752000, 32000,
+	},
+};
+
+static struct msm_rpmrs_platform_data msm_rpmrs_data __initdata = {
+	.levels = &msm_rpmrs_levels[0],
+	.num_levels = ARRAY_SIZE(msm_rpmrs_levels),
+	.vdd_mem_levels  = {
+		[MSM_RPMRS_VDD_MEM_RET_LOW]	= 750000,
+		[MSM_RPMRS_VDD_MEM_RET_HIGH]	= 750000,
+		[MSM_RPMRS_VDD_MEM_ACTIVE]	= 1050000,
+		[MSM_RPMRS_VDD_MEM_MAX]		= 1150000,
+	},
+	.vdd_dig_levels = {
+		[MSM_RPMRS_VDD_DIG_RET_LOW]	= 0,
+		[MSM_RPMRS_VDD_DIG_RET_HIGH]	= 0,
+		[MSM_RPMRS_VDD_DIG_ACTIVE]	= 1,
+		[MSM_RPMRS_VDD_DIG_MAX]		= 3,
+	},
+	.vdd_mask = 0x7FFFFF,
+	.rpmrs_target_id = {
+		[MSM_RPMRS_ID_PXO_CLK]		= MSM_RPM_ID_PXO_CLK,
+		[MSM_RPMRS_ID_L2_CACHE_CTL]	= MSM_RPM_ID_LAST,
+		[MSM_RPMRS_ID_VDD_DIG_0]	= MSM_RPM_ID_VOLTAGE_CORNER,
+		[MSM_RPMRS_ID_VDD_DIG_1]	= MSM_RPM_ID_LAST,
+		[MSM_RPMRS_ID_VDD_MEM_0]	= MSM_RPM_ID_PM8038_L24_0,
+		[MSM_RPMRS_ID_VDD_MEM_1]	= MSM_RPM_ID_PM8038_L24_1,
+		[MSM_RPMRS_ID_RPM_CTL]		= MSM_RPM_ID_RPM_CTL,
+	},
+};
+
+static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_TZ,
+};
+
+static struct msm_pm_sleep_status_data msm_pm_slp_sts_data = {
+	.base_addr = MSM_ACC0_BASE + 0x08,
+	.cpu_offset = MSM_ACC1_BASE - MSM_ACC0_BASE,
+	.mask = 1UL << 13,
+};
+
+#ifdef CONFIG_I2C
+#define I2C_SURF 1
+#define I2C_FFA  (1 << 1)
+#define I2C_RUMI (1 << 2)
+#define I2C_SIM  (1 << 3)
+#define I2C_FLUID (1 << 4)
+#define I2C_LIQUID (1 << 5)
+
+struct i2c_registry {
+	u8                     machs;
+	int                    bus;
+	struct i2c_board_info *info;
+	int                    len;
+};
+
+#ifdef CONFIG_ISL9519_CHARGER
+static struct isl_platform_data isl_data __initdata = {
+	.valid_n_gpio		= 0,	/* Not required when notify-by-pmic */
+	.chg_detection_config	= NULL,	/* Not required when notify-by-pmic */
+	.max_system_voltage	= 4200,
+	.min_system_voltage	= 3200,
+	.chgcurrent		= 1000, /* 1900, */
+	.term_current		= 400,	/* Need fine tuning */
+	.input_current		= 2048,
+};
+
+static struct i2c_board_info isl_charger_i2c_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("isl9519q", 0x9),
+		.irq		= 0,	/* Not required when notify-by-pmic */
+		.platform_data	= &isl_data,
+	},
+};
+#endif /* CONFIG_ISL9519_CHARGER */
+
+static struct i2c_registry msm8960_i2c_devices[] __initdata = {
+#ifdef CONFIG_ISL9519_CHARGER
+	{
+		I2C_LIQUID,
+		MSM_8930_GSBI10_QUP_I2C_BUS_ID,
+		isl_charger_i2c_info,
+		ARRAY_SIZE(isl_charger_i2c_info),
+	},
+#endif /* CONFIG_ISL9519_CHARGER */
+	{
+		I2C_SURF | I2C_FFA | I2C_FLUID,
+		MSM_8930_GSBI9_QUP_I2C_BUS_ID,
+		msm_isa1200_board_info,
+		ARRAY_SIZE(msm_isa1200_board_info),
+	},
+	{
+		I2C_SURF | I2C_FFA | I2C_FLUID,
+		MSM_8930_GSBI3_QUP_I2C_BUS_ID,
+		mxt_device_info_8930,
+		ARRAY_SIZE(mxt_device_info_8930),
+	},
+};
+#endif /* CONFIG_I2C */
+
+static void __init register_i2c_devices(void)
+{
+#ifdef CONFIG_I2C
+	u8 mach_mask = 0;
+	int i;
+#ifdef CONFIG_MSM_CAMERA
+	struct i2c_registry msm8930_camera_i2c_devices = {
+		I2C_SURF | I2C_FFA | I2C_FLUID | I2C_LIQUID | I2C_RUMI,
+		MSM_8930_GSBI4_QUP_I2C_BUS_ID,
+		msm8930_camera_board_info.board_info,
+		msm8930_camera_board_info.num_i2c_board_info,
+	};
+#endif
+
+	/* Build the matching 'supported_machs' bitmask */
+	if (machine_is_msm8930_cdp() || machine_is_msm8627_cdp())
+		mach_mask = I2C_SURF;
+	else if (machine_is_msm8930_fluid())
+		mach_mask = I2C_FLUID;
+	else if (machine_is_msm8930_mtp() || machine_is_msm8627_mtp())
+		mach_mask = I2C_FFA;
+	else
+		pr_err("unmatched machine ID in register_i2c_devices\n");
+
+	/* Run the array and install devices as appropriate */
+	for (i = 0; i < ARRAY_SIZE(msm8960_i2c_devices); ++i) {
+		if (msm8960_i2c_devices[i].machs & mach_mask)
+			i2c_register_board_info(msm8960_i2c_devices[i].bus,
+						msm8960_i2c_devices[i].info,
+						msm8960_i2c_devices[i].len);
+	}
+#ifdef CONFIG_MSM_CAMERA
+	if (msm8930_camera_i2c_devices.machs & mach_mask)
+		i2c_register_board_info(msm8930_camera_i2c_devices.bus,
+			msm8930_camera_i2c_devices.info,
+			msm8930_camera_i2c_devices.len);
+#endif
+#endif
+}
+
+static void __init msm8930_cdp_init(void)
+{
+	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));
+
+	regulator_suppress_info_printing();
+	if (msm_xo_init())
+		pr_err("Failed to initialize XO votes\n");
+	platform_device_register(&msm8930_device_rpm_regulator);
+	msm_clock_init(&msm8930_clock_init_data);
+	msm8960_device_otg.dev.platform_data = &msm_otg_pdata;
+	android_usb_pdata.swfi_latency =
+			msm_rpmrs_levels[0].latency_us;
+	msm8930_init_gpiomux();
+	msm8960_device_qup_spi_gsbi1.dev.platform_data =
+				&msm8960_qup_spi_gsbi1_pdata;
+	spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
+
+	/*
+	 * TODO: When physical 8930/PM8038 hardware becomes
+	 * available, remove this block or add the config
+	 * option.
+	 */
+#ifndef MSM8930_PHASE_2
+	msm8960_init_pmic();
+#else
+	msm8930_init_pmic();
+#endif
+	msm8930_i2c_init();
+	msm8930_init_gpu();
+	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
+	msm_spm_l2_init(msm_spm_l2_data);
+	msm8930_init_buses();
+	platform_add_devices(msm8930_footswitch, msm8930_num_footswitch);
+	platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
+	msm8930_add_vidc_device();
+	/*
+	 * TODO: When physical 8930/PM8038 hardware becomes
+	 * available, remove this block or add the config
+	 * option.
+	 */
+#ifndef MSM8930_PHASE_2
+	msm8960_pm8921_gpio_mpp_init();
+#else
+	msm8930_pm8038_gpio_mpp_init();
+#endif
+	platform_add_devices(cdp_devices, ARRAY_SIZE(cdp_devices));
+#ifdef CONFIG_MSM_CAMERA
+	msm8930_init_cam();
+#endif
+	msm8930_init_mmc();
+	acpuclk_init(&acpuclk_8930_soc_data);
+	mxt_init_vkeys_8930();
+	register_i2c_devices();
+	msm8930_init_fb();
+	slim_register_board_info(msm_slim_devices,
+		ARRAY_SIZE(msm_slim_devices));
+	change_memory_power = &msm8930_change_memory_power;
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+	msm_pm_init_sleep_status_data(&msm_pm_slp_sts_data);
+
+	if (PLATFORM_IS_CHARM25())
+		platform_add_devices(mdm_devices, ARRAY_SIZE(mdm_devices));
+}
+
+MACHINE_START(MSM8930_CDP, "QCT MSM8930 CDP")
+	.map_io = msm8930_map_io,
+	.reserve = msm8930_reserve,
+	.init_irq = msm8930_init_irq,
+	.handle_irq = gic_handle_irq,
+	.timer = &msm_timer,
+	.init_machine = msm8930_cdp_init,
+	.init_early = msm8930_allocate_memory_regions,
+	.init_very_early = msm8930_early_memory,
+MACHINE_END
+
+MACHINE_START(MSM8930_MTP, "QCT MSM8930 MTP")
+	.map_io = msm8930_map_io,
+	.reserve = msm8930_reserve,
+	.init_irq = msm8930_init_irq,
+	.handle_irq = gic_handle_irq,
+	.timer = &msm_timer,
+	.init_machine = msm8930_cdp_init,
+	.init_early = msm8930_allocate_memory_regions,
+	.init_very_early = msm8930_early_memory,
+MACHINE_END
+
+MACHINE_START(MSM8930_FLUID, "QCT MSM8930 FLUID")
+	.map_io = msm8930_map_io,
+	.reserve = msm8930_reserve,
+	.init_irq = msm8930_init_irq,
+	.handle_irq = gic_handle_irq,
+	.timer = &msm_timer,
+	.init_machine = msm8930_cdp_init,
+	.init_early = msm8930_allocate_memory_regions,
+	.init_very_early = msm8930_early_memory,
+MACHINE_END
+
+MACHINE_START(MSM8627_CDP, "QCT MSM8627 CDP")
+	.map_io = msm8930_map_io,
+	.reserve = msm8930_reserve,
+	.init_irq = msm8930_init_irq,
+	.handle_irq = gic_handle_irq,
+	.timer = &msm_timer,
+	.init_machine = msm8930_cdp_init,
+	.init_early = msm8930_allocate_memory_regions,
+	.init_very_early = msm8930_early_memory,
+MACHINE_END
+
+MACHINE_START(MSM8627_MTP, "QCT MSM8627 MTP")
+	.map_io = msm8930_map_io,
+	.reserve = msm8930_reserve,
+	.init_irq = msm8930_init_irq,
+	.handle_irq = gic_handle_irq,
+	.timer = &msm_timer,
+	.init_machine = msm8930_cdp_init,
+	.init_early = msm8930_allocate_memory_regions,
+	.init_very_early = msm8930_early_memory,
+MACHINE_END
diff --git a/arch/arm/mach-msm/board-8930.h b/arch/arm/mach-msm/board-8930.h
new file mode 100644
index 0000000..e564aff
--- /dev/null
+++ b/arch/arm/mach-msm/board-8930.h
@@ -0,0 +1,142 @@
+/* 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
+ * 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 __ARCH_ARM_MACH_MSM_BOARD_MSM8930_H
+#define __ARCH_ARM_MACH_MSM_BOARD_MSM8930_H
+
+#define MSM8930_PHASE_2
+
+#include <linux/regulator/msm-gpio-regulator.h>
+#include <linux/mfd/pm8xxx/pm8038.h>
+#include <linux/i2c.h>
+#include <linux/i2c/sx150x.h>
+#include <mach/irqs.h>
+#include <mach/rpm-regulator.h>
+#include <mach/msm_memtypes.h>
+#include <mach/msm_rtb.h>
+
+/*
+ * TODO: When physical 8930/PM8038 hardware becomes
+ * available, remove this block.
+ */
+#ifndef MSM8930_PHASE_2
+#include <linux/mfd/pm8xxx/pm8921.h>
+#define PM8921_GPIO_BASE		NR_GPIO_IRQS
+#define PM8921_GPIO_PM_TO_SYS(pm_gpio)	(pm_gpio - 1 + PM8921_GPIO_BASE)
+#define PM8921_MPP_BASE			(PM8921_GPIO_BASE + PM8921_NR_GPIOS)
+#define PM8921_MPP_PM_TO_SYS(pm_gpio)	(pm_gpio - 1 + PM8921_MPP_BASE)
+#endif
+
+/* Macros assume PMIC GPIOs and MPPs start at 1 */
+#define PM8038_GPIO_BASE		NR_GPIO_IRQS
+#define PM8038_GPIO_PM_TO_SYS(pm_gpio)	(pm_gpio - 1 + PM8038_GPIO_BASE)
+#define PM8038_MPP_BASE			(PM8038_GPIO_BASE + PM8038_NR_GPIOS)
+#define PM8038_MPP_PM_TO_SYS(pm_gpio)	(pm_gpio - 1 + PM8038_MPP_BASE)
+#define PM8038_IRQ_BASE			(NR_MSM_IRQS + NR_GPIO_IRQS)
+
+/*
+ * TODO: When physical 8930/PM8038 hardware becomes
+ * available, replace this block with 8930/pm8038 regulator
+ * declarations.
+ */
+#ifndef MSM8930_PHASE_2
+extern struct pm8xxx_regulator_platform_data
+	msm_pm8921_regulator_pdata[] __devinitdata;
+
+extern int msm_pm8921_regulator_pdata_len __devinitdata;
+
+extern struct gpio_regulator_platform_data
+	msm_gpio_regulator_pdata[] __devinitdata;
+
+extern struct rpm_regulator_platform_data msm_rpm_regulator_pdata __devinitdata;
+
+#define GPIO_VREG_ID_EXT_5V		0
+#define GPIO_VREG_ID_EXT_L2		1
+#define GPIO_VREG_ID_EXT_3P3V		2
+#endif
+
+extern struct regulator_init_data msm8930_saw_regulator_core0_pdata;
+extern struct regulator_init_data msm8930_saw_regulator_core1_pdata;
+
+extern struct pm8xxx_regulator_platform_data
+	msm8930_pm8038_regulator_pdata[] __devinitdata;
+
+extern int msm8930_pm8038_regulator_pdata_len __devinitdata;
+
+#define MSM8930_GPIO_VREG_ID_EXT_5V		0
+#define MSM8930_GPIO_VREG_ID_EXT_OTG_SW		1
+
+extern struct gpio_regulator_platform_data
+	msm8930_gpio_regulator_pdata[] __devinitdata;
+
+extern struct rpm_regulator_platform_data
+	msm8930_rpm_regulator_pdata __devinitdata;
+
+#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
+enum {
+	GPIO_EXPANDER_IRQ_BASE = (PM8038_IRQ_BASE + PM8038_NR_IRQS),
+	GPIO_EXPANDER_GPIO_BASE = (PM8038_MPP_BASE + PM8038_NR_MPPS),
+	/* CAM Expander */
+	GPIO_CAM_EXPANDER_BASE = GPIO_EXPANDER_GPIO_BASE,
+	GPIO_CAM_GP_STROBE_READY = GPIO_CAM_EXPANDER_BASE,
+	GPIO_CAM_GP_AFBUSY,
+	GPIO_CAM_GP_STROBE_CE,
+	GPIO_CAM_GP_CAM1MP_XCLR,
+	GPIO_CAM_GP_CAMIF_RESET_N,
+	GPIO_CAM_GP_XMT_FLASH_INT,
+	GPIO_CAM_GP_LED_EN1,
+	GPIO_CAM_GP_LED_EN2,
+
+};
+#endif
+
+enum {
+	SX150X_CAM,
+};
+
+#endif
+
+extern struct sx150x_platform_data msm8930_sx150x_data[];
+extern struct msm_camera_board_info msm8930_camera_board_info;
+void msm8930_init_cam(void);
+void msm8930_init_fb(void);
+void msm8930_init_pmic(void);
+extern void msm8930_add_vidc_device(void);
+
+/*
+ * TODO: When physical 8930/PM8038 hardware becomes
+ * available, remove this block or add the config
+ * option.
+ */
+#ifndef MSM8930_PHASE_2
+void msm8960_init_pmic(void);
+void msm8960_pm8921_gpio_mpp_init(void);
+#endif
+
+void msm8930_init_mmc(void);
+int msm8930_init_gpiomux(void);
+void msm8930_allocate_fb_region(void);
+void msm8930_pm8038_gpio_mpp_init(void);
+void msm8930_mdp_writeback(struct memtype_reserve *reserve_table);
+void __init msm8930_init_gpu(void);
+
+#define PLATFORM_IS_CHARM25() \
+	(machine_is_msm8930_cdp() && \
+		(socinfo_get_platform_subtype() == 1) \
+	)
+
+#define MSM_8930_GSBI3_QUP_I2C_BUS_ID 3
+#define MSM_8930_GSBI4_QUP_I2C_BUS_ID 4
+#define MSM_8930_GSBI9_QUP_I2C_BUS_ID 0
+#define MSM_8930_GSBI10_QUP_I2C_BUS_ID 10
+
+extern struct msm_rtb_platform_data msm8930_rtb_pdata;
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
new file mode 100644
index 0000000..9c25b78
--- /dev/null
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -0,0 +1,812 @@
+/* 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
+ * 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 <asm/mach-types.h>
+#include <linux/gpio.h>
+#include <mach/board.h>
+#include <mach/msm_bus_board.h>
+#include <mach/gpiomux.h>
+#include "devices.h"
+#include "board-8960.h"
+
+#ifdef CONFIG_MSM_CAMERA
+
+#if (defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)) && \
+	defined(CONFIG_I2C)
+
+static struct i2c_board_info cam_expander_i2c_info[] = {
+	{
+		I2C_BOARD_INFO("sx1508q", 0x22),
+		.platform_data = &msm8960_sx150x_data[SX150X_CAM]
+	},
+};
+
+static struct msm_cam_expander_info cam_expander_info[] = {
+	{
+		cam_expander_i2c_info,
+		MSM_8960_GSBI4_QUP_I2C_BUS_ID,
+	},
+};
+#endif
+
+static struct gpiomux_setting cam_settings[] = {
+	{
+		.func = GPIOMUX_FUNC_GPIO, /*suspend*/
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_DOWN,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_1, /*active 1*/
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_GPIO, /*active 2*/
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_1, /*active 3*/
+		.drv = GPIOMUX_DRV_8MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_5, /*active 4*/
+		.drv = GPIOMUX_DRV_8MA,
+		.pull = GPIOMUX_PULL_UP,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_6, /*active 5*/
+		.drv = GPIOMUX_DRV_8MA,
+		.pull = GPIOMUX_PULL_UP,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_2, /*active 6*/
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_UP,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_3, /*active 7*/
+		.drv = GPIOMUX_DRV_8MA,
+		.pull = GPIOMUX_PULL_UP,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_GPIO, /*i2c suspend*/
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_KEEPER,
+	},
+
+};
+
+static struct msm_gpiomux_config msm8960_cdp_flash_configs[] = {
+	{
+		.gpio = 3,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[1],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8960_cam_common_configs[] = {
+	{
+		.gpio = 2,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[2],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
+		},
+	},
+	{
+		.gpio = 3,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[2],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
+		},
+	},
+	{
+		.gpio = 4,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[1],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
+		},
+	},
+	{
+		.gpio = 5,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
+		},
+	},
+	{
+		.gpio = 76,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[2],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
+		},
+	},
+	{
+		.gpio = 107,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[2],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8960_cam_2d_configs[] = {
+	{
+		.gpio = 18,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &cam_settings[8],
+		},
+	},
+	{
+		.gpio = 19,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &cam_settings[8],
+		},
+	},
+	{
+		.gpio = 20,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &cam_settings[8],
+		},
+	},
+	{
+		.gpio = 21,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &cam_settings[8],
+		},
+	},
+};
+
+#define VFE_CAMIF_TIMER1_GPIO 2
+#define VFE_CAMIF_TIMER2_GPIO 3
+#define VFE_CAMIF_TIMER3_GPIO_INT 4
+static struct msm_camera_sensor_strobe_flash_data strobe_flash_xenon = {
+	.flash_trigger = VFE_CAMIF_TIMER2_GPIO,
+	.flash_charge = VFE_CAMIF_TIMER1_GPIO,
+	.flash_charge_done = VFE_CAMIF_TIMER3_GPIO_INT,
+	.flash_recharge_duration = 50000,
+	.irq = MSM_GPIO_TO_INT(VFE_CAMIF_TIMER3_GPIO_INT),
+};
+
+#ifdef CONFIG_MSM_CAMERA_FLASH
+static struct msm_camera_sensor_flash_src msm_flash_src = {
+	.flash_sr_type = MSM_CAMERA_FLASH_SRC_EXT,
+	._fsrc.ext_driver_src.led_en = VFE_CAMIF_TIMER1_GPIO,
+	._fsrc.ext_driver_src.led_flash_en = VFE_CAMIF_TIMER2_GPIO,
+	._fsrc.ext_driver_src.flash_id = MAM_CAMERA_EXT_LED_FLASH_SC628A,
+};
+#endif
+
+static struct msm_bus_vectors cam_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_MM_IMEM,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_MM_IMEM,
+		.ab  = 0,
+		.ib  = 0,
+	},
+};
+
+static struct msm_bus_vectors cam_preview_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 27648000,
+		.ib  = 110592000,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_MM_IMEM,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_MM_IMEM,
+		.ab  = 0,
+		.ib  = 0,
+	},
+};
+
+static struct msm_bus_vectors cam_video_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 154275840,
+		.ib  = 617103360,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 206807040,
+		.ib  = 488816640,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_MM_IMEM,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_MM_IMEM,
+		.ab  = 0,
+		.ib  = 0,
+	},
+};
+
+static struct msm_bus_vectors cam_snapshot_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 274423680,
+		.ib  = 1097694720,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 540000000,
+		.ib  = 1350000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_MM_IMEM,
+		.ab  = 43200000,
+		.ib  = 69120000,
+	},
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_MM_IMEM,
+		.ab  = 43200000,
+		.ib  = 69120000,
+	},
+};
+
+static struct msm_bus_vectors cam_zsl_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 302071680,
+		.ib  = 1208286720,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 540000000,
+		.ib  = 1350000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_MM_IMEM,
+		.ab  = 43200000,
+		.ib  = 69120000,
+	},
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_MM_IMEM,
+		.ab  = 43200000,
+		.ib  = 69120000,
+	},
+};
+
+static struct msm_bus_paths cam_bus_client_config[] = {
+	{
+		ARRAY_SIZE(cam_init_vectors),
+		cam_init_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_preview_vectors),
+		cam_preview_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_video_vectors),
+		cam_video_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_snapshot_vectors),
+		cam_snapshot_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_zsl_vectors),
+		cam_zsl_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata cam_bus_client_pdata = {
+		cam_bus_client_config,
+		ARRAY_SIZE(cam_bus_client_config),
+		.name = "msm_camera",
+};
+
+static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
+	{
+		.csid_core = 0,
+		.is_csiphy = 1,
+		.is_csid   = 1,
+		.is_ispif  = 1,
+		.is_vpe    = 1,
+		.cam_bus_scale_table = &cam_bus_client_pdata,
+	},
+	{
+		.csid_core = 1,
+		.is_csiphy = 1,
+		.is_csid   = 1,
+		.is_ispif  = 1,
+		.is_vpe    = 1,
+		.cam_bus_scale_table = &cam_bus_client_pdata,
+	},
+	{
+		.csid_core = 2,
+		.is_csiphy = 1,
+		.is_csid   = 1,
+		.is_ispif  = 1,
+		.is_vpe    = 1,
+		.cam_bus_scale_table = &cam_bus_client_pdata,
+	},
+};
+
+static struct camera_vreg_t msm_8960_back_cam_vreg[] = {
+	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
+	{"cam_vio", REG_VS, 0, 0, 0},
+	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
+	{"cam_vaf", REG_LDO, 2800000, 2800000, 300000},
+};
+
+static struct camera_vreg_t msm_8960_front_cam_vreg[] = {
+	{"cam_vio", REG_VS, 0, 0, 0},
+	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
+	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
+};
+
+static struct gpio msm8960_common_cam_gpio[] = {
+	{5, GPIOF_DIR_IN, "CAMIF_MCLK"},
+	{20, GPIOF_DIR_IN, "CAMIF_I2C_DATA"},
+	{21, GPIOF_DIR_IN, "CAMIF_I2C_CLK"},
+};
+
+static struct gpio msm8960_front_cam_gpio[] = {
+	{76, GPIOF_DIR_OUT, "CAM_RESET"},
+};
+
+static struct gpio msm8960_back_cam_gpio[] = {
+	{107, GPIOF_DIR_OUT, "CAM_RESET"},
+};
+
+static struct msm_gpio_set_tbl msm8960_front_cam_gpio_set_tbl[] = {
+	{76, GPIOF_OUT_INIT_LOW, 1000},
+	{76, GPIOF_OUT_INIT_HIGH, 4000},
+};
+
+static struct msm_gpio_set_tbl msm8960_back_cam_gpio_set_tbl[] = {
+	{107, GPIOF_OUT_INIT_LOW, 1000},
+	{107, GPIOF_OUT_INIT_HIGH, 4000},
+};
+
+static struct msm_camera_gpio_conf msm_8960_front_cam_gpio_conf = {
+	.cam_gpiomux_conf_tbl = msm8960_cam_2d_configs,
+	.cam_gpiomux_conf_tbl_size = ARRAY_SIZE(msm8960_cam_2d_configs),
+	.cam_gpio_common_tbl = msm8960_common_cam_gpio,
+	.cam_gpio_common_tbl_size = ARRAY_SIZE(msm8960_common_cam_gpio),
+	.cam_gpio_req_tbl = msm8960_front_cam_gpio,
+	.cam_gpio_req_tbl_size = ARRAY_SIZE(msm8960_front_cam_gpio),
+	.cam_gpio_set_tbl = msm8960_front_cam_gpio_set_tbl,
+	.cam_gpio_set_tbl_size = ARRAY_SIZE(msm8960_front_cam_gpio_set_tbl),
+};
+
+static struct msm_camera_gpio_conf msm_8960_back_cam_gpio_conf = {
+	.cam_gpiomux_conf_tbl = msm8960_cam_2d_configs,
+	.cam_gpiomux_conf_tbl_size = ARRAY_SIZE(msm8960_cam_2d_configs),
+	.cam_gpio_common_tbl = msm8960_common_cam_gpio,
+	.cam_gpio_common_tbl_size = ARRAY_SIZE(msm8960_common_cam_gpio),
+	.cam_gpio_req_tbl = msm8960_back_cam_gpio,
+	.cam_gpio_req_tbl_size = ARRAY_SIZE(msm8960_back_cam_gpio),
+	.cam_gpio_set_tbl = msm8960_back_cam_gpio_set_tbl,
+	.cam_gpio_set_tbl_size = ARRAY_SIZE(msm8960_back_cam_gpio_set_tbl),
+};
+
+static struct i2c_board_info msm_act_main_cam_i2c_info = {
+	I2C_BOARD_INFO("msm_actuator", 0x11),
+};
+
+static struct msm_actuator_info msm_act_main_cam_0_info = {
+	.board_info     = &msm_act_main_cam_i2c_info,
+	.cam_name   = MSM_ACTUATOR_MAIN_CAM_0,
+	.bus_id         = MSM_8960_GSBI4_QUP_I2C_BUS_ID,
+	.vcm_pwd        = 0,
+	.vcm_enable     = 0,
+};
+
+static struct i2c_board_info msm_act_main_cam1_i2c_info = {
+	I2C_BOARD_INFO("msm_actuator", 0x18),
+};
+
+static struct msm_actuator_info msm_act_main_cam_1_info = {
+	.board_info     = &msm_act_main_cam1_i2c_info,
+	.cam_name       = MSM_ACTUATOR_MAIN_CAM_1,
+	.bus_id         = MSM_8960_GSBI4_QUP_I2C_BUS_ID,
+	.vcm_pwd        = 0,
+	.vcm_enable     = 0,
+};
+
+static struct msm_camera_sensor_flash_data flash_imx074 = {
+	.flash_type	= MSM_CAMERA_FLASH_LED,
+#ifdef CONFIG_MSM_CAMERA_FLASH
+	.flash_src	= &msm_flash_src
+#endif
+};
+
+static struct msm_camera_csi_lane_params imx074_csi_lane_params = {
+	.csi_lane_assign = 0xE4,
+	.csi_lane_mask = 0xF,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_imx074 = {
+	.mount_angle	= 90,
+	.cam_vreg = msm_8960_back_cam_vreg,
+	.num_vreg = ARRAY_SIZE(msm_8960_back_cam_vreg),
+	.gpio_conf = &msm_8960_back_cam_gpio_conf,
+	.csi_lane_params = &imx074_csi_lane_params,
+};
+
+static struct i2c_board_info imx074_eeprom_i2c_info = {
+	I2C_BOARD_INFO("imx074_eeprom", 0x34 << 1),
+};
+
+static struct msm_eeprom_info imx074_eeprom_info = {
+	.board_info     = &imx074_eeprom_i2c_info,
+	.bus_id         = MSM_8960_GSBI4_QUP_I2C_BUS_ID,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_imx074_data = {
+	.sensor_name	= "imx074",
+	.pdata	= &msm_camera_csi_device_data[0],
+	.flash_data	= &flash_imx074,
+	.strobe_flash_data = &strobe_flash_xenon,
+	.sensor_platform_info = &sensor_board_info_imx074,
+	.csi_if	= 1,
+	.camera_type = BACK_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
+	.actuator_info = &msm_act_main_cam_0_info,
+	.eeprom_info = &imx074_eeprom_info,
+};
+
+static struct camera_vreg_t msm_8960_mt9m114_vreg[] = {
+	{"cam_vio", REG_VS, 0, 0, 0},
+	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
+	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
+	{"cam_vaf", REG_LDO, 2800000, 2800000, 300000},
+};
+
+static struct msm_camera_sensor_flash_data flash_mt9m114 = {
+	.flash_type = MSM_CAMERA_FLASH_NONE
+};
+
+static struct msm_camera_csi_lane_params mt9m114_csi_lane_params = {
+	.csi_lane_assign = 0xE4,
+	.csi_lane_mask = 0x1,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_mt9m114 = {
+	.mount_angle = 90,
+	.cam_vreg = msm_8960_mt9m114_vreg,
+	.num_vreg = ARRAY_SIZE(msm_8960_mt9m114_vreg),
+	.gpio_conf = &msm_8960_front_cam_gpio_conf,
+	.csi_lane_params = &mt9m114_csi_lane_params,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_mt9m114_data = {
+	.sensor_name = "mt9m114",
+	.pdata = &msm_camera_csi_device_data[1],
+	.flash_data = &flash_mt9m114,
+	.sensor_platform_info = &sensor_board_info_mt9m114,
+	.csi_if = 1,
+	.camera_type = FRONT_CAMERA_2D,
+	.sensor_type = YUV_SENSOR,
+};
+
+static struct msm_camera_sensor_flash_data flash_ov2720 = {
+	.flash_type	= MSM_CAMERA_FLASH_NONE,
+};
+
+static struct msm_camera_csi_lane_params ov2720_csi_lane_params = {
+	.csi_lane_assign = 0xE4,
+	.csi_lane_mask = 0x3,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_ov2720 = {
+	.mount_angle	= 0,
+	.cam_vreg = msm_8960_front_cam_vreg,
+	.num_vreg = ARRAY_SIZE(msm_8960_front_cam_vreg),
+	.gpio_conf = &msm_8960_front_cam_gpio_conf,
+	.csi_lane_params = &ov2720_csi_lane_params,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_ov2720_data = {
+	.sensor_name	= "ov2720",
+	.pdata	= &msm_camera_csi_device_data[1],
+	.flash_data	= &flash_ov2720,
+	.sensor_platform_info = &sensor_board_info_ov2720,
+	.csi_if	= 1,
+	.camera_type = FRONT_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
+};
+
+static struct camera_vreg_t msm_8960_s5k3l1yx_vreg[] = {
+	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
+	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
+	{"cam_vio", REG_VS, 0, 0, 0},
+	{"cam_vaf", REG_LDO, 2800000, 2800000, 300000},
+};
+
+static struct msm_camera_sensor_flash_data flash_s5k3l1yx = {
+	.flash_type = MSM_CAMERA_FLASH_NONE,
+};
+
+static struct msm_camera_csi_lane_params s5k3l1yx_csi_lane_params = {
+	.csi_lane_assign = 0xE4,
+	.csi_lane_mask = 0xF,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_s5k3l1yx = {
+	.mount_angle  = 0,
+	.cam_vreg = msm_8960_s5k3l1yx_vreg,
+	.num_vreg = ARRAY_SIZE(msm_8960_s5k3l1yx_vreg),
+	.gpio_conf = &msm_8960_back_cam_gpio_conf,
+	.csi_lane_params = &s5k3l1yx_csi_lane_params,
+};
+
+static struct msm_actuator_info msm_act_main_cam_2_info = {
+	.board_info     = &msm_act_main_cam_i2c_info,
+	.cam_name   = MSM_ACTUATOR_MAIN_CAM_2,
+	.bus_id         = MSM_8960_GSBI4_QUP_I2C_BUS_ID,
+	.vcm_pwd        = 0,
+	.vcm_enable     = 0,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_s5k3l1yx_data = {
+	.sensor_name          = "s5k3l1yx",
+	.pdata                = &msm_camera_csi_device_data[0],
+	.flash_data           = &flash_s5k3l1yx,
+	.sensor_platform_info = &sensor_board_info_s5k3l1yx,
+	.csi_if               = 1,
+	.camera_type          = BACK_CAMERA_2D,
+	.sensor_type          = BAYER_SENSOR,
+	.actuator_info    = &msm_act_main_cam_2_info,
+};
+
+static struct msm_camera_csi_lane_params imx091_csi_lane_params = {
+	.csi_lane_assign = 0xE4,
+	.csi_lane_mask = 0xF,
+};
+
+static struct camera_vreg_t msm_8960_imx091_vreg[] = {
+	{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
+	{"cam_vaf", REG_LDO, 2800000, 2800000, 300000},
+	{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
+	{"cam_vio", REG_VS, 0, 0, 0},
+};
+
+static struct msm_camera_sensor_flash_data flash_imx091 = {
+	.flash_type	= MSM_CAMERA_FLASH_LED,
+#ifdef CONFIG_MSM_CAMERA_FLASH
+	.flash_src	= &msm_flash_src
+#endif
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_imx091 = {
+	.mount_angle	= 0,
+	.cam_vreg = msm_8960_imx091_vreg,
+	.num_vreg = ARRAY_SIZE(msm_8960_imx091_vreg),
+	.gpio_conf = &msm_8960_back_cam_gpio_conf,
+	.csi_lane_params = &imx091_csi_lane_params,
+};
+
+static struct i2c_board_info imx091_eeprom_i2c_info = {
+	I2C_BOARD_INFO("imx091_eeprom", 0x21),
+};
+
+static struct msm_eeprom_info imx091_eeprom_info = {
+	.board_info     = &imx091_eeprom_i2c_info,
+	.bus_id         = MSM_8960_GSBI4_QUP_I2C_BUS_ID,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_imx091_data = {
+	.sensor_name	= "imx091",
+	.pdata	= &msm_camera_csi_device_data[0],
+	.flash_data	= &flash_imx091,
+	.sensor_platform_info = &sensor_board_info_imx091,
+	.csi_if	= 1,
+	.camera_type = BACK_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
+	.actuator_info = &msm_act_main_cam_1_info,
+	.eeprom_info = &imx091_eeprom_info,
+};
+
+static struct pm8xxx_mpp_config_data privacy_light_on_config = {
+	.type		= PM8XXX_MPP_TYPE_SINK,
+	.level		= PM8XXX_MPP_CS_OUT_5MA,
+	.control	= PM8XXX_MPP_CS_CTRL_MPP_LOW_EN,
+};
+
+static struct pm8xxx_mpp_config_data privacy_light_off_config = {
+	.type		= PM8XXX_MPP_TYPE_SINK,
+	.level		= PM8XXX_MPP_CS_OUT_5MA,
+	.control	= PM8XXX_MPP_CS_CTRL_DISABLE,
+};
+
+static int32_t msm_camera_8960_ext_power_ctrl(int enable)
+{
+	int rc = 0;
+	if (enable) {
+		rc = pm8xxx_mpp_config(PM8921_MPP_PM_TO_SYS(12),
+			&privacy_light_on_config);
+	} else {
+		rc = pm8xxx_mpp_config(PM8921_MPP_PM_TO_SYS(12),
+			&privacy_light_off_config);
+	}
+	return rc;
+}
+
+static struct platform_device msm_camera_server = {
+	.name = "msm_cam_server",
+	.id = 0,
+};
+
+void __init msm8960_init_cam(void)
+{
+	msm_gpiomux_install(msm8960_cam_common_configs,
+			ARRAY_SIZE(msm8960_cam_common_configs));
+
+	if (machine_is_msm8960_cdp()) {
+		msm_gpiomux_install(msm8960_cdp_flash_configs,
+			ARRAY_SIZE(msm8960_cdp_flash_configs));
+		msm_flash_src._fsrc.ext_driver_src.led_en =
+			GPIO_CAM_GP_LED_EN1;
+		msm_flash_src._fsrc.ext_driver_src.led_flash_en =
+			GPIO_CAM_GP_LED_EN2;
+		#if defined(CONFIG_I2C) && (defined(CONFIG_GPIO_SX150X) || \
+		defined(CONFIG_GPIO_SX150X_MODULE))
+		msm_flash_src._fsrc.ext_driver_src.expander_info =
+			cam_expander_info;
+		#endif
+	}
+
+	if (machine_is_msm8960_liquid()) {
+		struct msm_camera_sensor_info *s_info;
+		s_info = &msm_camera_sensor_imx074_data;
+		s_info->sensor_platform_info->mount_angle = 180;
+		s_info = &msm_camera_sensor_ov2720_data;
+		s_info->sensor_platform_info->ext_power_ctrl =
+			msm_camera_8960_ext_power_ctrl;
+	}
+
+	if (machine_is_msm8960_fluid()) {
+		msm_camera_sensor_imx091_data.sensor_platform_info->
+			mount_angle = 270;
+	}
+
+	platform_device_register(&msm_camera_server);
+	platform_device_register(&msm8960_device_csiphy0);
+	platform_device_register(&msm8960_device_csiphy1);
+	platform_device_register(&msm8960_device_csiphy2);
+	platform_device_register(&msm8960_device_csid0);
+	platform_device_register(&msm8960_device_csid1);
+	platform_device_register(&msm8960_device_csid2);
+	platform_device_register(&msm8960_device_ispif);
+	platform_device_register(&msm8960_device_vfe);
+	platform_device_register(&msm8960_device_vpe);
+}
+
+#ifdef CONFIG_I2C
+static struct i2c_board_info msm8960_camera_i2c_boardinfo[] = {
+	{
+	I2C_BOARD_INFO("imx074", 0x1A),
+	.platform_data = &msm_camera_sensor_imx074_data,
+	},
+	{
+	I2C_BOARD_INFO("ov2720", 0x6C),
+	.platform_data = &msm_camera_sensor_ov2720_data,
+	},
+	{
+	I2C_BOARD_INFO("mt9m114", 0x48),
+	.platform_data = &msm_camera_sensor_mt9m114_data,
+	},
+	{
+	I2C_BOARD_INFO("s5k3l1yx", 0x20),
+	.platform_data = &msm_camera_sensor_s5k3l1yx_data,
+	},
+#ifdef CONFIG_MSM_CAMERA_FLASH_SC628A
+	{
+	I2C_BOARD_INFO("sc628a", 0x6E),
+	},
+#endif
+	{
+	I2C_BOARD_INFO("imx091", 0x34),
+	.platform_data = &msm_camera_sensor_imx091_data,
+	},
+};
+
+struct msm_camera_board_info msm8960_camera_board_info = {
+	.board_info = msm8960_camera_i2c_boardinfo,
+	.num_i2c_board_info = ARRAY_SIZE(msm8960_camera_i2c_boardinfo),
+};
+#endif
+#endif
diff --git a/arch/arm/mach-msm/board-8960-display.c b/arch/arm/mach-msm/board-8960-display.c
new file mode 100644
index 0000000..a9b2a59
--- /dev/null
+++ b/arch/arm/mach-msm/board-8960-display.c
@@ -0,0 +1,1095 @@
+/* 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
+ * 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 <linux/ion.h>
+#include <linux/gpio.h>
+#include <asm/mach-types.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_memtypes.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
+#include <mach/ion.h>
+#include <mach/socinfo.h>
+
+#include "devices.h"
+#include "board-8960.h"
+
+#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
+#define MSM_FB_PRIM_BUF_SIZE \
+		(roundup((roundup(1920, 32) * roundup(1200, 32) * 4), 4096) * 3)
+			/* 4 bpp x 3 pages */
+#else
+#define MSM_FB_PRIM_BUF_SIZE \
+		(roundup((roundup(1920, 32) * roundup(1200, 32) * 4), 4096) * 2)
+			/* 4 bpp x 2 pages */
+#endif
+
+/* Note: must be multiple of 4096 */
+#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE, 4096)
+
+#ifdef CONFIG_FB_MSM_OVERLAY0_WRITEBACK
+#define MSM_FB_OVERLAY0_WRITEBACK_SIZE \
+		roundup((roundup(1920, 32) * roundup(1200, 32) * 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((roundup(1920, 32) * roundup(1080, 32) * 3 * 2), 4096)
+#else
+#define MSM_FB_OVERLAY1_WRITEBACK_SIZE (0)
+#endif  /* CONFIG_FB_MSM_OVERLAY1_WRITEBACK */
+
+#define MDP_VSYNC_GPIO 0
+
+#define MIPI_CMD_NOVATEK_QHD_PANEL_NAME	"mipi_cmd_novatek_qhd"
+#define MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME	"mipi_video_novatek_qhd"
+#define MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME	"mipi_video_toshiba_wsvga"
+#define MIPI_VIDEO_TOSHIBA_WUXGA_PANEL_NAME	"mipi_video_toshiba_wuxga"
+#define MIPI_VIDEO_CHIMEI_WXGA_PANEL_NAME	"mipi_video_chimei_wxga"
+#define MIPI_VIDEO_CHIMEI_WUXGA_PANEL_NAME	"mipi_video_chimei_wuxga"
+#define MIPI_VIDEO_SIMULATOR_VGA_PANEL_NAME	"mipi_video_simulator_vga"
+#define MIPI_CMD_RENESAS_FWVGA_PANEL_NAME	"mipi_cmd_renesas_fwvga"
+#define MIPI_VIDEO_ORISE_720P_PANEL_NAME	"mipi_video_orise_720p"
+#define MIPI_CMD_ORISE_720P_PANEL_NAME		"mipi_cmd_orise_720p"
+#define HDMI_PANEL_NAME	"hdmi_msm"
+#define TVOUT_PANEL_NAME	"tvout_msm"
+
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+static unsigned char hdmi_is_primary = 1;
+#else
+static unsigned char hdmi_is_primary;
+#endif
+
+unsigned char msm8960_hdmi_as_primary_selected(void)
+{
+	return hdmi_is_primary;
+}
+
+static struct resource msm_fb_resources[] = {
+	{
+		.flags = IORESOURCE_DMA,
+	}
+};
+
+static void set_mdp_clocks_for_wuxga(void);
+
+static int msm_fb_detect_panel(const char *name)
+{
+	if (machine_is_msm8960_liquid()) {
+		u32 ver = socinfo_get_platform_version();
+		if (SOCINFO_VERSION_MAJOR(ver) == 3) {
+			if (!strncmp(name, MIPI_VIDEO_CHIMEI_WUXGA_PANEL_NAME,
+				     strnlen(MIPI_VIDEO_CHIMEI_WUXGA_PANEL_NAME,
+						PANEL_NAME_MAX_LEN))) {
+				set_mdp_clocks_for_wuxga();
+				return 0;
+			}
+		} else {
+			if (!strncmp(name, MIPI_VIDEO_CHIMEI_WXGA_PANEL_NAME,
+				     strnlen(MIPI_VIDEO_CHIMEI_WXGA_PANEL_NAME,
+						PANEL_NAME_MAX_LEN)))
+				return 0;
+		}
+	} else {
+		if (!strncmp(name, MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME,
+				strnlen(MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME,
+					PANEL_NAME_MAX_LEN)))
+			return 0;
+
+#if !defined(CONFIG_FB_MSM_LVDS_MIPI_PANEL_DETECT) && \
+	!defined(CONFIG_FB_MSM_MIPI_PANEL_DETECT)
+		if (!strncmp(name, MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME,
+				strnlen(MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME,
+					PANEL_NAME_MAX_LEN)))
+			return 0;
+
+		if (!strncmp(name, MIPI_CMD_NOVATEK_QHD_PANEL_NAME,
+				strnlen(MIPI_CMD_NOVATEK_QHD_PANEL_NAME,
+					PANEL_NAME_MAX_LEN)))
+			return 0;
+
+		if (!strncmp(name, MIPI_VIDEO_SIMULATOR_VGA_PANEL_NAME,
+				strnlen(MIPI_VIDEO_SIMULATOR_VGA_PANEL_NAME,
+					PANEL_NAME_MAX_LEN)))
+			return 0;
+
+		if (!strncmp(name, MIPI_CMD_RENESAS_FWVGA_PANEL_NAME,
+				strnlen(MIPI_CMD_RENESAS_FWVGA_PANEL_NAME,
+					PANEL_NAME_MAX_LEN)))
+			return 0;
+
+		if (!strncmp(name, MIPI_VIDEO_TOSHIBA_WUXGA_PANEL_NAME,
+				strnlen(MIPI_VIDEO_TOSHIBA_WUXGA_PANEL_NAME,
+					PANEL_NAME_MAX_LEN))) {
+			set_mdp_clocks_for_wuxga();
+			return 0;
+		}
+
+		if (!strncmp(name, MIPI_VIDEO_ORISE_720P_PANEL_NAME,
+				strnlen(MIPI_VIDEO_ORISE_720P_PANEL_NAME,
+					PANEL_NAME_MAX_LEN)))
+			return 0;
+
+		if (!strncmp(name, MIPI_CMD_ORISE_720P_PANEL_NAME,
+				strnlen(MIPI_CMD_ORISE_720P_PANEL_NAME,
+					PANEL_NAME_MAX_LEN)))
+			return 0;
+#endif
+	}
+
+	if (!strncmp(name, HDMI_PANEL_NAME,
+			strnlen(HDMI_PANEL_NAME,
+				PANEL_NAME_MAX_LEN))) {
+		if (hdmi_is_primary)
+			set_mdp_clocks_for_wuxga();
+		return 0;
+	}
+
+	if (!strncmp(name, TVOUT_PANEL_NAME,
+			strnlen(TVOUT_PANEL_NAME,
+				PANEL_NAME_MAX_LEN)))
+		return 0;
+
+	pr_warning("%s: not supported '%s'", __func__, name);
+	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,
+};
+
+static void mipi_dsi_panel_pwm_cfg(void)
+{
+	int rc;
+	static int mipi_dsi_panel_gpio_configured;
+	static struct pm_gpio pwm_enable = {
+		.direction        = PM_GPIO_DIR_OUT,
+		.output_buffer    = PM_GPIO_OUT_BUF_CMOS,
+		.output_value     = 1,
+		.pull             = PM_GPIO_PULL_NO,
+		.vin_sel          = PM_GPIO_VIN_VPH,
+		.out_strength     = PM_GPIO_STRENGTH_HIGH,
+		.function         = PM_GPIO_FUNC_NORMAL,
+		.inv_int_pol      = 0,
+		.disable_pin      = 0,
+	};
+	static struct pm_gpio pwm_mode = {
+		.direction        = PM_GPIO_DIR_OUT,
+		.output_buffer    = PM_GPIO_OUT_BUF_CMOS,
+		.output_value     = 0,
+		.pull             = PM_GPIO_PULL_NO,
+		.vin_sel          = PM_GPIO_VIN_S4,
+		.out_strength     = PM_GPIO_STRENGTH_HIGH,
+		.function         = PM_GPIO_FUNC_2,
+		.inv_int_pol      = 0,
+		.disable_pin      = 0,
+	};
+
+	if (mipi_dsi_panel_gpio_configured == 0) {
+		/* pm8xxx: gpio-21, Backlight Enable */
+		rc = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(21),
+					&pwm_enable);
+		if (rc != 0)
+			pr_err("%s: pwm_enabled failed\n", __func__);
+
+		/* pm8xxx: gpio-24, Bl: Off, PWM mode */
+		rc = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(24),
+					&pwm_mode);
+		if (rc != 0)
+			pr_err("%s: pwm_mode failed\n", __func__);
+
+		mipi_dsi_panel_gpio_configured++;
+	}
+}
+
+static bool dsi_power_on;
+
+/**
+ * LiQUID panel on/off
+ *
+ * @param on
+ *
+ * @return int
+ */
+static int mipi_dsi_liquid_panel_power(int on)
+{
+	static struct regulator *reg_l2, *reg_ext_3p3v;
+	static int gpio21, gpio24, gpio43;
+	int rc;
+
+	mipi_dsi_panel_pwm_cfg();
+	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)*/
+	gpio24 = PM8921_GPIO_PM_TO_SYS(24); /* Backlight PWM */
+
+	if (!dsi_power_on) {
+
+		reg_l2 = regulator_get(&msm_mipi_dsi1_device.dev,
+				"dsi_vdda");
+		if (IS_ERR(reg_l2)) {
+			pr_err("could not get 8921_l2, rc = %ld\n",
+				PTR_ERR(reg_l2));
+			return -ENODEV;
+		}
+
+		rc = regulator_set_voltage(reg_l2, 1200000, 1200000);
+		if (rc) {
+			pr_err("set_voltage l2 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+
+		reg_ext_3p3v = regulator_get(&msm_mipi_dsi1_device.dev,
+			"vdd_lvds_3p3v");
+		if (IS_ERR(reg_ext_3p3v)) {
+			pr_err("could not get reg_ext_3p3v, rc = %ld\n",
+			       PTR_ERR(reg_ext_3p3v));
+		    return -ENODEV;
+		}
+
+		rc = gpio_request(gpio21, "disp_pwr_en_n");
+		if (rc) {
+			pr_err("request gpio 21 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+
+		rc = gpio_request(gpio43, "disp_rst_n");
+		if (rc) {
+			pr_err("request gpio 43 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+
+		rc = gpio_request(gpio24, "disp_backlight_pwm");
+		if (rc) {
+			pr_err("request gpio 24 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+
+		dsi_power_on = true;
+	}
+
+	if (on) {
+		rc = regulator_set_optimum_mode(reg_l2, 100000);
+		if (rc < 0) {
+			pr_err("set_optimum_mode l2 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+		rc = regulator_enable(reg_l2);
+		if (rc) {
+			pr_err("enable l2 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+
+		rc = regulator_enable(reg_ext_3p3v);
+		if (rc) {
+			pr_err("enable reg_ext_3p3v failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+
+		/* set reset pin before power enable */
+		gpio_set_value_cansleep(gpio43, 0); /* disp disable (resx=0) */
+
+		gpio_set_value_cansleep(gpio21, 0); /* disp power enable_n */
+		msleep(20);
+		gpio_set_value_cansleep(gpio43, 1); /* disp enable */
+		msleep(20);
+		gpio_set_value_cansleep(gpio43, 0); /* disp enable */
+		msleep(20);
+		gpio_set_value_cansleep(gpio43, 1); /* disp enable */
+		msleep(20);
+	} else {
+		gpio_set_value_cansleep(gpio43, 0);
+		gpio_set_value_cansleep(gpio21, 1);
+
+		rc = regulator_disable(reg_l2);
+		if (rc) {
+			pr_err("disable reg_l2 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		rc = regulator_disable(reg_ext_3p3v);
+		if (rc) {
+			pr_err("disable reg_ext_3p3v failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		rc = regulator_set_optimum_mode(reg_l2, 100);
+		if (rc < 0) {
+			pr_err("set_optimum_mode l2 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int mipi_dsi_cdp_panel_power(int on)
+{
+	static struct regulator *reg_l8, *reg_l23, *reg_l2;
+	static int gpio43;
+	int rc;
+
+	pr_debug("%s: state : %d\n", __func__, on);
+
+	if (!dsi_power_on) {
+
+		reg_l8 = regulator_get(&msm_mipi_dsi1_device.dev,
+				"dsi_vdc");
+		if (IS_ERR(reg_l8)) {
+			pr_err("could not get 8921_l8, rc = %ld\n",
+				PTR_ERR(reg_l8));
+			return -ENODEV;
+		}
+		reg_l23 = regulator_get(&msm_mipi_dsi1_device.dev,
+				"dsi_vddio");
+		if (IS_ERR(reg_l23)) {
+			pr_err("could not get 8921_l23, rc = %ld\n",
+				PTR_ERR(reg_l23));
+			return -ENODEV;
+		}
+		reg_l2 = regulator_get(&msm_mipi_dsi1_device.dev,
+				"dsi_vdda");
+		if (IS_ERR(reg_l2)) {
+			pr_err("could not get 8921_l2, rc = %ld\n",
+				PTR_ERR(reg_l2));
+			return -ENODEV;
+		}
+		rc = regulator_set_voltage(reg_l8, 2800000, 3000000);
+		if (rc) {
+			pr_err("set_voltage l8 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+		rc = regulator_set_voltage(reg_l23, 1800000, 1800000);
+		if (rc) {
+			pr_err("set_voltage l23 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+		rc = regulator_set_voltage(reg_l2, 1200000, 1200000);
+		if (rc) {
+			pr_err("set_voltage l2 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+		gpio43 = PM8921_GPIO_PM_TO_SYS(43);
+		rc = gpio_request(gpio43, "disp_rst_n");
+		if (rc) {
+			pr_err("request gpio 43 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		dsi_power_on = true;
+	}
+	if (on) {
+		rc = regulator_set_optimum_mode(reg_l8, 100000);
+		if (rc < 0) {
+			pr_err("set_optimum_mode l8 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+		rc = regulator_set_optimum_mode(reg_l23, 100000);
+		if (rc < 0) {
+			pr_err("set_optimum_mode l23 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+		rc = regulator_set_optimum_mode(reg_l2, 100000);
+		if (rc < 0) {
+			pr_err("set_optimum_mode l2 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+		rc = regulator_enable(reg_l8);
+		if (rc) {
+			pr_err("enable l8 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		rc = regulator_enable(reg_l23);
+		if (rc) {
+			pr_err("enable l8 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		rc = regulator_enable(reg_l2);
+		if (rc) {
+			pr_err("enable l2 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		gpio_set_value_cansleep(gpio43, 1);
+	} else {
+		rc = regulator_disable(reg_l2);
+		if (rc) {
+			pr_err("disable reg_l2 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		rc = regulator_disable(reg_l8);
+		if (rc) {
+			pr_err("disable reg_l8 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		rc = regulator_disable(reg_l23);
+		if (rc) {
+			pr_err("disable reg_l23 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		rc = regulator_set_optimum_mode(reg_l8, 100);
+		if (rc < 0) {
+			pr_err("set_optimum_mode l8 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+		rc = regulator_set_optimum_mode(reg_l23, 100);
+		if (rc < 0) {
+			pr_err("set_optimum_mode l23 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+		rc = regulator_set_optimum_mode(reg_l2, 100);
+		if (rc < 0) {
+			pr_err("set_optimum_mode l2 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+		gpio_set_value_cansleep(gpio43, 0);
+	}
+	return 0;
+}
+
+static char mipi_dsi_splash_is_enabled(void);
+static int mipi_dsi_panel_power(int on)
+{
+	int ret;
+
+	pr_debug("%s: on=%d\n", __func__, on);
+
+	if (machine_is_msm8960_liquid())
+		ret = mipi_dsi_liquid_panel_power(on);
+	else
+		ret = mipi_dsi_cdp_panel_power(on);
+
+	return ret;
+}
+
+static struct mipi_dsi_platform_data mipi_dsi_pdata = {
+	.vsync_gpio = MDP_VSYNC_GPIO,
+	.dsi_power_save = mipi_dsi_panel_power,
+	.splash_is_enabled = mipi_dsi_splash_is_enabled,
+};
+
+#ifdef CONFIG_MSM_BUS_SCALING
+static struct msm_bus_vectors mdp_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+static struct msm_bus_vectors mdp_ui_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 216000000 * 2,
+		.ib = 270000000 * 2,
+	},
+};
+
+static struct msm_bus_vectors mdp_vga_vectors[] = {
+	/* VGA and less video */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 216000000 * 2,
+		.ib = 270000000 * 2,
+	},
+};
+
+static struct msm_bus_vectors mdp_720p_vectors[] = {
+	/* 720p and less video */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 230400000 * 2,
+		.ib = 288000000 * 2,
+	},
+};
+
+static struct msm_bus_vectors mdp_1080p_vectors[] = {
+	/* 1080p and less video */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 334080000 * 2,
+		.ib = 417600000 * 2,
+	},
+};
+
+static struct msm_bus_paths mdp_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(mdp_init_vectors),
+		mdp_init_vectors,
+	},
+	{
+		ARRAY_SIZE(mdp_ui_vectors),
+		mdp_ui_vectors,
+	},
+	{
+		ARRAY_SIZE(mdp_ui_vectors),
+		mdp_ui_vectors,
+	},
+	{
+		ARRAY_SIZE(mdp_vga_vectors),
+		mdp_vga_vectors,
+	},
+	{
+		ARRAY_SIZE(mdp_720p_vectors),
+		mdp_720p_vectors,
+	},
+	{
+		ARRAY_SIZE(mdp_1080p_vectors),
+		mdp_1080p_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata mdp_bus_scale_pdata = {
+	mdp_bus_scale_usecases,
+	ARRAY_SIZE(mdp_bus_scale_usecases),
+	.name = "mdp",
+};
+
+#endif
+
+static int mdp_core_clk_rate_table[] = {
+	85330000,
+	128000000,
+	160000000,
+	200000000,
+};
+
+static struct msm_panel_common_pdata mdp_pdata = {
+	.gpio = MDP_VSYNC_GPIO,
+	.mdp_core_clk_rate = 85330000,
+	.mdp_core_clk_table = mdp_core_clk_rate_table,
+	.num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
+#ifdef CONFIG_MSM_BUS_SCALING
+	.mdp_bus_scale_table = &mdp_bus_scale_pdata,
+#endif
+	.mdp_rev = MDP_REV_42,
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	.mem_hid = BIT(ION_CP_MM_HEAP_ID),
+#else
+	.mem_hid = MEMTYPE_EBI1,
+#endif
+	.cont_splash_enabled = 0x01,
+};
+
+void __init msm8960_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
+}
+
+static char mipi_dsi_splash_is_enabled(void)
+{
+	return mdp_pdata.cont_splash_enabled;
+}
+
+static struct platform_device mipi_dsi_renesas_panel_device = {
+	.name = "mipi_renesas",
+	.id = 0,
+};
+
+static struct platform_device mipi_dsi_simulator_panel_device = {
+	.name = "mipi_simulator",
+	.id = 0,
+};
+
+#define LPM_CHANNEL0 0
+static int toshiba_gpio[] = {LPM_CHANNEL0};
+
+static struct mipi_dsi_panel_platform_data toshiba_pdata = {
+	.gpio = toshiba_gpio,
+	.dsi_pwm_cfg = mipi_dsi_panel_pwm_cfg,
+};
+
+static struct platform_device mipi_dsi_toshiba_panel_device = {
+	.name = "mipi_toshiba",
+	.id = 0,
+	.dev = {
+		.platform_data = &toshiba_pdata,
+	}
+};
+
+#define FPGA_3D_GPIO_CONFIG_ADDR	0xB5
+static int dsi2lvds_gpio[4] = {
+	0,/* Backlight PWM-ID=0 for PMIC-GPIO#24 */
+	0x1F08, /* DSI2LVDS Bridge GPIO Output, mask=0x1f, out=0x08 */
+	GPIO_LIQUID_EXPANDER_BASE+6,	/* TN Enable */
+	GPIO_LIQUID_EXPANDER_BASE+7,	/* TN Mode */
+	};
+
+static struct msm_panel_common_pdata mipi_dsi2lvds_pdata = {
+	.gpio_num = dsi2lvds_gpio,
+};
+
+static struct mipi_dsi_phy_ctrl dsi_novatek_cmd_mode_phy_db = {
+
+/* DSI_BIT_CLK at 500MHz, 2 lane, RGB888 */
+	{0x0F, 0x0a, 0x04, 0x00, 0x20},	/* regulator */
+	/* timing   */
+	{0xab, 0x8a, 0x18, 0x00, 0x92, 0x97, 0x1b, 0x8c,
+	0x0c, 0x03, 0x04, 0xa0},
+	{0x5f, 0x00, 0x00, 0x10},	/* phy ctrl */
+	{0xff, 0x00, 0x06, 0x00},	/* strength */
+	/* pll control */
+	{0x40, 0xf9, 0x30, 0xda, 0x00, 0x40, 0x03, 0x62,
+	0x40, 0x07, 0x03,
+	0x00, 0x1a, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0x01},
+};
+
+static struct mipi_dsi_panel_platform_data novatek_pdata = {
+	.fpga_3d_config_addr  = FPGA_3D_GPIO_CONFIG_ADDR,
+	.fpga_ctrl_mode = FPGA_SPI_INTF,
+	.phy_ctrl_settings = &dsi_novatek_cmd_mode_phy_db,
+};
+
+static struct platform_device mipi_dsi_novatek_panel_device = {
+	.name = "mipi_novatek",
+	.id = 0,
+	.dev = {
+		.platform_data = &novatek_pdata,
+	}
+};
+
+static struct platform_device mipi_dsi2lvds_bridge_device = {
+	.name = "mipi_tc358764",
+	.id = 0,
+	.dev.platform_data = &mipi_dsi2lvds_pdata,
+};
+
+static struct platform_device mipi_dsi_orise_panel_device = {
+	.name = "mipi_orise",
+	.id = 0,
+};
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+static struct resource hdmi_msm_resources[] = {
+	{
+		.name  = "hdmi_msm_qfprom_addr",
+		.start = 0x00700000,
+		.end   = 0x007060FF,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name  = "hdmi_msm_hdmi_addr",
+		.start = 0x04A00000,
+		.end   = 0x04A00FFF,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name  = "hdmi_msm_irq",
+		.start = HDMI_IRQ,
+		.end   = HDMI_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static int hdmi_enable_5v(int on);
+static int hdmi_core_power(int on, int show);
+static int hdmi_cec_power(int on);
+
+static struct msm_hdmi_platform_data hdmi_msm_data = {
+	.irq = HDMI_IRQ,
+	.enable_5v = hdmi_enable_5v,
+	.core_power = hdmi_core_power,
+	.cec_power = hdmi_cec_power,
+};
+
+static struct platform_device hdmi_msm_device = {
+	.name = "hdmi_msm",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(hdmi_msm_resources),
+	.resource = hdmi_msm_resources,
+	.dev.platform_data = &hdmi_msm_data,
+};
+#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL */
+
+#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
+static struct platform_device wfd_panel_device = {
+	.name = "wfd_panel",
+	.id = 0,
+	.dev.platform_data = NULL,
+};
+
+static struct platform_device wfd_device = {
+	.name          = "msm_wfd",
+	.id            = -1,
+};
+#endif
+
+#ifdef CONFIG_MSM_BUS_SCALING
+static struct msm_bus_vectors dtv_bus_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+static struct msm_bus_vectors dtv_bus_def_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 566092800 * 2,
+		.ib = 707616000 * 2,
+	},
+};
+
+static struct msm_bus_paths dtv_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(dtv_bus_init_vectors),
+		dtv_bus_init_vectors,
+	},
+	{
+		ARRAY_SIZE(dtv_bus_def_vectors),
+		dtv_bus_def_vectors,
+	},
+};
+static struct msm_bus_scale_pdata dtv_bus_scale_pdata = {
+	dtv_bus_scale_usecases,
+	ARRAY_SIZE(dtv_bus_scale_usecases),
+	.name = "dtv",
+};
+
+static struct lcdc_platform_data dtv_pdata = {
+	.bus_scale_table = &dtv_bus_scale_pdata,
+};
+#endif
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+static int hdmi_enable_5v(int on)
+{
+	/* TBD: PM8921 regulator instead of 8901 */
+	static struct regulator *reg_8921_hdmi_mvs;	/* HDMI_5V */
+	static int prev_on;
+	int rc;
+
+	if (on == prev_on)
+		return 0;
+
+	if (!reg_8921_hdmi_mvs) {
+		reg_8921_hdmi_mvs = regulator_get(&hdmi_msm_device.dev,
+					"hdmi_mvs");
+		if (IS_ERR(reg_8921_hdmi_mvs)) {
+			pr_err("'%s' regulator not found, rc=%ld\n",
+				"hdmi_mvs", IS_ERR(reg_8921_hdmi_mvs));
+			reg_8921_hdmi_mvs = NULL;
+			return -ENODEV;
+		}
+	}
+
+	if (on) {
+		rc = regulator_enable(reg_8921_hdmi_mvs);
+		if (rc) {
+			pr_err("'%s' regulator enable failed, rc=%d\n",
+				"8921_hdmi_mvs", rc);
+			return rc;
+		}
+		pr_debug("%s(on): success\n", __func__);
+	} else {
+		rc = regulator_disable(reg_8921_hdmi_mvs);
+		if (rc)
+			pr_warning("'%s' regulator disable failed, rc=%d\n",
+				"8921_hdmi_mvs", rc);
+		pr_debug("%s(off): success\n", __func__);
+	}
+
+	prev_on = on;
+
+	return 0;
+}
+
+static int hdmi_core_power(int on, int show)
+{
+	static struct regulator *reg_8921_l23, *reg_8921_s4;
+	static int prev_on;
+	int rc;
+
+	if (on == prev_on)
+		return 0;
+
+	/* TBD: PM8921 regulator instead of 8901 */
+	if (!reg_8921_l23) {
+		reg_8921_l23 = regulator_get(&hdmi_msm_device.dev, "hdmi_avdd");
+		if (IS_ERR(reg_8921_l23)) {
+			pr_err("could not get reg_8921_l23, rc = %ld\n",
+				PTR_ERR(reg_8921_l23));
+			return -ENODEV;
+		}
+		rc = regulator_set_voltage(reg_8921_l23, 1800000, 1800000);
+		if (rc) {
+			pr_err("set_voltage failed for 8921_l23, rc=%d\n", rc);
+			return -EINVAL;
+		}
+	}
+	if (!reg_8921_s4) {
+		reg_8921_s4 = regulator_get(&hdmi_msm_device.dev, "hdmi_vcc");
+		if (IS_ERR(reg_8921_s4)) {
+			pr_err("could not get reg_8921_s4, rc = %ld\n",
+				PTR_ERR(reg_8921_s4));
+			return -ENODEV;
+		}
+		rc = regulator_set_voltage(reg_8921_s4, 1800000, 1800000);
+		if (rc) {
+			pr_err("set_voltage failed for 8921_s4, rc=%d\n", rc);
+			return -EINVAL;
+		}
+	}
+
+	if (on) {
+		rc = regulator_set_optimum_mode(reg_8921_l23, 100000);
+		if (rc < 0) {
+			pr_err("set_optimum_mode l23 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+		rc = regulator_enable(reg_8921_l23);
+		if (rc) {
+			pr_err("'%s' regulator enable failed, rc=%d\n",
+				"hdmi_avdd", rc);
+			return rc;
+		}
+		rc = regulator_enable(reg_8921_s4);
+		if (rc) {
+			pr_err("'%s' regulator enable failed, rc=%d\n",
+				"hdmi_vcc", rc);
+			return rc;
+		}
+		rc = gpio_request(100, "HDMI_DDC_CLK");
+		if (rc) {
+			pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+				"HDMI_DDC_CLK", 100, rc);
+			goto error1;
+		}
+		rc = gpio_request(101, "HDMI_DDC_DATA");
+		if (rc) {
+			pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+				"HDMI_DDC_DATA", 101, rc);
+			goto error2;
+		}
+		rc = gpio_request(102, "HDMI_HPD");
+		if (rc) {
+			pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+				"HDMI_HPD", 102, rc);
+			goto error3;
+		}
+		pr_debug("%s(on): success\n", __func__);
+	} else {
+		gpio_free(100);
+		gpio_free(101);
+		gpio_free(102);
+
+		rc = regulator_disable(reg_8921_l23);
+		if (rc) {
+			pr_err("disable reg_8921_l23 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		rc = regulator_disable(reg_8921_s4);
+		if (rc) {
+			pr_err("disable reg_8921_s4 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		rc = regulator_set_optimum_mode(reg_8921_l23, 100);
+		if (rc < 0) {
+			pr_err("set_optimum_mode l23 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+		pr_debug("%s(off): success\n", __func__);
+	}
+
+	prev_on = on;
+
+	return 0;
+
+error3:
+	gpio_free(101);
+error2:
+	gpio_free(100);
+error1:
+	regulator_disable(reg_8921_l23);
+	regulator_disable(reg_8921_s4);
+	return rc;
+}
+
+static int hdmi_cec_power(int on)
+{
+	static int prev_on;
+	int rc;
+
+	if (on == prev_on)
+		return 0;
+
+	if (on) {
+		rc = gpio_request(99, "HDMI_CEC_VAR");
+		if (rc) {
+			pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+				"HDMI_CEC_VAR", 99, rc);
+			goto error;
+		}
+		pr_debug("%s(on): success\n", __func__);
+	} else {
+		gpio_free(99);
+		pr_debug("%s(off): success\n", __func__);
+	}
+
+	prev_on = on;
+
+	return 0;
+error:
+	return rc;
+}
+#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL */
+
+void __init msm8960_init_fb(void)
+{
+	platform_device_register(&msm_fb_device);
+
+#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
+	platform_device_register(&wfd_panel_device);
+	platform_device_register(&wfd_device);
+#endif
+
+	if (machine_is_msm8960_sim())
+		platform_device_register(&mipi_dsi_simulator_panel_device);
+
+	if (machine_is_msm8960_rumi3())
+		platform_device_register(&mipi_dsi_renesas_panel_device);
+
+	if (!machine_is_msm8960_sim() && !machine_is_msm8960_rumi3()) {
+		platform_device_register(&mipi_dsi_novatek_panel_device);
+		platform_device_register(&mipi_dsi_orise_panel_device);
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+		platform_device_register(&hdmi_msm_device);
+#endif
+	}
+
+	if (machine_is_msm8960_liquid())
+		platform_device_register(&mipi_dsi2lvds_bridge_device);
+	else
+		platform_device_register(&mipi_dsi_toshiba_panel_device);
+
+	if (machine_is_msm8x60_rumi3()) {
+		msm_fb_register_device("mdp", NULL);
+		mipi_dsi_pdata.target_type = 1;
+	} else
+		msm_fb_register_device("mdp", &mdp_pdata);
+	msm_fb_register_device("mipi_dsi", &mipi_dsi_pdata);
+#ifdef CONFIG_MSM_BUS_SCALING
+	msm_fb_register_device("dtv", &dtv_pdata);
+#endif
+}
+
+void __init msm8960_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));
+}
+
+/**
+ * Set MDP clocks to high frequency to avoid DSI underflow
+ * when using high resolution 1200x1920 WUXGA panels
+ */
+static void set_mdp_clocks_for_wuxga(void)
+{
+	int i;
+
+	mdp_ui_vectors[0].ab = 2000000000;
+	mdp_ui_vectors[0].ib = 2000000000;
+	mdp_vga_vectors[0].ab = 2000000000;
+	mdp_vga_vectors[0].ib = 2000000000;
+	mdp_720p_vectors[0].ab = 2000000000;
+	mdp_720p_vectors[0].ib = 2000000000;
+	mdp_1080p_vectors[0].ab = 2000000000;
+	mdp_1080p_vectors[0].ib = 2000000000;
+
+	mdp_pdata.mdp_core_clk_rate = 200000000;
+
+	for (i = 0; i < ARRAY_SIZE(mdp_core_clk_rate_table); i++)
+		mdp_core_clk_rate_table[i] = 200000000;
+
+	if (hdmi_is_primary) {
+		dtv_bus_def_vectors[0].ab = 2000000000;
+		dtv_bus_def_vectors[0].ib = 2000000000;
+	}
+}
+
+void __init msm8960_set_display_params(char *prim_panel, char *ext_panel)
+{
+	int disable_splash = 0;
+	if (strnlen(prim_panel, PANEL_NAME_MAX_LEN)) {
+		strlcpy(msm_fb_pdata.prim_panel_name, prim_panel,
+			PANEL_NAME_MAX_LEN);
+		pr_debug("msm_fb_pdata.prim_panel_name %s\n",
+			msm_fb_pdata.prim_panel_name);
+
+		if (strncmp((char *)msm_fb_pdata.prim_panel_name,
+			MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME,
+			strnlen(MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME,
+				PANEL_NAME_MAX_LEN))) {
+			/* Disable splash for panels other than Toshiba WSVGA */
+			disable_splash = 1;
+		}
+
+		if (!strncmp((char *)msm_fb_pdata.prim_panel_name,
+			HDMI_PANEL_NAME, strnlen(HDMI_PANEL_NAME,
+				PANEL_NAME_MAX_LEN))) {
+			pr_debug("HDMI is the primary display by"
+				" boot parameter\n");
+			hdmi_is_primary = 1;
+			set_mdp_clocks_for_wuxga();
+		}
+		if (!strncmp((char *)msm_fb_pdata.prim_panel_name,
+				MIPI_VIDEO_TOSHIBA_WUXGA_PANEL_NAME,
+				strnlen(MIPI_VIDEO_TOSHIBA_WUXGA_PANEL_NAME,
+					PANEL_NAME_MAX_LEN))) {
+			set_mdp_clocks_for_wuxga();
+		}
+	}
+	if (strnlen(ext_panel, PANEL_NAME_MAX_LEN)) {
+		strlcpy(msm_fb_pdata.ext_panel_name, ext_panel,
+			PANEL_NAME_MAX_LEN);
+		pr_debug("msm_fb_pdata.ext_panel_name %s\n",
+			msm_fb_pdata.ext_panel_name);
+	}
+
+	if (disable_splash)
+		mdp_pdata.cont_splash_enabled = 0;
+}
diff --git a/arch/arm/mach-msm/board-8960-gpiomux.c b/arch/arm/mach-msm/board-8960-gpiomux.c
new file mode 100644
index 0000000..fd326f1
--- /dev/null
+++ b/arch/arm/mach-msm/board-8960-gpiomux.c
@@ -0,0 +1,1004 @@
+/* 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
+ * 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/gpio.h>
+#include <asm/mach-types.h>
+#include <mach/gpiomux.h>
+#include <mach/socinfo.h>
+#include "devices.h"
+#include "board-8960.h"
+
+/* The SPI configurations apply to GSBI 1*/
+static struct gpiomux_setting spi_active = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_12MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting spi_suspended_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting spi_active_config2 = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting spi_suspended_config2 = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting gsbi3_suspended_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_KEEPER,
+};
+
+static struct gpiomux_setting gsbi3_active_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting external_vfr[] = {
+	/* Suspended state */
+	{
+		.func = GPIOMUX_FUNC_3,
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_KEEPER,
+	},
+	/* Active state */
+	{
+		.func = GPIOMUX_FUNC_3,
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_KEEPER,
+	},
+};
+
+static struct gpiomux_setting gsbi_uart = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi9_active_cfg = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting gsbi9_suspended_cfg = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting gsbi10 = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi12 = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting cdc_mclk = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting audio_auxpcm[] = {
+	/* Suspended state */
+	{
+		.func = GPIOMUX_FUNC_GPIO,
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_DOWN,
+	},
+	/* Active state */
+	{
+		.func = GPIOMUX_FUNC_1,
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+};
+
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+static struct gpiomux_setting gpio_eth_config = {
+	.pull = GPIOMUX_PULL_NONE,
+	.drv = GPIOMUX_DRV_8MA,
+	.func = GPIOMUX_FUNC_GPIO,
+};
+#endif
+
+static struct gpiomux_setting slimbus = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_KEEPER,
+};
+
+static struct gpiomux_setting wcnss_5wire_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv  = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting wcnss_5wire_active_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv  = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting cyts_resout_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting cyts_resout_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting cyts_sleep_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting cyts_sleep_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting cyts_int_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting cyts_int_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+#ifdef CONFIG_USB_EHCI_MSM_HSIC
+static struct gpiomux_setting hsic_act_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_12MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting hsic_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+	.dir = GPIOMUX_OUT_LOW,
+};
+
+static struct gpiomux_setting hsic_hub_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+#endif
+
+static struct gpiomux_setting hap_lvl_shft_suspended_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting hap_lvl_shft_active_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting ap2mdm_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting mdm2ap_status_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting mdm2ap_errfatal_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_16MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting ap2mdm_kpdpwr_n_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting mdp_vsync_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting mdp_vsync_active_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+static struct gpiomux_setting hdmi_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting hdmi_active_1_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting hdmi_active_2_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+#if defined(CONFIG_FB_MSM_HDMI_MHL_8334) || defined(CONFIG_FB_MSM_HDMI_MHL_9244)
+static struct gpiomux_setting hdmi_active_3_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+	.dir = GPIOMUX_IN,
+};
+
+static struct gpiomux_setting hdmi_active_4_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+	.dir = GPIOMUX_OUT_HIGH,
+};
+#endif
+#endif
+
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+static struct msm_gpiomux_config msm8960_ethernet_configs[] = {
+	{
+		.gpio = 90,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_eth_config,
+		}
+	},
+	{
+		.gpio = 89,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_eth_config,
+		}
+	},
+};
+#endif
+
+static struct msm_gpiomux_config msm8960_fusion_gsbi_configs[] = {
+	{
+		.gpio = 93,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi9_suspended_cfg,
+			[GPIOMUX_ACTIVE] = &gsbi9_active_cfg,
+		}
+	},
+	{
+		.gpio = 94,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi9_suspended_cfg,
+			[GPIOMUX_ACTIVE] = &gsbi9_active_cfg,
+		}
+	},
+	{
+		.gpio = 95,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi9_suspended_cfg,
+			[GPIOMUX_ACTIVE] = &gsbi9_active_cfg,
+		}
+	},
+	{
+		.gpio = 96,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi9_suspended_cfg,
+			[GPIOMUX_ACTIVE] = &gsbi9_active_cfg,
+		}
+	},
+};
+
+static struct msm_gpiomux_config msm8960_gsbi_configs[] __initdata = {
+	{
+		.gpio      = 6,		/* GSBI1 QUP SPI_DATA_MOSI */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &spi_suspended_config,
+			[GPIOMUX_ACTIVE] = &spi_active,
+		},
+	},
+	{
+		.gpio      = 7,		/* GSBI1 QUP SPI_DATA_MISO */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &spi_suspended_config,
+			[GPIOMUX_ACTIVE] = &spi_active,
+		},
+	},
+	{
+		.gpio      = 8,		/* GSBI1 QUP SPI_CS_N */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &spi_suspended_config,
+			[GPIOMUX_ACTIVE] = &spi_active,
+		},
+	},
+	{
+		.gpio      = 9,		/* GSBI1 QUP SPI_CLK */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &spi_suspended_config,
+			[GPIOMUX_ACTIVE] = &spi_active,
+		},
+	},
+	{
+		.gpio      = 14,		/* GSBI1 SPI_CS_1 */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &spi_suspended_config2,
+			[GPIOMUX_ACTIVE] = &spi_active_config2,
+		},
+	},
+	{
+		.gpio      = 16,	/* GSBI3 I2C QUP SDA */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi3_suspended_cfg,
+			[GPIOMUX_ACTIVE] = &gsbi3_active_cfg,
+		},
+	},
+	{
+		.gpio      = 17,	/* GSBI3 I2C QUP SCL */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi3_suspended_cfg,
+			[GPIOMUX_ACTIVE] = &gsbi3_active_cfg,
+		},
+	},
+	{
+		.gpio      = 44,	/* GSBI12 I2C QUP SDA */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi12,
+		},
+	},
+	{
+		.gpio      = 45,	/* GSBI12 I2C QUP SCL */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi12,
+		},
+	},
+	{
+		.gpio      = 73,	/* GSBI10 I2C QUP SDA */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi10,
+		},
+	},
+	{
+		.gpio      = 74,	/* GSBI10 I2C QUP SCL */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi10,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8960_gsbi5_uart_configs[] __initdata = {
+	{
+		.gpio      = 22,        /* GSBI5 UART2 */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi_uart,
+		},
+	},
+	{
+		.gpio      = 23,        /* GSBI5 UART2 */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi_uart,
+		},
+	},
+	{
+		.gpio      = 24,        /* GSBI5 UART2 */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi_uart,
+		},
+	},
+	{
+		.gpio      = 25,        /* GSBI5 UART2 */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi_uart,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8960_external_vfr_configs[] __initdata = {
+	{
+		.gpio      = 23,        /* EXTERNAL VFR */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &external_vfr[0],
+			[GPIOMUX_ACTIVE] = &external_vfr[1],
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8960_gsbi8_uart_configs[] __initdata = {
+	{
+		.gpio      = 34,        /* GSBI8 UART3 */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi_uart,
+		},
+	},
+	{
+		.gpio      = 35,        /* GSBI8 UART3 */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi_uart,
+		},
+	},
+	{
+		.gpio      = 36,        /* GSBI8 UART3 */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi_uart,
+		},
+	},
+	{
+		.gpio      = 37,        /* GSBI8 UART3 */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi_uart,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8960_slimbus_config[] __initdata = {
+	{
+		.gpio	= 60,		/* slimbus data */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &slimbus,
+		},
+	},
+	{
+		.gpio	= 61,		/* slimbus clk */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &slimbus,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8960_audio_codec_configs[] __initdata = {
+	{
+		.gpio = 59,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &cdc_mclk,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8960_audio_auxpcm_configs[] __initdata = {
+	{
+		.gpio = 63,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+			[GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+		},
+	},
+	{
+		.gpio = 64,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+			[GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+		},
+	},
+	{
+		.gpio = 65,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+			[GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+		},
+	},
+	{
+		.gpio = 66,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+			[GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+		},
+	},
+};
+
+static struct msm_gpiomux_config wcnss_5wire_interface[] = {
+	{
+		.gpio = 84,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5wire_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 85,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5wire_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 86,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5wire_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 87,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5wire_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 88,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5wire_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8960_cyts_configs[] __initdata = {
+	{	/* TS INTERRUPT */
+		.gpio = 11,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cyts_int_act_cfg,
+			[GPIOMUX_SUSPENDED] = &cyts_int_sus_cfg,
+		},
+	},
+	{	/* TS SLEEP */
+		.gpio = 50,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cyts_sleep_act_cfg,
+			[GPIOMUX_SUSPENDED] = &cyts_sleep_sus_cfg,
+		},
+	},
+	{	/* TS RESOUT */
+		.gpio = 52,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cyts_resout_act_cfg,
+			[GPIOMUX_SUSPENDED] = &cyts_resout_sus_cfg,
+		},
+	},
+};
+
+#ifdef CONFIG_USB_EHCI_MSM_HSIC
+static struct msm_gpiomux_config msm8960_hsic_configs[] = {
+	{
+		.gpio = 150,               /*HSIC_STROBE */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &hsic_act_cfg,
+			[GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
+		},
+	},
+	{
+		.gpio = 151,               /* HSIC_DATA */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &hsic_act_cfg,
+			[GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8960_hsic_hub_configs[] = {
+	{
+		.gpio = 91,               /* HSIC_HUB_RESET */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &hsic_hub_act_cfg,
+			[GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
+		},
+	},
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+static struct gpiomux_setting sdcc4_clk_actv_cfg = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting sdcc4_cmd_data_0_3_actv_cfg = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting sdcc4_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting sdcc4_data_1_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config msm8960_sdcc4_configs[] __initdata = {
+	{
+		/* SDC4_DATA_3 */
+		.gpio      = 83,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc4_cmd_data_0_3_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc4_suspend_cfg,
+		},
+	},
+	{
+		/* SDC4_DATA_2 */
+		.gpio      = 84,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc4_cmd_data_0_3_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc4_suspend_cfg,
+		},
+	},
+	{
+		/* SDC4_DATA_1 */
+		.gpio      = 85,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc4_cmd_data_0_3_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc4_data_1_suspend_cfg,
+		},
+	},
+	{
+		/* SDC4_DATA_0 */
+		.gpio      = 86,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc4_cmd_data_0_3_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc4_suspend_cfg,
+		},
+	},
+	{
+		/* SDC4_CMD */
+		.gpio      = 87,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc4_cmd_data_0_3_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc4_suspend_cfg,
+		},
+	},
+	{
+		/* SDC4_CLK */
+		.gpio      = 88,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc4_clk_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc4_suspend_cfg,
+		},
+	},
+};
+#endif
+
+
+static struct msm_gpiomux_config hap_lvl_shft_config[] __initdata = {
+	{
+		.gpio = 47,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &hap_lvl_shft_suspended_config,
+			[GPIOMUX_ACTIVE] = &hap_lvl_shft_active_config,
+		},
+	},
+};
+
+static struct msm_gpiomux_config sglte_configs[] __initdata = {
+	/* AP2MDM_STATUS */
+	{
+		.gpio = 77,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
+		}
+	},
+	/* MDM2AP_STATUS */
+	{
+		.gpio = 24,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &mdm2ap_status_cfg,
+		}
+	},
+	/* MDM2AP_ERRFATAL */
+	{
+		.gpio = 40,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &mdm2ap_errfatal_cfg,
+		}
+	},
+	/* AP2MDM_ERRFATAL */
+	{
+		.gpio = 80,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
+		}
+	},
+	/* AP2MDM_KPDPWR_N */
+	{
+		.gpio = 79,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_kpdpwr_n_cfg,
+		}
+	},
+	/* AP2MDM_PMIC_PWR_EN */
+	{
+		.gpio = 22,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_kpdpwr_n_cfg,
+		}
+	},
+	/* AP2MDM_SOFT_RESET */
+	{
+		.gpio = 78,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
+		}
+	},
+};
+
+static struct msm_gpiomux_config msm8960_mdp_vsync_configs[] __initdata = {
+	{
+		.gpio = 0,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &mdp_vsync_active_cfg,
+			[GPIOMUX_SUSPENDED] = &mdp_vsync_suspend_cfg,
+		},
+	}
+};
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+static struct msm_gpiomux_config msm8960_hdmi_configs[] __initdata = {
+	{
+		.gpio = 99,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_1_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 100,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_1_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 101,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_1_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 102,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_2_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+#ifdef CONFIG_FB_MSM_HDMI_MHL_9244
+		{
+		.gpio = 15,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_3_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 66,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_4_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+#endif
+#ifdef CONFIG_FB_MSM_HDMI_MHL_8334
+		{
+		.gpio = 4,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_3_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 15,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_4_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+#endif /* CONFIG_FB_MSM_HDMI_MHL */
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+static struct gpiomux_setting sdcc2_clk_actv_cfg = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting sdcc2_cmd_data_0_3_actv_cfg = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting sdcc2_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting sdcc2_data_1_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config msm8960_sdcc2_configs[] __initdata = {
+	{
+		/* DATA_3 */
+		.gpio      = 92,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_cmd_data_0_3_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+		},
+	},
+	{
+		/* DATA_2 */
+		.gpio      = 91,
+		.settings = {
+		[GPIOMUX_ACTIVE]    = &sdcc2_cmd_data_0_3_actv_cfg,
+		[GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+		},
+	},
+	{
+		/* DATA_1 */
+		.gpio      = 90,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_cmd_data_0_3_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_data_1_suspend_cfg,
+		},
+	},
+	{
+		/* DATA_0 */
+		.gpio      = 89,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_cmd_data_0_3_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+		},
+	},
+	{
+		/* CMD */
+		.gpio      = 97,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_cmd_data_0_3_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+		},
+	},
+	{
+		/* CLK */
+		.gpio      = 98,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_clk_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+		},
+	},
+};
+#endif
+
+int __init msm8960_init_gpiomux(void)
+{
+	int rc = msm_gpiomux_init(NR_GPIO_IRQS);
+	if (rc) {
+		pr_err(KERN_ERR "msm_gpiomux_init failed %d\n", rc);
+		return rc;
+	}
+
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+	msm_gpiomux_install(msm8960_ethernet_configs,
+			ARRAY_SIZE(msm8960_ethernet_configs));
+#endif
+
+	msm_gpiomux_install(msm8960_gsbi_configs,
+			ARRAY_SIZE(msm8960_gsbi_configs));
+
+	msm_gpiomux_install(msm8960_cyts_configs,
+			ARRAY_SIZE(msm8960_cyts_configs));
+
+	msm_gpiomux_install(msm8960_slimbus_config,
+			ARRAY_SIZE(msm8960_slimbus_config));
+
+	msm_gpiomux_install(msm8960_audio_codec_configs,
+			ARRAY_SIZE(msm8960_audio_codec_configs));
+
+	msm_gpiomux_install(msm8960_audio_auxpcm_configs,
+			ARRAY_SIZE(msm8960_audio_auxpcm_configs));
+
+	msm_gpiomux_install(wcnss_5wire_interface,
+			ARRAY_SIZE(wcnss_5wire_interface));
+
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+	msm_gpiomux_install(msm8960_sdcc4_configs,
+		ARRAY_SIZE(msm8960_sdcc4_configs));
+#endif
+
+	if (machine_is_msm8960_mtp() || machine_is_msm8960_fluid() ||
+		machine_is_msm8960_liquid() || machine_is_msm8960_cdp())
+		msm_gpiomux_install(hap_lvl_shft_config,
+			ARRAY_SIZE(hap_lvl_shft_config));
+
+#ifdef CONFIG_USB_EHCI_MSM_HSIC
+	if ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) != 1) &&
+		machine_is_msm8960_liquid())
+		msm_gpiomux_install(msm8960_hsic_configs,
+			ARRAY_SIZE(msm8960_hsic_configs));
+
+	if ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) != 1) &&
+			machine_is_msm8960_liquid())
+		msm_gpiomux_install(msm8960_hsic_hub_configs,
+			ARRAY_SIZE(msm8960_hsic_hub_configs));
+#endif
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+	msm_gpiomux_install(msm8960_hdmi_configs,
+			ARRAY_SIZE(msm8960_hdmi_configs));
+#endif
+
+	msm_gpiomux_install(msm8960_mdp_vsync_configs,
+			ARRAY_SIZE(msm8960_mdp_vsync_configs));
+
+	if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE)
+		msm_gpiomux_install(msm8960_gsbi8_uart_configs,
+			ARRAY_SIZE(msm8960_gsbi8_uart_configs));
+	else
+		msm_gpiomux_install(msm8960_gsbi5_uart_configs,
+			ARRAY_SIZE(msm8960_gsbi5_uart_configs));
+
+	if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
+		/* For 8960 Fusion 2.2 Primary IPC */
+		msm_gpiomux_install(msm8960_fusion_gsbi_configs,
+			ARRAY_SIZE(msm8960_fusion_gsbi_configs));
+		/* For SGLTE 8960 Fusion External VFR */
+		msm_gpiomux_install(msm8960_external_vfr_configs,
+			ARRAY_SIZE(msm8960_external_vfr_configs));
+	}
+
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+	msm_gpiomux_install(msm8960_sdcc2_configs,
+		ARRAY_SIZE(msm8960_sdcc2_configs));
+#endif
+
+	if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE)
+		msm_gpiomux_install(sglte_configs,
+			ARRAY_SIZE(sglte_configs));
+
+	return 0;
+}
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
new file mode 100644
index 0000000..ea1ab58
--- /dev/null
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -0,0 +1,624 @@
+/* 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
+ * 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/interrupt.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
+#include <linux/leds.h>
+#include <linux/leds-pm8xxx.h>
+#include <linux/msm_ssbi.h>
+#include <asm/mach-types.h>
+#include <mach/msm_bus_board.h>
+#include <mach/restart.h>
+#include "devices.h"
+#include "board-8960.h"
+
+struct pm8xxx_gpio_init {
+	unsigned			gpio;
+	struct pm_gpio			config;
+};
+
+struct pm8xxx_mpp_init {
+	unsigned			mpp;
+	struct pm8xxx_mpp_config_data	config;
+};
+
+#define PM8XXX_GPIO_INIT(_gpio, _dir, _buf, _val, _pull, _vin, _out_strength, \
+			_func, _inv, _disable) \
+{ \
+	.gpio	= PM8921_GPIO_PM_TO_SYS(_gpio), \
+	.config	= { \
+		.direction	= _dir, \
+		.output_buffer	= _buf, \
+		.output_value	= _val, \
+		.pull		= _pull, \
+		.vin_sel	= _vin, \
+		.out_strength	= _out_strength, \
+		.function	= _func, \
+		.inv_int_pol	= _inv, \
+		.disable_pin	= _disable, \
+	} \
+}
+
+#define PM8XXX_MPP_INIT(_mpp, _type, _level, _control) \
+{ \
+	.mpp	= PM8921_MPP_PM_TO_SYS(_mpp), \
+	.config	= { \
+		.type		= PM8XXX_MPP_TYPE_##_type, \
+		.level		= _level, \
+		.control	= PM8XXX_MPP_##_control, \
+	} \
+}
+
+#define PM8XXX_GPIO_DISABLE(_gpio) \
+	PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, 0, 0, 0, PM_GPIO_VIN_S4, \
+			 0, 0, 0, 1)
+
+#define PM8XXX_GPIO_OUTPUT(_gpio, _val) \
+	PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+			PM_GPIO_PULL_NO, PM_GPIO_VIN_S4, \
+			PM_GPIO_STRENGTH_HIGH, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
+#define PM8XXX_GPIO_INPUT(_gpio, _pull) \
+	PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, PM_GPIO_OUT_BUF_CMOS, 0, \
+			_pull, PM_GPIO_VIN_S4, \
+			PM_GPIO_STRENGTH_NO, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
+#define PM8XXX_GPIO_OUTPUT_FUNC(_gpio, _val, _func) \
+	PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+			PM_GPIO_PULL_NO, PM_GPIO_VIN_S4, \
+			PM_GPIO_STRENGTH_HIGH, \
+			_func, 0, 0)
+
+#define PM8XXX_GPIO_OUTPUT_VIN(_gpio, _val, _vin) \
+	PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+			PM_GPIO_PULL_NO, _vin, \
+			PM_GPIO_STRENGTH_HIGH, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
+#define PM8XXX_GPIO_OUTPUT_STRENGTH(_gpio, _val, _out_strength) \
+	PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+			PM_GPIO_PULL_NO, PM_GPIO_VIN_S4, \
+			_out_strength, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
+/* Initial PM8921 GPIO configurations */
+static struct pm8xxx_gpio_init pm8921_gpios[] __initdata = {
+	PM8XXX_GPIO_OUTPUT_VIN(6, 1, PM_GPIO_VIN_VPH),	 /* MHL power EN_N */
+	PM8XXX_GPIO_DISABLE(7),				 /* Disable NFC */
+	PM8XXX_GPIO_INPUT(16,	    PM_GPIO_PULL_UP_30), /* SD_CARD_WP */
+    /* External regulator shared by display and touchscreen on LiQUID */
+	PM8XXX_GPIO_OUTPUT(17,	    0),			 /* DISP 3.3 V Boost */
+	PM8XXX_GPIO_OUTPUT(18,	0),	/* TABLA SPKR_LEFT_EN=off */
+	PM8XXX_GPIO_OUTPUT(19,	0),	/* TABLA SPKR_RIGHT_EN=off */
+	PM8XXX_GPIO_DISABLE(22),			 /* Disable NFC */
+	PM8XXX_GPIO_OUTPUT_FUNC(25, 0, PM_GPIO_FUNC_2),	 /* TN_CLK */
+	PM8XXX_GPIO_INPUT(26,	    PM_GPIO_PULL_UP_30), /* SD_CARD_DET_N */
+	PM8XXX_GPIO_OUTPUT(43, 1),                       /* DISP_RESET_N */
+	PM8XXX_GPIO_OUTPUT(42, 0),                      /* USB 5V reg enable */
+	/* TABLA CODEC RESET */
+	PM8XXX_GPIO_OUTPUT_STRENGTH(34, 1, PM_GPIO_STRENGTH_MED)
+};
+
+/* Initial PM8921 MPP configurations */
+static struct pm8xxx_mpp_init pm8921_mpps[] __initdata = {
+	/* External 5V regulator enable; shared by HDMI and USB_OTG switches. */
+	PM8XXX_MPP_INIT(7, D_INPUT, PM8921_MPP_DIG_LEVEL_VPH, DIN_TO_INT),
+	PM8XXX_MPP_INIT(PM8XXX_AMUX_MPP_8, A_INPUT, PM8XXX_MPP_AIN_AMUX_CH8,
+								DOUT_CTRL_LOW),
+};
+
+void __init msm8960_pm8921_gpio_mpp_init(void)
+{
+	int i, rc;
+
+	for (i = 0; i < ARRAY_SIZE(pm8921_gpios); i++) {
+		rc = pm8xxx_gpio_config(pm8921_gpios[i].gpio,
+					&pm8921_gpios[i].config);
+		if (rc) {
+			pr_err("%s: pm8xxx_gpio_config: rc=%d\n", __func__, rc);
+			break;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(pm8921_mpps); i++) {
+		rc = pm8xxx_mpp_config(pm8921_mpps[i].mpp,
+					&pm8921_mpps[i].config);
+		if (rc) {
+			pr_err("%s: pm8xxx_mpp_config: rc=%d\n", __func__, rc);
+			break;
+		}
+	}
+}
+
+static struct pm8xxx_adc_amux pm8xxx_adc_channels_data[] = {
+	{"vcoin", CHANNEL_VCOIN, CHAN_PATH_SCALING2, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"vbat", CHANNEL_VBAT, CHAN_PATH_SCALING2, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"dcin", CHANNEL_DCIN, CHAN_PATH_SCALING4, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"ichg", CHANNEL_ICHG, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"vph_pwr", CHANNEL_VPH_PWR, CHAN_PATH_SCALING2, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"ibat", CHANNEL_IBAT, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"batt_therm", CHANNEL_BATT_THERM, CHAN_PATH_SCALING1, AMUX_RSV2,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_BATT_THERM},
+	{"batt_id", CHANNEL_BATT_ID, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"usbin", CHANNEL_USBIN, CHAN_PATH_SCALING3, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"pmic_therm", CHANNEL_DIE_TEMP, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_PMIC_THERM},
+	{"625mv", CHANNEL_625MV, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"125v", CHANNEL_125V, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"chg_temp", CHANNEL_CHG_TEMP, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"pa_therm1", ADC_MPP_1_AMUX8, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_PA_THERM},
+	{"xo_therm", CHANNEL_MUXOFF, CHAN_PATH_SCALING1, AMUX_RSV0,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_XOTHERM},
+	{"pa_therm0", ADC_MPP_1_AMUX3, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_PA_THERM},
+};
+
+static struct pm8xxx_adc_properties pm8xxx_adc_data = {
+	.adc_vdd_reference	= 1800, /* milli-voltage for this adc */
+	.bitresolution		= 15,
+	.bipolar                = 0,
+};
+
+static struct pm8xxx_adc_platform_data pm8xxx_adc_pdata = {
+	.adc_channel            = pm8xxx_adc_channels_data,
+	.adc_num_board_channel  = ARRAY_SIZE(pm8xxx_adc_channels_data),
+	.adc_prop               = &pm8xxx_adc_data,
+	.adc_mpp_base		= PM8921_MPP_PM_TO_SYS(1),
+};
+
+static struct pm8xxx_irq_platform_data pm8xxx_irq_pdata __devinitdata = {
+	.irq_base		= PM8921_IRQ_BASE,
+	.devirq			= MSM_GPIO_TO_INT(104),
+	.irq_trigger_flag	= IRQF_TRIGGER_LOW,
+};
+
+static struct pm8xxx_gpio_platform_data pm8xxx_gpio_pdata __devinitdata = {
+	.gpio_base	= PM8921_GPIO_PM_TO_SYS(1),
+};
+
+static struct pm8xxx_mpp_platform_data pm8xxx_mpp_pdata __devinitdata = {
+	.mpp_base	= PM8921_MPP_PM_TO_SYS(1),
+};
+
+static struct pm8xxx_rtc_platform_data pm8xxx_rtc_pdata __devinitdata = {
+	.rtc_write_enable       = false,
+	.rtc_alarm_powerup	= false,
+};
+
+static struct pm8xxx_pwrkey_platform_data pm8xxx_pwrkey_pdata = {
+	.pull_up		= 1,
+	.kpd_trigger_delay_us	= 15625,
+	.wakeup			= 1,
+};
+
+/* Rotate lock key is not available so use F1 */
+#define KEY_ROTATE_LOCK KEY_F1
+
+static const unsigned int keymap_liquid[] = {
+	KEY(0, 0, KEY_VOLUMEUP),
+	KEY(0, 1, KEY_VOLUMEDOWN),
+	KEY(1, 3, KEY_ROTATE_LOCK),
+	KEY(1, 4, KEY_HOME),
+};
+
+static struct matrix_keymap_data keymap_data_liquid = {
+	.keymap_size    = ARRAY_SIZE(keymap_liquid),
+	.keymap         = keymap_liquid,
+};
+
+static struct pm8xxx_keypad_platform_data keypad_data_liquid = {
+	.input_name             = "keypad_8960_liquid",
+	.input_phys_device      = "keypad_8960/input0",
+	.num_rows               = 2,
+	.num_cols               = 5,
+	.rows_gpio_start	= PM8921_GPIO_PM_TO_SYS(9),
+	.cols_gpio_start	= PM8921_GPIO_PM_TO_SYS(1),
+	.debounce_ms            = 15,
+	.scan_delay_ms          = 32,
+	.row_hold_ns            = 91500,
+	.wakeup                 = 1,
+	.keymap_data            = &keymap_data_liquid,
+};
+
+
+static const unsigned int keymap[] = {
+	KEY(0, 0, KEY_VOLUMEUP),
+	KEY(0, 1, KEY_VOLUMEDOWN),
+	KEY(0, 2, KEY_CAMERA_SNAPSHOT),
+	KEY(0, 3, KEY_CAMERA_FOCUS),
+};
+
+static struct matrix_keymap_data keymap_data = {
+	.keymap_size    = ARRAY_SIZE(keymap),
+	.keymap         = keymap,
+};
+
+static struct pm8xxx_keypad_platform_data keypad_data = {
+	.input_name             = "keypad_8960",
+	.input_phys_device      = "keypad_8960/input0",
+	.num_rows               = 1,
+	.num_cols               = 5,
+	.rows_gpio_start	= PM8921_GPIO_PM_TO_SYS(9),
+	.cols_gpio_start	= PM8921_GPIO_PM_TO_SYS(1),
+	.debounce_ms            = 15,
+	.scan_delay_ms          = 32,
+	.row_hold_ns            = 91500,
+	.wakeup                 = 1,
+	.keymap_data            = &keymap_data,
+};
+
+static const unsigned int keymap_sim[] = {
+	KEY(0, 0, KEY_7),
+	KEY(0, 1, KEY_DOWN),
+	KEY(0, 2, KEY_UP),
+	KEY(0, 3, KEY_RIGHT),
+	KEY(0, 4, KEY_ENTER),
+	KEY(0, 5, KEY_L),
+	KEY(0, 6, KEY_BACK),
+	KEY(0, 7, KEY_M),
+
+	KEY(1, 0, KEY_LEFT),
+	KEY(1, 1, KEY_SEND),
+	KEY(1, 2, KEY_1),
+	KEY(1, 3, KEY_4),
+	KEY(1, 4, KEY_CLEAR),
+	KEY(1, 5, KEY_MSDOS),
+	KEY(1, 6, KEY_SPACE),
+	KEY(1, 7, KEY_COMMA),
+
+	KEY(2, 0, KEY_6),
+	KEY(2, 1, KEY_5),
+	KEY(2, 2, KEY_8),
+	KEY(2, 3, KEY_3),
+	KEY(2, 4, KEY_NUMERIC_STAR),
+	KEY(2, 5, KEY_UP),
+	KEY(2, 6, KEY_DOWN),
+	KEY(2, 7, KEY_LEFTSHIFT),
+
+	KEY(3, 0, KEY_9),
+	KEY(3, 1, KEY_NUMERIC_POUND),
+	KEY(3, 2, KEY_0),
+	KEY(3, 3, KEY_2),
+	KEY(3, 4, KEY_SLEEP),
+	KEY(3, 5, KEY_F1),
+	KEY(3, 6, KEY_F2),
+	KEY(3, 7, KEY_F3),
+
+	KEY(4, 0, KEY_BACK),
+	KEY(4, 1, KEY_HOME),
+	KEY(4, 2, KEY_MENU),
+	KEY(4, 3, KEY_VOLUMEUP),
+	KEY(4, 4, KEY_VOLUMEDOWN),
+	KEY(4, 5, KEY_F4),
+	KEY(4, 6, KEY_F5),
+	KEY(4, 7, KEY_F6),
+
+	KEY(5, 0, KEY_R),
+	KEY(5, 1, KEY_T),
+	KEY(5, 2, KEY_Y),
+	KEY(5, 3, KEY_LEFTALT),
+	KEY(5, 4, KEY_KPENTER),
+	KEY(5, 5, KEY_Q),
+	KEY(5, 6, KEY_W),
+	KEY(5, 7, KEY_E),
+
+	KEY(6, 0, KEY_F),
+	KEY(6, 1, KEY_G),
+	KEY(6, 2, KEY_H),
+	KEY(6, 3, KEY_CAPSLOCK),
+	KEY(6, 4, KEY_PAGEUP),
+	KEY(6, 5, KEY_A),
+	KEY(6, 6, KEY_S),
+	KEY(6, 7, KEY_D),
+
+	KEY(7, 0, KEY_V),
+	KEY(7, 1, KEY_B),
+	KEY(7, 2, KEY_N),
+	KEY(7, 3, KEY_MENU),
+	KEY(7, 4, KEY_PAGEDOWN),
+	KEY(7, 5, KEY_Z),
+	KEY(7, 6, KEY_X),
+	KEY(7, 7, KEY_C),
+
+	KEY(8, 0, KEY_P),
+	KEY(8, 1, KEY_J),
+	KEY(8, 2, KEY_K),
+	KEY(8, 3, KEY_INSERT),
+	KEY(8, 4, KEY_LINEFEED),
+	KEY(8, 5, KEY_U),
+	KEY(8, 6, KEY_I),
+	KEY(8, 7, KEY_O),
+
+	KEY(9, 0, KEY_4),
+	KEY(9, 1, KEY_5),
+	KEY(9, 2, KEY_6),
+	KEY(9, 3, KEY_7),
+	KEY(9, 4, KEY_8),
+	KEY(9, 5, KEY_1),
+	KEY(9, 6, KEY_2),
+	KEY(9, 7, KEY_3),
+
+	KEY(10, 0, KEY_F7),
+	KEY(10, 1, KEY_F8),
+	KEY(10, 2, KEY_F9),
+	KEY(10, 3, KEY_F10),
+	KEY(10, 4, KEY_FN),
+	KEY(10, 5, KEY_9),
+	KEY(10, 6, KEY_0),
+	KEY(10, 7, KEY_DOT),
+
+	KEY(11, 0, KEY_LEFTCTRL),
+	KEY(11, 1, KEY_F11),
+	KEY(11, 2, KEY_ENTER),
+	KEY(11, 3, KEY_SEARCH),
+	KEY(11, 4, KEY_DELETE),
+	KEY(11, 5, KEY_RIGHT),
+	KEY(11, 6, KEY_LEFT),
+	KEY(11, 7, KEY_RIGHTSHIFT),
+	KEY(0, 0, KEY_VOLUMEUP),
+	KEY(0, 1, KEY_VOLUMEDOWN),
+	KEY(0, 2, KEY_CAMERA_SNAPSHOT),
+	KEY(0, 3, KEY_CAMERA_FOCUS),
+};
+
+static struct matrix_keymap_data keymap_data_sim = {
+	.keymap_size    = ARRAY_SIZE(keymap_sim),
+	.keymap         = keymap_sim,
+};
+
+static struct pm8xxx_keypad_platform_data keypad_data_sim = {
+	.input_name             = "keypad_8960",
+	.input_phys_device      = "keypad_8960/input0",
+	.num_rows               = 12,
+	.num_cols               = 8,
+	.rows_gpio_start	= PM8921_GPIO_PM_TO_SYS(9),
+	.cols_gpio_start	= PM8921_GPIO_PM_TO_SYS(1),
+	.debounce_ms            = 15,
+	.scan_delay_ms          = 32,
+	.row_hold_ns            = 91500,
+	.wakeup                 = 1,
+	.keymap_data            = &keymap_data_sim,
+};
+
+static int pm8921_therm_mitigation[] = {
+	1100,
+	700,
+	600,
+	325,
+};
+
+#define MAX_VOLTAGE_MV		4200
+static struct pm8921_charger_platform_data pm8921_chg_pdata __devinitdata = {
+	.safety_time		= 180,
+	.update_time		= 60000,
+	.max_voltage		= MAX_VOLTAGE_MV,
+	.min_voltage		= 3200,
+	.resume_voltage_delta	= 100,
+	.term_current		= 100,
+	.cool_temp		= 10,
+	.warm_temp		= 40,
+	.temp_check_period	= 1,
+	.max_bat_chg_current	= 1100,
+	.cool_bat_chg_current	= 350,
+	.warm_bat_chg_current	= 350,
+	.cool_bat_voltage	= 4100,
+	.warm_bat_voltage	= 4100,
+	.thermal_mitigation	= pm8921_therm_mitigation,
+	.thermal_levels		= ARRAY_SIZE(pm8921_therm_mitigation),
+	.rconn_mohm		= 18,
+};
+
+static struct pm8xxx_misc_platform_data pm8xxx_misc_pdata = {
+	.priority		= 0,
+};
+
+static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = {
+	.battery_type	= BATT_UNKNOWN,
+	.r_sense		= 10,
+	.i_test			= 2500,
+	.v_failure		= 3000,
+	.calib_delay_ms		= 600000,
+	.max_voltage_uv		= MAX_VOLTAGE_MV * 1000,
+	.rconn_mohm		= 30,
+};
+
+#define	PM8921_LC_LED_MAX_CURRENT	4	/* I = 4mA */
+#define	PM8921_LC_LED_LOW_CURRENT	1	/* I = 1mA */
+#define PM8XXX_LED_PWM_PERIOD		1000
+#define PM8XXX_LED_PWM_DUTY_MS		20
+/**
+ * PM8XXX_PWM_CHANNEL_NONE shall be used when LED shall not be
+ * driven using PWM feature.
+ */
+#define PM8XXX_PWM_CHANNEL_NONE		-1
+
+static struct led_info pm8921_led_info_liquid[] = {
+	{
+		.name		= "led:red",
+		.flags		= PM8XXX_ID_LED_0,
+		.default_trigger	= "battery-charging",
+	},
+	{
+		.name		= "led:green",
+		.flags		= PM8XXX_ID_LED_0,
+		.default_trigger	= "battery-full",
+	},
+	{
+		.name		= "led:blue",
+		.flags		= PM8XXX_ID_LED_2,
+		.default_trigger	= "notification",
+	},
+};
+
+static struct pm8xxx_led_config pm8921_led_configs_liquid[] = {
+	[0] = {
+		.id = PM8XXX_ID_LED_0,
+		.mode = PM8XXX_LED_MODE_MANUAL,
+		.max_current = PM8921_LC_LED_MAX_CURRENT,
+	},
+	[1] = {
+		.id = PM8XXX_ID_LED_1,
+		.mode = PM8XXX_LED_MODE_MANUAL,
+		.max_current = PM8921_LC_LED_LOW_CURRENT,
+	},
+	[2] = {
+		.id = PM8XXX_ID_LED_2,
+		.mode = PM8XXX_LED_MODE_MANUAL,
+		.max_current = PM8921_LC_LED_MAX_CURRENT,
+	},
+};
+
+static struct led_platform_data pm8xxx_leds_core_liquid = {
+	.num_leds = ARRAY_SIZE(pm8921_led_info_liquid),
+	.leds = pm8921_led_info_liquid,
+};
+
+static struct pm8xxx_led_platform_data pm8xxx_leds_pdata_liquid = {
+	.led_core = &pm8xxx_leds_core_liquid,
+	.configs = pm8921_led_configs_liquid,
+	.num_configs = ARRAY_SIZE(pm8921_led_configs_liquid),
+};
+
+static struct led_info pm8921_led_info[] = {
+	[0] = {
+		.name			= "led:battery_charging",
+		.default_trigger	= "battery-charging",
+	},
+	[1] = {
+		.name			= "led:battery_full",
+		.default_trigger	= "battery-full",
+	},
+};
+
+static struct led_platform_data pm8921_led_core_pdata = {
+	.num_leds = ARRAY_SIZE(pm8921_led_info),
+	.leds = pm8921_led_info,
+};
+
+static int pm8921_led0_pwm_duty_pcts[56] = {
+		1, 4, 8, 12, 16, 20, 24, 28, 32, 36,
+		40, 44, 46, 52, 56, 60, 64, 68, 72, 76,
+		80, 84, 88, 92, 96, 100, 100, 100, 98, 95,
+		92, 88, 84, 82, 78, 74, 70, 66, 62, 58,
+		58, 54, 50, 48, 42, 38, 34, 30, 26, 22,
+		14, 10, 6, 4, 1
+};
+
+static struct pm8xxx_pwm_duty_cycles pm8921_led0_pwm_duty_cycles = {
+	.duty_pcts = (int *)&pm8921_led0_pwm_duty_pcts,
+	.num_duty_pcts = ARRAY_SIZE(pm8921_led0_pwm_duty_pcts),
+	.duty_ms = PM8XXX_LED_PWM_DUTY_MS,
+	.start_idx = 0,
+};
+
+static struct pm8xxx_led_config pm8921_led_configs[] = {
+	[0] = {
+		.id = PM8XXX_ID_LED_0,
+		.mode = PM8XXX_LED_MODE_PWM2,
+		.max_current = PM8921_LC_LED_MAX_CURRENT,
+		.pwm_channel = 5,
+		.pwm_period_us = PM8XXX_LED_PWM_PERIOD,
+		.pwm_duty_cycles = &pm8921_led0_pwm_duty_cycles,
+	},
+	[1] = {
+		.id = PM8XXX_ID_LED_1,
+		.mode = PM8XXX_LED_MODE_PWM1,
+		.max_current = PM8921_LC_LED_MAX_CURRENT,
+		.pwm_channel = 4,
+		.pwm_period_us = PM8XXX_LED_PWM_PERIOD,
+	},
+};
+
+static struct pm8xxx_led_platform_data pm8xxx_leds_pdata = {
+		.led_core = &pm8921_led_core_pdata,
+		.configs = pm8921_led_configs,
+		.num_configs = ARRAY_SIZE(pm8921_led_configs),
+};
+
+static struct pm8xxx_ccadc_platform_data pm8xxx_ccadc_pdata = {
+	.r_sense		= 10,
+};
+
+/**
+ * PM8XXX_PWM_DTEST_CHANNEL_NONE shall be used when no LPG
+ * channel should be in DTEST mode.
+ */
+
+#define PM8XXX_PWM_DTEST_CHANNEL_NONE   (-1)
+
+static struct pm8xxx_pwm_platform_data pm8xxx_pwm_pdata = {
+	.dtest_channel	= PM8XXX_PWM_DTEST_CHANNEL_NONE,
+};
+
+static struct pm8921_platform_data pm8921_platform_data __devinitdata = {
+	.irq_pdata		= &pm8xxx_irq_pdata,
+	.gpio_pdata		= &pm8xxx_gpio_pdata,
+	.mpp_pdata		= &pm8xxx_mpp_pdata,
+	.rtc_pdata              = &pm8xxx_rtc_pdata,
+	.pwrkey_pdata		= &pm8xxx_pwrkey_pdata,
+	.keypad_pdata		= &keypad_data,
+	.misc_pdata		= &pm8xxx_misc_pdata,
+	.regulator_pdatas	= msm_pm8921_regulator_pdata,
+	.charger_pdata		= &pm8921_chg_pdata,
+	.bms_pdata		= &pm8921_bms_pdata,
+	.adc_pdata		= &pm8xxx_adc_pdata,
+	.leds_pdata		= &pm8xxx_leds_pdata,
+	.ccadc_pdata		= &pm8xxx_ccadc_pdata,
+	.pwm_pdata		= &pm8xxx_pwm_pdata,
+};
+
+static struct msm_ssbi_platform_data msm8960_ssbi_pm8921_pdata __devinitdata = {
+	.controller_type = MSM_SBI_CTRL_PMIC_ARBITER,
+	.slave	= {
+		.name			= "pm8921-core",
+		.platform_data		= &pm8921_platform_data,
+	},
+};
+
+void __init msm8960_init_pmic(void)
+{
+	pmic_reset_irq = PM8921_IRQ_BASE + PM8921_RESOUT_IRQ;
+	msm8960_device_ssbi_pmic.dev.platform_data =
+				&msm8960_ssbi_pm8921_pdata;
+	pm8921_platform_data.num_regulators = msm_pm8921_regulator_pdata_len;
+
+	/* Simulator supports a QWERTY keypad */
+	if (machine_is_msm8960_sim())
+		pm8921_platform_data.keypad_pdata = &keypad_data_sim;
+
+	if (machine_is_msm8960_liquid()) {
+		pm8921_platform_data.keypad_pdata = &keypad_data_liquid;
+		pm8921_platform_data.leds_pdata = &pm8xxx_leds_pdata_liquid;
+		pm8921_platform_data.bms_pdata->battery_type = BATT_DESAY;
+	} else if (machine_is_msm8960_mtp()) {
+		pm8921_platform_data.bms_pdata->battery_type = BATT_PALLADIUM;
+	}
+
+	if (machine_is_msm8960_fluid())
+		pm8921_bms_pdata.rconn_mohm = 20;
+}
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
new file mode 100644
index 0000000..93c72ea
--- /dev/null
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -0,0 +1,570 @@
+/*
+ * 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
+ * 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/regulator/pm8xxx-regulator.h>
+#include <linux/regulator/msm-gpio-regulator.h>
+#include <mach/rpm-regulator.h>
+
+#include "board-8960.h"
+
+#define VREG_CONSUMERS(_id) \
+	static struct regulator_consumer_supply vreg_consumers_##_id[]
+
+/*
+ * Consumer specific regulator names:
+ *			 regulator name		consumer dev_name
+ */
+VREG_CONSUMERS(L1) = {
+	REGULATOR_SUPPLY("8921_l1",		NULL),
+};
+VREG_CONSUMERS(L2) = {
+	REGULATOR_SUPPLY("8921_l2",		NULL),
+	REGULATOR_SUPPLY("dsi_vdda",		"mipi_dsi.1"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.0"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.1"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_csid.2"),
+};
+VREG_CONSUMERS(L3) = {
+	REGULATOR_SUPPLY("8921_l3",		NULL),
+	REGULATOR_SUPPLY("HSUSB_3p3",		"msm_otg"),
+};
+VREG_CONSUMERS(L4) = {
+	REGULATOR_SUPPLY("8921_l4",		NULL),
+	REGULATOR_SUPPLY("HSUSB_1p8",		"msm_otg"),
+	REGULATOR_SUPPLY("iris_vddxo",		"wcnss_wlan.0"),
+};
+VREG_CONSUMERS(L5) = {
+	REGULATOR_SUPPLY("8921_l5",		NULL),
+	REGULATOR_SUPPLY("sdc_vdd",		"msm_sdcc.1"),
+};
+VREG_CONSUMERS(L6) = {
+	REGULATOR_SUPPLY("8921_l6",		NULL),
+	REGULATOR_SUPPLY("sdc_vdd",		"msm_sdcc.3"),
+};
+VREG_CONSUMERS(L7) = {
+	REGULATOR_SUPPLY("8921_l7",		NULL),
+	REGULATOR_SUPPLY("sdc_vddp",		"msm_sdcc.3"),
+};
+VREG_CONSUMERS(L8) = {
+	REGULATOR_SUPPLY("8921_l8",		NULL),
+	REGULATOR_SUPPLY("dsi_vdc",		"mipi_dsi.1"),
+};
+VREG_CONSUMERS(L9) = {
+	REGULATOR_SUPPLY("8921_l9",		NULL),
+	REGULATOR_SUPPLY("vdd",			"3-0024"),
+	REGULATOR_SUPPLY("vdd_ana",		"3-004a"),
+};
+VREG_CONSUMERS(L10) = {
+	REGULATOR_SUPPLY("8921_l10",		NULL),
+	REGULATOR_SUPPLY("iris_vddpa",		"wcnss_wlan.0"),
+
+};
+VREG_CONSUMERS(L11) = {
+	REGULATOR_SUPPLY("8921_l11",		NULL),
+	REGULATOR_SUPPLY("cam_vana",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vana",		"4-006c"),
+	REGULATOR_SUPPLY("cam_vana",		"4-0048"),
+	REGULATOR_SUPPLY("cam_vana",		"4-0020"),
+	REGULATOR_SUPPLY("cam_vana",		"4-0034"),
+};
+VREG_CONSUMERS(L12) = {
+	REGULATOR_SUPPLY("8921_l12",		NULL),
+	REGULATOR_SUPPLY("cam_vdig",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vdig",		"4-006c"),
+	REGULATOR_SUPPLY("cam_vdig",		"4-0048"),
+	REGULATOR_SUPPLY("cam_vdig",		"4-0020"),
+	REGULATOR_SUPPLY("cam_vdig",		"4-0034"),
+};
+VREG_CONSUMERS(L14) = {
+	REGULATOR_SUPPLY("8921_l14",		NULL),
+	REGULATOR_SUPPLY("pa_therm",		"pm8xxx-adc"),
+};
+VREG_CONSUMERS(L15) = {
+	REGULATOR_SUPPLY("8921_l15",		NULL),
+};
+VREG_CONSUMERS(L16) = {
+	REGULATOR_SUPPLY("8921_l16",		NULL),
+	REGULATOR_SUPPLY("cam_vaf",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vaf",		"4-006c"),
+	REGULATOR_SUPPLY("cam_vaf",		"4-0048"),
+	REGULATOR_SUPPLY("cam_vaf",		"4-0020"),
+	REGULATOR_SUPPLY("cam_vaf",		"4-0034"),
+};
+VREG_CONSUMERS(L17) = {
+	REGULATOR_SUPPLY("8921_l17",		NULL),
+};
+VREG_CONSUMERS(L18) = {
+	REGULATOR_SUPPLY("8921_l18",		NULL),
+};
+VREG_CONSUMERS(L21) = {
+	REGULATOR_SUPPLY("8921_l21",		NULL),
+};
+VREG_CONSUMERS(L22) = {
+	REGULATOR_SUPPLY("8921_l22",		NULL),
+};
+VREG_CONSUMERS(L23) = {
+	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),
+	REGULATOR_SUPPLY("riva_vddmx",		"wcnss_wlan.0"),
+};
+VREG_CONSUMERS(L25) = {
+	REGULATOR_SUPPLY("8921_l25",		NULL),
+	REGULATOR_SUPPLY("VDDD_CDC_D",		"tabla-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",	"tabla-slim"),
+	REGULATOR_SUPPLY("VDDD_CDC_D",		"tabla2x-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",	"tabla2x-slim"),
+};
+VREG_CONSUMERS(L26) = {
+	REGULATOR_SUPPLY("8921_l26",		NULL),
+	REGULATOR_SUPPLY("core_vdd",		"pil_qdsp6v4.0"),
+};
+VREG_CONSUMERS(L27) = {
+	REGULATOR_SUPPLY("8921_l27",		NULL),
+	REGULATOR_SUPPLY("core_vdd",		"pil_qdsp6v4.2"),
+};
+VREG_CONSUMERS(L28) = {
+	REGULATOR_SUPPLY("8921_l28",		NULL),
+	REGULATOR_SUPPLY("core_vdd",		"pil_qdsp6v4.1"),
+};
+VREG_CONSUMERS(L29) = {
+	REGULATOR_SUPPLY("8921_l29",		NULL),
+};
+VREG_CONSUMERS(S1) = {
+	REGULATOR_SUPPLY("8921_s1",		NULL),
+};
+VREG_CONSUMERS(S2) = {
+	REGULATOR_SUPPLY("8921_s2",		NULL),
+	REGULATOR_SUPPLY("iris_vddrfa",		"wcnss_wlan.0"),
+
+};
+VREG_CONSUMERS(S3) = {
+	REGULATOR_SUPPLY("8921_s3",		NULL),
+	REGULATOR_SUPPLY("HSUSB_VDDCX",		"msm_otg"),
+	REGULATOR_SUPPLY("riva_vddcx",		"wcnss_wlan.0"),
+	REGULATOR_SUPPLY("HSIC_VDDCX",		"msm_hsic_host"),
+};
+VREG_CONSUMERS(S4) = {
+	REGULATOR_SUPPLY("8921_s4",		NULL),
+	REGULATOR_SUPPLY("sdc_vccq",		"msm_sdcc.1"),
+	REGULATOR_SUPPLY("sdc_vdd",		"msm_sdcc.2"),
+	REGULATOR_SUPPLY("sdc_vddp",            "msm_sdcc.4"),
+	REGULATOR_SUPPLY("riva_vddpx",		"wcnss_wlan.0"),
+	REGULATOR_SUPPLY("hdmi_vcc",		"hdmi_msm.0"),
+	REGULATOR_SUPPLY("VDDIO_CDC",		"tabla-slim"),
+	REGULATOR_SUPPLY("CDC_VDD_CP",		"tabla-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_TX",		"tabla-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_RX",		"tabla-slim"),
+	REGULATOR_SUPPLY("VDDIO_CDC",		"tabla2x-slim"),
+	REGULATOR_SUPPLY("CDC_VDD_CP",		"tabla2x-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_TX",		"tabla2x-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_RX",		"tabla2x-slim"),
+	REGULATOR_SUPPLY("vcc_i2c",		"3-005b"),
+	REGULATOR_SUPPLY("EXT_HUB_VDDIO",	"msm_smsc_hub"),
+	REGULATOR_SUPPLY("vcc_i2c",		"10-0048"),
+};
+VREG_CONSUMERS(S5) = {
+	REGULATOR_SUPPLY("8921_s5",		NULL),
+	REGULATOR_SUPPLY("krait0",		NULL),
+};
+VREG_CONSUMERS(S6) = {
+	REGULATOR_SUPPLY("8921_s6",		NULL),
+	REGULATOR_SUPPLY("krait1",		NULL),
+};
+VREG_CONSUMERS(S7) = {
+	REGULATOR_SUPPLY("8921_s7",		NULL),
+};
+VREG_CONSUMERS(S8) = {
+	REGULATOR_SUPPLY("8921_s8",		NULL),
+};
+VREG_CONSUMERS(LVS1) = {
+	REGULATOR_SUPPLY("8921_lvs1",		NULL),
+	REGULATOR_SUPPLY("iris_vddio",		"wcnss_wlan.0"),
+};
+VREG_CONSUMERS(LVS2) = {
+	REGULATOR_SUPPLY("8921_lvs2",		NULL),
+	REGULATOR_SUPPLY("iris_vdddig",		"wcnss_wlan.0"),
+};
+VREG_CONSUMERS(LVS3) = {
+	REGULATOR_SUPPLY("8921_lvs3",		NULL),
+};
+VREG_CONSUMERS(LVS4) = {
+	REGULATOR_SUPPLY("8921_lvs4",		NULL),
+	REGULATOR_SUPPLY("vcc_i2c",		"3-0024"),
+	REGULATOR_SUPPLY("vcc_i2c",		"3-004a"),
+};
+VREG_CONSUMERS(LVS5) = {
+	REGULATOR_SUPPLY("8921_lvs5",		NULL),
+	REGULATOR_SUPPLY("cam_vio",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vio",		"4-006c"),
+	REGULATOR_SUPPLY("cam_vio",		"4-0048"),
+	REGULATOR_SUPPLY("cam_vio",		"4-0020"),
+	REGULATOR_SUPPLY("cam_vio",		"4-0034"),
+};
+VREG_CONSUMERS(LVS6) = {
+	REGULATOR_SUPPLY("8921_lvs6",		NULL),
+	REGULATOR_SUPPLY("vdd_io",		"spi0.0"),
+};
+VREG_CONSUMERS(LVS7) = {
+	REGULATOR_SUPPLY("8921_lvs7",		NULL),
+};
+VREG_CONSUMERS(USB_OTG) = {
+	REGULATOR_SUPPLY("8921_usb_otg",	NULL),
+};
+VREG_CONSUMERS(HDMI_MVS) = {
+	REGULATOR_SUPPLY("8921_hdmi_mvs",	NULL),
+	REGULATOR_SUPPLY("hdmi_mvs",		"hdmi_msm.0"),
+};
+VREG_CONSUMERS(NCP) = {
+	REGULATOR_SUPPLY("8921_ncp",		NULL),
+};
+VREG_CONSUMERS(EXT_5V) = {
+	REGULATOR_SUPPLY("ext_5v",		NULL),
+};
+VREG_CONSUMERS(EXT_L2) = {
+	REGULATOR_SUPPLY("ext_l2",		NULL),
+	REGULATOR_SUPPLY("vdd_phy",		"spi0.0"),
+};
+VREG_CONSUMERS(EXT_3P3V) = {
+	REGULATOR_SUPPLY("ext_3p3v",		NULL),
+	REGULATOR_SUPPLY("vdd_ana",		"3-005b"),
+	REGULATOR_SUPPLY("vdd_lvds_3p3v",	"mipi_dsi.1"),
+	REGULATOR_SUPPLY("mhl_ext_3p3v",	"msm_otg"),
+};
+VREG_CONSUMERS(EXT_OTG_SW) = {
+	REGULATOR_SUPPLY("ext_otg_sw",		NULL),
+	REGULATOR_SUPPLY("vbus_otg",		"msm_otg"),
+};
+
+#define PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
+			 _apply_uV, _pull_down, _always_on, _supply_regulator, \
+			 _system_uA, _enable_time, _reg_id) \
+	{ \
+		.init_data = { \
+			.constraints = { \
+				.valid_modes_mask	= _modes, \
+				.valid_ops_mask		= _ops, \
+				.min_uV			= _min_uV, \
+				.max_uV			= _max_uV, \
+				.input_uV		= _max_uV, \
+				.apply_uV		= _apply_uV, \
+				.always_on		= _always_on, \
+				.name			= _name, \
+			}, \
+			.num_consumer_supplies	= \
+					ARRAY_SIZE(vreg_consumers_##_id), \
+			.consumer_supplies	= vreg_consumers_##_id, \
+			.supply_regulator	= _supply_regulator, \
+		}, \
+		.id			= _reg_id, \
+		.pull_down_enable	= _pull_down, \
+		.system_uA		= _system_uA, \
+		.enable_time		= _enable_time, \
+	}
+
+#define PM8XXX_LDO(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+		_enable_time, _supply_regulator, _system_uA, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
+		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
+		REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
+
+#define PM8XXX_NLDO1200(_id, _name, _always_on, _pull_down, _min_uV, \
+		_max_uV, _enable_time, _supply_regulator, _system_uA, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
+		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
+		REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
+
+#define PM8XXX_SMPS(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+		_enable_time, _supply_regulator, _system_uA, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
+		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
+		REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
+
+#define PM8XXX_FTSMPS(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+		_enable_time, _supply_regulator, _system_uA, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL, \
+		REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS \
+		| REGULATOR_CHANGE_MODE, 0, _pull_down, _always_on, \
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
+
+#define PM8XXX_VS(_id, _name, _always_on, _pull_down, _enable_time, \
+		_supply_regulator, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, \
+		_pull_down, _always_on, _supply_regulator, 0, _enable_time, \
+		_reg_id)
+
+#define PM8XXX_VS300(_id, _name, _always_on, _pull_down, _enable_time, \
+		_supply_regulator, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, \
+		_pull_down, _always_on, _supply_regulator, 0, _enable_time, \
+		_reg_id)
+
+#define PM8XXX_NCP(_id, _name, _always_on, _min_uV, _max_uV, _enable_time, \
+		_supply_regulator, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, 0, \
+		REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, 0, 0, \
+		_always_on, _supply_regulator, 0, _enable_time, _reg_id)
+
+/* Pin control initialization */
+#define PM8XXX_PC(_id, _name, _always_on, _pin_fn, _pin_ctrl, \
+		  _supply_regulator, _reg_id) \
+	{ \
+		.init_data = { \
+			.constraints = { \
+				.valid_ops_mask	= REGULATOR_CHANGE_STATUS, \
+				.always_on	= _always_on, \
+				.name		= _name, \
+			}, \
+			.num_consumer_supplies	= \
+					ARRAY_SIZE(vreg_consumers_##_id##_PC), \
+			.consumer_supplies	= vreg_consumers_##_id##_PC, \
+			.supply_regulator  = _supply_regulator, \
+		}, \
+		.id		= _reg_id, \
+		.pin_fn		= PM8XXX_VREG_PIN_FN_##_pin_fn, \
+		.pin_ctrl	= _pin_ctrl, \
+	}
+
+#define GPIO_VREG(_id, _reg_name, _gpio_label, _gpio, _supply_regulator) \
+	[GPIO_VREG_ID_##_id] = { \
+		.init_data = { \
+			.constraints = { \
+				.valid_ops_mask	= REGULATOR_CHANGE_STATUS, \
+			}, \
+			.num_consumer_supplies	= \
+					ARRAY_SIZE(vreg_consumers_##_id), \
+			.consumer_supplies	= vreg_consumers_##_id, \
+			.supply_regulator	= _supply_regulator, \
+		}, \
+		.regulator_name = _reg_name, \
+		.gpio_label	= _gpio_label, \
+		.gpio		= _gpio, \
+	}
+
+#define SAW_VREG_INIT(_id, _name, _min_uV, _max_uV) \
+	{ \
+		.constraints = { \
+			.name		= _name, \
+			.valid_ops_mask	= REGULATOR_CHANGE_VOLTAGE, \
+			.min_uV		= _min_uV, \
+			.max_uV		= _max_uV, \
+		}, \
+		.num_consumer_supplies	= ARRAY_SIZE(vreg_consumers_##_id), \
+		.consumer_supplies	= vreg_consumers_##_id, \
+	}
+
+#define RPM_INIT(_id, _min_uV, _max_uV, _modes, _ops, _apply_uV, _default_uV, \
+		 _peak_uA, _avg_uA, _pull_down, _pin_ctrl, _freq, _pin_fn, \
+		 _force_mode, _sleep_set_force_mode, _power_mode, _state, \
+		 _sleep_selectable, _always_on, _supply_regulator, _system_uA) \
+	{ \
+		.init_data = { \
+			.constraints = { \
+				.valid_modes_mask	= _modes, \
+				.valid_ops_mask		= _ops, \
+				.min_uV			= _min_uV, \
+				.max_uV			= _max_uV, \
+				.input_uV		= _min_uV, \
+				.apply_uV		= _apply_uV, \
+				.always_on		= _always_on, \
+			}, \
+			.num_consumer_supplies	= \
+					ARRAY_SIZE(vreg_consumers_##_id), \
+			.consumer_supplies	= vreg_consumers_##_id, \
+			.supply_regulator	= _supply_regulator, \
+		}, \
+		.id			= RPM_VREG_ID_PM8921_##_id, \
+		.default_uV		= _default_uV, \
+		.peak_uA		= _peak_uA, \
+		.avg_uA			= _avg_uA, \
+		.pull_down_enable	= _pull_down, \
+		.pin_ctrl		= _pin_ctrl, \
+		.freq			= RPM_VREG_FREQ_##_freq, \
+		.pin_fn			= _pin_fn, \
+		.force_mode		= _force_mode, \
+		.sleep_set_force_mode	= _sleep_set_force_mode, \
+		.power_mode		= _power_mode, \
+		.state			= _state, \
+		.sleep_selectable	= _sleep_selectable, \
+		.system_uA		= _system_uA, \
+	}
+
+#define RPM_LDO(_id, _always_on, _pd, _sleep_selectable, _min_uV, _max_uV, \
+		_supply_regulator, _system_uA, _init_peak_uA) \
+	RPM_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+		 | REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE \
+		 | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE \
+		 | REGULATOR_CHANGE_DRMS, 0, _max_uV, _init_peak_uA, 0, _pd, \
+		 RPM_VREG_PIN_CTRL_NONE, NONE, RPM_VREG_PIN_FN_8960_NONE, \
+		 RPM_VREG_FORCE_MODE_8960_NONE, \
+		 RPM_VREG_FORCE_MODE_8960_NONE, RPM_VREG_POWER_MODE_8960_PWM, \
+		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
+		 _supply_regulator, _system_uA)
+
+#define RPM_SMPS(_id, _always_on, _pd, _sleep_selectable, _min_uV, _max_uV, \
+		 _supply_regulator, _system_uA, _freq, _force_mode, \
+		 _sleep_set_force_mode) \
+	RPM_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+		 | REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE \
+		 | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE \
+		 | REGULATOR_CHANGE_DRMS, 0, _max_uV, _system_uA, 0, _pd, \
+		 RPM_VREG_PIN_CTRL_NONE, _freq, RPM_VREG_PIN_FN_8960_NONE, \
+		 RPM_VREG_FORCE_MODE_8960_##_force_mode, \
+		 RPM_VREG_FORCE_MODE_8960_##_sleep_set_force_mode, \
+		 RPM_VREG_POWER_MODE_8960_PWM, RPM_VREG_STATE_OFF, \
+		 _sleep_selectable, _always_on, _supply_regulator, _system_uA)
+
+#define RPM_VS(_id, _always_on, _pd, _sleep_selectable, _supply_regulator) \
+	RPM_INIT(_id, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, 0, 1000, 1000, _pd, \
+		 RPM_VREG_PIN_CTRL_NONE, NONE, RPM_VREG_PIN_FN_8960_NONE, \
+		 RPM_VREG_FORCE_MODE_8960_NONE, \
+		 RPM_VREG_FORCE_MODE_8960_NONE, RPM_VREG_POWER_MODE_8960_PWM, \
+		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
+		 _supply_regulator, 0)
+
+#define RPM_NCP(_id, _always_on, _sleep_selectable, _min_uV, _max_uV, \
+		_supply_regulator, _freq) \
+	RPM_INIT(_id, _min_uV, _max_uV, 0, REGULATOR_CHANGE_VOLTAGE \
+		 | REGULATOR_CHANGE_STATUS, 0, _max_uV, 1000, 1000, 0, \
+		 RPM_VREG_PIN_CTRL_NONE, _freq, RPM_VREG_PIN_FN_8960_NONE, \
+		 RPM_VREG_FORCE_MODE_8960_NONE, \
+		 RPM_VREG_FORCE_MODE_8960_NONE, RPM_VREG_POWER_MODE_8960_PWM, \
+		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
+		 _supply_regulator, 0)
+
+/* Pin control initialization */
+#define RPM_PC_INIT(_id, _always_on, _pin_fn, _pin_ctrl, _supply_regulator) \
+	{ \
+		.init_data = { \
+			.constraints = { \
+				.valid_ops_mask	= REGULATOR_CHANGE_STATUS, \
+				.always_on	= _always_on, \
+			}, \
+			.num_consumer_supplies	= \
+					ARRAY_SIZE(vreg_consumers_##_id##_PC), \
+			.consumer_supplies	= vreg_consumers_##_id##_PC, \
+			.supply_regulator	= _supply_regulator, \
+		}, \
+		.id	  = RPM_VREG_ID_PM8921_##_id##_PC, \
+		.pin_fn	  = RPM_VREG_PIN_FN_8960_##_pin_fn, \
+		.pin_ctrl = _pin_ctrl, \
+	}
+
+/* GPIO regulator constraints */
+struct gpio_regulator_platform_data msm_gpio_regulator_pdata[] __devinitdata = {
+	/*        ID      vreg_name gpio_label   gpio                  supply */
+	GPIO_VREG(EXT_5V, "ext_5v", "ext_5v_en", PM8921_MPP_PM_TO_SYS(7), NULL),
+	GPIO_VREG(EXT_L2, "ext_l2", "ext_l2_en", 91, NULL),
+	GPIO_VREG(EXT_3P3V, "ext_3p3v", "ext_3p3v_en",
+		PM8921_GPIO_PM_TO_SYS(17), NULL),
+	GPIO_VREG(EXT_OTG_SW, "ext_otg_sw", "ext_otg_sw_en",
+		PM8921_GPIO_PM_TO_SYS(42), "8921_usb_otg"),
+};
+
+/* SAW regulator constraints */
+struct regulator_init_data msm_saw_regulator_pdata_s5 =
+	/*	      ID  vreg_name	       min_uV   max_uV */
+	SAW_VREG_INIT(S5, "8921_s5",	       850000, 1300000);
+struct regulator_init_data msm_saw_regulator_pdata_s6 =
+	SAW_VREG_INIT(S6, "8921_s6",	       850000, 1300000);
+
+/* PM8921 regulator constraints */
+struct pm8xxx_regulator_platform_data
+msm_pm8921_regulator_pdata[] __devinitdata = {
+	/*
+	 *		ID   name always_on pd min_uV   max_uV   en_t supply
+	 *	system_uA reg_ID
+	 */
+	PM8XXX_NLDO1200(L26, "8921_l26", 0, 1, 375000, 1050000, 200, "8921_s7",
+		0, 1),
+	PM8XXX_NLDO1200(L27, "8921_l27", 0, 1, 375000, 1050000, 200, "8921_s7",
+		0, 2),
+	PM8XXX_NLDO1200(L28, "8921_l28", 0, 1, 375000, 1050000, 200, "8921_s7",
+		0, 3),
+	PM8XXX_LDO(L29,      "8921_l29", 0, 1, 2050000, 2100000, 200, "8921_s8",
+		0, 4),
+
+	/*	     ID        name      always_on pd en_t supply    reg_ID */
+	PM8XXX_VS300(USB_OTG,  "8921_usb_otg",  0, 1, 0,   "ext_5v", 5),
+	PM8XXX_VS300(HDMI_MVS, "8921_hdmi_mvs", 0, 1, 0,   "ext_5v", 6),
+};
+
+static struct rpm_regulator_init_data
+msm_rpm_regulator_init_data[] __devinitdata = {
+	/*	ID a_on pd ss min_uV   max_uV  supply sys_uA  freq  fm  ss_fm */
+	RPM_SMPS(S1, 1, 1, 0, 1225000, 1225000, NULL, 100000, 3p20, NONE, NONE),
+	RPM_SMPS(S2, 0, 1, 0, 1300000, 1300000, NULL,      0, 1p60, NONE, NONE),
+	RPM_SMPS(S3, 0, 1, 1,  500000, 1150000, NULL, 100000, 4p80, NONE, NONE),
+	RPM_SMPS(S4, 1, 1, 0, 1800000, 1800000, NULL, 100000, 1p60, AUTO, AUTO),
+	RPM_SMPS(S7, 0, 1, 0, 1150000, 1150000, NULL, 100000, 3p20, NONE, NONE),
+	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 */
+	RPM_LDO(L1,	 1, 1, 0, 1050000, 1050000, "8921_s4", 0, 10000),
+	RPM_LDO(L2,	 0, 1, 0, 1200000, 1200000, "8921_s4", 0, 0),
+	RPM_LDO(L3,	 0, 1, 0, 3075000, 3075000, NULL,      0, 0),
+	RPM_LDO(L4,	 1, 1, 0, 1800000, 1800000, NULL,      10000, 10000),
+	RPM_LDO(L5,	 0, 1, 0, 2950000, 2950000, NULL,      0, 0),
+	RPM_LDO(L6,	 0, 1, 0, 2950000, 2950000, NULL,      0, 0),
+	RPM_LDO(L7,	 1, 1, 0, 1850000, 2950000, NULL,      10000, 10000),
+	RPM_LDO(L8,	 0, 1, 0, 2800000, 3000000, NULL,      0, 0),
+	RPM_LDO(L9,	 0, 1, 0, 3000000, 3000000, NULL,      0, 0),
+	RPM_LDO(L10,	 0, 1, 0, 3000000, 3000000, NULL,      0, 0),
+	RPM_LDO(L11,	 0, 1, 0, 2850000, 2850000, NULL,      0, 0),
+	RPM_LDO(L12,	 0, 1, 0, 1200000, 1200000, "8921_s4", 0, 0),
+	RPM_LDO(L14,	 0, 1, 0, 1800000, 1800000, NULL,      0, 0),
+	RPM_LDO(L15,	 0, 1, 0, 1800000, 2950000, NULL,      0, 0),
+	RPM_LDO(L16,	 0, 1, 0, 2800000, 2800000, NULL,      0, 0),
+	RPM_LDO(L17,	 0, 1, 0, 1800000, 2950000, NULL,      0, 0),
+	RPM_LDO(L18,	 0, 1, 0, 1300000, 1300000, "8921_s4", 0, 0),
+	RPM_LDO(L21,	 0, 1, 0, 1900000, 1900000, "8921_s8", 0, 0),
+	RPM_LDO(L22,	 0, 1, 0, 2750000, 2750000, NULL,      0, 0),
+	RPM_LDO(L23,	 1, 1, 1, 1800000, 1800000, "8921_s8", 10000, 10000),
+	RPM_LDO(L24,	 0, 1, 1,  750000, 1150000, "8921_s1", 10000, 10000),
+	RPM_LDO(L25,	 1, 1, 0, 1250000, 1250000, "8921_s1", 10000, 10000),
+
+	/*	ID     a_on pd ss		    supply */
+	RPM_VS(LVS1,	 0, 1, 0,		    "8921_s4"),
+	RPM_VS(LVS2,	 0, 1, 0,		    "8921_s1"),
+	RPM_VS(LVS3,	 0, 1, 0,		    "8921_s4"),
+	RPM_VS(LVS4,	 0, 1, 0,		    "8921_s4"),
+	RPM_VS(LVS5,	 0, 1, 0,		    "8921_s4"),
+	RPM_VS(LVS6,	 0, 1, 0,		    "8921_s4"),
+	RPM_VS(LVS7,	 0, 1, 0,		    "8921_s4"),
+
+	/*	 ID      a_on  ss min_uV   max_uV   supply        freq */
+	RPM_NCP(NCP,	 0,    0, 1800000, 1800000, "8921_l6",    1p60),
+};
+
+int msm_pm8921_regulator_pdata_len __devinitdata =
+	ARRAY_SIZE(msm_pm8921_regulator_pdata);
+
+struct rpm_regulator_platform_data msm_rpm_regulator_pdata __devinitdata = {
+	.init_data		= msm_rpm_regulator_init_data,
+	.num_regulators		= ARRAY_SIZE(msm_rpm_regulator_init_data),
+	.version		= RPM_VREG_VERSION_8960,
+	.vreg_id_vdd_mem	= RPM_VREG_ID_PM8921_L24,
+	.vreg_id_vdd_dig	= RPM_VREG_ID_PM8921_S3,
+};
diff --git a/arch/arm/mach-msm/board-8960-storage.c b/arch/arm/mach-msm/board-8960-storage.c
new file mode 100644
index 0000000..1279b75
--- /dev/null
+++ b/arch/arm/mach-msm/board-8960-storage.c
@@ -0,0 +1,387 @@
+/* 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
+ * 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 <linux/gpio.h>
+#include <asm/mach-types.h>
+#include <asm/mach/mmc.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
+#include "devices.h"
+#include "board-8960.h"
+#include "board-storage-common-a.h"
+
+/* MSM8960 has 5 SDCC controllers */
+enum sdcc_controllers {
+	SDCC1,
+	SDCC2,
+	SDCC3,
+	SDCC4,
+	SDCC5,
+	MAX_SDCC_CONTROLLER
+};
+
+/* All SDCC controllers require VDD/VCC voltage */
+static struct msm_mmc_reg_data mmc_vdd_reg_data[MAX_SDCC_CONTROLLER] = {
+	/* SDCC1 : eMMC card connected */
+	[SDCC1] = {
+		.name = "sdc_vdd",
+		.high_vol_level = 2950000,
+		.low_vol_level = 2950000,
+		.always_on = 1,
+		.lpm_sup = 1,
+		.lpm_uA = 9000,
+		.hpm_uA = 200000, /* 200mA */
+	},
+	/* SDCC2 : SDIO slot connected */
+	[SDCC2] = {
+		.name = "sdc_vdd",
+		.high_vol_level = 1800000,
+		.low_vol_level = 1800000,
+		.always_on = 1,
+		.lpm_sup = 1,
+		.lpm_uA = 9000,
+		.hpm_uA = 200000, /* 200mA */
+	},
+	/* SDCC3 : External card slot connected */
+	[SDCC3] = {
+		.name = "sdc_vdd",
+		.high_vol_level = 2950000,
+		.low_vol_level = 2950000,
+		.hpm_uA = 600000, /* 600mA */
+	}
+};
+
+/* Only slots having eMMC card will require VCCQ voltage */
+static struct msm_mmc_reg_data mmc_vccq_reg_data[1] = {
+	/* SDCC1 : eMMC card connected */
+	[SDCC1] = {
+		.name = "sdc_vccq",
+		.always_on = 1,
+		.high_vol_level = 1800000,
+		.low_vol_level = 1800000,
+		.hpm_uA = 200000, /* 200mA */
+	}
+};
+
+/* All SDCC controllers may require voting for VDD PAD voltage */
+static struct msm_mmc_reg_data mmc_vddp_reg_data[MAX_SDCC_CONTROLLER] = {
+	/* SDCC3 : External card slot connected */
+	[SDCC3] = {
+		.name = "sdc_vddp",
+		.high_vol_level = 2950000,
+		.low_vol_level = 1850000,
+		.always_on = 1,
+		.lpm_sup = 1,
+		/* Max. Active current required is 16 mA */
+		.hpm_uA = 16000,
+		/*
+		 * Sleep current required is ~300 uA. But min. vote can be
+		 * in terms of mA (min. 1 mA). So let's vote for 2 mA
+		 * during sleep.
+		 */
+		.lpm_uA = 2000,
+	},
+	/* SDCC4 : SDIO slot connected */
+	[SDCC4] = {
+		.name = "sdc_vddp",
+		.high_vol_level = 1800000,
+		.low_vol_level = 1800000,
+		.always_on = 1,
+		.lpm_sup = 1,
+		.hpm_uA = 200000, /* 200mA */
+		.lpm_uA = 2000,
+	},
+};
+
+static struct msm_mmc_slot_reg_data mmc_slot_vreg_data[MAX_SDCC_CONTROLLER] = {
+	/* SDCC1 : eMMC card connected */
+	[SDCC1] = {
+		.vdd_data = &mmc_vdd_reg_data[SDCC1],
+		.vccq_data = &mmc_vccq_reg_data[SDCC1],
+	},
+	/* SDCC2 : SDIO card slot connected */
+	[SDCC2] = {
+		.vdd_data = &mmc_vdd_reg_data[SDCC2],
+	},
+	/* SDCC3 : External card slot connected */
+	[SDCC3] = {
+		.vdd_data = &mmc_vdd_reg_data[SDCC3],
+		.vddp_data = &mmc_vddp_reg_data[SDCC3],
+	},
+	/* SDCC4 : SDIO card slot connected */
+	[SDCC4] = {
+		.vddp_data = &mmc_vddp_reg_data[SDCC4],
+	},
+};
+
+/* SDC1 pad data */
+static struct msm_mmc_pad_drv sdc1_pad_drv_on_cfg[] = {
+	{TLMM_HDRV_SDC1_CLK, GPIO_CFG_16MA},
+	{TLMM_HDRV_SDC1_CMD, GPIO_CFG_10MA},
+	{TLMM_HDRV_SDC1_DATA, GPIO_CFG_10MA}
+};
+
+static struct msm_mmc_pad_drv sdc1_pad_drv_off_cfg[] = {
+	{TLMM_HDRV_SDC1_CLK, GPIO_CFG_2MA},
+	{TLMM_HDRV_SDC1_CMD, GPIO_CFG_2MA},
+	{TLMM_HDRV_SDC1_DATA, GPIO_CFG_2MA}
+};
+
+static struct msm_mmc_pad_pull sdc1_pad_pull_on_cfg[] = {
+	{TLMM_PULL_SDC1_CLK, GPIO_CFG_NO_PULL},
+	{TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_UP},
+	{TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_UP}
+};
+
+static struct msm_mmc_pad_pull sdc1_pad_pull_off_cfg[] = {
+	{TLMM_PULL_SDC1_CLK, GPIO_CFG_NO_PULL},
+	{TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_UP},
+	{TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_UP}
+};
+
+/* SDC3 pad data */
+static struct msm_mmc_pad_drv sdc3_pad_drv_on_cfg[] = {
+	{TLMM_HDRV_SDC3_CLK, GPIO_CFG_8MA},
+	{TLMM_HDRV_SDC3_CMD, GPIO_CFG_8MA},
+	{TLMM_HDRV_SDC3_DATA, GPIO_CFG_8MA}
+};
+
+static struct msm_mmc_pad_drv sdc3_pad_drv_off_cfg[] = {
+	{TLMM_HDRV_SDC3_CLK, GPIO_CFG_2MA},
+	{TLMM_HDRV_SDC3_CMD, GPIO_CFG_2MA},
+	{TLMM_HDRV_SDC3_DATA, GPIO_CFG_2MA}
+};
+
+static struct msm_mmc_pad_pull sdc3_pad_pull_on_cfg[] = {
+	{TLMM_PULL_SDC3_CLK, GPIO_CFG_NO_PULL},
+	{TLMM_PULL_SDC3_CMD, GPIO_CFG_PULL_UP},
+	{TLMM_PULL_SDC3_DATA, GPIO_CFG_PULL_UP}
+};
+
+static struct msm_mmc_pad_pull sdc3_pad_pull_off_cfg[] = {
+	{TLMM_PULL_SDC3_CLK, GPIO_CFG_NO_PULL},
+	/*
+	 * SDC3 CMD line should be PULLed UP otherwise fluid platform will
+	 * see transitions (1 -> 0 and 0 -> 1) on card detection line,
+	 * which would result in false card detection interrupts.
+	 */
+	{TLMM_PULL_SDC3_CMD, GPIO_CFG_PULL_UP},
+	/*
+	 * Keeping DATA lines status to PULL UP will make sure that
+	 * there is no current leak during sleep if external pull up
+	 * is connected to DATA lines.
+	 */
+	{TLMM_PULL_SDC3_DATA, GPIO_CFG_PULL_UP}
+};
+
+static struct msm_mmc_pad_pull_data mmc_pad_pull_data[MAX_SDCC_CONTROLLER] = {
+	[SDCC1] = {
+		.on = sdc1_pad_pull_on_cfg,
+		.off = sdc1_pad_pull_off_cfg,
+		.size = ARRAY_SIZE(sdc1_pad_pull_on_cfg)
+	},
+	[SDCC3] = {
+		.on = sdc3_pad_pull_on_cfg,
+		.off = sdc3_pad_pull_off_cfg,
+		.size = ARRAY_SIZE(sdc3_pad_pull_on_cfg)
+	},
+};
+
+static struct msm_mmc_pad_drv_data mmc_pad_drv_data[MAX_SDCC_CONTROLLER] = {
+	[SDCC1] = {
+		.on = sdc1_pad_drv_on_cfg,
+		.off = sdc1_pad_drv_off_cfg,
+		.size = ARRAY_SIZE(sdc1_pad_drv_on_cfg)
+	},
+	[SDCC3] = {
+		.on = sdc3_pad_drv_on_cfg,
+		.off = sdc3_pad_drv_off_cfg,
+		.size = ARRAY_SIZE(sdc3_pad_drv_on_cfg)
+	},
+};
+
+struct msm_mmc_gpio sdc2_gpio[] = {
+	{92, "sdc2_dat_3"},
+	{91, "sdc2_dat_2"},
+	{90, "sdc2_dat_1"},
+	{89, "sdc2_dat_0"},
+	{97, "sdc2_cmd"},
+	{98, "sdc2_clk"}
+};
+
+struct msm_mmc_gpio sdc4_gpio[] = {
+	{83, "sdc4_dat_3"},
+	{84, "sdc4_dat_2"},
+	{85, "sdc4_dat_1"},
+	{86, "sdc4_dat_0"},
+	{87, "sdc4_cmd"},
+	{88, "sdc4_clk"}
+};
+
+struct msm_mmc_gpio_data mmc_gpio_data[MAX_SDCC_CONTROLLER] = {
+	[SDCC2] = {
+		.gpio = sdc2_gpio,
+		.size = ARRAY_SIZE(sdc2_gpio),
+	},
+	[SDCC4] = {
+		.gpio = sdc4_gpio,
+		.size = ARRAY_SIZE(sdc4_gpio),
+	},
+};
+
+static struct msm_mmc_pad_data mmc_pad_data[MAX_SDCC_CONTROLLER] = {
+	[SDCC1] = {
+		.pull = &mmc_pad_pull_data[SDCC1],
+		.drv = &mmc_pad_drv_data[SDCC1]
+	},
+	[SDCC3] = {
+		.pull = &mmc_pad_pull_data[SDCC3],
+		.drv = &mmc_pad_drv_data[SDCC3]
+	},
+};
+
+static struct msm_mmc_pin_data mmc_slot_pin_data[MAX_SDCC_CONTROLLER] = {
+	[SDCC1] = {
+		.pad_data = &mmc_pad_data[SDCC1],
+	},
+	[SDCC2] = {
+		.is_gpio = 1,
+		.gpio_data = &mmc_gpio_data[SDCC2],
+	},
+	[SDCC3] = {
+		.pad_data = &mmc_pad_data[SDCC3],
+	},
+	[SDCC4] = {
+		.is_gpio = 1,
+		.gpio_data = &mmc_gpio_data[SDCC4],
+	},
+};
+
+#define MSM_MPM_PIN_SDC1_DAT1	17
+#define MSM_MPM_PIN_SDC3_DAT1	21
+
+static unsigned int sdc1_sup_clk_rates[] = {
+	400000, 24000000, 48000000
+};
+
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+static unsigned int sdc3_sup_clk_rates[] = {
+	400000, 24000000, 48000000, 96000000, 192000000
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+static struct mmc_platform_data msm8960_sdc1_data = {
+	.ocr_mask       = MMC_VDD_27_28 | MMC_VDD_28_29,
+#ifdef CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT
+	.mmc_bus_width  = MMC_CAP_8_BIT_DATA,
+#else
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+#endif
+	.sup_clk_table	= sdc1_sup_clk_rates,
+	.sup_clk_cnt	= ARRAY_SIZE(sdc1_sup_clk_rates),
+	.pclk_src_dfab	= 1,
+	.nonremovable	= 1,
+	.vreg_data	= &mmc_slot_vreg_data[SDCC1],
+	.pin_data	= &mmc_slot_pin_data[SDCC1],
+	.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC1_DAT1,
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+static unsigned int sdc2_sup_clk_rates[] = {
+	400000, 24000000, 48000000
+};
+
+static struct mmc_platform_data msm8960_sdc2_data = {
+	.ocr_mask       = MMC_VDD_165_195,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.sup_clk_table  = sdc2_sup_clk_rates,
+	.sup_clk_cnt    = ARRAY_SIZE(sdc2_sup_clk_rates),
+	.pclk_src_dfab  = 1,
+	.vreg_data      = &mmc_slot_vreg_data[SDCC2],
+	.pin_data       = &mmc_slot_pin_data[SDCC2],
+	.sdiowakeup_irq = MSM_GPIO_TO_INT(90),
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+static struct mmc_platform_data msm8960_sdc3_data = {
+	.ocr_mask       = MMC_VDD_27_28 | MMC_VDD_28_29,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.sup_clk_table	= sdc3_sup_clk_rates,
+	.sup_clk_cnt	= ARRAY_SIZE(sdc3_sup_clk_rates),
+	.pclk_src_dfab	= 1,
+#ifdef CONFIG_MMC_MSM_SDC3_WP_SUPPORT
+	.wpswitch_gpio	= PM8921_GPIO_PM_TO_SYS(16),
+#endif
+	.vreg_data	= &mmc_slot_vreg_data[SDCC3],
+	.pin_data	= &mmc_slot_pin_data[SDCC3],
+#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
+	.status_gpio	= PM8921_GPIO_PM_TO_SYS(26),
+	.status_irq	= PM8921_GPIO_IRQ(PM8921_IRQ_BASE, 26),
+	.irq_flags	= IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+	.is_status_gpio_active_low = true,
+#endif
+	.xpc_cap	= 1,
+	.uhs_caps	= (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+			MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_DDR50 |
+			MMC_CAP_UHS_SDR104 | MMC_CAP_MAX_CURRENT_600),
+	.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC3_DAT1,
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+static unsigned int sdc4_sup_clk_rates[] = {
+	400000, 24000000, 48000000
+};
+
+static struct mmc_platform_data msm8960_sdc4_data = {
+	.ocr_mask       = MMC_VDD_165_195,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.sup_clk_table  = sdc4_sup_clk_rates,
+	.sup_clk_cnt    = ARRAY_SIZE(sdc4_sup_clk_rates),
+	.pclk_src_dfab  = 1,
+	.vreg_data      = &mmc_slot_vreg_data[SDCC4],
+	.pin_data       = &mmc_slot_pin_data[SDCC4],
+	.sdiowakeup_irq = MSM_GPIO_TO_INT(85),
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
+};
+#endif
+
+void __init msm8960_init_mmc(void)
+{
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+	/* SDC1 : eMMC card connected */
+	msm_add_sdcc(1, &msm8960_sdc1_data);
+#endif
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+	/* SDC2: SDIO slot for WLAN*/
+	msm_add_sdcc(2, &msm8960_sdc2_data);
+#endif
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+	/* SDC3: External card slot */
+	msm_add_sdcc(3, &msm8960_sdc3_data);
+#endif
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+	/* SDC4: SDIO slot for WLAN */
+	msm_add_sdcc(4, &msm8960_sdc4_data);
+#endif
+}
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
new file mode 100644
index 0000000..898332f
--- /dev/null
+++ b/arch/arm/mach-msm/board-8960.c
@@ -0,0 +1,3158 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/i2c.h>
+#include <linux/i2c/sx150x.h>
+#include <linux/i2c/isl9519.h>
+#include <linux/gpio.h>
+#include <linux/msm_ssbi.h>
+#include <linux/regulator/msm-gpio-regulator.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/slimbus/slimbus.h>
+#include <linux/bootmem.h>
+#include <linux/msm_kgsl.h>
+#ifdef CONFIG_ANDROID_PMEM
+#include <linux/android_pmem.h>
+#endif
+#include <linux/cyttsp-qc.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_data/qcom_crypto_device.h>
+#include <linux/platform_data/qcom_wcnss_device.h>
+#include <linux/leds.h>
+#include <linux/leds-pm8xxx.h>
+#include <linux/i2c/atmel_mxt_ts.h>
+#include <linux/msm_tsens.h>
+#include <linux/ks8851.h>
+#include <linux/i2c/isa1200.h>
+#include <linux/memory.h>
+#include <linux/memblock.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/setup.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach/mmc.h>
+
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_spi.h>
+#include <mach/msm_serial_hs.h>
+#ifdef CONFIG_USB_MSM_OTG_72K
+#include <mach/msm_hsusb.h>
+#else
+#include <linux/usb/msm_hsusb.h>
+#endif
+#include <linux/usb/android.h>
+#include <mach/usbdiag.h>
+#include <mach/socinfo.h>
+#include <mach/rpm.h>
+#include <mach/gpiomux.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_memtypes.h>
+#include <mach/dma.h>
+#include <mach/msm_dsps.h>
+#include <mach/msm_xo.h>
+#include <mach/restart.h>
+
+#ifdef CONFIG_WCD9310_CODEC
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/pdata.h>
+#endif
+
+#include <linux/smsc3503.h>
+#include <linux/ion.h>
+#include <mach/ion.h>
+#include <mach/mdm2.h>
+#include <mach/mdm-peripheral.h>
+#include <mach/msm_rtb.h>
+#include <mach/msm_cache_dump.h>
+#include <mach/scm.h>
+#include <mach/iommu_domains.h>
+
+#include <linux/fmem.h>
+
+#include "timer.h"
+#include "devices.h"
+#include "devices-msm8x60.h"
+#include "spm.h"
+#include "board-8960.h"
+#include "pm.h"
+#include <mach/cpuidle.h>
+#include "rpm_resources.h"
+#include <mach/mpm.h>
+#include "acpuclock.h"
+#include "smd_private.h"
+#include "pm-boot.h"
+#include "msm_watchdog.h"
+
+static struct platform_device msm_fm_platform_init = {
+	.name = "iris_fm",
+	.id   = -1,
+};
+
+#define KS8851_RST_GPIO		89
+#define KS8851_IRQ_GPIO		90
+#define HAP_SHIFT_LVL_OE_GPIO	47
+
+#define MHL_GPIO_INT            4
+#define MHL_GPIO_RESET          15
+
+#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
+
+struct sx150x_platform_data msm8960_sx150x_data[] = {
+	[SX150X_CAM] = {
+		.gpio_base         = GPIO_CAM_EXPANDER_BASE,
+		.oscio_is_gpo      = false,
+		.io_pullup_ena     = 0x0,
+		.io_pulldn_ena     = 0xc0,
+		.io_open_drain_ena = 0x0,
+		.irq_summary       = -1,
+	},
+	[SX150X_LIQUID] = {
+		.gpio_base         = GPIO_LIQUID_EXPANDER_BASE,
+		.oscio_is_gpo      = false,
+		.io_pullup_ena     = 0x0c08,
+		.io_pulldn_ena     = 0x4060,
+		.io_open_drain_ena = 0x000c,
+		.io_polarity       = 0,
+		.irq_summary       = -1,
+	},
+};
+
+#endif
+
+#define MSM_PMEM_ADSP_SIZE         0x7800000
+#define MSM_PMEM_AUDIO_SIZE        0x4CF000
+#define MSM_PMEM_SIZE 0x2800000 /* 40 Mbytes */
+#define MSM_LIQUID_PMEM_SIZE 0x4000000 /* 64 Mbytes */
+#define MSM_HDMI_PRIM_PMEM_SIZE 0x4000000 /* 64 Mbytes */
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+#define MSM_PMEM_KERNEL_EBI1_SIZE  0x65000
+#ifdef CONFIG_MSM_IOMMU
+#define MSM_ION_MM_SIZE            0x3800000 /* Need to be multiple of 64K */
+#define MSM_ION_SF_SIZE            0x0
+#define MSM_ION_QSECOM_SIZE        0x780000 /* (7.5MB) */
+#define MSM_ION_HEAP_NUM	7
+#else
+#define MSM_ION_MM_SIZE            MSM_PMEM_ADSP_SIZE
+#define MSM_ION_SF_SIZE            MSM_PMEM_SIZE
+#define MSM_ION_QSECOM_SIZE        0x600000 /* (6MB) */
+#define MSM_ION_HEAP_NUM	8
+#endif
+#define MSM_ION_MM_FW_SIZE	0x200000 /* (2MB) */
+#define MSM_ION_MFC_SIZE	SZ_8K
+#define MSM_ION_AUDIO_SIZE	MSM_PMEM_AUDIO_SIZE
+
+#define MSM_LIQUID_ION_MM_SIZE (MSM_ION_MM_SIZE + 0x600000)
+#define MSM_LIQUID_ION_SF_SIZE MSM_LIQUID_PMEM_SIZE
+#define MSM_HDMI_PRIM_ION_SF_SIZE MSM_HDMI_PRIM_PMEM_SIZE
+
+#define MSM8960_FIXED_AREA_START 0xa0000000
+#define MAX_FIXED_AREA_SIZE	0x10000000
+#define MSM_MM_FW_SIZE		0x200000
+#define MSM8960_FW_START	(MSM8960_FIXED_AREA_START - MSM_MM_FW_SIZE)
+
+static unsigned msm_ion_sf_size = MSM_ION_SF_SIZE;
+#else
+#define MSM_PMEM_KERNEL_EBI1_SIZE  0x110C000
+#define MSM_ION_HEAP_NUM	1
+#endif
+
+#ifdef CONFIG_KERNEL_PMEM_EBI_REGION
+static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE;
+static int __init pmem_kernel_ebi1_size_setup(char *p)
+{
+	pmem_kernel_ebi1_size = memparse(p, NULL);
+	return 0;
+}
+early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
+#endif
+
+#ifdef CONFIG_ANDROID_PMEM
+static unsigned pmem_size = MSM_PMEM_SIZE;
+static unsigned pmem_param_set;
+static int __init pmem_size_setup(char *p)
+{
+	pmem_size = memparse(p, NULL);
+	pmem_param_set = 1;
+	return 0;
+}
+early_param("pmem_size", pmem_size_setup);
+
+static unsigned pmem_adsp_size = MSM_PMEM_ADSP_SIZE;
+
+static int __init pmem_adsp_size_setup(char *p)
+{
+	pmem_adsp_size = memparse(p, NULL);
+	return 0;
+}
+early_param("pmem_adsp_size", pmem_adsp_size_setup);
+
+static unsigned pmem_audio_size = MSM_PMEM_AUDIO_SIZE;
+
+static int __init pmem_audio_size_setup(char *p)
+{
+	pmem_audio_size = memparse(p, NULL);
+	return 0;
+}
+early_param("pmem_audio_size", pmem_audio_size_setup);
+#endif
+
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+static struct android_pmem_platform_data android_pmem_pdata = {
+	.name = "pmem",
+	.allocator_type = PMEM_ALLOCATORTYPE_ALLORNOTHING,
+	.cached = 1,
+	.memory_type = MEMTYPE_EBI1,
+};
+
+static struct platform_device msm8960_android_pmem_device = {
+	.name = "android_pmem",
+	.id = 0,
+	.dev = {.platform_data = &android_pmem_pdata},
+};
+
+static struct android_pmem_platform_data android_pmem_adsp_pdata = {
+	.name = "pmem_adsp",
+	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
+	.cached = 0,
+	.memory_type = MEMTYPE_EBI1,
+};
+static struct platform_device msm8960_android_pmem_adsp_device = {
+	.name = "android_pmem",
+	.id = 2,
+	.dev = { .platform_data = &android_pmem_adsp_pdata },
+};
+
+static struct android_pmem_platform_data android_pmem_audio_pdata = {
+	.name = "pmem_audio",
+	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
+	.cached = 0,
+	.memory_type = MEMTYPE_EBI1,
+};
+
+static struct platform_device msm8960_android_pmem_audio_device = {
+	.name = "android_pmem",
+	.id = 4,
+	.dev = { .platform_data = &android_pmem_audio_pdata },
+};
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
+
+struct fmem_platform_data msm8960_fmem_pdata = {
+};
+
+#define DSP_RAM_BASE_8960 0x8da00000
+#define DSP_RAM_SIZE_8960 0x1800000
+static int dspcrashd_pdata_8960 = 0xDEADDEAD;
+
+static struct resource resources_dspcrashd_8960[] = {
+	{
+		.name   = "msm_dspcrashd",
+		.start  = DSP_RAM_BASE_8960,
+		.end    = DSP_RAM_BASE_8960 + DSP_RAM_SIZE_8960,
+		.flags  = IORESOURCE_DMA,
+	},
+};
+
+static struct platform_device msm_device_dspcrashd_8960 = {
+	.name           = "msm_dspcrashd",
+	.num_resources  = ARRAY_SIZE(resources_dspcrashd_8960),
+	.resource       = resources_dspcrashd_8960,
+	.dev = { .platform_data = &dspcrashd_pdata_8960 },
+};
+
+static struct memtype_reserve msm8960_reserve_table[] __initdata = {
+	[MEMTYPE_SMI] = {
+	},
+	[MEMTYPE_EBI0] = {
+		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
+	},
+	[MEMTYPE_EBI1] = {
+		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
+	},
+};
+
+static void __init reserve_rtb_memory(void)
+{
+#if defined(CONFIG_MSM_RTB)
+	msm8960_reserve_table[MEMTYPE_EBI1].size += msm8960_rtb_pdata.size;
+#endif
+}
+
+static void __init size_pmem_devices(void)
+{
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+	android_pmem_adsp_pdata.size = pmem_adsp_size;
+
+	if (!pmem_param_set) {
+		if (machine_is_msm8960_liquid())
+			pmem_size = MSM_LIQUID_PMEM_SIZE;
+		if (msm8960_hdmi_as_primary_selected())
+			pmem_size = MSM_HDMI_PRIM_PMEM_SIZE;
+	}
+
+	android_pmem_pdata.size = pmem_size;
+	android_pmem_audio_pdata.size = MSM_PMEM_AUDIO_SIZE;
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
+}
+
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+static void __init reserve_memory_for(struct android_pmem_platform_data *p)
+{
+	msm8960_reserve_table[p->memory_type].size += p->size;
+}
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
+
+static void __init reserve_pmem_memory(void)
+{
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+	reserve_memory_for(&android_pmem_adsp_pdata);
+	reserve_memory_for(&android_pmem_pdata);
+	reserve_memory_for(&android_pmem_audio_pdata);
+#endif
+	msm8960_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
+#endif
+}
+
+static int msm8960_paddr_to_memtype(unsigned int paddr)
+{
+	return MEMTYPE_EBI1;
+}
+
+#define FMEM_ENABLED 0
+
+#ifdef CONFIG_ION_MSM
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+static struct ion_cp_heap_pdata cp_mm_msm8960_ion_pdata = {
+	.permission_type = IPT_TYPE_MM_CARVEOUT,
+	.align = SZ_64K,
+	.reusable = FMEM_ENABLED,
+	.mem_is_fmem = FMEM_ENABLED,
+	.fixed_position = FIXED_MIDDLE,
+	.iommu_map_all = 1,
+	.iommu_2x_map_domain = VIDEO_DOMAIN,
+};
+
+static struct ion_cp_heap_pdata cp_mfc_msm8960_ion_pdata = {
+	.permission_type = IPT_TYPE_MFC_SHAREDMEM,
+	.align = PAGE_SIZE,
+	.reusable = 0,
+	.mem_is_fmem = FMEM_ENABLED,
+	.fixed_position = FIXED_HIGH,
+};
+
+static struct ion_co_heap_pdata co_msm8960_ion_pdata = {
+	.adjacent_mem_id = INVALID_HEAP_ID,
+	.align = PAGE_SIZE,
+	.mem_is_fmem = 0,
+};
+
+static struct ion_co_heap_pdata fw_co_msm8960_ion_pdata = {
+	.adjacent_mem_id = ION_CP_MM_HEAP_ID,
+	.align = SZ_128K,
+	.mem_is_fmem = FMEM_ENABLED,
+	.fixed_position = FIXED_LOW,
+};
+#endif
+
+/**
+ * These heaps are listed in the order they will be allocated. Due to
+ * video hardware restrictions and content protection the FW heap has to
+ * be allocated adjacent (below) the MM heap and the MFC heap has to be
+ * allocated after the MM heap to ensure MFC heap is not more than 256MB
+ * away from the base address of the FW heap.
+ * However, the order of FW heap and MM heap doesn't matter since these
+ * two heaps are taken care of by separate code to ensure they are adjacent
+ * to each other.
+ * Don't swap the order unless you know what you are doing!
+ */
+static struct ion_platform_data msm8960_ion_pdata = {
+	.nr = MSM_ION_HEAP_NUM,
+	.heaps = {
+		{
+			.id	= ION_SYSTEM_HEAP_ID,
+			.type	= ION_HEAP_TYPE_SYSTEM,
+			.name	= ION_VMALLOC_HEAP_NAME,
+		},
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+		{
+			.id	= ION_CP_MM_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CP,
+			.name	= ION_MM_HEAP_NAME,
+			.size	= MSM_ION_MM_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &cp_mm_msm8960_ion_pdata,
+		},
+		{
+			.id	= ION_MM_FIRMWARE_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.name	= ION_MM_FIRMWARE_HEAP_NAME,
+			.size	= MSM_ION_MM_FW_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &fw_co_msm8960_ion_pdata,
+		},
+		{
+			.id	= ION_CP_MFC_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CP,
+			.name	= ION_MFC_HEAP_NAME,
+			.size	= MSM_ION_MFC_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &cp_mfc_msm8960_ion_pdata,
+		},
+#ifndef CONFIG_MSM_IOMMU
+		{
+			.id	= ION_SF_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.name	= ION_SF_HEAP_NAME,
+			.size	= MSM_ION_SF_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &co_msm8960_ion_pdata,
+		},
+#endif
+		{
+			.id	= ION_IOMMU_HEAP_ID,
+			.type	= ION_HEAP_TYPE_IOMMU,
+			.name	= ION_IOMMU_HEAP_NAME,
+		},
+		{
+			.id	= ION_QSECOM_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.name	= ION_QSECOM_HEAP_NAME,
+			.size	= MSM_ION_QSECOM_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &co_msm8960_ion_pdata,
+		},
+		{
+			.id	= ION_AUDIO_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.name	= ION_AUDIO_HEAP_NAME,
+			.size	= MSM_ION_AUDIO_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &co_msm8960_ion_pdata,
+		},
+#endif
+	}
+};
+
+static struct platform_device msm8960_ion_dev = {
+	.name = "ion-msm",
+	.id = 1,
+	.dev = { .platform_data = &msm8960_ion_pdata },
+};
+#endif
+
+struct platform_device msm8960_fmem_device = {
+	.name = "fmem",
+	.id = 1,
+	.dev = { .platform_data = &msm8960_fmem_pdata },
+};
+
+static void __init adjust_mem_for_liquid(void)
+{
+	unsigned int i;
+
+	if (!pmem_param_set) {
+		if (machine_is_msm8960_liquid())
+			msm_ion_sf_size = MSM_LIQUID_ION_SF_SIZE;
+
+		if (msm8960_hdmi_as_primary_selected())
+			msm_ion_sf_size = MSM_HDMI_PRIM_ION_SF_SIZE;
+
+		if (machine_is_msm8960_liquid() ||
+			msm8960_hdmi_as_primary_selected()) {
+			for (i = 0; i < msm8960_ion_pdata.nr; i++) {
+				if (msm8960_ion_pdata.heaps[i].id ==
+							ION_SF_HEAP_ID) {
+					msm8960_ion_pdata.heaps[i].size =
+						msm_ion_sf_size;
+					pr_debug("msm_ion_sf_size 0x%x\n",
+						msm_ion_sf_size);
+					break;
+				}
+			}
+		}
+	}
+}
+
+static void __init reserve_mem_for_ion(enum ion_memory_types mem_type,
+				      unsigned long size)
+{
+	msm8960_reserve_table[mem_type].size += size;
+}
+
+static void __init msm8960_reserve_fixed_area(unsigned long fixed_area_size)
+{
+#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
+	int ret;
+
+	if (fixed_area_size > MAX_FIXED_AREA_SIZE)
+		panic("fixed area size is larger than %dM\n",
+			MAX_FIXED_AREA_SIZE >> 20);
+
+	reserve_info->fixed_area_size = fixed_area_size;
+	reserve_info->fixed_area_start = MSM8960_FW_START;
+
+	ret = memblock_remove(reserve_info->fixed_area_start,
+		reserve_info->fixed_area_size);
+	BUG_ON(ret);
+#endif
+}
+
+/**
+ * Reserve memory for ION and calculate amount of reusable memory for fmem.
+ * We only reserve memory for heaps that are not reusable. However, we only
+ * support one reusable heap at the moment so we ignore the reusable flag for
+ * other than the first heap with reusable flag set. Also handle special case
+ * for video heaps (MM,FW, and MFC). Video requires heaps MM and MFC to be
+ * at a higher address than FW in addition to not more than 256MB away from the
+ * base address of the firmware. This means that if MM is reusable the other
+ * two heaps must be allocated in the same region as FW. This is handled by the
+ * mem_is_fmem flag in the platform data. In addition the MM heap must be
+ * adjacent to the FW heap for content protection purposes.
+ */
+static void __init reserve_ion_memory(void)
+{
+#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
+	unsigned int i;
+	unsigned int reusable_count = 0;
+	unsigned int fixed_size = 0;
+	unsigned int fixed_low_size, fixed_middle_size, fixed_high_size;
+	unsigned long fixed_low_start, fixed_middle_start, fixed_high_start;
+
+	adjust_mem_for_liquid();
+	msm8960_fmem_pdata.size = 0;
+	msm8960_fmem_pdata.reserved_size_low = 0;
+	msm8960_fmem_pdata.reserved_size_high = 0;
+	msm8960_fmem_pdata.align = PAGE_SIZE;
+	fixed_low_size = 0;
+	fixed_middle_size = 0;
+	fixed_high_size = 0;
+
+	/* We only support 1 reusable heap. Check if more than one heap
+	 * is specified as reusable and set as non-reusable if found.
+	 */
+	for (i = 0; i < msm8960_ion_pdata.nr; ++i) {
+		const struct ion_platform_heap *heap =
+						&(msm8960_ion_pdata.heaps[i]);
+
+		if (heap->type == ION_HEAP_TYPE_CP && heap->extra_data) {
+			struct ion_cp_heap_pdata *data = heap->extra_data;
+
+			reusable_count += (data->reusable) ? 1 : 0;
+
+			if (data->reusable && reusable_count > 1) {
+				pr_err("%s: Too many heaps specified as "
+					"reusable. Heap %s was not configured "
+					"as reusable.\n", __func__, heap->name);
+				data->reusable = 0;
+			}
+		}
+	}
+
+	for (i = 0; i < msm8960_ion_pdata.nr; ++i) {
+		struct ion_platform_heap *heap =
+						&(msm8960_ion_pdata.heaps[i]);
+		int align = SZ_4K;
+		int iommu_map_all = 0;
+		int adjacent_mem_id = INVALID_HEAP_ID;
+
+		if (heap->extra_data) {
+			int fixed_position = NOT_FIXED;
+			int mem_is_fmem = 0;
+
+			switch (heap->type) {
+			case ION_HEAP_TYPE_CP:
+				mem_is_fmem = ((struct ion_cp_heap_pdata *)
+					heap->extra_data)->mem_is_fmem;
+				fixed_position = ((struct ion_cp_heap_pdata *)
+					heap->extra_data)->fixed_position;
+				align = ((struct ion_cp_heap_pdata *)
+						heap->extra_data)->align;
+				iommu_map_all =
+					((struct ion_cp_heap_pdata *)
+					heap->extra_data)->iommu_map_all;
+				break;
+			case ION_HEAP_TYPE_CARVEOUT:
+				mem_is_fmem = ((struct ion_co_heap_pdata *)
+					heap->extra_data)->mem_is_fmem;
+				fixed_position = ((struct ion_co_heap_pdata *)
+					heap->extra_data)->fixed_position;
+				adjacent_mem_id = ((struct ion_co_heap_pdata *)
+					heap->extra_data)->adjacent_mem_id;
+				break;
+			default:
+				break;
+			}
+
+			if (iommu_map_all) {
+				if (heap->size & (SZ_64K-1)) {
+					heap->size = ALIGN(heap->size, SZ_64K);
+					pr_info("Heap %s not aligned to 64K. Adjusting size to %x\n",
+						heap->name, heap->size);
+				}
+			}
+
+			if (mem_is_fmem && adjacent_mem_id != INVALID_HEAP_ID)
+				msm8960_fmem_pdata.align = align;
+
+			if (fixed_position != NOT_FIXED)
+				fixed_size += heap->size;
+			else
+				reserve_mem_for_ion(MEMTYPE_EBI1, heap->size);
+
+			if (fixed_position == FIXED_LOW)
+				fixed_low_size += heap->size;
+			else if (fixed_position == FIXED_MIDDLE)
+				fixed_middle_size += heap->size;
+			else if (fixed_position == FIXED_HIGH)
+				fixed_high_size += heap->size;
+
+			if (mem_is_fmem)
+				msm8960_fmem_pdata.size += heap->size;
+		}
+	}
+
+	if (!fixed_size)
+		return;
+
+	if (msm8960_fmem_pdata.size) {
+		msm8960_fmem_pdata.reserved_size_low = fixed_low_size;
+		msm8960_fmem_pdata.reserved_size_high = fixed_high_size;
+	}
+
+	/* Since the fixed area may be carved out of lowmem,
+	 * make sure the length is a multiple of 1M.
+	 */
+	fixed_size = (fixed_size + MSM_MM_FW_SIZE + SECTION_SIZE - 1)
+		& SECTION_MASK;
+	msm8960_reserve_fixed_area(fixed_size);
+
+	fixed_low_start = MSM8960_FIXED_AREA_START;
+	fixed_middle_start = fixed_low_start + fixed_low_size;
+	fixed_high_start = fixed_middle_start + fixed_middle_size;
+
+	for (i = 0; i < msm8960_ion_pdata.nr; ++i) {
+		struct ion_platform_heap *heap = &(msm8960_ion_pdata.heaps[i]);
+
+		if (heap->extra_data) {
+			int fixed_position = NOT_FIXED;
+
+			switch (heap->type) {
+			case ION_HEAP_TYPE_CP:
+				fixed_position = ((struct ion_cp_heap_pdata *)
+					heap->extra_data)->fixed_position;
+				break;
+			case ION_HEAP_TYPE_CARVEOUT:
+				fixed_position = ((struct ion_co_heap_pdata *)
+					heap->extra_data)->fixed_position;
+				break;
+			default:
+				break;
+			}
+
+			switch (fixed_position) {
+			case FIXED_LOW:
+				heap->base = fixed_low_start;
+				break;
+			case FIXED_MIDDLE:
+				heap->base = fixed_middle_start;
+				break;
+			case FIXED_HIGH:
+				heap->base = fixed_high_start;
+				break;
+			default:
+				break;
+			}
+		}
+	}
+#endif
+}
+
+static void __init reserve_mdp_memory(void)
+{
+	msm8960_mdp_writeback(msm8960_reserve_table);
+}
+
+static void __init reserve_cache_dump_memory(void)
+{
+#ifdef CONFIG_MSM_CACHE_DUMP
+	unsigned int total;
+
+	total = msm8960_cache_dump_pdata.l1_size +
+		msm8960_cache_dump_pdata.l2_size;
+	msm8960_reserve_table[MEMTYPE_EBI1].size += total;
+#endif
+}
+
+static void __init msm8960_calculate_reserve_sizes(void)
+{
+	size_pmem_devices();
+	reserve_pmem_memory();
+	reserve_ion_memory();
+	reserve_mdp_memory();
+	reserve_rtb_memory();
+	reserve_cache_dump_memory();
+}
+
+static struct reserve_info msm8960_reserve_info __initdata = {
+	.memtype_reserve_table = msm8960_reserve_table,
+	.calculate_reserve_sizes = msm8960_calculate_reserve_sizes,
+	.reserve_fixed_area = msm8960_reserve_fixed_area,
+	.paddr_to_memtype = msm8960_paddr_to_memtype,
+};
+
+static int msm8960_memory_bank_size(void)
+{
+	return 1<<29;
+}
+
+static void __init locate_unstable_memory(void)
+{
+	struct membank *mb = &meminfo.bank[meminfo.nr_banks - 1];
+	unsigned long bank_size;
+	unsigned long low, high;
+
+	bank_size = msm8960_memory_bank_size();
+	msm8960_reserve_info.bank_size = bank_size;
+
+	low = meminfo.bank[0].start;
+	high = mb->start + mb->size;
+
+	/* Check if 32 bit overflow occured */
+	if (high < mb->start)
+		high = ~0UL;
+
+	if (high < MAX_FIXED_AREA_SIZE + MSM8960_FIXED_AREA_START)
+		panic("fixed area extends beyond end of memory\n");
+
+	low &= ~(bank_size - 1);
+
+	if (high - low <= bank_size)
+		goto no_dmm;
+
+#ifdef CONFIG_ENABLE_DMM
+	msm8960_reserve_info.low_unstable_address = mb->start -
+					MIN_MEMORY_BLOCK_SIZE + mb->size;
+	msm8960_reserve_info.max_unstable_size = MIN_MEMORY_BLOCK_SIZE;
+	pr_info("low unstable address %lx max size %lx bank size %lx\n",
+		msm8960_reserve_info.low_unstable_address,
+		msm8960_reserve_info.max_unstable_size,
+		msm8960_reserve_info.bank_size);
+	return;
+#endif
+no_dmm:
+	msm8960_reserve_info.low_unstable_address = high;
+	msm8960_reserve_info.max_unstable_size = 0;
+}
+
+static void __init place_movable_zone(void)
+{
+#ifdef CONFIG_ENABLE_DMM
+	movable_reserved_start = msm8960_reserve_info.low_unstable_address;
+	movable_reserved_size = msm8960_reserve_info.max_unstable_size;
+	pr_info("movable zone start %lx size %lx\n",
+		movable_reserved_start, movable_reserved_size);
+#endif
+}
+
+static void __init msm8960_early_memory(void)
+{
+	reserve_info = &msm8960_reserve_info;
+	locate_unstable_memory();
+	place_movable_zone();
+}
+
+static char prim_panel_name[PANEL_NAME_MAX_LEN];
+static char ext_panel_name[PANEL_NAME_MAX_LEN];
+static int __init prim_display_setup(char *param)
+{
+	if (strnlen(param, PANEL_NAME_MAX_LEN))
+		strlcpy(prim_panel_name, param, PANEL_NAME_MAX_LEN);
+	return 0;
+}
+early_param("prim_display", prim_display_setup);
+
+static int __init ext_display_setup(char *param)
+{
+	if (strnlen(param, PANEL_NAME_MAX_LEN))
+		strlcpy(ext_panel_name, param, PANEL_NAME_MAX_LEN);
+	return 0;
+}
+early_param("ext_display", ext_display_setup);
+
+static void __init msm8960_reserve(void)
+{
+	msm8960_set_display_params(prim_panel_name, ext_panel_name);
+	msm_reserve();
+	if (msm8960_fmem_pdata.size) {
+#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
+		if (reserve_info->fixed_area_size) {
+			msm8960_fmem_pdata.phys =
+				reserve_info->fixed_area_start + MSM_MM_FW_SIZE;
+			pr_info("mm fw at %lx (fixed) size %x\n",
+				reserve_info->fixed_area_start, MSM_MM_FW_SIZE);
+			pr_info("fmem start %lx (fixed) size %lx\n",
+				msm8960_fmem_pdata.phys,
+				msm8960_fmem_pdata.size);
+		}
+#endif
+	}
+}
+
+static int msm8960_change_memory_power(u64 start, u64 size,
+	int change_type)
+{
+	return soc_change_memory_power(start, size, change_type);
+}
+
+static void __init msm8960_allocate_memory_regions(void)
+{
+	msm8960_allocate_fb_region();
+}
+
+#ifdef CONFIG_WCD9310_CODEC
+
+#define TABLA_INTERRUPT_BASE (NR_MSM_IRQS + NR_GPIO_IRQS + NR_PM8921_IRQS)
+
+/* Micbias setting is based on 8660 CDP/MTP/FLUID requirement
+ * 4 micbiases are used to power various analog and digital
+ * microphones operating at 1800 mV. Technically, all micbiases
+ * can source from single cfilter since all microphones operate
+ * at the same voltage level. The arrangement below is to make
+ * sure all cfilters are exercised. LDO_H regulator ouput level
+ * does not need to be as high as 2.85V. It is choosen for
+ * microphone sensitivity purpose.
+ */
+static struct wcd9xxx_pdata tabla_platform_data = {
+	.slimbus_slave_device = {
+		.name = "tabla-slave",
+		.e_addr = {0, 0, 0x10, 0, 0x17, 2},
+	},
+	.irq = MSM_GPIO_TO_INT(62),
+	.irq_base = TABLA_INTERRUPT_BASE,
+	.num_irqs = NR_WCD9XXX_IRQS,
+	.reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
+	.micbias = {
+		.ldoh_v = TABLA_LDOH_2P85_V,
+		.cfilt1_mv = 1800,
+		.cfilt2_mv = 2700,
+		.cfilt3_mv = 1800,
+		.bias1_cfilt_sel = TABLA_CFILT1_SEL,
+		.bias2_cfilt_sel = TABLA_CFILT2_SEL,
+		.bias3_cfilt_sel = TABLA_CFILT3_SEL,
+		.bias4_cfilt_sel = TABLA_CFILT3_SEL,
+	},
+	.regulator = {
+	{
+		.name = "CDC_VDD_CP",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_RX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_RX_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_TX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_TX_CUR_MAX,
+	},
+	{
+		.name = "VDDIO_CDC",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_VDDIO_CDC_CUR_MAX,
+	},
+	{
+		.name = "VDDD_CDC_D",
+		.min_uV = 1225000,
+		.max_uV = 1250000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_A_1P2V",
+		.min_uV = 1225000,
+		.max_uV = 1250000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
+	},
+	},
+};
+
+static struct slim_device msm_slim_tabla = {
+	.name = "tabla-slim",
+	.e_addr = {0, 1, 0x10, 0, 0x17, 2},
+	.dev = {
+		.platform_data = &tabla_platform_data,
+	},
+};
+
+static struct wcd9xxx_pdata tabla20_platform_data = {
+	.slimbus_slave_device = {
+		.name = "tabla-slave",
+		.e_addr = {0, 0, 0x60, 0, 0x17, 2},
+	},
+	.irq = MSM_GPIO_TO_INT(62),
+	.irq_base = TABLA_INTERRUPT_BASE,
+	.num_irqs = NR_WCD9XXX_IRQS,
+	.reset_gpio = PM8921_GPIO_PM_TO_SYS(34),
+	.micbias = {
+		.ldoh_v = TABLA_LDOH_2P85_V,
+		.cfilt1_mv = 1800,
+		.cfilt2_mv = 2700,
+		.cfilt3_mv = 1800,
+		.bias1_cfilt_sel = TABLA_CFILT1_SEL,
+		.bias2_cfilt_sel = TABLA_CFILT2_SEL,
+		.bias3_cfilt_sel = TABLA_CFILT3_SEL,
+		.bias4_cfilt_sel = TABLA_CFILT3_SEL,
+	},
+	.regulator = {
+	{
+		.name = "CDC_VDD_CP",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_RX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_RX_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_TX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_TX_CUR_MAX,
+	},
+	{
+		.name = "VDDIO_CDC",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_VDDIO_CDC_CUR_MAX,
+	},
+	{
+		.name = "VDDD_CDC_D",
+		.min_uV = 1225000,
+		.max_uV = 1250000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_A_1P2V",
+		.min_uV = 1225000,
+		.max_uV = 1250000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
+	},
+	},
+};
+
+static struct slim_device msm_slim_tabla20 = {
+	.name = "tabla2x-slim",
+	.e_addr = {0, 1, 0x60, 0, 0x17, 2},
+	.dev = {
+		.platform_data = &tabla20_platform_data,
+	},
+};
+#endif
+
+static struct slim_boardinfo msm_slim_devices[] = {
+#ifdef CONFIG_WCD9310_CODEC
+	{
+		.bus_num = 1,
+		.slim_slave = &msm_slim_tabla,
+	},
+	{
+		.bus_num = 1,
+		.slim_slave = &msm_slim_tabla20,
+	},
+#endif
+	/* add more slimbus slaves as needed */
+};
+
+#define MSM_WCNSS_PHYS	0x03000000
+#define MSM_WCNSS_SIZE	0x280000
+
+static struct resource resources_wcnss_wlan[] = {
+	{
+		.start	= RIVA_APPS_WLAN_RX_DATA_AVAIL_IRQ,
+		.end	= RIVA_APPS_WLAN_RX_DATA_AVAIL_IRQ,
+		.name	= "wcnss_wlanrx_irq",
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= RIVA_APPS_WLAN_DATA_XFER_DONE_IRQ,
+		.end	= RIVA_APPS_WLAN_DATA_XFER_DONE_IRQ,
+		.name	= "wcnss_wlantx_irq",
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM_WCNSS_PHYS,
+		.end	= MSM_WCNSS_PHYS + MSM_WCNSS_SIZE - 1,
+		.name	= "wcnss_mmio",
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= 84,
+		.end	= 88,
+		.name	= "wcnss_gpios_5wire",
+		.flags	= IORESOURCE_IO,
+	},
+};
+
+static struct qcom_wcnss_opts qcom_wcnss_pdata = {
+	.has_48mhz_xo	= 1,
+};
+
+static struct platform_device msm_device_wcnss_wlan = {
+	.name		= "wcnss_wlan",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(resources_wcnss_wlan),
+	.resource	= resources_wcnss_wlan,
+	.dev		= {.platform_data = &qcom_wcnss_pdata},
+};
+
+#ifdef CONFIG_QSEECOM
+/* qseecom bus scaling */
+static struct msm_bus_vectors qseecom_clks_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ib = 0,
+		.ab = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_SPDM,
+		.dst = MSM_BUS_SLAVE_SPDM,
+		.ib = 0,
+		.ab = 0,
+	},
+};
+
+static struct msm_bus_vectors qseecom_enable_dfab_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ib = (492 * 8) * 1000000UL,
+		.ab = (492 * 8) *  100000UL,
+	},
+	{
+		.src = MSM_BUS_MASTER_SPDM,
+		.dst = MSM_BUS_SLAVE_SPDM,
+		.ib = 0,
+		.ab = 0,
+	},
+};
+
+static struct msm_bus_vectors qseecom_enable_sfpb_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ib = 0,
+		.ab = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_SPDM,
+		.dst = MSM_BUS_SLAVE_SPDM,
+		.ib = (64 * 8) * 1000000UL,
+		.ab = (64 * 8) *  100000UL,
+	},
+};
+
+static struct msm_bus_paths qseecom_hw_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(qseecom_clks_init_vectors),
+		qseecom_clks_init_vectors,
+	},
+	{
+		ARRAY_SIZE(qseecom_enable_dfab_vectors),
+		qseecom_enable_sfpb_vectors,
+	},
+	{
+		ARRAY_SIZE(qseecom_enable_sfpb_vectors),
+		qseecom_enable_sfpb_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata qseecom_bus_pdata = {
+	qseecom_hw_bus_scale_usecases,
+	ARRAY_SIZE(qseecom_hw_bus_scale_usecases),
+	.name = "qsee",
+};
+
+static struct platform_device qseecom_device = {
+	.name		= "qseecom",
+	.id		= 0,
+	.dev		= {
+		.platform_data = &qseecom_bus_pdata,
+	},
+};
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+
+#define QCE_SIZE		0x10000
+#define QCE_0_BASE		0x18500000
+
+#define QCE_HW_KEY_SUPPORT	0
+#define QCE_SHA_HMAC_SUPPORT	1
+#define QCE_SHARE_CE_RESOURCE	1
+#define QCE_CE_SHARED		0
+
+/* Begin Bus scaling definitions */
+static struct msm_bus_vectors crypto_hw_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_ADM_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_ADM_PORT1,
+		.dst = MSM_BUS_SLAVE_GSBI1_UART,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+static struct msm_bus_vectors crypto_hw_active_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_ADM_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 70000000UL,
+		.ib = 70000000UL,
+	},
+	{
+		.src = MSM_BUS_MASTER_ADM_PORT1,
+		.dst = MSM_BUS_SLAVE_GSBI1_UART,
+		.ab = 2480000000UL,
+		.ib = 2480000000UL,
+	},
+};
+
+static struct msm_bus_paths crypto_hw_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(crypto_hw_init_vectors),
+		crypto_hw_init_vectors,
+	},
+	{
+		ARRAY_SIZE(crypto_hw_active_vectors),
+		crypto_hw_active_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata crypto_hw_bus_scale_pdata = {
+		crypto_hw_bus_scale_usecases,
+		ARRAY_SIZE(crypto_hw_bus_scale_usecases),
+		.name = "cryptohw",
+};
+/* End Bus Scaling Definitions*/
+
+static struct resource qcrypto_resources[] = {
+	[0] = {
+		.start = QCE_0_BASE,
+		.end = QCE_0_BASE + QCE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.name = "crypto_channels",
+		.start = DMOV_CE_IN_CHAN,
+		.end = DMOV_CE_OUT_CHAN,
+		.flags = IORESOURCE_DMA,
+	},
+	[2] = {
+		.name = "crypto_crci_in",
+		.start = DMOV_CE_IN_CRCI,
+		.end = DMOV_CE_IN_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+	[3] = {
+		.name = "crypto_crci_out",
+		.start = DMOV_CE_OUT_CRCI,
+		.end = DMOV_CE_OUT_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static struct resource qcedev_resources[] = {
+	[0] = {
+		.start = QCE_0_BASE,
+		.end = QCE_0_BASE + QCE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.name = "crypto_channels",
+		.start = DMOV_CE_IN_CHAN,
+		.end = DMOV_CE_OUT_CHAN,
+		.flags = IORESOURCE_DMA,
+	},
+	[2] = {
+		.name = "crypto_crci_in",
+		.start = DMOV_CE_IN_CRCI,
+		.end = DMOV_CE_IN_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+	[3] = {
+		.name = "crypto_crci_out",
+		.start = DMOV_CE_OUT_CRCI,
+		.end = DMOV_CE_OUT_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
+
+static struct msm_ce_hw_support qcrypto_ce_hw_suppport = {
+	.ce_shared = QCE_CE_SHARED,
+	.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
+	.hw_key_support = QCE_HW_KEY_SUPPORT,
+	.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+	.bus_scale_table = &crypto_hw_bus_scale_pdata,
+};
+
+static struct platform_device qcrypto_device = {
+	.name		= "qcrypto",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(qcrypto_resources),
+	.resource	= qcrypto_resources,
+	.dev		= {
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+		.platform_data = &qcrypto_ce_hw_suppport,
+	},
+};
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+
+static struct msm_ce_hw_support qcedev_ce_hw_suppport = {
+	.ce_shared = QCE_CE_SHARED,
+	.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
+	.hw_key_support = QCE_HW_KEY_SUPPORT,
+	.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+	.bus_scale_table = &crypto_hw_bus_scale_pdata,
+};
+
+static struct platform_device qcedev_device = {
+	.name		= "qce",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(qcedev_resources),
+	.resource	= qcedev_resources,
+	.dev		= {
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+		.platform_data = &qcedev_ce_hw_suppport,
+	},
+};
+#endif
+
+static struct mdm_platform_data sglte_platform_data = {
+	.mdm_version = "4.0",
+	.ramdump_delay_ms = 1000,
+	.soft_reset_inverted = 1,
+	.peripheral_platform_device = NULL,
+};
+
+#define MSM_SHARED_RAM_PHYS 0x80000000
+
+static void __init msm8960_map_io(void)
+{
+	msm_shared_ram_phys = MSM_SHARED_RAM_PHYS;
+	msm_map_msm8960_io();
+
+	if (socinfo_init() < 0)
+		pr_err("socinfo_init() failed!\n");
+}
+
+static void __init msm8960_init_irq(void)
+{
+	struct msm_mpm_device_data *data = NULL;
+
+#ifdef CONFIG_MSM_MPM
+	data = &msm8960_mpm_dev_data;
+#endif
+
+	msm_mpm_irq_extn_init(data);
+	gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE,
+						(void *)MSM_QGIC_CPU_BASE);
+}
+
+static void __init msm8960_init_buses(void)
+{
+#ifdef CONFIG_MSM_BUS_SCALING
+	msm_bus_rpm_set_mt_mask();
+	msm_bus_8960_apps_fabric_pdata.rpm_enabled = 1;
+	msm_bus_8960_sys_fabric_pdata.rpm_enabled = 1;
+	msm_bus_8960_mm_fabric_pdata.rpm_enabled = 1;
+	msm_bus_apps_fabric.dev.platform_data =
+		&msm_bus_8960_apps_fabric_pdata;
+	msm_bus_sys_fabric.dev.platform_data = &msm_bus_8960_sys_fabric_pdata;
+	msm_bus_mm_fabric.dev.platform_data = &msm_bus_8960_mm_fabric_pdata;
+	msm_bus_sys_fpb.dev.platform_data = &msm_bus_8960_sys_fpb_pdata;
+	msm_bus_cpss_fpb.dev.platform_data = &msm_bus_8960_cpss_fpb_pdata;
+#endif
+}
+
+static struct msm_spi_platform_data msm8960_qup_spi_gsbi1_pdata = {
+	.max_clock_speed = 15060000,
+};
+
+#ifdef CONFIG_USB_MSM_OTG_72K
+static struct msm_otg_platform_data msm_otg_pdata;
+#else
+static int wr_phy_init_seq[] = {
+	0x44, 0x80, /* set VBUS valid threshold
+			and disconnect valid threshold */
+	0x38, 0x81, /* update DC voltage level */
+	0x14, 0x82, /* set preemphasis and rise/fall time */
+	0x13, 0x83, /* set source impedance adjusment */
+	-1};
+
+static int liquid_v1_phy_init_seq[] = {
+	0x44, 0x80,/* set VBUS valid threshold
+			and disconnect valid threshold */
+	0x3C, 0x81,/* update DC voltage level */
+	0x18, 0x82,/* set preemphasis and rise/fall time */
+	0x23, 0x83,/* set source impedance sdjusment */
+	-1};
+
+#ifdef CONFIG_MSM_BUS_SCALING
+/* Bandwidth requests (zero) if no vote placed */
+static struct msm_bus_vectors usb_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+/* Bus bandwidth requests in Bytes/sec */
+static struct msm_bus_vectors usb_max_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 60000000,		/* At least 480Mbps on bus. */
+		.ib = 960000000,	/* MAX bursts rate */
+	},
+};
+
+static struct msm_bus_paths usb_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(usb_init_vectors),
+		usb_init_vectors,
+	},
+	{
+		ARRAY_SIZE(usb_max_vectors),
+		usb_max_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata usb_bus_scale_pdata = {
+	usb_bus_scale_usecases,
+	ARRAY_SIZE(usb_bus_scale_usecases),
+	.name = "usb",
+};
+#endif
+
+static struct msm_otg_platform_data msm_otg_pdata = {
+	.mode			= USB_OTG,
+	.otg_control		= OTG_PMIC_CONTROL,
+	.phy_type		= SNPS_28NM_INTEGRATED_PHY,
+	.pmic_id_irq		= PM8921_USB_ID_IN_IRQ(PM8921_IRQ_BASE),
+	.power_budget		= 750,
+#ifdef CONFIG_MSM_BUS_SCALING
+	.bus_scale_table	= &usb_bus_scale_pdata,
+#endif
+};
+#endif
+
+#ifdef CONFIG_USB_EHCI_MSM_HSIC
+#define HSIC_HUB_RESET_GPIO	91
+static struct msm_hsic_host_platform_data msm_hsic_pdata = {
+	.strobe		= 150,
+	.data		= 151,
+};
+
+static struct smsc_hub_platform_data hsic_hub_pdata = {
+	.hub_reset		= HSIC_HUB_RESET_GPIO,
+};
+#else
+static struct msm_hsic_host_platform_data msm_hsic_pdata;
+static struct smsc_hub_platform_data hsic_hub_pdata;
+#endif
+
+static struct platform_device smsc_hub_device = {
+	.name	= "msm_smsc_hub",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &hsic_hub_pdata,
+	},
+};
+
+#define PID_MAGIC_ID		0x71432909
+#define SERIAL_NUM_MAGIC_ID	0x61945374
+#define SERIAL_NUMBER_LENGTH	127
+#define DLOAD_USB_BASE_ADD	0x2A03F0C8
+
+struct magic_num_struct {
+	uint32_t pid;
+	uint32_t serial_num;
+};
+
+struct dload_struct {
+	uint32_t	reserved1;
+	uint32_t	reserved2;
+	uint32_t	reserved3;
+	uint16_t	reserved4;
+	uint16_t	pid;
+	char		serial_number[SERIAL_NUMBER_LENGTH];
+	uint16_t	reserved5;
+	struct magic_num_struct magic_struct;
+};
+
+static int usb_diag_update_pid_and_serial_num(uint32_t pid, const char *snum)
+{
+	struct dload_struct __iomem *dload = 0;
+
+	dload = ioremap(DLOAD_USB_BASE_ADD, sizeof(*dload));
+	if (!dload) {
+		pr_err("%s: cannot remap I/O memory region: %08x\n",
+					__func__, DLOAD_USB_BASE_ADD);
+		return -ENXIO;
+	}
+
+	pr_debug("%s: dload:%p pid:%x serial_num:%s\n",
+				__func__, dload, pid, snum);
+	/* update pid */
+	dload->magic_struct.pid = PID_MAGIC_ID;
+	dload->pid = pid;
+
+	/* update serial number */
+	dload->magic_struct.serial_num = 0;
+	if (!snum) {
+		memset(dload->serial_number, 0, SERIAL_NUMBER_LENGTH);
+		goto out;
+	}
+
+	dload->magic_struct.serial_num = SERIAL_NUM_MAGIC_ID;
+	strlcpy(dload->serial_number, snum, SERIAL_NUMBER_LENGTH);
+out:
+	iounmap(dload);
+	return 0;
+}
+
+static struct android_usb_platform_data android_usb_pdata = {
+	.update_pid_and_serial_num = usb_diag_update_pid_and_serial_num,
+};
+
+static struct platform_device android_usb_device = {
+	.name	= "android_usb",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &android_usb_pdata,
+	},
+};
+
+static uint8_t spm_wfi_cmd_sequence[] __initdata = {
+			0x03, 0x0f,
+};
+
+static uint8_t spm_power_collapse_without_rpm[] __initdata = {
+			0x00, 0x24, 0x54, 0x10,
+			0x09, 0x03, 0x01,
+			0x10, 0x54, 0x30, 0x0C,
+			0x24, 0x30, 0x0f,
+};
+
+static uint8_t spm_power_collapse_with_rpm[] __initdata = {
+			0x00, 0x24, 0x54, 0x10,
+			0x09, 0x07, 0x01, 0x0B,
+			0x10, 0x54, 0x30, 0x0C,
+			0x24, 0x30, 0x0f,
+};
+
+static struct msm_spm_seq_entry msm_spm_seq_list[] __initdata = {
+	[0] = {
+		.mode = MSM_SPM_MODE_CLOCK_GATING,
+		.notify_rpm = false,
+		.cmd = spm_wfi_cmd_sequence,
+	},
+	[1] = {
+		.mode = MSM_SPM_MODE_POWER_COLLAPSE,
+		.notify_rpm = false,
+		.cmd = spm_power_collapse_without_rpm,
+	},
+	[2] = {
+		.mode = MSM_SPM_MODE_POWER_COLLAPSE,
+		.notify_rpm = true,
+		.cmd = spm_power_collapse_with_rpm,
+	},
+};
+
+static struct msm_spm_platform_data msm_spm_data[] __initdata = {
+	[0] = {
+		.reg_base_addr = MSM_SAW0_BASE,
+		.reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F,
+#if defined(CONFIG_MSM_AVS_HW)
+		.reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x00,
+		.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
+#endif
+		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
+		.vctl_timeout_us = 50,
+		.num_modes = ARRAY_SIZE(msm_spm_seq_list),
+		.modes = msm_spm_seq_list,
+	},
+	[1] = {
+		.reg_base_addr = MSM_SAW1_BASE,
+		.reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F,
+#if defined(CONFIG_MSM_AVS_HW)
+		.reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x00,
+		.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
+#endif
+		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
+		.vctl_timeout_us = 50,
+		.num_modes = ARRAY_SIZE(msm_spm_seq_list),
+		.modes = msm_spm_seq_list,
+	},
+};
+
+static uint8_t l2_spm_wfi_cmd_sequence[] __initdata = {
+			0x00, 0x20, 0x03, 0x20,
+			0x00, 0x0f,
+};
+
+static uint8_t l2_spm_gdhs_cmd_sequence[] __initdata = {
+			0x00, 0x20, 0x34, 0x64,
+			0x48, 0x07, 0x48, 0x20,
+			0x50, 0x64, 0x04, 0x34,
+			0x50, 0x0f,
+};
+static uint8_t l2_spm_power_off_cmd_sequence[] __initdata = {
+			0x00, 0x10, 0x34, 0x64,
+			0x48, 0x07, 0x48, 0x10,
+			0x50, 0x64, 0x04, 0x34,
+			0x50, 0x0F,
+};
+
+static struct msm_spm_seq_entry msm_spm_l2_seq_list[] __initdata = {
+	[0] = {
+		.mode = MSM_SPM_L2_MODE_RETENTION,
+		.notify_rpm = false,
+		.cmd = l2_spm_wfi_cmd_sequence,
+	},
+	[1] = {
+		.mode = MSM_SPM_L2_MODE_GDHS,
+		.notify_rpm = true,
+		.cmd = l2_spm_gdhs_cmd_sequence,
+	},
+	[2] = {
+		.mode = MSM_SPM_L2_MODE_POWER_COLLAPSE,
+		.notify_rpm = true,
+		.cmd = l2_spm_power_off_cmd_sequence,
+	},
+};
+
+static struct msm_spm_platform_data msm_spm_l2_data[] __initdata = {
+	[0] = {
+		.reg_base_addr = MSM_SAW_L2_BASE,
+		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x00,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x00A000AE,
+		.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x00A00020,
+		.modes = msm_spm_l2_seq_list,
+		.num_modes = ARRAY_SIZE(msm_spm_l2_seq_list),
+	},
+};
+
+#define PM_HAP_EN_GPIO		PM8921_GPIO_PM_TO_SYS(33)
+#define PM_HAP_LEN_GPIO		PM8921_GPIO_PM_TO_SYS(20)
+
+static struct msm_xo_voter *xo_handle_d1;
+
+static int isa1200_power(int on)
+{
+	int rc = 0;
+
+	gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, !!on);
+
+	rc = on ? msm_xo_mode_vote(xo_handle_d1, MSM_XO_MODE_ON) :
+			msm_xo_mode_vote(xo_handle_d1, MSM_XO_MODE_OFF);
+	if (rc < 0) {
+		pr_err("%s: failed to %svote for TCXO D1 buffer%d\n",
+				__func__, on ? "" : "de-", rc);
+		goto err_xo_vote;
+	}
+
+	return 0;
+
+err_xo_vote:
+	gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, !on);
+	return rc;
+}
+
+static int isa1200_dev_setup(bool enable)
+{
+	int rc = 0;
+
+	struct pm_gpio hap_gpio_config = {
+		.direction      = PM_GPIO_DIR_OUT,
+		.pull           = PM_GPIO_PULL_NO,
+		.out_strength   = PM_GPIO_STRENGTH_HIGH,
+		.function       = PM_GPIO_FUNC_NORMAL,
+		.inv_int_pol    = 0,
+		.vin_sel        = 2,
+		.output_buffer  = PM_GPIO_OUT_BUF_CMOS,
+		.output_value   = 0,
+	};
+
+	if (enable == true) {
+		rc = pm8xxx_gpio_config(PM_HAP_EN_GPIO, &hap_gpio_config);
+		if (rc) {
+			pr_err("%s: pm8921 gpio %d config failed(%d)\n",
+					__func__, PM_HAP_EN_GPIO, rc);
+			return rc;
+		}
+
+		rc = pm8xxx_gpio_config(PM_HAP_LEN_GPIO, &hap_gpio_config);
+		if (rc) {
+			pr_err("%s: pm8921 gpio %d config failed(%d)\n",
+					__func__, PM_HAP_LEN_GPIO, rc);
+			return rc;
+		}
+
+		rc = gpio_request(HAP_SHIFT_LVL_OE_GPIO, "hap_shft_lvl_oe");
+		if (rc) {
+			pr_err("%s: unable to request gpio %d (%d)\n",
+					__func__, HAP_SHIFT_LVL_OE_GPIO, rc);
+			return rc;
+		}
+
+		rc = gpio_direction_output(HAP_SHIFT_LVL_OE_GPIO, 0);
+		if (rc) {
+			pr_err("%s: Unable to set direction\n", __func__);
+			goto free_gpio;
+		}
+
+		xo_handle_d1 = msm_xo_get(MSM_XO_TCXO_D1, "isa1200");
+		if (IS_ERR(xo_handle_d1)) {
+			rc = PTR_ERR(xo_handle_d1);
+			pr_err("%s: failed to get the handle for D1(%d)\n",
+							__func__, rc);
+			goto gpio_set_dir;
+		}
+	} else {
+		gpio_free(HAP_SHIFT_LVL_OE_GPIO);
+
+		msm_xo_put(xo_handle_d1);
+	}
+
+	return 0;
+
+gpio_set_dir:
+	gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, 0);
+free_gpio:
+	gpio_free(HAP_SHIFT_LVL_OE_GPIO);
+	return rc;
+}
+
+static struct isa1200_regulator isa1200_reg_data[] = {
+	{
+		.name = "vcc_i2c",
+		.min_uV = ISA_I2C_VTG_MIN_UV,
+		.max_uV = ISA_I2C_VTG_MAX_UV,
+		.load_uA = ISA_I2C_CURR_UA,
+	},
+};
+
+static struct isa1200_platform_data isa1200_1_pdata = {
+	.name = "vibrator",
+	.dev_setup = isa1200_dev_setup,
+	.power_on = isa1200_power,
+	.hap_en_gpio = PM_HAP_EN_GPIO,
+	.hap_len_gpio = PM_HAP_LEN_GPIO,
+	.max_timeout = 15000,
+	.mode_ctrl = PWM_GEN_MODE,
+	.pwm_fd = {
+		.pwm_div = 256,
+	},
+	.is_erm = false,
+	.smart_en = true,
+	.ext_clk_en = true,
+	.chip_en = 1,
+	.regulator_info = isa1200_reg_data,
+	.num_regulators = ARRAY_SIZE(isa1200_reg_data),
+};
+
+static struct i2c_board_info msm_isa1200_board_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("isa1200_1", 0x90>>1),
+	},
+};
+
+#define CYTTSP_TS_GPIO_IRQ		11
+#define CYTTSP_TS_SLEEP_GPIO		50
+#define CYTTSP_TS_RESOUT_N_GPIO		52
+
+/*virtual key support */
+static ssize_t tma340_vkeys_show(struct kobject *kobj,
+			struct kobj_attribute *attr, char *buf)
+{
+	return snprintf(buf, 200,
+	__stringify(EV_KEY) ":" __stringify(KEY_BACK) ":73:1120:97:97"
+	":" __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":230:1120:97:97"
+	":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":389:1120:97:97"
+	":" __stringify(EV_KEY) ":" __stringify(KEY_SEARCH) ":544:1120:97:97"
+	"\n");
+}
+
+static struct kobj_attribute tma340_vkeys_attr = {
+	.attr = {
+		.mode = S_IRUGO,
+	},
+	.show = &tma340_vkeys_show,
+};
+
+static struct attribute *tma340_properties_attrs[] = {
+	&tma340_vkeys_attr.attr,
+	NULL
+};
+
+static struct attribute_group tma340_properties_attr_group = {
+	.attrs = tma340_properties_attrs,
+};
+
+
+static int cyttsp_platform_init(struct i2c_client *client)
+{
+	int rc = 0;
+	static struct kobject *tma340_properties_kobj;
+
+	tma340_vkeys_attr.attr.name = "virtualkeys.cyttsp-i2c";
+	tma340_properties_kobj = kobject_create_and_add("board_properties",
+								NULL);
+	if (tma340_properties_kobj)
+		rc = sysfs_create_group(tma340_properties_kobj,
+					&tma340_properties_attr_group);
+	if (!tma340_properties_kobj || rc)
+		pr_err("%s: failed to create board_properties\n",
+				__func__);
+
+	return 0;
+}
+
+static struct cyttsp_regulator regulator_data[] = {
+	{
+		.name = "vdd",
+		.min_uV = CY_TMA300_VTG_MIN_UV,
+		.max_uV = CY_TMA300_VTG_MAX_UV,
+		.hpm_load_uA = CY_TMA300_CURR_24HZ_UA,
+		.lpm_load_uA = CY_TMA300_SLEEP_CURR_UA,
+	},
+	/* TODO: Remove after runtime PM is enabled in I2C driver */
+	{
+		.name = "vcc_i2c",
+		.min_uV = CY_I2C_VTG_MIN_UV,
+		.max_uV = CY_I2C_VTG_MAX_UV,
+		.hpm_load_uA = CY_I2C_CURR_UA,
+		.lpm_load_uA = CY_I2C_SLEEP_CURR_UA,
+	},
+};
+
+static struct cyttsp_platform_data cyttsp_pdata = {
+	.panel_maxx = 634,
+	.panel_maxy = 1166,
+	.disp_maxx = 616,
+	.disp_maxy = 1023,
+	.disp_minx = 0,
+	.disp_miny = 16,
+	.flags = 0x01,
+	.gen = CY_GEN3,	/* or */
+	.use_st = CY_USE_ST,
+	.use_mt = CY_USE_MT,
+	.use_hndshk = CY_SEND_HNDSHK,
+	.use_trk_id = CY_USE_TRACKING_ID,
+	.use_sleep = CY_USE_DEEP_SLEEP_SEL | CY_USE_LOW_POWER_SEL,
+	.use_gestures = CY_USE_GESTURES,
+	.fw_fname = "cyttsp_8960_cdp.hex",
+	/* activate up to 4 groups
+	 * and set active distance
+	 */
+	.gest_set = CY_GEST_GRP1 | CY_GEST_GRP2 |
+				CY_GEST_GRP3 | CY_GEST_GRP4 |
+				CY_ACT_DIST,
+	/* change act_intrvl to customize the Active power state
+	 * scanning/processing refresh interval for Operating mode
+	 */
+	.act_intrvl = CY_ACT_INTRVL_DFLT,
+	/* change tch_tmout to customize the touch timeout for the
+	 * Active power state for Operating mode
+	 */
+	.tch_tmout = CY_TCH_TMOUT_DFLT,
+	/* change lp_intrvl to customize the Low Power power state
+	 * scanning/processing refresh interval for Operating mode
+	 */
+	.lp_intrvl = CY_LP_INTRVL_DFLT,
+	.sleep_gpio = CYTTSP_TS_SLEEP_GPIO,
+	.resout_gpio = CYTTSP_TS_RESOUT_N_GPIO,
+	.irq_gpio = CYTTSP_TS_GPIO_IRQ,
+	.regulator_info = regulator_data,
+	.num_regulators = ARRAY_SIZE(regulator_data),
+	.init = cyttsp_platform_init,
+	.correct_fw_ver = 9,
+};
+
+static struct i2c_board_info cyttsp_info[] __initdata = {
+	{
+		I2C_BOARD_INFO(CY_I2C_NAME, 0x24),
+		.platform_data = &cyttsp_pdata,
+#ifndef CY_USE_TIMER
+		.irq = MSM_GPIO_TO_INT(CYTTSP_TS_GPIO_IRQ),
+#endif /* CY_USE_TIMER */
+	},
+};
+
+/* configuration data for mxt1386 */
+static const u8 mxt1386_config_data[] = {
+	/* T6 Object */
+	0, 0, 0, 0, 0, 0,
+	/* T38 Object */
+	11, 2, 0, 11, 11, 11, 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 */
+	8, 0, 0, 0, 0, 0, 8, 14, 50, 215,
+	/* T9 Object */
+	131, 0, 0, 26, 42, 0, 32, 63, 3, 5,
+	0, 2, 1, 113, 10, 10, 8, 10, 255, 2,
+	85, 5, 0, 0, 20, 20, 75, 25, 202, 29,
+	10, 10, 45, 46,
+	/* T15 Object */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0,
+	/* T18 Object */
+	0, 0,
+	/* T22 Object */
+	5, 0, 0, 0, 0, 0, 0, 0, 30, 0,
+	0, 0, 5, 8, 10, 13, 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, 188, 52, 52, 33, 0, 0, 0, 0,
+	0, 0, 0, 0,
+	/* T27 Object */
+	0, 0, 0, 0, 0, 0, 0,
+	/* T28 Object */
+	0, 0, 0, 8, 12, 60,
+	/* T40 Object */
+	0, 0, 0, 0, 0,
+	/* T41 Object */
+	0, 0, 0, 0, 0, 0,
+	/* T43 Object */
+	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, 3, 0, 24, 5, 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 */
+	139, 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 */
+	1, 0, 60, 115, 156, 99,
+	/* T27 Object */
+	0, 0, 0, 0, 0, 0, 0,
+	/* T40 Object */
+	0, 0, 0, 0, 0,
+	/* T42 Object */
+	0, 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 */
+	1, 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,
+};
+
+/* configuration data for mxt1386e on 3D SKU using V2.1 firmware */
+static const u8 mxt1386e_config_data_3d[] = {
+	/* T6 Object */
+	0, 0, 0, 0, 0, 0,
+	/* T38 Object */
+	13, 1, 0, 23, 2, 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, 10, 50,
+	/* T8 Object */
+	25, 0, 20, 20, 0, 0, 0, 0, 0, 0,
+	/* T9 Object */
+	131, 0, 0, 26, 42, 0, 32, 80, 2, 5,
+	0, 5, 5, 0, 10, 30, 10, 10, 175, 4,
+	127, 7, 26, 21, 17, 19, 143, 35, 207, 40,
+	20, 5, 54, 49, 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 */
+	0, 0, 72, 113, 168, 97,
+	/* T27 Object */
+	0, 0, 0, 0, 0, 0, 0,
+	/* T40 Object */
+	0, 0, 0, 0, 0,
+	/* T42 Object */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	/* T43 Object */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0,
+	/* T46 Object */
+	68, 0, 16, 16, 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,
+	32, 50, 0, 10, 10, 0, 0, 100, 10, 90,
+	0, 0, 0, 0, 0, 0, 0, 10, 1, 30,
+	52, 10, 5, 0, 33, 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,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0,
+};
+
+#define MXT_TS_GPIO_IRQ			11
+#define MXT_TS_LDO_EN_GPIO		50
+#define MXT_TS_RESET_GPIO		52
+
+static void mxt_init_hw_liquid(void)
+{
+	int rc;
+
+	rc = gpio_request(MXT_TS_LDO_EN_GPIO, "mxt_ldo_en_gpio");
+	if (rc) {
+		pr_err("%s: unable to request mxt_ldo_en_gpio [%d]\n",
+			__func__, MXT_TS_LDO_EN_GPIO);
+		return;
+	}
+
+	rc = gpio_direction_output(MXT_TS_LDO_EN_GPIO, 1);
+	if (rc) {
+		pr_err("%s: unable to set_direction for mxt_ldo_en_gpio [%d]\n",
+			__func__, MXT_TS_LDO_EN_GPIO);
+		goto err_ldo_gpio_req;
+	}
+
+	return;
+
+err_ldo_gpio_req:
+	gpio_free(MXT_TS_LDO_EN_GPIO);
+}
+
+static struct mxt_config_info mxt_config_array_2d[] = {
+	{
+		.config		= mxt1386_config_data,
+		.config_length	= ARRAY_SIZE(mxt1386_config_data),
+		.family_id	= 0xA0,
+		.variant_id	= 0x0,
+		.version	= 0x10,
+		.build		= 0xAA,
+		.bootldr_id	= MXT_BOOTLOADER_ID_1386,
+	},
+	{
+		.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,
+		.bootldr_id	= MXT_BOOTLOADER_ID_1386E,
+		.fw_name	= "atmel_8960_liquid_v2_2_AA.hex",
+	},
+	{
+		.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,
+		.bootldr_id	= MXT_BOOTLOADER_ID_1386E,
+		.fw_name	= "atmel_8960_liquid_v2_2_AA.hex",
+	},
+	{
+		/* The config data for V2.2.AA is the same as for V2.1.AA */
+		.config		= mxt1386e_config_data_v2_1,
+		.config_length	= ARRAY_SIZE(mxt1386e_config_data_v2_1),
+		.family_id	= 0xA0,
+		.variant_id	= 0x7,
+		.version	= 0x22,
+		.build		= 0xAA,
+		.bootldr_id	= MXT_BOOTLOADER_ID_1386E,
+	},
+};
+
+static struct mxt_platform_data mxt_platform_data_2d = {
+	.config_array		= mxt_config_array_2d,
+	.config_array_size	= ARRAY_SIZE(mxt_config_array_2d),
+	.panel_minx		= 0,
+	.panel_maxx		= 1365,
+	.panel_miny		= 0,
+	.panel_maxy		= 767,
+	.disp_minx		= 0,
+	.disp_maxx		= 1365,
+	.disp_miny		= 0,
+	.disp_maxy		= 767,
+	.irqflags		= IRQF_TRIGGER_FALLING,
+	.i2c_pull_up		= true,
+	.reset_gpio		= MXT_TS_RESET_GPIO,
+	.irq_gpio		= MXT_TS_GPIO_IRQ,
+};
+
+static struct mxt_config_info mxt_config_array_3d[] = {
+	{
+		.config		= mxt1386e_config_data_3d,
+		.config_length	= ARRAY_SIZE(mxt1386e_config_data_3d),
+		.family_id	= 0xA0,
+		.variant_id	= 0x7,
+		.version	= 0x21,
+		.build		= 0xAA,
+	},
+};
+
+static struct mxt_platform_data mxt_platform_data_3d = {
+	.config_array		= mxt_config_array_3d,
+	.config_array_size	= ARRAY_SIZE(mxt_config_array_3d),
+	.panel_minx		= 0,
+	.panel_maxx		= 1919,
+	.panel_miny		= 0,
+	.panel_maxy		= 1199,
+	.disp_minx		= 0,
+	.disp_maxx		= 1919,
+	.disp_miny		= 0,
+	.disp_maxy		= 1199,
+	.irqflags		= IRQF_TRIGGER_FALLING,
+	.i2c_pull_up		= true,
+	.reset_gpio		= MXT_TS_RESET_GPIO,
+	.irq_gpio		= MXT_TS_GPIO_IRQ,
+};
+
+static struct i2c_board_info mxt_device_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("atmel_mxt_ts", 0x5b),
+		.irq = MSM_GPIO_TO_INT(MXT_TS_GPIO_IRQ),
+	},
+};
+
+#ifdef CONFIG_FB_MSM_HDMI_MHL_8334
+static void mhl_sii_reset_gpio(int on)
+{
+	gpio_set_value(MHL_GPIO_RESET, on);
+	return;
+}
+
+/*
+ * Request for GPIO allocations
+ * Set appropriate GPIO directions
+ */
+static int mhl_sii_gpio_setup(int on)
+{
+	int ret;
+
+	if (on) {
+		ret = gpio_request(MHL_GPIO_RESET, "W_RST#");
+		if (ret < 0) {
+			pr_err("GPIO RESET request failed: %d\n", ret);
+			return -EBUSY;
+		}
+		ret = gpio_direction_output(MHL_GPIO_RESET, 1);
+		if (ret < 0) {
+			pr_err("SET GPIO RESET direction failed: %d\n", ret);
+			gpio_free(MHL_GPIO_RESET);
+			return -EBUSY;
+		}
+		ret = gpio_request(MHL_GPIO_INT, "W_INT");
+		if (ret < 0) {
+			pr_err("GPIO INT request failed: %d\n", ret);
+			gpio_free(MHL_GPIO_RESET);
+			return -EBUSY;
+		}
+		ret = gpio_direction_input(MHL_GPIO_INT);
+		if (ret < 0) {
+			pr_err("SET GPIO INTR direction failed: %d\n", ret);
+			gpio_free(MHL_GPIO_RESET);
+			gpio_free(MHL_GPIO_INT);
+			return -EBUSY;
+		}
+	} else {
+		gpio_free(MHL_GPIO_RESET);
+		gpio_free(MHL_GPIO_INT);
+	}
+
+	return 0;
+}
+
+static struct msm_mhl_platform_data mhl_platform_data = {
+	.irq = MSM_GPIO_TO_INT(4),
+	.gpio_setup = mhl_sii_gpio_setup,
+	.reset_pin = mhl_sii_reset_gpio,
+};
+#endif
+
+static struct i2c_board_info sii_device_info[] __initdata = {
+	{
+#ifdef CONFIG_FB_MSM_HDMI_MHL_8334
+		/*
+		 * keeps SI 8334 as the default
+		 * MHL TX
+		 */
+		I2C_BOARD_INFO("sii8334", 0x39),
+		.platform_data = &mhl_platform_data,
+#endif
+#ifdef CONFIG_FB_MSM_HDMI_MHL_9244
+		I2C_BOARD_INFO("Sil-9244", 0x39),
+		.irq = MSM_GPIO_TO_INT(15),
+#endif /* CONFIG_MSM_HDMI_MHL */
+		.flags = I2C_CLIENT_WAKE,
+	},
+};
+
+static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi4_pdata = {
+	.clk_freq = 100000,
+	.src_clk_rate = 24000000,
+};
+
+static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi3_pdata = {
+	.clk_freq = 100000,
+	.src_clk_rate = 24000000,
+};
+
+static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi10_pdata = {
+	.clk_freq = 100000,
+	.src_clk_rate = 24000000,
+};
+
+static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi12_pdata = {
+	.clk_freq = 100000,
+	.src_clk_rate = 24000000,
+};
+
+static struct msm_pm_sleep_status_data msm_pm_slp_sts_data = {
+	.base_addr = MSM_ACC0_BASE + 0x08,
+	.cpu_offset = MSM_ACC1_BASE - MSM_ACC0_BASE,
+	.mask = 1UL << 13,
+};
+
+static struct ks8851_pdata spi_eth_pdata = {
+	.irq_gpio = KS8851_IRQ_GPIO,
+	.rst_gpio = KS8851_RST_GPIO,
+};
+
+static struct spi_board_info spi_board_info[] __initdata = {
+	{
+		.modalias               = "ks8851",
+		.irq                    = MSM_GPIO_TO_INT(KS8851_IRQ_GPIO),
+		.max_speed_hz           = 19200000,
+		.bus_num                = 0,
+		.chip_select            = 0,
+		.mode                   = SPI_MODE_0,
+		.platform_data		= &spi_eth_pdata
+	},
+	{
+		.modalias               = "dsi_novatek_3d_panel_spi",
+		.max_speed_hz           = 10800000,
+		.bus_num                = 0,
+		.chip_select            = 1,
+		.mode                   = SPI_MODE_0,
+	},
+};
+
+static struct platform_device msm_device_saw_core0 = {
+	.name          = "saw-regulator",
+	.id            = 0,
+	.dev	= {
+		.platform_data = &msm_saw_regulator_pdata_s5,
+	},
+};
+
+static struct platform_device msm_device_saw_core1 = {
+	.name          = "saw-regulator",
+	.id            = 1,
+	.dev	= {
+		.platform_data = &msm_saw_regulator_pdata_s6,
+	},
+};
+
+static struct tsens_platform_data msm_tsens_pdata  = {
+		.slope			= {910, 910, 910, 910, 910},
+		.tsens_factor		= 1000,
+		.hw_type		= MSM_8960,
+		.tsens_num_sensor	= 5,
+};
+
+static struct platform_device msm_tsens_device = {
+	.name   = "tsens8960-tm",
+	.id = -1,
+};
+
+#ifdef CONFIG_MSM_FAKE_BATTERY
+static struct platform_device fish_battery_device = {
+	.name = "fish_battery",
+};
+#endif
+
+static struct platform_device msm8960_device_ext_5v_vreg __devinitdata = {
+	.name	= GPIO_REGULATOR_DEV_NAME,
+	.id	= PM8921_MPP_PM_TO_SYS(7),
+	.dev	= {
+		.platform_data = &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_5V],
+	},
+};
+
+static struct platform_device msm8960_device_ext_l2_vreg __devinitdata = {
+	.name	= GPIO_REGULATOR_DEV_NAME,
+	.id	= 91,
+	.dev	= {
+		.platform_data = &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_L2],
+	},
+};
+
+static struct platform_device msm8960_device_ext_3p3v_vreg __devinitdata = {
+	.name	= GPIO_REGULATOR_DEV_NAME,
+	.id	= PM8921_GPIO_PM_TO_SYS(17),
+	.dev	= {
+		.platform_data =
+			&msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_3P3V],
+	},
+};
+
+static struct platform_device msm8960_device_ext_otg_sw_vreg __devinitdata = {
+	.name	= GPIO_REGULATOR_DEV_NAME,
+	.id	= PM8921_GPIO_PM_TO_SYS(42),
+	.dev	= {
+		.platform_data =
+			&msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_OTG_SW],
+	},
+};
+
+static struct platform_device msm8960_device_rpm_regulator __devinitdata = {
+	.name	= "rpm-regulator",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &msm_rpm_regulator_pdata,
+	},
+};
+#ifdef CONFIG_SERIAL_MSM_HS
+static int configure_uart_gpios(int on)
+{
+	int ret = 0, i;
+	int uart_gpios[] = {93, 94, 95, 96};
+
+	for (i = 0; i < ARRAY_SIZE(uart_gpios); i++) {
+		if (on) {
+			ret = gpio_request(uart_gpios[i], NULL);
+			if (ret) {
+				pr_err("%s: unable to request uart gpio[%d]\n",
+						__func__, uart_gpios[i]);
+				break;
+			}
+		} else {
+			gpio_free(uart_gpios[i]);
+		}
+	}
+
+	if (ret && on && i)
+		for (; i >= 0; i--)
+			gpio_free(uart_gpios[i]);
+	return ret;
+}
+
+static struct msm_serial_hs_platform_data msm_uart_dm9_pdata = {
+	.gpio_config	= configure_uart_gpios,
+};
+#else
+static struct msm_serial_hs_platform_data msm_uart_dm9_pdata;
+#endif
+
+static struct platform_device *common_devices[] __initdata = {
+	&msm8960_device_dmov,
+	&msm_device_smd,
+	&msm_device_uart_dm6,
+	&msm_device_uart_dm9,
+	&msm_device_saw_core0,
+	&msm_device_saw_core1,
+	&msm8960_device_ext_5v_vreg,
+	&msm8960_device_ssbi_pmic,
+	&msm8960_device_ext_otg_sw_vreg,
+	&msm8960_device_qup_spi_gsbi1,
+	&msm8960_device_qup_i2c_gsbi3,
+	&msm8960_device_qup_i2c_gsbi4,
+	&msm8960_device_qup_i2c_gsbi10,
+#ifndef CONFIG_MSM_DSPS
+	&msm8960_device_qup_i2c_gsbi12,
+#endif
+	&msm_slim_ctrl,
+	&msm_device_wcnss_wlan,
+#if defined(CONFIG_QSEECOM)
+	&qseecom_device,
+#endif
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
+	&qcrypto_device,
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+	&qcedev_device,
+#endif
+#ifdef CONFIG_MSM_ROTATOR
+	&msm_rotator_device,
+#endif
+	&msm_device_sps,
+#ifdef CONFIG_MSM_FAKE_BATTERY
+	&fish_battery_device,
+#endif
+	&msm8960_fmem_device,
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+	&msm8960_android_pmem_device,
+	&msm8960_android_pmem_adsp_device,
+	&msm8960_android_pmem_audio_device,
+#endif
+#endif
+	&msm_device_vidc,
+	&msm_device_bam_dmux,
+	&msm_fm_platform_init,
+
+#if defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE)
+#ifdef CONFIG_MSM_USE_TSIF1
+	&msm_device_tsif[1],
+#else
+	&msm_device_tsif[0],
+#endif
+#endif
+
+#ifdef CONFIG_HW_RANDOM_MSM
+	&msm_device_rng,
+#endif
+#ifdef CONFIG_ION_MSM
+	&msm8960_ion_dev,
+#endif
+	&msm8960_rpm_device,
+	&msm8960_rpm_log_device,
+	&msm8960_rpm_stat_device,
+	&msm_device_tz_log,
+#ifdef CONFIG_MSM_QDSS
+	&msm_qdss_device,
+	&msm_etb_device,
+	&msm_tpiu_device,
+	&msm_funnel_device,
+	&msm_etm_device,
+#endif
+	&msm_device_dspcrashd_8960,
+	&msm8960_device_watchdog,
+	&msm8960_rtb_device,
+	&msm8960_cpu_idle_device,
+	&msm8960_msm_gov_device,
+	&msm8960_device_cache_erp,
+	&msm8960_cache_dump_device,
+	&msm8960_iommu_domain_device,
+	&msm_tsens_device,
+};
+
+static struct platform_device *sim_devices[] __initdata = {
+	&msm8960_device_uart_gsbi5,
+	&msm8960_device_otg,
+	&msm8960_device_gadget_peripheral,
+	&msm_device_hsusb_host,
+	&msm_device_hsic_host,
+	&android_usb_device,
+	&msm_device_vidc,
+	&msm_bus_apps_fabric,
+	&msm_bus_sys_fabric,
+	&msm_bus_mm_fabric,
+	&msm_bus_sys_fpb,
+	&msm_bus_cpss_fpb,
+	&msm_pcm,
+	&msm_multi_ch_pcm,
+	&msm_pcm_routing,
+	&msm_cpudai0,
+	&msm_cpudai1,
+	&msm8960_cpudai_slimbus_2_tx,
+	&msm_cpudai_hdmi_rx,
+	&msm_cpudai_bt_rx,
+	&msm_cpudai_bt_tx,
+	&msm_cpudai_fm_rx,
+	&msm_cpudai_fm_tx,
+	&msm_cpudai_auxpcm_rx,
+	&msm_cpudai_auxpcm_tx,
+	&msm_cpu_fe,
+	&msm_stub_codec,
+	&msm_voice,
+	&msm_voip,
+	&msm_lpa_pcm,
+	&msm_compr_dsp,
+	&msm_cpudai_incall_music_rx,
+	&msm_cpudai_incall_record_rx,
+	&msm_cpudai_incall_record_tx,
+
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
+	&qcrypto_device,
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+	&qcedev_device,
+#endif
+};
+
+static struct platform_device *rumi3_devices[] __initdata = {
+	&msm8960_device_uart_gsbi5,
+	&msm_kgsl_3d0,
+	&msm_kgsl_2d0,
+	&msm_kgsl_2d1,
+#ifdef CONFIG_MSM_GEMINI
+	&msm8960_gemini_device,
+#endif
+};
+
+static struct platform_device *cdp_devices[] __initdata = {
+	&msm_8960_q6_lpass,
+	&msm_8960_q6_mss_fw,
+	&msm_8960_q6_mss_sw,
+	&msm_8960_riva,
+	&msm_pil_tzapps,
+	&msm_pil_dsps,
+	&msm_pil_vidc,
+	&msm8960_device_otg,
+	&msm8960_device_gadget_peripheral,
+	&msm_device_hsusb_host,
+	&android_usb_device,
+	&msm_pcm,
+	&msm_multi_ch_pcm,
+	&msm_pcm_routing,
+	&msm_cpudai0,
+	&msm_cpudai1,
+	&msm8960_cpudai_slimbus_2_tx,
+	&msm_cpudai_hdmi_rx,
+	&msm_cpudai_bt_rx,
+	&msm_cpudai_bt_tx,
+	&msm_cpudai_fm_rx,
+	&msm_cpudai_fm_tx,
+	&msm_cpudai_auxpcm_rx,
+	&msm_cpudai_auxpcm_tx,
+	&msm_cpu_fe,
+	&msm_stub_codec,
+	&msm_kgsl_3d0,
+#ifdef CONFIG_MSM_KGSL_2D
+	&msm_kgsl_2d0,
+	&msm_kgsl_2d1,
+#endif
+#ifdef CONFIG_MSM_GEMINI
+	&msm8960_gemini_device,
+#endif
+	&msm_voice,
+	&msm_voip,
+	&msm_lpa_pcm,
+	&msm_cpudai_afe_01_rx,
+	&msm_cpudai_afe_01_tx,
+	&msm_cpudai_afe_02_rx,
+	&msm_cpudai_afe_02_tx,
+	&msm_pcm_afe,
+	&msm_compr_dsp,
+	&msm_cpudai_incall_music_rx,
+	&msm_cpudai_incall_record_rx,
+	&msm_cpudai_incall_record_tx,
+	&msm_pcm_hostless,
+	&msm_bus_apps_fabric,
+	&msm_bus_sys_fabric,
+	&msm_bus_mm_fabric,
+	&msm_bus_sys_fpb,
+	&msm_bus_cpss_fpb,
+};
+
+static void __init msm8960_i2c_init(void)
+{
+	msm8960_device_qup_i2c_gsbi4.dev.platform_data =
+					&msm8960_i2c_qup_gsbi4_pdata;
+
+	msm8960_device_qup_i2c_gsbi3.dev.platform_data =
+					&msm8960_i2c_qup_gsbi3_pdata;
+
+	msm8960_device_qup_i2c_gsbi10.dev.platform_data =
+					&msm8960_i2c_qup_gsbi10_pdata;
+
+	msm8960_device_qup_i2c_gsbi12.dev.platform_data =
+					&msm8960_i2c_qup_gsbi12_pdata;
+}
+
+static void __init msm8960_gfx_init(void)
+{
+	uint32_t soc_platform_version = socinfo_get_version();
+	if (SOCINFO_VERSION_MAJOR(soc_platform_version) == 1) {
+		struct kgsl_device_platform_data *kgsl_3d0_pdata =
+				msm_kgsl_3d0.dev.platform_data;
+		kgsl_3d0_pdata->pwrlevel[0].gpu_freq = 320000000;
+		kgsl_3d0_pdata->pwrlevel[1].gpu_freq = 266667000;
+	}
+}
+
+static struct msm_rpmrs_level msm_rpmrs_levels[] = {
+	{
+		MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT,
+		MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
+		true,
+		1, 784, 180000, 100,
+	},
+
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
+		MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
+		true,
+		1300, 228, 1200000, 2000,
+	},
+
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+		MSM_RPMRS_LIMITS(ON, GDHS, MAX, ACTIVE),
+		false,
+		2000, 138, 1208400, 3200,
+	},
+
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+		MSM_RPMRS_LIMITS(ON, HSFS_OPEN, ACTIVE, RET_HIGH),
+		false,
+		6000, 119, 1850300, 9000,
+	},
+
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+		MSM_RPMRS_LIMITS(OFF, GDHS, MAX, ACTIVE),
+		false,
+		9200, 68, 2839200, 16400,
+	},
+
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, MAX, ACTIVE),
+		false,
+		10300, 63, 3128000, 18200,
+	},
+
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, ACTIVE, RET_HIGH),
+		false,
+		18000, 10, 4602600, 27000,
+	},
+
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, RET_HIGH, RET_LOW),
+		false,
+		20000, 2, 5752000, 32000,
+	},
+};
+
+static struct msm_rpmrs_platform_data msm_rpmrs_data __initdata = {
+	.levels = &msm_rpmrs_levels[0],
+	.num_levels = ARRAY_SIZE(msm_rpmrs_levels),
+	.vdd_mem_levels  = {
+		[MSM_RPMRS_VDD_MEM_RET_LOW]	= 750000,
+		[MSM_RPMRS_VDD_MEM_RET_HIGH]	= 750000,
+		[MSM_RPMRS_VDD_MEM_ACTIVE]	= 1050000,
+		[MSM_RPMRS_VDD_MEM_MAX]		= 1150000,
+	},
+	.vdd_dig_levels = {
+		[MSM_RPMRS_VDD_DIG_RET_LOW]	= 500000,
+		[MSM_RPMRS_VDD_DIG_RET_HIGH]	= 750000,
+		[MSM_RPMRS_VDD_DIG_ACTIVE]	= 950000,
+		[MSM_RPMRS_VDD_DIG_MAX]		= 1150000,
+	},
+	.vdd_mask = 0x7FFFFF,
+	.rpmrs_target_id = {
+		[MSM_RPMRS_ID_PXO_CLK]		= MSM_RPM_ID_PXO_CLK,
+		[MSM_RPMRS_ID_L2_CACHE_CTL]	= MSM_RPM_ID_LAST,
+		[MSM_RPMRS_ID_VDD_DIG_0]	= MSM_RPM_ID_PM8921_S3_0,
+		[MSM_RPMRS_ID_VDD_DIG_1]	= MSM_RPM_ID_PM8921_S3_1,
+		[MSM_RPMRS_ID_VDD_MEM_0]	= MSM_RPM_ID_PM8921_L24_0,
+		[MSM_RPMRS_ID_VDD_MEM_1]	= MSM_RPM_ID_PM8921_L24_1,
+		[MSM_RPMRS_ID_RPM_CTL]		= MSM_RPM_ID_RPM_CTL,
+	},
+};
+
+static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_TZ,
+};
+
+#ifdef CONFIG_I2C
+#define I2C_SURF 1
+#define I2C_FFA  (1 << 1)
+#define I2C_RUMI (1 << 2)
+#define I2C_SIM  (1 << 3)
+#define I2C_FLUID (1 << 4)
+#define I2C_LIQUID (1 << 5)
+
+struct i2c_registry {
+	u8                     machs;
+	int                    bus;
+	struct i2c_board_info *info;
+	int                    len;
+};
+
+/* Sensors DSPS platform data */
+#ifdef CONFIG_MSM_DSPS
+#define DSPS_PIL_GENERIC_NAME		"dsps"
+#endif /* CONFIG_MSM_DSPS */
+
+static void __init msm8960_init_dsps(void)
+{
+#ifdef CONFIG_MSM_DSPS
+	struct msm_dsps_platform_data *pdata =
+		msm_dsps_device.dev.platform_data;
+	pdata->pil_name = DSPS_PIL_GENERIC_NAME;
+	pdata->gpios = NULL;
+	pdata->gpios_num = 0;
+
+	platform_device_register(&msm_dsps_device);
+#endif /* CONFIG_MSM_DSPS */
+}
+
+static int hsic_peripheral_status = 1;
+static DEFINE_MUTEX(hsic_status_lock);
+
+void peripheral_connect()
+{
+	mutex_lock(&hsic_status_lock);
+	if (hsic_peripheral_status)
+		goto out;
+	platform_device_add(&msm_device_hsic_host);
+	hsic_peripheral_status = 1;
+out:
+	mutex_unlock(&hsic_status_lock);
+}
+EXPORT_SYMBOL(peripheral_connect);
+
+void peripheral_disconnect()
+{
+	mutex_lock(&hsic_status_lock);
+	if (!hsic_peripheral_status)
+		goto out;
+	platform_device_del(&msm_device_hsic_host);
+	hsic_peripheral_status = 0;
+out:
+	mutex_unlock(&hsic_status_lock);
+}
+EXPORT_SYMBOL(peripheral_disconnect);
+
+static void __init msm8960_init_smsc_hub(void)
+{
+	uint32_t version = socinfo_get_version();
+
+	if (SOCINFO_VERSION_MAJOR(version) == 1)
+		return;
+
+	if (machine_is_msm8960_liquid())
+		platform_device_register(&smsc_hub_device);
+}
+
+static void __init msm8960_init_hsic(void)
+{
+#ifdef CONFIG_USB_EHCI_MSM_HSIC
+	uint32_t version = socinfo_get_version();
+
+	if (SOCINFO_VERSION_MAJOR(version) == 1)
+		return;
+
+	if (machine_is_msm8960_liquid())
+		platform_device_register(&msm_device_hsic_host);
+#endif
+}
+
+#ifdef CONFIG_ISL9519_CHARGER
+static struct isl_platform_data isl_data __initdata = {
+	.valid_n_gpio		= 0,	/* Not required when notify-by-pmic */
+	.chg_detection_config	= NULL,	/* Not required when notify-by-pmic */
+	.max_system_voltage	= 4200,
+	.min_system_voltage	= 3200,
+	.chgcurrent		= 1900,
+	.term_current		= 0,
+	.input_current		= 2048,
+};
+
+static struct i2c_board_info isl_charger_i2c_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("isl9519q", 0x9),
+		.irq		= 0,	/* Not required when notify-by-pmic */
+		.platform_data	= &isl_data,
+	},
+};
+#endif /* CONFIG_ISL9519_CHARGER */
+
+static struct i2c_board_info liquid_io_expander_i2c_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("sx1508q", 0x20),
+		.platform_data = &msm8960_sx150x_data[SX150X_LIQUID]
+	},
+};
+
+static struct i2c_registry msm8960_i2c_devices[] __initdata = {
+#ifdef CONFIG_ISL9519_CHARGER
+	{
+		I2C_LIQUID,
+		MSM_8960_GSBI10_QUP_I2C_BUS_ID,
+		isl_charger_i2c_info,
+		ARRAY_SIZE(isl_charger_i2c_info),
+	},
+#endif /* CONFIG_ISL9519_CHARGER */
+	{
+		I2C_SURF | I2C_FFA | I2C_FLUID,
+		MSM_8960_GSBI3_QUP_I2C_BUS_ID,
+		cyttsp_info,
+		ARRAY_SIZE(cyttsp_info),
+	},
+	{
+		I2C_LIQUID,
+		MSM_8960_GSBI3_QUP_I2C_BUS_ID,
+		mxt_device_info,
+		ARRAY_SIZE(mxt_device_info),
+	},
+	{
+		I2C_SURF | I2C_FFA | I2C_LIQUID,
+		MSM_8960_GSBI10_QUP_I2C_BUS_ID,
+		sii_device_info,
+		ARRAY_SIZE(sii_device_info),
+	},
+	{
+		I2C_LIQUID,
+		MSM_8960_GSBI10_QUP_I2C_BUS_ID,
+		msm_isa1200_board_info,
+		ARRAY_SIZE(msm_isa1200_board_info),
+	},
+	{
+		I2C_LIQUID,
+		MSM_8960_GSBI10_QUP_I2C_BUS_ID,
+		liquid_io_expander_i2c_info,
+		ARRAY_SIZE(liquid_io_expander_i2c_info),
+	},
+};
+#endif /* CONFIG_I2C */
+
+static void __init register_i2c_devices(void)
+{
+#ifdef CONFIG_I2C
+	u8 mach_mask = 0;
+	int i;
+#ifdef CONFIG_MSM_CAMERA
+	struct i2c_registry msm8960_camera_i2c_devices = {
+		I2C_SURF | I2C_FFA | I2C_FLUID | I2C_LIQUID | I2C_RUMI,
+		MSM_8960_GSBI4_QUP_I2C_BUS_ID,
+		msm8960_camera_board_info.board_info,
+		msm8960_camera_board_info.num_i2c_board_info,
+	};
+#endif
+
+	/* Build the matching 'supported_machs' bitmask */
+	if (machine_is_msm8960_cdp())
+		mach_mask = I2C_SURF;
+	else if (machine_is_msm8960_rumi3())
+		mach_mask = I2C_RUMI;
+	else if (machine_is_msm8960_sim())
+		mach_mask = I2C_SIM;
+	else if (machine_is_msm8960_fluid())
+		mach_mask = I2C_FLUID;
+	else if (machine_is_msm8960_liquid())
+		mach_mask = I2C_LIQUID;
+	else if (machine_is_msm8960_mtp())
+		mach_mask = I2C_FFA;
+	else
+		pr_err("unmatched machine ID in register_i2c_devices\n");
+
+	if (machine_is_msm8960_liquid()) {
+		if (SOCINFO_VERSION_MAJOR(socinfo_get_platform_version()) == 3)
+			mxt_device_info[0].platform_data =
+						&mxt_platform_data_3d;
+		else
+			mxt_device_info[0].platform_data =
+						&mxt_platform_data_2d;
+	}
+
+	/* Run the array and install devices as appropriate */
+	for (i = 0; i < ARRAY_SIZE(msm8960_i2c_devices); ++i) {
+		if (msm8960_i2c_devices[i].machs & mach_mask)
+			i2c_register_board_info(msm8960_i2c_devices[i].bus,
+						msm8960_i2c_devices[i].info,
+						msm8960_i2c_devices[i].len);
+	}
+#ifdef CONFIG_MSM_CAMERA
+	if (msm8960_camera_i2c_devices.machs & mach_mask)
+		i2c_register_board_info(msm8960_camera_i2c_devices.bus,
+			msm8960_camera_i2c_devices.info,
+			msm8960_camera_i2c_devices.len);
+#endif
+#endif
+}
+
+static void __init msm8960_sim_init(void)
+{
+	struct msm_watchdog_pdata *wdog_pdata = (struct msm_watchdog_pdata *)
+		&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();
+	platform_device_register(&msm8960_device_rpm_regulator);
+	msm_clock_init(&msm8960_clock_init_data);
+	msm8960_init_pmic();
+
+	msm8960_device_otg.dev.platform_data = &msm_otg_pdata;
+	msm8960_init_gpiomux();
+	msm8960_i2c_init();
+	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
+	msm_spm_l2_init(msm_spm_l2_data);
+	msm8960_init_buses();
+	platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
+	msm8960_pm8921_gpio_mpp_init();
+	platform_add_devices(sim_devices, ARRAY_SIZE(sim_devices));
+	acpuclk_init(&acpuclk_8960_soc_data);
+
+	msm8960_device_qup_spi_gsbi1.dev.platform_data =
+				&msm8960_qup_spi_gsbi1_pdata;
+	spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
+
+	msm8960_init_mmc();
+	msm8960_init_fb();
+	slim_register_board_info(msm_slim_devices,
+		ARRAY_SIZE(msm_slim_devices));
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+	msm_pm_init_sleep_status_data(&msm_pm_slp_sts_data);
+}
+
+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();
+	platform_device_register(&msm8960_device_rpm_regulator);
+	msm8960_init_gpiomux();
+	msm8960_init_pmic();
+	msm8960_device_qup_spi_gsbi1.dev.platform_data =
+				&msm8960_qup_spi_gsbi1_pdata;
+	spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
+	msm8960_i2c_init();
+	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
+	msm_spm_l2_init(msm_spm_l2_data);
+	platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
+	msm8960_pm8921_gpio_mpp_init();
+	platform_add_devices(rumi3_devices, ARRAY_SIZE(rumi3_devices));
+	msm8960_init_mmc();
+	register_i2c_devices();
+
+
+	msm8960_init_fb();
+	slim_register_board_info(msm_slim_devices,
+		ARRAY_SIZE(msm_slim_devices));
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+	msm_pm_init_sleep_status_data(&msm_pm_slp_sts_data);
+}
+
+static void __init msm8960_cdp_init(void)
+{
+	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));
+
+	regulator_suppress_info_printing();
+	if (msm_xo_init())
+		pr_err("Failed to initialize XO votes\n");
+	platform_device_register(&msm8960_device_rpm_regulator);
+	msm_clock_init(&msm8960_clock_init_data);
+	if (machine_is_msm8960_liquid())
+		msm_otg_pdata.mhl_enable = true;
+	msm8960_device_otg.dev.platform_data = &msm_otg_pdata;
+	if (machine_is_msm8960_mtp() || machine_is_msm8960_fluid() ||
+		machine_is_msm8960_cdp()) {
+		msm_otg_pdata.phy_init_seq = wr_phy_init_seq;
+	} else if (machine_is_msm8960_liquid()) {
+			msm_otg_pdata.phy_init_seq =
+				liquid_v1_phy_init_seq;
+	}
+	android_usb_pdata.swfi_latency =
+		msm_rpmrs_levels[0].latency_us;
+	msm_device_hsic_host.dev.platform_data = &msm_hsic_pdata;
+	if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2 &&
+					machine_is_msm8960_liquid())
+		msm_device_hsic_host.dev.parent = &smsc_hub_device.dev;
+	msm8960_init_gpiomux();
+	msm8960_device_qup_spi_gsbi1.dev.platform_data =
+				&msm8960_qup_spi_gsbi1_pdata;
+	spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
+
+	msm8960_init_pmic();
+	if ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2 &&
+		(machine_is_msm8960_mtp())) || machine_is_msm8960_liquid())
+		msm_isa1200_board_info[0].platform_data = &isa1200_1_pdata;
+	msm8960_i2c_init();
+	msm8960_gfx_init();
+	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
+	msm_spm_l2_init(msm_spm_l2_data);
+	msm8960_init_buses();
+	platform_add_devices(msm8960_footswitch, msm8960_num_footswitch);
+	if (machine_is_msm8960_liquid())
+		platform_device_register(&msm8960_device_ext_3p3v_vreg);
+	if (machine_is_msm8960_cdp())
+		platform_device_register(&msm8960_device_ext_l2_vreg);
+
+	if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE)
+		platform_device_register(&msm8960_device_uart_gsbi8);
+	else
+		platform_device_register(&msm8960_device_uart_gsbi5);
+
+	/* For 8960 Fusion 2.2 Primary IPC */
+	if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
+		msm_uart_dm9_pdata.wakeup_irq = gpio_to_irq(94); /* GSBI9(2) */
+		msm_device_uart_dm9.dev.platform_data = &msm_uart_dm9_pdata;
+	}
+
+	platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
+	msm8960_pm8921_gpio_mpp_init();
+	platform_add_devices(cdp_devices, ARRAY_SIZE(cdp_devices));
+	msm8960_init_smsc_hub();
+	msm8960_init_hsic();
+#ifdef CONFIG_MSM_CAMERA
+	msm8960_init_cam();
+#endif
+	msm8960_init_mmc();
+	acpuclk_init(&acpuclk_8960_soc_data);
+	if (machine_is_msm8960_liquid())
+		mxt_init_hw_liquid();
+	register_i2c_devices();
+	msm8960_init_fb();
+	slim_register_board_info(msm_slim_devices,
+		ARRAY_SIZE(msm_slim_devices));
+	msm8960_init_dsps();
+	change_memory_power = &msm8960_change_memory_power;
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+	msm_pm_init_sleep_status_data(&msm_pm_slp_sts_data);
+	if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
+		mdm_sglte_device.dev.platform_data = &sglte_platform_data;
+		platform_device_register(&mdm_sglte_device);
+	}
+}
+
+MACHINE_START(MSM8960_SIM, "QCT MSM8960 SIMULATOR")
+	.map_io = msm8960_map_io,
+	.reserve = msm8960_reserve,
+	.init_irq = msm8960_init_irq,
+	.handle_irq = gic_handle_irq,
+	.timer = &msm_timer,
+	.init_machine = msm8960_sim_init,
+	.init_early = msm8960_allocate_memory_regions,
+	.init_very_early = msm8960_early_memory,
+MACHINE_END
+
+MACHINE_START(MSM8960_RUMI3, "QCT MSM8960 RUMI3")
+	.map_io = msm8960_map_io,
+	.reserve = msm8960_reserve,
+	.init_irq = msm8960_init_irq,
+	.handle_irq = gic_handle_irq,
+	.timer = &msm_timer,
+	.init_machine = msm8960_rumi3_init,
+	.init_early = msm8960_allocate_memory_regions,
+	.init_very_early = msm8960_early_memory,
+MACHINE_END
+
+MACHINE_START(MSM8960_CDP, "QCT MSM8960 CDP")
+	.map_io = msm8960_map_io,
+	.reserve = msm8960_reserve,
+	.init_irq = msm8960_init_irq,
+	.handle_irq = gic_handle_irq,
+	.timer = &msm_timer,
+	.init_machine = msm8960_cdp_init,
+	.init_early = msm8960_allocate_memory_regions,
+	.init_very_early = msm8960_early_memory,
+MACHINE_END
+
+MACHINE_START(MSM8960_MTP, "QCT MSM8960 MTP")
+	.map_io = msm8960_map_io,
+	.reserve = msm8960_reserve,
+	.init_irq = msm8960_init_irq,
+	.handle_irq = gic_handle_irq,
+	.timer = &msm_timer,
+	.init_machine = msm8960_cdp_init,
+	.init_early = msm8960_allocate_memory_regions,
+	.init_very_early = msm8960_early_memory,
+MACHINE_END
+
+MACHINE_START(MSM8960_FLUID, "QCT MSM8960 FLUID")
+	.map_io = msm8960_map_io,
+	.reserve = msm8960_reserve,
+	.init_irq = msm8960_init_irq,
+	.handle_irq = gic_handle_irq,
+	.timer = &msm_timer,
+	.init_machine = msm8960_cdp_init,
+	.init_early = msm8960_allocate_memory_regions,
+	.init_very_early = msm8960_early_memory,
+MACHINE_END
+
+MACHINE_START(MSM8960_LIQUID, "QCT MSM8960 LIQUID")
+	.map_io = msm8960_map_io,
+	.reserve = msm8960_reserve,
+	.init_irq = msm8960_init_irq,
+	.handle_irq = gic_handle_irq,
+	.timer = &msm_timer,
+	.init_machine = msm8960_cdp_init,
+	.init_early = msm8960_allocate_memory_regions,
+	.init_very_early = msm8960_early_memory,
+MACHINE_END
diff --git a/arch/arm/mach-msm/board-8960.h b/arch/arm/mach-msm/board-8960.h
new file mode 100644
index 0000000..d986670
--- /dev/null
+++ b/arch/arm/mach-msm/board-8960.h
@@ -0,0 +1,94 @@
+/* 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 __ARCH_ARM_MACH_MSM_BOARD_MSM8960_H
+#define __ARCH_ARM_MACH_MSM_BOARD_MSM8960_H
+
+#include <linux/regulator/msm-gpio-regulator.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/i2c.h>
+#include <linux/i2c/sx150x.h>
+#include <mach/irqs.h>
+#include <mach/rpm-regulator.h>
+#include <mach/msm_memtypes.h>
+#include <mach/msm_rtb.h>
+#include <mach/msm_cache_dump.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)
+#define PM8921_MPP_BASE			(PM8921_GPIO_BASE + PM8921_NR_GPIOS)
+#define PM8921_MPP_PM_TO_SYS(pm_gpio)	(pm_gpio - 1 + PM8921_MPP_BASE)
+#define PM8921_IRQ_BASE			(NR_MSM_IRQS + NR_GPIO_IRQS)
+
+extern struct pm8xxx_regulator_platform_data
+	msm_pm8921_regulator_pdata[] __devinitdata;
+
+extern int msm_pm8921_regulator_pdata_len __devinitdata;
+
+#define GPIO_VREG_ID_EXT_5V		0
+#define GPIO_VREG_ID_EXT_L2		1
+#define GPIO_VREG_ID_EXT_3P3V		2
+#define GPIO_VREG_ID_EXT_OTG_SW		3
+
+extern struct gpio_regulator_platform_data
+	msm_gpio_regulator_pdata[] __devinitdata;
+
+extern struct regulator_init_data msm_saw_regulator_pdata_s5;
+extern struct regulator_init_data msm_saw_regulator_pdata_s6;
+
+extern struct rpm_regulator_platform_data msm_rpm_regulator_pdata __devinitdata;
+
+#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
+enum {
+	GPIO_EXPANDER_IRQ_BASE = (PM8921_IRQ_BASE + PM8921_NR_IRQS),
+	GPIO_EXPANDER_GPIO_BASE = (PM8921_MPP_BASE + PM8921_NR_MPPS),
+	/* CAM Expander */
+	GPIO_CAM_EXPANDER_BASE = GPIO_EXPANDER_GPIO_BASE,
+	GPIO_CAM_GP_STROBE_READY = GPIO_CAM_EXPANDER_BASE,
+	GPIO_CAM_GP_AFBUSY,
+	GPIO_CAM_GP_STROBE_CE,
+	GPIO_CAM_GP_CAM1MP_XCLR,
+	GPIO_CAM_GP_CAMIF_RESET_N,
+	GPIO_CAM_GP_XMT_FLASH_INT,
+	GPIO_CAM_GP_LED_EN1,
+	GPIO_CAM_GP_LED_EN2,
+	GPIO_LIQUID_EXPANDER_BASE = GPIO_CAM_EXPANDER_BASE + 8,
+};
+#endif
+
+enum {
+	SX150X_CAM,
+	SX150X_LIQUID,
+};
+
+#endif
+
+extern struct sx150x_platform_data msm8960_sx150x_data[];
+extern struct msm_camera_board_info msm8960_camera_board_info;
+
+void msm8960_init_cam(void);
+void msm8960_init_fb(void);
+void msm8960_init_pmic(void);
+void msm8960_init_mmc(void);
+int msm8960_init_gpiomux(void);
+unsigned char msm8960_hdmi_as_primary_selected(void);
+void msm8960_allocate_fb_region(void);
+void msm8960_set_display_params(char *prim_panel, char *ext_panel);
+void msm8960_pm8921_gpio_mpp_init(void);
+void msm8960_mdp_writeback(struct memtype_reserve *reserve_table);
+#define MSM_8960_GSBI4_QUP_I2C_BUS_ID 4
+#define MSM_8960_GSBI3_QUP_I2C_BUS_ID 3
+#define MSM_8960_GSBI10_QUP_I2C_BUS_ID 10
+
+extern struct msm_rtb_platform_data msm8960_rtb_pdata;
+extern struct msm_cache_dump_platform_data msm8960_cache_dump_pdata;
diff --git a/arch/arm/mach-msm/board-9615-display.c b/arch/arm/mach-msm/board-9615-display.c
new file mode 100644
index 0000000..74bc984
--- /dev/null
+++ b/arch/arm/mach-msm/board-9615-display.c
@@ -0,0 +1,169 @@
+/* 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 <linux/ion.h>
+#include <asm/mach-types.h>
+#include <mach/msm_memtypes.h>
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/gpiomux.h>
+#include <mach/ion.h>
+#include <mach/msm_bus_board.h>
+
+#include "devices.h"
+#include "board-9615.h"
+
+/* prim = 240 x 320 x 4(bpp) x 2(pages) */
+#define MSM_FB_PRIM_BUF_SIZE roundup(240 * 320 * 4 * 2, 0x10000)
+#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE, 4096)
+
+#define GPIO_PIN_EBI2_LCD_A_D	21
+#define GPIO_PIN_EBI2_LCD_CS	22
+#define GPIO_PIN_EBI2_LCD_RS	24
+
+
+#ifdef CONFIG_FB_MSM
+
+static struct resource msm_fb_resources[] = {
+	{
+		.flags = IORESOURCE_MEM,
+	}
+};
+
+static int msm_fb_detect_panel(const char *name)
+{
+	return 0;
+}
+
+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 mdm9615_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));
+}
+
+
+static bool ebi2_power_init;
+static int ebi2_panel_power(int on)
+{
+	static struct regulator *panel_power;
+	int rc;
+
+	pr_debug("%s: on=%d\n", __func__, on);
+
+	if (!ebi2_power_init) {
+		panel_power = regulator_get(&msm_ebi2_lcdc_device.dev,
+				"VDDI2");
+		if (IS_ERR_OR_NULL(panel_power)) {
+			pr_err("could not get L14, rc = %ld\n",
+				PTR_ERR(panel_power));
+			return -ENODEV;
+		}
+
+		rc = regulator_set_voltage(panel_power, 2800000, 3800000);
+		if (rc) {
+			pr_err("set_voltage L14 failed, rc=%d\n", rc);
+			return -EINVAL;
+		}
+
+		ebi2_power_init = true;
+	}
+
+	if (on) {
+		rc = regulator_enable(panel_power);
+		if (rc) {
+			pr_err("enable L14 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+		rc = gpio_request(GPIO_PIN_EBI2_LCD_A_D, "disp_a_d");
+		if (rc) {
+			pr_err("request gpio EBI2_LCD_A_D failed, rc=%d\n", rc);
+			goto error1;
+		}
+		rc = gpio_request(GPIO_PIN_EBI2_LCD_CS, "disp_cs");
+		if (rc) {
+			pr_err("request gpio EBI2_LCD_CS failed, rc=%d\n", rc);
+			goto error2;
+		}
+		rc = gpio_request(GPIO_PIN_EBI2_LCD_RS, "disp_rs");
+		if (rc) {
+			pr_err("request gpio EBI2_LCD_RS failed, rc=%d\n", rc);
+			goto error3;
+		}
+	} else {
+		gpio_free(GPIO_PIN_EBI2_LCD_RS);
+		gpio_free(GPIO_PIN_EBI2_LCD_CS);
+		gpio_free(GPIO_PIN_EBI2_LCD_A_D);
+
+		rc = regulator_disable(panel_power);
+		if (rc) {
+			pr_err("disable L14 failed, rc=%d\n", rc);
+			return -ENODEV;
+		}
+	}
+
+	return 0;
+error3:
+	gpio_free(GPIO_PIN_EBI2_LCD_CS);
+error2:
+	gpio_free(GPIO_PIN_EBI2_LCD_A_D);
+error1:
+	regulator_disable(panel_power);
+	return rc;
+
+}
+
+static struct lcdc_platform_data ebi2_lcdc_pdata = {
+	.lcdc_power_save = ebi2_panel_power,
+};
+
+static struct lvds_panel_platform_data ebi2_epson_s1d_pdata;
+
+static struct platform_device ebi2_epson_s1d_panel_device = {
+	.name = "ebi2_epson_s1d_qvga",
+	.id = 0,
+	.dev = {
+		.platform_data = &ebi2_epson_s1d_pdata,
+	}
+};
+
+void __init mdm9615_init_fb(void)
+{
+	platform_device_register(&msm_fb_device);
+	platform_device_register(&ebi2_epson_s1d_panel_device);
+
+	msm_fb_register_device("ebi2_lcd", &ebi2_lcdc_pdata);
+}
+#endif
diff --git a/arch/arm/mach-msm/board-9615-gpiomux.c b/arch/arm/mach-msm/board-9615-gpiomux.c
new file mode 100644
index 0000000..47a9835
--- /dev/null
+++ b/arch/arm/mach-msm/board-9615-gpiomux.c
@@ -0,0 +1,370 @@
+/* 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
+ * 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/gpio.h>
+#include <mach/gpiomux.h>
+#include <mach/board.h>
+#include "board-9615.h"
+
+static struct gpiomux_setting ps_hold = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting slimbus = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_KEEPER,
+};
+
+static struct gpiomux_setting gsbi4 = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi5 = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi3 = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi3_cs1_config = {
+	.func = GPIOMUX_FUNC_4,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+#ifdef CONFIG_LTC4088_CHARGER
+static struct gpiomux_setting ltc4088_chg_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+#endif
+
+static struct gpiomux_setting sdcc2_clk_actv_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_16MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting sdcc2_cmd_data_0_3_actv_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting sdcc2_suspend_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting cdc_mclk = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+#ifdef CONFIG_FB_MSM_EBI2
+static struct gpiomux_setting ebi2_lcdc_a_d = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_12MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting ebi2_lcdc_cs = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_12MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting ebi2_lcdc_rs = {
+	.func = GPIOMUX_FUNC_3,
+	.drv = GPIOMUX_DRV_12MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+#endif
+
+static struct gpiomux_setting wlan_active_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_OUT_LOW,
+};
+
+static struct gpiomux_setting wlan_suspend_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_IN,
+};
+
+static struct msm_gpiomux_config msm9615_audio_codec_configs[] __initdata = {
+	{
+		.gpio = 24,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &cdc_mclk,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm9615_sdcc2_configs[] __initdata = {
+	{
+		/* SDC2_DATA_0 */
+		.gpio      = 25,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_cmd_data_0_3_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+		},
+	},
+	{
+		/* SDC2_DATA_1 */
+		.gpio      = 26,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_cmd_data_0_3_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_cmd_data_0_3_actv_cfg,
+		},
+	},
+	{
+		/* SDC2_DATA_2 */
+		.gpio      = 27,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_cmd_data_0_3_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+		},
+	},
+	{
+		/* SDC2_DATA_3 */
+		.gpio      = 28,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_cmd_data_0_3_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+		},
+	},
+	{
+		/* SDC2_CMD */
+		.gpio      = 29,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_cmd_data_0_3_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+		},
+	},
+	{
+		/* SDC2_CLK */
+		.gpio      = 30,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_clk_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+		},
+	},
+};
+
+struct msm_gpiomux_config msm9615_ps_hold_config[] __initdata = {
+	{
+		.gpio = 83,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ps_hold,
+		},
+	},
+};
+
+#ifdef CONFIG_LTC4088_CHARGER
+static struct msm_gpiomux_config
+	msm9615_ltc4088_charger_config[] __initdata = {
+	{
+		.gpio = 4,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ltc4088_chg_cfg,
+		},
+	},
+	{
+		.gpio = 6,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ltc4088_chg_cfg,
+		},
+	},
+	{
+		.gpio = 7,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ltc4088_chg_cfg,
+		},
+	},
+};
+#endif
+
+struct msm_gpiomux_config msm9615_gsbi_configs[] __initdata = {
+	{
+		.gpio      = 8,		/* GSBI3 QUP SPI_CLK */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi3,
+		},
+	},
+	{
+		.gpio      = 9,		/* GSBI3 QUP SPI_CS_N */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi3,
+		},
+	},
+	{
+		.gpio      = 10,	/* GSBI3 QUP SPI_DATA_MISO */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi3,
+		},
+	},
+	{
+		.gpio      = 11,	/* GSBI3 QUP SPI_DATA_MOSI */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi3,
+		},
+	},
+	{
+		.gpio      = 12,	/* GSBI4 UART */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi4,
+		},
+	},
+	{
+		.gpio      = 13,	/* GSBI4 UART */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi4,
+		},
+	},
+	{
+		.gpio      = 14,	/* GSBI4 UART */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi4,
+		},
+	},
+	{
+		.gpio      = 15,	/* GSBI4 UART */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi4,
+		},
+	},
+	{
+		.gpio      = 16,	/* GSBI5 I2C QUP SCL */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi5,
+			[GPIOMUX_ACTIVE] = &gsbi5,
+		},
+	},
+	{
+		.gpio      = 17,	/* GSBI5 I2C QUP SDA */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi5,
+		},
+	},
+	{
+		/* GPIO 19 can be used for I2C/UART on GSBI5 */
+		.gpio      = 19,	/* GSBI3 QUP SPI_CS_1 */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi3_cs1_config,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm9615_slimbus_configs[] __initdata = {
+	{
+		.gpio      = 20,	/* Slimbus data */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &slimbus,
+		},
+	},
+	{
+		.gpio      = 23,	/* Slimbus clk */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &slimbus,
+		},
+	},
+};
+
+#ifdef CONFIG_FB_MSM_EBI2
+static struct msm_gpiomux_config msm9615_ebi2_lcdc_configs[] __initdata = {
+	{
+		.gpio      = 21,	/* a_d */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_lcdc_a_d,
+		},
+	},
+	{
+		.gpio      = 22,	/* cs */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_lcdc_cs,
+		},
+	},
+	{
+		.gpio      = 24,	/* rs */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_lcdc_rs,
+		},
+	},
+};
+#endif
+
+static struct msm_gpiomux_config msm9615_wlan_configs[] __initdata = {
+	{
+		.gpio      = 21,/* WLAN_RESET_N */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &wlan_active_config,
+			[GPIOMUX_SUSPENDED] = &wlan_suspend_config,
+		},
+	},
+};
+
+
+int __init msm9615_init_gpiomux(void)
+{
+	int rc;
+
+	rc = msm_gpiomux_init(NR_GPIO_IRQS);
+	if (rc) {
+		pr_err(KERN_ERR "msm_gpiomux_init failed %d\n", rc);
+		return rc;
+	}
+	msm_gpiomux_install(msm9615_gsbi_configs,
+			ARRAY_SIZE(msm9615_gsbi_configs));
+
+	msm_gpiomux_install(msm9615_slimbus_configs,
+			ARRAY_SIZE(msm9615_slimbus_configs));
+
+	msm_gpiomux_install(msm9615_ps_hold_config,
+			ARRAY_SIZE(msm9615_ps_hold_config));
+	msm_gpiomux_install(msm9615_sdcc2_configs,
+			ARRAY_SIZE(msm9615_sdcc2_configs));
+#ifdef CONFIG_LTC4088_CHARGER
+	msm_gpiomux_install(msm9615_ltc4088_charger_config,
+			ARRAY_SIZE(msm9615_ltc4088_charger_config));
+#endif
+	msm_gpiomux_install(msm9615_audio_codec_configs,
+			ARRAY_SIZE(msm9615_audio_codec_configs));
+
+	msm_gpiomux_install(msm9615_wlan_configs,
+			ARRAY_SIZE(msm9615_wlan_configs));
+
+#ifdef CONFIG_FB_MSM_EBI2
+	msm_gpiomux_install(msm9615_ebi2_lcdc_configs,
+			ARRAY_SIZE(msm9615_ebi2_lcdc_configs));
+#endif
+
+	return 0;
+}
diff --git a/arch/arm/mach-msm/board-9615-regulator.c b/arch/arm/mach-msm/board-9615-regulator.c
new file mode 100644
index 0000000..7ed350d
--- /dev/null
+++ b/arch/arm/mach-msm/board-9615-regulator.c
@@ -0,0 +1,346 @@
+/*
+ * 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
+ * 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/regulator/pm8xxx-regulator.h>
+#include <linux/regulator/msm-gpio-regulator.h>
+#include <mach/rpm-regulator.h>
+
+#include "board-9615.h"
+
+#define VREG_CONSUMERS(_id) \
+	static struct regulator_consumer_supply vreg_consumers_##_id[]
+
+/*
+ * Consumer specific regulator names:
+ *			 regulator name		consumer dev_name
+ */
+VREG_CONSUMERS(L2) = {
+	REGULATOR_SUPPLY("8018_l2",		NULL),
+	REGULATOR_SUPPLY("HSUSB_1p8",		"msm_otg"),
+};
+VREG_CONSUMERS(L3) = {
+	REGULATOR_SUPPLY("8018_l3",		NULL),
+};
+VREG_CONSUMERS(L4) = {
+	REGULATOR_SUPPLY("8018_l4",		NULL),
+	REGULATOR_SUPPLY("HSUSB_3p3",		"msm_otg"),
+};
+VREG_CONSUMERS(L5) = {
+	REGULATOR_SUPPLY("8018_l5",		NULL),
+};
+VREG_CONSUMERS(L6) = {
+	REGULATOR_SUPPLY("8018_l6",		NULL),
+};
+VREG_CONSUMERS(L7) = {
+	REGULATOR_SUPPLY("8018_l7",		NULL),
+};
+VREG_CONSUMERS(L8) = {
+	REGULATOR_SUPPLY("8018_l8",		NULL),
+};
+VREG_CONSUMERS(L9) = {
+	REGULATOR_SUPPLY("8018_l9",		NULL),
+};
+VREG_CONSUMERS(L10) = {
+	REGULATOR_SUPPLY("8018_l10",		NULL),
+};
+VREG_CONSUMERS(L11) = {
+	REGULATOR_SUPPLY("8018_l11",		NULL),
+};
+VREG_CONSUMERS(L12) = {
+	REGULATOR_SUPPLY("8018_l12",		NULL),
+};
+VREG_CONSUMERS(L13) = {
+	REGULATOR_SUPPLY("8018_l13",		NULL),
+	REGULATOR_SUPPLY("sdc_vddp",		"msm_sdcc.1"),
+};
+VREG_CONSUMERS(L14) = {
+	REGULATOR_SUPPLY("8018_l14",		NULL),
+	REGULATOR_SUPPLY("VDDI2",		"ebi2_lcd.0"),
+};
+VREG_CONSUMERS(S1) = {
+	REGULATOR_SUPPLY("8018_s1",		NULL),
+	REGULATOR_SUPPLY("HSUSB_VDDCX",		"msm_otg"),
+	REGULATOR_SUPPLY("HSIC_VDDCX",		"msm_hsic_peripheral"),
+	REGULATOR_SUPPLY("HSIC_VDDCX",		"msm_hsic_host"),
+};
+VREG_CONSUMERS(S2) = {
+	REGULATOR_SUPPLY("8018_s2",		NULL),
+	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",	"tabla-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",	"tabla2x-slim"),
+	REGULATOR_SUPPLY("VDDD_CDC_D",		"tabla-slim"),
+	REGULATOR_SUPPLY("VDDD_CDC_D",		"tabla2x-slim"),
+	REGULATOR_SUPPLY("VDDD_CDC_D",          "0-000d"),
+	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",     "0-000d"),
+	REGULATOR_SUPPLY("VDDD_CDC_D",		"tabla top level"),
+	REGULATOR_SUPPLY("CDC_VDDA_A_1P2V",	"tabla top level"),
+};
+VREG_CONSUMERS(S3) = {
+	REGULATOR_SUPPLY("8018_s3",		NULL),
+	REGULATOR_SUPPLY("wlan_vreg",		"wlan_ar6000_pm_dev"),
+	REGULATOR_SUPPLY("CDC_VDD_CP",		"tabla-slim"),
+	REGULATOR_SUPPLY("CDC_VDD_CP",		"tabla2x-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_RX",		"tabla-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_RX",		"tabla2x-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_TX",		"tabla-slim"),
+	REGULATOR_SUPPLY("CDC_VDDA_TX",		"tabla2x-slim"),
+	REGULATOR_SUPPLY("VDDIO_CDC",		"tabla-slim"),
+	REGULATOR_SUPPLY("VDDIO_CDC",		"tabla2x-slim"),
+	REGULATOR_SUPPLY("VDDIO_CDC",		"tabla top level"),
+	REGULATOR_SUPPLY("CDC_VDD_CP",		"tabla top level"),
+	REGULATOR_SUPPLY("CDC_VDDA_TX",		"tabla top level"),
+	REGULATOR_SUPPLY("CDC_VDDA_RX",		"tabla top level"),
+	REGULATOR_SUPPLY("VDDIO_CDC",		"0-000d"),
+	REGULATOR_SUPPLY("CDC_VDD_CP",		"0-000d"),
+	REGULATOR_SUPPLY("CDC_VDDA_TX",		"0-000d"),
+	REGULATOR_SUPPLY("CDC_VDDA_RX",		"0-000d"),
+};
+VREG_CONSUMERS(S4) = {
+	REGULATOR_SUPPLY("8018_s4",		NULL),
+};
+VREG_CONSUMERS(S5) = {
+	REGULATOR_SUPPLY("8018_s5",		NULL),
+};
+VREG_CONSUMERS(LVS1) = {
+	REGULATOR_SUPPLY("8018_lvs1",		NULL),
+};
+VREG_CONSUMERS(EXT_2P95V) = {
+	REGULATOR_SUPPLY("ext_2p95v",		NULL),
+	REGULATOR_SUPPLY("sdc_vdd",		"msm_sdcc.1"),
+};
+
+#define PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
+			 _apply_uV, _pull_down, _always_on, _supply_regulator, \
+			 _system_uA, _enable_time, _reg_id) \
+	{ \
+		.init_data = { \
+			.constraints = { \
+				.valid_modes_mask	= _modes, \
+				.valid_ops_mask		= _ops, \
+				.min_uV			= _min_uV, \
+				.max_uV			= _max_uV, \
+				.input_uV		= _max_uV, \
+				.apply_uV		= _apply_uV, \
+				.always_on		= _always_on, \
+				.name			= _name, \
+			}, \
+			.num_consumer_supplies	= \
+					ARRAY_SIZE(vreg_consumers_##_id), \
+			.consumer_supplies	= vreg_consumers_##_id, \
+			.supply_regulator	= _supply_regulator, \
+		}, \
+		.id			= _reg_id, \
+		.pull_down_enable	= _pull_down, \
+		.system_uA		= _system_uA, \
+		.enable_time		= _enable_time, \
+	}
+
+#define PM8XXX_LDO(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+		_enable_time, _supply_regulator, _system_uA, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
+		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
+		REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
+
+#define PM8XXX_NLDO1200(_id, _name, _always_on, _pull_down, _min_uV, \
+		_max_uV, _enable_time, _supply_regulator, _system_uA, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
+		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
+		REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
+
+#define PM8XXX_SMPS(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+		_enable_time, _supply_regulator, _system_uA, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
+		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
+		REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
+
+#define PM8XXX_VS(_id, _name, _always_on, _pull_down, _enable_time, \
+		_supply_regulator, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, \
+		_pull_down, _always_on, _supply_regulator, 0, _enable_time, \
+		_reg_id)
+
+/* Pin control initialization */
+#define PM8XXX_PC(_id, _name, _always_on, _pin_fn, _pin_ctrl, \
+		  _supply_regulator, _reg_id) \
+	{ \
+		.init_data = { \
+			.constraints = { \
+				.valid_ops_mask	= REGULATOR_CHANGE_STATUS, \
+				.always_on	= _always_on, \
+				.name		= _name, \
+			}, \
+			.num_consumer_supplies	= \
+					ARRAY_SIZE(vreg_consumers_##_id##_PC), \
+			.consumer_supplies	= vreg_consumers_##_id##_PC, \
+			.supply_regulator  = _supply_regulator, \
+		}, \
+		.id		= _reg_id, \
+		.pin_fn		= PM8XXX_VREG_PIN_FN_##_pin_fn, \
+		.pin_ctrl	= _pin_ctrl, \
+	}
+
+#define RPM_INIT(_id, _min_uV, _max_uV, _modes, _ops, _apply_uV, _default_uV, \
+		 _peak_uA, _avg_uA, _pull_down, _pin_ctrl, _freq, _pin_fn, \
+		 _force_mode, _sleep_set_force_mode, _power_mode, _state, \
+		 _sleep_selectable, _always_on, _supply_regulator, _system_uA) \
+	{ \
+		.init_data = { \
+			.constraints = { \
+				.valid_modes_mask	= _modes, \
+				.valid_ops_mask		= _ops, \
+				.min_uV			= _min_uV, \
+				.max_uV			= _max_uV, \
+				.input_uV		= _min_uV, \
+				.apply_uV		= _apply_uV, \
+				.always_on		= _always_on, \
+			}, \
+			.num_consumer_supplies	= \
+					ARRAY_SIZE(vreg_consumers_##_id), \
+			.consumer_supplies	= vreg_consumers_##_id, \
+			.supply_regulator	= _supply_regulator, \
+		}, \
+		.id			= RPM_VREG_ID_PM8018_##_id, \
+		.default_uV		= _default_uV, \
+		.peak_uA		= _peak_uA, \
+		.avg_uA			= _avg_uA, \
+		.pull_down_enable	= _pull_down, \
+		.pin_ctrl		= _pin_ctrl, \
+		.freq			= RPM_VREG_FREQ_##_freq, \
+		.pin_fn			= _pin_fn, \
+		.force_mode		= _force_mode, \
+		.sleep_set_force_mode	= _sleep_set_force_mode, \
+		.power_mode		= _power_mode, \
+		.state			= _state, \
+		.sleep_selectable	= _sleep_selectable, \
+		.system_uA		= _system_uA, \
+	}
+
+#define RPM_LDO(_id, _always_on, _pd, _sleep_selectable, _min_uV, _max_uV, \
+		_supply_regulator, _system_uA, _init_peak_uA) \
+	RPM_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+		 | REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE \
+		 | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE \
+		 | REGULATOR_CHANGE_DRMS, 0, _max_uV, _init_peak_uA, 0, _pd, \
+		 RPM_VREG_PIN_CTRL_NONE, NONE, RPM_VREG_PIN_FN_9615_NONE, \
+		 RPM_VREG_FORCE_MODE_9615_NONE, \
+		 RPM_VREG_FORCE_MODE_9615_NONE, RPM_VREG_POWER_MODE_9615_PWM, \
+		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
+		 _supply_regulator, _system_uA)
+
+#define RPM_SMPS(_id, _always_on, _pd, _sleep_selectable, _min_uV, _max_uV, \
+		 _supply_regulator, _system_uA, _freq) \
+	RPM_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+		 | REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE \
+		 | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE \
+		 | REGULATOR_CHANGE_DRMS, 0, _max_uV, _system_uA, 0, _pd, \
+		 RPM_VREG_PIN_CTRL_NONE, _freq, RPM_VREG_PIN_FN_9615_NONE, \
+		 RPM_VREG_FORCE_MODE_9615_NONE, \
+		 RPM_VREG_FORCE_MODE_9615_NONE, RPM_VREG_POWER_MODE_9615_PWM, \
+		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
+		 _supply_regulator, _system_uA)
+
+#define RPM_VS(_id, _always_on, _pd, _sleep_selectable, _supply_regulator) \
+	RPM_INIT(_id, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, 0, 1000, 1000, _pd, \
+		 RPM_VREG_PIN_CTRL_NONE, NONE, RPM_VREG_PIN_FN_9615_NONE, \
+		 RPM_VREG_FORCE_MODE_9615_NONE, \
+		 RPM_VREG_FORCE_MODE_9615_NONE, RPM_VREG_POWER_MODE_9615_PWM, \
+		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
+		 _supply_regulator, 0)
+
+/* Pin control initialization */
+#define RPM_PC_INIT(_id, _always_on, _pin_fn, _pin_ctrl, _supply_regulator) \
+	{ \
+		.init_data = { \
+			.constraints = { \
+				.valid_ops_mask	= REGULATOR_CHANGE_STATUS, \
+				.always_on	= _always_on, \
+			}, \
+			.num_consumer_supplies	= \
+					ARRAY_SIZE(vreg_consumers_##_id##_PC), \
+			.consumer_supplies	= vreg_consumers_##_id##_PC, \
+			.supply_regulator	= _supply_regulator, \
+		}, \
+		.id	  = RPM_VREG_ID_PM8018_##_id##_PC, \
+		.pin_fn	  = RPM_VREG_PIN_FN_9615_##_pin_fn, \
+		.pin_ctrl = _pin_ctrl, \
+	}
+
+#define GPIO_VREG_INIT(_id, _reg_name, _gpio_label, _gpio) \
+	[GPIO_VREG_ID_##_id] = { \
+		.init_data = { \
+			.constraints = { \
+				.valid_ops_mask	= REGULATOR_CHANGE_STATUS, \
+			}, \
+			.num_consumer_supplies	= \
+					ARRAY_SIZE(vreg_consumers_##_id), \
+			.consumer_supplies	= vreg_consumers_##_id, \
+		}, \
+		.regulator_name = _reg_name, \
+		.gpio_label	= _gpio_label, \
+		.gpio		= _gpio, \
+	}
+
+/* GPIO regulator constraints */
+struct gpio_regulator_platform_data msm_gpio_regulator_pdata[] = {
+	GPIO_VREG_INIT(EXT_2P95V, "ext_2p95v", "ext_2p95_en", 18),
+};
+
+/* PM8018 regulator constraints */
+struct pm8xxx_regulator_platform_data
+msm_pm8018_regulator_pdata[] __devinitdata = {
+};
+
+static struct rpm_regulator_init_data
+msm_rpm_regulator_init_data[] __devinitdata = {
+	/*	 ID    a_on pd ss min_uV   max_uV  supply sys_uA  freq */
+	RPM_SMPS(S1,     0, 1, 1,  500000, 1150000, NULL, 100000, 1p60),
+	RPM_SMPS(S2,     0, 1, 0, 1225000, 1300000, NULL, 0,	  1p60),
+	RPM_SMPS(S3,     1, 1, 0, 1800000, 1800000, NULL, 100000, 1p60),
+	RPM_SMPS(S4,     0, 1, 0, 2100000, 2200000, NULL, 0,	  1p60),
+	RPM_SMPS(S5,     1, 1, 0, 1350000, 1350000, NULL, 100000, 1p60),
+
+	/*	 ID    a_on pd ss min_uV   max_uV  supply  sys_uA init_ip */
+	RPM_LDO(L2,      1, 1, 0, 1800000, 1800000, NULL,      0, 10000),
+	RPM_LDO(L3,      0, 1, 0, 1800000, 1800000, NULL,      0, 0),
+	RPM_LDO(L4,      0, 1, 0, 3075000, 3075000, NULL,      0, 0),
+	RPM_LDO(L5,      0, 1, 0, 2850000, 2850000, NULL,      0, 0),
+	RPM_LDO(L6,      0, 1, 0, 1800000, 2850000, NULL,      0, 0),
+	RPM_LDO(L7,      0, 1, 0, 1850000, 1900000, "8018_s4", 0, 0),
+	RPM_LDO(L8,      0, 1, 0, 1200000, 1200000, "8018_s3", 0, 0),
+	RPM_LDO(L9,      0, 1, 1,  750000, 1150000, "8018_s5", 10000, 10000),
+	RPM_LDO(L10,     0, 1, 0, 1050000, 1050000, "8018_s5", 0, 0),
+	RPM_LDO(L11,     0, 1, 0, 1050000, 1050000, "8018_s5", 0, 0),
+	RPM_LDO(L12,     0, 1, 0, 1050000, 1050000, "8018_s5", 0, 0),
+	RPM_LDO(L13,     0, 1, 0, 1850000, 2950000, NULL,      0, 0),
+	RPM_LDO(L14,     0, 1, 0, 2850000, 2850000, NULL,      0, 0),
+
+	/*	ID    a_on pd ss		    supply */
+	RPM_VS(LVS1,    0, 1, 0,		    "8018_s3"),
+};
+
+int msm_pm8018_regulator_pdata_len __devinitdata =
+	ARRAY_SIZE(msm_pm8018_regulator_pdata);
+
+struct rpm_regulator_platform_data
+msm_rpm_regulator_9615_pdata __devinitdata = {
+	.init_data		= msm_rpm_regulator_init_data,
+	.num_regulators		= ARRAY_SIZE(msm_rpm_regulator_init_data),
+	.version		= RPM_VREG_VERSION_9615,
+	.vreg_id_vdd_mem	= RPM_VREG_ID_PM8018_L9,
+	.vreg_id_vdd_dig	= RPM_VREG_ID_PM8018_S1,
+};
diff --git a/arch/arm/mach-msm/board-9615-storage.c b/arch/arm/mach-msm/board-9615-storage.c
new file mode 100644
index 0000000..5bdeb94
--- /dev/null
+++ b/arch/arm/mach-msm/board-9615-storage.c
@@ -0,0 +1,232 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <asm/mach-types.h>
+#include <asm/mach/mmc.h>
+#include <mach/msm_bus_board.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
+#include "devices.h"
+
+#include "board-9615.h"
+#include "board-storage-common-a.h"
+
+#if (defined(CONFIG_MMC_MSM_SDC1_SUPPORT) \
+		|| defined(CONFIG_MMC_MSM_SDC2_SUPPORT))
+
+#define GPIO_SDC1_HW_DET	80
+#define GPIO_SDC2_DAT1_WAKEUP	26
+
+/* MDM9x15 has 2 SDCC controllers */
+enum sdcc_controllers {
+	SDCC1,
+	SDCC2,
+	MAX_SDCC_CONTROLLER
+};
+
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+/* All SDCC controllers requires VDD/VCC voltage */
+static struct msm_mmc_reg_data mmc_vdd_reg_data[MAX_SDCC_CONTROLLER] = {
+	/* SDCC1 : External card slot connected */
+	[SDCC1] = {
+		.name = "sdc_vdd",
+		/*
+		 * This is a gpio-regulator and does not support
+		 * regulator_set_voltage and regulator_set_optimum_mode
+		 */
+		.high_vol_level = 2950000,
+		.low_vol_level = 2950000,
+		.hpm_uA = 600000, /* 600mA */
+	}
+};
+
+/* All SDCC controllers may require voting for VDD PAD voltage */
+static struct msm_mmc_reg_data mmc_vddp_reg_data[MAX_SDCC_CONTROLLER] = {
+	/* SDCC1 : External card slot connected */
+	[SDCC1] = {
+		.name = "sdc_vddp",
+		.high_vol_level = 2950000,
+		.low_vol_level = 1850000,
+		.always_on = true,
+		.lpm_sup = true,
+		/* Max. Active current required is 16 mA */
+		.hpm_uA = 16000,
+		/*
+		 * Sleep current required is ~300 uA. But min. vote can be
+		 * in terms of mA (min. 1 mA). So let's vote for 2 mA
+		 * during sleep.
+		 */
+		.lpm_uA = 2000,
+	}
+};
+
+static struct msm_mmc_slot_reg_data mmc_slot_vreg_data[MAX_SDCC_CONTROLLER] = {
+	/* SDCC1 : External card slot connected */
+	[SDCC1] = {
+		.vdd_data = &mmc_vdd_reg_data[SDCC1],
+		.vddp_data = &mmc_vddp_reg_data[SDCC1],
+	}
+};
+
+/* SDC1 pad data */
+static struct msm_mmc_pad_drv sdc1_pad_drv_on_cfg[] = {
+	{TLMM_HDRV_SDC1_CLK, GPIO_CFG_16MA},
+	{TLMM_HDRV_SDC1_CMD, GPIO_CFG_10MA},
+	{TLMM_HDRV_SDC1_DATA, GPIO_CFG_10MA}
+};
+
+static struct msm_mmc_pad_drv sdc1_pad_drv_off_cfg[] = {
+	{TLMM_HDRV_SDC1_CLK, GPIO_CFG_2MA},
+	{TLMM_HDRV_SDC1_CMD, GPIO_CFG_2MA},
+	{TLMM_HDRV_SDC1_DATA, GPIO_CFG_2MA}
+};
+
+static struct msm_mmc_pad_pull sdc1_pad_pull_on_cfg[] = {
+	{TLMM_PULL_SDC1_CLK, GPIO_CFG_NO_PULL},
+	{TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_UP},
+	{TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_UP}
+};
+
+static struct msm_mmc_pad_pull sdc1_pad_pull_off_cfg[] = {
+	{TLMM_PULL_SDC1_CLK, GPIO_CFG_NO_PULL},
+	{TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_DOWN},
+	{TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_DOWN}
+};
+
+static struct msm_mmc_pad_pull_data mmc_pad_pull_data[MAX_SDCC_CONTROLLER] = {
+	[SDCC1] = {
+		.on = sdc1_pad_pull_on_cfg,
+		.off = sdc1_pad_pull_off_cfg,
+		.size = ARRAY_SIZE(sdc1_pad_pull_on_cfg)
+	},
+};
+
+static struct msm_mmc_pad_drv_data mmc_pad_drv_data[MAX_SDCC_CONTROLLER] = {
+	[SDCC1] = {
+		.on = sdc1_pad_drv_on_cfg,
+		.off = sdc1_pad_drv_off_cfg,
+		.size = ARRAY_SIZE(sdc1_pad_drv_on_cfg)
+	},
+};
+
+static struct msm_mmc_pad_data mmc_pad_data[MAX_SDCC_CONTROLLER] = {
+	[SDCC1] = {
+		.pull = &mmc_pad_pull_data[SDCC1],
+		.drv = &mmc_pad_drv_data[SDCC1]
+	},
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+
+static struct msm_mmc_gpio sdc2_gpio_cfg[] = {
+	{25, "sdc2_dat_0"},
+	{26, "sdc2_dat_1"},
+	{27, "sdc2_dat_2"},
+	{28, "sdc2_dat_3"},
+	{29, "sdc2_cmd"},
+	{30, "sdc2_clk"},
+};
+
+static struct msm_mmc_gpio_data mmc_gpio_data[MAX_SDCC_CONTROLLER] = {
+	[SDCC2] = {
+		.gpio = sdc2_gpio_cfg,
+		.size = ARRAY_SIZE(sdc2_gpio_cfg),
+	},
+};
+#endif
+
+static struct msm_mmc_pin_data mmc_slot_pin_data[MAX_SDCC_CONTROLLER] = {
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+	[SDCC1] = {
+		.is_gpio = 0,
+		.pad_data = &mmc_pad_data[SDCC1],
+	},
+#endif
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+	[SDCC2] = {
+		.is_gpio = 1,
+		.gpio_data = &mmc_gpio_data[SDCC2],
+	},
+#endif
+};
+
+#define MSM_MPM_PIN_SDC1_DAT1	17
+
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+static unsigned int sdc1_sup_clk_rates[] = {
+	400000, 24000000, 48000000
+};
+
+static struct mmc_platform_data sdc1_data = {
+	.ocr_mask       = MMC_VDD_27_28 | MMC_VDD_28_29,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.sup_clk_table	= sdc1_sup_clk_rates,
+	.sup_clk_cnt	= ARRAY_SIZE(sdc1_sup_clk_rates),
+	.pclk_src_dfab	= true,
+	.vreg_data	= &mmc_slot_vreg_data[SDCC1],
+	.pin_data	= &mmc_slot_pin_data[SDCC1],
+#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
+	.status_gpio	= GPIO_SDC1_HW_DET,
+	.status_irq	= MSM_GPIO_TO_INT(GPIO_SDC1_HW_DET),
+	.irq_flags	= IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+#endif
+	.xpc_cap	= 1,
+	.uhs_caps	= (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+			   MMC_CAP_MAX_CURRENT_400),
+	.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC1_DAT1,
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
+};
+static struct mmc_platform_data *msm9615_sdc1_pdata = &sdc1_data;
+#else
+static struct mmc_platform_data *msm9615_sdc1_pdata;
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+static unsigned int sdc2_sup_clk_rates[] = {
+	400000, 24000000, 48000000
+};
+
+static struct mmc_platform_data sdc2_data = {
+	.ocr_mask       = MMC_VDD_27_28 | MMC_VDD_28_29,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.sup_clk_table	= sdc2_sup_clk_rates,
+	.sup_clk_cnt	= ARRAY_SIZE(sdc2_sup_clk_rates),
+	.pclk_src_dfab	= 1,
+	.pin_data	= &mmc_slot_pin_data[SDCC2],
+	.sdiowakeup_irq = MSM_GPIO_TO_INT(GPIO_SDC2_DAT1_WAKEUP),
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
+};
+static struct mmc_platform_data *msm9615_sdc2_pdata = &sdc2_data;
+#else
+static struct mmc_platform_data *msm9615_sdc2_pdata;
+#endif
+
+void __init msm9615_init_mmc(void)
+{
+	if (msm9615_sdc1_pdata)
+		/* SDC1: External card slot for SD/MMC cards */
+		msm_add_sdcc(1, msm9615_sdc1_pdata);
+
+	if (msm9615_sdc2_pdata)
+		/* SDC2: External card slot used for WLAN */
+		msm_add_sdcc(2, msm9615_sdc2_pdata);
+}
+#else
+void __init msm9615_init_mmc(void)
+{
+}
+#endif
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
new file mode 100644
index 0000000..d5a0857
--- /dev/null
+++ b/arch/arm/mach-msm/board-9615.c
@@ -0,0 +1,1030 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/slimbus/slimbus.h>
+#ifdef CONFIG_WCD9310_CODEC
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/pdata.h>
+#endif
+#include <linux/msm_ssbi.h>
+#include <linux/memblock.h>
+#include <linux/usb/android.h>
+#include <linux/usb/msm_hsusb.h>
+#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
+#include <linux/leds.h>
+#include <linux/leds-pm8xxx.h>
+#include <linux/power/ltc4088-charger.h>
+#include <linux/gpio.h>
+#include <linux/msm_tsens.h>
+#include <linux/ion.h>
+#include <linux/memory.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/hardware/gic.h>
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+#include <mach/socinfo.h>
+#include <mach/msm_spi.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_xo.h>
+#include <mach/dma.h>
+#include <mach/ion.h>
+#include <mach/msm_memtypes.h>
+#include <mach/cpuidle.h>
+#include <mach/usb_bam.h>
+#include "timer.h"
+#include "devices.h"
+#include "board-9615.h"
+#include "pm.h"
+#include "acpuclock.h"
+#include "pm-boot.h"
+#include <mach/gpiomux.h>
+
+#ifdef CONFIG_ION_MSM
+#define MSM_ION_AUDIO_SIZE	0xAF000
+#define MSM_ION_HEAP_NUM	3
+#define MSM_KERNEL_EBI_SIZE	0x51000
+
+static struct memtype_reserve msm9615_reserve_table[] __initdata = {
+	[MEMTYPE_SMI] = {
+	},
+	[MEMTYPE_EBI0] = {
+		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
+	},
+	[MEMTYPE_EBI1] = {
+		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
+	},
+};
+
+static int msm9615_paddr_to_memtype(unsigned int paddr)
+{
+	return MEMTYPE_EBI1;
+}
+
+static struct ion_co_heap_pdata co_ion_pdata = {
+	.adjacent_mem_id = INVALID_HEAP_ID,
+	.align = PAGE_SIZE,
+};
+
+static struct ion_platform_data ion_pdata = {
+	.nr = MSM_ION_HEAP_NUM,
+	.heaps = {
+		{
+			.id	= ION_SYSTEM_HEAP_ID,
+			.type	= ION_HEAP_TYPE_SYSTEM,
+			.name	= ION_VMALLOC_HEAP_NAME,
+		},
+		{
+			.id	= ION_IOMMU_HEAP_ID,
+			.type	= ION_HEAP_TYPE_IOMMU,
+			.name	= ION_IOMMU_HEAP_NAME,
+		},
+		{
+			.id	= ION_AUDIO_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.name	= ION_AUDIO_HEAP_NAME,
+			.size	= MSM_ION_AUDIO_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &co_ion_pdata,
+		},
+	}
+};
+
+static struct platform_device ion_dev = {
+	.name = "ion-msm",
+	.id = 1,
+	.dev = { .platform_data = &ion_pdata },
+};
+
+static void __init reserve_ion_memory(void)
+{
+	msm9615_reserve_table[MEMTYPE_EBI1].size += MSM_ION_AUDIO_SIZE;
+}
+
+static void __init msm9615_calculate_reserve_sizes(void)
+{
+	reserve_ion_memory();
+	msm9615_reserve_table[MEMTYPE_EBI1].size += MSM_KERNEL_EBI_SIZE;
+}
+
+static struct reserve_info msm9615_reserve_info __initdata = {
+	.memtype_reserve_table = msm9615_reserve_table,
+	.calculate_reserve_sizes = msm9615_calculate_reserve_sizes,
+	.paddr_to_memtype = msm9615_paddr_to_memtype,
+};
+#endif
+
+struct pm8xxx_gpio_init {
+	unsigned		gpio;
+	struct pm_gpio		config;
+};
+
+struct pm8xxx_mpp_init {
+	unsigned			mpp;
+	struct pm8xxx_mpp_config_data	config;
+};
+
+#define PM8018_GPIO_INIT(_gpio, _dir, _buf, _val, _pull, _vin, _out_strength, \
+			_func, _inv, _disable) \
+{ \
+	.gpio	= PM8018_GPIO_PM_TO_SYS(_gpio), \
+	.config	= { \
+		.direction	= _dir, \
+		.output_buffer	= _buf, \
+		.output_value	= _val, \
+		.pull		= _pull, \
+		.vin_sel	= _vin, \
+		.out_strength	= _out_strength, \
+		.function	= _func, \
+		.inv_int_pol	= _inv, \
+		.disable_pin	= _disable, \
+	} \
+}
+
+#define PM8018_MPP_INIT(_mpp, _type, _level, _control) \
+{ \
+	.mpp	= PM8018_MPP_PM_TO_SYS(_mpp), \
+	.config	= { \
+		.type		= PM8XXX_MPP_TYPE_##_type, \
+		.level		= _level, \
+		.control	= PM8XXX_MPP_##_control, \
+	} \
+}
+
+#define PM8018_GPIO_DISABLE(_gpio) \
+	PM8018_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, 0, 0, 0, PM8018_GPIO_VIN_S3, \
+			 0, 0, 0, 1)
+
+#define PM8018_GPIO_OUTPUT(_gpio, _val, _strength) \
+	PM8018_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+			PM_GPIO_PULL_NO, PM8018_GPIO_VIN_S3, \
+			PM_GPIO_STRENGTH_##_strength, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
+#define PM8018_GPIO_INPUT(_gpio, _pull) \
+	PM8018_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, PM_GPIO_OUT_BUF_CMOS, 0, \
+			_pull, PM8018_GPIO_VIN_S3, \
+			PM_GPIO_STRENGTH_NO, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
+#define PM8018_GPIO_OUTPUT_FUNC(_gpio, _val, _func) \
+	PM8018_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+			PM_GPIO_PULL_NO, PM8018_GPIO_VIN_S3, \
+			PM_GPIO_STRENGTH_HIGH, \
+			_func, 0, 0)
+
+#define PM8018_GPIO_OUTPUT_VIN(_gpio, _val, _vin) \
+	PM8018_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+			PM_GPIO_PULL_NO, _vin, \
+			PM_GPIO_STRENGTH_HIGH, \
+			PM_GPIO_FUNC_NORMAL, 0, 0)
+
+/* Initial PM8018 GPIO configurations */
+static struct pm8xxx_gpio_init pm8018_gpios[] __initdata = {
+	PM8018_GPIO_OUTPUT(2,	0,	HIGH) /* EXT_LDO_EN_WLAN */
+};
+
+/* Initial PM8018 MPP configurations */
+static struct pm8xxx_mpp_init pm8018_mpps[] __initdata = {
+};
+
+void __init msm9615_pm8xxx_gpio_mpp_init(void)
+{
+	int i, rc;
+
+	for (i = 0; i < ARRAY_SIZE(pm8018_gpios); i++) {
+		rc = pm8xxx_gpio_config(pm8018_gpios[i].gpio,
+					&pm8018_gpios[i].config);
+		if (rc) {
+			pr_err("%s: pm8018_gpio_config: rc=%d\n", __func__, rc);
+			break;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(pm8018_mpps); i++) {
+		rc = pm8xxx_mpp_config(pm8018_mpps[i].mpp,
+					&pm8018_mpps[i].config);
+		if (rc) {
+			pr_err("%s: pm8018_mpp_config: rc=%d\n", __func__, rc);
+			break;
+		}
+	}
+}
+
+static struct pm8xxx_adc_amux pm8018_adc_channels_data[] = {
+	{"vcoin", CHANNEL_VCOIN, CHAN_PATH_SCALING2, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"vbat", CHANNEL_VBAT, CHAN_PATH_SCALING2, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"vph_pwr", CHANNEL_VPH_PWR, CHAN_PATH_SCALING2, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	/* AMUX8 is used to read either Batt_id/Batt_therm.
+	 * Current configuration is to support Batt_id. If clients
+	 * want to read the Batt_therm, the scaling function needs to be
+	 * updated to use ADC_SCALE_BATT_THERM instead of ADC_SCALE_DEFAULT.
+	 * E.g.
+	 * {"batt_therm", CHANNEL_BATT_ID_THERM, CHAN_PATH_SCALING1,
+	 * AMUX_RSV2, ADC_DECIMATION_TYPE2, ADC_SCALE_BATT_THERM},
+	 */
+	{"batt_id", CHANNEL_BATT_ID_THERM, CHAN_PATH_SCALING1,
+		AMUX_RSV2, ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"pmic_therm", CHANNEL_DIE_TEMP, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_PMIC_THERM},
+	{"625mv", CHANNEL_625MV, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"125v", CHANNEL_125V, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+	{"pa_therm0", ADC_MPP_1_AMUX3, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_PA_THERM},
+};
+
+static struct pm8xxx_adc_properties pm8018_adc_data = {
+	.adc_vdd_reference	= 1800, /* milli-voltage for this adc */
+	.bitresolution		= 15,
+	.bipolar                = 0,
+};
+
+static struct pm8xxx_adc_platform_data pm8018_adc_pdata = {
+	.adc_channel		= pm8018_adc_channels_data,
+	.adc_num_board_channel	= ARRAY_SIZE(pm8018_adc_channels_data),
+	.adc_prop		= &pm8018_adc_data,
+};
+
+static struct pm8xxx_irq_platform_data pm8xxx_irq_pdata __devinitdata = {
+	.irq_base		= PM8018_IRQ_BASE,
+	.devirq			= MSM_GPIO_TO_INT(87),
+	.irq_trigger_flag	= IRQF_TRIGGER_LOW,
+};
+
+static struct pm8xxx_gpio_platform_data pm8xxx_gpio_pdata __devinitdata = {
+	.gpio_base		= PM8018_GPIO_PM_TO_SYS(1),
+};
+
+static struct pm8xxx_mpp_platform_data pm8xxx_mpp_pdata __devinitdata = {
+	.mpp_base		= PM8018_MPP_PM_TO_SYS(1),
+};
+
+static struct pm8xxx_rtc_platform_data pm8xxx_rtc_pdata __devinitdata = {
+	.rtc_write_enable	= false,
+	.rtc_alarm_powerup	= false,
+};
+
+static struct pm8xxx_pwrkey_platform_data pm8xxx_pwrkey_pdata = {
+	.pull_up		= 1,
+	.kpd_trigger_delay_us	= 15625,
+	.wakeup			= 1,
+};
+
+static struct pm8xxx_misc_platform_data pm8xxx_misc_pdata = {
+	.priority		= 0,
+};
+
+#define PM8018_LED_KB_MAX_CURRENT	20	/* I = 20mA */
+#define PM8XXX_LED_PWM_PERIOD_US	1000
+
+/**
+ * PM8XXX_PWM_CHANNEL_NONE shall be used when LED shall not be
+ * driven using PWM feature.
+ */
+#define PM8XXX_PWM_CHANNEL_NONE		-1
+
+static struct led_info pm8018_led_info[] = {
+	[0] = {
+		.name	= "led:kb",
+	},
+};
+
+static struct led_platform_data pm8018_led_core_pdata = {
+	.num_leds = ARRAY_SIZE(pm8018_led_info),
+	.leds = pm8018_led_info,
+};
+
+static struct pm8xxx_led_config pm8018_led_configs[] = {
+	[0] = {
+		.id = PM8XXX_ID_LED_KB_LIGHT,
+		.mode = PM8XXX_LED_MODE_PWM3,
+		.max_current = PM8018_LED_KB_MAX_CURRENT,
+		.pwm_channel = 2,
+		.pwm_period_us = PM8XXX_LED_PWM_PERIOD_US,
+	},
+};
+
+static struct pm8xxx_led_platform_data pm8xxx_leds_pdata = {
+		.led_core = &pm8018_led_core_pdata,
+		.configs = pm8018_led_configs,
+		.num_configs = ARRAY_SIZE(pm8018_led_configs),
+};
+
+#ifdef CONFIG_LTC4088_CHARGER
+static struct ltc4088_charger_platform_data ltc4088_chg_pdata = {
+		.gpio_mode_select_d0 = 7,
+		.gpio_mode_select_d1 = 6,
+		.gpio_mode_select_d2 = 4,
+};
+#endif
+
+static struct pm8018_platform_data pm8018_platform_data __devinitdata = {
+	.irq_pdata		= &pm8xxx_irq_pdata,
+	.gpio_pdata		= &pm8xxx_gpio_pdata,
+	.mpp_pdata		= &pm8xxx_mpp_pdata,
+	.rtc_pdata		= &pm8xxx_rtc_pdata,
+	.pwrkey_pdata		= &pm8xxx_pwrkey_pdata,
+	.misc_pdata		= &pm8xxx_misc_pdata,
+	.regulator_pdatas	= msm_pm8018_regulator_pdata,
+	.adc_pdata		= &pm8018_adc_pdata,
+	.leds_pdata		= &pm8xxx_leds_pdata,
+};
+
+static struct msm_ssbi_platform_data msm9615_ssbi_pm8018_pdata __devinitdata = {
+	.controller_type = MSM_SBI_CTRL_PMIC_ARBITER,
+	.slave	= {
+		.name		= PM8018_CORE_DEV_NAME,
+		.platform_data	= &pm8018_platform_data,
+	},
+};
+
+static struct platform_device msm9615_device_rpm_regulator __devinitdata = {
+	.name	= "rpm-regulator",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &msm_rpm_regulator_9615_pdata,
+	},
+};
+
+static struct platform_device msm9615_device_ext_2p95v_vreg = {
+	.name	= GPIO_REGULATOR_DEV_NAME,
+	.id	= 18,
+	.dev	= {
+		.platform_data =
+			&msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_2P95V],
+	},
+};
+
+static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR,
+	.v_addr = MSM_APCS_GLB_BASE +  0x24,
+};
+
+static void __init msm9615_init_buses(void)
+{
+#ifdef CONFIG_MSM_BUS_SCALING
+	msm_bus_rpm_set_mt_mask();
+	msm_bus_9615_sys_fabric_pdata.rpm_enabled = 1;
+	msm_bus_9615_sys_fabric.dev.platform_data =
+		&msm_bus_9615_sys_fabric_pdata;
+	msm_bus_def_fab.dev.platform_data = &msm_bus_9615_def_fab_pdata;
+#endif
+}
+
+#ifdef CONFIG_WCD9310_CODEC
+
+#define TABLA_INTERRUPT_BASE (NR_MSM_IRQS + NR_GPIO_IRQS)
+
+/*
+ * MDM9x15 I2S.
+ */
+static struct wcd9xxx_pdata wcd9xxx_i2c_platform_data = {
+	.irq = MSM_GPIO_TO_INT(85),
+	.irq_base = TABLA_INTERRUPT_BASE,
+	.num_irqs = NR_TABLA_IRQS,
+	.reset_gpio = 84,
+	.micbias = {
+		.ldoh_v = TABLA_LDOH_2P85_V,
+		.cfilt1_mv = 1800,
+		.cfilt2_mv = 1800,
+		.cfilt3_mv = 1800,
+		.bias1_cfilt_sel = TABLA_CFILT1_SEL,
+		.bias2_cfilt_sel = TABLA_CFILT2_SEL,
+		.bias3_cfilt_sel = TABLA_CFILT3_SEL,
+		.bias4_cfilt_sel = TABLA_CFILT3_SEL,
+	},
+	.regulator = {
+	{
+		.name = "CDC_VDD_CP",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_RX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_RX_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_TX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_TX_CUR_MAX,
+	},
+	{
+		.name = "VDDIO_CDC",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_VDDIO_CDC_CUR_MAX,
+	},
+	{
+		.name = "VDDD_CDC_D",
+		.min_uV = 1225000,
+		.max_uV = 1225000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_A_1P2V",
+		.min_uV = 1225000,
+		.max_uV = 1225000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
+	}
+	},
+};
+
+static struct i2c_board_info wcd9xxx_device_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("tabla top level", TABLA_I2C_SLAVE_ADDR),
+		.platform_data = &wcd9xxx_i2c_platform_data,
+	},
+	{
+		I2C_BOARD_INFO("tabla analog", TABLA_ANALOG_I2C_SLAVE_ADDR),
+		.platform_data = &wcd9xxx_i2c_platform_data,
+	},
+	{
+		I2C_BOARD_INFO("tabla digital1", TABLA_DIGITAL1_I2C_SLAVE_ADDR),
+		.platform_data = &wcd9xxx_i2c_platform_data,
+	},
+	{
+		I2C_BOARD_INFO("tabla digital2", TABLA_DIGITAL2_I2C_SLAVE_ADDR),
+		.platform_data = &wcd9xxx_i2c_platform_data,
+	},
+};
+
+static struct i2c_registry msm9615_i2c_devices[] __initdata = {
+	{
+		I2C_SURF | I2C_FFA | I2C_FLUID,
+		MSM_9615_GSBI5_QUP_I2C_BUS_ID,
+		wcd9xxx_device_info,
+		ARRAY_SIZE(wcd9xxx_device_info),
+	},
+};
+/*
+ * MDM9x15 I2S.
+ */
+
+/* Micbias setting is based on 8660 CDP/MTP/FLUID requirement
+ * 4 micbiases are used to power various analog and digital
+ * microphones operating at 1800 mV. Technically, all micbiases
+ * can source from single cfilter since all microphones operate
+ * at the same voltage level. The arrangement below is to make
+ * sure all cfilters are exercised. LDO_H regulator ouput level
+ * does not need to be as high as 2.85V. It is choosen for
+ * microphone sensitivity purpose.
+ */
+
+static struct wcd9xxx_pdata tabla20_platform_data = {
+	.slimbus_slave_device = {
+		.name = "tabla-slave",
+		.e_addr = {0, 0, 0x60, 0, 0x17, 2},
+	},
+	.irq = MSM_GPIO_TO_INT(85),
+	.irq_base = TABLA_INTERRUPT_BASE,
+	.num_irqs = NR_WCD9XXX_IRQS,
+	.reset_gpio = 84,
+	.micbias = {
+		.ldoh_v = TABLA_LDOH_2P85_V,
+		.cfilt1_mv = 1800,
+		.cfilt2_mv = 1800,
+		.cfilt3_mv = 1800,
+		.bias1_cfilt_sel = TABLA_CFILT1_SEL,
+		.bias2_cfilt_sel = TABLA_CFILT2_SEL,
+		.bias3_cfilt_sel = TABLA_CFILT3_SEL,
+		.bias4_cfilt_sel = TABLA_CFILT3_SEL,
+	},
+	.regulator = {
+	{
+		.name = "CDC_VDD_CP",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_RX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_RX_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_TX",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_CDC_VDDA_TX_CUR_MAX,
+	},
+	{
+		.name = "VDDIO_CDC",
+		.min_uV = 1800000,
+		.max_uV = 1800000,
+		.optimum_uA = WCD9XXX_VDDIO_CDC_CUR_MAX,
+	},
+	{
+		.name = "VDDD_CDC_D",
+		.min_uV = 1225000,
+		.max_uV = 1225000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
+	},
+	{
+		.name = "CDC_VDDA_A_1P2V",
+		.min_uV = 1225000,
+		.max_uV = 1225000,
+		.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
+	},
+	},
+};
+
+static struct slim_device msm_slim_tabla20 = {
+	.name = "tabla2x-slim",
+	.e_addr = {0, 1, 0x60, 0, 0x17, 2},
+	.dev = {
+		.platform_data = &tabla20_platform_data,
+	},
+};
+#endif
+
+static struct slim_boardinfo msm_slim_devices[] = {
+	/* add slimbus slaves as needed */
+#ifdef CONFIG_WCD9310_CODEC
+	{
+		.bus_num = 1,
+		.slim_slave = &msm_slim_tabla20,
+	},
+#endif
+};
+
+static struct msm_spi_platform_data msm9615_qup_spi_gsbi3_pdata = {
+	.max_clock_speed = 24000000,
+};
+
+static struct msm_i2c_platform_data msm9615_i2c_qup_gsbi5_pdata = {
+	.clk_freq = 100000,
+	.src_clk_rate = 24000000,
+};
+
+#define USB_5V_EN		3
+#define PM_USB_5V_EN	PM8018_GPIO_PM_TO_SYS(USB_5V_EN)
+
+static int msm_hsusb_vbus_power(bool on)
+{
+	int rc;
+	struct pm_gpio usb_vbus = {
+			.direction      = PM_GPIO_DIR_OUT,
+			.pull           = PM_GPIO_PULL_NO,
+			.output_buffer  = PM_GPIO_OUT_BUF_CMOS,
+			.vin_sel        = 2,
+			.out_strength   = PM_GPIO_STRENGTH_HIGH,
+			.function       = PM_GPIO_FUNC_NORMAL,
+			.inv_int_pol    = 0,
+	};
+
+	usb_vbus.output_value = on;
+
+	rc = pm8xxx_gpio_config(PM_USB_5V_EN, &usb_vbus);
+	if (rc)
+		pr_err("failed to config usb_5v_en gpio\n");
+
+	return rc;
+}
+
+static int shelby_phy_init_seq[] = {
+	0x44, 0x80,/* set VBUS valid threshold and
+			disconnect valid threshold */
+	0x38, 0x81, /* update DC voltage level */
+	0x24, 0x82,/* set preemphasis and rise/fall time */
+	0x13, 0x83,/* set source impedance adjustment */
+	-1};
+
+#define USB_BAM_PHY_BASE	0x12502000
+#define HSIC_BAM_PHY_BASE	0x12542000
+#define A2_BAM_PHY_BASE		0x124C2000
+static struct usb_bam_pipe_connect msm_usb_bam_connections[2][4][2] = {
+	[0][0][USB_TO_PEER_PERIPHERAL] = {
+		.src_phy_addr = USB_BAM_PHY_BASE,
+		.src_pipe_index = 11,
+		.dst_phy_addr = A2_BAM_PHY_BASE,
+		.dst_pipe_index = 0,
+		.data_fifo_base_offset = 0x1100,
+		.data_fifo_size = 0x600,
+		.desc_fifo_base_offset = 0x1700,
+		.desc_fifo_size = 0x300,
+	},
+	[0][0][PEER_PERIPHERAL_TO_USB] = {
+		.src_phy_addr = A2_BAM_PHY_BASE,
+		.src_pipe_index = 1,
+		.dst_phy_addr = USB_BAM_PHY_BASE,
+		.dst_pipe_index = 10,
+		.data_fifo_base_offset = 0xa00,
+		.data_fifo_size = 0x600,
+		.desc_fifo_base_offset = 0x1000,
+		.desc_fifo_size = 0x100,
+	},
+	[0][1][USB_TO_PEER_PERIPHERAL] = {
+		.src_phy_addr = USB_BAM_PHY_BASE,
+		.src_pipe_index = 13,
+		.dst_phy_addr = A2_BAM_PHY_BASE,
+		.dst_pipe_index = 2,
+		.data_fifo_base_offset = 0x2100,
+		.data_fifo_size = 0x600,
+		.desc_fifo_base_offset = 0x2700,
+		.desc_fifo_size = 0x300,
+	},
+	[0][1][PEER_PERIPHERAL_TO_USB] = {
+		.src_phy_addr = A2_BAM_PHY_BASE,
+		.src_pipe_index = 3,
+		.dst_phy_addr = USB_BAM_PHY_BASE,
+		.dst_pipe_index = 12,
+		.data_fifo_base_offset = 0x1a00,
+		.data_fifo_size = 0x600,
+		.desc_fifo_base_offset = 0x2000,
+		.desc_fifo_size = 0x100,
+	},
+	[0][2][USB_TO_PEER_PERIPHERAL] = {
+		.src_phy_addr = USB_BAM_PHY_BASE,
+		.src_pipe_index = 15,
+		.dst_phy_addr = A2_BAM_PHY_BASE,
+		.dst_pipe_index = 4,
+		.data_fifo_base_offset = 0x3100,
+		.data_fifo_size = 0x600,
+		.desc_fifo_base_offset = 0x3700,
+		.desc_fifo_size = 0x300,
+	},
+	[0][2][PEER_PERIPHERAL_TO_USB] = {
+		.src_phy_addr = A2_BAM_PHY_BASE,
+		.src_pipe_index = 5,
+		.dst_phy_addr = USB_BAM_PHY_BASE,
+		.dst_pipe_index = 14,
+		.data_fifo_base_offset = 0x2a00,
+		.data_fifo_size = 0x600,
+		.desc_fifo_base_offset = 0x3000,
+		.desc_fifo_size = 0x100,
+	},
+	[1][0][USB_TO_PEER_PERIPHERAL] = {
+		.src_phy_addr = HSIC_BAM_PHY_BASE,
+		.src_pipe_index = 1,
+		.dst_phy_addr = A2_BAM_PHY_BASE,
+		.dst_pipe_index = 0,
+		.data_fifo_base_offset = 0x1100,
+		.data_fifo_size = 0x600,
+		.desc_fifo_base_offset = 0x1700,
+		.desc_fifo_size = 0x300,
+	},
+	[1][0][PEER_PERIPHERAL_TO_USB] = {
+		.src_phy_addr = A2_BAM_PHY_BASE,
+		.src_pipe_index = 1,
+		.dst_phy_addr = HSIC_BAM_PHY_BASE,
+		.dst_pipe_index = 0,
+		.data_fifo_base_offset = 0xa00,
+		.data_fifo_size = 0x600,
+		.desc_fifo_base_offset = 0x1000,
+		.desc_fifo_size = 0x100,
+	},
+	[1][1][USB_TO_PEER_PERIPHERAL] = {
+		.src_phy_addr = HSIC_BAM_PHY_BASE,
+		.src_pipe_index = 3,
+		.dst_phy_addr = A2_BAM_PHY_BASE,
+		.dst_pipe_index = 2,
+		.data_fifo_base_offset = 0x2100,
+		.data_fifo_size = 0x600,
+		.desc_fifo_base_offset = 0x2700,
+		.desc_fifo_size = 0x300,
+	},
+	[1][1][PEER_PERIPHERAL_TO_USB] = {
+		.src_phy_addr = A2_BAM_PHY_BASE,
+		.src_pipe_index = 3,
+		.dst_phy_addr = HSIC_BAM_PHY_BASE,
+		.dst_pipe_index = 2,
+		.data_fifo_base_offset = 0x1a00,
+		.data_fifo_size = 0x600,
+		.desc_fifo_base_offset = 0x2000,
+		.desc_fifo_size = 0x100,
+	},
+	[1][2][USB_TO_PEER_PERIPHERAL] = {
+		.src_phy_addr = HSIC_BAM_PHY_BASE,
+		.src_pipe_index = 5,
+		.dst_phy_addr = A2_BAM_PHY_BASE,
+		.dst_pipe_index = 4,
+		.data_fifo_base_offset = 0x3100,
+		.data_fifo_size = 0x600,
+		.desc_fifo_base_offset = 0x3700,
+		.desc_fifo_size = 0x300,
+	},
+	[1][2][PEER_PERIPHERAL_TO_USB] = {
+		.src_phy_addr = A2_BAM_PHY_BASE,
+		.src_pipe_index = 5,
+		.dst_phy_addr = HSIC_BAM_PHY_BASE,
+		.dst_pipe_index = 4,
+		.data_fifo_base_offset = 0x2a00,
+		.data_fifo_size = 0x600,
+		.desc_fifo_base_offset = 0x3000,
+		.desc_fifo_size = 0x100,
+	}
+};
+
+static struct msm_usb_bam_platform_data msm_usb_bam_pdata = {
+	.connections = &msm_usb_bam_connections[0][0][0],
+#ifndef CONFIG_USB_CI13XXX_MSM_HSIC
+	.usb_active_bam = HSUSB_BAM,
+#else
+	.usb_active_bam = HSIC_BAM,
+#endif
+	.usb_bam_num_pipes = 16,
+};
+
+static struct msm_otg_platform_data msm_otg_pdata = {
+	.mode			= USB_OTG,
+	.otg_control	= OTG_PHY_CONTROL,
+	.phy_type		= SNPS_28NM_INTEGRATED_PHY,
+	.vbus_power		= msm_hsusb_vbus_power,
+	.disable_reset_on_disconnect	= true,
+	.enable_lpm_on_dev_suspend	= true,
+};
+
+static struct msm_hsic_peripheral_platform_data msm_hsic_peripheral_pdata = {
+	.keep_core_clk_on_suspend_workaround = true,
+};
+
+#define PID_MAGIC_ID		0x71432909
+#define SERIAL_NUM_MAGIC_ID	0x61945374
+#define SERIAL_NUMBER_LENGTH	127
+#define DLOAD_USB_BASE_ADD	0x2B0000C8
+
+struct magic_num_struct {
+	uint32_t pid;
+	uint32_t serial_num;
+};
+
+struct dload_struct {
+	uint32_t	reserved1;
+	uint32_t	reserved2;
+	uint32_t	reserved3;
+	uint16_t	reserved4;
+	uint16_t	pid;
+	char		serial_number[SERIAL_NUMBER_LENGTH];
+	uint16_t	reserved5;
+	struct magic_num_struct magic_struct;
+};
+
+static int usb_diag_update_pid_and_serial_num(uint32_t pid, const char *snum)
+{
+	struct dload_struct __iomem *dload = 0;
+
+	dload = ioremap(DLOAD_USB_BASE_ADD, sizeof(*dload));
+	if (!dload) {
+		pr_err("%s: cannot remap I/O memory region: %08x\n",
+					__func__, DLOAD_USB_BASE_ADD);
+		return -ENXIO;
+	}
+
+	pr_debug("%s: dload:%p pid:%x serial_num:%s\n",
+				__func__, dload, pid, snum);
+	/* update pid */
+	dload->magic_struct.pid = PID_MAGIC_ID;
+	dload->pid = pid;
+
+	/* update serial number */
+	dload->magic_struct.serial_num = 0;
+	if (!snum) {
+		memset(dload->serial_number, 0, SERIAL_NUMBER_LENGTH);
+		goto out;
+	}
+
+	dload->magic_struct.serial_num = SERIAL_NUM_MAGIC_ID;
+	strlcpy(dload->serial_number, snum, SERIAL_NUMBER_LENGTH);
+out:
+	iounmap(dload);
+	return 0;
+}
+
+static struct platform_device msm_wlan_ar6000_pm_device = {
+	.name           = "wlan_ar6000_pm_dev",
+	.id             = -1,
+};
+
+static int __init msm9615_init_ar6000pm(void)
+{
+	return platform_device_register(&msm_wlan_ar6000_pm_device);
+}
+
+#ifdef CONFIG_LTC4088_CHARGER
+static struct platform_device msm_device_charger = {
+	.name	= LTC4088_CHARGER_DEV_NAME,
+	.id	= -1,
+	.dev	= {
+		.platform_data = &ltc4088_chg_pdata,
+	},
+};
+#endif
+
+static struct tsens_platform_data msm_tsens_pdata  = {
+	.tsens_factor		= 1000,
+	.hw_type		= MDM_9615,
+	.tsens_num_sensor	= 5,
+	.slope = {1176, 1162, 1162, 1149, 1176},
+};
+
+static struct platform_device msm_tsens_device = {
+	.name   = "tsens8960-tm",
+	.id = -1,
+};
+
+static struct platform_device *common_devices[] = {
+	&msm9615_device_dmov,
+	&msm_device_smd,
+#ifdef CONFIG_LTC4088_CHARGER
+	&msm_device_charger,
+#endif
+	&msm_device_otg,
+	&msm_device_hsic_peripheral,
+	&msm_device_gadget_peripheral,
+	&msm_device_hsusb_host,
+	&msm_device_hsic_host,
+	&msm_device_usb_bam,
+	&msm_android_usb_device,
+	&msm9615_device_uart_gsbi4,
+	&msm9615_device_ext_2p95v_vreg,
+	&msm9615_device_ssbi_pmic1,
+	&msm9615_device_qup_i2c_gsbi5,
+	&msm9615_device_qup_spi_gsbi3,
+	&msm_device_sps,
+	&msm9615_slim_ctrl,
+	&msm_device_nand,
+	&msm_device_bam_dmux,
+	&msm9615_rpm_device,
+#ifdef CONFIG_HW_RANDOM_MSM
+	&msm_device_rng,
+#endif
+#ifdef CONFIG_ION_MSM
+	&ion_dev,
+#endif
+
+	&msm_pcm,
+	&msm_multi_ch_pcm,
+	&msm_pcm_routing,
+	&msm_cpudai0,
+	&msm_cpudai1,
+	&msm_cpudai_bt_rx,
+	&msm_cpudai_bt_tx,
+	&msm_cpu_fe,
+	&msm_stub_codec,
+	&msm_voice,
+	&msm_voip,
+	&msm_i2s_cpudai0,
+	&msm_i2s_cpudai1,
+	&msm_pcm_hostless,
+	&msm_cpudai_afe_01_rx,
+	&msm_cpudai_afe_01_tx,
+	&msm_cpudai_afe_02_rx,
+	&msm_cpudai_afe_02_tx,
+	&msm_pcm_afe,
+	&msm_cpudai_auxpcm_rx,
+	&msm_cpudai_auxpcm_tx,
+
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
+	&msm9615_qcrypto_device,
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+	&msm9615_qcedev_device,
+#endif
+	&msm9615_device_watchdog,
+	&msm_bus_9615_sys_fabric,
+	&msm_bus_def_fab,
+	&msm9615_rpm_log_device,
+	&msm9615_rpm_stat_device,
+	&msm_tsens_device,
+};
+
+static void __init msm9615_i2c_init(void)
+{
+	u8 mach_mask = 0;
+	int i;
+	/* Mask is hardcoded to SURF (CDP).
+	 * works on MTP with same configuration.
+	 */
+	mach_mask = I2C_SURF;
+	if (machine_is_msm9615_cdp())
+		mach_mask = I2C_SURF;
+	else if (machine_is_msm9615_mtp())
+		mach_mask = I2C_FFA;
+	else
+		pr_err("unmatched machine ID in register_i2c_devices\n");
+	msm9615_device_qup_i2c_gsbi5.dev.platform_data =
+					&msm9615_i2c_qup_gsbi5_pdata;
+	for (i = 0; i < ARRAY_SIZE(msm9615_i2c_devices); ++i) {
+		if (msm9615_i2c_devices[i].machs & mach_mask) {
+			i2c_register_board_info(msm9615_i2c_devices[i].bus,
+						msm9615_i2c_devices[i].info,
+						msm9615_i2c_devices[i].len);
+			}
+	}
+}
+
+static void __init msm9615_reserve(void)
+{
+#ifdef CONFIG_ION_MSM
+	reserve_info = &msm9615_reserve_info;
+	msm_reserve();
+#endif
+}
+
+static void __init msm9615_common_init(void)
+{
+	struct android_usb_platform_data *android_pdata =
+				msm_android_usb_device.dev.platform_data;
+
+	msm9615_device_init();
+	msm9615_init_gpiomux();
+	msm9615_i2c_init();
+	regulator_suppress_info_printing();
+	platform_device_register(&msm9615_device_rpm_regulator);
+	msm_xo_init();
+	msm_clock_init(&msm9615_clock_init_data);
+	msm9615_init_buses();
+	msm9615_device_qup_spi_gsbi3.dev.platform_data =
+				&msm9615_qup_spi_gsbi3_pdata;
+	msm9615_device_ssbi_pmic1.dev.platform_data =
+						&msm9615_ssbi_pm8018_pdata;
+	pm8018_platform_data.num_regulators = msm_pm8018_regulator_pdata_len;
+
+	msm_device_otg.dev.platform_data = &msm_otg_pdata;
+	msm_otg_pdata.phy_init_seq = shelby_phy_init_seq;
+	msm_device_hsic_peripheral.dev.platform_data =
+		&msm_hsic_peripheral_pdata;
+	msm_device_usb_bam.dev.platform_data = &msm_usb_bam_pdata;
+	platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
+	msm9615_pm8xxx_gpio_mpp_init();
+	acpuclk_init(&acpuclk_9615_soc_data);
+
+	/* Ensure ar6000pm device is registered before MMC/SDC */
+	msm9615_init_ar6000pm();
+
+	msm9615_init_mmc();
+	slim_register_board_info(msm_slim_devices,
+		ARRAY_SIZE(msm_slim_devices));
+	android_pdata->update_pid_and_serial_num =
+					usb_diag_update_pid_and_serial_num;
+	msm_pm_boot_pdata.p_addr = allocate_contiguous_ebi_nomap(SZ_8, SZ_64K);
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+	msm_tsens_early_init(&msm_tsens_pdata);
+}
+
+static void __init msm9615_cdp_init(void)
+{
+	msm9615_common_init();
+#ifdef CONFIG_FB_MSM
+	mdm9615_init_fb();
+#endif
+}
+
+static void __init msm9615_mtp_init(void)
+{
+	msm9615_common_init();
+}
+
+#ifdef CONFIG_FB_MSM
+static void __init mdm9615_allocate_memory_regions(void)
+{
+	mdm9615_allocate_fb_region();
+}
+#endif
+
+MACHINE_START(MSM9615_CDP, "QCT MSM9615 CDP")
+	.map_io = msm9615_map_io,
+	.init_irq = msm9615_init_irq,
+	.handle_irq = gic_handle_irq,
+	.timer = &msm_timer,
+	.init_machine = msm9615_cdp_init,
+	.reserve = msm9615_reserve,
+#ifdef CONFIG_FB_MSM
+	.init_early = mdm9615_allocate_memory_regions,
+#endif
+MACHINE_END
+
+MACHINE_START(MSM9615_MTP, "QCT MSM9615 MTP")
+	.map_io = msm9615_map_io,
+	.init_irq = msm9615_init_irq,
+	.handle_irq = gic_handle_irq,
+	.timer = &msm_timer,
+	.init_machine = msm9615_mtp_init,
+	.reserve = msm9615_reserve,
+MACHINE_END
diff --git a/arch/arm/mach-msm/board-9615.h b/arch/arm/mach-msm/board-9615.h
new file mode 100644
index 0000000..68d9951
--- /dev/null
+++ b/arch/arm/mach-msm/board-9615.h
@@ -0,0 +1,72 @@
+/* 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
+ * 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 __ARCH_ARM_MACH_MSM_BOARD_9615_H
+#define __ARCH_ARM_MACH_MSM_BOARD_9615_H
+
+#include <mach/irqs.h>
+#include <linux/mfd/pm8xxx/pm8018.h>
+#include <linux/regulator/msm-gpio-regulator.h>
+
+/*
+ * MDM9x15 I2S.
+ */
+#ifdef CONFIG_I2C
+#define I2C_SURF 1
+#define I2C_FFA  (1 << 1)
+#define I2C_RUMI (1 << 2)
+#define I2C_SIM  (1 << 3)
+#define I2C_FLUID (1 << 4)
+#define I2C_LIQUID (1 << 5)
+
+struct i2c_registry {
+	u8                     machs;
+	int                    bus;
+	struct i2c_board_info *info;
+	int                    len;
+};
+#endif
+/* Tabla slave address for I2C */
+#define TABLA_I2C_SLAVE_ADDR		0x0d
+#define TABLA_ANALOG_I2C_SLAVE_ADDR	0x77
+#define TABLA_DIGITAL1_I2C_SLAVE_ADDR	0x66
+#define TABLA_DIGITAL2_I2C_SLAVE_ADDR	0x55
+#define MSM_9615_GSBI5_QUP_I2C_BUS_ID 0
+/*
+ * MDM9x15 I2S.
+ */
+
+/* Macros assume PMIC GPIOs and MPPs start at 1 */
+#define PM8018_GPIO_BASE		NR_GPIO_IRQS
+#define PM8018_GPIO_PM_TO_SYS(pm_gpio)	(pm_gpio - 1 + PM8018_GPIO_BASE)
+#define PM8018_MPP_BASE			(PM8018_GPIO_BASE + PM8018_NR_GPIOS)
+#define PM8018_MPP_PM_TO_SYS(pm_gpio)	(pm_gpio - 1 + PM8018_MPP_BASE)
+#define PM8018_IRQ_BASE			(NR_MSM_IRQS + NR_GPIO_IRQS)
+#define PM8018_MPP_IRQ_BASE		(PM8018_IRQ_BASE + NR_GPIO_IRQS)
+
+extern struct pm8xxx_regulator_platform_data
+	msm_pm8018_regulator_pdata[] __devinitdata;
+
+extern int msm_pm8018_regulator_pdata_len __devinitdata;
+
+extern struct rpm_regulator_platform_data
+msm_rpm_regulator_9615_pdata __devinitdata;
+
+#define GPIO_VREG_ID_EXT_2P95V		0
+
+extern struct gpio_regulator_platform_data msm_gpio_regulator_pdata[];
+uint32_t msm9615_rpm_get_swfi_latency(void);
+int msm9615_init_gpiomux(void);
+void msm9615_init_mmc(void);
+void mdm9615_allocate_fb_region(void);
+void mdm9615_init_fb(void);
+#endif
diff --git a/arch/arm/mach-msm/board-9625-gpiomux.c b/arch/arm/mach-msm/board-9625-gpiomux.c
new file mode 100644
index 0000000..e28c734
--- /dev/null
+++ b/arch/arm/mach-msm/board-9625-gpiomux.c
@@ -0,0 +1,53 @@
+/* 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 <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/gpiomux.h>
+
+static struct gpiomux_setting gpio_uart_config = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_16MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_OUT_HIGH,
+};
+
+static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
+	{
+		.gpio      = 45,	       /* BLSP1 UART TX */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_uart_config,
+		},
+	},
+	{
+		.gpio      = 46,	       /* BLSP1 UART RX */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_uart_config,
+		},
+	},
+};
+
+void __init msm9625_init_gpiomux(void)
+{
+	int rc;
+
+	rc = msm_gpiomux_init(NR_GPIO_IRQS);
+	if (rc) {
+		pr_err(KERN_ERR "msm9625_init_gpiomux failed %d\n", rc);
+		return;
+	}
+
+	msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
+}
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
new file mode 100644
index 0000000..60dfe3c
--- /dev/null
+++ b/arch/arm/mach-msm/board-9625.c
@@ -0,0 +1,104 @@
+/* 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/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/memory.h>
+#include <asm/mach/map.h>
+#include <asm/hardware/gic.h>
+#include <asm/arch_timer.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <mach/socinfo.h>
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include "clock.h"
+
+static struct clk_lookup msm_clocks_dummy[] = {
+	CLK_DUMMY("core_clk",   BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
+	CLK_DUMMY("iface_clk",  BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
+	CLK_DUMMY("phy_clk", NULL, "msm_otg", OFF),
+	CLK_DUMMY("core_clk", NULL, "msm_otg", OFF),
+	CLK_DUMMY("alt_core_clk", NULL, "msm_otg", OFF),
+	CLK_DUMMY("iface_clk", NULL, "msm_otg", OFF),
+	CLK_DUMMY("xo", NULL, "msm_otg", OFF),
+	CLK_DUMMY("dfab_clk",	DFAB_CLK,	NULL, 0),
+	CLK_DUMMY("dma_bam_pclk",	DMA_BAM_P_CLK,	NULL, 0),
+	CLK_DUMMY("mem_clk",	NULL,	NULL, 0),
+	CLK_DUMMY("core_clk",	NULL,	"spi_qsd.1",	OFF),
+	CLK_DUMMY("iface_clk",	NULL,	"spi_qsd.1",	OFF),
+	CLK_DUMMY("core_clk",	NULL,	"f9966000.i2c", 0),
+	CLK_DUMMY("iface_clk",	NULL,	"f9966000.i2c", 0),
+	CLK_DUMMY("core_clk",	NULL,	"fe12f000.slim",	OFF),
+};
+
+struct clock_init_data msm_dummy_clock_init_data __initdata = {
+	.table = msm_clocks_dummy,
+	.size = ARRAY_SIZE(msm_clocks_dummy),
+};
+
+static struct of_device_id irq_match[] __initdata  = {
+	{ .compatible = "qcom,msm-qgic2", .data = gic_of_init, },
+	{ .compatible = "qcom,msm-gpio", .data = msm_gpio_of_init, },
+	{}
+};
+
+static const char *msm9625_dt_match[] __initconst = {
+	"qcom,msm9625",
+	NULL
+};
+
+static struct of_dev_auxdata msm9625_auxdata_lookup[] __initdata = {
+	OF_DEV_AUXDATA("qcom,msm-lsuart-v14", 0xF991F000, \
+			"msm_serial_hsl.0", NULL),
+	{}
+};
+
+void __init msm9625_init_irq(void)
+{
+	of_irq_init(irq_match);
+}
+
+static void __init msm_dt_timer_init(void)
+{
+	arch_timer_of_register();
+}
+
+static struct sys_timer msm_dt_timer = {
+	.init = msm_dt_timer_init
+};
+
+void __init msm9625_init(void)
+{
+	if (socinfo_init() < 0)
+		pr_err("%s: socinfo_init() failed\n", __func__);
+	msm_clock_init(&msm_dummy_clock_init_data);
+	of_platform_populate(NULL, of_default_bus_match_table,
+			msm9625_auxdata_lookup, NULL);
+}
+
+DT_MACHINE_START(MSM_DT, "Qualcomm MSM (Flattened Device Tree)")
+	.map_io = msm_map_msm9625_io,
+	.init_irq = msm9625_init_irq,
+	.init_machine = msm9625_init,
+	.handle_irq = gic_handle_irq,
+	.timer = &msm_dt_timer,
+	.dt_compat = msm9625_dt_match,
+	.nr_irqs = -1,
+MACHINE_END
diff --git a/arch/arm/mach-msm/board-copper-gpiomux.c b/arch/arm/mach-msm/board-copper-gpiomux.c
new file mode 100644
index 0000000..caba698
--- /dev/null
+++ b/arch/arm/mach-msm/board-copper-gpiomux.c
@@ -0,0 +1,131 @@
+/* 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 <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/gpiomux.h>
+
+#define KS8851_IRQ_GPIO 90
+
+static struct gpiomux_setting gpio_uart_config = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_16MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_OUT_HIGH,
+};
+
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+static struct gpiomux_setting gpio_eth_config = {
+	.pull = GPIOMUX_PULL_NONE,
+	.drv = GPIOMUX_DRV_8MA,
+	.func = GPIOMUX_FUNC_GPIO,
+};
+
+static struct gpiomux_setting gpio_spi_cs_config = {
+	.func = GPIOMUX_FUNC_4,
+	.drv = GPIOMUX_DRV_12MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gpio_spi_config = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_12MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct msm_gpiomux_config msm_eth_configs[] = {
+	{
+		.gpio = KS8851_IRQ_GPIO,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_eth_config,
+		}
+	},
+};
+#endif
+static struct gpiomux_setting gpio_i2c_config = {
+	.func = GPIOMUX_FUNC_3,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+
+static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+	{
+		.gpio      = 0,		/* BLSP1 QUP SPI_DATA_MOSI */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+		},
+	},
+	{
+		.gpio      = 1,		/* BLSP1 QUP SPI_DATA_MISO */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+		},
+	},
+	{
+		.gpio      = 3,		/* BLSP1 QUP SPI_CLK */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+		},
+	},
+	{
+		.gpio      = 9,		/* BLSP1 QUP SPI_CS_N */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_cs_config,
+		},
+	},
+#endif
+	{
+		.gpio      = 83,		/* BLSP11 QUP I2C_DAT */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+		},
+	},
+	{
+		.gpio      = 84,		/* BLSP11 QUP I2C_CLK */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+		},
+	},
+	{
+		.gpio      = 45,	       /* BLSP8 UART TX */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_uart_config,
+		},
+	},
+	{
+		.gpio      = 46,	       /* BLSP8 UART RX */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_uart_config,
+		},
+	},
+};
+
+void __init msm_copper_init_gpiomux(void)
+{
+	int rc;
+
+	rc = msm_gpiomux_init(NR_GPIO_IRQS);
+	if (rc) {
+		pr_err(KERN_ERR "msmcopper_init_gpiomux failed %d\n", rc);
+		return;
+	}
+
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+	msm_gpiomux_install(msm_eth_configs, ARRAY_SIZE(msm_eth_configs));
+#endif
+	msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
+}
diff --git a/arch/arm/mach-msm/board-copper-regulator.c b/arch/arm/mach-msm/board-copper-regulator.c
new file mode 100644
index 0000000..7543872
--- /dev/null
+++ b/arch/arm/mach-msm/board-copper-regulator.c
@@ -0,0 +1,95 @@
+/*
+ * 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/platform_device.h>
+#include <linux/regulator/stub-regulator.h>
+
+#define VREG_CONSUMERS(_name) \
+	static struct regulator_consumer_supply vreg_consumers_##_name[]
+
+/*
+ * Consumer specific regulator names:
+ *			 regulator name		consumer dev_name
+ */
+VREG_CONSUMERS(K0) = {
+	REGULATOR_SUPPLY("krait0",		NULL),
+};
+VREG_CONSUMERS(K1) = {
+	REGULATOR_SUPPLY("krait1",		NULL),
+};
+VREG_CONSUMERS(K2) = {
+	REGULATOR_SUPPLY("krait2",		NULL),
+};
+VREG_CONSUMERS(K3) = {
+	REGULATOR_SUPPLY("krait3",		NULL),
+};
+
+#define PM8X41_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
+			 _always_on, _supply_regulator, _hpm_min, _system_uA)  \
+	struct stub_regulator_pdata vreg_dev_##_id##_pdata __devinitdata = { \
+		.init_data = { \
+			.constraints = { \
+				.valid_modes_mask	= _modes, \
+				.valid_ops_mask		= _ops, \
+				.min_uV			= _min_uV, \
+				.max_uV			= _max_uV, \
+				.input_uV		= _max_uV, \
+				.apply_uV		= 0,	\
+				.always_on		= _always_on, \
+				.name			= _name, \
+			}, \
+			.num_consumer_supplies	= \
+					ARRAY_SIZE(vreg_consumers_##_id), \
+			.consumer_supplies	= vreg_consumers_##_id, \
+			.supply_regulator	= _supply_regulator, \
+		}, \
+		.hpm_min_load		= _hpm_min, \
+		.system_uA		= _system_uA, \
+	}
+
+#define KRAIT_PWR(_id, _name, _always_on, _min_uV, _max_uV, \
+		_supply_regulator, _hpm_min, _system_uA) \
+	PM8X41_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
+		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
+		REGULATOR_CHANGE_DRMS, _always_on, \
+		_supply_regulator, _hpm_min, _system_uA)
+
+/*	 ID      name     a_on  min_uV   max_uV  supply  hpm_min sys_uA  */
+KRAIT_PWR(K0, "krait0", 0, 850000,  1100000, NULL,     100000, 0);
+KRAIT_PWR(K1, "krait1", 0, 850000,  1100000, NULL,     100000, 0);
+KRAIT_PWR(K2, "krait2", 0, 850000,  1100000, NULL,     100000, 0);
+KRAIT_PWR(K3, "krait3", 0, 850000,  1100000, NULL,     100000, 0);
+
+#define VREG_DEVICE(_name, _devid)					       \
+		vreg_device_##_name __devinitdata =			       \
+		{							       \
+			.name = STUB_REGULATOR_DRIVER_NAME,		       \
+			.id = _devid,					       \
+			.dev = { .platform_data = &vreg_dev_##_name##_pdata }, \
+		}
+
+static struct platform_device VREG_DEVICE(K0, 0);
+static struct platform_device VREG_DEVICE(K1, 1);
+static struct platform_device VREG_DEVICE(K2, 2);
+static struct platform_device VREG_DEVICE(K3, 3);
+
+struct platform_device *msm_copper_stub_regulator_devices[] __devinitdata = {
+	&vreg_device_K0,
+	&vreg_device_K1,
+	&vreg_device_K2,
+	&vreg_device_K3,
+};
+
+int msm_copper_stub_regulator_devices_len __devinitdata =
+			ARRAY_SIZE(msm_copper_stub_regulator_devices);
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
new file mode 100644
index 0000000..a8094e1
--- /dev/null
+++ b/arch/arm/mach-msm/board-copper.c
@@ -0,0 +1,522 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#ifdef CONFIG_ION_MSM
+#include <linux/ion.h>
+#endif
+#include <linux/memory.h>
+#ifdef CONFIG_ANDROID_PMEM
+#include <linux/android_pmem.h>
+#endif
+#include <linux/regulator/stub-regulator.h>
+#include <linux/regulator/machine.h>
+#include <asm/mach/map.h>
+#include <asm/hardware/gic.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
+#include <mach/msm_iomap.h>
+#ifdef CONFIG_ION_MSM
+#include <mach/ion.h>
+#endif
+#include <mach/msm_memtypes.h>
+#include <mach/msm_smd.h>
+#include <mach/rpm-smd.h>
+#include <mach/rpm-regulator-smd.h>
+#include <mach/qpnp-int.h>
+#include <mach/socinfo.h>
+#include "clock.h"
+#include "devices.h"
+#include "spm.h"
+
+#define MSM_KERNEL_EBI1_MEM_SIZE	0x280000
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+#define MSM_ION_SF_SIZE 0x4000000 /* 64 Mbytes */
+#else
+#define MSM_ION_SF_SIZE 0x2800000 /* 40 Mbytes */
+#endif
+#define MSM_ION_MM_FW_SIZE	0xa00000 /* (10MB) */
+#define MSM_ION_MM_SIZE		0x7800000 /* (120MB) */
+#define MSM_ION_QSECOM_SIZE	0x100000 /* (1MB) */
+#define MSM_ION_MFC_SIZE	SZ_8K
+#define MSM_ION_AUDIO_SIZE	0x2B4000
+#define MSM_ION_HEAP_NUM	8
+
+#ifdef CONFIG_KERNEL_PMEM_EBI_REGION
+static unsigned kernel_ebi1_mem_size = MSM_KERNEL_EBI1_MEM_SIZE;
+static int __init kernel_ebi1_mem_size_setup(char *p)
+{
+	kernel_ebi1_mem_size = memparse(p, NULL);
+	return 0;
+}
+early_param("kernel_ebi1_mem_size", kernel_ebi1_mem_size_setup);
+#endif
+
+static struct memtype_reserve msm_copper_reserve_table[] __initdata = {
+	[MEMTYPE_SMI] = {
+	},
+	[MEMTYPE_EBI0] = {
+		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
+	},
+	[MEMTYPE_EBI1] = {
+		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
+	},
+};
+
+static int msm_copper_paddr_to_memtype(unsigned int paddr)
+{
+	return MEMTYPE_EBI1;
+}
+
+#ifdef CONFIG_ION_MSM
+static struct ion_cp_heap_pdata cp_mm_ion_pdata = {
+	.permission_type = IPT_TYPE_MM_CARVEOUT,
+	.align = PAGE_SIZE,
+};
+
+static struct ion_cp_heap_pdata cp_mfc_ion_pdata = {
+	.permission_type = IPT_TYPE_MFC_SHAREDMEM,
+	.align = PAGE_SIZE,
+};
+
+static struct ion_co_heap_pdata co_ion_pdata = {
+	.adjacent_mem_id = INVALID_HEAP_ID,
+	.align = PAGE_SIZE,
+};
+
+static struct ion_co_heap_pdata fw_co_ion_pdata = {
+	.adjacent_mem_id = ION_CP_MM_HEAP_ID,
+	.align = SZ_128K,
+};
+
+/**
+ * These heaps are listed in the order they will be allocated. Due to
+ * video hardware restrictions and content protection the FW heap has to
+ * be allocated adjacent (below) the MM heap and the MFC heap has to be
+ * allocated after the MM heap to ensure MFC heap is not more than 256MB
+ * away from the base address of the FW heap.
+ * However, the order of FW heap and MM heap doesn't matter since these
+ * two heaps are taken care of by separate code to ensure they are adjacent
+ * to each other.
+ * Don't swap the order unless you know what you are doing!
+ */
+static struct ion_platform_data ion_pdata = {
+	.nr = MSM_ION_HEAP_NUM,
+	.heaps = {
+		{
+			.id	= ION_SYSTEM_HEAP_ID,
+			.type	= ION_HEAP_TYPE_SYSTEM,
+			.name	= ION_VMALLOC_HEAP_NAME,
+		},
+		{
+			.id	= ION_CP_MM_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CP,
+			.name	= ION_MM_HEAP_NAME,
+			.size	= MSM_ION_MM_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &cp_mm_ion_pdata,
+		},
+		{
+			.id	= ION_MM_FIRMWARE_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.name	= ION_MM_FIRMWARE_HEAP_NAME,
+			.size	= MSM_ION_MM_FW_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &fw_co_ion_pdata,
+		},
+		{
+			.id	= ION_CP_MFC_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CP,
+			.name	= ION_MFC_HEAP_NAME,
+			.size	= MSM_ION_MFC_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &cp_mfc_ion_pdata,
+		},
+		{
+			.id	= ION_SF_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.name	= ION_SF_HEAP_NAME,
+			.size	= MSM_ION_SF_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &co_ion_pdata,
+		},
+		{
+			.id	= ION_IOMMU_HEAP_ID,
+			.type	= ION_HEAP_TYPE_IOMMU,
+			.name	= ION_IOMMU_HEAP_NAME,
+		},
+		{
+			.id	= ION_QSECOM_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.name	= ION_QSECOM_HEAP_NAME,
+			.size	= MSM_ION_QSECOM_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &co_ion_pdata,
+		},
+		{
+			.id	= ION_AUDIO_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.name	= ION_AUDIO_HEAP_NAME,
+			.size	= MSM_ION_AUDIO_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &co_ion_pdata,
+		},
+	}
+};
+
+static struct platform_device ion_dev = {
+	.name = "ion-msm",
+	.id = 1,
+	.dev = { .platform_data = &ion_pdata },
+};
+
+static void __init reserve_ion_memory(void)
+{
+	msm_copper_reserve_table[MEMTYPE_EBI1].size += MSM_ION_MM_SIZE;
+	msm_copper_reserve_table[MEMTYPE_EBI1].size += MSM_ION_MM_FW_SIZE;
+	msm_copper_reserve_table[MEMTYPE_EBI1].size += MSM_ION_SF_SIZE;
+	msm_copper_reserve_table[MEMTYPE_EBI1].size += MSM_ION_MFC_SIZE;
+	msm_copper_reserve_table[MEMTYPE_EBI1].size += MSM_ION_QSECOM_SIZE;
+	msm_copper_reserve_table[MEMTYPE_EBI1].size += MSM_ION_AUDIO_SIZE;
+#ifdef CONFIG_KERNEL_PMEM_EBI_REGION
+	msm_copper_reserve_table[MEMTYPE_EBI1].size += kernel_ebi1_mem_size;
+#endif
+}
+#endif
+
+static struct resource smd_resource[] = {
+	{
+		.name	= "modem_smd_in",
+		.start	= 32 + 17,		/* mss_sw_to_kpss_ipc_irq0  */
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "modem_smsm_in",
+		.start	= 32 + 18,		/* mss_sw_to_kpss_ipc_irq1  */
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "adsp_smd_in",
+		.start	= 32 + 156,		/* lpass_to_kpss_ipc_irq0  */
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "adsp_smsm_in",
+		.start	= 32 + 157,		/* lpass_to_kpss_ipc_irq1  */
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "wcnss_smd_in",
+		.start	= 32 + 142,		/* WcnssAppsSmdMedIrq  */
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "wcnss_smsm_in",
+		.start	= 32 + 144,		/* RivaAppsWlanSmsmIrq  */
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "rpm_smd_in",
+		.start	= 32 + 168,		/* rpm_to_kpss_ipc_irq4  */
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct smd_subsystem_config smd_config_list[] = {
+	{
+		.irq_config_id = SMD_MODEM,
+		.subsys_name = "modem",
+		.edge = SMD_APPS_MODEM,
+
+		.smd_int.irq_name = "modem_smd_in",
+		.smd_int.flags = IRQF_TRIGGER_RISING,
+		.smd_int.irq_id = -1,
+		.smd_int.device_name = "smd_dev",
+		.smd_int.dev_id = 0,
+		.smd_int.out_bit_pos = 1 << 12,
+		.smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smd_int.out_offset = 0x8,
+
+		.smsm_int.irq_name = "modem_smsm_in",
+		.smsm_int.flags = IRQF_TRIGGER_RISING,
+		.smsm_int.irq_id = -1,
+		.smsm_int.device_name = "smsm_dev",
+		.smsm_int.dev_id = 0,
+		.smsm_int.out_bit_pos = 1 << 13,
+		.smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smsm_int.out_offset = 0x8,
+	},
+	{
+		.irq_config_id = SMD_Q6,
+		.subsys_name = "q6",
+		.edge = SMD_APPS_QDSP,
+
+		.smd_int.irq_name = "adsp_smd_in",
+		.smd_int.flags = IRQF_TRIGGER_RISING,
+		.smd_int.irq_id = -1,
+		.smd_int.device_name = "smd_dev",
+		.smd_int.dev_id = 0,
+		.smd_int.out_bit_pos = 1 << 8,
+		.smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smd_int.out_offset = 0x8,
+
+		.smsm_int.irq_name = "adsp_smsm_in",
+		.smsm_int.flags = IRQF_TRIGGER_RISING,
+		.smsm_int.irq_id = -1,
+		.smsm_int.device_name = "smsm_dev",
+		.smsm_int.dev_id = 0,
+		.smsm_int.out_bit_pos = 1 << 9,
+		.smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smsm_int.out_offset = 0x8,
+	},
+	{
+		.irq_config_id = SMD_WCNSS,
+		.subsys_name = "wcnss",
+		.edge = SMD_APPS_WCNSS,
+
+		.smd_int.irq_name = "wcnss_smd_in",
+		.smd_int.flags = IRQF_TRIGGER_RISING,
+		.smd_int.irq_id = -1,
+		.smd_int.device_name = "smd_dev",
+		.smd_int.dev_id = 0,
+		.smd_int.out_bit_pos = 1 << 17,
+		.smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smd_int.out_offset = 0x8,
+
+		.smsm_int.irq_name = "wcnss_smsm_in",
+		.smsm_int.flags = IRQF_TRIGGER_RISING,
+		.smsm_int.irq_id = -1,
+		.smsm_int.device_name = "smsm_dev",
+		.smsm_int.dev_id = 0,
+		.smsm_int.out_bit_pos = 1 << 19,
+		.smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smsm_int.out_offset = 0x8,
+	},
+	{
+		.irq_config_id = SMD_RPM,
+		.subsys_name = NULL, /* do not use PIL to load RPM */
+		.edge = SMD_APPS_RPM,
+
+		.smd_int.irq_name = "rpm_smd_in",
+		.smd_int.flags = IRQF_TRIGGER_RISING,
+		.smd_int.irq_id = -1,
+		.smd_int.device_name = "smd_dev",
+		.smd_int.dev_id = 0,
+		.smd_int.out_bit_pos = 1 << 0,
+		.smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smd_int.out_offset = 0x8,
+
+		.smsm_int.irq_name = NULL, /* RPM does not support SMSM */
+		.smsm_int.flags = 0,
+		.smsm_int.irq_id = 0,
+		.smsm_int.device_name = NULL,
+		.smsm_int.dev_id = 0,
+		.smsm_int.out_bit_pos = 0,
+		.smsm_int.out_base = NULL,
+		.smsm_int.out_offset = 0,
+	},
+};
+
+static struct smd_smem_regions aux_smem_areas[] = {
+	{
+		.phys_addr = (void *)(0xfc428000),
+		.size = 0x4000,
+	},
+};
+
+static struct smd_subsystem_restart_config smd_ssr_cfg = {
+	.disable_smsm_reset_handshake = 1,
+};
+
+static struct smd_platform smd_platform_data = {
+	.num_ss_configs = ARRAY_SIZE(smd_config_list),
+	.smd_ss_configs = smd_config_list,
+	.smd_ssr_config = &smd_ssr_cfg,
+	.num_smem_areas = ARRAY_SIZE(aux_smem_areas),
+	.smd_smem_areas = aux_smem_areas,
+};
+
+struct platform_device msm_device_smd_copper = {
+	.name	= "msm_smd",
+	.id	= -1,
+	.resource = smd_resource,
+	.num_resources = ARRAY_SIZE(smd_resource),
+	.dev = {
+		.platform_data = &smd_platform_data,
+	}
+};
+
+static void __init msm_copper_calculate_reserve_sizes(void)
+{
+#ifdef CONFIG_ION_MSM
+	reserve_ion_memory();
+#endif
+}
+
+static struct reserve_info msm_copper_reserve_info __initdata = {
+	.memtype_reserve_table = msm_copper_reserve_table,
+	.calculate_reserve_sizes = msm_copper_calculate_reserve_sizes,
+	.paddr_to_memtype = msm_copper_paddr_to_memtype,
+};
+
+static void __init msm_copper_early_memory(void)
+{
+	reserve_info = &msm_copper_reserve_info;
+}
+
+void __init msm_copper_reserve(void)
+{
+	msm_reserve();
+}
+
+static struct platform_device android_usb_device = {
+	.name	= "android_usb",
+	.id	= -1,
+};
+
+#define SHARED_IMEM_TZ_BASE 0xFE805720
+static struct resource copper_tzlog_resources[] = {
+	{
+		.start = SHARED_IMEM_TZ_BASE,
+		.end = SHARED_IMEM_TZ_BASE + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device copper_device_tz_log = {
+	.name		= "tz_log",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(copper_tzlog_resources),
+	.resource	= copper_tzlog_resources,
+};
+
+
+void __init msm_copper_add_devices(void)
+{
+#ifdef CONFIG_ION_MSM
+	platform_device_register(&ion_dev);
+#endif
+	platform_device_register(&msm_device_smd_copper);
+	platform_device_register(&android_usb_device);
+	platform_add_devices(msm_copper_stub_regulator_devices,
+					msm_copper_stub_regulator_devices_len);
+	platform_device_register(&copper_device_tz_log);
+}
+
+/*
+ * Used to satisfy dependencies for devices that need to be
+ * run early or in a particular order. Most likely your device doesn't fall
+ * into this category, and thus the driver should not be added here. The
+ * EPROBE_DEFER can satisfy most dependency problems.
+ */
+void __init msm_copper_add_drivers(void)
+{
+	msm_smd_init();
+	msm_rpm_driver_init();
+	rpm_regulator_smd_driver_init();
+	msm_spm_device_init();
+	regulator_stub_init();
+}
+
+static struct of_device_id irq_match[] __initdata  = {
+	{ .compatible = "qcom,msm-qgic2", .data = gic_of_init, },
+	{ .compatible = "qcom,msm-gpio", .data = msm_gpio_of_init, },
+	{ .compatible = "qcom,spmi-pmic-arb", .data = qpnpint_of_init, },
+	{}
+};
+
+void __init msm_copper_init_irq(void)
+{
+	of_irq_init(irq_match);
+}
+
+static struct clk_lookup msm_clocks_dummy[] = {
+	CLK_DUMMY("xo",		XO_CLK,		NULL,	OFF),
+	CLK_DUMMY("xo",		XO_CLK,		"pil_pronto",		OFF),
+	CLK_DUMMY("core_clk",	BLSP2_UART_CLK,	"msm_serial_hsl.0",	OFF),
+	CLK_DUMMY("iface_clk",	BLSP2_UART_CLK,	"msm_serial_hsl.0",	OFF),
+	CLK_DUMMY("core_clk",	SDC1_CLK,	NULL,			OFF),
+	CLK_DUMMY("iface_clk",	SDC1_P_CLK,	NULL,			OFF),
+	CLK_DUMMY("core_clk",	SDC3_CLK,	NULL,			OFF),
+	CLK_DUMMY("iface_clk",	SDC3_P_CLK,	NULL,			OFF),
+	CLK_DUMMY("phy_clk", NULL, "msm_otg", OFF),
+	CLK_DUMMY("core_clk", NULL, "msm_otg", OFF),
+	CLK_DUMMY("iface_clk", NULL, "msm_otg", OFF),
+	CLK_DUMMY("xo", NULL, "msm_otg", OFF),
+	CLK_DUMMY("dfab_clk",	DFAB_CLK,	NULL, 0),
+	CLK_DUMMY("dma_bam_pclk",	DMA_BAM_P_CLK,	NULL, 0),
+	CLK_DUMMY("mem_clk",	NULL,	NULL, 0),
+	CLK_DUMMY("core_clk",	SPI_CLK,	"spi_qsd.1",	OFF),
+	CLK_DUMMY("iface_clk",	SPI_P_CLK,	"spi_qsd.1",	OFF),
+	CLK_DUMMY("core_clk",	NULL,	"f9966000.i2c", 0),
+	CLK_DUMMY("iface_clk",	NULL,	"f9966000.i2c", 0),
+	CLK_DUMMY("core_clk",	NULL,	"fe12f000.slim",	OFF),
+};
+
+struct clock_init_data msm_dummy_clock_init_data __initdata = {
+	.table = msm_clocks_dummy,
+	.size = ARRAY_SIZE(msm_clocks_dummy),
+};
+
+static struct of_dev_auxdata msm_copper_auxdata_lookup[] __initdata = {
+	OF_DEV_AUXDATA("qcom,msm-lsuart-v14", 0xF991F000, \
+			"msm_serial_hsl.0", NULL),
+	OF_DEV_AUXDATA("qcom,hsusb-otg", 0xF9A55000, \
+			"msm_otg", NULL),
+	OF_DEV_AUXDATA("qcom,spi-qup-v2", 0xF9924000, \
+			"spi_qsd.1", NULL),
+	OF_DEV_AUXDATA("qcom,spmi-pmic-arb", 0xFC4C0000, \
+			"spmi-pmic-arb.0", NULL),
+	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF9824000, \
+			"msm_sdcc.1", NULL),
+	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98A4000, \
+			"msm_sdcc.2", NULL),
+	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF9864000, \
+			"msm_sdcc.3", NULL),
+	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98E4000, \
+			"msm_sdcc.4", NULL),
+	OF_DEV_AUXDATA("qcom,pil-q6v5-lpass",   0xFE200000, \
+			"pil-q6v5-lpass", NULL),
+	OF_DEV_AUXDATA("qcom,pil-pronto", 0xFB21B000, \
+			"pil_pronto", NULL),
+	OF_DEV_AUXDATA("qcom,msm-rng", 0xF9BFF000, \
+			"msm_rng", NULL),
+	{}
+};
+
+void __init msm_copper_init(struct of_dev_auxdata **adata)
+{
+	msm_copper_init_gpiomux();
+
+	if (machine_is_copper_rumi())
+		msm_clock_init(&msm_dummy_clock_init_data);
+	else
+		msm_clock_init(&msmcopper_clock_init_data);
+
+	*adata = msm_copper_auxdata_lookup;
+
+	regulator_has_full_constraints();
+}
+
+void __init msm_copper_very_early(void)
+{
+	msm_copper_early_memory();
+}
diff --git a/arch/arm/mach-msm/board-dt.c b/arch/arm/mach-msm/board-dt.c
new file mode 100644
index 0000000..674df09
--- /dev/null
+++ b/arch/arm/mach-msm/board-dt.c
@@ -0,0 +1,91 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/errno.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/of_fdt.h>
+#include <linux/of_irq.h>
+#include <asm/hardware/gic.h>
+#include <asm/arch_timer.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <mach/socinfo.h>
+#include <mach/board.h>
+
+static void __init msm_dt_timer_init(void)
+{
+	arch_timer_of_register();
+}
+
+static struct sys_timer msm_dt_timer = {
+	.init = msm_dt_timer_init
+};
+
+static void __init msm_dt_init_irq(void)
+{
+	if (machine_is_copper())
+		msm_copper_init_irq();
+}
+
+static void __init msm_dt_map_io(void)
+{
+	if (early_machine_is_copper())
+		msm_map_copper_io();
+	if (socinfo_init() < 0)
+		pr_err("%s: socinfo_init() failed\n", __func__);
+}
+
+static void __init msm_dt_init(void)
+{
+	struct of_dev_auxdata *adata = NULL;
+
+	if (machine_is_copper())
+		msm_copper_init(&adata);
+
+	of_platform_populate(NULL, of_default_bus_match_table, adata, NULL);
+	if (machine_is_copper()) {
+		msm_copper_add_devices();
+		msm_copper_add_drivers();
+	}
+}
+
+static const char *msm_dt_match[] __initconst = {
+	"qcom,msmcopper",
+	NULL
+};
+
+static void __init msm_dt_reserve(void)
+{
+	if (early_machine_is_copper())
+		msm_copper_reserve();
+}
+
+static void __init msm_dt_init_very_early(void)
+{
+	if (early_machine_is_copper())
+		msm_copper_very_early();
+}
+
+DT_MACHINE_START(MSM_DT, "Qualcomm MSM (Flattened Device Tree)")
+	.map_io = msm_dt_map_io,
+	.init_irq = msm_dt_init_irq,
+	.init_machine = msm_dt_init,
+	.handle_irq = gic_handle_irq,
+	.timer = &msm_dt_timer,
+	.dt_compat = msm_dt_match,
+	.nr_irqs = -1,
+	.reserve = msm_dt_reserve,
+	.init_very_early = msm_dt_init_very_early,
+MACHINE_END
diff --git a/arch/arm/mach-msm/board-fsm9xxx.c b/arch/arm/mach-msm/board-fsm9xxx.c
new file mode 100644
index 0000000..6b44087
--- /dev/null
+++ b/arch/arm/mach-msm/board-fsm9xxx.c
@@ -0,0 +1,926 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/msm_ssbi.h>
+#include <linux/mfd/pmic8058.h>
+#include <linux/regulator/pmic8058-regulator.h>
+#include <linux/i2c.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/regulator/pm8058-xo.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/setup.h>
+
+#include <mach/board.h>
+#include <mach/memory.h>
+#include <mach/msm_iomap.h>
+#include <mach/dma.h>
+#include <mach/sirc.h>
+
+#include <mach/socinfo.h>
+#include "devices.h"
+#include "timer.h"
+#include "acpuclock.h"
+#include "pm.h"
+#include "spm.h"
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/machine.h>
+#include <linux/msm_adc.h>
+#include <linux/m_adcproc.h>
+#include <linux/platform_data/qcom_crypto_device.h>
+
+#define PMIC_GPIO_INT		144
+#define PMIC_VREG_WLAN_LEVEL	2900
+#define PMIC_GPIO_SD_DET	165
+
+#define GPIO_EPHY_RST_N		37
+#define GPIO_MAC_TXD_3      119
+#define GPIO_MAC_TXD_2      120
+#define GPIO_MAC_TXD_1      121
+#define GPIO_MAC_TXD_0      122
+#define GPIO_MAC_TX_EN      123
+#define GPIO_MAC_MDIO       127
+#define GPIO_MAC_MDC        128
+#define GPIO_MAC_TX_CLK     133
+#define GPIO_GRFC_FTR0_0	136 /* GRFC 20 */
+#define GPIO_GRFC_FTR0_1	137 /* GRFC 21 */
+#define GPIO_GRFC_FTR1_0	145 /* GRFC 22 */
+#define GPIO_GRFC_FTR1_1	93 /* GRFC 19 */
+#define GPIO_GRFC_2		110
+#define GPIO_GRFC_3		109
+#define GPIO_GRFC_4		108
+#define GPIO_GRFC_5		107
+#define GPIO_GRFC_6		106
+#define GPIO_GRFC_7		105
+#define GPIO_GRFC_8		104
+#define GPIO_GRFC_9		103
+#define GPIO_GRFC_10		102
+#define GPIO_GRFC_11		101
+#define GPIO_GRFC_13		99
+#define GPIO_GRFC_14		98
+#define GPIO_GRFC_15		97
+#define GPIO_GRFC_16		96
+#define GPIO_GRFC_17		95
+#define GPIO_GRFC_18		94
+#define GPIO_GRFC_24		150
+#define GPIO_GRFC_25		151
+#define GPIO_GRFC_26		152
+#define GPIO_GRFC_27		153
+#define GPIO_GRFC_28		154
+#define GPIO_GRFC_29		155
+
+#define GPIO_USER_FIRST		58
+#define GPIO_USER_LAST		63
+
+#define FPGA_SDCC_STATUS        0x8E0001A8
+
+/* Macros assume PMIC GPIOs start at 0 */
+#define PM8058_GPIO_PM_TO_SYS(pm_gpio)  (pm_gpio + NR_MSM_GPIOS)
+#define PM8058_GPIO_SYS_TO_PM(sys_gpio) (sys_gpio - NR_MSM_GPIOS)
+#define PM8058_MPP_BASE			(NR_MSM_GPIOS + PM8058_GPIOS)
+#define PM8058_MPP_PM_TO_SYS(pm_gpio)	(pm_gpio + PM8058_MPP_BASE)
+#define PM8058_MPP_SYS_TO_PM(sys_gpio)	(sys_gpio - PM8058_MPP_BASE)
+
+#define PMIC_GPIO_5V_PA_PWR	21	/* PMIC GPIO Number 22 */
+#define PMIC_GPIO_4_2V_PA_PWR	22	/* PMIC GPIO Number 23 */
+#define PMIC_MPP_3		2	/* PMIC MPP Number 3 */
+#define PMIC_MPP_6		5	/* PMIC MPP Number 6 */
+#define PMIC_MPP_7		6	/* PMIC MPP Number 7 */
+#define PMIC_MPP_10		9	/* PMIC MPP Number 10 */
+
+/*
+ * PM8058
+ */
+struct pm8xxx_mpp_init_info {
+	unsigned			mpp;
+	struct pm8xxx_mpp_config_data	config;
+};
+
+#define PM8XXX_MPP_INIT(_mpp, _type, _level, _control) \
+{ \
+	.mpp	= PM8058_MPP_PM_TO_SYS(_mpp), \
+	.config	= { \
+		.type		= PM8XXX_MPP_TYPE_##_type, \
+		.level		= _level, \
+		.control	= PM8XXX_MPP_##_control, \
+	} \
+}
+
+static int pm8058_gpios_init(void)
+{
+	int i;
+	int rc;
+	struct pm8058_gpio_cfg {
+		int                gpio;
+		struct pm_gpio	   cfg;
+	};
+
+	struct pm8058_gpio_cfg gpio_cfgs[] = {
+		{				/* 5V PA Power */
+			PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_5V_PA_PWR),
+			{
+				.vin_sel = 0,
+				.direction = PM_GPIO_DIR_BOTH,
+				.output_value = 1,
+				.output_buffer = PM_GPIO_OUT_BUF_CMOS,
+				.pull = PM_GPIO_PULL_DN,
+				.out_strength = PM_GPIO_STRENGTH_HIGH,
+				.function = PM_GPIO_FUNC_NORMAL,
+				.inv_int_pol = 0,
+			},
+		},
+		{				/* 4.2V PA Power */
+			PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_4_2V_PA_PWR),
+			{
+				.vin_sel = 0,
+				.direction = PM_GPIO_DIR_BOTH,
+				.output_value = 1,
+				.output_buffer = PM_GPIO_OUT_BUF_CMOS,
+				.pull = PM_GPIO_PULL_DN,
+				.out_strength = PM_GPIO_STRENGTH_HIGH,
+				.function = PM_GPIO_FUNC_NORMAL,
+				.inv_int_pol = 0,
+			},
+		},
+	};
+
+	for (i = 0; i < ARRAY_SIZE(gpio_cfgs); ++i) {
+		rc = pm8xxx_gpio_config(gpio_cfgs[i].gpio, &gpio_cfgs[i].cfg);
+		if (rc < 0) {
+			pr_err("%s pmic gpio config failed\n", __func__);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+static int pm8058_mpps_init(void)
+{
+	int rc, i;
+
+	struct pm8xxx_mpp_init_info pm8058_mpps[] = {
+		PM8XXX_MPP_INIT(PMIC_MPP_3, A_OUTPUT,
+			PM8XXX_MPP_AOUT_LVL_1V25_2, AOUT_CTRL_ENABLE),
+		PM8XXX_MPP_INIT(PMIC_MPP_6, A_OUTPUT,
+			PM8XXX_MPP_AOUT_LVL_1V25_2, AOUT_CTRL_ENABLE),
+	};
+
+	for (i = 0; i < ARRAY_SIZE(pm8058_mpps); i++) {
+		rc = pm8xxx_mpp_config(pm8058_mpps[i].mpp,
+					&pm8058_mpps[i].config);
+		if (rc) {
+			pr_err("%s: Config %d mpp pm 8058 failed\n",
+						__func__, pm8058_mpps[i].mpp);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+static struct regulator_consumer_supply pm8058_vreg_supply[PM8058_VREG_MAX] = {
+	[PM8058_VREG_ID_L3] = REGULATOR_SUPPLY("8058_l3", NULL),
+	[PM8058_VREG_ID_L8] = REGULATOR_SUPPLY("8058_l8", NULL),
+	[PM8058_VREG_ID_L9] = REGULATOR_SUPPLY("8058_l9", NULL),
+	[PM8058_VREG_ID_L14] = REGULATOR_SUPPLY("8058_l14", NULL),
+	[PM8058_VREG_ID_L15] = REGULATOR_SUPPLY("8058_l15", NULL),
+	[PM8058_VREG_ID_L18] = REGULATOR_SUPPLY("8058_l18", NULL),
+	[PM8058_VREG_ID_S4] = REGULATOR_SUPPLY("8058_s4", NULL),
+
+	[PM8058_VREG_ID_LVS0] = REGULATOR_SUPPLY("8058_lvs0", NULL),
+};
+
+#define PM8058_VREG_INIT(_id, _min_uV, _max_uV, _modes, _ops, _apply_uV, \
+			_always_on, _pull_down) \
+	{ \
+		.init_data = { \
+			.constraints = { \
+				.valid_modes_mask = _modes, \
+				.valid_ops_mask = _ops, \
+				.min_uV = _min_uV, \
+				.max_uV = _max_uV, \
+				.apply_uV = _apply_uV, \
+				.always_on = _always_on, \
+			}, \
+			.num_consumer_supplies = 1, \
+			.consumer_supplies = &pm8058_vreg_supply[_id], \
+		}, \
+		.id = _id, \
+		.pull_down_enable = _pull_down, \
+		.pin_ctrl = 0, \
+		.pin_fn = PM8058_VREG_PIN_FN_ENABLE, \
+	}
+
+#define PM8058_VREG_INIT_LDO(_id, _min_uV, _max_uV) \
+	PM8058_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL | \
+			REGULATOR_MODE_IDLE | REGULATOR_MODE_STANDBY, \
+			REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS | \
+			REGULATOR_CHANGE_MODE, 1, 1, 1)
+
+#define PM8058_VREG_INIT_SMPS(_id, _min_uV, _max_uV) \
+	PM8058_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL | \
+			REGULATOR_MODE_IDLE | REGULATOR_MODE_STANDBY, \
+			REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS | \
+			REGULATOR_CHANGE_MODE, 1, 1, 1)
+
+#define PM8058_VREG_INIT_LVS(_id, _min_uV, _max_uV) \
+	PM8058_VREG_INIT(_id, _min_uV, _min_uV, REGULATOR_MODE_NORMAL, \
+			REGULATOR_CHANGE_STATUS, 0, 0, 1)
+
+static struct pm8058_vreg_pdata pm8058_vreg_init[] = {
+	PM8058_VREG_INIT_LDO(PM8058_VREG_ID_L3, 1800000, 1800000),
+	PM8058_VREG_INIT_LDO(PM8058_VREG_ID_L8, 2200000, 2200000),
+	PM8058_VREG_INIT_LDO(PM8058_VREG_ID_L9, 2050000, 2050000),
+	PM8058_VREG_INIT_LDO(PM8058_VREG_ID_L14, 2850000, 2850000),
+	PM8058_VREG_INIT_LDO(PM8058_VREG_ID_L15, 2200000, 2200000),
+	PM8058_VREG_INIT_LDO(PM8058_VREG_ID_L18, 2200000, 2200000),
+	PM8058_VREG_INIT_LVS(PM8058_VREG_ID_LVS0, 1800000, 1800000),
+	PM8058_VREG_INIT_SMPS(PM8058_VREG_ID_S4, 1300000, 1300000),
+};
+
+#ifdef CONFIG_SENSORS_MSM_ADC
+static struct adc_access_fn xoadc_fn = {
+	pm8058_xoadc_select_chan_and_start_conv,
+	pm8058_xoadc_read_adc_code,
+	pm8058_xoadc_get_properties,
+	pm8058_xoadc_slot_request,
+	pm8058_xoadc_restore_slot,
+	pm8058_xoadc_calibrate,
+};
+
+static struct msm_adc_channels msm_adc_channels_data[] = {
+	{"pmic_therm", CHANNEL_ADC_DIE_TEMP, 0, &xoadc_fn, CHAN_PATH_TYPE12,
+		ADC_CONFIG_TYPE2, ADC_CALIB_CONFIG_TYPE1, scale_pmic_therm},
+	{"ref_1250mv", CHANNEL_ADC_1250_REF, 0, &xoadc_fn, CHAN_PATH_TYPE13,
+		ADC_CONFIG_TYPE2, ADC_CALIB_CONFIG_TYPE2, scale_default},
+	{"xo_therm", CHANNEL_ADC_XOTHERM, 0, &xoadc_fn, CHAN_PATH_TYPE_NONE,
+		ADC_CONFIG_TYPE2, ADC_CALIB_CONFIG_TYPE5, tdkntcgtherm},
+	{"fsm_therm", CHANNEL_ADC_FSM_THERM, 0, &xoadc_fn, CHAN_PATH_TYPE6,
+		ADC_CONFIG_TYPE2, ADC_CALIB_CONFIG_TYPE5, tdkntcgtherm},
+	{"pa_therm", CHANNEL_ADC_PA_THERM, 0, &xoadc_fn, CHAN_PATH_TYPE7,
+		ADC_CONFIG_TYPE2, ADC_CALIB_CONFIG_TYPE5, tdkntcgtherm},
+};
+
+static struct msm_adc_platform_data msm_adc_pdata = {
+	.channel = msm_adc_channels_data,
+	.num_chan_supported = ARRAY_SIZE(msm_adc_channels_data),
+	.target_hw = FSM_9xxx,
+};
+
+static struct platform_device msm_adc_device = {
+	.name   = "msm_adc",
+	.id = -1,
+	.dev = {
+		.platform_data = &msm_adc_pdata,
+	},
+};
+
+static void pmic8058_xoadc_mpp_config(void)
+{
+	int rc, i;
+	struct pm8xxx_mpp_init_info xoadc_mpps[] = {
+		PM8XXX_MPP_INIT(PMIC_MPP_7, A_INPUT, PM8XXX_MPP_AIN_AMUX_CH5,
+							AOUT_CTRL_DISABLE),
+		PM8XXX_MPP_INIT(PMIC_MPP_10, A_INPUT, PM8XXX_MPP_AIN_AMUX_CH6,
+							AOUT_CTRL_DISABLE),
+	};
+	for (i = 0; i < ARRAY_SIZE(xoadc_mpps); i++) {
+		rc = pm8xxx_mpp_config(xoadc_mpps[i].mpp,
+					&xoadc_mpps[i].config);
+		if (rc) {
+			pr_err("%s: Config MPP %d of PM8058 failed\n",
+					__func__, xoadc_mpps[i].mpp);
+		}
+	}
+}
+
+static struct regulator *vreg_ldo18_adc;
+
+static int pmic8058_xoadc_vreg_config(int on)
+{
+	int rc;
+
+	if (on) {
+		rc = regulator_enable(vreg_ldo18_adc);
+		if (rc)
+			pr_err("%s: Enable of regulator ldo18_adc "
+						"failed\n", __func__);
+	} else {
+		rc = regulator_disable(vreg_ldo18_adc);
+		if (rc)
+			pr_err("%s: Disable of regulator ldo18_adc "
+						"failed\n", __func__);
+	}
+
+	return rc;
+}
+
+static int pmic8058_xoadc_vreg_setup(void)
+{
+	int rc;
+
+	vreg_ldo18_adc = regulator_get(NULL, "8058_l18");
+	if (IS_ERR(vreg_ldo18_adc)) {
+		pr_err("%s: vreg get failed (%ld)\n",
+			__func__, PTR_ERR(vreg_ldo18_adc));
+		rc = PTR_ERR(vreg_ldo18_adc);
+		goto fail;
+	}
+
+	rc = regulator_set_voltage(vreg_ldo18_adc, 2200000, 2200000);
+	if (rc) {
+		pr_err("%s: unable to set ldo18 voltage to 2.2V\n", __func__);
+		goto fail;
+	}
+
+	return rc;
+fail:
+	regulator_put(vreg_ldo18_adc);
+	return rc;
+}
+
+static void pmic8058_xoadc_vreg_shutdown(void)
+{
+	regulator_put(vreg_ldo18_adc);
+}
+
+/* usec. For this ADC,
+ * this time represents clk rate @ txco w/ 1024 decimation ratio.
+ * Each channel has different configuration, thus at the time of starting
+ * the conversion, xoadc will return actual conversion time
+ * */
+static struct adc_properties pm8058_xoadc_data = {
+	.adc_reference          = 2200, /* milli-voltage for this adc */
+	.bitresolution         = 15,
+	.bipolar                = 0,
+	.conversiontime         = 54,
+};
+
+static struct xoadc_platform_data pm8058_xoadc_pdata = {
+	.xoadc_prop = &pm8058_xoadc_data,
+	.xoadc_mpp_config = pmic8058_xoadc_mpp_config,
+	.xoadc_vreg_set = pmic8058_xoadc_vreg_config,
+	.xoadc_num = XOADC_PMIC_0,
+	.xoadc_vreg_setup = pmic8058_xoadc_vreg_setup,
+	.xoadc_vreg_shutdown = pmic8058_xoadc_vreg_shutdown,
+};
+#endif
+
+#define XO_CONSUMERS(_id) \
+	static struct regulator_consumer_supply xo_consumers_##_id[]
+
+/*
+ * Consumer specific regulator names:
+ *                       regulator name         consumer dev_name
+ */
+XO_CONSUMERS(A0) = {
+	REGULATOR_SUPPLY("8058_xo_a0", NULL),
+	REGULATOR_SUPPLY("a0_clk_buffer", "fsm_xo_driver"),
+};
+XO_CONSUMERS(A1) = {
+	REGULATOR_SUPPLY("8058_xo_a1", NULL),
+	REGULATOR_SUPPLY("a1_clk_buffer", "fsm_xo_driver"),
+};
+
+#define PM8058_XO_INIT(_id, _modes, _ops, _always_on) \
+	{ \
+		.init_data = { \
+			.constraints = { \
+				.valid_modes_mask = _modes, \
+				.valid_ops_mask = _ops, \
+				.boot_on = 1, \
+				.always_on = _always_on, \
+			}, \
+			.num_consumer_supplies = \
+				ARRAY_SIZE(xo_consumers_##_id),\
+			.consumer_supplies = xo_consumers_##_id, \
+		}, \
+		.id = PM8058_XO_ID_##_id, \
+	}
+
+#define PM8058_XO_INIT_AX(_id) \
+	PM8058_XO_INIT(_id, REGULATOR_MODE_NORMAL, REGULATOR_CHANGE_STATUS, 0)
+
+static struct pm8058_xo_pdata pm8058_xo_init_pdata[] = {
+	PM8058_XO_INIT_AX(A0),
+	PM8058_XO_INIT_AX(A1),
+};
+
+#define PM8058_GPIO_INT		47
+
+static struct pm8xxx_irq_platform_data pm8xxx_irq_pdata = {
+	.irq_base		= PMIC8058_IRQ_BASE,
+	.devirq			= MSM_GPIO_TO_INT(PM8058_GPIO_INT),
+	.irq_trigger_flag	= IRQF_TRIGGER_LOW,
+};
+
+static struct pm8xxx_gpio_platform_data pm8xxx_gpio_pdata = {
+	.gpio_base	= PM8058_GPIO_PM_TO_SYS(0),
+};
+
+static struct pm8xxx_mpp_platform_data pm8xxx_mpp_pdata = {
+	.mpp_base	= PM8058_MPP_PM_TO_SYS(0),
+};
+
+static struct pm8058_platform_data pm8058_fsm9xxx_data = {
+	.irq_pdata		= &pm8xxx_irq_pdata,
+	.gpio_pdata		= &pm8xxx_gpio_pdata,
+	.mpp_pdata		= &pm8xxx_mpp_pdata,
+	.regulator_pdatas	= pm8058_vreg_init,
+	.num_regulators		= ARRAY_SIZE(pm8058_vreg_init),
+	.xo_buffer_pdata	= pm8058_xo_init_pdata,
+	.num_xo_buffers		= ARRAY_SIZE(pm8058_xo_init_pdata),
+#ifdef CONFIG_SENSORS_MSM_ADC
+	.xoadc_pdata		= &pm8058_xoadc_pdata,
+#endif
+};
+
+#ifdef CONFIG_MSM_SSBI
+static struct msm_ssbi_platform_data fsm9xxx_ssbi_pm8058_pdata = {
+	.controller_type = FSM_SBI_CTRL_SSBI,
+	.slave  = {
+		.name                   = "pm8058-core",
+		.platform_data          = &pm8058_fsm9xxx_data,
+	},
+};
+#endif
+
+static int __init buses_init(void)
+{
+	if (gpio_tlmm_config(GPIO_CFG(PMIC_GPIO_INT, 5, GPIO_CFG_INPUT,
+			GPIO_CFG_NO_PULL, GPIO_CFG_2MA), GPIO_CFG_ENABLE))
+		pr_err("%s: gpio_tlmm_config (gpio=%d) failed\n",
+			__func__, PMIC_GPIO_INT);
+
+	return 0;
+}
+
+/*
+ * EPHY
+ */
+
+static struct msm_gpio phy_config_data[] = {
+	{ GPIO_CFG(GPIO_EPHY_RST_N, 0, GPIO_CFG_OUTPUT,
+		GPIO_CFG_NO_PULL, GPIO_CFG_8MA), "MAC_RST_N" },
+	{ GPIO_CFG(GPIO_MAC_TXD_3, 0, GPIO_CFG_OUTPUT,
+		GPIO_CFG_NO_PULL, GPIO_CFG_8MA), "MAC_TXD_3"},
+	{ GPIO_CFG(GPIO_MAC_TXD_2, 0, GPIO_CFG_OUTPUT,
+		GPIO_CFG_NO_PULL, GPIO_CFG_8MA), "MAC_TXD_2"},
+	{ GPIO_CFG(GPIO_MAC_TXD_1, 0, GPIO_CFG_OUTPUT,
+		GPIO_CFG_NO_PULL, GPIO_CFG_8MA), "MAC_TXD_1"},
+	{ GPIO_CFG(GPIO_MAC_TXD_0, 0, GPIO_CFG_OUTPUT,
+		GPIO_CFG_NO_PULL, GPIO_CFG_8MA), "MAC_TXD_0"},
+	{ GPIO_CFG(GPIO_MAC_TX_EN, 0, GPIO_CFG_OUTPUT,
+		GPIO_CFG_NO_PULL, GPIO_CFG_8MA), "MAC_TX_EN"},
+	{ GPIO_CFG(GPIO_MAC_TX_CLK, 0, GPIO_CFG_OUTPUT,
+		GPIO_CFG_NO_PULL, GPIO_CFG_10MA), "MAC_TX_CLK"},
+	{ GPIO_CFG(GPIO_MAC_MDIO, 0, GPIO_CFG_OUTPUT,
+		GPIO_CFG_NO_PULL, GPIO_CFG_6MA), "MDIO_MAC_MDIO"},
+	{ GPIO_CFG(GPIO_MAC_MDC, 0, GPIO_CFG_OUTPUT,
+		GPIO_CFG_NO_PULL, GPIO_CFG_6MA), "MDC_MAC_MDC"},
+};
+
+static int __init phy_init(void)
+{
+	msm_gpios_request_enable(phy_config_data, ARRAY_SIZE(phy_config_data));
+	gpio_direction_output(GPIO_EPHY_RST_N, 0);
+	udelay(100);
+	gpio_set_value(GPIO_EPHY_RST_N, 1);
+
+	return 0;
+}
+
+/*
+ * RF
+ */
+
+static struct msm_gpio grfc_config_data[] = {
+	{ GPIO_CFG(GPIO_GRFC_FTR0_0, 7, GPIO_CFG_OUTPUT,
+		GPIO_CFG_PULL_DOWN, GPIO_CFG_4MA), "HH_RFMODE1_0" },
+	{ GPIO_CFG(GPIO_GRFC_FTR0_1, 7, GPIO_CFG_OUTPUT,
+		GPIO_CFG_PULL_DOWN, GPIO_CFG_4MA), "HH_RFMODE1_1" },
+	{ GPIO_CFG(GPIO_GRFC_FTR1_0, 7, GPIO_CFG_OUTPUT,
+		GPIO_CFG_PULL_DOWN, GPIO_CFG_4MA), "HH_RFMODE2_0" },
+	{ GPIO_CFG(GPIO_GRFC_FTR1_1, 7, GPIO_CFG_OUTPUT,
+		GPIO_CFG_PULL_DOWN, GPIO_CFG_4MA), "HH_RFMODE2_1" },
+	{ GPIO_CFG(GPIO_GRFC_2, 7, GPIO_CFG_OUTPUT,
+		GPIO_CFG_PULL_DOWN, GPIO_CFG_4MA), "GPIO_GRFC_2" },
+	{ GPIO_CFG(GPIO_GRFC_3, 7, GPIO_CFG_OUTPUT,
+		GPIO_CFG_PULL_DOWN, GPIO_CFG_4MA), "GPIO_GRFC_3" },
+	{ GPIO_CFG(GPIO_GRFC_4, 7, GPIO_CFG_OUTPUT,
+		GPIO_CFG_PULL_DOWN, GPIO_CFG_4MA), "GPIO_GRFC_4" },
+	{ GPIO_CFG(GPIO_GRFC_5, 7, GPIO_CFG_OUTPUT,
+		GPIO_CFG_PULL_DOWN, GPIO_CFG_4MA), "GPIO_GRFC_5" },
+	{ GPIO_CFG(GPIO_GRFC_6, 7, GPIO_CFG_OUTPUT,
+		GPIO_CFG_PULL_DOWN, GPIO_CFG_4MA), "GPIO_GRFC_6" },
+	{ GPIO_CFG(GPIO_GRFC_7, 7, GPIO_CFG_OUTPUT,
+		GPIO_CFG_PULL_DOWN, GPIO_CFG_4MA), "GPIO_GRFC_7" },
+	{ GPIO_CFG(GPIO_GRFC_8, 7, GPIO_CFG_OUTPUT,
+		GPIO_CFG_PULL_DOWN, GPIO_CFG_4MA), "GPIO_GRFC_8" },
+	{ GPIO_CFG(GPIO_GRFC_9, 7, GPIO_CFG_OUTPUT,
+		GPIO_CFG_PULL_DOWN, GPIO_CFG_4MA), "GPIO_GRFC_9" },
+	{ GPIO_CFG(GPIO_GRFC_10, 7, GPIO_CFG_OUTPUT,
+		GPIO_CFG_PULL_DOWN, GPIO_CFG_4MA), "GPIO_GRFC_10" },
+	{ GPIO_CFG(GPIO_GRFC_11, 7, GPIO_CFG_OUTPUT,
+		GPIO_CFG_PULL_DOWN, GPIO_CFG_4MA), "GPIO_GRFC_11" },
+	{ GPIO_CFG(GPIO_GRFC_13, 7, GPIO_CFG_OUTPUT,
+		GPIO_CFG_PULL_DOWN, GPIO_CFG_4MA), "GPIO_GRFC_13" },
+	{ GPIO_CFG(GPIO_GRFC_14, 7, GPIO_CFG_OUTPUT,
+		GPIO_CFG_PULL_DOWN, GPIO_CFG_4MA), "GPIO_GRFC_14" },
+	{ GPIO_CFG(GPIO_GRFC_15, 7, GPIO_CFG_OUTPUT,
+		GPIO_CFG_PULL_DOWN, GPIO_CFG_4MA), "GPIO_GRFC_15" },
+	{ GPIO_CFG(GPIO_GRFC_16, 7, GPIO_CFG_OUTPUT,
+		GPIO_CFG_PULL_DOWN, GPIO_CFG_4MA), "GPIO_GRFC_16" },
+	{ GPIO_CFG(GPIO_GRFC_17, 7, GPIO_CFG_OUTPUT,
+		GPIO_CFG_PULL_DOWN, GPIO_CFG_4MA), "GPIO_GRFC_17" },
+	{ GPIO_CFG(GPIO_GRFC_18, 7, GPIO_CFG_OUTPUT,
+		GPIO_CFG_PULL_DOWN, GPIO_CFG_4MA), "GPIO_GRFC_18" },
+	{ GPIO_CFG(GPIO_GRFC_24, 7, GPIO_CFG_OUTPUT,
+		GPIO_CFG_PULL_DOWN, GPIO_CFG_4MA), "GPIO_GRFC_24" },
+	{ GPIO_CFG(GPIO_GRFC_25, 7, GPIO_CFG_OUTPUT,
+		GPIO_CFG_PULL_DOWN, GPIO_CFG_4MA), "GPIO_GRFC_25" },
+	{ GPIO_CFG(GPIO_GRFC_26, 7, GPIO_CFG_OUTPUT,
+		GPIO_CFG_PULL_DOWN, GPIO_CFG_4MA), "GPIO_GRFC_26" },
+	{ GPIO_CFG(GPIO_GRFC_27, 7, GPIO_CFG_OUTPUT,
+		GPIO_CFG_PULL_DOWN, GPIO_CFG_4MA), "GPIO_GRFC_27" },
+	{ GPIO_CFG(GPIO_GRFC_28, 7, GPIO_CFG_OUTPUT,
+		GPIO_CFG_PULL_DOWN, GPIO_CFG_4MA), "GPIO_GRFC_28" },
+	{ GPIO_CFG(GPIO_GRFC_29, 7, GPIO_CFG_OUTPUT,
+		GPIO_CFG_PULL_DOWN, GPIO_CFG_4MA), "GPIO_GRFC_29" },
+	{ GPIO_CFG(39, 1, GPIO_CFG_OUTPUT,
+		GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "PP2S_EXT_SYNC" },
+};
+
+static int __init grfc_init(void)
+{
+	msm_gpios_request_enable(grfc_config_data,
+		ARRAY_SIZE(grfc_config_data));
+
+	return 0;
+}
+
+/*
+ * UART
+ */
+
+#ifdef CONFIG_SERIAL_MSM_CONSOLE
+static struct msm_gpio uart1_config_data[] = {
+	{ GPIO_CFG(138, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+		"UART1_Rx" },
+	{ GPIO_CFG(139, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+		"UART1_Tx" },
+};
+
+static void fsm9xxx_init_uart1(void)
+{
+	msm_gpios_request_enable(uart1_config_data,
+			ARRAY_SIZE(uart1_config_data));
+
+}
+#endif
+
+/*
+ * SSBI
+ */
+
+#ifdef CONFIG_I2C_SSBI
+static struct msm_i2c_ssbi_platform_data msm_i2c_ssbi2_pdata = {
+	.controller_type = FSM_SBI_CTRL_SSBI,
+};
+
+static struct msm_i2c_ssbi_platform_data msm_i2c_ssbi3_pdata = {
+	.controller_type = FSM_SBI_CTRL_SSBI,
+};
+#endif
+
+#if defined(CONFIG_I2C_SSBI) || defined(CONFIG_MSM_SSBI)
+/* Intialize GPIO configuration for SSBI */
+static struct msm_gpio ssbi_gpio_config_data[] = {
+	{ GPIO_CFG(140, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_4MA),
+		"SSBI_1" },
+	{ GPIO_CFG(141, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_4MA),
+		"SSBI_2" },
+	{ GPIO_CFG(92, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_4MA),
+		"SSBI_3" },
+};
+
+static void
+fsm9xxx_init_ssbi_gpio(void)
+{
+	msm_gpios_request_enable(ssbi_gpio_config_data,
+		ARRAY_SIZE(ssbi_gpio_config_data));
+
+}
+#endif
+
+/*
+ * User GPIOs
+ */
+
+static void user_gpios_init(void)
+{
+	unsigned int gpio;
+
+	for (gpio = GPIO_USER_FIRST; gpio <= GPIO_USER_LAST; ++gpio)
+		gpio_tlmm_config(GPIO_CFG(gpio, 0, GPIO_CFG_INPUT,
+			GPIO_CFG_NO_PULL, GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+}
+
+/*
+ * Crypto
+ */
+
+#define QCE_SIZE		0x10000
+
+#define QCE_0_BASE		0x80C00000
+#define QCE_1_BASE		0x80E00000
+#define QCE_2_BASE		0x81000000
+
+#define QCE_NO_HW_KEY_SUPPORT		0 /* No shared HW key with external */
+#define QCE_NO_SHARE_CE_RESOURCE	0 /* No CE resource shared with TZ */
+#define QCE_NO_CE_SHARED		0 /* CE not shared with TZ */
+#define QCE_NO_SHA_HMAC_SUPPORT		0 /* No SHA-HMAC by SHA operation */
+
+static struct resource qcrypto_resources[] = {
+	[0] = {
+		.start = QCE_0_BASE,
+		.end = QCE_0_BASE + QCE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.name = "crypto_channels",
+		.start = DMOV_CE1_IN_CHAN,
+		.end = DMOV_CE1_OUT_CHAN,
+		.flags = IORESOURCE_DMA,
+	},
+	[2] = {
+		.name = "crypto_crci_in",
+		.start = DMOV_CE1_IN_CRCI,
+		.end = DMOV_CE1_IN_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+	[3] = {
+		.name = "crypto_crci_out",
+		.start = DMOV_CE1_OUT_CRCI,
+		.end = DMOV_CE1_OUT_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+	[4] = {
+		.name = "crypto_crci_hash",
+		.start = DMOV_CE1_HASH_CRCI,
+		.end = DMOV_CE1_HASH_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static struct msm_ce_hw_support qcrypto_ce_hw_suppport = {
+	.ce_shared = QCE_NO_CE_SHARED,
+	.shared_ce_resource = QCE_NO_SHARE_CE_RESOURCE,
+	.hw_key_support = QCE_NO_HW_KEY_SUPPORT,
+	.sha_hmac = QCE_NO_SHA_HMAC_SUPPORT,
+	.bus_scale_table = NULL,
+};
+
+struct platform_device qcrypto_device = {
+	.name		= "qcrypto",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(qcrypto_resources),
+	.resource	= qcrypto_resources,
+	.dev		= {
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+		.platform_data = &qcrypto_ce_hw_suppport,
+	},
+};
+
+static struct resource qcedev_resources[] = {
+	[0] = {
+		.start = QCE_0_BASE,
+		.end = QCE_0_BASE + QCE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.name = "crypto_channels",
+		.start = DMOV_CE1_IN_CHAN,
+		.end = DMOV_CE1_OUT_CHAN,
+		.flags = IORESOURCE_DMA,
+	},
+	[2] = {
+		.name = "crypto_crci_in",
+		.start = DMOV_CE1_IN_CRCI,
+		.end = DMOV_CE1_IN_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+	[3] = {
+		.name = "crypto_crci_out",
+		.start = DMOV_CE1_OUT_CRCI,
+		.end = DMOV_CE1_OUT_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+	[4] = {
+		.name = "crypto_crci_hash",
+		.start = DMOV_CE1_HASH_CRCI,
+		.end = DMOV_CE1_HASH_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static struct msm_ce_hw_support qcedev_ce_hw_suppport = {
+	.ce_shared = QCE_NO_CE_SHARED,
+	.shared_ce_resource = QCE_NO_SHARE_CE_RESOURCE,
+	.hw_key_support = QCE_NO_HW_KEY_SUPPORT,
+	.sha_hmac = QCE_NO_SHA_HMAC_SUPPORT,
+	.bus_scale_table = NULL,
+};
+
+static struct platform_device qcedev_device = {
+	.name		= "qce",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(qcedev_resources),
+	.resource	= qcedev_resources,
+	.dev		= {
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+		.platform_data = &qcedev_ce_hw_suppport,
+	},
+};
+
+static struct resource ota_qcrypto_resources[] = {
+	[0] = {
+		.start = QCE_1_BASE,
+		.end = QCE_1_BASE + QCE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.name = "crypto_channels",
+		.start = DMOV_CE2_IN_CHAN,
+		.end = DMOV_CE2_OUT_CHAN,
+		.flags = IORESOURCE_DMA,
+	},
+	[2] = {
+		.name = "crypto_crci_in",
+		.start = DMOV_CE2_IN_CRCI,
+		.end = DMOV_CE2_IN_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+	[3] = {
+		.name = "crypto_crci_out",
+		.start = DMOV_CE2_OUT_CRCI,
+		.end = DMOV_CE2_OUT_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+	[4] = {
+		.name = "crypto_crci_hash",
+		.start = DMOV_CE2_HASH_CRCI,
+		.end = DMOV_CE2_HASH_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+struct platform_device ota_qcrypto_device = {
+	.name		= "qcota",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(ota_qcrypto_resources),
+	.resource	= ota_qcrypto_resources,
+	.dev		= {
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
+
+/*
+ * Devices
+ */
+
+static struct platform_device *devices[] __initdata = {
+	&msm_device_smd,
+	&msm_device_dmov,
+	&msm_device_nand,
+#ifdef CONFIG_MSM_SSBI
+	&msm_device_ssbi_pmic1,
+#endif
+#ifdef CONFIG_I2C_SSBI
+	&msm_device_ssbi2,
+	&msm_device_ssbi3,
+#endif
+#ifdef CONFIG_SENSORS_MSM_ADC
+	&msm_adc_device,
+#endif
+#ifdef CONFIG_I2C_QUP
+	&msm_gsbi1_qup_i2c_device,
+#endif
+#if defined(CONFIG_SERIAL_MSM) || defined(CONFIG_MSM_SERIAL_DEBUGGER)
+	&msm_device_uart1,
+#endif
+#if defined(CONFIG_QFP_FUSE)
+	&fsm_qfp_fuse_device,
+#endif
+	&qfec_device,
+	&qcrypto_device,
+	&qcedev_device,
+	&ota_qcrypto_device,
+	&fsm_xo_device,
+	&fsm9xxx_device_watchdog,
+};
+
+static void __init fsm9xxx_init_irq(void)
+{
+	msm_init_irq();
+	msm_init_sirc();
+}
+
+#ifdef CONFIG_MSM_SPM
+static struct msm_spm_platform_data msm_spm_data __initdata = {
+	.reg_base_addr = MSM_SAW_BASE,
+
+	.reg_init_values[MSM_SPM_REG_SAW_CFG] = 0x05,
+	.reg_init_values[MSM_SPM_REG_SAW_SPM_CTL] = 0x18,
+	.reg_init_values[MSM_SPM_REG_SAW_SPM_SLP_TMR_DLY] = 0x00006666,
+	.reg_init_values[MSM_SPM_REG_SAW_SPM_WAKE_TMR_DLY] = 0xFF000666,
+
+	.reg_init_values[MSM_SPM_REG_SAW_SPM_PMIC_CTL] = 0xE0F272,
+	.reg_init_values[MSM_SPM_REG_SAW_SLP_CLK_EN] = 0x01,
+	.reg_init_values[MSM_SPM_REG_SAW_SLP_HSFS_PRECLMP_EN] = 0x03,
+	.reg_init_values[MSM_SPM_REG_SAW_SLP_HSFS_POSTCLMP_EN] = 0x00,
+
+	.reg_init_values[MSM_SPM_REG_SAW_SLP_CLMP_EN] = 0x01,
+	.reg_init_values[MSM_SPM_REG_SAW_SLP_RST_EN] = 0x00,
+	.reg_init_values[MSM_SPM_REG_SAW_SPM_MPM_CFG] = 0x00,
+
+	.awake_vlevel = 0xF2,
+	.retention_vlevel = 0xE0,
+	.collapse_vlevel = 0x72,
+	.retention_mid_vlevel = 0xE0,
+	.collapse_mid_vlevel = 0xE0,
+};
+#endif
+
+static void __init fsm9xxx_init(void)
+{
+	acpuclk_init(&acpuclk_9xxx_soc_data);
+
+	regulator_has_full_constraints();
+
+#if defined(CONFIG_I2C_SSBI) || defined(CONFIG_MSM_SSBI)
+	fsm9xxx_init_ssbi_gpio();
+#endif
+#ifdef CONFIG_MSM_SSBI
+	msm_device_ssbi_pmic1.dev.platform_data =
+			&fsm9xxx_ssbi_pm8058_pdata;
+#endif
+	buses_init();
+
+	platform_add_devices(devices, ARRAY_SIZE(devices));
+
+#ifdef CONFIG_MSM_SPM
+	msm_spm_init(&msm_spm_data, 1);
+#endif
+	pm8058_gpios_init();
+	pm8058_mpps_init();
+	phy_init();
+	grfc_init();
+	user_gpios_init();
+
+#ifdef CONFIG_SERIAL_MSM_CONSOLE
+	fsm9xxx_init_uart1();
+#endif
+#ifdef CONFIG_I2C_SSBI
+	msm_device_ssbi2.dev.platform_data = &msm_i2c_ssbi2_pdata;
+	msm_device_ssbi3.dev.platform_data = &msm_i2c_ssbi3_pdata;
+#endif
+}
+
+static void __init fsm9xxx_map_io(void)
+{
+	msm_shared_ram_phys = 0x00100000;
+	msm_map_fsm9xxx_io();
+	msm_clock_init(&fsm9xxx_clock_init_data);
+	if (socinfo_init() < 0)
+		pr_err("%s: socinfo_init() failed!\n",
+		       __func__);
+
+}
+
+MACHINE_START(FSM9XXX_SURF, "QCT FSM9XXX")
+	.atag_offset = 0x100,
+	.map_io = fsm9xxx_map_io,
+	.init_irq = fsm9xxx_init_irq,
+	.handle_irq = vic_handle_irq,
+	.init_machine = fsm9xxx_init,
+	.timer = &msm_timer,
+MACHINE_END
diff --git a/arch/arm/mach-msm/board-halibut-keypad.c b/arch/arm/mach-msm/board-halibut-keypad.c
new file mode 100644
index 0000000..49c1075
--- /dev/null
+++ b/arch/arm/mach-msm/board-halibut-keypad.c
@@ -0,0 +1,177 @@
+/* linux/arch/arm/mach-msm/board-halibut-keypad.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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.
+ *
+ */
+
+#include <asm/mach-types.h>
+#include <linux/platform_device.h>
+#include <linux/gpio_event.h>
+
+#undef MODULE_PARAM_PREFIX
+#define MODULE_PARAM_PREFIX "board_halibut."
+static int halibut_ffa;
+module_param_named(ffa, halibut_ffa, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#define SCAN_FUNCTION_KEYS 0 /* don't turn this on without updating the ffa support */
+
+static unsigned int halibut_row_gpios[] = {
+	31, 32, 33, 34, 35, 41
+#if SCAN_FUNCTION_KEYS
+	, 42
+#endif
+};
+
+static unsigned int halibut_col_gpios[] = { 36, 37, 38, 39, 40 };
+
+/* FFA:
+ 36: KEYSENSE_N(0)
+ 37: KEYSENSE_N(1)
+ 38: KEYSENSE_N(2)
+ 39: KEYSENSE_N(3)
+ 40: KEYSENSE_N(4)
+
+ 31: KYPD_17
+ 32: KYPD_15
+ 33: KYPD_13
+ 34: KYPD_11
+ 35: KYPD_9
+ 41: KYPD_MEMO
+*/
+
+#define KEYMAP_INDEX(row, col) ((row)*ARRAY_SIZE(halibut_col_gpios) + (col))
+
+static const unsigned short halibut_keymap[ARRAY_SIZE(halibut_col_gpios) * ARRAY_SIZE(halibut_row_gpios)] = {
+	[KEYMAP_INDEX(0, 0)] = KEY_5,
+	[KEYMAP_INDEX(0, 1)] = KEY_9,
+	[KEYMAP_INDEX(0, 2)] = 229,            /* SOFT1 */
+	[KEYMAP_INDEX(0, 3)] = KEY_6,
+	[KEYMAP_INDEX(0, 4)] = KEY_LEFT,
+
+	[KEYMAP_INDEX(1, 0)] = KEY_0,
+	[KEYMAP_INDEX(1, 1)] = KEY_RIGHT,
+	[KEYMAP_INDEX(1, 2)] = KEY_1,
+	[KEYMAP_INDEX(1, 3)] = 228,           /* KEY_SHARP */
+	[KEYMAP_INDEX(1, 4)] = KEY_SEND,
+
+	[KEYMAP_INDEX(2, 0)] = KEY_VOLUMEUP,
+	[KEYMAP_INDEX(2, 1)] = KEY_HOME,      /* FA   */
+	[KEYMAP_INDEX(2, 2)] = KEY_F8,        /* QCHT */
+	[KEYMAP_INDEX(2, 3)] = KEY_F6,        /* R+   */
+	[KEYMAP_INDEX(2, 4)] = KEY_F7,        /* R-   */
+
+	[KEYMAP_INDEX(3, 0)] = KEY_UP,
+	[KEYMAP_INDEX(3, 1)] = KEY_CLEAR,
+	[KEYMAP_INDEX(3, 2)] = KEY_4,
+	[KEYMAP_INDEX(3, 3)] = KEY_MUTE,      /* SPKR */
+	[KEYMAP_INDEX(3, 4)] = KEY_2,
+
+	[KEYMAP_INDEX(4, 0)] = 230,           /* SOFT2 */
+	[KEYMAP_INDEX(4, 1)] = 232,           /* KEY_CENTER */
+	[KEYMAP_INDEX(4, 2)] = KEY_DOWN,
+	[KEYMAP_INDEX(4, 3)] = KEY_BACK,      /* FB */
+	[KEYMAP_INDEX(4, 4)] = KEY_8,
+
+	[KEYMAP_INDEX(5, 0)] = KEY_VOLUMEDOWN,
+	[KEYMAP_INDEX(5, 1)] = 227,           /* KEY_STAR */
+	[KEYMAP_INDEX(5, 2)] = KEY_MAIL,      /* MESG */
+	[KEYMAP_INDEX(5, 3)] = KEY_3,
+	[KEYMAP_INDEX(5, 4)] = KEY_7,
+
+#if SCAN_FUNCTION_KEYS
+	[KEYMAP_INDEX(6, 0)] = KEY_F5,
+	[KEYMAP_INDEX(6, 1)] = KEY_F4,
+	[KEYMAP_INDEX(6, 2)] = KEY_F3,
+	[KEYMAP_INDEX(6, 3)] = KEY_F2,
+	[KEYMAP_INDEX(6, 4)] = KEY_F1
+#endif
+};
+
+static const unsigned short halibut_keymap_ffa[ARRAY_SIZE(halibut_col_gpios) * ARRAY_SIZE(halibut_row_gpios)] = {
+	/*[KEYMAP_INDEX(0, 0)] = ,*/
+	/*[KEYMAP_INDEX(0, 1)] = ,*/
+	[KEYMAP_INDEX(0, 2)] = KEY_1,
+	[KEYMAP_INDEX(0, 3)] = KEY_SEND,
+	[KEYMAP_INDEX(0, 4)] = KEY_LEFT,
+
+	[KEYMAP_INDEX(1, 0)] = KEY_3,
+	[KEYMAP_INDEX(1, 1)] = KEY_RIGHT,
+	[KEYMAP_INDEX(1, 2)] = KEY_VOLUMEUP,
+	/*[KEYMAP_INDEX(1, 3)] = ,*/
+	[KEYMAP_INDEX(1, 4)] = KEY_6,
+
+	[KEYMAP_INDEX(2, 0)] = KEY_HOME,      /* A */
+	[KEYMAP_INDEX(2, 1)] = KEY_BACK,      /* B */
+	[KEYMAP_INDEX(2, 2)] = KEY_0,
+	[KEYMAP_INDEX(2, 3)] = 228,           /* KEY_SHARP */
+	[KEYMAP_INDEX(2, 4)] = KEY_9,
+
+	[KEYMAP_INDEX(3, 0)] = KEY_UP,
+	[KEYMAP_INDEX(3, 1)] = 232, /* KEY_CENTER */ /* i */
+	[KEYMAP_INDEX(3, 2)] = KEY_4,
+	/*[KEYMAP_INDEX(3, 3)] = ,*/
+	[KEYMAP_INDEX(3, 4)] = KEY_2,
+
+	[KEYMAP_INDEX(4, 0)] = KEY_VOLUMEDOWN,
+	[KEYMAP_INDEX(4, 1)] = KEY_SOUND,
+	[KEYMAP_INDEX(4, 2)] = KEY_DOWN,
+	[KEYMAP_INDEX(4, 3)] = KEY_8,
+	[KEYMAP_INDEX(4, 4)] = KEY_5,
+
+	/*[KEYMAP_INDEX(5, 0)] = ,*/
+	[KEYMAP_INDEX(5, 1)] = 227,           /* KEY_STAR */
+	[KEYMAP_INDEX(5, 2)] = 230, /*SOFT2*/ /* 2 */
+	[KEYMAP_INDEX(5, 3)] = KEY_MENU,      /* 1 */
+	[KEYMAP_INDEX(5, 4)] = KEY_7,
+};
+
+static struct gpio_event_matrix_info halibut_matrix_info = {
+	.info.func	= gpio_event_matrix_func,
+	.keymap		= halibut_keymap,
+	.output_gpios	= halibut_row_gpios,
+	.input_gpios	= halibut_col_gpios,
+	.noutputs	= ARRAY_SIZE(halibut_row_gpios),
+	.ninputs	= ARRAY_SIZE(halibut_col_gpios),
+	.settle_time.tv.nsec = 0,
+	.poll_time.tv.nsec = 20 * NSEC_PER_MSEC,
+	.flags		= GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE | GPIOKPF_PRINT_UNMAPPED_KEYS /*| GPIOKPF_PRINT_MAPPED_KEYS*/
+};
+
+struct gpio_event_info *halibut_keypad_info[] = {
+	&halibut_matrix_info.info
+};
+
+static struct gpio_event_platform_data halibut_keypad_data = {
+	.name		= "halibut_keypad",
+	.info		= halibut_keypad_info,
+	.info_count	= ARRAY_SIZE(halibut_keypad_info)
+};
+
+static struct platform_device halibut_keypad_device = {
+	.name	= GPIO_EVENT_DEV_NAME,
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &halibut_keypad_data,
+	},
+};
+
+static int __init halibut_init_keypad(void)
+{
+	if (!machine_is_halibut())
+		return 0;
+	if (halibut_ffa)
+		halibut_matrix_info.keymap = halibut_keymap_ffa;
+	return platform_device_register(&halibut_keypad_device);
+}
+
+device_initcall(halibut_init_keypad);
diff --git a/arch/arm/mach-msm/board-halibut-panel.c b/arch/arm/mach-msm/board-halibut-panel.c
new file mode 100644
index 0000000..2a6a6ed
--- /dev/null
+++ b/arch/arm/mach-msm/board-halibut-panel.c
@@ -0,0 +1,73 @@
+/* linux/arch/arm/mach-msm/board-halibut-mddi.c
+** Author: Brian Swetland <swetland@google.com>
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/leds.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/bootmem.h>
+
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <asm/mach-types.h>
+
+#include <mach/msm_fb.h>
+#include <mach/vreg.h>
+#include <mach/proc_comm.h>
+
+#include "devices.h"
+#include "board-halibut.h"
+
+static void halibut_mddi_power_client(struct msm_mddi_client_data *mddi,
+	int on)
+{
+}
+
+static struct resource resources_msm_fb = {
+	.start = MSM_FB_BASE,
+	.end = MSM_FB_BASE + MSM_FB_SIZE - 1,
+	.flags = IORESOURCE_MEM,
+};
+
+static struct msm_fb_data fb_data = {
+	.xres = 800,
+	.yres = 480,
+	.output_format = 0,
+};
+
+static struct msm_mddi_platform_data mddi_pdata = {
+	.clk_rate = 122880000,
+	.power_client = halibut_mddi_power_client,
+	.fb_resource = &resources_msm_fb,
+	.num_clients = 1,
+	.client_platform_data = {
+		{
+			.product_id = (0x4474 << 16 | 0xc065),
+			.name = "mddi_c_dummy",
+			.id = 0,
+			.client_data = &fb_data,
+			.clk_rate = 0,
+		},
+	},
+};
+
+int __init halibut_init_panel(void)
+{
+	int rc;
+
+	if (!machine_is_halibut())
+		return 0;
+
+	rc = platform_device_register(&msm_device_mdp);
+	if (rc)
+		return rc;
+
+	msm_device_mddi0.dev.platform_data = &mddi_pdata;
+	return platform_device_register(&msm_device_mddi0);
+}
+
+device_initcall(halibut_init_panel);
diff --git a/arch/arm/mach-msm/board-halibut.h b/arch/arm/mach-msm/board-halibut.h
new file mode 100644
index 0000000..edcdacb
--- /dev/null
+++ b/arch/arm/mach-msm/board-halibut.h
@@ -0,0 +1,20 @@
+/* linux/arch/arm/mach-msm/board-trout.h
+ * ** Author: Brian Swetland <swetland@google.com>
+ * */
+#ifndef __ARCH_ARM_MACH_MSM_BOARD_HALIBUT_H
+#define __ARCH_ARM_MACH_MSM_BOARD_HALIBUT_H
+
+#define MSM_PMEM_GPU0_BASE      (0x10000000 + 64*SZ_1M)
+#define MSM_PMEM_GPU0_SIZE      0x800000
+#define MSM_PMEM_MDP_BASE       (MSM_PMEM_GPU0_BASE + MSM_PMEM_GPU0_SIZE)
+#define MSM_PMEM_MDP_SIZE       0x800000
+#define MSM_PMEM_ADSP_BASE      (MSM_PMEM_MDP_BASE + MSM_PMEM_MDP_SIZE)
+#define MSM_PMEM_ADSP_SIZE      0x800000
+#define MSM_PMEM_GPU1_BASE      (MSM_PMEM_ADSP_BASE + MSM_PMEM_ADSP_SIZE)
+#define MSM_PMEM_GPU1_SIZE      0x800000
+#define MSM_FB_BASE		(MSM_PMEM_GPU1_BASE + MSM_PMEM_GPU1_SIZE)
+#define MSM_FB_SIZE             0x200000
+#define MSM_PMEM_CAMERA_BASE	(MSM_FB_BASE + MSM_FB_SIZE)
+#define MSM_PMEM_CAMERA_SIZE	0xA00000
+
+#endif
diff --git a/arch/arm/mach-msm/board-mahimahi-audio.c b/arch/arm/mach-msm/board-mahimahi-audio.c
new file mode 100644
index 0000000..523d187
--- /dev/null
+++ b/arch/arm/mach-msm/board-mahimahi-audio.c
@@ -0,0 +1,283 @@
+/* arch/arm/mach-msm/board-mahimahi-audio.c
+ *
+ * Copyright (C) 2009 HTC Corporation
+ * Copyright (C) 2009 Google Inc.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <mach/msm_qdsp6_audio.h>
+#include <mach/htc_acoustic_qsd.h>
+#include <mach/proc_comm.h>
+
+#include "board-mahimahi.h"
+#include "pmic.h"
+#include "board-mahimahi-tpa2018d1.h"
+
+#if 0
+#define D(fmt, args...) printk(KERN_INFO "Audio: "fmt, ##args)
+#else
+#define D(fmt, args...) do {} while (0)
+#endif
+
+static struct mutex mic_lock;
+static struct mutex bt_sco_lock;
+
+static struct q6_hw_info q6_audio_hw[Q6_HW_COUNT] = {
+	[Q6_HW_HANDSET] = {
+		.min_gain = -2000,
+		.max_gain = 0,
+	},
+	[Q6_HW_HEADSET] = {
+		.min_gain = -2000,
+		.max_gain = 0,
+	},
+	[Q6_HW_SPEAKER] = {
+		.min_gain = -1500,
+		.max_gain = 0,
+	},
+	[Q6_HW_TTY] = {
+		.min_gain = -2000,
+		.max_gain = 0,
+	},
+	[Q6_HW_BT_SCO] = {
+		.min_gain = -2000,
+		.max_gain = 0,
+	},
+	[Q6_HW_BT_A2DP] = {
+		.min_gain = -2000,
+		.max_gain = 0,
+	},
+};
+
+void mahimahi_headset_enable(int en)
+{
+	D("%s %d\n", __func__, en);
+	/* enable audio amp */
+	if (en) mdelay(15);
+	gpio_set_value(MAHIMAHI_AUD_JACKHP_EN, !!en);
+}
+
+void mahimahi_speaker_enable(int en)
+{
+	struct spkr_config_mode scm;
+	memset(&scm, 0, sizeof(scm));
+
+	D("%s %d\n", __func__, en);
+	if (en) {
+		scm.is_right_chan_en = 0;
+		scm.is_left_chan_en = 1;
+		scm.is_stereo_en = 0;
+		scm.is_hpf_en = 1;
+		pmic_spkr_en_mute(LEFT_SPKR, 0);
+		pmic_spkr_en_mute(RIGHT_SPKR, 0);
+		pmic_set_spkr_configuration(&scm);
+		pmic_spkr_en(LEFT_SPKR, 1);
+		pmic_spkr_en(RIGHT_SPKR, 0);
+
+		/* unmute */
+		pmic_spkr_en_mute(LEFT_SPKR, 1);
+	} else {
+		pmic_spkr_en_mute(LEFT_SPKR, 0);
+
+		pmic_spkr_en(LEFT_SPKR, 0);
+		pmic_spkr_en(RIGHT_SPKR, 0);
+
+		pmic_set_spkr_configuration(&scm);
+	}
+
+	if (is_cdma_version(system_rev))
+		tpa2018d1_set_speaker_amp(en);
+}
+
+void mahimahi_receiver_enable(int en)
+{
+	if (is_cdma_version(system_rev) &&
+		((system_rev == 0xC1) || (system_rev == 0xC2))) {
+		struct spkr_config_mode scm;
+		memset(&scm, 0, sizeof(scm));
+
+		D("%s %d\n", __func__, en);
+		if (en) {
+			scm.is_right_chan_en = 1;
+			scm.is_left_chan_en = 0;
+			scm.is_stereo_en = 0;
+			scm.is_hpf_en = 1;
+			pmic_spkr_en_mute(RIGHT_SPKR, 0);
+			pmic_set_spkr_configuration(&scm);
+			pmic_spkr_en(RIGHT_SPKR, 1);
+
+			/* unmute */
+			pmic_spkr_en_mute(RIGHT_SPKR, 1);
+		} else {
+			pmic_spkr_en_mute(RIGHT_SPKR, 0);
+
+			pmic_spkr_en(RIGHT_SPKR, 0);
+
+			pmic_set_spkr_configuration(&scm);
+		}
+	}
+}
+
+static void config_gpio_table(uint32_t *table, int len)
+{
+	int n;
+	unsigned id;
+	for (n = 0; n < len; n++) {
+		id = table[n];
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+	}
+}
+
+static uint32_t bt_sco_enable[] = {
+	PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_OUT, 1, GPIO_OUTPUT,
+			GPIO_NO_PULL, GPIO_2MA),
+	PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_IN, 1, GPIO_INPUT,
+			GPIO_NO_PULL, GPIO_2MA),
+	PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_SYNC, 2, GPIO_INPUT,
+			GPIO_NO_PULL, GPIO_2MA),
+	PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_CLK, 2, GPIO_INPUT,
+			GPIO_NO_PULL, GPIO_2MA),
+};
+
+static uint32_t bt_sco_disable[] = {
+	PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_OUT, 0, GPIO_OUTPUT,
+			GPIO_NO_PULL, GPIO_2MA),
+	PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_IN, 0, GPIO_INPUT,
+			GPIO_NO_PULL, GPIO_2MA),
+	PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_SYNC, 0, GPIO_INPUT,
+			GPIO_NO_PULL, GPIO_2MA),
+	PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_CLK, 0, GPIO_INPUT,
+			GPIO_NO_PULL, GPIO_2MA),
+};
+
+void mahimahi_bt_sco_enable(int en)
+{
+	static int bt_sco_refcount;
+	D("%s %d\n", __func__, en);
+
+	mutex_lock(&bt_sco_lock);
+	if (en) {
+		if (++bt_sco_refcount == 1)
+			config_gpio_table(bt_sco_enable,
+					ARRAY_SIZE(bt_sco_enable));
+	} else {
+		if (--bt_sco_refcount == 0) {
+			config_gpio_table(bt_sco_disable,
+					ARRAY_SIZE(bt_sco_disable));
+			gpio_set_value(MAHIMAHI_BT_PCM_OUT, 0);
+		}
+	}
+	mutex_unlock(&bt_sco_lock);
+}
+
+void mahimahi_mic_enable(int en)
+{
+	static int old_state = 0, new_state = 0;
+
+	D("%s %d\n", __func__, en);
+
+	mutex_lock(&mic_lock);
+	if (!!en)
+		new_state++;
+	else
+		new_state--;
+
+	if (new_state == 1 && old_state == 0) {
+		gpio_set_value(MAHIMAHI_AUD_2V5_EN, 1);
+		mdelay(60);
+	} else if (new_state == 0 && old_state == 1)
+		gpio_set_value(MAHIMAHI_AUD_2V5_EN, 0);
+	else
+		D("%s: do nothing %d %d\n", __func__, old_state, new_state);
+
+	old_state = new_state;
+	mutex_unlock(&mic_lock);
+}
+
+void mahimahi_analog_init(void)
+{
+	D("%s\n", __func__);
+	/* stereo pmic init */
+	pmic_spkr_set_gain(LEFT_SPKR, SPKR_GAIN_PLUS12DB);
+	pmic_spkr_set_gain(RIGHT_SPKR, SPKR_GAIN_PLUS12DB);
+	pmic_spkr_en_right_chan(OFF_CMD);
+	pmic_spkr_en_left_chan(OFF_CMD);
+	pmic_spkr_add_right_left_chan(OFF_CMD);
+	pmic_spkr_en_stereo(OFF_CMD);
+	pmic_spkr_select_usb_with_hpf_20hz(OFF_CMD);
+	pmic_spkr_bypass_mux(OFF_CMD);
+	pmic_spkr_en_hpf(ON_CMD);
+	pmic_spkr_en_sink_curr_from_ref_volt_cir(OFF_CMD);
+	pmic_spkr_set_mux_hpf_corner_freq(SPKR_FREQ_0_73KHZ);
+	pmic_mic_set_volt(MIC_VOLT_1_80V);
+
+	gpio_request(MAHIMAHI_AUD_JACKHP_EN, "aud_jackhp_en");
+	gpio_request(MAHIMAHI_BT_PCM_OUT, "bt_pcm_out");
+
+	gpio_direction_output(MAHIMAHI_AUD_JACKHP_EN, 0);
+
+	mutex_lock(&bt_sco_lock);
+	config_gpio_table(bt_sco_disable,
+			ARRAY_SIZE(bt_sco_disable));
+	gpio_direction_output(MAHIMAHI_BT_PCM_OUT, 0);
+	mutex_unlock(&bt_sco_lock);
+}
+
+int mahimahi_get_rx_vol(uint8_t hw, int level)
+{
+	int vol;
+
+	if (level > 100)
+		level = 100;
+	else if (level < 0)
+		level = 0;
+
+	if (is_cdma_version(system_rev) && hw == Q6_HW_HANDSET) {
+		int handset_volume[6] = { -1600, -1300, -1000, -600, -300, 0 };
+		vol = handset_volume[5 * level / 100];
+	} else {
+		struct q6_hw_info *info;
+		info = &q6_audio_hw[hw];
+		vol = info->min_gain + ((info->max_gain - info->min_gain) * level) / 100;
+	}
+
+	D("%s %d\n", __func__, vol);
+	return vol;
+}
+
+static struct qsd_acoustic_ops acoustic = {
+	.enable_mic_bias = mahimahi_mic_enable,
+};
+
+static struct q6audio_analog_ops ops = {
+	.init = mahimahi_analog_init,
+	.speaker_enable = mahimahi_speaker_enable,
+	.headset_enable = mahimahi_headset_enable,
+	.receiver_enable = mahimahi_receiver_enable,
+	.bt_sco_enable = mahimahi_bt_sco_enable,
+	.int_mic_enable = mahimahi_mic_enable,
+	.ext_mic_enable = mahimahi_mic_enable,
+	.get_rx_vol = mahimahi_get_rx_vol,
+};
+
+void __init mahimahi_audio_init(void)
+{
+	mutex_init(&mic_lock);
+	mutex_init(&bt_sco_lock);
+	q6audio_register_analog_ops(&ops);
+	acoustic_register_ops(&acoustic);
+	if (is_cdma_version(system_rev) &&
+		((system_rev == 0xC1) || (system_rev == 0xC2)))
+		q6audio_set_acdb_file("default_PMIC.acdb");
+}
diff --git a/arch/arm/mach-msm/board-mahimahi-flashlight.c b/arch/arm/mach-msm/board-mahimahi-flashlight.c
new file mode 100644
index 0000000..829b1f1
--- /dev/null
+++ b/arch/arm/mach-msm/board-mahimahi-flashlight.c
@@ -0,0 +1,279 @@
+/*
+ * arch/arm/mach-msm/flashlight.c - flashlight driver
+ *
+ *  Copyright (C) 2009 zion huang <zion_huang@htc.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ */
+
+#define DEBUG
+
+#include <linux/delay.h>
+#include <linux/earlysuspend.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/wakelock.h>
+#include <linux/hrtimer.h>
+#include <mach/msm_iomap.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+
+#include "board-mahimahi-flashlight.h"
+
+struct flashlight_struct {
+	struct led_classdev fl_lcdev;
+	struct early_suspend early_suspend_flashlight;
+	spinlock_t spin_lock;
+	struct hrtimer timer;
+	int brightness;
+	int gpio_torch;
+	int gpio_flash;
+	int flash_duration_ms;
+};
+
+static struct flashlight_struct the_fl;
+
+static inline void toggle(void)
+{
+	gpio_direction_output(the_fl.gpio_torch, 0);
+	udelay(2);
+	gpio_direction_output(the_fl.gpio_torch, 1);
+	udelay(2);
+}
+
+static void flashlight_hw_command(uint8_t addr, uint8_t data)
+{
+	int i;
+
+	for (i = 0; i < addr + 17; i++)
+		toggle();
+	udelay(500);
+
+	for (i = 0; i < data; i++)
+		toggle();
+	udelay(500);
+}
+
+static enum hrtimer_restart flashlight_timeout(struct hrtimer *timer)
+{
+	unsigned long flags;
+
+	pr_debug("%s\n", __func__);
+
+	spin_lock_irqsave(&the_fl.spin_lock, flags);
+	gpio_direction_output(the_fl.gpio_flash, 0);
+	the_fl.brightness = LED_OFF;
+	spin_unlock_irqrestore(&the_fl.spin_lock, flags);
+
+	return HRTIMER_NORESTART;
+}
+
+int flashlight_control(int mode)
+{
+	int ret = 0;
+	unsigned long flags;
+
+	pr_debug("%s: mode %d -> %d\n", __func__,
+			the_fl.brightness, mode);
+
+	spin_lock_irqsave(&the_fl.spin_lock, flags);
+
+	the_fl.brightness = mode;
+
+	switch (mode) {
+	case FLASHLIGHT_TORCH:
+		pr_info("%s: half\n", __func__);
+		/* If we are transitioning from flash to torch, make sure to
+		 * cancel the flash timeout timer, otherwise when it expires,
+		 * the torch will go off as well.
+		 */
+		hrtimer_cancel(&the_fl.timer);
+		flashlight_hw_command(2, 4);
+		break;
+
+	case FLASHLIGHT_FLASH:
+		pr_info("%s: full\n", __func__);
+		hrtimer_cancel(&the_fl.timer);
+		gpio_direction_output(the_fl.gpio_flash, 0);
+		udelay(40);
+		gpio_direction_output(the_fl.gpio_flash, 1);
+		hrtimer_start(&the_fl.timer,
+			ktime_set(the_fl.flash_duration_ms / 1000,
+					(the_fl.flash_duration_ms % 1000) *
+						NSEC_PER_MSEC),
+				HRTIMER_MODE_REL);
+		/* Flash overrides torch mode, and after the flash period, the
+		 * flash LED will turn off.
+		 */
+		mode = LED_OFF;
+		break;
+
+	case FLASHLIGHT_OFF:
+		pr_info("%s: off\n", __func__);
+		gpio_direction_output(the_fl.gpio_flash, 0);
+		gpio_direction_output(the_fl.gpio_torch, 0);
+		break;
+
+	default:
+		pr_err("%s: unknown flash_light flags: %d\n", __func__, mode);
+		ret = -EINVAL;
+		goto done;
+	}
+
+done:
+	spin_unlock_irqrestore(&the_fl.spin_lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL(flashlight_control);
+
+static void fl_lcdev_brightness_set(struct led_classdev *led_cdev,
+		enum led_brightness brightness)
+{
+	int level;
+	switch (brightness) {
+	case LED_HALF:
+		level = FLASHLIGHT_TORCH;
+		break;
+	case LED_FULL:
+		level = FLASHLIGHT_FLASH;
+		break;
+	case LED_OFF:
+	default:
+		level = FLASHLIGHT_OFF;
+	};
+
+	flashlight_control(level);
+}
+
+static void flashlight_early_suspend(struct early_suspend *handler)
+{
+	flashlight_control(FLASHLIGHT_OFF);
+}
+
+static int flashlight_setup_gpio(struct flashlight_platform_data *fl_pdata)
+{
+	int ret;
+
+	pr_debug("%s\n", __func__);
+
+	if (fl_pdata->gpio_init) {
+		ret = fl_pdata->gpio_init();
+		if (ret < 0) {
+			pr_err("%s: gpio init failed: %d\n", __func__,
+				ret);
+			return ret;
+		}
+	}
+
+	if (fl_pdata->torch) {
+		ret = gpio_request(fl_pdata->torch, "flashlight_torch");
+		if (ret < 0) {
+			pr_err("%s: gpio_request failed\n", __func__);
+			return ret;
+		}
+	}
+
+	if (fl_pdata->flash) {
+		ret = gpio_request(fl_pdata->flash, "flashlight_flash");
+		if (ret < 0) {
+			pr_err("%s: gpio_request failed\n", __func__);
+			gpio_free(fl_pdata->torch);
+			return ret;
+		}
+	}
+
+	the_fl.gpio_torch = fl_pdata->torch;
+	the_fl.gpio_flash = fl_pdata->flash;
+	the_fl.flash_duration_ms = fl_pdata->flash_duration_ms;
+	return 0;
+}
+
+static int flashlight_probe(struct platform_device *pdev)
+{
+	struct flashlight_platform_data *fl_pdata = pdev->dev.platform_data;
+	int err = 0;
+
+	pr_debug("%s\n", __func__);
+
+	err = flashlight_setup_gpio(fl_pdata);
+	if (err < 0) {
+		pr_err("%s: setup GPIO failed\n", __func__);
+		goto fail_free_mem;
+	}
+
+	spin_lock_init(&the_fl.spin_lock);
+	the_fl.fl_lcdev.name = pdev->name;
+	the_fl.fl_lcdev.brightness_set = fl_lcdev_brightness_set;
+	the_fl.fl_lcdev.brightness = LED_OFF;
+	err = led_classdev_register(&pdev->dev, &the_fl.fl_lcdev);
+	if (err < 0) {
+		pr_err("failed on led_classdev_register\n");
+		goto fail_free_gpio;
+	}
+
+	hrtimer_init(&the_fl.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	the_fl.timer.function = flashlight_timeout;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	the_fl.early_suspend_flashlight.suspend = flashlight_early_suspend;
+	the_fl.early_suspend_flashlight.resume = NULL;
+	register_early_suspend(&the_fl.early_suspend_flashlight);
+#endif
+
+	return 0;
+
+fail_free_gpio:
+	if (fl_pdata->torch)
+		gpio_free(fl_pdata->torch);
+	if (fl_pdata->flash)
+		gpio_free(fl_pdata->flash);
+fail_free_mem:
+	return err;
+}
+
+static int flashlight_remove(struct platform_device *pdev)
+{
+	struct flashlight_platform_data *fl_pdata = pdev->dev.platform_data;
+
+	pr_debug("%s\n", __func__);
+
+	hrtimer_cancel(&the_fl.timer);
+	unregister_early_suspend(&the_fl.early_suspend_flashlight);
+	flashlight_control(FLASHLIGHT_OFF);
+	led_classdev_unregister(&the_fl.fl_lcdev);
+	if (fl_pdata->torch)
+		gpio_free(fl_pdata->torch);
+	if (fl_pdata->flash)
+		gpio_free(fl_pdata->flash);
+	return 0;
+}
+
+static struct platform_driver flashlight_driver = {
+	.probe		= flashlight_probe,
+	.remove		= flashlight_remove,
+	.driver		= {
+		.name		= FLASHLIGHT_NAME,
+		.owner		= THIS_MODULE,
+	},
+};
+
+static int __init flashlight_init(void)
+{
+	pr_debug("%s\n", __func__);
+	return platform_driver_register(&flashlight_driver);
+}
+
+static void __exit flashlight_exit(void)
+{
+	pr_debug("%s\n", __func__);
+	platform_driver_unregister(&flashlight_driver);
+}
+
+module_init(flashlight_init);
+module_exit(flashlight_exit);
+
+MODULE_AUTHOR("Zion Huang <zion_huang@htc.com>");
+MODULE_DESCRIPTION("flash light driver");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/board-mahimahi-flashlight.h b/arch/arm/mach-msm/board-mahimahi-flashlight.h
new file mode 100644
index 0000000..93b4095
--- /dev/null
+++ b/arch/arm/mach-msm/board-mahimahi-flashlight.h
@@ -0,0 +1,20 @@
+#ifndef __ASM_ARM_ARCH_FLASHLIGHT_H
+#define __ASM_ARM_ARCH_FLASHLIGHT_H
+
+#define FLASHLIGHT_NAME "flashlight"
+
+#define FLASHLIGHT_OFF   0
+#define FLASHLIGHT_TORCH 1
+#define FLASHLIGHT_FLASH 2
+#define FLASHLIGHT_NUM   3
+
+struct flashlight_platform_data {
+	int (*gpio_init) (void);
+	int torch;
+	int flash;
+	int flash_duration_ms;
+};
+
+int flashlight_control(int level);
+
+#endif /*__ASM_ARM_ARCH_FLASHLIGHT_H*/
diff --git a/arch/arm/mach-msm/board-mahimahi-keypad.c b/arch/arm/mach-msm/board-mahimahi-keypad.c
new file mode 100644
index 0000000..ab38847
--- /dev/null
+++ b/arch/arm/mach-msm/board-mahimahi-keypad.c
@@ -0,0 +1,265 @@
+/* arch/arm/mach-msm/board-mahimahi-keypad.c
+ *
+ * Copyright (C) 2009 Google, Inc
+ * Copyright (C) 2009 HTC Corporation.
+ *
+ * Author: Dima Zavin <dima@android.com>
+ *
+ * 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.
+ */
+
+#include <linux/gpio_event.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/keyreset.h>
+#include <linux/platform_device.h>
+#include <mach/vreg.h>
+
+#include <asm/mach-types.h>
+
+#include "board-mahimahi.h"
+
+struct jog_axis_info {
+	struct gpio_event_axis_info	info;
+	uint16_t			in_state;
+	uint16_t			out_state;
+};
+
+static struct vreg *jog_vreg;
+static bool jog_just_on;
+static unsigned long jog_on_jiffies;
+
+static unsigned int mahimahi_col_gpios[] = { 33, 32, 31 };
+static unsigned int mahimahi_row_gpios[] = { 42, 41, 40 };
+
+#define KEYMAP_INDEX(col, row)	((col)*ARRAY_SIZE(mahimahi_row_gpios) + (row))
+#define KEYMAP_SIZE		(ARRAY_SIZE(mahimahi_col_gpios) * \
+				 ARRAY_SIZE(mahimahi_row_gpios))
+
+/* keypad */
+static const unsigned short mahimahi_keymap[KEYMAP_SIZE] = {
+	[KEYMAP_INDEX(0, 0)] = KEY_VOLUMEUP,
+	[KEYMAP_INDEX(0, 1)] = KEY_VOLUMEDOWN,
+	[KEYMAP_INDEX(1, 1)] = MATRIX_KEY(1, BTN_MOUSE),
+};
+
+static const unsigned short mahimahi_cdma_keymap[KEYMAP_SIZE] = {
+	[KEYMAP_INDEX(0, 0)] = KEY_VOLUMEUP,
+	[KEYMAP_INDEX(0, 1)] = KEY_VOLUMEDOWN,
+	[KEYMAP_INDEX(1, 1)] = MATRIX_KEY(1, BTN_MOUSE),
+
+	/* Key (2, 2) is not a physical key on mahimahi. The purpose of
+	 * registering the unused matrix key as a dummy <end> key is to make
+	 * userland able to send/receive the key event for some requested tests
+	 * in lab. of some CDMA carriers (e.g. Verizon).
+	 */
+	[KEYMAP_INDEX(2, 2)] = KEY_END,
+};
+
+static struct gpio_event_matrix_info mahimahi_keypad_matrix_info = {
+	.info.func = gpio_event_matrix_func,
+	.keymap = mahimahi_keymap,
+	.output_gpios = mahimahi_col_gpios,
+	.input_gpios = mahimahi_row_gpios,
+	.noutputs = ARRAY_SIZE(mahimahi_col_gpios),
+	.ninputs = ARRAY_SIZE(mahimahi_row_gpios),
+	.settle_time.tv.nsec = 40 * NSEC_PER_USEC,
+	.poll_time.tv.nsec = 20 * NSEC_PER_MSEC,
+	.flags = (GPIOKPF_LEVEL_TRIGGERED_IRQ |
+		  GPIOKPF_REMOVE_PHANTOM_KEYS |
+		  GPIOKPF_PRINT_UNMAPPED_KEYS),
+};
+
+static struct gpio_event_direct_entry mahimahi_keypad_key_map[] = {
+	{
+		.gpio	= MAHIMAHI_GPIO_POWER_KEY,
+		.code	= KEY_POWER,
+	},
+};
+
+static struct gpio_event_input_info mahimahi_keypad_key_info = {
+	.info.func = gpio_event_input_func,
+	.info.no_suspend = true,
+	.debounce_time.tv.nsec = 5 * NSEC_PER_MSEC,
+	.flags = 0,
+	.type = EV_KEY,
+	.keymap = mahimahi_keypad_key_map,
+	.keymap_size = ARRAY_SIZE(mahimahi_keypad_key_map)
+};
+
+/* jogball */
+static uint16_t jogball_axis_map(struct gpio_event_axis_info *info, uint16_t in)
+{
+	struct jog_axis_info *ai =
+		container_of(info, struct jog_axis_info, info);
+	uint16_t out = ai->out_state;
+
+	if (jog_just_on) {
+		if (jiffies == jog_on_jiffies || jiffies == jog_on_jiffies + 1)
+			goto ignore;
+		jog_just_on = 0;
+	}
+	if((ai->in_state ^ in) & 1)
+		out--;
+	if((ai->in_state ^ in) & 2)
+		out++;
+	ai->out_state = out;
+ignore:
+	ai->in_state = in;
+	return out;
+}
+
+static int jogball_power(const struct gpio_event_platform_data *pdata, bool on)
+{
+	if (on) {
+		vreg_enable(jog_vreg);
+		jog_just_on = 1;
+		jog_on_jiffies = jiffies;
+	} else {
+		vreg_disable(jog_vreg);
+	}
+
+	return 0;
+}
+
+static int jogball_power_cdma(const struct gpio_event_platform_data *pdata, bool on)
+{
+	if (on) {
+		gpio_set_value(MAHIMAHI_CDMA_JOG_2V6_EN, 1);
+		jog_just_on = 1;
+		jog_on_jiffies = jiffies;
+	} else {
+		gpio_set_value(MAHIMAHI_CDMA_JOG_2V6_EN, 0);
+	}
+
+	return 0;
+}
+
+static uint32_t jogball_x_gpios[] = {
+	MAHIMAHI_GPIO_BALL_LEFT, MAHIMAHI_GPIO_BALL_RIGHT,
+};
+static uint32_t jogball_y_gpios[] = {
+	MAHIMAHI_GPIO_BALL_UP, MAHIMAHI_GPIO_BALL_DOWN,
+};
+
+static struct jog_axis_info jogball_x_axis = {
+	.info = {
+		.info.func = gpio_event_axis_func,
+		.count = ARRAY_SIZE(jogball_x_gpios),
+		.dev = 1,
+		.type = EV_REL,
+		.code = REL_X,
+		.decoded_size = 1U << ARRAY_SIZE(jogball_x_gpios),
+		.map = jogball_axis_map,
+		.gpio = jogball_x_gpios,
+		.flags = GPIOEAF_PRINT_UNKNOWN_DIRECTION,
+	}
+};
+
+static struct jog_axis_info jogball_y_axis = {
+	.info = {
+		.info.func = gpio_event_axis_func,
+		.count = ARRAY_SIZE(jogball_y_gpios),
+		.dev = 1,
+		.type = EV_REL,
+		.code = REL_Y,
+		.decoded_size = 1U << ARRAY_SIZE(jogball_y_gpios),
+		.map = jogball_axis_map,
+		.gpio = jogball_y_gpios,
+		.flags = GPIOEAF_PRINT_UNKNOWN_DIRECTION,
+	}
+};
+
+static struct gpio_event_info *mahimahi_input_info[] = {
+	&mahimahi_keypad_matrix_info.info,
+	&mahimahi_keypad_key_info.info,
+	&jogball_x_axis.info.info,
+	&jogball_y_axis.info.info,
+};
+
+static struct gpio_event_platform_data mahimahi_input_data = {
+	.names = {
+		"mahimahi-keypad",
+		"mahimahi-nav",
+		NULL,
+	},
+	.info = mahimahi_input_info,
+	.info_count = ARRAY_SIZE(mahimahi_input_info),
+	.power = jogball_power,
+};
+
+static struct platform_device mahimahi_input_device = {
+	.name = GPIO_EVENT_DEV_NAME,
+	.id = 0,
+	.dev = {
+		.platform_data = &mahimahi_input_data,
+	},
+};
+
+static int mahimahi_reset_keys_up[] = {
+	KEY_VOLUMEUP,
+	0,
+};
+
+static struct keyreset_platform_data mahimahi_reset_keys_pdata = {
+	.keys_up	= mahimahi_reset_keys_up,
+	.keys_down	= {
+		KEY_POWER,
+		KEY_VOLUMEDOWN,
+		BTN_MOUSE,
+		0
+	},
+};
+
+struct platform_device mahimahi_reset_keys_device = {
+	.name	= KEYRESET_NAME,
+	.dev	= {
+		.platform_data = &mahimahi_reset_keys_pdata,
+	},
+};
+
+
+static int __init mahimahi_init_keypad_jogball(void)
+{
+	int ret;
+
+	if (!machine_is_mahimahi())
+		return 0;
+
+	ret = platform_device_register(&mahimahi_reset_keys_device);
+	if (ret != 0)
+		return ret;
+
+	if (is_cdma_version(system_rev)) {
+		mahimahi_keypad_matrix_info.keymap = mahimahi_cdma_keymap;
+		/* In the CDMA version, jogball power is supplied by a gpio. */
+		ret = gpio_request(MAHIMAHI_CDMA_JOG_2V6_EN, "jog_en");
+		if (ret < 0) {
+			pr_err("%s: gpio_request(%d) failed: %d\n", __func__,
+				MAHIMAHI_CDMA_JOG_2V6_EN, ret);
+			return ret;
+		}
+		mahimahi_input_data.power = jogball_power_cdma;
+	} else {
+		/* in UMTS version, jogball power is supplied by pmic */
+		jog_vreg = vreg_get(&mahimahi_input_device.dev, "gp2");
+		if (jog_vreg == NULL)
+			return -ENOENT;
+	}
+
+	ret = platform_device_register(&mahimahi_input_device);
+	if (ret != 0)
+		return ret;
+
+	return 0;
+}
+
+device_initcall(mahimahi_init_keypad_jogball);
diff --git a/arch/arm/mach-msm/board-mahimahi-microp.c b/arch/arm/mach-msm/board-mahimahi-microp.c
new file mode 100644
index 0000000..da30672
--- /dev/null
+++ b/arch/arm/mach-msm/board-mahimahi-microp.c
@@ -0,0 +1,2261 @@
+/* board-mahimahi-microp.c
+ * Copyright (C) 2009 Google.
+ * Copyright (C) 2009 HTC Corporation.
+ *
+ * The Microp on mahimahi is an i2c device that supports
+ * the following functions
+ *   - LEDs (Green, Amber, Jogball backlight)
+ *   - Lightsensor
+ *   - Headset remotekeys
+ *   - G-sensor
+ *   - Interrupts
+ *
+ * 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.
+*/
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/leds.h>
+#include <linux/workqueue.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/miscdevice.h>
+#include <linux/input.h>
+#include <asm/uaccess.h>
+#include <linux/wakelock.h>
+#include <asm/mach-types.h>
+#include <mach/htc_pwrsink.h>
+#include <linux/earlysuspend.h>
+#include <linux/bma150.h>
+#include <linux/lightsensor.h>
+#include <asm/mach/mmc.h>
+#include <mach/htc_35mm_jack.h>
+#include <asm/setup.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/mutex.h>
+#include <linux/jiffies.h>
+
+#include "board-mahimahi.h"
+
+
+#define MICROP_I2C_NAME "mahimahi-microp"
+
+#define MICROP_LSENSOR_ADC_CHAN		6
+#define MICROP_REMOTE_KEY_ADC_CHAN	7
+
+#define MICROP_I2C_WCMD_MISC				0x20
+#define MICROP_I2C_WCMD_SPI_EN				0x21
+#define MICROP_I2C_WCMD_AUTO_BL_CTL			0x23
+#define MICROP_I2C_RCMD_SPI_BL_STATUS			0x24
+#define MICROP_I2C_WCMD_BUTTONS_LED_CTRL		0x25
+#define MICROP_I2C_RCMD_VERSION				0x30
+#define MICROP_I2C_WCMD_ADC_TABLE			0x42
+#define MICROP_I2C_WCMD_LED_MODE			0x53
+#define MICROP_I2C_RCMD_GREEN_LED_REMAIN_TIME		0x54
+#define MICROP_I2C_RCMD_AMBER_RED_LED_REMAIN_TIME	0x55
+#define MICROP_I2C_RCMD_BLUE_LED_REMAIN_TIME		0x57
+#define MICROP_I2C_WCMD_JOGBALL_LED_MODE		0x5A
+#define MICROP_I2C_RCMD_JOGBALL_LED_REMAIN_TIME		0x5B
+#define MICROP_I2C_WCMD_JOGBALL_LED_PWM_SET		0x5C
+#define MICROP_I2C_WCMD_JOGBALL_LED_PERIOD_SET		0x5D
+#define MICROP_I2C_WCMD_READ_ADC_VALUE_REQ		0x60
+#define MICROP_I2C_RCMD_ADC_VALUE			0x62
+#define MICROP_I2C_WCMD_REMOTEKEY_TABLE			0x63
+#define MICROP_I2C_WCMD_LCM_REGISTER			0x70
+#define MICROP_I2C_WCMD_GSENSOR_REG			0x73
+#define MICROP_I2C_WCMD_GSENSOR_REG_DATA_REQ		0x74
+#define MICROP_I2C_RCMD_GSENSOR_REG_DATA		0x75
+#define MICROP_I2C_WCMD_GSENSOR_DATA_REQ		0x76
+#define MICROP_I2C_RCMD_GSENSOR_X_DATA			0x77
+#define MICROP_I2C_RCMD_GSENSOR_Y_DATA			0x78
+#define MICROP_I2C_RCMD_GSENSOR_Z_DATA			0x79
+#define MICROP_I2C_RCMD_GSENSOR_DATA			0x7A
+#define MICROP_I2C_WCMD_OJ_REG				0x7B
+#define MICROP_I2C_WCMD_OJ_REG_DATA_REQ			0x7C
+#define MICROP_I2C_RCMD_OJ_REG_DATA			0x7D
+#define MICROP_I2C_WCMD_OJ_POS_DATA_REQ			0x7E
+#define MICROP_I2C_RCMD_OJ_POS_DATA			0x7F
+#define MICROP_I2C_WCMD_GPI_INT_CTL_EN			0x80
+#define MICROP_I2C_WCMD_GPI_INT_CTL_DIS			0x81
+#define MICROP_I2C_RCMD_GPI_INT_STATUS			0x82
+#define MICROP_I2C_RCMD_GPI_STATUS			0x83
+#define MICROP_I2C_WCMD_GPI_INT_STATUS_CLR		0x84
+#define MICROP_I2C_RCMD_GPI_INT_SETTING			0x85
+#define MICROP_I2C_RCMD_REMOTE_KEYCODE			0x87
+#define MICROP_I2C_WCMD_REMOTE_KEY_DEBN_TIME		0x88
+#define MICROP_I2C_WCMD_REMOTE_PLUG_DEBN_TIME		0x89
+#define MICROP_I2C_WCMD_SIMCARD_DEBN_TIME		0x8A
+#define MICROP_I2C_WCMD_GPO_LED_STATUS_EN		0x90
+#define MICROP_I2C_WCMD_GPO_LED_STATUS_DIS		0x91
+
+#define IRQ_GSENSOR	(1<<10)
+#define IRQ_LSENSOR  	(1<<9)
+#define IRQ_REMOTEKEY	(1<<7)
+#define IRQ_HEADSETIN	(1<<2)
+#define IRQ_SDCARD	(1<<0)
+
+#define READ_GPI_STATE_HPIN	(1<<2)
+#define READ_GPI_STATE_SDCARD	(1<<0)
+
+#define ALS_CALIBRATE_MODE  147
+
+/* Check pattern, to check if ALS has been calibrated */
+#define ALS_CALIBRATED	0x6DA5
+
+/* delay for deferred light sensor read */
+#define LS_READ_DELAY   (HZ/2)
+
+/*#define DEBUG_BMA150  */
+#ifdef DEBUG_BMA150
+/* Debug logging of accelleration data */
+#define GSENSOR_LOG_MAX 2048  /* needs to be power of 2 */
+#define GSENSOR_LOG_MASK (GSENSOR_LOG_MAX - 1)
+
+struct gsensor_log {
+	ktime_t timestamp;
+	short x;
+	short y;
+	short z;
+};
+
+static DEFINE_MUTEX(gsensor_log_lock);
+static struct gsensor_log gsensor_log[GSENSOR_LOG_MAX];
+static unsigned gsensor_log_head;
+static unsigned gsensor_log_tail;
+
+void gsensor_log_status(ktime_t time, short x, short y, short z)
+{
+	unsigned n;
+	mutex_lock(&gsensor_log_lock);
+	n = gsensor_log_head;
+	gsensor_log[n].timestamp = time;
+	gsensor_log[n].x = x;
+	gsensor_log[n].y = y;
+	gsensor_log[n].z = z;
+	n = (n + 1) & GSENSOR_LOG_MASK;
+	if (n == gsensor_log_tail)
+		gsensor_log_tail = (gsensor_log_tail + 1) & GSENSOR_LOG_MASK;
+	gsensor_log_head = n;
+	mutex_unlock(&gsensor_log_lock);
+}
+
+static int gsensor_log_print(struct seq_file *sf, void *private)
+{
+	unsigned n;
+
+	mutex_lock(&gsensor_log_lock);
+	seq_printf(sf, "timestamp                  X      Y      Z\n");
+	for (n = gsensor_log_tail;
+	     n != gsensor_log_head;
+	     n = (n + 1) & GSENSOR_LOG_MASK) {
+		seq_printf(sf, "%10d.%010d %6d %6d %6d\n",
+			   gsensor_log[n].timestamp.tv.sec,
+			   gsensor_log[n].timestamp.tv.nsec,
+			   gsensor_log[n].x, gsensor_log[n].y,
+			   gsensor_log[n].z);
+	}
+	mutex_unlock(&gsensor_log_lock);
+	return 0;
+}
+
+static int gsensor_log_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, gsensor_log_print, NULL);
+}
+
+static struct file_operations gsensor_log_fops = {
+	.open = gsensor_log_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+#endif /* def DEBUG_BMA150 */
+
+static int microp_headset_has_mic(void);
+static int microp_enable_headset_plug_event(void);
+static int microp_enable_key_event(void);
+static int microp_disable_key_event(void);
+
+static struct h35mm_platform_data mahimahi_h35mm_data = {
+	.plug_event_enable = microp_enable_headset_plug_event,
+	.headset_has_mic = microp_headset_has_mic,
+	.key_event_enable = microp_enable_key_event,
+	.key_event_disable = microp_disable_key_event,
+};
+
+static struct platform_device mahimahi_h35mm = {
+	.name           = "htc_headset",
+	.id                     = -1,
+	.dev            = {
+		.platform_data  = &mahimahi_h35mm_data,
+	},
+};
+
+enum led_type {
+	GREEN_LED,
+	AMBER_LED,
+	RED_LED,
+	BLUE_LED,
+	JOGBALL_LED,
+	BUTTONS_LED,
+	NUM_LEDS,
+};
+
+static uint16_t lsensor_adc_table[10] = {
+	0x000, 0x001, 0x00F, 0x01E, 0x03C, 0x121, 0x190, 0x2BA, 0x26E, 0x3FF
+};
+
+static uint16_t remote_key_adc_table[6] = {
+	0, 33, 43, 110, 129, 220
+};
+
+static uint32_t golden_adc = 0xC0;
+static uint32_t als_kadc;
+
+static struct wake_lock microp_i2c_wakelock;
+
+static struct i2c_client *private_microp_client;
+
+struct microp_int_pin {
+	uint16_t int_gsensor;
+	uint16_t int_lsensor;
+	uint16_t int_reset;
+	uint16_t int_simcard;
+	uint16_t int_hpin;
+	uint16_t int_remotekey;
+};
+
+struct microp_led_data {
+	int type;
+	struct led_classdev ldev;
+	struct mutex led_data_mutex;
+	struct work_struct brightness_work;
+	spinlock_t brightness_lock;
+	enum led_brightness brightness;
+	uint8_t mode;
+	uint8_t blink;
+};
+
+struct microp_i2c_work {
+	struct work_struct work;
+	struct i2c_client *client;
+	int (*intr_debounce)(uint8_t *pin_status);
+	void (*intr_function)(uint8_t *pin_status);
+};
+
+struct microp_i2c_client_data {
+	struct microp_led_data leds[NUM_LEDS];
+	uint16_t version;
+	struct microp_i2c_work work;
+	struct delayed_work hpin_debounce_work;
+	struct delayed_work ls_read_work;
+	struct early_suspend early_suspend;
+	uint8_t enable_early_suspend;
+	uint8_t enable_reset_button;
+	int microp_is_suspend;
+	int auto_backlight_enabled;
+	uint8_t light_sensor_enabled;
+	uint8_t force_light_sensor_read;
+	uint8_t button_led_value;
+	int headset_is_in;
+	int is_hpin_pin_stable;
+	struct input_dev *ls_input_dev;
+	uint32_t als_kadc;
+	uint32_t als_gadc;
+	uint8_t als_calibrating;
+};
+
+static char *hex2string(uint8_t *data, int len)
+{
+	static char buf[101];
+	int i;
+
+	i = (sizeof(buf) - 1) / 4;
+	if (len > i)
+		len = i;
+
+	for (i = 0; i < len; i++)
+		sprintf(buf + i * 4, "[%02X]", data[i]);
+
+	return buf;
+}
+
+#define I2C_READ_RETRY_TIMES  10
+#define I2C_WRITE_RETRY_TIMES 10
+
+static int i2c_read_block(struct i2c_client *client, uint8_t addr,
+	uint8_t *data, int length)
+{
+	int retry;
+	int ret;
+	struct i2c_msg msgs[] = {
+	{
+		.addr = client->addr,
+		.flags = 0,
+		.len = 1,
+		.buf = &addr,
+	},
+	{
+		.addr = client->addr,
+		.flags = I2C_M_RD,
+		.len = length,
+		.buf = data,
+	}
+	};
+
+	mdelay(1);
+	for (retry = 0; retry <= I2C_READ_RETRY_TIMES; retry++) {
+		ret = i2c_transfer(client->adapter, msgs, 2);
+		if (ret == 2) {
+			dev_dbg(&client->dev, "R [%02X] = %s\n", addr,
+					hex2string(data, length));
+			return 0;
+		}
+		msleep(10);
+	}
+
+	dev_err(&client->dev, "i2c_read_block retry over %d\n",
+			I2C_READ_RETRY_TIMES);
+	return -EIO;
+}
+
+#define MICROP_I2C_WRITE_BLOCK_SIZE 21
+static int i2c_write_block(struct i2c_client *client, uint8_t addr,
+	uint8_t *data, int length)
+{
+	int retry;
+	uint8_t buf[MICROP_I2C_WRITE_BLOCK_SIZE];
+	int ret;
+
+	struct i2c_msg msg[] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.len = length + 1,
+			.buf = buf,
+		}
+	};
+
+	dev_dbg(&client->dev, "W [%02X] = %s\n", addr,
+			hex2string(data, length));
+
+	if (length + 1 > MICROP_I2C_WRITE_BLOCK_SIZE) {
+		dev_err(&client->dev, "i2c_write_block length too long\n");
+		return -E2BIG;
+	}
+
+	buf[0] = addr;
+	memcpy((void *)&buf[1], (void *)data, length);
+
+	mdelay(1);
+	for (retry = 0; retry <= I2C_WRITE_RETRY_TIMES; retry++) {
+		ret = i2c_transfer(client->adapter, msg, 1);
+		if (ret == 1)
+			return 0;
+		msleep(10);
+	}
+	dev_err(&client->dev, "i2c_write_block retry over %d\n",
+			I2C_WRITE_RETRY_TIMES);
+	return -EIO;
+}
+
+static int microp_read_adc(uint8_t channel, uint16_t *value)
+{
+	struct i2c_client *client;
+	int ret;
+	uint8_t cmd[2], data[2];
+
+	client = private_microp_client;
+	cmd[0] = 0;
+	cmd[1] = channel;
+	ret = i2c_write_block(client, MICROP_I2C_WCMD_READ_ADC_VALUE_REQ,
+			      cmd, 2);
+	if (ret < 0) {
+		dev_err(&client->dev, "%s: request adc fail\n", __func__);
+		return -EIO;
+	}
+
+	ret = i2c_read_block(client, MICROP_I2C_RCMD_ADC_VALUE, data, 2);
+	if (ret < 0) {
+		dev_err(&client->dev, "%s: read adc fail\n", __func__);
+		return -EIO;
+	}
+	*value = data[0] << 8 | data[1];
+	return 0;
+}
+
+static int microp_read_gpi_status(struct i2c_client *client, uint16_t *status)
+{
+	uint8_t data[2];
+	int ret;
+
+	ret = i2c_read_block(client, MICROP_I2C_RCMD_GPI_STATUS, data, 2);
+	if (ret < 0) {
+		dev_err(&client->dev, "%s: read failed\n", __func__);
+		return -EIO;
+	}
+	*status = (data[0] << 8) | data[1];
+	return 0;
+}
+
+static int microp_interrupt_enable(struct i2c_client *client,
+				   uint16_t interrupt_mask)
+{
+	uint8_t data[2];
+	int ret = -1;
+
+	data[0] = interrupt_mask >> 8;
+	data[1] = interrupt_mask & 0xFF;
+	ret = i2c_write_block(client, MICROP_I2C_WCMD_GPI_INT_CTL_EN, data, 2);
+
+	if (ret < 0)
+		dev_err(&client->dev, "%s: enable 0x%x interrupt failed\n",
+			__func__, interrupt_mask);
+	return ret;
+}
+
+static int microp_interrupt_disable(struct i2c_client *client,
+				    uint16_t interrupt_mask)
+{
+	uint8_t data[2];
+	int ret = -1;
+
+	data[0] = interrupt_mask >> 8;
+	data[1] = interrupt_mask & 0xFF;
+	ret = i2c_write_block(client, MICROP_I2C_WCMD_GPI_INT_CTL_DIS, data, 2);
+
+	if (ret < 0)
+		dev_err(&client->dev, "%s: disable 0x%x interrupt failed\n",
+			__func__, interrupt_mask);
+	return ret;
+}
+
+
+/*
+ * SD slot card-detect support
+ */
+static unsigned int sdslot_cd = 0;
+static void (*sdslot_status_cb)(int card_present, void *dev_id);
+static void *sdslot_mmc_dev;
+
+int mahimahi_microp_sdslot_status_register(
+		void (*cb)(int card_present, void *dev_id),
+		void *dev_id)
+{
+	if (sdslot_status_cb)
+		return -EBUSY;
+	sdslot_status_cb = cb;
+	sdslot_mmc_dev = dev_id;
+	return 0;
+}
+
+unsigned int mahimahi_microp_sdslot_status(struct device *dev)
+{
+	return sdslot_cd;
+}
+
+static void mahimahi_microp_sdslot_update_status(int status)
+{
+	sdslot_cd = !(status & READ_GPI_STATE_SDCARD);
+	if (sdslot_status_cb)
+		sdslot_status_cb(sdslot_cd, sdslot_mmc_dev);
+}
+
+/*
+ *Headset Support
+*/
+static void hpin_debounce_do_work(struct work_struct *work)
+{
+	uint16_t gpi_status = 0;
+	struct microp_i2c_client_data *cdata;
+	int insert = 0;
+	struct i2c_client *client;
+
+	client = private_microp_client;
+	cdata = i2c_get_clientdata(client);
+
+	microp_read_gpi_status(client, &gpi_status);
+	insert = (gpi_status & READ_GPI_STATE_HPIN) ? 0 : 1;
+	if (insert != cdata->headset_is_in) {
+		cdata->headset_is_in = insert;
+		pr_debug("headset %s\n", insert ? "inserted" : "removed");
+		htc_35mm_jack_plug_event(cdata->headset_is_in,
+					 &cdata->is_hpin_pin_stable);
+	}
+}
+
+static int microp_enable_headset_plug_event(void)
+{
+	int ret;
+	struct i2c_client *client;
+	struct microp_i2c_client_data *cdata;
+	uint16_t stat;
+
+	client = private_microp_client;
+	cdata = i2c_get_clientdata(client);
+
+	/* enable microp interrupt to detect changes */
+	ret = microp_interrupt_enable(client, IRQ_HEADSETIN);
+	if (ret < 0) {
+		dev_err(&client->dev, "%s: failed to enable irqs\n",
+			__func__);
+		return 0;
+	}
+	/* see if headset state has changed */
+	microp_read_gpi_status(client, &stat);
+	stat = !(stat & READ_GPI_STATE_HPIN);
+	if(cdata->headset_is_in != stat) {
+		cdata->headset_is_in = stat;
+		pr_debug("Headset state changed\n");
+		htc_35mm_jack_plug_event(stat, &cdata->is_hpin_pin_stable);
+	}
+
+	return 1;
+}
+
+static int microp_headset_detect_mic(void)
+{
+	uint16_t data;
+
+	microp_read_adc(MICROP_REMOTE_KEY_ADC_CHAN, &data);
+	if (data >= 200)
+		return 1;
+	else
+		return 0;
+}
+
+static int microp_headset_has_mic(void)
+{
+	int mic1 = -1;
+	int mic2 = -1;
+	int count = 0;
+
+	mic2 = microp_headset_detect_mic();
+
+	/* debounce the detection wait until 2 consecutive read are equal */
+	while ((mic1 != mic2) && (count < 10)) {
+		mic1 = mic2;
+		msleep(600);
+		mic2 = microp_headset_detect_mic();
+		count++;
+	}
+
+	pr_info("%s: microphone (%d) %s\n", __func__, count,
+		mic1 ? "present" : "not present");
+
+	return mic1;
+}
+
+static int microp_enable_key_event(void)
+{
+	int ret;
+	struct i2c_client *client;
+
+	client = private_microp_client;
+
+	if (!is_cdma_version(system_rev))
+		gpio_set_value(MAHIMAHI_GPIO_35MM_KEY_INT_SHUTDOWN, 1);
+
+	/* turn on  key interrupt */
+	/* enable microp interrupt to detect changes */
+	ret = microp_interrupt_enable(client, IRQ_REMOTEKEY);
+	if (ret < 0) {
+		dev_err(&client->dev, "%s: failed to enable irqs\n",
+			__func__);
+		return ret;
+	}
+	return 0;
+}
+
+static int microp_disable_key_event(void)
+{
+	int ret;
+	struct i2c_client *client;
+
+	client = private_microp_client;
+
+	/* shutdown key interrupt */
+	if (!is_cdma_version(system_rev))
+		gpio_set_value(MAHIMAHI_GPIO_35MM_KEY_INT_SHUTDOWN, 0);
+
+	/* disable microp interrupt to detect changes */
+	ret = microp_interrupt_disable(client, IRQ_REMOTEKEY);
+	if (ret < 0) {
+		dev_err(&client->dev, "%s: failed to disable irqs\n",
+			__func__);
+		return ret;
+	}
+	return 0;
+}
+
+static int get_remote_keycode(int *keycode)
+{
+	struct i2c_client *client = private_microp_client;
+	int ret;
+	uint8_t data[2];
+
+	ret = i2c_read_block(client, MICROP_I2C_RCMD_REMOTE_KEYCODE, data, 2);
+	if (ret < 0) {
+		dev_err(&client->dev, "%s: read remote keycode fail\n",
+			 __func__);
+		return -EIO;
+	}
+	pr_debug("%s: key = 0x%x\n", __func__, data[1]);
+	if (!data[1]) {
+		*keycode = 0;
+		return 1;		/* no keycode */
+	} else {
+		*keycode = data[1];
+	}
+	return 0;
+}
+
+static ssize_t microp_i2c_remotekey_adc_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct i2c_client *client;
+	uint16_t value;
+	int i, button = 0;
+	int ret;
+
+	client = to_i2c_client(dev);
+
+	microp_read_adc(MICROP_REMOTE_KEY_ADC_CHAN, &value);
+
+	for (i = 0; i < 3; i++) {
+		if ((value >= remote_key_adc_table[2 * i]) &&
+		    (value <= remote_key_adc_table[2 * i + 1])) {
+			button = i + 1;
+		}
+
+	}
+
+	ret = sprintf(buf, "Remote Key[0x%03X] => button %d\n",
+		      value, button);
+
+	return ret;
+}
+
+static DEVICE_ATTR(key_adc, 0644, microp_i2c_remotekey_adc_show, NULL);
+
+/*
+ * LED support
+*/
+static int microp_i2c_write_led_mode(struct i2c_client *client,
+				struct led_classdev *led_cdev,
+				uint8_t mode, uint16_t off_timer)
+{
+	struct microp_i2c_client_data *cdata;
+	struct microp_led_data *ldata;
+	uint8_t data[7];
+	int ret;
+
+	cdata = i2c_get_clientdata(client);
+	ldata = container_of(led_cdev, struct microp_led_data, ldev);
+
+
+	if (ldata->type == GREEN_LED) {
+		data[0] = 0x01;
+		data[1] = mode;
+		data[2] = off_timer >> 8;
+		data[3] = off_timer & 0xFF;
+		data[4] = 0x00;
+		data[5] = 0x00;
+		data[6] = 0x00;
+	} else if (ldata->type == AMBER_LED) {
+		data[0] = 0x02;
+		data[1] = 0x00;
+		data[2] = 0x00;
+		data[3] = 0x00;
+		data[4] = mode;
+		data[5] = off_timer >> 8;
+		data[6] = off_timer & 0xFF;
+	} else if (ldata->type == RED_LED) {
+		data[0] = 0x02;
+		data[1] = 0x00;
+		data[2] = 0x00;
+		data[3] = 0x00;
+		data[4] = mode? 5: 0;
+		data[5] = off_timer >> 8;
+		data[6] = off_timer & 0xFF;
+	} else if (ldata->type == BLUE_LED) {
+		data[0] = 0x04;
+		data[1] = mode;
+		data[2] = off_timer >> 8;
+		data[3] = off_timer & 0xFF;
+		data[4] = 0x00;
+		data[5] = 0x00;
+		data[6] = 0x00;
+	}
+
+	ret = i2c_write_block(client, MICROP_I2C_WCMD_LED_MODE, data, 7);
+	if (ret == 0) {
+		mutex_lock(&ldata->led_data_mutex);
+		if (mode > 1)
+			ldata->blink = mode;
+		else
+			ldata->mode = mode;
+		mutex_unlock(&ldata->led_data_mutex);
+	}
+	return ret;
+}
+
+static ssize_t microp_i2c_led_blink_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *led_cdev;
+	struct microp_led_data *ldata;
+	int ret;
+
+	led_cdev = (struct led_classdev *)dev_get_drvdata(dev);
+	ldata = container_of(led_cdev, struct microp_led_data, ldev);
+
+	mutex_lock(&ldata->led_data_mutex);
+	ret = sprintf(buf, "%d\n", ldata->blink ? ldata->blink - 1 : 0);
+	mutex_unlock(&ldata->led_data_mutex);
+
+	return ret;
+}
+
+static ssize_t microp_i2c_led_blink_store(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	struct led_classdev *led_cdev;
+	struct microp_led_data *ldata;
+	struct i2c_client *client;
+	int val, ret;
+	uint8_t mode;
+
+	val = -1;
+	sscanf(buf, "%u", &val);
+
+	led_cdev = (struct led_classdev *)dev_get_drvdata(dev);
+	ldata = container_of(led_cdev, struct microp_led_data, ldev);
+	client = to_i2c_client(dev->parent);
+
+	mutex_lock(&ldata->led_data_mutex);
+	switch (val) {
+	case 0: /* stop flashing */
+		mode = ldata->mode;
+		ldata->blink = 0;
+		break;
+	case 1:
+	case 2:
+	case 3:
+		mode = val + 1;
+		break;
+
+	default:
+		mutex_unlock(&ldata->led_data_mutex);
+		return -EINVAL;
+	}
+	mutex_unlock(&ldata->led_data_mutex);
+
+	ret = microp_i2c_write_led_mode(client, led_cdev, mode, 0xffff);
+	if (ret)
+		dev_err(&client->dev, "%s set blink failed\n", led_cdev->name);
+
+	return count;
+}
+
+static DEVICE_ATTR(blink, 0644, microp_i2c_led_blink_show,
+				microp_i2c_led_blink_store);
+
+static ssize_t microp_i2c_led_off_timer_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct microp_i2c_client_data *cdata;
+	struct led_classdev *led_cdev;
+	struct microp_led_data *ldata;
+	struct i2c_client *client;
+	uint8_t data[2];
+	int ret, offtime;
+
+
+	led_cdev = (struct led_classdev *)dev_get_drvdata(dev);
+	ldata = container_of(led_cdev, struct microp_led_data, ldev);
+	client = to_i2c_client(dev->parent);
+	cdata = i2c_get_clientdata(client);
+
+	dev_dbg(&client->dev, "Getting %s remaining time\n", led_cdev->name);
+
+	if (ldata->type == GREEN_LED) {
+		ret = i2c_read_block(client,
+				MICROP_I2C_RCMD_GREEN_LED_REMAIN_TIME, data, 2);
+	} else if (ldata->type == AMBER_LED) {
+		ret = i2c_read_block(client,
+				MICROP_I2C_RCMD_AMBER_RED_LED_REMAIN_TIME,
+				data, 2);
+	} else if (ldata->type == RED_LED) {
+		ret = i2c_read_block(client,
+				MICROP_I2C_RCMD_AMBER_RED_LED_REMAIN_TIME,
+				data, 2);
+	} else if (ldata->type == BLUE_LED) {
+		ret = i2c_read_block(client,
+				MICROP_I2C_RCMD_BLUE_LED_REMAIN_TIME, data, 2);
+	} else {
+		dev_err(&client->dev, "Unknown led %s\n", ldata->ldev.name);
+		return -EINVAL;
+	}
+
+	if (ret) {
+		dev_err(&client->dev,
+			"%s get off_timer failed\n", led_cdev->name);
+	}
+	offtime = (int)((data[1] | data[0] << 8) * 2);
+
+	ret = sprintf(buf, "Time remains %d:%d\n", offtime / 60, offtime % 60);
+	return ret;
+}
+
+static ssize_t microp_i2c_led_off_timer_store(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	struct led_classdev *led_cdev;
+	struct microp_led_data *ldata;
+	struct i2c_client *client;
+	int min, sec, ret;
+	uint16_t off_timer;
+
+	min = -1;
+	sec = -1;
+	sscanf(buf, "%d %d", &min, &sec);
+
+	if (min < 0 || min > 255)
+		return -EINVAL;
+	if (sec < 0 || sec > 255)
+		return -EINVAL;
+
+	led_cdev = (struct led_classdev *)dev_get_drvdata(dev);
+	ldata = container_of(led_cdev, struct microp_led_data, ldev);
+	client = to_i2c_client(dev->parent);
+
+	dev_dbg(&client->dev, "Setting %s off_timer to %d min %d sec\n",
+			led_cdev->name, min, sec);
+
+	if (!min && !sec)
+		off_timer = 0xFFFF;
+	else
+		off_timer = (min * 60 + sec) / 2;
+
+	ret = microp_i2c_write_led_mode(client, led_cdev,
+					ldata->mode, off_timer);
+	if (ret) {
+		dev_err(&client->dev,
+			"%s set off_timer %d min %d sec failed\n",
+			led_cdev->name, min, sec);
+	}
+	return count;
+}
+
+static DEVICE_ATTR(off_timer, 0644, microp_i2c_led_off_timer_show,
+			microp_i2c_led_off_timer_store);
+
+static ssize_t microp_i2c_jogball_color_store(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	struct led_classdev *led_cdev;
+	struct microp_led_data *ldata;
+	struct i2c_client *client;
+	int rpwm, gpwm, bpwm, ret;
+	uint8_t data[4];
+
+	rpwm = -1;
+	gpwm = -1;
+	bpwm = -1;
+	sscanf(buf, "%d %d %d", &rpwm, &gpwm, &bpwm);
+
+	if (rpwm < 0 || rpwm > 255)
+		return -EINVAL;
+	if (gpwm < 0 || gpwm > 255)
+		return -EINVAL;
+	if (bpwm < 0 || bpwm > 255)
+		return -EINVAL;
+
+	led_cdev = (struct led_classdev *)dev_get_drvdata(dev);
+	ldata = container_of(led_cdev, struct microp_led_data, ldev);
+	client = to_i2c_client(dev->parent);
+
+	dev_dbg(&client->dev, "Setting %s color to R=%d, G=%d, B=%d\n",
+			led_cdev->name, rpwm, gpwm, bpwm);
+
+	data[0] = rpwm;
+	data[1] = gpwm;
+	data[2] = bpwm;
+	data[3] = 0x00;
+
+	ret = i2c_write_block(client, MICROP_I2C_WCMD_JOGBALL_LED_PWM_SET,
+			      data, 4);
+	if (ret) {
+		dev_err(&client->dev,
+			"%s set color R=%d G=%d B=%d failed\n",
+			led_cdev->name, rpwm, gpwm, bpwm);
+	}
+	return count;
+}
+
+static DEVICE_ATTR(color, 0644, NULL, microp_i2c_jogball_color_store);
+
+static ssize_t microp_i2c_jogball_period_store(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	struct led_classdev *led_cdev;
+	struct microp_led_data *ldata;
+	struct i2c_client *client;
+	int period = -1;
+	int ret;
+	uint8_t data[4];
+
+	sscanf(buf, "%d", &period);
+
+	if (period < 2 || period > 12)
+		return -EINVAL;
+
+	led_cdev = (struct led_classdev *)dev_get_drvdata(dev);
+	ldata = container_of(led_cdev, struct microp_led_data, ldev);
+	client = to_i2c_client(dev->parent);
+
+	dev_info(&client->dev, "Setting Jogball flash period to %d\n", period);
+
+	data[0] = 0x00;
+	data[1] = period;
+
+	ret = i2c_write_block(client, MICROP_I2C_WCMD_JOGBALL_LED_PERIOD_SET,
+			      data, 2);
+	if (ret) {
+		dev_err(&client->dev, "%s set period=%d failed\n",
+			led_cdev->name, period);
+	}
+	return count;
+}
+
+static DEVICE_ATTR(period, 0644, NULL, microp_i2c_jogball_period_store);
+
+static void microp_brightness_set(struct led_classdev *led_cdev,
+			       enum led_brightness brightness)
+{
+	unsigned long flags;
+	struct i2c_client *client = to_i2c_client(led_cdev->dev->parent);
+	struct microp_led_data *ldata =
+		container_of(led_cdev, struct microp_led_data, ldev);
+
+	dev_dbg(&client->dev, "Setting %s brightness current %d new %d\n",
+			led_cdev->name, led_cdev->brightness, brightness);
+
+	if (brightness > 255)
+		brightness = 255;
+	led_cdev->brightness = brightness;
+
+	spin_lock_irqsave(&ldata->brightness_lock, flags);
+	ldata->brightness = brightness;
+	spin_unlock_irqrestore(&ldata->brightness_lock, flags);
+
+	schedule_work(&ldata->brightness_work);
+}
+
+static void microp_led_brightness_set_work(struct work_struct *work)
+{
+	unsigned long flags;
+	struct microp_led_data *ldata =
+		container_of(work, struct microp_led_data, brightness_work);
+	struct led_classdev *led_cdev = &ldata->ldev;
+
+	struct i2c_client *client = to_i2c_client(led_cdev->dev->parent);
+
+	enum led_brightness brightness;
+	int ret;
+	uint8_t mode;
+
+	spin_lock_irqsave(&ldata->brightness_lock, flags);
+	brightness = ldata->brightness;
+	spin_unlock_irqrestore(&ldata->brightness_lock, flags);
+
+	if (brightness)
+		mode = 1;
+	else
+		mode = 0;
+
+	ret = microp_i2c_write_led_mode(client, led_cdev, mode, 0xffff);
+	if (ret) {
+		dev_err(&client->dev,
+			 "led_brightness_set failed to set mode\n");
+	}
+}
+
+struct device_attribute *green_amber_attrs[] = {
+	&dev_attr_blink,
+	&dev_attr_off_timer,
+};
+
+struct device_attribute *jogball_attrs[] = {
+	&dev_attr_color,
+	&dev_attr_period,
+};
+
+static void microp_led_buttons_brightness_set_work(struct work_struct *work)
+{
+
+	unsigned long flags;
+	struct microp_led_data *ldata =
+		container_of(work, struct microp_led_data, brightness_work);
+	struct led_classdev *led_cdev = &ldata->ldev;
+
+	struct i2c_client *client = to_i2c_client(led_cdev->dev->parent);
+	struct microp_i2c_client_data *cdata = i2c_get_clientdata(client);
+
+
+	uint8_t data[4] = {0, 0, 0};
+	int ret = 0;
+	enum led_brightness brightness;
+	uint8_t value;
+
+
+	spin_lock_irqsave(&ldata->brightness_lock, flags);
+	brightness = ldata->brightness;
+	spin_unlock_irqrestore(&ldata->brightness_lock, flags);
+
+	value = brightness >= 255 ? 0x20 : 0;
+
+	/* avoid a flicker that can occur when writing the same value */
+	if (cdata->button_led_value == value)
+		return;
+	cdata->button_led_value = value;
+
+	/* in 40ms */
+	data[0] = 0x05;
+	/* duty cycle 0-255 */
+	data[1] = value;
+	/* bit2 == change brightness */
+	data[3] = 0x04;
+
+	ret = i2c_write_block(client, MICROP_I2C_WCMD_BUTTONS_LED_CTRL,
+			      data, 4);
+	if (ret < 0)
+		dev_err(&client->dev, "%s failed on set buttons\n", __func__);
+}
+
+static void microp_led_jogball_brightness_set_work(struct work_struct *work)
+{
+	unsigned long flags;
+	struct microp_led_data *ldata =
+		container_of(work, struct microp_led_data, brightness_work);
+	struct led_classdev *led_cdev = &ldata->ldev;
+
+	struct i2c_client *client = to_i2c_client(led_cdev->dev->parent);
+	uint8_t data[3] = {0, 0, 0};
+	int ret = 0;
+	enum led_brightness brightness;
+
+	spin_lock_irqsave(&ldata->brightness_lock, flags);
+	brightness = ldata->brightness;
+	spin_unlock_irqrestore(&ldata->brightness_lock, flags);
+
+	switch (brightness) {
+	case 0:
+		data[0] = 0;
+		break;
+	case 3:
+		data[0] = 1;
+		data[1] = data[2] = 0xFF;
+		break;
+	case 7:
+		data[0] = 2;
+		data[1] = 0;
+		data[2] = 60;
+		break;
+	default:
+		dev_warn(&client->dev, "%s: unknown value: %d\n",
+			__func__, brightness);
+		break;
+	}
+	ret = i2c_write_block(client, MICROP_I2C_WCMD_JOGBALL_LED_MODE,
+			      data, 3);
+	if (ret < 0)
+		dev_err(&client->dev, "%s failed on set jogball mode:0x%2.2X\n",
+				__func__, data[0]);
+}
+
+/*
+ * Light Sensor Support
+ */
+static int microp_i2c_auto_backlight_mode(struct i2c_client *client,
+					    uint8_t enabled)
+{
+	uint8_t data[2];
+	int ret = 0;
+
+	data[0] = 0;
+	if (enabled)
+		data[1] = 1;
+	else
+		data[1] = 0;
+
+	ret = i2c_write_block(client, MICROP_I2C_WCMD_AUTO_BL_CTL, data, 2);
+	if (ret != 0)
+		pr_err("%s: set auto light sensor fail\n", __func__);
+
+	return ret;
+}
+
+static int lightsensor_enable(void)
+{
+	struct i2c_client *client;
+	struct microp_i2c_client_data *cdata;
+	int ret;
+
+	client = private_microp_client;
+	cdata = i2c_get_clientdata(client);
+
+	if (cdata->microp_is_suspend) {
+		pr_err("%s: abort, uP is going to suspend after #\n",
+		       __func__);
+		return -EIO;
+	}
+
+	disable_irq(client->irq);
+	ret = microp_i2c_auto_backlight_mode(client, 1);
+	if (ret < 0) {
+		pr_err("%s: set auto light sensor fail\n", __func__);
+		enable_irq(client->irq);
+		return ret;
+	}
+
+	cdata->auto_backlight_enabled = 1;
+	/* TEMPORARY HACK: schedule a deferred light sensor read
+	 * to work around sensor manager race condition
+	 */
+	schedule_delayed_work(&cdata->ls_read_work, LS_READ_DELAY);
+	schedule_work(&cdata->work.work);
+
+	return 0;
+}
+
+static int lightsensor_disable(void)
+{
+	/* update trigger data when done */
+	struct i2c_client *client;
+	struct microp_i2c_client_data *cdata;
+	int ret;
+
+	client = private_microp_client;
+	cdata = i2c_get_clientdata(client);
+
+	if (cdata->microp_is_suspend) {
+		pr_err("%s: abort, uP is going to suspend after #\n",
+		       __func__);
+		return -EIO;
+	}
+
+	cancel_delayed_work(&cdata->ls_read_work);
+
+	ret = microp_i2c_auto_backlight_mode(client, 0);
+	if (ret < 0)
+		pr_err("%s: disable auto light sensor fail\n",
+		       __func__);
+	else
+		cdata->auto_backlight_enabled = 0;
+	return 0;
+}
+
+static int microp_lightsensor_read(uint16_t *adc_value,
+					  uint8_t *adc_level)
+{
+	struct i2c_client *client;
+	struct microp_i2c_client_data *cdata;
+	uint8_t i;
+	int ret;
+
+	client = private_microp_client;
+	cdata = i2c_get_clientdata(client);
+
+	ret = microp_read_adc(MICROP_LSENSOR_ADC_CHAN, adc_value);
+	if (ret != 0)
+		return -1;
+
+	if (*adc_value > 0x3FF) {
+		pr_warning("%s: get wrong value: 0x%X\n",
+			__func__, *adc_value);
+		return -1;
+	} else {
+		if (!cdata->als_calibrating) {
+			*adc_value = *adc_value
+				* cdata->als_gadc / cdata->als_kadc;
+			if (*adc_value > 0x3FF)
+				*adc_value = 0x3FF;
+		}
+
+		*adc_level = ARRAY_SIZE(lsensor_adc_table) - 1;
+		for (i = 0; i < ARRAY_SIZE(lsensor_adc_table); i++) {
+			if (*adc_value <= lsensor_adc_table[i]) {
+				*adc_level = i;
+				break;
+			}
+		}
+		pr_debug("%s: ADC value: 0x%X, level: %d #\n",
+				__func__, *adc_value, *adc_level);
+	}
+
+	return 0;
+}
+
+static ssize_t microp_i2c_lightsensor_adc_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	uint8_t adc_level = 0;
+	uint16_t adc_value = 0;
+	int ret;
+
+	ret = microp_lightsensor_read(&adc_value, &adc_level);
+
+	ret = sprintf(buf, "ADC[0x%03X] => level %d\n", adc_value, adc_level);
+
+	return ret;
+}
+
+static DEVICE_ATTR(ls_adc, 0644, microp_i2c_lightsensor_adc_show, NULL);
+
+static ssize_t microp_i2c_ls_auto_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct i2c_client *client;
+	uint8_t data[2] = {0, 0};
+	int ret;
+
+	client = to_i2c_client(dev);
+
+	i2c_read_block(client, MICROP_I2C_RCMD_SPI_BL_STATUS, data, 2);
+	ret = sprintf(buf, "Light sensor Auto = %d, SPI enable = %d\n",
+			data[0], data[1]);
+
+	return ret;
+}
+
+static ssize_t microp_i2c_ls_auto_store(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	struct i2c_client *client;
+	struct microp_i2c_client_data *cdata;
+	uint8_t enable = 0;
+	int ls_auto;
+
+	ls_auto = -1;
+	sscanf(buf, "%d", &ls_auto);
+
+	if (ls_auto != 0 && ls_auto != 1 && ls_auto != ALS_CALIBRATE_MODE)
+		return -EINVAL;
+
+	client = to_i2c_client(dev);
+	cdata = i2c_get_clientdata(client);
+
+	if (ls_auto) {
+		enable = 1;
+		cdata->als_calibrating = (ls_auto == ALS_CALIBRATE_MODE) ? 1 : 0;
+		cdata->auto_backlight_enabled = 1;
+	} else {
+		enable = 0;
+		cdata->als_calibrating = 0;
+		cdata->auto_backlight_enabled = 0;
+	}
+
+	microp_i2c_auto_backlight_mode(client, enable);
+
+	return count;
+}
+
+static DEVICE_ATTR(ls_auto, 0644,  microp_i2c_ls_auto_show,
+			microp_i2c_ls_auto_store);
+
+DEFINE_MUTEX(api_lock);
+static int lightsensor_opened;
+
+static int lightsensor_open(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	pr_debug("%s\n", __func__);
+	mutex_lock(&api_lock);
+	if (lightsensor_opened) {
+		pr_err("%s: already opened\n", __func__);
+		rc = -EBUSY;
+	}
+	lightsensor_opened = 1;
+	mutex_unlock(&api_lock);
+	return rc;
+}
+
+static int lightsensor_release(struct inode *inode, struct file *file)
+{
+	pr_debug("%s\n", __func__);
+	mutex_lock(&api_lock);
+	lightsensor_opened = 0;
+	mutex_unlock(&api_lock);
+	return 0;
+}
+
+static long lightsensor_ioctl(struct file *file, unsigned int cmd,
+		unsigned long arg)
+{
+	int rc, val;
+	struct i2c_client *client;
+	struct microp_i2c_client_data *cdata;
+
+	mutex_lock(&api_lock);
+
+	client = private_microp_client;
+	cdata = i2c_get_clientdata(client);
+
+	pr_debug("%s cmd %d\n", __func__, _IOC_NR(cmd));
+
+	switch (cmd) {
+	case LIGHTSENSOR_IOCTL_ENABLE:
+		if (get_user(val, (unsigned long __user *)arg)) {
+			rc = -EFAULT;
+			break;
+		}
+		rc = val ? lightsensor_enable() : lightsensor_disable();
+		break;
+	case LIGHTSENSOR_IOCTL_GET_ENABLED:
+		val = cdata->auto_backlight_enabled;
+		pr_debug("%s enabled %d\n", __func__, val);
+		rc = put_user(val, (unsigned long __user *)arg);
+		break;
+	default:
+		pr_err("%s: invalid cmd %d\n", __func__, _IOC_NR(cmd));
+		rc = -EINVAL;
+	}
+
+	mutex_unlock(&api_lock);
+	return rc;
+}
+
+static struct file_operations lightsensor_fops = {
+	.owner = THIS_MODULE,
+	.open = lightsensor_open,
+	.release = lightsensor_release,
+	.unlocked_ioctl = lightsensor_ioctl
+};
+
+struct miscdevice lightsensor_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "lightsensor",
+	.fops = &lightsensor_fops
+};
+
+/*
+ * G-sensor
+ */
+static int microp_spi_enable(uint8_t on)
+{
+	struct i2c_client *client;
+	int ret;
+
+	client = private_microp_client;
+	ret = i2c_write_block(client, MICROP_I2C_WCMD_SPI_EN, &on, 1);
+	if (ret < 0) {
+		dev_err(&client->dev,"%s: i2c_write_block fail\n", __func__);
+		return ret;
+	}
+	msleep(10);
+	return ret;
+}
+
+static int gsensor_read_reg(uint8_t reg, uint8_t *data)
+{
+	struct i2c_client *client;
+	int ret;
+	uint8_t tmp[2];
+
+	client = private_microp_client;
+	ret = i2c_write_block(client, MICROP_I2C_WCMD_GSENSOR_REG_DATA_REQ,
+			      &reg, 1);
+	if (ret < 0) {
+		dev_err(&client->dev,"%s: i2c_write_block fail\n", __func__);
+		return ret;
+	}
+	msleep(10);
+
+	ret = i2c_read_block(client, MICROP_I2C_RCMD_GSENSOR_REG_DATA, tmp, 2);
+	if (ret < 0) {
+		dev_err(&client->dev,"%s: i2c_read_block fail\n", __func__);
+		return ret;
+	}
+	*data = tmp[1];
+	return ret;
+}
+
+static int gsensor_write_reg(uint8_t reg, uint8_t data)
+{
+	struct i2c_client *client;
+	int ret;
+	uint8_t tmp[2];
+
+	client = private_microp_client;
+
+	tmp[0] = reg;
+	tmp[1] = data;
+	ret = i2c_write_block(client, MICROP_I2C_WCMD_GSENSOR_REG, tmp, 2);
+	if (ret < 0) {
+		dev_err(&client->dev,"%s: i2c_write_block fail\n", __func__);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int gsensor_read_acceleration(short *buf)
+{
+	struct i2c_client *client;
+	int ret;
+	uint8_t tmp[6];
+	struct microp_i2c_client_data *cdata;
+
+	client = private_microp_client;
+
+	cdata = i2c_get_clientdata(client);
+
+	tmp[0] = 1;
+	ret = i2c_write_block(client, MICROP_I2C_WCMD_GSENSOR_DATA_REQ,
+			      tmp, 1);
+	if (ret < 0) {
+		dev_err(&client->dev,"%s: i2c_write_block fail\n", __func__);
+		return ret;
+	}
+
+	msleep(10);
+
+	if (cdata->version <= 0x615) {
+		/*
+		 * Note the data is a 10bit signed value from the chip.
+		*/
+		ret = i2c_read_block(client, MICROP_I2C_RCMD_GSENSOR_X_DATA,
+				     tmp, 2);
+		if (ret < 0) {
+			dev_err(&client->dev, "%s: i2c_read_block fail\n",
+				__func__);
+			return ret;
+		}
+		buf[0] = (short)(tmp[0] << 8 | tmp[1]);
+		buf[0] >>= 6;
+
+		ret = i2c_read_block(client, MICROP_I2C_RCMD_GSENSOR_Y_DATA,
+				     tmp, 2);
+		if (ret < 0) {
+			dev_err(&client->dev, "%s: i2c_read_block fail\n",
+				__func__);
+			return ret;
+		}
+		buf[1] = (short)(tmp[0] << 8 | tmp[1]);
+		buf[1] >>= 6;
+
+		ret = i2c_read_block(client, MICROP_I2C_RCMD_GSENSOR_Z_DATA,
+				     tmp, 2);
+		if (ret < 0) {
+			dev_err(&client->dev, "%s: i2c_read_block fail\n",
+				__func__);
+			return ret;
+		}
+		buf[2] = (short)(tmp[0] << 8 | tmp[1]);
+		buf[2] >>= 6;
+	} else {
+		ret = i2c_read_block(client, MICROP_I2C_RCMD_GSENSOR_DATA,
+				     tmp, 6);
+		if (ret < 0) {
+			dev_err(&client->dev, "%s: i2c_read_block fail\n",
+				__func__);
+			return ret;
+		}
+		buf[0] = (short)(tmp[0] << 8 | tmp[1]);
+		buf[0] >>= 6;
+		buf[1] = (short)(tmp[2] << 8 | tmp[3]);
+		buf[1] >>= 6;
+		buf[2] = (short)(tmp[4] << 8 | tmp[5]);
+		buf[2] >>= 6;
+	}
+
+#ifdef DEBUG_BMA150
+	/* Log this to debugfs */
+	gsensor_log_status(ktime_get(), buf[0], buf[1], buf[2]);
+#endif
+	return 1;
+}
+
+static int gsensor_init_hw(void)
+{
+	uint8_t reg;
+	int ret;
+
+	pr_debug("%s\n", __func__);
+
+	microp_spi_enable(1);
+
+	ret = gsensor_read_reg(RANGE_BWIDTH_REG, &reg);
+	if (ret < 0 )
+		return -EIO;
+	reg &= 0xe0;
+	ret = gsensor_write_reg(RANGE_BWIDTH_REG, reg);
+	if (ret < 0 )
+		return -EIO;
+
+	ret = gsensor_read_reg(SMB150_CONF2_REG, &reg);
+	if (ret < 0 )
+		return -EIO;
+	reg |= (1 << 3);
+	ret = gsensor_write_reg(SMB150_CONF2_REG, reg);
+
+	return ret;
+}
+
+static int bma150_set_mode(char mode)
+{
+	uint8_t reg;
+	int ret;
+
+	pr_debug("%s mode = %d\n", __func__, mode);
+	if (mode == BMA_MODE_NORMAL)
+		microp_spi_enable(1);
+
+
+	ret = gsensor_read_reg(SMB150_CTRL_REG, &reg);
+	if (ret < 0 )
+		return -EIO;
+	reg = (reg & 0xfe) | mode;
+	ret = gsensor_write_reg(SMB150_CTRL_REG, reg);
+
+	if (mode == BMA_MODE_SLEEP)
+		microp_spi_enable(0);
+
+	return ret;
+}
+static int gsensor_read(uint8_t *data)
+{
+	int ret;
+	uint8_t reg = data[0];
+
+	ret = gsensor_read_reg(reg, &data[1]);
+	pr_debug("%s reg = %x data = %x\n", __func__, reg, data[1]);
+	return ret;
+}
+
+static int gsensor_write(uint8_t *data)
+{
+	int ret;
+	uint8_t reg = data[0];
+
+	pr_debug("%s reg = %x data = %x\n", __func__, reg, data[1]);
+	ret = gsensor_write_reg(reg, data[1]);
+	return ret;
+}
+
+static int bma150_open(struct inode *inode, struct file *file)
+{
+	pr_debug("%s\n", __func__);
+	return nonseekable_open(inode, file);
+}
+
+static int bma150_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static int bma150_ioctl(struct inode *inode, struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	char rwbuf[8];
+	int ret = -1;
+	short buf[8], temp;
+
+	switch (cmd) {
+	case BMA_IOCTL_READ:
+	case BMA_IOCTL_WRITE:
+	case BMA_IOCTL_SET_MODE:
+		if (copy_from_user(&rwbuf, argp, sizeof(rwbuf)))
+			return -EFAULT;
+		break;
+	case BMA_IOCTL_READ_ACCELERATION:
+		if (copy_from_user(&buf, argp, sizeof(buf)))
+			return -EFAULT;
+		break;
+	default:
+		break;
+	}
+
+	switch (cmd) {
+	case BMA_IOCTL_INIT:
+		ret = gsensor_init_hw();
+		if (ret < 0)
+			return ret;
+		break;
+
+	case BMA_IOCTL_READ:
+		if (rwbuf[0] < 1)
+			return -EINVAL;
+		ret = gsensor_read(rwbuf);
+		if (ret < 0)
+			return ret;
+		break;
+	case BMA_IOCTL_WRITE:
+		if (rwbuf[0] < 2)
+			return -EINVAL;
+		ret = gsensor_write(rwbuf);
+		if (ret < 0)
+			return ret;
+		break;
+	case BMA_IOCTL_READ_ACCELERATION:
+		ret = gsensor_read_acceleration(&buf[0]);
+		if (ret < 0)
+			return ret;
+		break;
+	case BMA_IOCTL_SET_MODE:
+		bma150_set_mode(rwbuf[0]);
+		break;
+	case BMA_IOCTL_GET_INT:
+		temp = 0;
+		break;
+	default:
+		return -ENOTTY;
+	}
+
+	switch (cmd) {
+	case BMA_IOCTL_READ:
+		if (copy_to_user(argp, &rwbuf, sizeof(rwbuf)))
+			return -EFAULT;
+		break;
+	case BMA_IOCTL_READ_ACCELERATION:
+		if (copy_to_user(argp, &buf, sizeof(buf)))
+			return -EFAULT;
+		break;
+	case BMA_IOCTL_GET_INT:
+		if (copy_to_user(argp, &temp, sizeof(temp)))
+			return -EFAULT;
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static struct file_operations bma_fops = {
+	.owner = THIS_MODULE,
+	.open = bma150_open,
+	.release = bma150_release,
+	.ioctl = bma150_ioctl,
+};
+
+static struct miscdevice spi_bma_device = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = BMA150_G_SENSOR_NAME,
+	.fops = &bma_fops,
+};
+
+/*
+ * Interrupt
+ */
+static irqreturn_t microp_i2c_intr_irq_handler(int irq, void *dev_id)
+{
+	struct i2c_client *client;
+	struct microp_i2c_client_data *cdata;
+
+	client = to_i2c_client(dev_id);
+	cdata = i2c_get_clientdata(client);
+
+	dev_dbg(&client->dev, "intr_irq_handler\n");
+
+	disable_irq_nosync(client->irq);
+	schedule_work(&cdata->work.work);
+	return IRQ_HANDLED;
+}
+
+static void microp_i2c_intr_work_func(struct work_struct *work)
+{
+	struct microp_i2c_work *up_work;
+	struct i2c_client *client;
+	struct microp_i2c_client_data *cdata;
+	uint8_t data[3], adc_level;
+	uint16_t intr_status = 0, adc_value, gpi_status = 0;
+	int keycode = 0, ret = 0;
+
+	up_work = container_of(work, struct microp_i2c_work, work);
+	client = up_work->client;
+	cdata = i2c_get_clientdata(client);
+
+	ret = i2c_read_block(client, MICROP_I2C_RCMD_GPI_INT_STATUS, data, 2);
+	if (ret < 0) {
+		dev_err(&client->dev, "%s: read interrupt status fail\n",
+			 __func__);
+	}
+
+	intr_status = data[0]<<8 | data[1];
+	ret = i2c_write_block(client, MICROP_I2C_WCMD_GPI_INT_STATUS_CLR,
+			      data, 2);
+	if (ret < 0) {
+		dev_err(&client->dev, "%s: clear interrupt status fail\n",
+			 __func__);
+	}
+	pr_debug("intr_status=0x%02x\n", intr_status);
+
+	if ((intr_status & IRQ_LSENSOR) || cdata->force_light_sensor_read) {
+		ret = microp_lightsensor_read(&adc_value, &adc_level);
+		if (cdata->force_light_sensor_read) {
+			/* report an invalid value first to ensure we trigger an event
+			 * when adc_level is zero.
+			 */
+			input_report_abs(cdata->ls_input_dev, ABS_MISC, -1);
+			input_sync(cdata->ls_input_dev);
+			cdata->force_light_sensor_read = 0;
+		}
+		input_report_abs(cdata->ls_input_dev, ABS_MISC, (int)adc_level);
+		input_sync(cdata->ls_input_dev);
+	}
+
+	if (intr_status & IRQ_SDCARD) {
+		microp_read_gpi_status(client, &gpi_status);
+		mahimahi_microp_sdslot_update_status(gpi_status);
+	}
+
+	if (intr_status & IRQ_HEADSETIN) {
+		cdata->is_hpin_pin_stable = 0;
+		wake_lock_timeout(&microp_i2c_wakelock, 3*HZ);
+		if (!cdata->headset_is_in)
+			schedule_delayed_work(&cdata->hpin_debounce_work,
+					msecs_to_jiffies(500));
+		else
+			schedule_delayed_work(&cdata->hpin_debounce_work,
+					msecs_to_jiffies(300));
+	}
+	if (intr_status & IRQ_REMOTEKEY) {
+		if ((get_remote_keycode(&keycode) == 0) &&
+			(cdata->is_hpin_pin_stable)) {
+			htc_35mm_key_event(keycode, &cdata->is_hpin_pin_stable);
+		}
+	}
+
+	enable_irq(client->irq);
+}
+
+static void ls_read_do_work(struct work_struct *work)
+{
+	struct i2c_client *client = private_microp_client;
+	struct microp_i2c_client_data *cdata = i2c_get_clientdata(client);
+
+	/* force a light sensor reading */
+	disable_irq(client->irq);
+	cdata->force_light_sensor_read = 1;
+	schedule_work(&cdata->work.work);
+}
+
+static int microp_function_initialize(struct i2c_client *client)
+{
+	struct microp_i2c_client_data *cdata;
+	uint8_t data[20];
+	uint16_t stat, interrupts = 0;
+	int i;
+	int ret;
+	struct led_classdev *led_cdev;
+
+	cdata = i2c_get_clientdata(client);
+
+	/* Light Sensor */
+	if (als_kadc >> 16 == ALS_CALIBRATED)
+		cdata->als_kadc = als_kadc & 0xFFFF;
+	else {
+		cdata->als_kadc = 0;
+		pr_info("%s: no ALS calibrated\n", __func__);
+	}
+
+	if (cdata->als_kadc && golden_adc) {
+		cdata->als_kadc =
+			(cdata->als_kadc > 0 && cdata->als_kadc < 0x400)
+			? cdata->als_kadc : golden_adc;
+		cdata->als_gadc =
+			(golden_adc > 0)
+			? golden_adc : cdata->als_kadc;
+	} else {
+		cdata->als_kadc = 1;
+		cdata->als_gadc = 1;
+	}
+	pr_info("%s: als_kadc=0x%x, als_gadc=0x%x\n",
+		__func__, cdata->als_kadc, cdata->als_gadc);
+
+	for (i = 0; i < 10; i++) {
+		data[i] = (uint8_t)(lsensor_adc_table[i]
+			* cdata->als_kadc / cdata->als_gadc >> 8);
+		data[i + 10] = (uint8_t)(lsensor_adc_table[i]
+			* cdata->als_kadc / cdata->als_gadc);
+	}
+	ret = i2c_write_block(client, MICROP_I2C_WCMD_ADC_TABLE, data, 20);
+	if (ret)
+		goto exit;
+
+	ret = gpio_request(MAHIMAHI_GPIO_LS_EN_N, "microp_i2c");
+	if (ret < 0) {
+		dev_err(&client->dev, "failed on request gpio ls_on\n");
+		goto exit;
+	}
+	ret = gpio_direction_output(MAHIMAHI_GPIO_LS_EN_N, 0);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed on gpio_direction_output"
+				"ls_on\n");
+		goto err_gpio_ls;
+	}
+	cdata->light_sensor_enabled = 1;
+
+	/* Headset */
+	for (i = 0; i < 6; i++) {
+		data[i] = (uint8_t)(remote_key_adc_table[i] >> 8);
+		data[i + 6] = (uint8_t)(remote_key_adc_table[i]);
+	}
+	ret = i2c_write_block(client,
+		MICROP_I2C_WCMD_REMOTEKEY_TABLE, data, 12);
+	if (ret)
+		goto exit;
+
+	INIT_DELAYED_WORK(
+		&cdata->hpin_debounce_work, hpin_debounce_do_work);
+	INIT_DELAYED_WORK(
+		&cdata->ls_read_work, ls_read_do_work);
+
+	/* SD Card */
+	interrupts |= IRQ_SDCARD;
+
+	/* set LED initial state */
+	for (i = 0; i < BLUE_LED; i++) {
+		led_cdev = &cdata->leds[i].ldev;
+		microp_i2c_write_led_mode(client, led_cdev, 0, 0xffff);
+	}
+
+	/* enable the interrupts */
+	ret = microp_interrupt_enable(client, interrupts);
+	if (ret < 0) {
+		dev_err(&client->dev, "%s: failed to enable gpi irqs\n",
+			__func__);
+		goto err_irq_en;
+	}
+
+	microp_read_gpi_status(client, &stat);
+	mahimahi_microp_sdslot_update_status(stat);
+
+	return 0;
+
+err_irq_en:
+err_gpio_ls:
+	gpio_free(MAHIMAHI_GPIO_LS_EN_N);
+exit:
+	return ret;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+void microp_early_suspend(struct early_suspend *h)
+{
+	struct microp_i2c_client_data *cdata;
+	struct i2c_client *client = private_microp_client;
+	int ret;
+
+	if (!client) {
+		pr_err("%s: dataset: client is empty\n", __func__);
+		return;
+	}
+	cdata = i2c_get_clientdata(client);
+
+	cdata->microp_is_suspend = 1;
+
+	disable_irq(client->irq);
+	ret = cancel_work_sync(&cdata->work.work);
+	if (ret != 0) {
+		enable_irq(client->irq);
+	}
+
+	if (cdata->auto_backlight_enabled)
+		microp_i2c_auto_backlight_mode(client, 0);
+	if (cdata->light_sensor_enabled == 1) {
+		gpio_set_value(MAHIMAHI_GPIO_LS_EN_N, 1);
+		cdata->light_sensor_enabled = 0;
+	}
+}
+
+void microp_early_resume(struct early_suspend *h)
+{
+	struct i2c_client *client = private_microp_client;
+	struct microp_i2c_client_data *cdata;
+
+	if (!client) {
+		pr_err("%s: dataset: client is empty\n", __func__);
+		return;
+	}
+	cdata = i2c_get_clientdata(client);
+
+	gpio_set_value(MAHIMAHI_GPIO_LS_EN_N, 0);
+	cdata->light_sensor_enabled = 1;
+
+	if (cdata->auto_backlight_enabled)
+		microp_i2c_auto_backlight_mode(client, 1);
+
+	cdata->microp_is_suspend = 0;
+	enable_irq(client->irq);
+}
+#endif
+
+static int microp_i2c_suspend(struct i2c_client *client,
+	pm_message_t mesg)
+{
+	return 0;
+}
+
+static int microp_i2c_resume(struct i2c_client *client)
+{
+	return 0;
+}
+
+static struct {
+	const char *name;
+	void (*led_set_work)(struct work_struct *);
+	struct device_attribute **attrs;
+	int attr_cnt;
+} microp_leds[] = {
+	[GREEN_LED] = {
+		.name		= "green",
+		.led_set_work   = microp_led_brightness_set_work,
+		.attrs		= green_amber_attrs,
+		.attr_cnt	= ARRAY_SIZE(green_amber_attrs)
+	},
+	[AMBER_LED] = {
+		.name		= "amber",
+		.led_set_work   = microp_led_brightness_set_work,
+		.attrs		= green_amber_attrs,
+		.attr_cnt	= ARRAY_SIZE(green_amber_attrs)
+	},
+	[RED_LED] = {
+		.name		= "red",
+		.led_set_work   = microp_led_brightness_set_work,
+		.attrs		= green_amber_attrs,
+		.attr_cnt	= ARRAY_SIZE(green_amber_attrs)
+	},
+	[BLUE_LED] = {
+		.name		= "blue",
+		.led_set_work   = microp_led_brightness_set_work,
+		.attrs		= green_amber_attrs,
+		.attr_cnt	= ARRAY_SIZE(green_amber_attrs)
+	},
+	[JOGBALL_LED] = {
+		.name		= "jogball-backlight",
+		.led_set_work	= microp_led_jogball_brightness_set_work,
+		.attrs		= jogball_attrs,
+		.attr_cnt	= ARRAY_SIZE(jogball_attrs)
+	},
+	[BUTTONS_LED] = {
+		.name		= "button-backlight",
+		.led_set_work	= microp_led_buttons_brightness_set_work
+	},
+};
+
+static int microp_i2c_probe(struct i2c_client *client,
+			    const struct i2c_device_id *id)
+{
+	struct microp_i2c_client_data *cdata;
+	uint8_t data[6];
+	int ret;
+	int i;
+	int j;
+
+	private_microp_client = client;
+	ret = i2c_read_block(client, MICROP_I2C_RCMD_VERSION, data, 2);
+	if (ret || !(data[0] && data[1])) {
+		ret = -ENODEV;
+		dev_err(&client->dev, "failed on get microp version\n");
+		goto err_exit;
+	}
+	dev_info(&client->dev, "microp version [%02X][%02X]\n",
+		  data[0], data[1]);
+
+	ret = gpio_request(MAHIMAHI_GPIO_UP_RESET_N, "microp_i2c_wm");
+	if (ret < 0) {
+		dev_err(&client->dev, "failed on request gpio reset\n");
+		goto err_exit;
+	}
+	ret = gpio_direction_output(MAHIMAHI_GPIO_UP_RESET_N, 1);
+	if (ret < 0) {
+		dev_err(&client->dev,
+			 "failed on gpio_direction_output reset\n");
+		goto err_gpio_reset;
+	}
+
+	cdata = kzalloc(sizeof(struct microp_i2c_client_data), GFP_KERNEL);
+	if (!cdata) {
+		ret = -ENOMEM;
+		dev_err(&client->dev, "failed on allocat cdata\n");
+		goto err_cdata;
+	}
+
+	i2c_set_clientdata(client, cdata);
+	cdata->version = data[0] << 8 | data[1];
+	cdata->microp_is_suspend = 0;
+	cdata->auto_backlight_enabled = 0;
+	cdata->light_sensor_enabled = 0;
+
+	wake_lock_init(&microp_i2c_wakelock, WAKE_LOCK_SUSPEND,
+			 "microp_i2c_present");
+
+	/* Light Sensor */
+	ret = device_create_file(&client->dev, &dev_attr_ls_adc);
+	ret = device_create_file(&client->dev, &dev_attr_ls_auto);
+	cdata->ls_input_dev = input_allocate_device();
+	if (!cdata->ls_input_dev) {
+		pr_err("%s: could not allocate input device\n", __func__);
+		ret = -ENOMEM;
+		goto err_request_input_dev;
+	}
+	cdata->ls_input_dev->name = "lightsensor-level";
+	set_bit(EV_ABS, cdata->ls_input_dev->evbit);
+	input_set_abs_params(cdata->ls_input_dev, ABS_MISC, 0, 9, 0, 0);
+
+	ret = input_register_device(cdata->ls_input_dev);
+	if (ret < 0) {
+		dev_err(&client->dev, "%s: can not register input device\n",
+				__func__);
+		goto err_register_input_dev;
+	}
+
+	ret = misc_register(&lightsensor_misc);
+	if (ret < 0) {
+		dev_err(&client->dev, "%s: can not register misc device\n",
+				__func__);
+		goto err_register_misc_register;
+	}
+
+	/* LEDs */
+	ret = 0;
+	for (i = 0; i < ARRAY_SIZE(microp_leds) && !ret; ++i) {
+		struct microp_led_data *ldata = &cdata->leds[i];
+
+		ldata->type = i;
+		ldata->ldev.name = microp_leds[i].name;
+		ldata->ldev.brightness_set = microp_brightness_set;
+		mutex_init(&ldata->led_data_mutex);
+		INIT_WORK(&ldata->brightness_work, microp_leds[i].led_set_work);
+		spin_lock_init(&ldata->brightness_lock);
+		ret = led_classdev_register(&client->dev, &ldata->ldev);
+		if (ret) {
+			ldata->ldev.name = NULL;
+			break;
+		}
+
+		for (j = 0; j < microp_leds[i].attr_cnt && !ret; ++j)
+			ret = device_create_file(ldata->ldev.dev,
+						 microp_leds[i].attrs[j]);
+	}
+	if (ret) {
+		dev_err(&client->dev, "failed to add leds\n");
+		goto err_add_leds;
+	}
+
+	/* Headset */
+	cdata->headset_is_in = 0;
+	cdata->is_hpin_pin_stable = 1;
+	platform_device_register(&mahimahi_h35mm);
+
+	ret = device_create_file(&client->dev, &dev_attr_key_adc);
+
+	/* G-sensor */
+	ret = misc_register(&spi_bma_device);
+	if (ret < 0) {
+		pr_err("%s: init bma150 misc_register fail\n",
+				__func__);
+		goto err_register_bma150;
+	}
+#ifdef DEBUG_BMA150
+	debugfs_create_file("gsensor_log", 0444, NULL, NULL, &gsensor_log_fops);
+#endif
+	/* Setup IRQ handler */
+	INIT_WORK(&cdata->work.work, microp_i2c_intr_work_func);
+	cdata->work.client = client;
+
+	ret = request_irq(client->irq,
+			microp_i2c_intr_irq_handler,
+			IRQF_TRIGGER_LOW,
+			"microp_interrupt",
+			&client->dev);
+	if (ret) {
+		dev_err(&client->dev, "request_irq failed\n");
+		goto err_intr;
+	}
+	ret = set_irq_wake(client->irq, 1);
+	if (ret) {
+		dev_err(&client->dev, "set_irq_wake failed\n");
+		goto err_intr;
+	}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	if (cdata->enable_early_suspend) {
+		cdata->early_suspend.level =
+				EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+		cdata->early_suspend.suspend = microp_early_suspend;
+		cdata->early_suspend.resume = microp_early_resume;
+		register_early_suspend(&cdata->early_suspend);
+	}
+#endif
+
+	ret = microp_function_initialize(client);
+	if (ret) {
+		dev_err(&client->dev, "failed on microp function initialize\n");
+		goto err_fun_init;
+	}
+
+	return 0;
+
+err_fun_init:
+err_intr:
+	misc_deregister(&spi_bma_device);
+
+err_register_bma150:
+	platform_device_unregister(&mahimahi_h35mm);
+	device_remove_file(&client->dev, &dev_attr_key_adc);
+
+err_add_leds:
+	for (i = 0; i < ARRAY_SIZE(microp_leds); ++i) {
+		if (!cdata->leds[i].ldev.name)
+			continue;
+		led_classdev_unregister(&cdata->leds[i].ldev);
+		for (j = 0; j < microp_leds[i].attr_cnt; ++j)
+			device_remove_file(cdata->leds[i].ldev.dev,
+					   microp_leds[i].attrs[j]);
+	}
+
+	misc_deregister(&lightsensor_misc);
+
+err_register_misc_register:
+	input_unregister_device(cdata->ls_input_dev);
+
+err_register_input_dev:
+	input_free_device(cdata->ls_input_dev);
+
+err_request_input_dev:
+	wake_lock_destroy(&microp_i2c_wakelock);
+	device_remove_file(&client->dev, &dev_attr_ls_adc);
+	device_remove_file(&client->dev, &dev_attr_ls_auto);
+	kfree(cdata);
+	i2c_set_clientdata(client, NULL);
+
+err_cdata:
+err_gpio_reset:
+	gpio_free(MAHIMAHI_GPIO_UP_RESET_N);
+err_exit:
+	return ret;
+}
+
+static int __devexit microp_i2c_remove(struct i2c_client *client)
+{
+	struct microp_i2c_client_data *cdata;
+	int i;
+	int j;
+
+	cdata = i2c_get_clientdata(client);
+
+	for (i = 0; i < ARRAY_SIZE(microp_leds); ++i) {
+		struct microp_led_data *ldata = &cdata->leds[i];
+		cancel_work_sync(&ldata->brightness_work);
+	}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	if (cdata->enable_early_suspend) {
+		unregister_early_suspend(&cdata->early_suspend);
+	}
+#endif
+
+	for (i = 0; i < ARRAY_SIZE(microp_leds); ++i) {
+		if (!cdata->leds[i].ldev.name)
+			continue;
+		led_classdev_unregister(&cdata->leds[i].ldev);
+		for (j = 0; j < microp_leds[i].attr_cnt; ++j)
+			device_remove_file(cdata->leds[i].ldev.dev,
+					   microp_leds[i].attrs[j]);
+	}
+
+	free_irq(client->irq, &client->dev);
+
+	gpio_free(MAHIMAHI_GPIO_UP_RESET_N);
+
+	misc_deregister(&lightsensor_misc);
+	input_unregister_device(cdata->ls_input_dev);
+	input_free_device(cdata->ls_input_dev);
+	device_remove_file(&client->dev, &dev_attr_ls_adc);
+	device_remove_file(&client->dev, &dev_attr_key_adc);
+	device_remove_file(&client->dev, &dev_attr_ls_auto);
+
+	platform_device_unregister(&mahimahi_h35mm);
+
+	/* G-sensor */
+	misc_deregister(&spi_bma_device);
+
+	kfree(cdata);
+
+	return 0;
+}
+
+#define ATAG_ALS	0x5441001b
+static int __init parse_tag_als_kadc(const struct tag *tags)
+{
+	int found = 0;
+	struct tag *t = (struct tag *)tags;
+
+	for (; t->hdr.size; t = tag_next(t)) {
+		if (t->hdr.tag == ATAG_ALS) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (found)
+		als_kadc = t->u.revision.rev;
+	pr_debug("%s: als_kadc = 0x%x\n", __func__, als_kadc);
+	return 0;
+}
+__tagtable(ATAG_ALS, parse_tag_als_kadc);
+
+static const struct i2c_device_id microp_i2c_id[] = {
+	{ MICROP_I2C_NAME, 0 },
+	{ }
+};
+
+static struct i2c_driver microp_i2c_driver = {
+	.driver = {
+		   .name = MICROP_I2C_NAME,
+		   },
+	.id_table = microp_i2c_id,
+	.probe = microp_i2c_probe,
+	.suspend = microp_i2c_suspend,
+	.resume = microp_i2c_resume,
+	.remove = __devexit_p(microp_i2c_remove),
+};
+
+
+static int __init microp_i2c_init(void)
+{
+	return i2c_add_driver(&microp_i2c_driver);
+}
+
+static void __exit microp_i2c_exit(void)
+{
+	i2c_del_driver(&microp_i2c_driver);
+}
+
+module_init(microp_i2c_init);
+module_exit(microp_i2c_exit);
+
+MODULE_AUTHOR("Eric Olsen <eolsen@android.com>");
+MODULE_DESCRIPTION("MicroP I2C driver");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/board-mahimahi-mmc.c b/arch/arm/mach-msm/board-mahimahi-mmc.c
new file mode 100644
index 0000000..dc57781
--- /dev/null
+++ b/arch/arm/mach-msm/board-mahimahi-mmc.c
@@ -0,0 +1,454 @@
+/* linux/arch/arm/mach-msm/board-mahimahi-mmc.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ *
+ * 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.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/platform_device.h>
+
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/mach/mmc.h>
+
+#include <mach/vreg.h>
+#include <mach/proc_comm.h>
+
+#include "board-mahimahi.h"
+#include "devices.h"
+
+#undef MAHIMAHI_DEBUG_MMC
+
+static bool opt_disable_sdcard;
+static int __init mahimahi_disablesdcard_setup(char *str)
+{
+	opt_disable_sdcard = (bool)simple_strtol(str, NULL, 0);
+	return 1;
+}
+
+__setup("board_mahimahi.disable_sdcard=", mahimahi_disablesdcard_setup);
+
+static void config_gpio_table(uint32_t *table, int len)
+{
+	int n;
+	unsigned id;
+	for(n = 0; n < len; n++) {
+		id = table[n];
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+	}
+}
+
+static uint32_t sdcard_on_gpio_table[] = {
+	PCOM_GPIO_CFG(62, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* CLK */
+	PCOM_GPIO_CFG(63, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* CMD */
+	PCOM_GPIO_CFG(64, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT3 */
+	PCOM_GPIO_CFG(65, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT2 */
+	PCOM_GPIO_CFG(66, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT1 */
+	PCOM_GPIO_CFG(67, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT0 */
+};
+
+static uint32_t sdcard_off_gpio_table[] = {
+	PCOM_GPIO_CFG(62, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CLK */
+	PCOM_GPIO_CFG(63, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CMD */
+	PCOM_GPIO_CFG(64, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */
+	PCOM_GPIO_CFG(65, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */
+	PCOM_GPIO_CFG(66, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT1 */
+	PCOM_GPIO_CFG(67, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT0 */
+};
+
+static struct vreg	*sdslot_vreg;
+static uint32_t		sdslot_vdd = 0xffffffff;
+static uint32_t		sdslot_vreg_enabled;
+
+static struct {
+	int mask;
+	int level;
+} mmc_vdd_table[] = {
+	{ MMC_VDD_165_195,	1800 },
+	{ MMC_VDD_20_21,	2050 },
+	{ MMC_VDD_21_22,	2150 },
+	{ MMC_VDD_22_23,	2250 },
+	{ MMC_VDD_23_24,	2350 },
+	{ MMC_VDD_24_25,	2450 },
+	{ MMC_VDD_25_26,	2550 },
+	{ MMC_VDD_26_27,	2650 },
+	{ MMC_VDD_27_28,	2750 },
+	{ MMC_VDD_28_29,	2850 },
+	{ MMC_VDD_29_30,	2950 },
+};
+
+static uint32_t mahimahi_sdslot_switchvdd(struct device *dev, unsigned int vdd)
+{
+	int i;
+	int ret;
+
+	if (vdd == sdslot_vdd)
+		return 0;
+
+	sdslot_vdd = vdd;
+
+	if (vdd == 0) {
+		config_gpio_table(sdcard_off_gpio_table,
+				  ARRAY_SIZE(sdcard_off_gpio_table));
+		vreg_disable(sdslot_vreg);
+		sdslot_vreg_enabled = 0;
+		return 0;
+	}
+
+	if (!sdslot_vreg_enabled) {
+		ret = vreg_enable(sdslot_vreg);
+		if (ret)
+			pr_err("%s: Error enabling vreg (%d)\n", __func__, ret);
+		config_gpio_table(sdcard_on_gpio_table,
+				  ARRAY_SIZE(sdcard_on_gpio_table));
+		sdslot_vreg_enabled = 1;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(mmc_vdd_table); i++) {
+		if (mmc_vdd_table[i].mask != (1 << vdd))
+			continue;
+		ret = vreg_set_level(sdslot_vreg, mmc_vdd_table[i].level);
+		if (ret)
+			pr_err("%s: Error setting level (%d)\n", __func__, ret);
+		return 0;
+	}
+
+	pr_err("%s: Invalid VDD (%d) specified\n", __func__, vdd);
+	return 0;
+}
+
+static uint32_t mahimahi_cdma_sdslot_switchvdd(struct device *dev, unsigned int vdd)
+{
+	if (!vdd == !sdslot_vdd)
+		return 0;
+
+	/* In CDMA version, the vdd of sdslot is not configurable, and it is
+	 * fixed in 2.85V by hardware design.
+	 */
+
+	sdslot_vdd = vdd ? MMC_VDD_28_29 : 0;
+
+	if (vdd) {
+		gpio_set_value(MAHIMAHI_CDMA_SD_2V85_EN, 1);
+		config_gpio_table(sdcard_on_gpio_table,
+				  ARRAY_SIZE(sdcard_on_gpio_table));
+	} else {
+		config_gpio_table(sdcard_off_gpio_table,
+				  ARRAY_SIZE(sdcard_off_gpio_table));
+		gpio_set_value(MAHIMAHI_CDMA_SD_2V85_EN, 0);
+	}
+
+	sdslot_vreg_enabled = !!vdd;
+
+	return 0;
+}
+
+static unsigned int mahimahi_sdslot_status_rev0(struct device *dev)
+{
+	return !gpio_get_value(MAHIMAHI_GPIO_SDMC_CD_REV0_N);
+}
+
+#define MAHIMAHI_MMC_VDD	(MMC_VDD_165_195 | MMC_VDD_20_21 | \
+				 MMC_VDD_21_22  | MMC_VDD_22_23 | \
+				 MMC_VDD_23_24 | MMC_VDD_24_25 | \
+				 MMC_VDD_25_26 | MMC_VDD_26_27 | \
+				 MMC_VDD_27_28 | MMC_VDD_28_29 | \
+				 MMC_VDD_29_30)
+
+int mahimahi_microp_sdslot_status_register(void (*cb)(int, void *), void *);
+unsigned int mahimahi_microp_sdslot_status(struct device *);
+
+static struct mmc_platform_data mahimahi_sdslot_data = {
+	.ocr_mask		= MAHIMAHI_MMC_VDD,
+	.status			= mahimahi_microp_sdslot_status,
+	.register_status_notify	= mahimahi_microp_sdslot_status_register,
+	.translate_vdd		= mahimahi_sdslot_switchvdd,
+};
+
+static uint32_t wifi_on_gpio_table[] = {
+	PCOM_GPIO_CFG(51, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT3 */
+	PCOM_GPIO_CFG(52, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT2 */
+	PCOM_GPIO_CFG(53, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT1 */
+	PCOM_GPIO_CFG(54, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT0 */
+	PCOM_GPIO_CFG(55, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* CMD */
+	PCOM_GPIO_CFG(56, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* CLK */
+	PCOM_GPIO_CFG(152, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_4MA),  /* WLAN IRQ */
+};
+
+static uint32_t wifi_off_gpio_table[] = {
+	PCOM_GPIO_CFG(51, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */
+	PCOM_GPIO_CFG(52, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */
+	PCOM_GPIO_CFG(53, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT1 */
+	PCOM_GPIO_CFG(54, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT0 */
+	PCOM_GPIO_CFG(55, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CMD */
+	PCOM_GPIO_CFG(56, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CLK */
+	PCOM_GPIO_CFG(152, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA),  /* WLAN IRQ */
+};
+
+/* BCM4329 returns wrong sdio_vsn(1) when we read cccr,
+ * we use predefined value (sdio_vsn=2) here to initial sdio driver well
+ */
+static struct embedded_sdio_data mahimahi_wifi_emb_data = {
+	.cccr	= {
+		.sdio_vsn	= 2,
+		.multi_block	= 1,
+		.low_speed	= 0,
+		.wide_bus	= 0,
+		.high_power	= 1,
+		.high_speed	= 1,
+	},
+};
+
+static int mahimahi_wifi_cd = 0; /* WIFI virtual 'card detect' status */
+static void (*wifi_status_cb)(int card_present, void *dev_id);
+static void *wifi_status_cb_devid;
+
+static int mahimahi_wifi_status_register(
+			void (*callback)(int card_present, void *dev_id),
+			void *dev_id)
+{
+	if (wifi_status_cb)
+		return -EAGAIN;
+	wifi_status_cb = callback;
+	wifi_status_cb_devid = dev_id;
+	return 0;
+}
+
+static unsigned int mahimahi_wifi_status(struct device *dev)
+{
+	return mahimahi_wifi_cd;
+}
+
+static struct mmc_platform_data mahimahi_wifi_data = {
+	.ocr_mask		= MMC_VDD_28_29,
+	.built_in		= 1,
+	.status			= mahimahi_wifi_status,
+	.register_status_notify	= mahimahi_wifi_status_register,
+	.embedded_sdio		= &mahimahi_wifi_emb_data,
+};
+
+int mahimahi_wifi_set_carddetect(int val)
+{
+	pr_info("%s: %d\n", __func__, val);
+	mahimahi_wifi_cd = val;
+	if (wifi_status_cb) {
+		wifi_status_cb(val, wifi_status_cb_devid);
+	} else
+		pr_warning("%s: Nobody to notify\n", __func__);
+	return 0;
+}
+
+static int mahimahi_wifi_power_state;
+
+int mahimahi_wifi_power(int on)
+{
+	printk("%s: %d\n", __func__, on);
+
+	if (on) {
+		config_gpio_table(wifi_on_gpio_table,
+				  ARRAY_SIZE(wifi_on_gpio_table));
+		mdelay(50);
+	} else {
+		config_gpio_table(wifi_off_gpio_table,
+				  ARRAY_SIZE(wifi_off_gpio_table));
+	}
+
+	mdelay(100);
+	gpio_set_value(MAHIMAHI_GPIO_WIFI_SHUTDOWN_N, on); /* WIFI_SHUTDOWN */
+	mdelay(200);
+
+	mahimahi_wifi_power_state = on;
+	return 0;
+}
+
+static int mahimahi_wifi_reset_state;
+
+int mahimahi_wifi_reset(int on)
+{
+	printk("%s: do nothing\n", __func__);
+	mahimahi_wifi_reset_state = on;
+	return 0;
+}
+
+int msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat,
+		 unsigned int stat_irq, unsigned long stat_irq_flags);
+
+int __init mahimahi_init_mmc(unsigned int sys_rev, unsigned debug_uart)
+{
+	uint32_t id;
+
+	printk("%s()+\n", __func__);
+
+	/* initial WIFI_SHUTDOWN# */
+	id = PCOM_GPIO_CFG(MAHIMAHI_GPIO_WIFI_SHUTDOWN_N, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA),
+	msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+
+	msm_add_sdcc(1, &mahimahi_wifi_data, 0, 0);
+
+	if (debug_uart) {
+		pr_info("%s: sdcard disabled due to debug uart\n", __func__);
+		goto done;
+	}
+	if (opt_disable_sdcard) {
+		pr_info("%s: sdcard disabled on cmdline\n", __func__);
+		goto done;
+	}
+
+	sdslot_vreg_enabled = 0;
+
+	if (is_cdma_version(sys_rev)) {
+		/* In the CDMA version, sdslot is supplied by a gpio. */
+		int rc = gpio_request(MAHIMAHI_CDMA_SD_2V85_EN, "sdslot_en");
+		if (rc < 0) {
+			pr_err("%s: gpio_request(%d) failed: %d\n", __func__,
+				MAHIMAHI_CDMA_SD_2V85_EN, rc);
+			return rc;
+		}
+		mahimahi_sdslot_data.translate_vdd = mahimahi_cdma_sdslot_switchvdd;
+	} else {
+		/* in UMTS version, sdslot is supplied by pmic */
+		sdslot_vreg = vreg_get(0, "gp6");
+		if (IS_ERR(sdslot_vreg))
+			return PTR_ERR(sdslot_vreg);
+	}
+
+	if (system_rev > 0)
+		msm_add_sdcc(2, &mahimahi_sdslot_data, 0, 0);
+	else {
+		mahimahi_sdslot_data.status = mahimahi_sdslot_status_rev0;
+		mahimahi_sdslot_data.register_status_notify = NULL;
+		set_irq_wake(MSM_GPIO_TO_INT(MAHIMAHI_GPIO_SDMC_CD_REV0_N), 1);
+		msm_add_sdcc(2, &mahimahi_sdslot_data,
+			     MSM_GPIO_TO_INT(MAHIMAHI_GPIO_SDMC_CD_REV0_N),
+			     IORESOURCE_IRQ_LOWEDGE | IORESOURCE_IRQ_HIGHEDGE);
+	}
+
+done:
+	printk("%s()-\n", __func__);
+	return 0;
+}
+
+#if defined(MAHIMAHI_DEBUG_MMC) && defined(CONFIG_DEBUG_FS)
+
+static int mahimahimmc_dbg_wifi_reset_set(void *data, u64 val)
+{
+	mahimahi_wifi_reset((int) val);
+	return 0;
+}
+
+static int mahimahimmc_dbg_wifi_reset_get(void *data, u64 *val)
+{
+	*val = mahimahi_wifi_reset_state;
+	return 0;
+}
+
+static int mahimahimmc_dbg_wifi_cd_set(void *data, u64 val)
+{
+	mahimahi_wifi_set_carddetect((int) val);
+	return 0;
+}
+
+static int mahimahimmc_dbg_wifi_cd_get(void *data, u64 *val)
+{
+	*val = mahimahi_wifi_cd;
+	return 0;
+}
+
+static int mahimahimmc_dbg_wifi_pwr_set(void *data, u64 val)
+{
+	mahimahi_wifi_power((int) val);
+	return 0;
+}
+
+static int mahimahimmc_dbg_wifi_pwr_get(void *data, u64 *val)
+{
+	*val = mahimahi_wifi_power_state;
+	return 0;
+}
+
+static int mahimahimmc_dbg_sd_pwr_set(void *data, u64 val)
+{
+	mahimahi_sdslot_switchvdd(NULL, (unsigned int) val);
+	return 0;
+}
+
+static int mahimahimmc_dbg_sd_pwr_get(void *data, u64 *val)
+{
+	*val = sdslot_vdd;
+	return 0;
+}
+
+static int mahimahimmc_dbg_sd_cd_set(void *data, u64 val)
+{
+	return -ENOSYS;
+}
+
+static int mahimahimmc_dbg_sd_cd_get(void *data, u64 *val)
+{
+	*val = mahimahi_sdslot_data.status(NULL);
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(mahimahimmc_dbg_wifi_reset_fops,
+			mahimahimmc_dbg_wifi_reset_get,
+			mahimahimmc_dbg_wifi_reset_set, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(mahimahimmc_dbg_wifi_cd_fops,
+			mahimahimmc_dbg_wifi_cd_get,
+			mahimahimmc_dbg_wifi_cd_set, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(mahimahimmc_dbg_wifi_pwr_fops,
+			mahimahimmc_dbg_wifi_pwr_get,
+			mahimahimmc_dbg_wifi_pwr_set, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(mahimahimmc_dbg_sd_pwr_fops,
+			mahimahimmc_dbg_sd_pwr_get,
+			mahimahimmc_dbg_sd_pwr_set, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(mahimahimmc_dbg_sd_cd_fops,
+			mahimahimmc_dbg_sd_cd_get,
+			mahimahimmc_dbg_sd_cd_set, "%llu\n");
+
+static int __init mahimahimmc_dbg_init(void)
+{
+	struct dentry *dent;
+
+	if (!machine_is_mahimahi())
+		return 0;
+
+	dent = debugfs_create_dir("mahimahi_mmc_dbg", 0);
+	if (IS_ERR(dent))
+		return PTR_ERR(dent);
+
+	debugfs_create_file("wifi_reset", 0644, dent, NULL,
+			    &mahimahimmc_dbg_wifi_reset_fops);
+	debugfs_create_file("wifi_cd", 0644, dent, NULL,
+			    &mahimahimmc_dbg_wifi_cd_fops);
+	debugfs_create_file("wifi_pwr", 0644, dent, NULL,
+			    &mahimahimmc_dbg_wifi_pwr_fops);
+	debugfs_create_file("sd_pwr", 0644, dent, NULL,
+			    &mahimahimmc_dbg_sd_pwr_fops);
+	debugfs_create_file("sd_cd", 0644, dent, NULL,
+			    &mahimahimmc_dbg_sd_cd_fops);
+	return 0;
+}
+
+device_initcall(mahimahimmc_dbg_init);
+#endif
diff --git a/arch/arm/mach-msm/board-mahimahi-panel.c b/arch/arm/mach-msm/board-mahimahi-panel.c
new file mode 100644
index 0000000..31ec742
--- /dev/null
+++ b/arch/arm/mach-msm/board-mahimahi-panel.c
@@ -0,0 +1,998 @@
+/* linux/arch/arm/mach-msm/board-mahimahi-panel.c
+ *
+ * Copyright (c) 2009 Google Inc.
+ * Author: Dima Zavin <dima@android.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+
+#include <asm/io.h>
+#include <asm/mach-types.h>
+
+#include <mach/msm_fb.h>
+#include <mach/msm_iomap.h>
+#include <mach/vreg.h>
+#include <mach/proc_comm.h>
+
+#include "board-mahimahi.h"
+#include "devices.h"
+
+
+#define SPI_CONFIG              (0x00000000)
+#define SPI_IO_CONTROL          (0x00000004)
+#define SPI_OPERATIONAL         (0x00000030)
+#define SPI_ERROR_FLAGS_EN      (0x00000038)
+#define SPI_ERROR_FLAGS         (0x00000038)
+#define SPI_OUTPUT_FIFO         (0x00000100)
+
+static void __iomem *spi_base;
+static struct clk *spi_clk ;
+static struct vreg *vreg_lcm_rftx_2v6;
+static struct vreg *vreg_lcm_aux_2v6;
+
+static int qspi_send(uint32_t id, uint8_t data)
+{
+	uint32_t err;
+
+	/* bit-5: OUTPUT_FIFO_NOT_EMPTY */
+	while (readl(spi_base + SPI_OPERATIONAL) & (1<<5)) {
+		if ((err = readl(spi_base + SPI_ERROR_FLAGS))) {
+			pr_err("%s: ERROR: SPI_ERROR_FLAGS=0x%08x\n", __func__,
+			       err);
+			return -EIO;
+		}
+	}
+	writel((0x7000 | (id << 9) | data) << 16, spi_base + SPI_OUTPUT_FIFO);
+	udelay(100);
+
+	return 0;
+}
+
+static int qspi_send_9bit(uint32_t id, uint8_t data)
+{
+	uint32_t err;
+
+	while (readl(spi_base + SPI_OPERATIONAL) & (1<<5)) {
+		err = readl(spi_base + SPI_ERROR_FLAGS);
+		if (err) {
+			pr_err("%s: ERROR: SPI_ERROR_FLAGS=0x%08x\n", __func__,
+			       err);
+			return -EIO;
+		}
+	}
+	writel(((id << 8) | data) << 23, spi_base + SPI_OUTPUT_FIFO);
+	udelay(100);
+
+	return 0;
+}
+
+static int lcm_writeb(uint8_t reg, uint8_t val)
+{
+	qspi_send(0x0, reg);
+	qspi_send(0x1, val);
+	return 0;
+}
+
+static int lcm_writew(uint8_t reg, uint16_t val)
+{
+	qspi_send(0x0, reg);
+	qspi_send(0x1, val >> 8);
+	qspi_send(0x1, val & 0xff);
+	return 0;
+}
+
+static struct resource resources_msm_fb[] = {
+	{
+		.start = MSM_FB_BASE,
+		.end = MSM_FB_BASE + MSM_FB_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+struct lcm_tbl {
+	uint8_t		reg;
+	uint8_t		val;
+};
+
+static struct lcm_tbl samsung_oled_rgb565_init_table[] = {
+	{ 0x31, 0x08 },
+	{ 0x32, 0x14 },
+	{ 0x30, 0x2 },
+	{ 0x27, 0x1 },
+	{ 0x12, 0x8 },
+	{ 0x13, 0x8 },
+	{ 0x15, 0x0 },
+	{ 0x16, 0x02 },
+	{ 0x39, 0x24 },
+	{ 0x17, 0x22 },
+	{ 0x18, 0x33 },
+	{ 0x19, 0x3 },
+	{ 0x1A, 0x1 },
+	{ 0x22, 0xA4 },
+	{ 0x23, 0x0 },
+	{ 0x26, 0xA0 },
+};
+
+static struct lcm_tbl samsung_oled_rgb666_init_table[] = {
+	{ 0x31, 0x08 },
+	{ 0x32, 0x14 },
+	{ 0x30, 0x2  },
+	{ 0x27, 0x1  },
+	{ 0x12, 0x8  },
+	{ 0x13, 0x8  },
+	{ 0x15, 0x0  },
+	{ 0x16, 0x01 },
+	{ 0x39, 0x24 },
+	{ 0x17, 0x22 },
+	{ 0x18, 0x33 },
+	{ 0x19, 0x3  },
+	{ 0x1A, 0x1  },
+	{ 0x22, 0xA4 },
+	{ 0x23, 0x0  },
+	{ 0x26, 0xA0 },
+};
+
+static struct lcm_tbl *init_tablep = samsung_oled_rgb565_init_table;
+static size_t init_table_sz = ARRAY_SIZE(samsung_oled_rgb565_init_table);
+
+#define OLED_GAMMA_TABLE_SIZE		(7 * 3)
+static struct lcm_tbl samsung_oled_gamma_table[][OLED_GAMMA_TABLE_SIZE] = {
+	/* level 10 */
+	{
+		/* Gamma-R */
+		{ 0x40, 0x0 },
+		{ 0x41, 0x3f },
+		{ 0x42, 0x3f },
+		{ 0x43, 0x35 },
+		{ 0x44, 0x30 },
+		{ 0x45, 0x2c },
+		{ 0x46, 0x13 },
+		/* Gamma -G */
+		{ 0x50, 0x0 },
+		{ 0x51, 0x0 },
+		{ 0x52, 0x0 },
+		{ 0x53, 0x0 },
+		{ 0x54, 0x27 },
+		{ 0x55, 0x2b },
+		{ 0x56, 0x12 },
+		/* Gamma -B */
+		{ 0x60, 0x0 },
+		{ 0x61, 0x3f },
+		{ 0x62, 0x3f },
+		{ 0x63, 0x34 },
+		{ 0x64, 0x2f },
+		{ 0x65, 0x2b },
+		{ 0x66, 0x1b },
+	},
+
+	/* level 40 */
+	{
+		/* Gamma -R */
+		{ 0x40, 0x0 },
+		{ 0x41, 0x3f },
+		{ 0x42, 0x3e },
+		{ 0x43, 0x2e },
+		{ 0x44, 0x2d },
+		{ 0x45, 0x28 },
+		{ 0x46, 0x21 },
+		/* Gamma -G */
+		{ 0x50, 0x0 },
+		{ 0x51, 0x0 },
+		{ 0x52, 0x0 },
+		{ 0x53, 0x21 },
+		{ 0x54, 0x2a },
+		{ 0x55, 0x28 },
+		{ 0x56, 0x20 },
+		/* Gamma -B */
+		{ 0x60, 0x0 },
+		{ 0x61, 0x3f },
+		{ 0x62, 0x3e },
+		{ 0x63, 0x2d },
+		{ 0x64, 0x2b },
+		{ 0x65, 0x26 },
+		{ 0x66, 0x2d },
+	},
+
+	/* level 70 */
+	{
+		/* Gamma -R */
+		{ 0x40, 0x0 },
+		{ 0x41, 0x3f },
+		{ 0x42, 0x35 },
+		{ 0x43, 0x2c },
+		{ 0x44, 0x2b },
+		{ 0x45, 0x26 },
+		{ 0x46, 0x29 },
+		/* Gamma -G */
+		{ 0x50, 0x0 },
+		{ 0x51, 0x0 },
+		{ 0x52, 0x0 },
+		{ 0x53, 0x25 },
+		{ 0x54, 0x29 },
+		{ 0x55, 0x26 },
+		{ 0x56, 0x28 },
+		/* Gamma -B */
+		{ 0x60, 0x0 },
+		{ 0x61, 0x3f },
+		{ 0x62, 0x34 },
+		{ 0x63, 0x2b },
+		{ 0x64, 0x2a },
+		{ 0x65, 0x23 },
+		{ 0x66, 0x37 },
+	},
+
+	/* level 100 */
+	{
+		/* Gamma -R */
+		{ 0x40, 0x0 },
+		{ 0x41, 0x3f },
+		{ 0x42, 0x30 },
+		{ 0x43, 0x2a },
+		{ 0x44, 0x2b },
+		{ 0x45, 0x24 },
+		{ 0x46, 0x2f },
+		/* Gamma -G */
+		{ 0x50, 0x0 },
+		{ 0x51, 0x0 },
+		{ 0x52, 0x0 },
+		{ 0x53, 0x25 },
+		{ 0x54, 0x29 },
+		{ 0x55, 0x24 },
+		{ 0x56, 0x2e },
+		/* Gamma -B */
+		{ 0x60, 0x0 },
+		{ 0x61, 0x3f },
+		{ 0x62, 0x2f },
+		{ 0x63, 0x29 },
+		{ 0x64, 0x29 },
+		{ 0x65, 0x21 },
+		{ 0x66, 0x3f },
+	},
+
+	/* level 130 */
+	{
+		/* Gamma -R */
+		{ 0x40, 0x0 },
+		{ 0x41, 0x3f },
+		{ 0x42, 0x2e },
+		{ 0x43, 0x29 },
+		{ 0x44, 0x2a },
+		{ 0x45, 0x23 },
+		{ 0x46, 0x34 },
+		/* Gamma -G */
+		{ 0x50, 0x0 },
+		{ 0x51, 0x0 },
+		{ 0x52, 0xa },
+		{ 0x53, 0x25 },
+		{ 0x54, 0x28 },
+		{ 0x55, 0x23 },
+		{ 0x56, 0x33 },
+		/* Gamma -B */
+		{ 0x60, 0x0 },
+		{ 0x61, 0x3f },
+		{ 0x62, 0x2d },
+		{ 0x63, 0x28 },
+		{ 0x64, 0x27 },
+		{ 0x65, 0x20 },
+		{ 0x66, 0x46 },
+	},
+
+	/* level 160 */
+	{
+		/* Gamma -R */
+		{ 0x40, 0x0 },
+		{ 0x41, 0x3f },
+		{ 0x42, 0x2b },
+		{ 0x43, 0x29 },
+		{ 0x44, 0x28 },
+		{ 0x45, 0x23 },
+		{ 0x46, 0x38 },
+		/* Gamma -G */
+		{ 0x50, 0x0 },
+		{ 0x51, 0x0 },
+		{ 0x52, 0xb },
+		{ 0x53, 0x25 },
+		{ 0x54, 0x27 },
+		{ 0x55, 0x23 },
+		{ 0x56, 0x37 },
+		/* Gamma -B */
+		{ 0x60, 0x0 },
+		{ 0x61, 0x3f },
+		{ 0x62, 0x29 },
+		{ 0x63, 0x28 },
+		{ 0x64, 0x25 },
+		{ 0x65, 0x20 },
+		{ 0x66, 0x4b },
+	},
+
+	/* level 190 */
+	{
+		/* Gamma -R */
+		{ 0x40, 0x0 },
+		{ 0x41, 0x3f },
+		{ 0x42, 0x29 },
+		{ 0x43, 0x29 },
+		{ 0x44, 0x27 },
+		{ 0x45, 0x22 },
+		{ 0x46, 0x3c },
+		/* Gamma -G */
+		{ 0x50, 0x0 },
+		{ 0x51, 0x0 },
+		{ 0x52, 0x10 },
+		{ 0x53, 0x26 },
+		{ 0x54, 0x26 },
+		{ 0x55, 0x22 },
+		{ 0x56, 0x3b },
+		/* Gamma -B */
+		{ 0x60, 0x0 },
+		{ 0x61, 0x3f },
+		{ 0x62, 0x28 },
+		{ 0x63, 0x28 },
+		{ 0x64, 0x24 },
+		{ 0x65, 0x1f },
+		{ 0x66, 0x50 },
+	},
+
+	/* level 220 */
+	{
+		/* Gamma -R */
+		{ 0x40, 0x0 },
+		{ 0x41, 0x3f },
+		{ 0x42, 0x28 },
+		{ 0x43, 0x28 },
+		{ 0x44, 0x28 },
+		{ 0x45, 0x20 },
+		{ 0x46, 0x40 },
+		/* Gamma -G */
+		{ 0x50, 0x0 },
+		{ 0x51, 0x0 },
+		{ 0x52, 0x11 },
+		{ 0x53, 0x25 },
+		{ 0x54, 0x27 },
+		{ 0x55, 0x20 },
+		{ 0x56, 0x3f },
+		/* Gamma -B */
+		{ 0x60, 0x0 },
+		{ 0x61, 0x3f },
+		{ 0x62, 0x27 },
+		{ 0x63, 0x26 },
+		{ 0x64, 0x26 },
+		{ 0x65, 0x1c },
+		{ 0x66, 0x56 },
+	},
+
+	/* level 250 */
+	{
+		/* Gamma -R */
+		{ 0x40, 0x0 },
+		{ 0x41, 0x3f },
+		{ 0x42, 0x2a },
+		{ 0x43, 0x27 },
+		{ 0x44, 0x27 },
+		{ 0x45, 0x1f },
+		{ 0x46, 0x44 },
+		/* Gamma -G */
+		{ 0x50, 0x0 },
+		{ 0x51, 0x0 },
+		{ 0x52, 0x17 },
+		{ 0x53, 0x24 },
+		{ 0x54, 0x26 },
+		{ 0x55, 0x1f },
+		{ 0x56, 0x43 },
+		/* Gamma -B */
+		{ 0x60, 0x0 },
+		{ 0x61, 0x3f },
+		{ 0x62, 0x2a },
+		{ 0x63, 0x25 },
+		{ 0x64, 0x24 },
+		{ 0x65, 0x1b },
+		{ 0x66, 0x5c },
+	},
+};
+#define SAMSUNG_OLED_NUM_LEVELS		ARRAY_SIZE(samsung_oled_gamma_table)
+
+#define SAMSUNG_OLED_MIN_VAL		10
+#define SAMSUNG_OLED_MAX_VAL		250
+#define SAMSUNG_OLED_DEFAULT_VAL	(SAMSUNG_OLED_MIN_VAL +		\
+					 (SAMSUNG_OLED_MAX_VAL -	\
+					  SAMSUNG_OLED_MIN_VAL) / 2)
+
+#define SAMSUNG_OLED_LEVEL_STEP		((SAMSUNG_OLED_MAX_VAL -	\
+					  SAMSUNG_OLED_MIN_VAL) /	\
+					 (SAMSUNG_OLED_NUM_LEVELS - 1))
+
+
+#define SONY_TFT_DEF_USER_VAL         102
+#define SONY_TFT_MIN_USER_VAL         30
+#define SONY_TFT_MAX_USER_VAL         255
+#define SONY_TFT_DEF_PANEL_VAL        155
+#define SONY_TFT_MIN_PANEL_VAL        26
+#define SONY_TFT_MAX_PANEL_VAL        255
+
+
+static DEFINE_MUTEX(panel_lock);
+static struct work_struct brightness_delayed_work;
+static DEFINE_SPINLOCK(brightness_lock);
+static uint8_t new_val = SAMSUNG_OLED_DEFAULT_VAL;
+static uint8_t last_val = SAMSUNG_OLED_DEFAULT_VAL;
+static uint8_t table_sel_vals[] = { 0x43, 0x34 };
+static int table_sel_idx = 0;
+static uint8_t tft_panel_on;
+
+static void gamma_table_bank_select(void)
+{
+	lcm_writeb(0x39, table_sel_vals[table_sel_idx]);
+	table_sel_idx ^= 1;
+}
+
+static void samsung_oled_set_gamma_val(int val)
+{
+	int i;
+	int level;
+	int frac;
+
+	val = clamp(val, SAMSUNG_OLED_MIN_VAL, SAMSUNG_OLED_MAX_VAL);
+	val = (val / 2) * 2;
+
+	level = (val - SAMSUNG_OLED_MIN_VAL) / SAMSUNG_OLED_LEVEL_STEP;
+	frac = (val - SAMSUNG_OLED_MIN_VAL) % SAMSUNG_OLED_LEVEL_STEP;
+
+	clk_enable(spi_clk);
+
+	for (i = 0; i < OLED_GAMMA_TABLE_SIZE; ++i) {
+		unsigned int v1;
+		unsigned int v2 = 0;
+		u8 v;
+		if (frac == 0) {
+			v = samsung_oled_gamma_table[level][i].val;
+		} else {
+
+			v1 = samsung_oled_gamma_table[level][i].val;
+			v2 = samsung_oled_gamma_table[level+1][i].val;
+			v = (v1 * (SAMSUNG_OLED_LEVEL_STEP - frac) +
+			     v2 * frac) / SAMSUNG_OLED_LEVEL_STEP;
+		}
+		lcm_writeb(samsung_oled_gamma_table[level][i].reg, v);
+	}
+
+	gamma_table_bank_select();
+	clk_disable(spi_clk);
+	last_val = val;
+}
+
+static int samsung_oled_panel_init(struct msm_lcdc_panel_ops *ops)
+{
+	pr_info("%s: +()\n", __func__);
+	mutex_lock(&panel_lock);
+
+	clk_enable(spi_clk);
+	/* Set the gamma write target to 4, leave the current gamma set at 2 */
+	lcm_writeb(0x39, 0x24);
+	clk_disable(spi_clk);
+
+	mutex_unlock(&panel_lock);
+	pr_info("%s: -()\n", __func__);
+	return 0;
+}
+
+static int samsung_oled_panel_unblank(struct msm_lcdc_panel_ops *ops)
+{
+	int i;
+
+	pr_info("%s: +()\n", __func__);
+
+	mutex_lock(&panel_lock);
+
+	gpio_set_value(MAHIMAHI_GPIO_LCD_RST_N, 1);
+	udelay(50);
+	gpio_set_value(MAHIMAHI_GPIO_LCD_RST_N, 0);
+	udelay(20);
+	gpio_set_value(MAHIMAHI_GPIO_LCD_RST_N, 1);
+	msleep(20);
+
+	clk_enable(spi_clk);
+
+	for (i = 0; i < init_table_sz; i++)
+		lcm_writeb(init_tablep[i].reg, init_tablep[i].val);
+
+	lcm_writew(0xef, 0xd0e8);
+	lcm_writeb(0x1d, 0xa0);
+	table_sel_idx = 0;
+	gamma_table_bank_select();
+	samsung_oled_set_gamma_val(last_val);
+	msleep(250);
+	lcm_writeb(0x14, 0x03);
+	clk_disable(spi_clk);
+
+	mutex_unlock(&panel_lock);
+
+	pr_info("%s: -()\n", __func__);
+	return 0;
+}
+
+static int samsung_oled_panel_blank(struct msm_lcdc_panel_ops *ops)
+{
+	pr_info("%s: +()\n", __func__);
+	mutex_lock(&panel_lock);
+
+	clk_enable(spi_clk);
+	lcm_writeb(0x14, 0x0);
+	mdelay(1);
+	lcm_writeb(0x1d, 0xa1);
+	clk_disable(spi_clk);
+	msleep(200);
+
+	gpio_set_value(MAHIMAHI_GPIO_LCD_RST_N, 0);
+
+	mutex_unlock(&panel_lock);
+	pr_info("%s: -()\n", __func__);
+	return 0;
+}
+
+struct lcm_cmd {
+	int reg;
+	uint32_t val;
+	unsigned delay;
+};
+
+#define LCM_GPIO_CFG(gpio, func, str) \
+		PCOM_GPIO_CFG(gpio, func, GPIO_OUTPUT, GPIO_NO_PULL, str)
+
+static uint32_t sony_tft_display_on_gpio_table[] = {
+	LCM_GPIO_CFG(MAHIMAHI_LCD_R1, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_R2, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_R3, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_R4, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_R5, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_G0, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_G1, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_G2, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_G3, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_G4, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_G5, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_B1, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_B2, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_B3, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_B4, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_B5, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_PCLK, 1, GPIO_4MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_VSYNC, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_HSYNC, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_DE, 1, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_SPI_CLK, 1, GPIO_4MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_SPI_DO, 1, GPIO_4MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_SPI_CSz, 1, GPIO_4MA),
+};
+
+static uint32_t sony_tft_display_off_gpio_table[] = {
+	LCM_GPIO_CFG(MAHIMAHI_LCD_R1, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_R2, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_R3, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_R4, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_R5, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_G0, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_G1, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_G2, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_G3, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_G4, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_G5, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_B1, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_B2, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_B3, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_B4, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_B5, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_PCLK, 0, GPIO_4MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_VSYNC, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_HSYNC, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_DE, 0, GPIO_8MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_SPI_CLK, 0, GPIO_4MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_SPI_DO, 0, GPIO_4MA),
+	LCM_GPIO_CFG(MAHIMAHI_LCD_SPI_CSz, 0, GPIO_4MA),
+};
+
+#undef LCM_GPIO_CFG
+
+#define SONY_TFT_DEF_PANEL_DELTA \
+		(SONY_TFT_DEF_PANEL_VAL - SONY_TFT_MIN_PANEL_VAL)
+#define SONY_TFT_DEF_USER_DELTA \
+		(SONY_TFT_DEF_USER_VAL - SONY_TFT_MIN_USER_VAL)
+
+static void sony_tft_set_pwm_val(int val)
+{
+	pr_info("%s: %d\n", __func__, val);
+
+	last_val = val;
+
+	if (!tft_panel_on)
+		return;
+
+	if (val <= SONY_TFT_DEF_USER_VAL) {
+		if (val <= SONY_TFT_MIN_USER_VAL)
+			val = SONY_TFT_MIN_PANEL_VAL;
+		else
+			val = SONY_TFT_DEF_PANEL_DELTA *
+				(val - SONY_TFT_MIN_USER_VAL) /
+				SONY_TFT_DEF_USER_DELTA +
+				SONY_TFT_MIN_PANEL_VAL;
+	} else
+		val = (SONY_TFT_MAX_PANEL_VAL - SONY_TFT_DEF_PANEL_VAL) *
+			(val - SONY_TFT_DEF_USER_VAL) /
+			(SONY_TFT_MAX_USER_VAL - SONY_TFT_DEF_USER_VAL) +
+			SONY_TFT_DEF_PANEL_VAL;
+
+	clk_enable(spi_clk);
+	qspi_send_9bit(0x0, 0x51);
+	qspi_send_9bit(0x1, val);
+	qspi_send_9bit(0x0, 0x53);
+	qspi_send_9bit(0x1, 0x24);
+	clk_disable(spi_clk);
+}
+
+#undef SONY_TFT_DEF_PANEL_DELTA
+#undef SONY_TFT_DEF_USER_DELTA
+
+static void sony_tft_panel_config_gpio_table(uint32_t *table, int len)
+{
+	int n;
+	unsigned id;
+	for (n = 0; n < len; n++) {
+		id = table[n];
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+	}
+}
+
+
+static int sony_tft_panel_power(int on)
+{
+	unsigned id, on_off;
+
+	if (on) {
+		on_off = 0;
+
+		vreg_enable(vreg_lcm_aux_2v6);
+		vreg_enable(vreg_lcm_rftx_2v6);
+
+		id = PM_VREG_PDOWN_AUX_ID;
+		msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
+
+		id = PM_VREG_PDOWN_RFTX_ID;
+		msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
+		mdelay(10);
+		gpio_set_value(MAHIMAHI_GPIO_LCD_RST_N, 1);
+		mdelay(10);
+		gpio_set_value(MAHIMAHI_GPIO_LCD_RST_N, 0);
+		udelay(500);
+		gpio_set_value(MAHIMAHI_GPIO_LCD_RST_N, 1);
+		mdelay(10);
+		sony_tft_panel_config_gpio_table(
+			sony_tft_display_on_gpio_table,
+			ARRAY_SIZE(sony_tft_display_on_gpio_table));
+	} else {
+		on_off = 1;
+
+		gpio_set_value(MAHIMAHI_GPIO_LCD_RST_N, 0);
+
+		mdelay(120);
+
+		vreg_disable(vreg_lcm_rftx_2v6);
+		vreg_disable(vreg_lcm_aux_2v6);
+
+		id = PM_VREG_PDOWN_RFTX_ID;
+		msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
+
+		id = PM_VREG_PDOWN_AUX_ID;
+		msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
+		sony_tft_panel_config_gpio_table(
+			sony_tft_display_off_gpio_table,
+			ARRAY_SIZE(sony_tft_display_off_gpio_table));
+	}
+	return 0;
+}
+
+static int sony_tft_panel_init(struct msm_lcdc_panel_ops *ops)
+{
+	return 0;
+}
+
+static int sony_tft_panel_unblank(struct msm_lcdc_panel_ops *ops)
+{
+	pr_info("%s: +()\n", __func__);
+
+	mutex_lock(&panel_lock);
+
+	if (tft_panel_on) {
+		pr_info("%s: -() already unblanked\n", __func__);
+		goto done;
+	}
+
+	sony_tft_panel_power(1);
+	msleep(45);
+
+	clk_enable(spi_clk);
+	qspi_send_9bit(0x0, 0x11);
+	msleep(5);
+	qspi_send_9bit(0x0, 0x3a);
+	qspi_send_9bit(0x1, 0x05);
+	msleep(100);
+	qspi_send_9bit(0x0, 0x29);
+	/* unlock register page for pwm setting */
+	qspi_send_9bit(0x0, 0xf0);
+	qspi_send_9bit(0x1, 0x5a);
+	qspi_send_9bit(0x1, 0x5a);
+	qspi_send_9bit(0x0, 0xf1);
+	qspi_send_9bit(0x1, 0x5a);
+	qspi_send_9bit(0x1, 0x5a);
+	qspi_send_9bit(0x0, 0xd0);
+	qspi_send_9bit(0x1, 0x5a);
+	qspi_send_9bit(0x1, 0x5a);
+
+	qspi_send_9bit(0x0, 0xc2);
+	qspi_send_9bit(0x1, 0x53);
+	qspi_send_9bit(0x1, 0x12);
+	clk_disable(spi_clk);
+	msleep(100);
+	tft_panel_on = 1;
+	sony_tft_set_pwm_val(last_val);
+
+	pr_info("%s: -()\n", __func__);
+done:
+	mutex_unlock(&panel_lock);
+	return 0;
+}
+
+static int sony_tft_panel_blank(struct msm_lcdc_panel_ops *ops)
+{
+	pr_info("%s: +()\n", __func__);
+
+	mutex_lock(&panel_lock);
+
+	clk_enable(spi_clk);
+	qspi_send_9bit(0x0, 0x28);
+	qspi_send_9bit(0x0, 0x10);
+	clk_disable(spi_clk);
+
+	msleep(40);
+	sony_tft_panel_power(0);
+	tft_panel_on = 0;
+
+	mutex_unlock(&panel_lock);
+
+	pr_info("%s: -()\n", __func__);
+	return 0;
+}
+
+static struct msm_lcdc_panel_ops mahimahi_lcdc_amoled_panel_ops = {
+	.init		= samsung_oled_panel_init,
+	.blank		= samsung_oled_panel_blank,
+	.unblank	= samsung_oled_panel_unblank,
+};
+
+static struct msm_lcdc_panel_ops mahimahi_lcdc_tft_panel_ops = {
+	.init		= sony_tft_panel_init,
+	.blank		= sony_tft_panel_blank,
+	.unblank	= sony_tft_panel_unblank,
+};
+
+
+static struct msm_lcdc_timing mahimahi_lcdc_amoled_timing = {
+		.clk_rate		= 24576000,
+		.hsync_pulse_width	= 4,
+		.hsync_back_porch	= 8,
+		.hsync_front_porch	= 8,
+		.hsync_skew		= 0,
+		.vsync_pulse_width	= 2,
+		.vsync_back_porch	= 8,
+		.vsync_front_porch	= 8,
+		.vsync_act_low		= 1,
+		.hsync_act_low		= 1,
+		.den_act_low		= 1,
+};
+
+static struct msm_lcdc_timing mahimahi_lcdc_tft_timing = {
+		.clk_rate		= 24576000,
+		.hsync_pulse_width	= 2,
+		.hsync_back_porch	= 20,
+		.hsync_front_porch	= 20,
+		.hsync_skew		= 0,
+		.vsync_pulse_width	= 2,
+		.vsync_back_porch	= 6,
+		.vsync_front_porch	= 4,
+		.vsync_act_low		= 1,
+		.hsync_act_low		= 1,
+		.den_act_low		= 0,
+};
+
+static struct msm_fb_data mahimahi_lcdc_fb_data = {
+		.xres		= 480,
+		.yres		= 800,
+		.width		= 48,
+		.height		= 80,
+		.output_format	= MSM_MDP_OUT_IF_FMT_RGB565,
+};
+
+static struct msm_lcdc_platform_data mahimahi_lcdc_amoled_platform_data = {
+	.panel_ops	= &mahimahi_lcdc_amoled_panel_ops,
+	.timing		= &mahimahi_lcdc_amoled_timing,
+	.fb_id		= 0,
+	.fb_data	= &mahimahi_lcdc_fb_data,
+	.fb_resource	= &resources_msm_fb[0],
+};
+
+static struct msm_lcdc_platform_data mahimahi_lcdc_tft_platform_data = {
+	.panel_ops	= &mahimahi_lcdc_tft_panel_ops,
+	.timing		= &mahimahi_lcdc_tft_timing,
+	.fb_id		= 0,
+	.fb_data	= &mahimahi_lcdc_fb_data,
+	.fb_resource	= &resources_msm_fb[0],
+};
+
+static struct platform_device mahimahi_lcdc_amoled_device = {
+	.name	= "msm_mdp_lcdc",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &mahimahi_lcdc_amoled_platform_data,
+	},
+};
+
+static struct platform_device mahimahi_lcdc_tft_device = {
+	.name	= "msm_mdp_lcdc",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &mahimahi_lcdc_tft_platform_data,
+	},
+};
+
+static int mahimahi_init_spi_hack(void)
+{
+	int ret;
+
+	spi_base = ioremap(MSM_SPI_PHYS, MSM_SPI_SIZE);
+	if (!spi_base)
+		return -1;
+
+	spi_clk = clk_get(&msm_device_spi.dev, "spi_clk");
+	if (IS_ERR(spi_clk)) {
+		pr_err("%s: unable to get spi_clk\n", __func__);
+		ret = PTR_ERR(spi_clk);
+		goto err_clk_get;
+	}
+
+	clk_enable(spi_clk);
+
+	printk("spi: SPI_CONFIG=%x\n", readl(spi_base + SPI_CONFIG));
+	printk("spi: SPI_IO_CONTROL=%x\n", readl(spi_base + SPI_IO_CONTROL));
+	printk("spi: SPI_OPERATIONAL=%x\n", readl(spi_base + SPI_OPERATIONAL));
+	printk("spi: SPI_ERROR_FLAGS_EN=%x\n",
+	       readl(spi_base + SPI_ERROR_FLAGS_EN));
+	printk("spi: SPI_ERROR_FLAGS=%x\n", readl(spi_base + SPI_ERROR_FLAGS));
+	printk("-%s()\n", __FUNCTION__);
+	clk_disable(spi_clk);
+
+	return 0;
+
+err_clk_get:
+	iounmap(spi_base);
+	return ret;
+}
+
+static void mahimahi_brightness_set(struct led_classdev *led_cdev,
+				    enum led_brightness val)
+{
+	unsigned long flags;
+	led_cdev->brightness = val;
+
+	spin_lock_irqsave(&brightness_lock, flags);
+	new_val = val;
+	spin_unlock_irqrestore(&brightness_lock, flags);
+
+	schedule_work(&brightness_delayed_work);
+}
+
+static void mahimahi_brightness_amoled_set_work(struct work_struct *work_ptr)
+{
+	unsigned long flags;
+	uint8_t val;
+
+	spin_lock_irqsave(&brightness_lock, flags);
+	val = new_val;
+	spin_unlock_irqrestore(&brightness_lock, flags);
+
+	mutex_lock(&panel_lock);
+	samsung_oled_set_gamma_val(val);
+	mutex_unlock(&panel_lock);
+}
+
+static void mahimahi_brightness_tft_set_work(struct work_struct *work_ptr)
+{
+	unsigned long flags;
+	uint8_t val;
+
+	spin_lock_irqsave(&brightness_lock, flags);
+	val = new_val;
+	spin_unlock_irqrestore(&brightness_lock, flags);
+
+	mutex_lock(&panel_lock);
+	sony_tft_set_pwm_val(val);
+	mutex_unlock(&panel_lock);
+}
+
+static struct led_classdev mahimahi_brightness_led = {
+	.name = "lcd-backlight",
+	.brightness = LED_FULL,
+	.brightness_set = mahimahi_brightness_set,
+};
+
+int __init mahimahi_init_panel(void)
+{
+	int ret;
+
+	if (!machine_is_mahimahi())
+		return 0;
+
+	if (system_rev > 0xC0) {
+		/* CDMA version (except for EVT1) supports RGB666 */
+		init_tablep = samsung_oled_rgb666_init_table;
+		init_table_sz = ARRAY_SIZE(samsung_oled_rgb666_init_table);
+		mahimahi_lcdc_fb_data.output_format = MSM_MDP_OUT_IF_FMT_RGB666;
+	}
+
+	ret = platform_device_register(&msm_device_mdp);
+	if (ret != 0)
+		return ret;
+
+	ret = mahimahi_init_spi_hack();
+	if (ret != 0)
+		return ret;
+
+	if (gpio_get_value(MAHIMAHI_GPIO_LCD_ID0)) {
+		pr_info("%s: tft panel\n", __func__);
+		vreg_lcm_rftx_2v6 = vreg_get(0, "rftx");
+		if (IS_ERR(vreg_lcm_rftx_2v6))
+			return PTR_ERR(vreg_lcm_rftx_2v6);
+		vreg_set_level(vreg_lcm_rftx_2v6, 2600);
+
+		vreg_lcm_aux_2v6 = vreg_get(0, "gp4");
+		if (IS_ERR(vreg_lcm_aux_2v6))
+			return PTR_ERR(vreg_lcm_aux_2v6);
+
+		if (gpio_get_value(MAHIMAHI_GPIO_LCD_RST_N))
+			tft_panel_on = 1;
+		ret = platform_device_register(&mahimahi_lcdc_tft_device);
+		INIT_WORK(&brightness_delayed_work, mahimahi_brightness_tft_set_work);
+	} else {
+		pr_info("%s: amoled panel\n", __func__);
+		ret = platform_device_register(&mahimahi_lcdc_amoled_device);
+		INIT_WORK(&brightness_delayed_work, mahimahi_brightness_amoled_set_work);
+	}
+
+	if (ret != 0)
+		return ret;
+
+	ret = led_classdev_register(NULL, &mahimahi_brightness_led);
+	if (ret != 0) {
+		pr_err("%s: Cannot register brightness led\n", __func__);
+		return ret;
+	}
+
+	return 0;
+}
+
+device_initcall(mahimahi_init_panel);
diff --git a/arch/arm/mach-msm/board-mahimahi-rfkill.c b/arch/arm/mach-msm/board-mahimahi-rfkill.c
new file mode 100644
index 0000000..05c9bb0
--- /dev/null
+++ b/arch/arm/mach-msm/board-mahimahi-rfkill.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rfkill.h>
+#include <asm/gpio.h>
+#include <asm/mach-types.h>
+
+#include "board-mahimahi.h"
+
+static struct rfkill *bt_rfk;
+static const char bt_name[] = "bcm4329";
+
+static int bluetooth_set_power(void *data, bool blocked)
+{
+	if (!blocked) {
+ 		gpio_direction_output(MAHIMAHI_GPIO_BT_RESET_N, 1);
+		gpio_direction_output(MAHIMAHI_GPIO_BT_SHUTDOWN_N, 1);
+	} else {
+ 		gpio_direction_output(MAHIMAHI_GPIO_BT_SHUTDOWN_N, 0);
+		gpio_direction_output(MAHIMAHI_GPIO_BT_RESET_N, 0);
+	}
+	return 0;
+}
+
+static struct rfkill_ops mahimahi_rfkill_ops = {
+	.set_block = bluetooth_set_power,
+};
+
+static int mahimahi_rfkill_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	bool default_state = true;  /* off */
+
+	rc = gpio_request(MAHIMAHI_GPIO_BT_RESET_N, "bt_reset");
+	if (rc)
+		goto err_gpio_reset;
+	rc = gpio_request(MAHIMAHI_GPIO_BT_SHUTDOWN_N, "bt_shutdown");
+	if (rc)
+		goto err_gpio_shutdown;
+
+	bluetooth_set_power(NULL, default_state);
+
+	bt_rfk = rfkill_alloc(bt_name, &pdev->dev, RFKILL_TYPE_BLUETOOTH,
+				&mahimahi_rfkill_ops, NULL);
+	if (!bt_rfk) {
+		rc = -ENOMEM;
+		goto err_rfkill_alloc;
+	}
+
+	rfkill_set_states(bt_rfk, default_state, false);
+
+	/* userspace cannot take exclusive control */
+
+	rc = rfkill_register(bt_rfk);
+	if (rc)
+		goto err_rfkill_reg;
+
+	return 0;
+
+err_rfkill_reg:
+	rfkill_destroy(bt_rfk);
+err_rfkill_alloc:
+	gpio_free(MAHIMAHI_GPIO_BT_SHUTDOWN_N);
+err_gpio_shutdown:
+	gpio_free(MAHIMAHI_GPIO_BT_RESET_N);
+err_gpio_reset:
+	return rc;
+}
+
+static int mahimahi_rfkill_remove(struct platform_device *dev)
+{
+	rfkill_unregister(bt_rfk);
+	rfkill_destroy(bt_rfk);
+	gpio_free(MAHIMAHI_GPIO_BT_SHUTDOWN_N);
+	gpio_free(MAHIMAHI_GPIO_BT_RESET_N);
+
+	return 0;
+}
+
+static struct platform_driver mahimahi_rfkill_driver = {
+	.probe = mahimahi_rfkill_probe,
+	.remove = mahimahi_rfkill_remove,
+	.driver = {
+		.name = "mahimahi_rfkill",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init mahimahi_rfkill_init(void)
+{
+	if (!machine_is_mahimahi())
+		return 0;
+
+	return platform_driver_register(&mahimahi_rfkill_driver);
+}
+
+static void __exit mahimahi_rfkill_exit(void)
+{
+	platform_driver_unregister(&mahimahi_rfkill_driver);
+}
+
+module_init(mahimahi_rfkill_init);
+module_exit(mahimahi_rfkill_exit);
+MODULE_DESCRIPTION("mahimahi rfkill");
+MODULE_AUTHOR("Nick Pelly <npelly@google.com>");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/board-mahimahi-smb329.c b/arch/arm/mach-msm/board-mahimahi-smb329.c
new file mode 100644
index 0000000..b80db78
--- /dev/null
+++ b/arch/arm/mach-msm/board-mahimahi-smb329.c
@@ -0,0 +1,177 @@
+/* drivers/i2c/chips/smb329.c
+ *
+ * SMB329B Switch Charger (SUMMIT Microelectronics)
+ *
+ * Copyright (C) 2009 HTC Corporation
+ * Author: Justin Lin <Justin_Lin@htc.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <asm/atomic.h>
+
+#include "board-mahimahi-smb329.h"
+
+static struct smb329_data {
+	struct i2c_client *client;
+	uint8_t version;
+	struct work_struct work;
+	struct mutex state_lock;
+	int chg_state;
+} smb329;
+
+static int smb329_i2c_write(uint8_t *value, uint8_t reg, uint8_t num_bytes)
+{
+	int ret;
+	struct i2c_msg msg;
+
+	/* write the first byte of buffer as the register address */
+	value[0] = reg;
+	msg.addr = smb329.client->addr;
+	msg.len = num_bytes + 1;
+	msg.flags = 0;
+	msg.buf = value;
+
+	ret = i2c_transfer(smb329.client->adapter, &msg, 1);
+
+	return (ret >= 0) ? 0 : ret;
+}
+
+static int smb329_i2c_read(uint8_t *value, uint8_t reg, uint8_t num_bytes)
+{
+	int ret;
+	struct i2c_msg msg[2];
+
+	/* setup the address to read */
+	msg[0].addr = smb329.client->addr;
+	msg[0].len = 1;
+	msg[0].flags = 0;
+	msg[0].buf = &reg;
+
+	/* setup the read buffer */
+	msg[1].addr = smb329.client->addr;
+	msg[1].flags = I2C_M_RD;
+	msg[1].len = num_bytes;
+	msg[1].buf = value;
+
+	ret = i2c_transfer(smb329.client->adapter, msg, 2);
+
+	return (ret >= 0) ? 0 : ret;
+}
+
+static int smb329_i2c_write_byte(uint8_t value, uint8_t reg)
+{
+	int ret;
+	uint8_t buf[2] = { 0 };
+
+	buf[1] = value;
+	ret = smb329_i2c_write(buf, reg, 1);
+	if (ret)
+		pr_err("smb329: write byte error (%d)\n", ret);
+
+	return ret;
+}
+
+static int smb329_i2c_read_byte(uint8_t *value, uint8_t reg)
+{
+	int ret = smb329_i2c_read(value, reg, 1);
+	if (ret)
+		pr_err("smb329: read byte error (%d)\n", ret);
+
+	return ret;
+}
+
+int smb329_set_charger_ctrl(uint32_t ctl)
+{
+	mutex_lock(&smb329.state_lock);
+	smb329.chg_state = ctl;
+	schedule_work(&smb329.work);
+	mutex_unlock(&smb329.state_lock);
+	return 0;
+}
+
+static void smb329_work_func(struct work_struct *work)
+{
+	mutex_lock(&smb329.state_lock);
+
+	switch (smb329.chg_state) {
+	case SMB329_ENABLE_FAST_CHG:
+		pr_info("smb329: charger on (fast)\n");
+		smb329_i2c_write_byte(0x84, 0x31);
+		smb329_i2c_write_byte(0x08, 0x05);
+		if ((smb329.version & 0x18) == 0x0)
+			smb329_i2c_write_byte(0xA9, 0x00);
+		break;
+
+	case SMB329_DISABLE_CHG:
+	case SMB329_ENABLE_SLOW_CHG:
+		pr_info("smb329: charger off/slow\n");
+		smb329_i2c_write_byte(0x88, 0x31);
+		smb329_i2c_write_byte(0x08, 0x05);
+		break;
+	default:
+		pr_err("smb329: unknown charger state %d\n",
+			smb329.chg_state);
+	}
+
+	mutex_unlock(&smb329.state_lock);
+}
+
+static int smb329_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
+		dev_dbg(&client->dev, "[SMB329]:I2C fail\n");
+		return -EIO;
+	}
+
+	smb329.client = client;
+	mutex_init(&smb329.state_lock);
+	INIT_WORK(&smb329.work, smb329_work_func);
+
+	smb329_i2c_read_byte(&smb329.version, 0x3B);
+	pr_info("smb329 version: 0x%02x\n", smb329.version);
+
+	return 0;
+}
+
+static const struct i2c_device_id smb329_id[] = {
+	{ "smb329", 0 },
+	{  },
+};
+
+static struct i2c_driver smb329_driver = {
+	.driver.name    = "smb329",
+	.id_table   = smb329_id,
+	.probe      = smb329_probe,
+};
+
+static int __init smb329_init(void)
+{
+	int ret = i2c_add_driver(&smb329_driver);
+	if (ret)
+		pr_err("smb329_init: failed\n");
+
+	return ret;
+}
+
+module_init(smb329_init);
+
+MODULE_AUTHOR("Justin Lin <Justin_Lin@htc.com>");
+MODULE_DESCRIPTION("SUMMIT Microelectronics SMB329B switch charger");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/board-mahimahi-smb329.h b/arch/arm/mach-msm/board-mahimahi-smb329.h
new file mode 100644
index 0000000..13b326f
--- /dev/null
+++ b/arch/arm/mach-msm/board-mahimahi-smb329.h
@@ -0,0 +1,32 @@
+/* include/linux/smb329.h - smb329 switch charger driver
+ *
+ * Copyright (C) 2009 HTC Corporation.
+ *
+ * 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 _LINUX_SMB329_H
+#define _LINUX_SMB329_H
+
+#ifdef __KERNEL__
+
+enum {
+	SMB329_DISABLE_CHG,
+	SMB329_ENABLE_SLOW_CHG,
+	SMB329_ENABLE_FAST_CHG,
+};
+
+extern int smb329_set_charger_ctrl(uint32_t ctl);
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_SMB329_H */
+
diff --git a/arch/arm/mach-msm/board-mahimahi-tpa2018d1.c b/arch/arm/mach-msm/board-mahimahi-tpa2018d1.c
new file mode 100644
index 0000000..78919b9b
--- /dev/null
+++ b/arch/arm/mach-msm/board-mahimahi-tpa2018d1.c
@@ -0,0 +1,368 @@
+/* drivers/i2c/chips/tpa2018d1.c
+ *
+ * TI TPA2018D1 Speaker Amplifier
+ *
+ * Copyright (C) 2009 HTC Corporation
+ *
+ * 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.
+ *
+ */
+
+/* TODO: content validation in TPA2018_SET_CONFIG */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/i2c.h>
+#include <linux/miscdevice.h>
+#include <linux/gpio.h>
+#include <asm/uaccess.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/tpa2018d1.h>
+
+#include "board-mahimahi-tpa2018d1.h"
+
+static struct i2c_client *this_client;
+static struct tpa2018d1_platform_data *pdata;
+static int is_on;
+static char spk_amp_cfg[8];
+static const char spk_amp_on[8] = { /* same length as spk_amp_cfg */
+	0x01, 0xc3, 0x20, 0x01, 0x00, 0x08, 0x1a, 0x21
+};
+static const char spk_amp_off[] = {0x01, 0xa2};
+
+static DEFINE_MUTEX(spk_amp_lock);
+static int tpa2018d1_opened;
+static char *config_data;
+static int tpa2018d1_num_modes;
+
+#define DEBUG 0
+
+static int tpa2018_i2c_write(const char *txData, int length)
+{
+	struct i2c_msg msg[] = {
+		{
+			.addr = this_client->addr,
+			.flags = 0,
+			.len = length,
+			.buf = txData,
+		},
+	};
+
+	if (i2c_transfer(this_client->adapter, msg, 1) < 0) {
+		pr_err("%s: I2C transfer error\n", __func__);
+		return -EIO;
+	} else
+		return 0;
+}
+
+static int tpa2018_i2c_read(char *rxData, int length)
+{
+	struct i2c_msg msgs[] = {
+		{
+			.addr = this_client->addr,
+			.flags = I2C_M_RD,
+			.len = length,
+			.buf = rxData,
+		},
+	};
+
+	if (i2c_transfer(this_client->adapter, msgs, 1) < 0) {
+		pr_err("%s: I2C transfer error\n", __func__);
+		return -EIO;
+	}
+
+#if DEBUG
+	do {
+		int i = 0;
+		for (i = 0; i < length; i++)
+			pr_info("%s: rx[%d] = %2x\n",
+				__func__, i, rxData[i]);
+	} while(0);
+#endif
+
+	return 0;
+}
+
+static int tpa2018d1_open(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+
+	mutex_lock(&spk_amp_lock);
+
+	if (tpa2018d1_opened) {
+		pr_err("%s: busy\n", __func__);
+		rc = -EBUSY;
+		goto done;
+	}
+
+	tpa2018d1_opened = 1;
+done:
+	mutex_unlock(&spk_amp_lock);
+	return rc;
+}
+
+static int tpa2018d1_release(struct inode *inode, struct file *file)
+{
+	mutex_lock(&spk_amp_lock);
+	tpa2018d1_opened = 0;
+	mutex_unlock(&spk_amp_lock);
+
+	return 0;
+}
+
+static int tpa2018d1_read_config(void __user *argp)
+{
+	int rc = 0;
+	unsigned char reg_idx = 0x01;
+	unsigned char tmp[7];
+
+	if (!is_on) {
+		gpio_set_value(pdata->gpio_tpa2018_spk_en, 1);
+		msleep(5); /* According to TPA2018D1 Spec */
+	}
+
+	rc = tpa2018_i2c_write(&reg_idx, sizeof(reg_idx));
+	if (rc < 0)
+		goto err;
+
+	rc = tpa2018_i2c_read(tmp, sizeof(tmp));
+	if (rc < 0)
+		goto err;
+
+	if (copy_to_user(argp, &tmp, sizeof(tmp)))
+		rc = -EFAULT;
+
+err:
+	if (!is_on)
+		gpio_set_value(pdata->gpio_tpa2018_spk_en, 0);
+	return rc;
+}
+
+static int tpa2018d1_ioctl(struct inode *inode, struct file *file,
+		unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int rc = 0;
+	int mode = -1;
+	int offset = 0;
+	struct tpa2018d1_config_data cfg;
+
+	mutex_lock(&spk_amp_lock);
+
+	switch (cmd) {
+	case TPA2018_SET_CONFIG:
+		if (copy_from_user(spk_amp_cfg, argp, sizeof(spk_amp_cfg)))
+			rc = -EFAULT;
+		break;
+
+	case TPA2018_READ_CONFIG:
+		rc = tpa2018d1_read_config(argp);
+		break;
+
+	case TPA2018_SET_MODE:
+		if (copy_from_user(&mode, argp, sizeof(mode))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (mode >= tpa2018d1_num_modes || mode < 0) {
+			pr_err("%s: unsupported tpa2018d1 mode %d\n",
+				__func__, mode);
+			rc = -EINVAL;
+			break;
+		}
+		if (!config_data) {
+			pr_err("%s: no config data!\n", __func__);
+			rc = -EIO;
+			break;
+		}
+		memcpy(spk_amp_cfg, config_data + mode * TPA2018D1_CMD_LEN,
+			TPA2018D1_CMD_LEN);
+		break;
+
+	case TPA2018_SET_PARAM:
+		if (copy_from_user(&cfg, argp, sizeof(cfg))) {
+			pr_err("%s: copy from user failed.\n", __func__);
+			rc = -EFAULT;
+			break;
+		}
+		tpa2018d1_num_modes = cfg.mode_num;
+		if (tpa2018d1_num_modes > TPA2018_NUM_MODES) {
+			pr_err("%s: invalid number of modes %d\n", __func__,
+				tpa2018d1_num_modes);
+			rc = -EINVAL;
+			break;
+		}
+		if (cfg.data_len != tpa2018d1_num_modes*TPA2018D1_CMD_LEN) {
+			pr_err("%s: invalid data length %d, expecting %d\n",
+				__func__, cfg.data_len,
+				tpa2018d1_num_modes * TPA2018D1_CMD_LEN);
+			rc = -EINVAL;
+			break;
+		}
+		/* Free the old data */
+		if (config_data)
+			kfree(config_data);
+		config_data = kmalloc(cfg.data_len, GFP_KERNEL);
+		if (!config_data) {
+			pr_err("%s: out of memory\n", __func__);
+			rc = -ENOMEM;
+			break;
+		}
+		if (copy_from_user(config_data, cfg.cmd_data, cfg.data_len)) {
+			pr_err("%s: copy data from user failed.\n", __func__);
+			kfree(config_data);
+			config_data = NULL;
+			rc = -EFAULT;
+			break;
+		}
+		/* replace default setting with playback setting */
+		if (tpa2018d1_num_modes >= TPA2018_MODE_PLAYBACK) {
+			offset = TPA2018_MODE_PLAYBACK * TPA2018D1_CMD_LEN;
+			memcpy(spk_amp_cfg, config_data + offset,
+					TPA2018D1_CMD_LEN);
+		}
+		break;
+
+	default:
+		pr_err("%s: invalid command %d\n", __func__, _IOC_NR(cmd));
+		rc = -EINVAL;
+		break;
+	}
+	mutex_unlock(&spk_amp_lock);
+	return rc;
+}
+
+static struct file_operations tpa2018d1_fops = {
+	.owner = THIS_MODULE,
+	.open = tpa2018d1_open,
+	.release = tpa2018d1_release,
+	.ioctl = tpa2018d1_ioctl,
+};
+
+static struct miscdevice tpa2018d1_device = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "tpa2018d1",
+	.fops = &tpa2018d1_fops,
+};
+
+void tpa2018d1_set_speaker_amp(int on)
+{
+	if (!pdata) {
+		pr_err("%s: no platform data!\n", __func__);
+		return;
+	}
+	mutex_lock(&spk_amp_lock);
+	if (on && !is_on) {
+		gpio_set_value(pdata->gpio_tpa2018_spk_en, 1);
+		msleep(5); /* According to TPA2018D1 Spec */
+
+		if (tpa2018_i2c_write(spk_amp_cfg, sizeof(spk_amp_cfg)) == 0) {
+			is_on = 1;
+			pr_info("%s: ON\n", __func__);
+		}
+	} else if (!on && is_on) {
+		if (tpa2018_i2c_write(spk_amp_off, sizeof(spk_amp_off)) == 0) {
+			is_on = 0;
+			msleep(2);
+			gpio_set_value(pdata->gpio_tpa2018_spk_en, 0);
+			pr_info("%s: OFF\n", __func__);
+		}
+	}
+	mutex_unlock(&spk_amp_lock);
+}
+
+static int tpa2018d1_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	int ret = 0;
+
+	pdata = client->dev.platform_data;
+
+	if (!pdata) {
+		ret = -EINVAL;
+		pr_err("%s: platform data is NULL\n", __func__);
+		goto err_no_pdata;
+	}
+
+	this_client = client;
+
+	ret = gpio_request(pdata->gpio_tpa2018_spk_en, "tpa2018");
+	if (ret < 0) {
+		pr_err("%s: gpio request aud_spk_en pin failed\n", __func__);
+		goto err_free_gpio;
+	}
+
+	ret = gpio_direction_output(pdata->gpio_tpa2018_spk_en, 1);
+	if (ret < 0) {
+		pr_err("%s: request aud_spk_en gpio direction failed\n",
+			__func__);
+		goto err_free_gpio;
+	}
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		pr_err("%s: i2c check functionality error\n", __func__);
+		ret = -ENODEV;
+		goto err_free_gpio;
+	}
+
+	gpio_set_value(pdata->gpio_tpa2018_spk_en, 0); /* Default Low */
+
+	ret = misc_register(&tpa2018d1_device);
+	if (ret) {
+		pr_err("%s: tpa2018d1_device register failed\n", __func__);
+		goto err_free_gpio;
+	}
+	memcpy(spk_amp_cfg, spk_amp_on, sizeof(spk_amp_on));
+	return 0;
+
+err_free_gpio:
+	gpio_free(pdata->gpio_tpa2018_spk_en);
+err_no_pdata:
+	return ret;
+}
+
+static int tpa2018d1_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	return 0;
+}
+
+static int tpa2018d1_resume(struct i2c_client *client)
+{
+	return 0;
+}
+
+static const struct i2c_device_id tpa2018d1_id[] = {
+	{ TPA2018D1_I2C_NAME, 0 },
+	{ }
+};
+
+static struct i2c_driver tpa2018d1_driver = {
+	.probe = tpa2018d1_probe,
+	.suspend = tpa2018d1_suspend,
+	.resume = tpa2018d1_resume,
+	.id_table = tpa2018d1_id,
+	.driver = {
+		.name = TPA2018D1_I2C_NAME,
+	},
+};
+
+static int __init tpa2018d1_init(void)
+{
+	pr_info("%s\n", __func__);
+	return i2c_add_driver(&tpa2018d1_driver);
+}
+
+module_init(tpa2018d1_init);
+
+MODULE_DESCRIPTION("tpa2018d1 speaker amp driver");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/board-mahimahi-tpa2018d1.h b/arch/arm/mach-msm/board-mahimahi-tpa2018d1.h
new file mode 100644
index 0000000..dc11012
--- /dev/null
+++ b/arch/arm/mach-msm/board-mahimahi-tpa2018d1.h
@@ -0,0 +1,35 @@
+/* include/linux/tpa2018d1.h - tpa2018d1 speaker amplifier driver
+ *
+ * Copyright (C) 2009 HTC Corporation.
+ *
+ * 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_ARM_ARCH_TPA2018D1_H
+#define __ASM_ARM_ARCH_TPA2018D1_H
+
+#define TPA2018D1_I2C_NAME "tpa2018d1"
+#define TPA2018D1_CMD_LEN 8
+
+struct tpa2018d1_platform_data {
+	uint32_t gpio_tpa2018_spk_en;
+};
+
+struct tpa2018d1_config_data {
+	unsigned char *cmd_data;  /* [mode][cmd_len][cmds..] */
+	unsigned int mode_num;
+	unsigned int data_len;
+};
+
+extern void tpa2018d1_set_speaker_amp(int on);
+
+#endif /* __ASM_ARM_ARCH_TPA2018D1_H */
diff --git a/arch/arm/mach-msm/board-mahimahi-wifi.c b/arch/arm/mach-msm/board-mahimahi-wifi.c
new file mode 100644
index 0000000..8cd2476
--- /dev/null
+++ b/arch/arm/mach-msm/board-mahimahi-wifi.c
@@ -0,0 +1,146 @@
+/* linux/arch/arm/mach-msm/board-mahimahi-wifi.c
+*/
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <asm/mach-types.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <linux/skbuff.h>
+#include <linux/wlan_plat.h>
+
+#include "board-mahimahi.h"
+
+int mahimahi_wifi_power(int on);
+int mahimahi_wifi_reset(int on);
+int mahimahi_wifi_set_carddetect(int on);
+
+#define PREALLOC_WLAN_NUMBER_OF_SECTIONS	4
+#define PREALLOC_WLAN_NUMBER_OF_BUFFERS		160
+#define PREALLOC_WLAN_SECTION_HEADER		24
+
+#define WLAN_SECTION_SIZE_0	(PREALLOC_WLAN_NUMBER_OF_BUFFERS * 128)
+#define WLAN_SECTION_SIZE_1	(PREALLOC_WLAN_NUMBER_OF_BUFFERS * 128)
+#define WLAN_SECTION_SIZE_2	(PREALLOC_WLAN_NUMBER_OF_BUFFERS * 512)
+#define WLAN_SECTION_SIZE_3	(PREALLOC_WLAN_NUMBER_OF_BUFFERS * 1024)
+
+#define WLAN_SKB_BUF_NUM	16
+
+static struct sk_buff *wlan_static_skb[WLAN_SKB_BUF_NUM];
+
+typedef struct wifi_mem_prealloc_struct {
+	void *mem_ptr;
+	unsigned long size;
+} wifi_mem_prealloc_t;
+
+static wifi_mem_prealloc_t wifi_mem_array[PREALLOC_WLAN_NUMBER_OF_SECTIONS] = {
+	{ NULL, (WLAN_SECTION_SIZE_0 + PREALLOC_WLAN_SECTION_HEADER) },
+	{ NULL, (WLAN_SECTION_SIZE_1 + PREALLOC_WLAN_SECTION_HEADER) },
+	{ NULL, (WLAN_SECTION_SIZE_2 + PREALLOC_WLAN_SECTION_HEADER) },
+	{ NULL, (WLAN_SECTION_SIZE_3 + PREALLOC_WLAN_SECTION_HEADER) }
+};
+
+static void *mahimahi_wifi_mem_prealloc(int section, unsigned long size)
+{
+	if (section == PREALLOC_WLAN_NUMBER_OF_SECTIONS)
+		return wlan_static_skb;
+	if ((section < 0) || (section > PREALLOC_WLAN_NUMBER_OF_SECTIONS))
+		return NULL;
+	if (wifi_mem_array[section].size < size)
+		return NULL;
+	return wifi_mem_array[section].mem_ptr;
+}
+
+int __init mahimahi_init_wifi_mem(void)
+{
+	int i;
+
+	for(i=0;( i < WLAN_SKB_BUF_NUM );i++) {
+		if (i < (WLAN_SKB_BUF_NUM/2))
+			wlan_static_skb[i] = dev_alloc_skb(4096);
+		else
+			wlan_static_skb[i] = dev_alloc_skb(8192);
+	}
+	for(i=0;( i < PREALLOC_WLAN_NUMBER_OF_SECTIONS );i++) {
+		wifi_mem_array[i].mem_ptr = kmalloc(wifi_mem_array[i].size,
+							GFP_KERNEL);
+		if (wifi_mem_array[i].mem_ptr == NULL)
+			return -ENOMEM;
+	}
+	return 0;
+}
+
+static struct resource mahimahi_wifi_resources[] = {
+	[0] = {
+		.name		= "bcm4329_wlan_irq",
+		.start		= MSM_GPIO_TO_INT(MAHIMAHI_GPIO_WIFI_IRQ),
+		.end		= MSM_GPIO_TO_INT(MAHIMAHI_GPIO_WIFI_IRQ),
+		.flags          = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE,
+	},
+};
+
+static struct wifi_platform_data mahimahi_wifi_control = {
+	.set_power      = mahimahi_wifi_power,
+	.set_reset      = mahimahi_wifi_reset,
+	.set_carddetect = mahimahi_wifi_set_carddetect,
+	.mem_prealloc	= mahimahi_wifi_mem_prealloc,
+};
+
+static struct platform_device mahimahi_wifi_device = {
+        .name           = "bcm4329_wlan",
+        .id             = 1,
+        .num_resources  = ARRAY_SIZE(mahimahi_wifi_resources),
+        .resource       = mahimahi_wifi_resources,
+        .dev            = {
+                .platform_data = &mahimahi_wifi_control,
+        },
+};
+
+extern unsigned char *get_wifi_nvs_ram(void);
+extern int wifi_calibration_size_set(void);
+
+static unsigned mahimahi_wifi_update_nvs(char *str, int add_flag)
+{
+#define NVS_LEN_OFFSET		0x0C
+#define NVS_DATA_OFFSET		0x40
+	unsigned char *ptr;
+	unsigned len;
+
+	if (!str)
+		return -EINVAL;
+	ptr = get_wifi_nvs_ram();
+	/* Size in format LE assumed */
+	memcpy(&len, ptr + NVS_LEN_OFFSET, sizeof(len));
+	/* if the last byte in NVRAM is 0, trim it */
+	if (ptr[NVS_DATA_OFFSET + len - 1] == 0)
+		len -= 1;
+	if (add_flag) {
+		strcpy(ptr + NVS_DATA_OFFSET + len, str);
+		len += strlen(str);
+	} else {
+		if (strnstr(ptr + NVS_DATA_OFFSET, str, len))
+			len -= strlen(str);
+	}
+	memcpy(ptr + NVS_LEN_OFFSET, &len, sizeof(len));
+	wifi_calibration_size_set();
+	return 0;
+}
+
+static int __init mahimahi_wifi_init(void)
+{
+	int ret;
+
+	if (!machine_is_mahimahi())
+		return 0;
+
+	printk("%s: start\n", __func__);
+	mahimahi_wifi_update_nvs("sd_oobonly=1\r\n", 0);
+	mahimahi_wifi_update_nvs("btc_params70=0x32\r\n", 1);
+	mahimahi_init_wifi_mem();
+	ret = platform_device_register(&mahimahi_wifi_device);
+        return ret;
+}
+
+late_initcall(mahimahi_wifi_init);
diff --git a/arch/arm/mach-msm/board-mahimahi.c b/arch/arm/mach-msm/board-mahimahi.c
index 5a4882f..ec87a0d 100644
--- a/arch/arm/mach-msm/board-mahimahi.c
+++ b/arch/arm/mach-msm/board-mahimahi.c
@@ -31,10 +31,10 @@
 #include <mach/board.h>
 #include <mach/hardware.h>
 #include <mach/system.h>
+#include <mach/proc_comm.h>
 
 #include "board-mahimahi.h"
 #include "devices.h"
-#include "proc_comm.h"
 
 static uint debug_uart;
 
diff --git a/arch/arm/mach-msm/board-mahimahi.h b/arch/arm/mach-msm/board-mahimahi.h
new file mode 100644
index 0000000..9696a47
--- /dev/null
+++ b/arch/arm/mach-msm/board-mahimahi.h
@@ -0,0 +1,175 @@
+/* arch/arm/mach-msm/board-mahimahi.h
+ *
+ * Copyright (C) 2009 HTC Corporation.
+ * Author: Haley Teng <Haley_Teng@htc.com>
+ *
+ * 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 __ARCH_ARM_MACH_MSM_BOARD_MAHIMAHI_H
+#define __ARCH_ARM_MACH_MSM_BOARD_MAHIMAHI_H
+
+#include <mach/board.h>
+
+#define MSM_SMI_BASE		0x02B00000
+#define MSM_SMI_SIZE		0x01500000
+
+#define MSM_RAM_CONSOLE_BASE	0x03A00000
+#define MSM_RAM_CONSOLE_SIZE	0x00040000
+
+#define MSM_FB_BASE		0x03B00000
+#define MSM_FB_SIZE		0x00465000
+
+#define MSM_EBI1_BANK0_BASE	0x20000000
+#define MSM_EBI1_BANK0_SIZE	0x0E000000
+
+#define MSM_GPU_MEM_BASE	0x2DB00000
+#define MSM_GPU_MEM_SIZE	0x00500000
+
+#define MSM_EBI1_BANK1_BASE	0x30000000
+#define MSM_EBI1_BANK1_SIZE	0x10000000
+
+#define MSM_PMEM_MDP_BASE	0x30000000
+#define MSM_PMEM_MDP_SIZE	0x02000000
+
+#define MSM_PMEM_ADSP_BASE	0x32000000
+#define MSM_PMEM_ADSP_SIZE	0x02900000
+
+#define MSM_PMEM_CAMERA_BASE	0x34900000
+#define MSM_PMEM_CAMERA_SIZE	0x00800000
+
+#define MSM_HIGHMEM_BASE	0x35100000
+#define MSM_HIGHMEM_SIZE	0x0AF00000
+
+#define MAHIMAHI_GPIO_PS_HOLD		25
+
+#define MAHIMAHI_GPIO_UP_INT_N		35
+#define MAHIMAHI_GPIO_UP_RESET_N	82
+#define MAHIMAHI_GPIO_LS_EN_N		119
+
+#define MAHIMAHI_GPIO_TP_INT_N		92
+#define MAHIMAHI_GPIO_TP_LS_EN		93
+#define MAHIMAHI_GPIO_TP_EN		160
+
+#define MAHIMAHI_GPIO_POWER_KEY		94
+#define MAHIMAHI_GPIO_SDMC_CD_REV0_N	153
+
+#define MAHIMAHI_GPIO_WIFI_SHUTDOWN_N	127
+#define MAHIMAHI_GPIO_WIFI_IRQ		152
+
+#define MAHIMAHI_GPIO_BALL_UP		38
+#define MAHIMAHI_GPIO_BALL_DOWN		37
+#define MAHIMAHI_GPIO_BALL_LEFT		145
+#define MAHIMAHI_GPIO_BALL_RIGHT	21
+
+#define MAHIMAHI_GPIO_BT_UART1_RTS	43
+#define MAHIMAHI_GPIO_BT_UART1_CTS	44
+#define MAHIMAHI_GPIO_BT_UART1_RX	45
+#define MAHIMAHI_GPIO_BT_UART1_TX	46
+#define MAHIMAHI_GPIO_BT_RESET_N	146
+#define MAHIMAHI_GPIO_BT_SHUTDOWN_N	128
+
+#define MAHIMAHI_GPIO_BT_WAKE		57
+#define MAHIMAHI_GPIO_BT_HOST_WAKE	86
+
+#define MAHIMAHI_GPIO_PROXIMITY_INT_N	90
+#define MAHIMAHI_GPIO_PROXIMITY_EN	120
+
+#define MAHIMAHI_GPIO_DS2482_SLP_N	87
+#define MAHIMAHI_GPIO_VIBRATOR_ON	89
+/* Compass */
+#define MAHIMAHI_REV0_GPIO_COMPASS_INT_N	36
+
+#define MAHIMAHI_GPIO_COMPASS_INT_N	153
+#define MAHIMAHI_GPIO_COMPASS_RST_N	107
+#define MAHIMAHI_PROJECT_NAME          "mahimahi"
+#define MAHIMAHI_LAYOUTS { 			   \
+	{ {-1,  0, 0}, { 0, -1,  0}, {0, 0,  1} }, \
+	{ { 0, -1, 0}, { 1,  0,  0}, {0, 0, -1} }, \
+	{ { 0, -1, 0}, { 1,  0,  0}, {0, 0,  1} }, \
+	{ {-1,  0, 0}, { 0,  0, -1}, {0, 1,  0} }  \
+}
+
+/* Audio */
+#define MAHIMAHI_AUD_JACKHP_EN		157
+#define MAHIMAHI_AUD_2V5_EN		158
+#define MAHIMAHI_AUD_MICPATH_SEL 	111
+#define MAHIMAHI_AUD_A1026_INT		112
+#define MAHIMAHI_AUD_A1026_WAKEUP 	113
+#define MAHIMAHI_AUD_A1026_RESET 	129
+#define MAHIMAHI_AUD_A1026_CLK		 -1
+#define MAHIMAHI_CDMA_XA_AUD_A1026_CLK	105
+/* NOTE: MAHIMAHI_CDMA_XB_AUD_A1026_WAKEUP on CDMA is the same GPIO as
+ * MAHIMAHI_GPIO_BATTERY_CHARGER_CURRENT on UMTS.  Also,
+ * MAHIMAHI_CDMA_XB_AUD_A1026_RESET is the same as
+ * GPIO MAHIMAHI_GPIO_35MM_KEY_INT_SHUTDOWN on UMTS.
+ */
+#define MAHIMAHI_CDMA_XB_AUD_A1026_WAKEUP	16
+#define MAHIMAHI_CDMA_XB_AUD_A1026_RESET	19
+#define MAHIMAHI_CDMA_XB_AUD_A1026_CLK	-1
+
+/* Bluetooth PCM */
+#define MAHIMAHI_BT_PCM_OUT		68
+#define MAHIMAHI_BT_PCM_IN		69
+#define MAHIMAHI_BT_PCM_SYNC		70
+#define MAHIMAHI_BT_PCM_CLK		71
+/* flash light */
+#define MAHIMAHI_GPIO_FLASHLIGHT_TORCH	58
+#define MAHIMAHI_GPIO_FLASHLIGHT_FLASH	84
+
+#define MAHIMAHI_GPIO_LED_3V3_EN	85
+#define MAHIMAHI_GPIO_LCD_RST_N		29
+#define MAHIMAHI_GPIO_LCD_ID0		147
+
+/* 3.5mm remote control key interrupt shutdown signal */
+#define MAHIMAHI_GPIO_35MM_KEY_INT_SHUTDOWN	19
+
+#define MAHIMAHI_GPIO_DOCK		106
+
+/* speaker amplifier enable pin for mahimahi CDMA version */
+#define MAHIMAHI_CDMA_GPIO_AUD_SPK_AMP_EN	104
+
+#define MAHIMAHI_GPIO_BATTERY_DETECTION		39
+#define MAHIMAHI_GPIO_BATTERY_CHARGER_EN	22
+#define MAHIMAHI_GPIO_BATTERY_CHARGER_CURRENT	16
+
+#define MAHIMAHI_CDMA_GPIO_BT_WAKE		28
+#define MAHIMAHI_CDMA_GPIO_FLASHLIGHT_TORCH	26
+
+#define MAHIMAHI_CDMA_SD_2V85_EN		100
+#define MAHIMAHI_CDMA_JOG_2V6_EN		150
+/* display relative */
+#define MAHIMAHI_LCD_SPI_CLK            (17)
+#define MAHIMAHI_LCD_SPI_DO             (18)
+#define MAHIMAHI_LCD_SPI_CSz            (20)
+#define MAHIMAHI_LCD_RSTz               (29)
+#define MAHIMAHI_LCD_R1                 (114)
+#define MAHIMAHI_LCD_R2                 (115)
+#define MAHIMAHI_LCD_R3                 (116)
+#define MAHIMAHI_LCD_R4                 (117)
+#define MAHIMAHI_LCD_R5                 (118)
+#define MAHIMAHI_LCD_G0                 (121)
+#define MAHIMAHI_LCD_G1                 (122)
+#define MAHIMAHI_LCD_G2                 (123)
+#define MAHIMAHI_LCD_G3                 (124)
+#define MAHIMAHI_LCD_G4                 (125)
+#define MAHIMAHI_LCD_G5                 (126)
+#define MAHIMAHI_LCD_B1                 (130)
+#define MAHIMAHI_LCD_B2                 (131)
+#define MAHIMAHI_LCD_B3                 (132)
+#define MAHIMAHI_LCD_B4                 (133)
+#define MAHIMAHI_LCD_B5                 (134)
+#define MAHIMAHI_LCD_PCLK               (135)
+#define MAHIMAHI_LCD_VSYNC              (136)
+#define MAHIMAHI_LCD_HSYNC              (137)
+#define MAHIMAHI_LCD_DE                 (138)
+#define is_cdma_version(rev) (((rev) & 0xF0) == 0xC0)
+
+#endif /* __ARCH_ARM_MACH_MSM_BOARD_MAHIMAHI_H */
diff --git a/arch/arm/mach-msm/board-msm7627-regulator.c b/arch/arm/mach-msm/board-msm7627-regulator.c
new file mode 100644
index 0000000..7437911
--- /dev/null
+++ b/arch/arm/mach-msm/board-msm7627-regulator.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "board-msm7627-regulator.h"
+
+#define PCOM_VREG_CONSUMERS(name) \
+	static struct regulator_consumer_supply __pcom_vreg_supply_##name[]
+
+#define PCOM_VREG_CONSTRAINT_LVSW(_name, _always_on, _boot_on, _supply_uV) \
+{ \
+	.name = #_name, \
+	.min_uV = 0, \
+	.max_uV = 0, \
+	.input_uV = _supply_uV, \
+	.valid_modes_mask = REGULATOR_MODE_NORMAL, \
+	.valid_ops_mask = REGULATOR_CHANGE_STATUS, \
+	.apply_uV = 0, \
+	.boot_on = _boot_on, \
+	.always_on = _always_on \
+}
+
+#define PCOM_VREG_CONSTRAINT_DYN(_name, _min_uV, _max_uV, _always_on, \
+		_boot_on, _apply_uV, _supply_uV) \
+{ \
+	.name = #_name, \
+	.min_uV = _min_uV, \
+	.max_uV = _max_uV, \
+	.valid_modes_mask = REGULATOR_MODE_NORMAL, \
+	.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, \
+	.input_uV = _supply_uV, \
+	.apply_uV = _apply_uV, \
+	.boot_on = _boot_on, \
+	.always_on = _always_on \
+}
+
+
+#define PCOM_VREG_INIT(_name, _supply, _constraints)\
+{ \
+	.supply_regulator = _supply, \
+	.consumer_supplies = __pcom_vreg_supply_##_name, \
+	.num_consumer_supplies = ARRAY_SIZE(__pcom_vreg_supply_##_name), \
+	.constraints = _constraints \
+}
+
+#define PCOM_VREG_SMP(_name, _id, _supply, _min_uV, _max_uV, _rise_time, \
+		_pulldown, _always_on, _boot_on, _apply_uV, _supply_uV) \
+{ \
+	.init_data = PCOM_VREG_INIT(_name, _supply, \
+		PCOM_VREG_CONSTRAINT_DYN(_name, _min_uV, _max_uV, _always_on, \
+			_boot_on, _apply_uV, _supply_uV)), \
+	.id = _id, \
+	.rise_time = _rise_time, \
+	.pulldown = _pulldown, \
+	.negative = 0, \
+}
+
+#define PCOM_VREG_LDO PCOM_VREG_SMP
+
+PCOM_VREG_CONSUMERS(smps0) = {
+	REGULATOR_SUPPLY("smps0",	NULL),
+	REGULATOR_SUPPLY("msmc1",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(smps1) = {
+	REGULATOR_SUPPLY("smps1",	NULL),
+	REGULATOR_SUPPLY("msmc2",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(smps2) = {
+	REGULATOR_SUPPLY("smps2",	NULL),
+	REGULATOR_SUPPLY("pa",		NULL),
+};
+
+PCOM_VREG_CONSUMERS(smps3) = {
+	REGULATOR_SUPPLY("smps3",	NULL),
+	REGULATOR_SUPPLY("msme1",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo00) = {
+	REGULATOR_SUPPLY("ldo00",	NULL),
+	REGULATOR_SUPPLY("gp3",		NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo01) = {
+	REGULATOR_SUPPLY("ldo01",	NULL),
+	REGULATOR_SUPPLY("msma",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo02) = {
+	REGULATOR_SUPPLY("ldo02",	NULL),
+	REGULATOR_SUPPLY("msmp",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo03) = {
+	REGULATOR_SUPPLY("ldo03",	NULL),
+	REGULATOR_SUPPLY("ruim",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo04) = {
+	REGULATOR_SUPPLY("ldo04",	NULL),
+	REGULATOR_SUPPLY("tcxo",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo05) = {
+	REGULATOR_SUPPLY("ldo05",	NULL),
+	REGULATOR_SUPPLY("mmc",		NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo06) = {
+	REGULATOR_SUPPLY("ldo06",	NULL),
+	REGULATOR_SUPPLY("usb",		NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo07) = {
+	REGULATOR_SUPPLY("ldo07",	NULL),
+	REGULATOR_SUPPLY("rfrx1",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo08) = {
+	REGULATOR_SUPPLY("ldo08",	NULL),
+	REGULATOR_SUPPLY("synt",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo09) = {
+	REGULATOR_SUPPLY("ldo09",	NULL),
+	REGULATOR_SUPPLY("gp1",		NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo10) = {
+	REGULATOR_SUPPLY("ldo10",	NULL),
+	REGULATOR_SUPPLY("gp4",		NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo11) = {
+	REGULATOR_SUPPLY("ldo11",	NULL),
+	REGULATOR_SUPPLY("gp2",		NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo12) = {
+	REGULATOR_SUPPLY("ldo12",	NULL),
+	REGULATOR_SUPPLY("rftx",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo13) = {
+	REGULATOR_SUPPLY("ldo13",	NULL),
+	REGULATOR_SUPPLY("wlan",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo14) = {
+	REGULATOR_SUPPLY("ldo14",	NULL),
+	REGULATOR_SUPPLY("rf",		NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo15) = {
+	REGULATOR_SUPPLY("ldo15",	NULL),
+	REGULATOR_SUPPLY("gp6",		NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo16) = {
+	REGULATOR_SUPPLY("ldo16",	NULL),
+	REGULATOR_SUPPLY("gp5",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo17) = {
+	REGULATOR_SUPPLY("ldo17",	NULL),
+	REGULATOR_SUPPLY("msme2",	NULL),
+};
+
+/**
+ * Minimum and Maximum range for the regulators is as per the
+ * device Datasheet. Actual value used by consumer is between
+ * the provided range.
+ */
+static struct proccomm_regulator_info msm7627_pcom_vreg_info[] = {
+	/* Standard regulators (SMPS and LDO)
+	 * R = rise time (us)
+	 * P = pulldown (1 = pull down, 0 = float, -1 = don't care)
+	 * A = always on
+	 * B = boot on
+	 * V = automatic voltage set (meaningful for single-voltage regs only)
+	 * S = supply voltage (uV)
+	 *             name  id  supp    min uV    max uV  R   P  A  B  V  S */
+	PCOM_VREG_SMP(smps0,  3, NULL,  750000,  3050000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_SMP(smps1,  4, NULL,  750000,  3050000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_SMP(smps2, 10, NULL,  750000,  3050000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_SMP(smps3,  2, NULL,  750000,  3050000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo00,  5, NULL,  2850000,  2850000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo01,  0, NULL,  2600000,  2600000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo02,  1, NULL,  2600000,  2600000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo03, 19, NULL,  2850000,  2850000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo04,  9, NULL,  2850000,  2850000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo05, 18, NULL,  2850000,  2850000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo06, 16, NULL,  3300000,  3300000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo07, 12, NULL,  2700000,  2700000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo08, 14, NULL,  2700000,  2700000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo09,  8, NULL,  2900000,  2900000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo10,  7, NULL,  2600000,  2600000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo11, 21, NULL,  1800000,  1800000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo12, 11, NULL,  1800000,  1800000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo13, 15, NULL,  1800000,  2850000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo14, 24, NULL,  2700000,  2700000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo15, 23, NULL,  2600000,  2600000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo16, 22, NULL,  2850000,  3000000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo17,  6, NULL,  1300000,  1300000, 0, -1, 0, 0, 0, 0),
+
+};
+
+struct proccomm_regulator_platform_data msm7627_proccomm_regulator_data = {
+	.regs = msm7627_pcom_vreg_info,
+	.nregs = ARRAY_SIZE(msm7627_pcom_vreg_info)
+};
diff --git a/arch/arm/mach-msm/board-msm7627-regulator.h b/arch/arm/mach-msm/board-msm7627-regulator.h
new file mode 100644
index 0000000..d82c5c0
--- /dev/null
+++ b/arch/arm/mach-msm/board-msm7627-regulator.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_BOARD_7627_REGULATOR_H__
+#define __ARCH_ARM_MACH_MSM_BOARD_7627_REGULATOR_H__
+
+#include "proccomm-regulator.h"
+
+extern struct proccomm_regulator_platform_data msm7627_proccomm_regulator_data;
+
+#endif
diff --git a/arch/arm/mach-msm/board-msm7627a-bt.c b/arch/arm/mach-msm/board-msm7627a-bt.c
new file mode 100644
index 0000000..e4edf9b
--- /dev/null
+++ b/arch/arm/mach-msm/board-msm7627a-bt.c
@@ -0,0 +1,1018 @@
+/* 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
+ * 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/delay.h>
+#include <linux/rfkill.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mfd/marimba.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <asm/mach-types.h>
+#include <mach/rpc_pmapp.h>
+#include <mach/socinfo.h>
+
+#include "board-msm7627a.h"
+#include "devices-msm7x2xa.h"
+
+#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
+
+
+static struct bt_vreg_info bt_vregs[] = {
+	{"msme1", 2, 1800000, 1800000, 0, NULL},
+	{"bt", 21, 2900000, 3300000, 1, NULL}
+};
+
+static struct platform_device msm_bt_power_device = {
+	.name = "bt_power",
+};
+
+static unsigned bt_config_power_on[] = {
+	/*RFR*/
+	GPIO_CFG(43, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	/*CTS*/
+	GPIO_CFG(44, 2, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	/*RX*/
+	GPIO_CFG(45, 2, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	/*TX*/
+	GPIO_CFG(46, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+};
+static unsigned bt_config_pcm_on[] = {
+	/*PCM_DOUT*/
+	GPIO_CFG(68, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	/*PCM_DIN*/
+	GPIO_CFG(69, 1, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	/*PCM_SYNC*/
+	GPIO_CFG(70, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	/*PCM_CLK*/
+	GPIO_CFG(71, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+};
+static unsigned bt_config_power_off[] = {
+	/*RFR*/
+	GPIO_CFG(43, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/*CTS*/
+	GPIO_CFG(44, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/*RX*/
+	GPIO_CFG(45, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/*TX*/
+	GPIO_CFG(46, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+};
+static unsigned bt_config_pcm_off[] = {
+	/*PCM_DOUT*/
+	GPIO_CFG(68, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/*PCM_DIN*/
+	GPIO_CFG(69, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/*PCM_SYNC*/
+	GPIO_CFG(70, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/*PCM_CLK*/
+	GPIO_CFG(71, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+};
+
+static unsigned fm_i2s_config_power_on[] = {
+	/*FM_I2S_SD*/
+	GPIO_CFG(68, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	/*FM_I2S_WS*/
+	GPIO_CFG(70, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	/*FM_I2S_SCK*/
+	GPIO_CFG(71, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+};
+
+static unsigned fm_i2s_config_power_off[] = {
+	/*FM_I2S_SD*/
+	GPIO_CFG(68, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/*FM_I2S_WS*/
+	GPIO_CFG(70, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/*FM_I2S_SCK*/
+	GPIO_CFG(71, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+};
+
+int gpio_bt_sys_rest_en = 133;
+static void gpio_bt_config(void)
+{
+	u32 socinfo = socinfo_get_platform_version();
+	if (machine_is_msm7627a_qrd1())
+		gpio_bt_sys_rest_en = 114;
+	if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()
+				|| machine_is_msm8625_evt())
+		gpio_bt_sys_rest_en = 16;
+	if (machine_is_msm8625_qrd7())
+		gpio_bt_sys_rest_en = 88;
+	if (machine_is_msm7627a_qrd3()) {
+		if (socinfo == 0x70002)
+			gpio_bt_sys_rest_en = 88;
+		 else
+			gpio_bt_sys_rest_en = 85;
+	}
+}
+
+static int bt_set_gpio(int on)
+{
+	int rc = 0;
+	struct marimba config = { .mod_id =  SLAVE_ID_BAHAMA};
+
+	pr_debug("%s: Setting SYS_RST_PIN(%d) to %d\n",
+			__func__, gpio_bt_sys_rest_en, on);
+	if (on) {
+
+		if (machine_is_msm7627a_evb() || machine_is_msm8625_qrd7()) {
+			rc = gpio_tlmm_config(GPIO_CFG(gpio_bt_sys_rest_en, 0,
+					GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
+					GPIO_CFG_2MA),
+					GPIO_CFG_ENABLE);
+
+			gpio_set_value(gpio_bt_sys_rest_en, 1);
+		} else {
+			rc = gpio_direction_output(gpio_bt_sys_rest_en, 1);
+		}
+		msleep(100);
+	} else {
+
+		if (!marimba_get_fm_status(&config) &&
+				!marimba_get_bt_status(&config)) {
+			if (machine_is_msm7627a_evb() ||
+					 machine_is_msm8625_qrd7()) {
+				gpio_set_value(gpio_bt_sys_rest_en, 0);
+				rc = gpio_tlmm_config(GPIO_CFG(
+					gpio_bt_sys_rest_en, 0,
+					GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN,
+					GPIO_CFG_2MA),
+					GPIO_CFG_ENABLE);
+			} else {
+				gpio_set_value_cansleep(gpio_bt_sys_rest_en, 0);
+				rc = gpio_direction_input(gpio_bt_sys_rest_en);
+			}
+			msleep(100);
+		}
+	}
+	if (rc)
+		pr_err("%s: BT sys_reset_en GPIO : Error", __func__);
+
+	return rc;
+}
+
+static struct regulator *fm_regulator;
+static int fm_radio_setup(struct marimba_fm_platform_data *pdata)
+{
+	int rc = 0;
+	const char *id = "FMPW";
+	uint32_t irqcfg;
+	struct marimba config = { .mod_id =  SLAVE_ID_BAHAMA};
+	u8 value;
+
+	/* Voting for 1.8V Regulator */
+	fm_regulator = regulator_get(NULL , "msme1");
+	if (IS_ERR(fm_regulator)) {
+		rc = PTR_ERR(fm_regulator);
+		pr_err("%s: could not get regulator: %d\n", __func__, rc);
+		goto out;
+	}
+
+	/* Set the voltage level to 1.8V */
+	rc = regulator_set_voltage(fm_regulator, 1800000, 1800000);
+	if (rc < 0) {
+		pr_err("%s: could not set voltage: %d\n", __func__, rc);
+		goto reg_free;
+	}
+
+	/* Enabling the 1.8V regulator */
+	rc = regulator_enable(fm_regulator);
+	if (rc) {
+		pr_err("%s: could not enable regulator: %d\n", __func__, rc);
+		goto reg_free;
+	}
+
+	/* Voting for 19.2MHz clock */
+	rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
+			PMAPP_CLOCK_VOTE_ON);
+	if (rc < 0) {
+		pr_err("%s: clock vote failed with :(%d)\n",
+			__func__, rc);
+		goto reg_disable;
+	}
+
+	rc = bt_set_gpio(1);
+	if (rc) {
+		pr_err("%s: bt_set_gpio = %d", __func__, rc);
+		goto gpio_deconfig;
+	}
+	/*re-write FM Slave Id, after reset*/
+	value = BAHAMA_SLAVE_ID_FM_ADDR;
+	rc = marimba_write_bit_mask(&config,
+			BAHAMA_SLAVE_ID_FM_REG, &value, 1, 0xFF);
+	if (rc < 0) {
+		pr_err("%s: FM Slave ID rewrite Failed = %d", __func__, rc);
+		goto gpio_deconfig;
+	}
+	/* Configuring the FM GPIO */
+	irqcfg = GPIO_CFG(FM_GPIO, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL,
+			GPIO_CFG_2MA);
+
+	rc = gpio_tlmm_config(irqcfg, GPIO_CFG_ENABLE);
+	if (rc) {
+		pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
+			 __func__, irqcfg, rc);
+		goto gpio_deconfig;
+	}
+
+	return 0;
+
+gpio_deconfig:
+	pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
+		PMAPP_CLOCK_VOTE_OFF);
+	bt_set_gpio(0);
+reg_disable:
+	regulator_disable(fm_regulator);
+reg_free:
+	regulator_put(fm_regulator);
+	fm_regulator = NULL;
+out:
+	return rc;
+};
+
+static void fm_radio_shutdown(struct marimba_fm_platform_data *pdata)
+{
+	int rc;
+	const char *id = "FMPW";
+
+	/* Releasing the GPIO line used by FM */
+	uint32_t irqcfg = GPIO_CFG(FM_GPIO, 0, GPIO_CFG_INPUT,
+		GPIO_CFG_PULL_UP, GPIO_CFG_2MA);
+
+	rc = gpio_tlmm_config(irqcfg, GPIO_CFG_ENABLE);
+	if (rc)
+		pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
+			 __func__, irqcfg, rc);
+
+	/* Releasing the 1.8V Regulator */
+	if (!IS_ERR_OR_NULL(fm_regulator)) {
+		rc = regulator_disable(fm_regulator);
+		if (rc)
+			pr_err("%s: could not disable regulator: %d\n",
+					__func__, rc);
+		regulator_put(fm_regulator);
+		fm_regulator = NULL;
+	}
+
+	/* Voting off the clock */
+	rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
+		PMAPP_CLOCK_VOTE_OFF);
+	if (rc < 0)
+		pr_err("%s: voting off failed with :(%d)\n",
+			__func__, rc);
+	rc = bt_set_gpio(0);
+	if (rc)
+		pr_err("%s: bt_set_gpio = %d", __func__, rc);
+}
+static int switch_pcm_i2s_reg_mode(int mode)
+{
+	unsigned char reg = 0;
+	int rc = -1;
+	unsigned char set = I2C_PIN_CTL; /*SET PIN CTL mode*/
+	unsigned char unset = I2C_NORMAL; /* UNSET PIN CTL MODE*/
+	struct marimba config = { .mod_id =  SLAVE_ID_BAHAMA};
+
+	if (mode == 0) {
+		/* as we need to switch path to FM we need to move
+		BT AUX PCM lines to PIN CONTROL mode then move
+		FM to normal mode.*/
+		for (reg = BT_PCM_BCLK_MODE; reg <= BT_PCM_SYNC_MODE; reg++) {
+			rc = marimba_write(&config, reg, &set, 1);
+			if (rc < 0) {
+				pr_err("pcm pinctl failed = %d", rc);
+				goto err_all;
+			}
+		}
+		for (reg = FM_I2S_SD_MODE; reg <= FM_I2S_SCK_MODE; reg++) {
+			rc = marimba_write(&config, reg, &unset, 1);
+			if (rc < 0) {
+				pr_err("i2s normal failed = %d", rc);
+				goto err_all;
+			}
+		}
+	} else {
+		/* as we need to switch path to AUXPCM we need to move
+		FM I2S lines to PIN CONTROL mode then move
+		BT AUX_PCM to normal mode.*/
+		for (reg = FM_I2S_SD_MODE; reg <= FM_I2S_SCK_MODE; reg++) {
+			rc = marimba_write(&config, reg, &set, 1);
+			if (rc < 0) {
+				pr_err("i2s pinctl failed = %d", rc);
+				goto err_all;
+			}
+		}
+		for (reg = BT_PCM_BCLK_MODE; reg <= BT_PCM_SYNC_MODE; reg++) {
+			rc = marimba_write(&config, reg, &unset, 1);
+			if (rc < 0) {
+				pr_err("pcm normal failed = %d", rc);
+				goto err_all;
+			}
+		}
+	}
+
+	return 0;
+
+err_all:
+	return rc;
+}
+
+
+static void config_pcm_i2s_mode(int mode)
+{
+	void __iomem *cfg_ptr;
+	u8 reg2;
+
+	cfg_ptr = ioremap_nocache(FPGA_MSM_CNTRL_REG2, sizeof(char));
+
+	if (!cfg_ptr)
+		return;
+	if (mode) {
+		/*enable the pcm mode in FPGA*/
+		reg2 = readb_relaxed(cfg_ptr);
+		if (reg2 == 0) {
+			reg2 = 1;
+			writeb_relaxed(reg2, cfg_ptr);
+		}
+	} else {
+		/*enable i2s mode in FPGA*/
+		reg2 = readb_relaxed(cfg_ptr);
+		if (reg2 == 1) {
+			reg2 = 0;
+			writeb_relaxed(reg2, cfg_ptr);
+		}
+	}
+	iounmap(cfg_ptr);
+}
+
+static int config_i2s(int mode)
+{
+	int pin, rc = 0;
+
+	if (mode == FM_I2S_ON) {
+		if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf()
+				|| machine_is_msm8625_surf())
+			config_pcm_i2s_mode(0);
+		pr_err("%s mode = FM_I2S_ON", __func__);
+
+		rc = switch_pcm_i2s_reg_mode(0);
+		if (rc) {
+			pr_err("switch mode failed");
+			return rc;
+		}
+		for (pin = 0; pin < ARRAY_SIZE(fm_i2s_config_power_on);
+			pin++) {
+				rc = gpio_tlmm_config(
+					fm_i2s_config_power_on[pin],
+					GPIO_CFG_ENABLE
+					);
+				if (rc < 0)
+					return rc;
+			}
+	} else if (mode == FM_I2S_OFF) {
+		pr_err("%s mode = FM_I2S_OFF", __func__);
+		rc = switch_pcm_i2s_reg_mode(1);
+		if (rc) {
+			pr_err("switch mode failed");
+			return rc;
+		}
+		for (pin = 0; pin < ARRAY_SIZE(fm_i2s_config_power_off);
+			pin++) {
+				rc = gpio_tlmm_config(
+					fm_i2s_config_power_off[pin],
+					GPIO_CFG_ENABLE
+					);
+				if (rc < 0)
+					return rc;
+			}
+	}
+	return rc;
+}
+
+static int config_pcm(int mode)
+{
+	int pin, rc = 0;
+
+	if (mode == BT_PCM_ON) {
+		if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf()
+				|| machine_is_msm8625_surf())
+			config_pcm_i2s_mode(1);
+		pr_err("%s mode =BT_PCM_ON", __func__);
+		rc = switch_pcm_i2s_reg_mode(1);
+		if (rc) {
+			pr_err("switch mode failed");
+			return rc;
+		}
+		for (pin = 0; pin < ARRAY_SIZE(bt_config_pcm_on);
+			pin++) {
+				rc = gpio_tlmm_config(bt_config_pcm_on[pin],
+					GPIO_CFG_ENABLE);
+				if (rc < 0)
+					return rc;
+		}
+	} else if (mode == BT_PCM_OFF) {
+		pr_err("%s mode =BT_PCM_OFF", __func__);
+		rc = switch_pcm_i2s_reg_mode(0);
+		if (rc) {
+			pr_err("switch mode failed");
+			return rc;
+		}
+		for (pin = 0; pin < ARRAY_SIZE(bt_config_pcm_off);
+			pin++) {
+				rc = gpio_tlmm_config(bt_config_pcm_off[pin],
+					GPIO_CFG_ENABLE);
+				if (rc < 0)
+					return rc;
+		}
+
+	}
+
+	return rc;
+}
+
+static int msm_bahama_setup_pcm_i2s(int mode)
+{
+	int fm_state = 0, bt_state = 0;
+	int rc = 0;
+	struct marimba config = { .mod_id =  SLAVE_ID_BAHAMA};
+
+	fm_state = marimba_get_fm_status(&config);
+	bt_state = marimba_get_bt_status(&config);
+
+	switch (mode) {
+	case BT_PCM_ON:
+	case BT_PCM_OFF:
+		if (!fm_state)
+			rc = config_pcm(mode);
+		break;
+	case FM_I2S_ON:
+		rc = config_i2s(mode);
+		break;
+	case FM_I2S_OFF:
+		if (bt_state)
+			rc = config_pcm(BT_PCM_ON);
+		else
+			rc = config_i2s(mode);
+		break;
+	default:
+		rc = -EIO;
+		pr_err("%s:Unsupported mode", __func__);
+	}
+	return rc;
+}
+
+static int bahama_bt(int on)
+{
+	int rc = 0;
+	int i;
+
+	struct marimba config = { .mod_id =  SLAVE_ID_BAHAMA};
+
+	struct bahama_variant_register {
+		const size_t size;
+		const struct bahama_config_register *set;
+	};
+
+	const struct bahama_config_register *p;
+
+	u8 version;
+
+	const struct bahama_config_register v10_bt_on[] = {
+		{ 0xE9, 0x00, 0xFF },
+		{ 0xF4, 0x80, 0xFF },
+		{ 0xE4, 0x00, 0xFF },
+		{ 0xE5, 0x00, 0x0F },
+#ifdef CONFIG_WLAN
+		{ 0xE6, 0x38, 0x7F },
+		{ 0xE7, 0x06, 0xFF },
+#endif
+		{ 0xE9, 0x21, 0xFF },
+		{ 0x01, 0x0C, 0x1F },
+		{ 0x01, 0x08, 0x1F },
+	};
+
+	const struct bahama_config_register v20_bt_on_fm_off[] = {
+		{ 0x11, 0x0C, 0xFF },
+		{ 0x13, 0x01, 0xFF },
+		{ 0xF4, 0x80, 0xFF },
+		{ 0xF0, 0x00, 0xFF },
+		{ 0xE9, 0x00, 0xFF },
+#ifdef CONFIG_WLAN
+		{ 0x81, 0x00, 0x7F },
+		{ 0x82, 0x00, 0xFF },
+		{ 0xE6, 0x38, 0x7F },
+		{ 0xE7, 0x06, 0xFF },
+#endif
+		{ 0x8E, 0x15, 0xFF },
+		{ 0x8F, 0x15, 0xFF },
+		{ 0x90, 0x15, 0xFF },
+
+		{ 0xE9, 0x21, 0xFF },
+	};
+
+	const struct bahama_config_register v20_bt_on_fm_on[] = {
+		{ 0x11, 0x0C, 0xFF },
+		{ 0x13, 0x01, 0xFF },
+		{ 0xF4, 0x86, 0xFF },
+		{ 0xF0, 0x06, 0xFF },
+		{ 0xE9, 0x00, 0xFF },
+#ifdef CONFIG_WLAN
+		{ 0x81, 0x00, 0x7F },
+		{ 0x82, 0x00, 0xFF },
+		{ 0xE6, 0x38, 0x7F },
+		{ 0xE7, 0x06, 0xFF },
+#endif
+		{ 0xE9, 0x21, 0xFF },
+	};
+
+	const struct bahama_config_register v10_bt_off[] = {
+		{ 0xE9, 0x00, 0xFF },
+	};
+
+	const struct bahama_config_register v20_bt_off_fm_off[] = {
+		{ 0xF4, 0x84, 0xFF },
+		{ 0xF0, 0x04, 0xFF },
+		{ 0xE9, 0x00, 0xFF }
+	};
+
+	const struct bahama_config_register v20_bt_off_fm_on[] = {
+		{ 0xF4, 0x86, 0xFF },
+		{ 0xF0, 0x06, 0xFF },
+		{ 0xE9, 0x00, 0xFF }
+	};
+
+	const struct bahama_variant_register bt_bahama[2][3] = {
+	{
+		{ ARRAY_SIZE(v10_bt_off), v10_bt_off },
+		{ ARRAY_SIZE(v20_bt_off_fm_off), v20_bt_off_fm_off },
+		{ ARRAY_SIZE(v20_bt_off_fm_on), v20_bt_off_fm_on }
+	},
+	{
+		{ ARRAY_SIZE(v10_bt_on), v10_bt_on },
+		{ ARRAY_SIZE(v20_bt_on_fm_off), v20_bt_on_fm_off },
+		{ ARRAY_SIZE(v20_bt_on_fm_on), v20_bt_on_fm_on }
+	}
+	};
+
+	u8 offset = 0; /* index into bahama configs */
+	on = on ? 1 : 0;
+	version = marimba_read_bahama_ver(&config);
+	if ((int)version < 0 || version == BAHAMA_VER_UNSUPPORTED) {
+		dev_err(&msm_bt_power_device.dev, "%s : Bahama "
+			"version read Error, version = %d\n",
+			__func__, version);
+		return -EIO;
+	}
+
+	if (version == BAHAMA_VER_2_0) {
+		if (marimba_get_fm_status(&config))
+			offset = 0x01;
+	}
+
+	p = bt_bahama[on][version + offset].set;
+
+	dev_info(&msm_bt_power_device.dev,
+		"%s: found version %d\n", __func__, version);
+
+	for (i = 0; i < bt_bahama[on][version + offset].size; i++) {
+		u8 value = (p+i)->value;
+		rc = marimba_write_bit_mask(&config,
+			(p+i)->reg,
+			&value,
+			sizeof((p+i)->value),
+			(p+i)->mask);
+		if (rc < 0) {
+			dev_err(&msm_bt_power_device.dev,
+				"%s: reg %x write failed: %d\n",
+				__func__, (p+i)->reg, rc);
+			return rc;
+		}
+		dev_dbg(&msm_bt_power_device.dev,
+			"%s: reg 0x%02x write value 0x%02x mask 0x%02x\n",
+				__func__, (p+i)->reg,
+				value, (p+i)->mask);
+		value = 0;
+		rc = marimba_read_bit_mask(&config,
+				(p+i)->reg, &value,
+				sizeof((p+i)->value), (p+i)->mask);
+		if (rc < 0)
+			dev_err(&msm_bt_power_device.dev,
+				"%s marimba_read_bit_mask- error",
+				__func__);
+		dev_dbg(&msm_bt_power_device.dev,
+			"%s: reg 0x%02x read value 0x%02x mask 0x%02x\n",
+				__func__, (p+i)->reg,
+				value, (p+i)->mask);
+	}
+	/* Update BT Status */
+	if (on)
+		marimba_set_bt_status(&config, true);
+	else
+		marimba_set_bt_status(&config, false);
+	return rc;
+}
+
+static int bluetooth_switch_regulators(int on)
+{
+	int i, rc = 0;
+	const char *id = "BTPW";
+
+	for (i = 0; i < ARRAY_SIZE(bt_vregs); i++) {
+		if (IS_ERR_OR_NULL(bt_vregs[i].reg)) {
+			bt_vregs[i].reg =
+				regulator_get(&msm_bt_power_device.dev,
+						bt_vregs[i].name);
+			if (IS_ERR(bt_vregs[i].reg)) {
+				rc = PTR_ERR(bt_vregs[i].reg);
+				dev_err(&msm_bt_power_device.dev,
+					"%s: could not get regulator %s: %d\n",
+					__func__, bt_vregs[i].name, rc);
+				goto reg_disable;
+			}
+		}
+
+		rc = on ? regulator_set_voltage(bt_vregs[i].reg,
+					bt_vregs[i].min_level,
+						bt_vregs[i].max_level) : 0;
+		if (rc) {
+			dev_err(&msm_bt_power_device.dev,
+				"%s: could not set voltage for %s: %d\n",
+					__func__, bt_vregs[i].name, rc);
+			goto reg_disable;
+		}
+
+		rc = on ? regulator_enable(bt_vregs[i].reg) : 0;
+		if (rc) {
+			dev_err(&msm_bt_power_device.dev,
+				"%s: could not %sable regulator %s: %d\n",
+					__func__, "en", bt_vregs[i].name, rc);
+			goto reg_disable;
+		}
+
+		if (bt_vregs[i].is_pin_controlled) {
+			rc = pmapp_vreg_lpm_pincntrl_vote(id,
+				bt_vregs[i].pmapp_id,
+					PMAPP_CLOCK_ID_D1,
+					on ? PMAPP_CLOCK_VOTE_ON :
+						PMAPP_CLOCK_VOTE_OFF);
+			if (rc) {
+				dev_err(&msm_bt_power_device.dev,
+					"%s: pin control failed for %s: %d\n",
+					__func__, bt_vregs[i].name, rc);
+				goto pin_cnt_fail;
+			}
+		}
+		rc = on ? 0 : regulator_disable(bt_vregs[i].reg);
+
+		if (rc) {
+			dev_err(&msm_bt_power_device.dev,
+				"%s: could not %sable regulator %s: %d\n",
+					__func__, "dis", bt_vregs[i].name, rc);
+			goto reg_disable;
+		}
+	}
+
+	return rc;
+pin_cnt_fail:
+	if (on)
+		regulator_disable(bt_vregs[i].reg);
+reg_disable:
+	while (i) {
+		if (on) {
+			i--;
+			regulator_disable(bt_vregs[i].reg);
+			regulator_put(bt_vregs[i].reg);
+			bt_vregs[i].reg = NULL;
+		}
+	}
+	return rc;
+}
+
+static struct regulator *reg_s3;
+static unsigned int msm_bahama_setup_power(void)
+{
+	int rc = 0;
+
+	reg_s3 = regulator_get(NULL, "msme1");
+	if (IS_ERR(reg_s3)) {
+		rc = PTR_ERR(reg_s3);
+		pr_err("%s: could not get regulator: %d\n", __func__, rc);
+		goto out;
+	}
+
+	rc = regulator_set_voltage(reg_s3, 1800000, 1800000);
+	if (rc < 0) {
+		pr_err("%s: could not set voltage: %d\n", __func__, rc);
+		goto reg_fail;
+	}
+
+	rc = regulator_enable(reg_s3);
+	if (rc < 0) {
+		pr_err("%s: could not enable regulator: %d\n", __func__, rc);
+		goto reg_fail;
+	}
+	gpio_tlmm_config(GPIO_CFG(gpio_bt_sys_rest_en, 0,
+				GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
+				GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+
+	/*setup Bahama_sys_reset_n*/
+	rc = gpio_request(gpio_bt_sys_rest_en, "bahama sys_rst_n");
+	if (rc < 0) {
+		pr_err("%s: gpio_request %d = %d\n", __func__,
+			gpio_bt_sys_rest_en, rc);
+		goto reg_disable;
+	}
+
+	rc = bt_set_gpio(1);
+	if (rc < 0) {
+		pr_err("%s: bt_set_gpio %d = %d\n", __func__,
+			gpio_bt_sys_rest_en, rc);
+		goto gpio_fail;
+	}
+
+	return rc;
+
+gpio_fail:
+	gpio_free(gpio_bt_sys_rest_en);
+reg_disable:
+	regulator_disable(reg_s3);
+reg_fail:
+	regulator_put(reg_s3);
+out:
+	reg_s3 = NULL;
+	return rc;
+}
+
+static unsigned int msm_bahama_shutdown_power(int value)
+{
+	int rc = 0;
+
+	if (IS_ERR_OR_NULL(reg_s3)) {
+		rc = reg_s3 ? PTR_ERR(reg_s3) : -ENODEV;
+		goto out;
+	}
+
+	rc = regulator_disable(reg_s3);
+	if (rc) {
+		pr_err("%s: could not disable regulator: %d\n", __func__, rc);
+		goto out;
+	}
+
+	if (value == BAHAMA_ID) {
+		rc = bt_set_gpio(0);
+		if (rc) {
+			pr_err("%s: bt_set_gpio = %d\n",
+					__func__, rc);
+			goto reg_enable;
+		}
+		gpio_free(gpio_bt_sys_rest_en);
+	}
+
+	regulator_put(reg_s3);
+	reg_s3 = NULL;
+
+	return 0;
+
+reg_enable:
+	regulator_enable(reg_s3);
+out:
+	return rc;
+}
+
+static unsigned int msm_bahama_core_config(int type)
+{
+	int rc = 0;
+
+	if (type == BAHAMA_ID) {
+		int i;
+		struct marimba config = { .mod_id =  SLAVE_ID_BAHAMA};
+		const struct bahama_config_register v20_init[] = {
+			/* reg, value, mask */
+			{ 0xF4, 0x84, 0xFF }, /* AREG */
+			{ 0xF0, 0x04, 0xFF } /* DREG */
+		};
+		if (marimba_read_bahama_ver(&config) == BAHAMA_VER_2_0) {
+			for (i = 0; i < ARRAY_SIZE(v20_init); i++) {
+				u8 value = v20_init[i].value;
+				rc = marimba_write_bit_mask(&config,
+					v20_init[i].reg,
+					&value,
+					sizeof(v20_init[i].value),
+					v20_init[i].mask);
+				if (rc < 0) {
+					pr_err("%s: reg %d write failed: %d\n",
+						__func__, v20_init[i].reg, rc);
+					return rc;
+				}
+				pr_debug("%s: reg 0x%02x value 0x%02x"
+					" mask 0x%02x\n",
+					__func__, v20_init[i].reg,
+					v20_init[i].value, v20_init[i].mask);
+			}
+		}
+	}
+	rc = bt_set_gpio(0);
+	if (rc) {
+		pr_err("%s: bt_set_gpio = %d\n",
+		       __func__, rc);
+	}
+	pr_debug("core type: %d\n", type);
+	return rc;
+}
+
+static int bluetooth_power(int on)
+{
+	int pin, rc = 0;
+	const char *id = "BTPW";
+	int cid = 0;
+
+	cid = adie_get_detected_connectivity_type();
+	if (cid != BAHAMA_ID) {
+		pr_err("%s: unexpected adie connectivity type: %d\n",
+					__func__, cid);
+		return -ENODEV;
+	}
+	if (on) {
+		/*setup power for BT SOC*/
+		rc = bt_set_gpio(on);
+		if (rc) {
+			pr_err("%s: bt_set_gpio = %d\n",
+					__func__, rc);
+			goto exit;
+		}
+		rc = bluetooth_switch_regulators(on);
+		if (rc < 0) {
+			pr_err("%s: bluetooth_switch_regulators rc = %d",
+					__func__, rc);
+			goto exit;
+		}
+		/*setup BT GPIO lines*/
+		for (pin = 0; pin < ARRAY_SIZE(bt_config_power_on);
+			pin++) {
+			rc = gpio_tlmm_config(bt_config_power_on[pin],
+					GPIO_CFG_ENABLE);
+			if (rc < 0) {
+				pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
+						__func__,
+						bt_config_power_on[pin],
+						rc);
+				goto fail_power;
+			}
+		}
+		/*Setup BT clocks*/
+		rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
+			PMAPP_CLOCK_VOTE_ON);
+		if (rc < 0) {
+			pr_err("Failed to vote for TCXO_D1 ON\n");
+			goto fail_clock;
+		}
+		msleep(20);
+
+		/*I2C config for Bahama*/
+		rc = bahama_bt(1);
+		if (rc < 0) {
+			pr_err("%s: bahama_bt rc = %d", __func__, rc);
+			goto fail_i2c;
+		}
+		msleep(20);
+
+		/*setup BT PCM lines*/
+		rc = msm_bahama_setup_pcm_i2s(BT_PCM_ON);
+		if (rc < 0) {
+			pr_err("%s: msm_bahama_setup_pcm_i2s , rc =%d\n",
+				__func__, rc);
+				goto fail_power;
+			}
+		rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
+				  PMAPP_CLOCK_VOTE_PIN_CTRL);
+		if (rc < 0)
+			pr_err("%s:Pin Control Failed, rc = %d",
+					__func__, rc);
+
+	} else {
+		rc = bahama_bt(0);
+		if (rc < 0)
+			pr_err("%s: bahama_bt rc = %d", __func__, rc);
+
+		rc = msm_bahama_setup_pcm_i2s(BT_PCM_OFF);
+		if (rc < 0) {
+			pr_err("%s: msm_bahama_setup_pcm_i2s, rc =%d\n",
+				__func__, rc);
+		}
+		rc = bt_set_gpio(on);
+		if (rc) {
+			pr_err("%s: bt_set_gpio = %d\n",
+					__func__, rc);
+		}
+fail_i2c:
+		rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
+				  PMAPP_CLOCK_VOTE_OFF);
+		if (rc < 0)
+			pr_err("%s: Failed to vote Off D1\n", __func__);
+fail_clock:
+		for (pin = 0; pin < ARRAY_SIZE(bt_config_power_off);
+			pin++) {
+			rc = gpio_tlmm_config(bt_config_power_off[pin],
+				GPIO_CFG_ENABLE);
+			if (rc < 0) {
+				pr_err("%s:"
+					" gpio_tlmm_config(%#x)=%d\n",
+					__func__,
+					bt_config_power_off[pin], rc);
+			}
+		}
+fail_power:
+		rc = bluetooth_switch_regulators(0);
+		if (rc < 0) {
+			pr_err("%s: switch_regulators : rc = %d",\
+				__func__, rc);
+			goto exit;
+		}
+	}
+	return rc;
+exit:
+	pr_err("%s: failed with rc = %d", __func__, rc);
+	return rc;
+}
+
+static struct marimba_fm_platform_data marimba_fm_pdata = {
+	.fm_setup = fm_radio_setup,
+	.fm_shutdown = fm_radio_shutdown,
+	.irq = MSM_GPIO_TO_INT(FM_GPIO),
+	.vreg_s2 = NULL,
+	.vreg_xo_out = NULL,
+	/* Configuring the FM SoC as I2S Master */
+	.is_fm_soc_i2s_master = true,
+	.config_i2s_gpio = msm_bahama_setup_pcm_i2s,
+};
+
+static struct marimba_platform_data marimba_pdata = {
+	.slave_id[SLAVE_ID_BAHAMA_FM]	= BAHAMA_SLAVE_ID_FM_ADDR,
+	.slave_id[SLAVE_ID_BAHAMA_QMEMBIST] = BAHAMA_SLAVE_ID_QMEMBIST_ADDR,
+	.bahama_setup			= msm_bahama_setup_power,
+	.bahama_shutdown		= msm_bahama_shutdown_power,
+	.bahama_core_config		= msm_bahama_core_config,
+	.fm			        = &marimba_fm_pdata,
+};
+
+static struct i2c_board_info bahama_devices[] = {
+{
+	I2C_BOARD_INFO("marimba", 0xc),
+	.platform_data = &marimba_pdata,
+},
+};
+
+void __init msm7627a_bt_power_init(void)
+{
+	int i, rc = 0;
+	struct device *dev;
+
+
+	gpio_bt_config();
+
+	rc = i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
+				bahama_devices,
+				ARRAY_SIZE(bahama_devices));
+	if (rc < 0) {
+		pr_err("%s: I2C Register failed\n", __func__);
+		return;
+	}
+
+	rc = platform_device_register(&msm_bt_power_device);
+	if (rc < 0) {
+		pr_err("%s: device register failed\n", __func__);
+		return;
+	}
+
+	dev = &msm_bt_power_device.dev;
+
+	for (i = 0; i < ARRAY_SIZE(bt_vregs); i++) {
+		bt_vregs[i].reg = regulator_get(dev, bt_vregs[i].name);
+		if (IS_ERR(bt_vregs[i].reg)) {
+			rc = PTR_ERR(bt_vregs[i].reg);
+			dev_err(dev, "%s: could not get regulator %s: %d\n",
+					__func__, bt_vregs[i].name, rc);
+			goto reg_get_fail;
+		}
+	}
+
+	dev->platform_data = &bluetooth_power;
+
+	return;
+
+reg_get_fail:
+	while (i--) {
+		regulator_put(bt_vregs[i].reg);
+		bt_vregs[i].reg = NULL;
+	}
+	platform_device_unregister(&msm_bt_power_device);
+}
+#endif
diff --git a/arch/arm/mach-msm/board-msm7627a-camera.c b/arch/arm/mach-msm/board-msm7627a-camera.c
new file mode 100644
index 0000000..3270d19
--- /dev/null
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -0,0 +1,1184 @@
+/* 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/i2c.h>
+#include <linux/i2c/sx150x.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <asm/mach-types.h>
+#include <mach/msm_iomap.h>
+#include <mach/board.h>
+#include <mach/irqs-7xxx.h>
+#include "devices-msm7x2xa.h"
+#include "board-msm7627a.h"
+#include <mach/vreg.h>
+
+#define GPIO_SKU1_CAM_VGA_SHDN    18
+#define GPIO_SKU1_CAM_VGA_RESET_N 29
+#define GPIO_SKU3_CAM_5MP_SHDN_N   5         /* PWDN */
+#define GPIO_SKU3_CAM_5MP_CAMIF_RESET   6    /* (board_is(EVT))?123:121 RESET */
+#define GPIO_SKU3_CAM_5MP_CAM_DRIVER_PWDN 30
+#define GPIO_SKU7_CAM_VGA_SHDN    91
+#define GPIO_SKU7_CAM_5MP_SHDN_N   93         /* PWDN */
+#define GPIO_SKU7_CAM_5MP_CAMIF_RESET   23   /* (board_is(EVT))?123:121 RESET */
+
+#ifdef CONFIG_MSM_CAMERA_V4L2
+static uint32_t camera_off_gpio_table[] = {
+	GPIO_CFG(15, 0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+};
+
+static uint32_t camera_on_gpio_table[] = {
+	GPIO_CFG(15, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+};
+
+static struct gpio s5k4e1_cam_req_gpio[] = {
+	{GPIO_CAM_GP_CAMIF_RESET_N, GPIOF_DIR_OUT, "CAM_RESET"},
+};
+
+static struct msm_gpio_set_tbl s5k4e1_cam_gpio_set_tbl[] = {
+	{GPIO_CAM_GP_CAMIF_RESET_N, GPIOF_OUT_INIT_LOW, 1000},
+	{GPIO_CAM_GP_CAMIF_RESET_N, GPIOF_OUT_INIT_HIGH, 4000},
+};
+
+static struct msm_camera_gpio_conf gpio_conf_s5k4e1 = {
+	.camera_off_table = camera_off_gpio_table,
+	.camera_off_table_size = ARRAY_SIZE(camera_off_gpio_table),
+	.camera_on_table = camera_on_gpio_table,
+	.camera_on_table_size = ARRAY_SIZE(camera_on_gpio_table),
+	.cam_gpio_req_tbl = s5k4e1_cam_req_gpio,
+	.cam_gpio_req_tbl_size = ARRAY_SIZE(s5k4e1_cam_req_gpio),
+	.cam_gpio_set_tbl = s5k4e1_cam_gpio_set_tbl,
+	.cam_gpio_set_tbl_size = ARRAY_SIZE(s5k4e1_cam_gpio_set_tbl),
+	.gpio_no_mux = 1,
+};
+
+static struct msm_camera_gpio_conf gpio_conf_mt9e013 = {
+	.camera_off_table = camera_off_gpio_table,
+	.camera_on_table = camera_on_gpio_table,
+	.gpio_no_mux = 1,
+};
+
+static struct msm_camera_gpio_conf gpio_conf_ov9726 = {
+	.camera_off_table = camera_off_gpio_table,
+	.camera_on_table = camera_on_gpio_table,
+	.gpio_no_mux = 1,
+};
+
+#ifdef CONFIG_OV7692
+static struct gpio ov7692_cam_req_gpio[] = {
+	{GPIO_SKU1_CAM_VGA_SHDN, GPIOF_DIR_OUT, "CAM_VGA_SHDN"},
+	{GPIO_SKU1_CAM_VGA_RESET_N, GPIOF_DIR_OUT, "CAM_VGA_RESET"},
+};
+
+static struct msm_gpio_set_tbl ov7692_cam_gpio_set_tbl[] = {
+	{GPIO_SKU1_CAM_VGA_SHDN, GPIOF_OUT_INIT_HIGH, 5000},
+	{GPIO_SKU1_CAM_VGA_SHDN, GPIOF_OUT_INIT_LOW, 5000},
+	{GPIO_SKU1_CAM_VGA_RESET_N, GPIOF_OUT_INIT_HIGH, 5000},
+	{GPIO_SKU1_CAM_VGA_RESET_N, GPIOF_OUT_INIT_LOW, 5000},
+};
+
+static struct msm_camera_gpio_conf gpio_conf_ov7692 = {
+	.cam_gpio_req_tbl = ov7692_cam_req_gpio,
+	.cam_gpio_req_tbl_size = ARRAY_SIZE(ov7692_cam_req_gpio),
+	.cam_gpio_set_tbl = ov7692_cam_gpio_set_tbl,
+	.cam_gpio_set_tbl_size = ARRAY_SIZE(ov7692_cam_gpio_set_tbl),
+	.gpio_no_mux = 1,
+};
+#endif
+
+#ifdef CONFIG_OV5647
+static struct msm_camera_gpio_conf gpio_conf_ov5647 = {
+	.camera_off_table = camera_off_gpio_table,
+	.camera_on_table = camera_on_gpio_table,
+	.gpio_no_mux = 1,
+};
+#endif
+
+#ifdef CONFIG_MSM_CAMERA_FLASH
+static struct msm_camera_sensor_flash_src msm_flash_src = {
+	.flash_sr_type = MSM_CAMERA_FLASH_SRC_EXT,
+	._fsrc.ext_driver_src.led_en = GPIO_CAM_GP_LED_EN1,
+	._fsrc.ext_driver_src.led_flash_en = GPIO_CAM_GP_LED_EN2,
+};
+#endif
+
+static struct camera_vreg_t msm_cam_vreg[] = {
+	{"msme1", REG_LDO, 1800000, 1800000, 0},
+	{"gp2", REG_LDO, 2850000, 2850000, 0},
+	{"usb2", REG_LDO, 1800000, 1800000, 0},
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_s5k4e1_data;
+
+struct msm_camera_device_platform_data msm_camera_device_data_csi1[] = {
+	{
+		.csid_core = 1,
+		.is_csic = 1,
+		.ioclk = {
+			.vfe_clk_rate = 192000000,
+		},
+	},
+	{
+		.csid_core = 1,
+		.is_csic = 1,
+		.ioclk = {
+			.vfe_clk_rate = 266667000,
+		},
+	},
+};
+
+struct msm_camera_device_platform_data msm_camera_device_data_csi0[] = {
+	{
+		.csid_core = 0,
+		.is_csic = 1,
+		.ioclk = {
+			.vfe_clk_rate = 192000000,
+		},
+	},
+	{
+		.csid_core = 0,
+		.is_csic = 1,
+		.ioclk = {
+			.vfe_clk_rate = 266667000,
+		},
+	},
+};
+
+static struct i2c_board_info msm_act_main_cam_i2c_info = {
+	I2C_BOARD_INFO("msm_actuator", 0x11),
+};
+
+static struct msm_actuator_info msm_act_main_cam_4_info = {
+	.board_info     = &msm_act_main_cam_i2c_info,
+	.cam_name   = MSM_ACTUATOR_MAIN_CAM_4,
+	.bus_id         = MSM_GSBI0_QUP_I2C_BUS_ID,
+	.vcm_pwd        = GPIO_CAM_GP_CAM_PWDN,
+	.vcm_enable     = 1,
+};
+
+#ifdef CONFIG_S5K4E1
+static struct msm_camera_sensor_flash_data flash_s5k4e1 = {
+	.flash_type             = MSM_CAMERA_FLASH_LED,
+	.flash_src              = &msm_flash_src
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_s5k4e1 = {
+	.mount_angle	= 90,
+	.cam_vreg = msm_cam_vreg,
+	.num_vreg = ARRAY_SIZE(msm_cam_vreg),
+	.gpio_conf = &gpio_conf_s5k4e1,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_s5k4e1_data = {
+	.sensor_name    = "s5k4e1",
+	.sensor_reset_enable = 1,
+	.pmic_gpio_enable    = 0,
+	.pdata                  = &msm_camera_device_data_csi1[0],
+	.flash_data             = &flash_s5k4e1,
+	.sensor_platform_info   = &sensor_board_info_s5k4e1,
+	.csi_if                 = 1,
+	.camera_type = BACK_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
+	.actuator_info = &msm_act_main_cam_4_info,
+};
+#endif
+
+#ifdef CONFIG_OV7692
+static struct msm_camera_sensor_platform_info sensor_board_info_ov7692 = {
+	.mount_angle = 90,
+	.cam_vreg = msm_cam_vreg,
+	.num_vreg = ARRAY_SIZE(msm_cam_vreg),
+	.gpio_conf = &gpio_conf_ov7692,
+};
+
+static struct msm_camera_sensor_flash_data flash_ov7692 = {
+	.flash_type     = MSM_CAMERA_FLASH_NONE,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_ov7692_data = {
+	.sensor_name	    = "ov7692",
+	.sensor_reset_enable    = 0,
+	.pmic_gpio_enable  = 1,
+	.sensor_lcd_gpio_onoff = lcd_camera_power_onoff,
+	.sensor_reset	   = GPIO_SKU1_CAM_VGA_RESET_N,
+	.sensor_pwd	     = GPIO_SKU1_CAM_VGA_SHDN,
+	.pdata			= &msm_camera_device_data_csi0[0],
+	.flash_data	     = &flash_ov7692,
+	.sensor_platform_info   = &sensor_board_info_ov7692,
+	.csi_if		 = 1,
+	.camera_type = FRONT_CAMERA_2D,
+	.sensor_type = YUV_SENSOR,
+};
+#endif
+
+#ifdef CONFIG_OV5647
+
+static struct msm_actuator_info msm_act_main_cam_5_info = {
+	.board_info     = &msm_act_main_cam_i2c_info,
+	.cam_name   = MSM_ACTUATOR_MAIN_CAM_5,
+	.bus_id         = MSM_GSBI0_QUP_I2C_BUS_ID,
+	.vcm_pwd        = GPIO_SKU3_CAM_5MP_CAM_DRIVER_PWDN,
+	.vcm_enable     = 1,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_ov5647 = {
+	.mount_angle = 90,
+	.cam_vreg = msm_cam_vreg,
+	.num_vreg = ARRAY_SIZE(msm_cam_vreg),
+	.gpio_conf = &gpio_conf_ov5647,
+};
+
+static struct msm_camera_sensor_flash_src msm_flash_src_ov5647 = {
+	.flash_sr_type = MSM_CAMERA_FLASH_SRC_LED1,
+	._fsrc.ext_driver_src.led_en = 13,
+	._fsrc.ext_driver_src.led_flash_en = 32,
+};
+
+static struct msm_camera_sensor_flash_data flash_ov5647 = {
+	.flash_type             = MSM_CAMERA_FLASH_LED,
+	.flash_src              = &msm_flash_src_ov5647,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_ov5647_data = {
+	.sensor_name    = "ov5647",
+	.sensor_reset_enable = 1,
+	.pmic_gpio_enable  = 1,
+	.sensor_lcd_gpio_onoff = lcd_camera_power_onoff,
+	.sensor_reset   = GPIO_SKU3_CAM_5MP_CAMIF_RESET,
+	.sensor_pwd     = GPIO_SKU3_CAM_5MP_SHDN_N,
+	.pdata          = &msm_camera_device_data_csi1[0],
+	.flash_data     = &flash_ov5647,
+	.sensor_platform_info   = &sensor_board_info_ov5647,
+	.csi_if                 = 1,
+	.camera_type	= BACK_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
+	.actuator_info = &msm_act_main_cam_5_info,
+};
+
+#endif
+#ifdef CONFIG_MT9E013
+static struct msm_camera_sensor_flash_data flash_mt9e013 = {
+	.flash_type             = MSM_CAMERA_FLASH_LED,
+	.flash_src              = &msm_flash_src
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_mt9e013 = {
+	.mount_angle	= 90,
+	.cam_vreg = msm_cam_vreg,
+	.num_vreg = ARRAY_SIZE(msm_cam_vreg),
+	.gpio_conf = &gpio_conf_mt9e013,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_mt9e013_data = {
+	.sensor_name    = "mt9e013",
+	.sensor_reset_enable = 1,
+	.pmic_gpio_enable    = 0,
+	.pdata                  = &msm_camera_device_data_csi1[1],
+	.flash_data             = &flash_mt9e013,
+	.sensor_platform_info   = &sensor_board_info_mt9e013,
+	.csi_if                 = 1,
+	.camera_type = BACK_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
+};
+#endif
+
+#ifdef CONFIG_WEBCAM_OV9726
+static struct msm_camera_sensor_flash_data flash_ov9726 = {
+	.flash_type             = MSM_CAMERA_FLASH_LED,
+	.flash_src              = &msm_flash_src
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_ov9726 = {
+	.mount_angle	= 90,
+	.cam_vreg = msm_cam_vreg,
+	.num_vreg = ARRAY_SIZE(msm_cam_vreg),
+	.gpio_conf = &gpio_conf_ov9726,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_ov9726_data = {
+	.sensor_name    = "ov9726",
+	.sensor_reset_enable = 0,
+	.pmic_gpio_enable  = 0,
+	.pdata                  = &msm_camera_device_data_csi0[0],
+	.flash_data             = &flash_ov9726,
+	.sensor_platform_info   = &sensor_board_info_ov9726,
+	.csi_if                 = 1,
+	.camera_type = FRONT_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
+};
+#endif
+
+static struct platform_device msm_camera_server = {
+	.name = "msm_cam_server",
+	.id = 0,
+};
+
+static void __init msm7x27a_init_cam(void)
+{
+	if (!(machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa()
+				|| machine_is_msm7627a_qrd1()
+				|| machine_is_msm8625_ffa())) {
+		sensor_board_info_s5k4e1.cam_vreg = NULL;
+		sensor_board_info_s5k4e1.num_vreg = 0;
+		sensor_board_info_mt9e013.cam_vreg = NULL;
+		sensor_board_info_mt9e013.num_vreg = 0;
+		sensor_board_info_ov9726.cam_vreg = NULL;
+		sensor_board_info_ov9726.num_vreg = 0;
+		sensor_board_info_ov7692.cam_vreg = NULL;
+		sensor_board_info_ov7692.num_vreg = 0;
+		sensor_board_info_ov5647.cam_vreg = NULL;
+		sensor_board_info_ov5647.num_vreg = 0;
+	}
+	platform_device_register(&msm_camera_server);
+	if (machine_is_msm8625_surf() || machine_is_msm8625_evb()
+			|| machine_is_msm8625_evt()
+			|| machine_is_msm8625_qrd7()) {
+		platform_device_register(&msm8625_device_csic0);
+		platform_device_register(&msm8625_device_csic1);
+	} else {
+		platform_device_register(&msm7x27a_device_csic0);
+		platform_device_register(&msm7x27a_device_csic1);
+	}
+	if (machine_is_msm8625_evb()
+			|| machine_is_msm8625_evt()
+			|| machine_is_msm8625_qrd7())
+		*(int *) msm7x27a_device_clkctl.dev.platform_data = 1;
+	platform_device_register(&msm7x27a_device_clkctl);
+	platform_device_register(&msm7x27a_device_vfe);
+}
+
+static struct i2c_board_info i2c_camera_devices[] = {
+	{
+		I2C_BOARD_INFO("s5k4e1", 0x36),
+		.platform_data = &msm_camera_sensor_s5k4e1_data,
+	},
+	{
+		I2C_BOARD_INFO("ov9726", 0x10),
+		.platform_data = &msm_camera_sensor_ov9726_data,
+	},
+	{
+		I2C_BOARD_INFO("mt9e013", 0x6C >> 2),
+		.platform_data = &msm_camera_sensor_mt9e013_data,
+	},
+	{
+		I2C_BOARD_INFO("ov7692", 0x78),
+		.platform_data = &msm_camera_sensor_ov7692_data,
+	},
+	{
+		I2C_BOARD_INFO("ov5647", 0x36 << 1),
+		.platform_data = &msm_camera_sensor_ov5647_data,
+	},
+	{
+		I2C_BOARD_INFO("sc628a", 0x6E),
+	},
+};
+#else
+static uint32_t camera_off_gpio_table[] = {
+	GPIO_CFG(15, 0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+};
+
+static uint32_t camera_on_gpio_table[] = {
+	GPIO_CFG(15, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+};
+
+#ifdef CONFIG_MSM_CAMERA_FLASH
+static struct msm_camera_sensor_flash_src msm_flash_src = {
+	.flash_sr_type = MSM_CAMERA_FLASH_SRC_EXT,
+	._fsrc.ext_driver_src.led_en = GPIO_CAM_GP_LED_EN1,
+	._fsrc.ext_driver_src.led_flash_en = GPIO_CAM_GP_LED_EN2,
+};
+#endif
+
+static struct regulator_bulk_data regs_camera[] = {
+	{ .supply = "msme1", .min_uV = 1800000, .max_uV = 1800000 },
+	{ .supply = "gp2",   .min_uV = 2850000, .max_uV = 2850000 },
+	{ .supply = "usb2",  .min_uV = 1800000, .max_uV = 1800000 },
+};
+
+static void qrd1_camera_gpio_cfg(void)
+{
+
+	int rc = 0;
+
+	rc = gpio_request(QRD_GPIO_CAM_5MP_SHDN_EN, "ov5640");
+	if (rc < 0)
+		pr_err("%s: gpio_request---GPIO_CAM_5MP_SHDN_EN failed!",
+				__func__);
+
+
+	rc = gpio_tlmm_config(GPIO_CFG(QRD_GPIO_CAM_5MP_SHDN_EN, 0,
+				GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
+				GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+	if (rc < 0) {
+		pr_err("%s: unable to enable Power Down gpio for main"
+				"camera!\n", __func__);
+		gpio_free(QRD_GPIO_CAM_5MP_SHDN_EN);
+	}
+
+
+	rc = gpio_request(QRD_GPIO_CAM_5MP_RESET, "ov5640");
+	if (rc < 0) {
+		pr_err("%s: gpio_request---GPIO_CAM_5MP_RESET failed!",
+				__func__);
+		gpio_free(QRD_GPIO_CAM_5MP_SHDN_EN);
+	}
+
+
+	rc = gpio_tlmm_config(GPIO_CFG(QRD_GPIO_CAM_5MP_RESET, 0,
+				GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
+				GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+	if (rc < 0) {
+		pr_err("%s: unable to enable reset gpio for main camera!\n",
+				__func__);
+		gpio_free(QRD_GPIO_CAM_5MP_RESET);
+	}
+
+	rc = gpio_request(QRD_GPIO_CAM_3MP_PWDN, "ov7692");
+	if (rc < 0)
+		pr_err("%s: gpio_request---GPIO_CAM_3MP_PWDN failed!",
+				__func__);
+
+	rc = gpio_tlmm_config(GPIO_CFG(QRD_GPIO_CAM_3MP_PWDN, 0,
+				GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
+				GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+	if (rc < 0) {
+		pr_err("%s: unable to enable Power Down gpio for front"
+				"camera!\n", __func__);
+		gpio_free(QRD_GPIO_CAM_3MP_PWDN);
+	}
+
+	gpio_direction_output(QRD_GPIO_CAM_5MP_SHDN_EN, 1);
+	gpio_direction_output(QRD_GPIO_CAM_5MP_RESET, 1);
+	gpio_direction_output(QRD_GPIO_CAM_3MP_PWDN, 1);
+}
+#endif
+
+static void evb_camera_gpio_cfg(void)
+{
+	int rc = 0;
+
+	rc = gpio_request(msm_camera_sensor_ov5647_data.sensor_pwd, "ov5647");
+	if (rc < 0)
+		pr_err("%s: gpio_request OV5647 sensor_pwd: %d failed!",
+			 __func__, msm_camera_sensor_ov5647_data.sensor_pwd);
+
+	rc = gpio_tlmm_config(GPIO_CFG(msm_camera_sensor_ov5647_data.sensor_pwd,
+				0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN,
+				GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+	if (rc < 0) {
+		pr_err("%s:unable to enable Powr Dwn gpio for main camera!\n",
+			 __func__);
+		gpio_free(msm_camera_sensor_ov5647_data.sensor_pwd);
+	}
+
+	rc = gpio_direction_output(msm_camera_sensor_ov5647_data.sensor_pwd, 1);
+	if (rc < 0)
+		pr_err("%s: unable to set gpio: %d direction for ov5647 camera\n",
+			__func__, msm_camera_sensor_ov5647_data.sensor_pwd);
+
+	rc = gpio_request(msm_camera_sensor_ov5647_data.sensor_reset, "ov5647");
+	if (rc < 0)
+		pr_err("%s: gpio_request OV5647 sensor_reset: %d failed!",
+			 __func__, msm_camera_sensor_ov5647_data.sensor_reset);
+
+	rc = gpio_tlmm_config(GPIO_CFG(
+				msm_camera_sensor_ov5647_data.sensor_reset,
+				0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN,
+				GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+	if (rc < 0) {
+		pr_err("%s: unable to enable reset gpio for main camera!\n",
+			 __func__);
+		gpio_free(msm_camera_sensor_ov5647_data.sensor_reset);
+	}
+
+	rc = gpio_direction_output(
+			msm_camera_sensor_ov5647_data.sensor_reset, 1);
+	if (rc < 0)
+		pr_err("%s: unable to set gpio: %d direction for ov5647 camera\n",
+			__func__, msm_camera_sensor_ov5647_data.sensor_reset);
+
+}
+
+#ifndef CONFIG_MSM_CAMERA_V4L2
+
+static void msm_camera_vreg_config(int vreg_en)
+{
+	int rc = vreg_en ?
+		regulator_bulk_enable(ARRAY_SIZE(regs_camera), regs_camera) :
+		regulator_bulk_disable(ARRAY_SIZE(regs_camera), regs_camera);
+
+	if (rc)
+		pr_err("%s: could not %sable regulators: %d\n",
+				__func__, vreg_en ? "en" : "dis", rc);
+}
+
+static int config_gpio_table(uint32_t *table, int len)
+{
+	int rc = 0, i = 0;
+
+	for (i = 0; i < len; i++) {
+		rc = gpio_tlmm_config(table[i], GPIO_CFG_ENABLE);
+		if (rc) {
+			pr_err("%s not able to get gpio\n", __func__);
+			for (i--; i >= 0; i--)
+				gpio_tlmm_config(camera_off_gpio_table[i],
+							GPIO_CFG_ENABLE);
+			break;
+		}
+	}
+	return rc;
+}
+
+static int config_camera_on_gpios_rear(void)
+{
+	int rc = 0;
+
+	if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa()
+				|| machine_is_msm7627a_qrd1()
+				|| machine_is_msm8625_ffa())
+		msm_camera_vreg_config(1);
+
+	rc = config_gpio_table(camera_on_gpio_table,
+			ARRAY_SIZE(camera_on_gpio_table));
+	if (rc < 0) {
+		pr_err("%s: CAMSENSOR gpio table request"
+		"failed\n", __func__);
+		return rc;
+	}
+
+	return rc;
+}
+
+static void config_camera_off_gpios_rear(void)
+{
+	if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa()
+				|| machine_is_msm7627a_qrd1()
+				|| machine_is_msm8625_ffa())
+		msm_camera_vreg_config(0);
+
+	config_gpio_table(camera_off_gpio_table,
+			ARRAY_SIZE(camera_off_gpio_table));
+}
+
+static int config_camera_on_gpios_front(void)
+{
+	int rc = 0;
+
+	if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa()
+				|| machine_is_msm7627a_qrd1()
+				|| machine_is_msm8625_ffa())
+		msm_camera_vreg_config(1);
+
+	rc = config_gpio_table(camera_on_gpio_table,
+			ARRAY_SIZE(camera_on_gpio_table));
+	if (rc < 0) {
+		pr_err("%s: CAMSENSOR gpio table request"
+			"failed\n", __func__);
+		return rc;
+	}
+
+	return rc;
+}
+
+static void config_camera_off_gpios_front(void)
+{
+	if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa()
+				|| machine_is_msm7627a_qrd1()
+				|| machine_is_msm8625_ffa())
+		msm_camera_vreg_config(0);
+
+	config_gpio_table(camera_off_gpio_table,
+			ARRAY_SIZE(camera_off_gpio_table));
+}
+
+struct msm_camera_device_platform_data msm_camera_device_data_rear = {
+	.camera_gpio_on		= config_camera_on_gpios_rear,
+	.camera_gpio_off	= config_camera_off_gpios_rear,
+	.ioext.csiphy		= 0xA1000000,
+	.ioext.csisz		= 0x00100000,
+	.ioext.csiirq		= INT_CSI_IRQ_1,
+	.ioclk.mclk_clk_rate	= 24000000,
+	.ioclk.vfe_clk_rate	= 192000000,
+	.ioext.appphy		= MSM7XXX_CLK_CTL_PHYS,
+	.ioext.appsz		= MSM7XXX_CLK_CTL_SIZE,
+};
+
+struct msm_camera_device_platform_data msm_camera_device_data_front = {
+	.camera_gpio_on		= config_camera_on_gpios_front,
+	.camera_gpio_off	= config_camera_off_gpios_front,
+	.ioext.csiphy		= 0xA0F00000,
+	.ioext.csisz		= 0x00100000,
+	.ioext.csiirq		= INT_CSI_IRQ_0,
+	.ioclk.mclk_clk_rate	= 24000000,
+	.ioclk.vfe_clk_rate	= 192000000,
+	.ioext.appphy		= MSM7XXX_CLK_CTL_PHYS,
+	.ioext.appsz		= MSM7XXX_CLK_CTL_SIZE,
+};
+
+#ifdef CONFIG_OV5647
+
+static struct msm_camera_sensor_platform_info ov5647_sensor_7627a_info = {
+	.mount_angle = 90
+};
+
+static struct msm_camera_sensor_flash_src msm_flash_src_ov5647 = {
+	.flash_sr_type = MSM_CAMERA_FLASH_SRC_LED,
+	._fsrc.led_src.led_name = "flashlight",
+	._fsrc.led_src.led_name_len = 10,
+};
+
+static struct msm_camera_sensor_flash_data flash_ov5647 = {
+	.flash_type             = MSM_CAMERA_FLASH_LED,
+	.flash_src              = &msm_flash_src_ov5647,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_ov5647_data = {
+	.sensor_name    = "ov5647",
+	.sensor_reset_enable = 1,
+	.sensor_reset   = GPIO_SKU3_CAM_5MP_CAMIF_RESET,
+	.pmic_gpio_enable  = 1,
+	.sensor_pwd     = GPIO_SKU3_CAM_5MP_SHDN_N,
+	.vcm_pwd        = GPIO_SKU3_CAM_5MP_CAM_DRIVER_PWDN,
+	.vcm_enable     = 1,
+	.pdata          = &msm_camera_device_data_rear,
+	.flash_data     = &flash_ov5647,
+	.sensor_platform_info   = &ov5647_sensor_7627a_info,
+	.csi_if                 = 1
+};
+
+static struct platform_device msm_camera_sensor_ov5647 = {
+	.name      = "msm_camera_ov5647",
+	.dev       = {
+		.platform_data = &msm_camera_sensor_ov5647_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_S5K4E1
+static struct msm_camera_sensor_platform_info s5k4e1_sensor_7627a_info = {
+	.mount_angle = 90
+};
+
+static struct msm_camera_sensor_flash_data flash_s5k4e1 = {
+	.flash_type	     = MSM_CAMERA_FLASH_LED,
+	.flash_src	      = &msm_flash_src
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_s5k4e1_data = {
+	.sensor_name		= "s5k4e1",
+	.sensor_reset_enable	= 1,
+	.sensor_reset		= GPIO_CAM_GP_CAMIF_RESET_N,
+	.pmic_gpio_enable       = 0,
+	.sensor_pwd	     = 85,
+	.vcm_pwd		= GPIO_CAM_GP_CAM_PWDN,
+	.vcm_enable	     = 1,
+	.pdata			= &msm_camera_device_data_rear,
+	.flash_data	     = &flash_s5k4e1,
+	.sensor_platform_info   = &s5k4e1_sensor_7627a_info,
+	.csi_if			= 1
+};
+
+static struct platform_device msm_camera_sensor_s5k4e1 = {
+	.name   = "msm_camera_s5k4e1",
+	.dev    = {
+		.platform_data = &msm_camera_sensor_s5k4e1_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_IMX072
+static struct msm_camera_sensor_platform_info imx072_sensor_7627a_info = {
+	.mount_angle = 90
+};
+
+static struct msm_camera_sensor_flash_data flash_imx072 = {
+	.flash_type	     = MSM_CAMERA_FLASH_LED,
+	.flash_src	      = &msm_flash_src
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_imx072_data = {
+	.sensor_name		= "imx072",
+	.sensor_reset_enable	= 1,
+	.sensor_reset		= GPIO_CAM_GP_CAMIF_RESET_N, /* TODO 106,*/
+	.pmic_gpio_enable       = 0,
+	.sensor_pwd	     = 85,
+	.vcm_pwd		= GPIO_CAM_GP_CAM_PWDN,
+	.vcm_enable	     = 1,
+	.pdata			= &msm_camera_device_data_rear,
+	.flash_data	     = &flash_imx072,
+	.sensor_platform_info	= &imx072_sensor_7627a_info,
+	.csi_if			= 1
+};
+
+static struct platform_device msm_camera_sensor_imx072 = {
+	.name   = "msm_camera_imx072",
+	.dev    = {
+		.platform_data = &msm_camera_sensor_imx072_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_WEBCAM_OV9726
+static struct msm_camera_sensor_info msm_camera_sensor_ov9726_data;
+static struct msm_camera_sensor_platform_info ov9726_sensor_7627a_info = {
+	.mount_angle = 90
+};
+
+static struct msm_camera_sensor_flash_data flash_ov9726 = {
+	.flash_type	     = MSM_CAMERA_FLASH_NONE,
+	.flash_src	      = &msm_flash_src
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_ov9726_data = {
+	.sensor_name		= "ov9726",
+	.sensor_reset_enable	= 0,
+	.sensor_reset		= GPIO_CAM_GP_CAM1MP_XCLR,
+	.pmic_gpio_enable       = 0,
+	.sensor_pwd	     = 85,
+	.vcm_pwd		= 1,
+	.vcm_enable	     = 0,
+	.pdata			= &msm_camera_device_data_front,
+	.flash_data	     = &flash_ov9726,
+	.sensor_platform_info   = &ov9726_sensor_7627a_info,
+	.csi_if			= 1
+};
+
+static struct platform_device msm_camera_sensor_ov9726 = {
+	.name   = "msm_camera_ov9726",
+	.dev    = {
+		.platform_data = &msm_camera_sensor_ov9726_data,
+	},
+};
+#else
+static inline void msm_camera_vreg_init(void) { }
+#endif
+
+#ifdef CONFIG_MT9E013
+static struct msm_camera_sensor_platform_info mt9e013_sensor_7627a_info = {
+	.mount_angle = 90
+};
+
+static struct msm_camera_sensor_flash_data flash_mt9e013 = {
+	.flash_type = MSM_CAMERA_FLASH_LED,
+	.flash_src  = &msm_flash_src
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_mt9e013_data = {
+	.sensor_name		= "mt9e013",
+	.sensor_reset		= 0,
+	.sensor_reset_enable	= 1,
+	.pmic_gpio_enable       = 0,
+	.sensor_pwd		= 85,
+	.vcm_pwd		= 1,
+	.vcm_enable		= 0,
+	.pdata		= &msm_camera_device_data_rear,
+	.flash_data		= &flash_mt9e013,
+	.sensor_platform_info   = &mt9e013_sensor_7627a_info,
+	.csi_if		= 1
+};
+
+static struct platform_device msm_camera_sensor_mt9e013 = {
+	.name      = "msm_camera_mt9e013",
+	.dev       = {
+		.platform_data = &msm_camera_sensor_mt9e013_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_OV5640
+static struct msm_camera_sensor_platform_info ov5640_sensor_info = {
+	.mount_angle    = 90
+};
+
+static struct msm_camera_sensor_flash_src msm_flash_src_ov5640 = {
+	.flash_sr_type = MSM_CAMERA_FLASH_SRC_LED,
+	._fsrc.led_src.led_name = "flashlight",
+	._fsrc.led_src.led_name_len = 10,
+};
+
+static struct msm_camera_sensor_flash_data flash_ov5640 = {
+	.flash_type     = MSM_CAMERA_FLASH_LED,
+	.flash_src      = &msm_flash_src_ov5640,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_ov5640_data = {
+	.sensor_name	    = "ov5640",
+	.sensor_reset_enable    = 1,
+	.pmic_gpio_enable  = 0,
+	.sensor_reset	   = QRD_GPIO_CAM_5MP_RESET,
+	.sensor_pwd	     = QRD_GPIO_CAM_5MP_SHDN_EN,
+	.vcm_pwd		= 0,
+	.vcm_enable	     = 0,
+	.pdata			= &msm_camera_device_data_rear,
+	.flash_data	     = &flash_ov5640,
+	.sensor_platform_info   = &ov5640_sensor_info,
+	.csi_if		 = 1,
+};
+
+static struct platform_device msm_camera_sensor_ov5640 = {
+	.name   = "msm_camera_ov5640",
+	.dev    = {
+		.platform_data = &msm_camera_sensor_ov5640_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_WEBCAM_OV7692_QRD
+static struct msm_camera_sensor_platform_info ov7692_sensor_7627a_info = {
+	.mount_angle = 90
+};
+
+static struct msm_camera_sensor_flash_data flash_ov7692 = {
+	.flash_type     = MSM_CAMERA_FLASH_NONE,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_ov7692_data = {
+	.sensor_name	    = "ov7692",
+	.sensor_reset_enable    = 0,
+	.pmic_gpio_enable  = 1,
+	.sensor_reset	   = GPIO_SKU1_CAM_VGA_RESET_N,
+	.sensor_pwd	     = GPIO_SKU1_CAM_VGA_SHDN,
+	.vcm_pwd		= 0,
+	.vcm_enable	     = 0,
+	.pdata			= &msm_camera_device_data_front,
+	.flash_data	     = &flash_ov7692,
+	.sensor_platform_info   = &ov7692_sensor_7627a_info,
+	.csi_if		 = 1,
+};
+
+static struct platform_device msm_camera_sensor_ov7692 = {
+	.name   = "msm_camera_ov7692",
+	.dev    = {
+		.platform_data = &msm_camera_sensor_ov7692_data,
+	},
+};
+#endif
+
+static struct i2c_board_info i2c_camera_devices[] = {
+	#ifdef CONFIG_S5K4E1
+	{
+		I2C_BOARD_INFO("s5k4e1", 0x36),
+	},
+	{
+		I2C_BOARD_INFO("s5k4e1_af", 0x8c >> 1),
+	},
+	#endif
+	#ifdef CONFIG_WEBCAM_OV9726
+	{
+		I2C_BOARD_INFO("ov9726", 0x10),
+	},
+	#endif
+	#ifdef CONFIG_IMX072
+	{
+		I2C_BOARD_INFO("imx072", 0x34),
+	},
+	#endif
+	#ifdef CONFIG_MT9E013
+	{
+		I2C_BOARD_INFO("mt9e013", 0x6C >> 2),
+	},
+	#endif
+	{
+		I2C_BOARD_INFO("sc628a", 0x6E),
+	},
+};
+
+static struct i2c_board_info i2c_camera_devices_qrd[] = {
+	#ifdef CONFIG_OV5640
+	{
+		I2C_BOARD_INFO("ov5640", 0x78 >> 1),
+	},
+	#endif
+	#ifdef CONFIG_WEBCAM_OV7692_QRD
+	{
+		I2C_BOARD_INFO("ov7692", 0x78),
+	},
+	#endif
+};
+
+static struct i2c_board_info i2c_camera_devices_evb[] = {
+	#ifdef CONFIG_OV5647
+	{
+		I2C_BOARD_INFO("ov5647", 0x36 << 1),
+	},
+	{
+		I2C_BOARD_INFO("ov5647_af", 0x18 >> 1),
+	},
+	#endif
+	#ifdef CONFIG_WEBCAM_OV7692_QRD
+	{
+		I2C_BOARD_INFO("ov7692", 0x78),
+	},
+	#endif
+};
+
+static struct platform_device *camera_devices_msm[] __initdata = {
+#ifdef CONFIG_S5K4E1
+	&msm_camera_sensor_s5k4e1,
+#endif
+#ifdef CONFIG_IMX072
+	&msm_camera_sensor_imx072,
+#endif
+#ifdef CONFIG_WEBCAM_OV9726
+	&msm_camera_sensor_ov9726,
+#endif
+#ifdef CONFIG_MT9E013
+	&msm_camera_sensor_mt9e013,
+#endif
+};
+
+static struct platform_device *camera_devices_qrd[] __initdata = {
+#ifdef CONFIG_OV5640
+	&msm_camera_sensor_ov5640,
+#endif
+#ifdef CONFIG_WEBCAM_OV7692_QRD
+	&msm_camera_sensor_ov7692,
+#endif
+};
+
+static struct platform_device *camera_devices_evb[] __initdata = {
+#ifdef CONFIG_OV5647
+	&msm_camera_sensor_ov5647,
+#endif
+#ifdef CONFIG_WEBCAM_OV7692_QRD
+	&msm_camera_sensor_ov7692,
+#endif
+};
+#endif
+
+enum {
+	SX150X_CAM,
+};
+
+static struct sx150x_platform_data sx150x_data[] __initdata = {
+	[SX150X_CAM]    = {
+		.gpio_base	      = GPIO_CAM_EXPANDER_BASE,
+		.oscio_is_gpo	   = false,
+		.io_pullup_ena	  = 0,
+		.io_pulldn_ena	  = 0,
+		.io_open_drain_ena      = 0x23,
+		.irq_summary	    = -1,
+	},
+};
+
+static struct i2c_board_info cam_exp_i2c_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("sx1508q", 0x22),
+		.platform_data  = &sx150x_data[SX150X_CAM],
+	},
+};
+
+static void __init register_i2c_devices(void)
+{
+	i2c_register_board_info(MSM_GSBI0_QUP_I2C_BUS_ID,
+				cam_exp_i2c_info,
+				ARRAY_SIZE(cam_exp_i2c_info));
+}
+
+#define LCD_CAMERA_LDO_2V8 35 /* SKU1&SKU3 2.8V LDO */
+#define SKU3_LCD_CAMERA_LDO_1V8 40 /* SKU3 1.8V LDO */
+#define SKU7_LCD_CAMERA_LDO_1V8 58 /* SKU7 1.8V LDO */
+
+static int lcd_camera_ldo_1v8 = SKU3_LCD_CAMERA_LDO_1V8;
+
+static void lcd_camera_power_init(void)
+{
+	int rc = 0;
+
+	pr_debug("lcd_camera_power_init\n");
+
+	if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7())
+		lcd_camera_ldo_1v8 = SKU7_LCD_CAMERA_LDO_1V8;
+	else
+		lcd_camera_ldo_1v8 = SKU3_LCD_CAMERA_LDO_1V8;
+
+	/* LDO_EXT2V8 */
+	if (gpio_request(LCD_CAMERA_LDO_2V8, "lcd_camera_ldo_2v8")) {
+		pr_err("failed to request gpio lcd_camera_ldo_2v8\n");
+		return;
+	}
+
+	rc = gpio_tlmm_config(GPIO_CFG(LCD_CAMERA_LDO_2V8, 0,
+		GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN,
+		GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+	if (rc < 0) {
+		pr_err("%s: unable to enable lcd_camera_ldo_2v8!\n", __func__);
+		goto fail_gpio2;
+	}
+
+	/* LDO_EVT1V8 */
+	if (gpio_request(lcd_camera_ldo_1v8, "lcd_camera_ldo_1v8")) {
+		pr_err("failed to request gpio lcd_camera_ldo_1v8\n");
+		goto fail_gpio2;
+	}
+
+	rc = gpio_tlmm_config(GPIO_CFG(lcd_camera_ldo_1v8, 0,
+		GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN,
+		GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+	if (rc < 0) {
+		pr_err("%s: unable to enable lcd_camera_ldo_1v8!\n", __func__);
+		goto fail_gpio1;
+	}
+
+	return;
+
+fail_gpio1:
+	gpio_free(lcd_camera_ldo_1v8);
+fail_gpio2:
+	gpio_free(LCD_CAMERA_LDO_2V8);
+
+	return;
+}
+
+static int lcd_camera_power_on_sku3(void)
+{
+	int rc = 0;
+
+	pr_debug("turn on sku3 lcd_camera_ldo_1v8\n");
+	gpio_set_value_cansleep(lcd_camera_ldo_1v8, 1);
+
+	pr_debug("turn on sku3 lcd_camera_ldo\n");
+	gpio_set_value_cansleep(LCD_CAMERA_LDO_2V8, 1);
+
+	return rc;
+}
+
+static int lcd_camera_power_off_sku3(void)
+{
+	int rc = 0;
+
+	pr_debug("turn off sku3 lcd_camera_ldo_1v8\n");
+	gpio_set_value_cansleep(lcd_camera_ldo_1v8, 0);
+
+	pr_debug("turn off sku3 lcd_camera_ldo\n");
+	gpio_set_value_cansleep(LCD_CAMERA_LDO_2V8, 0);
+
+	gpio_free(lcd_camera_ldo_1v8);
+	gpio_free(LCD_CAMERA_LDO_2V8);
+
+	return rc;
+}
+
+int lcd_camera_power_onoff(int on)
+{
+	int rc = 0;
+
+	pr_debug("lcd_camera_power_onoff on = %d,\n", on);
+
+	if (on)
+		rc = lcd_camera_power_on_sku3();
+	else
+		rc = lcd_camera_power_off_sku3();
+
+	return rc;
+}
+EXPORT_SYMBOL(lcd_camera_power_onoff);
+
+void __init msm7627a_camera_init(void)
+{
+
+#ifndef CONFIG_MSM_CAMERA_V4L2
+	int rc;
+#endif
+
+	pr_debug("msm7627a_camera_init Entered\n");
+
+	if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7()) {
+		ov7692_cam_req_gpio[0].gpio =
+			GPIO_SKU7_CAM_VGA_SHDN;
+		ov7692_cam_gpio_set_tbl[0].gpio = GPIO_SKU7_CAM_VGA_SHDN;
+		ov7692_cam_gpio_set_tbl[1].gpio = GPIO_SKU7_CAM_VGA_SHDN;
+
+		msm_camera_sensor_ov5647_data.sensor_pwd =
+			GPIO_SKU7_CAM_5MP_SHDN_N;
+		msm_camera_sensor_ov5647_data.sensor_reset =
+			GPIO_SKU7_CAM_5MP_CAMIF_RESET;
+
+	}
+
+	/* LCD and camera power (VREG & LDO) init */
+	if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()
+			|| machine_is_msm8625_evt()
+			|| machine_is_msm7627a_qrd3()
+			|| machine_is_msm8625_qrd7()) {
+
+		lcd_camera_power_init();
+		evb_camera_gpio_cfg();
+	}
+
+#ifndef CONFIG_MSM_CAMERA_V4L2
+	if (machine_is_msm7627a_qrd1()) {
+		qrd1_camera_gpio_cfg();
+		platform_add_devices(camera_devices_qrd,
+				ARRAY_SIZE(camera_devices_qrd));
+	} else if (machine_is_msm7627a_evb()
+			|| machine_is_msm8625_evb()
+			|| machine_is_msm8625_evt()
+			|| machine_is_msm7627a_qrd3()
+			|| machine_is_msm8625_qrd7()) {
+		platform_add_devices(camera_devices_evb,
+				ARRAY_SIZE(camera_devices_evb));
+	} else if (machine_is_msm7627a_qrd3())
+		return;
+	else
+		platform_add_devices(camera_devices_msm,
+				ARRAY_SIZE(camera_devices_msm));
+#endif
+	if (!machine_is_msm7627a_qrd1() || !machine_is_msm7627a_evb()
+					|| !machine_is_msm8625_evb()
+					|| !machine_is_msm8625_evt()
+					|| !machine_is_msm7627a_qrd3()
+					|| !machine_is_msm8625_qrd7())
+		register_i2c_devices();
+#ifndef CONFIG_MSM_CAMERA_V4L2
+	rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs_camera), regs_camera);
+
+	if (rc) {
+		pr_err("%s: could not get regulators: %d\n", __func__, rc);
+		return;
+	}
+
+	rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs_camera), regs_camera);
+
+	if (rc) {
+		pr_err("%s: could not set voltages: %d\n", __func__, rc);
+		return;
+	}
+#endif
+
+#if defined(CONFIG_MSM_CAMERA_V4L2)
+	msm7x27a_init_cam();
+#endif
+#ifndef CONFIG_MSM_CAMERA_V4L2
+	if (machine_is_msm7627a_qrd1()) {
+		i2c_register_board_info(MSM_GSBI0_QUP_I2C_BUS_ID,
+				i2c_camera_devices_qrd,
+				ARRAY_SIZE(i2c_camera_devices_qrd));
+	} else if (machine_is_msm7627a_evb()
+			|| machine_is_msm8625_evb()
+			|| machine_is_msm8625_evt()
+			|| machine_is_msm7627a_qrd3()
+			|| machine_is_msm8625_qrd7()) {
+		pr_debug("machine_is_msm7627a_evb i2c_register_board_info\n");
+		i2c_register_board_info(MSM_GSBI0_QUP_I2C_BUS_ID,
+				i2c_camera_devices_evb,
+				ARRAY_SIZE(i2c_camera_devices_evb));
+	} else
+#endif
+		pr_debug("i2c_register_board_info\n");
+		i2c_register_board_info(MSM_GSBI0_QUP_I2C_BUS_ID,
+				i2c_camera_devices,
+				ARRAY_SIZE(i2c_camera_devices));
+}
diff --git a/arch/arm/mach-msm/board-msm7627a-display.c b/arch/arm/mach-msm/board-msm7627a-display.c
new file mode 100644
index 0000000..bd38f30
--- /dev/null
+++ b/arch/arm/mach-msm/board-msm7627a-display.c
@@ -0,0 +1,1326 @@
+/* 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 <linux/regulator/consumer.h>
+#include <linux/gpio.h>
+#include <asm/mach-types.h>
+#include <asm/io.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_memtypes.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
+#include <mach/socinfo.h>
+#include <mach/rpc_pmapp.h>
+#include "devices.h"
+#include "board-msm7627a.h"
+
+#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
+#define MSM_FB_SIZE		0x4BF000
+#define MSM7x25A_MSM_FB_SIZE    0x1C2000
+#define MSM8x25_MSM_FB_SIZE	0x5FA000
+#else
+#define MSM_FB_SIZE		0x32A000
+#define MSM7x25A_MSM_FB_SIZE	0x12C000
+#define MSM8x25_MSM_FB_SIZE	0x3FC000
+#endif
+
+/*
+ * Reserve enough v4l2 space for a double buffered full screen
+ * res image (864x480x1.5x2)
+ */
+#define MSM_V4L2_VIDEO_OVERLAY_BUF_SIZE 1244160
+
+static unsigned fb_size = MSM_FB_SIZE;
+static int __init fb_size_setup(char *p)
+{
+	fb_size = memparse(p, NULL);
+	return 0;
+}
+
+early_param("fb_size", fb_size_setup);
+
+static uint32_t lcdc_truly_gpio_initialized;
+static struct regulator_bulk_data regs_truly_lcdc[] = {
+	{ .supply = "rfrx1",   .min_uV = 1800000, .max_uV = 1800000 },
+};
+
+#define SKU3_LCDC_GPIO_DISPLAY_RESET	90
+#define SKU3_LCDC_GPIO_SPI_MOSI		19
+#define SKU3_LCDC_GPIO_SPI_CLK		20
+#define SKU3_LCDC_GPIO_SPI_CS0_N	21
+#define SKU3_LCDC_LCD_CAMERA_LDO_2V8	35  /*LCD_CAMERA_LDO_2V8*/
+#define SKU3_LCDC_LCD_CAMERA_LDO_1V8	34  /*LCD_CAMERA_LDO_1V8*/
+#define SKU3_1_LCDC_LCD_CAMERA_LDO_1V8	58  /*LCD_CAMERA_LDO_1V8*/
+
+static uint32_t lcdc_truly_gpio_table[] = {
+	19,
+	20,
+	21,
+	89,
+	90,
+};
+
+static char *lcdc_gpio_name_table[5] = {
+	"spi_mosi",
+	"spi_clk",
+	"spi_cs",
+	"gpio_bkl_en",
+	"gpio_disp_reset",
+};
+
+static int lcdc_truly_gpio_init(void)
+{
+	int i;
+	int rc = 0;
+
+	if (!lcdc_truly_gpio_initialized) {
+		for (i = 0; i < ARRAY_SIZE(lcdc_truly_gpio_table); i++) {
+			rc = gpio_request(lcdc_truly_gpio_table[i],
+				lcdc_gpio_name_table[i]);
+			if (rc < 0) {
+				pr_err("Error request gpio %s\n",
+					lcdc_gpio_name_table[i]);
+				goto truly_gpio_fail;
+			}
+			rc = gpio_tlmm_config(GPIO_CFG(lcdc_truly_gpio_table[i],
+				0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
+				GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+			if (rc < 0) {
+				pr_err("Error config lcdc gpio:%d\n",
+					lcdc_truly_gpio_table[i]);
+				goto truly_gpio_fail;
+			}
+			rc = gpio_direction_output(lcdc_truly_gpio_table[i], 0);
+			if (rc < 0) {
+				pr_err("Error direct lcdc gpio:%d\n",
+					lcdc_truly_gpio_table[i]);
+				goto truly_gpio_fail;
+			}
+		}
+
+			lcdc_truly_gpio_initialized = 1;
+	}
+
+	return rc;
+
+truly_gpio_fail:
+	for (; i >= 0; i--) {
+		pr_err("Freeing GPIO: %d", lcdc_truly_gpio_table[i]);
+		gpio_free(lcdc_truly_gpio_table[i]);
+	}
+
+	lcdc_truly_gpio_initialized = 0;
+	return rc;
+}
+
+
+void sku3_lcdc_lcd_camera_power_init(void)
+{
+	int rc = 0;
+	u32 socinfo = socinfo_get_platform_type();
+
+	  /* LDO_EXT2V8 */
+	if (gpio_request(SKU3_LCDC_LCD_CAMERA_LDO_2V8, "lcd_camera_ldo_2v8")) {
+		pr_err("failed to request gpio lcd_camera_ldo_2v8\n");
+		return;
+	}
+
+	rc = gpio_tlmm_config(GPIO_CFG(SKU3_LCDC_LCD_CAMERA_LDO_2V8, 0,
+		GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+		GPIO_CFG_ENABLE);
+
+	if (rc < 0) {
+		pr_err("%s:unable to enable lcd_camera_ldo_2v8!\n", __func__);
+		goto fail_gpio2;
+	}
+
+	/* LDO_EVT1V8 */
+	if (socinfo == 0x0B) {
+		if (gpio_request(SKU3_LCDC_LCD_CAMERA_LDO_1V8,
+				"lcd_camera_ldo_1v8")) {
+			pr_err("failed to request gpio lcd_camera_ldo_1v8\n");
+			goto fail_gpio1;
+		}
+
+		rc = gpio_tlmm_config(GPIO_CFG(SKU3_LCDC_LCD_CAMERA_LDO_1V8, 0,
+			GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+			GPIO_CFG_ENABLE);
+
+		if (rc < 0) {
+			pr_err("%s: unable to enable lcdc_camera_ldo_1v8!\n",
+				__func__);
+			goto fail_gpio1;
+		}
+	} else if (socinfo == 0x0F || machine_is_msm8625_qrd7()) {
+		if (gpio_request(SKU3_1_LCDC_LCD_CAMERA_LDO_1V8,
+				"lcd_camera_ldo_1v8")) {
+			pr_err("failed to request gpio lcd_camera_ldo_1v8\n");
+			goto fail_gpio1;
+		}
+
+		rc = gpio_tlmm_config(GPIO_CFG(SKU3_1_LCDC_LCD_CAMERA_LDO_1V8,
+			0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+			GPIO_CFG_ENABLE);
+
+		if (rc < 0) {
+			pr_err("%s: unable to enable lcdc_camera_ldo_1v8!\n",
+				__func__);
+			goto fail_gpio1;
+		}
+	}
+
+	rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs_truly_lcdc),
+			regs_truly_lcdc);
+	if (rc)
+		pr_err("%s: could not get regulators: %d\n", __func__, rc);
+
+	rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs_truly_lcdc),
+			regs_truly_lcdc);
+	if (rc)
+		pr_err("%s: could not set voltages: %d\n", __func__, rc);
+
+	return;
+
+fail_gpio1:
+	if (socinfo == 0x0B)
+		gpio_free(SKU3_LCDC_LCD_CAMERA_LDO_1V8);
+	else if (socinfo == 0x0F || machine_is_msm8625_qrd7())
+		gpio_free(SKU3_1_LCDC_LCD_CAMERA_LDO_1V8);
+fail_gpio2:
+	gpio_free(SKU3_LCDC_LCD_CAMERA_LDO_2V8);
+	return;
+}
+
+int sku3_lcdc_lcd_camera_power_onoff(int on)
+{
+	int rc = 0;
+	u32 socinfo = socinfo_get_platform_type();
+
+	if (on) {
+		if (socinfo == 0x0B)
+			gpio_set_value_cansleep(SKU3_LCDC_LCD_CAMERA_LDO_1V8,
+				1);
+		else if (socinfo == 0x0F || machine_is_msm8625_qrd7())
+			gpio_set_value_cansleep(SKU3_1_LCDC_LCD_CAMERA_LDO_1V8,
+				1);
+
+		gpio_set_value_cansleep(SKU3_LCDC_LCD_CAMERA_LDO_2V8, 1);
+
+		rc = regulator_bulk_enable(ARRAY_SIZE(regs_truly_lcdc),
+				regs_truly_lcdc);
+		if (rc)
+			pr_err("%s: could not enable regulators: %d\n",
+				__func__, rc);
+	} else {
+		if (socinfo == 0x0B)
+			gpio_set_value_cansleep(SKU3_LCDC_LCD_CAMERA_LDO_1V8,
+				0);
+		else if (socinfo == 0x0F || machine_is_msm8625_qrd7())
+			gpio_set_value_cansleep(SKU3_1_LCDC_LCD_CAMERA_LDO_1V8,
+				0);
+
+		gpio_set_value_cansleep(SKU3_LCDC_LCD_CAMERA_LDO_2V8, 0);
+
+		rc = regulator_bulk_disable(ARRAY_SIZE(regs_truly_lcdc),
+				regs_truly_lcdc);
+		if (rc)
+			pr_err("%s: could not disable regulators: %d\n",
+				__func__, rc);
+	}
+
+	return rc;
+}
+
+static int sku3_lcdc_power_save(int on)
+{
+	int rc = 0;
+
+	if (on) {
+		sku3_lcdc_lcd_camera_power_onoff(1);
+		rc = lcdc_truly_gpio_init();
+		if (rc < 0) {
+			pr_err("%s(): Truly GPIO initializations failed",
+				__func__);
+			return rc;
+		}
+
+		if (lcdc_truly_gpio_initialized) {
+			/*LCD reset*/
+			gpio_set_value(SKU3_LCDC_GPIO_DISPLAY_RESET, 1);
+			msleep(20);
+			gpio_set_value(SKU3_LCDC_GPIO_DISPLAY_RESET, 0);
+			msleep(20);
+			gpio_set_value(SKU3_LCDC_GPIO_DISPLAY_RESET, 1);
+			msleep(20);
+		}
+	} else {
+		/* pull down LCD IO to avoid current leakage */
+		gpio_set_value(SKU3_LCDC_GPIO_SPI_MOSI, 0);
+		gpio_set_value(SKU3_LCDC_GPIO_SPI_CLK, 0);
+		gpio_set_value(SKU3_LCDC_GPIO_SPI_CS0_N, 0);
+		gpio_set_value(SKU3_LCDC_GPIO_DISPLAY_RESET, 0);
+
+		sku3_lcdc_lcd_camera_power_onoff(0);
+	}
+	return rc;
+}
+
+static struct msm_panel_common_pdata lcdc_truly_panel_data = {
+	.panel_config_gpio = NULL,
+	.gpio_num	  = lcdc_truly_gpio_table,
+};
+
+static struct platform_device lcdc_truly_panel_device = {
+	.name   = "lcdc_truly_hvga_ips3p2335_pt",
+	.id     = 0,
+	.dev    = {
+		.platform_data = &lcdc_truly_panel_data,
+	}
+};
+
+static struct regulator_bulk_data regs_lcdc[] = {
+	{ .supply = "gp2",   .min_uV = 2850000, .max_uV = 2850000 },
+	{ .supply = "msme1", .min_uV = 1800000, .max_uV = 1800000 },
+};
+static uint32_t lcdc_gpio_initialized;
+
+static void lcdc_toshiba_gpio_init(void)
+{
+	int rc = 0;
+	if (!lcdc_gpio_initialized) {
+		if (gpio_request(GPIO_SPI_CLK, "spi_clk")) {
+			pr_err("failed to request gpio spi_clk\n");
+			return;
+		}
+		if (gpio_request(GPIO_SPI_CS0_N, "spi_cs")) {
+			pr_err("failed to request gpio spi_cs0_N\n");
+			goto fail_gpio6;
+		}
+		if (gpio_request(GPIO_SPI_MOSI, "spi_mosi")) {
+			pr_err("failed to request gpio spi_mosi\n");
+			goto fail_gpio5;
+		}
+		if (gpio_request(GPIO_SPI_MISO, "spi_miso")) {
+			pr_err("failed to request gpio spi_miso\n");
+			goto fail_gpio4;
+		}
+		if (gpio_request(GPIO_DISPLAY_PWR_EN, "gpio_disp_pwr")) {
+			pr_err("failed to request gpio_disp_pwr\n");
+			goto fail_gpio3;
+		}
+		if (gpio_request(GPIO_BACKLIGHT_EN, "gpio_bkl_en")) {
+			pr_err("failed to request gpio_bkl_en\n");
+			goto fail_gpio2;
+		}
+		pmapp_disp_backlight_init();
+
+		rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs_lcdc),
+					regs_lcdc);
+		if (rc) {
+			pr_err("%s: could not get regulators: %d\n",
+					__func__, rc);
+			goto fail_gpio1;
+		}
+
+		rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs_lcdc),
+				regs_lcdc);
+		if (rc) {
+			pr_err("%s: could not set voltages: %d\n",
+					__func__, rc);
+			goto fail_vreg;
+		}
+		lcdc_gpio_initialized = 1;
+	}
+	return;
+fail_vreg:
+	regulator_bulk_free(ARRAY_SIZE(regs_lcdc), regs_lcdc);
+fail_gpio1:
+	gpio_free(GPIO_BACKLIGHT_EN);
+fail_gpio2:
+	gpio_free(GPIO_DISPLAY_PWR_EN);
+fail_gpio3:
+	gpio_free(GPIO_SPI_MISO);
+fail_gpio4:
+	gpio_free(GPIO_SPI_MOSI);
+fail_gpio5:
+	gpio_free(GPIO_SPI_CS0_N);
+fail_gpio6:
+	gpio_free(GPIO_SPI_CLK);
+	lcdc_gpio_initialized = 0;
+}
+
+static uint32_t lcdc_gpio_table[] = {
+	GPIO_SPI_CLK,
+	GPIO_SPI_CS0_N,
+	GPIO_SPI_MOSI,
+	GPIO_DISPLAY_PWR_EN,
+	GPIO_BACKLIGHT_EN,
+	GPIO_SPI_MISO,
+};
+
+static void config_lcdc_gpio_table(uint32_t *table, int len, unsigned enable)
+{
+	int n;
+
+	if (lcdc_gpio_initialized) {
+		/* All are IO Expander GPIOs */
+		for (n = 0; n < (len - 1); n++)
+			gpio_direction_output(table[n], 1);
+	}
+}
+
+static void lcdc_toshiba_config_gpios(int enable)
+{
+	config_lcdc_gpio_table(lcdc_gpio_table,
+		ARRAY_SIZE(lcdc_gpio_table), enable);
+}
+
+static int msm_fb_lcdc_power_save(int on)
+{
+	int rc = 0;
+	/* Doing the init of the LCDC GPIOs very late as they are from
+		an I2C-controlled IO Expander */
+	lcdc_toshiba_gpio_init();
+
+	if (lcdc_gpio_initialized) {
+		gpio_set_value_cansleep(GPIO_DISPLAY_PWR_EN, on);
+		gpio_set_value_cansleep(GPIO_BACKLIGHT_EN, on);
+
+		rc = on ? regulator_bulk_enable(
+				ARRAY_SIZE(regs_lcdc), regs_lcdc) :
+			  regulator_bulk_disable(
+				ARRAY_SIZE(regs_lcdc), regs_lcdc);
+
+		if (rc)
+			pr_err("%s: could not %sable regulators: %d\n",
+					__func__, on ? "en" : "dis", rc);
+	}
+
+	return rc;
+}
+
+static int lcdc_toshiba_set_bl(int level)
+{
+	int ret;
+
+	ret = pmapp_disp_backlight_set_brightness(level);
+	if (ret)
+		pr_err("%s: can't set lcd backlight!\n", __func__);
+
+	return ret;
+}
+
+
+static int msm_lcdc_power_save(int on)
+{
+	int rc = 0;
+	if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7())
+		rc = sku3_lcdc_power_save(on);
+	else
+		rc = msm_fb_lcdc_power_save(on);
+
+	return rc;
+}
+
+static struct lcdc_platform_data lcdc_pdata = {
+	.lcdc_gpio_config = NULL,
+	.lcdc_power_save   = msm_lcdc_power_save,
+};
+
+static int lcd_panel_spi_gpio_num[] = {
+		GPIO_SPI_MOSI,  /* spi_sdi */
+		GPIO_SPI_MISO,  /* spi_sdoi */
+		GPIO_SPI_CLK,   /* spi_clk */
+		GPIO_SPI_CS0_N, /* spi_cs  */
+};
+
+static struct msm_panel_common_pdata lcdc_toshiba_panel_data = {
+	.panel_config_gpio = lcdc_toshiba_config_gpios,
+	.pmic_backlight = lcdc_toshiba_set_bl,
+	.gpio_num	 = lcd_panel_spi_gpio_num,
+};
+
+static struct platform_device lcdc_toshiba_panel_device = {
+	.name   = "lcdc_toshiba_fwvga_pt",
+	.id     = 0,
+	.dev    = {
+		.platform_data = &lcdc_toshiba_panel_data,
+	}
+};
+
+static struct resource msm_fb_resources[] = {
+	{
+		.flags  = IORESOURCE_DMA,
+	}
+};
+
+#ifdef CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE
+static struct resource msm_v4l2_video_overlay_resources[] = {
+	{
+		.flags = IORESOURCE_DMA,
+	}
+};
+#endif
+
+#define LCDC_TOSHIBA_FWVGA_PANEL_NAME   "lcdc_toshiba_fwvga_pt"
+#define MIPI_CMD_RENESAS_FWVGA_PANEL_NAME       "mipi_cmd_renesas_fwvga"
+
+static int msm_fb_detect_panel(const char *name)
+{
+	int ret = -ENODEV;
+
+	if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf() ||
+			machine_is_msm8625_surf()) {
+		if (!strncmp(name, "lcdc_toshiba_fwvga_pt", 21) ||
+				!strncmp(name, "mipi_cmd_renesas_fwvga", 22))
+			ret = 0;
+	} else if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa()
+					|| machine_is_msm8625_ffa()) {
+		if (!strncmp(name, "mipi_cmd_renesas_fwvga", 22))
+			ret = 0;
+	} else if (machine_is_msm7627a_qrd1()) {
+		if (!strncmp(name, "mipi_video_truly_wvga", 21))
+			ret = 0;
+	} else if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7()) {
+		if (!strncmp(name, "lcdc_truly_hvga_ips3p2335_pt", 28))
+			ret = 0;
+	} else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
+		if (!strncmp(name, "mipi_cmd_nt35510_wvga", 21))
+			ret = 0;
+	} else if (machine_is_msm8625_evt()) {
+		if (!strncmp(name, "mipi_video_nt35510_wvga", 23))
+			ret = 0;
+	}
+
+#if !defined(CONFIG_FB_MSM_LCDC_AUTO_DETECT) && \
+	!defined(CONFIG_FB_MSM_MIPI_PANEL_AUTO_DETECT) && \
+	!defined(CONFIG_FB_MSM_LCDC_MIPI_PANEL_AUTO_DETECT)
+		if (machine_is_msm7x27a_surf() ||
+			machine_is_msm7625a_surf() ||
+			machine_is_msm8625_surf()) {
+			if (!strncmp(name, LCDC_TOSHIBA_FWVGA_PANEL_NAME,
+				strnlen(LCDC_TOSHIBA_FWVGA_PANEL_NAME,
+					PANEL_NAME_MAX_LEN)))
+				return 0;
+		}
+#endif
+
+	return ret;
+}
+
+static int mipi_truly_set_bl(int on)
+{
+	gpio_set_value_cansleep(QRD_GPIO_BACKLIGHT_EN, !!on);
+
+	return 1;
+}
+
+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,
+	}
+};
+
+#ifdef CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE
+static struct platform_device msm_v4l2_video_overlay_device = {
+		.name   = "msm_v4l2_overlay_pd",
+		.id     = 0,
+		.num_resources  = ARRAY_SIZE(msm_v4l2_video_overlay_resources),
+		.resource       = msm_v4l2_video_overlay_resources,
+	};
+#endif
+
+
+#ifdef CONFIG_FB_MSM_MIPI_DSI
+static int mipi_renesas_set_bl(int level)
+{
+	int ret;
+
+	ret = pmapp_disp_backlight_set_brightness(level);
+
+	if (ret)
+		pr_err("%s: can't set lcd backlight!\n", __func__);
+
+	return ret;
+}
+
+static struct msm_panel_common_pdata mipi_renesas_pdata = {
+	.pmic_backlight = mipi_renesas_set_bl,
+};
+
+
+static struct platform_device mipi_dsi_renesas_panel_device = {
+	.name = "mipi_renesas",
+	.id = 0,
+	.dev    = {
+		.platform_data = &mipi_renesas_pdata,
+	}
+};
+#endif
+
+static int evb_backlight_control(int level)
+{
+
+	int i = 0;
+	int remainder;
+	/* device address byte = 0x72 */
+	gpio_set_value(96, 0);
+	udelay(67);
+	gpio_set_value(96, 1);
+	udelay(33);
+	gpio_set_value(96, 0);
+	udelay(33);
+	gpio_set_value(96, 1);
+	udelay(67);
+	gpio_set_value(96, 0);
+	udelay(33);
+	gpio_set_value(96, 1);
+	udelay(67);
+	gpio_set_value(96, 0);
+	udelay(33);
+	gpio_set_value(96, 1);
+	udelay(67);
+	gpio_set_value(96, 0);
+	udelay(67);
+	gpio_set_value(96, 1);
+	udelay(33);
+	gpio_set_value(96, 0);
+	udelay(67);
+	gpio_set_value(96, 1);
+	udelay(33);
+	gpio_set_value(96, 0);
+	udelay(33);
+	gpio_set_value(96, 1);
+	udelay(67);
+	gpio_set_value(96, 0);
+	udelay(67);
+	gpio_set_value(96, 1);
+	udelay(33);
+
+	/* t-EOS and t-start */
+	gpio_set_value(96, 0);
+	ndelay(4200);
+	gpio_set_value(96, 1);
+	ndelay(9000);
+
+	/* data byte */
+	/* RFA = 0 */
+	gpio_set_value(96, 0);
+	udelay(67);
+	gpio_set_value(96, 1);
+	udelay(33);
+
+	/* Address bits */
+	gpio_set_value(96, 0);
+	udelay(67);
+	gpio_set_value(96, 1);
+	udelay(33);
+	gpio_set_value(96, 0);
+	udelay(67);
+	gpio_set_value(96, 1);
+	udelay(33);
+
+	/* Data bits */
+	for (i = 0; i < 5; i++) {
+		remainder = (level) & (16);
+		if (remainder) {
+			gpio_set_value(96, 0);
+			udelay(33);
+			gpio_set_value(96, 1);
+			udelay(67);
+		} else {
+			gpio_set_value(96, 0);
+			udelay(67);
+			gpio_set_value(96, 1);
+			udelay(33);
+		}
+		level = level << 1;
+	}
+
+	/* t-EOS */
+	gpio_set_value(96, 0);
+	ndelay(12000);
+	gpio_set_value(96, 1);
+	return 0;
+}
+
+static int mipi_NT35510_rotate_panel(void)
+{
+	int rotate = 0;
+	if (machine_is_msm8625_evt())
+		rotate = 1;
+
+	return rotate;
+}
+
+static struct msm_panel_common_pdata mipi_truly_pdata = {
+	.pmic_backlight = mipi_truly_set_bl,
+};
+
+static struct platform_device mipi_dsi_truly_panel_device = {
+	.name   = "mipi_truly",
+	.id     = 0,
+	.dev    = {
+		.platform_data = &mipi_truly_pdata,
+	}
+};
+
+static struct msm_panel_common_pdata mipi_NT35510_pdata = {
+	.pmic_backlight = evb_backlight_control,
+	.rotate_panel = mipi_NT35510_rotate_panel,
+};
+
+static struct platform_device mipi_dsi_NT35510_panel_device = {
+	.name = "mipi_NT35510",
+	.id   = 0,
+	.dev  = {
+		.platform_data = &mipi_NT35510_pdata,
+	}
+};
+
+static struct msm_panel_common_pdata mipi_NT35516_pdata = {
+	.pmic_backlight = evb_backlight_control,
+};
+
+static struct platform_device mipi_dsi_NT35516_panel_device = {
+	.name   = "mipi_truly_tft540960_1_e",
+	.id     = 0,
+	.dev    = {
+		.platform_data = &mipi_NT35516_pdata,
+	}
+};
+
+static struct platform_device *msm_fb_devices[] __initdata = {
+	&msm_fb_device,
+	&lcdc_toshiba_panel_device,
+#ifdef CONFIG_FB_MSM_MIPI_DSI
+	&mipi_dsi_renesas_panel_device,
+#endif
+#ifdef CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE
+	&msm_v4l2_video_overlay_device,
+#endif
+};
+
+static struct platform_device *qrd_fb_devices[] __initdata = {
+	&msm_fb_device,
+	&mipi_dsi_truly_panel_device,
+};
+
+static struct platform_device *qrd3_fb_devices[] __initdata = {
+	&msm_fb_device,
+	&lcdc_truly_panel_device,
+};
+
+static struct platform_device *evb_fb_devices[] __initdata = {
+	&msm_fb_device,
+	&mipi_dsi_NT35510_panel_device,
+	&mipi_dsi_NT35516_panel_device,
+};
+
+void __init msm_msm7627a_allocate_memory_regions(void)
+{
+	void *addr;
+	unsigned long fb_size;
+
+	if (machine_is_msm7625a_surf() || machine_is_msm7625a_ffa())
+		fb_size = MSM7x25A_MSM_FB_SIZE;
+	else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()
+						|| machine_is_msm8625_evt())
+		fb_size = MSM8x25_MSM_FB_SIZE;
+	else
+		fb_size = MSM_FB_SIZE;
+
+	addr = alloc_bootmem_align(fb_size, 0x1000);
+	msm_fb_resources[0].start = __pa(addr);
+	msm_fb_resources[0].end = msm_fb_resources[0].start + fb_size - 1;
+	pr_info("allocating %lu bytes at %p (%lx physical) for fb\n", fb_size,
+						addr, __pa(addr));
+
+#ifdef CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE
+	fb_size = MSM_V4L2_VIDEO_OVERLAY_BUF_SIZE;
+	addr = alloc_bootmem_align(fb_size, 0x1000);
+	msm_v4l2_video_overlay_resources[0].start = __pa(addr);
+	msm_v4l2_video_overlay_resources[0].end =
+		msm_v4l2_video_overlay_resources[0].start + fb_size - 1;
+	pr_debug("allocating %lu bytes at %p (%lx physical) for v4l2\n",
+		fb_size, addr, __pa(addr));
+#endif
+
+}
+
+static struct msm_panel_common_pdata mdp_pdata = {
+	.gpio = 97,
+	.mdp_rev = MDP_REV_303,
+};
+
+#define GPIO_LCDC_BRDG_PD	128
+#define GPIO_LCDC_BRDG_RESET_N	129
+#define GPIO_LCD_DSI_SEL	125
+#define LCDC_RESET_PHYS		0x90008014
+
+static  void __iomem *lcdc_reset_ptr;
+
+static unsigned mipi_dsi_gpio[] = {
+		GPIO_CFG(GPIO_LCDC_BRDG_RESET_N, 0, GPIO_CFG_OUTPUT,
+		GPIO_CFG_NO_PULL, GPIO_CFG_2MA), /* LCDC_BRDG_RESET_N */
+		GPIO_CFG(GPIO_LCDC_BRDG_PD, 0, GPIO_CFG_OUTPUT,
+		GPIO_CFG_NO_PULL, GPIO_CFG_2MA), /* LCDC_BRDG_PD */
+};
+
+static unsigned lcd_dsi_sel_gpio[] = {
+	GPIO_CFG(GPIO_LCD_DSI_SEL, 0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
+			GPIO_CFG_2MA),
+};
+
+enum {
+	DSI_SINGLE_LANE = 1,
+	DSI_TWO_LANES,
+};
+
+static int msm_fb_get_lane_config(void)
+{
+	/* For MSM7627A SURF/FFA and QRD */
+	int rc = DSI_TWO_LANES;
+	if (machine_is_msm7625a_surf() || machine_is_msm7625a_ffa()) {
+		rc = DSI_SINGLE_LANE;
+		pr_info("DSI_SINGLE_LANES\n");
+	} else {
+		pr_info("DSI_TWO_LANES\n");
+	}
+	return rc;
+}
+
+static int msm_fb_dsi_client_msm_reset(void)
+{
+	int rc = 0;
+
+	rc = gpio_request(GPIO_LCDC_BRDG_RESET_N, "lcdc_brdg_reset_n");
+	if (rc < 0) {
+		pr_err("failed to request lcd brdg reset_n\n");
+		return rc;
+	}
+
+	rc = gpio_request(GPIO_LCDC_BRDG_PD, "lcdc_brdg_pd");
+	if (rc < 0) {
+		pr_err("failed to request lcd brdg pd\n");
+		return rc;
+	}
+
+	rc = gpio_tlmm_config(mipi_dsi_gpio[0], GPIO_CFG_ENABLE);
+	if (rc) {
+		pr_err("Failed to enable LCDC Bridge reset enable\n");
+		goto gpio_error;
+	}
+
+	rc = gpio_tlmm_config(mipi_dsi_gpio[1], GPIO_CFG_ENABLE);
+	if (rc) {
+		pr_err("Failed to enable LCDC Bridge pd enable\n");
+		goto gpio_error2;
+	}
+
+	rc = gpio_direction_output(GPIO_LCDC_BRDG_RESET_N, 1);
+	rc |= gpio_direction_output(GPIO_LCDC_BRDG_PD, 1);
+	gpio_set_value_cansleep(GPIO_LCDC_BRDG_PD, 0);
+
+	if (!rc) {
+		if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf()
+				|| machine_is_msm8625_surf()) {
+			lcdc_reset_ptr = ioremap_nocache(LCDC_RESET_PHYS,
+				sizeof(uint32_t));
+
+			if (!lcdc_reset_ptr)
+				return 0;
+		}
+		return rc;
+	} else {
+		goto gpio_error;
+	}
+
+gpio_error2:
+	pr_err("Failed GPIO bridge pd\n");
+	gpio_free(GPIO_LCDC_BRDG_PD);
+
+gpio_error:
+	pr_err("Failed GPIO bridge reset\n");
+	gpio_free(GPIO_LCDC_BRDG_RESET_N);
+	return rc;
+}
+
+static int mipi_truly_sel_mode(int video_mode)
+{
+	int rc = 0;
+
+	rc = gpio_request(GPIO_LCD_DSI_SEL, "lcd_dsi_sel");
+	if (rc < 0)
+		goto gpio_error;
+
+	rc = gpio_tlmm_config(lcd_dsi_sel_gpio[0], GPIO_CFG_ENABLE);
+	if (rc)
+		goto gpio_error;
+
+	rc = gpio_direction_output(GPIO_LCD_DSI_SEL, 1);
+	if (!rc) {
+		gpio_set_value_cansleep(GPIO_LCD_DSI_SEL, video_mode);
+		return rc;
+	} else {
+		goto gpio_error;
+	}
+
+gpio_error:
+	pr_err("mipi_truly_sel_mode failed\n");
+	gpio_free(GPIO_LCD_DSI_SEL);
+	return rc;
+}
+
+static int msm_fb_dsi_client_qrd1_reset(void)
+{
+	int rc = 0;
+
+	rc = gpio_request(GPIO_LCDC_BRDG_RESET_N, "lcdc_brdg_reset_n");
+	if (rc < 0) {
+		pr_err("failed to request lcd brdg reset_n\n");
+		return rc;
+	}
+
+	rc = gpio_tlmm_config(mipi_dsi_gpio[0], GPIO_CFG_ENABLE);
+	if (rc < 0) {
+		pr_err("Failed to enable LCDC Bridge reset enable\n");
+		return rc;
+	}
+
+	rc = gpio_direction_output(GPIO_LCDC_BRDG_RESET_N, 1);
+	if (rc < 0) {
+		pr_err("Failed GPIO bridge pd\n");
+		gpio_free(GPIO_LCDC_BRDG_RESET_N);
+		return rc;
+	}
+
+	mipi_truly_sel_mode(1);
+
+	return rc;
+}
+
+#define GPIO_QRD3_LCD_BRDG_RESET_N	85
+#define GPIO_QRD3_LCD_BACKLIGHT_EN	96
+#define GPIO_QRD3_LCD_EXT_2V85_EN	35
+#define GPIO_QRD3_LCD_EXT_1V8_EN	40
+
+static unsigned qrd3_mipi_dsi_gpio[] = {
+	GPIO_CFG(GPIO_QRD3_LCD_BRDG_RESET_N, 0, GPIO_CFG_OUTPUT,
+			GPIO_CFG_NO_PULL,
+			GPIO_CFG_2MA), /* GPIO_QRD3_LCD_BRDG_RESET_N */
+	GPIO_CFG(GPIO_QRD3_LCD_BACKLIGHT_EN, 0, GPIO_CFG_OUTPUT,
+			GPIO_CFG_NO_PULL,
+			GPIO_CFG_2MA), /* GPIO_QRD3_LCD_BACKLIGHT_EN */
+	GPIO_CFG(GPIO_QRD3_LCD_EXT_2V85_EN, 0, GPIO_CFG_OUTPUT,
+			GPIO_CFG_NO_PULL,
+			GPIO_CFG_2MA), /* GPIO_QRD3_LCD_EXT_2V85_EN */
+	GPIO_CFG(GPIO_QRD3_LCD_EXT_1V8_EN, 0, GPIO_CFG_OUTPUT,
+			GPIO_CFG_NO_PULL,
+			GPIO_CFG_2MA), /* GPIO_QRD3_LCD_EXT_1V8_EN */
+};
+
+static int msm_fb_dsi_client_qrd3_reset(void)
+{
+	int rc = 0;
+
+	rc = gpio_request(GPIO_QRD3_LCD_BRDG_RESET_N, "qrd3_lcd_brdg_reset_n");
+	if (rc < 0) {
+		pr_err("failed to request qrd3 lcd brdg reset_n\n");
+		return rc;
+	}
+
+	return rc;
+}
+
+static int msm_fb_dsi_client_reset(void)
+{
+	int rc = 0;
+
+	if (machine_is_msm7627a_qrd1())
+		rc = msm_fb_dsi_client_qrd1_reset();
+	else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()
+						|| machine_is_msm8625_evt())
+		rc = msm_fb_dsi_client_qrd3_reset();
+	else
+		rc = msm_fb_dsi_client_msm_reset();
+
+	return rc;
+
+}
+
+static struct regulator_bulk_data regs_dsi[] = {
+	{ .supply = "gp2",   .min_uV = 2850000, .max_uV = 2850000 },
+	{ .supply = "msme1", .min_uV = 1800000, .max_uV = 1800000 },
+};
+
+static int dsi_gpio_initialized;
+
+static int mipi_dsi_panel_msm_power(int on)
+{
+	int rc = 0;
+	uint32_t lcdc_reset_cfg;
+
+	/* I2C-controlled GPIO Expander -init of the GPIOs very late */
+	if (unlikely(!dsi_gpio_initialized)) {
+		pmapp_disp_backlight_init();
+
+		rc = gpio_request(GPIO_DISPLAY_PWR_EN, "gpio_disp_pwr");
+		if (rc < 0) {
+			pr_err("failed to request gpio_disp_pwr\n");
+			return rc;
+		}
+
+		if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf()
+				|| machine_is_msm8625_surf()) {
+			rc = gpio_direction_output(GPIO_DISPLAY_PWR_EN, 1);
+			if (rc < 0) {
+				pr_err("failed to enable display pwr\n");
+				goto fail_gpio1;
+			}
+
+			rc = gpio_request(GPIO_BACKLIGHT_EN, "gpio_bkl_en");
+			if (rc < 0) {
+				pr_err("failed to request gpio_bkl_en\n");
+				goto fail_gpio1;
+			}
+
+			rc = gpio_direction_output(GPIO_BACKLIGHT_EN, 1);
+			if (rc < 0) {
+				pr_err("failed to enable backlight\n");
+				goto fail_gpio2;
+			}
+		}
+
+		rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs_dsi), regs_dsi);
+		if (rc) {
+			pr_err("%s: could not get regulators: %d\n",
+					__func__, rc);
+			goto fail_gpio2;
+		}
+
+		rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs_dsi),
+						regs_dsi);
+		if (rc) {
+			pr_err("%s: could not set voltages: %d\n",
+					__func__, rc);
+			goto fail_vreg;
+		}
+		if (pmapp_disp_backlight_set_brightness(100))
+			pr_err("backlight set brightness failed\n");
+
+		dsi_gpio_initialized = 1;
+	}
+	if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf() ||
+			machine_is_msm8625_surf()) {
+		gpio_set_value_cansleep(GPIO_DISPLAY_PWR_EN, on);
+		gpio_set_value_cansleep(GPIO_BACKLIGHT_EN, on);
+	} else if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa()
+					|| machine_is_msm8625_ffa()) {
+		if (on) {
+			/* This line drives an active low pin on FFA */
+			rc = gpio_direction_output(GPIO_DISPLAY_PWR_EN, !on);
+			if (rc < 0)
+				pr_err("failed to set direction for "
+					"display pwr\n");
+		} else {
+			gpio_set_value_cansleep(GPIO_DISPLAY_PWR_EN, !on);
+			rc = gpio_direction_input(GPIO_DISPLAY_PWR_EN);
+			if (rc < 0)
+				pr_err("failed to set direction for "
+					"display pwr\n");
+		}
+	}
+
+	if (on) {
+		gpio_set_value_cansleep(GPIO_LCDC_BRDG_PD, 0);
+
+		if (machine_is_msm7x27a_surf() ||
+				 machine_is_msm7625a_surf() ||
+				 machine_is_msm8625_surf()) {
+			lcdc_reset_cfg = readl_relaxed(lcdc_reset_ptr);
+			rmb();
+			lcdc_reset_cfg &= ~1;
+
+			writel_relaxed(lcdc_reset_cfg, lcdc_reset_ptr);
+			msleep(20);
+			wmb();
+			lcdc_reset_cfg |= 1;
+			writel_relaxed(lcdc_reset_cfg, lcdc_reset_ptr);
+		} else {
+			gpio_set_value_cansleep(GPIO_LCDC_BRDG_RESET_N, 0);
+			msleep(20);
+			gpio_set_value_cansleep(GPIO_LCDC_BRDG_RESET_N, 1);
+		}
+	} else {
+		gpio_set_value_cansleep(GPIO_LCDC_BRDG_PD, 1);
+	}
+
+	rc = on ? regulator_bulk_enable(ARRAY_SIZE(regs_dsi), regs_dsi) :
+		  regulator_bulk_disable(ARRAY_SIZE(regs_dsi), regs_dsi);
+
+	if (rc)
+		pr_err("%s: could not %sable regulators: %d\n",
+				__func__, on ? "en" : "dis", rc);
+
+	return rc;
+fail_vreg:
+	regulator_bulk_free(ARRAY_SIZE(regs_dsi), regs_dsi);
+fail_gpio2:
+	gpio_free(GPIO_BACKLIGHT_EN);
+fail_gpio1:
+	gpio_free(GPIO_DISPLAY_PWR_EN);
+	dsi_gpio_initialized = 0;
+	return rc;
+}
+
+static int mipi_dsi_panel_qrd1_power(int on)
+{
+	int rc = 0;
+
+	if (!dsi_gpio_initialized) {
+		rc = gpio_request(QRD_GPIO_BACKLIGHT_EN, "gpio_bkl_en");
+		if (rc < 0)
+			return rc;
+
+		rc = gpio_tlmm_config(GPIO_CFG(QRD_GPIO_BACKLIGHT_EN, 0,
+			GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+			GPIO_CFG_ENABLE);
+		if (rc < 0) {
+			pr_err("failed GPIO_BACKLIGHT_EN tlmm config\n");
+			return rc;
+		}
+
+		rc = gpio_direction_output(QRD_GPIO_BACKLIGHT_EN, 1);
+		if (rc < 0) {
+			pr_err("failed to enable backlight\n");
+			gpio_free(QRD_GPIO_BACKLIGHT_EN);
+			return rc;
+		}
+		dsi_gpio_initialized = 1;
+	}
+
+	gpio_set_value_cansleep(QRD_GPIO_BACKLIGHT_EN, !!on);
+
+	if (on) {
+		gpio_set_value_cansleep(GPIO_LCDC_BRDG_RESET_N, 1);
+		msleep(20);
+		gpio_set_value_cansleep(GPIO_LCDC_BRDG_RESET_N, 0);
+		msleep(20);
+		gpio_set_value_cansleep(GPIO_LCDC_BRDG_RESET_N, 1);
+
+	}
+
+	return rc;
+}
+
+static int qrd3_dsi_gpio_initialized;
+
+static int mipi_dsi_panel_qrd3_power(int on)
+{
+	int rc = 0;
+
+	if (!qrd3_dsi_gpio_initialized) {
+		rc = gpio_request(GPIO_QRD3_LCD_BACKLIGHT_EN,
+			"qrd3_gpio_bkl_en");
+		if (rc < 0)
+			return rc;
+
+		rc = gpio_request(GPIO_QRD3_LCD_EXT_2V85_EN,
+			"qrd3_gpio_ext_2v85_en");
+		if (rc < 0)
+			return rc;
+
+		rc = gpio_tlmm_config(GPIO_CFG(GPIO_QRD3_LCD_EXT_2V85_EN, 0,
+			GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+			GPIO_CFG_ENABLE);
+		if (rc < 0) {
+			pr_err("failed QRD3 GPIO_QRD3_LCD_EXT_2V85_EN tlmm config\n");
+			return rc;
+		}
+
+		rc = gpio_direction_output(GPIO_QRD3_LCD_EXT_2V85_EN, 1);
+		if (rc < 0) {
+			pr_err("failed to enable external 2V85\n");
+			gpio_free(GPIO_QRD3_LCD_EXT_2V85_EN);
+			return rc;
+		}
+
+		rc = gpio_request(GPIO_QRD3_LCD_EXT_1V8_EN,
+			"qrd3_gpio_ext_1v8_en");
+		if (rc < 0)
+			return rc;
+
+		rc = gpio_tlmm_config(GPIO_CFG(GPIO_QRD3_LCD_EXT_1V8_EN, 0,
+			GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+			GPIO_CFG_ENABLE);
+		if (rc < 0) {
+			pr_err("failed QRD3 GPIO_QRD3_LCD_EXT_1V8_EN tlmm config\n");
+			return rc;
+		}
+
+		rc = gpio_direction_output(GPIO_QRD3_LCD_EXT_1V8_EN, 1);
+		if (rc < 0) {
+			pr_err("failed to enable external 1v8\n");
+			gpio_free(GPIO_QRD3_LCD_EXT_1V8_EN);
+			return rc;
+		}
+
+			qrd3_dsi_gpio_initialized = 1;
+	}
+
+	if (on) {
+		rc = gpio_tlmm_config(GPIO_CFG(GPIO_QRD3_LCD_BACKLIGHT_EN, 0,
+			GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_2MA),
+			GPIO_CFG_ENABLE);
+		if (rc < 0) {
+			pr_err("failed QRD3 GPIO_BACKLIGHT_EN tlmm config\n");
+			return rc;
+		}
+		rc = gpio_direction_output(GPIO_QRD3_LCD_BACKLIGHT_EN, 1);
+		if (rc < 0) {
+			pr_err("failed to enable backlight\n");
+			gpio_free(GPIO_QRD3_LCD_BACKLIGHT_EN);
+			return rc;
+		}
+
+		gpio_set_value_cansleep(GPIO_QRD3_LCD_BACKLIGHT_EN, 1);
+		udelay(190);
+		gpio_set_value_cansleep(GPIO_QRD3_LCD_BACKLIGHT_EN, 0);
+		udelay(286);
+		gpio_set_value_cansleep(GPIO_QRD3_LCD_BACKLIGHT_EN, 1);
+		/* 1 wire mode starts from this low to high transition */
+		udelay(50);
+	} else {
+		gpio_tlmm_config(GPIO_CFG(GPIO_QRD3_LCD_BACKLIGHT_EN, 0,
+			GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+			GPIO_CFG_DISABLE);
+	}
+
+	gpio_set_value_cansleep(GPIO_QRD3_LCD_EXT_2V85_EN, !!on);
+	gpio_set_value_cansleep(GPIO_QRD3_LCD_EXT_1V8_EN, !!on);
+
+	if (on) {
+		rc = gpio_tlmm_config(qrd3_mipi_dsi_gpio[0], GPIO_CFG_ENABLE);
+
+		if (rc < 0) {
+			pr_err("Failed to enable LCD Bridge reset enable\n");
+			return rc;
+		}
+
+		rc = gpio_direction_output(GPIO_QRD3_LCD_BRDG_RESET_N, 1);
+
+		if (rc < 0) {
+			pr_err("Failed GPIO bridge Reset\n");
+			gpio_free(GPIO_QRD3_LCD_BRDG_RESET_N);
+			return rc;
+		}
+
+		msleep(20);
+		gpio_set_value_cansleep(GPIO_QRD3_LCD_BRDG_RESET_N, 0);
+		msleep(20);
+		gpio_set_value_cansleep(GPIO_QRD3_LCD_BRDG_RESET_N, 1);
+		msleep(20);
+	} else {
+		gpio_tlmm_config(GPIO_CFG(GPIO_QRD3_LCD_BRDG_RESET_N, 0,
+			GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+			GPIO_CFG_DISABLE);
+	}
+
+		return rc;
+}
+
+static int mipi_dsi_panel_power(int on)
+{
+	int rc = 0;
+
+	if (machine_is_msm7627a_qrd1())
+		rc = mipi_dsi_panel_qrd1_power(on);
+	else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()
+						|| machine_is_msm8625_evt())
+		rc = mipi_dsi_panel_qrd3_power(on);
+	else
+		rc = mipi_dsi_panel_msm_power(on);
+	return rc;
+}
+
+#define MDP_303_VSYNC_GPIO 97
+
+#ifdef CONFIG_FB_MSM_MIPI_DSI
+static struct mipi_dsi_platform_data mipi_dsi_pdata = {
+	.vsync_gpio		= MDP_303_VSYNC_GPIO,
+	.dsi_power_save		= mipi_dsi_panel_power,
+	.dsi_client_reset       = msm_fb_dsi_client_reset,
+	.get_lane_config	= msm_fb_get_lane_config,
+};
+#endif
+
+static char prim_panel_name[PANEL_NAME_MAX_LEN];
+static int __init prim_display_setup(char *param)
+{
+	if (strnlen(param, PANEL_NAME_MAX_LEN))
+		strlcpy(prim_panel_name, param, PANEL_NAME_MAX_LEN);
+	return 0;
+}
+early_param("prim_display", prim_display_setup);
+
+void msm7x27a_set_display_params(char *prim_panel)
+{
+	if (strnlen(prim_panel, PANEL_NAME_MAX_LEN)) {
+		strlcpy(msm_fb_pdata.prim_panel_name, prim_panel,
+			PANEL_NAME_MAX_LEN);
+		pr_debug("msm_fb_pdata.prim_panel_name %s\n",
+			msm_fb_pdata.prim_panel_name);
+	}
+}
+
+void __init msm_fb_add_devices(void)
+{
+	msm7x27a_set_display_params(prim_panel_name);
+	if (machine_is_msm7627a_qrd1())
+		platform_add_devices(qrd_fb_devices,
+				ARRAY_SIZE(qrd_fb_devices));
+	else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()
+						|| machine_is_msm8625_evt()) {
+		mipi_NT35510_pdata.bl_lock = 1;
+		mipi_NT35516_pdata.bl_lock = 1;
+		platform_add_devices(evb_fb_devices,
+				ARRAY_SIZE(evb_fb_devices));
+	} else if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7()) {
+		sku3_lcdc_lcd_camera_power_init();
+		platform_add_devices(qrd3_fb_devices,
+						ARRAY_SIZE(qrd3_fb_devices));
+	} else
+		platform_add_devices(msm_fb_devices,
+				ARRAY_SIZE(msm_fb_devices));
+
+	msm_fb_register_device("mdp", &mdp_pdata);
+	if (machine_is_msm7625a_surf() || machine_is_msm7x27a_surf() ||
+			machine_is_msm8625_surf() || machine_is_msm7627a_qrd3()
+			|| machine_is_msm8625_qrd7())
+		msm_fb_register_device("lcdc", &lcdc_pdata);
+#ifdef CONFIG_FB_MSM_MIPI_DSI
+	msm_fb_register_device("mipi_dsi", &mipi_dsi_pdata);
+#endif
+}
diff --git a/arch/arm/mach-msm/board-msm7627a-io.c b/arch/arm/mach-msm/board-msm7627a-io.c
new file mode 100644
index 0000000..ec168f9
--- /dev/null
+++ b/arch/arm/mach-msm/board-msm7627a-io.c
@@ -0,0 +1,891 @@
+/* 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/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio_event.h>
+#include <linux/leds.h>
+#include <linux/i2c/atmel_mxt_ts.h>
+#include <linux/i2c.h>
+#include <linux/input/rmi_platformdata.h>
+#include <linux/input/rmi_i2c.h>
+#include <linux/delay.h>
+#include <linux/atmel_maxtouch.h>
+#include <linux/input/ft5x06_ts.h>
+#include <asm/gpio.h>
+#include <asm/mach-types.h>
+#include <mach/rpc_server_handset.h>
+#include <mach/pmic.h>
+
+#include "devices.h"
+#include "board-msm7627a.h"
+#include "devices-msm7x2xa.h"
+
+#define ATMEL_TS_I2C_NAME "maXTouch"
+#define ATMEL_X_OFFSET 13
+#define ATMEL_Y_OFFSET 0
+
+#if defined(CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C) || \
+defined(CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C_MODULE)
+
+#ifndef CLEARPAD3000_ATTEN_GPIO
+#define CLEARPAD3000_ATTEN_GPIO (48)
+#endif
+
+#ifndef CLEARPAD3000_RESET_GPIO
+#define CLEARPAD3000_RESET_GPIO (26)
+#endif
+
+#define KP_INDEX(row, col) ((row)*ARRAY_SIZE(kp_col_gpios) + (col))
+
+static unsigned int kp_row_gpios[] = {31, 32, 33, 34, 35};
+static unsigned int kp_col_gpios[] = {36, 37, 38, 39, 40};
+
+static const unsigned short keymap[ARRAY_SIZE(kp_col_gpios) *
+					  ARRAY_SIZE(kp_row_gpios)] = {
+	[KP_INDEX(0, 0)] = KEY_7,
+	[KP_INDEX(0, 1)] = KEY_DOWN,
+	[KP_INDEX(0, 2)] = KEY_UP,
+	[KP_INDEX(0, 3)] = KEY_RIGHT,
+	[KP_INDEX(0, 4)] = KEY_ENTER,
+
+	[KP_INDEX(1, 0)] = KEY_LEFT,
+	[KP_INDEX(1, 1)] = KEY_SEND,
+	[KP_INDEX(1, 2)] = KEY_1,
+	[KP_INDEX(1, 3)] = KEY_4,
+	[KP_INDEX(1, 4)] = KEY_CLEAR,
+
+	[KP_INDEX(2, 0)] = KEY_6,
+	[KP_INDEX(2, 1)] = KEY_5,
+	[KP_INDEX(2, 2)] = KEY_8,
+	[KP_INDEX(2, 3)] = KEY_3,
+	[KP_INDEX(2, 4)] = KEY_NUMERIC_STAR,
+
+	[KP_INDEX(3, 0)] = KEY_9,
+	[KP_INDEX(3, 1)] = KEY_NUMERIC_POUND,
+	[KP_INDEX(3, 2)] = KEY_0,
+	[KP_INDEX(3, 3)] = KEY_2,
+	[KP_INDEX(3, 4)] = KEY_SLEEP,
+
+	[KP_INDEX(4, 0)] = KEY_BACK,
+	[KP_INDEX(4, 1)] = KEY_HOME,
+	[KP_INDEX(4, 2)] = KEY_MENU,
+	[KP_INDEX(4, 3)] = KEY_VOLUMEUP,
+	[KP_INDEX(4, 4)] = KEY_VOLUMEDOWN,
+};
+
+/* SURF keypad platform device information */
+static struct gpio_event_matrix_info kp_matrix_info = {
+	.info.func	= gpio_event_matrix_func,
+	.keymap		= keymap,
+	.output_gpios	= kp_row_gpios,
+	.input_gpios	= kp_col_gpios,
+	.noutputs	= ARRAY_SIZE(kp_row_gpios),
+	.ninputs	= ARRAY_SIZE(kp_col_gpios),
+	.settle_time.tv64 = 40 * NSEC_PER_USEC,
+	.poll_time.tv64 = 20 * NSEC_PER_MSEC,
+	.flags		= GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE |
+			  GPIOKPF_PRINT_UNMAPPED_KEYS,
+};
+
+static struct gpio_event_info *kp_info[] = {
+	&kp_matrix_info.info
+};
+
+static struct gpio_event_platform_data kp_pdata = {
+	.name		= "7x27a_kp",
+	.info		= kp_info,
+	.info_count	= ARRAY_SIZE(kp_info)
+};
+
+static struct platform_device kp_pdev = {
+	.name	= GPIO_EVENT_DEV_NAME,
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &kp_pdata,
+	},
+};
+
+/* 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 const unsigned short keymap_8625_evt[] = {
+	KEY_VOLUMEDOWN,
+	KEY_VOLUMEUP,
+};
+
+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.tv64 = 40 * NSEC_PER_USEC,
+	.poll_time.tv64 = 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           = "7x27a_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_GPIO_PDM 96
+#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,
+	},
+};
+
+#define MXT_TS_IRQ_GPIO         48
+#define MXT_TS_RESET_GPIO       26
+#define MAX_VKEY_LEN		100
+
+static ssize_t mxt_virtual_keys_register(struct kobject *kobj,
+		struct kobj_attribute *attr, char *buf)
+{
+	char *virtual_keys = __stringify(EV_KEY) ":" __stringify(KEY_MENU) \
+		":60:840:120:80" ":" __stringify(EV_KEY) \
+		":" __stringify(KEY_HOME)   ":180:840:120:80" \
+		":" __stringify(EV_KEY) ":" \
+		__stringify(KEY_BACK) ":300:840:120:80" \
+		":" __stringify(EV_KEY) ":" \
+		__stringify(KEY_SEARCH)   ":420:840:120:80" "\n";
+
+	return snprintf(buf, strnlen(virtual_keys, MAX_VKEY_LEN) + 1 , "%s",
+			virtual_keys);
+}
+
+static struct kobj_attribute mxt_virtual_keys_attr = {
+	.attr = {
+		.name = "virtualkeys.atmel_mxt_ts",
+		.mode = S_IRUGO,
+	},
+	.show = &mxt_virtual_keys_register,
+};
+
+static struct attribute *mxt_virtual_key_properties_attrs[] = {
+	&mxt_virtual_keys_attr.attr,
+	NULL,
+};
+
+static struct attribute_group mxt_virtual_key_properties_attr_group = {
+	.attrs = mxt_virtual_key_properties_attrs,
+};
+
+struct kobject *mxt_virtual_key_properties_kobj;
+
+static int mxt_vkey_setup(void)
+{
+	int retval;
+
+	mxt_virtual_key_properties_kobj =
+		kobject_create_and_add("board_properties", NULL);
+	if (mxt_virtual_key_properties_kobj)
+		retval = sysfs_create_group(mxt_virtual_key_properties_kobj,
+				&mxt_virtual_key_properties_attr_group);
+	if (!mxt_virtual_key_properties_kobj || retval)
+		pr_err("failed to create mxt board_properties\n");
+
+	return retval;
+}
+
+static const u8 mxt_config_data[] = {
+	/* T6 Object */
+	0, 0, 0, 0, 0, 0,
+	/* T38 Object */
+	16, 1, 0, 0, 0, 0, 0, 0,
+	/* T7 Object */
+	32, 16, 50,
+	/* T8 Object */
+	30, 0, 20, 20, 0, 0, 20, 0, 50, 0,
+	/* T9 Object */
+	3, 0, 0, 18, 11, 0, 32, 75, 3, 3,
+	0, 1, 1, 0, 10, 10, 10, 10, 31, 3,
+	223, 1, 11, 11, 15, 15, 151, 43, 145, 80,
+	100, 15, 0, 0, 0,
+	/* T15 Object */
+	131, 0, 11, 11, 1, 1, 0, 45, 3, 0,
+	0,
+	/* T18 Object */
+	0, 0,
+	/* T19 Object */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0,
+	/* T23 Object */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0,
+	/* T25 Object */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0,
+	/* T40 Object */
+	0, 0, 0, 0, 0,
+	/* T42 Object */
+	0, 0, 0, 0, 0, 0, 0, 0,
+	/* T46 Object */
+	0, 2, 32, 48, 0, 0, 0, 0, 0,
+	/* T47 Object */
+	1, 20, 60, 5, 2, 50, 40, 0, 0, 40,
+	/* T48 Object */
+	1, 12, 80, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 6, 6, 0, 0, 100, 4, 64,
+	10, 0, 20, 5, 0, 38, 0, 20, 0, 0,
+	0, 0, 0, 0, 16, 65, 3, 1, 1, 0,
+	10, 10, 10, 0, 0, 15, 15, 154, 58, 145,
+	80, 100, 15, 3,
+};
+
+static const u8 mxt_config_data_evt[] = {
+	/* T6 Object */
+	0, 0, 0, 0, 0, 0,
+	/* T38 Object */
+	20, 0, 0, 0, 0, 0, 0, 0,
+	/* T7 Object */
+	24, 12, 10,
+	/* T8 Object */
+	30, 0, 20, 20, 0, 0, 9, 45, 10, 192,
+	/* T9 Object */
+	3, 0, 0, 18, 11, 0, 16, 60, 3, 1,
+	0, 1, 1, 0, 10, 10, 10, 10, 107, 3,
+	223, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+	20, 15, 0, 0, 2,
+	/* T15 Object */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0,
+	/* T18 Object */
+	0, 0,
+	/* T19 Object */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0,
+	/* T23 Object */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0,
+	/* T25 Object */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0,
+	/* T40 Object */
+	17, 0, 0, 30, 30,
+	/* T42 Object */
+	3, 20, 45, 40, 128, 0, 0, 0,
+	/* T46 Object */
+	0, 2, 16, 16, 0, 0, 0, 0, 0,
+	/* T47 Object */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	/* T48 Object */
+	1, 128, 96, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 6, 6, 0, 0, 63, 4, 64,
+	10, 0, 32, 5, 0, 38, 0, 8, 0, 0,
+	0, 0, 0, 0, 16, 65, 3, 1, 1, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0,
+};
+
+static struct mxt_config_info mxt_config_array[] = {
+	{
+		.config		= mxt_config_data,
+		.config_length	= ARRAY_SIZE(mxt_config_data),
+		.family_id	= 0x81,
+		.variant_id	= 0x01,
+		.version	= 0x10,
+		.build		= 0xAA,
+	},
+};
+
+static int mxt_key_codes[MXT_KEYARRAY_MAX_KEYS] = {
+	[0] = KEY_HOME,
+	[1] = KEY_MENU,
+	[9] = KEY_BACK,
+	[10] = KEY_SEARCH,
+};
+
+static struct mxt_platform_data mxt_platform_data = {
+	.config_array		= mxt_config_array,
+	.config_array_size	= ARRAY_SIZE(mxt_config_array),
+	.panel_minx		= 0,
+	.panel_maxx		= 479,
+	.panel_miny		= 0,
+	.panel_maxy		= 799,
+	.disp_minx		= 0,
+	.disp_maxx		= 479,
+	.disp_miny		= 0,
+	.disp_maxy		= 799,
+	.irqflags		= IRQF_TRIGGER_FALLING,
+	.i2c_pull_up		= true,
+	.reset_gpio		= MXT_TS_RESET_GPIO,
+	.irq_gpio		= MXT_TS_IRQ_GPIO,
+	.key_codes		= mxt_key_codes,
+};
+
+static struct i2c_board_info mxt_device_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("atmel_mxt_ts", 0x4a),
+		.platform_data = &mxt_platform_data,
+		.irq = MSM_GPIO_TO_INT(MXT_TS_IRQ_GPIO),
+	},
+};
+
+static int synaptics_touchpad_setup(void);
+
+static struct msm_gpio clearpad3000_cfg_data[] = {
+	{GPIO_CFG(CLEARPAD3000_ATTEN_GPIO, 0, GPIO_CFG_INPUT,
+			GPIO_CFG_NO_PULL, GPIO_CFG_6MA), "rmi4_attn"},
+	{GPIO_CFG(CLEARPAD3000_RESET_GPIO, 0, GPIO_CFG_OUTPUT,
+			GPIO_CFG_PULL_DOWN, GPIO_CFG_8MA), "rmi4_reset"},
+};
+
+static struct rmi_XY_pair rmi_offset = {.x = 0, .y = 0};
+static struct rmi_range rmi_clipx = {.min = 48, .max = 980};
+static struct rmi_range rmi_clipy = {.min = 7, .max = 1647};
+static struct rmi_f11_functiondata synaptics_f11_data = {
+	.swap_axes = false,
+	.flipX = false,
+	.flipY = false,
+	.offset = &rmi_offset,
+	.button_height = 113,
+	.clipX = &rmi_clipx,
+	.clipY = &rmi_clipy,
+};
+
+#define MAX_LEN		100
+
+static ssize_t clearpad3000_virtual_keys_register(struct kobject *kobj,
+		     struct kobj_attribute *attr, char *buf)
+{
+	char *virtual_keys = __stringify(EV_KEY) ":" __stringify(KEY_MENU) \
+			     ":60:830:120:60" ":" __stringify(EV_KEY) \
+			     ":" __stringify(KEY_HOME)   ":180:830:120:60" \
+				":" __stringify(EV_KEY) ":" \
+				__stringify(KEY_SEARCH) ":300:830:120:60" \
+				":" __stringify(EV_KEY) ":" \
+			__stringify(KEY_BACK)   ":420:830:120:60" "\n";
+
+	return snprintf(buf, strnlen(virtual_keys, MAX_LEN) + 1 , "%s",
+			virtual_keys);
+}
+
+static struct kobj_attribute clearpad3000_virtual_keys_attr = {
+	.attr = {
+		.name = "virtualkeys.sensor00fn11",
+		.mode = S_IRUGO,
+	},
+	.show = &clearpad3000_virtual_keys_register,
+};
+
+static struct attribute *virtual_key_properties_attrs[] = {
+	&clearpad3000_virtual_keys_attr.attr,
+	NULL
+};
+
+static struct attribute_group virtual_key_properties_attr_group = {
+	.attrs = virtual_key_properties_attrs,
+};
+
+struct kobject *virtual_key_properties_kobj;
+
+static struct rmi_functiondata synaptics_functiondata[] = {
+	{
+		.function_index = RMI_F11_INDEX,
+		.data = &synaptics_f11_data,
+	},
+};
+
+static struct rmi_functiondata_list synaptics_perfunctiondata = {
+	.count = ARRAY_SIZE(synaptics_functiondata),
+	.functiondata = synaptics_functiondata,
+};
+
+static struct rmi_sensordata synaptics_sensordata = {
+	.perfunctiondata = &synaptics_perfunctiondata,
+	.rmi_sensor_setup	= synaptics_touchpad_setup,
+};
+
+static struct rmi_i2c_platformdata synaptics_platformdata = {
+	.i2c_address = 0x2c,
+	.irq_type = IORESOURCE_IRQ_LOWLEVEL,
+	.sensordata = &synaptics_sensordata,
+};
+
+static struct i2c_board_info synaptic_i2c_clearpad3k[] = {
+	{
+	I2C_BOARD_INFO("rmi4_ts", 0x2c),
+	.platform_data = &synaptics_platformdata,
+	},
+};
+
+static int synaptics_touchpad_setup(void)
+{
+	int retval = 0;
+
+	virtual_key_properties_kobj =
+		kobject_create_and_add("board_properties", NULL);
+	if (virtual_key_properties_kobj)
+		retval = sysfs_create_group(virtual_key_properties_kobj,
+				&virtual_key_properties_attr_group);
+	if (!virtual_key_properties_kobj || retval)
+		pr_err("failed to create ft5202 board_properties\n");
+
+	retval = msm_gpios_request_enable(clearpad3000_cfg_data,
+		    sizeof(clearpad3000_cfg_data)/sizeof(struct msm_gpio));
+	if (retval) {
+		pr_err("%s:Failed to obtain touchpad GPIO %d. Code: %d.",
+				__func__, CLEARPAD3000_ATTEN_GPIO, retval);
+		retval = 0; /* ignore the err */
+	}
+	synaptics_platformdata.irq = gpio_to_irq(CLEARPAD3000_ATTEN_GPIO);
+
+	gpio_set_value(CLEARPAD3000_RESET_GPIO, 0);
+	usleep(10000);
+	gpio_set_value(CLEARPAD3000_RESET_GPIO, 1);
+	usleep(50000);
+
+	return retval;
+}
+#endif
+
+static struct regulator_bulk_data regs_atmel[] = {
+	{ .supply = "ldo12", .min_uV = 2700000, .max_uV = 3300000 },
+	{ .supply = "smps3", .min_uV = 1800000, .max_uV = 1800000 },
+};
+
+#define ATMEL_TS_GPIO_IRQ 82
+
+static int atmel_ts_power_on(bool on)
+{
+	int rc = on ?
+		regulator_bulk_enable(ARRAY_SIZE(regs_atmel), regs_atmel) :
+		regulator_bulk_disable(ARRAY_SIZE(regs_atmel), regs_atmel);
+
+	if (rc)
+		pr_err("%s: could not %sable regulators: %d\n",
+				__func__, on ? "en" : "dis", rc);
+	else
+		msleep(50);
+
+	return rc;
+}
+
+static int atmel_ts_platform_init(struct i2c_client *client)
+{
+	int rc;
+	struct device *dev = &client->dev;
+
+	rc = regulator_bulk_get(dev, ARRAY_SIZE(regs_atmel), regs_atmel);
+	if (rc) {
+		dev_err(dev, "%s: could not get regulators: %d\n",
+				__func__, rc);
+		goto out;
+	}
+
+	rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs_atmel), regs_atmel);
+	if (rc) {
+		dev_err(dev, "%s: could not set voltages: %d\n",
+				__func__, rc);
+		goto reg_free;
+	}
+
+	rc = gpio_tlmm_config(GPIO_CFG(ATMEL_TS_GPIO_IRQ, 0,
+				GPIO_CFG_INPUT, GPIO_CFG_PULL_UP,
+				GPIO_CFG_8MA), GPIO_CFG_ENABLE);
+	if (rc) {
+		dev_err(dev, "%s: gpio_tlmm_config for %d failed\n",
+			__func__, ATMEL_TS_GPIO_IRQ);
+		goto reg_free;
+	}
+
+	/* configure touchscreen interrupt gpio */
+	rc = gpio_request(ATMEL_TS_GPIO_IRQ, "atmel_maxtouch_gpio");
+	if (rc) {
+		dev_err(dev, "%s: unable to request gpio %d\n",
+			__func__, ATMEL_TS_GPIO_IRQ);
+		goto ts_gpio_tlmm_unconfig;
+	}
+
+	rc = gpio_direction_input(ATMEL_TS_GPIO_IRQ);
+	if (rc < 0) {
+		dev_err(dev, "%s: unable to set the direction of gpio %d\n",
+			__func__, ATMEL_TS_GPIO_IRQ);
+		goto free_ts_gpio;
+	}
+	return 0;
+
+free_ts_gpio:
+	gpio_free(ATMEL_TS_GPIO_IRQ);
+ts_gpio_tlmm_unconfig:
+	gpio_tlmm_config(GPIO_CFG(ATMEL_TS_GPIO_IRQ, 0,
+				GPIO_CFG_INPUT, GPIO_CFG_NO_PULL,
+				GPIO_CFG_2MA), GPIO_CFG_DISABLE);
+reg_free:
+	regulator_bulk_free(ARRAY_SIZE(regs_atmel), regs_atmel);
+out:
+	return rc;
+}
+
+static int atmel_ts_platform_exit(struct i2c_client *client)
+{
+	gpio_free(ATMEL_TS_GPIO_IRQ);
+	gpio_tlmm_config(GPIO_CFG(ATMEL_TS_GPIO_IRQ, 0,
+				GPIO_CFG_INPUT, GPIO_CFG_NO_PULL,
+				GPIO_CFG_2MA), GPIO_CFG_DISABLE);
+	regulator_bulk_free(ARRAY_SIZE(regs_atmel), regs_atmel);
+	return 0;
+}
+
+static u8 atmel_ts_read_chg(void)
+{
+	return gpio_get_value(ATMEL_TS_GPIO_IRQ);
+}
+
+static u8 atmel_ts_valid_interrupt(void)
+{
+	return !atmel_ts_read_chg();
+}
+
+
+static struct maxtouch_platform_data atmel_ts_pdata = {
+	.numtouch = 4,
+	.init_platform_hw = atmel_ts_platform_init,
+	.exit_platform_hw = atmel_ts_platform_exit,
+	.power_on = atmel_ts_power_on,
+	.display_res_x = 480,
+	.display_res_y = 864,
+	.min_x = ATMEL_X_OFFSET,
+	.max_x = (505 - ATMEL_X_OFFSET),
+	.min_y = ATMEL_Y_OFFSET,
+	.max_y = (863 - ATMEL_Y_OFFSET),
+	.valid_interrupt = atmel_ts_valid_interrupt,
+	.read_chg = atmel_ts_read_chg,
+};
+
+static struct i2c_board_info atmel_ts_i2c_info[] __initdata = {
+	{
+		I2C_BOARD_INFO(ATMEL_TS_I2C_NAME, 0x4a),
+		.platform_data = &atmel_ts_pdata,
+		.irq = MSM_GPIO_TO_INT(ATMEL_TS_GPIO_IRQ),
+	},
+};
+
+static struct msm_handset_platform_data hs_platform_data = {
+	.hs_name = "7k_handset",
+	.pwr_key_delay_ms = 500, /* 0 will disable end key */
+};
+
+static struct platform_device hs_pdev = {
+	.name   = "msm-handset",
+	.id     = -1,
+	.dev    = {
+		.platform_data = &hs_platform_data,
+	},
+};
+
+#define FT5X06_IRQ_GPIO		48
+#define FT5X06_RESET_GPIO	26
+
+static ssize_t
+ft5x06_virtual_keys_register(struct kobject *kobj,
+			     struct kobj_attribute *attr,
+			     char *buf)
+{
+	return snprintf(buf, 200,
+	__stringify(EV_KEY) ":" __stringify(KEY_MENU)  ":40:510:80:60"
+	":" __stringify(EV_KEY) ":" __stringify(KEY_HOME)   ":120:510:80:60"
+	":" __stringify(EV_KEY) ":" __stringify(KEY_SEARCH) ":200:510:80:60"
+	":" __stringify(EV_KEY) ":" __stringify(KEY_BACK)   ":280:510:80:60"
+	"\n");
+}
+
+static struct kobj_attribute ft5x06_virtual_keys_attr = {
+	.attr = {
+		.name = "virtualkeys.ft5x06_ts",
+		.mode = S_IRUGO,
+	},
+	.show = &ft5x06_virtual_keys_register,
+};
+
+static struct attribute *ft5x06_virtual_key_properties_attrs[] = {
+	&ft5x06_virtual_keys_attr.attr,
+	NULL,
+};
+
+static struct attribute_group ft5x06_virtual_key_properties_attr_group = {
+	.attrs = ft5x06_virtual_key_properties_attrs,
+};
+
+struct kobject *ft5x06_virtual_key_properties_kobj;
+
+static struct ft5x06_ts_platform_data ft5x06_platformdata = {
+	.x_max		= 320,
+	.y_max		= 480,
+	.reset_gpio	= FT5X06_RESET_GPIO,
+	.irq_gpio	= FT5X06_IRQ_GPIO,
+	.irqflags	= IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+};
+
+static struct i2c_board_info ft5x06_device_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("ft5x06_ts", 0x38),
+		.platform_data = &ft5x06_platformdata,
+		.irq = MSM_GPIO_TO_INT(FT5X06_IRQ_GPIO),
+	},
+};
+
+static void __init ft5x06_touchpad_setup(void)
+{
+	int rc;
+
+	rc = gpio_tlmm_config(GPIO_CFG(FT5X06_IRQ_GPIO, 0,
+			GPIO_CFG_INPUT, GPIO_CFG_PULL_UP,
+			GPIO_CFG_8MA), GPIO_CFG_ENABLE);
+	if (rc)
+		pr_err("%s: gpio_tlmm_config for %d failed\n",
+			__func__, FT5X06_IRQ_GPIO);
+
+	rc = gpio_tlmm_config(GPIO_CFG(FT5X06_RESET_GPIO, 0,
+			GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN,
+			GPIO_CFG_8MA), GPIO_CFG_ENABLE);
+	if (rc)
+		pr_err("%s: gpio_tlmm_config for %d failed\n",
+			__func__, FT5X06_RESET_GPIO);
+
+	ft5x06_virtual_key_properties_kobj =
+			kobject_create_and_add("board_properties", NULL);
+
+	if (ft5x06_virtual_key_properties_kobj)
+		rc = sysfs_create_group(ft5x06_virtual_key_properties_kobj,
+				&ft5x06_virtual_key_properties_attr_group);
+
+	if (!ft5x06_virtual_key_properties_kobj || rc)
+		pr_err("%s: failed to create board_properties\n", __func__);
+
+	i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
+				ft5x06_device_info,
+				ARRAY_SIZE(ft5x06_device_info));
+}
+
+/* SKU3/SKU7 keypad device information */
+#define KP_INDEX_SKU3(row, col) ((row)*ARRAY_SIZE(kp_col_gpios_sku3) + (col))
+static unsigned int kp_row_gpios_sku3[] = {31, 32};
+static unsigned int kp_col_gpios_sku3[] = {36, 37};
+
+static const unsigned short keymap_sku3[] = {
+	[KP_INDEX_SKU3(0, 0)] = KEY_VOLUMEUP,
+	[KP_INDEX_SKU3(0, 1)] = KEY_VOLUMEDOWN,
+	[KP_INDEX_SKU3(1, 1)] = KEY_CAMERA,
+};
+
+static struct gpio_event_matrix_info kp_matrix_info_sku3 = {
+	.info.func      = gpio_event_matrix_func,
+	.keymap         = keymap_sku3,
+	.output_gpios   = kp_row_gpios_sku3,
+	.input_gpios    = kp_col_gpios_sku3,
+	.noutputs       = ARRAY_SIZE(kp_row_gpios_sku3),
+	.ninputs        = ARRAY_SIZE(kp_col_gpios_sku3),
+	.settle_time.tv64 = 40 * NSEC_PER_USEC,
+	.poll_time.tv64 = 20 * NSEC_PER_MSEC,
+	.flags          = GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE |
+				GPIOKPF_PRINT_UNMAPPED_KEYS,
+};
+
+static struct gpio_event_info *kp_info_sku3[] = {
+	&kp_matrix_info_sku3.info,
+};
+static struct gpio_event_platform_data kp_pdata_sku3 = {
+	.name           = "7x27a_kp",
+	.info           = kp_info_sku3,
+	.info_count     = ARRAY_SIZE(kp_info_sku3)
+};
+
+static struct platform_device kp_pdev_sku3 = {
+	.name   = GPIO_EVENT_DEV_NAME,
+	.id     = -1,
+	.dev    = {
+		.platform_data  = &kp_pdata_sku3,
+	},
+};
+
+static struct led_info ctp_backlight_info = {
+	.name           = "button-backlight",
+	.flags          = PM_MPP__I_SINK__LEVEL_40mA << 16 | PM_MPP_7,
+};
+
+static struct led_platform_data ctp_backlight_pdata = {
+	.leds = &ctp_backlight_info,
+	.num_leds = 1,
+};
+
+static struct platform_device pmic_mpp_leds_pdev = {
+	.name   = "pmic-mpp-leds",
+	.id     = -1,
+	.dev    = {
+		.platform_data  = &ctp_backlight_pdata,
+	},
+};
+
+void __init msm7627a_add_io_devices(void)
+{
+	/* touchscreen */
+	if (machine_is_msm7625a_surf() || machine_is_msm7625a_ffa()) {
+		atmel_ts_pdata.min_x = 0;
+		atmel_ts_pdata.max_x = 480;
+		atmel_ts_pdata.min_y = 0;
+		atmel_ts_pdata.max_y = 320;
+	}
+
+	i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
+				atmel_ts_i2c_info,
+				ARRAY_SIZE(atmel_ts_i2c_info));
+	/* keypad */
+	platform_device_register(&kp_pdev);
+
+	/* headset */
+	platform_device_register(&hs_pdev);
+
+	/* LED: configure it as a pdm function */
+	if (gpio_tlmm_config(GPIO_CFG(LED_GPIO_PDM, 3,
+				GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
+				GPIO_CFG_8MA), GPIO_CFG_ENABLE))
+		pr_err("%s: gpio_tlmm_config for %d failed\n",
+			__func__, LED_GPIO_PDM);
+	else
+		platform_device_register(&led_pdev);
+
+	/* Vibrator */
+	if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa()
+					|| machine_is_msm8625_ffa())
+		msm_init_pmic_vibrator();
+}
+
+void __init qrd7627a_add_io_devices(void)
+{
+	int rc;
+
+	/* touchscreen */
+	if (machine_is_msm7627a_qrd1()) {
+		i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
+					synaptic_i2c_clearpad3k,
+					ARRAY_SIZE(synaptic_i2c_clearpad3k));
+	} else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb() ||
+			machine_is_msm8625_evt()) {
+		/* Use configuration data for EVT */
+		if (machine_is_msm8625_evt()) {
+			mxt_config_array[0].config = mxt_config_data_evt;
+			mxt_config_array[0].config_length =
+					ARRAY_SIZE(mxt_config_data_evt);
+			mxt_platform_data.panel_maxy = 875;
+			mxt_vkey_setup();
+		}
+
+		rc = gpio_tlmm_config(GPIO_CFG(MXT_TS_IRQ_GPIO, 0,
+				GPIO_CFG_INPUT, GPIO_CFG_PULL_UP,
+				GPIO_CFG_8MA), GPIO_CFG_ENABLE);
+		if (rc) {
+			pr_err("%s: gpio_tlmm_config for %d failed\n",
+				__func__, MXT_TS_IRQ_GPIO);
+		}
+
+		rc = gpio_tlmm_config(GPIO_CFG(MXT_TS_RESET_GPIO, 0,
+				GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN,
+				GPIO_CFG_8MA), GPIO_CFG_ENABLE);
+		if (rc) {
+			pr_err("%s: gpio_tlmm_config for %d failed\n",
+				__func__, MXT_TS_RESET_GPIO);
+		}
+
+		i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
+					mxt_device_info,
+					ARRAY_SIZE(mxt_device_info));
+	} else if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7()) {
+		ft5x06_touchpad_setup();
+	}
+
+	/* headset */
+	platform_device_register(&hs_pdev);
+
+	/* vibrator */
+#ifdef CONFIG_MSM_RPC_VIBRATOR
+	msm_init_pmic_vibrator();
+#endif
+
+	/* keypad */
+	if (machine_is_msm8625_evt())
+		kp_matrix_info_8625.keymap = keymap_8625_evt;
+
+	if (machine_is_msm7627a_evb() || machine_is_msm8625_evb() ||
+			machine_is_msm8625_evt())
+		platform_device_register(&kp_pdev_8625);
+	else if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7())
+		platform_device_register(&kp_pdev_sku3);
+
+	/* leds */
+	if (machine_is_msm7627a_evb() || machine_is_msm8625_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);
+		platform_device_register(&pmic_mpp_leds_pdev);
+	}
+}
diff --git a/arch/arm/mach-msm/board-msm7627a-storage.c b/arch/arm/mach-msm/board-msm7627a-storage.c
new file mode 100644
index 0000000..e2184f4
--- /dev/null
+++ b/arch/arm/mach-msm/board-msm7627a-storage.c
@@ -0,0 +1,412 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
+#include <asm/mach-types.h>
+#include <asm/mach/mmc.h>
+#include <mach/gpiomux.h>
+#include <mach/board.h>
+#include "devices.h"
+#include "pm.h"
+#include "board-msm7627a.h"
+
+#if (defined(CONFIG_MMC_MSM_SDC1_SUPPORT)\
+	|| defined(CONFIG_MMC_MSM_SDC2_SUPPORT)\
+	|| defined(CONFIG_MMC_MSM_SDC3_SUPPORT)\
+	|| defined(CONFIG_MMC_MSM_SDC4_SUPPORT))
+
+#define MAX_SDCC_CONTROLLER 4
+static unsigned long vreg_sts, gpio_sts;
+
+struct sdcc_gpio {
+	struct msm_gpio *cfg_data;
+	uint32_t size;
+	struct msm_gpio *sleep_cfg_data;
+};
+
+/**
+ * Due to insufficient drive strengths for SDC GPIO lines some old versioned
+ * SD/MMC cards may cause data CRC errors. Hence, set optimal values
+ * for SDC slots based on timing closure and marginality. SDC1 slot
+ * require higher value since it should handle bad signal quality due
+ * to size of T-flash adapters.
+ */
+static struct msm_gpio sdc1_cfg_data[] = {
+	{GPIO_CFG(51, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_14MA),
+								"sdc1_dat_3"},
+	{GPIO_CFG(52, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_14MA),
+								"sdc1_dat_2"},
+	{GPIO_CFG(53, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_14MA),
+								"sdc1_dat_1"},
+	{GPIO_CFG(54, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_14MA),
+								"sdc1_dat_0"},
+	{GPIO_CFG(55, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_14MA),
+								"sdc1_cmd"},
+	{GPIO_CFG(56, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_14MA),
+								"sdc1_clk"},
+};
+
+static struct msm_gpio sdc2_cfg_data[] = {
+	{GPIO_CFG(62, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
+								"sdc2_clk"},
+	{GPIO_CFG(63, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc2_cmd"},
+	{GPIO_CFG(64, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc2_dat_3"},
+	{GPIO_CFG(65, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc2_dat_2"},
+	{GPIO_CFG(66, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc2_dat_1"},
+	{GPIO_CFG(67, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc2_dat_0"},
+};
+
+static struct msm_gpio sdc2_sleep_cfg_data[] = {
+	{GPIO_CFG(62, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+								"sdc2_clk"},
+	{GPIO_CFG(63, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_UP, GPIO_CFG_2MA),
+								"sdc2_cmd"},
+	{GPIO_CFG(64, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_UP, GPIO_CFG_2MA),
+								"sdc2_dat_3"},
+	{GPIO_CFG(65, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_UP, GPIO_CFG_2MA),
+								"sdc2_dat_2"},
+	{GPIO_CFG(66, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_UP, GPIO_CFG_2MA),
+								"sdc2_dat_1"},
+	{GPIO_CFG(67, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_UP, GPIO_CFG_2MA),
+								"sdc2_dat_0"},
+};
+static struct msm_gpio sdc3_cfg_data[] = {
+	{GPIO_CFG(88, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
+								"sdc3_clk"},
+	{GPIO_CFG(89, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc3_cmd"},
+	{GPIO_CFG(90, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc3_dat_3"},
+	{GPIO_CFG(91, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc3_dat_2"},
+	{GPIO_CFG(92, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc3_dat_1"},
+	{GPIO_CFG(93, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc3_dat_0"},
+#ifdef CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT
+	{GPIO_CFG(19, 3, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc3_dat_7"},
+	{GPIO_CFG(20, 3, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc3_dat_6"},
+	{GPIO_CFG(21, 3, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc3_dat_5"},
+	{GPIO_CFG(108, 3, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc3_dat_4"},
+#endif
+};
+
+static struct msm_gpio sdc4_cfg_data[] = {
+	{GPIO_CFG(19, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc4_dat_3"},
+	{GPIO_CFG(20, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc4_dat_2"},
+	{GPIO_CFG(21, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc4_dat_1"},
+	{GPIO_CFG(107, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc4_cmd"},
+	{GPIO_CFG(108, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
+								"sdc4_dat_0"},
+	{GPIO_CFG(109, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
+								"sdc4_clk"},
+};
+
+static struct sdcc_gpio sdcc_cfg_data[] = {
+	{
+		.cfg_data = sdc1_cfg_data,
+		.size = ARRAY_SIZE(sdc1_cfg_data),
+	},
+	{
+		.cfg_data = sdc2_cfg_data,
+		.size = ARRAY_SIZE(sdc2_cfg_data),
+		.sleep_cfg_data = sdc2_sleep_cfg_data,
+	},
+	{
+		.cfg_data = sdc3_cfg_data,
+		.size = ARRAY_SIZE(sdc3_cfg_data),
+	},
+	{
+		.cfg_data = sdc4_cfg_data,
+		.size = ARRAY_SIZE(sdc4_cfg_data),
+	},
+};
+
+static int gpio_sdc1_hw_det = 85;
+static void gpio_sdc1_config(void)
+{
+	if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()
+					|| machine_is_msm8625_evb()
+					|| machine_is_msm7627a_qrd3()
+					|| machine_is_msm8625_qrd7())
+		gpio_sdc1_hw_det = 42;
+}
+
+static struct regulator *sdcc_vreg_data[MAX_SDCC_CONTROLLER];
+static int msm_sdcc_setup_gpio(int dev_id, unsigned int enable)
+{
+	int rc = 0;
+	struct sdcc_gpio *curr;
+
+	curr = &sdcc_cfg_data[dev_id - 1];
+	if (!(test_bit(dev_id, &gpio_sts)^enable))
+		return rc;
+
+	if (enable) {
+		set_bit(dev_id, &gpio_sts);
+		rc = msm_gpios_request_enable(curr->cfg_data, curr->size);
+		if (rc)
+			pr_err("%s: Failed to turn on GPIOs for slot %d\n",
+					__func__,  dev_id);
+	} else {
+		clear_bit(dev_id, &gpio_sts);
+		if (curr->sleep_cfg_data) {
+			rc = msm_gpios_enable(curr->sleep_cfg_data, curr->size);
+			msm_gpios_free(curr->sleep_cfg_data, curr->size);
+			return rc;
+		}
+		msm_gpios_disable_free(curr->cfg_data, curr->size);
+	}
+	return rc;
+}
+
+static int msm_sdcc_setup_vreg(int dev_id, unsigned int enable)
+{
+	int rc = 0;
+	struct regulator *curr = sdcc_vreg_data[dev_id - 1];
+
+	if (test_bit(dev_id, &vreg_sts) == enable)
+		return 0;
+
+	if (!curr)
+		return -ENODEV;
+
+	if (IS_ERR(curr))
+		return PTR_ERR(curr);
+
+	if (enable) {
+		set_bit(dev_id, &vreg_sts);
+
+		rc = regulator_enable(curr);
+		if (rc)
+			pr_err("%s: could not enable regulator: %d\n",
+						__func__, rc);
+	} else {
+		clear_bit(dev_id, &vreg_sts);
+
+		rc = regulator_disable(curr);
+		if (rc)
+			pr_err("%s: could not disable regulator: %d\n",
+						__func__, rc);
+	}
+	return rc;
+}
+
+static uint32_t msm_sdcc_setup_power(struct device *dv, unsigned int vdd)
+{
+	int rc = 0;
+	struct platform_device *pdev;
+
+	pdev = container_of(dv, struct platform_device, dev);
+
+	rc = msm_sdcc_setup_gpio(pdev->id, !!vdd);
+	if (rc)
+		goto out;
+
+	rc = msm_sdcc_setup_vreg(pdev->id, !!vdd);
+out:
+	return rc;
+}
+
+#if defined(CONFIG_MMC_MSM_SDC1_SUPPORT) \
+	&& defined(CONFIG_MMC_MSM_CARD_HW_DETECTION)
+static unsigned int msm7627a_sdcc_slot_status(struct device *dev)
+{
+	int status;
+
+	status = gpio_tlmm_config(GPIO_CFG(gpio_sdc1_hw_det, 2, GPIO_CFG_INPUT,
+				GPIO_CFG_PULL_UP, GPIO_CFG_8MA),
+				GPIO_CFG_ENABLE);
+	if (status)
+		pr_err("%s:Failed to configure tlmm for GPIO %d\n", __func__,
+				gpio_sdc1_hw_det);
+
+	status = gpio_request(gpio_sdc1_hw_det, "SD_HW_Detect");
+	if (status) {
+		pr_err("%s:Failed to request GPIO %d\n", __func__,
+				gpio_sdc1_hw_det);
+	} else {
+		status = gpio_direction_input(gpio_sdc1_hw_det);
+		if (!status) {
+			if (machine_is_msm7627a_qrd1() ||
+					machine_is_msm7627a_evb() ||
+					machine_is_msm8625_evb()  ||
+					machine_is_msm7627a_qrd3() ||
+					machine_is_msm8625_qrd7())
+				status = !gpio_get_value(gpio_sdc1_hw_det);
+			else
+				status = gpio_get_value(gpio_sdc1_hw_det);
+		}
+		gpio_free(gpio_sdc1_hw_det);
+	}
+	return status;
+}
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+static struct mmc_platform_data sdc1_plat_data = {
+	.ocr_mask       = MMC_VDD_28_29,
+	.translate_vdd  = msm_sdcc_setup_power,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.msmsdcc_fmin   = 144000,
+	.msmsdcc_fmid   = 24576000,
+	.msmsdcc_fmax   = 49152000,
+#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
+	.status      = msm7627a_sdcc_slot_status,
+	.irq_flags   = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+#endif
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+static struct mmc_platform_data sdc2_plat_data = {
+	/*
+	 * SDC2 supports only 1.8V, claim for 2.85V range is just
+	 * for allowing buggy cards who advertise 2.8V even though
+	 * they can operate at 1.8V supply.
+	 */
+	.ocr_mask       = MMC_VDD_28_29 | MMC_VDD_165_195,
+	.translate_vdd  = msm_sdcc_setup_power,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.sdiowakeup_irq = MSM_GPIO_TO_INT(66),
+	.msmsdcc_fmin   = 144000,
+	.msmsdcc_fmid   = 24576000,
+	.msmsdcc_fmax   = 49152000,
+#ifdef CONFIG_MMC_MSM_SDC2_DUMMY52_REQUIRED
+	.dummy52_required = 1,
+#endif
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+static struct mmc_platform_data sdc3_plat_data = {
+	.ocr_mask       = MMC_VDD_28_29,
+	.translate_vdd  = msm_sdcc_setup_power,
+#ifdef CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT
+	.mmc_bus_width  = MMC_CAP_8_BIT_DATA,
+#else
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+#endif
+	.msmsdcc_fmin   = 144000,
+	.msmsdcc_fmid   = 24576000,
+	.msmsdcc_fmax   = 49152000,
+	.nonremovable   = 1,
+};
+#endif
+
+#if (defined(CONFIG_MMC_MSM_SDC4_SUPPORT)\
+		&& !defined(CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT))
+static struct mmc_platform_data sdc4_plat_data = {
+	.ocr_mask       = MMC_VDD_28_29,
+	.translate_vdd  = msm_sdcc_setup_power,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.msmsdcc_fmin   = 144000,
+	.msmsdcc_fmid   = 24576000,
+	.msmsdcc_fmax   = 49152000,
+};
+#endif
+
+static int __init mmc_regulator_init(int sdcc_no, const char *supply, int uV)
+{
+	int rc;
+
+	BUG_ON(sdcc_no < 1 || sdcc_no > 4);
+
+	sdcc_no--;
+
+	sdcc_vreg_data[sdcc_no] = regulator_get(NULL, supply);
+
+	if (IS_ERR(sdcc_vreg_data[sdcc_no])) {
+		rc = PTR_ERR(sdcc_vreg_data[sdcc_no]);
+		pr_err("%s: could not get regulator \"%s\": %d\n",
+				__func__, supply, rc);
+		goto out;
+	}
+
+	rc = regulator_set_voltage(sdcc_vreg_data[sdcc_no], uV, uV);
+
+	if (rc) {
+		pr_err("%s: could not set voltage for \"%s\" to %d uV: %d\n",
+				__func__, supply, uV, rc);
+		goto reg_free;
+	}
+
+	return rc;
+
+reg_free:
+	regulator_put(sdcc_vreg_data[sdcc_no]);
+out:
+	sdcc_vreg_data[sdcc_no] = NULL;
+	return rc;
+}
+
+void __init msm7627a_init_mmc(void)
+{
+	/* eMMC slot */
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+
+	/* There is no eMMC on SDC3 for QRD3 based devices */
+	if (!(machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7())) {
+		if (mmc_regulator_init(3, "emmc", 3000000))
+			return;
+		msm_add_sdcc(3, &sdc3_plat_data);
+	}
+#endif
+	/* Micro-SD slot */
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+	gpio_sdc1_config();
+	if (mmc_regulator_init(1, "mmc", 2850000))
+		return;
+#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
+	/* 8x25 EVT do not use hw detector */
+	if (!(machine_is_msm8625_evt()))
+		sdc1_plat_data.status_irq = MSM_GPIO_TO_INT(gpio_sdc1_hw_det);
+	if (machine_is_msm8625_evt())
+		sdc1_plat_data.status = NULL;
+#endif
+
+	msm_add_sdcc(1, &sdc1_plat_data);
+#endif
+	/* SDIO WLAN slot */
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+	if (mmc_regulator_init(2, "smps3", 1800000))
+		return;
+	msm_add_sdcc(2, &sdc2_plat_data);
+#endif
+	/* Not Used */
+#if (defined(CONFIG_MMC_MSM_SDC4_SUPPORT)\
+		&& !defined(CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT))
+	/* There is no SDC4 for QRD3/7 based devices */
+	if (!(machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7())) {
+		if (mmc_regulator_init(4, "smps3", 1800000))
+			return;
+		msm_add_sdcc(4, &sdc4_plat_data);
+	}
+#endif
+}
+#endif
diff --git a/arch/arm/mach-msm/board-msm7627a-wlan.c b/arch/arm/mach-msm/board-msm7627a-wlan.c
new file mode 100644
index 0000000..07b7ab0
--- /dev/null
+++ b/arch/arm/mach-msm/board-msm7627a-wlan.c
@@ -0,0 +1,385 @@
+/* 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/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <asm/mach-types.h>
+#include <mach/rpc_pmapp.h>
+#include "board-msm7627a.h"
+#include "devices-msm7x2xa.h"
+#include "timer.h"
+
+#define GPIO_WLAN_3V3_EN 119
+static const char *id = "WLAN";
+
+enum {
+	WLAN_VREG_S3 = 0,
+	WLAN_VREG_L17,
+	WLAN_VREG_L19
+};
+
+struct wlan_vreg_info {
+	const char *vreg_id;
+	unsigned int level_min;
+	unsigned int level_max;
+	unsigned int pmapp_id;
+	unsigned int is_vreg_pin_controlled;
+	struct regulator *reg;
+};
+
+static struct wlan_vreg_info vreg_info[] = {
+	{"msme1",     1800000, 1800000, 2,  0, NULL},
+	{"bt",        3300000, 3300000, 21, 1, NULL},
+	{"wlan4",     1800000, 1800000, 23, 1, NULL}
+};
+
+int gpio_wlan_sys_rest_en = 134;
+static void gpio_wlan_config(void)
+{
+	if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()
+					|| machine_is_msm8625_evb()
+					|| machine_is_msm8625_evt()
+					|| machine_is_msm7627a_qrd3()
+					|| machine_is_msm8625_qrd7())
+		gpio_wlan_sys_rest_en = 124;
+}
+
+static unsigned int qrf6285_init_regs(void)
+{
+	struct regulator_bulk_data regs[ARRAY_SIZE(vreg_info)];
+	int i = 0, rc = 0;
+
+	for (i = 0; i < ARRAY_SIZE(regs); i++) {
+		regs[i].supply = vreg_info[i].vreg_id;
+		regs[i].min_uV = vreg_info[i].level_min;
+		regs[i].max_uV = vreg_info[i].level_max;
+	}
+
+	rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs), regs);
+	if (rc) {
+		pr_err("%s: could not get regulators: %d\n", __func__, rc);
+		goto out;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(regs); i++)
+		vreg_info[i].reg = regs[i].consumer;
+
+out:
+	return rc;
+}
+
+static unsigned int setup_wlan_gpio(bool on)
+{
+	int rc = 0;
+
+	if (on) {
+		rc = gpio_direction_output(gpio_wlan_sys_rest_en, 1);
+		msleep(100);
+	} else {
+		gpio_set_value_cansleep(gpio_wlan_sys_rest_en, 0);
+		rc = gpio_direction_input(gpio_wlan_sys_rest_en);
+		msleep(100);
+	}
+
+	if (rc)
+		pr_err("%s: WLAN sys_reset_en GPIO: Error", __func__);
+
+	return rc;
+}
+
+static unsigned int setup_wlan_clock(bool on)
+{
+	int rc = 0;
+
+	if (on) {
+		/* Vote for A0 clock */
+		rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_A0,
+					PMAPP_CLOCK_VOTE_ON);
+	} else {
+		/* Vote against A0 clock */
+		rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_A0,
+					 PMAPP_CLOCK_VOTE_OFF);
+	}
+
+	if (rc)
+		pr_err("%s: Configuring A0 clock for WLAN: Error", __func__);
+
+	return rc;
+}
+
+static unsigned int wlan_switch_regulators(int on)
+{
+	int rc = 0, index = 0;
+
+	if (machine_is_msm7627a_qrd1())
+		index = 2;
+
+	for ( ; index < ARRAY_SIZE(vreg_info); index++) {
+		if (on) {
+			rc = regulator_set_voltage(vreg_info[index].reg,
+						vreg_info[index].level_min,
+						vreg_info[index].level_max);
+			if (rc) {
+				pr_err("%s:%s set voltage failed %d\n",
+					__func__, vreg_info[index].vreg_id, rc);
+				goto reg_disable;
+			}
+
+			rc = regulator_enable(vreg_info[index].reg);
+			if (rc) {
+				pr_err("%s:%s vreg enable failed %d\n",
+					__func__, vreg_info[index].vreg_id, rc);
+				goto reg_disable;
+			}
+
+			if (vreg_info[index].is_vreg_pin_controlled) {
+				rc = pmapp_vreg_lpm_pincntrl_vote(id,
+						vreg_info[index].pmapp_id,
+						PMAPP_CLOCK_ID_A0, 1);
+				if (rc) {
+					pr_err("%s:%s pincntrl failed %d\n",
+						__func__,
+						vreg_info[index].vreg_id, rc);
+					goto pin_cnt_fail;
+				}
+			}
+		} else {
+			if (vreg_info[index].is_vreg_pin_controlled) {
+				rc = pmapp_vreg_lpm_pincntrl_vote(id,
+						vreg_info[index].pmapp_id,
+						PMAPP_CLOCK_ID_A0, 0);
+				if (rc) {
+					pr_err("%s:%s pincntrl failed %d\n",
+						__func__,
+						vreg_info[index].vreg_id, rc);
+					goto pin_cnt_fail;
+				}
+			}
+
+			rc = regulator_disable(vreg_info[index].reg);
+			if (rc) {
+				pr_err("%s:%s vreg disable failed %d\n",
+					__func__,
+					vreg_info[index].vreg_id, rc);
+				goto reg_disable;
+			}
+		}
+	}
+	return 0;
+pin_cnt_fail:
+	if (on)
+		regulator_disable(vreg_info[index].reg);
+reg_disable:
+	if (!machine_is_msm7627a_qrd1()) {
+		while (index) {
+			if (on) {
+				index--;
+				regulator_disable(vreg_info[index].reg);
+				regulator_put(vreg_info[index].reg);
+			}
+		}
+	}
+	return rc;
+}
+
+static unsigned int msm_AR600X_setup_power(bool on)
+{
+	int rc = 0;
+	static bool init_done;
+
+	if (unlikely(!init_done)) {
+		gpio_wlan_config();
+		rc = qrf6285_init_regs();
+		if (rc) {
+			pr_err("%s: qrf6285 init failed = %d\n", __func__, rc);
+			return rc;
+		} else {
+			init_done = true;
+		}
+	}
+
+	rc = wlan_switch_regulators(on);
+	if (rc) {
+		pr_err("%s: wlan_switch_regulators error = %d\n", __func__, rc);
+		goto out;
+	}
+
+	/* GPIO_WLAN_3V3_EN is only required for the QRD7627a */
+	if (machine_is_msm7627a_qrd1()) {
+		rc = gpio_tlmm_config(GPIO_CFG(GPIO_WLAN_3V3_EN, 0,
+					GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
+					GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+		if (rc) {
+			pr_err("%s gpio_tlmm_config 119 failed,error = %d\n",
+				__func__, rc);
+			goto reg_disable;
+		}
+		gpio_set_value(GPIO_WLAN_3V3_EN, 1);
+	}
+
+	/*
+	 * gpio_wlan_sys_rest_en is not from the GPIO expander for QRD7627a,
+	 * EVB1.0 and QRD8625,so the below step is required for those devices.
+	 */
+	if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()
+					|| machine_is_msm8625_evb()
+					|| machine_is_msm8625_evt()
+					|| machine_is_msm7627a_qrd3()
+					|| machine_is_msm8625_qrd7()) {
+		rc = gpio_tlmm_config(GPIO_CFG(gpio_wlan_sys_rest_en, 0,
+					GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
+					GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+		if (rc) {
+			pr_err("%s gpio_tlmm_config 119 failed,error = %d\n",
+				__func__, rc);
+			goto qrd_gpio_fail;
+		}
+		gpio_set_value(gpio_wlan_sys_rest_en, 1);
+	} else {
+		rc = gpio_request(gpio_wlan_sys_rest_en, "WLAN_DEEP_SLEEP_N");
+		if (rc) {
+			pr_err("%s: WLAN sys_rest_en GPIO %d request failed %d\n",
+				__func__,
+				gpio_wlan_sys_rest_en, rc);
+			goto qrd_gpio_fail;
+		}
+		rc = setup_wlan_gpio(on);
+		if (rc) {
+			pr_err("%s: wlan_set_gpio = %d\n", __func__, rc);
+			goto gpio_fail;
+		}
+	}
+
+	/* Enable the A0 clock */
+	rc = setup_wlan_clock(on);
+	if (rc) {
+		pr_err("%s: setup_wlan_clock = %d\n", __func__, rc);
+		goto set_gpio_fail;
+	}
+
+	/* Configure A0 clock to be slave to WLAN_CLK_PWR_REQ */
+	rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_A0,
+				 PMAPP_CLOCK_VOTE_PIN_CTRL);
+	if (rc) {
+		pr_err("%s: Configuring A0 to Pin controllable failed %d\n",
+				__func__, rc);
+		goto set_clock_fail;
+	}
+
+	pr_info("WLAN power-up success\n");
+	return 0;
+set_clock_fail:
+	setup_wlan_clock(0);
+set_gpio_fail:
+	setup_wlan_gpio(0);
+gpio_fail:
+	gpio_free(gpio_wlan_sys_rest_en);
+qrd_gpio_fail:
+	/* GPIO_WLAN_3V3_EN is only required for the QRD7627a */
+	if (machine_is_msm7627a_qrd1())
+		gpio_free(GPIO_WLAN_3V3_EN);
+reg_disable:
+	wlan_switch_regulators(0);
+out:
+	pr_info("WLAN power-up failed\n");
+	return rc;
+}
+
+static unsigned int msm_AR600X_shutdown_power(bool on)
+{
+	int rc = 0;
+
+	/* Disable the A0 clock */
+	rc = setup_wlan_clock(on);
+	if (rc) {
+		pr_err("%s: setup_wlan_clock = %d\n", __func__, rc);
+		goto set_clock_fail;
+	}
+
+	/*
+	 * gpio_wlan_sys_rest_en is not from the GPIO expander for QRD7627a,
+	 * EVB1.0 and QRD8625,so the below step is required for those devices.
+	 */
+	if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()
+					|| machine_is_msm8625_evb()
+					|| machine_is_msm8625_evt()
+					|| machine_is_msm7627a_qrd3()
+					|| machine_is_msm8625_qrd7()) {
+		rc = gpio_tlmm_config(GPIO_CFG(gpio_wlan_sys_rest_en, 0,
+					GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
+					GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+		if (rc) {
+			pr_err("%s gpio_tlmm_config 119 failed,error = %d\n",
+				__func__, rc);
+			goto gpio_fail;
+		}
+		gpio_set_value(gpio_wlan_sys_rest_en, 0);
+	} else {
+		gpio_request(gpio_wlan_sys_rest_en, "WLAN_DEEP_SLEEP_N");
+		rc = setup_wlan_gpio(on);
+		if (rc) {
+			pr_err("%s: wlan_set_gpio = %d\n", __func__, rc);
+			goto set_gpio_fail;
+		}
+		gpio_free(gpio_wlan_sys_rest_en);
+	}
+
+	/* GPIO_WLAN_3V3_EN is only required for the QRD7627a */
+	if (machine_is_msm7627a_qrd1()) {
+		rc = gpio_tlmm_config(GPIO_CFG(GPIO_WLAN_3V3_EN, 0,
+					GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
+					GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+		if (rc) {
+			pr_err("%s gpio_tlmm_config 119 failed,error = %d\n",
+				__func__, rc);
+			goto qrd_gpio_fail;
+		}
+		gpio_set_value(GPIO_WLAN_3V3_EN, 0);
+	}
+
+	rc = wlan_switch_regulators(on);
+	if (rc) {
+		pr_err("%s: wlan_switch_regulators error = %d\n",
+			__func__, rc);
+		goto reg_disable;
+	}
+
+	pr_info("WLAN power-down success\n");
+	return 0;
+set_clock_fail:
+	setup_wlan_clock(0);
+set_gpio_fail:
+	setup_wlan_gpio(0);
+gpio_fail:
+	gpio_free(gpio_wlan_sys_rest_en);
+qrd_gpio_fail:
+	/* GPIO_WLAN_3V3_EN is only required for the QRD7627a */
+	if (machine_is_msm7627a_qrd1())
+		gpio_free(GPIO_WLAN_3V3_EN);
+reg_disable:
+	wlan_switch_regulators(0);
+	pr_info("WLAN power-down failed\n");
+	return rc;
+}
+
+int  ar600x_wlan_power(bool on)
+{
+	if (on)
+		msm_AR600X_setup_power(on);
+	else
+		msm_AR600X_shutdown_power(on);
+
+	return 0;
+}
diff --git a/arch/arm/mach-msm/board-msm7627a.h b/arch/arm/mach-msm/board-msm7627a.h
new file mode 100644
index 0000000..4357e01
--- /dev/null
+++ b/arch/arm/mach-msm/board-msm7627a.h
@@ -0,0 +1,110 @@
+/* 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
+ * 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 __ARCH_ARM_MACH_MSM_BOARD_7627A__
+#define __ARCH_ARM_MACH_MSM_BOARD_7627A__
+
+#include "pm.h"
+void __init msm7627a_init_mmc(void);
+
+void __init msm_msm7627a_allocate_memory_regions(void);
+void __init msm_fb_add_devices(void);
+
+enum {
+	GPIO_EXPANDER_IRQ_BASE  = NR_MSM_IRQS + NR_GPIO_IRQS,
+	GPIO_EXPANDER_GPIO_BASE = NR_MSM_GPIOS,
+	/* SURF expander */
+	GPIO_CORE_EXPANDER_BASE = GPIO_EXPANDER_GPIO_BASE,
+	GPIO_BT_SYS_REST_EN     = GPIO_CORE_EXPANDER_BASE,
+	GPIO_WLAN_EXT_POR_N,
+	GPIO_DISPLAY_PWR_EN,
+	GPIO_BACKLIGHT_EN,
+	GPIO_PRESSURE_XCLR,
+	GPIO_VREG_S3_EXP,
+	GPIO_UBM2M_PWRDWN,
+	GPIO_ETM_MODE_CS_N,
+	GPIO_HOST_VBUS_EN,
+	GPIO_SPI_MOSI,
+	GPIO_SPI_MISO,
+	GPIO_SPI_CLK,
+	GPIO_SPI_CS0_N,
+	GPIO_CORE_EXPANDER_IO13,
+	GPIO_CORE_EXPANDER_IO14,
+	GPIO_CORE_EXPANDER_IO15,
+	/* Camera expander */
+	GPIO_CAM_EXPANDER_BASE  = GPIO_CORE_EXPANDER_BASE + 16,
+	GPIO_CAM_GP_STROBE_READY	= GPIO_CAM_EXPANDER_BASE,
+	GPIO_CAM_GP_AFBUSY,
+	GPIO_CAM_GP_CAM_PWDN,
+	GPIO_CAM_GP_CAM1MP_XCLR,
+	GPIO_CAM_GP_CAMIF_RESET_N,
+	GPIO_CAM_GP_STROBE_CE,
+	GPIO_CAM_GP_LED_EN1,
+	GPIO_CAM_GP_LED_EN2,
+};
+
+enum {
+	QRD_GPIO_HOST_VBUS_EN       = 107,
+	QRD_GPIO_BT_SYS_REST_EN     = 114,
+	QRD_GPIO_WAKE_ON_WIRELESS,
+	QRD_GPIO_BACKLIGHT_EN,
+	QRD_GPIO_NC,
+	QRD_GPIO_CAM_3MP_PWDN,      /* CAM_VGA */
+	QRD_GPIO_WLAN_EN,
+	QRD_GPIO_CAM_5MP_SHDN_EN,
+	QRD_GPIO_CAM_5MP_RESET,
+	QRD_GPIO_TP,
+	QRD_GPIO_CAM_GP_CAMIF_RESET,
+};
+
+#define ADSP_RPC_PROG           0x3000000a
+#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
+
+#define FPGA_MSM_CNTRL_REG2 0x90008010
+#define BAHAMA_SLAVE_ID_FM_REG 0x02
+#define BAHAMA_SLAVE_ID_FM_ADDR  0x2A
+#define BAHAMA_SLAVE_ID_QMEMBIST_ADDR   0x7B
+#define FM_GPIO 83
+#define BT_PCM_BCLK_MODE  0x88
+#define BT_PCM_DIN_MODE   0x89
+#define BT_PCM_DOUT_MODE  0x8A
+#define BT_PCM_SYNC_MODE  0x8B
+#define FM_I2S_SD_MODE    0x8E
+#define FM_I2S_WS_MODE    0x8F
+#define FM_I2S_SCK_MODE   0x90
+#define I2C_PIN_CTL       0x15
+#define I2C_NORMAL	  0x40
+
+struct bahama_config_register {
+	u8 reg;
+	u8 value;
+	u8 mask;
+};
+
+struct bt_vreg_info {
+	const char *name;
+	unsigned int pmapp_id;
+	unsigned int min_level;
+	unsigned int max_level;
+	unsigned int is_pin_controlled;
+	struct regulator *reg;
+};
+
+void __init msm7627a_bt_power_init(void);
+#endif
+
+void __init msm7627a_camera_init(void);
+int lcd_camera_power_onoff(int on);
+
+void __init msm7627a_add_io_devices(void);
+void __init qrd7627a_add_io_devices(void);
+#endif
diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c
index 6d84ee7..d42458f 100644
--- a/arch/arm/mach-msm/board-msm7x27.c
+++ b/arch/arm/mach-msm/board-msm7x27.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -13,15 +13,17 @@
  * GNU General Public License for more details.
  *
  */
-#include <linux/gpio.h>
 #include <linux/kernel.h>
+#include <linux/gpio.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/input.h>
 #include <linux/io.h>
 #include <linux/delay.h>
+#include <linux/bootmem.h>
 #include <linux/power_supply.h>
 
+#include <mach/msm_memtypes.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -32,17 +34,64 @@
 #include <asm/hardware/cache-l2x0.h>
 #endif
 
+#include <asm/mach/mmc.h>
 #include <mach/vreg.h>
 #include <mach/mpp.h>
 #include <mach/board.h>
+#include <mach/pmic.h>
 #include <mach/msm_iomap.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/msm_hsusb.h>
+#include <mach/rpc_hsusb.h>
+#include <mach/rpc_pmapp.h>
+#include <mach/msm_serial_hs.h>
+#include <mach/memory.h>
+#include <mach/msm_battery.h>
+#include <mach/rpc_server_handset.h>
+#include <mach/msm_tsif.h>
+#include <mach/socinfo.h>
 
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
+#include <linux/i2c.h>
+#include <linux/android_pmem.h>
+#include <mach/camera.h>
 
+#ifdef CONFIG_USB_G_ANDROID
+#include <linux/usb/android.h>
+#include <mach/usbdiag.h>
+#endif
+
+#include "board-msm7627-regulator.h"
 #include "devices.h"
-#include "socinfo.h"
 #include "clock.h"
+#include "acpuclock.h"
+#include "msm-keypad-devices.h"
+#include "pm.h"
+#include "pm-boot.h"
+
+#ifdef CONFIG_ARCH_MSM7X25
+#define MSM_PMEM_MDP_SIZE	0xb21000
+#define MSM_PMEM_ADSP_SIZE	0x97b000
+#define MSM_PMEM_AUDIO_SIZE	0x121000
+#define MSM_FB_SIZE		0x200000
+#define PMEM_KERNEL_EBI1_SIZE	0x64000
+#endif
+
+#ifdef CONFIG_ARCH_MSM7X27
+#define MSM_PMEM_MDP_SIZE	0x1B76000
+#define MSM_PMEM_ADSP_SIZE	0xC8A000
+#define MSM_PMEM_AUDIO_SIZE	0x5B000
+
+#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
+#define MSM_FB_SIZE		0x233000
+#else
+#define MSM_FB_SIZE		0x177000
+#endif
+
+#define PMEM_KERNEL_EBI1_SIZE	0x1C000
+#endif
+#define ADSP_RPC_PROG           0x3000000a
 
 static struct resource smc91x_resources[] = {
 	[0] = {
@@ -64,14 +113,1226 @@
 	.resource	= smc91x_resources,
 };
 
+#ifdef CONFIG_USB_G_ANDROID
+static struct android_usb_platform_data android_usb_pdata = {
+	.update_pid_and_serial_num = usb_diag_update_pid_and_serial_num,
+};
+
+static struct platform_device android_usb_device = {
+	.name	= "android_usb",
+	.id		= -1,
+	.dev		= {
+		.platform_data = &android_usb_pdata,
+	},
+};
+#endif
+
+#ifdef CONFIG_USB_EHCI_MSM_72K
+static void msm_hsusb_vbus_power(unsigned phy_info, int on)
+{
+	if (on)
+		msm_hsusb_vbus_powerup();
+	else
+		msm_hsusb_vbus_shutdown();
+}
+
+static struct msm_usb_host_platform_data msm_usb_host_pdata = {
+	.phy_info       = (USB_PHY_INTEGRATED | USB_PHY_MODEL_65NM),
+};
+
+static void __init msm7x2x_init_host(void)
+{
+	if (machine_is_msm7x25_ffa() || machine_is_msm7x27_ffa())
+		return;
+
+	msm_add_host(0, &msm_usb_host_pdata);
+}
+#endif
+
+#ifdef CONFIG_USB_MSM_OTG_72K
+static int hsusb_rpc_connect(int connect)
+{
+	if (connect)
+		return msm_hsusb_rpc_connect();
+	else
+		return msm_hsusb_rpc_close();
+}
+#endif
+
+#ifdef CONFIG_USB_MSM_OTG_72K
+static int msm_hsusb_ldo_init(int init)
+{
+	static struct regulator *reg_hsusb;
+	int rc;
+	if (init) {
+		reg_hsusb = regulator_get(NULL, "usb");
+		if (IS_ERR(reg_hsusb)) {
+			rc = PTR_ERR(reg_hsusb);
+			pr_err("%s: could not get regulator: %d\n",
+					__func__, rc);
+			goto out;
+		}
+
+		rc = regulator_set_voltage(reg_hsusb, 3300000, 3300000);
+		if (rc < 0) {
+			pr_err("%s: could not set voltage: %d\n",
+					 __func__, rc);
+			goto usb_reg_fail;
+		}
+
+		rc = regulator_enable(reg_hsusb);
+		if (rc < 0) {
+			pr_err("%s: could not enable regulator: %d\n",
+					__func__, rc);
+			goto usb_reg_fail;
+		}
+
+		/*
+		 * PHY 3.3V analog domain(VDDA33) is powered up by
+		 * an always enabled power supply (LP5900TL-3.3).
+		 * USB VREG default source is VBUS line. Turning
+		 * on USB VREG has a side effect on the USB suspend
+		 * current. Hence USB VREG is explicitly turned
+		 * off here.
+		 */
+
+		rc = regulator_disable(reg_hsusb);
+		if (rc < 0) {
+			pr_err("%s: could not disable regulator: %d\n",
+					__func__, rc);
+			goto usb_reg_fail;
+		}
+
+		regulator_put(reg_hsusb);
+	}
+
+	return 0;
+usb_reg_fail:
+	regulator_put(reg_hsusb);
+out:
+	return rc;
+}
+
+static int msm_hsusb_pmic_notif_init(void (*callback)(int online), int init)
+{
+	int ret;
+
+	if (init) {
+		ret = msm_pm_app_rpc_init(callback);
+	} else {
+		msm_pm_app_rpc_deinit(callback);
+		ret = 0;
+	}
+	return ret;
+}
+
+static int msm_otg_rpc_phy_reset(void __iomem *regs)
+{
+	return msm_hsusb_phy_reset();
+}
+
+static struct msm_otg_platform_data msm_otg_pdata = {
+	.rpc_connect	= hsusb_rpc_connect,
+	.pmic_vbus_notif_init         = msm_hsusb_pmic_notif_init,
+	.chg_vbus_draw		 = hsusb_chg_vbus_draw,
+	.chg_connected		 = hsusb_chg_connected,
+	.chg_init		 = hsusb_chg_init,
+#ifdef CONFIG_USB_EHCI_MSM_72K
+	.vbus_power = msm_hsusb_vbus_power,
+#endif
+	.ldo_init		= msm_hsusb_ldo_init,
+	.pclk_required_during_lpm = 1,
+};
+
+#ifdef CONFIG_USB_GADGET
+static struct msm_hsusb_gadget_platform_data msm_gadget_pdata;
+#endif
+#endif
+
+#define SND(desc, num) { .name = #desc, .id = num }
+static struct snd_endpoint snd_endpoints_list[] = {
+	SND(HANDSET, 0),
+	SND(MONO_HEADSET, 2),
+	SND(HEADSET, 3),
+	SND(SPEAKER, 6),
+	SND(TTY_HEADSET, 8),
+	SND(TTY_VCO, 9),
+	SND(TTY_HCO, 10),
+	SND(BT, 12),
+	SND(IN_S_SADC_OUT_HANDSET, 16),
+	SND(IN_S_SADC_OUT_SPEAKER_PHONE, 25),
+	SND(CURRENT, 27),
+};
+#undef SND
+
+static struct msm_snd_endpoints msm_device_snd_endpoints = {
+	.endpoints = snd_endpoints_list,
+	.num = sizeof(snd_endpoints_list) / sizeof(struct snd_endpoint)
+};
+
+static struct platform_device msm_device_snd = {
+	.name = "msm_snd",
+	.id = -1,
+	.dev    = {
+		.platform_data = &msm_device_snd_endpoints
+	},
+};
+
+#define DEC0_FORMAT ((1<<MSM_ADSP_CODEC_MP3)| \
+	(1<<MSM_ADSP_CODEC_AAC)|(1<<MSM_ADSP_CODEC_WMA)| \
+	(1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \
+	(1<<MSM_ADSP_CODEC_AMRNB)|(1<<MSM_ADSP_CODEC_WAV)| \
+	(1<<MSM_ADSP_CODEC_ADPCM)|(1<<MSM_ADSP_CODEC_YADPCM)| \
+	(1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP))
+#ifdef CONFIG_ARCH_MSM7X25
+#define DEC1_FORMAT ((1<<MSM_ADSP_CODEC_WAV)|(1<<MSM_ADSP_CODEC_ADPCM)| \
+	(1<<MSM_ADSP_CODEC_YADPCM)|(1<<MSM_ADSP_CODEC_QCELP)| \
+	(1<<MSM_ADSP_CODEC_MP3))
+#define DEC2_FORMAT ((1<<MSM_ADSP_CODEC_WAV)|(1<<MSM_ADSP_CODEC_ADPCM)| \
+	(1<<MSM_ADSP_CODEC_YADPCM)|(1<<MSM_ADSP_CODEC_QCELP)| \
+	(1<<MSM_ADSP_CODEC_MP3))
+#define DEC3_FORMAT 0
+#define DEC4_FORMAT 0
+#else
+#define DEC1_FORMAT ((1<<MSM_ADSP_CODEC_MP3)| \
+	(1<<MSM_ADSP_CODEC_AAC)|(1<<MSM_ADSP_CODEC_WMA)| \
+	(1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \
+	(1<<MSM_ADSP_CODEC_AMRNB)|(1<<MSM_ADSP_CODEC_WAV)| \
+	(1<<MSM_ADSP_CODEC_ADPCM)|(1<<MSM_ADSP_CODEC_YADPCM)| \
+	(1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP))
+#define DEC2_FORMAT ((1<<MSM_ADSP_CODEC_MP3)| \
+	(1<<MSM_ADSP_CODEC_AAC)|(1<<MSM_ADSP_CODEC_WMA)| \
+	(1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \
+	(1<<MSM_ADSP_CODEC_AMRNB)|(1<<MSM_ADSP_CODEC_WAV)| \
+	(1<<MSM_ADSP_CODEC_ADPCM)|(1<<MSM_ADSP_CODEC_YADPCM)| \
+	(1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP))
+#define DEC3_FORMAT ((1<<MSM_ADSP_CODEC_MP3)| \
+	(1<<MSM_ADSP_CODEC_AAC)|(1<<MSM_ADSP_CODEC_WMA)| \
+	(1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \
+	(1<<MSM_ADSP_CODEC_AMRNB)|(1<<MSM_ADSP_CODEC_WAV)| \
+	(1<<MSM_ADSP_CODEC_ADPCM)|(1<<MSM_ADSP_CODEC_YADPCM)| \
+	(1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP))
+#define DEC4_FORMAT (1<<MSM_ADSP_CODEC_MIDI)
+#endif
+
+static unsigned int dec_concurrency_table[] = {
+	/* Audio LP */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DMA)), 0,
+	0, 0, 0,
+
+	/* Concurrency 1 */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC4_FORMAT),
+
+	 /* Concurrency 2 */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC4_FORMAT),
+
+	/* Concurrency 3 */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC4_FORMAT),
+
+	/* Concurrency 4 */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC4_FORMAT),
+
+	/* Concurrency 5 */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC4_FORMAT),
+
+	/* Concurrency 6 */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	0, 0, 0, 0,
+
+	/* Concurrency 7 */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC4_FORMAT),
+};
+
+#define DEC_INFO(name, queueid, decid, nr_codec) { .module_name = name, \
+	.module_queueid = queueid, .module_decid = decid, \
+	.nr_codec_support = nr_codec}
+
+static struct msm_adspdec_info dec_info_list[] = {
+	DEC_INFO("AUDPLAY0TASK", 13, 0, 11), /* AudPlay0BitStreamCtrlQueue */
+#ifdef CONFIG_ARCH_MSM7X25
+	DEC_INFO("AUDPLAY1TASK", 14, 1, 5),  /* AudPlay1BitStreamCtrlQueue */
+	DEC_INFO("AUDPLAY2TASK", 15, 2, 5),  /* AudPlay2BitStreamCtrlQueue */
+	DEC_INFO("AUDPLAY3TASK", 16, 3, 0),  /* AudPlay3BitStreamCtrlQueue */
+	DEC_INFO("AUDPLAY4TASK", 17, 4, 0),  /* AudPlay4BitStreamCtrlQueue */
+#else
+	DEC_INFO("AUDPLAY1TASK", 14, 1, 11),  /* AudPlay1BitStreamCtrlQueue */
+	DEC_INFO("AUDPLAY2TASK", 15, 2, 11),  /* AudPlay2BitStreamCtrlQueue */
+	DEC_INFO("AUDPLAY3TASK", 16, 3, 11),  /* AudPlay3BitStreamCtrlQueue */
+	DEC_INFO("AUDPLAY4TASK", 17, 4, 1),  /* AudPlay4BitStreamCtrlQueue */
+#endif
+};
+
+static struct msm_adspdec_database msm_device_adspdec_database = {
+	.num_dec = ARRAY_SIZE(dec_info_list),
+	.num_concurrency_support = (ARRAY_SIZE(dec_concurrency_table) / \
+					ARRAY_SIZE(dec_info_list)),
+	.dec_concurrency_table = dec_concurrency_table,
+	.dec_info_list = dec_info_list,
+};
+
+static struct platform_device msm_device_adspdec = {
+	.name = "msm_adspdec",
+	.id = -1,
+	.dev    = {
+		.platform_data = &msm_device_adspdec_database
+	},
+};
+
+static struct android_pmem_platform_data android_pmem_pdata = {
+	.name = "pmem",
+	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
+	.cached = 1,
+	.memory_type = MEMTYPE_EBI1,
+};
+
+static struct android_pmem_platform_data android_pmem_adsp_pdata = {
+	.name = "pmem_adsp",
+	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
+	.cached = 0,
+	.memory_type = MEMTYPE_EBI1,
+};
+
+static struct android_pmem_platform_data android_pmem_audio_pdata = {
+	.name = "pmem_audio",
+	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
+	.cached = 0,
+	.memory_type = MEMTYPE_EBI1,
+};
+
+static struct platform_device android_pmem_device = {
+	.name = "android_pmem",
+	.id = 0,
+	.dev = { .platform_data = &android_pmem_pdata },
+};
+
+static struct platform_device android_pmem_adsp_device = {
+	.name = "android_pmem",
+	.id = 1,
+	.dev = { .platform_data = &android_pmem_adsp_pdata },
+};
+
+static struct platform_device android_pmem_audio_device = {
+	.name = "android_pmem",
+	.id = 2,
+	.dev = { .platform_data = &android_pmem_audio_pdata },
+};
+
+static struct msm_handset_platform_data hs_platform_data = {
+	.hs_name = "7k_handset",
+	.pwr_key_delay_ms = 500, /* 0 will disable end key */
+};
+
+static struct platform_device hs_device = {
+	.name   = "msm-handset",
+	.id     = -1,
+	.dev    = {
+		.platform_data = &hs_platform_data,
+	},
+};
+
+/* TSIF begin */
+#if defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE)
+
+#define TSIF_B_SYNC      GPIO_CFG(87, 5, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_B_DATA      GPIO_CFG(86, 3, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_B_EN        GPIO_CFG(85, 3, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_B_CLK       GPIO_CFG(84, 4, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+
+static const struct msm_gpio tsif_gpios[] = {
+	{ .gpio_cfg = TSIF_B_CLK,  .label =  "tsif_clk", },
+	{ .gpio_cfg = TSIF_B_EN,   .label =  "tsif_en", },
+	{ .gpio_cfg = TSIF_B_DATA, .label =  "tsif_data", },
+	{ .gpio_cfg = TSIF_B_SYNC, .label =  "tsif_sync", },
+};
+
+static struct msm_tsif_platform_data tsif_platform_data = {
+	.num_gpios = ARRAY_SIZE(tsif_gpios),
+	.gpios = tsif_gpios,
+	.tsif_clk = "core_clk",
+	.tsif_pclk = "iface_clk",
+	.tsif_ref_clk = "ref_clk",
+};
+#endif /* defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE) */
+/* TSIF end   */
+
+#define LCDC_CONFIG_PROC          21
+#define LCDC_UN_CONFIG_PROC       22
+#define LCDC_API_PROG             0x30000066
+#define LCDC_API_VERS             0x00010001
+
+#define GPIO_OUT_132    132
+#define GPIO_OUT_131    131
+#define GPIO_OUT_103    103
+#define GPIO_OUT_102    102
+#define GPIO_OUT_88     88
+
+static struct msm_rpc_endpoint *lcdc_ep;
+
+static int msm_fb_lcdc_config(int on)
+{
+	int rc = 0;
+	struct rpc_request_hdr hdr;
+
+	if (on)
+		pr_info("lcdc config\n");
+	else
+		pr_info("lcdc un-config\n");
+
+	lcdc_ep = msm_rpc_connect_compatible(LCDC_API_PROG, LCDC_API_VERS, 0);
+	if (IS_ERR(lcdc_ep)) {
+		printk(KERN_ERR "%s: msm_rpc_connect failed! rc = %ld\n",
+			__func__, PTR_ERR(lcdc_ep));
+		return -EINVAL;
+	}
+
+	rc = msm_rpc_call(lcdc_ep,
+				(on) ? LCDC_CONFIG_PROC : LCDC_UN_CONFIG_PROC,
+				&hdr, sizeof(hdr),
+				5 * HZ);
+	if (rc)
+		printk(KERN_ERR
+			"%s: msm_rpc_call failed! rc = %d\n", __func__, rc);
+
+	msm_rpc_close(lcdc_ep);
+	return rc;
+}
+
+static int gpio_array_num[] = {
+				GPIO_OUT_132, /* spi_clk */
+				GPIO_OUT_131, /* spi_cs  */
+				GPIO_OUT_103, /* spi_sdi */
+				GPIO_OUT_102, /* spi_sdoi */
+				GPIO_OUT_88
+				};
+
+static void lcdc_gordon_gpio_init(void)
+{
+	if (gpio_request(GPIO_OUT_132, "spi_clk"))
+		pr_err("failed to request gpio spi_clk\n");
+	if (gpio_request(GPIO_OUT_131, "spi_cs"))
+		pr_err("failed to request gpio spi_cs\n");
+	if (gpio_request(GPIO_OUT_103, "spi_sdi"))
+		pr_err("failed to request gpio spi_sdi\n");
+	if (gpio_request(GPIO_OUT_102, "spi_sdoi"))
+		pr_err("failed to request gpio spi_sdoi\n");
+	if (gpio_request(GPIO_OUT_88, "gpio_dac"))
+		pr_err("failed to request gpio_dac\n");
+}
+
+static uint32_t lcdc_gpio_table[] = {
+	GPIO_CFG(GPIO_OUT_132, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	GPIO_CFG(GPIO_OUT_131, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	GPIO_CFG(GPIO_OUT_103, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	GPIO_CFG(GPIO_OUT_102, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	GPIO_CFG(GPIO_OUT_88,  0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+};
+
+static void config_lcdc_gpio_table(uint32_t *table, int len, unsigned enable)
+{
+	int n, rc;
+	for (n = 0; n < len; n++) {
+		rc = gpio_tlmm_config(table[n],
+			enable ? GPIO_CFG_ENABLE : GPIO_CFG_DISABLE);
+		if (rc) {
+			printk(KERN_ERR "%s: gpio_tlmm_config(%#x)=%d\n",
+				__func__, table[n], rc);
+			break;
+		}
+	}
+}
+
+static void lcdc_gordon_config_gpios(int enable)
+{
+	config_lcdc_gpio_table(lcdc_gpio_table,
+		ARRAY_SIZE(lcdc_gpio_table), enable);
+}
+
+static char *msm_fb_lcdc_vreg[] = {
+	"gp5"
+};
+
+static int msm_fb_lcdc_power_save(int on)
+{
+	int i, rc = 0;
+	static struct regulator *vreg[ARRAY_SIZE(msm_fb_lcdc_vreg)];
+
+	if (on) {
+		for (i = 0; i < ARRAY_SIZE(msm_fb_lcdc_vreg); i++) {
+			vreg[i] = regulator_get(NULL, msm_fb_lcdc_vreg[i]);
+			if (IS_ERR(vreg[i])) {
+				rc = PTR_ERR(vreg[i]);
+				pr_err("%s: could get not regulator: %d\n",
+						__func__, rc);
+				goto reg_get_fail;
+			}
+
+			rc = regulator_set_voltage(vreg[i], 2850000, 3000000);
+			if (rc < 0) {
+				pr_err("%s: could not set voltage: %d\n",
+						__func__, rc);
+				goto reg_get_fail;
+			}
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(msm_fb_lcdc_vreg); i++) {
+		if (on) {
+			rc = regulator_enable(vreg[i]);
+			if (rc) {
+				pr_err("%s: could not enable regulator %s:"
+					"%d\n", __func__,
+						msm_fb_lcdc_vreg[i], rc);
+				goto vreg_lcdc_fail;
+			}
+		} else {
+			rc = regulator_disable(vreg[i]);
+			if (rc) {
+				pr_err("%s: could not disable regulator %s:"
+					"%d\n", __func__,
+					 msm_fb_lcdc_vreg[i], rc);
+
+				regulator_put(vreg[i]);
+				goto vreg_lcdc_fail;
+
+			}
+
+			regulator_put(vreg[i]);
+			rc = gpio_tlmm_config(GPIO_CFG(GPIO_OUT_88, 0,
+						GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
+						GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+			if (rc)
+				printk(KERN_ERR "gpio_tlmm_config failed\n");
+
+			gpio_set_value(88, 0);
+			mdelay(15);
+			gpio_set_value(88, 1);
+			mdelay(15);
+		}
+	}
+
+	return rc;
+
+reg_get_fail:
+	for (; i > 0; i--)
+		regulator_put(vreg[i - 1]);
+	return rc;
+
+vreg_lcdc_fail:
+	if (on) {
+		for (; i > 0; i--)
+			regulator_disable(vreg[i - 1]);
+	} else {
+		for (; i > 0; i--)
+			regulator_enable(vreg[i - 1]);
+	}
+
+	return rc;
+}
+
+static struct lcdc_platform_data lcdc_pdata = {
+	.lcdc_gpio_config = msm_fb_lcdc_config,
+	.lcdc_power_save   = msm_fb_lcdc_power_save,
+};
+
+static struct msm_panel_common_pdata lcdc_gordon_panel_data = {
+	.panel_config_gpio = lcdc_gordon_config_gpios,
+	.gpio_num          = gpio_array_num,
+};
+
+static struct platform_device lcdc_gordon_panel_device = {
+	.name   = "lcdc_gordon_vga",
+	.id     = 0,
+	.dev    = {
+		.platform_data = &lcdc_gordon_panel_data,
+	}
+};
+
+static struct resource msm_fb_resources[] = {
+	{
+		.flags  = IORESOURCE_DMA,
+	}
+};
+
+static int msm_fb_detect_panel(const char *name)
+{
+	int ret = -EPERM;
+
+	if (machine_is_msm7x25_ffa() || machine_is_msm7x27_ffa()) {
+		if (!strcmp(name, "lcdc_gordon_vga"))
+			ret = 0;
+		else
+			ret = -ENODEV;
+	}
+
+	return ret;
+}
+
+static struct msm_fb_platform_data msm_fb_pdata = {
+	.detect_client = msm_fb_detect_panel,
+	.mddi_prescan = 1,
+};
+
+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,
+	}
+};
+
+#ifdef CONFIG_BT
+static struct platform_device msm_bt_power_device = {
+	.name = "bt_power",
+};
+
+enum {
+	BT_WAKE,
+	BT_RFR,
+	BT_CTS,
+	BT_RX,
+	BT_TX,
+	BT_PCM_DOUT,
+	BT_PCM_DIN,
+	BT_PCM_SYNC,
+	BT_PCM_CLK,
+	BT_HOST_WAKE,
+};
+
+static unsigned bt_config_power_on[] = {
+	GPIO_CFG(42, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),	/* WAKE */
+	GPIO_CFG(43, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),	/* RFR */
+	GPIO_CFG(44, 2, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA),	/* CTS */
+	GPIO_CFG(45, 2, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA),	/* Rx */
+	GPIO_CFG(46, 3, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),	/* Tx */
+	GPIO_CFG(68, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),	/* PCM_DOUT */
+	GPIO_CFG(69, 1, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA),	/* PCM_DIN */
+	GPIO_CFG(70, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),	/* PCM_SYNC */
+	GPIO_CFG(71, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),	/* PCM_CLK */
+	GPIO_CFG(83, 0, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA),	/* HOST_WAKE */
+};
+static unsigned bt_config_power_off[] = {
+	GPIO_CFG(42, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),	/* WAKE */
+	GPIO_CFG(43, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),	/* RFR */
+	GPIO_CFG(44, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),	/* CTS */
+	GPIO_CFG(45, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),	/* Rx */
+	GPIO_CFG(46, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),	/* Tx */
+	GPIO_CFG(68, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),	/* PCM_DOUT */
+	GPIO_CFG(69, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),	/* PCM_DIN */
+	GPIO_CFG(70, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),	/* PCM_SYNC */
+	GPIO_CFG(71, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),	/* PCM_CLK */
+	GPIO_CFG(83, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),	/* HOST_WAKE */
+};
+
+static int bluetooth_power(int on)
+{
+	int pin, rc;
+	static struct regulator *vreg_bt;
+
+	printk(KERN_DEBUG "%s\n", __func__);
+
+	/* do not have vreg bt defined, gp6 is the same */
+	/* vreg_get parameter 1 (struct device *) is ignored */
+
+	if (on) {
+		for (pin = 0; pin < ARRAY_SIZE(bt_config_power_on); pin++) {
+			rc = gpio_tlmm_config(bt_config_power_on[pin],
+					      GPIO_CFG_ENABLE);
+			if (rc) {
+				printk(KERN_ERR
+				       "%s: gpio_tlmm_config(%#x)=%d\n",
+				       __func__, bt_config_power_on[pin], rc);
+				return -EIO;
+			}
+		}
+		vreg_bt = regulator_get(NULL, "gp6");
+
+		if (IS_ERR(vreg_bt)) {
+			rc = PTR_ERR(vreg_bt);
+			pr_err("%s: could get not regulator: %d\n",
+					__func__, rc);
+			goto out;
+		}
+
+		/* units of mV, steps of 50 mV */
+		rc = regulator_set_voltage(vreg_bt, 2600000, 2600000);
+		if (rc < 0) {
+			pr_err("%s: could not set voltage: %d\n", __func__, rc);
+			goto bt_vreg_fail;
+		}
+		rc = regulator_enable(vreg_bt);
+		if (rc < 0) {
+			pr_err("%s: could not enable regulator: %d\n",
+					 __func__, rc);
+			goto bt_vreg_fail;
+		}
+	} else {
+		rc = regulator_disable(vreg_bt);
+		if (rc < 0) {
+			pr_err("%s: could not disable regulator: %d\n",
+					 __func__, rc);
+			goto bt_vreg_fail;
+		}
+		regulator_put(vreg_bt);
+		for (pin = 0; pin < ARRAY_SIZE(bt_config_power_off); pin++) {
+			rc = gpio_tlmm_config(bt_config_power_off[pin],
+					      GPIO_CFG_ENABLE);
+			if (rc) {
+				printk(KERN_ERR
+				       "%s: gpio_tlmm_config(%#x)=%d\n",
+				       __func__, bt_config_power_off[pin], rc);
+				return -EIO;
+			}
+		}
+	}
+	return 0;
+
+bt_vreg_fail:
+	regulator_put(vreg_bt);
+out:
+	return rc;
+}
+
+static void __init bt_power_init(void)
+{
+	msm_bt_power_device.dev.platform_data = &bluetooth_power;
+}
+#else
+#define bt_power_init(x) do {} while (0)
+#endif
+
+static struct platform_device msm_device_pmic_leds = {
+	.name   = "pmic-leds",
+	.id = -1,
+};
+
+static struct resource bluesleep_resources[] = {
+	{
+		.name	= "gpio_host_wake",
+		.start	= 83,
+		.end	= 83,
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.name	= "gpio_ext_wake",
+		.start	= 42,
+		.end	= 42,
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.name	= "host_wake",
+		.start	= MSM_GPIO_TO_INT(83),
+		.end	= MSM_GPIO_TO_INT(83),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device msm_bluesleep_device = {
+	.name = "bluesleep",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(bluesleep_resources),
+	.resource	= bluesleep_resources,
+};
+
+static struct i2c_board_info i2c_devices[] = {
+#ifdef CONFIG_MT9D112
+	{
+		I2C_BOARD_INFO("mt9d112", 0x78 >> 1),
+	},
+#endif
+#ifdef CONFIG_S5K3E2FX
+	{
+		I2C_BOARD_INFO("s5k3e2fx", 0x20 >> 1),
+	},
+#endif
+#ifdef CONFIG_MT9P012
+	{
+		I2C_BOARD_INFO("mt9p012", 0x6C >> 1),
+	},
+#endif
+#ifdef CONFIG_MT9P012_KM
+	{
+		I2C_BOARD_INFO("mt9p012_km", 0x6C >> 2),
+	},
+#endif
+#if defined(CONFIG_MT9T013) || defined(CONFIG_SENSORS_MT9T013)
+	{
+		I2C_BOARD_INFO("mt9t013", 0x6C),
+	},
+#endif
+#ifdef CONFIG_VB6801
+	{
+		I2C_BOARD_INFO("vb6801", 0x20),
+	},
+#endif
+};
+
+#ifdef CONFIG_MSM_CAMERA
+static uint32_t camera_off_gpio_table[] = {
+	/* parallel CAMERA interfaces */
+	GPIO_CFG(0,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT0 */
+	GPIO_CFG(1,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT1 */
+	GPIO_CFG(2,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT2 */
+	GPIO_CFG(3,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT3 */
+	GPIO_CFG(4,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT4 */
+	GPIO_CFG(5,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT5 */
+	GPIO_CFG(6,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT6 */
+	GPIO_CFG(7,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT7 */
+	GPIO_CFG(8,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT8 */
+	GPIO_CFG(9,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT9 */
+	GPIO_CFG(10, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT10 */
+	GPIO_CFG(11, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT11 */
+	GPIO_CFG(12, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* PCLK */
+	GPIO_CFG(13, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* HSYNC_IN */
+	GPIO_CFG(14, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* VSYNC_IN */
+	GPIO_CFG(15, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), /* MCLK */
+};
+
+static uint32_t camera_on_gpio_table[] = {
+	/* parallel CAMERA interfaces */
+	GPIO_CFG(0,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT0 */
+	GPIO_CFG(1,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT1 */
+	GPIO_CFG(2,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT2 */
+	GPIO_CFG(3,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT3 */
+	GPIO_CFG(4,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT4 */
+	GPIO_CFG(5,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT5 */
+	GPIO_CFG(6,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT6 */
+	GPIO_CFG(7,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT7 */
+	GPIO_CFG(8,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT8 */
+	GPIO_CFG(9,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT9 */
+	GPIO_CFG(10, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT10 */
+	GPIO_CFG(11, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT11 */
+	GPIO_CFG(12, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_16MA), /* PCLK */
+	GPIO_CFG(13, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* HSYNC_IN */
+	GPIO_CFG(14, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* VSYNC_IN */
+	GPIO_CFG(15, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_16MA), /* MCLK */
+	};
+
+static void config_gpio_table(uint32_t *table, int len)
+{
+	int n, rc;
+	for (n = 0; n < len; n++) {
+		rc = gpio_tlmm_config(table[n], GPIO_CFG_ENABLE);
+		if (rc) {
+			printk(KERN_ERR "%s: gpio_tlmm_config(%#x)=%d\n",
+				__func__, table[n], rc);
+			break;
+		}
+	}
+}
+
+static void msm_camera_vreg_config(int vreg_en)
+{
+	int rc;
+	static struct regulator *vreg_gp2;
+	static struct regulator *vreg_gp3;
+
+	if (vreg_gp2 == NULL && vreg_gp3 == NULL) {
+		vreg_gp2 = regulator_get(NULL, "gp2");
+		if (IS_ERR(vreg_gp2)) {
+			rc = PTR_ERR(vreg_gp2);
+			pr_err("%s: could not get regulator: %d\n",
+					__func__, rc);
+			return;
+		}
+
+		rc = regulator_set_voltage(vreg_gp2, 1800000, 1800000);
+		if (rc < 0) {
+			pr_err("%s: could not set voltage: %d\n",
+					__func__, rc);
+			goto cam_vreg_fail;
+		}
+
+		vreg_gp3 = regulator_get(NULL, "gp3");
+		if (IS_ERR(vreg_gp3)) {
+			rc = PTR_ERR(vreg_gp3);
+			pr_err("%s: could not get regulator: %d\n",
+					__func__, rc);
+			goto cam_vreg_fail;
+		}
+
+		rc = regulator_set_voltage(vreg_gp3, 2850000, 2850000);
+		if (rc < 0) {
+			pr_err("%s: could not set voltage: %d\n", __func__, rc);
+			goto cam_vreg2_fail;
+		}
+
+		return;
+
+	}
+
+	if (vreg_gp2 == NULL || vreg_gp3 == NULL) {
+		pr_err("Camera Regulators are not initialized\n");
+		return;
+	}
+
+	if (vreg_en) {
+		rc = regulator_enable(vreg_gp2);
+		if (rc) {
+			pr_err("%s: could not enable regulator: %d\n",
+					__func__, rc);
+			goto cam_vreg2_fail;
+		}
+
+		rc = regulator_enable(vreg_gp3);
+		if (rc) {
+			pr_err("%s: could not enable regulator: %d\n",
+					__func__, rc);
+			goto vreg_gp3_fail;
+		}
+	} else {
+		rc = regulator_disable(vreg_gp2);
+		if (rc) {
+			pr_err("%s: could not disable regulator: %d\n",
+					__func__, rc);
+			return;
+		}
+
+		rc = regulator_disable(vreg_gp3);
+		if (rc) {
+			pr_err("%s: could not disable regulator: %d\n",
+					__func__, rc);
+			goto cam_vreg2_fail;
+		}
+	}
+
+	return;
+
+vreg_gp3_fail:
+	if (vreg_en)
+		regulator_disable(vreg_gp2);
+
+cam_vreg2_fail:
+	regulator_put(vreg_gp3);
+cam_vreg_fail:
+	regulator_put(vreg_gp2);
+	vreg_gp3 = NULL;
+	vreg_gp2 = NULL;
+}
+
+static int config_camera_on_gpios(void)
+{
+	int vreg_en = 1;
+
+	if (machine_is_msm7x25_ffa() ||
+	    machine_is_msm7x27_ffa())
+		msm_camera_vreg_config(vreg_en);
+
+	config_gpio_table(camera_on_gpio_table,
+		ARRAY_SIZE(camera_on_gpio_table));
+	return 0;
+}
+
+static void config_camera_off_gpios(void)
+{
+	int vreg_en = 0;
+
+	if (machine_is_msm7x25_ffa() ||
+	    machine_is_msm7x27_ffa())
+		msm_camera_vreg_config(vreg_en);
+
+	config_gpio_table(camera_off_gpio_table,
+		ARRAY_SIZE(camera_off_gpio_table));
+}
+
+static struct msm_camera_device_platform_data msm_camera_device_data = {
+	.camera_gpio_on  = config_camera_on_gpios,
+	.camera_gpio_off = config_camera_off_gpios,
+	.ioext.mdcphy = MSM7XXX_MDC_PHYS,
+	.ioext.mdcsz  = MSM7XXX_MDC_SIZE,
+	.ioext.appphy = MSM7XXX_CLK_CTL_PHYS,
+	.ioext.appsz  = MSM7XXX_CLK_CTL_SIZE,
+};
+
+int pmic_set_flash_led_current(enum pmic8058_leds id, unsigned mA)
+{
+	int rc;
+	rc = pmic_flash_led_set_current(mA);
+	return rc;
+}
+
+static struct msm_camera_sensor_flash_src msm_flash_src = {
+	.flash_sr_type = MSM_CAMERA_FLASH_SRC_PMIC,
+	._fsrc.pmic_src.num_of_src = 1,
+	._fsrc.pmic_src.low_current  = 30,
+	._fsrc.pmic_src.high_current = 100,
+	._fsrc.pmic_src.led_src_1 = 0,
+	._fsrc.pmic_src.led_src_2 = 0,
+	._fsrc.pmic_src.pmic_set_current = pmic_set_flash_led_current,
+};
+
+#ifdef CONFIG_MT9D112
+static struct msm_camera_sensor_flash_data flash_mt9d112 = {
+	.flash_type = MSM_CAMERA_FLASH_LED,
+	.flash_src  = &msm_flash_src
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_mt9d112_data = {
+	.sensor_name    = "mt9d112",
+	.sensor_reset   = 89,
+	.sensor_pwd     = 85,
+	.vcm_pwd        = 0,
+	.vcm_enable     = 0,
+	.pdata          = &msm_camera_device_data,
+	.flash_data     = &flash_mt9d112
+};
+
+static struct platform_device msm_camera_sensor_mt9d112 = {
+	.name      = "msm_camera_mt9d112",
+	.dev       = {
+		.platform_data = &msm_camera_sensor_mt9d112_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_S5K3E2FX
+static struct msm_camera_sensor_flash_data flash_s5k3e2fx = {
+	.flash_type = MSM_CAMERA_FLASH_LED,
+	.flash_src  = &msm_flash_src
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_s5k3e2fx_data = {
+	.sensor_name    = "s5k3e2fx",
+	.sensor_reset   = 89,
+	.sensor_pwd     = 85,
+	.vcm_pwd        = 0,
+	.vcm_enable     = 0,
+	.pdata          = &msm_camera_device_data,
+	.flash_data     = &flash_s5k3e2fx
+};
+
+static struct platform_device msm_camera_sensor_s5k3e2fx = {
+	.name      = "msm_camera_s5k3e2fx",
+	.dev       = {
+		.platform_data = &msm_camera_sensor_s5k3e2fx_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_MT9P012
+static struct msm_camera_sensor_flash_data flash_mt9p012 = {
+	.flash_type = MSM_CAMERA_FLASH_LED,
+	.flash_src  = &msm_flash_src
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_mt9p012_data = {
+	.sensor_name    = "mt9p012",
+	.sensor_reset   = 89,
+	.sensor_pwd     = 85,
+	.vcm_pwd        = 88,
+	.vcm_enable     = 0,
+	.pdata          = &msm_camera_device_data,
+	.flash_data     = &flash_mt9p012
+};
+
+static struct platform_device msm_camera_sensor_mt9p012 = {
+	.name      = "msm_camera_mt9p012",
+	.dev       = {
+		.platform_data = &msm_camera_sensor_mt9p012_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_MT9P012_KM
+static struct msm_camera_sensor_flash_data flash_mt9p012_km = {
+	.flash_type = MSM_CAMERA_FLASH_LED,
+	.flash_src  = &msm_flash_src
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_mt9p012_km_data = {
+	.sensor_name    = "mt9p012_km",
+	.sensor_reset   = 89,
+	.sensor_pwd     = 85,
+	.vcm_pwd        = 88,
+	.vcm_enable     = 0,
+	.pdata          = &msm_camera_device_data,
+	.flash_data     = &flash_mt9p012_km
+};
+
+static struct platform_device msm_camera_sensor_mt9p012_km = {
+	.name      = "msm_camera_mt9p012_km",
+	.dev       = {
+		.platform_data = &msm_camera_sensor_mt9p012_km_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_MT9T013
+static struct msm_camera_sensor_flash_data flash_mt9t013 = {
+	.flash_type = MSM_CAMERA_FLASH_LED,
+	.flash_src  = &msm_flash_src
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_mt9t013_data = {
+	.sensor_name    = "mt9t013",
+	.sensor_reset   = 89,
+	.sensor_pwd     = 85,
+	.vcm_pwd        = 0,
+	.vcm_enable     = 0,
+	.pdata          = &msm_camera_device_data,
+	.flash_data     = &flash_mt9t013
+};
+
+static struct platform_device msm_camera_sensor_mt9t013 = {
+	.name      = "msm_camera_mt9t013",
+	.dev       = {
+		.platform_data = &msm_camera_sensor_mt9t013_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_VB6801
+static struct msm_camera_sensor_flash_data flash_vb6801 = {
+	.flash_type = MSM_CAMERA_FLASH_LED,
+	.flash_src  = &msm_flash_src
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_vb6801_data = {
+	.sensor_name    = "vb6801",
+	.sensor_reset   = 89,
+	.sensor_pwd     = 88,
+	.vcm_pwd        = 0,
+	.vcm_enable     = 0,
+	.pdata          = &msm_camera_device_data,
+	.flash_data     = &flash_vb6801
+};
+
+static struct platform_device msm_camera_sensor_vb6801 = {
+	.name      = "msm_camera_vb6801",
+	.dev       = {
+		.platform_data = &msm_camera_sensor_vb6801_data,
+	},
+};
+#endif
+#endif
+
+static u32 msm_calculate_batt_capacity(u32 current_voltage);
+
+static struct msm_psy_batt_pdata msm_psy_batt_data = {
+	.voltage_min_design 	= 2800,
+	.voltage_max_design	= 4300,
+	.avail_chg_sources   	= AC_CHG | USB_CHG ,
+	.batt_technology        = POWER_SUPPLY_TECHNOLOGY_LION,
+	.calculate_capacity	= &msm_calculate_batt_capacity,
+};
+
+static u32 msm_calculate_batt_capacity(u32 current_voltage)
+{
+	u32 low_voltage   = msm_psy_batt_data.voltage_min_design;
+	u32 high_voltage  = msm_psy_batt_data.voltage_max_design;
+
+	return (current_voltage - low_voltage) * 100
+		/ (high_voltage - low_voltage);
+}
+
+static struct platform_device msm_batt_device = {
+	.name 		    = "msm-battery",
+	.id		    = -1,
+	.dev.platform_data  = &msm_psy_batt_data,
+};
+
+
 static struct platform_device *devices[] __initdata = {
-	&msm_device_uart3,
+	&asoc_msm_pcm,
+	&asoc_msm_dai0,
+	&asoc_msm_dai1,
+
 	&msm_device_smd,
 	&msm_device_dmov,
 	&msm_device_nand,
+
+#ifdef CONFIG_USB_MSM_OTG_72K
+	&msm_device_otg,
+#ifdef CONFIG_USB_GADGET
+	&msm_device_gadget_peripheral,
+#endif
+#endif
+
+#ifdef CONFIG_USB_G_ANDROID
+	&android_usb_device,
+#endif
+
+	&msm_device_i2c,
 	&smc91x_device,
+	&msm_device_tssc,
+	&android_pmem_device,
+	&android_pmem_adsp_device,
+	&android_pmem_audio_device,
+	&msm_fb_device,
+	&lcdc_gordon_panel_device,
+	&msm_device_uart_dm1,
+#ifdef CONFIG_BT
+	&msm_bt_power_device,
+#endif
+	&msm_device_pmic_leds,
+	&msm_device_snd,
+	&msm_device_adspdec,
+#ifdef CONFIG_MT9T013
+	&msm_camera_sensor_mt9t013,
+#endif
+#ifdef CONFIG_MT9D112
+	&msm_camera_sensor_mt9d112,
+#endif
+#ifdef CONFIG_S5K3E2FX
+	&msm_camera_sensor_s5k3e2fx,
+#endif
+#ifdef CONFIG_MT9P012
+	&msm_camera_sensor_mt9p012,
+#endif
+#ifdef CONFIG_MT9P012_KM
+	&msm_camera_sensor_mt9p012_km,
+#endif
+#ifdef CONFIG_VB6801
+	&msm_camera_sensor_vb6801,
+#endif
+	&msm_bluesleep_device,
+#ifdef CONFIG_ARCH_MSM7X27
+	&msm_kgsl_3d0,
+#endif
+#if defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE)
+	&msm_device_tsif,
+#endif
+	&hs_device,
+	&msm_batt_device,
 };
 
+static struct msm_panel_common_pdata mdp_pdata = {
+	.gpio = 97,
+	.mdp_rev = MDP_REV_30,
+};
+
+static void __init msm_fb_add_devices(void)
+{
+	msm_fb_register_device("mdp", &mdp_pdata);
+	msm_fb_register_device("pmdh", 0);
+	msm_fb_register_device("lcdc", &lcdc_pdata);
+}
+
 extern struct sys_timer msm_timer;
 
 static void __init msm7x2x_init_irq(void)
@@ -79,51 +1340,646 @@
 	msm_init_irq();
 }
 
+void msm_serial_debug_init(unsigned int base, int irq,
+			   struct device *clk_device, int signal_irq);
+
+#if (defined(CONFIG_MMC_MSM_SDC1_SUPPORT)\
+	|| defined(CONFIG_MMC_MSM_SDC2_SUPPORT)\
+	|| defined(CONFIG_MMC_MSM_SDC3_SUPPORT)\
+	|| defined(CONFIG_MMC_MSM_SDC4_SUPPORT))
+
+static unsigned long vreg_sts, gpio_sts;
+static struct regulator *vreg_mmc;
+static unsigned mpp_mmc = 2;
+
+struct sdcc_gpio {
+	struct msm_gpio *cfg_data;
+	uint32_t size;
+	struct msm_gpio *sleep_cfg_data;
+};
+
+static struct msm_gpio sdc1_cfg_data[] = {
+	{GPIO_CFG(51, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc1_dat_3"},
+	{GPIO_CFG(52, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc1_dat_2"},
+	{GPIO_CFG(53, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc1_dat_1"},
+	{GPIO_CFG(54, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc1_dat_0"},
+	{GPIO_CFG(55, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc1_cmd"},
+	{GPIO_CFG(56, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), "sdc1_clk"},
+};
+
+static struct msm_gpio sdc2_cfg_data[] = {
+	{GPIO_CFG(62, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), "sdc2_clk"},
+	{GPIO_CFG(63, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc2_cmd"},
+	{GPIO_CFG(64, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc2_dat_3"},
+	{GPIO_CFG(65, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc2_dat_2"},
+	{GPIO_CFG(66, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc2_dat_1"},
+	{GPIO_CFG(67, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc2_dat_0"},
+};
+
+static struct msm_gpio sdc2_sleep_cfg_data[] = {
+	{GPIO_CFG(62, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "sdc2_clk"},
+	{GPIO_CFG(63, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "sdc2_cmd"},
+	{GPIO_CFG(64, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "sdc2_dat_3"},
+	{GPIO_CFG(65, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "sdc2_dat_2"},
+	{GPIO_CFG(66, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "sdc2_dat_1"},
+	{GPIO_CFG(67, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "sdc2_dat_0"},
+};
+static struct msm_gpio sdc3_cfg_data[] = {
+	{GPIO_CFG(88, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), "sdc3_clk"},
+	{GPIO_CFG(89, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc3_cmd"},
+	{GPIO_CFG(90, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc3_dat_3"},
+	{GPIO_CFG(91, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc3_dat_2"},
+	{GPIO_CFG(92, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc3_dat_1"},
+	{GPIO_CFG(93, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc3_dat_0"},
+};
+
+static struct msm_gpio sdc4_cfg_data[] = {
+	{GPIO_CFG(19, 3, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc4_dat_3"},
+	{GPIO_CFG(20, 3, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc4_dat_2"},
+	{GPIO_CFG(21, 4, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc4_dat_1"},
+	{GPIO_CFG(107, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc4_cmd"},
+	{GPIO_CFG(108, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc4_dat_0"},
+	{GPIO_CFG(109, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), "sdc4_clk"},
+};
+
+static struct sdcc_gpio sdcc_cfg_data[] = {
+	{
+		.cfg_data = sdc1_cfg_data,
+		.size = ARRAY_SIZE(sdc1_cfg_data),
+		.sleep_cfg_data = NULL,
+	},
+	{
+		.cfg_data = sdc2_cfg_data,
+		.size = ARRAY_SIZE(sdc2_cfg_data),
+		.sleep_cfg_data = sdc2_sleep_cfg_data,
+	},
+	{
+		.cfg_data = sdc3_cfg_data,
+		.size = ARRAY_SIZE(sdc3_cfg_data),
+		.sleep_cfg_data = NULL,
+	},
+	{
+		.cfg_data = sdc4_cfg_data,
+		.size = ARRAY_SIZE(sdc4_cfg_data),
+		.sleep_cfg_data = NULL,
+	},
+};
+
+static void msm_sdcc_setup_gpio(int dev_id, unsigned int enable)
+{
+	int rc = 0;
+	struct sdcc_gpio *curr;
+
+	curr = &sdcc_cfg_data[dev_id - 1];
+	if (!(test_bit(dev_id, &gpio_sts)^enable))
+		return;
+
+	if (enable) {
+		set_bit(dev_id, &gpio_sts);
+		rc = msm_gpios_request_enable(curr->cfg_data, curr->size);
+		if (rc)
+			printk(KERN_ERR "%s: Failed to turn on GPIOs for slot %d\n",
+				__func__,  dev_id);
+	} else {
+		clear_bit(dev_id, &gpio_sts);
+		if (curr->sleep_cfg_data) {
+			msm_gpios_enable(curr->sleep_cfg_data, curr->size);
+			msm_gpios_free(curr->sleep_cfg_data, curr->size);
+			return;
+		}
+		msm_gpios_disable_free(curr->cfg_data, curr->size);
+	}
+}
+
+static uint32_t msm_sdcc_setup_power(struct device *dv, unsigned int vdd)
+{
+	int rc = 0;
+	struct platform_device *pdev;
+
+	pdev = container_of(dv, struct platform_device, dev);
+	msm_sdcc_setup_gpio(pdev->id, !!vdd);
+
+	if (vdd == 0) {
+		if (!vreg_sts)
+			return 0;
+
+		clear_bit(pdev->id, &vreg_sts);
+
+		if (!vreg_sts) {
+			if (machine_is_msm7x25_ffa() ||
+					machine_is_msm7x27_ffa()) {
+				rc = mpp_config_digital_out(mpp_mmc,
+				     MPP_CFG(MPP_DLOGIC_LVL_MSMP,
+				     MPP_DLOGIC_OUT_CTRL_LOW));
+			} else
+				rc = regulator_disable(vreg_mmc);
+			if (rc) {
+				pr_err("%s: return val: %d\n",
+					__func__, rc);
+			}
+		}
+		return 0;
+	}
+
+	if (!vreg_sts) {
+		if (machine_is_msm7x25_ffa() || machine_is_msm7x27_ffa()) {
+			rc = mpp_config_digital_out(mpp_mmc,
+			     MPP_CFG(MPP_DLOGIC_LVL_MSMP,
+			     MPP_DLOGIC_OUT_CTRL_HIGH));
+		} else {
+			rc = regulator_set_voltage(vreg_mmc, 2850000, 2850000);
+			if (!rc)
+				rc = regulator_enable(vreg_mmc);
+		}
+		if (rc) {
+			pr_err("%s: return val: %d\n",
+					__func__, rc);
+		}
+	}
+	set_bit(pdev->id, &vreg_sts);
+	return 0;
+}
+
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+static struct mmc_platform_data msm7x2x_sdc1_data = {
+	.ocr_mask	= MMC_VDD_28_29,
+	.translate_vdd	= msm_sdcc_setup_power,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.msmsdcc_fmin	= 144000,
+	.msmsdcc_fmid	= 24576000,
+	.msmsdcc_fmax	= 49152000,
+	.nonremovable	= 0,
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+static struct mmc_platform_data msm7x2x_sdc2_data = {
+	.ocr_mask	= MMC_VDD_28_29,
+	.translate_vdd	= msm_sdcc_setup_power,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.sdiowakeup_irq = MSM_GPIO_TO_INT(66),
+	.msmsdcc_fmin	= 144000,
+	.msmsdcc_fmid	= 24576000,
+	.msmsdcc_fmax	= 49152000,
+	.nonremovable	= 0,
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+static struct mmc_platform_data msm7x2x_sdc3_data = {
+	.ocr_mask	= MMC_VDD_28_29,
+	.translate_vdd	= msm_sdcc_setup_power,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.msmsdcc_fmin	= 144000,
+	.msmsdcc_fmid	= 24576000,
+	.msmsdcc_fmax	= 49152000,
+	.nonremovable	= 0,
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+static struct mmc_platform_data msm7x2x_sdc4_data = {
+	.ocr_mask	= MMC_VDD_28_29,
+	.translate_vdd	= msm_sdcc_setup_power,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.msmsdcc_fmin	= 144000,
+	.msmsdcc_fmid	= 24576000,
+	.msmsdcc_fmax	= 49152000,
+	.nonremovable	= 0,
+};
+#endif
+
+static void __init msm7x2x_init_mmc(void)
+{
+	if (!machine_is_msm7x25_ffa() && !machine_is_msm7x27_ffa()) {
+		vreg_mmc = regulator_get(NULL, "mmc");
+		if (IS_ERR(vreg_mmc)) {
+			pr_err("%s: could not get regulator: %ld\n",
+					__func__, PTR_ERR(vreg_mmc));
+		}
+	}
+
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+	msm_add_sdcc(1, &msm7x2x_sdc1_data);
+#endif
+
+	if (machine_is_msm7x25_surf() || machine_is_msm7x27_surf() ||
+		machine_is_msm7x27_ffa()) {
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+		msm_sdcc_setup_gpio(2, 1);
+		msm_add_sdcc(2, &msm7x2x_sdc2_data);
+#endif
+	}
+
+	if (machine_is_msm7x25_surf() || machine_is_msm7x27_surf()) {
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+		msm_add_sdcc(3, &msm7x2x_sdc3_data);
+#endif
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+		msm_add_sdcc(4, &msm7x2x_sdc4_data);
+#endif
+	}
+}
+#else
+#define msm7x2x_init_mmc() do {} while (0)
+#endif
+
+
+static struct msm_pm_platform_data msm7x25_pm_data[MSM_PM_SLEEP_MODE_NR] = {
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)].latency = 16000,
+
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN)]
+		.latency = 12000,
+
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT)]
+		.latency = 2000,
+};
+
+static struct msm_pm_platform_data msm7x27_pm_data[MSM_PM_SLEEP_MODE_NR] = {
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = {
+		.idle_supported = 1,
+		.suspend_supported = 1,
+		.idle_enabled = 1,
+		.suspend_enabled = 1,
+		.latency = 16000,
+		.residency = 20000,
+	},
+
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN)] = {
+		.idle_supported = 1,
+		.suspend_supported = 1,
+		.idle_enabled = 1,
+		.suspend_enabled = 1,
+		.latency = 12000,
+		.residency = 20000,
+	},
+
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT)] = {
+		.idle_supported = 1,
+		.suspend_supported = 1,
+		.idle_enabled = 1,
+		.suspend_enabled = 1,
+		.latency = 2000,
+		.residency = 0,
+	},
+};
+
+static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS,
+	.p_addr = 0,
+};
+
+static void
+msm_i2c_gpio_config(int iface, int config_type)
+{
+	int gpio_scl;
+	int gpio_sda;
+	if (iface) {
+		gpio_scl = 95;
+		gpio_sda = 96;
+	} else {
+		gpio_scl = 60;
+		gpio_sda = 61;
+	}
+	if (config_type) {
+		gpio_tlmm_config(GPIO_CFG(gpio_scl, 1, GPIO_CFG_INPUT,
+					GPIO_CFG_NO_PULL, GPIO_CFG_16MA), GPIO_CFG_ENABLE);
+		gpio_tlmm_config(GPIO_CFG(gpio_sda, 1, GPIO_CFG_INPUT,
+					GPIO_CFG_NO_PULL, GPIO_CFG_16MA), GPIO_CFG_ENABLE);
+	} else {
+		gpio_tlmm_config(GPIO_CFG(gpio_scl, 0, GPIO_CFG_OUTPUT,
+					GPIO_CFG_NO_PULL, GPIO_CFG_16MA), GPIO_CFG_ENABLE);
+		gpio_tlmm_config(GPIO_CFG(gpio_sda, 0, GPIO_CFG_OUTPUT,
+					GPIO_CFG_NO_PULL, GPIO_CFG_16MA), GPIO_CFG_ENABLE);
+	}
+}
+
+static struct msm_i2c_platform_data msm_i2c_pdata = {
+	.clk_freq = 100000,
+	.rmutex  = 0,
+	.pri_clk = 60,
+	.pri_dat = 61,
+	.aux_clk = 95,
+	.aux_dat = 96,
+	.msm_i2c_config_gpio = msm_i2c_gpio_config,
+};
+static struct platform_device msm_proccomm_regulator_dev = {
+	.name   = PROCCOMM_REGULATOR_DEV_NAME,
+	.id     = -1,
+	.dev    = {
+		.platform_data = &msm7627_proccomm_regulator_data
+	}
+};
+
+static void __init msm7627_init_regulators(void)
+{
+	int rc = platform_device_register(&msm_proccomm_regulator_dev);
+	if (rc)
+		pr_err("%s: could not register regulator device: %d\n",
+				__func__, rc);
+}
+static void __init msm_device_i2c_init(void)
+{
+	if (gpio_request(60, "i2c_pri_clk"))
+		pr_err("failed to request gpio i2c_pri_clk\n");
+	if (gpio_request(61, "i2c_pri_dat"))
+		pr_err("failed to request gpio i2c_pri_dat\n");
+	if (gpio_request(95, "i2c_sec_clk"))
+		pr_err("failed to request gpio i2c_sec_clk\n");
+	if (gpio_request(96, "i2c_sec_dat"))
+		pr_err("failed to request gpio i2c_sec_dat\n");
+
+	if (cpu_is_msm7x27())
+		msm_i2c_pdata.pm_lat =
+		msm7x27_pm_data[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]
+		.latency;
+	else
+		msm_i2c_pdata.pm_lat =
+		msm7x25_pm_data[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]
+		.latency;
+
+	msm_device_i2c.dev.platform_data = &msm_i2c_pdata;
+}
+
+static void usb_mpp_init(void)
+{
+	unsigned rc;
+	unsigned mpp_usb = 7;
+
+	if (machine_is_msm7x25_ffa() || machine_is_msm7x27_ffa()) {
+		rc = mpp_config_digital_out(mpp_usb,
+			MPP_CFG(MPP_DLOGIC_LVL_VDD,
+				MPP_DLOGIC_OUT_CTRL_HIGH));
+		if (rc)
+			pr_err("%s: configuring mpp pin"
+				"to enable 3.3V LDO failed\n", __func__);
+	}
+}
+
+static void msm7x27_wlan_init(void)
+{
+	int rc = 0;
+	/* TBD: if (machine_is_msm7x27_ffa_with_wcn1312()) */
+	if (machine_is_msm7x27_ffa()) {
+		rc = mpp_config_digital_out(3, MPP_CFG(MPP_DLOGIC_LVL_MSMP,
+				MPP_DLOGIC_OUT_CTRL_LOW));
+		if (rc)
+			printk(KERN_ERR "%s: return val: %d \n",
+				__func__, rc);
+	}
+}
+
+static void msm_adsp_add_pdev(void)
+{
+	int rc = 0;
+	struct rpc_board_dev *rpc_adsp_pdev;
+
+	rpc_adsp_pdev = kzalloc(sizeof(struct rpc_board_dev), GFP_KERNEL);
+	if (rpc_adsp_pdev == NULL) {
+		pr_err("%s: Memory Allocation failure\n", __func__);
+		return;
+	}
+	rpc_adsp_pdev->prog = ADSP_RPC_PROG;
+	rpc_adsp_pdev->pdev = msm_adsp_device;
+	rc = msm_rpc_add_board_dev(rpc_adsp_pdev, 1);
+	if (rc < 0) {
+		pr_err("%s: return val: %d\n",	__func__, rc);
+		kfree(rpc_adsp_pdev);
+	}
+}
+
 static void __init msm7x2x_init(void)
 {
-	if (socinfo_init() < 0)
-		BUG();
 
+	msm7627_init_regulators();
+#ifdef CONFIG_ARCH_MSM7X25
+	msm_clock_init(msm_clocks_7x25, msm_num_clocks_7x25);
+#elif defined(CONFIG_ARCH_MSM7X27)
+	msm_clock_init(&msm7x27_clock_init_data);
+#endif
+
+#if defined(CONFIG_SMC91X)
 	if (machine_is_msm7x25_ffa() || machine_is_msm7x27_ffa()) {
 		smc91x_resources[0].start = 0x98000300;
 		smc91x_resources[0].end = 0x980003ff;
 		smc91x_resources[1].start = MSM_GPIO_TO_INT(85);
 		smc91x_resources[1].end = MSM_GPIO_TO_INT(85);
 		if (gpio_tlmm_config(GPIO_CFG(85, 0,
-					      GPIO_INPUT,
-					      GPIO_PULL_DOWN,
-					      GPIO_2MA),
-				     GPIO_ENABLE)) {
+					      GPIO_CFG_INPUT,
+					      GPIO_CFG_PULL_DOWN,
+					      GPIO_CFG_2MA),
+				     GPIO_CFG_ENABLE)) {
 			printk(KERN_ERR
 			       "%s: Err: Config GPIO-85 INT\n",
 				__func__);
 		}
 	}
+#endif
+	acpuclk_init(&acpuclk_7x27_soc_data);
 
+	usb_mpp_init();
+
+
+#ifdef CONFIG_USB_MSM_OTG_72K
+	msm_device_otg.dev.platform_data = &msm_otg_pdata;
+	if (machine_is_msm7x25_surf() || machine_is_msm7x25_ffa()) {
+		msm_otg_pdata.pemp_level =
+			PRE_EMPHASIS_WITH_20_PERCENT;
+		msm_otg_pdata.drv_ampl = HS_DRV_AMPLITUDE_5_PERCENT;
+		msm_otg_pdata.cdr_autoreset = CDR_AUTO_RESET_ENABLE;
+		msm_otg_pdata.phy_reset = msm_otg_rpc_phy_reset;
+	}
+	if (machine_is_msm7x27_surf() || machine_is_msm7x27_ffa()) {
+		msm_otg_pdata.pemp_level =
+			PRE_EMPHASIS_WITH_10_PERCENT;
+		msm_otg_pdata.drv_ampl = HS_DRV_AMPLITUDE_5_PERCENT;
+		msm_otg_pdata.cdr_autoreset = CDR_AUTO_RESET_DISABLE;
+		msm_otg_pdata.phy_reset_sig_inverted = 1;
+	}
+
+#ifdef CONFIG_USB_GADGET
+	msm_otg_pdata.swfi_latency =
+		msm7x27_pm_data
+		[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency;
+	msm_device_gadget_peripheral.dev.platform_data = &msm_gadget_pdata;
+	msm_gadget_pdata.is_phy_status_timer_on = 1;
+#endif
+#endif
+#if defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE)
+	msm_device_tsif.dev.platform_data = &tsif_platform_data;
+#endif
+	platform_add_devices(msm_footswitch_devices,
+			     msm_num_footswitch_devices);
 	platform_add_devices(devices, ARRAY_SIZE(devices));
+#ifdef CONFIG_MSM_CAMERA
+	config_camera_off_gpios(); /* might not be necessary */
+#endif
+	msm_adsp_add_pdev();
+	msm_device_i2c_init();
+	i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices));
+
+#ifdef CONFIG_SURF_FFA_GPIO_KEYPAD
+	if (machine_is_msm7x25_ffa() || machine_is_msm7x27_ffa())
+		platform_device_register(&keypad_device_7k_ffa);
+	else
+		platform_device_register(&keypad_device_surf);
+#endif
+	lcdc_gordon_gpio_init();
+	msm_fb_add_devices();
+#ifdef CONFIG_USB_EHCI_MSM_72K
+	msm7x2x_init_host();
+#endif
+	msm7x2x_init_mmc();
+	bt_power_init();
+
+	if (cpu_is_msm7x27())
+		msm_pm_set_platform_data(msm7x27_pm_data,
+					ARRAY_SIZE(msm7x27_pm_data));
+	else
+		msm_pm_set_platform_data(msm7x25_pm_data,
+					ARRAY_SIZE(msm7x25_pm_data));
+
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+
+	msm7x27_wlan_init();
+}
+
+static unsigned pmem_kernel_ebi1_size = PMEM_KERNEL_EBI1_SIZE;
+static int __init pmem_kernel_ebi1_size_setup(char *p)
+{
+	pmem_kernel_ebi1_size = memparse(p, NULL);
+	return 0;
+}
+early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
+
+static unsigned pmem_mdp_size = MSM_PMEM_MDP_SIZE;
+static int __init pmem_mdp_size_setup(char *p)
+{
+	pmem_mdp_size = memparse(p, NULL);
+	return 0;
+}
+early_param("pmem_mdp_size", pmem_mdp_size_setup);
+
+static unsigned pmem_adsp_size = MSM_PMEM_ADSP_SIZE;
+static int __init pmem_adsp_size_setup(char *p)
+{
+	pmem_adsp_size = memparse(p, NULL);
+	return 0;
+}
+early_param("pmem_adsp_size", pmem_adsp_size_setup);
+
+static unsigned pmem_audio_size = MSM_PMEM_AUDIO_SIZE;
+static int __init pmem_audio_size_setup(char *p)
+{
+	pmem_audio_size = memparse(p, NULL);
+	return 0;
+}
+early_param("pmem_audio_size", pmem_audio_size_setup);
+
+static unsigned fb_size = MSM_FB_SIZE;
+static int __init fb_size_setup(char *p)
+{
+	fb_size = memparse(p, NULL);
+	return 0;
+}
+early_param("fb_size", fb_size_setup);
+
+static void __init msm_msm7x2x_allocate_memory_regions(void)
+{
+	void *addr;
+	unsigned long size;
+
+	size = fb_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));
+}
+
+static struct memtype_reserve msm7x27_reserve_table[] __initdata = {
+	[MEMTYPE_SMI] = {
+	},
+	[MEMTYPE_EBI0] = {
+		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
+	},
+	[MEMTYPE_EBI1] = {
+		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
+	},
+};
+
+static void __init size_pmem_devices(void)
+{
+#ifdef CONFIG_ANDROID_PMEM
+	android_pmem_adsp_pdata.size = pmem_adsp_size;
+	android_pmem_pdata.size = pmem_mdp_size;
+	android_pmem_audio_pdata.size = pmem_audio_size;
+#endif
+}
+
+static void __init reserve_memory_for(struct android_pmem_platform_data *p)
+{
+	msm7x27_reserve_table[p->memory_type].size += p->size;
+}
+
+static void __init reserve_pmem_memory(void)
+{
+#ifdef CONFIG_ANDROID_PMEM
+	reserve_memory_for(&android_pmem_adsp_pdata);
+	reserve_memory_for(&android_pmem_pdata);
+	reserve_memory_for(&android_pmem_audio_pdata);
+	msm7x27_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
+#endif
+}
+
+static void __init msm7x27_calculate_reserve_sizes(void)
+{
+	size_pmem_devices();
+	reserve_pmem_memory();
+}
+
+static int msm7x27_paddr_to_memtype(unsigned int paddr)
+{
+	return MEMTYPE_EBI1;
+}
+
+static struct reserve_info msm7x27_reserve_info __initdata = {
+	.memtype_reserve_table = msm7x27_reserve_table,
+	.calculate_reserve_sizes = msm7x27_calculate_reserve_sizes,
+	.paddr_to_memtype = msm7x27_paddr_to_memtype,
+};
+
+static void __init msm7x27_reserve(void)
+{
+	reserve_info = &msm7x27_reserve_info;
+	msm_reserve();
+}
+
+static void __init msm7x27_init_early(void)
+{
+	msm_msm7x2x_allocate_memory_regions();
 }
 
 static void __init msm7x2x_map_io(void)
 {
 	msm_map_common_io();
-	/* Technically dependent on the SoC but using machine_is
-	 * macros since socinfo is not available this early and there
-	 * are plans to restructure the code which will eliminate the
-	 * need for socinfo.
-	 */
-	if (machine_is_msm7x27_surf() || machine_is_msm7x27_ffa())
-		msm_clock_init(msm_clocks_7x27, msm_num_clocks_7x27);
 
-	if (machine_is_msm7x25_surf() || machine_is_msm7x25_ffa())
-		msm_clock_init(msm_clocks_7x25, msm_num_clocks_7x25);
+	if (socinfo_init() < 0)
+		BUG();
 
 #ifdef CONFIG_CACHE_L2X0
 	if (machine_is_msm7x27_surf() || machine_is_msm7x27_ffa()) {
 		/* 7x27 has 256KB L2 cache:
 			64Kb/Way and 4-Way Associativity;
-			R/W latency: 3 cycles;
 			evmon/parity/share disabled. */
-		l2x0_init(MSM_L2CC_BASE, 0x00068012, 0xfe000000);
+		if ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) > 1)
+			|| ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1)
+			&& (SOCINFO_VERSION_MINOR(socinfo_get_version()) >= 3)))
+			/* R/W latency: 4 cycles; */
+			l2x0_init(MSM_L2CC_BASE, 0x0006801B, 0xfe000000);
+		else
+			/* R/W latency: 3 cycles; */
+			l2x0_init(MSM_L2CC_BASE, 0x00068012, 0xfe000000);
 	}
 #endif
 }
@@ -131,31 +1987,43 @@
 MACHINE_START(MSM7X27_SURF, "QCT MSM7x27 SURF")
 	.atag_offset	= 0x100,
 	.map_io		= msm7x2x_map_io,
+	.reserve	= msm7x27_reserve,
 	.init_irq	= msm7x2x_init_irq,
 	.init_machine	= msm7x2x_init,
 	.timer		= &msm_timer,
+        .init_early     = msm7x27_init_early,
+	.handle_irq     = vic_handle_irq,
 MACHINE_END
 
 MACHINE_START(MSM7X27_FFA, "QCT MSM7x27 FFA")
 	.atag_offset	= 0x100,
 	.map_io		= msm7x2x_map_io,
+	.reserve	= msm7x27_reserve,
 	.init_irq	= msm7x2x_init_irq,
 	.init_machine	= msm7x2x_init,
 	.timer		= &msm_timer,
+        .init_early     = msm7x27_init_early,
+	.handle_irq     = vic_handle_irq,
 MACHINE_END
 
 MACHINE_START(MSM7X25_SURF, "QCT MSM7x25 SURF")
 	.atag_offset	= 0x100,
 	.map_io		= msm7x2x_map_io,
+	.reserve	= msm7x27_reserve,
 	.init_irq	= msm7x2x_init_irq,
 	.init_machine	= msm7x2x_init,
 	.timer		= &msm_timer,
+        .init_early     = msm7x27_init_early,
+	.handle_irq     = vic_handle_irq,
 MACHINE_END
 
 MACHINE_START(MSM7X25_FFA, "QCT MSM7x25 FFA")
 	.atag_offset	= 0x100,
 	.map_io		= msm7x2x_map_io,
+	.reserve	= msm7x27_reserve,
 	.init_irq	= msm7x2x_init_irq,
 	.init_machine	= msm7x2x_init,
 	.timer		= &msm_timer,
+        .init_early     = msm7x27_init_early,
+	.handle_irq     = vic_handle_irq,
 MACHINE_END
diff --git a/arch/arm/mach-msm/board-msm7x27a-regulator.c b/arch/arm/mach-msm/board-msm7x27a-regulator.c
new file mode 100644
index 0000000..c67ab7f
--- /dev/null
+++ b/arch/arm/mach-msm/board-msm7x27a-regulator.c
@@ -0,0 +1,247 @@
+/*
+ * 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
+ * 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/kernel.h>
+#include "board-msm7x27a-regulator.h"
+
+#define VOLTAGE_RANGE(min_uV, max_uV, step_uV)	((max_uV - min_uV) / step_uV)
+
+/* Physically available PMIC regulator voltage setpoint ranges */
+#define p_ranges VOLTAGE_RANGE(1500000, 3300000, 25000)
+
+#define n_ranges VOLTAGE_RANGE(750000, 1525000, 12500)
+
+#define s_ranges (VOLTAGE_RANGE(700000, 1500000, 12500) + \
+			VOLTAGE_RANGE(1500000, 3050000, 25000))
+
+#define PCOM_VREG_CONSUMERS(name) \
+	static struct regulator_consumer_supply __pcom_vreg_supply_##name[]
+
+#define PCOM_VREG_INIT_DATA(_name, _supply, _min_uV, _max_uV, _always_on, \
+		_boot_on, _apply_uV, _supply_uV)\
+{ \
+	.supply_regulator = _supply, \
+	.consumer_supplies = __pcom_vreg_supply_##_name, \
+	.num_consumer_supplies = ARRAY_SIZE(__pcom_vreg_supply_##_name), \
+	.constraints = { \
+		.name = #_name, \
+		.min_uV = _min_uV, \
+		.max_uV = _max_uV, \
+		.valid_modes_mask = REGULATOR_MODE_NORMAL, \
+		.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | \
+				  REGULATOR_CHANGE_STATUS, \
+		.input_uV = _supply_uV, \
+		.apply_uV = _apply_uV, \
+		.boot_on = _boot_on, \
+		.always_on = _always_on \
+	} \
+}
+
+#define PCOM_VREG_SMP(_name, _id, _supply, _min_uV, _max_uV, _rise_time, \
+	_pulldown, _always_on, _boot_on, _apply_uV, _supply_uV, _range) \
+{ \
+	.init_data = PCOM_VREG_INIT_DATA(_name, _supply, _min_uV, _max_uV, \
+			_always_on, _boot_on, _apply_uV, _supply_uV), \
+	.id = _id, \
+	.rise_time = _rise_time, \
+	.pulldown = _pulldown, \
+	.negative = 0, \
+	.n_voltages = _range##_ranges, \
+}
+
+#define PCOM_VREG_LDO PCOM_VREG_SMP
+
+#define PCOM_VREG_NCP(_name, _id, _supply, _min_uV, _max_uV, _rise_time, \
+		_always_on, _boot_on, _apply_uV, _supply_uV) \
+{ \
+	.init_data = PCOM_VREG_INIT_DATA(_name, _supply, -(_min_uV), \
+		-(_max_uV), _always_on, _boot_on, _apply_uV, _supply_uV), \
+	.id = _id, \
+	.rise_time = _rise_time, \
+	.pulldown = -1, \
+	.negative = 1, \
+}
+
+PCOM_VREG_CONSUMERS(smps1) = {
+	REGULATOR_SUPPLY("smps1",	NULL),
+	REGULATOR_SUPPLY("msmc1",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(smps2) = {
+	REGULATOR_SUPPLY("smps2",	NULL),
+	REGULATOR_SUPPLY("msmc2",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(smps3) = {
+	REGULATOR_SUPPLY("smps3",	NULL),
+	REGULATOR_SUPPLY("msme1",	NULL),
+	REGULATOR_SUPPLY("vcc_i2c",	"1-004a"),
+	REGULATOR_SUPPLY("vcc_i2c",	"1-0038"),
+};
+
+PCOM_VREG_CONSUMERS(smps4) = {
+	REGULATOR_SUPPLY("smps4",	NULL),
+	REGULATOR_SUPPLY("rf",		NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo01) = {
+	REGULATOR_SUPPLY("ldo01",	NULL),
+	REGULATOR_SUPPLY("ldo1",	NULL),
+	REGULATOR_SUPPLY("rfrx1",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo02) = {
+	REGULATOR_SUPPLY("ldo02",	NULL),
+	REGULATOR_SUPPLY("ldo2",	NULL),
+	REGULATOR_SUPPLY("rfrx2",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo03) = {
+	REGULATOR_SUPPLY("ldo03",	NULL),
+	REGULATOR_SUPPLY("ldo3",	NULL),
+	REGULATOR_SUPPLY("mddi",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo04) = {
+	REGULATOR_SUPPLY("ldo04",	NULL),
+	REGULATOR_SUPPLY("ldo4",	NULL),
+	REGULATOR_SUPPLY("pllx",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo05) = {
+	REGULATOR_SUPPLY("ldo05",	NULL),
+	REGULATOR_SUPPLY("ldo5",	NULL),
+	REGULATOR_SUPPLY("wlan2",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo06) = {
+	REGULATOR_SUPPLY("ldo06",	NULL),
+	REGULATOR_SUPPLY("ldo6",	NULL),
+	REGULATOR_SUPPLY("wlan3",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo07) = {
+	REGULATOR_SUPPLY("ldo07",	NULL),
+	REGULATOR_SUPPLY("ldo7",	NULL),
+	REGULATOR_SUPPLY("msma",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo08) = {
+	REGULATOR_SUPPLY("ldo08",	NULL),
+	REGULATOR_SUPPLY("ldo8",	NULL),
+	REGULATOR_SUPPLY("tcxo",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo09) = {
+	REGULATOR_SUPPLY("ldo09",	NULL),
+	REGULATOR_SUPPLY("ldo9",	NULL),
+	REGULATOR_SUPPLY("usb2",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo10) = {
+	REGULATOR_SUPPLY("ldo10",	NULL),
+	REGULATOR_SUPPLY("emmc",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo11) = {
+	REGULATOR_SUPPLY("ldo11",	NULL),
+	REGULATOR_SUPPLY("wlan_tcx0",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo12) = {
+	REGULATOR_SUPPLY("ldo12",	NULL),
+	REGULATOR_SUPPLY("gp2",		NULL),
+	REGULATOR_SUPPLY("vdd_ana",	"1-004a"),
+	REGULATOR_SUPPLY("vdd",		"1-0038"),
+};
+
+PCOM_VREG_CONSUMERS(ldo13) = {
+	REGULATOR_SUPPLY("ldo13",	NULL),
+	REGULATOR_SUPPLY("mmc",		NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo14) = {
+	REGULATOR_SUPPLY("ldo14",	NULL),
+	REGULATOR_SUPPLY("usb",		NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo15) = {
+	REGULATOR_SUPPLY("ldo15",	NULL),
+	REGULATOR_SUPPLY("usim2",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo16) = {
+	REGULATOR_SUPPLY("ldo16",	NULL),
+	REGULATOR_SUPPLY("ruim",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo17) = {
+	REGULATOR_SUPPLY("ldo17",	NULL),
+	REGULATOR_SUPPLY("bt",		NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo18) = {
+	REGULATOR_SUPPLY("ldo18",	NULL),
+	REGULATOR_SUPPLY("rftx",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo19) = {
+	REGULATOR_SUPPLY("ldo19",	NULL),
+	REGULATOR_SUPPLY("wlan4",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ncp)   = {
+	REGULATOR_SUPPLY("ncp",		NULL),
+};
+
+static struct proccomm_regulator_info msm7x27a_pcom_vreg_info[] = {
+	/* Standard regulators (SMPS and LDO)
+	 * R = rise time (us)
+	 * P = pulldown (1 = pull down, 0 = float, -1 = don't care)
+	 * A = always on
+	 * B = boot on
+	 * V = automatic voltage set (meaningful for single-voltage regs only)
+	 * S = supply voltage (uV)
+	 * T = type of regulator (smps, pldo, nldo)
+	 *            name   id  supp  min uV    max uV  R   P  A  B  V  S  T*/
+	PCOM_VREG_SMP(smps1,  3, NULL, 1100000, 1100000, 0, -1, 0, 0, 0, 0, s),
+	PCOM_VREG_SMP(smps2,  4, NULL, 1100000, 1100000, 0, -1, 0, 0, 0, 0, s),
+	PCOM_VREG_SMP(smps3,  2, NULL, 1800000, 1800000, 0, -1, 0, 0, 0, 0, s),
+	PCOM_VREG_SMP(smps4, 24, NULL, 2100000, 2100000, 0, -1, 0, 0, 0, 0, s),
+	PCOM_VREG_LDO(ldo01, 12, NULL, 1800000, 2100000, 0, -1, 0, 0, 0, 0, p),
+	PCOM_VREG_LDO(ldo02, 13, NULL, 2850000, 2850000, 0, -1, 0, 0, 0, 0, p),
+	PCOM_VREG_LDO(ldo03, 49, NULL, 1200000, 1200000, 0, -1, 0, 0, 0, 0, n),
+	PCOM_VREG_LDO(ldo04, 50, NULL, 1100000, 1100000, 0, -1, 0, 0, 0, 0, n),
+	PCOM_VREG_LDO(ldo05, 45, NULL, 1300000, 1350000, 0, -1, 0, 0, 0, 0, n),
+	PCOM_VREG_LDO(ldo06, 51, NULL, 1200000, 1200000, 0, -1, 0, 0, 0, 0, n),
+	PCOM_VREG_LDO(ldo07,  0, NULL, 2600000, 2600000, 0, -1, 0, 0, 0, 0, p),
+	PCOM_VREG_LDO(ldo08,  9, NULL, 2850000, 2850000, 0, -1, 0, 0, 0, 0, p),
+	PCOM_VREG_LDO(ldo09, 44, NULL, 1800000, 1800000, 0, -1, 0, 0, 0, 0, p),
+	PCOM_VREG_LDO(ldo10, 52, NULL, 1800000, 3000000, 0, -1, 0, 0, 0, 0, p),
+	PCOM_VREG_LDO(ldo11, 53, NULL, 1800000, 1800000, 0, -1, 0, 0, 0, 0, p),
+	PCOM_VREG_LDO(ldo12, 21, NULL, 2850000, 2850000, 0, -1, 0, 0, 0, 0, p),
+	PCOM_VREG_LDO(ldo13, 18, NULL, 2850000, 2850000, 0, -1, 0, 0, 0, 0, p),
+	PCOM_VREG_LDO(ldo14, 16, NULL, 3300000, 3300000, 0, -1, 0, 0, 0, 0, p),
+	PCOM_VREG_LDO(ldo15, 54, NULL, 1800000, 2850000, 0, -1, 0, 0, 0, 0, p),
+	PCOM_VREG_LDO(ldo16, 19, NULL, 1800000, 2850000, 0, -1, 0, 0, 0, 0, p),
+	PCOM_VREG_LDO(ldo17, 56, NULL, 2900000, 3300000, 0, -1, 0, 0, 0, 0, p),
+	PCOM_VREG_LDO(ldo18, 11, NULL, 2700000, 2700000, 0, -1, 0, 0, 0, 0, p),
+	PCOM_VREG_LDO(ldo19, 57, NULL, 1200000, 1800000, 0, -1, 0, 0, 0, 0, p),
+
+	PCOM_VREG_NCP(ncp,   31, NULL, -1800000, -1800000, 0,     0, 0, 0, 0),
+};
+
+struct proccomm_regulator_platform_data msm7x27a_proccomm_regulator_data = {
+	.regs = msm7x27a_pcom_vreg_info,
+	.nregs = ARRAY_SIZE(msm7x27a_pcom_vreg_info)
+};
diff --git a/arch/arm/mach-msm/board-msm7x27a-regulator.h b/arch/arm/mach-msm/board-msm7x27a-regulator.h
new file mode 100644
index 0000000..01dc70e
--- /dev/null
+++ b/arch/arm/mach-msm/board-msm7x27a-regulator.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_BOARD_7X27A_REGULATOR_H__
+#define __ARCH_ARM_MACH_MSM_BOARD_7X27A_REGULATOR_H__
+
+#include "proccomm-regulator.h"
+
+extern struct proccomm_regulator_platform_data msm7x27a_proccomm_regulator_data;
+
+#endif
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
new file mode 100644
index 0000000..6ecd1e3
--- /dev/null
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -0,0 +1,1261 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio_event.h>
+#include <linux/memblock.h>
+#include <asm/mach-types.h>
+#include <linux/memblock.h>
+#include <asm/mach/arch.h>
+#include <asm/hardware/gic.h>
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_hsusb.h>
+#include <mach/rpc_hsusb.h>
+#include <mach/rpc_pmapp.h>
+#include <mach/usbdiag.h>
+#include <mach/msm_memtypes.h>
+#include <mach/msm_serial_hs.h>
+#include <linux/usb/android.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <mach/vreg.h>
+#include <mach/pmic.h>
+#include <mach/socinfo.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <asm/mach/mmc.h>
+#include <linux/i2c.h>
+#include <linux/i2c/sx150x.h>
+#include <linux/gpio.h>
+#include <linux/android_pmem.h>
+#include <linux/bootmem.h>
+#include <linux/mfd/marimba.h>
+#include <mach/vreg.h>
+#include <linux/power_supply.h>
+#include <linux/regulator/consumer.h>
+#include <mach/rpc_pmapp.h>
+#include <mach/msm_battery.h>
+#include <linux/smsc911x.h>
+#include <linux/atmel_maxtouch.h>
+#include <linux/fmem.h>
+#include <linux/msm_adc.h>
+#include "devices.h"
+#include "timer.h"
+#include "board-msm7x27a-regulator.h"
+#include "devices-msm7x2xa.h"
+#include "pm.h"
+#include <mach/rpc_server_handset.h>
+#include <mach/socinfo.h>
+#include "pm-boot.h"
+#include "board-msm7627a.h"
+
+#define PMEM_KERNEL_EBI1_SIZE	0x3A000
+#define MSM_PMEM_AUDIO_SIZE	0x1F4000
+
+#if defined(CONFIG_GPIO_SX150X)
+enum {
+	SX150X_CORE,
+};
+
+static struct sx150x_platform_data sx150x_data[] __initdata = {
+	[SX150X_CORE]	= {
+		.gpio_base		= GPIO_CORE_EXPANDER_BASE,
+		.oscio_is_gpo		= false,
+		.io_pullup_ena		= 0,
+		.io_pulldn_ena		= 0x02,
+		.io_open_drain_ena	= 0xfef8,
+		.irq_summary		= -1,
+	},
+};
+#endif
+
+
+#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
+static struct platform_device msm_wlan_ar6000_pm_device = {
+	.name           = "wlan_ar6000_pm_dev",
+	.id             = -1,
+};
+#endif
+
+#if defined(CONFIG_I2C) && defined(CONFIG_GPIO_SX150X)
+static struct i2c_board_info core_exp_i2c_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("sx1509q", 0x3e),
+	},
+};
+
+static void __init register_i2c_devices(void)
+{
+	if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf() ||
+			machine_is_msm8625_surf())
+		sx150x_data[SX150X_CORE].io_open_drain_ena = 0xe0f0;
+
+	core_exp_i2c_info[0].platform_data =
+			&sx150x_data[SX150X_CORE];
+
+	i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
+				core_exp_i2c_info,
+				ARRAY_SIZE(core_exp_i2c_info));
+}
+#endif
+
+static struct msm_gpio qup_i2c_gpios_io[] = {
+	{ GPIO_CFG(60, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
+		"qup_scl" },
+	{ GPIO_CFG(61, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
+		"qup_sda" },
+	{ GPIO_CFG(131, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
+		"qup_scl" },
+	{ GPIO_CFG(132, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
+		"qup_sda" },
+};
+
+static struct msm_gpio qup_i2c_gpios_hw[] = {
+	{ GPIO_CFG(60, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
+		"qup_scl" },
+	{ GPIO_CFG(61, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
+		"qup_sda" },
+	{ GPIO_CFG(131, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
+		"qup_scl" },
+	{ GPIO_CFG(132, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
+		"qup_sda" },
+};
+
+static void gsbi_qup_i2c_gpio_config(int adap_id, int config_type)
+{
+	int rc;
+
+	if (adap_id < 0 || adap_id > 1)
+		return;
+
+	/* Each adapter gets 2 lines from the table */
+	if (config_type)
+		rc = msm_gpios_request_enable(&qup_i2c_gpios_hw[adap_id*2], 2);
+	else
+		rc = msm_gpios_request_enable(&qup_i2c_gpios_io[adap_id*2], 2);
+	if (rc < 0)
+		pr_err("QUP GPIO request/enable failed: %d\n", rc);
+}
+
+static struct msm_i2c_platform_data msm_gsbi0_qup_i2c_pdata = {
+	.clk_freq		= 100000,
+	.msm_i2c_config_gpio	= gsbi_qup_i2c_gpio_config,
+};
+
+static struct msm_i2c_platform_data msm_gsbi1_qup_i2c_pdata = {
+	.clk_freq		= 100000,
+	.msm_i2c_config_gpio	= gsbi_qup_i2c_gpio_config,
+};
+
+#ifdef CONFIG_ARCH_MSM7X27A
+#define MSM_PMEM_MDP_SIZE       0x2300000
+#define MSM7x25A_MSM_PMEM_MDP_SIZE       0x1500000
+
+#define MSM_PMEM_ADSP_SIZE      0x1100000
+#define MSM7x25A_MSM_PMEM_ADSP_SIZE      0xB91000
+
+#endif
+
+static struct android_usb_platform_data android_usb_pdata = {
+	.update_pid_and_serial_num = usb_diag_update_pid_and_serial_num,
+};
+
+static struct platform_device android_usb_device = {
+	.name	= "android_usb",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &android_usb_pdata,
+	},
+};
+
+#ifdef CONFIG_USB_EHCI_MSM_72K
+static void msm_hsusb_vbus_power(unsigned phy_info, int on)
+{
+	int rc = 0;
+	unsigned gpio;
+
+	gpio = GPIO_HOST_VBUS_EN;
+
+	rc = gpio_request(gpio, "i2c_host_vbus_en");
+	if (rc < 0) {
+		pr_err("failed to request %d GPIO\n", gpio);
+		return;
+	}
+	gpio_direction_output(gpio, !!on);
+	gpio_set_value_cansleep(gpio, !!on);
+	gpio_free(gpio);
+}
+
+static struct msm_usb_host_platform_data msm_usb_host_pdata = {
+	.phy_info       = (USB_PHY_INTEGRATED | USB_PHY_MODEL_45NM),
+};
+
+static void __init msm7x2x_init_host(void)
+{
+	msm_add_host(0, &msm_usb_host_pdata);
+}
+#endif
+
+#ifdef CONFIG_USB_MSM_OTG_72K
+static int hsusb_rpc_connect(int connect)
+{
+	if (connect)
+		return msm_hsusb_rpc_connect();
+	else
+		return msm_hsusb_rpc_close();
+}
+
+static struct regulator *reg_hsusb;
+static int msm_hsusb_ldo_init(int init)
+{
+	int rc = 0;
+
+	if (init) {
+		reg_hsusb = regulator_get(NULL, "usb");
+		if (IS_ERR(reg_hsusb)) {
+			rc = PTR_ERR(reg_hsusb);
+			pr_err("%s: could not get regulator: %d\n",
+					__func__, rc);
+			goto out;
+		}
+
+		rc = regulator_set_voltage(reg_hsusb, 3300000, 3300000);
+		if (rc) {
+			pr_err("%s: could not set voltage: %d\n",
+					__func__, rc);
+			goto reg_free;
+		}
+
+		return 0;
+	}
+	/* else fall through */
+reg_free:
+	regulator_put(reg_hsusb);
+out:
+	reg_hsusb = NULL;
+	return rc;
+}
+
+static int msm_hsusb_ldo_enable(int enable)
+{
+	static int ldo_status;
+
+	if (IS_ERR_OR_NULL(reg_hsusb))
+		return reg_hsusb ? PTR_ERR(reg_hsusb) : -ENODEV;
+
+	if (ldo_status == enable)
+		return 0;
+
+	ldo_status = enable;
+
+	return enable ?
+		regulator_enable(reg_hsusb) :
+		regulator_disable(reg_hsusb);
+}
+
+#ifndef CONFIG_USB_EHCI_MSM_72K
+static int msm_hsusb_pmic_notif_init(void (*callback)(int online), int init)
+{
+	int ret = 0;
+
+	if (init)
+		ret = msm_pm_app_rpc_init(callback);
+	else
+		msm_pm_app_rpc_deinit(callback);
+
+	return ret;
+}
+#endif
+
+static struct msm_otg_platform_data msm_otg_pdata = {
+#ifndef CONFIG_USB_EHCI_MSM_72K
+	.pmic_vbus_notif_init	 = msm_hsusb_pmic_notif_init,
+#else
+	.vbus_power		 = msm_hsusb_vbus_power,
+#endif
+	.rpc_connect		 = hsusb_rpc_connect,
+	.pemp_level		 = PRE_EMPHASIS_WITH_20_PERCENT,
+	.cdr_autoreset		 = CDR_AUTO_RESET_DISABLE,
+	.drv_ampl		 = HS_DRV_AMPLITUDE_DEFAULT,
+	.se1_gating		 = SE1_GATING_DISABLE,
+	.ldo_init		 = msm_hsusb_ldo_init,
+	.ldo_enable		 = msm_hsusb_ldo_enable,
+	.chg_init		 = hsusb_chg_init,
+	.chg_connected		 = hsusb_chg_connected,
+	.chg_vbus_draw		 = hsusb_chg_vbus_draw,
+};
+#endif
+
+static struct msm_hsusb_gadget_platform_data msm_gadget_pdata = {
+	.is_phy_status_timer_on = 1,
+};
+
+static struct resource smc91x_resources[] = {
+	[0] = {
+		.start = 0x90000300,
+		.end   = 0x900003ff,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = MSM_GPIO_TO_INT(4),
+		.end   = MSM_GPIO_TO_INT(4),
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device smc91x_device = {
+	.name           = "smc91x",
+	.id             = 0,
+	.num_resources  = ARRAY_SIZE(smc91x_resources),
+	.resource       = smc91x_resources,
+};
+
+#ifdef CONFIG_SERIAL_MSM_HS
+static struct msm_serial_hs_platform_data msm_uart_dm1_pdata = {
+	.inject_rx_on_wakeup	= 1,
+	.rx_to_inject		= 0xFD,
+};
+#endif
+static struct msm_pm_platform_data msm7x27a_pm_data[MSM_PM_SLEEP_MODE_NR] = {
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 1,
+					.suspend_enabled = 1,
+					.latency = 16000,
+					.residency = 20000,
+	},
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 1,
+					.suspend_enabled = 1,
+					.latency = 12000,
+					.residency = 20000,
+	},
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 0,
+					.suspend_enabled = 1,
+					.latency = 2000,
+					.residency = 0,
+	},
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 1,
+					.suspend_enabled = 1,
+					.latency = 2,
+					.residency = 0,
+	},
+};
+
+static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS,
+	.p_addr = 0,
+};
+
+/* 8625 PM platform data */
+static struct msm_pm_platform_data msm8625_pm_data[MSM_PM_SLEEP_MODE_NR * 2] = {
+	/* CORE0 entries */
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 0,
+					.suspend_enabled = 0,
+					.latency = 16000,
+					.residency = 20000,
+	},
+
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 0,
+					.suspend_enabled = 0,
+					.latency = 12000,
+					.residency = 20000,
+	},
+
+	/* picked latency & redisdency values from 7x30 */
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 0,
+					.suspend_enabled = 0,
+					.latency = 500,
+					.residency = 6000,
+	},
+
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 1,
+					.suspend_enabled = 1,
+					.latency = 2,
+					.residency = 10,
+	},
+
+	/* picked latency & redisdency values from 7x30 */
+	[MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 0,
+					.suspend_enabled = 0,
+					.latency = 500,
+					.residency = 6000,
+	},
+
+	[MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 1,
+					.suspend_enabled = 1,
+					.latency = 2,
+					.residency = 10,
+	},
+
+};
+
+static struct msm_pm_boot_platform_data msm_pm_8625_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR,
+	.v_addr = MSM_CFG_CTL_BASE,
+};
+
+static struct android_pmem_platform_data android_pmem_adsp_pdata = {
+	.name = "pmem_adsp",
+	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
+	.cached = 1,
+	.memory_type = MEMTYPE_EBI1,
+	.request_region = request_fmem_c_region,
+	.release_region = release_fmem_c_region,
+	.reusable = 1,
+};
+
+static struct platform_device android_pmem_adsp_device = {
+	.name = "android_pmem",
+	.id = 1,
+	.dev = { .platform_data = &android_pmem_adsp_pdata },
+};
+
+static unsigned pmem_mdp_size = MSM_PMEM_MDP_SIZE;
+static int __init pmem_mdp_size_setup(char *p)
+{
+	pmem_mdp_size = memparse(p, NULL);
+	return 0;
+}
+
+early_param("pmem_mdp_size", pmem_mdp_size_setup);
+
+static unsigned pmem_adsp_size = MSM_PMEM_ADSP_SIZE;
+static int __init pmem_adsp_size_setup(char *p)
+{
+	pmem_adsp_size = memparse(p, NULL);
+	return 0;
+}
+
+early_param("pmem_adsp_size", pmem_adsp_size_setup);
+
+#define SND(desc, num) { .name = #desc, .id = num }
+static struct snd_endpoint snd_endpoints_list[] = {
+	SND(HANDSET, 0),
+	SND(MONO_HEADSET, 2),
+	SND(HEADSET, 3),
+	SND(SPEAKER, 6),
+	SND(TTY_HEADSET, 8),
+	SND(TTY_VCO, 9),
+	SND(TTY_HCO, 10),
+	SND(BT, 12),
+	SND(IN_S_SADC_OUT_HANDSET, 16),
+	SND(IN_S_SADC_OUT_SPEAKER_PHONE, 25),
+	SND(FM_DIGITAL_STEREO_HEADSET, 26),
+	SND(FM_DIGITAL_SPEAKER_PHONE, 27),
+	SND(FM_DIGITAL_BT_A2DP_HEADSET, 28),
+	SND(STEREO_HEADSET_AND_SPEAKER, 31),
+	SND(CURRENT, 0x7FFFFFFE),
+	SND(FM_ANALOG_STEREO_HEADSET, 35),
+	SND(FM_ANALOG_STEREO_HEADSET_CODEC, 36),
+};
+#undef SND
+
+static struct msm_snd_endpoints msm_device_snd_endpoints = {
+	.endpoints = snd_endpoints_list,
+	.num = sizeof(snd_endpoints_list) / sizeof(struct snd_endpoint)
+};
+
+static struct platform_device msm_device_snd = {
+	.name = "msm_snd",
+	.id = -1,
+	.dev    = {
+		.platform_data = &msm_device_snd_endpoints
+	},
+};
+
+#define DEC0_FORMAT ((1<<MSM_ADSP_CODEC_MP3)| \
+	(1<<MSM_ADSP_CODEC_AAC)|(1<<MSM_ADSP_CODEC_WMA)| \
+	(1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \
+	(1<<MSM_ADSP_CODEC_AMRNB)|(1<<MSM_ADSP_CODEC_WAV)| \
+	(1<<MSM_ADSP_CODEC_ADPCM)|(1<<MSM_ADSP_CODEC_YADPCM)| \
+	(1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP))
+#define DEC1_FORMAT ((1<<MSM_ADSP_CODEC_MP3)| \
+	(1<<MSM_ADSP_CODEC_AAC)|(1<<MSM_ADSP_CODEC_WMA)| \
+	(1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \
+	(1<<MSM_ADSP_CODEC_AMRNB)|(1<<MSM_ADSP_CODEC_WAV)| \
+	(1<<MSM_ADSP_CODEC_ADPCM)|(1<<MSM_ADSP_CODEC_YADPCM)| \
+	(1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP))
+#define DEC2_FORMAT ((1<<MSM_ADSP_CODEC_MP3)| \
+	(1<<MSM_ADSP_CODEC_AAC)|(1<<MSM_ADSP_CODEC_WMA)| \
+	(1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \
+	(1<<MSM_ADSP_CODEC_AMRNB)|(1<<MSM_ADSP_CODEC_WAV)| \
+	(1<<MSM_ADSP_CODEC_ADPCM)|(1<<MSM_ADSP_CODEC_YADPCM)| \
+	(1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP))
+#define DEC3_FORMAT ((1<<MSM_ADSP_CODEC_MP3)| \
+	(1<<MSM_ADSP_CODEC_AAC)|(1<<MSM_ADSP_CODEC_WMA)| \
+	(1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \
+	(1<<MSM_ADSP_CODEC_AMRNB)|(1<<MSM_ADSP_CODEC_WAV)| \
+	(1<<MSM_ADSP_CODEC_ADPCM)|(1<<MSM_ADSP_CODEC_YADPCM)| \
+	(1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP))
+#define DEC4_FORMAT (1<<MSM_ADSP_CODEC_MIDI)
+
+static unsigned int dec_concurrency_table[] = {
+	/* Audio LP */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DMA)), 0,
+	0, 0, 0,
+
+	/* Concurrency 1 */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC4_FORMAT),
+
+	 /* Concurrency 2 */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC4_FORMAT),
+
+	/* Concurrency 3 */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC4_FORMAT),
+
+	/* Concurrency 4 */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC4_FORMAT),
+
+	/* Concurrency 5 */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC4_FORMAT),
+
+	/* Concurrency 6 */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|
+			(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	0, 0, 0, 0,
+
+	/* Concurrency 7 */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC4_FORMAT),
+};
+
+#define DEC_INFO(name, queueid, decid, nr_codec) { .module_name = name, \
+	.module_queueid = queueid, .module_decid = decid, \
+	.nr_codec_support = nr_codec}
+
+static struct msm_adspdec_info dec_info_list[] = {
+	DEC_INFO("AUDPLAY0TASK", 13, 0, 11), /* AudPlay0BitStreamCtrlQueue */
+	DEC_INFO("AUDPLAY1TASK", 14, 1, 11),  /* AudPlay1BitStreamCtrlQueue */
+	DEC_INFO("AUDPLAY2TASK", 15, 2, 11),  /* AudPlay2BitStreamCtrlQueue */
+	DEC_INFO("AUDPLAY3TASK", 16, 3, 11),  /* AudPlay3BitStreamCtrlQueue */
+	DEC_INFO("AUDPLAY4TASK", 17, 4, 1),  /* AudPlay4BitStreamCtrlQueue */
+};
+
+static struct msm_adspdec_database msm_device_adspdec_database = {
+	.num_dec = ARRAY_SIZE(dec_info_list),
+	.num_concurrency_support = (ARRAY_SIZE(dec_concurrency_table) / \
+					ARRAY_SIZE(dec_info_list)),
+	.dec_concurrency_table = dec_concurrency_table,
+	.dec_info_list = dec_info_list,
+};
+
+static struct platform_device msm_device_adspdec = {
+	.name = "msm_adspdec",
+	.id = -1,
+	.dev    = {
+		.platform_data = &msm_device_adspdec_database
+	},
+};
+
+static struct android_pmem_platform_data android_pmem_audio_pdata = {
+	.name = "pmem_audio",
+	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
+	.cached = 0,
+	.memory_type = MEMTYPE_EBI1,
+};
+
+static struct platform_device android_pmem_audio_device = {
+	.name = "android_pmem",
+	.id = 2,
+	.dev = { .platform_data = &android_pmem_audio_pdata },
+};
+
+static struct android_pmem_platform_data android_pmem_pdata = {
+	.name = "pmem",
+	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
+	.cached = 1,
+	.memory_type = MEMTYPE_EBI1,
+};
+static struct platform_device android_pmem_device = {
+	.name = "android_pmem",
+	.id = 0,
+	.dev = { .platform_data = &android_pmem_pdata },
+};
+
+static u32 msm_calculate_batt_capacity(u32 current_voltage);
+
+static struct msm_psy_batt_pdata msm_psy_batt_data = {
+	.voltage_min_design     = 2800,
+	.voltage_max_design     = 4300,
+	.avail_chg_sources      = AC_CHG | USB_CHG ,
+	.batt_technology        = POWER_SUPPLY_TECHNOLOGY_LION,
+	.calculate_capacity     = &msm_calculate_batt_capacity,
+};
+
+static u32 msm_calculate_batt_capacity(u32 current_voltage)
+{
+	u32 low_voltage	 = msm_psy_batt_data.voltage_min_design;
+	u32 high_voltage = msm_psy_batt_data.voltage_max_design;
+
+	return (current_voltage - low_voltage) * 100
+			/ (high_voltage - low_voltage);
+}
+
+static struct platform_device msm_batt_device = {
+	.name               = "msm-battery",
+	.id                 = -1,
+	.dev.platform_data  = &msm_psy_batt_data,
+};
+
+static struct smsc911x_platform_config smsc911x_config = {
+	.irq_polarity	= SMSC911X_IRQ_POLARITY_ACTIVE_HIGH,
+	.irq_type	= SMSC911X_IRQ_TYPE_PUSH_PULL,
+	.flags		= SMSC911X_USE_16BIT,
+};
+
+static struct resource smsc911x_resources[] = {
+	[0] = {
+		.start	= 0x90000000,
+		.end	= 0x90007fff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= MSM_GPIO_TO_INT(48),
+		.end	= MSM_GPIO_TO_INT(48),
+		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+};
+
+static struct platform_device smsc911x_device = {
+	.name		= "smsc911x",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(smsc911x_resources),
+	.resource	= smsc911x_resources,
+	.dev		= {
+		.platform_data	= &smsc911x_config,
+	},
+};
+
+static struct msm_gpio smsc911x_gpios[] = {
+	{ GPIO_CFG(48, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_6MA),
+							 "smsc911x_irq"  },
+	{ GPIO_CFG(49, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_6MA),
+							 "eth_fifo_sel" },
+};
+
+static char *msm_adc_surf_device_names[] = {
+	"XO_ADC",
+};
+
+static struct msm_adc_platform_data msm_adc_pdata = {
+	.dev_names = msm_adc_surf_device_names,
+	.num_adc = ARRAY_SIZE(msm_adc_surf_device_names),
+	.target_hw = MSM_8x25,
+};
+
+static struct platform_device msm_adc_device = {
+	.name   = "msm_adc",
+	.id = -1,
+	.dev = {
+		.platform_data = &msm_adc_pdata,
+	},
+};
+
+#define ETH_FIFO_SEL_GPIO	49
+static void msm7x27a_cfg_smsc911x(void)
+{
+	int res;
+
+	res = msm_gpios_request_enable(smsc911x_gpios,
+				 ARRAY_SIZE(smsc911x_gpios));
+	if (res) {
+		pr_err("%s: unable to enable gpios for SMSC911x\n", __func__);
+		return;
+	}
+
+	/* ETH_FIFO_SEL */
+	res = gpio_direction_output(ETH_FIFO_SEL_GPIO, 0);
+	if (res) {
+		pr_err("%s: unable to get direction for gpio %d\n", __func__,
+							 ETH_FIFO_SEL_GPIO);
+		msm_gpios_disable_free(smsc911x_gpios,
+						 ARRAY_SIZE(smsc911x_gpios));
+		return;
+	}
+	gpio_set_value(ETH_FIFO_SEL_GPIO, 0);
+}
+
+#if defined(CONFIG_SERIAL_MSM_HSL_CONSOLE) \
+		&& defined(CONFIG_MSM_SHARED_GPIO_FOR_UART2DM)
+static struct msm_gpio uart2dm_gpios[] = {
+	{GPIO_CFG(19, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+							"uart2dm_rfr_n" },
+	{GPIO_CFG(20, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+							"uart2dm_cts_n" },
+	{GPIO_CFG(21, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+							"uart2dm_rx"    },
+	{GPIO_CFG(108, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+							"uart2dm_tx"    },
+};
+
+static void msm7x27a_cfg_uart2dm_serial(void)
+{
+	int ret;
+	ret = msm_gpios_request_enable(uart2dm_gpios,
+					ARRAY_SIZE(uart2dm_gpios));
+	if (ret)
+		pr_err("%s: unable to enable gpios for uart2dm\n", __func__);
+}
+#else
+static void msm7x27a_cfg_uart2dm_serial(void) { }
+#endif
+
+static struct fmem_platform_data fmem_pdata;
+
+static struct platform_device fmem_device = {
+	.name = "fmem",
+	.id = 1,
+	.dev = { .platform_data = &fmem_pdata },
+};
+
+static struct platform_device *rumi_sim_devices[] __initdata = {
+	&msm_device_dmov,
+	&msm_device_smd,
+	&smc91x_device,
+	&msm_device_uart1,
+	&msm_device_nand,
+	&msm_device_uart_dm1,
+	&msm_gsbi0_qup_i2c_device,
+	&msm_gsbi1_qup_i2c_device,
+};
+
+static struct platform_device *msm8625_rumi3_devices[] __initdata = {
+	&msm8625_device_dmov,
+	&msm8625_device_smd,
+	&msm8625_device_uart1,
+	&msm8625_gsbi0_qup_i2c_device,
+};
+
+static struct platform_device *msm7627a_surf_ffa_devices[] __initdata = {
+	&msm_device_dmov,
+	&msm_device_smd,
+	&msm_device_uart1,
+	&msm_device_uart_dm1,
+	&msm_device_uart_dm2,
+	&msm_gsbi0_qup_i2c_device,
+	&msm_gsbi1_qup_i2c_device,
+	&msm_device_otg,
+	&msm_device_gadget_peripheral,
+	&smsc911x_device,
+	&msm_kgsl_3d0,
+};
+
+static struct platform_device *common_devices[] __initdata = {
+	&android_usb_device,
+	&android_pmem_device,
+	&android_pmem_adsp_device,
+	&android_pmem_audio_device,
+	&fmem_device,
+	&msm_device_nand,
+	&msm_device_snd,
+	&msm_device_adspdec,
+	&asoc_msm_pcm,
+	&asoc_msm_dai0,
+	&asoc_msm_dai1,
+	&msm_batt_device,
+	&msm_adc_device,
+};
+
+static struct platform_device *msm8625_surf_devices[] __initdata = {
+	&msm8625_device_dmov,
+	&msm8625_device_uart1,
+	&msm8625_device_uart_dm1,
+	&msm8625_device_uart_dm2,
+	&msm8625_gsbi0_qup_i2c_device,
+	&msm8625_gsbi1_qup_i2c_device,
+	&msm8625_device_smd,
+	&msm8625_device_otg,
+	&msm8625_device_gadget_peripheral,
+	&msm8625_kgsl_3d0,
+};
+
+static unsigned pmem_kernel_ebi1_size = PMEM_KERNEL_EBI1_SIZE;
+static int __init pmem_kernel_ebi1_size_setup(char *p)
+{
+	pmem_kernel_ebi1_size = memparse(p, NULL);
+	return 0;
+}
+early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
+
+static unsigned pmem_audio_size = MSM_PMEM_AUDIO_SIZE;
+static int __init pmem_audio_size_setup(char *p)
+{
+	pmem_audio_size = memparse(p, NULL);
+	return 0;
+}
+early_param("pmem_audio_size", pmem_audio_size_setup);
+
+static struct memtype_reserve msm7x27a_reserve_table[] __initdata = {
+	[MEMTYPE_SMI] = {
+	},
+	[MEMTYPE_EBI0] = {
+		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
+	},
+	[MEMTYPE_EBI1] = {
+		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
+	},
+};
+
+#ifdef CONFIG_ANDROID_PMEM
+static struct android_pmem_platform_data *pmem_pdata_array[] __initdata = {
+		&android_pmem_adsp_pdata,
+		&android_pmem_audio_pdata,
+		&android_pmem_pdata,
+};
+#endif
+
+static void __init size_pmem_devices(void)
+{
+#ifdef CONFIG_ANDROID_PMEM
+	unsigned int i;
+	unsigned int reusable_count = 0;
+
+	if (machine_is_msm7625a_surf() || machine_is_msm7625a_ffa()) {
+		pmem_mdp_size = MSM7x25A_MSM_PMEM_MDP_SIZE;
+		pmem_adsp_size = MSM7x25A_MSM_PMEM_ADSP_SIZE;
+	} else {
+		pmem_mdp_size = MSM_PMEM_MDP_SIZE;
+		pmem_adsp_size = MSM_PMEM_ADSP_SIZE;
+	}
+
+	android_pmem_adsp_pdata.size = pmem_adsp_size;
+	android_pmem_pdata.size = pmem_mdp_size;
+	android_pmem_audio_pdata.size = pmem_audio_size;
+
+	fmem_pdata.size = 0;
+	fmem_pdata.align = PAGE_SIZE;
+
+	/* Find pmem devices that should use FMEM (reusable) memory.
+	 */
+	for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i) {
+		struct android_pmem_platform_data *pdata = pmem_pdata_array[i];
+
+		if (!reusable_count && pdata->reusable)
+			fmem_pdata.size += pdata->size;
+
+		reusable_count += (pdata->reusable) ? 1 : 0;
+
+		if (pdata->reusable && reusable_count > 1) {
+			pr_err("%s: Too many PMEM devices specified as reusable. PMEM device %s was not configured as reusable.\n",
+				__func__, pdata->name);
+			pdata->reusable = 0;
+		}
+	}
+#endif
+
+}
+
+static void __init reserve_memory_for(struct android_pmem_platform_data *p)
+{
+	msm7x27a_reserve_table[p->memory_type].size += p->size;
+}
+
+static void __init reserve_pmem_memory(void)
+{
+#ifdef CONFIG_ANDROID_PMEM
+	unsigned int i;
+	for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i)
+		reserve_memory_for(pmem_pdata_array[i]);
+
+	msm7x27a_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
+#endif
+}
+
+static void __init msm7x27a_calculate_reserve_sizes(void)
+{
+	size_pmem_devices();
+	reserve_pmem_memory();
+}
+
+static int msm7x27a_paddr_to_memtype(unsigned int paddr)
+{
+	return MEMTYPE_EBI1;
+}
+
+static struct reserve_info msm7x27a_reserve_info __initdata = {
+	.memtype_reserve_table = msm7x27a_reserve_table,
+	.calculate_reserve_sizes = msm7x27a_calculate_reserve_sizes,
+	.paddr_to_memtype = msm7x27a_paddr_to_memtype,
+};
+
+static void __init msm7x27a_reserve(void)
+{
+	reserve_info = &msm7x27a_reserve_info;
+	msm_reserve();
+}
+
+static void __init msm8625_reserve(void)
+{
+	msm7x27a_reserve();
+	memblock_remove(MSM8625_SECONDARY_PHYS, SZ_8);
+	memblock_remove(MSM8625_WARM_BOOT_PHYS, SZ_32);
+}
+
+static void __init msm7x27a_device_i2c_init(void)
+{
+	msm_gsbi0_qup_i2c_device.dev.platform_data = &msm_gsbi0_qup_i2c_pdata;
+	msm_gsbi1_qup_i2c_device.dev.platform_data = &msm_gsbi1_qup_i2c_pdata;
+}
+
+static void __init msm8625_device_i2c_init(void)
+{
+	msm8625_gsbi0_qup_i2c_device.dev.platform_data =
+		&msm_gsbi0_qup_i2c_pdata;
+	msm8625_gsbi1_qup_i2c_device.dev.platform_data =
+		&msm_gsbi1_qup_i2c_pdata;
+}
+
+#define MSM_EBI2_PHYS			0xa0d00000
+#define MSM_EBI2_XMEM_CS2_CFG1		0xa0d10030
+
+static void __init msm7x27a_init_ebi2(void)
+{
+	uint32_t ebi2_cfg;
+	void __iomem *ebi2_cfg_ptr;
+
+	ebi2_cfg_ptr = ioremap_nocache(MSM_EBI2_PHYS, sizeof(uint32_t));
+	if (!ebi2_cfg_ptr)
+		return;
+
+	ebi2_cfg = readl(ebi2_cfg_ptr);
+	if (machine_is_msm7x27a_rumi3() || machine_is_msm7x27a_surf() ||
+		machine_is_msm7625a_surf() || machine_is_msm8625_surf())
+		ebi2_cfg |= (1 << 4); /* CS2 */
+
+	writel(ebi2_cfg, ebi2_cfg_ptr);
+	iounmap(ebi2_cfg_ptr);
+
+	/* Enable A/D MUX[bit 31] from EBI2_XMEM_CS2_CFG1 */
+	ebi2_cfg_ptr = ioremap_nocache(MSM_EBI2_XMEM_CS2_CFG1,
+							 sizeof(uint32_t));
+	if (!ebi2_cfg_ptr)
+		return;
+
+	ebi2_cfg = readl(ebi2_cfg_ptr);
+	if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf())
+		ebi2_cfg |= (1 << 31);
+
+	writel(ebi2_cfg, ebi2_cfg_ptr);
+	iounmap(ebi2_cfg_ptr);
+}
+
+static struct platform_device msm_proccomm_regulator_dev = {
+	.name   = PROCCOMM_REGULATOR_DEV_NAME,
+	.id     = -1,
+	.dev    = {
+		.platform_data = &msm7x27a_proccomm_regulator_data
+	}
+};
+
+static void msm_adsp_add_pdev(void)
+{
+	int rc = 0;
+	struct rpc_board_dev *rpc_adsp_pdev;
+
+	rpc_adsp_pdev = kzalloc(sizeof(struct rpc_board_dev), GFP_KERNEL);
+	if (rpc_adsp_pdev == NULL) {
+		pr_err("%s: Memory Allocation failure\n", __func__);
+		return;
+	}
+	rpc_adsp_pdev->prog = ADSP_RPC_PROG;
+
+	if (cpu_is_msm8625())
+		rpc_adsp_pdev->pdev = msm8625_device_adsp;
+	else
+		rpc_adsp_pdev->pdev = msm_adsp_device;
+	rc = msm_rpc_add_board_dev(rpc_adsp_pdev, 1);
+	if (rc < 0) {
+		pr_err("%s: return val: %d\n",	__func__, rc);
+		kfree(rpc_adsp_pdev);
+	}
+}
+
+static void __init msm7627a_rumi3_init(void)
+{
+	msm7x27a_init_ebi2();
+	platform_add_devices(rumi_sim_devices,
+			ARRAY_SIZE(rumi_sim_devices));
+}
+
+static void __init msm8625_rumi3_init(void)
+{
+	msm7x2x_misc_init();
+	msm_adsp_add_pdev();
+	msm8625_device_i2c_init();
+	platform_add_devices(msm8625_rumi3_devices,
+			ARRAY_SIZE(msm8625_rumi3_devices));
+
+	msm_pm_set_platform_data(msm8625_pm_data,
+			 ARRAY_SIZE(msm8625_pm_data));
+	BUG_ON(msm_pm_boot_init(&msm_pm_8625_boot_pdata));
+	msm8x25_spm_device_init();
+}
+
+#define UART1DM_RX_GPIO		45
+
+#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
+static int __init msm7x27a_init_ar6000pm(void)
+{
+	msm_wlan_ar6000_pm_device.dev.platform_data = &ar600x_wlan_power;
+	return platform_device_register(&msm_wlan_ar6000_pm_device);
+}
+#else
+static int __init msm7x27a_init_ar6000pm(void) { return 0; }
+#endif
+
+static void __init msm7x27a_init_regulators(void)
+{
+	int rc = platform_device_register(&msm_proccomm_regulator_dev);
+	if (rc)
+		pr_err("%s: could not register regulator device: %d\n",
+				__func__, rc);
+}
+
+static void __init msm7x27a_add_footswitch_devices(void)
+{
+	platform_add_devices(msm_footswitch_devices,
+			msm_num_footswitch_devices);
+}
+
+static void __init msm7x27a_add_platform_devices(void)
+{
+	if (machine_is_msm8625_surf() || machine_is_msm8625_ffa()) {
+		platform_add_devices(msm8625_surf_devices,
+			ARRAY_SIZE(msm8625_surf_devices));
+	} else {
+		platform_add_devices(msm7627a_surf_ffa_devices,
+			ARRAY_SIZE(msm7627a_surf_ffa_devices));
+	}
+
+	platform_add_devices(common_devices,
+			ARRAY_SIZE(common_devices));
+}
+
+static void __init msm7x27a_uartdm_config(void)
+{
+	msm7x27a_cfg_uart2dm_serial();
+	msm_uart_dm1_pdata.wakeup_irq = gpio_to_irq(UART1DM_RX_GPIO);
+	if (cpu_is_msm8625())
+		msm8625_device_uart_dm1.dev.platform_data =
+			&msm_uart_dm1_pdata;
+	else
+		msm_device_uart_dm1.dev.platform_data = &msm_uart_dm1_pdata;
+}
+
+static void __init msm7x27a_otg_gadget(void)
+{
+	if (cpu_is_msm8625()) {
+		msm_otg_pdata.swfi_latency =
+		msm8625_pm_data[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].latency;
+		msm8625_device_otg.dev.platform_data = &msm_otg_pdata;
+		msm8625_device_gadget_peripheral.dev.platform_data =
+			&msm_gadget_pdata;
+	} else {
+		msm_otg_pdata.swfi_latency =
+		msm7x27a_pm_data[
+		MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency;
+		msm_device_otg.dev.platform_data = &msm_otg_pdata;
+		msm_device_gadget_peripheral.dev.platform_data =
+			&msm_gadget_pdata;
+	}
+}
+
+static void __init msm7x27a_pm_init(void)
+{
+	if (machine_is_msm8625_surf() || machine_is_msm8625_ffa()) {
+		msm_pm_set_platform_data(msm8625_pm_data,
+				ARRAY_SIZE(msm8625_pm_data));
+		BUG_ON(msm_pm_boot_init(&msm_pm_8625_boot_pdata));
+		msm8x25_spm_device_init();
+	} else {
+		msm_pm_set_platform_data(msm7x27a_pm_data,
+				ARRAY_SIZE(msm7x27a_pm_data));
+		BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+	}
+
+	msm_pm_register_irqs();
+}
+
+static void __init msm7x2x_init(void)
+{
+	msm7x2x_misc_init();
+
+	/* Initialize regulators first so that other devices can use them */
+	msm7x27a_init_regulators();
+	msm_adsp_add_pdev();
+	if (cpu_is_msm8625())
+		msm8625_device_i2c_init();
+	else
+		msm7x27a_device_i2c_init();
+	msm7x27a_init_ebi2();
+	msm7x27a_uartdm_config();
+
+	msm7x27a_otg_gadget();
+	msm7x27a_cfg_smsc911x();
+
+	msm7x27a_add_footswitch_devices();
+	msm7x27a_add_platform_devices();
+	/* Ensure ar6000pm device is registered before MMC/SDC */
+	msm7x27a_init_ar6000pm();
+	msm7627a_init_mmc();
+	msm_fb_add_devices();
+	msm7x2x_init_host();
+	msm7x27a_pm_init();
+	register_i2c_devices();
+#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
+	msm7627a_bt_power_init();
+#endif
+	msm7627a_camera_init();
+	msm7627a_add_io_devices();
+	/*7x25a kgsl initializations*/
+	msm7x25a_kgsl_3d0_init();
+	/*8x25 kgsl initializations*/
+	msm8x25_kgsl_3d0_init();
+}
+
+static void __init msm7x2x_init_early(void)
+{
+	msm_msm7627a_allocate_memory_regions();
+}
+
+MACHINE_START(MSM7X27A_RUMI3, "QCT MSM7x27a RUMI3")
+	.atag_offset	= 0x100,
+	.map_io		= msm_common_io_init,
+	.reserve	= msm7x27a_reserve,
+	.init_irq	= msm_init_irq,
+	.init_machine	= msm7627a_rumi3_init,
+	.timer		= &msm_timer,
+	.init_early     = msm7x2x_init_early,
+	.handle_irq	= vic_handle_irq,
+MACHINE_END
+MACHINE_START(MSM7X27A_SURF, "QCT MSM7x27a SURF")
+	.atag_offset	= 0x100,
+	.map_io		= msm_common_io_init,
+	.reserve	= msm7x27a_reserve,
+	.init_irq	= msm_init_irq,
+	.init_machine	= msm7x2x_init,
+	.timer		= &msm_timer,
+	.init_early     = msm7x2x_init_early,
+	.handle_irq	= vic_handle_irq,
+MACHINE_END
+MACHINE_START(MSM7X27A_FFA, "QCT MSM7x27a FFA")
+	.atag_offset	= 0x100,
+	.map_io		= msm_common_io_init,
+	.reserve	= msm7x27a_reserve,
+	.init_irq	= msm_init_irq,
+	.init_machine	= msm7x2x_init,
+	.timer		= &msm_timer,
+	.init_early     = msm7x2x_init_early,
+	.handle_irq	= vic_handle_irq,
+MACHINE_END
+MACHINE_START(MSM7625A_SURF, "QCT MSM7625a SURF")
+	.atag_offset    = 0x100,
+	.map_io         = msm_common_io_init,
+	.reserve        = msm7x27a_reserve,
+	.init_irq       = msm_init_irq,
+	.init_machine   = msm7x2x_init,
+	.timer          = &msm_timer,
+	.init_early     = msm7x2x_init_early,
+	.handle_irq	= vic_handle_irq,
+MACHINE_END
+MACHINE_START(MSM7625A_FFA, "QCT MSM7625a FFA")
+	.atag_offset    = 0x100,
+	.map_io         = msm_common_io_init,
+	.reserve        = msm7x27a_reserve,
+	.init_irq       = msm_init_irq,
+	.init_machine   = msm7x2x_init,
+	.timer          = &msm_timer,
+	.init_early     = msm7x2x_init_early,
+	.handle_irq	= vic_handle_irq,
+MACHINE_END
+MACHINE_START(MSM8625_RUMI3, "QCT MSM8625 RUMI3")
+	.atag_offset    = 0x100,
+	.map_io         = msm8625_map_io,
+	.reserve        = msm8625_reserve,
+	.init_irq       = msm8625_init_irq,
+	.init_machine   = msm8625_rumi3_init,
+	.timer          = &msm_timer,
+	.handle_irq	= gic_handle_irq,
+MACHINE_END
+MACHINE_START(MSM8625_SURF, "QCT MSM8625 SURF")
+	.atag_offset    = 0x100,
+	.map_io         = msm8625_map_io,
+	.reserve        = msm8625_reserve,
+	.init_irq       = msm8625_init_irq,
+	.init_machine   = msm7x2x_init,
+	.timer          = &msm_timer,
+	.init_early     = msm7x2x_init_early,
+	.handle_irq	= gic_handle_irq,
+MACHINE_END
+MACHINE_START(MSM8625_FFA, "QCT MSM8625 FFA")
+	.atag_offset    = 0x100,
+	.map_io         = msm8625_map_io,
+	.reserve        = msm8625_reserve,
+	.init_irq       = msm8625_init_irq,
+	.init_machine   = msm7x2x_init,
+	.timer          = &msm_timer,
+	.init_early     = msm7x2x_init_early,
+	.handle_irq	= gic_handle_irq,
+MACHINE_END
diff --git a/arch/arm/mach-msm/board-msm7x30-regulator.c b/arch/arm/mach-msm/board-msm7x30-regulator.c
new file mode 100644
index 0000000..a3f5ee1
--- /dev/null
+++ b/arch/arm/mach-msm/board-msm7x30-regulator.c
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "board-msm7x30-regulator.h"
+
+#define PCOM_VREG_CONSUMERS(name) \
+	static struct regulator_consumer_supply __pcom_vreg_supply_##name[]
+
+#define PCOM_VREG_CONSTRAINT_LVSW(_name, _always_on, _boot_on, _supply_uV) \
+{ \
+	.name = #_name, \
+	.min_uV = 0, \
+	.max_uV = 0, \
+	.input_uV = _supply_uV, \
+	.valid_modes_mask = REGULATOR_MODE_NORMAL, \
+	.valid_ops_mask = REGULATOR_CHANGE_STATUS, \
+	.apply_uV = 0, \
+	.boot_on = _boot_on, \
+	.always_on = _always_on \
+}
+
+#define PCOM_VREG_CONSTRAINT_DYN(_name, _min_uV, _max_uV, _always_on, \
+		_boot_on, _apply_uV, _supply_uV) \
+{ \
+	.name = #_name, \
+	.min_uV = _min_uV, \
+	.max_uV = _max_uV, \
+	.valid_modes_mask = REGULATOR_MODE_NORMAL, \
+	.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, \
+	.input_uV = _supply_uV, \
+	.apply_uV = _apply_uV, \
+	.boot_on = _boot_on, \
+	.always_on = _always_on \
+}
+
+
+#define PCOM_VREG_INIT(_name, _supply, _constraints)\
+{ \
+	.supply_regulator = _supply, \
+	.consumer_supplies = __pcom_vreg_supply_##_name, \
+	.num_consumer_supplies = ARRAY_SIZE(__pcom_vreg_supply_##_name), \
+	.constraints = _constraints \
+}
+
+#define PCOM_VREG_SMP(_name, _id, _supply, _min_uV, _max_uV, _rise_time, \
+		_pulldown, _always_on, _boot_on, _apply_uV, _supply_uV) \
+{ \
+	.init_data = PCOM_VREG_INIT(_name, _supply, \
+		PCOM_VREG_CONSTRAINT_DYN(_name, _min_uV, _max_uV, _always_on, \
+			_boot_on, _apply_uV, _supply_uV)), \
+	.id = _id, \
+	.rise_time = _rise_time, \
+	.pulldown = _pulldown, \
+	.negative = 0, \
+}
+
+#define PCOM_VREG_LDO PCOM_VREG_SMP
+
+#define PCOM_VREG_LVS(_name, _id, _supply, _rise_time, _pulldown, _always_on, \
+		_boot_on) \
+{ \
+	.init_data = PCOM_VREG_INIT(_name, _supply, \
+		PCOM_VREG_CONSTRAINT_LVSW(_name, _always_on, _boot_on, 0)), \
+	.id = _id, \
+	.rise_time = _rise_time, \
+	.pulldown = _pulldown, \
+	.negative = 0, \
+}
+
+#define PCOM_VREG_NCP(_name, _id, _supply, _min_uV, _max_uV, _rise_time, \
+		_always_on, _boot_on, _apply_uV, _supply_uV) \
+{ \
+	.init_data = PCOM_VREG_INIT(_name, _supply, \
+		PCOM_VREG_CONSTRAINT_DYN(_name, -(_min_uV), -(_max_uV), \
+			_always_on, _boot_on, _apply_uV, _supply_uV)), \
+	.id = _id, \
+	.rise_time = _rise_time, \
+	.pulldown = -1, \
+	.negative = 1, \
+}
+
+PCOM_VREG_CONSUMERS(smps0) = {
+	REGULATOR_SUPPLY("smps0",	NULL),
+	REGULATOR_SUPPLY("msmc1",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(smps1) = {
+	REGULATOR_SUPPLY("smps1",	NULL),
+	REGULATOR_SUPPLY("msmc2",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(smps2) = {
+	REGULATOR_SUPPLY("smps2",	NULL),
+	REGULATOR_SUPPLY("s2",		NULL),
+};
+
+PCOM_VREG_CONSUMERS(smps3) = {
+	REGULATOR_SUPPLY("smps3",	NULL),
+	REGULATOR_SUPPLY("s3",		NULL),
+};
+
+PCOM_VREG_CONSUMERS(smps4) = {
+	REGULATOR_SUPPLY("smps4",	NULL),
+	REGULATOR_SUPPLY("s4",		NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo00) = {
+	REGULATOR_SUPPLY("ldo00",	NULL),
+	REGULATOR_SUPPLY("ldo0",	NULL),
+	REGULATOR_SUPPLY("gp3",		NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo02) = {
+	REGULATOR_SUPPLY("ldo02",	NULL),
+	REGULATOR_SUPPLY("ldo2",	NULL),
+	REGULATOR_SUPPLY("xo_out",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo03) = {
+	REGULATOR_SUPPLY("ldo03",	NULL),
+	REGULATOR_SUPPLY("ldo3",	NULL),
+	REGULATOR_SUPPLY("ruim",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo04) = {
+	REGULATOR_SUPPLY("ldo04",	NULL),
+	REGULATOR_SUPPLY("ldo4",	NULL),
+	REGULATOR_SUPPLY("tcxo",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo05) = {
+	REGULATOR_SUPPLY("ldo05",	NULL),
+	REGULATOR_SUPPLY("ldo5",	NULL),
+	REGULATOR_SUPPLY("mmc",		NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo06) = {
+	REGULATOR_SUPPLY("ldo06",	NULL),
+	REGULATOR_SUPPLY("ldo6",	NULL),
+	REGULATOR_SUPPLY("usb",		NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo07) = {
+	REGULATOR_SUPPLY("ldo07",	NULL),
+	REGULATOR_SUPPLY("ldo7",	NULL),
+	REGULATOR_SUPPLY("usb2",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo08) = {
+	REGULATOR_SUPPLY("ldo08",	NULL),
+	REGULATOR_SUPPLY("ldo8",	NULL),
+	REGULATOR_SUPPLY("gp7",		NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo09) = {
+	REGULATOR_SUPPLY("ldo09",	NULL),
+	REGULATOR_SUPPLY("ldo9",	NULL),
+	REGULATOR_SUPPLY("gp1",		NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo10) = {
+	REGULATOR_SUPPLY("ldo10",	NULL),
+	REGULATOR_SUPPLY("gp4",		NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo11) = {
+	REGULATOR_SUPPLY("ldo11",	NULL),
+	REGULATOR_SUPPLY("gp2",		NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo12) = {
+	REGULATOR_SUPPLY("ldo12",	NULL),
+	REGULATOR_SUPPLY("gp9",		NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo13) = {
+	REGULATOR_SUPPLY("ldo13",	NULL),
+	REGULATOR_SUPPLY("wlan",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo14) = {
+	REGULATOR_SUPPLY("ldo14",	NULL),
+	REGULATOR_SUPPLY("rf",		NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo15) = {
+	REGULATOR_SUPPLY("ldo15",	NULL),
+	REGULATOR_SUPPLY("gp6",		NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo16) = {
+	REGULATOR_SUPPLY("ldo16",	NULL),
+	REGULATOR_SUPPLY("gp10",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo17) = {
+	REGULATOR_SUPPLY("ldo17",	NULL),
+	REGULATOR_SUPPLY("gp11",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo18) = {
+	REGULATOR_SUPPLY("ldo18",	NULL),
+	REGULATOR_SUPPLY("gp12",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo19) = {
+	REGULATOR_SUPPLY("ldo19",	NULL),
+	REGULATOR_SUPPLY("wlan2",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo20) = {
+	REGULATOR_SUPPLY("ldo20",	NULL),
+	REGULATOR_SUPPLY("gp13",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo21) = {
+	REGULATOR_SUPPLY("ldo21",	NULL),
+	REGULATOR_SUPPLY("gp14",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo22) = {
+	REGULATOR_SUPPLY("ldo22",	NULL),
+	REGULATOR_SUPPLY("gp15",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo23) = {
+	REGULATOR_SUPPLY("ldo23",	NULL),
+	REGULATOR_SUPPLY("gp5",		NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo24) = {
+	REGULATOR_SUPPLY("ldo24",	NULL),
+	REGULATOR_SUPPLY("gp16",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ldo25) = {
+	REGULATOR_SUPPLY("ldo25",	NULL),
+	REGULATOR_SUPPLY("gp17",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(lvsw0) = {
+	REGULATOR_SUPPLY("lvsw0",	NULL),
+	REGULATOR_SUPPLY("lvs0",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(lvsw1) = {
+	REGULATOR_SUPPLY("lvsw1",	NULL),
+	REGULATOR_SUPPLY("lvs1",	NULL),
+};
+
+PCOM_VREG_CONSUMERS(ncp)   = {
+	REGULATOR_SUPPLY("ncp",		NULL),
+};
+
+/* This list needs to be verified against actual 7x30 hardware requirements. */
+static struct proccomm_regulator_info msm7x30_pcom_vreg_info[] = {
+	/* Standard regulators (SMPS and LDO)
+	 * R = rise time (us)
+	 * P = pulldown (1 = pull down, 0 = float, -1 = don't care)
+	 * A = always on
+	 * B = boot on
+	 * V = automatic voltage set (meaningful for single-voltage regs only)
+	 * S = supply voltage (uV)
+	 *             name  id  supp    min uV    max uV  R   P  A  B  V  S */
+	PCOM_VREG_SMP(smps0,  3, NULL,   500000,  1500000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_SMP(smps1,  4, NULL,   500000,  1500000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_SMP(smps2, 28, NULL,  1300000,  1300000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_SMP(smps3, 29, NULL,  1800000,  1800000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_SMP(smps4, 43, NULL,  2200000,  2200000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo00,  5, NULL,  1200000,  1200000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo02, 46, NULL,  2600000,  2600000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo03, 19, NULL,  1800000,  3000000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo04,  9, NULL,  2850000,  2850000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo05, 18, NULL,  2850000,  2850000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo06, 16, NULL,  3075000,  3400000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo07, 44, NULL,  1800000,  1800000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo08, 32, NULL,  1800000,  1800000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo09,  8, NULL,  2050000,  2050000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo10,  7, NULL,  2600000,  2600000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo11, 21, NULL,  2600000,  2600000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo12, 34, NULL,  1800000,  1800000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo13, 15, NULL,  2900000,  3050000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo14, 24, NULL,  2850000,  2850000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo15, 23, NULL,  3050000,  3100000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo16, 35, NULL,  2600000,  2600000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo17, 36, NULL,  2600000,  2600000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo18, 37, NULL,  2200000,  2200000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo19, 45, NULL,  2400000,  2500000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo20, 38, NULL,  1500000,  1800000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo21, 39, NULL,  1100000,  1100000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo22, 40, NULL,  1200000,  1300000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo23, 22, NULL,  1350000,  1350000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo24, 41, NULL,  1200000,  1200000, 0, -1, 0, 0, 0, 0),
+	PCOM_VREG_LDO(ldo25, 42, NULL,  1200000,  1200000, 0, -1, 0, 0, 0, 0),
+
+	/* Low-voltage switches */
+	PCOM_VREG_LVS(lvsw0, 47, NULL,                     0, -1, 0, 0),
+	PCOM_VREG_LVS(lvsw1, 48, NULL,                     0, -1, 0, 0),
+
+	PCOM_VREG_NCP(ncp,   31, NULL, -1800000, -1800000, 0,     0, 0, 0, 0),
+};
+
+struct proccomm_regulator_platform_data msm7x30_proccomm_regulator_data = {
+	.regs = msm7x30_pcom_vreg_info,
+	.nregs = ARRAY_SIZE(msm7x30_pcom_vreg_info)
+};
diff --git a/arch/arm/mach-msm/board-msm7x30-regulator.h b/arch/arm/mach-msm/board-msm7x30-regulator.h
new file mode 100644
index 0000000..bd9b02d
--- /dev/null
+++ b/arch/arm/mach-msm/board-msm7x30-regulator.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_BOARD_7X30_REGULATOR_H__
+#define __ARCH_ARM_MACH_MSM_BOARD_7X30_REGULATOR_H__
+
+#include "proccomm-regulator.h"
+
+extern struct proccomm_regulator_platform_data msm7x30_proccomm_regulator_data;
+
+#endif
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index db81ed5..8abcef0 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2010, 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
@@ -9,143 +9,7328 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
  */
-#include <linux/gpio.h>
+
 #include <linux/kernel.h>
 #include <linux/irq.h>
 #include <linux/gpio.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
+#include <linux/bootmem.h>
 #include <linux/io.h>
+#ifdef CONFIG_SPI_QSD
+#include <linux/spi/spi.h>
+#endif
+#include <linux/msm_ssbi.h>
+#include <linux/mfd/pmic8058.h>
+#include <linux/leds.h>
+#include <linux/mfd/marimba.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
 #include <linux/smsc911x.h>
-#include <linux/usb/msm_hsusb.h>
-#include <linux/clkdev.h>
-#include <linux/memblock.h>
+#include <linux/ofn_atlab.h>
+#include <linux/power_supply.h>
+#include <linux/i2c/isa1200.h>
+#include <linux/i2c/tsc2007.h>
+#include <linux/input/kp_flip_switch.h>
+#include <linux/leds-pmic8058.h>
+#include <linux/input/cy8c_ts.h>
+#include <linux/msm_adc.h>
+#include <linux/dma-mapping.h>
+#include <linux/regulator/consumer.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
-#include <asm/memory.h>
 #include <asm/setup.h>
 
+#include <mach/mpp.h>
 #include <mach/board.h>
+#include <mach/camera.h>
+#include <mach/memory.h>
 #include <mach/msm_iomap.h>
+#include <mach/msm_hsusb.h>
+#include <mach/rpc_hsusb.h>
+#include <mach/msm_spi.h>
+#include <mach/qdsp5v2/msm_lpa.h>
 #include <mach/dma.h>
+#include <linux/android_pmem.h>
+#include <linux/input/msm_ts.h>
+#include <mach/pmic.h>
+#include <mach/rpc_pmapp.h>
+#include <mach/qdsp5v2/aux_pcm.h>
+#include <mach/qdsp5v2/mi2s.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/msm_battery.h>
+#include <mach/rpc_server_handset.h>
+#include <mach/msm_tsif.h>
+#include <mach/socinfo.h>
+#include <mach/msm_memtypes.h>
+#include <linux/cyttsp-qc.h>
 
+#include <asm/mach/mmc.h>
+#include <asm/mach/flash.h>
 #include <mach/vreg.h>
+#include <linux/platform_data/qcom_crypto_device.h>
+
 #include "devices.h"
-#include "gpiomux.h"
-#include "proc_comm.h"
+#include "timer.h"
+#ifdef CONFIG_USB_G_ANDROID
+#include <linux/usb/android.h>
+#include <mach/usbdiag.h>
+#endif
+#include "pm.h"
+#include "pm-boot.h"
+#include "spm.h"
+#include "acpuclock.h"
+#include <mach/dal_axi.h>
+#include <mach/msm_serial_hs.h>
+#include <mach/qdsp5v2/mi2s.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/sdio_al.h>
+#include "smd_private.h"
+#include <linux/bma150.h>
 
-extern struct sys_timer msm_timer;
+#include "board-msm7x30-regulator.h"
+#include "pm.h"
 
-static void __init msm7x30_fixup(struct tag *tag, char **cmdline,
-		struct meminfo *mi)
+#define MSM_PMEM_SF_SIZE	0x1700000
+#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
+#define MSM_FB_SIZE            0x780000
+#else
+#define MSM_FB_SIZE            0x500000
+#endif
+/*
+ * Reserve space for double buffered full screen
+ * res V4L2 video overlay - i.e. 1280x720x1.5x2
+ */
+#define MSM_V4L2_VIDEO_OVERLAY_BUF_SIZE 2764800
+#define MSM_PMEM_ADSP_SIZE      0x1E00000
+#define MSM_FLUID_PMEM_ADSP_SIZE	0x2800000
+#define PMEM_KERNEL_EBI0_SIZE   0x600000
+#define MSM_PMEM_AUDIO_SIZE     0x200000
+
+#define PMIC_GPIO_INT		27
+#define PMIC_VREG_WLAN_LEVEL	2900
+#define PMIC_GPIO_SD_DET	36
+#define PMIC_GPIO_SDC4_EN_N	17  /* PMIC GPIO Number 18 */
+#define PMIC_GPIO_HDMI_5V_EN_V3 32  /* PMIC GPIO for V3 H/W */
+#define PMIC_GPIO_HDMI_5V_EN_V2 39 /* PMIC GPIO for V2 H/W */
+
+#define ADV7520_I2C_ADDR	0x39
+
+#define FPGA_SDCC_STATUS       0x8E0001A8
+
+#define FPGA_OPTNAV_GPIO_ADDR	0x8E000026
+#define OPTNAV_I2C_SLAVE_ADDR	(0xB0 >> 1)
+#define OPTNAV_IRQ		20
+#define OPTNAV_CHIP_SELECT	19
+#define PMIC_GPIO_SDC4_PWR_EN_N 24  /* PMIC GPIO Number 25 */
+
+/* Macros assume PMIC GPIOs start at 0 */
+#define PM8058_GPIO_PM_TO_SYS(pm_gpio)     (pm_gpio + NR_GPIO_IRQS)
+#define PM8058_GPIO_SYS_TO_PM(sys_gpio)    (sys_gpio - NR_GPIO_IRQS)
+#define PM8058_MPP_BASE			   PM8058_GPIO_PM_TO_SYS(PM8058_GPIOS)
+#define PM8058_MPP_PM_TO_SYS(pm_gpio)	   (pm_gpio + PM8058_MPP_BASE)
+
+#define PMIC_GPIO_FLASH_BOOST_ENABLE	15	/* PMIC GPIO Number 16 */
+#define PMIC_GPIO_HAP_ENABLE   16  /* PMIC GPIO Number 17 */
+
+#define PMIC_GPIO_WLAN_EXT_POR  22 /* PMIC GPIO NUMBER 23 */
+
+#define BMA150_GPIO_INT 1
+
+#define HAP_LVL_SHFT_MSM_GPIO 24
+
+#define PMIC_GPIO_QUICKVX_CLK 37 /* PMIC GPIO 38 */
+
+#define	PM_FLIP_MPP 5 /* PMIC MPP 06 */
+
+#define DDR1_BANK_BASE 0X20000000
+#define DDR2_BANK_BASE 0X40000000
+
+static unsigned int phys_add = DDR2_BANK_BASE;
+unsigned long ebi1_phys_offset = DDR2_BANK_BASE;
+EXPORT_SYMBOL(ebi1_phys_offset);
+
+struct pm8xxx_gpio_init_info {
+	unsigned			gpio;
+	struct pm_gpio			config;
+};
+
+static int pm8058_gpios_init(void)
 {
-	for (; tag->hdr.size; tag = tag_next(tag))
-		if (tag->hdr.tag == ATAG_MEM && tag->u.mem.start == 0x200000) {
-			tag->u.mem.start = 0;
-			tag->u.mem.size += SZ_2M;
+	int rc;
+
+	struct pm8xxx_gpio_init_info sdc4_en = {
+		PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_SDC4_EN_N),
+		{
+			.direction      = PM_GPIO_DIR_OUT,
+			.pull           = PM_GPIO_PULL_NO,
+			.vin_sel        = PM8058_GPIO_VIN_L5,
+			.function       = PM_GPIO_FUNC_NORMAL,
+			.inv_int_pol    = 0,
+			.out_strength   = PM_GPIO_STRENGTH_LOW,
+			.output_value   = 0,
+		},
+	};
+
+	struct pm8xxx_gpio_init_info sdc4_pwr_en = {
+		PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_SDC4_PWR_EN_N),
+		{
+			.direction      = PM_GPIO_DIR_OUT,
+			.pull           = PM_GPIO_PULL_NO,
+			.vin_sel        = PM8058_GPIO_VIN_L5,
+			.function       = PM_GPIO_FUNC_NORMAL,
+			.inv_int_pol    = 0,
+			.out_strength   = PM_GPIO_STRENGTH_LOW,
+			.output_value   = 0,
+		},
+	};
+
+	struct pm8xxx_gpio_init_info haptics_enable = {
+		PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_HAP_ENABLE),
+		{
+			.direction      = PM_GPIO_DIR_OUT,
+			.pull           = PM_GPIO_PULL_NO,
+			.out_strength   = PM_GPIO_STRENGTH_HIGH,
+			.function       = PM_GPIO_FUNC_NORMAL,
+			.inv_int_pol    = 0,
+			.vin_sel        = 2,
+			.output_buffer  = PM_GPIO_OUT_BUF_CMOS,
+			.output_value   = 0,
+		},
+	};
+
+	struct pm8xxx_gpio_init_info hdmi_5V_en = {
+		PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_HDMI_5V_EN_V3),
+		{
+			.direction      = PM_GPIO_DIR_OUT,
+			.pull           = PM_GPIO_PULL_NO,
+			.vin_sel        = PM8058_GPIO_VIN_VPH,
+			.function       = PM_GPIO_FUNC_NORMAL,
+			.out_strength   = PM_GPIO_STRENGTH_LOW,
+			.output_value   = 0,
+		},
+	};
+
+	struct pm8xxx_gpio_init_info flash_boost_enable = {
+		PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_FLASH_BOOST_ENABLE),
+		{
+			.direction      = PM_GPIO_DIR_OUT,
+			.output_buffer  = PM_GPIO_OUT_BUF_CMOS,
+			.output_value   = 0,
+			.pull           = PM_GPIO_PULL_NO,
+			.vin_sel        = PM8058_GPIO_VIN_S3,
+			.out_strength   = PM_GPIO_STRENGTH_HIGH,
+			.function        = PM_GPIO_FUNC_2,
+		},
+	};
+
+	struct pm8xxx_gpio_init_info gpio23 = {
+		PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_WLAN_EXT_POR),
+		{
+			.direction      = PM_GPIO_DIR_OUT,
+			.output_buffer  = PM_GPIO_OUT_BUF_CMOS,
+			.output_value   = 0,
+			.pull           = PM_GPIO_PULL_NO,
+			.vin_sel        = 2,
+			.out_strength   = PM_GPIO_STRENGTH_LOW,
+			.function       = PM_GPIO_FUNC_NORMAL,
 		}
+	};
+
+#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
+	struct pm8xxx_gpio_init_info sdcc_det = {
+		PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_SD_DET - 1),
+		{
+			.direction      = PM_GPIO_DIR_IN,
+			.pull           = PM_GPIO_PULL_UP_1P5,
+			.vin_sel        = 2,
+			.function       = PM_GPIO_FUNC_NORMAL,
+			.inv_int_pol    = 0,
+		},
+	};
+
+	if (machine_is_msm7x30_fluid())
+		sdcc_det.config.inv_int_pol = 1;
+
+	rc = pm8xxx_gpio_config(sdcc_det.gpio, &sdcc_det.config);
+	if (rc) {
+		pr_err("%s PMIC_GPIO_SD_DET config failed\n", __func__);
+		return rc;
+	}
+#endif
+
+	if (machine_is_msm8x55_svlte_surf() || machine_is_msm8x55_svlte_ffa() ||
+						machine_is_msm7x30_fluid())
+		hdmi_5V_en.gpio = PMIC_GPIO_HDMI_5V_EN_V2;
+	else
+		hdmi_5V_en.gpio = PMIC_GPIO_HDMI_5V_EN_V3;
+
+	hdmi_5V_en.gpio = PM8058_GPIO_PM_TO_SYS(hdmi_5V_en.gpio);
+
+	rc = pm8xxx_gpio_config(hdmi_5V_en.gpio, &hdmi_5V_en.config);
+	if (rc) {
+		pr_err("%s PMIC_GPIO_HDMI_5V_EN config failed\n", __func__);
+		return rc;
+	}
+
+	/* Deassert GPIO#23 (source for Ext_POR on WLAN-Volans) */
+	rc = pm8xxx_gpio_config(gpio23.gpio, &gpio23.config);
+	if (rc) {
+		pr_err("%s PMIC_GPIO_WLAN_EXT_POR config failed\n", __func__);
+		return rc;
+	}
+
+	if (machine_is_msm7x30_fluid()) {
+		/* Haptics gpio */
+		rc = pm8xxx_gpio_config(haptics_enable.gpio,
+						&haptics_enable.config);
+		if (rc) {
+			pr_err("%s: PMIC GPIO %d write failed\n", __func__,
+							haptics_enable.gpio);
+			return rc;
+		}
+		/* Flash boost gpio */
+		rc = pm8xxx_gpio_config(flash_boost_enable.gpio,
+						&flash_boost_enable.config);
+		if (rc) {
+			pr_err("%s: PMIC GPIO %d write failed\n", __func__,
+						flash_boost_enable.gpio);
+			return rc;
+		}
+		/* SCD4 gpio */
+		rc = pm8xxx_gpio_config(sdc4_en.gpio, &sdc4_en.config);
+		if (rc) {
+			pr_err("%s PMIC_GPIO_SDC4_EN_N config failed\n",
+								 __func__);
+			return rc;
+		}
+		rc = gpio_request(sdc4_en.gpio, "sdc4_en");
+		if (rc) {
+			pr_err("%s PMIC_GPIO_SDC4_EN_N gpio_request failed\n",
+				__func__);
+			return rc;
+		}
+		gpio_set_value_cansleep(sdc4_en.gpio, 0);
+	}
+	/* FFA -> gpio_25 controls vdd of sdcc4 */
+	else {
+		/* SCD4 gpio_25 */
+		rc = pm8xxx_gpio_config(sdc4_pwr_en.gpio, &sdc4_pwr_en.config);
+		if (rc) {
+			pr_err("%s PMIC_GPIO_SDC4_PWR_EN_N config failed: %d\n",
+			       __func__, rc);
+			return rc;
+		}
+
+		rc = gpio_request(sdc4_pwr_en.gpio, "sdc4_pwr_en");
+		if (rc) {
+			pr_err("PMIC_GPIO_SDC4_PWR_EN_N gpio_req failed: %d\n",
+			       rc);
+			return rc;
+		}
+	}
+
+	return 0;
 }
 
-static void __init msm7x30_reserve(void)
+/* Regulator API support */
+
+#ifdef CONFIG_MSM_PROC_COMM_REGULATOR
+static struct platform_device msm_proccomm_regulator_dev = {
+	.name = PROCCOMM_REGULATOR_DEV_NAME,
+	.id   = -1,
+	.dev  = {
+		.platform_data = &msm7x30_proccomm_regulator_data
+	}
+};
+#endif
+
+/*virtual key support */
+static ssize_t tma300_vkeys_show(struct kobject *kobj,
+			struct kobj_attribute *attr, char *buf)
 {
-	memblock_remove(0x0, SZ_2M);
+	return sprintf(buf,
+	__stringify(EV_KEY) ":" __stringify(KEY_BACK) ":50:842:80:100"
+	":" __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":170:842:80:100"
+	":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":290:842:80:100"
+	":" __stringify(EV_KEY) ":" __stringify(KEY_SEARCH) ":410:842:80:100"
+	"\n");
 }
 
-static int hsusb_phy_init_seq[] = {
-	0x30, 0x32,	/* Enable and set Pre-Emphasis Depth to 20% */
-	0x02, 0x36,	/* Disable CDR Auto Reset feature */
-	-1
+static struct kobj_attribute tma300_vkeys_attr = {
+	.attr = {
+		.mode = S_IRUGO,
+	},
+	.show = &tma300_vkeys_show,
 };
 
-static struct msm_otg_platform_data msm_otg_pdata = {
-	.phy_init_seq		= hsusb_phy_init_seq,
-	.mode                   = USB_PERIPHERAL,
-	.otg_control		= OTG_PHY_CONTROL,
+static struct attribute *tma300_properties_attrs[] = {
+	&tma300_vkeys_attr.attr,
+	NULL
 };
 
-struct msm_gpiomux_config msm_gpiomux_configs[GPIOMUX_NGPIOS] = {
-#ifdef CONFIG_SERIAL_MSM_CONSOLE
-	[49] = { /* UART2 RFR */
-		.suspended = GPIOMUX_DRV_2MA | GPIOMUX_PULL_DOWN |
-			     GPIOMUX_FUNC_2 | GPIOMUX_VALID,
+static struct attribute_group tma300_properties_attr_group = {
+	.attrs = tma300_properties_attrs,
+};
+
+static struct kobject *properties_kobj;
+static struct regulator_bulk_data cyttsp_regs[] = {
+	{ .supply = "ldo8",  .min_uV = 1800000, .max_uV = 1800000 },
+	{ .supply = "ldo15", .min_uV = 3050000, .max_uV = 3100000 },
+};
+
+#define CYTTSP_TS_GPIO_IRQ	150
+static int cyttsp_platform_init(struct i2c_client *client)
+{
+	int rc = -EINVAL;
+
+	rc = regulator_bulk_get(NULL, ARRAY_SIZE(cyttsp_regs), cyttsp_regs);
+
+	if (rc) {
+		pr_err("%s: could not get regulators: %d\n", __func__, rc);
+		goto out;
+	}
+
+	rc = regulator_bulk_set_voltage(ARRAY_SIZE(cyttsp_regs), cyttsp_regs);
+
+	if (rc) {
+		pr_err("%s: could not set regulator voltages: %d\n", __func__,
+				rc);
+		goto regs_free;
+	}
+
+	rc = regulator_bulk_enable(ARRAY_SIZE(cyttsp_regs), cyttsp_regs);
+
+	if (rc) {
+		pr_err("%s: could not enable regulators: %d\n", __func__, rc);
+		goto regs_free;
+	}
+
+	/* check this device active by reading first byte/register */
+	rc = i2c_smbus_read_byte_data(client, 0x01);
+	if (rc < 0) {
+		pr_err("%s: i2c sanity check failed\n", __func__);
+		goto regs_disable;
+	}
+
+	rc = gpio_tlmm_config(GPIO_CFG(CYTTSP_TS_GPIO_IRQ, 0, GPIO_CFG_INPUT,
+					GPIO_CFG_PULL_UP, GPIO_CFG_6MA), GPIO_CFG_ENABLE);
+	if (rc) {
+		pr_err("%s: Could not configure gpio %d\n",
+					 __func__, CYTTSP_TS_GPIO_IRQ);
+		goto regs_disable;
+	}
+
+	/* virtual keys */
+	tma300_vkeys_attr.attr.name = "virtualkeys.cyttsp-i2c";
+	properties_kobj = kobject_create_and_add("board_properties",
+				NULL);
+	if (properties_kobj)
+		rc = sysfs_create_group(properties_kobj,
+			&tma300_properties_attr_group);
+	if (!properties_kobj || rc)
+		pr_err("%s: failed to create board_properties\n",
+				__func__);
+
+	return CY_OK;
+
+regs_disable:
+	regulator_bulk_disable(ARRAY_SIZE(cyttsp_regs), cyttsp_regs);
+regs_free:
+	regulator_bulk_free(ARRAY_SIZE(cyttsp_regs), cyttsp_regs);
+out:
+	return rc;
+}
+
+/* TODO: Put the regulator to LPM / HPM in suspend/resume*/
+static int cyttsp_platform_suspend(struct i2c_client *client)
+{
+	msleep(20);
+
+	return CY_OK;
+}
+
+static int cyttsp_platform_resume(struct i2c_client *client)
+{
+	/* add any special code to strobe a wakeup pin or chip reset */
+	mdelay(10);
+
+	return CY_OK;
+}
+
+static struct cyttsp_platform_data cyttsp_data = {
+	.fw_fname = "cyttsp_7630_fluid.hex",
+	.panel_maxx = 479,
+	.panel_maxy = 799,
+	.disp_maxx = 469,
+	.disp_maxy = 799,
+	.disp_minx = 10,
+	.disp_miny = 0,
+	.flags = 0,
+	.gen = CY_GEN3,	/* or */
+	.use_st = CY_USE_ST,
+	.use_mt = CY_USE_MT,
+	.use_hndshk = CY_SEND_HNDSHK,
+	.use_trk_id = CY_USE_TRACKING_ID,
+	.use_sleep = CY_USE_DEEP_SLEEP_SEL | CY_USE_LOW_POWER_SEL,
+	.use_gestures = CY_USE_GESTURES,
+	/* activate up to 4 groups
+	 * and set active distance
+	 */
+	.gest_set = CY_GEST_GRP1 | CY_GEST_GRP2 |
+				CY_GEST_GRP3 | CY_GEST_GRP4 |
+				CY_ACT_DIST,
+	/* change act_intrvl to customize the Active power state
+	 * scanning/processing refresh interval for Operating mode
+	 */
+	.act_intrvl = CY_ACT_INTRVL_DFLT,
+	/* change tch_tmout to customize the touch timeout for the
+	 * Active power state for Operating mode
+	 */
+	.tch_tmout = CY_TCH_TMOUT_DFLT,
+	/* change lp_intrvl to customize the Low Power power state
+	 * scanning/processing refresh interval for Operating mode
+	 */
+	.lp_intrvl = CY_LP_INTRVL_DFLT,
+	.resume = cyttsp_platform_resume,
+	.suspend = cyttsp_platform_suspend,
+	.init = cyttsp_platform_init,
+	.sleep_gpio = -1,
+	.resout_gpio = -1,
+	.irq_gpio = CYTTSP_TS_GPIO_IRQ,
+	.correct_fw_ver = 2,
+};
+
+static int pm8058_pwm_config(struct pwm_device *pwm, int ch, int on)
+{
+	struct pm_gpio pwm_gpio_config = {
+		.direction      = PM_GPIO_DIR_OUT,
+		.output_buffer  = PM_GPIO_OUT_BUF_CMOS,
+		.output_value   = 0,
+		.pull           = PM_GPIO_PULL_NO,
+		.vin_sel        = PM8058_GPIO_VIN_S3,
+		.out_strength   = PM_GPIO_STRENGTH_HIGH,
+		.function       = PM_GPIO_FUNC_2,
+	};
+	int	rc = -EINVAL;
+	int	id, mode, max_mA;
+
+	id = mode = max_mA = 0;
+	switch (ch) {
+	case 0:
+	case 1:
+	case 2:
+		if (on) {
+			id = 24 + ch;
+			rc = pm8xxx_gpio_config(PM8058_GPIO_PM_TO_SYS(id - 1),
+							&pwm_gpio_config);
+			if (rc)
+				pr_err("%s: pm8xxx_gpio_config(%d): rc=%d\n",
+				       __func__, id, rc);
+		}
+		break;
+
+	case 3:
+		id = PM_PWM_LED_KPD;
+		mode = PM_PWM_CONF_DTEST3;
+		max_mA = 200;
+		break;
+
+	case 4:
+		id = PM_PWM_LED_0;
+		mode = PM_PWM_CONF_PWM1;
+		max_mA = 40;
+		break;
+
+	case 5:
+		id = PM_PWM_LED_2;
+		mode = PM_PWM_CONF_PWM2;
+		max_mA = 40;
+		break;
+
+	case 6:
+		id = PM_PWM_LED_FLASH;
+		mode = PM_PWM_CONF_DTEST3;
+		max_mA = 200;
+		break;
+
+	default:
+		break;
+	}
+
+	if (ch >= 3 && ch <= 6) {
+		if (!on) {
+			mode = PM_PWM_CONF_NONE;
+			max_mA = 0;
+		}
+		rc = pm8058_pwm_config_led(pwm, id, mode, max_mA);
+		if (rc)
+			pr_err("%s: pm8058_pwm_config_led(ch=%d): rc=%d\n",
+			       __func__, ch, rc);
+	}
+
+	return rc;
+}
+
+static int pm8058_pwm_enable(struct pwm_device *pwm, int ch, int on)
+{
+	int	rc;
+
+	switch (ch) {
+	case 7:
+		rc = pm8058_pwm_set_dtest(pwm, on);
+		if (rc)
+			pr_err("%s: pwm_set_dtest(%d): rc=%d\n",
+			       __func__, on, rc);
+		break;
+	default:
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+static const unsigned int fluid_keymap[] = {
+	KEY(0, 0, KEY_7),
+	KEY(0, 1, KEY_ENTER),
+	KEY(0, 2, KEY_UP),
+	/* drop (0,3) as it always shows up in pair with(0,2) */
+	KEY(0, 4, KEY_DOWN),
+
+	KEY(1, 0, KEY_CAMERA_SNAPSHOT),
+	KEY(1, 1, KEY_SELECT),
+	KEY(1, 2, KEY_1),
+	KEY(1, 3, KEY_VOLUMEUP),
+	KEY(1, 4, KEY_VOLUMEDOWN),
+};
+
+static const unsigned int surf_keymap[] = {
+	KEY(0, 0, KEY_7),
+	KEY(0, 1, KEY_DOWN),
+	KEY(0, 2, KEY_UP),
+	KEY(0, 3, KEY_RIGHT),
+	KEY(0, 4, KEY_ENTER),
+	KEY(0, 5, KEY_L),
+	KEY(0, 6, KEY_BACK),
+	KEY(0, 7, KEY_M),
+
+	KEY(1, 0, KEY_LEFT),
+	KEY(1, 1, KEY_SEND),
+	KEY(1, 2, KEY_1),
+	KEY(1, 3, KEY_4),
+	KEY(1, 4, KEY_CLEAR),
+	KEY(1, 5, KEY_MSDOS),
+	KEY(1, 6, KEY_SPACE),
+	KEY(1, 7, KEY_COMMA),
+
+	KEY(2, 0, KEY_6),
+	KEY(2, 1, KEY_5),
+	KEY(2, 2, KEY_8),
+	KEY(2, 3, KEY_3),
+	KEY(2, 4, KEY_NUMERIC_STAR),
+	KEY(2, 5, KEY_UP),
+	KEY(2, 6, KEY_DOWN), /* SYN */
+	KEY(2, 7, KEY_LEFTSHIFT),
+
+	KEY(3, 0, KEY_9),
+	KEY(3, 1, KEY_NUMERIC_POUND),
+	KEY(3, 2, KEY_0),
+	KEY(3, 3, KEY_2),
+	KEY(3, 4, KEY_SLEEP),
+	KEY(3, 5, KEY_F1),
+	KEY(3, 6, KEY_F2),
+	KEY(3, 7, KEY_F3),
+
+	KEY(4, 0, KEY_BACK),
+	KEY(4, 1, KEY_HOME),
+	KEY(4, 2, KEY_MENU),
+	KEY(4, 3, KEY_VOLUMEUP),
+	KEY(4, 4, KEY_VOLUMEDOWN),
+	KEY(4, 5, KEY_F4),
+	KEY(4, 6, KEY_F5),
+	KEY(4, 7, KEY_F6),
+
+	KEY(5, 0, KEY_R),
+	KEY(5, 1, KEY_T),
+	KEY(5, 2, KEY_Y),
+	KEY(5, 3, KEY_LEFTALT),
+	KEY(5, 4, KEY_KPENTER),
+	KEY(5, 5, KEY_Q),
+	KEY(5, 6, KEY_W),
+	KEY(5, 7, KEY_E),
+
+	KEY(6, 0, KEY_F),
+	KEY(6, 1, KEY_G),
+	KEY(6, 2, KEY_H),
+	KEY(6, 3, KEY_CAPSLOCK),
+	KEY(6, 4, KEY_PAGEUP),
+	KEY(6, 5, KEY_A),
+	KEY(6, 6, KEY_S),
+	KEY(6, 7, KEY_D),
+
+	KEY(7, 0, KEY_V),
+	KEY(7, 1, KEY_B),
+	KEY(7, 2, KEY_N),
+	KEY(7, 3, KEY_MENU), /* REVISIT - SYM */
+	KEY(7, 4, KEY_PAGEDOWN),
+	KEY(7, 5, KEY_Z),
+	KEY(7, 6, KEY_X),
+	KEY(7, 7, KEY_C),
+
+	KEY(8, 0, KEY_P),
+	KEY(8, 1, KEY_J),
+	KEY(8, 2, KEY_K),
+	KEY(8, 3, KEY_INSERT),
+	KEY(8, 4, KEY_LINEFEED),
+	KEY(8, 5, KEY_U),
+	KEY(8, 6, KEY_I),
+	KEY(8, 7, KEY_O),
+
+	KEY(9, 0, KEY_4),
+	KEY(9, 1, KEY_5),
+	KEY(9, 2, KEY_6),
+	KEY(9, 3, KEY_7),
+	KEY(9, 4, KEY_8),
+	KEY(9, 5, KEY_1),
+	KEY(9, 6, KEY_2),
+	KEY(9, 7, KEY_3),
+
+	KEY(10, 0, KEY_F7),
+	KEY(10, 1, KEY_F8),
+	KEY(10, 2, KEY_F9),
+	KEY(10, 3, KEY_F10),
+	KEY(10, 4, KEY_FN),
+	KEY(10, 5, KEY_9),
+	KEY(10, 6, KEY_0),
+	KEY(10, 7, KEY_DOT),
+
+	KEY(11, 0, KEY_LEFTCTRL),
+	KEY(11, 1, KEY_F11),  /* START */
+	KEY(11, 2, KEY_ENTER),
+	KEY(11, 3, KEY_SEARCH),
+	KEY(11, 4, KEY_DELETE),
+	KEY(11, 5, KEY_RIGHT),
+	KEY(11, 6, KEY_LEFT),
+	KEY(11, 7, KEY_RIGHTSHIFT),
+};
+
+static struct matrix_keymap_data surf_keymap_data = {
+	.keymap_size    = ARRAY_SIZE(surf_keymap),
+	.keymap		= surf_keymap,
+};
+
+static struct pm8xxx_keypad_platform_data surf_keypad_data = {
+	.input_name		= "surf_keypad",
+	.input_phys_device	= "surf_keypad/input0",
+	.num_rows		= 12,
+	.num_cols		= 8,
+	.rows_gpio_start	= PM8058_GPIO_PM_TO_SYS(8),
+	.cols_gpio_start	= PM8058_GPIO_PM_TO_SYS(0),
+	.debounce_ms		= 15,
+	.scan_delay_ms		= 32,
+	.row_hold_ns		= 91500,
+	.wakeup			= 1,
+	.keymap_data		= &surf_keymap_data,
+};
+
+static struct matrix_keymap_data fluid_keymap_data = {
+	.keymap_size	= ARRAY_SIZE(fluid_keymap),
+	.keymap		= fluid_keymap,
+};
+
+static struct pm8xxx_keypad_platform_data fluid_keypad_data = {
+	.input_name		= "fluid-keypad",
+	.input_phys_device	= "fluid-keypad/input0",
+	.num_rows		= 5,
+	.num_cols		= 5,
+	.rows_gpio_start	= PM8058_GPIO_PM_TO_SYS(8),
+	.cols_gpio_start	= PM8058_GPIO_PM_TO_SYS(0),
+	.debounce_ms		= 15,
+	.scan_delay_ms		= 32,
+	.row_hold_ns		= 91500,
+	.wakeup			= 1,
+	.keymap_data		= &fluid_keymap_data,
+};
+
+static struct pm8058_pwm_pdata pm8058_pwm_data = {
+	.config         = pm8058_pwm_config,
+	.enable         = pm8058_pwm_enable,
+};
+
+static struct pmic8058_led pmic8058_ffa_leds[] = {
+	[0] = {
+		.name		= "keyboard-backlight",
+		.max_brightness = 15,
+		.id		= PMIC8058_ID_LED_KB_LIGHT,
 	},
-	[50] = { /* UART2 CTS */
-		.suspended = GPIOMUX_DRV_2MA | GPIOMUX_PULL_DOWN |
-			     GPIOMUX_FUNC_2 | GPIOMUX_VALID,
+};
+
+static struct pmic8058_leds_platform_data pm8058_ffa_leds_data = {
+	.num_leds = ARRAY_SIZE(pmic8058_ffa_leds),
+	.leds	= pmic8058_ffa_leds,
+};
+
+static struct pmic8058_led pmic8058_surf_leds[] = {
+	[0] = {
+		.name		= "keyboard-backlight",
+		.max_brightness = 15,
+		.id		= PMIC8058_ID_LED_KB_LIGHT,
 	},
-	[51] = { /* UART2 RX */
-		.suspended = GPIOMUX_DRV_2MA | GPIOMUX_PULL_DOWN |
-			     GPIOMUX_FUNC_2 | GPIOMUX_VALID,
+	[1] = {
+		.name		= "voice:red",
+		.max_brightness = 20,
+		.id		= PMIC8058_ID_LED_0,
 	},
-	[52] = { /* UART2 TX */
-		.suspended = GPIOMUX_DRV_2MA | GPIOMUX_PULL_DOWN |
-			     GPIOMUX_FUNC_2 | GPIOMUX_VALID,
+	[2] = {
+		.name		= "wlan:green",
+		.max_brightness = 20,
+		.id		= PMIC8058_ID_LED_2,
+	},
+};
+
+static struct pmic8058_leds_platform_data pm8058_surf_leds_data = {
+	.num_leds = ARRAY_SIZE(pmic8058_surf_leds),
+	.leds	= pmic8058_surf_leds,
+};
+
+static struct pmic8058_led pmic8058_fluid_leds[] = {
+	[0] = {
+		.name		= "keyboard-backlight",
+		.max_brightness = 15,
+		.id		= PMIC8058_ID_LED_KB_LIGHT,
+	},
+	[1] = {
+		.name		= "flash:led_0",
+		.max_brightness = 15,
+		.id		= PMIC8058_ID_FLASH_LED_0,
+	},
+	[2] = {
+		.name		= "flash:led_1",
+		.max_brightness = 15,
+		.id		= PMIC8058_ID_FLASH_LED_1,
+	},
+};
+
+static struct pmic8058_leds_platform_data pm8058_fluid_leds_data = {
+	.num_leds = ARRAY_SIZE(pmic8058_fluid_leds),
+	.leds	= pmic8058_fluid_leds,
+};
+
+static struct pm8xxx_irq_platform_data pm8xxx_irq_pdata = {
+	.irq_base		= PMIC8058_IRQ_BASE,
+	.devirq			= MSM_GPIO_TO_INT(PMIC_GPIO_INT),
+	.irq_trigger_flag       = IRQF_TRIGGER_LOW,
+};
+
+static struct pm8xxx_gpio_platform_data pm8xxx_gpio_pdata = {
+	.gpio_base		= PM8058_GPIO_PM_TO_SYS(0),
+};
+
+static struct pm8xxx_mpp_platform_data pm8xxx_mpp_pdata = {
+	.mpp_base	= PM8058_MPP_PM_TO_SYS(0),
+};
+
+static struct pm8058_platform_data pm8058_7x30_data = {
+	.irq_pdata		= &pm8xxx_irq_pdata,
+	.gpio_pdata		= &pm8xxx_gpio_pdata,
+	.mpp_pdata		= &pm8xxx_mpp_pdata,
+	.pwm_pdata		= &pm8058_pwm_data,
+};
+
+#ifdef CONFIG_MSM_SSBI
+static struct msm_ssbi_platform_data msm7x30_ssbi_pm8058_pdata = {
+	.rsl_id = "D:PMIC_SSBI",
+	.controller_type = MSM_SBI_CTRL_SSBI2,
+	.slave	= {
+		.name			= "pm8058-core",
+		.platform_data		= &pm8058_7x30_data,
+	},
+};
+#endif
+
+static struct i2c_board_info cy8info[] __initdata = {
+	{
+		I2C_BOARD_INFO(CY_I2C_NAME, 0x24),
+		.platform_data = &cyttsp_data,
+#ifndef CY_USE_TIMER
+		.irq = MSM_GPIO_TO_INT(CYTTSP_TS_GPIO_IRQ),
+#endif /* CY_USE_TIMER */
+	},
+};
+
+#ifdef CONFIG_MSM_CAMERA_V4L2
+static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
+	{
+		.csid_core = 0,
+		.is_csic = 1,
+		.is_vpe    = 1,
+		.ioclk = {
+			.vfe_clk_rate =	153600000,
+		},
+	},
+	{
+		.csid_core = 0,
+		.is_vpe    = 1,
+		.ioclk = {
+			.vfe_clk_rate =	153600000,
+		},
+	},
+};
+
+static struct camera_vreg_t msm_7x30_back_cam_vreg[] = {
+	{"gp2", REG_LDO, 2600000, 2600000, -1},
+	{"lvsw1", REG_VS, 0, 0, 0},
+};
+
+static uint32_t camera_off_gpio_table[] = {
+	/* parallel CAMERA interfaces */
+	/* RST */
+	GPIO_CFG(0,  0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT2 */
+	GPIO_CFG(2,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT3 */
+	GPIO_CFG(3,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT4 */
+	GPIO_CFG(4,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT5 */
+	GPIO_CFG(5,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT6 */
+	GPIO_CFG(6,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT7 */
+	GPIO_CFG(7,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT8 */
+	GPIO_CFG(8,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT9 */
+	GPIO_CFG(9,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT10 */
+	GPIO_CFG(10, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT11 */
+	GPIO_CFG(11, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* PCLK */
+	GPIO_CFG(12, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* HSYNC_IN */
+	GPIO_CFG(13, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* VSYNC_IN */
+	GPIO_CFG(14, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* MCLK */
+	GPIO_CFG(15, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+};
+
+static uint32_t camera_on_gpio_table[] = {
+	/* parallel CAMERA interfaces */
+	/* RST */
+	GPIO_CFG(0,  0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT2 */
+	GPIO_CFG(2,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT3 */
+	GPIO_CFG(3,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT4 */
+	GPIO_CFG(4,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT5 */
+	GPIO_CFG(5,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT6 */
+	GPIO_CFG(6,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT7 */
+	GPIO_CFG(7,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT8 */
+	GPIO_CFG(8,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT9 */
+	GPIO_CFG(9,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT10 */
+	GPIO_CFG(10, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT11 */
+	GPIO_CFG(11, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* PCLK */
+	GPIO_CFG(12, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* HSYNC_IN */
+	GPIO_CFG(13, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* VSYNC_IN */
+	GPIO_CFG(14, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* MCLK */
+	GPIO_CFG(15, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+};
+
+static struct gpio msm7x30_back_cam_gpio[] = {
+	{0, GPIOF_DIR_OUT, "CAM_RESET"},
+};
+
+static struct msm_gpio_set_tbl msm7x30_back_cam_gpio_set_tbl[] = {
+	{0, GPIOF_OUT_INIT_LOW, 1000},
+	{0, GPIOF_OUT_INIT_HIGH, 4000},
+};
+
+static struct msm_camera_gpio_conf msm_7x30_back_cam_gpio_conf = {
+	.cam_gpio_req_tbl = msm7x30_back_cam_gpio,
+	.cam_gpio_req_tbl_size = ARRAY_SIZE(msm7x30_back_cam_gpio),
+	.cam_gpio_set_tbl = msm7x30_back_cam_gpio_set_tbl,
+	.cam_gpio_set_tbl_size = ARRAY_SIZE(msm7x30_back_cam_gpio_set_tbl),
+	.camera_off_table = camera_off_gpio_table,
+	.camera_off_table_size = ARRAY_SIZE(camera_off_gpio_table),
+	.camera_on_table = camera_on_gpio_table,
+	.camera_on_table_size = ARRAY_SIZE(camera_on_gpio_table),
+	.gpio_no_mux = 1,
+};
+
+static struct msm_camera_sensor_flash_data flash_vx6953 = {
+	.flash_type	= MSM_CAMERA_FLASH_NONE,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_vx6953 = {
+	.mount_angle	= 0,
+	.cam_vreg = msm_7x30_back_cam_vreg,
+	.num_vreg = ARRAY_SIZE(msm_7x30_back_cam_vreg),
+	.gpio_conf = &msm_7x30_back_cam_gpio_conf,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_vx6953_data = {
+	.sensor_name	= "vx6953",
+	.pdata	= &msm_camera_csi_device_data[0],
+	.flash_data	= &flash_vx6953,
+	.sensor_platform_info = &sensor_board_info_vx6953,
+	.csi_if	= 1,
+	.camera_type = BACK_CAMERA_2D,
+};
+
+static struct platform_device msm_camera_server = {
+	.name = "msm_cam_server",
+	.id = 0,
+};
+
+void __init msm7x30_init_cam(void)
+{
+	platform_device_register(&msm_camera_server);
+	platform_device_register(&msm_device_csic0);
+	platform_device_register(&msm_device_vfe);
+	platform_device_register(&msm_device_vpe);
+}
+
+#ifdef CONFIG_I2C
+static struct i2c_board_info msm_camera_boardinfo[] = {
+	{
+	I2C_BOARD_INFO("vx6953", 0x20),
+	.platform_data = &msm_camera_sensor_vx6953_data,
+	},
+};
+#endif
+#else
+static struct i2c_board_info msm_camera_boardinfo[] __initdata = {
+#ifdef CONFIG_MT9D112
+	{
+		I2C_BOARD_INFO("mt9d112", 0x78 >> 1),
 	},
 #endif
+#ifdef CONFIG_WEBCAM_OV9726
+	{
+		I2C_BOARD_INFO("ov9726", 0x10),
+	},
+#endif
+#ifdef CONFIG_S5K3E2FX
+	{
+		I2C_BOARD_INFO("s5k3e2fx", 0x20 >> 1),
+	},
+#endif
+#ifdef CONFIG_MT9P012
+	{
+		I2C_BOARD_INFO("mt9p012", 0x6C >> 1),
+	},
+#endif
+#ifdef CONFIG_VX6953
+	{
+		I2C_BOARD_INFO("vx6953", 0x20),
+	},
+#endif
+#ifdef CONFIG_MT9E013
+	{
+		I2C_BOARD_INFO("mt9e013", 0x6C >> 2),
+	},
+#endif
+#ifdef CONFIG_SN12M0PZ
+	{
+		I2C_BOARD_INFO("sn12m0pz", 0x34 >> 1),
+	},
+#endif
+#if defined(CONFIG_MT9T013) || defined(CONFIG_SENSORS_MT9T013)
+	{
+		I2C_BOARD_INFO("mt9t013", 0x6C),
+	},
+#endif
+
 };
 
+#ifdef CONFIG_MSM_CAMERA
+#define	CAM_STNDBY	143
+static uint32_t camera_off_vcm_gpio_table[] = {
+GPIO_CFG(1, 0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* VCM */
+};
+
+static uint32_t camera_off_gpio_table[] = {
+	/* parallel CAMERA interfaces */
+	/* RST */
+	GPIO_CFG(0,  0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT2 */
+	GPIO_CFG(2,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT3 */
+	GPIO_CFG(3,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT4 */
+	GPIO_CFG(4,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT5 */
+	GPIO_CFG(5,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT6 */
+	GPIO_CFG(6,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT7 */
+	GPIO_CFG(7,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT8 */
+	GPIO_CFG(8,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT9 */
+	GPIO_CFG(9,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT10 */
+	GPIO_CFG(10, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT11 */
+	GPIO_CFG(11, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* PCLK */
+	GPIO_CFG(12, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* HSYNC_IN */
+	GPIO_CFG(13, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* VSYNC_IN */
+	GPIO_CFG(14, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* MCLK */
+	GPIO_CFG(15, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+};
+
+static uint32_t camera_on_vcm_gpio_table[] = {
+GPIO_CFG(1, 0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_2MA), /* VCM */
+};
+
+static uint32_t camera_on_gpio_table[] = {
+	/* parallel CAMERA interfaces */
+	/* RST */
+	GPIO_CFG(0,  0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT2 */
+	GPIO_CFG(2,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT3 */
+	GPIO_CFG(3,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT4 */
+	GPIO_CFG(4,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT5 */
+	GPIO_CFG(5,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT6 */
+	GPIO_CFG(6,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT7 */
+	GPIO_CFG(7,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT8 */
+	GPIO_CFG(8,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT9 */
+	GPIO_CFG(9,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT10 */
+	GPIO_CFG(10, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* DAT11 */
+	GPIO_CFG(11, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* PCLK */
+	GPIO_CFG(12, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* HSYNC_IN */
+	GPIO_CFG(13, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* VSYNC_IN */
+	GPIO_CFG(14, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* MCLK */
+	GPIO_CFG(15, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+};
+
+static uint32_t camera_off_gpio_fluid_table[] = {
+	/* FLUID: CAM_VGA_RST_N */
+	GPIO_CFG(31, 0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* FLUID: CAMIF_STANDBY */
+	GPIO_CFG(CAM_STNDBY, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA)
+};
+
+static uint32_t camera_on_gpio_fluid_table[] = {
+	/* FLUID: CAM_VGA_RST_N */
+	GPIO_CFG(31, 0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/* FLUID: CAMIF_STANDBY */
+	GPIO_CFG(CAM_STNDBY, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA)
+};
+
+static void config_gpio_table(uint32_t *table, int len)
+{
+	int n, rc;
+	for (n = 0; n < len; n++) {
+		rc = gpio_tlmm_config(table[n], GPIO_CFG_ENABLE);
+		if (rc) {
+			pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
+				__func__, table[n], rc);
+			break;
+		}
+	}
+}
+static int config_camera_on_gpios(void)
+{
+	config_gpio_table(camera_on_gpio_table,
+		ARRAY_SIZE(camera_on_gpio_table));
+
+	if (adie_get_detected_codec_type() != TIMPANI_ID)
+		/* GPIO1 is shared also used in Timpani RF card so
+		only configure it for non-Timpani RF card */
+		config_gpio_table(camera_on_vcm_gpio_table,
+			ARRAY_SIZE(camera_on_vcm_gpio_table));
+
+	if (machine_is_msm7x30_fluid()) {
+		config_gpio_table(camera_on_gpio_fluid_table,
+			ARRAY_SIZE(camera_on_gpio_fluid_table));
+		/* FLUID: turn on 5V booster */
+		gpio_set_value(
+			PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_FLASH_BOOST_ENABLE), 1);
+		/* FLUID: drive high to put secondary sensor to STANDBY */
+		gpio_set_value(CAM_STNDBY, 1);
+	}
+	return 0;
+}
+
+static void config_camera_off_gpios(void)
+{
+	config_gpio_table(camera_off_gpio_table,
+		ARRAY_SIZE(camera_off_gpio_table));
+
+	if (adie_get_detected_codec_type() != TIMPANI_ID)
+		/* GPIO1 is shared also used in Timpani RF card so
+		only configure it for non-Timpani RF card */
+		config_gpio_table(camera_off_vcm_gpio_table,
+			ARRAY_SIZE(camera_off_vcm_gpio_table));
+
+	if (machine_is_msm7x30_fluid()) {
+		config_gpio_table(camera_off_gpio_fluid_table,
+			ARRAY_SIZE(camera_off_gpio_fluid_table));
+		/* FLUID: turn off 5V booster */
+		gpio_set_value(
+			PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_FLASH_BOOST_ENABLE), 0);
+	}
+}
+
+struct resource msm_camera_resources[] = {
+	{
+		.start	= 0xA6000000,
+		.end	= 0xA6000000 + SZ_1M - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_VFE,
+		.end	= INT_VFE,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.flags  = IORESOURCE_DMA,
+	}
+};
+
+struct msm_camera_device_platform_data msm_camera_device_data = {
+	.camera_gpio_on  = config_camera_on_gpios,
+	.camera_gpio_off = config_camera_off_gpios,
+	.ioext.camifpadphy = 0xAB000000,
+	.ioext.camifpadsz  = 0x00000400,
+	.ioext.csiphy = 0xA6100000,
+	.ioext.csisz  = 0x00000400,
+	.ioext.csiirq = INT_CSI,
+	.ioclk.mclk_clk_rate = 24000000,
+	.ioclk.vfe_clk_rate  = 147456000,
+};
+
+static struct msm_camera_sensor_flash_src msm_flash_src_pwm = {
+	.flash_sr_type = MSM_CAMERA_FLASH_SRC_PWM,
+	._fsrc.pwm_src.freq  = 1000,
+	._fsrc.pwm_src.max_load = 300,
+	._fsrc.pwm_src.low_load = 30,
+	._fsrc.pwm_src.high_load = 100,
+	._fsrc.pwm_src.channel = 7,
+};
+
+#ifdef CONFIG_MT9D112
+static struct msm_camera_sensor_flash_data flash_mt9d112 = {
+	.flash_type = MSM_CAMERA_FLASH_LED,
+	.flash_src  = &msm_flash_src_pwm
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_mt9d112_data = {
+	.sensor_name    = "mt9d112",
+	.sensor_reset   = 0,
+	.sensor_pwd     = 85,
+	.vcm_pwd        = 1,
+	.vcm_enable     = 0,
+	.pdata          = &msm_camera_device_data,
+	.resource       = msm_camera_resources,
+	.num_resources  = ARRAY_SIZE(msm_camera_resources),
+	.flash_data     = &flash_mt9d112,
+	.csi_if         = 0
+};
+
+static struct platform_device msm_camera_sensor_mt9d112 = {
+	.name      = "msm_camera_mt9d112",
+	.dev       = {
+		.platform_data = &msm_camera_sensor_mt9d112_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_WEBCAM_OV9726
+
+static struct msm_camera_sensor_platform_info ov9726_sensor_7630_info = {
+	.mount_angle = 90
+};
+
+static struct msm_camera_sensor_flash_data flash_ov9726 = {
+	.flash_type	= MSM_CAMERA_FLASH_LED,
+	.flash_src	= &msm_flash_src_pwm
+};
+static struct msm_camera_sensor_info msm_camera_sensor_ov9726_data = {
+	.sensor_name	= "ov9726",
+	.sensor_reset	= 0,
+	.sensor_pwd	= 85,
+	.vcm_pwd	= 1,
+	.vcm_enable	= 0,
+	.pdata		= &msm_camera_device_data,
+	.resource	= msm_camera_resources,
+	.num_resources	= ARRAY_SIZE(msm_camera_resources),
+	.flash_data	= &flash_ov9726,
+	.sensor_platform_info = &ov9726_sensor_7630_info,
+	.csi_if		= 1
+};
+struct platform_device msm_camera_sensor_ov9726 = {
+	.name	= "msm_camera_ov9726",
+	.dev	= {
+		.platform_data = &msm_camera_sensor_ov9726_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_S5K3E2FX
+static struct msm_camera_sensor_flash_data flash_s5k3e2fx = {
+	.flash_type = MSM_CAMERA_FLASH_LED,
+	.flash_src  = &msm_flash_src_pwm,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_s5k3e2fx_data = {
+	.sensor_name    = "s5k3e2fx",
+	.sensor_reset   = 0,
+	.sensor_pwd     = 85,
+	.vcm_pwd        = 1,
+	.vcm_enable     = 0,
+	.pdata          = &msm_camera_device_data,
+	.resource       = msm_camera_resources,
+	.num_resources  = ARRAY_SIZE(msm_camera_resources),
+	.flash_data     = &flash_s5k3e2fx,
+	.csi_if         = 0
+};
+
+static struct platform_device msm_camera_sensor_s5k3e2fx = {
+	.name      = "msm_camera_s5k3e2fx",
+	.dev       = {
+		.platform_data = &msm_camera_sensor_s5k3e2fx_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_MT9P012
+static struct msm_camera_sensor_flash_data flash_mt9p012 = {
+	.flash_type = MSM_CAMERA_FLASH_LED,
+	.flash_src  = &msm_flash_src_pwm
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_mt9p012_data = {
+	.sensor_name    = "mt9p012",
+	.sensor_reset   = 0,
+	.sensor_pwd     = 85,
+	.vcm_pwd        = 1,
+	.vcm_enable     = 1,
+	.pdata          = &msm_camera_device_data,
+	.resource       = msm_camera_resources,
+	.num_resources  = ARRAY_SIZE(msm_camera_resources),
+	.flash_data     = &flash_mt9p012,
+	.csi_if         = 0
+};
+
+static struct platform_device msm_camera_sensor_mt9p012 = {
+	.name      = "msm_camera_mt9p012",
+	.dev       = {
+		.platform_data = &msm_camera_sensor_mt9p012_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_MT9E013
+static struct msm_camera_sensor_platform_info mt9e013_sensor_7630_info = {
+	.mount_angle = 0
+};
+
+static struct msm_camera_sensor_flash_data flash_mt9e013 = {
+	.flash_type = MSM_CAMERA_FLASH_LED,
+	.flash_src  = &msm_flash_src_pwm
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_mt9e013_data = {
+	.sensor_name    = "mt9e013",
+	.sensor_reset   = 0,
+	.sensor_pwd     = 85,
+	.vcm_pwd        = 1,
+	.vcm_enable     = 1,
+	.pdata          = &msm_camera_device_data,
+	.resource       = msm_camera_resources,
+	.num_resources  = ARRAY_SIZE(msm_camera_resources),
+	.flash_data     = &flash_mt9e013,
+	.sensor_platform_info = &mt9e013_sensor_7630_info,
+	.csi_if         = 1
+};
+
+static struct platform_device msm_camera_sensor_mt9e013 = {
+	.name      = "msm_camera_mt9e013",
+	.dev       = {
+		.platform_data = &msm_camera_sensor_mt9e013_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_VX6953
+static struct msm_camera_sensor_platform_info vx6953_sensor_7630_info = {
+	.mount_angle = 0
+};
+
+static struct msm_camera_sensor_flash_data flash_vx6953 = {
+	.flash_type = MSM_CAMERA_FLASH_LED,
+	.flash_src  = &msm_flash_src_pwm
+};
+static struct msm_camera_sensor_info msm_camera_sensor_vx6953_data = {
+	.sensor_name    = "vx6953",
+	.sensor_reset   = 0,
+	.sensor_pwd     = 85,
+	.vcm_pwd        = 1,
+	.vcm_enable		= 0,
+	.pdata          = &msm_camera_device_data,
+	.resource       = msm_camera_resources,
+	.num_resources  = ARRAY_SIZE(msm_camera_resources),
+	.sensor_platform_info = &vx6953_sensor_7630_info,
+	.flash_data     = &flash_vx6953,
+	.csi_if         = 1
+};
+static struct platform_device msm_camera_sensor_vx6953 = {
+	.name  	= "msm_camera_vx6953",
+	.dev   	= {
+		.platform_data = &msm_camera_sensor_vx6953_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_SN12M0PZ
+static struct msm_camera_sensor_flash_src msm_flash_src_current_driver = {
+	.flash_sr_type = MSM_CAMERA_FLASH_SRC_CURRENT_DRIVER,
+	._fsrc.current_driver_src.low_current = 210,
+	._fsrc.current_driver_src.high_current = 700,
+	._fsrc.current_driver_src.driver_channel = &pm8058_fluid_leds_data,
+};
+
+static struct msm_camera_sensor_flash_data flash_sn12m0pz = {
+	.flash_type = MSM_CAMERA_FLASH_LED,
+	.flash_src  = &msm_flash_src_current_driver
+};
+static struct msm_camera_sensor_info msm_camera_sensor_sn12m0pz_data = {
+	.sensor_name    = "sn12m0pz",
+	.sensor_reset   = 0,
+	.sensor_pwd     = 85,
+	.vcm_pwd        = 1,
+	.vcm_enable     = 1,
+	.pdata          = &msm_camera_device_data,
+	.flash_data     = &flash_sn12m0pz,
+	.resource       = msm_camera_resources,
+	.num_resources  = ARRAY_SIZE(msm_camera_resources),
+	.csi_if         = 0
+};
+
+static struct platform_device msm_camera_sensor_sn12m0pz = {
+	.name      = "msm_camera_sn12m0pz",
+	.dev       = {
+		.platform_data = &msm_camera_sensor_sn12m0pz_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_MT9T013
+static struct msm_camera_sensor_flash_data flash_mt9t013 = {
+	.flash_type = MSM_CAMERA_FLASH_LED,
+	.flash_src  = &msm_flash_src_pwm
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_mt9t013_data = {
+	.sensor_name    = "mt9t013",
+	.sensor_reset   = 0,
+	.sensor_pwd     = 85,
+	.vcm_pwd        = 1,
+	.vcm_enable     = 0,
+	.pdata          = &msm_camera_device_data,
+	.resource       = msm_camera_resources,
+	.num_resources  = ARRAY_SIZE(msm_camera_resources),
+	.flash_data     = &flash_mt9t013,
+	.csi_if         = 1
+};
+
+static struct platform_device msm_camera_sensor_mt9t013 = {
+	.name      = "msm_camera_mt9t013",
+	.dev       = {
+		.platform_data = &msm_camera_sensor_mt9t013_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_MSM_VPE
+static struct resource msm_vpe_resources[] = {
+	{
+		.start	= 0xAD200000,
+		.end	= 0xAD200000 + SZ_1M - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_VPE,
+		.end	= INT_VPE,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device msm_vpe_device = {
+       .name = "msm_vpe",
+       .id   = 0,
+       .num_resources = ARRAY_SIZE(msm_vpe_resources),
+       .resource = msm_vpe_resources,
+};
+#endif
+
+#endif /*CONFIG_MSM_CAMERA*/
+#endif
+
+#ifdef CONFIG_MSM_GEMINI
+static struct resource msm_gemini_resources[] = {
+	{
+		.start  = 0xA3A00000,
+		.end    = 0xA3A00000 + 0x0150 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = INT_JPEG,
+		.end    = INT_JPEG,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device msm_gemini_device = {
+	.name           = "msm_gemini",
+	.resource       = msm_gemini_resources,
+	.num_resources  = ARRAY_SIZE(msm_gemini_resources),
+};
+#endif
+
+#ifdef CONFIG_MSM7KV2_AUDIO
+static uint32_t audio_pamp_gpio_config =
+   GPIO_CFG(82, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA);
+
+static uint32_t audio_fluid_icodec_tx_config =
+  GPIO_CFG(85, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA);
+
+static int __init snddev_poweramp_gpio_init(void)
+{
+	int rc;
+
+	pr_info("snddev_poweramp_gpio_init \n");
+	rc = gpio_tlmm_config(audio_pamp_gpio_config, GPIO_CFG_ENABLE);
+	if (rc) {
+		printk(KERN_ERR
+			"%s: gpio_tlmm_config(%#x)=%d\n",
+			__func__, audio_pamp_gpio_config, rc);
+	}
+	return rc;
+}
+
+void msm_snddev_tx_route_config(void)
+{
+	int rc;
+
+	pr_debug("%s()\n", __func__);
+
+	if (machine_is_msm7x30_fluid()) {
+		rc = gpio_tlmm_config(audio_fluid_icodec_tx_config,
+		GPIO_CFG_ENABLE);
+		if (rc) {
+			printk(KERN_ERR
+				"%s: gpio_tlmm_config(%#x)=%d\n",
+				__func__, audio_fluid_icodec_tx_config, rc);
+		} else
+			gpio_set_value(85, 0);
+	}
+}
+
+void msm_snddev_tx_route_deconfig(void)
+{
+	int rc;
+
+	pr_debug("%s()\n", __func__);
+
+	if (machine_is_msm7x30_fluid()) {
+		rc = gpio_tlmm_config(audio_fluid_icodec_tx_config,
+		GPIO_CFG_DISABLE);
+		if (rc) {
+			printk(KERN_ERR
+				"%s: gpio_tlmm_config(%#x)=%d\n",
+				__func__, audio_fluid_icodec_tx_config, rc);
+		}
+	}
+}
+
+void msm_snddev_poweramp_on(void)
+{
+	gpio_set_value(82, 1);	/* enable spkr poweramp */
+	pr_info("%s: power on amplifier\n", __func__);
+}
+
+void msm_snddev_poweramp_off(void)
+{
+	gpio_set_value(82, 0);	/* disable spkr poweramp */
+	pr_info("%s: power off amplifier\n", __func__);
+}
+
+static struct regulator_bulk_data snddev_regs[] = {
+	{ .supply = "gp4", .min_uV = 2600000, .max_uV = 2600000 },
+	{ .supply = "ncp", .min_uV = 1800000, .max_uV = 1800000 },
+};
+
+static int __init snddev_hsed_voltage_init(void)
+{
+	int rc;
+
+	rc = regulator_bulk_get(NULL, ARRAY_SIZE(snddev_regs), snddev_regs);
+
+	if (rc) {
+		pr_err("%s: could not get regulators: %d\n", __func__, rc);
+		goto out;
+	}
+
+	rc = regulator_bulk_set_voltage(ARRAY_SIZE(snddev_regs), snddev_regs);
+
+	if (rc) {
+		pr_err("%s: could not set regulator voltages: %d\n",
+				__func__, rc);
+		goto regs_free;
+	}
+
+	return 0;
+
+regs_free:
+	regulator_bulk_free(ARRAY_SIZE(snddev_regs), snddev_regs);
+out:
+	return rc;
+}
+
+
+void msm_snddev_hsed_voltage_on(void)
+{
+	int rc = regulator_bulk_enable(ARRAY_SIZE(snddev_regs), snddev_regs);
+
+	if (rc)
+		pr_err("%s: could not enable regulators: %d\n", __func__, rc);
+}
+
+void msm_snddev_hsed_voltage_off(void)
+{
+	int rc = regulator_bulk_disable(ARRAY_SIZE(snddev_regs), snddev_regs);
+
+	if (rc) {
+		pr_err("%s: could not disable regulators: %d\n", __func__, rc);
+	}
+}
+
+static unsigned aux_pcm_gpio_on[] = {
+	GPIO_CFG(138, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),   /* PCM_DOUT */
+	GPIO_CFG(139, 1, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA),   /* PCM_DIN  */
+	GPIO_CFG(140, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),   /* PCM_SYNC */
+	GPIO_CFG(141, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),   /* PCM_CLK  */
+};
+
+static int __init aux_pcm_gpio_init(void)
+{
+	int pin, rc;
+
+	pr_info("aux_pcm_gpio_init \n");
+	for (pin = 0; pin < ARRAY_SIZE(aux_pcm_gpio_on); pin++) {
+		rc = gpio_tlmm_config(aux_pcm_gpio_on[pin],
+					GPIO_CFG_ENABLE);
+		if (rc) {
+			printk(KERN_ERR
+				"%s: gpio_tlmm_config(%#x)=%d\n",
+				__func__, aux_pcm_gpio_on[pin], rc);
+		}
+	}
+	return rc;
+}
+
+static struct msm_gpio mi2s_clk_gpios[] = {
+	{ GPIO_CFG(145, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	    "MI2S_SCLK"},
+	{ GPIO_CFG(144, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	    "MI2S_WS"},
+	{ GPIO_CFG(120, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	    "MI2S_MCLK_A"},
+};
+
+static struct msm_gpio mi2s_rx_data_lines_gpios[] = {
+	{ GPIO_CFG(121, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	    "MI2S_DATA_SD0_A"},
+	{ GPIO_CFG(122, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	    "MI2S_DATA_SD1_A"},
+	{ GPIO_CFG(123, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	    "MI2S_DATA_SD2_A"},
+	{ GPIO_CFG(146, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	    "MI2S_DATA_SD3"},
+};
+
+static struct msm_gpio mi2s_tx_data_lines_gpios[] = {
+	{ GPIO_CFG(146, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	    "MI2S_DATA_SD3"},
+};
+
+int mi2s_config_clk_gpio(void)
+{
+	int rc = 0;
+
+	rc = msm_gpios_request_enable(mi2s_clk_gpios,
+			ARRAY_SIZE(mi2s_clk_gpios));
+	if (rc) {
+		pr_err("%s: enable mi2s clk gpios  failed\n",
+					__func__);
+		return rc;
+	}
+	return 0;
+}
+
+int  mi2s_unconfig_data_gpio(u32 direction, u8 sd_line_mask)
+{
+	int i, rc = 0;
+	sd_line_mask &= MI2S_SD_LINE_MASK;
+
+	switch (direction) {
+	case DIR_TX:
+		msm_gpios_disable_free(mi2s_tx_data_lines_gpios, 1);
+		break;
+	case DIR_RX:
+		i = 0;
+		while (sd_line_mask) {
+			if (sd_line_mask & 0x1)
+				msm_gpios_disable_free(
+					mi2s_rx_data_lines_gpios + i , 1);
+			sd_line_mask = sd_line_mask >> 1;
+			i++;
+		}
+		break;
+	default:
+		pr_err("%s: Invaild direction  direction = %u\n",
+						__func__, direction);
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+int mi2s_config_data_gpio(u32 direction, u8 sd_line_mask)
+{
+	int i , rc = 0;
+	u8 sd_config_done_mask = 0;
+
+	sd_line_mask &= MI2S_SD_LINE_MASK;
+
+	switch (direction) {
+	case DIR_TX:
+		if ((sd_line_mask & MI2S_SD_0) || (sd_line_mask & MI2S_SD_1) ||
+		   (sd_line_mask & MI2S_SD_2) || !(sd_line_mask & MI2S_SD_3)) {
+			pr_err("%s: can not use SD0 or SD1 or SD2 for TX"
+				".only can use SD3. sd_line_mask = 0x%x\n",
+				__func__ , sd_line_mask);
+			rc = -EINVAL;
+		} else {
+			rc = msm_gpios_request_enable(mi2s_tx_data_lines_gpios,
+							 1);
+			if (rc)
+				pr_err("%s: enable mi2s gpios for TX failed\n",
+					   __func__);
+		}
+		break;
+	case DIR_RX:
+		i = 0;
+		while (sd_line_mask && (rc == 0)) {
+			if (sd_line_mask & 0x1) {
+				rc = msm_gpios_request_enable(
+					mi2s_rx_data_lines_gpios + i , 1);
+				if (rc) {
+					pr_err("%s: enable mi2s gpios for"
+					 "RX failed.  SD line = %s\n",
+					 __func__,
+					 (mi2s_rx_data_lines_gpios + i)->label);
+					mi2s_unconfig_data_gpio(DIR_RX,
+						sd_config_done_mask);
+				} else
+					sd_config_done_mask |= (1 << i);
+			}
+			sd_line_mask = sd_line_mask >> 1;
+			i++;
+		}
+		break;
+	default:
+		pr_err("%s: Invaild direction  direction = %u\n",
+			__func__, direction);
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+int mi2s_unconfig_clk_gpio(void)
+{
+	msm_gpios_disable_free(mi2s_clk_gpios, ARRAY_SIZE(mi2s_clk_gpios));
+	return 0;
+}
+
+#endif /* CONFIG_MSM7KV2_AUDIO */
+
+static int __init buses_init(void)
+{
+	if (gpio_tlmm_config(GPIO_CFG(PMIC_GPIO_INT, 1, GPIO_CFG_INPUT,
+				  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), GPIO_CFG_ENABLE))
+		pr_err("%s: gpio_tlmm_config (gpio=%d) failed\n",
+		       __func__, PMIC_GPIO_INT);
+
+	if (machine_is_msm8x60_fluid())
+		pm8058_7x30_data.keypad_pdata = &fluid_keypad_data;
+	else
+		pm8058_7x30_data.keypad_pdata = &surf_keypad_data;
+
+	return 0;
+}
+
+#define TIMPANI_RESET_GPIO	1
+
+struct bahama_config_register{
+	u8 reg;
+	u8 value;
+	u8 mask;
+};
+
+enum version{
+	VER_1_0,
+	VER_2_0,
+	VER_UNSUPPORTED = 0xFF
+};
+
+static struct regulator *vreg_marimba_1;
+static struct regulator *vreg_marimba_2;
+static struct regulator *vreg_bahama;
+
+static struct msm_gpio timpani_reset_gpio_cfg[] = {
+{ GPIO_CFG(TIMPANI_RESET_GPIO, 0, GPIO_CFG_OUTPUT,
+	GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "timpani_reset"} };
+
+static u8 read_bahama_ver(void)
+{
+	int rc;
+	struct marimba config = { .mod_id = SLAVE_ID_BAHAMA };
+	u8 bahama_version;
+
+	rc = marimba_read_bit_mask(&config, 0x00,  &bahama_version, 1, 0x1F);
+	if (rc < 0) {
+		printk(KERN_ERR
+			 "%s: version read failed: %d\n",
+			__func__, rc);
+			return rc;
+	} else {
+		printk(KERN_INFO
+		"%s: version read got: 0x%x\n",
+		__func__, bahama_version);
+	}
+
+	switch (bahama_version) {
+	case 0x08: /* varient of bahama v1 */
+	case 0x10:
+	case 0x00:
+		return VER_1_0;
+	case 0x09: /* variant of bahama v2 */
+		return VER_2_0;
+	default:
+		return VER_UNSUPPORTED;
+	}
+}
+
+static int config_timpani_reset(void)
+{
+	int rc;
+
+	rc = msm_gpios_request_enable(timpani_reset_gpio_cfg,
+				ARRAY_SIZE(timpani_reset_gpio_cfg));
+	if (rc < 0) {
+		printk(KERN_ERR
+			"%s: msm_gpios_request_enable failed (%d)\n",
+				__func__, rc);
+	}
+	return rc;
+}
+
+static unsigned int msm_timpani_setup_power(void)
+{
+	int rc;
+
+	rc = config_timpani_reset();
+	if (rc < 0)
+		goto out;
+
+	rc = regulator_enable(vreg_marimba_1);
+	if (rc) {
+		pr_err("%s: regulator_enable failed (%d)\n", __func__, rc);
+		goto out;
+	}
+
+	rc = regulator_enable(vreg_marimba_2);
+	if (rc) {
+		pr_err("%s: regulator_enable failed (%d)\n", __func__, rc);
+		goto disable_marimba_1;
+	}
+
+	rc = gpio_direction_output(TIMPANI_RESET_GPIO, 1);
+	if (rc < 0) {
+		pr_err("%s: gpio_direction_output failed (%d)\n",
+				__func__, rc);
+		msm_gpios_free(timpani_reset_gpio_cfg,
+				ARRAY_SIZE(timpani_reset_gpio_cfg));
+		goto disable_marimba_2;
+	}
+
+	return 0;
+
+disable_marimba_2:
+	regulator_disable(vreg_marimba_2);
+disable_marimba_1:
+	regulator_disable(vreg_marimba_1);
+out:
+	return rc;
+};
+
+static void msm_timpani_shutdown_power(void)
+{
+	int rc;
+
+	rc = regulator_disable(vreg_marimba_2);
+	if (rc)
+		pr_err("%s: regulator_disable failed (%d)\n", __func__, rc);
+
+	rc = regulator_disable(vreg_marimba_1);
+	if (rc)
+		pr_err("%s: regulator_disable failed (%d)\n", __func__, rc);
+
+	rc = gpio_direction_output(TIMPANI_RESET_GPIO, 0);
+	if (rc < 0)
+		pr_err("%s: gpio_direction_output failed (%d)\n",
+				__func__, rc);
+
+	msm_gpios_free(timpani_reset_gpio_cfg,
+				   ARRAY_SIZE(timpani_reset_gpio_cfg));
+};
+
+static unsigned int msm_bahama_core_config(int type)
+{
+	int rc = 0;
+
+	if (type == BAHAMA_ID) {
+
+		int i;
+		struct marimba config = { .mod_id = SLAVE_ID_BAHAMA };
+
+		const struct bahama_config_register v20_init[] = {
+			/* reg, value, mask */
+			{ 0xF4, 0x84, 0xFF }, /* AREG */
+			{ 0xF0, 0x04, 0xFF } /* DREG */
+		};
+
+		if (read_bahama_ver() == VER_2_0) {
+			for (i = 0; i < ARRAY_SIZE(v20_init); i++) {
+				u8 value = v20_init[i].value;
+				rc = marimba_write_bit_mask(&config,
+					v20_init[i].reg,
+					&value,
+					sizeof(v20_init[i].value),
+					v20_init[i].mask);
+				if (rc < 0) {
+					printk(KERN_ERR
+						"%s: reg %d write failed: %d\n",
+						__func__, v20_init[i].reg, rc);
+					return rc;
+				}
+				printk(KERN_INFO "%s: reg 0x%02x value 0x%02x"
+					" mask 0x%02x\n",
+					__func__, v20_init[i].reg,
+					v20_init[i].value, v20_init[i].mask);
+			}
+		}
+	}
+	printk(KERN_INFO "core type: %d\n", type);
+
+	return rc;
+}
+
+static unsigned int msm_bahama_setup_power(void)
+{
+	int rc = regulator_enable(vreg_bahama);
+
+	if (rc)
+		pr_err("%s: regulator_enable failed (%d)\n", __func__, rc);
+
+	return rc;
+};
+
+static unsigned int msm_bahama_shutdown_power(int value)
+{
+	int rc = 0;
+
+	if (value != BAHAMA_ID) {
+		rc = regulator_disable(vreg_bahama);
+
+		if (rc)
+			pr_err("%s: regulator_disable failed (%d)\n",
+					__func__, rc);
+	}
+
+	return rc;
+};
+
+static struct msm_gpio marimba_svlte_config_clock[] = {
+	{ GPIO_CFG(34, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+		"MARIMBA_SVLTE_CLOCK_ENABLE" },
+};
+
+static unsigned int msm_marimba_gpio_config_svlte(int gpio_cfg_marimba)
+{
+	if (machine_is_msm8x55_svlte_surf() ||
+		machine_is_msm8x55_svlte_ffa()) {
+		if (gpio_cfg_marimba)
+			gpio_set_value(GPIO_PIN
+				(marimba_svlte_config_clock->gpio_cfg), 1);
+		else
+			gpio_set_value(GPIO_PIN
+				(marimba_svlte_config_clock->gpio_cfg), 0);
+	}
+
+	return 0;
+};
+
+static unsigned int msm_marimba_setup_power(void)
+{
+	int rc;
+
+	rc = regulator_enable(vreg_marimba_1);
+	if (rc) {
+		pr_err("%s: regulator_enable failed (%d)\n", __func__, rc);
+		goto out;
+	}
+
+	rc = regulator_enable(vreg_marimba_2);
+	if (rc) {
+		pr_err("%s: regulator_enable failed (%d)\n", __func__, rc);
+		goto disable_marimba_1;
+	}
+
+	if (machine_is_msm8x55_svlte_surf() || machine_is_msm8x55_svlte_ffa()) {
+		rc = msm_gpios_request_enable(marimba_svlte_config_clock,
+				ARRAY_SIZE(marimba_svlte_config_clock));
+		if (rc < 0) {
+			pr_err("%s: msm_gpios_request_enable failed (%d)\n",
+					__func__, rc);
+			goto disable_marimba_2;
+		}
+
+		rc = gpio_direction_output(GPIO_PIN
+			(marimba_svlte_config_clock->gpio_cfg), 0);
+		if (rc < 0) {
+			pr_err("%s: gpio_direction_output failed (%d)\n",
+					__func__, rc);
+			goto disable_marimba_2;
+		}
+	}
+
+	return 0;
+
+disable_marimba_2:
+	regulator_disable(vreg_marimba_2);
+disable_marimba_1:
+	regulator_disable(vreg_marimba_1);
+out:
+	return rc;
+};
+
+static void msm_marimba_shutdown_power(void)
+{
+	int rc;
+
+	rc = regulator_disable(vreg_marimba_2);
+	if (rc)
+		pr_err("%s: regulator_disable failed (%d)\n", __func__, rc);
+
+	rc = regulator_disable(vreg_marimba_1);
+	if (rc)
+		pr_err("%s: regulator_disable failed (%d)\n", __func__, rc);
+};
+
+static int bahama_present(void)
+{
+	int id;
+	switch (id = adie_get_detected_connectivity_type()) {
+	case BAHAMA_ID:
+		return 1;
+
+	case MARIMBA_ID:
+		return 0;
+
+	case TIMPANI_ID:
+	default:
+	printk(KERN_ERR "%s: unexpected adie connectivity type: %d\n",
+			__func__, id);
+	return -ENODEV;
+	}
+}
+
+struct regulator *fm_regulator;
+static int fm_radio_setup(struct marimba_fm_platform_data *pdata)
+{
+	int rc, voltage;
+	uint32_t irqcfg;
+	const char *id = "FMPW";
+
+	int bahama_not_marimba = bahama_present();
+
+	if (bahama_not_marimba < 0) {
+		pr_warn("%s: bahama_present: %d\n",
+				__func__, bahama_not_marimba);
+		rc = -ENODEV;
+		goto out;
+	}
+	if (bahama_not_marimba) {
+		fm_regulator = regulator_get(NULL, "s3");
+		voltage = 1800000;
+	} else {
+		fm_regulator = regulator_get(NULL, "s2");
+		voltage = 1300000;
+	}
+
+	if (IS_ERR(fm_regulator)) {
+		rc = PTR_ERR(fm_regulator);
+		pr_err("%s: regulator_get failed (%d)\n", __func__, rc);
+		goto out;
+	}
+
+	rc = regulator_set_voltage(fm_regulator, voltage, voltage);
+
+	if (rc) {
+		pr_err("%s: regulator_set_voltage failed (%d)\n", __func__, rc);
+		goto regulator_free;
+	}
+
+	rc = regulator_enable(fm_regulator);
+
+	if (rc) {
+		pr_err("%s: regulator_enable failed (%d)\n", __func__, rc);
+		goto regulator_free;
+	}
+
+	rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_DO, PMAPP_CLOCK_VOTE_ON);
+
+	if (rc < 0) {
+		pr_err("%s: clock vote failed (%d)\n", __func__, rc);
+		goto regulator_disable;
+	}
+
+	/*Request the Clock Using GPIO34/AP2MDM_MRMBCK_EN in case
+	of svlte*/
+	if (machine_is_msm8x55_svlte_surf() || machine_is_msm8x55_svlte_ffa()) {
+		rc = marimba_gpio_config(1);
+		if (rc < 0) {
+			pr_err("%s: clock enable for svlte : %d\n",
+					__func__, rc);
+			goto clock_devote;
+		}
+	}
+	irqcfg = GPIO_CFG(147, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL,
+					GPIO_CFG_2MA);
+	rc = gpio_tlmm_config(irqcfg, GPIO_CFG_ENABLE);
+	if (rc) {
+		pr_err("%s: gpio_tlmm_config(%#x)=%d\n", __func__, irqcfg, rc);
+		rc = -EIO;
+		goto gpio_deconfig;
+
+	}
+	return 0;
+
+gpio_deconfig:
+	if (machine_is_msm8x55_svlte_surf() || machine_is_msm8x55_svlte_ffa())
+		marimba_gpio_config(0);
+clock_devote:
+	pmapp_clock_vote(id, PMAPP_CLOCK_ID_DO, PMAPP_CLOCK_VOTE_OFF);
+regulator_disable:
+	regulator_disable(fm_regulator);
+regulator_free:
+	regulator_put(fm_regulator);
+	fm_regulator = NULL;
+out:
+	return rc;
+};
+
+static void fm_radio_shutdown(struct marimba_fm_platform_data *pdata)
+{
+	int rc;
+	const char *id = "FMPW";
+	uint32_t irqcfg = GPIO_CFG(147, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_UP,
+					GPIO_CFG_2MA);
+
+	int bahama_not_marimba = bahama_present();
+	if (bahama_not_marimba == -1) {
+		pr_warn("%s: bahama_present: %d\n",
+				__func__, bahama_not_marimba);
+		return;
+	}
+
+	rc = gpio_tlmm_config(irqcfg, GPIO_CFG_ENABLE);
+	if (rc) {
+		pr_err("%s: gpio_tlmm_config(%#x)=%d\n", __func__, irqcfg, rc);
+	}
+	if (!IS_ERR_OR_NULL(fm_regulator)) {
+		rc = regulator_disable(fm_regulator);
+
+		if (rc)
+			pr_err("%s: return val: %d\n", __func__, rc);
+
+		regulator_put(fm_regulator);
+		fm_regulator = NULL;
+	}
+	rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_DO,
+					  PMAPP_CLOCK_VOTE_OFF);
+	if (rc < 0)
+		pr_err("%s: clock_vote return val: %d\n", __func__, rc);
+
+	/*Disable the Clock Using GPIO34/AP2MDM_MRMBCK_EN in case
+	of svlte*/
+	if (machine_is_msm8x55_svlte_surf() || machine_is_msm8x55_svlte_ffa()) {
+		rc = marimba_gpio_config(0);
+		if (rc < 0)
+			pr_err("%s: clock disable for svlte : %d\n",
+					__func__, rc);
+	}
+}
+
+static struct marimba_fm_platform_data marimba_fm_pdata = {
+	.fm_setup =  fm_radio_setup,
+	.fm_shutdown = fm_radio_shutdown,
+	.irq = MSM_GPIO_TO_INT(147),
+	.vreg_s2 = NULL,
+	.vreg_xo_out = NULL,
+	.is_fm_soc_i2s_master = false,
+	.config_i2s_gpio = NULL,
+};
+
+
+/* Slave id address for FM/CDC/QMEMBIST
+ * Values can be programmed using Marimba slave id 0
+ * should there be a conflict with other I2C devices
+ * */
+#define MARIMBA_SLAVE_ID_FM_ADDR	0x2A
+#define MARIMBA_SLAVE_ID_CDC_ADDR	0x77
+#define MARIMBA_SLAVE_ID_QMEMBIST_ADDR	0X66
+
+#define BAHAMA_SLAVE_ID_FM_ADDR         0x2A
+#define BAHAMA_SLAVE_ID_QMEMBIST_ADDR   0x7B
+
+static const char *tsadc_id = "MADC";
+
+static struct regulator_bulk_data regs_tsadc_marimba[] = {
+	{ .supply = "gp12", .min_uV = 2200000, .max_uV = 2200000 },
+	{ .supply = "s2",   .min_uV = 1300000, .max_uV = 1300000 },
+};
+
+static struct regulator_bulk_data regs_tsadc_timpani[] = {
+	{ .supply = "s3",   .min_uV = 1800000, .max_uV = 1800000 },
+	{ .supply = "gp12", .min_uV = 2200000, .max_uV = 2200000 },
+	{ .supply = "gp16", .min_uV = 1200000, .max_uV = 1200000 },
+};
+
+static struct regulator_bulk_data *regs_tsadc;
+static int regs_tsadc_count;
+
+static int marimba_tsadc_power(int vreg_on)
+{
+	int rc = 0;
+	int tsadc_adie_type = adie_get_detected_codec_type();
+
+	switch (tsadc_adie_type) {
+	case TIMPANI_ID:
+		rc = pmapp_clock_vote(tsadc_id, PMAPP_CLOCK_ID_D1,
+			vreg_on ? PMAPP_CLOCK_VOTE_ON : PMAPP_CLOCK_VOTE_OFF);
+		if (rc)	{
+			pr_err("%s: unable to %svote for d1 clk\n",
+				__func__, vreg_on ? "" : "de-");
+			goto D1_vote_fail;
+		}
+
+		/* fall through */
+	case MARIMBA_ID:
+		rc = pmapp_clock_vote(tsadc_id, PMAPP_CLOCK_ID_DO,
+			vreg_on ? PMAPP_CLOCK_VOTE_ON : PMAPP_CLOCK_VOTE_OFF);
+		if (rc)	{
+			pr_err("%s: unable to %svote for d1 clk\n",
+				__func__, vreg_on ? "" : "de-");
+			goto D0_vote_fail;
+		}
+
+		WARN_ON(regs_tsadc_count == 0);
+
+		rc = vreg_on ?
+			regulator_bulk_enable(regs_tsadc_count, regs_tsadc) :
+			regulator_bulk_disable(regs_tsadc_count, regs_tsadc);
+
+		if (rc) {
+			pr_err("%s: regulator %sable failed: %d\n",
+					__func__, vreg_on ? "en" : "dis", rc);
+			goto regulator_switch_fail;
+		}
+
+		break;
+	default:
+		pr_err("%s:Adie %d not supported\n",
+				__func__, tsadc_adie_type);
+		return -ENODEV;
+	}
+
+	msleep(5); /* ensure power is stable */
+
+	return 0;
+
+regulator_switch_fail:
+	pmapp_clock_vote(tsadc_id, PMAPP_CLOCK_ID_DO,
+		vreg_on ? PMAPP_CLOCK_VOTE_OFF : PMAPP_CLOCK_VOTE_ON);
+D0_vote_fail:
+	if (tsadc_adie_type == TIMPANI_ID)
+		pmapp_clock_vote(tsadc_id, PMAPP_CLOCK_ID_D1,
+			vreg_on ? PMAPP_CLOCK_VOTE_OFF : PMAPP_CLOCK_VOTE_ON);
+D1_vote_fail:
+	return rc;
+}
+
+static int marimba_tsadc_init(void)
+{
+	int rc = 0;
+	int tsadc_adie_type = adie_get_detected_codec_type();
+
+	switch (tsadc_adie_type) {
+	case MARIMBA_ID:
+		regs_tsadc = regs_tsadc_marimba;
+		regs_tsadc_count = ARRAY_SIZE(regs_tsadc_marimba);
+		break;
+	case TIMPANI_ID:
+		regs_tsadc = regs_tsadc_timpani;
+		regs_tsadc_count = ARRAY_SIZE(regs_tsadc_timpani);
+		break;
+	default:
+		pr_err("%s:Adie %d not supported\n",
+				__func__, tsadc_adie_type);
+		rc = -ENODEV;
+		goto out;
+	}
+
+	rc = regulator_bulk_get(NULL, regs_tsadc_count, regs_tsadc);
+	if (rc) {
+		pr_err("%s: could not get regulators: %d\n",
+				__func__, rc);
+		goto out;
+	}
+
+	rc = regulator_bulk_set_voltage(regs_tsadc_count, regs_tsadc);
+	if (rc) {
+		pr_err("%s: could not set regulator voltages: %d\n",
+				__func__, rc);
+		goto vreg_free;
+	}
+
+	return 0;
+
+vreg_free:
+	regulator_bulk_free(regs_tsadc_count, regs_tsadc);
+out:
+	regs_tsadc = NULL;
+	regs_tsadc_count = 0;
+	return rc;
+}
+
+static int marimba_tsadc_exit(void)
+{
+	regulator_bulk_free(regs_tsadc_count, regs_tsadc);
+	regs_tsadc_count = 0;
+	regs_tsadc = NULL;
+
+	return 0;
+}
+
+
+static struct msm_ts_platform_data msm_ts_data = {
+	.min_x          = 284,
+	.max_x          = 3801,
+	.min_y          = 155,
+	.max_y          = 3929,
+	.min_press      = 0,
+	.max_press      = 255,
+	.inv_x          = 4096,
+	.inv_y          = 4096,
+	.can_wakeup	= false,
+};
+
+static struct marimba_tsadc_platform_data marimba_tsadc_pdata = {
+	.marimba_tsadc_power =  marimba_tsadc_power,
+	.init		     =  marimba_tsadc_init,
+	.exit		     =  marimba_tsadc_exit,
+	.tsadc_prechg_en = true,
+	.can_wakeup	= false,
+	.setup = {
+		.pen_irq_en	=	true,
+		.tsadc_en	=	true,
+	},
+	.params2 = {
+		.input_clk_khz		=	2400,
+		.sample_prd		=	TSADC_CLK_3,
+	},
+	.params3 = {
+		.prechg_time_nsecs	=	6400,
+		.stable_time_nsecs	=	6400,
+		.tsadc_test_mode	=	0,
+	},
+	.tssc_data = &msm_ts_data,
+};
+
+static struct regulator_bulk_data codec_regs[] = {
+	{ .supply = "s4", .min_uV = 2200000, .max_uV = 2200000 },
+};
+
+static int __init msm_marimba_codec_init(void)
+{
+	int rc = regulator_bulk_get(NULL, ARRAY_SIZE(codec_regs), codec_regs);
+
+	if (rc) {
+		pr_err("%s: could not get regulators: %d\n", __func__, rc);
+		goto out;
+	}
+
+	rc = regulator_bulk_set_voltage(ARRAY_SIZE(codec_regs), codec_regs);
+	if (rc) {
+		pr_err("%s: could not set regulator voltages: %d\n",
+				__func__, rc);
+		goto reg_free;
+	}
+
+	return rc;
+
+reg_free:
+	regulator_bulk_free(ARRAY_SIZE(codec_regs), codec_regs);
+out:
+	return rc;
+}
+
+static int msm_marimba_codec_power(int vreg_on)
+{
+	int rc = vreg_on ?
+		regulator_bulk_enable(ARRAY_SIZE(codec_regs), codec_regs) :
+		regulator_bulk_disable(ARRAY_SIZE(codec_regs), codec_regs);
+
+	if (rc) {
+		pr_err("%s: could not %sable regulators: %d",
+				__func__, vreg_on ? "en" : "dis", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+static struct marimba_codec_platform_data mariba_codec_pdata = {
+	.marimba_codec_power =  msm_marimba_codec_power,
+#ifdef CONFIG_MARIMBA_CODEC
+	.snddev_profile_init = msm_snddev_init,
+#endif
+};
+
+static struct marimba_platform_data marimba_pdata = {
+	.slave_id[MARIMBA_SLAVE_ID_FM]       = MARIMBA_SLAVE_ID_FM_ADDR,
+	.slave_id[MARIMBA_SLAVE_ID_CDC]	     = MARIMBA_SLAVE_ID_CDC_ADDR,
+	.slave_id[MARIMBA_SLAVE_ID_QMEMBIST] = MARIMBA_SLAVE_ID_QMEMBIST_ADDR,
+	.slave_id[SLAVE_ID_BAHAMA_FM]        = BAHAMA_SLAVE_ID_FM_ADDR,
+	.slave_id[SLAVE_ID_BAHAMA_QMEMBIST]  = BAHAMA_SLAVE_ID_QMEMBIST_ADDR,
+	.marimba_setup = msm_marimba_setup_power,
+	.marimba_shutdown = msm_marimba_shutdown_power,
+	.bahama_setup = msm_bahama_setup_power,
+	.bahama_shutdown = msm_bahama_shutdown_power,
+	.marimba_gpio_config = msm_marimba_gpio_config_svlte,
+	.bahama_core_config = msm_bahama_core_config,
+	.fm = &marimba_fm_pdata,
+	.codec = &mariba_codec_pdata,
+	.tsadc_ssbi_adap = MARIMBA_SSBI_ADAP,
+};
+
+static void __init msm7x30_init_marimba(void)
+{
+	int rc;
+
+	struct regulator_bulk_data regs[] = {
+		{ .supply = "s3",   .min_uV = 1800000, .max_uV = 1800000 },
+		{ .supply = "gp16", .min_uV = 1200000, .max_uV = 1200000 },
+		{ .supply = "usb2", .min_uV = 1800000, .max_uV = 1800000 },
+	};
+
+	rc = msm_marimba_codec_init();
+
+	if (rc) {
+		pr_err("%s: msm_marimba_codec_init failed (%d)\n",
+				__func__, rc);
+		return;
+	}
+
+	rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs), regs);
+
+	if (rc) {
+		pr_err("%s: could not get regulators: %d\n", __func__, rc);
+		return;
+	}
+
+	rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs), regs);
+
+	if (rc) {
+		pr_err("%s: could not set voltages: %d\n", __func__, rc);
+		regulator_bulk_free(ARRAY_SIZE(regs), regs);
+		return;
+	}
+
+	vreg_marimba_1 = regs[0].consumer;
+	vreg_marimba_2 = regs[1].consumer;
+	vreg_bahama    = regs[2].consumer;
+}
+
+static struct marimba_codec_platform_data timpani_codec_pdata = {
+	.marimba_codec_power =  msm_marimba_codec_power,
+#ifdef CONFIG_TIMPANI_CODEC
+	.snddev_profile_init = msm_snddev_init_timpani,
+#endif
+};
+
+static struct marimba_platform_data timpani_pdata = {
+	.slave_id[MARIMBA_SLAVE_ID_CDC]	= MARIMBA_SLAVE_ID_CDC_ADDR,
+	.slave_id[MARIMBA_SLAVE_ID_QMEMBIST] = MARIMBA_SLAVE_ID_QMEMBIST_ADDR,
+	.marimba_setup = msm_timpani_setup_power,
+	.marimba_shutdown = msm_timpani_shutdown_power,
+	.codec = &timpani_codec_pdata,
+	.tsadc = &marimba_tsadc_pdata,
+	.tsadc_ssbi_adap = MARIMBA_SSBI_ADAP,
+};
+
+#define TIMPANI_I2C_SLAVE_ADDR	0xD
+
+static struct i2c_board_info msm_i2c_gsbi7_timpani_info[] = {
+	{
+		I2C_BOARD_INFO("timpani", TIMPANI_I2C_SLAVE_ADDR),
+		.platform_data = &timpani_pdata,
+	},
+};
+
+#ifdef CONFIG_MSM7KV2_AUDIO
+static struct resource msm_aictl_resources[] = {
+	{
+		.name = "aictl",
+		.start = 0xa5000100,
+		.end = 0xa5000100,
+		.flags = IORESOURCE_MEM,
+	}
+};
+
+static struct resource msm_mi2s_resources[] = {
+	{
+		.name = "hdmi",
+		.start = 0xac900000,
+		.end = 0xac900038,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = "codec_rx",
+		.start = 0xac940040,
+		.end = 0xac940078,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = "codec_tx",
+		.start = 0xac980080,
+		.end = 0xac9800B8,
+		.flags = IORESOURCE_MEM,
+	}
+
+};
+
+static struct msm_lpa_platform_data lpa_pdata = {
+	.obuf_hlb_size = 0x2BFF8,
+	.dsp_proc_id = 0,
+	.app_proc_id = 2,
+	.nosb_config = {
+		.llb_min_addr = 0,
+		.llb_max_addr = 0x3ff8,
+		.sb_min_addr = 0,
+		.sb_max_addr = 0,
+	},
+	.sb_config = {
+		.llb_min_addr = 0,
+		.llb_max_addr = 0x37f8,
+		.sb_min_addr = 0x3800,
+		.sb_max_addr = 0x3ff8,
+	}
+};
+
+static struct resource msm_lpa_resources[] = {
+	{
+		.name = "lpa",
+		.start = 0xa5000000,
+		.end = 0xa50000a0,
+		.flags = IORESOURCE_MEM,
+	}
+};
+
+static struct resource msm_aux_pcm_resources[] = {
+
+	{
+		.name = "aux_codec_reg_addr",
+		.start = 0xac9c00c0,
+		.end = 0xac9c00c8,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name   = "aux_pcm_dout",
+		.start  = 138,
+		.end    = 138,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "aux_pcm_din",
+		.start  = 139,
+		.end    = 139,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "aux_pcm_syncout",
+		.start  = 140,
+		.end    = 140,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "aux_pcm_clkin_a",
+		.start  = 141,
+		.end    = 141,
+		.flags  = IORESOURCE_IO,
+	},
+};
+
+static struct platform_device msm_aux_pcm_device = {
+	.name   = "msm_aux_pcm",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_aux_pcm_resources),
+	.resource       = msm_aux_pcm_resources,
+};
+
+struct platform_device msm_aictl_device = {
+	.name = "audio_interct",
+	.id   = 0,
+	.num_resources = ARRAY_SIZE(msm_aictl_resources),
+	.resource = msm_aictl_resources,
+};
+
+struct platform_device msm_mi2s_device = {
+	.name = "mi2s",
+	.id   = 0,
+	.num_resources = ARRAY_SIZE(msm_mi2s_resources),
+	.resource = msm_mi2s_resources,
+};
+
+struct platform_device msm_lpa_device = {
+	.name = "lpa",
+	.id   = 0,
+	.num_resources = ARRAY_SIZE(msm_lpa_resources),
+	.resource = msm_lpa_resources,
+	.dev		= {
+		.platform_data = &lpa_pdata,
+	},
+};
+#endif /* CONFIG_MSM7KV2_AUDIO */
+
+#define DEC0_FORMAT ((1<<MSM_ADSP_CODEC_MP3)| \
+	(1<<MSM_ADSP_CODEC_AAC)|(1<<MSM_ADSP_CODEC_WMA)| \
+	(1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \
+	(1<<MSM_ADSP_CODEC_AMRNB)|(1<<MSM_ADSP_CODEC_WAV)| \
+	(1<<MSM_ADSP_CODEC_ADPCM)|(1<<MSM_ADSP_CODEC_YADPCM)| \
+	(1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP))
+#define DEC1_FORMAT ((1<<MSM_ADSP_CODEC_MP3)| \
+	(1<<MSM_ADSP_CODEC_AAC)|(1<<MSM_ADSP_CODEC_WMA)| \
+	(1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \
+	(1<<MSM_ADSP_CODEC_AMRNB)|(1<<MSM_ADSP_CODEC_WAV)| \
+	(1<<MSM_ADSP_CODEC_ADPCM)|(1<<MSM_ADSP_CODEC_YADPCM)| \
+	(1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP))
+ #define DEC2_FORMAT ((1<<MSM_ADSP_CODEC_MP3)| \
+	(1<<MSM_ADSP_CODEC_AAC)|(1<<MSM_ADSP_CODEC_WMA)| \
+	(1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \
+	(1<<MSM_ADSP_CODEC_AMRNB)|(1<<MSM_ADSP_CODEC_WAV)| \
+	(1<<MSM_ADSP_CODEC_ADPCM)|(1<<MSM_ADSP_CODEC_YADPCM)| \
+	(1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP))
+ #define DEC3_FORMAT ((1<<MSM_ADSP_CODEC_MP3)| \
+	(1<<MSM_ADSP_CODEC_AAC)|(1<<MSM_ADSP_CODEC_WMA)| \
+	(1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \
+	(1<<MSM_ADSP_CODEC_AMRNB)|(1<<MSM_ADSP_CODEC_WAV)| \
+	(1<<MSM_ADSP_CODEC_ADPCM)|(1<<MSM_ADSP_CODEC_YADPCM)| \
+	(1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP))
+#define DEC4_FORMAT (1<<MSM_ADSP_CODEC_MIDI)
+
+static unsigned int dec_concurrency_table[] = {
+	/* Audio LP */
+	0,
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_MODE_LP)|
+	(1<<MSM_ADSP_OP_DM)),
+
+	/* Concurrency 1 */
+	(DEC4_FORMAT),
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+
+	 /* Concurrency 2 */
+	(DEC4_FORMAT),
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+
+	/* Concurrency 3 */
+	(DEC4_FORMAT),
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+
+	/* Concurrency 4 */
+	(DEC4_FORMAT),
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+
+	/* Concurrency 5 */
+	(DEC4_FORMAT),
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+
+	/* Concurrency 6 */
+	(DEC4_FORMAT),
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+};
+
+#define DEC_INFO(name, queueid, decid, nr_codec) { .module_name = name, \
+	.module_queueid = queueid, .module_decid = decid, \
+	.nr_codec_support = nr_codec}
+
+#define DEC_INSTANCE(max_instance_same, max_instance_diff) { \
+	.max_instances_same_dec = max_instance_same, \
+	.max_instances_diff_dec = max_instance_diff}
+
+static struct msm_adspdec_info dec_info_list[] = {
+	DEC_INFO("AUDPLAY4TASK", 17, 4, 1),  /* AudPlay4BitStreamCtrlQueue */
+	DEC_INFO("AUDPLAY3TASK", 16, 3, 11),  /* AudPlay3BitStreamCtrlQueue */
+	DEC_INFO("AUDPLAY2TASK", 15, 2, 11),  /* AudPlay2BitStreamCtrlQueue */
+	DEC_INFO("AUDPLAY1TASK", 14, 1, 11),  /* AudPlay1BitStreamCtrlQueue */
+	DEC_INFO("AUDPLAY0TASK", 13, 0, 11), /* AudPlay0BitStreamCtrlQueue */
+};
+
+static struct dec_instance_table dec_instance_list[][MSM_MAX_DEC_CNT] = {
+	/* Non Turbo Mode */
+	{
+		DEC_INSTANCE(4, 3), /* WAV */
+		DEC_INSTANCE(4, 3), /* ADPCM */
+		DEC_INSTANCE(4, 2), /* MP3 */
+		DEC_INSTANCE(0, 0), /* Real Audio */
+		DEC_INSTANCE(4, 2), /* WMA */
+		DEC_INSTANCE(3, 2), /* AAC */
+		DEC_INSTANCE(0, 0), /* Reserved */
+		DEC_INSTANCE(0, 0), /* MIDI */
+		DEC_INSTANCE(4, 3), /* YADPCM */
+		DEC_INSTANCE(4, 3), /* QCELP */
+		DEC_INSTANCE(4, 3), /* AMRNB */
+		DEC_INSTANCE(1, 1), /* AMRWB/WB+ */
+		DEC_INSTANCE(4, 3), /* EVRC */
+		DEC_INSTANCE(1, 1), /* WMAPRO */
+	},
+	/* Turbo Mode */
+	{
+		DEC_INSTANCE(4, 3), /* WAV */
+		DEC_INSTANCE(4, 3), /* ADPCM */
+		DEC_INSTANCE(4, 3), /* MP3 */
+		DEC_INSTANCE(0, 0), /* Real Audio */
+		DEC_INSTANCE(4, 3), /* WMA */
+		DEC_INSTANCE(4, 3), /* AAC */
+		DEC_INSTANCE(0, 0), /* Reserved */
+		DEC_INSTANCE(0, 0), /* MIDI */
+		DEC_INSTANCE(4, 3), /* YADPCM */
+		DEC_INSTANCE(4, 3), /* QCELP */
+		DEC_INSTANCE(4, 3), /* AMRNB */
+		DEC_INSTANCE(2, 3), /* AMRWB/WB+ */
+		DEC_INSTANCE(4, 3), /* EVRC */
+		DEC_INSTANCE(1, 2), /* WMAPRO */
+	},
+};
+
+static struct msm_adspdec_database msm_device_adspdec_database = {
+	.num_dec = ARRAY_SIZE(dec_info_list),
+	.num_concurrency_support = (ARRAY_SIZE(dec_concurrency_table) / \
+					ARRAY_SIZE(dec_info_list)),
+	.dec_concurrency_table = dec_concurrency_table,
+	.dec_info_list = dec_info_list,
+	.dec_instance_list = &dec_instance_list[0][0],
+};
+
+static struct platform_device msm_device_adspdec = {
+	.name = "msm_adspdec",
+	.id = -1,
+	.dev    = {
+		.platform_data = &msm_device_adspdec_database
+	},
+};
+
+static struct resource smc91x_resources[] = {
+	[0] = {
+		.start = 0x8A000300,
+		.end = 0x8A0003ff,
+		.flags  = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = MSM_GPIO_TO_INT(156),
+		.end = MSM_GPIO_TO_INT(156),
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device smc91x_device = {
+	.name           = "smc91x",
+	.id             = 0,
+	.num_resources  = ARRAY_SIZE(smc91x_resources),
+	.resource       = smc91x_resources,
+};
+
+static struct smsc911x_platform_config smsc911x_config = {
+	.phy_interface	= PHY_INTERFACE_MODE_MII,
+	.irq_polarity	= SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+	.irq_type	= SMSC911X_IRQ_TYPE_PUSH_PULL,
+	.flags		= SMSC911X_USE_32BIT,
+};
+
+static struct resource smsc911x_resources[] = {
+	[0] = {
+		.start		= 0x8D000000,
+		.end		= 0x8D000100,
+		.flags		= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start		= MSM_GPIO_TO_INT(88),
+		.end		= MSM_GPIO_TO_INT(88),
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device smsc911x_device = {
+	.name		= "smsc911x",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(smsc911x_resources),
+	.resource	= smsc911x_resources,
+	.dev		= {
+		.platform_data = &smsc911x_config,
+	},
+};
+
+static struct msm_gpio smsc911x_gpios[] = {
+    { GPIO_CFG(172, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "ebi2_addr6" },
+    { GPIO_CFG(173, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "ebi2_addr5" },
+    { GPIO_CFG(174, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "ebi2_addr4" },
+    { GPIO_CFG(175, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "ebi2_addr3" },
+    { GPIO_CFG(176, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "ebi2_addr2" },
+    { GPIO_CFG(177, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "ebi2_addr1" },
+    { GPIO_CFG(178, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "ebi2_addr0" },
+    { GPIO_CFG(88, 2, GPIO_CFG_INPUT, GPIO_CFG_PULL_UP, GPIO_CFG_2MA), "smsc911x_irq"  },
+};
+
+static void msm7x30_cfg_smsc911x(void)
+{
+	int rc;
+
+	rc = msm_gpios_request_enable(smsc911x_gpios,
+			ARRAY_SIZE(smsc911x_gpios));
+	if (rc)
+		pr_err("%s: unable to enable gpios\n", __func__);
+}
+
+#ifdef CONFIG_USB_G_ANDROID
+static struct android_usb_platform_data android_usb_pdata = {
+	.update_pid_and_serial_num = usb_diag_update_pid_and_serial_num,
+};
+
+static struct platform_device android_usb_device = {
+	.name	= "android_usb",
+	.id		= -1,
+	.dev		= {
+		.platform_data = &android_usb_pdata,
+	},
+};
+#endif
+
+static struct msm_gpio optnav_config_data[] = {
+	{ GPIO_CFG(OPTNAV_CHIP_SELECT, 0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA),
+	"optnav_chip_select" },
+};
+
+static struct regulator_bulk_data optnav_regulators[] = {
+	{ .supply = "gp7", .min_uV = 1800000, .max_uV = 1800000 },
+	{ .supply = "gp4", .min_uV = 2600000, .max_uV = 2600000 },
+	{ .supply = "gp9", .min_uV = 1800000, .max_uV = 1800000 },
+	{ .supply = "usb", .min_uV = 3300000, .max_uV = 3300000 },
+};
+
+static void __iomem *virtual_optnav;
+
+static int optnav_gpio_setup(void)
+{
+	int rc = -ENODEV;
+	rc = msm_gpios_request_enable(optnav_config_data,
+			ARRAY_SIZE(optnav_config_data));
+
+	if (rc)
+		return rc;
+
+	/* Configure the FPGA for GPIOs */
+	virtual_optnav = ioremap(FPGA_OPTNAV_GPIO_ADDR, 0x4);
+	if (!virtual_optnav) {
+		pr_err("%s:Could not ioremap region\n", __func__);
+		return -ENOMEM;
+	}
+	/*
+	 * Configure the FPGA to set GPIO 19 as
+	 * normal, active(enabled), output(MSM to SURF)
+	 */
+	writew(0x311E, virtual_optnav);
+
+	rc = regulator_bulk_get(NULL, ARRAY_SIZE(optnav_regulators),
+			optnav_regulators);
+	if (rc)
+		return rc;
+
+	rc = regulator_bulk_set_voltage(ARRAY_SIZE(optnav_regulators),
+			optnav_regulators);
+
+	if (rc)
+		goto regulator_put;
+
+	return rc;
+
+regulator_put:
+	regulator_bulk_free(ARRAY_SIZE(optnav_regulators), optnav_regulators);
+	return rc;
+}
+
+static void optnav_gpio_release(void)
+{
+	msm_gpios_disable_free(optnav_config_data,
+		ARRAY_SIZE(optnav_config_data));
+	iounmap(virtual_optnav);
+	regulator_bulk_free(ARRAY_SIZE(optnav_regulators), optnav_regulators);
+}
+
+static int optnav_enable(void)
+{
+	int rc;
+	/*
+	 * Enable the VREGs L8(gp7), L10(gp4), L12(gp9), L6(usb)
+	 * for I2C communication with keyboard.
+	 */
+
+	rc = regulator_bulk_enable(ARRAY_SIZE(optnav_regulators),
+			optnav_regulators);
+
+	if (rc)
+		return rc;
+
+	/* Enable the chip select GPIO */
+	gpio_set_value(OPTNAV_CHIP_SELECT, 1);
+	gpio_set_value(OPTNAV_CHIP_SELECT, 0);
+
+	return 0;
+}
+
+static void optnav_disable(void)
+{
+	regulator_bulk_disable(ARRAY_SIZE(optnav_regulators),
+			optnav_regulators);
+
+	gpio_set_value(OPTNAV_CHIP_SELECT, 1);
+}
+
+static struct ofn_atlab_platform_data optnav_data = {
+	.gpio_setup    = optnav_gpio_setup,
+	.gpio_release  = optnav_gpio_release,
+	.optnav_on     = optnav_enable,
+	.optnav_off    = optnav_disable,
+	.rotate_xy     = 0,
+	.function1 = {
+		.no_motion1_en		= true,
+		.touch_sensor_en	= true,
+		.ofn_en			= true,
+		.clock_select_khz	= 1500,
+		.cpi_selection		= 1200,
+	},
+	.function2 =  {
+		.invert_y		= false,
+		.invert_x		= true,
+		.swap_x_y		= false,
+		.hold_a_b_en		= true,
+		.motion_filter_en       = true,
+	},
+};
+
+static int hdmi_comm_power(int on, int show);
+static int hdmi_init_irq(void);
+static int hdmi_enable_5v(int on);
+static int hdmi_core_power(int on, int show);
+static int hdmi_cec_power(int on);
+static bool hdmi_check_hdcp_hw_support(void);
+
+static struct msm_hdmi_platform_data adv7520_hdmi_data = {
+	.irq = MSM_GPIO_TO_INT(18),
+	.comm_power = hdmi_comm_power,
+	.init_irq = hdmi_init_irq,
+	.enable_5v = hdmi_enable_5v,
+	.core_power = hdmi_core_power,
+	.cec_power = hdmi_cec_power,
+	.check_hdcp_hw_support = hdmi_check_hdcp_hw_support,
+};
+
+#ifdef CONFIG_BOSCH_BMA150
+
+static struct regulator_bulk_data sensors_ldo[] = {
+	{ .supply = "gp7", .min_uV = 1800000, .max_uV = 1800000 },
+	{ .supply = "gp6", .min_uV = 3050000, .max_uV = 3100000 },
+};
+
+static int __init sensors_ldo_init(void)
+{
+	int rc;
+
+	rc = regulator_bulk_get(NULL, ARRAY_SIZE(sensors_ldo), sensors_ldo);
+
+	if (rc) {
+		pr_err("%s: could not get regulators: %d\n", __func__, rc);
+		goto out;
+	}
+
+	rc = regulator_bulk_set_voltage(ARRAY_SIZE(sensors_ldo), sensors_ldo);
+
+	if (rc) {
+		pr_err("%s: could not set voltages: %d\n", __func__, rc);
+		goto reg_free;
+	}
+
+	return 0;
+
+reg_free:
+	regulator_bulk_free(ARRAY_SIZE(sensors_ldo), sensors_ldo);
+out:
+	return rc;
+}
+
+static int sensors_ldo_set(int on)
+{
+	int rc = on ?
+		regulator_bulk_enable(ARRAY_SIZE(sensors_ldo), sensors_ldo) :
+		regulator_bulk_disable(ARRAY_SIZE(sensors_ldo), sensors_ldo);
+
+	if (rc)
+		pr_err("%s: could not %sable regulators: %d\n",
+				__func__, on ? "en" : "dis", rc);
+
+	return rc;
+}
+
+static int sensors_ldo_enable(void)
+{
+	return sensors_ldo_set(1);
+}
+
+static void sensors_ldo_disable(void)
+{
+	sensors_ldo_set(0);
+}
+
+static struct bma150_platform_data bma150_data = {
+	.power_on = sensors_ldo_enable,
+	.power_off = sensors_ldo_disable,
+};
+
+static struct i2c_board_info bma150_board_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("bma150", 0x38),
+		.flags = I2C_CLIENT_WAKE,
+		.irq = MSM_GPIO_TO_INT(BMA150_GPIO_INT),
+		.platform_data = &bma150_data,
+	},
+};
+#endif
+
+static struct i2c_board_info msm_i2c_board_info[] = {
+	{
+		I2C_BOARD_INFO("m33c01", OPTNAV_I2C_SLAVE_ADDR),
+		.irq		= MSM_GPIO_TO_INT(OPTNAV_IRQ),
+		.platform_data = &optnav_data,
+	},
+	{
+		I2C_BOARD_INFO("adv7520", ADV7520_I2C_ADDR),
+		.platform_data = &adv7520_hdmi_data,
+	},
+};
+
+static struct i2c_board_info msm_marimba_board_info[] = {
+	{
+		I2C_BOARD_INFO("marimba", 0xc),
+		.platform_data = &marimba_pdata,
+	}
+};
+
+
+static struct msm_handset_platform_data hs_platform_data = {
+	.hs_name = "7k_handset",
+	.pwr_key_delay_ms = 500, /* 0 will disable end key */
+};
+
+static struct platform_device hs_device = {
+	.name   = "msm-handset",
+	.id     = -1,
+	.dev    = {
+		.platform_data = &hs_platform_data,
+	},
+};
+
+static struct msm_pm_platform_data msm_pm_data[MSM_PM_SLEEP_MODE_NR] = {
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = {
+		.idle_supported = 1,
+		.suspend_supported = 1,
+		.idle_enabled = 1,
+		.suspend_enabled = 1,
+		.latency = 8594,
+		.residency = 23740,
+	},
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN)] = {
+		.idle_supported = 1,
+		.suspend_supported = 1,
+		.idle_enabled = 1,
+		.suspend_enabled = 1,
+		.latency = 4594,
+		.residency = 23740,
+	},
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = {
+#ifdef CONFIG_MSM_STANDALONE_POWER_COLLAPSE
+		.idle_supported = 1,
+		.suspend_supported = 1,
+		.idle_enabled = 1,
+		.suspend_enabled = 0,
+#else /*CONFIG_MSM_STANDALONE_POWER_COLLAPSE*/
+		.idle_supported = 0,
+		.suspend_supported = 0,
+		.idle_enabled = 0,
+		.suspend_enabled = 0,
+#endif /*CONFIG_MSM_STANDALONE_POWER_COLLAPSE*/
+		.latency = 500,
+		.residency = 6000,
+	},
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT)] = {
+		.idle_supported = 1,
+		.suspend_supported = 1,
+		.idle_enabled = 0,
+		.suspend_enabled = 1,
+		.latency = 443,
+		.residency = 1098,
+	},
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
+		.idle_supported = 1,
+		.suspend_supported = 1,
+		.idle_enabled = 1,
+		.suspend_enabled = 1,
+		.latency = 2,
+		.residency = 0,
+	},
+};
+
+static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT,
+	.v_addr = (uint32_t *)PAGE_OFFSET,
+};
+
+static struct resource qsd_spi_resources[] = {
+	{
+		.name   = "spi_irq_in",
+		.start	= INT_SPI_INPUT,
+		.end	= INT_SPI_INPUT,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name   = "spi_irq_out",
+		.start	= INT_SPI_OUTPUT,
+		.end	= INT_SPI_OUTPUT,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name   = "spi_irq_err",
+		.start	= INT_SPI_ERROR,
+		.end	= INT_SPI_ERROR,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name   = "spi_base",
+		.start	= 0xA8000000,
+		.end	= 0xA8000000 + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "spidm_channels",
+		.flags  = IORESOURCE_DMA,
+	},
+	{
+		.name   = "spidm_crci",
+		.flags  = IORESOURCE_DMA,
+	},
+};
+
+#define AMDH0_BASE_PHYS		0xAC200000
+#define ADMH0_GP_CTL		(ct_adm_base + 0x3D8)
+static int msm_qsd_spi_dma_config(void)
+{
+	void __iomem *ct_adm_base = 0;
+	u32 spi_mux = 0;
+	int ret = 0;
+
+	ct_adm_base = ioremap(AMDH0_BASE_PHYS, PAGE_SIZE);
+	if (!ct_adm_base) {
+		pr_err("%s: Could not remap %x\n", __func__, AMDH0_BASE_PHYS);
+		return -ENOMEM;
+	}
+
+	spi_mux = (ioread32(ADMH0_GP_CTL) & (0x3 << 12)) >> 12;
+
+	qsd_spi_resources[4].start  = DMOV_USB_CHAN;
+	qsd_spi_resources[4].end    = DMOV_TSIF_CHAN;
+
+	switch (spi_mux) {
+	case (1):
+		qsd_spi_resources[5].start  = DMOV_HSUART1_RX_CRCI;
+		qsd_spi_resources[5].end    = DMOV_HSUART1_TX_CRCI;
+		break;
+	case (2):
+		qsd_spi_resources[5].start  = DMOV_HSUART2_RX_CRCI;
+		qsd_spi_resources[5].end    = DMOV_HSUART2_TX_CRCI;
+		break;
+	case (3):
+		qsd_spi_resources[5].start  = DMOV_CE_OUT_CRCI;
+		qsd_spi_resources[5].end    = DMOV_CE_IN_CRCI;
+		break;
+	default:
+		ret = -ENOENT;
+	}
+
+	iounmap(ct_adm_base);
+
+	return ret;
+}
+
+static struct platform_device qsd_device_spi = {
+	.name		= "spi_qsd",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(qsd_spi_resources),
+	.resource	= qsd_spi_resources,
+};
+
+#ifdef CONFIG_SPI_QSD
+static struct spi_board_info lcdc_sharp_spi_board_info[] __initdata = {
+	{
+		.modalias	= "lcdc_sharp_ls038y7dx01",
+		.mode		= SPI_MODE_1,
+		.bus_num	= 0,
+		.chip_select	= 0,
+		.max_speed_hz	= 26331429,
+	}
+};
+static struct spi_board_info lcdc_toshiba_spi_board_info[] __initdata = {
+	{
+		.modalias       = "lcdc_toshiba_ltm030dd40",
+		.mode           = SPI_MODE_3|SPI_CS_HIGH,
+		.bus_num        = 0,
+		.chip_select    = 0,
+		.max_speed_hz   = 9963243,
+	}
+};
+#endif
+
+static struct msm_gpio qsd_spi_gpio_config_data[] = {
+	{ GPIO_CFG(45, 1, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "spi_clk" },
+	{ GPIO_CFG(46, 1, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "spi_cs0" },
+	{ GPIO_CFG(47, 1, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_8MA), "spi_mosi" },
+	{ GPIO_CFG(48, 1, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "spi_miso" },
+};
+
+static int msm_qsd_spi_gpio_config(void)
+{
+	return msm_gpios_request_enable(qsd_spi_gpio_config_data,
+		ARRAY_SIZE(qsd_spi_gpio_config_data));
+}
+
+static void msm_qsd_spi_gpio_release(void)
+{
+	msm_gpios_disable_free(qsd_spi_gpio_config_data,
+		ARRAY_SIZE(qsd_spi_gpio_config_data));
+}
+
+static struct msm_spi_platform_data qsd_spi_pdata = {
+	.max_clock_speed = 26331429,
+	.gpio_config  = msm_qsd_spi_gpio_config,
+	.gpio_release = msm_qsd_spi_gpio_release,
+	.dma_config = msm_qsd_spi_dma_config,
+};
+
+static void __init msm_qsd_spi_init(void)
+{
+	qsd_device_spi.dev.platform_data = &qsd_spi_pdata;
+}
+
+#ifdef CONFIG_USB_EHCI_MSM_72K
+static void msm_hsusb_vbus_power(unsigned phy_info, int on)
+{
+        int rc;
+        static int vbus_is_on;
+	struct pm8xxx_gpio_init_info usb_vbus = {
+		PM8058_GPIO_PM_TO_SYS(36),
+		{
+			.direction      = PM_GPIO_DIR_OUT,
+			.pull           = PM_GPIO_PULL_NO,
+			.output_buffer  = PM_GPIO_OUT_BUF_CMOS,
+			.output_value   = 1,
+			.vin_sel        = 2,
+			.out_strength   = PM_GPIO_STRENGTH_MED,
+			.function       = PM_GPIO_FUNC_NORMAL,
+			.inv_int_pol    = 0,
+		},
+	};
+
+        /* If VBUS is already on (or off), do nothing. */
+        if (unlikely(on == vbus_is_on))
+                return;
+
+        if (on) {
+		rc = pm8xxx_gpio_config(usb_vbus.gpio, &usb_vbus.config);
+		if (rc) {
+                        pr_err("%s PMIC GPIO 36 write failed\n", __func__);
+                        return;
+                }
+	} else {
+		gpio_set_value_cansleep(PM8058_GPIO_PM_TO_SYS(36), 0);
+	}
+
+        vbus_is_on = on;
+}
+
+static struct msm_usb_host_platform_data msm_usb_host_pdata = {
+        .phy_info   = (USB_PHY_INTEGRATED | USB_PHY_MODEL_45NM),
+        .vbus_power = msm_hsusb_vbus_power,
+        .power_budget   = 180,
+};
+#endif
+
+#ifdef CONFIG_USB_MSM_OTG_72K
+static int hsusb_rpc_connect(int connect)
+{
+	if (connect)
+		return msm_hsusb_rpc_connect();
+	else
+		return msm_hsusb_rpc_close();
+}
+#endif
+
+#ifdef CONFIG_USB_MSM_OTG_72K
+static struct regulator *vreg_3p3;
+static int msm_hsusb_ldo_init(int init)
+{
+	uint32_t version = 0;
+	int def_vol = 3400000;
+
+	version = socinfo_get_version();
+
+	if (SOCINFO_VERSION_MAJOR(version) >= 2 &&
+			SOCINFO_VERSION_MINOR(version) >= 1) {
+		def_vol = 3075000;
+		pr_debug("%s: default voltage:%d\n", __func__, def_vol);
+	}
+
+	if (init) {
+		vreg_3p3 = regulator_get(NULL, "usb");
+		if (IS_ERR(vreg_3p3))
+			return PTR_ERR(vreg_3p3);
+		regulator_set_voltage(vreg_3p3, def_vol, def_vol);
+	} else
+		regulator_put(vreg_3p3);
+
+	return 0;
+}
+
+static int msm_hsusb_ldo_enable(int enable)
+{
+	static int ldo_status;
+
+	if (!vreg_3p3 || IS_ERR(vreg_3p3))
+		return -ENODEV;
+
+	if (ldo_status == enable)
+		return 0;
+
+	ldo_status = enable;
+
+	if (enable)
+		return regulator_enable(vreg_3p3);
+	else
+		return regulator_disable(vreg_3p3);
+}
+
+static int msm_hsusb_ldo_set_voltage(int mV)
+{
+	static int cur_voltage;
+
+	if (!vreg_3p3 || IS_ERR(vreg_3p3))
+		return -ENODEV;
+
+	if (cur_voltage == mV)
+		return 0;
+
+	cur_voltage = mV;
+
+	pr_debug("%s: (%d)\n", __func__, mV);
+
+	return regulator_set_voltage(vreg_3p3, mV*1000, mV*1000);
+}
+#endif
+
+#ifndef CONFIG_USB_EHCI_MSM_72K
+static int msm_hsusb_pmic_notif_init(void (*callback)(int online), int init);
+#endif
+static struct msm_otg_platform_data msm_otg_pdata = {
+	.rpc_connect	= hsusb_rpc_connect,
+
+#ifndef CONFIG_USB_EHCI_MSM_72K
+	.pmic_vbus_notif_init         = msm_hsusb_pmic_notif_init,
+#else
+	.vbus_power = msm_hsusb_vbus_power,
+#endif
+	.pemp_level		 = PRE_EMPHASIS_WITH_20_PERCENT,
+	.cdr_autoreset		 = CDR_AUTO_RESET_DISABLE,
+	.drv_ampl		 = HS_DRV_AMPLITUDE_DEFAULT,
+	.se1_gating		 = SE1_GATING_DISABLE,
+	.chg_vbus_draw		 = hsusb_chg_vbus_draw,
+	.chg_connected		 = hsusb_chg_connected,
+	.chg_init		 = hsusb_chg_init,
+	.ldo_enable		 = msm_hsusb_ldo_enable,
+	.ldo_init		 = msm_hsusb_ldo_init,
+	.ldo_set_voltage	 = msm_hsusb_ldo_set_voltage,
+};
+
+#ifdef CONFIG_USB_GADGET
+static struct msm_hsusb_gadget_platform_data msm_gadget_pdata = {
+	.is_phy_status_timer_on = 1,
+};
+#endif
+#ifndef CONFIG_USB_EHCI_MSM_72K
+typedef void (*notify_vbus_state) (int);
+notify_vbus_state notify_vbus_state_func_ptr;
+int vbus_on_irq;
+static irqreturn_t pmic_vbus_on_irq(int irq, void *data)
+{
+	pr_info("%s: vbus notification from pmic\n", __func__);
+
+	(*notify_vbus_state_func_ptr) (1);
+
+	return IRQ_HANDLED;
+}
+static int msm_hsusb_pmic_notif_init(void (*callback)(int online), int init)
+{
+	int ret;
+
+	if (init) {
+		if (!callback)
+			return -ENODEV;
+
+		notify_vbus_state_func_ptr = callback;
+		vbus_on_irq = platform_get_irq_byname(&msm_device_otg,
+			"vbus_on");
+		if (vbus_on_irq <= 0) {
+			pr_err("%s: unable to get vbus on irq\n", __func__);
+			return -ENODEV;
+		}
+
+		ret = request_any_context_irq(vbus_on_irq, pmic_vbus_on_irq,
+			IRQF_TRIGGER_RISING, "msm_otg_vbus_on", NULL);
+		if (ret < 0) {
+			pr_info("%s: request_irq for vbus_on"
+				"interrupt failed\n", __func__);
+			return ret;
+		}
+		msm_otg_pdata.pmic_vbus_irq = vbus_on_irq;
+		return 0;
+	} else {
+		free_irq(vbus_on_irq, 0);
+		notify_vbus_state_func_ptr = NULL;
+		return 0;
+	}
+}
+#endif
+
+static struct android_pmem_platform_data android_pmem_pdata = {
+	.name = "pmem",
+	.allocator_type = PMEM_ALLOCATORTYPE_ALLORNOTHING,
+	.cached = 1,
+	.memory_type = MEMTYPE_EBI0,
+};
+
+static struct platform_device android_pmem_device = {
+	.name = "android_pmem",
+	.id = 0,
+	.dev = { .platform_data = &android_pmem_pdata },
+};
+
+#ifndef CONFIG_SPI_QSD
+static int lcdc_gpio_array_num[] = {
+				45, /* spi_clk */
+				46, /* spi_cs  */
+				47, /* spi_mosi */
+				48, /* spi_miso */
+				};
+
+static struct msm_gpio lcdc_gpio_config_data[] = {
+	{ GPIO_CFG(45, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "spi_clk" },
+	{ GPIO_CFG(46, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "spi_cs0" },
+	{ GPIO_CFG(47, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "spi_mosi" },
+	{ GPIO_CFG(48, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "spi_miso" },
+};
+
+static void lcdc_config_gpios(int enable)
+{
+	if (enable) {
+		msm_gpios_request_enable(lcdc_gpio_config_data,
+					      ARRAY_SIZE(
+						      lcdc_gpio_config_data));
+	} else
+		msm_gpios_disable_free(lcdc_gpio_config_data,
+					    ARRAY_SIZE(
+						    lcdc_gpio_config_data));
+}
+#endif
+
+static struct msm_panel_common_pdata lcdc_sharp_panel_data = {
+#ifndef CONFIG_SPI_QSD
+	.panel_config_gpio = lcdc_config_gpios,
+	.gpio_num          = lcdc_gpio_array_num,
+#endif
+	.gpio = 2, 	/* LPG PMIC_GPIO26 channel number */
+};
+
+static struct platform_device lcdc_sharp_panel_device = {
+	.name   = "lcdc_sharp_wvga",
+	.id     = 0,
+	.dev    = {
+		.platform_data = &lcdc_sharp_panel_data,
+	}
+};
+
+static struct msm_gpio dtv_panel_irq_gpios[] = {
+	{ GPIO_CFG(18, 0, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA),
+		"hdmi_int" },
+};
+
+static struct msm_gpio dtv_panel_gpios[] = {
+	{ GPIO_CFG(120, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "wca_mclk" },
+	{ GPIO_CFG(121, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "wca_sd0" },
+	{ GPIO_CFG(122, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "wca_sd1" },
+	{ GPIO_CFG(123, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "wca_sd2" },
+	{ GPIO_CFG(124, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_8MA), "dtv_pclk" },
+	{ GPIO_CFG(125, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "dtv_en" },
+	{ GPIO_CFG(126, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "dtv_vsync" },
+	{ GPIO_CFG(127, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "dtv_hsync" },
+	{ GPIO_CFG(128, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "dtv_data0" },
+	{ GPIO_CFG(129, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "dtv_data1" },
+	{ GPIO_CFG(130, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "dtv_data2" },
+	{ GPIO_CFG(131, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "dtv_data3" },
+	{ GPIO_CFG(132, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "dtv_data4" },
+	{ GPIO_CFG(160, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "dtv_data5" },
+	{ GPIO_CFG(161, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "dtv_data6" },
+	{ GPIO_CFG(162, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "dtv_data7" },
+	{ GPIO_CFG(163, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "dtv_data8" },
+	{ GPIO_CFG(164, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "dtv_data9" },
+	{ GPIO_CFG(165, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "dtv_dat10" },
+	{ GPIO_CFG(166, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "dtv_dat11" },
+	{ GPIO_CFG(167, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "dtv_dat12" },
+	{ GPIO_CFG(168, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "dtv_dat13" },
+	{ GPIO_CFG(169, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "dtv_dat14" },
+	{ GPIO_CFG(170, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "dtv_dat15" },
+	{ GPIO_CFG(171, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "dtv_dat16" },
+	{ GPIO_CFG(172, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "dtv_dat17" },
+	{ GPIO_CFG(173, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "dtv_dat18" },
+	{ GPIO_CFG(174, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "dtv_dat19" },
+	{ GPIO_CFG(175, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "dtv_dat20" },
+	{ GPIO_CFG(176, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "dtv_dat21" },
+	{ GPIO_CFG(177, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "dtv_dat22" },
+	{ GPIO_CFG(178, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_4MA), "dtv_dat23" },
+};
+
+
+#ifdef HDMI_RESET
+static unsigned dtv_reset_gpio =
+	GPIO_CFG(37, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA);
+#endif
+
+static struct regulator_bulk_data hdmi_core_regs[] = {
+	{ .supply = "ldo8",  .min_uV = 1800000, .max_uV = 1800000 },
+};
+
+static struct regulator_bulk_data hdmi_comm_regs[] = {
+	{ .supply = "ldo8",  .min_uV = 1800000, .max_uV = 1800000 },
+	{ .supply = "ldo10", .min_uV = 2600000, .max_uV = 2600000 },
+};
+
+static struct regulator_bulk_data hdmi_cec_regs[] = {
+	{ .supply = "ldo17", .min_uV = 2600000, .max_uV = 2600000 },
+};
+
+static int __init hdmi_init_regs(void)
+{
+	int rc;
+
+	rc = regulator_bulk_get(NULL, ARRAY_SIZE(hdmi_core_regs),
+			hdmi_core_regs);
+
+	if (rc) {
+		pr_err("%s: could not get %s regulators: %d\n",
+				__func__, "core", rc);
+		goto out;
+	}
+
+	rc = regulator_bulk_set_voltage(ARRAY_SIZE(hdmi_core_regs),
+			hdmi_core_regs);
+
+	if (rc) {
+		pr_err("%s: could not set %s voltages: %d\n",
+				__func__, "core", rc);
+		goto free_core;
+	}
+
+	rc = regulator_bulk_get(NULL, ARRAY_SIZE(hdmi_comm_regs),
+			hdmi_comm_regs);
+
+	if (rc) {
+		pr_err("%s: could not get %s regulators: %d\n",
+				__func__, "comm", rc);
+		goto free_core;
+	}
+
+	rc = regulator_bulk_set_voltage(ARRAY_SIZE(hdmi_comm_regs),
+			hdmi_comm_regs);
+
+	if (rc) {
+		pr_err("%s: could not set %s voltages: %d\n",
+				__func__, "comm", rc);
+		goto free_comm;
+	}
+
+	rc = regulator_bulk_get(NULL, ARRAY_SIZE(hdmi_cec_regs),
+			hdmi_cec_regs);
+
+	if (rc) {
+		pr_err("%s: could not get %s regulators: %d\n",
+				__func__, "cec", rc);
+		goto free_comm;
+	}
+
+	rc = regulator_bulk_set_voltage(ARRAY_SIZE(hdmi_cec_regs),
+			hdmi_cec_regs);
+
+	if (rc) {
+		pr_err("%s: could not set %s voltages: %d\n",
+				__func__, "cec", rc);
+		goto free_cec;
+	}
+
+	return 0;
+
+free_cec:
+	regulator_bulk_free(ARRAY_SIZE(hdmi_cec_regs), hdmi_cec_regs);
+free_comm:
+	regulator_bulk_free(ARRAY_SIZE(hdmi_comm_regs), hdmi_comm_regs);
+free_core:
+	regulator_bulk_free(ARRAY_SIZE(hdmi_core_regs), hdmi_core_regs);
+out:
+	return rc;
+}
+
+static int hdmi_init_irq(void)
+{
+	int rc = msm_gpios_enable(dtv_panel_irq_gpios,
+			ARRAY_SIZE(dtv_panel_irq_gpios));
+	if (rc < 0) {
+		pr_err("%s: gpio enable failed: %d\n", __func__, rc);
+		return rc;
+	}
+	pr_info("%s\n", __func__);
+
+	return 0;
+}
+
+static int hdmi_enable_5v(int on)
+{
+	int pmic_gpio_hdmi_5v_en ;
+
+	if (machine_is_msm8x55_svlte_surf() || machine_is_msm8x55_svlte_ffa() ||
+						machine_is_msm7x30_fluid())
+		pmic_gpio_hdmi_5v_en = PMIC_GPIO_HDMI_5V_EN_V2 ;
+	else
+		pmic_gpio_hdmi_5v_en = PMIC_GPIO_HDMI_5V_EN_V3 ;
+
+	pr_info("%s: %d\n", __func__, on);
+	if (on) {
+		int rc;
+		rc = gpio_request(PM8058_GPIO_PM_TO_SYS(pmic_gpio_hdmi_5v_en),
+			"hdmi_5V_en");
+		if (rc) {
+			pr_err("%s PMIC_GPIO_HDMI_5V_EN gpio_request failed\n",
+				__func__);
+			return rc;
+		}
+		gpio_set_value_cansleep(
+			PM8058_GPIO_PM_TO_SYS(pmic_gpio_hdmi_5v_en), 1);
+	} else {
+		gpio_set_value_cansleep(
+			PM8058_GPIO_PM_TO_SYS(pmic_gpio_hdmi_5v_en), 0);
+		gpio_free(PM8058_GPIO_PM_TO_SYS(pmic_gpio_hdmi_5v_en));
+	}
+	return 0;
+}
+
+static int hdmi_comm_power(int on, int show)
+{
+	if (show)
+		pr_info("%s: i2c comm: %d <LDO8+LDO10>\n", __func__, on);
+	return on ?
+		regulator_bulk_enable(ARRAY_SIZE(hdmi_comm_regs),
+				hdmi_comm_regs) :
+		regulator_bulk_disable(ARRAY_SIZE(hdmi_comm_regs),
+				hdmi_comm_regs);
+}
+
+static int hdmi_core_power(int on, int show)
+{
+	if (show)
+		pr_info("%s: %d <LDO8>\n", __func__, on);
+	return on ?
+		regulator_bulk_enable(ARRAY_SIZE(hdmi_core_regs),
+				hdmi_core_regs) :
+		regulator_bulk_disable(ARRAY_SIZE(hdmi_core_regs),
+				hdmi_core_regs);
+}
+
+static int hdmi_cec_power(int on)
+{
+	pr_info("%s: %d <LDO17>\n", __func__, on);
+	return on ? regulator_bulk_enable(ARRAY_SIZE(hdmi_cec_regs),
+				hdmi_cec_regs) :
+		regulator_bulk_disable(ARRAY_SIZE(hdmi_cec_regs),
+				hdmi_cec_regs);
+}
+
+#if defined(CONFIG_FB_MSM_HDMI_ADV7520_PANEL) || defined(CONFIG_BOSCH_BMA150)
+/* there is an i2c address conflict between adv7520 and bma150 sensor after
+ * power up on fluid. As a solution, the default address of adv7520's packet
+ * memory is changed as soon as possible
+ */
+static int __init fluid_i2c_address_fixup(void)
+{
+	unsigned char wBuff[16];
+	unsigned char rBuff[16];
+	struct i2c_msg msgs[3];
+	int res;
+	int rc = -EINVAL;
+	struct i2c_adapter *adapter;
+
+	if (machine_is_msm7x30_fluid()) {
+		adapter = i2c_get_adapter(0);
+		if (!adapter) {
+			pr_err("%s: invalid i2c adapter\n", __func__);
+			return PTR_ERR(adapter);
+		}
+
+		/* turn on LDO8 */
+		rc = hdmi_core_power(1, 0);
+		if (rc) {
+			pr_err("%s: could not enable hdmi core regs: %d",
+					__func__, rc);
+			goto adapter_put;
+		}
+
+		/* change packet memory address to 0x74 */
+		wBuff[0] = 0x45;
+		wBuff[1] = 0x74;
+
+		msgs[0].addr = ADV7520_I2C_ADDR;
+		msgs[0].flags = 0;
+		msgs[0].buf = (unsigned char *) wBuff;
+		msgs[0].len = 2;
+
+		res = i2c_transfer(adapter, msgs, 1);
+		if (res != 1) {
+			pr_err("%s: error writing adv7520\n", __func__);
+			goto ldo8_disable;
+		}
+
+		/* powerdown adv7520 using bit 6 */
+		/* i2c read first */
+		wBuff[0] = 0x41;
+
+		msgs[0].addr = ADV7520_I2C_ADDR;
+		msgs[0].flags = 0;
+		msgs[0].buf = (unsigned char *) wBuff;
+		msgs[0].len = 1;
+
+		msgs[1].addr = ADV7520_I2C_ADDR;
+		msgs[1].flags = I2C_M_RD;
+		msgs[1].buf = rBuff;
+		msgs[1].len = 1;
+		res = i2c_transfer(adapter, msgs, 2);
+		if (res != 2) {
+			pr_err("%s: error reading adv7520\n", __func__);
+			goto ldo8_disable;
+		}
+
+		/* i2c write back */
+		wBuff[0] = 0x41;
+		wBuff[1] = rBuff[0] | 0x40;
+
+		msgs[0].addr = ADV7520_I2C_ADDR;
+		msgs[0].flags = 0;
+		msgs[0].buf = (unsigned char *) wBuff;
+		msgs[0].len = 2;
+
+		res = i2c_transfer(adapter, msgs, 1);
+		if (res != 1) {
+			pr_err("%s: error writing adv7520\n", __func__);
+			goto ldo8_disable;
+		}
+
+		/* for successful fixup, we release the i2c adapter */
+		/* but leave ldo8 on so that the adv7520 is not repowered */
+		i2c_put_adapter(adapter);
+		pr_info("%s: fluid i2c address conflict resolved\n", __func__);
+	}
+	return 0;
+
+ldo8_disable:
+	hdmi_core_power(0, 0);
+adapter_put:
+	i2c_put_adapter(adapter);
+	return rc;
+}
+fs_initcall_sync(fluid_i2c_address_fixup);
+#endif
+
+static bool hdmi_check_hdcp_hw_support(void)
+{
+	if (machine_is_msm7x30_fluid())
+		return false;
+	else
+		return true;
+}
+
+static int dtv_panel_power(int on)
+{
+	int flag_on = !!on;
+	static int dtv_power_save_on;
+	int rc;
+
+	if (dtv_power_save_on == flag_on)
+		return 0;
+
+	dtv_power_save_on = flag_on;
+	pr_info("%s: %d\n", __func__, on);
+
+#ifdef HDMI_RESET
+	if (on) {
+		/* reset Toshiba WeGA chip -- toggle reset pin -- gpio_180 */
+		rc = gpio_tlmm_config(dtv_reset_gpio, GPIO_CFG_ENABLE);
+		if (rc) {
+			pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
+				       __func__, dtv_reset_gpio, rc);
+			return rc;
+		}
+
+		/* bring reset line low to hold reset*/
+		gpio_set_value(37, 0);
+	}
+#endif
+
+	if (on) {
+		rc = msm_gpios_enable(dtv_panel_gpios,
+				ARRAY_SIZE(dtv_panel_gpios));
+		if (rc < 0) {
+			printk(KERN_ERR "%s: gpio enable failed: %d\n",
+				__func__, rc);
+			return rc;
+		}
+	} else {
+		rc = msm_gpios_disable(dtv_panel_gpios,
+				ARRAY_SIZE(dtv_panel_gpios));
+		if (rc < 0) {
+			printk(KERN_ERR "%s: gpio disable failed: %d\n",
+				__func__, rc);
+			return rc;
+		}
+	}
+
+	mdelay(5);		/* ensure power is stable */
+
+#ifdef HDMI_RESET
+	if (on) {
+		gpio_set_value(37, 1);	/* bring reset line high */
+		mdelay(10);		/* 10 msec before IO can be accessed */
+	}
+#endif
+
+	return rc;
+}
+
+static struct lcdc_platform_data dtv_pdata = {
+	.lcdc_power_save   = dtv_panel_power,
+};
+
+static struct msm_serial_hs_platform_data msm_uart_dm1_pdata = {
+       .inject_rx_on_wakeup = 1,
+       .rx_to_inject = 0xFD,
+};
+
+static struct resource msm_fb_resources[] = {
+	{
+		.flags  = IORESOURCE_DMA,
+	}
+};
+
+#ifdef CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE
+static struct resource msm_v4l2_video_overlay_resources[] = {
+	{
+	   .flags = IORESOURCE_DMA,
+	}
+};
+#endif
+
+static int msm_fb_detect_panel(const char *name)
+{
+	if (machine_is_msm7x30_fluid()) {
+		if (!strcmp(name, "lcdc_sharp_wvga_pt"))
+			return 0;
+	} else {
+		if (!strncmp(name, "mddi_toshiba_wvga_pt", 20))
+			return -EPERM;
+		else if (!strncmp(name, "lcdc_toshiba_wvga_pt", 20))
+			return 0;
+		else if (!strcmp(name, "mddi_orise"))
+			return -EPERM;
+		else if (!strcmp(name, "mddi_quickvx"))
+			return -EPERM;
+	}
+	return -ENODEV;
+}
+
+static struct msm_fb_platform_data msm_fb_pdata = {
+	.detect_client = msm_fb_detect_panel,
+	.mddi_prescan = 1,
+};
+
+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,
+	}
+};
+
+#ifdef CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE
+
+static struct platform_device msm_v4l2_video_overlay_device = {
+	.name   = "msm_v4l2_overlay_pd",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_v4l2_video_overlay_resources),
+	.resource       = msm_v4l2_video_overlay_resources,
+};
+#endif
+
+static struct platform_device msm_migrate_pages_device = {
+	.name   = "msm_migrate_pages",
+	.id     = -1,
+};
+
+static struct android_pmem_platform_data android_pmem_adsp_pdata = {
+       .name = "pmem_adsp",
+       .allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
+       .cached = 0,
+	.memory_type = MEMTYPE_EBI0,
+};
+
+static struct android_pmem_platform_data android_pmem_audio_pdata = {
+       .name = "pmem_audio",
+       .allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
+       .cached = 0,
+	.memory_type = MEMTYPE_EBI0,
+};
+
+static struct platform_device android_pmem_adsp_device = {
+       .name = "android_pmem",
+       .id = 2,
+       .dev = { .platform_data = &android_pmem_adsp_pdata },
+};
+
+static struct platform_device android_pmem_audio_device = {
+       .name = "android_pmem",
+       .id = 4,
+       .dev = { .platform_data = &android_pmem_audio_pdata },
+};
+
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+
+#define QCE_SIZE		0x10000
+#define QCE_0_BASE		0xA8400000
+
+#define QCE_HW_KEY_SUPPORT	1
+#define QCE_SHA_HMAC_SUPPORT	0
+#define QCE_SHARE_CE_RESOURCE	0
+#define QCE_CE_SHARED		0
+
+static struct resource qcrypto_resources[] = {
+	[0] = {
+		.start = QCE_0_BASE,
+		.end = QCE_0_BASE + QCE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.name = "crypto_channels",
+		.start = DMOV_CE_IN_CHAN,
+		.end = DMOV_CE_OUT_CHAN,
+		.flags = IORESOURCE_DMA,
+	},
+	[2] = {
+		.name = "crypto_crci_in",
+		.start = DMOV_CE_IN_CRCI,
+		.end = DMOV_CE_IN_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+	[3] = {
+		.name = "crypto_crci_out",
+		.start = DMOV_CE_OUT_CRCI,
+		.end = DMOV_CE_OUT_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+	[4] = {
+		.name = "crypto_crci_hash",
+		.start = DMOV_CE_HASH_CRCI,
+		.end = DMOV_CE_HASH_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static struct resource qcedev_resources[] = {
+	[0] = {
+		.start = QCE_0_BASE,
+		.end = QCE_0_BASE + QCE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.name = "crypto_channels",
+		.start = DMOV_CE_IN_CHAN,
+		.end = DMOV_CE_OUT_CHAN,
+		.flags = IORESOURCE_DMA,
+	},
+	[2] = {
+		.name = "crypto_crci_in",
+		.start = DMOV_CE_IN_CRCI,
+		.end = DMOV_CE_IN_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+	[3] = {
+		.name = "crypto_crci_out",
+		.start = DMOV_CE_OUT_CRCI,
+		.end = DMOV_CE_OUT_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+	[4] = {
+		.name = "crypto_crci_hash",
+		.start = DMOV_CE_HASH_CRCI,
+		.end = DMOV_CE_HASH_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
+
+static struct msm_ce_hw_support qcrypto_ce_hw_suppport = {
+	.ce_shared = QCE_CE_SHARED,
+	.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
+	.hw_key_support = QCE_HW_KEY_SUPPORT,
+	.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+	/* Bus Scaling declaration*/
+	.bus_scale_table = NULL,
+};
+
+static struct platform_device qcrypto_device = {
+	.name		= "qcrypto",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(qcrypto_resources),
+	.resource	= qcrypto_resources,
+	.dev		= {
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+		.platform_data = &qcrypto_ce_hw_suppport,
+	},
+};
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+
+static struct msm_ce_hw_support qcedev_ce_hw_suppport = {
+	.ce_shared = QCE_CE_SHARED,
+	.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
+	.hw_key_support = QCE_HW_KEY_SUPPORT,
+	.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+	/* Bus Scaling declaration*/
+	.bus_scale_table = NULL,
+};
+static struct platform_device qcedev_device = {
+	.name		= "qce",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(qcedev_resources),
+	.resource	= qcedev_resources,
+	.dev		= {
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+		.platform_data = &qcedev_ce_hw_suppport,
+	},
+};
+#endif
+
+static int mddi_toshiba_pmic_bl(int level)
+{
+	int ret = -EPERM;
+
+	ret = pmic_set_led_intensity(LED_LCD, level);
+
+	if (ret)
+		printk(KERN_WARNING "%s: can't set lcd backlight!\n",
+					__func__);
+	return ret;
+}
+
+static struct msm_panel_common_pdata mddi_toshiba_pdata = {
+	.pmic_backlight = mddi_toshiba_pmic_bl,
+};
+
+static struct platform_device mddi_toshiba_device = {
+	.name   = "mddi_toshiba",
+	.id     = 0,
+	.dev    = {
+		.platform_data = &mddi_toshiba_pdata,
+	}
+};
+
+static unsigned wega_reset_gpio =
+	GPIO_CFG(180, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA);
+
+static struct msm_gpio fluid_vee_reset_gpio[] = {
+	{ GPIO_CFG(20, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "vee_reset" },
+};
+
+static unsigned char quickvx_mddi_client = 1, other_mddi_client = 1;
+static unsigned char quickvx_ldo_enabled;
+
+static unsigned quickvx_vlp_gpio =
+	GPIO_CFG(97, 0, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL,	GPIO_CFG_2MA);
+
+static struct pm8xxx_gpio_init_info pmic_quickvx_clk_gpio = {
+	PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_QUICKVX_CLK),
+	{
+		.direction      = PM_GPIO_DIR_OUT,
+		.output_buffer  = PM_GPIO_OUT_BUF_CMOS,
+		.output_value   = 1,
+		.pull           = PM_GPIO_PULL_NO,
+		.vin_sel        = PM8058_GPIO_VIN_S3,
+		.out_strength   = PM_GPIO_STRENGTH_HIGH,
+		.function       = PM_GPIO_FUNC_2,
+	},
+};
+
+static struct regulator *mddi_ldo20;
+static struct regulator *mddi_ldo12;
+static struct regulator *mddi_ldo16;
+static struct regulator *mddi_ldo6;
+static struct regulator *mddi_lcd;
+
+static int display_common_init(void)
+{
+	struct regulator_bulk_data regs[5] = {
+		{ .supply = "ldo20", /* voltage set in display_common_power */},
+		{ .supply = "ldo12", .min_uV = 1800000, .max_uV = 1800000 },
+		{ .supply = "ldo6",  .min_uV = 3075000, .max_uV = 3400000 },
+		{ .supply = "ldo16", .min_uV = 2600000, .max_uV = 2600000 },
+		{ .supply = NULL,    /* mddi_lcd, initialized below */ },
+	};
+
+	int rc = 0;
+
+	if (machine_is_msm7x30_fluid()) {
+		/* lcd: LDO8 @1.8V */
+		regs[4].supply = "ldo8";
+		regs[4].min_uV = 1800000;
+		regs[4].max_uV = 1800000;
+	} else {
+		/* lcd: LDO15 @3.1V */
+		regs[4].supply = "ldo15";
+		regs[4].min_uV = 3100000;
+		regs[4].max_uV = 3100000;
+	}
+
+	rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs), regs);
+	if (rc) {
+		pr_err("%s: regulator_bulk_get failed: %d\n",
+				__func__, rc);
+		goto bail;
+	}
+
+	rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs), regs);
+	if (rc) {
+		pr_err("%s: regulator_bulk_set_voltage failed: %d\n",
+				__func__, rc);
+		goto put_regs;
+	}
+
+	mddi_ldo20 = regs[0].consumer;
+	mddi_ldo12 = regs[1].consumer;
+	mddi_ldo6  = regs[2].consumer;
+	mddi_ldo16 = regs[3].consumer;
+	mddi_lcd   = regs[4].consumer;
+
+	return rc;
+
+put_regs:
+	regulator_bulk_free(ARRAY_SIZE(regs), regs);
+bail:
+	return rc;
+}
+
+static int display_common_power(int on)
+{
+	int rc = 0, flag_on = !!on;
+	static int display_common_power_save_on;
+	static bool display_regs_initialized;
+
+	if (display_common_power_save_on == flag_on)
+		return 0;
+
+	display_common_power_save_on = flag_on;
+
+	if (unlikely(!display_regs_initialized)) {
+		rc = display_common_init();
+		if (rc) {
+			pr_err("%s: regulator init failed: %d\n",
+					__func__, rc);
+			return rc;
+		}
+		display_regs_initialized = true;
+	}
+
+
+	if (on) {
+		/* reset Toshiba WeGA chip -- toggle reset pin -- gpio_180 */
+		rc = gpio_tlmm_config(wega_reset_gpio, GPIO_CFG_ENABLE);
+		if (rc) {
+			pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
+				       __func__, wega_reset_gpio, rc);
+			return rc;
+		}
+
+		/* bring reset line low to hold reset*/
+		gpio_set_value(180, 0);
+
+		if (quickvx_mddi_client) {
+			/* QuickVX chip -- VLP pin -- gpio 97 */
+			rc = gpio_tlmm_config(quickvx_vlp_gpio,
+				GPIO_CFG_ENABLE);
+			if (rc) {
+				pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
+					__func__, quickvx_vlp_gpio, rc);
+				return rc;
+			}
+
+			/* bring QuickVX VLP line low */
+			gpio_set_value(97, 0);
+
+			rc = pm8xxx_gpio_config(pmic_quickvx_clk_gpio.gpio,
+						&pmic_quickvx_clk_gpio.config);
+			if (rc) {
+				pr_err("%s: pm8xxx_gpio_config(%#x)=%d\n",
+					__func__, pmic_quickvx_clk_gpio.gpio,
+					rc);
+				return rc;
+			}
+
+			gpio_set_value_cansleep(PM8058_GPIO_PM_TO_SYS(
+				PMIC_GPIO_QUICKVX_CLK), 0);
+		}
+	}
+
+	if (quickvx_mddi_client)
+		rc = regulator_set_voltage(mddi_ldo20, 1800000, 1800000);
+	else
+		rc = regulator_set_voltage(mddi_ldo20, 1500000, 1500000);
+
+	if (rc) {
+		pr_err("%s: could not set voltage for ldo20: %d\n",
+				__func__, rc);
+		return rc;
+	}
+
+	if (on) {
+		rc = regulator_enable(mddi_ldo20);
+		if (rc) {
+			pr_err("%s: LDO20 regulator enable failed (%d)\n",
+			       __func__, rc);
+			return rc;
+		}
+
+		rc = regulator_enable(mddi_ldo12);
+		if (rc) {
+			pr_err("%s: LDO12 regulator enable failed (%d)\n",
+			       __func__, rc);
+			return rc;
+		}
+
+		if (other_mddi_client) {
+			rc = regulator_enable(mddi_ldo16);
+			if (rc) {
+				pr_err("%s: LDO16 regulator enable failed (%d)\n",
+					   __func__, rc);
+				return rc;
+			}
+		}
+
+		if (quickvx_ldo_enabled) {
+			/* Disable LDO6 during display ON */
+			rc = regulator_disable(mddi_ldo6);
+			if (rc) {
+				pr_err("%s: LDO6 regulator disable failed (%d)\n",
+					   __func__, rc);
+				return rc;
+			}
+			quickvx_ldo_enabled = 0;
+		}
+
+		rc = regulator_enable(mddi_lcd);
+		if (rc) {
+			pr_err("%s: LCD regulator enable failed (%d)\n",
+				__func__, rc);
+			return rc;
+		}
+
+		mdelay(5);		/* ensure power is stable */
+
+		if (machine_is_msm7x30_fluid()) {
+			rc = msm_gpios_request_enable(fluid_vee_reset_gpio,
+					ARRAY_SIZE(fluid_vee_reset_gpio));
+			if (rc)
+				pr_err("%s gpio_request_enable failed rc=%d\n",
+							__func__, rc);
+			else {
+				/* assert vee reset_n */
+				gpio_set_value(20, 1);
+				gpio_set_value(20, 0);
+				mdelay(1);
+				gpio_set_value(20, 1);
+			}
+		}
+
+		gpio_set_value(180, 1); /* bring reset line high */
+		mdelay(10);	/* 10 msec before IO can be accessed */
+
+		if (quickvx_mddi_client) {
+			gpio_set_value(97, 1);
+			msleep(2);
+			gpio_set_value_cansleep(PM8058_GPIO_PM_TO_SYS(
+				PMIC_GPIO_QUICKVX_CLK), 1);
+			msleep(2);
+		}
+
+		rc = pmapp_display_clock_config(1);
+		if (rc) {
+			pr_err("%s pmapp_display_clock_config rc=%d\n",
+					__func__, rc);
+			return rc;
+		}
+
+	} else {
+		rc = regulator_disable(mddi_ldo20);
+		if (rc) {
+			pr_err("%s: LDO20 regulator disable failed (%d)\n",
+			       __func__, rc);
+			return rc;
+		}
+
+
+		if (other_mddi_client) {
+			rc = regulator_disable(mddi_ldo16);
+			if (rc) {
+				pr_err("%s: LDO16 regulator disable failed (%d)\n",
+					   __func__, rc);
+				return rc;
+			}
+		}
+
+		if (quickvx_mddi_client && !quickvx_ldo_enabled) {
+			/* Enable LDO6 during display OFF for
+			   Quicklogic chip to sleep with data retention */
+			rc = regulator_enable(mddi_ldo6);
+			if (rc) {
+				pr_err("%s: LDO6 regulator enable failed (%d)\n",
+					   __func__, rc);
+				return rc;
+			}
+			quickvx_ldo_enabled = 1;
+		}
+
+		gpio_set_value(180, 0); /* bring reset line low */
+
+		if (quickvx_mddi_client) {
+			gpio_set_value(97, 0);
+			gpio_set_value_cansleep(PM8058_GPIO_PM_TO_SYS(
+				PMIC_GPIO_QUICKVX_CLK), 0);
+		}
+
+		rc = regulator_disable(mddi_lcd);
+		if (rc) {
+			pr_err("%s: LCD regulator disable failed (%d)\n",
+				__func__, rc);
+			return rc;
+		}
+
+		mdelay(5);	/* ensure power is stable */
+
+		rc = regulator_disable(mddi_ldo12);
+		if (rc) {
+			pr_err("%s: LDO12 regulator disable failed (%d)\n",
+			       __func__, rc);
+			return rc;
+		}
+
+		if (machine_is_msm7x30_fluid()) {
+			msm_gpios_disable_free(fluid_vee_reset_gpio,
+					ARRAY_SIZE(fluid_vee_reset_gpio));
+		}
+
+		rc = pmapp_display_clock_config(0);
+		if (rc) {
+			pr_err("%s pmapp_display_clock_config rc=%d\n",
+					__func__, rc);
+			return rc;
+		}
+	}
+
+	return rc;
+}
+
+static int msm_fb_mddi_sel_clk(u32 *clk_rate)
+{
+	*clk_rate *= 2;
+	return 0;
+}
+
+static int msm_fb_mddi_client_power(u32 client_id)
+{
+	int rc;
+	printk(KERN_NOTICE "\n client_id = 0x%x", client_id);
+	/* Check if it is Quicklogic client */
+	if (client_id == 0xc5835800) {
+		printk(KERN_NOTICE "\n Quicklogic MDDI client");
+		other_mddi_client = 0;
+		if (IS_ERR(mddi_ldo16)) {
+			rc = PTR_ERR(mddi_ldo16);
+			pr_err("%s: gp10 vreg get failed (%d)\n", __func__, rc);
+			return rc;
+		}
+		rc = regulator_disable(mddi_ldo16);
+		if (rc) {
+			pr_err("%s: LDO16 vreg enable failed (%d)\n",
+							__func__, rc);
+			return rc;
+		}
+
+	} else {
+		printk(KERN_NOTICE "\n Non-Quicklogic MDDI client");
+		quickvx_mddi_client = 0;
+		gpio_set_value(97, 0);
+		gpio_set_value_cansleep(PM8058_GPIO_PM_TO_SYS(
+			PMIC_GPIO_QUICKVX_CLK), 0);
+	}
+
+	return 0;
+}
+
+static struct mddi_platform_data mddi_pdata = {
+	.mddi_power_save = display_common_power,
+	.mddi_sel_clk = msm_fb_mddi_sel_clk,
+	.mddi_client_power = msm_fb_mddi_client_power,
+};
+
+int mdp_core_clk_rate_table[] = {
+	122880000,
+	122880000,
+	192000000,
+	192000000,
+};
+
+static struct msm_panel_common_pdata mdp_pdata = {
+	.hw_revision_addr = 0xac001270,
+	.gpio = 30,
+	.mdp_core_clk_rate = 122880000,
+	.mdp_core_clk_table = mdp_core_clk_rate_table,
+	.num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
+	.mdp_rev = MDP_REV_40,
+};
+
+static int lcd_panel_spi_gpio_num[] = {
+			45, /* spi_clk */
+			46, /* spi_cs  */
+			47, /* spi_mosi */
+			48, /* spi_miso */
+		};
+
+static struct msm_gpio lcd_panel_gpios[] = {
+/* Workaround, since HDMI_INT is using the same GPIO line (18), and is used as
+ * input.  if there is a hardware revision; we should reassign this GPIO to a
+ * new open line; and removing it will just ensure that this will be missed in
+ * the future.
+	{ GPIO_CFG(18, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_grn0" },
+ */
+	{ GPIO_CFG(19, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_grn1" },
+	{ GPIO_CFG(20, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_blu0" },
+	{ GPIO_CFG(21, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_blu1" },
+	{ GPIO_CFG(22, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_blu2" },
+	{ GPIO_CFG(23, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_red0" },
+	{ GPIO_CFG(24, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_red1" },
+	{ GPIO_CFG(25, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_red2" },
+#ifndef CONFIG_SPI_QSD
+	{ GPIO_CFG(45, 0, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "spi_clk" },
+	{ GPIO_CFG(46, 0, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "spi_cs0" },
+	{ GPIO_CFG(47, 0, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "spi_mosi" },
+	{ GPIO_CFG(48, 0, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "spi_miso" },
+#endif
+	{ GPIO_CFG(90, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_pclk" },
+	{ GPIO_CFG(91, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_en" },
+	{ GPIO_CFG(92, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_vsync" },
+	{ GPIO_CFG(93, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_hsync" },
+	{ GPIO_CFG(94, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_grn2" },
+	{ GPIO_CFG(95, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_grn3" },
+	{ GPIO_CFG(96, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_grn4" },
+	{ GPIO_CFG(97, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_grn5" },
+	{ GPIO_CFG(98, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_grn6" },
+	{ GPIO_CFG(99, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_grn7" },
+	{ GPIO_CFG(100, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_blu3" },
+	{ GPIO_CFG(101, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_blu4" },
+	{ GPIO_CFG(102, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_blu5" },
+	{ GPIO_CFG(103, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_blu6" },
+	{ GPIO_CFG(104, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_blu7" },
+	{ GPIO_CFG(105, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_red3" },
+	{ GPIO_CFG(106, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_red4" },
+	{ GPIO_CFG(107, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_red5" },
+	{ GPIO_CFG(108, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_red6" },
+	{ GPIO_CFG(109, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_red7" },
+};
+
+static struct msm_gpio lcd_sharp_panel_gpios[] = {
+	{ GPIO_CFG(22, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_blu2" },
+	{ GPIO_CFG(25, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_red2" },
+	{ GPIO_CFG(90, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_pclk" },
+	{ GPIO_CFG(91, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_en" },
+	{ GPIO_CFG(92, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_vsync" },
+	{ GPIO_CFG(93, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_hsync" },
+	{ GPIO_CFG(94, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_grn2" },
+	{ GPIO_CFG(95, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_grn3" },
+	{ GPIO_CFG(96, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_grn4" },
+	{ GPIO_CFG(97, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_grn5" },
+	{ GPIO_CFG(98, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_grn6" },
+	{ GPIO_CFG(99, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_grn7" },
+	{ GPIO_CFG(100, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_blu3" },
+	{ GPIO_CFG(101, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_blu4" },
+	{ GPIO_CFG(102, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_blu5" },
+	{ GPIO_CFG(103, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_blu6" },
+	{ GPIO_CFG(104, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_blu7" },
+	{ GPIO_CFG(105, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_red3" },
+	{ GPIO_CFG(106, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_red4" },
+	{ GPIO_CFG(107, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_red5" },
+	{ GPIO_CFG(108, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_red6" },
+	{ GPIO_CFG(109, 1, GPIO_CFG_OUTPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "lcdc_red7" },
+};
+
+static int lcdc_toshiba_panel_power(int on)
+{
+	int rc, i;
+	struct msm_gpio *gp;
+
+	rc = display_common_power(on);
+	if (rc < 0) {
+		printk(KERN_ERR "%s display_common_power failed: %d\n",
+				__func__, rc);
+		return rc;
+	}
+
+	if (on) {
+		rc = msm_gpios_enable(lcd_panel_gpios,
+				ARRAY_SIZE(lcd_panel_gpios));
+		if (rc < 0) {
+			printk(KERN_ERR "%s: gpio enable failed: %d\n",
+					__func__, rc);
+		}
+	} else {	/* off */
+		gp = lcd_panel_gpios;
+		for (i = 0; i < ARRAY_SIZE(lcd_panel_gpios); i++) {
+			/* ouput low */
+			gpio_set_value(GPIO_PIN(gp->gpio_cfg), 0);
+			gp++;
+		}
+	}
+
+	return rc;
+}
+
+static int lcdc_sharp_panel_power(int on)
+{
+	int rc, i;
+	struct msm_gpio *gp;
+
+	rc = display_common_power(on);
+	if (rc < 0) {
+		printk(KERN_ERR "%s display_common_power failed: %d\n",
+				__func__, rc);
+		return rc;
+	}
+
+	if (on) {
+		rc = msm_gpios_enable(lcd_sharp_panel_gpios,
+				ARRAY_SIZE(lcd_sharp_panel_gpios));
+		if (rc < 0) {
+			printk(KERN_ERR "%s: gpio enable failed: %d\n",
+				__func__, rc);
+		}
+	} else {	/* off */
+		gp = lcd_sharp_panel_gpios;
+		for (i = 0; i < ARRAY_SIZE(lcd_sharp_panel_gpios); i++) {
+			/* ouput low */
+			gpio_set_value(GPIO_PIN(gp->gpio_cfg), 0);
+			gp++;
+		}
+	}
+
+	return rc;
+}
+
+static int lcdc_panel_power(int on)
+{
+	int flag_on = !!on;
+	static int lcdc_power_save_on, lcdc_power_initialized;
+
+	if (lcdc_power_save_on == flag_on)
+		return 0;
+
+	lcdc_power_save_on = flag_on;
+
+	if (unlikely(!lcdc_power_initialized)) {
+		quickvx_mddi_client = 0;
+		display_common_init();
+		lcdc_power_initialized = 1;
+	}
+
+	if (machine_is_msm7x30_fluid())
+		return lcdc_sharp_panel_power(on);
+	else
+		return lcdc_toshiba_panel_power(on);
+}
+
+static struct lcdc_platform_data lcdc_pdata = {
+	.lcdc_power_save   = lcdc_panel_power,
+};
+
+static struct regulator *atv_s4, *atv_ldo9;
+
+static int __init atv_dac_power_init(void)
+{
+	int rc;
+	struct regulator_bulk_data regs[] = {
+		{ .supply = "smps4", .min_uV = 2200000, .max_uV = 2200000 },
+		{ .supply = "ldo9",  .min_uV = 2050000, .max_uV = 2050000 },
+	};
+
+	rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs), regs);
+
+	if (rc) {
+		pr_err("%s: could not get regulators: %d\n", __func__, rc);
+		goto bail;
+	}
+
+	rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs), regs);
+
+	if (rc) {
+		pr_err("%s: could not set voltages: %d\n", __func__, rc);
+		goto reg_free;
+	}
+
+	atv_s4   = regs[0].consumer;
+	atv_ldo9 = regs[1].consumer;
+
+reg_free:
+	regulator_bulk_free(ARRAY_SIZE(regs), regs);
+bail:
+	return rc;
+}
+
+static int atv_dac_power(int on)
+{
+	int rc = 0;
+
+	if (on) {
+		rc = regulator_enable(atv_s4);
+		if (rc) {
+			pr_err("%s: s4 vreg enable failed (%d)\n",
+				__func__, rc);
+			return rc;
+		}
+		rc = regulator_enable(atv_ldo9);
+		if (rc) {
+			pr_err("%s: ldo9 vreg enable failed (%d)\n",
+				__func__, rc);
+			return rc;
+		}
+	} else {
+		rc = regulator_disable(atv_ldo9);
+		if (rc) {
+			pr_err("%s: ldo9 vreg disable failed (%d)\n",
+				   __func__, rc);
+			return rc;
+		}
+		rc = regulator_disable(atv_s4);
+		if (rc) {
+			pr_err("%s: s4 vreg disable failed (%d)\n",
+				   __func__, rc);
+			return rc;
+		}
+	}
+	return rc;
+}
+
+static struct tvenc_platform_data atv_pdata = {
+	.poll		 = 1,
+	.pm_vid_en	 = atv_dac_power,
+};
+
+static void __init msm_fb_add_devices(void)
+{
+	msm_fb_register_device("mdp", &mdp_pdata);
+	msm_fb_register_device("pmdh", &mddi_pdata);
+	msm_fb_register_device("lcdc", &lcdc_pdata);
+	msm_fb_register_device("dtv", &dtv_pdata);
+	msm_fb_register_device("tvenc", &atv_pdata);
+#ifdef CONFIG_FB_MSM_TVOUT
+	msm_fb_register_device("tvout_device", NULL);
+#endif
+}
+
+static struct msm_panel_common_pdata lcdc_toshiba_panel_data = {
+	.gpio_num          = lcd_panel_spi_gpio_num,
+};
+
+static struct platform_device lcdc_toshiba_panel_device = {
+	.name   = "lcdc_toshiba_wvga",
+	.id     = 0,
+	.dev    = {
+		.platform_data = &lcdc_toshiba_panel_data,
+	}
+};
+
+#if defined(CONFIG_MARIMBA_CORE) && \
+   (defined(CONFIG_MSM_BT_POWER) || defined(CONFIG_MSM_BT_POWER_MODULE))
+static struct platform_device msm_bt_power_device = {
+	.name = "bt_power",
+	.id     = -1
+};
+
+enum {
+	BT_RFR,
+	BT_CTS,
+	BT_RX,
+	BT_TX,
+};
+
+static struct msm_gpio bt_config_power_on[] = {
+	{ GPIO_CFG(134, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,   GPIO_CFG_2MA),
+		"UART1DM_RFR" },
+	{ GPIO_CFG(135, 1, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL,   GPIO_CFG_2MA),
+		"UART1DM_CTS" },
+	{ GPIO_CFG(136, 1, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL,   GPIO_CFG_2MA),
+		"UART1DM_Rx" },
+	{ GPIO_CFG(137, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,   GPIO_CFG_2MA),
+		"UART1DM_Tx" }
+};
+
+static struct msm_gpio bt_config_power_off[] = {
+	{ GPIO_CFG(134, 0, GPIO_CFG_INPUT,  GPIO_CFG_PULL_DOWN,   GPIO_CFG_2MA),
+		"UART1DM_RFR" },
+	{ GPIO_CFG(135, 0, GPIO_CFG_INPUT,  GPIO_CFG_PULL_DOWN,   GPIO_CFG_2MA),
+		"UART1DM_CTS" },
+	{ GPIO_CFG(136, 0, GPIO_CFG_INPUT,  GPIO_CFG_PULL_DOWN,   GPIO_CFG_2MA),
+		"UART1DM_Rx" },
+	{ GPIO_CFG(137, 0, GPIO_CFG_INPUT,  GPIO_CFG_PULL_DOWN,   GPIO_CFG_2MA),
+		"UART1DM_Tx" }
+};
+
+static u8 bahama_version;
+
+static struct regulator_bulk_data regs_bt_marimba[] = {
+	{ .supply = "smps3", .min_uV = 1800000, .max_uV = 1800000 },
+	{ .supply = "smps2", .min_uV = 1300000, .max_uV = 1300000 },
+	{ .supply = "ldo24", .min_uV = 1200000, .max_uV = 1200000 },
+	{ .supply = "ldo13", .min_uV = 2900000, .max_uV = 3050000 },
+};
+
+static struct regulator_bulk_data regs_bt_bahama_v1[] = {
+	{ .supply = "smps3", .min_uV = 1800000, .max_uV = 1800000 },
+	{ .supply = "ldo7",  .min_uV = 1800000, .max_uV = 1800000 },
+	{ .supply = "smps2", .min_uV = 1300000, .max_uV = 1300000 },
+	{ .supply = "ldo13", .min_uV = 2900000, .max_uV = 3050000 },
+};
+
+static struct regulator_bulk_data regs_bt_bahama_v2[] = {
+	{ .supply = "smps3", .min_uV = 1800000, .max_uV = 1800000 },
+	{ .supply = "ldo7",  .min_uV = 1800000, .max_uV = 1800000 },
+	{ .supply = "ldo13", .min_uV = 2900000, .max_uV = 3050000 },
+};
+
+static struct regulator_bulk_data *regs_bt;
+static int regs_bt_count;
+
+static int marimba_bt(int on)
+{
+	int rc;
+	int i;
+	struct marimba config = { .mod_id = MARIMBA_SLAVE_ID_MARIMBA };
+
+	struct marimba_config_register {
+		u8 reg;
+		u8 value;
+		u8 mask;
+	};
+
+	struct marimba_variant_register {
+		const size_t size;
+		const struct marimba_config_register *set;
+	};
+
+	const struct marimba_config_register *p;
+
+	u8 version;
+
+	const struct marimba_config_register v10_bt_on[] = {
+		{ 0xE5, 0x0B, 0x0F },
+		{ 0x05, 0x02, 0x07 },
+		{ 0x06, 0x88, 0xFF },
+		{ 0xE7, 0x21, 0x21 },
+		{ 0xE3, 0x38, 0xFF },
+		{ 0xE4, 0x06, 0xFF },
+	};
+
+	const struct marimba_config_register v10_bt_off[] = {
+		{ 0xE5, 0x0B, 0x0F },
+		{ 0x05, 0x08, 0x0F },
+		{ 0x06, 0x88, 0xFF },
+		{ 0xE7, 0x00, 0x21 },
+		{ 0xE3, 0x00, 0xFF },
+		{ 0xE4, 0x00, 0xFF },
+	};
+
+	const struct marimba_config_register v201_bt_on[] = {
+		{ 0x05, 0x08, 0x07 },
+		{ 0x06, 0x88, 0xFF },
+		{ 0xE7, 0x21, 0x21 },
+		{ 0xE3, 0x38, 0xFF },
+		{ 0xE4, 0x06, 0xFF },
+	};
+
+	const struct marimba_config_register v201_bt_off[] = {
+		{ 0x05, 0x08, 0x07 },
+		{ 0x06, 0x88, 0xFF },
+		{ 0xE7, 0x00, 0x21 },
+		{ 0xE3, 0x00, 0xFF },
+		{ 0xE4, 0x00, 0xFF },
+	};
+
+	const struct marimba_config_register v210_bt_on[] = {
+		{ 0xE9, 0x01, 0x01 },
+		{ 0x06, 0x88, 0xFF },
+		{ 0xE7, 0x21, 0x21 },
+		{ 0xE3, 0x38, 0xFF },
+		{ 0xE4, 0x06, 0xFF },
+	};
+
+	const struct marimba_config_register v210_bt_off[] = {
+		{ 0x06, 0x88, 0xFF },
+		{ 0xE7, 0x00, 0x21 },
+		{ 0xE9, 0x00, 0x01 },
+		{ 0xE3, 0x00, 0xFF },
+		{ 0xE4, 0x00, 0xFF },
+	};
+
+	const struct marimba_variant_register bt_marimba[2][4] = {
+		{
+			{ ARRAY_SIZE(v10_bt_off), v10_bt_off },
+			{ 0, NULL },
+			{ ARRAY_SIZE(v201_bt_off), v201_bt_off },
+			{ ARRAY_SIZE(v210_bt_off), v210_bt_off }
+		},
+		{
+			{ ARRAY_SIZE(v10_bt_on), v10_bt_on },
+			{ 0, NULL },
+			{ ARRAY_SIZE(v201_bt_on), v201_bt_on },
+			{ ARRAY_SIZE(v210_bt_on), v210_bt_on }
+		}
+	};
+
+	on = on ? 1 : 0;
+
+	rc = marimba_read_bit_mask(&config, 0x11,  &version, 1, 0x1F);
+	if (rc < 0) {
+		printk(KERN_ERR
+			"%s: version read failed: %d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	if ((version >= ARRAY_SIZE(bt_marimba[on])) ||
+	    (bt_marimba[on][version].size == 0)) {
+		printk(KERN_ERR
+			"%s: unsupported version\n",
+			__func__);
+		return -EIO;
+	}
+
+	p = bt_marimba[on][version].set;
+
+	printk(KERN_INFO "%s: found version %d\n", __func__, version);
+
+	for (i = 0; i < bt_marimba[on][version].size; i++) {
+		u8 value = (p+i)->value;
+		rc = marimba_write_bit_mask(&config,
+			(p+i)->reg,
+			&value,
+			sizeof((p+i)->value),
+			(p+i)->mask);
+		if (rc < 0) {
+			printk(KERN_ERR
+				"%s: reg %d write failed: %d\n",
+				__func__, (p+i)->reg, rc);
+			return rc;
+		}
+		printk(KERN_INFO "%s: reg 0x%02x value 0x%02x mask 0x%02x\n",
+				__func__, (p+i)->reg,
+				value, (p+i)->mask);
+	}
+	return 0;
+}
+
+static int bahama_bt(int on)
+{
+	int rc;
+	int i;
+	struct marimba config = { .mod_id = SLAVE_ID_BAHAMA };
+
+	struct bahama_variant_register {
+		const size_t size;
+		const struct bahama_config_register *set;
+	};
+
+	const struct bahama_config_register *p;
+
+
+	const struct bahama_config_register v10_bt_on[] = {
+		{ 0xE9, 0x00, 0xFF },
+		{ 0xF4, 0x80, 0xFF },
+		{ 0xF0, 0x06, 0xFF },
+		{ 0xE4, 0x00, 0xFF },
+		{ 0xE5, 0x00, 0x0F },
+#ifdef CONFIG_WLAN
+		{ 0xE6, 0x38, 0x7F },
+		{ 0xE7, 0x06, 0xFF },
+#endif
+		{ 0x11, 0x13, 0xFF },
+		{ 0xE9, 0x21, 0xFF },
+		{ 0x01, 0x0C, 0x1F },
+		{ 0x01, 0x08, 0x1F },
+	};
+
+	const struct bahama_config_register v20_bt_on_fm_off[] = {
+		{ 0x11, 0x0C, 0xFF },
+		{ 0x13, 0x01, 0xFF },
+		{ 0xF4, 0x80, 0xFF },
+		{ 0xF0, 0x00, 0xFF },
+		{ 0xE9, 0x00, 0xFF },
+#ifdef CONFIG_WLAN
+		{ 0x81, 0x00, 0xFF },
+		{ 0x82, 0x00, 0xFF },
+		{ 0xE6, 0x38, 0x7F },
+		{ 0xE7, 0x06, 0xFF },
+#endif
+		{ 0xE9, 0x21, 0xFF }
+	};
+
+	const struct bahama_config_register v20_bt_on_fm_on[] = {
+		{ 0x11, 0x0C, 0xFF },
+		{ 0x13, 0x01, 0xFF },
+		{ 0xF4, 0x86, 0xFF },
+		{ 0xF0, 0x06, 0xFF },
+		{ 0xE9, 0x00, 0xFF },
+#ifdef CONFIG_WLAN
+		{ 0x81, 0x00, 0xFF },
+		{ 0x82, 0x00, 0xFF },
+		{ 0xE6, 0x38, 0x7F },
+		{ 0xE7, 0x06, 0xFF },
+#endif
+		{ 0xE9, 0x21, 0xFF }
+	};
+
+	const struct bahama_config_register v10_bt_off[] = {
+		{ 0xE9, 0x00, 0xFF },
+	};
+
+	const struct bahama_config_register v20_bt_off_fm_off[] = {
+		{ 0xF4, 0x84, 0xFF },
+		{ 0xF0, 0x04, 0xFF },
+		{ 0xE9, 0x00, 0xFF }
+	};
+
+	const struct bahama_config_register v20_bt_off_fm_on[] = {
+		{ 0xF4, 0x86, 0xFF },
+		{ 0xF0, 0x06, 0xFF },
+		{ 0xE9, 0x00, 0xFF }
+	};
+
+	const struct bahama_variant_register bt_bahama[2][3] = {
+		{
+			{ ARRAY_SIZE(v10_bt_off), v10_bt_off },
+			{ ARRAY_SIZE(v20_bt_off_fm_off), v20_bt_off_fm_off },
+			{ ARRAY_SIZE(v20_bt_off_fm_on), v20_bt_off_fm_on }
+		},
+		{
+			{ ARRAY_SIZE(v10_bt_on), v10_bt_on },
+			{ ARRAY_SIZE(v20_bt_on_fm_off), v20_bt_on_fm_off },
+			{ ARRAY_SIZE(v20_bt_on_fm_on), v20_bt_on_fm_on }
+		}
+	};
+
+	u8 offset = 0; /* index into bahama configs */
+
+	on = on ? 1 : 0;
+
+
+	if (bahama_version == VER_2_0) {
+		if (marimba_get_fm_status(&config))
+			offset = 0x01;
+	}
+
+	p = bt_bahama[on][bahama_version + offset].set;
+
+	dev_info(&msm_bt_power_device.dev,
+		"%s: found version %d\n", __func__, bahama_version);
+
+	for (i = 0; i < bt_bahama[on][bahama_version + offset].size; i++) {
+		u8 value = (p+i)->value;
+		rc = marimba_write_bit_mask(&config,
+			(p+i)->reg,
+			&value,
+			sizeof((p+i)->value),
+			(p+i)->mask);
+		if (rc < 0) {
+			dev_err(&msm_bt_power_device.dev,
+				"%s: reg %d write failed: %d\n",
+				__func__, (p+i)->reg, rc);
+			return rc;
+		}
+		dev_info(&msm_bt_power_device.dev,
+			"%s: reg 0x%02x write value 0x%02x mask 0x%02x\n",
+				__func__, (p+i)->reg,
+				value, (p+i)->mask);
+	}
+	/* Update BT status */
+	if (on)
+		marimba_set_bt_status(&config, true);
+	else
+		marimba_set_bt_status(&config, false);
+
+	return 0;
+}
+
+static int bluetooth_regs_init(int bahama_not_marimba)
+{
+	int rc = 0;
+	struct device *const dev = &msm_bt_power_device.dev;
+
+	if (bahama_not_marimba) {
+		bahama_version = read_bahama_ver();
+
+		switch (bahama_version) {
+		case VER_1_0:
+			regs_bt = regs_bt_bahama_v1;
+			regs_bt_count = ARRAY_SIZE(regs_bt_bahama_v1);
+			break;
+		case VER_2_0:
+			regs_bt = regs_bt_bahama_v2;
+			regs_bt_count = ARRAY_SIZE(regs_bt_bahama_v2);
+			break;
+		case VER_UNSUPPORTED:
+		default:
+			dev_err(dev,
+				"%s: i2c failure or unsupported version: %d\n",
+				__func__, bahama_version);
+			rc = -EIO;
+			goto out;
+		}
+	} else {
+		regs_bt = regs_bt_marimba;
+		regs_bt_count = ARRAY_SIZE(regs_bt_marimba);
+	}
+
+	rc = regulator_bulk_get(&msm_bt_power_device.dev,
+			regs_bt_count, regs_bt);
+	if (rc) {
+		dev_err(dev, "%s: could not get regulators: %d\n",
+				__func__, rc);
+		goto out;
+	}
+
+	rc = regulator_bulk_set_voltage(regs_bt_count, regs_bt);
+	if (rc) {
+		dev_err(dev, "%s: could not set voltages: %d\n",
+				__func__, rc);
+		goto reg_free;
+	}
+
+	return 0;
+
+reg_free:
+	regulator_bulk_free(regs_bt_count, regs_bt);
+out:
+	regs_bt_count = 0;
+	regs_bt = NULL;
+	return rc;
+}
+
+static int bluetooth_power(int on)
+{
+	int rc;
+	const char *id = "BTPW";
+
+	int bahama_not_marimba = bahama_present();
+
+	if (bahama_not_marimba == -1) {
+		printk(KERN_WARNING "%s: bahama_present: %d\n",
+				__func__, bahama_not_marimba);
+		return -ENODEV;
+	}
+
+	if (unlikely(regs_bt_count == 0)) {
+		rc = bluetooth_regs_init(bahama_not_marimba);
+		if (rc)
+			return rc;
+	}
+
+	if (on) {
+		rc = regulator_bulk_enable(regs_bt_count, regs_bt);
+		if (rc)
+			return rc;
+
+		rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_DO,
+					  PMAPP_CLOCK_VOTE_ON);
+		if (rc < 0)
+			return -EIO;
+
+		if (machine_is_msm8x55_svlte_surf() ||
+				machine_is_msm8x55_svlte_ffa()) {
+					rc = marimba_gpio_config(1);
+					if (rc < 0)
+						return -EIO;
+		}
+
+		rc = (bahama_not_marimba ? bahama_bt(on) : marimba_bt(on));
+		if (rc < 0)
+			return -EIO;
+
+		msleep(10);
+
+		rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_DO,
+					  PMAPP_CLOCK_VOTE_PIN_CTRL);
+		if (rc < 0)
+			return -EIO;
+
+		if (machine_is_msm8x55_svlte_surf() ||
+				machine_is_msm8x55_svlte_ffa()) {
+					rc = marimba_gpio_config(0);
+					if (rc < 0)
+						return -EIO;
+		}
+
+		rc = msm_gpios_enable(bt_config_power_on,
+			ARRAY_SIZE(bt_config_power_on));
+
+		if (rc < 0)
+			return rc;
+
+	} else {
+		rc = msm_gpios_enable(bt_config_power_off,
+					ARRAY_SIZE(bt_config_power_off));
+		if (rc < 0)
+			return rc;
+
+		/* check for initial RFKILL block (power off) */
+		if (platform_get_drvdata(&msm_bt_power_device) == NULL)
+			goto out;
+
+		rc = (bahama_not_marimba ? bahama_bt(on) : marimba_bt(on));
+		if (rc < 0)
+			return -EIO;
+
+		rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_DO,
+					  PMAPP_CLOCK_VOTE_OFF);
+		if (rc < 0)
+			return -EIO;
+
+		rc = regulator_bulk_disable(regs_bt_count, regs_bt);
+		if (rc)
+			return rc;
+
+	}
+
+out:
+	printk(KERN_DEBUG "Bluetooth power switch: %d\n", on);
+
+	return 0;
+}
+
+static void __init bt_power_init(void)
+{
+	msm_bt_power_device.dev.platform_data = &bluetooth_power;
+}
+#else
+#define bt_power_init(x) do {} while (0)
+#endif
+
+static struct msm_psy_batt_pdata msm_psy_batt_data = {
+	.voltage_min_design 	= 2800,
+	.voltage_max_design	= 4300,
+	.avail_chg_sources   	= AC_CHG | USB_CHG ,
+	.batt_technology        = POWER_SUPPLY_TECHNOLOGY_LION,
+};
+
+static struct platform_device msm_batt_device = {
+	.name 		    = "msm-battery",
+	.id		    = -1,
+	.dev.platform_data  = &msm_psy_batt_data,
+};
+
+static char *msm_adc_fluid_device_names[] = {
+	"LTC_ADC1",
+	"LTC_ADC2",
+	"LTC_ADC3",
+};
+
+static char *msm_adc_surf_device_names[] = {
+	"XO_ADC",
+};
+
+static struct msm_adc_platform_data msm_adc_pdata;
+
+static struct platform_device msm_adc_device = {
+	.name   = "msm_adc",
+	.id = -1,
+	.dev = {
+		.platform_data = &msm_adc_pdata,
+	},
+};
+
+#ifdef CONFIG_MSM_SDIO_AL
+static struct msm_gpio mdm2ap_status = {
+	GPIO_CFG(77, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	"mdm2ap_status"
+};
+
+
+static int configure_mdm2ap_status(int on)
+{
+	if (on)
+		return msm_gpios_request_enable(&mdm2ap_status, 1);
+	else {
+		msm_gpios_disable_free(&mdm2ap_status, 1);
+		return 0;
+	}
+}
+
+static int get_mdm2ap_status(void)
+{
+	return gpio_get_value(GPIO_PIN(mdm2ap_status.gpio_cfg));
+}
+
+static struct sdio_al_platform_data sdio_al_pdata = {
+	.config_mdm2ap_status = configure_mdm2ap_status,
+	.get_mdm2ap_status = get_mdm2ap_status,
+	.allow_sdioc_version_major_2 = 1,
+	.peer_sdioc_version_minor = 0x0001,
+	.peer_sdioc_version_major = 0x0003,
+	.peer_sdioc_boot_version_minor = 0x0001,
+	.peer_sdioc_boot_version_major = 0x0003,
+};
+
+struct platform_device msm_device_sdio_al = {
+	.name = "msm_sdio_al",
+	.id = -1,
+	.dev		= {
+		.platform_data	= &sdio_al_pdata,
+	},
+};
+
+#endif /* CONFIG_MSM_SDIO_AL */
+
 static struct platform_device *devices[] __initdata = {
 #if defined(CONFIG_SERIAL_MSM) || defined(CONFIG_MSM_SERIAL_DEBUGGER)
-        &msm_device_uart2,
+	&msm_device_uart2,
+#endif
+#ifdef CONFIG_MSM_PROC_COMM_REGULATOR
+	&msm_proccomm_regulator_dev,
+#endif
+	&asoc_msm_pcm,
+	&asoc_msm_dai0,
+	&asoc_msm_dai1,
+#if defined (CONFIG_SND_MSM_MVS_DAI_SOC)
+	&asoc_msm_mvs,
+	&asoc_mvs_dai0,
+	&asoc_mvs_dai1,
 #endif
 	&msm_device_smd,
+	&msm_device_dmov,
+	&smc91x_device,
+	&smsc911x_device,
+	&msm_device_nand,
+#ifdef CONFIG_USB_MSM_OTG_72K
 	&msm_device_otg,
-	&msm_device_hsusb,
-	&msm_device_hsusb_host,
+#ifdef CONFIG_USB_GADGET
+	&msm_device_gadget_peripheral,
+#endif
+#endif
+#ifdef CONFIG_USB_G_ANDROID
+	&android_usb_device,
+#endif
+	&qsd_device_spi,
+
+#ifdef CONFIG_MSM_SSBI
+	&msm_device_ssbi_pmic1,
+#endif
+#ifdef CONFIG_I2C_SSBI
+	&msm_device_ssbi7,
+#endif
+	&android_pmem_device,
+	&msm_fb_device,
+#ifdef CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE
+	&msm_v4l2_video_overlay_device,
+#endif
+	&msm_migrate_pages_device,
+	&mddi_toshiba_device,
+	&lcdc_toshiba_panel_device,
+#ifdef CONFIG_MSM_ROTATOR
+	&msm_rotator_device,
+#endif
+	&lcdc_sharp_panel_device,
+	&android_pmem_adsp_device,
+	&android_pmem_audio_device,
+	&msm_device_i2c,
+	&msm_device_i2c_2,
+	&msm_device_uart_dm1,
+	&hs_device,
+#ifdef CONFIG_MSM7KV2_AUDIO
+	&msm_aictl_device,
+	&msm_mi2s_device,
+	&msm_lpa_device,
+	&msm_aux_pcm_device,
+#endif
+	&msm_device_adspdec,
+	&qup_device_i2c,
+#if defined(CONFIG_MARIMBA_CORE) && \
+   (defined(CONFIG_MSM_BT_POWER) || defined(CONFIG_MSM_BT_POWER_MODULE))
+	&msm_bt_power_device,
+#endif
+	&msm_kgsl_3d0,
+	&msm_kgsl_2d0,
+#ifndef CONFIG_MSM_CAMERA_V4L2
+#ifdef CONFIG_MT9T013
+	&msm_camera_sensor_mt9t013,
+#endif
+#ifdef CONFIG_MT9D112
+	&msm_camera_sensor_mt9d112,
+#endif
+#ifdef CONFIG_WEBCAM_OV9726
+	&msm_camera_sensor_ov9726,
+#endif
+#ifdef CONFIG_S5K3E2FX
+	&msm_camera_sensor_s5k3e2fx,
+#endif
+#ifdef CONFIG_MT9P012
+	&msm_camera_sensor_mt9p012,
+#endif
+#ifdef CONFIG_MT9E013
+	&msm_camera_sensor_mt9e013,
+#endif
+#ifdef CONFIG_VX6953
+	&msm_camera_sensor_vx6953,
+#endif
+#ifdef CONFIG_SN12M0PZ
+	&msm_camera_sensor_sn12m0pz,
+#endif
+#endif
+	&msm_device_vidc_720p,
+#ifdef CONFIG_MSM_GEMINI
+	&msm_gemini_device,
+#endif
+#ifndef CONFIG_MSM_CAMERA_V4L2
+#ifdef CONFIG_MSM_VPE
+	&msm_vpe_device,
+#endif
+#endif
+#if defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE)
+	&msm_device_tsif,
+#endif
+#ifdef CONFIG_MSM_SDIO_AL
+	&msm_device_sdio_al,
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
+	&qcrypto_device,
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+	&qcedev_device,
+#endif
+
+	&msm_batt_device,
+	&msm_adc_device,
+	&msm_ebi0_thermal,
+	&msm_ebi1_thermal,
+	&msm_adsp_device
 };
 
+static struct msm_gpio msm_i2c_gpios_hw[] = {
+	{ GPIO_CFG(70, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_16MA), "i2c_scl" },
+	{ GPIO_CFG(71, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_16MA), "i2c_sda" },
+};
+
+static struct msm_gpio msm_i2c_gpios_io[] = {
+	{ GPIO_CFG(70, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_16MA), "i2c_scl" },
+	{ GPIO_CFG(71, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_16MA), "i2c_sda" },
+};
+
+static struct msm_gpio qup_i2c_gpios_io[] = {
+	{ GPIO_CFG(16, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_16MA), "qup_scl" },
+	{ GPIO_CFG(17, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_16MA), "qup_sda" },
+};
+static struct msm_gpio qup_i2c_gpios_hw[] = {
+	{ GPIO_CFG(16, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_16MA), "qup_scl" },
+	{ GPIO_CFG(17, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_16MA), "qup_sda" },
+};
+
+static void
+msm_i2c_gpio_config(int adap_id, int config_type)
+{
+	struct msm_gpio *msm_i2c_table;
+
+	/* Each adapter gets 2 lines from the table */
+	if (adap_id > 0)
+		return;
+	if (config_type)
+		msm_i2c_table = &msm_i2c_gpios_hw[adap_id*2];
+	else
+		msm_i2c_table = &msm_i2c_gpios_io[adap_id*2];
+	msm_gpios_enable(msm_i2c_table, 2);
+}
+/*This needs to be enabled only for OEMS*/
+#ifndef CONFIG_QUP_EXCLUSIVE_TO_CAMERA
+static struct regulator *qup_vreg;
+#endif
+static void
+qup_i2c_gpio_config(int adap_id, int config_type)
+{
+	int rc = 0;
+	struct msm_gpio *qup_i2c_table;
+	/* Each adapter gets 2 lines from the table */
+	if (adap_id != 4)
+		return;
+	if (config_type)
+		qup_i2c_table = qup_i2c_gpios_hw;
+	else
+		qup_i2c_table = qup_i2c_gpios_io;
+	rc = msm_gpios_enable(qup_i2c_table, 2);
+	if (rc < 0)
+		printk(KERN_ERR "QUP GPIO enable failed: %d\n", rc);
+	/*This needs to be enabled only for OEMS*/
+#ifndef CONFIG_QUP_EXCLUSIVE_TO_CAMERA
+	if (!IS_ERR_OR_NULL(qup_vreg)) {
+		rc = regulator_enable(qup_vreg);
+		if (rc) {
+			pr_err("%s: regulator_enable failed: %d\n",
+			__func__, rc);
+		}
+	}
+#endif
+}
+
+static struct msm_i2c_platform_data msm_i2c_pdata = {
+	.clk_freq = 100000,
+	.pri_clk = 70,
+	.pri_dat = 71,
+	.rmutex  = 1,
+	.rsl_id = "D:I2C02000021",
+	.msm_i2c_config_gpio = msm_i2c_gpio_config,
+};
+
+static void __init msm_device_i2c_init(void)
+{
+	if (msm_gpios_request(msm_i2c_gpios_hw, ARRAY_SIZE(msm_i2c_gpios_hw)))
+		pr_err("failed to request I2C gpios\n");
+
+	msm_device_i2c.dev.platform_data = &msm_i2c_pdata;
+}
+
+static struct msm_i2c_platform_data msm_i2c_2_pdata = {
+	.clk_freq = 100000,
+	.rmutex  = 1,
+	.rsl_id = "D:I2C02000022",
+	.msm_i2c_config_gpio = msm_i2c_gpio_config,
+};
+
+static void __init msm_device_i2c_2_init(void)
+{
+	msm_device_i2c_2.dev.platform_data = &msm_i2c_2_pdata;
+}
+
+static struct msm_i2c_platform_data qup_i2c_pdata = {
+	.clk_freq = 384000,
+	.msm_i2c_config_gpio = qup_i2c_gpio_config,
+};
+
+static void __init qup_device_i2c_init(void)
+{
+	if (msm_gpios_request(qup_i2c_gpios_hw, ARRAY_SIZE(qup_i2c_gpios_hw)))
+		pr_err("failed to request I2C gpios\n");
+
+	qup_device_i2c.dev.platform_data = &qup_i2c_pdata;
+	/*This needs to be enabled only for OEMS*/
+#ifndef CONFIG_QUP_EXCLUSIVE_TO_CAMERA
+	qup_vreg = regulator_get(&qup_device_i2c.dev, "lvsw1");
+	if (IS_ERR(qup_vreg)) {
+		dev_err(&qup_device_i2c.dev,
+			"%s: regulator_get failed: %ld\n",
+			__func__, PTR_ERR(qup_vreg));
+	}
+#endif
+}
+
+#ifdef CONFIG_I2C_SSBI
+static struct msm_i2c_ssbi_platform_data msm_i2c_ssbi7_pdata = {
+	.rsl_id = "D:CODEC_SSBI",
+	.controller_type = MSM_SBI_CTRL_SSBI,
+};
+#endif
+
 static void __init msm7x30_init_irq(void)
 {
 	msm_init_irq();
 }
 
+static struct msm_gpio msm_nand_ebi2_cfg_data[] = {
+	{GPIO_CFG(86, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "ebi2_cs1"},
+	{GPIO_CFG(115, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "ebi2_busy1"},
+};
+
+#if (defined(CONFIG_MMC_MSM_SDC1_SUPPORT)\
+	|| defined(CONFIG_MMC_MSM_SDC2_SUPPORT)\
+	|| defined(CONFIG_MMC_MSM_SDC3_SUPPORT)\
+	|| defined(CONFIG_MMC_MSM_SDC4_SUPPORT))
+
+struct sdcc_gpio {
+	struct msm_gpio *cfg_data;
+	uint32_t size;
+	struct msm_gpio *sleep_cfg_data;
+};
+#if defined(CONFIG_MMC_MSM_SDC1_SUPPORT)
+static struct msm_gpio sdc1_lvlshft_cfg_data[] = {
+	{GPIO_CFG(35, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_16MA), "sdc1_lvlshft"},
+};
+#endif
+static struct msm_gpio sdc1_cfg_data[] = {
+	{GPIO_CFG(38, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_16MA), "sdc1_clk"},
+	{GPIO_CFG(39, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc1_cmd"},
+	{GPIO_CFG(40, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc1_dat_3"},
+	{GPIO_CFG(41, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc1_dat_2"},
+	{GPIO_CFG(42, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc1_dat_1"},
+	{GPIO_CFG(43, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc1_dat_0"},
+};
+
+static struct msm_gpio sdc2_cfg_data[] = {
+	{GPIO_CFG(64, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_16MA), "sdc2_clk"},
+	{GPIO_CFG(65, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc2_cmd"},
+	{GPIO_CFG(66, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc2_dat_3"},
+	{GPIO_CFG(67, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc2_dat_2"},
+	{GPIO_CFG(68, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc2_dat_1"},
+	{GPIO_CFG(69, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc2_dat_0"},
+
+#ifdef CONFIG_MMC_MSM_SDC2_8_BIT_SUPPORT
+	{GPIO_CFG(115, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc2_dat_4"},
+	{GPIO_CFG(114, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc2_dat_5"},
+	{GPIO_CFG(113, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc2_dat_6"},
+	{GPIO_CFG(112, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc2_dat_7"},
+#endif
+};
+
+static struct msm_gpio sdc3_cfg_data[] = {
+	{GPIO_CFG(110, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_16MA), "sdc3_clk"},
+	{GPIO_CFG(111, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc3_cmd"},
+	{GPIO_CFG(116, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc3_dat_3"},
+	{GPIO_CFG(117, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc3_dat_2"},
+	{GPIO_CFG(118, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc3_dat_1"},
+	{GPIO_CFG(119, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc3_dat_0"},
+};
+
+static struct msm_gpio sdc3_sleep_cfg_data[] = {
+	{GPIO_CFG(110, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+			"sdc3_clk"},
+	{GPIO_CFG(111, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+			"sdc3_cmd"},
+	{GPIO_CFG(116, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+			"sdc3_dat_3"},
+	{GPIO_CFG(117, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+			"sdc3_dat_2"},
+	{GPIO_CFG(118, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+			"sdc3_dat_1"},
+	{GPIO_CFG(119, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+			"sdc3_dat_0"},
+};
+
+static struct msm_gpio sdc4_cfg_data[] = {
+	{GPIO_CFG(58, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_16MA), "sdc4_clk"},
+	{GPIO_CFG(59, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc4_cmd"},
+	{GPIO_CFG(60, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc4_dat_3"},
+	{GPIO_CFG(61, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc4_dat_2"},
+	{GPIO_CFG(62, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc4_dat_1"},
+	{GPIO_CFG(63, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc4_dat_0"},
+};
+
+static struct sdcc_gpio sdcc_cfg_data[] = {
+	{
+		.cfg_data = sdc1_cfg_data,
+		.size = ARRAY_SIZE(sdc1_cfg_data),
+		.sleep_cfg_data = NULL,
+	},
+	{
+		.cfg_data = sdc2_cfg_data,
+		.size = ARRAY_SIZE(sdc2_cfg_data),
+		.sleep_cfg_data = NULL,
+	},
+	{
+		.cfg_data = sdc3_cfg_data,
+		.size = ARRAY_SIZE(sdc3_cfg_data),
+		.sleep_cfg_data = sdc3_sleep_cfg_data,
+	},
+	{
+		.cfg_data = sdc4_cfg_data,
+		.size = ARRAY_SIZE(sdc4_cfg_data),
+		.sleep_cfg_data = NULL,
+	},
+};
+
+static struct regulator *sdcc_vreg_data[ARRAY_SIZE(sdcc_cfg_data)];
+
+static unsigned long vreg_sts, gpio_sts;
+
+static uint32_t msm_sdcc_setup_gpio(int dev_id, unsigned int enable)
+{
+	int rc = 0;
+	struct sdcc_gpio *curr;
+
+	curr = &sdcc_cfg_data[dev_id - 1];
+
+	if (!(test_bit(dev_id, &gpio_sts)^enable))
+		return rc;
+
+	if (enable) {
+		set_bit(dev_id, &gpio_sts);
+		rc = msm_gpios_request_enable(curr->cfg_data, curr->size);
+		if (rc)
+			printk(KERN_ERR "%s: Failed to turn on GPIOs for slot %d\n",
+				__func__,  dev_id);
+	} else {
+		clear_bit(dev_id, &gpio_sts);
+		if (curr->sleep_cfg_data) {
+			msm_gpios_enable(curr->sleep_cfg_data, curr->size);
+			msm_gpios_free(curr->sleep_cfg_data, curr->size);
+		} else {
+			msm_gpios_disable_free(curr->cfg_data, curr->size);
+		}
+	}
+
+	return rc;
+}
+
+static uint32_t msm_sdcc_setup_vreg(int dev_id, unsigned int enable)
+{
+	int rc = 0;
+	struct regulator *curr = sdcc_vreg_data[dev_id - 1];
+	static int enabled_once[] = {0, 0, 0, 0};
+
+	if (test_bit(dev_id, &vreg_sts) == enable)
+		return rc;
+
+	if (dev_id == 4) {
+		if (enable) {
+			pr_debug("Enable Vdd dev_%d\n", dev_id);
+			gpio_set_value_cansleep(
+				PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_SDC4_PWR_EN_N),
+						0);
+			set_bit(dev_id, &vreg_sts);
+		} else {
+			pr_debug("Disable Vdd dev_%d\n", dev_id);
+			gpio_set_value_cansleep(
+				PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_SDC4_PWR_EN_N),
+				1);
+			clear_bit(dev_id, &vreg_sts);
+		}
+	}
+
+	if (!enable || enabled_once[dev_id - 1])
+			return 0;
+	if (!curr)
+		return -ENODEV;
+
+	if (IS_ERR(curr))
+		return PTR_ERR(curr);
+
+	if (enable) {
+		set_bit(dev_id, &vreg_sts);
+
+		rc = regulator_enable(curr);
+		if (rc)
+			pr_err("%s: could not enable regulator: %d\n",
+					__func__, rc);
+		enabled_once[dev_id - 1] = 1;
+	} else {
+		clear_bit(dev_id, &vreg_sts);
+
+		rc = regulator_disable(curr);
+		if (rc)
+			pr_err("%s: could not disable regulator: %d\n",
+					__func__, rc);
+	}
+	return rc;
+}
+
+static uint32_t msm_sdcc_setup_power(struct device *dv, unsigned int vdd)
+{
+	int rc = 0;
+	struct platform_device *pdev;
+
+	pdev = container_of(dv, struct platform_device, dev);
+	rc = msm_sdcc_setup_gpio(pdev->id, (vdd ? 1 : 0));
+	if (rc)
+		goto out;
+
+	if (pdev->id == 4) /* S3 is always ON and cannot be disabled */
+		rc = msm_sdcc_setup_vreg(pdev->id, (vdd ? 1 : 0));
+out:
+	return rc;
+}
+
+#if defined(CONFIG_MMC_MSM_SDC1_SUPPORT) && \
+	defined(CONFIG_CSDIO_VENDOR_ID) && \
+	defined(CONFIG_CSDIO_DEVICE_ID) && \
+	(CONFIG_CSDIO_VENDOR_ID == 0x70 && CONFIG_CSDIO_DEVICE_ID == 0x1117)
+
+#define MBP_ON  1
+#define MBP_OFF 0
+
+#define MBP_RESET_N \
+	GPIO_CFG(44, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA)
+#define MBP_INT0 \
+	GPIO_CFG(46, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA)
+
+#define MBP_MODE_CTRL_0 \
+	GPIO_CFG(35, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA)
+#define MBP_MODE_CTRL_1 \
+	GPIO_CFG(36, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA)
+#define MBP_MODE_CTRL_2 \
+	GPIO_CFG(34, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA)
+#define TSIF_EN \
+	GPIO_CFG(35, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN,	GPIO_CFG_2MA)
+#define TSIF_DATA \
+	GPIO_CFG(36, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN,	GPIO_CFG_2MA)
+#define TSIF_CLK \
+	GPIO_CFG(34, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+
+static struct msm_gpio mbp_cfg_data[] = {
+	{GPIO_CFG(44, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_16MA),
+		"mbp_reset"},
+	{GPIO_CFG(85, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_16MA),
+		"mbp_io_voltage"},
+};
+
+static int mbp_config_gpios_pre_init(int enable)
+{
+	int rc = 0;
+
+	if (enable) {
+		rc = msm_gpios_request_enable(mbp_cfg_data,
+			ARRAY_SIZE(mbp_cfg_data));
+		if (rc) {
+			printk(KERN_ERR
+				"%s: Failed to turnon GPIOs for mbp chip(%d)\n",
+				__func__, rc);
+		}
+	} else
+		msm_gpios_disable_free(mbp_cfg_data, ARRAY_SIZE(mbp_cfg_data));
+	return rc;
+}
+
+static struct regulator_bulk_data mbp_regs_io[2];
+static struct regulator_bulk_data mbp_regs_rf[2];
+static struct regulator_bulk_data mbp_regs_adc[1];
+static struct regulator_bulk_data mbp_regs_core[1];
+
+static int mbp_init_regs(struct device *dev)
+{
+	struct regulator_bulk_data regs[] = {
+		/* Analog and I/O regs */
+		{ .supply = "gp4",  .min_uV = 2600000, .max_uV = 2600000 },
+		{ .supply = "s3",   .min_uV = 1800000, .max_uV = 1800000 },
+		/* RF regs */
+		{ .supply = "s2",   .min_uV = 1300000, .max_uV = 1300000 },
+		{ .supply = "rf",   .min_uV = 2600000, .max_uV = 2600000 },
+		/* ADC regs */
+		{ .supply = "s4",   .min_uV = 2200000, .max_uV = 2200000 },
+		/* Core regs */
+		{ .supply = "gp16", .min_uV = 1200000, .max_uV = 1200000 },
+	};
+
+	struct regulator_bulk_data *regptr = regs;
+	int rc;
+
+	rc = regulator_bulk_get(dev, ARRAY_SIZE(regs), regs);
+
+	if (rc) {
+		dev_err(dev, "%s: could not get regulators: %d\n",
+				__func__, rc);
+		goto out;
+	}
+
+	rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs), regs);
+
+	if (rc) {
+		dev_err(dev, "%s: could not set voltages: %d\n",
+				__func__, rc);
+		goto reg_free;
+	}
+
+	memcpy(mbp_regs_io, regptr, sizeof(mbp_regs_io));
+	regptr += ARRAY_SIZE(mbp_regs_io);
+
+	memcpy(mbp_regs_rf, regptr, sizeof(mbp_regs_rf));
+	regptr += ARRAY_SIZE(mbp_regs_rf);
+
+	memcpy(mbp_regs_adc, regptr, sizeof(mbp_regs_adc));
+	regptr += ARRAY_SIZE(mbp_regs_adc);
+
+	memcpy(mbp_regs_core, regptr, sizeof(mbp_regs_core));
+
+	return 0;
+
+reg_free:
+	regulator_bulk_free(ARRAY_SIZE(regs), regs);
+out:
+	return rc;
+}
+
+static int mbp_setup_rf_vregs(int state)
+{
+	return state ?
+		regulator_bulk_enable(ARRAY_SIZE(mbp_regs_rf), mbp_regs_rf) :
+		regulator_bulk_disable(ARRAY_SIZE(mbp_regs_rf), mbp_regs_rf);
+}
+
+static int mbp_setup_vregs(int state)
+{
+	return state ?
+		regulator_bulk_enable(ARRAY_SIZE(mbp_regs_io), mbp_regs_io) :
+		regulator_bulk_disable(ARRAY_SIZE(mbp_regs_io), mbp_regs_io);
+}
+
+static int mbp_set_tcxo_en(int enable)
+{
+	int rc;
+	const char *id = "UBMC";
+	struct vreg *vreg_analog = NULL;
+
+	rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_A1,
+		enable ? PMAPP_CLOCK_VOTE_ON : PMAPP_CLOCK_VOTE_OFF);
+	if (rc < 0) {
+		printk(KERN_ERR "%s: unable to %svote for a1 clk\n",
+			__func__, enable ? "" : "de-");
+		return -EIO;
+	}
+	return rc;
+}
+
+static void mbp_set_freeze_io(int state)
+{
+	if (state)
+		gpio_set_value(85, 0);
+	else
+		gpio_set_value(85, 1);
+}
+
+static int mbp_set_core_voltage_en(int enable)
+{
+	static bool is_enabled;
+	int rc = 0;
+
+	if (enable && !is_enabled) {
+		rc = regulator_bulk_enable(ARRAY_SIZE(mbp_regs_core),
+				mbp_regs_core);
+		if (rc) {
+			pr_err("%s: could not enable regulators: %d\n",
+					__func__, rc);
+		} else {
+			is_enabled = true;
+		}
+	}
+
+	return rc;
+}
+
+static void mbp_set_reset(int state)
+{
+	if (state)
+		gpio_set_value(GPIO_PIN(MBP_RESET_N), 0);
+	else
+		gpio_set_value(GPIO_PIN(MBP_RESET_N), 1);
+}
+
+static int mbp_config_interface_mode(int state)
+{
+	if (state) {
+		gpio_tlmm_config(MBP_MODE_CTRL_0, GPIO_CFG_ENABLE);
+		gpio_tlmm_config(MBP_MODE_CTRL_1, GPIO_CFG_ENABLE);
+		gpio_tlmm_config(MBP_MODE_CTRL_2, GPIO_CFG_ENABLE);
+		gpio_set_value(GPIO_PIN(MBP_MODE_CTRL_0), 0);
+		gpio_set_value(GPIO_PIN(MBP_MODE_CTRL_1), 1);
+		gpio_set_value(GPIO_PIN(MBP_MODE_CTRL_2), 0);
+	} else {
+		gpio_tlmm_config(MBP_MODE_CTRL_0, GPIO_CFG_DISABLE);
+		gpio_tlmm_config(MBP_MODE_CTRL_1, GPIO_CFG_DISABLE);
+		gpio_tlmm_config(MBP_MODE_CTRL_2, GPIO_CFG_DISABLE);
+	}
+	return 0;
+}
+
+static int mbp_setup_adc_vregs(int state)
+{
+	return state ?
+		regulator_bulk_enable(ARRAY_SIZE(mbp_regs_adc), mbp_regs_adc) :
+		regulator_bulk_disable(ARRAY_SIZE(mbp_regs_adc), mbp_regs_adc);
+}
+
+static int mbp_power_up(void)
+{
+	int rc;
+
+	rc = mbp_config_gpios_pre_init(MBP_ON);
+	if (rc)
+		goto exit;
+	pr_debug("%s: mbp_config_gpios_pre_init() done\n", __func__);
+
+	rc = mbp_setup_vregs(MBP_ON);
+	if (rc)
+		goto exit;
+	pr_debug("%s: gp4 (2.6) and s3 (1.8) done\n", __func__);
+
+	rc = mbp_set_tcxo_en(MBP_ON);
+	if (rc)
+		goto exit;
+	pr_debug("%s: tcxo clock done\n", __func__);
+
+	mbp_set_freeze_io(MBP_OFF);
+	pr_debug("%s: set gpio 85 to 1 done\n", __func__);
+
+	udelay(100);
+	mbp_set_reset(MBP_ON);
+
+	udelay(300);
+	rc = mbp_config_interface_mode(MBP_ON);
+	if (rc)
+		goto exit;
+	pr_debug("%s: mbp_config_interface_mode() done\n", __func__);
+
+	udelay(100 + mbp_set_core_voltage_en(MBP_ON));
+	pr_debug("%s: power gp16 1.2V done\n", __func__);
+
+	mbp_set_freeze_io(MBP_ON);
+	pr_debug("%s: set gpio 85 to 0 done\n", __func__);
+
+	udelay(100);
+
+	rc = mbp_setup_rf_vregs(MBP_ON);
+	if (rc)
+		goto exit;
+	pr_debug("%s: s2 1.3V and rf 2.6V done\n", __func__);
+
+	rc = mbp_setup_adc_vregs(MBP_ON);
+	if (rc)
+		goto exit;
+	pr_debug("%s: s4 2.2V  done\n", __func__);
+
+	udelay(200);
+
+	mbp_set_reset(MBP_OFF);
+	pr_debug("%s: close gpio 44 done\n", __func__);
+
+	msleep(20);
+exit:
+	return rc;
+}
+
+static int mbp_power_down(void)
+{
+	int rc;
+
+	mbp_set_reset(MBP_ON);
+	pr_debug("%s: mbp_set_reset(MBP_ON) done\n", __func__);
+
+	udelay(100);
+
+	rc = mbp_setup_adc_vregs(MBP_OFF);
+	if (rc)
+		goto exit;
+	pr_debug("%s: vreg_disable(vreg_adc) done\n", __func__);
+
+	udelay(5);
+
+	rc = mbp_setup_rf_vregs(MBP_OFF);
+	if (rc)
+		goto exit;
+	pr_debug("%s: mbp_setup_rf_vregs(MBP_OFF) done\n", __func__);
+
+	udelay(5);
+
+	mbp_set_freeze_io(MBP_OFF);
+	pr_debug("%s: mbp_set_freeze_io(MBP_OFF) done\n", __func__);
+
+	udelay(100);
+	rc = mbp_set_core_voltage_en(MBP_OFF);
+	if (rc)
+		goto exit;
+	pr_debug("%s: mbp_set_core_voltage_en(MBP_OFF) done\n", __func__);
+
+	rc = mbp_set_tcxo_en(MBP_OFF);
+	if (rc)
+		goto exit;
+	pr_debug("%s: mbp_set_tcxo_en(MBP_OFF) done\n", __func__);
+
+	rc = mbp_setup_vregs(MBP_OFF);
+	if (rc)
+		goto exit;
+	pr_debug("%s: mbp_setup_vregs(MBP_OFF) done\n", __func__);
+
+	rc = mbp_config_gpios_pre_init(MBP_OFF);
+	if (rc)
+		goto exit;
+exit:
+	return rc;
+}
+
+static void (*mbp_status_notify_cb)(int card_present, void *dev_id);
+static void *mbp_status_notify_cb_devid;
+static int mbp_power_status;
+static int mbp_power_init_done;
+
+static uint32_t mbp_setup_power(struct device *dv,
+	unsigned int power_status)
+{
+	int rc = 0;
+	struct platform_device *pdev;
+
+	pdev = container_of(dv, struct platform_device, dev);
+
+	if (power_status == mbp_power_status)
+		goto exit;
+	if (power_status) {
+		pr_debug("turn on power of mbp slot");
+		rc = mbp_power_up();
+		mbp_power_status = 1;
+	} else {
+		pr_debug("turn off power of mbp slot");
+		rc = mbp_power_down();
+		mbp_power_status = 0;
+	}
+exit:
+	return rc;
+};
+
+int mbp_register_status_notify(void (*callback)(int, void *),
+	void *dev_id)
+{
+	mbp_status_notify_cb = callback;
+	mbp_status_notify_cb_devid = dev_id;
+	return 0;
+}
+
+static unsigned int mbp_status(struct device *dev)
+{
+	return mbp_power_status;
+}
+
+static uint32_t msm_sdcc_setup_power_mbp(struct device *dv, unsigned int vdd)
+{
+	struct platform_device *pdev;
+	uint32_t rc = 0;
+
+	pdev = container_of(dv, struct platform_device, dev);
+	rc = msm_sdcc_setup_power(dv, vdd);
+	if (rc) {
+		pr_err("%s: Failed to setup power (%d)\n",
+			__func__, rc);
+		goto out;
+	}
+	if (!mbp_power_init_done) {
+		rc = mbp_init_regs(dv);
+		if (rc) {
+			dev_err(dv, "%s: regulator init failed: %d\n",
+					__func__, rc);
+			goto out;
+		}
+		mbp_setup_power(dv, 1);
+		mbp_setup_power(dv, 0);
+		mbp_power_init_done = 1;
+	}
+	if (vdd >= 0x8000) {
+		rc = mbp_setup_power(dv, (0x8000 == vdd) ? 0 : 1);
+		if (rc) {
+			pr_err("%s: Failed to config mbp chip power (%d)\n",
+				__func__, rc);
+			goto out;
+		}
+		if (mbp_status_notify_cb) {
+			mbp_status_notify_cb(mbp_power_status,
+				mbp_status_notify_cb_devid);
+		}
+	}
+out:
+	/* should return 0 only */
+	return 0;
+}
+
+#endif
+
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
+static unsigned int msm7x30_sdcc_slot_status(struct device *dev)
+{
+	return (unsigned int)
+		gpio_get_value_cansleep(
+			PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_SD_DET - 1));
+}
+#endif
+
+static int msm_sdcc_get_wpswitch(struct device *dv)
+{
+	void __iomem *wp_addr = 0;
+	uint32_t ret = 0;
+	struct platform_device *pdev;
+
+	if (!(machine_is_msm7x30_surf()))
+		return -1;
+	pdev = container_of(dv, struct platform_device, dev);
+
+	wp_addr = ioremap(FPGA_SDCC_STATUS, 4);
+	if (!wp_addr) {
+		pr_err("%s: Could not remap %x\n", __func__, FPGA_SDCC_STATUS);
+		return -ENOMEM;
+	}
+
+	ret = (((readl(wp_addr) >> 4) >> (pdev->id-1)) & 0x01);
+	pr_info("%s: WP Status for Slot %d = 0x%x \n", __func__,
+							pdev->id, ret);
+	iounmap(wp_addr);
+
+	return ret;
+}
+#endif
+
+#if defined(CONFIG_MMC_MSM_SDC1_SUPPORT)
+#if defined(CONFIG_CSDIO_VENDOR_ID) && \
+	defined(CONFIG_CSDIO_DEVICE_ID) && \
+	(CONFIG_CSDIO_VENDOR_ID == 0x70 && CONFIG_CSDIO_DEVICE_ID == 0x1117)
+static struct mmc_platform_data msm7x30_sdc1_data = {
+	.ocr_mask	= MMC_VDD_165_195 | MMC_VDD_27_28 | MMC_VDD_28_29,
+	.translate_vdd	= msm_sdcc_setup_power_mbp,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.status	        = mbp_status,
+	.register_status_notify = mbp_register_status_notify,
+	.msmsdcc_fmin	= 144000,
+	.msmsdcc_fmid	= 24576000,
+	.msmsdcc_fmax	= 24576000,
+	.nonremovable	= 0,
+};
+#else
+static struct mmc_platform_data msm7x30_sdc1_data = {
+	.ocr_mask	= MMC_VDD_165_195,
+	.translate_vdd	= msm_sdcc_setup_power,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.msmsdcc_fmin	= 144000,
+	.msmsdcc_fmid	= 24576000,
+	.msmsdcc_fmax	= 49152000,
+	.nonremovable	= 0,
+};
+#endif
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+static struct mmc_platform_data msm7x30_sdc2_data = {
+	.ocr_mask	= MMC_VDD_165_195 | MMC_VDD_27_28,
+	.translate_vdd	= msm_sdcc_setup_power,
+#ifdef CONFIG_MMC_MSM_SDC2_8_BIT_SUPPORT
+	.mmc_bus_width  = MMC_CAP_8_BIT_DATA,
+#else
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+#endif
+	.msmsdcc_fmin	= 144000,
+	.msmsdcc_fmid	= 24576000,
+	.msmsdcc_fmax	= 49152000,
+	.nonremovable	= 1,
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+static struct mmc_platform_data msm7x30_sdc3_data = {
+	.ocr_mask	= MMC_VDD_27_28 | MMC_VDD_28_29,
+	.translate_vdd	= msm_sdcc_setup_power,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.sdiowakeup_irq = MSM_GPIO_TO_INT(118),
+	.msmsdcc_fmin	= 144000,
+	.msmsdcc_fmid	= 24576000,
+	.msmsdcc_fmax	= 49152000,
+	.nonremovable	= 0,
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+static struct mmc_platform_data msm7x30_sdc4_data = {
+	.ocr_mask	= MMC_VDD_27_28 | MMC_VDD_28_29,
+	.translate_vdd	= msm_sdcc_setup_power,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
+	.status      = msm7x30_sdcc_slot_status,
+	.status_irq  = PM8058_GPIO_IRQ(PMIC8058_IRQ_BASE, PMIC_GPIO_SD_DET - 1),
+	.irq_flags   = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+#endif
+	.wpswitch    = msm_sdcc_get_wpswitch,
+	.msmsdcc_fmin	= 144000,
+	.msmsdcc_fmid	= 24576000,
+	.msmsdcc_fmax	= 49152000,
+	.nonremovable	= 0,
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+static int msm_sdc1_lvlshft_enable(void)
+{
+	static struct regulator *ldo5;
+	int rc;
+
+	/* Enable LDO5, an input to the FET that powers slot 1 */
+
+	ldo5 = regulator_get(NULL, "ldo5");
+
+	if (IS_ERR(ldo5)) {
+		rc = PTR_ERR(ldo5);
+		pr_err("%s: could not get ldo5: %d\n", __func__, rc);
+		goto out;
+	}
+
+	rc = regulator_set_voltage(ldo5, 2850000, 2850000);
+	if (rc) {
+		pr_err("%s: could not set ldo5 voltage: %d\n", __func__, rc);
+		goto ldo5_free;
+	}
+
+	rc = regulator_enable(ldo5);
+	if (rc) {
+		pr_err("%s: could not enable ldo5: %d\n", __func__, rc);
+		goto ldo5_free;
+	}
+
+	/* Enable GPIO 35, to turn on the FET that powers slot 1 */
+	rc = msm_gpios_request_enable(sdc1_lvlshft_cfg_data,
+				ARRAY_SIZE(sdc1_lvlshft_cfg_data));
+	if (rc)
+		printk(KERN_ERR "%s: Failed to enable GPIO 35\n", __func__);
+
+	rc = gpio_direction_output(GPIO_PIN(sdc1_lvlshft_cfg_data[0].gpio_cfg),
+				1);
+	if (rc)
+		printk(KERN_ERR "%s: Failed to turn on GPIO 35\n", __func__);
+
+	return 0;
+
+ldo5_free:
+	regulator_put(ldo5);
+out:
+	ldo5 = NULL;
+	return rc;
+}
+#endif
+
+static int mmc_regulator_init(int sdcc_no, const char *supply, int uV)
+{
+	int rc;
+
+	BUG_ON(sdcc_no < 1 || sdcc_no > 4);
+
+	sdcc_no--;
+
+	sdcc_vreg_data[sdcc_no] = regulator_get(NULL, supply);
+
+	if (IS_ERR(sdcc_vreg_data[sdcc_no])) {
+		rc = PTR_ERR(sdcc_vreg_data[sdcc_no]);
+		pr_err("%s: could not get regulator \"%s\": %d\n",
+				__func__, supply, rc);
+		goto out;
+	}
+
+	rc = regulator_set_voltage(sdcc_vreg_data[sdcc_no], uV, uV);
+
+	if (rc) {
+		pr_err("%s: could not set voltage for \"%s\" to %d uV: %d\n",
+				__func__, supply, uV, rc);
+		goto reg_free;
+	}
+
+	return rc;
+
+reg_free:
+	regulator_put(sdcc_vreg_data[sdcc_no]);
+out:
+	sdcc_vreg_data[sdcc_no] = NULL;
+	return rc;
+}
+
+static void __init msm7x30_init_mmc(void)
+{
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+	if (mmc_regulator_init(1, "s3", 1800000))
+		goto out1;
+
+	if (machine_is_msm7x30_fluid()) {
+		msm7x30_sdc1_data.ocr_mask =  MMC_VDD_27_28 | MMC_VDD_28_29;
+		if (msm_sdc1_lvlshft_enable()) {
+			pr_err("%s: could not enable level shift\n");
+			goto out1;
+		}
+	}
+
+	msm_add_sdcc(1, &msm7x30_sdc1_data);
+out1:
+#endif
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+	if (mmc_regulator_init(2, "s3", 1800000))
+		goto out2;
+
+	if (machine_is_msm8x55_svlte_surf())
+		msm7x30_sdc2_data.msmsdcc_fmax =  24576000;
+	if (machine_is_msm8x55_svlte_surf() ||
+			machine_is_msm8x55_svlte_ffa()) {
+		msm7x30_sdc2_data.sdiowakeup_irq = MSM_GPIO_TO_INT(68);
+		msm7x30_sdc2_data.is_sdio_al_client = 1;
+	}
+
+	msm_add_sdcc(2, &msm7x30_sdc2_data);
+out2:
+#endif
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+	if (mmc_regulator_init(3, "s3", 1800000))
+		goto out3;
+
+	msm_sdcc_setup_gpio(3, 1);
+	msm_add_sdcc(3, &msm7x30_sdc3_data);
+out3:
+#endif
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+	if (mmc_regulator_init(4, "mmc", 2850000))
+		return;
+
+	msm_add_sdcc(4, &msm7x30_sdc4_data);
+#endif
+
+}
+
+static void __init msm7x30_init_nand(void)
+{
+	char *build_id;
+	struct flash_platform_data *plat_data;
+
+	build_id = socinfo_get_build_id();
+	if (build_id == NULL) {
+		pr_err("%s: Build ID not available from socinfo\n", __func__);
+		return;
+	}
+
+	if (build_id[8] == 'C' &&
+			!msm_gpios_request_enable(msm_nand_ebi2_cfg_data,
+			ARRAY_SIZE(msm_nand_ebi2_cfg_data))) {
+		plat_data = msm_device_nand.dev.platform_data;
+		plat_data->interleave = 1;
+		printk(KERN_INFO "%s: Interleave mode Build ID found\n",
+			__func__);
+	}
+}
+
+#ifdef CONFIG_SERIAL_MSM_CONSOLE
+static struct msm_gpio uart2_config_data[] = {
+	{ GPIO_CFG(49, 2, GPIO_CFG_OUTPUT,  GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "UART2_RFR"},
+	{ GPIO_CFG(50, 2, GPIO_CFG_INPUT,   GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "UART2_CTS"},
+	{ GPIO_CFG(51, 2, GPIO_CFG_INPUT,   GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "UART2_Rx"},
+	{ GPIO_CFG(52, 2, GPIO_CFG_OUTPUT,  GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "UART2_Tx"},
+};
+
+static void msm7x30_init_uart2(void)
+{
+	msm_gpios_request_enable(uart2_config_data,
+			ARRAY_SIZE(uart2_config_data));
+
+}
+#endif
+
+/* TSIF begin */
+#if defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE)
+
+#define TSIF_B_SYNC      GPIO_CFG(37, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_B_DATA      GPIO_CFG(36, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_B_EN        GPIO_CFG(35, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_B_CLK       GPIO_CFG(34, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+
+static const struct msm_gpio tsif_gpios[] = {
+	{ .gpio_cfg = TSIF_B_CLK,  .label =  "tsif_clk", },
+	{ .gpio_cfg = TSIF_B_EN,   .label =  "tsif_en", },
+	{ .gpio_cfg = TSIF_B_DATA, .label =  "tsif_data", },
+	{ .gpio_cfg = TSIF_B_SYNC, .label =  "tsif_sync", },
+};
+
+static struct msm_tsif_platform_data tsif_platform_data = {
+	.num_gpios = ARRAY_SIZE(tsif_gpios),
+	.gpios = tsif_gpios,
+	.tsif_pclk = "iface_clk",
+	.tsif_ref_clk = "ref_clk",
+};
+#endif /* defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE) */
+/* TSIF end   */
+
+static void __init pmic8058_leds_init(void)
+{
+	if (machine_is_msm7x30_surf())
+		pm8058_7x30_data.leds_pdata = &pm8058_surf_leds_data;
+	else if (!machine_is_msm7x30_fluid())
+		pm8058_7x30_data.leds_pdata = &pm8058_ffa_leds_data;
+	else if (machine_is_msm7x30_fluid())
+		pm8058_7x30_data.leds_pdata = &pm8058_fluid_leds_data;
+}
+
+static struct msm_spm_platform_data msm_spm_data __initdata = {
+	.reg_base_addr = MSM_SAW0_BASE,
+
+	.reg_init_values[MSM_SPM_REG_SAW_CFG] = 0x05,
+	.reg_init_values[MSM_SPM_REG_SAW_SPM_CTL] = 0x18,
+	.reg_init_values[MSM_SPM_REG_SAW_SPM_SLP_TMR_DLY] = 0x00006666,
+	.reg_init_values[MSM_SPM_REG_SAW_SPM_WAKE_TMR_DLY] = 0xFF000666,
+
+	.reg_init_values[MSM_SPM_REG_SAW_SLP_CLK_EN] = 0x01,
+	.reg_init_values[MSM_SPM_REG_SAW_SLP_HSFS_PRECLMP_EN] = 0x03,
+	.reg_init_values[MSM_SPM_REG_SAW_SLP_HSFS_POSTCLMP_EN] = 0x00,
+
+	.reg_init_values[MSM_SPM_REG_SAW_SLP_CLMP_EN] = 0x01,
+	.reg_init_values[MSM_SPM_REG_SAW_SLP_RST_EN] = 0x00,
+	.reg_init_values[MSM_SPM_REG_SAW_SPM_MPM_CFG] = 0x00,
+
+	.awake_vlevel = 0xF2,
+	.retention_vlevel = 0xE0,
+	.collapse_vlevel = 0x72,
+	.retention_mid_vlevel = 0xE0,
+	.collapse_mid_vlevel = 0xE0,
+
+	.vctl_timeout_us = 50,
+};
+
+#if defined(CONFIG_TOUCHSCREEN_TSC2007) || \
+	defined(CONFIG_TOUCHSCREEN_TSC2007_MODULE)
+
+#define TSC2007_TS_PEN_INT	20
+
+static struct msm_gpio tsc2007_config_data[] = {
+	{ GPIO_CFG(TSC2007_TS_PEN_INT, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	"tsc2007_irq" },
+};
+
+static struct regulator_bulk_data tsc2007_regs[] = {
+	{ .supply = "s3", .min_uV = 1800000, .max_uV = 1800000 },
+	{ .supply = "s2", .min_uV = 1300000, .max_uV = 1300000 },
+};
+
+static int tsc2007_init(void)
+{
+	int rc;
+
+	rc = regulator_bulk_get(NULL, ARRAY_SIZE(tsc2007_regs), tsc2007_regs);
+
+	if (rc) {
+		pr_err("%s: could not get regulators: %d\n", __func__, rc);
+		goto out;
+	}
+
+	rc = regulator_bulk_set_voltage(ARRAY_SIZE(tsc2007_regs), tsc2007_regs);
+
+	if (rc) {
+		pr_err("%s: could not set voltages: %d\n", __func__, rc);
+		goto reg_free;
+	}
+
+	rc = regulator_bulk_enable(ARRAY_SIZE(tsc2007_regs), tsc2007_regs);
+
+	if (rc) {
+		pr_err("%s: could not enable regulators: %d\n", __func__, rc);
+		goto reg_free;
+	}
+
+	rc = msm_gpios_request_enable(tsc2007_config_data,
+			ARRAY_SIZE(tsc2007_config_data));
+	if (rc) {
+		pr_err("%s: Unable to request gpios\n", __func__);
+		goto reg_disable;
+	}
+
+	return 0;
+
+reg_disable:
+	regulator_bulk_disable(ARRAY_SIZE(tsc2007_regs), tsc2007_regs);
+reg_free:
+	regulator_bulk_free(ARRAY_SIZE(tsc2007_regs), tsc2007_regs);
+out:
+	return rc;
+}
+
+static int tsc2007_get_pendown_state(void)
+{
+	int rc;
+
+	rc = gpio_get_value(TSC2007_TS_PEN_INT);
+	if (rc < 0) {
+		pr_err("%s: MSM GPIO %d read failed\n", __func__,
+						TSC2007_TS_PEN_INT);
+		return rc;
+	}
+
+	return (rc == 0 ? 1 : 0);
+}
+
+static void tsc2007_exit(void)
+{
+
+	regulator_bulk_disable(ARRAY_SIZE(tsc2007_regs), tsc2007_regs);
+	regulator_bulk_free(ARRAY_SIZE(tsc2007_regs), tsc2007_regs);
+
+	msm_gpios_disable_free(tsc2007_config_data,
+		ARRAY_SIZE(tsc2007_config_data));
+}
+
+static int tsc2007_power_shutdown(bool enable)
+{
+	int rc;
+
+	rc = (enable == false) ?
+		regulator_bulk_enable(ARRAY_SIZE(tsc2007_regs), tsc2007_regs) :
+		regulator_bulk_disable(ARRAY_SIZE(tsc2007_regs), tsc2007_regs);
+
+	if (rc) {
+		pr_err("%s: could not %sable regulators: %d\n",
+				__func__, enable ? "dis" : "en", rc);
+		return rc;
+	}
+
+	if (enable == false)
+		msleep(20);
+
+	return 0;
+}
+
+static struct tsc2007_platform_data tsc2007_ts_data = {
+	.model = 2007,
+	.x_plate_ohms = 300,
+	.min_x		= 210,
+	.max_x		= 3832,
+	.min_y		= 150,
+	.max_y		= 3936,
+	.irq_flags    = IRQF_TRIGGER_LOW,
+	.init_platform_hw = tsc2007_init,
+	.exit_platform_hw = tsc2007_exit,
+	.power_shutdown	  = tsc2007_power_shutdown,
+	.invert_x	  = true,
+	.invert_y	  = true,
+	/* REVISIT: Temporary fix for reversed pressure */
+	.invert_z1	  = true,
+	.invert_z2	  = true,
+	.get_pendown_state = tsc2007_get_pendown_state,
+};
+
+static struct i2c_board_info tsc_i2c_board_info[] = {
+	{
+		I2C_BOARD_INFO("tsc2007", 0x48),
+		.irq		= MSM_GPIO_TO_INT(TSC2007_TS_PEN_INT),
+		.platform_data = &tsc2007_ts_data,
+	},
+};
+#endif
+
+static struct regulator_bulk_data regs_isa1200[] = {
+	{ .supply = "gp7",  .min_uV = 1800000, .max_uV = 1800000 },
+	{ .supply = "gp10", .min_uV = 2600000, .max_uV = 2600000 },
+};
+
+static int isa1200_power(int vreg_on)
+{
+	int rc = 0;
+
+	rc = vreg_on ?
+		regulator_bulk_enable(ARRAY_SIZE(regs_isa1200), regs_isa1200) :
+		regulator_bulk_disable(ARRAY_SIZE(regs_isa1200), regs_isa1200);
+
+	if (rc) {
+		pr_err("%s: could not %sable regulators: %d\n",
+				__func__, vreg_on ? "en" : "dis", rc);
+		goto out;
+	}
+
+	/* vote for DO buffer */
+	rc = pmapp_clock_vote("VIBR", PMAPP_CLOCK_ID_DO,
+		vreg_on ? PMAPP_CLOCK_VOTE_ON : PMAPP_CLOCK_VOTE_OFF);
+	if (rc)	{
+		pr_err("%s: unable to %svote for d0 clk\n",
+			__func__, vreg_on ? "" : "de-");
+		goto vreg_fail;
+	}
+
+	return 0;
+
+vreg_fail:
+	if (vreg_on)
+		regulator_bulk_disable(ARRAY_SIZE(regs_isa1200), regs_isa1200);
+	else
+		regulator_bulk_enable(ARRAY_SIZE(regs_isa1200), regs_isa1200);
+out:
+	return rc;
+}
+
+static int isa1200_dev_setup(bool enable)
+{
+	int rc;
+
+	if (enable == true) {
+		rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs_isa1200),
+				regs_isa1200);
+
+		if (rc) {
+			pr_err("%s: could not get regulators: %d\n",
+					__func__, rc);
+			goto out;
+		}
+
+		rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs_isa1200),
+				regs_isa1200);
+		if (rc) {
+			pr_err("%s: could not set voltages: %d\n",
+					__func__, rc);
+			goto reg_free;
+		}
+
+		rc = gpio_tlmm_config(GPIO_CFG(HAP_LVL_SHFT_MSM_GPIO, 0,
+				GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
+				GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+		if (rc) {
+			pr_err("%s: Could not configure gpio %d\n",
+					__func__, HAP_LVL_SHFT_MSM_GPIO);
+			goto reg_free;
+		}
+
+		rc = gpio_request(HAP_LVL_SHFT_MSM_GPIO, "haptics_shft_lvl_oe");
+		if (rc) {
+			pr_err("%s: unable to request gpio %d (%d)\n",
+					__func__, HAP_LVL_SHFT_MSM_GPIO, rc);
+			goto reg_free;
+		}
+
+		gpio_set_value(HAP_LVL_SHFT_MSM_GPIO, 1);
+	} else {
+		regulator_bulk_free(ARRAY_SIZE(regs_isa1200), regs_isa1200);
+		gpio_free(HAP_LVL_SHFT_MSM_GPIO);
+	}
+
+	return 0;
+
+reg_free:
+	regulator_bulk_free(ARRAY_SIZE(regs_isa1200), regs_isa1200);
+out:
+	return rc;
+}
+static struct isa1200_platform_data isa1200_1_pdata = {
+	.name = "vibrator",
+	.power_on = isa1200_power,
+	.dev_setup = isa1200_dev_setup,
+	.pwm_ch_id = 1, /*channel id*/
+	/*gpio to enable haptic*/
+	.hap_en_gpio = PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_HAP_ENABLE),
+	.hap_len_gpio = -1,
+	.max_timeout = 15000,
+	.mode_ctrl = PWM_GEN_MODE,
+	.pwm_fd = {
+		.pwm_div = 256,
+	},
+	.is_erm = false,
+	.smart_en = true,
+	.ext_clk_en = true,
+	.chip_en = 1,
+};
+
+static struct i2c_board_info msm_isa1200_board_info[] = {
+	{
+		I2C_BOARD_INFO("isa1200_1", 0x90>>1),
+		.platform_data = &isa1200_1_pdata,
+	},
+};
+
+
+static int kp_flip_mpp_config(void)
+{
+	struct pm8xxx_mpp_config_data kp_flip_mpp = {
+		.type = PM8XXX_MPP_TYPE_D_INPUT,
+		.level = PM8018_MPP_DIG_LEVEL_S3,
+		.control = PM8XXX_MPP_DIN_TO_INT,
+	};
+
+	return pm8xxx_mpp_config(PM8058_MPP_PM_TO_SYS(PM_FLIP_MPP),
+						&kp_flip_mpp);
+}
+
+static struct flip_switch_pdata flip_switch_data = {
+	.name = "kp_flip_switch",
+	.flip_gpio = PM8058_GPIO_PM_TO_SYS(PM8058_GPIOS) + PM_FLIP_MPP,
+	.left_key = KEY_OPEN,
+	.right_key = KEY_CLOSE,
+	.active_low = 0,
+	.wakeup = 1,
+	.flip_mpp_config = kp_flip_mpp_config,
+};
+
+static struct platform_device flip_switch_device = {
+	.name   = "kp_flip_switch",
+	.id	= -1,
+	.dev    = {
+		.platform_data = &flip_switch_data,
+	}
+};
+
+static struct regulator_bulk_data regs_tma300[] = {
+	{ .supply = "gp6", .min_uV = 3050000, .max_uV = 3100000 },
+	{ .supply = "gp7", .min_uV = 1800000, .max_uV = 1800000 },
+};
+
+static int tma300_power(int vreg_on)
+{
+	int rc;
+
+	rc = vreg_on ?
+		regulator_bulk_enable(ARRAY_SIZE(regs_tma300), regs_tma300) :
+		regulator_bulk_disable(ARRAY_SIZE(regs_tma300), regs_tma300);
+
+	if (rc)
+		pr_err("%s: could not %sable regulators: %d\n",
+				__func__, vreg_on ? "en" : "dis", rc);
+	return rc;
+}
+
+#define TS_GPIO_IRQ 150
+
+static int tma300_dev_setup(bool enable)
+{
+	int rc;
+
+	if (enable) {
+		rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs_tma300),
+				regs_tma300);
+
+		if (rc) {
+			pr_err("%s: could not get regulators: %d\n",
+					__func__, rc);
+			goto out;
+		}
+
+		rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs_tma300),
+				regs_tma300);
+
+		if (rc) {
+			pr_err("%s: could not set voltages: %d\n",
+					__func__, rc);
+			goto reg_free;
+		}
+
+		/* enable interrupt gpio */
+		rc = gpio_tlmm_config(GPIO_CFG(TS_GPIO_IRQ, 0, GPIO_CFG_INPUT,
+				GPIO_CFG_PULL_UP, GPIO_CFG_6MA), GPIO_CFG_ENABLE);
+		if (rc) {
+			pr_err("%s: Could not configure gpio %d\n",
+					__func__, TS_GPIO_IRQ);
+			goto reg_free;
+		}
+
+		/* virtual keys */
+		tma300_vkeys_attr.attr.name = "virtualkeys.msm_tma300_ts";
+		properties_kobj = kobject_create_and_add("board_properties",
+					NULL);
+		if (!properties_kobj) {
+			pr_err("%s: failed to create a kobject "
+					"for board_properties\n", __func__);
+			rc = -ENOMEM;
+			goto reg_free;
+		}
+		rc = sysfs_create_group(properties_kobj,
+				&tma300_properties_attr_group);
+		if (rc) {
+			pr_err("%s: failed to create a sysfs entry %s\n",
+					__func__, tma300_vkeys_attr.attr.name);
+			goto kobj_free;
+		}
+	} else {
+		regulator_bulk_free(ARRAY_SIZE(regs_tma300), regs_tma300);
+		/* destroy virtual keys */
+		if (properties_kobj) {
+			sysfs_remove_group(properties_kobj,
+				&tma300_properties_attr_group);
+			kobject_put(properties_kobj);
+		}
+	}
+	return 0;
+
+kobj_free:
+	kobject_put(properties_kobj);
+	properties_kobj = NULL;
+reg_free:
+	regulator_bulk_free(ARRAY_SIZE(regs_tma300), regs_tma300);
+out:
+	return rc;
+}
+
+static struct cy8c_ts_platform_data cy8ctma300_pdata = {
+	.power_on = tma300_power,
+	.dev_setup = tma300_dev_setup,
+	.ts_name = "msm_tma300_ts",
+	.dis_min_x = 0,
+	.dis_max_x = 479,
+	.dis_min_y = 0,
+	.dis_max_y = 799,
+	.res_x	 = 479,
+	.res_y	 = 1009,
+	.min_tid = 1,
+	.max_tid = 255,
+	.min_touch = 0,
+	.max_touch = 255,
+	.min_width = 0,
+	.max_width = 255,
+	.invert_y = 1,
+	.nfingers = 4,
+	.irq_gpio = TS_GPIO_IRQ,
+	.resout_gpio = -1,
+};
+
+static struct i2c_board_info cy8ctma300_board_info[] = {
+	{
+		I2C_BOARD_INFO("cy8ctma300", 0x2),
+		.platform_data = &cy8ctma300_pdata,
+	}
+};
+
 static void __init msm7x30_init(void)
 {
-	msm_device_otg.dev.platform_data = &msm_otg_pdata;
-	msm_device_hsusb.dev.parent = &msm_device_otg.dev;
-	msm_device_hsusb_host.dev.parent = &msm_device_otg.dev;
+	int rc;
+	unsigned smem_size;
+	uint32_t usb_hub_gpio_cfg_value = GPIO_CFG(56,
+						0,
+						GPIO_CFG_OUTPUT,
+						GPIO_CFG_NO_PULL,
+						GPIO_CFG_2MA);
+	uint32_t soc_version = 0;
 
+	soc_version = socinfo_get_version();
+
+	msm_clock_init(&msm7x30_clock_init_data);
+#ifdef CONFIG_SERIAL_MSM_CONSOLE
+	msm7x30_init_uart2();
+#endif
+	msm_spm_init(&msm_spm_data, 1);
+	acpuclk_init(&acpuclk_7x30_soc_data);
+	if (machine_is_msm7x30_surf() || machine_is_msm7x30_fluid())
+		msm7x30_cfg_smsc911x();
+
+#ifdef CONFIG_USB_MSM_OTG_72K
+	if (SOCINFO_VERSION_MAJOR(soc_version) >= 2 &&
+			SOCINFO_VERSION_MINOR(soc_version) >= 1) {
+		pr_debug("%s: SOC Version:2.(1 or more)\n", __func__);
+		msm_otg_pdata.ldo_set_voltage = 0;
+	}
+
+	msm_device_otg.dev.platform_data = &msm_otg_pdata;
+#ifdef CONFIG_USB_GADGET
+	msm_otg_pdata.swfi_latency =
+ 	msm_pm_data
+ 	[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency;
+	msm_device_gadget_peripheral.dev.platform_data = &msm_gadget_pdata;
+#endif
+#endif
+	msm_uart_dm1_pdata.wakeup_irq = gpio_to_irq(136);
+	msm_device_uart_dm1.dev.platform_data = &msm_uart_dm1_pdata;
+#if defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE)
+	msm_device_tsif.dev.platform_data = &tsif_platform_data;
+#endif
+	if (machine_is_msm7x30_fluid()) {
+		msm_adc_pdata.dev_names = msm_adc_fluid_device_names;
+		msm_adc_pdata.num_adc = ARRAY_SIZE(msm_adc_fluid_device_names);
+	} else {
+		msm_adc_pdata.dev_names = msm_adc_surf_device_names;
+		msm_adc_pdata.num_adc = ARRAY_SIZE(msm_adc_surf_device_names);
+	}
+
+	pmic8058_leds_init();
+
+	buses_init();
+
+#ifdef CONFIG_MSM_SSBI
+	msm_device_ssbi_pmic1.dev.platform_data =
+				&msm7x30_ssbi_pm8058_pdata;
+#endif
+
+	platform_add_devices(msm_footswitch_devices,
+			     msm_num_footswitch_devices);
 	platform_add_devices(devices, ARRAY_SIZE(devices));
+#ifdef CONFIG_USB_EHCI_MSM_72K
+	msm_add_host(0, &msm_usb_host_pdata);
+#endif
+#ifdef CONFIG_MSM_CAMERA_V4L2
+	msm7x30_init_cam();
+#endif
+	msm7x30_init_mmc();
+	msm7x30_init_nand();
+	msm_qsd_spi_init();
+
+#ifdef CONFIG_SPI_QSD
+	if (machine_is_msm7x30_fluid())
+		spi_register_board_info(lcdc_sharp_spi_board_info,
+			ARRAY_SIZE(lcdc_sharp_spi_board_info));
+	else
+		spi_register_board_info(lcdc_toshiba_spi_board_info,
+			ARRAY_SIZE(lcdc_toshiba_spi_board_info));
+#endif
+
+	atv_dac_power_init();
+	sensors_ldo_init();
+	hdmi_init_regs();
+	msm_fb_add_devices();
+	msm_pm_set_platform_data(msm_pm_data, ARRAY_SIZE(msm_pm_data));
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+	msm_pm_register_irqs();
+	msm_device_i2c_init();
+	msm_device_i2c_2_init();
+	qup_device_i2c_init();
+	msm7x30_init_marimba();
+#ifdef CONFIG_MSM7KV2_AUDIO
+	snddev_poweramp_gpio_init();
+	snddev_hsed_voltage_init();
+	aux_pcm_gpio_init();
+#endif
+
+	i2c_register_board_info(0, msm_i2c_board_info,
+			ARRAY_SIZE(msm_i2c_board_info));
+
+	if (!machine_is_msm8x55_svlte_ffa() && !machine_is_msm7x30_fluid())
+		marimba_pdata.tsadc = &marimba_tsadc_pdata;
+
+	if (machine_is_msm7x30_fluid())
+		i2c_register_board_info(0, cy8info,
+					ARRAY_SIZE(cy8info));
+#ifdef CONFIG_BOSCH_BMA150
+	if (machine_is_msm7x30_fluid())
+		i2c_register_board_info(0, bma150_board_info,
+					ARRAY_SIZE(bma150_board_info));
+#endif
+
+	i2c_register_board_info(2, msm_marimba_board_info,
+			ARRAY_SIZE(msm_marimba_board_info));
+
+	i2c_register_board_info(2, msm_i2c_gsbi7_timpani_info,
+			ARRAY_SIZE(msm_i2c_gsbi7_timpani_info));
+
+	i2c_register_board_info(4 /* QUP ID */, msm_camera_boardinfo,
+				ARRAY_SIZE(msm_camera_boardinfo));
+
+	bt_power_init();
+#ifdef CONFIG_I2C_SSBI
+	msm_device_ssbi7.dev.platform_data = &msm_i2c_ssbi7_pdata;
+#endif
+	if (machine_is_msm7x30_fluid())
+		i2c_register_board_info(0, msm_isa1200_board_info,
+			ARRAY_SIZE(msm_isa1200_board_info));
+
+#if defined(CONFIG_TOUCHSCREEN_TSC2007) || \
+	defined(CONFIG_TOUCHSCREEN_TSC2007_MODULE)
+	if (machine_is_msm8x55_svlte_ffa())
+		i2c_register_board_info(2, tsc_i2c_board_info,
+				ARRAY_SIZE(tsc_i2c_board_info));
+#endif
+
+	if (machine_is_msm7x30_surf())
+		platform_device_register(&flip_switch_device);
+
+	pm8058_gpios_init();
+
+	if (machine_is_msm7x30_fluid()) {
+		/* Initialize platform data for fluid v2 hardware */
+		if (SOCINFO_VERSION_MAJOR(
+				socinfo_get_platform_version()) == 2) {
+			cy8ctma300_pdata.res_y = 920;
+			cy8ctma300_pdata.invert_y = 0;
+		}
+		i2c_register_board_info(0, cy8ctma300_board_info,
+			ARRAY_SIZE(cy8ctma300_board_info));
+	}
+
+	if (machine_is_msm8x55_svlte_surf() || machine_is_msm8x55_svlte_ffa()) {
+		rc = gpio_tlmm_config(usb_hub_gpio_cfg_value, GPIO_CFG_ENABLE);
+		if (rc)
+			pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
+				__func__, usb_hub_gpio_cfg_value, rc);
+	}
+
+	boot_reason = *(unsigned int *)
+		(smem_get_entry(SMEM_POWER_ON_STATUS_INFO, &smem_size));
+	printk(KERN_NOTICE "Boot Reason = 0x%02x\n", boot_reason);
+}
+
+static unsigned pmem_sf_size = MSM_PMEM_SF_SIZE;
+static int __init pmem_sf_size_setup(char *p)
+{
+	pmem_sf_size = memparse(p, NULL);
+	return 0;
+}
+early_param("pmem_sf_size", pmem_sf_size_setup);
+
+static unsigned fb_size = MSM_FB_SIZE;
+static int __init fb_size_setup(char *p)
+{
+	fb_size = memparse(p, NULL);
+	return 0;
+}
+early_param("fb_size", fb_size_setup);
+
+static unsigned pmem_adsp_size = MSM_PMEM_ADSP_SIZE;
+static int __init pmem_adsp_size_setup(char *p)
+{
+	pmem_adsp_size = memparse(p, NULL);
+	return 0;
+}
+early_param("pmem_adsp_size", pmem_adsp_size_setup);
+
+static unsigned fluid_pmem_adsp_size = MSM_FLUID_PMEM_ADSP_SIZE;
+static int __init fluid_pmem_adsp_size_setup(char *p)
+{
+	fluid_pmem_adsp_size = memparse(p, NULL);
+	return 0;
+}
+early_param("fluid_pmem_adsp_size", fluid_pmem_adsp_size_setup);
+
+static unsigned pmem_audio_size = MSM_PMEM_AUDIO_SIZE;
+static int __init pmem_audio_size_setup(char *p)
+{
+	pmem_audio_size = memparse(p, NULL);
+	return 0;
+}
+early_param("pmem_audio_size", pmem_audio_size_setup);
+
+static unsigned pmem_kernel_ebi0_size = PMEM_KERNEL_EBI0_SIZE;
+static int __init pmem_kernel_ebi0_size_setup(char *p)
+{
+	pmem_kernel_ebi0_size = memparse(p, NULL);
+	return 0;
+}
+early_param("pmem_kernel_ebi0_size", pmem_kernel_ebi0_size_setup);
+
+static struct memtype_reserve msm7x30_reserve_table[] __initdata = {
+	[MEMTYPE_SMI] = {
+	},
+	[MEMTYPE_EBI0] = {
+		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
+	},
+	[MEMTYPE_EBI1] = {
+		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
+	},
+};
+
+static void __init size_pmem_devices(void)
+{
+#ifdef CONFIG_ANDROID_PMEM
+	unsigned long size;
+
+	if machine_is_msm7x30_fluid()
+		size = fluid_pmem_adsp_size;
+	else
+		size = pmem_adsp_size;
+	android_pmem_adsp_pdata.size = size;
+	android_pmem_audio_pdata.size = pmem_audio_size;
+	android_pmem_pdata.size = pmem_sf_size;
+#endif
+}
+
+static void __init reserve_memory_for(struct android_pmem_platform_data *p)
+{
+	msm7x30_reserve_table[p->memory_type].size += p->size;
+}
+
+static void __init reserve_pmem_memory(void)
+{
+#ifdef CONFIG_ANDROID_PMEM
+	reserve_memory_for(&android_pmem_adsp_pdata);
+	reserve_memory_for(&android_pmem_audio_pdata);
+	reserve_memory_for(&android_pmem_pdata);
+	msm7x30_reserve_table[MEMTYPE_EBI0].size += pmem_kernel_ebi0_size;
+#endif
+}
+
+static void __init msm7x30_calculate_reserve_sizes(void)
+{
+	size_pmem_devices();
+	reserve_pmem_memory();
+}
+
+static int msm7x30_paddr_to_memtype(unsigned int paddr)
+{
+	if (paddr < phys_add)
+		return MEMTYPE_EBI0;
+	if (paddr >= phys_add && paddr < 0x80000000)
+		return MEMTYPE_EBI1;
+	return MEMTYPE_NONE;
+}
+
+static struct reserve_info msm7x30_reserve_info __initdata = {
+	.memtype_reserve_table = msm7x30_reserve_table,
+	.calculate_reserve_sizes = msm7x30_calculate_reserve_sizes,
+	.paddr_to_memtype = msm7x30_paddr_to_memtype,
+};
+
+static void __init msm7x30_reserve(void)
+{
+	reserve_info = &msm7x30_reserve_info;
+	msm_reserve();
+}
+
+static void __init msm7x30_allocate_memory_regions(void)
+{
+	void *addr;
+	unsigned long size;
+
+	size = fb_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));
+
+#ifdef CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE
+	size = MSM_V4L2_VIDEO_OVERLAY_BUF_SIZE;
+	addr = alloc_bootmem_align(size, 0x1000);
+	msm_v4l2_video_overlay_resources[0].start = __pa(addr);
+	msm_v4l2_video_overlay_resources[0].end =
+		msm_v4l2_video_overlay_resources[0].start + size - 1;
+	pr_debug("allocating %lu bytes at %p (%lx physical) for v4l2\n",
+		size, addr, __pa(addr));
+#endif
 }
 
 static void __init msm7x30_map_io(void)
 {
+	msm_shared_ram_phys = 0x00100000;
 	msm_map_msm7x30_io();
-	msm_clock_init(msm_clocks_7x30, msm_num_clocks_7x30);
+	if (socinfo_init() < 0)
+		printk(KERN_ERR "%s: socinfo_init() failed!\n",
+		       __func__);
+}
+
+static void __init msm7x30_init_early(void)
+{
+	msm7x30_allocate_memory_regions();
+}
+
+static void __init msm7x30_fixup(struct tag *tags, char **cmdline,
+				 struct meminfo *mi)
+{
+	for (; tags->hdr.size; tags = tag_next(tags)) {
+		if (tags->hdr.tag == ATAG_MEM && tags->u.mem.start ==
+							DDR1_BANK_BASE) {
+				ebi1_phys_offset = DDR1_BANK_BASE;
+				phys_add = DDR1_BANK_BASE;
+				break;
+		}
+	}
 }
 
 MACHINE_START(MSM7X30_SURF, "QCT MSM7X30 SURF")
 	.atag_offset = 0x100,
-	.fixup = msm7x30_fixup,
-	.reserve = msm7x30_reserve,
 	.map_io = msm7x30_map_io,
+	.reserve = msm7x30_reserve,
 	.init_irq = msm7x30_init_irq,
 	.init_machine = msm7x30_init,
 	.timer = &msm_timer,
+	.init_early = msm7x30_init_early,
+	.handle_irq = vic_handle_irq,
+	.fixup = msm7x30_fixup,
 MACHINE_END
 
 MACHINE_START(MSM7X30_FFA, "QCT MSM7X30 FFA")
 	.atag_offset = 0x100,
-	.fixup = msm7x30_fixup,
-	.reserve = msm7x30_reserve,
 	.map_io = msm7x30_map_io,
+	.reserve = msm7x30_reserve,
 	.init_irq = msm7x30_init_irq,
 	.init_machine = msm7x30_init,
 	.timer = &msm_timer,
+	.init_early = msm7x30_init_early,
+	.handle_irq = vic_handle_irq,
+	.fixup = msm7x30_fixup,
 MACHINE_END
 
 MACHINE_START(MSM7X30_FLUID, "QCT MSM7X30 FLUID")
 	.atag_offset = 0x100,
-	.fixup = msm7x30_fixup,
-	.reserve = msm7x30_reserve,
 	.map_io = msm7x30_map_io,
+	.reserve = msm7x30_reserve,
 	.init_irq = msm7x30_init_irq,
 	.init_machine = msm7x30_init,
 	.timer = &msm_timer,
+	.init_early = msm7x30_init_early,
+	.handle_irq = vic_handle_irq,
+	.fixup = msm7x30_fixup,
+MACHINE_END
+
+MACHINE_START(MSM8X55_SURF, "QCT MSM8X55 SURF")
+	.atag_offset = 0x100,
+	.map_io = msm7x30_map_io,
+	.reserve = msm7x30_reserve,
+	.init_irq = msm7x30_init_irq,
+	.init_machine = msm7x30_init,
+	.timer = &msm_timer,
+	.init_early = msm7x30_init_early,
+	.handle_irq = vic_handle_irq,
+	.fixup = msm7x30_fixup,
+MACHINE_END
+
+MACHINE_START(MSM8X55_FFA, "QCT MSM8X55 FFA")
+	.atag_offset = 0x100,
+	.map_io = msm7x30_map_io,
+	.reserve = msm7x30_reserve,
+	.init_irq = msm7x30_init_irq,
+	.init_machine = msm7x30_init,
+	.timer = &msm_timer,
+	.init_early = msm7x30_init_early,
+	.handle_irq = vic_handle_irq,
+	.fixup = msm7x30_fixup,
+MACHINE_END
+MACHINE_START(MSM8X55_SVLTE_SURF, "QCT MSM8X55 SVLTE SURF")
+	.atag_offset = 0x100,
+	.map_io = msm7x30_map_io,
+	.reserve = msm7x30_reserve,
+	.init_irq = msm7x30_init_irq,
+	.init_machine = msm7x30_init,
+	.timer = &msm_timer,
+	.init_early = msm7x30_init_early,
+	.handle_irq = vic_handle_irq,
+	.fixup = msm7x30_fixup,
+MACHINE_END
+MACHINE_START(MSM8X55_SVLTE_FFA, "QCT MSM8X55 SVLTE FFA")
+	.atag_offset = 0x100,
+	.map_io = msm7x30_map_io,
+	.reserve = msm7x30_reserve,
+	.init_irq = msm7x30_init_irq,
+	.init_machine = msm7x30_init,
+	.timer = &msm_timer,
+	.init_early = msm7x30_init_early,
+	.handle_irq = vic_handle_irq,
+	.fixup = msm7x30_fixup,
 MACHINE_END
diff --git a/arch/arm/mach-msm/board-msm8960.c b/arch/arm/mach-msm/board-msm8960.c
deleted file mode 100644
index ed35981..0000000
--- a/arch/arm/mach-msm/board-msm8960.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- */
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/clkdev.h>
-#include <linux/memblock.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/hardware/gic.h>
-#include <asm/setup.h>
-
-#include <mach/board.h>
-#include <mach/msm_iomap.h>
-
-#include "devices.h"
-
-static void __init msm8960_fixup(struct tag *tag, char **cmdline,
-		struct meminfo *mi)
-{
-	for (; tag->hdr.size; tag = tag_next(tag))
-		if (tag->hdr.tag == ATAG_MEM &&
-				tag->u.mem.start == 0x40200000) {
-			tag->u.mem.start = 0x40000000;
-			tag->u.mem.size += SZ_2M;
-		}
-}
-
-static void __init msm8960_reserve(void)
-{
-	memblock_remove(0x40000000, SZ_2M);
-}
-
-static void __init msm8960_map_io(void)
-{
-	msm_map_msm8960_io();
-}
-
-static void __init msm8960_init_irq(void)
-{
-	unsigned int i;
-	gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE,
-		 (void *)MSM_QGIC_CPU_BASE);
-
-	/* Edge trigger PPIs except AVS_SVICINT and AVS_SVICINTSWDONE */
-	writel(0xFFFFD7FF, MSM_QGIC_DIST_BASE + GIC_DIST_CONFIG + 4);
-
-	if (machine_is_msm8960_rumi3())
-		writel(0x0000FFFF, MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET);
-
-	/* FIXME: Not installing AVS_SVICINT and AVS_SVICINTSWDONE yet
-	 * as they are configured as level, which does not play nice with
-	 * handle_percpu_irq.
-	 */
-	for (i = GIC_PPI_START; i < GIC_SPI_START; i++) {
-		if (i != AVS_SVICINT && i != AVS_SVICINTSWDONE)
-			irq_set_handler(i, handle_percpu_irq);
-	}
-}
-
-static struct platform_device *sim_devices[] __initdata = {
-	&msm8960_device_uart_gsbi2,
-};
-
-static struct platform_device *rumi3_devices[] __initdata = {
-	&msm8960_device_uart_gsbi5,
-};
-
-static void __init msm8960_sim_init(void)
-{
-	platform_add_devices(sim_devices, ARRAY_SIZE(sim_devices));
-}
-
-static void __init msm8960_rumi3_init(void)
-{
-	platform_add_devices(rumi3_devices, ARRAY_SIZE(rumi3_devices));
-}
-
-MACHINE_START(MSM8960_SIM, "QCT MSM8960 SIMULATOR")
-	.fixup = msm8960_fixup,
-	.reserve = msm8960_reserve,
-	.map_io = msm8960_map_io,
-	.init_irq = msm8960_init_irq,
-	.timer = &msm_timer,
-	.handle_irq = gic_handle_irq,
-	.init_machine = msm8960_sim_init,
-MACHINE_END
-
-MACHINE_START(MSM8960_RUMI3, "QCT MSM8960 RUMI3")
-	.fixup = msm8960_fixup,
-	.reserve = msm8960_reserve,
-	.map_io = msm8960_map_io,
-	.init_irq = msm8960_init_irq,
-	.timer = &msm_timer,
-	.handle_irq = gic_handle_irq,
-	.init_machine = msm8960_rumi3_init,
-MACHINE_END
-
diff --git a/arch/arm/mach-msm/board-msm8x60-camera.c b/arch/arm/mach-msm/board-msm8x60-camera.c
new file mode 100644
index 0000000..32d5530
--- /dev/null
+++ b/arch/arm/mach-msm/board-msm8x60-camera.c
@@ -0,0 +1,543 @@
+/* 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 <asm/mach-types.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/mfd/pmic8901.h>
+#include <mach/board.h>
+#include <mach/board-msm8660.h>
+#include <mach/gpiomux.h>
+#include <mach/msm_bus_board.h>
+#include "devices-msm8x60.h"
+#include "devices.h"
+
+#define GPIO_EXT_CAMIF_PWR_EN1 (PM8901_MPP_BASE + PM8901_MPPS + 13)
+#define GPIO_WEB_CAMIF_STANDBY1 (PM8901_MPP_BASE + PM8901_MPPS + 60)
+#ifdef CONFIG_MSM_CAMERA_FLASH
+#define VFE_CAMIF_TIMER1_GPIO 29
+#define VFE_CAMIF_TIMER2_GPIO 30
+#define VFE_CAMIF_TIMER3_GPIO_INT 31
+#define FUSION_VFE_CAMIF_TIMER1_GPIO 42
+
+static struct msm_camera_sensor_flash_src msm_flash_src = {
+	.flash_sr_type = MSM_CAMERA_FLASH_SRC_PMIC,
+	._fsrc.pmic_src.num_of_src = 2,
+	._fsrc.pmic_src.low_current  = 100,
+	._fsrc.pmic_src.high_current = 300,
+	._fsrc.pmic_src.led_src_1 = PMIC8058_ID_FLASH_LED_0,
+	._fsrc.pmic_src.led_src_2 = PMIC8058_ID_FLASH_LED_1,
+	._fsrc.pmic_src.pmic_set_current = pm8058_set_flash_led_current,
+};
+static struct msm_camera_sensor_strobe_flash_data strobe_flash_xenon = {
+	.flash_trigger = VFE_CAMIF_TIMER2_GPIO,
+	.flash_charge = VFE_CAMIF_TIMER1_GPIO,
+	.flash_charge_done = VFE_CAMIF_TIMER3_GPIO_INT,
+	.flash_recharge_duration = 50000,
+	.irq = MSM_GPIO_TO_INT(VFE_CAMIF_TIMER3_GPIO_INT),
+};
+#endif
+
+static struct msm_bus_vectors cam_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+};
+
+static struct msm_bus_vectors cam_preview_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 283115520,
+		.ib  = 452984832,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+};
+
+static struct msm_bus_vectors cam_video_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 283115520,
+		.ib  = 452984832,
+	},
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 283115520,
+		.ib  = 452984832,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 319610880,
+		.ib  = 511377408,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+};
+
+static struct msm_bus_vectors cam_snapshot_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 566231040,
+		.ib  = 905969664,
+	},
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 69984000,
+		.ib  = 111974400,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 320864256,
+		.ib  = 513382810,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 320864256,
+		.ib  = 513382810,
+	},
+};
+
+static struct msm_bus_vectors cam_zsl_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 566231040,
+		.ib  = 905969664,
+	},
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 706199040,
+		.ib  = 1129918464,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 320864256,
+		.ib  = 513382810,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 320864256,
+		.ib  = 513382810,
+	},
+};
+
+static struct msm_bus_vectors cam_stereo_video_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 212336640,
+		.ib  = 339738624,
+	},
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 25090560,
+		.ib  = 40144896,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 239708160,
+		.ib  = 383533056,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 79902720,
+		.ib  = 127844352,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+};
+
+static struct msm_bus_vectors cam_stereo_snapshot_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 300902400,
+		.ib  = 481443840,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 230307840,
+		.ib  = 368492544,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 245113344,
+		.ib  = 392181351,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 106536960,
+		.ib  = 170459136,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 106536960,
+		.ib  = 170459136,
+	},
+};
+
+static struct msm_bus_paths cam_bus_client_config[] = {
+	{
+		ARRAY_SIZE(cam_init_vectors),
+		cam_zsl_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_preview_vectors),
+		cam_zsl_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_video_vectors),
+		cam_zsl_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_snapshot_vectors),
+		cam_snapshot_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_zsl_vectors),
+		cam_zsl_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_stereo_video_vectors),
+		cam_stereo_video_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_stereo_snapshot_vectors),
+		cam_stereo_snapshot_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata cam_bus_client_pdata = {
+		cam_bus_client_config,
+		ARRAY_SIZE(cam_bus_client_config),
+		.name = "msm_camera",
+};
+
+static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
+	{
+		.csid_core = 0,
+		.is_csic = 1,
+		.is_vpe    = 1,
+		.cam_bus_scale_table = &cam_bus_client_pdata,
+		.ioclk = {
+			.vfe_clk_rate =	228570000,
+		},
+	},
+	{
+		.csid_core = 1,
+		.is_csic = 1,
+		.is_vpe    = 1,
+		.cam_bus_scale_table = &cam_bus_client_pdata,
+		.ioclk = {
+			.vfe_clk_rate =	228570000,
+		},
+	},
+};
+static struct camera_vreg_t msm_8x60_back_cam_vreg[] = {
+	{"cam_vana", REG_LDO, 2850000, 2850000, -1},
+	{"cam_vio", REG_VS, 0, 0, 0},
+	{"cam_vdig", REG_LDO, 1200000, 1200000, -1},
+};
+
+static struct gpio msm8x60_common_cam_gpio[] = {
+	{32, GPIOF_DIR_IN, "CAMIF_MCLK"},
+	{47, GPIOF_DIR_IN, "CAMIF_I2C_DATA"},
+	{48, GPIOF_DIR_IN, "CAMIF_I2C_CLK"},
+	{105, GPIOF_DIR_IN, "STANDBY"},
+};
+
+static struct gpio msm8x60_back_cam_gpio[] = {
+	{GPIO_EXT_CAMIF_PWR_EN1, GPIOF_DIR_OUT, "CAMIF_PWR_EN"},
+	{106, GPIOF_DIR_OUT, "CAM_RESET"},
+};
+
+static struct msm_gpio_set_tbl msm8x60_back_cam_gpio_set_tbl[] = {
+	{GPIO_EXT_CAMIF_PWR_EN1, GPIOF_OUT_INIT_LOW, 10000},
+	{GPIO_EXT_CAMIF_PWR_EN1, GPIOF_OUT_INIT_HIGH, 5000},
+	{106, GPIOF_OUT_INIT_LOW, 1000},
+	{106, GPIOF_OUT_INIT_HIGH, 4000},
+};
+
+static struct msm_camera_gpio_conf msm_8x60_back_cam_gpio_conf = {
+	.cam_gpio_common_tbl = msm8x60_common_cam_gpio,
+	.cam_gpio_common_tbl_size = ARRAY_SIZE(msm8x60_common_cam_gpio),
+	.cam_gpio_req_tbl = msm8x60_back_cam_gpio,
+	.cam_gpio_req_tbl_size = ARRAY_SIZE(msm8x60_back_cam_gpio),
+	.cam_gpio_set_tbl = msm8x60_back_cam_gpio_set_tbl,
+	.cam_gpio_set_tbl_size = ARRAY_SIZE(msm8x60_back_cam_gpio_set_tbl),
+};
+
+
+static struct i2c_board_info imx074_actuator_i2c_info = {
+	I2C_BOARD_INFO("msm_actuator", 0x11),
+};
+
+static struct msm_actuator_info imx074_actuator_info = {
+	.board_info     = &imx074_actuator_i2c_info,
+	.cam_name   = MSM_ACTUATOR_MAIN_CAM_0,
+	.bus_id         = MSM_GSBI4_QUP_I2C_BUS_ID,
+	.vcm_enable     = 0,
+};
+
+static struct msm_camera_sensor_flash_data flash_imx074 = {
+	.flash_type	= MSM_CAMERA_FLASH_LED,
+#ifdef CONFIG_MSM_CAMERA_FLASH
+	.flash_src	= &msm_flash_src,
+#endif
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_imx074 = {
+	.mount_angle	= 180,
+	.cam_vreg = msm_8x60_back_cam_vreg,
+	.num_vreg = ARRAY_SIZE(msm_8x60_back_cam_vreg),
+	.gpio_conf = &msm_8x60_back_cam_gpio_conf,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_imx074_data = {
+	.sensor_name	= "imx074",
+	.pdata	= &msm_camera_csi_device_data[0],
+	.flash_data	= &flash_imx074,
+	.strobe_flash_data = &strobe_flash_xenon,
+	.sensor_platform_info = &sensor_board_info_imx074,
+	.csi_if	= 1,
+	.camera_type = BACK_CAMERA_2D,
+	.actuator_info = &imx074_actuator_info
+};
+
+static struct msm_camera_sensor_flash_data flash_mt9e013 = {
+	.flash_type	= MSM_CAMERA_FLASH_NONE,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_mt9e013 = {
+	.mount_angle	= 0,
+	.cam_vreg = msm_8x60_back_cam_vreg,
+	.num_vreg = ARRAY_SIZE(msm_8x60_back_cam_vreg),
+	.gpio_conf = &msm_8x60_back_cam_gpio_conf,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_mt9e013_data = {
+	.sensor_name	= "mt9e013",
+	.pdata	= &msm_camera_csi_device_data[0],
+	.flash_data	= &flash_mt9e013,
+	.sensor_platform_info = &sensor_board_info_mt9e013,
+	.csi_if	= 1,
+	.camera_type = BACK_CAMERA_2D,
+};
+
+static struct gpio ov7692_cam_gpio[] = {
+	{GPIO_WEB_CAMIF_STANDBY1, GPIOF_DIR_OUT, "CAM_EN"},
+};
+
+static struct msm_gpio_set_tbl ov7692_cam_gpio_set_tbl[] = {
+	{GPIO_WEB_CAMIF_STANDBY1, GPIOF_OUT_INIT_LOW, 10000},
+};
+
+static struct msm_camera_gpio_conf ov7692_cam_gpio_conf = {
+	.cam_gpio_common_tbl = msm8x60_common_cam_gpio,
+	.cam_gpio_common_tbl_size = ARRAY_SIZE(msm8x60_common_cam_gpio),
+	.cam_gpio_req_tbl = ov7692_cam_gpio,
+	.cam_gpio_req_tbl_size = ARRAY_SIZE(ov7692_cam_gpio),
+	.cam_gpio_set_tbl = ov7692_cam_gpio_set_tbl,
+	.cam_gpio_set_tbl_size = ARRAY_SIZE(ov7692_cam_gpio_set_tbl),
+};
+
+static struct msm_camera_sensor_flash_data flash_ov7692 = {
+	.flash_type	= MSM_CAMERA_FLASH_NONE,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_ov7692 = {
+	.mount_angle	= 0,
+	.cam_vreg = msm_8x60_back_cam_vreg,
+	.num_vreg = ARRAY_SIZE(msm_8x60_back_cam_vreg),
+	.gpio_conf = &ov7692_cam_gpio_conf,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_ov7692_data = {
+	.sensor_name	= "ov7692",
+	.pdata	= &msm_camera_csi_device_data[1],
+	.flash_data	= &flash_ov7692,
+	.sensor_platform_info = &sensor_board_info_ov7692,
+	.csi_if	= 1,
+	.camera_type = FRONT_CAMERA_2D,
+};
+
+static struct platform_device msm_camera_server = {
+	.name = "msm_cam_server",
+	.id = 0,
+};
+
+void __init msm8x60_init_cam(void)
+{
+	platform_device_register(&msm_camera_server);
+	platform_device_register(&msm_device_csic0);
+	platform_device_register(&msm_device_csic1);
+	platform_device_register(&msm_device_vfe);
+	platform_device_register(&msm_device_vpe);
+}
+
+#ifdef CONFIG_I2C
+static struct i2c_board_info msm8x60_camera_i2c_boardinfo[] = {
+	{
+	I2C_BOARD_INFO("imx074", 0x1A),
+	.platform_data = &msm_camera_sensor_imx074_data,
+	},
+	{
+	I2C_BOARD_INFO("mt9e013", 0x6C),
+	.platform_data = &msm_camera_sensor_mt9e013_data,
+	},
+	{
+	I2C_BOARD_INFO("ov7692", 0x78),
+	.platform_data = &msm_camera_sensor_ov7692_data,
+	},
+};
+
+struct msm_camera_board_info msm8x60_camera_board_info = {
+	.board_info = msm8x60_camera_i2c_boardinfo,
+	.num_i2c_board_info = ARRAY_SIZE(msm8x60_camera_i2c_boardinfo),
+};
+#endif
diff --git a/arch/arm/mach-msm/board-msm8x60-vcm.c b/arch/arm/mach-msm/board-msm8x60-vcm.c
new file mode 100644
index 0000000..6078367
--- /dev/null
+++ b/arch/arm/mach-msm/board-msm8x60-vcm.c
@@ -0,0 +1,168 @@
+/* Copyright (c) 2010, 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/kernel.h>
+#include <linux/bootmem.h>
+
+#include <linux/vcm.h>
+#include <linux/vcm_alloc.h>
+
+#define MSM_SMI_BASE           0x38000000
+#define MSM_SMI_SIZE           0x04000000
+
+#define SMI_16M	0
+#define SMI_1M	1
+#define SMI_64K	2
+#define SMI_4K	3
+#define EBI_16M 4
+#define EBI_1M  5
+#define EBI_64K 6
+#define EBI_4K	7
+
+static void free_ebi_pools(void);
+
+static struct physmem_region memory[] = {
+	{	/* SMI 16M */
+		.addr = MSM_SMI_BASE,
+		.size = SZ_16M,
+		.chunk_size = SZ_16M
+	},
+	{	/* SMI 1M */
+		.addr = MSM_SMI_BASE + SZ_16M,
+		.size = SZ_8M,
+		.chunk_size = SZ_1M
+	},
+	{	/* SMI 64K */
+		.addr = MSM_SMI_BASE + SZ_16M + SZ_8M,
+		.size = SZ_4M,
+		.chunk_size = SZ_64K
+	},
+	{	/* SMI 4K */
+		.addr = MSM_SMI_BASE + SZ_16M + SZ_8M + SZ_4M,
+		.size = SZ_4M,
+		.chunk_size = SZ_4K
+	},
+
+	{	/* EBI 16M */
+		.addr = 0,
+		.size = SZ_16M,
+		.chunk_size = SZ_16M
+	},
+	{	/* EBI 1M */
+		.addr = 0,
+		.size = SZ_8M,
+		.chunk_size = SZ_1M
+	},
+	{	/* EBI 64K */
+		.addr = 0,
+		.size = SZ_4M,
+		.chunk_size = SZ_64K
+	},
+	{	/* EBI 4K */
+		.addr = 0,
+		.size = SZ_4M,
+		.chunk_size = SZ_4K
+	}
+};
+
+
+/* The pool priority MUST be in descending order of size */
+static struct vcm_memtype_map mt_map[] __initdata = {
+	{
+		/* MEMTYPE_0 */
+		.pool_id = {SMI_16M, SMI_1M, SMI_64K, SMI_4K},
+		.num_pools = 4,
+	},
+	{
+		/* MEMTYPE_1 */
+		.pool_id = {SMI_16M, SMI_1M, SMI_64K, EBI_4K},
+		.num_pools = 4,
+	},
+	{	/* MEMTYPE_2 */
+		.pool_id = {EBI_16M, EBI_1M, EBI_64K, EBI_4K},
+		.num_pools = 4,
+	},
+	{
+		/* MEMTYPE_3 */
+		.pool_id = {SMI_16M, SMI_1M, EBI_1M, SMI_64K, EBI_64K, EBI_4K},
+		.num_pools = 6,
+	}
+};
+
+static int __init msm8x60_vcm_init(void)
+{
+	int ret, i;
+	void *ebi_chunk;
+
+
+	for (i = 0; i < ARRAY_SIZE(memory); i++) {
+		if (memory[i].addr == 0) {
+			ebi_chunk = __alloc_bootmem(memory[i].size,
+							    memory[i].size, 0);
+			if (!ebi_chunk) {
+				pr_err("Could not allocate VCM-managed physical"
+				       " memory\n");
+				ret = -ENOMEM;
+				goto fail;
+			}
+			memory[i].addr = __pa(ebi_chunk);
+		}
+	}
+
+	ret = vcm_sys_init(memory, ARRAY_SIZE(memory),
+			   mt_map, ARRAY_SIZE(mt_map),
+			   (void *)MSM_SMI_BASE + MSM_SMI_SIZE - SZ_8M, SZ_8M);
+
+	if (ret != 0) {
+		pr_err("vcm_sys_init() ret %i\n", ret);
+		goto fail;
+	}
+
+	return 0;
+fail:
+	free_ebi_pools();
+	return ret;
+};
+
+static void free_ebi_pools(void)
+{
+	int i;
+	phys_addr_t r;
+	for (i = 0; i < ARRAY_SIZE(memory); i++) {
+		r = memory[i].addr;
+		if (r > MSM_SMI_BASE + MSM_SMI_SIZE)
+			free_bootmem((unsigned long)__va(r), memory[i].size);
+	}
+}
+
+
+/* Useful for testing, and if VCM is ever unloaded */
+static void __exit msm8x60_vcm_exit(void)
+{
+	int ret;
+
+	ret = vcm_sys_destroy();
+	if (ret != 0) {
+		pr_err("vcm_sys_destroy() ret %i\n", ret);
+		goto fail;
+	}
+	free_ebi_pools();
+fail:
+	return;
+}
+
+
+subsys_initcall(msm8x60_vcm_init);
+module_exit(msm8x60_vcm_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Stepan Moskovchenko <stepanm@codeaurora.org>");
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index fb3496a..efde720 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.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
@@ -8,149 +8,10624 @@
  * 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/kernel.h>
 #include <linux/platform_device.h>
-#include <linux/io.h>
+#include <linux/gpio.h>
 #include <linux/irq.h>
-#include <linux/irqdomain.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/of_platform.h>
-#include <linux/memblock.h>
+#include <linux/io.h>
+#include <linux/msm_ssbi.h>
+#include <linux/mfd/pmic8058.h>
 
+#include <linux/leds.h>
+#include <linux/pmic8058-othc.h>
+#include <linux/mfd/pmic8901.h>
+#include <linux/regulator/msm-gpio-regulator.h>
+#include <linux/regulator/pmic8901-regulator.h>
+#include <linux/bootmem.h>
+#include <linux/msm_adc.h>
+#include <linux/m_adcproc.h>
+#include <linux/mfd/marimba.h>
+#include <linux/msm-charger.h>
+#include <linux/i2c.h>
+#include <linux/i2c/sx150x.h>
+#include <linux/smsc911x.h>
+#include <linux/spi/spi.h>
+#include <linux/input/tdisc_shinetsu.h>
+#include <linux/input/cy8c_ts.h>
+#include <linux/cyttsp-qc.h>
+#include <linux/i2c/isa1200.h>
+#include <linux/dma-mapping.h>
+#include <linux/i2c/bq27520.h>
+
+#ifdef CONFIG_ANDROID_PMEM
+#include <linux/android_pmem.h>
+#endif
+
+#if defined(CONFIG_SMB137B_CHARGER) || defined(CONFIG_SMB137B_CHARGER_MODULE)
+#include <linux/i2c/smb137b.h>
+#endif
+#ifdef CONFIG_SND_SOC_WM8903
+#include <sound/wm8903.h>
+#endif
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
-#include <asm/hardware/gic.h>
 #include <asm/setup.h>
+#include <asm/hardware/gic.h>
 
+#include <mach/dma.h>
 #include <mach/board.h>
+#include <mach/irqs.h>
+#include <mach/msm_spi.h>
+#include <mach/msm_serial_hs.h>
+#include <mach/msm_serial_hs_lite.h>
 #include <mach/msm_iomap.h>
+#include <mach/msm_memtypes.h>
+#include <asm/mach/mmc.h>
+#include <mach/msm_battery.h>
+#include <mach/msm_hsusb.h>
+#include <mach/gpiomux.h>
+#ifdef CONFIG_MSM_DSPS
+#include <mach/msm_dsps.h>
+#endif
+#include <mach/msm_xo.h>
+#include <mach/msm_bus_board.h>
+#include <mach/socinfo.h>
+#include <linux/i2c/isl9519.h>
+#ifdef CONFIG_USB_G_ANDROID
+#include <linux/usb/android.h>
+#include <mach/usbdiag.h>
+#endif
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/machine.h>
+#include <mach/sdio_al.h>
+#include <mach/rpm.h>
+#include <mach/rpm-regulator.h>
+#include <mach/restart.h>
+#include <mach/board-msm8660.h>
+#include <mach/iommu_domains.h>
 
-static void __init msm8x60_fixup(struct tag *tag, char **cmdline,
-		struct meminfo *mi)
-{
-	for (; tag->hdr.size; tag = tag_next(tag))
-		if (tag->hdr.tag == ATAG_MEM &&
-				tag->u.mem.start == 0x40200000) {
-			tag->u.mem.start = 0x40000000;
-			tag->u.mem.size += SZ_2M;
-		}
+#include "devices.h"
+#include "devices-msm8x60.h"
+#include <mach/cpuidle.h>
+#include "pm.h"
+#include <mach/mpm.h>
+#include "spm.h"
+#include "rpm_log.h"
+#include "timer.h"
+#include "gpiomux-8x60.h"
+#include "rpm_stats.h"
+#include "peripheral-loader.h"
+#include <linux/platform_data/qcom_crypto_device.h>
+#include "rpm_resources.h"
+#include "acpuclock.h"
+#include "pm-boot.h"
+#include "board-storage-common-a.h"
+
+#include <linux/ion.h>
+#include <mach/ion.h>
+#include <mach/msm_rtb.h>
+
+#define MSM_SHARED_RAM_PHYS 0x40000000
+#define MDM2AP_SYNC 129
+
+#define GPIO_ETHERNET_RESET_N_DRAGON	30
+#define LCDC_SPI_GPIO_CLK				73
+#define LCDC_SPI_GPIO_CS				72
+#define LCDC_SPI_GPIO_MOSI				70
+#define LCDC_AUO_PANEL_NAME				"lcdc_auo_wvga"
+#define LCDC_SAMSUNG_OLED_PANEL_NAME	"lcdc_samsung_oled"
+#define LCDC_SAMSUNG_WSVGA_PANEL_NAME	"lcdc_samsung_wsvga"
+#define LCDC_SAMSUNG_SPI_DEVICE_NAME	"lcdc_samsung_ams367pe02"
+#define LCDC_AUO_SPI_DEVICE_NAME		"lcdc_auo_nt35582"
+#define LCDC_NT35582_PANEL_NAME			"lcdc_nt35582_wvga"
+
+#define MIPI_CMD_NOVATEK_QHD_PANEL_NAME	"mipi_cmd_novatek_qhd"
+#define MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME	"mipi_video_novatek_qhd"
+#define MIPI_VIDEO_TOSHIBA_WVGA_PANEL_NAME	"mipi_video_toshiba_wvga"
+#define HDMI_PANEL_NAME	"hdmi_msm"
+#define TVOUT_PANEL_NAME	"tvout_msm"
+
+#define DSPS_PIL_GENERIC_NAME		"dsps"
+#define DSPS_PIL_FLUID_NAME		"dsps_fluid"
+
+#ifdef CONFIG_ION_MSM
+static struct platform_device ion_dev;
+#endif
+
+enum {
+	GPIO_EXPANDER_IRQ_BASE  = PM8901_IRQ_BASE + NR_PMIC8901_IRQS,
+	GPIO_EXPANDER_GPIO_BASE = PM8901_MPP_BASE + PM8901_MPPS,
+	/* CORE expander */
+	GPIO_CORE_EXPANDER_BASE = GPIO_EXPANDER_GPIO_BASE,
+	GPIO_CLASS_D1_EN        = GPIO_CORE_EXPANDER_BASE,
+	GPIO_WLAN_DEEP_SLEEP_N,
+	GPIO_LVDS_SHUTDOWN_N,
+	GPIO_DISP_RESX_N        = GPIO_LVDS_SHUTDOWN_N,
+	GPIO_MS_SYS_RESET_N,
+	GPIO_CAP_TS_RESOUT_N,
+	GPIO_CAP_GAUGE_BI_TOUT,
+	GPIO_ETHERNET_PME,
+	GPIO_EXT_GPS_LNA_EN,
+	GPIO_MSM_WAKES_BT,
+	GPIO_ETHERNET_RESET_N,
+	GPIO_HEADSET_DET_N,
+	GPIO_USB_UICC_EN,
+	GPIO_BACKLIGHT_EN,
+	GPIO_EXT_CAMIF_PWR_EN,
+	GPIO_BATT_GAUGE_INT_N,
+	GPIO_BATT_GAUGE_EN,
+	/* DOCKING expander */
+	GPIO_DOCKING_EXPANDER_BASE = GPIO_EXPANDER_GPIO_BASE + 16,
+	GPIO_MIPI_DSI_RST_N        = GPIO_DOCKING_EXPANDER_BASE,
+	GPIO_AUX_JTAG_DET_N,
+	GPIO_DONGLE_DET_N,
+	GPIO_SVIDEO_LOAD_DET,
+	GPIO_SVID_AMP_SHUTDOWN1_N,
+	GPIO_SVID_AMP_SHUTDOWN0_N,
+	GPIO_SDC_WP,
+	GPIO_IRDA_PWDN,
+	GPIO_IRDA_RESET_N,
+	GPIO_DONGLE_GPIO0,
+	GPIO_DONGLE_GPIO1,
+	GPIO_DONGLE_GPIO2,
+	GPIO_DONGLE_GPIO3,
+	GPIO_DONGLE_PWR_EN,
+	GPIO_EMMC_RESET_N,
+	GPIO_TP_EXP2_IO15,
+	/* SURF expander */
+	GPIO_SURF_EXPANDER_BASE = GPIO_EXPANDER_GPIO_BASE + (16 * 2),
+	GPIO_SD_CARD_DET_1      = GPIO_SURF_EXPANDER_BASE,
+	GPIO_SD_CARD_DET_2,
+	GPIO_SD_CARD_DET_4,
+	GPIO_SD_CARD_DET_5,
+	GPIO_UIM3_RST,
+	GPIO_SURF_EXPANDER_IO5,
+	GPIO_SURF_EXPANDER_IO6,
+	GPIO_ADC_I2C_EN,
+	GPIO_SURF_EXPANDER_IO8,
+	GPIO_SURF_EXPANDER_IO9,
+	GPIO_SURF_EXPANDER_IO10,
+	GPIO_SURF_EXPANDER_IO11,
+	GPIO_SURF_EXPANDER_IO12,
+	GPIO_SURF_EXPANDER_IO13,
+	GPIO_SURF_EXPANDER_IO14,
+	GPIO_SURF_EXPANDER_IO15,
+	/* LEFT KB IO expander */
+	GPIO_LEFT_KB_EXPANDER_BASE = GPIO_EXPANDER_GPIO_BASE + (16 * 3),
+	GPIO_LEFT_LED_1            = GPIO_LEFT_KB_EXPANDER_BASE,
+	GPIO_LEFT_LED_2,
+	GPIO_LEFT_LED_3,
+	GPIO_LEFT_LED_WLAN,
+	GPIO_JOYSTICK_EN,
+	GPIO_CAP_TS_SLEEP,
+	GPIO_LEFT_KB_IO6,
+	GPIO_LEFT_LED_5,
+	/* RIGHT KB IO expander */
+	GPIO_RIGHT_KB_EXPANDER_BASE = GPIO_EXPANDER_GPIO_BASE + (16 * 3) + 8,
+	GPIO_RIGHT_LED_1            = GPIO_RIGHT_KB_EXPANDER_BASE,
+	GPIO_RIGHT_LED_2,
+	GPIO_RIGHT_LED_3,
+	GPIO_RIGHT_LED_BT,
+	GPIO_WEB_CAMIF_STANDBY,
+	GPIO_COMPASS_RST_N,
+	GPIO_WEB_CAMIF_RESET_N,
+	GPIO_RIGHT_LED_5,
+	GPIO_R_ALTIMETER_RESET_N,
+	/* FLUID S IO expander */
+	GPIO_SOUTH_EXPANDER_BASE,
+	GPIO_MIC2_ANCR_SEL = GPIO_SOUTH_EXPANDER_BASE,
+	GPIO_MIC1_ANCL_SEL,
+	GPIO_HS_MIC4_SEL,
+	GPIO_FML_MIC3_SEL,
+	GPIO_FMR_MIC5_SEL,
+	GPIO_TS_SLEEP,
+	GPIO_HAP_SHIFT_LVL_OE,
+	GPIO_HS_SW_DIR,
+	/* FLUID N IO expander */
+	GPIO_NORTH_EXPANDER_BASE,
+	GPIO_EPM_3_3V_EN = GPIO_NORTH_EXPANDER_BASE,
+	GPIO_EPM_5V_BOOST_EN,
+	GPIO_AUX_CAM_2P7_EN,
+	GPIO_LED_FLASH_EN,
+	GPIO_LED1_GREEN_N,
+	GPIO_LED2_RED_N,
+	GPIO_FRONT_CAM_RESET_N,
+	GPIO_EPM_LVLSFT_EN,
+	GPIO_N_ALTIMETER_RESET_N,
+	/* EPM expander */
+	GPIO_EPM_EXPANDER_BASE,
+	GPIO_PWR_MON_START = GPIO_EPM_EXPANDER_BASE,
+	GPIO_PWR_MON_RESET_N,
+	GPIO_ADC1_PWDN_N,
+	GPIO_ADC2_PWDN_N,
+	GPIO_EPM_EXPANDER_IO4,
+	GPIO_ADC1_MUX_SPI_INT_N_3_3V,
+	GPIO_ADC2_MUX_SPI_INT_N,
+	GPIO_EPM_EXPANDER_IO7,
+	GPIO_PWR_MON_ENABLE,
+	GPIO_EPM_SPI_ADC1_CS_N,
+	GPIO_EPM_SPI_ADC2_CS_N,
+	GPIO_EPM_EXPANDER_IO11,
+	GPIO_EPM_EXPANDER_IO12,
+	GPIO_EPM_EXPANDER_IO13,
+	GPIO_EPM_EXPANDER_IO14,
+	GPIO_EPM_EXPANDER_IO15,
+};
+
+struct pm8xxx_mpp_init_info {
+	unsigned			mpp;
+	struct pm8xxx_mpp_config_data	config;
+};
+
+#define PM8058_MPP_INIT(_mpp, _type, _level, _control) \
+{ \
+	.mpp	= PM8058_MPP_PM_TO_SYS(_mpp), \
+	.config	= { \
+		.type		= PM8XXX_MPP_TYPE_##_type, \
+		.level		= _level, \
+		.control	= PM8XXX_MPP_##_control, \
+	} \
 }
 
+#define PM8901_MPP_INIT(_mpp, _type, _level, _control) \
+{ \
+	.mpp	= PM8901_MPP_PM_TO_SYS(_mpp), \
+	.config	= { \
+		.type		= PM8XXX_MPP_TYPE_##_type, \
+		.level		= _level, \
+		.control	= PM8XXX_MPP_##_control, \
+	} \
+}
+
+/*
+ * The UI_INTx_N lines are pmic gpio lines which connect i2c
+ * gpio expanders to the pm8058.
+ */
+#define UI_INT1_N 25
+#define UI_INT2_N 34
+#define UI_INT3_N 14
+/*
+FM GPIO is GPIO 18 on PMIC 8058.
+As the index starts from 0 in the PMIC driver, and hence 17
+corresponds to GPIO 18 on PMIC 8058.
+*/
+#define FM_GPIO 17
+
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+static void (*sdc2_status_notify_cb)(int card_present, void *dev_id);
+static void *sdc2_status_notify_cb_devid;
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC5_SUPPORT
+static void (*sdc5_status_notify_cb)(int card_present, void *dev_id);
+static void *sdc5_status_notify_cb_devid;
+#endif
+
+static struct msm_spm_platform_data msm_spm_data_v1[] __initdata = {
+	[0] = {
+		.reg_base_addr = MSM_SAW0_BASE,
+
+#ifdef CONFIG_MSM_AVS_HW
+		.reg_init_values[MSM_SPM_REG_SAW_AVS_CTL] = 0x586020FF,
+#endif
+		.reg_init_values[MSM_SPM_REG_SAW_CFG] = 0x0F,
+		.reg_init_values[MSM_SPM_REG_SAW_SPM_CTL] = 0x68,
+		.reg_init_values[MSM_SPM_REG_SAW_SPM_SLP_TMR_DLY] = 0xFFFFFFFF,
+		.reg_init_values[MSM_SPM_REG_SAW_SPM_WAKE_TMR_DLY] = 0xFFFFFFFF,
+
+		.reg_init_values[MSM_SPM_REG_SAW_SLP_CLK_EN] = 0x01,
+		.reg_init_values[MSM_SPM_REG_SAW_SLP_HSFS_PRECLMP_EN] = 0x07,
+		.reg_init_values[MSM_SPM_REG_SAW_SLP_HSFS_POSTCLMP_EN] = 0x00,
+
+		.reg_init_values[MSM_SPM_REG_SAW_SLP_CLMP_EN] = 0x01,
+		.reg_init_values[MSM_SPM_REG_SAW_SLP_RST_EN] = 0x00,
+		.reg_init_values[MSM_SPM_REG_SAW_SPM_MPM_CFG] = 0x00,
+
+		.awake_vlevel = 0x94,
+		.retention_vlevel = 0x81,
+		.collapse_vlevel = 0x20,
+		.retention_mid_vlevel = 0x94,
+		.collapse_mid_vlevel = 0x8C,
+
+		.vctl_timeout_us = 50,
+	},
+
+	[1] = {
+		.reg_base_addr = MSM_SAW1_BASE,
+
+#ifdef CONFIG_MSM_AVS_HW
+		.reg_init_values[MSM_SPM_REG_SAW_AVS_CTL] = 0x586020FF,
+#endif
+		.reg_init_values[MSM_SPM_REG_SAW_CFG] = 0x0F,
+		.reg_init_values[MSM_SPM_REG_SAW_SPM_CTL] = 0x68,
+		.reg_init_values[MSM_SPM_REG_SAW_SPM_SLP_TMR_DLY] = 0xFFFFFFFF,
+		.reg_init_values[MSM_SPM_REG_SAW_SPM_WAKE_TMR_DLY] = 0xFFFFFFFF,
+
+		.reg_init_values[MSM_SPM_REG_SAW_SLP_CLK_EN] = 0x13,
+		.reg_init_values[MSM_SPM_REG_SAW_SLP_HSFS_PRECLMP_EN] = 0x07,
+		.reg_init_values[MSM_SPM_REG_SAW_SLP_HSFS_POSTCLMP_EN] = 0x00,
+
+		.reg_init_values[MSM_SPM_REG_SAW_SLP_CLMP_EN] = 0x01,
+		.reg_init_values[MSM_SPM_REG_SAW_SLP_RST_EN] = 0x00,
+		.reg_init_values[MSM_SPM_REG_SAW_SPM_MPM_CFG] = 0x00,
+
+		.awake_vlevel = 0x94,
+		.retention_vlevel = 0x81,
+		.collapse_vlevel = 0x20,
+		.retention_mid_vlevel = 0x94,
+		.collapse_mid_vlevel = 0x8C,
+
+		.vctl_timeout_us = 50,
+	},
+};
+
+static struct msm_spm_platform_data msm_spm_data[] __initdata = {
+	[0] = {
+		.reg_base_addr = MSM_SAW0_BASE,
+
+#ifdef CONFIG_MSM_AVS_HW
+		.reg_init_values[MSM_SPM_REG_SAW_AVS_CTL] = 0x586020FF,
+#endif
+		.reg_init_values[MSM_SPM_REG_SAW_CFG] = 0x1C,
+		.reg_init_values[MSM_SPM_REG_SAW_SPM_CTL] = 0x68,
+		.reg_init_values[MSM_SPM_REG_SAW_SPM_SLP_TMR_DLY] = 0x0C0CFFFF,
+		.reg_init_values[MSM_SPM_REG_SAW_SPM_WAKE_TMR_DLY] = 0x78780FFF,
+
+		.reg_init_values[MSM_SPM_REG_SAW_SLP_CLK_EN] = 0x01,
+		.reg_init_values[MSM_SPM_REG_SAW_SLP_HSFS_PRECLMP_EN] = 0x07,
+		.reg_init_values[MSM_SPM_REG_SAW_SLP_HSFS_POSTCLMP_EN] = 0x00,
+
+		.reg_init_values[MSM_SPM_REG_SAW_SLP_CLMP_EN] = 0x01,
+		.reg_init_values[MSM_SPM_REG_SAW_SLP_RST_EN] = 0x00,
+		.reg_init_values[MSM_SPM_REG_SAW_SPM_MPM_CFG] = 0x00,
+
+		.awake_vlevel = 0xA0,
+		.retention_vlevel = 0x89,
+		.collapse_vlevel = 0x20,
+		.retention_mid_vlevel = 0x89,
+		.collapse_mid_vlevel = 0x89,
+
+		.vctl_timeout_us = 50,
+	},
+
+	[1] = {
+		.reg_base_addr = MSM_SAW1_BASE,
+
+#ifdef CONFIG_MSM_AVS_HW
+		.reg_init_values[MSM_SPM_REG_SAW_AVS_CTL] = 0x586020FF,
+#endif
+		.reg_init_values[MSM_SPM_REG_SAW_CFG] = 0x1C,
+		.reg_init_values[MSM_SPM_REG_SAW_SPM_CTL] = 0x68,
+		.reg_init_values[MSM_SPM_REG_SAW_SPM_SLP_TMR_DLY] = 0x0C0CFFFF,
+		.reg_init_values[MSM_SPM_REG_SAW_SPM_WAKE_TMR_DLY] = 0x78780FFF,
+
+		.reg_init_values[MSM_SPM_REG_SAW_SLP_CLK_EN] = 0x13,
+		.reg_init_values[MSM_SPM_REG_SAW_SLP_HSFS_PRECLMP_EN] = 0x07,
+		.reg_init_values[MSM_SPM_REG_SAW_SLP_HSFS_POSTCLMP_EN] = 0x00,
+
+		.reg_init_values[MSM_SPM_REG_SAW_SLP_CLMP_EN] = 0x01,
+		.reg_init_values[MSM_SPM_REG_SAW_SLP_RST_EN] = 0x00,
+		.reg_init_values[MSM_SPM_REG_SAW_SPM_MPM_CFG] = 0x00,
+
+		.awake_vlevel = 0xA0,
+		.retention_vlevel = 0x89,
+		.collapse_vlevel = 0x20,
+		.retention_mid_vlevel = 0x89,
+		.collapse_mid_vlevel = 0x89,
+
+		.vctl_timeout_us = 50,
+	},
+};
+
+/*
+ * Consumer specific regulator names:
+ *			 regulator name		consumer dev_name
+ */
+static struct regulator_consumer_supply vreg_consumers_8901_S0[] = {
+	REGULATOR_SUPPLY("8901_s0",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_8901_S1[] = {
+	REGULATOR_SUPPLY("8901_s1",		NULL),
+};
+
+static struct regulator_init_data saw_s0_init_data = {
+		.constraints = {
+			.name = "8901_s0",
+			.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+			.min_uV = 800000,
+			.max_uV = 1325000,
+		},
+		.consumer_supplies = vreg_consumers_8901_S0,
+		.num_consumer_supplies = ARRAY_SIZE(vreg_consumers_8901_S0),
+};
+
+static struct regulator_init_data saw_s1_init_data = {
+		.constraints = {
+			.name = "8901_s1",
+			.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+			.min_uV = 800000,
+			.max_uV = 1325000,
+		},
+		.consumer_supplies = vreg_consumers_8901_S1,
+		.num_consumer_supplies = ARRAY_SIZE(vreg_consumers_8901_S1),
+};
+
+static struct platform_device msm_device_saw_s0 = {
+	.name          = "saw-regulator",
+	.id            = 0,
+	.dev           = {
+		.platform_data = &saw_s0_init_data,
+	},
+};
+
+static struct platform_device msm_device_saw_s1 = {
+	.name          = "saw-regulator",
+	.id            = 1,
+	.dev           = {
+		.platform_data = &saw_s1_init_data,
+	},
+};
+
+/*
+ * The smc91x configuration varies depending on platform.
+ * The resources data structure is filled in at runtime.
+ */
+static struct resource smc91x_resources[] = {
+	[0] = {
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device smc91x_device = {
+	.name          = "smc91x",
+	.id            = 0,
+	.num_resources = ARRAY_SIZE(smc91x_resources),
+	.resource      = smc91x_resources,
+};
+
+static struct resource smsc911x_resources[] = {
+	[0] = {
+		.flags = IORESOURCE_MEM,
+		.start = 0x1b800000,
+		.end   = 0x1b8000ff
+	},
+	[1] = {
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
+	},
+};
+
+static struct smsc911x_platform_config smsc911x_config = {
+	.irq_polarity	= SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+	.irq_type	= SMSC911X_IRQ_TYPE_PUSH_PULL,
+	.flags		= SMSC911X_USE_16BIT,
+	.has_reset_gpio	= 1,
+	.reset_gpio	= GPIO_ETHERNET_RESET_N
+};
+
+static struct platform_device smsc911x_device = {
+	.name          = "smsc911x",
+	.id            = 0,
+	.num_resources = ARRAY_SIZE(smsc911x_resources),
+	.resource      = smsc911x_resources,
+	.dev           = {
+		.platform_data = &smsc911x_config
+	}
+};
+
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+
+#define QCE_SIZE		0x10000
+#define QCE_0_BASE		0x18500000
+
+#define QCE_HW_KEY_SUPPORT	0
+#define QCE_SHA_HMAC_SUPPORT	0
+#define QCE_SHARE_CE_RESOURCE	2
+#define QCE_CE_SHARED		1
+
+static struct resource qcrypto_resources[] = {
+	[0] = {
+		.start = QCE_0_BASE,
+		.end = QCE_0_BASE + QCE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.name = "crypto_channels",
+		.start = DMOV_CE_IN_CHAN,
+		.end = DMOV_CE_OUT_CHAN,
+		.flags = IORESOURCE_DMA,
+	},
+	[2] = {
+		.name = "crypto_crci_in",
+		.start = DMOV_CE_IN_CRCI,
+		.end = DMOV_CE_IN_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+	[3] = {
+		.name = "crypto_crci_out",
+		.start = DMOV_CE_OUT_CRCI,
+		.end = DMOV_CE_OUT_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+	[4] = {
+		.name = "crypto_crci_hash",
+		.start = DMOV_CE_HASH_CRCI,
+		.end = DMOV_CE_HASH_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static struct resource qcedev_resources[] = {
+	[0] = {
+		.start = QCE_0_BASE,
+		.end = QCE_0_BASE + QCE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.name = "crypto_channels",
+		.start = DMOV_CE_IN_CHAN,
+		.end = DMOV_CE_OUT_CHAN,
+		.flags = IORESOURCE_DMA,
+	},
+	[2] = {
+		.name = "crypto_crci_in",
+		.start = DMOV_CE_IN_CRCI,
+		.end = DMOV_CE_IN_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+	[3] = {
+		.name = "crypto_crci_out",
+		.start = DMOV_CE_OUT_CRCI,
+		.end = DMOV_CE_OUT_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+	[4] = {
+		.name = "crypto_crci_hash",
+		.start = DMOV_CE_HASH_CRCI,
+		.end = DMOV_CE_HASH_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
+
+static struct msm_ce_hw_support qcrypto_ce_hw_suppport = {
+	.ce_shared = QCE_CE_SHARED,
+	.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
+	.hw_key_support = QCE_HW_KEY_SUPPORT,
+	.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+	.bus_scale_table = NULL,
+};
+
+static struct platform_device qcrypto_device = {
+	.name		= "qcrypto",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(qcrypto_resources),
+	.resource	= qcrypto_resources,
+	.dev		= {
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+		.platform_data = &qcrypto_ce_hw_suppport,
+	},
+};
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+
+static struct msm_ce_hw_support qcedev_ce_hw_suppport = {
+	.ce_shared = QCE_CE_SHARED,
+	.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
+	.hw_key_support = QCE_HW_KEY_SUPPORT,
+	.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+	.bus_scale_table = NULL,
+};
+
+static struct platform_device qcedev_device = {
+	.name		= "qce",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(qcedev_resources),
+	.resource	= qcedev_resources,
+	.dev		= {
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+		.platform_data = &qcedev_ce_hw_suppport,
+	},
+};
+#endif
+
+#if defined(CONFIG_HAPTIC_ISA1200) || \
+		defined(CONFIG_HAPTIC_ISA1200_MODULE)
+
+static const char *vregs_isa1200_name[] = {
+	"8058_s3",
+	"8901_l4",
+};
+
+static const int vregs_isa1200_val[] = {
+	1800000,/* uV */
+	2600000,
+};
+static struct regulator *vregs_isa1200[ARRAY_SIZE(vregs_isa1200_name)];
+static struct msm_xo_voter *xo_handle_a1;
+
+static int isa1200_power(int vreg_on)
+{
+	int i, rc = 0;
+
+	for (i = 0; i < ARRAY_SIZE(vregs_isa1200_name); i++) {
+		rc = vreg_on ? regulator_enable(vregs_isa1200[i]) :
+			regulator_disable(vregs_isa1200[i]);
+		if (rc < 0) {
+			pr_err("%s: vreg %s %s failed (%d)\n",
+				__func__, vregs_isa1200_name[i],
+				vreg_on ? "enable" : "disable", rc);
+			goto vreg_fail;
+		}
+	}
+
+	rc = vreg_on ? msm_xo_mode_vote(xo_handle_a1, MSM_XO_MODE_ON) :
+			msm_xo_mode_vote(xo_handle_a1, MSM_XO_MODE_OFF);
+	if (rc < 0) {
+		pr_err("%s: failed to %svote for TCXO A1 buffer%d\n",
+				__func__, vreg_on ? "" : "de-", rc);
+		goto vreg_fail;
+	}
+	return 0;
+
+vreg_fail:
+	while (i--)
+		!vreg_on ? regulator_enable(vregs_isa1200[i]) :
+			regulator_disable(vregs_isa1200[i]);
+	return rc;
+}
+
+static int isa1200_dev_setup(bool enable)
+{
+	int i, rc;
+
+	if (enable == true) {
+		for (i = 0; i < ARRAY_SIZE(vregs_isa1200_name); i++) {
+			vregs_isa1200[i] = regulator_get(NULL,
+						vregs_isa1200_name[i]);
+			if (IS_ERR(vregs_isa1200[i])) {
+				pr_err("%s: regulator get of %s failed (%ld)\n",
+					__func__, vregs_isa1200_name[i],
+					PTR_ERR(vregs_isa1200[i]));
+				rc = PTR_ERR(vregs_isa1200[i]);
+				goto vreg_get_fail;
+			}
+			rc = regulator_set_voltage(vregs_isa1200[i],
+				vregs_isa1200_val[i], vregs_isa1200_val[i]);
+			if (rc) {
+				pr_err("%s: regulator_set_voltage(%s) failed\n",
+					__func__, vregs_isa1200_name[i]);
+				goto vreg_get_fail;
+			}
+		}
+
+		rc = gpio_request(GPIO_HAP_SHIFT_LVL_OE, "haptics_shft_lvl_oe");
+		if (rc) {
+			pr_err("%s: unable to request gpio %d (%d)\n",
+					__func__, GPIO_HAP_SHIFT_LVL_OE, rc);
+			goto vreg_get_fail;
+		}
+
+		rc = gpio_direction_output(GPIO_HAP_SHIFT_LVL_OE, 1);
+		if (rc) {
+			pr_err("%s: Unable to set direction\n", __func__);;
+			goto free_gpio;
+		}
+
+		xo_handle_a1 = msm_xo_get(MSM_XO_TCXO_A1, "isa1200");
+		if (IS_ERR(xo_handle_a1)) {
+			rc = PTR_ERR(xo_handle_a1);
+			pr_err("%s: failed to get the handle for A1(%d)\n",
+							__func__, rc);
+			goto gpio_set_dir;
+		}
+	} else {
+		gpio_set_value(GPIO_HAP_SHIFT_LVL_OE, 0);
+		gpio_free(GPIO_HAP_SHIFT_LVL_OE);
+
+		for (i = 0; i < ARRAY_SIZE(vregs_isa1200_name); i++)
+			regulator_put(vregs_isa1200[i]);
+
+		msm_xo_put(xo_handle_a1);
+	}
+
+	return 0;
+gpio_set_dir:
+	gpio_set_value(GPIO_HAP_SHIFT_LVL_OE, 0);
+free_gpio:
+	gpio_free(GPIO_HAP_SHIFT_LVL_OE);
+vreg_get_fail:
+	while (i)
+		regulator_put(vregs_isa1200[--i]);
+	return rc;
+}
+
+#define PMIC_GPIO_HAP_ENABLE   18  /* PMIC GPIO Number 19 */
+#define PMIC_GPIO_HAP_LDO_ENABLE   5  /* PMIC GPIO Number 6 */
+static struct isa1200_platform_data isa1200_1_pdata = {
+	.name = "vibrator",
+	.power_on = isa1200_power,
+	.dev_setup = isa1200_dev_setup,
+	/*gpio to enable haptic*/
+	.hap_en_gpio = PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_HAP_ENABLE),
+	.hap_len_gpio = PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_HAP_LDO_ENABLE),
+	.max_timeout = 15000,
+	.mode_ctrl = PWM_GEN_MODE,
+	.pwm_fd = {
+		.pwm_div = 256,
+	},
+	.is_erm = false,
+	.smart_en = true,
+	.ext_clk_en = true,
+	.chip_en = 1,
+};
+
+static struct i2c_board_info msm_isa1200_board_info[] = {
+	{
+		I2C_BOARD_INFO("isa1200_1", 0x90>>1),
+		.platform_data = &isa1200_1_pdata,
+	},
+};
+#endif
+
+#if defined(CONFIG_BATTERY_BQ27520) || \
+		defined(CONFIG_BATTERY_BQ27520_MODULE)
+static struct bq27520_platform_data bq27520_pdata = {
+	.name		= "fuel-gauge",
+	.vreg_name	= "8058_s3",
+	.vreg_value	= 1800000,
+	.soc_int	= GPIO_BATT_GAUGE_INT_N,
+	.bi_tout	= GPIO_CAP_GAUGE_BI_TOUT,
+	.chip_en	= GPIO_BATT_GAUGE_EN,
+	.enable_dlog	= 0, /* if enable coulomb counter logger */
+};
+
+static struct i2c_board_info msm_bq27520_board_info[] = {
+	{
+		I2C_BOARD_INFO("bq27520", 0xaa>>1),
+		.platform_data = &bq27520_pdata,
+	},
+};
+#endif
+
+static struct msm_rpmrs_level msm_rpmrs_levels[] __initdata = {
+	{
+		MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT,
+		MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
+		true,
+		1, 8000, 100000, 1,
+	},
+
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
+		MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
+		true,
+		1500, 5000, 60100000, 3000,
+	},
+
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+		MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
+		false,
+		1800, 5000, 60350000, 3500,
+	},
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+		MSM_RPMRS_LIMITS(OFF, ACTIVE, MAX, ACTIVE),
+		false,
+		3800, 4500, 65350000, 5500,
+	},
+
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+		MSM_RPMRS_LIMITS(ON, HSFS_OPEN, MAX, ACTIVE),
+		false,
+		2800, 2500, 66850000, 4800,
+	},
+
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, MAX, ACTIVE),
+		false,
+		4800, 2000, 71850000, 6800,
+	},
+
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, ACTIVE, RET_HIGH),
+		false,
+		6800, 500, 75850000, 8800,
+	},
+
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, RET_HIGH, RET_LOW),
+		false,
+		7800, 0, 76350000, 9800,
+	},
+};
+
+static struct msm_rpmrs_platform_data msm_rpmrs_data __initdata = {
+	.levels = &msm_rpmrs_levels[0],
+	.num_levels = ARRAY_SIZE(msm_rpmrs_levels),
+	.vdd_mem_levels  = {
+		[MSM_RPMRS_VDD_MEM_RET_LOW]     = 500,
+		[MSM_RPMRS_VDD_MEM_RET_HIGH]    = 750,
+		[MSM_RPMRS_VDD_MEM_ACTIVE]      = 1000,
+		[MSM_RPMRS_VDD_MEM_MAX]         = 1325,
+	},
+	.vdd_dig_levels = {
+		[MSM_RPMRS_VDD_DIG_RET_LOW]     = 500,
+		[MSM_RPMRS_VDD_DIG_RET_HIGH]    = 750,
+		[MSM_RPMRS_VDD_DIG_ACTIVE]      = 1000,
+		[MSM_RPMRS_VDD_DIG_MAX]         = 1250,
+	},
+	.vdd_mask = 0xFFF,
+	.rpmrs_target_id = {
+		[MSM_RPMRS_ID_PXO_CLK]          = MSM_RPM_ID_PXO_CLK,
+		[MSM_RPMRS_ID_L2_CACHE_CTL]     = MSM_RPM_ID_APPS_L2_CACHE_CTL,
+		[MSM_RPMRS_ID_VDD_DIG_0]        = MSM_RPM_ID_SMPS1_0,
+		[MSM_RPMRS_ID_VDD_DIG_1]        = MSM_RPM_ID_SMPS1_1,
+		[MSM_RPMRS_ID_VDD_MEM_0]        = MSM_RPM_ID_SMPS0_0,
+		[MSM_RPMRS_ID_VDD_MEM_1]        = MSM_RPM_ID_SMPS0_1,
+		[MSM_RPMRS_ID_RPM_CTL]          = MSM_RPM_ID_TRIGGER_SET_FROM,
+	},
+};
+
+static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_TZ,
+};
+
+#if defined(CONFIG_USB_PEHCI_HCD) || defined(CONFIG_USB_PEHCI_HCD_MODULE)
+
+#define ISP1763_INT_GPIO		117
+#define ISP1763_RST_GPIO		152
+static struct resource isp1763_resources[] = {
+	[0] = {
+		.flags	= IORESOURCE_MEM,
+		.start	= 0x1D000000,
+		.end	= 0x1D005FFF,		/* 24KB */
+	},
+	[1] = {
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+static void __init msm8x60_cfg_isp1763(void)
+{
+	isp1763_resources[1].start = gpio_to_irq(ISP1763_INT_GPIO);
+	isp1763_resources[1].end = gpio_to_irq(ISP1763_INT_GPIO);
+}
+
+static int isp1763_setup_gpio(int enable)
+{
+	int status = 0;
+
+	if (enable) {
+		status = gpio_request(ISP1763_INT_GPIO, "isp1763_usb");
+		if (status) {
+			pr_err("%s:Failed to request GPIO %d\n",
+						__func__, ISP1763_INT_GPIO);
+			return status;
+		}
+		status = gpio_direction_input(ISP1763_INT_GPIO);
+		if (status) {
+			pr_err("%s:Failed to configure GPIO %d\n",
+					__func__, ISP1763_INT_GPIO);
+			goto gpio_free_int;
+		}
+		status = gpio_request(ISP1763_RST_GPIO, "isp1763_usb");
+		if (status) {
+			pr_err("%s:Failed to request GPIO %d\n",
+						__func__, ISP1763_RST_GPIO);
+			goto gpio_free_int;
+		}
+		status = gpio_direction_output(ISP1763_RST_GPIO, 1);
+		if (status) {
+			pr_err("%s:Failed to configure GPIO %d\n",
+					__func__, ISP1763_RST_GPIO);
+			goto gpio_free_rst;
+		}
+		pr_debug("\nISP GPIO configuration done\n");
+		return status;
+	}
+
+gpio_free_rst:
+	gpio_free(ISP1763_RST_GPIO);
+gpio_free_int:
+	gpio_free(ISP1763_INT_GPIO);
+
+	return status;
+}
+static struct isp1763_platform_data isp1763_pdata = {
+	.reset_gpio	= ISP1763_RST_GPIO,
+	.setup_gpio	= isp1763_setup_gpio
+};
+
+static struct platform_device isp1763_device = {
+	.name          = "isp1763_usb",
+	.num_resources = ARRAY_SIZE(isp1763_resources),
+	.resource      = isp1763_resources,
+	.dev           = {
+		.platform_data = &isp1763_pdata
+	}
+};
+#endif
+
+#if defined(CONFIG_USB_MSM_72K) || defined(CONFIG_USB_EHCI_MSM_72K)
+static struct msm_otg_platform_data msm_otg_pdata;
+static struct regulator *ldo6_3p3;
+static struct regulator *ldo7_1p8;
+static struct regulator *vdd_cx;
+#define PMICID_INT		PM8058_GPIO_IRQ(PM8058_IRQ_BASE, 36)
+#define PMIC_ID_GPIO		36
+notify_vbus_state notify_vbus_state_func_ptr;
+static int usb_phy_susp_dig_vol = 750000;
+static int pmic_id_notif_supported;
+
+#ifdef CONFIG_USB_EHCI_MSM_72K
+#define USB_PMIC_ID_DET_DELAY	msecs_to_jiffies(100)
+struct delayed_work pmic_id_det;
+
+static int __init usb_id_pin_rework_setup(char *support)
+{
+	if (strncmp(support, "true", 4) == 0)
+		pmic_id_notif_supported = 1;
+
+	return 1;
+}
+__setup("usb_id_pin_rework=", usb_id_pin_rework_setup);
+
+static void pmic_id_detect(struct work_struct *w)
+{
+	int val = gpio_get_value_cansleep(PM8058_GPIO_PM_TO_SYS(36));
+	pr_debug("%s(): gpio_read_value = %d\n", __func__, val);
+
+	if (notify_vbus_state_func_ptr)
+		(*notify_vbus_state_func_ptr) (val);
+}
+
+static irqreturn_t pmic_id_on_irq(int irq, void *data)
+{
+	/*
+	 * Spurious interrupts are observed on pmic gpio line
+	 * even though there is no state change on USB ID. Schedule the
+	 * work to to allow debounce on gpio
+	 */
+	schedule_delayed_work(&pmic_id_det, USB_PMIC_ID_DET_DELAY);
+
+	return IRQ_HANDLED;
+}
+
+static int msm_hsusb_phy_id_setup_init(int init)
+{
+	unsigned ret;
+
+	struct pm8xxx_mpp_config_data hsusb_phy_mpp = {
+		.type	= PM8XXX_MPP_TYPE_D_OUTPUT,
+		.level	= PM8901_MPP_DIG_LEVEL_L5,
+	};
+
+	if (init) {
+		hsusb_phy_mpp.control = PM8XXX_MPP_DOUT_CTRL_HIGH;
+		ret = pm8xxx_mpp_config(PM8901_MPP_PM_TO_SYS(1),
+							&hsusb_phy_mpp);
+		if (ret < 0)
+			pr_err("%s:MPP2 configuration failed\n", __func__);
+	} else {
+		hsusb_phy_mpp.control = PM8XXX_MPP_DOUT_CTRL_LOW;
+		ret = pm8xxx_mpp_config(PM8901_MPP_PM_TO_SYS(1),
+							&hsusb_phy_mpp);
+		if (ret < 0)
+			pr_err("%s:MPP2 un config failed\n", __func__);
+	}
+	return ret;
+}
+
+static int msm_hsusb_pmic_id_notif_init(void (*callback)(int online), int init)
+{
+	unsigned ret = -ENODEV;
+
+	struct pm_gpio pmic_id_cfg = {
+		.direction	= PM_GPIO_DIR_IN,
+		.pull		= PM_GPIO_PULL_UP_1P5,
+		.function	= PM_GPIO_FUNC_NORMAL,
+		.vin_sel	= 2,
+		.inv_int_pol	= 0,
+	};
+	struct pm_gpio pmic_id_uncfg = {
+		.direction	= PM_GPIO_DIR_IN,
+		.pull		= PM_GPIO_PULL_NO,
+		.function	= PM_GPIO_FUNC_NORMAL,
+		.vin_sel	= 2,
+		.inv_int_pol	= 0,
+	};
+	if (!callback)
+		return -EINVAL;
+
+	if (machine_is_msm8x60_fluid())
+		return -ENOTSUPP;
+
+	if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) != 2) {
+		pr_debug("%s: USB_ID pin is not routed to PMIC"
+					"on V1 surf/ffa\n", __func__);
+		return -ENOTSUPP;
+	}
+
+	if ((machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa() ||
+			machine_is_msm8x60_ffa()) && !pmic_id_notif_supported) {
+		pr_debug("%s: USB_ID is not routed to PMIC"
+			"on V2 ffa\n", __func__);
+		return -ENOTSUPP;
+	}
+
+	usb_phy_susp_dig_vol = 500000;
+
+	if (init) {
+		notify_vbus_state_func_ptr = callback;
+		INIT_DELAYED_WORK(&pmic_id_det, pmic_id_detect);
+		ret = pm8xxx_gpio_config(PM8058_GPIO_PM_TO_SYS(PMIC_ID_GPIO),
+							&pmic_id_cfg);
+		if (ret) {
+			pr_err("%s:return val of pm8xxx_gpio_config: %d\n",
+						__func__,  ret);
+			return ret;
+		}
+		ret = request_threaded_irq(PMICID_INT, NULL, pmic_id_on_irq,
+			(IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING),
+						"msm_otg_id", NULL);
+		if (ret) {
+			pr_err("%s:pmic_usb_id interrupt registration failed",
+					__func__);
+			return ret;
+		}
+		msm_otg_pdata.pmic_id_irq = PMICID_INT;
+	} else {
+		usb_phy_susp_dig_vol = 750000;
+		free_irq(PMICID_INT, 0);
+		ret = pm8xxx_gpio_config(PM8058_GPIO_PM_TO_SYS(PMIC_ID_GPIO),
+							&pmic_id_uncfg);
+		if (ret) {
+			pr_err("%s: return val of pm8xxx_gpio_config: %d\n",
+						__func__,  ret);
+			return ret;
+		}
+		msm_otg_pdata.pmic_id_irq = 0;
+		cancel_delayed_work_sync(&pmic_id_det);
+		notify_vbus_state_func_ptr = NULL;
+	}
+	return 0;
+}
+#endif
+
+#define USB_PHY_OPERATIONAL_MIN_VDD_DIG_VOL	1000000
+#define USB_PHY_MAX_VDD_DIG_VOL			1320000
+static int msm_hsusb_init_vddcx(int init)
+{
+	int ret = 0;
+
+	if (init) {
+		vdd_cx = regulator_get(NULL, "8058_s1");
+		if (IS_ERR(vdd_cx)) {
+			return PTR_ERR(vdd_cx);
+		}
+
+		ret = regulator_set_voltage(vdd_cx,
+				USB_PHY_OPERATIONAL_MIN_VDD_DIG_VOL,
+				USB_PHY_MAX_VDD_DIG_VOL);
+		if (ret) {
+			pr_err("%s: unable to set the voltage for regulator"
+				"vdd_cx\n", __func__);
+			regulator_put(vdd_cx);
+			return ret;
+		}
+
+		ret = regulator_enable(vdd_cx);
+		if (ret) {
+			pr_err("%s: unable to enable regulator"
+				"vdd_cx\n", __func__);
+			regulator_put(vdd_cx);
+		}
+	} else {
+		ret = regulator_disable(vdd_cx);
+		if (ret) {
+			pr_err("%s: Unable to disable the regulator:"
+				"vdd_cx\n", __func__);
+			return ret;
+		}
+
+		regulator_put(vdd_cx);
+	}
+
+	return ret;
+}
+
+static int msm_hsusb_config_vddcx(int high)
+{
+	int max_vol = USB_PHY_MAX_VDD_DIG_VOL;
+	int min_vol;
+	int ret;
+
+	if (high)
+		min_vol = USB_PHY_OPERATIONAL_MIN_VDD_DIG_VOL;
+	else
+		min_vol = usb_phy_susp_dig_vol;
+
+	ret = regulator_set_voltage(vdd_cx, min_vol, max_vol);
+	if (ret) {
+		pr_err("%s: unable to set the voltage for regulator"
+			"vdd_cx\n", __func__);
+		return ret;
+	}
+
+	pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol);
+
+	return ret;
+}
+
+#define USB_PHY_3P3_VOL_MIN	3050000 /* uV */
+#define USB_PHY_3P3_VOL_MAX	3050000 /* uV */
+#define USB_PHY_3P3_HPM_LOAD	50000	/* uA */
+#define USB_PHY_3P3_LPM_LOAD	4000	/* uA */
+
+#define USB_PHY_1P8_VOL_MIN	1800000 /* uV */
+#define USB_PHY_1P8_VOL_MAX	1800000 /* uV */
+#define USB_PHY_1P8_HPM_LOAD	50000	/* uA */
+#define USB_PHY_1P8_LPM_LOAD	4000	/* uA */
+static int msm_hsusb_ldo_init(int init)
+{
+	int rc = 0;
+
+	if (init) {
+		ldo6_3p3 = regulator_get(NULL, "8058_l6");
+		if (IS_ERR(ldo6_3p3))
+			return PTR_ERR(ldo6_3p3);
+
+		ldo7_1p8 = regulator_get(NULL, "8058_l7");
+		if (IS_ERR(ldo7_1p8)) {
+			rc = PTR_ERR(ldo7_1p8);
+			goto put_3p3;
+		}
+
+		rc = regulator_set_voltage(ldo6_3p3, USB_PHY_3P3_VOL_MIN,
+				USB_PHY_3P3_VOL_MAX);
+		if (rc) {
+			pr_err("%s: Unable to set voltage level for"
+				"ldo6_3p3 regulator\n", __func__);
+			goto put_1p8;
+		}
+		rc = regulator_enable(ldo6_3p3);
+		if (rc) {
+			pr_err("%s: Unable to enable the regulator:"
+				"ldo6_3p3\n", __func__);
+			goto put_1p8;
+		}
+		rc = regulator_set_voltage(ldo7_1p8, USB_PHY_1P8_VOL_MIN,
+				USB_PHY_1P8_VOL_MAX);
+		if (rc) {
+			pr_err("%s: Unable to set voltage level for"
+				"ldo7_1p8 regulator\n", __func__);
+			goto disable_3p3;
+		}
+		rc = regulator_enable(ldo7_1p8);
+		if (rc) {
+			pr_err("%s: Unable to enable the regulator:"
+				"ldo7_1p8\n", __func__);
+			goto disable_3p3;
+		}
+
+		return 0;
+	}
+
+	regulator_disable(ldo7_1p8);
+disable_3p3:
+	regulator_disable(ldo6_3p3);
+put_1p8:
+	regulator_put(ldo7_1p8);
+put_3p3:
+	regulator_put(ldo6_3p3);
+	return rc;
+}
+
+static int msm_hsusb_ldo_enable(int on)
+{
+	int ret = 0;
+
+	if (!ldo7_1p8 || IS_ERR(ldo7_1p8)) {
+		pr_err("%s: ldo7_1p8 is not initialized\n", __func__);
+		return -ENODEV;
+	}
+
+	if (!ldo6_3p3 || IS_ERR(ldo6_3p3)) {
+		pr_err("%s: ldo6_3p3 is not initialized\n", __func__);
+		return -ENODEV;
+	}
+
+	if (on) {
+		ret = regulator_set_optimum_mode(ldo7_1p8,
+				USB_PHY_1P8_HPM_LOAD);
+		if (ret < 0) {
+			pr_err("%s: Unable to set HPM of the regulator:"
+				"ldo7_1p8\n", __func__);
+			return ret;
+		}
+		ret = regulator_set_optimum_mode(ldo6_3p3,
+				USB_PHY_3P3_HPM_LOAD);
+		if (ret < 0) {
+			pr_err("%s: Unable to set HPM of the regulator:"
+				"ldo6_3p3\n", __func__);
+			regulator_set_optimum_mode(ldo7_1p8,
+				USB_PHY_1P8_LPM_LOAD);
+			return ret;
+		}
+	} else {
+		ret = regulator_set_optimum_mode(ldo7_1p8,
+				USB_PHY_1P8_LPM_LOAD);
+		if (ret < 0)
+			pr_err("%s: Unable to set LPM of the regulator:"
+				"ldo7_1p8\n", __func__);
+		ret = regulator_set_optimum_mode(ldo6_3p3,
+				USB_PHY_3P3_LPM_LOAD);
+		if (ret < 0)
+			pr_err("%s: Unable to set LPM of the regulator:"
+				"ldo6_3p3\n", __func__);
+	}
+
+	pr_debug("reg (%s)\n", on ? "HPM" : "LPM");
+	return ret < 0 ? ret : 0;
+ }
+#endif
+#ifdef CONFIG_USB_EHCI_MSM_72K
+#if defined(CONFIG_SMB137B_CHARGER) || defined(CONFIG_SMB137B_CHARGER_MODULE)
+static void msm_hsusb_smb137b_vbus_power(unsigned phy_info, int on)
+{
+	static int vbus_is_on;
+
+	/* If VBUS is already on (or off), do nothing. */
+	if (on == vbus_is_on)
+		return;
+	smb137b_otg_power(on);
+	vbus_is_on = on;
+}
+#endif
+static void msm_hsusb_vbus_power(unsigned phy_info, int on)
+{
+	static struct regulator *votg_5v_switch;
+	static struct regulator *ext_5v_reg;
+	static int vbus_is_on;
+
+	/* If VBUS is already on (or off), do nothing. */
+	if (on == vbus_is_on)
+		return;
+
+	if (!votg_5v_switch) {
+		votg_5v_switch = regulator_get(NULL, "8901_usb_otg");
+		if (IS_ERR(votg_5v_switch)) {
+			pr_err("%s: unable to get votg_5v_switch\n", __func__);
+			return;
+		}
+	}
+	if (!ext_5v_reg) {
+		ext_5v_reg = regulator_get(NULL, "8901_mpp0");
+		if (IS_ERR(ext_5v_reg)) {
+			pr_err("%s: unable to get ext_5v_reg\n", __func__);
+			return;
+		}
+	}
+	if (on) {
+		if (regulator_enable(ext_5v_reg)) {
+			pr_err("%s: Unable to enable the regulator:"
+					" ext_5v_reg\n", __func__);
+			return;
+		}
+		if (regulator_enable(votg_5v_switch)) {
+			pr_err("%s: Unable to enable the regulator:"
+					" votg_5v_switch\n", __func__);
+			return;
+		}
+	} else {
+		if (regulator_disable(votg_5v_switch))
+			pr_err("%s: Unable to enable the regulator:"
+				" votg_5v_switch\n", __func__);
+		if (regulator_disable(ext_5v_reg))
+			pr_err("%s: Unable to enable the regulator:"
+				" ext_5v_reg\n", __func__);
+	}
+
+	vbus_is_on = on;
+}
+
+static struct msm_usb_host_platform_data msm_usb_host_pdata = {
+	.phy_info	= (USB_PHY_INTEGRATED | USB_PHY_MODEL_45NM),
+	.power_budget	= 390,
+};
+#endif
+
+#ifdef CONFIG_BATTERY_MSM8X60
+static int msm_hsusb_pmic_vbus_notif_init(void (*callback)(int online),
+								int init)
+{
+	int ret = -ENOTSUPP;
+
+#if defined(CONFIG_SMB137B_CHARGER) || defined(CONFIG_SMB137B_CHARGER_MODULE)
+	if (machine_is_msm8x60_fluid()) {
+		if (init)
+			msm_charger_register_vbus_sn(callback);
+		else
+			msm_charger_unregister_vbus_sn(callback);
+		return  0;
+	}
+#endif
+	/* ID and VBUS lines are connected to pmic on 8660.V2.SURF,
+	 * hence, irrespective of either peripheral only mode or
+	 * OTG (host and peripheral) modes, can depend on pmic for
+	 * vbus notifications
+	 */
+	if ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2)
+			&& (machine_is_msm8x60_surf() ||
+				pmic_id_notif_supported)) {
+		if (init)
+			ret = msm_charger_register_vbus_sn(callback);
+		else {
+			msm_charger_unregister_vbus_sn(callback);
+			ret = 0;
+		}
+	} else {
+#if !defined(CONFIG_USB_EHCI_MSM_72K)
+	if (init)
+		ret = msm_charger_register_vbus_sn(callback);
+	else {
+		msm_charger_unregister_vbus_sn(callback);
+		ret = 0;
+	}
+#endif
+	}
+	return ret;
+}
+#endif
+
+#if defined(CONFIG_USB_MSM_72K) || defined(CONFIG_USB_EHCI_MSM_72K)
+static struct msm_otg_platform_data msm_otg_pdata = {
+	/* if usb link is in sps there is no need for
+	 * usb pclk as dayatona fabric clock will be
+	 * used instead
+	 */
+	.pemp_level		 = PRE_EMPHASIS_WITH_20_PERCENT,
+	.cdr_autoreset		 = CDR_AUTO_RESET_DISABLE,
+	.se1_gating		 = SE1_GATING_DISABLE,
+	.bam_disable		 = 1,
+#ifdef CONFIG_USB_EHCI_MSM_72K
+	.pmic_id_notif_init = msm_hsusb_pmic_id_notif_init,
+	.phy_id_setup_init = msm_hsusb_phy_id_setup_init,
+#endif
+#ifdef CONFIG_USB_EHCI_MSM_72K
+	.vbus_power = msm_hsusb_vbus_power,
+#endif
+#ifdef CONFIG_BATTERY_MSM8X60
+	.pmic_vbus_notif_init	= msm_hsusb_pmic_vbus_notif_init,
+#endif
+	.ldo_init		 = msm_hsusb_ldo_init,
+	.ldo_enable		 = msm_hsusb_ldo_enable,
+	.config_vddcx            = msm_hsusb_config_vddcx,
+	.init_vddcx              = msm_hsusb_init_vddcx,
+#ifdef CONFIG_BATTERY_MSM8X60
+	.chg_vbus_draw = msm_charger_vbus_draw,
+#endif
+};
+#endif
+
+#ifdef CONFIG_USB_MSM_72K
+static struct msm_hsusb_gadget_platform_data msm_gadget_pdata = {
+	.is_phy_status_timer_on = 1,
+};
+#endif
+
+#ifdef CONFIG_USB_G_ANDROID
+
+#define PID_MAGIC_ID		0x71432909
+#define SERIAL_NUM_MAGIC_ID	0x61945374
+#define SERIAL_NUMBER_LENGTH	127
+#define DLOAD_USB_BASE_ADD	0x2A05F0C8
+
+struct magic_num_struct {
+	uint32_t pid;
+	uint32_t serial_num;
+};
+
+struct dload_struct {
+	uint32_t	reserved1;
+	uint32_t	reserved2;
+	uint32_t	reserved3;
+	uint16_t	reserved4;
+	uint16_t	pid;
+	char		serial_number[SERIAL_NUMBER_LENGTH];
+	uint16_t	reserved5;
+	struct magic_num_struct
+			magic_struct;
+};
+
+static int usb_diag_update_pid_and_serial_num(uint32_t pid, const char *snum)
+{
+	struct dload_struct __iomem *dload = 0;
+
+	dload = ioremap(DLOAD_USB_BASE_ADD, sizeof(*dload));
+	if (!dload) {
+		pr_err("%s: cannot remap I/O memory region: %08x\n",
+					__func__, DLOAD_USB_BASE_ADD);
+		return -ENXIO;
+	}
+
+	pr_debug("%s: dload:%p pid:%x serial_num:%s\n",
+				__func__, dload, pid, snum);
+	/* update pid */
+	dload->magic_struct.pid = PID_MAGIC_ID;
+	dload->pid = pid;
+
+	/* update serial number */
+	dload->magic_struct.serial_num = 0;
+	if (!snum)
+		return 0;
+
+	dload->magic_struct.serial_num = SERIAL_NUM_MAGIC_ID;
+	strncpy(dload->serial_number, snum, SERIAL_NUMBER_LENGTH);
+	dload->serial_number[SERIAL_NUMBER_LENGTH - 1] = '\0';
+
+	iounmap(dload);
+
+	return 0;
+}
+
+static struct android_usb_platform_data android_usb_pdata = {
+	.update_pid_and_serial_num = usb_diag_update_pid_and_serial_num,
+};
+
+static struct platform_device android_usb_device = {
+	.name	= "android_usb",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &android_usb_pdata,
+	},
+};
+
+
+#endif
+
+#ifdef CONFIG_MSM_VPE
+#ifndef CONFIG_MSM_CAMERA_V4L2
+static struct resource msm_vpe_resources[] = {
+	{
+		.start	= 0x05300000,
+		.end	= 0x05300000 + SZ_1M - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_VPE,
+		.end	= INT_VPE,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device msm_vpe_device = {
+	.name = "msm_vpe",
+	.id   = 0,
+	.num_resources = ARRAY_SIZE(msm_vpe_resources),
+	.resource = msm_vpe_resources,
+};
+#endif
+#endif
+
+#ifdef CONFIG_MSM_CAMERA
+#ifndef CONFIG_MSM_CAMERA_V4L2
+#ifdef CONFIG_MSM_CAMERA_FLASH
+#define VFE_CAMIF_TIMER1_GPIO 29
+#define VFE_CAMIF_TIMER2_GPIO 30
+#define VFE_CAMIF_TIMER3_GPIO_INT 31
+#define FUSION_VFE_CAMIF_TIMER1_GPIO 42
+static struct msm_camera_sensor_flash_src msm_flash_src = {
+	.flash_sr_type = MSM_CAMERA_FLASH_SRC_PMIC,
+	._fsrc.pmic_src.num_of_src = 2,
+	._fsrc.pmic_src.low_current  = 100,
+	._fsrc.pmic_src.high_current = 300,
+	._fsrc.pmic_src.led_src_1 = PMIC8058_ID_FLASH_LED_0,
+	._fsrc.pmic_src.led_src_2 = PMIC8058_ID_FLASH_LED_1,
+	._fsrc.pmic_src.pmic_set_current = pm8058_set_flash_led_current,
+};
+#ifdef CONFIG_IMX074
+static struct msm_camera_sensor_strobe_flash_data strobe_flash_xenon = {
+	.flash_trigger = VFE_CAMIF_TIMER2_GPIO,
+	.flash_charge = VFE_CAMIF_TIMER1_GPIO,
+	.flash_charge_done = VFE_CAMIF_TIMER3_GPIO_INT,
+	.flash_recharge_duration = 50000,
+	.irq = MSM_GPIO_TO_INT(VFE_CAMIF_TIMER3_GPIO_INT),
+};
+#endif
+#endif
+
+int msm_cam_gpio_tbl[] = {
+	32,/*CAMIF_MCLK*/
+	47,/*CAMIF_I2C_DATA*/
+	48,/*CAMIF_I2C_CLK*/
+	105,/*STANDBY*/
+};
+
+enum msm_cam_stat{
+	MSM_CAM_OFF,
+	MSM_CAM_ON,
+};
+
+static int config_gpio_table(enum msm_cam_stat stat)
+{
+	int rc = 0, i = 0;
+	if (stat == MSM_CAM_ON) {
+		for (i = 0; i < ARRAY_SIZE(msm_cam_gpio_tbl); i++) {
+			rc = gpio_request(msm_cam_gpio_tbl[i], "CAM_GPIO");
+			if (unlikely(rc < 0)) {
+				pr_err("%s not able to get gpio\n", __func__);
+				for (i--; i >= 0; i--)
+					gpio_free(msm_cam_gpio_tbl[i]);
+				break;
+			}
+		}
+	} else {
+		for (i = 0; i < ARRAY_SIZE(msm_cam_gpio_tbl); i++)
+			gpio_free(msm_cam_gpio_tbl[i]);
+	}
+	return rc;
+}
+
+static struct msm_camera_sensor_platform_info sensor_board_info = {
+	.mount_angle = 0
+};
+
+/*external regulator VREG_5V*/
+static struct regulator *reg_flash_5V;
+
+static int config_camera_on_gpios_fluid(void)
+{
+	int rc = 0;
+
+	reg_flash_5V = regulator_get(NULL, "8901_mpp0");
+	if (IS_ERR(reg_flash_5V)) {
+		pr_err("'%s' regulator not found, rc=%ld\n",
+				"8901_mpp0", IS_ERR(reg_flash_5V));
+		return -ENODEV;
+	}
+
+	rc = regulator_enable(reg_flash_5V);
+	if (rc) {
+		pr_err("'%s' regulator enable failed, rc=%d\n",
+			"8901_mpp0", rc);
+		regulator_put(reg_flash_5V);
+		return rc;
+	}
+
+#ifdef CONFIG_IMX074
+	sensor_board_info.mount_angle = 90;
+#endif
+	rc = config_gpio_table(MSM_CAM_ON);
+	if (rc < 0) {
+		printk(KERN_ERR "%s: CAMSENSOR gpio table request"
+		"failed\n", __func__);
+		return rc;
+	}
+
+	rc = gpio_request(GPIO_EXT_CAMIF_PWR_EN, "CAM_EN");
+	if (rc < 0) {
+		printk(KERN_ERR "%s: CAMSENSOR gpio %d request"
+			"failed\n", __func__, GPIO_EXT_CAMIF_PWR_EN);
+		regulator_disable(reg_flash_5V);
+		regulator_put(reg_flash_5V);
+		return rc;
+	}
+	gpio_direction_output(GPIO_EXT_CAMIF_PWR_EN, 0);
+	msleep(20);
+	gpio_set_value_cansleep(GPIO_EXT_CAMIF_PWR_EN, 1);
+
+
+	/*Enable LED_FLASH_EN*/
+	rc = gpio_request(GPIO_LED_FLASH_EN, "LED_FLASH_EN");
+	if (rc < 0) {
+		printk(KERN_ERR "%s: CAMSENSOR gpio %d request"
+			"failed\n", __func__, GPIO_LED_FLASH_EN);
+
+		regulator_disable(reg_flash_5V);
+		regulator_put(reg_flash_5V);
+		config_gpio_table(MSM_CAM_OFF);
+		gpio_set_value_cansleep(GPIO_EXT_CAMIF_PWR_EN, 0);
+		gpio_free(GPIO_EXT_CAMIF_PWR_EN);
+		return rc;
+	}
+	gpio_direction_output(GPIO_LED_FLASH_EN, 1);
+	msleep(20);
+	return rc;
+}
+
+
+static void config_camera_off_gpios_fluid(void)
+{
+	regulator_disable(reg_flash_5V);
+	regulator_put(reg_flash_5V);
+
+	gpio_direction_output(GPIO_LED_FLASH_EN, 0);
+	gpio_free(GPIO_LED_FLASH_EN);
+
+	config_gpio_table(MSM_CAM_OFF);
+
+	gpio_set_value_cansleep(GPIO_EXT_CAMIF_PWR_EN, 0);
+	gpio_free(GPIO_EXT_CAMIF_PWR_EN);
+}
+static int config_camera_on_gpios(void)
+{
+	int rc = 0;
+
+	if (machine_is_msm8x60_fluid())
+		return config_camera_on_gpios_fluid();
+
+	rc = config_gpio_table(MSM_CAM_ON);
+	if (rc < 0) {
+		printk(KERN_ERR "%s: CAMSENSOR gpio table request"
+		"failed\n", __func__);
+		return rc;
+	}
+
+	if (!machine_is_msm8x60_dragon()) {
+		rc = gpio_request(GPIO_EXT_CAMIF_PWR_EN, "CAM_EN");
+		if (rc < 0) {
+			config_gpio_table(MSM_CAM_OFF);
+			pr_err("%s: CAMSENSOR gpio %d request"
+				"failed\n", __func__, GPIO_EXT_CAMIF_PWR_EN);
+			return rc;
+		}
+		gpio_direction_output(GPIO_EXT_CAMIF_PWR_EN, 0);
+		msleep(20);
+		gpio_set_value_cansleep(GPIO_EXT_CAMIF_PWR_EN, 1);
+	}
+
+#ifdef CONFIG_MSM_CAMERA_FLASH
+#ifdef CONFIG_IMX074
+	if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
+		strobe_flash_xenon.flash_charge = FUSION_VFE_CAMIF_TIMER1_GPIO;
+#endif
+#endif
+	return rc;
+}
+
+static void config_camera_off_gpios(void)
+{
+	if (machine_is_msm8x60_fluid())
+		return config_camera_off_gpios_fluid();
+
+
+	config_gpio_table(MSM_CAM_OFF);
+
+	if (!machine_is_msm8x60_dragon()) {
+		gpio_set_value_cansleep(GPIO_EXT_CAMIF_PWR_EN, 0);
+		gpio_free(GPIO_EXT_CAMIF_PWR_EN);
+	}
+}
+
+#ifdef CONFIG_QS_S5K4E1
+
+#define QS_CAM_HC37_CAM_PD PM8058_GPIO_PM_TO_SYS(26)
+
+static int config_camera_on_gpios_qs_cam_fluid(void)
+{
+	int rc = 0;
+
+	/* request QS_CAM_HC37_CAM_PD as an output to HC37 ASIC pin CAM_PD */
+	rc = gpio_request(QS_CAM_HC37_CAM_PD, "QS_CAM_HC37_CAM_PD");
+	if (rc < 0) {
+		printk(KERN_ERR "%s: QS_CAM_HC37_CAM_PD gpio %d request"
+			" failed\n", __func__, QS_CAM_HC37_CAM_PD);
+		return rc;
+	}
+	gpio_direction_output(QS_CAM_HC37_CAM_PD, 0);
+	msleep(20);
+	gpio_set_value_cansleep(QS_CAM_HC37_CAM_PD, 1);
+	msleep(20);
+
+	/*
+	 * Set GPIO_AUX_CAM_2P7_EN to 1 on North Expander IO2
+	 * to enable 2.7V power to Camera
+	 */
+	rc = gpio_request(GPIO_AUX_CAM_2P7_EN, "CAM_2P7_EN");
+	if (rc < 0) {
+		printk(KERN_ERR "%s: CAMSENSOR gpio %d request"
+			" failed\n", __func__, GPIO_AUX_CAM_2P7_EN);
+		gpio_set_value_cansleep(QS_CAM_HC37_CAM_PD, 0);
+		gpio_free(QS_CAM_HC37_CAM_PD);
+		return rc;
+	}
+	gpio_direction_output(GPIO_AUX_CAM_2P7_EN, 0);
+	msleep(20);
+	gpio_set_value_cansleep(GPIO_AUX_CAM_2P7_EN, 1);
+	msleep(20);
+
+	rc = config_camera_on_gpios_fluid();
+	if (rc < 0) {
+		printk(KERN_ERR "%s: config_camera_on_gpios_fluid"
+		" failed\n", __func__);
+		gpio_set_value_cansleep(QS_CAM_HC37_CAM_PD, 0);
+		gpio_free(QS_CAM_HC37_CAM_PD);
+		gpio_set_value_cansleep(GPIO_AUX_CAM_2P7_EN, 0);
+		gpio_free(GPIO_AUX_CAM_2P7_EN);
+		return rc;
+	}
+	return rc;
+}
+
+static void config_camera_off_gpios_qs_cam_fluid(void)
+{
+	/*
+	 * Set GPIO_AUX_CAM_2P7_EN to 0 on North Expander IO2
+	 * to disable 2.7V power to Camera
+	 */
+	gpio_set_value_cansleep(GPIO_AUX_CAM_2P7_EN, 0);
+	gpio_free(GPIO_AUX_CAM_2P7_EN);
+
+	/* set QS_CAM_HC37_CAM_PD to 0 to power off HC37 ASIC*/
+	gpio_set_value_cansleep(QS_CAM_HC37_CAM_PD, 0);
+	gpio_free(QS_CAM_HC37_CAM_PD);
+
+	config_camera_off_gpios_fluid();
+	return;
+}
+
+static int config_camera_on_gpios_qs_cam(void)
+{
+	int rc = 0;
+
+	if (machine_is_msm8x60_fluid())
+		return config_camera_on_gpios_qs_cam_fluid();
+
+	rc = config_camera_on_gpios();
+	return rc;
+}
+
+static void config_camera_off_gpios_qs_cam(void)
+{
+	if (machine_is_msm8x60_fluid())
+		return config_camera_off_gpios_qs_cam_fluid();
+
+	config_camera_off_gpios();
+	return;
+}
+#endif
+
+static int config_camera_on_gpios_web_cam(void)
+{
+	int rc = 0;
+	rc = config_gpio_table(MSM_CAM_ON);
+	if (rc < 0) {
+		printk(KERN_ERR "%s: CAMSENSOR gpio table request"
+		"failed\n", __func__);
+		return rc;
+	}
+
+	if (!(machine_is_msm8x60_fluid() || machine_is_msm8x60_dragon())) {
+		rc = gpio_request(GPIO_WEB_CAMIF_STANDBY, "CAM_EN");
+		if (rc < 0) {
+			config_gpio_table(MSM_CAM_OFF);
+			pr_err(KERN_ERR "%s: CAMSENSOR gpio %d request"
+				"failed\n", __func__, GPIO_WEB_CAMIF_STANDBY);
+			return rc;
+		}
+		gpio_direction_output(GPIO_WEB_CAMIF_STANDBY, 0);
+	}
+	return rc;
+}
+
+static void config_camera_off_gpios_web_cam(void)
+{
+	config_gpio_table(MSM_CAM_OFF);
+	if (!(machine_is_msm8x60_fluid() || machine_is_msm8x60_dragon())) {
+		gpio_set_value_cansleep(GPIO_WEB_CAMIF_STANDBY, 1);
+		gpio_free(GPIO_WEB_CAMIF_STANDBY);
+	}
+	return;
+}
+
+#ifdef CONFIG_MSM_BUS_SCALING
+static struct msm_bus_vectors cam_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+};
+
+static struct msm_bus_vectors cam_preview_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 283115520,
+		.ib  = 452984832,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+};
+
+static struct msm_bus_vectors cam_video_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 283115520,
+		.ib  = 452984832,
+	},
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 283115520,
+		.ib  = 452984832,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 319610880,
+		.ib  = 511377408,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+};
+
+static struct msm_bus_vectors cam_snapshot_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 566231040,
+		.ib  = 905969664,
+	},
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 69984000,
+		.ib  = 111974400,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 320864256,
+		.ib  = 513382810,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 320864256,
+		.ib  = 513382810,
+	},
+};
+
+static struct msm_bus_vectors cam_zsl_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 566231040,
+		.ib  = 905969664,
+	},
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 706199040,
+		.ib  = 1129918464,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 320864256,
+		.ib  = 513382810,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 320864256,
+		.ib  = 513382810,
+	},
+};
+
+static struct msm_bus_vectors cam_stereo_video_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 212336640,
+		.ib  = 339738624,
+	},
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 25090560,
+		.ib  = 40144896,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 239708160,
+		.ib  = 383533056,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 79902720,
+		.ib  = 127844352,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+};
+
+static struct msm_bus_vectors cam_stereo_snapshot_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 300902400,
+		.ib  = 481443840,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 230307840,
+		.ib  = 368492544,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 245113344,
+		.ib  = 392181351,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 106536960,
+		.ib  = 170459136,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 106536960,
+		.ib  = 170459136,
+	},
+};
+
+static struct msm_bus_paths cam_bus_client_config[] = {
+	{
+		ARRAY_SIZE(cam_init_vectors),
+		cam_init_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_preview_vectors),
+		cam_preview_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_video_vectors),
+		cam_video_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_snapshot_vectors),
+		cam_snapshot_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_zsl_vectors),
+		cam_zsl_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_stereo_video_vectors),
+		cam_stereo_video_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_stereo_snapshot_vectors),
+		cam_stereo_snapshot_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata cam_bus_client_pdata = {
+		cam_bus_client_config,
+		ARRAY_SIZE(cam_bus_client_config),
+		.name = "msm_camera",
+};
+#endif
+
+struct msm_camera_device_platform_data msm_camera_device_data = {
+	.camera_gpio_on  = config_camera_on_gpios,
+	.camera_gpio_off = config_camera_off_gpios,
+	.ioext.csiphy = 0x04800000,
+	.ioext.csisz  = 0x00000400,
+	.ioext.csiirq = CSI_0_IRQ,
+	.ioclk.mclk_clk_rate = 24000000,
+	.ioclk.vfe_clk_rate  = 228570000,
+#ifdef CONFIG_MSM_BUS_SCALING
+	.cam_bus_scale_table = &cam_bus_client_pdata,
+#endif
+};
+
+#ifdef CONFIG_QS_S5K4E1
+struct msm_camera_device_platform_data msm_camera_device_data_qs_cam = {
+	.camera_gpio_on  = config_camera_on_gpios_qs_cam,
+	.camera_gpio_off = config_camera_off_gpios_qs_cam,
+	.ioext.csiphy = 0x04800000,
+	.ioext.csisz  = 0x00000400,
+	.ioext.csiirq = CSI_0_IRQ,
+	.ioclk.mclk_clk_rate = 24000000,
+	.ioclk.vfe_clk_rate  = 228570000,
+#ifdef CONFIG_MSM_BUS_SCALING
+	.cam_bus_scale_table = &cam_bus_client_pdata,
+#endif
+};
+#endif
+
+struct msm_camera_device_platform_data msm_camera_device_data_web_cam = {
+	.camera_gpio_on  = config_camera_on_gpios_web_cam,
+	.camera_gpio_off = config_camera_off_gpios_web_cam,
+	.ioext.csiphy = 0x04900000,
+	.ioext.csisz  = 0x00000400,
+	.ioext.csiirq = CSI_1_IRQ,
+	.ioclk.mclk_clk_rate = 24000000,
+	.ioclk.vfe_clk_rate  = 228570000,
+#ifdef CONFIG_MSM_BUS_SCALING
+	.cam_bus_scale_table = &cam_bus_client_pdata,
+#endif
+};
+
+struct resource msm_camera_resources[] = {
+	{
+		.start	= 0x04500000,
+		.end	= 0x04500000 + SZ_1M - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= VFE_IRQ,
+		.end	= VFE_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+#ifdef CONFIG_MT9E013
+static struct msm_camera_sensor_platform_info mt9e013_sensor_8660_info = {
+	.mount_angle = 0
+};
+
+static struct msm_camera_sensor_flash_data flash_mt9e013 = {
+	.flash_type			= MSM_CAMERA_FLASH_LED,
+	.flash_src			= &msm_flash_src
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_mt9e013_data = {
+		.sensor_name	= "mt9e013",
+		.sensor_reset	= 106,
+		.sensor_pwd		= 85,
+		.vcm_pwd		= 1,
+		.vcm_enable		= 0,
+		.pdata			= &msm_camera_device_data,
+		.resource		= msm_camera_resources,
+		.num_resources	= ARRAY_SIZE(msm_camera_resources),
+		.flash_data		= &flash_mt9e013,
+		.strobe_flash_data	= &strobe_flash_xenon,
+		.sensor_platform_info = &mt9e013_sensor_8660_info,
+		.csi_if			= 1
+};
+struct platform_device msm_camera_sensor_mt9e013 = {
+		.name	= "msm_camera_mt9e013",
+		.dev	= {
+			.platform_data = &msm_camera_sensor_mt9e013_data,
+		},
+};
+#endif
+
+#ifdef CONFIG_IMX074
+static struct msm_camera_sensor_platform_info imx074_sensor_board_info = {
+	.mount_angle = 180
+};
+
+static struct msm_camera_sensor_flash_data flash_imx074 = {
+	.flash_type		= MSM_CAMERA_FLASH_LED,
+	.flash_src		= &msm_flash_src
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_imx074_data = {
+	.sensor_name		= "imx074",
+	.sensor_reset		= 106,
+	.sensor_pwd		= 85,
+	.vcm_pwd		= GPIO_AUX_CAM_2P7_EN,
+	.vcm_enable		= 1,
+	.pdata			= &msm_camera_device_data,
+	.resource		= msm_camera_resources,
+	.num_resources		= ARRAY_SIZE(msm_camera_resources),
+	.flash_data		= &flash_imx074,
+	.strobe_flash_data	= &strobe_flash_xenon,
+	.sensor_platform_info = &imx074_sensor_board_info,
+	.csi_if			= 1
+};
+struct platform_device msm_camera_sensor_imx074 = {
+	.name	= "msm_camera_imx074",
+	.dev	= {
+		.platform_data = &msm_camera_sensor_imx074_data,
+	},
+};
+#endif
+#ifdef CONFIG_WEBCAM_OV9726
+
+static struct msm_camera_sensor_platform_info ov9726_sensor_8660_info = {
+	.mount_angle = 0
+};
+
+static struct msm_camera_sensor_flash_data flash_ov9726 = {
+	.flash_type	= MSM_CAMERA_FLASH_LED,
+	.flash_src	= &msm_flash_src
+};
+static struct msm_camera_sensor_info msm_camera_sensor_ov9726_data = {
+	.sensor_name	= "ov9726",
+	.sensor_reset_enable = 1,
+	.sensor_reset	= GPIO_FRONT_CAM_RESET_N,
+	.sensor_pwd	= 85,
+	.vcm_pwd	= 1,
+	.vcm_enable	= 0,
+	.pdata		= &msm_camera_device_data_web_cam,
+	.resource	= msm_camera_resources,
+	.num_resources	= ARRAY_SIZE(msm_camera_resources),
+	.flash_data	= &flash_ov9726,
+	.sensor_platform_info = &ov9726_sensor_8660_info,
+	.csi_if		= 1
+};
+struct platform_device msm_camera_sensor_webcam_ov9726 = {
+	.name	= "msm_camera_ov9726",
+	.dev	= {
+		.platform_data = &msm_camera_sensor_ov9726_data,
+	},
+};
+#endif
+#ifdef CONFIG_WEBCAM_OV7692
+static struct msm_camera_sensor_flash_data flash_ov7692 = {
+	.flash_type		= MSM_CAMERA_FLASH_LED,
+	.flash_src		= &msm_flash_src
+};
+static struct msm_camera_sensor_info msm_camera_sensor_ov7692_data = {
+	.sensor_name	= "ov7692",
+	.sensor_reset	= GPIO_WEB_CAMIF_RESET_N,
+	.sensor_pwd	= 85,
+	.vcm_pwd	= 1,
+	.vcm_enable	= 0,
+	.pdata		= &msm_camera_device_data_web_cam,
+	.resource	= msm_camera_resources,
+	.num_resources	= ARRAY_SIZE(msm_camera_resources),
+	.flash_data	= &flash_ov7692,
+	.csi_if		= 1
+};
+
+static struct platform_device msm_camera_sensor_webcam_ov7692 = {
+	.name	= "msm_camera_ov7692",
+	.dev	= {
+		.platform_data = &msm_camera_sensor_ov7692_data,
+	},
+};
+#endif
+#ifdef CONFIG_VX6953
+static struct msm_camera_sensor_platform_info vx6953_sensor_8660_info = {
+	.mount_angle = 270
+};
+
+static struct msm_camera_sensor_flash_data flash_vx6953 = {
+	.flash_type		= MSM_CAMERA_FLASH_NONE,
+	.flash_src		= &msm_flash_src
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_vx6953_data = {
+	.sensor_name	= "vx6953",
+	.sensor_reset	= 63,
+	.sensor_pwd		= 63,
+	.vcm_pwd		= GPIO_AUX_CAM_2P7_EN,
+	.vcm_enable		= 1,
+	.pdata			= &msm_camera_device_data,
+	.resource		= msm_camera_resources,
+	.num_resources	= ARRAY_SIZE(msm_camera_resources),
+	.flash_data		= &flash_vx6953,
+	.sensor_platform_info = &vx6953_sensor_8660_info,
+	.csi_if			= 1
+};
+struct platform_device msm_camera_sensor_vx6953 = {
+	.name	= "msm_camera_vx6953",
+	.dev	= {
+		.platform_data = &msm_camera_sensor_vx6953_data,
+	},
+};
+#endif
+#ifdef CONFIG_QS_S5K4E1
+
+static struct msm_camera_sensor_platform_info qs_s5k4e1_sensor_8660_info = {
+#ifdef CONFIG_FB_MSM_MIPI_NOVATEK_CMD_QHD_PT
+	.mount_angle = 90
+#else
+	.mount_angle = 0
+#endif
+};
+
+static char eeprom_data[864];
+static struct msm_camera_sensor_flash_data flash_qs_s5k4e1 = {
+	.flash_type		= MSM_CAMERA_FLASH_LED,
+	.flash_src		= &msm_flash_src
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_qs_s5k4e1_data = {
+	.sensor_name	= "qs_s5k4e1",
+	.sensor_reset	= 106,
+	.sensor_pwd		= 85,
+	.vcm_pwd		= 1,
+	.vcm_enable		= 0,
+	.pdata			= &msm_camera_device_data_qs_cam,
+	.resource		= msm_camera_resources,
+	.num_resources	= ARRAY_SIZE(msm_camera_resources),
+	.flash_data		= &flash_qs_s5k4e1,
+	.strobe_flash_data	= &strobe_flash_xenon,
+	.sensor_platform_info = &qs_s5k4e1_sensor_8660_info,
+	.csi_if			= 1,
+	.eeprom_data	= eeprom_data,
+};
+struct platform_device msm_camera_sensor_qs_s5k4e1 = {
+	.name	= "msm_camera_qs_s5k4e1",
+	.dev	= {
+		.platform_data = &msm_camera_sensor_qs_s5k4e1_data,
+	},
+};
+#endif
+static struct i2c_board_info msm_camera_boardinfo[] __initdata = {
+	#ifdef CONFIG_MT9E013
+	{
+		I2C_BOARD_INFO("mt9e013", 0x6C >> 2),
+	},
+	#endif
+	#ifdef CONFIG_IMX074
+	{
+		I2C_BOARD_INFO("imx074", 0x1A),
+	},
+	#endif
+	#ifdef CONFIG_WEBCAM_OV7692
+	{
+		I2C_BOARD_INFO("ov7692", 0x78),
+	},
+	#endif
+	#ifdef CONFIG_WEBCAM_OV9726
+	{
+		I2C_BOARD_INFO("ov9726", 0x10),
+	},
+	#endif
+	#ifdef CONFIG_QS_S5K4E1
+	{
+		I2C_BOARD_INFO("qs_s5k4e1", 0x20),
+	},
+	#endif
+};
+
+static struct i2c_board_info msm_camera_dragon_boardinfo[] __initdata = {
+	#ifdef CONFIG_WEBCAM_OV9726
+	{
+		I2C_BOARD_INFO("ov9726", 0x10),
+	},
+	#endif
+	#ifdef CONFIG_VX6953
+	{
+		I2C_BOARD_INFO("vx6953", 0x20),
+	},
+	#endif
+};
+#endif
+#endif
+
+#ifdef CONFIG_MSM_GEMINI
+static struct resource msm_gemini_resources[] = {
+	{
+		.start  = 0x04600000,
+		.end    = 0x04600000 + SZ_1M - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = INT_JPEG,
+		.end    = INT_JPEG,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device msm_gemini_device = {
+	.name           = "msm_gemini",
+	.resource       = msm_gemini_resources,
+	.num_resources  = ARRAY_SIZE(msm_gemini_resources),
+};
+#endif
+
+#ifdef CONFIG_I2C_QUP
+static void gsbi_qup_i2c_gpio_config(int adap_id, int config_type)
+{
+}
+
+static struct msm_i2c_platform_data msm_gsbi3_qup_i2c_pdata = {
+	.clk_freq = 384000,
+	.src_clk_rate = 24000000,
+	.msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
+};
+
+static struct msm_i2c_platform_data msm_gsbi4_qup_i2c_pdata = {
+	.clk_freq = 100000,
+	.src_clk_rate = 24000000,
+	.msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
+};
+
+static struct msm_i2c_platform_data msm_gsbi7_qup_i2c_pdata = {
+	.clk_freq = 100000,
+	.src_clk_rate = 24000000,
+	.msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
+};
+
+static struct msm_i2c_platform_data msm_gsbi8_qup_i2c_pdata = {
+	.clk_freq = 100000,
+	.src_clk_rate = 24000000,
+	.msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
+};
+
+static struct msm_i2c_platform_data msm_gsbi9_qup_i2c_pdata = {
+	.clk_freq = 100000,
+	.src_clk_rate = 24000000,
+	.msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
+};
+
+static struct msm_i2c_platform_data msm_gsbi12_qup_i2c_pdata = {
+	.clk_freq = 100000,
+	.src_clk_rate = 24000000,
+	.use_gsbi_shared_mode = 1,
+	.msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
+};
+#endif
+
+#if defined(CONFIG_SPI_QUP) || defined(CONFIG_SPI_QUP_MODULE)
+static struct msm_spi_platform_data msm_gsbi1_qup_spi_pdata = {
+	.max_clock_speed = 24000000,
+};
+
+static struct msm_spi_platform_data msm_gsbi10_qup_spi_pdata = {
+	.max_clock_speed = 24000000,
+};
+#endif
+
+#ifdef CONFIG_I2C_SSBI
+/* CODEC/TSSC SSBI */
+static struct msm_i2c_ssbi_platform_data msm_ssbi3_pdata = {
+	.controller_type = MSM_SBI_CTRL_SSBI,
+};
+#endif
+
+#ifdef CONFIG_BATTERY_MSM
+/* Use basic value for fake MSM battery */
+static struct msm_psy_batt_pdata msm_psy_batt_data = {
+	.avail_chg_sources = AC_CHG,
+};
+
+static struct platform_device msm_batt_device = {
+	.name              = "msm-battery",
+	.id                = -1,
+	.dev.platform_data = &msm_psy_batt_data,
+};
+#endif
+
+#ifdef CONFIG_FB_MSM_LCDC_DSUB
+/* VGA = 1440 x 900 x 4(bpp) x 2(pages)
+   prim = 1024 x 600 x 4(bpp) x 2(pages)
+   This is the difference. */
+#define MSM_FB_DSUB_PMEM_ADDER (0xA32000-0x4B0000)
+#else
+#define MSM_FB_DSUB_PMEM_ADDER (0)
+#endif
+
+/* Sensors DSPS platform data */
+#ifdef CONFIG_MSM_DSPS
+
+static struct dsps_gpio_info dsps_surf_gpios[] = {
+	{
+		.name = "compass_rst_n",
+		.num = GPIO_COMPASS_RST_N,
+		.on_val = 1,	/* device not in reset */
+		.off_val = 0,	/* device in reset */
+	},
+	{
+		.name = "gpio_r_altimeter_reset_n",
+		.num = GPIO_R_ALTIMETER_RESET_N,
+		.on_val = 1,	/* device not in reset */
+		.off_val = 0,	/* device in reset */
+	}
+};
+
+static struct dsps_gpio_info dsps_fluid_gpios[] = {
+	{
+		.name = "gpio_n_altimeter_reset_n",
+		.num = GPIO_N_ALTIMETER_RESET_N,
+		.on_val = 1,	/* device not in reset */
+		.off_val = 0,	/* device in reset */
+	}
+};
+
+static void __init msm8x60_init_dsps(void)
+{
+	struct msm_dsps_platform_data *pdata =
+		msm_dsps_device.dev.platform_data;
+	/*
+	 * On Fluid the Compass sensor Chip-Select (CS) is directly connected
+	 * to the power supply and not controled via GPIOs. Fluid uses a
+	 * different IO-Expender (north) than used on surf/ffa.
+	 */
+	if (machine_is_msm8x60_fluid()) {
+		/* fluid has different firmware, gpios */
+		pdata->pil_name = DSPS_PIL_FLUID_NAME;
+		msm_pil_dsps.dev.platform_data = DSPS_PIL_FLUID_NAME;
+		pdata->gpios = dsps_fluid_gpios;
+		pdata->gpios_num = ARRAY_SIZE(dsps_fluid_gpios);
+	} else {
+		pdata->pil_name = DSPS_PIL_GENERIC_NAME;
+		msm_pil_dsps.dev.platform_data = DSPS_PIL_GENERIC_NAME;
+		pdata->gpios = dsps_surf_gpios;
+		pdata->gpios_num = ARRAY_SIZE(dsps_surf_gpios);
+	}
+
+	platform_device_register(&msm_dsps_device);
+}
+#endif /* CONFIG_MSM_DSPS */
+
+#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
+#define MSM_FB_PRIM_BUF_SIZE \
+		(roundup((1024 * 600 * 4), 4096) * 3) /* 4 bpp x 3 pages */
+#else
+#define MSM_FB_PRIM_BUF_SIZE \
+		(roundup((1024 * 600 * 4), 4096) * 2) /* 4 bpp x 2 pages */
+#endif
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+#define MSM_FB_EXT_BUF_SIZE  \
+		(roundup((1920 * 1080 * 2), 4096) * 1) /* 2 bpp x 1 page */
+#elif defined(CONFIG_FB_MSM_TVOUT)
+#define MSM_FB_EXT_BUF_SIZE  \
+		(roundup((720 * 576 * 2), 4096) * 2) /* 2 bpp x 2 pages */
+#else
+#define MSM_FB_EXT_BUFT_SIZE	0
+#endif
+
+/* Note: must be multiple of 4096 */
+#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE + \
+				MSM_FB_DSUB_PMEM_ADDER, 4096)
+
+#define MSM_PMEM_SF_SIZE 0x4000000 /* 64 Mbytes */
+#define MSM_HDMI_PRIM_PMEM_SF_SIZE 0x8000000 /* 128 Mbytes */
+
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+unsigned char hdmi_is_primary = 1;
+#else
+unsigned char hdmi_is_primary;
+#endif
+
+#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 */
+
+#define MSM_PMEM_KERNEL_EBI1_SIZE  0x3BC000
+#define MSM_PMEM_ADSP_SIZE         0x4200000
+#define MSM_PMEM_AUDIO_SIZE        0x4CF000
+
+#define MSM_SMI_BASE          0x38000000
+#define MSM_SMI_SIZE          0x4000000
+
+#define KERNEL_SMI_BASE       (MSM_SMI_BASE)
+#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
+#define KERNEL_SMI_SIZE       0x000000
+#else
+#define KERNEL_SMI_SIZE       0x600000
+#endif
+
+#define USER_SMI_BASE         (KERNEL_SMI_BASE + KERNEL_SMI_SIZE)
+#define USER_SMI_SIZE         (MSM_SMI_SIZE - KERNEL_SMI_SIZE)
+#define MSM_PMEM_SMIPOOL_SIZE USER_SMI_SIZE
+
+#define MSM_ION_SF_SIZE		0x4000000 /* 64MB */
+#define MSM_ION_CAMERA_SIZE     MSM_PMEM_ADSP_SIZE
+#define MSM_ION_MM_FW_SIZE	0x200000 /* (2MB) */
+#define MSM_ION_MM_SIZE		0x3c00000 /* (60MB) Must be a multiple of 64K */
+#define MSM_ION_MFC_SIZE	SZ_8K
+#ifdef CONFIG_FB_MSM_OVERLAY1_WRITEBACK
+#define MSM_ION_WB_SIZE		0xC00000 /* 12MB */
+#else
+#define MSM_ION_WB_SIZE		0x600000 /* 6MB */
+#endif
+
+#define MSM_ION_QSECOM_SIZE	0x600000 /* (6MB) */
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+#define MSM_ION_AUDIO_SIZE	MSM_PMEM_AUDIO_SIZE
+#define MSM_ION_HEAP_NUM	9
+#define MSM_HDMI_PRIM_ION_SF_SIZE MSM_HDMI_PRIM_PMEM_SF_SIZE
+static unsigned msm_ion_sf_size = MSM_ION_SF_SIZE;
+#else
+#define MSM_ION_HEAP_NUM	1
+#endif
+
+static unsigned fb_size;
+static int __init fb_size_setup(char *p)
+{
+	fb_size = memparse(p, NULL);
+	return 0;
+}
+early_param("fb_size", fb_size_setup);
+
+static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE;
+static int __init pmem_kernel_ebi1_size_setup(char *p)
+{
+	pmem_kernel_ebi1_size = memparse(p, NULL);
+	return 0;
+}
+early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
+
+#ifdef CONFIG_ANDROID_PMEM
+static unsigned pmem_sf_size = MSM_PMEM_SF_SIZE;
+static int __init pmem_sf_size_setup(char *p)
+{
+	pmem_sf_size = memparse(p, NULL);
+	return 0;
+}
+early_param("pmem_sf_size", pmem_sf_size_setup);
+
+static unsigned pmem_adsp_size = MSM_PMEM_ADSP_SIZE;
+
+static int __init pmem_adsp_size_setup(char *p)
+{
+	pmem_adsp_size = memparse(p, NULL);
+	return 0;
+}
+early_param("pmem_adsp_size", pmem_adsp_size_setup);
+
+static unsigned pmem_audio_size = MSM_PMEM_AUDIO_SIZE;
+
+static int __init pmem_audio_size_setup(char *p)
+{
+	pmem_audio_size = memparse(p, NULL);
+	return 0;
+}
+early_param("pmem_audio_size", pmem_audio_size_setup);
+#endif
+
+static struct resource msm_fb_resources[] = {
+	{
+		.flags  = IORESOURCE_DMA,
+	}
+};
+
+static void set_mdp_clocks_for_wuxga(void);
+
+static int msm_fb_detect_panel(const char *name)
+{
+	if (machine_is_msm8x60_fluid()) {
+		uint32_t soc_platform_version = socinfo_get_platform_version();
+		if (SOCINFO_VERSION_MAJOR(soc_platform_version) < 3) {
+#ifdef CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT
+			if (!strncmp(name, LCDC_SAMSUNG_OLED_PANEL_NAME,
+					strnlen(LCDC_SAMSUNG_OLED_PANEL_NAME,
+						PANEL_NAME_MAX_LEN)))
+				return 0;
+#endif
+		} else { /*P3 and up use AUO panel */
+#ifdef CONFIG_FB_MSM_LCDC_AUO_WVGA
+			if (!strncmp(name, LCDC_AUO_PANEL_NAME,
+					strnlen(LCDC_AUO_PANEL_NAME,
+						PANEL_NAME_MAX_LEN)))
+				return 0;
+#endif
+		}
+#ifdef CONFIG_FB_MSM_LCDC_NT35582_WVGA
+	} else if machine_is_msm8x60_dragon() {
+	    if (!strncmp(name, LCDC_NT35582_PANEL_NAME,
+				strnlen(LCDC_NT35582_PANEL_NAME,
+					PANEL_NAME_MAX_LEN)))
+			return 0;
+#endif
+	} else {
+		if (!strncmp(name, LCDC_SAMSUNG_WSVGA_PANEL_NAME,
+				strnlen(LCDC_SAMSUNG_WSVGA_PANEL_NAME,
+					PANEL_NAME_MAX_LEN)))
+			return 0;
+
+#if !defined(CONFIG_FB_MSM_LCDC_AUTO_DETECT) && \
+	!defined(CONFIG_FB_MSM_MIPI_PANEL_AUTO_DETECT) && \
+	!defined(CONFIG_FB_MSM_LCDC_MIPI_PANEL_AUTO_DETECT)
+		if (!strncmp(name, MIPI_VIDEO_TOSHIBA_WVGA_PANEL_NAME,
+				strnlen(MIPI_VIDEO_TOSHIBA_WVGA_PANEL_NAME,
+					PANEL_NAME_MAX_LEN)))
+			return 0;
+
+		if (!strncmp(name, MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME,
+				strnlen(MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME,
+					  PANEL_NAME_MAX_LEN)))
+			return 0;
+
+		if (!strncmp(name, MIPI_CMD_NOVATEK_QHD_PANEL_NAME,
+				strnlen(MIPI_CMD_NOVATEK_QHD_PANEL_NAME,
+					PANEL_NAME_MAX_LEN)))
+			return 0;
+#endif
+	}
+
+	if (!strncmp(name, HDMI_PANEL_NAME,
+			strnlen(HDMI_PANEL_NAME,
+				PANEL_NAME_MAX_LEN))) {
+		if (hdmi_is_primary)
+			set_mdp_clocks_for_wuxga();
+		return 0;
+	}
+
+	if (!strncmp(name, TVOUT_PANEL_NAME,
+			strnlen(TVOUT_PANEL_NAME,
+				PANEL_NAME_MAX_LEN)))
+		return 0;
+
+	pr_warning("%s: not supported '%s'", __func__, name);
+	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,
+};
+
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+static struct android_pmem_platform_data android_pmem_pdata = {
+	.name = "pmem",
+	.allocator_type = PMEM_ALLOCATORTYPE_ALLORNOTHING,
+	.cached = 1,
+	.memory_type = MEMTYPE_EBI1,
+};
+
+static struct platform_device android_pmem_device = {
+	.name = "android_pmem",
+	.id = 0,
+	.dev = {.platform_data = &android_pmem_pdata},
+};
+
+static struct android_pmem_platform_data android_pmem_adsp_pdata = {
+	.name = "pmem_adsp",
+	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
+	.cached = 0,
+	.memory_type = MEMTYPE_EBI1,
+};
+
+static struct platform_device android_pmem_adsp_device = {
+	.name = "android_pmem",
+	.id = 2,
+	.dev = { .platform_data = &android_pmem_adsp_pdata },
+};
+
+static struct android_pmem_platform_data android_pmem_audio_pdata = {
+	.name = "pmem_audio",
+	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
+	.cached = 0,
+	.memory_type = MEMTYPE_EBI1,
+};
+
+static struct platform_device android_pmem_audio_device = {
+	.name = "android_pmem",
+	.id = 4,
+	.dev = { .platform_data = &android_pmem_audio_pdata },
+};
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#define PMEM_BUS_WIDTH(_bw) \
+	{ \
+		.vectors = &(struct msm_bus_vectors){ \
+			.src = MSM_BUS_MASTER_AMPSS_M0, \
+			.dst = MSM_BUS_SLAVE_SMI, \
+			.ib = (_bw), \
+			.ab = 0, \
+		}, \
+	.num_paths = 1, \
+	}
+
+static struct msm_bus_paths mem_smi_table[] = {
+	[0] = PMEM_BUS_WIDTH(0), /* Off */
+	[1] = PMEM_BUS_WIDTH(1), /* On */
+};
+
+static struct msm_bus_scale_pdata smi_client_pdata = {
+	.usecase = mem_smi_table,
+	.num_usecases = ARRAY_SIZE(mem_smi_table),
+	.name = "mem_smi",
+};
+
+int request_smi_region(void *data)
+{
+	int bus_id = (int) data;
+
+	msm_bus_scale_client_update_request(bus_id, 1);
+	return 0;
+}
+
+int release_smi_region(void *data)
+{
+	int bus_id = (int) data;
+
+	msm_bus_scale_client_update_request(bus_id, 0);
+	return 0;
+}
+
+void *setup_smi_region(void)
+{
+	return (void *)msm_bus_scale_register_client(&smi_client_pdata);
+}
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+static struct android_pmem_platform_data android_pmem_smipool_pdata = {
+	.name = "pmem_smipool",
+	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
+	.cached = 0,
+	.memory_type = MEMTYPE_SMI,
+	.request_region = request_smi_region,
+	.release_region = release_smi_region,
+	.setup_region = setup_smi_region,
+	.map_on_demand = 1,
+};
+static struct platform_device android_pmem_smipool_device = {
+	.name = "android_pmem",
+	.id = 7,
+	.dev = { .platform_data = &android_pmem_smipool_pdata },
+};
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
+
+#define GPIO_DONGLE_PWR_EN 258
+static void setup_display_power(void);
+static int lcdc_vga_enabled;
+static int vga_enable_request(int enable)
+{
+	if (enable)
+		lcdc_vga_enabled = 1;
+	else
+		lcdc_vga_enabled = 0;
+	setup_display_power();
+
+	return 0;
+}
+
+#define GPIO_BACKLIGHT_PWM0 0
+#define GPIO_BACKLIGHT_PWM1 1
+
+static int pmic_backlight_gpio[2]
+	= { GPIO_BACKLIGHT_PWM0, GPIO_BACKLIGHT_PWM1 };
+static struct msm_panel_common_pdata lcdc_samsung_panel_data = {
+	.gpio_num = pmic_backlight_gpio, /* two LPG CHANNELS for backlight */
+	.vga_switch = vga_enable_request,
+};
+
+static struct platform_device lcdc_samsung_panel_device = {
+	.name = LCDC_SAMSUNG_WSVGA_PANEL_NAME,
+	.id = 0,
+	.dev = {
+		.platform_data = &lcdc_samsung_panel_data,
+	}
+};
+#if (!defined(CONFIG_SPI_QUP)) && \
+	(defined(CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT) || \
+	defined(CONFIG_FB_MSM_LCDC_AUO_WVGA))
+
+static int lcdc_spi_gpio_array_num[] = {
+	LCDC_SPI_GPIO_CLK,
+	LCDC_SPI_GPIO_CS,
+	LCDC_SPI_GPIO_MOSI,
+};
+
+static uint32_t lcdc_spi_gpio_config_data[] = {
+	GPIO_CFG(LCDC_SPI_GPIO_CLK, 0,
+			GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	GPIO_CFG(LCDC_SPI_GPIO_CS, 0,
+			GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	GPIO_CFG(LCDC_SPI_GPIO_MOSI, 0,
+			GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+};
+
+static void lcdc_config_spi_gpios(int enable)
+{
+	int n;
+	for (n = 0; n < ARRAY_SIZE(lcdc_spi_gpio_config_data); ++n)
+		gpio_tlmm_config(lcdc_spi_gpio_config_data[n], 0);
+}
+#endif
+
+#ifdef CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT
+#ifdef CONFIG_SPI_QUP
+static struct spi_board_info lcdc_samsung_spi_board_info[] __initdata = {
+	{
+		.modalias       = LCDC_SAMSUNG_SPI_DEVICE_NAME,
+		.mode           = SPI_MODE_3,
+		.bus_num        = 1,
+		.chip_select    = 0,
+		.max_speed_hz   = 10800000,
+	}
+};
+#endif /* CONFIG_SPI_QUP */
+
+static struct msm_panel_common_pdata lcdc_samsung_oled_panel_data = {
+#ifndef CONFIG_SPI_QUP
+	.panel_config_gpio = lcdc_config_spi_gpios,
+	.gpio_num          = lcdc_spi_gpio_array_num,
+#endif
+};
+
+static struct platform_device lcdc_samsung_oled_panel_device = {
+	.name   = LCDC_SAMSUNG_OLED_PANEL_NAME,
+	.id     = 0,
+	.dev.platform_data = &lcdc_samsung_oled_panel_data,
+};
+#endif /*CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT */
+
+#ifdef CONFIG_FB_MSM_LCDC_AUO_WVGA
+#ifdef CONFIG_SPI_QUP
+static struct spi_board_info lcdc_auo_spi_board_info[] __initdata = {
+	{
+		.modalias       = LCDC_AUO_SPI_DEVICE_NAME,
+		.mode           = SPI_MODE_3,
+		.bus_num        = 1,
+		.chip_select    = 0,
+		.max_speed_hz   = 10800000,
+	}
+};
+#endif
+
+static struct msm_panel_common_pdata lcdc_auo_wvga_panel_data = {
+#ifndef CONFIG_SPI_QUP
+	.panel_config_gpio = lcdc_config_spi_gpios,
+	.gpio_num          = lcdc_spi_gpio_array_num,
+#endif
+};
+
+static struct platform_device lcdc_auo_wvga_panel_device = {
+	.name   = LCDC_AUO_PANEL_NAME,
+	.id     = 0,
+	.dev.platform_data = &lcdc_auo_wvga_panel_data,
+};
+#endif /*CONFIG_FB_MSM_LCDC_AUO_WVGA*/
+
+#ifdef CONFIG_FB_MSM_LCDC_NT35582_WVGA
+
+#define GPIO_NT35582_RESET			94
+#define GPIO_NT35582_BL_EN_HW_PIN	24
+#define GPIO_NT35582_BL_EN	\
+	PM8058_GPIO_PM_TO_SYS(GPIO_NT35582_BL_EN_HW_PIN - 1)
+
+static int lcdc_nt35582_pmic_gpio[] = {GPIO_NT35582_BL_EN };
+
+static struct msm_panel_common_pdata lcdc_nt35582_panel_data = {
+	.gpio_num = lcdc_nt35582_pmic_gpio,
+};
+
+static struct platform_device lcdc_nt35582_panel_device = {
+	.name = LCDC_NT35582_PANEL_NAME,
+	.id = 0,
+	.dev = {
+		.platform_data = &lcdc_nt35582_panel_data,
+	}
+};
+
+static struct spi_board_info lcdc_nt35582_spi_board_info[] __initdata = {
+	{
+		.modalias     = "lcdc_nt35582_spi",
+		.mode         = SPI_MODE_0,
+		.bus_num      = 0,
+		.chip_select  = 0,
+		.max_speed_hz = 1100000,
+	}
+};
+#endif
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+static struct resource hdmi_msm_resources[] = {
+	{
+		.name  = "hdmi_msm_qfprom_addr",
+		.start = 0x00700000,
+		.end   = 0x007060FF,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name  = "hdmi_msm_hdmi_addr",
+		.start = 0x04A00000,
+		.end   = 0x04A00FFF,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name  = "hdmi_msm_irq",
+		.start = HDMI_IRQ,
+		.end   = HDMI_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static int hdmi_enable_5v(int on);
+static int hdmi_core_power(int on, int show);
+static int hdmi_cec_power(int on);
+
+static struct msm_hdmi_platform_data hdmi_msm_data = {
+	.irq = HDMI_IRQ,
+	.enable_5v = hdmi_enable_5v,
+	.core_power = hdmi_core_power,
+	.cec_power = hdmi_cec_power,
+};
+
+static struct platform_device hdmi_msm_device = {
+	.name = "hdmi_msm",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(hdmi_msm_resources),
+	.resource = hdmi_msm_resources,
+	.dev.platform_data = &hdmi_msm_data,
+};
+#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL */
+
+#ifdef CONFIG_FB_MSM_MIPI_DSI
+static struct platform_device mipi_dsi_toshiba_panel_device = {
+	.name = "mipi_toshiba",
+	.id = 0,
+};
+
+#define FPGA_3D_GPIO_CONFIG_ADDR	0x1D00017A
+
+static struct mipi_dsi_panel_platform_data novatek_pdata = {
+	.fpga_3d_config_addr  = FPGA_3D_GPIO_CONFIG_ADDR,
+	.fpga_ctrl_mode = FPGA_EBI2_INTF,
+};
+
+static struct platform_device mipi_dsi_novatek_panel_device = {
+	.name = "mipi_novatek",
+	.id = 0,
+	.dev = {
+		.platform_data = &novatek_pdata,
+	}
+};
+#endif
+
+static void __init msm8x60_allocate_memory_regions(void)
+{
+	void *addr;
+	unsigned long size;
+
+	if (hdmi_is_primary)
+		size = roundup((1920 * 1088 * 4 * 2), 4096);
+	else
+		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));
+
+}
+
+void __init msm8x60_set_display_params(char *prim_panel, char *ext_panel)
+{
+	if (strnlen(prim_panel, PANEL_NAME_MAX_LEN)) {
+		strlcpy(msm_fb_pdata.prim_panel_name, prim_panel,
+			PANEL_NAME_MAX_LEN);
+		pr_debug("msm_fb_pdata.prim_panel_name %s\n",
+			msm_fb_pdata.prim_panel_name);
+
+		if (!strncmp((char *)msm_fb_pdata.prim_panel_name,
+			HDMI_PANEL_NAME, strnlen(HDMI_PANEL_NAME,
+				PANEL_NAME_MAX_LEN))) {
+			pr_debug("HDMI is the primary display by"
+				" boot parameter\n");
+			hdmi_is_primary = 1;
+			set_mdp_clocks_for_wuxga();
+		}
+	}
+	if (strnlen(ext_panel, PANEL_NAME_MAX_LEN)) {
+		strlcpy(msm_fb_pdata.ext_panel_name, ext_panel,
+			PANEL_NAME_MAX_LEN);
+		pr_debug("msm_fb_pdata.ext_panel_name %s\n",
+			msm_fb_pdata.ext_panel_name);
+	}
+}
+
+#if defined(CONFIG_TOUCHSCREEN_CYTTSP_I2C_QC) || \
+		defined(CONFIG_TOUCHSCREEN_CYTTSP_I2C_QC_MODULE)
+/*virtual key support */
+static ssize_t tma300_vkeys_show(struct kobject *kobj,
+			struct kobj_attribute *attr, char *buf)
+{
+	return sprintf(buf,
+	__stringify(EV_KEY) ":" __stringify(KEY_BACK) ":60:900:90:120"
+	":" __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":180:900:90:120"
+	":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":300:900:90:120"
+	":" __stringify(EV_KEY) ":" __stringify(KEY_SEARCH) ":420:900:90:120"
+	"\n");
+}
+
+static struct kobj_attribute tma300_vkeys_attr = {
+	.attr = {
+		.mode = S_IRUGO,
+	},
+	.show = &tma300_vkeys_show,
+};
+
+static struct attribute *tma300_properties_attrs[] = {
+	&tma300_vkeys_attr.attr,
+	NULL
+};
+
+static struct attribute_group tma300_properties_attr_group = {
+	.attrs = tma300_properties_attrs,
+};
+
+static struct kobject *properties_kobj;
+
+
+
+#define CYTTSP_TS_GPIO_IRQ	61
+static int cyttsp_platform_init(struct i2c_client *client)
+{
+	int rc = -EINVAL;
+	struct regulator *pm8058_l5 = NULL, *pm8058_s3;
+
+	if (machine_is_msm8x60_fluid()) {
+		pm8058_l5 = regulator_get(NULL, "8058_l5");
+		if (IS_ERR(pm8058_l5)) {
+			pr_err("%s: regulator get of 8058_l5 failed (%ld)\n",
+				__func__, PTR_ERR(pm8058_l5));
+			rc = PTR_ERR(pm8058_l5);
+			return rc;
+		}
+		rc = regulator_set_voltage(pm8058_l5, 2850000, 2850000);
+		if (rc) {
+			pr_err("%s: regulator_set_voltage of 8058_l5 failed(%d)\n",
+				__func__, rc);
+			goto reg_l5_put;
+		}
+
+		rc = regulator_enable(pm8058_l5);
+		if (rc) {
+			pr_err("%s: regulator_enable of 8058_l5 failed(%d)\n",
+				__func__, rc);
+			goto reg_l5_put;
+		}
+	}
+	/* vote for s3 to enable i2c communication lines */
+	pm8058_s3 = regulator_get(NULL, "8058_s3");
+	if (IS_ERR(pm8058_s3)) {
+		pr_err("%s: regulator get of 8058_s3 failed (%ld)\n",
+			__func__, PTR_ERR(pm8058_s3));
+		rc = PTR_ERR(pm8058_s3);
+		goto reg_l5_disable;
+	}
+
+	rc = regulator_set_voltage(pm8058_s3, 1800000, 1800000);
+	if (rc) {
+		pr_err("%s: regulator_set_voltage() = %d\n",
+			__func__, rc);
+		goto reg_s3_put;
+	}
+
+	rc = regulator_enable(pm8058_s3);
+	if (rc) {
+		pr_err("%s: regulator_enable of 8058_l5 failed(%d)\n",
+			__func__, rc);
+		goto reg_s3_put;
+	}
+
+	/* wait for vregs to stabilize */
+	usleep_range(10000, 10000);
+
+	/* check this device active by reading first byte/register */
+	rc = i2c_smbus_read_byte_data(client, 0x01);
+	if (rc < 0) {
+		pr_err("%s: i2c sanity check failed\n", __func__);
+		goto reg_s3_disable;
+	}
+
+	/* virtual keys */
+	if (machine_is_msm8x60_fluid()) {
+		properties_kobj = kobject_create_and_add("board_properties",
+					NULL);
+		if (properties_kobj);
+		if (!properties_kobj || rc)
+			pr_err("%s: failed to create board_properties\n",
+					__func__);
+	}
+	return CY_OK;
+
+reg_s3_disable:
+	regulator_disable(pm8058_s3);
+reg_s3_put:
+	regulator_put(pm8058_s3);
+reg_l5_disable:
+	if (machine_is_msm8x60_fluid())
+		regulator_disable(pm8058_l5);
+reg_l5_put:
+	if (machine_is_msm8x60_fluid())
+		regulator_put(pm8058_l5);
+	return rc;
+}
+
+/* TODO: Put the regulator to LPM / HPM in suspend/resume*/
+static int cyttsp_platform_suspend(struct i2c_client *client)
+{
+	msleep(20);
+
+	return CY_OK;
+}
+
+static int cyttsp_platform_resume(struct i2c_client *client)
+{
+	/* add any special code to strobe a wakeup pin or chip reset */
+	msleep(10);
+
+	return CY_OK;
+}
+
+static struct cyttsp_platform_data cyttsp_fluid_pdata = {
+	.flags = 0x04,
+	.gen = CY_GEN3,	/* or */
+	.use_st = CY_USE_ST,
+	.use_mt = CY_USE_MT,
+	.use_hndshk = CY_SEND_HNDSHK,
+	.use_trk_id = CY_USE_TRACKING_ID,
+	.use_sleep = CY_USE_DEEP_SLEEP_SEL | CY_USE_LOW_POWER_SEL,
+	.use_gestures = CY_USE_GESTURES,
+	/* activate up to 4 groups
+	 * and set active distance
+	 */
+	.gest_set = CY_GEST_GRP1 | CY_GEST_GRP2 |
+				CY_GEST_GRP3 | CY_GEST_GRP4 |
+				CY_ACT_DIST,
+	/* change act_intrvl to customize the Active power state
+	 * scanning/processing refresh interval for Operating mode
+	 */
+	.act_intrvl = CY_ACT_INTRVL_DFLT,
+	/* change tch_tmout to customize the touch timeout for the
+	 * Active power state for Operating mode
+	 */
+	.tch_tmout = CY_TCH_TMOUT_DFLT,
+	/* change lp_intrvl to customize the Low Power power state
+	 * scanning/processing refresh interval for Operating mode
+	 */
+	.lp_intrvl = CY_LP_INTRVL_DFLT,
+	.sleep_gpio = -1,
+	.resout_gpio = -1,
+	.irq_gpio = CYTTSP_TS_GPIO_IRQ,
+	.resume = cyttsp_platform_resume,
+	.suspend = cyttsp_platform_suspend,
+	.init = cyttsp_platform_init,
+};
+
+static struct cyttsp_platform_data cyttsp_tmg240_pdata = {
+	.panel_maxx = 1083,
+	.panel_maxy = 659,
+	.disp_minx = 30,
+	.disp_maxx = 1053,
+	.disp_miny = 30,
+	.disp_maxy = 629,
+	.correct_fw_ver = 8,
+	.fw_fname = "cyttsp_8660_ffa.hex",
+	.flags = 0x00,
+	.gen = CY_GEN2,	/* or */
+	.use_st = CY_USE_ST,
+	.use_mt = CY_USE_MT,
+	.use_hndshk = CY_SEND_HNDSHK,
+	.use_trk_id = CY_USE_TRACKING_ID,
+	.use_sleep = CY_USE_DEEP_SLEEP_SEL | CY_USE_LOW_POWER_SEL,
+	.use_gestures = CY_USE_GESTURES,
+	/* activate up to 4 groups
+	 * and set active distance
+	 */
+	.gest_set = CY_GEST_GRP1 | CY_GEST_GRP2 |
+				CY_GEST_GRP3 | CY_GEST_GRP4 |
+				CY_ACT_DIST,
+	/* change act_intrvl to customize the Active power state
+	 * scanning/processing refresh interval for Operating mode
+	 */
+	.act_intrvl = CY_ACT_INTRVL_DFLT,
+	/* change tch_tmout to customize the touch timeout for the
+	 * Active power state for Operating mode
+	 */
+	.tch_tmout = CY_TCH_TMOUT_DFLT,
+	/* change lp_intrvl to customize the Low Power power state
+	 * scanning/processing refresh interval for Operating mode
+	 */
+	.lp_intrvl = CY_LP_INTRVL_DFLT,
+	.sleep_gpio = -1,
+	.resout_gpio = -1,
+	.irq_gpio = CYTTSP_TS_GPIO_IRQ,
+	.resume = cyttsp_platform_resume,
+	.suspend = cyttsp_platform_suspend,
+	.init = cyttsp_platform_init,
+	.disable_ghost_det = true,
+};
+static void cyttsp_set_params(void)
+{
+	if (SOCINFO_VERSION_MAJOR(socinfo_get_platform_version()) < 3) {
+		cyttsp_fluid_pdata.fw_fname = "cyttsp_8660_fluid_p2.hex";
+		cyttsp_fluid_pdata.panel_maxx = 539;
+		cyttsp_fluid_pdata.panel_maxy = 994;
+		cyttsp_fluid_pdata.disp_minx = 30;
+		cyttsp_fluid_pdata.disp_maxx = 509;
+		cyttsp_fluid_pdata.disp_miny = 60;
+		cyttsp_fluid_pdata.disp_maxy = 859;
+		cyttsp_fluid_pdata.correct_fw_ver = 4;
+	} else {
+		cyttsp_fluid_pdata.fw_fname = "cyttsp_8660_fluid_p3.hex";
+		cyttsp_fluid_pdata.panel_maxx = 550;
+		cyttsp_fluid_pdata.panel_maxy = 1013;
+		cyttsp_fluid_pdata.disp_minx = 35;
+		cyttsp_fluid_pdata.disp_maxx = 515;
+		cyttsp_fluid_pdata.disp_miny = 69;
+		cyttsp_fluid_pdata.disp_maxy = 869;
+		cyttsp_fluid_pdata.correct_fw_ver = 5;
+	}
+
+}
+
+static struct i2c_board_info cyttsp_fluid_info[] __initdata = {
+	{
+		I2C_BOARD_INFO(CY_I2C_NAME, 0x24),
+		.platform_data = &cyttsp_fluid_pdata,
+#ifndef CY_USE_TIMER
+		.irq = MSM_GPIO_TO_INT(CYTTSP_TS_GPIO_IRQ),
+#endif /* CY_USE_TIMER */
+	},
+};
+
+static struct i2c_board_info cyttsp_ffa_info[] __initdata = {
+	{
+		I2C_BOARD_INFO(CY_I2C_NAME, 0x3b),
+		.platform_data = &cyttsp_tmg240_pdata,
+#ifndef CY_USE_TIMER
+		.irq = MSM_GPIO_TO_INT(CYTTSP_TS_GPIO_IRQ),
+#endif /* CY_USE_TIMER */
+	},
+};
+#endif
+
+static struct regulator *vreg_tmg200;
+
+#define TS_PEN_IRQ_GPIO 61
+static int tmg200_power(int vreg_on)
+{
+	int rc = -EINVAL;
+
+	if (!vreg_tmg200) {
+		printk(KERN_ERR "%s: regulator 8058_s3 not found (%d)\n",
+			__func__, rc);
+		return rc;
+	}
+
+	rc = vreg_on ? regulator_enable(vreg_tmg200) :
+		  regulator_disable(vreg_tmg200);
+	if (rc < 0)
+		printk(KERN_ERR "%s: vreg 8058_s3 %s failed (%d)\n",
+				__func__, vreg_on ? "enable" : "disable", rc);
+
+	/* wait for vregs to stabilize */
+	msleep(20);
+
+	return rc;
+}
+
+static int tmg200_dev_setup(bool enable)
+{
+	int rc;
+
+	if (enable) {
+		vreg_tmg200 = regulator_get(NULL, "8058_s3");
+		if (IS_ERR(vreg_tmg200)) {
+			pr_err("%s: regulator get of 8058_s3 failed (%ld)\n",
+				__func__, PTR_ERR(vreg_tmg200));
+			rc = PTR_ERR(vreg_tmg200);
+			return rc;
+		}
+
+		rc = regulator_set_voltage(vreg_tmg200, 1800000, 1800000);
+		if (rc) {
+			pr_err("%s: regulator_set_voltage() = %d\n",
+				__func__, rc);
+			goto reg_put;
+		}
+	} else {
+		/* put voltage sources */
+		regulator_put(vreg_tmg200);
+	}
+	return 0;
+reg_put:
+	regulator_put(vreg_tmg200);
+	return rc;
+}
+
+static struct cy8c_ts_platform_data cy8ctmg200_pdata = {
+	.ts_name = "msm_tmg200_ts",
+	.dis_min_x = 0,
+	.dis_max_x = 1023,
+	.dis_min_y = 0,
+	.dis_max_y = 599,
+	.min_tid = 0,
+	.max_tid = 255,
+	.min_touch = 0,
+	.max_touch = 255,
+	.min_width = 0,
+	.max_width = 255,
+	.power_on = tmg200_power,
+	.dev_setup = tmg200_dev_setup,
+	.nfingers = 2,
+	.irq_gpio = TS_PEN_IRQ_GPIO,
+	.resout_gpio = GPIO_CAP_TS_RESOUT_N,
+};
+
+static struct i2c_board_info cy8ctmg200_board_info[] = {
+	{
+		I2C_BOARD_INFO("cy8ctmg200", 0x2),
+		.platform_data = &cy8ctmg200_pdata,
+	}
+};
+
+static struct regulator *vreg_tma340;
+
+static int tma340_power(int vreg_on)
+{
+	int rc = -EINVAL;
+
+	if (!vreg_tma340) {
+		pr_err("%s: regulator 8901_l2 not found (%d)\n",
+			__func__, rc);
+		return rc;
+	}
+
+	rc = vreg_on ? regulator_enable(vreg_tma340) :
+			regulator_disable(vreg_tma340);
+	if (rc < 0)
+		pr_err("%s: vreg 8901_l2 %s failed (%d)\n",
+				__func__, vreg_on ? "enable" : "disable", rc);
+
+	/* wait for vregs to stabilize */
+	msleep(100);
+
+	return rc;
+}
+
+static struct kobject *tma340_prop_kobj;
+
+static int tma340_dragon_dev_setup(bool enable)
+{
+	int rc;
+
+	if (enable) {
+		vreg_tma340 = regulator_get(NULL, "8901_l2");
+		if (IS_ERR(vreg_tma340)) {
+			pr_err("%s: regulator get of 8901_l2 failed (%ld)\n",
+				__func__, PTR_ERR(vreg_tma340));
+			rc = PTR_ERR(vreg_tma340);
+			return rc;
+		}
+
+		rc = regulator_set_voltage(vreg_tma340, 3300000, 3300000);
+		if (rc) {
+			pr_err("%s: regulator_set_voltage() = %d\n",
+				__func__, rc);
+			goto reg_put;
+		}
+		tma340_prop_kobj = kobject_create_and_add("board_properties",
+					NULL);
+		if (tma340_prop_kobj) {
+			;
+			if (rc) {
+				kobject_put(tma340_prop_kobj);
+				pr_err("%s: failed to create board_properties\n",
+					__func__);
+				goto reg_put;
+			}
+		}
+
+	} else {
+		/* put voltage sources */
+		regulator_put(vreg_tma340);
+		/* destroy virtual keys */
+		if (tma340_prop_kobj) {
+			kobject_put(tma340_prop_kobj);
+		}
+	}
+	return 0;
+reg_put:
+	regulator_put(vreg_tma340);
+	return rc;
+}
+
+
+static struct cy8c_ts_platform_data cy8ctma340_dragon_pdata = {
+	.ts_name = "cy8ctma340",
+	.dis_min_x = 0,
+	.dis_max_x = 479,
+	.dis_min_y = 0,
+	.dis_max_y = 799,
+	.min_tid = 0,
+	.max_tid = 255,
+	.min_touch = 0,
+	.max_touch = 255,
+	.min_width = 0,
+	.max_width = 255,
+	.power_on = tma340_power,
+	.dev_setup = tma340_dragon_dev_setup,
+	.nfingers = 2,
+	.irq_gpio = TS_PEN_IRQ_GPIO,
+	.resout_gpio = -1,
+};
+
+static struct i2c_board_info cy8ctma340_dragon_board_info[] = {
+	{
+		I2C_BOARD_INFO("cy8ctma340", 0x24),
+		.platform_data = &cy8ctma340_dragon_pdata,
+	}
+};
+
+#ifdef CONFIG_SERIAL_MSM_HS
+static int configure_uart_gpios(int on)
+{
+	int ret = 0, i;
+	int uart_gpios[] = {53, 54, 55, 56};
+	for (i = 0; i < ARRAY_SIZE(uart_gpios); i++) {
+		if (on) {
+			ret = msm_gpiomux_get(uart_gpios[i]);
+			if (unlikely(ret))
+				break;
+		} else {
+			ret = msm_gpiomux_put(uart_gpios[i]);
+			if (unlikely(ret))
+				return ret;
+		}
+	}
+	if (ret)
+		for (; i >= 0; i--)
+			msm_gpiomux_put(uart_gpios[i]);
+	return ret;
+}
+static struct msm_serial_hs_platform_data msm_uart_dm1_pdata = {
+       .inject_rx_on_wakeup = 1,
+       .rx_to_inject = 0xFD,
+       .gpio_config = configure_uart_gpios,
+};
+#endif
+
+
+#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
+
+static struct gpio_led gpio_exp_leds_config[] = {
+	{
+		.name = "left_led1:green",
+		.gpio = GPIO_LEFT_LED_1,
+		.active_low = 1,
+		.retain_state_suspended = 0,
+		.default_state = LEDS_GPIO_DEFSTATE_OFF,
+	},
+	{
+		.name = "left_led2:red",
+		.gpio = GPIO_LEFT_LED_2,
+		.active_low = 1,
+		.retain_state_suspended = 0,
+		.default_state = LEDS_GPIO_DEFSTATE_OFF,
+	},
+	{
+		.name = "left_led3:green",
+		.gpio = GPIO_LEFT_LED_3,
+		.active_low = 1,
+		.retain_state_suspended = 0,
+		.default_state = LEDS_GPIO_DEFSTATE_OFF,
+	},
+	{
+		.name = "wlan_led:orange",
+		.gpio = GPIO_LEFT_LED_WLAN,
+		.active_low = 1,
+		.retain_state_suspended = 0,
+		.default_state = LEDS_GPIO_DEFSTATE_OFF,
+	},
+	{
+		.name = "left_led5:green",
+		.gpio = GPIO_LEFT_LED_5,
+		.active_low = 1,
+		.retain_state_suspended = 0,
+		.default_state = LEDS_GPIO_DEFSTATE_OFF,
+	},
+	{
+		.name = "right_led1:green",
+		.gpio = GPIO_RIGHT_LED_1,
+		.active_low = 1,
+		.retain_state_suspended = 0,
+		.default_state = LEDS_GPIO_DEFSTATE_OFF,
+	},
+	{
+		.name = "right_led2:red",
+		.gpio = GPIO_RIGHT_LED_2,
+		.active_low = 1,
+		.retain_state_suspended = 0,
+		.default_state = LEDS_GPIO_DEFSTATE_OFF,
+	},
+	{
+		.name = "right_led3:green",
+		.gpio = GPIO_RIGHT_LED_3,
+		.active_low = 1,
+		.retain_state_suspended = 0,
+		.default_state = LEDS_GPIO_DEFSTATE_OFF,
+	},
+	{
+		.name = "bt_led:blue",
+		.gpio = GPIO_RIGHT_LED_BT,
+		.active_low = 1,
+		.retain_state_suspended = 0,
+		.default_state = LEDS_GPIO_DEFSTATE_OFF,
+	},
+	{
+		.name = "right_led5:green",
+		.gpio = GPIO_RIGHT_LED_5,
+		.active_low = 1,
+		.retain_state_suspended = 0,
+		.default_state = LEDS_GPIO_DEFSTATE_OFF,
+	},
+};
+
+static struct gpio_led_platform_data gpio_leds_pdata = {
+	.num_leds = ARRAY_SIZE(gpio_exp_leds_config),
+	.leds = gpio_exp_leds_config,
+};
+
+static struct platform_device gpio_leds = {
+	.name          = "leds-gpio",
+	.id            = -1,
+	.dev           = {
+		.platform_data = &gpio_leds_pdata,
+	},
+};
+
+static struct gpio_led fluid_gpio_leds[] = {
+	{
+		.name			= "dual_led:green",
+		.gpio			= GPIO_LED1_GREEN_N,
+		.default_state		= LEDS_GPIO_DEFSTATE_OFF,
+		.active_low		= 1,
+		.retain_state_suspended = 0,
+	},
+	{
+		.name			= "dual_led:red",
+		.gpio			= GPIO_LED2_RED_N,
+		.default_state		= LEDS_GPIO_DEFSTATE_OFF,
+		.active_low		= 1,
+		.retain_state_suspended = 0,
+	},
+};
+
+static struct gpio_led_platform_data gpio_led_pdata = {
+	.leds		= fluid_gpio_leds,
+	.num_leds	= ARRAY_SIZE(fluid_gpio_leds),
+};
+
+static struct platform_device fluid_leds_gpio = {
+	.name	= "leds-gpio",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &gpio_led_pdata,
+	},
+};
+
+#endif
+
+#ifdef CONFIG_BATTERY_MSM8X60
+static struct msm_charger_platform_data msm_charger_data = {
+	.safety_time = 180,
+	.update_time = 1,
+	.max_voltage = 4200,
+	.min_voltage = 3200,
+};
+
+static struct platform_device msm_charger_device = {
+	.name = "msm-charger",
+	.id = -1,
+	.dev = {
+		.platform_data = &msm_charger_data,
+	}
+};
+#endif
+
+/*
+ * Consumer specific regulator names:
+ *			 regulator name		consumer dev_name
+ */
+static struct regulator_consumer_supply vreg_consumers_PM8058_L0[] = {
+	REGULATOR_SUPPLY("8058_l0",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L1[] = {
+	REGULATOR_SUPPLY("8058_l1",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L2[] = {
+	REGULATOR_SUPPLY("8058_l2",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L3[] = {
+	REGULATOR_SUPPLY("8058_l3",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L4[] = {
+	REGULATOR_SUPPLY("8058_l4",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L5[] = {
+	REGULATOR_SUPPLY("8058_l5",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L6[] = {
+	REGULATOR_SUPPLY("8058_l6",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L7[] = {
+	REGULATOR_SUPPLY("8058_l7",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L8[] = {
+	REGULATOR_SUPPLY("8058_l8",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L9[] = {
+	REGULATOR_SUPPLY("8058_l9",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L10[] = {
+	REGULATOR_SUPPLY("8058_l10",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L11[] = {
+	REGULATOR_SUPPLY("8058_l11",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L12[] = {
+	REGULATOR_SUPPLY("8058_l12",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L13[] = {
+	REGULATOR_SUPPLY("8058_l13",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L14[] = {
+	REGULATOR_SUPPLY("8058_l14",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L15[] = {
+	REGULATOR_SUPPLY("8058_l15",		NULL),
+	REGULATOR_SUPPLY("cam_vana",		"1-001a"),
+	REGULATOR_SUPPLY("cam_vana",		"1-006c"),
+	REGULATOR_SUPPLY("cam_vana",		"1-0078"),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L16[] = {
+	REGULATOR_SUPPLY("8058_l16",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L17[] = {
+	REGULATOR_SUPPLY("8058_l17",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L18[] = {
+	REGULATOR_SUPPLY("8058_l18",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L19[] = {
+	REGULATOR_SUPPLY("8058_l19",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L20[] = {
+	REGULATOR_SUPPLY("8058_l20",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L21[] = {
+	REGULATOR_SUPPLY("8058_l21",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L22[] = {
+	REGULATOR_SUPPLY("8058_l22",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L23[] = {
+	REGULATOR_SUPPLY("8058_l23",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L24[] = {
+	REGULATOR_SUPPLY("8058_l24",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L25[] = {
+	REGULATOR_SUPPLY("8058_l25",		NULL),
+	REGULATOR_SUPPLY("cam_vdig",		"1-001a"),
+	REGULATOR_SUPPLY("cam_vdig",		"1-006c"),
+	REGULATOR_SUPPLY("cam_vdig",		"1-0078"),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_S0[] = {
+	REGULATOR_SUPPLY("8058_s0",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_S1[] = {
+	REGULATOR_SUPPLY("8058_s1",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_S2[] = {
+	REGULATOR_SUPPLY("8058_s2",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_S3[] = {
+	REGULATOR_SUPPLY("8058_s3",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_S4[] = {
+	REGULATOR_SUPPLY("8058_s4",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_LVS0[] = {
+	REGULATOR_SUPPLY("8058_lvs0",		NULL),
+	REGULATOR_SUPPLY("cam_vio",			"1-001a"),
+	REGULATOR_SUPPLY("cam_vio",			"1-006c"),
+	REGULATOR_SUPPLY("cam_vio",			"1-0078"),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_LVS1[] = {
+	REGULATOR_SUPPLY("8058_lvs1",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_NCP[] = {
+	REGULATOR_SUPPLY("8058_ncp",		NULL),
+};
+
+static struct regulator_consumer_supply vreg_consumers_PM8901_L0[] = {
+	REGULATOR_SUPPLY("8901_l0",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8901_L1[] = {
+	REGULATOR_SUPPLY("8901_l1",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8901_L2[] = {
+	REGULATOR_SUPPLY("8901_l2",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8901_L3[] = {
+	REGULATOR_SUPPLY("8901_l3",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8901_L4[] = {
+	REGULATOR_SUPPLY("8901_l4",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8901_L5[] = {
+	REGULATOR_SUPPLY("8901_l5",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8901_L6[] = {
+	REGULATOR_SUPPLY("8901_l6",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8901_S2[] = {
+	REGULATOR_SUPPLY("8901_s2",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8901_S3[] = {
+	REGULATOR_SUPPLY("8901_s3",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8901_S4[] = {
+	REGULATOR_SUPPLY("8901_s4",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8901_LVS0[] = {
+	REGULATOR_SUPPLY("8901_lvs0",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8901_LVS1[] = {
+	REGULATOR_SUPPLY("8901_lvs1",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8901_LVS2[] = {
+	REGULATOR_SUPPLY("8901_lvs2",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8901_LVS3[] = {
+	REGULATOR_SUPPLY("8901_lvs3",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8901_MVS0[] = {
+	REGULATOR_SUPPLY("8901_mvs0",		NULL),
+};
+
+/* Pin control regulators */
+static struct regulator_consumer_supply vreg_consumers_PM8058_L8_PC[] = {
+	REGULATOR_SUPPLY("8058_l8_pc",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L20_PC[] = {
+	REGULATOR_SUPPLY("8058_l20_pc",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L21_PC[] = {
+	REGULATOR_SUPPLY("8058_l21_pc",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_S2_PC[] = {
+	REGULATOR_SUPPLY("8058_s2_pc",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8901_L0_PC[] = {
+	REGULATOR_SUPPLY("8901_l0_pc",		NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8901_S4_PC[] = {
+	REGULATOR_SUPPLY("8901_s4_pc",		NULL),
+};
+
+#define RPM_VREG_INIT(_id, _min_uV, _max_uV, _modes, _ops, _apply_uV, \
+		      _default_uV, _peak_uA, _avg_uA, _pull_down, _pin_ctrl, \
+		      _freq, _pin_fn, _force_mode, _sleep_set_force_mode, \
+		      _state, _sleep_selectable, _always_on) \
+	{ \
+		.init_data = { \
+			.constraints = { \
+				.valid_modes_mask	= _modes, \
+				.valid_ops_mask		= _ops, \
+				.min_uV			= _min_uV, \
+				.max_uV			= _max_uV, \
+				.input_uV		= _min_uV, \
+				.apply_uV		= _apply_uV, \
+				.always_on		= _always_on, \
+			}, \
+			.consumer_supplies	= vreg_consumers_##_id, \
+			.num_consumer_supplies	= \
+				ARRAY_SIZE(vreg_consumers_##_id), \
+		}, \
+		.id			= RPM_VREG_ID_##_id, \
+		.default_uV		= _default_uV, \
+		.peak_uA		= _peak_uA, \
+		.avg_uA			= _avg_uA, \
+		.pull_down_enable	= _pull_down, \
+		.pin_ctrl		= _pin_ctrl, \
+		.freq			= RPM_VREG_FREQ_##_freq, \
+		.pin_fn			= _pin_fn, \
+		.force_mode		= _force_mode, \
+		.sleep_set_force_mode	= _sleep_set_force_mode, \
+		.state			= _state, \
+		.sleep_selectable	= _sleep_selectable, \
+	}
+
+/* Pin control initialization */
+#define RPM_PC(_id, _always_on, _pin_fn, _pin_ctrl) \
+	{ \
+		.init_data = { \
+			.constraints = { \
+				.valid_ops_mask	= REGULATOR_CHANGE_STATUS, \
+				.always_on	= _always_on, \
+			}, \
+			.num_consumer_supplies	= \
+					ARRAY_SIZE(vreg_consumers_##_id##_PC), \
+			.consumer_supplies	= vreg_consumers_##_id##_PC, \
+		}, \
+		.id	  = RPM_VREG_ID_##_id##_PC, \
+		.pin_fn	  = RPM_VREG_PIN_FN_8660_##_pin_fn, \
+		.pin_ctrl = _pin_ctrl, \
+	}
+
+/*
+ * The default LPM/HPM state of an RPM controlled regulator can be controlled
+ * via the peak_uA value specified in the table below.  If the value is less
+ * than the high power min threshold for the regulator, then the regulator will
+ * be set to LPM.  Otherwise, it will be set to HPM.
+ *
+ * This value can be further overridden by specifying an initial mode via
+ * .init_data.constraints.initial_mode.
+ */
+
+#define RPM_LDO(_id, _always_on, _pd, _sleep_selectable, _min_uV, _max_uV, \
+		_init_peak_uA) \
+	RPM_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_FAST | \
+		      REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE | \
+		      REGULATOR_MODE_STANDBY, REGULATOR_CHANGE_VOLTAGE | \
+		      REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
+		      REGULATOR_CHANGE_DRMS, 0, _min_uV, _init_peak_uA, \
+		      _init_peak_uA, _pd, RPM_VREG_PIN_CTRL_NONE, NONE, \
+		      RPM_VREG_PIN_FN_8660_ENABLE, \
+		      RPM_VREG_FORCE_MODE_8660_NONE, \
+		      RPM_VREG_FORCE_MODE_8660_NONE, RPM_VREG_STATE_OFF, \
+		      _sleep_selectable, _always_on)
+
+#define RPM_SMPS(_id, _always_on, _pd, _sleep_selectable, _min_uV, _max_uV, \
+		 _init_peak_uA, _freq) \
+	RPM_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_FAST | \
+		      REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE | \
+		      REGULATOR_MODE_STANDBY, REGULATOR_CHANGE_VOLTAGE | \
+		      REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
+		      REGULATOR_CHANGE_DRMS, 0, _min_uV, _init_peak_uA, \
+		      _init_peak_uA, _pd, RPM_VREG_PIN_CTRL_NONE, _freq, \
+		      RPM_VREG_PIN_FN_8660_ENABLE, \
+		      RPM_VREG_FORCE_MODE_8660_NONE, \
+		      RPM_VREG_FORCE_MODE_8660_NONE, RPM_VREG_STATE_OFF, \
+		      _sleep_selectable, _always_on)
+
+#define RPM_VS(_id, _always_on, _pd, _sleep_selectable) \
+	RPM_VREG_INIT(_id, 0, 0, REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE, \
+		      REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE, 0, 0, \
+		      1000, 1000, _pd, RPM_VREG_PIN_CTRL_NONE, NONE, \
+		      RPM_VREG_PIN_FN_8660_ENABLE, \
+		      RPM_VREG_FORCE_MODE_8660_NONE, \
+		      RPM_VREG_FORCE_MODE_8660_NONE, RPM_VREG_STATE_OFF, \
+		      _sleep_selectable, _always_on)
+
+#define RPM_NCP(_id, _always_on, _pd, _sleep_selectable, _min_uV, _max_uV) \
+	RPM_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL, \
+		      REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, 0, \
+		      _min_uV, 1000, 1000, _pd, RPM_VREG_PIN_CTRL_NONE, NONE, \
+		      RPM_VREG_PIN_FN_8660_ENABLE, \
+		      RPM_VREG_FORCE_MODE_8660_NONE, \
+		      RPM_VREG_FORCE_MODE_8660_NONE, RPM_VREG_STATE_OFF, \
+		      _sleep_selectable, _always_on)
+
+#define LDO50HMIN	RPM_VREG_8660_LDO_50_HPM_MIN_LOAD
+#define LDO150HMIN	RPM_VREG_8660_LDO_150_HPM_MIN_LOAD
+#define LDO300HMIN	RPM_VREG_8660_LDO_300_HPM_MIN_LOAD
+#define SMPS_HMIN	RPM_VREG_8660_SMPS_HPM_MIN_LOAD
+#define FTS_HMIN	RPM_VREG_8660_FTSMPS_HPM_MIN_LOAD
+
+/* RPM early regulator constraints */
+static struct rpm_regulator_init_data rpm_regulator_early_init_data[] = {
+	/*	 ID       a_on pd ss min_uV   max_uV   init_ip    freq */
+	RPM_SMPS(PM8058_S0, 0, 1, 1,  500000, 1325000, SMPS_HMIN, 1p60),
+	RPM_SMPS(PM8058_S1, 0, 1, 1,  500000, 1250000, SMPS_HMIN, 1p60),
+};
+
+/* RPM regulator constraints */
+static struct rpm_regulator_init_data rpm_regulator_init_data[] = {
+	/*	ID        a_on pd ss min_uV   max_uV   init_ip */
+	RPM_LDO(PM8058_L0,  0, 1, 0, 1200000, 1200000, LDO150HMIN),
+	RPM_LDO(PM8058_L1,  0, 1, 0, 1200000, 1200000, LDO300HMIN),
+	RPM_LDO(PM8058_L2,  0, 1, 0, 1800000, 2600000, LDO300HMIN),
+	RPM_LDO(PM8058_L3,  0, 1, 0, 1800000, 1800000, LDO150HMIN),
+	RPM_LDO(PM8058_L4,  0, 1, 0, 2850000, 2850000,  LDO50HMIN),
+	RPM_LDO(PM8058_L5,  0, 1, 0, 2850000, 2850000, LDO300HMIN),
+	RPM_LDO(PM8058_L6,  0, 1, 0, 3000000, 3600000,  LDO50HMIN),
+	RPM_LDO(PM8058_L7,  0, 1, 0, 1800000, 1800000,  LDO50HMIN),
+	RPM_LDO(PM8058_L8,  0, 1, 0, 2900000, 3050000, LDO300HMIN),
+	RPM_LDO(PM8058_L9,  0, 1, 0, 1800000, 1800000, LDO300HMIN),
+	RPM_LDO(PM8058_L10, 0, 1, 0, 2600000, 2600000, LDO300HMIN),
+	RPM_LDO(PM8058_L11, 0, 1, 0, 1500000, 1500000, LDO150HMIN),
+	RPM_LDO(PM8058_L12, 0, 1, 0, 2900000, 2900000, LDO150HMIN),
+	RPM_LDO(PM8058_L13, 0, 1, 0, 2050000, 2050000, LDO300HMIN),
+	RPM_LDO(PM8058_L14, 0, 0, 0, 2850000, 2850000, LDO300HMIN),
+	RPM_LDO(PM8058_L15, 0, 1, 0, 2850000, 2850000, LDO300HMIN),
+	RPM_LDO(PM8058_L16, 1, 1, 0, 1800000, 1800000, LDO300HMIN),
+	RPM_LDO(PM8058_L17, 0, 1, 0, 2600000, 2600000, LDO150HMIN),
+	RPM_LDO(PM8058_L18, 0, 1, 0, 2200000, 2200000, LDO150HMIN),
+	RPM_LDO(PM8058_L19, 0, 1, 0, 2500000, 2500000, LDO150HMIN),
+	RPM_LDO(PM8058_L20, 0, 1, 0, 1800000, 1800000, LDO150HMIN),
+	RPM_LDO(PM8058_L21, 1, 1, 0, 1200000, 1200000, LDO150HMIN),
+	RPM_LDO(PM8058_L22, 0, 1, 0, 1150000, 1150000, LDO300HMIN),
+	RPM_LDO(PM8058_L23, 0, 1, 0, 1200000, 1200000, LDO300HMIN),
+	RPM_LDO(PM8058_L24, 0, 1, 0, 1200000, 1200000, LDO150HMIN),
+	RPM_LDO(PM8058_L25, 0, 1, 0, 1200000, 1200000, LDO150HMIN),
+
+	/*	 ID       a_on pd ss min_uV   max_uV   init_ip    freq */
+	RPM_SMPS(PM8058_S2, 0, 1, 1, 1200000, 1400000, SMPS_HMIN, 1p60),
+	RPM_SMPS(PM8058_S3, 1, 1, 0, 1800000, 1800000, SMPS_HMIN, 1p60),
+	RPM_SMPS(PM8058_S4, 1, 1, 0, 2200000, 2200000, SMPS_HMIN, 1p60),
+
+	/*     ID         a_on pd ss */
+	RPM_VS(PM8058_LVS0, 0, 1, 0),
+	RPM_VS(PM8058_LVS1, 0, 1, 0),
+
+	/*	ID        a_on pd ss min_uV   max_uV */
+	RPM_NCP(PM8058_NCP, 0, 1, 0, 1800000, 1800000),
+
+	/*	ID        a_on pd ss min_uV   max_uV   init_ip */
+	RPM_LDO(PM8901_L0,  0, 1, 0, 1200000, 1200000, LDO300HMIN),
+	RPM_LDO(PM8901_L1,  0, 1, 0, 3300000, 3300000, LDO300HMIN),
+	RPM_LDO(PM8901_L2,  0, 1, 0, 2850000, 3300000, LDO300HMIN),
+	RPM_LDO(PM8901_L3,  0, 1, 0, 3300000, 3300000, LDO300HMIN),
+	RPM_LDO(PM8901_L4,  0, 1, 0, 2600000, 2600000, LDO300HMIN),
+	RPM_LDO(PM8901_L5,  0, 1, 0, 2850000, 2850000, LDO300HMIN),
+	RPM_LDO(PM8901_L6,  0, 1, 0, 2200000, 2200000, LDO300HMIN),
+
+	/*	 ID       a_on pd ss min_uV   max_uV   init_ip   freq */
+	RPM_SMPS(PM8901_S2, 0, 1, 0, 1300000, 1300000, FTS_HMIN, 1p60),
+	RPM_SMPS(PM8901_S3, 0, 1, 0, 1100000, 1100000, FTS_HMIN, 1p60),
+	RPM_SMPS(PM8901_S4, 0, 1, 0, 1225000, 1225000, FTS_HMIN, 1p60),
+
+	/*	ID        a_on pd ss */
+	RPM_VS(PM8901_LVS0, 1, 1, 0),
+	RPM_VS(PM8901_LVS1, 0, 1, 0),
+	RPM_VS(PM8901_LVS2, 0, 1, 0),
+	RPM_VS(PM8901_LVS3, 0, 1, 0),
+	RPM_VS(PM8901_MVS0, 0, 1, 0),
+
+	/*     ID         a_on pin_func pin_ctrl */
+	RPM_PC(PM8058_L8,   0, SLEEP_B, RPM_VREG_PIN_CTRL_NONE),
+	RPM_PC(PM8058_L20,  0, SLEEP_B, RPM_VREG_PIN_CTRL_NONE),
+	RPM_PC(PM8058_L21,  1, SLEEP_B, RPM_VREG_PIN_CTRL_NONE),
+	RPM_PC(PM8058_S2,   0, ENABLE,  RPM_VREG_PIN_CTRL_PM8058_A0),
+	RPM_PC(PM8901_L0,   0, ENABLE,  RPM_VREG_PIN_CTRL_PM8901_A0),
+	RPM_PC(PM8901_S4,   0, ENABLE,  RPM_VREG_PIN_CTRL_PM8901_A0),
+};
+
+static struct rpm_regulator_platform_data rpm_regulator_early_pdata = {
+	.init_data		= rpm_regulator_early_init_data,
+	.num_regulators		= ARRAY_SIZE(rpm_regulator_early_init_data),
+	.version		= RPM_VREG_VERSION_8660,
+	.vreg_id_vdd_mem	= RPM_VREG_ID_PM8058_S0,
+	.vreg_id_vdd_dig	= RPM_VREG_ID_PM8058_S1,
+};
+
+static struct rpm_regulator_platform_data rpm_regulator_pdata = {
+	.init_data		= rpm_regulator_init_data,
+	.num_regulators		= ARRAY_SIZE(rpm_regulator_init_data),
+	.version		= RPM_VREG_VERSION_8660,
+};
+
+static struct platform_device rpm_regulator_early_device = {
+	.name	= "rpm-regulator",
+	.id	= 0,
+	.dev	= {
+		.platform_data = &rpm_regulator_early_pdata,
+	},
+};
+
+static struct platform_device rpm_regulator_device = {
+	.name	= "rpm-regulator",
+	.id	= 1,
+	.dev	= {
+		.platform_data = &rpm_regulator_pdata,
+	},
+};
+
+static struct platform_device *early_regulators[] __initdata = {
+	&msm_device_saw_s0,
+	&msm_device_saw_s1,
+	&rpm_regulator_early_device,
+};
+
+static struct platform_device *early_devices[] __initdata = {
+#ifdef CONFIG_MSM_BUS_SCALING
+	&msm_bus_apps_fabric,
+	&msm_bus_sys_fabric,
+	&msm_bus_mm_fabric,
+	&msm_bus_sys_fpb,
+	&msm_bus_cpss_fpb,
+#endif
+	&msm_device_dmov_adm0,
+	&msm_device_dmov_adm1,
+};
+
+#if (defined(CONFIG_MARIMBA_CORE)) && \
+	(defined(CONFIG_MSM_BT_POWER) || defined(CONFIG_MSM_BT_POWER_MODULE))
+
+static int bluetooth_power(int);
+static struct platform_device msm_bt_power_device = {
+	.name	 = "bt_power",
+	.id	 = -1,
+	.dev	 = {
+		.platform_data = &bluetooth_power,
+	},
+};
+#endif
+
+static struct platform_device msm_tsens_device = {
+	.name   = "tsens-tm",
+	.id = -1,
+};
+
+static struct platform_device *rumi_sim_devices[] __initdata = {
+	&smc91x_device,
+	&msm_device_uart_dm12,
+#ifdef CONFIG_I2C_QUP
+	&msm_gsbi3_qup_i2c_device,
+	&msm_gsbi4_qup_i2c_device,
+	&msm_gsbi7_qup_i2c_device,
+	&msm_gsbi8_qup_i2c_device,
+	&msm_gsbi9_qup_i2c_device,
+	&msm_gsbi12_qup_i2c_device,
+#endif
+#ifdef CONFIG_I2C_SSBI
+	&msm_device_ssbi3,
+#endif
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+	&android_pmem_device,
+	&android_pmem_adsp_device,
+	&android_pmem_smipool_device,
+	&android_pmem_audio_device,
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
+#ifdef CONFIG_MSM_ROTATOR
+	&msm_rotator_device,
+#endif
+	&msm_fb_device,
+	&msm_kgsl_3d0,
+	&msm_kgsl_2d0,
+	&msm_kgsl_2d1,
+	&lcdc_samsung_panel_device,
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+	&hdmi_msm_device,
+#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL */
+#ifdef CONFIG_MSM_CAMERA
+#ifndef CONFIG_MSM_CAMERA_V4L2
+#ifdef CONFIG_MT9E013
+	&msm_camera_sensor_mt9e013,
+#endif
+#ifdef CONFIG_IMX074
+	&msm_camera_sensor_imx074,
+#endif
+#ifdef CONFIG_VX6953
+	&msm_camera_sensor_vx6953,
+#endif
+#ifdef CONFIG_WEBCAM_OV7692
+	&msm_camera_sensor_webcam_ov7692,
+#endif
+#ifdef CONFIG_WEBCAM_OV9726
+	&msm_camera_sensor_webcam_ov9726,
+#endif
+#ifdef CONFIG_QS_S5K4E1
+	&msm_camera_sensor_qs_s5k4e1,
+#endif
+#endif
+#endif
+#ifdef CONFIG_MSM_GEMINI
+	&msm_gemini_device,
+#endif
+#ifdef CONFIG_MSM_VPE
+#ifndef CONFIG_MSM_CAMERA_V4L2
+	&msm_vpe_device,
+#endif
+#endif
+	&msm_device_vidc,
+};
+
+#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
+enum {
+	SX150X_CORE,
+	SX150X_DOCKING,
+	SX150X_SURF,
+	SX150X_LEFT_FHA,
+	SX150X_RIGHT_FHA,
+	SX150X_SOUTH,
+	SX150X_NORTH,
+	SX150X_CORE_FLUID,
+};
+
+static struct sx150x_platform_data sx150x_data[] __initdata = {
+	[SX150X_CORE] = {
+		.gpio_base         = GPIO_CORE_EXPANDER_BASE,
+		.oscio_is_gpo      = false,
+		.io_pullup_ena     = 0x0c08,
+		.io_pulldn_ena     = 0x4060,
+		.io_open_drain_ena = 0x000c,
+		.io_polarity       = 0,
+		.irq_summary       = -1, /* see fixup_i2c_configs() */
+		.irq_base          = GPIO_EXPANDER_IRQ_BASE,
+	},
+	[SX150X_DOCKING] = {
+		.gpio_base         = GPIO_DOCKING_EXPANDER_BASE,
+		.oscio_is_gpo      = false,
+		.io_pullup_ena     = 0x5e06,
+		.io_pulldn_ena     = 0x81b8,
+		.io_open_drain_ena = 0,
+		.io_polarity       = 0,
+		.irq_summary       = PM8058_GPIO_IRQ(PM8058_IRQ_BASE,
+						     UI_INT2_N),
+		.irq_base          = GPIO_EXPANDER_IRQ_BASE +
+				     GPIO_DOCKING_EXPANDER_BASE -
+				     GPIO_EXPANDER_GPIO_BASE,
+	},
+	[SX150X_SURF] = {
+		.gpio_base         = GPIO_SURF_EXPANDER_BASE,
+		.oscio_is_gpo      = false,
+		.io_pullup_ena     = 0,
+		.io_pulldn_ena     = 0,
+		.io_open_drain_ena = 0,
+		.io_polarity       = 0,
+		.irq_summary       = PM8058_GPIO_IRQ(PM8058_IRQ_BASE,
+						     UI_INT1_N),
+		.irq_base          = GPIO_EXPANDER_IRQ_BASE +
+				     GPIO_SURF_EXPANDER_BASE -
+				     GPIO_EXPANDER_GPIO_BASE,
+	},
+	[SX150X_LEFT_FHA] = {
+		.gpio_base         = GPIO_LEFT_KB_EXPANDER_BASE,
+		.oscio_is_gpo      = false,
+		.io_pullup_ena     = 0,
+		.io_pulldn_ena     = 0x40,
+		.io_open_drain_ena = 0,
+		.io_polarity       = 0,
+		.irq_summary       = PM8058_GPIO_IRQ(PM8058_IRQ_BASE,
+						     UI_INT3_N),
+		.irq_base          = GPIO_EXPANDER_IRQ_BASE +
+				     GPIO_LEFT_KB_EXPANDER_BASE -
+				     GPIO_EXPANDER_GPIO_BASE,
+	},
+	[SX150X_RIGHT_FHA] = {
+		.gpio_base         = GPIO_RIGHT_KB_EXPANDER_BASE,
+		.oscio_is_gpo      = true,
+		.io_pullup_ena     = 0,
+		.io_pulldn_ena     = 0,
+		.io_open_drain_ena = 0,
+		.io_polarity       = 0,
+		.irq_summary       = PM8058_GPIO_IRQ(PM8058_IRQ_BASE,
+						     UI_INT3_N),
+		.irq_base          = GPIO_EXPANDER_IRQ_BASE +
+				     GPIO_RIGHT_KB_EXPANDER_BASE -
+				     GPIO_EXPANDER_GPIO_BASE,
+	},
+	[SX150X_SOUTH] = {
+		.gpio_base    = GPIO_SOUTH_EXPANDER_BASE,
+		.irq_base     = GPIO_EXPANDER_IRQ_BASE +
+				GPIO_SOUTH_EXPANDER_BASE -
+				GPIO_EXPANDER_GPIO_BASE,
+		.irq_summary  = PM8058_GPIO_IRQ(PM8058_IRQ_BASE, UI_INT3_N),
+	},
+	[SX150X_NORTH] = {
+		.gpio_base    = GPIO_NORTH_EXPANDER_BASE,
+		.irq_base     = GPIO_EXPANDER_IRQ_BASE +
+				GPIO_NORTH_EXPANDER_BASE -
+				GPIO_EXPANDER_GPIO_BASE,
+		.irq_summary  = PM8058_GPIO_IRQ(PM8058_IRQ_BASE, UI_INT3_N),
+		.oscio_is_gpo = true,
+		.io_open_drain_ena = 0x30,
+	},
+	[SX150X_CORE_FLUID] = {
+		.gpio_base         = GPIO_CORE_EXPANDER_BASE,
+		.oscio_is_gpo      = false,
+		.io_pullup_ena     = 0x0408,
+		.io_pulldn_ena     = 0x4060,
+		.io_open_drain_ena = 0x0008,
+		.io_polarity       = 0,
+		.irq_summary       = -1, /* see fixup_i2c_configs() */
+		.irq_base          = GPIO_EXPANDER_IRQ_BASE,
+	},
+};
+
+#ifdef CONFIG_SENSORS_MSM_ADC
+/* Configuration of EPM expander is done when client
+ * request an adc read
+ */
+static struct sx150x_platform_data sx150x_epmdata = {
+	.gpio_base         = GPIO_EPM_EXPANDER_BASE,
+	.irq_base	   = GPIO_EXPANDER_IRQ_BASE +
+				GPIO_EPM_EXPANDER_BASE -
+				GPIO_EXPANDER_GPIO_BASE,
+	.irq_summary       = -1,
+};
+#endif
+
+/* sx150x_low_power_cfg
+ *
+ * This data and init function are used to put unused gpio-expander output
+ * lines into their low-power states at boot. The init
+ * function must be deferred until a later init stage because the i2c
+ * gpio expander drivers do not probe until after they are registered
+ * (see register_i2c_devices) and the work-queues for those registrations
+ * are processed.  Because these lines are unused, there is no risk of
+ * competing with a device driver for the gpio.
+ *
+ * gpio lines whose low-power states are input are naturally in their low-
+ * power configurations once probed, see the platform data structures above.
+ */
+struct sx150x_low_power_cfg {
+	unsigned gpio;
+	unsigned val;
+};
+
+static struct sx150x_low_power_cfg
+common_sx150x_lp_cfgs[] __initdata = {
+	{GPIO_WLAN_DEEP_SLEEP_N, 0},
+	{GPIO_EXT_GPS_LNA_EN,    0},
+	{GPIO_MSM_WAKES_BT,      0},
+	{GPIO_USB_UICC_EN,       0},
+	{GPIO_BATT_GAUGE_EN,     0},
+};
+
+static struct sx150x_low_power_cfg
+surf_ffa_sx150x_lp_cfgs[] __initdata = {
+	{GPIO_MIPI_DSI_RST_N,      0},
+	{GPIO_DONGLE_PWR_EN,       0},
+	{GPIO_CAP_TS_SLEEP,        1},
+	{GPIO_WEB_CAMIF_RESET_N,   0},
+};
+
+static void __init
+cfg_gpio_low_power(struct sx150x_low_power_cfg *cfgs, unsigned nelems)
+{
+	unsigned n;
+	int rc;
+
+	for (n = 0; n < nelems; ++n) {
+		rc = gpio_request(cfgs[n].gpio, NULL);
+		if (!rc) {
+			rc = gpio_direction_output(cfgs[n].gpio, cfgs[n].val);
+			gpio_free(cfgs[n].gpio);
+		}
+
+		if (rc) {
+			printk(KERN_NOTICE "%s: failed to sleep gpio %d: %d\n",
+			       __func__, cfgs[n].gpio, rc);
+		}
+	}
+}
+
+static int __init cfg_sx150xs_low_power(void)
+{
+	cfg_gpio_low_power(common_sx150x_lp_cfgs,
+		ARRAY_SIZE(common_sx150x_lp_cfgs));
+	if (!machine_is_msm8x60_fluid())
+		cfg_gpio_low_power(surf_ffa_sx150x_lp_cfgs,
+			ARRAY_SIZE(surf_ffa_sx150x_lp_cfgs));
+	return 0;
+}
+module_init(cfg_sx150xs_low_power);
+
+#ifdef CONFIG_I2C
+static struct i2c_board_info core_expander_i2c_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("sx1509q", 0x3e),
+		.platform_data = &sx150x_data[SX150X_CORE]
+	},
+};
+
+static struct i2c_board_info docking_expander_i2c_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("sx1509q", 0x3f),
+		.platform_data = &sx150x_data[SX150X_DOCKING]
+	},
+};
+
+static struct i2c_board_info surf_expanders_i2c_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("sx1509q", 0x70),
+		.platform_data = &sx150x_data[SX150X_SURF]
+	}
+};
+
+static struct i2c_board_info fha_expanders_i2c_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("sx1508q", 0x21),
+		.platform_data = &sx150x_data[SX150X_LEFT_FHA]
+	},
+	{
+		I2C_BOARD_INFO("sx1508q", 0x22),
+		.platform_data = &sx150x_data[SX150X_RIGHT_FHA]
+	}
+};
+
+static struct i2c_board_info fluid_expanders_i2c_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("sx1508q", 0x23),
+		.platform_data = &sx150x_data[SX150X_SOUTH]
+	},
+	{
+		I2C_BOARD_INFO("sx1508q", 0x20),
+		.platform_data = &sx150x_data[SX150X_NORTH]
+	}
+};
+
+static struct i2c_board_info fluid_core_expander_i2c_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("sx1509q", 0x3e),
+		.platform_data = &sx150x_data[SX150X_CORE_FLUID]
+	},
+};
+
+#ifdef CONFIG_SENSORS_MSM_ADC
+static struct i2c_board_info fluid_expanders_i2c_epm_info[] = {
+	{
+		I2C_BOARD_INFO("sx1509q", 0x3e),
+		.platform_data = &sx150x_epmdata
+	},
+};
+#endif
+#endif
+#endif
+
+#ifdef CONFIG_SENSORS_MSM_ADC
+
+static struct adc_access_fn xoadc_fn = {
+	pm8058_xoadc_select_chan_and_start_conv,
+	pm8058_xoadc_read_adc_code,
+	pm8058_xoadc_get_properties,
+	pm8058_xoadc_slot_request,
+	pm8058_xoadc_restore_slot,
+	pm8058_xoadc_calibrate,
+};
+
+#if defined(CONFIG_I2C) && \
+	(defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE))
+static struct regulator *vreg_adc_epm1;
+
+static struct i2c_client *epm_expander_i2c_register_board(void)
+
+{
+	struct i2c_adapter *i2c_adap;
+	struct i2c_client *client = NULL;
+	i2c_adap = i2c_get_adapter(0x0);
+
+	if (i2c_adap == NULL)
+		printk(KERN_ERR "\nepm_expander_i2c_adapter is NULL\n");
+
+	if (i2c_adap != NULL)
+		client = i2c_new_device(i2c_adap,
+			&fluid_expanders_i2c_epm_info[0]);
+	return client;
+
+}
+
+static unsigned int msm_adc_gpio_configure_expander_enable(void)
+{
+	int rc = 0;
+	static struct i2c_client *epm_i2c_client;
+
+	printk(KERN_DEBUG "Enter msm_adc_gpio_configure_expander_enable\n");
+
+	vreg_adc_epm1 = regulator_get(NULL, "8058_s3");
+
+	if (IS_ERR(vreg_adc_epm1)) {
+		printk(KERN_ERR "%s: Unable to get 8058_s3\n", __func__);
+		return 0;
+	}
+
+	rc = regulator_set_voltage(vreg_adc_epm1, 1800000, 1800000);
+	if (rc)
+		printk(KERN_ERR "msm_adc_gpio_configure_expander_enable: "
+				"regulator set voltage failed\n");
+
+	rc = regulator_enable(vreg_adc_epm1);
+	if (rc) {
+		printk(KERN_ERR "msm_adc_gpio_configure_expander_enable: "
+			"Error while enabling regulator for epm s3 %d\n", rc);
+		return rc;
+	}
+
+	printk(KERN_DEBUG "msm_adc_gpio_configure_expander_enable: Start"
+			" setting the value of the EPM 3.3, 5v and lvlsft\n");
+
+	msleep(1000);
+
+	rc = gpio_request(GPIO_EPM_5V_BOOST_EN, "boost_epm_5v");
+	if (!rc) {
+		printk(KERN_DEBUG "msm_adc_gpio_configure_expander_enable: "
+				"Configure 5v boost\n");
+		gpio_direction_output(GPIO_EPM_5V_BOOST_EN, 1);
+	} else {
+		printk(KERN_ERR "msm_adc_gpio_configure_expander_enable: "
+				"Error for epm 5v boost en\n");
+		goto exit_vreg_epm;
+	}
+
+	msleep(500);
+
+	rc = gpio_request(GPIO_EPM_3_3V_EN, "epm_3_3v");
+	if (!rc) {
+		gpio_direction_output(GPIO_EPM_3_3V_EN, 1);
+		printk(KERN_DEBUG "msm_adc_gpio_configure_expander_enable: "
+				"Configure epm 3.3v\n");
+	} else {
+		printk(KERN_ERR "msm_adc_gpio_configure_expander_enable: "
+				"Error for gpio 3.3ven\n");
+		goto exit_vreg_epm;
+	}
+	msleep(500);
+
+	printk(KERN_DEBUG "msm_adc_gpio_configure_expander_enable: "
+			"Trying to request EPM LVLSFT_EN\n");
+	rc = gpio_request(GPIO_EPM_LVLSFT_EN, "lvsft_en");
+	if (!rc) {
+		gpio_direction_output(GPIO_EPM_LVLSFT_EN, 1);
+		printk(KERN_DEBUG "msm_adc_gpio_configure_expander_enable: "
+				"Configure the lvlsft\n");
+	} else {
+		printk(KERN_ERR "msm_adc_gpio_configure_expander_enable: "
+				"Error for epm lvlsft_en\n");
+		goto exit_vreg_epm;
+	}
+
+	msleep(500);
+
+	if (!epm_i2c_client)
+		epm_i2c_client = epm_expander_i2c_register_board();
+
+	rc = gpio_request(GPIO_PWR_MON_ENABLE, "pwr_mon_enable");
+	if (!rc)
+		rc = gpio_direction_output(GPIO_PWR_MON_ENABLE, 1);
+		if (rc) {
+			printk(KERN_ERR "msm_adc_gpio_configure_expander_enable"
+					": GPIO PWR MON Enable issue\n");
+			goto exit_vreg_epm;
+		}
+
+	msleep(1000);
+
+	rc = gpio_request(GPIO_ADC1_PWDN_N, "adc1_pwdn");
+	if (!rc) {
+		rc = gpio_direction_output(GPIO_ADC1_PWDN_N, 1);
+		if (rc) {
+			printk(KERN_ERR "msm_adc_gpio_configure_expander_enable"
+					": ADC1_PWDN error direction out\n");
+			goto exit_vreg_epm;
+		}
+	}
+
+	msleep(100);
+
+	rc = gpio_request(GPIO_ADC2_PWDN_N, "adc2_pwdn");
+	if (!rc) {
+		rc = gpio_direction_output(GPIO_ADC2_PWDN_N, 1);
+		if (rc) {
+			printk(KERN_ERR "msm_adc_gpio_configure_expander_enable"
+					": ADC2_PWD error direction out\n");
+			goto exit_vreg_epm;
+		}
+	}
+
+	msleep(1000);
+
+	rc = gpio_request(GPIO_PWR_MON_START, "pwr_mon_start");
+	if (!rc) {
+		rc = gpio_direction_output(GPIO_PWR_MON_START, 0);
+		if (rc) {
+			printk(KERN_ERR "msm_adc_gpio_configure_expander_enable"
+				"Gpio request problem %d\n", rc);
+			goto exit_vreg_epm;
+		}
+	}
+
+	rc = gpio_request(GPIO_EPM_SPI_ADC1_CS_N, "spi_adc1_cs");
+	if (!rc) {
+		rc = gpio_direction_output(GPIO_EPM_SPI_ADC1_CS_N, 0);
+		if (rc) {
+			printk(KERN_ERR "msm_adc_gpio_configure_expander_enable"
+					": EPM_SPI_ADC1_CS_N error\n");
+			goto exit_vreg_epm;
+		}
+	}
+
+	rc = gpio_request(GPIO_EPM_SPI_ADC2_CS_N, "spi_adc2_cs");
+	if (!rc) {
+		rc = gpio_direction_output(GPIO_EPM_SPI_ADC2_CS_N, 0);
+		if (rc) {
+			printk(KERN_ERR "msm_adc_gpio_configure_expander_enable"
+					": EPM_SPI_ADC2_Cs_N error\n");
+			goto exit_vreg_epm;
+		}
+	}
+
+	printk(KERN_DEBUG "msm_adc_gpio_configure_expander_enable: Set "
+			"the power monitor reset for epm\n");
+
+	rc = gpio_request(GPIO_PWR_MON_RESET_N, "pwr_mon_reset_n");
+	if (!rc) {
+		gpio_direction_output(GPIO_PWR_MON_RESET_N, 0);
+		if (rc)	{
+			printk(KERN_ERR "msm_adc_gpio_configure_expander_enable"
+					": Error in the power mon reset\n");
+			goto exit_vreg_epm;
+		}
+	}
+
+	msleep(1000);
+
+	gpio_set_value_cansleep(GPIO_PWR_MON_RESET_N, 1);
+
+	msleep(500);
+
+	gpio_set_value_cansleep(GPIO_EPM_SPI_ADC1_CS_N, 1);
+
+	gpio_set_value_cansleep(GPIO_EPM_SPI_ADC2_CS_N, 1);
+
+	return rc;
+
+exit_vreg_epm:
+	regulator_disable(vreg_adc_epm1);
+
+	printk(KERN_ERR "msm_adc_gpio_configure_expander_enable: Exit."
+			" rc = %d.\n", rc);
+	return rc;
+};
+
+static unsigned int msm_adc_gpio_configure_expander_disable(void)
+{
+	int rc = 0;
+
+	gpio_set_value_cansleep(GPIO_PWR_MON_RESET_N, 0);
+	gpio_free(GPIO_PWR_MON_RESET_N);
+
+	gpio_set_value_cansleep(GPIO_EPM_SPI_ADC1_CS_N, 0);
+	gpio_free(GPIO_EPM_SPI_ADC1_CS_N);
+
+	gpio_set_value_cansleep(GPIO_EPM_SPI_ADC2_CS_N, 0);
+	gpio_free(GPIO_EPM_SPI_ADC2_CS_N);
+
+	gpio_set_value_cansleep(GPIO_PWR_MON_START, 0);
+	gpio_free(GPIO_PWR_MON_START);
+
+	gpio_direction_output(GPIO_ADC1_PWDN_N, 0);
+	gpio_free(GPIO_ADC1_PWDN_N);
+
+	gpio_direction_output(GPIO_ADC2_PWDN_N, 0);
+	gpio_free(GPIO_ADC2_PWDN_N);
+
+	gpio_set_value_cansleep(GPIO_PWR_MON_ENABLE, 0);
+	gpio_free(GPIO_PWR_MON_ENABLE);
+
+	gpio_set_value_cansleep(GPIO_EPM_LVLSFT_EN, 0);
+	gpio_free(GPIO_EPM_LVLSFT_EN);
+
+	gpio_set_value_cansleep(GPIO_EPM_5V_BOOST_EN, 0);
+	gpio_free(GPIO_EPM_5V_BOOST_EN);
+
+	gpio_set_value_cansleep(GPIO_EPM_3_3V_EN, 0);
+	gpio_free(GPIO_EPM_3_3V_EN);
+
+	rc = regulator_disable(vreg_adc_epm1);
+	if (rc)
+		printk(KERN_DEBUG "msm_adc_gpio_configure_expander_disable: "
+			"Error while enabling regulator for epm s3 %d\n", rc);
+	regulator_put(vreg_adc_epm1);
+
+	printk(KERN_DEBUG "Exi msm_adc_gpio_configure_expander_disable\n");
+	return rc;
+};
+
+unsigned int msm_adc_gpio_expander_enable(int cs_enable)
+{
+	int rc = 0;
+
+	printk(KERN_DEBUG "msm_adc_gpio_expander_enable: cs_enable = %d",
+		cs_enable);
+
+	if (cs_enable < 16) {
+		gpio_set_value_cansleep(GPIO_EPM_SPI_ADC1_CS_N, 0);
+		gpio_set_value_cansleep(GPIO_EPM_SPI_ADC2_CS_N, 1);
+	} else {
+		gpio_set_value_cansleep(GPIO_EPM_SPI_ADC2_CS_N, 0);
+		gpio_set_value_cansleep(GPIO_EPM_SPI_ADC1_CS_N, 1);
+	}
+	return rc;
+};
+
+unsigned int msm_adc_gpio_expander_disable(int cs_disable)
+{
+	int rc = 0;
+
+	printk(KERN_DEBUG "Enter msm_adc_gpio_expander_disable.\n");
+
+	gpio_set_value_cansleep(GPIO_EPM_SPI_ADC1_CS_N, 1);
+
+	gpio_set_value_cansleep(GPIO_EPM_SPI_ADC2_CS_N, 1);
+
+	return rc;
+};
+#endif
+
+static struct msm_adc_channels msm_adc_channels_data[] = {
+	{"vbatt", CHANNEL_ADC_VBATT, 0, &xoadc_fn, CHAN_PATH_TYPE2,
+		ADC_CONFIG_TYPE2, ADC_CALIB_CONFIG_TYPE3, scale_default},
+	{"vcoin", CHANNEL_ADC_VCOIN, 0, &xoadc_fn, CHAN_PATH_TYPE1,
+		ADC_CONFIG_TYPE2, ADC_CALIB_CONFIG_TYPE2, scale_default},
+	{"vcharger_channel", CHANNEL_ADC_VCHG, 0, &xoadc_fn, CHAN_PATH_TYPE3,
+		ADC_CONFIG_TYPE2, ADC_CALIB_CONFIG_TYPE4, scale_default},
+	{"charger_current_monitor", CHANNEL_ADC_CHG_MONITOR, 0, &xoadc_fn,
+		CHAN_PATH_TYPE4,
+		ADC_CONFIG_TYPE2, ADC_CALIB_CONFIG_TYPE1, scale_default},
+	{"vph_pwr", CHANNEL_ADC_VPH_PWR, 0, &xoadc_fn, CHAN_PATH_TYPE5,
+		ADC_CONFIG_TYPE2, ADC_CALIB_CONFIG_TYPE3, scale_default},
+	{"usb_vbus", CHANNEL_ADC_USB_VBUS, 0, &xoadc_fn, CHAN_PATH_TYPE11,
+		ADC_CONFIG_TYPE2, ADC_CALIB_CONFIG_TYPE3, scale_default},
+	{"pmic_therm", CHANNEL_ADC_DIE_TEMP, 0, &xoadc_fn, CHAN_PATH_TYPE12,
+		ADC_CONFIG_TYPE2, ADC_CALIB_CONFIG_TYPE1, scale_pmic_therm},
+	{"pmic_therm_4K", CHANNEL_ADC_DIE_TEMP_4K, 0, &xoadc_fn,
+		CHAN_PATH_TYPE12,
+		ADC_CONFIG_TYPE1, ADC_CALIB_CONFIG_TYPE7, scale_pmic_therm},
+	{"xo_therm", CHANNEL_ADC_XOTHERM, 0, &xoadc_fn, CHAN_PATH_TYPE_NONE,
+		ADC_CONFIG_TYPE2, ADC_CALIB_CONFIG_TYPE5, tdkntcgtherm},
+	{"xo_therm_4K", CHANNEL_ADC_XOTHERM_4K, 0, &xoadc_fn,
+		CHAN_PATH_TYPE_NONE,
+		ADC_CONFIG_TYPE1, ADC_CALIB_CONFIG_TYPE6, tdkntcgtherm},
+	{"hdset_detect", CHANNEL_ADC_HDSET, 0, &xoadc_fn, CHAN_PATH_TYPE6,
+		ADC_CONFIG_TYPE2, ADC_CALIB_CONFIG_TYPE1, scale_default},
+	{"chg_batt_amon", CHANNEL_ADC_BATT_AMON, 0, &xoadc_fn, CHAN_PATH_TYPE10,
+		ADC_CONFIG_TYPE2, ADC_CALIB_CONFIG_TYPE1,
+		scale_xtern_chgr_cur},
+	{"msm_therm", CHANNEL_ADC_MSM_THERM, 0, &xoadc_fn, CHAN_PATH_TYPE8,
+		ADC_CONFIG_TYPE2, ADC_CALIB_CONFIG_TYPE2, scale_msm_therm},
+	{"batt_therm", CHANNEL_ADC_BATT_THERM, 0, &xoadc_fn, CHAN_PATH_TYPE7,
+		ADC_CONFIG_TYPE2, ADC_CALIB_CONFIG_TYPE2, scale_batt_therm},
+	{"batt_id", CHANNEL_ADC_BATT_ID, 0, &xoadc_fn, CHAN_PATH_TYPE9,
+		ADC_CONFIG_TYPE2, ADC_CALIB_CONFIG_TYPE2, scale_default},
+	{"ref_625mv", CHANNEL_ADC_625_REF, 0, &xoadc_fn, CHAN_PATH_TYPE15,
+		ADC_CONFIG_TYPE2, ADC_CALIB_CONFIG_TYPE2, scale_default},
+	{"ref_1250mv", CHANNEL_ADC_1250_REF, 0, &xoadc_fn, CHAN_PATH_TYPE13,
+		ADC_CONFIG_TYPE2, ADC_CALIB_CONFIG_TYPE2, scale_default},
+	{"ref_325mv", CHANNEL_ADC_325_REF, 0, &xoadc_fn, CHAN_PATH_TYPE14,
+		ADC_CONFIG_TYPE2, ADC_CALIB_CONFIG_TYPE2, scale_default},
+};
+
+static char *msm_adc_fluid_device_names[] = {
+	"ADS_ADC1",
+	"ADS_ADC2",
+};
+
+static struct msm_adc_platform_data msm_adc_pdata = {
+	.channel = msm_adc_channels_data,
+	.num_chan_supported = ARRAY_SIZE(msm_adc_channels_data),
+#if defined(CONFIG_I2C) && \
+	(defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE))
+	.adc_gpio_enable = msm_adc_gpio_expander_enable,
+	.adc_gpio_disable   = msm_adc_gpio_expander_disable,
+	.adc_fluid_enable = msm_adc_gpio_configure_expander_enable,
+	.adc_fluid_disable  = msm_adc_gpio_configure_expander_disable,
+#endif
+};
+
+static struct platform_device msm_adc_device = {
+	.name   = "msm_adc",
+	.id = -1,
+	.dev = {
+		.platform_data = &msm_adc_pdata,
+	},
+};
+
+static struct msm_rtb_platform_data msm_rtb_pdata = {
+	.size = SZ_1M,
+};
+
+static int __init msm_rtb_set_buffer_size(char *p)
+{
+	int s;
+
+	s = memparse(p, NULL);
+	msm_rtb_pdata.size = ALIGN(s, SZ_4K);
+	return 0;
+}
+early_param("msm_rtb_size", msm_rtb_set_buffer_size);
+
+
+static struct platform_device msm_rtb_device = {
+	.name           = "msm_rtb",
+	.id             = -1,
+	.dev            = {
+		.platform_data = &msm_rtb_pdata,
+	},
+};
+
+static void pmic8058_xoadc_mpp_config(void)
+{
+	int rc, i;
+	struct pm8xxx_mpp_init_info xoadc_mpps[] = {
+		PM8058_MPP_INIT(XOADC_MPP_3, A_INPUT, PM8XXX_MPP_AIN_AMUX_CH5,
+							AOUT_CTRL_DISABLE),
+		PM8058_MPP_INIT(XOADC_MPP_5, A_INPUT, PM8XXX_MPP_AIN_AMUX_CH9,
+							AOUT_CTRL_DISABLE),
+		PM8058_MPP_INIT(XOADC_MPP_7, A_INPUT, PM8XXX_MPP_AIN_AMUX_CH6,
+							AOUT_CTRL_DISABLE),
+		PM8058_MPP_INIT(XOADC_MPP_8, A_INPUT, PM8XXX_MPP_AIN_AMUX_CH8,
+							AOUT_CTRL_DISABLE),
+		PM8058_MPP_INIT(XOADC_MPP_10, A_INPUT, PM8XXX_MPP_AIN_AMUX_CH7,
+							AOUT_CTRL_DISABLE),
+		PM8901_MPP_INIT(XOADC_MPP_4, D_OUTPUT, PM8901_MPP_DIG_LEVEL_S4,
+							DOUT_CTRL_LOW),
+	};
+
+	for (i = 0; i < ARRAY_SIZE(xoadc_mpps); i++) {
+		rc = pm8xxx_mpp_config(xoadc_mpps[i].mpp,
+					&xoadc_mpps[i].config);
+		if (rc) {
+			pr_err("%s: Config MPP %d of PM8058 failed\n",
+					__func__, xoadc_mpps[i].mpp);
+		}
+	}
+}
+
+static struct regulator *vreg_ldo18_adc;
+
+static int pmic8058_xoadc_vreg_config(int on)
+{
+	int rc;
+
+	if (on) {
+		rc = regulator_enable(vreg_ldo18_adc);
+		if (rc)
+			pr_err("%s: Enable of regulator ldo18_adc "
+						"failed\n", __func__);
+	} else {
+		rc = regulator_disable(vreg_ldo18_adc);
+		if (rc)
+			pr_err("%s: Disable of regulator ldo18_adc "
+						"failed\n", __func__);
+	}
+
+	return rc;
+}
+
+static int pmic8058_xoadc_vreg_setup(void)
+{
+	int rc;
+
+	vreg_ldo18_adc = regulator_get(NULL, "8058_l18");
+	if (IS_ERR(vreg_ldo18_adc)) {
+		printk(KERN_ERR "%s: vreg get failed (%ld)\n",
+			__func__, PTR_ERR(vreg_ldo18_adc));
+		rc = PTR_ERR(vreg_ldo18_adc);
+		goto fail;
+	}
+
+	rc = regulator_set_voltage(vreg_ldo18_adc, 2200000, 2200000);
+	if (rc) {
+		pr_err("%s: unable to set ldo18 voltage to 2.2V\n", __func__);
+		goto fail;
+	}
+
+	return rc;
+fail:
+	regulator_put(vreg_ldo18_adc);
+	return rc;
+}
+
+static void pmic8058_xoadc_vreg_shutdown(void)
+{
+	regulator_put(vreg_ldo18_adc);
+}
+
+/* usec. For this ADC,
+ * this time represents clk rate @ txco w/ 1024 decimation ratio.
+ * Each channel has different configuration, thus at the time of starting
+ * the conversion, xoadc will return actual conversion time
+ * */
+static struct adc_properties pm8058_xoadc_data = {
+	.adc_reference          = 2200, /* milli-voltage for this adc */
+	.bitresolution         = 15,
+	.bipolar                = 0,
+	.conversiontime         = 54,
+};
+
+static struct xoadc_platform_data pm8058_xoadc_pdata = {
+	.xoadc_prop = &pm8058_xoadc_data,
+	.xoadc_mpp_config = pmic8058_xoadc_mpp_config,
+	.xoadc_vreg_set = pmic8058_xoadc_vreg_config,
+	.xoadc_num = XOADC_PMIC_0,
+	.xoadc_vreg_setup = pmic8058_xoadc_vreg_setup,
+	.xoadc_vreg_shutdown = pmic8058_xoadc_vreg_shutdown,
+};
+#endif
+
+#ifdef CONFIG_MSM_SDIO_AL
+
+static unsigned mdm2ap_status = 140;
+
+static int configure_mdm2ap_status(int on)
+{
+	int ret = 0;
+	if (on)
+		ret = msm_gpiomux_get(mdm2ap_status);
+	else
+		ret = msm_gpiomux_put(mdm2ap_status);
+
+	if (ret)
+		pr_err("%s: mdm2ap_status config failed, on = %d\n", __func__,
+		       on);
+
+	return ret;
+}
+
+
+static int get_mdm2ap_status(void)
+{
+	return gpio_get_value(mdm2ap_status);
+}
+
+static struct sdio_al_platform_data sdio_al_pdata = {
+	.config_mdm2ap_status = configure_mdm2ap_status,
+	.get_mdm2ap_status = get_mdm2ap_status,
+	.allow_sdioc_version_major_2 = 0,
+	.peer_sdioc_version_minor = 0x0202,
+	.peer_sdioc_version_major = 0x0004,
+	.peer_sdioc_boot_version_minor = 0x0001,
+	.peer_sdioc_boot_version_major = 0x0003
+};
+
+struct platform_device msm_device_sdio_al = {
+	.name = "msm_sdio_al",
+	.id = -1,
+	.dev		= {
+		.parent = &msm_charm_modem.dev,
+		.platform_data	= &sdio_al_pdata,
+	},
+};
+
+#endif /* CONFIG_MSM_SDIO_AL */
+
+#define GPIO_VREG_ID_EXT_5V		0
+
+static struct regulator_consumer_supply vreg_consumers_EXT_5V[] = {
+	REGULATOR_SUPPLY("ext_5v",	NULL),
+	REGULATOR_SUPPLY("8901_mpp0",	NULL),
+};
+
+#define GPIO_VREG_INIT(_id, _reg_name, _gpio_label, _gpio, _active_low) \
+	[GPIO_VREG_ID_##_id] = { \
+		.init_data = { \
+			.constraints = { \
+				.valid_ops_mask	= REGULATOR_CHANGE_STATUS, \
+			}, \
+			.num_consumer_supplies	= \
+					ARRAY_SIZE(vreg_consumers_##_id), \
+			.consumer_supplies	= vreg_consumers_##_id, \
+		}, \
+		.regulator_name	= _reg_name, \
+		.active_low	= _active_low, \
+		.gpio_label	= _gpio_label, \
+		.gpio		= _gpio, \
+	}
+
+/* GPIO regulator constraints */
+static struct gpio_regulator_platform_data msm_gpio_regulator_pdata[] = {
+	GPIO_VREG_INIT(EXT_5V, "ext_5v", "ext_5v_en",
+					PM8901_MPP_PM_TO_SYS(0), 0),
+};
+
+/* GPIO regulator */
+static struct platform_device msm8x60_8901_mpp_vreg __devinitdata = {
+	.name	= GPIO_REGULATOR_DEV_NAME,
+	.id	= PM8901_MPP_PM_TO_SYS(0),
+	.dev	= {
+		.platform_data =
+			&msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_5V],
+	},
+};
+
+static void __init pm8901_vreg_mpp0_init(void)
+{
+	int rc;
+
+	struct pm8xxx_mpp_init_info pm8901_vreg_mpp0 = {
+		.mpp	= PM8901_MPP_PM_TO_SYS(0),
+		.config =  {
+			.type	= PM8XXX_MPP_TYPE_D_OUTPUT,
+			.level	= PM8901_MPP_DIG_LEVEL_VPH,
+		},
+	};
+
+	/*
+	 * Set PMIC 8901 MPP0 active_high to 0 for surf and charm_surf. This
+	 * implies that the regulator connected to MPP0 is enabled when
+	 * MPP0 is low.
+	 */
+	if (machine_is_msm8x60_surf() || machine_is_msm8x60_fusion()) {
+		msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_5V].active_low = 1;
+		pm8901_vreg_mpp0.config.control = PM8XXX_MPP_DOUT_CTRL_HIGH;
+	} else {
+		msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_5V].active_low = 0;
+		pm8901_vreg_mpp0.config.control = PM8XXX_MPP_DOUT_CTRL_LOW;
+	}
+
+	rc = pm8xxx_mpp_config(pm8901_vreg_mpp0.mpp, &pm8901_vreg_mpp0.config);
+	if (rc)
+		pr_err("%s: pm8xxx_mpp_config: rc=%d\n", __func__, rc);
+}
+
+static struct platform_device *charm_devices[] __initdata = {
+	&msm_charm_modem,
+#ifdef CONFIG_MSM_SDIO_AL
+	&msm_device_sdio_al,
+#endif
+};
+
+#ifdef CONFIG_SND_SOC_MSM8660_APQ
+static struct platform_device *dragon_alsa_devices[] __initdata = {
+	&msm_pcm,
+	&msm_pcm_routing,
+	&msm_cpudai0,
+	&msm_cpudai1,
+	&msm_cpudai_hdmi_rx,
+	&msm_cpudai_bt_rx,
+	&msm_cpudai_bt_tx,
+	&msm_cpudai_fm_rx,
+	&msm_cpudai_fm_tx,
+	&msm_cpu_fe,
+	&msm_stub_codec,
+	&msm_lpa_pcm,
+};
+#endif
+
+static struct platform_device *asoc_devices[] __initdata = {
+	&asoc_msm_pcm,
+	&asoc_msm_dai0,
+	&asoc_msm_dai1,
+};
+
+static struct platform_device *surf_devices[] __initdata = {
+	&msm_device_smd,
+	&msm_device_uart_dm12,
+	&msm_pil_q6v3,
+	&msm_pil_modem,
+	&msm_pil_tzapps,
+	&msm_pil_dsps,
+#ifdef CONFIG_I2C_QUP
+	&msm_gsbi3_qup_i2c_device,
+	&msm_gsbi4_qup_i2c_device,
+	&msm_gsbi7_qup_i2c_device,
+	&msm_gsbi8_qup_i2c_device,
+	&msm_gsbi9_qup_i2c_device,
+	&msm_gsbi12_qup_i2c_device,
+#endif
+#ifdef CONFIG_SERIAL_MSM_HS
+	&msm_device_uart_dm1,
+#endif
+#ifdef CONFIG_MSM_SSBI
+	&msm_device_ssbi_pmic1,
+	&msm_device_ssbi_pmic2,
+#endif
+#ifdef CONFIG_I2C_SSBI
+	&msm_device_ssbi3,
+#endif
+#if defined(CONFIG_USB_PEHCI_HCD) || defined(CONFIG_USB_PEHCI_HCD_MODULE)
+	&isp1763_device,
+#endif
+
+#if defined (CONFIG_MSM_8x60_VOIP)
+	&asoc_msm_mvs,
+	&asoc_mvs_dai0,
+	&asoc_mvs_dai1,
+#endif
+
+#if defined(CONFIG_USB_MSM_72K) || defined(CONFIG_USB_EHCI_HCD)
+	&msm_device_otg,
+#endif
+#ifdef CONFIG_USB_MSM_72K
+	&msm_device_gadget_peripheral,
+#endif
+#ifdef CONFIG_USB_G_ANDROID
+	&android_usb_device,
+#endif
+#ifdef CONFIG_BATTERY_MSM
+	&msm_batt_device,
+#endif
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+	&android_pmem_device,
+	&android_pmem_adsp_device,
+	&android_pmem_smipool_device,
+	&android_pmem_audio_device,
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
+#ifdef CONFIG_MSM_ROTATOR
+	&msm_rotator_device,
+#endif
+	&msm_fb_device,
+	&msm_kgsl_3d0,
+	&msm_kgsl_2d0,
+	&msm_kgsl_2d1,
+	&lcdc_samsung_panel_device,
+#ifdef CONFIG_FB_MSM_LCDC_NT35582_WVGA
+	&lcdc_nt35582_panel_device,
+#endif
+#ifdef CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT
+	&lcdc_samsung_oled_panel_device,
+#endif
+#ifdef CONFIG_FB_MSM_LCDC_AUO_WVGA
+	&lcdc_auo_wvga_panel_device,
+#endif
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+	&hdmi_msm_device,
+#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL */
+#ifdef CONFIG_FB_MSM_MIPI_DSI
+	&mipi_dsi_toshiba_panel_device,
+	&mipi_dsi_novatek_panel_device,
+#endif
+#ifdef CONFIG_MSM_CAMERA
+#ifndef CONFIG_MSM_CAMERA_V4L2
+#ifdef CONFIG_MT9E013
+	&msm_camera_sensor_mt9e013,
+#endif
+#ifdef CONFIG_IMX074
+	&msm_camera_sensor_imx074,
+#endif
+#ifdef CONFIG_WEBCAM_OV7692
+	&msm_camera_sensor_webcam_ov7692,
+#endif
+#ifdef CONFIG_WEBCAM_OV9726
+	&msm_camera_sensor_webcam_ov9726,
+#endif
+#ifdef CONFIG_QS_S5K4E1
+	&msm_camera_sensor_qs_s5k4e1,
+#endif
+#ifdef CONFIG_VX6953
+	&msm_camera_sensor_vx6953,
+#endif
+#endif
+#endif
+#ifdef CONFIG_MSM_GEMINI
+	&msm_gemini_device,
+#endif
+#ifdef CONFIG_MSM_VPE
+#ifndef CONFIG_MSM_CAMERA_V4L2
+	&msm_vpe_device,
+#endif
+#endif
+
+#if defined(CONFIG_MSM_RPM_LOG) || defined(CONFIG_MSM_RPM_LOG_MODULE)
+	&msm8660_rpm_log_device,
+#endif
+#if defined(CONFIG_MSM_RPM_STATS_LOG)
+	&msm8660_rpm_stat_device,
+#endif
+	&msm_device_vidc,
+#if (defined(CONFIG_MARIMBA_CORE)) && \
+	(defined(CONFIG_MSM_BT_POWER) || defined(CONFIG_MSM_BT_POWER_MODULE))
+	&msm_bt_power_device,
+#endif
+#ifdef CONFIG_SENSORS_MSM_ADC
+	&msm_adc_device,
+#endif
+	&rpm_regulator_device,
+
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
+	&qcrypto_device,
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+	&qcedev_device,
+#endif
+
+
+#if defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE)
+#ifdef CONFIG_MSM_USE_TSIF1
+	&msm_device_tsif[1],
+#else
+	&msm_device_tsif[0],
+#endif /* CONFIG_MSM_USE_TSIF1 */
+#endif /* CONFIG_TSIF */
+
+#ifdef CONFIG_HW_RANDOM_MSM
+	&msm_device_rng,
+#endif
+
+	&msm_tsens_device,
+	&msm8660_rpm_device,
+#ifdef CONFIG_ION_MSM
+	&ion_dev,
+#endif
+	&msm8660_device_watchdog,
+	&msm_device_tz_log,
+	&msm_rtb_device,
+};
+
+#ifdef CONFIG_ION_MSM
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+static struct ion_cp_heap_pdata cp_mm_ion_pdata = {
+	.permission_type = IPT_TYPE_MM_CARVEOUT,
+	.align = SZ_64K,
+	.request_region = request_smi_region,
+	.release_region = release_smi_region,
+	.setup_region = setup_smi_region,
+	.iommu_map_all = 1,
+	.iommu_2x_map_domain = VIDEO_DOMAIN,
+};
+
+static struct ion_cp_heap_pdata cp_mfc_ion_pdata = {
+	.permission_type = IPT_TYPE_MFC_SHAREDMEM,
+	.align = PAGE_SIZE,
+	.request_region = request_smi_region,
+	.release_region = release_smi_region,
+	.setup_region = setup_smi_region,
+};
+
+static struct ion_cp_heap_pdata cp_wb_ion_pdata = {
+	.permission_type = IPT_TYPE_MDP_WRITEBACK,
+	.align = PAGE_SIZE,
+};
+
+static struct ion_co_heap_pdata fw_co_ion_pdata = {
+	.adjacent_mem_id = ION_CP_MM_HEAP_ID,
+	.align = SZ_128K,
+};
+
+static struct ion_co_heap_pdata co_ion_pdata = {
+	.adjacent_mem_id = INVALID_HEAP_ID,
+	.align = PAGE_SIZE,
+};
+#endif
+
+/**
+ * These heaps are listed in the order they will be allocated. Due to
+ * video hardware restrictions and content protection the FW heap has to
+ * be allocated adjacent (below) the MM heap and the MFC heap has to be
+ * allocated after the MM heap to ensure MFC heap is not more than 256MB
+ * away from the base address of the FW heap.
+ * However, the order of FW heap and MM heap doesn't matter since these
+ * two heaps are taken care of by separate code to ensure they are adjacent
+ * to each other.
+ * Don't swap the order unless you know what you are doing!
+ */
+static struct ion_platform_data ion_pdata = {
+	.nr = MSM_ION_HEAP_NUM,
+	.heaps = {
+		{
+			.id	= ION_SYSTEM_HEAP_ID,
+			.type	= ION_HEAP_TYPE_SYSTEM,
+			.name	= ION_VMALLOC_HEAP_NAME,
+		},
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+		{
+			.id	= ION_CP_MM_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CP,
+			.name	= ION_MM_HEAP_NAME,
+			.size	= MSM_ION_MM_SIZE,
+			.memory_type = ION_SMI_TYPE,
+			.extra_data = (void *) &cp_mm_ion_pdata,
+		},
+		{
+			.id	= ION_MM_FIRMWARE_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.name	= ION_MM_FIRMWARE_HEAP_NAME,
+			.size	= MSM_ION_MM_FW_SIZE,
+			.memory_type = ION_SMI_TYPE,
+			.extra_data = (void *) &fw_co_ion_pdata,
+		},
+		{
+			.id	= ION_CP_MFC_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CP,
+			.name	= ION_MFC_HEAP_NAME,
+			.size	= MSM_ION_MFC_SIZE,
+			.memory_type = ION_SMI_TYPE,
+			.extra_data = (void *) &cp_mfc_ion_pdata,
+		},
+		{
+			.id	= ION_SF_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.name	= ION_SF_HEAP_NAME,
+			.size	= MSM_ION_SF_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *)&co_ion_pdata,
+		},
+		{
+			.id	= ION_CAMERA_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.name	= ION_CAMERA_HEAP_NAME,
+			.size	= MSM_ION_CAMERA_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = &co_ion_pdata,
+		},
+		{
+			.id	= ION_CP_WB_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CP,
+			.name	= ION_WB_HEAP_NAME,
+			.size	= MSM_ION_WB_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &cp_wb_ion_pdata,
+		},
+		{
+			.id	= ION_QSECOM_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.name	= ION_QSECOM_HEAP_NAME,
+			.size	= MSM_ION_QSECOM_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &co_ion_pdata,
+		},
+		{
+			.id	= ION_AUDIO_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.name	= ION_AUDIO_HEAP_NAME,
+			.size	= MSM_ION_AUDIO_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *)&co_ion_pdata,
+		},
+#endif
+	}
+};
+
+static struct platform_device ion_dev = {
+	.name = "ion-msm",
+	.id = 1,
+	.dev = { .platform_data = &ion_pdata },
+};
+#endif
+
+
+static struct memtype_reserve msm8x60_reserve_table[] __initdata = {
+	/* Kernel SMI memory pool for video core, used for firmware */
+	/* and encoder, decoder scratch buffers */
+	/* Kernel SMI memory pool should always precede the user space */
+	/* SMI memory pool, as the video core will use offset address */
+	/* from the Firmware base */
+	[MEMTYPE_SMI_KERNEL] = {
+		.start	=	KERNEL_SMI_BASE,
+		.limit	=	KERNEL_SMI_SIZE,
+		.size	=	KERNEL_SMI_SIZE,
+		.flags	=	MEMTYPE_FLAGS_FIXED,
+	},
+	/* User space SMI memory pool for video core */
+	/* used for encoder, decoder input & output buffers  */
+	[MEMTYPE_SMI] = {
+		.start	=	USER_SMI_BASE,
+		.limit	=	USER_SMI_SIZE,
+		.flags	=	MEMTYPE_FLAGS_FIXED,
+	},
+	[MEMTYPE_EBI0] = {
+		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
+	},
+	[MEMTYPE_EBI1] = {
+		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
+	},
+};
+
+static void __init reserve_ion_memory(void)
+{
+#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
+	unsigned int i;
+
+	if (hdmi_is_primary) {
+		msm_ion_sf_size = MSM_HDMI_PRIM_ION_SF_SIZE;
+		for (i = 0; i < ion_pdata.nr; i++) {
+			if (ion_pdata.heaps[i].id == ION_SF_HEAP_ID) {
+				ion_pdata.heaps[i].size = msm_ion_sf_size;
+				pr_debug("msm_ion_sf_size 0x%x\n",
+					msm_ion_sf_size);
+				break;
+			}
+		}
+	}
+
+	/* Verify size of heap is a multiple of 64K */
+	for (i = 0; i < ion_pdata.nr; i++) {
+		struct ion_platform_heap *heap = &(ion_pdata.heaps[i]);
+
+		if (heap->extra_data && heap->type == ION_HEAP_TYPE_CP) {
+			int map_all = ((struct ion_cp_heap_pdata *)
+				heap->extra_data)->iommu_map_all;
+
+			if (map_all && (heap->size & (SZ_64K-1))) {
+				heap->size = ALIGN(heap->size, SZ_64K);
+				pr_err("Heap %s size is not a multiple of 64K. Adjusting size to %x\n",
+					heap->name, heap->size);
+
+			}
+		}
+	}
+
+	msm8x60_reserve_table[MEMTYPE_EBI1].size += msm_ion_sf_size;
+	msm8x60_reserve_table[MEMTYPE_SMI].size += MSM_ION_MM_FW_SIZE;
+	msm8x60_reserve_table[MEMTYPE_SMI].size += MSM_ION_MM_SIZE;
+	msm8x60_reserve_table[MEMTYPE_SMI].size += MSM_ION_MFC_SIZE;
+	msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_CAMERA_SIZE;
+	msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_WB_SIZE;
+	msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_AUDIO_SIZE;
+	msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_QSECOM_SIZE;
+#endif
+}
+
+static void __init size_pmem_devices(void)
+{
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+	android_pmem_adsp_pdata.size = pmem_adsp_size;
+	android_pmem_smipool_pdata.size = MSM_PMEM_SMIPOOL_SIZE;
+
+	if (hdmi_is_primary)
+		pmem_sf_size = MSM_HDMI_PRIM_PMEM_SF_SIZE;
+	android_pmem_pdata.size = pmem_sf_size;
+	android_pmem_audio_pdata.size = MSM_PMEM_AUDIO_SIZE;
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
+}
+
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+static void __init reserve_memory_for(struct android_pmem_platform_data *p)
+{
+	msm8x60_reserve_table[p->memory_type].size += p->size;
+}
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
+
+static void __init reserve_pmem_memory(void)
+{
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+	reserve_memory_for(&android_pmem_adsp_pdata);
+	reserve_memory_for(&android_pmem_smipool_pdata);
+	reserve_memory_for(&android_pmem_pdata);
+	reserve_memory_for(&android_pmem_audio_pdata);
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+	msm8x60_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
+#endif /*CONFIG_ANDROID_PMEM*/
+}
+
+static void __init reserve_mdp_memory(void);
+
+static void __init reserve_rtb_memory(void)
+{
+#if defined(CONFIG_MSM_RTB)
+	msm8x60_reserve_table[MEMTYPE_EBI1].size += msm_rtb_pdata.size;
+#endif
+}
+
+static void __init msm8x60_calculate_reserve_sizes(void)
+{
+	size_pmem_devices();
+	reserve_pmem_memory();
+	reserve_ion_memory();
+	reserve_mdp_memory();
+	reserve_rtb_memory();
+}
+
+static int msm8x60_paddr_to_memtype(unsigned int paddr)
+{
+	if (paddr >= 0x40000000 && paddr < 0x60000000)
+		return MEMTYPE_EBI1;
+	if (paddr >= 0x38000000 && paddr < 0x40000000)
+		return MEMTYPE_SMI;
+	return MEMTYPE_NONE;
+}
+
+static struct reserve_info msm8x60_reserve_info __initdata = {
+	.memtype_reserve_table = msm8x60_reserve_table,
+	.calculate_reserve_sizes = msm8x60_calculate_reserve_sizes,
+	.paddr_to_memtype = msm8x60_paddr_to_memtype,
+};
+
+static char prim_panel_name[PANEL_NAME_MAX_LEN];
+static char ext_panel_name[PANEL_NAME_MAX_LEN];
+static int __init prim_display_setup(char *param)
+{
+	if (strnlen(param, PANEL_NAME_MAX_LEN))
+		strlcpy(prim_panel_name, param, PANEL_NAME_MAX_LEN);
+	return 0;
+}
+early_param("prim_display", prim_display_setup);
+
+static int __init ext_display_setup(char *param)
+{
+	if (strnlen(param, PANEL_NAME_MAX_LEN))
+		strlcpy(ext_panel_name, param, PANEL_NAME_MAX_LEN);
+	return 0;
+}
+early_param("ext_display", ext_display_setup);
+
 static void __init msm8x60_reserve(void)
 {
-	memblock_remove(0x40000000, SZ_2M);
+	msm8x60_set_display_params(prim_panel_name, ext_panel_name);
+	reserve_info = &msm8x60_reserve_info;
+	msm_reserve();
+}
+
+#define EXT_CHG_VALID_MPP 10
+#define EXT_CHG_VALID_MPP_2 11
+
+static struct pm8xxx_mpp_init_info isl_mpp[] = {
+	PM8058_MPP_INIT(EXT_CHG_VALID_MPP, D_INPUT,
+		PM8058_MPP_DIG_LEVEL_S3, DIN_TO_INT),
+	PM8058_MPP_INIT(EXT_CHG_VALID_MPP_2, D_BI_DIR,
+		PM8058_MPP_DIG_LEVEL_S3, BI_PULLUP_10KOHM),
+};
+
+#ifdef CONFIG_ISL9519_CHARGER
+static int isl_detection_setup(void)
+{
+	int ret = 0, i;
+
+	for (i = 0; i < ARRAY_SIZE(isl_mpp); i++) {
+		ret = pm8xxx_mpp_config(isl_mpp[i].mpp,
+					&isl_mpp[i].config);
+		if (ret) {
+			pr_err("%s: Config MPP %d of PM8058 failed\n",
+						 __func__, isl_mpp[i].mpp);
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+static struct isl_platform_data isl_data __initdata = {
+	.chgcurrent		= 700,
+	.valid_n_gpio		= PM8058_MPP_PM_TO_SYS(10),
+	.chg_detection_config	= isl_detection_setup,
+	.max_system_voltage	= 4200,
+	.min_system_voltage	= 3200,
+	.term_current		= 120,
+	.input_current		= 2048,
+};
+
+static struct i2c_board_info isl_charger_i2c_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("isl9519q", 0x9),
+		.irq = PM8058_IRQ_BASE + PM8058_CBLPWR_IRQ,
+		.platform_data = &isl_data,
+	},
+};
+#endif
+
+#if defined(CONFIG_SMB137B_CHARGER) || defined(CONFIG_SMB137B_CHARGER_MODULE)
+static int smb137b_detection_setup(void)
+{
+	int ret = 0, i;
+
+	for (i = 0; i < ARRAY_SIZE(isl_mpp); i++) {
+		ret = pm8xxx_mpp_config(isl_mpp[i].mpp,
+					&isl_mpp[i].config);
+		if (ret) {
+			pr_err("%s: Config MPP %d of PM8058 failed\n",
+						 __func__, isl_mpp[i].mpp);
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+static struct smb137b_platform_data smb137b_data __initdata = {
+	.chg_detection_config = smb137b_detection_setup,
+	.valid_n_gpio = PM8058_MPP_PM_TO_SYS(10),
+	.batt_mah_rating = 950,
+};
+
+static struct i2c_board_info smb137b_charger_i2c_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("smb137b", 0x08),
+		.irq = PM8058_IRQ_BASE + PM8058_CBLPWR_IRQ,
+		.platform_data = &smb137b_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_PMIC8058
+#define PMIC_GPIO_SDC3_DET 22
+#define PMIC_GPIO_TOUCH_DISC_INTR 5
+
+static int pm8058_gpios_init(void)
+{
+	int i;
+	int rc;
+	struct pm8058_gpio_cfg {
+		int                gpio;
+		struct pm_gpio	   cfg;
+	};
+
+	struct pm8058_gpio_cfg gpio_cfgs[] = {
+		{ /* FFA ethernet */
+			PM8058_GPIO_PM_TO_SYS(6),
+			{
+				.direction      = PM_GPIO_DIR_IN,
+				.pull           = PM_GPIO_PULL_DN,
+				.vin_sel        = 2,
+				.function       = PM_GPIO_FUNC_NORMAL,
+				.inv_int_pol    = 0,
+			},
+		},
+#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
+		{
+			PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_SDC3_DET - 1),
+			{
+				.direction      = PM_GPIO_DIR_IN,
+				.pull           = PM_GPIO_PULL_UP_30,
+				.vin_sel        = 2,
+				.function       = PM_GPIO_FUNC_NORMAL,
+				.inv_int_pol    = 0,
+			},
+		},
+#endif
+		{ /* core&surf gpio expander */
+			PM8058_GPIO_PM_TO_SYS(UI_INT1_N),
+			{
+				.direction      = PM_GPIO_DIR_IN,
+				.pull           = PM_GPIO_PULL_NO,
+				.vin_sel        = PM8058_GPIO_VIN_S3,
+				.function       = PM_GPIO_FUNC_NORMAL,
+				.inv_int_pol    = 0,
+			},
+		},
+		{ /* docking gpio expander */
+			PM8058_GPIO_PM_TO_SYS(UI_INT2_N),
+			{
+				.direction      = PM_GPIO_DIR_IN,
+				.pull           = PM_GPIO_PULL_NO,
+				.vin_sel        = PM8058_GPIO_VIN_S3,
+				.function       = PM_GPIO_FUNC_NORMAL,
+				.inv_int_pol    = 0,
+			},
+		},
+		{ /* FHA/keypad gpio expanders */
+			PM8058_GPIO_PM_TO_SYS(UI_INT3_N),
+			{
+				.direction      = PM_GPIO_DIR_IN,
+				.pull           = PM_GPIO_PULL_NO,
+				.vin_sel        = PM8058_GPIO_VIN_S3,
+				.function       = PM_GPIO_FUNC_NORMAL,
+				.inv_int_pol    = 0,
+			},
+		},
+		{ /* Timpani Reset */
+			PM8058_GPIO_PM_TO_SYS(20),
+			{
+				.direction	= PM_GPIO_DIR_OUT,
+				.output_value	= 1,
+				.output_buffer	= PM_GPIO_OUT_BUF_CMOS,
+				.pull		= PM_GPIO_PULL_DN,
+				.out_strength	= PM_GPIO_STRENGTH_HIGH,
+				.function	= PM_GPIO_FUNC_NORMAL,
+				.vin_sel	= 2,
+				.inv_int_pol	= 0,
+			}
+		},
+		{ /* PMIC ID interrupt */
+			PM8058_GPIO_PM_TO_SYS(36),
+			{
+				.direction	= PM_GPIO_DIR_IN,
+				.pull		= PM_GPIO_PULL_NO,
+				.function	= PM_GPIO_FUNC_NORMAL,
+				.vin_sel	= 2,
+				.inv_int_pol	= 0,
+			}
+		},
+	};
+
+#if defined(CONFIG_TOUCHDISC_VTD518_SHINETSU) || \
+		defined(CONFIG_TOUCHDISC_VTD518_SHINETSU_MODULE)
+	struct pm_gpio touchdisc_intr_gpio_cfg = {
+		.direction      = PM_GPIO_DIR_IN,
+		.pull           = PM_GPIO_PULL_UP_1P5,
+		.vin_sel        = 2,
+		.function       = PM_GPIO_FUNC_NORMAL,
+	};
+#endif
+
+#if defined(CONFIG_HAPTIC_ISA1200) || \
+			defined(CONFIG_HAPTIC_ISA1200_MODULE)
+	struct pm_gpio en_hap_gpio_cfg = {
+		.direction      = PM_GPIO_DIR_OUT,
+		.pull           = PM_GPIO_PULL_NO,
+		.out_strength   = PM_GPIO_STRENGTH_HIGH,
+		.function       = PM_GPIO_FUNC_NORMAL,
+		.inv_int_pol    = 0,
+		.vin_sel        = 2,
+		.output_buffer  = PM_GPIO_OUT_BUF_CMOS,
+		.output_value   = 0,
+	};
+#endif
+
+#if defined(CONFIG_PMIC8058_OTHC) || defined(CONFIG_PMIC8058_OTHC_MODULE)
+	struct pm8058_gpio_cfg line_in_gpio_cfg = {
+			PM8058_GPIO_PM_TO_SYS(18),
+			{
+				.direction	= PM_GPIO_DIR_IN,
+				.pull           = PM_GPIO_PULL_UP_1P5,
+				.vin_sel        = 2,
+				.function       = PM_GPIO_FUNC_NORMAL,
+				.inv_int_pol    = 0,
+			}
+	};
+#endif
+
+#if defined(CONFIG_QS_S5K4E1)
+		{
+			struct pm8058_gpio_cfg qs_hc37_cam_pd_gpio_cfg = {
+			PM8058_GPIO_PM_TO_SYS(26),
+			{
+				.direction		= PM_GPIO_DIR_OUT,
+				.output_value	= 0,
+				.output_buffer	= PM_GPIO_OUT_BUF_CMOS,
+				.pull			= PM_GPIO_PULL_DN,
+				.out_strength	= PM_GPIO_STRENGTH_HIGH,
+				.function		= PM_GPIO_FUNC_NORMAL,
+				.vin_sel		= 2,
+				.inv_int_pol	= 0,
+			}
+		};
+#endif
+#ifdef CONFIG_FB_MSM_LCDC_NT35582_WVGA
+	struct pm8058_gpio_cfg pmic_lcdc_nt35582_gpio_cfg = {
+		PM8058_GPIO_PM_TO_SYS(GPIO_NT35582_BL_EN_HW_PIN - 1),
+		{
+			.direction		= PM_GPIO_DIR_OUT,
+			.output_buffer	= PM_GPIO_OUT_BUF_CMOS,
+			.output_value	= 1,
+			.pull			= PM_GPIO_PULL_UP_30,
+			/* 2.9V  PM_GPIO_VIN_L2, which gives 2.6V */
+			.vin_sel		= PM8058_GPIO_VIN_L5,
+			.out_strength	= PM_GPIO_STRENGTH_HIGH,
+			.function		= PM_GPIO_FUNC_NORMAL,
+			.inv_int_pol	= 0,
+		}
+	};
+#endif
+#if defined(CONFIG_HAPTIC_ISA1200) || \
+			defined(CONFIG_HAPTIC_ISA1200_MODULE)
+	if (machine_is_msm8x60_fluid()) {
+		rc = pm8xxx_gpio_config(
+			PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_HAP_ENABLE),
+			&en_hap_gpio_cfg);
+		if (rc < 0) {
+			pr_err("%s: pmic haptics gpio config failed\n",
+							__func__);
+		}
+		rc = pm8xxx_gpio_config(
+			PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_HAP_LDO_ENABLE),
+			&en_hap_gpio_cfg);
+		if (rc < 0) {
+			pr_err("%s: pmic haptics ldo gpio config failed\n",
+							__func__);
+		}
+
+	}
+#endif
+
+#if defined(CONFIG_TOUCHDISC_VTD518_SHINETSU) || \
+		defined(CONFIG_TOUCHDISC_VTD518_SHINETSU_MODULE)
+	if (machine_is_msm8x60_ffa() || machine_is_msm8x60_surf() ||
+		machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa()) {
+		rc = pm8xxx_gpio_config(
+			PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_TOUCH_DISC_INTR),
+			&touchdisc_intr_gpio_cfg);
+		if (rc < 0) {
+			pr_err("%s: Touchdisc interrupt gpio config failed\n",
+							__func__);
+		}
+	}
+#endif
+
+#if defined(CONFIG_PMIC8058_OTHC) || defined(CONFIG_PMIC8058_OTHC_MODULE)
+	/* Line_in only for 8660 ffa & surf */
+	if (machine_is_msm8x60_ffa() || machine_is_msm8x60_surf() ||
+		machine_is_msm8x60_fusion() || machine_is_msm8x60_dragon() ||
+		machine_is_msm8x60_fusn_ffa()) {
+		rc = pm8xxx_gpio_config(line_in_gpio_cfg.gpio,
+				&line_in_gpio_cfg.cfg);
+		if (rc < 0) {
+			pr_err("%s pmic line_in gpio config failed\n",
+							__func__);
+			return rc;
+		}
+	}
+#endif
+
+#ifdef CONFIG_FB_MSM_LCDC_NT35582_WVGA
+	if (machine_is_msm8x60_dragon()) {
+		rc = pm8xxx_gpio_config(pmic_lcdc_nt35582_gpio_cfg.gpio,
+				&pmic_lcdc_nt35582_gpio_cfg.cfg);
+		if (rc < 0) {
+			pr_err("%s pmic gpio config failed\n", __func__);
+			return rc;
+		}
+	}
+#endif
+
+#if defined(CONFIG_QS_S5K4E1)
+		/* qs_cam_hc37_cam_pd only for 8660 fluid qs camera*/
+		if (machine_is_msm8x60_fluid()) {
+			rc = pm8xxx_gpio_config(qs_hc37_cam_pd_gpio_cfg.gpio,
+					&qs_hc37_cam_pd_gpio_cfg.cfg);
+			if (rc < 0) {
+				pr_err("%s pmic qs_hc37_cam_pd gpio config failed\n",
+								__func__);
+				return rc;
+			}
+		}
+	}
+#endif
+
+	for (i = 0; i < ARRAY_SIZE(gpio_cfgs); ++i) {
+		rc = pm8xxx_gpio_config(gpio_cfgs[i].gpio,
+				&gpio_cfgs[i].cfg);
+		if (rc < 0) {
+			pr_err("%s pmic gpio config failed\n",
+				__func__);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+static const unsigned int ffa_keymap[] = {
+	KEY(0, 0, KEY_FN_F1),	 /* LS - PUSH1 */
+	KEY(0, 1, KEY_UP),	 /* NAV - UP */
+	KEY(0, 2, KEY_LEFT),	 /* NAV - LEFT */
+	KEY(0, 3, KEY_VOLUMEUP), /* Shuttle SW_UP */
+
+	KEY(1, 0, KEY_FN_F2), 	 /* LS - PUSH2 */
+	KEY(1, 1, KEY_RIGHT),    /* NAV - RIGHT */
+	KEY(1, 2, KEY_DOWN),     /* NAV - DOWN */
+	KEY(1, 3, KEY_VOLUMEDOWN),
+
+	KEY(2, 3, KEY_ENTER),     /* SW_PUSH key */
+
+	KEY(4, 0, KEY_CAMERA_FOCUS), /* RS - PUSH1 */
+	KEY(4, 1, KEY_UP),	  /* USER_UP */
+	KEY(4, 2, KEY_LEFT),	  /* USER_LEFT */
+	KEY(4, 3, KEY_HOME),	  /* Right switch: MIC Bd */
+	KEY(4, 4, KEY_FN_F3),	  /* Reserved MIC */
+
+	KEY(5, 0, KEY_CAMERA), /* RS - PUSH2 */
+	KEY(5, 1, KEY_RIGHT),	  /* USER_RIGHT */
+	KEY(5, 2, KEY_DOWN),	  /* USER_DOWN */
+	KEY(5, 3, KEY_BACK),	  /* Left switch: MIC */
+	KEY(5, 4, KEY_MENU),	  /* Center switch: MIC */
+};
+
+static const unsigned int dragon_keymap[] = {
+	KEY(0, 0, KEY_MENU),
+	KEY(0, 2, KEY_1),
+	KEY(0, 3, KEY_4),
+	KEY(0, 4, KEY_7),
+
+	KEY(1, 0, KEY_UP),
+	KEY(1, 1, KEY_LEFT),
+	KEY(1, 2, KEY_DOWN),
+	KEY(1, 3, KEY_5),
+	KEY(1, 4, KEY_8),
+
+	KEY(2, 0, KEY_HOME),
+	KEY(2, 1, KEY_REPLY),
+	KEY(2, 2, KEY_2),
+	KEY(2, 3, KEY_6),
+	KEY(2, 4, KEY_0),
+
+	KEY(3, 0, KEY_VOLUMEUP),
+	KEY(3, 1, KEY_RIGHT),
+	KEY(3, 2, KEY_3),
+	KEY(3, 3, KEY_9),
+	KEY(3, 4, KEY_SWITCHVIDEOMODE),
+
+	KEY(4, 0, KEY_VOLUMEDOWN),
+	KEY(4, 1, KEY_BACK),
+	KEY(4, 2, KEY_CAMERA),
+	KEY(4, 3, KEY_KBDILLUMTOGGLE),
+};
+
+static struct matrix_keymap_data ffa_keymap_data = {
+	.keymap_size	= ARRAY_SIZE(ffa_keymap),
+	.keymap		= ffa_keymap,
+};
+
+static struct pm8xxx_keypad_platform_data ffa_keypad_data = {
+	.input_name		= "ffa-keypad",
+	.input_phys_device	= "ffa-keypad/input0",
+	.num_rows		= 6,
+	.num_cols		= 5,
+	.rows_gpio_start	= PM8058_GPIO_PM_TO_SYS(8),
+	.cols_gpio_start	= PM8058_GPIO_PM_TO_SYS(0),
+	.debounce_ms		= 15,
+	.scan_delay_ms		= 32,
+	.row_hold_ns            = 91500,
+	.wakeup			= 1,
+	.keymap_data		= &ffa_keymap_data,
+};
+
+static struct matrix_keymap_data dragon_keymap_data = {
+	.keymap_size = ARRAY_SIZE(dragon_keymap),
+	.keymap = dragon_keymap,
+};
+
+static struct pm8xxx_keypad_platform_data dragon_keypad_data = {
+	.input_name = "dragon-keypad",
+	.input_phys_device = "dragon-keypad/input0",
+	.num_rows = 6,
+	.num_cols = 5,
+	.rows_gpio_start	= PM8058_GPIO_PM_TO_SYS(8),
+	.cols_gpio_start	= PM8058_GPIO_PM_TO_SYS(0),
+	.debounce_ms		= 15,
+	.scan_delay_ms = 32,
+	.row_hold_ns = 91500,
+	.wakeup = 1,
+	.keymap_data = &dragon_keymap_data,
+};
+
+static const unsigned int fluid_keymap[] = {
+	KEY(0, 0, KEY_FN_F1),	 /* LS - PUSH1 */
+	KEY(0, 1, KEY_UP),	 /* NAV - UP */
+	KEY(0, 2, KEY_LEFT),	 /* NAV - LEFT */
+	KEY(0, 3, KEY_VOLUMEDOWN), /* Shuttle SW_UP */
+
+	KEY(1, 0, KEY_FN_F2),	 /* LS - PUSH2 */
+	KEY(1, 1, KEY_RIGHT),    /* NAV - RIGHT */
+	KEY(1, 2, KEY_DOWN),     /* NAV - DOWN */
+	KEY(1, 3, KEY_VOLUMEUP),
+
+	KEY(2, 3, KEY_ENTER),     /* SW_PUSH key */
+
+	KEY(4, 0, KEY_CAMERA_FOCUS), /* RS - PUSH1 */
+	KEY(4, 1, KEY_UP),	  /* USER_UP */
+	KEY(4, 2, KEY_LEFT),	  /* USER_LEFT */
+	KEY(4, 3, KEY_HOME),	  /* Right switch: MIC Bd */
+	KEY(4, 4, KEY_FN_F3),	  /* Reserved MIC */
+
+	KEY(5, 0, KEY_CAMERA), /* RS - PUSH2 */
+	KEY(5, 1, KEY_RIGHT),	  /* USER_RIGHT */
+	KEY(5, 2, KEY_DOWN),	  /* USER_DOWN */
+	KEY(5, 3, KEY_BACK),	  /* Left switch: MIC */
+	KEY(5, 4, KEY_MENU),	  /* Center switch: MIC */
+};
+
+static struct matrix_keymap_data fluid_keymap_data = {
+	.keymap_size	= ARRAY_SIZE(fluid_keymap),
+	.keymap		= fluid_keymap,
+};
+
+static struct pm8xxx_keypad_platform_data fluid_keypad_data = {
+	.input_name		= "fluid-keypad",
+	.input_phys_device	= "fluid-keypad/input0",
+	.num_rows		= 6,
+	.num_cols		= 5,
+	.rows_gpio_start	= PM8058_GPIO_PM_TO_SYS(8),
+	.cols_gpio_start	= PM8058_GPIO_PM_TO_SYS(0),
+	.debounce_ms		= 15,
+	.scan_delay_ms		= 32,
+	.row_hold_ns            = 91500,
+	.wakeup			= 1,
+	.keymap_data		= &fluid_keymap_data,
+};
+
+static struct pm8xxx_vibrator_platform_data pm8058_vib_pdata = {
+	.initial_vibrate_ms  = 500,
+	.level_mV = 3000,
+	.max_timeout_ms = 15000,
+};
+
+static struct pm8xxx_rtc_platform_data pm8058_rtc_pdata = {
+	.rtc_write_enable       = false,
+	.rtc_alarm_powerup	= false,
+};
+
+static struct pm8xxx_pwrkey_platform_data pm8058_pwrkey_pdata = {
+	.pull_up		= 1,
+	.kpd_trigger_delay_us   = 15625,
+	.wakeup			= 1,
+};
+
+#define PM8058_LINE_IN_DET_GPIO	PM8058_GPIO_PM_TO_SYS(18)
+
+static struct othc_accessory_info othc_accessories[]  = {
+	{
+		.accessory = OTHC_SVIDEO_OUT,
+		.detect_flags = OTHC_MICBIAS_DETECT | OTHC_SWITCH_DETECT
+							| OTHC_ADC_DETECT,
+		.key_code = SW_VIDEOOUT_INSERT,
+		.enabled = false,
+		.adc_thres = {
+				.min_threshold = 20,
+				.max_threshold = 40,
+			},
+	},
+	{
+		.accessory = OTHC_ANC_HEADPHONE,
+		.detect_flags = OTHC_MICBIAS_DETECT | OTHC_GPIO_DETECT |
+							OTHC_SWITCH_DETECT,
+		.gpio = PM8058_LINE_IN_DET_GPIO,
+		.active_low = 1,
+		.key_code = SW_HEADPHONE_INSERT,
+		.enabled = true,
+	},
+	{
+		.accessory = OTHC_ANC_HEADSET,
+		.detect_flags = OTHC_MICBIAS_DETECT | OTHC_GPIO_DETECT,
+		.gpio = PM8058_LINE_IN_DET_GPIO,
+		.active_low = 1,
+		.key_code = SW_HEADPHONE_INSERT,
+		.enabled = true,
+	},
+	{
+		.accessory = OTHC_HEADPHONE,
+		.detect_flags = OTHC_MICBIAS_DETECT | OTHC_SWITCH_DETECT,
+		.key_code = SW_HEADPHONE_INSERT,
+		.enabled = true,
+	},
+	{
+		.accessory = OTHC_MICROPHONE,
+		.detect_flags = OTHC_GPIO_DETECT,
+		.gpio = PM8058_LINE_IN_DET_GPIO,
+		.active_low = 1,
+		.key_code = SW_MICROPHONE_INSERT,
+		.enabled = true,
+	},
+	{
+		.accessory = OTHC_HEADSET,
+		.detect_flags = OTHC_MICBIAS_DETECT,
+		.key_code = SW_HEADPHONE_INSERT,
+		.enabled = true,
+	},
+};
+
+static struct othc_switch_info switch_info[] = {
+	{
+		.min_adc_threshold = 0,
+		.max_adc_threshold = 100,
+		.key_code = KEY_PLAYPAUSE,
+	},
+	{
+		.min_adc_threshold = 100,
+		.max_adc_threshold = 200,
+		.key_code = KEY_REWIND,
+	},
+	{
+		.min_adc_threshold = 200,
+		.max_adc_threshold = 500,
+		.key_code = KEY_FASTFORWARD,
+	},
+};
+
+static struct othc_n_switch_config switch_config = {
+	.voltage_settling_time_ms = 0,
+	.num_adc_samples = 3,
+	.adc_channel = CHANNEL_ADC_HDSET,
+	.switch_info = switch_info,
+	.num_keys = ARRAY_SIZE(switch_info),
+	.default_sw_en = true,
+	.default_sw_idx = 0,
+};
+
+static struct hsed_bias_config hsed_bias_config = {
+	/* HSED mic bias config info */
+	.othc_headset = OTHC_HEADSET_NO,
+	.othc_lowcurr_thresh_uA = 100,
+	.othc_highcurr_thresh_uA = 600,
+	.othc_hyst_prediv_us = 7800,
+	.othc_period_clkdiv_us = 62500,
+	.othc_hyst_clk_us = 121000,
+	.othc_period_clk_us = 312500,
+	.othc_wakeup = 1,
+};
+
+static struct othc_hsed_config hsed_config_1 = {
+	.hsed_bias_config = &hsed_bias_config,
+	/*
+	 * The detection delay and switch reporting delay are
+	 * required to encounter a hardware bug (spurious switch
+	 * interrupts on slow insertion/removal of the headset).
+	 * This will introduce a delay in reporting the accessory
+	 * insertion and removal to the userspace.
+	 */
+	.detection_delay_ms = 1500,
+	/* Switch info */
+	.switch_debounce_ms = 1500,
+	.othc_support_n_switch = false,
+	.switch_config = &switch_config,
+	.ir_gpio = -1,
+	/* Accessory info */
+	.accessories_support = true,
+	.accessories = othc_accessories,
+	.othc_num_accessories = ARRAY_SIZE(othc_accessories),
+};
+
+static struct othc_regulator_config othc_reg = {
+	.regulator	 = "8058_l5",
+	.max_uV		 = 2850000,
+	.min_uV		 = 2850000,
+};
+
+/* MIC_BIAS0 is configured as normal MIC BIAS */
+static struct pmic8058_othc_config_pdata othc_config_pdata_0 = {
+	.micbias_select = OTHC_MICBIAS_0,
+	.micbias_capability = OTHC_MICBIAS,
+	.micbias_enable = OTHC_SIGNAL_OFF,
+	.micbias_regulator = &othc_reg,
+};
+
+/* MIC_BIAS1 is configured as HSED_BIAS for OTHC */
+static struct pmic8058_othc_config_pdata othc_config_pdata_1 = {
+	.micbias_select = OTHC_MICBIAS_1,
+	.micbias_capability = OTHC_MICBIAS_HSED,
+	.micbias_enable = OTHC_SIGNAL_PWM_TCXO,
+	.micbias_regulator = &othc_reg,
+	.hsed_config = &hsed_config_1,
+	.hsed_name = "8660_handset",
+};
+
+/* MIC_BIAS2 is configured as normal MIC BIAS */
+static struct pmic8058_othc_config_pdata othc_config_pdata_2 = {
+	.micbias_select = OTHC_MICBIAS_2,
+	.micbias_capability = OTHC_MICBIAS,
+	.micbias_enable = OTHC_SIGNAL_OFF,
+	.micbias_regulator = &othc_reg,
+};
+
+
+static void __init msm8x60_init_pm8058_othc(void)
+{
+	int i;
+
+	if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2 ||
+		machine_is_msm8x60_fluid() || machine_is_msm8x60_fusion() ||
+		machine_is_msm8x60_fusn_ffa()) {
+		/* 3-switch headset supported only by V2 FFA and FLUID */
+		hsed_config_1.accessories_adc_support = true,
+		/* ADC based accessory detection works only on V2 and FLUID */
+		hsed_config_1.accessories_adc_channel = CHANNEL_ADC_HDSET,
+		hsed_config_1.othc_support_n_switch = true;
+	}
+
+	/* IR GPIO is absent on FLUID */
+	if (machine_is_msm8x60_fluid())
+		hsed_config_1.ir_gpio = -1;
+
+	for (i = 0; i < ARRAY_SIZE(othc_accessories); i++) {
+		if (machine_is_msm8x60_fluid()) {
+			switch (othc_accessories[i].accessory) {
+			case OTHC_ANC_HEADPHONE:
+			case OTHC_ANC_HEADSET:
+				othc_accessories[i].gpio = GPIO_HEADSET_DET_N;
+				break;
+			case OTHC_MICROPHONE:
+				othc_accessories[i].enabled = false;
+				break;
+			case OTHC_SVIDEO_OUT:
+				othc_accessories[i].enabled = true;
+				hsed_config_1.video_out_gpio = GPIO_HS_SW_DIR;
+				break;
+			}
+		}
+	}
+}
+
+
+static int pm8058_pwm_config(struct pwm_device *pwm, int ch, int on)
+{
+	struct pm_gpio pwm_gpio_config = {
+		.direction      = PM_GPIO_DIR_OUT,
+		.output_buffer  = PM_GPIO_OUT_BUF_CMOS,
+		.output_value   = 0,
+		.pull           = PM_GPIO_PULL_NO,
+		.vin_sel        = PM8058_GPIO_VIN_VPH,
+		.out_strength   = PM_GPIO_STRENGTH_HIGH,
+		.function       = PM_GPIO_FUNC_2,
+	};
+
+	int rc = -EINVAL;
+	int id, mode, max_mA;
+
+	id = mode = max_mA = 0;
+	switch (ch) {
+	case 0:
+	case 1:
+	case 2:
+		if (on) {
+			id = 24 + ch;
+			rc = pm8xxx_gpio_config(PM8058_GPIO_PM_TO_SYS(id - 1),
+							&pwm_gpio_config);
+			if (rc)
+				pr_err("%s: pm8xxx_gpio_config(%d): rc=%d\n",
+					__func__, id, rc);
+		}
+		break;
+
+	case 6:
+		id = PM_PWM_LED_FLASH;
+		mode = PM_PWM_CONF_PWM1;
+		max_mA = 300;
+		break;
+
+	case 7:
+		id = PM_PWM_LED_FLASH1;
+		mode = PM_PWM_CONF_PWM1;
+		max_mA = 300;
+		break;
+
+	default:
+		break;
+	}
+
+	if (ch >= 6 && ch <= 7) {
+		if (!on) {
+			mode = PM_PWM_CONF_NONE;
+			max_mA = 0;
+		}
+		rc = pm8058_pwm_config_led(pwm, id, mode, max_mA);
+		if (rc)
+			pr_err("%s: pm8058_pwm_config_led(ch=%d): rc=%d\n",
+			       __func__, ch, rc);
+	}
+	return rc;
+
+}
+
+static struct pm8058_pwm_pdata pm8058_pwm_data = {
+	.config		= pm8058_pwm_config,
+};
+
+#define PM8058_GPIO_INT           88
+
+static struct pmic8058_led pmic8058_flash_leds[] = {
+	[0] = {
+		.name		= "camera:flash0",
+		.max_brightness = 15,
+		.id		= PMIC8058_ID_FLASH_LED_0,
+	},
+	[1] = {
+		.name		= "camera:flash1",
+		.max_brightness = 15,
+		.id		= PMIC8058_ID_FLASH_LED_1,
+	},
+};
+
+static struct pmic8058_leds_platform_data pm8058_flash_leds_data = {
+	.num_leds = ARRAY_SIZE(pmic8058_flash_leds),
+	.leds	= pmic8058_flash_leds,
+};
+
+static struct pmic8058_led pmic8058_dragon_leds[] = {
+	[0] = {
+		/* RED */
+		.name		= "led_drv0",
+		.max_brightness = 15,
+		.id		= PMIC8058_ID_LED_0,
+	},/* 300 mA flash led0 drv sink */
+	[1] = {
+		/* Yellow */
+		.name		= "led_drv1",
+		.max_brightness = 15,
+		.id		= PMIC8058_ID_LED_1,
+	},/* 300 mA flash led0 drv sink */
+	[2] = {
+		/* Green */
+		.name		= "led_drv2",
+		.max_brightness = 15,
+		.id		= PMIC8058_ID_LED_2,
+	},/* 300 mA flash led0 drv sink */
+	[3] = {
+		.name		= "led_psensor",
+		.max_brightness = 15,
+		.id		= PMIC8058_ID_LED_KB_LIGHT,
+	},/* 300 mA flash led0 drv sink */
+};
+
+static struct pmic8058_leds_platform_data pm8058_dragon_leds_data = {
+	.num_leds = ARRAY_SIZE(pmic8058_dragon_leds),
+	.leds	= pmic8058_dragon_leds,
+};
+
+static struct pmic8058_led pmic8058_fluid_flash_leds[] = {
+	[0] = {
+		.name		= "led:drv0",
+		.max_brightness = 15,
+		.id		= PMIC8058_ID_FLASH_LED_0,
+	},/* 300 mA flash led0 drv sink */
+	[1] = {
+		.name		= "led:drv1",
+		.max_brightness = 15,
+		.id		= PMIC8058_ID_FLASH_LED_1,
+	},/* 300 mA flash led1 sink */
+	[2] = {
+		.name		= "led:drv2",
+		.max_brightness = 20,
+		.id		= PMIC8058_ID_LED_0,
+	},/* 40 mA led0 sink */
+	[3] = {
+		.name		= "keypad:drv",
+		.max_brightness = 15,
+		.id		= PMIC8058_ID_LED_KB_LIGHT,
+	},/* 300 mA keypad drv sink */
+};
+
+static struct pmic8058_leds_platform_data pm8058_fluid_flash_leds_data = {
+	.num_leds = ARRAY_SIZE(pmic8058_fluid_flash_leds),
+	.leds	= pmic8058_fluid_flash_leds,
+};
+
+static struct pmic8058_charger_data pmic8058_charger_dragon = {
+		.charger_data_valid = true,
+		.max_source_current = 1800,
+		.charger_type = CHG_TYPE_AC,
+};
+
+static struct pmic8058_charger_data pmic8058_charger_ffa_surf = {
+		.charger_data_valid = false,
+};
+
+static struct pm8xxx_misc_platform_data pm8058_misc_pdata = {
+	.priority		= 0,
+};
+
+static struct pm8xxx_irq_platform_data pm8058_irq_pdata = {
+	.irq_base		= PM8058_IRQ_BASE,
+	.devirq			= MSM_GPIO_TO_INT(PM8058_GPIO_INT),
+	.irq_trigger_flag	= IRQF_TRIGGER_LOW,
+};
+
+static struct pm8xxx_gpio_platform_data pm8058_gpio_pdata = {
+	.gpio_base	= PM8058_GPIO_PM_TO_SYS(0),
+};
+
+static struct pm8xxx_mpp_platform_data pm8058_mpp_pdata = {
+	.mpp_base	= PM8058_MPP_PM_TO_SYS(0),
+};
+
+static struct pm8058_platform_data pm8058_platform_data = {
+	.irq_pdata		= &pm8058_irq_pdata,
+	.gpio_pdata		= &pm8058_gpio_pdata,
+	.mpp_pdata		= &pm8058_mpp_pdata,
+	.rtc_pdata		= &pm8058_rtc_pdata,
+	.pwrkey_pdata		= &pm8058_pwrkey_pdata,
+	.othc0_pdata		= &othc_config_pdata_0,
+	.othc1_pdata		= &othc_config_pdata_1,
+	.othc2_pdata		= &othc_config_pdata_2,
+	.pwm_pdata		= &pm8058_pwm_data,
+	.misc_pdata		= &pm8058_misc_pdata,
+#ifdef CONFIG_SENSORS_MSM_ADC
+	.xoadc_pdata		= &pm8058_xoadc_pdata,
+#endif
+};
+
+#ifdef CONFIG_MSM_SSBI
+static struct msm_ssbi_platform_data msm8x60_ssbi_pm8058_pdata __devinitdata = {
+	.controller_type = MSM_SBI_CTRL_PMIC_ARBITER,
+	.slave	= {
+		.name			= "pm8058-core",
+		.platform_data		= &pm8058_platform_data,
+	},
+};
+#endif
+#endif  /* CONFIG_PMIC8058 */
+
+#if defined(CONFIG_TOUCHDISC_VTD518_SHINETSU) || \
+		defined(CONFIG_TOUCHDISC_VTD518_SHINETSU_MODULE)
+#define TDISC_I2C_SLAVE_ADDR	0x67
+#define PMIC_GPIO_TDISC		PM8058_GPIO_PM_TO_SYS(5)
+#define TDISC_INT		PM8058_GPIO_IRQ(PM8058_IRQ_BASE, 5)
+
+static const char *vregs_tdisc_name[] = {
+	"8058_l5",
+	"8058_s3",
+};
+
+static const int vregs_tdisc_val[] = {
+	2850000,/* uV */
+	1800000,
+};
+static struct regulator *vregs_tdisc[ARRAY_SIZE(vregs_tdisc_name)];
+
+static int tdisc_shinetsu_setup(void)
+{
+	int rc, i;
+
+	rc = gpio_request(PMIC_GPIO_TDISC, "tdisc_interrupt");
+	if (rc) {
+		pr_err("%s: gpio_request failed for PMIC_GPIO_TDISC\n",
+								__func__);
+		return rc;
+	}
+
+	rc = gpio_request(GPIO_JOYSTICK_EN, "tdisc_oe");
+	if (rc) {
+		pr_err("%s: gpio_request failed for GPIO_JOYSTICK_EN\n",
+							__func__);
+		goto fail_gpio_oe;
+	}
+
+	rc = gpio_direction_output(GPIO_JOYSTICK_EN, 1);
+	if (rc) {
+		pr_err("%s: gpio_direction_output failed for GPIO_JOYSTICK_EN\n",
+								__func__);
+		gpio_free(GPIO_JOYSTICK_EN);
+		goto fail_gpio_oe;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(vregs_tdisc_name); i++) {
+		vregs_tdisc[i] = regulator_get(NULL, vregs_tdisc_name[i]);
+		if (IS_ERR(vregs_tdisc[i])) {
+			printk(KERN_ERR "%s: regulator get %s failed (%ld)\n",
+				__func__, vregs_tdisc_name[i],
+				PTR_ERR(vregs_tdisc[i]));
+			rc = PTR_ERR(vregs_tdisc[i]);
+			goto vreg_get_fail;
+		}
+
+		rc = regulator_set_voltage(vregs_tdisc[i],
+				vregs_tdisc_val[i], vregs_tdisc_val[i]);
+		if (rc) {
+			printk(KERN_ERR "%s: regulator_set_voltage() = %d\n",
+				__func__, rc);
+			goto vreg_set_voltage_fail;
+		}
+	}
+
+	return rc;
+vreg_set_voltage_fail:
+	i++;
+vreg_get_fail:
+	while (i)
+		regulator_put(vregs_tdisc[--i]);
+fail_gpio_oe:
+	gpio_free(PMIC_GPIO_TDISC);
+	return rc;
+}
+
+static void tdisc_shinetsu_release(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(vregs_tdisc_name); i++)
+		regulator_put(vregs_tdisc[i]);
+
+	gpio_free(PMIC_GPIO_TDISC);
+	gpio_free(GPIO_JOYSTICK_EN);
+}
+
+static int tdisc_shinetsu_enable(void)
+{
+	int i, rc = -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(vregs_tdisc_name); i++) {
+		rc = regulator_enable(vregs_tdisc[i]);
+		if (rc < 0) {
+			printk(KERN_ERR "%s: vreg %s enable failed (%d)\n",
+				__func__, vregs_tdisc_name[i], rc);
+			goto vreg_fail;
+		}
+	}
+
+	/* Enable the OE (output enable) gpio */
+	gpio_set_value_cansleep(GPIO_JOYSTICK_EN, 1);
+	/* voltage and gpio stabilization delay */
+	msleep(50);
+
+	return 0;
+vreg_fail:
+	while (i)
+		regulator_disable(vregs_tdisc[--i]);
+	return rc;
+}
+
+static int tdisc_shinetsu_disable(void)
+{
+	int i, rc;
+
+	for (i = 0; i < ARRAY_SIZE(vregs_tdisc_name); i++) {
+		rc = regulator_disable(vregs_tdisc[i]);
+		if (rc < 0) {
+			printk(KERN_ERR "%s: vreg %s disable failed (%d)\n",
+				__func__, vregs_tdisc_name[i], rc);
+			goto tdisc_reg_fail;
+		}
+	}
+
+	/* Disable the OE (output enable) gpio */
+	gpio_set_value_cansleep(GPIO_JOYSTICK_EN, 0);
+
+	return 0;
+
+tdisc_reg_fail:
+	while (i)
+		regulator_enable(vregs_tdisc[--i]);
+	return rc;
+}
+
+static struct tdisc_abs_values tdisc_abs = {
+	.x_max = 32,
+	.y_max = 32,
+	.x_min = -32,
+	.y_min = -32,
+	.pressure_max = 32,
+	.pressure_min = 0,
+};
+
+static struct tdisc_platform_data tdisc_data = {
+	.tdisc_setup = tdisc_shinetsu_setup,
+	.tdisc_release = tdisc_shinetsu_release,
+	.tdisc_enable = tdisc_shinetsu_enable,
+	.tdisc_disable = tdisc_shinetsu_disable,
+	.tdisc_wakeup  = 0,
+	.tdisc_gpio = PMIC_GPIO_TDISC,
+	.tdisc_report_keys = true,
+	.tdisc_report_relative = true,
+	.tdisc_report_absolute = false,
+	.tdisc_report_wheel = false,
+	.tdisc_reverse_x = false,
+	.tdisc_reverse_y = true,
+	.tdisc_abs  = &tdisc_abs,
+};
+
+static struct i2c_board_info msm_i2c_gsbi3_tdisc_info[] = {
+	{
+		I2C_BOARD_INFO("vtd518", TDISC_I2C_SLAVE_ADDR),
+		.irq =  TDISC_INT,
+		.platform_data = &tdisc_data,
+	},
+};
+#endif
+
+#define PM_GPIO_CDC_RST_N 20
+#define GPIO_CDC_RST_N PM8058_GPIO_PM_TO_SYS(PM_GPIO_CDC_RST_N)
+
+static struct regulator *vreg_timpani_1;
+static struct regulator *vreg_timpani_2;
+
+static unsigned int msm_timpani_setup_power(void)
+{
+	int rc;
+
+	vreg_timpani_1 = regulator_get(NULL, "8058_l0");
+	if (IS_ERR(vreg_timpani_1)) {
+		pr_err("%s: Unable to get 8058_l0\n", __func__);
+		return -ENODEV;
+	}
+
+	vreg_timpani_2 = regulator_get(NULL, "8058_s3");
+	if (IS_ERR(vreg_timpani_2)) {
+		pr_err("%s: Unable to get 8058_s3\n", __func__);
+		regulator_put(vreg_timpani_1);
+		return -ENODEV;
+	}
+
+	rc = regulator_set_voltage(vreg_timpani_1, 1200000, 1200000);
+	if (rc) {
+		pr_err("%s: unable to set L0 voltage to 1.2V\n", __func__);
+		goto fail;
+	}
+
+	rc = regulator_set_voltage(vreg_timpani_2, 1800000, 1800000);
+	if (rc) {
+		pr_err("%s: unable to set S3 voltage to 1.8V\n", __func__);
+		goto fail;
+	}
+
+	rc = regulator_enable(vreg_timpani_1);
+	if (rc) {
+		pr_err("%s: Enable regulator 8058_l0 failed\n", __func__);
+		goto fail;
+	}
+
+	/* The settings for LDO0 should be set such that
+	*  it doesn't require to reset the timpani. */
+	rc = regulator_set_optimum_mode(vreg_timpani_1, 5000);
+	if (rc < 0) {
+		pr_err("Timpani regulator optimum mode setting failed\n");
+		goto fail;
+	}
+
+	rc = regulator_enable(vreg_timpani_2);
+	if (rc) {
+		pr_err("%s: Enable regulator 8058_s3 failed\n", __func__);
+		regulator_disable(vreg_timpani_1);
+		goto fail;
+	}
+
+	rc = gpio_request(GPIO_CDC_RST_N, "CDC_RST_N");
+	if (rc) {
+		pr_err("%s: GPIO Request %d failed\n", __func__,
+			GPIO_CDC_RST_N);
+		regulator_disable(vreg_timpani_1);
+		regulator_disable(vreg_timpani_2);
+		goto fail;
+	} else {
+		gpio_direction_output(GPIO_CDC_RST_N, 1);
+		usleep_range(1000, 1050);
+		gpio_direction_output(GPIO_CDC_RST_N, 0);
+		usleep_range(1000, 1050);
+		gpio_direction_output(GPIO_CDC_RST_N, 1);
+		gpio_free(GPIO_CDC_RST_N);
+	}
+	return rc;
+
+fail:
+	regulator_put(vreg_timpani_1);
+	regulator_put(vreg_timpani_2);
+	return rc;
+}
+
+static void msm_timpani_shutdown_power(void)
+{
+	int rc;
+
+	rc = regulator_disable(vreg_timpani_1);
+	if (rc)
+		pr_err("%s: Disable regulator 8058_l0 failed\n", __func__);
+
+	regulator_put(vreg_timpani_1);
+
+	rc = regulator_disable(vreg_timpani_2);
+	if (rc)
+		pr_err("%s: Disable regulator 8058_s3 failed\n", __func__);
+
+	regulator_put(vreg_timpani_2);
+}
+
+/* Power analog function of codec */
+static struct regulator *vreg_timpani_cdc_apwr;
+static int msm_timpani_codec_power(int vreg_on)
+{
+	int rc = 0;
+
+	if (!vreg_timpani_cdc_apwr) {
+
+		vreg_timpani_cdc_apwr = regulator_get(NULL, "8058_s4");
+
+		if (IS_ERR(vreg_timpani_cdc_apwr)) {
+			pr_err("%s: vreg_get failed (%ld)\n",
+			__func__, PTR_ERR(vreg_timpani_cdc_apwr));
+			rc = PTR_ERR(vreg_timpani_cdc_apwr);
+			return rc;
+		}
+	}
+
+	if (vreg_on) {
+
+		rc = regulator_set_voltage(vreg_timpani_cdc_apwr,
+				2200000, 2200000);
+		if (rc) {
+			pr_err("%s: unable to set 8058_s4 voltage to 2.2 V\n",
+					__func__);
+			goto vreg_fail;
+		}
+
+		rc = regulator_enable(vreg_timpani_cdc_apwr);
+		if (rc) {
+			pr_err("%s: vreg_enable failed %d\n", __func__, rc);
+			goto vreg_fail;
+		}
+	} else {
+		rc = regulator_disable(vreg_timpani_cdc_apwr);
+		if (rc) {
+			pr_err("%s: vreg_disable failed %d\n",
+			__func__, rc);
+			goto vreg_fail;
+		}
+	}
+
+	return 0;
+
+vreg_fail:
+	regulator_put(vreg_timpani_cdc_apwr);
+	vreg_timpani_cdc_apwr = NULL;
+	return rc;
+}
+
+static struct marimba_codec_platform_data timpani_codec_pdata = {
+	.marimba_codec_power =  msm_timpani_codec_power,
+};
+
+#define TIMPANI_SLAVE_ID_CDC_ADDR		0X77
+#define TIMPANI_SLAVE_ID_QMEMBIST_ADDR		0X66
+
+static struct marimba_platform_data timpani_pdata = {
+	.slave_id[MARIMBA_SLAVE_ID_CDC]	= TIMPANI_SLAVE_ID_CDC_ADDR,
+	.slave_id[MARIMBA_SLAVE_ID_QMEMBIST] = TIMPANI_SLAVE_ID_QMEMBIST_ADDR,
+	.marimba_setup = msm_timpani_setup_power,
+	.marimba_shutdown = msm_timpani_shutdown_power,
+	.codec = &timpani_codec_pdata,
+	.tsadc_ssbi_adap = MARIMBA_SSBI_ADAP,
+};
+
+#define TIMPANI_I2C_SLAVE_ADDR	0xD
+
+static struct i2c_board_info msm_i2c_gsbi7_timpani_info[] = {
+	{
+		I2C_BOARD_INFO("timpani", TIMPANI_I2C_SLAVE_ADDR),
+		.platform_data = &timpani_pdata,
+	},
+};
+
+#ifdef CONFIG_SND_SOC_WM8903
+static struct wm8903_platform_data wm8903_pdata = {
+	.gpio_cfg[2] = 0x3A8,
+};
+
+#define WM8903_I2C_SLAVE_ADDR 0x34
+static struct i2c_board_info wm8903_codec_i2c_info[] = {
+	{
+		I2C_BOARD_INFO("wm8903", WM8903_I2C_SLAVE_ADDR >> 1),
+		.platform_data = &wm8903_pdata,
+	},
+};
+#endif
+#ifdef CONFIG_PMIC8901
+
+#define PM8901_GPIO_INT           91
+/*
+ * Consumer specific regulator names:
+ *			 regulator name		consumer dev_name
+ */
+static struct regulator_consumer_supply vreg_consumers_8901_USB_OTG[] = {
+	REGULATOR_SUPPLY("8901_usb_otg",	NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_8901_HDMI_MVS[] = {
+	REGULATOR_SUPPLY("8901_hdmi_mvs",	NULL),
+};
+
+#define PM8901_VREG_INIT(_id, _min_uV, _max_uV, _modes, _ops, _apply_uV, \
+			 _always_on) \
+	{ \
+		.init_data = { \
+			.constraints = { \
+				.valid_modes_mask = _modes, \
+				.valid_ops_mask = _ops, \
+				.min_uV = _min_uV, \
+				.max_uV = _max_uV, \
+				.input_uV = _min_uV, \
+				.apply_uV = _apply_uV, \
+				.always_on = _always_on, \
+			}, \
+			.consumer_supplies = vreg_consumers_8901_##_id, \
+			.num_consumer_supplies = \
+				ARRAY_SIZE(vreg_consumers_8901_##_id), \
+		}, \
+		.id = PM8901_VREG_ID_##_id, \
+	}
+
+#define PM8901_VREG_INIT_VS(_id) \
+	PM8901_VREG_INIT(_id, 0, 0, REGULATOR_MODE_NORMAL, \
+			REGULATOR_CHANGE_STATUS, 0, 0)
+
+static struct pm8901_vreg_pdata pm8901_vreg_init[] = {
+	PM8901_VREG_INIT_VS(USB_OTG),
+	PM8901_VREG_INIT_VS(HDMI_MVS),
+};
+
+static struct pm8xxx_misc_platform_data pm8901_misc_pdata = {
+	.priority		= 1,
+};
+
+static struct pm8xxx_irq_platform_data pm8901_irq_pdata = {
+	.irq_base		= PM8901_IRQ_BASE,
+	.devirq			= MSM_GPIO_TO_INT(PM8901_GPIO_INT),
+	.irq_trigger_flag	= IRQF_TRIGGER_LOW,
+};
+
+static struct pm8xxx_mpp_platform_data pm8901_mpp_pdata = {
+	.mpp_base		= PM8901_MPP_PM_TO_SYS(0),
+};
+
+static struct pm8901_platform_data pm8901_platform_data = {
+	.irq_pdata		= &pm8901_irq_pdata,
+	.mpp_pdata		= &pm8901_mpp_pdata,
+	.regulator_pdatas	= pm8901_vreg_init,
+	.num_regulators		= ARRAY_SIZE(pm8901_vreg_init),
+	.misc_pdata		= &pm8901_misc_pdata,
+};
+
+static struct msm_ssbi_platform_data msm8x60_ssbi_pm8901_pdata __devinitdata = {
+	.controller_type = MSM_SBI_CTRL_PMIC_ARBITER,
+	.slave	= {
+		.name = "pm8901-core",
+		.platform_data = &pm8901_platform_data,
+	},
+};
+#endif /* CONFIG_PMIC8901 */
+
+#if defined(CONFIG_MARIMBA_CORE) && (defined(CONFIG_GPIO_SX150X) \
+	|| defined(CONFIG_GPIO_SX150X_MODULE))
+
+static struct regulator *vreg_bahama;
+static int msm_bahama_sys_rst = GPIO_MS_SYS_RESET_N;
+
+struct bahama_config_register{
+	u8 reg;
+	u8 value;
+	u8 mask;
+};
+
+enum version{
+	VER_1_0,
+	VER_2_0,
+	VER_UNSUPPORTED = 0xFF
+};
+
+static u8 read_bahama_ver(void)
+{
+	int rc;
+	struct marimba config = { .mod_id = SLAVE_ID_BAHAMA };
+	u8 bahama_version;
+
+	rc = marimba_read_bit_mask(&config, 0x00,  &bahama_version, 1, 0x1F);
+	if (rc < 0) {
+		printk(KERN_ERR
+			 "%s: version read failed: %d\n",
+			__func__, rc);
+			return VER_UNSUPPORTED;
+	} else {
+		printk(KERN_INFO
+		"%s: version read got: 0x%x\n",
+		__func__, bahama_version);
+	}
+
+	switch (bahama_version) {
+	case 0x08: /* varient of bahama v1 */
+	case 0x10:
+	case 0x00:
+		return VER_1_0;
+	case 0x09: /* variant of bahama v2 */
+		return VER_2_0;
+	default:
+		return VER_UNSUPPORTED;
+	}
+}
+
+static int msm_bahama_setup_power_enable;
+static unsigned int msm_bahama_setup_power(void)
+{
+	int rc = 0;
+	const char *msm_bahama_regulator = "8058_s3";
+
+	if (machine_is_msm8x60_dragon())
+		msm_bahama_sys_rst = GPIO_CDC_RST_N;
+
+	vreg_bahama = regulator_get(NULL, msm_bahama_regulator);
+
+	if (IS_ERR(vreg_bahama)) {
+		rc = PTR_ERR(vreg_bahama);
+		pr_err("%s: regulator_get %s = %d\n", __func__,
+			msm_bahama_regulator, rc);
+		return rc;
+	}
+
+	rc = regulator_set_voltage(vreg_bahama, 1800000, 1800000);
+	if (rc) {
+		pr_err("%s: regulator_set_voltage %s = %d\n", __func__,
+			msm_bahama_regulator, rc);
+		goto unget;
+	}
+
+	rc = regulator_enable(vreg_bahama);
+	if (rc) {
+		pr_err("%s: regulator_enable %s = %d\n", __func__,
+			msm_bahama_regulator, rc);
+		goto unget;
+	}
+
+	rc = gpio_request(msm_bahama_sys_rst, "bahama sys_rst_n");
+	if (rc) {
+		pr_err("%s: gpio_request %d = %d\n", __func__,
+			msm_bahama_sys_rst, rc);
+		goto unenable;
+	}
+
+	gpio_direction_output(msm_bahama_sys_rst, 0);
+	usleep_range(1000, 1050);
+	gpio_set_value_cansleep(msm_bahama_sys_rst, 1);
+	usleep_range(1000, 1050);
+	msm_bahama_setup_power_enable = 1;
+	return rc;
+
+unenable:
+	regulator_disable(vreg_bahama);
+unget:
+	regulator_put(vreg_bahama);
+	return rc;
+};
+
+static unsigned int msm_bahama_shutdown_power(int value)
+{
+	if (msm_bahama_setup_power_enable) {
+		gpio_set_value_cansleep(msm_bahama_sys_rst, 0);
+		gpio_free(msm_bahama_sys_rst);
+		regulator_disable(vreg_bahama);
+		regulator_put(vreg_bahama);
+		msm_bahama_setup_power_enable = 0;
+	}
+
+	return 0;
+};
+
+static unsigned int msm_bahama_core_config(int type)
+{
+	int rc = 0;
+
+	if (type == BAHAMA_ID) {
+
+		int i;
+		struct marimba config = { .mod_id = SLAVE_ID_BAHAMA };
+
+		const struct bahama_config_register v20_init[] = {
+			/* reg, value, mask */
+			{ 0xF4, 0x84, 0xFF }, /* AREG */
+			{ 0xF0, 0x04, 0xFF } /* DREG */
+		};
+
+		if (read_bahama_ver() == VER_2_0) {
+			for (i = 0; i < ARRAY_SIZE(v20_init); i++) {
+				u8 value = v20_init[i].value;
+				rc = marimba_write_bit_mask(&config,
+					v20_init[i].reg,
+					&value,
+					sizeof(v20_init[i].value),
+					v20_init[i].mask);
+				if (rc < 0) {
+					printk(KERN_ERR
+						"%s: reg %d write failed: %d\n",
+						__func__, v20_init[i].reg, rc);
+					return rc;
+				}
+				printk(KERN_INFO "%s: reg 0x%02x value 0x%02x"
+					" mask 0x%02x\n",
+					__func__, v20_init[i].reg,
+					v20_init[i].value, v20_init[i].mask);
+			}
+		}
+	}
+	printk(KERN_INFO "core type: %d\n", type);
+
+	return rc;
+}
+
+static struct regulator *fm_regulator_s3;
+static struct msm_xo_voter *fm_clock;
+
+static int fm_radio_setup(struct marimba_fm_platform_data *pdata)
+{
+	int rc = 0;
+	struct pm_gpio cfg = {
+				.direction      = PM_GPIO_DIR_IN,
+				.pull           = PM_GPIO_PULL_NO,
+				.vin_sel        = PM8058_GPIO_VIN_S3,
+				.function       = PM_GPIO_FUNC_NORMAL,
+				.inv_int_pol    = 0,
+				};
+
+	if (!fm_regulator_s3) {
+		fm_regulator_s3 = regulator_get(NULL, "8058_s3");
+		if (IS_ERR(fm_regulator_s3)) {
+			rc = PTR_ERR(fm_regulator_s3);
+			printk(KERN_ERR "%s: regulator get s3 (%d)\n",
+				__func__, rc);
+			goto out;
+			}
+	}
+
+
+	rc = regulator_set_voltage(fm_regulator_s3, 1800000, 1800000);
+	if (rc < 0) {
+		printk(KERN_ERR "%s: regulator set voltage failed (%d)\n",
+				__func__, rc);
+		goto fm_fail_put;
+	}
+
+	rc = regulator_enable(fm_regulator_s3);
+	if (rc < 0) {
+		printk(KERN_ERR "%s: regulator s3 enable failed (%d)\n",
+					__func__, rc);
+		goto fm_fail_put;
+	}
+
+	/*Vote for XO clock*/
+	fm_clock = msm_xo_get(MSM_XO_TCXO_D0, "fm_power");
+
+	if (IS_ERR(fm_clock)) {
+		rc = PTR_ERR(fm_clock);
+		printk(KERN_ERR "%s: Couldn't get TCXO_D0 vote for FM (%d)\n",
+					__func__, rc);
+		goto fm_fail_switch;
+	}
+
+	rc = msm_xo_mode_vote(fm_clock, MSM_XO_MODE_ON);
+	if (rc < 0) {
+		printk(KERN_ERR "%s:  Failed to vote for TCX0_D0 ON (%d)\n",
+					__func__, rc);
+		goto fm_fail_vote;
+	}
+
+	/*GPIO 18 on PMIC is FM_IRQ*/
+	rc = pm8xxx_gpio_config(PM8058_GPIO_PM_TO_SYS(FM_GPIO), &cfg);
+	if (rc) {
+		printk(KERN_ERR "%s: return val of pm8xxx_gpio_config: %d\n",
+						__func__,  rc);
+		goto fm_fail_clock;
+	}
+	goto out;
+
+fm_fail_clock:
+		msm_xo_mode_vote(fm_clock, MSM_XO_MODE_OFF);
+fm_fail_vote:
+		msm_xo_put(fm_clock);
+fm_fail_switch:
+		regulator_disable(fm_regulator_s3);
+fm_fail_put:
+		regulator_put(fm_regulator_s3);
+out:
+	return rc;
+};
+
+static void fm_radio_shutdown(struct marimba_fm_platform_data *pdata)
+{
+	int rc = 0;
+	if (fm_regulator_s3 != NULL) {
+		rc = regulator_disable(fm_regulator_s3);
+		if (rc < 0) {
+			printk(KERN_ERR "%s: regulator s3 disable (%d)\n",
+							__func__, rc);
+		}
+		regulator_put(fm_regulator_s3);
+		fm_regulator_s3 = NULL;
+	}
+	printk(KERN_ERR "%s: Voting off for XO", __func__);
+
+	if (fm_clock != NULL) {
+		rc = msm_xo_mode_vote(fm_clock, MSM_XO_MODE_OFF);
+		if (rc < 0) {
+			printk(KERN_ERR "%s: Voting off XO clock (%d)\n",
+					__func__, rc);
+		}
+		msm_xo_put(fm_clock);
+	}
+	printk(KERN_ERR "%s: coming out of fm_radio_shutdown", __func__);
+}
+
+/* Slave id address for FM/CDC/QMEMBIST
+ * Values can be programmed using Marimba slave id 0
+ * should there be a conflict with other I2C devices
+ * */
+#define BAHAMA_SLAVE_ID_FM_ADDR         0x2A
+#define BAHAMA_SLAVE_ID_QMEMBIST_ADDR   0x7B
+
+static struct marimba_fm_platform_data marimba_fm_pdata = {
+	.fm_setup =  fm_radio_setup,
+	.fm_shutdown = fm_radio_shutdown,
+	.irq = PM8058_GPIO_IRQ(PM8058_IRQ_BASE, FM_GPIO),
+	.is_fm_soc_i2s_master = false,
+	.config_i2s_gpio = NULL,
+};
+
+/*
+Just initializing the BAHAMA related slave
+*/
+static struct marimba_platform_data marimba_pdata = {
+	.slave_id[SLAVE_ID_BAHAMA_FM]        = BAHAMA_SLAVE_ID_FM_ADDR,
+	.slave_id[SLAVE_ID_BAHAMA_QMEMBIST]  = BAHAMA_SLAVE_ID_QMEMBIST_ADDR,
+	.bahama_setup = msm_bahama_setup_power,
+	.bahama_shutdown = msm_bahama_shutdown_power,
+	.bahama_core_config = msm_bahama_core_config,
+	.fm = &marimba_fm_pdata,
+	.tsadc_ssbi_adap = MARIMBA_SSBI_ADAP,
+};
+
+
+static struct i2c_board_info msm_marimba_board_info[] = {
+	{
+		I2C_BOARD_INFO("marimba", 0xc),
+		.platform_data = &marimba_pdata,
+	}
+};
+#endif /* CONFIG_MAIMBA_CORE */
+
+#ifdef CONFIG_I2C
+#define I2C_SURF 1
+#define I2C_FFA  (1 << 1)
+#define I2C_RUMI (1 << 2)
+#define I2C_SIM  (1 << 3)
+#define I2C_FLUID (1 << 4)
+#define I2C_DRAGON (1 << 5)
+
+struct i2c_registry {
+	u8                     machs;
+	int                    bus;
+	struct i2c_board_info *info;
+	int                    len;
+};
+
+static struct i2c_registry msm8x60_i2c_devices[] __initdata = {
+#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
+	{
+		I2C_SURF | I2C_FFA | I2C_DRAGON,
+		MSM_GSBI8_QUP_I2C_BUS_ID,
+		core_expander_i2c_info,
+		ARRAY_SIZE(core_expander_i2c_info),
+	},
+	{
+		I2C_SURF | I2C_FFA | I2C_DRAGON,
+		MSM_GSBI8_QUP_I2C_BUS_ID,
+		docking_expander_i2c_info,
+		ARRAY_SIZE(docking_expander_i2c_info),
+	},
+	{
+		I2C_SURF,
+		MSM_GSBI8_QUP_I2C_BUS_ID,
+		surf_expanders_i2c_info,
+		ARRAY_SIZE(surf_expanders_i2c_info),
+	},
+	{
+		I2C_SURF | I2C_FFA | I2C_DRAGON,
+		MSM_GSBI3_QUP_I2C_BUS_ID,
+		fha_expanders_i2c_info,
+		ARRAY_SIZE(fha_expanders_i2c_info),
+	},
+	{
+		I2C_FLUID,
+		MSM_GSBI3_QUP_I2C_BUS_ID,
+		fluid_expanders_i2c_info,
+		ARRAY_SIZE(fluid_expanders_i2c_info),
+	},
+	{
+		I2C_FLUID,
+		MSM_GSBI8_QUP_I2C_BUS_ID,
+		fluid_core_expander_i2c_info,
+		ARRAY_SIZE(fluid_core_expander_i2c_info),
+	},
+#endif
+#if defined(CONFIG_TOUCHDISC_VTD518_SHINETSU) || \
+		defined(CONFIG_TOUCHDISC_VTD518_SHINETSU_MODULE)
+	{
+		I2C_SURF | I2C_FFA | I2C_FLUID | I2C_DRAGON,
+		MSM_GSBI3_QUP_I2C_BUS_ID,
+		msm_i2c_gsbi3_tdisc_info,
+		ARRAY_SIZE(msm_i2c_gsbi3_tdisc_info),
+	},
+#endif
+	{
+		I2C_SURF | I2C_FFA | I2C_FLUID,
+		MSM_GSBI3_QUP_I2C_BUS_ID,
+		cy8ctmg200_board_info,
+		ARRAY_SIZE(cy8ctmg200_board_info),
+	},
+	{
+		I2C_DRAGON,
+		MSM_GSBI3_QUP_I2C_BUS_ID,
+		cy8ctma340_dragon_board_info,
+		ARRAY_SIZE(cy8ctma340_dragon_board_info),
+	},
+#if defined(CONFIG_TOUCHSCREEN_CYTTSP_I2C_QC) || \
+		defined(CONFIG_TOUCHSCREEN_CYTTSP_I2C_QC_MODULE)
+	{
+		I2C_FLUID,
+		MSM_GSBI3_QUP_I2C_BUS_ID,
+		cyttsp_fluid_info,
+		ARRAY_SIZE(cyttsp_fluid_info),
+	},
+	{
+		I2C_FFA | I2C_SURF,
+		MSM_GSBI3_QUP_I2C_BUS_ID,
+		cyttsp_ffa_info,
+		ARRAY_SIZE(cyttsp_ffa_info),
+	},
+#endif
+#ifdef CONFIG_MSM_CAMERA
+#ifndef CONFIG_MSM_CAMERA_V4L2
+	{
+		I2C_SURF | I2C_FFA | I2C_FLUID ,
+		MSM_GSBI4_QUP_I2C_BUS_ID,
+		msm_camera_boardinfo,
+		ARRAY_SIZE(msm_camera_boardinfo),
+	},
+	{
+		I2C_DRAGON,
+		MSM_GSBI4_QUP_I2C_BUS_ID,
+		msm_camera_dragon_boardinfo,
+		ARRAY_SIZE(msm_camera_dragon_boardinfo),
+	},
+#endif
+#endif
+	{
+		I2C_SURF | I2C_FFA | I2C_FLUID,
+		MSM_GSBI7_QUP_I2C_BUS_ID,
+		msm_i2c_gsbi7_timpani_info,
+		ARRAY_SIZE(msm_i2c_gsbi7_timpani_info),
+	},
+#if defined(CONFIG_MARIMBA_CORE)
+	{
+		I2C_SURF | I2C_FFA | I2C_FLUID | I2C_DRAGON,
+		MSM_GSBI7_QUP_I2C_BUS_ID,
+		msm_marimba_board_info,
+		ARRAY_SIZE(msm_marimba_board_info),
+	},
+#endif /* CONFIG_MARIMBA_CORE */
+#ifdef CONFIG_ISL9519_CHARGER
+	{
+		I2C_SURF | I2C_FFA,
+		MSM_GSBI8_QUP_I2C_BUS_ID,
+		isl_charger_i2c_info,
+		ARRAY_SIZE(isl_charger_i2c_info),
+	},
+#endif
+#if defined(CONFIG_HAPTIC_ISA1200) || \
+		defined(CONFIG_HAPTIC_ISA1200_MODULE)
+	{
+		I2C_FLUID,
+		MSM_GSBI8_QUP_I2C_BUS_ID,
+		msm_isa1200_board_info,
+		ARRAY_SIZE(msm_isa1200_board_info),
+	},
+#endif
+#if defined(CONFIG_SMB137B_CHARGER) || defined(CONFIG_SMB137B_CHARGER_MODULE)
+	{
+		I2C_FLUID,
+		MSM_GSBI8_QUP_I2C_BUS_ID,
+		smb137b_charger_i2c_info,
+		ARRAY_SIZE(smb137b_charger_i2c_info),
+	},
+#endif
+#if defined(CONFIG_BATTERY_BQ27520) || \
+		defined(CONFIG_BATTERY_BQ27520_MODULE)
+	{
+		I2C_FLUID,
+		MSM_GSBI8_QUP_I2C_BUS_ID,
+		msm_bq27520_board_info,
+		ARRAY_SIZE(msm_bq27520_board_info),
+	},
+#endif
+#if defined(CONFIG_SND_SOC_WM8903) || defined(CONFIG_SND_SOC_WM8903_MODULE)
+	{
+		I2C_DRAGON,
+		MSM_GSBI8_QUP_I2C_BUS_ID,
+		wm8903_codec_i2c_info,
+		ARRAY_SIZE(wm8903_codec_i2c_info),
+	},
+#endif
+};
+#endif /* CONFIG_I2C */
+
+static void __init fixup_i2c_configs(void)
+{
+#ifdef CONFIG_I2C
+#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
+	if (machine_is_msm8x60_surf() || machine_is_msm8x60_fusion())
+		sx150x_data[SX150X_CORE].irq_summary =
+			PM8058_GPIO_IRQ(PM8058_IRQ_BASE, UI_INT2_N);
+	else if (machine_is_msm8x60_ffa() || machine_is_msm8x60_fusn_ffa() ||
+		machine_is_msm8x60_dragon())
+		sx150x_data[SX150X_CORE].irq_summary =
+			PM8058_GPIO_IRQ(PM8058_IRQ_BASE, UI_INT1_N);
+	else if (machine_is_msm8x60_fluid())
+		sx150x_data[SX150X_CORE_FLUID].irq_summary =
+			PM8058_GPIO_IRQ(PM8058_IRQ_BASE, UI_INT1_N);
+#endif
+#endif
+}
+
+static void __init register_i2c_devices(void)
+{
+#ifdef CONFIG_I2C
+	u8 mach_mask = 0;
+	int i;
+#ifdef CONFIG_MSM_CAMERA_V4L2
+	struct i2c_registry msm8x60_camera_i2c_devices = {
+		I2C_SURF | I2C_FFA | I2C_FLUID,
+		MSM_GSBI4_QUP_I2C_BUS_ID,
+		msm8x60_camera_board_info.board_info,
+		msm8x60_camera_board_info.num_i2c_board_info,
+	};
+#endif
+
+	/* Build the matching 'supported_machs' bitmask */
+	if (machine_is_msm8x60_surf() || machine_is_msm8x60_fusion())
+		mach_mask = I2C_SURF;
+	else if (machine_is_msm8x60_ffa() || machine_is_msm8x60_fusn_ffa())
+		mach_mask = I2C_FFA;
+	else if (machine_is_msm8x60_rumi3())
+		mach_mask = I2C_RUMI;
+	else if (machine_is_msm8x60_sim())
+		mach_mask = I2C_SIM;
+	else if (machine_is_msm8x60_fluid())
+		mach_mask = I2C_FLUID;
+	else if (machine_is_msm8x60_dragon())
+		mach_mask = I2C_DRAGON;
+	else
+		pr_err("unmatched machine ID in register_i2c_devices\n");
+
+	/* Run the array and install devices as appropriate */
+	for (i = 0; i < ARRAY_SIZE(msm8x60_i2c_devices); ++i) {
+		if (msm8x60_i2c_devices[i].machs & mach_mask)
+			i2c_register_board_info(msm8x60_i2c_devices[i].bus,
+						msm8x60_i2c_devices[i].info,
+						msm8x60_i2c_devices[i].len);
+	}
+#ifdef CONFIG_MSM_CAMERA_V4L2
+	if (msm8x60_camera_i2c_devices.machs & mach_mask)
+		i2c_register_board_info(msm8x60_camera_i2c_devices.bus,
+			msm8x60_camera_i2c_devices.info,
+			msm8x60_camera_i2c_devices.len);
+#endif
+#endif
+}
+
+static void __init msm8x60_init_uart12dm(void)
+{
+#if !defined(CONFIG_USB_PEHCI_HCD) && !defined(CONFIG_USB_PEHCI_HCD_MODULE)
+	/* 0x1D000000 now belongs to EBI2:CS3 i.e. USB ISP Controller */
+	void *fpga_mem = ioremap_nocache(0x1D000000, SZ_4K);
+
+	if (!fpga_mem)
+		pr_err("%s(): Error getting memory\n", __func__);
+
+	/* Advanced mode */
+	writew(0xFFFF, fpga_mem + 0x15C);
+	/* FPGA_UART_SEL */
+	writew(0, fpga_mem + 0x172);
+	/* FPGA_GPIO_CONFIG_117 */
+	writew(1, fpga_mem + 0xEA);
+	/* FPGA_GPIO_CONFIG_118 */
+	writew(1, fpga_mem + 0xEC);
+	mb();
+	iounmap(fpga_mem);
+#endif
+}
+
+#define MSM_GSBI9_PHYS		0x19900000
+#define GSBI_DUAL_MODE_CODE	0x60
+
+static void __init msm8x60_init_buses(void)
+{
+#ifdef CONFIG_I2C_QUP
+	void *gsbi_mem = ioremap_nocache(0x19C00000, 4);
+	/* Setting protocol code to 0x60 for dual UART/I2C in GSBI12 */
+	writel_relaxed(0x6 << 4, gsbi_mem);
+	/* Ensure protocol code is written before proceeding further */
+	mb();
+	iounmap(gsbi_mem);
+
+	msm_gsbi3_qup_i2c_device.dev.platform_data = &msm_gsbi3_qup_i2c_pdata;
+	msm_gsbi4_qup_i2c_device.dev.platform_data = &msm_gsbi4_qup_i2c_pdata;
+	msm_gsbi7_qup_i2c_device.dev.platform_data = &msm_gsbi7_qup_i2c_pdata;
+	msm_gsbi8_qup_i2c_device.dev.platform_data = &msm_gsbi8_qup_i2c_pdata;
+
+#ifdef CONFIG_MSM_GSBI9_UART
+	if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa()) {
+		/* Setting protocol code to 0x60 for dual UART/I2C in GSBI9 */
+		gsbi_mem = ioremap_nocache(MSM_GSBI9_PHYS, 4);
+		writel_relaxed(GSBI_DUAL_MODE_CODE, gsbi_mem);
+		iounmap(gsbi_mem);
+		msm_gsbi9_qup_i2c_pdata.use_gsbi_shared_mode = 1;
+	}
+#endif
+	msm_gsbi9_qup_i2c_device.dev.platform_data = &msm_gsbi9_qup_i2c_pdata;
+	msm_gsbi12_qup_i2c_device.dev.platform_data = &msm_gsbi12_qup_i2c_pdata;
+#endif
+#if defined(CONFIG_SPI_QUP) || defined(CONFIG_SPI_QUP_MODULE)
+	msm_gsbi1_qup_spi_device.dev.platform_data = &msm_gsbi1_qup_spi_pdata;
+#endif
+#ifdef CONFIG_I2C_SSBI
+	msm_device_ssbi3.dev.platform_data = &msm_ssbi3_pdata;
+#endif
+
+#ifdef CONFIG_MSM_SSBI
+	msm_device_ssbi_pmic1.dev.platform_data =
+				&msm8x60_ssbi_pm8058_pdata;
+	msm_device_ssbi_pmic2.dev.platform_data =
+				&msm8x60_ssbi_pm8901_pdata;
+#endif
+
+	if (machine_is_msm8x60_fluid()) {
+#if (defined(CONFIG_USB_EHCI_MSM_72K) && \
+	(defined(CONFIG_SMB137B_CHARGER) || \
+	 defined(CONFIG_SMB137B_CHARGER_MODULE)))
+		msm_otg_pdata.vbus_power = msm_hsusb_smb137b_vbus_power;
+#endif
+#if defined(CONFIG_SPI_QUP) || defined(CONFIG_SPI_QUP_MODULE)
+		msm_gsbi10_qup_spi_device.dev.platform_data =
+					&msm_gsbi10_qup_spi_pdata;
+#endif
+	}
+
+#if defined(CONFIG_USB_MSM_72K) || defined(CONFIG_USB_EHCI_HCD)
+	/*
+	 * We can not put USB regulators (8058_l6 and 8058_l7) in LPM
+	 * when we depend on USB PHY for VBUS/ID notifications. VBUS
+	 * and ID notifications are available only on V2 surf and FFA
+	 * with a hardware workaround.
+	 */
+	if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2 &&
+			(machine_is_msm8x60_surf() ||
+			(machine_is_msm8x60_ffa() &&
+			pmic_id_notif_supported)))
+		msm_otg_pdata.phy_can_powercollapse = 1;
+	msm_device_otg.dev.platform_data = &msm_otg_pdata;
+#endif
+
+#ifdef CONFIG_USB_MSM_72K
+	msm_device_gadget_peripheral.dev.platform_data = &msm_gadget_pdata;
+#endif
+
+#ifdef CONFIG_SERIAL_MSM_HS
+	msm_uart_dm1_pdata.wakeup_irq = gpio_to_irq(54); /* GSBI6(2) */
+	msm_device_uart_dm1.dev.platform_data = &msm_uart_dm1_pdata;
+#endif
+#ifdef CONFIG_MSM_GSBI9_UART
+	if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa()) {
+		msm_device_uart_gsbi9 = msm_add_gsbi9_uart();
+		if (IS_ERR(msm_device_uart_gsbi9))
+			pr_err("%s(): Failed to create uart gsbi9 device\n",
+								__func__);
+	}
+#endif
+
+#ifdef CONFIG_MSM_BUS_SCALING
+
+	/* RPM calls are only enabled on V2 */
+	if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2) {
+		msm_bus_apps_fabric_pdata.rpm_enabled = 1;
+		msm_bus_sys_fabric_pdata.rpm_enabled = 1;
+		msm_bus_mm_fabric_pdata.rpm_enabled = 1;
+		msm_bus_sys_fpb_pdata.rpm_enabled = 1;
+		msm_bus_cpss_fpb_pdata.rpm_enabled = 1;
+	}
+
+	msm_bus_apps_fabric.dev.platform_data = &msm_bus_apps_fabric_pdata;
+	msm_bus_sys_fabric.dev.platform_data = &msm_bus_sys_fabric_pdata;
+	msm_bus_mm_fabric.dev.platform_data = &msm_bus_mm_fabric_pdata;
+	msm_bus_sys_fpb.dev.platform_data = &msm_bus_sys_fpb_pdata;
+	msm_bus_cpss_fpb.dev.platform_data = &msm_bus_cpss_fpb_pdata;
+#endif
 }
 
 static void __init msm8x60_map_io(void)
 {
+	msm_shared_ram_phys = MSM_SHARED_RAM_PHYS;
 	msm_map_msm8x60_io();
+
+	if (socinfo_init() < 0)
+		pr_err("socinfo_init() failed!\n");
 }
 
-#ifdef CONFIG_OF
-static struct of_device_id msm_dt_gic_match[] __initdata = {
-	{ .compatible = "qcom,msm-8660-qgic", .data = gic_of_init },
-	{}
-};
-#endif
-
-static void __init msm8x60_init_irq(void)
+/*
+ * Most segments of the EBI2 bus are disabled by default.
+ */
+static void __init msm8x60_init_ebi2(void)
 {
-	if (!of_have_populated_dt())
-		gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE,
-			 (void *)MSM_QGIC_CPU_BASE);
-#ifdef CONFIG_OF
-	else
-		of_irq_init(msm_dt_gic_match);
-#endif
+	uint32_t ebi2_cfg;
+	void *ebi2_cfg_ptr;
+	struct clk *mem_clk = clk_get_sys("msm_ebi2", "mem_clk");
 
-	/* Edge trigger PPIs except AVS_SVICINT and AVS_SVICINTSWDONE */
-	writel(0xFFFFD7FF, MSM_QGIC_DIST_BASE + GIC_DIST_CONFIG + 4);
+	if (IS_ERR(mem_clk)) {
+		pr_err("%s: clk_get_sys(%s,%s), failed", __func__,
+					"msm_ebi2", "mem_clk");
+		return;
+	}
+	clk_prepare_enable(mem_clk);
+	clk_put(mem_clk);
 
-	/* RUMI does not adhere to GIC spec by enabling STIs by default.
-	 * Enable/clear is supposed to be RO for STIs, but is RW on RUMI.
-	 */
-	if (!machine_is_msm8x60_sim())
-		writel(0x0000FFFF, MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET);
-}
+	ebi2_cfg_ptr = ioremap_nocache(0x1a100000, sizeof(uint32_t));
+	if (ebi2_cfg_ptr != 0) {
+		ebi2_cfg = readl_relaxed(ebi2_cfg_ptr);
 
-static void __init msm8x60_init(void)
-{
-}
+		if (machine_is_msm8x60_surf() || machine_is_msm8x60_ffa() ||
+			machine_is_msm8x60_fluid() ||
+			machine_is_msm8x60_dragon())
+			ebi2_cfg |= (1 << 4) | (1 << 5); /* CS2, CS3 */
+		else if (machine_is_msm8x60_sim())
+			ebi2_cfg |= (1 << 4); /* CS2 */
+		else if (machine_is_msm8x60_rumi3())
+			ebi2_cfg |= (1 << 5); /* CS3 */
 
-#ifdef CONFIG_OF
-static struct of_dev_auxdata msm_auxdata_lookup[] __initdata = {
-	{}
-};
-
-static void __init msm8x60_dt_init(void)
-{
-	if (of_machine_is_compatible("qcom,msm8660-surf")) {
-		printk(KERN_INFO "Init surf UART registers\n");
-		msm8x60_init_uart12dm();
+		writel_relaxed(ebi2_cfg, ebi2_cfg_ptr);
+		iounmap(ebi2_cfg_ptr);
 	}
 
-	of_platform_populate(NULL, of_default_bus_match_table,
-			msm_auxdata_lookup, NULL);
+	if (machine_is_msm8x60_surf() || machine_is_msm8x60_ffa() ||
+	    machine_is_msm8x60_fluid() || machine_is_msm8x60_dragon()) {
+		ebi2_cfg_ptr = ioremap_nocache(0x1a110000, SZ_4K);
+		if (ebi2_cfg_ptr != 0) {
+			/* EBI2_XMEM_CFG:PWRSAVE_MODE off */
+			writel_relaxed(0UL, ebi2_cfg_ptr);
+
+			/* CS2: Delay 9 cycles (140ns@64MHz) between SMSC
+			 * LAN9221 Ethernet controller reads and writes.
+			 * The lowest 4 bits are the read delay, the next
+			 * 4 are the write delay. */
+			writel_relaxed(0x031F1C99, ebi2_cfg_ptr + 0x10);
+#if defined(CONFIG_USB_PEHCI_HCD) || defined(CONFIG_USB_PEHCI_HCD_MODULE)
+			/*
+			 * RECOVERY=5, HOLD_WR=1
+			 * INIT_LATENCY_WR=1, INIT_LATENCY_RD=1
+			 * WAIT_WR=1, WAIT_RD=2
+			 */
+			writel_relaxed(0x51010112, ebi2_cfg_ptr + 0x14);
+			/*
+			 * HOLD_RD=1
+			 * ADV_OE_RECOVERY=0, ADDR_HOLD_ENA=1
+			 */
+			writel_relaxed(0x01000020, ebi2_cfg_ptr + 0x34);
+#else
+			/* EBI2 CS3 muxed address/data,
+			* two cyc addr enable */
+			writel_relaxed(0xA3030020, ebi2_cfg_ptr + 0x34);
+
+#endif
+			iounmap(ebi2_cfg_ptr);
+		}
+	}
 }
 
-static const char *msm8x60_fluid_match[] __initdata = {
-	"qcom,msm8660-fluid",
-	"qcom,msm8660-surf",
-	NULL
+static void __init msm8x60_configure_smc91x(void)
+{
+	if (machine_is_msm8x60_sim()) {
+
+		smc91x_resources[0].start = 0x1b800300;
+		smc91x_resources[0].end   = 0x1b8003ff;
+
+		smc91x_resources[1].start = (NR_MSM_IRQS + 40);
+		smc91x_resources[1].end   = (NR_MSM_IRQS + 40);
+
+	} else if (machine_is_msm8x60_rumi3()) {
+
+		smc91x_resources[0].start = 0x1d000300;
+		smc91x_resources[0].end   = 0x1d0003ff;
+
+		smc91x_resources[1].start = TLMM_MSM_DIR_CONN_IRQ_0;
+		smc91x_resources[1].end   = TLMM_MSM_DIR_CONN_IRQ_0;
+	}
+}
+
+static void __init msm8x60_init_tlmm(void)
+{
+	if (machine_is_msm8x60_rumi3())
+		msm_gpio_install_direct_irq(0, 0, 1);
+}
+
+#if (defined(CONFIG_MMC_MSM_SDC1_SUPPORT)\
+	|| defined(CONFIG_MMC_MSM_SDC2_SUPPORT)\
+	|| defined(CONFIG_MMC_MSM_SDC3_SUPPORT)\
+	|| defined(CONFIG_MMC_MSM_SDC4_SUPPORT)\
+	|| defined(CONFIG_MMC_MSM_SDC5_SUPPORT))
+
+/* 8x60 has 5 SDCC controllers */
+#define MAX_SDCC_CONTROLLER	5
+
+struct msm_sdcc_gpio {
+	/* maximum 10 GPIOs per SDCC controller */
+	s16 no;
+	/* name of this GPIO */
+	const char *name;
+	bool always_on;
+	bool is_enabled;
 };
-#endif /* CONFIG_OF */
+
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+static struct msm_sdcc_gpio sdc1_gpio_cfg[] = {
+	{159, "sdc1_dat_0"},
+	{160, "sdc1_dat_1"},
+	{161, "sdc1_dat_2"},
+	{162, "sdc1_dat_3"},
+#ifdef CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT
+	{163, "sdc1_dat_4"},
+	{164, "sdc1_dat_5"},
+	{165, "sdc1_dat_6"},
+	{166, "sdc1_dat_7"},
+#endif
+	{167, "sdc1_clk"},
+	{168, "sdc1_cmd"}
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+static struct msm_sdcc_gpio sdc2_gpio_cfg[] = {
+	{143, "sdc2_dat_0"},
+	{144, "sdc2_dat_1", 1},
+	{145, "sdc2_dat_2"},
+	{146, "sdc2_dat_3"},
+#ifdef CONFIG_MMC_MSM_SDC2_8_BIT_SUPPORT
+	{147, "sdc2_dat_4"},
+	{148, "sdc2_dat_5"},
+	{149, "sdc2_dat_6"},
+	{150, "sdc2_dat_7"},
+#endif
+	{151, "sdc2_cmd"},
+	{152, "sdc2_clk", 1}
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC5_SUPPORT
+static struct msm_sdcc_gpio sdc5_gpio_cfg[] = {
+	{95, "sdc5_cmd"},
+	{96, "sdc5_dat_3"},
+	{97, "sdc5_clk", 1},
+	{98, "sdc5_dat_2"},
+	{99, "sdc5_dat_1", 1},
+	{100, "sdc5_dat_0"}
+};
+#endif
+
+struct msm_sdcc_pad_pull_cfg {
+	enum msm_tlmm_pull_tgt pull;
+	u32 pull_val;
+};
+
+struct msm_sdcc_pad_drv_cfg {
+	enum msm_tlmm_hdrive_tgt drv;
+	u32 drv_val;
+};
+
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+static struct msm_sdcc_pad_drv_cfg sdc3_pad_on_drv_cfg[] = {
+	{TLMM_HDRV_SDC3_CLK, GPIO_CFG_8MA},
+	{TLMM_HDRV_SDC3_CMD, GPIO_CFG_8MA},
+	{TLMM_HDRV_SDC3_DATA, GPIO_CFG_8MA}
+};
+
+static struct msm_sdcc_pad_pull_cfg sdc3_pad_on_pull_cfg[] = {
+	{TLMM_PULL_SDC3_CMD, GPIO_CFG_PULL_UP},
+	{TLMM_PULL_SDC3_DATA, GPIO_CFG_PULL_UP}
+};
+
+static struct msm_sdcc_pad_drv_cfg sdc3_pad_off_drv_cfg[] = {
+	{TLMM_HDRV_SDC3_CLK, GPIO_CFG_2MA},
+	{TLMM_HDRV_SDC3_CMD, GPIO_CFG_2MA},
+	{TLMM_HDRV_SDC3_DATA, GPIO_CFG_2MA}
+};
+
+static struct msm_sdcc_pad_pull_cfg sdc3_pad_off_pull_cfg[] = {
+	{TLMM_PULL_SDC3_CMD, GPIO_CFG_PULL_DOWN},
+	{TLMM_PULL_SDC3_DATA, GPIO_CFG_PULL_DOWN}
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+static struct msm_sdcc_pad_drv_cfg sdc4_pad_on_drv_cfg[] = {
+	{TLMM_HDRV_SDC4_CLK, GPIO_CFG_8MA},
+	{TLMM_HDRV_SDC4_CMD, GPIO_CFG_8MA},
+	{TLMM_HDRV_SDC4_DATA, GPIO_CFG_8MA}
+};
+
+static struct msm_sdcc_pad_pull_cfg sdc4_pad_on_pull_cfg[] = {
+	{TLMM_PULL_SDC4_CMD, GPIO_CFG_PULL_UP},
+	{TLMM_PULL_SDC4_DATA, GPIO_CFG_PULL_UP}
+};
+
+static struct msm_sdcc_pad_drv_cfg sdc4_pad_off_drv_cfg[] = {
+	{TLMM_HDRV_SDC4_CLK, GPIO_CFG_2MA},
+	{TLMM_HDRV_SDC4_CMD, GPIO_CFG_2MA},
+	{TLMM_HDRV_SDC4_DATA, GPIO_CFG_2MA}
+};
+
+static struct msm_sdcc_pad_pull_cfg sdc4_pad_off_pull_cfg[] = {
+	{TLMM_PULL_SDC4_CMD, GPIO_CFG_PULL_DOWN},
+	{TLMM_PULL_SDC4_DATA, GPIO_CFG_PULL_DOWN}
+};
+#endif
+
+struct msm_sdcc_pin_cfg {
+	/*
+	 * = 1 if controller pins are using gpios
+	 * = 0 if controller has dedicated MSM pins
+	 */
+	u8 is_gpio;
+	u8 cfg_sts;
+	u8 gpio_data_size;
+	struct msm_sdcc_gpio *gpio_data;
+	struct msm_sdcc_pad_drv_cfg *pad_drv_on_data;
+	struct msm_sdcc_pad_drv_cfg *pad_drv_off_data;
+	struct msm_sdcc_pad_pull_cfg *pad_pull_on_data;
+	struct msm_sdcc_pad_pull_cfg *pad_pull_off_data;
+	u8 pad_drv_data_size;
+	u8 pad_pull_data_size;
+	u8 sdio_lpm_gpio_cfg;
+};
+
+
+static struct msm_sdcc_pin_cfg sdcc_pin_cfg_data[MAX_SDCC_CONTROLLER] = {
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+	[0] = {
+		.is_gpio = 1,
+		.gpio_data_size = ARRAY_SIZE(sdc1_gpio_cfg),
+		.gpio_data = sdc1_gpio_cfg
+	},
+#endif
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+	[1] = {
+		.is_gpio = 1,
+		.gpio_data_size = ARRAY_SIZE(sdc2_gpio_cfg),
+		.gpio_data = sdc2_gpio_cfg
+	},
+#endif
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+	[2] = {
+		.is_gpio = 0,
+		.pad_drv_on_data = sdc3_pad_on_drv_cfg,
+		.pad_drv_off_data = sdc3_pad_off_drv_cfg,
+		.pad_pull_on_data = sdc3_pad_on_pull_cfg,
+		.pad_pull_off_data = sdc3_pad_off_pull_cfg,
+		.pad_drv_data_size = ARRAY_SIZE(sdc3_pad_on_drv_cfg),
+		.pad_pull_data_size = ARRAY_SIZE(sdc3_pad_on_pull_cfg)
+	},
+#endif
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+	[3] = {
+		.is_gpio = 0,
+		.pad_drv_on_data = sdc4_pad_on_drv_cfg,
+		.pad_drv_off_data = sdc4_pad_off_drv_cfg,
+		.pad_pull_on_data = sdc4_pad_on_pull_cfg,
+		.pad_pull_off_data = sdc4_pad_off_pull_cfg,
+		.pad_drv_data_size = ARRAY_SIZE(sdc4_pad_on_drv_cfg),
+		.pad_pull_data_size = ARRAY_SIZE(sdc4_pad_on_pull_cfg)
+	},
+#endif
+#ifdef CONFIG_MMC_MSM_SDC5_SUPPORT
+	[4] = {
+		.is_gpio = 1,
+		.gpio_data_size = ARRAY_SIZE(sdc5_gpio_cfg),
+		.gpio_data = sdc5_gpio_cfg
+	}
+#endif
+};
+
+static int msm_sdcc_setup_gpio(int dev_id, unsigned int enable)
+{
+	int rc = 0;
+	struct msm_sdcc_pin_cfg *curr;
+	int n;
+
+	curr = &sdcc_pin_cfg_data[dev_id - 1];
+	if (!curr->gpio_data)
+		goto out;
+
+	for (n = 0; n < curr->gpio_data_size; n++) {
+		if (enable) {
+
+			if (curr->gpio_data[n].always_on &&
+				curr->gpio_data[n].is_enabled)
+				continue;
+			pr_debug("%s: enable: %s\n", __func__,
+					curr->gpio_data[n].name);
+			rc = gpio_request(curr->gpio_data[n].no,
+				curr->gpio_data[n].name);
+			if (rc) {
+				pr_err("%s: gpio_request(%d, %s)"
+					"failed", __func__,
+					curr->gpio_data[n].no,
+					curr->gpio_data[n].name);
+				goto free_gpios;
+			}
+			/* set direction as output for all GPIOs */
+			rc = gpio_direction_output(
+				curr->gpio_data[n].no, 1);
+			if (rc) {
+				pr_err("%s: gpio_direction_output"
+					"(%d, 1) failed\n", __func__,
+					curr->gpio_data[n].no);
+				goto free_gpios;
+			}
+			curr->gpio_data[n].is_enabled = 1;
+		} else {
+			/*
+			 * now free this GPIO which will put GPIO
+			 * in low power mode and will also put GPIO
+			 * in input mode
+			 */
+			if (curr->gpio_data[n].always_on)
+				continue;
+			pr_debug("%s: disable: %s\n", __func__,
+					curr->gpio_data[n].name);
+			gpio_free(curr->gpio_data[n].no);
+			curr->gpio_data[n].is_enabled = 0;
+		}
+	}
+	curr->cfg_sts = enable;
+	goto out;
+
+free_gpios:
+	for (; n >= 0; n--)
+		gpio_free(curr->gpio_data[n].no);
+out:
+	return rc;
+}
+
+static int msm_sdcc_setup_pad(int dev_id, unsigned int enable)
+{
+	int rc = 0;
+	struct msm_sdcc_pin_cfg *curr;
+	int n;
+
+	curr = &sdcc_pin_cfg_data[dev_id - 1];
+	if (!curr->pad_drv_on_data || !curr->pad_pull_on_data)
+		goto out;
+
+	if (enable) {
+		/*
+		 * set up the normal driver strength and
+		 * pull config for pads
+		 */
+		for (n = 0; n < curr->pad_drv_data_size; n++) {
+			if (curr->sdio_lpm_gpio_cfg) {
+				if (curr->pad_drv_on_data[n].drv ==
+						TLMM_HDRV_SDC4_DATA)
+					continue;
+			}
+			msm_tlmm_set_hdrive(curr->pad_drv_on_data[n].drv,
+				curr->pad_drv_on_data[n].drv_val);
+		}
+		for (n = 0; n < curr->pad_pull_data_size; n++) {
+			if (curr->sdio_lpm_gpio_cfg) {
+				if (curr->pad_pull_on_data[n].pull ==
+						TLMM_PULL_SDC4_DATA)
+					continue;
+			}
+			msm_tlmm_set_pull(curr->pad_pull_on_data[n].pull,
+				curr->pad_pull_on_data[n].pull_val);
+		}
+	} else {
+		/* set the low power config for pads */
+		for (n = 0; n < curr->pad_drv_data_size; n++) {
+			if (curr->sdio_lpm_gpio_cfg) {
+				if (curr->pad_drv_off_data[n].drv ==
+						TLMM_HDRV_SDC4_DATA)
+					continue;
+			}
+			msm_tlmm_set_hdrive(
+				curr->pad_drv_off_data[n].drv,
+				curr->pad_drv_off_data[n].drv_val);
+		}
+		for (n = 0; n < curr->pad_pull_data_size; n++) {
+			if (curr->sdio_lpm_gpio_cfg) {
+				if (curr->pad_pull_off_data[n].pull ==
+						TLMM_PULL_SDC4_DATA)
+					continue;
+			}
+			msm_tlmm_set_pull(
+				curr->pad_pull_off_data[n].pull,
+				curr->pad_pull_off_data[n].pull_val);
+		}
+	}
+	curr->cfg_sts = enable;
+out:
+	return rc;
+}
+
+struct sdcc_reg {
+	/* VDD/VCC/VCCQ regulator name on PMIC8058/PMIC8089*/
+	const char *reg_name;
+	/*
+	 * is set voltage supported for this regulator?
+	 * 0 = not supported, 1 = supported
+	 */
+	unsigned char set_voltage_sup;
+	/* voltage level to be set */
+	unsigned int level;
+	/* VDD/VCC/VCCQ voltage regulator handle */
+	struct regulator *reg;
+	/* is this regulator enabled? */
+	bool enabled;
+	/* is this regulator needs to be always on? */
+	bool always_on;
+	/* is operating power mode setting required for this regulator? */
+	bool op_pwr_mode_sup;
+	/* Load values for low power and high power mode */
+	unsigned int lpm_uA;
+	unsigned int hpm_uA;
+};
+/* all SDCC controllers require VDD/VCC voltage */
+static struct sdcc_reg sdcc_vdd_reg_data[MAX_SDCC_CONTROLLER];
+/* only SDCC1 requires VCCQ voltage */
+static struct sdcc_reg sdcc_vccq_reg_data[1];
+/* all SDCC controllers may require voting for VDD PAD voltage */
+static struct sdcc_reg sdcc_vddp_reg_data[MAX_SDCC_CONTROLLER];
+
+struct sdcc_reg_data {
+	struct sdcc_reg *vdd_data; /* keeps VDD/VCC regulator info */
+	struct sdcc_reg *vccq_data; /* keeps VCCQ regulator info */
+	struct sdcc_reg *vddp_data; /* keeps VDD Pad regulator info */
+	unsigned char sts; /* regulator enable/disable status */
+};
+/* msm8x60 has 5 SDCC controllers */
+static struct sdcc_reg_data sdcc_vreg_data[MAX_SDCC_CONTROLLER];
+
+static int msm_sdcc_vreg_init_reg(struct sdcc_reg *vreg)
+{
+	int rc = 0;
+
+	/* Get the regulator handle */
+	vreg->reg = regulator_get(NULL, vreg->reg_name);
+	if (IS_ERR(vreg->reg)) {
+		rc = PTR_ERR(vreg->reg);
+		pr_err("%s: regulator_get(%s) failed. rc=%d\n",
+			__func__, vreg->reg_name, rc);
+		goto out;
+	}
+
+	/* Set the voltage level if required */
+	if (vreg->set_voltage_sup) {
+		rc = regulator_set_voltage(vreg->reg, vreg->level,
+					vreg->level);
+		if (rc) {
+			pr_err("%s: regulator_set_voltage(%s) failed rc=%d\n",
+				__func__, vreg->reg_name, rc);
+			goto vreg_put;
+		}
+	}
+	goto out;
+
+vreg_put:
+	regulator_put(vreg->reg);
+out:
+	return rc;
+}
+
+static inline void msm_sdcc_vreg_deinit_reg(struct sdcc_reg *vreg)
+{
+	regulator_put(vreg->reg);
+}
+
+/* this init function should be called only once for each SDCC */
+static int msm_sdcc_vreg_init(int dev_id, unsigned char init)
+{
+	int rc = 0;
+	struct sdcc_reg *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
+	struct sdcc_reg_data *curr;
+
+	curr = &sdcc_vreg_data[dev_id - 1];
+	curr_vdd_reg = curr->vdd_data;
+	curr_vccq_reg = curr->vccq_data;
+	curr_vddp_reg = curr->vddp_data;
+
+	if (init) {
+		/*
+		 * get the regulator handle from voltage regulator framework
+		 * and then try to set the voltage level for the regulator
+		 */
+		if (curr_vdd_reg) {
+			rc = msm_sdcc_vreg_init_reg(curr_vdd_reg);
+			if (rc)
+				goto out;
+		}
+		if (curr_vccq_reg) {
+			rc = msm_sdcc_vreg_init_reg(curr_vccq_reg);
+			if (rc)
+				goto vdd_reg_deinit;
+		}
+		if (curr_vddp_reg) {
+			rc = msm_sdcc_vreg_init_reg(curr_vddp_reg);
+			if (rc)
+				goto vccq_reg_deinit;
+		}
+		goto out;
+	} else
+		/* deregister with all regulators from regulator framework */
+		goto vddp_reg_deinit;
+
+vddp_reg_deinit:
+	if (curr_vddp_reg)
+		msm_sdcc_vreg_deinit_reg(curr_vddp_reg);
+vccq_reg_deinit:
+	if (curr_vccq_reg)
+		msm_sdcc_vreg_deinit_reg(curr_vccq_reg);
+vdd_reg_deinit:
+	if (curr_vdd_reg)
+		msm_sdcc_vreg_deinit_reg(curr_vdd_reg);
+out:
+	return rc;
+}
+
+static int msm_sdcc_vreg_enable(struct sdcc_reg *vreg)
+{
+	int rc;
+
+	if (!vreg->enabled) {
+		rc = regulator_enable(vreg->reg);
+		if (rc) {
+			pr_err("%s: regulator_enable(%s) failed. rc=%d\n",
+				__func__, vreg->reg_name, rc);
+			goto out;
+		}
+		vreg->enabled = 1;
+	}
+
+	/* Put always_on regulator in HPM (high power mode) */
+	if (vreg->always_on && vreg->op_pwr_mode_sup) {
+		rc = regulator_set_optimum_mode(vreg->reg, vreg->hpm_uA);
+		if (rc < 0) {
+			pr_err("%s: reg=%s: HPM setting failed"
+				" hpm_uA=%d, rc=%d\n",
+				__func__, vreg->reg_name,
+				vreg->hpm_uA, rc);
+			goto vreg_disable;
+		}
+		rc = 0;
+	}
+	goto out;
+
+vreg_disable:
+	regulator_disable(vreg->reg);
+	vreg->enabled = 0;
+out:
+	return rc;
+}
+
+static int msm_sdcc_vreg_disable(struct sdcc_reg *vreg)
+{
+	int rc;
+
+	/* Never disable always_on regulator */
+	if (!vreg->always_on) {
+		rc = regulator_disable(vreg->reg);
+		if (rc) {
+			pr_err("%s: regulator_disable(%s) failed. rc=%d\n",
+				__func__, vreg->reg_name, rc);
+			goto out;
+		}
+		vreg->enabled = 0;
+	}
+
+	/* Put always_on regulator in LPM (low power mode) */
+	if (vreg->always_on && vreg->op_pwr_mode_sup) {
+		rc = regulator_set_optimum_mode(vreg->reg, vreg->lpm_uA);
+		if (rc < 0) {
+			pr_err("%s: reg=%s: LPM setting failed"
+				" lpm_uA=%d, rc=%d\n",
+				__func__,
+				vreg->reg_name,
+				vreg->lpm_uA, rc);
+			goto out;
+		}
+		rc = 0;
+	}
+
+out:
+	return rc;
+}
+
+static int msm_sdcc_setup_vreg(int dev_id, unsigned char enable)
+{
+	int rc = 0;
+	struct sdcc_reg *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
+	struct sdcc_reg_data *curr;
+
+	curr = &sdcc_vreg_data[dev_id - 1];
+	curr_vdd_reg = curr->vdd_data;
+	curr_vccq_reg = curr->vccq_data;
+	curr_vddp_reg = curr->vddp_data;
+
+	/* check if regulators are initialized or not? */
+	if ((curr_vdd_reg && !curr_vdd_reg->reg) ||
+		(curr_vccq_reg && !curr_vccq_reg->reg) ||
+		(curr_vddp_reg && !curr_vddp_reg->reg)) {
+		/* initialize voltage regulators required for this SDCC */
+		rc = msm_sdcc_vreg_init(dev_id, 1);
+		if (rc) {
+			pr_err("%s: regulator init failed = %d\n",
+				__func__, rc);
+			goto out;
+		}
+	}
+
+	if (curr->sts == enable)
+		goto out;
+
+	if (curr_vdd_reg) {
+		if (enable)
+			rc = msm_sdcc_vreg_enable(curr_vdd_reg);
+		else
+			rc = msm_sdcc_vreg_disable(curr_vdd_reg);
+		if (rc)
+			goto out;
+	}
+
+	if (curr_vccq_reg) {
+		if (enable)
+			rc = msm_sdcc_vreg_enable(curr_vccq_reg);
+		else
+			rc = msm_sdcc_vreg_disable(curr_vccq_reg);
+		if (rc)
+			goto out;
+	}
+
+	if (curr_vddp_reg) {
+		if (enable)
+			rc = msm_sdcc_vreg_enable(curr_vddp_reg);
+		else
+			rc = msm_sdcc_vreg_disable(curr_vddp_reg);
+		if (rc)
+			goto out;
+	}
+	curr->sts = enable;
+
+out:
+	return rc;
+}
+
+static u32 msm_sdcc_setup_power(struct device *dv, unsigned int vdd)
+{
+	u32 rc_pin_cfg = 0;
+	u32 rc_vreg_cfg = 0;
+	u32 rc = 0;
+	struct platform_device *pdev;
+	struct msm_sdcc_pin_cfg *curr_pin_cfg;
+
+	pdev = container_of(dv, struct platform_device, dev);
+
+	/* setup gpio/pad */
+	curr_pin_cfg = &sdcc_pin_cfg_data[pdev->id - 1];
+	if (curr_pin_cfg->cfg_sts == !!vdd)
+		goto setup_vreg;
+
+	if (curr_pin_cfg->is_gpio)
+		rc_pin_cfg = msm_sdcc_setup_gpio(pdev->id, !!vdd);
+	else
+		rc_pin_cfg = msm_sdcc_setup_pad(pdev->id, !!vdd);
+
+setup_vreg:
+	/* setup voltage regulators */
+	rc_vreg_cfg = msm_sdcc_setup_vreg(pdev->id, !!vdd);
+
+	if (rc_pin_cfg || rc_vreg_cfg)
+		rc = rc_pin_cfg ? rc_pin_cfg : rc_vreg_cfg;
+
+	return rc;
+}
+
+static void msm_sdcc_sdio_lpm_gpio(struct device *dv, unsigned int active)
+{
+	struct msm_sdcc_pin_cfg *curr_pin_cfg;
+	struct platform_device *pdev;
+
+	pdev = container_of(dv, struct platform_device, dev);
+	/* setup gpio/pad */
+	curr_pin_cfg = &sdcc_pin_cfg_data[pdev->id - 1];
+
+	if (curr_pin_cfg->cfg_sts == active)
+		return;
+
+	curr_pin_cfg->sdio_lpm_gpio_cfg = 1;
+	if (curr_pin_cfg->is_gpio)
+		msm_sdcc_setup_gpio(pdev->id, active);
+	else
+		msm_sdcc_setup_pad(pdev->id, active);
+	curr_pin_cfg->sdio_lpm_gpio_cfg = 0;
+}
+
+static int msm_sdc3_get_wpswitch(struct device *dev)
+{
+	struct platform_device *pdev;
+	int status;
+	pdev = container_of(dev, struct platform_device, dev);
+
+	status = gpio_request(GPIO_SDC_WP, "SD_WP_Switch");
+	if (status) {
+		pr_err("%s:Failed to request GPIO %d\n",
+					__func__, GPIO_SDC_WP);
+	} else {
+		status = gpio_direction_input(GPIO_SDC_WP);
+		if (!status) {
+			status = gpio_get_value_cansleep(GPIO_SDC_WP);
+			pr_info("%s: WP Status for Slot %d = %d\n",
+				 __func__, pdev->id, status);
+		}
+		gpio_free(GPIO_SDC_WP);
+	}
+	return status;
+}
+
+#ifdef CONFIG_MMC_MSM_SDC5_SUPPORT
+int sdc5_register_status_notify(void (*callback)(int, void *),
+	void *dev_id)
+{
+	sdc5_status_notify_cb = callback;
+	sdc5_status_notify_cb_devid = dev_id;
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+int sdc2_register_status_notify(void (*callback)(int, void *),
+	void *dev_id)
+{
+	sdc2_status_notify_cb = callback;
+	sdc2_status_notify_cb_devid = dev_id;
+	return 0;
+}
+#endif
+
+/* Interrupt handler for SDC2 and SDC5 detection
+ * This function uses dual-edge interrputs settings in order
+ * to get SDIO detection when the GPIO is rising and SDIO removal
+ * when the GPIO is falling */
+static irqreturn_t msm8x60_multi_sdio_slot_status_irq(int irq, void *dev_id)
+{
+	int status;
+
+	if (!machine_is_msm8x60_fusion() &&
+	    !machine_is_msm8x60_fusn_ffa())
+		return IRQ_NONE;
+
+	status = gpio_get_value(MDM2AP_SYNC);
+	pr_info("%s: MDM2AP_SYNC Status = %d\n",
+		 __func__, status);
+
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+	if (sdc2_status_notify_cb) {
+		pr_info("%s: calling sdc2_status_notify_cb\n", __func__);
+		sdc2_status_notify_cb(status,
+			sdc2_status_notify_cb_devid);
+	}
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC5_SUPPORT
+	if (sdc5_status_notify_cb) {
+		pr_info("%s: calling sdc5_status_notify_cb\n", __func__);
+		sdc5_status_notify_cb(status,
+			sdc5_status_notify_cb_devid);
+	}
+#endif
+	return IRQ_HANDLED;
+}
+
+static int msm8x60_multi_sdio_init(void)
+{
+	int ret, irq_num;
+
+	if (!machine_is_msm8x60_fusion() &&
+	    !machine_is_msm8x60_fusn_ffa())
+		return 0;
+
+	ret = msm_gpiomux_get(MDM2AP_SYNC);
+	if (ret) {
+		pr_err("%s:Failed to request GPIO %d, ret=%d\n",
+					__func__, MDM2AP_SYNC, ret);
+		return ret;
+	}
+
+	irq_num = gpio_to_irq(MDM2AP_SYNC);
+
+	ret = request_irq(irq_num,
+		msm8x60_multi_sdio_slot_status_irq,
+		IRQ_TYPE_EDGE_BOTH,
+		"sdio_multidetection", NULL);
+
+	if (ret) {
+		pr_err("%s:Failed to request irq, ret=%d\n",
+					__func__, ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
+static unsigned int msm8x60_sdcc_slot_status(struct device *dev)
+{
+	int status;
+
+	status = gpio_request(PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_SDC3_DET - 1)
+				, "SD_HW_Detect");
+	if (status) {
+		pr_err("%s:Failed to request GPIO %d\n", __func__,
+				PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_SDC3_DET - 1));
+	} else {
+		status = gpio_direction_input(
+				PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_SDC3_DET - 1));
+		if (!status)
+			status = !(gpio_get_value_cansleep(
+				PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_SDC3_DET - 1)));
+		gpio_free(PM8058_GPIO_PM_TO_SYS(PMIC_GPIO_SDC3_DET - 1));
+	}
+	return (unsigned int) status;
+}
+#endif
+#endif
+#endif
+
+#define MSM_MPM_PIN_SDC3_DAT1	21
+#define MSM_MPM_PIN_SDC4_DAT1	23
+
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+static struct mmc_platform_data msm8x60_sdc1_data = {
+	.ocr_mask       = MMC_VDD_27_28 | MMC_VDD_28_29,
+	.translate_vdd  = msm_sdcc_setup_power,
+#ifdef CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT
+	.mmc_bus_width  = MMC_CAP_8_BIT_DATA,
+#else
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+#endif
+	.msmsdcc_fmin	= 400000,
+	.msmsdcc_fmid	= 24000000,
+	.msmsdcc_fmax	= 48000000,
+	.nonremovable	= 1,
+	.pclk_src_dfab	= 1,
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+static struct mmc_platform_data msm8x60_sdc2_data = {
+	.ocr_mask       = MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_165_195,
+	.translate_vdd  = msm_sdcc_setup_power,
+	.sdio_lpm_gpio_setup = msm_sdcc_sdio_lpm_gpio,
+	.mmc_bus_width  = MMC_CAP_8_BIT_DATA,
+	.msmsdcc_fmin	= 400000,
+	.msmsdcc_fmid	= 24000000,
+	.msmsdcc_fmax	= 48000000,
+	.nonremovable	= 0,
+	.pclk_src_dfab  = 1,
+	.register_status_notify = sdc2_register_status_notify,
+#ifdef CONFIG_MSM_SDIO_AL
+	.is_sdio_al_client = 1,
+#endif
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+static struct mmc_platform_data msm8x60_sdc3_data = {
+	.ocr_mask       = MMC_VDD_27_28 | MMC_VDD_28_29,
+	.translate_vdd  = msm_sdcc_setup_power,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.wpswitch  	= msm_sdc3_get_wpswitch,
+#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
+	.status      = msm8x60_sdcc_slot_status,
+	.status_irq  = PM8058_GPIO_IRQ(PM8058_IRQ_BASE,
+				       PMIC_GPIO_SDC3_DET - 1),
+	.irq_flags   = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+#endif
+	.msmsdcc_fmin	= 400000,
+	.msmsdcc_fmid	= 24000000,
+	.msmsdcc_fmax	= 48000000,
+	.nonremovable	= 0,
+	.pclk_src_dfab  = 1,
+	.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC3_DAT1,
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+static struct mmc_platform_data msm8x60_sdc4_data = {
+	.ocr_mask       = MMC_VDD_27_28 | MMC_VDD_28_29,
+	.translate_vdd  = msm_sdcc_setup_power,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.msmsdcc_fmin	= 400000,
+	.msmsdcc_fmid	= 24000000,
+	.msmsdcc_fmax	= 48000000,
+	.nonremovable	= 0,
+	.pclk_src_dfab  = 1,
+	.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC4_DAT1,
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC5_SUPPORT
+static struct mmc_platform_data msm8x60_sdc5_data = {
+	.ocr_mask       = MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_165_195,
+	.translate_vdd  = msm_sdcc_setup_power,
+	.sdio_lpm_gpio_setup = msm_sdcc_sdio_lpm_gpio,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.msmsdcc_fmin	= 400000,
+	.msmsdcc_fmid	= 24000000,
+	.msmsdcc_fmax	= 48000000,
+	.nonremovable	= 0,
+	.pclk_src_dfab  = 1,
+	.register_status_notify = sdc5_register_status_notify,
+#ifdef CONFIG_MSM_SDIO_AL
+	.is_sdio_al_client = 1,
+#endif
+	.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
+};
+#endif
+
+static void __init msm8x60_init_mmc(void)
+{
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+	/* SDCC1 : eMMC card connected */
+	sdcc_vreg_data[0].vdd_data = &sdcc_vdd_reg_data[0];
+	sdcc_vreg_data[0].vdd_data->reg_name = "8901_l5";
+	sdcc_vreg_data[0].vdd_data->set_voltage_sup = 1;
+	sdcc_vreg_data[0].vdd_data->level = 2850000;
+	sdcc_vreg_data[0].vdd_data->always_on = 1;
+	sdcc_vreg_data[0].vdd_data->op_pwr_mode_sup = 1;
+	sdcc_vreg_data[0].vdd_data->lpm_uA = 9000;
+	sdcc_vreg_data[0].vdd_data->hpm_uA = 200000;
+
+	sdcc_vreg_data[0].vccq_data = &sdcc_vccq_reg_data[0];
+	sdcc_vreg_data[0].vccq_data->reg_name = "8901_lvs0";
+	sdcc_vreg_data[0].vccq_data->set_voltage_sup = 0;
+	sdcc_vreg_data[0].vccq_data->always_on = 1;
+
+	msm_add_sdcc(1, &msm8x60_sdc1_data);
+#endif
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+	/*
+	 * MDM SDIO client is connected to SDC2 on charm SURF/FFA
+	 * and no card is connected on 8660 SURF/FFA/FLUID.
+	 */
+	sdcc_vreg_data[1].vdd_data = &sdcc_vdd_reg_data[1];
+	sdcc_vreg_data[1].vdd_data->reg_name = "8058_s3";
+	sdcc_vreg_data[1].vdd_data->set_voltage_sup = 1;
+	sdcc_vreg_data[1].vdd_data->level = 1800000;
+
+	sdcc_vreg_data[1].vccq_data = NULL;
+
+	if (machine_is_msm8x60_fusion())
+		msm8x60_sdc2_data.msmsdcc_fmax = 24000000;
+	if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa()) {
+		msm8x60_sdc2_data.sdiowakeup_irq = gpio_to_irq(144);
+		msm_sdcc_setup_gpio(2, 1);
+		msm_add_sdcc(2, &msm8x60_sdc2_data);
+	}
+#endif
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+	/* SDCC3 : External card slot connected */
+	sdcc_vreg_data[2].vdd_data = &sdcc_vdd_reg_data[2];
+	sdcc_vreg_data[2].vdd_data->reg_name = "8058_l14";
+	sdcc_vreg_data[2].vdd_data->set_voltage_sup = 1;
+	sdcc_vreg_data[2].vdd_data->level = 2850000;
+	sdcc_vreg_data[2].vdd_data->always_on = 1;
+	sdcc_vreg_data[2].vdd_data->op_pwr_mode_sup = 1;
+	sdcc_vreg_data[2].vdd_data->lpm_uA = 9000;
+	sdcc_vreg_data[2].vdd_data->hpm_uA = 200000;
+
+	sdcc_vreg_data[2].vccq_data = NULL;
+
+	sdcc_vreg_data[2].vddp_data = &sdcc_vddp_reg_data[2];
+	sdcc_vreg_data[2].vddp_data->reg_name = "8058_l5";
+	sdcc_vreg_data[2].vddp_data->set_voltage_sup = 1;
+	sdcc_vreg_data[2].vddp_data->level = 2850000;
+	sdcc_vreg_data[2].vddp_data->always_on = 1;
+	sdcc_vreg_data[2].vddp_data->op_pwr_mode_sup = 1;
+	/* Sleep current required is ~300 uA. But min. RPM
+	 * vote can be in terms of mA (min. 1 mA).
+	 * So let's vote for 2 mA during sleep.
+	 */
+	sdcc_vreg_data[2].vddp_data->lpm_uA = 2000;
+	/* Max. Active current required is 16 mA */
+	sdcc_vreg_data[2].vddp_data->hpm_uA = 16000;
+
+	if (machine_is_msm8x60_fluid())
+		msm8x60_sdc3_data.wpswitch = NULL;
+	msm_add_sdcc(3, &msm8x60_sdc3_data);
+#endif
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+	/* SDCC4 : WLAN WCN1314 chip is connected */
+	sdcc_vreg_data[3].vdd_data = &sdcc_vdd_reg_data[3];
+	sdcc_vreg_data[3].vdd_data->reg_name = "8058_s3";
+	sdcc_vreg_data[3].vdd_data->set_voltage_sup = 1;
+	sdcc_vreg_data[3].vdd_data->level = 1800000;
+
+	sdcc_vreg_data[3].vccq_data = NULL;
+
+	msm_add_sdcc(4, &msm8x60_sdc4_data);
+#endif
+#ifdef CONFIG_MMC_MSM_SDC5_SUPPORT
+	/*
+	 * MDM SDIO client is connected to SDC5 on charm SURF/FFA
+	 * and no card is connected on 8660 SURF/FFA/FLUID.
+	 */
+	sdcc_vreg_data[4].vdd_data = &sdcc_vdd_reg_data[4];
+	sdcc_vreg_data[4].vdd_data->reg_name = "8058_s3";
+	sdcc_vreg_data[4].vdd_data->set_voltage_sup = 1;
+	sdcc_vreg_data[4].vdd_data->level = 1800000;
+
+	sdcc_vreg_data[4].vccq_data = NULL;
+
+	if (machine_is_msm8x60_fusion())
+		msm8x60_sdc5_data.msmsdcc_fmax = 24000000;
+	if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa()) {
+		msm8x60_sdc5_data.sdiowakeup_irq = gpio_to_irq(99);
+		msm_sdcc_setup_gpio(5, 1);
+		msm_add_sdcc(5, &msm8x60_sdc5_data);
+	}
+#endif
+}
+
+#if !defined(CONFIG_GPIO_SX150X) && !defined(CONFIG_GPIO_SX150X_MODULE)
+static inline void display_common_power(int on) {}
+#else
+
+#define _GET_REGULATOR(var, name) do {					\
+	if (var == NULL) {						\
+		var = regulator_get(NULL, name);			\
+		if (IS_ERR(var)) {					\
+			pr_err("'%s' regulator not found, rc=%ld\n",	\
+				name, PTR_ERR(var));			\
+			var = NULL;					\
+		}							\
+	}								\
+} while (0)
+
+static int dsub_regulator(int on)
+{
+	static struct regulator *dsub_reg;
+	static struct regulator *mpp0_reg;
+	static int dsub_reg_enabled;
+	int rc = 0;
+
+	_GET_REGULATOR(dsub_reg, "8901_l3");
+	if (IS_ERR(dsub_reg)) {
+		printk(KERN_ERR "%s: failed to get reg 8901_l3 err=%ld",
+		       __func__, PTR_ERR(dsub_reg));
+		return PTR_ERR(dsub_reg);
+	}
+
+	_GET_REGULATOR(mpp0_reg, "8901_mpp0");
+	if (IS_ERR(mpp0_reg)) {
+		printk(KERN_ERR "%s: failed to get reg 8901_mpp0 err=%ld",
+		       __func__, PTR_ERR(mpp0_reg));
+		return PTR_ERR(mpp0_reg);
+	}
+
+	if (on && !dsub_reg_enabled) {
+		rc = regulator_set_voltage(dsub_reg, 3300000, 3300000);
+		if (rc) {
+			printk(KERN_ERR "%s: failed to set reg 8901_l3 voltage"
+			       " err=%d", __func__, rc);
+			goto dsub_regulator_err;
+		}
+		rc = regulator_enable(dsub_reg);
+		if (rc) {
+			printk(KERN_ERR "%s: failed to enable reg 8901_l3"
+			       " err=%d", __func__, rc);
+			goto dsub_regulator_err;
+		}
+		rc = regulator_enable(mpp0_reg);
+		if (rc) {
+			printk(KERN_ERR "%s: failed to enable reg 8901_mpp0"
+			       " err=%d", __func__, rc);
+			goto dsub_regulator_err;
+		}
+		dsub_reg_enabled = 1;
+	} else if (!on && dsub_reg_enabled) {
+		rc = regulator_disable(dsub_reg);
+		if (rc)
+			printk(KERN_WARNING "%s: failed to disable reg 8901_l3"
+			       " err=%d", __func__, rc);
+		rc = regulator_disable(mpp0_reg);
+		if (rc)
+			printk(KERN_WARNING "%s: failed to disable reg "
+			       "8901_mpp0 err=%d", __func__, rc);
+		dsub_reg_enabled = 0;
+	}
+
+	return rc;
+
+dsub_regulator_err:
+	regulator_put(mpp0_reg);
+	regulator_put(dsub_reg);
+	return rc;
+}
+
+static int display_power_on;
+static void setup_display_power(void)
+{
+	if (display_power_on)
+		if (lcdc_vga_enabled) {
+			dsub_regulator(1);
+			gpio_set_value_cansleep(GPIO_LVDS_SHUTDOWN_N, 0);
+			gpio_set_value_cansleep(GPIO_BACKLIGHT_EN, 0);
+			if (machine_is_msm8x60_ffa() ||
+			    machine_is_msm8x60_fusn_ffa())
+				gpio_set_value_cansleep(GPIO_DONGLE_PWR_EN, 1);
+		} else {
+			dsub_regulator(0);
+			gpio_set_value_cansleep(GPIO_LVDS_SHUTDOWN_N, 1);
+			gpio_set_value_cansleep(GPIO_BACKLIGHT_EN, 1);
+			if (machine_is_msm8x60_ffa() ||
+			    machine_is_msm8x60_fusn_ffa())
+				gpio_set_value_cansleep(GPIO_DONGLE_PWR_EN, 0);
+		}
+	else {
+		dsub_regulator(0);
+		if (machine_is_msm8x60_ffa() || machine_is_msm8x60_fusn_ffa())
+			gpio_set_value_cansleep(GPIO_DONGLE_PWR_EN, 0);
+		/* BACKLIGHT */
+		gpio_set_value_cansleep(GPIO_BACKLIGHT_EN, 0);
+		/* LVDS */
+		gpio_set_value_cansleep(GPIO_LVDS_SHUTDOWN_N, 0);
+	}
+}
+
+#define _GET_REGULATOR(var, name) do {					\
+	if (var == NULL) {						\
+		var = regulator_get(NULL, name);			\
+		if (IS_ERR(var)) {					\
+			pr_err("'%s' regulator not found, rc=%ld\n",	\
+				name, PTR_ERR(var));			\
+			var = NULL;					\
+		}							\
+	}								\
+} while (0)
+
+#define GPIO_RESX_N (GPIO_EXPANDER_GPIO_BASE + 2)
+
+static void display_common_power(int on)
+{
+	int rc;
+	static struct regulator *display_reg;
+
+	if (machine_is_msm8x60_surf() || machine_is_msm8x60_ffa() ||
+	    machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa()) {
+		if (on) {
+			/* LVDS */
+			_GET_REGULATOR(display_reg, "8901_l2");
+			if (!display_reg)
+				return;
+			rc = regulator_set_voltage(display_reg,
+				3300000, 3300000);
+			if (rc)
+				goto out;
+			rc = regulator_enable(display_reg);
+			if (rc)
+				goto out;
+			rc = gpio_request(GPIO_LVDS_SHUTDOWN_N,
+				"LVDS_STDN_OUT_N");
+			if (rc) {
+				printk(KERN_ERR "%s: LVDS gpio %d request"
+					"failed\n", __func__,
+					 GPIO_LVDS_SHUTDOWN_N);
+				goto out2;
+			}
+
+			/* BACKLIGHT */
+			rc = gpio_request(GPIO_BACKLIGHT_EN, "BACKLIGHT_EN");
+			if (rc) {
+				printk(KERN_ERR "%s: BACKLIGHT gpio %d request"
+					"failed\n", __func__,
+					 GPIO_BACKLIGHT_EN);
+				goto out3;
+			}
+
+			if (machine_is_msm8x60_ffa() ||
+			    machine_is_msm8x60_fusn_ffa()) {
+				rc = gpio_request(GPIO_DONGLE_PWR_EN,
+						  "DONGLE_PWR_EN");
+				if (rc) {
+					printk(KERN_ERR "%s: DONGLE_PWR_EN gpio"
+					       " %d request failed\n", __func__,
+					       GPIO_DONGLE_PWR_EN);
+					goto out4;
+				}
+			}
+
+			gpio_direction_output(GPIO_LVDS_SHUTDOWN_N, 0);
+			gpio_direction_output(GPIO_BACKLIGHT_EN, 0);
+			if (machine_is_msm8x60_ffa() ||
+			    machine_is_msm8x60_fusn_ffa())
+				gpio_direction_output(GPIO_DONGLE_PWR_EN, 0);
+			mdelay(20);
+			display_power_on = 1;
+			setup_display_power();
+		} else {
+			if (display_power_on) {
+				display_power_on = 0;
+				setup_display_power();
+				mdelay(20);
+				if (machine_is_msm8x60_ffa() ||
+				    machine_is_msm8x60_fusn_ffa())
+					gpio_free(GPIO_DONGLE_PWR_EN);
+				goto out4;
+			}
+		}
+	}
+#if defined(CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT) || \
+	defined(CONFIG_FB_MSM_LCDC_AUO_WVGA)
+	else if (machine_is_msm8x60_fluid()) {
+		static struct regulator *fluid_reg;
+		static struct regulator *fluid_reg2;
+
+		if (on) {
+			_GET_REGULATOR(fluid_reg, "8901_l2");
+			if (!fluid_reg)
+				return;
+			_GET_REGULATOR(fluid_reg2, "8058_s3");
+			if (!fluid_reg2) {
+				regulator_put(fluid_reg);
+				return;
+			}
+			rc = gpio_request(GPIO_RESX_N, "RESX_N");
+			if (rc) {
+				regulator_put(fluid_reg2);
+				regulator_put(fluid_reg);
+				return;
+			}
+			regulator_set_voltage(fluid_reg, 2850000, 2850000);
+			regulator_set_voltage(fluid_reg2, 1800000, 1800000);
+			regulator_enable(fluid_reg);
+			regulator_enable(fluid_reg2);
+			msleep(20);
+			gpio_direction_output(GPIO_RESX_N, 0);
+			udelay(10);
+			gpio_set_value_cansleep(GPIO_RESX_N, 1);
+			display_power_on = 1;
+			setup_display_power();
+		} else {
+			gpio_set_value_cansleep(GPIO_RESX_N, 0);
+			gpio_free(GPIO_RESX_N);
+			msleep(20);
+			regulator_disable(fluid_reg2);
+			regulator_disable(fluid_reg);
+			regulator_put(fluid_reg2);
+			regulator_put(fluid_reg);
+			display_power_on = 0;
+			setup_display_power();
+			fluid_reg = NULL;
+			fluid_reg2 = NULL;
+		}
+	}
+#endif
+#if defined(CONFIG_FB_MSM_LCDC_NT35582_WVGA)
+	else if (machine_is_msm8x60_dragon()) {
+		static struct regulator *dragon_reg;
+		static struct regulator *dragon_reg2;
+
+		if (on) {
+			_GET_REGULATOR(dragon_reg, "8901_l2");
+			if (!dragon_reg)
+				return;
+			_GET_REGULATOR(dragon_reg2, "8058_l16");
+			if (!dragon_reg2) {
+				regulator_put(dragon_reg);
+				dragon_reg = NULL;
+				return;
+			}
+
+			rc = gpio_request(GPIO_NT35582_BL_EN, "lcdc_bl_en");
+			if (rc) {
+				pr_err("%s: gpio %d request failed with rc=%d\n",
+					__func__, GPIO_NT35582_BL_EN, rc);
+				regulator_put(dragon_reg);
+				regulator_put(dragon_reg2);
+				dragon_reg = NULL;
+				dragon_reg2 = NULL;
+				return;
+			}
+
+			if (gpio_tlmm_config(GPIO_CFG(GPIO_NT35582_RESET, 0,
+				GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN,
+				GPIO_CFG_16MA), GPIO_CFG_ENABLE)) {
+				pr_err("%s: config gpio '%d' failed!\n",
+					__func__, GPIO_NT35582_RESET);
+				gpio_free(GPIO_NT35582_BL_EN);
+				regulator_put(dragon_reg);
+				regulator_put(dragon_reg2);
+				dragon_reg = NULL;
+				dragon_reg2 = NULL;
+				return;
+			}
+
+			rc = gpio_request(GPIO_NT35582_RESET, "lcdc_reset");
+			if (rc) {
+				pr_err("%s: unable to request gpio %d (rc=%d)\n",
+					__func__, GPIO_NT35582_RESET, rc);
+				gpio_free(GPIO_NT35582_BL_EN);
+				regulator_put(dragon_reg);
+				regulator_put(dragon_reg2);
+				dragon_reg = NULL;
+				dragon_reg2 = NULL;
+				return;
+			}
+
+			regulator_set_voltage(dragon_reg, 3300000, 3300000);
+			regulator_set_voltage(dragon_reg2, 1800000, 1800000);
+			regulator_enable(dragon_reg);
+			regulator_enable(dragon_reg2);
+			msleep(20);
+
+			gpio_set_value_cansleep(GPIO_NT35582_RESET, 1);
+			msleep(20);
+			gpio_set_value_cansleep(GPIO_NT35582_RESET, 0);
+			msleep(20);
+			gpio_set_value_cansleep(GPIO_NT35582_RESET, 1);
+			msleep(50);
+
+			gpio_set_value_cansleep(GPIO_NT35582_BL_EN, 1);
+
+			display_power_on = 1;
+		} else if ((dragon_reg != NULL) && (dragon_reg2 != NULL)) {
+			gpio_free(GPIO_NT35582_RESET);
+			gpio_free(GPIO_NT35582_BL_EN);
+			regulator_disable(dragon_reg2);
+			regulator_disable(dragon_reg);
+			regulator_put(dragon_reg2);
+			regulator_put(dragon_reg);
+			display_power_on = 0;
+			dragon_reg = NULL;
+			dragon_reg2 = NULL;
+		}
+	}
+#endif
+	return;
+
+out4:
+	gpio_free(GPIO_BACKLIGHT_EN);
+out3:
+	gpio_free(GPIO_LVDS_SHUTDOWN_N);
+out2:
+	regulator_disable(display_reg);
+out:
+	regulator_put(display_reg);
+	display_reg = NULL;
+}
+#undef _GET_REGULATOR
+#endif
+
+static int mipi_dsi_panel_power(int on);
+
+#define LCDC_NUM_GPIO 28
+#define LCDC_GPIO_START 0
+
+static void lcdc_samsung_panel_power(int on)
+{
+	int n, ret = 0;
+
+	display_common_power(on);
+
+	for (n = 0; n < LCDC_NUM_GPIO; n++) {
+		if (on) {
+			ret = gpio_request(LCDC_GPIO_START + n, "LCDC_GPIO");
+			if (unlikely(ret)) {
+				pr_err("%s not able to get gpio\n", __func__);
+				break;
+			}
+		} else
+			gpio_free(LCDC_GPIO_START + n);
+	}
+
+	if (ret) {
+		for (n--; n >= 0; n--)
+			gpio_free(LCDC_GPIO_START + n);
+	}
+
+	mipi_dsi_panel_power(0); /* set 8058_ldo0 to LPM */
+}
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+#define _GET_REGULATOR(var, name) do {				\
+	var = regulator_get(NULL, name);			\
+	if (IS_ERR(var)) {					\
+		pr_err("'%s' regulator not found, rc=%ld\n",	\
+			name, IS_ERR(var));			\
+		var = NULL;					\
+		return -ENODEV;					\
+	}							\
+} while (0)
+
+static int hdmi_enable_5v(int on)
+{
+	static struct regulator *reg_8901_hdmi_mvs;	/* HDMI_5V */
+	static struct regulator *reg_8901_mpp0;		/* External 5V */
+	static int prev_on;
+	int rc;
+
+	if (on == prev_on)
+		return 0;
+
+	if (!reg_8901_hdmi_mvs)
+		_GET_REGULATOR(reg_8901_hdmi_mvs, "8901_hdmi_mvs");
+	if (!reg_8901_mpp0)
+		_GET_REGULATOR(reg_8901_mpp0, "8901_mpp0");
+
+	if (on) {
+		rc = regulator_enable(reg_8901_mpp0);
+		if (rc) {
+			pr_err("'%s' regulator enable failed, rc=%d\n",
+				"reg_8901_mpp0", rc);
+			return rc;
+		}
+		rc = regulator_enable(reg_8901_hdmi_mvs);
+		if (rc) {
+			pr_err("'%s' regulator enable failed, rc=%d\n",
+				"8901_hdmi_mvs", rc);
+			return rc;
+		}
+		pr_info("%s(on): success\n", __func__);
+	} else {
+		rc = regulator_disable(reg_8901_hdmi_mvs);
+		if (rc)
+			pr_warning("'%s' regulator disable failed, rc=%d\n",
+				"8901_hdmi_mvs", rc);
+		rc = regulator_disable(reg_8901_mpp0);
+		if (rc)
+			pr_warning("'%s' regulator disable failed, rc=%d\n",
+				"reg_8901_mpp0", rc);
+		pr_info("%s(off): success\n", __func__);
+	}
+
+	prev_on = on;
+
+	return 0;
+}
+
+static int hdmi_core_power(int on, int show)
+{
+	static struct regulator *reg_8058_l16;		/* VDD_HDMI */
+	static int prev_on;
+	int rc;
+
+	if (on == prev_on)
+		return 0;
+
+	if (!reg_8058_l16)
+		_GET_REGULATOR(reg_8058_l16, "8058_l16");
+
+	if (on) {
+		rc = regulator_set_voltage(reg_8058_l16, 1800000, 1800000);
+		if (!rc)
+			rc = regulator_enable(reg_8058_l16);
+		if (rc) {
+			pr_err("'%s' regulator enable failed, rc=%d\n",
+				"8058_l16", rc);
+			return rc;
+		}
+		rc = gpio_request(170, "HDMI_DDC_CLK");
+		if (rc) {
+			pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+				"HDMI_DDC_CLK", 170, rc);
+			goto error1;
+		}
+		rc = gpio_request(171, "HDMI_DDC_DATA");
+		if (rc) {
+			pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+				"HDMI_DDC_DATA", 171, rc);
+			goto error2;
+		}
+		rc = gpio_request(172, "HDMI_HPD");
+		if (rc) {
+			pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+				"HDMI_HPD", 172, rc);
+			goto error3;
+		}
+		pr_info("%s(on): success\n", __func__);
+	} else {
+		gpio_free(170);
+		gpio_free(171);
+		gpio_free(172);
+		rc = regulator_disable(reg_8058_l16);
+		if (rc)
+			pr_warning("'%s' regulator disable failed, rc=%d\n",
+				"8058_l16", rc);
+		pr_info("%s(off): success\n", __func__);
+	}
+
+	prev_on = on;
+
+	return 0;
+
+error3:
+	gpio_free(171);
+error2:
+	gpio_free(170);
+error1:
+	regulator_disable(reg_8058_l16);
+	return rc;
+}
+
+static int hdmi_cec_power(int on)
+{
+	static struct regulator *reg_8901_l3;		/* HDMI_CEC */
+	static int prev_on;
+	int rc;
+
+	if (on == prev_on)
+		return 0;
+
+	if (!reg_8901_l3)
+		_GET_REGULATOR(reg_8901_l3, "8901_l3");
+
+	if (on) {
+		rc = regulator_set_voltage(reg_8901_l3, 3300000, 3300000);
+		if (!rc)
+			rc = regulator_enable(reg_8901_l3);
+		if (rc) {
+			pr_err("'%s' regulator enable failed, rc=%d\n",
+				"8901_l3", rc);
+			return rc;
+		}
+		rc = gpio_request(169, "HDMI_CEC_VAR");
+		if (rc) {
+			pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+				"HDMI_CEC_VAR", 169, rc);
+			goto error;
+		}
+		pr_info("%s(on): success\n", __func__);
+	} else {
+		gpio_free(169);
+		rc = regulator_disable(reg_8901_l3);
+		if (rc)
+			pr_warning("'%s' regulator disable failed, rc=%d\n",
+				"8901_l3", rc);
+		pr_info("%s(off): success\n", __func__);
+	}
+
+	prev_on = on;
+
+	return 0;
+error:
+	regulator_disable(reg_8901_l3);
+	return rc;
+}
+
+#undef _GET_REGULATOR
+
+#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL */
+
+static int lcdc_panel_power(int on)
+{
+	int flag_on = !!on;
+	static int lcdc_power_save_on;
+
+	if (lcdc_power_save_on == flag_on)
+		return 0;
+
+	lcdc_power_save_on = flag_on;
+
+	lcdc_samsung_panel_power(on);
+
+	return 0;
+}
+
+#ifdef CONFIG_MSM_BUS_SCALING
+
+static struct msm_bus_vectors rotator_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_ROTATOR,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab = 0,
+		.ib = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_ROTATOR,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+static struct msm_bus_vectors rotator_ui_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_ROTATOR,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_ROTATOR,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = (1024 * 600 * 4 * 2 * 60),
+		.ib  = (1024 * 600 * 4 * 2 * 60 * 1.5),
+	},
+};
+
+static struct msm_bus_vectors rotator_vga_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_ROTATOR,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = (640 * 480 * 2 * 2 * 30),
+		.ib  = (640 * 480 * 2 * 2 * 30 * 1.5),
+	},
+	{
+		.src = MSM_BUS_MASTER_ROTATOR,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = (640 * 480 * 2 * 2 * 30),
+		.ib  = (640 * 480 * 2 * 2 * 30 * 1.5),
+	},
+};
+
+static struct msm_bus_vectors rotator_720p_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_ROTATOR,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = (1280 * 736 * 2 * 2 * 30),
+		.ib  = (1280 * 736 * 2 * 2 * 30 * 1.5),
+	},
+	{
+		.src = MSM_BUS_MASTER_ROTATOR,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = (1280 * 736 * 2 * 2 * 30),
+		.ib  = (1280 * 736 * 2 * 2 * 30 * 1.5),
+	},
+};
+
+static struct msm_bus_vectors rotator_1080p_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_ROTATOR,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = (1920 * 1088 * 2 * 2 * 30),
+		.ib  = (1920 * 1088 * 2 * 2 * 30 * 1.5),
+	},
+	{
+		.src = MSM_BUS_MASTER_ROTATOR,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = (1920 * 1088 * 2 * 2 * 30),
+		.ib  = (1920 * 1088 * 2 * 2 * 30 * 1.5),
+	},
+};
+
+static struct msm_bus_paths rotator_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(rotator_init_vectors),
+		rotator_init_vectors,
+	},
+	{
+		ARRAY_SIZE(rotator_ui_vectors),
+		rotator_ui_vectors,
+	},
+	{
+		ARRAY_SIZE(rotator_vga_vectors),
+		rotator_vga_vectors,
+	},
+	{
+		ARRAY_SIZE(rotator_720p_vectors),
+		rotator_720p_vectors,
+	},
+	{
+		ARRAY_SIZE(rotator_1080p_vectors),
+		rotator_1080p_vectors,
+	},
+};
+
+struct msm_bus_scale_pdata rotator_bus_scale_pdata = {
+	rotator_bus_scale_usecases,
+	ARRAY_SIZE(rotator_bus_scale_usecases),
+	.name = "rotator",
+};
+
+static struct msm_bus_vectors mdp_init_vectors[] = {
+	/* For now, 0th array entry is reserved.
+	 * Please leave 0 as is and don't use it
+	 */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab = 0,
+		.ib = 0,
+	},
+	/* Master and slaves can be from different fabrics */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+#ifdef CONFIG_FB_MSM_LCDC_DSUB
+static struct msm_bus_vectors mdp_sd_smi_vectors[] = {
+	/* Default case static display/UI/2d/3d if FB SMI */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab = 388800000,
+		.ib = 486000000,
+	},
+	/* Master and slaves can be from different fabrics */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+static struct msm_bus_vectors mdp_sd_ebi_vectors[] = {
+	/* Default case static display/UI/2d/3d if FB SMI */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab = 0,
+		.ib = 0,
+	},
+	/* Master and slaves can be from different fabrics */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 388800000,
+		.ib = 486000000 * 2,
+	},
+};
+static struct msm_bus_vectors mdp_vga_vectors[] = {
+	/* VGA and less video */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab = 458092800,
+		.ib = 572616000,
+	},
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 458092800,
+		.ib = 572616000 * 2,
+	},
+};
+static struct msm_bus_vectors mdp_720p_vectors[] = {
+	/* 720p and less video */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab = 471744000,
+		.ib = 589680000,
+	},
+	/* Master and slaves can be from different fabrics */
+       {
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+	       .ab = 471744000,
+	       .ib = 589680000 * 2,
+	},
+};
+
+static struct msm_bus_vectors mdp_1080p_vectors[] = {
+	/* 1080p and less video */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab = 575424000,
+		.ib = 719280000,
+	},
+	/* Master and slaves can be from different fabrics */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 575424000,
+		.ib = 719280000 * 2,
+	},
+};
+
+#else
+static struct msm_bus_vectors mdp_sd_smi_vectors[] = {
+	/* Default case static display/UI/2d/3d if FB SMI */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab = 175110000,
+		.ib = 218887500,
+	},
+	/* Master and slaves can be from different fabrics */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+static struct msm_bus_vectors mdp_sd_ebi_vectors[] = {
+	/* Default case static display/UI/2d/3d if FB SMI */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab = 0,
+		.ib = 0,
+	},
+	/* Master and slaves can be from different fabrics */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 216000000,
+		.ib = 270000000 * 2,
+	},
+};
+static struct msm_bus_vectors mdp_vga_vectors[] = {
+	/* VGA and less video */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab = 216000000,
+		.ib = 270000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 216000000,
+		.ib = 270000000 * 2,
+	},
+};
+
+static struct msm_bus_vectors mdp_720p_vectors[] = {
+	/* 720p and less video */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab = 230400000,
+		.ib = 288000000,
+	},
+	/* Master and slaves can be from different fabrics */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 230400000,
+		.ib = 288000000 * 2,
+	},
+};
+
+static struct msm_bus_vectors mdp_1080p_vectors[] = {
+	/* 1080p and less video */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab = 334080000,
+		.ib = 417600000,
+	},
+	/* Master and slaves can be from different fabrics */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 334080000,
+		.ib = 550000000 * 2,
+	},
+};
+
+#endif
+static struct msm_bus_paths mdp_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(mdp_init_vectors),
+		mdp_init_vectors,
+	},
+	{
+		ARRAY_SIZE(mdp_sd_smi_vectors),
+		mdp_sd_smi_vectors,
+	},
+	{
+		ARRAY_SIZE(mdp_sd_ebi_vectors),
+		mdp_sd_ebi_vectors,
+	},
+	{
+		ARRAY_SIZE(mdp_vga_vectors),
+		mdp_vga_vectors,
+	},
+	{
+		ARRAY_SIZE(mdp_720p_vectors),
+		mdp_720p_vectors,
+	},
+	{
+		ARRAY_SIZE(mdp_1080p_vectors),
+		mdp_1080p_vectors,
+	},
+};
+static struct msm_bus_scale_pdata mdp_bus_scale_pdata = {
+	mdp_bus_scale_usecases,
+	ARRAY_SIZE(mdp_bus_scale_usecases),
+	.name = "mdp",
+};
+
+#endif
+#ifdef CONFIG_MSM_BUS_SCALING
+static struct msm_bus_vectors dtv_bus_init_vectors[] = {
+	/* For now, 0th array entry is reserved.
+	 * Please leave 0 as is and don't use it
+	 */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab = 0,
+		.ib = 0,
+	},
+	/* Master and slaves can be from different fabrics */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+static struct msm_bus_vectors dtv_bus_def_vectors[] = {
+	/* For now, 0th array entry is reserved.
+	 * Please leave 0 as is and don't use it
+	 */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab = 566092800,
+		.ib = 707616000,
+	},
+	/* Master and slaves can be from different fabrics */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 566092800,
+		.ib = 707616000,
+	},
+};
+
+static struct msm_bus_vectors dtv_bus_hdmi_prim_vectors[] = {
+	/* For now, 0th array entry is reserved.
+	 * Please leave 0 as is and don't use it
+	 */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab = 2000000000,
+		.ib = 2000000000,
+	},
+	/* Master and slaves can be from different fabrics */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 2000000000,
+		.ib = 2000000000,
+	},
+};
+
+static struct msm_bus_paths dtv_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(dtv_bus_init_vectors),
+		dtv_bus_init_vectors,
+	},
+	{
+		ARRAY_SIZE(dtv_bus_def_vectors),
+		dtv_bus_def_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata dtv_bus_scale_pdata = {
+	dtv_bus_scale_usecases,
+	ARRAY_SIZE(dtv_bus_scale_usecases),
+	.name = "dtv",
+};
+
+static struct lcdc_platform_data dtv_pdata = {
+	.bus_scale_table = &dtv_bus_scale_pdata,
+};
+
+static struct msm_bus_paths dtv_hdmi_prim_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(dtv_bus_init_vectors),
+		dtv_bus_init_vectors,
+	},
+	{
+		ARRAY_SIZE(dtv_bus_hdmi_prim_vectors),
+		dtv_bus_hdmi_prim_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata dtv_hdmi_prim_bus_scale_pdata = {
+	dtv_hdmi_prim_bus_scale_usecases,
+	ARRAY_SIZE(dtv_hdmi_prim_bus_scale_usecases),
+	.name = "dtv",
+};
+
+static struct lcdc_platform_data dtv_hdmi_prim_pdata = {
+	.bus_scale_table = &dtv_hdmi_prim_bus_scale_pdata,
+};
+#endif
+
+
+static struct lcdc_platform_data lcdc_pdata = {
+	.lcdc_power_save   = lcdc_panel_power,
+};
+
+
+#define MDP_VSYNC_GPIO			28
+
+/*
+ * MIPI_DSI only use 8058_LDO0 which need always on
+ * therefore it need to be put at low power mode if
+ * it was not used instead of turn it off.
+ */
+static int mipi_dsi_panel_power(int on)
+{
+	int flag_on = !!on;
+	static int mipi_dsi_power_save_on;
+	static struct regulator *ldo0;
+	int rc = 0;
+
+	if (mipi_dsi_power_save_on == flag_on)
+		return 0;
+
+	mipi_dsi_power_save_on = flag_on;
+
+	if (ldo0 == NULL) {	/* init */
+		ldo0 = regulator_get(NULL, "8058_l0");
+		if (IS_ERR(ldo0)) {
+			pr_debug("%s: LDO0 failed\n", __func__);
+			rc = PTR_ERR(ldo0);
+			return rc;
+		}
+
+		rc = regulator_set_voltage(ldo0, 1200000, 1200000);
+		if (rc)
+			goto out;
+
+		rc = regulator_enable(ldo0);
+		if (rc)
+			goto out;
+	}
+
+	if (on) {
+		/* set ldo0 to HPM */
+		rc = regulator_set_optimum_mode(ldo0, 100000);
+		if (rc < 0)
+			goto out;
+	} else {
+		/* set ldo0 to LPM */
+		rc = regulator_set_optimum_mode(ldo0, 1000);
+		if (rc < 0)
+			goto out;
+	}
+
+	return 0;
+out:
+	regulator_disable(ldo0);
+	regulator_put(ldo0);
+	ldo0 = NULL;
+	return rc;
+}
+
+static struct mipi_dsi_platform_data mipi_dsi_pdata = {
+	.vsync_gpio = MDP_VSYNC_GPIO,
+	.dsi_power_save   = mipi_dsi_panel_power,
+};
+
+#ifdef CONFIG_FB_MSM_TVOUT
+static struct regulator *reg_8058_l13;
+
+static int atv_dac_power(int on)
+{
+	int rc = 0;
+	#define _GET_REGULATOR(var, name) do {				\
+		var = regulator_get(NULL, name);			\
+		if (IS_ERR(var)) {					\
+			pr_info("'%s' regulator not found, rc=%ld\n",	\
+				name, IS_ERR(var));			\
+			var = NULL;					\
+			return -ENODEV;					\
+		}							\
+	} while (0)
+
+	if (!reg_8058_l13)
+		_GET_REGULATOR(reg_8058_l13, "8058_l13");
+	#undef _GET_REGULATOR
+
+	if (on) {
+		rc = regulator_set_voltage(reg_8058_l13, 2050000, 2050000);
+		if (rc) {
+			pr_info("%s: '%s' regulator set voltage failed,\
+				rc=%d\n", __func__, "8058_l13", rc);
+			return rc;
+		}
+
+		rc = regulator_enable(reg_8058_l13);
+		if (rc) {
+			pr_err("%s: '%s' regulator enable failed,\
+				rc=%d\n", __func__, "8058_l13", rc);
+			return rc;
+		}
+	} else {
+		rc = regulator_force_disable(reg_8058_l13);
+		if (rc)
+			pr_warning("%s: '%s' regulator disable failed, rc=%d\n",
+				__func__, "8058_l13", rc);
+	}
+	return rc;
+
+}
+#endif
+
+#ifdef CONFIG_FB_MSM_MIPI_DSI
+int mdp_core_clk_rate_table[] = {
+	85330000,
+	128000000,
+	160000000,
+	200000000,
+};
+#else
+int mdp_core_clk_rate_table[] = {
+	59080000,
+	128000000,
+	128000000,
+	200000000,
+};
+#endif
+
+static struct msm_panel_common_pdata mdp_pdata = {
+	.gpio = MDP_VSYNC_GPIO,
+	.mdp_core_clk_rate = 59080000,
+	.mdp_core_clk_table = mdp_core_clk_rate_table,
+	.num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
+#ifdef CONFIG_MSM_BUS_SCALING
+	.mdp_bus_scale_table = &mdp_bus_scale_pdata,
+#endif
+	.mdp_rev = MDP_REV_41,
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	.mem_hid = BIT(ION_CP_WB_HEAP_ID),
+#else
+	.mem_hid = MEMTYPE_EBI1,
+#endif
+};
+
+static void __init reserve_mdp_memory(void)
+{
+	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)
+	msm8x60_reserve_table[mdp_pdata.mem_hid].size +=
+		mdp_pdata.ov0_wb_size;
+	msm8x60_reserve_table[mdp_pdata.mem_hid].size +=
+		mdp_pdata.ov1_wb_size;
+#endif
+}
+
+#ifdef CONFIG_FB_MSM_TVOUT
+
+#ifdef CONFIG_MSM_BUS_SCALING
+static struct msm_bus_vectors atv_bus_init_vectors[] = {
+	/* For now, 0th array entry is reserved.
+	 * Please leave 0 as is and don't use it
+	 */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab = 0,
+		.ib = 0,
+	},
+	/* Master and slaves can be from different fabrics */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+static struct msm_bus_vectors atv_bus_def_vectors[] = {
+	/* For now, 0th array entry is reserved.
+	 * Please leave 0 as is and don't use it
+	 */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab = 236390400,
+		.ib = 265939200,
+	},
+	/* Master and slaves can be from different fabrics */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 236390400,
+		.ib = 265939200,
+	},
+};
+static struct msm_bus_paths atv_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(atv_bus_init_vectors),
+		atv_bus_init_vectors,
+	},
+	{
+		ARRAY_SIZE(atv_bus_def_vectors),
+		atv_bus_def_vectors,
+	},
+};
+static struct msm_bus_scale_pdata atv_bus_scale_pdata = {
+	atv_bus_scale_usecases,
+	ARRAY_SIZE(atv_bus_scale_usecases),
+	.name = "atv",
+};
+#endif
+
+static struct tvenc_platform_data atv_pdata = {
+	.poll		 = 0,
+	.pm_vid_en	 = atv_dac_power,
+#ifdef CONFIG_MSM_BUS_SCALING
+	.bus_scale_table = &atv_bus_scale_pdata,
+#endif
+};
+#endif
+
+static void __init msm_fb_add_devices(void)
+{
+#ifdef CONFIG_FB_MSM_LCDC_DSUB
+	mdp_pdata.mdp_core_clk_table = NULL;
+	mdp_pdata.num_mdp_clk = 0;
+	mdp_pdata.mdp_core_clk_rate = 200000000;
+#endif
+	if (machine_is_msm8x60_rumi3())
+		msm_fb_register_device("mdp", NULL);
+	else
+		msm_fb_register_device("mdp", &mdp_pdata);
+
+	msm_fb_register_device("lcdc", &lcdc_pdata);
+	msm_fb_register_device("mipi_dsi", &mipi_dsi_pdata);
+#ifdef CONFIG_MSM_BUS_SCALING
+	if (hdmi_is_primary)
+		msm_fb_register_device("dtv", &dtv_hdmi_prim_pdata);
+	else
+		msm_fb_register_device("dtv", &dtv_pdata);
+#endif
+#ifdef CONFIG_FB_MSM_TVOUT
+	msm_fb_register_device("tvenc", &atv_pdata);
+	msm_fb_register_device("tvout_device", NULL);
+#endif
+}
+
+/**
+ * Set MDP clocks to high frequency to avoid underflow when
+ * using high resolution 1200x1920 WUXGA/HDMI as primary panels
+ */
+static void set_mdp_clocks_for_wuxga(void)
+{
+	int i;
+
+	mdp_sd_smi_vectors[0].ab = 2000000000;
+	mdp_sd_smi_vectors[0].ib = 2000000000;
+	mdp_sd_smi_vectors[1].ab = 2000000000;
+	mdp_sd_smi_vectors[1].ib = 2000000000;
+
+	mdp_sd_ebi_vectors[0].ab = 2000000000;
+	mdp_sd_ebi_vectors[0].ib = 2000000000;
+	mdp_sd_ebi_vectors[1].ab = 2000000000;
+	mdp_sd_ebi_vectors[1].ib = 2000000000;
+
+	mdp_vga_vectors[0].ab = 2000000000;
+	mdp_vga_vectors[0].ib = 2000000000;
+	mdp_vga_vectors[1].ab = 2000000000;
+	mdp_vga_vectors[1].ib = 2000000000;
+
+	mdp_720p_vectors[0].ab = 2000000000;
+	mdp_720p_vectors[0].ib = 2000000000;
+	mdp_720p_vectors[1].ab = 2000000000;
+	mdp_720p_vectors[1].ib = 2000000000;
+
+	mdp_1080p_vectors[0].ab = 2000000000;
+	mdp_1080p_vectors[0].ib = 2000000000;
+	mdp_1080p_vectors[1].ab = 2000000000;
+	mdp_1080p_vectors[1].ib = 2000000000;
+
+	mdp_pdata.mdp_core_clk_rate = 200000000;
+
+	for (i = 0; i < ARRAY_SIZE(mdp_core_clk_rate_table); i++)
+		mdp_core_clk_rate_table[i] = 200000000;
+}
+
+#if (defined(CONFIG_MARIMBA_CORE)) && \
+	(defined(CONFIG_MSM_BT_POWER) || defined(CONFIG_MSM_BT_POWER_MODULE))
+
+static const struct {
+	char *name;
+	int vmin;
+	int vmax;
+} bt_regs_info[] = {
+	{ "8058_s3", 1800000, 1800000 },
+	{ "8058_s2", 1300000, 1300000 },
+	{ "8058_l8", 2900000, 3050000 },
+};
+
+static struct {
+	bool enabled;
+} bt_regs_status[] = {
+	{ false },
+	{ false },
+	{ false },
+};
+static struct regulator *bt_regs[ARRAY_SIZE(bt_regs_info)];
+
+static int bahama_bt(int on)
+{
+	int rc;
+	int i;
+	struct marimba config = { .mod_id =  SLAVE_ID_BAHAMA};
+
+	struct bahama_variant_register {
+		const size_t size;
+		const struct bahama_config_register *set;
+	};
+
+	const struct bahama_config_register *p;
+
+	u8 version;
+
+	const struct bahama_config_register v10_bt_on[] = {
+		{ 0xE9, 0x00, 0xFF },
+		{ 0xF4, 0x80, 0xFF },
+		{ 0xE4, 0x00, 0xFF },
+		{ 0xE5, 0x00, 0x0F },
+#ifdef CONFIG_WLAN
+		{ 0xE6, 0x38, 0x7F },
+		{ 0xE7, 0x06, 0xFF },
+#endif
+		{ 0xE9, 0x21, 0xFF },
+		{ 0x01, 0x0C, 0x1F },
+		{ 0x01, 0x08, 0x1F },
+	};
+
+	const struct bahama_config_register v20_bt_on_fm_off[] = {
+		{ 0x11, 0x0C, 0xFF },
+		{ 0x13, 0x01, 0xFF },
+		{ 0xF4, 0x80, 0xFF },
+		{ 0xF0, 0x00, 0xFF },
+		{ 0xE9, 0x00, 0xFF },
+#ifdef CONFIG_WLAN
+		{ 0x81, 0x00, 0x7F },
+		{ 0x82, 0x00, 0xFF },
+		{ 0xE6, 0x38, 0x7F },
+		{ 0xE7, 0x06, 0xFF },
+#endif
+		{ 0xE9, 0x21, 0xFF },
+	};
+
+	const struct bahama_config_register v20_bt_on_fm_on[] = {
+		{ 0x11, 0x0C, 0xFF },
+		{ 0x13, 0x01, 0xFF },
+		{ 0xF4, 0x86, 0xFF },
+		{ 0xF0, 0x06, 0xFF },
+		{ 0xE9, 0x00, 0xFF },
+#ifdef CONFIG_WLAN
+		{ 0x81, 0x00, 0x7F },
+		{ 0x82, 0x00, 0xFF },
+		{ 0xE6, 0x38, 0x7F },
+		{ 0xE7, 0x06, 0xFF },
+#endif
+		{ 0xE9, 0x21, 0xFF },
+	};
+
+	const struct bahama_config_register v10_bt_off[] = {
+		{ 0xE9, 0x00, 0xFF },
+	};
+
+	const struct bahama_config_register v20_bt_off_fm_off[] = {
+		{ 0xF4, 0x84, 0xFF },
+		{ 0xF0, 0x04, 0xFF },
+		{ 0xE9, 0x00, 0xFF }
+	};
+
+	const struct bahama_config_register v20_bt_off_fm_on[] = {
+		{ 0xF4, 0x86, 0xFF },
+		{ 0xF0, 0x06, 0xFF },
+		{ 0xE9, 0x00, 0xFF }
+	};
+	const struct bahama_variant_register bt_bahama[2][3] = {
+		{
+			{ ARRAY_SIZE(v10_bt_off), v10_bt_off },
+			{ ARRAY_SIZE(v20_bt_off_fm_off), v20_bt_off_fm_off },
+			{ ARRAY_SIZE(v20_bt_off_fm_on), v20_bt_off_fm_on }
+		},
+		{
+			{ ARRAY_SIZE(v10_bt_on), v10_bt_on },
+			{ ARRAY_SIZE(v20_bt_on_fm_off), v20_bt_on_fm_off },
+			{ ARRAY_SIZE(v20_bt_on_fm_on), v20_bt_on_fm_on }
+		}
+	};
+
+	u8 offset = 0; /* index into bahama configs */
+
+	on = on ? 1 : 0;
+	version = read_bahama_ver();
+
+	if (version ==  VER_UNSUPPORTED) {
+		dev_err(&msm_bt_power_device.dev,
+			"%s: unsupported version\n",
+			__func__);
+		return -EIO;
+	}
+
+	if (version == VER_2_0) {
+		if (marimba_get_fm_status(&config))
+			offset = 0x01;
+	}
+
+	/* Voting off 1.3V S2 Regulator,BahamaV2 used in Normal mode */
+	if (on && (version == VER_2_0)) {
+		for (i = 0; i < ARRAY_SIZE(bt_regs_info); i++) {
+			if ((!strcmp(bt_regs_info[i].name, "8058_s2"))
+				&& (bt_regs_status[i].enabled == true)) {
+				if (regulator_disable(bt_regs[i])) {
+					dev_err(&msm_bt_power_device.dev,
+						"%s: regulator disable failed",
+						__func__);
+				}
+				bt_regs_status[i].enabled = false;
+				break;
+			}
+		}
+	}
+
+	p = bt_bahama[on][version + offset].set;
+
+	dev_info(&msm_bt_power_device.dev,
+		"%s: found version %d\n", __func__, version);
+
+	for (i = 0; i < bt_bahama[on][version + offset].size; i++) {
+		u8 value = (p+i)->value;
+		rc = marimba_write_bit_mask(&config,
+			(p+i)->reg,
+			&value,
+			sizeof((p+i)->value),
+			(p+i)->mask);
+		if (rc < 0) {
+			dev_err(&msm_bt_power_device.dev,
+				"%s: reg %d write failed: %d\n",
+				__func__, (p+i)->reg, rc);
+			return rc;
+		}
+		dev_dbg(&msm_bt_power_device.dev,
+			"%s: reg 0x%02x write value 0x%02x mask 0x%02x\n",
+				__func__, (p+i)->reg,
+				value, (p+i)->mask);
+	}
+	/* Update BT Status */
+	if (on)
+		marimba_set_bt_status(&config, true);
+	else
+		marimba_set_bt_status(&config, false);
+
+	return 0;
+}
+
+static int bluetooth_use_regulators(int on)
+{
+	int i, recover = -1, rc = 0;
+
+	for (i = 0; i < ARRAY_SIZE(bt_regs_info); i++) {
+		bt_regs[i] = on ? regulator_get(&msm_bt_power_device.dev,
+						bt_regs_info[i].name) :
+				(regulator_put(bt_regs[i]), NULL);
+		if (IS_ERR(bt_regs[i])) {
+			rc = PTR_ERR(bt_regs[i]);
+			dev_err(&msm_bt_power_device.dev,
+				"regulator %s get failed (%d)\n",
+				bt_regs_info[i].name, rc);
+			recover = i - 1;
+			bt_regs[i] = NULL;
+			break;
+		}
+
+		if (!on)
+			continue;
+
+		rc = regulator_set_voltage(bt_regs[i],
+					  bt_regs_info[i].vmin,
+					  bt_regs_info[i].vmax);
+		if (rc < 0) {
+			dev_err(&msm_bt_power_device.dev,
+				"regulator %s voltage set (%d)\n",
+				bt_regs_info[i].name, rc);
+			recover = i;
+			break;
+		}
+	}
+
+	if (on && (recover > -1))
+		for (i = recover; i >= 0; i--) {
+			regulator_put(bt_regs[i]);
+			bt_regs[i] = NULL;
+		}
+
+	return rc;
+}
+
+static int bluetooth_switch_regulators(int on)
+{
+	int i, rc = 0;
+
+	for (i = 0; i < ARRAY_SIZE(bt_regs_info); i++) {
+		if (on && (bt_regs_status[i].enabled == false)) {
+			rc = regulator_enable(bt_regs[i]);
+			if (rc < 0) {
+				dev_err(&msm_bt_power_device.dev,
+					"regulator %s %s failed (%d)\n",
+					bt_regs_info[i].name,
+					"enable", rc);
+				if (i > 0) {
+					while (--i) {
+						regulator_disable(bt_regs[i]);
+						bt_regs_status[i].enabled
+								 = false;
+					}
+					break;
+				}
+			}
+			bt_regs_status[i].enabled = true;
+		} else if (!on && (bt_regs_status[i].enabled == true)) {
+			rc = regulator_disable(bt_regs[i]);
+			if (rc < 0) {
+				dev_err(&msm_bt_power_device.dev,
+					"regulator %s %s failed (%d)\n",
+					bt_regs_info[i].name,
+					"disable", rc);
+				break;
+			}
+			bt_regs_status[i].enabled = false;
+		}
+	}
+	return rc;
+}
+
+static struct msm_xo_voter *bt_clock;
+
+static int bluetooth_power(int on)
+{
+	int rc = 0;
+	int id;
+
+	/* In case probe function fails, cur_connv_type would be -1 */
+	id = adie_get_detected_connectivity_type();
+	if (id != BAHAMA_ID) {
+		pr_err("%s: unexpected adie connectivity type: %d\n",
+			__func__, id);
+		return -ENODEV;
+	}
+
+	if (on) {
+
+		rc = bluetooth_use_regulators(1);
+		if (rc < 0)
+			goto out;
+
+		rc = bluetooth_switch_regulators(1);
+
+		if (rc < 0)
+			goto fail_put;
+
+		bt_clock = msm_xo_get(MSM_XO_TCXO_D0, "bt_power");
+
+		if (IS_ERR(bt_clock)) {
+			pr_err("Couldn't get TCXO_D0 voter\n");
+			goto fail_switch;
+		}
+
+		rc = msm_xo_mode_vote(bt_clock, MSM_XO_MODE_ON);
+
+		if (rc < 0) {
+			pr_err("Failed to vote for TCXO_DO ON\n");
+			goto fail_vote;
+		}
+
+		rc = bahama_bt(1);
+
+		if (rc < 0)
+			goto fail_clock;
+
+		msleep(10);
+
+		rc = msm_xo_mode_vote(bt_clock, MSM_XO_MODE_PIN_CTRL);
+
+		if (rc < 0) {
+			pr_err("Failed to vote for TCXO_DO pin control\n");
+			goto fail_vote;
+		}
+	} else {
+		/* check for initial RFKILL block (power off) */
+		/* some RFKILL versions/configurations rfkill_register */
+		/* calls here for an initial set_block */
+		/* avoid calling i2c and regulator before unblock (on) */
+		if (platform_get_drvdata(&msm_bt_power_device) == NULL) {
+			dev_info(&msm_bt_power_device.dev,
+				"%s: initialized OFF/blocked\n", __func__);
+			goto out;
+		}
+
+		bahama_bt(0);
+
+fail_clock:
+		msm_xo_mode_vote(bt_clock, MSM_XO_MODE_OFF);
+fail_vote:
+		msm_xo_put(bt_clock);
+fail_switch:
+		bluetooth_switch_regulators(0);
+fail_put:
+		bluetooth_use_regulators(0);
+	}
+
+out:
+	if (rc < 0)
+		on = 0;
+	dev_info(&msm_bt_power_device.dev,
+		"Bluetooth power switch: state %d result %d\n", on, rc);
+
+	return rc;
+}
+
+#endif /*CONFIG_MARIMBA_CORE, CONFIG_MSM_BT_POWER, CONFIG_MSM_BT_POWER_MODULE*/
+
+static void __init msm8x60_cfg_smsc911x(void)
+{
+	smsc911x_resources[1].start =
+		PM8058_GPIO_IRQ(PM8058_IRQ_BASE, 6);
+	smsc911x_resources[1].end =
+		PM8058_GPIO_IRQ(PM8058_IRQ_BASE, 6);
+}
+
+void msm_fusion_setup_pinctrl(void)
+{
+	struct msm_xo_voter *a1;
+
+	if (socinfo_get_platform_subtype() == 0x3) {
+		/*
+		 * Vote for the A1 clock to be in pin control mode before
+		* the external images are loaded.
+		*/
+		a1 = msm_xo_get(MSM_XO_TCXO_A1, "mdm");
+		BUG_ON(!a1);
+		msm_xo_mode_vote(a1, MSM_XO_MODE_PIN_CTRL);
+	}
+}
+
+struct msm_board_data {
+	struct msm_gpiomux_configs *gpiomux_cfgs;
+};
+
+static struct msm_board_data msm8x60_rumi3_board_data __initdata = {
+	.gpiomux_cfgs = msm8x60_surf_ffa_gpiomux_cfgs,
+};
+
+static struct msm_board_data msm8x60_sim_board_data __initdata = {
+	.gpiomux_cfgs = msm8x60_surf_ffa_gpiomux_cfgs,
+};
+
+static struct msm_board_data msm8x60_surf_board_data __initdata = {
+	.gpiomux_cfgs = msm8x60_surf_ffa_gpiomux_cfgs,
+};
+
+static struct msm_board_data msm8x60_ffa_board_data __initdata = {
+	.gpiomux_cfgs = msm8x60_surf_ffa_gpiomux_cfgs,
+};
+
+static struct msm_board_data msm8x60_fluid_board_data __initdata = {
+	.gpiomux_cfgs = msm8x60_fluid_gpiomux_cfgs,
+};
+
+static struct msm_board_data msm8x60_charm_surf_board_data __initdata = {
+	.gpiomux_cfgs = msm8x60_charm_gpiomux_cfgs,
+};
+
+static struct msm_board_data msm8x60_charm_ffa_board_data __initdata = {
+	.gpiomux_cfgs = msm8x60_charm_gpiomux_cfgs,
+};
+
+static struct msm_board_data msm8x60_dragon_board_data __initdata = {
+	.gpiomux_cfgs = msm8x60_dragon_gpiomux_cfgs,
+};
+
+static void __init msm8x60_init(struct msm_board_data *board_data)
+{
+	uint32_t soc_platform_version;
+#ifdef CONFIG_USB_EHCI_MSM_72K
+	struct pm8xxx_mpp_config_data hsusb_phy_mpp = {
+		.type		= PM8XXX_MPP_TYPE_D_OUTPUT,
+		.level		= PM8901_MPP_DIG_LEVEL_L5,
+		.control	= PM8XXX_MPP_DOUT_CTRL_HIGH,
+	};
+#endif
+	pmic_reset_irq = PM8058_IRQ_BASE + PM8058_RESOUT_IRQ;
+
+	/*
+	 * Initialize RPM first as other drivers and devices may need
+	 * it for their initialization.
+	 */
+	BUG_ON(msm_rpm_init(&msm8660_rpm_data));
+	BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
+	if (msm_xo_init())
+		pr_err("Failed to initialize XO votes\n");
+
+	msm8x60_check_2d_hardware();
+
+	/* Change SPM handling of core 1 if PMM 8160 is present. */
+	soc_platform_version = socinfo_get_platform_version();
+	if (SOCINFO_VERSION_MAJOR(soc_platform_version) == 1 &&
+			SOCINFO_VERSION_MINOR(soc_platform_version) >= 2) {
+		struct msm_spm_platform_data *spm_data;
+
+		spm_data = &msm_spm_data_v1[1];
+		spm_data->reg_init_values[MSM_SPM_REG_SAW_CFG] &= ~0x0F00UL;
+		spm_data->reg_init_values[MSM_SPM_REG_SAW_CFG] |= 0x0100UL;
+
+		spm_data = &msm_spm_data[1];
+		spm_data->reg_init_values[MSM_SPM_REG_SAW_CFG] &= ~0x0F00UL;
+		spm_data->reg_init_values[MSM_SPM_REG_SAW_CFG] |= 0x0100UL;
+	}
+
+	/*
+	 * Initialize SPM before acpuclock as the latter calls into SPM
+	 * driver to set ACPU voltages.
+	 */
+	if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) != 1)
+		msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
+	else
+		msm_spm_init(msm_spm_data_v1, ARRAY_SIZE(msm_spm_data_v1));
+
+	/*
+	 * Set regulators 8901_l4 and 8901_l6 to be always on in HPM for SURF
+	 * devices so that the RPM doesn't drop into a low power mode that an
+	 * un-reworked SURF cannot resume from.
+	 */
+	if (machine_is_msm8x60_surf()) {
+		int i;
+
+		for (i = 0; i < ARRAY_SIZE(rpm_regulator_init_data); i++)
+			if (rpm_regulator_init_data[i].id
+				== RPM_VREG_ID_PM8901_L4
+			    || rpm_regulator_init_data[i].id
+				== RPM_VREG_ID_PM8901_L6)
+				rpm_regulator_init_data[i]
+					.init_data.constraints.always_on = 1;
+	}
+
+	/*
+	 * Disable regulator info printing so that regulator registration
+	 * messages do not enter the kmsg log.
+	 */
+	regulator_suppress_info_printing();
+
+	/* Initialize regulators needed for clock_init. */
+	platform_add_devices(early_regulators, ARRAY_SIZE(early_regulators));
+
+	msm_clock_init(&msm8x60_clock_init_data);
+
+	/* Buses need to be initialized before early-device registration
+	 * to get the platform data for fabrics.
+	 */
+	msm8x60_init_buses();
+	platform_add_devices(early_devices, ARRAY_SIZE(early_devices));
+	/* CPU frequency control is not supported on simulated targets. */
+	if (!machine_is_msm8x60_rumi3() && !machine_is_msm8x60_sim())
+		acpuclk_init(&acpuclk_8x60_soc_data);
+
+	/*
+	 * Enable EBI2 only for boards which make use of it. Leave
+	 * it disabled for all others for additional power savings.
+	 */
+	if (machine_is_msm8x60_surf() || machine_is_msm8x60_ffa() ||
+			machine_is_msm8x60_rumi3() ||
+			machine_is_msm8x60_sim() ||
+			machine_is_msm8x60_fluid() ||
+			machine_is_msm8x60_dragon())
+		msm8x60_init_ebi2();
+	msm8x60_init_tlmm();
+	msm8x60_init_gpiomux(board_data->gpiomux_cfgs);
+	msm8x60_init_uart12dm();
+#ifdef CONFIG_MSM_CAMERA_V4L2
+	msm8x60_init_cam();
+#endif
+	msm8x60_init_mmc();
+
+
+#if defined(CONFIG_PMIC8058_OTHC) || defined(CONFIG_PMIC8058_OTHC_MODULE)
+	msm8x60_init_pm8058_othc();
+#endif
+
+	if (machine_is_msm8x60_fluid())
+		pm8058_platform_data.keypad_pdata = &fluid_keypad_data;
+	else if (machine_is_msm8x60_dragon())
+		pm8058_platform_data.keypad_pdata = &dragon_keypad_data;
+	else
+		pm8058_platform_data.keypad_pdata = &ffa_keypad_data;
+#if !defined(CONFIG_MSM_CAMERA_V4L2) && defined(CONFIG_WEBCAM_OV9726)
+	/* Specify reset pin for OV9726 */
+	if (machine_is_msm8x60_dragon()) {
+		msm_camera_sensor_ov9726_data.sensor_reset = 62;
+		ov9726_sensor_8660_info.mount_angle = 270;
+	}
+#endif
+#ifdef CONFIG_BATTERY_MSM8X60
+	if (machine_is_msm8x60_surf() || machine_is_msm8x60_ffa() ||
+		machine_is_msm8x60_fusion() || machine_is_msm8x60_dragon() ||
+		machine_is_msm8x60_fusn_ffa() || machine_is_msm8x60_fluid())
+		platform_device_register(&msm_charger_device);
+#endif
+
+	if (machine_is_msm8x60_dragon())
+		pm8058_platform_data.charger_pdata = &pmic8058_charger_dragon;
+	if (!machine_is_msm8x60_fluid())
+		pm8058_platform_data.charger_pdata = &pmic8058_charger_ffa_surf;
+
+	/* configure pmic leds */
+	if (machine_is_msm8x60_fluid())
+		pm8058_platform_data.leds_pdata = &pm8058_fluid_flash_leds_data;
+	else if (machine_is_msm8x60_dragon())
+		pm8058_platform_data.leds_pdata = &pm8058_dragon_leds_data;
+	else
+		pm8058_platform_data.leds_pdata = &pm8058_flash_leds_data;
+
+	if (machine_is_msm8x60_ffa() || machine_is_msm8x60_fusn_ffa() ||
+		machine_is_msm8x60_dragon()) {
+		pm8058_platform_data.vibrator_pdata = &pm8058_vib_pdata;
+	}
+
+	if (machine_is_msm8x60_surf() || machine_is_msm8x60_ffa() ||
+	    machine_is_msm8x60_fluid() || machine_is_msm8x60_fusion() ||
+	    machine_is_msm8x60_fusn_ffa() || machine_is_msm8x60_dragon()) {
+		msm8x60_cfg_smsc911x();
+		if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) != 1)
+			platform_add_devices(msm8660_footswitch,
+					     msm8660_num_footswitch);
+		platform_add_devices(surf_devices,
+				     ARRAY_SIZE(surf_devices));
+
+#ifdef CONFIG_MSM_DSPS
+		if (machine_is_msm8x60_fluid()) {
+			platform_device_unregister(&msm_gsbi12_qup_i2c_device);
+			msm8x60_init_dsps();
+		}
+#endif
+
+	pm8901_vreg_mpp0_init();
+
+	platform_device_register(&msm8x60_8901_mpp_vreg);
+
+#ifdef CONFIG_USB_EHCI_MSM_72K
+	/*
+	 * Drive MPP2 pin HIGH for PHY to generate ID interrupts on 8660
+	 * fluid
+	 */
+	if (machine_is_msm8x60_fluid())
+		pm8xxx_mpp_config(PM8901_MPP_PM_TO_SYS(1), &hsusb_phy_mpp);
+	msm_add_host(0, &msm_usb_host_pdata);
+#endif
+
+#ifdef CONFIG_SND_SOC_MSM8660_APQ
+		if (machine_is_msm8x60_dragon())
+			platform_add_devices(dragon_alsa_devices,
+					ARRAY_SIZE(dragon_alsa_devices));
+		else
+#endif
+			platform_add_devices(asoc_devices,
+					ARRAY_SIZE(asoc_devices));
+	} else {
+		msm8x60_configure_smc91x();
+		platform_add_devices(rumi_sim_devices,
+				     ARRAY_SIZE(rumi_sim_devices));
+	}
+#if defined(CONFIG_USB_PEHCI_HCD) || defined(CONFIG_USB_PEHCI_HCD_MODULE)
+	if (machine_is_msm8x60_surf() || machine_is_msm8x60_ffa() ||
+		machine_is_msm8x60_dragon())
+		msm8x60_cfg_isp1763();
+#endif
+
+	if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
+		platform_add_devices(charm_devices, ARRAY_SIZE(charm_devices));
+
+
+#if defined(CONFIG_SPI_QUP) || defined(CONFIG_SPI_QUP_MODULE)
+	if (machine_is_msm8x60_fluid())
+		platform_device_register(&msm_gsbi10_qup_spi_device);
+	else
+		platform_device_register(&msm_gsbi1_qup_spi_device);
+#endif
+
+#if defined(CONFIG_TOUCHSCREEN_CYTTSP_I2C_QC) || \
+		defined(CONFIG_TOUCHSCREEN_CYTTSP_I2C_QC_MODULE)
+	if (machine_is_msm8x60_fluid())
+		cyttsp_set_params();
+#endif
+	if (!machine_is_msm8x60_sim())
+		msm_fb_add_devices();
+	fixup_i2c_configs();
+	register_i2c_devices();
+
+	if (machine_is_msm8x60_dragon())
+		smsc911x_config.reset_gpio
+			= GPIO_ETHERNET_RESET_N_DRAGON;
+
+	platform_device_register(&smsc911x_device);
+
+#if (defined(CONFIG_SPI_QUP)) && \
+	(defined(CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT) || \
+	defined(CONFIG_FB_MSM_LCDC_AUO_WVGA) || \
+	defined(CONFIG_FB_MSM_LCDC_NT35582_WVGA))
+
+	if (machine_is_msm8x60_fluid()) {
+#ifdef CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT
+		if (SOCINFO_VERSION_MAJOR(soc_platform_version) < 3) {
+			spi_register_board_info(lcdc_samsung_spi_board_info,
+				ARRAY_SIZE(lcdc_samsung_spi_board_info));
+		} else
+#endif
+		{
+#ifdef CONFIG_FB_MSM_LCDC_AUO_WVGA
+			spi_register_board_info(lcdc_auo_spi_board_info,
+				ARRAY_SIZE(lcdc_auo_spi_board_info));
+#endif
+		}
+#ifdef CONFIG_FB_MSM_LCDC_NT35582_WVGA
+	} else if (machine_is_msm8x60_dragon()) {
+		spi_register_board_info(lcdc_nt35582_spi_board_info,
+			ARRAY_SIZE(lcdc_nt35582_spi_board_info));
+#endif
+	}
+#endif
+
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+
+	pm8058_gpios_init();
+
+#ifdef CONFIG_SENSORS_MSM_ADC
+	if (machine_is_msm8x60_fluid()) {
+		msm_adc_pdata.dev_names = msm_adc_fluid_device_names;
+		msm_adc_pdata.num_adc = ARRAY_SIZE(msm_adc_fluid_device_names);
+		if (SOCINFO_VERSION_MAJOR(soc_platform_version) < 3)
+			msm_adc_pdata.gpio_config = APROC_CONFIG;
+		else
+			msm_adc_pdata.gpio_config = MPROC_CONFIG;
+	}
+	msm_adc_pdata.target_hw = MSM_8x60;
+#endif
+#ifdef CONFIG_MSM8X60_AUDIO
+	msm_snddev_init();
+#endif
+#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
+	if (machine_is_msm8x60_fluid())
+		platform_device_register(&fluid_leds_gpio);
+	else
+		platform_device_register(&gpio_leds);
+#endif
+
+	msm8x60_multi_sdio_init();
+
+	if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
+		msm_fusion_setup_pinctrl();
+}
+
+static void __init msm8x60_rumi3_init(void)
+{
+	msm8x60_init(&msm8x60_rumi3_board_data);
+}
+
+static void __init msm8x60_sim_init(void)
+{
+	msm8x60_init(&msm8x60_sim_board_data);
+}
+
+static void __init msm8x60_surf_init(void)
+{
+	msm8x60_init(&msm8x60_surf_board_data);
+}
+
+static void __init msm8x60_ffa_init(void)
+{
+	msm8x60_init(&msm8x60_ffa_board_data);
+}
+
+static void __init msm8x60_fluid_init(void)
+{
+	msm8x60_init(&msm8x60_fluid_board_data);
+}
+
+static void __init msm8x60_charm_surf_init(void)
+{
+	msm8x60_init(&msm8x60_charm_surf_board_data);
+}
+
+static void __init msm8x60_charm_ffa_init(void)
+{
+	msm8x60_init(&msm8x60_charm_ffa_board_data);
+}
+
+static void __init msm8x60_charm_init_early(void)
+{
+	msm8x60_allocate_memory_regions();
+}
+
+static void __init msm8x60_dragon_init(void)
+{
+	msm8x60_init(&msm8x60_dragon_board_data);
+}
 
 MACHINE_START(MSM8X60_RUMI3, "QCT MSM8X60 RUMI3")
-	.fixup = msm8x60_fixup,
-	.reserve = msm8x60_reserve,
 	.map_io = msm8x60_map_io,
+	.reserve = msm8x60_reserve,
 	.init_irq = msm8x60_init_irq,
 	.handle_irq = gic_handle_irq,
-	.init_machine = msm8x60_init,
+	.init_machine = msm8x60_rumi3_init,
 	.timer = &msm_timer,
-MACHINE_END
-
-MACHINE_START(MSM8X60_SURF, "QCT MSM8X60 SURF")
-	.fixup = msm8x60_fixup,
-	.reserve = msm8x60_reserve,
-	.map_io = msm8x60_map_io,
-	.init_irq = msm8x60_init_irq,
-	.handle_irq = gic_handle_irq,
-	.init_machine = msm8x60_init,
-	.timer = &msm_timer,
+	.init_early = msm8x60_charm_init_early,
 MACHINE_END
 
 MACHINE_START(MSM8X60_SIM, "QCT MSM8X60 SIMULATOR")
-	.fixup = msm8x60_fixup,
-	.reserve = msm8x60_reserve,
 	.map_io = msm8x60_map_io,
+	.reserve = msm8x60_reserve,
 	.init_irq = msm8x60_init_irq,
 	.handle_irq = gic_handle_irq,
-	.init_machine = msm8x60_init,
+	.init_machine = msm8x60_sim_init,
 	.timer = &msm_timer,
+	.init_early = msm8x60_charm_init_early,
+MACHINE_END
+
+MACHINE_START(MSM8X60_SURF, "QCT MSM8X60 SURF")
+	.map_io = msm8x60_map_io,
+	.reserve = msm8x60_reserve,
+	.init_irq = msm8x60_init_irq,
+	.handle_irq = gic_handle_irq,
+	.init_machine = msm8x60_surf_init,
+	.timer = &msm_timer,
+	.init_early = msm8x60_charm_init_early,
 MACHINE_END
 
 MACHINE_START(MSM8X60_FFA, "QCT MSM8X60 FFA")
-	.fixup = msm8x60_fixup,
-	.reserve = msm8x60_reserve,
 	.map_io = msm8x60_map_io,
+	.reserve = msm8x60_reserve,
 	.init_irq = msm8x60_init_irq,
 	.handle_irq = gic_handle_irq,
-	.init_machine = msm8x60_init,
+	.init_machine = msm8x60_ffa_init,
 	.timer = &msm_timer,
+	.init_early = msm8x60_charm_init_early,
 MACHINE_END
 
-#ifdef CONFIG_OF
-/* TODO: General device tree support for all MSM. */
-DT_MACHINE_START(MSM_DT, "Qualcomm MSM (Flattened Device Tree)")
+MACHINE_START(MSM8X60_FLUID, "QCT MSM8X60 FLUID")
 	.map_io = msm8x60_map_io,
+	.reserve = msm8x60_reserve,
 	.init_irq = msm8x60_init_irq,
-	.init_machine = msm8x60_dt_init,
+	.handle_irq = gic_handle_irq,
+	.init_machine = msm8x60_fluid_init,
 	.timer = &msm_timer,
-	.dt_compat = msm8x60_fluid_match,
+	.init_early = msm8x60_charm_init_early,
 MACHINE_END
-#endif /* CONFIG_OF */
+
+MACHINE_START(MSM8X60_FUSION, "QCT MSM8X60 FUSION SURF")
+	.map_io = msm8x60_map_io,
+	.reserve = msm8x60_reserve,
+	.init_irq = msm8x60_init_irq,
+	.handle_irq = gic_handle_irq,
+	.init_machine = msm8x60_charm_surf_init,
+	.timer = &msm_timer,
+	.init_early = msm8x60_charm_init_early,
+MACHINE_END
+
+MACHINE_START(MSM8X60_FUSN_FFA, "QCT MSM8X60 FUSION FFA")
+	.map_io = msm8x60_map_io,
+	.reserve = msm8x60_reserve,
+	.init_irq = msm8x60_init_irq,
+	.handle_irq = gic_handle_irq,
+	.init_machine = msm8x60_charm_ffa_init,
+	.timer = &msm_timer,
+	.init_early = msm8x60_charm_init_early,
+MACHINE_END
+
+MACHINE_START(MSM8X60_DRAGON, "QCT MSM8X60 DRAGON")
+	.map_io = msm8x60_map_io,
+	.reserve = msm8x60_reserve,
+	.init_irq = msm8x60_init_irq,
+	.handle_irq = gic_handle_irq,
+	.init_machine = msm8x60_dragon_init,
+	.timer = &msm_timer,
+	.init_early = msm8x60_charm_init_early,
+MACHINE_END
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
new file mode 100644
index 0000000..db0c9c0
--- /dev/null
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -0,0 +1,1025 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio_event.h>
+#include <linux/usb/android.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/i2c.h>
+#include <linux/android_pmem.h>
+#include <linux/bootmem.h>
+#include <linux/mfd/marimba.h>
+#include <linux/power_supply.h>
+#include <linux/input/rmi_platformdata.h>
+#include <linux/input/rmi_i2c.h>
+#include <linux/i2c/atmel_mxt_ts.h>
+#include <linux/regulator/consumer.h>
+#include <linux/memblock.h>
+#include <linux/input/ft5x06_ts.h>
+#include <linux/msm_adc.h>
+#include <linux/fmem.h>
+#include <asm/mach/mmc.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/hardware/gic.h>
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_hsusb.h>
+#include <mach/rpc_hsusb.h>
+#include <mach/rpc_pmapp.h>
+#include <mach/usbdiag.h>
+#include <mach/msm_memtypes.h>
+#include <mach/msm_serial_hs.h>
+#include <mach/pmic.h>
+#include <mach/socinfo.h>
+#include <mach/vreg.h>
+#include <mach/rpc_pmapp.h>
+#include <mach/msm_battery.h>
+#include <mach/rpc_server_handset.h>
+#include <mach/socinfo.h>
+#include "board-msm7x27a-regulator.h"
+#include "devices.h"
+#include "devices-msm7x2xa.h"
+#include "pm.h"
+#include "timer.h"
+#include "pm-boot.h"
+#include "board-msm7x27a-regulator.h"
+#include "board-msm7627a.h"
+
+#define PMEM_KERNEL_EBI1_SIZE	0x3A000
+#define MSM_PMEM_AUDIO_SIZE	0x1F4000
+#define BAHAMA_SLAVE_ID_FM_REG 0x02
+#define FM_GPIO	83
+#define BT_PCM_BCLK_MODE  0x88
+#define BT_PCM_DIN_MODE   0x89
+#define BT_PCM_DOUT_MODE  0x8A
+#define BT_PCM_SYNC_MODE  0x8B
+#define FM_I2S_SD_MODE    0x8E
+#define FM_I2S_WS_MODE    0x8F
+#define FM_I2S_SCK_MODE   0x90
+#define I2C_PIN_CTL       0x15
+#define I2C_NORMAL        0x40
+
+static struct platform_device msm_wlan_ar6000_pm_device = {
+	.name           = "wlan_ar6000_pm_dev",
+	.id             = -1,
+};
+
+static struct msm_gpio qup_i2c_gpios_io[] = {
+	{ GPIO_CFG(60, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
+		"qup_scl" },
+	{ GPIO_CFG(61, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
+		"qup_sda" },
+	{ GPIO_CFG(131, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
+		"qup_scl" },
+	{ GPIO_CFG(132, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
+		"qup_sda" },
+};
+
+static struct msm_gpio qup_i2c_gpios_hw[] = {
+	{ GPIO_CFG(60, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
+		"qup_scl" },
+	{ GPIO_CFG(61, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
+		"qup_sda" },
+	{ GPIO_CFG(131, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
+		"qup_scl" },
+	{ GPIO_CFG(132, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
+		"qup_sda" },
+};
+
+static void gsbi_qup_i2c_gpio_config(int adap_id, int config_type)
+{
+	int rc;
+
+	if (adap_id < 0 || adap_id > 1)
+		return;
+
+	/* Each adapter gets 2 lines from the table */
+	if (config_type)
+		rc = msm_gpios_request_enable(&qup_i2c_gpios_hw[adap_id*2], 2);
+	else
+		rc = msm_gpios_request_enable(&qup_i2c_gpios_io[adap_id*2], 2);
+	if (rc < 0)
+		pr_err("QUP GPIO request/enable failed: %d\n", rc);
+}
+
+static struct msm_i2c_platform_data msm_gsbi0_qup_i2c_pdata = {
+	.clk_freq		= 100000,
+	.msm_i2c_config_gpio	= gsbi_qup_i2c_gpio_config,
+};
+
+static struct msm_i2c_platform_data msm_gsbi1_qup_i2c_pdata = {
+	.clk_freq		= 100000,
+	.msm_i2c_config_gpio	= gsbi_qup_i2c_gpio_config,
+};
+
+#ifdef CONFIG_ARCH_MSM7X27A
+#define MSM_PMEM_MDP_SIZE       0x2300000
+#define MSM_PMEM_ADSP_SIZE      0x1100000
+#endif
+
+static struct android_usb_platform_data android_usb_pdata = {
+	.update_pid_and_serial_num = usb_diag_update_pid_and_serial_num,
+};
+
+static struct platform_device android_usb_device = {
+	.name	= "android_usb",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &android_usb_pdata,
+	},
+};
+
+#ifdef CONFIG_USB_EHCI_MSM_72K
+static void msm_hsusb_vbus_power(unsigned phy_info, int on)
+{
+	int rc = 0;
+	unsigned gpio;
+
+	gpio = QRD_GPIO_HOST_VBUS_EN;
+
+	rc = gpio_request(gpio,	"i2c_host_vbus_en");
+	if (rc < 0) {
+		pr_err("failed to request %d GPIO\n", gpio);
+		return;
+	}
+	gpio_direction_output(gpio, !!on);
+	gpio_set_value_cansleep(gpio, !!on);
+	gpio_free(gpio);
+}
+
+static struct msm_usb_host_platform_data msm_usb_host_pdata = {
+	.phy_info       = (USB_PHY_INTEGRATED | USB_PHY_MODEL_45NM),
+};
+
+static void __init msm7627a_init_host(void)
+{
+	msm_add_host(0, &msm_usb_host_pdata);
+}
+#endif
+
+#ifdef CONFIG_USB_MSM_OTG_72K
+static int hsusb_rpc_connect(int connect)
+{
+	if (connect)
+		return msm_hsusb_rpc_connect();
+	else
+		return msm_hsusb_rpc_close();
+}
+
+static struct regulator *reg_hsusb;
+static int msm_hsusb_ldo_init(int init)
+{
+	int rc = 0;
+
+	if (init) {
+		reg_hsusb = regulator_get(NULL, "usb");
+		if (IS_ERR(reg_hsusb)) {
+			rc = PTR_ERR(reg_hsusb);
+			pr_err("%s: could not get regulator: %d\n",
+					__func__, rc);
+			goto out;
+		}
+
+		rc = regulator_set_voltage(reg_hsusb, 3300000, 3300000);
+		if (rc) {
+			pr_err("%s: could not set voltage: %d\n",
+					__func__, rc);
+			goto reg_free;
+		}
+
+		return 0;
+	}
+	/* else fall through */
+reg_free:
+	regulator_put(reg_hsusb);
+out:
+	reg_hsusb = NULL;
+	return rc;
+}
+
+static int msm_hsusb_ldo_enable(int enable)
+{
+	static int ldo_status;
+
+	if (IS_ERR_OR_NULL(reg_hsusb))
+		return reg_hsusb ? PTR_ERR(reg_hsusb) : -ENODEV;
+
+	if (ldo_status == enable)
+		return 0;
+
+	ldo_status = enable;
+
+	return enable ?
+		regulator_enable(reg_hsusb) :
+		regulator_disable(reg_hsusb);
+}
+
+#ifndef CONFIG_USB_EHCI_MSM_72K
+static int msm_hsusb_pmic_notif_init(void (*callback)(int online), int init)
+{
+	int ret = 0;
+
+	if (init)
+		ret = msm_pm_app_rpc_init(callback);
+	else
+		msm_pm_app_rpc_deinit(callback);
+
+	return ret;
+}
+#endif
+
+static struct msm_otg_platform_data msm_otg_pdata = {
+#ifndef CONFIG_USB_EHCI_MSM_72K
+	.pmic_vbus_notif_init	 = msm_hsusb_pmic_notif_init,
+#else
+	.vbus_power		 = msm_hsusb_vbus_power,
+#endif
+	.rpc_connect		 = hsusb_rpc_connect,
+	.pemp_level		 = PRE_EMPHASIS_WITH_20_PERCENT,
+	.cdr_autoreset		 = CDR_AUTO_RESET_DISABLE,
+	.drv_ampl		 = HS_DRV_AMPLITUDE_DEFAULT,
+	.se1_gating		 = SE1_GATING_DISABLE,
+	.ldo_init		 = msm_hsusb_ldo_init,
+	.ldo_enable		 = msm_hsusb_ldo_enable,
+	.chg_init		 = hsusb_chg_init,
+	.chg_connected		 = hsusb_chg_connected,
+	.chg_vbus_draw		 = hsusb_chg_vbus_draw,
+};
+#endif
+
+static struct msm_hsusb_gadget_platform_data msm_gadget_pdata = {
+	.is_phy_status_timer_on = 1,
+};
+
+#ifdef CONFIG_SERIAL_MSM_HS
+static struct msm_serial_hs_platform_data msm_uart_dm1_pdata = {
+	.inject_rx_on_wakeup	= 1,
+	.rx_to_inject		= 0xFD,
+};
+#endif
+static struct msm_pm_platform_data msm7627a_pm_data[MSM_PM_SLEEP_MODE_NR] = {
+	[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 1,
+					.suspend_enabled = 1,
+					.latency = 16000,
+					.residency = 20000,
+	},
+	[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 1,
+					.suspend_enabled = 1,
+					.latency = 12000,
+					.residency = 20000,
+	},
+	[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 0,
+					.suspend_enabled = 1,
+					.latency = 2000,
+					.residency = 0,
+	},
+	[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 1,
+					.suspend_enabled = 1,
+					.latency = 2,
+					.residency = 0,
+	},
+};
+
+static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS,
+	.p_addr = 0,
+};
+
+/* 8625 PM platform data */
+static struct msm_pm_platform_data msm8625_pm_data[MSM_PM_SLEEP_MODE_NR * 2] = {
+	/* CORE0 entries */
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 0,
+					.suspend_enabled = 0,
+					.latency = 16000,
+					.residency = 20000,
+	},
+
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 0,
+					.suspend_enabled = 0,
+					.latency = 12000,
+					.residency = 20000,
+	},
+
+	/* picked latency & redisdency values from 7x30 */
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 0,
+					.suspend_enabled = 0,
+					.latency = 500,
+					.residency = 6000,
+	},
+
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 1,
+					.suspend_enabled = 1,
+					.latency = 2,
+					.residency = 10,
+	},
+
+	/* picked latency & redisdency values from 7x30 */
+	[MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 0,
+					.suspend_enabled = 0,
+					.latency = 500,
+					.residency = 6000,
+	},
+
+	[MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 1,
+					.suspend_enabled = 1,
+					.latency = 2,
+					.residency = 10,
+	},
+
+};
+
+static struct msm_pm_boot_platform_data msm_pm_8625_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR,
+	.v_addr = MSM_CFG_CTL_BASE,
+};
+
+static struct android_pmem_platform_data android_pmem_adsp_pdata = {
+	.name = "pmem_adsp",
+	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
+	.cached = 1,
+	.memory_type = MEMTYPE_EBI1,
+	.request_region = request_fmem_c_region,
+	.release_region = release_fmem_c_region,
+	.reusable = 1,
+};
+
+static struct platform_device android_pmem_adsp_device = {
+	.name = "android_pmem",
+	.id = 1,
+	.dev = { .platform_data = &android_pmem_adsp_pdata },
+};
+
+static unsigned pmem_mdp_size = MSM_PMEM_MDP_SIZE;
+static int __init pmem_mdp_size_setup(char *p)
+{
+	pmem_mdp_size = memparse(p, NULL);
+	return 0;
+}
+
+early_param("pmem_mdp_size", pmem_mdp_size_setup);
+
+static unsigned pmem_adsp_size = MSM_PMEM_ADSP_SIZE;
+static int __init pmem_adsp_size_setup(char *p)
+{
+	pmem_adsp_size = memparse(p, NULL);
+	return 0;
+}
+
+early_param("pmem_adsp_size", pmem_adsp_size_setup);
+
+#define SND(desc, num) { .name = #desc, .id = num }
+static struct snd_endpoint snd_endpoints_list[] = {
+	SND(HANDSET, 0),
+	SND(MONO_HEADSET, 2),
+	SND(HEADSET, 3),
+	SND(SPEAKER, 6),
+	SND(TTY_HEADSET, 8),
+	SND(TTY_VCO, 9),
+	SND(TTY_HCO, 10),
+	SND(BT, 12),
+	SND(IN_S_SADC_OUT_HANDSET, 16),
+	SND(IN_S_SADC_OUT_SPEAKER_PHONE, 25),
+	SND(FM_DIGITAL_STEREO_HEADSET, 26),
+	SND(FM_DIGITAL_SPEAKER_PHONE, 27),
+	SND(FM_DIGITAL_BT_A2DP_HEADSET, 28),
+	SND(STEREO_HEADSET_AND_SPEAKER, 31),
+	SND(CURRENT, 0x7FFFFFFE),
+	SND(FM_ANALOG_STEREO_HEADSET, 35),
+	SND(FM_ANALOG_STEREO_HEADSET_CODEC, 36),
+};
+#undef SND
+
+static struct msm_snd_endpoints msm_device_snd_endpoints = {
+	.endpoints = snd_endpoints_list,
+	.num = sizeof(snd_endpoints_list) / sizeof(struct snd_endpoint)
+};
+
+static struct platform_device msm_device_snd = {
+	.name = "msm_snd",
+	.id = -1,
+	.dev    = {
+		.platform_data = &msm_device_snd_endpoints
+	},
+};
+
+#define DEC0_FORMAT ((1<<MSM_ADSP_CODEC_MP3)| \
+	(1<<MSM_ADSP_CODEC_AAC)|(1<<MSM_ADSP_CODEC_WMA)| \
+	(1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \
+	(1<<MSM_ADSP_CODEC_AMRNB)|(1<<MSM_ADSP_CODEC_WAV)| \
+	(1<<MSM_ADSP_CODEC_ADPCM)|(1<<MSM_ADSP_CODEC_YADPCM)| \
+	(1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP))
+#define DEC1_FORMAT ((1<<MSM_ADSP_CODEC_MP3)| \
+	(1<<MSM_ADSP_CODEC_AAC)|(1<<MSM_ADSP_CODEC_WMA)| \
+	(1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \
+	(1<<MSM_ADSP_CODEC_AMRNB)|(1<<MSM_ADSP_CODEC_WAV)| \
+	(1<<MSM_ADSP_CODEC_ADPCM)|(1<<MSM_ADSP_CODEC_YADPCM)| \
+	(1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP))
+#define DEC2_FORMAT ((1<<MSM_ADSP_CODEC_MP3)| \
+	(1<<MSM_ADSP_CODEC_AAC)|(1<<MSM_ADSP_CODEC_WMA)| \
+	(1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \
+	(1<<MSM_ADSP_CODEC_AMRNB)|(1<<MSM_ADSP_CODEC_WAV)| \
+	(1<<MSM_ADSP_CODEC_ADPCM)|(1<<MSM_ADSP_CODEC_YADPCM)| \
+	(1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP))
+#define DEC3_FORMAT ((1<<MSM_ADSP_CODEC_MP3)| \
+	(1<<MSM_ADSP_CODEC_AAC)|(1<<MSM_ADSP_CODEC_WMA)| \
+	(1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \
+	(1<<MSM_ADSP_CODEC_AMRNB)|(1<<MSM_ADSP_CODEC_WAV)| \
+	(1<<MSM_ADSP_CODEC_ADPCM)|(1<<MSM_ADSP_CODEC_YADPCM)| \
+	(1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP))
+#define DEC4_FORMAT (1<<MSM_ADSP_CODEC_MIDI)
+
+static unsigned int dec_concurrency_table[] = {
+	/* Audio LP */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DMA)), 0,
+	0, 0, 0,
+
+	/* Concurrency 1 */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC4_FORMAT),
+
+	 /* Concurrency 2 */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC4_FORMAT),
+
+	/* Concurrency 3 */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC4_FORMAT),
+
+	/* Concurrency 4 */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC4_FORMAT),
+
+	/* Concurrency 5 */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC4_FORMAT),
+
+	/* Concurrency 6 */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|
+			(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	0, 0, 0, 0,
+
+	/* Concurrency 7 */
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC2_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	(DEC4_FORMAT),
+};
+
+#define DEC_INFO(name, queueid, decid, nr_codec) { .module_name = name, \
+	.module_queueid = queueid, .module_decid = decid, \
+	.nr_codec_support = nr_codec}
+
+static struct msm_adspdec_info dec_info_list[] = {
+	DEC_INFO("AUDPLAY0TASK", 13, 0, 11), /* AudPlay0BitStreamCtrlQueue */
+	DEC_INFO("AUDPLAY1TASK", 14, 1, 11),  /* AudPlay1BitStreamCtrlQueue */
+	DEC_INFO("AUDPLAY2TASK", 15, 2, 11),  /* AudPlay2BitStreamCtrlQueue */
+	DEC_INFO("AUDPLAY3TASK", 16, 3, 11),  /* AudPlay3BitStreamCtrlQueue */
+	DEC_INFO("AUDPLAY4TASK", 17, 4, 1),  /* AudPlay4BitStreamCtrlQueue */
+};
+
+static struct msm_adspdec_database msm_device_adspdec_database = {
+	.num_dec = ARRAY_SIZE(dec_info_list),
+	.num_concurrency_support = (ARRAY_SIZE(dec_concurrency_table) / \
+					ARRAY_SIZE(dec_info_list)),
+	.dec_concurrency_table = dec_concurrency_table,
+	.dec_info_list = dec_info_list,
+};
+
+static struct platform_device msm_device_adspdec = {
+	.name = "msm_adspdec",
+	.id = -1,
+	.dev    = {
+		.platform_data = &msm_device_adspdec_database
+	},
+};
+
+static struct android_pmem_platform_data android_pmem_audio_pdata = {
+	.name = "pmem_audio",
+	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
+	.cached = 0,
+	.memory_type = MEMTYPE_EBI1,
+};
+
+static struct platform_device android_pmem_audio_device = {
+	.name = "android_pmem",
+	.id = 2,
+	.dev = { .platform_data = &android_pmem_audio_pdata },
+};
+
+static struct android_pmem_platform_data android_pmem_pdata = {
+	.name = "pmem",
+	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
+	.cached = 1,
+	.memory_type = MEMTYPE_EBI1,
+};
+static struct platform_device android_pmem_device = {
+	.name = "android_pmem",
+	.id = 0,
+	.dev = { .platform_data = &android_pmem_pdata },
+};
+
+static u32 msm_calculate_batt_capacity(u32 current_voltage);
+
+static struct msm_psy_batt_pdata msm_psy_batt_data = {
+	.voltage_min_design     = 2800,
+	.voltage_max_design     = 4300,
+	.avail_chg_sources      = AC_CHG | USB_CHG ,
+	.batt_technology        = POWER_SUPPLY_TECHNOLOGY_LION,
+	.calculate_capacity     = &msm_calculate_batt_capacity,
+};
+
+static u32 msm_calculate_batt_capacity(u32 current_voltage)
+{
+	u32 low_voltage	 = msm_psy_batt_data.voltage_min_design;
+	u32 high_voltage = msm_psy_batt_data.voltage_max_design;
+
+	return (current_voltage - low_voltage) * 100
+			/ (high_voltage - low_voltage);
+}
+
+static struct platform_device msm_batt_device = {
+	.name               = "msm-battery",
+	.id                 = -1,
+	.dev.platform_data  = &msm_psy_batt_data,
+};
+
+static char *msm_adc_surf_device_names[] = {
+	"XO_ADC",
+};
+
+static struct msm_adc_platform_data msm_adc_pdata = {
+	.dev_names = msm_adc_surf_device_names,
+	.num_adc = ARRAY_SIZE(msm_adc_surf_device_names),
+	.target_hw = MSM_8x25,
+};
+
+static struct platform_device msm_adc_device = {
+	.name   = "msm_adc",
+	.id = -1,
+	.dev = {
+		.platform_data = &msm_adc_pdata,
+	},
+};
+
+static struct fmem_platform_data fmem_pdata;
+
+static struct platform_device fmem_device = {
+	.name = "fmem",
+	.id = 1,
+	.dev = { .platform_data = &fmem_pdata },
+};
+
+static struct platform_device *common_devices[] __initdata = {
+	&android_usb_device,
+	&android_pmem_device,
+	&android_pmem_adsp_device,
+	&android_pmem_audio_device,
+	&msm_batt_device,
+	&msm_device_adspdec,
+	&msm_device_snd,
+	&asoc_msm_pcm,
+	&asoc_msm_dai0,
+	&asoc_msm_dai1,
+	&msm_adc_device,
+	&fmem_device,
+};
+
+static struct platform_device *qrd7627a_devices[] __initdata = {
+	&msm_device_dmov,
+	&msm_device_smd,
+	&msm_device_uart1,
+	&msm_device_uart_dm1,
+	&msm_gsbi0_qup_i2c_device,
+	&msm_gsbi1_qup_i2c_device,
+	&msm_device_otg,
+	&msm_device_gadget_peripheral,
+	&msm_kgsl_3d0,
+};
+
+static struct platform_device *qrd3_devices[] __initdata = {
+	&msm_device_nand,
+};
+
+static struct platform_device *msm8625_evb_devices[] __initdata = {
+	&msm8625_device_dmov,
+	&msm8625_device_smd,
+	&msm8625_gsbi0_qup_i2c_device,
+	&msm8625_gsbi1_qup_i2c_device,
+	&msm8625_device_uart1,
+	&msm8625_device_uart_dm1,
+	&msm8625_device_otg,
+	&msm8625_device_gadget_peripheral,
+	&msm8625_kgsl_3d0,
+};
+
+static unsigned pmem_kernel_ebi1_size = PMEM_KERNEL_EBI1_SIZE;
+static int __init pmem_kernel_ebi1_size_setup(char *p)
+{
+	pmem_kernel_ebi1_size = memparse(p, NULL);
+	return 0;
+}
+early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
+
+static unsigned pmem_audio_size = MSM_PMEM_AUDIO_SIZE;
+static int __init pmem_audio_size_setup(char *p)
+{
+	pmem_audio_size = memparse(p, NULL);
+	return 0;
+}
+early_param("pmem_audio_size", pmem_audio_size_setup);
+
+static struct memtype_reserve msm7627a_reserve_table[] __initdata = {
+	[MEMTYPE_SMI] = {
+	},
+	[MEMTYPE_EBI0] = {
+		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
+	},
+	[MEMTYPE_EBI1] = {
+		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
+	},
+};
+
+#ifdef CONFIG_ANDROID_PMEM
+static struct android_pmem_platform_data *pmem_pdata_array[] __initdata = {
+		&android_pmem_adsp_pdata,
+		&android_pmem_audio_pdata,
+		&android_pmem_pdata,
+};
+#endif
+
+static void __init size_pmem_devices(void)
+{
+#ifdef CONFIG_ANDROID_PMEM
+	unsigned int i;
+	unsigned int reusable_count = 0;
+
+	android_pmem_adsp_pdata.size = pmem_adsp_size;
+	android_pmem_pdata.size = pmem_mdp_size;
+	android_pmem_audio_pdata.size = pmem_audio_size;
+
+	fmem_pdata.size = 0;
+	fmem_pdata.align = PAGE_SIZE;
+
+	/* Find pmem devices that should use FMEM (reusable) memory.
+	 */
+	for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i) {
+		struct android_pmem_platform_data *pdata = pmem_pdata_array[i];
+
+		if (!reusable_count && pdata->reusable)
+			fmem_pdata.size += pdata->size;
+
+		reusable_count += (pdata->reusable) ? 1 : 0;
+
+		if (pdata->reusable && reusable_count > 1) {
+			pr_err("%s: Too many PMEM devices specified as reusable. PMEM device %s was not configured as reusable.\n",
+				__func__, pdata->name);
+			pdata->reusable = 0;
+		}
+	}
+
+#endif
+}
+
+static void __init reserve_memory_for(struct android_pmem_platform_data *p)
+{
+	msm7627a_reserve_table[p->memory_type].size += p->size;
+}
+
+static void __init reserve_pmem_memory(void)
+{
+#ifdef CONFIG_ANDROID_PMEM
+	unsigned int i;
+	for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i)
+		reserve_memory_for(pmem_pdata_array[i]);
+
+	msm7627a_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
+#endif
+}
+
+static void __init msm7627a_calculate_reserve_sizes(void)
+{
+	size_pmem_devices();
+	reserve_pmem_memory();
+}
+
+static int msm7627a_paddr_to_memtype(unsigned int paddr)
+{
+	return MEMTYPE_EBI1;
+}
+
+static struct reserve_info msm7627a_reserve_info __initdata = {
+	.memtype_reserve_table = msm7627a_reserve_table,
+	.calculate_reserve_sizes = msm7627a_calculate_reserve_sizes,
+	.paddr_to_memtype = msm7627a_paddr_to_memtype,
+};
+
+static void __init msm7627a_reserve(void)
+{
+	reserve_info = &msm7627a_reserve_info;
+	msm_reserve();
+	memblock_remove(MSM8625_WARM_BOOT_PHYS, SZ_32);
+}
+
+static void __init msm8625_reserve(void)
+{
+	memblock_remove(MSM8625_SECONDARY_PHYS, SZ_8);
+	msm7627a_reserve();
+}
+
+static void msmqrd_adsp_add_pdev(void)
+{
+	int rc = 0;
+	struct rpc_board_dev *rpc_adsp_pdev;
+
+	rpc_adsp_pdev = kzalloc(sizeof(struct rpc_board_dev), GFP_KERNEL);
+	if (rpc_adsp_pdev == NULL) {
+		pr_err("%s: Memory Allocation failure\n", __func__);
+		return;
+	}
+	rpc_adsp_pdev->prog = ADSP_RPC_PROG;
+
+	if (cpu_is_msm8625())
+		rpc_adsp_pdev->pdev = msm8625_device_adsp;
+	else
+		rpc_adsp_pdev->pdev = msm_adsp_device;
+	rc = msm_rpc_add_board_dev(rpc_adsp_pdev, 1);
+	if (rc < 0) {
+		pr_err("%s: return val: %d\n",	__func__, rc);
+		kfree(rpc_adsp_pdev);
+	}
+}
+
+static void __init msm7627a_device_i2c_init(void)
+{
+	msm_gsbi0_qup_i2c_device.dev.platform_data = &msm_gsbi0_qup_i2c_pdata;
+	msm_gsbi1_qup_i2c_device.dev.platform_data = &msm_gsbi1_qup_i2c_pdata;
+}
+
+static void __init msm8625_device_i2c_init(void)
+{
+	msm8625_gsbi0_qup_i2c_device.dev.platform_data
+					= &msm_gsbi0_qup_i2c_pdata;
+	msm8625_gsbi1_qup_i2c_device.dev.platform_data
+					= &msm_gsbi1_qup_i2c_pdata;
+}
+
+static struct platform_device msm_proccomm_regulator_dev = {
+	.name   = PROCCOMM_REGULATOR_DEV_NAME,
+	.id     = -1,
+	.dev    = {
+		.platform_data = &msm7x27a_proccomm_regulator_data
+	}
+};
+
+static void __init msm7627a_init_regulators(void)
+{
+	int rc = platform_device_register(&msm_proccomm_regulator_dev);
+	if (rc)
+		pr_err("%s: could not register regulator device: %d\n",
+				__func__, rc);
+}
+
+static int __init msm_qrd_init_ar6000pm(void)
+{
+	msm_wlan_ar6000_pm_device.dev.platform_data = &ar600x_wlan_power;
+	return platform_device_register(&msm_wlan_ar6000_pm_device);
+}
+
+static void __init msm_add_footswitch_devices(void)
+{
+	platform_add_devices(msm_footswitch_devices,
+				msm_num_footswitch_devices);
+}
+
+static void __init add_platform_devices(void)
+{
+	if (machine_is_msm8625_evb() || machine_is_msm8625_qrd7()
+				|| machine_is_msm8625_evt()) {
+		platform_add_devices(msm8625_evb_devices,
+				ARRAY_SIZE(msm8625_evb_devices));
+		platform_add_devices(qrd3_devices,
+				ARRAY_SIZE(qrd3_devices));
+	} else {
+		platform_add_devices(qrd7627a_devices,
+				ARRAY_SIZE(qrd7627a_devices));
+	}
+
+	if (machine_is_msm7627a_qrd3() || machine_is_msm7627a_evb())
+		platform_add_devices(qrd3_devices,
+				ARRAY_SIZE(qrd3_devices));
+
+	platform_add_devices(common_devices,
+			ARRAY_SIZE(common_devices));
+}
+
+#define UART1DM_RX_GPIO		45
+static void __init qrd7627a_uart1dm_config(void)
+{
+	msm_uart_dm1_pdata.wakeup_irq = gpio_to_irq(UART1DM_RX_GPIO);
+	if (cpu_is_msm8625())
+		msm8625_device_uart_dm1.dev.platform_data =
+			&msm_uart_dm1_pdata;
+	else
+		msm_device_uart_dm1.dev.platform_data = &msm_uart_dm1_pdata;
+}
+
+static void __init qrd7627a_otg_gadget(void)
+{
+	if (cpu_is_msm8625()) {
+		msm_otg_pdata.swfi_latency = msm8625_pm_data
+		[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].latency;
+		msm8625_device_otg.dev.platform_data = &msm_otg_pdata;
+		msm8625_device_gadget_peripheral.dev.platform_data =
+					&msm_gadget_pdata;
+
+	} else {
+	msm_otg_pdata.swfi_latency = msm7627a_pm_data
+		[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency;
+		msm_device_otg.dev.platform_data = &msm_otg_pdata;
+		msm_device_gadget_peripheral.dev.platform_data =
+					&msm_gadget_pdata;
+	}
+}
+
+static void __init msm_pm_init(void)
+{
+
+	if (!cpu_is_msm8625()) {
+		msm_pm_set_platform_data(msm7627a_pm_data,
+				ARRAY_SIZE(msm7627a_pm_data));
+		BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+	} else {
+		msm_pm_set_platform_data(msm8625_pm_data,
+				ARRAY_SIZE(msm8625_pm_data));
+		BUG_ON(msm_pm_boot_init(&msm_pm_8625_boot_pdata));
+		msm8x25_spm_device_init();
+	}
+}
+
+static void __init msm_qrd_init(void)
+{
+	msm7x2x_misc_init();
+	msm7627a_init_regulators();
+	msmqrd_adsp_add_pdev();
+
+	if (cpu_is_msm8625())
+		msm8625_device_i2c_init();
+	else
+		msm7627a_device_i2c_init();
+
+	/* uart1dm*/
+	qrd7627a_uart1dm_config();
+	/*OTG gadget*/
+	qrd7627a_otg_gadget();
+
+	msm_add_footswitch_devices();
+	add_platform_devices();
+
+	/* Ensure ar6000pm device is registered before MMC/SDC */
+	msm_qrd_init_ar6000pm();
+	msm7627a_init_mmc();
+
+#ifdef CONFIG_USB_EHCI_MSM_72K
+	msm7627a_init_host();
+#endif
+	msm_pm_init();
+
+	msm_pm_register_irqs();
+	msm_fb_add_devices();
+
+#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
+	msm7627a_bt_power_init();
+#endif
+
+	msm7627a_camera_init();
+	qrd7627a_add_io_devices();
+	msm7x25a_kgsl_3d0_init();
+	msm8x25_kgsl_3d0_init();
+}
+
+static void __init qrd7627a_init_early(void)
+{
+	msm_msm7627a_allocate_memory_regions();
+}
+
+MACHINE_START(MSM7627A_QRD1, "QRD MSM7627a QRD1")
+	.atag_offset	= 0x100,
+	.map_io		= msm_common_io_init,
+	.reserve	= msm7627a_reserve,
+	.init_irq	= msm_init_irq,
+	.init_machine	= msm_qrd_init,
+	.timer		= &msm_timer,
+	.init_early	= qrd7627a_init_early,
+	.handle_irq	= vic_handle_irq,
+MACHINE_END
+MACHINE_START(MSM7627A_QRD3, "QRD MSM7627a QRD3")
+	.atag_offset	= 0x100,
+	.map_io		= msm_common_io_init,
+	.reserve	= msm7627a_reserve,
+	.init_irq	= msm_init_irq,
+	.init_machine	= msm_qrd_init,
+	.timer		= &msm_timer,
+	.init_early	= qrd7627a_init_early,
+	.handle_irq	= vic_handle_irq,
+MACHINE_END
+MACHINE_START(MSM7627A_EVB, "QRD MSM7627a EVB")
+	.atag_offset	= 0x100,
+	.map_io		= msm_common_io_init,
+	.reserve	= msm7627a_reserve,
+	.init_irq	= msm_init_irq,
+	.init_machine	= msm_qrd_init,
+	.timer		= &msm_timer,
+	.init_early	= qrd7627a_init_early,
+	.handle_irq	= vic_handle_irq,
+MACHINE_END
+MACHINE_START(MSM8625_EVB, "QRD MSM8625 EVB")
+	.atag_offset	= 0x100,
+	.map_io		= msm8625_map_io,
+	.reserve	= msm8625_reserve,
+	.init_irq	= msm8625_init_irq,
+	.init_machine	= msm_qrd_init,
+	.timer		= &msm_timer,
+	.init_early	= qrd7627a_init_early,
+	.handle_irq	= gic_handle_irq,
+MACHINE_END
+MACHINE_START(MSM8625_QRD7, "QRD MSM8625 QRD7")
+	.atag_offset	= 0x100,
+	.map_io		= msm8625_map_io,
+	.reserve	= msm8625_reserve,
+	.init_irq	= msm8625_init_irq,
+	.init_machine	= msm_qrd_init,
+	.timer		= &msm_timer,
+	.init_early	= qrd7627a_init_early,
+	.handle_irq	= gic_handle_irq,
+MACHINE_END
+MACHINE_START(MSM8625_EVT, "QRD MSM8625 EVT")
+	.atag_offset	= 0x100,
+	.map_io		= msm8625_map_io,
+	.reserve	= msm8625_reserve,
+	.init_irq	= msm8625_init_irq,
+	.init_machine	= msm_qrd_init,
+	.timer		= &msm_timer,
+	.init_early	= qrd7627a_init_early,
+	.handle_irq	= gic_handle_irq,
+MACHINE_END
diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c
index 7e8909c..6a39316 100644
--- a/arch/arm/mach-msm/board-qsd8x50.c
+++ b/arch/arm/mach-msm/board-qsd8x50.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-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
@@ -9,52 +9,260 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
  */
-#include <linux/gpio.h>
+
 #include <linux/kernel.h>
 #include <linux/irq.h>
 #include <linux/gpio.h>
 #include <linux/platform_device.h>
+#include <linux/android_pmem.h>
+#include <linux/bootmem.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
 #include <linux/delay.h>
-#include <linux/usb/msm_hsusb.h>
-#include <linux/err.h>
-#include <linux/clkdev.h>
+#include <linux/bma150.h>
+#include <linux/power_supply.h>
+#include <linux/clk.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/io.h>
 #include <asm/setup.h>
 
-#include <mach/board.h>
-#include <mach/irqs.h>
-#include <mach/sirc.h>
+#include <asm/mach/mmc.h>
 #include <mach/vreg.h>
-#include <mach/mmc.h>
+#include <mach/mpp.h>
+#include <mach/board.h>
+#include <mach/sirc.h>
+#include <mach/dma.h>
+#include <mach/rpc_hsusb.h>
+#include <mach/rpc_pmapp.h>
+#include <mach/msm_hsusb.h>
+#include <mach/msm_serial_hs.h>
+#include <mach/msm_touchpad.h>
+#include <mach/msm_i2ckbd.h>
+#include <mach/pmic.h>
+#include <mach/camera.h>
+#include <mach/memory.h>
+#include <mach/msm_spi.h>
+#include <mach/msm_tsif.h>
+#include <mach/msm_battery.h>
+#include <mach/rpc_server_handset.h>
+#include <mach/socinfo.h>
+#include <mach/proc_comm.h>
 
 #include "devices.h"
+#include "timer.h"
+#include "msm-keypad-devices.h"
+#include "acpuclock.h"
+#include "pm.h"
+#include "irq.h"
+#include "pm-boot.h"
+#ifdef CONFIG_USB_ANDROID
+#include <linux/usb/android_composite.h>
+#endif
 
-extern struct sys_timer msm_timer;
+#define TOUCHPAD_SUSPEND 	34
+#define TOUCHPAD_IRQ 		38
 
-static const resource_size_t qsd8x50_surf_smc91x_base __initdata = 0x70000300;
-static const unsigned        qsd8x50_surf_smc91x_gpio __initdata = 156;
+#define MSM_PMEM_SF_SIZE	0x1700000
 
-/* Leave smc91x resources empty here, as we'll fill them in
- * at run-time: they vary from board to board, and the true
- * configuration won't be known until boot.
- */
+#define SMEM_SPINLOCK_I2C	"S:6"
+
+#define MSM_PMEM_ADSP_SIZE	0x2A05000
+#define MSM_FB_SIZE         0x2EE000
+#define MSM_AUDIO_SIZE		0x80000
+
+#ifdef CONFIG_MSM_SOC_REV_A
+#define MSM_SMI_BASE		0xE0000000
+#else
+#define MSM_SMI_BASE		0x00000000
+#endif
+
+#define MSM_SHARED_RAM_PHYS	(MSM_SMI_BASE + 0x00100000)
+
+#define MSM_PMEM_SMI_BASE	(MSM_SMI_BASE + 0x02B00000)
+#define MSM_PMEM_SMI_SIZE	0x01500000
+
+#define MSM_FB_BASE		MSM_PMEM_SMI_BASE
+#define MSM_PMEM_SMIPOOL_BASE	(MSM_FB_BASE + MSM_FB_SIZE)
+#define MSM_PMEM_SMIPOOL_SIZE	(MSM_PMEM_SMI_SIZE - MSM_FB_SIZE)
+
+#define PMEM_KERNEL_EBI1_SIZE	0x28000
+
+#define PMIC_VREG_WLAN_LEVEL	2600
+#define PMIC_VREG_GP6_LEVEL	2900
+
+#define FPGA_SDCC_STATUS	0x70000280
+
 static struct resource smc91x_resources[] = {
 	[0] = {
-		.flags = IORESOURCE_MEM,
+		.flags  = IORESOURCE_MEM,
 	},
 	[1] = {
-		.flags = IORESOURCE_IRQ,
+		.flags  = IORESOURCE_IRQ,
 	},
 };
 
+#ifdef CONFIG_USB_FUNCTION
+static struct usb_mass_storage_platform_data usb_mass_storage_pdata = {
+	.nluns          = 0x02,
+	.buf_size       = 16384,
+	.vendor         = "GOOGLE",
+	.product        = "Mass storage",
+	.release        = 0xffff,
+};
+
+static struct platform_device mass_storage_device = {
+	.name           = "usb_mass_storage",
+	.id             = -1,
+	.dev            = {
+		.platform_data          = &usb_mass_storage_pdata,
+	},
+};
+#endif
+
+#ifdef CONFIG_USB_ANDROID
+static char *usb_functions_default[] = {
+	"diag",
+	"modem",
+	"nmea",
+	"rmnet",
+	"usb_mass_storage",
+};
+
+static char *usb_functions_default_adb[] = {
+	"diag",
+	"adb",
+	"modem",
+	"nmea",
+	"rmnet",
+	"usb_mass_storage",
+};
+
+static char *usb_functions_rndis[] = {
+	"rndis",
+};
+
+static char *usb_functions_rndis_adb[] = {
+	"rndis",
+	"adb",
+};
+
+static char *usb_functions_all[] = {
+#ifdef CONFIG_USB_ANDROID_RNDIS
+	"rndis",
+#endif
+#ifdef CONFIG_USB_ANDROID_DIAG
+	"diag",
+#endif
+	"adb",
+#ifdef CONFIG_USB_F_SERIAL
+	"modem",
+	"nmea",
+#endif
+#ifdef CONFIG_USB_ANDROID_RMNET
+	"rmnet",
+#endif
+	"usb_mass_storage",
+#ifdef CONFIG_USB_ANDROID_ACM
+	"acm",
+#endif
+};
+
+static struct android_usb_product usb_products[] = {
+	{
+		.product_id	= 0x9026,
+		.num_functions	= ARRAY_SIZE(usb_functions_default),
+		.functions	= usb_functions_default,
+	},
+	{
+		.product_id	= 0x9025,
+		.num_functions	= ARRAY_SIZE(usb_functions_default_adb),
+		.functions	= usb_functions_default_adb,
+	},
+	{
+		.product_id	= 0xf00e,
+		.num_functions	= ARRAY_SIZE(usb_functions_rndis),
+		.functions	= usb_functions_rndis,
+	},
+	{
+		.product_id	= 0x9024,
+		.num_functions	= ARRAY_SIZE(usb_functions_rndis_adb),
+		.functions	= usb_functions_rndis_adb,
+	},
+};
+
+static struct usb_mass_storage_platform_data mass_storage_pdata = {
+	.nluns		= 1,
+	.vendor		= "Qualcomm Incorporated",
+	.product        = "Mass storage",
+	.release	= 0x0100,
+};
+
+static struct platform_device usb_mass_storage_device = {
+	.name	= "usb_mass_storage",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &mass_storage_pdata,
+	},
+};
+
+static struct usb_ether_platform_data rndis_pdata = {
+	/* ethaddr is filled by board_serialno_setup */
+	.vendorID	= 0x05C6,
+	.vendorDescr	= "Qualcomm Incorporated",
+};
+
+static struct platform_device rndis_device = {
+	.name	= "rndis",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &rndis_pdata,
+	},
+};
+
+static struct android_usb_platform_data android_usb_pdata = {
+	.vendor_id	= 0x05C6,
+	.product_id	= 0x9026,
+	.version	= 0x0100,
+	.product_name		= "Qualcomm HSUSB Device",
+	.manufacturer_name	= "Qualcomm Incorporated",
+	.num_products = ARRAY_SIZE(usb_products),
+	.products = usb_products,
+	.num_functions = ARRAY_SIZE(usb_functions_all),
+	.functions = usb_functions_all,
+	.serial_number = "1234567890ABCDEF",
+};
+
+static struct platform_device android_usb_device = {
+	.name	= "android_usb",
+	.id		= -1,
+	.dev		= {
+		.platform_data = &android_usb_pdata,
+	},
+};
+
+static int __init board_serialno_setup(char *serialno)
+{
+	int i;
+	char *src = serialno;
+
+	/* create a fake MAC address from our serial number.
+	 * first byte is 0x02 to signify locally administered.
+	 */
+	rndis_pdata.ethaddr[0] = 0x02;
+	for (i = 0; *src; i++) {
+		/* XOR the USB serial across the remaining bytes */
+		rndis_pdata.ethaddr[i % (ETH_ALEN - 1) + 1] ^= *src++;
+	}
+
+	android_usb_pdata.serial_number = serialno;
+	return 1;
+}
+__setup("androidboot.serialno=", board_serialno_setup);
+#endif
+
 static struct platform_device smc91x_device = {
 	.name           = "smc91x",
 	.id             = 0,
@@ -62,53 +270,1816 @@
 	.resource       = smc91x_resources,
 };
 
-static int __init msm_init_smc91x(void)
+#ifdef CONFIG_USB_FUNCTION
+static struct usb_function_map usb_functions_map[] = {
+	{"diag", 0},
+	{"adb", 1},
+	{"modem", 2},
+	{"nmea", 3},
+	{"mass_storage", 4},
+	{"ethernet", 5},
+};
+
+/* dynamic composition */
+static struct usb_composition usb_func_composition[] = {
+	{
+		.product_id         = 0x9012,
+		.functions	    = 0x5, /* 0101 */
+	},
+
+	{
+		.product_id         = 0x9013,
+		.functions	    = 0x15, /* 10101 */
+	},
+
+	{
+		.product_id         = 0x9014,
+		.functions	    = 0x30, /* 110000 */
+	},
+
+	{
+		.product_id         = 0x9015,
+		.functions	    = 0x12, /* 10010 */
+	},
+
+	{
+		.product_id         = 0x9016,
+		.functions	    = 0xD, /* 01101 */
+	},
+
+	{
+		.product_id         = 0x9017,
+		.functions	    = 0x1D, /* 11101 */
+	},
+
+	{
+		.product_id         = 0xF000,
+		.functions	    = 0x10, /* 10000 */
+	},
+
+	{
+		.product_id         = 0xF009,
+		.functions	    = 0x20, /* 100000 */
+	},
+
+	{
+		.product_id         = 0x9018,
+		.functions	    = 0x1F, /* 011111 */
+	},
+
+	{
+		.product_id         = 0x901A,
+		.functions	    = 0x0F, /* 01111 */
+	},
+};
+#endif
+
+static struct msm_handset_platform_data hs_platform_data = {
+	.hs_name = "8k_handset",
+	.pwr_key_delay_ms = 500, /* 0 will disable end key */
+};
+
+static struct platform_device hs_device = {
+	.name   = "msm-handset",
+	.id     = -1,
+	.dev    = {
+		.platform_data = &hs_platform_data,
+	},
+};
+
+#ifdef CONFIG_USB_FS_HOST
+static struct msm_gpio fsusb_config[] = {
+	{ GPIO_CFG(139, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "fs_dat" },
+	{ GPIO_CFG(140, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "fs_se0" },
+	{ GPIO_CFG(141, 3, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "fs_oe_n" },
+};
+
+static int fsusb_gpio_init(void)
 {
-	if (machine_is_qsd8x50_surf()) {
-		smc91x_resources[0].start = qsd8x50_surf_smc91x_base;
-		smc91x_resources[0].end   = qsd8x50_surf_smc91x_base + 0xff;
-		smc91x_resources[1].start =
-			gpio_to_irq(qsd8x50_surf_smc91x_gpio);
-		smc91x_resources[1].end   =
-			gpio_to_irq(qsd8x50_surf_smc91x_gpio);
-		platform_device_register(&smc91x_device);
+	return msm_gpios_request(fsusb_config, ARRAY_SIZE(fsusb_config));
+}
+
+static void msm_fsusb_setup_gpio(unsigned int enable)
+{
+	if (enable)
+		msm_gpios_enable(fsusb_config, ARRAY_SIZE(fsusb_config));
+	else
+		msm_gpios_disable(fsusb_config, ARRAY_SIZE(fsusb_config));
+
+}
+#endif
+
+#define MSM_USB_BASE              ((unsigned)addr)
+
+static struct msm_hsusb_platform_data msm_hsusb_pdata = {
+#ifdef CONFIG_USB_FUNCTION
+	.version	= 0x0100,
+	.phy_info	= (USB_PHY_INTEGRATED | USB_PHY_MODEL_180NM),
+	.vendor_id          = 0x5c6,
+	.product_name       = "Qualcomm HSUSB Device",
+	.serial_number      = "1234567890ABCDEF",
+	.manufacturer_name  = "Qualcomm Incorporated",
+	.compositions	= usb_func_composition,
+	.num_compositions = ARRAY_SIZE(usb_func_composition),
+	.function_map   = usb_functions_map,
+	.num_functions	= ARRAY_SIZE(usb_functions_map),
+	.config_gpio    = NULL,
+
+#endif
+};
+
+static struct vreg *vreg_usb;
+static void msm_hsusb_vbus_power(unsigned phy_info, int on)
+{
+
+	switch (PHY_TYPE(phy_info)) {
+	case USB_PHY_INTEGRATED:
+		if (on)
+			msm_hsusb_vbus_powerup();
+		else
+			msm_hsusb_vbus_shutdown();
+		break;
+	case USB_PHY_SERIAL_PMIC:
+		if (on)
+			vreg_enable(vreg_usb);
+		else
+			vreg_disable(vreg_usb);
+		break;
+	default:
+		pr_err("%s: undefined phy type ( %X ) \n", __func__,
+						phy_info);
+	}
+
+}
+
+static struct msm_usb_host_platform_data msm_usb_host_pdata = {
+	.phy_info	= (USB_PHY_INTEGRATED | USB_PHY_MODEL_180NM),
+};
+
+#ifdef CONFIG_USB_FS_HOST
+static struct msm_usb_host_platform_data msm_usb_host2_pdata = {
+	.phy_info	= USB_PHY_SERIAL_PMIC,
+	.config_gpio = msm_fsusb_setup_gpio,
+	.vbus_power = msm_hsusb_vbus_power,
+};
+#endif
+
+static struct android_pmem_platform_data android_pmem_kernel_ebi1_pdata = {
+	.name = PMEM_KERNEL_EBI1_DATA_NAME,
+	/* if no allocator_type, defaults to PMEM_ALLOCATORTYPE_BITMAP,
+	 * the only valid choice at this time. The board structure is
+	 * set to all zeros by the C runtime initialization and that is now
+	 * the enum value of PMEM_ALLOCATORTYPE_BITMAP, now forced to 0 in
+	 * include/linux/android_pmem.h.
+	 */
+	.cached = 0,
+};
+
+#ifdef CONFIG_KERNEL_PMEM_SMI_REGION
+
+static struct android_pmem_platform_data android_pmem_kernel_smi_pdata = {
+	.name = PMEM_KERNEL_SMI_DATA_NAME,
+	/* if no allocator_type, defaults to PMEM_ALLOCATORTYPE_BITMAP,
+	 * the only valid choice at this time. The board structure is
+	 * set to all zeros by the C runtime initialization and that is now
+	 * the enum value of PMEM_ALLOCATORTYPE_BITMAP, now forced to 0 in
+	 * include/linux/android_pmem.h.
+	 */
+	.cached = 0,
+};
+
+#endif
+
+static struct android_pmem_platform_data android_pmem_pdata = {
+	.name = "pmem",
+	.allocator_type = PMEM_ALLOCATORTYPE_ALLORNOTHING,
+	.cached = 1,
+};
+
+static struct android_pmem_platform_data android_pmem_adsp_pdata = {
+	.name = "pmem_adsp",
+	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
+	.cached = 0,
+};
+
+static struct android_pmem_platform_data android_pmem_smipool_pdata = {
+	.name = "pmem_smipool",
+	.size = MSM_PMEM_SMIPOOL_SIZE,
+	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
+	.cached = 0,
+};
+
+
+static struct platform_device android_pmem_device = {
+	.name = "android_pmem",
+	.id = 0,
+	.dev = { .platform_data = &android_pmem_pdata },
+};
+
+static struct platform_device android_pmem_adsp_device = {
+	.name = "android_pmem",
+	.id = 1,
+	.dev = { .platform_data = &android_pmem_adsp_pdata },
+};
+
+static struct platform_device android_pmem_smipool_device = {
+	.name = "android_pmem",
+	.id = 2,
+	.dev = { .platform_data = &android_pmem_smipool_pdata },
+};
+
+
+static struct platform_device android_pmem_kernel_ebi1_device = {
+	.name = "android_pmem",
+	.id = 3,
+	.dev = { .platform_data = &android_pmem_kernel_ebi1_pdata },
+};
+
+#ifdef CONFIG_KERNEL_PMEM_SMI_REGION
+static struct platform_device android_pmem_kernel_smi_device = {
+	.name = "android_pmem",
+	.id = 4,
+	.dev = { .platform_data = &android_pmem_kernel_smi_pdata },
+};
+#endif
+
+static struct resource msm_fb_resources[] = {
+	{
+		.flags  = IORESOURCE_DMA,
+	}
+};
+
+static int msm_fb_detect_panel(const char *name)
+{
+	int ret = -EPERM;
+
+	if (machine_is_qsd8x50_ffa()) {
+		if (!strncmp(name, "mddi_toshiba_wvga_pt", 20))
+			ret = 0;
+		else
+			ret = -ENODEV;
+	} else if ((machine_is_qsd8x50_surf())
+			&& !strcmp(name, "lcdc_external"))
+		ret = 0;
+
+	return ret;
+}
+
+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,
+	}
+};
+
+static struct msm_gpio bma_spi_gpio_config_data[] = {
+	{ GPIO_CFG(22, 0, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "bma_irq" },
+};
+
+static int msm_bma_gpio_setup(struct device *dev)
+{
+	int rc;
+
+	rc = msm_gpios_request_enable(bma_spi_gpio_config_data,
+		ARRAY_SIZE(bma_spi_gpio_config_data));
+
+	return rc;
+}
+
+static void msm_bma_gpio_teardown(struct device *dev)
+{
+	msm_gpios_disable_free(bma_spi_gpio_config_data,
+		ARRAY_SIZE(bma_spi_gpio_config_data));
+}
+
+static struct bma150_platform_data bma_pdata = {
+	.setup    = msm_bma_gpio_setup,
+	.teardown = msm_bma_gpio_teardown,
+};
+
+static struct resource qsd_spi_resources[] = {
+	{
+		.name   = "spi_irq_in",
+		.start	= INT_SPI_INPUT,
+		.end	= INT_SPI_INPUT,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name   = "spi_irq_out",
+		.start	= INT_SPI_OUTPUT,
+		.end	= INT_SPI_OUTPUT,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name   = "spi_irq_err",
+		.start	= INT_SPI_ERROR,
+		.end	= INT_SPI_ERROR,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name   = "spi_base",
+		.start	= 0xA1200000,
+		.end	= 0xA1200000 + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "spidm_channels",
+		.flags  = IORESOURCE_DMA,
+	},
+	{
+		.name   = "spidm_crci",
+		.flags  = IORESOURCE_DMA,
+	},
+};
+
+static struct platform_device qsd_device_spi = {
+	.name	        = "spi_qsd",
+	.id	        = 0,
+	.num_resources	= ARRAY_SIZE(qsd_spi_resources),
+	.resource	= qsd_spi_resources,
+};
+
+static struct spi_board_info msm_spi_board_info[] __initdata = {
+	{
+		.modalias	= "bma150",
+		.mode		= SPI_MODE_3,
+		.irq		= MSM_GPIO_TO_INT(22),
+		.bus_num	= 0,
+		.chip_select	= 0,
+		.max_speed_hz	= 10000000,
+		.platform_data	= &bma_pdata,
+	},
+};
+
+#define CT_CSR_PHYS		0xA8700000
+#define TCSR_SPI_MUX		(ct_csr_base + 0x54)
+static int msm_qsd_spi_dma_config(void)
+{
+	void __iomem *ct_csr_base = 0;
+	u32 spi_mux;
+	int ret = 0;
+
+	ct_csr_base = ioremap(CT_CSR_PHYS, PAGE_SIZE);
+	if (!ct_csr_base) {
+		pr_err("%s: Could not remap %x\n", __func__, CT_CSR_PHYS);
+		return -1;
+	}
+
+	spi_mux = readl(TCSR_SPI_MUX);
+	switch (spi_mux) {
+	case (1):
+		qsd_spi_resources[4].start  = DMOV_HSUART1_RX_CHAN;
+		qsd_spi_resources[4].end    = DMOV_HSUART1_TX_CHAN;
+		qsd_spi_resources[5].start  = DMOV_HSUART1_RX_CRCI;
+		qsd_spi_resources[5].end    = DMOV_HSUART1_TX_CRCI;
+		break;
+	case (2):
+		qsd_spi_resources[4].start  = DMOV_HSUART2_RX_CHAN;
+		qsd_spi_resources[4].end    = DMOV_HSUART2_TX_CHAN;
+		qsd_spi_resources[5].start  = DMOV_HSUART2_RX_CRCI;
+		qsd_spi_resources[5].end    = DMOV_HSUART2_TX_CRCI;
+		break;
+	case (3):
+		qsd_spi_resources[4].start  = DMOV_CE_OUT_CHAN;
+		qsd_spi_resources[4].end    = DMOV_CE_IN_CHAN;
+		qsd_spi_resources[5].start  = DMOV_CE_OUT_CRCI;
+		qsd_spi_resources[5].end    = DMOV_CE_IN_CRCI;
+		break;
+	default:
+		ret = -1;
+	}
+
+	iounmap(ct_csr_base);
+	return ret;
+}
+
+static struct msm_gpio qsd_spi_gpio_config_data[] = {
+	{ GPIO_CFG(17, 1, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "spi_clk" },
+	{ GPIO_CFG(18, 1, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "spi_mosi" },
+	{ GPIO_CFG(19, 1, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "spi_miso" },
+	{ GPIO_CFG(20, 1, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA), "spi_cs0" },
+	{ GPIO_CFG(21, 0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_16MA), "spi_pwr" },
+};
+
+static int msm_qsd_spi_gpio_config(void)
+{
+	int rc;
+
+	rc = msm_gpios_request_enable(qsd_spi_gpio_config_data,
+		ARRAY_SIZE(qsd_spi_gpio_config_data));
+	if (rc)
+		return rc;
+
+	/* Set direction for SPI_PWR */
+	gpio_direction_output(21, 1);
+
+	return 0;
+}
+
+static void msm_qsd_spi_gpio_release(void)
+{
+	msm_gpios_disable_free(qsd_spi_gpio_config_data,
+		ARRAY_SIZE(qsd_spi_gpio_config_data));
+}
+
+static struct msm_spi_platform_data qsd_spi_pdata = {
+	.max_clock_speed = 19200000,
+	.gpio_config  = msm_qsd_spi_gpio_config,
+	.gpio_release = msm_qsd_spi_gpio_release,
+	.dma_config = msm_qsd_spi_dma_config,
+};
+
+static void __init msm_qsd_spi_init(void)
+{
+	qsd_device_spi.dev.platform_data = &qsd_spi_pdata;
+}
+
+static int mddi_toshiba_pmic_bl(int level)
+{
+	int ret = -EPERM;
+
+	if (machine_is_qsd8x50_ffa()) {
+		ret = pmic_set_led_intensity(LED_LCD, level);
+
+		if (ret)
+			printk(KERN_WARNING "%s: can't set lcd backlight!\n",
+						__func__);
+	}
+
+	return ret;
+}
+
+static struct msm_panel_common_pdata mddi_toshiba_pdata = {
+	.pmic_backlight = mddi_toshiba_pmic_bl,
+};
+
+static struct platform_device mddi_toshiba_device = {
+	.name   = "mddi_toshiba",
+	.id     = 0,
+	.dev    = {
+		.platform_data = &mddi_toshiba_pdata,
+	}
+};
+
+static void msm_fb_vreg_config(const char *name, int on)
+{
+	struct vreg *vreg;
+	int ret = 0;
+
+	vreg = vreg_get(NULL, name);
+	if (IS_ERR(vreg)) {
+		printk(KERN_ERR "%s: vreg_get(%s) failed (%ld)\n",
+		__func__, name, PTR_ERR(vreg));
+		return;
+	}
+
+	ret = (on) ? vreg_enable(vreg) : vreg_disable(vreg);
+	if (ret)
+		printk(KERN_ERR "%s: %s(%s) failed!\n",
+			__func__, (on) ? "vreg_enable" : "vreg_disable", name);
+}
+
+#define MDDI_RST_OUT_GPIO 100
+
+static int mddi_power_save_on;
+static int msm_fb_mddi_power_save(int on)
+{
+	int flag_on = !!on;
+	int ret = 0;
+
+
+	if (mddi_power_save_on == flag_on)
+		return ret;
+
+	mddi_power_save_on = flag_on;
+
+	if (!flag_on && machine_is_qsd8x50_ffa()) {
+		gpio_set_value(MDDI_RST_OUT_GPIO, 0);
+		mdelay(1);
+	}
+
+	ret = pmic_lp_mode_control(flag_on ? OFF_CMD : ON_CMD,
+		PM_VREG_LP_MSME2_ID);
+	if (ret)
+		printk(KERN_ERR "%s: pmic_lp_mode_control failed!\n", __func__);
+
+	msm_fb_vreg_config("gp5", flag_on);
+	msm_fb_vreg_config("boost", flag_on);
+
+	if (flag_on && machine_is_qsd8x50_ffa()) {
+		gpio_set_value(MDDI_RST_OUT_GPIO, 0);
+		mdelay(1);
+		gpio_set_value(MDDI_RST_OUT_GPIO, 1);
+		gpio_set_value(MDDI_RST_OUT_GPIO, 1);
+		mdelay(1);
+	}
+
+	return ret;
+}
+
+static int msm_fb_mddi_sel_clk(u32 *clk_rate)
+{
+	*clk_rate *= 2;
+	return 0;
+}
+
+static struct mddi_platform_data mddi_pdata = {
+	.mddi_power_save = msm_fb_mddi_power_save,
+	.mddi_sel_clk = msm_fb_mddi_sel_clk,
+};
+
+static struct msm_panel_common_pdata mdp_pdata = {
+	.gpio = 98,
+	.mdp_rev = MDP_REV_31,
+};
+
+static void __init msm_fb_add_devices(void)
+{
+	msm_fb_register_device("mdp", &mdp_pdata);
+	msm_fb_register_device("pmdh", &mddi_pdata);
+	msm_fb_register_device("emdh", &mddi_pdata);
+	msm_fb_register_device("tvenc", 0);
+	msm_fb_register_device("lcdc", 0);
+}
+
+static struct resource msm_audio_resources[] = {
+	{
+		.flags  = IORESOURCE_DMA,
+	},
+	{
+		.name   = "aux_pcm_dout",
+		.start  = 68,
+		.end    = 68,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "aux_pcm_din",
+		.start  = 69,
+		.end    = 69,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "aux_pcm_syncout",
+		.start  = 70,
+		.end    = 70,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "aux_pcm_clkin_a",
+		.start  = 71,
+		.end    = 71,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "sdac_din",
+		.start  = 144,
+		.end    = 144,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "sdac_dout",
+		.start  = 145,
+		.end    = 145,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "sdac_wsout",
+		.start  = 143,
+		.end    = 143,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "cc_i2s_clk",
+		.start  = 142,
+		.end    = 142,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "audio_master_clkout",
+		.start  = 146,
+		.end    = 146,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name	= "audio_base_addr",
+		.start	= 0xa0700000,
+		.end	= 0xa0700000 + 4,
+		.flags	= IORESOURCE_MEM,
+	},
+
+};
+
+static unsigned audio_gpio_on[] = {
+	GPIO_CFG(68, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),	/* PCM_DOUT */
+	GPIO_CFG(69, 1, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA),	/* PCM_DIN */
+	GPIO_CFG(70, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),	/* PCM_SYNC */
+	GPIO_CFG(71, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),	/* PCM_CLK */
+	GPIO_CFG(142, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),	/* CC_I2S_CLK */
+	GPIO_CFG(143, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),	/* SADC_WSOUT */
+	GPIO_CFG(144, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),	/* SADC_DIN */
+	GPIO_CFG(145, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),	/* SDAC_DOUT */
+	GPIO_CFG(146, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),	/* MA_CLK_OUT */
+};
+
+static void __init audio_gpio_init(void)
+{
+	int pin, rc;
+
+	for (pin = 0; pin < ARRAY_SIZE(audio_gpio_on); pin++) {
+		rc = gpio_tlmm_config(audio_gpio_on[pin],
+			GPIO_CFG_ENABLE);
+		if (rc) {
+			printk(KERN_ERR
+				"%s: gpio_tlmm_config(%#x)=%d\n",
+				__func__, audio_gpio_on[pin], rc);
+			return;
+		}
+	}
+}
+
+static struct platform_device msm_audio_device = {
+	.name   = "msm_audio",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_audio_resources),
+	.resource       = msm_audio_resources,
+};
+
+static struct resource bluesleep_resources[] = {
+	{
+		.name	= "gpio_host_wake",
+		.start	= 21,
+		.end	= 21,
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.name	= "gpio_ext_wake",
+		.start	= 19,
+		.end	= 19,
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.name	= "host_wake",
+		.start	= MSM_GPIO_TO_INT(21),
+		.end	= MSM_GPIO_TO_INT(21),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device msm_bluesleep_device = {
+	.name = "bluesleep",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(bluesleep_resources),
+	.resource	= bluesleep_resources,
+};
+
+#ifdef CONFIG_BT
+static struct platform_device msm_bt_power_device = {
+	.name = "bt_power",
+};
+
+enum {
+	BT_SYSRST,
+	BT_WAKE,
+	BT_HOST_WAKE,
+	BT_VDD_IO,
+	BT_RFR,
+	BT_CTS,
+	BT_RX,
+	BT_TX,
+	BT_VDD_FREG
+};
+
+static struct msm_gpio bt_config_power_off[] = {
+	{ GPIO_CFG(18, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+		"BT SYSRST" },
+	{ GPIO_CFG(19, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+		"BT WAKE" },
+	{ GPIO_CFG(21, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+		"HOST WAKE" },
+	{ GPIO_CFG(22, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+		"BT VDD_IO" },
+	{ GPIO_CFG(43, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+		"UART1DM_RFR" },
+	{ GPIO_CFG(44, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+		"UART1DM_CTS" },
+	{ GPIO_CFG(45, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+		"UART1DM_RX" },
+	{ GPIO_CFG(46, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+		"UART1DM_TX" }
+};
+
+static struct msm_gpio bt_config_power_on[] = {
+	{ GPIO_CFG(18, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+		"BT SYSRST" },
+	{ GPIO_CFG(19, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+		"BT WAKE" },
+	{ GPIO_CFG(21, 0, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+		"HOST WAKE" },
+	{ GPIO_CFG(22, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+		"BT VDD_IO" },
+	{ GPIO_CFG(43, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+		"UART1DM_RFR" },
+	{ GPIO_CFG(44, 2, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+		"UART1DM_CTS" },
+	{ GPIO_CFG(45, 2, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+		"UART1DM_RX" },
+	{ GPIO_CFG(46, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+		"UART1DM_TX" }
+};
+
+static struct msm_gpio wlan_config_power_off[] = {
+	{ GPIO_CFG(62, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+		"SDC2_CLK" },
+	{ GPIO_CFG(63, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+		"SDC2_CMD" },
+	{ GPIO_CFG(64, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+		"SDC2_D3" },
+	{ GPIO_CFG(65, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+		"SDC2_D2" },
+	{ GPIO_CFG(66, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+		"SDC2_D1" },
+	{ GPIO_CFG(67, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+		"SDC2_D0" },
+	{ GPIO_CFG(113, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+		"VDD_WLAN" },
+	{ GPIO_CFG(138, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+		"WLAN_PWD" }
+};
+
+static struct msm_gpio wlan_config_power_on[] = {
+	{ GPIO_CFG(62, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+		"SDC2_CLK" },
+	{ GPIO_CFG(63, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+		"SDC2_CMD" },
+	{ GPIO_CFG(64, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+		"SDC2_D3" },
+	{ GPIO_CFG(65, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+		"SDC2_D2" },
+	{ GPIO_CFG(66, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+		"SDC2_D1" },
+	{ GPIO_CFG(67, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+		"SDC2_D0" },
+	{ GPIO_CFG(113, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+		"VDD_WLAN" },
+	{ GPIO_CFG(138, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+		"WLAN_PWD" }
+};
+
+static int bluetooth_power(int on)
+{
+	int rc;
+	struct vreg *vreg_wlan;
+
+	vreg_wlan = vreg_get(NULL, "wlan");
+
+	if (IS_ERR(vreg_wlan)) {
+		printk(KERN_ERR "%s: vreg get failed (%ld)\n",
+		       __func__, PTR_ERR(vreg_wlan));
+		return PTR_ERR(vreg_wlan);
+	}
+
+	if (on) {
+		/* units of mV, steps of 50 mV */
+		rc = vreg_set_level(vreg_wlan, PMIC_VREG_WLAN_LEVEL);
+		if (rc) {
+			printk(KERN_ERR "%s: vreg wlan set level failed (%d)\n",
+			       __func__, rc);
+			return -EIO;
+		}
+		rc = vreg_enable(vreg_wlan);
+		if (rc) {
+			printk(KERN_ERR "%s: vreg wlan enable failed (%d)\n",
+			       __func__, rc);
+			return -EIO;
+		}
+
+		rc = msm_gpios_enable(bt_config_power_on,
+					ARRAY_SIZE(bt_config_power_on));
+		if (rc < 0) {
+			printk(KERN_ERR
+				"%s: bt power on gpio config failed: %d\n",
+				__func__, rc);
+			return rc;
+		}
+
+		if (machine_is_qsd8x50_ffa()) {
+			rc = msm_gpios_enable
+					(wlan_config_power_on,
+					 ARRAY_SIZE(wlan_config_power_on));
+			if (rc < 0) {
+				printk
+				 (KERN_ERR
+				 "%s: wlan power on gpio config failed: %d\n",
+					__func__, rc);
+				return rc;
+			}
+		}
+
+		gpio_set_value(22, on); /* VDD_IO */
+		gpio_set_value(18, on); /* SYSRST */
+
+		if (machine_is_qsd8x50_ffa()) {
+			gpio_set_value(138, 0); /* WLAN: CHIP_PWD */
+			gpio_set_value(113, on); /* WLAN */
+		}
+	} else {
+		if (machine_is_qsd8x50_ffa()) {
+			gpio_set_value(138, on); /* WLAN: CHIP_PWD */
+			gpio_set_value(113, on); /* WLAN */
+		}
+
+		gpio_set_value(18, on); /* SYSRST */
+		gpio_set_value(22, on); /* VDD_IO */
+
+		rc = vreg_disable(vreg_wlan);
+		if (rc) {
+			printk(KERN_ERR "%s: vreg wlan disable failed (%d)\n",
+					__func__, rc);
+			return -EIO;
+		}
+
+		rc = msm_gpios_enable(bt_config_power_off,
+					ARRAY_SIZE(bt_config_power_off));
+		if (rc < 0) {
+			printk(KERN_ERR
+				"%s: bt power off gpio config failed: %d\n",
+				__func__, rc);
+			return rc;
+		}
+
+		if (machine_is_qsd8x50_ffa()) {
+			rc = msm_gpios_enable
+					(wlan_config_power_off,
+					 ARRAY_SIZE(wlan_config_power_off));
+			if (rc < 0) {
+				printk
+				 (KERN_ERR
+				 "%s: wlan power off gpio config failed: %d\n",
+					__func__, rc);
+				return rc;
+			}
+		}
+	}
+
+	printk(KERN_DEBUG "Bluetooth power switch: %d\n", on);
+
+	return 0;
+}
+
+static void __init bt_power_init(void)
+{
+	struct vreg *vreg_bt;
+	int rc;
+
+	if (machine_is_qsd8x50_ffa()) {
+		gpio_set_value(138, 0); /* WLAN: CHIP_PWD */
+		gpio_set_value(113, 0); /* WLAN */
+	}
+
+	gpio_set_value(18, 0); /* SYSRST */
+	gpio_set_value(22, 0); /* VDD_IO */
+
+	/* do not have vreg bt defined, gp6 is the same */
+	/* vreg_get parameter 1 (struct device *) is ignored */
+	vreg_bt = vreg_get(NULL, "gp6");
+
+	if (IS_ERR(vreg_bt)) {
+		printk(KERN_ERR "%s: vreg get failed (%ld)\n",
+		       __func__, PTR_ERR(vreg_bt));
+		goto exit;
+	}
+
+	/* units of mV, steps of 50 mV */
+	rc = vreg_set_level(vreg_bt, PMIC_VREG_GP6_LEVEL);
+	if (rc) {
+		printk(KERN_ERR "%s: vreg bt set level failed (%d)\n",
+		       __func__, rc);
+		goto exit;
+	}
+	rc = vreg_enable(vreg_bt);
+	if (rc) {
+		printk(KERN_ERR "%s: vreg bt enable failed (%d)\n",
+		       __func__, rc);
+		goto exit;
+	}
+
+	if (bluetooth_power(0))
+		goto exit;
+
+	msm_bt_power_device.dev.platform_data = &bluetooth_power;
+
+	printk(KERN_DEBUG "Bluetooth power switch: initialized\n");
+
+exit:
+	return;
+}
+#else
+#define bt_power_init(x) do {} while (0)
+#endif
+
+static struct platform_device msm_device_pmic_leds = {
+	.name	= "pmic-leds",
+	.id	= -1,
+};
+
+/* TSIF begin */
+#if defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE)
+
+#define TSIF_A_SYNC      GPIO_CFG(106, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_A_DATA      GPIO_CFG(107, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_A_EN        GPIO_CFG(108, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_A_CLK       GPIO_CFG(109, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+
+static const struct msm_gpio tsif_gpios[] = {
+	{ .gpio_cfg = TSIF_A_CLK,  .label =  "tsif_clk", },
+	{ .gpio_cfg = TSIF_A_EN,   .label =  "tsif_en", },
+	{ .gpio_cfg = TSIF_A_DATA, .label =  "tsif_data", },
+	{ .gpio_cfg = TSIF_A_SYNC, .label =  "tsif_sync", },
+};
+
+static struct msm_tsif_platform_data tsif_platform_data = {
+	.num_gpios = ARRAY_SIZE(tsif_gpios),
+	.gpios = tsif_gpios,
+	.tsif_clk = "core_clk",
+	.tsif_ref_clk = "ref_clk",
+};
+
+#endif /* defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE) */
+/* TSIF end   */
+
+static void touchpad_gpio_release(void)
+{
+	gpio_free(TOUCHPAD_IRQ);
+	gpio_free(TOUCHPAD_SUSPEND);
+}
+
+static int touchpad_gpio_setup(void)
+{
+	int rc;
+	int suspend_pin = TOUCHPAD_SUSPEND;
+	int irq_pin = TOUCHPAD_IRQ;
+	unsigned suspend_cfg =
+		GPIO_CFG(suspend_pin, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA);
+	unsigned irq_cfg =
+		GPIO_CFG(irq_pin, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA);
+
+	rc = gpio_request(irq_pin, "msm_touchpad_irq");
+	if (rc) {
+		pr_err("gpio_request failed on pin %d (rc=%d)\n",
+		       irq_pin, rc);
+		goto err_gpioconfig;
+	}
+	rc = gpio_request(suspend_pin, "msm_touchpad_suspend");
+	if (rc) {
+		pr_err("gpio_request failed on pin %d (rc=%d)\n",
+		       suspend_pin, rc);
+		goto err_gpioconfig;
+	}
+	rc = gpio_tlmm_config(suspend_cfg, GPIO_CFG_ENABLE);
+	if (rc) {
+		pr_err("gpio_tlmm_config failed on pin %d (rc=%d)\n",
+		       suspend_pin, rc);
+		goto err_gpioconfig;
+	}
+	rc = gpio_tlmm_config(irq_cfg, GPIO_CFG_ENABLE);
+	if (rc) {
+		pr_err("gpio_tlmm_config failed on pin %d (rc=%d)\n",
+		       irq_pin, rc);
+		goto err_gpioconfig;
+	}
+	return rc;
+
+err_gpioconfig:
+	touchpad_gpio_release();
+	return rc;
+}
+
+static struct msm_touchpad_platform_data msm_touchpad_data = {
+	.gpioirq     = TOUCHPAD_IRQ,
+	.gpiosuspend = TOUCHPAD_SUSPEND,
+	.gpio_setup  = touchpad_gpio_setup,
+	.gpio_shutdown = touchpad_gpio_release
+};
+
+#define KBD_RST 35
+#define KBD_IRQ 36
+
+static void kbd_gpio_release(void)
+{
+	gpio_free(KBD_IRQ);
+	gpio_free(KBD_RST);
+}
+
+static int kbd_gpio_setup(void)
+{
+	int rc;
+	int respin = KBD_RST;
+	int irqpin = KBD_IRQ;
+	unsigned rescfg =
+		GPIO_CFG(respin, 0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA);
+	unsigned irqcfg =
+		GPIO_CFG(irqpin, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA);
+
+	rc = gpio_request(irqpin, "gpio_keybd_irq");
+	if (rc) {
+		pr_err("gpio_request failed on pin %d (rc=%d)\n",
+			irqpin, rc);
+		goto err_gpioconfig;
+	}
+	rc = gpio_request(respin, "gpio_keybd_reset");
+	if (rc) {
+		pr_err("gpio_request failed on pin %d (rc=%d)\n",
+			respin, rc);
+		goto err_gpioconfig;
+	}
+	rc = gpio_tlmm_config(rescfg, GPIO_CFG_ENABLE);
+	if (rc) {
+		pr_err("gpio_tlmm_config failed on pin %d (rc=%d)\n",
+			respin, rc);
+		goto err_gpioconfig;
+	}
+	rc = gpio_tlmm_config(irqcfg, GPIO_CFG_ENABLE);
+	if (rc) {
+		pr_err("gpio_tlmm_config failed on pin %d (rc=%d)\n",
+			irqpin, rc);
+		goto err_gpioconfig;
+	}
+	return rc;
+
+err_gpioconfig:
+	kbd_gpio_release();
+	return rc;
+}
+
+/* use gpio output pin to toggle keyboard external reset pin */
+static void kbd_hwreset(int kbd_mclrpin)
+{
+	gpio_direction_output(kbd_mclrpin, 0);
+	gpio_direction_output(kbd_mclrpin, 1);
+}
+
+static struct msm_i2ckbd_platform_data msm_kybd_data = {
+	.hwrepeat = 0,
+	.scanset1 = 1,
+	.gpioreset = KBD_RST,
+	.gpioirq = KBD_IRQ,
+	.gpio_setup = kbd_gpio_setup,
+	.gpio_shutdown = kbd_gpio_release,
+	.hw_reset = kbd_hwreset,
+};
+
+static struct i2c_board_info msm_i2c_board_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("glidesensor", 0x2A),
+		.irq           =  MSM_GPIO_TO_INT(TOUCHPAD_IRQ),
+		.platform_data = &msm_touchpad_data
+	},
+	{
+		I2C_BOARD_INFO("msm-i2ckbd", 0x3A),
+		.type           = "msm-i2ckbd",
+		.irq           =  MSM_GPIO_TO_INT(KBD_IRQ),
+		.platform_data  = &msm_kybd_data
+	},
+#ifdef CONFIG_MT9D112
+	{
+		I2C_BOARD_INFO("mt9d112", 0x78 >> 1),
+	},
+#endif
+#ifdef CONFIG_S5K3E2FX
+	{
+		I2C_BOARD_INFO("s5k3e2fx", 0x20 >> 1),
+	},
+#endif
+#ifdef CONFIG_MT9P012
+	{
+		I2C_BOARD_INFO("mt9p012", 0x6C >> 1),
+	},
+#endif
+#ifdef CONFIG_MT9P012_KM
+	{
+		I2C_BOARD_INFO("mt9p012_km", 0x6C >> 2),
+	},
+#endif
+#if defined(CONFIG_MT9T013) || defined(CONFIG_SENSORS_MT9T013)
+	{
+		I2C_BOARD_INFO("mt9t013", 0x6C),
+	},
+#endif
+	{
+		I2C_BOARD_INFO("tps65023", 0x48),
+	},
+};
+
+#ifdef CONFIG_MSM_CAMERA
+static uint32_t camera_off_gpio_table[] = {
+	/* parallel CAMERA interfaces */
+	GPIO_CFG(0,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT0 */
+	GPIO_CFG(1,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT1 */
+	GPIO_CFG(2,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT2 */
+	GPIO_CFG(3,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT3 */
+	GPIO_CFG(4,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT4 */
+	GPIO_CFG(5,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT5 */
+	GPIO_CFG(6,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT6 */
+	GPIO_CFG(7,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT7 */
+	GPIO_CFG(8,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT8 */
+	GPIO_CFG(9,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT9 */
+	GPIO_CFG(10, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT10 */
+	GPIO_CFG(11, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT11 */
+	GPIO_CFG(12, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* PCLK */
+	GPIO_CFG(13, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* HSYNC_IN */
+	GPIO_CFG(14, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* VSYNC_IN */
+	GPIO_CFG(15, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA), /* MCLK */
+};
+
+static uint32_t camera_on_gpio_table[] = {
+	/* parallel CAMERA interfaces */
+	GPIO_CFG(0,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT0 */
+	GPIO_CFG(1,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT1 */
+	GPIO_CFG(2,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT2 */
+	GPIO_CFG(3,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT3 */
+	GPIO_CFG(4,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT4 */
+	GPIO_CFG(5,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT5 */
+	GPIO_CFG(6,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT6 */
+	GPIO_CFG(7,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT7 */
+	GPIO_CFG(8,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT8 */
+	GPIO_CFG(9,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT9 */
+	GPIO_CFG(10, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT10 */
+	GPIO_CFG(11, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* DAT11 */
+	GPIO_CFG(12, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* PCLK */
+	GPIO_CFG(13, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* HSYNC_IN */
+	GPIO_CFG(14, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), /* VSYNC_IN */
+	GPIO_CFG(15, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_16MA), /* MCLK */
+};
+
+static uint32_t camera_on_gpio_ffa_table[] = {
+	/* parallel CAMERA interfaces */
+	GPIO_CFG(95,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_16MA), /* I2C_SCL */
+	GPIO_CFG(96,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_16MA), /* I2C_SDA */
+	/* FFA front Sensor Reset */
+	GPIO_CFG(137,  1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_16MA),
+};
+
+static uint32_t camera_off_gpio_ffa_table[] = {
+	/* FFA front Sensor Reset */
+	GPIO_CFG(137,  0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_16MA),
+};
+
+static void config_gpio_table(uint32_t *table, int len)
+{
+	int n, rc;
+	for (n = 0; n < len; n++) {
+		rc = gpio_tlmm_config(table[n], GPIO_CFG_ENABLE);
+		if (rc) {
+			printk(KERN_ERR "%s: gpio_tlmm_config(%#x)=%d\n",
+				__func__, table[n], rc);
+			break;
+		}
+	}
+}
+
+static struct vreg *vreg_gp2;
+static struct vreg *vreg_gp3;
+
+static void msm_camera_vreg_config(int vreg_en)
+{
+	int rc;
+
+	if (vreg_gp2 == NULL) {
+		vreg_gp2 = vreg_get(NULL, "gp2");
+		if (IS_ERR(vreg_gp2)) {
+			printk(KERN_ERR "%s: vreg_get(%s) failed (%ld)\n",
+				__func__, "gp2", PTR_ERR(vreg_gp2));
+			return;
+		}
+
+		rc = vreg_set_level(vreg_gp2, 1800);
+		if (rc) {
+			printk(KERN_ERR "%s: GP2 set_level failed (%d)\n",
+				__func__, rc);
+		}
+	}
+
+	if (vreg_gp3 == NULL) {
+		vreg_gp3 = vreg_get(NULL, "gp3");
+		if (IS_ERR(vreg_gp3)) {
+			printk(KERN_ERR "%s: vreg_get(%s) failed (%ld)\n",
+				__func__, "gp3", PTR_ERR(vreg_gp3));
+			return;
+		}
+
+		rc = vreg_set_level(vreg_gp3, 2800);
+		if (rc) {
+			printk(KERN_ERR "%s: GP3 set level failed (%d)\n",
+				__func__, rc);
+		}
+	}
+
+	if (vreg_en) {
+		rc = vreg_enable(vreg_gp2);
+		if (rc) {
+			printk(KERN_ERR "%s: GP2 enable failed (%d)\n",
+				 __func__, rc);
+		}
+
+		rc = vreg_enable(vreg_gp3);
+		if (rc) {
+			printk(KERN_ERR "%s: GP3 enable failed (%d)\n",
+				__func__, rc);
+		}
+	} else {
+		rc = vreg_disable(vreg_gp2);
+		if (rc) {
+			printk(KERN_ERR "%s: GP2 disable failed (%d)\n",
+				 __func__, rc);
+		}
+
+		rc = vreg_disable(vreg_gp3);
+		if (rc) {
+			printk(KERN_ERR "%s: GP3 disable failed (%d)\n",
+				__func__, rc);
+		}
+	}
+}
+
+static int config_camera_on_gpios(void)
+{
+	int vreg_en = 1;
+
+	if (machine_is_qsd8x50_ffa()) {
+		config_gpio_table(camera_on_gpio_ffa_table,
+		ARRAY_SIZE(camera_on_gpio_ffa_table));
+
+		msm_camera_vreg_config(vreg_en);
+		gpio_set_value(137, 0);
+	}
+	config_gpio_table(camera_on_gpio_table,
+		ARRAY_SIZE(camera_on_gpio_table));
+	return 0;
+}
+
+static void config_camera_off_gpios(void)
+{
+	int vreg_en = 0;
+
+	if (machine_is_qsd8x50_ffa()) {
+		config_gpio_table(camera_off_gpio_ffa_table,
+		ARRAY_SIZE(camera_off_gpio_ffa_table));
+
+		msm_camera_vreg_config(vreg_en);
+	}
+	config_gpio_table(camera_off_gpio_table,
+		ARRAY_SIZE(camera_off_gpio_table));
+}
+
+static struct resource msm_camera_resources[] = {
+	{
+		.start	= 0xA0F00000,
+		.end	= 0xA0F00000 + SZ_1M - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_VFE,
+		.end	= INT_VFE,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct msm_camera_device_platform_data msm_camera_device_data = {
+	.camera_gpio_on  = config_camera_on_gpios,
+	.camera_gpio_off = config_camera_off_gpios,
+	.ioext.mdcphy = MSM_MDC_PHYS,
+	.ioext.mdcsz  = MSM_MDC_SIZE,
+	.ioext.appphy = MSM_CLK_CTL_PHYS,
+	.ioext.appsz  = MSM_CLK_CTL_SIZE,
+};
+
+int pmic_set_flash_led_current(enum pmic8058_leds id, unsigned mA)
+{
+	int rc;
+	rc = pmic_flash_led_set_current(mA);
+	return rc;
+}
+static struct msm_camera_sensor_flash_src msm_flash_src = {
+	.flash_sr_type = MSM_CAMERA_FLASH_SRC_PMIC,
+	._fsrc.pmic_src.num_of_src = 1,
+	._fsrc.pmic_src.low_current  = 30,
+	._fsrc.pmic_src.high_current = 100,
+	._fsrc.pmic_src.led_src_1 = 0,
+	._fsrc.pmic_src.led_src_2 = 0,
+	._fsrc.pmic_src.pmic_set_current = pmic_set_flash_led_current,
+};
+
+#ifdef CONFIG_MT9D112
+static struct msm_camera_sensor_flash_data flash_mt9d112 = {
+	.flash_type = MSM_CAMERA_FLASH_LED,
+	.flash_src  = &msm_flash_src
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_mt9d112_data = {
+	.sensor_name    = "mt9d112",
+	.sensor_reset   = 17,
+	.sensor_pwd     = 85,
+	.vcm_pwd        = 0,
+	.vcm_enable     = 0,
+	.pdata          = &msm_camera_device_data,
+	.resource       = msm_camera_resources,
+	.num_resources  = ARRAY_SIZE(msm_camera_resources),
+	.flash_data     = &flash_mt9d112
+};
+
+static struct platform_device msm_camera_sensor_mt9d112 = {
+	.name      = "msm_camera_mt9d112",
+	.dev       = {
+		.platform_data = &msm_camera_sensor_mt9d112_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_S5K3E2FX
+static struct msm_camera_sensor_flash_data flash_s5k3e2fx = {
+	.flash_type = MSM_CAMERA_FLASH_LED,
+	.flash_src  = &msm_flash_src
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_s5k3e2fx_data = {
+	.sensor_name    = "s5k3e2fx",
+	.sensor_reset   = 17,
+	.sensor_pwd     = 85,
+	/*.vcm_pwd = 31, */  /* CAM1_VCM_EN, enabled in a9 */
+	.vcm_enable     = 0,
+	.pdata          = &msm_camera_device_data,
+	.resource       = msm_camera_resources,
+	.num_resources  = ARRAY_SIZE(msm_camera_resources),
+	.flash_data     = &flash_s5k3e2fx
+};
+
+static struct platform_device msm_camera_sensor_s5k3e2fx = {
+	.name      = "msm_camera_s5k3e2fx",
+	.dev       = {
+		.platform_data = &msm_camera_sensor_s5k3e2fx_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_MT9P012
+static struct msm_camera_sensor_flash_data flash_mt9p012 = {
+	.flash_type = MSM_CAMERA_FLASH_LED,
+	.flash_src  = &msm_flash_src
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_mt9p012_data = {
+	.sensor_name    = "mt9p012",
+	.sensor_reset   = 17,
+	.sensor_pwd     = 85,
+	.vcm_pwd        = 88,
+	.vcm_enable     = 0,
+	.pdata          = &msm_camera_device_data,
+	.resource       = msm_camera_resources,
+	.num_resources  = ARRAY_SIZE(msm_camera_resources),
+	.flash_data     = &flash_mt9p012
+};
+
+static struct platform_device msm_camera_sensor_mt9p012 = {
+	.name      = "msm_camera_mt9p012",
+	.dev       = {
+		.platform_data = &msm_camera_sensor_mt9p012_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_MT9P012_KM
+static struct msm_camera_sensor_flash_data flash_mt9p012_km = {
+	.flash_type = MSM_CAMERA_FLASH_LED,
+	.flash_src  = &msm_flash_src
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_mt9p012_km_data = {
+	.sensor_name    = "mt9p012_km",
+	.sensor_reset   = 17,
+	.sensor_pwd     = 85,
+	.vcm_pwd        = 88,
+	.vcm_enable     = 0,
+	.pdata          = &msm_camera_device_data,
+	.resource       = msm_camera_resources,
+	.num_resources  = ARRAY_SIZE(msm_camera_resources),
+	.flash_data     = &flash_mt9p012_km
+};
+
+static struct platform_device msm_camera_sensor_mt9p012_km = {
+	.name      = "msm_camera_mt9p012_km",
+	.dev       = {
+		.platform_data = &msm_camera_sensor_mt9p012_km_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_MT9T013
+static struct msm_camera_sensor_flash_data flash_mt9t013 = {
+	.flash_type = MSM_CAMERA_FLASH_LED,
+	.flash_src  = &msm_flash_src
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_mt9t013_data = {
+	.sensor_name    = "mt9t013",
+	.sensor_reset   = 17,
+	.sensor_pwd     = 85,
+	.vcm_pwd        = 0,
+	.vcm_enable     = 0,
+	.pdata          = &msm_camera_device_data,
+	.resource       = msm_camera_resources,
+	.num_resources  = ARRAY_SIZE(msm_camera_resources),
+	.flash_data     = &flash_mt9t013
+};
+
+static struct platform_device msm_camera_sensor_mt9t013 = {
+	.name      = "msm_camera_mt9t013",
+	.dev       = {
+		.platform_data = &msm_camera_sensor_mt9t013_data,
+	},
+};
+#endif
+#endif /*CONFIG_MSM_CAMERA*/
+
+static u32 msm_calculate_batt_capacity(u32 current_voltage);
+
+static struct msm_psy_batt_pdata msm_psy_batt_data = {
+	.voltage_min_design 	= 3200,
+	.voltage_max_design	= 4200,
+	.avail_chg_sources   	= AC_CHG | USB_CHG ,
+	.batt_technology        = POWER_SUPPLY_TECHNOLOGY_LION,
+	.calculate_capacity	= &msm_calculate_batt_capacity,
+};
+
+static u32 msm_calculate_batt_capacity(u32 current_voltage)
+{
+	u32 low_voltage   = msm_psy_batt_data.voltage_min_design;
+	u32 high_voltage  = msm_psy_batt_data.voltage_max_design;
+
+	return (current_voltage - low_voltage) * 100
+		/ (high_voltage - low_voltage);
+}
+
+static struct platform_device msm_batt_device = {
+	.name 		    = "msm-battery",
+	.id		    = -1,
+	.dev.platform_data  = &msm_psy_batt_data,
+};
+
+static int hsusb_rpc_connect(int connect)
+{
+	if (connect)
+		return msm_hsusb_rpc_connect();
+	else
+		return msm_hsusb_rpc_close();
+}
+
+static int msm_hsusb_pmic_notif_init(void (*callback)(int online), int init)
+{
+	int ret;
+
+	if (init) {
+		ret = msm_pm_app_rpc_init(callback);
+	} else {
+		msm_pm_app_rpc_deinit(callback);
+		ret = 0;
+	}
+	return ret;
+}
+static int msm_hsusb_ldo_init(int init);
+static int msm_hsusb_ldo_enable(int enable);
+
+static struct msm_otg_platform_data msm_otg_pdata = {
+	.rpc_connect	= hsusb_rpc_connect,
+	.pmic_vbus_notif_init         = msm_hsusb_pmic_notif_init,
+	.pemp_level              = PRE_EMPHASIS_WITH_10_PERCENT,
+	.cdr_autoreset           = CDR_AUTO_RESET_DEFAULT,
+	.drv_ampl                = HS_DRV_AMPLITUDE_5_PERCENT,
+	.vbus_power		 = msm_hsusb_vbus_power,
+	.chg_vbus_draw		 = hsusb_chg_vbus_draw,
+	.chg_connected		 = hsusb_chg_connected,
+	.chg_init		 = hsusb_chg_init,
+	.phy_can_powercollapse	 = 1,
+	.ldo_init		 = msm_hsusb_ldo_init,
+	.ldo_enable		 = msm_hsusb_ldo_enable,
+};
+
+static struct msm_hsusb_gadget_platform_data msm_gadget_pdata;
+
+static struct platform_device *devices[] __initdata = {
+	&msm_fb_device,
+	&mddi_toshiba_device,
+	&smc91x_device,
+	&msm_device_smd,
+	&msm_device_dmov,
+	&android_pmem_kernel_ebi1_device,
+#ifdef CONFIG_KERNEL_PMEM_SMI_REGION
+	&android_pmem_kernel_smi_device,
+#endif
+	&android_pmem_device,
+	&android_pmem_adsp_device,
+	&android_pmem_smipool_device,
+	&msm_device_nand,
+	&msm_device_i2c,
+	&qsd_device_spi,
+#ifdef CONFIG_USB_FUNCTION
+	&mass_storage_device,
+#endif
+#ifdef CONFIG_USB_ANDROID
+	&usb_mass_storage_device,
+	&rndis_device,
+#ifdef CONFIG_USB_ANDROID_DIAG
+	&usb_diag_device,
+#endif
+#ifdef CONFIG_USB_F_SERIAL
+	&usb_gadget_fserial_device,
+#endif
+	&android_usb_device,
+#endif
+	&msm_device_tssc,
+	&msm_audio_device,
+	&msm_device_uart_dm1,
+	&msm_bluesleep_device,
+#ifdef CONFIG_BT
+	&msm_bt_power_device,
+#endif
+#if !defined(CONFIG_MSM_SERIAL_DEBUGGER)
+	&msm_device_uart3,
+#endif
+	&msm_device_pmic_leds,
+	&msm_kgsl_3d0,
+	&hs_device,
+#if defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE)
+	&msm_device_tsif,
+#endif
+#ifdef CONFIG_MT9T013
+	&msm_camera_sensor_mt9t013,
+#endif
+#ifdef CONFIG_MT9D112
+	&msm_camera_sensor_mt9d112,
+#endif
+#ifdef CONFIG_S5K3E2FX
+	&msm_camera_sensor_s5k3e2fx,
+#endif
+#ifdef CONFIG_MT9P012
+	&msm_camera_sensor_mt9p012,
+#endif
+#ifdef CONFIG_MT9P012_KM
+	&msm_camera_sensor_mt9p012_km,
+#endif
+	&msm_batt_device,
+};
+
+static void __init qsd8x50_init_irq(void)
+{
+	msm_init_irq();
+	msm_init_sirc();
+}
+
+static void usb_mpp_init(void)
+{
+	unsigned rc;
+	unsigned mpp_usb = 20;
+
+	if (machine_is_qsd8x50_ffa()) {
+		rc = mpp_config_digital_out(mpp_usb,
+			MPP_CFG(MPP_DLOGIC_LVL_VDD,
+				MPP_DLOGIC_OUT_CTRL_HIGH));
+		if (rc)
+			pr_err("%s: configuring mpp pin"
+				"to enable 3.3V LDO failed\n", __func__);
+	}
+}
+
+/* TBD: 8x50 FFAs have internal 3p3 voltage regulator as opposed to
+ * external 3p3 voltage regulator on Surf platform. There is no way
+ * s/w can detect fi concerned regulator is internal or external to
+ * to MSM. Internal 3p3 regulator is powered through boost voltage
+ * regulator where as external 3p3 regulator is powered through VPH.
+ * So for internal voltage regulator it is required to power on
+ * boost voltage regulator first. Unfortunately some of the FFAs are
+ * re-worked to install external 3p3 regulator. For now, assuming all
+ * FFAs have 3p3 internal regulators and all SURFs have external 3p3
+ * regulator as there is no way s/w can determine if theregulator is
+ * internal or external. May be, we can implement this flag as kernel
+ * boot parameters so that we can change code behaviour dynamically
+ */
+static int regulator_3p3_is_internal;
+static struct vreg *vreg_5v;
+static struct vreg *vreg_3p3;
+static int msm_hsusb_ldo_init(int init)
+{
+	if (init) {
+		if (regulator_3p3_is_internal) {
+			vreg_5v = vreg_get(NULL, "boost");
+			if (IS_ERR(vreg_5v))
+				return PTR_ERR(vreg_5v);
+			vreg_set_level(vreg_5v, 5000);
+		}
+
+		vreg_3p3 = vreg_get(NULL, "usb");
+		if (IS_ERR(vreg_3p3))
+			return PTR_ERR(vreg_3p3);
+		vreg_set_level(vreg_3p3, 3300);
+	} else {
+		if (regulator_3p3_is_internal)
+			vreg_put(vreg_5v);
+		vreg_put(vreg_3p3);
 	}
 
 	return 0;
 }
-module_init(msm_init_smc91x);
 
-static int hsusb_phy_init_seq[] = {
-	0x08, 0x31,	/* Increase HS Driver Amplitude */
-	0x20, 0x32,	/* Enable and set Pre-Emphasis Depth to 10% */
-	-1
-};
+static int msm_hsusb_ldo_enable(int enable)
+{
+	static int ldo_status;
+	int ret;
 
-static struct msm_otg_platform_data msm_otg_pdata = {
-	.phy_init_seq		= hsusb_phy_init_seq,
-	.mode                   = USB_PERIPHERAL,
-	.otg_control		= OTG_PHY_CONTROL,
-};
+	if (ldo_status == enable)
+		return 0;
 
-static struct platform_device *devices[] __initdata = {
-	&msm_device_uart3,
-	&msm_device_smd,
-	&msm_device_otg,
-	&msm_device_hsusb,
-	&msm_device_hsusb_host,
-};
+	if (regulator_3p3_is_internal && (!vreg_5v || IS_ERR(vreg_5v)))
+		return -ENODEV;
+	if (!vreg_3p3 || IS_ERR(vreg_3p3))
+		return -ENODEV;
 
-static struct msm_mmc_gpio sdc1_gpio_cfg[] = {
-	{51, "sdc1_dat_3"},
-	{52, "sdc1_dat_2"},
-	{53, "sdc1_dat_1"},
-	{54, "sdc1_dat_0"},
-	{55, "sdc1_cmd"},
-	{56, "sdc1_clk"}
-};
+	ldo_status = enable;
+
+	if (enable) {
+		if (regulator_3p3_is_internal) {
+			ret = vreg_enable(vreg_5v);
+			if (ret)
+				return ret;
+
+			/* power supply to 3p3 regulator can vary from
+			 * USB VBUS or VREG 5V. If the power supply is
+			 * USB VBUS cable disconnection cannot be
+			 * deteted. Select power supply to VREG 5V
+			 */
+			/* TBD: comeup with a better name */
+			ret = pmic_vote_3p3_pwr_sel_switch(1);
+			if (ret)
+				return ret;
+		}
+		ret = vreg_enable(vreg_3p3);
+
+		return ret;
+	} else {
+		if (regulator_3p3_is_internal) {
+			ret = vreg_disable(vreg_5v);
+			if (ret)
+				return ret;
+			ret = pmic_vote_3p3_pwr_sel_switch(0);
+			if (ret)
+				return ret;
+		}
+			ret = vreg_disable(vreg_3p3);
+
+			return ret;
+	}
+}
+
+static void __init qsd8x50_init_usb(void)
+{
+	usb_mpp_init();
+
+	if (machine_is_qsd8x50_ffa())
+		regulator_3p3_is_internal = 1;
+
+#ifdef CONFIG_USB_MSM_OTG_72K
+	platform_device_register(&msm_device_otg);
+#endif
+
+#ifdef CONFIG_USB_FUNCTION_MSM_HSUSB
+	platform_device_register(&msm_device_hsusb_peripheral);
+#endif
+
+#ifdef CONFIG_USB_MSM_72K
+	platform_device_register(&msm_device_gadget_peripheral);
+#endif
+
+	if (machine_is_qsd8x50_ffa())
+		return;
+
+	vreg_usb = vreg_get(NULL, "boost");
+
+	if (IS_ERR(vreg_usb)) {
+		printk(KERN_ERR "%s: vreg get failed (%ld)\n",
+		       __func__, PTR_ERR(vreg_usb));
+		return;
+	}
+
+	platform_device_register(&msm_device_hsusb_otg);
+	msm_add_host(0, &msm_usb_host_pdata);
+#ifdef CONFIG_USB_FS_HOST
+	if (fsusb_gpio_init())
+		return;
+	msm_add_host(1, &msm_usb_host2_pdata);
+#endif
+}
 
 static struct vreg *vreg_mmc;
-static unsigned long vreg_sts;
+
+#if (defined(CONFIG_MMC_MSM_SDC1_SUPPORT)\
+	|| defined(CONFIG_MMC_MSM_SDC2_SUPPORT)\
+	|| defined(CONFIG_MMC_MSM_SDC3_SUPPORT)\
+	|| defined(CONFIG_MMC_MSM_SDC4_SUPPORT))
+
+struct sdcc_gpio {
+	struct msm_gpio *cfg_data;
+	uint32_t size;
+};
+
+static struct msm_gpio sdc1_cfg_data[] = {
+	{GPIO_CFG(51, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc1_dat_3"},
+	{GPIO_CFG(52, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc1_dat_2"},
+	{GPIO_CFG(53, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc1_dat_1"},
+	{GPIO_CFG(54, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc1_dat_0"},
+	{GPIO_CFG(55, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc1_cmd"},
+	{GPIO_CFG(56, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), "sdc1_clk"},
+};
+
+static struct msm_gpio sdc2_cfg_data[] = {
+	{GPIO_CFG(62, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), "sdc2_clk"},
+	{GPIO_CFG(63, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc2_cmd"},
+	{GPIO_CFG(64, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc2_dat_3"},
+	{GPIO_CFG(65, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc2_dat_2"},
+	{GPIO_CFG(66, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc2_dat_1"},
+	{GPIO_CFG(67, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc2_dat_0"},
+};
+
+static struct msm_gpio sdc3_cfg_data[] = {
+	{GPIO_CFG(88, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), "sdc3_clk"},
+	{GPIO_CFG(89, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc3_cmd"},
+	{GPIO_CFG(90, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc3_dat_3"},
+	{GPIO_CFG(91, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc3_dat_2"},
+	{GPIO_CFG(92, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc3_dat_1"},
+	{GPIO_CFG(93, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc3_dat_0"},
+
+#ifdef CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT
+	{GPIO_CFG(158, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc3_dat_4"},
+	{GPIO_CFG(159, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc3_dat_5"},
+	{GPIO_CFG(160, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc3_dat_6"},
+	{GPIO_CFG(161, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc3_dat_7"},
+#endif
+};
+
+static struct msm_gpio sdc4_cfg_data[] = {
+	{GPIO_CFG(142, 3, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA), "sdc4_clk"},
+	{GPIO_CFG(143, 3, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc4_cmd"},
+	{GPIO_CFG(144, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc4_dat_0"},
+	{GPIO_CFG(145, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc4_dat_1"},
+	{GPIO_CFG(146, 3, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc4_dat_2"},
+	{GPIO_CFG(147, 3, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_8MA), "sdc4_dat_3"},
+};
+
+static struct sdcc_gpio sdcc_cfg_data[] = {
+	{
+		.cfg_data = sdc1_cfg_data,
+		.size = ARRAY_SIZE(sdc1_cfg_data),
+	},
+	{
+		.cfg_data = sdc2_cfg_data,
+		.size = ARRAY_SIZE(sdc2_cfg_data),
+	},
+	{
+		.cfg_data = sdc3_cfg_data,
+		.size = ARRAY_SIZE(sdc3_cfg_data),
+	},
+	{
+		.cfg_data = sdc4_cfg_data,
+		.size = ARRAY_SIZE(sdc4_cfg_data),
+	},
+};
+
+static unsigned long vreg_sts, gpio_sts;
+
+static void msm_sdcc_setup_gpio(int dev_id, unsigned int enable)
+{
+	int rc = 0;
+	struct sdcc_gpio *curr;
+
+	curr = &sdcc_cfg_data[dev_id - 1];
+	if (!(test_bit(dev_id, &gpio_sts)^enable))
+		return;
+
+	if (enable) {
+		set_bit(dev_id, &gpio_sts);
+		rc = msm_gpios_request_enable(curr->cfg_data, curr->size);
+		if (rc)
+			printk(KERN_ERR "%s: Failed to turn on GPIOs for slot %d\n",
+				__func__,  dev_id);
+	} else {
+		clear_bit(dev_id, &gpio_sts);
+		msm_gpios_disable_free(curr->cfg_data, curr->size);
+	}
+}
 
 static uint32_t msm_sdcc_setup_power(struct device *dv, unsigned int vdd)
 {
@@ -116,6 +2087,7 @@
 	struct platform_device *pdev;
 
 	pdev = container_of(dv, struct platform_device, dev);
+	msm_sdcc_setup_gpio(pdev->id, !!vdd);
 
 	if (vdd == 0) {
 		if (!vreg_sts)
@@ -126,69 +2098,431 @@
 		if (!vreg_sts) {
 			rc = vreg_disable(vreg_mmc);
 			if (rc)
-				pr_err("vreg_mmc disable failed for slot "
-						"%d: %d\n", pdev->id, rc);
+				printk(KERN_ERR "%s: return val: %d \n",
+					__func__, rc);
 		}
 		return 0;
 	}
 
 	if (!vreg_sts) {
-		rc = vreg_set_level(vreg_mmc, 2900);
+		rc = vreg_set_level(vreg_mmc, PMIC_VREG_GP6_LEVEL);
+		if (!rc)
+			rc = vreg_enable(vreg_mmc);
 		if (rc)
-			pr_err("vreg_mmc set level failed for slot %d: %d\n",
-					pdev->id, rc);
-		rc = vreg_enable(vreg_mmc);
-		if (rc)
-			pr_err("vreg_mmc enable failed for slot %d: %d\n",
-					pdev->id, rc);
+			printk(KERN_ERR "%s: return val: %d \n",
+					__func__, rc);
 	}
 	set_bit(pdev->id, &vreg_sts);
 	return 0;
 }
 
-static struct msm_mmc_gpio_data sdc1_gpio = {
-	.gpio = sdc1_gpio_cfg,
-	.size = ARRAY_SIZE(sdc1_gpio_cfg),
-};
+#endif
+#if (defined(CONFIG_MMC_MSM_SDC1_SUPPORT)\
+	|| defined(CONFIG_MMC_MSM_SDC2_SUPPORT)\
+	|| defined(CONFIG_MMC_MSM_SDC4_SUPPORT))
 
-static struct msm_mmc_platform_data qsd8x50_sdc1_data = {
+static int msm_sdcc_get_wpswitch(struct device *dv)
+{
+	void __iomem *wp_addr = 0;
+	uint32_t ret = 0;
+	struct platform_device *pdev;
+
+	if (!machine_is_qsd8x50_surf())
+		return -1;
+
+	pdev = container_of(dv, struct platform_device, dev);
+
+	wp_addr = ioremap(FPGA_SDCC_STATUS, 4);
+	if (!wp_addr) {
+		pr_err("%s: Could not remap %x\n", __func__, FPGA_SDCC_STATUS);
+		return -ENOMEM;
+	}
+
+	ret = (readl(wp_addr) >> ((pdev->id - 1) << 1)) & (0x03);
+	pr_info("%s: WP/CD Status for Slot %d = 0x%x \n", __func__,
+							pdev->id, ret);
+	iounmap(wp_addr);
+	return ((ret == 0x02) ? 1 : 0);
+
+}
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+static struct mmc_platform_data qsd8x50_sdc1_data = {
 	.ocr_mask	= MMC_VDD_27_28 | MMC_VDD_28_29,
 	.translate_vdd	= msm_sdcc_setup_power,
-	.gpio_data = &sdc1_gpio,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.wpswitch	= msm_sdcc_get_wpswitch,
+	.msmsdcc_fmin	= 144000,
+	.msmsdcc_fmid	= 25000000,
+	.msmsdcc_fmax	= 49152000,
+	.nonremovable	= 0,
 };
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+static struct mmc_platform_data qsd8x50_sdc2_data = {
+	.ocr_mask       = MMC_VDD_27_28 | MMC_VDD_28_29,
+	.translate_vdd  = msm_sdcc_setup_power,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.wpswitch	= msm_sdcc_get_wpswitch,
+	.msmsdcc_fmin	= 144000,
+	.msmsdcc_fmid	= 25000000,
+	.msmsdcc_fmax	= 49152000,
+	.nonremovable	= 1,
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+static struct mmc_platform_data qsd8x50_sdc3_data = {
+	.ocr_mask       = MMC_VDD_27_28 | MMC_VDD_28_29,
+	.translate_vdd  = msm_sdcc_setup_power,
+#ifdef CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT
+	.mmc_bus_width  = MMC_CAP_8_BIT_DATA,
+#else
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+#endif
+	.msmsdcc_fmin	= 144000,
+	.msmsdcc_fmid	= 25000000,
+	.msmsdcc_fmax	= 49152000,
+	.nonremovable	= 0,
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+static struct mmc_platform_data qsd8x50_sdc4_data = {
+	.ocr_mask       = MMC_VDD_27_28 | MMC_VDD_28_29,
+	.translate_vdd  = msm_sdcc_setup_power,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.wpswitch	= msm_sdcc_get_wpswitch,
+	.msmsdcc_fmin	= 144000,
+	.msmsdcc_fmid	= 25000000,
+	.msmsdcc_fmax	= 49152000,
+	.nonremovable	= 0,
+};
+#endif
 
 static void __init qsd8x50_init_mmc(void)
 {
-	vreg_mmc = vreg_get(NULL, "gp5");
+	if (machine_is_qsd8x50_ffa())
+		vreg_mmc = vreg_get(NULL, "gp6");
+	else
+		vreg_mmc = vreg_get(NULL, "gp5");
 
 	if (IS_ERR(vreg_mmc)) {
-		pr_err("vreg get for vreg_mmc failed (%ld)\n",
-				PTR_ERR(vreg_mmc));
+		printk(KERN_ERR "%s: vreg get failed (%ld)\n",
+		       __func__, PTR_ERR(vreg_mmc));
 		return;
 	}
 
-	msm_add_sdcc(1, &qsd8x50_sdc1_data, 0, 0);
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+	msm_add_sdcc(1, &qsd8x50_sdc1_data);
+#endif
+
+	if (machine_is_qsd8x50_surf()) {
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+		msm_add_sdcc(2, &qsd8x50_sdc2_data);
+#endif
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+		msm_add_sdcc(3, &qsd8x50_sdc3_data);
+#endif
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+		msm_add_sdcc(4, &qsd8x50_sdc4_data);
+#endif
+	}
+
+}
+
+static void __init qsd8x50_cfg_smc91x(void)
+{
+	int rc = 0;
+
+	if (machine_is_qsd8x50_surf()) {
+		smc91x_resources[0].start = 0x70000300;
+		smc91x_resources[0].end = 0x700003ff;
+		smc91x_resources[1].start = MSM_GPIO_TO_INT(156);
+		smc91x_resources[1].end = MSM_GPIO_TO_INT(156);
+	} else if (machine_is_qsd8x50_ffa()) {
+		smc91x_resources[0].start = 0x84000300;
+		smc91x_resources[0].end = 0x840003ff;
+		smc91x_resources[1].start = MSM_GPIO_TO_INT(87);
+		smc91x_resources[1].end = MSM_GPIO_TO_INT(87);
+
+		rc = gpio_tlmm_config(GPIO_CFG(87, 0, GPIO_CFG_INPUT,
+					       GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+					       GPIO_CFG_ENABLE);
+		if (rc) {
+			printk(KERN_ERR "%s: gpio_tlmm_config=%d\n",
+					__func__, rc);
+		}
+	} else
+		printk(KERN_ERR "%s: invalid machine type\n", __func__);
+}
+
+static struct msm_pm_platform_data msm_pm_data[MSM_PM_SLEEP_MODE_NR] = {
+	[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = {
+		.idle_supported = 1,
+		.suspend_supported = 1,
+		.idle_enabled = 1,
+		.suspend_enabled = 1,
+		.latency = 8594,
+		.residency = 23740,
+	},
+
+	[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN] = {
+		.idle_supported = 1,
+		.suspend_supported = 1,
+		.idle_enabled = 1,
+		.suspend_enabled = 1,
+		.latency = 4594,
+		.residency = 23740,
+	},
+
+	[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT] = {
+		.idle_supported = 1,
+		.suspend_supported = 1,
+		.idle_enabled = 0,
+		.suspend_enabled = 1,
+		.latency = 443,
+		.residency = 1098,
+	},
+
+	[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT] = {
+		.idle_supported = 1,
+		.suspend_supported = 1,
+		.idle_enabled = 1,
+		.suspend_enabled = 1,
+		.latency = 2,
+		.residency = 0,
+	},
+};
+
+static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT,
+	.v_addr = (unsigned int *)PAGE_OFFSET,
+};
+
+static void
+msm_i2c_gpio_config(int iface, int config_type)
+{
+	int gpio_scl;
+	int gpio_sda;
+	if (iface) {
+		gpio_scl = 60;
+		gpio_sda = 61;
+	} else {
+		gpio_scl = 95;
+		gpio_sda = 96;
+	}
+	if (config_type) {
+		gpio_tlmm_config(GPIO_CFG(gpio_scl, 1, GPIO_CFG_INPUT,
+					GPIO_CFG_NO_PULL, GPIO_CFG_16MA), GPIO_CFG_ENABLE);
+		gpio_tlmm_config(GPIO_CFG(gpio_sda, 1, GPIO_CFG_INPUT,
+					GPIO_CFG_NO_PULL, GPIO_CFG_16MA), GPIO_CFG_ENABLE);
+	} else {
+		gpio_tlmm_config(GPIO_CFG(gpio_scl, 0, GPIO_CFG_OUTPUT,
+					GPIO_CFG_NO_PULL, GPIO_CFG_16MA), GPIO_CFG_ENABLE);
+		gpio_tlmm_config(GPIO_CFG(gpio_sda, 0, GPIO_CFG_OUTPUT,
+					GPIO_CFG_NO_PULL, GPIO_CFG_16MA), GPIO_CFG_ENABLE);
+	}
+}
+
+static struct msm_i2c_platform_data msm_i2c_pdata = {
+	.clk_freq = 100000,
+	.rsl_id = SMEM_SPINLOCK_I2C,
+	.pri_clk = 95,
+	.pri_dat = 96,
+	.aux_clk = 60,
+	.aux_dat = 61,
+	.msm_i2c_config_gpio = msm_i2c_gpio_config,
+};
+
+static void __init msm_device_i2c_init(void)
+{
+	if (gpio_request(95, "i2c_pri_clk"))
+		pr_err("failed to request gpio i2c_pri_clk\n");
+	if (gpio_request(96, "i2c_pri_dat"))
+		pr_err("failed to request gpio i2c_pri_dat\n");
+	if (gpio_request(60, "i2c_sec_clk"))
+		pr_err("failed to request gpio i2c_sec_clk\n");
+	if (gpio_request(61, "i2c_sec_dat"))
+		pr_err("failed to request gpio i2c_sec_dat\n");
+
+	msm_i2c_pdata.rmutex = 1;
+	msm_i2c_pdata.pm_lat =
+		msm_pm_data[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]
+		.latency;
+	msm_device_i2c.dev.platform_data = &msm_i2c_pdata;
+}
+
+static unsigned pmem_kernel_ebi1_size = PMEM_KERNEL_EBI1_SIZE;
+static int __init pmem_kernel_ebi1_size_setup(char *p)
+{
+	pmem_kernel_ebi1_size = memparse(p, NULL);
+	return 0;
+}
+early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
+
+#ifdef CONFIG_KERNEL_PMEM_SMI_REGION
+static unsigned pmem_kernel_smi_size = MSM_PMEM_SMIPOOL_SIZE;
+static int __init pmem_kernel_smi_size_setup(char *p)
+{
+	pmem_kernel_smi_size = memparse(p, NULL);
+
+	/* Make sure that we don't allow more SMI memory then is
+	   available - the kernel mapping code has no way of knowing
+	   if it has gone over the edge */
+
+	if (pmem_kernel_smi_size > MSM_PMEM_SMIPOOL_SIZE)
+		pmem_kernel_smi_size = MSM_PMEM_SMIPOOL_SIZE;
+	return 0;
+}
+early_param("pmem_kernel_smi_size", pmem_kernel_smi_size_setup);
+#endif
+
+static unsigned pmem_sf_size = MSM_PMEM_SF_SIZE;
+static int __init pmem_sf_size_setup(char *p)
+{
+	pmem_sf_size = memparse(p, NULL);
+	return 0;
+}
+early_param("pmem_sf_size", pmem_sf_size_setup);
+
+static unsigned pmem_adsp_size = MSM_PMEM_ADSP_SIZE;
+static int __init pmem_adsp_size_setup(char *p)
+{
+	pmem_adsp_size = memparse(p, NULL);
+	return 0;
+}
+early_param("pmem_adsp_size", pmem_adsp_size_setup);
+
+
+static unsigned audio_size = MSM_AUDIO_SIZE;
+static int __init audio_size_setup(char *p)
+{
+	audio_size = memparse(p, NULL);
+	return 0;
+}
+early_param("audio_size", audio_size_setup);
+
+static void __init qsd8x50_init(void)
+{
+	msm_clock_init(&qds8x50_clock_init_data);
+	qsd8x50_cfg_smc91x();
+	acpuclk_init(&acpuclk_8x50_soc_data);
+
+	msm_hsusb_pdata.swfi_latency =
+		msm_pm_data
+		[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency;
+	msm_device_hsusb_peripheral.dev.platform_data = &msm_hsusb_pdata;
+
+	msm_otg_pdata.swfi_latency =
+		msm_pm_data
+		[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency;
+	msm_device_otg.dev.platform_data = &msm_otg_pdata;
+	msm_device_gadget_peripheral.dev.platform_data = &msm_gadget_pdata;
+	msm_gadget_pdata.is_phy_status_timer_on = 1;
+
+#if defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE)
+	msm_device_tsif.dev.platform_data = &tsif_platform_data;
+#endif
+	platform_add_devices(devices, ARRAY_SIZE(devices));
+	msm_fb_add_devices();
+#ifdef CONFIG_MSM_CAMERA
+	config_camera_off_gpios(); /* might not be necessary */
+#endif
+	qsd8x50_init_usb();
+	qsd8x50_init_mmc();
+	bt_power_init();
+	audio_gpio_init();
+	msm_device_i2c_init();
+	msm_qsd_spi_init();
+	i2c_register_board_info(0, msm_i2c_board_info,
+				ARRAY_SIZE(msm_i2c_board_info));
+	spi_register_board_info(msm_spi_board_info,
+				ARRAY_SIZE(msm_spi_board_info));
+	msm_pm_set_platform_data(msm_pm_data, ARRAY_SIZE(msm_pm_data));
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+	msm_pm_register_irqs();
+
+#ifdef CONFIG_SURF_FFA_GPIO_KEYPAD
+	if (machine_is_qsd8x50_ffa())
+		platform_device_register(&keypad_device_8k_ffa);
+	else
+		platform_device_register(&keypad_device_surf);
+#endif
+}
+
+static void __init qsd8x50_allocate_memory_regions(void)
+{
+	void *addr;
+	unsigned long size;
+
+	size = pmem_kernel_ebi1_size;
+	if (size) {
+		addr = alloc_bootmem_align(size, 0x100000);
+		android_pmem_kernel_ebi1_pdata.size = size;
+		pr_info("allocating %lu bytes at %p (%lx physical) for kernel"
+			" ebi1 pmem arena\n", size, addr, __pa(addr));
+	}
+
+#ifdef CONFIG_KERNEL_PMEM_SMI_REGION
+	size = pmem_kernel_smi_size;
+	if (size > MSM_PMEM_SMIPOOL_SIZE) {
+		printk(KERN_ERR "pmem kernel smi arena size %lu is too big\n",
+			size);
+
+		size = MSM_PMEM_SMIPOOL_SIZE;
+	}
+
+	android_pmem_kernel_smi_pdata.size = size;
+
+	pr_info("allocating %lu bytes at %lx (%lx physical)"
+		"for pmem kernel smi arena\n", size,
+		(long unsigned int) MSM_PMEM_SMIPOOL_BASE,
+		__pa(MSM_PMEM_SMIPOOL_BASE));
+#endif
+
+	size = pmem_sf_size;
+	if (size) {
+		addr = alloc_bootmem(size);
+		android_pmem_pdata.size = size;
+		pr_info("allocating %lu bytes at %p (%lx physical) for sf "
+			"pmem arena\n", size, addr, __pa(addr));
+	}
+
+	size = pmem_adsp_size;
+	if (size) {
+		addr = alloc_bootmem(size);
+		android_pmem_adsp_pdata.size = size;
+		pr_info("allocating %lu bytes at %p (%lx physical) for adsp "
+			"pmem arena\n", size, addr, __pa(addr));
+	}
+
+
+	size = MSM_FB_SIZE;
+	addr = (void *)MSM_FB_BASE;
+	msm_fb_resources[0].start = (unsigned long)addr;
+	msm_fb_resources[0].end = msm_fb_resources[0].start + size - 1;
+	pr_info("using %lu bytes of SMI at %lx physical for fb\n",
+	       size, (unsigned long)addr);
+
+	size = audio_size ? : MSM_AUDIO_SIZE;
+	addr = alloc_bootmem(size);
+	msm_audio_resources[0].start = __pa(addr);
+	msm_audio_resources[0].end = msm_audio_resources[0].start + size - 1;
+	pr_info("allocating %lu bytes at %p (%lx physical) for audio\n",
+		size, addr, __pa(addr));
 }
 
 static void __init qsd8x50_map_io(void)
 {
+	msm_shared_ram_phys = MSM_SHARED_RAM_PHYS;
 	msm_map_qsd8x50_io();
-	msm_clock_init(msm_clocks_8x50, msm_num_clocks_8x50);
-}
-
-static void __init qsd8x50_init_irq(void)
-{
-	msm_init_irq();
-	msm_init_sirc();
-}
-
-static void __init qsd8x50_init(void)
-{
-	msm_device_otg.dev.platform_data = &msm_otg_pdata;
-	msm_device_hsusb.dev.parent = &msm_device_otg.dev;
-	msm_device_hsusb_host.dev.parent = &msm_device_otg.dev;
-	platform_add_devices(devices, ARRAY_SIZE(devices));
-	qsd8x50_init_mmc();
+	qsd8x50_allocate_memory_regions();
+	if (socinfo_init() < 0)
+		printk(KERN_ERR "%s: socinfo_init() failed!\n",
+		       __func__);
 }
 
 MACHINE_START(QSD8X50_SURF, "QCT QSD8X50 SURF")
@@ -199,7 +2533,7 @@
 	.timer = &msm_timer,
 MACHINE_END
 
-MACHINE_START(QSD8X50A_ST1_5, "QCT QSD8X50A ST1.5")
+MACHINE_START(QSD8X50_FFA, "QCT QSD8X50 FFA")
 	.atag_offset = 0x100,
 	.map_io = qsd8x50_map_io,
 	.init_irq = qsd8x50_init_irq,
diff --git a/arch/arm/mach-msm/board-sapphire-gpio.c b/arch/arm/mach-msm/board-sapphire-gpio.c
new file mode 100644
index 0000000..375440c
--- /dev/null
+++ b/arch/arm/mach-msm/board-sapphire-gpio.c
@@ -0,0 +1,326 @@
+/* arch/arm/mach-msm/board-sapphire-gpio.c
+ * Copyright (C) 2007-2009 HTC Corporation.
+ * Author: Thomas Tsai <thomas_tsai@htc.com>
+ *
+ * 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.
+*/
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/irq.h>
+#include <linux/pm.h>
+#include <linux/sysdev.h>
+
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <asm/mach-types.h>
+
+#include "gpio_chip.h"
+#include "board-sapphire.h"
+
+#ifdef DEBUG_SAPPHIRE_GPIO
+#define DBG(fmt, arg...) printk(KERN_INFO "%s: " fmt "\n", __func__, ## arg)
+#else
+#define DBG(fmt, arg...) do {} while (0)
+#endif
+
+#define	SAPPHIRE_CPLD_INT_STATUS	(SAPPHIRE_CPLD_BASE + 0x0E)
+#define	SAPPHIRE_CPLD_INT_LEVEL		(SAPPHIRE_CPLD_BASE + 0x08)
+#define	SAPPHIRE_CPLD_INT_MASK		(SAPPHIRE_CPLD_BASE + 0x0C)
+
+/*CPLD misc reg offset*/
+static const int _g_CPLD_MISCn_Offset[] = {	0x0A,		/*misc1 reg*/
+						0x00,		/*misc2 reg*/
+						0x02,		/*misc3 reg*/
+						0x04,		/*misc4 reg*/
+						0x06};		/*misc5 reg*/
+/*CPLD INT Bank*/
+/*BANK0: int1 status, int2 level, int3 mask*/
+static const int _g_INT_BANK_Offset[][3] = {{0x0E, 0x08, 0x0C} };
+
+static uint8_t sapphire_cpld_initdata[4]  = {
+	[0] = 0x80, /* for serial debug UART3, low current	misc2*/
+	[1] = 0x34, /* jog & tp enable, I2C pull		misc3*/
+	[3] = 0x04, /* mmdi 32k en				misc5*/
+};
+
+/*save current working int mask, so the value can be restored after resume.
+Sapphire has only bank0.*/
+static uint8_t sapphire_int_mask[] = {
+	[0] = 0xfb, /* enable all interrupts, bit 2 is not used */
+};
+
+/*Sleep have to prepare the wake up source in advance.
+default to disable all wakeup sources when suspend.*/
+static uint8_t sapphire_sleep_int_mask[] = {
+	[0] = 0x00,	/* bit2 is not used */
+};
+
+static int sapphire_suspended;
+
+static int sapphire_gpio_read(struct gpio_chip *chip, unsigned n)
+{
+	if (n < SAPPHIRE_GPIO_INT_B0_BASE)	/*MISCn*/
+		return !!(readb(CPLD_GPIO_REG(n)) & CPLD_GPIO_BIT_POS_MASK(n));
+	else if (n <= SAPPHIRE_GPIO_END)	/*gpio n is INT pin*/
+		return !!(readb(CPLD_INT_LEVEL_REG_G(n)) &
+						CPLD_GPIO_BIT_POS_MASK(n));
+	return 0;
+}
+
+/*CPLD Write only register :MISC2, MISC3, MISC4, MISC5 => reg=0,2,4,6
+Reading from write-only registers is undefined, so the writing value
+should be kept in shadow for later usage.*/
+int sapphire_gpio_write(struct gpio_chip *chip, unsigned n, unsigned on)
+{
+	unsigned long flags;
+	uint8_t reg_val;
+	if (n > SAPPHIRE_GPIO_END)
+		return -1;
+
+	local_irq_save(flags);
+	reg_val = readb(CPLD_GPIO_REG(n));
+	if (on)
+		reg_val |= CPLD_GPIO_BIT_POS_MASK(n);
+	else
+		reg_val &= ~CPLD_GPIO_BIT_POS_MASK(n);
+	writeb(reg_val, CPLD_GPIO_REG(n));
+
+	DBG("gpio=%d, l=0x%x\r\n", n, readb(SAPPHIRE_CPLD_INT_LEVEL));
+
+	local_irq_restore(flags);
+
+	return 0;
+}
+
+static int sapphire_gpio_configure(struct gpio_chip *chip, unsigned int gpio,
+				   unsigned long flags)
+{
+	if (flags & (GPIOF_OUTPUT_LOW | GPIOF_OUTPUT_HIGH))
+		sapphire_gpio_write(chip, gpio, flags & GPIOF_OUTPUT_HIGH);
+
+	DBG("gpio=%d, l=0x%x\r\n", gpio, readb(SAPPHIRE_CPLD_INT_LEVEL));
+
+	return 0;
+}
+
+static int sapphire_gpio_get_irq_num(struct gpio_chip *chip, unsigned int gpio,
+				unsigned int *irqp, unsigned long *irqnumflagsp)
+{
+	DBG("gpio=%d, l=0x%x\r\n", gpio, readb(SAPPHIRE_CPLD_INT_LEVEL));
+	DBG("SAPPHIRE_GPIO_INT_B0_BASE=%d, SAPPHIRE_GPIO_LAST_INT=%d\r\n",
+	    SAPPHIRE_GPIO_INT_B0_BASE, SAPPHIRE_GPIO_LAST_INT);
+	if ((gpio < SAPPHIRE_GPIO_INT_B0_BASE) ||
+	     (gpio > SAPPHIRE_GPIO_LAST_INT))
+		return -ENOENT;
+	*irqp = SAPPHIRE_GPIO_TO_INT(gpio);
+	DBG("*irqp=%d\r\n", *irqp);
+	if (irqnumflagsp)
+		*irqnumflagsp = 0;
+	return 0;
+}
+
+/*write 1 to clear INT status bit.*/
+static void sapphire_gpio_irq_ack(unsigned int irq)
+{
+	/*write 1 to clear*/
+	writeb(SAPPHIRE_INT_BIT_MASK(irq), CPLD_INT_STATUS_REG(irq));
+}
+
+/*unmask/enable the INT
+static void sapphire_gpio_irq_unmask(unsigned int irq)*/
+static void sapphire_gpio_irq_enable(unsigned int irq)
+{
+	unsigned long flags;
+	uint8_t reg_val;
+
+	local_irq_save(flags);	/*disabling all interrupts*/
+
+	reg_val = readb(CPLD_INT_MASK_REG(irq)) | SAPPHIRE_INT_BIT_MASK(irq);
+	DBG("(irq=%d,0x%x, 0x%x)\r\n", irq, CPLD_INT_MASK_REG(irq),
+	    SAPPHIRE_INT_BIT_MASK(irq));
+	DBG("sapphire_suspended=%d\r\n", sapphire_suspended);
+	/*printk(KERN_INFO "sapphire_gpio_irq_mask irq %d => %d:%02x\n",
+	       irq, bank, reg_val);*/
+	if (!sapphire_suspended)
+		writeb(reg_val, CPLD_INT_MASK_REG(irq));
+
+	reg_val = readb(CPLD_INT_MASK_REG(irq));
+	DBG("reg_val= 0x%x\r\n", reg_val);
+	DBG("l=0x%x\r\n", readb(SAPPHIRE_CPLD_INT_LEVEL));
+
+	local_irq_restore(flags); /*restore the interrupts*/
+}
+
+/*mask/disable INT
+static void sapphire_gpio_irq_mask(unsigned int irq)*/
+static void sapphire_gpio_irq_disable(unsigned int irq)
+{
+	unsigned long flags;
+	uint8_t reg_val;
+
+	local_irq_save(flags);
+	reg_val = readb(CPLD_INT_MASK_REG(irq)) & ~SAPPHIRE_INT_BIT_MASK(irq);
+	/*CPLD INT MASK is r/w now.*/
+
+	/*printk(KERN_INFO "sapphire_gpio_irq_unmask irq %d => %d:%02x\n",
+	       irq, bank, reg_val);*/
+	DBG("(%d,0x%x, 0x%x, 0x%x)\r\n", irq, reg_val, CPLD_INT_MASK_REG(irq),
+	    SAPPHIRE_INT_BIT_MASK(irq));
+	DBG("sapphire_suspended=%d\r\n", sapphire_suspended);
+	if (!sapphire_suspended)
+		writeb(reg_val, CPLD_INT_MASK_REG(irq));
+
+	reg_val = readb(CPLD_INT_MASK_REG(irq));
+	DBG("reg_val= 0x%x\r\n", reg_val);
+	DBG("l=0x%x\r\n", readb(SAPPHIRE_CPLD_INT_LEVEL));
+
+	local_irq_restore(flags);
+}
+
+/*preparing enable/disable wake source before sleep*/
+int sapphire_gpio_irq_set_wake(unsigned int irq, unsigned int on)
+{
+	unsigned long flags;
+	uint8_t mask = SAPPHIRE_INT_BIT_MASK(irq);
+
+	local_irq_save(flags);
+
+	if (on)	/*wake on -> mask the bit*/
+		sapphire_sleep_int_mask[CPLD_INT_TO_BANK(irq)] |= mask;
+	else	/*no wake -> unmask the bit*/
+		sapphire_sleep_int_mask[CPLD_INT_TO_BANK(irq)] &= ~mask;
+	local_irq_restore(flags);
+	return 0;
+}
+
+/*Sapphire has only one INT Bank.*/
+static void sapphire_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	int j;
+	unsigned v;
+	int int_base = SAPPHIRE_INT_START;
+
+	v = readb(SAPPHIRE_CPLD_INT_STATUS);	/*INT1 status reg, BANK0*/
+
+	for (j = 0; j < 8 ; j++) {	/*8 bit per bank*/
+		if (v & (1U << j)) {	/*got the INT Bit*/
+			DBG("generic_handle_irq j=0x%x\r\n", j);
+			generic_handle_irq(int_base + j);
+		}
+	}
+
+	desc->chip->ack(irq);	/*clear CPLD INT in SOC side.*/
+	DBG("irq=%d, l=0x%x\r\n", irq, readb(SAPPHIRE_CPLD_INT_LEVEL));
+}
+
+/*Save current working sources before sleep, so we can restore it after
+ * resume.*/
+static int sapphire_sysdev_suspend(struct sys_device *dev, pm_message_t state)
+{
+	sapphire_suspended = 1;
+	/*save current masking*/
+	sapphire_int_mask[0] = readb(SAPPHIRE_CPLD_BASE +
+					SAPPHIRE_GPIO_INT_B0_MASK_REG);
+
+	/*set waking source before sleep.*/
+	writeb(sapphire_sleep_int_mask[0],
+	       SAPPHIRE_CPLD_BASE +  SAPPHIRE_GPIO_INT_B0_MASK_REG);
+
+	return 0;
+}
+
+/*All the registers will be kept till a power loss...*/
+int sapphire_sysdev_resume(struct sys_device *dev)
+{
+	/*restore the working mask saved before sleep*/
+	writeb(sapphire_int_mask[0], SAPPHIRE_CPLD_BASE +
+					SAPPHIRE_GPIO_INT_B0_MASK_REG);
+	sapphire_suspended = 0;
+	return 0;
+}
+
+/**
+ * linux/irq.h :: struct irq_chip
+ * @enable:		enable the interrupt (defaults to chip->unmask if NULL)
+ * @disable:	disable the interrupt (defaults to chip->mask if NULL)
+ * @ack:		start of a new interrupt
+ * @mask:		mask an interrupt source
+ * @mask_ack:		ack and mask an interrupt source
+ * @unmask:		unmask an interrupt source
+ */
+static struct irq_chip sapphire_gpio_irq_chip = {
+	.name      = "sapphiregpio",
+	.ack       = sapphire_gpio_irq_ack,
+	.mask      = sapphire_gpio_irq_disable,	/*sapphire_gpio_irq_mask,*/
+	.unmask    = sapphire_gpio_irq_enable,	/*sapphire_gpio_irq_unmask,*/
+	.set_wake  = sapphire_gpio_irq_set_wake,
+	/*.set_type  = sapphire_gpio_irq_set_type,*/
+};
+
+/*Thomas:For CPLD*/
+static struct gpio_chip sapphire_gpio_chip = {
+	.start = SAPPHIRE_GPIO_START,
+	.end = SAPPHIRE_GPIO_END,
+	.configure = sapphire_gpio_configure,
+	.get_irq_num = sapphire_gpio_get_irq_num,
+	.read = sapphire_gpio_read,
+	.write = sapphire_gpio_write,
+/*	.read_detect_status = sapphire_gpio_read_detect_status,
+	.clear_detect_status = sapphire_gpio_clear_detect_status */
+};
+
+struct sysdev_class sapphire_sysdev_class = {
+	.name = "sapphiregpio_irq",
+	.suspend = sapphire_sysdev_suspend,
+	.resume = sapphire_sysdev_resume,
+};
+
+static struct sys_device sapphire_irq_device = {
+	.cls    = &sapphire_sysdev_class,
+};
+
+int sapphire_init_gpio(void)
+{
+	int i;
+	if (!machine_is_sapphire())
+		return 0;
+
+	DBG("%d,%d\r\n", SAPPHIRE_INT_START, SAPPHIRE_INT_END);
+	DBG("NR_MSM_IRQS=%d, NR_GPIO_IRQS=%d\r\n", NR_MSM_IRQS, NR_GPIO_IRQS);
+	for (i = SAPPHIRE_INT_START; i <= SAPPHIRE_INT_END; i++) {
+		set_irq_chip(i, &sapphire_gpio_irq_chip);
+		set_irq_handler(i, handle_edge_irq);
+		set_irq_flags(i, IRQF_VALID);
+	}
+
+	register_gpio_chip(&sapphire_gpio_chip);
+
+	/*setup CPLD INT connecting to SOC's gpio 17 */
+	set_irq_type(MSM_GPIO_TO_INT(17), IRQF_TRIGGER_HIGH);
+	set_irq_chained_handler(MSM_GPIO_TO_INT(17), sapphire_gpio_irq_handler);
+	set_irq_wake(MSM_GPIO_TO_INT(17), 1);
+
+	if (sysdev_class_register(&sapphire_sysdev_class) == 0)
+		sysdev_register(&sapphire_irq_device);
+
+	return 0;
+}
+
+int sapphire_init_cpld(unsigned int sys_rev)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(sapphire_cpld_initdata); i++)
+		writeb(sapphire_cpld_initdata[i], SAPPHIRE_CPLD_BASE + i * 2);
+	return 0;
+}
+
+postcore_initcall(sapphire_init_gpio);
diff --git a/arch/arm/mach-msm/board-sapphire-h2w.c b/arch/arm/mach-msm/board-sapphire-h2w.c
new file mode 100644
index 0000000..aa83e21
--- /dev/null
+++ b/arch/arm/mach-msm/board-sapphire-h2w.c
@@ -0,0 +1,545 @@
+/*
+ *  H2W device detection driver.
+ *
+ * Copyright (C) 2008 HTC Corporation.
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * Authors:
+ *  Laurence Chen <Laurence_Chen@htc.com>
+ *  Nick Pelly <npelly@google.com>
+ *
+ * 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.
+ *
+ */
+
+/*  For detecting HTC 2 Wire devices, such as wired headset.
+
+    Logically, the H2W driver is always present, and H2W state (hi->state)
+    indicates what is currently plugged into the H2W interface.
+
+    When the headset is plugged in, CABLE_IN1 is pulled low. When the headset
+    button is pressed, CABLE_IN2 is pulled low. These two lines are shared with
+    the TX and RX (respectively) of UART3 - used for serial debugging.
+
+    This headset driver keeps the CPLD configured as UART3 for as long as
+    possible, so that we can do serial FIQ debugging even when the kernel is
+    locked and this driver no longer runs. So it only configures the CPLD to
+    GPIO while the headset is plugged in, and for 10ms during detection work.
+
+    Unfortunately we can't leave the CPLD as UART3 while a headset is plugged
+    in, UART3 is pullup on TX but the headset is pull-down, causing a 55 mA
+    drain on sapphire.
+
+    The headset detection work involves setting CPLD to GPIO, and then pulling
+    CABLE_IN1 high with a stronger pullup than usual. A H2W headset will still
+    pull this line low, whereas other attachments such as a serial console
+    would get pulled up by this stronger pullup.
+
+    Headset insertion/removal causes UEvent's to be sent, and
+    /sys/class/switch/h2w/state to be updated.
+
+    Button presses are interpreted as input event (KEY_MEDIA). Button presses
+    are ignored if the headset is plugged in, so the buttons on 11 pin -> 3.5mm
+    jack adapters do not work until a headset is plugged into the adapter. This
+    is to avoid serial RX traffic causing spurious button press events.
+
+    We tend to check the status of CABLE_IN1 a few more times than strictly
+    necessary during headset detection, to avoid spurious headset insertion
+    events caused by serial debugger TX traffic.
+*/
+
+
+#include <linux/module.h>
+#include <linux/sysdev.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/hrtimer.h>
+#include <linux/switch.h>
+#include <linux/input.h>
+#include <linux/debugfs.h>
+#include <linux/gpio.h>
+#include <asm/atomic.h>
+#include <mach/board.h>
+#include <mach/vreg.h>
+#include <asm/mach-types.h>
+#include "board-sapphire.h"
+
+#ifdef CONFIG_DEBUG_SAPPHIRE_H2W
+#define H2W_DBG(fmt, arg...) printk(KERN_INFO "[H2W] %s " fmt "\n", __FUNCTION__, ## arg)
+#else
+#define H2W_DBG(fmt, arg...) do {} while (0)
+#endif
+
+static struct workqueue_struct *g_detection_work_queue;
+static void detection_work(struct work_struct *work);
+static DECLARE_WORK(g_detection_work, detection_work);
+enum {
+	NO_DEVICE	= 0,
+	HTC_HEADSET	= 1,
+};
+
+enum {
+	UART3		= 0,
+	GPIO		= 1,
+};
+
+struct h2w_info {
+	struct switch_dev sdev;
+	struct input_dev *input;
+
+	atomic_t btn_state;
+	int ignore_btn;
+
+	unsigned int irq;
+	unsigned int irq_btn;
+
+	struct hrtimer timer;
+	ktime_t debounce_time;
+
+	struct hrtimer btn_timer;
+	ktime_t btn_debounce_time;
+};
+static struct h2w_info *hi;
+
+static ssize_t sapphire_h2w_print_name(struct switch_dev *sdev, char *buf)
+{
+	switch (switch_get_state(&hi->sdev)) {
+	case NO_DEVICE:
+		return sprintf(buf, "No Device\n");
+	case HTC_HEADSET:
+		return sprintf(buf, "Headset\n");
+	}
+	return -EINVAL;
+}
+
+static void configure_cpld(int route)
+{
+	H2W_DBG(" route = %s", route == UART3 ? "UART3" : "GPIO");
+	switch (route) {
+	case UART3:
+		gpio_set_value(SAPPHIRE_GPIO_H2W_SEL0, 0);
+		gpio_set_value(SAPPHIRE_GPIO_H2W_SEL1, 1);
+		break;
+	case GPIO:
+		gpio_set_value(SAPPHIRE_GPIO_H2W_SEL0, 0);
+		gpio_set_value(SAPPHIRE_GPIO_H2W_SEL1, 0);
+		break;
+	}
+}
+
+static void button_pressed(void)
+{
+	H2W_DBG("");
+	atomic_set(&hi->btn_state, 1);
+	input_report_key(hi->input, KEY_MEDIA, 1);
+	input_sync(hi->input);
+}
+
+static void button_released(void)
+{
+	H2W_DBG("");
+	atomic_set(&hi->btn_state, 0);
+	input_report_key(hi->input, KEY_MEDIA, 0);
+	input_sync(hi->input);
+}
+
+#ifdef CONFIG_MSM_SERIAL_DEBUGGER
+extern void msm_serial_debug_enable(int);
+#endif
+
+static void insert_headset(void)
+{
+	unsigned long irq_flags;
+
+	H2W_DBG("");
+
+	switch_set_state(&hi->sdev, HTC_HEADSET);
+	configure_cpld(GPIO);
+
+#ifdef CONFIG_MSM_SERIAL_DEBUGGER
+	msm_serial_debug_enable(false);
+#endif
+
+
+	/* On some non-standard headset adapters (usually those without a
+	 * button) the btn line is pulled down at the same time as the detect
+	 * line. We can check here by sampling the button line, if it is
+	 * low then it is probably a bad adapter so ignore the button.
+	 * If the button is released then we stop ignoring the button, so that
+	 * the user can recover from the situation where a headset is plugged
+	 * in with button held down.
+	 */
+	hi->ignore_btn = !gpio_get_value(SAPPHIRE_GPIO_CABLE_IN2);
+
+	/* Enable button irq */
+	local_irq_save(irq_flags);
+	enable_irq(hi->irq_btn);
+	local_irq_restore(irq_flags);
+
+	hi->debounce_time = ktime_set(0, 20000000);  /* 20 ms */
+}
+
+static void remove_headset(void)
+{
+	unsigned long irq_flags;
+
+	H2W_DBG("");
+
+	switch_set_state(&hi->sdev, NO_DEVICE);
+	configure_cpld(UART3);
+
+	/* Disable button */
+	local_irq_save(irq_flags);
+	disable_irq(hi->irq_btn);
+	local_irq_restore(irq_flags);
+
+	if (atomic_read(&hi->btn_state))
+		button_released();
+
+	hi->debounce_time = ktime_set(0, 100000000);  /* 100 ms */
+}
+
+static void detection_work(struct work_struct *work)
+{
+	unsigned long irq_flags;
+	int clk, cable_in1;
+
+	H2W_DBG("");
+
+	if (gpio_get_value(SAPPHIRE_GPIO_CABLE_IN1) != 0) {
+		/* Headset not plugged in */
+		if (switch_get_state(&hi->sdev) == HTC_HEADSET)
+			remove_headset();
+		return;
+	}
+
+	/* Something plugged in, lets make sure its a headset */
+
+	/* Switch CPLD to GPIO to do detection */
+	configure_cpld(GPIO);
+	/* Disable headset interrupt while detecting.*/
+	local_irq_save(irq_flags);
+	disable_irq(hi->irq);
+	local_irq_restore(irq_flags);
+
+	/* Set GPIO_CABLE_IN1 as output high */
+	gpio_direction_output(SAPPHIRE_GPIO_CABLE_IN1, 1);
+	/* Delay 10ms for pin stable. */
+	msleep(10);
+	/* Save H2W_CLK */
+	clk = gpio_get_value(SAPPHIRE_GPIO_H2W_CLK_GPI);
+	/* Set GPIO_CABLE_IN1 as input */
+	gpio_direction_input(SAPPHIRE_GPIO_CABLE_IN1);
+
+	/* Restore IRQs */
+	local_irq_save(irq_flags);
+	enable_irq(hi->irq);
+	local_irq_restore(irq_flags);
+
+	cable_in1 = gpio_get_value(SAPPHIRE_GPIO_CABLE_IN1);
+
+	if (cable_in1 == 0 && clk == 0) {
+		if (switch_get_state(&hi->sdev) == NO_DEVICE)
+			insert_headset();
+	} else {
+		configure_cpld(UART3);
+		H2W_DBG("CABLE_IN1 was low, but not a headset "
+			"(recent cable_in1 = %d, clk = %d)", cable_in1, clk);
+	}
+}
+
+static enum hrtimer_restart button_event_timer_func(struct hrtimer *data)
+{
+	H2W_DBG("");
+
+	if (switch_get_state(&hi->sdev) == HTC_HEADSET) {
+		if (gpio_get_value(SAPPHIRE_GPIO_CABLE_IN2)) {
+			if (hi->ignore_btn)
+				hi->ignore_btn = 0;
+			else if (atomic_read(&hi->btn_state))
+				button_released();
+		} else {
+			if (!hi->ignore_btn && !atomic_read(&hi->btn_state))
+				button_pressed();
+		}
+	}
+
+	return HRTIMER_NORESTART;
+}
+
+static enum hrtimer_restart detect_event_timer_func(struct hrtimer *data)
+{
+	H2W_DBG("");
+
+	queue_work(g_detection_work_queue, &g_detection_work);
+	return HRTIMER_NORESTART;
+}
+
+static irqreturn_t detect_irq_handler(int irq, void *dev_id)
+{
+	int value1, value2;
+	int retry_limit = 10;
+
+	H2W_DBG("");
+	do {
+		value1 = gpio_get_value(SAPPHIRE_GPIO_CABLE_IN1);
+		set_irq_type(hi->irq, value1 ?
+				IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH);
+		value2 = gpio_get_value(SAPPHIRE_GPIO_CABLE_IN1);
+	} while (value1 != value2 && retry_limit-- > 0);
+
+	H2W_DBG("value2 = %d (%d retries)", value2, (10-retry_limit));
+
+	if ((switch_get_state(&hi->sdev) == NO_DEVICE) ^ value2) {
+		if (switch_get_state(&hi->sdev) == HTC_HEADSET)
+			hi->ignore_btn = 1;
+		/* Do the rest of the work in timer context */
+		hrtimer_start(&hi->timer, hi->debounce_time, HRTIMER_MODE_REL);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t button_irq_handler(int irq, void *dev_id)
+{
+	int value1, value2;
+	int retry_limit = 10;
+
+	H2W_DBG("");
+	do {
+		value1 = gpio_get_value(SAPPHIRE_GPIO_CABLE_IN2);
+		set_irq_type(hi->irq_btn, value1 ?
+				IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH);
+		value2 = gpio_get_value(SAPPHIRE_GPIO_CABLE_IN2);
+	} while (value1 != value2 && retry_limit-- > 0);
+
+	H2W_DBG("value2 = %d (%d retries)", value2, (10-retry_limit));
+
+	hrtimer_start(&hi->btn_timer, hi->btn_debounce_time, HRTIMER_MODE_REL);
+
+	return IRQ_HANDLED;
+}
+
+#if defined(CONFIG_DEBUG_FS)
+static void h2w_debug_set(void *data, u64 val)
+{
+	switch_set_state(&hi->sdev, (int)val);
+}
+
+static u64 h2w_debug_get(void *data)
+{
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(h2w_debug_fops, h2w_debug_get, h2w_debug_set, "%llu\n");
+static int __init h2w_debug_init(void)
+{
+	struct dentry *dent;
+
+	dent = debugfs_create_dir("h2w", 0);
+	if (IS_ERR(dent))
+		return PTR_ERR(dent);
+
+	debugfs_create_file("state", 0644, dent, NULL, &h2w_debug_fops);
+
+	return 0;
+}
+
+device_initcall(h2w_debug_init);
+#endif
+
+static int sapphire_h2w_probe(struct platform_device *pdev)
+{
+	int ret;
+	unsigned long irq_flags;
+
+	printk(KERN_INFO "H2W: Registering H2W (headset) driver\n");
+	hi = kzalloc(sizeof(struct h2w_info), GFP_KERNEL);
+	if (!hi)
+		return -ENOMEM;
+
+	atomic_set(&hi->btn_state, 0);
+	hi->ignore_btn = 0;
+
+	hi->debounce_time = ktime_set(0, 100000000);  /* 100 ms */
+	hi->btn_debounce_time = ktime_set(0, 10000000); /* 10 ms */
+	hi->sdev.name = "h2w";
+	hi->sdev.print_name = sapphire_h2w_print_name;
+
+	ret = switch_dev_register(&hi->sdev);
+	if (ret < 0)
+		goto err_switch_dev_register;
+
+	g_detection_work_queue = create_workqueue("detection");
+	if (g_detection_work_queue == NULL) {
+		ret = -ENOMEM;
+		goto err_create_work_queue;
+	}
+
+	ret = gpio_request(SAPPHIRE_GPIO_CABLE_IN1, "h2w_detect");
+	if (ret < 0)
+		goto err_request_detect_gpio;
+
+	ret = gpio_request(SAPPHIRE_GPIO_CABLE_IN2, "h2w_button");
+	if (ret < 0)
+		goto err_request_button_gpio;
+
+	ret = gpio_direction_input(SAPPHIRE_GPIO_CABLE_IN1);
+	if (ret < 0)
+		goto err_set_detect_gpio;
+
+	ret = gpio_direction_input(SAPPHIRE_GPIO_CABLE_IN2);
+	if (ret < 0)
+		goto err_set_button_gpio;
+
+	hi->irq = gpio_to_irq(SAPPHIRE_GPIO_CABLE_IN1);
+	if (hi->irq < 0) {
+		ret = hi->irq;
+		goto err_get_h2w_detect_irq_num_failed;
+	}
+
+	hi->irq_btn = gpio_to_irq(SAPPHIRE_GPIO_CABLE_IN2);
+	if (hi->irq_btn < 0) {
+		ret = hi->irq_btn;
+		goto err_get_button_irq_num_failed;
+	}
+
+	/* Set CPLD MUX to H2W <-> CPLD GPIO */
+	configure_cpld(UART3);
+	/* Set the CPLD connected H2W GPIO's to input */
+	gpio_set_value(SAPPHIRE_GPIO_H2W_CLK_DIR, 0);
+	gpio_set_value(SAPPHIRE_GPIO_H2W_DAT_DIR, 0);
+
+	hrtimer_init(&hi->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	hi->timer.function = detect_event_timer_func;
+	hrtimer_init(&hi->btn_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	hi->btn_timer.function = button_event_timer_func;
+
+	ret = request_irq(hi->irq, detect_irq_handler,
+			  IRQF_TRIGGER_LOW, "h2w_detect", NULL);
+	if (ret < 0)
+		goto err_request_detect_irq;
+
+	/* Disable button until plugged in */
+	set_irq_flags(hi->irq_btn, IRQF_VALID | IRQF_NOAUTOEN);
+	ret = request_irq(hi->irq_btn, button_irq_handler,
+			  IRQF_TRIGGER_LOW, "h2w_button", NULL);
+	if (ret < 0)
+		goto err_request_h2w_headset_button_irq;
+
+	ret = set_irq_wake(hi->irq, 1);
+	if (ret < 0)
+		goto err_request_input_dev;
+	ret = set_irq_wake(hi->irq_btn, 1);
+	if (ret < 0)
+		goto err_request_input_dev;
+
+	hi->input = input_allocate_device();
+	if (!hi->input) {
+		ret = -ENOMEM;
+		goto err_request_input_dev;
+	}
+
+	hi->input->name = "h2w headset";
+	hi->input->evbit[0] = BIT_MASK(EV_KEY);
+	hi->input->keybit[BIT_WORD(KEY_MEDIA)] = BIT_MASK(KEY_MEDIA);
+
+	ret = input_register_device(hi->input);
+	if (ret < 0)
+		goto err_register_input_dev;
+
+	return 0;
+
+err_register_input_dev:
+	input_free_device(hi->input);
+err_request_input_dev:
+	free_irq(hi->irq_btn, 0);
+err_request_h2w_headset_button_irq:
+	free_irq(hi->irq, 0);
+err_request_detect_irq:
+err_get_button_irq_num_failed:
+err_get_h2w_detect_irq_num_failed:
+err_set_button_gpio:
+err_set_detect_gpio:
+	gpio_free(SAPPHIRE_GPIO_CABLE_IN2);
+err_request_button_gpio:
+	gpio_free(SAPPHIRE_GPIO_CABLE_IN1);
+err_request_detect_gpio:
+	destroy_workqueue(g_detection_work_queue);
+err_create_work_queue:
+	switch_dev_unregister(&hi->sdev);
+err_switch_dev_register:
+	printk(KERN_ERR "H2W: Failed to register driver\n");
+
+	return ret;
+}
+
+static int sapphire_h2w_remove(struct platform_device *pdev)
+{
+	H2W_DBG("");
+	if (switch_get_state(&hi->sdev))
+		remove_headset();
+	input_unregister_device(hi->input);
+	gpio_free(SAPPHIRE_GPIO_CABLE_IN2);
+	gpio_free(SAPPHIRE_GPIO_CABLE_IN1);
+	free_irq(hi->irq_btn, 0);
+	free_irq(hi->irq, 0);
+	destroy_workqueue(g_detection_work_queue);
+	switch_dev_unregister(&hi->sdev);
+
+	return 0;
+}
+
+static struct platform_device sapphire_h2w_device = {
+	.name		= "sapphire-h2w",
+};
+
+static struct platform_driver sapphire_h2w_driver = {
+	.probe		= sapphire_h2w_probe,
+	.remove		= sapphire_h2w_remove,
+	.driver		= {
+		.name		= "sapphire-h2w",
+		.owner		= THIS_MODULE,
+	},
+};
+
+static int __init sapphire_h2w_init(void)
+{
+	if (!machine_is_sapphire())
+		return 0;
+	int ret;
+	H2W_DBG("");
+	ret = platform_driver_register(&sapphire_h2w_driver);
+	if (ret)
+		return ret;
+	return platform_device_register(&sapphire_h2w_device);
+}
+
+static void __exit sapphire_h2w_exit(void)
+{
+	platform_device_unregister(&sapphire_h2w_device);
+	platform_driver_unregister(&sapphire_h2w_driver);
+}
+
+module_init(sapphire_h2w_init);
+module_exit(sapphire_h2w_exit);
+
+MODULE_AUTHOR("Laurence Chen <Laurence_Chen@htc.com>");
+MODULE_DESCRIPTION("HTC 2 Wire detection driver for sapphire");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/board-sapphire-keypad.c b/arch/arm/mach-msm/board-sapphire-keypad.c
new file mode 100644
index 0000000..5c8fc37
--- /dev/null
+++ b/arch/arm/mach-msm/board-sapphire-keypad.c
@@ -0,0 +1,132 @@
+/* arch/arm/mach-msm/board-sapphire-keypad.c
+ * Copyright (C) 2007-2009 HTC Corporation.
+ * Author: Thomas Tsai <thomas_tsai@htc.com>
+ *
+ * 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.
+*/
+
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/gpio_event.h>
+#include <asm/mach-types.h>
+#include "gpio_chip.h"
+#include "board-sapphire.h"
+static char *keycaps = "--qwerty";
+#undef MODULE_PARAM_PREFIX
+#define MODULE_PARAM_PREFIX "board_sapphire."
+module_param_named(keycaps, keycaps, charp, 0);
+
+
+static unsigned int sapphire_col_gpios[] = { 35, 34 };
+
+/* KP_MKIN2 (GPIO40) is not used? */
+static unsigned int sapphire_row_gpios[] = { 42, 41 };
+
+#define KEYMAP_INDEX(col, row) ((col)*ARRAY_SIZE(sapphire_row_gpios) + (row))
+
+/*scan matrix key*/
+/* HOME(up) MENU (up) Back Search */
+static const unsigned short sapphire_keymap2[ARRAY_SIZE(sapphire_col_gpios) * ARRAY_SIZE(sapphire_row_gpios)] = {
+	[KEYMAP_INDEX(0, 0)] = KEY_COMPOSE,
+	[KEYMAP_INDEX(0, 1)] = KEY_BACK,
+
+	[KEYMAP_INDEX(1, 0)] = KEY_MENU,
+	[KEYMAP_INDEX(1, 1)] = KEY_SEND,
+};
+
+/* HOME(up) + MENU (down)*/
+static const unsigned short sapphire_keymap1[ARRAY_SIZE(sapphire_col_gpios) *
+					ARRAY_SIZE(sapphire_row_gpios)] = {
+	[KEYMAP_INDEX(0, 0)] = KEY_BACK,
+	[KEYMAP_INDEX(0, 1)] = KEY_MENU,
+
+	[KEYMAP_INDEX(1, 0)] = KEY_HOME,
+	[KEYMAP_INDEX(1, 1)] = KEY_SEND,
+};
+
+/* MENU(up) + HOME (down)*/
+static const unsigned short sapphire_keymap0[ARRAY_SIZE(sapphire_col_gpios) *
+					ARRAY_SIZE(sapphire_row_gpios)] = {
+	[KEYMAP_INDEX(0, 0)] = KEY_BACK,
+	[KEYMAP_INDEX(0, 1)] = KEY_HOME,
+
+	[KEYMAP_INDEX(1, 0)] = KEY_MENU,
+	[KEYMAP_INDEX(1, 1)] = KEY_SEND,
+};
+
+static struct gpio_event_matrix_info sapphire_keypad_matrix_info = {
+	.info.func = gpio_event_matrix_func,
+	.keymap = sapphire_keymap2,
+	.output_gpios = sapphire_col_gpios,
+	.input_gpios = sapphire_row_gpios,
+	.noutputs = ARRAY_SIZE(sapphire_col_gpios),
+	.ninputs = ARRAY_SIZE(sapphire_row_gpios),
+	.settle_time.tv.nsec = 40 * NSEC_PER_USEC,
+	.poll_time.tv.nsec = 20 * NSEC_PER_MSEC,
+	.debounce_delay.tv.nsec = 50 * NSEC_PER_MSEC,
+	.flags = GPIOKPF_LEVEL_TRIGGERED_IRQ |
+		 GPIOKPF_REMOVE_PHANTOM_KEYS |
+		 GPIOKPF_PRINT_UNMAPPED_KEYS /*| GPIOKPF_PRINT_MAPPED_KEYS*/
+};
+
+static struct gpio_event_direct_entry sapphire_keypad_nav_map[] = {
+	{ SAPPHIRE_POWER_KEY,              KEY_END        },
+	{ SAPPHIRE_VOLUME_UP,              KEY_VOLUMEUP   },
+	{ SAPPHIRE_VOLUME_DOWN,            KEY_VOLUMEDOWN },
+};
+
+static struct gpio_event_input_info sapphire_keypad_nav_info = {
+	.info.func = gpio_event_input_func,
+	.flags = 0,
+	.type = EV_KEY,
+	.keymap = sapphire_keypad_nav_map,
+	.debounce_time.tv.nsec = 20 * NSEC_PER_MSEC,
+	.keymap_size = ARRAY_SIZE(sapphire_keypad_nav_map)
+};
+
+static struct gpio_event_info *sapphire_keypad_info[] = {
+	&sapphire_keypad_matrix_info.info,
+	&sapphire_keypad_nav_info.info,
+};
+
+static struct gpio_event_platform_data sapphire_keypad_data = {
+	.name = "sapphire-keypad",
+	.info = sapphire_keypad_info,
+	.info_count = ARRAY_SIZE(sapphire_keypad_info)
+};
+
+static struct platform_device sapphire_keypad_device = {
+	.name = GPIO_EVENT_DEV_NAME,
+	.id = 0,
+	.dev		= {
+		.platform_data	= &sapphire_keypad_data,
+	},
+};
+
+static int __init sapphire_init_keypad(void)
+{
+	if (!machine_is_sapphire())
+		return 0;
+
+	switch (sapphire_get_hwid()) {
+	case 0:
+		sapphire_keypad_matrix_info.keymap = sapphire_keymap0;
+		break;
+	default:
+		if(system_rev != 0x80)
+			sapphire_keypad_matrix_info.keymap = sapphire_keymap1;
+		break;
+	}
+	return platform_device_register(&sapphire_keypad_device);
+}
+
+device_initcall(sapphire_init_keypad);
+
diff --git a/arch/arm/mach-msm/board-sapphire-mmc.c b/arch/arm/mach-msm/board-sapphire-mmc.c
new file mode 100644
index 0000000..8cb913f
--- /dev/null
+++ b/arch/arm/mach-msm/board-sapphire-mmc.c
@@ -0,0 +1,486 @@
+/* linux/arch/arm/mach-msm/board-sapphire-mmc.c
+ * Copyright (C) 2007-2009 HTC Corporation.
+ * Author: Thomas Tsai <thomas_tsai@htc.com>
+ *
+ * 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.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/err.h>
+#include <linux/debugfs.h>
+
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <asm/mach-types.h>
+
+#include <mach/vreg.h>
+#include <mach/htc_pwrsink.h>
+#include <mach/proc_comm.h>
+
+#include <asm/mach/mmc.h>
+
+#include "devices.h"
+#include "gpio_chip.h"
+#include "board-sapphire.h"
+
+#define DEBUG_SDSLOT_VDD 0
+
+extern int msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat,
+			unsigned int stat_irq, unsigned long stat_irq_flags);
+
+/* ---- COMMON ---- */
+static void config_gpio_table(uint32_t *table, int len)
+{
+	int n;
+	unsigned id;
+	for (n = 0; n < len; n++) {
+		id = table[n];
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+	}
+}
+
+/* ---- SDCARD ---- */
+
+static uint32_t sdcard_on_gpio_table[] = {
+	PCOM_GPIO_CFG(62, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* CLK */
+	PCOM_GPIO_CFG(63, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* CMD */
+	PCOM_GPIO_CFG(64, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* DAT3 */
+	PCOM_GPIO_CFG(65, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* DAT2 */
+	PCOM_GPIO_CFG(66, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT1 */
+	PCOM_GPIO_CFG(67, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT0 */
+};
+
+static uint32_t sdcard_off_gpio_table[] = {
+	PCOM_GPIO_CFG(62, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CLK */
+	PCOM_GPIO_CFG(63, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CMD */
+	PCOM_GPIO_CFG(64, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */
+	PCOM_GPIO_CFG(65, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */
+	PCOM_GPIO_CFG(66, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT1 */
+	PCOM_GPIO_CFG(67, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT0 */
+};
+
+static uint opt_disable_sdcard;
+
+static int __init sapphire_disablesdcard_setup(char *str)
+{
+	int cal = simple_strtol(str, NULL, 0);
+
+	opt_disable_sdcard = cal;
+	return 1;
+}
+
+__setup("board_sapphire.disable_sdcard=", sapphire_disablesdcard_setup);
+
+static struct vreg *vreg_sdslot;	/* SD slot power */
+
+struct mmc_vdd_xlat {
+	int mask;
+	int level;
+};
+
+static struct mmc_vdd_xlat mmc_vdd_table[] = {
+	{ MMC_VDD_165_195,	1800 },
+	{ MMC_VDD_20_21,	2050 },
+	{ MMC_VDD_21_22,	2150 },
+	{ MMC_VDD_22_23,	2250 },
+	{ MMC_VDD_23_24,	2350 },
+	{ MMC_VDD_24_25,	2450 },
+	{ MMC_VDD_25_26,	2550 },
+	{ MMC_VDD_26_27,	2650 },
+	{ MMC_VDD_27_28,	2750 },
+	{ MMC_VDD_28_29,	2850 },
+	{ MMC_VDD_29_30,	2950 },
+};
+
+static unsigned int sdslot_vdd = 0xffffffff;
+static unsigned int sdslot_vreg_enabled;
+
+static uint32_t sapphire_sdslot_switchvdd(struct device *dev, unsigned int vdd)
+{
+	int i, rc;
+
+	BUG_ON(!vreg_sdslot);
+
+	if (vdd == sdslot_vdd)
+		return 0;
+
+	sdslot_vdd = vdd;
+
+	if (vdd == 0) {
+#if DEBUG_SDSLOT_VDD
+		printk(KERN_DEBUG "%s: Disabling SD slot power\n", __func__);
+#endif
+		config_gpio_table(sdcard_off_gpio_table,
+				  ARRAY_SIZE(sdcard_off_gpio_table));
+		vreg_disable(vreg_sdslot);
+		sdslot_vreg_enabled = 0;
+		return 0;
+	}
+
+	if (!sdslot_vreg_enabled) {
+		rc = vreg_enable(vreg_sdslot);
+		if (rc) {
+			printk(KERN_ERR "%s: Error enabling vreg (%d)\n",
+			       __func__, rc);
+		}
+		config_gpio_table(sdcard_on_gpio_table,
+				  ARRAY_SIZE(sdcard_on_gpio_table));
+		sdslot_vreg_enabled = 1;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(mmc_vdd_table); i++) {
+		if (mmc_vdd_table[i].mask == (1 << vdd)) {
+#if DEBUG_SDSLOT_VDD
+			printk(KERN_DEBUG "%s: Setting level to %u\n",
+				__func__, mmc_vdd_table[i].level);
+#endif
+			rc = vreg_set_level(vreg_sdslot,
+					    mmc_vdd_table[i].level);
+			if (rc) {
+				printk(KERN_ERR
+				       "%s: Error setting vreg level (%d)\n",
+				       __func__, rc);
+			}
+			return 0;
+		}
+	}
+
+	printk(KERN_ERR "%s: Invalid VDD %d specified\n", __func__, vdd);
+	return 0;
+}
+
+static unsigned int sapphire_sdslot_status(struct device *dev)
+{
+	unsigned int status;
+
+	status = (unsigned int) gpio_get_value(SAPPHIRE_GPIO_SDMC_CD_N);
+	return !status;
+}
+
+#define SAPPHIRE_MMC_VDD (MMC_VDD_165_195 | MMC_VDD_20_21 | MMC_VDD_21_22 \
+			| MMC_VDD_22_23 | MMC_VDD_23_24 | MMC_VDD_24_25 \
+			| MMC_VDD_25_26 | MMC_VDD_26_27 | MMC_VDD_27_28 \
+			| MMC_VDD_28_29 | MMC_VDD_29_30)
+
+static struct mmc_platform_data sapphire_sdslot_data = {
+	.ocr_mask	= SAPPHIRE_MMC_VDD,
+	.status		= sapphire_sdslot_status,
+	.translate_vdd	= sapphire_sdslot_switchvdd,
+};
+
+/* ---- WIFI ---- */
+
+static uint32_t wifi_on_gpio_table[] = {
+	PCOM_GPIO_CFG(51, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT3 */
+	PCOM_GPIO_CFG(52, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT2 */
+	PCOM_GPIO_CFG(53, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT1 */
+	PCOM_GPIO_CFG(54, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT0 */
+	PCOM_GPIO_CFG(55, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* CMD */
+	PCOM_GPIO_CFG(56, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* CLK */
+	PCOM_GPIO_CFG(29, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_4MA),  /* WLAN IRQ */
+};
+
+static uint32_t wifi_off_gpio_table[] = {
+	PCOM_GPIO_CFG(51, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */
+	PCOM_GPIO_CFG(52, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */
+	PCOM_GPIO_CFG(53, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT1 */
+	PCOM_GPIO_CFG(54, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT0 */
+	PCOM_GPIO_CFG(55, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CMD */
+	PCOM_GPIO_CFG(56, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CLK */
+	PCOM_GPIO_CFG(29, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA),  /* WLAN IRQ */
+};
+
+static struct vreg *vreg_wifi_osc;	/* WIFI 32khz oscilator */
+static int sapphire_wifi_cd = 0;	/* WIFI virtual 'card detect' status */
+
+static struct sdio_embedded_func wifi_func = {
+	.f_class	= SDIO_CLASS_WLAN,
+	.f_maxblksize	= 512,
+};
+
+static struct embedded_sdio_data sapphire_wifi_emb_data = {
+	.cis	= {
+		.vendor		= 0x104c,
+		.device		= 0x9066,
+		.blksize	= 512,
+		.max_dtr	= 20000000,
+	},
+	.cccr	= {
+		.multi_block	= 0,
+		.low_speed	= 0,
+		.wide_bus	= 1,
+		.high_power	= 0,
+		.high_speed	= 0,
+	},
+	.funcs	= &wifi_func,
+	.num_funcs = 1,
+};
+
+static void (*wifi_status_cb)(int card_present, void *dev_id);
+static void *wifi_status_cb_devid;
+
+static int sapphire_wifi_status_register(void (*callback)(int card_present,
+							  void *dev_id),
+					 void *dev_id)
+{
+	if (wifi_status_cb)
+		return -EAGAIN;
+	wifi_status_cb = callback;
+	wifi_status_cb_devid = dev_id;
+	return 0;
+}
+
+static unsigned int sapphire_wifi_status(struct device *dev)
+{
+	return sapphire_wifi_cd;
+}
+
+int sapphire_wifi_set_carddetect(int val)
+{
+	printk(KERN_DEBUG "%s: %d\n", __func__, val);
+	sapphire_wifi_cd = val;
+	if (wifi_status_cb)
+		wifi_status_cb(val, wifi_status_cb_devid);
+	else
+		printk(KERN_WARNING "%s: Nobody to notify\n", __func__);
+	return 0;
+}
+#ifndef CONFIG_WIFI_CONTROL_FUNC
+EXPORT_SYMBOL(sapphire_wifi_set_carddetect);
+#endif
+
+int sapphire_wifi_power_state=0;
+int sapphire_bt_power_state=0;
+
+int sapphire_wifi_power(int on)
+{
+	int rc;
+
+	printk(KERN_DEBUG "%s: %d\n", __func__, on);
+
+	if (on) {
+		config_gpio_table(wifi_on_gpio_table,
+				  ARRAY_SIZE(wifi_on_gpio_table));
+		rc = vreg_enable(vreg_wifi_osc);
+		if (rc)
+			return rc;
+		htc_pwrsink_set(PWRSINK_WIFI, 70);
+	} else {
+		config_gpio_table(wifi_off_gpio_table,
+				  ARRAY_SIZE(wifi_off_gpio_table));
+		htc_pwrsink_set(PWRSINK_WIFI, 0);
+	}
+	gpio_set_value(SAPPHIRE_GPIO_MAC_32K_EN, on);
+	mdelay(100);
+	gpio_set_value(SAPPHIRE_GPIO_WIFI_EN, on);
+	mdelay(100);
+	if (!on) {
+		if(!sapphire_bt_power_state)
+		{
+		vreg_disable(vreg_wifi_osc);
+			printk("WiFi disable vreg_wifi_osc.\n");
+		}
+		else
+			printk("WiFi shouldn't disable vreg_wifi_osc. BT is using it!!\n");
+	}
+	sapphire_wifi_power_state = on;
+	return 0;
+}
+#ifndef CONFIG_WIFI_CONTROL_FUNC
+EXPORT_SYMBOL(sapphire_wifi_power);
+#endif
+
+/* Eenable VREG_MMC pin to turn on fastclock oscillator : colin */
+int sapphire_bt_fastclock_power(int on)
+{
+	int rc;
+
+	printk(KERN_DEBUG "sapphire_bt_fastclock_power on = %d\n", on);
+	if (vreg_wifi_osc) {
+		if (on) {
+			rc = vreg_enable(vreg_wifi_osc);
+			printk(KERN_DEBUG "BT vreg_enable vreg_mmc, rc=%d\n",
+			       rc);
+			if (rc) {
+				printk("Error turn sapphire_bt_fastclock_power rc=%d\n", rc);
+				return rc;
+			}
+		} else {
+			if (!sapphire_wifi_power_state) {
+				vreg_disable(vreg_wifi_osc);
+				printk(KERN_DEBUG "BT disable vreg_wifi_osc.\n");
+			} else
+				printk(KERN_DEBUG "BT shouldn't disable vreg_wifi_osc. WiFi is using it!!\n");
+		}
+	}
+	sapphire_bt_power_state = on;
+	return 0;
+}
+EXPORT_SYMBOL(sapphire_bt_fastclock_power);
+
+static int sapphire_wifi_reset_state;
+void sapphire_wifi_reset(int on)
+{
+	printk(KERN_DEBUG "%s: %d\n", __func__, on);
+	gpio_set_value(SAPPHIRE_GPIO_WIFI_PA_RESETX, !on);
+	sapphire_wifi_reset_state = on;
+	mdelay(50);
+}
+#ifndef CONFIG_WIFI_CONTROL_FUNC
+EXPORT_SYMBOL(sapphire_wifi_reset);
+#endif
+
+static struct mmc_platform_data sapphire_wifi_data = {
+	.ocr_mask		= MMC_VDD_28_29,
+	.status			= sapphire_wifi_status,
+	.register_status_notify	= sapphire_wifi_status_register,
+	.embedded_sdio		= &sapphire_wifi_emb_data,
+};
+
+int __init sapphire_init_mmc(unsigned int sys_rev)
+{
+	wifi_status_cb = NULL;
+
+	sdslot_vreg_enabled = 0;
+
+	vreg_sdslot = vreg_get(0, "gp6");
+	if (IS_ERR(vreg_sdslot))
+		return PTR_ERR(vreg_sdslot);
+	vreg_wifi_osc = vreg_get(0, "mmc");
+	if (IS_ERR(vreg_wifi_osc))
+		return PTR_ERR(vreg_wifi_osc);
+
+	set_irq_wake(SAPPHIRE_GPIO_TO_INT(SAPPHIRE_GPIO_SDMC_CD_N), 1);
+
+	msm_add_sdcc(1, &sapphire_wifi_data, 0, 0);
+
+	if (!opt_disable_sdcard)
+		msm_add_sdcc(2, &sapphire_sdslot_data,
+			     SAPPHIRE_GPIO_TO_INT(SAPPHIRE_GPIO_SDMC_CD_N), 0);
+	else
+		printk(KERN_INFO "sapphire: SD-Card interface disabled\n");
+	return 0;
+}
+
+#if defined(CONFIG_DEBUG_FS)
+static int sapphiremmc_dbg_wifi_reset_set(void *data, u64 val)
+{
+	sapphire_wifi_reset((int) val);
+	return 0;
+}
+
+static int sapphiremmc_dbg_wifi_reset_get(void *data, u64 *val)
+{
+	*val = sapphire_wifi_reset_state;
+	return 0;
+}
+
+static int sapphiremmc_dbg_wifi_cd_set(void *data, u64 val)
+{
+	sapphire_wifi_set_carddetect((int) val);
+	return 0;
+}
+
+static int sapphiremmc_dbg_wifi_cd_get(void *data, u64 *val)
+{
+	*val = sapphire_wifi_cd;
+	return 0;
+}
+
+static int sapphiremmc_dbg_wifi_pwr_set(void *data, u64 val)
+{
+	sapphire_wifi_power((int) val);
+	return 0;
+}
+
+static int sapphiremmc_dbg_wifi_pwr_get(void *data, u64 *val)
+{
+
+	*val = sapphire_wifi_power_state;
+	return 0;
+}
+
+static int sapphiremmc_dbg_sd_pwr_set(void *data, u64 val)
+{
+	sapphire_sdslot_switchvdd(NULL, (unsigned int) val);
+	return 0;
+}
+
+static int sapphiremmc_dbg_sd_pwr_get(void *data, u64 *val)
+{
+	*val = sdslot_vdd;
+	return 0;
+}
+
+static int sapphiremmc_dbg_sd_cd_set(void *data, u64 val)
+{
+	return -ENOSYS;
+}
+
+static int sapphiremmc_dbg_sd_cd_get(void *data, u64 *val)
+{
+	*val = sapphire_sdslot_status(NULL);
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(sapphiremmc_dbg_wifi_reset_fops,
+			sapphiremmc_dbg_wifi_reset_get,
+			sapphiremmc_dbg_wifi_reset_set, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(sapphiremmc_dbg_wifi_cd_fops,
+			sapphiremmc_dbg_wifi_cd_get,
+			sapphiremmc_dbg_wifi_cd_set, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(sapphiremmc_dbg_wifi_pwr_fops,
+			sapphiremmc_dbg_wifi_pwr_get,
+			sapphiremmc_dbg_wifi_pwr_set, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(sapphiremmc_dbg_sd_pwr_fops,
+			sapphiremmc_dbg_sd_pwr_get,
+			sapphiremmc_dbg_sd_pwr_set, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(sapphiremmc_dbg_sd_cd_fops,
+			sapphiremmc_dbg_sd_cd_get,
+			sapphiremmc_dbg_sd_cd_set, "%llu\n");
+
+static int __init sapphiremmc_dbg_init(void)
+{
+	struct dentry *dent;
+
+	if (!machine_is_sapphire())
+		return 0;
+
+	dent = debugfs_create_dir("sapphiremmc_dbg", 0);
+	if (IS_ERR(dent))
+		return PTR_ERR(dent);
+
+	debugfs_create_file("wifi_reset", 0644, dent, NULL,
+			    &sapphiremmc_dbg_wifi_reset_fops);
+	debugfs_create_file("wifi_cd", 0644, dent, NULL,
+			    &sapphiremmc_dbg_wifi_cd_fops);
+	debugfs_create_file("wifi_pwr", 0644, dent, NULL,
+			    &sapphiremmc_dbg_wifi_pwr_fops);
+
+	debugfs_create_file("sd_pwr", 0644, dent, NULL,
+			    &sapphiremmc_dbg_sd_pwr_fops);
+	debugfs_create_file("sd_cd", 0644, dent, NULL,
+			    &sapphiremmc_dbg_sd_cd_fops);
+
+	return 0;
+}
+
+device_initcall(sapphiremmc_dbg_init);
+
+#endif
diff --git a/arch/arm/mach-msm/board-sapphire-panel.c b/arch/arm/mach-msm/board-sapphire-panel.c
new file mode 100644
index 0000000..1a5f63a
--- /dev/null
+++ b/arch/arm/mach-msm/board-sapphire-panel.c
@@ -0,0 +1,1272 @@
+/* linux/arch/arm/mach-msm/board-sapphire-panel.c
+ * Copyright (C) 2007-2009 HTC Corporation.
+ * Author: Thomas Tsai <thomas_tsai@htc.com>
+ *
+ * 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.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/leds.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <asm/mach-types.h>
+
+#include <mach/msm_fb.h>
+#include <mach/vreg.h>
+#include <mach/htc_pwrsink.h>
+#include <mach/proc_comm.h>
+
+#include "gpio_chip.h"
+#include "board-sapphire.h"
+#include "devices.h"
+
+#define DEBUG_SAPPHIRE_PANEL 0
+#define userid 0xD10
+
+#define VSYNC_GPIO 97
+
+enum sapphire_panel_type {
+	SAPPHIRE_PANEL_SHARP = 0,
+	SAPPHIRE_PANEL_TOPPOLY,
+	NUM_OF_SAPPHIRE_PANELS,
+};
+static int g_panel_id = -1 ;
+static int g_panel_inited = 0 ;
+
+#define SAPPHIRE_DEFAULT_BACKLIGHT_BRIGHTNESS	132
+#define GOOGLE_DEFAULT_BACKLIGHT_BRIGHTNESS 	102
+#define SDBB 					SAPPHIRE_DEFAULT_BACKLIGHT_BRIGHTNESS
+#define GDBB 					GOOGLE_DEFAULT_BACKLIGHT_BRIGHTNESS
+
+static int sapphire_backlight_off;
+static int sapphire_backlight_brightness =
+					SAPPHIRE_DEFAULT_BACKLIGHT_BRIGHTNESS;
+
+static uint8_t sapphire_backlight_last_level = 33;
+static DEFINE_MUTEX(sapphire_backlight_lock);
+
+/* Divide dimming level into 12 sections, and restrict maximum level to 27 */
+#define DIMMING_STEPS       12
+static unsigned dimming_levels[NUM_OF_SAPPHIRE_PANELS][DIMMING_STEPS] = {
+	{0, 1, 2, 3, 6, 9, 11, 13, 16, 19, 22, 25},         /* Sharp */
+	{0, 1, 2, 4, 7, 10, 13, 15, 18, 21, 24, 27},        /* Toppolly */
+};
+static unsigned pwrsink_percents[] = {0, 6, 8, 15, 26, 34, 46, 54, 65, 77, 87,
+				      100};
+
+static void sapphire_set_backlight_level(uint8_t level)
+{
+	unsigned dimming_factor = 255/DIMMING_STEPS + 1;
+	int index, new_level ;
+	unsigned percent;
+	unsigned long flags;
+	int i = 0;
+
+	/* Non-linear transform for the difference between two 
+         * kind of default backlight settings. 
+	 */
+	new_level = level<=GDBB ? 
+		level*SDBB/GDBB : (SDBB + (level-GDBB)*(255-SDBB) / (255-GDBB)) ;
+	index = new_level/dimming_factor ;
+
+#if DEBUG_SAPPHIRE_PANEL
+	printk(KERN_INFO "level=%d, new level=%d, dimming_levels[%d]=%d\n",
+		level, new_level, index, dimming_levels[g_panel_id][index]);
+#endif
+	percent = pwrsink_percents[index];
+	level = dimming_levels[g_panel_id][index];
+
+	if (sapphire_backlight_last_level == level)
+		return;
+
+	if (level == 0) {
+		gpio_set_value(27, 0);
+		msleep(2);
+	} else {
+		local_irq_save(flags);
+		if (sapphire_backlight_last_level == 0) {
+			gpio_set_value(27, 1);
+			udelay(40);
+			sapphire_backlight_last_level = 33;
+		}
+		i = (sapphire_backlight_last_level - level + 33) % 33;
+		while (i-- > 0) {
+			gpio_set_value(27, 0);
+			udelay(1);
+			gpio_set_value(27, 1);
+			udelay(1);
+		}
+		local_irq_restore(flags);
+	}
+	sapphire_backlight_last_level = level;
+	htc_pwrsink_set(PWRSINK_BACKLIGHT, percent);
+}
+
+#define MDDI_CLIENT_CORE_BASE  0x108000
+#define LCD_CONTROL_BLOCK_BASE 0x110000
+#define SPI_BLOCK_BASE         0x120000
+#define I2C_BLOCK_BASE         0x130000
+#define PWM_BLOCK_BASE         0x140000
+#define GPIO_BLOCK_BASE        0x150000
+#define SYSTEM_BLOCK1_BASE     0x160000
+#define SYSTEM_BLOCK2_BASE     0x170000
+
+
+#define	DPSUS       (MDDI_CLIENT_CORE_BASE|0x24)
+#define	SYSCLKENA   (MDDI_CLIENT_CORE_BASE|0x2C)
+#define	PWM0OFF	      (PWM_BLOCK_BASE|0x1C)
+
+#define V_VDDE2E_VDD2_GPIO 0
+#define V_VDDE2E_VDD2_GPIO_5M 89
+#define MDDI_RST_N 82
+
+#define	MDDICAP0    (MDDI_CLIENT_CORE_BASE|0x00)
+#define	MDDICAP1    (MDDI_CLIENT_CORE_BASE|0x04)
+#define	MDDICAP2    (MDDI_CLIENT_CORE_BASE|0x08)
+#define	MDDICAP3    (MDDI_CLIENT_CORE_BASE|0x0C)
+#define	MDCAPCHG    (MDDI_CLIENT_CORE_BASE|0x10)
+#define	MDCRCERC    (MDDI_CLIENT_CORE_BASE|0x14)
+#define	TTBUSSEL    (MDDI_CLIENT_CORE_BASE|0x18)
+#define	DPSET0      (MDDI_CLIENT_CORE_BASE|0x1C)
+#define	DPSET1      (MDDI_CLIENT_CORE_BASE|0x20)
+#define	DPSUS       (MDDI_CLIENT_CORE_BASE|0x24)
+#define	DPRUN       (MDDI_CLIENT_CORE_BASE|0x28)
+#define	SYSCKENA    (MDDI_CLIENT_CORE_BASE|0x2C)
+#define	TESTMODE    (MDDI_CLIENT_CORE_BASE|0x30)
+#define	FIFOMONI    (MDDI_CLIENT_CORE_BASE|0x34)
+#define	INTMONI     (MDDI_CLIENT_CORE_BASE|0x38)
+#define	MDIOBIST    (MDDI_CLIENT_CORE_BASE|0x3C)
+#define	MDIOPSET    (MDDI_CLIENT_CORE_BASE|0x40)
+#define	BITMAP0     (MDDI_CLIENT_CORE_BASE|0x44)
+#define	BITMAP1     (MDDI_CLIENT_CORE_BASE|0x48)
+#define	BITMAP2     (MDDI_CLIENT_CORE_BASE|0x4C)
+#define	BITMAP3     (MDDI_CLIENT_CORE_BASE|0x50)
+#define	BITMAP4     (MDDI_CLIENT_CORE_BASE|0x54)
+
+#define	SRST        (LCD_CONTROL_BLOCK_BASE|0x00)
+#define	PORT_ENB    (LCD_CONTROL_BLOCK_BASE|0x04)
+#define	START       (LCD_CONTROL_BLOCK_BASE|0x08)
+#define	PORT        (LCD_CONTROL_BLOCK_BASE|0x0C)
+#define	CMN         (LCD_CONTROL_BLOCK_BASE|0x10)
+#define	GAMMA       (LCD_CONTROL_BLOCK_BASE|0x14)
+#define	INTFLG      (LCD_CONTROL_BLOCK_BASE|0x18)
+#define	INTMSK      (LCD_CONTROL_BLOCK_BASE|0x1C)
+#define	MPLFBUF     (LCD_CONTROL_BLOCK_BASE|0x20)
+#define	HDE_LEFT    (LCD_CONTROL_BLOCK_BASE|0x24)
+#define	VDE_TOP     (LCD_CONTROL_BLOCK_BASE|0x28)
+#define	PXL         (LCD_CONTROL_BLOCK_BASE|0x30)
+#define	HCYCLE      (LCD_CONTROL_BLOCK_BASE|0x34)
+#define	HSW         (LCD_CONTROL_BLOCK_BASE|0x38)
+#define	HDE_START   (LCD_CONTROL_BLOCK_BASE|0x3C)
+#define	HDE_SIZE    (LCD_CONTROL_BLOCK_BASE|0x40)
+#define	VCYCLE      (LCD_CONTROL_BLOCK_BASE|0x44)
+#define	VSW         (LCD_CONTROL_BLOCK_BASE|0x48)
+#define	VDE_START   (LCD_CONTROL_BLOCK_BASE|0x4C)
+#define	VDE_SIZE    (LCD_CONTROL_BLOCK_BASE|0x50)
+#define	WAKEUP      (LCD_CONTROL_BLOCK_BASE|0x54)
+#define	WSYN_DLY    (LCD_CONTROL_BLOCK_BASE|0x58)
+#define	REGENB      (LCD_CONTROL_BLOCK_BASE|0x5C)
+#define	VSYNIF      (LCD_CONTROL_BLOCK_BASE|0x60)
+#define	WRSTB       (LCD_CONTROL_BLOCK_BASE|0x64)
+#define	RDSTB       (LCD_CONTROL_BLOCK_BASE|0x68)
+#define	ASY_DATA    (LCD_CONTROL_BLOCK_BASE|0x6C)
+#define	ASY_DATB    (LCD_CONTROL_BLOCK_BASE|0x70)
+#define	ASY_DATC    (LCD_CONTROL_BLOCK_BASE|0x74)
+#define	ASY_DATD    (LCD_CONTROL_BLOCK_BASE|0x78)
+#define	ASY_DATE    (LCD_CONTROL_BLOCK_BASE|0x7C)
+#define	ASY_DATF    (LCD_CONTROL_BLOCK_BASE|0x80)
+#define	ASY_DATG    (LCD_CONTROL_BLOCK_BASE|0x84)
+#define	ASY_DATH    (LCD_CONTROL_BLOCK_BASE|0x88)
+#define	ASY_CMDSET  (LCD_CONTROL_BLOCK_BASE|0x8C)
+
+#define	SSICTL      (SPI_BLOCK_BASE|0x00)
+#define	SSITIME     (SPI_BLOCK_BASE|0x04)
+#define	SSITX       (SPI_BLOCK_BASE|0x08)
+#define	SSIRX       (SPI_BLOCK_BASE|0x0C)
+#define	SSIINTC     (SPI_BLOCK_BASE|0x10)
+#define	SSIINTS     (SPI_BLOCK_BASE|0x14)
+#define	SSIDBG1     (SPI_BLOCK_BASE|0x18)
+#define	SSIDBG2     (SPI_BLOCK_BASE|0x1C)
+#define	SSIID       (SPI_BLOCK_BASE|0x20)
+
+#define	WKREQ       (SYSTEM_BLOCK1_BASE|0x00)
+#define	CLKENB      (SYSTEM_BLOCK1_BASE|0x04)
+#define	DRAMPWR     (SYSTEM_BLOCK1_BASE|0x08)
+#define	INTMASK     (SYSTEM_BLOCK1_BASE|0x0C)
+#define	GPIOSEL     (SYSTEM_BLOCK2_BASE|0x00)
+
+#define	GPIODATA    (GPIO_BLOCK_BASE|0x00)
+#define	GPIODIR     (GPIO_BLOCK_BASE|0x04)
+#define	GPIOIS      (GPIO_BLOCK_BASE|0x08)
+#define	GPIOIBE     (GPIO_BLOCK_BASE|0x0C)
+#define	GPIOIEV     (GPIO_BLOCK_BASE|0x10)
+#define	GPIOIE      (GPIO_BLOCK_BASE|0x14)
+#define	GPIORIS     (GPIO_BLOCK_BASE|0x18)
+#define	GPIOMIS     (GPIO_BLOCK_BASE|0x1C)
+#define	GPIOIC      (GPIO_BLOCK_BASE|0x20)
+#define	GPIOOMS     (GPIO_BLOCK_BASE|0x24)
+#define	GPIOPC      (GPIO_BLOCK_BASE|0x28)
+#define	GPIOID      (GPIO_BLOCK_BASE|0x30)
+
+#define SPI_WRITE(reg, val) \
+	{ SSITX,        0x00010000 | (((reg) & 0xff) << 8) | ((val) & 0xff) }, \
+	{ 0, 5 },
+
+#define SPI_WRITE1(reg) \
+	{ SSITX,        (reg) & 0xff }, \
+	{ 0, 5 },
+
+struct mddi_table {
+	uint32_t reg;
+	uint32_t value;
+};
+static struct mddi_table mddi_toshiba_init_table[] = {
+	{ DPSET0,       0x09e90046 },
+	{ DPSET1,       0x00000118 },
+	{ DPSUS,        0x00000000 },
+	{ DPRUN,        0x00000001 },
+	{ 1,            14         }, /* msleep 14 */
+	{ SYSCKENA,     0x00000001 },
+	/*{ CLKENB,       0x000000EF } */
+	{ CLKENB,       0x0000A1EF },  /*    # SYS.CLKENB  # Enable clocks for each module (without DCLK , i2cCLK) */
+	/*{ CLKENB,       0x000025CB },  Clock enable register */
+
+	{ GPIODATA,     0x02000200 },  /*   # GPI .GPIODATA  # GPIO2(RESET_LCD_N) set to 0 , GPIO3(eDRAM_Power) set to 0 */
+	{ GPIODIR,      0x000030D  },  /* 24D   # GPI .GPIODIR  # Select direction of GPIO port (0,2,3,6,9 output) */
+	{ GPIOSEL,      0/*0x00000173*/},  /*   # SYS.GPIOSEL  # GPIO port multiplexing control */
+	{ GPIOPC,       0x03C300C0 },  /*   # GPI .GPIOPC  # GPIO2,3 PD cut */
+	{ WKREQ,        0x00000000 },  /*   # SYS.WKREQ  # Wake-up request event is VSYNC alignment */
+
+	{ GPIOIBE,      0x000003FF },
+	{ GPIOIS,       0x00000000 },
+	{ GPIOIC,       0x000003FF },
+	{ GPIOIE,       0x00000000 },
+
+	{ GPIODATA,     0x00040004 },  /*   # GPI .GPIODATA  # eDRAM VD supply */
+	{ 1,            1          }, /* msleep 1 */
+	{ GPIODATA,     0x02040004 },  /*   # GPI .GPIODATA  # eDRAM VD supply */
+	{ DRAMPWR,      0x00000001 }, /* eDRAM power */
+};
+
+static struct mddi_table mddi_toshiba_panel_init_table[] = {
+	{ SRST,         0x00000003 }, /* FIFO/LCDC not reset */
+	{ PORT_ENB,     0x00000001 }, /* Enable sync. Port */
+	{ START,        0x00000000 }, /* To stop operation */
+	/*{ START,        0x00000001 }, To start operation */
+	{ PORT,         0x00000004 }, /* Polarity of VS/HS/DE. */
+	{ CMN,          0x00000000 },
+	{ GAMMA,        0x00000000 }, /* No Gamma correction */
+	{ INTFLG,       0x00000000 }, /* VSYNC interrupt flag clear/status */
+	{ INTMSK,       0x00000000 }, /* VSYNC interrupt mask is off. */
+	{ MPLFBUF,      0x00000000 }, /* Select frame buffer's base address. */
+	{ HDE_LEFT,     0x00000000 }, /* The value of HDE_LEFT. */
+	{ VDE_TOP,      0x00000000 }, /* The value of VDE_TPO. */
+	{ PXL,          0x00000001 }, /* 1. RGB666 */
+				      /* 2. Data is valid from 1st frame of beginning. */
+	{ HDE_START,    0x00000006 }, /* HDE_START= 14 PCLK */
+	{ HDE_SIZE,     0x0000009F }, /* HDE_SIZE=320 PCLK */
+	{ HSW,          0x00000004 }, /* HSW= 10 PCLK */
+	{ VSW,          0x00000001 }, /* VSW=2 HCYCLE */
+	{ VDE_START,    0x00000003 }, /* VDE_START=4 HCYCLE */
+	{ VDE_SIZE,     0x000001DF }, /* VDE_SIZE=480 HCYCLE */
+	{ WAKEUP,       0x000001e2 }, /* Wakeup position in VSYNC mode. */
+	{ WSYN_DLY,     0x00000000 }, /* Wakeup position in VSIN mode. */
+	{ REGENB,       0x00000001 }, /* Set 1 to enable to change the value of registers. */
+	{ CLKENB,       0x000025CB }, /* Clock enable register */
+
+	{ SSICTL,       0x00000170 }, /* SSI control register */
+	{ SSITIME,      0x00000250 }, /* SSI timing control register */
+	{ SSICTL,       0x00000172 }, /* SSI control register */
+};
+
+
+static struct mddi_table mddi_sharp_init_table[] = {
+	{ VCYCLE,       0x000001eb },
+	{ HCYCLE,       0x000000ae },
+	{ REGENB,       0x00000001 }, /* Set 1 to enable to change the value of registers. */
+	{ GPIODATA,     0x00040000 }, /* GPIO2 low */
+	{ GPIODIR,      0x00000004 }, /* GPIO2 out */
+	{ 1,            1          }, /* msleep 1 */
+	{ GPIODATA,     0x00040004 }, /* GPIO2 high */
+	{ 1,            10         }, /* msleep 10 */
+	SPI_WRITE(0x5f, 0x01)
+	SPI_WRITE1(0x11)
+	{ 1,            200        }, /* msleep 200 */
+	SPI_WRITE1(0x29)
+	SPI_WRITE1(0xde)
+	{ START,        0x00000001 }, /* To start operation */
+};
+
+static struct mddi_table mddi_sharp_deinit_table[] = {
+	{ 1,            200        }, /* msleep 200 */
+	SPI_WRITE(0x10, 0x1)
+	{ 1,            100        }, /* msleep 100 */
+	{ GPIODATA,     0x00040004 }, /* GPIO2 high */
+	{ GPIODIR,      0x00000004 }, /* GPIO2 out */
+	{ GPIODATA,     0x00040000 }, /* GPIO2 low */
+	{ 1,            10         }, /* msleep 10 */
+};
+
+static struct mddi_table mddi_tpo_init_table[] = {
+	{ VCYCLE,       0x000001e5 },
+	{ HCYCLE,       0x000000ac },
+	{ REGENB,       0x00000001 }, /* Set 1 to enable to change the value of registers. */
+	{ 0,            20         }, /* udelay 20 */
+	{ GPIODATA,     0x00000004 }, /* GPIO2 high */
+	{ GPIODIR,      0x00000004 }, /* GPIO2 out */
+	{ 0,            20         }, /* udelay 20 */
+
+	SPI_WRITE(0x08, 0x01)
+	{ 0,            500        }, /* udelay 500 */
+	SPI_WRITE(0x08, 0x00)
+	SPI_WRITE(0x02, 0x00)
+	SPI_WRITE(0x03, 0x04)
+	SPI_WRITE(0x04, 0x0e)
+	SPI_WRITE(0x09, 0x02)
+	SPI_WRITE(0x0b, 0x08)
+	SPI_WRITE(0x0c, 0x53)
+	SPI_WRITE(0x0d, 0x01)
+	SPI_WRITE(0x0e, 0xe0)
+	SPI_WRITE(0x0f, 0x01)
+	SPI_WRITE(0x10, 0x58)
+	SPI_WRITE(0x20, 0x1e)
+	SPI_WRITE(0x21, 0x0a)
+	SPI_WRITE(0x22, 0x0a)
+	SPI_WRITE(0x23, 0x1e)
+	SPI_WRITE(0x25, 0x32)
+	SPI_WRITE(0x26, 0x00)
+	SPI_WRITE(0x27, 0xac)
+	SPI_WRITE(0x29, 0x06)
+	SPI_WRITE(0x2a, 0xa4)
+	SPI_WRITE(0x2b, 0x45)
+	SPI_WRITE(0x2c, 0x45)
+	SPI_WRITE(0x2d, 0x15)
+	SPI_WRITE(0x2e, 0x5a)
+	SPI_WRITE(0x2f, 0xff)
+	SPI_WRITE(0x30, 0x6b)
+	SPI_WRITE(0x31, 0x0d)
+	SPI_WRITE(0x32, 0x48)
+	SPI_WRITE(0x33, 0x82)
+	SPI_WRITE(0x34, 0xbd)
+	SPI_WRITE(0x35, 0xe7)
+	SPI_WRITE(0x36, 0x18)
+	SPI_WRITE(0x37, 0x94)
+	SPI_WRITE(0x38, 0x01)
+	SPI_WRITE(0x39, 0x5d)
+	SPI_WRITE(0x3a, 0xae)
+	SPI_WRITE(0x3b, 0xff)
+	SPI_WRITE(0x07, 0x09)
+	{ 0,            10         }, /* udelay 10 */
+	{ START,        0x00000001 }, /* To start operation */
+};
+
+static struct mddi_table mddi_tpo_deinit_table[] = {
+	SPI_WRITE(0x07, 0x19)
+	{ START,        0x00000000 }, /* To stop operation */
+	{ GPIODATA,     0x00040004 }, /* GPIO2 high */
+	{ GPIODIR,      0x00000004 }, /* GPIO2 out */
+	{ GPIODATA,     0x00040000 }, /* GPIO2 low */
+	{ 0,            5        }, /* usleep 5 */
+};
+
+
+#define GPIOSEL_VWAKEINT (1U << 0)
+#define INTMASK_VWAKEOUT (1U << 0)
+
+static void sapphire_process_mddi_table(
+				     struct msm_mddi_client_data *client_data,
+				     const struct mddi_table *table,
+				     size_t count)
+{
+	int i;
+	for (i = 0; i < count; i++) {
+		uint32_t reg = table[i].reg;
+		uint32_t value = table[i].value;
+
+		if (reg == 0)
+			udelay(value);
+		else if (reg == 1)
+			msleep(value);
+		else
+			client_data->remote_write(client_data, value, reg);
+	}
+}
+
+static struct vreg *vreg_lcm_2v85;
+
+static void sapphire_mddi_power_client(struct msm_mddi_client_data *client_data,
+				    int on)
+{
+	unsigned id, on_off;
+#if DEBUG_SAPPHIRE_PANEL
+	printk(KERN_INFO "sapphire_mddi_client_power:%d\r\n", on);
+#endif
+	if (on) {
+		on_off = 0;
+		id = PM_VREG_PDOWN_MDDI_ID;
+		msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
+
+		gpio_set_value(SAPPHIRE_MDDI_1V5_EN, 1);
+		mdelay(5); /* delay time >5ms and <10ms */
+
+		if  (is_12pin_camera())
+			gpio_set_value(V_VDDE2E_VDD2_GPIO_5M, 1);
+		else
+			gpio_set_value(V_VDDE2E_VDD2_GPIO, 1);
+
+		gpio_set_value(SAPPHIRE_GPIO_MDDI_32K_EN, 1);
+		msleep(3);
+		id = PM_VREG_PDOWN_AUX_ID;
+		msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
+		vreg_enable(vreg_lcm_2v85);
+		msleep(3);
+	} else {
+		gpio_set_value(SAPPHIRE_GPIO_MDDI_32K_EN, 0);
+		gpio_set_value(MDDI_RST_N, 0);
+		msleep(10);
+		vreg_disable(vreg_lcm_2v85);
+		on_off = 1;
+		id = PM_VREG_PDOWN_AUX_ID;
+		msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
+		msleep(5);
+		if (is_12pin_camera())
+			gpio_set_value(V_VDDE2E_VDD2_GPIO_5M, 0);
+		else
+			gpio_set_value(V_VDDE2E_VDD2_GPIO, 0);
+
+		msleep(200);
+		gpio_set_value(SAPPHIRE_MDDI_1V5_EN, 0);
+		id = PM_VREG_PDOWN_MDDI_ID;
+		msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
+	}
+}
+
+static int sapphire_mddi_toshiba_client_init(
+			struct msm_mddi_bridge_platform_data *bridge_data,
+			struct msm_mddi_client_data *client_data)
+{
+	int panel_id;
+
+	/* Set the MDDI_RST_N accroding to MDDI client repectively(
+	 * been set in sapphire_mddi_power_client() originally)
+	 */
+	gpio_set_value(MDDI_RST_N, 1);
+	msleep(10);
+
+	client_data->auto_hibernate(client_data, 0);
+	sapphire_process_mddi_table(client_data, mddi_toshiba_init_table,
+				 ARRAY_SIZE(mddi_toshiba_init_table));
+	client_data->auto_hibernate(client_data, 1);
+	g_panel_id = panel_id =
+		(client_data->remote_read(client_data, GPIODATA) >> 4) & 3;
+	if (panel_id > 1) {
+#if DEBUG_SAPPHIRE_PANEL
+		printk(KERN_ERR "unknown panel id at mddi_enable\n");
+#endif
+		return -1;
+	}
+	return 0;
+}
+
+static int sapphire_mddi_toshiba_client_uninit(
+			struct msm_mddi_bridge_platform_data *bridge_data,
+			struct msm_mddi_client_data *client_data)
+{
+	gpio_set_value(MDDI_RST_N, 0);
+	msleep(10);
+
+	return 0;
+}
+
+static int sapphire_mddi_panel_unblank(
+			struct msm_mddi_bridge_platform_data *bridge_data,
+			struct msm_mddi_client_data *client_data)
+{
+	int panel_id, ret = 0;
+
+	sapphire_set_backlight_level(0);
+	client_data->auto_hibernate(client_data, 0);
+	sapphire_process_mddi_table(client_data, mddi_toshiba_panel_init_table,
+		ARRAY_SIZE(mddi_toshiba_panel_init_table));
+	panel_id = (client_data->remote_read(client_data, GPIODATA) >> 4) & 3;
+	switch (panel_id) {
+	case 0:
+#if DEBUG_SAPPHIRE_PANEL
+		printk(KERN_DEBUG "init sharp panel\n");
+#endif
+		sapphire_process_mddi_table(client_data,
+					 mddi_sharp_init_table,
+					 ARRAY_SIZE(mddi_sharp_init_table));
+		break;
+	case 1:
+#if DEBUG_SAPPHIRE_PANEL
+		printk(KERN_DEBUG "init tpo panel\n");
+#endif
+		sapphire_process_mddi_table(client_data,
+					 mddi_tpo_init_table,
+					 ARRAY_SIZE(mddi_tpo_init_table));
+		break;
+	default:
+
+		printk(KERN_DEBUG "unknown panel_id: %d\n", panel_id);
+		ret = -1;
+	};
+	mutex_lock(&sapphire_backlight_lock);
+	sapphire_set_backlight_level(sapphire_backlight_brightness);
+	sapphire_backlight_off = 0;
+	mutex_unlock(&sapphire_backlight_lock);
+	client_data->auto_hibernate(client_data, 1);
+	/* reenable vsync */
+	client_data->remote_write(client_data, GPIOSEL_VWAKEINT,
+				  GPIOSEL);
+	client_data->remote_write(client_data, INTMASK_VWAKEOUT,
+				  INTMASK);
+	return ret;
+
+}
+
+static int sapphire_mddi_panel_blank(
+			struct msm_mddi_bridge_platform_data *bridge_data,
+			struct msm_mddi_client_data *client_data)
+{
+	int panel_id, ret = 0;
+
+	panel_id = (client_data->remote_read(client_data, GPIODATA) >> 4) & 3;
+	client_data->auto_hibernate(client_data, 0);
+	switch (panel_id) {
+	case 0:
+		printk(KERN_DEBUG "deinit sharp panel\n");
+		sapphire_process_mddi_table(client_data,
+					 mddi_sharp_deinit_table,
+					 ARRAY_SIZE(mddi_sharp_deinit_table));
+		break;
+	case 1:
+		printk(KERN_DEBUG "deinit tpo panel\n");
+		sapphire_process_mddi_table(client_data,
+					 mddi_tpo_deinit_table,
+					 ARRAY_SIZE(mddi_tpo_deinit_table));
+		break;
+	default:
+		printk(KERN_DEBUG "unknown panel_id: %d\n", panel_id);
+		ret = -1;
+	};
+	client_data->auto_hibernate(client_data, 1);
+	mutex_lock(&sapphire_backlight_lock);
+	sapphire_set_backlight_level(0);
+	sapphire_backlight_off = 1;
+	mutex_unlock(&sapphire_backlight_lock);
+	client_data->remote_write(client_data, 0, SYSCLKENA);
+	client_data->remote_write(client_data, 1, DPSUS);
+
+	return ret;
+}
+
+
+/* Initial sequence of sharp panel with Novatek NT35399 MDDI client */
+static const struct mddi_table sharp2_init_table[] = {
+	{ 0x02A0, 0x00 },
+	{ 0x02A1, 0x00 },
+	{ 0x02A2, 0x3F },
+	{ 0x02A3, 0x01 },
+	{ 0x02B0, 0x00 },
+	{ 0x02B1, 0x00 },
+	{ 0x02B2, 0xDF },
+	{ 0x02B3, 0x01 },
+	{ 0x02D0, 0x00 },
+	{ 0x02D1, 0x00 },
+	{ 0x02D2, 0x00 },
+	{ 0x02D3, 0x00 },
+	{ 0x0350, 0x80 },	/* Set frame tearing effect(FTE) position */
+	{ 0x0351, 0x00 },
+	{ 0x0360, 0x30 },
+	{ 0x0361, 0xC1 },
+	{ 0x0362, 0x00 },
+	{ 0x0370, 0x00 },
+	{ 0x0371, 0xEF },
+	{ 0x0372, 0x01 },
+
+	{ 0x0B00, 0x10 },
+
+	{ 0x0B10, 0x00 },
+	{ 0x0B20, 0x22 },
+	{ 0x0B30, 0x46 },
+	{ 0x0B40, 0x07 },
+	{ 0x0B41, 0x1C },
+	{ 0x0B50, 0x0F },
+	{ 0x0B51, 0x7A },
+	{ 0x0B60, 0x16 },
+	{ 0x0B70, 0x0D },
+	{ 0x0B80, 0x04 },
+	{ 0x0B90, 0x07 },
+	{ 0x0BA0, 0x04 },
+	{ 0x0BA1, 0x86 },
+	{ 0x0BB0, 0xFF },
+	{ 0x0BB1, 0x01 },
+	{ 0x0BB2, 0xF7 },
+	{ 0x0BB3, 0x01 },
+	{ 0x0BC0, 0x00 },
+	{ 0x0BC1, 0x00 },
+	{ 0x0BC2, 0x00 },
+	{ 0x0BC3, 0x00 },
+	{ 0x0BE0, 0x01 },
+	{ 0x0BE1, 0x3F },
+
+	{ 0x0BF0, 0x03 },
+
+	{ 0x0C10, 0x02 },
+
+	{ 0x0C30, 0x22 },
+	{ 0x0C31, 0x20 },
+	{ 0x0C40, 0x48 },
+	{ 0x0C41, 0x06 },
+
+	{ 0xE00, 0x0028},
+	{ 0xE01, 0x002F},
+	{ 0xE02, 0x0032},
+	{ 0xE03, 0x000A},
+	{ 0xE04, 0x0023},
+	{ 0xE05, 0x0024},
+	{ 0xE06, 0x0022},
+	{ 0xE07, 0x0012},
+	{ 0xE08, 0x000D},
+	{ 0xE09, 0x0035},
+	{ 0xE0A, 0x000E},
+	{ 0xE0B, 0x001A},
+	{ 0xE0C, 0x003C},
+	{ 0xE0D, 0x003A},
+	{ 0xE0E, 0x0050},
+	{ 0xE0F, 0x0069},
+	{ 0xE10, 0x0006},
+	{ 0xE11, 0x001F},
+	{ 0xE12, 0x0035},
+	{ 0xE13, 0x0020},
+	{ 0xE14, 0x0043},
+	{ 0xE15, 0x0030},
+	{ 0xE16, 0x003C},
+	{ 0xE17, 0x0010},
+	{ 0xE18, 0x0009},
+	{ 0xE19, 0x0051},
+	{ 0xE1A, 0x001D},
+	{ 0xE1B, 0x003C},
+	{ 0xE1C, 0x0053},
+	{ 0xE1D, 0x0041},
+	{ 0xE1E, 0x0045},
+	{ 0xE1F, 0x004B},
+	{ 0xE20, 0x000A},
+	{ 0xE21, 0x0014},
+	{ 0xE22, 0x001C},
+	{ 0xE23, 0x0013},
+	{ 0xE24, 0x002E},
+	{ 0xE25, 0x0029},
+	{ 0xE26, 0x001B},
+	{ 0xE27, 0x0014},
+	{ 0xE28, 0x000E},
+	{ 0xE29, 0x0032},
+	{ 0xE2A, 0x000D},
+	{ 0xE2B, 0x001B},
+	{ 0xE2C, 0x0033},
+	{ 0xE2D, 0x0033},
+	{ 0xE2E, 0x005B},
+	{ 0xE2F, 0x0069},
+	{ 0xE30, 0x0006},
+	{ 0xE31, 0x0014},
+	{ 0xE32, 0x003D},
+	{ 0xE33, 0x0029},
+	{ 0xE34, 0x0042},
+	{ 0xE35, 0x0032},
+	{ 0xE36, 0x003F},
+	{ 0xE37, 0x000E},
+	{ 0xE38, 0x0008},
+	{ 0xE39, 0x0059},
+	{ 0xE3A, 0x0015},
+	{ 0xE3B, 0x002E},
+	{ 0xE3C, 0x0049},
+	{ 0xE3D, 0x0058},
+	{ 0xE3E, 0x0061},
+	{ 0xE3F, 0x006B},
+	{ 0xE40, 0x000A},
+	{ 0xE41, 0x001A},
+	{ 0xE42, 0x0022},
+	{ 0xE43, 0x0014},
+	{ 0xE44, 0x002F},
+	{ 0xE45, 0x002A},
+	{ 0xE46, 0x001A},
+	{ 0xE47, 0x0014},
+	{ 0xE48, 0x000E},
+	{ 0xE49, 0x002F},
+	{ 0xE4A, 0x000F},
+	{ 0xE4B, 0x001B},
+	{ 0xE4C, 0x0030},
+	{ 0xE4D, 0x002C},
+	{ 0xE4E, 0x0051},
+	{ 0xE4F, 0x0069},
+	{ 0xE50, 0x0006},
+	{ 0xE51, 0x001E},
+	{ 0xE52, 0x0043},
+	{ 0xE53, 0x002F},
+	{ 0xE54, 0x0043},
+	{ 0xE55, 0x0032},
+	{ 0xE56, 0x0043},
+	{ 0xE57, 0x000D},
+	{ 0xE58, 0x0008},
+	{ 0xE59, 0x0059},
+	{ 0xE5A, 0x0016},
+	{ 0xE5B, 0x0030},
+	{ 0xE5C, 0x004B},
+	{ 0xE5D, 0x0051},
+	{ 0xE5E, 0x005A},
+	{ 0xE5F, 0x006B},
+
+        { 0x0290, 0x01 },
+};
+
+#undef TPO2_ONE_GAMMA
+/* Initial sequence of TPO panel with Novatek NT35399 MDDI client */
+
+static const struct mddi_table tpo2_init_table[] = {
+	/* Panel interface control */
+	{ 0xB30, 0x44 },
+	{ 0xB40, 0x00 },
+	{ 0xB41, 0x87 },
+	{ 0xB50, 0x06 },
+	{ 0xB51, 0x7B },
+	{ 0xB60, 0x0E },
+	{ 0xB70, 0x0F },
+	{ 0xB80, 0x03 },
+	{ 0xB90, 0x00 },
+	{ 0x350, 0x70 },        /* FTE is at line 0x70 */
+
+	/* Entry Mode */
+	{ 0x360, 0x30 },
+	{ 0x361, 0xC1 },
+	{ 0x362, 0x04 },
+
+/* 0x2 for gray scale gamma correction, 0x12 for RGB gamma correction  */
+#ifdef TPO2_ONE_GAMMA
+	{ 0xB00, 0x02 },
+#else
+	{ 0xB00, 0x12 },
+#endif
+	/* Driver output control */
+	{ 0x371, 0xEF },
+	{ 0x372, 0x03 },
+
+	/* DCDC on glass control */
+	{ 0xC31, 0x10 },
+	{ 0xBA0, 0x00 },
+	{ 0xBA1, 0x86 },
+
+	/* VCOMH voltage control */
+	{ 0xC50, 0x3b },
+
+	/* Special function control */
+	{ 0xC10, 0x82 },
+
+	/* Power control */
+	{ 0xC40, 0x44 },
+	{ 0xC41, 0x02 },
+
+	/* Source output control */
+	{ 0xBE0, 0x01 },
+	{ 0xBE1, 0x00 },
+
+	/* Windows address setting */
+	{ 0x2A0, 0x00 },
+	{ 0x2A1, 0x00 },
+	{ 0x2A2, 0x3F },
+	{ 0x2A3, 0x01 },
+	{ 0x2B0, 0x00 },
+	{ 0x2B1, 0x00 },
+	{ 0x2B2, 0xDF },
+	{ 0x2B3, 0x01 },
+
+	/* RAM address setting */
+	{ 0x2D0, 0x00 },
+	{ 0x2D1, 0x00 },
+	{ 0x2D2, 0x00 },
+	{ 0x2D3, 0x00 },
+
+	{ 0xF20, 0x55 },
+	{ 0xF21, 0xAA },
+	{ 0xF22, 0x66 },
+	{ 0xF57, 0x45 },
+
+/*
+ * The NT35399 provides gray or RGB gamma correction table,
+ * which determinated by register-0xb00, and following table
+ */
+#ifdef TPO2_ONE_GAMMA
+	/* Positive Gamma setting */
+	{ 0xE00, 0x04 },
+	{ 0xE01, 0x12 },
+	{ 0xE02, 0x18 },
+	{ 0xE03, 0x10 },
+	{ 0xE04, 0x29 },
+	{ 0xE05, 0x26 },
+	{ 0xE06, 0x1f },
+	{ 0xE07, 0x11 },
+	{ 0xE08, 0x0c },
+	{ 0xE09, 0x3a },
+	{ 0xE0A, 0x0d },
+	{ 0xE0B, 0x28 },
+	{ 0xE0C, 0x40 },
+	{ 0xE0D, 0x4e },
+	{ 0xE0E, 0x6f },
+	{ 0xE0F, 0x5E },
+
+	/* Negative Gamma setting */
+	{ 0xE10, 0x0B },
+	{ 0xE11, 0x00 },
+	{ 0xE12, 0x00 },
+	{ 0xE13, 0x1F },
+	{ 0xE14, 0x4b },
+	{ 0xE15, 0x33 },
+	{ 0xE16, 0x13 },
+	{ 0xE17, 0x12 },
+	{ 0xE18, 0x0d },
+	{ 0xE19, 0x2f },
+	{ 0xE1A, 0x16 },
+	{ 0xE1B, 0x2e },
+	{ 0xE1C, 0x49 },
+	{ 0xE1D, 0x41 },
+	{ 0xE1E, 0x46 },
+	{ 0xE1F, 0x55 },
+#else
+	/* Red Positive Gamma  */
+	{ 0xE00, 0x0f },
+	{ 0xE01, 0x19 },
+	{ 0xE02, 0x22 },
+	{ 0xE03, 0x0b },
+	{ 0xE04, 0x23 },
+	{ 0xE05, 0x23 },
+	{ 0xE06, 0x14 },
+	{ 0xE07, 0x13 },
+	{ 0xE08, 0x0f },
+	{ 0xE09, 0x2a },
+	{ 0xE0A, 0x0d },
+	{ 0xE0B, 0x26 },
+	{ 0xE0C, 0x43 },
+	{ 0xE0D, 0x20 },
+	{ 0xE0E, 0x2a },
+	{ 0xE0F, 0x5c },
+
+	/* Red Negative Gamma   */
+	{ 0xE10, 0x0d },
+	{ 0xE11, 0x45 },
+	{ 0xE12, 0x4c },
+	{ 0xE13, 0x1c },
+	{ 0xE14, 0x4d },
+	{ 0xE15, 0x33 },
+	{ 0xE16, 0x23 },
+	{ 0xE17, 0x0f },
+	{ 0xE18, 0x0b },
+	{ 0xE19, 0x3a },
+	{ 0xE1A, 0x19 },
+	{ 0xE1B, 0x32 },
+	{ 0xE1C, 0x4e },
+	{ 0xE1D, 0x37 },
+	{ 0xE1E, 0x38 },
+	{ 0xE1F, 0x3b },
+
+	/* Green Positive Gamma */
+	{ 0xE20, 0x00 },
+	{ 0xE21, 0x09 },
+	{ 0xE22, 0x10 },
+	{ 0xE23, 0x0f },
+	{ 0xE24, 0x29 },
+	{ 0xE25, 0x23 },
+	{ 0xE26, 0x0b },
+	{ 0xE27, 0x14 },
+	{ 0xE28, 0x12 },
+	{ 0xE29, 0x25 },
+	{ 0xE2A, 0x12 },
+	{ 0xE2B, 0x2f },
+	{ 0xE2C, 0x43 },
+	{ 0xE2D, 0x2d },
+	{ 0xE2E, 0x52 },
+	{ 0xE2F, 0x61 },
+
+	/* Green Negative Gamma */
+	{ 0xE30, 0x08 },
+	{ 0xE31, 0x1d },
+	{ 0xE32, 0x3f },
+	{ 0xE33, 0x1c },
+	{ 0xE34, 0x44 },
+	{ 0xE35, 0x2e },
+	{ 0xE36, 0x28 },
+	{ 0xE37, 0x0c },
+	{ 0xE38, 0x0a },
+	{ 0xE39, 0x42 },
+	{ 0xE3A, 0x17 },
+	{ 0xE3B, 0x30 },
+	{ 0xE3C, 0x4b },
+	{ 0xE3D, 0x3f },
+	{ 0xE3E, 0x43 },
+	{ 0xE3F, 0x45 },
+
+	/* Blue Positive Gamma */
+	{ 0xE40, 0x32 },
+	{ 0xE41, 0x32 },
+	{ 0xE42, 0x31 },
+	{ 0xE43, 0x06 },
+	{ 0xE44, 0x08 },
+	{ 0xE45, 0x0d },
+	{ 0xE46, 0x04 },
+	{ 0xE47, 0x14 },
+	{ 0xE48, 0x0f },
+	{ 0xE49, 0x1d },
+	{ 0xE4A, 0x1a },
+	{ 0xE4B, 0x39 },
+	{ 0xE4C, 0x4c },
+	{ 0xE4D, 0x1e },
+	{ 0xE4E, 0x43 },
+	{ 0xE4F, 0x61 },
+
+	/* Blue Negative Gamma */
+	{ 0xE50, 0x08 },
+	{ 0xE51, 0x2c },
+	{ 0xE52, 0x4e },
+	{ 0xE53, 0x13 },
+	{ 0xE54, 0x3a },
+	{ 0xE55, 0x26 },
+	{ 0xE56, 0x30 },
+	{ 0xE57, 0x0f },
+	{ 0xE58, 0x0a },
+	{ 0xE59, 0x49 },
+	{ 0xE5A, 0x34 },
+	{ 0xE5B, 0x4a },
+	{ 0xE5C, 0x53 },
+	{ 0xE5D, 0x28 },
+	{ 0xE5E, 0x26 },
+	{ 0xE5F, 0x27 },
+
+#endif
+	/* Sleep in mode 		*/
+	{ 0x110, 0x00 },
+	{ 0x1,   0x23 },
+	/* Display on mode 		*/
+	{ 0x290, 0x00 },
+	{ 0x1,   0x27 },
+	/* Driver output control	*/
+	{ 0x372, 0x01 },
+	{ 0x1,   0x40 },
+	/* Display on mode		*/
+	{ 0x290, 0x01 },
+};
+
+static const struct mddi_table tpo2_display_on[] = {
+	{ 0x290, 0x01 },
+};
+
+static const struct mddi_table tpo2_display_off[] = {
+	{ 0x110, 0x01 },
+	{ 0x290, 0x00 },
+	{ 0x1,   100 },
+};
+
+static const struct mddi_table tpo2_power_off[] = {
+	{ 0x0110, 0x01 },
+};
+
+static int nt35399_detect_panel(struct msm_mddi_client_data *client_data)
+{
+	int id = -1, i ;
+
+	/* If the MDDI client is failed to report the panel ID,
+	 * perform retrial 5 times.
+	 */
+	for( i=0; i < 5; i++ ) {
+		client_data->remote_write(client_data, 0, 0x110);
+		msleep(5);
+		id = client_data->remote_read(client_data, userid) ;
+		if( id == 0 || id == 1 ) {
+			if(i==0) {
+				printk(KERN_ERR "%s: got valid panel ID=%d, "
+						"without retry\n",
+						__FUNCTION__, id);
+			}
+			else {
+				printk(KERN_ERR "%s: got valid panel ID=%d, "
+						"after %d retry\n",
+						__FUNCTION__, id, i+1);
+			}
+			break ;
+		}
+		printk(KERN_ERR "%s: got invalid panel ID:%d, trial #%d\n",
+				__FUNCTION__, id, i+1);
+
+		gpio_set_value(MDDI_RST_N, 0);
+		msleep(5);
+
+		gpio_set_value(MDDI_RST_N, 1);
+		msleep(10);
+		gpio_set_value(MDDI_RST_N, 0);
+		udelay(100);
+		gpio_set_value(MDDI_RST_N, 1);
+		mdelay(10);
+	}
+	printk(KERN_INFO "%s: final panel id=%d\n", __FUNCTION__, id);
+
+	switch(id) {
+	case 0:
+		return SAPPHIRE_PANEL_TOPPOLY;
+	case 1:
+		return SAPPHIRE_PANEL_SHARP;
+	default :
+		printk(KERN_ERR "%s(): Invalid panel ID: %d, "
+				"treat as sharp panel.", __FUNCTION__, id);
+		return SAPPHIRE_PANEL_SHARP;
+	}
+}
+
+static int nt35399_client_init(
+		struct msm_mddi_bridge_platform_data *bridge_data,
+		struct msm_mddi_client_data *client_data)
+{
+	int panel_id;
+
+	if (g_panel_inited == 0) {
+		g_panel_id = panel_id = nt35399_detect_panel(client_data);
+		g_panel_inited = 1 ;
+	} else {
+		gpio_set_value(MDDI_RST_N, 1);
+		msleep(10);
+		gpio_set_value(MDDI_RST_N, 0);
+		udelay(100);
+		gpio_set_value(MDDI_RST_N, 1);
+		mdelay(10);
+
+		g_panel_id = panel_id = nt35399_detect_panel(client_data);
+		if (panel_id == -1) {
+			printk("Invalid panel id\n");
+			return -1;
+		}
+
+		client_data->auto_hibernate(client_data, 0);
+		if (panel_id == SAPPHIRE_PANEL_TOPPOLY) {
+			sapphire_process_mddi_table(client_data, tpo2_init_table,
+						    ARRAY_SIZE(tpo2_init_table));
+		} else if(panel_id == SAPPHIRE_PANEL_SHARP) {
+			sapphire_process_mddi_table(client_data, sharp2_init_table,
+						    ARRAY_SIZE(sharp2_init_table));
+		}
+
+		client_data->auto_hibernate(client_data, 1);
+	}
+
+	return 0;
+}
+
+static int nt35399_client_uninit(
+		struct msm_mddi_bridge_platform_data *bridge_data,
+		struct msm_mddi_client_data *cdata)
+{
+	return 0;
+}
+
+static int nt35399_panel_unblank(
+		struct msm_mddi_bridge_platform_data *bridge_data,
+		struct msm_mddi_client_data *client_data)
+{
+	int ret = 0;
+
+	mdelay(20);
+	sapphire_set_backlight_level(0);
+	client_data->auto_hibernate(client_data, 0);
+
+	mutex_lock(&sapphire_backlight_lock);
+	sapphire_set_backlight_level(sapphire_backlight_brightness);
+	sapphire_backlight_off = 0;
+	mutex_unlock(&sapphire_backlight_lock);
+
+	client_data->auto_hibernate(client_data, 1);
+
+	return ret;
+}
+
+static int nt35399_panel_blank(
+		struct msm_mddi_bridge_platform_data *bridge_data,
+		struct msm_mddi_client_data *client_data)
+{
+	int ret = 0;
+
+	client_data->auto_hibernate(client_data, 0);
+	sapphire_process_mddi_table(client_data, tpo2_display_off,
+			ARRAY_SIZE(tpo2_display_off));
+	client_data->auto_hibernate(client_data, 1);
+
+	mutex_lock(&sapphire_backlight_lock);
+	sapphire_set_backlight_level(0);
+	sapphire_backlight_off = 1;
+	mutex_unlock(&sapphire_backlight_lock);
+
+	return ret;
+}
+
+static void sapphire_brightness_set(struct led_classdev *led_cdev, enum led_brightness value)
+{
+	mutex_lock(&sapphire_backlight_lock);
+	sapphire_backlight_brightness = value;
+	if (!sapphire_backlight_off)
+		sapphire_set_backlight_level(sapphire_backlight_brightness);
+	mutex_unlock(&sapphire_backlight_lock);
+}
+
+static struct led_classdev sapphire_backlight_led = {
+	.name			= "lcd-backlight",
+	.brightness = SAPPHIRE_DEFAULT_BACKLIGHT_BRIGHTNESS,
+	.brightness_set = sapphire_brightness_set,
+};
+
+static int sapphire_backlight_probe(struct platform_device *pdev)
+{
+	led_classdev_register(&pdev->dev, &sapphire_backlight_led);
+	return 0;
+}
+
+static int sapphire_backlight_remove(struct platform_device *pdev)
+{
+	led_classdev_unregister(&sapphire_backlight_led);
+	return 0;
+}
+
+static struct platform_driver sapphire_backlight_driver = {
+	.probe		= sapphire_backlight_probe,
+	.remove		= sapphire_backlight_remove,
+	.driver		= {
+		.name		= "sapphire-backlight",
+		.owner		= THIS_MODULE,
+	},
+};
+
+static struct resource resources_msm_fb[] = {
+	{
+		.start = SMI64_MSM_FB_BASE,
+		.end = SMI64_MSM_FB_BASE + SMI64_MSM_FB_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct msm_mddi_bridge_platform_data toshiba_client_data = {
+	.init = sapphire_mddi_toshiba_client_init,
+	.uninit = sapphire_mddi_toshiba_client_uninit,
+	.blank = sapphire_mddi_panel_blank,
+	.unblank = sapphire_mddi_panel_unblank,
+	.fb_data = {
+		.xres = 320,
+		.yres = 480,
+		.width = 45,
+		.height = 67,
+		.output_format = 0,
+	},
+};
+
+#define NT35399_MFR_NAME	0x0bda
+#define NT35399_PRODUCT_CODE 	0x8a47
+
+static void nt35399_fixup(uint16_t * mfr_name, uint16_t * product_code)
+{
+	printk(KERN_DEBUG "%s: enter.\n", __func__);
+	*mfr_name = NT35399_MFR_NAME ;
+	*product_code= NT35399_PRODUCT_CODE ;
+}
+
+static struct msm_mddi_bridge_platform_data nt35399_client_data = {
+
+	.init = nt35399_client_init,
+	.uninit = nt35399_client_uninit,
+	.blank = nt35399_panel_blank,
+	.unblank = nt35399_panel_unblank,
+	.fb_data = {
+		.xres = 320,
+		.yres = 480,
+		.output_format = 0,
+	},
+};
+
+static struct msm_mddi_platform_data mddi_pdata = {
+	.clk_rate = 122880000,
+	.power_client = sapphire_mddi_power_client,
+	.fixup = nt35399_fixup,
+	.vsync_irq = MSM_GPIO_TO_INT(VSYNC_GPIO),
+	.fb_resource = resources_msm_fb,
+	.num_clients = 2,
+	.client_platform_data = {
+		{
+			.product_id = (0xd263 << 16 | 0),
+			.name = "mddi_c_d263_0000",
+			.id = 0,
+			.client_data = &toshiba_client_data,
+			.clk_rate = 0,
+		},
+		{
+			.product_id =
+				(NT35399_MFR_NAME << 16 | NT35399_PRODUCT_CODE),
+			.name = "mddi_c_simple" ,
+			.id = 0,
+			.client_data = &nt35399_client_data,
+			.clk_rate = 0,
+		},
+	},
+};
+
+static struct platform_device sapphire_backlight = {
+	.name = "sapphire-backlight",
+};
+
+int __init sapphire_init_panel(void)
+{
+	int rc = -1;
+	uint32_t config = PCOM_GPIO_CFG(27, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA); /* GPIO27 */
+
+	if (!machine_is_sapphire())
+		return 0;
+
+	/* checking board as soon as possible */
+	printk("sapphire_init_panel:machine_is_sapphire=%d, machine_arch_type=%d, MACH_TYPE_SAPPHIRE=%d\r\n", machine_is_sapphire(), machine_arch_type, MACH_TYPE_SAPPHIRE);
+	if (!machine_is_sapphire())
+		return 0;
+
+	vreg_lcm_2v85 = vreg_get(0, "gp4");
+	if (IS_ERR(vreg_lcm_2v85))
+		return PTR_ERR(vreg_lcm_2v85);
+
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &config, 0);
+
+	/* setup FB by SMI size */
+	if (sapphire_get_smi_size() == 32) {
+		resources_msm_fb[0].start = SMI32_MSM_FB_BASE;
+		resources_msm_fb[0].end = SMI32_MSM_FB_BASE + SMI32_MSM_FB_SIZE - 1;
+	}
+
+	rc = gpio_request(VSYNC_GPIO, "vsync");
+	if (rc)
+		return rc;
+	rc = gpio_direction_input(VSYNC_GPIO);
+	if (rc)
+		return rc;
+	rc = platform_device_register(&msm_device_mdp);
+	if (rc)
+		return rc;
+	msm_device_mddi0.dev.platform_data = &mddi_pdata;
+	rc = platform_device_register(&msm_device_mddi0);
+	if (rc)
+		return rc;
+	platform_device_register(&sapphire_backlight);
+	return platform_driver_register(&sapphire_backlight_driver);
+}
+
+device_initcall(sapphire_init_panel);
diff --git a/arch/arm/mach-msm/board-sapphire-rfkill.c b/arch/arm/mach-msm/board-sapphire-rfkill.c
new file mode 100644
index 0000000..2fd6ea1
--- /dev/null
+++ b/arch/arm/mach-msm/board-sapphire-rfkill.c
@@ -0,0 +1,105 @@
+/* linux/arch/arm/mach-msm/board-sapphire-rfkill.c
+ * Copyright (C) 2007-2009 HTC Corporation.
+ * Author: Thomas Tsai <thomas_tsai@htc.com>
+ *
+ * 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.
+*/
+
+/* Control bluetooth power for sapphire platform */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/rfkill.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <asm/mach-types.h>
+#include "gpio_chip.h"
+#include "board-sapphire.h"
+
+static struct rfkill *bt_rfk;
+static const char bt_name[] = "brf6300";
+
+extern int sapphire_bt_fastclock_power(int on);
+
+static int bluetooth_set_power(void *data, bool blocked)
+{
+	if (!blocked) {
+		sapphire_bt_fastclock_power(1);
+		gpio_set_value(SAPPHIRE_GPIO_BT_32K_EN, 1);
+		udelay(10);
+		gpio_direction_output(101, 1);
+	} else {
+		gpio_direction_output(101, 0);
+		gpio_set_value(SAPPHIRE_GPIO_BT_32K_EN, 0);
+		sapphire_bt_fastclock_power(0);
+	}
+	return 0;
+}
+
+static struct rfkill_ops sapphire_rfkill_ops = {
+	.set_block = bluetooth_set_power,
+};
+
+static int sapphire_rfkill_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	bool default_state = true;  /* off */
+
+	bluetooth_set_power(NULL, default_state);
+
+	bt_rfk = rfkill_alloc(bt_name, &pdev->dev, RFKILL_TYPE_BLUETOOTH,
+			      &sapphire_rfkill_ops, NULL);
+	if (!bt_rfk)
+		return -ENOMEM;
+
+	/* userspace cannot take exclusive control */
+
+	rfkill_set_states(bt_rfk, default_state, false);
+
+	rc = rfkill_register(bt_rfk);
+
+	if (rc)
+		rfkill_destroy(bt_rfk);
+	return rc;
+}
+
+static int sapphire_rfkill_remove(struct platform_device *dev)
+{
+	rfkill_unregister(bt_rfk);
+	rfkill_destroy(bt_rfk);
+
+	return 0;
+}
+
+static struct platform_driver sapphire_rfkill_driver = {
+	.probe = sapphire_rfkill_probe,
+	.remove = sapphire_rfkill_remove,
+	.driver = {
+		.name = "sapphire_rfkill",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init sapphire_rfkill_init(void)
+{
+	return platform_driver_register(&sapphire_rfkill_driver);
+}
+
+static void __exit sapphire_rfkill_exit(void)
+{
+	platform_driver_unregister(&sapphire_rfkill_driver);
+}
+
+module_init(sapphire_rfkill_init);
+module_exit(sapphire_rfkill_exit);
+MODULE_DESCRIPTION("sapphire rfkill");
+MODULE_AUTHOR("Nick Pelly <npelly@google.com>");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/board-sapphire-wifi.c b/arch/arm/mach-msm/board-sapphire-wifi.c
new file mode 100644
index 0000000..43f827c
--- /dev/null
+++ b/arch/arm/mach-msm/board-sapphire-wifi.c
@@ -0,0 +1,74 @@
+/* arch/arm/mach-msm/board-sapphire-wifi.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Dmitry Shmidt <dimitrysh@google.com>
+ *
+ * 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.
+ *
+ */
+
+#ifdef CONFIG_WIFI_CONTROL_FUNC
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/vmalloc.h>
+#include <linux/err.h>
+#include <linux/wifi_tiwlan.h>
+
+extern int sapphire_wifi_set_carddetect(int val);
+extern int sapphire_wifi_power(int on);
+extern int sapphire_wifi_reset(int on);
+
+#ifdef CONFIG_WIFI_MEM_PREALLOC
+typedef struct wifi_mem_prealloc_struct {
+	void *mem_ptr;
+	unsigned long size;
+} wifi_mem_prealloc_t;
+
+static wifi_mem_prealloc_t wifi_mem_array[WMPA_NUMBER_OF_SECTIONS] = {
+	{ NULL, (WMPA_SECTION_SIZE_0 + WMPA_SECTION_HEADER) },
+	{ NULL, (WMPA_SECTION_SIZE_1 + WMPA_SECTION_HEADER) },
+	{ NULL, (WMPA_SECTION_SIZE_2 + WMPA_SECTION_HEADER) }
+};
+
+static void *sapphire_wifi_mem_prealloc(int section, unsigned long size)
+{
+	if ((section < 0) || (section >= WMPA_NUMBER_OF_SECTIONS))
+		return NULL;
+	if (wifi_mem_array[section].size < size)
+		return NULL;
+	return wifi_mem_array[section].mem_ptr;
+}
+
+int __init sapphire_init_wifi_mem (void)
+{
+	int i;
+
+	for (i = 0; (i < WMPA_NUMBER_OF_SECTIONS); i++) {
+		wifi_mem_array[i].mem_ptr = vmalloc(wifi_mem_array[i].size);
+		if (wifi_mem_array[i].mem_ptr == NULL)
+			return -ENOMEM;
+	}
+	return 0;
+}
+#endif
+
+struct wifi_platform_data sapphire_wifi_control = {
+	.set_power		= sapphire_wifi_power,
+	.set_reset		= sapphire_wifi_reset,
+	.set_carddetect		= sapphire_wifi_set_carddetect,
+#ifdef CONFIG_WIFI_MEM_PREALLOC
+	.mem_prealloc		= sapphire_wifi_mem_prealloc,
+#else
+	.mem_prealloc		= NULL,
+#endif
+};
+
+#endif
diff --git a/arch/arm/mach-msm/board-sapphire.c b/arch/arm/mach-msm/board-sapphire.c
index 4a8ea0d..abb6157 100644
--- a/arch/arm/mach-msm/board-sapphire.c
+++ b/arch/arm/mach-msm/board-sapphire.c
@@ -30,6 +30,7 @@
 #include <mach/system.h>
 #include <mach/vreg.h>
 #include <mach/board.h>
+#include <mach/proc_comm.h>
 
 #include <asm/io.h>
 #include <asm/delay.h>
@@ -40,7 +41,6 @@
 
 #include "gpio_chip.h"
 #include "board-sapphire.h"
-#include "proc_comm.h"
 #include "devices.h"
 
 void msm_init_irq(void);
diff --git a/arch/arm/mach-msm/board-sapphire.h b/arch/arm/mach-msm/board-sapphire.h
new file mode 100644
index 0000000..d96760a
--- /dev/null
+++ b/arch/arm/mach-msm/board-sapphire.h
@@ -0,0 +1,224 @@
+/* linux/arch/arm/mach-msm/board-sapphire.h
+ * Copyright (C) 2007-2009 HTC Corporation.
+ * Author: Thomas Tsai <thomas_tsai@htc.com>
+ *
+ * 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 __ARCH_ARM_MACH_MSM_BOARD_SAPPHIRE_H
+#define __ARCH_ARM_MACH_MSM_BOARD_SAPPHIRE_H
+
+#include <mach/board.h>
+
+#define MSM_SMI_BASE		0x00000000
+#define MSM_SMI_SIZE		0x00800000
+
+#define MSM_EBI_BASE		0x10000000
+#define MSM_EBI_SIZE		0x07100000
+
+#define MSM_PMEM_GPU0_BASE	0x00000000
+#define MSM_PMEM_GPU0_SIZE	0x00700000
+
+#define SMI64_MSM_PMEM_MDP_BASE	0x15900000
+#define SMI64_MSM_PMEM_MDP_SIZE	0x00800000
+
+#define SMI64_MSM_PMEM_ADSP_BASE	0x16100000
+#define SMI64_MSM_PMEM_ADSP_SIZE	0x00800000
+
+#define SMI64_MSM_PMEM_CAMERA_BASE	0x15400000
+#define SMI64_MSM_PMEM_CAMERA_SIZE	0x00500000
+
+#define SMI64_MSM_FB_BASE		0x00700000
+#define SMI64_MSM_FB_SIZE		0x00100000
+
+#define SMI64_MSM_LINUX_BASE		MSM_EBI_BASE
+#define SMI64_MSM_LINUX_SIZE		0x068e0000
+
+#define SMI64_MSM_LINUX_BASE_1		0x02000000
+#define SMI64_MSM_LINUX_SIZE_1		0x02000000
+
+#define SMI64_MSM_LINUX_BASE_2		MSM_EBI_BASE
+#define SMI64_MSM_LINUX_SIZE_2		0x05400000
+
+#define SMI32_MSM_LINUX_BASE		MSM_EBI_BASE
+#define SMI32_MSM_LINUX_SIZE		0x5400000
+
+#define SMI32_MSM_PMEM_MDP_BASE	SMI32_MSM_LINUX_BASE + SMI32_MSM_LINUX_SIZE
+#define SMI32_MSM_PMEM_MDP_SIZE	0x800000
+
+#define SMI32_MSM_PMEM_ADSP_BASE	SMI32_MSM_PMEM_MDP_BASE + SMI32_MSM_PMEM_MDP_SIZE
+#define SMI32_MSM_PMEM_ADSP_SIZE	0x800000
+
+#define SMI32_MSM_FB_BASE		SMI32_MSM_PMEM_ADSP_BASE + SMI32_MSM_PMEM_ADSP_SIZE
+#define SMI32_MSM_FB_SIZE		0x9b000
+
+
+#define MSM_PMEM_GPU1_SIZE	0x800000
+#define MSM_PMEM_GPU1_BASE     (MSM_RAM_CONSOLE_BASE + MSM_RAM_CONSOLE_SIZE)
+
+#define MSM_RAM_CONSOLE_BASE	0x169E0000
+#define MSM_RAM_CONSOLE_SIZE	128 * SZ_1K
+
+#if (SMI32_MSM_FB_BASE + SMI32_MSM_FB_SIZE) >= (MSM_PMEM_GPU1_BASE)
+#error invalid memory map
+#endif
+
+#if (SMI64_MSM_FB_BASE + SMI64_MSM_FB_SIZE) >= (MSM_PMEM_GPU1_BASE)
+#error invalid memory map
+#endif
+
+#define DECLARE_MSM_IOMAP
+#include <mach/msm_iomap.h>
+
+/*
+** SOC GPIO
+*/
+#define SAPPHIRE_BALL_UP_0     94
+#define SAPPHIRE_BALL_LEFT_0   18
+#define SAPPHIRE_BALL_DOWN_0   49
+#define SAPPHIRE_BALL_RIGHT_0  19
+
+#define SAPPHIRE_POWER_KEY     20
+#define SAPPHIRE_VOLUME_UP     36
+#define SAPPHIRE_VOLUME_DOWN   39
+
+#define SAPPHIRE_GPIO_PS_HOLD   (25)
+#define SAPPHIRE_MDDI_1V5_EN	(28)
+#define SAPPHIRE_BL_PWM			(27)
+#define SAPPHIRE_TP_LS_EN    	(1)
+#define SAPPHIRE20_TP_LS_EN			(88)
+
+/* H2W */
+#define SAPPHIRE_GPIO_CABLE_IN1		(83)
+#define SAPPHIRE_GPIO_CABLE_IN2		(37)
+#define SAPPHIRE_GPIO_UART3_RX		(86)
+#define SAPPHIRE_GPIO_UART3_TX		(87)
+#define SAPPHIRE_GPIO_H2W_DATA		(86)
+#define SAPPHIRE_GPIO_H2W_CLK		(87)
+
+#define SAPPHIRE_GPIO_UART1_RTS		(43)
+#define SAPPHIRE_GPIO_UART1_CTS		(44)
+
+/*
+** CPLD GPIO
+**
+** Sapphire Altera CPLD can keep the registers value and
+** doesn't need a shadow to backup.
+**/
+#define SAPPHIRE_CPLD_BASE   0xFA000000	/* VA */
+#define SAPPHIRE_CPLD_START  0x98000000	/* PA */
+#define SAPPHIRE_CPLD_SIZE   SZ_4K
+
+#define SAPPHIRE_GPIO_START (128)				/* Pseudo GPIO number */
+
+/* Sapphire has one INT BANK only. */
+#define SAPPHIRE_GPIO_INT_B0_MASK_REG           (0x0c)	/*INT3 MASK*/
+#define SAPPHIRE_GPIO_INT_B0_STAT_REG           (0x0e)	/*INT1 STATUS*/
+
+/* LED control register */
+#define SAPPHIRE_CPLD_LED_BASE									(SAPPHIRE_CPLD_BASE + 0x10)		/* VA */
+#define SAPPHIRE_CPLD_LED_START									(SAPPHIRE_CPLD_START + 0x10)	/* PA */
+#define SAPPHIRE_CPLD_LED_SIZE									0x08
+
+/* MISCn: GPO pin to Enable/Disable some functions. */
+#define SAPPHIRE_GPIO_MISC1_BASE               	(SAPPHIRE_GPIO_START + 0x00)
+#define SAPPHIRE_GPIO_MISC2_BASE               	(SAPPHIRE_GPIO_START + 0x08)
+#define SAPPHIRE_GPIO_MISC3_BASE               	(SAPPHIRE_GPIO_START + 0x10)
+#define SAPPHIRE_GPIO_MISC4_BASE               	(SAPPHIRE_GPIO_START + 0x18)
+#define SAPPHIRE_GPIO_MISC5_BASE               	(SAPPHIRE_GPIO_START + 0x20)
+
+/* INT BANK0: INT1: int status, INT2: int level, INT3: int Mask */
+#define SAPPHIRE_GPIO_INT_B0_BASE              	(SAPPHIRE_GPIO_START + 0x28)
+
+/* MISCn GPIO: */
+#define SAPPHIRE_GPIO_CPLD128_VER_0            	(SAPPHIRE_GPIO_MISC1_BASE + 4)
+#define SAPPHIRE_GPIO_CPLD128_VER_1            	(SAPPHIRE_GPIO_MISC1_BASE + 5)
+#define SAPPHIRE_GPIO_CPLD128_VER_2            	(SAPPHIRE_GPIO_MISC1_BASE + 6)
+#define SAPPHIRE_GPIO_CPLD128_VER_3            	(SAPPHIRE_GPIO_MISC1_BASE + 7)
+
+#define SAPPHIRE_GPIO_H2W_DAT_DIR              	(SAPPHIRE_GPIO_MISC2_BASE + 2)
+#define SAPPHIRE_GPIO_H2W_CLK_DIR              	(SAPPHIRE_GPIO_MISC2_BASE + 3)
+#define SAPPHIRE_GPIO_H2W_SEL0                 	(SAPPHIRE_GPIO_MISC2_BASE + 6)
+#define SAPPHIRE_GPIO_H2W_SEL1                 	(SAPPHIRE_GPIO_MISC2_BASE + 7)
+
+#define SAPPHIRE_GPIO_I2C_PULL                 	(SAPPHIRE_GPIO_MISC3_BASE + 2)
+#define SAPPHIRE_GPIO_TP_EN                    	(SAPPHIRE_GPIO_MISC3_BASE + 4)
+#define SAPPHIRE_GPIO_JOG_EN                   	(SAPPHIRE_GPIO_MISC3_BASE + 5)
+#define SAPPHIRE_GPIO_JOG_LED_EN               	(SAPPHIRE_GPIO_MISC3_BASE + 6)
+#define SAPPHIRE_GPIO_APKEY_LED_EN             	(SAPPHIRE_GPIO_MISC3_BASE + 7)
+
+#define SAPPHIRE_GPIO_VCM_PWDN                 	(SAPPHIRE_GPIO_MISC4_BASE + 0)
+#define SAPPHIRE_GPIO_USB_H2W_SW               	(SAPPHIRE_GPIO_MISC4_BASE + 1)
+#define SAPPHIRE_GPIO_COMPASS_RST_N            	(SAPPHIRE_GPIO_MISC4_BASE + 2)
+#define SAPPHIRE_GPIO_USB_PHY_RST_N            	(SAPPHIRE_GPIO_MISC4_BASE + 5)
+#define SAPPHIRE_GPIO_WIFI_PA_RESETX           	(SAPPHIRE_GPIO_MISC4_BASE + 6)
+#define SAPPHIRE_GPIO_WIFI_EN                  	(SAPPHIRE_GPIO_MISC4_BASE + 7)
+
+#define SAPPHIRE_GPIO_BT_32K_EN                	(SAPPHIRE_GPIO_MISC5_BASE + 0)
+#define SAPPHIRE_GPIO_MAC_32K_EN               	(SAPPHIRE_GPIO_MISC5_BASE + 1)
+#define SAPPHIRE_GPIO_MDDI_32K_EN              	(SAPPHIRE_GPIO_MISC5_BASE + 2)
+#define SAPPHIRE_GPIO_COMPASS_32K_EN           	(SAPPHIRE_GPIO_MISC5_BASE + 3)
+
+/* INT STATUS/LEVEL/MASK : INT GPIO should be the last. */
+#define SAPPHIRE_GPIO_NAVI_ACT_N           		(SAPPHIRE_GPIO_INT_B0_BASE + 0)
+#define SAPPHIRE_GPIO_COMPASS_IRQ         		(SAPPHIRE_GPIO_INT_B0_BASE + 1)
+#define SAPPHIRE_GPIO_SEARCH_ACT_N			(SAPPHIRE_GPIO_INT_B0_BASE + 2)
+#define SAPPHIRE_GPIO_AUD_HSMIC_DET_N      		(SAPPHIRE_GPIO_INT_B0_BASE + 3)
+#define SAPPHIRE_GPIO_SDMC_CD_N      			(SAPPHIRE_GPIO_INT_B0_BASE + 4)
+#define SAPPHIRE_GPIO_CAM_BTN_STEP1_N          	(SAPPHIRE_GPIO_INT_B0_BASE + 5)
+#define SAPPHIRE_GPIO_CAM_BTN_STEP2_N          	(SAPPHIRE_GPIO_INT_B0_BASE + 6)
+#define SAPPHIRE_GPIO_TP_ATT_N            		(SAPPHIRE_GPIO_INT_B0_BASE + 7)
+
+#define	SAPPHIRE_GPIO_END						SAPPHIRE_GPIO_TP_ATT_N
+#define	SAPPHIRE_GPIO_LAST_INT					(SAPPHIRE_GPIO_TP_ATT_N)
+
+/* Bit position in the CPLD MISCn by the CPLD GPIOn: only bit0-7 is used. */
+#define	CPLD_GPIO_BIT_POS_MASK(n)		(1U << ((n) & 7))
+#define	CPLD_GPIO_REG_OFFSET(n)			_g_CPLD_MISCn_Offset[((n)-SAPPHIRE_GPIO_START) >> 3]
+#define	CPLD_GPIO_REG(n)				(CPLD_GPIO_REG_OFFSET(n) + SAPPHIRE_CPLD_BASE)
+
+/*
+** CPLD INT Start
+*/
+#define SAPPHIRE_INT_START 					(NR_MSM_IRQS + NR_GPIO_IRQS)	/* pseudo number for CPLD INT */
+/* Using INT status/Bank0 for GPIO to INT */
+#define	SAPPHIRE_GPIO_TO_INT(n)				((n-SAPPHIRE_GPIO_INT_B0_BASE) + SAPPHIRE_INT_START)
+#define SAPPHIRE_INT_END 					(SAPPHIRE_GPIO_TO_INT(SAPPHIRE_GPIO_END))
+
+/* get the INT reg by GPIO number */
+#define	CPLD_INT_GPIO_TO_BANK(n)			(((n)-SAPPHIRE_GPIO_INT_B0_BASE) >> 3)
+#define	CPLD_INT_STATUS_REG_OFFSET_G(n)		_g_INT_BANK_Offset[CPLD_INT_GPIO_TO_BANK(n)][0]
+#define	CPLD_INT_LEVEL_REG_OFFSET_G(n)		_g_INT_BANK_Offset[CPLD_INT_GPIO_TO_BANK(n)][1]
+#define	CPLD_INT_MASK_REG_OFFSET_G(n)		_g_INT_BANK_Offset[CPLD_INT_GPIO_TO_BANK(n)][2]
+#define	CPLD_INT_STATUS_REG_G(n)			(SAPPHIRE_CPLD_BASE + CPLD_INT_STATUS_REG_OFFSET_G(n))
+#define	CPLD_INT_LEVEL_REG_G(n)				(SAPPHIRE_CPLD_BASE + CPLD_INT_LEVEL_REG_OFFSET_G(n))
+#define	CPLD_INT_MASK_REG_G(n)				(SAPPHIRE_CPLD_BASE + CPLD_INT_MASK_REG_OFFSET_G(n))
+
+/* get the INT reg by INT number */
+#define	CPLD_INT_TO_BANK(i)					((i-SAPPHIRE_INT_START) >> 3)
+#define	CPLD_INT_STATUS_REG_OFFSET(i)		_g_INT_BANK_Offset[CPLD_INT_TO_BANK(i)][0]
+#define	CPLD_INT_LEVEL_REG_OFFSET(i)		_g_INT_BANK_Offset[CPLD_INT_TO_BANK(i)][1]
+#define	CPLD_INT_MASK_REG_OFFSET(i)			_g_INT_BANK_Offset[CPLD_INT_TO_BANK(i)][2]
+#define	CPLD_INT_STATUS_REG(i)				(SAPPHIRE_CPLD_BASE + CPLD_INT_STATUS_REG_OFFSET(i))
+#define	CPLD_INT_LEVEL_REG(i)				(SAPPHIRE_CPLD_BASE + CPLD_INT_LEVEL_REG_OFFSET(i))
+#define	CPLD_INT_MASK_REG(i)				(SAPPHIRE_CPLD_BASE + CPLD_INT_MASK_REG_OFFSET(i) )
+
+/* return the bit mask by INT number */
+#define SAPPHIRE_INT_BIT_MASK(i) 			(1U << ((i - SAPPHIRE_INT_START) & 7))
+
+void config_sapphire_camera_on_gpios(void);
+void config_sapphire_camera_off_gpios(void);
+int sapphire_get_smi_size(void);
+unsigned int sapphire_get_hwid(void);
+unsigned int sapphire_get_skuid(void);
+unsigned int is_12pin_camera(void);
+int sapphire_is_5M_camera(void);
+int sapphire_gpio_write(struct gpio_chip *chip, unsigned n, unsigned on);
+
+#endif /* GUARD */
diff --git a/arch/arm/mach-msm/board-storage-common-a.h b/arch/arm/mach-msm/board-storage-common-a.h
new file mode 100644
index 0000000..7737819
--- /dev/null
+++ b/arch/arm/mach-msm/board-storage-common-a.h
@@ -0,0 +1,99 @@
+/* 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 _BOARD_STORAGE_A_H
+#define _BOARD_STORAGE_A_H
+
+#include <asm/mach/mmc.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_bus.h>
+
+#define MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(num, _ib) \
+static struct msm_bus_vectors sps_to_ddr_perf_vectors_##num[] = { \
+	{ \
+		.src = MSM_BUS_MASTER_SPS, \
+		.dst = MSM_BUS_SLAVE_EBI_CH0, \
+		.ib = (_ib), \
+		.ab = ((_ib) / 2), \
+	} \
+}
+
+#define MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(num) \
+	{ \
+		ARRAY_SIZE(sps_to_ddr_perf_vectors_##num), \
+		sps_to_ddr_perf_vectors_##num, \
+	}
+
+/* no bandwidth required */
+MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(0, 0);
+/*
+ * 13 MB/s bandwidth
+ * 4-bit MMC_TIMING_LEGACY
+ * 4-bit MMC_TIMING_UHS_SDR12
+ */
+MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(1, 13 * 1024 * 1024);
+/*
+ * 26 MB/s bandwidth
+ * 8-bit MMC_TIMING_LEGACY
+ * 4-bit MMC_TIMING_MMC_HS / MMC_TIMING_SD_HS /
+ *	 MMC_TIMING_UHS_SDR25
+ */
+MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(2, 26 * 1024 * 1024);
+/*
+ * 52 MB/s bandwidth
+ * 8-bit MMC_TIMING_MMC_HS
+ * 4-bit MMC_TIMING_UHS_SDR50 / MMC_TIMING_UHS_DDR50
+ */
+MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(3, 52 * 1024 * 1024);
+/*
+ * 104 MB/s bandwidth
+ * 8-bit MMC_TIMING_UHS_DDR50
+ * 4-bit MMC_TIMING_UHS_SDR104 / MMC_TIMING_MMC_HS200
+ */
+MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(4, 104 * 1024 * 1024);
+/*
+ * 200 MB/s bandwidth
+ * 8-bit MMC_TIMING_MMC_HS200
+ */
+MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(5, 200 * 1024 * 1024);
+/* max. possible bandwidth */
+MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(6, UINT_MAX);
+
+static unsigned int sdcc_bw_vectors[] = {0, (13 * 1024 * 1024),
+				(26 * 1024 * 1024), (52 * 1024 * 1024),
+				(104 * 1024 * 1024), (200 * 1024 * 1024),
+				UINT_MAX};
+
+static struct msm_bus_paths sps_to_ddr_bus_scale_usecases[] = {
+	MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(0),
+	MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(1),
+	MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(2),
+	MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(3),
+	MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(4),
+	MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(5),
+	MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(6),
+};
+
+static struct msm_bus_scale_pdata sps_to_ddr_bus_scale_data = {
+	sps_to_ddr_bus_scale_usecases,
+	ARRAY_SIZE(sps_to_ddr_bus_scale_usecases),
+	.name = "msm_sdcc",
+};
+
+static struct msm_mmc_bus_voting_data sps_to_ddr_bus_voting_data = {
+	.use_cases = &sps_to_ddr_bus_scale_data,
+	.bw_vecs = sdcc_bw_vectors,
+	.bw_vecs_size = sizeof(sdcc_bw_vectors),
+};
+
+#endif /* _BOARD_STORAGE_A_H */
diff --git a/arch/arm/mach-msm/board-swordfish-keypad.c b/arch/arm/mach-msm/board-swordfish-keypad.c
new file mode 100644
index 0000000..f2c2f39
--- /dev/null
+++ b/arch/arm/mach-msm/board-swordfish-keypad.c
@@ -0,0 +1,177 @@
+/* linux/arch/arm/mach-msm/board-swordfish-keypad.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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.
+ *
+ */
+
+#include <asm/mach-types.h>
+#include <linux/platform_device.h>
+#include <linux/gpio_event.h>
+
+#undef MODULE_PARAM_PREFIX
+#define MODULE_PARAM_PREFIX "board_swordfish."
+static int swordfish_ffa;
+module_param_named(ffa, swordfish_ffa, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#define SCAN_FUNCTION_KEYS 0 /* don't turn this on without updating the ffa support */
+
+static unsigned int swordfish_row_gpios[] = {
+	31, 32, 33, 34, 35, 41
+#if SCAN_FUNCTION_KEYS
+	, 42
+#endif
+};
+
+static unsigned int swordfish_col_gpios[] = { 36, 37, 38, 39, 40 };
+
+/* FFA:
+ 36: KEYSENSE_N(0)
+ 37: KEYSENSE_N(1)
+ 38: KEYSENSE_N(2)
+ 39: KEYSENSE_N(3)
+ 40: KEYSENSE_N(4)
+
+ 31: KYPD_17
+ 32: KYPD_15
+ 33: KYPD_13
+ 34: KYPD_11
+ 35: KYPD_9
+ 41: KYPD_MEMO
+*/
+
+#define KEYMAP_INDEX(row, col) ((row)*ARRAY_SIZE(swordfish_col_gpios) + (col))
+
+static const unsigned short swordfish_keymap[ARRAY_SIZE(swordfish_col_gpios) * ARRAY_SIZE(swordfish_row_gpios)] = {
+	[KEYMAP_INDEX(0, 0)] = KEY_5,
+	[KEYMAP_INDEX(0, 1)] = KEY_9,
+	[KEYMAP_INDEX(0, 2)] = 229,            /* SOFT1 */
+	[KEYMAP_INDEX(0, 3)] = KEY_6,
+	[KEYMAP_INDEX(0, 4)] = KEY_LEFT,
+
+	[KEYMAP_INDEX(1, 0)] = KEY_0,
+	[KEYMAP_INDEX(1, 1)] = KEY_RIGHT,
+	[KEYMAP_INDEX(1, 2)] = KEY_1,
+	[KEYMAP_INDEX(1, 3)] = 228,           /* KEY_SHARP */
+	[KEYMAP_INDEX(1, 4)] = KEY_SEND,
+
+	[KEYMAP_INDEX(2, 0)] = KEY_VOLUMEUP,
+	[KEYMAP_INDEX(2, 1)] = KEY_HOME,      /* FA   */
+	[KEYMAP_INDEX(2, 2)] = KEY_F8,        /* QCHT */
+	[KEYMAP_INDEX(2, 3)] = KEY_F6,        /* R+   */
+	[KEYMAP_INDEX(2, 4)] = KEY_F7,        /* R-   */
+
+	[KEYMAP_INDEX(3, 0)] = KEY_UP,
+	[KEYMAP_INDEX(3, 1)] = KEY_CLEAR,
+	[KEYMAP_INDEX(3, 2)] = KEY_4,
+	[KEYMAP_INDEX(3, 3)] = KEY_MUTE,      /* SPKR */
+	[KEYMAP_INDEX(3, 4)] = KEY_2,
+
+	[KEYMAP_INDEX(4, 0)] = 230,           /* SOFT2 */
+	[KEYMAP_INDEX(4, 1)] = 232,           /* KEY_CENTER */
+	[KEYMAP_INDEX(4, 2)] = KEY_DOWN,
+	[KEYMAP_INDEX(4, 3)] = KEY_BACK,      /* FB */
+	[KEYMAP_INDEX(4, 4)] = KEY_8,
+
+	[KEYMAP_INDEX(5, 0)] = KEY_VOLUMEDOWN,
+	[KEYMAP_INDEX(5, 1)] = 227,           /* KEY_STAR */
+	[KEYMAP_INDEX(5, 2)] = KEY_MAIL,      /* MESG */
+	[KEYMAP_INDEX(5, 3)] = KEY_3,
+	[KEYMAP_INDEX(5, 4)] = KEY_7,
+
+#if SCAN_FUNCTION_KEYS
+	[KEYMAP_INDEX(6, 0)] = KEY_F5,
+	[KEYMAP_INDEX(6, 1)] = KEY_F4,
+	[KEYMAP_INDEX(6, 2)] = KEY_F3,
+	[KEYMAP_INDEX(6, 3)] = KEY_F2,
+	[KEYMAP_INDEX(6, 4)] = KEY_F1
+#endif
+};
+
+static const unsigned short swordfish_keymap_ffa[ARRAY_SIZE(swordfish_col_gpios) * ARRAY_SIZE(swordfish_row_gpios)] = {
+	/*[KEYMAP_INDEX(0, 0)] = ,*/
+	/*[KEYMAP_INDEX(0, 1)] = ,*/
+	[KEYMAP_INDEX(0, 2)] = KEY_1,
+	[KEYMAP_INDEX(0, 3)] = KEY_SEND,
+	[KEYMAP_INDEX(0, 4)] = KEY_LEFT,
+
+	[KEYMAP_INDEX(1, 0)] = KEY_3,
+	[KEYMAP_INDEX(1, 1)] = KEY_RIGHT,
+	[KEYMAP_INDEX(1, 2)] = KEY_VOLUMEUP,
+	/*[KEYMAP_INDEX(1, 3)] = ,*/
+	[KEYMAP_INDEX(1, 4)] = KEY_6,
+
+	[KEYMAP_INDEX(2, 0)] = KEY_HOME,      /* A */
+	[KEYMAP_INDEX(2, 1)] = KEY_BACK,      /* B */
+	[KEYMAP_INDEX(2, 2)] = KEY_0,
+	[KEYMAP_INDEX(2, 3)] = 228,           /* KEY_SHARP */
+	[KEYMAP_INDEX(2, 4)] = KEY_9,
+
+	[KEYMAP_INDEX(3, 0)] = KEY_UP,
+	[KEYMAP_INDEX(3, 1)] = 232, /* KEY_CENTER */ /* i */
+	[KEYMAP_INDEX(3, 2)] = KEY_4,
+	/*[KEYMAP_INDEX(3, 3)] = ,*/
+	[KEYMAP_INDEX(3, 4)] = KEY_2,
+
+	[KEYMAP_INDEX(4, 0)] = KEY_VOLUMEDOWN,
+	[KEYMAP_INDEX(4, 1)] = KEY_SOUND,
+	[KEYMAP_INDEX(4, 2)] = KEY_DOWN,
+	[KEYMAP_INDEX(4, 3)] = KEY_8,
+	[KEYMAP_INDEX(4, 4)] = KEY_5,
+
+	/*[KEYMAP_INDEX(5, 0)] = ,*/
+	[KEYMAP_INDEX(5, 1)] = 227,           /* KEY_STAR */
+	[KEYMAP_INDEX(5, 2)] = 230, /*SOFT2*/ /* 2 */
+	[KEYMAP_INDEX(5, 3)] = KEY_MENU,      /* 1 */
+	[KEYMAP_INDEX(5, 4)] = KEY_7,
+};
+
+static struct gpio_event_matrix_info swordfish_matrix_info = {
+	.info.func	= gpio_event_matrix_func,
+	.keymap		= swordfish_keymap,
+	.output_gpios	= swordfish_row_gpios,
+	.input_gpios	= swordfish_col_gpios,
+	.noutputs	= ARRAY_SIZE(swordfish_row_gpios),
+	.ninputs	= ARRAY_SIZE(swordfish_col_gpios),
+	.settle_time.tv.nsec = 0,
+	.poll_time.tv.nsec = 20 * NSEC_PER_MSEC,
+	.flags		= GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE | GPIOKPF_PRINT_UNMAPPED_KEYS /*| GPIOKPF_PRINT_MAPPED_KEYS*/
+};
+
+struct gpio_event_info *swordfish_keypad_info[] = {
+	&swordfish_matrix_info.info
+};
+
+static struct gpio_event_platform_data swordfish_keypad_data = {
+	.name		= "swordfish_keypad",
+	.info		= swordfish_keypad_info,
+	.info_count	= ARRAY_SIZE(swordfish_keypad_info)
+};
+
+static struct platform_device swordfish_keypad_device = {
+	.name	= GPIO_EVENT_DEV_NAME,
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &swordfish_keypad_data,
+	},
+};
+
+static int __init swordfish_init_keypad(void)
+{
+	if (!machine_is_swordfish())
+		return 0;
+	if (swordfish_ffa)
+		swordfish_matrix_info.keymap = swordfish_keymap_ffa;
+	return platform_device_register(&swordfish_keypad_device);
+}
+
+device_initcall(swordfish_init_keypad);
diff --git a/arch/arm/mach-msm/board-swordfish-mmc.c b/arch/arm/mach-msm/board-swordfish-mmc.c
new file mode 100644
index 0000000..e4a2a64
--- /dev/null
+++ b/arch/arm/mach-msm/board-swordfish-mmc.c
@@ -0,0 +1,263 @@
+/* linux/arch/arm/mach-msm/board-swordfish-mmc.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * 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.
+ *
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/platform_device.h>
+
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/mach/mmc.h>
+
+#include <mach/vreg.h>
+#include <mach/proc_comm.h>
+
+#include "devices.h"
+
+#define FPGA_BASE		0x70000000
+#define FPGA_SDIO_STATUS	0x280
+
+static void __iomem *fpga_base;
+
+#define DEBUG_SWORDFISH_MMC 1
+
+extern int msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat,
+			unsigned int stat_irq, unsigned long stat_irq_flags);
+
+static int config_gpio_table(unsigned *table, int len, int enable)
+{
+	int n;
+	int rc = 0;
+
+	for (n = 0; n < len; n++) {
+		unsigned dis = !enable;
+		unsigned id = table[n];
+
+		if (msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, &dis)) {
+			pr_err("%s: id=0x%08x dis=%d\n", __func__, table[n],
+			       dis);
+			rc = -1;
+		}
+	}
+
+	return rc;
+}
+
+static unsigned sdc1_gpio_table[] = {
+	PCOM_GPIO_CFG(51, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(52, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(53, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(54, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(55, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(56, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA),
+};
+
+static unsigned sdc2_gpio_table[] = {
+	PCOM_GPIO_CFG(62, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA),
+	PCOM_GPIO_CFG(63, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(64, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(65, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(66, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(67, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA),
+};
+
+static unsigned sdc3_gpio_table[] = {
+	PCOM_GPIO_CFG(88, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA),
+	PCOM_GPIO_CFG(89, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(90, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(91, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(92, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(93, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+};
+
+static unsigned sdc4_gpio_table[] = {
+	PCOM_GPIO_CFG(142, 3, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA),
+	PCOM_GPIO_CFG(143, 3, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(144, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(145, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(146, 3, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+	PCOM_GPIO_CFG(147, 3, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+};
+
+struct sdc_info {
+	unsigned *table;
+	unsigned len;
+};
+
+static struct sdc_info sdcc_gpio_tables[] = {
+	[0] = {
+		.table	= sdc1_gpio_table,
+		.len	= ARRAY_SIZE(sdc1_gpio_table),
+	},
+	[1] = {
+		.table	= sdc2_gpio_table,
+		.len	= ARRAY_SIZE(sdc2_gpio_table),
+	},
+	[2] = {
+		.table	= sdc3_gpio_table,
+		.len	= ARRAY_SIZE(sdc3_gpio_table),
+	},
+	[3] = {
+		.table	= sdc4_gpio_table,
+		.len	= ARRAY_SIZE(sdc4_gpio_table),
+	},
+};
+
+static int swordfish_sdcc_setup_gpio(int dev_id, unsigned enable)
+{
+	struct sdc_info *info;
+
+	if (dev_id < 1 || dev_id > 4)
+		return -1;
+
+	info = &sdcc_gpio_tables[dev_id - 1];
+	return config_gpio_table(info->table, info->len, enable);
+}
+
+struct mmc_vdd_xlat {
+	int mask;
+	int level;
+};
+
+static struct mmc_vdd_xlat mmc_vdd_table[] = {
+	{ MMC_VDD_165_195,	1800 },
+	{ MMC_VDD_20_21,	2050 },
+	{ MMC_VDD_21_22,	2150 },
+	{ MMC_VDD_22_23,	2250 },
+	{ MMC_VDD_23_24,	2350 },
+	{ MMC_VDD_24_25,	2450 },
+	{ MMC_VDD_25_26,	2550 },
+	{ MMC_VDD_26_27,	2650 },
+	{ MMC_VDD_27_28,	2750 },
+	{ MMC_VDD_28_29,	2850 },
+	{ MMC_VDD_29_30,	2950 },
+};
+
+static struct vreg *vreg_sdcc;
+static unsigned int vreg_sdcc_enabled;
+static unsigned int sdcc_vdd = 0xffffffff;
+
+static uint32_t sdcc_translate_vdd(struct device *dev, unsigned int vdd)
+{
+	int i;
+	int rc = 0;
+	struct platform_device *pdev;
+
+	pdev = container_of(dev, struct platform_device, dev);
+	BUG_ON(!vreg_sdcc);
+
+	if (vdd == sdcc_vdd)
+		return 0;
+
+	sdcc_vdd = vdd;
+
+	/* enable/disable the signals to the slot */
+	swordfish_sdcc_setup_gpio(pdev->id, !!vdd);
+
+	/* power down */
+	if (vdd == 0) {
+#if DEBUG_SWORDFISH_MMC
+		pr_info("%s: disable sdcc power\n", __func__);
+#endif
+		vreg_disable(vreg_sdcc);
+		vreg_sdcc_enabled = 0;
+		return 0;
+	}
+
+	if (!vreg_sdcc_enabled) {
+		rc = vreg_enable(vreg_sdcc);
+		if (rc)
+			pr_err("%s: Error enabling vreg (%d)\n", __func__, rc);
+		vreg_sdcc_enabled = 1;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(mmc_vdd_table); i++) {
+		if (mmc_vdd_table[i].mask != (1 << vdd))
+			continue;
+#if DEBUG_SWORDFISH_MMC
+		pr_info("%s: Setting level to %u\n", __func__,
+			mmc_vdd_table[i].level);
+#endif
+		rc = vreg_set_level(vreg_sdcc, mmc_vdd_table[i].level);
+		if (rc)
+			pr_err("%s: Error setting vreg level (%d)\n", __func__, 				rc);
+		return 0;
+	}
+
+	pr_err("%s: Invalid VDD %d specified\n", __func__, vdd);
+	return 0;
+}
+
+static unsigned int swordfish_sdcc_slot_status (struct device *dev)
+{
+	struct platform_device *pdev;
+	uint32_t sdcc_stat;
+
+	pdev = container_of(dev, struct platform_device, dev);
+
+	sdcc_stat = readl(fpga_base + FPGA_SDIO_STATUS);
+
+	/* bit 0 - sdcc1 crd_det
+	 * bit 1 - sdcc1 wr_prt
+	 * bit 2 - sdcc2 crd_det
+	 * bit 3 - sdcc2 wr_prt
+	 * etc...
+	 */
+
+	/* crd_det is active low */
+	return !(sdcc_stat & (1 << ((pdev->id - 1) << 1)));
+}
+
+#define SWORDFISH_MMC_VDD (MMC_VDD_165_195 | MMC_VDD_20_21 | MMC_VDD_21_22 \
+			| MMC_VDD_22_23 | MMC_VDD_23_24 | MMC_VDD_24_25 \
+			| MMC_VDD_25_26 | MMC_VDD_26_27 | MMC_VDD_27_28 \
+			| MMC_VDD_28_29 | MMC_VDD_29_30)
+
+static struct mmc_platform_data swordfish_sdcc_data = {
+	.ocr_mask	= SWORDFISH_MMC_VDD/*MMC_VDD_27_28 | MMC_VDD_28_29*/,
+	.status		= swordfish_sdcc_slot_status,
+	.translate_vdd	= sdcc_translate_vdd,
+};
+
+int __init swordfish_init_mmc(void)
+{
+	vreg_sdcc_enabled = 0;
+	vreg_sdcc = vreg_get(NULL, "gp5");
+	if (IS_ERR(vreg_sdcc)) {
+		pr_err("%s: vreg get failed (%ld)\n",
+		       __func__, PTR_ERR(vreg_sdcc));
+		return PTR_ERR(vreg_sdcc);
+	}
+
+	fpga_base = ioremap(FPGA_BASE, SZ_4K);
+	if (!fpga_base) {
+		pr_err("%s: Can't ioremap FPGA base address (0x%08x)\n",
+		       __func__, FPGA_BASE);
+		vreg_put(vreg_sdcc);
+		return -EIO;
+	}
+
+	msm_add_sdcc(1, &swordfish_sdcc_data, 0, 0);
+	msm_add_sdcc(4, &swordfish_sdcc_data, 0, 0);
+
+	return 0;
+}
+
diff --git a/arch/arm/mach-msm/board-swordfish-panel.c b/arch/arm/mach-msm/board-swordfish-panel.c
new file mode 100644
index 0000000..cf5f3f6
--- /dev/null
+++ b/arch/arm/mach-msm/board-swordfish-panel.c
@@ -0,0 +1,116 @@
+/* linux/arch/arm/mach-msm/board-swordfish-panel.c
+ *
+ * Copyright (c) 2009 Google Inc.
+ *
+ * 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.
+ *
+ * Author: Dima Zavin <dima@android.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+
+#include <asm/io.h>
+#include <asm/mach-types.h>
+
+#include <mach/msm_fb.h>
+
+#include "board-swordfish.h"
+#include "devices.h"
+
+#define CLK_NS_TO_RATE(ns)			(1000000000UL / (ns))
+
+int swordfish_panel_blank(struct msm_lcdc_panel_ops *ops)
+{
+	/* TODO: Turn backlight off? */
+	return 0;
+}
+
+int swordfish_panel_unblank(struct msm_lcdc_panel_ops *ops)
+{
+	/* TODO: Turn backlight on? */
+	return 0;
+}
+
+int swordfish_panel_init(struct msm_lcdc_panel_ops *ops)
+{
+	return 0;
+}
+
+static struct resource resources_msm_fb[] = {
+	{
+		.start = MSM_FB_BASE,
+		.end = MSM_FB_BASE + MSM_FB_SIZE,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct msm_lcdc_timing swordfish_lcdc_timing = {
+	.clk_rate		= CLK_NS_TO_RATE(26),
+	.hsync_pulse_width	= 60,
+	.hsync_back_porch	= 81,
+	.hsync_front_porch	= 81,
+	.hsync_skew		= 0,
+	.vsync_pulse_width	= 2,
+	.vsync_back_porch	= 20,
+	.vsync_front_porch	= 27,
+	.vsync_act_low		= 0,
+	.hsync_act_low		= 0,
+	.den_act_low		= 0,
+};
+
+static struct msm_fb_data swordfish_lcdc_fb_data = {
+	.xres		= 800,
+	.yres		= 480,
+	.width		= 94,
+	.height		= 57,
+	.output_format	= 0,
+};
+
+static struct msm_lcdc_panel_ops swordfish_lcdc_panel_ops = {
+	.init		= swordfish_panel_init,
+	.blank		= swordfish_panel_blank,
+	.unblank	= swordfish_panel_unblank,
+};
+
+static struct msm_lcdc_platform_data swordfish_lcdc_platform_data = {
+	.panel_ops	= &swordfish_lcdc_panel_ops,
+	.timing		= &swordfish_lcdc_timing,
+	.fb_id		= 0,
+	.fb_data	= &swordfish_lcdc_fb_data,
+	.fb_resource = &resources_msm_fb[0],
+};
+
+static struct platform_device swordfish_lcdc_device = {
+	.name	= "msm_mdp_lcdc",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &swordfish_lcdc_platform_data,
+	},
+};
+
+int __init swordfish_init_panel(void)
+{
+	int rc;
+	if (!machine_is_swordfish())
+		return 0;
+
+	if ((rc = platform_device_register(&msm_device_mdp)) != 0)
+		return rc;
+
+	if ((rc = platform_device_register(&swordfish_lcdc_device)) != 0)
+		return rc;
+
+	return 0;
+}
+
+device_initcall(swordfish_init_panel);
diff --git a/arch/arm/mach-msm/board-swordfish.c b/arch/arm/mach-msm/board-swordfish.c
new file mode 100644
index 0000000..45d5bb0
--- /dev/null
+++ b/arch/arm/mach-msm/board-swordfish.c
@@ -0,0 +1,366 @@
+/* linux/arch/arm/mach-msm/board-swordfish.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/android_pmem.h>
+#include <linux/msm_kgsl.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/setup.h>
+
+#include <mach/board.h>
+#include <mach/irqs.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_hsusb.h>
+#include <mach/msm_ts.h>
+#include <mach/proc_comm.h>
+#include <linux/usb/android_composite.h>
+
+#include "board-swordfish.h"
+#include "devices.h"
+
+extern int swordfish_init_mmc(void);
+
+static struct resource smc91x_resources[] = {
+	[0] = {
+		.start	= 0x70000300,
+		.end	= 0x70000400,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= MSM_GPIO_TO_INT(156),
+		.end	= MSM_GPIO_TO_INT(156),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device smc91x_device = {
+	.name		= "smc91x",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(smc91x_resources),
+	.resource	= smc91x_resources,
+};
+
+static int swordfish_phy_init_seq[] = {
+	0x0C, 0x31,
+	0x1D, 0x0D,
+	0x1D, 0x10,
+	-1
+};
+
+static void swordfish_usb_phy_reset(void)
+{
+	u32 id;
+	int ret;
+
+	id = PCOM_CLKRGM_APPS_RESET_USB_PHY;
+	ret = msm_proc_comm(PCOM_CLK_REGIME_SEC_RESET_ASSERT, &id, NULL);
+	if (ret) {
+		pr_err("%s: Cannot assert (%d)\n", __func__, ret);
+		return;
+	}
+
+	msleep(1);
+
+	id = PCOM_CLKRGM_APPS_RESET_USB_PHY;
+	ret = msm_proc_comm(PCOM_CLK_REGIME_SEC_RESET_DEASSERT, &id, NULL);
+	if (ret) {
+		pr_err("%s: Cannot assert (%d)\n", __func__, ret);
+		return;
+	}
+}
+
+static void swordfish_usb_hw_reset(bool enable)
+{
+	u32 id;
+	int ret;
+	u32 func;
+
+	id = PCOM_CLKRGM_APPS_RESET_USBH;
+	if (enable)
+		func = PCOM_CLK_REGIME_SEC_RESET_ASSERT;
+	else
+		func = PCOM_CLK_REGIME_SEC_RESET_DEASSERT;
+	ret = msm_proc_comm(func, &id, NULL);
+	if (ret)
+		pr_err("%s: Cannot set reset to %d (%d)\n", __func__, enable,
+		       ret);
+}
+
+
+static struct msm_hsusb_platform_data msm_hsusb_pdata = {
+	.phy_init_seq		= swordfish_phy_init_seq,
+	.phy_reset		= swordfish_usb_phy_reset,
+	.hw_reset		= swordfish_usb_hw_reset,
+};
+
+static struct usb_mass_storage_platform_data mass_storage_pdata = {
+	.nluns		= 1,
+	.vendor		= "Qualcomm",
+	.product	= "Swordfish",
+	.release	= 0x0100,
+};
+
+static struct platform_device usb_mass_storage_device = {
+	.name	= "usb_mass_storage",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &mass_storage_pdata,
+	},
+};
+
+static struct resource msm_kgsl_resources[] = {
+        {
+                .name   = "kgsl_reg_memory",
+                .start  = MSM_GPU_REG_PHYS,
+                .end    = MSM_GPU_REG_PHYS + MSM_GPU_REG_SIZE - 1,
+                .flags  = IORESOURCE_MEM,
+        },
+        {
+                .name   = "kgsl_phys_memory",
+                .start  = MSM_GPU_MEM_BASE,
+                .end    = MSM_GPU_MEM_BASE + MSM_GPU_MEM_SIZE - 1,
+                .flags  = IORESOURCE_MEM,
+        },
+        {
+                .start  = INT_GRAPHICS,
+                .end    = INT_GRAPHICS,
+                .flags  = IORESOURCE_IRQ,
+        },
+};
+
+static struct platform_device msm_kgsl_device = {
+        .name           = "kgsl",
+        .id             = -1,
+        .resource       = msm_kgsl_resources,
+        .num_resources  = ARRAY_SIZE(msm_kgsl_resources),
+};
+
+static struct android_pmem_platform_data mdp_pmem_pdata = {
+        .name           = "pmem",
+        .start          = MSM_PMEM_MDP_BASE,
+        .size           = MSM_PMEM_MDP_SIZE,
+        .no_allocator   = 0,
+        .cached         = 1,
+};
+
+static struct android_pmem_platform_data android_pmem_gpu0_pdata = {
+        .name           = "pmem_gpu0",
+        .start          = MSM_PMEM_GPU0_BASE,
+        .size           = MSM_PMEM_GPU0_SIZE,
+        .no_allocator   = 0,
+        .cached         = 0,
+};
+
+static struct android_pmem_platform_data android_pmem_gpu1_pdata = {
+        .name           = "pmem_gpu1",
+        .start          = MSM_PMEM_GPU1_BASE,
+        .size           = MSM_PMEM_GPU1_SIZE,
+        .no_allocator   = 0,
+        .cached         = 0,
+};
+
+static struct android_pmem_platform_data android_pmem_adsp_pdata = {
+        .name           = "pmem_adsp",
+        .start          = MSM_PMEM_ADSP_BASE,
+        .size           = MSM_PMEM_ADSP_SIZE,
+        .no_allocator   = 0,
+        .cached         = 0,
+};
+
+static struct platform_device android_pmem_mdp_device = {
+        .name           = "android_pmem",
+        .id             = 0,
+        .dev            = {
+                .platform_data = &mdp_pmem_pdata
+        },
+};
+
+static struct platform_device android_pmem_adsp_device = {
+        .name           = "android_pmem",
+        .id             = 1,
+        .dev            = {
+                .platform_data = &android_pmem_adsp_pdata,
+        },
+};
+
+static struct platform_device android_pmem_gpu0_device = {
+        .name           = "android_pmem",
+        .id             = 2,
+        .dev            = {
+                .platform_data = &android_pmem_gpu0_pdata,
+        },
+};
+
+static struct platform_device android_pmem_gpu1_device = {
+        .name           = "android_pmem",
+        .id             = 3,
+        .dev            = {
+                .platform_data = &android_pmem_gpu1_pdata,
+        },
+};
+
+static char *usb_functions[] = { "usb_mass_storage" };
+static char *usb_functions_adb[] = { "usb_mass_storage", "adb" };
+
+static struct android_usb_product usb_products[] = {
+	{
+		.product_id	= 0x0c01,
+		.num_functions	= ARRAY_SIZE(usb_functions),
+		.functions	= usb_functions,
+	},
+	{
+		.product_id	= 0x0c02,
+		.num_functions	= ARRAY_SIZE(usb_functions_adb),
+		.functions	= usb_functions_adb,
+	},
+};
+
+static struct android_usb_platform_data android_usb_pdata = {
+	.vendor_id		= 0x18d1,
+	.product_id		= 0x0d01,
+	.version		= 0x0100,
+	.serial_number		= "42",
+	.product_name		= "Swordfishdroid",
+	.manufacturer_name	= "Qualcomm",
+	.num_products = ARRAY_SIZE(usb_products),
+	.products = usb_products,
+	.num_functions = ARRAY_SIZE(usb_functions_adb),
+	.functions = usb_functions_adb,
+};
+
+static struct platform_device android_usb_device = {
+	.name	= "android_usb",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &android_usb_pdata,
+	},
+};
+
+static struct platform_device fish_battery_device = {
+	.name = "fish_battery",
+};
+
+static struct msm_ts_platform_data swordfish_ts_pdata = {
+	.min_x		= 296,
+	.max_x		= 3800,
+	.min_y		= 296,
+	.max_y		= 3800,
+	.min_press	= 0,
+	.max_press	= 256,
+	.inv_x		= 4096,
+	.inv_y		= 4096,
+};
+
+static struct platform_device *devices[] __initdata = {
+#if !defined(CONFIG_MSM_SERIAL_DEBUGGER)
+	&msm_device_uart3,
+#endif
+	&msm_device_smd,
+	&msm_device_dmov,
+	&msm_device_nand,
+	&msm_device_hsusb,
+	&usb_mass_storage_device,
+	&android_usb_device,
+	&fish_battery_device,
+	&smc91x_device,
+	&msm_device_touchscreen,
+	&android_pmem_mdp_device,
+	&android_pmem_adsp_device,
+	&android_pmem_gpu0_device,
+	&android_pmem_gpu1_device,
+	&msm_kgsl_device,
+};
+
+extern struct sys_timer msm_timer;
+
+static struct msm_acpu_clock_platform_data swordfish_clock_data = {
+	.acpu_switch_time_us	= 20,
+	.max_speed_delta_khz	= 256000,
+	.vdd_switch_time_us	= 62,
+	.power_collapse_khz	= 128000000,
+	.wait_for_irq_khz	= 128000000,
+};
+
+void msm_serial_debug_init(unsigned int base, int irq,
+			   struct device *clk_device, int signal_irq);
+
+static void __init swordfish_init(void)
+{
+	int rc;
+
+	msm_acpu_clock_init(&swordfish_clock_data);
+#if defined(CONFIG_MSM_SERIAL_DEBUGGER)
+	msm_serial_debug_init(MSM_UART3_PHYS, INT_UART3,
+			      &msm_device_uart3.dev, 1);
+#endif
+	msm_device_hsusb.dev.platform_data = &msm_hsusb_pdata;
+	msm_device_touchscreen.dev.platform_data = &swordfish_ts_pdata;
+	platform_add_devices(devices, ARRAY_SIZE(devices));
+	msm_hsusb_set_vbus_state(1);
+	rc = swordfish_init_mmc();
+	if (rc)
+		pr_crit("%s: MMC init failure (%d)\n", __func__, rc);
+}
+
+static void __init swordfish_fixup(struct machine_desc *desc, struct tag *tags,
+				 char **cmdline, struct meminfo *mi)
+{
+	mi->nr_banks = 1;
+	mi->bank[0].start = PHYS_OFFSET;
+	mi->bank[0].node = PHYS_TO_NID(PHYS_OFFSET);
+	mi->bank[0].size = (101*1024*1024);
+}
+
+static void __init swordfish_map_io(void)
+{
+	msm_map_qsd8x50_io();
+	msm_clock_init(msm_clocks_8x50, msm_num_clocks_8x50);
+}
+
+MACHINE_START(SWORDFISH, "Swordfish Board (QCT SURF8250)")
+#ifdef CONFIG_MSM_DEBUG_UART
+	.phys_io        = MSM_DEBUG_UART_PHYS,
+	.io_pg_offst    = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
+#endif
+	.atag_offset	= 0x100,
+	.fixup		= swordfish_fixup,
+	.map_io		= swordfish_map_io,
+	.init_irq	= msm_init_irq,
+	.init_machine	= swordfish_init,
+	.timer		= &msm_timer,
+MACHINE_END
+
+MACHINE_START(QSD8X50_FFA, "qsd8x50 FFA Board (QCT FFA8250)")
+#ifdef CONFIG_MSM_DEBUG_UART
+	.phys_io	= MSM_DEBUG_UART_PHYS,
+	.io_pg_offst	= ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
+#endif
+	.atag_offset	= 0x100,
+	.fixup		= swordfish_fixup,
+	.map_io		= swordfish_map_io,
+	.init_irq	= msm_init_irq,
+	.init_machine	= swordfish_init,
+	.timer		= &msm_timer,
+MACHINE_END
diff --git a/arch/arm/mach-msm/board-swordfish.h b/arch/arm/mach-msm/board-swordfish.h
new file mode 100644
index 0000000..b9ea54f
--- /dev/null
+++ b/arch/arm/mach-msm/board-swordfish.h
@@ -0,0 +1,48 @@
+/* arch/arm/mach-msm/board-swordfish.h
+ *
+ * Copyright (C) 2009 Google Inc.
+ * Author: Dima Zavin <dima@android.com>
+ *
+ * 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 __ARCH_ARM_MACH_MSM_BOARD_SWORDFISH_H
+#define __ARCH_ARM_MACH_MSM_BOARD_SWORDFISH_H
+
+#include <mach/board.h>
+
+#define MSM_SMI_BASE		0x02B00000
+#define MSM_SMI_SIZE		0x01500000
+
+#define MSM_PMEM_MDP_BASE	0x03000000
+#define MSM_PMEM_MDP_SIZE	0x01000000
+
+#define MSM_EBI1_BASE		0x20000000
+#define MSM_EBI1_SIZE		0x0E000000
+
+#define MSM_PMEM_ADSP_BASE      0x2A300000
+#define MSM_PMEM_ADSP_SIZE      0x02000000
+
+#define MSM_PMEM_GPU1_BASE	0x2C300000
+#define MSM_PMEM_GPU1_SIZE	0x01400000
+
+#define MSM_PMEM_GPU0_BASE	0x2D700000
+#define MSM_PMEM_GPU0_SIZE	0x00400000
+
+#define MSM_GPU_MEM_BASE	0x2DB00000
+#define MSM_GPU_MEM_SIZE	0x00200000
+
+#define MSM_RAM_CONSOLE_BASE	0x2DD00000
+#define MSM_RAM_CONSOLE_SIZE	0x00040000
+
+#define MSM_FB_BASE		0x2DE00000
+#define MSM_FB_SIZE		0x00200000
+
+#endif /* __ARCH_ARM_MACH_MSM_BOARD_SWORDFISH_H */
diff --git a/arch/arm/mach-msm/board-trout-keypad.c b/arch/arm/mach-msm/board-trout-keypad.c
new file mode 100644
index 0000000..0299d06
--- /dev/null
+++ b/arch/arm/mach-msm/board-trout-keypad.c
@@ -0,0 +1,345 @@
+/* arch/arm/mach-msm/board-trout-keypad.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/gpio_event.h>
+#include <asm/mach-types.h>
+
+#include "board-trout.h"
+
+static char *keycaps = "--qwerty";
+#undef MODULE_PARAM_PREFIX
+#define MODULE_PARAM_PREFIX "board_trout."
+module_param_named(keycaps, keycaps, charp, 0);
+
+
+static unsigned int trout_col_gpios[] = { 35, 34, 33, 32, 31, 23, 30, 78 };
+static unsigned int trout_row_gpios[] = { 42, 41, 40, 39, 38, 37, 36 };
+
+#define KEYMAP_INDEX(col, row) ((col)*ARRAY_SIZE(trout_row_gpios) + (row))
+
+static const unsigned short trout_keymap[ARRAY_SIZE(trout_col_gpios) * ARRAY_SIZE(trout_row_gpios)] = {
+	[KEYMAP_INDEX(0, 0)] = KEY_BACK,
+	[KEYMAP_INDEX(0, 1)] = KEY_HOME,
+//	[KEYMAP_INDEX(0, 2)] = KEY_,
+	[KEYMAP_INDEX(0, 3)] = KEY_BACKSPACE,
+	[KEYMAP_INDEX(0, 4)] = KEY_ENTER,
+	[KEYMAP_INDEX(0, 5)] = KEY_RIGHTALT,
+	[KEYMAP_INDEX(0, 6)] = KEY_P,
+
+	[KEYMAP_INDEX(1, 0)] = KEY_MENU,
+//	[KEYMAP_INDEX(1, 0)] = 229, // SOFT1
+	[KEYMAP_INDEX(1, 1)] = KEY_SEND,
+	[KEYMAP_INDEX(1, 2)] = KEY_END,
+	[KEYMAP_INDEX(1, 3)] = KEY_LEFTALT,
+	[KEYMAP_INDEX(1, 4)] = KEY_A,
+	[KEYMAP_INDEX(1, 5)] = KEY_LEFTSHIFT,
+	[KEYMAP_INDEX(1, 6)] = KEY_Q,
+
+	[KEYMAP_INDEX(2, 0)] = KEY_U,
+	[KEYMAP_INDEX(2, 1)] = KEY_7,
+	[KEYMAP_INDEX(2, 2)] = KEY_K,
+	[KEYMAP_INDEX(2, 3)] = KEY_J,
+	[KEYMAP_INDEX(2, 4)] = KEY_M,
+	[KEYMAP_INDEX(2, 5)] = KEY_SLASH,
+	[KEYMAP_INDEX(2, 6)] = KEY_8,
+
+	[KEYMAP_INDEX(3, 0)] = KEY_5,
+	[KEYMAP_INDEX(3, 1)] = KEY_6,
+	[KEYMAP_INDEX(3, 2)] = KEY_B,
+	[KEYMAP_INDEX(3, 3)] = KEY_H,
+	[KEYMAP_INDEX(3, 4)] = KEY_N,
+	[KEYMAP_INDEX(3, 5)] = KEY_SPACE,
+	[KEYMAP_INDEX(3, 6)] = KEY_Y,
+
+	[KEYMAP_INDEX(4, 0)] = KEY_4,
+	[KEYMAP_INDEX(4, 1)] = KEY_R,
+	[KEYMAP_INDEX(4, 2)] = KEY_V,
+	[KEYMAP_INDEX(4, 3)] = KEY_G,
+	[KEYMAP_INDEX(4, 4)] = KEY_C,
+	//[KEYMAP_INDEX(4, 5)] = KEY_,
+	[KEYMAP_INDEX(4, 6)] = KEY_T,
+
+	[KEYMAP_INDEX(5, 0)] = KEY_2,
+	[KEYMAP_INDEX(5, 1)] = KEY_W,
+	[KEYMAP_INDEX(5, 2)] = KEY_COMPOSE,
+	[KEYMAP_INDEX(5, 3)] = KEY_VOLUMEUP,
+	[KEYMAP_INDEX(5, 4)] = KEY_S,
+	[KEYMAP_INDEX(5, 5)] = KEY_Z,
+	[KEYMAP_INDEX(5, 6)] = KEY_1,
+
+	[KEYMAP_INDEX(6, 0)] = KEY_I,
+	[KEYMAP_INDEX(6, 1)] = KEY_0,
+	[KEYMAP_INDEX(6, 2)] = KEY_O,
+	[KEYMAP_INDEX(6, 3)] = KEY_L,
+	[KEYMAP_INDEX(6, 4)] = KEY_DOT,
+	[KEYMAP_INDEX(6, 5)] = KEY_COMMA,
+	[KEYMAP_INDEX(6, 6)] = KEY_9,
+
+	[KEYMAP_INDEX(7, 0)] = KEY_3,
+	[KEYMAP_INDEX(7, 1)] = KEY_E,
+	[KEYMAP_INDEX(7, 2)] = KEY_EMAIL, // @
+	[KEYMAP_INDEX(7, 3)] = KEY_VOLUMEDOWN,
+	[KEYMAP_INDEX(7, 4)] = KEY_X,
+	[KEYMAP_INDEX(7, 5)] = KEY_F,
+	[KEYMAP_INDEX(7, 6)] = KEY_D
+};
+
+static unsigned int trout_col_gpios_evt2[] = { 35, 34, 33, 32, 31, 23, 30, 109 };
+static unsigned int trout_row_gpios_evt2[] = { 42, 41, 40, 39, 38, 37, 36 };
+
+static const unsigned short trout_keymap_evt2_1[ARRAY_SIZE(trout_col_gpios) * ARRAY_SIZE(trout_row_gpios)] = {
+	[KEYMAP_INDEX(0, 0)] = KEY_BACK,
+	[KEYMAP_INDEX(0, 1)] = KEY_HOME,
+//	[KEYMAP_INDEX(0, 2)] = KEY_,
+	[KEYMAP_INDEX(0, 3)] = KEY_BACKSPACE,
+	[KEYMAP_INDEX(0, 4)] = KEY_ENTER,
+	[KEYMAP_INDEX(0, 5)] = KEY_RIGHTSHIFT,
+	[KEYMAP_INDEX(0, 6)] = KEY_P,
+
+	[KEYMAP_INDEX(1, 0)] = KEY_MENU,
+	[KEYMAP_INDEX(1, 1)] = KEY_SEND,
+//	[KEYMAP_INDEX(1, 2)] = KEY_,
+	[KEYMAP_INDEX(1, 3)] = KEY_LEFTSHIFT,
+	[KEYMAP_INDEX(1, 4)] = KEY_A,
+	[KEYMAP_INDEX(1, 5)] = KEY_COMPOSE,
+	[KEYMAP_INDEX(1, 6)] = KEY_Q,
+
+	[KEYMAP_INDEX(2, 0)] = KEY_U,
+	[KEYMAP_INDEX(2, 1)] = KEY_7,
+	[KEYMAP_INDEX(2, 2)] = KEY_K,
+	[KEYMAP_INDEX(2, 3)] = KEY_J,
+	[KEYMAP_INDEX(2, 4)] = KEY_M,
+	[KEYMAP_INDEX(2, 5)] = KEY_SLASH,
+	[KEYMAP_INDEX(2, 6)] = KEY_8,
+
+	[KEYMAP_INDEX(3, 0)] = KEY_5,
+	[KEYMAP_INDEX(3, 1)] = KEY_6,
+	[KEYMAP_INDEX(3, 2)] = KEY_B,
+	[KEYMAP_INDEX(3, 3)] = KEY_H,
+	[KEYMAP_INDEX(3, 4)] = KEY_N,
+	[KEYMAP_INDEX(3, 5)] = KEY_SPACE,
+	[KEYMAP_INDEX(3, 6)] = KEY_Y,
+
+	[KEYMAP_INDEX(4, 0)] = KEY_4,
+	[KEYMAP_INDEX(4, 1)] = KEY_R,
+	[KEYMAP_INDEX(4, 2)] = KEY_V,
+	[KEYMAP_INDEX(4, 3)] = KEY_G,
+	[KEYMAP_INDEX(4, 4)] = KEY_C,
+//	[KEYMAP_INDEX(4, 5)] = KEY_,
+	[KEYMAP_INDEX(4, 6)] = KEY_T,
+
+	[KEYMAP_INDEX(5, 0)] = KEY_2,
+	[KEYMAP_INDEX(5, 1)] = KEY_W,
+	[KEYMAP_INDEX(5, 2)] = KEY_LEFTALT,
+	[KEYMAP_INDEX(5, 3)] = KEY_VOLUMEUP,
+	[KEYMAP_INDEX(5, 4)] = KEY_S,
+	[KEYMAP_INDEX(5, 5)] = KEY_Z,
+	[KEYMAP_INDEX(5, 6)] = KEY_1,
+
+	[KEYMAP_INDEX(6, 0)] = KEY_I,
+	[KEYMAP_INDEX(6, 1)] = KEY_0,
+	[KEYMAP_INDEX(6, 2)] = KEY_O,
+	[KEYMAP_INDEX(6, 3)] = KEY_L,
+	[KEYMAP_INDEX(6, 4)] = KEY_COMMA,
+	[KEYMAP_INDEX(6, 5)] = KEY_DOT,
+	[KEYMAP_INDEX(6, 6)] = KEY_9,
+
+	[KEYMAP_INDEX(7, 0)] = KEY_3,
+	[KEYMAP_INDEX(7, 1)] = KEY_E,
+	[KEYMAP_INDEX(7, 2)] = KEY_EMAIL, // @
+	[KEYMAP_INDEX(7, 3)] = KEY_VOLUMEDOWN,
+	[KEYMAP_INDEX(7, 4)] = KEY_X,
+	[KEYMAP_INDEX(7, 5)] = KEY_F,
+	[KEYMAP_INDEX(7, 6)] = KEY_D
+};
+
+static const unsigned short trout_keymap_evt2_2[ARRAY_SIZE(trout_col_gpios) * ARRAY_SIZE(trout_row_gpios)] = {
+	[KEYMAP_INDEX(0, 0)] = KEY_BACK,
+	[KEYMAP_INDEX(0, 1)] = KEY_HOME,
+//	[KEYMAP_INDEX(0, 2)] = KEY_,
+	[KEYMAP_INDEX(0, 3)] = KEY_BACKSPACE,
+	[KEYMAP_INDEX(0, 4)] = KEY_ENTER,
+	[KEYMAP_INDEX(0, 5)] = KEY_RIGHTSHIFT,
+	[KEYMAP_INDEX(0, 6)] = KEY_P,
+
+	[KEYMAP_INDEX(1, 0)] = KEY_MENU, /* external menu key */
+	[KEYMAP_INDEX(1, 1)] = KEY_SEND,
+//	[KEYMAP_INDEX(1, 2)] = KEY_,
+	[KEYMAP_INDEX(1, 3)] = KEY_LEFTSHIFT,
+	[KEYMAP_INDEX(1, 4)] = KEY_A,
+	[KEYMAP_INDEX(1, 5)] = KEY_F1, /* qwerty menu key */
+	[KEYMAP_INDEX(1, 6)] = KEY_Q,
+
+	[KEYMAP_INDEX(2, 0)] = KEY_U,
+	[KEYMAP_INDEX(2, 1)] = KEY_7,
+	[KEYMAP_INDEX(2, 2)] = KEY_K,
+	[KEYMAP_INDEX(2, 3)] = KEY_J,
+	[KEYMAP_INDEX(2, 4)] = KEY_M,
+	[KEYMAP_INDEX(2, 5)] = KEY_DOT,
+	[KEYMAP_INDEX(2, 6)] = KEY_8,
+
+	[KEYMAP_INDEX(3, 0)] = KEY_5,
+	[KEYMAP_INDEX(3, 1)] = KEY_6,
+	[KEYMAP_INDEX(3, 2)] = KEY_B,
+	[KEYMAP_INDEX(3, 3)] = KEY_H,
+	[KEYMAP_INDEX(3, 4)] = KEY_N,
+	[KEYMAP_INDEX(3, 5)] = KEY_SPACE,
+	[KEYMAP_INDEX(3, 6)] = KEY_Y,
+
+	[KEYMAP_INDEX(4, 0)] = KEY_4,
+	[KEYMAP_INDEX(4, 1)] = KEY_R,
+	[KEYMAP_INDEX(4, 2)] = KEY_V,
+	[KEYMAP_INDEX(4, 3)] = KEY_G,
+	[KEYMAP_INDEX(4, 4)] = KEY_C,
+	[KEYMAP_INDEX(4, 5)] = KEY_EMAIL, // @
+	[KEYMAP_INDEX(4, 6)] = KEY_T,
+
+	[KEYMAP_INDEX(5, 0)] = KEY_2,
+	[KEYMAP_INDEX(5, 1)] = KEY_W,
+	[KEYMAP_INDEX(5, 2)] = KEY_LEFTALT,
+	[KEYMAP_INDEX(5, 3)] = KEY_VOLUMEUP,
+	[KEYMAP_INDEX(5, 4)] = KEY_S,
+	[KEYMAP_INDEX(5, 5)] = KEY_Z,
+	[KEYMAP_INDEX(5, 6)] = KEY_1,
+
+	[KEYMAP_INDEX(6, 0)] = KEY_I,
+	[KEYMAP_INDEX(6, 1)] = KEY_0,
+	[KEYMAP_INDEX(6, 2)] = KEY_O,
+	[KEYMAP_INDEX(6, 3)] = KEY_L,
+	[KEYMAP_INDEX(6, 4)] = KEY_COMMA,
+	[KEYMAP_INDEX(6, 5)] = KEY_RIGHTALT,
+	[KEYMAP_INDEX(6, 6)] = KEY_9,
+
+	[KEYMAP_INDEX(7, 0)] = KEY_3,
+	[KEYMAP_INDEX(7, 1)] = KEY_E,
+	[KEYMAP_INDEX(7, 2)] = KEY_COMPOSE,
+	[KEYMAP_INDEX(7, 3)] = KEY_VOLUMEDOWN,
+	[KEYMAP_INDEX(7, 4)] = KEY_X,
+	[KEYMAP_INDEX(7, 5)] = KEY_F,
+	[KEYMAP_INDEX(7, 6)] = KEY_D
+};
+
+static struct gpio_event_matrix_info trout_keypad_matrix_info = {
+	.info.func = gpio_event_matrix_func,
+	.keymap = trout_keymap,
+	.output_gpios = trout_col_gpios,
+	.input_gpios = trout_row_gpios,
+	.noutputs = ARRAY_SIZE(trout_col_gpios),
+	.ninputs = ARRAY_SIZE(trout_row_gpios),
+	.settle_time.tv.nsec = 40 * NSEC_PER_USEC,
+	.poll_time.tv.nsec = 20 * NSEC_PER_MSEC,
+	.flags = GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_REMOVE_PHANTOM_KEYS |GPIOKPF_PRINT_UNMAPPED_KEYS /*| GPIOKPF_PRINT_MAPPED_KEYS*/
+};
+
+static struct gpio_event_direct_entry trout_keypad_nav_map[] = {
+	{ TROUT_POWER_KEY,              KEY_POWER    },
+	{ TROUT_GPIO_CAM_BTN_STEP1_N,   KEY_CAMERA-1 }, //steal KEY_HP
+	{ TROUT_GPIO_CAM_BTN_STEP2_N,   KEY_CAMERA   },
+};
+
+static struct gpio_event_direct_entry trout_keypad_nav_map_evt2[] = {
+	{ TROUT_POWER_KEY,              KEY_END      },
+	{ TROUT_GPIO_CAM_BTN_STEP1_N,   KEY_CAMERA-1 }, //steal KEY_HP
+	{ TROUT_GPIO_CAM_BTN_STEP2_N,   KEY_CAMERA   },
+};
+
+static struct gpio_event_input_info trout_keypad_nav_info = {
+	.info.func = gpio_event_input_func,
+	.flags = 0,
+	.type = EV_KEY,
+	.keymap = trout_keypad_nav_map,
+	.keymap_size = ARRAY_SIZE(trout_keypad_nav_map)
+};
+
+static struct gpio_event_direct_entry trout_keypad_switch_map[] = {
+	{ TROUT_GPIO_SLIDING_DET,       SW_LID       }
+};
+
+static struct gpio_event_input_info trout_keypad_switch_info = {
+	.info.func = gpio_event_input_func,
+	.flags = 0,
+	.type = EV_SW,
+	.keymap = trout_keypad_switch_map,
+	.keymap_size = ARRAY_SIZE(trout_keypad_switch_map)
+};
+
+static struct gpio_event_info *trout_keypad_info[] = {
+	&trout_keypad_matrix_info.info,
+	&trout_keypad_nav_info.info,
+	&trout_keypad_switch_info.info,
+};
+
+static struct gpio_event_platform_data trout_keypad_data = {
+	.name = "trout-keypad",
+	.info = trout_keypad_info,
+	.info_count = ARRAY_SIZE(trout_keypad_info)
+};
+
+static struct platform_device trout_keypad_device = {
+	.name = GPIO_EVENT_DEV_NAME,
+	.id = 0,
+	.dev		= {
+		.platform_data	= &trout_keypad_data,
+	},
+};
+
+static int __init trout_init_keypad(void)
+{
+	if (!machine_is_trout())
+		return 0;
+
+	switch (system_rev) {
+	case 0:
+		/* legacy default keylayout */
+		break;
+	case 1:
+		/* v1 has a new keyboard layout */
+		trout_keypad_matrix_info.keymap = trout_keymap_evt2_1;
+		trout_keypad_matrix_info.output_gpios = trout_col_gpios_evt2;
+		trout_keypad_matrix_info.input_gpios = trout_row_gpios_evt2;
+		
+		/* v1 has new direct keys */
+		trout_keypad_nav_info.keymap = trout_keypad_nav_map_evt2;
+		trout_keypad_nav_info.keymap_size = ARRAY_SIZE(trout_keypad_nav_map_evt2);
+
+		/* userspace needs to know about these changes as well */
+		trout_keypad_data.name = "trout-keypad-v2";
+		break;
+	default: /* 2, 3, 4 currently */
+		/* v2 has a new keyboard layout */
+		trout_keypad_matrix_info.keymap = trout_keymap_evt2_2;
+		trout_keypad_matrix_info.output_gpios = trout_col_gpios_evt2;
+		trout_keypad_matrix_info.input_gpios = trout_row_gpios_evt2;
+		
+		/* v2 has new direct keys */
+		trout_keypad_nav_info.keymap = trout_keypad_nav_map_evt2;
+		trout_keypad_nav_info.keymap_size = ARRAY_SIZE(trout_keypad_nav_map_evt2);
+
+		/* userspace needs to know about these changes as well */
+		if (!strcmp(keycaps, "qwertz")) {
+			trout_keypad_data.name = "trout-keypad-qwertz";
+		} else {
+			trout_keypad_data.name = "trout-keypad-v3";
+		}
+		break;
+	}
+	return platform_device_register(&trout_keypad_device);
+}
+
+device_initcall(trout_init_keypad);
+
diff --git a/arch/arm/mach-msm/board-trout-mmc.c b/arch/arm/mach-msm/board-trout-mmc.c
index 8650342..f7109d5 100644
--- a/arch/arm/mach-msm/board-trout-mmc.c
+++ b/arch/arm/mach-msm/board-trout-mmc.c
@@ -14,15 +14,13 @@
 #include <asm/io.h>
 
 #include <mach/vreg.h>
-
+#include <mach/proc_comm.h>
 #include <mach/mmc.h>
 
 #include "devices.h"
 
 #include "board-trout.h"
 
-#include "proc_comm.h"
-
 #define DEBUG_SDSLOT_VDD 1
 
 /* ---- COMMON ---- */
diff --git a/arch/arm/mach-msm/board-trout-panel.c b/arch/arm/mach-msm/board-trout-panel.c
index 89bf6b4..52948b2 100644
--- a/arch/arm/mach-msm/board-trout-panel.c
+++ b/arch/arm/mach-msm/board-trout-panel.c
@@ -16,9 +16,9 @@
 
 #include <mach/msm_fb.h>
 #include <mach/vreg.h>
+#include <mach/proc_comm.h>
 
 #include "board-trout.h"
-#include "proc_comm.h"
 #include "devices.h"
 
 #define TROUT_DEFAULT_BACKLIGHT_BRIGHTNESS 255
diff --git a/arch/arm/mach-msm/board-trout-rfkill.c b/arch/arm/mach-msm/board-trout-rfkill.c
new file mode 100644
index 0000000..e68eb2a
--- /dev/null
+++ b/arch/arm/mach-msm/board-trout-rfkill.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Nick Pelly <npelly@google.com>
+ *
+ * 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.
+ *
+ */
+
+/* Control bluetooth power for trout platform */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/rfkill.h>
+#include <linux/delay.h>
+#include <asm/gpio.h>
+
+#include "board-trout.h"
+
+static struct rfkill *bt_rfk;
+static const char bt_name[] = "brf6300";
+
+static int bluetooth_set_power(void *data, bool blocked)
+{
+	if (!blocked) {
+		gpio_set_value(TROUT_GPIO_BT_32K_EN, 1);
+		udelay(10);
+		gpio_direction_output(101, 1);
+	} else {
+		gpio_direction_output(101, 0);
+		gpio_set_value(TROUT_GPIO_BT_32K_EN, 0);
+	}
+	return 0;
+}
+
+static struct rfkill_ops trout_rfkill_ops = {
+	.set_block = bluetooth_set_power,
+};
+
+static int trout_rfkill_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	bool default_state = true;  /* off */
+
+	bluetooth_set_power(NULL, default_state);
+
+	bt_rfk = rfkill_alloc(bt_name, &pdev->dev, RFKILL_TYPE_BLUETOOTH,
+				&trout_rfkill_ops, NULL);
+	if (!bt_rfk)
+		return -ENOMEM;
+
+	rfkill_set_states(bt_rfk, default_state, false);
+
+	/* userspace cannot take exclusive control */
+
+	rc = rfkill_register(bt_rfk);
+
+	if (rc)
+		rfkill_destroy(bt_rfk);
+	return rc;
+}
+
+static int trout_rfkill_remove(struct platform_device *dev)
+{
+	rfkill_unregister(bt_rfk);
+	rfkill_destroy(bt_rfk);
+
+	return 0;
+}
+
+static struct platform_driver trout_rfkill_driver = {
+	.probe = trout_rfkill_probe,
+	.remove = trout_rfkill_remove,
+	.driver = {
+		.name = "trout_rfkill",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init trout_rfkill_init(void)
+{
+	return platform_driver_register(&trout_rfkill_driver);
+}
+
+static void __exit trout_rfkill_exit(void)
+{
+	platform_driver_unregister(&trout_rfkill_driver);
+}
+
+module_init(trout_rfkill_init);
+module_exit(trout_rfkill_exit);
+MODULE_DESCRIPTION("trout rfkill");
+MODULE_AUTHOR("Nick Pelly <npelly@google.com>");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/board-trout-wifi.c b/arch/arm/mach-msm/board-trout-wifi.c
new file mode 100644
index 0000000..51b26a4
--- /dev/null
+++ b/arch/arm/mach-msm/board-trout-wifi.c
@@ -0,0 +1,74 @@
+/* arch/arm/mach-msm/board-trout-wifi.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Dmitry Shmidt <dimitrysh@google.com>
+ *
+ * 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.
+ *
+ */
+
+#ifdef CONFIG_WIFI_CONTROL_FUNC
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/vmalloc.h>
+#include <linux/err.h>
+#include <linux/wifi_tiwlan.h>
+
+extern int trout_wifi_set_carddetect(int val);
+extern int trout_wifi_power(int on);
+extern int trout_wifi_reset(int on);
+
+#ifdef CONFIG_WIFI_MEM_PREALLOC
+typedef struct wifi_mem_prealloc_struct {
+	void *mem_ptr;
+	unsigned long size;
+} wifi_mem_prealloc_t;
+
+static wifi_mem_prealloc_t wifi_mem_array[WMPA_NUMBER_OF_SECTIONS] = {
+	{ NULL, (WMPA_SECTION_SIZE_0 + WMPA_SECTION_HEADER) },
+	{ NULL, (WMPA_SECTION_SIZE_1 + WMPA_SECTION_HEADER) },
+	{ NULL, (WMPA_SECTION_SIZE_2 + WMPA_SECTION_HEADER) }
+};
+
+static void *trout_wifi_mem_prealloc(int section, unsigned long size)
+{
+	if( (section < 0) || (section >= WMPA_NUMBER_OF_SECTIONS) )
+		return NULL;
+	if( wifi_mem_array[section].size < size )
+		return NULL;
+	return wifi_mem_array[section].mem_ptr;
+}
+
+int __init trout_init_wifi_mem( void )
+{
+	int i;
+
+	for(i=0;( i < WMPA_NUMBER_OF_SECTIONS );i++) {
+		wifi_mem_array[i].mem_ptr = vmalloc(wifi_mem_array[i].size);
+		if( wifi_mem_array[i].mem_ptr == NULL )
+			return -ENOMEM;
+	}
+	return 0;
+}
+#endif
+
+struct wifi_platform_data trout_wifi_control = {
+	.set_power		= trout_wifi_power,
+	.set_reset		= trout_wifi_reset,
+	.set_carddetect		= trout_wifi_set_carddetect,
+#ifdef CONFIG_WIFI_MEM_PREALLOC
+	.mem_prealloc		= trout_wifi_mem_prealloc,
+#else
+	.mem_prealloc		= NULL,
+#endif	
+};
+
+#endif
diff --git a/arch/arm/mach-msm/btpintest.c b/arch/arm/mach-msm/btpintest.c
new file mode 100644
index 0000000..97a511e
--- /dev/null
+++ b/arch/arm/mach-msm/btpintest.c
@@ -0,0 +1,234 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/uaccess.h>
+#include <linux/version.h>
+#include <linux/debugfs.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <mach/gpio.h>
+#include <mach/vreg.h>
+#include <mach/gpiomux.h>
+
+#define VERSION     "1.0"
+struct dentry *pin_debugfs_dent;
+
+/* UART GPIO lines for 8660 */
+enum uartpins {
+	UARTDM_TX = 53,
+	UARTDM_RX = 54,
+	UARTDM_CTS = 55,
+	UARTDM_RFR = 56
+};
+
+/* Aux PCM GPIO lines for 8660 */
+enum auxpcmpins {
+	AUX_PCM_CLK = 114,
+	AUX_PCM_SYNC = 113,
+	AUX_PCM_DIN  = 112,
+	AUX_PCM_DOUT = 111
+};
+/*Number of UART and PCM pins */
+#define PIN_COUNT 8
+
+static struct gpiomux_setting pin_test_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+/* Static array to intialise the return config */
+static struct gpiomux_setting currentconfig[2*PIN_COUNT];
+
+static struct msm_gpiomux_config pin_test_configs[]  = {
+	{
+		.gpio = AUX_PCM_DOUT,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &pin_test_config,
+			[GPIOMUX_SUSPENDED] = &pin_test_config,
+		},
+	},
+	{
+		.gpio = AUX_PCM_DIN,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &pin_test_config,
+			[GPIOMUX_SUSPENDED] = &pin_test_config,
+		},
+	},
+	{
+		.gpio = AUX_PCM_SYNC,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &pin_test_config,
+			[GPIOMUX_SUSPENDED] = &pin_test_config,
+		},
+	},
+	{
+		.gpio = AUX_PCM_CLK,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &pin_test_config,
+			[GPIOMUX_SUSPENDED] = &pin_test_config,
+		},
+	},
+	{
+		.gpio = UARTDM_TX,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &pin_test_config,
+			[GPIOMUX_SUSPENDED] = &pin_test_config,
+		},
+	},
+	{
+		.gpio = UARTDM_RX,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &pin_test_config,
+			[GPIOMUX_SUSPENDED] = &pin_test_config,
+		},
+	},
+	{
+		.gpio = UARTDM_CTS,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &pin_test_config,
+			[GPIOMUX_SUSPENDED] = &pin_test_config,
+		},
+	},
+	{
+		.gpio = UARTDM_RFR,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &pin_test_config,
+			[GPIOMUX_SUSPENDED] = &pin_test_config,
+		},
+	},
+};
+static struct msm_gpiomux_config pin_config[PIN_COUNT];
+
+static int pintest_open(struct inode *inode, struct file *file)
+{
+	/* non-seekable */
+	file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
+	return 0;
+}
+
+static int pintest_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static int configure_pins(struct msm_gpiomux_config *config,
+				struct msm_gpiomux_config *oldconfig,
+				unsigned int num_configs)
+{
+	int rc = 0, j, i;
+	for (i = 0; i < num_configs; i++) {
+		for (j = 0; j < GPIOMUX_NSETTINGS; j++) {
+			(oldconfig + i)->gpio = (config + i)->gpio;
+			rc = msm_gpiomux_write((config + i)->gpio,
+				j,
+				(config + i)->settings[j],
+				(oldconfig + i)->settings[j]);
+			if (rc < 0)
+				break;
+		}
+
+	}
+	return rc;
+}
+
+static void init_current_config_pointers(void)
+{
+	int i = 0, j = 0;
+	/* The current config variables will hold the current configuration
+	 * which is getting overwritten during a msm_gpiomux_write call
+	 */
+	for (i = 0, j = 0; i < PIN_COUNT; i += 1, j += 2) {
+		pin_config[i].settings[GPIOMUX_ACTIVE] = &currentconfig[j];
+		pin_config[i].settings[GPIOMUX_SUSPENDED] =
+							&currentconfig[j + 1];
+	}
+
+}
+
+static ssize_t pintest_write(
+	struct file *file,
+	const char __user *buff,
+	size_t count,
+	loff_t *ppos)
+{
+	char mode;
+	int rc = 0;
+
+	if (count < 1)
+		return -EINVAL;
+
+	if (buff == NULL)
+		return -EINVAL;
+
+	if (copy_from_user(&mode, buff, count))
+		return -EFAULT;
+	mode = mode - '0';
+
+	init_current_config_pointers();
+
+	if (mode) {
+		/* Configure all pin test gpios for the custom settings */
+		rc = configure_pins(pin_test_configs, pin_config,
+					ARRAY_SIZE(pin_test_configs));
+		if (rc < 0)
+			return rc;
+	} else {
+		/* Configure all pin test gpios for the original settings */
+		rc = configure_pins(pin_config, pin_test_configs,
+					ARRAY_SIZE(pin_test_configs));
+		if (rc < 0)
+			return rc;
+	}
+	return rc;
+}
+
+static const struct file_operations pintest_debugfs_fops = {
+	.open = pintest_open,
+	.release = pintest_release,
+	.write = pintest_write,
+};
+
+static int __init bluepintest_init(void)
+{
+	pin_debugfs_dent = debugfs_create_dir("btpintest", NULL);
+
+	if (IS_ERR(pin_debugfs_dent)) {
+		printk(KERN_ERR "%s(%d): debugfs_create_dir fail, error %ld\n",
+			__FILE__, __LINE__, PTR_ERR(pin_debugfs_dent));
+		return -ENOMEM;
+	}
+
+	if (debugfs_create_file("enable", 0644, pin_debugfs_dent,
+					0, &pintest_debugfs_fops) == NULL) {
+		printk(KERN_ERR "%s(%d): debugfs_create_file: index fail\n",
+							__FILE__, __LINE__);
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+static void __exit bluepintest_exit(void)
+{
+	debugfs_remove_recursive(pin_debugfs_dent);
+}
+
+module_init(bluepintest_init);
+module_exit(bluepintest_exit);
+
+MODULE_DESCRIPTION("Bluetooth Pin Connectivty Test Driver ver %s " VERSION);
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/cache_erp.c b/arch/arm/mach-msm/cache_erp.c
new file mode 100644
index 0000000..97225ac
--- /dev/null
+++ b/arch/arm/mach-msm/cache_erp.c
@@ -0,0 +1,515 @@
+/* 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/interrupt.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/cpu.h>
+#include <linux/io.h>
+#include <mach/msm-krait-l2-accessors.h>
+#include <mach/msm_iomap.h>
+#include <asm/cputype.h>
+#include "acpuclock.h"
+
+#define CESR_DCTPE		BIT(0)
+#define CESR_DCDPE		BIT(1)
+#define CESR_ICTPE		BIT(2)
+#define CESR_ICDPE		BIT(3)
+#define CESR_DCTE		(BIT(4) | BIT(5))
+#define CESR_ICTE		(BIT(6) | BIT(7))
+#define CESR_TLBMH		BIT(16)
+#define CESR_I_MASK		0x000000CC
+
+/* Print a message for everything but TLB MH events */
+#define CESR_PRINT_MASK		0x000000FF
+
+#define L2ESR_IND_ADDR		0x204
+#define L2ESYNR0_IND_ADDR	0x208
+#define L2ESYNR1_IND_ADDR	0x209
+#define L2EAR0_IND_ADDR		0x20C
+#define L2EAR1_IND_ADDR		0x20D
+
+#define L2ESR_MPDCD		BIT(0)
+#define L2ESR_MPSLV             BIT(1)
+#define L2ESR_TSESB             BIT(2)
+#define L2ESR_TSEDB             BIT(3)
+#define L2ESR_DSESB             BIT(4)
+#define L2ESR_DSEDB             BIT(5)
+#define L2ESR_MSE		BIT(6)
+#define L2ESR_MPLDREXNOK	BIT(8)
+
+#define L2ESR_ACCESS_ERR_MASK	0xFFFC
+
+#define L2ESR_CPU_MASK		0x0F
+#define L2ESR_CPU_SHIFT		16
+
+#ifdef CONFIG_MSM_L1_ERR_PANIC
+#define ERP_L1_ERR(a) panic(a)
+#else
+#define ERP_L1_ERR(a) do { } while (0)
+#endif
+
+#ifdef CONFIG_MSM_L2_ERP_PORT_PANIC
+#define ERP_PORT_ERR(a) panic(a)
+#else
+#define ERP_PORT_ERR(a) WARN(1, a)
+#endif
+
+#ifdef CONFIG_MSM_L2_ERP_1BIT_PANIC
+#define ERP_1BIT_ERR(a) panic(a)
+#else
+#define ERP_1BIT_ERR(a) do { } while (0)
+#endif
+
+#ifdef CONFIG_MSM_L2_ERP_PRINT_ACCESS_ERRORS
+#define print_access_errors()	1
+#else
+#define print_access_errors()	0
+#endif
+
+#ifdef CONFIG_MSM_L2_ERP_2BIT_PANIC
+#define ERP_2BIT_ERR(a) panic(a)
+#else
+#define ERP_2BIT_ERR(a) do { } while (0)
+#endif
+
+#define MODULE_NAME "msm_cache_erp"
+
+struct msm_l1_err_stats {
+	unsigned int dctpe;
+	unsigned int dcdpe;
+	unsigned int ictpe;
+	unsigned int icdpe;
+	unsigned int dcte;
+	unsigned int icte;
+	unsigned int tlbmh;
+};
+
+struct msm_l2_err_stats {
+	unsigned int mpdcd;
+	unsigned int mpslv;
+	unsigned int tsesb;
+	unsigned int tsedb;
+	unsigned int dsesb;
+	unsigned int dsedb;
+	unsigned int mse;
+	unsigned int mplxrexnok;
+};
+
+static DEFINE_PER_CPU(struct msm_l1_err_stats, msm_l1_erp_stats);
+static struct msm_l2_err_stats msm_l2_erp_stats;
+
+static int l1_erp_irq, l2_erp_irq;
+static struct proc_dir_entry *procfs_entry;
+
+static inline unsigned int read_cesr(void)
+{
+	unsigned int cesr;
+	asm volatile ("mrc p15, 7, %0, c15, c0, 1" : "=r" (cesr));
+	return cesr;
+}
+
+static inline void write_cesr(unsigned int cesr)
+{
+	asm volatile ("mcr p15, 7, %[cesr], c15, c0, 1" : : [cesr]"r" (cesr));
+}
+
+static inline unsigned int read_cesynr(void)
+{
+	unsigned int cesynr;
+	asm volatile ("mrc p15, 7, %0, c15, c0, 3" : "=r" (cesynr));
+	return cesynr;
+}
+
+static int proc_read_status(char *page, char **start, off_t off, int count,
+			    int *eof, void *data)
+{
+	struct msm_l1_err_stats *l1_stats;
+	char *p = page;
+	int len, cpu, ret, bytes_left = PAGE_SIZE;
+
+	for_each_present_cpu(cpu) {
+		l1_stats = &per_cpu(msm_l1_erp_stats, cpu);
+
+		ret = snprintf(p, bytes_left,
+			"CPU %d:\n"	\
+			"\tD-cache tag parity errors:\t%u\n"	\
+			"\tD-cache data parity errors:\t%u\n"	\
+			"\tI-cache tag parity errors:\t%u\n"	\
+			"\tI-cache data parity errors:\t%u\n"	\
+			"\tD-cache timing errors:\t\t%u\n"	\
+			"\tI-cache timing errors:\t\t%u\n"	\
+			"\tTLB multi-hit errors:\t\t%u\n\n",	\
+			cpu,
+			l1_stats->dctpe,
+			l1_stats->dcdpe,
+			l1_stats->ictpe,
+			l1_stats->icdpe,
+			l1_stats->dcte,
+			l1_stats->icte,
+			l1_stats->tlbmh);
+		p += ret;
+		bytes_left -= ret;
+	}
+
+	p += snprintf(p, bytes_left,
+			"L2 master port decode errors:\t\t%u\n"	\
+			"L2 master port slave errors:\t\t%u\n"		\
+			"L2 tag soft errors, single-bit:\t\t%u\n"	\
+			"L2 tag soft errors, double-bit:\t\t%u\n"	\
+			"L2 data soft errors, single-bit:\t%u\n"	\
+			"L2 data soft errors, double-bit:\t%u\n"	\
+			"L2 modified soft errors:\t\t%u\n"		\
+			"L2 master port LDREX NOK errors:\t%u\n",
+			msm_l2_erp_stats.mpdcd,
+			msm_l2_erp_stats.mpslv,
+			msm_l2_erp_stats.tsesb,
+			msm_l2_erp_stats.tsedb,
+			msm_l2_erp_stats.dsesb,
+			msm_l2_erp_stats.dsedb,
+			msm_l2_erp_stats.mse,
+			msm_l2_erp_stats.mplxrexnok);
+
+	len = (p - page) - off;
+	if (len < 0)
+		len = 0;
+
+	*eof = (len <= count) ? 1 : 0;
+	*start = page + off;
+
+	return len;
+}
+
+static irqreturn_t msm_l1_erp_irq(int irq, void *dev_id)
+{
+	struct msm_l1_err_stats *l1_stats = dev_id;
+	unsigned int cesr = read_cesr();
+	unsigned int i_cesynr, d_cesynr;
+	unsigned int cpu = smp_processor_id();
+	int print_regs = cesr & CESR_PRINT_MASK;
+
+	void *const saw_bases[] = {
+		MSM_SAW0_BASE,
+		MSM_SAW1_BASE,
+		MSM_SAW2_BASE,
+		MSM_SAW3_BASE,
+	};
+
+	if (print_regs) {
+		pr_alert("L1 / TLB Error detected on CPU %d!\n", cpu);
+		pr_alert("\tCESR      = 0x%08x\n", cesr);
+		pr_alert("\tCPU speed = %lu\n", acpuclk_get_rate(cpu));
+		pr_alert("\tMIDR      = 0x%08x\n", read_cpuid_id());
+		pr_alert("\tPTE fuses = 0x%08x\n",
+					readl_relaxed(MSM_QFPROM_BASE + 0xC0));
+		pr_alert("\tPMIC_VREG = 0x%08x\n",
+					readl_relaxed(saw_bases[cpu] + 0x14));
+	}
+
+	if (cesr & CESR_DCTPE) {
+		pr_alert("D-cache tag parity error\n");
+		l1_stats->dctpe++;
+	}
+
+	if (cesr & CESR_DCDPE) {
+		pr_alert("D-cache data parity error\n");
+		l1_stats->dcdpe++;
+	}
+
+	if (cesr & CESR_ICTPE) {
+		pr_alert("I-cache tag parity error\n");
+		l1_stats->ictpe++;
+	}
+
+	if (cesr & CESR_ICDPE) {
+		pr_alert("I-cache data parity error\n");
+		l1_stats->icdpe++;
+	}
+
+	if (cesr & CESR_DCTE) {
+		pr_alert("D-cache timing error\n");
+		l1_stats->dcte++;
+	}
+
+	if (cesr & CESR_ICTE) {
+		pr_alert("I-cache timing error\n");
+		l1_stats->icte++;
+	}
+
+	if (cesr & CESR_TLBMH) {
+		asm ("mcr p15, 0, r0, c8, c7, 0");
+		l1_stats->tlbmh++;
+	}
+
+	if (cesr & (CESR_ICTPE | CESR_ICDPE | CESR_ICTE)) {
+		i_cesynr = read_cesynr();
+		pr_alert("I-side CESYNR = 0x%08x\n", i_cesynr);
+		write_cesr(CESR_I_MASK);
+
+		/*
+		 * Clear the I-side bits from the captured CESR value so that we
+		 * don't accidentally clear any new I-side errors when we do
+		 * the CESR write-clear operation.
+		 */
+		cesr &= ~CESR_I_MASK;
+	}
+
+	if (cesr & (CESR_DCTPE | CESR_DCDPE | CESR_DCTE)) {
+		d_cesynr = read_cesynr();
+		pr_alert("D-side CESYNR = 0x%08x\n", d_cesynr);
+	}
+
+	/* Clear the interrupt bits we processed */
+	write_cesr(cesr);
+
+	if (print_regs)
+		ERP_L1_ERR("L1 cache error detected");
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t msm_l2_erp_irq(int irq, void *dev_id)
+{
+	unsigned int l2esr;
+	unsigned int l2esynr0;
+	unsigned int l2esynr1;
+	unsigned int l2ear0;
+	unsigned int l2ear1;
+	int soft_error = 0;
+	int port_error = 0;
+	int unrecoverable = 0;
+	int print_alert;
+
+	l2esr = get_l2_indirect_reg(L2ESR_IND_ADDR);
+	l2esynr0 = get_l2_indirect_reg(L2ESYNR0_IND_ADDR);
+	l2esynr1 = get_l2_indirect_reg(L2ESYNR1_IND_ADDR);
+	l2ear0 = get_l2_indirect_reg(L2EAR0_IND_ADDR);
+	l2ear1 = get_l2_indirect_reg(L2EAR1_IND_ADDR);
+
+	print_alert = print_access_errors() || (l2esr & L2ESR_ACCESS_ERR_MASK);
+
+	if (print_alert) {
+		pr_alert("L2 Error detected!\n");
+		pr_alert("\tL2ESR    = 0x%08x\n", l2esr);
+		pr_alert("\tL2ESYNR0 = 0x%08x\n", l2esynr0);
+		pr_alert("\tL2ESYNR1 = 0x%08x\n", l2esynr1);
+		pr_alert("\tL2EAR0   = 0x%08x\n", l2ear0);
+		pr_alert("\tL2EAR1   = 0x%08x\n", l2ear1);
+		pr_alert("\tCPU bitmap = 0x%x\n", (l2esr >> L2ESR_CPU_SHIFT) &
+							L2ESR_CPU_MASK);
+	}
+
+	if (l2esr & L2ESR_MPDCD) {
+		if (print_alert)
+			pr_alert("L2 master port decode error\n");
+		port_error++;
+		msm_l2_erp_stats.mpdcd++;
+	}
+
+	if (l2esr & L2ESR_MPSLV) {
+		if (print_alert)
+			pr_alert("L2 master port slave error\n");
+		port_error++;
+		msm_l2_erp_stats.mpslv++;
+	}
+
+	if (l2esr & L2ESR_TSESB) {
+		pr_alert("L2 tag soft error, single-bit\n");
+		soft_error++;
+		msm_l2_erp_stats.tsesb++;
+	}
+
+	if (l2esr & L2ESR_TSEDB) {
+		pr_alert("L2 tag soft error, double-bit\n");
+		soft_error++;
+		unrecoverable++;
+		msm_l2_erp_stats.tsedb++;
+	}
+
+	if (l2esr & L2ESR_DSESB) {
+		pr_alert("L2 data soft error, single-bit\n");
+		soft_error++;
+		msm_l2_erp_stats.dsesb++;
+	}
+
+	if (l2esr & L2ESR_DSEDB) {
+		pr_alert("L2 data soft error, double-bit\n");
+		soft_error++;
+		unrecoverable++;
+		msm_l2_erp_stats.dsedb++;
+	}
+
+	if (l2esr & L2ESR_MSE) {
+		pr_alert("L2 modified soft error\n");
+		soft_error++;
+		msm_l2_erp_stats.mse++;
+	}
+
+	if (l2esr & L2ESR_MPLDREXNOK) {
+		pr_alert("L2 master port LDREX received Normal OK response\n");
+		port_error++;
+		msm_l2_erp_stats.mplxrexnok++;
+	}
+
+	if (port_error && print_alert)
+		ERP_PORT_ERR("L2 master port error detected");
+
+	if (soft_error && !unrecoverable)
+		ERP_1BIT_ERR("L2 single-bit error detected");
+
+	if (unrecoverable)
+		ERP_2BIT_ERR("L2 double-bit error detected, trouble ahead");
+
+	set_l2_indirect_reg(L2ESR_IND_ADDR, l2esr);
+	return IRQ_HANDLED;
+}
+
+static void enable_erp_irq_callback(void *info)
+{
+	enable_percpu_irq(l1_erp_irq, IRQ_TYPE_LEVEL_HIGH);
+}
+
+static void disable_erp_irq_callback(void *info)
+{
+	disable_percpu_irq(l1_erp_irq);
+}
+
+static int cache_erp_cpu_callback(struct notifier_block *nfb,
+					    unsigned long action, void *hcpu)
+{
+	switch (action & (~CPU_TASKS_FROZEN)) {
+	case CPU_STARTING:
+		enable_erp_irq_callback(NULL);
+		break;
+
+	case CPU_DYING:
+		disable_erp_irq_callback(NULL);
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block cache_erp_cpu_notifier = {
+	.notifier_call = cache_erp_cpu_callback,
+};
+
+static int msm_cache_erp_probe(struct platform_device *pdev)
+{
+	struct resource *r;
+	int ret, cpu;
+
+	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "l1_irq");
+
+	if (!r) {
+		pr_err("Could not get L1 resource\n");
+		ret = -ENODEV;
+		goto fail;
+	}
+
+	l1_erp_irq = r->start;
+
+	ret = request_percpu_irq(l1_erp_irq, msm_l1_erp_irq, "MSM_L1",
+				 &msm_l1_erp_stats);
+
+	if (ret) {
+		pr_err("Failed to request the L1 cache error interrupt\n");
+		goto fail;
+	}
+
+	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "l2_irq");
+
+	if (!r) {
+		pr_err("Could not get L2 resource\n");
+		ret = -ENODEV;
+		goto fail_l1;
+	}
+
+	l2_erp_irq = r->start;
+	ret = request_irq(l2_erp_irq, msm_l2_erp_irq, 0, "MSM_L2", NULL);
+
+	if (ret) {
+		pr_err("Failed to request the L2 cache error interrupt\n");
+		goto fail_l1;
+	}
+
+	procfs_entry = create_proc_entry("cpu/msm_cache_erp", S_IRUGO, NULL);
+
+	if (!procfs_entry) {
+		pr_err("Failed to create procfs node for cache error reporting\n");
+		ret = -ENODEV;
+		goto fail_l2;
+	}
+
+	get_online_cpus();
+	register_hotcpu_notifier(&cache_erp_cpu_notifier);
+	for_each_cpu(cpu, cpu_online_mask)
+		smp_call_function_single(cpu, enable_erp_irq_callback, NULL, 1);
+	put_online_cpus();
+
+	procfs_entry->read_proc = proc_read_status;
+	return 0;
+
+fail_l2:
+	free_irq(l2_erp_irq, NULL);
+fail_l1:
+	free_percpu_irq(l1_erp_irq, NULL);
+fail:
+	return  ret;
+}
+
+static int msm_cache_erp_remove(struct platform_device *pdev)
+{
+	int cpu;
+	if (procfs_entry)
+		remove_proc_entry("cpu/msm_cache_erp", NULL);
+
+	get_online_cpus();
+	unregister_hotcpu_notifier(&cache_erp_cpu_notifier);
+	for_each_cpu(cpu, cpu_online_mask)
+		smp_call_function_single(cpu, disable_erp_irq_callback, NULL,
+					 1);
+	put_online_cpus();
+
+	free_percpu_irq(l1_erp_irq, NULL);
+
+	disable_irq(l2_erp_irq);
+	free_irq(l2_erp_irq, NULL);
+	return 0;
+}
+
+static struct platform_driver msm_cache_erp_driver = {
+	.probe = msm_cache_erp_probe,
+	.remove = msm_cache_erp_remove,
+	.driver = {
+		.name = MODULE_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_cache_erp_init(void)
+{
+	return platform_driver_register(&msm_cache_erp_driver);
+}
+
+static void __exit msm_cache_erp_exit(void)
+{
+	platform_driver_unregister(&msm_cache_erp_driver);
+}
+
+
+module_init(msm_cache_erp_init);
+module_exit(msm_cache_erp_exit);
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MSM cache error reporting driver");
diff --git a/arch/arm/mach-msm/clock-7x30.c b/arch/arm/mach-msm/clock-7x30.c
new file mode 100644
index 0000000..aa94be6
--- /dev/null
+++ b/arch/arm/mach-msm/clock-7x30.c
@@ -0,0 +1,3024 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/string.h>
+
+#include <mach/msm_iomap.h>
+#include <mach/clk.h>
+#include <mach/proc_comm.h>
+
+#include "clock.h"
+#include "clock-local.h"
+#include "clock-pcom.h"
+#include "clock-voter.h"
+#include "clock-pll.h"
+
+#define REG_BASE(off) (MSM_CLK_CTL_BASE + (off))
+#define REG(off) (MSM_CLK_CTL_SH2_BASE + (off))
+
+/* Shadow-region 2 (SH2) registers. */
+#define	QUP_I2C_NS_REG		REG(0x04F0)
+#define CAM_NS_REG		REG(0x0374)
+#define CAM_VFE_NS_REG		REG(0x0044)
+#define CLK_HALT_STATEA_REG	REG(0x0108)
+#define CLK_HALT_STATEB_REG	REG(0x010C)
+#define CLK_HALT_STATEC_REG	REG(0x02D4)
+#define CSI_NS_REG		REG(0x0174)
+#define EMDH_NS_REG		REG(0x0050)
+#define GLBL_CLK_ENA_2_SC_REG	REG(0x03C0)
+#define GLBL_CLK_ENA_SC_REG	REG(0x03BC)
+#define GLBL_CLK_STATE_2_REG	REG(0x037C)
+#define GLBL_CLK_STATE_REG	REG(0x0004)
+#define GRP_2D_NS_REG		REG(0x0034)
+#define GRP_NS_REG		REG(0x0084)
+#define HDMI_NS_REG		REG(0x0484)
+#define I2C_2_NS_REG		REG(0x02D8)
+#define I2C_NS_REG		REG(0x0068)
+#define JPEG_NS_REG		REG(0x0164)
+#define LPA_CORE_CLK_MA0_REG	REG(0x04F4)
+#define LPA_CORE_CLK_MA2_REG	REG(0x04FC)
+#define LPA_NS_REG		REG(0x02E8)
+#define MDC_NS_REG		REG(0x007C)
+#define MDP_LCDC_NS_REG		REG(0x0390)
+#define MDP_NS_REG		REG(0x014C)
+#define MDP_VSYNC_REG		REG(0x0460)
+#define MFC_NS_REG		REG(0x0154)
+#define MI2S_CODEC_RX_DIV_REG	REG(0x02EC)
+#define MI2S_CODEC_TX_DIV_REG	REG(0x02F0)
+#define MI2S_DIV_REG		REG(0x02E4)
+#define MI2S_NS_REG		REG(0x02E0)
+#define MI2S_RX_NS_REG		REG(0x0070)
+#define MI2S_TX_NS_REG		REG(0x0078)
+#define PLL_ENA_REG		REG(0x0264)
+#define PMDH_NS_REG		REG(0x008C)
+#define SDAC_NS_REG		REG(0x009C)
+#define SDCn_NS_REG(n)		REG(0x00A4+(0x8*((n)-1)))
+#define SPI_NS_REG		REG(0x02C8)
+#define TSIF_NS_REG		REG(0x00C4)
+#define TV_NS_REG		REG(0x00CC)
+#define UART1DM_NS_REG		REG(0x00D4)
+#define UART2DM_NS_REG		REG(0x00DC)
+#define UART2_NS_REG		REG(0x0464)
+#define UART_NS_REG		REG(0x00E0)
+#define USBH2_NS_REG		REG(0x046C)
+#define USBH3_NS_REG		REG(0x0470)
+#define USBH_MD_REG		REG(0x02BC)
+#define USBH_NS_REG		REG(0x02C0)
+#define VPE_NS_REG		REG(0x015C)
+
+/* Registers in the base (non-shadow) region. */
+#define CLK_TEST_BASE_REG	REG_BASE(0x011C)
+#define CLK_TEST_2_BASE_REG	REG_BASE(0x0384)
+#define MISC_CLK_CTL_BASE_REG	REG_BASE(0x0110)
+#define PRPH_WEB_NS_BASE_REG	REG_BASE(0x0080)
+#define PLL0_STATUS_BASE_REG	REG_BASE(0x0318)
+#define PLL1_STATUS_BASE_REG	REG_BASE(0x0334)
+#define PLL2_STATUS_BASE_REG	REG_BASE(0x0350)
+#define PLL3_STATUS_BASE_REG	REG_BASE(0x036C)
+#define PLL4_STATUS_BASE_REG	REG_BASE(0x0254)
+#define PLL5_STATUS_BASE_REG	REG_BASE(0x0258)
+#define PLL6_STATUS_BASE_REG	REG_BASE(0x04EC)
+#define RINGOSC_CNT_BASE_REG	REG_BASE(0x00FC)
+#define SH2_OWN_APPS1_BASE_REG	REG_BASE(0x040C)
+#define SH2_OWN_APPS2_BASE_REG	REG_BASE(0x0414)
+#define SH2_OWN_APPS3_BASE_REG	REG_BASE(0x0444)
+#define SH2_OWN_GLBL_BASE_REG	REG_BASE(0x0404)
+#define SH2_OWN_ROW1_BASE_REG	REG_BASE(0x041C)
+#define SH2_OWN_ROW2_BASE_REG	REG_BASE(0x0424)
+#define TCXO_CNT_BASE_REG	REG_BASE(0x00F8)
+#define TCXO_CNT_DONE_BASE_REG	REG_BASE(0x00F8)
+
+
+/* MUX source input identifiers. */
+#define SRC_SEL_pll0		4 /* Modem PLL */
+#define SRC_SEL_pll1		1 /* Global PLL */
+#define SRC_SEL_pll3		3 /* Multimedia/Peripheral PLL or Backup PLL1 */
+#define SRC_SEL_pll4		2 /* Display PLL */
+#define SRC_SEL_SDAC_lpxo	5 /* Low-power XO for SDAC */
+#define SRC_SEL_lpxo		6 /* Low-power XO */
+#define SRC_SEL_tcxo		0 /* Used for rates from TCXO */
+#define SRC_SEL_axi		0 /* Used for rates that sync to AXI */
+#define SRC_SEL_gnd		7 /* No clock */
+
+/* Clock declaration macros. */
+#define N8(msb, lsb, m, n)	(BVAL(msb, lsb, ~(n-m)) | BVAL(6, 5, \
+					(MN_MODE_DUAL_EDGE * !!(n))))
+#define N16(m, n)		(BVAL(31, 16, ~(n-m)) | BVAL(6, 5, \
+					(MN_MODE_DUAL_EDGE * !!(n))))
+#define SPDIV(s, d)		(BVAL(4, 3, d-1) | BVAL(2, 0, s))
+#define SDIV(s, d)		(BVAL(6, 3, d-1) | BVAL(2, 0, s))
+#define F_MASK_BASIC		(BM(6, 3)|BM(2, 0))
+#define F_MASK_MND16		(BM(31, 16)|BM(6, 5)|BM(4, 3)|BM(2, 0))
+#define F_MASK_MND8(m, l)	(BM(m, l)|BM(6, 5)|BM(4, 3)|BM(2, 0))
+
+/*
+ * Clock frequency definitions and macros
+ */
+#define F_BASIC(f, s, div) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.ns_val = SDIV(SRC_SEL_##s, div), \
+	}
+
+#define F_MND16(f, s, div, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD16(m, n), \
+		.ns_val = N16(m, n) | SPDIV(SRC_SEL_##s, div), \
+	}
+
+#define F_MND8(f, nmsb, nlsb, s, div, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD8(8, m, 0, n), \
+		.ns_val = N8(nmsb, nlsb, m, n) | SPDIV(SRC_SEL_##s, div), \
+	}
+
+enum vdd_dig_levels {
+	VDD_DIG_NONE,
+	VDD_DIG_LOW,
+	VDD_DIG_NOMINAL,
+	VDD_DIG_HIGH
+};
+
+static int set_vdd_dig(struct clk_vdd_class *vdd_class, int level)
+{
+	int rc, target_mv;
+
+	static const int mv[] = {
+		[VDD_DIG_NONE]    = 1000,
+		[VDD_DIG_LOW]     = 1000,
+		[VDD_DIG_NOMINAL] = 1100,
+		[VDD_DIG_HIGH]    = 1200
+	};
+
+	target_mv = mv[level];
+	rc = msm_proc_comm(PCOM_CLKCTL_RPC_MIN_MSMC1, &target_mv, NULL);
+	if (rc)
+		return rc;
+	if (target_mv)
+		rc = -EINVAL;
+
+	return rc;
+}
+
+static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig);
+
+#define VDD_DIG_FMAX_MAP1(l1, f1) \
+	.vdd_class = &vdd_dig, \
+	.fmax[VDD_DIG_##l1] = (f1)
+#define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
+	.vdd_class = &vdd_dig, \
+	.fmax[VDD_DIG_##l1] = (f1), \
+	.fmax[VDD_DIG_##l2] = (f2)
+
+#define PCOM_XO_DISABLE	0
+#define PCOM_XO_ENABLE	1
+#define PCOM_XO_TCXO	0
+#define PCOM_XO_LPXO	1
+
+static bool pcom_is_local(struct clk *clk)
+{
+	return false;
+}
+
+static int pcom_xo_enable(unsigned pcom_id, unsigned enable)
+{
+	/* TODO: Check return code in pcom_id */
+	return msm_proc_comm(PCOM_CLKCTL_RPC_SRC_REQUEST, &pcom_id, &enable);
+}
+
+static int tcxo_clk_enable(struct clk *clk)
+{
+	return pcom_xo_enable(PCOM_XO_TCXO, PCOM_XO_ENABLE);
+}
+
+static void tcxo_clk_disable(struct clk *clk)
+{
+	pcom_xo_enable(PCOM_XO_TCXO, PCOM_XO_DISABLE);
+}
+
+static enum handoff xo_clk_handoff(struct clk *clk)
+{
+	return HANDOFF_ENABLED_CLK;
+}
+
+static struct clk_ops clk_ops_tcxo = {
+	.enable = tcxo_clk_enable,
+	.disable = tcxo_clk_disable,
+	.handoff = xo_clk_handoff,
+	.is_local = pcom_is_local,
+};
+
+static struct fixed_clk tcxo_clk = {
+	.c = {
+		.dbg_name = "tcxo_clk",
+		.rate = 19200000,
+		.ops = &clk_ops_tcxo,
+		CLK_INIT(tcxo_clk.c),
+		.warned = true,
+	},
+};
+
+static int lpxo_clk_enable(struct clk *clk)
+{
+	return pcom_xo_enable(PCOM_XO_LPXO, PCOM_XO_ENABLE);
+}
+
+static void lpxo_clk_disable(struct clk *clk)
+{
+	pcom_xo_enable(PCOM_XO_LPXO, PCOM_XO_DISABLE);
+}
+
+static struct clk_ops clk_ops_lpxo = {
+	.enable = lpxo_clk_enable,
+	.disable = lpxo_clk_disable,
+	.handoff = xo_clk_handoff,
+	.is_local = pcom_is_local,
+};
+
+static struct fixed_clk lpxo_clk = {
+	.c = {
+		.dbg_name = "lpxo_clk",
+		.rate = 24576000,
+		.ops = &clk_ops_lpxo,
+		CLK_INIT(lpxo_clk.c),
+		.warned = true,
+	},
+};
+
+static struct pll_vote_clk pll1_clk = {
+	.en_reg = PLL_ENA_REG,
+	.en_mask = BIT(1),
+	.status_reg = PLL1_STATUS_BASE_REG,
+	.status_mask = BIT(16),
+	.parent = &tcxo_clk.c,
+	.c = {
+		.dbg_name = "pll1_clk",
+		.rate = 768000000,
+		.ops = &clk_ops_pll_vote,
+		CLK_INIT(pll1_clk.c),
+		.warned = true,
+	},
+};
+
+static struct pll_vote_clk pll2_clk = {
+	.en_reg = PLL_ENA_REG,
+	.en_mask = BIT(2),
+	.status_reg = PLL2_STATUS_BASE_REG,
+	.status_mask = BIT(16),
+	.parent = &tcxo_clk.c,
+	.c = {
+		.dbg_name = "pll2_clk",
+		.rate = 806400000, /* TODO: Support scaling */
+		.ops = &clk_ops_pll_vote,
+		CLK_INIT(pll2_clk.c),
+		.warned = true,
+	},
+};
+
+static struct pll_vote_clk pll3_clk = {
+	.en_reg = PLL_ENA_REG,
+	.en_mask = BIT(3),
+	.status_reg = PLL3_STATUS_BASE_REG,
+	.status_mask = BIT(16),
+	.parent = &lpxo_clk.c,
+	.c = {
+		.dbg_name = "pll3_clk",
+		.rate = 737280000,
+		.ops = &clk_ops_pll_vote,
+		CLK_INIT(pll3_clk.c),
+	},
+};
+
+static struct pll_vote_clk pll4_clk = {
+	.en_reg = PLL_ENA_REG,
+	.en_mask = BIT(4),
+	.status_reg = PLL4_STATUS_BASE_REG,
+	.status_mask = BIT(16),
+	.parent = &lpxo_clk.c,
+	.c = {
+		.dbg_name = "pll4_clk",
+		.rate = 891000000,
+		.ops = &clk_ops_pll_vote,
+		CLK_INIT(pll4_clk.c),
+		.warned = true,
+	},
+};
+
+static struct clk_freq_tbl clk_tbl_axi[] = {
+	F_RAW(1, &lpxo_clk.c, 0, 0, 0, NULL),
+	F_END,
+};
+
+/* For global clocks to be on we must have GLBL_ROOT_ENA set */
+static struct rcg_clk glbl_root_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_SC_REG,
+		.en_mask = BIT(29),
+		.halt_check = NOCHECK,
+	},
+	.freq_tbl = clk_tbl_axi,
+	.set_rate = set_rate_nop,
+	.current_freq = &rcg_dummy_freq,
+	.set_rate = set_rate_nop,
+	.c = {
+		.dbg_name = "glbl_root_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 1),
+		CLK_INIT(glbl_root_clk.c),
+	},
+};
+
+/* AXI bridge clocks. */
+static struct branch_clk axi_li_apps_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_SC_REG,
+		.en_mask = BIT(2),
+		.halt_reg = GLBL_CLK_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 2,
+	},
+	.parent = &glbl_root_clk.c,
+	.c = {
+		.dbg_name = "axi_li_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(axi_li_apps_clk.c),
+	},
+};
+
+static struct branch_clk axi_li_adsp_a_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_2_SC_REG,
+		.en_mask = BIT(14),
+		.halt_reg = GLBL_CLK_STATE_2_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 14,
+	},
+	.parent = &axi_li_apps_clk.c,
+	.c = {
+		.dbg_name = "axi_li_adsp_a_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(axi_li_adsp_a_clk.c),
+	},
+};
+
+static struct branch_clk axi_li_jpeg_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_2_SC_REG,
+		.en_mask = BIT(19),
+		.halt_reg = GLBL_CLK_STATE_2_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 19,
+	},
+	.parent = &axi_li_apps_clk.c,
+	.c = {
+		.dbg_name = "axi_li_jpeg_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(axi_li_jpeg_clk.c),
+	},
+};
+
+static struct branch_clk axi_li_vfe_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_SC_REG,
+		.en_mask = BIT(23),
+		.halt_reg = GLBL_CLK_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 23,
+	},
+	.parent = &axi_li_apps_clk.c,
+	.c = {
+		.dbg_name = "axi_li_vfe_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(axi_li_vfe_clk.c),
+	},
+};
+
+static struct branch_clk axi_mdp_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_2_SC_REG,
+		.en_mask = BIT(29),
+		.halt_reg = GLBL_CLK_STATE_2_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 29,
+	},
+	.parent = &axi_li_apps_clk.c,
+	.c = {
+		.dbg_name = "axi_mdp_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(axi_mdp_clk.c),
+	},
+};
+
+static struct branch_clk axi_li_vg_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_SC_REG,
+		.en_mask = BIT(3),
+		.halt_reg = GLBL_CLK_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 3,
+	},
+	.parent = &glbl_root_clk.c,
+	.c = {
+		.dbg_name = "axi_li_vg_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(axi_li_vg_clk.c),
+	},
+};
+
+static struct branch_clk axi_grp_2d_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_SC_REG,
+		.en_mask = BIT(21),
+		.halt_reg = GLBL_CLK_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 21,
+	},
+	.parent = &axi_li_vg_clk.c,
+	.c = {
+		.dbg_name = "axi_grp_2d_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(axi_grp_2d_clk.c),
+	},
+};
+
+static struct branch_clk axi_li_grp_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_SC_REG,
+		.en_mask = BIT(22),
+		.halt_reg = GLBL_CLK_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 22,
+	},
+	.parent = &axi_li_vg_clk.c,
+	.c = {
+		.dbg_name = "axi_li_grp_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(axi_li_grp_clk.c),
+	},
+};
+
+static struct branch_clk axi_mfc_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_2_SC_REG,
+		.en_mask = BIT(20),
+		.halt_reg = GLBL_CLK_STATE_2_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 20,
+	},
+	.parent = &axi_li_vg_clk.c,
+	.c = {
+		.dbg_name = "axi_mfc_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(axi_mfc_clk.c),
+	},
+};
+
+static struct branch_clk axi_rotator_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_2_SC_REG,
+		.en_mask = BIT(22),
+		.halt_reg = GLBL_CLK_STATE_2_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 22,
+		.reset_mask = P_AXI_ROTATOR_CLK,
+	},
+	.parent = &axi_li_vg_clk.c,
+	.c = {
+		.dbg_name = "axi_rotator_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(axi_rotator_clk.c),
+	},
+};
+
+static struct branch_clk axi_vpe_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_2_SC_REG,
+		.en_mask = BIT(21),
+		.halt_reg = GLBL_CLK_STATE_2_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 21,
+	},
+	.parent = &axi_li_vg_clk.c,
+	.c = {
+		.dbg_name = "axi_vpe_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(axi_vpe_clk.c),
+	},
+};
+
+/* Peripheral bus clocks. */
+static struct branch_clk adm_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_SC_REG,
+		.en_mask = BIT(5),
+		.halt_reg = GLBL_CLK_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 5,
+		.reset_mask = P_ADM_CLK,
+	},
+	.parent = &axi_li_apps_clk.c,
+	.c = {
+		.dbg_name = "adm_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(adm_clk.c),
+	},
+};
+
+static struct branch_clk adm_p_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_2_SC_REG,
+		.en_mask = BIT(15),
+		.halt_reg = GLBL_CLK_STATE_2_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 15,
+	},
+	.parent = &glbl_root_clk.c,
+	.c = {
+		.dbg_name = "adm_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(adm_p_clk.c),
+	},
+};
+
+static struct branch_clk ce_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_SC_REG,
+		.en_mask = BIT(6),
+		.halt_reg = GLBL_CLK_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 6,
+		.reset_mask = P_CE_CLK,
+	},
+	.parent = &glbl_root_clk.c,
+	.c = {
+		.dbg_name = "ce_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(ce_clk.c),
+	},
+};
+
+static struct branch_clk camif_pad_p_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_SC_REG,
+		.en_mask = BIT(9),
+		.halt_reg = GLBL_CLK_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 9,
+		.reset_mask = P_CAMIF_PAD_P_CLK,
+	},
+	.parent = &glbl_root_clk.c,
+	.c = {
+		.dbg_name = "camif_pad_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camif_pad_p_clk.c),
+	},
+};
+
+static struct branch_clk csi0_p_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_SC_REG,
+		.en_mask = BIT(30),
+		.halt_reg = GLBL_CLK_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 30,
+		.reset_mask = P_CSI0_P_CLK,
+	},
+	.parent = &glbl_root_clk.c,
+	.c = {
+		.dbg_name = "csi0_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi0_p_clk.c),
+	},
+};
+
+static struct branch_clk emdh_p_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_2_SC_REG,
+		.en_mask = BIT(3),
+		.halt_reg = GLBL_CLK_STATE_2_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 3,
+		.reset_mask = P_EMDH_P_CLK,
+	},
+	.parent = &glbl_root_clk.c,
+	.c = {
+		.dbg_name = "emdh_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(emdh_p_clk.c),
+	},
+};
+
+static struct branch_clk grp_2d_p_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_SC_REG,
+		.en_mask = BIT(24),
+		.halt_reg = GLBL_CLK_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 24,
+		.reset_mask = P_GRP_2D_P_CLK,
+	},
+	.parent = &glbl_root_clk.c,
+	.c = {
+		.dbg_name = "grp_2d_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(grp_2d_p_clk.c),
+	},
+};
+
+static struct branch_clk grp_3d_p_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_2_SC_REG,
+		.en_mask = BIT(17),
+		.halt_reg = GLBL_CLK_STATE_2_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 17,
+		.reset_mask = P_GRP_3D_P_CLK,
+	},
+	.parent = &glbl_root_clk.c,
+	.c = {
+		.dbg_name = "grp_3d_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(grp_3d_p_clk.c),
+	},
+};
+
+static struct branch_clk jpeg_p_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_2_SC_REG,
+		.en_mask = BIT(24),
+		.halt_reg = GLBL_CLK_STATE_2_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 24,
+		.reset_mask = P_JPEG_P_CLK,
+	},
+	.parent = &glbl_root_clk.c,
+	.c = {
+		.dbg_name = "jpeg_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(jpeg_p_clk.c),
+	},
+};
+
+static struct branch_clk lpa_p_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_2_SC_REG,
+		.en_mask = BIT(7),
+		.halt_reg = GLBL_CLK_STATE_2_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 7,
+		.reset_mask = P_LPA_P_CLK,
+	},
+	.parent = &glbl_root_clk.c,
+	.c = {
+		.dbg_name = "lpa_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(lpa_p_clk.c),
+	},
+};
+
+static struct branch_clk mdp_p_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_2_SC_REG,
+		.en_mask = BIT(6),
+		.halt_reg = GLBL_CLK_STATE_2_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 6,
+		.reset_mask = P_MDP_P_CLK,
+	},
+	.parent = &glbl_root_clk.c,
+	.c = {
+		.dbg_name = "mdp_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdp_p_clk.c),
+	},
+};
+
+static struct branch_clk mfc_p_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_2_SC_REG,
+		.en_mask = BIT(26),
+		.halt_reg = GLBL_CLK_STATE_2_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 26,
+		.reset_mask = P_MFC_P_CLK,
+	},
+	.parent = &glbl_root_clk.c,
+	.c = {
+		.dbg_name = "mfc_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mfc_p_clk.c),
+	},
+};
+
+static struct branch_clk pmdh_p_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_2_SC_REG,
+		.en_mask = BIT(4),
+		.halt_reg = GLBL_CLK_STATE_2_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 4,
+		.reset_mask = P_PMDH_P_CLK,
+	},
+	.parent = &glbl_root_clk.c,
+	.c = {
+		.dbg_name = "pmdh_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(pmdh_p_clk.c),
+	},
+};
+
+static struct branch_clk rotator_imem_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_2_SC_REG,
+		.en_mask = BIT(23),
+		.halt_reg = GLBL_CLK_STATE_2_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 23,
+		.reset_mask = P_ROTATOR_IMEM_CLK,
+	},
+	.parent = &glbl_root_clk.c,
+	.c = {
+		.dbg_name = "rotator_imem_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(rotator_imem_clk.c),
+	},
+};
+
+static struct branch_clk rotator_p_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_2_SC_REG,
+		.en_mask = BIT(25),
+		.halt_reg = GLBL_CLK_STATE_2_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 25,
+		.reset_mask = P_ROTATOR_P_CLK,
+	},
+	.parent = &glbl_root_clk.c,
+	.c = {
+		.dbg_name = "rotator_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(rotator_p_clk.c),
+	},
+};
+
+static struct branch_clk sdc1_p_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_SC_REG,
+		.en_mask = BIT(7),
+		.halt_reg = GLBL_CLK_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 7,
+		.reset_mask = P_SDC1_P_CLK,
+	},
+	.parent = &glbl_root_clk.c,
+	.c = {
+		.dbg_name = "sdc1_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sdc1_p_clk.c),
+	},
+};
+
+static struct branch_clk sdc2_p_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_SC_REG,
+		.en_mask = BIT(8),
+		.halt_reg = GLBL_CLK_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 8,
+		.reset_mask = P_SDC2_P_CLK,
+	},
+	.parent = &glbl_root_clk.c,
+	.c = {
+		.dbg_name = "sdc2_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sdc2_p_clk.c),
+	},
+};
+
+static struct branch_clk sdc3_p_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_SC_REG,
+		.en_mask = BIT(27),
+		.halt_reg = GLBL_CLK_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 27,
+		.reset_mask = P_SDC3_P_CLK,
+	},
+	.parent = &glbl_root_clk.c,
+	.c = {
+		.dbg_name = "sdc3_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sdc3_p_clk.c),
+	},
+};
+
+static struct branch_clk sdc4_p_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_SC_REG,
+		.en_mask = BIT(28),
+		.halt_reg = GLBL_CLK_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 28,
+		.reset_mask = P_SDC4_P_CLK,
+	},
+	.parent = &glbl_root_clk.c,
+	.c = {
+		.dbg_name = "sdc4_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sdc4_p_clk.c),
+	},
+};
+
+static struct branch_clk spi_p_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_2_SC_REG,
+		.en_mask = BIT(10),
+		.halt_reg = GLBL_CLK_STATE_2_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 10,
+		.reset_mask = P_SPI_P_CLK,
+	},
+	.parent = &glbl_root_clk.c,
+	.c = {
+		.dbg_name = "spi_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(spi_p_clk.c),
+	},
+};
+
+static struct branch_clk tsif_p_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_SC_REG,
+		.en_mask = BIT(18),
+		.halt_reg = GLBL_CLK_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 18,
+		.reset_mask = P_TSIF_P_CLK,
+	},
+	.parent = &glbl_root_clk.c,
+	.c = {
+		.dbg_name = "tsif_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(tsif_p_clk.c),
+	},
+};
+
+static struct branch_clk uart1dm_p_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_SC_REG,
+		.en_mask = BIT(17),
+		.halt_reg = GLBL_CLK_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 17,
+	},
+	.parent = &glbl_root_clk.c,
+	.c = {
+		.dbg_name = "uart1dm_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(uart1dm_p_clk.c),
+	},
+};
+
+static struct branch_clk uart2dm_p_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_SC_REG,
+		.en_mask = BIT(26),
+		.halt_reg = GLBL_CLK_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 26,
+	},
+	.parent = &glbl_root_clk.c,
+	.c = {
+		.dbg_name = "uart2dm_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(uart2dm_p_clk.c),
+	},
+};
+
+static struct branch_clk usb_hs2_p_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_2_SC_REG,
+		.en_mask = BIT(8),
+		.halt_reg = GLBL_CLK_STATE_2_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 8,
+		.reset_mask = P_USB_HS2_P_CLK,
+	},
+	.parent = &glbl_root_clk.c,
+	.c = {
+		.dbg_name = "usb_hs2_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_hs2_p_clk.c),
+	},
+};
+
+static struct branch_clk usb_hs3_p_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_2_SC_REG,
+		.en_mask = BIT(9),
+		.halt_reg = GLBL_CLK_STATE_2_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 9,
+		.reset_mask = P_USB_HS3_P_CLK,
+	},
+	.parent = &glbl_root_clk.c,
+	.c = {
+		.dbg_name = "usb_hs3_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_hs3_p_clk.c),
+	},
+};
+
+static struct branch_clk usb_hs_p_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_SC_REG,
+		.en_mask = BIT(25),
+		.halt_reg = GLBL_CLK_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 25,
+		.reset_mask = P_USB_HS_P_CLK,
+	},
+	.parent = &glbl_root_clk.c,
+	.c = {
+		.dbg_name = "usb_hs_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_hs_p_clk.c),
+	},
+};
+
+static struct branch_clk vfe_p_clk = {
+	.b = {
+		.ctl_reg = GLBL_CLK_ENA_2_SC_REG,
+		.en_mask = BIT(27),
+		.halt_reg = GLBL_CLK_STATE_2_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 27,
+		.reset_mask = P_VFE_P_CLK,
+	},
+	.parent = &glbl_root_clk.c,
+	.c = {
+		.dbg_name = "vfe_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(vfe_p_clk.c),
+	},
+};
+
+static struct clk_freq_tbl clk_tbl_csi[] = {
+	F_MND8(        0,  0,  0, gnd,  1, 0, 0),
+	F_MND8(153600000, 24, 17, pll1, 2, 2, 5),
+	F_MND8(192000000, 24, 17, pll1, 4, 0, 0),
+	F_MND8(384000000, 24, 17, pll1, 2, 0, 0),
+	F_END,
+};
+
+static struct rcg_clk csi0_clk = {
+	.b = {
+		.ctl_reg = CSI_NS_REG,
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_STATEC_REG,
+		.halt_bit = 17,
+		.reset_mask = P_CSI0_CLK,
+	},
+	.ns_reg = CSI_NS_REG,
+	.md_reg = CSI_NS_REG - 4,
+	.ns_mask = F_MASK_MND8(24, 17),
+	.mnd_en_mask = BIT(8),
+	.root_en_mask = BIT(11),
+	.freq_tbl = clk_tbl_csi,
+	.current_freq = &rcg_dummy_freq,
+	.set_rate = set_rate_mnd,
+	.c = {
+		.dbg_name = "csi0_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 384000000),
+		CLK_INIT(csi0_clk.c),
+	},
+};
+
+static struct clk_freq_tbl clk_tbl_tcxo[] = {
+	F_RAW(19200000, &tcxo_clk.c, 0, 0, 0, NULL),
+	F_END,
+};
+
+static struct rcg_clk i2c_clk = {
+	.b = {
+		.ctl_reg = I2C_NS_REG,
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_STATEA_REG,
+		.halt_bit = 15,
+		.reset_mask = P_I2C_CLK,
+	},
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_tcxo,
+	.root_en_mask = BIT(11),
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "i2c_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 19200000),
+		CLK_INIT(i2c_clk.c),
+	},
+};
+
+static struct rcg_clk i2c_2_clk = {
+	.b = {
+		.ctl_reg = I2C_2_NS_REG,
+		.en_mask = BIT(0),
+		.halt_reg = CLK_HALT_STATEC_REG,
+		.halt_bit = 2,
+		.reset_mask = P_I2C_2_CLK,
+	},
+	.root_en_mask = BIT(2),
+	.freq_tbl = clk_tbl_tcxo,
+	.set_rate = set_rate_nop,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "i2c_2_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 19200000),
+		CLK_INIT(i2c_2_clk.c),
+	},
+};
+
+static struct rcg_clk qup_i2c_clk = {
+	.b = {
+		.ctl_reg = QUP_I2C_NS_REG,
+		.en_mask = BIT(0),
+		.halt_reg = CLK_HALT_STATEB_REG,
+		.halt_bit = 31,
+		.reset_mask = P_QUP_I2C_CLK,
+	},
+	.root_en_mask = BIT(2),
+	.freq_tbl = clk_tbl_tcxo,
+	.set_rate = set_rate_nop,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "qup_i2c_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 19200000),
+		CLK_INIT(qup_i2c_clk.c),
+	},
+};
+
+static struct rcg_clk uart1_clk = {
+	.b = {
+		.ctl_reg = UART_NS_REG,
+		.en_mask = BIT(5),
+		.halt_reg = CLK_HALT_STATEB_REG,
+		.halt_bit = 7,
+		.reset_mask = P_UART1_CLK,
+	},
+	.root_en_mask = BIT(4),
+	.freq_tbl = clk_tbl_tcxo,
+	.set_rate = set_rate_nop,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "uart1_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 19200000),
+		CLK_INIT(uart1_clk.c),
+	},
+};
+
+static struct rcg_clk uart2_clk = {
+	.b = {
+		.ctl_reg = UART2_NS_REG,
+		.en_mask = BIT(5),
+		.halt_reg = CLK_HALT_STATEB_REG,
+		.halt_bit = 5,
+		.reset_mask = P_UART2_CLK,
+	},
+	.root_en_mask = BIT(4),
+	.freq_tbl = clk_tbl_tcxo,
+	.set_rate = set_rate_nop,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "uart2_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 19200000),
+		CLK_INIT(uart2_clk.c),
+	},
+};
+
+static struct clk_freq_tbl clk_tbl_uartdm[] = {
+	F_MND16(       0, gnd,  1,   0,   0),
+	F_MND16( 3686400, pll3, 3,   3, 200),
+	F_MND16( 7372800, pll3, 3,   3, 100),
+	F_MND16(14745600, pll3, 3,   3,  50),
+	F_MND16(32000000, pll3, 3,  25, 192),
+	F_MND16(40000000, pll3, 3, 125, 768),
+	F_MND16(46400000, pll3, 3, 145, 768),
+	F_MND16(48000000, pll3, 3,  25, 128),
+	F_MND16(51200000, pll3, 3,   5,  24),
+	F_MND16(56000000, pll3, 3, 175, 768),
+	F_MND16(58982400, pll3, 3,   6,  25),
+	F_MND16(64000000, pll1, 4,   1,   3),
+	F_END,
+};
+
+static struct rcg_clk uart1dm_clk = {
+	.b = {
+		.ctl_reg = UART1DM_NS_REG,
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_STATEB_REG,
+		.halt_bit = 6,
+		.reset_mask = P_UART1DM_CLK,
+	},
+	.ns_reg = UART1DM_NS_REG,
+	.md_reg = UART1DM_NS_REG - 4,
+	.root_en_mask = BIT(11),
+	.mnd_en_mask = BIT(8),
+	.freq_tbl = clk_tbl_uartdm,
+	.ns_mask = F_MASK_MND16,
+	.current_freq = &rcg_dummy_freq,
+	.set_rate = set_rate_mnd,
+	.c = {
+		.dbg_name = "uart1dm_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 64000000),
+		CLK_INIT(uart1dm_clk.c),
+	},
+};
+
+static struct rcg_clk uart2dm_clk = {
+	.b = {
+		.ctl_reg = UART2DM_NS_REG,
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_STATEB_REG,
+		.halt_bit = 23,
+		.reset_mask = P_UART2DM_CLK,
+	},
+	.ns_reg = UART2DM_NS_REG,
+	.md_reg = UART2DM_NS_REG - 4,
+	.root_en_mask = BIT(11),
+	.freq_tbl = clk_tbl_uartdm,
+	.ns_mask = F_MASK_MND16,
+	.mnd_en_mask = BIT(8),
+	.set_rate = set_rate_mnd,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "uart2dm_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 64000000),
+		CLK_INIT(uart2dm_clk.c),
+	},
+};
+
+static struct clk_freq_tbl clk_tbl_mdh[] = {
+	F_BASIC(        0, gnd,   1),
+	F_BASIC( 49150000, pll3, 15),
+	F_BASIC( 92160000, pll3,  8),
+	F_BASIC(122880000, pll3,  6),
+	F_BASIC(184320000, pll3,  4),
+	F_BASIC(245760000, pll3,  3),
+	F_BASIC(368640000, pll3,  2),
+	F_BASIC(384000000, pll1,  2),
+	F_BASIC(445500000, pll4,  2),
+	F_END,
+};
+
+static struct rcg_clk emdh_clk = {
+	.b = {
+		.ctl_reg = EMDH_NS_REG,
+		.halt_check = DELAY,
+		.reset_mask = P_EMDH_CLK,
+	},
+	.root_en_mask = BIT(11),
+	.ns_reg = EMDH_NS_REG,
+	.ns_mask = F_MASK_BASIC,
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_mdh,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "emdh_clk",
+		.flags = CLKFLAG_MIN | CLKFLAG_MAX,
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 445500000),
+		CLK_INIT(emdh_clk.c),
+		.depends = &axi_li_adsp_a_clk.c,
+	},
+};
+
+static struct rcg_clk pmdh_clk = {
+	.b = {
+		.ctl_reg = PMDH_NS_REG,
+		.halt_check = DELAY,
+		.reset_mask = P_PMDH_CLK,
+	},
+	.root_en_mask = BIT(11),
+	.ns_reg = PMDH_NS_REG,
+	.ns_mask = F_MASK_BASIC,
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_mdh,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "pmdh_clk",
+		.flags = CLKFLAG_MIN | CLKFLAG_MAX,
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 445500000),
+		CLK_INIT(pmdh_clk.c),
+		.depends = &axi_li_adsp_a_clk.c,
+	},
+};
+
+static struct clk_freq_tbl clk_tbl_grp[] = {
+	F_BASIC( 24576000, lpxo,  1),
+	F_BASIC( 46080000, pll3, 16),
+	F_BASIC( 49152000, pll3, 15),
+	F_BASIC( 52662875, pll3, 14),
+	F_BASIC( 56713846, pll3, 13),
+	F_BASIC( 61440000, pll3, 12),
+	F_BASIC( 67025454, pll3, 11),
+	F_BASIC( 73728000, pll3, 10),
+	F_BASIC( 81920000, pll3,  9),
+	F_BASIC( 92160000, pll3,  8),
+	F_BASIC(105325714, pll3,  7),
+	F_BASIC(122880000, pll3,  6),
+	F_BASIC(147456000, pll3,  5),
+	F_BASIC(184320000, pll3,  4),
+	F_BASIC(192000000, pll1,  4),
+	F_BASIC(245760000, pll3,  3),
+	/* Sync to AXI. Hence this "rate" is not fixed. */
+	F_RAW(1, &lpxo_clk.c, 0, BIT(14), 0, NULL),
+	F_END,
+};
+
+static struct rcg_clk grp_2d_clk = {
+	.b = {
+		.ctl_reg = GRP_2D_NS_REG,
+		.en_mask = BIT(7),
+		.halt_reg = CLK_HALT_STATEA_REG,
+		.halt_bit = 31,
+		.reset_mask = P_GRP_2D_CLK,
+	},
+	.ns_reg = GRP_2D_NS_REG,
+	.root_en_mask = BIT(11),
+	.ns_mask = F_MASK_BASIC | (7 << 12),
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_grp,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "grp_2d_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(NOMINAL, 192000000, HIGH, 245760000),
+		CLK_INIT(grp_2d_clk.c),
+		.depends = &axi_grp_2d_clk.c,
+	},
+};
+
+static struct rcg_clk grp_3d_src_clk = {
+	.ns_reg = GRP_NS_REG,
+	.b = {
+		.ctl_reg = GRP_NS_REG,
+		.halt_check = NOCHECK,
+	},
+	.root_en_mask = BIT(11),
+	.ns_mask = F_MASK_BASIC | (7 << 12),
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_grp,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "grp_3d_src_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(NOMINAL, 192000000, HIGH, 245760000),
+		CLK_INIT(grp_3d_src_clk.c),
+		.depends = &axi_li_grp_clk.c,
+	},
+};
+
+static struct branch_clk grp_3d_clk = {
+	.b = {
+		.ctl_reg = GRP_NS_REG,
+		.en_mask = BIT(7),
+		.halt_reg = CLK_HALT_STATEB_REG,
+		.halt_bit = 18,
+		.reset_mask = P_GRP_3D_CLK,
+	},
+	.parent = &grp_3d_src_clk.c,
+	.c = {
+		.dbg_name = "grp_3d_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(grp_3d_clk.c),
+	},
+};
+
+static struct branch_clk imem_clk = {
+	.b = {
+		.ctl_reg = GRP_NS_REG,
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_STATEB_REG,
+		.halt_bit = 19,
+		.reset_mask = P_IMEM_CLK,
+	},
+	.parent = &grp_3d_src_clk.c,
+	.c = {
+		.dbg_name = "imem_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(imem_clk.c),
+	},
+};
+
+static struct clk_freq_tbl clk_tbl_sdc1_3[] = {
+	F_MND8(       0,  0,  0, gnd,  1,   0,    0),
+	F_MND8(  144000, 19, 12, lpxo, 1,   1,  171),
+	F_MND8(  400000, 19, 12, lpxo, 1,   2,  123),
+	F_MND8(16027000, 19, 12, pll3, 3,  14,  215),
+	F_MND8(17000000, 19, 12, pll3, 4,  19,  206),
+	F_MND8(20480000, 19, 12, pll3, 4,  23,  212),
+	F_MND8(24576000, 19, 12, lpxo, 1,   0,    0),
+	F_MND8(49152000, 19, 12, pll3, 3,   1,    5),
+	F_END,
+};
+
+static struct rcg_clk sdc1_clk = {
+	.b = {
+		.ctl_reg = SDCn_NS_REG(1),
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_STATEA_REG,
+		.halt_bit = 1,
+		.reset_mask = P_SDC1_CLK,
+	},
+	.ns_reg = SDCn_NS_REG(1),
+	.md_reg = SDCn_NS_REG(1) - 4,
+	.ns_mask = F_MASK_MND8(19, 12),
+	.mnd_en_mask = BIT(8),
+	.root_en_mask = BIT(11),
+	.freq_tbl = clk_tbl_sdc1_3,
+	.current_freq = &rcg_dummy_freq,
+	.set_rate = set_rate_mnd,
+	.c = {
+		.dbg_name = "sdc1_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 49152000),
+		CLK_INIT(sdc1_clk.c),
+	},
+};
+
+static struct rcg_clk sdc3_clk = {
+	.b = {
+		.ctl_reg = SDCn_NS_REG(3),
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_STATEB_REG,
+		.halt_bit = 24,
+		.reset_mask = P_SDC3_CLK,
+	},
+	.ns_reg = SDCn_NS_REG(3),
+	.md_reg = SDCn_NS_REG(3) - 4,
+	.ns_mask = F_MASK_MND8(19, 12),
+	.mnd_en_mask = BIT(8),
+	.root_en_mask = BIT(11),
+	.freq_tbl = clk_tbl_sdc1_3,
+	.current_freq = &rcg_dummy_freq,
+	.set_rate = set_rate_mnd,
+	.c = {
+		.dbg_name = "sdc3_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 49152000),
+		CLK_INIT(sdc3_clk.c),
+	},
+};
+
+static struct clk_freq_tbl clk_tbl_sdc2_4[] = {
+	F_MND8(       0,  0,  0, gnd,  1,   0,    0),
+	F_MND8(  144000, 20, 13, lpxo, 1,   1,  171),
+	F_MND8(  400000, 20, 13, lpxo, 1,   2,  123),
+	F_MND8(16027000, 20, 13, pll3, 3,  14,  215),
+	F_MND8(17000000, 20, 13, pll3, 4,  19,  206),
+	F_MND8(20480000, 20, 13, pll3, 4,  23,  212),
+	F_MND8(24576000, 20, 13, lpxo, 1,   0,    0),
+	F_MND8(49152000, 20, 13, pll3, 3,   1,    5),
+	F_END,
+};
+
+static struct rcg_clk sdc2_clk = {
+	.b = {
+		.ctl_reg = SDCn_NS_REG(2),
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_STATEA_REG,
+		.halt_bit = 0,
+		.reset_mask = P_SDC2_CLK,
+	},
+	.ns_reg = SDCn_NS_REG(2),
+	.md_reg = SDCn_NS_REG(2) - 4,
+	.ns_mask = F_MASK_MND8(20, 13),
+	.mnd_en_mask = BIT(8),
+	.root_en_mask = BIT(11),
+	.freq_tbl = clk_tbl_sdc2_4,
+	.current_freq = &rcg_dummy_freq,
+	.set_rate = set_rate_mnd,
+	.c = {
+		.dbg_name = "sdc2_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 49152000),
+		CLK_INIT(sdc2_clk.c),
+	},
+};
+
+static struct rcg_clk sdc4_clk = {
+	.b = {
+		.ctl_reg = SDCn_NS_REG(4),
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_STATEB_REG,
+		.halt_bit = 25,
+		.reset_mask = P_SDC4_CLK,
+	},
+	.ns_reg = SDCn_NS_REG(4),
+	.md_reg = SDCn_NS_REG(4) - 4,
+	.ns_mask = F_MASK_MND8(20, 13),
+	.mnd_en_mask = BIT(8),
+	.root_en_mask = BIT(11),
+	.freq_tbl = clk_tbl_sdc2_4,
+	.current_freq = &rcg_dummy_freq,
+	.set_rate = set_rate_mnd,
+	.c = {
+		.dbg_name = "sdc4_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 49152000),
+		CLK_INIT(sdc4_clk.c),
+	},
+};
+
+static struct clk_freq_tbl clk_tbl_mdp_core[] = {
+	F_BASIC( 24576000, lpxo,  1),
+	F_BASIC( 46080000, pll3, 16),
+	F_BASIC( 49152000, pll3, 15),
+	F_BASIC( 52663000, pll3, 14),
+	F_BASIC( 92160000, pll3,  8),
+	F_BASIC(122880000, pll3,  6),
+	F_BASIC(147456000, pll3,  5),
+	F_BASIC(153600000, pll1,  5),
+	F_BASIC(192000000, pll1,  4),
+	F_END,
+};
+
+static struct rcg_clk mdp_clk = {
+	.b = {
+		.ctl_reg = MDP_NS_REG,
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_STATEB_REG,
+		.halt_bit = 16,
+		.reset_mask = P_MDP_CLK,
+	},
+	.ns_reg = MDP_NS_REG,
+	.root_en_mask = BIT(11),
+	.ns_mask = F_MASK_BASIC,
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_mdp_core,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "mdp_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(NOMINAL, 153600000, HIGH, 192000000),
+		CLK_INIT(mdp_clk.c),
+		.depends = &axi_mdp_clk.c,
+	},
+};
+
+static struct clk_freq_tbl clk_tbl_mdp_lcdc[] = {
+	F_MND16(       0, gnd,  1,   0,   0),
+	F_MND16(24576000, lpxo, 1,   0,   0),
+	F_MND16(30720000, pll3, 4,   1,   6),
+	F_MND16(32768000, pll3, 3,   2,  15),
+	F_MND16(40960000, pll3, 2,   1,   9),
+	F_MND16(73728000, pll3, 2,   1,   5),
+	F_END,
+};
+
+static struct rcg_clk mdp_lcdc_pclk_clk = {
+	.b = {
+		.ctl_reg = MDP_LCDC_NS_REG,
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_STATEB_REG,
+		.halt_bit = 28,
+		.reset_mask = P_MDP_LCDC_PCLK_CLK,
+	},
+	.ns_reg = MDP_LCDC_NS_REG,
+	.md_reg = MDP_LCDC_NS_REG - 4,
+	.root_en_mask = BIT(11),
+	.ns_mask = F_MASK_MND16,
+	.mnd_en_mask = BIT(8),
+	.set_rate = set_rate_mnd,
+	.freq_tbl = clk_tbl_mdp_lcdc,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "mdp_lcdc_pclk_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 73728000),
+		CLK_INIT(mdp_lcdc_pclk_clk.c),
+	},
+};
+
+static struct branch_clk mdp_lcdc_pad_pclk_clk = {
+	.b = {
+		.ctl_reg = MDP_LCDC_NS_REG,
+		.en_mask = BIT(12),
+		.halt_reg = CLK_HALT_STATEB_REG,
+		.halt_bit = 29,
+		.reset_mask = P_MDP_LCDC_PAD_PCLK_CLK,
+	},
+	.parent = &mdp_lcdc_pclk_clk.c,
+	.c = {
+		.dbg_name = "mdp_lcdc_pad_pclk_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdp_lcdc_pad_pclk_clk.c),
+	},
+};
+
+static struct clk_freq_tbl clk_tbl_mdp_vsync[] = {
+	F_RAW(       0, &gnd_clk.c,  0, (0x3<<2), 0, NULL),
+	F_RAW(24576000, &lpxo_clk.c, 0, (0x1<<2), 0, NULL),
+	F_END,
+};
+
+static struct rcg_clk mdp_vsync_clk = {
+	.b = {
+		.ctl_reg = MDP_VSYNC_REG,
+		.en_mask = BIT(0),
+		.halt_reg = CLK_HALT_STATEB_REG,
+		.halt_bit = 30,
+		.reset_mask = P_MDP_VSYNC_CLK,
+	},
+	.ns_reg = MDP_VSYNC_REG,
+	.ns_mask = BM(3, 2),
+	.freq_tbl = clk_tbl_mdp_vsync,
+	.set_rate = set_rate_nop,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "mdp_vsync_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 24576000),
+		CLK_INIT(mdp_vsync_clk.c),
+	},
+};
+
+static struct clk_freq_tbl clk_tbl_mi2s_codec[] = {
+	F_MND16(       0, gnd,  1,   0,   0),
+	F_MND16( 2048000, lpxo, 4,   1,   3),
+	F_MND16(12288000, lpxo, 2,   0,   0),
+	F_END,
+};
+
+static struct rcg_clk mi2s_codec_rx_m_clk = {
+	.b = {
+		.ctl_reg = MI2S_RX_NS_REG,
+		.en_mask = BIT(12),
+		.halt_reg = CLK_HALT_STATEA_REG,
+		.halt_bit = 12,
+		.reset_mask = P_MI2S_CODEC_RX_M_CLK,
+	},
+	.ns_reg = MI2S_RX_NS_REG,
+	.md_reg = MI2S_RX_NS_REG - 4,
+	.root_en_mask = BIT(11),
+	.ns_mask = F_MASK_MND16,
+	.mnd_en_mask = BIT(8),
+	.set_rate = set_rate_mnd,
+	.freq_tbl = clk_tbl_mi2s_codec,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "mi2s_codec_rx_m_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 12288000),
+		CLK_INIT(mi2s_codec_rx_m_clk.c),
+	},
+};
+
+static struct branch_clk mi2s_codec_rx_s_clk = {
+	.b = {
+		.ctl_reg = MI2S_RX_NS_REG,
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_STATEA_REG,
+		.halt_bit = 13,
+		.reset_mask = P_MI2S_CODEC_RX_S_CLK,
+	},
+	.parent = &mi2s_codec_rx_m_clk.c,
+	.c = {
+		.dbg_name = "mi2s_codec_rx_s_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mi2s_codec_rx_s_clk.c),
+	},
+};
+
+static struct rcg_clk mi2s_codec_tx_m_clk = {
+	.b = {
+		.ctl_reg = MI2S_TX_NS_REG,
+		.en_mask = BIT(12),
+		.halt_reg = CLK_HALT_STATEC_REG,
+		.halt_bit = 8,
+		.reset_mask = P_MI2S_CODEC_TX_M_CLK,
+	},
+	.ns_reg = MI2S_TX_NS_REG,
+	.md_reg = MI2S_TX_NS_REG - 4,
+	.root_en_mask = BIT(11),
+	.ns_mask = F_MASK_MND16,
+	.mnd_en_mask = BIT(8),
+	.set_rate = set_rate_mnd,
+	.freq_tbl = clk_tbl_mi2s_codec,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "mi2s_codec_tx_m_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 12288000),
+		CLK_INIT(mi2s_codec_tx_m_clk.c),
+	},
+};
+
+static struct branch_clk mi2s_codec_tx_s_clk = {
+	.b = {
+		.ctl_reg = MI2S_TX_NS_REG,
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_STATEA_REG,
+		.halt_bit = 11,
+		.reset_mask = P_MI2S_CODEC_TX_S_CLK,
+	},
+	.parent = &mi2s_codec_tx_m_clk.c,
+	.c = {
+		.dbg_name = "mi2s_codec_tx_s_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mi2s_codec_tx_s_clk.c),
+	},
+};
+
+static struct clk_freq_tbl clk_tbl_mi2s[] = {
+	F_MND16(       0, gnd,  1,   0,   0),
+	F_MND16(12288000, lpxo, 2,   0,   0),
+	F_END,
+};
+
+static struct rcg_clk mi2s_m_clk = {
+	.b = {
+		.ctl_reg = MI2S_NS_REG,
+		.en_mask = BIT(12),
+		.halt_reg = CLK_HALT_STATEC_REG,
+		.halt_bit = 4,
+		.reset_mask = P_MI2S_M_CLK,
+	},
+	.ns_reg = MI2S_NS_REG,
+	.md_reg = MI2S_NS_REG - 4,
+	.root_en_mask = BIT(11),
+	.ns_mask = F_MASK_MND16,
+	.mnd_en_mask = BIT(8),
+	.set_rate = set_rate_mnd,
+	.freq_tbl = clk_tbl_mi2s,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "mi2s_m_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 12288000),
+		CLK_INIT(mi2s_m_clk.c),
+	},
+};
+
+static struct branch_clk mi2s_s_clk = {
+	.b = {
+		.ctl_reg = MI2S_NS_REG,
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_STATEC_REG,
+		.halt_bit = 3,
+		.reset_mask = P_MI2S_S_CLK,
+	},
+	.parent = &mi2s_m_clk.c,
+	.c = {
+		.dbg_name = "mi2s_s_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mi2s_s_clk.c),
+	},
+};
+
+#define F_SDAC(f, s, div, m, n) \
+	{ \
+		.freq_hz = f, \
+		.md_val = MD16(m, n), \
+		.ns_val = N16(m, n) | SPDIV(SRC_SEL_SDAC_##s, div), \
+		.src_clk = &s##_clk.c, \
+	}
+
+static struct clk_freq_tbl clk_tbl_sdac[] = {
+	F_SDAC( 256000, lpxo, 4,   1,    24),
+	F_SDAC( 352800, lpxo, 1, 147, 10240),
+	F_SDAC( 384000, lpxo, 4,   1,    16),
+	F_SDAC( 512000, lpxo, 4,   1,    12),
+	F_SDAC( 705600, lpxo, 1, 147,  5120),
+	F_SDAC( 768000, lpxo, 4,   1,     8),
+	F_SDAC(1024000, lpxo, 4,   1,     6),
+	F_SDAC(1411200, lpxo, 1, 147,  2560),
+	F_SDAC(1536000, lpxo, 4,   1,     4),
+	F_END,
+};
+
+static struct rcg_clk sdac_clk = {
+	.b = {
+		.ctl_reg = SDAC_NS_REG,
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_STATEA_REG,
+		.halt_bit = 2,
+		.reset_mask = P_SDAC_CLK,
+	},
+	.ns_reg = SDAC_NS_REG,
+	.md_reg = SDAC_NS_REG - 4,
+	.root_en_mask = BIT(11),
+	.mnd_en_mask = BIT(8),
+	.freq_tbl = clk_tbl_sdac,
+	.ns_mask = F_MASK_MND16,
+	.set_rate = set_rate_mnd,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "sdac_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 1536000),
+		CLK_INIT(sdac_clk.c),
+	},
+};
+
+static struct branch_clk sdac_m_clk = {
+	.b = {
+		.ctl_reg = SDAC_NS_REG,
+		.en_mask = BIT(12),
+		.halt_reg = CLK_HALT_STATEB_REG,
+		.halt_bit = 17,
+		.reset_mask = P_SDAC_M_CLK,
+	},
+	.parent = &sdac_clk.c,
+	.c = {
+		.dbg_name = "sdac_m_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sdac_m_clk.c),
+	},
+};
+
+static struct clk_freq_tbl clk_tbl_tv[] = {
+	F_MND8(       0,  0,  0, gnd,  1,  0,   0),
+	F_MND8(27000000, 23, 16, pll4, 2,  2,  33),
+	F_MND8(74250000, 23, 16, pll4, 2,  1,   6),
+	F_END,
+};
+
+static struct rcg_clk tv_clk = {
+	.ns_reg = TV_NS_REG,
+	.b = {
+		.ctl_reg = TV_NS_REG,
+		.halt_check = NOCHECK,
+	},
+	.md_reg = TV_NS_REG - 4,
+	.ns_mask = F_MASK_MND8(23, 16),
+	.mnd_en_mask = BIT(8),
+	.root_en_mask = BIT(11),
+	.freq_tbl = clk_tbl_tv,
+	.current_freq = &rcg_dummy_freq,
+	.set_rate = set_rate_mnd,
+	.c = {
+		.dbg_name = "tv_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 74250000),
+		CLK_INIT(tv_clk.c),
+	},
+};
+
+static struct branch_clk hdmi_clk = {
+	.b = {
+		.ctl_reg = HDMI_NS_REG,
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_STATEC_REG,
+		.halt_bit = 7,
+		.reset_mask = P_HDMI_CLK,
+	},
+	.parent = &tv_clk.c,
+	.c = {
+		.dbg_name = "hdmi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(hdmi_clk.c),
+	},
+};
+
+static struct branch_clk tv_dac_clk = {
+	.b = {
+		.ctl_reg = TV_NS_REG,
+		.en_mask = BIT(12),
+		.halt_reg = CLK_HALT_STATEB_REG,
+		.halt_bit = 27,
+		.reset_mask = P_TV_DAC_CLK,
+	},
+	.parent = &tv_clk.c,
+	.c = {
+		.dbg_name = "tv_dac_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(tv_dac_clk.c),
+	},
+};
+
+static struct branch_clk tv_enc_clk = {
+	.b = {
+		.ctl_reg = TV_NS_REG,
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_STATEB_REG,
+		.halt_bit = 10,
+		.reset_mask = P_TV_ENC_CLK,
+	},
+	.parent = &tv_clk.c,
+	.c = {
+		.dbg_name = "tv_enc_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(tv_enc_clk.c),
+	},
+};
+
+/* Hacking root & branch into one param. */
+static struct branch_clk tsif_ref_clk = {
+	.b = {
+		.ctl_reg = TSIF_NS_REG,
+		.en_mask = BIT(9)|BIT(11),
+		.halt_reg = CLK_HALT_STATEB_REG,
+		.halt_bit = 11,
+		.reset_mask = P_TSIF_REF_CLK,
+	},
+	.parent = &tv_clk.c,
+	.c = {
+		.dbg_name = "tsif_ref_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(tsif_ref_clk.c),
+	},
+};
+
+static struct clk_freq_tbl clk_tbl_usb[] = {
+	F_MND8(       0,  0,  0, gnd,  1,  0,   0),
+	F_MND8(60000000, 23, 16, pll1, 2,  5,  32),
+	F_END,
+};
+
+static struct rcg_clk usb_hs_src_clk = {
+	.ns_reg = USBH_NS_REG,
+	.b = {
+		.ctl_reg = USBH_NS_REG,
+		.halt_check = NOCHECK,
+	},
+	.md_reg = USBH_NS_REG - 4,
+	.ns_mask = F_MASK_MND8(23, 16),
+	.mnd_en_mask = BIT(8),
+	.root_en_mask = BIT(11),
+	.freq_tbl = clk_tbl_usb,
+	.current_freq = &rcg_dummy_freq,
+	.set_rate = set_rate_mnd,
+	.c = {
+		.dbg_name = "usb_hs_src_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 60000000),
+		CLK_INIT(usb_hs_src_clk.c),
+		.depends = &axi_li_adsp_a_clk.c,
+	},
+};
+
+static struct branch_clk usb_hs_clk = {
+	.b = {
+		.ctl_reg = USBH_NS_REG,
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_STATEB_REG,
+		.halt_bit = 26,
+		.reset_mask = P_USB_HS_CLK,
+	},
+	.c = {
+		.dbg_name = "usb_hs_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_hs_clk.c),
+	},
+};
+
+static struct branch_clk usb_hs_core_clk = {
+	.b = {
+		.ctl_reg = USBH_NS_REG,
+		.en_mask = BIT(13),
+		.halt_reg = CLK_HALT_STATEA_REG,
+		.halt_bit = 27,
+		.reset_mask = P_USB_HS_CORE_CLK,
+	},
+	.parent = &usb_hs_src_clk.c,
+	.c = {
+		.dbg_name = "usb_hs_core_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_hs_core_clk.c),
+	},
+};
+
+static struct branch_clk usb_hs2_clk = {
+	.b = {
+		.ctl_reg = USBH2_NS_REG,
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_STATEB_REG,
+		.halt_bit = 3,
+		.reset_mask = P_USB_HS2_CLK,
+	},
+	.parent = &usb_hs_src_clk.c,
+	.c = {
+		.dbg_name = "usb_hs2_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_hs2_clk.c),
+	},
+};
+
+static struct branch_clk usb_hs2_core_clk = {
+	.b = {
+		.ctl_reg = USBH2_NS_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_STATEA_REG,
+		.halt_bit = 28,
+		.reset_mask = P_USB_HS2_CORE_CLK,
+	},
+	.parent = &usb_hs_src_clk.c,
+	.c = {
+		.dbg_name = "usb_hs2_core_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_hs2_core_clk.c),
+	},
+};
+
+static struct branch_clk usb_hs3_clk = {
+	.b = {
+		.ctl_reg = USBH3_NS_REG,
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_STATEB_REG,
+		.halt_bit = 2,
+		.reset_mask = P_USB_HS3_CLK,
+	},
+	.parent = &usb_hs_src_clk.c,
+	.c = {
+		.dbg_name = "usb_hs3_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_hs3_clk.c),
+	},
+};
+
+static struct branch_clk usb_hs3_core_clk = {
+	.b = {
+		.ctl_reg = USBH3_NS_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_STATEA_REG,
+		.halt_bit = 29,
+		.reset_mask = P_USB_HS3_CORE_CLK,
+	},
+	.parent = &usb_hs_src_clk.c,
+	.c = {
+		.dbg_name = "usb_hs3_core_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_hs3_core_clk.c),
+	},
+};
+
+static struct clk_freq_tbl clk_tbl_vfe_jpeg[] = {
+	F_MND16( 24576000, lpxo, 1,   0,   0),
+	F_MND16( 36864000, pll3, 4,   1,   5),
+	F_MND16( 46080000, pll3, 4,   1,   4),
+	F_MND16( 61440000, pll3, 4,   1,   3),
+	F_MND16( 73728000, pll3, 2,   1,   5),
+	F_MND16( 81920000, pll3, 3,   1,   3),
+	F_MND16( 92160000, pll3, 4,   1,   2),
+	F_MND16( 98304000, pll3, 3,   2,   5),
+	F_MND16(105326000, pll3, 2,   2,   7),
+	F_MND16(122880000, pll3, 2,   1,   3),
+	F_MND16(147456000, pll3, 2,   2,   5),
+	F_MND16(153600000, pll1, 2,   2,   5),
+	F_MND16(192000000, pll1, 4,   0,   0),
+	F_END,
+};
+
+static struct rcg_clk jpeg_clk = {
+	.b = {
+		.ctl_reg = JPEG_NS_REG,
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_STATEB_REG,
+		.halt_bit = 1,
+		.reset_mask = P_JPEG_CLK,
+	},
+	.ns_reg = JPEG_NS_REG,
+	.md_reg = JPEG_NS_REG - 4,
+	.root_en_mask = BIT(11),
+	.freq_tbl = clk_tbl_vfe_jpeg,
+	.ns_mask = F_MASK_MND16,
+	.mnd_en_mask = BIT(8),
+	.set_rate = set_rate_mnd,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "jpeg_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(NOMINAL, 153600000, HIGH, 192000000),
+		CLK_INIT(jpeg_clk.c),
+		.depends = &axi_li_jpeg_clk.c,
+	},
+};
+
+static struct rcg_clk vfe_clk = {
+	.b = {
+		.ctl_reg = CAM_VFE_NS_REG,
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_STATEB_REG,
+		.halt_bit = 0,
+		.reset_mask = P_VFE_CLK,
+	},
+	.ns_reg = CAM_VFE_NS_REG,
+	.md_reg = CAM_VFE_NS_REG - 4,
+	.root_en_mask = BIT(13),
+	.freq_tbl = clk_tbl_vfe_jpeg,
+	.ns_mask = F_MASK_MND16,
+	.mnd_en_mask = BIT(8),
+	.set_rate = set_rate_mnd,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "vfe_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(NOMINAL, 153600000, HIGH, 192000000),
+		CLK_INIT(vfe_clk.c),
+		.depends = &axi_li_vfe_clk.c,
+	},
+};
+
+static struct branch_clk vfe_mdc_clk = {
+	.b = {
+		.ctl_reg = CAM_VFE_NS_REG,
+		.en_mask = BIT(11),
+		.halt_reg = CLK_HALT_STATEA_REG,
+		.halt_bit = 9,
+		.reset_mask = P_VFE_MDC_CLK,
+	},
+	.parent = &vfe_clk.c,
+	.c = {
+		.dbg_name = "vfe_mdc_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(vfe_mdc_clk.c),
+	},
+};
+
+static struct branch_clk vfe_camif_clk = {
+	.b = {
+		.ctl_reg = CAM_VFE_NS_REG,
+		.en_mask = BIT(15),
+		.halt_reg = CLK_HALT_STATEC_REG,
+		.halt_bit = 13,
+		.reset_mask = P_VFE_CAMIF_CLK,
+	},
+	.parent = &vfe_clk.c,
+	.c = {
+		.dbg_name = "vfe_camif_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(vfe_camif_clk.c),
+	},
+};
+
+static struct branch_clk csi0_vfe_clk = {
+	.b = {
+		.ctl_reg = CSI_NS_REG,
+		.en_mask = BIT(15),
+		.halt_reg = CLK_HALT_STATEC_REG,
+		.halt_bit = 16,
+		.reset_mask = P_CSI0_VFE_CLK,
+	},
+	.parent = &vfe_clk.c,
+	.c = {
+		.dbg_name = "csi0_vfe_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi0_vfe_clk.c),
+	},
+};
+
+static struct clk_freq_tbl clk_tbl_cam[] = {
+	F_MND16(       0, gnd,  1,   0,   0),
+	F_MND16( 6000000, pll1, 4,   1,  32),
+	F_MND16( 8000000, pll1, 4,   1,  24),
+	F_MND16(12000000, pll1, 4,   1,  16),
+	F_MND16(16000000, pll1, 4,   1,  12),
+	F_MND16(19200000, pll1, 4,   1,  10),
+	F_MND16(24000000, pll1, 4,   1,   8),
+	F_MND16(32000000, pll1, 4,   1,   6),
+	F_MND16(48000000, pll1, 4,   1,   4),
+	F_MND16(64000000, pll1, 4,   1,   3),
+	F_END,
+};
+
+static struct rcg_clk cam_m_clk = {
+	.b = {
+		.ctl_reg = CAM_NS_REG,
+		.halt_check = DELAY,
+		.reset_mask = P_CAM_M_CLK,
+	},
+	.ns_reg = CAM_NS_REG,
+	.md_reg = CAM_NS_REG - 4,
+	.root_en_mask = BIT(9),
+	.freq_tbl = clk_tbl_cam,
+	.ns_mask = F_MASK_MND16,
+	.mnd_en_mask = BIT(8),
+	.set_rate = set_rate_mnd,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "cam_m_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 64000000),
+		CLK_INIT(cam_m_clk.c),
+	},
+};
+
+static struct clk_freq_tbl clk_tbl_vpe[] = {
+	F_MND8( 24576000, 22, 15, lpxo, 1,   0,   0),
+	F_MND8( 30720000, 22, 15, pll3, 4,   1,   6),
+	F_MND8( 61440000, 22, 15, pll3, 4,   1,   3),
+	F_MND8( 81920000, 22, 15, pll3, 3,   1,   3),
+	F_MND8(122880000, 22, 15, pll3, 3,   1,   2),
+	F_MND8(147456000, 22, 15, pll3, 1,   1,   5),
+	F_MND8(153600000, 22, 15, pll1, 1,   1,   5),
+	F_END,
+};
+
+static struct rcg_clk vpe_clk = {
+	.b = {
+		.ctl_reg = VPE_NS_REG,
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_STATEC_REG,
+		.halt_bit = 10,
+		.reset_mask = P_VPE_CLK,
+	},
+	.ns_reg = VPE_NS_REG,
+	.md_reg = VPE_NS_REG - 4,
+	.ns_mask = F_MASK_MND8(22, 15),
+	.mnd_en_mask = BIT(8),
+	.root_en_mask = BIT(11),
+	.freq_tbl = clk_tbl_vpe,
+	.current_freq = &rcg_dummy_freq,
+	.set_rate = set_rate_mnd,
+	.c = {
+		.dbg_name = "vpe_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 153600000),
+		CLK_INIT(vpe_clk.c),
+		.depends = &axi_vpe_clk.c,
+	},
+};
+
+static struct clk_freq_tbl clk_tbl_mfc[] = {
+	F_MND8( 24576000, 24, 17, lpxo, 1,   0,   0),
+	F_MND8( 30720000, 24, 17, pll3, 4,   1,   6),
+	F_MND8( 61440000, 24, 17, pll3, 4,   1,   3),
+	F_MND8( 81920000, 24, 17, pll3, 3,   1,   3),
+	F_MND8(122880000, 24, 17, pll3, 3,   1,   2),
+	F_MND8(147456000, 24, 17, pll3, 1,   1,   5),
+	F_MND8(153600000, 24, 17, pll1, 1,   1,   5),
+	F_MND8(170667000, 24, 17, pll1, 1,   2,   9),
+	F_END,
+};
+
+static struct rcg_clk mfc_clk = {
+	.b = {
+		.ctl_reg = MFC_NS_REG,
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_STATEC_REG,
+		.halt_bit = 12,
+		.reset_mask = P_MFC_CLK,
+	},
+	.ns_reg = MFC_NS_REG,
+	.md_reg = MFC_NS_REG - 4,
+	.ns_mask = F_MASK_MND8(24, 17),
+	.mnd_en_mask = BIT(8),
+	.root_en_mask = BIT(11),
+	.freq_tbl = clk_tbl_mfc,
+	.current_freq = &rcg_dummy_freq,
+	.set_rate = set_rate_mnd,
+	.c = {
+		.dbg_name = "mfc_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 170667000),
+		CLK_INIT(mfc_clk.c),
+		.depends = &axi_mfc_clk.c,
+	},
+};
+
+static struct branch_clk mfc_div2_clk = {
+	.b = {
+		.ctl_reg = MFC_NS_REG,
+		.en_mask = BIT(15),
+		.halt_reg = CLK_HALT_STATEC_REG,
+		.halt_bit = 11,
+		.reset_mask = P_MFC_DIV2_CLK,
+	},
+	.parent = &mfc_clk.c,
+	.c = {
+		.dbg_name = "mfc_div2_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mfc_div2_clk.c),
+	},
+};
+
+static struct clk_freq_tbl clk_tbl_spi[] = {
+	F_MND8(       0,  0,  0, gnd,  1,   0,     0),
+	F_MND8( 9963243, 19, 12, pll3, 4,   2,    37),
+	F_MND8(24576000, 19, 12, lpxo, 1,   0,     0),
+	F_MND8(26331429, 19, 12, pll3, 4,   1,     7),
+	F_END,
+};
+
+static struct rcg_clk spi_clk = {
+	.b = {
+		.ctl_reg = SPI_NS_REG,
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_STATEC_REG,
+		.halt_bit = 0,
+		.reset_mask = P_SPI_CLK,
+	},
+	.ns_reg = SPI_NS_REG,
+	.md_reg = SPI_NS_REG - 4,
+	.ns_mask = F_MASK_MND8(19, 12),
+	.mnd_en_mask = BIT(8),
+	.root_en_mask = BIT(11),
+	.freq_tbl = clk_tbl_spi,
+	.current_freq = &rcg_dummy_freq,
+	.set_rate = set_rate_mnd,
+	.c = {
+		.dbg_name = "spi_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 26331429),
+		CLK_INIT(spi_clk.c),
+	},
+};
+
+static struct clk_freq_tbl clk_tbl_lpa_codec[] = {
+	F_RAW(1, NULL, 0, 0, 0, NULL), /* src MI2S_CODEC_RX */
+	F_RAW(2, NULL, 0, 1, 0, NULL), /* src ECODEC_CIF */
+	F_RAW(3, NULL, 0, 2, 0, NULL), /* src MI2S */
+	F_RAW(4, NULL, 0, 3, 0, NULL), /* src SDAC */
+	F_END,
+};
+
+static struct rcg_clk lpa_codec_clk = {
+	.b = {
+		.ctl_reg = LPA_NS_REG,
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_STATEC_REG,
+		.halt_bit = 6,
+		.reset_mask = P_LPA_CODEC_CLK,
+	},
+	.ns_reg = LPA_NS_REG,
+	.ns_mask = BM(1, 0),
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_lpa_codec,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "lpa_codec_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 4),
+		CLK_INIT(lpa_codec_clk.c),
+	},
+};
+
+static struct clk_freq_tbl clk_tbl_mdc[] = {
+	F_RAW(1, NULL, 0, 0, 0, NULL),
+	F_END
+};
+
+static struct rcg_clk mdc_clk = {
+	.b = {
+		.ctl_reg = MDC_NS_REG,
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_STATEA_REG,
+		.halt_bit = 10,
+		.reset_mask = P_MDC_CLK,
+	},
+	.ns_reg = MDC_NS_REG,
+	.root_en_mask = BIT(11),
+	.freq_tbl = clk_tbl_mdc,
+	.current_freq = &rcg_dummy_freq,
+	.set_rate = set_rate_nop,
+	.c = {
+		.dbg_name = "mdc_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 1),
+		CLK_INIT(mdc_clk.c),
+	},
+};
+
+static struct branch_clk lpa_core_clk = {
+	.b = {
+		.ctl_reg = LPA_NS_REG,
+		.en_mask = BIT(5),
+		.halt_reg = CLK_HALT_STATEC_REG,
+		.halt_bit = 5,
+		.reset_mask = P_LPA_CORE_CLK,
+	},
+	.c = {
+		.dbg_name = "lpa_core_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(lpa_core_clk.c),
+	},
+};
+
+static DEFINE_CLK_PCOM(adsp_clk, ADSP_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(codec_ssbi_clk,	CODEC_SSBI_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(ebi1_clk, EBI1_CLK, CLKFLAG_SKIP_AUTO_OFF | CLKFLAG_MIN);
+static DEFINE_CLK_PCOM(ebi1_fixed_clk, EBI1_FIXED_CLK, CLKFLAG_MIN |
+						       CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(ecodec_clk, ECODEC_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(gp_clk, GP_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(uart3_clk, UART3_CLK, 0);
+static DEFINE_CLK_PCOM(usb_phy_clk, USB_PHY_CLK, CLKFLAG_MIN);
+
+static DEFINE_CLK_PCOM(p_grp_2d_clk, GRP_2D_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_grp_2d_p_clk, GRP_2D_P_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_hdmi_clk, HDMI_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_jpeg_clk, JPEG_CLK, CLKFLAG_MIN);
+static DEFINE_CLK_PCOM(p_jpeg_p_clk, JPEG_P_CLK, 0);
+static DEFINE_CLK_PCOM(p_lpa_codec_clk, LPA_CODEC_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_lpa_core_clk, LPA_CORE_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_lpa_p_clk, LPA_P_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_mi2s_m_clk, MI2S_M_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_mi2s_s_clk, MI2S_S_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_mi2s_codec_rx_m_clk, MI2S_CODEC_RX_M_CLK,
+		CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_mi2s_codec_rx_s_clk, MI2S_CODEC_RX_S_CLK,
+		CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_mi2s_codec_tx_m_clk, MI2S_CODEC_TX_M_CLK,
+		CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_mi2s_codec_tx_s_clk, MI2S_CODEC_TX_S_CLK,
+		CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_sdac_clk, SDAC_CLK, 0);
+static DEFINE_CLK_PCOM(p_sdac_m_clk, SDAC_M_CLK, 0);
+static DEFINE_CLK_PCOM(p_vfe_clk, VFE_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_vfe_camif_clk, VFE_CAMIF_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_vfe_mdc_clk, VFE_MDC_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_vfe_p_clk, VFE_P_CLK, 0);
+static DEFINE_CLK_PCOM(p_grp_3d_clk, GRP_3D_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_grp_3d_p_clk, GRP_3D_P_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_imem_clk, IMEM_CLK, 0);
+static DEFINE_CLK_PCOM(p_mdp_lcdc_pad_pclk_clk, MDP_LCDC_PAD_PCLK_CLK,
+		CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_mdp_lcdc_pclk_clk, MDP_LCDC_PCLK_CLK,
+		CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_mdp_p_clk, MDP_P_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_mdp_vsync_clk, MDP_VSYNC_CLK, 0);
+static DEFINE_CLK_PCOM(p_tsif_ref_clk, TSIF_REF_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_tsif_p_clk, TSIF_P_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_tv_dac_clk, TV_DAC_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_tv_enc_clk, TV_ENC_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_emdh_clk, EMDH_CLK, CLKFLAG_MIN | CLKFLAG_MAX);
+static DEFINE_CLK_PCOM(p_emdh_p_clk, EMDH_P_CLK, 0);
+static DEFINE_CLK_PCOM(p_i2c_clk, I2C_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_i2c_2_clk, I2C_2_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_mdc_clk, MDC_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_pmdh_clk, PMDH_CLK, CLKFLAG_MIN | CLKFLAG_MAX);
+static DEFINE_CLK_PCOM(p_pmdh_p_clk, PMDH_P_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_sdc1_clk, SDC1_CLK, 0);
+static DEFINE_CLK_PCOM(p_sdc1_p_clk, SDC1_P_CLK, 0);
+static DEFINE_CLK_PCOM(p_sdc2_clk, SDC2_CLK, 0);
+static DEFINE_CLK_PCOM(p_sdc2_p_clk, SDC2_P_CLK, 0);
+static DEFINE_CLK_PCOM(p_sdc3_clk, SDC3_CLK, 0);
+static DEFINE_CLK_PCOM(p_sdc3_p_clk, SDC3_P_CLK, 0);
+static DEFINE_CLK_PCOM(p_sdc4_clk, SDC4_CLK, 0);
+static DEFINE_CLK_PCOM(p_sdc4_p_clk, SDC4_P_CLK, 0);
+static DEFINE_CLK_PCOM(p_uart2_clk, UART2_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_usb_hs2_clk, USB_HS2_CLK, 0);
+static DEFINE_CLK_PCOM(p_usb_hs2_core_clk, USB_HS2_CORE_CLK, 0);
+static DEFINE_CLK_PCOM(p_usb_hs2_p_clk, USB_HS2_P_CLK, 0);
+static DEFINE_CLK_PCOM(p_usb_hs3_clk, USB_HS3_CLK, 0);
+static DEFINE_CLK_PCOM(p_usb_hs3_core_clk, USB_HS3_CORE_CLK, 0);
+static DEFINE_CLK_PCOM(p_usb_hs3_p_clk, USB_HS3_P_CLK, 0);
+static DEFINE_CLK_PCOM(p_qup_i2c_clk, QUP_I2C_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_spi_clk, SPI_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_spi_p_clk, SPI_P_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_uart1_clk, UART1_CLK, 0);
+static DEFINE_CLK_PCOM(p_uart1dm_clk, UART1DM_CLK, 0);
+static DEFINE_CLK_PCOM(p_uart2dm_clk, UART2DM_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_usb_hs_clk, USB_HS_CLK, 0);
+static DEFINE_CLK_PCOM(p_usb_hs_core_clk, USB_HS_CORE_CLK, 0);
+static DEFINE_CLK_PCOM(p_usb_hs_p_clk, USB_HS_P_CLK, 0);
+static DEFINE_CLK_PCOM(p_cam_m_clk, CAM_M_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_camif_pad_p_clk, CAMIF_PAD_P_CLK, 0);
+static DEFINE_CLK_PCOM(p_csi0_clk, CSI0_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_csi0_vfe_clk, CSI0_VFE_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_csi0_p_clk, CSI0_P_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_mdp_clk, MDP_CLK, CLKFLAG_MIN);
+static DEFINE_CLK_PCOM(p_mfc_clk, MFC_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_mfc_div2_clk, MFC_DIV2_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_mfc_p_clk, MFC_P_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_vpe_clk, VPE_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_adm_clk, ADM_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_ce_clk, CE_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_axi_rotator_clk, AXI_ROTATOR_CLK,
+		CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(p_rotator_imem_clk, ROTATOR_IMEM_CLK, 0);
+static DEFINE_CLK_PCOM(p_rotator_p_clk, ROTATOR_P_CLK, 0);
+
+static DEFINE_CLK_VOTER(ebi_dtv_clk, &ebi1_fixed_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_grp_3d_clk, &ebi1_fixed_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_grp_2d_clk, &ebi1_fixed_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_lcdc_clk, &ebi1_fixed_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_mddi_clk, &ebi1_fixed_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_tv_clk, &ebi1_fixed_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_vcd_clk, &ebi1_fixed_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_vfe_clk, &ebi1_fixed_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_adm_clk, &ebi1_fixed_clk.c, 0);
+
+#ifdef CONFIG_DEBUG_FS
+
+#define CLK_TEST_2(s) (s)
+#define CLK_TEST_HS(s) (0x4000 | ((s) << 8))
+#define CLK_TEST_LS(s) (0x4D40 | (s))
+
+struct measure_sel {
+	u32 test_vector;
+	struct clk *clk;
+};
+
+static struct measure_sel measure_mux[] = {
+	{ CLK_TEST_2(0x03), &emdh_p_clk.c },
+	{ CLK_TEST_2(0x04), &pmdh_p_clk.c },
+	{ CLK_TEST_2(0x06), &mdp_p_clk.c },
+	{ CLK_TEST_2(0x07), &lpa_p_clk.c },
+	{ CLK_TEST_2(0x08), &usb_hs2_p_clk.c },
+	{ CLK_TEST_2(0x09), &spi_clk.c },
+	{ CLK_TEST_2(0x0B), &i2c_2_clk.c },
+	{ CLK_TEST_2(0x0D), &mi2s_m_clk.c },
+	{ CLK_TEST_2(0x0E), &lpa_core_clk.c },
+	{ CLK_TEST_2(0x0F), &lpa_codec_clk.c },
+	{ CLK_TEST_2(0x10), &usb_hs3_p_clk.c },
+	{ CLK_TEST_2(0x11), &adm_p_clk.c },
+	{ CLK_TEST_2(0x13), &hdmi_clk.c },
+	{ CLK_TEST_2(0x14), &usb_hs_core_clk.c },
+	{ CLK_TEST_2(0x15), &usb_hs2_core_clk.c },
+	{ CLK_TEST_2(0x16), &usb_hs3_core_clk.c },
+	{ CLK_TEST_2(0x17), &mi2s_codec_tx_s_clk.c },
+	{ CLK_TEST_2(0x18), &spi_p_clk.c },
+	{ CLK_TEST_2(0x1A), &camif_pad_p_clk.c },
+	{ CLK_TEST_2(0x1C), &qup_i2c_clk.c },
+	{ CLK_TEST_2(0x1F), &mfc_div2_clk.c },
+	{ CLK_TEST_2(0x38), &mfc_clk.c },
+
+	{ CLK_TEST_HS(0x00), &adm_clk.c },
+	{ CLK_TEST_HS(0x01), &mdp_lcdc_pad_pclk_clk.c },
+	{ CLK_TEST_HS(0x02), &mdp_lcdc_pclk_clk.c },
+	{ CLK_TEST_HS(0x03), &axi_rotator_clk.c },
+	{ CLK_TEST_HS(0x07), &axi_li_vg_clk.c },
+	{ CLK_TEST_HS(0x09), &axi_li_apps_clk.c },
+	{ CLK_TEST_HS(0x0E), &axi_li_jpeg_clk.c },
+	{ CLK_TEST_HS(0x0F), &emdh_clk.c },
+	{ CLK_TEST_HS(0x14), &mdp_clk.c },
+	{ CLK_TEST_HS(0x15), &pmdh_clk.c },
+	{ CLK_TEST_HS(0x19), &axi_grp_2d_clk.c },
+	{ CLK_TEST_HS(0x1A), &axi_li_grp_clk.c },
+	{ CLK_TEST_HS(0x1B), &axi_li_vfe_clk.c },
+	{ CLK_TEST_HS(0x1C), &grp_2d_clk.c },
+	{ CLK_TEST_HS(0x1E), &grp_3d_clk.c },
+	{ CLK_TEST_HS(0x1F), &imem_clk.c },
+	{ CLK_TEST_HS(0x20), &jpeg_clk.c },
+	{ CLK_TEST_HS(0x24), &axi_li_adsp_a_clk.c },
+	{ CLK_TEST_HS(0x26), &rotator_imem_clk.c },
+	{ CLK_TEST_HS(0x27), &axi_vpe_clk.c },
+	{ CLK_TEST_HS(0x2A), &axi_mfc_clk.c },
+	{ CLK_TEST_HS(0x2B), &axi_mdp_clk.c },
+	{ CLK_TEST_HS(0x2C), &vpe_clk.c },
+	{ CLK_TEST_HS(0x30), &vfe_camif_clk.c },
+	{ CLK_TEST_HS(0x31), &csi0_clk.c },
+	{ CLK_TEST_HS(0x32), &csi0_vfe_clk.c },
+	{ CLK_TEST_HS(0x33), &csi0_p_clk.c },
+
+	{ CLK_TEST_LS(0x03), &ce_clk.c },
+	{ CLK_TEST_LS(0x04), &cam_m_clk.c },
+	{ CLK_TEST_LS(0x0C), &grp_2d_p_clk.c },
+	{ CLK_TEST_LS(0x0D), &i2c_clk.c },
+	{ CLK_TEST_LS(0x0E), &mi2s_codec_rx_m_clk.c },
+	{ CLK_TEST_LS(0x0F), &mi2s_codec_rx_s_clk.c },
+	{ CLK_TEST_LS(0x10), &mi2s_codec_tx_m_clk.c },
+	{ CLK_TEST_LS(0x13), &mdp_vsync_clk.c },
+	{ CLK_TEST_LS(0x15), &vfe_p_clk.c },
+	{ CLK_TEST_LS(0x16), &mdc_clk.c },
+	{ CLK_TEST_LS(0x17), &vfe_mdc_clk.c },
+	{ CLK_TEST_LS(0x18), &usb_hs_p_clk.c },
+	{ CLK_TEST_LS(0x1C), &uart1dm_p_clk.c },
+	{ CLK_TEST_LS(0x1E), &jpeg_p_clk.c },
+	{ CLK_TEST_LS(0x20), &sdac_clk.c },
+	{ CLK_TEST_LS(0x21), &sdc1_p_clk.c },
+	{ CLK_TEST_LS(0x22), &sdc1_clk.c },
+	{ CLK_TEST_LS(0x23), &sdc2_p_clk.c },
+	{ CLK_TEST_LS(0x24), &sdc2_clk.c },
+	{ CLK_TEST_LS(0x25), &tsif_p_clk.c },
+	{ CLK_TEST_LS(0x26), &sdac_m_clk.c },
+	{ CLK_TEST_LS(0x27), &grp_3d_p_clk.c },
+	{ CLK_TEST_LS(0x2A), &tsif_ref_clk.c },
+	{ CLK_TEST_LS(0x2B), &tv_enc_clk.c },
+	{ CLK_TEST_LS(0x2C), &tv_dac_clk.c },
+	{ CLK_TEST_LS(0x2D), &rotator_p_clk.c },
+	{ CLK_TEST_LS(0x2F), &uart1_clk.c },
+	{ CLK_TEST_LS(0x30), &uart1dm_clk.c },
+	{ CLK_TEST_LS(0x31), &uart2_clk.c },
+	{ CLK_TEST_LS(0x33), &usb_hs2_clk.c },
+	{ CLK_TEST_LS(0x34), &usb_hs3_clk.c },
+	{ CLK_TEST_LS(0x35), &mfc_p_clk.c },
+	{ CLK_TEST_LS(0x36), &vfe_clk.c },
+	{ CLK_TEST_LS(0x39), &sdc3_p_clk.c },
+	{ CLK_TEST_LS(0x3A), &sdc3_clk.c },
+	{ CLK_TEST_LS(0x3B), &sdc4_p_clk.c },
+	{ CLK_TEST_LS(0x3C), &sdc4_clk.c },
+	{ CLK_TEST_LS(0x3D), &uart2dm_clk.c },
+	{ CLK_TEST_LS(0x3E), &uart2dm_p_clk.c },
+	{ CLK_TEST_LS(0x3F), &usb_hs_clk.c },
+};
+
+static struct measure_sel *find_measure_sel(struct clk *clk)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(measure_mux); i++)
+		if (measure_mux[i].clk == clk)
+			return &measure_mux[i];
+	return NULL;
+}
+
+static int measure_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	struct measure_sel *p;
+	unsigned long flags;
+
+	if (!parent)
+		return -EINVAL;
+
+	p = find_measure_sel(parent);
+	if (!p)
+		return -EINVAL;
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+
+	/* Program test vector. */
+	if (p->test_vector <= 0xFF) {
+		/* Select CLK_TEST_2 */
+		writel_relaxed(0x4D40, CLK_TEST_BASE_REG);
+		writel_relaxed(p->test_vector, CLK_TEST_2_BASE_REG);
+	} else
+		writel_relaxed(p->test_vector, CLK_TEST_BASE_REG);
+
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	return 0;
+}
+
+/* Sample clock for 'tcxo4_ticks' reference clock ticks. */
+static unsigned long run_measurement(unsigned tcxo4_ticks)
+{
+	/* TCXO4_CNT_EN and RINGOSC_CNT_EN register values. */
+	u32 reg_val_enable = readl_relaxed(MISC_CLK_CTL_BASE_REG) | 0x3;
+	u32 reg_val_disable = reg_val_enable & ~0x3;
+
+	/* Stop counters and set the TCXO4 counter start value. */
+	writel_relaxed(reg_val_disable, MISC_CLK_CTL_BASE_REG);
+	writel_relaxed(tcxo4_ticks, TCXO_CNT_BASE_REG);
+
+	/* Run measurement and wait for completion. */
+	writel_relaxed(reg_val_enable, MISC_CLK_CTL_BASE_REG);
+	while (readl_relaxed(TCXO_CNT_DONE_BASE_REG) == 0)
+		cpu_relax();
+
+	/* Stop counters. */
+	writel_relaxed(reg_val_disable, MISC_CLK_CTL_BASE_REG);
+
+	return readl_relaxed(RINGOSC_CNT_BASE_REG);
+}
+
+/* Perform a hardware rate measurement for a given clock.
+   FOR DEBUG USE ONLY: Measurements take ~15 ms! */
+static unsigned long measure_clk_get_rate(struct clk *clk)
+{
+	unsigned long flags;
+	u32 regval, prph_web_reg_old;
+	u64 raw_count_short, raw_count_full;
+	unsigned ret;
+
+	clk_prepare_enable(&tcxo_clk.c);
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+
+	/* Enable TCXO4 clock branch and root. */
+	prph_web_reg_old = readl_relaxed(PRPH_WEB_NS_BASE_REG);
+	regval = prph_web_reg_old | BIT(9) | BIT(11);
+	writel_relaxed(regval, PRPH_WEB_NS_BASE_REG);
+
+	/*
+	 * The ring oscillator counter will not reset if the measured clock
+	 * is not running.  To detect this, run a short measurement before
+	 * the full measurement.  If the raw results of the two are the same
+	 * then the clock must be off.
+	 */
+
+	/* Run a short measurement. (~1 ms) */
+	raw_count_short = run_measurement(0x1000);
+	/* Run a full measurement. (~14 ms) */
+	raw_count_full = run_measurement(0x10000);
+
+	/* Disable TCXO4 clock branch and root. */
+	writel_relaxed(prph_web_reg_old, PRPH_WEB_NS_BASE_REG);
+
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	/* Return 0 if the clock is off. */
+	if (raw_count_full == raw_count_short)
+		ret = 0;
+	else {
+		/* Compute rate in Hz. */
+		raw_count_full = ((raw_count_full * 10) + 15) * 4800000;
+		do_div(raw_count_full, ((0x10000 * 10) + 35));
+		ret = raw_count_full;
+	}
+
+	clk_disable_unprepare(&tcxo_clk.c);
+
+	return ret;
+}
+#else /* !CONFIG_DEBUG_FS */
+static int measure_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	return -EINVAL;
+}
+
+static unsigned long measure_clk_get_rate(struct clk *clk)
+{
+	return 0;
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static struct clk_ops clk_ops_measure = {
+	.set_parent = measure_clk_set_parent,
+	.get_rate = measure_clk_get_rate,
+};
+
+static struct clk measure_clk = {
+	.dbg_name = "measure_clk",
+	.ops = &clk_ops_measure,
+	CLK_INIT(measure_clk),
+};
+
+/* Implementation for clk_set_flags(). */
+int soc_clk_set_flags(struct clk *clk, unsigned clk_flags)
+{
+	uint32_t regval, ret = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+
+	if (clk == &vfe_clk.c) {
+		regval = readl_relaxed(CAM_VFE_NS_REG);
+		/* Flag values chosen for backward compatibility
+		 * with proc_comm remote clock control. */
+		if (clk_flags == 0x00000100) {
+			/* Select external source. */
+			regval |= BIT(14);
+		} else if (clk_flags == 0x00000200) {
+			/* Select internal source. */
+			regval &= ~BIT(14);
+		} else
+			ret = -EINVAL;
+
+		writel_relaxed(regval, CAM_VFE_NS_REG);
+		/* Make sure write is issued before returning. */
+		mb();
+	} else
+		ret = -EPERM;
+
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	return ret;
+}
+
+static int msm7x30_clk_reset(struct clk *clk, enum clk_reset_action action)
+{
+	/* reset_mask is actually a proc_comm id */
+	unsigned id = to_rcg_clk(clk)->b.reset_mask;
+	return pc_clk_reset(id, action);
+}
+
+static int soc_branch_clk_reset(struct clk *clk, enum clk_reset_action action)
+{
+	unsigned id = to_branch_clk(clk)->b.reset_mask;
+	return pc_clk_reset(id, action);
+}
+
+/*
+ * Clock ownership detection code
+ */
+
+enum {
+	SH2_OWN_GLBL,
+	SH2_OWN_APPS1,
+	SH2_OWN_APPS2,
+	SH2_OWN_ROW1,
+	SH2_OWN_ROW2,
+	SH2_OWN_APPS3,
+	NUM_OWNERSHIP
+};
+static __initdata uint32_t ownership_regs[NUM_OWNERSHIP];
+
+static void __init cache_ownership(void)
+{
+	ownership_regs[SH2_OWN_GLBL]  = readl_relaxed(SH2_OWN_GLBL_BASE_REG);
+	ownership_regs[SH2_OWN_APPS1] = readl_relaxed(SH2_OWN_APPS1_BASE_REG);
+	ownership_regs[SH2_OWN_APPS2] = readl_relaxed(SH2_OWN_APPS2_BASE_REG);
+	ownership_regs[SH2_OWN_ROW1]  = readl_relaxed(SH2_OWN_ROW1_BASE_REG);
+	ownership_regs[SH2_OWN_ROW2]  = readl_relaxed(SH2_OWN_ROW2_BASE_REG);
+	ownership_regs[SH2_OWN_APPS3] = readl_relaxed(SH2_OWN_APPS3_BASE_REG);
+}
+
+static void __init print_ownership(void)
+{
+	pr_info("Clock ownership\n");
+	pr_info("  GLBL  : %08x\n", ownership_regs[SH2_OWN_GLBL]);
+	pr_info("  APPS  : %08x %08x %08x\n", ownership_regs[SH2_OWN_APPS1],
+		ownership_regs[SH2_OWN_APPS2], ownership_regs[SH2_OWN_APPS3]);
+	pr_info("  ROW   : %08x %08x\n", ownership_regs[SH2_OWN_ROW1],
+		ownership_regs[SH2_OWN_ROW2]);
+}
+
+#define O(x) (&ownership_regs[(SH2_OWN_##x)])
+#define OWN(r, b, name, clk, dev) \
+	{ \
+		.lk = CLK_LOOKUP(name, clk.c, dev), \
+		.remote = &p_##clk.c, \
+		.reg = O(r), \
+		.bit = BIT(b), \
+	}
+
+static struct clk_local_ownership {
+	struct clk_lookup lk;
+	const u32 *reg;
+	const u32 bit;
+	struct clk *remote;
+} ownership_map[] __initdata = {
+	/* Sources */
+	{ CLK_LOOKUP("pll1_clk",	pll1_clk.c,	"acpu") },
+	{ CLK_LOOKUP("pll2_clk",	pll2_clk.c,	"acpu") },
+	{ CLK_LOOKUP("pll3_clk",	pll3_clk.c,	"acpu") },
+	{ CLK_LOOKUP("measure",		measure_clk,	"debug") },
+
+	/* PCOM */
+	{ CLK_LOOKUP("adsp_clk",	adsp_clk.c,	NULL) },
+	{ CLK_LOOKUP("codec_ssbi_clk",	codec_ssbi_clk.c,	NULL) },
+	{ CLK_LOOKUP("ebi1_clk",	ebi1_clk.c,	NULL) },
+	{ CLK_LOOKUP("ebi1_fixed_clk",	ebi1_fixed_clk.c,	NULL) },
+	{ CLK_LOOKUP("ecodec_clk",	ecodec_clk.c,	NULL) },
+	{ CLK_LOOKUP("core_clk",	gp_clk.c,	"") },
+	{ CLK_LOOKUP("core_clk",	uart3_clk.c,	"msm_serial.2") },
+	{ CLK_LOOKUP("phy_clk",		usb_phy_clk.c,	"msm_otg") },
+
+	/* Voters */
+	{ CLK_LOOKUP("mem_clk",	ebi_dtv_clk.c,	"dtv.0") },
+	{ CLK_LOOKUP("bus_clk",		ebi_grp_2d_clk.c, "kgsl-2d0.0") },
+	{ CLK_LOOKUP("bus_clk",		ebi_grp_3d_clk.c, "kgsl-3d0.0") },
+	{ CLK_LOOKUP("mem_clk",	ebi_lcdc_clk.c,	"lcdc.0") },
+	{ CLK_LOOKUP("mem_clk",	ebi_mddi_clk.c,	"mddi.0") },
+	{ CLK_LOOKUP("mem_clk",	ebi_tv_clk.c,	"tvenc.0") },
+	{ CLK_LOOKUP("mem_clk",		ebi_vcd_clk.c,	"msm_vidc.0") },
+	{ CLK_LOOKUP("ebi1_vfe_clk",	ebi_vfe_clk.c,	NULL) },
+	{ CLK_LOOKUP("mem_clk",		ebi_adm_clk.c,	"msm_dmov") },
+
+	/*
+	 * This is a many-to-one mapping because we don't know how the remote
+	 * clock code has decided to handle the dependencies between clocks for
+	 * a particular hardware block. We determine the ownership for all the
+	 * clocks going into a block by checking the ownership bit of one
+	 * register (usually the ns register).
+	 */
+	OWN(APPS1,  6, "core_clk",	grp_2d_clk,	"kgsl-2d0.0"),
+	OWN(APPS1,  6, "core_clk",	grp_2d_clk,	"footswitch-pcom.0"),
+	OWN(APPS1,  6, "iface_clk",	grp_2d_p_clk,	"kgsl-2d0.0"),
+	OWN(APPS1,  6, "iface_clk",	grp_2d_p_clk,	"footswitch-pcom.0"),
+	OWN(APPS1, 31, "hdmi_clk",	hdmi_clk,	"dtv.0"),
+	OWN(APPS1,  0, "core_clk",	jpeg_clk,	"msm_gemini.0"),
+	OWN(APPS1,  0, "iface_clk",	jpeg_p_clk,	"msm_gemini.0"),
+	OWN(APPS1, 23, "lpa_codec_clk", lpa_codec_clk,	NULL),
+	OWN(APPS1, 23, "lpa_core_clk",	lpa_core_clk,	NULL),
+	OWN(APPS1, 23, "lpa_pclk",	lpa_p_clk,	NULL),
+	OWN(APPS1, 28, "mi2s_m_clk",	mi2s_m_clk,	NULL),
+	OWN(APPS1, 28, "mi2s_s_clk",	mi2s_s_clk,	NULL),
+	OWN(APPS1, 12, "mi2s_codec_rx_m_clk", mi2s_codec_rx_m_clk, NULL),
+	OWN(APPS1, 12, "mi2s_codec_rx_s_clk", mi2s_codec_rx_s_clk, NULL),
+	OWN(APPS1, 14, "mi2s_codec_tx_m_clk", mi2s_codec_tx_m_clk, NULL),
+	OWN(APPS1, 14, "mi2s_codec_tx_s_clk", mi2s_codec_tx_s_clk, NULL),
+	OWN(APPS1, 26, "sdac_clk",	sdac_clk,	NULL),
+	OWN(APPS1, 26, "sdac_m_clk",	sdac_m_clk,	NULL),
+	OWN(APPS1,  8, "vfe_clk",	vfe_clk,	NULL),
+	OWN(APPS1,  8, "core_clk",	vfe_clk,	"footswitch-pcom.8"),
+	OWN(APPS1,  8, "vfe_camif_clk", vfe_camif_clk,	NULL),
+	OWN(APPS1,  8, "vfe_mdc_clk",	vfe_mdc_clk,	NULL),
+	OWN(APPS1,  8, "vfe_pclk",	vfe_p_clk,	NULL),
+	OWN(APPS1,  8, "iface_clk",	vfe_p_clk,	"footswitch-pcom.8"),
+
+	OWN(APPS2,  0, "core_clk",	grp_3d_clk,	"kgsl-3d0.0"),
+	OWN(APPS2,  0, "core_clk",	grp_3d_clk,	"footswitch-pcom.2"),
+	OWN(APPS2,  0, "iface_clk",	grp_3d_p_clk,	"kgsl-3d0.0"),
+	OWN(APPS2,  0, "iface_clk",	grp_3d_p_clk,	"footswitch-pcom.2"),
+	{ CLK_LOOKUP("src_clk",     grp_3d_src_clk.c, "kgsl-3d0.0"),
+		O(APPS2), BIT(0), &p_grp_3d_clk.c },
+	{ CLK_LOOKUP("src_clk",     grp_3d_src_clk.c, "footswitch-pcom.2"),
+		O(APPS2), BIT(0), &p_grp_3d_clk.c },
+	OWN(APPS2,  0, "mem_clk",	imem_clk,	"kgsl-3d0.0"),
+	OWN(APPS2, 4, "lcdc_clk", mdp_lcdc_pad_pclk_clk, "lcdc.0"),
+	OWN(APPS2,  4, "mdp_clk", mdp_lcdc_pclk_clk, "lcdc.0"),
+	OWN(APPS2,  4, "iface_clk",	mdp_p_clk,	"mdp.0"),
+	OWN(APPS2,  4, "iface_clk",	mdp_p_clk,	"footswitch-pcom.4"),
+	OWN(APPS2, 28, "vsync_clk", mdp_vsync_clk,	"mdp.0"),
+	OWN(APPS2,  5, "ref_clk",	tsif_ref_clk,	"msm_tsif.0"),
+	OWN(APPS2,  5, "iface_clk",	tsif_p_clk,	"msm_tsif.0"),
+	{ CLK_LOOKUP("src_clk",      tv_clk.c,       "dtv.0"),
+		O(APPS2), BIT(2), &p_tv_enc_clk.c },
+	OWN(APPS2,  2, "tv_dac_clk",	tv_dac_clk,	NULL),
+	OWN(APPS2,  2, "tv_enc_clk",	tv_enc_clk,	NULL),
+
+	OWN(ROW1,  7, "core_clk",	emdh_clk,	"msm_mddi.1"),
+	OWN(ROW1,  7, "iface_clk",	emdh_p_clk,	"msm_mddi.1"),
+	OWN(ROW1, 11, "core_clk",	i2c_clk,	"msm_i2c.0"),
+	OWN(ROW1, 12, "core_clk",	i2c_2_clk,	"msm_i2c.2"),
+	OWN(ROW1, 17, "mdc_clk",	mdc_clk,	NULL),
+	OWN(ROW1, 19, "core_clk",	pmdh_clk,	"mddi.0"),
+	OWN(ROW1, 19, "iface_clk",	pmdh_p_clk,	"mddi.0"),
+	OWN(ROW1, 23, "core_clk",	sdc1_clk,	"msm_sdcc.1"),
+	OWN(ROW1, 23, "iface_clk",	sdc1_p_clk,	"msm_sdcc.1"),
+	OWN(ROW1, 25, "core_clk",	sdc2_clk,	"msm_sdcc.2"),
+	OWN(ROW1, 25, "iface_clk",	sdc2_p_clk,	"msm_sdcc.2"),
+	OWN(ROW1, 27, "core_clk",	sdc3_clk,	"msm_sdcc.3"),
+	OWN(ROW1, 27, "iface_clk",	sdc3_p_clk,	"msm_sdcc.3"),
+	OWN(ROW1, 29, "core_clk",	sdc4_clk,	"msm_sdcc.4"),
+	OWN(ROW1, 29, "iface_clk",	sdc4_p_clk,	"msm_sdcc.4"),
+	OWN(ROW1,  0, "core_clk",	uart2_clk,	"msm_serial.1"),
+	OWN(ROW1,  2, "alt_core_clk",	usb_hs2_clk,	"msm_hsusb_host.0"),
+	OWN(ROW1,  2, "core_clk",	usb_hs2_core_clk, "msm_hsusb_host.0"),
+	OWN(ROW1,  2, "iface_clk",	usb_hs2_p_clk,	"msm_hsusb_host.0"),
+	OWN(ROW1,  4, "alt_core_clk",	usb_hs3_clk,	""),
+	OWN(ROW1,  4, "core_clk",	usb_hs3_core_clk, ""),
+	OWN(ROW1,  4, "iface_clk",	usb_hs3_p_clk,	""),
+
+	OWN(ROW2,  3, "core_clk",	qup_i2c_clk,	"qup_i2c.4"),
+	OWN(ROW2,  1, "core_clk",	spi_clk,	"spi_qsd.0"),
+	OWN(ROW2,  1, "iface_clk",	spi_p_clk,	"spi_qsd.0"),
+	OWN(ROW2,  9, "core_clk",	uart1_clk,	"msm_serial.0"),
+	OWN(ROW2,  6, "core_clk",	uart1dm_clk,	"msm_serial_hs.0"),
+	OWN(ROW2,  8, "core_clk",	uart2dm_clk,	"msm_serial_hs.1"),
+	OWN(ROW2, 11, "alt_core_clk",	usb_hs_clk,	"msm_otg"),
+	OWN(ROW2, 11, "core_clk",	usb_hs_core_clk, "msm_otg"),
+	OWN(ROW2, 11, "iface_clk",	usb_hs_p_clk,	"msm_otg"),
+
+	OWN(APPS3,  6, "cam_m_clk",	cam_m_clk,	NULL),
+	OWN(APPS3,  6, "cam_clk",	cam_m_clk,	"4-0020"),
+	OWN(APPS3,  6, "camif_pad_pclk", camif_pad_p_clk, NULL),
+	OWN(APPS3,  6, "iface_clk",	camif_pad_p_clk, "qup_i2c.4"),
+	OWN(APPS3, 11, "csi_clk",	csi0_clk,	NULL),
+	OWN(APPS3, 11, "csi_vfe_clk",	csi0_vfe_clk,	NULL),
+	OWN(APPS3, 11, "csi_pclk",	csi0_p_clk,	NULL),
+	OWN(APPS3,  0, "core_clk",	mdp_clk,	"mdp.0"),
+	OWN(APPS3,  0, "core_clk",	mdp_clk,	"footswitch-pcom.4"),
+	OWN(APPS3,  2, "core_clk",	mfc_clk,	"msm_vidc.0"),
+	OWN(APPS3,  2, "core_clk",	mfc_clk,	"footswitch-pcom.5"),
+	OWN(APPS3,  2, "core_div2_clk",	mfc_div2_clk,	"msm_vidc.0"),
+	OWN(APPS3,  2, "iface_clk",	mfc_p_clk,	"msm_vidc.0"),
+	OWN(APPS3,  2, "iface_clk",	mfc_p_clk,	"footswitch-pcom.5"),
+	OWN(APPS3,  4, "vpe_clk",	vpe_clk,	NULL),
+	OWN(APPS3,  4, "core_clk",	vpe_clk,	"footswitch-pcom.9"),
+
+	OWN(GLBL,  8, "core_clk",	adm_clk,	"msm_dmov"),
+	{ CLK_LOOKUP("iface_clk",		adm_p_clk.c,	"msm_dmov"),
+		O(GLBL), BIT(13), &dummy_clk },
+	OWN(GLBL,  8, "core_clk",	ce_clk,		"qce.0"),
+	OWN(GLBL,  8, "core_clk",	ce_clk,		"crypto.0"),
+	OWN(GLBL, 13, "core_clk",	axi_rotator_clk, "msm_rotator.0"),
+	OWN(GLBL, 13, "core_clk",	axi_rotator_clk, "footswitch-pcom.6"),
+	OWN(GLBL, 13, "mem_clk",	rotator_imem_clk, "msm_rotator.0"),
+	OWN(GLBL, 13, "iface_clk",	rotator_p_clk,	"msm_rotator.0"),
+	OWN(GLBL, 13, "iface_clk",	rotator_p_clk,	"footswitch-pcom.6"),
+	{ CLK_LOOKUP("iface_clk",     uart1dm_p_clk.c, "msm_serial_hs.0"),
+		O(GLBL), BIT(8), &dummy_clk },
+	{ CLK_LOOKUP("iface_clk",     uart2dm_p_clk.c, "msm_serial_hs.1"),
+		O(GLBL), BIT(8), &dummy_clk },
+};
+
+static struct clk_lookup msm_clocks_7x30[ARRAY_SIZE(ownership_map)];
+
+static void __init set_clock_ownership(void)
+{
+	unsigned i;
+	struct clk_lookup *lk;
+
+	for (i = 0; i < ARRAY_SIZE(ownership_map); i++) {
+		const u32 *reg = ownership_map[i].reg;
+		u32 bit = ownership_map[i].bit;
+		struct clk *remote = ownership_map[i].remote;
+
+		lk = &ownership_map[i].lk;
+		memcpy(&msm_clocks_7x30[i], lk, sizeof(*lk));
+
+		if (reg && !(*reg & bit))
+			msm_clocks_7x30[i].clk = remote;
+	}
+}
+
+/*
+ * Miscellaneous clock register initializations
+ */
+static const struct reg_init {
+	const void __iomem *reg;
+	uint32_t mask;
+	uint32_t val;
+} ri_list[] __initconst = {
+	/* Enable UMDX_P clock. Known to causes issues, so never turn off. */
+	{GLBL_CLK_ENA_2_SC_REG, BIT(2), BIT(2)},
+
+	/* Disable all the child clocks of USB_HS_SRC. */
+	{ USBH_NS_REG, BIT(13) | BIT(9), 0 },
+	{ USBH2_NS_REG, BIT(9) | BIT(4), 0 },
+	{ USBH3_NS_REG, BIT(9) | BIT(4), 0 },
+
+	{EMDH_NS_REG, BM(18, 17) , BVAL(18, 17, 0x3)}, /* RX div = div-4. */
+	{PMDH_NS_REG, BM(18, 17), BVAL(18, 17, 0x3)}, /* RX div = div-4. */
+	/* MI2S_CODEC_RX_S src = MI2S_CODEC_RX_M. */
+	{MI2S_RX_NS_REG, BIT(14), 0x0},
+	/* MI2S_CODEC_TX_S src = MI2S_CODEC_TX_M. */
+	{MI2S_TX_NS_REG, BIT(14), 0x0},
+	{MI2S_NS_REG, BIT(14), 0x0}, /* MI2S_S src = MI2S_M. */
+	/* Allow DSP to decide the LPA CORE src. */
+	{LPA_CORE_CLK_MA0_REG, BIT(0), BIT(0)},
+	{LPA_CORE_CLK_MA2_REG, BIT(0), BIT(0)},
+	{MI2S_CODEC_RX_DIV_REG, 0xF, 0xD}, /* MI2S_CODEC_RX_S div = div-8. */
+	{MI2S_CODEC_TX_DIV_REG, 0xF, 0xD}, /* MI2S_CODEC_TX_S div = div-8. */
+	{MI2S_DIV_REG, 0xF, 0x7}, /* MI2S_S div = div-8. */
+	{MDC_NS_REG, 0x3, 0x3}, /* MDC src = external MDH src. */
+	{SDAC_NS_REG, BM(15, 14), 0x0}, /* SDAC div = div-1. */
+	/* Disable sources TCXO/5 & TCXO/6. UART1 src = TCXO*/
+	{UART_NS_REG, BM(26, 25) | BM(2, 0), 0x0},
+	/* HDMI div = div-1, non-inverted. tv_enc_src = tv_clk_src */
+	{HDMI_NS_REG, 0x7, 0x0},
+	{TV_NS_REG, BM(15, 14), 0x0}, /* tv_clk_src_div2 = div-1 */
+
+	/* USBH core clocks src = USB_HS_SRC. */
+	{USBH_NS_REG, BIT(15), BIT(15)},
+	{USBH2_NS_REG, BIT(6), BIT(6)},
+	{USBH3_NS_REG, BIT(6), BIT(6)},
+};
+
+static void __init msm7x30_clock_pre_init(void)
+{
+	int i;
+	uint32_t val;
+
+	clk_ops_branch.reset = soc_branch_clk_reset;
+	clk_ops_rcg.reset = msm7x30_clk_reset;
+	clk_ops_rcg.set_flags = soc_clk_set_flags;
+
+	cache_ownership();
+	print_ownership();
+	set_clock_ownership();
+
+	/* When we have no local clock control, the rest of the code in this
+	 * function is a NOP since writes to shadow regions that we don't own
+	 * are ignored. */
+
+	for (i = 0; i < ARRAY_SIZE(ri_list); i++) {
+		val = readl_relaxed(ri_list[i].reg);
+		val &= ~ri_list[i].mask;
+		val |= ri_list[i].val;
+		writel_relaxed(val, ri_list[i].reg);
+	}
+}
+
+static void __init msm7x30_clock_post_init(void)
+{
+	clk_set_rate(&usb_hs_src_clk.c, 60000000);
+	clk_set_rate(&i2c_clk.c, 19200000);
+	clk_set_rate(&i2c_2_clk.c, 19200000);
+	clk_set_rate(&qup_i2c_clk.c, 19200000);
+	clk_set_rate(&uart1_clk.c, 19200000);
+	clk_set_rate(&uart2_clk.c, 19200000);
+	clk_set_rate(&mi2s_m_clk.c, 12288000);
+	clk_set_rate(&mdp_vsync_clk.c, 24576000);
+	clk_set_rate(&glbl_root_clk.c, 1);
+	clk_set_rate(&mdc_clk.c, 1);
+	/* Sync the LPA_CODEC clock to MI2S_CODEC_RX */
+	clk_set_rate(&lpa_codec_clk.c, 1);
+	/* Sync the GRP2D clock to AXI */
+	clk_set_rate(&grp_2d_clk.c, 1);
+}
+
+struct clock_init_data msm7x30_clock_init_data __initdata = {
+	.table = msm_clocks_7x30,
+	.size = ARRAY_SIZE(msm_clocks_7x30),
+	.pre_init = msm7x30_clock_pre_init,
+	.post_init = msm7x30_clock_post_init,
+};
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
new file mode 100644
index 0000000..a1b9c1c
--- /dev/null
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -0,0 +1,6332 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <asm/clkdev.h>
+#include <asm/mach-types.h>
+
+#include <mach/msm_iomap.h>
+#include <mach/clk.h>
+#include <mach/rpm-regulator.h>
+#include <mach/socinfo.h>
+
+#include "clock-local.h"
+#include "clock-rpm.h"
+#include "clock-voter.h"
+#include "clock-dss-8960.h"
+#include "devices.h"
+#include "clock-pll.h"
+
+#define REG(off)	(MSM_CLK_CTL_BASE + (off))
+#define REG_MM(off)	(MSM_MMSS_CLK_CTL_BASE + (off))
+#define REG_LPA(off)	(MSM_LPASS_CLK_CTL_BASE + (off))
+#define REG_GCC(off)	(MSM_APCS_GCC_BASE + (off))
+
+/* Peripheral clock registers. */
+#define ADM0_PBUS_CLK_CTL_REG			REG(0x2208)
+#define SFAB_SATA_S_HCLK_CTL_REG		REG(0x2480)
+#define CE1_HCLK_CTL_REG			REG(0x2720)
+#define CE1_CORE_CLK_CTL_REG			REG(0x2724)
+#define PRNG_CLK_NS_REG				REG(0x2E80)
+#define CE3_HCLK_CTL_REG			REG(0x36C4)
+#define CE3_CORE_CLK_CTL_REG			REG(0x36CC)
+#define CE3_CLK_SRC_NS_REG			REG(0x36C0)
+#define DMA_BAM_HCLK_CTL			REG(0x25C0)
+#define CLK_HALT_AFAB_SFAB_STATEA_REG		REG(0x2FC0)
+#define CLK_HALT_AFAB_SFAB_STATEB_REG		REG(0x2FC4)
+#define CLK_HALT_CFPB_STATEA_REG		REG(0x2FCC)
+#define CLK_HALT_CFPB_STATEB_REG		REG(0x2FD0)
+#define CLK_HALT_CFPB_STATEC_REG		REG(0x2FD4)
+#define CLK_HALT_DFAB_STATE_REG			REG(0x2FC8)
+/* 8064 name CLK_HALT_GSS_KPSS_MISC_STATE_REG */
+#define CLK_HALT_MSS_SMPSS_MISC_STATE_REG	REG(0x2FDC)
+#define CLK_HALT_SFPB_MISC_STATE_REG		REG(0x2FD8)
+#define CLK_HALT_AFAB_SFAB_STATEB_REG		REG(0x2FC4)
+#define CLK_TEST_REG				REG(0x2FA0)
+#define GPn_MD_REG(n)				REG(0x2D00+(0x20*(n)))
+#define GPn_NS_REG(n)				REG(0x2D24+(0x20*(n)))
+#define GSBIn_HCLK_CTL_REG(n)			REG(0x29C0+(0x20*((n)-1)))
+#define GSBIn_QUP_APPS_MD_REG(n)		REG(0x29C8+(0x20*((n)-1)))
+#define GSBIn_QUP_APPS_NS_REG(n)		REG(0x29CC+(0x20*((n)-1)))
+#define GSBIn_RESET_REG(n)			REG(0x29DC+(0x20*((n)-1)))
+#define GSBIn_UART_APPS_MD_REG(n)		REG(0x29D0+(0x20*((n)-1)))
+#define GSBIn_UART_APPS_NS_REG(n)		REG(0x29D4+(0x20*((n)-1)))
+#define PDM_CLK_NS_REG				REG(0x2CC0)
+/* 8064 name BB_PLL_ENA_APCS_REG */
+#define BB_PLL_ENA_SC0_REG			REG(0x34C0)
+#define BB_PLL_ENA_RPM_REG			REG(0x34A0)
+#define BB_PLL0_STATUS_REG			REG(0x30D8)
+#define BB_PLL5_STATUS_REG			REG(0x30F8)
+#define BB_PLL6_STATUS_REG			REG(0x3118)
+#define BB_PLL7_STATUS_REG			REG(0x3138)
+#define BB_PLL8_L_VAL_REG			REG(0x3144)
+#define BB_PLL8_M_VAL_REG			REG(0x3148)
+#define BB_PLL8_MODE_REG			REG(0x3140)
+#define BB_PLL8_N_VAL_REG			REG(0x314C)
+#define BB_PLL8_STATUS_REG			REG(0x3158)
+#define BB_PLL8_CONFIG_REG			REG(0x3154)
+#define BB_PLL8_TEST_CTL_REG			REG(0x3150)
+#define BB_MMCC_PLL2_MODE_REG			REG(0x3160)
+#define BB_MMCC_PLL2_TEST_CTL_REG		REG(0x3170)
+#define BB_PLL14_MODE_REG			REG(0x31C0)
+#define BB_PLL14_L_VAL_REG			REG(0x31C4)
+#define BB_PLL14_M_VAL_REG			REG(0x31C8)
+#define BB_PLL14_N_VAL_REG			REG(0x31CC)
+#define BB_PLL14_TEST_CTL_REG			REG(0x31D0)
+#define BB_PLL14_CONFIG_REG			REG(0x31D4)
+#define BB_PLL14_STATUS_REG			REG(0x31D8)
+#define PLLTEST_PAD_CFG_REG			REG(0x2FA4)
+#define PMEM_ACLK_CTL_REG			REG(0x25A0)
+#define RINGOSC_NS_REG				REG(0x2DC0)
+#define RINGOSC_STATUS_REG			REG(0x2DCC)
+#define RINGOSC_TCXO_CTL_REG			REG(0x2DC4)
+#define RPM_MSG_RAM_HCLK_CTL_REG		REG(0x27E0)
+#define SC0_U_CLK_BRANCH_ENA_VOTE_REG		REG(0x3080)
+#define SDCn_APPS_CLK_MD_REG(n)			REG(0x2828+(0x20*((n)-1)))
+#define SDCn_APPS_CLK_NS_REG(n)			REG(0x282C+(0x20*((n)-1)))
+#define SDCn_HCLK_CTL_REG(n)			REG(0x2820+(0x20*((n)-1)))
+#define SDCn_RESET_REG(n)			REG(0x2830+(0x20*((n)-1)))
+#define SLIMBUS_XO_SRC_CLK_CTL_REG		REG(0x2628)
+#define TSIF_HCLK_CTL_REG			REG(0x2700)
+#define TSIF_REF_CLK_MD_REG			REG(0x270C)
+#define TSIF_REF_CLK_NS_REG			REG(0x2710)
+#define TSSC_CLK_CTL_REG			REG(0x2CA0)
+#define SATA_HCLK_CTL_REG			REG(0x2C00)
+#define SATA_CLK_SRC_NS_REG			REG(0x2C08)
+#define SATA_RXOOB_CLK_CTL_REG			REG(0x2C0C)
+#define SATA_PMALIVE_CLK_CTL_REG		REG(0x2C10)
+#define SATA_PHY_REF_CLK_CTL_REG		REG(0x2C14)
+#define SATA_ACLK_CTL_REG			REG(0x2C20)
+#define SATA_PHY_CFG_CLK_CTL_REG		REG(0x2C40)
+#define USB_FSn_HCLK_CTL_REG(n)			REG(0x2960+(0x20*((n)-1)))
+#define USB_FSn_RESET_REG(n)			REG(0x2974+(0x20*((n)-1)))
+#define USB_FSn_SYSTEM_CLK_CTL_REG(n)		REG(0x296C+(0x20*((n)-1)))
+#define USB_FSn_XCVR_FS_CLK_MD_REG(n)		REG(0x2964+(0x20*((n)-1)))
+#define USB_FSn_XCVR_FS_CLK_NS_REG(n)		REG(0x2968+(0x20*((n)-1)))
+#define USB_HS1_HCLK_CTL_REG			REG(0x2900)
+#define USB_HS1_HCLK_FS_REG			REG(0x2904)
+#define USB_HS1_RESET_REG			REG(0x2910)
+#define USB_HS1_XCVR_FS_CLK_MD_REG		REG(0x2908)
+#define USB_HS1_XCVR_FS_CLK_NS_REG		REG(0x290C)
+#define USB_HS3_HCLK_CTL_REG			REG(0x3700)
+#define USB_HS3_HCLK_FS_REG			REG(0x3704)
+#define USB_HS3_RESET_REG			REG(0x3710)
+#define USB_HS3_XCVR_FS_CLK_MD_REG		REG(0X3708)
+#define USB_HS3_XCVR_FS_CLK_NS_REG		REG(0X370C)
+#define USB_HS4_HCLK_CTL_REG			REG(0x3720)
+#define USB_HS4_HCLK_FS_REG			REG(0x3724)
+#define USB_HS4_RESET_REG			REG(0x3730)
+#define USB_HS4_XCVR_FS_CLK_MD_REG		REG(0X3728)
+#define USB_HS4_XCVR_FS_CLK_NS_REG		REG(0X372C)
+#define USB_HSIC_HCLK_CTL_REG			REG(0x2920)
+#define USB_HSIC_HSIC_CLK_CTL_REG		REG(0x2B44)
+#define USB_HSIC_HSIC_CLK_SRC_CTL_REG		REG(0x2B40)
+#define USB_HSIC_HSIO_CAL_CLK_CTL_REG		REG(0x2B48)
+#define USB_HSIC_RESET_REG			REG(0x2934)
+#define USB_HSIC_SYSTEM_CLK_CTL_REG		REG(0x292C)
+#define USB_HSIC_XCVR_FS_CLK_MD_REG		REG(0x2924)
+#define USB_HSIC_XCVR_FS_CLK_NS_REG		REG(0x2928)
+#define USB_PHY0_RESET_REG			REG(0x2E20)
+#define PCIE_ALT_REF_CLK_NS_REG			REG(0x3860)
+#define PCIE_ACLK_CTL_REG			REG(0x22C0)
+#define PCIE_HCLK_CTL_REG			REG(0x22CC)
+#define PCIE_PCLK_CTL_REG			REG(0x22D0)
+#define GPLL1_MODE_REG				REG(0x3160)
+#define GPLL1_L_VAL_REG				REG(0x3164)
+#define GPLL1_M_VAL_REG				REG(0x3168)
+#define GPLL1_N_VAL_REG				REG(0x316C)
+#define GPLL1_CONFIG_REG			REG(0x3174)
+#define GPLL1_STATUS_REG			REG(0x3178)
+#define PXO_SRC_CLK_CTL_REG			REG(0x2EA0)
+
+/* Multimedia clock registers. */
+#define AHB_EN_REG				REG_MM(0x0008)
+#define AHB_EN2_REG				REG_MM(0x0038)
+#define AHB_EN3_REG				REG_MM(0x0248)
+#define AHB_NS_REG				REG_MM(0x0004)
+#define AXI_NS_REG				REG_MM(0x0014)
+#define CAMCLK0_NS_REG				REG_MM(0x0148)
+#define CAMCLK0_CC_REG				REG_MM(0x0140)
+#define CAMCLK0_MD_REG				REG_MM(0x0144)
+#define CAMCLK1_NS_REG				REG_MM(0x015C)
+#define CAMCLK1_CC_REG				REG_MM(0x0154)
+#define CAMCLK1_MD_REG				REG_MM(0x0158)
+#define CAMCLK2_NS_REG				REG_MM(0x0228)
+#define CAMCLK2_CC_REG				REG_MM(0x0220)
+#define CAMCLK2_MD_REG				REG_MM(0x0224)
+#define CSI0_NS_REG				REG_MM(0x0048)
+#define CSI0_CC_REG				REG_MM(0x0040)
+#define CSI0_MD_REG				REG_MM(0x0044)
+#define CSI1_NS_REG				REG_MM(0x0010)
+#define CSI1_CC_REG				REG_MM(0x0024)
+#define CSI1_MD_REG				REG_MM(0x0028)
+#define CSI2_NS_REG				REG_MM(0x0234)
+#define CSI2_CC_REG				REG_MM(0x022C)
+#define CSI2_MD_REG				REG_MM(0x0230)
+#define CSIPHYTIMER_CC_REG			REG_MM(0x0160)
+#define CSIPHYTIMER_MD_REG			REG_MM(0x0164)
+#define CSIPHYTIMER_NS_REG			REG_MM(0x0168)
+#define DSI1_BYTE_NS_REG			REG_MM(0x00B0)
+#define DSI1_BYTE_CC_REG			REG_MM(0x0090)
+#define DSI2_BYTE_NS_REG			REG_MM(0x00BC)
+#define DSI2_BYTE_CC_REG			REG_MM(0x00B4)
+#define DSI1_ESC_NS_REG				REG_MM(0x011C)
+#define DSI1_ESC_CC_REG				REG_MM(0x00CC)
+#define DSI2_ESC_NS_REG				REG_MM(0x0150)
+#define DSI2_ESC_CC_REG				REG_MM(0x013C)
+#define DSI_PIXEL_CC_REG			REG_MM(0x0130)
+#define DSI2_PIXEL_CC_REG			REG_MM(0x0094)
+#define DBG_BUS_VEC_A_REG			REG_MM(0x01C8)
+#define DBG_BUS_VEC_B_REG			REG_MM(0x01CC)
+#define DBG_BUS_VEC_C_REG			REG_MM(0x01D0)
+#define DBG_BUS_VEC_D_REG			REG_MM(0x01D4)
+#define DBG_BUS_VEC_E_REG			REG_MM(0x01D8)
+#define DBG_BUS_VEC_F_REG			REG_MM(0x01DC)
+#define DBG_BUS_VEC_G_REG			REG_MM(0x01E0)
+#define DBG_BUS_VEC_H_REG			REG_MM(0x01E4)
+#define DBG_BUS_VEC_I_REG			REG_MM(0x01E8)
+#define DBG_BUS_VEC_J_REG			REG_MM(0x0240)
+#define DBG_CFG_REG_HS_REG			REG_MM(0x01B4)
+#define DBG_CFG_REG_LS_REG			REG_MM(0x01B8)
+#define GFX2D0_CC_REG				REG_MM(0x0060)
+#define GFX2D0_MD0_REG				REG_MM(0x0064)
+#define GFX2D0_MD1_REG				REG_MM(0x0068)
+#define GFX2D0_NS_REG				REG_MM(0x0070)
+#define GFX2D1_CC_REG				REG_MM(0x0074)
+#define GFX2D1_MD0_REG				REG_MM(0x0078)
+#define GFX2D1_MD1_REG				REG_MM(0x006C)
+#define GFX2D1_NS_REG				REG_MM(0x007C)
+#define GFX3D_CC_REG				REG_MM(0x0080)
+#define GFX3D_MD0_REG				REG_MM(0x0084)
+#define GFX3D_MD1_REG				REG_MM(0x0088)
+#define GFX3D_NS_REG				REG_MM(0x008C)
+#define IJPEG_CC_REG				REG_MM(0x0098)
+#define IJPEG_MD_REG				REG_MM(0x009C)
+#define IJPEG_NS_REG				REG_MM(0x00A0)
+#define JPEGD_CC_REG				REG_MM(0x00A4)
+#define JPEGD_NS_REG				REG_MM(0x00AC)
+#define VCAP_CC_REG				REG_MM(0x0178)
+#define VCAP_NS_REG				REG_MM(0x021C)
+#define VCAP_MD0_REG				REG_MM(0x01EC)
+#define VCAP_MD1_REG				REG_MM(0x0218)
+#define MAXI_EN_REG				REG_MM(0x0018)
+#define MAXI_EN2_REG				REG_MM(0x0020)
+#define MAXI_EN3_REG				REG_MM(0x002C)
+#define MAXI_EN4_REG				REG_MM(0x0114)
+#define MAXI_EN5_REG				REG_MM(0x0244)
+#define MDP_CC_REG				REG_MM(0x00C0)
+#define MDP_LUT_CC_REG				REG_MM(0x016C)
+#define MDP_MD0_REG				REG_MM(0x00C4)
+#define MDP_MD1_REG				REG_MM(0x00C8)
+#define MDP_NS_REG				REG_MM(0x00D0)
+#define MISC_CC_REG				REG_MM(0x0058)
+#define MISC_CC2_REG				REG_MM(0x005C)
+#define MISC_CC3_REG				REG_MM(0x0238)
+#define MM_PLL1_MODE_REG			REG_MM(0x031C)
+#define MM_PLL1_L_VAL_REG			REG_MM(0x0320)
+#define MM_PLL1_M_VAL_REG			REG_MM(0x0324)
+#define MM_PLL1_N_VAL_REG			REG_MM(0x0328)
+#define MM_PLL1_CONFIG_REG			REG_MM(0x032C)
+#define MM_PLL1_TEST_CTL_REG			REG_MM(0x0330)
+#define MM_PLL1_STATUS_REG			REG_MM(0x0334)
+#define MM_PLL3_MODE_REG			REG_MM(0x0338)
+#define MM_PLL3_L_VAL_REG			REG_MM(0x033C)
+#define MM_PLL3_M_VAL_REG			REG_MM(0x0340)
+#define MM_PLL3_N_VAL_REG			REG_MM(0x0344)
+#define MM_PLL3_CONFIG_REG			REG_MM(0x0348)
+#define MM_PLL3_TEST_CTL_REG			REG_MM(0x034C)
+#define MM_PLL3_STATUS_REG			REG_MM(0x0350)
+#define ROT_CC_REG				REG_MM(0x00E0)
+#define ROT_NS_REG				REG_MM(0x00E8)
+#define SAXI_EN_REG				REG_MM(0x0030)
+#define SW_RESET_AHB_REG			REG_MM(0x020C)
+#define SW_RESET_AHB2_REG			REG_MM(0x0200)
+#define SW_RESET_ALL_REG			REG_MM(0x0204)
+#define SW_RESET_AXI_REG			REG_MM(0x0208)
+#define SW_RESET_CORE_REG			REG_MM(0x0210)
+#define SW_RESET_CORE2_REG			REG_MM(0x0214)
+#define TV_CC_REG				REG_MM(0x00EC)
+#define TV_CC2_REG				REG_MM(0x0124)
+#define TV_MD_REG				REG_MM(0x00F0)
+#define TV_NS_REG				REG_MM(0x00F4)
+#define VCODEC_CC_REG				REG_MM(0x00F8)
+#define VCODEC_MD0_REG				REG_MM(0x00FC)
+#define VCODEC_MD1_REG				REG_MM(0x0128)
+#define VCODEC_NS_REG				REG_MM(0x0100)
+#define VFE_CC_REG				REG_MM(0x0104)
+#define VFE_MD_REG				REG_MM(0x0108)
+#define VFE_NS_REG				REG_MM(0x010C)
+#define VFE_CC2_REG				REG_MM(0x023C)
+#define VPE_CC_REG				REG_MM(0x0110)
+#define VPE_NS_REG				REG_MM(0x0118)
+
+/* Low-power Audio clock registers. */
+#define LCC_CLK_HS_DEBUG_CFG_REG		REG_LPA(0x00A4)
+#define LCC_CLK_LS_DEBUG_CFG_REG		REG_LPA(0x00A8)
+#define LCC_CODEC_I2S_MIC_MD_REG		REG_LPA(0x0064)
+#define LCC_CODEC_I2S_MIC_NS_REG		REG_LPA(0x0060)
+#define LCC_CODEC_I2S_MIC_STATUS_REG		REG_LPA(0x0068)
+#define LCC_CODEC_I2S_SPKR_MD_REG		REG_LPA(0x0070)
+#define LCC_CODEC_I2S_SPKR_NS_REG		REG_LPA(0x006C)
+#define LCC_CODEC_I2S_SPKR_STATUS_REG		REG_LPA(0x0074)
+#define LCC_MI2S_MD_REG				REG_LPA(0x004C)
+#define LCC_MI2S_NS_REG				REG_LPA(0x0048)
+#define LCC_MI2S_STATUS_REG			REG_LPA(0x0050)
+#define LCC_PCM_MD_REG				REG_LPA(0x0058)
+#define LCC_PCM_NS_REG				REG_LPA(0x0054)
+#define LCC_PCM_STATUS_REG			REG_LPA(0x005C)
+#define LCC_PLL0_MODE_REG			REG_LPA(0x0000)
+#define LCC_PLL0_L_VAL_REG			REG_LPA(0x0004)
+#define LCC_PLL0_M_VAL_REG			REG_LPA(0x0008)
+#define LCC_PLL0_N_VAL_REG			REG_LPA(0x000C)
+#define LCC_PLL0_CONFIG_REG			REG_LPA(0x0014)
+#define LCC_PLL0_STATUS_REG			REG_LPA(0x0018)
+#define LCC_SPARE_I2S_MIC_MD_REG		REG_LPA(0x007C)
+#define LCC_SPARE_I2S_MIC_NS_REG		REG_LPA(0x0078)
+#define LCC_SPARE_I2S_MIC_STATUS_REG		REG_LPA(0x0080)
+#define LCC_SPARE_I2S_SPKR_MD_REG		REG_LPA(0x0088)
+#define LCC_SPARE_I2S_SPKR_NS_REG		REG_LPA(0x0084)
+#define LCC_SPARE_I2S_SPKR_STATUS_REG		REG_LPA(0x008C)
+#define LCC_SLIMBUS_NS_REG			REG_LPA(0x00CC)
+#define LCC_SLIMBUS_MD_REG			REG_LPA(0x00D0)
+#define LCC_SLIMBUS_STATUS_REG			REG_LPA(0x00D4)
+#define LCC_AHBEX_BRANCH_CTL_REG		REG_LPA(0x00E4)
+#define LCC_PRI_PLL_CLK_CTL_REG			REG_LPA(0x00C4)
+
+#define GCC_APCS_CLK_DIAG			REG_GCC(0x001C)
+
+/* MUX source input identifiers. */
+#define pxo_to_bb_mux		0
+#define cxo_to_bb_mux		5
+#define pll0_to_bb_mux		2
+#define pll8_to_bb_mux		3
+#define pll6_to_bb_mux		4
+#define gnd_to_bb_mux		5
+#define pll3_to_bb_mux		6
+#define pxo_to_mm_mux		0
+#define pll1_to_mm_mux		1
+#define pll2_to_mm_mux		1	/* or MMCC_PLL1 */
+#define pll8_to_mm_mux		2	/* or GCC_PERF */
+#define pll0_to_mm_mux		3
+#define pll15_to_mm_mux		3	/* or MM_PLL3 */
+#define gnd_to_mm_mux		4
+#define pll3_to_mm_mux		3	/* or MMCC_PLL2 */
+#define hdmi_pll_to_mm_mux	3
+#define cxo_to_xo_mux		0
+#define pxo_to_xo_mux		1
+#define gnd_to_xo_mux		3
+#define pxo_to_lpa_mux		0
+#define cxo_to_lpa_mux		1
+#define pll4_to_lpa_mux		2
+#define gnd_to_lpa_mux		6
+#define pxo_to_pcie_mux		0
+#define pll3_to_pcie_mux	1
+
+/* Test Vector Macros */
+#define TEST_TYPE_PER_LS	1
+#define TEST_TYPE_PER_HS	2
+#define TEST_TYPE_MM_LS		3
+#define TEST_TYPE_MM_HS		4
+#define TEST_TYPE_LPA		5
+#define TEST_TYPE_CPUL2		6
+#define TEST_TYPE_LPA_HS	7
+#define TEST_TYPE_SHIFT		24
+#define TEST_CLK_SEL_MASK	BM(23, 0)
+#define TEST_VECTOR(s, t)	(((t) << TEST_TYPE_SHIFT) | BVAL(23, 0, (s)))
+#define TEST_PER_LS(s)		TEST_VECTOR((s), TEST_TYPE_PER_LS)
+#define TEST_PER_HS(s)		TEST_VECTOR((s), TEST_TYPE_PER_HS)
+#define TEST_MM_LS(s)		TEST_VECTOR((s), TEST_TYPE_MM_LS)
+#define TEST_MM_HS(s)		TEST_VECTOR((s), TEST_TYPE_MM_HS)
+#define TEST_LPA(s)		TEST_VECTOR((s), TEST_TYPE_LPA)
+#define TEST_LPA_HS(s)		TEST_VECTOR((s), TEST_TYPE_LPA_HS)
+#define TEST_CPUL2(s)		TEST_VECTOR((s), TEST_TYPE_CPUL2)
+
+#define MN_MODE_DUAL_EDGE 0x2
+
+struct pll_rate {
+	const uint32_t	l_val;
+	const uint32_t	m_val;
+	const uint32_t	n_val;
+	const uint32_t	vco;
+	const uint32_t	post_div;
+	const uint32_t	i_bits;
+};
+#define PLL_RATE(l, m, n, v, d, i) { l, m, n, v, (d>>1), i }
+
+enum vdd_dig_levels {
+	VDD_DIG_NONE,
+	VDD_DIG_LOW,
+	VDD_DIG_NOMINAL,
+	VDD_DIG_HIGH
+};
+
+static int set_vdd_dig_8960(struct clk_vdd_class *vdd_class, int level)
+{
+	static const int vdd_uv[] = {
+		[VDD_DIG_NONE]    =       0,
+		[VDD_DIG_LOW]     =  945000,
+		[VDD_DIG_NOMINAL] = 1050000,
+		[VDD_DIG_HIGH]    = 1150000
+	};
+	return rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S3, RPM_VREG_VOTER3,
+				    vdd_uv[level], 1150000, 1);
+}
+
+static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig_8960);
+
+static int set_vdd_dig_8930(struct clk_vdd_class *vdd_class, int level)
+{
+	static const int vdd_corner[] = {
+		[VDD_DIG_NONE]    = RPM_VREG_CORNER_NONE,
+		[VDD_DIG_LOW]     = RPM_VREG_CORNER_LOW,
+		[VDD_DIG_NOMINAL] = RPM_VREG_CORNER_NOMINAL,
+		[VDD_DIG_HIGH]    = RPM_VREG_CORNER_HIGH,
+	};
+	return rpm_vreg_set_voltage(RPM_VREG_ID_PM8038_VDD_DIG_CORNER,
+					RPM_VREG_VOTER3,
+					vdd_corner[level],
+					RPM_VREG_CORNER_HIGH, 1);
+}
+
+#define VDD_DIG_FMAX_MAP1(l1, f1) \
+	.vdd_class = &vdd_dig, \
+	.fmax[VDD_DIG_##l1] = (f1)
+#define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
+	.vdd_class = &vdd_dig, \
+	.fmax[VDD_DIG_##l1] = (f1), \
+	.fmax[VDD_DIG_##l2] = (f2)
+#define VDD_DIG_FMAX_MAP3(l1, f1, l2, f2, l3, f3) \
+	.vdd_class = &vdd_dig, \
+	.fmax[VDD_DIG_##l1] = (f1), \
+	.fmax[VDD_DIG_##l2] = (f2), \
+	.fmax[VDD_DIG_##l3] = (f3)
+
+enum vdd_sr2_pll_levels {
+	VDD_SR2_PLL_OFF,
+	VDD_SR2_PLL_ON
+};
+
+static int set_vdd_sr2_pll_8960(struct clk_vdd_class *vdd_class, int level)
+{
+	int rc = 0;
+
+	if (level == VDD_SR2_PLL_OFF) {
+		rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_L23,
+				RPM_VREG_VOTER3, 0, 0, 1);
+		if (rc)
+			return rc;
+		rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S8,
+				RPM_VREG_VOTER3, 0, 0, 1);
+		if (rc)
+			rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_L23,
+				RPM_VREG_VOTER3, 1800000, 1800000, 1);
+	} else {
+		rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S8,
+				RPM_VREG_VOTER3, 2050000, 2100000, 1);
+		if (rc)
+			return rc;
+		rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_L23,
+				RPM_VREG_VOTER3, 1800000, 1800000, 1);
+		if (rc)
+			rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S8,
+					RPM_VREG_VOTER3, 0, 0, 1);
+	}
+
+	return rc;
+}
+
+static DEFINE_VDD_CLASS(vdd_sr2_pll, set_vdd_sr2_pll_8960);
+
+static int sr2_lreg_uv[] = {
+	[VDD_SR2_PLL_OFF] = 0,
+	[VDD_SR2_PLL_ON] = 1800000,
+};
+
+static int set_vdd_sr2_pll_8064(struct clk_vdd_class *vdd_class, int level)
+{
+	return rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_LVS7, RPM_VREG_VOTER3,
+				    sr2_lreg_uv[level], sr2_lreg_uv[level], 1);
+}
+
+static int set_vdd_sr2_pll_8930(struct clk_vdd_class *vdd_class, int level)
+{
+	return rpm_vreg_set_voltage(RPM_VREG_ID_PM8038_L23, RPM_VREG_VOTER3,
+				    sr2_lreg_uv[level], sr2_lreg_uv[level], 1);
+}
+
+/*
+ * Clock Descriptions
+ */
+
+DEFINE_CLK_RPM_BRANCH(pxo_clk, pxo_a_clk, PXO, 27000000);
+DEFINE_CLK_RPM_BRANCH(cxo_clk, cxo_a_clk, CXO, 19200000);
+
+static struct pll_clk pll2_clk = {
+	.mode_reg = MM_PLL1_MODE_REG,
+	.parent = &pxo_clk.c,
+	.c = {
+		.dbg_name = "pll2_clk",
+		.rate = 800000000,
+		.ops = &clk_ops_local_pll,
+		CLK_INIT(pll2_clk.c),
+		.warned = true,
+	},
+};
+
+static struct pll_clk pll3_clk = {
+	.mode_reg = BB_MMCC_PLL2_MODE_REG,
+	.parent = &pxo_clk.c,
+	.c = {
+		.dbg_name = "pll3_clk",
+		.rate = 1200000000,
+		.ops = &clk_ops_local_pll,
+		.vdd_class = &vdd_sr2_pll,
+		.fmax[VDD_SR2_PLL_ON] = ULONG_MAX,
+		CLK_INIT(pll3_clk.c),
+		.warned = true,
+	},
+};
+
+static struct pll_vote_clk pll4_clk = {
+	.en_reg = BB_PLL_ENA_SC0_REG,
+	.en_mask = BIT(4),
+	.status_reg = LCC_PLL0_STATUS_REG,
+	.status_mask = BIT(16),
+	.parent = &pxo_clk.c,
+	.c = {
+		.dbg_name = "pll4_clk",
+		.rate = 393216000,
+		.ops = &clk_ops_pll_vote,
+		CLK_INIT(pll4_clk.c),
+		.warned = true,
+	},
+};
+
+static struct pll_vote_clk pll8_clk = {
+	.en_reg = BB_PLL_ENA_SC0_REG,
+	.en_mask = BIT(8),
+	.status_reg = BB_PLL8_STATUS_REG,
+	.status_mask = BIT(16),
+	.parent = &pxo_clk.c,
+	.c = {
+		.dbg_name = "pll8_clk",
+		.rate = 384000000,
+		.ops = &clk_ops_pll_vote,
+		CLK_INIT(pll8_clk.c),
+		.warned = true,
+	},
+};
+
+static struct pll_vote_clk pll14_clk = {
+	.en_reg = BB_PLL_ENA_SC0_REG,
+	.en_mask = BIT(14),
+	.status_reg = BB_PLL14_STATUS_REG,
+	.status_mask = BIT(16),
+	.parent = &pxo_clk.c,
+	.c = {
+		.dbg_name = "pll14_clk",
+		.rate = 480000000,
+		.ops = &clk_ops_pll_vote,
+		CLK_INIT(pll14_clk.c),
+		.warned = true,
+	},
+};
+
+static struct pll_clk pll15_clk = {
+	.mode_reg = MM_PLL3_MODE_REG,
+	.parent = &pxo_clk.c,
+	.c = {
+		.dbg_name = "pll15_clk",
+		.rate = 975000000,
+		.ops = &clk_ops_local_pll,
+		CLK_INIT(pll15_clk.c),
+		.warned = true,
+	},
+};
+
+/* AXI Interfaces */
+static struct branch_clk gmem_axi_clk = {
+	.b = {
+		.ctl_reg = MAXI_EN_REG,
+		.en_mask = BIT(24),
+		.halt_reg = DBG_BUS_VEC_E_REG,
+		.halt_bit = 6,
+		.retain_reg = MAXI_EN2_REG,
+		.retain_mask = BIT(21),
+	},
+	.c = {
+		.dbg_name = "gmem_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gmem_axi_clk.c),
+	},
+};
+
+static struct branch_clk ijpeg_axi_clk = {
+	.b = {
+		.ctl_reg = MAXI_EN_REG,
+		.en_mask = BIT(21),
+		.hwcg_reg = MAXI_EN_REG,
+		.hwcg_mask = BIT(11),
+		.reset_reg = SW_RESET_AXI_REG,
+		.reset_mask = BIT(14),
+		.halt_reg = DBG_BUS_VEC_E_REG,
+		.halt_bit = 4,
+	},
+	.c = {
+		.dbg_name = "ijpeg_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(ijpeg_axi_clk.c),
+	},
+};
+
+static struct branch_clk imem_axi_clk = {
+	.b = {
+		.ctl_reg = MAXI_EN_REG,
+		.en_mask = BIT(22),
+		.hwcg_reg = MAXI_EN_REG,
+		.hwcg_mask = BIT(15),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(10),
+		.halt_reg = DBG_BUS_VEC_E_REG,
+		.halt_bit = 7,
+		.retain_reg = MAXI_EN2_REG,
+		.retain_mask = BIT(10),
+	},
+	.c = {
+		.dbg_name = "imem_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(imem_axi_clk.c),
+	},
+};
+
+static struct branch_clk jpegd_axi_clk = {
+	.b = {
+		.ctl_reg = MAXI_EN_REG,
+		.en_mask = BIT(25),
+		.halt_reg = DBG_BUS_VEC_E_REG,
+		.halt_bit = 5,
+	},
+	.c = {
+		.dbg_name = "jpegd_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(jpegd_axi_clk.c),
+	},
+};
+
+static struct branch_clk vcodec_axi_b_clk = {
+	.b = {
+		.ctl_reg = MAXI_EN4_REG,
+		.en_mask = BIT(23),
+		.hwcg_reg = MAXI_EN4_REG,
+		.hwcg_mask = BIT(22),
+		.halt_reg = DBG_BUS_VEC_I_REG,
+		.halt_bit = 25,
+		.retain_reg = MAXI_EN4_REG,
+		.retain_mask = BIT(21),
+	},
+	.c = {
+		.dbg_name = "vcodec_axi_b_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(vcodec_axi_b_clk.c),
+	},
+};
+
+static struct branch_clk vcodec_axi_a_clk = {
+	.b = {
+		.ctl_reg = MAXI_EN4_REG,
+		.en_mask = BIT(25),
+		.hwcg_reg = MAXI_EN4_REG,
+		.hwcg_mask = BIT(24),
+		.halt_reg = DBG_BUS_VEC_I_REG,
+		.halt_bit = 26,
+		.retain_reg = MAXI_EN4_REG,
+		.retain_mask = BIT(10),
+	},
+	.c = {
+		.dbg_name = "vcodec_axi_a_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(vcodec_axi_a_clk.c),
+		.depends = &vcodec_axi_b_clk.c,
+	},
+};
+
+static struct branch_clk vcodec_axi_clk = {
+	.b = {
+		.ctl_reg = MAXI_EN_REG,
+		.en_mask = BIT(19),
+		.hwcg_reg = MAXI_EN_REG,
+		.hwcg_mask = BIT(13),
+		.reset_reg = SW_RESET_AXI_REG,
+		.reset_mask = BIT(4)|BIT(5)|BIT(7),
+		.halt_reg = DBG_BUS_VEC_E_REG,
+		.halt_bit = 3,
+		.retain_reg = MAXI_EN2_REG,
+		.retain_mask = BIT(28),
+	},
+	.c = {
+		.dbg_name = "vcodec_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(vcodec_axi_clk.c),
+		.depends = &vcodec_axi_a_clk.c,
+	},
+};
+
+static struct branch_clk vfe_axi_clk = {
+	.b = {
+		.ctl_reg = MAXI_EN_REG,
+		.en_mask = BIT(18),
+		.reset_reg = SW_RESET_AXI_REG,
+		.reset_mask = BIT(9),
+		.halt_reg = DBG_BUS_VEC_E_REG,
+		.halt_bit = 0,
+	},
+	.c = {
+		.dbg_name = "vfe_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(vfe_axi_clk.c),
+	},
+};
+
+static struct branch_clk mdp_axi_clk = {
+	.b = {
+		.ctl_reg = MAXI_EN_REG,
+		.en_mask = BIT(23),
+		.hwcg_reg = MAXI_EN_REG,
+		.hwcg_mask = BIT(16),
+		.reset_reg = SW_RESET_AXI_REG,
+		.reset_mask = BIT(13),
+		.halt_reg = DBG_BUS_VEC_E_REG,
+		.halt_bit = 8,
+		.retain_reg = MAXI_EN_REG,
+		.retain_mask = BIT(0),
+	},
+	.c = {
+		.dbg_name = "mdp_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdp_axi_clk.c),
+	},
+};
+
+static struct branch_clk rot_axi_clk = {
+	.b = {
+		.ctl_reg = MAXI_EN2_REG,
+		.en_mask = BIT(24),
+		.hwcg_reg = MAXI_EN2_REG,
+		.hwcg_mask = BIT(25),
+		.reset_reg = SW_RESET_AXI_REG,
+		.reset_mask = BIT(6),
+		.halt_reg = DBG_BUS_VEC_E_REG,
+		.halt_bit = 2,
+		.retain_reg = MAXI_EN3_REG,
+		.retain_mask = BIT(10),
+	},
+	.c = {
+		.dbg_name = "rot_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(rot_axi_clk.c),
+	},
+};
+
+static struct branch_clk vpe_axi_clk = {
+	.b = {
+		.ctl_reg = MAXI_EN2_REG,
+		.en_mask = BIT(26),
+		.hwcg_reg = MAXI_EN2_REG,
+		.hwcg_mask = BIT(27),
+		.reset_reg = SW_RESET_AXI_REG,
+		.reset_mask = BIT(15),
+		.halt_reg = DBG_BUS_VEC_E_REG,
+		.halt_bit = 1,
+		.retain_reg = MAXI_EN3_REG,
+		.retain_mask = BIT(21),
+
+	},
+	.c = {
+		.dbg_name = "vpe_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(vpe_axi_clk.c),
+	},
+};
+
+static struct branch_clk vcap_axi_clk = {
+	.b = {
+		.ctl_reg = MAXI_EN5_REG,
+		.en_mask = BIT(12),
+		.hwcg_reg = MAXI_EN5_REG,
+		.hwcg_mask = BIT(11),
+		.reset_reg = SW_RESET_AXI_REG,
+		.reset_mask = BIT(16),
+		.halt_reg = DBG_BUS_VEC_J_REG,
+		.halt_bit = 20,
+	},
+	.c = {
+		.dbg_name = "vcap_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(vcap_axi_clk.c),
+	},
+};
+
+/* gfx3d_axi_clk is set as a dependency of gmem_axi_clk at runtime */
+static struct branch_clk gfx3d_axi_clk_8064 = {
+	.b = {
+		.ctl_reg = MAXI_EN5_REG,
+		.en_mask = BIT(25),
+		.hwcg_reg = MAXI_EN5_REG,
+		.hwcg_mask = BIT(24),
+		.reset_reg = SW_RESET_AXI_REG,
+		.reset_mask = BIT(17),
+		.halt_reg = DBG_BUS_VEC_J_REG,
+		.halt_bit = 30,
+	},
+	.c = {
+		.dbg_name = "gfx3d_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gfx3d_axi_clk_8064.c),
+	},
+};
+
+static struct branch_clk gfx3d_axi_clk_8930 = {
+	.b = {
+		.ctl_reg = MAXI_EN5_REG,
+		.en_mask = BIT(12),
+		.reset_reg = SW_RESET_AXI_REG,
+		.reset_mask = BIT(16),
+		.halt_reg = DBG_BUS_VEC_J_REG,
+		.halt_bit = 12,
+	},
+	.c = {
+		.dbg_name = "gfx3d_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gfx3d_axi_clk_8930.c),
+	},
+};
+
+/* AHB Interfaces */
+static struct branch_clk amp_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(24),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(20),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 18,
+	},
+	.c = {
+		.dbg_name = "amp_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(amp_p_clk.c),
+	},
+};
+
+static struct branch_clk csi_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(7),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(17),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 16,
+	},
+	.c = {
+		.dbg_name = "csi_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi_p_clk.c),
+	},
+};
+
+static struct branch_clk dsi1_m_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(9),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(6),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 19,
+	},
+	.c = {
+		.dbg_name = "dsi1_m_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(dsi1_m_p_clk.c),
+	},
+};
+
+static struct branch_clk dsi1_s_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(18),
+		.hwcg_reg = AHB_EN2_REG,
+		.hwcg_mask = BIT(20),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(5),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 21,
+	},
+	.c = {
+		.dbg_name = "dsi1_s_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(dsi1_s_p_clk.c),
+	},
+};
+
+static struct branch_clk dsi2_m_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(17),
+		.reset_reg = SW_RESET_AHB2_REG,
+		.reset_mask = BIT(1),
+		.halt_reg = DBG_BUS_VEC_E_REG,
+		.halt_bit = 18,
+	},
+	.c = {
+		.dbg_name = "dsi2_m_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(dsi2_m_p_clk.c),
+	},
+};
+
+static struct branch_clk dsi2_s_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(22),
+		.hwcg_reg = AHB_EN2_REG,
+		.hwcg_mask = BIT(15),
+		.reset_reg = SW_RESET_AHB2_REG,
+		.reset_mask = BIT(0),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 20,
+	},
+	.c = {
+		.dbg_name = "dsi2_s_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(dsi2_s_p_clk.c),
+	},
+};
+
+static struct branch_clk gfx2d0_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(19),
+		.hwcg_reg = AHB_EN2_REG,
+		.hwcg_mask = BIT(28),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(12),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 2,
+	},
+	.c = {
+		.dbg_name = "gfx2d0_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gfx2d0_p_clk.c),
+	},
+};
+
+static struct branch_clk gfx2d1_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(2),
+		.hwcg_reg = AHB_EN2_REG,
+		.hwcg_mask = BIT(29),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(11),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 3,
+	},
+	.c = {
+		.dbg_name = "gfx2d1_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gfx2d1_p_clk.c),
+	},
+};
+
+static struct branch_clk gfx3d_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(3),
+		.hwcg_reg = AHB_EN2_REG,
+		.hwcg_mask = BIT(27),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(10),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 4,
+	},
+	.c = {
+		.dbg_name = "gfx3d_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gfx3d_p_clk.c),
+	},
+};
+
+static struct branch_clk hdmi_m_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(14),
+		.hwcg_reg = AHB_EN2_REG,
+		.hwcg_mask = BIT(21),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(9),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 5,
+	},
+	.c = {
+		.dbg_name = "hdmi_m_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(hdmi_m_p_clk.c),
+	},
+};
+
+static struct branch_clk hdmi_s_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(4),
+		.hwcg_reg = AHB_EN2_REG,
+		.hwcg_mask = BIT(22),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(9),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 6,
+	},
+	.c = {
+		.dbg_name = "hdmi_s_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(hdmi_s_p_clk.c),
+	},
+};
+
+static struct branch_clk ijpeg_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(5),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(7),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 9,
+	},
+	.c = {
+		.dbg_name = "ijpeg_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(ijpeg_p_clk.c),
+	},
+};
+
+static struct branch_clk imem_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(6),
+		.hwcg_reg = AHB_EN2_REG,
+		.hwcg_mask = BIT(12),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(8),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 10,
+	},
+	.c = {
+		.dbg_name = "imem_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(imem_p_clk.c),
+	},
+};
+
+static struct branch_clk jpegd_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(21),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(4),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 7,
+	},
+	.c = {
+		.dbg_name = "jpegd_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(jpegd_p_clk.c),
+	},
+};
+
+static struct branch_clk mdp_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(10),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(3),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 11,
+	},
+	.c = {
+		.dbg_name = "mdp_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdp_p_clk.c),
+	},
+};
+
+static struct branch_clk rot_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(12),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(2),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 13,
+	},
+	.c = {
+		.dbg_name = "rot_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(rot_p_clk.c),
+	},
+};
+
+static struct branch_clk smmu_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(15),
+		.hwcg_reg = AHB_EN_REG,
+		.hwcg_mask = BIT(26),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 22,
+	},
+	.c = {
+		.dbg_name = "smmu_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(smmu_p_clk.c),
+	},
+};
+
+static struct branch_clk tv_enc_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(25),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(15),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 23,
+	},
+	.c = {
+		.dbg_name = "tv_enc_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(tv_enc_p_clk.c),
+	},
+};
+
+static struct branch_clk vcodec_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(11),
+		.hwcg_reg = AHB_EN2_REG,
+		.hwcg_mask = BIT(26),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(1),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 12,
+	},
+	.c = {
+		.dbg_name = "vcodec_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(vcodec_p_clk.c),
+	},
+};
+
+static struct branch_clk vfe_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(13),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(0),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 14,
+		.retain_reg = AHB_EN2_REG,
+		.retain_mask = BIT(0),
+	},
+	.c = {
+		.dbg_name = "vfe_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(vfe_p_clk.c),
+	},
+};
+
+static struct branch_clk vpe_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(16),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(14),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 15,
+	},
+	.c = {
+		.dbg_name = "vpe_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(vpe_p_clk.c),
+	},
+};
+
+static struct branch_clk vcap_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN3_REG,
+		.en_mask = BIT(1),
+		.hwcg_reg = AHB_EN3_REG,
+		.hwcg_mask = BIT(0),
+		.reset_reg = SW_RESET_AHB2_REG,
+		.reset_mask = BIT(2),
+		.halt_reg = DBG_BUS_VEC_J_REG,
+		.halt_bit = 23,
+	},
+	.c = {
+		.dbg_name = "vcap_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(vcap_p_clk.c),
+	},
+};
+
+/*
+ * Peripheral Clocks
+ */
+#define CLK_GP(i, n, h_r, h_b) \
+	struct rcg_clk i##_clk = { \
+		.b = { \
+			.ctl_reg = GPn_NS_REG(n), \
+			.en_mask = BIT(9), \
+			.halt_reg = h_r, \
+			.halt_bit = h_b, \
+		}, \
+		.ns_reg = GPn_NS_REG(n), \
+		.md_reg = GPn_MD_REG(n), \
+		.root_en_mask = BIT(11), \
+		.ns_mask = (BM(23, 16) | BM(6, 0)), \
+		.mnd_en_mask = BIT(8), \
+		.set_rate = set_rate_mnd, \
+		.freq_tbl = clk_tbl_gp, \
+		.current_freq = &rcg_dummy_freq, \
+		.c = { \
+			.dbg_name = #i "_clk", \
+			.ops = &clk_ops_rcg, \
+			VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000), \
+			CLK_INIT(i##_clk.c), \
+		}, \
+	}
+#define F_GP(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD8(16, m, 0, n), \
+		.ns_val = NS(23, 16, n, m, 5, 4, 3, d, 2, 0, s##_to_bb_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_gp[] = {
+	F_GP(        0, gnd,  1, 0, 0),
+	F_GP(  9600000, cxo,  2, 0, 0),
+	F_GP( 13500000, pxo,  2, 0, 0),
+	F_GP( 19200000, cxo,  1, 0, 0),
+	F_GP( 27000000, pxo,  1, 0, 0),
+	F_GP( 64000000, pll8, 2, 1, 3),
+	F_GP( 76800000, pll8, 1, 1, 5),
+	F_GP( 96000000, pll8, 4, 0, 0),
+	F_GP(128000000, pll8, 3, 0, 0),
+	F_GP(192000000, pll8, 2, 0, 0),
+	F_END
+};
+
+static CLK_GP(gp0, 0, CLK_HALT_SFPB_MISC_STATE_REG, 7);
+static CLK_GP(gp1, 1, CLK_HALT_SFPB_MISC_STATE_REG, 6);
+static CLK_GP(gp2, 2, CLK_HALT_SFPB_MISC_STATE_REG, 5);
+
+#define CLK_GSBI_UART(i, n, h_r, h_b) \
+	struct rcg_clk i##_clk = { \
+		.b = { \
+			.ctl_reg = GSBIn_UART_APPS_NS_REG(n), \
+			.en_mask = BIT(9), \
+			.reset_reg = GSBIn_RESET_REG(n), \
+			.reset_mask = BIT(0), \
+			.halt_reg = h_r, \
+			.halt_bit = h_b, \
+		}, \
+		.ns_reg = GSBIn_UART_APPS_NS_REG(n), \
+		.md_reg = GSBIn_UART_APPS_MD_REG(n), \
+		.root_en_mask = BIT(11), \
+		.ns_mask = (BM(31, 16) | BM(6, 0)), \
+		.mnd_en_mask = BIT(8), \
+		.set_rate = set_rate_mnd, \
+		.freq_tbl = clk_tbl_gsbi_uart, \
+		.current_freq = &rcg_dummy_freq, \
+		.c = { \
+			.dbg_name = #i "_clk", \
+			.ops = &clk_ops_rcg, \
+			VDD_DIG_FMAX_MAP2(LOW, 32000000, NOMINAL, 64000000), \
+			CLK_INIT(i##_clk.c), \
+		}, \
+	}
+#define F_GSBI_UART(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD16(m, n), \
+		.ns_val = NS(31, 16, n, m, 5, 4, 3, d, 2, 0, s##_to_bb_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_gsbi_uart[] = {
+	F_GSBI_UART(       0, gnd,  1,  0,   0),
+	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),
+	F_GSBI_UART(40000000, pll8, 1,  5,  48),
+	F_GSBI_UART(46400000, pll8, 1, 29, 240),
+	F_GSBI_UART(48000000, pll8, 4,  1,   2),
+	F_GSBI_UART(51200000, pll8, 1,  2,  15),
+	F_GSBI_UART(56000000, pll8, 1,  7,  48),
+	F_GSBI_UART(58982400, pll8, 1, 96, 625),
+	F_GSBI_UART(64000000, pll8, 2,  1,   3),
+	F_END
+};
+
+static CLK_GSBI_UART(gsbi1_uart,   1, CLK_HALT_CFPB_STATEA_REG, 10);
+static CLK_GSBI_UART(gsbi2_uart,   2, CLK_HALT_CFPB_STATEA_REG,  6);
+static CLK_GSBI_UART(gsbi3_uart,   3, CLK_HALT_CFPB_STATEA_REG,  2);
+static CLK_GSBI_UART(gsbi4_uart,   4, CLK_HALT_CFPB_STATEB_REG, 26);
+static CLK_GSBI_UART(gsbi5_uart,   5, CLK_HALT_CFPB_STATEB_REG, 22);
+static CLK_GSBI_UART(gsbi6_uart,   6, CLK_HALT_CFPB_STATEB_REG, 18);
+static CLK_GSBI_UART(gsbi7_uart,   7, CLK_HALT_CFPB_STATEB_REG, 14);
+static CLK_GSBI_UART(gsbi8_uart,   8, CLK_HALT_CFPB_STATEB_REG, 10);
+static CLK_GSBI_UART(gsbi9_uart,   9, CLK_HALT_CFPB_STATEB_REG,  6);
+static CLK_GSBI_UART(gsbi10_uart, 10, CLK_HALT_CFPB_STATEB_REG,  2);
+static CLK_GSBI_UART(gsbi11_uart, 11, CLK_HALT_CFPB_STATEC_REG, 17);
+static CLK_GSBI_UART(gsbi12_uart, 12, CLK_HALT_CFPB_STATEC_REG, 13);
+
+#define CLK_GSBI_QUP(i, n, h_r, h_b) \
+	struct rcg_clk i##_clk = { \
+		.b = { \
+			.ctl_reg = GSBIn_QUP_APPS_NS_REG(n), \
+			.en_mask = BIT(9), \
+			.reset_reg = GSBIn_RESET_REG(n), \
+			.reset_mask = BIT(0), \
+			.halt_reg = h_r, \
+			.halt_bit = h_b, \
+		}, \
+		.ns_reg = GSBIn_QUP_APPS_NS_REG(n), \
+		.md_reg = GSBIn_QUP_APPS_MD_REG(n), \
+		.root_en_mask = BIT(11), \
+		.ns_mask = (BM(23, 16) | BM(6, 0)), \
+		.mnd_en_mask = BIT(8), \
+		.set_rate = set_rate_mnd, \
+		.freq_tbl = clk_tbl_gsbi_qup, \
+		.current_freq = &rcg_dummy_freq, \
+		.c = { \
+			.dbg_name = #i "_clk", \
+			.ops = &clk_ops_rcg, \
+			VDD_DIG_FMAX_MAP2(LOW, 24000000, NOMINAL, 52000000), \
+			CLK_INIT(i##_clk.c), \
+		}, \
+	}
+#define F_GSBI_QUP(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD8(16, m, 0, n), \
+		.ns_val = NS(23, 16, n, m, 5, 4, 3, d, 2, 0, s##_to_bb_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_gsbi_qup[] = {
+	F_GSBI_QUP(       0, gnd,  1, 0,  0),
+	F_GSBI_QUP( 1100000, pxo,  1, 2, 49),
+	F_GSBI_QUP( 5400000, pxo,  1, 1,  5),
+	F_GSBI_QUP(10800000, pxo,  1, 2,  5),
+	F_GSBI_QUP(15060000, pll8, 1, 2, 51),
+	F_GSBI_QUP(24000000, pll8, 4, 1,  4),
+	F_GSBI_QUP(25600000, pll8, 1, 1, 15),
+	F_GSBI_QUP(27000000, pxo,  1, 0,  0),
+	F_GSBI_QUP(48000000, pll8, 4, 1,  2),
+	F_GSBI_QUP(51200000, pll8, 1, 2, 15),
+	F_END
+};
+
+static CLK_GSBI_QUP(gsbi1_qup,   1, CLK_HALT_CFPB_STATEA_REG,  9);
+static CLK_GSBI_QUP(gsbi2_qup,   2, CLK_HALT_CFPB_STATEA_REG,  4);
+static CLK_GSBI_QUP(gsbi3_qup,   3, CLK_HALT_CFPB_STATEA_REG,  0);
+static CLK_GSBI_QUP(gsbi4_qup,   4, CLK_HALT_CFPB_STATEB_REG, 24);
+static CLK_GSBI_QUP(gsbi5_qup,   5, CLK_HALT_CFPB_STATEB_REG, 20);
+static CLK_GSBI_QUP(gsbi6_qup,   6, CLK_HALT_CFPB_STATEB_REG, 16);
+static CLK_GSBI_QUP(gsbi7_qup,   7, CLK_HALT_CFPB_STATEB_REG, 12);
+static CLK_GSBI_QUP(gsbi8_qup,   8, CLK_HALT_CFPB_STATEB_REG,  8);
+static CLK_GSBI_QUP(gsbi9_qup,   9, CLK_HALT_CFPB_STATEB_REG,  4);
+static CLK_GSBI_QUP(gsbi10_qup, 10, CLK_HALT_CFPB_STATEB_REG,  0);
+static CLK_GSBI_QUP(gsbi11_qup, 11, CLK_HALT_CFPB_STATEC_REG, 15);
+static CLK_GSBI_QUP(gsbi12_qup, 12, CLK_HALT_CFPB_STATEC_REG, 11);
+
+#define F_PDM(f, s, d) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.ns_val = NS_SRC_SEL(1, 0, s##_to_xo_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_pdm[] = {
+	F_PDM(       0, gnd, 1),
+	F_PDM(27000000, pxo, 1),
+	F_END
+};
+
+static struct rcg_clk pdm_clk = {
+	.b = {
+		.ctl_reg = PDM_CLK_NS_REG,
+		.en_mask = BIT(9),
+		.reset_reg = PDM_CLK_NS_REG,
+		.reset_mask = BIT(12),
+		.halt_reg = CLK_HALT_CFPB_STATEC_REG,
+		.halt_bit = 3,
+	},
+	.ns_reg = PDM_CLK_NS_REG,
+	.root_en_mask = BIT(11),
+	.ns_mask = BM(1, 0),
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_pdm,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "pdm_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 27000000),
+		CLK_INIT(pdm_clk.c),
+	},
+};
+
+static struct branch_clk pmem_clk = {
+	.b = {
+		.ctl_reg = PMEM_ACLK_CTL_REG,
+		.en_mask = BIT(4),
+		.hwcg_reg = PMEM_ACLK_CTL_REG,
+		.hwcg_mask = BIT(6),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 20,
+	},
+	.c = {
+		.dbg_name = "pmem_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(pmem_clk.c),
+	},
+};
+
+#define F_PRNG(f, s) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+	}
+static struct clk_freq_tbl clk_tbl_prng_32[] = {
+	F_PRNG(32000000, pll8),
+	F_END
+};
+
+static struct clk_freq_tbl clk_tbl_prng_64[] = {
+	F_PRNG(64000000, pll8),
+	F_END
+};
+
+static struct rcg_clk prng_clk = {
+	.b = {
+		.ctl_reg = SC0_U_CLK_BRANCH_ENA_VOTE_REG,
+		.en_mask = BIT(10),
+		.halt_reg = CLK_HALT_SFPB_MISC_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 10,
+	},
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_prng_32,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "prng_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 32000000, NOMINAL, 64000000),
+		CLK_INIT(prng_clk.c),
+	},
+};
+
+#define CLK_SDC(name, n, h_b, fmax_low, fmax_nom) \
+	struct rcg_clk name = { \
+		.b = { \
+			.ctl_reg = SDCn_APPS_CLK_NS_REG(n), \
+			.en_mask = BIT(9), \
+			.reset_reg = SDCn_RESET_REG(n), \
+			.reset_mask = BIT(0), \
+			.halt_reg = CLK_HALT_DFAB_STATE_REG, \
+			.halt_bit = h_b, \
+		}, \
+		.ns_reg = SDCn_APPS_CLK_NS_REG(n), \
+		.md_reg = SDCn_APPS_CLK_MD_REG(n), \
+		.root_en_mask = BIT(11), \
+		.ns_mask = (BM(23, 16) | BM(6, 0)), \
+		.mnd_en_mask = BIT(8), \
+		.set_rate = set_rate_mnd, \
+		.freq_tbl = clk_tbl_sdc, \
+		.current_freq = &rcg_dummy_freq, \
+		.c = { \
+			.dbg_name = #name, \
+			.ops = &clk_ops_rcg, \
+			VDD_DIG_FMAX_MAP2(LOW, fmax_low, NOMINAL, fmax_nom), \
+			CLK_INIT(name.c), \
+		}, \
+	}
+#define F_SDC(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD8(16, m, 0, n), \
+		.ns_val = NS(23, 16, n, m, 5, 4, 3, d, 2, 0, s##_to_bb_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_sdc[] = {
+	F_SDC(        0, gnd,   1, 0,   0),
+	F_SDC(   144000, pxo,   3, 2, 125),
+	F_SDC(   400000, pll8,  4, 1, 240),
+	F_SDC( 16000000, pll8,  4, 1,   6),
+	F_SDC( 17070000, pll8,  1, 2,  45),
+	F_SDC( 20210000, pll8,  1, 1,  19),
+	F_SDC( 24000000, pll8,  4, 1,   4),
+	F_SDC( 48000000, pll8,  4, 1,   2),
+	F_SDC( 64000000, pll8,  3, 1,   2),
+	F_SDC( 96000000, pll8,  4, 0,   0),
+	F_SDC(192000000, pll8,  2, 0,   0),
+	F_END
+};
+
+static CLK_SDC(sdc1_clk, 1, 6,  52000000, 104000000);
+static CLK_SDC(sdc2_clk, 2, 5,  52000000, 104000000);
+static CLK_SDC(sdc3_clk, 3, 4, 104000000, 208000000);
+static CLK_SDC(sdc4_clk, 4, 3,  33000000,  67000000);
+static CLK_SDC(sdc5_clk, 5, 2,  33000000,  67000000);
+
+#define F_TSIF_REF(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD16(m, n), \
+		.ns_val = NS(31, 16, n, m, 5, 4, 3, d, 2, 0, s##_to_bb_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_tsif_ref[] = {
+	F_TSIF_REF(     0, gnd,  1, 0,   0),
+	F_TSIF_REF(105000, pxo,  1, 1, 256),
+	F_END
+};
+
+static struct rcg_clk tsif_ref_clk = {
+	.b = {
+		.ctl_reg = TSIF_REF_CLK_NS_REG,
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_CFPB_STATEC_REG,
+		.halt_bit = 5,
+	},
+	.ns_reg = TSIF_REF_CLK_NS_REG,
+	.md_reg = TSIF_REF_CLK_MD_REG,
+	.root_en_mask = BIT(11),
+	.ns_mask = (BM(31, 16) | BM(6, 0)),
+	.mnd_en_mask = BIT(8),
+	.set_rate = set_rate_mnd,
+	.freq_tbl = clk_tbl_tsif_ref,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "tsif_ref_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 27000000, NOMINAL, 54000000),
+		CLK_INIT(tsif_ref_clk.c),
+	},
+};
+
+#define F_TSSC(f, s) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.ns_val = NS_SRC_SEL(1, 0, s##_to_xo_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_tssc[] = {
+	F_TSSC(       0, gnd),
+	F_TSSC(27000000, pxo),
+	F_END
+};
+
+static struct rcg_clk tssc_clk = {
+	.b = {
+		.ctl_reg = TSSC_CLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEC_REG,
+		.halt_bit = 4,
+	},
+	.ns_reg = TSSC_CLK_CTL_REG,
+	.ns_mask = BM(1, 0),
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_tssc,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "tssc_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 27000000),
+		CLK_INIT(tssc_clk.c),
+	},
+};
+
+#define CLK_USB_HS(name, n, h_b) \
+	static struct rcg_clk name = { \
+	.b = { \
+		.ctl_reg = USB_HS##n##_XCVR_FS_CLK_NS_REG, \
+		.en_mask = BIT(9), \
+		.reset_reg = USB_HS##n##_RESET_REG, \
+		.reset_mask = BIT(0), \
+		.halt_reg = CLK_HALT_DFAB_STATE_REG, \
+		.halt_bit = h_b, \
+	}, \
+	.ns_reg = USB_HS##n##_XCVR_FS_CLK_NS_REG, \
+	.md_reg = USB_HS##n##_XCVR_FS_CLK_MD_REG, \
+	.root_en_mask = BIT(11), \
+	.ns_mask = (BM(23, 16) | BM(6, 0)), \
+	.mnd_en_mask = BIT(8), \
+	.set_rate = set_rate_mnd, \
+	.freq_tbl = clk_tbl_usb, \
+	.current_freq = &rcg_dummy_freq, \
+	.c = { \
+		.dbg_name = #name, \
+		.ops = &clk_ops_rcg, \
+		VDD_DIG_FMAX_MAP1(NOMINAL, 64000000), \
+		CLK_INIT(name.c), \
+	}, \
+}
+
+#define F_USB(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD8(16, m, 0, n), \
+		.ns_val = NS(23, 16, n, m, 5, 4, 3, d, 2, 0, s##_to_bb_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_usb[] = {
+	F_USB(       0, gnd,  1, 0,  0),
+	F_USB(60000000, pll8, 1, 5, 32),
+	F_END
+};
+
+CLK_USB_HS(usb_hs1_xcvr_clk, 1, 0);
+CLK_USB_HS(usb_hs3_xcvr_clk, 3, 30);
+CLK_USB_HS(usb_hs4_xcvr_clk, 4, 2);
+
+static struct clk_freq_tbl clk_tbl_usb_hsic[] = {
+	F_USB(       0, gnd,  1, 0,  0),
+	F_USB(60000000, pll8, 1, 5, 32),
+	F_END
+};
+
+static struct rcg_clk usb_hsic_xcvr_fs_clk = {
+	.b = {
+		.ctl_reg = USB_HSIC_XCVR_FS_CLK_NS_REG,
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
+		.halt_bit = 26,
+	},
+	.ns_reg = USB_HSIC_XCVR_FS_CLK_NS_REG,
+	.md_reg = USB_HSIC_XCVR_FS_CLK_MD_REG,
+	.root_en_mask = BIT(11),
+	.ns_mask = (BM(23, 16) | BM(6, 0)),
+	.mnd_en_mask = BIT(8),
+	.set_rate = set_rate_mnd,
+	.freq_tbl = clk_tbl_usb_hsic,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "usb_hsic_xcvr_fs_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 60000000),
+		CLK_INIT(usb_hsic_xcvr_fs_clk.c),
+	},
+};
+
+static struct branch_clk usb_hsic_system_clk = {
+	.b = {
+		.ctl_reg = USB_HSIC_SYSTEM_CLK_CTL_REG,
+		.en_mask = BIT(4),
+		.reset_reg = USB_HSIC_RESET_REG,
+		.reset_mask = BIT(0),
+		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
+		.halt_bit = 24,
+	},
+	.parent = &usb_hsic_xcvr_fs_clk.c,
+	.c = {
+		.dbg_name = "usb_hsic_system_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_hsic_system_clk.c),
+	},
+};
+
+#define F_USB_HSIC(f, s) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+	}
+static struct clk_freq_tbl clk_tbl_usb2_hsic[] = {
+	F_USB_HSIC(480000000, pll14),
+	F_END
+};
+
+static struct rcg_clk usb_hsic_hsic_src_clk = {
+	.b = {
+		.ctl_reg = USB_HSIC_HSIC_CLK_SRC_CTL_REG,
+		.halt_check = NOCHECK,
+	},
+	.root_en_mask = BIT(0),
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_usb2_hsic,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "usb_hsic_hsic_src_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 480000000),
+		CLK_INIT(usb_hsic_hsic_src_clk.c),
+	},
+};
+
+static struct branch_clk usb_hsic_hsic_clk = {
+	.b = {
+		.ctl_reg = USB_HSIC_HSIC_CLK_CTL_REG,
+		.en_mask = BIT(0),
+		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
+		.halt_bit = 19,
+	},
+	.parent = &usb_hsic_hsic_src_clk.c,
+	.c = {
+		.dbg_name = "usb_hsic_hsic_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_hsic_hsic_clk.c),
+	},
+};
+
+#define F_USB_HSIO_CAL(f, s) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+	}
+static struct clk_freq_tbl clk_tbl_usb_hsio_cal[] = {
+	F_USB_HSIO_CAL(9000000, pxo),
+	F_END
+};
+
+static struct rcg_clk usb_hsic_hsio_cal_clk = {
+	.b = {
+		.ctl_reg = USB_HSIC_HSIO_CAL_CLK_CTL_REG,
+		.en_mask = BIT(0),
+		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
+		.halt_bit = 23,
+	},
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_usb_hsio_cal,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "usb_hsic_hsio_cal_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 10000000),
+		CLK_INIT(usb_hsic_hsio_cal_clk.c),
+	},
+};
+
+static struct branch_clk usb_phy0_clk = {
+	.b = {
+		.reset_reg = USB_PHY0_RESET_REG,
+		.reset_mask = BIT(0),
+	},
+	.c = {
+		.dbg_name = "usb_phy0_clk",
+		.ops = &clk_ops_reset,
+		CLK_INIT(usb_phy0_clk.c),
+	},
+};
+
+#define CLK_USB_FS(i, n, fmax_nom) \
+	struct rcg_clk i##_clk = { \
+		.ns_reg = USB_FSn_XCVR_FS_CLK_NS_REG(n), \
+		.b = { \
+			.ctl_reg = USB_FSn_XCVR_FS_CLK_NS_REG(n), \
+			.halt_check = NOCHECK, \
+		}, \
+		.md_reg = USB_FSn_XCVR_FS_CLK_MD_REG(n), \
+		.root_en_mask = BIT(11), \
+		.ns_mask = (BM(23, 16) | BM(6, 0)), \
+		.mnd_en_mask = BIT(8), \
+		.set_rate = set_rate_mnd, \
+		.freq_tbl = clk_tbl_usb, \
+		.current_freq = &rcg_dummy_freq, \
+		.c = { \
+			.dbg_name = #i "_clk", \
+			.ops = &clk_ops_rcg, \
+			VDD_DIG_FMAX_MAP1(NOMINAL, fmax_nom), \
+			CLK_INIT(i##_clk.c), \
+		}, \
+	}
+
+static CLK_USB_FS(usb_fs1_src, 1, 64000000);
+static struct branch_clk usb_fs1_xcvr_clk = {
+	.b = {
+		.ctl_reg = USB_FSn_XCVR_FS_CLK_NS_REG(1),
+		.en_mask = BIT(9),
+		.reset_reg = USB_FSn_RESET_REG(1),
+		.reset_mask = BIT(1),
+		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
+		.halt_bit = 15,
+	},
+	.parent = &usb_fs1_src_clk.c,
+	.c = {
+		.dbg_name = "usb_fs1_xcvr_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_fs1_xcvr_clk.c),
+	},
+};
+
+static struct branch_clk usb_fs1_sys_clk = {
+	.b = {
+		.ctl_reg = USB_FSn_SYSTEM_CLK_CTL_REG(1),
+		.en_mask = BIT(4),
+		.reset_reg = USB_FSn_RESET_REG(1),
+		.reset_mask = BIT(0),
+		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
+		.halt_bit = 16,
+	},
+	.parent = &usb_fs1_src_clk.c,
+	.c = {
+		.dbg_name = "usb_fs1_sys_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_fs1_sys_clk.c),
+	},
+};
+
+static CLK_USB_FS(usb_fs2_src, 2, 60000000);
+static struct branch_clk usb_fs2_xcvr_clk = {
+	.b = {
+		.ctl_reg = USB_FSn_XCVR_FS_CLK_NS_REG(2),
+		.en_mask = BIT(9),
+		.reset_reg = USB_FSn_RESET_REG(2),
+		.reset_mask = BIT(1),
+		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
+		.halt_bit = 12,
+	},
+	.parent = &usb_fs2_src_clk.c,
+	.c = {
+		.dbg_name = "usb_fs2_xcvr_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_fs2_xcvr_clk.c),
+	},
+};
+
+static struct branch_clk usb_fs2_sys_clk = {
+	.b = {
+		.ctl_reg = USB_FSn_SYSTEM_CLK_CTL_REG(2),
+		.en_mask = BIT(4),
+		.reset_reg = USB_FSn_RESET_REG(2),
+		.reset_mask = BIT(0),
+		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
+		.halt_bit = 13,
+	},
+	.parent = &usb_fs2_src_clk.c,
+	.c = {
+		.dbg_name = "usb_fs2_sys_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_fs2_sys_clk.c),
+	},
+};
+
+/* Fast Peripheral Bus Clocks */
+static struct branch_clk ce1_core_clk = {
+	.b = {
+		.ctl_reg = CE1_CORE_CLK_CTL_REG,
+		.en_mask = BIT(4),
+		.hwcg_reg = CE1_CORE_CLK_CTL_REG,
+		.hwcg_mask = BIT(6),
+		.halt_reg = CLK_HALT_CFPB_STATEC_REG,
+		.halt_bit = 27,
+	},
+	.c = {
+		.dbg_name = "ce1_core_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(ce1_core_clk.c),
+	},
+};
+
+static struct branch_clk ce1_p_clk = {
+	.b = {
+		.ctl_reg = CE1_HCLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEC_REG,
+		.halt_bit = 1,
+	},
+	.c = {
+		.dbg_name = "ce1_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(ce1_p_clk.c),
+	},
+};
+
+#define F_CE3(f, s, d) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.ns_val = NS_DIVSRC(6, 3, d, 2, 0, s##_to_bb_mux), \
+	}
+
+static struct clk_freq_tbl clk_tbl_ce3[] = {
+	F_CE3(        0, gnd,   1),
+	F_CE3( 48000000, pll8,  8),
+	F_CE3(100000000, pll3, 12),
+	F_END
+};
+
+static struct rcg_clk ce3_src_clk = {
+	.b = {
+		.ctl_reg = CE3_CLK_SRC_NS_REG,
+		.halt_check = NOCHECK,
+	},
+	.ns_reg = CE3_CLK_SRC_NS_REG,
+	.root_en_mask = BIT(7),
+	.ns_mask = BM(6, 0),
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_ce3,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "ce3_src_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 50000000, NOMINAL, 100000000),
+		CLK_INIT(ce3_src_clk.c),
+	},
+};
+
+static struct branch_clk ce3_core_clk = {
+	.b = {
+		.ctl_reg = CE3_CORE_CLK_CTL_REG,
+		.en_mask = BIT(4),
+		.reset_reg = CE3_CORE_CLK_CTL_REG,
+		.reset_mask = BIT(7),
+		.halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
+		.halt_bit = 5,
+	},
+	.parent = &ce3_src_clk.c,
+	.c = {
+		.dbg_name = "ce3_core_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(ce3_core_clk.c),
+	}
+};
+
+static struct branch_clk ce3_p_clk = {
+	.b = {
+		.ctl_reg = CE3_HCLK_CTL_REG,
+		.en_mask = BIT(4),
+		.reset_reg = CE3_HCLK_CTL_REG,
+		.reset_mask = BIT(7),
+		.halt_reg = CLK_HALT_AFAB_SFAB_STATEB_REG,
+		.halt_bit = 16,
+	},
+	.parent = &ce3_src_clk.c,
+	.c = {
+		.dbg_name = "ce3_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(ce3_p_clk.c),
+	}
+};
+
+#define F_SATA(f, s, d) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.ns_val = NS_DIVSRC(6, 3, d, 2, 0, s##_to_bb_mux), \
+	}
+
+static struct clk_freq_tbl clk_tbl_sata[] = {
+	F_SATA(        0,  gnd, 1),
+	F_SATA( 48000000, pll8, 8),
+	F_SATA(100000000, pll3, 12),
+	F_END
+};
+
+static struct rcg_clk sata_src_clk = {
+	.b = {
+		.ctl_reg = SATA_CLK_SRC_NS_REG,
+		.halt_check = NOCHECK,
+	},
+	.ns_reg = SATA_CLK_SRC_NS_REG,
+	.root_en_mask = BIT(7),
+	.ns_mask = BM(6, 0),
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_sata,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "sata_src_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 50000000, NOMINAL, 100000000),
+		CLK_INIT(sata_src_clk.c),
+	},
+};
+
+static struct branch_clk sata_rxoob_clk = {
+	.b = {
+		.ctl_reg = SATA_RXOOB_CLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
+		.halt_bit = 26,
+	},
+	.parent = &sata_src_clk.c,
+	.c = {
+		.dbg_name = "sata_rxoob_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sata_rxoob_clk.c),
+	},
+};
+
+static struct branch_clk sata_pmalive_clk = {
+	.b = {
+		.ctl_reg = SATA_PMALIVE_CLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
+		.halt_bit = 25,
+	},
+	.parent = &sata_src_clk.c,
+	.c = {
+		.dbg_name = "sata_pmalive_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sata_pmalive_clk.c),
+	},
+};
+
+static struct branch_clk sata_phy_ref_clk = {
+	.b = {
+		.ctl_reg = SATA_PHY_REF_CLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
+		.halt_bit = 24,
+	},
+	.parent = &pxo_clk.c,
+	.c = {
+		.dbg_name = "sata_phy_ref_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sata_phy_ref_clk.c),
+	},
+};
+
+static struct branch_clk sata_a_clk = {
+	.b = {
+		.ctl_reg = SATA_ACLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_AFAB_SFAB_STATEA_REG,
+		.halt_bit = 12,
+	},
+	.c = {
+		.dbg_name = "sata_a_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sata_a_clk.c),
+	},
+};
+
+static struct branch_clk sata_p_clk = {
+	.b = {
+		.ctl_reg = SATA_HCLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
+		.halt_bit = 27,
+	},
+	.c = {
+		.dbg_name = "sata_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sata_p_clk.c),
+	},
+};
+
+static struct branch_clk sfab_sata_s_p_clk = {
+	.b = {
+		.ctl_reg = SFAB_SATA_S_HCLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_AFAB_SFAB_STATEB_REG,
+		.halt_bit = 14,
+	},
+	.c = {
+		.dbg_name = "sfab_sata_s_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sfab_sata_s_p_clk.c),
+	},
+};
+static struct branch_clk pcie_p_clk = {
+	.b = {
+		.ctl_reg = PCIE_HCLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEC_REG,
+		.halt_bit = 8,
+	},
+	.c = {
+		.dbg_name = "pcie_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(pcie_p_clk.c),
+	},
+};
+
+static struct branch_clk pcie_phy_ref_clk = {
+	.b = {
+		.ctl_reg = PCIE_PCLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
+		.halt_bit = 29,
+	},
+	.c = {
+		.dbg_name = "pcie_phy_ref_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(pcie_phy_ref_clk.c),
+	},
+};
+
+static struct branch_clk pcie_a_clk = {
+	.b = {
+		.ctl_reg = PCIE_ACLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_AFAB_SFAB_STATEA_REG,
+		.halt_bit = 13,
+	},
+	.c = {
+		.dbg_name = "pcie_a_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(pcie_a_clk.c),
+	},
+};
+
+static struct branch_clk dma_bam_p_clk = {
+	.b = {
+		.ctl_reg = DMA_BAM_HCLK_CTL,
+		.en_mask = BIT(4),
+		.hwcg_reg = DMA_BAM_HCLK_CTL,
+		.hwcg_mask = BIT(6),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 12,
+	},
+	.c = {
+		.dbg_name = "dma_bam_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(dma_bam_p_clk.c),
+	},
+};
+
+static struct branch_clk gsbi1_p_clk = {
+	.b = {
+		.ctl_reg = GSBIn_HCLK_CTL_REG(1),
+		.en_mask = BIT(4),
+		.hwcg_reg = GSBIn_HCLK_CTL_REG(1),
+		.hwcg_mask = BIT(6),
+		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
+		.halt_bit = 11,
+	},
+	.c = {
+		.dbg_name = "gsbi1_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gsbi1_p_clk.c),
+	},
+};
+
+static struct branch_clk gsbi2_p_clk = {
+	.b = {
+		.ctl_reg = GSBIn_HCLK_CTL_REG(2),
+		.en_mask = BIT(4),
+		.hwcg_reg = GSBIn_HCLK_CTL_REG(2),
+		.hwcg_mask = BIT(6),
+		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
+		.halt_bit = 7,
+	},
+	.c = {
+		.dbg_name = "gsbi2_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gsbi2_p_clk.c),
+	},
+};
+
+static struct branch_clk gsbi3_p_clk = {
+	.b = {
+		.ctl_reg = GSBIn_HCLK_CTL_REG(3),
+		.en_mask = BIT(4),
+		.hwcg_reg = GSBIn_HCLK_CTL_REG(3),
+		.hwcg_mask = BIT(6),
+		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
+		.halt_bit = 3,
+	},
+	.c = {
+		.dbg_name = "gsbi3_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gsbi3_p_clk.c),
+	},
+};
+
+static struct branch_clk gsbi4_p_clk = {
+	.b = {
+		.ctl_reg = GSBIn_HCLK_CTL_REG(4),
+		.en_mask = BIT(4),
+		.hwcg_reg = GSBIn_HCLK_CTL_REG(4),
+		.hwcg_mask = BIT(6),
+		.halt_reg = CLK_HALT_CFPB_STATEB_REG,
+		.halt_bit = 27,
+	},
+	.c = {
+		.dbg_name = "gsbi4_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gsbi4_p_clk.c),
+	},
+};
+
+static struct branch_clk gsbi5_p_clk = {
+	.b = {
+		.ctl_reg = GSBIn_HCLK_CTL_REG(5),
+		.en_mask = BIT(4),
+		.hwcg_reg = GSBIn_HCLK_CTL_REG(5),
+		.hwcg_mask = BIT(6),
+		.halt_reg = CLK_HALT_CFPB_STATEB_REG,
+		.halt_bit = 23,
+	},
+	.c = {
+		.dbg_name = "gsbi5_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gsbi5_p_clk.c),
+	},
+};
+
+static struct branch_clk gsbi6_p_clk = {
+	.b = {
+		.ctl_reg = GSBIn_HCLK_CTL_REG(6),
+		.en_mask = BIT(4),
+		.hwcg_reg = GSBIn_HCLK_CTL_REG(6),
+		.hwcg_mask = BIT(6),
+		.halt_reg = CLK_HALT_CFPB_STATEB_REG,
+		.halt_bit = 19,
+	},
+	.c = {
+		.dbg_name = "gsbi6_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gsbi6_p_clk.c),
+	},
+};
+
+static struct branch_clk gsbi7_p_clk = {
+	.b = {
+		.ctl_reg = GSBIn_HCLK_CTL_REG(7),
+		.en_mask = BIT(4),
+		.hwcg_reg = GSBIn_HCLK_CTL_REG(7),
+		.hwcg_mask = BIT(6),
+		.halt_reg = CLK_HALT_CFPB_STATEB_REG,
+		.halt_bit = 15,
+	},
+	.c = {
+		.dbg_name = "gsbi7_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gsbi7_p_clk.c),
+	},
+};
+
+static struct branch_clk gsbi8_p_clk = {
+	.b = {
+		.ctl_reg = GSBIn_HCLK_CTL_REG(8),
+		.en_mask = BIT(4),
+		.hwcg_reg = GSBIn_HCLK_CTL_REG(8),
+		.hwcg_mask = BIT(6),
+		.halt_reg = CLK_HALT_CFPB_STATEB_REG,
+		.halt_bit = 11,
+	},
+	.c = {
+		.dbg_name = "gsbi8_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gsbi8_p_clk.c),
+	},
+};
+
+static struct branch_clk gsbi9_p_clk = {
+	.b = {
+		.ctl_reg = GSBIn_HCLK_CTL_REG(9),
+		.en_mask = BIT(4),
+		.hwcg_reg = GSBIn_HCLK_CTL_REG(9),
+		.hwcg_mask = BIT(6),
+		.halt_reg = CLK_HALT_CFPB_STATEB_REG,
+		.halt_bit = 7,
+	},
+	.c = {
+		.dbg_name = "gsbi9_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gsbi9_p_clk.c),
+	},
+};
+
+static struct branch_clk gsbi10_p_clk = {
+	.b = {
+		.ctl_reg = GSBIn_HCLK_CTL_REG(10),
+		.en_mask = BIT(4),
+		.hwcg_reg = GSBIn_HCLK_CTL_REG(10),
+		.hwcg_mask = BIT(6),
+		.halt_reg = CLK_HALT_CFPB_STATEB_REG,
+		.halt_bit = 3,
+	},
+	.c = {
+		.dbg_name = "gsbi10_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gsbi10_p_clk.c),
+	},
+};
+
+static struct branch_clk gsbi11_p_clk = {
+	.b = {
+		.ctl_reg = GSBIn_HCLK_CTL_REG(11),
+		.en_mask = BIT(4),
+		.hwcg_reg = GSBIn_HCLK_CTL_REG(11),
+		.hwcg_mask = BIT(6),
+		.halt_reg = CLK_HALT_CFPB_STATEC_REG,
+		.halt_bit = 18,
+	},
+	.c = {
+		.dbg_name = "gsbi11_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gsbi11_p_clk.c),
+	},
+};
+
+static struct branch_clk gsbi12_p_clk = {
+	.b = {
+		.ctl_reg = GSBIn_HCLK_CTL_REG(12),
+		.en_mask = BIT(4),
+		.hwcg_reg = GSBIn_HCLK_CTL_REG(12),
+		.hwcg_mask = BIT(6),
+		.halt_reg = CLK_HALT_CFPB_STATEC_REG,
+		.halt_bit = 14,
+	},
+	.c = {
+		.dbg_name = "gsbi12_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gsbi12_p_clk.c),
+	},
+};
+
+static struct branch_clk sata_phy_cfg_clk = {
+	.b = {
+		.ctl_reg = SATA_PHY_CFG_CLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
+		.halt_bit = 12,
+	},
+	.c = {
+		.dbg_name = "sata_phy_cfg_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sata_phy_cfg_clk.c),
+	},
+};
+
+static struct branch_clk tsif_p_clk = {
+	.b = {
+		.ctl_reg = TSIF_HCLK_CTL_REG,
+		.en_mask = BIT(4),
+		.hwcg_reg = TSIF_HCLK_CTL_REG,
+		.hwcg_mask = BIT(6),
+		.halt_reg = CLK_HALT_CFPB_STATEC_REG,
+		.halt_bit = 7,
+	},
+	.c = {
+		.dbg_name = "tsif_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(tsif_p_clk.c),
+	},
+};
+
+static struct branch_clk usb_fs1_p_clk = {
+	.b = {
+		.ctl_reg = USB_FSn_HCLK_CTL_REG(1),
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
+		.halt_bit = 17,
+	},
+	.c = {
+		.dbg_name = "usb_fs1_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_fs1_p_clk.c),
+	},
+};
+
+static struct branch_clk usb_fs2_p_clk = {
+	.b = {
+		.ctl_reg = USB_FSn_HCLK_CTL_REG(2),
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
+		.halt_bit = 14,
+	},
+	.c = {
+		.dbg_name = "usb_fs2_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_fs2_p_clk.c),
+	},
+};
+
+static struct branch_clk usb_hs1_p_clk = {
+	.b = {
+		.ctl_reg = USB_HS1_HCLK_CTL_REG,
+		.en_mask = BIT(4),
+		.hwcg_reg = USB_HS1_HCLK_CTL_REG,
+		.hwcg_mask = BIT(6),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 1,
+	},
+	.c = {
+		.dbg_name = "usb_hs1_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_hs1_p_clk.c),
+	},
+};
+
+static struct branch_clk usb_hs3_p_clk = {
+	.b = {
+		.ctl_reg = USB_HS3_HCLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 31,
+	},
+	.c = {
+		.dbg_name = "usb_hs3_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_hs3_p_clk.c),
+	},
+};
+
+static struct branch_clk usb_hs4_p_clk = {
+	.b = {
+		.ctl_reg = USB_HS4_HCLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 7,
+	},
+	.c = {
+		.dbg_name = "usb_hs4_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_hs4_p_clk.c),
+	},
+};
+
+static struct branch_clk usb_hsic_p_clk = {
+	.b = {
+		.ctl_reg = USB_HSIC_HCLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
+		.halt_bit = 28,
+	},
+	.c = {
+		.dbg_name = "usb_hsic_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_hsic_p_clk.c),
+	},
+};
+
+static struct branch_clk sdc1_p_clk = {
+	.b = {
+		.ctl_reg = SDCn_HCLK_CTL_REG(1),
+		.en_mask = BIT(4),
+		.hwcg_reg = SDCn_HCLK_CTL_REG(1),
+		.hwcg_mask = BIT(6),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 11,
+	},
+	.c = {
+		.dbg_name = "sdc1_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sdc1_p_clk.c),
+	},
+};
+
+static struct branch_clk sdc2_p_clk = {
+	.b = {
+		.ctl_reg = SDCn_HCLK_CTL_REG(2),
+		.en_mask = BIT(4),
+		.hwcg_reg = SDCn_HCLK_CTL_REG(2),
+		.hwcg_mask = BIT(6),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 10,
+	},
+	.c = {
+		.dbg_name = "sdc2_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sdc2_p_clk.c),
+	},
+};
+
+static struct branch_clk sdc3_p_clk = {
+	.b = {
+		.ctl_reg = SDCn_HCLK_CTL_REG(3),
+		.en_mask = BIT(4),
+		.hwcg_reg = SDCn_HCLK_CTL_REG(3),
+		.hwcg_mask = BIT(6),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 9,
+	},
+	.c = {
+		.dbg_name = "sdc3_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sdc3_p_clk.c),
+	},
+};
+
+static struct branch_clk sdc4_p_clk = {
+	.b = {
+		.ctl_reg = SDCn_HCLK_CTL_REG(4),
+		.en_mask = BIT(4),
+		.hwcg_reg = SDCn_HCLK_CTL_REG(4),
+		.hwcg_mask = BIT(6),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 8,
+	},
+	.c = {
+		.dbg_name = "sdc4_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sdc4_p_clk.c),
+	},
+};
+
+static struct branch_clk sdc5_p_clk = {
+	.b = {
+		.ctl_reg = SDCn_HCLK_CTL_REG(5),
+		.en_mask = BIT(4),
+		.hwcg_reg = SDCn_HCLK_CTL_REG(5),
+		.hwcg_mask = BIT(6),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 7,
+	},
+	.c = {
+		.dbg_name = "sdc5_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sdc5_p_clk.c),
+	},
+};
+
+/* HW-Voteable Clocks */
+static struct branch_clk adm0_clk = {
+	.b = {
+		.ctl_reg = SC0_U_CLK_BRANCH_ENA_VOTE_REG,
+		.en_mask = BIT(2),
+		.halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 14,
+	},
+	.c = {
+		.dbg_name = "adm0_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(adm0_clk.c),
+	},
+};
+
+static struct branch_clk adm0_p_clk = {
+	.b = {
+		.ctl_reg = SC0_U_CLK_BRANCH_ENA_VOTE_REG,
+		.en_mask = BIT(3),
+		.hwcg_reg = ADM0_PBUS_CLK_CTL_REG,
+		.hwcg_mask = BIT(6),
+		.halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 13,
+	},
+	.c = {
+		.dbg_name = "adm0_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(adm0_p_clk.c),
+	},
+};
+
+static struct branch_clk pmic_arb0_p_clk = {
+	.b = {
+		.ctl_reg = SC0_U_CLK_BRANCH_ENA_VOTE_REG,
+		.en_mask = BIT(8),
+		.halt_reg = CLK_HALT_SFPB_MISC_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 22,
+	},
+	.c = {
+		.dbg_name = "pmic_arb0_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(pmic_arb0_p_clk.c),
+	},
+};
+
+static struct branch_clk pmic_arb1_p_clk = {
+	.b = {
+		.ctl_reg = SC0_U_CLK_BRANCH_ENA_VOTE_REG,
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_SFPB_MISC_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 21,
+	},
+	.c = {
+		.dbg_name = "pmic_arb1_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(pmic_arb1_p_clk.c),
+	},
+};
+
+static struct branch_clk pmic_ssbi2_clk = {
+	.b = {
+		.ctl_reg = SC0_U_CLK_BRANCH_ENA_VOTE_REG,
+		.en_mask = BIT(7),
+		.halt_reg = CLK_HALT_SFPB_MISC_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 23,
+	},
+	.c = {
+		.dbg_name = "pmic_ssbi2_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(pmic_ssbi2_clk.c),
+	},
+};
+
+static struct branch_clk rpm_msg_ram_p_clk = {
+	.b = {
+		.ctl_reg = SC0_U_CLK_BRANCH_ENA_VOTE_REG,
+		.en_mask = BIT(6),
+		.hwcg_reg = RPM_MSG_RAM_HCLK_CTL_REG,
+		.hwcg_mask = BIT(6),
+		.halt_reg = CLK_HALT_SFPB_MISC_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 12,
+	},
+	.c = {
+		.dbg_name = "rpm_msg_ram_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(rpm_msg_ram_p_clk.c),
+	},
+};
+
+/*
+ * Multimedia Clocks
+ */
+
+#define CLK_CAM(name, n, hb) \
+	struct rcg_clk name = { \
+		.b = { \
+			.ctl_reg = CAMCLK##n##_CC_REG, \
+			.en_mask = BIT(0), \
+			.halt_reg = DBG_BUS_VEC_I_REG, \
+			.halt_bit = hb, \
+		}, \
+		.ns_reg = CAMCLK##n##_NS_REG, \
+		.md_reg = CAMCLK##n##_MD_REG, \
+		.root_en_mask = BIT(2), \
+		.ns_mask = BM(31, 24) | BM(15, 14) | BM(2, 0), \
+		.mnd_en_mask = BIT(5), \
+		.ctl_mask = BM(7, 6), \
+		.set_rate = set_rate_mnd_8, \
+		.freq_tbl = clk_tbl_cam, \
+		.current_freq = &rcg_dummy_freq, \
+		.c = { \
+			.dbg_name = #name, \
+			.ops = &clk_ops_rcg, \
+			VDD_DIG_FMAX_MAP2(LOW, 64000000, NOMINAL, 128000000), \
+			CLK_INIT(name.c), \
+		}, \
+	}
+#define F_CAM(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD8(8, m, 0, n), \
+		.ns_val = NS_MM(31, 24, n, m, 15, 14, d, 2, 0, s##_to_mm_mux), \
+		.ctl_val = CC(6, n), \
+	}
+static struct clk_freq_tbl clk_tbl_cam[] = {
+	F_CAM(        0, gnd,  1, 0,  0),
+	F_CAM(  6000000, pll8, 4, 1, 16),
+	F_CAM(  8000000, pll8, 4, 1, 12),
+	F_CAM( 12000000, pll8, 4, 1,  8),
+	F_CAM( 16000000, pll8, 4, 1,  6),
+	F_CAM( 19200000, pll8, 4, 1,  5),
+	F_CAM( 24000000, pll8, 4, 1,  4),
+	F_CAM( 32000000, pll8, 4, 1,  3),
+	F_CAM( 48000000, pll8, 4, 1,  2),
+	F_CAM( 64000000, pll8, 3, 1,  2),
+	F_CAM( 96000000, pll8, 4, 0,  0),
+	F_CAM(128000000, pll8, 3, 0,  0),
+	F_END
+};
+
+static CLK_CAM(cam0_clk, 0, 15);
+static CLK_CAM(cam1_clk, 1, 16);
+static CLK_CAM(cam2_clk, 2, 31);
+
+#define F_CSI(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD8(8, m, 0, n), \
+		.ns_val = NS_MM(31, 24, n, m, 15, 14, d, 2, 0, s##_to_mm_mux), \
+		.ctl_val = CC(6, n), \
+	}
+static struct clk_freq_tbl clk_tbl_csi[] = {
+	F_CSI(        0, gnd,  1, 0, 0),
+	F_CSI( 27000000, pxo,  1, 0, 0),
+	F_CSI( 85330000, pll8, 1, 2, 9),
+	F_CSI(177780000, pll2, 1, 2, 9),
+	F_END
+};
+
+static struct rcg_clk csi0_src_clk = {
+	.ns_reg = CSI0_NS_REG,
+	.b = {
+		.ctl_reg = CSI0_CC_REG,
+		.halt_check = NOCHECK,
+	},
+	.md_reg	= CSI0_MD_REG,
+	.root_en_mask = BIT(2),
+	.ns_mask = BM(31, 24) | BM(15, 14) | BM(2, 0),
+	.mnd_en_mask = BIT(5),
+	.ctl_mask = BM(7, 6),
+	.set_rate = set_rate_mnd,
+	.freq_tbl = clk_tbl_csi,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "csi0_src_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 86000000, NOMINAL, 178000000),
+		CLK_INIT(csi0_src_clk.c),
+	},
+};
+
+static struct branch_clk csi0_clk = {
+	.b = {
+		.ctl_reg = CSI0_CC_REG,
+		.en_mask = BIT(0),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(8),
+		.halt_reg = DBG_BUS_VEC_B_REG,
+		.halt_bit = 13,
+	},
+	.parent = &csi0_src_clk.c,
+	.c = {
+		.dbg_name = "csi0_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi0_clk.c),
+	},
+};
+
+static struct branch_clk csi0_phy_clk = {
+	.b = {
+		.ctl_reg = CSI0_CC_REG,
+		.en_mask = BIT(8),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(29),
+		.halt_reg = DBG_BUS_VEC_I_REG,
+		.halt_bit = 9,
+	},
+	.parent = &csi0_src_clk.c,
+	.c = {
+		.dbg_name = "csi0_phy_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi0_phy_clk.c),
+	},
+};
+
+static struct rcg_clk csi1_src_clk = {
+	.ns_reg = CSI1_NS_REG,
+	.b = {
+		.ctl_reg = CSI1_CC_REG,
+		.halt_check = NOCHECK,
+	},
+	.md_reg	= CSI1_MD_REG,
+	.root_en_mask = BIT(2),
+	.ns_mask = BM(31, 24) | BM(15, 14) | BM(2, 0),
+	.mnd_en_mask = BIT(5),
+	.ctl_mask = BM(7, 6),
+	.set_rate = set_rate_mnd,
+	.freq_tbl = clk_tbl_csi,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "csi1_src_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 86000000, NOMINAL, 178000000),
+		CLK_INIT(csi1_src_clk.c),
+	},
+};
+
+static struct branch_clk csi1_clk = {
+	.b = {
+		.ctl_reg = CSI1_CC_REG,
+		.en_mask = BIT(0),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(18),
+		.halt_reg = DBG_BUS_VEC_B_REG,
+		.halt_bit = 14,
+	},
+	.parent = &csi1_src_clk.c,
+	.c = {
+		.dbg_name = "csi1_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi1_clk.c),
+	},
+};
+
+static struct branch_clk csi1_phy_clk = {
+	.b = {
+		.ctl_reg = CSI1_CC_REG,
+		.en_mask = BIT(8),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(28),
+		.halt_reg = DBG_BUS_VEC_I_REG,
+		.halt_bit = 10,
+	},
+	.parent = &csi1_src_clk.c,
+	.c = {
+		.dbg_name = "csi1_phy_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi1_phy_clk.c),
+	},
+};
+
+static struct rcg_clk csi2_src_clk = {
+	.ns_reg = CSI2_NS_REG,
+	.b = {
+		.ctl_reg = CSI2_CC_REG,
+		.halt_check = NOCHECK,
+	},
+	.md_reg = CSI2_MD_REG,
+	.root_en_mask = BIT(2),
+	.ns_mask = BM(31, 24) | BM(15, 14) | BM(2, 0),
+	.mnd_en_mask = BIT(5),
+	.ctl_mask = BM(7, 6),
+	.set_rate = set_rate_mnd,
+	.freq_tbl = clk_tbl_csi,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "csi2_src_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 86000000, NOMINAL, 178000000),
+		CLK_INIT(csi2_src_clk.c),
+	},
+};
+
+static struct branch_clk csi2_clk = {
+	.b = {
+		.ctl_reg = CSI2_CC_REG,
+		.en_mask = BIT(0),
+		.reset_reg = SW_RESET_CORE2_REG,
+		.reset_mask = BIT(2),
+		.halt_reg = DBG_BUS_VEC_B_REG,
+		.halt_bit = 29,
+	},
+	.parent = &csi2_src_clk.c,
+	.c = {
+		.dbg_name = "csi2_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi2_clk.c),
+	},
+};
+
+static struct branch_clk csi2_phy_clk = {
+	.b = {
+		.ctl_reg = CSI2_CC_REG,
+		.en_mask = BIT(8),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(31),
+		.halt_reg = DBG_BUS_VEC_I_REG,
+		.halt_bit = 29,
+	},
+	.parent = &csi2_src_clk.c,
+	.c = {
+		.dbg_name = "csi2_phy_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi2_phy_clk.c),
+	},
+};
+
+static struct clk *pix_rdi_mux_map[] = {
+	[0] = &csi0_clk.c,
+	[1] = &csi1_clk.c,
+	[2] = &csi2_clk.c,
+	NULL,
+};
+
+struct pix_rdi_clk {
+	bool enabled;
+	unsigned long cur_rate;
+
+	void __iomem *const s_reg;
+	u32 s_mask;
+
+	void __iomem *const s2_reg;
+	u32 s2_mask;
+
+	struct branch b;
+	struct clk c;
+};
+
+static inline struct pix_rdi_clk *to_pix_rdi_clk(struct clk *clk)
+{
+	return container_of(clk, struct pix_rdi_clk, c);
+}
+
+static int pix_rdi_clk_set_rate(struct clk *c, unsigned long rate)
+{
+	int ret, i;
+	u32 reg;
+	unsigned long flags;
+	struct pix_rdi_clk *clk = to_pix_rdi_clk(c);
+	struct clk **mux_map = pix_rdi_mux_map;
+
+	/*
+	 * These clocks select three inputs via two muxes. One mux selects
+	 * between csi0 and csi1 and the second mux selects between that mux's
+	 * output and csi2. The source and destination selections for each
+	 * mux must be clocking for the switch to succeed so just turn on
+	 * all three sources because it's easier than figuring out what source
+	 * needs to be on at what time.
+	 */
+	for (i = 0; mux_map[i]; i++) {
+		ret = clk_enable(mux_map[i]);
+		if (ret)
+			goto err;
+	}
+	if (rate >= i) {
+		ret = -EINVAL;
+		goto err;
+	}
+	/* Keep the new source on when switching inputs of an enabled clock */
+	if (clk->enabled) {
+		clk_disable(mux_map[clk->cur_rate]);
+		clk_enable(mux_map[rate]);
+	}
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	reg = readl_relaxed(clk->s2_reg);
+	reg &= ~clk->s2_mask;
+	reg |= rate == 2 ? clk->s2_mask : 0;
+	writel_relaxed(reg, clk->s2_reg);
+	/*
+	 * Wait at least 6 cycles of slowest clock
+	 * for the glitch-free MUX to fully switch sources.
+	 */
+	mb();
+	udelay(1);
+	reg = readl_relaxed(clk->s_reg);
+	reg &= ~clk->s_mask;
+	reg |= rate == 1 ? clk->s_mask : 0;
+	writel_relaxed(reg, clk->s_reg);
+	/*
+	 * Wait at least 6 cycles of slowest clock
+	 * for the glitch-free MUX to fully switch sources.
+	 */
+	mb();
+	udelay(1);
+	clk->cur_rate = rate;
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+err:
+	for (i--; i >= 0; i--)
+		clk_disable(mux_map[i]);
+
+	return 0;
+}
+
+static unsigned long pix_rdi_clk_get_rate(struct clk *c)
+{
+	return to_pix_rdi_clk(c)->cur_rate;
+}
+
+static int pix_rdi_clk_enable(struct clk *c)
+{
+	unsigned long flags;
+	struct pix_rdi_clk *clk = to_pix_rdi_clk(c);
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	__branch_clk_enable_reg(&clk->b, clk->c.dbg_name);
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+	clk->enabled = true;
+
+	return 0;
+}
+
+static void pix_rdi_clk_disable(struct clk *c)
+{
+	unsigned long flags;
+	struct pix_rdi_clk *clk = to_pix_rdi_clk(c);
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	__branch_clk_disable_reg(&clk->b, clk->c.dbg_name);
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+	clk->enabled = false;
+}
+
+static int pix_rdi_clk_reset(struct clk *clk, enum clk_reset_action action)
+{
+	return branch_reset(&to_pix_rdi_clk(clk)->b, action);
+}
+
+static struct clk *pix_rdi_clk_get_parent(struct clk *c)
+{
+	struct pix_rdi_clk *clk = to_pix_rdi_clk(c);
+
+	return pix_rdi_mux_map[clk->cur_rate];
+}
+
+static int pix_rdi_clk_list_rate(struct clk *c, unsigned n)
+{
+	if (pix_rdi_mux_map[n])
+		return n;
+	return -ENXIO;
+}
+
+static enum handoff pix_rdi_clk_handoff(struct clk *c)
+{
+	u32 reg;
+	struct pix_rdi_clk *clk = to_pix_rdi_clk(c);
+	enum handoff ret;
+
+	ret = branch_handoff(&clk->b, &clk->c);
+	if (ret == HANDOFF_DISABLED_CLK)
+		return ret;
+
+	reg = readl_relaxed(clk->s_reg);
+	clk->cur_rate = reg & clk->s_mask ? 1 : 0;
+	reg = readl_relaxed(clk->s2_reg);
+	clk->cur_rate = reg & clk->s2_mask ? 2 : clk->cur_rate;
+
+	return HANDOFF_ENABLED_CLK;
+}
+
+static struct clk_ops clk_ops_pix_rdi_8960 = {
+	.enable = pix_rdi_clk_enable,
+	.disable = pix_rdi_clk_disable,
+	.auto_off = pix_rdi_clk_disable,
+	.handoff = pix_rdi_clk_handoff,
+	.set_rate = pix_rdi_clk_set_rate,
+	.get_rate = pix_rdi_clk_get_rate,
+	.list_rate = pix_rdi_clk_list_rate,
+	.reset = pix_rdi_clk_reset,
+	.get_parent = pix_rdi_clk_get_parent,
+};
+
+static struct pix_rdi_clk csi_pix_clk = {
+	.b = {
+		.ctl_reg = MISC_CC_REG,
+		.en_mask = BIT(26),
+		.halt_check = DELAY,
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(26),
+	},
+	.s_reg = MISC_CC_REG,
+	.s_mask = BIT(25),
+	.s2_reg = MISC_CC3_REG,
+	.s2_mask = BIT(13),
+	.c = {
+		.dbg_name = "csi_pix_clk",
+		.ops = &clk_ops_pix_rdi_8960,
+		CLK_INIT(csi_pix_clk.c),
+	},
+};
+
+static struct pix_rdi_clk csi_pix1_clk = {
+	.b = {
+		.ctl_reg = MISC_CC3_REG,
+		.en_mask = BIT(10),
+		.halt_check = DELAY,
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(30),
+	},
+	.s_reg = MISC_CC3_REG,
+	.s_mask = BIT(8),
+	.s2_reg = MISC_CC3_REG,
+	.s2_mask = BIT(9),
+	.c = {
+		.dbg_name = "csi_pix1_clk",
+		.ops = &clk_ops_pix_rdi_8960,
+		CLK_INIT(csi_pix1_clk.c),
+	},
+};
+
+static struct pix_rdi_clk csi_rdi_clk = {
+	.b = {
+		.ctl_reg = MISC_CC_REG,
+		.en_mask = BIT(13),
+		.halt_check = DELAY,
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(27),
+	},
+	.s_reg = MISC_CC_REG,
+	.s_mask = BIT(12),
+	.s2_reg = MISC_CC3_REG,
+	.s2_mask = BIT(12),
+	.c = {
+		.dbg_name = "csi_rdi_clk",
+		.ops = &clk_ops_pix_rdi_8960,
+		CLK_INIT(csi_rdi_clk.c),
+	},
+};
+
+static struct pix_rdi_clk csi_rdi1_clk = {
+	.b = {
+		.ctl_reg = MISC_CC3_REG,
+		.en_mask = BIT(2),
+		.halt_check = DELAY,
+		.reset_reg = SW_RESET_CORE2_REG,
+		.reset_mask = BIT(1),
+	},
+	.s_reg = MISC_CC3_REG,
+	.s_mask = BIT(0),
+	.s2_reg = MISC_CC3_REG,
+	.s2_mask = BIT(1),
+	.c = {
+		.dbg_name = "csi_rdi1_clk",
+		.ops = &clk_ops_pix_rdi_8960,
+		CLK_INIT(csi_rdi1_clk.c),
+	},
+};
+
+static struct pix_rdi_clk csi_rdi2_clk = {
+	.b = {
+		.ctl_reg = MISC_CC3_REG,
+		.en_mask = BIT(6),
+		.halt_check = DELAY,
+		.reset_reg = SW_RESET_CORE2_REG,
+		.reset_mask = BIT(0),
+	},
+	.s_reg = MISC_CC3_REG,
+	.s_mask = BIT(4),
+	.s2_reg = MISC_CC3_REG,
+	.s2_mask = BIT(5),
+	.c = {
+		.dbg_name = "csi_rdi2_clk",
+		.ops = &clk_ops_pix_rdi_8960,
+		CLK_INIT(csi_rdi2_clk.c),
+	},
+};
+
+#define F_CSI_PHYTIMER(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD8(8, m, 0, n), \
+		.ns_val = NS_MM(31, 24, n, m, 15, 14, d, 2, 0, s##_to_mm_mux), \
+		.ctl_val = CC(6, n), \
+	}
+static struct clk_freq_tbl clk_tbl_csi_phytimer[] = {
+	F_CSI_PHYTIMER(        0, gnd,  1, 0, 0),
+	F_CSI_PHYTIMER( 85330000, pll8, 1, 2, 9),
+	F_CSI_PHYTIMER(177780000, pll2, 1, 2, 9),
+	F_END
+};
+
+static struct rcg_clk csiphy_timer_src_clk = {
+	.ns_reg = CSIPHYTIMER_NS_REG,
+	.b = {
+		.ctl_reg = CSIPHYTIMER_CC_REG,
+		.halt_check = NOCHECK,
+	},
+	.md_reg = CSIPHYTIMER_MD_REG,
+	.root_en_mask = BIT(2),
+	.ns_mask = (BM(31, 24) | BM(15, 14) | BM(2, 0)),
+	.mnd_en_mask = BIT(5),
+	.ctl_mask = BM(7, 6),
+	.set_rate = set_rate_mnd_8,
+	.freq_tbl = clk_tbl_csi_phytimer,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "csiphy_timer_src_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 86000000, NOMINAL, 178000000),
+		CLK_INIT(csiphy_timer_src_clk.c),
+	},
+};
+
+static struct branch_clk csi0phy_timer_clk = {
+	.b = {
+		.ctl_reg = CSIPHYTIMER_CC_REG,
+		.en_mask = BIT(0),
+		.halt_reg = DBG_BUS_VEC_I_REG,
+		.halt_bit = 17,
+	},
+	.parent = &csiphy_timer_src_clk.c,
+	.c = {
+		.dbg_name = "csi0phy_timer_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi0phy_timer_clk.c),
+	},
+};
+
+static struct branch_clk csi1phy_timer_clk = {
+	.b = {
+		.ctl_reg = CSIPHYTIMER_CC_REG,
+		.en_mask = BIT(9),
+		.halt_reg = DBG_BUS_VEC_I_REG,
+		.halt_bit = 18,
+	},
+	.parent = &csiphy_timer_src_clk.c,
+	.c = {
+		.dbg_name = "csi1phy_timer_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi1phy_timer_clk.c),
+	},
+};
+
+static struct branch_clk csi2phy_timer_clk = {
+	.b = {
+		.ctl_reg = CSIPHYTIMER_CC_REG,
+		.en_mask = BIT(11),
+		.halt_reg = DBG_BUS_VEC_I_REG,
+		.halt_bit = 30,
+	},
+	.parent = &csiphy_timer_src_clk.c,
+	.c = {
+		.dbg_name = "csi2phy_timer_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi2phy_timer_clk.c),
+	},
+};
+
+#define F_DSI(d) \
+	{ \
+		.freq_hz = d, \
+		.ns_val = BVAL(15, 12, (d-1)), \
+	}
+/*
+ * The DSI_BYTE/ESC clock is sourced from the DSI PHY PLL, which may change rate
+ * without this clock driver knowing.  So, overload the clk_set_rate() to set
+ * the divider (1 to 16) of the clock with respect to the PLL rate.
+ */
+static struct clk_freq_tbl clk_tbl_dsi_byte[] = {
+	F_DSI(1),  F_DSI(2),  F_DSI(3),  F_DSI(4),
+	F_DSI(5),  F_DSI(6),  F_DSI(7),  F_DSI(8),
+	F_DSI(9),  F_DSI(10), F_DSI(11), F_DSI(12),
+	F_DSI(13), F_DSI(14), F_DSI(15), F_DSI(16),
+	F_END
+};
+
+static struct rcg_clk dsi1_byte_clk = {
+	.b = {
+		.ctl_reg = DSI1_BYTE_CC_REG,
+		.en_mask = BIT(0),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(7),
+		.halt_reg = DBG_BUS_VEC_B_REG,
+		.halt_bit = 21,
+		.retain_reg = DSI1_BYTE_CC_REG,
+		.retain_mask = BIT(31),
+	},
+	.ns_reg = DSI1_BYTE_NS_REG,
+	.root_en_mask = BIT(2),
+	.ns_mask = BM(15, 12),
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_dsi_byte,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "dsi1_byte_clk",
+		.ops = &clk_ops_rcg,
+		CLK_INIT(dsi1_byte_clk.c),
+	},
+};
+
+static struct rcg_clk dsi2_byte_clk = {
+	.b = {
+		.ctl_reg = DSI2_BYTE_CC_REG,
+		.en_mask = BIT(0),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(25),
+		.halt_reg = DBG_BUS_VEC_B_REG,
+		.halt_bit = 20,
+		.retain_reg = DSI2_BYTE_CC_REG,
+		.retain_mask = BIT(31),
+	},
+	.ns_reg = DSI2_BYTE_NS_REG,
+	.root_en_mask = BIT(2),
+	.ns_mask = BM(15, 12),
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_dsi_byte,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "dsi2_byte_clk",
+		.ops = &clk_ops_rcg,
+		CLK_INIT(dsi2_byte_clk.c),
+	},
+};
+
+static struct rcg_clk dsi1_esc_clk = {
+	.b = {
+		.ctl_reg = DSI1_ESC_CC_REG,
+		.en_mask = BIT(0),
+		.reset_reg = SW_RESET_CORE_REG,
+		.halt_reg = DBG_BUS_VEC_I_REG,
+		.halt_bit = 1,
+	},
+	.ns_reg = DSI1_ESC_NS_REG,
+	.root_en_mask = BIT(2),
+	.ns_mask = BM(15, 12),
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_dsi_byte,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "dsi1_esc_clk",
+		.ops = &clk_ops_rcg,
+		CLK_INIT(dsi1_esc_clk.c),
+	},
+};
+
+static struct rcg_clk dsi2_esc_clk = {
+	.b = {
+		.ctl_reg = DSI2_ESC_CC_REG,
+		.en_mask = BIT(0),
+		.halt_reg = DBG_BUS_VEC_I_REG,
+		.halt_bit = 3,
+	},
+	.ns_reg = DSI2_ESC_NS_REG,
+	.root_en_mask = BIT(2),
+	.ns_mask = BM(15, 12),
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_dsi_byte,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "dsi2_esc_clk",
+		.ops = &clk_ops_rcg,
+		CLK_INIT(dsi2_esc_clk.c),
+	},
+};
+
+#define F_GFX2D(f, s, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD4(4, m, 0, n), \
+		.ns_val = NS_MND_BANKED4(20, 16, n, m, 3, 0, s##_to_mm_mux), \
+		.ctl_val = CC_BANKED(9, 6, n), \
+	}
+static struct clk_freq_tbl clk_tbl_gfx2d[] = {
+	F_GFX2D(        0, gnd,  0,  0),
+	F_GFX2D( 27000000, pxo,  0,  0),
+	F_GFX2D( 48000000, pll8, 1,  8),
+	F_GFX2D( 54857000, pll8, 1,  7),
+	F_GFX2D( 64000000, pll8, 1,  6),
+	F_GFX2D( 76800000, pll8, 1,  5),
+	F_GFX2D( 96000000, pll8, 1,  4),
+	F_GFX2D(128000000, pll8, 1,  3),
+	F_GFX2D(145455000, pll2, 2, 11),
+	F_GFX2D(160000000, pll2, 1,  5),
+	F_GFX2D(177778000, pll2, 2,  9),
+	F_GFX2D(200000000, pll2, 1,  4),
+	F_GFX2D(228571000, pll2, 2,  7),
+	F_END
+};
+
+static struct bank_masks bmnd_info_gfx2d0 = {
+	.bank_sel_mask =			BIT(11),
+	.bank0_mask = {
+			.md_reg =		GFX2D0_MD0_REG,
+			.ns_mask =		BM(23, 20) | BM(5, 3),
+			.rst_mask =		BIT(25),
+			.mnd_en_mask =		BIT(8),
+			.mode_mask =		BM(10, 9),
+	},
+	.bank1_mask = {
+			.md_reg =		GFX2D0_MD1_REG,
+			.ns_mask =		BM(19, 16) | BM(2, 0),
+			.rst_mask =		BIT(24),
+			.mnd_en_mask =		BIT(5),
+			.mode_mask =		BM(7, 6),
+	},
+};
+
+static struct rcg_clk gfx2d0_clk = {
+	.b = {
+		.ctl_reg = GFX2D0_CC_REG,
+		.en_mask = BIT(0),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(14),
+		.halt_reg = DBG_BUS_VEC_A_REG,
+		.halt_bit = 9,
+		.retain_reg = GFX2D0_CC_REG,
+		.retain_mask = BIT(31),
+	},
+	.ns_reg = GFX2D0_NS_REG,
+	.root_en_mask = BIT(2),
+	.set_rate = set_rate_mnd_banked,
+	.freq_tbl = clk_tbl_gfx2d,
+	.bank_info = &bmnd_info_gfx2d0,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "gfx2d0_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW,  100000000, NOMINAL, 200000000,
+				  HIGH, 228571000),
+		CLK_INIT(gfx2d0_clk.c),
+	},
+};
+
+static struct bank_masks bmnd_info_gfx2d1 = {
+	.bank_sel_mask =		BIT(11),
+	.bank0_mask = {
+			.md_reg =		GFX2D1_MD0_REG,
+			.ns_mask =		BM(23, 20) | BM(5, 3),
+			.rst_mask =		BIT(25),
+			.mnd_en_mask =		BIT(8),
+			.mode_mask =		BM(10, 9),
+	},
+	.bank1_mask = {
+			.md_reg =		GFX2D1_MD1_REG,
+			.ns_mask =		BM(19, 16) | BM(2, 0),
+			.rst_mask =		BIT(24),
+			.mnd_en_mask =		BIT(5),
+			.mode_mask =		BM(7, 6),
+	},
+};
+
+static struct rcg_clk gfx2d1_clk = {
+	.b = {
+		.ctl_reg = GFX2D1_CC_REG,
+		.en_mask = BIT(0),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(13),
+		.halt_reg = DBG_BUS_VEC_A_REG,
+		.halt_bit = 14,
+		.retain_reg = GFX2D1_CC_REG,
+		.retain_mask = BIT(31),
+	},
+	.ns_reg = GFX2D1_NS_REG,
+	.root_en_mask = BIT(2),
+	.set_rate = set_rate_mnd_banked,
+	.freq_tbl = clk_tbl_gfx2d,
+	.bank_info = &bmnd_info_gfx2d1,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "gfx2d1_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW,  100000000, NOMINAL, 200000000,
+				  HIGH, 228571000),
+		CLK_INIT(gfx2d1_clk.c),
+	},
+};
+
+#define F_GFX3D(f, s, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD4(4, m, 0, n), \
+		.ns_val = NS_MND_BANKED4(18, 14, n, m, 3, 0, s##_to_mm_mux), \
+		.ctl_val = CC_BANKED(9, 6, n), \
+	}
+
+static struct clk_freq_tbl clk_tbl_gfx3d_8960[] = {
+	F_GFX3D(        0, gnd,  0,  0),
+	F_GFX3D( 27000000, pxo,  0,  0),
+	F_GFX3D( 48000000, pll8, 1,  8),
+	F_GFX3D( 54857000, pll8, 1,  7),
+	F_GFX3D( 64000000, pll8, 1,  6),
+	F_GFX3D( 76800000, pll8, 1,  5),
+	F_GFX3D( 96000000, pll8, 1,  4),
+	F_GFX3D(128000000, pll8, 1,  3),
+	F_GFX3D(145455000, pll2, 2, 11),
+	F_GFX3D(160000000, pll2, 1,  5),
+	F_GFX3D(177778000, pll2, 2,  9),
+	F_GFX3D(200000000, pll2, 1,  4),
+	F_GFX3D(228571000, pll2, 2,  7),
+	F_GFX3D(266667000, pll2, 1,  3),
+	F_GFX3D(300000000, pll3, 1,  4),
+	F_GFX3D(320000000, pll2, 2,  5),
+	F_GFX3D(400000000, pll2, 1,  2),
+	F_END
+};
+
+static struct clk_freq_tbl clk_tbl_gfx3d_8064[] = {
+	F_GFX3D(        0, gnd,   0,  0),
+	F_GFX3D( 27000000, pxo,   0,  0),
+	F_GFX3D( 48000000, pll8,  1,  8),
+	F_GFX3D( 54857000, pll8,  1,  7),
+	F_GFX3D( 64000000, pll8,  1,  6),
+	F_GFX3D( 76800000, pll8,  1,  5),
+	F_GFX3D( 96000000, pll8,  1,  4),
+	F_GFX3D(128000000, pll8,  1,  3),
+	F_GFX3D(145455000, pll2,  2, 11),
+	F_GFX3D(160000000, pll2,  1,  5),
+	F_GFX3D(177778000, pll2,  2,  9),
+	F_GFX3D(200000000, pll2,  1,  4),
+	F_GFX3D(228571000, pll2,  2,  7),
+	F_GFX3D(266667000, pll2,  1,  3),
+	F_GFX3D(325000000, pll15, 1,  3),
+	F_GFX3D(400000000, pll2,  1,  2),
+	F_END
+};
+
+static struct clk_freq_tbl clk_tbl_gfx3d_8930[] = {
+	F_GFX3D(        0, gnd,   0,  0),
+	F_GFX3D( 27000000, pxo,   0,  0),
+	F_GFX3D( 48000000, pll8,  1,  8),
+	F_GFX3D( 54857000, pll8,  1,  7),
+	F_GFX3D( 64000000, pll8,  1,  6),
+	F_GFX3D( 76800000, pll8,  1,  5),
+	F_GFX3D( 96000000, pll8,  1,  4),
+	F_GFX3D(128000000, pll8,  1,  3),
+	F_GFX3D(145455000, pll2,  2, 11),
+	F_GFX3D(160000000, pll2,  1,  5),
+	F_GFX3D(177778000, pll2,  2,  9),
+	F_GFX3D(192000000, pll8,  1,  2),
+	F_GFX3D(200000000, pll2,  1,  4),
+	F_GFX3D(228571000, pll2,  2,  7),
+	F_GFX3D(266667000, pll2,  1,  3),
+	F_GFX3D(320000000, pll2,  2,  5),
+	F_GFX3D(400000000, pll2,  1,  2),
+	F_GFX3D(450000000, pll15, 1,  2),
+	F_END
+};
+
+static unsigned long fmax_gfx3d_8064[MAX_VDD_LEVELS] __initdata = {
+	[VDD_DIG_LOW]     = 128000000,
+	[VDD_DIG_NOMINAL] = 325000000,
+	[VDD_DIG_HIGH]    = 400000000
+};
+
+static unsigned long fmax_gfx3d_8930[MAX_VDD_LEVELS] __initdata = {
+	[VDD_DIG_LOW]     = 192000000,
+	[VDD_DIG_NOMINAL] = 320000000,
+	[VDD_DIG_HIGH]    = 450000000
+};
+
+static struct bank_masks bmnd_info_gfx3d = {
+	.bank_sel_mask =		BIT(11),
+	.bank0_mask = {
+			.md_reg =		GFX3D_MD0_REG,
+			.ns_mask =		BM(21, 18) | BM(5, 3),
+			.rst_mask =		BIT(23),
+			.mnd_en_mask =		BIT(8),
+			.mode_mask =		BM(10, 9),
+	},
+	.bank1_mask = {
+			.md_reg =		GFX3D_MD1_REG,
+			.ns_mask =		BM(17, 14) | BM(2, 0),
+			.rst_mask =		BIT(22),
+			.mnd_en_mask =		BIT(5),
+			.mode_mask =		BM(7, 6),
+	},
+};
+
+static struct rcg_clk gfx3d_clk = {
+	.b = {
+		.ctl_reg = GFX3D_CC_REG,
+		.en_mask = BIT(0),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(12),
+		.halt_reg = DBG_BUS_VEC_A_REG,
+		.halt_bit = 4,
+		.retain_reg = GFX3D_CC_REG,
+		.retain_mask = BIT(31),
+	},
+	.ns_reg = GFX3D_NS_REG,
+	.root_en_mask = BIT(2),
+	.set_rate = set_rate_mnd_banked,
+	.freq_tbl = clk_tbl_gfx3d_8960,
+	.bank_info = &bmnd_info_gfx3d,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "gfx3d_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW,  128000000, NOMINAL, 300000000,
+				  HIGH, 400000000),
+		CLK_INIT(gfx3d_clk.c),
+		.depends = &gmem_axi_clk.c,
+	},
+};
+
+#define F_VCAP(f, s, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD4(4, m, 0, n), \
+		.ns_val = NS_MND_BANKED4(18, 14, n, m, 3, 0, s##_to_mm_mux), \
+		.ctl_val = CC_BANKED(9, 6, n), \
+	}
+
+static struct clk_freq_tbl clk_tbl_vcap[] = {
+	F_VCAP(        0, gnd,  0,  0),
+	F_VCAP( 27000000, pxo,  0,  0),
+	F_VCAP( 54860000, pll8, 1,  7),
+	F_VCAP( 64000000, pll8, 1,  6),
+	F_VCAP( 76800000, pll8, 1,  5),
+	F_VCAP(128000000, pll8, 1,  3),
+	F_VCAP(160000000, pll2, 1,  5),
+	F_VCAP(200000000, pll2, 1,  4),
+	F_END
+};
+
+static struct bank_masks bmnd_info_vcap = {
+	.bank_sel_mask =                BIT(11),
+	.bank0_mask = {
+		.md_reg =               VCAP_MD0_REG,
+		.ns_mask =              BM(21, 18) | BM(5, 3),
+		.rst_mask =             BIT(23),
+		.mnd_en_mask =          BIT(8),
+		.mode_mask =            BM(10, 9),
+	},
+	.bank1_mask = {
+		.md_reg =               VCAP_MD1_REG,
+		.ns_mask =              BM(17, 14) | BM(2, 0),
+		.rst_mask =             BIT(22),
+		.mnd_en_mask =          BIT(5),
+		.mode_mask =            BM(7, 6),
+	},
+};
+
+static struct rcg_clk vcap_clk = {
+	.b = {
+		.ctl_reg = VCAP_CC_REG,
+		.en_mask = BIT(0),
+		.halt_reg = DBG_BUS_VEC_J_REG,
+		.halt_bit = 15,
+	},
+	.ns_reg = VCAP_NS_REG,
+	.root_en_mask = BIT(2),
+	.set_rate = set_rate_mnd_banked,
+	.freq_tbl = clk_tbl_vcap,
+	.bank_info = &bmnd_info_vcap,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "vcap_clk",
+		.ops = &clk_ops_rcg,
+		.depends = &vcap_axi_clk.c,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(vcap_clk.c),
+	},
+};
+
+static struct branch_clk vcap_npl_clk = {
+	.b = {
+		.ctl_reg = VCAP_CC_REG,
+		.en_mask = BIT(13),
+		.halt_reg = DBG_BUS_VEC_J_REG,
+		.halt_bit = 25,
+	},
+	.parent = &vcap_clk.c,
+	.c = {
+		.dbg_name = "vcap_npl_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(vcap_npl_clk.c),
+	},
+};
+
+#define F_IJPEG(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD8(8, m, 0, n), \
+		.ns_val = NS_MM(23, 16, n, m, 15, 12, d, 2, 0, s##_to_mm_mux), \
+		.ctl_val = CC(6, n), \
+	}
+
+static struct clk_freq_tbl clk_tbl_ijpeg[] = {
+	F_IJPEG(        0, gnd,  1, 0,  0),
+	F_IJPEG( 27000000, pxo,  1, 0,  0),
+	F_IJPEG( 36570000, pll8, 1, 2, 21),
+	F_IJPEG( 54860000, pll8, 7, 0,  0),
+	F_IJPEG( 96000000, pll8, 4, 0,  0),
+	F_IJPEG(109710000, pll8, 1, 2,  7),
+	F_IJPEG(128000000, pll8, 3, 0,  0),
+	F_IJPEG(153600000, pll8, 1, 2,  5),
+	F_IJPEG(200000000, pll2, 4, 0,  0),
+	F_IJPEG(228571000, pll2, 1, 2,  7),
+	F_IJPEG(266667000, pll2, 1, 1,  3),
+	F_IJPEG(320000000, pll2, 1, 2,  5),
+	F_END
+};
+
+static unsigned long fmax_ijpeg_8064[MAX_VDD_LEVELS] __initdata = {
+	[VDD_DIG_LOW]     = 128000000,
+	[VDD_DIG_NOMINAL] = 266667000,
+	[VDD_DIG_HIGH]    = 320000000
+};
+
+static struct rcg_clk ijpeg_clk = {
+	.b = {
+		.ctl_reg = IJPEG_CC_REG,
+		.en_mask = BIT(0),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(9),
+		.halt_reg = DBG_BUS_VEC_A_REG,
+		.halt_bit = 24,
+		.retain_reg = IJPEG_CC_REG,
+		.retain_mask = BIT(31),
+	},
+	.ns_reg = IJPEG_NS_REG,
+	.md_reg = IJPEG_MD_REG,
+	.root_en_mask = BIT(2),
+	.ns_mask = (BM(23, 16) | BM(15, 12) | BM(2, 0)),
+	.mnd_en_mask = BIT(5),
+	.ctl_mask = BM(7, 6),
+	.set_rate = set_rate_mnd,
+	.freq_tbl = clk_tbl_ijpeg,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "ijpeg_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 110000000, NOMINAL, 266667000,
+				  HIGH, 320000000),
+		CLK_INIT(ijpeg_clk.c),
+		.depends = &ijpeg_axi_clk.c,
+	},
+};
+
+#define F_JPEGD(f, s, d) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.ns_val = NS_DIVSRC(15, 12, d, 2, 0, s##_to_mm_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_jpegd[] = {
+	F_JPEGD(        0, gnd,  1),
+	F_JPEGD( 64000000, pll8, 6),
+	F_JPEGD( 76800000, pll8, 5),
+	F_JPEGD( 96000000, pll8, 4),
+	F_JPEGD(160000000, pll2, 5),
+	F_JPEGD(200000000, pll2, 4),
+	F_END
+};
+
+static struct rcg_clk jpegd_clk = {
+	.b = {
+		.ctl_reg = JPEGD_CC_REG,
+		.en_mask = BIT(0),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(19),
+		.halt_reg = DBG_BUS_VEC_A_REG,
+		.halt_bit = 19,
+		.retain_reg = JPEGD_CC_REG,
+		.retain_mask = BIT(31),
+	},
+	.ns_reg = JPEGD_NS_REG,
+	.root_en_mask = BIT(2),
+	.ns_mask =  (BM(15, 12) | BM(2, 0)),
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_jpegd,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "jpegd_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 96000000, NOMINAL, 200000000),
+		CLK_INIT(jpegd_clk.c),
+		.depends = &jpegd_axi_clk.c,
+	},
+};
+
+#define F_MDP(f, s, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD8(8, m, 0, n), \
+		.ns_val = NS_MND_BANKED8(22, 14, n, m, 3, 0, s##_to_mm_mux), \
+		.ctl_val = CC_BANKED(9, 6, n), \
+	}
+static struct clk_freq_tbl clk_tbl_mdp[] = {
+	F_MDP(        0, gnd,  0,  0),
+	F_MDP(  9600000, pll8, 1, 40),
+	F_MDP( 13710000, pll8, 1, 28),
+	F_MDP( 27000000, pxo,  0,  0),
+	F_MDP( 29540000, pll8, 1, 13),
+	F_MDP( 34910000, pll8, 1, 11),
+	F_MDP( 38400000, pll8, 1, 10),
+	F_MDP( 59080000, pll8, 2, 13),
+	F_MDP( 76800000, pll8, 1,  5),
+	F_MDP( 85330000, pll8, 2,  9),
+	F_MDP( 96000000, pll8, 1,  4),
+	F_MDP(128000000, pll8, 1,  3),
+	F_MDP(160000000, pll2, 1,  5),
+	F_MDP(177780000, pll2, 2,  9),
+	F_MDP(200000000, pll2, 1,  4),
+	F_MDP(266667000, pll2, 1,  3),
+	F_END
+};
+
+static unsigned long fmax_mdp_8064[MAX_VDD_LEVELS] __initdata = {
+	[VDD_DIG_LOW]     = 128000000,
+	[VDD_DIG_NOMINAL] = 266667000
+};
+
+static struct bank_masks bmnd_info_mdp = {
+	.bank_sel_mask =		BIT(11),
+	.bank0_mask = {
+			.md_reg =		MDP_MD0_REG,
+			.ns_mask =		BM(29, 22) | BM(5, 3),
+			.rst_mask =		BIT(31),
+			.mnd_en_mask =		BIT(8),
+			.mode_mask =		BM(10, 9),
+	},
+	.bank1_mask = {
+			.md_reg =		MDP_MD1_REG,
+			.ns_mask =		BM(21, 14) | BM(2, 0),
+			.rst_mask =		BIT(30),
+			.mnd_en_mask =		BIT(5),
+			.mode_mask =		BM(7, 6),
+	},
+};
+
+static struct rcg_clk mdp_clk = {
+	.b = {
+		.ctl_reg = MDP_CC_REG,
+		.en_mask = BIT(0),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(21),
+		.halt_reg = DBG_BUS_VEC_C_REG,
+		.halt_bit = 10,
+		.retain_reg = MDP_CC_REG,
+		.retain_mask = BIT(31),
+	},
+	.ns_reg = MDP_NS_REG,
+	.root_en_mask = BIT(2),
+	.set_rate = set_rate_mnd_banked,
+	.freq_tbl = clk_tbl_mdp,
+	.bank_info = &bmnd_info_mdp,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "mdp_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 96000000, NOMINAL, 200000000),
+		CLK_INIT(mdp_clk.c),
+		.depends = &mdp_axi_clk.c,
+	},
+};
+
+static struct branch_clk lut_mdp_clk = {
+	.b = {
+		.ctl_reg = MDP_LUT_CC_REG,
+		.en_mask = BIT(0),
+		.halt_reg = DBG_BUS_VEC_I_REG,
+		.halt_bit = 13,
+		.retain_reg = MDP_LUT_CC_REG,
+		.retain_mask = BIT(31),
+	},
+	.parent = &mdp_clk.c,
+	.c = {
+		.dbg_name = "lut_mdp_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(lut_mdp_clk.c),
+	},
+};
+
+#define F_MDP_VSYNC(f, s) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.ns_val = NS_SRC_SEL(13, 13, s##_to_bb_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_mdp_vsync[] = {
+	F_MDP_VSYNC(27000000, pxo),
+	F_END
+};
+
+static struct rcg_clk mdp_vsync_clk = {
+	.b = {
+		.ctl_reg = MISC_CC_REG,
+		.en_mask = BIT(6),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(3),
+		.halt_reg = DBG_BUS_VEC_B_REG,
+		.halt_bit = 22,
+	},
+	.ns_reg = MISC_CC2_REG,
+	.ns_mask = BIT(13),
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_mdp_vsync,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "mdp_vsync_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 27000000),
+		CLK_INIT(mdp_vsync_clk.c),
+	},
+};
+
+#define F_ROT(f, s, d) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.ns_val = NS_DIVSRC_BANKED(29, 26, 25, 22, d, \
+				21, 19, 18, 16, s##_to_mm_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_rot[] = {
+	F_ROT(        0, gnd,   1),
+	F_ROT( 27000000, pxo,   1),
+	F_ROT( 29540000, pll8, 13),
+	F_ROT( 32000000, pll8, 12),
+	F_ROT( 38400000, pll8, 10),
+	F_ROT( 48000000, pll8,  8),
+	F_ROT( 54860000, pll8,  7),
+	F_ROT( 64000000, pll8,  6),
+	F_ROT( 76800000, pll8,  5),
+	F_ROT( 96000000, pll8,  4),
+	F_ROT(100000000, pll2,  8),
+	F_ROT(114290000, pll2,  7),
+	F_ROT(133330000, pll2,  6),
+	F_ROT(160000000, pll2,  5),
+	F_ROT(200000000, pll2,  4),
+	F_END
+};
+
+static struct bank_masks bdiv_info_rot = {
+	.bank_sel_mask = BIT(30),
+	.bank0_mask = {
+		.ns_mask =	BM(25, 22) | BM(18, 16),
+	},
+	.bank1_mask = {
+		.ns_mask =	BM(29, 26) | BM(21, 19),
+	},
+};
+
+static struct rcg_clk rot_clk = {
+	.b = {
+		.ctl_reg = ROT_CC_REG,
+		.en_mask = BIT(0),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(2),
+		.halt_reg = DBG_BUS_VEC_C_REG,
+		.halt_bit = 15,
+		.retain_reg = ROT_CC_REG,
+		.retain_mask = BIT(31),
+	},
+	.ns_reg = ROT_NS_REG,
+	.root_en_mask = BIT(2),
+	.set_rate = set_rate_div_banked,
+	.freq_tbl = clk_tbl_rot,
+	.bank_info = &bdiv_info_rot,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "rot_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 96000000, NOMINAL, 200000000),
+		CLK_INIT(rot_clk.c),
+		.depends = &rot_axi_clk.c,
+	},
+};
+
+static int hdmi_pll_clk_enable(struct clk *clk)
+{
+	int ret;
+	unsigned long flags;
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	ret = hdmi_pll_enable();
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+	return ret;
+}
+
+static void hdmi_pll_clk_disable(struct clk *clk)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	hdmi_pll_disable();
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+}
+
+static unsigned long hdmi_pll_clk_get_rate(struct clk *clk)
+{
+	return hdmi_pll_get_rate();
+}
+
+static struct clk *hdmi_pll_clk_get_parent(struct clk *clk)
+{
+	return &pxo_clk.c;
+}
+
+static struct clk_ops clk_ops_hdmi_pll = {
+	.enable = hdmi_pll_clk_enable,
+	.disable = hdmi_pll_clk_disable,
+	.get_rate = hdmi_pll_clk_get_rate,
+	.get_parent = hdmi_pll_clk_get_parent,
+};
+
+static struct clk hdmi_pll_clk = {
+	.dbg_name = "hdmi_pll_clk",
+	.ops = &clk_ops_hdmi_pll,
+	CLK_INIT(hdmi_pll_clk),
+};
+
+#define F_TV_GND(f, s, p_r, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD8(8, m, 0, n), \
+		.ns_val = NS_MM(23, 16, n, m, 15, 14, d, 2, 0, s##_to_mm_mux), \
+		.ctl_val = CC(6, n), \
+	}
+#define F_TV(f, s, p_r, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk, \
+		.md_val = MD8(8, m, 0, n), \
+		.ns_val = NS_MM(23, 16, n, m, 15, 14, d, 2, 0, s##_to_mm_mux), \
+		.ctl_val = CC(6, n), \
+		.extra_freq_data = (void *)p_r, \
+	}
+/* Switching TV freqs requires PLL reconfiguration. */
+static struct clk_freq_tbl clk_tbl_tv[] = {
+	F_TV_GND(    0,      gnd,         0, 1, 0, 0),
+	F_TV( 25200000, hdmi_pll,  25200000, 1, 0, 0),
+	F_TV( 27000000, hdmi_pll,  27000000, 1, 0, 0),
+	F_TV( 27030000, hdmi_pll,  27030000, 1, 0, 0),
+	F_TV( 74250000, hdmi_pll,  74250000, 1, 0, 0),
+	F_TV(148500000, hdmi_pll, 148500000, 1, 0, 0),
+	F_END
+};
+
+static unsigned long fmax_tv_src_8064[MAX_VDD_LEVELS] __initdata = {
+	[VDD_DIG_LOW]     =  74250000,
+	[VDD_DIG_NOMINAL] = 149000000
+};
+
+/*
+ * Unlike other clocks, the TV rate is adjusted through PLL
+ * re-programming. It is also routed through an MND divider.
+ */
+void set_rate_tv(struct rcg_clk *clk, struct clk_freq_tbl *nf)
+{
+	unsigned long pll_rate = (unsigned long)nf->extra_freq_data;
+	if (pll_rate)
+		hdmi_pll_set_rate(pll_rate);
+	set_rate_mnd(clk, nf);
+}
+
+static struct rcg_clk tv_src_clk = {
+	.ns_reg = TV_NS_REG,
+	.b = {
+		.ctl_reg = TV_CC_REG,
+		.halt_check = NOCHECK,
+		.retain_reg = TV_CC_REG,
+		.retain_mask = BIT(31),
+	},
+	.md_reg = TV_MD_REG,
+	.root_en_mask = BIT(2),
+	.ns_mask = (BM(23, 16) | BM(15, 14) | BM(2, 0)),
+	.mnd_en_mask = BIT(5),
+	.ctl_mask = BM(7, 6),
+	.set_rate = set_rate_tv,
+	.freq_tbl = clk_tbl_tv,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "tv_src_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 27030000, NOMINAL, 149000000),
+		CLK_INIT(tv_src_clk.c),
+	},
+};
+
+static struct cdiv_clk tv_src_div_clk = {
+	.b = {
+		.ctl_reg = TV_NS_REG,
+		.halt_check = NOCHECK,
+	},
+	.ns_reg = TV_NS_REG,
+	.div_offset = 6,
+	.max_div = 2,
+	.c = {
+		.dbg_name = "tv_src_div_clk",
+		.ops = &clk_ops_cdiv,
+		CLK_INIT(tv_src_div_clk.c),
+	},
+};
+
+static struct branch_clk tv_enc_clk = {
+	.b = {
+		.ctl_reg = TV_CC_REG,
+		.en_mask = BIT(8),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(0),
+		.halt_reg = DBG_BUS_VEC_D_REG,
+		.halt_bit = 9,
+	},
+	.parent = &tv_src_clk.c,
+	.c = {
+		.dbg_name = "tv_enc_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(tv_enc_clk.c),
+	},
+};
+
+static struct branch_clk tv_dac_clk = {
+	.b = {
+		.ctl_reg = TV_CC_REG,
+		.en_mask = BIT(10),
+		.halt_reg = DBG_BUS_VEC_D_REG,
+		.halt_bit = 10,
+	},
+	.parent = &tv_src_clk.c,
+	.c = {
+		.dbg_name = "tv_dac_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(tv_dac_clk.c),
+	},
+};
+
+static struct branch_clk mdp_tv_clk = {
+	.b = {
+		.ctl_reg = TV_CC_REG,
+		.en_mask = BIT(0),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(4),
+		.halt_reg = DBG_BUS_VEC_D_REG,
+		.halt_bit = 12,
+		.retain_reg = TV_CC2_REG,
+		.retain_mask = BIT(10),
+	},
+	.parent = &tv_src_clk.c,
+	.c = {
+		.dbg_name = "mdp_tv_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdp_tv_clk.c),
+	},
+};
+
+static struct branch_clk hdmi_tv_clk = {
+	.b = {
+		.ctl_reg = TV_CC_REG,
+		.en_mask = BIT(12),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(1),
+		.halt_reg = DBG_BUS_VEC_D_REG,
+		.halt_bit = 11,
+	},
+	.parent = &tv_src_clk.c,
+	.c = {
+		.dbg_name = "hdmi_tv_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(hdmi_tv_clk.c),
+	},
+};
+
+static struct branch_clk rgb_tv_clk = {
+	.b = {
+		.ctl_reg = TV_CC2_REG,
+		.en_mask = BIT(14),
+		.halt_reg = DBG_BUS_VEC_J_REG,
+		.halt_bit = 27,
+	},
+	.parent = &tv_src_clk.c,
+	.c = {
+		.dbg_name = "rgb_tv_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(rgb_tv_clk.c),
+	},
+};
+
+static struct branch_clk npl_tv_clk = {
+	.b = {
+		.ctl_reg = TV_CC2_REG,
+		.en_mask = BIT(16),
+		.halt_reg = DBG_BUS_VEC_J_REG,
+		.halt_bit = 26,
+	},
+	.parent = &tv_src_clk.c,
+	.c = {
+		.dbg_name = "npl_tv_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(npl_tv_clk.c),
+	},
+};
+
+static struct branch_clk hdmi_app_clk = {
+	.b = {
+		.ctl_reg = MISC_CC2_REG,
+		.en_mask = BIT(11),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(11),
+		.halt_reg = DBG_BUS_VEC_B_REG,
+		.halt_bit = 25,
+	},
+	.c = {
+		.dbg_name = "hdmi_app_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(hdmi_app_clk.c),
+	},
+};
+
+static struct bank_masks bmnd_info_vcodec = {
+	.bank_sel_mask =		BIT(13),
+	.bank0_mask = {
+			.md_reg =		VCODEC_MD0_REG,
+			.ns_mask =		BM(18, 11) | BM(2, 0),
+			.rst_mask =		BIT(31),
+			.mnd_en_mask =		BIT(5),
+			.mode_mask =		BM(7, 6),
+	},
+	.bank1_mask = {
+			.md_reg =		VCODEC_MD1_REG,
+			.ns_mask =		BM(26, 19) | BM(29, 27),
+			.rst_mask =		BIT(30),
+			.mnd_en_mask =		BIT(10),
+			.mode_mask =		BM(12, 11),
+	},
+};
+#define F_VCODEC(f, s, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD8(8, m, 0, n), \
+		.ns_val = NS_MND_BANKED8(11, 19, n, m, 0, 27, s##_to_mm_mux), \
+		.ctl_val = CC_BANKED(6, 11, n), \
+	}
+static struct clk_freq_tbl clk_tbl_vcodec[] = {
+	F_VCODEC(        0, gnd,  0,  0),
+	F_VCODEC( 27000000, pxo,  0,  0),
+	F_VCODEC( 32000000, pll8, 1, 12),
+	F_VCODEC( 48000000, pll8, 1,  8),
+	F_VCODEC( 54860000, pll8, 1,  7),
+	F_VCODEC( 96000000, pll8, 1,  4),
+	F_VCODEC(133330000, pll2, 1,  6),
+	F_VCODEC(200000000, pll2, 1,  4),
+	F_VCODEC(228570000, pll2, 2,  7),
+	F_END
+};
+
+static struct rcg_clk vcodec_clk = {
+	.b = {
+		.ctl_reg = VCODEC_CC_REG,
+		.en_mask = BIT(0),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(6),
+		.halt_reg = DBG_BUS_VEC_C_REG,
+		.halt_bit = 29,
+		.retain_reg = VCODEC_CC_REG,
+		.retain_mask = BIT(31),
+	},
+	.ns_reg = VCODEC_NS_REG,
+	.root_en_mask = BIT(2),
+	.set_rate = set_rate_mnd_banked,
+	.bank_info = &bmnd_info_vcodec,
+	.freq_tbl = clk_tbl_vcodec,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "vcodec_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW,  100000000, NOMINAL, 200000000,
+				  HIGH, 228571000),
+		CLK_INIT(vcodec_clk.c),
+		.depends = &vcodec_axi_clk.c,
+	},
+};
+
+#define F_VPE(f, s, d) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.ns_val = NS_DIVSRC(15, 12, d, 2, 0, s##_to_mm_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_vpe[] = {
+	F_VPE(        0, gnd,   1),
+	F_VPE( 27000000, pxo,   1),
+	F_VPE( 34909000, pll8, 11),
+	F_VPE( 38400000, pll8, 10),
+	F_VPE( 64000000, pll8,  6),
+	F_VPE( 76800000, pll8,  5),
+	F_VPE( 96000000, pll8,  4),
+	F_VPE(100000000, pll2,  8),
+	F_VPE(160000000, pll2,  5),
+	F_END
+};
+
+static struct rcg_clk vpe_clk = {
+	.b = {
+		.ctl_reg = VPE_CC_REG,
+		.en_mask = BIT(0),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(17),
+		.halt_reg = DBG_BUS_VEC_A_REG,
+		.halt_bit = 28,
+		.retain_reg = VPE_CC_REG,
+		.retain_mask = BIT(31),
+	},
+	.ns_reg = VPE_NS_REG,
+	.root_en_mask = BIT(2),
+	.ns_mask = (BM(15, 12) | BM(2, 0)),
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_vpe,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "vpe_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 76800000, NOMINAL, 160000000),
+		CLK_INIT(vpe_clk.c),
+		.depends = &vpe_axi_clk.c,
+	},
+};
+
+#define F_VFE(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD8(8, m, 0, n), \
+		.ns_val = NS_MM(23, 16, n, m, 11, 10, d, 2, 0, s##_to_mm_mux), \
+		.ctl_val = CC(6, n), \
+	}
+
+static struct clk_freq_tbl clk_tbl_vfe[] = {
+	F_VFE(        0, gnd,   1, 0,  0),
+	F_VFE( 13960000, pll8,  1, 2, 55),
+	F_VFE( 27000000, pxo,   1, 0,  0),
+	F_VFE( 36570000, pll8,  1, 2, 21),
+	F_VFE( 38400000, pll8,  2, 1,  5),
+	F_VFE( 45180000, pll8,  1, 2, 17),
+	F_VFE( 48000000, pll8,  2, 1,  4),
+	F_VFE( 54860000, pll8,  1, 1,  7),
+	F_VFE( 64000000, pll8,  2, 1,  3),
+	F_VFE( 76800000, pll8,  1, 1,  5),
+	F_VFE( 96000000, pll8,  2, 1,  2),
+	F_VFE(109710000, pll8,  1, 2,  7),
+	F_VFE(128000000, pll8,  1, 1,  3),
+	F_VFE(153600000, pll8,  1, 2,  5),
+	F_VFE(200000000, pll2,  2, 1,  2),
+	F_VFE(228570000, pll2,  1, 2,  7),
+	F_VFE(266667000, pll2,  1, 1,  3),
+	F_VFE(320000000, pll2,  1, 2,  5),
+	F_END
+};
+
+static unsigned long fmax_vfe_8064[MAX_VDD_LEVELS] __initdata = {
+	[VDD_DIG_LOW]     = 128000000,
+	[VDD_DIG_NOMINAL] = 266667000,
+	[VDD_DIG_HIGH]    = 320000000
+};
+
+static struct rcg_clk vfe_clk = {
+	.b = {
+		.ctl_reg = VFE_CC_REG,
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(15),
+		.halt_reg = DBG_BUS_VEC_B_REG,
+		.halt_bit = 6,
+		.en_mask = BIT(0),
+		.retain_reg = VFE_CC2_REG,
+		.retain_mask = BIT(31),
+	},
+	.ns_reg = VFE_NS_REG,
+	.md_reg = VFE_MD_REG,
+	.root_en_mask = BIT(2),
+	.ns_mask = (BM(23, 16) | BM(11, 10) | BM(2, 0)),
+	.mnd_en_mask = BIT(5),
+	.ctl_mask = BM(7, 6),
+	.set_rate = set_rate_mnd,
+	.freq_tbl = clk_tbl_vfe,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "vfe_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 110000000, NOMINAL, 266667000,
+				  HIGH, 320000000),
+		CLK_INIT(vfe_clk.c),
+		.depends = &vfe_axi_clk.c,
+	},
+};
+
+static struct branch_clk csi_vfe_clk = {
+	.b = {
+		.ctl_reg = VFE_CC_REG,
+		.en_mask = BIT(12),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(24),
+		.halt_reg = DBG_BUS_VEC_B_REG,
+		.halt_bit = 8,
+	},
+	.parent = &vfe_clk.c,
+	.c = {
+		.dbg_name = "csi_vfe_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi_vfe_clk.c),
+	},
+};
+
+/*
+ * Low Power Audio Clocks
+ */
+#define F_AIF_OSR(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD8(8, m, 0, n), \
+		.ns_val = NS(31, 24, n, m, 5, 4, 3, d, 2, 0, s##_to_lpa_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_aif_osr[] = {
+	F_AIF_OSR(       0, gnd,  1, 0,   0),
+	F_AIF_OSR(  512000, pll4, 4, 1, 192),
+	F_AIF_OSR(  768000, pll4, 4, 1, 128),
+	F_AIF_OSR( 1024000, pll4, 4, 1,  96),
+	F_AIF_OSR( 1536000, pll4, 4, 1,  64),
+	F_AIF_OSR( 2048000, pll4, 4, 1,  48),
+	F_AIF_OSR( 3072000, pll4, 4, 1,  32),
+	F_AIF_OSR( 4096000, pll4, 4, 1,  24),
+	F_AIF_OSR( 6144000, pll4, 4, 1,  16),
+	F_AIF_OSR( 8192000, pll4, 4, 1,  12),
+	F_AIF_OSR(12288000, pll4, 4, 1,   8),
+	F_AIF_OSR(24576000, pll4, 4, 1,   4),
+	F_END
+};
+
+#define CLK_AIF_OSR(i, ns, md, h_r) \
+	struct rcg_clk i##_clk = { \
+		.b = { \
+			.ctl_reg = ns, \
+			.en_mask = BIT(17), \
+			.reset_reg = ns, \
+			.reset_mask = BIT(19), \
+			.halt_reg = h_r, \
+			.halt_check = ENABLE, \
+			.halt_bit = 1, \
+		}, \
+		.ns_reg = ns, \
+		.md_reg = md, \
+		.root_en_mask = BIT(9), \
+		.ns_mask = (BM(31, 24) | BM(6, 0)), \
+		.mnd_en_mask = BIT(8), \
+		.set_rate = set_rate_mnd, \
+		.freq_tbl = clk_tbl_aif_osr, \
+		.current_freq = &rcg_dummy_freq, \
+		.c = { \
+			.dbg_name = #i "_clk", \
+			.ops = &clk_ops_rcg, \
+			VDD_DIG_FMAX_MAP1(LOW, 24576000), \
+			CLK_INIT(i##_clk.c), \
+		}, \
+	}
+#define CLK_AIF_OSR_DIV(i, ns, md, h_r) \
+	struct rcg_clk i##_clk = { \
+		.b = { \
+			.ctl_reg = ns, \
+			.en_mask = BIT(21), \
+			.reset_reg = ns, \
+			.reset_mask = BIT(23), \
+			.halt_reg = h_r, \
+			.halt_check = ENABLE, \
+			.halt_bit = 1, \
+		}, \
+		.ns_reg = ns, \
+		.md_reg = md, \
+		.root_en_mask = BIT(9), \
+		.ns_mask = (BM(31, 24) | BM(6, 0)), \
+		.mnd_en_mask = BIT(8), \
+		.set_rate = set_rate_mnd, \
+		.freq_tbl = clk_tbl_aif_osr, \
+		.current_freq = &rcg_dummy_freq, \
+		.c = { \
+			.dbg_name = #i "_clk", \
+			.ops = &clk_ops_rcg, \
+			VDD_DIG_FMAX_MAP1(LOW, 24576000), \
+			CLK_INIT(i##_clk.c), \
+		}, \
+	}
+
+#define CLK_AIF_BIT(i, ns, h_r) \
+	struct cdiv_clk i##_clk = { \
+		.b = { \
+			.ctl_reg = ns, \
+			.en_mask = BIT(15), \
+			.halt_reg = h_r, \
+			.halt_check = DELAY, \
+		}, \
+		.ns_reg = ns, \
+		.ext_mask = BIT(14), \
+		.div_offset = 10, \
+		.max_div = 16, \
+		.c = { \
+			.dbg_name = #i "_clk", \
+			.ops = &clk_ops_cdiv, \
+			CLK_INIT(i##_clk.c), \
+		}, \
+	}
+
+#define CLK_AIF_BIT_DIV(i, ns, h_r) \
+	struct cdiv_clk i##_clk = { \
+		.b = { \
+			.ctl_reg = ns, \
+			.en_mask = BIT(19), \
+			.halt_reg = h_r, \
+			.halt_check = DELAY, \
+		}, \
+		.ns_reg = ns, \
+		.ext_mask = BIT(18), \
+		.div_offset = 10, \
+		.max_div = 256, \
+		.c = { \
+			.dbg_name = #i "_clk", \
+			.ops = &clk_ops_cdiv, \
+			CLK_INIT(i##_clk.c), \
+		}, \
+	}
+
+static CLK_AIF_OSR(mi2s_osr, LCC_MI2S_NS_REG, LCC_MI2S_MD_REG,
+		LCC_MI2S_STATUS_REG);
+static CLK_AIF_BIT(mi2s_bit, LCC_MI2S_NS_REG, LCC_MI2S_STATUS_REG);
+
+static CLK_AIF_OSR_DIV(codec_i2s_mic_osr, LCC_CODEC_I2S_MIC_NS_REG,
+		LCC_CODEC_I2S_MIC_MD_REG, LCC_CODEC_I2S_MIC_STATUS_REG);
+static CLK_AIF_BIT_DIV(codec_i2s_mic_bit, LCC_CODEC_I2S_MIC_NS_REG,
+		LCC_CODEC_I2S_MIC_STATUS_REG);
+
+static CLK_AIF_OSR_DIV(spare_i2s_mic_osr, LCC_SPARE_I2S_MIC_NS_REG,
+		LCC_SPARE_I2S_MIC_MD_REG, LCC_SPARE_I2S_MIC_STATUS_REG);
+static CLK_AIF_BIT_DIV(spare_i2s_mic_bit, LCC_SPARE_I2S_MIC_NS_REG,
+		LCC_SPARE_I2S_MIC_STATUS_REG);
+
+static CLK_AIF_OSR_DIV(codec_i2s_spkr_osr, LCC_CODEC_I2S_SPKR_NS_REG,
+		LCC_CODEC_I2S_SPKR_MD_REG, LCC_CODEC_I2S_SPKR_STATUS_REG);
+static CLK_AIF_BIT_DIV(codec_i2s_spkr_bit, LCC_CODEC_I2S_SPKR_NS_REG,
+		LCC_CODEC_I2S_SPKR_STATUS_REG);
+
+static CLK_AIF_OSR_DIV(spare_i2s_spkr_osr, LCC_SPARE_I2S_SPKR_NS_REG,
+		LCC_SPARE_I2S_SPKR_MD_REG, LCC_SPARE_I2S_SPKR_STATUS_REG);
+static CLK_AIF_BIT_DIV(spare_i2s_spkr_bit, LCC_SPARE_I2S_SPKR_NS_REG,
+		LCC_SPARE_I2S_SPKR_STATUS_REG);
+
+#define F_PCM(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD16(m, n), \
+		.ns_val = NS(31, 16, n, m, 5, 4, 3, d, 2, 0, s##_to_lpa_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_pcm[] = {
+	{ .ns_val = BIT(10) /* external input */ },
+	F_PCM(  512000, pll4, 4, 1, 192),
+	F_PCM(  768000, pll4, 4, 1, 128),
+	F_PCM( 1024000, pll4, 4, 1,  96),
+	F_PCM( 1536000, pll4, 4, 1,  64),
+	F_PCM( 2048000, pll4, 4, 1,  48),
+	F_PCM( 3072000, pll4, 4, 1,  32),
+	F_PCM( 4096000, pll4, 4, 1,  24),
+	F_PCM( 6144000, pll4, 4, 1,  16),
+	F_PCM( 8192000, pll4, 4, 1,  12),
+	F_PCM(12288000, pll4, 4, 1,   8),
+	F_PCM(24576000, pll4, 4, 1,   4),
+	F_END
+};
+
+static struct rcg_clk pcm_clk = {
+	.b = {
+		.ctl_reg = LCC_PCM_NS_REG,
+		.en_mask = BIT(11),
+		.reset_reg = LCC_PCM_NS_REG,
+		.reset_mask = BIT(13),
+		.halt_reg = LCC_PCM_STATUS_REG,
+		.halt_check = ENABLE,
+		.halt_bit = 0,
+	},
+	.ns_reg = LCC_PCM_NS_REG,
+	.md_reg = LCC_PCM_MD_REG,
+	.root_en_mask = BIT(9),
+	.ns_mask = BM(31, 16) | BIT(10) | BM(6, 0),
+	.mnd_en_mask = BIT(8),
+	.set_rate = set_rate_mnd,
+	.freq_tbl = clk_tbl_pcm,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "pcm_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 24576000),
+		CLK_INIT(pcm_clk.c),
+	},
+};
+
+static struct rcg_clk audio_slimbus_clk = {
+	.b = {
+		.ctl_reg = LCC_SLIMBUS_NS_REG,
+		.en_mask = BIT(10),
+		.reset_reg = LCC_AHBEX_BRANCH_CTL_REG,
+		.reset_mask = BIT(5),
+		.halt_reg = LCC_SLIMBUS_STATUS_REG,
+		.halt_check = ENABLE,
+		.halt_bit = 0,
+	},
+	.ns_reg = LCC_SLIMBUS_NS_REG,
+	.md_reg = LCC_SLIMBUS_MD_REG,
+	.root_en_mask = BIT(9),
+	.ns_mask = (BM(31, 24) | BM(6, 0)),
+	.mnd_en_mask = BIT(8),
+	.set_rate = set_rate_mnd,
+	.freq_tbl = clk_tbl_aif_osr,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "audio_slimbus_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 24576000),
+		CLK_INIT(audio_slimbus_clk.c),
+	},
+};
+
+static struct branch_clk sps_slimbus_clk = {
+	.b = {
+		.ctl_reg = LCC_SLIMBUS_NS_REG,
+		.en_mask = BIT(12),
+		.halt_reg = LCC_SLIMBUS_STATUS_REG,
+		.halt_check = ENABLE,
+		.halt_bit = 1,
+	},
+	.parent = &audio_slimbus_clk.c,
+	.c = {
+		.dbg_name = "sps_slimbus_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sps_slimbus_clk.c),
+	},
+};
+
+static struct branch_clk slimbus_xo_src_clk = {
+	.b = {
+		.ctl_reg = SLIMBUS_XO_SRC_CLK_CTL_REG,
+		.en_mask = BIT(2),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 28,
+	},
+	.parent = &sps_slimbus_clk.c,
+	.c = {
+		.dbg_name = "slimbus_xo_src_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(slimbus_xo_src_clk.c),
+	},
+};
+
+DEFINE_CLK_RPM(afab_clk, afab_a_clk, APPS_FABRIC, NULL);
+DEFINE_CLK_RPM(cfpb_clk, cfpb_a_clk, CFPB, NULL);
+DEFINE_CLK_RPM(dfab_clk, dfab_a_clk, DAYTONA_FABRIC, NULL);
+DEFINE_CLK_RPM(ebi1_clk, ebi1_a_clk, EBI1, NULL);
+DEFINE_CLK_RPM(mmfab_clk, mmfab_a_clk, MM_FABRIC, NULL);
+DEFINE_CLK_RPM(mmfpb_clk, mmfpb_a_clk, MMFPB, NULL);
+DEFINE_CLK_RPM(sfab_clk, sfab_a_clk, SYSTEM_FABRIC, NULL);
+DEFINE_CLK_RPM(sfpb_clk, sfpb_a_clk, SFPB, NULL);
+
+static DEFINE_CLK_VOTER(sfab_msmbus_a_clk, &sfab_a_clk.c, 0);
+static DEFINE_CLK_VOTER(sfab_tmr_a_clk, &sfab_a_clk.c, 0);
+
+static DEFINE_CLK_VOTER(dfab_dsps_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_usb_hs_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_usb_hs3_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_usb_hs4_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_sdc1_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_sdc2_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_sdc3_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_sdc4_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_sdc5_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_sps_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_bam_dmux_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_scm_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_qseecom_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_tzcom_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_msmbus_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_msmbus_a_clk, &dfab_a_clk.c, 0);
+
+static DEFINE_CLK_VOTER(ebi1_msmbus_clk, &ebi1_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(ebi1_adm_clk, &ebi1_clk.c, 0);
+
+#ifdef CONFIG_DEBUG_FS
+struct measure_sel {
+	u32 test_vector;
+	struct clk *clk;
+};
+
+static DEFINE_CLK_MEASURE(l2_m_clk);
+static DEFINE_CLK_MEASURE(krait0_m_clk);
+static DEFINE_CLK_MEASURE(krait1_m_clk);
+static DEFINE_CLK_MEASURE(krait2_m_clk);
+static DEFINE_CLK_MEASURE(krait3_m_clk);
+static DEFINE_CLK_MEASURE(q6sw_clk);
+static DEFINE_CLK_MEASURE(q6fw_clk);
+static DEFINE_CLK_MEASURE(q6_func_clk);
+
+static struct measure_sel measure_mux[] = {
+	{ TEST_PER_LS(0x08), &slimbus_xo_src_clk.c },
+	{ TEST_PER_LS(0x12), &sdc1_p_clk.c },
+	{ TEST_PER_LS(0x13), &sdc1_clk.c },
+	{ TEST_PER_LS(0x14), &sdc2_p_clk.c },
+	{ TEST_PER_LS(0x15), &sdc2_clk.c },
+	{ TEST_PER_LS(0x16), &sdc3_p_clk.c },
+	{ TEST_PER_LS(0x17), &sdc3_clk.c },
+	{ TEST_PER_LS(0x18), &sdc4_p_clk.c },
+	{ TEST_PER_LS(0x19), &sdc4_clk.c },
+	{ TEST_PER_LS(0x1A), &sdc5_p_clk.c },
+	{ TEST_PER_LS(0x1B), &sdc5_clk.c },
+	{ TEST_PER_LS(0x1F), &gp0_clk.c },
+	{ TEST_PER_LS(0x20), &gp1_clk.c },
+	{ TEST_PER_LS(0x21), &gp2_clk.c },
+	{ TEST_PER_LS(0x25), &dfab_clk.c },
+	{ TEST_PER_LS(0x25), &dfab_a_clk.c },
+	{ TEST_PER_LS(0x26), &pmem_clk.c },
+	{ TEST_PER_LS(0x32), &dma_bam_p_clk.c },
+	{ TEST_PER_LS(0x33), &cfpb_clk.c },
+	{ TEST_PER_LS(0x33), &cfpb_a_clk.c },
+	{ TEST_PER_LS(0x3D), &gsbi1_p_clk.c },
+	{ TEST_PER_LS(0x3E), &gsbi1_uart_clk.c },
+	{ TEST_PER_LS(0x3F), &gsbi1_qup_clk.c },
+	{ TEST_PER_LS(0x41), &gsbi2_p_clk.c },
+	{ TEST_PER_LS(0x42), &gsbi2_uart_clk.c },
+	{ TEST_PER_LS(0x44), &gsbi2_qup_clk.c },
+	{ TEST_PER_LS(0x45), &gsbi3_p_clk.c },
+	{ TEST_PER_LS(0x46), &gsbi3_uart_clk.c },
+	{ TEST_PER_LS(0x48), &gsbi3_qup_clk.c },
+	{ TEST_PER_LS(0x49), &gsbi4_p_clk.c },
+	{ TEST_PER_LS(0x4A), &gsbi4_uart_clk.c },
+	{ TEST_PER_LS(0x4C), &gsbi4_qup_clk.c },
+	{ TEST_PER_LS(0x4D), &gsbi5_p_clk.c },
+	{ TEST_PER_LS(0x4E), &gsbi5_uart_clk.c },
+	{ TEST_PER_LS(0x50), &gsbi5_qup_clk.c },
+	{ TEST_PER_LS(0x51), &gsbi6_p_clk.c },
+	{ TEST_PER_LS(0x52), &gsbi6_uart_clk.c },
+	{ TEST_PER_LS(0x54), &gsbi6_qup_clk.c },
+	{ TEST_PER_LS(0x55), &gsbi7_p_clk.c },
+	{ TEST_PER_LS(0x56), &gsbi7_uart_clk.c },
+	{ TEST_PER_LS(0x58), &gsbi7_qup_clk.c },
+	{ TEST_PER_LS(0x59), &gsbi8_p_clk.c },
+	{ TEST_PER_LS(0x59), &sfab_sata_s_p_clk.c },
+	{ TEST_PER_LS(0x5A), &gsbi8_uart_clk.c },
+	{ TEST_PER_LS(0x5A), &sata_p_clk.c },
+	{ TEST_PER_LS(0x5B), &sata_rxoob_clk.c },
+	{ TEST_PER_LS(0x5C), &sata_pmalive_clk.c },
+	{ TEST_PER_LS(0x5C), &gsbi8_qup_clk.c },
+	{ TEST_PER_LS(0x5D), &gsbi9_p_clk.c },
+	{ TEST_PER_LS(0x5E), &gsbi9_uart_clk.c },
+	{ TEST_PER_LS(0x60), &gsbi9_qup_clk.c },
+	{ TEST_PER_LS(0x61), &gsbi10_p_clk.c },
+	{ TEST_PER_LS(0x62), &gsbi10_uart_clk.c },
+	{ TEST_PER_LS(0x64), &gsbi10_qup_clk.c },
+	{ TEST_PER_LS(0x65), &gsbi11_p_clk.c },
+	{ TEST_PER_LS(0x66), &gsbi11_uart_clk.c },
+	{ TEST_PER_LS(0x68), &gsbi11_qup_clk.c },
+	{ TEST_PER_LS(0x69), &gsbi12_p_clk.c },
+	{ TEST_PER_LS(0x6A), &gsbi12_uart_clk.c },
+	{ TEST_PER_LS(0x6C), &gsbi12_qup_clk.c },
+	{ TEST_PER_LS(0x5E), &pcie_p_clk.c },
+	{ TEST_PER_LS(0x5F), &ce3_p_clk.c },
+	{ TEST_PER_LS(0x60), &ce3_core_clk.c },
+	{ TEST_PER_LS(0x63), &usb_hs3_p_clk.c },
+	{ TEST_PER_LS(0x64), &usb_hs3_xcvr_clk.c },
+	{ TEST_PER_LS(0x65), &usb_hs4_p_clk.c },
+	{ TEST_PER_LS(0x66), &usb_hs4_xcvr_clk.c },
+	{ TEST_PER_LS(0x6B), &sata_phy_ref_clk.c },
+	{ TEST_PER_LS(0x6C), &sata_phy_cfg_clk.c },
+	{ TEST_PER_LS(0x78), &sfpb_clk.c },
+	{ TEST_PER_LS(0x78), &sfpb_a_clk.c },
+	{ TEST_PER_LS(0x7A), &pmic_ssbi2_clk.c },
+	{ TEST_PER_LS(0x7B), &pmic_arb0_p_clk.c },
+	{ TEST_PER_LS(0x7C), &pmic_arb1_p_clk.c },
+	{ TEST_PER_LS(0x7D), &prng_clk.c },
+	{ TEST_PER_LS(0x7F), &rpm_msg_ram_p_clk.c },
+	{ TEST_PER_LS(0x80), &adm0_p_clk.c },
+	{ TEST_PER_LS(0x84), &usb_hs1_p_clk.c },
+	{ TEST_PER_LS(0x85), &usb_hs1_xcvr_clk.c },
+	{ TEST_PER_LS(0x86), &usb_hsic_p_clk.c },
+	{ TEST_PER_LS(0x87), &usb_hsic_system_clk.c },
+	{ TEST_PER_LS(0x88), &usb_hsic_xcvr_fs_clk.c },
+	{ TEST_PER_LS(0x89), &usb_fs1_p_clk.c },
+	{ TEST_PER_LS(0x8A), &usb_fs1_sys_clk.c },
+	{ TEST_PER_LS(0x8B), &usb_fs1_xcvr_clk.c },
+	{ TEST_PER_LS(0x8C), &usb_fs2_p_clk.c },
+	{ TEST_PER_LS(0x8D), &usb_fs2_sys_clk.c },
+	{ TEST_PER_LS(0x8E), &usb_fs2_xcvr_clk.c },
+	{ TEST_PER_LS(0x8F), &tsif_p_clk.c },
+	{ TEST_PER_LS(0x91), &tsif_ref_clk.c },
+	{ TEST_PER_LS(0x92), &ce1_p_clk.c },
+	{ TEST_PER_LS(0x94), &tssc_clk.c },
+	{ TEST_PER_LS(0x9D), &usb_hsic_hsio_cal_clk.c },
+	{ TEST_PER_LS(0xA4), &ce1_core_clk.c },
+
+	{ TEST_PER_HS(0x07), &afab_clk.c },
+	{ TEST_PER_HS(0x07), &afab_a_clk.c },
+	{ TEST_PER_HS(0x18), &sfab_clk.c },
+	{ TEST_PER_HS(0x18), &sfab_a_clk.c },
+	{ TEST_PER_HS(0x26), &q6sw_clk },
+	{ TEST_PER_HS(0x27), &q6fw_clk },
+	{ TEST_PER_HS(0x2A), &adm0_clk.c },
+	{ TEST_PER_HS(0x31), &sata_a_clk.c },
+	{ TEST_PER_HS(0x2D), &pcie_phy_ref_clk.c },
+	{ TEST_PER_HS(0x32), &pcie_a_clk.c },
+	{ TEST_PER_HS(0x34), &ebi1_clk.c },
+	{ TEST_PER_HS(0x34), &ebi1_a_clk.c },
+	{ TEST_PER_HS(0x50), &usb_hsic_hsic_clk.c },
+
+	{ TEST_MM_LS(0x00), &dsi1_byte_clk.c },
+	{ TEST_MM_LS(0x01), &dsi2_byte_clk.c },
+	{ TEST_MM_LS(0x02), &cam1_clk.c },
+	{ TEST_MM_LS(0x06), &amp_p_clk.c },
+	{ TEST_MM_LS(0x07), &csi_p_clk.c },
+	{ TEST_MM_LS(0x08), &dsi2_s_p_clk.c },
+	{ TEST_MM_LS(0x09), &dsi1_m_p_clk.c },
+	{ TEST_MM_LS(0x0A), &dsi1_s_p_clk.c },
+	{ TEST_MM_LS(0x0C), &gfx2d0_p_clk.c },
+	{ TEST_MM_LS(0x0D), &gfx2d1_p_clk.c },
+	{ TEST_MM_LS(0x0E), &gfx3d_p_clk.c },
+	{ TEST_MM_LS(0x0F), &hdmi_m_p_clk.c },
+	{ TEST_MM_LS(0x10), &hdmi_s_p_clk.c },
+	{ TEST_MM_LS(0x11), &ijpeg_p_clk.c },
+	{ TEST_MM_LS(0x12), &imem_p_clk.c },
+	{ TEST_MM_LS(0x13), &jpegd_p_clk.c },
+	{ TEST_MM_LS(0x14), &mdp_p_clk.c },
+	{ TEST_MM_LS(0x16), &rot_p_clk.c },
+	{ TEST_MM_LS(0x17), &dsi1_esc_clk.c },
+	{ TEST_MM_LS(0x18), &smmu_p_clk.c },
+	{ TEST_MM_LS(0x19), &tv_enc_p_clk.c },
+	{ TEST_MM_LS(0x1A), &vcodec_p_clk.c },
+	{ TEST_MM_LS(0x1B), &vfe_p_clk.c },
+	{ TEST_MM_LS(0x1C), &vpe_p_clk.c },
+	{ TEST_MM_LS(0x1D), &cam0_clk.c },
+	{ TEST_MM_LS(0x1F), &hdmi_app_clk.c },
+	{ TEST_MM_LS(0x20), &mdp_vsync_clk.c },
+	{ TEST_MM_LS(0x21), &tv_dac_clk.c },
+	{ TEST_MM_LS(0x22), &tv_enc_clk.c },
+	{ TEST_MM_LS(0x23), &dsi2_esc_clk.c },
+	{ TEST_MM_LS(0x25), &mmfpb_clk.c },
+	{ TEST_MM_LS(0x25), &mmfpb_a_clk.c },
+	{ TEST_MM_LS(0x26), &dsi2_m_p_clk.c },
+	{ TEST_MM_LS(0x27), &cam2_clk.c },
+	{ TEST_MM_LS(0x28), &vcap_p_clk.c },
+
+	{ TEST_MM_HS(0x00), &csi0_clk.c },
+	{ TEST_MM_HS(0x01), &csi1_clk.c },
+	{ TEST_MM_HS(0x04), &csi_vfe_clk.c },
+	{ TEST_MM_HS(0x05), &ijpeg_clk.c },
+	{ TEST_MM_HS(0x06), &vfe_clk.c },
+	{ TEST_MM_HS(0x07), &gfx2d0_clk.c },
+	{ TEST_MM_HS(0x08), &gfx2d1_clk.c },
+	{ TEST_MM_HS(0x09), &gfx3d_clk.c },
+	{ TEST_MM_HS(0x0A), &jpegd_clk.c },
+	{ TEST_MM_HS(0x0B), &vcodec_clk.c },
+	{ TEST_MM_HS(0x0F), &mmfab_clk.c },
+	{ TEST_MM_HS(0x0F), &mmfab_a_clk.c },
+	{ TEST_MM_HS(0x11), &gmem_axi_clk.c },
+	{ TEST_MM_HS(0x12), &ijpeg_axi_clk.c },
+	{ TEST_MM_HS(0x13), &imem_axi_clk.c },
+	{ TEST_MM_HS(0x14), &jpegd_axi_clk.c },
+	{ TEST_MM_HS(0x15), &mdp_axi_clk.c },
+	{ TEST_MM_HS(0x16), &rot_axi_clk.c },
+	{ TEST_MM_HS(0x17), &vcodec_axi_clk.c },
+	{ TEST_MM_HS(0x18), &vfe_axi_clk.c },
+	{ TEST_MM_HS(0x19), &vpe_axi_clk.c },
+	{ TEST_MM_HS(0x1A), &mdp_clk.c },
+	{ TEST_MM_HS(0x1B), &rot_clk.c },
+	{ TEST_MM_HS(0x1C), &vpe_clk.c },
+	{ TEST_MM_HS(0x1E), &hdmi_tv_clk.c },
+	{ TEST_MM_HS(0x1F), &mdp_tv_clk.c },
+	{ TEST_MM_HS(0x24), &csi0_phy_clk.c },
+	{ TEST_MM_HS(0x25), &csi1_phy_clk.c },
+	{ TEST_MM_HS(0x26), &csi_pix_clk.c },
+	{ TEST_MM_HS(0x27), &csi_rdi_clk.c },
+	{ TEST_MM_HS(0x28), &lut_mdp_clk.c },
+	{ TEST_MM_HS(0x29), &vcodec_axi_a_clk.c },
+	{ TEST_MM_HS(0x2A), &vcodec_axi_b_clk.c },
+	{ TEST_MM_HS(0x2B), &csi1phy_timer_clk.c },
+	{ TEST_MM_HS(0x2C), &csi0phy_timer_clk.c },
+	{ TEST_MM_HS(0x2D), &csi2_clk.c },
+	{ TEST_MM_HS(0x2E), &csi2_phy_clk.c },
+	{ TEST_MM_HS(0x2F), &csi2phy_timer_clk.c },
+	{ TEST_MM_HS(0x30), &csi_pix1_clk.c },
+	{ TEST_MM_HS(0x31), &csi_rdi1_clk.c },
+	{ TEST_MM_HS(0x32), &csi_rdi2_clk.c },
+	{ TEST_MM_HS(0x33), &vcap_clk.c },
+	{ TEST_MM_HS(0x34), &vcap_npl_clk.c },
+	{ TEST_MM_HS(0x34), &gfx3d_axi_clk_8930.c },
+	{ TEST_MM_HS(0x35), &vcap_axi_clk.c },
+	{ TEST_MM_HS(0x36), &rgb_tv_clk.c },
+	{ TEST_MM_HS(0x37), &npl_tv_clk.c },
+	{ TEST_MM_HS(0x38), &gfx3d_axi_clk_8064.c },
+
+	{ TEST_LPA(0x0F), &mi2s_bit_clk.c },
+	{ TEST_LPA(0x10), &codec_i2s_mic_bit_clk.c },
+	{ TEST_LPA(0x11), &codec_i2s_spkr_bit_clk.c },
+	{ TEST_LPA(0x12), &spare_i2s_mic_bit_clk.c },
+	{ TEST_LPA(0x13), &spare_i2s_spkr_bit_clk.c },
+	{ TEST_LPA(0x14), &pcm_clk.c },
+	{ TEST_LPA(0x1D), &audio_slimbus_clk.c },
+
+	{ TEST_LPA_HS(0x00), &q6_func_clk },
+
+	{ TEST_CPUL2(0x2), &l2_m_clk },
+	{ TEST_CPUL2(0x0), &krait0_m_clk },
+	{ TEST_CPUL2(0x1), &krait1_m_clk },
+	{ TEST_CPUL2(0x4), &krait2_m_clk },
+	{ TEST_CPUL2(0x5), &krait3_m_clk },
+};
+
+static struct measure_sel *find_measure_sel(struct clk *clk)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(measure_mux); i++)
+		if (measure_mux[i].clk == clk)
+			return &measure_mux[i];
+	return NULL;
+}
+
+static int measure_clk_set_parent(struct clk *c, struct clk *parent)
+{
+	int ret = 0;
+	u32 clk_sel;
+	struct measure_sel *p;
+	struct measure_clk *clk = to_measure_clk(c);
+	unsigned long flags;
+
+	if (!parent)
+		return -EINVAL;
+
+	p = find_measure_sel(parent);
+	if (!p)
+		return -EINVAL;
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+
+	/*
+	 * Program the test vector, measurement period (sample_ticks)
+	 * and scaling multiplier.
+	 */
+	clk->sample_ticks = 0x10000;
+	clk_sel = p->test_vector & TEST_CLK_SEL_MASK;
+	clk->multiplier = 1;
+	switch (p->test_vector >> TEST_TYPE_SHIFT) {
+	case TEST_TYPE_PER_LS:
+		writel_relaxed(0x4030D00|BVAL(7, 0, clk_sel), CLK_TEST_REG);
+		break;
+	case TEST_TYPE_PER_HS:
+		writel_relaxed(0x4020000|BVAL(16, 10, clk_sel), CLK_TEST_REG);
+		break;
+	case TEST_TYPE_MM_LS:
+		writel_relaxed(0x4030D97, CLK_TEST_REG);
+		writel_relaxed(BVAL(6, 1, clk_sel)|BIT(0), DBG_CFG_REG_LS_REG);
+		break;
+	case TEST_TYPE_MM_HS:
+		writel_relaxed(0x402B800, CLK_TEST_REG);
+		writel_relaxed(BVAL(6, 1, clk_sel)|BIT(0), DBG_CFG_REG_HS_REG);
+		break;
+	case TEST_TYPE_LPA:
+		writel_relaxed(0x4030D98, CLK_TEST_REG);
+		writel_relaxed(BVAL(6, 1, clk_sel)|BIT(0),
+				LCC_CLK_LS_DEBUG_CFG_REG);
+		break;
+	case TEST_TYPE_LPA_HS:
+		writel_relaxed(0x402BC00, CLK_TEST_REG);
+		writel_relaxed(BVAL(2, 1, clk_sel)|BIT(0),
+				LCC_CLK_HS_DEBUG_CFG_REG);
+		break;
+	case TEST_TYPE_CPUL2:
+		writel_relaxed(0x4030400, CLK_TEST_REG);
+		writel_relaxed(0x80|BVAL(5, 3, clk_sel), GCC_APCS_CLK_DIAG);
+		clk->sample_ticks = 0x4000;
+		clk->multiplier = 2;
+		break;
+	default:
+		ret = -EPERM;
+	}
+	/* Make sure test vector is set before starting measurements. */
+	mb();
+
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	return ret;
+}
+
+/* Sample clock for 'ticks' reference clock ticks. */
+static u32 run_measurement(unsigned ticks)
+{
+	/* Stop counters and set the XO4 counter start value. */
+	writel_relaxed(ticks, RINGOSC_TCXO_CTL_REG);
+
+	/* Wait for timer to become ready. */
+	while ((readl_relaxed(RINGOSC_STATUS_REG) & BIT(25)) != 0)
+		cpu_relax();
+
+	/* Run measurement and wait for completion. */
+	writel_relaxed(BIT(20)|ticks, RINGOSC_TCXO_CTL_REG);
+	while ((readl_relaxed(RINGOSC_STATUS_REG) & BIT(25)) == 0)
+		cpu_relax();
+
+	/* Stop counters. */
+	writel_relaxed(0x0, RINGOSC_TCXO_CTL_REG);
+
+	/* Return measured ticks. */
+	return readl_relaxed(RINGOSC_STATUS_REG) & BM(24, 0);
+}
+
+
+/* Perform a hardware rate measurement for a given clock.
+   FOR DEBUG USE ONLY: Measurements take ~15 ms! */
+static unsigned long measure_clk_get_rate(struct clk *c)
+{
+	unsigned long flags;
+	u32 pdm_reg_backup, ringosc_reg_backup;
+	u64 raw_count_short, raw_count_full;
+	struct measure_clk *clk = to_measure_clk(c);
+	unsigned ret;
+
+	ret = clk_prepare_enable(&cxo_clk.c);
+	if (ret) {
+		pr_warning("CXO clock failed to enable. Can't measure\n");
+		return 0;
+	}
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+
+	/* Enable CXO/4 and RINGOSC branch and root. */
+	pdm_reg_backup = readl_relaxed(PDM_CLK_NS_REG);
+	ringosc_reg_backup = readl_relaxed(RINGOSC_NS_REG);
+	writel_relaxed(0x2898, PDM_CLK_NS_REG);
+	writel_relaxed(0xA00, RINGOSC_NS_REG);
+
+	/*
+	 * The ring oscillator counter will not reset if the measured clock
+	 * is not running.  To detect this, run a short measurement before
+	 * the full measurement.  If the raw results of the two are the same
+	 * then the clock must be off.
+	 */
+
+	/* Run a short measurement. (~1 ms) */
+	raw_count_short = run_measurement(0x1000);
+	/* Run a full measurement. (~14 ms) */
+	raw_count_full = run_measurement(clk->sample_ticks);
+
+	writel_relaxed(ringosc_reg_backup, RINGOSC_NS_REG);
+	writel_relaxed(pdm_reg_backup, PDM_CLK_NS_REG);
+
+	/* Return 0 if the clock is off. */
+	if (raw_count_full == raw_count_short)
+		ret = 0;
+	else {
+		/* Compute rate in Hz. */
+		raw_count_full = ((raw_count_full * 10) + 15) * 4800000;
+		do_div(raw_count_full, ((clk->sample_ticks * 10) + 35));
+		ret = (raw_count_full * clk->multiplier);
+	}
+
+	/* Route dbg_hs_clk to PLLTEST.  300mV single-ended amplitude. */
+	writel_relaxed(0x38F8, PLLTEST_PAD_CFG_REG);
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	clk_disable_unprepare(&cxo_clk.c);
+
+	return ret;
+}
+#else /* !CONFIG_DEBUG_FS */
+static int measure_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	return -EINVAL;
+}
+
+static unsigned long measure_clk_get_rate(struct clk *clk)
+{
+	return 0;
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static struct clk_ops clk_ops_measure = {
+	.set_parent = measure_clk_set_parent,
+	.get_rate = measure_clk_get_rate,
+};
+
+static struct measure_clk measure_clk = {
+	.c = {
+		.dbg_name = "measure_clk",
+		.ops = &clk_ops_measure,
+		CLK_INIT(measure_clk.c),
+	},
+	.multiplier = 1,
+};
+
+static struct clk_lookup msm_clocks_8064[] = {
+	CLK_LOOKUP("xo",		cxo_a_clk.c,	""),
+	CLK_LOOKUP("xo",		pxo_a_clk.c,	""),
+	CLK_LOOKUP("cxo",		cxo_clk.c,	"wcnss_wlan.0"),
+	CLK_LOOKUP("cxo",		cxo_clk.c,	"pil_riva"),
+	CLK_LOOKUP("xo",		pxo_clk.c,	"pil_qdsp6v4.0"),
+	CLK_LOOKUP("xo",		cxo_clk.c,	"pil_qdsp6v4.1"),
+	CLK_LOOKUP("xo",		cxo_clk.c,	"pil_qdsp6v4.2"),
+	CLK_LOOKUP("xo",		cxo_clk.c,	"pil_gss"),
+	CLK_LOOKUP("xo",		cxo_clk.c,	"BAM_RMNT"),
+	CLK_LOOKUP("xo",		cxo_clk.c,	"msm_xo"),
+	CLK_LOOKUP("pll2",		pll2_clk.c,	NULL),
+	CLK_LOOKUP("pll8",		pll8_clk.c,	NULL),
+	CLK_LOOKUP("pll4",		pll4_clk.c,	NULL),
+	CLK_LOOKUP("measure",		measure_clk.c,	"debug"),
+
+	CLK_LOOKUP("bus_clk",		afab_clk.c,		"msm_apps_fab"),
+	CLK_LOOKUP("bus_a_clk",		afab_a_clk.c,		"msm_apps_fab"),
+	CLK_LOOKUP("bus_clk",		cfpb_clk.c,		"msm_cpss_fpb"),
+	CLK_LOOKUP("bus_a_clk",		cfpb_a_clk.c,		"msm_cpss_fpb"),
+	CLK_LOOKUP("bus_clk",		sfab_clk.c,		"msm_sys_fab"),
+	CLK_LOOKUP("bus_a_clk",		sfab_msmbus_a_clk.c,	"msm_sys_fab"),
+	CLK_LOOKUP("bus_clk",		sfpb_clk.c,		"msm_sys_fpb"),
+	CLK_LOOKUP("bus_a_clk",		sfpb_a_clk.c,		"msm_sys_fpb"),
+	CLK_LOOKUP("bus_clk",		mmfab_clk.c,		"msm_mm_fab"),
+	CLK_LOOKUP("bus_a_clk",		mmfab_a_clk.c,		"msm_mm_fab"),
+	CLK_LOOKUP("mem_clk",		ebi1_msmbus_clk.c,	"msm_bus"),
+	CLK_LOOKUP("mem_a_clk",		ebi1_a_clk.c,		"msm_bus"),
+	CLK_LOOKUP("dfab_clk",		dfab_msmbus_clk.c,	"msm_bus"),
+	CLK_LOOKUP("dfab_a_clk",	dfab_msmbus_a_clk.c,	"msm_bus"),
+
+	CLK_LOOKUP("ebi1_clk",		ebi1_clk.c,		""),
+	CLK_LOOKUP("mmfpb_clk",		mmfpb_clk.c,		""),
+	CLK_LOOKUP("mmfpb_a_clk",	mmfpb_a_clk.c,		"clock-8960"),
+	CLK_LOOKUP("cfpb_a_clk",	cfpb_a_clk.c,		"clock-8960"),
+
+	CLK_LOOKUP("core_clk",		gp0_clk.c,		""),
+	CLK_LOOKUP("core_clk",		gp1_clk.c,		""),
+	CLK_LOOKUP("core_clk",		gp2_clk.c,		""),
+	CLK_LOOKUP("core_clk",		gsbi1_uart_clk.c, "msm_serial_hsl.1"),
+	CLK_LOOKUP("core_clk",		gsbi2_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi3_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi4_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi5_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi6_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi7_uart_clk.c, "msm_serial_hsl.0"),
+	CLK_LOOKUP("core_clk",		gsbi1_qup_clk.c,	"qup_i2c.0"),
+	CLK_LOOKUP("core_clk",		gsbi2_qup_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi3_qup_clk.c,	"qup_i2c.3"),
+	CLK_LOOKUP("core_clk",		gsbi4_qup_clk.c,	"qup_i2c.4"),
+	CLK_LOOKUP("core_clk",		gsbi5_qup_clk.c,	"spi_qsd.0"),
+	CLK_LOOKUP("core_clk",		gsbi5_qup_clk.c,	"qup_i2c.5"),
+	CLK_LOOKUP("core_clk",		gsbi6_qup_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi7_qup_clk.c,	""),
+	CLK_LOOKUP("core_clk",		pdm_clk.c,		""),
+	CLK_LOOKUP("mem_clk",		pmem_clk.c,		"msm_sps"),
+	CLK_LOOKUP("core_clk",          prng_clk.c,		"msm_rng.0"),
+	CLK_LOOKUP("core_clk",		sdc1_clk.c,		"msm_sdcc.1"),
+	CLK_LOOKUP("core_clk",		sdc2_clk.c,		"msm_sdcc.2"),
+	CLK_LOOKUP("core_clk",		sdc3_clk.c,		"msm_sdcc.3"),
+	CLK_LOOKUP("core_clk",		sdc4_clk.c,		"msm_sdcc.4"),
+	CLK_LOOKUP("ref_clk",		tsif_ref_clk.c,		""),
+	CLK_LOOKUP("core_clk",		tssc_clk.c,		""),
+	CLK_LOOKUP("alt_core_clk",	usb_hs1_xcvr_clk.c,	"msm_otg"),
+	CLK_LOOKUP("alt_core_clk",      usb_hs3_xcvr_clk.c,  "msm_ehci_host.0"),
+	CLK_LOOKUP("alt_core_clk",      usb_hs4_xcvr_clk.c,  "msm_ehci_host.1"),
+	CLK_LOOKUP("src_clk",		usb_fs1_src_clk.c,	""),
+	CLK_LOOKUP("alt_core_clk",	usb_fs1_xcvr_clk.c,	""),
+	CLK_LOOKUP("sys_clk",		usb_fs1_sys_clk.c,	""),
+	CLK_LOOKUP("ref_clk",		sata_phy_ref_clk.c,	""),
+	CLK_LOOKUP("cfg_clk",		sata_phy_cfg_clk.c,	""),
+	CLK_LOOKUP("src_clk",		sata_src_clk.c,		""),
+	CLK_LOOKUP("core_rxoob_clk",	sata_rxoob_clk.c,	""),
+	CLK_LOOKUP("core_pmalive_clk",	sata_pmalive_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		sata_a_clk.c,		""),
+	CLK_LOOKUP("iface_clk",		sata_p_clk.c,		""),
+	CLK_LOOKUP("slave_iface_clk",	sfab_sata_s_p_clk.c,	""),
+	CLK_LOOKUP("iface_clk",		ce3_p_clk.c,		"qce.0"),
+	CLK_LOOKUP("iface_clk",		ce3_p_clk.c,		"qcrypto.0"),
+	CLK_LOOKUP("core_clk",		ce3_core_clk.c,		"qce.0"),
+	CLK_LOOKUP("core_clk",		ce3_core_clk.c,		"qcrypto.0"),
+	CLK_LOOKUP("ce3_core_src_clk",	ce3_src_clk.c,		"qce.0"),
+	CLK_LOOKUP("ce3_core_src_clk",	ce3_src_clk.c,		"qcrypto.0"),
+	CLK_LOOKUP("dma_bam_pclk",	dma_bam_p_clk.c,	NULL),
+	CLK_LOOKUP("iface_clk",		gsbi1_p_clk.c,	"msm_serial_hsl.1"),
+	CLK_LOOKUP("iface_clk",		gsbi1_p_clk.c,	"qup_i2c.0"),
+	CLK_LOOKUP("iface_clk",		gsbi2_p_clk.c,		""),
+	CLK_LOOKUP("iface_clk",		gsbi3_p_clk.c,		"qup_i2c.3"),
+	CLK_LOOKUP("iface_clk",		gsbi4_p_clk.c,		"qup_i2c.4"),
+	CLK_LOOKUP("iface_clk",		gsbi5_p_clk.c,		"spi_qsd.0"),
+	CLK_LOOKUP("iface_clk",		gsbi5_p_clk.c,		"qup_i2c.5"),
+	CLK_LOOKUP("iface_clk",		gsbi6_p_clk.c,		""),
+	CLK_LOOKUP("iface_clk",		gsbi7_p_clk.c,	"msm_serial_hsl.0"),
+	CLK_LOOKUP("iface_clk",		tsif_p_clk.c,		""),
+	CLK_LOOKUP("iface_clk",		usb_fs1_p_clk.c,	""),
+	CLK_LOOKUP("iface_clk",		usb_hs1_p_clk.c,	"msm_otg"),
+	CLK_LOOKUP("iface_clk",         usb_hs3_p_clk.c,     "msm_ehci_host.0"),
+	CLK_LOOKUP("iface_clk",         usb_hs4_p_clk.c,     "msm_ehci_host.1"),
+	CLK_LOOKUP("iface_clk",		sdc1_p_clk.c,		"msm_sdcc.1"),
+	CLK_LOOKUP("iface_clk",		sdc2_p_clk.c,		"msm_sdcc.2"),
+	CLK_LOOKUP("iface_clk",		sdc3_p_clk.c,		"msm_sdcc.3"),
+	CLK_LOOKUP("iface_clk",		sdc4_p_clk.c,		"msm_sdcc.4"),
+	CLK_LOOKUP("iface_clk",		pcie_p_clk.c,		"msm_pcie"),
+	CLK_LOOKUP("ref_clk",		pcie_phy_ref_clk.c,	"msm_pcie"),
+	CLK_LOOKUP("bus_clk",		pcie_a_clk.c,		"msm_pcie"),
+	CLK_LOOKUP("core_clk",		adm0_clk.c,		"msm_dmov"),
+	CLK_LOOKUP("iface_clk",		adm0_p_clk.c,		"msm_dmov"),
+	CLK_LOOKUP("iface_clk",		pmic_arb0_p_clk.c,	""),
+	CLK_LOOKUP("iface_clk",		pmic_arb1_p_clk.c,	""),
+	CLK_LOOKUP("core_clk",		pmic_ssbi2_clk.c,	""),
+	CLK_LOOKUP("mem_clk",		rpm_msg_ram_p_clk.c,	""),
+	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-001a"),
+	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-0034"),
+	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-0020"),
+	CLK_LOOKUP("cam_clk",		cam1_clk.c,	"4-0048"),
+	CLK_LOOKUP("cam_clk",		cam1_clk.c,	"4-006c"),
+	CLK_LOOKUP("csi_src_clk",	csi0_src_clk.c,		"msm_csid.0"),
+	CLK_LOOKUP("csi_src_clk",	csi1_src_clk.c,		"msm_csid.1"),
+	CLK_LOOKUP("csi_src_clk",	csi2_src_clk.c,		"msm_csid.2"),
+	CLK_LOOKUP("csi_clk",		csi0_clk.c,		"msm_csid.0"),
+	CLK_LOOKUP("csi_clk",		csi1_clk.c,		"msm_csid.1"),
+	CLK_LOOKUP("csi_clk",		csi2_clk.c,		"msm_csid.2"),
+	CLK_LOOKUP("csi_phy_clk",	csi0_phy_clk.c,		"msm_csid.0"),
+	CLK_LOOKUP("csi_phy_clk",	csi1_phy_clk.c,		"msm_csid.1"),
+	CLK_LOOKUP("csi_phy_clk",	csi2_phy_clk.c,		"msm_csid.2"),
+	CLK_LOOKUP("csi_pix_clk",	csi_pix_clk.c,		"msm_ispif.0"),
+	CLK_LOOKUP("csi_pix1_clk",	csi_pix1_clk.c,		"msm_ispif.0"),
+	CLK_LOOKUP("csi_rdi_clk",	csi_rdi_clk.c,		"msm_ispif.0"),
+	CLK_LOOKUP("csi_rdi1_clk",	csi_rdi1_clk.c,		"msm_ispif.0"),
+	CLK_LOOKUP("csi_rdi2_clk",	csi_rdi2_clk.c,		"msm_ispif.0"),
+	CLK_LOOKUP("csiphy_timer_src_clk",
+			   csiphy_timer_src_clk.c, "msm_csiphy.0"),
+	CLK_LOOKUP("csiphy_timer_src_clk",
+			   csiphy_timer_src_clk.c, "msm_csiphy.1"),
+	CLK_LOOKUP("csiphy_timer_src_clk",
+			   csiphy_timer_src_clk.c, "msm_csiphy.2"),
+	CLK_LOOKUP("csiphy_timer_clk",	csi0phy_timer_clk.c,	"msm_csiphy.0"),
+	CLK_LOOKUP("csiphy_timer_clk",	csi1phy_timer_clk.c,	"msm_csiphy.1"),
+	CLK_LOOKUP("csiphy_timer_clk",	csi2phy_timer_clk.c,	"msm_csiphy.2"),
+	CLK_LOOKUP("byte_clk",	dsi1_byte_clk.c,	"mipi_dsi.1"),
+	CLK_LOOKUP("byte_clk",	dsi2_byte_clk.c,	"mipi_dsi.2"),
+	CLK_LOOKUP("esc_clk",	dsi1_esc_clk.c,		"mipi_dsi.1"),
+	CLK_LOOKUP("esc_clk",	dsi2_esc_clk.c,		"mipi_dsi.2"),
+	CLK_LOOKUP("rgb_clk",		rgb_tv_clk.c,		""),
+	CLK_LOOKUP("npl_clk",		npl_tv_clk.c,		""),
+
+	CLK_LOOKUP("core_clk",		gfx3d_clk.c,	"kgsl-3d0.0"),
+	CLK_LOOKUP("core_clk",		gfx3d_clk.c,	"footswitch-8x60.2"),
+	CLK_LOOKUP("bus_clk",
+			    gfx3d_axi_clk_8064.c, "footswitch-8x60.2"),
+	CLK_LOOKUP("iface_clk",         vcap_p_clk.c,           ""),
+	CLK_LOOKUP("iface_clk",         vcap_p_clk.c,           "msm_vcap.0"),
+	CLK_LOOKUP("iface_clk",         vcap_p_clk.c,	"footswitch-8x60.10"),
+	CLK_LOOKUP("bus_clk",		vcap_axi_clk.c,	"footswitch-8x60.10"),
+	CLK_LOOKUP("core_clk",          vcap_clk.c,             ""),
+	CLK_LOOKUP("core_clk",          vcap_clk.c,             "msm_vcap.0"),
+	CLK_LOOKUP("core_clk",          vcap_clk.c,	"footswitch-8x60.10"),
+	CLK_LOOKUP("vcap_npl_clk",      vcap_npl_clk.c,         ""),
+	CLK_LOOKUP("vcap_npl_clk",      vcap_npl_clk.c,         "msm_vcap.0"),
+	CLK_LOOKUP("bus_clk",		ijpeg_axi_clk.c, "footswitch-8x60.3"),
+	CLK_LOOKUP("mem_clk",		imem_axi_clk.c,	"msm_gemini.0"),
+	CLK_LOOKUP("core_clk",          ijpeg_clk.c,    "msm_gemini.0"),
+	CLK_LOOKUP("core_clk",		ijpeg_clk.c,	"footswitch-8x60.3"),
+	CLK_LOOKUP("core_clk",		jpegd_clk.c,		""),
+	CLK_LOOKUP("core_clk",		mdp_clk.c,		"mdp.0"),
+	CLK_LOOKUP("core_clk",		mdp_clk.c,	 "footswitch-8x60.4"),
+	CLK_LOOKUP("vsync_clk",	mdp_vsync_clk.c,	"mdp.0"),
+	CLK_LOOKUP("vsync_clk",		mdp_vsync_clk.c, "footswitch-8x60.4"),
+	CLK_LOOKUP("lut_clk",		lut_mdp_clk.c,		"mdp.0"),
+	CLK_LOOKUP("lut_clk",		lut_mdp_clk.c,	"footswitch-8x60.4"),
+	CLK_LOOKUP("core_clk",		rot_clk.c,	"msm_rotator.0"),
+	CLK_LOOKUP("core_clk",		rot_clk.c,	"footswitch-8x60.6"),
+	CLK_LOOKUP("tv_src_clk",	tv_src_clk.c,	"footswitch-8x60.4"),
+	CLK_LOOKUP("src_clk",	tv_src_clk.c,		"dtv.0"),
+	CLK_LOOKUP("div_clk",	tv_src_div_clk.c,	""),
+	CLK_LOOKUP("core_clk",		vcodec_clk.c,		"msm_vidc.0"),
+	CLK_LOOKUP("core_clk",		vcodec_clk.c,	"footswitch-8x60.7"),
+	CLK_LOOKUP("mdp_clk",	mdp_tv_clk.c,		"dtv.0"),
+	CLK_LOOKUP("tv_clk",		mdp_tv_clk.c,	"footswitch-8x60.4"),
+	CLK_LOOKUP("hdmi_clk",		hdmi_tv_clk.c,		"dtv.0"),
+	CLK_LOOKUP("core_clk",		hdmi_app_clk.c,		"hdmi_msm.1"),
+	CLK_LOOKUP("vpe_clk",		vpe_clk.c,		"msm_vpe.0"),
+	CLK_LOOKUP("core_clk",		vpe_clk.c,	"footswitch-8x60.9"),
+	CLK_LOOKUP("vfe_clk",		vfe_clk.c,		"msm_vfe.0"),
+	CLK_LOOKUP("core_clk",		vfe_clk.c,	"footswitch-8x60.8"),
+	CLK_LOOKUP("csi_vfe_clk",	csi_vfe_clk.c,		"msm_vfe.0"),
+	CLK_LOOKUP("bus_clk",		vfe_axi_clk.c,	"footswitch-8x60.8"),
+	CLK_LOOKUP("bus_clk",		mdp_axi_clk.c,	"footswitch-8x60.4"),
+	CLK_LOOKUP("bus_clk",		rot_axi_clk.c,	"footswitch-8x60.6"),
+	CLK_LOOKUP("bus_clk",		vcodec_axi_clk.c,  "footswitch-8x60.7"),
+	CLK_LOOKUP("bus_a_clk",        vcodec_axi_a_clk.c, "footswitch-8x60.7"),
+	CLK_LOOKUP("bus_b_clk",        vcodec_axi_b_clk.c, "footswitch-8x60.7"),
+	CLK_LOOKUP("bus_clk",		vpe_axi_clk.c,	"footswitch-8x60.9"),
+	CLK_LOOKUP("arb_clk",		amp_p_clk.c,		"mipi_dsi.1"),
+	CLK_LOOKUP("arb_clk",		amp_p_clk.c,		"mipi_dsi.2"),
+	CLK_LOOKUP("csi_pclk",          csi_p_clk.c,            "msm_csid.0"),
+	CLK_LOOKUP("csi_pclk",          csi_p_clk.c,            "msm_csid.1"),
+	CLK_LOOKUP("csi_pclk",          csi_p_clk.c,            "msm_csid.2"),
+	CLK_LOOKUP("master_iface_clk",	dsi1_m_p_clk.c,		"mipi_dsi.1"),
+	CLK_LOOKUP("slave_iface_clk",	dsi1_s_p_clk.c,		"mipi_dsi.1"),
+	CLK_LOOKUP("master_iface_clk",	dsi2_m_p_clk.c,		"mipi_dsi.2"),
+	CLK_LOOKUP("slave_iface_clk",	dsi2_s_p_clk.c,		"mipi_dsi.2"),
+	CLK_LOOKUP("iface_clk",		gfx3d_p_clk.c,	"kgsl-3d0.0"),
+	CLK_LOOKUP("iface_clk",		gfx3d_p_clk.c,	"footswitch-8x60.2"),
+	CLK_LOOKUP("master_iface_clk",	hdmi_m_p_clk.c,		"hdmi_msm.1"),
+	CLK_LOOKUP("slave_iface_clk",	hdmi_s_p_clk.c,		"hdmi_msm.1"),
+	CLK_LOOKUP("iface_clk",		ijpeg_p_clk.c,		"msm_gemini.0"),
+	CLK_LOOKUP("iface_clk",		ijpeg_p_clk.c,	"footswitch-8x60.3"),
+	CLK_LOOKUP("iface_clk",		jpegd_p_clk.c,		""),
+	CLK_LOOKUP("mem_iface_clk",	imem_p_clk.c,	"kgsl-3d0.0"),
+	CLK_LOOKUP("iface_clk",		mdp_p_clk.c,		"mdp.0"),
+	CLK_LOOKUP("iface_clk",		mdp_p_clk.c,	"footswitch-8x60.4"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,		"msm_iommu"),
+	CLK_LOOKUP("iface_clk",		rot_p_clk.c,	"msm_rotator.0"),
+	CLK_LOOKUP("iface_clk",		rot_p_clk.c,	"footswitch-8x60.6"),
+	CLK_LOOKUP("iface_clk",		vcodec_p_clk.c,		"msm_vidc.0"),
+	CLK_LOOKUP("iface_clk",		vcodec_p_clk.c,	"footswitch-8x60.7"),
+	CLK_LOOKUP("vfe_pclk",		vfe_p_clk.c,		"msm_vfe.0"),
+	CLK_LOOKUP("iface_clk",		vfe_p_clk.c,	"footswitch-8x60.8"),
+	CLK_LOOKUP("vpe_pclk",		vpe_p_clk.c,		"msm_vpe.0"),
+	CLK_LOOKUP("iface_clk",		vpe_p_clk.c,	"footswitch-8x60.9"),
+
+	CLK_LOOKUP("bit_clk",		mi2s_bit_clk.c,
+			    "msm-dai-q6-mi2s"),
+	CLK_LOOKUP("osr_clk",		mi2s_osr_clk.c,
+			    "msm-dai-q6-mi2s"),
+	CLK_LOOKUP("bit_clk",		codec_i2s_mic_bit_clk.c,
+			   "msm-dai-q6.1"),
+	CLK_LOOKUP("osr_clk",		codec_i2s_mic_osr_clk.c,
+			   "msm-dai-q6.1"),
+	CLK_LOOKUP("bit_clk",		spare_i2s_mic_bit_clk.c,
+			   "msm-dai-q6.5"),
+	CLK_LOOKUP("osr_clk",		spare_i2s_mic_osr_clk.c,
+			   "msm-dai-q6.5"),
+	CLK_LOOKUP("bit_clk",		codec_i2s_spkr_bit_clk.c,
+			   "msm-dai-q6.16384"),
+	CLK_LOOKUP("osr_clk",		codec_i2s_spkr_osr_clk.c,
+			   "msm-dai-q6.16384"),
+	CLK_LOOKUP("bit_clk",		spare_i2s_spkr_bit_clk.c,
+			   "msm-dai-q6.4"),
+	CLK_LOOKUP("osr_clk",		spare_i2s_spkr_osr_clk.c,
+			   "msm-dai-q6.4"),
+	CLK_LOOKUP("pcm_clk",		pcm_clk.c,		"msm-dai-q6.2"),
+	CLK_LOOKUP("pcm_clk",		pcm_clk.c,		"msm-dai-q6.3"),
+	CLK_LOOKUP("sps_slimbus_clk",	sps_slimbus_clk.c,	""),
+	CLK_LOOKUP("core_clk",		audio_slimbus_clk.c, "msm_slim_ctrl.1"),
+	CLK_LOOKUP("core_clk",		jpegd_axi_clk.c,	""),
+	CLK_LOOKUP("core_clk",		vpe_axi_clk.c,		""),
+	CLK_LOOKUP("core_clk",		mdp_axi_clk.c,		""),
+	CLK_LOOKUP("core_clk",		vcap_axi_clk.c,		""),
+	CLK_LOOKUP("core_clk",		rot_axi_clk.c,		""),
+	CLK_LOOKUP("core_clk",		ijpeg_axi_clk.c,	""),
+	CLK_LOOKUP("core_clk",		vfe_axi_clk.c,		""),
+	CLK_LOOKUP("core_clk",		vcodec_axi_a_clk.c,	""),
+	CLK_LOOKUP("core_clk",		vcodec_axi_b_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gfx3d_axi_clk_8064.c,	""),
+
+	CLK_LOOKUP("dfab_dsps_clk",	dfab_dsps_clk.c, NULL),
+	CLK_LOOKUP("core_clk",		dfab_usb_hs_clk.c,	"msm_otg"),
+	CLK_LOOKUP("core_clk",		dfab_usb_hs3_clk.c, "msm_ehci_host.0"),
+	CLK_LOOKUP("core_clk",		dfab_usb_hs3_clk.c, "msm_ehci_host.1"),
+	CLK_LOOKUP("bus_clk",		dfab_sdc1_clk.c, "msm_sdcc.1"),
+	CLK_LOOKUP("bus_clk",		dfab_sdc2_clk.c, "msm_sdcc.2"),
+	CLK_LOOKUP("bus_clk",		dfab_sdc3_clk.c, "msm_sdcc.3"),
+	CLK_LOOKUP("bus_clk",		dfab_sdc4_clk.c, "msm_sdcc.4"),
+	CLK_LOOKUP("dfab_clk",		dfab_sps_clk.c,	"msm_sps"),
+	CLK_LOOKUP("bus_clk",		dfab_bam_dmux_clk.c,	"BAM_RMNT"),
+	CLK_LOOKUP("bus_clk",		dfab_scm_clk.c,	"scm"),
+	CLK_LOOKUP("bus_clk",		dfab_qseecom_clk.c,	"qseecom"),
+	CLK_LOOKUP("bus_clk",		dfab_tzcom_clk.c,	"tzcom"),
+
+	CLK_LOOKUP("alt_core_clk",    usb_hsic_xcvr_fs_clk.c,  "msm_hsic_host"),
+	CLK_LOOKUP("phy_clk",	      usb_hsic_hsic_clk.c,     "msm_hsic_host"),
+	CLK_LOOKUP("cal_clk",	      usb_hsic_hsio_cal_clk.c, "msm_hsic_host"),
+	CLK_LOOKUP("core_clk",	      usb_hsic_system_clk.c,   "msm_hsic_host"),
+	CLK_LOOKUP("iface_clk",	      usb_hsic_p_clk.c,        "msm_hsic_host"),
+
+	CLK_LOOKUP("core_clk",		jpegd_axi_clk.c,	"msm_iommu.0"),
+	CLK_LOOKUP("core_clk",		vpe_axi_clk.c,		"msm_iommu.1"),
+	CLK_LOOKUP("core_clk",		mdp_axi_clk.c,		"msm_iommu.2"),
+	CLK_LOOKUP("core_clk",		mdp_axi_clk.c,		"msm_iommu.3"),
+	CLK_LOOKUP("core_clk",		rot_axi_clk.c,		"msm_iommu.4"),
+	CLK_LOOKUP("core_clk",		ijpeg_axi_clk.c,	"msm_iommu.5"),
+	CLK_LOOKUP("core_clk",		vfe_axi_clk.c,		"msm_iommu.6"),
+	CLK_LOOKUP("core_clk",		vcodec_axi_a_clk.c,	"msm_iommu.7"),
+	CLK_LOOKUP("core_clk",		vcodec_axi_b_clk.c,	"msm_iommu.8"),
+	CLK_LOOKUP("core_clk",		gfx3d_axi_clk_8064.c,	"msm_iommu.9"),
+	CLK_LOOKUP("core_clk",		gfx3d_axi_clk_8064.c,	"msm_iommu.10"),
+	CLK_LOOKUP("core_clk",		vcap_axi_clk.c,		"msm_iommu.11"),
+
+	CLK_LOOKUP("mdp_iommu_clk", mdp_axi_clk.c,	"msm_vidc.0"),
+	CLK_LOOKUP("rot_iommu_clk",	rot_axi_clk.c,	"msm_vidc.0"),
+	CLK_LOOKUP("vcodec_iommu0_clk", vcodec_axi_a_clk.c, "msm_vidc.0"),
+	CLK_LOOKUP("vcodec_iommu1_clk", vcodec_axi_b_clk.c, "msm_vidc.0"),
+	CLK_LOOKUP("smmu_iface_clk", smmu_p_clk.c,	"msm_vidc.0"),
+	CLK_LOOKUP("core_clk",		vcodec_axi_clk.c,  "pil_vidc"),
+	CLK_LOOKUP("smmu_iface_clk",	smmu_p_clk.c,  "pil_vidc"),
+
+	CLK_LOOKUP("mem_clk",		ebi1_adm_clk.c, "msm_dmov"),
+
+	CLK_LOOKUP("l2_mclk",		l2_m_clk,     ""),
+	CLK_LOOKUP("krait0_mclk",	krait0_m_clk, ""),
+	CLK_LOOKUP("krait1_mclk",	krait1_m_clk, ""),
+	CLK_LOOKUP("krait2_mclk",	krait2_m_clk, ""),
+	CLK_LOOKUP("krait3_mclk",	krait3_m_clk, ""),
+};
+
+static struct clk_lookup msm_clocks_8960[] = {
+	CLK_LOOKUP("xo",		cxo_a_clk.c,	""),
+	CLK_LOOKUP("xo",		pxo_a_clk.c,	""),
+	CLK_LOOKUP("cxo",		cxo_clk.c,	"wcnss_wlan.0"),
+	CLK_LOOKUP("cxo",		cxo_clk.c,	"pil_riva"),
+	CLK_LOOKUP("xo",		pxo_clk.c,	"pil_qdsp6v4.0"),
+	CLK_LOOKUP("xo",		cxo_clk.c,	"pil_qdsp6v4.1"),
+	CLK_LOOKUP("xo",		cxo_clk.c,	"pil_qdsp6v4.2"),
+	CLK_LOOKUP("xo",		cxo_clk.c,	"BAM_RMNT"),
+	CLK_LOOKUP("xo",		cxo_clk.c,	"msm_xo"),
+	CLK_LOOKUP("pll2",		pll2_clk.c,	NULL),
+	CLK_LOOKUP("pll8",		pll8_clk.c,	NULL),
+	CLK_LOOKUP("pll4",		pll4_clk.c,	NULL),
+	CLK_LOOKUP("measure",		measure_clk.c,	"debug"),
+
+	CLK_LOOKUP("bus_clk",		afab_clk.c,		"msm_apps_fab"),
+	CLK_LOOKUP("bus_a_clk",		afab_a_clk.c,		"msm_apps_fab"),
+	CLK_LOOKUP("bus_clk",		cfpb_clk.c,		"msm_cpss_fpb"),
+	CLK_LOOKUP("bus_a_clk",		cfpb_a_clk.c,		"msm_cpss_fpb"),
+	CLK_LOOKUP("bus_clk",		sfab_clk.c,		"msm_sys_fab"),
+	CLK_LOOKUP("bus_a_clk",		sfab_msmbus_a_clk.c,	"msm_sys_fab"),
+	CLK_LOOKUP("bus_clk",		sfpb_clk.c,		"msm_sys_fpb"),
+	CLK_LOOKUP("bus_a_clk",		sfpb_a_clk.c,		"msm_sys_fpb"),
+	CLK_LOOKUP("bus_clk",		mmfab_clk.c,		"msm_mm_fab"),
+	CLK_LOOKUP("bus_a_clk",		mmfab_a_clk.c,		"msm_mm_fab"),
+	CLK_LOOKUP("mem_clk",		ebi1_msmbus_clk.c,	"msm_bus"),
+	CLK_LOOKUP("mem_a_clk",		ebi1_a_clk.c,		"msm_bus"),
+	CLK_LOOKUP("dfab_clk",		dfab_msmbus_clk.c,	"msm_bus"),
+	CLK_LOOKUP("dfab_a_clk",	dfab_msmbus_a_clk.c,	"msm_bus"),
+
+	CLK_LOOKUP("ebi1_clk",		ebi1_clk.c,		NULL),
+	CLK_LOOKUP("mmfpb_clk",		mmfpb_clk.c,		NULL),
+	CLK_LOOKUP("mmfpb_a_clk",	mmfpb_a_clk.c,		"clock-8960"),
+	CLK_LOOKUP("cfpb_a_clk",	cfpb_a_clk.c,		"clock-8960"),
+
+	CLK_LOOKUP("core_clk",		gp0_clk.c,		""),
+	CLK_LOOKUP("core_clk",		gp1_clk.c,		""),
+	CLK_LOOKUP("core_clk",		gp2_clk.c,		""),
+	CLK_LOOKUP("core_clk",		gsbi1_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi2_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi3_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi4_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi5_uart_clk.c, "msm_serial_hsl.0"),
+	CLK_LOOKUP("core_clk",		gsbi6_uart_clk.c, "msm_serial_hs.0"),
+	CLK_LOOKUP("core_clk",		gsbi7_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi8_uart_clk.c, "msm_serial_hsl.1"),
+	CLK_LOOKUP("core_clk",		gsbi9_uart_clk.c, "msm_serial_hs.1"),
+	CLK_LOOKUP("core_clk",		gsbi10_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi11_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi12_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi1_qup_clk.c,	"spi_qsd.0"),
+	CLK_LOOKUP("core_clk",		gsbi2_qup_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi3_qup_clk.c,	"qup_i2c.3"),
+	CLK_LOOKUP("core_clk",		gsbi4_qup_clk.c,	"qup_i2c.4"),
+	CLK_LOOKUP("core_clk",		gsbi5_qup_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi6_qup_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi7_qup_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi8_qup_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi9_qup_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi10_qup_clk.c,	"qup_i2c.10"),
+	CLK_LOOKUP("core_clk",		gsbi11_qup_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi12_qup_clk.c,	"qup_i2c.12"),
+	CLK_LOOKUP("core_clk",		pdm_clk.c,		""),
+	CLK_LOOKUP("mem_clk",		pmem_clk.c,		"msm_sps"),
+	CLK_LOOKUP("core_clk",		prng_clk.c,		"msm_rng.0"),
+	CLK_LOOKUP("core_clk",		sdc1_clk.c,		"msm_sdcc.1"),
+	CLK_LOOKUP("core_clk",		sdc2_clk.c,		"msm_sdcc.2"),
+	CLK_LOOKUP("core_clk",		sdc3_clk.c,		"msm_sdcc.3"),
+	CLK_LOOKUP("core_clk",		sdc4_clk.c,		"msm_sdcc.4"),
+	CLK_LOOKUP("core_clk",		sdc5_clk.c,		"msm_sdcc.5"),
+	CLK_LOOKUP("slimbus_xo_src_clk", slimbus_xo_src_clk.c,	NULL),
+	CLK_LOOKUP("ref_clk",		tsif_ref_clk.c,		""),
+	CLK_LOOKUP("core_clk",		tssc_clk.c,		""),
+	CLK_LOOKUP("alt_core_clk",	usb_hs1_xcvr_clk.c,	"msm_otg"),
+	CLK_LOOKUP("phy_clk",		usb_phy0_clk.c,		"msm_otg"),
+	CLK_LOOKUP("alt_core_clk",	usb_fs1_xcvr_clk.c,	""),
+	CLK_LOOKUP("sys_clk",		usb_fs1_sys_clk.c,	""),
+	CLK_LOOKUP("src_clk",		usb_fs1_src_clk.c,	""),
+	CLK_LOOKUP("alt_core_clk",	usb_fs2_xcvr_clk.c,	""),
+	CLK_LOOKUP("sys_clk",		usb_fs2_sys_clk.c,	""),
+	CLK_LOOKUP("src_clk",		usb_fs2_src_clk.c,	""),
+	CLK_LOOKUP("alt_core_clk",    usb_hsic_xcvr_fs_clk.c,  "msm_hsic_host"),
+	CLK_LOOKUP("phy_clk",	      usb_hsic_hsic_clk.c,     "msm_hsic_host"),
+	CLK_LOOKUP("cal_clk",	      usb_hsic_hsio_cal_clk.c, "msm_hsic_host"),
+	CLK_LOOKUP("core_clk",	      usb_hsic_system_clk.c,   "msm_hsic_host"),
+	CLK_LOOKUP("iface_clk",	      usb_hsic_p_clk.c,        "msm_hsic_host"),
+	CLK_LOOKUP("iface_clk",		ce1_p_clk.c,		"qce.0"),
+	CLK_LOOKUP("iface_clk",		ce1_p_clk.c,		"qcrypto.0"),
+	CLK_LOOKUP("core_clk",		ce1_core_clk.c,		"qce.0"),
+	CLK_LOOKUP("core_clk",		ce1_core_clk.c,		"qcrypto.0"),
+	CLK_LOOKUP("dma_bam_pclk",	dma_bam_p_clk.c,	NULL),
+	CLK_LOOKUP("iface_clk",		gsbi1_p_clk.c,		"spi_qsd.0"),
+	CLK_LOOKUP("iface_clk",		gsbi2_p_clk.c,		""),
+	CLK_LOOKUP("iface_clk",		gsbi3_p_clk.c,		"qup_i2c.3"),
+	CLK_LOOKUP("iface_clk",		gsbi4_p_clk.c,		"qup_i2c.4"),
+	CLK_LOOKUP("iface_clk",		gsbi5_p_clk.c,	"msm_serial_hsl.0"),
+	CLK_LOOKUP("iface_clk",		gsbi6_p_clk.c,  "msm_serial_hs.0"),
+	CLK_LOOKUP("iface_clk",		gsbi7_p_clk.c,		""),
+	CLK_LOOKUP("iface_clk",		gsbi8_p_clk.c,	"msm_serial_hsl.1"),
+	CLK_LOOKUP("iface_clk",		gsbi9_p_clk.c,  "msm_serial_hs.1"),
+	CLK_LOOKUP("iface_clk",		gsbi10_p_clk.c,		"qup_i2c.10"),
+	CLK_LOOKUP("iface_clk",		gsbi11_p_clk.c,		""),
+	CLK_LOOKUP("iface_clk",		gsbi12_p_clk.c,		"qup_i2c.12"),
+	CLK_LOOKUP("iface_clk",		tsif_p_clk.c,		""),
+	CLK_LOOKUP("iface_clk",		usb_fs1_p_clk.c,	""),
+	CLK_LOOKUP("iface_clk",		usb_fs2_p_clk.c,	""),
+	CLK_LOOKUP("iface_clk",		usb_hs1_p_clk.c,	"msm_otg"),
+	CLK_LOOKUP("iface_clk",		sdc1_p_clk.c,		"msm_sdcc.1"),
+	CLK_LOOKUP("iface_clk",		sdc2_p_clk.c,		"msm_sdcc.2"),
+	CLK_LOOKUP("iface_clk",		sdc3_p_clk.c,		"msm_sdcc.3"),
+	CLK_LOOKUP("iface_clk",		sdc4_p_clk.c,		"msm_sdcc.4"),
+	CLK_LOOKUP("iface_clk",		sdc5_p_clk.c,		"msm_sdcc.5"),
+	CLK_LOOKUP("core_clk",		adm0_clk.c,		"msm_dmov"),
+	CLK_LOOKUP("iface_clk",		adm0_p_clk.c,		"msm_dmov"),
+	CLK_LOOKUP("iface_clk",		pmic_arb0_p_clk.c,	""),
+	CLK_LOOKUP("iface_clk",		pmic_arb1_p_clk.c,	""),
+	CLK_LOOKUP("core_clk",		pmic_ssbi2_clk.c,	""),
+	CLK_LOOKUP("mem_clk",		rpm_msg_ram_p_clk.c,	""),
+	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-001a"),
+	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-006c"),
+	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-0048"),
+	CLK_LOOKUP("cam_clk",		cam2_clk.c,		NULL),
+	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-0020"),
+	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-0034"),
+	CLK_LOOKUP("csi_src_clk",	csi0_src_clk.c,		"msm_csid.0"),
+	CLK_LOOKUP("csi_src_clk",	csi1_src_clk.c,		"msm_csid.1"),
+	CLK_LOOKUP("csi_src_clk",	csi2_src_clk.c,		"msm_csid.2"),
+	CLK_LOOKUP("csi_clk",		csi0_clk.c,		"msm_csid.0"),
+	CLK_LOOKUP("csi_clk",		csi1_clk.c,		"msm_csid.1"),
+	CLK_LOOKUP("csi_clk",		csi2_clk.c,		"msm_csid.2"),
+	CLK_LOOKUP("csi_phy_clk",	csi0_phy_clk.c,		"msm_csid.0"),
+	CLK_LOOKUP("csi_phy_clk",	csi1_phy_clk.c,		"msm_csid.1"),
+	CLK_LOOKUP("csi_phy_clk",	csi2_phy_clk.c,		"msm_csid.2"),
+	CLK_LOOKUP("csi_pix_clk",	csi_pix_clk.c,		"msm_ispif.0"),
+	CLK_LOOKUP("csi_rdi_clk",	csi_rdi_clk.c,		"msm_ispif.0"),
+	CLK_LOOKUP("csi_src_clk",	csi2_src_clk.c,		NULL),
+	CLK_LOOKUP("csi_clk",		csi2_clk.c,		NULL),
+	CLK_LOOKUP("csi_pix1_clk",	csi_pix1_clk.c,		"msm_ispif.0"),
+	CLK_LOOKUP("csi_rdi1_clk",	csi_rdi1_clk.c,		"msm_ispif.0"),
+	CLK_LOOKUP("csi_rdi2_clk",	csi_rdi2_clk.c,		"msm_ispif.0"),
+	CLK_LOOKUP("csi_phy_clk",	csi2_phy_clk.c,		NULL),
+	CLK_LOOKUP("csi2phy_timer_clk",	csi2phy_timer_clk.c,	NULL),
+	CLK_LOOKUP("csiphy_timer_src_clk",
+			   csiphy_timer_src_clk.c, "msm_csiphy.0"),
+	CLK_LOOKUP("csiphy_timer_src_clk",
+			   csiphy_timer_src_clk.c, "msm_csiphy.1"),
+	CLK_LOOKUP("csiphy_timer_src_clk",
+			   csiphy_timer_src_clk.c, "msm_csiphy.2"),
+	CLK_LOOKUP("csiphy_timer_clk",	csi0phy_timer_clk.c,	"msm_csiphy.0"),
+	CLK_LOOKUP("csiphy_timer_clk",	csi1phy_timer_clk.c,	"msm_csiphy.1"),
+	CLK_LOOKUP("csiphy_timer_clk",	csi2phy_timer_clk.c,	"msm_csiphy.2"),
+	CLK_LOOKUP("byte_clk",	dsi1_byte_clk.c,	"mipi_dsi.1"),
+	CLK_LOOKUP("byte_clk",	dsi2_byte_clk.c,	"mipi_dsi.2"),
+	CLK_LOOKUP("esc_clk",	dsi1_esc_clk.c,		"mipi_dsi.1"),
+	CLK_LOOKUP("esc_clk",	dsi2_esc_clk.c,		"mipi_dsi.2"),
+	CLK_LOOKUP("core_clk",		gfx2d0_clk.c,	"kgsl-2d0.0"),
+	CLK_LOOKUP("core_clk",		gfx2d0_clk.c,	"footswitch-8x60.0"),
+	CLK_LOOKUP("core_clk",		gfx2d1_clk.c,	"kgsl-2d1.1"),
+	CLK_LOOKUP("core_clk",		gfx2d1_clk.c,	"footswitch-8x60.1"),
+	CLK_LOOKUP("core_clk",		gfx3d_clk.c,	"kgsl-3d0.0"),
+	CLK_LOOKUP("core_clk",		gfx3d_clk.c,	"footswitch-8x60.2"),
+	CLK_LOOKUP("bus_clk",		ijpeg_axi_clk.c, "footswitch-8x60.3"),
+	CLK_LOOKUP("mem_clk",		imem_axi_clk.c,	"msm_gemini.0"),
+	CLK_LOOKUP("core_clk",          ijpeg_clk.c,    "msm_gemini.0"),
+	CLK_LOOKUP("core_clk",		ijpeg_clk.c,	"footswitch-8x60.3"),
+	CLK_LOOKUP("core_clk",		jpegd_clk.c,		""),
+	CLK_LOOKUP("core_clk",		mdp_clk.c,		"mdp.0"),
+	CLK_LOOKUP("core_clk",		mdp_clk.c,	"footswitch-8x60.4"),
+	CLK_LOOKUP("vsync_clk",	mdp_vsync_clk.c,	"mdp.0"),
+	CLK_LOOKUP("vsync_clk",		mdp_vsync_clk.c, "footswitch-8x60.4"),
+	CLK_LOOKUP("lut_clk",		lut_mdp_clk.c,		"mdp.0"),
+	CLK_LOOKUP("lut_clk",		lut_mdp_clk.c,	"footswitch-8x60.4"),
+	CLK_LOOKUP("core_clk",		rot_clk.c,	"msm_rotator.0"),
+	CLK_LOOKUP("core_clk",		rot_clk.c,	"footswitch-8x60.6"),
+	CLK_LOOKUP("src_clk",	tv_src_clk.c,		"dtv.0"),
+	CLK_LOOKUP("src_clk",	tv_src_clk.c,		"tvenc.0"),
+	CLK_LOOKUP("tv_src_clk",	tv_src_clk.c,	"footswitch-8x60.4"),
+	CLK_LOOKUP("enc_clk",	tv_enc_clk.c,		"tvenc.0"),
+	CLK_LOOKUP("dac_clk",	tv_dac_clk.c,		"tvenc.0"),
+	CLK_LOOKUP("core_clk",		vcodec_clk.c,	"msm_vidc.0"),
+	CLK_LOOKUP("core_clk",		vcodec_clk.c,	"footswitch-8x60.7"),
+	CLK_LOOKUP("mdp_clk",	mdp_tv_clk.c,		"dtv.0"),
+	CLK_LOOKUP("mdp_clk",	mdp_tv_clk.c,		"tvenc.0"),
+	CLK_LOOKUP("tv_clk",		mdp_tv_clk.c,	"footswitch-8x60.4"),
+	CLK_LOOKUP("hdmi_clk",		hdmi_tv_clk.c,		"dtv.0"),
+	CLK_LOOKUP("core_clk",		hdmi_app_clk.c,	"hdmi_msm.1"),
+	CLK_LOOKUP("vpe_clk",		vpe_clk.c,		"msm_vpe.0"),
+	CLK_LOOKUP("core_clk",		vpe_clk.c,	"footswitch-8x60.9"),
+	CLK_LOOKUP("vfe_clk",		vfe_clk.c,		"msm_vfe.0"),
+	CLK_LOOKUP("core_clk",		vfe_clk.c,	"footswitch-8x60.8"),
+	CLK_LOOKUP("csi_vfe_clk",	csi_vfe_clk.c,		"msm_vfe.0"),
+	CLK_LOOKUP("bus_clk",		vfe_axi_clk.c,	"footswitch-8x60.8"),
+	CLK_LOOKUP("bus_clk",		mdp_axi_clk.c,	"footswitch-8x60.4"),
+	CLK_LOOKUP("bus_clk",		rot_axi_clk.c,	"footswitch-8x60.6"),
+	CLK_LOOKUP("bus_clk",		vcodec_axi_clk.c, "footswitch-8x60.7"),
+	CLK_LOOKUP("bus_a_clk",	       vcodec_axi_a_clk.c, "footswitch-8x60.7"),
+	CLK_LOOKUP("bus_b_clk",        vcodec_axi_b_clk.c, "footswitch-8x60.7"),
+	CLK_LOOKUP("bus_clk",		vpe_axi_clk.c,	"footswitch-8x60.9"),
+	CLK_LOOKUP("arb_clk",		amp_p_clk.c,		"mipi_dsi.1"),
+	CLK_LOOKUP("arb_clk",		amp_p_clk.c,		"mipi_dsi.2"),
+	CLK_LOOKUP("csi_pclk",		csi_p_clk.c,		"msm_csid.0"),
+	CLK_LOOKUP("csi_pclk",		csi_p_clk.c,		"msm_csid.1"),
+	CLK_LOOKUP("csi_pclk",		csi_p_clk.c,		"msm_csid.2"),
+	CLK_LOOKUP("master_iface_clk",	dsi1_m_p_clk.c,		"mipi_dsi.1"),
+	CLK_LOOKUP("slave_iface_clk",	dsi1_s_p_clk.c,		"mipi_dsi.1"),
+	CLK_LOOKUP("master_iface_clk",	dsi2_m_p_clk.c,		"mipi_dsi.2"),
+	CLK_LOOKUP("slave_iface_clk",	dsi2_s_p_clk.c,		"mipi_dsi.2"),
+	CLK_LOOKUP("iface_clk",		gfx2d0_p_clk.c,	"kgsl-2d0.0"),
+	CLK_LOOKUP("iface_clk",		gfx2d0_p_clk.c,	"footswitch-8x60.0"),
+	CLK_LOOKUP("iface_clk",		gfx2d1_p_clk.c,	"kgsl-2d1.1"),
+	CLK_LOOKUP("iface_clk",		gfx2d1_p_clk.c,	"footswitch-8x60.1"),
+	CLK_LOOKUP("iface_clk",		gfx3d_p_clk.c,	"kgsl-3d0.0"),
+	CLK_LOOKUP("iface_clk",		gfx3d_p_clk.c,	"footswitch-8x60.2"),
+	CLK_LOOKUP("master_iface_clk",	hdmi_m_p_clk.c,	"hdmi_msm.1"),
+	CLK_LOOKUP("slave_iface_clk",	hdmi_s_p_clk.c,	"hdmi_msm.1"),
+	CLK_LOOKUP("iface_clk",		ijpeg_p_clk.c,	"msm_gemini.0"),
+	CLK_LOOKUP("iface_clk",		ijpeg_p_clk.c,	"footswitch-8x60.3"),
+	CLK_LOOKUP("iface_clk",		jpegd_p_clk.c,		""),
+	CLK_LOOKUP("mem_iface_clk",	imem_p_clk.c,	"kgsl-3d0.0"),
+	CLK_LOOKUP("iface_clk",		mdp_p_clk.c,		"mdp.0"),
+	CLK_LOOKUP("iface_clk",		mdp_p_clk.c,	"footswitch-8x60.4"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu"),
+	CLK_LOOKUP("iface_clk",		rot_p_clk.c,	"msm_rotator.0"),
+	CLK_LOOKUP("iface_clk",		rot_p_clk.c,	"footswitch-8x60.6"),
+	CLK_LOOKUP("iface_clk",	tv_enc_p_clk.c,		"tvenc.0"),
+	CLK_LOOKUP("iface_clk",		vcodec_p_clk.c,	"msm_vidc.0"),
+	CLK_LOOKUP("iface_clk",		vcodec_p_clk.c,	"footswitch-8x60.7"),
+	CLK_LOOKUP("vfe_pclk",		vfe_p_clk.c,		"msm_vfe.0"),
+	CLK_LOOKUP("iface_clk",		vfe_p_clk.c,	"footswitch-8x60.8"),
+	CLK_LOOKUP("vpe_pclk",		vpe_p_clk.c,		"msm_vpe.0"),
+	CLK_LOOKUP("iface_clk",		vpe_p_clk.c,	"footswitch-8x60.9"),
+	CLK_LOOKUP("bit_clk",		mi2s_bit_clk.c,
+			    "msm-dai-q6-mi2s"),
+	CLK_LOOKUP("osr_clk",		mi2s_osr_clk.c,
+			    "msm-dai-q6-mi2s"),
+	CLK_LOOKUP("bit_clk",		codec_i2s_mic_bit_clk.c,
+			   "msm-dai-q6.1"),
+	CLK_LOOKUP("osr_clk",		codec_i2s_mic_osr_clk.c,
+			   "msm-dai-q6.1"),
+	CLK_LOOKUP("bit_clk",		spare_i2s_mic_bit_clk.c,
+			   "msm-dai-q6.5"),
+	CLK_LOOKUP("osr_clk",		spare_i2s_mic_osr_clk.c,
+			   "msm-dai-q6.5"),
+	CLK_LOOKUP("bit_clk",		codec_i2s_spkr_bit_clk.c,
+			   "msm-dai-q6.16384"),
+	CLK_LOOKUP("osr_clk",		codec_i2s_spkr_osr_clk.c,
+			   "msm-dai-q6.16384"),
+	CLK_LOOKUP("bit_clk",		spare_i2s_spkr_bit_clk.c,
+			   "msm-dai-q6.4"),
+	CLK_LOOKUP("osr_clk",		spare_i2s_spkr_osr_clk.c,
+			   "msm-dai-q6.4"),
+	CLK_LOOKUP("pcm_clk",		pcm_clk.c,		"msm-dai-q6.2"),
+	CLK_LOOKUP("pcm_clk",		pcm_clk.c,		"msm-dai-q6.3"),
+	CLK_LOOKUP("sps_slimbus_clk",	sps_slimbus_clk.c,	NULL),
+	CLK_LOOKUP("core_clk",		audio_slimbus_clk.c, "msm_slim_ctrl.1"),
+	CLK_LOOKUP("core_clk",		jpegd_axi_clk.c,	"msm_iommu.0"),
+	CLK_LOOKUP("core_clk",		vpe_axi_clk.c,		"msm_iommu.1"),
+	CLK_LOOKUP("core_clk",		mdp_axi_clk.c,		"msm_iommu.2"),
+	CLK_LOOKUP("core_clk",		mdp_axi_clk.c,		"msm_iommu.3"),
+	CLK_LOOKUP("core_clk",		rot_axi_clk.c,		"msm_iommu.4"),
+	CLK_LOOKUP("core_clk",		ijpeg_axi_clk.c,	"msm_iommu.5"),
+	CLK_LOOKUP("core_clk",		vfe_axi_clk.c,		"msm_iommu.6"),
+	CLK_LOOKUP("core_clk",		vcodec_axi_a_clk.c,	"msm_iommu.7"),
+	CLK_LOOKUP("core_clk",		vcodec_axi_b_clk.c,	"msm_iommu.8"),
+	CLK_LOOKUP("core_clk",		gfx3d_clk.c,		"msm_iommu.9"),
+	CLK_LOOKUP("core_clk",		gfx2d0_clk.c,		"msm_iommu.10"),
+	CLK_LOOKUP("core_clk",		gfx2d1_clk.c,		"msm_iommu.11"),
+
+	CLK_LOOKUP("mdp_iommu_clk", mdp_axi_clk.c,	"msm_vidc.0"),
+	CLK_LOOKUP("rot_iommu_clk",	rot_axi_clk.c,	"msm_vidc.0"),
+	CLK_LOOKUP("vcodec_iommu0_clk", vcodec_axi_a_clk.c, "msm_vidc.0"),
+	CLK_LOOKUP("vcodec_iommu1_clk", vcodec_axi_b_clk.c, "msm_vidc.0"),
+	CLK_LOOKUP("smmu_iface_clk", smmu_p_clk.c,	"msm_vidc.0"),
+	CLK_LOOKUP("core_clk",		vcodec_axi_clk.c,  "pil_vidc"),
+	CLK_LOOKUP("smmu_iface_clk",	smmu_p_clk.c,  "pil_vidc"),
+
+	CLK_LOOKUP("dfab_dsps_clk",	dfab_dsps_clk.c, NULL),
+	CLK_LOOKUP("core_clk",		dfab_usb_hs_clk.c,	"msm_otg"),
+	CLK_LOOKUP("bus_clk",		dfab_sdc1_clk.c, "msm_sdcc.1"),
+	CLK_LOOKUP("bus_clk",		dfab_sdc2_clk.c, "msm_sdcc.2"),
+	CLK_LOOKUP("bus_clk",		dfab_sdc3_clk.c, "msm_sdcc.3"),
+	CLK_LOOKUP("bus_clk",		dfab_sdc4_clk.c, "msm_sdcc.4"),
+	CLK_LOOKUP("bus_clk",		dfab_sdc5_clk.c, "msm_sdcc.5"),
+	CLK_LOOKUP("dfab_clk",		dfab_sps_clk.c,	"msm_sps"),
+	CLK_LOOKUP("bus_clk",		dfab_bam_dmux_clk.c,	"BAM_RMNT"),
+	CLK_LOOKUP("bus_clk",		dfab_scm_clk.c,	"scm"),
+	CLK_LOOKUP("bus_clk",		dfab_qseecom_clk.c,	"qseecom"),
+	CLK_LOOKUP("bus_clk",		dfab_tzcom_clk.c,	"tzcom"),
+
+	CLK_LOOKUP("mem_clk",		ebi1_adm_clk.c, "msm_dmov"),
+
+	CLK_LOOKUP("l2_mclk",		l2_m_clk,     ""),
+	CLK_LOOKUP("krait0_mclk",	krait0_m_clk, ""),
+	CLK_LOOKUP("krait1_mclk",	krait1_m_clk, ""),
+	CLK_LOOKUP("q6sw_clk",		q6sw_clk,     ""),
+	CLK_LOOKUP("q6fw_clk",		q6fw_clk,     ""),
+	CLK_LOOKUP("q6_func_clk",	q6_func_clk,  ""),
+};
+
+static struct clk_lookup msm_clocks_8930[] = {
+	CLK_LOOKUP("xo",		cxo_clk.c,	"msm_xo"),
+	CLK_LOOKUP("cxo",		cxo_clk.c,	"wcnss_wlan.0"),
+	CLK_LOOKUP("cxo",		cxo_clk.c,	"pil_riva"),
+	CLK_LOOKUP("xo",		pxo_clk.c,	"pil_qdsp6v4.0"),
+	CLK_LOOKUP("xo",		cxo_clk.c,	"pil_qdsp6v4.1"),
+	CLK_LOOKUP("xo",		cxo_clk.c,	"pil_qdsp6v4.2"),
+	CLK_LOOKUP("xo",		cxo_clk.c,	"BAM_RMNT"),
+	CLK_LOOKUP("pll2",		pll2_clk.c,	NULL),
+	CLK_LOOKUP("pll8",		pll8_clk.c,	NULL),
+	CLK_LOOKUP("pll4",		pll4_clk.c,	NULL),
+	CLK_LOOKUP("measure",		measure_clk.c,	"debug"),
+
+	CLK_LOOKUP("bus_clk",		afab_clk.c,		"msm_apps_fab"),
+	CLK_LOOKUP("bus_a_clk",		afab_a_clk.c,		"msm_apps_fab"),
+	CLK_LOOKUP("bus_clk",		cfpb_clk.c,		"msm_cpss_fpb"),
+	CLK_LOOKUP("bus_a_clk",		cfpb_a_clk.c,		"msm_cpss_fpb"),
+	CLK_LOOKUP("bus_clk",		sfab_clk.c,		"msm_sys_fab"),
+	CLK_LOOKUP("bus_a_clk",		sfab_msmbus_a_clk.c,	"msm_sys_fab"),
+	CLK_LOOKUP("bus_clk",		sfpb_clk.c,		"msm_sys_fpb"),
+	CLK_LOOKUP("bus_a_clk",		sfpb_a_clk.c,		"msm_sys_fpb"),
+	CLK_LOOKUP("bus_clk",		mmfab_clk.c,		"msm_mm_fab"),
+	CLK_LOOKUP("bus_a_clk",		mmfab_a_clk.c,		"msm_mm_fab"),
+	CLK_LOOKUP("mem_clk",		ebi1_msmbus_clk.c,	"msm_bus"),
+	CLK_LOOKUP("mem_a_clk",		ebi1_a_clk.c,		"msm_bus"),
+	CLK_LOOKUP("dfab_clk",		dfab_msmbus_clk.c,	"msm_bus"),
+	CLK_LOOKUP("dfab_a_clk",	dfab_msmbus_a_clk.c,	"msm_bus"),
+
+	CLK_LOOKUP("ebi1_clk",		ebi1_clk.c,		NULL),
+	CLK_LOOKUP("mmfpb_clk",		mmfpb_clk.c,		NULL),
+	CLK_LOOKUP("mmfpb_a_clk",	mmfpb_a_clk.c,		"clock-8960"),
+	CLK_LOOKUP("cfpb_a_clk",	cfpb_a_clk.c,		"clock-8960"),
+
+	CLK_LOOKUP("core_clk",		gp0_clk.c,		""),
+	CLK_LOOKUP("core_clk",		gp1_clk.c,		""),
+	CLK_LOOKUP("core_clk",		gp2_clk.c,		""),
+	CLK_LOOKUP("core_clk",		gsbi1_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi2_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi3_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi4_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi5_uart_clk.c, "msm_serial_hsl.0"),
+	CLK_LOOKUP("core_clk",		gsbi6_uart_clk.c, "msm_serial_hs.0"),
+	CLK_LOOKUP("core_clk",		gsbi7_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi8_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi9_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi10_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi11_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi12_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi1_qup_clk.c,	"spi_qsd.0"),
+	CLK_LOOKUP("core_clk",		gsbi2_qup_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi3_qup_clk.c,	"qup_i2c.3"),
+	CLK_LOOKUP("core_clk",		gsbi4_qup_clk.c,	"qup_i2c.4"),
+	CLK_LOOKUP("core_clk",		gsbi5_qup_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi6_qup_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi7_qup_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi8_qup_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi9_qup_clk.c,	"qup_i2c.0"),
+	CLK_LOOKUP("core_clk",		gsbi10_qup_clk.c,	"qup_i2c.10"),
+	CLK_LOOKUP("core_clk",		gsbi11_qup_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi12_qup_clk.c,	"qup_i2c.12"),
+	CLK_LOOKUP("core_clk",		pdm_clk.c,		""),
+	CLK_LOOKUP("mem_clk",		pmem_clk.c,		"msm_sps"),
+	CLK_LOOKUP("core_clk",		prng_clk.c,		"msm_rng.0"),
+	CLK_LOOKUP("core_clk",		sdc1_clk.c,		"msm_sdcc.1"),
+	CLK_LOOKUP("core_clk",		sdc2_clk.c,		"msm_sdcc.2"),
+	CLK_LOOKUP("core_clk",		sdc3_clk.c,		"msm_sdcc.3"),
+	CLK_LOOKUP("core_clk",		sdc4_clk.c,		"msm_sdcc.4"),
+	CLK_LOOKUP("core_clk",		sdc5_clk.c,		"msm_sdcc.5"),
+	CLK_LOOKUP("ref_clk",		tsif_ref_clk.c,		""),
+	CLK_LOOKUP("core_clk",		tssc_clk.c,		""),
+	CLK_LOOKUP("alt_core_clk",	usb_hs1_xcvr_clk.c,	"msm_otg"),
+	CLK_LOOKUP("phy_clk",		usb_phy0_clk.c,		"msm_otg"),
+	CLK_LOOKUP("alt_core_clk",	usb_fs1_xcvr_clk.c,	""),
+	CLK_LOOKUP("sys_clk",		usb_fs1_sys_clk.c,	""),
+	CLK_LOOKUP("src_clk",		usb_fs1_src_clk.c,	""),
+	CLK_LOOKUP("alt_core_clk",	usb_fs2_xcvr_clk.c,	""),
+	CLK_LOOKUP("sys_clk",		usb_fs2_sys_clk.c,	""),
+	CLK_LOOKUP("src_clk",		usb_fs2_src_clk.c,	""),
+	CLK_LOOKUP("alt_core_clk",    usb_hsic_xcvr_fs_clk.c,  "msm_hsic_host"),
+	CLK_LOOKUP("phy_clk",	      usb_hsic_hsic_clk.c,     "msm_hsic_host"),
+	CLK_LOOKUP("cal_clk",	      usb_hsic_hsio_cal_clk.c, "msm_hsic_host"),
+	CLK_LOOKUP("core_clk",	      usb_hsic_system_clk.c,   "msm_hsic_host"),
+	CLK_LOOKUP("iface_clk",	      usb_hsic_p_clk.c,        "msm_hsic_host"),
+	CLK_LOOKUP("iface_clk",		ce1_p_clk.c,		"qce.0"),
+	CLK_LOOKUP("iface_clk",		ce1_p_clk.c,		"qcrypto.0"),
+	CLK_LOOKUP("core_clk",		ce1_core_clk.c,		"qce.0"),
+	CLK_LOOKUP("core_clk",		ce1_core_clk.c,		"qcrypto.0"),
+	CLK_LOOKUP("dma_bam_pclk",	dma_bam_p_clk.c,	NULL),
+	CLK_LOOKUP("iface_clk",		gsbi1_p_clk.c,		"spi_qsd.0"),
+	CLK_LOOKUP("iface_clk",		gsbi2_p_clk.c,		""),
+	CLK_LOOKUP("iface_clk",		gsbi3_p_clk.c,		"qup_i2c.3"),
+	CLK_LOOKUP("iface_clk",		gsbi4_p_clk.c,		"qup_i2c.4"),
+	CLK_LOOKUP("iface_clk",		gsbi5_p_clk.c,	"msm_serial_hsl.0"),
+	CLK_LOOKUP("iface_clk",		gsbi6_p_clk.c,  "msm_serial_hs.0"),
+	CLK_LOOKUP("iface_clk",		gsbi7_p_clk.c,		""),
+	CLK_LOOKUP("iface_clk",		gsbi8_p_clk.c,		""),
+	CLK_LOOKUP("iface_clk",		gsbi9_p_clk.c,		"qup_i2c.0"),
+	CLK_LOOKUP("iface_clk",		gsbi10_p_clk.c,		"qup_i2c.10"),
+	CLK_LOOKUP("iface_clk",		gsbi11_p_clk.c,		""),
+	CLK_LOOKUP("iface_clk",		gsbi12_p_clk.c,		"qup_i2c.12"),
+	CLK_LOOKUP("iface_clk",		tsif_p_clk.c,		""),
+	CLK_LOOKUP("iface_clk",		usb_fs1_p_clk.c,	""),
+	CLK_LOOKUP("iface_clk",		usb_fs2_p_clk.c,	""),
+	CLK_LOOKUP("iface_clk",		usb_hs1_p_clk.c,	"msm_otg"),
+	CLK_LOOKUP("iface_clk",		sdc1_p_clk.c,		"msm_sdcc.1"),
+	CLK_LOOKUP("iface_clk",		sdc2_p_clk.c,		"msm_sdcc.2"),
+	CLK_LOOKUP("iface_clk",		sdc3_p_clk.c,		"msm_sdcc.3"),
+	CLK_LOOKUP("iface_clk",		sdc4_p_clk.c,		"msm_sdcc.4"),
+	CLK_LOOKUP("iface_clk",		sdc5_p_clk.c,		"msm_sdcc.5"),
+	CLK_LOOKUP("core_clk",		adm0_clk.c,		"msm_dmov"),
+	CLK_LOOKUP("iface_clk",		adm0_p_clk.c,		"msm_dmov"),
+	CLK_LOOKUP("iface_clk",		pmic_arb0_p_clk.c,	""),
+	CLK_LOOKUP("iface_clk",		pmic_arb1_p_clk.c,	""),
+	CLK_LOOKUP("core_clk",		pmic_ssbi2_clk.c,	""),
+	CLK_LOOKUP("mem_clk",		rpm_msg_ram_p_clk.c,	""),
+	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-001a"),
+	CLK_LOOKUP("cam_clk",		cam1_clk.c,	"4-006c"),
+	CLK_LOOKUP("cam_clk",		cam1_clk.c,	"4-0048"),
+	CLK_LOOKUP("cam_clk",		cam2_clk.c,		NULL),
+	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-0020"),
+	CLK_LOOKUP("csi_src_clk",	csi0_src_clk.c,		"msm_csid.0"),
+	CLK_LOOKUP("csi_src_clk",	csi1_src_clk.c,		"msm_csid.1"),
+	CLK_LOOKUP("csi_src_clk",	csi2_src_clk.c,		"msm_csid.2"),
+	CLK_LOOKUP("csi_clk",		csi0_clk.c,		"msm_csid.0"),
+	CLK_LOOKUP("csi_clk",		csi1_clk.c,		"msm_csid.1"),
+	CLK_LOOKUP("csi_clk",		csi2_clk.c,		"msm_csid.2"),
+	CLK_LOOKUP("csi_phy_clk",	csi0_phy_clk.c,		"msm_csid.0"),
+	CLK_LOOKUP("csi_phy_clk",	csi1_phy_clk.c,		"msm_csid.1"),
+	CLK_LOOKUP("csi_phy_clk",	csi2_phy_clk.c,		"msm_csid.2"),
+	CLK_LOOKUP("csi_pix_clk",	csi_pix_clk.c,		"msm_ispif.0"),
+	CLK_LOOKUP("csi_rdi_clk",	csi_rdi_clk.c,		"msm_ispif.0"),
+	CLK_LOOKUP("csi_src_clk",	csi2_src_clk.c,		NULL),
+	CLK_LOOKUP("csi_clk",		csi2_clk.c,		NULL),
+	CLK_LOOKUP("csi_pix1_clk",	csi_pix1_clk.c,		"msm_ispif.0"),
+	CLK_LOOKUP("csi_rdi1_clk",	csi_rdi1_clk.c,		"msm_ispif.0"),
+	CLK_LOOKUP("csi_rdi2_clk",	csi_rdi2_clk.c,		"msm_ispif.0"),
+	CLK_LOOKUP("csi_phy_clk",	csi2_phy_clk.c,		NULL),
+	CLK_LOOKUP("csi2phy_timer_clk",	csi2phy_timer_clk.c,	NULL),
+	CLK_LOOKUP("csiphy_timer_src_clk",
+			   csiphy_timer_src_clk.c, "msm_csiphy.0"),
+	CLK_LOOKUP("csiphy_timer_src_clk",
+			   csiphy_timer_src_clk.c, "msm_csiphy.1"),
+	CLK_LOOKUP("csiphy_timer_src_clk",
+			   csiphy_timer_src_clk.c, "msm_csiphy.2"),
+	CLK_LOOKUP("csiphy_timer_clk",	csi0phy_timer_clk.c,	"msm_csiphy.0"),
+	CLK_LOOKUP("csiphy_timer_clk",	csi1phy_timer_clk.c,	"msm_csiphy.1"),
+	CLK_LOOKUP("csiphy_timer_clk",	csi2phy_timer_clk.c,	"msm_csiphy.2"),
+	CLK_LOOKUP("byte_clk",	dsi1_byte_clk.c,	"mipi_dsi.1"),
+	CLK_LOOKUP("esc_clk",	dsi1_esc_clk.c,		"mipi_dsi.1"),
+	CLK_LOOKUP("core_clk",		gfx3d_clk.c,	"kgsl-3d0.0"),
+	CLK_LOOKUP("core_clk",		gfx3d_clk.c,	"footswitch-8x60.2"),
+	CLK_LOOKUP("bus_clk",
+			    gfx3d_axi_clk_8930.c, "footswitch-8x60.2"),
+	CLK_LOOKUP("bus_clk",		ijpeg_axi_clk.c, "footswitch-8x60.3"),
+	CLK_LOOKUP("mem_clk",		imem_axi_clk.c, "msm_gemini.0"),
+	CLK_LOOKUP("core_clk",          ijpeg_clk.c,    "msm_gemini.0"),
+	CLK_LOOKUP("core_clk",		ijpeg_clk.c,	"footswitch-8x60.3"),
+	CLK_LOOKUP("core_clk",		mdp_clk.c,		"mdp.0"),
+	CLK_LOOKUP("core_clk",		mdp_clk.c,	"footswitch-8x60.4"),
+	CLK_LOOKUP("vsync_clk",	mdp_vsync_clk.c,	"mdp.0"),
+	CLK_LOOKUP("vsync_clk",		mdp_vsync_clk.c, "footswitch-8x60.4"),
+	CLK_LOOKUP("lut_clk",		lut_mdp_clk.c,		"mdp.0"),
+	CLK_LOOKUP("lut_clk",		lut_mdp_clk.c,	"footswitch-8x60.4"),
+	CLK_LOOKUP("core_clk",		rot_clk.c,	"msm_rotator.0"),
+	CLK_LOOKUP("core_clk",		rot_clk.c,	"footswitch-8x60.6"),
+	CLK_LOOKUP("src_clk",	tv_src_clk.c,		"dtv.0"),
+	CLK_LOOKUP("src_clk",	tv_src_clk.c,		"tvenc.0"),
+	CLK_LOOKUP("tv_src_clk",	tv_src_clk.c,	"footswitch-8x60.4"),
+	CLK_LOOKUP("dac_clk",	tv_dac_clk.c,		"tvenc.0"),
+	CLK_LOOKUP("core_clk",		vcodec_clk.c,	"msm_vidc.0"),
+	CLK_LOOKUP("core_clk",		vcodec_clk.c,	"footswitch-8x60.7"),
+	CLK_LOOKUP("mdp_clk",	mdp_tv_clk.c,		"dtv.0"),
+	CLK_LOOKUP("mdp_clk",	mdp_tv_clk.c,		"tvenc.0"),
+	CLK_LOOKUP("tv_clk",		mdp_tv_clk.c,	"footswitch-8x60.4"),
+	CLK_LOOKUP("hdmi_clk",		hdmi_tv_clk.c,		"dtv.0"),
+	CLK_LOOKUP("core_clk",		hdmi_app_clk.c,	"hdmi_msm.1"),
+	CLK_LOOKUP("vpe_clk",		vpe_clk.c,		"msm_vpe.0"),
+	CLK_LOOKUP("core_clk",		vpe_clk.c,	"footswitch-8x60.9"),
+	CLK_LOOKUP("vfe_clk",		vfe_clk.c,		"msm_vfe.0"),
+	CLK_LOOKUP("core_clk",		vfe_clk.c,	"footswitch-8x60.8"),
+	CLK_LOOKUP("csi_vfe_clk",	csi_vfe_clk.c,		"msm_vfe.0"),
+	CLK_LOOKUP("bus_clk",		vfe_axi_clk.c,	"footswitch-8x60.8"),
+	CLK_LOOKUP("bus_clk",		mdp_axi_clk.c,	"footswitch-8x60.4"),
+	CLK_LOOKUP("bus_clk",		rot_axi_clk.c,	"footswitch-8x60.6"),
+	CLK_LOOKUP("bus_clk",		vcodec_axi_clk.c, "footswitch-8x60.7"),
+	CLK_LOOKUP("bus_a_clk",	       vcodec_axi_a_clk.c, "footswitch-8x60.7"),
+	CLK_LOOKUP("bus_b_clk",        vcodec_axi_b_clk.c, "footswitch-8x60.7"),
+	CLK_LOOKUP("bus_clk",		vpe_axi_clk.c,	"footswitch-8x60.9"),
+	CLK_LOOKUP("arb_clk",		amp_p_clk.c,		"mipi_dsi.1"),
+	CLK_LOOKUP("csi_pclk",		csi_p_clk.c,		"msm_csid.0"),
+	CLK_LOOKUP("csi_pclk",		csi_p_clk.c,		"msm_csid.1"),
+	CLK_LOOKUP("csi_pclk",		csi_p_clk.c,		"msm_csid.2"),
+	CLK_LOOKUP("master_iface_clk",	dsi1_m_p_clk.c,		"mipi_dsi.1"),
+	CLK_LOOKUP("slave_iface_clk",	dsi1_s_p_clk.c,		"mipi_dsi.1"),
+	CLK_LOOKUP("iface_clk",		gfx3d_p_clk.c,	"kgsl-3d0.0"),
+	CLK_LOOKUP("iface_clk",		gfx3d_p_clk.c,	"footswitch-8x60.2"),
+	CLK_LOOKUP("master_iface_clk",	hdmi_m_p_clk.c,	"hdmi_msm.1"),
+	CLK_LOOKUP("slave_iface_clk",	hdmi_s_p_clk.c,	"hdmi_msm.1"),
+	CLK_LOOKUP("iface_clk",		ijpeg_p_clk.c,	"msm_gemini.0"),
+	CLK_LOOKUP("iface_clk",		ijpeg_p_clk.c,	"footswitch-8x60.3"),
+	CLK_LOOKUP("mem_iface_clk",	imem_p_clk.c,	"kgsl-3d0.0"),
+	CLK_LOOKUP("iface_clk",		mdp_p_clk.c,		"mdp.0"),
+	CLK_LOOKUP("iface_clk",		mdp_p_clk.c,	"footswitch-8x60.4"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu"),
+	CLK_LOOKUP("iface_clk",		rot_p_clk.c,	"msm_rotator.0"),
+	CLK_LOOKUP("iface_clk",		rot_p_clk.c,	"footswitch-8x60.6"),
+	CLK_LOOKUP("iface_clk",		vcodec_p_clk.c,	"msm_vidc.0"),
+	CLK_LOOKUP("iface_clk",		vcodec_p_clk.c,	"footswitch-8x60.7"),
+	CLK_LOOKUP("vfe_pclk",		vfe_p_clk.c,		"msm_vfe.0"),
+	CLK_LOOKUP("iface_clk",		vfe_p_clk.c,	"footswitch-8x60.8"),
+	CLK_LOOKUP("vpe_pclk",		vpe_p_clk.c,		"msm_vpe.0"),
+	CLK_LOOKUP("iface_clk",		vpe_p_clk.c,	"footswitch-8x60.9"),
+	CLK_LOOKUP("bit_clk",		mi2s_bit_clk.c,		"msm-dai-q6.6"),
+	CLK_LOOKUP("osr_clk",		mi2s_osr_clk.c,		"msm-dai-q6.6"),
+	CLK_LOOKUP("bit_clk",		codec_i2s_mic_bit_clk.c,
+			   "msm-dai-q6.1"),
+	CLK_LOOKUP("osr_clk",		codec_i2s_mic_osr_clk.c,
+			   "msm-dai-q6.1"),
+	CLK_LOOKUP("bit_clk",		spare_i2s_mic_bit_clk.c,
+			   "msm-dai-q6.5"),
+	CLK_LOOKUP("osr_clk",		spare_i2s_mic_osr_clk.c,
+			   "msm-dai-q6.5"),
+	CLK_LOOKUP("bit_clk",		codec_i2s_spkr_bit_clk.c,
+			   "msm-dai-q6.16384"),
+	CLK_LOOKUP("osr_clk",		codec_i2s_spkr_osr_clk.c,
+			   "msm-dai-q6.16384"),
+	CLK_LOOKUP("bit_clk",		spare_i2s_spkr_bit_clk.c,
+			   "msm-dai-q6.4"),
+	CLK_LOOKUP("osr_clk",		spare_i2s_spkr_osr_clk.c,
+			   "msm-dai-q6.4"),
+	CLK_LOOKUP("pcm_clk",		pcm_clk.c,		"msm-dai-q6.2"),
+	CLK_LOOKUP("sps_slimbus_clk",	sps_slimbus_clk.c,	NULL),
+	CLK_LOOKUP("core_clk",		audio_slimbus_clk.c, "msm_slim_ctrl.1"),
+	CLK_LOOKUP("core_clk",		vpe_axi_clk.c,		"msm_iommu.1"),
+	CLK_LOOKUP("core_clk",		mdp_axi_clk.c,		"msm_iommu.2"),
+	CLK_LOOKUP("core_clk",		mdp_axi_clk.c,		"msm_iommu.3"),
+	CLK_LOOKUP("core_clk",		rot_axi_clk.c,		"msm_iommu.4"),
+	CLK_LOOKUP("core_clk",		ijpeg_axi_clk.c,	"msm_iommu.5"),
+	CLK_LOOKUP("core_clk",		vfe_axi_clk.c,		"msm_iommu.6"),
+	CLK_LOOKUP("core_clk",		vcodec_axi_a_clk.c,	"msm_iommu.7"),
+	CLK_LOOKUP("core_clk",		vcodec_axi_b_clk.c,	"msm_iommu.8"),
+	CLK_LOOKUP("core_clk",		gfx3d_axi_clk_8930.c,	"msm_iommu.9"),
+	CLK_LOOKUP("core_clk",		gfx3d_axi_clk_8930.c,	"msm_iommu.10"),
+
+	CLK_LOOKUP("mdp_iommu_clk", mdp_axi_clk.c,	"msm_vidc.0"),
+	CLK_LOOKUP("rot_iommu_clk",	rot_axi_clk.c,	"msm_vidc.0"),
+	CLK_LOOKUP("vcodec_iommu0_clk", vcodec_axi_a_clk.c, "msm_vidc.0"),
+	CLK_LOOKUP("vcodec_iommu1_clk", vcodec_axi_b_clk.c, "msm_vidc.0"),
+	CLK_LOOKUP("smmu_iface_clk", smmu_p_clk.c,	"msm_vidc.0"),
+	CLK_LOOKUP("core_clk",		vcodec_axi_clk.c,  "pil_vidc"),
+	CLK_LOOKUP("smmu_iface_clk",	smmu_p_clk.c,  "pil_vidc"),
+
+	CLK_LOOKUP("dfab_dsps_clk",	dfab_dsps_clk.c, NULL),
+	CLK_LOOKUP("core_clk",		dfab_usb_hs_clk.c,	"msm_otg"),
+	CLK_LOOKUP("bus_clk",		dfab_sdc1_clk.c, "msm_sdcc.1"),
+	CLK_LOOKUP("bus_clk",		dfab_sdc2_clk.c, "msm_sdcc.2"),
+	CLK_LOOKUP("bus_clk",		dfab_sdc3_clk.c, "msm_sdcc.3"),
+	CLK_LOOKUP("bus_clk",		dfab_sdc4_clk.c, "msm_sdcc.4"),
+	CLK_LOOKUP("bus_clk",		dfab_sdc5_clk.c, "msm_sdcc.5"),
+	CLK_LOOKUP("dfab_clk",		dfab_sps_clk.c,	"msm_sps"),
+	CLK_LOOKUP("bus_clk",		dfab_bam_dmux_clk.c,	"BAM_RMNT"),
+	CLK_LOOKUP("bus_clk",		dfab_scm_clk.c,	"scm"),
+	CLK_LOOKUP("bus_clk",		dfab_qseecom_clk.c,	"qseecom"),
+
+	CLK_LOOKUP("mem_clk",		ebi1_adm_clk.c, "msm_dmov"),
+
+	CLK_LOOKUP("l2_mclk",		l2_m_clk,     ""),
+	CLK_LOOKUP("krait0_mclk",	krait0_m_clk, ""),
+	CLK_LOOKUP("krait1_mclk",	krait1_m_clk, ""),
+	CLK_LOOKUP("q6sw_clk",		q6sw_clk,     ""),
+	CLK_LOOKUP("q6fw_clk",		q6fw_clk,     ""),
+	CLK_LOOKUP("q6_func_clk",	q6_func_clk,  ""),
+};
+/*
+ * Miscellaneous clock register initializations
+ */
+
+/* Read, modify, then write-back a register. */
+static void __init rmwreg(uint32_t val, void *reg, uint32_t mask)
+{
+	uint32_t regval = readl_relaxed(reg);
+	regval &= ~mask;
+	regval |= val;
+	writel_relaxed(regval, reg);
+}
+
+static struct pll_config_regs pll4_regs __initdata = {
+	.l_reg = LCC_PLL0_L_VAL_REG,
+	.m_reg = LCC_PLL0_M_VAL_REG,
+	.n_reg = LCC_PLL0_N_VAL_REG,
+	.config_reg = LCC_PLL0_CONFIG_REG,
+	.mode_reg = LCC_PLL0_MODE_REG,
+};
+
+static struct pll_config pll4_config __initdata = {
+	.l = 0xE,
+	.m = 0x27A,
+	.n = 0x465,
+	.vco_val = 0x0,
+	.vco_mask = BM(17, 16),
+	.pre_div_val = 0x0,
+	.pre_div_mask = BIT(19),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(21, 20),
+	.mn_ena_val = BIT(22),
+	.mn_ena_mask = BIT(22),
+	.main_output_val = BIT(23),
+	.main_output_mask = BIT(23),
+};
+
+static struct pll_config_regs pll15_regs __initdata = {
+	.l_reg = MM_PLL3_L_VAL_REG,
+	.m_reg = MM_PLL3_M_VAL_REG,
+	.n_reg = MM_PLL3_N_VAL_REG,
+	.config_reg = MM_PLL3_CONFIG_REG,
+	.mode_reg = MM_PLL3_MODE_REG,
+};
+
+static struct pll_config pll15_config __initdata = {
+	.l = (0x24 | BVAL(31, 7, 0x620)),
+	.m = 0x1,
+	.n = 0x9,
+	.vco_val = BVAL(17, 16, 0x2),
+	.vco_mask = BM(17, 16),
+	.pre_div_val = 0x0,
+	.pre_div_mask = BIT(19),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(21, 20),
+	.mn_ena_val = BIT(22),
+	.mn_ena_mask = BIT(22),
+	.main_output_val = BIT(23),
+	.main_output_mask = BIT(23),
+};
+
+static struct pll_config_regs pll14_regs __initdata = {
+	.l_reg = BB_PLL14_L_VAL_REG,
+	.m_reg = BB_PLL14_M_VAL_REG,
+	.n_reg = BB_PLL14_N_VAL_REG,
+	.config_reg = BB_PLL14_CONFIG_REG,
+	.mode_reg = BB_PLL14_MODE_REG,
+};
+
+static struct pll_config pll14_config __initdata = {
+	.l = (0x11 | BVAL(31, 7, 0x620)),
+	.m = 0x7,
+	.n = 0x9,
+	.vco_val = 0x0,
+	.vco_mask = BM(17, 16),
+	.pre_div_val = 0x0,
+	.pre_div_mask = BIT(19),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(21, 20),
+	.mn_ena_val = BIT(22),
+	.mn_ena_mask = BIT(22),
+	.main_output_val = BIT(23),
+	.main_output_mask = BIT(23),
+};
+
+static void __init reg_init(void)
+{
+	void __iomem *imem_reg;
+
+	/* Deassert MM SW_RESET_ALL signal. */
+	writel_relaxed(0, SW_RESET_ALL_REG);
+
+	/*
+	 * Some bits are only used on 8960 or 8064 or 8930 and are marked as
+	 * reserved bits on the other SoCs. Writing to these reserved bits
+	 * should have no effect.
+	 */
+	/*
+	 * Initialize MM AHB registers: Enable the FPB clock and disable HW
+	 * gating on non-8960 for all clocks. Also set VFE_AHB's
+	 * FORCE_CORE_ON bit to prevent its memory from being collapsed when
+	 * the clock is halted. The sleep and wake-up delays are set to safe
+	 * values.
+	 */
+	if (cpu_is_msm8960() || cpu_is_apq8064()) {
+		rmwreg(0x44000000, AHB_EN_REG,  0x6C000103);
+		writel_relaxed(0x3C7097F9, AHB_EN2_REG);
+	} else {
+		rmwreg(0x00000003, AHB_EN_REG,  0x6C000103);
+		writel_relaxed(0x000007F9, AHB_EN2_REG);
+	}
+	if (cpu_is_apq8064())
+		rmwreg(0x00000001, AHB_EN3_REG, 0x00000001);
+
+	/* Deassert all locally-owned MM AHB resets. */
+	rmwreg(0, SW_RESET_AHB_REG, 0xFFF7DFFF);
+	rmwreg(0, SW_RESET_AHB2_REG, 0x0000000F);
+
+	/* Initialize MM AXI registers: Enable HW gating for all clocks that
+	 * support it. Also set FORCE_CORE_ON bits, and any sleep and wake-up
+	 * delays to safe values. */
+	if ((cpu_is_msm8960() &&
+			SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 3) ||
+			cpu_is_apq8064()) {
+		rmwreg(0x0003AFF9, MAXI_EN_REG,  0x0803FFFF);
+		rmwreg(0x3A27FCFF, MAXI_EN2_REG, 0x3A3FFFFF);
+		rmwreg(0x0027FCFF, MAXI_EN4_REG, 0x017FFFFF);
+	} else {
+		rmwreg(0x000007F9, MAXI_EN_REG,  0x0803FFFF);
+		rmwreg(0x3027FCFF, MAXI_EN2_REG, 0x3A3FFFFF);
+		rmwreg(0x0027FCFF, MAXI_EN4_REG, 0x017FFFFF);
+	}
+	rmwreg(0x0027FCFF, MAXI_EN3_REG, 0x003FFFFF);
+	if (cpu_is_apq8064())
+		rmwreg(0x019FECFF, MAXI_EN5_REG, 0x01FFEFFF);
+	if (cpu_is_msm8930())
+		rmwreg(0x000004FF, MAXI_EN5_REG, 0x00000FFF);
+	if (cpu_is_msm8960() || cpu_is_apq8064())
+		rmwreg(0x00003C38, SAXI_EN_REG,  0x00003FFF);
+	else
+		rmwreg(0x000003C7, SAXI_EN_REG,  0x00003FFF);
+
+	/* Enable IMEM's clk_on signal */
+	imem_reg = ioremap(0x04b00040, 4);
+	if (imem_reg) {
+		writel_relaxed(0x3, imem_reg);
+		iounmap(imem_reg);
+	}
+
+	/* Initialize MM CC registers: Set MM FORCE_CORE_ON bits so that core
+	 * memories retain state even when not clocked. Also, set sleep and
+	 * wake-up delays to safe values. */
+	rmwreg(0x00000000, CSI0_CC_REG,       0x00000410);
+	rmwreg(0x00000000, CSI1_CC_REG,       0x00000410);
+	rmwreg(0x80FF0000, DSI1_BYTE_CC_REG,  0xE0FF0010);
+	rmwreg(0x80FF0000, DSI_PIXEL_CC_REG,  0xE0FF0010);
+	rmwreg(0xC0FF0000, GFX3D_CC_REG,      0xE0FF0010);
+	rmwreg(0x80FF0000, IJPEG_CC_REG,      0xE0FF0010);
+	rmwreg(0x80FF0000, MDP_CC_REG,        0xE1FF0010);
+	rmwreg(0x80FF0000, MDP_LUT_CC_REG,    0xE0FF0010);
+	rmwreg(0x80FF0000, ROT_CC_REG,        0xE0FF0010);
+	rmwreg(0x000004FF, TV_CC2_REG,        0x000007FF);
+	rmwreg(0xC0FF0000, VCODEC_CC_REG,     0xE0FF0010);
+	rmwreg(0x80FF0000, VFE_CC_REG,        0xE0FF4010);
+	rmwreg(0x800000FF, VFE_CC2_REG,       0xE00000FF);
+	rmwreg(0x80FF0000, VPE_CC_REG,        0xE0FF0010);
+	if (cpu_is_msm8960() || cpu_is_apq8064()) {
+		rmwreg(0x80FF0000, DSI2_BYTE_CC_REG,  0xE0FF0010);
+		rmwreg(0x80FF0000, DSI2_PIXEL_CC_REG, 0xE0FF0010);
+		rmwreg(0x80FF0000, JPEGD_CC_REG,      0xE0FF0010);
+	}
+	if (cpu_is_msm8960() || cpu_is_msm8930())
+		rmwreg(0x80FF0000, TV_CC_REG,         0xE1FFC010);
+
+	if (cpu_is_msm8960()) {
+		rmwreg(0x80FF0000, GFX2D0_CC_REG,     0xE0FF0010);
+		rmwreg(0x80FF0000, GFX2D1_CC_REG,     0xE0FF0010);
+	}
+	if (cpu_is_apq8064()) {
+		rmwreg(0x00000000, TV_CC_REG,         0x00004010);
+		rmwreg(0x80FF0000, VCAP_CC_REG,       0xE0FF1010);
+	}
+
+	/*
+	 * Initialize USB_HS_HCLK_FS registers: Set FORCE_C_ON bits so that
+	 * core remain active during halt state of the clk. Also, set sleep
+	 * and wake-up value to max.
+	 */
+	rmwreg(0x0000004F, USB_HS1_HCLK_FS_REG, 0x0000007F);
+	if (cpu_is_apq8064()) {
+		rmwreg(0x0000004F, USB_HS3_HCLK_FS_REG, 0x0000007F);
+		rmwreg(0x0000004F, USB_HS4_HCLK_FS_REG, 0x0000007F);
+	}
+
+	/* De-assert MM AXI resets to all hardware blocks. */
+	writel_relaxed(0, SW_RESET_AXI_REG);
+
+	/* Deassert all MM core resets. */
+	writel_relaxed(0, SW_RESET_CORE_REG);
+	writel_relaxed(0, SW_RESET_CORE2_REG);
+
+	/* Enable TSSC and PDM PXO sources. */
+	writel_relaxed(BIT(11), TSSC_CLK_CTL_REG);
+	writel_relaxed(BIT(15), PDM_CLK_NS_REG);
+
+	/* Source SLIMBus xo src from slimbus reference clock */
+	if (cpu_is_msm8960())
+		writel_relaxed(0x3, SLIMBUS_XO_SRC_CLK_CTL_REG);
+
+	/* Source the dsi_byte_clks from the DSI PHY PLLs */
+	rmwreg(0x1, DSI1_BYTE_NS_REG, 0x7);
+	if (cpu_is_msm8960() || cpu_is_apq8064())
+		rmwreg(0x2, DSI2_BYTE_NS_REG, 0x7);
+
+	/*
+	 * Source the sata_phy_ref_clk from PXO and set predivider of
+	 * sata_pmalive_clk to 1.
+	 */
+	if (cpu_is_apq8064()) {
+		rmwreg(0, SATA_PHY_REF_CLK_CTL_REG, 0x1);
+		rmwreg(0, SATA_PMALIVE_CLK_CTL_REG, 0x3);
+	}
+
+	/*
+	 * TODO: Programming below PLLs and prng_clk is temporary and
+	 *	 needs to be removed after bootloaders program them.
+	 */
+	if (cpu_is_apq8064()) {
+		u32 is_pll_enabled;
+
+		/* Program pxo_src_clk to source from PXO */
+		rmwreg(0x1, PXO_SRC_CLK_CTL_REG, 0x7);
+
+		/* Check if PLL14 is active */
+		is_pll_enabled = readl_relaxed(BB_PLL14_STATUS_REG) & BIT(16);
+		if (!is_pll_enabled)
+			/* Ref clk = 27MHz and program pll14 to 480MHz */
+			configure_pll(&pll14_config, &pll14_regs, 1);
+
+		/* Program PLL15 to 975MHz with ref clk = 27MHz */
+		configure_pll(&pll15_config, &pll15_regs, 0);
+
+		/* Check if PLL4 is active */
+		is_pll_enabled = readl_relaxed(LCC_PLL0_STATUS_REG) & BIT(16);
+		if (!is_pll_enabled)
+			/* Ref clk = 27MHz and program pll4 to 393.2160MHz */
+			configure_pll(&pll4_config, &pll4_regs, 1);
+
+		/* Enable PLL4 source on the LPASS Primary PLL Mux */
+		writel_relaxed(0x1, LCC_PRI_PLL_CLK_CTL_REG);
+
+		/* Program prng_clk to 64MHz if it isn't configured */
+		if (!readl_relaxed(PRNG_CLK_NS_REG))
+			writel_relaxed(0x2B, PRNG_CLK_NS_REG);
+	}
+
+	/*
+	 * Program PLL15 to 900MHz with ref clk = 27MHz and
+	 * only enable PLL main output.
+	 */
+	if (cpu_is_msm8930()) {
+		pll15_config.l = 0x21 | BVAL(31, 7, 0x600);
+		pll15_config.m = 0x1;
+		pll15_config.n = 0x3;
+		configure_pll(&pll15_config, &pll15_regs, 0);
+		/* Disable AUX and BIST outputs */
+		writel_relaxed(0, MM_PLL3_TEST_CTL_REG);
+	}
+}
+
+static void __init msm8960_clock_pre_init(void)
+{
+	if (cpu_is_apq8064()) {
+		vdd_sr2_pll.set_vdd = set_vdd_sr2_pll_8064;
+	} else if (cpu_is_msm8930() || cpu_is_msm8627()) {
+		vdd_dig.set_vdd = set_vdd_dig_8930;
+		vdd_sr2_pll.set_vdd = set_vdd_sr2_pll_8930;
+	}
+
+	/*
+	 * Change the freq tables for and voltage requirements for
+	 * clocks which differ between 8960 and 8064.
+	 */
+	if (cpu_is_apq8064()) {
+		gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8064;
+
+		memcpy(gfx3d_clk.c.fmax, fmax_gfx3d_8064,
+		       sizeof(gfx3d_clk.c.fmax));
+		memcpy(ijpeg_clk.c.fmax, fmax_ijpeg_8064,
+		       sizeof(ijpeg_clk.c.fmax));
+		memcpy(mdp_clk.c.fmax, fmax_mdp_8064,
+		       sizeof(ijpeg_clk.c.fmax));
+		memcpy(tv_src_clk.c.fmax, fmax_tv_src_8064,
+		       sizeof(tv_src_clk.c.fmax));
+		memcpy(vfe_clk.c.fmax, fmax_vfe_8064,
+		       sizeof(vfe_clk.c.fmax));
+
+		gmem_axi_clk.c.depends = &gfx3d_axi_clk_8064.c;
+	}
+
+	/*
+	 * Change the freq tables and voltage requirements for
+	 * clocks which differ between 8960 and 8930.
+	 */
+	if (cpu_is_msm8930()) {
+		gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8930;
+
+		memcpy(gfx3d_clk.c.fmax, fmax_gfx3d_8930,
+		       sizeof(gfx3d_clk.c.fmax));
+
+		pll15_clk.c.rate = 900000000;
+		gmem_axi_clk.c.depends = &gfx3d_axi_clk_8930.c;
+	}
+	if ((readl_relaxed(PRNG_CLK_NS_REG) & 0x7F) == 0x2B)
+		prng_clk.freq_tbl = clk_tbl_prng_64;
+
+	vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
+
+	clk_ops_local_pll.enable = sr_pll_clk_enable;
+
+	/* Initialize clock registers. */
+	reg_init();
+}
+
+static void __init msm8960_clock_post_init(void)
+{
+	/* Keep PXO on whenever APPS cpu is active */
+	clk_prepare_enable(&pxo_a_clk.c);
+
+	/* Reset 3D core while clocked to ensure it resets completely. */
+	clk_set_rate(&gfx3d_clk.c, 27000000);
+	clk_prepare_enable(&gfx3d_clk.c);
+	clk_reset(&gfx3d_clk.c, CLK_RESET_ASSERT);
+	udelay(5);
+	clk_reset(&gfx3d_clk.c, CLK_RESET_DEASSERT);
+	clk_disable_unprepare(&gfx3d_clk.c);
+
+	/* Initialize rates for clocks that only support one. */
+	clk_set_rate(&pdm_clk.c, 27000000);
+	clk_set_rate(&prng_clk.c, prng_clk.freq_tbl->freq_hz);
+	clk_set_rate(&mdp_vsync_clk.c, 27000000);
+	clk_set_rate(&tsif_ref_clk.c, 105000);
+	clk_set_rate(&tssc_clk.c, 27000000);
+	clk_set_rate(&usb_hs1_xcvr_clk.c, 60000000);
+	if (cpu_is_apq8064()) {
+		clk_set_rate(&usb_hs3_xcvr_clk.c, 60000000);
+		clk_set_rate(&usb_hs4_xcvr_clk.c, 60000000);
+	}
+	clk_set_rate(&usb_fs1_src_clk.c, 60000000);
+	if (cpu_is_msm8960() || cpu_is_msm8930())
+		clk_set_rate(&usb_fs2_src_clk.c, 60000000);
+	clk_set_rate(&usb_hsic_xcvr_fs_clk.c, 60000000);
+	clk_set_rate(&usb_hsic_hsic_src_clk.c, 480000000);
+	clk_set_rate(&usb_hsic_hsio_cal_clk.c, 9000000);
+	clk_set_rate(&usb_hsic_system_clk.c, 60000000);
+	/*
+	 * Set the CSI rates to a safe default to avoid warnings when
+	 * switching csi pix and rdi clocks.
+	 */
+	clk_set_rate(&csi0_src_clk.c, 27000000);
+	clk_set_rate(&csi1_src_clk.c, 27000000);
+	clk_set_rate(&csi2_src_clk.c, 27000000);
+
+	/*
+	 * The halt status bits for these clocks may be incorrect at boot.
+	 * Toggle these clocks on and off to refresh them.
+	 */
+	clk_prepare_enable(&pdm_clk.c);
+	clk_disable_unprepare(&pdm_clk.c);
+	clk_prepare_enable(&tssc_clk.c);
+	clk_disable_unprepare(&tssc_clk.c);
+	clk_prepare_enable(&usb_hsic_hsic_clk.c);
+	clk_disable_unprepare(&usb_hsic_hsic_clk.c);
+
+	/*
+	 * Keep sfab floor @ 54MHz so that Krait AHB is at least 27MHz at all
+	 * times when Apps CPU is active. This ensures the timer's requirement
+	 * of Krait AHB running 4 times as fast as the timer itself.
+	 */
+	clk_set_rate(&sfab_tmr_a_clk.c, 54000000);
+	clk_prepare_enable(&sfab_tmr_a_clk.c);
+}
+
+static int __init msm8960_clock_late_init(void)
+{
+	int rc;
+	struct clk *mmfpb_a_clk = clk_get_sys("clock-8960", "mmfpb_a_clk");
+	struct clk *cfpb_a_clk = clk_get_sys("clock-8960", "cfpb_a_clk");
+
+	/* Vote for MMFPB to be at least 76.8MHz when an Apps CPU is active. */
+	if (WARN(IS_ERR(mmfpb_a_clk), "mmfpb_a_clk not found (%ld)\n",
+			PTR_ERR(mmfpb_a_clk)))
+		return PTR_ERR(mmfpb_a_clk);
+	rc = clk_set_rate(mmfpb_a_clk, 76800000);
+	if (WARN(rc, "mmfpb_a_clk rate was not set (%d)\n", rc))
+		return rc;
+	rc = clk_prepare_enable(mmfpb_a_clk);
+	if (WARN(rc, "mmfpb_a_clk not enabled (%d)\n", rc))
+		return rc;
+
+	/* Vote for CFPB to be at least 64MHz when an Apps CPU is active. */
+	if (WARN(IS_ERR(cfpb_a_clk), "cfpb_a_clk not found (%ld)\n",
+			PTR_ERR(cfpb_a_clk)))
+		return PTR_ERR(cfpb_a_clk);
+	rc = clk_set_rate(cfpb_a_clk, 64000000);
+	if (WARN(rc, "cfpb_a_clk rate was not set (%d)\n", rc))
+		return rc;
+	rc = clk_prepare_enable(cfpb_a_clk);
+	if (WARN(rc, "cfpb_a_clk not enabled (%d)\n", rc))
+		return rc;
+
+	return unvote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
+}
+
+struct clock_init_data msm8960_clock_init_data __initdata = {
+	.table = msm_clocks_8960,
+	.size = ARRAY_SIZE(msm_clocks_8960),
+	.pre_init = msm8960_clock_pre_init,
+	.post_init = msm8960_clock_post_init,
+	.late_init = msm8960_clock_late_init,
+};
+
+struct clock_init_data apq8064_clock_init_data __initdata = {
+	.table = msm_clocks_8064,
+	.size = ARRAY_SIZE(msm_clocks_8064),
+	.pre_init = msm8960_clock_pre_init,
+	.post_init = msm8960_clock_post_init,
+	.late_init = msm8960_clock_late_init,
+};
+
+struct clock_init_data msm8930_clock_init_data __initdata = {
+	.table = msm_clocks_8930,
+	.size = ARRAY_SIZE(msm_clocks_8930),
+	.pre_init = msm8960_clock_pre_init,
+	.post_init = msm8960_clock_post_init,
+	.late_init = msm8960_clock_late_init,
+};
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
new file mode 100644
index 0000000..7aed579
--- /dev/null
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -0,0 +1,3869 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+
+#include <mach/msm_iomap.h>
+#include <mach/clk.h>
+#include <mach/scm-io.h>
+#include <mach/rpm.h>
+#include <mach/rpm-regulator.h>
+
+#include "clock-local.h"
+#include "clock-rpm.h"
+#include "clock-voter.h"
+#include "clock-pll.h"
+
+#ifdef CONFIG_MSM_SECURE_IO
+#undef readl_relaxed
+#undef writel_relaxed
+#define readl_relaxed secure_readl
+#define writel_relaxed secure_writel
+#endif
+
+#define REG(off)	(MSM_CLK_CTL_BASE + (off))
+#define REG_MM(off)	(MSM_MMSS_CLK_CTL_BASE + (off))
+#define REG_LPA(off)	(MSM_LPASS_CLK_CTL_BASE + (off))
+
+/* Peripheral clock registers. */
+#define CE2_HCLK_CTL_REG			REG(0x2740)
+#define CLK_HALT_CFPB_STATEA_REG		REG(0x2FCC)
+#define CLK_HALT_CFPB_STATEB_REG		REG(0x2FD0)
+#define CLK_HALT_CFPB_STATEC_REG		REG(0x2FD4)
+#define CLK_HALT_DFAB_STATE_REG			REG(0x2FC8)
+#define CLK_HALT_MSS_SMPSS_MISC_STATE_REG	REG(0x2FDC)
+#define CLK_HALT_SFPB_MISC_STATE_REG		REG(0x2FD8)
+#define CLK_TEST_REG				REG(0x2FA0)
+#define EBI2_2X_CLK_CTL_REG			REG(0x2660)
+#define EBI2_CLK_CTL_REG			REG(0x2664)
+#define GPn_MD_REG(n)				REG(0x2D00+(0x20*(n)))
+#define GPn_NS_REG(n)				REG(0x2D24+(0x20*(n)))
+#define GSBIn_HCLK_CTL_REG(n)			REG(0x29C0+(0x20*((n)-1)))
+#define GSBIn_QUP_APPS_MD_REG(n)		REG(0x29C8+(0x20*((n)-1)))
+#define GSBIn_QUP_APPS_NS_REG(n)		REG(0x29CC+(0x20*((n)-1)))
+#define GSBIn_RESET_REG(n)			REG(0x29DC+(0x20*((n)-1)))
+#define GSBIn_UART_APPS_MD_REG(n)		REG(0x29D0+(0x20*((n)-1)))
+#define GSBIn_UART_APPS_NS_REG(n)		REG(0x29D4+(0x20*((n)-1)))
+#define PDM_CLK_NS_REG				REG(0x2CC0)
+#define BB_PLL_ENA_SC0_REG			REG(0x34C0)
+#define BB_PLL0_STATUS_REG			REG(0x30D8)
+#define BB_PLL6_STATUS_REG			REG(0x3118)
+#define BB_PLL8_L_VAL_REG			REG(0x3144)
+#define BB_PLL8_M_VAL_REG			REG(0x3148)
+#define BB_PLL8_MODE_REG			REG(0x3140)
+#define BB_PLL8_N_VAL_REG			REG(0x314C)
+#define BB_PLL8_STATUS_REG			REG(0x3158)
+#define PLLTEST_PAD_CFG_REG			REG(0x2FA4)
+#define PMEM_ACLK_CTL_REG			REG(0x25A0)
+#define PPSS_HCLK_CTL_REG			REG(0x2580)
+#define PRNG_CLK_NS_REG				REG(0x2E80)
+#define RINGOSC_NS_REG				REG(0x2DC0)
+#define RINGOSC_STATUS_REG			REG(0x2DCC)
+#define RINGOSC_TCXO_CTL_REG			REG(0x2DC4)
+#define SC0_U_CLK_BRANCH_ENA_VOTE_REG		REG(0x3080)
+#define SC1_U_CLK_BRANCH_ENA_VOTE_REG		REG(0x30A0)
+#define SC0_U_CLK_SLEEP_ENA_VOTE_REG		REG(0x3084)
+#define SC1_U_CLK_SLEEP_ENA_VOTE_REG		REG(0x30A4)
+#define SDCn_APPS_CLK_MD_REG(n)			REG(0x2828+(0x20*((n)-1)))
+#define SDCn_APPS_CLK_NS_REG(n)			REG(0x282C+(0x20*((n)-1)))
+#define SDCn_HCLK_CTL_REG(n)			REG(0x2820+(0x20*((n)-1)))
+#define SDCn_RESET_REG(n)			REG(0x2830+(0x20*((n)-1)))
+#define TSIF_HCLK_CTL_REG			REG(0x2700)
+#define TSIF_REF_CLK_MD_REG			REG(0x270C)
+#define TSIF_REF_CLK_NS_REG			REG(0x2710)
+#define TSSC_CLK_CTL_REG			REG(0x2CA0)
+#define USB_FSn_HCLK_CTL_REG(n)			REG(0x2960+(0x20*((n)-1)))
+#define USB_FSn_RESET_REG(n)			REG(0x2974+(0x20*((n)-1)))
+#define USB_FSn_SYSTEM_CLK_CTL_REG(n)		REG(0x296C+(0x20*((n)-1)))
+#define USB_FSn_XCVR_FS_CLK_MD_REG(n)		REG(0x2964+(0x20*((n)-1)))
+#define USB_FSn_XCVR_FS_CLK_NS_REG(n)		REG(0x2968+(0x20*((n)-1)))
+#define USB_HS1_HCLK_CTL_REG			REG(0x2900)
+#define USB_HS1_RESET_REG			REG(0x2910)
+#define USB_HS1_XCVR_FS_CLK_MD_REG		REG(0x2908)
+#define USB_HS1_XCVR_FS_CLK_NS_REG		REG(0x290C)
+#define USB_PHY0_RESET_REG			REG(0x2E20)
+
+/* Multimedia clock registers. */
+#define AHB_EN_REG				REG_MM(0x0008)
+#define AHB_EN2_REG				REG_MM(0x0038)
+#define AHB_NS_REG				REG_MM(0x0004)
+#define AXI_NS_REG				REG_MM(0x0014)
+#define CAMCLK_CC_REG				REG_MM(0x0140)
+#define CAMCLK_MD_REG				REG_MM(0x0144)
+#define CAMCLK_NS_REG				REG_MM(0x0148)
+#define CSI_CC_REG				REG_MM(0x0040)
+#define CSI_NS_REG				REG_MM(0x0048)
+#define DBG_BUS_VEC_A_REG			REG_MM(0x01C8)
+#define DBG_BUS_VEC_B_REG			REG_MM(0x01CC)
+#define DBG_BUS_VEC_C_REG			REG_MM(0x01D0)
+#define DBG_BUS_VEC_D_REG			REG_MM(0x01D4)
+#define DBG_BUS_VEC_E_REG			REG_MM(0x01D8)
+#define DBG_BUS_VEC_F_REG			REG_MM(0x01DC)
+#define DBG_BUS_VEC_H_REG			REG_MM(0x01E4)
+#define DBG_BUS_VEC_I_REG			REG_MM(0x01E8)
+#define DBG_CFG_REG_HS_REG			REG_MM(0x01B4)
+#define DBG_CFG_REG_LS_REG			REG_MM(0x01B8)
+#define GFX2D0_CC_REG				REG_MM(0x0060)
+#define GFX2D0_MD0_REG				REG_MM(0x0064)
+#define GFX2D0_MD1_REG				REG_MM(0x0068)
+#define GFX2D0_NS_REG				REG_MM(0x0070)
+#define GFX2D1_CC_REG				REG_MM(0x0074)
+#define GFX2D1_MD0_REG				REG_MM(0x0078)
+#define GFX2D1_MD1_REG				REG_MM(0x006C)
+#define GFX2D1_NS_REG				REG_MM(0x007C)
+#define GFX3D_CC_REG				REG_MM(0x0080)
+#define GFX3D_MD0_REG				REG_MM(0x0084)
+#define GFX3D_MD1_REG				REG_MM(0x0088)
+#define GFX3D_NS_REG				REG_MM(0x008C)
+#define IJPEG_CC_REG				REG_MM(0x0098)
+#define IJPEG_MD_REG				REG_MM(0x009C)
+#define IJPEG_NS_REG				REG_MM(0x00A0)
+#define JPEGD_CC_REG				REG_MM(0x00A4)
+#define JPEGD_NS_REG				REG_MM(0x00AC)
+#define MAXI_EN_REG				REG_MM(0x0018)
+#define MAXI_EN2_REG				REG_MM(0x0020)
+#define MAXI_EN3_REG				REG_MM(0x002C)
+#define MDP_CC_REG				REG_MM(0x00C0)
+#define MDP_MD0_REG				REG_MM(0x00C4)
+#define MDP_MD1_REG				REG_MM(0x00C8)
+#define MDP_NS_REG				REG_MM(0x00D0)
+#define MISC_CC_REG				REG_MM(0x0058)
+#define MISC_CC2_REG				REG_MM(0x005C)
+#define PIXEL_CC_REG				REG_MM(0x00D4)
+#define PIXEL_CC2_REG				REG_MM(0x0120)
+#define PIXEL_MD_REG				REG_MM(0x00D8)
+#define PIXEL_NS_REG				REG_MM(0x00DC)
+#define MM_PLL0_MODE_REG			REG_MM(0x0300)
+#define MM_PLL1_MODE_REG			REG_MM(0x031C)
+#define MM_PLL2_CONFIG_REG			REG_MM(0x0348)
+#define MM_PLL2_L_VAL_REG			REG_MM(0x033C)
+#define MM_PLL2_M_VAL_REG			REG_MM(0x0340)
+#define MM_PLL2_MODE_REG			REG_MM(0x0338)
+#define MM_PLL2_N_VAL_REG			REG_MM(0x0344)
+#define ROT_CC_REG				REG_MM(0x00E0)
+#define ROT_NS_REG				REG_MM(0x00E8)
+#define SAXI_EN_REG				REG_MM(0x0030)
+#define SW_RESET_AHB_REG			REG_MM(0x020C)
+#define SW_RESET_ALL_REG			REG_MM(0x0204)
+#define SW_RESET_AXI_REG			REG_MM(0x0208)
+#define SW_RESET_CORE_REG			REG_MM(0x0210)
+#define TV_CC_REG				REG_MM(0x00EC)
+#define TV_CC2_REG				REG_MM(0x0124)
+#define TV_MD_REG				REG_MM(0x00F0)
+#define TV_NS_REG				REG_MM(0x00F4)
+#define VCODEC_CC_REG				REG_MM(0x00F8)
+#define VCODEC_MD0_REG				REG_MM(0x00FC)
+#define VCODEC_MD1_REG				REG_MM(0x0128)
+#define VCODEC_NS_REG				REG_MM(0x0100)
+#define VFE_CC_REG				REG_MM(0x0104)
+#define VFE_MD_REG				REG_MM(0x0108)
+#define VFE_NS_REG				REG_MM(0x010C)
+#define VPE_CC_REG				REG_MM(0x0110)
+#define VPE_NS_REG				REG_MM(0x0118)
+
+/* Low-power Audio clock registers. */
+#define LCC_CLK_LS_DEBUG_CFG_REG		REG_LPA(0x00A8)
+#define LCC_CODEC_I2S_MIC_MD_REG		REG_LPA(0x0064)
+#define LCC_CODEC_I2S_MIC_NS_REG		REG_LPA(0x0060)
+#define LCC_CODEC_I2S_MIC_STATUS_REG		REG_LPA(0x0068)
+#define LCC_CODEC_I2S_SPKR_MD_REG		REG_LPA(0x0070)
+#define LCC_CODEC_I2S_SPKR_NS_REG		REG_LPA(0x006C)
+#define LCC_CODEC_I2S_SPKR_STATUS_REG		REG_LPA(0x0074)
+#define LCC_MI2S_MD_REG				REG_LPA(0x004C)
+#define LCC_MI2S_NS_REG				REG_LPA(0x0048)
+#define LCC_MI2S_STATUS_REG			REG_LPA(0x0050)
+#define LCC_PCM_MD_REG				REG_LPA(0x0058)
+#define LCC_PCM_NS_REG				REG_LPA(0x0054)
+#define LCC_PCM_STATUS_REG			REG_LPA(0x005C)
+#define LCC_PLL0_CONFIG_REG			REG_LPA(0x0014)
+#define LCC_PLL0_L_VAL_REG			REG_LPA(0x0004)
+#define LCC_PLL0_M_VAL_REG			REG_LPA(0x0008)
+#define LCC_PLL0_MODE_REG			REG_LPA(0x0000)
+#define LCC_PLL0_N_VAL_REG			REG_LPA(0x000C)
+#define LCC_PRI_PLL_CLK_CTL_REG			REG_LPA(0x00C4)
+#define LCC_SPARE_I2S_MIC_MD_REG		REG_LPA(0x007C)
+#define LCC_SPARE_I2S_MIC_NS_REG		REG_LPA(0x0078)
+#define LCC_SPARE_I2S_MIC_STATUS_REG		REG_LPA(0x0080)
+#define LCC_SPARE_I2S_SPKR_MD_REG		REG_LPA(0x0088)
+#define LCC_SPARE_I2S_SPKR_NS_REG		REG_LPA(0x0084)
+#define LCC_SPARE_I2S_SPKR_STATUS_REG		REG_LPA(0x008C)
+
+/* MUX source input identifiers. */
+#define pxo_to_bb_mux		0
+#define mxo_to_bb_mux		1
+#define cxo_to_bb_mux		5
+#define pll0_to_bb_mux		2
+#define pll8_to_bb_mux		3
+#define pll6_to_bb_mux		4
+#define gnd_to_bb_mux		6
+#define pxo_to_mm_mux		0
+#define pll1_to_mm_mux		1	/* or MMSS_PLL0 */
+#define pll2_to_mm_mux		1	/* or MMSS_PLL1 */
+#define pll3_to_mm_mux		3	/* or MMSS_PLL2 */
+#define pll8_to_mm_mux		2	/* or MMSS_GPERF */
+#define pll0_to_mm_mux		3	/* or MMSS_GPLL0 */
+#define mxo_to_mm_mux		4
+#define gnd_to_mm_mux		6
+#define cxo_to_xo_mux		0
+#define pxo_to_xo_mux		1
+#define mxo_to_xo_mux		2
+#define gnd_to_xo_mux		3
+#define pxo_to_lpa_mux		0
+#define cxo_to_lpa_mux		1
+#define pll4_to_lpa_mux		2	/* or LPA_PLL0 */
+#define gnd_to_lpa_mux		6
+
+/* Test Vector Macros */
+#define TEST_TYPE_PER_LS	1
+#define TEST_TYPE_PER_HS	2
+#define TEST_TYPE_MM_LS		3
+#define TEST_TYPE_MM_HS		4
+#define TEST_TYPE_LPA		5
+#define TEST_TYPE_SC		6
+#define TEST_TYPE_MM_HS2X	7
+#define TEST_TYPE_SHIFT		24
+#define TEST_CLK_SEL_MASK	BM(23, 0)
+#define TEST_VECTOR(s, t)	(((t) << TEST_TYPE_SHIFT) | BVAL(23, 0, (s)))
+#define TEST_PER_LS(s)		TEST_VECTOR((s), TEST_TYPE_PER_LS)
+#define TEST_PER_HS(s)		TEST_VECTOR((s), TEST_TYPE_PER_HS)
+#define TEST_MM_LS(s)		TEST_VECTOR((s), TEST_TYPE_MM_LS)
+#define TEST_MM_HS(s)		TEST_VECTOR((s), TEST_TYPE_MM_HS)
+#define TEST_LPA(s)		TEST_VECTOR((s), TEST_TYPE_LPA)
+#define TEST_SC(s)		TEST_VECTOR((s), TEST_TYPE_SC)
+#define TEST_MM_HS2X(s)		TEST_VECTOR((s), TEST_TYPE_MM_HS2X)
+
+struct pll_rate {
+	const uint32_t	l_val;
+	const uint32_t	m_val;
+	const uint32_t	n_val;
+	const uint32_t	vco;
+	const uint32_t	post_div;
+	const uint32_t	i_bits;
+};
+#define PLL_RATE(l, m, n, v, d, i) { l, m, n, v, (d>>1), i }
+/*
+ * Clock frequency definitions and macros
+ */
+
+enum vdd_dig_levels {
+	VDD_DIG_NONE,
+	VDD_DIG_LOW,
+	VDD_DIG_NOMINAL,
+	VDD_DIG_HIGH
+};
+
+static int set_vdd_dig(struct clk_vdd_class *vdd_class, int level)
+{
+	static const int vdd_uv[] = {
+		[VDD_DIG_NONE]    =  500000,
+		[VDD_DIG_LOW]     = 1000000,
+		[VDD_DIG_NOMINAL] = 1100000,
+		[VDD_DIG_HIGH]    = 1200000
+	};
+
+	return rpm_vreg_set_voltage(RPM_VREG_ID_PM8058_S1, RPM_VREG_VOTER3,
+				    vdd_uv[level], 1200000, 1);
+}
+
+static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig);
+
+#define VDD_DIG_FMAX_MAP1(l1, f1) \
+	.vdd_class = &vdd_dig, \
+	.fmax[VDD_DIG_##l1] = (f1)
+#define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
+	.vdd_class = &vdd_dig, \
+	.fmax[VDD_DIG_##l1] = (f1), \
+	.fmax[VDD_DIG_##l2] = (f2)
+#define VDD_DIG_FMAX_MAP3(l1, f1, l2, f2, l3, f3) \
+	.vdd_class = &vdd_dig, \
+	.fmax[VDD_DIG_##l1] = (f1), \
+	.fmax[VDD_DIG_##l2] = (f2), \
+	.fmax[VDD_DIG_##l3] = (f3)
+
+DEFINE_CLK_RPM_BRANCH(pxo_clk, pxo_a_clk, PXO, 27000000);
+DEFINE_CLK_RPM_BRANCH(cxo_clk, cxo_a_clk, CXO, 19200000);
+
+static struct pll_vote_clk pll8_clk = {
+	.en_reg = BB_PLL_ENA_SC0_REG,
+	.en_mask = BIT(8),
+	.status_reg = BB_PLL8_STATUS_REG,
+	.status_mask = BIT(16),
+	.parent = &pxo_clk.c,
+	.c = {
+		.dbg_name = "pll8_clk",
+		.rate = 384000000,
+		.ops = &clk_ops_pll_vote,
+		CLK_INIT(pll8_clk.c),
+		.warned = true,
+	},
+};
+
+static struct pll_clk pll2_clk = {
+	.mode_reg = MM_PLL1_MODE_REG,
+	.parent = &pxo_clk.c,
+	.c = {
+		.dbg_name = "pll2_clk",
+		.rate = 800000000,
+		.ops = &clk_ops_local_pll,
+		CLK_INIT(pll2_clk.c),
+		.warned = true,
+	},
+};
+
+static struct pll_clk pll3_clk = {
+	.mode_reg = MM_PLL2_MODE_REG,
+	.parent = &pxo_clk.c,
+	.c = {
+		.dbg_name = "pll3_clk",
+		.rate = 0, /* TODO: Detect rate dynamically */
+		.ops = &clk_ops_local_pll,
+		CLK_INIT(pll3_clk.c),
+		.warned = true,
+	},
+};
+
+static int pll4_clk_enable(struct clk *clk)
+{
+	struct msm_rpm_iv_pair iv = { MSM_RPM_ID_PLL_4, 1 };
+	return msm_rpm_set_noirq(MSM_RPM_CTX_SET_0, &iv, 1);
+}
+
+static void pll4_clk_disable(struct clk *clk)
+{
+	struct msm_rpm_iv_pair iv = { MSM_RPM_ID_PLL_4, 0 };
+	msm_rpm_set_noirq(MSM_RPM_CTX_SET_0, &iv, 1);
+}
+
+static struct clk *pll4_clk_get_parent(struct clk *clk)
+{
+	return &pxo_clk.c;
+}
+
+static bool pll4_clk_is_local(struct clk *clk)
+{
+	return false;
+}
+
+static enum handoff pll4_clk_handoff(struct clk *clk)
+{
+	struct msm_rpm_iv_pair iv = { MSM_RPM_ID_PLL_4 };
+	int rc = msm_rpm_get_status(&iv, 1);
+	if (rc < 0 || !iv.value)
+		return HANDOFF_DISABLED_CLK;
+
+	return HANDOFF_ENABLED_CLK;
+}
+
+static struct clk_ops clk_ops_pll4 = {
+	.enable = pll4_clk_enable,
+	.disable = pll4_clk_disable,
+	.get_parent = pll4_clk_get_parent,
+	.is_local = pll4_clk_is_local,
+	.handoff = pll4_clk_handoff,
+};
+
+static struct fixed_clk pll4_clk = {
+	.c = {
+		.dbg_name = "pll4_clk",
+		.rate = 540672000,
+		.ops = &clk_ops_pll4,
+		CLK_INIT(pll4_clk.c),
+		.warned = true,
+	},
+};
+
+/*
+ * SoC-specific Set-Rate Functions
+ */
+
+/* Unlike other clocks, the TV rate is adjusted through PLL
+ * re-programming. It is also routed through an MND divider. */
+static void set_rate_tv(struct rcg_clk *clk, struct clk_freq_tbl *nf)
+{
+	struct pll_rate *rate = nf->extra_freq_data;
+	uint32_t pll_mode, pll_config, misc_cc2;
+
+	/* Disable PLL output. */
+	pll_mode = readl_relaxed(MM_PLL2_MODE_REG);
+	pll_mode &= ~BIT(0);
+	writel_relaxed(pll_mode, MM_PLL2_MODE_REG);
+
+	/* Assert active-low PLL reset. */
+	pll_mode &= ~BIT(2);
+	writel_relaxed(pll_mode, MM_PLL2_MODE_REG);
+
+	/* Program L, M and N values. */
+	writel_relaxed(rate->l_val, MM_PLL2_L_VAL_REG);
+	writel_relaxed(rate->m_val, MM_PLL2_M_VAL_REG);
+	writel_relaxed(rate->n_val, MM_PLL2_N_VAL_REG);
+
+	/* Configure MN counter, post-divide, VCO, and i-bits. */
+	pll_config = readl_relaxed(MM_PLL2_CONFIG_REG);
+	pll_config &= ~(BM(22, 20) | BM(18, 0));
+	pll_config |= rate->n_val ? BIT(22) : 0;
+	pll_config |= BVAL(21, 20, rate->post_div);
+	pll_config |= BVAL(17, 16, rate->vco);
+	pll_config |= rate->i_bits;
+	writel_relaxed(pll_config, MM_PLL2_CONFIG_REG);
+
+	/* Configure MND. */
+	set_rate_mnd(clk, nf);
+
+	/* Configure hdmi_ref_clk to be equal to the TV clock rate. */
+	misc_cc2 = readl_relaxed(MISC_CC2_REG);
+	misc_cc2 &= ~(BIT(28)|BM(21, 18));
+	misc_cc2 |= (BIT(28)|BVAL(21, 18, (nf->ns_val >> 14) & 0x3));
+	writel_relaxed(misc_cc2, MISC_CC2_REG);
+
+	/* De-assert active-low PLL reset. */
+	pll_mode |= BIT(2);
+	writel_relaxed(pll_mode, MM_PLL2_MODE_REG);
+
+	/* Enable PLL output. */
+	pll_mode |= BIT(0);
+	writel_relaxed(pll_mode, MM_PLL2_MODE_REG);
+}
+
+/*
+ * Clock Descriptions
+ */
+
+/* AXI Interfaces */
+static struct branch_clk gmem_axi_clk = {
+	.b = {
+		.ctl_reg = MAXI_EN_REG,
+		.en_mask = BIT(24),
+		.halt_reg = DBG_BUS_VEC_E_REG,
+		.halt_bit = 6,
+	},
+	.c = {
+		.dbg_name = "gmem_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gmem_axi_clk.c),
+	},
+};
+
+static struct branch_clk ijpeg_axi_clk = {
+	.b = {
+		.ctl_reg = MAXI_EN_REG,
+		.en_mask = BIT(21),
+		.reset_reg = SW_RESET_AXI_REG,
+		.reset_mask = BIT(14),
+		.halt_reg = DBG_BUS_VEC_E_REG,
+		.halt_bit = 4,
+	},
+	.c = {
+		.dbg_name = "ijpeg_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(ijpeg_axi_clk.c),
+	},
+};
+
+static struct branch_clk imem_axi_clk = {
+	.b = {
+		.ctl_reg = MAXI_EN_REG,
+		.en_mask = BIT(22),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(10),
+		.halt_reg = DBG_BUS_VEC_E_REG,
+		.halt_bit = 7,
+		.retain_reg = MAXI_EN2_REG,
+		.retain_mask = BIT(10),
+	},
+	.c = {
+		.dbg_name = "imem_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(imem_axi_clk.c),
+	},
+};
+
+static struct branch_clk jpegd_axi_clk = {
+	.b = {
+		.ctl_reg = MAXI_EN_REG,
+		.en_mask = BIT(25),
+		.halt_reg = DBG_BUS_VEC_E_REG,
+		.halt_bit = 5,
+	},
+	.c = {
+		.dbg_name = "jpegd_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(jpegd_axi_clk.c),
+	},
+};
+
+static struct branch_clk mdp_axi_clk = {
+	.b = {
+		.ctl_reg = MAXI_EN_REG,
+		.en_mask = BIT(23),
+		.reset_reg = SW_RESET_AXI_REG,
+		.reset_mask = BIT(13),
+		.halt_reg = DBG_BUS_VEC_E_REG,
+		.halt_bit = 8,
+		.retain_reg = MAXI_EN_REG,
+		.retain_mask = BIT(0),
+	},
+	.c = {
+		.dbg_name = "mdp_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdp_axi_clk.c),
+	},
+};
+
+static struct branch_clk vcodec_axi_clk = {
+	.b = {
+		.ctl_reg = MAXI_EN_REG,
+		.en_mask = BIT(19),
+		.reset_reg = SW_RESET_AXI_REG,
+		.reset_mask = BIT(4)|BIT(5),
+		.halt_reg = DBG_BUS_VEC_E_REG,
+		.halt_bit = 3,
+	},
+	.c = {
+		.dbg_name = "vcodec_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(vcodec_axi_clk.c),
+	},
+};
+
+static struct branch_clk vfe_axi_clk = {
+	.b = {
+		.ctl_reg = MAXI_EN_REG,
+		.en_mask = BIT(18),
+		.reset_reg = SW_RESET_AXI_REG,
+		.reset_mask = BIT(9),
+		.halt_reg = DBG_BUS_VEC_E_REG,
+		.halt_bit = 0,
+	},
+	.c = {
+		.dbg_name = "vfe_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(vfe_axi_clk.c),
+	},
+};
+
+static struct branch_clk rot_axi_clk = {
+	.b = {
+		.ctl_reg = MAXI_EN2_REG,
+		.en_mask = BIT(24),
+		.reset_reg = SW_RESET_AXI_REG,
+		.reset_mask = BIT(6),
+		.halt_reg = DBG_BUS_VEC_E_REG,
+		.halt_bit = 2,
+	},
+	.c = {
+		.dbg_name = "rot_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(rot_axi_clk.c),
+	},
+};
+
+static struct branch_clk vpe_axi_clk = {
+	.b = {
+		.ctl_reg = MAXI_EN2_REG,
+		.en_mask = BIT(26),
+		.reset_reg = SW_RESET_AXI_REG,
+		.reset_mask = BIT(15),
+		.halt_reg = DBG_BUS_VEC_E_REG,
+		.halt_bit = 1,
+	},
+	.c = {
+		.dbg_name = "vpe_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(vpe_axi_clk.c),
+	},
+};
+
+static struct branch_clk smi_2x_axi_clk = {
+	.b = {
+		.ctl_reg = MAXI_EN2_REG,
+		.en_mask = BIT(30),
+		.halt_reg = DBG_BUS_VEC_I_REG,
+		.halt_bit = 0,
+	},
+	.c = {
+		.dbg_name = "smi_2x_axi_clk",
+		.ops = &clk_ops_branch,
+		.flags = CLKFLAG_SKIP_AUTO_OFF,
+		CLK_INIT(smi_2x_axi_clk.c),
+	},
+};
+
+/* AHB Interfaces */
+static struct branch_clk amp_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(24),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(20),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 18,
+	},
+	.c = {
+		.dbg_name = "amp_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(amp_p_clk.c),
+	},
+};
+
+static struct branch_clk csi0_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(7),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(17),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 16,
+	},
+	.c = {
+		.dbg_name = "csi0_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi0_p_clk.c),
+	},
+};
+
+static struct branch_clk csi1_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(20),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(16),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 17,
+	},
+	.c = {
+		.dbg_name = "csi1_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi1_p_clk.c),
+	},
+};
+
+static struct branch_clk dsi_m_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(9),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(6),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 19,
+	},
+	.c = {
+		.dbg_name = "dsi_m_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(dsi_m_p_clk.c),
+	},
+};
+
+static struct branch_clk dsi_s_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(18),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(5),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 20,
+	},
+	.c = {
+		.dbg_name = "dsi_s_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(dsi_s_p_clk.c),
+	},
+};
+
+static struct branch_clk gfx2d0_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(19),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(12),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 2,
+	},
+	.c = {
+		.dbg_name = "gfx2d0_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gfx2d0_p_clk.c),
+	},
+};
+
+static struct branch_clk gfx2d1_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(2),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(11),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 3,
+	},
+	.c = {
+		.dbg_name = "gfx2d1_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gfx2d1_p_clk.c),
+	},
+};
+
+static struct branch_clk gfx3d_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(3),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(10),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 4,
+	},
+	.c = {
+		.dbg_name = "gfx3d_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gfx3d_p_clk.c),
+	},
+};
+
+static struct branch_clk hdmi_m_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(14),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(9),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 5,
+	},
+	.c = {
+		.dbg_name = "hdmi_m_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(hdmi_m_p_clk.c),
+	},
+};
+
+static struct branch_clk hdmi_s_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(4),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(9),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 6,
+	},
+	.c = {
+		.dbg_name = "hdmi_s_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(hdmi_s_p_clk.c),
+	},
+};
+
+static struct branch_clk ijpeg_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(5),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(7),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 9,
+	},
+	.c = {
+		.dbg_name = "ijpeg_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(ijpeg_p_clk.c),
+	},
+};
+
+static struct branch_clk imem_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(6),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(8),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 10,
+	},
+	.c = {
+		.dbg_name = "imem_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(imem_p_clk.c),
+	},
+};
+
+static struct branch_clk jpegd_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(21),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(4),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 7,
+	},
+	.c = {
+		.dbg_name = "jpegd_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(jpegd_p_clk.c),
+	},
+};
+
+static struct branch_clk mdp_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(10),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(3),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 11,
+	},
+	.c = {
+		.dbg_name = "mdp_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdp_p_clk.c),
+	},
+};
+
+static struct branch_clk rot_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(12),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(2),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 13,
+	},
+	.c = {
+		.dbg_name = "rot_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(rot_p_clk.c),
+	},
+};
+
+static struct branch_clk smmu_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(15),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 22,
+	},
+	.c = {
+		.dbg_name = "smmu_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(smmu_p_clk.c),
+	},
+};
+
+static struct branch_clk tv_enc_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(25),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(15),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 23,
+	},
+	.c = {
+		.dbg_name = "tv_enc_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(tv_enc_p_clk.c),
+	},
+};
+
+static struct branch_clk vcodec_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(11),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(1),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 12,
+	},
+	.c = {
+		.dbg_name = "vcodec_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(vcodec_p_clk.c),
+	},
+};
+
+static struct branch_clk vfe_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(13),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(0),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 14,
+		.retain_reg = AHB_EN2_REG,
+		.retain_mask = BIT(0),
+	},
+	.c = {
+		.dbg_name = "vfe_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(vfe_p_clk.c),
+	},
+};
+
+static struct branch_clk vpe_p_clk = {
+	.b = {
+		.ctl_reg = AHB_EN_REG,
+		.en_mask = BIT(16),
+		.reset_reg = SW_RESET_AHB_REG,
+		.reset_mask = BIT(14),
+		.halt_reg = DBG_BUS_VEC_F_REG,
+		.halt_bit = 15,
+	},
+	.c = {
+		.dbg_name = "vpe_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(vpe_p_clk.c),
+	},
+};
+
+/*
+ * Peripheral Clocks
+ */
+#define CLK_GP(i, n, h_r, h_b) \
+	struct rcg_clk i##_clk = { \
+		.b = { \
+			.ctl_reg = GPn_NS_REG(n), \
+			.en_mask = BIT(9), \
+			.halt_reg = h_r, \
+			.halt_bit = h_b, \
+		}, \
+		.ns_reg = GPn_NS_REG(n), \
+		.md_reg = GPn_MD_REG(n), \
+		.root_en_mask = BIT(11), \
+		.ns_mask = (BM(23, 16) | BM(6, 0)), \
+		.mnd_en_mask = BIT(8), \
+		.set_rate = set_rate_mnd, \
+		.freq_tbl = clk_tbl_gp, \
+		.current_freq = &rcg_dummy_freq, \
+		.c = { \
+			.dbg_name = #i "_clk", \
+			.ops = &clk_ops_rcg, \
+			VDD_DIG_FMAX_MAP1(LOW, 27000000), \
+			CLK_INIT(i##_clk.c), \
+		}, \
+	}
+#define F_GP(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD8(16, m, 0, n), \
+		.ns_val = NS(23, 16, n, m, 5, 4, 3, d, 2, 0, s##_to_bb_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_gp[] = {
+	F_GP(        0, gnd,  1, 0, 0),
+	F_GP(  9600000, cxo,  2, 0, 0),
+	F_GP( 13500000, pxo,  2, 0, 0),
+	F_GP( 19200000, cxo,  1, 0, 0),
+	F_GP( 27000000, pxo,  1, 0, 0),
+	F_END
+};
+
+static CLK_GP(gp0, 0, CLK_HALT_SFPB_MISC_STATE_REG, 7);
+static CLK_GP(gp1, 1, CLK_HALT_SFPB_MISC_STATE_REG, 6);
+static CLK_GP(gp2, 2, CLK_HALT_SFPB_MISC_STATE_REG, 5);
+
+#define CLK_GSBI_UART(i, n, h_r, h_b) \
+	struct rcg_clk i##_clk = { \
+		.b = { \
+			.ctl_reg = GSBIn_UART_APPS_NS_REG(n), \
+			.en_mask = BIT(9), \
+			.reset_reg = GSBIn_RESET_REG(n), \
+			.reset_mask = BIT(0), \
+			.halt_reg = h_r, \
+			.halt_bit = h_b, \
+		}, \
+		.ns_reg = GSBIn_UART_APPS_NS_REG(n), \
+		.md_reg = GSBIn_UART_APPS_MD_REG(n), \
+		.root_en_mask = BIT(11), \
+		.ns_mask = (BM(31, 16) | BM(6, 0)), \
+		.mnd_en_mask = BIT(8), \
+		.set_rate = set_rate_mnd, \
+		.freq_tbl = clk_tbl_gsbi_uart, \
+		.current_freq = &rcg_dummy_freq, \
+		.c = { \
+			.dbg_name = #i "_clk", \
+			.ops = &clk_ops_rcg, \
+			VDD_DIG_FMAX_MAP2(LOW, 32000000, NOMINAL, 64000000), \
+			CLK_INIT(i##_clk.c), \
+		}, \
+	}
+#define F_GSBI_UART(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD16(m, n), \
+		.ns_val = NS(31, 16, n, m, 5, 4, 3, d, 2, 0, s##_to_bb_mux), \
+	}
+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(16000000, pll8, 4,  1,   6),
+	F_GSBI_UART(24000000, pll8, 4,  1,   4),
+	F_GSBI_UART(32000000, pll8, 4,  1,   3),
+	F_GSBI_UART(40000000, pll8, 1,  5,  48),
+	F_GSBI_UART(46400000, pll8, 1, 29, 240),
+	F_GSBI_UART(48000000, pll8, 4,  1,   2),
+	F_GSBI_UART(51200000, pll8, 1,  2,  15),
+	F_GSBI_UART(56000000, pll8, 1,  7,  48),
+	F_GSBI_UART(58982400, pll8, 1, 96, 625),
+	F_GSBI_UART(64000000, pll8, 2,  1,   3),
+	F_END
+};
+
+static CLK_GSBI_UART(gsbi1_uart,   1, CLK_HALT_CFPB_STATEA_REG, 10);
+static CLK_GSBI_UART(gsbi2_uart,   2, CLK_HALT_CFPB_STATEA_REG,  6);
+static CLK_GSBI_UART(gsbi3_uart,   3, CLK_HALT_CFPB_STATEA_REG,  2);
+static CLK_GSBI_UART(gsbi4_uart,   4, CLK_HALT_CFPB_STATEB_REG, 26);
+static CLK_GSBI_UART(gsbi5_uart,   5, CLK_HALT_CFPB_STATEB_REG, 22);
+static CLK_GSBI_UART(gsbi6_uart,   6, CLK_HALT_CFPB_STATEB_REG, 18);
+static CLK_GSBI_UART(gsbi7_uart,   7, CLK_HALT_CFPB_STATEB_REG, 14);
+static CLK_GSBI_UART(gsbi8_uart,   8, CLK_HALT_CFPB_STATEB_REG, 10);
+static CLK_GSBI_UART(gsbi9_uart,   9, CLK_HALT_CFPB_STATEB_REG,  6);
+static CLK_GSBI_UART(gsbi10_uart, 10, CLK_HALT_CFPB_STATEB_REG,  2);
+static CLK_GSBI_UART(gsbi11_uart, 11, CLK_HALT_CFPB_STATEC_REG, 17);
+static CLK_GSBI_UART(gsbi12_uart, 12, CLK_HALT_CFPB_STATEC_REG, 13);
+
+#define CLK_GSBI_QUP(i, n, h_r, h_b) \
+	struct rcg_clk i##_clk = { \
+		.b = { \
+			.ctl_reg = GSBIn_QUP_APPS_NS_REG(n), \
+			.en_mask = BIT(9), \
+			.reset_reg = GSBIn_RESET_REG(n), \
+			.reset_mask = BIT(0), \
+			.halt_reg = h_r, \
+			.halt_bit = h_b, \
+		}, \
+		.ns_reg = GSBIn_QUP_APPS_NS_REG(n), \
+		.md_reg = GSBIn_QUP_APPS_MD_REG(n), \
+		.root_en_mask = BIT(11), \
+		.ns_mask = (BM(23, 16) | BM(6, 0)), \
+		.mnd_en_mask = BIT(8), \
+		.set_rate = set_rate_mnd, \
+		.freq_tbl = clk_tbl_gsbi_qup, \
+		.current_freq = &rcg_dummy_freq, \
+		.c = { \
+			.dbg_name = #i "_clk", \
+			.ops = &clk_ops_rcg, \
+			VDD_DIG_FMAX_MAP2(LOW, 24000000, NOMINAL, 52000000), \
+			CLK_INIT(i##_clk.c), \
+		}, \
+	}
+#define F_GSBI_QUP(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD8(16, m, 0, n), \
+		.ns_val = NS(23, 16, n, m, 5, 4, 3, d, 2, 0, s##_to_bb_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_gsbi_qup[] = {
+	F_GSBI_QUP(       0, gnd,  1, 0,  0),
+	F_GSBI_QUP( 1100000, pxo,  1, 2, 49),
+	F_GSBI_QUP( 5400000, pxo,  1, 1,  5),
+	F_GSBI_QUP(10800000, pxo,  1, 2,  5),
+	F_GSBI_QUP(15060000, pll8, 1, 2, 51),
+	F_GSBI_QUP(24000000, pll8, 4, 1,  4),
+	F_GSBI_QUP(25600000, pll8, 1, 1, 15),
+	F_GSBI_QUP(27000000, pxo,  1, 0,  0),
+	F_GSBI_QUP(48000000, pll8, 4, 1,  2),
+	F_GSBI_QUP(51200000, pll8, 1, 2, 15),
+	F_END
+};
+
+static CLK_GSBI_QUP(gsbi1_qup,   1, CLK_HALT_CFPB_STATEA_REG,  9);
+static CLK_GSBI_QUP(gsbi2_qup,   2, CLK_HALT_CFPB_STATEA_REG,  4);
+static CLK_GSBI_QUP(gsbi3_qup,   3, CLK_HALT_CFPB_STATEA_REG,  0);
+static CLK_GSBI_QUP(gsbi4_qup,   4, CLK_HALT_CFPB_STATEB_REG, 24);
+static CLK_GSBI_QUP(gsbi5_qup,   5, CLK_HALT_CFPB_STATEB_REG, 20);
+static CLK_GSBI_QUP(gsbi6_qup,   6, CLK_HALT_CFPB_STATEB_REG, 16);
+static CLK_GSBI_QUP(gsbi7_qup,   7, CLK_HALT_CFPB_STATEB_REG, 12);
+static CLK_GSBI_QUP(gsbi8_qup,   8, CLK_HALT_CFPB_STATEB_REG,  8);
+static CLK_GSBI_QUP(gsbi9_qup,   9, CLK_HALT_CFPB_STATEB_REG,  4);
+static CLK_GSBI_QUP(gsbi10_qup, 10, CLK_HALT_CFPB_STATEB_REG,  0);
+static CLK_GSBI_QUP(gsbi11_qup, 11, CLK_HALT_CFPB_STATEC_REG, 15);
+static CLK_GSBI_QUP(gsbi12_qup, 12, CLK_HALT_CFPB_STATEC_REG, 11);
+
+#define F_PDM(f, s, d) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.ns_val = NS_SRC_SEL(1, 0, s##_to_xo_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_pdm[] = {
+	F_PDM(       0, gnd, 1),
+	F_PDM(27000000, pxo, 1),
+	F_END
+};
+
+static struct rcg_clk pdm_clk = {
+	.b = {
+		.ctl_reg = PDM_CLK_NS_REG,
+		.en_mask = BIT(9),
+		.reset_reg = PDM_CLK_NS_REG,
+		.reset_mask = BIT(12),
+		.halt_reg = CLK_HALT_CFPB_STATEC_REG,
+		.halt_bit = 3,
+	},
+	.ns_reg = PDM_CLK_NS_REG,
+	.root_en_mask = BIT(11),
+	.ns_mask = BM(1, 0),
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_pdm,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "pdm_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 27000000),
+		CLK_INIT(pdm_clk.c),
+	},
+};
+
+static struct branch_clk pmem_clk = {
+	.b = {
+		.ctl_reg = PMEM_ACLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 20,
+	},
+	.c = {
+		.dbg_name = "pmem_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(pmem_clk.c),
+	},
+};
+
+#define F_PRNG(f, s) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+	}
+static struct clk_freq_tbl clk_tbl_prng_32[] = {
+	F_PRNG(32000000, pll8),
+	F_END
+};
+
+static struct clk_freq_tbl clk_tbl_prng_64[] = {
+	F_PRNG(64000000, pll8),
+	F_END
+};
+
+static struct rcg_clk prng_clk = {
+	.b = {
+		.ctl_reg = SC0_U_CLK_BRANCH_ENA_VOTE_REG,
+		.en_mask = BIT(10),
+		.halt_reg = CLK_HALT_SFPB_MISC_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 10,
+	},
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_prng_32,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "prng_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 32000000, NOMINAL, 64000000),
+		CLK_INIT(prng_clk.c),
+	},
+};
+
+#define CLK_SDC(i, n, h_r, h_b) \
+	struct rcg_clk i##_clk = { \
+		.b = { \
+			.ctl_reg = SDCn_APPS_CLK_NS_REG(n), \
+			.en_mask = BIT(9), \
+			.reset_reg = SDCn_RESET_REG(n), \
+			.reset_mask = BIT(0), \
+			.halt_reg = h_r, \
+			.halt_bit = h_b, \
+		}, \
+		.ns_reg = SDCn_APPS_CLK_NS_REG(n), \
+		.md_reg = SDCn_APPS_CLK_MD_REG(n), \
+		.root_en_mask = BIT(11), \
+		.ns_mask = (BM(23, 16) | BM(6, 0)), \
+		.mnd_en_mask = BIT(8), \
+		.set_rate = set_rate_mnd, \
+		.freq_tbl = clk_tbl_sdc, \
+		.current_freq = &rcg_dummy_freq, \
+		.c = { \
+			.dbg_name = #i "_clk", \
+			.ops = &clk_ops_rcg, \
+			VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000), \
+			CLK_INIT(i##_clk.c), \
+		}, \
+	}
+#define F_SDC(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD8(16, m, 0, n), \
+		.ns_val = NS(23, 16, n, m, 5, 4, 3, d, 2, 0, s##_to_bb_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_sdc[] = {
+	F_SDC(       0, gnd,   1, 0,   0),
+	F_SDC(  144000, pxo,   3, 2, 125),
+	F_SDC(  400000, pll8,  4, 1, 240),
+	F_SDC(16000000, pll8,  4, 1,   6),
+	F_SDC(17070000, pll8,  1, 2,  45),
+	F_SDC(20210000, pll8,  1, 1,  19),
+	F_SDC(24000000, pll8,  4, 1,   4),
+	F_SDC(48000000, pll8,  4, 1,   2),
+	F_END
+};
+
+static CLK_SDC(sdc1, 1, CLK_HALT_DFAB_STATE_REG, 6);
+static CLK_SDC(sdc2, 2, CLK_HALT_DFAB_STATE_REG, 5);
+static CLK_SDC(sdc3, 3, CLK_HALT_DFAB_STATE_REG, 4);
+static CLK_SDC(sdc4, 4, CLK_HALT_DFAB_STATE_REG, 3);
+static CLK_SDC(sdc5, 5, CLK_HALT_DFAB_STATE_REG, 2);
+
+#define F_TSIF_REF(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD16(m, n), \
+		.ns_val = NS(31, 16, n, m, 5, 4, 3, d, 2, 0, s##_to_bb_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_tsif_ref[] = {
+	F_TSIF_REF(     0, gnd,  1, 0,   0),
+	F_TSIF_REF(105000, pxo,  1, 1, 256),
+	F_END
+};
+
+static struct rcg_clk tsif_ref_clk = {
+	.b = {
+		.ctl_reg = TSIF_REF_CLK_NS_REG,
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_CFPB_STATEC_REG,
+		.halt_bit = 5,
+	},
+	.ns_reg = TSIF_REF_CLK_NS_REG,
+	.md_reg = TSIF_REF_CLK_MD_REG,
+	.root_en_mask = BIT(11),
+	.ns_mask = (BM(31, 16) | BM(6, 0)),
+	.mnd_en_mask = BIT(8),
+	.set_rate = set_rate_mnd,
+	.freq_tbl = clk_tbl_tsif_ref,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "tsif_ref_clk",
+		.ops = &clk_ops_rcg,
+		CLK_INIT(tsif_ref_clk.c),
+	},
+};
+
+#define F_TSSC(f, s) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.ns_val = NS_SRC_SEL(1, 0, s##_to_xo_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_tssc[] = {
+	F_TSSC(       0, gnd),
+	F_TSSC(27000000, pxo),
+	F_END
+};
+
+static struct rcg_clk tssc_clk = {
+	.b = {
+		.ctl_reg = TSSC_CLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEC_REG,
+		.halt_bit = 4,
+	},
+	.ns_reg = TSSC_CLK_CTL_REG,
+	.ns_mask = BM(1, 0),
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_tssc,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "tssc_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 27000000),
+		CLK_INIT(tssc_clk.c),
+	},
+};
+
+#define F_USB(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD8(16, m, 0, n), \
+		.ns_val = NS(23, 16, n, m, 5, 4, 3, d, 2, 0, s##_to_bb_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_usb[] = {
+	F_USB(       0, gnd,  1, 0,  0),
+	F_USB(60000000, pll8, 1, 5, 32),
+	F_END
+};
+
+static struct rcg_clk usb_hs1_xcvr_clk = {
+	.b = {
+		.ctl_reg = USB_HS1_XCVR_FS_CLK_NS_REG,
+		.en_mask = BIT(9),
+		.reset_reg = USB_HS1_RESET_REG,
+		.reset_mask = BIT(0),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 0,
+	},
+	.ns_reg = USB_HS1_XCVR_FS_CLK_NS_REG,
+	.md_reg = USB_HS1_XCVR_FS_CLK_MD_REG,
+	.root_en_mask = BIT(11),
+	.ns_mask = (BM(23, 16) | BM(6, 0)),
+	.mnd_en_mask = BIT(8),
+	.set_rate = set_rate_mnd,
+	.freq_tbl = clk_tbl_usb,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "usb_hs1_xcvr_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 60000000),
+		CLK_INIT(usb_hs1_xcvr_clk.c),
+	},
+};
+
+static struct branch_clk usb_phy0_clk = {
+	.b = {
+		.reset_reg = USB_PHY0_RESET_REG,
+		.reset_mask = BIT(0),
+	},
+	.c = {
+		.dbg_name = "usb_phy0_clk",
+		.ops = &clk_ops_reset,
+		CLK_INIT(usb_phy0_clk.c),
+	},
+};
+
+#define CLK_USB_FS(i, n) \
+	struct rcg_clk i##_clk = { \
+		.ns_reg = USB_FSn_XCVR_FS_CLK_NS_REG(n), \
+		.b = { \
+			.ctl_reg = USB_FSn_XCVR_FS_CLK_NS_REG(n), \
+			.halt_check = NOCHECK, \
+		}, \
+		.md_reg = USB_FSn_XCVR_FS_CLK_MD_REG(n), \
+		.root_en_mask = BIT(11), \
+		.ns_mask = (BM(23, 16) | BM(6, 0)), \
+		.mnd_en_mask = BIT(8), \
+		.set_rate = set_rate_mnd, \
+		.freq_tbl = clk_tbl_usb, \
+		.current_freq = &rcg_dummy_freq, \
+		.c = { \
+			.dbg_name = #i "_clk", \
+			.ops = &clk_ops_rcg, \
+			VDD_DIG_FMAX_MAP1(NOMINAL, 60000000), \
+			CLK_INIT(i##_clk.c), \
+		}, \
+	}
+
+static CLK_USB_FS(usb_fs1_src, 1);
+static struct branch_clk usb_fs1_xcvr_clk = {
+	.b = {
+		.ctl_reg = USB_FSn_XCVR_FS_CLK_NS_REG(1),
+		.en_mask = BIT(9),
+		.reset_reg = USB_FSn_RESET_REG(1),
+		.reset_mask = BIT(1),
+		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
+		.halt_bit = 15,
+	},
+	.parent = &usb_fs1_src_clk.c,
+	.c = {
+		.dbg_name = "usb_fs1_xcvr_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_fs1_xcvr_clk.c),
+	},
+};
+
+static struct branch_clk usb_fs1_sys_clk = {
+	.b = {
+		.ctl_reg = USB_FSn_SYSTEM_CLK_CTL_REG(1),
+		.en_mask = BIT(4),
+		.reset_reg = USB_FSn_RESET_REG(1),
+		.reset_mask = BIT(0),
+		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
+		.halt_bit = 16,
+	},
+	.parent = &usb_fs1_src_clk.c,
+	.c = {
+		.dbg_name = "usb_fs1_sys_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_fs1_sys_clk.c),
+	},
+};
+
+static CLK_USB_FS(usb_fs2_src, 2);
+static struct branch_clk usb_fs2_xcvr_clk = {
+	.b = {
+		.ctl_reg = USB_FSn_XCVR_FS_CLK_NS_REG(2),
+		.en_mask = BIT(9),
+		.reset_reg = USB_FSn_RESET_REG(2),
+		.reset_mask = BIT(1),
+		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
+		.halt_bit = 12,
+	},
+	.parent = &usb_fs2_src_clk.c,
+	.c = {
+		.dbg_name = "usb_fs2_xcvr_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_fs2_xcvr_clk.c),
+	},
+};
+
+static struct branch_clk usb_fs2_sys_clk = {
+	.b = {
+		.ctl_reg = USB_FSn_SYSTEM_CLK_CTL_REG(2),
+		.en_mask = BIT(4),
+		.reset_reg = USB_FSn_RESET_REG(2),
+		.reset_mask = BIT(0),
+		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
+		.halt_bit = 13,
+	},
+	.parent = &usb_fs2_src_clk.c,
+	.c = {
+		.dbg_name = "usb_fs2_sys_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_fs2_sys_clk.c),
+	},
+};
+
+/* Fast Peripheral Bus Clocks */
+static struct branch_clk ce2_p_clk = {
+	.b = {
+		.ctl_reg = CE2_HCLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEC_REG,
+		.halt_bit = 0,
+	},
+	.parent = &pxo_clk.c,
+	.c = {
+		.dbg_name = "ce2_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(ce2_p_clk.c),
+	},
+};
+
+static struct branch_clk gsbi1_p_clk = {
+	.b = {
+		.ctl_reg = GSBIn_HCLK_CTL_REG(1),
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
+		.halt_bit = 11,
+	},
+	.c = {
+		.dbg_name = "gsbi1_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gsbi1_p_clk.c),
+	},
+};
+
+static struct branch_clk gsbi2_p_clk = {
+	.b = {
+		.ctl_reg = GSBIn_HCLK_CTL_REG(2),
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
+		.halt_bit = 7,
+	},
+	.c = {
+		.dbg_name = "gsbi2_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gsbi2_p_clk.c),
+	},
+};
+
+static struct branch_clk gsbi3_p_clk = {
+	.b = {
+		.ctl_reg = GSBIn_HCLK_CTL_REG(3),
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
+		.halt_bit = 3,
+	},
+	.c = {
+		.dbg_name = "gsbi3_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gsbi3_p_clk.c),
+	},
+};
+
+static struct branch_clk gsbi4_p_clk = {
+	.b = {
+		.ctl_reg = GSBIn_HCLK_CTL_REG(4),
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEB_REG,
+		.halt_bit = 27,
+	},
+	.c = {
+		.dbg_name = "gsbi4_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gsbi4_p_clk.c),
+	},
+};
+
+static struct branch_clk gsbi5_p_clk = {
+	.b = {
+		.ctl_reg = GSBIn_HCLK_CTL_REG(5),
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEB_REG,
+		.halt_bit = 23,
+	},
+	.c = {
+		.dbg_name = "gsbi5_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gsbi5_p_clk.c),
+	},
+};
+
+static struct branch_clk gsbi6_p_clk = {
+	.b = {
+		.ctl_reg = GSBIn_HCLK_CTL_REG(6),
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEB_REG,
+		.halt_bit = 19,
+	},
+	.c = {
+		.dbg_name = "gsbi6_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gsbi6_p_clk.c),
+	},
+};
+
+static struct branch_clk gsbi7_p_clk = {
+	.b = {
+		.ctl_reg = GSBIn_HCLK_CTL_REG(7),
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEB_REG,
+		.halt_bit = 15,
+	},
+	.c = {
+		.dbg_name = "gsbi7_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gsbi7_p_clk.c),
+	},
+};
+
+static struct branch_clk gsbi8_p_clk = {
+	.b = {
+		.ctl_reg = GSBIn_HCLK_CTL_REG(8),
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEB_REG,
+		.halt_bit = 11,
+	},
+	.c = {
+		.dbg_name = "gsbi8_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gsbi8_p_clk.c),
+	},
+};
+
+static struct branch_clk gsbi9_p_clk = {
+	.b = {
+		.ctl_reg = GSBIn_HCLK_CTL_REG(9),
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEB_REG,
+		.halt_bit = 7,
+	},
+	.c = {
+		.dbg_name = "gsbi9_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gsbi9_p_clk.c),
+	},
+};
+
+static struct branch_clk gsbi10_p_clk = {
+	.b = {
+		.ctl_reg = GSBIn_HCLK_CTL_REG(10),
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEB_REG,
+		.halt_bit = 3,
+	},
+	.c = {
+		.dbg_name = "gsbi10_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gsbi10_p_clk.c),
+	},
+};
+
+static struct branch_clk gsbi11_p_clk = {
+	.b = {
+		.ctl_reg = GSBIn_HCLK_CTL_REG(11),
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEC_REG,
+		.halt_bit = 18,
+	},
+	.c = {
+		.dbg_name = "gsbi11_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gsbi11_p_clk.c),
+	},
+};
+
+static struct branch_clk gsbi12_p_clk = {
+	.b = {
+		.ctl_reg = GSBIn_HCLK_CTL_REG(12),
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEC_REG,
+		.halt_bit = 14,
+	},
+	.c = {
+		.dbg_name = "gsbi12_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gsbi12_p_clk.c),
+	},
+};
+
+static struct branch_clk ppss_p_clk = {
+	.b = {
+		.ctl_reg = PPSS_HCLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 19,
+	},
+	.c = {
+		.dbg_name = "ppss_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(ppss_p_clk.c),
+	},
+};
+
+static struct branch_clk tsif_p_clk = {
+	.b = {
+		.ctl_reg = TSIF_HCLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEC_REG,
+		.halt_bit = 7,
+	},
+	.c = {
+		.dbg_name = "tsif_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(tsif_p_clk.c),
+	},
+};
+
+static struct branch_clk usb_fs1_p_clk = {
+	.b = {
+		.ctl_reg = USB_FSn_HCLK_CTL_REG(1),
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
+		.halt_bit = 17,
+	},
+	.c = {
+		.dbg_name = "usb_fs1_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_fs1_p_clk.c),
+	},
+};
+
+static struct branch_clk usb_fs2_p_clk = {
+	.b = {
+		.ctl_reg = USB_FSn_HCLK_CTL_REG(2),
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
+		.halt_bit = 14,
+	},
+	.c = {
+		.dbg_name = "usb_fs2_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_fs2_p_clk.c),
+	},
+};
+
+static struct branch_clk usb_hs1_p_clk = {
+	.b = {
+		.ctl_reg = USB_HS1_HCLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 1,
+	},
+	.c = {
+		.dbg_name = "usb_hs1_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_hs1_p_clk.c),
+	},
+};
+
+static struct branch_clk sdc1_p_clk = {
+	.b = {
+		.ctl_reg = SDCn_HCLK_CTL_REG(1),
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 11,
+	},
+	.c = {
+		.dbg_name = "sdc1_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sdc1_p_clk.c),
+	},
+};
+
+static struct branch_clk sdc2_p_clk = {
+	.b = {
+		.ctl_reg = SDCn_HCLK_CTL_REG(2),
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 10,
+	},
+	.c = {
+		.dbg_name = "sdc2_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sdc2_p_clk.c),
+	},
+};
+
+static struct branch_clk sdc3_p_clk = {
+	.b = {
+		.ctl_reg = SDCn_HCLK_CTL_REG(3),
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 9,
+	},
+	.c = {
+		.dbg_name = "sdc3_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sdc3_p_clk.c),
+	},
+};
+
+static struct branch_clk sdc4_p_clk = {
+	.b = {
+		.ctl_reg = SDCn_HCLK_CTL_REG(4),
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 8,
+	},
+	.c = {
+		.dbg_name = "sdc4_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sdc4_p_clk.c),
+	},
+};
+
+static struct branch_clk sdc5_p_clk = {
+	.b = {
+		.ctl_reg = SDCn_HCLK_CTL_REG(5),
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 7,
+	},
+	.c = {
+		.dbg_name = "sdc5_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sdc5_p_clk.c),
+	},
+};
+
+static struct branch_clk ebi2_2x_clk = {
+	.b = {
+		.ctl_reg = EBI2_2X_CLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
+		.halt_bit = 18,
+	},
+	.c = {
+		.dbg_name = "ebi2_2x_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(ebi2_2x_clk.c),
+	},
+};
+
+static struct branch_clk ebi2_clk = {
+	.b = {
+		.ctl_reg = EBI2_CLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
+		.halt_bit = 19,
+	},
+	.c = {
+		.dbg_name = "ebi2_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(ebi2_clk.c),
+		.depends = &ebi2_2x_clk.c,
+	},
+};
+
+/* HW-Voteable Clocks */
+static struct branch_clk adm0_clk = {
+	.b = {
+		.ctl_reg = SC0_U_CLK_BRANCH_ENA_VOTE_REG,
+		.en_mask = BIT(2),
+		.halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 14,
+	},
+	.parent = &pxo_clk.c,
+	.c = {
+		.dbg_name = "adm0_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(adm0_clk.c),
+	},
+};
+
+static struct branch_clk adm0_p_clk = {
+	.b = {
+		.ctl_reg = SC0_U_CLK_BRANCH_ENA_VOTE_REG,
+		.en_mask = BIT(3),
+		.halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 13,
+	},
+	.c = {
+		.dbg_name = "adm0_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(adm0_p_clk.c),
+	},
+};
+
+static struct branch_clk adm1_clk = {
+	.b = {
+		.ctl_reg = SC0_U_CLK_BRANCH_ENA_VOTE_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 12,
+	},
+	.parent = &pxo_clk.c,
+	.c = {
+		.dbg_name = "adm1_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(adm1_clk.c),
+	},
+};
+
+static struct branch_clk adm1_p_clk = {
+	.b = {
+		.ctl_reg = SC0_U_CLK_BRANCH_ENA_VOTE_REG,
+		.en_mask = BIT(5),
+		.halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 11,
+	},
+	.c = {
+		.dbg_name = "adm1_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(adm1_p_clk.c),
+	},
+};
+
+static struct branch_clk modem_ahb1_p_clk = {
+	.b = {
+		.ctl_reg = SC0_U_CLK_BRANCH_ENA_VOTE_REG,
+		.en_mask = BIT(0),
+		.halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 8,
+	},
+	.c = {
+		.dbg_name = "modem_ahb1_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(modem_ahb1_p_clk.c),
+	},
+};
+
+static struct branch_clk modem_ahb2_p_clk = {
+	.b = {
+		.ctl_reg = SC0_U_CLK_BRANCH_ENA_VOTE_REG,
+		.en_mask = BIT(1),
+		.halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 7,
+	},
+	.c = {
+		.dbg_name = "modem_ahb2_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(modem_ahb2_p_clk.c),
+	},
+};
+
+static struct branch_clk pmic_arb0_p_clk = {
+	.b = {
+		.ctl_reg = SC0_U_CLK_BRANCH_ENA_VOTE_REG,
+		.en_mask = BIT(8),
+		.halt_reg = CLK_HALT_SFPB_MISC_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 22,
+	},
+	.c = {
+		.dbg_name = "pmic_arb0_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(pmic_arb0_p_clk.c),
+	},
+};
+
+static struct branch_clk pmic_arb1_p_clk = {
+	.b = {
+		.ctl_reg = SC0_U_CLK_BRANCH_ENA_VOTE_REG,
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_SFPB_MISC_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 21,
+	},
+	.c = {
+		.dbg_name = "pmic_arb1_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(pmic_arb1_p_clk.c),
+	},
+};
+
+static struct branch_clk pmic_ssbi2_clk = {
+	.b = {
+		.ctl_reg = SC0_U_CLK_BRANCH_ENA_VOTE_REG,
+		.en_mask = BIT(7),
+		.halt_reg = CLK_HALT_SFPB_MISC_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 23,
+	},
+	.c = {
+		.dbg_name = "pmic_ssbi2_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(pmic_ssbi2_clk.c),
+	},
+};
+
+static struct branch_clk rpm_msg_ram_p_clk = {
+	.b = {
+		.ctl_reg = SC0_U_CLK_BRANCH_ENA_VOTE_REG,
+		.en_mask = BIT(6),
+		.halt_reg = CLK_HALT_SFPB_MISC_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 12,
+	},
+	.c = {
+		.dbg_name = "rpm_msg_ram_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(rpm_msg_ram_p_clk.c),
+	},
+};
+
+/*
+ * Multimedia Clocks
+ */
+
+#define F_CAM(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD8(8, m, 0, n), \
+		.ns_val = NS_MM(31, 24, n, m, 15, 14, d, 2, 0, s##_to_mm_mux), \
+		.ctl_val = CC(6, n), \
+	}
+static struct clk_freq_tbl clk_tbl_cam[] = {
+	F_CAM(        0, gnd,  1, 0,  0),
+	F_CAM(  6000000, pll8, 4, 1, 16),
+	F_CAM(  8000000, pll8, 4, 1, 12),
+	F_CAM( 12000000, pll8, 4, 1,  8),
+	F_CAM( 16000000, pll8, 4, 1,  6),
+	F_CAM( 19200000, pll8, 4, 1,  5),
+	F_CAM( 24000000, pll8, 4, 1,  4),
+	F_CAM( 32000000, pll8, 4, 1,  3),
+	F_CAM( 48000000, pll8, 4, 1,  2),
+	F_CAM( 64000000, pll8, 3, 1,  2),
+	F_CAM( 96000000, pll8, 4, 0,  0),
+	F_CAM(128000000, pll8, 3, 0,  0),
+	F_END
+};
+
+static struct rcg_clk cam_clk = {
+	.b = {
+		.ctl_reg = CAMCLK_CC_REG,
+		.en_mask = BIT(0),
+		.halt_check = DELAY,
+	},
+	.ns_reg = CAMCLK_NS_REG,
+	.md_reg = CAMCLK_MD_REG,
+	.root_en_mask = BIT(2),
+	.ns_mask = (BM(31, 24) | BM(15, 14) | BM(2, 0)),
+	.mnd_en_mask = BIT(5),
+	.ctl_mask = BM(7, 6),
+	.set_rate = set_rate_mnd_8,
+	.freq_tbl = clk_tbl_cam,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "cam_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 64000000, NOMINAL, 128000000),
+		CLK_INIT(cam_clk.c),
+	},
+};
+
+#define F_CSI(f, s, d) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.ns_val = NS_DIVSRC(15, 12, d, 2, 0, s##_to_mm_mux),  \
+	}
+static struct clk_freq_tbl clk_tbl_csi[] = {
+	F_CSI(        0,  gnd, 1),
+	F_CSI(192000000, pll8, 2),
+	F_CSI(384000000, pll8, 1),
+	F_END
+};
+
+static struct rcg_clk csi_src_clk = {
+	.ns_reg = CSI_NS_REG,
+	.b = {
+		.ctl_reg = CSI_CC_REG,
+		.halt_check = NOCHECK,
+	},
+	.root_en_mask = BIT(2),
+	.ns_mask = (BM(15, 12) | BM(2, 0)),
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_csi,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "csi_src_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 192000000, NOMINAL, 384000000),
+		CLK_INIT(csi_src_clk.c),
+	},
+};
+
+static struct branch_clk csi0_clk = {
+	.b = {
+		.ctl_reg = CSI_CC_REG,
+		.en_mask = BIT(0),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(8),
+		.halt_reg = DBG_BUS_VEC_B_REG,
+		.halt_bit = 13,
+	},
+	.parent = &csi_src_clk.c,
+	.c = {
+		.dbg_name = "csi0_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi0_clk.c),
+	},
+};
+
+static struct branch_clk csi1_clk = {
+	.b = {
+		.ctl_reg = CSI_CC_REG,
+		.en_mask = BIT(7),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(18),
+		.halt_reg = DBG_BUS_VEC_B_REG,
+		.halt_bit = 14,
+	},
+	.parent = &csi_src_clk.c,
+	.c = {
+		.dbg_name = "csi1_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi1_clk.c),
+	},
+};
+
+#define F_DSI(d) \
+	{ \
+		.freq_hz = d, \
+		.ns_val = BVAL(27, 24, (d-1)), \
+	}
+/* The DSI_BYTE clock is sourced from the DSI PHY PLL, which may change rate
+ * without this clock driver knowing.  So, overload the clk_set_rate() to set
+ * the divider (1 to 16) of the clock with respect to the PLL rate. */
+static struct clk_freq_tbl clk_tbl_dsi_byte[] = {
+	F_DSI(1),  F_DSI(2),  F_DSI(3),  F_DSI(4),
+	F_DSI(5),  F_DSI(6),  F_DSI(7),  F_DSI(8),
+	F_DSI(9),  F_DSI(10), F_DSI(11), F_DSI(12),
+	F_DSI(13), F_DSI(14), F_DSI(15), F_DSI(16),
+	F_END
+};
+
+
+static struct rcg_clk dsi_byte_clk = {
+	.b = {
+		.ctl_reg = MISC_CC_REG,
+		.halt_check = DELAY,
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(7),
+		.retain_reg = MISC_CC2_REG,
+		.retain_mask = BIT(10),
+	},
+	.ns_reg = MISC_CC2_REG,
+	.root_en_mask = BIT(2),
+	.ns_mask = BM(27, 24),
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_dsi_byte,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "dsi_byte_clk",
+		.ops = &clk_ops_rcg,
+		CLK_INIT(dsi_byte_clk.c),
+	},
+};
+
+static struct branch_clk dsi_esc_clk = {
+	.b = {
+		.ctl_reg = MISC_CC_REG,
+		.en_mask = BIT(0),
+		.halt_reg = DBG_BUS_VEC_B_REG,
+		.halt_bit = 24,
+	},
+	.c = {
+		.dbg_name = "dsi_esc_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(dsi_esc_clk.c),
+	},
+};
+
+#define F_GFX2D(f, s, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD4(4, m, 0, n), \
+		.ns_val = NS_MND_BANKED4(20, 16, n, m, 3, 0, s##_to_mm_mux), \
+		.ctl_val = CC_BANKED(9, 6, n), \
+	}
+static struct clk_freq_tbl clk_tbl_gfx2d[] = {
+	F_GFX2D(        0, gnd,  0,  0),
+	F_GFX2D( 27000000, pxo,  0,  0),
+	F_GFX2D( 48000000, pll8, 1,  8),
+	F_GFX2D( 54857000, pll8, 1,  7),
+	F_GFX2D( 64000000, pll8, 1,  6),
+	F_GFX2D( 76800000, pll8, 1,  5),
+	F_GFX2D( 96000000, pll8, 1,  4),
+	F_GFX2D(128000000, pll8, 1,  3),
+	F_GFX2D(145455000, pll2, 2, 11),
+	F_GFX2D(160000000, pll2, 1,  5),
+	F_GFX2D(177778000, pll2, 2,  9),
+	F_GFX2D(200000000, pll2, 1,  4),
+	F_GFX2D(228571000, pll2, 2,  7),
+	F_END
+};
+
+static struct bank_masks bmnd_info_gfx2d0 = {
+	.bank_sel_mask =			BIT(11),
+	.bank0_mask = {
+			.md_reg =		GFX2D0_MD0_REG,
+			.ns_mask =		BM(23, 20) | BM(5, 3),
+			.rst_mask =		BIT(25),
+			.mnd_en_mask =		BIT(8),
+			.mode_mask =		BM(10, 9),
+	},
+	.bank1_mask = {
+			.md_reg =		GFX2D0_MD1_REG,
+			.ns_mask =		BM(19, 16) | BM(2, 0),
+			.rst_mask =		BIT(24),
+			.mnd_en_mask =		BIT(5),
+			.mode_mask =		BM(7, 6),
+	},
+};
+
+static struct rcg_clk gfx2d0_clk = {
+	.b = {
+		.ctl_reg = GFX2D0_CC_REG,
+		.en_mask = BIT(0),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(14),
+		.halt_reg = DBG_BUS_VEC_A_REG,
+		.halt_bit = 9,
+		.retain_reg = GFX2D0_CC_REG,
+		.retain_mask = BIT(31),
+	},
+	.ns_reg = GFX2D0_NS_REG,
+	.root_en_mask = BIT(2),
+	.set_rate = set_rate_mnd_banked,
+	.freq_tbl = clk_tbl_gfx2d,
+	.bank_info = &bmnd_info_gfx2d0,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "gfx2d0_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW,  100000000, NOMINAL, 200000000,
+				  HIGH, 228571000),
+		CLK_INIT(gfx2d0_clk.c),
+	},
+};
+
+static struct bank_masks bmnd_info_gfx2d1 = {
+	.bank_sel_mask =		BIT(11),
+	.bank0_mask = {
+			.md_reg =		GFX2D1_MD0_REG,
+			.ns_mask =		BM(23, 20) | BM(5, 3),
+			.rst_mask =		BIT(25),
+			.mnd_en_mask =		BIT(8),
+			.mode_mask =		BM(10, 9),
+	},
+	.bank1_mask = {
+			.md_reg =		GFX2D1_MD1_REG,
+			.ns_mask =		BM(19, 16) | BM(2, 0),
+			.rst_mask =		BIT(24),
+			.mnd_en_mask =		BIT(5),
+			.mode_mask =		BM(7, 6),
+	},
+};
+
+static struct rcg_clk gfx2d1_clk = {
+	.b = {
+		.ctl_reg = GFX2D1_CC_REG,
+		.en_mask = BIT(0),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(13),
+		.halt_reg = DBG_BUS_VEC_A_REG,
+		.halt_bit = 14,
+		.retain_reg = GFX2D1_CC_REG,
+		.retain_mask = BIT(31),
+	},
+	.ns_reg = GFX2D1_NS_REG,
+	.root_en_mask = BIT(2),
+	.set_rate = set_rate_mnd_banked,
+	.freq_tbl = clk_tbl_gfx2d,
+	.bank_info = &bmnd_info_gfx2d1,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "gfx2d1_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW,  100000000, NOMINAL, 200000000,
+				  HIGH, 228571000),
+		CLK_INIT(gfx2d1_clk.c),
+	},
+};
+
+#define F_GFX3D(f, s, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD4(4, m, 0, n), \
+		.ns_val = NS_MND_BANKED4(18, 14, n, m, 3, 0, s##_to_mm_mux), \
+		.ctl_val = CC_BANKED(9, 6, n), \
+	}
+static struct clk_freq_tbl clk_tbl_gfx3d[] = {
+	F_GFX3D(        0, gnd,  0,  0),
+	F_GFX3D( 27000000, pxo,  0,  0),
+	F_GFX3D( 48000000, pll8, 1,  8),
+	F_GFX3D( 54857000, pll8, 1,  7),
+	F_GFX3D( 64000000, pll8, 1,  6),
+	F_GFX3D( 76800000, pll8, 1,  5),
+	F_GFX3D( 96000000, pll8, 1,  4),
+	F_GFX3D(128000000, pll8, 1,  3),
+	F_GFX3D(145455000, pll2, 2, 11),
+	F_GFX3D(160000000, pll2, 1,  5),
+	F_GFX3D(177778000, pll2, 2,  9),
+	F_GFX3D(200000000, pll2, 1,  4),
+	F_GFX3D(228571000, pll2, 2,  7),
+	F_GFX3D(266667000, pll2, 1,  3),
+	F_GFX3D(320000000, pll2, 2,  5),
+	F_END
+};
+
+static struct bank_masks bmnd_info_gfx3d = {
+	.bank_sel_mask =		BIT(11),
+	.bank0_mask = {
+			.md_reg =		GFX3D_MD0_REG,
+			.ns_mask =		BM(21, 18) | BM(5, 3),
+			.rst_mask =		BIT(23),
+			.mnd_en_mask =		BIT(8),
+			.mode_mask =		BM(10, 9),
+	},
+	.bank1_mask = {
+			.md_reg =		GFX3D_MD1_REG,
+			.ns_mask =		BM(17, 14) | BM(2, 0),
+			.rst_mask =		BIT(22),
+			.mnd_en_mask =		BIT(5),
+			.mode_mask =		BM(7, 6),
+	},
+};
+
+static struct rcg_clk gfx3d_clk = {
+	.b = {
+		.ctl_reg = GFX3D_CC_REG,
+		.en_mask = BIT(0),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(12),
+		.halt_reg = DBG_BUS_VEC_A_REG,
+		.halt_bit = 4,
+		.retain_reg = GFX3D_CC_REG,
+		.retain_mask = BIT(31),
+	},
+	.ns_reg = GFX3D_NS_REG,
+	.root_en_mask = BIT(2),
+	.set_rate = set_rate_mnd_banked,
+	.freq_tbl = clk_tbl_gfx3d,
+	.bank_info = &bmnd_info_gfx3d,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "gfx3d_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW,   96000000, NOMINAL, 200000000,
+				  HIGH, 320000000),
+		CLK_INIT(gfx3d_clk.c),
+		.depends = &gmem_axi_clk.c,
+	},
+};
+
+#define F_IJPEG(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD8(8, m, 0, n), \
+		.ns_val = NS_MM(23, 16, n, m, 15, 12, d, 2, 0, s##_to_mm_mux), \
+		.ctl_val = CC(6, n), \
+	}
+static struct clk_freq_tbl clk_tbl_ijpeg[] = {
+	F_IJPEG(        0, gnd,  1, 0,  0),
+	F_IJPEG( 27000000, pxo,  1, 0,  0),
+	F_IJPEG( 36570000, pll8, 1, 2, 21),
+	F_IJPEG( 54860000, pll8, 7, 0,  0),
+	F_IJPEG( 96000000, pll8, 4, 0,  0),
+	F_IJPEG(109710000, pll8, 1, 2,  7),
+	F_IJPEG(128000000, pll8, 3, 0,  0),
+	F_IJPEG(153600000, pll8, 1, 2,  5),
+	F_IJPEG(200000000, pll2, 4, 0,  0),
+	F_IJPEG(228571000, pll2, 1, 2,  7),
+	F_END
+};
+
+static struct rcg_clk ijpeg_clk = {
+	.b = {
+		.ctl_reg = IJPEG_CC_REG,
+		.en_mask = BIT(0),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(9),
+		.halt_reg = DBG_BUS_VEC_A_REG,
+		.halt_bit = 24,
+		.retain_reg = IJPEG_CC_REG,
+		.retain_mask = BIT(31),
+	},
+	.ns_reg = IJPEG_NS_REG,
+	.md_reg = IJPEG_MD_REG,
+	.root_en_mask = BIT(2),
+	.ns_mask = (BM(23, 16) | BM(15, 12) | BM(2, 0)),
+	.mnd_en_mask = BIT(5),
+	.ctl_mask = BM(7, 6),
+	.set_rate = set_rate_mnd,
+	.freq_tbl = clk_tbl_ijpeg,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "ijpeg_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 110000000, NOMINAL, 228571000),
+		CLK_INIT(ijpeg_clk.c),
+		.depends = &ijpeg_axi_clk.c,
+	},
+};
+
+#define F_JPEGD(f, s, d) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.ns_val = NS_DIVSRC(15, 12, d, 2, 0, s##_to_mm_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_jpegd[] = {
+	F_JPEGD(        0, gnd,  1),
+	F_JPEGD( 64000000, pll8, 6),
+	F_JPEGD( 76800000, pll8, 5),
+	F_JPEGD( 96000000, pll8, 4),
+	F_JPEGD(160000000, pll2, 5),
+	F_JPEGD(200000000, pll2, 4),
+	F_END
+};
+
+static struct rcg_clk jpegd_clk = {
+	.b = {
+		.ctl_reg = JPEGD_CC_REG,
+		.en_mask = BIT(0),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(19),
+		.halt_reg = DBG_BUS_VEC_A_REG,
+		.halt_bit = 19,
+		.retain_reg = JPEGD_CC_REG,
+		.retain_mask = BIT(31),
+	},
+	.ns_reg = JPEGD_NS_REG,
+	.root_en_mask = BIT(2),
+	.ns_mask =  (BM(15, 12) | BM(2, 0)),
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_jpegd,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "jpegd_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 96000000, NOMINAL, 200000000),
+		CLK_INIT(jpegd_clk.c),
+		.depends = &jpegd_axi_clk.c,
+	},
+};
+
+#define F_MDP(f, s, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD8(8, m, 0, n), \
+		.ns_val = NS_MND_BANKED8(22, 14, n, m, 3, 0, s##_to_mm_mux), \
+		.ctl_val = CC_BANKED(9, 6, n), \
+	}
+static struct clk_freq_tbl clk_tbl_mdp[] = {
+	F_MDP(        0, gnd,  0,  0),
+	F_MDP(  9600000, pll8, 1, 40),
+	F_MDP( 13710000, pll8, 1, 28),
+	F_MDP( 27000000, pxo,  0,  0),
+	F_MDP( 29540000, pll8, 1, 13),
+	F_MDP( 34910000, pll8, 1, 11),
+	F_MDP( 38400000, pll8, 1, 10),
+	F_MDP( 59080000, pll8, 2, 13),
+	F_MDP( 76800000, pll8, 1,  5),
+	F_MDP( 85330000, pll8, 2,  9),
+	F_MDP( 96000000, pll8, 1,  4),
+	F_MDP(128000000, pll8, 1,  3),
+	F_MDP(160000000, pll2, 1,  5),
+	F_MDP(177780000, pll2, 2,  9),
+	F_MDP(200000000, pll2, 1,  4),
+	F_END
+};
+
+static struct bank_masks bmnd_info_mdp = {
+	.bank_sel_mask =		BIT(11),
+	.bank0_mask = {
+			.md_reg =		MDP_MD0_REG,
+			.ns_mask =		BM(29, 22) | BM(5, 3),
+			.rst_mask =		BIT(31),
+			.mnd_en_mask =		BIT(8),
+			.mode_mask =		BM(10, 9),
+	},
+	.bank1_mask = {
+			.md_reg =		MDP_MD1_REG,
+			.ns_mask =		BM(21, 14) | BM(2, 0),
+			.rst_mask =		BIT(30),
+			.mnd_en_mask =		BIT(5),
+			.mode_mask =		BM(7, 6),
+	},
+};
+
+static struct rcg_clk mdp_clk = {
+	.b = {
+		.ctl_reg = MDP_CC_REG,
+		.en_mask = BIT(0),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(21),
+		.halt_reg = DBG_BUS_VEC_C_REG,
+		.halt_bit = 10,
+		.retain_reg = MDP_CC_REG,
+		.retain_mask = BIT(31),
+	},
+	.ns_reg = MDP_NS_REG,
+	.root_en_mask = BIT(2),
+	.set_rate = set_rate_mnd_banked,
+	.freq_tbl = clk_tbl_mdp,
+	.bank_info = &bmnd_info_mdp,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "mdp_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW,   85330000, NOMINAL, 200000000,
+				  HIGH, 228571000),
+		CLK_INIT(mdp_clk.c),
+		.depends = &mdp_axi_clk.c,
+	},
+};
+
+#define F_MDP_VSYNC(f, s) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.ns_val = NS_SRC_SEL(13, 13, s##_to_bb_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_mdp_vsync[] = {
+	F_MDP_VSYNC(27000000, pxo),
+	F_END
+};
+
+static struct rcg_clk mdp_vsync_clk = {
+	.b = {
+		.ctl_reg = MISC_CC_REG,
+		.en_mask = BIT(6),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(3),
+		.halt_reg = DBG_BUS_VEC_B_REG,
+		.halt_bit = 22,
+	},
+	.ns_reg = MISC_CC2_REG,
+	.ns_mask = BIT(13),
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_mdp_vsync,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "mdp_vsync_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 27000000),
+		CLK_INIT(mdp_vsync_clk.c),
+	},
+};
+
+#define F_PIXEL_MDP(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD16(m, n), \
+		.ns_val = NS_MM(31, 16, n, m, 15, 14, d, 2, 0, s##_to_mm_mux), \
+		.ctl_val = CC(6, n), \
+	}
+static struct clk_freq_tbl clk_tbl_pixel_mdp[] = {
+	F_PIXEL_MDP(        0, gnd,  1,   0,    0),
+	F_PIXEL_MDP( 25600000, pll8, 3,   1,    5),
+	F_PIXEL_MDP( 42667000, pll8, 1,   1,    9),
+	F_PIXEL_MDP( 43192000, pll8, 1,  64,  569),
+	F_PIXEL_MDP( 48000000, pll8, 4,   1,    2),
+	F_PIXEL_MDP( 53990000, pll8, 2, 169,  601),
+	F_PIXEL_MDP( 64000000, pll8, 2,   1,    3),
+	F_PIXEL_MDP( 69300000, pll8, 1, 231, 1280),
+	F_PIXEL_MDP( 76800000, pll8, 1,   1,    5),
+	F_PIXEL_MDP( 85333000, pll8, 1,   2,    9),
+	F_PIXEL_MDP(106500000, pll8, 1,  71,  256),
+	F_PIXEL_MDP(109714000, pll8, 1,   2,    7),
+	F_END
+};
+
+static struct rcg_clk pixel_mdp_clk = {
+	.ns_reg = PIXEL_NS_REG,
+	.md_reg = PIXEL_MD_REG,
+	.b = {
+		.ctl_reg = PIXEL_CC_REG,
+		.en_mask = BIT(0),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(5),
+		.halt_reg = DBG_BUS_VEC_C_REG,
+		.halt_bit = 23,
+		.retain_reg = PIXEL_CC_REG,
+		.retain_mask = BIT(31),
+	},
+	.root_en_mask = BIT(2),
+	.ns_mask = (BM(31, 16) | BM(15, 14) | BM(2, 0)),
+	.mnd_en_mask = BIT(5),
+	.ctl_mask = BM(7, 6),
+	.set_rate = set_rate_mnd,
+	.freq_tbl = clk_tbl_pixel_mdp,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "pixel_mdp_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 85333000, NOMINAL, 170000000),
+		CLK_INIT(pixel_mdp_clk.c),
+	},
+};
+
+static struct branch_clk pixel_lcdc_clk = {
+	.b = {
+		.ctl_reg = PIXEL_CC_REG,
+		.en_mask = BIT(8),
+		.halt_reg = DBG_BUS_VEC_C_REG,
+		.halt_bit = 21,
+	},
+	.parent = &pixel_mdp_clk.c,
+	.c = {
+		.dbg_name = "pixel_lcdc_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(pixel_lcdc_clk.c),
+	},
+};
+
+#define F_ROT(f, s, d) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.ns_val = NS_DIVSRC_BANKED(29, 26, 25, 22, d, \
+				21, 19, 18, 16, s##_to_mm_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_rot[] = {
+	F_ROT(        0, gnd,   1),
+	F_ROT( 27000000, pxo,   1),
+	F_ROT( 29540000, pll8, 13),
+	F_ROT( 32000000, pll8, 12),
+	F_ROT( 38400000, pll8, 10),
+	F_ROT( 48000000, pll8,  8),
+	F_ROT( 54860000, pll8,  7),
+	F_ROT( 64000000, pll8,  6),
+	F_ROT( 76800000, pll8,  5),
+	F_ROT( 96000000, pll8,  4),
+	F_ROT(100000000, pll2,  8),
+	F_ROT(114290000, pll2,  7),
+	F_ROT(133330000, pll2,  6),
+	F_ROT(160000000, pll2,  5),
+	F_END
+};
+
+static struct bank_masks bdiv_info_rot = {
+	.bank_sel_mask = BIT(30),
+	.bank0_mask = {
+		.ns_mask =	BM(25, 22) | BM(18, 16),
+	},
+	.bank1_mask = {
+		.ns_mask =	BM(29, 26) | BM(21, 19),
+	},
+};
+
+static struct rcg_clk rot_clk = {
+	.b = {
+		.ctl_reg = ROT_CC_REG,
+		.en_mask = BIT(0),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(2),
+		.halt_reg = DBG_BUS_VEC_C_REG,
+		.halt_bit = 15,
+		.retain_reg = ROT_CC_REG,
+		.retain_mask = BIT(31),
+	},
+	.ns_reg = ROT_NS_REG,
+	.root_en_mask = BIT(2),
+	.set_rate = set_rate_div_banked,
+	.freq_tbl = clk_tbl_rot,
+	.bank_info = &bdiv_info_rot,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "rot_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 80000000, NOMINAL, 160000000),
+		CLK_INIT(rot_clk.c),
+		.depends = &rot_axi_clk.c,
+	},
+};
+
+#define F_TV(f, s, p_r, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD8(8, m, 0, n), \
+		.ns_val = NS_MM(23, 16, n, m, 15, 14, d, 2, 0, s##_to_mm_mux), \
+		.ctl_val = CC(6, n), \
+		.extra_freq_data = p_r, \
+	}
+/* Switching TV freqs requires PLL reconfiguration. */
+static struct pll_rate mm_pll2_rate[] = {
+	[0] = PLL_RATE( 7, 6301, 13500, 0, 4, 0x4248B), /*  50400500 Hz */
+	[1] = PLL_RATE( 8,    0,     0, 0, 4, 0x4248B), /*  54000000 Hz */
+	[2] = PLL_RATE(16,    2,   125, 0, 4, 0x5248F), /* 108108000 Hz */
+	[3] = PLL_RATE(22,    0,     0, 2, 4, 0x6248B), /* 148500000 Hz */
+	[4] = PLL_RATE(44,    0,     0, 2, 4, 0x6248F), /* 297000000 Hz */
+};
+static struct clk_freq_tbl clk_tbl_tv[] = {
+	F_TV(        0, gnd,  &mm_pll2_rate[0], 1, 0, 0),
+	F_TV( 25200000, pll3, &mm_pll2_rate[0], 2, 0, 0),
+	F_TV( 27000000, pll3, &mm_pll2_rate[1], 2, 0, 0),
+	F_TV( 27030000, pll3, &mm_pll2_rate[2], 4, 0, 0),
+	F_TV( 74250000, pll3, &mm_pll2_rate[3], 2, 0, 0),
+	F_TV(148500000, pll3, &mm_pll2_rate[4], 2, 0, 0),
+	F_END
+};
+
+static struct rcg_clk tv_src_clk = {
+	.ns_reg = TV_NS_REG,
+	.b = {
+		.ctl_reg = TV_CC_REG,
+		.halt_check = NOCHECK,
+		.retain_reg = TV_CC_REG,
+		.retain_mask = BIT(31),
+	},
+	.md_reg = TV_MD_REG,
+	.root_en_mask = BIT(2),
+	.ns_mask = (BM(23, 16) | BM(15, 14) | BM(2, 0)),
+	.mnd_en_mask = BIT(5),
+	.ctl_mask = BM(7, 6),
+	.set_rate = set_rate_tv,
+	.freq_tbl = clk_tbl_tv,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "tv_src_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 27030000, NOMINAL, 149000000),
+		CLK_INIT(tv_src_clk.c),
+	},
+};
+
+static struct branch_clk tv_enc_clk = {
+	.b = {
+		.ctl_reg = TV_CC_REG,
+		.en_mask = BIT(8),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(0),
+		.halt_reg = DBG_BUS_VEC_D_REG,
+		.halt_bit = 8,
+	},
+	.parent = &tv_src_clk.c,
+	.c = {
+		.dbg_name = "tv_enc_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(tv_enc_clk.c),
+	},
+};
+
+static struct branch_clk tv_dac_clk = {
+	.b = {
+		.ctl_reg = TV_CC_REG,
+		.en_mask = BIT(10),
+		.halt_reg = DBG_BUS_VEC_D_REG,
+		.halt_bit = 9,
+	},
+	.parent = &tv_src_clk.c,
+	.c = {
+		.dbg_name = "tv_dac_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(tv_dac_clk.c),
+	},
+};
+
+static struct branch_clk mdp_tv_clk = {
+	.b = {
+		.ctl_reg = TV_CC_REG,
+		.en_mask = BIT(0),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(4),
+		.halt_reg = DBG_BUS_VEC_D_REG,
+		.halt_bit = 11,
+	},
+	.parent = &tv_src_clk.c,
+	.c = {
+		.dbg_name = "mdp_tv_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdp_tv_clk.c),
+	},
+};
+
+static struct branch_clk hdmi_tv_clk = {
+	.b = {
+		.ctl_reg = TV_CC_REG,
+		.en_mask = BIT(12),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(1),
+		.halt_reg = DBG_BUS_VEC_D_REG,
+		.halt_bit = 10,
+	},
+	.parent = &tv_src_clk.c,
+	.c = {
+		.dbg_name = "hdmi_tv_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(hdmi_tv_clk.c),
+	},
+};
+
+static struct branch_clk hdmi_app_clk = {
+	.b = {
+		.ctl_reg = MISC_CC2_REG,
+		.en_mask = BIT(11),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(11),
+		.halt_reg = DBG_BUS_VEC_B_REG,
+		.halt_bit = 25,
+	},
+	.c = {
+		.dbg_name = "hdmi_app_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(hdmi_app_clk.c),
+	},
+};
+
+#define F_VCODEC(f, s, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD8(8, m, 0, n), \
+		.ns_val = NS_MM(18, 11, n, m, 0, 0, 1, 2, 0, s##_to_mm_mux), \
+		.ctl_val = CC(6, n), \
+	}
+static struct clk_freq_tbl clk_tbl_vcodec[] = {
+	F_VCODEC(        0, gnd,  0,  0),
+	F_VCODEC( 27000000, pxo,  0,  0),
+	F_VCODEC( 32000000, pll8, 1, 12),
+	F_VCODEC( 48000000, pll8, 1,  8),
+	F_VCODEC( 54860000, pll8, 1,  7),
+	F_VCODEC( 96000000, pll8, 1,  4),
+	F_VCODEC(133330000, pll2, 1,  6),
+	F_VCODEC(200000000, pll2, 1,  4),
+	F_VCODEC(228570000, pll2, 2,  7),
+	F_END
+};
+
+static struct rcg_clk vcodec_clk = {
+	.b = {
+		.ctl_reg = VCODEC_CC_REG,
+		.en_mask = BIT(0),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(6),
+		.halt_reg = DBG_BUS_VEC_C_REG,
+		.halt_bit = 29,
+		.retain_reg = VCODEC_CC_REG,
+		.retain_mask = BIT(31),
+	},
+	.ns_reg = VCODEC_NS_REG,
+	.md_reg = VCODEC_MD0_REG,
+	.root_en_mask = BIT(2),
+	.ns_mask = (BM(18, 11) | BM(2, 0)),
+	.mnd_en_mask = BIT(5),
+	.ctl_mask = BM(7, 6),
+	.set_rate = set_rate_mnd,
+	.freq_tbl = clk_tbl_vcodec,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "vcodec_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW,  100000000, NOMINAL, 200000000,
+				  HIGH, 228571000),
+		CLK_INIT(vcodec_clk.c),
+		.depends = &vcodec_axi_clk.c,
+	},
+};
+
+#define F_VPE(f, s, d) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.ns_val = NS_DIVSRC(15, 12, d, 2, 0, s##_to_mm_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_vpe[] = {
+	F_VPE(        0, gnd,   1),
+	F_VPE( 27000000, pxo,   1),
+	F_VPE( 34909000, pll8, 11),
+	F_VPE( 38400000, pll8, 10),
+	F_VPE( 64000000, pll8,  6),
+	F_VPE( 76800000, pll8,  5),
+	F_VPE( 96000000, pll8,  4),
+	F_VPE(100000000, pll2,  8),
+	F_VPE(160000000, pll2,  5),
+	F_VPE(200000000, pll2,  4),
+	F_END
+};
+
+static struct rcg_clk vpe_clk = {
+	.b = {
+		.ctl_reg = VPE_CC_REG,
+		.en_mask = BIT(0),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(17),
+		.halt_reg = DBG_BUS_VEC_A_REG,
+		.halt_bit = 28,
+		.retain_reg = VPE_CC_REG,
+		.retain_mask =  BIT(31),
+	},
+	.ns_reg = VPE_NS_REG,
+	.root_en_mask = BIT(2),
+	.ns_mask = (BM(15, 12) | BM(2, 0)),
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_vpe,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "vpe_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW,   76800000, NOMINAL, 160000000,
+				  HIGH, 200000000),
+		CLK_INIT(vpe_clk.c),
+		.depends = &vpe_axi_clk.c,
+	},
+};
+
+#define F_VFE(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD8(8, m, 0, n), \
+		.ns_val = NS_MM(23, 16, n, m, 11, 10, d, 2, 0, s##_to_mm_mux), \
+		.ctl_val = CC(6, n), \
+	}
+static struct clk_freq_tbl clk_tbl_vfe[] = {
+	F_VFE(        0, gnd,   1, 0,  0),
+	F_VFE( 13960000, pll8,  1, 2, 55),
+	F_VFE( 27000000, pxo,   1, 0,  0),
+	F_VFE( 36570000, pll8,  1, 2, 21),
+	F_VFE( 38400000, pll8,  2, 1,  5),
+	F_VFE( 45180000, pll8,  1, 2, 17),
+	F_VFE( 48000000, pll8,  2, 1,  4),
+	F_VFE( 54860000, pll8,  1, 1,  7),
+	F_VFE( 64000000, pll8,  2, 1,  3),
+	F_VFE( 76800000, pll8,  1, 1,  5),
+	F_VFE( 96000000, pll8,  2, 1,  2),
+	F_VFE(109710000, pll8,  1, 2,  7),
+	F_VFE(128000000, pll8,  1, 1,  3),
+	F_VFE(153600000, pll8,  1, 2,  5),
+	F_VFE(200000000, pll2,  2, 1,  2),
+	F_VFE(228570000, pll2,  1, 2,  7),
+	F_VFE(266667000, pll2,  1, 1,  3),
+	F_END
+};
+
+static struct rcg_clk vfe_clk = {
+	.b = {
+		.ctl_reg = VFE_CC_REG,
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(15),
+		.halt_reg = DBG_BUS_VEC_B_REG,
+		.halt_bit = 6,
+		.en_mask = BIT(0),
+		.retain_reg = VFE_CC_REG,
+		.retain_mask = BIT(31),
+	},
+	.ns_reg = VFE_NS_REG,
+	.md_reg = VFE_MD_REG,
+	.root_en_mask = BIT(2),
+	.ns_mask = (BM(23, 16) | BM(11, 10) | BM(2, 0)),
+	.mnd_en_mask = BIT(5),
+	.ctl_mask = BM(7, 6),
+	.set_rate = set_rate_mnd,
+	.freq_tbl = clk_tbl_vfe,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "vfe_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW,  110000000, NOMINAL, 228570000,
+				  HIGH, 266667000),
+		CLK_INIT(vfe_clk.c),
+		.depends = &vfe_axi_clk.c,
+	},
+};
+
+static struct branch_clk csi0_vfe_clk = {
+	.b = {
+		.ctl_reg = VFE_CC_REG,
+		.en_mask = BIT(12),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(24),
+		.halt_reg = DBG_BUS_VEC_B_REG,
+		.halt_bit = 7,
+	},
+	.parent = &vfe_clk.c,
+	.c = {
+		.dbg_name = "csi0_vfe_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi0_vfe_clk.c),
+	},
+};
+
+static struct branch_clk csi1_vfe_clk = {
+	.b = {
+		.ctl_reg = VFE_CC_REG,
+		.en_mask = BIT(10),
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(23),
+		.halt_reg = DBG_BUS_VEC_B_REG,
+		.halt_bit = 8,
+	},
+	.parent = &vfe_clk.c,
+	.c = {
+		.dbg_name = "csi1_vfe_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi1_vfe_clk.c),
+	},
+};
+
+/*
+ * Low Power Audio Clocks
+ */
+#define F_AIF_OSR(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD8(8, m, 0, n), \
+		.ns_val = NS(31, 24, n, m, 5, 4, 3, d, 2, 0, s##_to_lpa_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_aif_osr[] = {
+	F_AIF_OSR(       0, gnd,  1, 0,   0),
+	F_AIF_OSR(  768000, pll4, 4, 1, 176),
+	F_AIF_OSR( 1024000, pll4, 4, 1, 132),
+	F_AIF_OSR( 1536000, pll4, 4, 1,  88),
+	F_AIF_OSR( 2048000, pll4, 4, 1,  66),
+	F_AIF_OSR( 3072000, pll4, 4, 1,  44),
+	F_AIF_OSR( 4096000, pll4, 4, 1,  33),
+	F_AIF_OSR( 6144000, pll4, 4, 1,  22),
+	F_AIF_OSR( 8192000, pll4, 2, 1,  33),
+	F_AIF_OSR(12288000, pll4, 4, 1,  11),
+	F_AIF_OSR(24576000, pll4, 2, 1,  11),
+	F_END
+};
+
+#define CLK_AIF_OSR(i, ns, md, h_r) \
+	struct rcg_clk i##_clk = { \
+		.b = { \
+			.ctl_reg = ns, \
+			.en_mask = BIT(17), \
+			.reset_reg = ns, \
+			.reset_mask = BIT(19), \
+			.halt_reg = h_r, \
+			.halt_check = ENABLE, \
+			.halt_bit = 1, \
+		}, \
+		.ns_reg = ns, \
+		.md_reg = md, \
+		.root_en_mask = BIT(9), \
+		.ns_mask = (BM(31, 24) | BM(6, 0)), \
+		.mnd_en_mask = BIT(8), \
+		.set_rate = set_rate_mnd, \
+		.freq_tbl = clk_tbl_aif_osr, \
+		.current_freq = &rcg_dummy_freq, \
+		.c = { \
+			.dbg_name = #i "_clk", \
+			.ops = &clk_ops_rcg, \
+			VDD_DIG_FMAX_MAP1(LOW, 24576000), \
+			CLK_INIT(i##_clk.c), \
+		}, \
+	}
+
+#define CLK_AIF_BIT(i, ns, h_r) \
+	struct cdiv_clk i##_clk = { \
+		.b = { \
+			.ctl_reg = ns, \
+			.en_mask = BIT(15), \
+			.halt_reg = h_r, \
+			.halt_check = DELAY, \
+		}, \
+		.ns_reg = ns, \
+		.ext_mask = BIT(14), \
+		.div_offset = 10, \
+		.max_div = 16, \
+		.c = { \
+			.dbg_name = #i "_clk", \
+			.ops = &clk_ops_cdiv, \
+			CLK_INIT(i##_clk.c), \
+		}, \
+	}
+
+static CLK_AIF_OSR(mi2s_osr, LCC_MI2S_NS_REG, LCC_MI2S_MD_REG,
+		LCC_MI2S_STATUS_REG);
+static CLK_AIF_BIT(mi2s_bit, LCC_MI2S_NS_REG, LCC_MI2S_STATUS_REG);
+
+static CLK_AIF_OSR(codec_i2s_mic_osr, LCC_CODEC_I2S_MIC_NS_REG,
+		LCC_CODEC_I2S_MIC_MD_REG, LCC_CODEC_I2S_MIC_STATUS_REG);
+static CLK_AIF_BIT(codec_i2s_mic_bit, LCC_CODEC_I2S_MIC_NS_REG,
+		LCC_CODEC_I2S_MIC_STATUS_REG);
+
+static CLK_AIF_OSR(spare_i2s_mic_osr, LCC_SPARE_I2S_MIC_NS_REG,
+		LCC_SPARE_I2S_MIC_MD_REG, LCC_SPARE_I2S_MIC_STATUS_REG);
+static CLK_AIF_BIT(spare_i2s_mic_bit, LCC_SPARE_I2S_MIC_NS_REG,
+		LCC_SPARE_I2S_MIC_STATUS_REG);
+
+static CLK_AIF_OSR(codec_i2s_spkr_osr, LCC_CODEC_I2S_SPKR_NS_REG,
+		LCC_CODEC_I2S_SPKR_MD_REG, LCC_CODEC_I2S_SPKR_STATUS_REG);
+static CLK_AIF_BIT(codec_i2s_spkr_bit, LCC_CODEC_I2S_SPKR_NS_REG,
+		LCC_CODEC_I2S_SPKR_STATUS_REG);
+
+static CLK_AIF_OSR(spare_i2s_spkr_osr, LCC_SPARE_I2S_SPKR_NS_REG,
+		LCC_SPARE_I2S_SPKR_MD_REG, LCC_SPARE_I2S_SPKR_STATUS_REG);
+static CLK_AIF_BIT(spare_i2s_spkr_bit, LCC_SPARE_I2S_SPKR_NS_REG,
+		LCC_SPARE_I2S_SPKR_STATUS_REG);
+
+#define F_PCM(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD16(m, n), \
+		.ns_val = NS(31, 16, n, m, 5, 4, 3, d, 2, 0, s##_to_lpa_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_pcm[] = {
+	{ .ns_val = BIT(10) /* external input */ },
+	F_PCM(  512000, pll4, 4, 1, 264),
+	F_PCM(  768000, pll4, 4, 1, 176),
+	F_PCM( 1024000, pll4, 4, 1, 132),
+	F_PCM( 1536000, pll4, 4, 1,  88),
+	F_PCM( 2048000, pll4, 4, 1,  66),
+	F_PCM( 3072000, pll4, 4, 1,  44),
+	F_PCM( 4096000, pll4, 4, 1,  33),
+	F_PCM( 6144000, pll4, 4, 1,  22),
+	F_PCM( 8192000, pll4, 2, 1,  33),
+	F_PCM(12288000, pll4, 4, 1,  11),
+	F_PCM(24580000, pll4, 2, 1,  11),
+	F_END
+};
+
+static struct rcg_clk pcm_clk = {
+	.b = {
+		.ctl_reg = LCC_PCM_NS_REG,
+		.en_mask = BIT(11),
+		.reset_reg = LCC_PCM_NS_REG,
+		.reset_mask = BIT(13),
+		.halt_reg = LCC_PCM_STATUS_REG,
+		.halt_check = ENABLE,
+		.halt_bit = 0,
+	},
+	.ns_reg = LCC_PCM_NS_REG,
+	.md_reg = LCC_PCM_MD_REG,
+	.root_en_mask = BIT(9),
+	.ns_mask = BM(31, 16) | BIT(10) | BM(6, 0),
+	.mnd_en_mask = BIT(8),
+	.set_rate = set_rate_mnd,
+	.freq_tbl = clk_tbl_pcm,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "pcm_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 24580000),
+		CLK_INIT(pcm_clk.c),
+	},
+};
+
+DEFINE_CLK_RPM(afab_clk, afab_a_clk, APPS_FABRIC, NULL);
+DEFINE_CLK_RPM(cfpb_clk, cfpb_a_clk, CFPB, NULL);
+DEFINE_CLK_RPM(dfab_clk, dfab_a_clk, DAYTONA_FABRIC, NULL);
+DEFINE_CLK_RPM(ebi1_clk, ebi1_a_clk, EBI1, NULL);
+DEFINE_CLK_RPM(mmfab_clk, mmfab_a_clk, MM_FABRIC, NULL);
+DEFINE_CLK_RPM(mmfpb_clk, mmfpb_a_clk, MMFPB, NULL);
+DEFINE_CLK_RPM(sfab_clk, sfab_a_clk, SYSTEM_FABRIC, NULL);
+DEFINE_CLK_RPM(sfpb_clk, sfpb_a_clk, SFPB, NULL);
+DEFINE_CLK_RPM(smi_clk, smi_a_clk, SMI, &smi_2x_axi_clk.c);
+
+static DEFINE_CLK_VOTER(dfab_dsps_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_usb_hs_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_sdc1_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_sdc2_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_sdc3_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_sdc4_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_sdc5_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_scm_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_qseecom_clk, &dfab_clk.c, 0);
+
+static DEFINE_CLK_VOTER(ebi1_msmbus_clk, &ebi1_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(ebi1_adm0_clk,   &ebi1_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi1_adm1_clk,   &ebi1_clk.c, 0);
+static DEFINE_CLK_MEASURE(sc0_m_clk);
+static DEFINE_CLK_MEASURE(sc1_m_clk);
+static DEFINE_CLK_MEASURE(l2_m_clk);
+
+#ifdef CONFIG_DEBUG_FS
+struct measure_sel {
+	u32 test_vector;
+	struct clk *clk;
+};
+
+static struct measure_sel measure_mux[] = {
+	{ TEST_PER_LS(0x08), &modem_ahb1_p_clk.c },
+	{ TEST_PER_LS(0x09), &modem_ahb2_p_clk.c },
+	{ TEST_PER_LS(0x12), &sdc1_p_clk.c },
+	{ TEST_PER_LS(0x13), &sdc1_clk.c },
+	{ TEST_PER_LS(0x14), &sdc2_p_clk.c },
+	{ TEST_PER_LS(0x15), &sdc2_clk.c },
+	{ TEST_PER_LS(0x16), &sdc3_p_clk.c },
+	{ TEST_PER_LS(0x17), &sdc3_clk.c },
+	{ TEST_PER_LS(0x18), &sdc4_p_clk.c },
+	{ TEST_PER_LS(0x19), &sdc4_clk.c },
+	{ TEST_PER_LS(0x1A), &sdc5_p_clk.c },
+	{ TEST_PER_LS(0x1B), &sdc5_clk.c },
+	{ TEST_PER_LS(0x1D), &ebi2_2x_clk.c },
+	{ TEST_PER_LS(0x1E), &ebi2_clk.c },
+	{ TEST_PER_LS(0x1F), &gp0_clk.c },
+	{ TEST_PER_LS(0x20), &gp1_clk.c },
+	{ TEST_PER_LS(0x21), &gp2_clk.c },
+	{ TEST_PER_LS(0x25), &dfab_clk.c },
+	{ TEST_PER_LS(0x25), &dfab_a_clk.c },
+	{ TEST_PER_LS(0x26), &pmem_clk.c },
+	{ TEST_PER_LS(0x2B), &ppss_p_clk.c },
+	{ TEST_PER_LS(0x33), &cfpb_clk.c },
+	{ TEST_PER_LS(0x33), &cfpb_a_clk.c },
+	{ TEST_PER_LS(0x3D), &gsbi1_p_clk.c },
+	{ TEST_PER_LS(0x3E), &gsbi1_uart_clk.c },
+	{ TEST_PER_LS(0x3F), &gsbi1_qup_clk.c },
+	{ TEST_PER_LS(0x41), &gsbi2_p_clk.c },
+	{ TEST_PER_LS(0x42), &gsbi2_uart_clk.c },
+	{ TEST_PER_LS(0x44), &gsbi2_qup_clk.c },
+	{ TEST_PER_LS(0x45), &gsbi3_p_clk.c },
+	{ TEST_PER_LS(0x46), &gsbi3_uart_clk.c },
+	{ TEST_PER_LS(0x48), &gsbi3_qup_clk.c },
+	{ TEST_PER_LS(0x49), &gsbi4_p_clk.c },
+	{ TEST_PER_LS(0x4A), &gsbi4_uart_clk.c },
+	{ TEST_PER_LS(0x4C), &gsbi4_qup_clk.c },
+	{ TEST_PER_LS(0x4D), &gsbi5_p_clk.c },
+	{ TEST_PER_LS(0x4E), &gsbi5_uart_clk.c },
+	{ TEST_PER_LS(0x50), &gsbi5_qup_clk.c },
+	{ TEST_PER_LS(0x51), &gsbi6_p_clk.c },
+	{ TEST_PER_LS(0x52), &gsbi6_uart_clk.c },
+	{ TEST_PER_LS(0x54), &gsbi6_qup_clk.c },
+	{ TEST_PER_LS(0x55), &gsbi7_p_clk.c },
+	{ TEST_PER_LS(0x56), &gsbi7_uart_clk.c },
+	{ TEST_PER_LS(0x58), &gsbi7_qup_clk.c },
+	{ TEST_PER_LS(0x59), &gsbi8_p_clk.c },
+	{ TEST_PER_LS(0x5A), &gsbi8_uart_clk.c },
+	{ TEST_PER_LS(0x5C), &gsbi8_qup_clk.c },
+	{ TEST_PER_LS(0x5D), &gsbi9_p_clk.c },
+	{ TEST_PER_LS(0x5E), &gsbi9_uart_clk.c },
+	{ TEST_PER_LS(0x60), &gsbi9_qup_clk.c },
+	{ TEST_PER_LS(0x61), &gsbi10_p_clk.c },
+	{ TEST_PER_LS(0x62), &gsbi10_uart_clk.c },
+	{ TEST_PER_LS(0x64), &gsbi10_qup_clk.c },
+	{ TEST_PER_LS(0x65), &gsbi11_p_clk.c },
+	{ TEST_PER_LS(0x66), &gsbi11_uart_clk.c },
+	{ TEST_PER_LS(0x68), &gsbi11_qup_clk.c },
+	{ TEST_PER_LS(0x69), &gsbi12_p_clk.c },
+	{ TEST_PER_LS(0x6A), &gsbi12_uart_clk.c },
+	{ TEST_PER_LS(0x6C), &gsbi12_qup_clk.c },
+	{ TEST_PER_LS(0x78), &sfpb_clk.c },
+	{ TEST_PER_LS(0x78), &sfpb_a_clk.c },
+	{ TEST_PER_LS(0x7A), &pmic_ssbi2_clk.c },
+	{ TEST_PER_LS(0x7B), &pmic_arb0_p_clk.c },
+	{ TEST_PER_LS(0x7C), &pmic_arb1_p_clk.c },
+	{ TEST_PER_LS(0x7D), &prng_clk.c },
+	{ TEST_PER_LS(0x7F), &rpm_msg_ram_p_clk.c },
+	{ TEST_PER_LS(0x80), &adm0_p_clk.c },
+	{ TEST_PER_LS(0x81), &adm1_p_clk.c },
+	{ TEST_PER_LS(0x84), &usb_hs1_p_clk.c },
+	{ TEST_PER_LS(0x85), &usb_hs1_xcvr_clk.c },
+	{ TEST_PER_LS(0x89), &usb_fs1_p_clk.c },
+	{ TEST_PER_LS(0x8A), &usb_fs1_sys_clk.c },
+	{ TEST_PER_LS(0x8B), &usb_fs1_xcvr_clk.c },
+	{ TEST_PER_LS(0x8C), &usb_fs2_p_clk.c },
+	{ TEST_PER_LS(0x8D), &usb_fs2_sys_clk.c },
+	{ TEST_PER_LS(0x8E), &usb_fs2_xcvr_clk.c },
+	{ TEST_PER_LS(0x8F), &tsif_p_clk.c },
+	{ TEST_PER_LS(0x91), &tsif_ref_clk.c },
+	{ TEST_PER_LS(0x93), &ce2_p_clk.c },
+	{ TEST_PER_LS(0x94), &tssc_clk.c },
+
+	{ TEST_PER_HS(0x07), &afab_clk.c },
+	{ TEST_PER_HS(0x07), &afab_a_clk.c },
+	{ TEST_PER_HS(0x18), &sfab_clk.c },
+	{ TEST_PER_HS(0x18), &sfab_a_clk.c },
+	{ TEST_PER_HS(0x2A), &adm0_clk.c },
+	{ TEST_PER_HS(0x2B), &adm1_clk.c },
+	{ TEST_PER_HS(0x34), &ebi1_clk.c },
+	{ TEST_PER_HS(0x34), &ebi1_a_clk.c },
+
+	{ TEST_MM_LS(0x00), &dsi_byte_clk.c },
+	{ TEST_MM_LS(0x01), &pixel_lcdc_clk.c },
+	{ TEST_MM_LS(0x04), &pixel_mdp_clk.c },
+	{ TEST_MM_LS(0x06), &amp_p_clk.c },
+	{ TEST_MM_LS(0x07), &csi0_p_clk.c },
+	{ TEST_MM_LS(0x08), &csi1_p_clk.c },
+	{ TEST_MM_LS(0x09), &dsi_m_p_clk.c },
+	{ TEST_MM_LS(0x0A), &dsi_s_p_clk.c },
+	{ TEST_MM_LS(0x0C), &gfx2d0_p_clk.c },
+	{ TEST_MM_LS(0x0D), &gfx2d1_p_clk.c },
+	{ TEST_MM_LS(0x0E), &gfx3d_p_clk.c },
+	{ TEST_MM_LS(0x0F), &hdmi_m_p_clk.c },
+	{ TEST_MM_LS(0x10), &hdmi_s_p_clk.c },
+	{ TEST_MM_LS(0x11), &ijpeg_p_clk.c },
+	{ TEST_MM_LS(0x12), &imem_p_clk.c },
+	{ TEST_MM_LS(0x13), &jpegd_p_clk.c },
+	{ TEST_MM_LS(0x14), &mdp_p_clk.c },
+	{ TEST_MM_LS(0x16), &rot_p_clk.c },
+	{ TEST_MM_LS(0x18), &smmu_p_clk.c },
+	{ TEST_MM_LS(0x19), &tv_enc_p_clk.c },
+	{ TEST_MM_LS(0x1A), &vcodec_p_clk.c },
+	{ TEST_MM_LS(0x1B), &vfe_p_clk.c },
+	{ TEST_MM_LS(0x1C), &vpe_p_clk.c },
+	{ TEST_MM_LS(0x1D), &cam_clk.c },
+	{ TEST_MM_LS(0x1F), &hdmi_app_clk.c },
+	{ TEST_MM_LS(0x20), &mdp_vsync_clk.c },
+	{ TEST_MM_LS(0x21), &tv_dac_clk.c },
+	{ TEST_MM_LS(0x22), &tv_enc_clk.c },
+	{ TEST_MM_LS(0x23), &dsi_esc_clk.c },
+	{ TEST_MM_LS(0x25), &mmfpb_clk.c },
+	{ TEST_MM_LS(0x25), &mmfpb_a_clk.c },
+
+	{ TEST_MM_HS(0x00), &csi0_clk.c },
+	{ TEST_MM_HS(0x01), &csi1_clk.c },
+	{ TEST_MM_HS(0x03), &csi0_vfe_clk.c },
+	{ TEST_MM_HS(0x04), &csi1_vfe_clk.c },
+	{ TEST_MM_HS(0x05), &ijpeg_clk.c },
+	{ TEST_MM_HS(0x06), &vfe_clk.c },
+	{ TEST_MM_HS(0x07), &gfx2d0_clk.c },
+	{ TEST_MM_HS(0x08), &gfx2d1_clk.c },
+	{ TEST_MM_HS(0x09), &gfx3d_clk.c },
+	{ TEST_MM_HS(0x0A), &jpegd_clk.c },
+	{ TEST_MM_HS(0x0B), &vcodec_clk.c },
+	{ TEST_MM_HS(0x0F), &mmfab_clk.c },
+	{ TEST_MM_HS(0x0F), &mmfab_a_clk.c },
+	{ TEST_MM_HS(0x11), &gmem_axi_clk.c },
+	{ TEST_MM_HS(0x12), &ijpeg_axi_clk.c },
+	{ TEST_MM_HS(0x13), &imem_axi_clk.c },
+	{ TEST_MM_HS(0x14), &jpegd_axi_clk.c },
+	{ TEST_MM_HS(0x15), &mdp_axi_clk.c },
+	{ TEST_MM_HS(0x16), &rot_axi_clk.c },
+	{ TEST_MM_HS(0x17), &vcodec_axi_clk.c },
+	{ TEST_MM_HS(0x18), &vfe_axi_clk.c },
+	{ TEST_MM_HS(0x19), &vpe_axi_clk.c },
+	{ TEST_MM_HS(0x1A), &mdp_clk.c },
+	{ TEST_MM_HS(0x1B), &rot_clk.c },
+	{ TEST_MM_HS(0x1C), &vpe_clk.c },
+	{ TEST_MM_HS(0x1E), &hdmi_tv_clk.c },
+	{ TEST_MM_HS(0x1F), &mdp_tv_clk.c },
+	{ TEST_MM_HS(0x24), &smi_2x_axi_clk.c },
+
+	{ TEST_MM_HS2X(0x24), &smi_clk.c },
+	{ TEST_MM_HS2X(0x24), &smi_a_clk.c },
+
+	{ TEST_LPA(0x0A), &mi2s_osr_clk.c },
+	{ TEST_LPA(0x0B), &mi2s_bit_clk.c },
+	{ TEST_LPA(0x0C), &codec_i2s_mic_osr_clk.c },
+	{ TEST_LPA(0x0D), &codec_i2s_mic_bit_clk.c },
+	{ TEST_LPA(0x0E), &codec_i2s_spkr_osr_clk.c },
+	{ TEST_LPA(0x0F), &codec_i2s_spkr_bit_clk.c },
+	{ TEST_LPA(0x10), &spare_i2s_mic_osr_clk.c },
+	{ TEST_LPA(0x11), &spare_i2s_mic_bit_clk.c },
+	{ TEST_LPA(0x12), &spare_i2s_spkr_osr_clk.c },
+	{ TEST_LPA(0x13), &spare_i2s_spkr_bit_clk.c },
+	{ TEST_LPA(0x14), &pcm_clk.c },
+
+	{ TEST_SC(0x40), &sc0_m_clk },
+	{ TEST_SC(0x41), &sc1_m_clk },
+	{ TEST_SC(0x42), &l2_m_clk },
+};
+
+static struct measure_sel *find_measure_sel(struct clk *clk)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(measure_mux); i++)
+		if (measure_mux[i].clk == clk)
+			return &measure_mux[i];
+	return NULL;
+}
+
+static int measure_clk_set_parent(struct clk *c, struct clk *parent)
+{
+	int ret = 0;
+	u32 clk_sel;
+	struct measure_sel *p;
+	struct measure_clk *clk = to_measure_clk(c);
+	unsigned long flags;
+
+	if (!parent)
+		return -EINVAL;
+
+	p = find_measure_sel(parent);
+	if (!p)
+		return -EINVAL;
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+
+	/*
+	 * Program the test vector, measurement period (sample_ticks)
+	 * and scaling factors (multiplier, divider).
+	 */
+	clk_sel = p->test_vector & TEST_CLK_SEL_MASK;
+	clk->sample_ticks = 0x10000;
+	clk->multiplier = 1;
+	clk->divider = 1;
+	switch (p->test_vector >> TEST_TYPE_SHIFT) {
+	case TEST_TYPE_PER_LS:
+		writel_relaxed(0x4030D00|BVAL(7, 0, clk_sel), CLK_TEST_REG);
+		break;
+	case TEST_TYPE_PER_HS:
+		writel_relaxed(0x4020000|BVAL(16, 10, clk_sel), CLK_TEST_REG);
+		break;
+	case TEST_TYPE_MM_LS:
+		writel_relaxed(0x4030D97, CLK_TEST_REG);
+		writel_relaxed(BVAL(6, 1, clk_sel)|BIT(0), DBG_CFG_REG_LS_REG);
+		break;
+	case TEST_TYPE_MM_HS2X:
+		clk->divider = 2;
+	case TEST_TYPE_MM_HS:
+		writel_relaxed(0x402B800, CLK_TEST_REG);
+		writel_relaxed(BVAL(6, 1, clk_sel)|BIT(0), DBG_CFG_REG_HS_REG);
+		break;
+	case TEST_TYPE_LPA:
+		writel_relaxed(0x4030D98, CLK_TEST_REG);
+		writel_relaxed(BVAL(6, 1, clk_sel)|BIT(0),
+				LCC_CLK_LS_DEBUG_CFG_REG);
+		break;
+	case TEST_TYPE_SC:
+		writel_relaxed(0x5020000|BVAL(16, 10, clk_sel), CLK_TEST_REG);
+		clk->sample_ticks = 0x4000;
+		clk->multiplier = 2;
+		break;
+	default:
+		ret = -EPERM;
+	}
+	/* Make sure test vector is set before starting measurements. */
+	mb();
+
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	return ret;
+}
+
+/* Sample clock for 'ticks' reference clock ticks. */
+static u32 run_measurement(unsigned ticks)
+{
+	/* Stop counters and set the XO4 counter start value. */
+	writel_relaxed(ticks, RINGOSC_TCXO_CTL_REG);
+
+	/* Wait for timer to become ready. */
+	while ((readl_relaxed(RINGOSC_STATUS_REG) & BIT(25)) != 0)
+		cpu_relax();
+
+	/* Run measurement and wait for completion. */
+	writel_relaxed(BIT(20)|ticks, RINGOSC_TCXO_CTL_REG);
+	while ((readl_relaxed(RINGOSC_STATUS_REG) & BIT(25)) == 0)
+		cpu_relax();
+
+	/* Stop counters. */
+	writel_relaxed(0x0, RINGOSC_TCXO_CTL_REG);
+
+	/* Return measured ticks. */
+	return readl_relaxed(RINGOSC_STATUS_REG) & BM(24, 0);
+}
+
+/* Perform a hardware rate measurement for a given clock.
+   FOR DEBUG USE ONLY: Measurements take ~15 ms! */
+static unsigned long measure_clk_get_rate(struct clk *c)
+{
+	unsigned long flags;
+	u32 pdm_reg_backup, ringosc_reg_backup;
+	u64 raw_count_short, raw_count_full;
+	struct measure_clk *clk = to_measure_clk(c);
+	unsigned ret;
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+
+	/* Enable CXO/4 and RINGOSC branch and root. */
+	pdm_reg_backup = readl_relaxed(PDM_CLK_NS_REG);
+	ringosc_reg_backup = readl_relaxed(RINGOSC_NS_REG);
+	writel_relaxed(0x2898, PDM_CLK_NS_REG);
+	writel_relaxed(0xA00, RINGOSC_NS_REG);
+
+	/*
+	 * The ring oscillator counter will not reset if the measured clock
+	 * is not running.  To detect this, run a short measurement before
+	 * the full measurement.  If the raw results of the two are the same
+	 * then the clock must be off.
+	 */
+
+	/* Run a short measurement. (~1 ms) */
+	raw_count_short = run_measurement(0x1000);
+	/* Run a full measurement. (~14 ms) */
+	raw_count_full = run_measurement(clk->sample_ticks);
+
+	writel_relaxed(ringosc_reg_backup, RINGOSC_NS_REG);
+	writel_relaxed(pdm_reg_backup, PDM_CLK_NS_REG);
+
+	/* Return 0 if the clock is off. */
+	if (raw_count_full == raw_count_short)
+		ret = 0;
+	else {
+		/* Compute rate in Hz. */
+		raw_count_full = ((raw_count_full * 10) + 15) * 4800000;
+		do_div(raw_count_full,
+		       (((clk->sample_ticks * 10) + 35) * clk->divider));
+		ret = (raw_count_full * clk->multiplier);
+	}
+
+	/* Route dbg_hs_clk to PLLTEST.  300mV single-ended amplitude. */
+	writel_relaxed(0x3CF8, PLLTEST_PAD_CFG_REG);
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	return ret;
+}
+#else /* !CONFIG_DEBUG_FS */
+static int measure_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	return -EINVAL;
+}
+
+static unsigned long measure_clk_get_rate(struct clk *clk)
+{
+	return 0;
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static struct clk_ops clk_ops_measure = {
+	.set_parent = measure_clk_set_parent,
+	.get_rate = measure_clk_get_rate,
+};
+
+static struct measure_clk measure_clk = {
+	.c = {
+		.dbg_name = "measure_clk",
+		.ops = &clk_ops_measure,
+		CLK_INIT(measure_clk.c),
+	},
+	.multiplier = 1,
+	.divider = 1,
+};
+
+static struct clk_lookup msm_clocks_8x60[] = {
+	CLK_LOOKUP("xo",		cxo_clk.c,	""),
+	CLK_LOOKUP("xo",		cxo_a_clk.c,	""),
+	CLK_LOOKUP("xo",		pxo_a_clk.c,	""),
+	CLK_LOOKUP("xo",		pxo_clk.c,	"pil_modem"),
+	CLK_LOOKUP("pll4",		pll4_clk.c,	"pil_qdsp6v3"),
+	CLK_LOOKUP("measure",		measure_clk.c,	"debug"),
+
+	CLK_LOOKUP("bus_clk",		afab_clk.c,	"msm_apps_fab"),
+	CLK_LOOKUP("bus_a_clk",		afab_a_clk.c,	"msm_apps_fab"),
+	CLK_LOOKUP("bus_clk",		sfab_clk.c,	"msm_sys_fab"),
+	CLK_LOOKUP("bus_a_clk",		sfab_a_clk.c,	"msm_sys_fab"),
+	CLK_LOOKUP("bus_clk",		sfpb_clk.c,	"msm_sys_fpb"),
+	CLK_LOOKUP("bus_a_clk",		sfpb_a_clk.c,	"msm_sys_fpb"),
+	CLK_LOOKUP("bus_clk",		mmfab_clk.c,	"msm_mm_fab"),
+	CLK_LOOKUP("bus_a_clk",		mmfab_a_clk.c,	"msm_mm_fab"),
+	CLK_LOOKUP("bus_clk",		cfpb_clk.c,	"msm_cpss_fpb"),
+	CLK_LOOKUP("bus_a_clk",		cfpb_a_clk.c,	"msm_cpss_fpb"),
+	CLK_LOOKUP("mem_clk",		ebi1_msmbus_clk.c, "msm_bus"),
+	CLK_LOOKUP("mem_a_clk",		ebi1_a_clk.c,	"msm_bus"),
+	CLK_LOOKUP("smi_clk",		smi_clk.c,	"msm_bus"),
+	CLK_LOOKUP("smi_a_clk",		smi_a_clk.c,	"msm_bus"),
+
+	CLK_LOOKUP("ebi1_clk",		ebi1_clk.c,	NULL),
+	CLK_LOOKUP("dfab_clk",		dfab_clk.c,	NULL),
+	CLK_LOOKUP("dfab_a_clk",	dfab_a_clk.c,	NULL),
+	CLK_LOOKUP("mmfpb_clk",		mmfpb_clk.c,	NULL),
+	CLK_LOOKUP("mmfpb_a_clk",	mmfpb_a_clk.c,	NULL),
+
+	CLK_LOOKUP("core_clk",		gp0_clk.c,		""),
+	CLK_LOOKUP("core_clk",		gp1_clk.c,		""),
+	CLK_LOOKUP("core_clk",		gp2_clk.c,		""),
+	CLK_LOOKUP("core_clk",		gsbi1_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi2_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi3_uart_clk.c, "msm_serial_hsl.2"),
+	CLK_LOOKUP("core_clk",		gsbi4_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi5_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi6_uart_clk.c, "msm_serial_hs.0"),
+	CLK_LOOKUP("core_clk",		gsbi7_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi8_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi9_uart_clk.c, "msm_serial_hsl.1"),
+	CLK_LOOKUP("core_clk",		gsbi10_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi11_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi12_uart_clk.c, "msm_serial_hsl.0"),
+	CLK_LOOKUP("core_clk",		gsbi1_qup_clk.c,	"spi_qsd.0"),
+	CLK_LOOKUP("core_clk",		gsbi2_qup_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi3_qup_clk.c,	"qup_i2c.0"),
+	CLK_LOOKUP("core_clk",		gsbi4_qup_clk.c,	"qup_i2c.1"),
+	CLK_LOOKUP("core_clk",		gsbi5_qup_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi6_qup_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi7_qup_clk.c,	"qup_i2c.4"),
+	CLK_LOOKUP("core_clk",		gsbi8_qup_clk.c,	"qup_i2c.3"),
+	CLK_LOOKUP("core_clk",		gsbi9_qup_clk.c,	"qup_i2c.2"),
+	CLK_LOOKUP("core_clk",		gsbi10_qup_clk.c,	"spi_qsd.1"),
+	CLK_LOOKUP("core_clk",		gsbi11_qup_clk.c,	""),
+	CLK_LOOKUP("gsbi_qup_clk",	gsbi12_qup_clk.c,	"msm_dsps"),
+	CLK_LOOKUP("core_clk",		gsbi12_qup_clk.c,	"qup_i2c.5"),
+	CLK_LOOKUP("core_clk",		pdm_clk.c,		""),
+	CLK_LOOKUP("mem_clk",		pmem_clk.c,		"msm_dsps"),
+	CLK_LOOKUP("core_clk",		prng_clk.c,	"msm_rng.0"),
+	CLK_LOOKUP("core_clk",		sdc1_clk.c, "msm_sdcc.1"),
+	CLK_LOOKUP("core_clk",		sdc2_clk.c, "msm_sdcc.2"),
+	CLK_LOOKUP("core_clk",		sdc3_clk.c, "msm_sdcc.3"),
+	CLK_LOOKUP("core_clk",		sdc4_clk.c, "msm_sdcc.4"),
+	CLK_LOOKUP("core_clk",		sdc5_clk.c, "msm_sdcc.5"),
+	CLK_LOOKUP("ref_clk",		tsif_ref_clk.c,		"msm_tsif.0"),
+	CLK_LOOKUP("ref_clk",		tsif_ref_clk.c,		"msm_tsif.1"),
+	CLK_LOOKUP("core_clk",		tssc_clk.c,		""),
+	CLK_LOOKUP("alt_core_clk",	usb_hs1_xcvr_clk.c,	"msm_otg"),
+	CLK_LOOKUP("phy_clk",		usb_phy0_clk.c,		"msm_otg"),
+	CLK_LOOKUP("alt_core_clk",	usb_fs1_xcvr_clk.c,	""),
+	CLK_LOOKUP("sys_clk",		usb_fs1_sys_clk.c,	""),
+	CLK_LOOKUP("src_clk",		usb_fs1_src_clk.c,	""),
+	CLK_LOOKUP("alt_core_clk",	usb_fs2_xcvr_clk.c,	""),
+	CLK_LOOKUP("sys_clk",		usb_fs2_sys_clk.c,	""),
+	CLK_LOOKUP("src_clk",		usb_fs2_src_clk.c,	""),
+	CLK_LOOKUP("core_clk",		ce2_p_clk.c,		"qce.0"),
+	CLK_LOOKUP("core_clk",		ce2_p_clk.c,		"qcrypto.0"),
+	CLK_LOOKUP("iface_clk",		gsbi1_p_clk.c,		"spi_qsd.0"),
+	CLK_LOOKUP("iface_clk",		gsbi2_p_clk.c,		""),
+	CLK_LOOKUP("iface_clk",		gsbi3_p_clk.c, "msm_serial_hsl.2"),
+	CLK_LOOKUP("iface_clk",		gsbi3_p_clk.c,		"qup_i2c.0"),
+	CLK_LOOKUP("iface_clk",		gsbi4_p_clk.c,		"qup_i2c.1"),
+	CLK_LOOKUP("iface_clk",		gsbi5_p_clk.c,		""),
+	CLK_LOOKUP("iface_clk",		gsbi6_p_clk.c, "msm_serial_hs.0"),
+	CLK_LOOKUP("iface_clk",		gsbi7_p_clk.c,		"qup_i2c.4"),
+	CLK_LOOKUP("iface_clk",		gsbi8_p_clk.c,		"qup_i2c.3"),
+	CLK_LOOKUP("iface_clk",		gsbi9_p_clk.c, "msm_serial_hsl.1"),
+	CLK_LOOKUP("iface_clk",		gsbi9_p_clk.c,		"qup_i2c.2"),
+	CLK_LOOKUP("iface_clk",		gsbi10_p_clk.c,		"spi_qsd.1"),
+	CLK_LOOKUP("iface_clk",		gsbi11_p_clk.c,		""),
+	CLK_LOOKUP("iface_clk",		gsbi12_p_clk.c,		""),
+	CLK_LOOKUP("iface_clk",		gsbi12_p_clk.c, "msm_serial_hsl.0"),
+	CLK_LOOKUP("iface_clk",		gsbi12_p_clk.c,		"qup_i2c.5"),
+	CLK_LOOKUP("iface_clk",		ppss_p_clk.c,		"msm_dsps"),
+	CLK_LOOKUP("iface_clk",		tsif_p_clk.c,		"msm_tsif.0"),
+	CLK_LOOKUP("iface_clk",		tsif_p_clk.c,		"msm_tsif.1"),
+	CLK_LOOKUP("iface_clk",		usb_fs1_p_clk.c,	""),
+	CLK_LOOKUP("iface_clk",		usb_fs2_p_clk.c,	""),
+	CLK_LOOKUP("iface_clk",		usb_hs1_p_clk.c,	"msm_otg"),
+	CLK_LOOKUP("iface_clk",		sdc1_p_clk.c, "msm_sdcc.1"),
+	CLK_LOOKUP("iface_clk",		sdc2_p_clk.c, "msm_sdcc.2"),
+	CLK_LOOKUP("iface_clk",		sdc3_p_clk.c, "msm_sdcc.3"),
+	CLK_LOOKUP("iface_clk",		sdc4_p_clk.c, "msm_sdcc.4"),
+	CLK_LOOKUP("iface_clk",		sdc5_p_clk.c, "msm_sdcc.5"),
+	CLK_LOOKUP("mem_clk",		ebi2_2x_clk.c,		""),
+	CLK_LOOKUP("mem_clk",		ebi2_clk.c,		"msm_ebi2"),
+	CLK_LOOKUP("core_clk",		adm0_clk.c, "msm_dmov.0"),
+	CLK_LOOKUP("iface_clk",		adm0_p_clk.c, "msm_dmov.0"),
+	CLK_LOOKUP("core_clk",		adm1_clk.c, "msm_dmov.1"),
+	CLK_LOOKUP("iface_clk",		adm1_p_clk.c, "msm_dmov.1"),
+	CLK_LOOKUP("iface_clk",		modem_ahb1_p_clk.c,	""),
+	CLK_LOOKUP("iface_clk",		modem_ahb2_p_clk.c,	""),
+	CLK_LOOKUP("iface_clk",		pmic_arb0_p_clk.c,	""),
+	CLK_LOOKUP("iface_clk",		pmic_arb1_p_clk.c,	""),
+	CLK_LOOKUP("core_clk",		pmic_ssbi2_clk.c,	""),
+	CLK_LOOKUP("mem_clk",		rpm_msg_ram_p_clk.c,	""),
+	CLK_LOOKUP("cam_clk",		cam_clk.c,		NULL),
+	CLK_LOOKUP("csi_clk",		csi0_clk.c,		NULL),
+	CLK_LOOKUP("csi_clk",		csi1_clk.c, "msm_camera_ov7692.0"),
+	CLK_LOOKUP("csi_clk",		csi1_clk.c, "msm_camera_ov9726.0"),
+	CLK_LOOKUP("csi_clk",		csi1_clk.c, "msm_csic.1"),
+	CLK_LOOKUP("csi_src_clk",	csi_src_clk.c,		NULL),
+	CLK_LOOKUP("byte_clk",	dsi_byte_clk.c,		"mipi_dsi.1"),
+	CLK_LOOKUP("esc_clk",	dsi_esc_clk.c,		"mipi_dsi.1"),
+	CLK_LOOKUP("core_clk",		gfx2d0_clk.c,	"kgsl-2d0.0"),
+	CLK_LOOKUP("core_clk",		gfx2d0_clk.c,	"footswitch-8x60.0"),
+	CLK_LOOKUP("core_clk",		gfx2d1_clk.c,	"kgsl-2d1.1"),
+	CLK_LOOKUP("core_clk",		gfx2d1_clk.c,	"footswitch-8x60.1"),
+	CLK_LOOKUP("core_clk",		gfx3d_clk.c,	"kgsl-3d0.0"),
+	CLK_LOOKUP("core_clk",		gfx3d_clk.c,	"footswitch-8x60.2"),
+	CLK_LOOKUP("core_clk",		ijpeg_clk.c,	"msm_gemini.0"),
+	CLK_LOOKUP("core_clk",		ijpeg_clk.c,	"footswitch-8x60.3"),
+	CLK_LOOKUP("core_clk",		jpegd_clk.c,		NULL),
+	CLK_LOOKUP("core_clk",		mdp_clk.c,		"mdp.0"),
+	CLK_LOOKUP("core_clk",		mdp_clk.c,	"footswitch-8x60.4"),
+	CLK_LOOKUP("vsync_clk",	mdp_vsync_clk.c,		"mdp.0"),
+	CLK_LOOKUP("vsync_clk",		mdp_vsync_clk.c, "footswitch-8x60.4"),
+	CLK_LOOKUP("lcdc_clk",	pixel_lcdc_clk.c,		"lcdc.0"),
+	CLK_LOOKUP("pixel_lcdc_clk",	pixel_lcdc_clk.c, "footswitch-8x60.4"),
+	CLK_LOOKUP("mdp_clk",	pixel_mdp_clk.c,	"lcdc.0"),
+	CLK_LOOKUP("pixel_mdp_clk",	pixel_mdp_clk.c, "footswitch-8x60.4"),
+	CLK_LOOKUP("core_clk",		rot_clk.c,	"msm_rotator.0"),
+	CLK_LOOKUP("core_clk",		rot_clk.c,	"footswitch-8x60.6"),
+	CLK_LOOKUP("tv_enc_clk",	tv_enc_clk.c,		NULL),
+	CLK_LOOKUP("tv_dac_clk",	tv_dac_clk.c,		NULL),
+	CLK_LOOKUP("core_clk",		vcodec_clk.c,	"msm_vidc.0"),
+	CLK_LOOKUP("core_clk",		vcodec_clk.c,	"footswitch-8x60.7"),
+	CLK_LOOKUP("mdp_clk",	mdp_tv_clk.c,		"dtv.0"),
+	CLK_LOOKUP("tv_clk",		mdp_tv_clk.c,	"footswitch-8x60.4"),
+	CLK_LOOKUP("hdmi_clk",		hdmi_tv_clk.c,	"dtv.0"),
+	CLK_LOOKUP("src_clk",	tv_src_clk.c,	"dtv.0"),
+	CLK_LOOKUP("tv_src_clk",	tv_src_clk.c,	"footswitch-8x60.4"),
+	CLK_LOOKUP("core_clk",		hdmi_app_clk.c,	"hdmi_msm.1"),
+	CLK_LOOKUP("vpe_clk",		vpe_clk.c,		NULL),
+	CLK_LOOKUP("core_clk",		vpe_clk.c,	"footswitch-8x60.9"),
+	CLK_LOOKUP("csi_vfe_clk",	csi0_vfe_clk.c,		NULL),
+	CLK_LOOKUP("csi_vfe_clk",	csi1_vfe_clk.c, "msm_camera_ov7692.0"),
+	CLK_LOOKUP("csi_vfe_clk",	csi1_vfe_clk.c, "msm_camera_ov9726.0"),
+	CLK_LOOKUP("csi_vfe_clk",	csi1_vfe_clk.c, "msm_csic.1"),
+	CLK_LOOKUP("vfe_clk",		vfe_clk.c,		NULL),
+	CLK_LOOKUP("core_clk",		vfe_clk.c,	"footswitch-8x60.8"),
+	CLK_LOOKUP("bus_clk",		vfe_axi_clk.c,	"footswitch-8x60.8"),
+	CLK_LOOKUP("bus_clk",		ijpeg_axi_clk.c, "footswitch-8x60.3"),
+	CLK_LOOKUP("mem_clk",		imem_axi_clk.c,	"kgsl-3d0.0"),
+	CLK_LOOKUP("bus_clk",		mdp_axi_clk.c,	 "footswitch-8x60.4"),
+	CLK_LOOKUP("bus_clk",		rot_axi_clk.c,	 "footswitch-8x60.6"),
+	CLK_LOOKUP("bus_clk",		vcodec_axi_clk.c, "footswitch-8x60.7"),
+	CLK_LOOKUP("bus_clk",		vpe_axi_clk.c,	 "footswitch-8x60.9"),
+	CLK_LOOKUP("arb_clk",		amp_p_clk.c,		"mipi_dsi.1"),
+	CLK_LOOKUP("csi_pclk",		csi0_p_clk.c,		NULL),
+	CLK_LOOKUP("csi_pclk",		csi1_p_clk.c, "msm_camera_ov7692.0"),
+	CLK_LOOKUP("csi_pclk",		csi1_p_clk.c, "msm_camera_ov9726.0"),
+	CLK_LOOKUP("csi_pclk",		csi1_p_clk.c,		"msm_csic.1"),
+	CLK_LOOKUP("master_iface_clk",	dsi_m_p_clk.c,		"mipi_dsi.1"),
+	CLK_LOOKUP("slave_iface_clk",	dsi_s_p_clk.c,		"mipi_dsi.1"),
+	CLK_LOOKUP("iface_clk",		gfx2d0_p_clk.c,	"kgsl-2d0.0"),
+	CLK_LOOKUP("iface_clk",		gfx2d0_p_clk.c,	"footswitch-8x60.0"),
+	CLK_LOOKUP("iface_clk",		gfx2d1_p_clk.c,	"kgsl-2d1.1"),
+	CLK_LOOKUP("iface_clk",		gfx2d1_p_clk.c,	"footswitch-8x60.1"),
+	CLK_LOOKUP("iface_clk",		gfx3d_p_clk.c,	"kgsl-3d0.0"),
+	CLK_LOOKUP("iface_clk",		gfx3d_p_clk.c,	"footswitch-8x60.2"),
+	CLK_LOOKUP("master_iface_clk",	hdmi_m_p_clk.c,	"hdmi_msm.1"),
+	CLK_LOOKUP("slave_iface_clk",	hdmi_s_p_clk.c,	"hdmi_msm.1"),
+	CLK_LOOKUP("iface_clk",		ijpeg_p_clk.c,	"msm_gemini.0"),
+	CLK_LOOKUP("iface_clk",		ijpeg_p_clk.c,	"footswitch-8x60.3"),
+	CLK_LOOKUP("iface_clk",		jpegd_p_clk.c,		NULL),
+	CLK_LOOKUP("mem_iface_clk",	imem_p_clk.c,	"kgsl-3d0.0"),
+	CLK_LOOKUP("iface_clk",		mdp_p_clk.c,		"mdp.0"),
+	CLK_LOOKUP("iface_clk",		mdp_p_clk.c,	"footswitch-8x60.4"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu"),
+	CLK_LOOKUP("iface_clk",		rot_p_clk.c,	"msm_rotator.0"),
+	CLK_LOOKUP("iface_clk",		rot_p_clk.c,	"footswitch-8x60.6"),
+	CLK_LOOKUP("tv_enc_pclk",	tv_enc_p_clk.c,		NULL),
+	CLK_LOOKUP("iface_clk",		vcodec_p_clk.c,	"msm_vidc.0"),
+	CLK_LOOKUP("iface_clk",		vcodec_p_clk.c, "footswitch-8x60.7"),
+	CLK_LOOKUP("vfe_pclk",		vfe_p_clk.c,		NULL),
+	CLK_LOOKUP("iface_clk",		vfe_p_clk.c,	"footswitch-8x60.8"),
+	CLK_LOOKUP("vpe_pclk",		vpe_p_clk.c,		NULL),
+	CLK_LOOKUP("iface_clk",		vpe_p_clk.c,	"footswitch-8x60.9"),
+	CLK_LOOKUP("mi2s_osr_clk",	mi2s_osr_clk.c,		NULL),
+	CLK_LOOKUP("mi2s_bit_clk",	mi2s_bit_clk.c,		NULL),
+	CLK_LOOKUP("i2s_mic_osr_clk",	codec_i2s_mic_osr_clk.c,	NULL),
+	CLK_LOOKUP("i2s_mic_bit_clk",	codec_i2s_mic_bit_clk.c,	NULL),
+	CLK_LOOKUP("i2s_mic_osr_clk",	spare_i2s_mic_osr_clk.c,	NULL),
+	CLK_LOOKUP("i2s_mic_bit_clk",	spare_i2s_mic_bit_clk.c,	NULL),
+	CLK_LOOKUP("i2s_spkr_osr_clk",	codec_i2s_spkr_osr_clk.c,	NULL),
+	CLK_LOOKUP("i2s_spkr_bit_clk",	codec_i2s_spkr_bit_clk.c,	NULL),
+	CLK_LOOKUP("i2s_spkr_osr_clk",	spare_i2s_spkr_osr_clk.c,	NULL),
+	CLK_LOOKUP("i2s_spkr_bit_clk",	spare_i2s_spkr_bit_clk.c,	NULL),
+	CLK_LOOKUP("pcm_clk",		pcm_clk.c,		NULL),
+	CLK_LOOKUP("core_clk",		jpegd_axi_clk.c,	"msm_iommu.0"),
+	CLK_LOOKUP("core_clk",		vpe_axi_clk.c,		"msm_iommu.1"),
+	CLK_LOOKUP("core_clk",		mdp_axi_clk.c,		"msm_iommu.2"),
+	CLK_LOOKUP("core_clk",		mdp_axi_clk.c,		"msm_iommu.3"),
+	CLK_LOOKUP("core_clk",		rot_axi_clk.c,		"msm_iommu.4"),
+	CLK_LOOKUP("core_clk",		ijpeg_axi_clk.c,	"msm_iommu.5"),
+	CLK_LOOKUP("core_clk",		vfe_axi_clk.c,		"msm_iommu.6"),
+	CLK_LOOKUP("core_clk",		vcodec_axi_clk.c,	"msm_iommu.7"),
+	CLK_LOOKUP("core_clk",		vcodec_axi_clk.c,	"msm_iommu.8"),
+	CLK_LOOKUP("core_clk",		gfx3d_clk.c,		"msm_iommu.9"),
+	CLK_LOOKUP("core_clk",		gfx2d0_clk.c,		"msm_iommu.10"),
+	CLK_LOOKUP("core_clk",		gfx2d1_clk.c,		"msm_iommu.11"),
+
+	CLK_LOOKUP("mdp_iommu_clk", mdp_axi_clk.c,	"msm_vidc.0"),
+	CLK_LOOKUP("rot_iommu_clk",	rot_axi_clk.c,	"msm_vidc.0"),
+	CLK_LOOKUP("vcodec_iommu0_clk", vcodec_axi_clk.c, "msm_vidc.0"),
+	CLK_LOOKUP("vcodec_iommu1_clk", vcodec_axi_clk.c, "msm_vidc.0"),
+	CLK_LOOKUP("smmu_iface_clk", smmu_p_clk.c,	"msm_vidc.0"),
+
+	CLK_LOOKUP("dfab_dsps_clk",	dfab_dsps_clk.c, NULL),
+	CLK_LOOKUP("core_clk",		dfab_usb_hs_clk.c,	"msm_otg"),
+	CLK_LOOKUP("bus_clk",		dfab_sdc1_clk.c, "msm_sdcc.1"),
+	CLK_LOOKUP("bus_clk",		dfab_sdc2_clk.c, "msm_sdcc.2"),
+	CLK_LOOKUP("bus_clk",		dfab_sdc3_clk.c, "msm_sdcc.3"),
+	CLK_LOOKUP("bus_clk",		dfab_sdc4_clk.c, "msm_sdcc.4"),
+	CLK_LOOKUP("bus_clk",		dfab_sdc5_clk.c, "msm_sdcc.5"),
+	CLK_LOOKUP("bus_clk",		dfab_scm_clk.c,	"scm"),
+	CLK_LOOKUP("bus_clk",		dfab_qseecom_clk.c,	"qseecom"),
+
+	CLK_LOOKUP("mem_clk",		ebi1_adm0_clk.c, "msm_dmov.0"),
+	CLK_LOOKUP("mem_clk",		ebi1_adm1_clk.c, "msm_dmov.1"),
+
+	CLK_LOOKUP("sc0_mclk",		sc0_m_clk, ""),
+	CLK_LOOKUP("sc1_mclk",		sc1_m_clk, ""),
+	CLK_LOOKUP("l2_mclk",		l2_m_clk,  ""),
+};
+
+/*
+ * Miscellaneous clock register initializations
+ */
+
+/* Read, modify, then write-back a register. */
+static void __init rmwreg(uint32_t val, void *reg, uint32_t mask)
+{
+	uint32_t regval = readl_relaxed(reg);
+	regval &= ~mask;
+	regval |= val;
+	writel_relaxed(regval, reg);
+}
+
+static void __init msm8660_clock_pre_init(void)
+{
+	vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
+
+	/* Setup MM_PLL2 (PLL3), but turn it off. Rate set by set_rate_tv(). */
+	rmwreg(0, MM_PLL2_MODE_REG, BIT(0)); /* Disable output */
+	/* Set ref, bypass, assert reset, disable output, disable test mode */
+	writel_relaxed(0, MM_PLL2_MODE_REG); /* PXO */
+	writel_relaxed(0x00800000, MM_PLL2_CONFIG_REG); /* Enable main out. */
+
+	/* The clock driver doesn't use SC1's voting register to control
+	 * HW-voteable clocks.  Clear its bits so that disabling bits in the
+	 * SC0 register will cause the corresponding clocks to be disabled. */
+	rmwreg(BIT(12)|BIT(11), SC0_U_CLK_BRANCH_ENA_VOTE_REG, BM(12, 11));
+	writel_relaxed(BIT(12)|BIT(11), SC1_U_CLK_BRANCH_ENA_VOTE_REG);
+	/* Let sc_aclk and sc_clk halt when both Scorpions are collapsed. */
+	writel_relaxed(BIT(12)|BIT(11), SC0_U_CLK_SLEEP_ENA_VOTE_REG);
+	writel_relaxed(BIT(12)|BIT(11), SC1_U_CLK_SLEEP_ENA_VOTE_REG);
+
+	/* Deassert MM SW_RESET_ALL signal. */
+	writel_relaxed(0, SW_RESET_ALL_REG);
+
+	/* Initialize MM AHB registers: Enable the FPB clock and disable HW
+	 * gating for all clocks. Also set VFE_AHB's FORCE_CORE_ON bit to
+	 * prevent its memory from being collapsed when the clock is halted.
+	 * The sleep and wake-up delays are set to safe values. */
+	rmwreg(0x00000003, AHB_EN_REG,  0x6C000003);
+	writel_relaxed(0x000007F9, AHB_EN2_REG);
+
+	/* Deassert all locally-owned MM AHB resets. */
+	rmwreg(0, SW_RESET_AHB_REG, 0xFFF7DFFF);
+
+	/* Initialize MM AXI registers: Enable HW gating for all clocks that
+	 * support it. Also set FORCE_CORE_ON bits, and any sleep and wake-up
+	 * delays to safe values. */
+	rmwreg(0x100207F9, MAXI_EN_REG,  0x1803FFFF);
+	rmwreg(0x7027FCFF, MAXI_EN2_REG, 0x7A3FFFFF);
+	writel_relaxed(0x3FE7FCFF, MAXI_EN3_REG);
+	writel_relaxed(0x000001D8, SAXI_EN_REG);
+
+	/* Initialize MM CC registers: Set MM FORCE_CORE_ON bits so that core
+	 * memories retain state even when not clocked. Also, set sleep and
+	 * wake-up delays to safe values. */
+	rmwreg(0x00000000, CSI_CC_REG,    0x00000018);
+	rmwreg(0x00000400, MISC_CC_REG,   0x017C0400);
+	rmwreg(0x000007FD, MISC_CC2_REG,  0x70C2E7FF);
+	rmwreg(0x80FF0000, GFX2D0_CC_REG, 0xE0FF0010);
+	rmwreg(0x80FF0000, GFX2D1_CC_REG, 0xE0FF0010);
+	rmwreg(0x80FF0000, GFX3D_CC_REG,  0xE0FF0010);
+	rmwreg(0x80FF0000, IJPEG_CC_REG,  0xE0FF0018);
+	rmwreg(0x80FF0000, JPEGD_CC_REG,  0xE0FF0018);
+	rmwreg(0x80FF0000, MDP_CC_REG,    0xE1FF0010);
+	rmwreg(0x80FF0000, PIXEL_CC_REG,  0xE1FF0010);
+	rmwreg(0x000004FF, PIXEL_CC2_REG, 0x000007FF);
+	rmwreg(0x80FF0000, ROT_CC_REG,    0xE0FF0010);
+	rmwreg(0x80FF0000, TV_CC_REG,     0xE1FFC010);
+	rmwreg(0x000004FF, TV_CC2_REG,    0x000027FF);
+	rmwreg(0xC0FF0000, VCODEC_CC_REG, 0xE0FF0010);
+	rmwreg(0x80FF0000, VFE_CC_REG,    0xE0FFC010);
+	rmwreg(0x80FF0000, VPE_CC_REG,    0xE0FF0010);
+
+	/* De-assert MM AXI resets to all hardware blocks. */
+	writel_relaxed(0, SW_RESET_AXI_REG);
+
+	/* Deassert all MM core resets. */
+	writel_relaxed(0, SW_RESET_CORE_REG);
+
+	/* Enable TSSC and PDM PXO sources. */
+	writel_relaxed(BIT(11), TSSC_CLK_CTL_REG);
+	writel_relaxed(BIT(15), PDM_CLK_NS_REG);
+	/* Set the dsi_byte_clk src to the DSI PHY PLL,
+	 * dsi_esc_clk to PXO/2, and the hdmi_app_clk src to PXO */
+	rmwreg(0x400001, MISC_CC2_REG, 0x424003);
+
+	if ((readl_relaxed(PRNG_CLK_NS_REG) & 0x7F) == 0x2B)
+		prng_clk.freq_tbl = clk_tbl_prng_64;
+}
+
+static void __init msm8660_clock_post_init(void)
+{
+	/* Keep PXO on whenever APPS cpu is active */
+	clk_prepare_enable(&pxo_a_clk.c);
+
+	/* Reset 3D core while clocked to ensure it resets completely. */
+	clk_set_rate(&gfx3d_clk.c, 27000000);
+	clk_prepare_enable(&gfx3d_clk.c);
+	clk_reset(&gfx3d_clk.c, CLK_RESET_ASSERT);
+	udelay(5);
+	clk_reset(&gfx3d_clk.c, CLK_RESET_DEASSERT);
+	clk_disable_unprepare(&gfx3d_clk.c);
+
+	/* Initialize rates for clocks that only support one. */
+	clk_set_rate(&pdm_clk.c, 27000000);
+	clk_set_rate(&prng_clk.c, prng_clk.freq_tbl->freq_hz);
+	clk_set_rate(&mdp_vsync_clk.c, 27000000);
+	clk_set_rate(&tsif_ref_clk.c, 105000);
+	clk_set_rate(&tssc_clk.c, 27000000);
+	clk_set_rate(&usb_hs1_xcvr_clk.c, 60000000);
+	clk_set_rate(&usb_fs1_src_clk.c, 60000000);
+	clk_set_rate(&usb_fs2_src_clk.c, 60000000);
+
+	/* The halt status bits for PDM and TSSC may be incorrect at boot.
+	 * Toggle these clocks on and off to refresh them. */
+	clk_prepare_enable(&pdm_clk.c);
+	clk_disable_unprepare(&pdm_clk.c);
+	clk_prepare_enable(&tssc_clk.c);
+	clk_disable_unprepare(&tssc_clk.c);
+}
+
+static int __init msm8660_clock_late_init(void)
+{
+	int rc;
+
+	/* Vote for MMFPB to be at least 64MHz when an Apps CPU is active. */
+	struct clk *mmfpb_a_clk = clk_get(NULL, "mmfpb_a_clk");
+	if (WARN(IS_ERR(mmfpb_a_clk), "mmfpb_a_clk not found (%ld)\n",
+			PTR_ERR(mmfpb_a_clk)))
+		return PTR_ERR(mmfpb_a_clk);
+	rc = clk_set_rate(mmfpb_a_clk, 64000000);
+	if (WARN(rc, "mmfpb_a_clk rate was not set (%d)\n", rc))
+		return rc;
+	rc = clk_prepare_enable(mmfpb_a_clk);
+	if (WARN(rc, "mmfpb_a_clk not enabled (%d)\n", rc))
+		return rc;
+
+	return unvote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
+}
+
+struct clock_init_data msm8x60_clock_init_data __initdata = {
+	.table = msm_clocks_8x60,
+	.size = ARRAY_SIZE(msm_clocks_8x60),
+	.pre_init = msm8660_clock_pre_init,
+	.post_init = msm8660_clock_post_init,
+	.late_init = msm8660_clock_late_init,
+};
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
new file mode 100644
index 0000000..66d849a
--- /dev/null
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -0,0 +1,1837 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+
+#include <asm/mach-types.h>
+
+#include <mach/msm_iomap.h>
+#include <mach/clk.h>
+#include <mach/rpm-9615.h>
+#include <mach/rpm-regulator.h>
+
+#include "clock-local.h"
+#include "clock-voter.h"
+#include "clock-rpm.h"
+#include "devices.h"
+#include "clock-pll.h"
+
+#define REG(off)	(MSM_CLK_CTL_BASE + (off))
+#define REG_LPA(off)	(MSM_LPASS_CLK_CTL_BASE + (off))
+#define REG_GCC(off)	(MSM_APCS_GCC_BASE + (off))
+
+/* Peripheral clock registers. */
+#define CE1_HCLK_CTL_REG			REG(0x2720)
+#define CE1_CORE_CLK_CTL_REG			REG(0x2724)
+#define DMA_BAM_HCLK_CTL			REG(0x25C0)
+#define CLK_HALT_CFPB_STATEA_REG		REG(0x2FCC)
+#define CLK_HALT_CFPB_STATEB_REG		REG(0x2FD0)
+#define CLK_HALT_CFPB_STATEC_REG		REG(0x2FD4)
+#define CLK_HALT_DFAB_STATE_REG			REG(0x2FC8)
+
+#define CLK_HALT_MSS_KPSS_MISC_STATE_REG	REG(0x2FDC)
+#define CLK_HALT_SFPB_MISC_STATE_REG		REG(0x2FD8)
+#define CLK_TEST_REG				REG(0x2FA0)
+#define GPn_MD_REG(n)				REG(0x2D00+(0x20*(n)))
+#define GPn_NS_REG(n)				REG(0x2D24+(0x20*(n)))
+#define GSBIn_HCLK_CTL_REG(n)			REG(0x29C0+(0x20*((n)-1)))
+#define GSBIn_QUP_APPS_MD_REG(n)		REG(0x29C8+(0x20*((n)-1)))
+#define GSBIn_QUP_APPS_NS_REG(n)		REG(0x29CC+(0x20*((n)-1)))
+#define GSBIn_RESET_REG(n)			REG(0x29DC+(0x20*((n)-1)))
+#define GSBIn_UART_APPS_MD_REG(n)		REG(0x29D0+(0x20*((n)-1)))
+#define GSBIn_UART_APPS_NS_REG(n)		REG(0x29D4+(0x20*((n)-1)))
+#define PDM_CLK_NS_REG				REG(0x2CC0)
+#define BB_PLL_ENA_SC0_REG			REG(0x34C0)
+
+#define BB_PLL0_L_VAL_REG			REG(0x30C4)
+#define BB_PLL0_M_VAL_REG			REG(0x30C8)
+#define BB_PLL0_MODE_REG			REG(0x30C0)
+#define BB_PLL0_N_VAL_REG			REG(0x30CC)
+#define BB_PLL0_STATUS_REG			REG(0x30D8)
+#define BB_PLL0_CONFIG_REG			REG(0x30D4)
+#define BB_PLL0_TEST_CTL_REG			REG(0x30D0)
+
+#define BB_PLL8_L_VAL_REG			REG(0x3144)
+#define BB_PLL8_M_VAL_REG			REG(0x3148)
+#define BB_PLL8_MODE_REG			REG(0x3140)
+#define BB_PLL8_N_VAL_REG			REG(0x314C)
+#define BB_PLL8_STATUS_REG			REG(0x3158)
+#define BB_PLL8_CONFIG_REG			REG(0x3154)
+#define BB_PLL8_TEST_CTL_REG			REG(0x3150)
+
+#define BB_PLL14_L_VAL_REG			REG(0x31C4)
+#define BB_PLL14_M_VAL_REG			REG(0x31C8)
+#define BB_PLL14_MODE_REG			REG(0x31C0)
+#define BB_PLL14_N_VAL_REG			REG(0x31CC)
+#define BB_PLL14_STATUS_REG			REG(0x31D8)
+#define BB_PLL14_CONFIG_REG			REG(0x31D4)
+#define BB_PLL14_TEST_CTL_REG			REG(0x31D0)
+
+#define SC_PLL0_L_VAL_REG			REG(0x3208)
+#define SC_PLL0_M_VAL_REG			REG(0x320C)
+#define SC_PLL0_MODE_REG			REG(0x3200)
+#define SC_PLL0_N_VAL_REG			REG(0x3210)
+#define SC_PLL0_STATUS_REG			REG(0x321C)
+#define SC_PLL0_CONFIG_REG			REG(0x3204)
+#define SC_PLL0_TEST_CTL_REG			REG(0x3218)
+
+#define PLLTEST_PAD_CFG_REG			REG(0x2FA4)
+#define PMEM_ACLK_CTL_REG			REG(0x25A0)
+#define RINGOSC_NS_REG				REG(0x2DC0)
+#define RINGOSC_STATUS_REG			REG(0x2DCC)
+#define RINGOSC_TCXO_CTL_REG			REG(0x2DC4)
+#define SC0_U_CLK_BRANCH_ENA_VOTE_REG		REG(0x3080)
+#define SDCn_APPS_CLK_MD_REG(n)			REG(0x2828+(0x20*((n)-1)))
+#define SDCn_APPS_CLK_NS_REG(n)			REG(0x282C+(0x20*((n)-1)))
+#define SDCn_HCLK_CTL_REG(n)			REG(0x2820+(0x20*((n)-1)))
+#define SDCn_RESET_REG(n)			REG(0x2830+(0x20*((n)-1)))
+#define USB_HS1_HCLK_CTL_REG			REG(0x2900)
+#define USB_HS1_RESET_REG			REG(0x2910)
+#define USB_HS1_XCVR_FS_CLK_MD_REG		REG(0x2908)
+#define USB_HS1_XCVR_FS_CLK_NS_REG		REG(0x290C)
+#define USB_HS1_SYS_CLK_MD_REG			REG(0x36A0)
+#define USB_HS1_SYS_CLK_NS_REG			REG(0x36A4)
+#define USB_HSIC_HCLK_CTL_REG			REG(0x2920)
+#define USB_HSIC_XCVR_FS_CLK_MD_REG		REG(0x2924)
+#define USB_HSIC_XCVR_FS_CLK_NS_REG		REG(0x2928)
+#define USB_HSIC_RESET_REG			REG(0x2934)
+#define USB_HSIC_HSIO_CAL_CLK_CTL_REG		REG(0x2B48)
+#define USB_HSIC_CLK_MD_REG			REG(0x2B4C)
+#define USB_HSIC_CLK_NS_REG			REG(0x2B50)
+#define USB_HSIC_SYSTEM_CLK_MD_REG		REG(0x2B54)
+#define USB_HSIC_SYSTEM_CLK_NS_REG		REG(0x2B58)
+#define SLIMBUS_XO_SRC_CLK_CTL_REG		REG(0x2628)
+
+/* Low-power Audio clock registers. */
+#define LCC_CLK_HS_DEBUG_CFG_REG		REG_LPA(0x00A4)
+#define LCC_CLK_LS_DEBUG_CFG_REG		REG_LPA(0x00A8)
+#define LCC_CODEC_I2S_MIC_MD_REG		REG_LPA(0x0064)
+#define LCC_CODEC_I2S_MIC_NS_REG		REG_LPA(0x0060)
+#define LCC_CODEC_I2S_MIC_STATUS_REG		REG_LPA(0x0068)
+#define LCC_CODEC_I2S_SPKR_MD_REG		REG_LPA(0x0070)
+#define LCC_CODEC_I2S_SPKR_NS_REG		REG_LPA(0x006C)
+#define LCC_CODEC_I2S_SPKR_STATUS_REG		REG_LPA(0x0074)
+#define LCC_MI2S_MD_REG				REG_LPA(0x004C)
+#define LCC_MI2S_NS_REG				REG_LPA(0x0048)
+#define LCC_MI2S_STATUS_REG			REG_LPA(0x0050)
+#define LCC_PCM_MD_REG				REG_LPA(0x0058)
+#define LCC_PCM_NS_REG				REG_LPA(0x0054)
+#define LCC_PCM_STATUS_REG			REG_LPA(0x005C)
+#define LCC_PLL0_STATUS_REG			REG_LPA(0x0018)
+#define LCC_SPARE_I2S_MIC_MD_REG		REG_LPA(0x007C)
+#define LCC_SPARE_I2S_MIC_NS_REG		REG_LPA(0x0078)
+#define LCC_SPARE_I2S_MIC_STATUS_REG		REG_LPA(0x0080)
+#define LCC_SPARE_I2S_SPKR_MD_REG		REG_LPA(0x0088)
+#define LCC_SPARE_I2S_SPKR_NS_REG		REG_LPA(0x0084)
+#define LCC_SPARE_I2S_SPKR_STATUS_REG		REG_LPA(0x008C)
+#define LCC_SLIMBUS_NS_REG			REG_LPA(0x00CC)
+#define LCC_SLIMBUS_MD_REG			REG_LPA(0x00D0)
+#define LCC_SLIMBUS_STATUS_REG			REG_LPA(0x00D4)
+#define LCC_AHBEX_BRANCH_CTL_REG		REG_LPA(0x00E4)
+#define LCC_PRI_PLL_CLK_CTL_REG			REG_LPA(0x00C4)
+
+#define GCC_APCS_CLK_DIAG			REG_GCC(0x001C)
+
+/* MUX source input identifiers. */
+#define cxo_to_bb_mux		0
+#define pll8_to_bb_mux		3
+#define pll8_acpu_to_bb_mux	3
+#define pll14_to_bb_mux		4
+#define gnd_to_bb_mux		6
+#define cxo_to_xo_mux		0
+#define gnd_to_xo_mux		3
+#define cxo_to_lpa_mux		1
+#define pll4_to_lpa_mux		2
+#define gnd_to_lpa_mux		6
+
+/* Test Vector Macros */
+#define TEST_TYPE_PER_LS	1
+#define TEST_TYPE_PER_HS	2
+#define TEST_TYPE_LPA		5
+#define TEST_TYPE_LPA_HS	6
+#define TEST_TYPE_SHIFT		24
+#define TEST_CLK_SEL_MASK	BM(23, 0)
+#define TEST_VECTOR(s, t)	(((t) << TEST_TYPE_SHIFT) | BVAL(23, 0, (s)))
+#define TEST_PER_LS(s)		TEST_VECTOR((s), TEST_TYPE_PER_LS)
+#define TEST_PER_HS(s)		TEST_VECTOR((s), TEST_TYPE_PER_HS)
+#define TEST_LPA(s)		TEST_VECTOR((s), TEST_TYPE_LPA)
+#define TEST_LPA_HS(s)		TEST_VECTOR((s), TEST_TYPE_LPA_HS)
+
+enum vdd_dig_levels {
+	VDD_DIG_NONE,
+	VDD_DIG_LOW,
+	VDD_DIG_NOMINAL,
+	VDD_DIG_HIGH
+};
+
+static int set_vdd_dig(struct clk_vdd_class *vdd_class, int level)
+{
+	static const int vdd_uv[] = {
+		[VDD_DIG_NONE]    =       0,
+		[VDD_DIG_LOW]     =  945000,
+		[VDD_DIG_NOMINAL] = 1050000,
+		[VDD_DIG_HIGH]    = 1150000
+	};
+
+	return rpm_vreg_set_voltage(RPM_VREG_ID_PM8018_S1, RPM_VREG_VOTER3,
+				    vdd_uv[level], vdd_uv[VDD_DIG_HIGH], 1);
+}
+
+static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig);
+
+#define VDD_DIG_FMAX_MAP1(l1, f1) \
+	.vdd_class = &vdd_dig, \
+	.fmax[VDD_DIG_##l1] = (f1)
+#define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
+	.vdd_class = &vdd_dig, \
+	.fmax[VDD_DIG_##l1] = (f1), \
+	.fmax[VDD_DIG_##l2] = (f2)
+
+/*
+ * Clock Descriptions
+ */
+
+DEFINE_CLK_RPM_BRANCH(cxo_clk, cxo_a_clk, CXO, 19200000);
+
+static DEFINE_SPINLOCK(soft_vote_lock);
+
+static int pll_acpu_vote_clk_enable(struct clk *clk)
+{
+	int ret = 0;
+	unsigned long flags;
+	struct pll_vote_clk *pll = to_pll_vote_clk(clk);
+
+	spin_lock_irqsave(&soft_vote_lock, flags);
+
+	if (!*pll->soft_vote)
+		ret = pll_vote_clk_enable(clk);
+	if (ret == 0)
+		*pll->soft_vote |= (pll->soft_vote_mask);
+
+	spin_unlock_irqrestore(&soft_vote_lock, flags);
+	return ret;
+}
+
+static void pll_acpu_vote_clk_disable(struct clk *clk)
+{
+	unsigned long flags;
+	struct pll_vote_clk *pll = to_pll_vote_clk(clk);
+
+	spin_lock_irqsave(&soft_vote_lock, flags);
+
+	*pll->soft_vote &= ~(pll->soft_vote_mask);
+	if (!*pll->soft_vote)
+		pll_vote_clk_disable(clk);
+
+	spin_unlock_irqrestore(&soft_vote_lock, flags);
+}
+
+static struct clk_ops clk_ops_pll_acpu_vote = {
+	.enable = pll_acpu_vote_clk_enable,
+	.disable = pll_acpu_vote_clk_disable,
+	.auto_off = pll_acpu_vote_clk_disable,
+	.is_enabled = pll_vote_clk_is_enabled,
+	.get_parent = pll_vote_clk_get_parent,
+};
+
+#define PLL_SOFT_VOTE_PRIMARY	BIT(0)
+#define PLL_SOFT_VOTE_ACPU	BIT(1)
+
+static unsigned int soft_vote_pll0;
+
+static struct pll_vote_clk pll0_clk = {
+	.en_reg = BB_PLL_ENA_SC0_REG,
+	.en_mask = BIT(0),
+	.status_reg = BB_PLL0_STATUS_REG,
+	.status_mask = BIT(16),
+	.parent = &cxo_clk.c,
+	.soft_vote = &soft_vote_pll0,
+	.soft_vote_mask = PLL_SOFT_VOTE_PRIMARY,
+	.c = {
+		.dbg_name = "pll0_clk",
+		.rate = 276000000,
+		.ops = &clk_ops_pll_acpu_vote,
+		CLK_INIT(pll0_clk.c),
+		.warned = true,
+	},
+};
+
+static struct pll_vote_clk pll0_acpu_clk = {
+	.en_reg = BB_PLL_ENA_SC0_REG,
+	.en_mask = BIT(0),
+	.status_reg = BB_PLL0_STATUS_REG,
+	.status_mask = BIT(16),
+	.soft_vote = &soft_vote_pll0,
+	.soft_vote_mask = PLL_SOFT_VOTE_ACPU,
+	.c = {
+		.dbg_name = "pll0_acpu_clk",
+		.rate = 276000000,
+		.ops = &clk_ops_pll_acpu_vote,
+		CLK_INIT(pll0_acpu_clk.c),
+		.warned = true,
+	},
+};
+
+static struct pll_vote_clk pll4_clk = {
+	.en_reg = BB_PLL_ENA_SC0_REG,
+	.en_mask = BIT(4),
+	.status_reg = LCC_PLL0_STATUS_REG,
+	.status_mask = BIT(16),
+	.parent = &cxo_clk.c,
+	.c = {
+		.dbg_name = "pll4_clk",
+		.rate = 393216000,
+		.ops = &clk_ops_pll_vote,
+		CLK_INIT(pll4_clk.c),
+		.warned = true,
+	},
+};
+
+static unsigned int soft_vote_pll8;
+
+static struct pll_vote_clk pll8_clk = {
+	.en_reg = BB_PLL_ENA_SC0_REG,
+	.en_mask = BIT(8),
+	.status_reg = BB_PLL8_STATUS_REG,
+	.status_mask = BIT(16),
+	.parent = &cxo_clk.c,
+	.soft_vote = &soft_vote_pll8,
+	.soft_vote_mask = PLL_SOFT_VOTE_PRIMARY,
+	.c = {
+		.dbg_name = "pll8_clk",
+		.rate = 384000000,
+		.ops = &clk_ops_pll_acpu_vote,
+		CLK_INIT(pll8_clk.c),
+		.warned = true,
+	},
+};
+
+static struct pll_vote_clk pll8_acpu_clk = {
+	.en_reg = BB_PLL_ENA_SC0_REG,
+	.en_mask = BIT(8),
+	.status_reg = BB_PLL8_STATUS_REG,
+	.status_mask = BIT(16),
+	.soft_vote = &soft_vote_pll8,
+	.soft_vote_mask = PLL_SOFT_VOTE_ACPU,
+	.c = {
+		.dbg_name = "pll8_acpu_clk",
+		.rate = 384000000,
+		.ops = &clk_ops_pll_acpu_vote,
+		CLK_INIT(pll8_acpu_clk.c),
+		.warned = true,
+	},
+};
+
+static struct pll_clk pll9_acpu_clk = {
+	.mode_reg = SC_PLL0_MODE_REG,
+	.c = {
+		.dbg_name = "pll9_acpu_clk",
+		.rate = 440000000,
+		.ops = &clk_ops_local_pll,
+		CLK_INIT(pll9_acpu_clk.c),
+		.warned = true,
+	},
+};
+
+static struct pll_vote_clk pll14_clk = {
+	.en_reg = BB_PLL_ENA_SC0_REG,
+	.en_mask = BIT(11),
+	.status_reg = BB_PLL14_STATUS_REG,
+	.status_mask = BIT(16),
+	.parent = &cxo_clk.c,
+	.c = {
+		.dbg_name = "pll14_clk",
+		.rate = 480000000,
+		.ops = &clk_ops_pll_vote,
+		CLK_INIT(pll14_clk.c),
+		.warned = true,
+	},
+};
+
+/*
+ * Peripheral Clocks
+ */
+#define CLK_GP(i, n, h_r, h_b) \
+	struct rcg_clk i##_clk = { \
+		.b = { \
+			.ctl_reg = GPn_NS_REG(n), \
+			.en_mask = BIT(9), \
+			.halt_reg = h_r, \
+			.halt_bit = h_b, \
+		}, \
+		.ns_reg = GPn_NS_REG(n), \
+		.md_reg = GPn_MD_REG(n), \
+		.root_en_mask = BIT(11), \
+		.ns_mask = (BM(23, 16) | BM(6, 0)), \
+		.mnd_en_mask = BIT(8), \
+		.set_rate = set_rate_mnd, \
+		.freq_tbl = clk_tbl_gp, \
+		.current_freq = &rcg_dummy_freq, \
+		.c = { \
+			.dbg_name = #i "_clk", \
+			.ops = &clk_ops_rcg, \
+			VDD_DIG_FMAX_MAP1(LOW, 27000000), \
+			CLK_INIT(i##_clk.c), \
+		}, \
+	}
+#define F_GP(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD8(16, m, 0, n), \
+		.ns_val = NS(23, 16, n, m, 5, 4, 3, d, 2, 0, s##_to_bb_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_gp[] = {
+	F_GP(        0, gnd,  1, 0, 0),
+	F_GP(  9600000, cxo,  2, 0, 0),
+	F_GP( 19200000, cxo,  1, 0, 0),
+	F_END
+};
+
+static CLK_GP(gp0, 0, CLK_HALT_SFPB_MISC_STATE_REG, 7);
+static CLK_GP(gp1, 1, CLK_HALT_SFPB_MISC_STATE_REG, 6);
+static CLK_GP(gp2, 2, CLK_HALT_SFPB_MISC_STATE_REG, 5);
+
+#define CLK_GSBI_UART(i, n, h_r, h_b) \
+	struct rcg_clk i##_clk = { \
+		.b = { \
+			.ctl_reg = GSBIn_UART_APPS_NS_REG(n), \
+			.en_mask = BIT(9), \
+			.reset_reg = GSBIn_RESET_REG(n), \
+			.reset_mask = BIT(0), \
+			.halt_reg = h_r, \
+			.halt_bit = h_b, \
+		}, \
+		.ns_reg = GSBIn_UART_APPS_NS_REG(n), \
+		.md_reg = GSBIn_UART_APPS_MD_REG(n), \
+		.root_en_mask = BIT(11), \
+		.ns_mask = (BM(31, 16) | BM(6, 0)), \
+		.mnd_en_mask = BIT(8), \
+		.set_rate = set_rate_mnd, \
+		.freq_tbl = clk_tbl_gsbi_uart, \
+		.current_freq = &rcg_dummy_freq, \
+		.c = { \
+			.dbg_name = #i "_clk", \
+			.ops = &clk_ops_rcg, \
+			VDD_DIG_FMAX_MAP2(LOW, 32000000, NOMINAL, 64000000), \
+			CLK_INIT(i##_clk.c), \
+		}, \
+	}
+#define F_GSBI_UART(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD16(m, n), \
+		.ns_val = NS(31, 16, n, m, 5, 4, 3, d, 2, 0, s##_to_bb_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_gsbi_uart[] = {
+	F_GSBI_UART(       0, gnd,  1,  0,   0),
+	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),
+	F_GSBI_UART(40000000, pll8, 1,  5,  48),
+	F_GSBI_UART(46400000, pll8, 1, 29, 240),
+	F_GSBI_UART(48000000, pll8, 4,  1,   2),
+	F_GSBI_UART(51200000, pll8, 1,  2,  15),
+	F_GSBI_UART(56000000, pll8, 1,  7,  48),
+	F_GSBI_UART(58982400, pll8, 1, 96, 625),
+	F_GSBI_UART(64000000, pll8, 2,  1,   3),
+	F_END
+};
+
+static CLK_GSBI_UART(gsbi1_uart,   1, CLK_HALT_CFPB_STATEA_REG, 10);
+static CLK_GSBI_UART(gsbi2_uart,   2, CLK_HALT_CFPB_STATEA_REG,  6);
+static CLK_GSBI_UART(gsbi3_uart,   3, CLK_HALT_CFPB_STATEA_REG,  2);
+static CLK_GSBI_UART(gsbi4_uart,   4, CLK_HALT_CFPB_STATEB_REG, 26);
+static CLK_GSBI_UART(gsbi5_uart,   5, CLK_HALT_CFPB_STATEB_REG, 22);
+
+#define CLK_GSBI_QUP(i, n, h_r, h_b) \
+	struct rcg_clk i##_clk = { \
+		.b = { \
+			.ctl_reg = GSBIn_QUP_APPS_NS_REG(n), \
+			.en_mask = BIT(9), \
+			.reset_reg = GSBIn_RESET_REG(n), \
+			.reset_mask = BIT(0), \
+			.halt_reg = h_r, \
+			.halt_bit = h_b, \
+		}, \
+		.ns_reg = GSBIn_QUP_APPS_NS_REG(n), \
+		.md_reg = GSBIn_QUP_APPS_MD_REG(n), \
+		.root_en_mask = BIT(11), \
+		.ns_mask = (BM(23, 16) | BM(6, 0)), \
+		.mnd_en_mask = BIT(8), \
+		.set_rate = set_rate_mnd, \
+		.freq_tbl = clk_tbl_gsbi_qup, \
+		.current_freq = &rcg_dummy_freq, \
+		.c = { \
+			.dbg_name = #i "_clk", \
+			.ops = &clk_ops_rcg, \
+			VDD_DIG_FMAX_MAP2(LOW, 24000000, NOMINAL, 52000000), \
+			CLK_INIT(i##_clk.c), \
+		}, \
+	}
+#define F_GSBI_QUP(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD8(16, m, 0, n), \
+		.ns_val = NS(23, 16, n, m, 5, 4, 3, d, 2, 0, s##_to_bb_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_gsbi_qup[] = {
+	F_GSBI_QUP(       0, gnd,  1, 0,  0),
+	F_GSBI_QUP(  960000, cxo,  4, 1,  5),
+	F_GSBI_QUP( 4800000, cxo,  4, 0,  1),
+	F_GSBI_QUP( 9600000, cxo,  2, 0,  1),
+	F_GSBI_QUP(15058800, pll8, 1, 2, 51),
+	F_GSBI_QUP(24000000, pll8, 4, 1,  4),
+	F_GSBI_QUP(25600000, pll8, 1, 1, 15),
+	F_GSBI_QUP(48000000, pll8, 4, 1,  2),
+	F_GSBI_QUP(51200000, pll8, 1, 2, 15),
+	F_END
+};
+
+static CLK_GSBI_QUP(gsbi1_qup,   1, CLK_HALT_CFPB_STATEA_REG,  9);
+static CLK_GSBI_QUP(gsbi2_qup,   2, CLK_HALT_CFPB_STATEA_REG,  4);
+static CLK_GSBI_QUP(gsbi3_qup,   3, CLK_HALT_CFPB_STATEA_REG,  0);
+static CLK_GSBI_QUP(gsbi4_qup,   4, CLK_HALT_CFPB_STATEB_REG, 24);
+static CLK_GSBI_QUP(gsbi5_qup,   5, CLK_HALT_CFPB_STATEB_REG, 20);
+
+#define F_PDM(f, s, d) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.ns_val = NS_SRC_SEL(1, 0, s##_to_xo_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_pdm[] = {
+	F_PDM(       0, gnd, 1),
+	F_PDM(19200000, cxo, 1),
+	F_END
+};
+
+static struct rcg_clk pdm_clk = {
+	.b = {
+		.ctl_reg = PDM_CLK_NS_REG,
+		.en_mask = BIT(9),
+		.reset_reg = PDM_CLK_NS_REG,
+		.reset_mask = BIT(12),
+		.halt_reg = CLK_HALT_CFPB_STATEC_REG,
+		.halt_bit = 3,
+	},
+	.ns_reg = PDM_CLK_NS_REG,
+	.root_en_mask = BIT(11),
+	.ns_mask = BM(1, 0),
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_pdm,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "pdm_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 19200000),
+		CLK_INIT(pdm_clk.c),
+	},
+};
+
+static struct branch_clk pmem_clk = {
+	.b = {
+		.ctl_reg = PMEM_ACLK_CTL_REG,
+		.en_mask = BIT(4),
+		.hwcg_reg =  PMEM_ACLK_CTL_REG,
+		.hwcg_mask = BIT(6),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 20,
+	},
+	.c = {
+		.dbg_name = "pmem_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(pmem_clk.c),
+	},
+};
+
+#define F_PRNG(f, s) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+	}
+static struct clk_freq_tbl clk_tbl_prng[] = {
+	F_PRNG(32000000, pll8),
+	F_END
+};
+
+static struct rcg_clk prng_clk = {
+	.b = {
+		.ctl_reg = SC0_U_CLK_BRANCH_ENA_VOTE_REG,
+		.en_mask = BIT(10),
+		.halt_reg = CLK_HALT_SFPB_MISC_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 10,
+	},
+	.set_rate = set_rate_nop,
+	.freq_tbl = clk_tbl_prng,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "prng_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 32000000, NOMINAL, 65000000),
+		CLK_INIT(prng_clk.c),
+	},
+};
+
+#define CLK_SDC(name, n, h_b, f_table) \
+	struct rcg_clk name = { \
+		.b = { \
+			.ctl_reg = SDCn_APPS_CLK_NS_REG(n), \
+			.en_mask = BIT(9), \
+			.reset_reg = SDCn_RESET_REG(n), \
+			.reset_mask = BIT(0), \
+			.halt_reg = CLK_HALT_DFAB_STATE_REG, \
+			.halt_bit = h_b, \
+		}, \
+		.ns_reg = SDCn_APPS_CLK_NS_REG(n), \
+		.md_reg = SDCn_APPS_CLK_MD_REG(n), \
+		.root_en_mask = BIT(11), \
+		.ns_mask = (BM(23, 16) | BM(6, 0)), \
+		.mnd_en_mask = BIT(8), \
+		.set_rate = set_rate_mnd, \
+		.freq_tbl = f_table, \
+		.current_freq = &rcg_dummy_freq, \
+		.c = { \
+			.dbg_name = #name, \
+			.ops = &clk_ops_rcg, \
+			VDD_DIG_FMAX_MAP2(LOW, 26000000, NOMINAL, 52000000), \
+			CLK_INIT(name.c), \
+		}, \
+	}
+#define F_SDC(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD8(16, m, 0, n), \
+		.ns_val = NS(23, 16, n, m, 5, 4, 3, d, 2, 0, s##_to_bb_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_sdc1_2[] = {
+	F_SDC(        0, gnd,   1, 0,   0),
+	F_SDC(   144300, cxo,   1, 1, 133),
+	F_SDC(   400000, pll8,  4, 1, 240),
+	F_SDC( 16000000, pll8,  4, 1,   6),
+	F_SDC( 17070000, pll8,  1, 2,  45),
+	F_SDC( 20210000, pll8,  1, 1,  19),
+	F_SDC( 24000000, pll8,  4, 1,   4),
+	F_SDC( 38400000, pll8,  2, 1,   5),
+	F_SDC( 48000000, pll8,  4, 1,   2),
+	F_SDC( 64000000, pll8,  3, 1,   2),
+	F_SDC( 76800000, pll8,  1, 1,   5),
+	F_END
+};
+
+static CLK_SDC(sdc1_clk, 1, 6, clk_tbl_sdc1_2);
+static CLK_SDC(sdc2_clk, 2, 5, clk_tbl_sdc1_2);
+
+#define F_USB(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD8(16, m, 0, n), \
+		.ns_val = NS(23, 16, n, m, 5, 4, 3, d, 2, 0, s##_to_bb_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_usb[] = {
+	F_USB(       0, gnd,  1, 0,  0),
+	F_USB(60000000, pll8, 1, 5, 32),
+	F_END
+};
+
+static struct clk_freq_tbl clk_tbl_usb_hsic_sys[] = {
+	F_USB(       0,       gnd, 1, 0, 0),
+	F_USB(64000000, pll8_acpu, 1, 1, 6),
+	F_END
+};
+
+static struct rcg_clk usb_hs1_xcvr_clk = {
+	.b = {
+		.ctl_reg = USB_HS1_XCVR_FS_CLK_NS_REG,
+		.en_mask = BIT(9),
+		.reset_reg = USB_HS1_RESET_REG,
+		.reset_mask = BIT(0),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 0,
+	},
+	.ns_reg = USB_HS1_XCVR_FS_CLK_NS_REG,
+	.md_reg = USB_HS1_XCVR_FS_CLK_MD_REG,
+	.root_en_mask = BIT(11),
+	.ns_mask = (BM(23, 16) | BM(6, 0)),
+	.mnd_en_mask = BIT(8),
+	.set_rate = set_rate_mnd,
+	.freq_tbl = clk_tbl_usb,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "usb_hs1_xcvr_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 60000000),
+		CLK_INIT(usb_hs1_xcvr_clk.c),
+	},
+};
+
+static struct rcg_clk usb_hs1_sys_clk = {
+	.b = {
+		.ctl_reg = USB_HS1_SYS_CLK_NS_REG,
+		.en_mask = BIT(9),
+		.reset_reg = USB_HS1_RESET_REG,
+		.reset_mask = BIT(0),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 4,
+	},
+	.ns_reg = USB_HS1_SYS_CLK_NS_REG,
+	.md_reg = USB_HS1_SYS_CLK_MD_REG,
+	.root_en_mask = BIT(11),
+	.ns_mask = (BM(23, 16) | BM(6, 0)),
+	.mnd_en_mask = BIT(8),
+	.set_rate = set_rate_mnd,
+	.freq_tbl = clk_tbl_usb,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "usb_hs1_sys_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 60000000),
+		CLK_INIT(usb_hs1_sys_clk.c),
+	},
+};
+
+static struct rcg_clk usb_hsic_xcvr_clk = {
+	.b = {
+		.ctl_reg = USB_HSIC_XCVR_FS_CLK_NS_REG,
+		.en_mask = BIT(9),
+		.reset_reg = USB_HSIC_RESET_REG,
+		.reset_mask = BIT(0),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 9,
+	},
+	.ns_reg = USB_HSIC_XCVR_FS_CLK_NS_REG,
+	.md_reg = USB_HSIC_XCVR_FS_CLK_MD_REG,
+	.root_en_mask = BIT(11),
+	.ns_mask = (BM(23, 16) | BM(6, 0)),
+	.mnd_en_mask = BIT(8),
+	.set_rate = set_rate_mnd,
+	.freq_tbl = clk_tbl_usb,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "usb_hsic_xcvr_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 60000000),
+		CLK_INIT(usb_hsic_xcvr_clk.c),
+	},
+};
+
+static struct rcg_clk usb_hsic_sys_clk = {
+	.b = {
+		.ctl_reg = USB_HSIC_SYSTEM_CLK_NS_REG,
+		.en_mask = BIT(9),
+		.reset_reg = USB_HSIC_RESET_REG,
+		.reset_mask = BIT(0),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 7,
+	},
+	.ns_reg = USB_HSIC_SYSTEM_CLK_NS_REG,
+	.md_reg = USB_HSIC_SYSTEM_CLK_MD_REG,
+	.root_en_mask = BIT(11),
+	.ns_mask = (BM(23, 16) | BM(6, 0)),
+	.mnd_en_mask = BIT(8),
+	.set_rate = set_rate_mnd,
+	.freq_tbl = clk_tbl_usb_hsic_sys,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "usb_hsic_sys_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 64000000),
+		CLK_INIT(usb_hsic_sys_clk.c),
+	},
+};
+
+static struct clk_freq_tbl clk_tbl_usb_hsic[] = {
+	F_USB(        0, gnd,   1, 0, 0),
+	F_USB(480000000, pll14, 1, 0, 0),
+	F_END
+};
+
+static struct rcg_clk usb_hsic_clk = {
+	.b = {
+		.ctl_reg = USB_HSIC_CLK_NS_REG,
+		.en_mask = BIT(9),
+		.reset_reg = USB_HSIC_RESET_REG,
+		.reset_mask = BIT(0),
+		.halt_check = DELAY,
+	},
+	.ns_reg = USB_HSIC_CLK_NS_REG,
+	.md_reg = USB_HSIC_CLK_MD_REG,
+	.root_en_mask = BIT(11),
+	.ns_mask = (BM(23, 16) | BM(6, 0)),
+	.set_rate = set_rate_mnd,
+	.freq_tbl = clk_tbl_usb_hsic,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "usb_hsic_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 480000000),
+		CLK_INIT(usb_hsic_clk.c),
+	},
+};
+
+static struct branch_clk usb_hsic_hsio_cal_clk = {
+	.b = {
+		.ctl_reg = USB_HSIC_HSIO_CAL_CLK_CTL_REG,
+		.en_mask = BIT(0),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 8,
+	},
+	.parent = &cxo_clk.c,
+	.c = {
+		.dbg_name = "usb_hsic_hsio_cal_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_hsic_hsio_cal_clk.c),
+	},
+};
+
+/* Fast Peripheral Bus Clocks */
+static struct branch_clk ce1_core_clk = {
+	.b = {
+		.ctl_reg = CE1_CORE_CLK_CTL_REG,
+		.en_mask = BIT(4),
+		.hwcg_reg =  CE1_CORE_CLK_CTL_REG,
+		.hwcg_mask = BIT(6),
+		.halt_reg = CLK_HALT_CFPB_STATEC_REG,
+		.halt_bit = 27,
+	},
+	.c = {
+		.dbg_name = "ce1_core_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(ce1_core_clk.c),
+	},
+};
+static struct branch_clk ce1_p_clk = {
+	.b = {
+		.ctl_reg = CE1_HCLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEC_REG,
+		.halt_bit = 1,
+	},
+	.c = {
+		.dbg_name = "ce1_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(ce1_p_clk.c),
+	},
+};
+
+static struct branch_clk dma_bam_p_clk = {
+	.b = {
+		.ctl_reg = DMA_BAM_HCLK_CTL,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 12,
+	},
+	.c = {
+		.dbg_name = "dma_bam_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(dma_bam_p_clk.c),
+	},
+};
+
+static struct branch_clk gsbi1_p_clk = {
+	.b = {
+		.ctl_reg = GSBIn_HCLK_CTL_REG(1),
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
+		.halt_bit = 11,
+	},
+	.c = {
+		.dbg_name = "gsbi1_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gsbi1_p_clk.c),
+	},
+};
+
+static struct branch_clk gsbi2_p_clk = {
+	.b = {
+		.ctl_reg = GSBIn_HCLK_CTL_REG(2),
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
+		.halt_bit = 7,
+	},
+	.c = {
+		.dbg_name = "gsbi2_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gsbi2_p_clk.c),
+	},
+};
+
+static struct branch_clk gsbi3_p_clk = {
+	.b = {
+		.ctl_reg = GSBIn_HCLK_CTL_REG(3),
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEA_REG,
+		.halt_bit = 3,
+	},
+	.c = {
+		.dbg_name = "gsbi3_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gsbi3_p_clk.c),
+	},
+};
+
+static struct branch_clk gsbi4_p_clk = {
+	.b = {
+		.ctl_reg = GSBIn_HCLK_CTL_REG(4),
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEB_REG,
+		.halt_bit = 27,
+	},
+	.c = {
+		.dbg_name = "gsbi4_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gsbi4_p_clk.c),
+	},
+};
+
+static struct branch_clk gsbi5_p_clk = {
+	.b = {
+		.ctl_reg = GSBIn_HCLK_CTL_REG(5),
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_CFPB_STATEB_REG,
+		.halt_bit = 23,
+	},
+	.c = {
+		.dbg_name = "gsbi5_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gsbi5_p_clk.c),
+	},
+};
+
+static struct branch_clk usb_hs1_p_clk = {
+	.b = {
+		.ctl_reg = USB_HS1_HCLK_CTL_REG,
+		.en_mask = BIT(4),
+		.hwcg_reg =  USB_HS1_HCLK_CTL_REG,
+		.hwcg_mask = BIT(6),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 1,
+	},
+	.c = {
+		.dbg_name = "usb_hs1_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_hs1_p_clk.c),
+	},
+};
+
+static struct branch_clk usb_hsic_p_clk = {
+	.b = {
+		.ctl_reg = USB_HSIC_HCLK_CTL_REG,
+		.en_mask = BIT(4),
+		.hwcg_reg =  USB_HSIC_HCLK_CTL_REG,
+		.hwcg_mask = BIT(6),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 3,
+	},
+	.c = {
+		.dbg_name = "usb_hsic_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(usb_hsic_p_clk.c),
+	},
+};
+
+static struct branch_clk sdc1_p_clk = {
+	.b = {
+		.ctl_reg = SDCn_HCLK_CTL_REG(1),
+		.en_mask = BIT(4),
+		.hwcg_reg =  SDCn_HCLK_CTL_REG(1),
+		.hwcg_mask = BIT(6),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 11,
+	},
+	.c = {
+		.dbg_name = "sdc1_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sdc1_p_clk.c),
+	},
+};
+
+static struct branch_clk sdc2_p_clk = {
+	.b = {
+		.ctl_reg = SDCn_HCLK_CTL_REG(2),
+		.en_mask = BIT(4),
+		.hwcg_reg =  SDCn_HCLK_CTL_REG(2),
+		.hwcg_mask = BIT(6),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 10,
+	},
+	.c = {
+		.dbg_name = "sdc2_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sdc2_p_clk.c),
+	},
+};
+
+/* HW-Voteable Clocks */
+static struct branch_clk adm0_clk = {
+	.b = {
+		.ctl_reg = SC0_U_CLK_BRANCH_ENA_VOTE_REG,
+		.en_mask = BIT(2),
+		.halt_reg = CLK_HALT_MSS_KPSS_MISC_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 14,
+	},
+	.c = {
+		.dbg_name = "adm0_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(adm0_clk.c),
+	},
+};
+
+static struct branch_clk adm0_p_clk = {
+	.b = {
+		.ctl_reg = SC0_U_CLK_BRANCH_ENA_VOTE_REG,
+		.en_mask = BIT(3),
+		.halt_reg = CLK_HALT_MSS_KPSS_MISC_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 13,
+	},
+	.c = {
+		.dbg_name = "adm0_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(adm0_p_clk.c),
+	},
+};
+
+static struct branch_clk pmic_arb0_p_clk = {
+	.b = {
+		.ctl_reg = SC0_U_CLK_BRANCH_ENA_VOTE_REG,
+		.en_mask = BIT(8),
+		.halt_reg = CLK_HALT_SFPB_MISC_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 22,
+	},
+	.c = {
+		.dbg_name = "pmic_arb0_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(pmic_arb0_p_clk.c),
+	},
+};
+
+static struct branch_clk pmic_arb1_p_clk = {
+	.b = {
+		.ctl_reg = SC0_U_CLK_BRANCH_ENA_VOTE_REG,
+		.en_mask = BIT(9),
+		.halt_reg = CLK_HALT_SFPB_MISC_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 21,
+	},
+	.c = {
+		.dbg_name = "pmic_arb1_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(pmic_arb1_p_clk.c),
+	},
+};
+
+static struct branch_clk pmic_ssbi2_clk = {
+	.b = {
+		.ctl_reg = SC0_U_CLK_BRANCH_ENA_VOTE_REG,
+		.en_mask = BIT(7),
+		.halt_reg = CLK_HALT_SFPB_MISC_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 23,
+	},
+	.c = {
+		.dbg_name = "pmic_ssbi2_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(pmic_ssbi2_clk.c),
+	},
+};
+
+static struct branch_clk rpm_msg_ram_p_clk = {
+	.b = {
+		.ctl_reg = SC0_U_CLK_BRANCH_ENA_VOTE_REG,
+		.en_mask = BIT(6),
+		.halt_reg = CLK_HALT_SFPB_MISC_STATE_REG,
+		.halt_check = HALT_VOTED,
+		.halt_bit = 12,
+	},
+	.c = {
+		.dbg_name = "rpm_msg_ram_p_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(rpm_msg_ram_p_clk.c),
+	},
+};
+
+/*
+ * Low Power Audio Clocks
+ */
+#define F_AIF_OSR(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD8(8, m, 0, n), \
+		.ns_val = NS(31, 24, n, m, 5, 4, 3, d, 2, 0, s##_to_lpa_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_aif_osr[] = {
+	F_AIF_OSR(       0, gnd,  1, 0,   0),
+	F_AIF_OSR(  512000, pll4, 4, 1, 192),
+	F_AIF_OSR(  768000, pll4, 4, 1, 128),
+	F_AIF_OSR( 1024000, pll4, 4, 1,  96),
+	F_AIF_OSR( 1536000, pll4, 4, 1,  64),
+	F_AIF_OSR( 2048000, pll4, 4, 1,  48),
+	F_AIF_OSR( 3072000, pll4, 4, 1,  32),
+	F_AIF_OSR( 4096000, pll4, 4, 1,  24),
+	F_AIF_OSR( 6144000, pll4, 4, 1,  16),
+	F_AIF_OSR( 8192000, pll4, 4, 1,  12),
+	F_AIF_OSR(12288000, pll4, 4, 1,   8),
+	F_AIF_OSR(24576000, pll4, 4, 1,   4),
+	F_END
+};
+
+#define CLK_AIF_OSR(i, ns, md, h_r) \
+	struct rcg_clk i##_clk = { \
+		.b = { \
+			.ctl_reg = ns, \
+			.en_mask = BIT(17), \
+			.reset_reg = ns, \
+			.reset_mask = BIT(19), \
+			.halt_reg = h_r, \
+			.halt_check = ENABLE, \
+			.halt_bit = 1, \
+		}, \
+		.ns_reg = ns, \
+		.md_reg = md, \
+		.root_en_mask = BIT(9), \
+		.ns_mask = (BM(31, 24) | BM(6, 0)), \
+		.mnd_en_mask = BIT(8), \
+		.set_rate = set_rate_mnd, \
+		.freq_tbl = clk_tbl_aif_osr, \
+		.current_freq = &rcg_dummy_freq, \
+		.c = { \
+			.dbg_name = #i "_clk", \
+			.ops = &clk_ops_rcg, \
+			CLK_INIT(i##_clk.c), \
+		}, \
+	}
+#define CLK_AIF_OSR_DIV(i, ns, md, h_r) \
+	struct rcg_clk i##_clk = { \
+		.b = { \
+			.ctl_reg = ns, \
+			.en_mask = BIT(21), \
+			.reset_reg = ns, \
+			.reset_mask = BIT(23), \
+			.halt_reg = h_r, \
+			.halt_check = ENABLE, \
+			.halt_bit = 1, \
+		}, \
+		.ns_reg = ns, \
+		.md_reg = md, \
+		.root_en_mask = BIT(9), \
+		.ns_mask = (BM(31, 24) | BM(6, 0)), \
+		.mnd_en_mask = BIT(8), \
+		.set_rate = set_rate_mnd, \
+		.freq_tbl = clk_tbl_aif_osr, \
+		.current_freq = &rcg_dummy_freq, \
+		.c = { \
+			.dbg_name = #i "_clk", \
+			.ops = &clk_ops_rcg, \
+			CLK_INIT(i##_clk.c), \
+		}, \
+	}
+
+#define CLK_AIF_BIT(i, ns, h_r) \
+	struct cdiv_clk i##_clk = { \
+		.b = { \
+			.ctl_reg = ns, \
+			.en_mask = BIT(15), \
+			.halt_reg = h_r, \
+			.halt_check = DELAY, \
+		}, \
+		.ns_reg = ns, \
+		.ext_mask = BIT(14), \
+		.div_offset = 10, \
+		.max_div = 16, \
+		.c = { \
+			.dbg_name = #i "_clk", \
+			.ops = &clk_ops_cdiv, \
+			CLK_INIT(i##_clk.c), \
+		}, \
+	}
+
+#define CLK_AIF_BIT_DIV(i, ns, h_r) \
+	struct cdiv_clk i##_clk = { \
+		.b = { \
+			.ctl_reg = ns, \
+			.en_mask = BIT(19), \
+			.halt_reg = h_r, \
+			.halt_check = DELAY, \
+		}, \
+		.ns_reg = ns, \
+		.ext_mask = BIT(18), \
+		.div_offset = 10, \
+		.max_div = 256, \
+		.c = { \
+			.dbg_name = #i "_clk", \
+			.ops = &clk_ops_cdiv, \
+			CLK_INIT(i##_clk.c), \
+		}, \
+	}
+
+static CLK_AIF_OSR(mi2s_osr, LCC_MI2S_NS_REG, LCC_MI2S_MD_REG,
+		LCC_MI2S_STATUS_REG);
+static CLK_AIF_BIT(mi2s_bit, LCC_MI2S_NS_REG, LCC_MI2S_STATUS_REG);
+
+static CLK_AIF_OSR_DIV(codec_i2s_mic_osr, LCC_CODEC_I2S_MIC_NS_REG,
+		LCC_CODEC_I2S_MIC_MD_REG, LCC_CODEC_I2S_MIC_STATUS_REG);
+static CLK_AIF_BIT_DIV(codec_i2s_mic_bit, LCC_CODEC_I2S_MIC_NS_REG,
+		LCC_CODEC_I2S_MIC_STATUS_REG);
+
+static CLK_AIF_OSR_DIV(spare_i2s_mic_osr, LCC_SPARE_I2S_MIC_NS_REG,
+		LCC_SPARE_I2S_MIC_MD_REG, LCC_SPARE_I2S_MIC_STATUS_REG);
+static CLK_AIF_BIT_DIV(spare_i2s_mic_bit, LCC_SPARE_I2S_MIC_NS_REG,
+		LCC_SPARE_I2S_MIC_STATUS_REG);
+
+static CLK_AIF_OSR_DIV(codec_i2s_spkr_osr, LCC_CODEC_I2S_SPKR_NS_REG,
+		LCC_CODEC_I2S_SPKR_MD_REG, LCC_CODEC_I2S_SPKR_STATUS_REG);
+static CLK_AIF_BIT_DIV(codec_i2s_spkr_bit, LCC_CODEC_I2S_SPKR_NS_REG,
+		LCC_CODEC_I2S_SPKR_STATUS_REG);
+
+static CLK_AIF_OSR_DIV(spare_i2s_spkr_osr, LCC_SPARE_I2S_SPKR_NS_REG,
+		LCC_SPARE_I2S_SPKR_MD_REG, LCC_SPARE_I2S_SPKR_STATUS_REG);
+static CLK_AIF_BIT_DIV(spare_i2s_spkr_bit, LCC_SPARE_I2S_SPKR_NS_REG,
+		LCC_SPARE_I2S_SPKR_STATUS_REG);
+
+#define F_PCM(f, s, d, m, n) \
+	{ \
+		.freq_hz = f, \
+		.src_clk = &s##_clk.c, \
+		.md_val = MD16(m, n), \
+		.ns_val = NS(31, 16, n, m, 5, 4, 3, d, 2, 0, s##_to_lpa_mux), \
+	}
+static struct clk_freq_tbl clk_tbl_pcm[] = {
+	{ .ns_val = BIT(10) /* external input */ },
+	F_PCM(  512000, pll4, 4, 1, 192),
+	F_PCM(  768000, pll4, 4, 1, 128),
+	F_PCM( 1024000, pll4, 4, 1,  96),
+	F_PCM( 1536000, pll4, 4, 1,  64),
+	F_PCM( 2048000, pll4, 4, 1,  48),
+	F_PCM( 3072000, pll4, 4, 1,  32),
+	F_PCM( 4096000, pll4, 4, 1,  24),
+	F_PCM( 6144000, pll4, 4, 1,  16),
+	F_PCM( 8192000, pll4, 4, 1,  12),
+	F_PCM(12288000, pll4, 4, 1,   8),
+	F_PCM(24576000, pll4, 4, 1,   4),
+	F_END
+};
+
+static struct rcg_clk pcm_clk = {
+	.b = {
+		.ctl_reg = LCC_PCM_NS_REG,
+		.en_mask = BIT(11),
+		.reset_reg = LCC_PCM_NS_REG,
+		.reset_mask = BIT(13),
+		.halt_reg = LCC_PCM_STATUS_REG,
+		.halt_check = ENABLE,
+		.halt_bit = 0,
+	},
+	.ns_reg = LCC_PCM_NS_REG,
+	.md_reg = LCC_PCM_MD_REG,
+	.root_en_mask = BIT(9),
+	.ns_mask = BM(31, 16) | BIT(10) | BM(6, 0),
+	.mnd_en_mask = BIT(8),
+	.set_rate = set_rate_mnd,
+	.freq_tbl = clk_tbl_pcm,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "pcm_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 24576000),
+		CLK_INIT(pcm_clk.c),
+	},
+};
+
+static struct rcg_clk audio_slimbus_clk = {
+	.b = {
+		.ctl_reg = LCC_SLIMBUS_NS_REG,
+		.en_mask = BIT(10),
+		.reset_reg = LCC_AHBEX_BRANCH_CTL_REG,
+		.reset_mask = BIT(5),
+		.halt_reg = LCC_SLIMBUS_STATUS_REG,
+		.halt_check = ENABLE,
+		.halt_bit = 0,
+	},
+	.ns_reg = LCC_SLIMBUS_NS_REG,
+	.md_reg = LCC_SLIMBUS_MD_REG,
+	.root_en_mask = BIT(9),
+	.ns_mask = (BM(31, 24) | BM(6, 0)),
+	.mnd_en_mask = BIT(8),
+	.set_rate = set_rate_mnd,
+	.freq_tbl = clk_tbl_aif_osr,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "audio_slimbus_clk",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 24576000),
+		CLK_INIT(audio_slimbus_clk.c),
+	},
+};
+
+static struct branch_clk sps_slimbus_clk = {
+	.b = {
+		.ctl_reg = LCC_SLIMBUS_NS_REG,
+		.en_mask = BIT(12),
+		.halt_reg = LCC_SLIMBUS_STATUS_REG,
+		.halt_check = ENABLE,
+		.halt_bit = 1,
+	},
+	.parent = &audio_slimbus_clk.c,
+	.c = {
+		.dbg_name = "sps_slimbus_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(sps_slimbus_clk.c),
+	},
+};
+
+static struct branch_clk slimbus_xo_src_clk = {
+	.b = {
+		.ctl_reg = SLIMBUS_XO_SRC_CLK_CTL_REG,
+		.en_mask = BIT(2),
+		.halt_reg = CLK_HALT_DFAB_STATE_REG,
+		.halt_bit = 28,
+	},
+	.parent = &sps_slimbus_clk.c,
+	.c = {
+		.dbg_name = "slimbus_xo_src_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(slimbus_xo_src_clk.c),
+	},
+};
+
+DEFINE_CLK_RPM(cfpb_clk, cfpb_a_clk, CFPB, NULL);
+DEFINE_CLK_RPM(dfab_clk, dfab_a_clk, DAYTONA_FABRIC, NULL);
+DEFINE_CLK_RPM(ebi1_clk, ebi1_a_clk, EBI1, NULL);
+DEFINE_CLK_RPM(sfab_clk, sfab_a_clk, SYSTEM_FABRIC, NULL);
+DEFINE_CLK_RPM(sfpb_clk, sfpb_a_clk, SFPB, NULL);
+
+static DEFINE_CLK_VOTER(dfab_usb_hs_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_sdc1_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_sdc2_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_sps_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_bam_dmux_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_msmbus_clk, &dfab_clk.c, 0);
+static DEFINE_CLK_VOTER(dfab_msmbus_a_clk, &dfab_a_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi1_msmbus_clk, &ebi1_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(ebi1_adm_clk, &ebi1_clk.c, 0);
+
+#ifdef CONFIG_DEBUG_FS
+struct measure_sel {
+	u32 test_vector;
+	struct clk *clk;
+};
+
+static DEFINE_CLK_MEASURE(q6sw_clk);
+static DEFINE_CLK_MEASURE(q6fw_clk);
+static DEFINE_CLK_MEASURE(q6_func_clk);
+
+static struct measure_sel measure_mux[] = {
+	{ TEST_PER_LS(0x08), &slimbus_xo_src_clk.c },
+	{ TEST_PER_LS(0x12), &sdc1_p_clk.c },
+	{ TEST_PER_LS(0x13), &sdc1_clk.c },
+	{ TEST_PER_LS(0x14), &sdc2_p_clk.c },
+	{ TEST_PER_LS(0x15), &sdc2_clk.c },
+	{ TEST_PER_LS(0x1F), &gp0_clk.c },
+	{ TEST_PER_LS(0x20), &gp1_clk.c },
+	{ TEST_PER_LS(0x21), &gp2_clk.c },
+	{ TEST_PER_LS(0x26), &pmem_clk.c },
+	{ TEST_PER_LS(0x25), &dfab_clk.c },
+	{ TEST_PER_LS(0x25), &dfab_a_clk.c },
+	{ TEST_PER_LS(0x32), &dma_bam_p_clk.c },
+	{ TEST_PER_LS(0x33), &cfpb_clk.c },
+	{ TEST_PER_LS(0x33), &cfpb_a_clk.c },
+	{ TEST_PER_LS(0x3E), &gsbi1_uart_clk.c },
+	{ TEST_PER_LS(0x3F), &gsbi1_qup_clk.c },
+	{ TEST_PER_LS(0x41), &gsbi2_p_clk.c },
+	{ TEST_PER_LS(0x42), &gsbi2_uart_clk.c },
+	{ TEST_PER_LS(0x44), &gsbi2_qup_clk.c },
+	{ TEST_PER_LS(0x45), &gsbi3_p_clk.c },
+	{ TEST_PER_LS(0x46), &gsbi3_uart_clk.c },
+	{ TEST_PER_LS(0x48), &gsbi3_qup_clk.c },
+	{ TEST_PER_LS(0x49), &gsbi4_p_clk.c },
+	{ TEST_PER_LS(0x4A), &gsbi4_uart_clk.c },
+	{ TEST_PER_LS(0x4C), &gsbi4_qup_clk.c },
+	{ TEST_PER_LS(0x4D), &gsbi5_p_clk.c },
+	{ TEST_PER_LS(0x4E), &gsbi5_uart_clk.c },
+	{ TEST_PER_LS(0x50), &gsbi5_qup_clk.c },
+	{ TEST_PER_LS(0x78), &sfpb_clk.c },
+	{ TEST_PER_LS(0x78), &sfpb_a_clk.c },
+	{ TEST_PER_LS(0x7A), &pmic_ssbi2_clk.c },
+	{ TEST_PER_LS(0x7B), &pmic_arb0_p_clk.c },
+	{ TEST_PER_LS(0x7C), &pmic_arb1_p_clk.c },
+	{ TEST_PER_LS(0x7D), &prng_clk.c },
+	{ TEST_PER_LS(0x7F), &rpm_msg_ram_p_clk.c },
+	{ TEST_PER_LS(0x80), &adm0_p_clk.c },
+	{ TEST_PER_LS(0x84), &usb_hs1_p_clk.c },
+	{ TEST_PER_LS(0x85), &usb_hs1_xcvr_clk.c },
+	{ TEST_PER_LS(0x86), &usb_hsic_sys_clk.c },
+	{ TEST_PER_LS(0x87), &usb_hsic_p_clk.c },
+	{ TEST_PER_LS(0x88), &usb_hsic_xcvr_clk.c },
+	{ TEST_PER_LS(0x8B), &usb_hsic_hsio_cal_clk.c },
+	{ TEST_PER_LS(0x8D), &usb_hs1_sys_clk.c },
+	{ TEST_PER_LS(0x92), &ce1_p_clk.c },
+	{ TEST_PER_HS(0x18), &sfab_clk.c },
+	{ TEST_PER_HS(0x18), &sfab_a_clk.c },
+	{ TEST_PER_HS(0x26), &q6sw_clk },
+	{ TEST_PER_HS(0x27), &q6fw_clk },
+	{ TEST_PER_LS(0xA4), &ce1_core_clk.c },
+	{ TEST_PER_HS(0x2A), &adm0_clk.c },
+	{ TEST_PER_HS(0x34), &ebi1_clk.c },
+	{ TEST_PER_HS(0x34), &ebi1_a_clk.c },
+	{ TEST_PER_HS(0x3E), &usb_hsic_clk.c },
+	{ TEST_LPA(0x0F), &mi2s_bit_clk.c },
+	{ TEST_LPA(0x10), &codec_i2s_mic_bit_clk.c },
+	{ TEST_LPA(0x11), &codec_i2s_spkr_bit_clk.c },
+	{ TEST_LPA(0x12), &spare_i2s_mic_bit_clk.c },
+	{ TEST_LPA(0x13), &spare_i2s_spkr_bit_clk.c },
+	{ TEST_LPA(0x14), &pcm_clk.c },
+	{ TEST_LPA(0x1D), &audio_slimbus_clk.c },
+	{ TEST_LPA_HS(0x00), &q6_func_clk },
+};
+
+static struct measure_sel *find_measure_sel(struct clk *clk)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(measure_mux); i++)
+		if (measure_mux[i].clk == clk)
+			return &measure_mux[i];
+	return NULL;
+}
+
+static int measure_clk_set_parent(struct clk *c, struct clk *parent)
+{
+	int ret = 0;
+	u32 clk_sel;
+	struct measure_sel *p;
+	struct measure_clk *clk = to_measure_clk(c);
+	unsigned long flags;
+
+	if (!parent)
+		return -EINVAL;
+
+	p = find_measure_sel(parent);
+	if (!p)
+		return -EINVAL;
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+
+	/*
+	 * Program the test vector, measurement period (sample_ticks)
+	 * and scaling multiplier.
+	 */
+	clk->sample_ticks = 0x10000;
+	clk_sel = p->test_vector & TEST_CLK_SEL_MASK;
+	clk->multiplier = 1;
+	switch (p->test_vector >> TEST_TYPE_SHIFT) {
+	case TEST_TYPE_PER_LS:
+		writel_relaxed(0x4030D00|BVAL(7, 0, clk_sel), CLK_TEST_REG);
+		break;
+	case TEST_TYPE_PER_HS:
+		writel_relaxed(0x4020000|BVAL(16, 10, clk_sel), CLK_TEST_REG);
+		break;
+	case TEST_TYPE_LPA:
+		writel_relaxed(0x4030D98, CLK_TEST_REG);
+		writel_relaxed(BVAL(6, 1, clk_sel)|BIT(0),
+				LCC_CLK_LS_DEBUG_CFG_REG);
+		break;
+	case TEST_TYPE_LPA_HS:
+		writel_relaxed(0x402BC00, CLK_TEST_REG);
+		writel_relaxed(BVAL(2, 1, clk_sel)|BIT(0),
+				LCC_CLK_HS_DEBUG_CFG_REG);
+		break;
+	default:
+		ret = -EPERM;
+	}
+	/* Make sure test vector is set before starting measurements. */
+	mb();
+
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	return ret;
+}
+
+/* Sample clock for 'ticks' reference clock ticks. */
+static unsigned long run_measurement(unsigned ticks)
+{
+	/* Stop counters and set the XO4 counter start value. */
+	writel_relaxed(ticks, RINGOSC_TCXO_CTL_REG);
+
+	/* Wait for timer to become ready. */
+	while ((readl_relaxed(RINGOSC_STATUS_REG) & BIT(25)) != 0)
+		cpu_relax();
+
+	/* Run measurement and wait for completion. */
+	writel_relaxed(BIT(28)|ticks, RINGOSC_TCXO_CTL_REG);
+	while ((readl_relaxed(RINGOSC_STATUS_REG) & BIT(25)) == 0)
+		cpu_relax();
+
+	/* Stop counters. */
+	writel_relaxed(0x0, RINGOSC_TCXO_CTL_REG);
+
+	/* Return measured ticks. */
+	return readl_relaxed(RINGOSC_STATUS_REG) & BM(24, 0);
+}
+
+
+/* Perform a hardware rate measurement for a given clock.
+   FOR DEBUG USE ONLY: Measurements take ~15 ms! */
+static unsigned long measure_clk_get_rate(struct clk *c)
+{
+	unsigned long flags;
+	u32 pdm_reg_backup, ringosc_reg_backup;
+	u64 raw_count_short, raw_count_full;
+	struct measure_clk *clk = to_measure_clk(c);
+	unsigned ret;
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+
+	/* Enable CXO/4 and RINGOSC branch and root. */
+	pdm_reg_backup = readl_relaxed(PDM_CLK_NS_REG);
+	ringosc_reg_backup = readl_relaxed(RINGOSC_NS_REG);
+	writel_relaxed(0x2898, PDM_CLK_NS_REG);
+	writel_relaxed(0xA00, RINGOSC_NS_REG);
+
+	/*
+	 * The ring oscillator counter will not reset if the measured clock
+	 * is not running.  To detect this, run a short measurement before
+	 * the full measurement.  If the raw results of the two are the same
+	 * then the clock must be off.
+	 */
+
+	/* Run a short measurement. (~1 ms) */
+	raw_count_short = run_measurement(0x1000);
+	/* Run a full measurement. (~14 ms) */
+	raw_count_full = run_measurement(clk->sample_ticks);
+
+	writel_relaxed(ringosc_reg_backup, RINGOSC_NS_REG);
+	writel_relaxed(pdm_reg_backup, PDM_CLK_NS_REG);
+
+	/* Return 0 if the clock is off. */
+	if (raw_count_full == raw_count_short)
+		ret = 0;
+	else {
+		/* Compute rate in Hz. */
+		raw_count_full = ((raw_count_full * 10) + 15) * 4800000;
+		do_div(raw_count_full, ((clk->sample_ticks * 10) + 35));
+		ret = (raw_count_full * clk->multiplier);
+	}
+
+	/* Route dbg_hs_clk to PLLTEST.  300mV single-ended amplitude. */
+	writel_relaxed(0x38F8, PLLTEST_PAD_CFG_REG);
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	return ret;
+}
+#else /* !CONFIG_DEBUG_FS */
+static int measure_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	return -EINVAL;
+}
+
+static unsigned long measure_clk_get_rate(struct clk *clk)
+{
+	return 0;
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static struct clk_ops clk_ops_measure = {
+	.set_parent = measure_clk_set_parent,
+	.get_rate = measure_clk_get_rate,
+};
+
+static struct measure_clk measure_clk = {
+	.c = {
+		.dbg_name = "measure_clk",
+		.ops = &clk_ops_measure,
+		CLK_INIT(measure_clk.c),
+	},
+	.multiplier = 1,
+};
+
+static struct clk_lookup msm_clocks_9615[] = {
+	CLK_LOOKUP("xo",	cxo_a_clk.c,	""),
+	CLK_LOOKUP("xo",	cxo_clk.c,	"BAM_RMNT"),
+	CLK_LOOKUP("xo",	cxo_clk.c,	"msm_xo"),
+	CLK_LOOKUP("pll0",	pll0_clk.c,	NULL),
+	CLK_LOOKUP("pll8",	pll8_clk.c,	NULL),
+	CLK_LOOKUP("pll14",	pll14_clk.c,	NULL),
+
+	CLK_LOOKUP("pll0", pll0_acpu_clk.c, "acpu"),
+	CLK_LOOKUP("pll8", pll8_acpu_clk.c, "acpu"),
+	CLK_LOOKUP("pll9", pll9_acpu_clk.c, "acpu"),
+
+	CLK_LOOKUP("measure",	measure_clk.c,	"debug"),
+
+	CLK_LOOKUP("bus_clk",		sfab_clk.c,		"msm_sys_fab"),
+	CLK_LOOKUP("bus_a_clk",		sfab_a_clk.c,		"msm_sys_fab"),
+	CLK_LOOKUP("mem_clk",		ebi1_msmbus_clk.c,	"msm_bus"),
+	CLK_LOOKUP("mem_a_clk",		ebi1_a_clk.c,		"msm_bus"),
+	CLK_LOOKUP("dfab_clk",		dfab_msmbus_clk.c,	"msm_bus"),
+	CLK_LOOKUP("dfab_a_clk",	dfab_msmbus_a_clk.c,	"msm_bus"),
+
+	CLK_LOOKUP("bus_clk",		sfpb_clk.c,	NULL),
+	CLK_LOOKUP("bus_a_clk",		sfpb_a_clk.c,	NULL),
+	CLK_LOOKUP("bus_clk",		cfpb_clk.c,	NULL),
+	CLK_LOOKUP("bus_a_clk",		cfpb_a_clk.c,	NULL),
+	CLK_LOOKUP("ebi1_clk",		ebi1_clk.c,	NULL),
+
+	CLK_LOOKUP("core_clk",		gp0_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gp1_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gp2_clk.c,	""),
+
+	CLK_LOOKUP("core_clk", gsbi3_uart_clk.c, ""),
+	CLK_LOOKUP("core_clk", gsbi4_uart_clk.c, "msm_serial_hsl.0"),
+	CLK_LOOKUP("core_clk", gsbi5_uart_clk.c, ""),
+
+	CLK_LOOKUP("core_clk",	gsbi3_qup_clk.c, "spi_qsd.0"),
+	CLK_LOOKUP("core_clk",	gsbi4_qup_clk.c, ""),
+	CLK_LOOKUP("core_clk",	gsbi5_qup_clk.c, "qup_i2c.0"),
+
+	CLK_LOOKUP("core_clk",		pdm_clk.c,		""),
+	CLK_LOOKUP("mem_clk",		pmem_clk.c,		"msm_sps"),
+	CLK_LOOKUP("core_clk",		prng_clk.c,		"msm_rng.0"),
+	CLK_LOOKUP("core_clk",		sdc1_clk.c,		"msm_sdcc.1"),
+	CLK_LOOKUP("core_clk",		sdc2_clk.c,		"msm_sdcc.2"),
+	CLK_LOOKUP("iface_clk",		ce1_p_clk.c,		""),
+	CLK_LOOKUP("core_clk",		ce1_core_clk.c,		""),
+	CLK_LOOKUP("dma_bam_pclk",	dma_bam_p_clk.c,	NULL),
+
+	CLK_LOOKUP("iface_clk",	gsbi3_p_clk.c, "spi_qsd.0"),
+	CLK_LOOKUP("iface_clk",	gsbi4_p_clk.c, "msm_serial_hsl.0"),
+	CLK_LOOKUP("iface_clk",	gsbi5_p_clk.c, "qup_i2c.0"),
+
+	CLK_LOOKUP("iface_clk",	     usb_hs1_p_clk.c,		"msm_otg"),
+	CLK_LOOKUP("core_clk",       usb_hs1_sys_clk.c,		"msm_otg"),
+	CLK_LOOKUP("alt_core_clk",   usb_hs1_xcvr_clk.c,	"msm_otg"),
+	CLK_LOOKUP("alt_core_clk",   usb_hsic_xcvr_clk.c,      "msm_hsic_host"),
+	CLK_LOOKUP("cal_clk",	     usb_hsic_hsio_cal_clk.c,  "msm_hsic_host"),
+	CLK_LOOKUP("core_clk",	     usb_hsic_sys_clk.c,       "msm_hsic_host"),
+	CLK_LOOKUP("iface_clk",	     usb_hsic_p_clk.c,	       "msm_hsic_host"),
+	CLK_LOOKUP("phy_clk",        usb_hsic_clk.c,	       "msm_hsic_host"),
+	CLK_LOOKUP("alt_core_clk",  usb_hsic_xcvr_clk.c, "msm_hsic_peripheral"),
+	CLK_LOOKUP("cal_clk",  usb_hsic_hsio_cal_clk.c,  "msm_hsic_peripheral"),
+	CLK_LOOKUP("core_clk",      usb_hsic_sys_clk.c,  "msm_hsic_peripheral"),
+	CLK_LOOKUP("iface_clk",     usb_hsic_p_clk.c,    "msm_hsic_peripheral"),
+	CLK_LOOKUP("phy_clk",       usb_hsic_clk.c,      "msm_hsic_peripheral"),
+
+	CLK_LOOKUP("iface_clk",		sdc1_p_clk.c,		"msm_sdcc.1"),
+	CLK_LOOKUP("iface_clk",		sdc2_p_clk.c,		"msm_sdcc.2"),
+	CLK_LOOKUP("core_clk",		adm0_clk.c,		"msm_dmov"),
+	CLK_LOOKUP("iface_clk",		adm0_p_clk.c,		"msm_dmov"),
+	CLK_LOOKUP("iface_clk",		pmic_arb0_p_clk.c,	""),
+	CLK_LOOKUP("iface_clk",		pmic_arb1_p_clk.c,	""),
+	CLK_LOOKUP("core_clk",		pmic_ssbi2_clk.c,	""),
+	CLK_LOOKUP("mem_clk",		rpm_msg_ram_p_clk.c,	""),
+	CLK_LOOKUP("bit_clk",		mi2s_bit_clk.c,		"msm-dai-q6.6"),
+	CLK_LOOKUP("osr_clk",		mi2s_osr_clk.c,		"msm-dai-q6.6"),
+
+	CLK_LOOKUP("bit_clk",		codec_i2s_mic_bit_clk.c,
+			   "msm-dai-q6.1"),
+	CLK_LOOKUP("osr_clk",		codec_i2s_mic_osr_clk.c,
+			   "msm-dai-q6.1"),
+	CLK_LOOKUP("bit_clk",		codec_i2s_spkr_bit_clk.c,
+			   "msm-dai-q6.0"),
+	CLK_LOOKUP("osr_clk",		codec_i2s_spkr_osr_clk.c,
+			   "msm-dai-q6.0"),
+	CLK_LOOKUP("bit_clk",		spare_i2s_mic_bit_clk.c,
+			   "msm-dai-q6.5"),
+	CLK_LOOKUP("osr_clk",		spare_i2s_mic_osr_clk.c,
+			   "msm-dai-q6.5"),
+	CLK_LOOKUP("bit_clk",		codec_i2s_spkr_bit_clk.c,
+			   "msm-dai-q6.16384"),
+	CLK_LOOKUP("osr_clk",		codec_i2s_spkr_osr_clk.c,
+			   "msm-dai-q6.16384"),
+	CLK_LOOKUP("bit_clk",		spare_i2s_spkr_bit_clk.c,
+			   "msm-dai-q6.4"),
+	CLK_LOOKUP("osr_clk",		spare_i2s_spkr_osr_clk.c,
+			   "msm-dai-q6.4"),
+	CLK_LOOKUP("pcm_clk",		pcm_clk.c,	"msm-dai-q6.2"),
+	CLK_LOOKUP("pcm_clk",		pcm_clk.c,	"msm-dai-q6.3"),
+
+	CLK_LOOKUP("sps_slimbus_clk",	sps_slimbus_clk.c,	NULL),
+	CLK_LOOKUP("core_clk",		audio_slimbus_clk.c, "msm_slim_ctrl.1"),
+	CLK_LOOKUP("core_clk",		dfab_usb_hs_clk.c,	"msm_otg"),
+	CLK_LOOKUP("bus_clk",		dfab_sdc1_clk.c,	"msm_sdcc.1"),
+	CLK_LOOKUP("bus_clk",		dfab_sdc2_clk.c,	"msm_sdcc.2"),
+	CLK_LOOKUP("dfab_clk",		dfab_sps_clk.c,		"msm_sps"),
+	CLK_LOOKUP("bus_clk",		dfab_bam_dmux_clk.c,	"BAM_RMNT"),
+	CLK_LOOKUP("mem_clk",		ebi1_adm_clk.c, "msm_dmov"),
+
+	CLK_LOOKUP("iface_clk",		ce1_p_clk.c,		"qce.0"),
+	CLK_LOOKUP("iface_clk",		ce1_p_clk.c,		"qcrypto.0"),
+	CLK_LOOKUP("core_clk",		ce1_core_clk.c,		"qce.0"),
+	CLK_LOOKUP("core_clk",		ce1_core_clk.c,		"qcrypto.0"),
+
+	CLK_LOOKUP("q6sw_clk",		q6sw_clk, NULL),
+	CLK_LOOKUP("q6fw_clk",		q6fw_clk, NULL),
+	CLK_LOOKUP("q6_func_clk",	q6_func_clk, NULL),
+};
+
+static struct pll_config_regs pll0_regs __initdata = {
+	.l_reg = BB_PLL0_L_VAL_REG,
+	.m_reg = BB_PLL0_M_VAL_REG,
+	.n_reg = BB_PLL0_N_VAL_REG,
+	.config_reg = BB_PLL0_CONFIG_REG,
+	.mode_reg = BB_PLL0_MODE_REG,
+};
+
+static struct pll_config pll0_config __initdata = {
+	.l = 0xE,
+	.m = 0x3,
+	.n = 0x8,
+	.vco_val = 0x0,
+	.vco_mask = BM(17, 16),
+	.pre_div_val = 0x0,
+	.pre_div_mask = BIT(19),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(21, 20),
+	.mn_ena_val = BIT(22),
+	.mn_ena_mask = BIT(22),
+	.main_output_val = BIT(23),
+	.main_output_mask = BIT(23),
+};
+
+static struct pll_config_regs pll14_regs __initdata = {
+	.l_reg = BB_PLL14_L_VAL_REG,
+	.m_reg = BB_PLL14_M_VAL_REG,
+	.n_reg = BB_PLL14_N_VAL_REG,
+	.config_reg = BB_PLL14_CONFIG_REG,
+	.mode_reg = BB_PLL14_MODE_REG,
+};
+
+static struct pll_config pll14_config __initdata = {
+	.l = 0x19,
+	.m = 0x0,
+	.n = 0x1,
+	.vco_val = 0x0,
+	.vco_mask = BM(17, 16),
+	.pre_div_val = 0x0,
+	.pre_div_mask = BIT(19),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(21, 20),
+	.main_output_val = BIT(23),
+	.main_output_mask = BIT(23),
+};
+
+/*
+ * Miscellaneous clock register initializations
+ */
+static void __init msm9615_clock_pre_init(void)
+{
+	u32 regval, is_pll_enabled, pll9_lval;
+
+	vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
+
+	clk_ops_local_pll.enable = sr_pll_clk_enable;
+
+	/* Enable PDM CXO source. */
+	regval = readl_relaxed(PDM_CLK_NS_REG);
+	writel_relaxed(BIT(13) | regval, PDM_CLK_NS_REG);
+
+	/* Check if PLL0 is active */
+	is_pll_enabled = readl_relaxed(BB_PLL0_STATUS_REG) & BIT(16);
+
+	if (!is_pll_enabled) {
+		/* Enable AUX output */
+		regval = readl_relaxed(BB_PLL0_TEST_CTL_REG);
+		regval |= BIT(12);
+		writel_relaxed(regval, BB_PLL0_TEST_CTL_REG);
+
+		configure_pll(&pll0_config, &pll0_regs, 1);
+	}
+
+	/* Check if PLL14 is enabled in FSM mode */
+	is_pll_enabled  = readl_relaxed(BB_PLL14_STATUS_REG) & BIT(16);
+
+	if (!is_pll_enabled)
+		configure_pll(&pll14_config, &pll14_regs, 1);
+	else if (!(readl_relaxed(BB_PLL14_MODE_REG) & BIT(20)))
+		WARN(1, "PLL14 enabled in non-FSM mode!\n");
+
+	/* Detect PLL9 rate and fixup structure accordingly */
+	pll9_lval = readl_relaxed(SC_PLL0_L_VAL_REG);
+
+	if (pll9_lval == 0x1C)
+		pll9_acpu_clk.c.rate = 550000000;
+
+	/* Enable PLL4 source on the LPASS Primary PLL Mux */
+	regval = readl_relaxed(LCC_PRI_PLL_CLK_CTL_REG);
+	writel_relaxed(regval | BIT(0), LCC_PRI_PLL_CLK_CTL_REG);
+
+	/*
+	 * Disable hardware clock gating for pmem_clk. Leaving it enabled
+	 * results in the clock staying on.
+	 */
+	regval = readl_relaxed(PMEM_ACLK_CTL_REG);
+	regval &= ~BIT(6);
+	writel_relaxed(regval, PMEM_ACLK_CTL_REG);
+
+	/*
+	 * Disable hardware clock gating for dma_bam_p_clk, which does
+	 * not have working support for the feature.
+	 */
+	regval = readl_relaxed(DMA_BAM_HCLK_CTL);
+	regval &= ~BIT(6);
+	writel_relaxed(regval, DMA_BAM_HCLK_CTL);
+}
+
+static void __init msm9615_clock_post_init(void)
+{
+	/* Keep CXO on whenever APPS cpu is active */
+	clk_prepare_enable(&cxo_a_clk.c);
+
+	/* Initialize rates for clocks that only support one. */
+	clk_set_rate(&pdm_clk.c, 19200000);
+	clk_set_rate(&prng_clk.c, 32000000);
+	clk_set_rate(&usb_hs1_xcvr_clk.c, 60000000);
+	clk_set_rate(&usb_hs1_sys_clk.c, 60000000);
+	clk_set_rate(&usb_hsic_xcvr_clk.c, 60000000);
+	clk_set_rate(&usb_hsic_sys_clk.c, 64000000);
+	clk_set_rate(&usb_hsic_clk.c, 480000000);
+
+	/*
+	 * The halt status bits for PDM may be incorrect at boot.
+	 * Toggle these clocks on and off to refresh them.
+	*/
+	clk_prepare_enable(&pdm_clk.c);
+	clk_disable_unprepare(&pdm_clk.c);
+}
+
+static int __init msm9615_clock_late_init(void)
+{
+	return unvote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
+}
+
+struct clock_init_data msm9615_clock_init_data __initdata = {
+	.table = msm_clocks_9615,
+	.size = ARRAY_SIZE(msm_clocks_9615),
+	.pre_init = msm9615_clock_pre_init,
+	.post_init = msm9615_clock_post_init,
+	.late_init = msm9615_clock_late_init,
+};
diff --git a/arch/arm/mach-msm/clock-copper.c b/arch/arm/mach-msm/clock-copper.c
new file mode 100644
index 0000000..4d5f773
--- /dev/null
+++ b/arch/arm/mach-msm/clock-copper.c
@@ -0,0 +1,5202 @@
+/* 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/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <mach/clk.h>
+
+#include "clock-local2.h"
+#include "clock-pll.h"
+
+enum {
+	GCC_BASE,
+	MMSS_BASE,
+	LPASS_BASE,
+	MSS_BASE,
+	N_BASES,
+};
+
+static void __iomem *virt_bases[N_BASES];
+
+#define GCC_REG_BASE(x) (void __iomem *)(virt_bases[GCC_BASE] + (x))
+#define MMSS_REG_BASE(x) (void __iomem *)(virt_bases[MMSS_BASE] + (x))
+#define LPASS_REG_BASE(x) (void __iomem *)(virt_bases[LPASS_BASE] + (x))
+#define MSS_REG_BASE(x) (void __iomem *)(virt_bases[MSS_BASE] + (x))
+
+#define GPLL0_MODE_REG                 0x0000
+#define GPLL0_L_REG                    0x0004
+#define GPLL0_M_REG                    0x0008
+#define GPLL0_N_REG                    0x000C
+#define GPLL0_USER_CTL_REG             0x0010
+#define GPLL0_CONFIG_CTL_REG           0x0014
+#define GPLL0_TEST_CTL_REG             0x0018
+#define GPLL0_STATUS_REG               0x001C
+
+#define GPLL1_MODE_REG                 0x0040
+#define GPLL1_L_REG                    0x0044
+#define GPLL1_M_REG                    0x0048
+#define GPLL1_N_REG                    0x004C
+#define GPLL1_USER_CTL_REG             0x0050
+#define GPLL1_CONFIG_CTL_REG           0x0054
+#define GPLL1_TEST_CTL_REG             0x0058
+#define GPLL1_STATUS_REG               0x005C
+
+#define MMPLL0_MODE_REG                0x0000
+#define MMPLL0_L_REG                   0x0004
+#define MMPLL0_M_REG                   0x0008
+#define MMPLL0_N_REG                   0x000C
+#define MMPLL0_USER_CTL_REG            0x0010
+#define MMPLL0_CONFIG_CTL_REG          0x0014
+#define MMPLL0_TEST_CTL_REG            0x0018
+#define MMPLL0_STATUS_REG              0x001C
+
+#define MMPLL1_MODE_REG                0x0040
+#define MMPLL1_L_REG                   0x0044
+#define MMPLL1_M_REG                   0x0048
+#define MMPLL1_N_REG                   0x004C
+#define MMPLL1_USER_CTL_REG            0x0050
+#define MMPLL1_CONFIG_CTL_REG          0x0054
+#define MMPLL1_TEST_CTL_REG            0x0058
+#define MMPLL1_STATUS_REG              0x005C
+
+#define MMPLL3_MODE_REG                0x0080
+#define MMPLL3_L_REG                   0x0084
+#define MMPLL3_M_REG                   0x0088
+#define MMPLL3_N_REG                   0x008C
+#define MMPLL3_USER_CTL_REG            0x0090
+#define MMPLL3_CONFIG_CTL_REG          0x0094
+#define MMPLL3_TEST_CTL_REG            0x0098
+#define MMPLL3_STATUS_REG              0x009C
+
+#define LPAPLL_MODE_REG                0x0000
+#define LPAPLL_L_REG                   0x0004
+#define LPAPLL_M_REG                   0x0008
+#define LPAPLL_N_REG                   0x000C
+#define LPAPLL_USER_CTL_REG            0x0010
+#define LPAPLL_CONFIG_CTL_REG          0x0014
+#define LPAPLL_TEST_CTL_REG            0x0018
+#define LPAPLL_STATUS_REG              0x001C
+
+#define GCC_DEBUG_CLK_CTL_REG          0x1880
+#define CLOCK_FRQ_MEASURE_CTL_REG      0x1884
+#define CLOCK_FRQ_MEASURE_STATUS_REG   0x1888
+#define GCC_XO_DIV4_CBCR_REG           0x10C8
+#define APCS_GPLL_ENA_VOTE_REG         0x1480
+#define MMSS_PLL_VOTE_APCS_REG         0x0100
+#define MMSS_DEBUG_CLK_CTL_REG         0x0900
+#define LPASS_DEBUG_CLK_CTL_REG        0x29000
+#define LPASS_LPA_PLL_VOTE_APPS_REG    0x2000
+#define MSS_DEBUG_CLK_CTL_REG          0x0078
+
+#define USB30_MASTER_CMD_RCGR          0x03D4
+#define USB30_MOCK_UTMI_CMD_RCGR       0x03E8
+#define USB_HSIC_SYSTEM_CMD_RCGR       0x041C
+#define USB_HSIC_CMD_RCGR              0x0440
+#define USB_HSIC_IO_CAL_CMD_RCGR       0x0458
+#define USB_HS_SYSTEM_CMD_RCGR         0x0490
+#define SDCC1_APPS_CMD_RCGR            0x04D0
+#define SDCC2_APPS_CMD_RCGR            0x0510
+#define SDCC3_APPS_CMD_RCGR            0x0550
+#define SDCC4_APPS_CMD_RCGR            0x0590
+#define BLSP1_QUP1_SPI_APPS_CMD_RCGR   0x064C
+#define BLSP1_UART1_APPS_CMD_RCGR      0x068C
+#define BLSP1_QUP2_SPI_APPS_CMD_RCGR   0x06CC
+#define BLSP1_UART2_APPS_CMD_RCGR      0x070C
+#define BLSP1_QUP3_SPI_APPS_CMD_RCGR   0x074C
+#define BLSP1_UART3_APPS_CMD_RCGR      0x078C
+#define BLSP1_QUP4_SPI_APPS_CMD_RCGR   0x07CC
+#define BLSP1_UART4_APPS_CMD_RCGR      0x080C
+#define BLSP1_QUP5_SPI_APPS_CMD_RCGR   0x084C
+#define BLSP1_UART5_APPS_CMD_RCGR      0x088C
+#define BLSP1_QUP6_SPI_APPS_CMD_RCGR   0x08CC
+#define BLSP1_UART6_APPS_CMD_RCGR      0x090C
+#define BLSP2_QUP1_SPI_APPS_CMD_RCGR   0x098C
+#define BLSP2_UART1_APPS_CMD_RCGR      0x09CC
+#define BLSP2_QUP2_SPI_APPS_CMD_RCGR   0x0A0C
+#define BLSP2_UART2_APPS_CMD_RCGR      0x0A4C
+#define BLSP2_QUP3_SPI_APPS_CMD_RCGR   0x0A8C
+#define BLSP2_UART3_APPS_CMD_RCGR      0x0ACC
+#define BLSP2_QUP4_SPI_APPS_CMD_RCGR   0x0B0C
+#define BLSP2_UART4_APPS_CMD_RCGR      0x0B4C
+#define BLSP2_QUP5_SPI_APPS_CMD_RCGR   0x0B8C
+#define BLSP2_UART5_APPS_CMD_RCGR      0x0BCC
+#define BLSP2_QUP6_SPI_APPS_CMD_RCGR   0x0C0C
+#define BLSP2_UART6_APPS_CMD_RCGR      0x0C4C
+#define PDM2_CMD_RCGR                  0x0CD0
+#define TSIF_REF_CMD_RCGR              0x0D90
+#define CE1_CMD_RCGR                   0x1050
+#define CE2_CMD_RCGR                   0x1090
+#define GP1_CMD_RCGR                   0x1904
+#define GP2_CMD_RCGR                   0x1944
+#define GP3_CMD_RCGR                   0x1984
+#define LPAIF_SPKR_CMD_RCGR            0xA000
+#define LPAIF_PRI_CMD_RCGR             0xB000
+#define LPAIF_SEC_CMD_RCGR             0xC000
+#define LPAIF_TER_CMD_RCGR             0xD000
+#define LPAIF_QUAD_CMD_RCGR            0xE000
+#define LPAIF_PCM0_CMD_RCGR            0xF000
+#define LPAIF_PCM1_CMD_RCGR            0x10000
+#define RESAMPLER_CMD_RCGR             0x11000
+#define SLIMBUS_CMD_RCGR               0x12000
+#define LPAIF_PCMOE_CMD_RCGR           0x13000
+#define AHBFABRIC_CMD_RCGR             0x18000
+#define VCODEC0_CMD_RCGR               0x1000
+#define PCLK0_CMD_RCGR                 0x2000
+#define PCLK1_CMD_RCGR                 0x2020
+#define MDP_CMD_RCGR                   0x2040
+#define EXTPCLK_CMD_RCGR               0x2060
+#define VSYNC_CMD_RCGR                 0x2080
+#define EDPPIXEL_CMD_RCGR              0x20A0
+#define EDPLINK_CMD_RCGR               0x20C0
+#define EDPAUX_CMD_RCGR                0x20E0
+#define HDMI_CMD_RCGR                  0x2100
+#define BYTE0_CMD_RCGR                 0x2120
+#define BYTE1_CMD_RCGR                 0x2140
+#define ESC0_CMD_RCGR                  0x2160
+#define ESC1_CMD_RCGR                  0x2180
+#define CSI0PHYTIMER_CMD_RCGR          0x3000
+#define CSI1PHYTIMER_CMD_RCGR          0x3030
+#define CSI2PHYTIMER_CMD_RCGR          0x3060
+#define CSI0_CMD_RCGR                  0x3090
+#define CSI1_CMD_RCGR                  0x3100
+#define CSI2_CMD_RCGR                  0x3160
+#define CSI3_CMD_RCGR                  0x31C0
+#define CCI_CMD_RCGR                   0x3300
+#define MCLK0_CMD_RCGR                 0x3360
+#define MCLK1_CMD_RCGR                 0x3390
+#define MCLK2_CMD_RCGR                 0x33C0
+#define MCLK3_CMD_RCGR                 0x33F0
+#define MMSS_GP0_CMD_RCGR              0x3420
+#define MMSS_GP1_CMD_RCGR              0x3450
+#define JPEG0_CMD_RCGR                 0x3500
+#define JPEG1_CMD_RCGR                 0x3520
+#define JPEG2_CMD_RCGR                 0x3540
+#define VFE0_CMD_RCGR                  0x3600
+#define VFE1_CMD_RCGR                  0x3620
+#define CPP_CMD_RCGR                   0x3640
+#define GFX3D_CMD_RCGR                 0x4000
+#define RBCPR_CMD_RCGR                 0x4060
+#define AHB_CMD_RCGR                   0x5000
+#define AXI_CMD_RCGR                   0x5040
+#define OCMEMNOC_CMD_RCGR              0x5090
+
+#define MMSS_BCR                  0x0240
+#define USB_30_BCR                0x03C0
+#define USB3_PHY_BCR              0x03FC
+#define USB_HS_HSIC_BCR           0x0400
+#define USB_HS_BCR                0x0480
+#define SDCC1_BCR                 0x04C0
+#define SDCC2_BCR                 0x0500
+#define SDCC3_BCR                 0x0540
+#define SDCC4_BCR                 0x0580
+#define BLSP1_BCR                 0x05C0
+#define BLSP1_QUP1_BCR            0x0640
+#define BLSP1_UART1_BCR           0x0680
+#define BLSP1_QUP2_BCR            0x06C0
+#define BLSP1_UART2_BCR           0x0700
+#define BLSP1_QUP3_BCR            0x0740
+#define BLSP1_UART3_BCR           0x0780
+#define BLSP1_QUP4_BCR            0x07C0
+#define BLSP1_UART4_BCR           0x0800
+#define BLSP1_QUP5_BCR            0x0840
+#define BLSP1_UART5_BCR           0x0880
+#define BLSP1_QUP6_BCR            0x08C0
+#define BLSP1_UART6_BCR           0x0900
+#define BLSP2_BCR                 0x0940
+#define BLSP2_QUP1_BCR            0x0980
+#define BLSP2_UART1_BCR           0x09C0
+#define BLSP2_QUP2_BCR            0x0A00
+#define BLSP2_UART2_BCR           0x0A40
+#define BLSP2_QUP3_BCR            0x0A80
+#define BLSP2_UART3_BCR           0x0AC0
+#define BLSP2_QUP4_BCR            0x0B00
+#define BLSP2_UART4_BCR           0x0B40
+#define BLSP2_QUP5_BCR            0x0B80
+#define BLSP2_UART5_BCR           0x0BC0
+#define BLSP2_QUP6_BCR            0x0C00
+#define BLSP2_UART6_BCR           0x0C40
+#define BOOT_ROM_BCR              0x0E00
+#define PDM_BCR                   0x0CC0
+#define PRNG_BCR                  0x0D00
+#define BAM_DMA_BCR               0x0D40
+#define TSIF_BCR                  0x0D80
+#define CE1_BCR                   0x1040
+#define CE2_BCR                   0x1080
+#define AUDIO_CORE_BCR            0x4000
+#define VENUS0_BCR                0x1020
+#define MDSS_BCR                  0x2300
+#define CAMSS_PHY0_BCR            0x3020
+#define CAMSS_PHY1_BCR            0x3050
+#define CAMSS_PHY2_BCR            0x3080
+#define CAMSS_CSI0_BCR            0x30B0
+#define CAMSS_CSI0PHY_BCR         0x30C0
+#define CAMSS_CSI0RDI_BCR         0x30D0
+#define CAMSS_CSI0PIX_BCR         0x30E0
+#define CAMSS_CSI1_BCR            0x3120
+#define CAMSS_CSI1PHY_BCR         0x3130
+#define CAMSS_CSI1RDI_BCR         0x3140
+#define CAMSS_CSI1PIX_BCR         0x3150
+#define CAMSS_CSI2_BCR            0x3180
+#define CAMSS_CSI2PHY_BCR         0x3190
+#define CAMSS_CSI2RDI_BCR         0x31A0
+#define CAMSS_CSI2PIX_BCR         0x31B0
+#define CAMSS_CSI3_BCR            0x31E0
+#define CAMSS_CSI3PHY_BCR         0x31F0
+#define CAMSS_CSI3RDI_BCR         0x3200
+#define CAMSS_CSI3PIX_BCR         0x3210
+#define CAMSS_ISPIF_BCR           0x3220
+#define CAMSS_CCI_BCR             0x3340
+#define CAMSS_MCLK0_BCR           0x3380
+#define CAMSS_MCLK1_BCR           0x33B0
+#define CAMSS_MCLK2_BCR           0x33E0
+#define CAMSS_MCLK3_BCR           0x3410
+#define CAMSS_GP0_BCR             0x3440
+#define CAMSS_GP1_BCR             0x3470
+#define CAMSS_TOP_BCR             0x3480
+#define CAMSS_MICRO_BCR           0x3490
+#define CAMSS_JPEG_BCR            0x35A0
+#define CAMSS_VFE_BCR             0x36A0
+#define CAMSS_CSI_VFE0_BCR        0x3700
+#define CAMSS_CSI_VFE1_BCR        0x3710
+#define OCMEMNOC_BCR              0x50B0
+#define MMSSNOCAHB_BCR            0x5020
+#define MMSSNOCAXI_BCR            0x5060
+#define OXILI_GFX3D_CBCR          0x4028
+#define OXILICX_AHB_CBCR          0x403C
+#define OXILICX_AXI_CBCR          0x4038
+#define OXILI_BCR                 0x4020
+#define OXILICX_BCR               0x4030
+#define LPASS_Q6SS_BCR            0x6000
+#define MSS_Q6SS_BCR              0x1068
+
+#define OCMEM_SYS_NOC_AXI_CBCR                   0x0244
+#define OCMEM_NOC_CFG_AHB_CBCR                   0x0248
+#define MMSS_NOC_CFG_AHB_CBCR                    0x024C
+
+#define USB30_MASTER_CBCR                        0x03C8
+#define USB30_MOCK_UTMI_CBCR                     0x03D0
+#define USB_HSIC_AHB_CBCR                        0x0408
+#define USB_HSIC_SYSTEM_CBCR                     0x040C
+#define USB_HSIC_CBCR                            0x0410
+#define USB_HSIC_IO_CAL_CBCR                     0x0414
+#define USB_HS_SYSTEM_CBCR                       0x0484
+#define USB_HS_AHB_CBCR                          0x0488
+#define SDCC1_APPS_CBCR                          0x04C4
+#define SDCC1_AHB_CBCR                           0x04C8
+#define SDCC2_APPS_CBCR                          0x0504
+#define SDCC2_AHB_CBCR                           0x0508
+#define SDCC3_APPS_CBCR                          0x0544
+#define SDCC3_AHB_CBCR                           0x0548
+#define SDCC4_APPS_CBCR                          0x0584
+#define SDCC4_AHB_CBCR                           0x0588
+#define BLSP1_AHB_CBCR                           0x05C4
+#define BLSP1_QUP1_SPI_APPS_CBCR                 0x0644
+#define BLSP1_QUP1_I2C_APPS_CBCR                 0x0648
+#define BLSP1_UART1_APPS_CBCR                    0x0684
+#define BLSP1_UART1_SIM_CBCR                     0x0688
+#define BLSP1_QUP2_SPI_APPS_CBCR                 0x06C4
+#define BLSP1_QUP2_I2C_APPS_CBCR                 0x06C8
+#define BLSP1_UART2_APPS_CBCR                    0x0704
+#define BLSP1_UART2_SIM_CBCR                     0x0708
+#define BLSP1_QUP3_SPI_APPS_CBCR                 0x0744
+#define BLSP1_QUP3_I2C_APPS_CBCR                 0x0748
+#define BLSP1_UART3_APPS_CBCR                    0x0784
+#define BLSP1_UART3_SIM_CBCR                     0x0788
+#define BLSP1_QUP4_SPI_APPS_CBCR                 0x07C4
+#define BLSP1_QUP4_I2C_APPS_CBCR                 0x07C8
+#define BLSP1_UART4_APPS_CBCR                    0x0804
+#define BLSP1_UART4_SIM_CBCR                     0x0808
+#define BLSP1_QUP5_SPI_APPS_CBCR                 0x0844
+#define BLSP1_QUP5_I2C_APPS_CBCR                 0x0848
+#define BLSP1_UART5_APPS_CBCR                    0x0884
+#define BLSP1_UART5_SIM_CBCR                     0x0888
+#define BLSP1_QUP6_SPI_APPS_CBCR                 0x08C4
+#define BLSP1_QUP6_I2C_APPS_CBCR                 0x08C8
+#define BLSP1_UART6_APPS_CBCR                    0x0904
+#define BLSP1_UART6_SIM_CBCR                     0x0908
+#define BLSP2_AHB_CBCR                           0x0944
+#define BOOT_ROM_AHB_CBCR                        0x0E04
+#define BLSP2_QUP1_SPI_APPS_CBCR                 0x0984
+#define BLSP2_QUP1_I2C_APPS_CBCR                 0x0988
+#define BLSP2_UART1_APPS_CBCR                    0x09C4
+#define BLSP2_UART1_SIM_CBCR                     0x09C8
+#define BLSP2_QUP2_SPI_APPS_CBCR                 0x0A04
+#define BLSP2_QUP2_I2C_APPS_CBCR                 0x0A08
+#define BLSP2_UART2_APPS_CBCR                    0x0A44
+#define BLSP2_UART2_SIM_CBCR                     0x0A48
+#define BLSP2_QUP3_SPI_APPS_CBCR                 0x0A84
+#define BLSP2_QUP3_I2C_APPS_CBCR                 0x0A88
+#define BLSP2_UART3_APPS_CBCR                    0x0AC4
+#define BLSP2_UART3_SIM_CBCR                     0x0AC8
+#define BLSP2_QUP4_SPI_APPS_CBCR                 0x0B04
+#define BLSP2_QUP4_I2C_APPS_CBCR                 0x0B08
+#define BLSP2_UART4_APPS_CBCR                    0x0B44
+#define BLSP2_UART4_SIM_CBCR                     0x0B48
+#define BLSP2_QUP5_SPI_APPS_CBCR                 0x0B84
+#define BLSP2_QUP5_I2C_APPS_CBCR                 0x0B88
+#define BLSP2_UART5_APPS_CBCR                    0x0BC4
+#define BLSP2_UART5_SIM_CBCR                     0x0BC8
+#define BLSP2_QUP6_SPI_APPS_CBCR                 0x0C04
+#define BLSP2_QUP6_I2C_APPS_CBCR                 0x0C08
+#define BLSP2_UART6_APPS_CBCR                    0x0C44
+#define BLSP2_UART6_SIM_CBCR                     0x0C48
+#define PDM_AHB_CBCR                             0x0CC4
+#define PDM_XO4_CBCR                             0x0CC8
+#define PDM2_CBCR                                0x0CCC
+#define PRNG_AHB_CBCR                            0x0D04
+#define BAM_DMA_AHB_CBCR                         0x0D44
+#define TSIF_AHB_CBCR                            0x0D84
+#define TSIF_REF_CBCR                            0x0D88
+#define MSG_RAM_AHB_CBCR                         0x0E44
+#define CE1_CBCR                                 0x1044
+#define CE1_AXI_CBCR                             0x1048
+#define CE1_AHB_CBCR                             0x104C
+#define CE2_CBCR                                 0x1084
+#define CE2_AXI_CBCR                             0x1088
+#define CE2_AHB_CBCR                             0x108C
+#define GCC_AHB_CBCR                             0x10C0
+#define GP1_CBCR                                 0x1900
+#define GP2_CBCR                                 0x1940
+#define GP3_CBCR                                 0x1980
+#define AUDIO_CORE_LPAIF_CODEC_SPKR_OSR_CBCR     0xA014
+#define AUDIO_CORE_LPAIF_CODEC_SPKR_IBIT_CBCR    0xA018
+#define AUDIO_CORE_LPAIF_CODEC_SPKR_EBIT_CBCR    0xA01C
+#define AUDIO_CORE_LPAIF_PRI_OSR_CBCR            0xB014
+#define AUDIO_CORE_LPAIF_PRI_IBIT_CBCR           0xB018
+#define AUDIO_CORE_LPAIF_PRI_EBIT_CBCR           0xB01C
+#define AUDIO_CORE_LPAIF_SEC_OSR_CBCR            0xC014
+#define AUDIO_CORE_LPAIF_SEC_IBIT_CBCR           0xC018
+#define AUDIO_CORE_LPAIF_SEC_EBIT_CBCR           0xC01C
+#define AUDIO_CORE_LPAIF_TER_OSR_CBCR            0xD014
+#define AUDIO_CORE_LPAIF_TER_IBIT_CBCR           0xD018
+#define AUDIO_CORE_LPAIF_TER_EBIT_CBCR           0xD01C
+#define AUDIO_CORE_LPAIF_QUAD_OSR_CBCR           0xE014
+#define AUDIO_CORE_LPAIF_QUAD_IBIT_CBCR          0xE018
+#define AUDIO_CORE_LPAIF_QUAD_EBIT_CBCR          0xE01C
+#define AUDIO_CORE_LPAIF_PCM0_IBIT_CBCR          0xF014
+#define AUDIO_CORE_LPAIF_PCM0_EBIT_CBCR          0xF018
+#define AUDIO_CORE_LPAIF_PCM1_IBIT_CBCR          0x10014
+#define AUDIO_CORE_LPAIF_PCM1_EBIT_CBCR          0x10018
+#define AUDIO_CORE_RESAMPLER_CORE_CBCR           0x11014
+#define AUDIO_CORE_RESAMPLER_LFABIF_CBCR         0x11018
+#define AUDIO_CORE_SLIMBUS_CORE_CBCR             0x12014
+#define AUDIO_CORE_SLIMBUS_LFABIF_CBCR           0x12018
+#define AUDIO_CORE_LPAIF_PCM_DATA_OE_CBCR        0x13014
+#define VENUS0_VCODEC0_CBCR                      0x1028
+#define VENUS0_AHB_CBCR                          0x1030
+#define VENUS0_AXI_CBCR                          0x1034
+#define VENUS0_OCMEMNOC_CBCR                     0x1038
+#define MDSS_AHB_CBCR                            0x2308
+#define MDSS_HDMI_AHB_CBCR                       0x230C
+#define MDSS_AXI_CBCR                            0x2310
+#define MDSS_PCLK0_CBCR                          0x2314
+#define MDSS_PCLK1_CBCR                          0x2318
+#define MDSS_MDP_CBCR                            0x231C
+#define MDSS_MDP_LUT_CBCR                        0x2320
+#define MDSS_EXTPCLK_CBCR                        0x2324
+#define MDSS_VSYNC_CBCR                          0x2328
+#define MDSS_EDPPIXEL_CBCR                       0x232C
+#define MDSS_EDPLINK_CBCR                        0x2330
+#define MDSS_EDPAUX_CBCR                         0x2334
+#define MDSS_HDMI_CBCR                           0x2338
+#define MDSS_BYTE0_CBCR                          0x233C
+#define MDSS_BYTE1_CBCR                          0x2340
+#define MDSS_ESC0_CBCR                           0x2344
+#define MDSS_ESC1_CBCR                           0x2348
+#define CAMSS_PHY0_CSI0PHYTIMER_CBCR             0x3024
+#define CAMSS_PHY1_CSI1PHYTIMER_CBCR             0x3054
+#define CAMSS_PHY2_CSI2PHYTIMER_CBCR             0x3084
+#define CAMSS_CSI0_CBCR                          0x30B4
+#define CAMSS_CSI0_AHB_CBCR                      0x30BC
+#define CAMSS_CSI0PHY_CBCR                       0x30C4
+#define CAMSS_CSI0RDI_CBCR                       0x30D4
+#define CAMSS_CSI0PIX_CBCR                       0x30E4
+#define CAMSS_CSI1_CBCR                          0x3124
+#define CAMSS_CSI1_AHB_CBCR                      0x3128
+#define CAMSS_CSI1PHY_CBCR                       0x3134
+#define CAMSS_CSI1RDI_CBCR                       0x3144
+#define CAMSS_CSI1PIX_CBCR                       0x3154
+#define CAMSS_CSI2_CBCR                          0x3184
+#define CAMSS_CSI2_AHB_CBCR                      0x3188
+#define CAMSS_CSI2PHY_CBCR                       0x3194
+#define CAMSS_CSI2RDI_CBCR                       0x31A4
+#define CAMSS_CSI2PIX_CBCR                       0x31B4
+#define CAMSS_CSI3_CBCR                          0x31E4
+#define CAMSS_CSI3_AHB_CBCR                      0x31E8
+#define CAMSS_CSI3PHY_CBCR                       0x31F4
+#define CAMSS_CSI3RDI_CBCR                       0x3204
+#define CAMSS_CSI3PIX_CBCR                       0x3214
+#define CAMSS_ISPIF_AHB_CBCR                     0x3224
+#define CAMSS_CCI_CCI_CBCR                       0x3344
+#define CAMSS_CCI_CCI_AHB_CBCR                   0x3348
+#define CAMSS_MCLK0_CBCR                         0x3384
+#define CAMSS_MCLK1_CBCR                         0x33B4
+#define CAMSS_MCLK2_CBCR                         0x33E4
+#define CAMSS_MCLK3_CBCR                         0x3414
+#define CAMSS_GP0_CBCR                           0x3444
+#define CAMSS_GP1_CBCR                           0x3474
+#define CAMSS_TOP_AHB_CBCR                       0x3484
+#define CAMSS_MICRO_AHB_CBCR                     0x3494
+#define CAMSS_JPEG_JPEG0_CBCR                    0x35A8
+#define CAMSS_JPEG_JPEG1_CBCR                    0x35AC
+#define CAMSS_JPEG_JPEG2_CBCR                    0x35B0
+#define CAMSS_JPEG_JPEG_AHB_CBCR                 0x35B4
+#define CAMSS_JPEG_JPEG_AXI_CBCR                 0x35B8
+#define CAMSS_JPEG_JPEG_OCMEMNOC_CBCR            0x35BC
+#define CAMSS_VFE_VFE0_CBCR                      0x36A8
+#define CAMSS_VFE_VFE1_CBCR                      0x36AC
+#define CAMSS_VFE_CPP_CBCR                       0x36B0
+#define CAMSS_VFE_CPP_AHB_CBCR                   0x36B4
+#define CAMSS_VFE_VFE_AHB_CBCR                   0x36B8
+#define CAMSS_VFE_VFE_AXI_CBCR                   0x36BC
+#define CAMSS_VFE_VFE_OCMEMNOC_CBCR              0x36C0
+#define CAMSS_CSI_VFE0_CBCR                      0x3704
+#define CAMSS_CSI_VFE1_CBCR                      0x3714
+#define MMSS_MMSSNOC_AXI_CBCR                    0x506C
+#define MMSS_MMSSNOC_AHB_CBCR                    0x5024
+#define MMSS_MMSSNOC_BTO_AHB_CBCR                0x5028
+#define MMSS_MISC_AHB_CBCR                       0x502C
+#define MMSS_S0_AXI_CBCR                         0x5064
+#define OCMEMNOC_CBCR                            0x50B4
+#define LPASS_Q6SS_AHB_LFABIF_CBCR               0x22000
+#define LPASS_Q6SS_XO_CBCR                       0x26000
+#define MSS_XO_Q6_CBCR                           0x108C
+#define MSS_BUS_Q6_CBCR                          0x10A4
+#define MSS_CFG_AHB_CBCR                         0x0280
+
+#define APCS_CLOCK_BRANCH_ENA_VOTE 0x1484
+#define APCS_CLOCK_SLEEP_ENA_VOTE  0x1488
+
+/* Mux source select values */
+#define cxo_source_val	0
+#define gpll0_source_val 1
+#define gpll1_source_val 2
+#define gnd_source_val	5
+#define mmpll0_mm_source_val 1
+#define mmpll1_mm_source_val 2
+#define mmpll3_mm_source_val 3
+#define gpll0_mm_source_val 5
+#define cxo_mm_source_val 0
+#define mm_gnd_source_val 6
+#define gpll1_hsic_source_val 4
+#define cxo_lpass_source_val 0
+#define lpapll0_lpass_source_val 1
+#define gpll0_lpass_source_val 5
+#define edppll_270_mm_source_val 4
+#define edppll_350_mm_source_val 4
+#define dsipll_750_mm_source_val 1
+#define dsipll_250_mm_source_val 2
+#define hdmipll_297_mm_source_val 3
+
+#define F(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.src_clk = &s##_clk_src.c, \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+			| BVAL(10, 8, s##_source_val), \
+	}
+
+#define F_MM(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.src_clk = &s##_clk_src.c, \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+			| BVAL(10, 8, s##_mm_source_val), \
+	}
+
+#define F_MDSS(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+			| BVAL(10, 8, s##_mm_source_val), \
+	}
+
+#define F_HSIC(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.src_clk = &s##_clk_src.c, \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+			| BVAL(10, 8, s##_hsic_source_val), \
+	}
+
+#define F_LPASS(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.src_clk = &s##_clk_src.c, \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+			| BVAL(10, 8, s##_lpass_source_val), \
+	}
+
+#define VDD_DIG_FMAX_MAP1(l1, f1) \
+	.vdd_class = &vdd_dig, \
+	.fmax[VDD_DIG_##l1] = (f1)
+#define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
+	.vdd_class = &vdd_dig, \
+	.fmax[VDD_DIG_##l1] = (f1), \
+	.fmax[VDD_DIG_##l2] = (f2)
+#define VDD_DIG_FMAX_MAP3(l1, f1, l2, f2, l3, f3) \
+	.vdd_class = &vdd_dig, \
+	.fmax[VDD_DIG_##l1] = (f1), \
+	.fmax[VDD_DIG_##l2] = (f2), \
+	.fmax[VDD_DIG_##l3] = (f3)
+
+enum vdd_dig_levels {
+	VDD_DIG_NONE,
+	VDD_DIG_LOW,
+	VDD_DIG_NOMINAL,
+	VDD_DIG_HIGH
+};
+
+static int set_vdd_dig(struct clk_vdd_class *vdd_class, int level)
+{
+	/* TODO: Actually call into regulator APIs to set VDD_DIG here. */
+	return 0;
+}
+
+static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig);
+
+static int cxo_clk_enable(struct clk *clk)
+{
+	/* TODO: Remove from here once the rpm xo clock is ready. */
+	return 0;
+}
+
+static void cxo_clk_disable(struct clk *clk)
+{
+	/* TODO: Remove from here once the rpm xo clock is ready. */
+	return;
+}
+
+static enum handoff cxo_clk_handoff(struct clk *clk)
+{
+	/* TODO: Remove from here once the rpm xo clock is ready. */
+	return HANDOFF_ENABLED_CLK;
+}
+
+static struct clk_ops clk_ops_cxo = {
+	.enable = cxo_clk_enable,
+	.disable = cxo_clk_disable,
+	.handoff = cxo_clk_handoff,
+};
+
+static struct fixed_clk cxo_clk_src = {
+	.c = {
+		.rate = 19200000,
+		.dbg_name = "cxo_clk_src",
+		.ops = &clk_ops_cxo,
+		.warned = true,
+		CLK_INIT(cxo_clk_src.c),
+	},
+};
+
+static struct pll_vote_clk gpll0_clk_src = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE_REG,
+	.en_mask = BIT(0),
+	.status_reg = (void __iomem *)GPLL0_STATUS_REG,
+	.status_mask = BIT(17),
+	.parent = &cxo_clk_src.c,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.rate = 600000000,
+		.dbg_name = "gpll0_clk_src",
+		.ops = &clk_ops_pll_vote,
+		.warned = true,
+		CLK_INIT(gpll0_clk_src.c),
+	},
+};
+
+static struct pll_vote_clk gpll1_clk_src = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE_REG,
+	.en_mask = BIT(1),
+	.status_reg = (void __iomem *)GPLL1_STATUS_REG,
+	.status_mask = BIT(17),
+	.parent = &cxo_clk_src.c,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.rate = 480000000,
+		.dbg_name = "gpll1_clk_src",
+		.ops = &clk_ops_pll_vote,
+		.warned = true,
+		CLK_INIT(gpll1_clk_src.c),
+	},
+};
+
+static struct pll_vote_clk lpapll0_clk_src = {
+	.en_reg = (void __iomem *)LPASS_LPA_PLL_VOTE_APPS_REG,
+	.en_mask = BIT(0),
+	.status_reg = (void __iomem *)LPAPLL_STATUS_REG,
+	.status_mask = BIT(17),
+	.parent = &cxo_clk_src.c,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.rate = 491520000,
+		.dbg_name = "lpapll0_clk_src",
+		.ops = &clk_ops_pll_vote,
+		.warned = true,
+		CLK_INIT(lpapll0_clk_src.c),
+	},
+};
+
+static struct pll_vote_clk mmpll0_clk_src = {
+	.en_reg = (void __iomem *)MMSS_PLL_VOTE_APCS_REG,
+	.en_mask = BIT(0),
+	.status_reg = (void __iomem *)MMPLL0_STATUS_REG,
+	.status_mask = BIT(17),
+	.parent = &cxo_clk_src.c,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mmpll0_clk_src",
+		.rate = 800000000,
+		.ops = &clk_ops_pll_vote,
+		.warned = true,
+		CLK_INIT(mmpll0_clk_src.c),
+	},
+};
+
+static struct pll_vote_clk mmpll1_clk_src = {
+	.en_reg = (void __iomem *)MMSS_PLL_VOTE_APCS_REG,
+	.en_mask = BIT(1),
+	.status_reg = (void __iomem *)MMPLL1_STATUS_REG,
+	.status_mask = BIT(17),
+	.parent = &cxo_clk_src.c,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mmpll1_clk_src",
+		.rate = 1000000000,
+		.ops = &clk_ops_pll_vote,
+		.warned = true,
+		CLK_INIT(mmpll1_clk_src.c),
+	},
+};
+
+static struct pll_clk mmpll3_clk_src = {
+	.mode_reg = (void __iomem *)MMPLL3_MODE_REG,
+	.status_reg = (void __iomem *)MMPLL3_STATUS_REG,
+	.parent = &cxo_clk_src.c,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mmpll3_clk_src",
+		.rate = 1000000000,
+		.ops = &clk_ops_local_pll,
+		CLK_INIT(mmpll3_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb30_master_clk[] = {
+	F(125000000,  gpll0,   1,   5,  24),
+	F_END
+};
+
+static struct rcg_clk usb30_master_clk_src = {
+	.cmd_rcgr_reg = USB30_MASTER_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_usb30_master_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb30_master_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 125000000),
+		CLK_INIT(usb30_master_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk[] = {
+	F(  960000,    cxo,  10,   1,   2),
+	F( 4800000,    cxo,   4,   0,   0),
+	F( 9600000,    cxo,   2,   0,   0),
+	F(15000000,  gpll0,  10,   1,   4),
+	F(19200000,    cxo,   1,   0,   0),
+	F(25000000,  gpll0,  12,   1,   2),
+	F(50000000,  gpll0,  12,   0,   0),
+	F_END
+};
+
+static struct rcg_clk blsp1_qup1_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP1_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup1_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup1_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup2_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP2_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup2_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup2_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup3_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP3_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup3_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup3_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup4_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP4_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup4_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup4_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup5_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP5_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup5_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup5_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup6_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP6_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup6_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup6_spi_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_2_uart1_6_apps_clk[] = {
+	F( 3686400,  gpll0,    1,  96,  15625),
+	F( 7372800,  gpll0,    1, 192,  15625),
+	F(14745600,  gpll0,    1, 384,  15625),
+	F(16000000,  gpll0,    5,   2,     15),
+	F(19200000,    cxo,    1,   0,      0),
+	F(24000000,  gpll0,    5,   1,      5),
+	F(32000000,  gpll0,    1,   4,     75),
+	F(40000000,  gpll0,   15,   0,      0),
+	F(46400000,  gpll0,    1,  29,    375),
+	F(48000000,  gpll0, 12.5,   0,      0),
+	F(51200000,  gpll0,    1,  32,    375),
+	F(56000000,  gpll0,    1,   7,     75),
+	F(58982400,  gpll0,    1, 1536, 15625),
+	F(60000000,  gpll0,   10,   0,      0),
+	F_END
+};
+
+static struct rcg_clk blsp1_uart1_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART1_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart1_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart1_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart2_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART2_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart2_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart2_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart3_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART3_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart3_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart3_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart4_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART4_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart4_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart4_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart5_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART5_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart5_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart5_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart6_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART6_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart6_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart6_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup1_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_QUP1_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup1_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp2_qup1_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup2_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_QUP2_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup2_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp2_qup2_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup3_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_QUP3_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup3_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp2_qup3_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup4_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_QUP4_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup4_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp2_qup4_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup5_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_QUP5_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup5_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp2_qup5_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup6_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_QUP6_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup6_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp2_qup6_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_uart1_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_UART1_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_uart1_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp2_uart1_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_uart2_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_UART2_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_uart2_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp2_uart2_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_uart3_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_UART3_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_uart3_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp2_uart3_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_uart4_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_UART4_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_uart4_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp2_uart4_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_uart5_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_UART5_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_uart5_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp2_uart5_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_uart6_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_UART6_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_uart6_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp2_uart6_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_ce1_clk[] = {
+	F( 50000000,  gpll0,  12,   0,   0),
+	F(100000000,  gpll0,   6,   0,   0),
+	F_END
+};
+
+static struct rcg_clk ce1_clk_src = {
+	.cmd_rcgr_reg = CE1_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_ce1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "ce1_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 50000000, NOMINAL, 100000000),
+		CLK_INIT(ce1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_ce2_clk[] = {
+	F( 50000000,  gpll0,  12,   0,   0),
+	F(100000000,  gpll0,   6,   0,   0),
+	F_END
+};
+
+static struct rcg_clk ce2_clk_src = {
+	.cmd_rcgr_reg = CE2_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_ce2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "ce2_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 50000000, NOMINAL, 100000000),
+		CLK_INIT(ce2_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_gp_clk[] = {
+	F(19200000,  cxo,  1,   0,   0),
+	F_END
+};
+
+static struct rcg_clk gp1_clk_src = {
+	.cmd_rcgr_reg = GP1_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_gp_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gp1_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(gp1_clk_src.c),
+	},
+};
+
+static struct rcg_clk gp2_clk_src = {
+	.cmd_rcgr_reg = GP2_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_gp_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gp2_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(gp2_clk_src.c),
+	},
+};
+
+static struct rcg_clk gp3_clk_src = {
+	.cmd_rcgr_reg = GP3_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_gp_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gp3_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(gp3_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_pdm2_clk[] = {
+	F(60000000,  gpll0,  10,   0,   0),
+	F_END
+};
+
+static struct rcg_clk pdm2_clk_src = {
+	.cmd_rcgr_reg = PDM2_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_pdm2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "pdm2_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 60000000),
+		CLK_INIT(pdm2_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_sdcc1_2_apps_clk[] = {
+	F(   144000,    cxo,  16,   3,  25),
+	F(   400000,    cxo,  12,   1,   4),
+	F( 20000000,  gpll0,  15,   1,   2),
+	F( 25000000,  gpll0,  12,   1,   2),
+	F( 50000000,  gpll0,  12,   0,   0),
+	F(100000000,  gpll0,   6,   0,   0),
+	F(200000000,  gpll0,   3,   0,   0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_sdcc3_4_apps_clk[] = {
+	F(   144000,    cxo,  16,   3,  25),
+	F(   400000,    cxo,  12,   1,   4),
+	F( 20000000,  gpll0,  15,   1,   2),
+	F( 25000000,  gpll0,  12,   1,   2),
+	F( 50000000,  gpll0,  12,   0,   0),
+	F(100000000,  gpll0,   6,   0,   0),
+	F_END
+};
+
+static struct rcg_clk sdcc1_apps_clk_src = {
+	.cmd_rcgr_reg = SDCC1_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_sdcc1_2_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "sdcc1_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(sdcc1_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk sdcc2_apps_clk_src = {
+	.cmd_rcgr_reg = SDCC2_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_sdcc1_2_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "sdcc2_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(sdcc2_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk sdcc3_apps_clk_src = {
+	.cmd_rcgr_reg = SDCC3_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_sdcc3_4_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "sdcc3_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 50000000, NOMINAL, 100000000),
+		CLK_INIT(sdcc3_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk sdcc4_apps_clk_src = {
+	.cmd_rcgr_reg = SDCC4_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_sdcc3_4_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "sdcc4_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 50000000, NOMINAL, 100000000),
+		CLK_INIT(sdcc4_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_tsif_ref_clk[] = {
+	F(105000,    cxo,   2,   1,  91),
+	F_END
+};
+
+static struct rcg_clk tsif_ref_clk_src = {
+	.cmd_rcgr_reg = TSIF_REF_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_tsif_ref_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "tsif_ref_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOW, 105500),
+		CLK_INIT(tsif_ref_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb30_mock_utmi_clk[] = {
+	F(60000000,  gpll0,   10,   0,   0),
+	F_END
+};
+
+static struct rcg_clk usb30_mock_utmi_clk_src = {
+	.cmd_rcgr_reg = USB30_MOCK_UTMI_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_usb30_mock_utmi_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb30_mock_utmi_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 60000000),
+		CLK_INIT(usb30_mock_utmi_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hs_system_clk[] = {
+	F(75000000,  gpll0,   8,   0,   0),
+	F_END
+};
+
+static struct rcg_clk usb_hs_system_clk_src = {
+	.cmd_rcgr_reg = USB_HS_SYSTEM_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_usb_hs_system_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_hs_system_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 37500000, NOMINAL, 75000000),
+		CLK_INIT(usb_hs_system_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hsic_clk[] = {
+	F_HSIC(480000000,  gpll1,   1,   0,   0),
+	F_END
+};
+
+static struct rcg_clk usb_hsic_clk_src = {
+	.cmd_rcgr_reg = USB_HSIC_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_usb_hsic_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_hsic_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 480000000),
+		CLK_INIT(usb_hsic_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hsic_io_cal_clk[] = {
+	F(9600000,    cxo,   2,   0,   0),
+	F_END
+};
+
+static struct rcg_clk usb_hsic_io_cal_clk_src = {
+	.cmd_rcgr_reg = USB_HSIC_IO_CAL_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_usb_hsic_io_cal_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_hsic_io_cal_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 9600000),
+		CLK_INIT(usb_hsic_io_cal_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hsic_system_clk[] = {
+	F(75000000,  gpll0,   8,   0,   0),
+	F_END
+};
+
+static struct rcg_clk usb_hsic_system_clk_src = {
+	.cmd_rcgr_reg = USB_HSIC_SYSTEM_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_usb_hsic_system_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_hsic_system_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 37500000, NOMINAL, 75000000),
+		CLK_INIT(usb_hsic_system_clk_src.c),
+	},
+};
+
+static struct local_vote_clk gcc_bam_dma_ahb_clk = {
+	.cbcr_reg = BAM_DMA_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(12),
+	.bcr_reg = BAM_DMA_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_bam_dma_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_bam_dma_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_blsp1_ahb_clk = {
+	.cbcr_reg = BLSP1_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(17),
+	.bcr_reg = BLSP1_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_blsp1_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup1_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP1_I2C_APPS_CBCR,
+	.parent = &cxo_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = BLSP1_QUP1_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup1_i2c_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup1_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup1_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP1_SPI_APPS_CBCR,
+	.parent = &blsp1_qup1_spi_apps_clk_src.c,
+	.bcr_reg = BLSP1_QUP1_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup1_spi_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup1_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup2_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP2_I2C_APPS_CBCR,
+	.parent = &cxo_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = BLSP1_QUP2_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup2_i2c_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup2_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup2_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP2_SPI_APPS_CBCR,
+	.parent = &blsp1_qup2_spi_apps_clk_src.c,
+	.bcr_reg = BLSP1_QUP2_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup2_spi_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup2_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup3_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP3_I2C_APPS_CBCR,
+	.parent = &cxo_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = BLSP1_QUP3_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup3_i2c_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup3_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup3_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP3_SPI_APPS_CBCR,
+	.parent = &blsp1_qup3_spi_apps_clk_src.c,
+	.bcr_reg = BLSP1_QUP3_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup3_spi_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup3_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup4_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP4_I2C_APPS_CBCR,
+	.parent = &cxo_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = BLSP1_QUP4_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup4_i2c_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup4_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup4_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP4_SPI_APPS_CBCR,
+	.parent = &blsp1_qup4_spi_apps_clk_src.c,
+	.bcr_reg = BLSP1_QUP4_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup4_spi_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup4_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup5_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP5_I2C_APPS_CBCR,
+	.parent = &cxo_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = BLSP1_QUP5_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup5_i2c_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup5_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup5_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP5_SPI_APPS_CBCR,
+	.parent = &blsp1_qup5_spi_apps_clk_src.c,
+	.bcr_reg = BLSP1_QUP5_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup5_spi_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup5_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup6_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP6_I2C_APPS_CBCR,
+	.parent = &cxo_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = BLSP1_QUP6_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup6_i2c_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup6_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup6_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP6_SPI_APPS_CBCR,
+	.parent = &blsp1_qup6_spi_apps_clk_src.c,
+	.bcr_reg = BLSP1_QUP6_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup6_spi_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup6_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart1_apps_clk = {
+	.cbcr_reg = BLSP1_UART1_APPS_CBCR,
+	.parent = &blsp1_uart1_apps_clk_src.c,
+	.bcr_reg = BLSP1_UART1_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart1_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart1_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart2_apps_clk = {
+	.cbcr_reg = BLSP1_UART2_APPS_CBCR,
+	.parent = &blsp1_uart2_apps_clk_src.c,
+	.bcr_reg = BLSP1_UART2_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart2_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart2_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart3_apps_clk = {
+	.cbcr_reg = BLSP1_UART3_APPS_CBCR,
+	.parent = &blsp1_uart3_apps_clk_src.c,
+	.bcr_reg = BLSP1_UART3_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart3_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart3_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart4_apps_clk = {
+	.cbcr_reg = BLSP1_UART4_APPS_CBCR,
+	.parent = &blsp1_uart4_apps_clk_src.c,
+	.bcr_reg = BLSP1_UART4_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart4_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart4_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart5_apps_clk = {
+	.cbcr_reg = BLSP1_UART5_APPS_CBCR,
+	.parent = &blsp1_uart5_apps_clk_src.c,
+	.bcr_reg = BLSP1_UART5_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart5_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart5_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart6_apps_clk = {
+	.cbcr_reg = BLSP1_UART6_APPS_CBCR,
+	.parent = &blsp1_uart6_apps_clk_src.c,
+	.bcr_reg = BLSP1_UART6_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart6_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart6_apps_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_boot_rom_ahb_clk = {
+	.cbcr_reg = BOOT_ROM_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(10),
+	.bcr_reg = BOOT_ROM_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_boot_rom_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_boot_rom_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_blsp2_ahb_clk = {
+	.cbcr_reg = BLSP2_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(15),
+	.bcr_reg = BLSP2_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_blsp2_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup1_i2c_apps_clk = {
+	.cbcr_reg = BLSP2_QUP1_I2C_APPS_CBCR,
+	.parent = &cxo_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = BLSP2_QUP1_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup1_i2c_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup1_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup1_spi_apps_clk = {
+	.cbcr_reg = BLSP2_QUP1_SPI_APPS_CBCR,
+	.parent = &blsp2_qup1_spi_apps_clk_src.c,
+	.bcr_reg = BLSP2_QUP1_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup1_spi_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup1_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup2_i2c_apps_clk = {
+	.cbcr_reg = BLSP2_QUP2_I2C_APPS_CBCR,
+	.parent = &cxo_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = BLSP2_QUP2_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup2_i2c_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup2_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup2_spi_apps_clk = {
+	.cbcr_reg = BLSP2_QUP2_SPI_APPS_CBCR,
+	.parent = &blsp2_qup2_spi_apps_clk_src.c,
+	.bcr_reg = BLSP2_QUP2_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup2_spi_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup2_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup3_i2c_apps_clk = {
+	.cbcr_reg = BLSP2_QUP3_I2C_APPS_CBCR,
+	.parent = &cxo_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = BLSP2_QUP3_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup3_i2c_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup3_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup3_spi_apps_clk = {
+	.cbcr_reg = BLSP2_QUP3_SPI_APPS_CBCR,
+	.parent = &blsp2_qup3_spi_apps_clk_src.c,
+	.bcr_reg = BLSP2_QUP3_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup3_spi_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup3_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup4_i2c_apps_clk = {
+	.cbcr_reg = BLSP2_QUP4_I2C_APPS_CBCR,
+	.parent = &cxo_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = BLSP2_QUP4_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup4_i2c_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup4_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup4_spi_apps_clk = {
+	.cbcr_reg = BLSP2_QUP4_SPI_APPS_CBCR,
+	.parent = &blsp2_qup4_spi_apps_clk_src.c,
+	.bcr_reg = BLSP2_QUP4_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup4_spi_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup4_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup5_i2c_apps_clk = {
+	.cbcr_reg = BLSP2_QUP5_I2C_APPS_CBCR,
+	.parent = &cxo_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = BLSP2_QUP5_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup5_i2c_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup5_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup5_spi_apps_clk = {
+	.cbcr_reg = BLSP2_QUP5_SPI_APPS_CBCR,
+	.parent = &blsp2_qup5_spi_apps_clk_src.c,
+	.bcr_reg = BLSP2_QUP5_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup5_spi_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup5_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup6_i2c_apps_clk = {
+	.cbcr_reg = BLSP2_QUP6_I2C_APPS_CBCR,
+	.parent = &cxo_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = BLSP2_QUP6_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup6_i2c_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup6_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup6_spi_apps_clk = {
+	.cbcr_reg = BLSP2_QUP6_SPI_APPS_CBCR,
+	.parent = &blsp2_qup6_spi_apps_clk_src.c,
+	.bcr_reg = BLSP2_QUP6_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup6_spi_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup6_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_uart1_apps_clk = {
+	.cbcr_reg = BLSP2_UART1_APPS_CBCR,
+	.parent = &blsp2_uart1_apps_clk_src.c,
+	.bcr_reg = BLSP2_UART1_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_uart1_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_uart1_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_uart2_apps_clk = {
+	.cbcr_reg = BLSP2_UART2_APPS_CBCR,
+	.parent = &blsp2_uart2_apps_clk_src.c,
+	.bcr_reg = BLSP2_UART2_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_uart2_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_uart2_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_uart3_apps_clk = {
+	.cbcr_reg = BLSP2_UART3_APPS_CBCR,
+	.parent = &blsp2_uart3_apps_clk_src.c,
+	.bcr_reg = BLSP2_UART3_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_uart3_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_uart3_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_uart4_apps_clk = {
+	.cbcr_reg = BLSP2_UART4_APPS_CBCR,
+	.parent = &blsp2_uart4_apps_clk_src.c,
+	.bcr_reg = BLSP2_UART4_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_uart4_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_uart4_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_uart5_apps_clk = {
+	.cbcr_reg = BLSP2_UART5_APPS_CBCR,
+	.parent = &blsp2_uart5_apps_clk_src.c,
+	.bcr_reg = BLSP2_UART5_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_uart5_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_uart5_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_uart6_apps_clk = {
+	.cbcr_reg = BLSP2_UART6_APPS_CBCR,
+	.parent = &blsp2_uart6_apps_clk_src.c,
+	.bcr_reg = BLSP2_UART6_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_uart6_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_uart6_apps_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_ce1_clk = {
+	.cbcr_reg = CE1_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(5),
+	.bcr_reg = CE1_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_ce1_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_ce1_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_ce1_ahb_clk = {
+	.cbcr_reg = CE1_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(3),
+	.bcr_reg = CE1_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_ce1_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_ce1_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_ce1_axi_clk = {
+	.cbcr_reg = CE1_AXI_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(4),
+	.bcr_reg = CE1_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_ce1_axi_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_ce1_axi_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_ce2_clk = {
+	.cbcr_reg = CE2_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(2),
+	.bcr_reg = CE2_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_ce2_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_ce2_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_ce2_ahb_clk = {
+	.cbcr_reg = CE2_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(0),
+	.bcr_reg = CE2_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_ce1_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_ce1_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_ce2_axi_clk = {
+	.cbcr_reg = CE2_AXI_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(1),
+	.bcr_reg = CE2_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_ce1_axi_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_ce2_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_gp1_clk = {
+	.cbcr_reg = GP1_CBCR,
+	.parent = &gp1_clk_src.c,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_gp1_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_gp1_clk.c),
+	},
+};
+
+static struct branch_clk gcc_gp2_clk = {
+	.cbcr_reg = GP2_CBCR,
+	.parent = &gp2_clk_src.c,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_gp2_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_gp2_clk.c),
+	},
+};
+
+static struct branch_clk gcc_gp3_clk = {
+	.cbcr_reg = GP3_CBCR,
+	.parent = &gp3_clk_src.c,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_gp3_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_gp3_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pdm2_clk = {
+	.cbcr_reg = PDM2_CBCR,
+	.parent = &pdm2_clk_src.c,
+	.bcr_reg = PDM_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_pdm2_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pdm2_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pdm_ahb_clk = {
+	.cbcr_reg = PDM_AHB_CBCR,
+	.has_sibling = 1,
+	.bcr_reg = PDM_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_pdm_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pdm_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_prng_ahb_clk = {
+	.cbcr_reg = PRNG_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(13),
+	.bcr_reg = PRNG_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_prng_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_prng_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc1_ahb_clk = {
+	.cbcr_reg = SDCC1_AHB_CBCR,
+	.has_sibling = 1,
+	.bcr_reg = SDCC1_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc1_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc1_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc1_apps_clk = {
+	.cbcr_reg = SDCC1_APPS_CBCR,
+	.parent = &sdcc1_apps_clk_src.c,
+	.bcr_reg = SDCC1_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc1_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc1_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc2_ahb_clk = {
+	.cbcr_reg = SDCC2_AHB_CBCR,
+	.has_sibling = 1,
+	.bcr_reg = SDCC2_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc2_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc2_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc2_apps_clk = {
+	.cbcr_reg = SDCC2_APPS_CBCR,
+	.parent = &sdcc2_apps_clk_src.c,
+	.bcr_reg = SDCC2_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc2_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc2_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc3_ahb_clk = {
+	.cbcr_reg = SDCC3_AHB_CBCR,
+	.has_sibling = 1,
+	.bcr_reg = SDCC3_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc3_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc3_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc3_apps_clk = {
+	.cbcr_reg = SDCC3_APPS_CBCR,
+	.parent = &sdcc3_apps_clk_src.c,
+	.bcr_reg = SDCC3_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc3_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc3_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc4_ahb_clk = {
+	.cbcr_reg = SDCC4_AHB_CBCR,
+	.has_sibling = 1,
+	.bcr_reg = SDCC4_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc4_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc4_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc4_apps_clk = {
+	.cbcr_reg = SDCC4_APPS_CBCR,
+	.parent = &sdcc4_apps_clk_src.c,
+	.bcr_reg = SDCC4_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc4_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc4_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_tsif_ahb_clk = {
+	.cbcr_reg = TSIF_AHB_CBCR,
+	.has_sibling = 1,
+	.bcr_reg = TSIF_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_tsif_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_tsif_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_tsif_ref_clk = {
+	.cbcr_reg = TSIF_REF_CBCR,
+	.parent = &tsif_ref_clk_src.c,
+	.bcr_reg = TSIF_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_tsif_ref_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_tsif_ref_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb30_master_clk = {
+	.cbcr_reg = USB30_MASTER_CBCR,
+	.parent = &usb30_master_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = USB_30_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb30_master_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb30_master_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb30_mock_utmi_clk = {
+	.cbcr_reg = USB30_MOCK_UTMI_CBCR,
+	.parent = &usb30_mock_utmi_clk_src.c,
+	.bcr_reg = USB_30_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb30_mock_utmi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb30_mock_utmi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hs_ahb_clk = {
+	.cbcr_reg = USB_HS_AHB_CBCR,
+	.has_sibling = 1,
+	.bcr_reg = USB_HS_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hs_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hs_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hs_system_clk = {
+	.cbcr_reg = USB_HS_SYSTEM_CBCR,
+	.parent = &usb_hs_system_clk_src.c,
+	.bcr_reg = USB_HS_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hs_system_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hs_system_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hsic_ahb_clk = {
+	.cbcr_reg = USB_HSIC_AHB_CBCR,
+	.has_sibling = 1,
+	.bcr_reg = USB_HS_HSIC_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hsic_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hsic_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hsic_clk = {
+	.cbcr_reg = USB_HSIC_CBCR,
+	.parent = &usb_hsic_clk_src.c,
+	.bcr_reg = USB_HS_HSIC_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hsic_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hsic_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hsic_io_cal_clk = {
+	.cbcr_reg = USB_HSIC_IO_CAL_CBCR,
+	.parent = &usb_hsic_io_cal_clk_src.c,
+	.bcr_reg = USB_HS_HSIC_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hsic_io_cal_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hsic_io_cal_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hsic_system_clk = {
+	.cbcr_reg = USB_HSIC_SYSTEM_CBCR,
+	.parent = &usb_hsic_system_clk_src.c,
+	.bcr_reg = USB_HS_HSIC_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hsic_system_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hsic_system_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mss_cfg_ahb_clk = {
+	.cbcr_reg = MSS_CFG_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mss_cfg_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mss_cfg_ahb_clk.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mmss_ahb_clk[] = {
+	F_MM(19200000,    cxo,   1,   0,   0),
+	F_MM(40000000,  gpll0,  15,   0,   0),
+	F_MM(80000000, mmpll0,  10,   0,   0),
+	F_END,
+};
+
+/* TODO: This may go away (may be controlled by the RPM). */
+static struct rcg_clk ahb_clk_src = {
+	.cmd_rcgr_reg = 0x5000,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mmss_ahb_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "ahb_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 40000000, NOMINAL, 80000000),
+		CLK_INIT(ahb_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mmss_axi_clk[] = {
+	F_MM( 19200000,    cxo,   1,   0,   0),
+	F_MM(150000000,  gpll0,   4,   0,   0),
+	F_MM(333330000, mmpll1,   3,   0,   0),
+	F_MM(400000000, mmpll0,   2,   0,   0),
+	F_END
+};
+
+static struct rcg_clk axi_clk_src = {
+	.cmd_rcgr_reg = 0x5040,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mmss_axi_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "axi_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 150000000, NOMINAL, 333330000,
+				  HIGH, 400000000),
+		CLK_INIT(axi_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_camss_csi0_3_clk[] = {
+	F_MM(100000000,  gpll0,   6,   0,   0),
+	F_MM(200000000, mmpll0,   4,   0,   0),
+	F_END
+};
+
+static struct rcg_clk csi0_clk_src = {
+	.cmd_rcgr_reg = CSI0_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_csi0_3_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "csi0_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(csi0_clk_src.c),
+	},
+};
+
+static struct rcg_clk csi1_clk_src = {
+	.cmd_rcgr_reg = CSI1_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_csi0_3_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "csi1_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(csi1_clk_src.c),
+	},
+};
+
+static struct rcg_clk csi2_clk_src = {
+	.cmd_rcgr_reg = CSI2_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_csi0_3_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "csi2_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(csi2_clk_src.c),
+	},
+};
+
+static struct rcg_clk csi3_clk_src = {
+	.cmd_rcgr_reg = CSI3_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_csi0_3_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "csi3_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(csi3_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_camss_vfe_vfe0_1_clk[] = {
+	F_MM( 37500000,  gpll0,  16,   0,   0),
+	F_MM( 50000000,  gpll0,  12,   0,   0),
+	F_MM( 60000000,  gpll0,  10,   0,   0),
+	F_MM( 80000000,  gpll0, 7.5,   0,   0),
+	F_MM(100000000,  gpll0,   6,   0,   0),
+	F_MM(109090000,  gpll0, 5.5,   0,   0),
+	F_MM(150000000,  gpll0,   4,   0,   0),
+	F_MM(200000000,  gpll0,   3,   0,   0),
+	F_MM(228570000, mmpll0, 3.5,   0,   0),
+	F_MM(266670000, mmpll0,   3,   0,   0),
+	F_MM(320000000, mmpll0, 2.5,   0,   0),
+	F_END
+};
+
+static struct rcg_clk vfe0_clk_src = {
+	.cmd_rcgr_reg = VFE0_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_vfe_vfe0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "vfe0_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 133330000, NOMINAL, 266670000,
+				  HIGH, 320000000),
+		CLK_INIT(vfe0_clk_src.c),
+	},
+};
+
+static struct rcg_clk vfe1_clk_src = {
+	.cmd_rcgr_reg = VFE1_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_vfe_vfe0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "vfe1_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 133330000, NOMINAL, 266670000,
+				  HIGH, 320000000),
+		CLK_INIT(vfe1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mdss_mdp_clk[] = {
+	F_MM( 37500000,  gpll0,  16,   0,   0),
+	F_MM( 60000000,  gpll0,  10,   0,   0),
+	F_MM( 75000000,  gpll0,   8,   0,   0),
+	F_MM( 85710000,  gpll0,   7,   0,   0),
+	F_MM(100000000,  gpll0,   6,   0,   0),
+	F_MM(133330000, mmpll0,   6,   0,   0),
+	F_MM(160000000, mmpll0,   5,   0,   0),
+	F_MM(200000000, mmpll0,   4,   0,   0),
+	F_MM(266670000, mmpll0,   3,   0,   0),
+	F_MM(320000000, mmpll0, 2.5,   0,   0),
+	F_END
+};
+
+static struct rcg_clk mdp_clk_src = {
+	.cmd_rcgr_reg = MDP_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mdss_mdp_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdp_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 133330000, NOMINAL, 266670000,
+				  HIGH, 320000000),
+		CLK_INIT(mdp_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_camss_cci_cci_clk[] = {
+	F_MM(19200000,    cxo,   1,   0,   0),
+	F_END
+};
+
+static struct rcg_clk cci_clk_src = {
+	.cmd_rcgr_reg = CCI_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_cci_cci_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "cci_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 20000000, NOMINAL, 40000000),
+		CLK_INIT(cci_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_camss_gp0_1_clk[] = {
+	F_MM(   10000,    cxo,  16,   1, 120),
+	F_MM(   20000,    cxo,  16,   1,  50),
+	F_MM( 6000000,  gpll0,  10,   1,  10),
+	F_MM(12000000,  gpll0,  10,   1,   5),
+	F_MM(13000000,  gpll0,  10,  13,  60),
+	F_MM(24000000,  gpll0,   5,   1,   5),
+	F_END
+};
+
+static struct rcg_clk mmss_gp0_clk_src = {
+	.cmd_rcgr_reg = MMSS_GP0_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_camss_gp0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mmss_gp0_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(mmss_gp0_clk_src.c),
+	},
+};
+
+static struct rcg_clk mmss_gp1_clk_src = {
+	.cmd_rcgr_reg = MMSS_GP1_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_camss_gp0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mmss_gp1_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(mmss_gp1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_camss_jpeg_jpeg0_2_clk[] = {
+	F_MM( 75000000,  gpll0,   8,   0,   0),
+	F_MM(150000000,  gpll0,   4,   0,   0),
+	F_MM(200000000,  gpll0,   3,   0,   0),
+	F_MM(228570000, mmpll0, 3.5,   0,   0),
+	F_MM(266670000, mmpll0,   3,   0,   0),
+	F_MM(320000000, mmpll0, 2.5,   0,   0),
+	F_END
+};
+
+static struct rcg_clk jpeg0_clk_src = {
+	.cmd_rcgr_reg = JPEG0_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_jpeg_jpeg0_2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "jpeg0_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 133330000, NOMINAL, 266670000,
+				  HIGH, 320000000),
+		CLK_INIT(jpeg0_clk_src.c),
+	},
+};
+
+static struct rcg_clk jpeg1_clk_src = {
+	.cmd_rcgr_reg = JPEG1_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_jpeg_jpeg0_2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "jpeg1_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 133330000, NOMINAL, 266670000,
+				  HIGH, 320000000),
+		CLK_INIT(jpeg1_clk_src.c),
+	},
+};
+
+static struct rcg_clk jpeg2_clk_src = {
+	.cmd_rcgr_reg = JPEG2_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_jpeg_jpeg0_2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "jpeg2_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 133330000, NOMINAL, 266670000,
+				  HIGH, 320000000),
+		CLK_INIT(jpeg2_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_camss_mclk0_3_clk[] = {
+	F_MM(66670000,  gpll0,   9,   0,   0),
+	F_END
+};
+
+static struct rcg_clk mclk0_clk_src = {
+	.cmd_rcgr_reg = MCLK0_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_mclk0_3_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mclk0_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 66670000),
+		CLK_INIT(mclk0_clk_src.c),
+	},
+};
+
+static struct rcg_clk mclk1_clk_src = {
+	.cmd_rcgr_reg = MCLK1_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_mclk0_3_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mclk1_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 66670000),
+		CLK_INIT(mclk1_clk_src.c),
+	},
+};
+
+static struct rcg_clk mclk2_clk_src = {
+	.cmd_rcgr_reg = MCLK2_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_mclk0_3_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mclk2_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 66670000),
+		CLK_INIT(mclk2_clk_src.c),
+	},
+};
+
+static struct rcg_clk mclk3_clk_src = {
+	.cmd_rcgr_reg = MCLK3_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_mclk0_3_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mclk3_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 66670000),
+		CLK_INIT(mclk3_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_camss_phy0_2_csi0_2phytimer_clk[] = {
+	F_MM(100000000,  gpll0,   6,   0,   0),
+	F_MM(200000000, mmpll0,   4,   0,   0),
+	F_END
+};
+
+static struct rcg_clk csi0phytimer_clk_src = {
+	.cmd_rcgr_reg = CSI0PHYTIMER_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_phy0_2_csi0_2phytimer_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "csi0phytimer_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(csi0phytimer_clk_src.c),
+	},
+};
+
+static struct rcg_clk csi1phytimer_clk_src = {
+	.cmd_rcgr_reg = CSI1PHYTIMER_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_phy0_2_csi0_2phytimer_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "csi1phytimer_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(csi1phytimer_clk_src.c),
+	},
+};
+
+static struct rcg_clk csi2phytimer_clk_src = {
+	.cmd_rcgr_reg = CSI2PHYTIMER_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_phy0_2_csi0_2phytimer_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "csi2phytimer_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(csi2phytimer_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_camss_vfe_cpp_clk[] = {
+	F_MM(150000000,  gpll0,   4,   0,   0),
+	F_MM(266670000, mmpll0,   3,   0,   0),
+	F_MM(320000000, mmpll0, 2.5,   0,   0),
+	F_END
+};
+
+static struct rcg_clk cpp_clk_src = {
+	.cmd_rcgr_reg = CPP_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_vfe_cpp_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "cpp_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 133330000, NOMINAL, 266670000,
+				  HIGH, 320000000),
+		CLK_INIT(cpp_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mdss_byte0_1_clk[] = {
+	F_MDSS( 93750000, dsipll_750,   8,   0,   0),
+	F_MDSS(187500000, dsipll_750,   4,   0,   0),
+	F_END
+};
+
+static struct rcg_clk byte0_clk_src = {
+	.cmd_rcgr_reg = BYTE0_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mdss_byte0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "byte0_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 93800000, NOMINAL, 187500000,
+				  HIGH, 188000000),
+		CLK_INIT(byte0_clk_src.c),
+	},
+};
+
+static struct rcg_clk byte1_clk_src = {
+	.cmd_rcgr_reg = BYTE1_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mdss_byte0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "byte1_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 93800000, NOMINAL, 187500000,
+				  HIGH, 188000000),
+		CLK_INIT(byte1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mdss_edpaux_clk[] = {
+	F_MM(19200000,    cxo,   1,   0,   0),
+	F_END
+};
+
+static struct rcg_clk edpaux_clk_src = {
+	.cmd_rcgr_reg = EDPAUX_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mdss_edpaux_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "edpaux_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 20000000, NOMINAL, 40000000),
+		CLK_INIT(edpaux_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mdss_edplink_clk[] = {
+	F_MDSS(135000000, edppll_270,   2,   0,   0),
+	F_MDSS(270000000, edppll_270,  11,   0,   0),
+	F_END
+};
+
+static struct rcg_clk edplink_clk_src = {
+	.cmd_rcgr_reg = EDPLINK_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mdss_edplink_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "edplink_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 135000000, NOMINAL, 270000000),
+		CLK_INIT(edplink_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mdss_edppixel_clk[] = {
+	F_MDSS(175000000, edppll_350,   2,   0,   0),
+	F_MDSS(350000000, edppll_350,  11,   0,   0),
+	F_END
+};
+
+static struct rcg_clk edppixel_clk_src = {
+	.cmd_rcgr_reg = EDPPIXEL_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_mdss_edppixel_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "edppixel_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 175000000, NOMINAL, 350000000),
+		CLK_INIT(edppixel_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mdss_esc0_1_clk[] = {
+	F_MM(19200000,    cxo,   1,   0,   0),
+	F_END
+};
+
+static struct rcg_clk esc0_clk_src = {
+	.cmd_rcgr_reg = ESC0_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mdss_esc0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "esc0_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 20000000, NOMINAL, 40000000),
+		CLK_INIT(esc0_clk_src.c),
+	},
+};
+
+static struct rcg_clk esc1_clk_src = {
+	.cmd_rcgr_reg = ESC1_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mdss_esc0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "esc1_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 20000000, NOMINAL, 40000000),
+		CLK_INIT(esc1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mdss_extpclk_clk[] = {
+	F_MDSS(148500000, hdmipll_297,   2,   0,   0),
+	F_END
+};
+
+static struct rcg_clk extpclk_clk_src = {
+	.cmd_rcgr_reg = EXTPCLK_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mdss_extpclk_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "extpclk_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 148500000, NOMINAL, 297000000),
+		CLK_INIT(extpclk_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mdss_hdmi_clk[] = {
+	F_MDSS(19200000,    cxo,   1,   0,   0),
+	F_END
+};
+
+static struct rcg_clk hdmi_clk_src = {
+	.cmd_rcgr_reg = HDMI_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mdss_hdmi_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "hdmi_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 20000000, NOMINAL, 40000000),
+		CLK_INIT(hdmi_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mdss_pclk0_1_clk[] = {
+	F_MDSS(125000000, dsipll_250,   2,   0,   0),
+	F_MDSS(250000000, dsipll_250,   1,   0,   0),
+	F_END
+};
+
+static struct rcg_clk pclk0_clk_src = {
+	.cmd_rcgr_reg = PCLK0_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_mdss_pclk0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "pclk0_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 125000000, NOMINAL, 250000000),
+		CLK_INIT(pclk0_clk_src.c),
+	},
+};
+
+static struct rcg_clk pclk1_clk_src = {
+	.cmd_rcgr_reg = PCLK1_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_mdss_pclk0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "pclk1_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 125000000, NOMINAL, 250000000),
+		CLK_INIT(pclk1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mdss_vsync_clk[] = {
+	F_MDSS(19200000,    cxo,   1,   0,   0),
+	F_END
+};
+
+static struct rcg_clk vsync_clk_src = {
+	.cmd_rcgr_reg = VSYNC_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mdss_vsync_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "vsync_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 20000000, NOMINAL, 40000000),
+		CLK_INIT(vsync_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_venus0_vcodec0_clk[] = {
+	F_MM( 50000000,  gpll0,  12,   0,   0),
+	F_MM(100000000,  gpll0,   6,   0,   0),
+	F_MM(133330000, mmpll0,   6,   0,   0),
+	F_MM(200000000, mmpll0,   4,   0,   0),
+	F_MM(266670000, mmpll0,   3,   0,   0),
+	F_MM(410000000, mmpll3,   2,   0,   0),
+	F_END
+};
+
+static struct rcg_clk vcodec0_clk_src = {
+	.cmd_rcgr_reg = VCODEC0_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_venus0_vcodec0_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "vcodec0_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP3(LOW, 133330000, NOMINAL, 266670000,
+				  HIGH, 410000000),
+		CLK_INIT(vcodec0_clk_src.c),
+	},
+};
+
+static struct branch_clk camss_cci_cci_ahb_clk = {
+	.cbcr_reg = CAMSS_CCI_CCI_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CCI_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_cci_cci_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_cci_cci_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_cci_cci_clk = {
+	.cbcr_reg = CAMSS_CCI_CCI_CBCR,
+	.parent = &cci_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = CAMSS_CCI_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_cci_cci_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_cci_cci_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi0_ahb_clk = {
+	.cbcr_reg = CAMSS_CSI0_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI0_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi0_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi0_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi0_clk = {
+	.cbcr_reg = CAMSS_CSI0_CBCR,
+	.parent = &csi0_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI0_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi0_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi0_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi0phy_clk = {
+	.cbcr_reg = CAMSS_CSI0PHY_CBCR,
+	.parent = &csi0_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI0PHY_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi0phy_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi0phy_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi0pix_clk = {
+	.cbcr_reg = CAMSS_CSI0PIX_CBCR,
+	.parent = &csi0_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI0PIX_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi0pix_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi0pix_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi0rdi_clk = {
+	.cbcr_reg = CAMSS_CSI0RDI_CBCR,
+	.parent = &csi0_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI0RDI_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi0rdi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi0rdi_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi1_ahb_clk = {
+	.cbcr_reg = CAMSS_CSI1_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI1_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi1_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi1_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi1_clk = {
+	.cbcr_reg = CAMSS_CSI1_CBCR,
+	.parent = &csi1_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI1_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi1_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi1_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi1phy_clk = {
+	.cbcr_reg = CAMSS_CSI1PHY_CBCR,
+	.parent = &csi1_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI1PHY_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi1phy_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi1phy_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi1pix_clk = {
+	.cbcr_reg = CAMSS_CSI1PIX_CBCR,
+	.parent = &csi1_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI1PIX_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi1pix_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi1pix_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi1rdi_clk = {
+	.cbcr_reg = CAMSS_CSI1RDI_CBCR,
+	.parent = &csi1_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI1RDI_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi1rdi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi1rdi_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi2_ahb_clk = {
+	.cbcr_reg = CAMSS_CSI2_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI2_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi2_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi2_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi2_clk = {
+	.cbcr_reg = CAMSS_CSI2_CBCR,
+	.parent = &csi2_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI2_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi2_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi2_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi2phy_clk = {
+	.cbcr_reg = CAMSS_CSI2PHY_CBCR,
+	.parent = &csi2_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI2PHY_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi2phy_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi2phy_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi2pix_clk = {
+	.cbcr_reg = CAMSS_CSI2PIX_CBCR,
+	.parent = &csi2_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI2PIX_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi2pix_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi2pix_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi2rdi_clk = {
+	.cbcr_reg = CAMSS_CSI2RDI_CBCR,
+	.parent = &csi2_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI2RDI_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi2rdi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi2rdi_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi3_ahb_clk = {
+	.cbcr_reg = CAMSS_CSI3_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI3_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi3_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi3_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi3_clk = {
+	.cbcr_reg = CAMSS_CSI3_CBCR,
+	.parent = &csi3_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI3_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi3_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi3_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi3phy_clk = {
+	.cbcr_reg = CAMSS_CSI3PHY_CBCR,
+	.parent = &csi3_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI3PHY_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi3phy_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi3phy_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi3pix_clk = {
+	.cbcr_reg = CAMSS_CSI3PIX_CBCR,
+	.parent = &csi3_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI3PIX_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi3pix_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi3pix_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi3rdi_clk = {
+	.cbcr_reg = CAMSS_CSI3RDI_CBCR,
+	.parent = &csi3_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI3RDI_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi3rdi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi3rdi_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi_vfe0_clk = {
+	.cbcr_reg = CAMSS_CSI_VFE0_CBCR,
+	.parent = &vfe0_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI_VFE0_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi_vfe0_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi_vfe0_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi_vfe1_clk = {
+	.cbcr_reg = CAMSS_CSI_VFE1_CBCR,
+	.parent = &vfe1_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI_VFE1_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi_vfe1_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi_vfe1_clk.c),
+	},
+};
+
+static struct branch_clk camss_gp0_clk = {
+	.cbcr_reg = CAMSS_GP0_CBCR,
+	.parent = &mmss_gp0_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = CAMSS_GP0_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_gp0_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_gp0_clk.c),
+	},
+};
+
+static struct branch_clk camss_gp1_clk = {
+	.cbcr_reg = CAMSS_GP1_CBCR,
+	.parent = &mmss_gp1_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = CAMSS_GP1_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_gp1_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_gp1_clk.c),
+	},
+};
+
+static struct branch_clk camss_ispif_ahb_clk = {
+	.cbcr_reg = CAMSS_ISPIF_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_ISPIF_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_ispif_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_ispif_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_jpeg_jpeg0_clk = {
+	.cbcr_reg = CAMSS_JPEG_JPEG0_CBCR,
+	.parent = &jpeg0_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = CAMSS_JPEG_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_jpeg_jpeg0_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_jpeg_jpeg0_clk.c),
+	},
+};
+
+static struct branch_clk camss_jpeg_jpeg1_clk = {
+	.cbcr_reg = CAMSS_JPEG_JPEG1_CBCR,
+	.parent = &jpeg1_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = CAMSS_JPEG_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_jpeg_jpeg1_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_jpeg_jpeg1_clk.c),
+	},
+};
+
+static struct branch_clk camss_jpeg_jpeg2_clk = {
+	.cbcr_reg = CAMSS_JPEG_JPEG2_CBCR,
+	.parent = &jpeg2_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = CAMSS_JPEG_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_jpeg_jpeg2_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_jpeg_jpeg2_clk.c),
+	},
+};
+
+static struct branch_clk camss_jpeg_jpeg_ahb_clk = {
+	.cbcr_reg = CAMSS_JPEG_JPEG_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_JPEG_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_jpeg_jpeg_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_jpeg_jpeg_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_jpeg_jpeg_axi_clk = {
+	.cbcr_reg = CAMSS_JPEG_JPEG_AXI_CBCR,
+	.parent = &axi_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_JPEG_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_jpeg_jpeg_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_jpeg_jpeg_axi_clk.c),
+	},
+};
+
+static struct branch_clk camss_jpeg_jpeg_ocmemnoc_clk = {
+	.cbcr_reg = CAMSS_JPEG_JPEG_OCMEMNOC_CBCR,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_JPEG_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_jpeg_jpeg_ocmemnoc_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_jpeg_jpeg_ocmemnoc_clk.c),
+	},
+};
+
+static struct branch_clk camss_mclk0_clk = {
+	.cbcr_reg = CAMSS_MCLK0_CBCR,
+	.parent = &mclk0_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = CAMSS_MCLK0_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_mclk0_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_mclk0_clk.c),
+	},
+};
+
+static struct branch_clk camss_mclk1_clk = {
+	.cbcr_reg = CAMSS_MCLK1_CBCR,
+	.parent = &mclk1_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = CAMSS_MCLK1_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_mclk1_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_mclk1_clk.c),
+	},
+};
+
+static struct branch_clk camss_mclk2_clk = {
+	.cbcr_reg = CAMSS_MCLK2_CBCR,
+	.parent = &mclk2_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = CAMSS_MCLK2_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_mclk2_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_mclk2_clk.c),
+	},
+};
+
+static struct branch_clk camss_mclk3_clk = {
+	.cbcr_reg = CAMSS_MCLK3_CBCR,
+	.parent = &mclk3_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = CAMSS_MCLK3_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_mclk3_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_mclk3_clk.c),
+	},
+};
+
+static struct branch_clk camss_micro_ahb_clk = {
+	.cbcr_reg = CAMSS_MICRO_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_MICRO_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_micro_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_micro_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_phy0_csi0phytimer_clk = {
+	.cbcr_reg = CAMSS_PHY0_CSI0PHYTIMER_CBCR,
+	.parent = &csi0phytimer_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = CAMSS_PHY0_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_phy0_csi0phytimer_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_phy0_csi0phytimer_clk.c),
+	},
+};
+
+static struct branch_clk camss_phy1_csi1phytimer_clk = {
+	.cbcr_reg = CAMSS_PHY1_CSI1PHYTIMER_CBCR,
+	.parent = &csi1phytimer_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = CAMSS_PHY1_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_phy1_csi1phytimer_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_phy1_csi1phytimer_clk.c),
+	},
+};
+
+static struct branch_clk camss_phy2_csi2phytimer_clk = {
+	.cbcr_reg = CAMSS_PHY2_CSI2PHYTIMER_CBCR,
+	.parent = &csi2phytimer_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = CAMSS_PHY2_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_phy2_csi2phytimer_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_phy2_csi2phytimer_clk.c),
+	},
+};
+
+static struct branch_clk camss_top_ahb_clk = {
+	.cbcr_reg = CAMSS_TOP_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_TOP_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_top_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_top_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_vfe_cpp_ahb_clk = {
+	.cbcr_reg = CAMSS_VFE_CPP_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_VFE_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_vfe_cpp_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_vfe_cpp_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_vfe_cpp_clk = {
+	.cbcr_reg = CAMSS_VFE_CPP_CBCR,
+	.parent = &cpp_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = CAMSS_VFE_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_vfe_cpp_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_vfe_cpp_clk.c),
+	},
+};
+
+static struct branch_clk camss_vfe_vfe0_clk = {
+	.cbcr_reg = CAMSS_VFE_VFE0_CBCR,
+	.parent = &vfe0_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_VFE_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_vfe_vfe0_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_vfe_vfe0_clk.c),
+	},
+};
+
+static struct branch_clk camss_vfe_vfe1_clk = {
+	.cbcr_reg = CAMSS_VFE_VFE1_CBCR,
+	.parent = &vfe1_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_VFE_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_vfe_vfe1_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_vfe_vfe1_clk.c),
+	},
+};
+
+static struct branch_clk camss_vfe_vfe_ahb_clk = {
+	.cbcr_reg = CAMSS_VFE_VFE_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_VFE_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_vfe_vfe_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_vfe_vfe_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_vfe_vfe_axi_clk = {
+	.cbcr_reg = CAMSS_VFE_VFE_AXI_CBCR,
+	.parent = &axi_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_VFE_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_vfe_vfe_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_vfe_vfe_axi_clk.c),
+	},
+};
+
+static struct branch_clk camss_vfe_vfe_ocmemnoc_clk = {
+	.cbcr_reg = CAMSS_VFE_VFE_OCMEMNOC_CBCR,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_VFE_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_vfe_vfe_ocmemnoc_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_vfe_vfe_ocmemnoc_clk.c),
+	},
+};
+
+static struct branch_clk mdss_ahb_clk = {
+	.cbcr_reg = MDSS_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_ahb_clk.c),
+	},
+};
+
+static struct branch_clk mdss_axi_clk = {
+	.cbcr_reg = MDSS_AXI_CBCR,
+	.parent = &axi_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_axi_clk.c),
+	},
+};
+
+static struct branch_clk mdss_byte0_clk = {
+	.cbcr_reg = MDSS_BYTE0_CBCR,
+	.parent = &byte0_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_byte0_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_byte0_clk.c),
+	},
+};
+
+static struct branch_clk mdss_byte1_clk = {
+	.cbcr_reg = MDSS_BYTE1_CBCR,
+	.parent = &byte1_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_byte1_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_byte1_clk.c),
+	},
+};
+
+static struct branch_clk mdss_edpaux_clk = {
+	.cbcr_reg = MDSS_EDPAUX_CBCR,
+	.parent = &edpaux_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_edpaux_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_edpaux_clk.c),
+	},
+};
+
+static struct branch_clk mdss_edplink_clk = {
+	.cbcr_reg = MDSS_EDPLINK_CBCR,
+	.parent = &edplink_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_edplink_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_edplink_clk.c),
+	},
+};
+
+static struct branch_clk mdss_edppixel_clk = {
+	.cbcr_reg = MDSS_EDPPIXEL_CBCR,
+	.parent = &edppixel_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_edppixel_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_edppixel_clk.c),
+	},
+};
+
+static struct branch_clk mdss_esc0_clk = {
+	.cbcr_reg = MDSS_ESC0_CBCR,
+	.parent = &esc0_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_esc0_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_esc0_clk.c),
+	},
+};
+
+static struct branch_clk mdss_esc1_clk = {
+	.cbcr_reg = MDSS_ESC1_CBCR,
+	.parent = &esc1_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_esc1_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_esc1_clk.c),
+	},
+};
+
+static struct branch_clk mdss_extpclk_clk = {
+	.cbcr_reg = MDSS_EXTPCLK_CBCR,
+	.parent = &extpclk_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_extpclk_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_extpclk_clk.c),
+	},
+};
+
+static struct branch_clk mdss_hdmi_ahb_clk = {
+	.cbcr_reg = MDSS_HDMI_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_hdmi_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_hdmi_ahb_clk.c),
+	},
+};
+
+static struct branch_clk mdss_hdmi_clk = {
+	.cbcr_reg = MDSS_HDMI_CBCR,
+	.parent = &hdmi_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_hdmi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_hdmi_clk.c),
+	},
+};
+
+static struct branch_clk mdss_mdp_clk = {
+	.cbcr_reg = MDSS_MDP_CBCR,
+	.parent = &mdp_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_mdp_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_mdp_clk.c),
+	},
+};
+
+static struct branch_clk mdss_mdp_lut_clk = {
+	.cbcr_reg = MDSS_MDP_LUT_CBCR,
+	.parent = &mdp_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_mdp_lut_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_mdp_lut_clk.c),
+	},
+};
+
+static struct branch_clk mdss_pclk0_clk = {
+	.cbcr_reg = MDSS_PCLK0_CBCR,
+	.parent = &pclk0_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_pclk0_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_pclk0_clk.c),
+	},
+};
+
+static struct branch_clk mdss_pclk1_clk = {
+	.cbcr_reg = MDSS_PCLK1_CBCR,
+	.parent = &pclk1_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_pclk1_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_pclk1_clk.c),
+	},
+};
+
+static struct branch_clk mdss_vsync_clk = {
+	.cbcr_reg = MDSS_VSYNC_CBCR,
+	.parent = &vsync_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_vsync_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_vsync_clk.c),
+	},
+};
+
+static struct branch_clk mmss_misc_ahb_clk = {
+	.cbcr_reg = MMSS_MISC_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = MMSSNOCAHB_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mmss_misc_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mmss_misc_ahb_clk.c),
+	},
+};
+
+static struct branch_clk mmss_mmssnoc_ahb_clk = {
+	.cbcr_reg = MMSS_MMSSNOC_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = MMSSNOCAHB_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mmss_mmssnoc_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mmss_mmssnoc_ahb_clk.c),
+	},
+};
+
+static struct branch_clk mmss_mmssnoc_bto_ahb_clk = {
+	.cbcr_reg = MMSS_MMSSNOC_BTO_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = MMSSNOCAHB_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mmss_mmssnoc_bto_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mmss_mmssnoc_bto_ahb_clk.c),
+	},
+};
+
+static struct branch_clk mmss_mmssnoc_axi_clk = {
+	.cbcr_reg = MMSS_MMSSNOC_AXI_CBCR,
+	.parent = &axi_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = MMSSNOCAXI_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mmss_mmssnoc_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mmss_mmssnoc_axi_clk.c),
+	},
+};
+
+static struct branch_clk mmss_s0_axi_clk = {
+	.cbcr_reg = MMSS_S0_AXI_CBCR,
+	.parent = &axi_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = MMSSNOCAXI_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mmss_s0_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mmss_s0_axi_clk.c),
+	},
+};
+
+static struct branch_clk venus0_ahb_clk = {
+	.cbcr_reg = VENUS0_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = VENUS0_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "venus0_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(venus0_ahb_clk.c),
+	},
+};
+
+static struct branch_clk venus0_axi_clk = {
+	.cbcr_reg = VENUS0_AXI_CBCR,
+	.parent = &axi_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = VENUS0_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "venus0_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(venus0_axi_clk.c),
+	},
+};
+
+static struct branch_clk venus0_ocmemnoc_clk = {
+	.cbcr_reg = VENUS0_OCMEMNOC_CBCR,
+	.has_sibling = 1,
+	.bcr_reg = VENUS0_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "venus0_ocmemnoc_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(venus0_ocmemnoc_clk.c),
+	},
+};
+
+static struct branch_clk venus0_vcodec0_clk = {
+	.cbcr_reg = VENUS0_VCODEC0_CBCR,
+	.parent = &vcodec0_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = VENUS0_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "venus0_vcodec0_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(venus0_vcodec0_clk.c),
+	},
+};
+
+static struct branch_clk oxili_gfx3d_clk = {
+	.cbcr_reg = OXILI_GFX3D_CBCR,
+	.has_sibling = 1,
+	.bcr_reg = OXILI_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "oxili_gfx3d_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(oxili_gfx3d_clk.c),
+	},
+};
+
+static struct branch_clk oxilicx_ahb_clk = {
+	.cbcr_reg = OXILICX_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = OXILICX_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "oxilicx_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(oxilicx_ahb_clk.c),
+	},
+};
+
+static struct branch_clk oxilicx_axi_clk = {
+	.cbcr_reg = OXILICX_AXI_CBCR,
+	.parent = &axi_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = OXILICX_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "oxilicx_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(oxilicx_axi_clk.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_audio_core_slimbus_core_clock[] = {
+	F_LPASS(28800000, lpapll0, 1, 15, 256),
+	F_END
+};
+
+static struct rcg_clk audio_core_slimbus_core_clk_src = {
+	.cmd_rcgr_reg = SLIMBUS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_audio_core_slimbus_core_clock,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_slimbus_core_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 70000000, NOMINAL, 140000000),
+		CLK_INIT(audio_core_slimbus_core_clk_src.c),
+	},
+};
+
+static struct branch_clk audio_core_slimbus_core_clk = {
+	.cbcr_reg = AUDIO_CORE_SLIMBUS_CORE_CBCR,
+	.parent = &audio_core_slimbus_core_clk_src.c,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_slimbus_core_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_slimbus_core_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_slimbus_lfabif_clk = {
+	.cbcr_reg = AUDIO_CORE_SLIMBUS_LFABIF_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_slimbus_lfabif_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_slimbus_lfabif_clk.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_audio_core_lpaif_clock[] = {
+	F_LPASS(  512000, lpapll0, 16, 1, 60),
+	F_LPASS(  768000, lpapll0, 16, 1, 40),
+	F_LPASS( 1024000, lpapll0, 16, 1, 30),
+	F_LPASS( 1536000, lpapll0, 16, 1, 10),
+	F_LPASS( 2048000, lpapll0, 16, 1, 15),
+	F_LPASS( 3072000, lpapll0, 16, 1, 10),
+	F_LPASS( 4096000, lpapll0, 15, 1,  8),
+	F_LPASS( 6144000, lpapll0, 10, 1,  8),
+	F_LPASS( 8192000, lpapll0, 15, 1,  4),
+	F_LPASS(12288000, lpapll0, 10, 1,  4),
+	F_END
+};
+
+static struct rcg_clk audio_core_lpaif_codec_spkr_clk_src = {
+	.cmd_rcgr_reg = LPAIF_SPKR_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_audio_core_lpaif_clock,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_codec_spkr_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
+		CLK_INIT(audio_core_lpaif_codec_spkr_clk_src.c),
+	},
+};
+
+static struct rcg_clk audio_core_lpaif_pri_clk_src = {
+	.cmd_rcgr_reg = LPAIF_PRI_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_audio_core_lpaif_clock,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_pri_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
+		CLK_INIT(audio_core_lpaif_pri_clk_src.c),
+	},
+};
+
+static struct rcg_clk audio_core_lpaif_sec_clk_src = {
+	.cmd_rcgr_reg = LPAIF_SEC_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_audio_core_lpaif_clock,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_sec_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
+		CLK_INIT(audio_core_lpaif_sec_clk_src.c),
+	},
+};
+
+static struct rcg_clk audio_core_lpaif_ter_clk_src = {
+	.cmd_rcgr_reg = LPAIF_TER_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_audio_core_lpaif_clock,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_ter_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
+		CLK_INIT(audio_core_lpaif_ter_clk_src.c),
+	},
+};
+
+static struct rcg_clk audio_core_lpaif_quad_clk_src = {
+	.cmd_rcgr_reg = LPAIF_QUAD_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_audio_core_lpaif_clock,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_quad_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
+		CLK_INIT(audio_core_lpaif_quad_clk_src.c),
+	},
+};
+
+static struct rcg_clk audio_core_lpaif_pcm0_clk_src = {
+	.cmd_rcgr_reg = LPAIF_PCM0_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_audio_core_lpaif_clock,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_pcm0_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
+		CLK_INIT(audio_core_lpaif_pcm0_clk_src.c),
+	},
+};
+
+static struct rcg_clk audio_core_lpaif_pcm1_clk_src = {
+	.cmd_rcgr_reg = LPAIF_PCM1_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_audio_core_lpaif_clock,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_pcm1_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
+		CLK_INIT(audio_core_lpaif_pcm1_clk_src.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_codec_spkr_osr_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_OSR_CBCR,
+	.parent = &audio_core_lpaif_codec_spkr_clk_src.c,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_codec_spkr_clk_src",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_codec_spkr_clk_src.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_codec_spkr_ebit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_EBIT_CBCR,
+	.parent = &audio_core_lpaif_codec_spkr_clk_src.c,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_codec_spkr_clk_src",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_codec_spkr_clk_src.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_codec_spkr_ibit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_IBIT_CBCR,
+	.parent = &audio_core_lpaif_codec_spkr_clk_src.c,
+	.has_sibling = 1,
+	.max_div = 16,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_codec_spkr_clk_src",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_codec_spkr_clk_src.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_pri_osr_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_PRI_OSR_CBCR,
+	.parent = &audio_core_lpaif_pri_clk_src.c,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_pri_osr_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_pri_osr_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_pri_ebit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_PRI_EBIT_CBCR,
+	.parent = &audio_core_lpaif_pri_clk_src.c,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_pri_ebit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_pri_ebit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_pri_ibit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_PRI_IBIT_CBCR,
+	.parent = &audio_core_lpaif_pri_clk_src.c,
+	.has_sibling = 1,
+	.max_div = 16,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_pri_ibit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_pri_ibit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_sec_osr_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_SEC_OSR_CBCR,
+	.parent = &audio_core_lpaif_sec_clk_src.c,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_sec_osr_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_sec_osr_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_sec_ebit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_SEC_EBIT_CBCR,
+	.parent = &audio_core_lpaif_sec_clk_src.c,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_sec_ebit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_sec_ebit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_sec_ibit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_SEC_IBIT_CBCR,
+	.parent = &audio_core_lpaif_sec_clk_src.c,
+	.has_sibling = 1,
+	.max_div = 16,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_sec_ibit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_sec_ibit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_ter_osr_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_TER_OSR_CBCR,
+	.parent = &audio_core_lpaif_ter_clk_src.c,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_ter_osr_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_ter_osr_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_ter_ebit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_TER_EBIT_CBCR,
+	.parent = &audio_core_lpaif_ter_clk_src.c,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_ter_ebit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_ter_ebit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_ter_ibit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_TER_IBIT_CBCR,
+	.parent = &audio_core_lpaif_ter_clk_src.c,
+	.has_sibling = 1,
+	.max_div = 16,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_ter_ibit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_ter_ibit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_quad_osr_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_QUAD_OSR_CBCR,
+	.parent = &audio_core_lpaif_quad_clk_src.c,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_quad_osr_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_quad_osr_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_quad_ebit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_QUAD_EBIT_CBCR,
+	.parent = &audio_core_lpaif_quad_clk_src.c,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_quad_ebit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_quad_ebit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_quad_ibit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_QUAD_IBIT_CBCR,
+	.parent = &audio_core_lpaif_quad_clk_src.c,
+	.has_sibling = 1,
+	.max_div = 16,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_quad_ibit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_quad_ibit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_pcm0_ebit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_PCM0_EBIT_CBCR,
+	.parent = &audio_core_lpaif_pcm0_clk_src.c,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_pcm0_ebit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_pcm0_ebit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_pcm0_ibit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_PCM0_IBIT_CBCR,
+	.parent = &audio_core_lpaif_pcm0_clk_src.c,
+	.has_sibling = 1,
+	.max_div = 16,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_pcm0_ibit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_pcm0_ibit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_pcm1_ebit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_PCM1_EBIT_CBCR,
+	.parent = &audio_core_lpaif_pcm1_clk_src.c,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_pcm1_ebit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_pcm1_ebit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_pcm1_ibit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_PCM1_IBIT_CBCR,
+	.parent = &audio_core_lpaif_pcm1_clk_src.c,
+	.has_sibling = 1,
+	.max_div = 16,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_pcm1_ibit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_pcm1_ibit_clk.c),
+	},
+};
+
+static struct branch_clk q6ss_ahb_lfabif_clk = {
+	.cbcr_reg = LPASS_Q6SS_AHB_LFABIF_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "q6ss_ahb_lfabif_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(q6ss_ahb_lfabif_clk.c),
+	},
+};
+
+static struct branch_clk q6ss_xo_clk = {
+	.cbcr_reg = LPASS_Q6SS_XO_CBCR,
+	.bcr_reg = LPASS_Q6SS_BCR,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "q6ss_xo_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(q6ss_xo_clk.c),
+	},
+};
+
+static struct branch_clk mss_xo_q6_clk = {
+	.cbcr_reg = MSS_XO_Q6_CBCR,
+	.bcr_reg = MSS_Q6SS_BCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MSS_BASE],
+	.c = {
+		.dbg_name = "mss_xo_q6_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mss_xo_q6_clk.c),
+		.depends = &gcc_mss_cfg_ahb_clk.c,
+	},
+};
+
+static struct branch_clk mss_bus_q6_clk = {
+	.cbcr_reg = MSS_BUS_Q6_CBCR,
+	.bcr_reg = MSS_Q6SS_BCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MSS_BASE],
+	.c = {
+		.dbg_name = "mss_bus_q6_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mss_bus_q6_clk.c),
+		.depends = &gcc_mss_cfg_ahb_clk.c,
+	},
+};
+
+#ifdef CONFIG_DEBUG_FS
+
+struct measure_mux_entry {
+	struct clk *c;
+	int base;
+	u32 debug_mux;
+};
+
+struct measure_mux_entry measure_mux[] = {
+	{&gcc_bam_dma_ahb_clk.c,		GCC_BASE, 0x00e8},
+	{&gcc_blsp1_ahb_clk.c,			GCC_BASE, 0x0090},
+	{&gcc_blsp1_qup1_i2c_apps_clk.c,	GCC_BASE, 0x0093},
+	{&gcc_blsp1_qup1_spi_apps_clk.c,	GCC_BASE, 0x0092},
+	{&gcc_blsp1_qup2_i2c_apps_clk.c,	GCC_BASE, 0x0098},
+	{&gcc_blsp1_qup2_spi_apps_clk.c,	GCC_BASE, 0x0096},
+	{&gcc_blsp1_qup3_i2c_apps_clk.c,	GCC_BASE, 0x009c},
+	{&gcc_blsp1_qup3_spi_apps_clk.c,	GCC_BASE, 0x009b},
+	{&gcc_blsp1_qup4_i2c_apps_clk.c,	GCC_BASE, 0x00a1},
+	{&gcc_blsp1_qup4_spi_apps_clk.c,	GCC_BASE, 0x00a0},
+	{&gcc_blsp1_qup5_i2c_apps_clk.c,	GCC_BASE, 0x00a5},
+	{&gcc_blsp1_qup5_spi_apps_clk.c,	GCC_BASE, 0x00a4},
+	{&gcc_blsp1_qup6_i2c_apps_clk.c,	GCC_BASE, 0x00aa},
+	{&gcc_blsp1_qup6_spi_apps_clk.c,	GCC_BASE, 0x00a9},
+	{&gcc_blsp1_uart1_apps_clk.c,		GCC_BASE, 0x0094},
+	{&gcc_blsp1_uart2_apps_clk.c,		GCC_BASE, 0x0099},
+	{&gcc_blsp1_uart3_apps_clk.c,		GCC_BASE, 0x009d},
+	{&gcc_blsp1_uart4_apps_clk.c,		GCC_BASE, 0x00a2},
+	{&gcc_blsp1_uart5_apps_clk.c,		GCC_BASE, 0x00a6},
+	{&gcc_blsp1_uart6_apps_clk.c,		GCC_BASE, 0x00ab},
+	{&gcc_blsp2_ahb_clk.c,			GCC_BASE, 0x00b0},
+	{&gcc_blsp2_qup1_i2c_apps_clk.c,	GCC_BASE, 0x00b3},
+	{&gcc_blsp2_qup1_spi_apps_clk.c,	GCC_BASE, 0x00b2},
+	{&gcc_blsp2_qup2_i2c_apps_clk.c,	GCC_BASE, 0x00b8},
+	{&gcc_blsp2_qup2_spi_apps_clk.c,	GCC_BASE, 0x00b6},
+	{&gcc_blsp2_qup3_i2c_apps_clk.c,	GCC_BASE, 0x00bc},
+	{&gcc_blsp2_qup3_spi_apps_clk.c,	GCC_BASE, 0x00bb},
+	{&gcc_blsp2_qup4_i2c_apps_clk.c,	GCC_BASE, 0x00c1},
+	{&gcc_blsp2_qup4_spi_apps_clk.c,	GCC_BASE, 0x00c0},
+	{&gcc_blsp2_qup5_i2c_apps_clk.c,	GCC_BASE, 0x00c5},
+	{&gcc_blsp2_qup5_spi_apps_clk.c,	GCC_BASE, 0x00c4},
+	{&gcc_blsp2_qup6_i2c_apps_clk.c,	GCC_BASE, 0x00ca},
+	{&gcc_blsp2_qup6_spi_apps_clk.c,	GCC_BASE, 0x00c9},
+	{&gcc_blsp2_uart1_apps_clk.c,		GCC_BASE, 0x00b4},
+	{&gcc_blsp2_uart2_apps_clk.c,		GCC_BASE, 0x00b9},
+	{&gcc_blsp2_uart3_apps_clk.c,		GCC_BASE, 0x00bd},
+	{&gcc_blsp2_uart4_apps_clk.c,		GCC_BASE, 0x00c2},
+	{&gcc_blsp2_uart5_apps_clk.c,		GCC_BASE, 0x00c6},
+	{&gcc_blsp2_uart6_apps_clk.c,		GCC_BASE, 0x00cb},
+	{&gcc_boot_rom_ahb_clk.c,		GCC_BASE, 0x0100},
+	{&gcc_mss_cfg_ahb_clk.c,		GCC_BASE, 0x0030},
+	{&gcc_ce1_clk.c,			GCC_BASE, 0x0140},
+	{&gcc_ce2_clk.c,			GCC_BASE, 0x0148},
+	{&gcc_pdm2_clk.c,			GCC_BASE, 0x00da},
+	{&gcc_pdm_ahb_clk.c,			GCC_BASE, 0x00d8},
+	{&gcc_prng_ahb_clk.c,			GCC_BASE, 0x00e0},
+	{&gcc_sdcc1_ahb_clk.c,			GCC_BASE, 0x0071},
+	{&gcc_sdcc1_apps_clk.c,			GCC_BASE, 0x0070},
+	{&gcc_sdcc2_ahb_clk.c,			GCC_BASE, 0x0079},
+	{&gcc_sdcc2_apps_clk.c,			GCC_BASE, 0x0078},
+	{&gcc_sdcc3_ahb_clk.c,			GCC_BASE, 0x0081},
+	{&gcc_sdcc3_apps_clk.c,			GCC_BASE, 0x0080},
+	{&gcc_sdcc4_ahb_clk.c,			GCC_BASE, 0x0089},
+	{&gcc_sdcc4_apps_clk.c,			GCC_BASE, 0x0088},
+	{&gcc_tsif_ahb_clk.c,			GCC_BASE, 0x00f0},
+	{&gcc_tsif_ref_clk.c,			GCC_BASE, 0x00f1},
+	{&gcc_usb30_master_clk.c,		GCC_BASE, 0x0050},
+	{&gcc_usb30_mock_utmi_clk.c,		GCC_BASE, 0x0052},
+	{&gcc_usb_hs_ahb_clk.c,			GCC_BASE, 0x0069},
+	{&gcc_usb_hs_system_clk.c,		GCC_BASE, 0x0068},
+	{&gcc_usb_hsic_ahb_clk.c,		GCC_BASE, 0x0060},
+	{&gcc_usb_hsic_clk.c,			GCC_BASE, 0x0062},
+	{&gcc_usb_hsic_io_cal_clk.c,		GCC_BASE, 0x0063},
+	{&gcc_usb_hsic_system_clk.c,		GCC_BASE, 0x0061},
+	{&mmss_mmssnoc_ahb_clk.c,		MMSS_BASE, 0x0001},
+	{&mmss_mmssnoc_axi_clk.c,		MMSS_BASE, 0x0004},
+	{&camss_cci_cci_ahb_clk.c,		MMSS_BASE, 0x002e},
+	{&camss_cci_cci_clk.c,			MMSS_BASE, 0x002d},
+	{&camss_csi0_ahb_clk.c,			MMSS_BASE, 0x0042},
+	{&camss_csi0_clk.c,			MMSS_BASE, 0x0041},
+	{&camss_csi0phy_clk.c,			MMSS_BASE, 0x0043},
+	{&camss_csi0pix_clk.c,			MMSS_BASE, 0x0045},
+	{&camss_csi0rdi_clk.c,			MMSS_BASE, 0x0044},
+	{&camss_csi1_ahb_clk.c,			MMSS_BASE, 0x0047},
+	{&camss_csi1_clk.c,			MMSS_BASE, 0x0046},
+	{&camss_csi1phy_clk.c,			MMSS_BASE, 0x0048},
+	{&camss_csi1pix_clk.c,			MMSS_BASE, 0x004a},
+	{&camss_csi1rdi_clk.c,			MMSS_BASE, 0x0049},
+	{&camss_csi2_ahb_clk.c,			MMSS_BASE, 0x004c},
+	{&camss_csi2_clk.c,			MMSS_BASE, 0x004b},
+	{&camss_csi2phy_clk.c,			MMSS_BASE, 0x004d},
+	{&camss_csi2pix_clk.c,			MMSS_BASE, 0x004f},
+	{&camss_csi2rdi_clk.c,			MMSS_BASE, 0x004e},
+	{&camss_csi3_ahb_clk.c,			MMSS_BASE, 0x0051},
+	{&camss_csi3_clk.c,			MMSS_BASE, 0x0050},
+	{&camss_csi3phy_clk.c,			MMSS_BASE, 0x0052},
+	{&camss_csi3pix_clk.c,			MMSS_BASE, 0x0054},
+	{&camss_csi3rdi_clk.c,			MMSS_BASE, 0x0053},
+	{&camss_csi_vfe0_clk.c,			MMSS_BASE, 0x003f},
+	{&camss_csi_vfe1_clk.c,			MMSS_BASE, 0x0040},
+	{&camss_gp0_clk.c,			MMSS_BASE, 0x0027},
+	{&camss_gp1_clk.c,			MMSS_BASE, 0x0028},
+	{&camss_ispif_ahb_clk.c,		MMSS_BASE, 0x0055},
+	{&camss_jpeg_jpeg0_clk.c,		MMSS_BASE, 0x0032},
+	{&camss_jpeg_jpeg1_clk.c,		MMSS_BASE, 0x0033},
+	{&camss_jpeg_jpeg2_clk.c,		MMSS_BASE, 0x0034},
+	{&camss_jpeg_jpeg_ahb_clk.c,		MMSS_BASE, 0x0035},
+	{&camss_jpeg_jpeg_axi_clk.c,		MMSS_BASE, 0x0036},
+	{&camss_jpeg_jpeg_ocmemnoc_clk.c,	MMSS_BASE, 0x0037},
+	{&camss_mclk0_clk.c,			MMSS_BASE, 0x0029},
+	{&camss_mclk1_clk.c,			MMSS_BASE, 0x002a},
+	{&camss_mclk2_clk.c,			MMSS_BASE, 0x002b},
+	{&camss_mclk3_clk.c,			MMSS_BASE, 0x002c},
+	{&camss_micro_ahb_clk.c,		MMSS_BASE, 0x0026},
+	{&camss_phy0_csi0phytimer_clk.c,	MMSS_BASE, 0x002f},
+	{&camss_phy1_csi1phytimer_clk.c,	MMSS_BASE, 0x0030},
+	{&camss_phy2_csi2phytimer_clk.c,	MMSS_BASE, 0x0031},
+	{&camss_top_ahb_clk.c,			MMSS_BASE, 0x0025},
+	{&camss_vfe_cpp_ahb_clk.c,		MMSS_BASE, 0x003b},
+	{&camss_vfe_cpp_clk.c,			MMSS_BASE, 0x003a},
+	{&camss_vfe_vfe0_clk.c,			MMSS_BASE, 0x0038},
+	{&camss_vfe_vfe1_clk.c,			MMSS_BASE, 0x0039},
+	{&camss_vfe_vfe_ahb_clk.c,		MMSS_BASE, 0x003c},
+	{&camss_vfe_vfe_axi_clk.c,		MMSS_BASE, 0x003d},
+	{&camss_vfe_vfe_ocmemnoc_clk.c,		MMSS_BASE, 0x003e},
+	{&mdss_ahb_clk.c,			MMSS_BASE, 0x0022},
+	{&mdss_hdmi_clk.c,			MMSS_BASE, 0x001d},
+	{&mdss_mdp_clk.c,			MMSS_BASE, 0x0014},
+	{&mdss_mdp_lut_clk.c,			MMSS_BASE, 0x0015},
+	{&mdss_axi_clk.c,			MMSS_BASE, 0x0024},
+	{&mdss_vsync_clk.c,			MMSS_BASE, 0x001c},
+	{&mdss_esc0_clk.c,			MMSS_BASE, 0x0020},
+	{&mdss_esc1_clk.c,			MMSS_BASE, 0x0021},
+	{&mdss_edpaux_clk.c,			MMSS_BASE, 0x001b},
+	{&mdss_byte0_clk.c,			MMSS_BASE, 0x001e},
+	{&mdss_byte1_clk.c,			MMSS_BASE, 0x001f},
+	{&mdss_edplink_clk.c,			MMSS_BASE, 0x001a},
+	{&mdss_edppixel_clk.c,			MMSS_BASE, 0x0019},
+	{&mdss_extpclk_clk.c,			MMSS_BASE, 0x0018},
+	{&mdss_hdmi_ahb_clk.c,			MMSS_BASE, 0x0023},
+	{&mdss_pclk0_clk.c,			MMSS_BASE, 0x0016},
+	{&mdss_pclk1_clk.c,			MMSS_BASE, 0x0017},
+	{&audio_core_lpaif_pri_clk_src.c,	LPASS_BASE, 0x0017},
+	{&audio_core_lpaif_sec_clk_src.c,	LPASS_BASE, 0x0016},
+	{&audio_core_lpaif_ter_clk_src.c,	LPASS_BASE, 0x0015},
+	{&audio_core_lpaif_quad_clk_src.c,	LPASS_BASE, 0x0014},
+	{&audio_core_lpaif_pcm0_clk_src.c,	LPASS_BASE, 0x0013},
+	{&audio_core_lpaif_pcm1_clk_src.c,	LPASS_BASE, 0x0012},
+	{&audio_core_slimbus_core_clk.c,	LPASS_BASE, 0x003d},
+	{&audio_core_slimbus_lfabif_clk.c,	LPASS_BASE, 0x003e},
+	{&q6ss_xo_clk.c,			LPASS_BASE, 0x002b},
+	{&q6ss_ahb_lfabif_clk.c,		LPASS_BASE, 0x001e},
+	{&mss_bus_q6_clk.c,			MSS_BASE, 0x003c},
+	{&mss_xo_q6_clk.c,			MSS_BASE, 0x0007},
+
+	{&dummy_clk,				N_BASES,   0x0000},
+};
+
+static int measure_clk_set_parent(struct clk *c, struct clk *parent)
+{
+	struct measure_clk *clk = to_measure_clk(c);
+	unsigned long flags;
+	u32 regval, clk_sel, i;
+
+	if (!parent)
+		return -EINVAL;
+
+	for (i = 0; i < (ARRAY_SIZE(measure_mux) - 1); i++)
+		if (measure_mux[i].c == parent)
+			break;
+
+	if (measure_mux[i].c == &dummy_clk)
+		return -EINVAL;
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	/*
+	 * Program the test vector, measurement period (sample_ticks)
+	 * and scaling multiplier.
+	 */
+	clk->sample_ticks = 0x10000;
+	clk->multiplier = 1;
+
+	writel_relaxed(0, MSS_REG_BASE(MSS_DEBUG_CLK_CTL_REG));
+	writel_relaxed(0, LPASS_REG_BASE(LPASS_DEBUG_CLK_CTL_REG));
+	writel_relaxed(0, MMSS_REG_BASE(MMSS_DEBUG_CLK_CTL_REG));
+	writel_relaxed(0, GCC_REG_BASE(GCC_DEBUG_CLK_CTL_REG));
+
+	switch (measure_mux[i].base) {
+
+	case GCC_BASE:
+		clk_sel = measure_mux[i].debug_mux;
+		break;
+
+	case MMSS_BASE:
+		clk_sel = 0x02C;
+		regval = BVAL(11, 0, measure_mux[i].debug_mux);
+		writel_relaxed(regval, MMSS_REG_BASE(MMSS_DEBUG_CLK_CTL_REG));
+
+		/* Activate debug clock output */
+		regval |= BIT(16);
+		writel_relaxed(regval, MMSS_REG_BASE(MMSS_DEBUG_CLK_CTL_REG));
+		break;
+
+	case LPASS_BASE:
+		clk_sel = 0x169;
+		regval = BVAL(11, 0, measure_mux[i].debug_mux);
+		writel_relaxed(regval, LPASS_REG_BASE(LPASS_DEBUG_CLK_CTL_REG));
+
+		/* Activate debug clock output */
+		regval |= BIT(16);
+		writel_relaxed(regval, LPASS_REG_BASE(LPASS_DEBUG_CLK_CTL_REG));
+		break;
+
+	case MSS_BASE:
+		clk_sel = 0x32;
+		regval = BVAL(5, 0, measure_mux[i].debug_mux);
+		writel_relaxed(regval, MSS_REG_BASE(MSS_DEBUG_CLK_CTL_REG));
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* Set debug mux clock index */
+	regval = BVAL(8, 0, clk_sel);
+	writel_relaxed(regval, GCC_REG_BASE(GCC_DEBUG_CLK_CTL_REG));
+
+	/* Activate debug clock output */
+	regval |= BIT(16);
+	writel_relaxed(regval, GCC_REG_BASE(GCC_DEBUG_CLK_CTL_REG));
+
+	/* Make sure test vector is set before starting measurements. */
+	mb();
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	return 0;
+}
+
+/* Sample clock for 'ticks' reference clock ticks. */
+static u32 run_measurement(unsigned ticks)
+{
+	/* Stop counters and set the XO4 counter start value. */
+	writel_relaxed(ticks, GCC_REG_BASE(CLOCK_FRQ_MEASURE_CTL_REG));
+
+	/* Wait for timer to become ready. */
+	while ((readl_relaxed(GCC_REG_BASE(CLOCK_FRQ_MEASURE_STATUS_REG)) &
+			BIT(25)) != 0)
+		cpu_relax();
+
+	/* Run measurement and wait for completion. */
+	writel_relaxed(BIT(20)|ticks, GCC_REG_BASE(CLOCK_FRQ_MEASURE_CTL_REG));
+	while ((readl_relaxed(GCC_REG_BASE(CLOCK_FRQ_MEASURE_STATUS_REG)) &
+			BIT(25)) == 0)
+		cpu_relax();
+
+	/* Return measured ticks. */
+	return readl_relaxed(GCC_REG_BASE(CLOCK_FRQ_MEASURE_STATUS_REG)) &
+				BM(24, 0);
+}
+
+/*
+ * Perform a hardware rate measurement for a given clock.
+ * FOR DEBUG USE ONLY: Measurements take ~15 ms!
+ */
+static unsigned long measure_clk_get_rate(struct clk *c)
+{
+	unsigned long flags;
+	u32 gcc_xo4_reg_backup;
+	u64 raw_count_short, raw_count_full;
+	struct measure_clk *clk = to_measure_clk(c);
+	unsigned ret;
+
+	ret = clk_prepare_enable(&cxo_clk_src.c);
+	if (ret) {
+		pr_warning("CXO clock failed to enable. Can't measure\n");
+		return 0;
+	}
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+
+	/* Enable CXO/4 and RINGOSC branch. */
+	gcc_xo4_reg_backup = readl_relaxed(GCC_REG_BASE(GCC_XO_DIV4_CBCR_REG));
+	writel_relaxed(0x1, GCC_REG_BASE(GCC_XO_DIV4_CBCR_REG));
+
+	/*
+	 * The ring oscillator counter will not reset if the measured clock
+	 * is not running.  To detect this, run a short measurement before
+	 * the full measurement.  If the raw results of the two are the same
+	 * then the clock must be off.
+	 */
+
+	/* Run a short measurement. (~1 ms) */
+	raw_count_short = run_measurement(0x1000);
+	/* Run a full measurement. (~14 ms) */
+	raw_count_full = run_measurement(clk->sample_ticks);
+
+	writel_relaxed(gcc_xo4_reg_backup, GCC_REG_BASE(GCC_XO_DIV4_CBCR_REG));
+
+	/* Return 0 if the clock is off. */
+	if (raw_count_full == raw_count_short) {
+		ret = 0;
+	} else {
+		/* Compute rate in Hz. */
+		raw_count_full = ((raw_count_full * 10) + 15) * 4800000;
+		do_div(raw_count_full, ((clk->sample_ticks * 10) + 35));
+		ret = (raw_count_full * clk->multiplier);
+	}
+
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	clk_disable_unprepare(&cxo_clk_src.c);
+
+	return ret;
+}
+#else /* !CONFIG_DEBUG_FS */
+static int measure_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	return -EINVAL;
+}
+
+static unsigned long measure_clk_get_rate(struct clk *clk)
+{
+	return 0;
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static struct clk_ops clk_ops_measure = {
+	.set_parent = measure_clk_set_parent,
+	.get_rate = measure_clk_get_rate,
+};
+
+static struct measure_clk measure_clk = {
+	.c = {
+		.dbg_name = "measure_clk",
+		.ops = &clk_ops_measure,
+		CLK_INIT(measure_clk.c),
+	},
+	.multiplier = 1,
+};
+
+static struct clk_lookup msm_clocks_copper[] = {
+	CLK_LOOKUP("xo",	cxo_clk_src.c,	"msm_otg"),
+	CLK_LOOKUP("xo",	cxo_clk_src.c,	"pil-q6v5-lpass"),
+	CLK_LOOKUP("xo",	cxo_clk_src.c,	"pil_pronto"),
+	CLK_LOOKUP("measure",	measure_clk.c,	"debug"),
+
+	CLK_LOOKUP("dma_bam_pclk", gcc_bam_dma_ahb_clk.c, "msm_sps"),
+	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "msm_serial_hsl.0"),
+	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "spi_qsd.1"),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup1_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup1_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup2_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup2_spi_apps_clk.c, "spi_qsd.1"),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup3_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup3_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup4_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup4_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup5_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup5_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup6_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup6_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_uart1_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_uart2_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_uart3_apps_clk.c, "msm_serial_hsl.0"),
+	CLK_LOOKUP("core_clk", gcc_blsp1_uart4_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_uart5_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_uart6_apps_clk.c, ""),
+
+	CLK_LOOKUP("iface_clk", gcc_blsp2_ahb_clk.c, "f9966000.i2c"),
+	CLK_LOOKUP("iface_clk", gcc_blsp2_ahb_clk.c, "f995e000.serial"),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup1_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup1_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup2_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup2_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup3_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup3_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup4_i2c_apps_clk.c, "f9966000.i2c"),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup4_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup5_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup5_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup6_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup6_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_uart1_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_uart2_apps_clk.c, "f995e000.serial"),
+	CLK_LOOKUP("core_clk", gcc_blsp2_uart3_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_uart4_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_uart5_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_uart6_apps_clk.c, ""),
+
+	CLK_LOOKUP("core_clk", gcc_ce1_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_ce2_clk.c, ""),
+	CLK_LOOKUP("iface_clk", gcc_ce1_ahb_clk.c, ""),
+	CLK_LOOKUP("iface_clk", gcc_ce2_ahb_clk.c, ""),
+	CLK_LOOKUP("bus_clk", gcc_ce1_axi_clk.c, ""),
+	CLK_LOOKUP("bus_clk", gcc_ce2_axi_clk.c, ""),
+
+	CLK_LOOKUP("core_clk", gcc_gp1_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_gp2_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_gp3_clk.c, ""),
+
+	CLK_LOOKUP("core_clk", gcc_pdm2_clk.c, ""),
+	CLK_LOOKUP("iface_clk", gcc_pdm_ahb_clk.c, ""),
+	CLK_LOOKUP("iface_clk", gcc_prng_ahb_clk.c, ""),
+
+	CLK_LOOKUP("iface_clk", gcc_sdcc1_ahb_clk.c, "msm_sdcc.1"),
+	CLK_LOOKUP("core_clk", gcc_sdcc1_apps_clk.c, "msm_sdcc.1"),
+	CLK_LOOKUP("iface_clk", gcc_sdcc2_ahb_clk.c, "msm_sdcc.2"),
+	CLK_LOOKUP("core_clk", gcc_sdcc2_apps_clk.c, "msm_sdcc.2"),
+	CLK_LOOKUP("iface_clk", gcc_sdcc3_ahb_clk.c, "msm_sdcc.3"),
+	CLK_LOOKUP("core_clk", gcc_sdcc3_apps_clk.c, "msm_sdcc.3"),
+	CLK_LOOKUP("iface_clk", gcc_sdcc4_ahb_clk.c, "msm_sdcc.4"),
+	CLK_LOOKUP("core_clk", gcc_sdcc4_apps_clk.c, "msm_sdcc.4"),
+
+	CLK_LOOKUP("iface_clk", gcc_tsif_ahb_clk.c, ""),
+	CLK_LOOKUP("ref_clk", gcc_tsif_ref_clk.c, ""),
+
+	CLK_LOOKUP("core_clk", gcc_usb30_master_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_usb30_mock_utmi_clk.c, ""),
+	CLK_LOOKUP("iface_clk", gcc_usb_hs_ahb_clk.c, "msm_otg"),
+	CLK_LOOKUP("core_clk", gcc_usb_hs_system_clk.c, ""),
+	CLK_LOOKUP("iface_clk", gcc_usb_hsic_ahb_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_usb_hsic_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_usb_hsic_io_cal_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_usb_hsic_system_clk.c, ""),
+
+	/* Multimedia clocks */
+	CLK_LOOKUP("bus_clk_src", axi_clk_src.c, ""),
+	CLK_LOOKUP("bus_clk_src", ahb_clk_src.c, ""),
+	CLK_LOOKUP("bus_clk", mmss_mmssnoc_ahb_clk.c, ""),
+	CLK_LOOKUP("bus_clk", mmss_mmssnoc_axi_clk.c, ""),
+	CLK_LOOKUP("core_clk", mdss_edpaux_clk.c, ""),
+	CLK_LOOKUP("core_clk", mdss_edppixel_clk.c, ""),
+	CLK_LOOKUP("core_clk", mdss_esc0_clk.c, ""),
+	CLK_LOOKUP("core_clk", mdss_esc1_clk.c, ""),
+	CLK_LOOKUP("iface_clk", mdss_hdmi_ahb_clk.c, ""),
+	CLK_LOOKUP("core_clk", mdss_hdmi_clk.c, ""),
+	CLK_LOOKUP("core_clk", mdss_mdp_clk.c, ""),
+	CLK_LOOKUP("core_clk", mdss_mdp_lut_clk.c, ""),
+	CLK_LOOKUP("core_clk", mdp_clk_src.c, ""),
+	CLK_LOOKUP("core_clk", mdss_vsync_clk.c, ""),
+	CLK_LOOKUP("iface_clk", camss_cci_cci_ahb_clk.c, ""),
+	CLK_LOOKUP("core_clk", camss_cci_cci_clk.c, ""),
+	CLK_LOOKUP("iface_clk", camss_csi0_ahb_clk.c, ""),
+	CLK_LOOKUP("camss_csi0_clk", camss_csi0_clk.c, ""),
+	CLK_LOOKUP("camss_csi0phy_clk", camss_csi0phy_clk.c, ""),
+	CLK_LOOKUP("camss_csi0pix_clk", camss_csi0pix_clk.c, ""),
+	CLK_LOOKUP("camss_csi0rdi_clk", camss_csi0rdi_clk.c, ""),
+	CLK_LOOKUP("iface_clk", camss_csi1_ahb_clk.c, ""),
+	CLK_LOOKUP("camss_csi1_clk", camss_csi1_clk.c, ""),
+	CLK_LOOKUP("camss_csi1phy_clk", camss_csi1phy_clk.c, ""),
+	CLK_LOOKUP("camss_csi1pix_clk", camss_csi1pix_clk.c, ""),
+	CLK_LOOKUP("camss_csi1rdi_clk", camss_csi1rdi_clk.c, ""),
+	CLK_LOOKUP("iface_clk", camss_csi2_ahb_clk.c, ""),
+	CLK_LOOKUP("camss_csi2_clk", camss_csi2_clk.c, ""),
+	CLK_LOOKUP("camss_csi2phy_clk", camss_csi2phy_clk.c, ""),
+	CLK_LOOKUP("camss_csi2pix_clk", camss_csi2pix_clk.c, ""),
+	CLK_LOOKUP("camss_csi2rdi_clk", camss_csi2rdi_clk.c, ""),
+	CLK_LOOKUP("iface_clk", camss_csi3_ahb_clk.c, ""),
+	CLK_LOOKUP("camss_csi3_clk", camss_csi3_clk.c, ""),
+	CLK_LOOKUP("camss_csi3phy_clk", camss_csi3phy_clk.c, ""),
+	CLK_LOOKUP("camss_csi3pix_clk", camss_csi3pix_clk.c, ""),
+	CLK_LOOKUP("camss_csi3rdi_clk", camss_csi3rdi_clk.c, ""),
+	CLK_LOOKUP("camss_csi0_clk_src", csi0_clk_src.c, ""),
+	CLK_LOOKUP("camss_csi1_clk_src", csi1_clk_src.c, ""),
+	CLK_LOOKUP("camss_csi2_clk_src", csi2_clk_src.c, ""),
+	CLK_LOOKUP("camss_csi3_clk_src", csi3_clk_src.c, ""),
+	CLK_LOOKUP("camss_csi_vfe0_clk", camss_csi_vfe0_clk.c, ""),
+	CLK_LOOKUP("camss_csi_vfe1_clk", camss_csi_vfe1_clk.c, ""),
+	CLK_LOOKUP("core_clk", camss_gp0_clk.c, ""),
+	CLK_LOOKUP("core_clk", camss_gp1_clk.c, ""),
+	CLK_LOOKUP("iface_clk", camss_ispif_ahb_clk.c, ""),
+	CLK_LOOKUP("core_clk", camss_jpeg_jpeg0_clk.c, ""),
+	CLK_LOOKUP("core_clk", camss_jpeg_jpeg1_clk.c, ""),
+	CLK_LOOKUP("core_clk", camss_jpeg_jpeg2_clk.c, ""),
+	CLK_LOOKUP("iface_clk", camss_jpeg_jpeg_ahb_clk.c,
+						"fda64000.qcom,iommu"),
+	CLK_LOOKUP("core_clk", camss_jpeg_jpeg_axi_clk.c,
+						"fda64000.qcom,iommu"),
+	CLK_LOOKUP("bus_clk", camss_jpeg_jpeg_axi_clk.c, ""),
+	CLK_LOOKUP("bus_clk", camss_jpeg_jpeg_ocmemnoc_clk.c, ""),
+	CLK_LOOKUP("core_clk", camss_mclk0_clk.c, ""),
+	CLK_LOOKUP("core_clk", camss_mclk1_clk.c, ""),
+	CLK_LOOKUP("core_clk", camss_mclk2_clk.c, ""),
+	CLK_LOOKUP("core_clk", camss_mclk3_clk.c, ""),
+	CLK_LOOKUP("iface_clk", camss_micro_ahb_clk.c, ""),
+	CLK_LOOKUP("core_clk", camss_phy0_csi0phytimer_clk.c, ""),
+	CLK_LOOKUP("core_clk", camss_phy1_csi1phytimer_clk.c, ""),
+	CLK_LOOKUP("core_clk", camss_phy2_csi2phytimer_clk.c, ""),
+	CLK_LOOKUP("iface_clk", camss_top_ahb_clk.c, ""),
+	CLK_LOOKUP("iface_clk", camss_vfe_cpp_ahb_clk.c, ""),
+	CLK_LOOKUP("core_clk", camss_vfe_cpp_clk.c, ""),
+	CLK_LOOKUP("camss_vfe_vfe0_clk", camss_vfe_vfe0_clk.c, ""),
+	CLK_LOOKUP("camss_vfe_vfe1_clk", camss_vfe_vfe1_clk.c, ""),
+	CLK_LOOKUP("vfe0_clk_src", vfe0_clk_src.c, ""),
+	CLK_LOOKUP("vfe1_clk_src", vfe1_clk_src.c, ""),
+	CLK_LOOKUP("iface_clk", camss_vfe_vfe_ahb_clk.c, ""),
+	CLK_LOOKUP("bus_clk", camss_vfe_vfe_axi_clk.c, ""),
+	CLK_LOOKUP("bus_clk", camss_vfe_vfe_ocmemnoc_clk.c, ""),
+	CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd928000.qcom,iommu"),
+	CLK_LOOKUP("core_clk", mdss_axi_clk.c, "fd928000.qcom,iommu"),
+	CLK_LOOKUP("bus_clk", mdss_axi_clk.c, ""),
+	CLK_LOOKUP("core_clk", oxili_gfx3d_clk.c, ""),
+	CLK_LOOKUP("iface_clk", oxilicx_ahb_clk.c, ""),
+	CLK_LOOKUP("bus_clk", oxilicx_axi_clk.c, ""),
+	CLK_LOOKUP("iface_clk", venus0_ahb_clk.c, "fdc84000.qcom,iommu"),
+	CLK_LOOKUP("core_clk", venus0_axi_clk.c, "fdc84000.qcom,iommu"),
+	CLK_LOOKUP("bus_clk", venus0_axi_clk.c, ""),
+
+	/* LPASS clocks */
+	CLK_LOOKUP("core_clk", audio_core_slimbus_core_clk.c, "fe12f000.slim"),
+	CLK_LOOKUP("iface_clk", audio_core_slimbus_lfabif_clk.c,
+			"fe12f000.slim"),
+	CLK_LOOKUP("core_clk", audio_core_lpaif_codec_spkr_clk_src.c, ""),
+	CLK_LOOKUP("osr_clk", audio_core_lpaif_codec_spkr_osr_clk.c, ""),
+	CLK_LOOKUP("ebit_clk", audio_core_lpaif_codec_spkr_ebit_clk.c, ""),
+	CLK_LOOKUP("ibit_clk", audio_core_lpaif_codec_spkr_ibit_clk.c, ""),
+	CLK_LOOKUP("core_clk", audio_core_lpaif_pri_clk_src.c, ""),
+	CLK_LOOKUP("osr_clk", audio_core_lpaif_pri_osr_clk.c, ""),
+	CLK_LOOKUP("ebit_clk", audio_core_lpaif_pri_ebit_clk.c, ""),
+	CLK_LOOKUP("ibit_clk", audio_core_lpaif_pri_ibit_clk.c, ""),
+	CLK_LOOKUP("core_clk", audio_core_lpaif_sec_clk_src.c, ""),
+	CLK_LOOKUP("osr_clk", audio_core_lpaif_sec_osr_clk.c, ""),
+	CLK_LOOKUP("ebit_clk", audio_core_lpaif_sec_ebit_clk.c, ""),
+	CLK_LOOKUP("ibit_clk", audio_core_lpaif_sec_ibit_clk.c, ""),
+	CLK_LOOKUP("core_clk", audio_core_lpaif_ter_clk_src.c, ""),
+	CLK_LOOKUP("osr_clk", audio_core_lpaif_ter_osr_clk.c, ""),
+	CLK_LOOKUP("ebit_clk", audio_core_lpaif_ter_ebit_clk.c, ""),
+	CLK_LOOKUP("ibit_clk", audio_core_lpaif_ter_ibit_clk.c, ""),
+	CLK_LOOKUP("core_clk", audio_core_lpaif_quad_clk_src.c, ""),
+	CLK_LOOKUP("osr_clk", audio_core_lpaif_quad_osr_clk.c, ""),
+	CLK_LOOKUP("ebit_clk", audio_core_lpaif_quad_ebit_clk.c, ""),
+	CLK_LOOKUP("ibit_clk", audio_core_lpaif_quad_ibit_clk.c, ""),
+	CLK_LOOKUP("core_clk", audio_core_lpaif_pcm0_clk_src.c, ""),
+	CLK_LOOKUP("ebit_clk", audio_core_lpaif_pcm0_ebit_clk.c, ""),
+	CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm0_ibit_clk.c, ""),
+	CLK_LOOKUP("core_clk", audio_core_lpaif_pcm1_clk_src.c, ""),
+	CLK_LOOKUP("ebit_clk", audio_core_lpaif_pcm1_ebit_clk.c, ""),
+	CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm1_ibit_clk.c, ""),
+
+	CLK_LOOKUP("core_clk",       mss_xo_q6_clk.c, ""),
+	CLK_LOOKUP("bus_clk",       mss_bus_q6_clk.c, ""),
+	CLK_LOOKUP("core_clk",         q6ss_xo_clk.c, "pil-q6v5-lpass"),
+	CLK_LOOKUP("bus_clk",  q6ss_ahb_lfabif_clk.c, "pil-q6v5-lpass"),
+	CLK_LOOKUP("mem_clk", gcc_boot_rom_ahb_clk.c, ""),
+	CLK_LOOKUP("bus_clk",  gcc_mss_cfg_ahb_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_prng_ahb_clk.c, "msm_rng"),
+
+	/* TODO: Remove dummy clocks as soon as they become unnecessary */
+	CLK_DUMMY("phy_clk",       NULL,    "msm_otg", OFF),
+	CLK_DUMMY("core_clk",      NULL,    "msm_otg", OFF),
+	CLK_DUMMY("dfab_clk",  DFAB_CLK,    "msm_sps", OFF),
+	CLK_DUMMY("mem_clk",       NULL,    "msm_sps", OFF),
+	CLK_DUMMY("bus_clk",       NULL,        "scm", OFF),
+};
+
+static struct pll_config_regs gpll0_regs __initdata = {
+	.l_reg = (void __iomem *)GPLL0_L_REG,
+	.m_reg = (void __iomem *)GPLL0_M_REG,
+	.n_reg = (void __iomem *)GPLL0_N_REG,
+	.config_reg = (void __iomem *)GPLL0_USER_CTL_REG,
+	.mode_reg = (void __iomem *)GPLL0_MODE_REG,
+	.base = &virt_bases[GCC_BASE],
+};
+
+/* GPLL0 at 600 MHz, main output enabled. */
+static struct pll_config gpll0_config __initdata = {
+	.l = 0x1f,
+	.m = 0x1,
+	.n = 0x4,
+	.vco_val = 0x0,
+	.vco_mask = BM(21, 20),
+	.pre_div_val = 0x0,
+	.pre_div_mask = BM(14, 12),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(9, 8),
+	.mn_ena_val = BIT(24),
+	.mn_ena_mask = BIT(24),
+	.main_output_val = BIT(0),
+	.main_output_mask = BIT(0),
+};
+
+static struct pll_config_regs gpll1_regs __initdata = {
+	.l_reg = (void __iomem *)GPLL1_L_REG,
+	.m_reg = (void __iomem *)GPLL1_M_REG,
+	.n_reg = (void __iomem *)GPLL1_N_REG,
+	.config_reg = (void __iomem *)GPLL1_USER_CTL_REG,
+	.mode_reg = (void __iomem *)GPLL1_MODE_REG,
+	.base = &virt_bases[GCC_BASE],
+};
+
+/* GPLL1 at 480 MHz, main output enabled. */
+static struct pll_config gpll1_config __initdata = {
+	.l = 0x19,
+	.m = 0x0,
+	.n = 0x1,
+	.vco_val = 0x0,
+	.vco_mask = BM(21, 20),
+	.pre_div_val = 0x0,
+	.pre_div_mask = BM(14, 12),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(9, 8),
+	.main_output_val = BIT(0),
+	.main_output_mask = BIT(0),
+};
+
+static struct pll_config_regs mmpll0_regs __initdata = {
+	.l_reg = (void __iomem *)MMPLL0_L_REG,
+	.m_reg = (void __iomem *)MMPLL0_M_REG,
+	.n_reg = (void __iomem *)MMPLL0_N_REG,
+	.config_reg = (void __iomem *)MMPLL0_USER_CTL_REG,
+	.mode_reg = (void __iomem *)MMPLL0_MODE_REG,
+	.base = &virt_bases[MMSS_BASE],
+};
+
+/* MMPLL0 at 800 MHz, main output enabled. */
+static struct pll_config mmpll0_config __initdata = {
+	.l = 0x29,
+	.m = 0x2,
+	.n = 0x3,
+	.vco_val = 0x0,
+	.vco_mask = BM(21, 20),
+	.pre_div_val = 0x0,
+	.pre_div_mask = BM(14, 12),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(9, 8),
+	.mn_ena_val = BIT(24),
+	.mn_ena_mask = BIT(24),
+	.main_output_val = BIT(0),
+	.main_output_mask = BIT(0),
+};
+
+static struct pll_config_regs mmpll1_regs __initdata = {
+	.l_reg = (void __iomem *)MMPLL1_L_REG,
+	.m_reg = (void __iomem *)MMPLL1_M_REG,
+	.n_reg = (void __iomem *)MMPLL1_N_REG,
+	.config_reg = (void __iomem *)MMPLL1_USER_CTL_REG,
+	.mode_reg = (void __iomem *)MMPLL1_MODE_REG,
+	.base = &virt_bases[MMSS_BASE],
+};
+
+/* MMPLL1 at 1000 MHz, main output enabled. */
+static struct pll_config mmpll1_config __initdata = {
+	.l = 0x34,
+	.m = 0x1,
+	.n = 0xC,
+	.vco_val = 0x0,
+	.vco_mask = BM(21, 20),
+	.pre_div_val = 0x0,
+	.pre_div_mask = BM(14, 12),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(9, 8),
+	.mn_ena_val = BIT(24),
+	.mn_ena_mask = BIT(24),
+	.main_output_val = BIT(0),
+	.main_output_mask = BIT(0),
+};
+
+static struct pll_config_regs mmpll3_regs __initdata = {
+	.l_reg = (void __iomem *)MMPLL3_L_REG,
+	.m_reg = (void __iomem *)MMPLL3_M_REG,
+	.n_reg = (void __iomem *)MMPLL3_N_REG,
+	.config_reg = (void __iomem *)MMPLL3_USER_CTL_REG,
+	.mode_reg = (void __iomem *)MMPLL3_MODE_REG,
+	.base = &virt_bases[MMSS_BASE],
+};
+
+/* MMPLL3 at 820 MHz, main output enabled. */
+static struct pll_config mmpll3_config __initdata = {
+	.l = 0x2A,
+	.m = 0x11,
+	.n = 0x18,
+	.vco_val = 0x0,
+	.vco_mask = BM(21, 20),
+	.pre_div_val = 0x0,
+	.pre_div_mask = BM(14, 12),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(9, 8),
+	.mn_ena_val = BIT(24),
+	.mn_ena_mask = BIT(24),
+	.main_output_val = BIT(0),
+	.main_output_mask = BIT(0),
+};
+
+static struct pll_config_regs lpapll0_regs __initdata = {
+	.l_reg = (void __iomem *)LPAPLL_L_REG,
+	.m_reg = (void __iomem *)LPAPLL_M_REG,
+	.n_reg = (void __iomem *)LPAPLL_N_REG,
+	.config_reg = (void __iomem *)LPAPLL_USER_CTL_REG,
+	.mode_reg = (void __iomem *)LPAPLL_MODE_REG,
+	.base = &virt_bases[LPASS_BASE],
+};
+
+/* LPAPLL0 at 491.52 MHz, main output enabled. */
+static struct pll_config lpapll0_config __initdata = {
+	.l = 0x33,
+	.m = 0x1,
+	.n = 0x5,
+	.vco_val = 0x0,
+	.vco_mask = BM(21, 20),
+	.pre_div_val = BVAL(14, 12, 0x1),
+	.pre_div_mask = BM(14, 12),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(9, 8),
+	.mn_ena_val = BIT(24),
+	.mn_ena_mask = BIT(24),
+	.main_output_val = BIT(0),
+	.main_output_mask = BIT(0),
+};
+
+#define PLL_AUX_OUTPUT BIT(1)
+
+static void __init reg_init(void)
+{
+	u32 regval;
+
+	if (!(readl_relaxed(GCC_REG_BASE(GPLL0_STATUS_REG))
+			& gpll0_clk_src.status_mask))
+		configure_pll(&gpll0_config, &gpll0_regs, 1);
+
+	if (!(readl_relaxed(GCC_REG_BASE(GPLL1_STATUS_REG))
+			& gpll1_clk_src.status_mask))
+		configure_pll(&gpll1_config, &gpll1_regs, 1);
+
+	configure_pll(&mmpll0_config, &mmpll0_regs, 1);
+	configure_pll(&mmpll1_config, &mmpll1_regs, 1);
+	configure_pll(&mmpll3_config, &mmpll3_regs, 0);
+	configure_pll(&lpapll0_config, &lpapll0_regs, 1);
+
+	/* Active GPLL0's aux output. This is needed by acpuclock. */
+	regval = readl_relaxed(GCC_REG_BASE(GPLL0_USER_CTL_REG));
+	regval |= BIT(PLL_AUX_OUTPUT);
+	writel_relaxed(regval, GCC_REG_BASE(GPLL0_USER_CTL_REG));
+
+	/* Vote for GPLL0 to turn on. Needed by acpuclock. */
+	regval = readl_relaxed(GCC_REG_BASE(APCS_GPLL_ENA_VOTE_REG));
+	regval |= BIT(0);
+	writel_relaxed(regval, GCC_REG_BASE(APCS_GPLL_ENA_VOTE_REG));
+
+	/*
+	 * TODO: Confirm that no clocks need to be voted on in this sleep vote
+	 * register.
+	 */
+	writel_relaxed(0x0, GCC_REG_BASE(APCS_CLOCK_SLEEP_ENA_VOTE));
+}
+
+static void __init msmcopper_clock_post_init(void)
+{
+	clk_set_rate(&ahb_clk_src.c, 80000000);
+	clk_set_rate(&axi_clk_src.c, 333330000);
+
+	/* Set rates for single-rate clocks. */
+	clk_set_rate(&usb30_master_clk_src.c,
+			usb30_master_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&tsif_ref_clk_src.c,
+			tsif_ref_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&usb_hs_system_clk_src.c,
+			usb_hs_system_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&usb_hsic_clk_src.c,
+			usb_hsic_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&usb_hsic_io_cal_clk_src.c,
+			usb_hsic_io_cal_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&usb_hsic_system_clk_src.c,
+			usb_hsic_system_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&usb30_mock_utmi_clk_src.c,
+			usb30_mock_utmi_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&pdm2_clk_src.c, pdm2_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&cci_clk_src.c, cci_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&mclk0_clk_src.c, mclk0_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&mclk1_clk_src.c, mclk1_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&mclk2_clk_src.c, mclk2_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&edpaux_clk_src.c, edpaux_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&esc0_clk_src.c, esc0_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&esc1_clk_src.c, esc1_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&hdmi_clk_src.c, hdmi_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&vsync_clk_src.c, vsync_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&audio_core_slimbus_core_clk_src.c,
+			audio_core_slimbus_core_clk_src.freq_tbl[0].freq_hz);
+}
+
+#define GCC_CC_PHYS	0xFC400000
+#define GCC_CC_SIZE	SZ_16K
+
+#define MMSS_CC_PHYS	0xFD8C0000
+#define MMSS_CC_SIZE	SZ_256K
+
+#define LPASS_CC_PHYS	0xFE000000
+#define LPASS_CC_SIZE	SZ_256K
+
+#define MSS_CC_PHYS	0xFC980000
+#define MSS_CC_SIZE	SZ_16K
+
+static void __init msmcopper_clock_pre_init(void)
+{
+	virt_bases[GCC_BASE] = ioremap(GCC_CC_PHYS, GCC_CC_SIZE);
+	if (!virt_bases[GCC_BASE])
+		panic("clock-copper: Unable to ioremap GCC memory!");
+
+	virt_bases[MMSS_BASE] = ioremap(MMSS_CC_PHYS, MMSS_CC_SIZE);
+	if (!virt_bases[MMSS_BASE])
+		panic("clock-copper: Unable to ioremap MMSS_CC memory!");
+
+	virt_bases[LPASS_BASE] = ioremap(LPASS_CC_PHYS, LPASS_CC_SIZE);
+	if (!virt_bases[LPASS_BASE])
+		panic("clock-copper: Unable to ioremap LPASS_CC memory!");
+
+	virt_bases[MSS_BASE] = ioremap(MSS_CC_PHYS, MSS_CC_SIZE);
+	if (!virt_bases[MSS_BASE])
+		panic("clock-copper: Unable to ioremap MSS_CC memory!");
+
+	clk_ops_local_pll.enable = copper_pll_clk_enable;
+
+	reg_init();
+}
+
+struct clock_init_data msmcopper_clock_init_data __initdata = {
+	.table = msm_clocks_copper,
+	.size = ARRAY_SIZE(msm_clocks_copper),
+	.pre_init = msmcopper_clock_pre_init,
+	.post_init = msmcopper_clock_post_init,
+};
diff --git a/arch/arm/mach-msm/clock-debug.c b/arch/arm/mach-msm/clock-debug.c
index 4886404..e8c3e05 100644
--- a/arch/arm/mach-msm/clock-debug.c
+++ b/arch/arm/mach-msm/clock-debug.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2007-2012, Code Aurora Forum. 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
@@ -17,7 +17,11 @@
 #include <linux/module.h>
 #include <linux/ctype.h>
 #include <linux/debugfs.h>
+#include <linux/seq_file.h>
 #include <linux/clk.h>
+#include <linux/list.h>
+#include <linux/clkdev.h>
+
 #include "clock.h"
 
 static int clock_debug_rate_set(void *data, u64 val)
@@ -27,15 +31,12 @@
 
 	/* Only increases to max rate will succeed, but that's actually good
 	 * for debugging purposes so we don't check for error. */
-	if (clock->flags & CLK_MAX)
+	if (clock->flags & CLKFLAG_MAX)
 		clk_set_max_rate(clock, val);
-	if (clock->flags & CLK_MIN)
-		ret = clk_set_min_rate(clock, val);
-	else
-		ret = clk_set_rate(clock, val);
-	if (ret != 0)
-		printk(KERN_ERR "clk_set%s_rate failed (%d)\n",
-			(clock->flags & CLK_MIN) ? "_min" : "", ret);
+	ret = clk_set_rate(clock, val);
+	if (ret)
+		pr_err("clk_set_rate failed (%d)\n", ret);
+
 	return ret;
 }
 
@@ -49,15 +50,51 @@
 DEFINE_SIMPLE_ATTRIBUTE(clock_rate_fops, clock_debug_rate_get,
 			clock_debug_rate_set, "%llu\n");
 
+static struct clk *measure;
+
+static int clock_debug_measure_get(void *data, u64 *val)
+{
+	struct clk *clock = data;
+	int ret, is_hw_gated;
+
+	/* Check to see if the clock is in hardware gating mode */
+	if (clock->flags & CLKFLAG_HWCG)
+		is_hw_gated = clock->ops->in_hwcg_mode(clock);
+	else
+		is_hw_gated = 0;
+
+	ret = clk_set_parent(measure, clock);
+	if (!ret) {
+		/*
+		 * Disable hw gating to get accurate rate measurements. Only do
+		 * this if the clock is explictly enabled by software. This
+		 * allows us to detect errors where clocks are on even though
+		 * software is not requesting them to be on due to broken
+		 * hardware gating signals.
+		 */
+		if (is_hw_gated && clock->count)
+			clock->ops->disable_hwcg(clock);
+		*val = clk_get_rate(measure);
+		/* Reenable hwgating if it was disabled */
+		if (is_hw_gated && clock->count)
+			clock->ops->enable_hwcg(clock);
+	}
+
+	return ret;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(clock_measure_fops, clock_debug_measure_get,
+			NULL, "%lld\n");
+
 static int clock_debug_enable_set(void *data, u64 val)
 {
 	struct clk *clock = data;
 	int rc = 0;
 
 	if (val)
-		rc = clock->ops->enable(clock->id);
+		rc = clk_prepare_enable(clock);
 	else
-		clock->ops->disable(clock->id);
+		clk_disable_unprepare(clock);
 
 	return rc;
 }
@@ -65,20 +102,28 @@
 static int clock_debug_enable_get(void *data, u64 *val)
 {
 	struct clk *clock = data;
+	int enabled;
 
-	*val = clock->ops->is_enabled(clock->id);
+	if (clock->ops->is_enabled)
+		enabled = clock->ops->is_enabled(clock);
+	else
+		enabled = !!(clock->count);
 
+	*val = enabled;
 	return 0;
 }
 
 DEFINE_SIMPLE_ATTRIBUTE(clock_enable_fops, clock_debug_enable_get,
-			clock_debug_enable_set, "%llu\n");
+			clock_debug_enable_set, "%lld\n");
 
 static int clock_debug_local_get(void *data, u64 *val)
 {
 	struct clk *clock = data;
 
-	*val = clock->ops->is_local(clock->id);
+	if (!clock->ops->is_local)
+		*val = true;
+	else
+		*val = clock->ops->is_local(clock);
 
 	return 0;
 }
@@ -86,16 +131,114 @@
 DEFINE_SIMPLE_ATTRIBUTE(clock_local_fops, clock_debug_local_get,
 			NULL, "%llu\n");
 
-static struct dentry *debugfs_base;
+static int clock_debug_hwcg_get(void *data, u64 *val)
+{
+	struct clk *clock = data;
+	*val = !!(clock->flags & CLKFLAG_HWCG);
+	return 0;
+}
 
-int __init clock_debug_init(void)
+DEFINE_SIMPLE_ATTRIBUTE(clock_hwcg_fops, clock_debug_hwcg_get,
+			NULL, "%llu\n");
+
+static struct dentry *debugfs_base;
+static u32 debug_suspend;
+static struct clk_lookup *msm_clocks;
+static size_t num_msm_clocks;
+
+int __init clock_debug_init(struct clock_init_data *data)
 {
 	debugfs_base = debugfs_create_dir("clk", NULL);
 	if (!debugfs_base)
 		return -ENOMEM;
+	if (!debugfs_create_u32("debug_suspend", S_IRUGO | S_IWUSR,
+				debugfs_base, &debug_suspend)) {
+		debugfs_remove_recursive(debugfs_base);
+		return -ENOMEM;
+	}
+	msm_clocks = data->table;
+	num_msm_clocks = data->size;
+
+	measure = clk_get_sys("debug", "measure");
+	if (IS_ERR(measure))
+		measure = NULL;
+
 	return 0;
 }
 
+
+static int clock_debug_print_clock(struct clk *c)
+{
+	size_t ln = 0;
+	char s[128];
+
+	if (!c || !c->count)
+		return 0;
+
+	ln += snprintf(s, sizeof(s), "\t%s", c->dbg_name);
+	while (ln < sizeof(s) && (c = clk_get_parent(c)))
+		ln += snprintf(s + ln, sizeof(s) - ln, " -> %s", c->dbg_name);
+	pr_info("%s\n", s);
+	return 1;
+}
+
+void clock_debug_print_enabled(void)
+{
+	unsigned i;
+	int cnt = 0;
+
+	if (likely(!debug_suspend))
+		return;
+
+	pr_info("Enabled clocks:\n");
+	for (i = 0; i < num_msm_clocks; i++)
+		cnt += clock_debug_print_clock(msm_clocks[i].clk);
+
+	if (cnt)
+		pr_info("Enabled clock count: %d\n", cnt);
+	else
+		pr_info("No clocks enabled.\n");
+
+}
+
+static int list_rates_show(struct seq_file *m, void *unused)
+{
+	struct clk *clock = m->private;
+	int rate, level, fmax = 0, i = 0;
+
+	/* Find max frequency supported within voltage constraints. */
+	if (!clock->vdd_class) {
+		fmax = INT_MAX;
+	} else {
+		for (level = 0; level < ARRAY_SIZE(clock->fmax); level++)
+			if (clock->fmax[level])
+				fmax = clock->fmax[level];
+	}
+
+	/*
+	 * List supported frequencies <= fmax. Higher frequencies may appear in
+	 * the frequency table, but are not valid and should not be listed.
+	 */
+	while ((rate = clock->ops->list_rate(clock, i++)) >= 0) {
+		if (rate <= fmax)
+			seq_printf(m, "%u\n", rate);
+	}
+
+	return 0;
+}
+
+static int list_rates_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, list_rates_show, inode->i_private);
+}
+
+static const struct file_operations list_rates_fops = {
+	.open		= list_rates_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
+
 int __init clock_debug_add(struct clk *clock)
 {
 	char temp[50], *ptr;
@@ -104,7 +247,7 @@
 	if (!debugfs_base)
 		return -ENOMEM;
 
-	strncpy(temp, clock->dbg_name, ARRAY_SIZE(temp)-1);
+	strlcpy(temp, clock->dbg_name, ARRAY_SIZE(temp));
 	for (ptr = temp; *ptr; ptr++)
 		*ptr = tolower(*ptr);
 
@@ -123,6 +266,22 @@
 	if (!debugfs_create_file("is_local", S_IRUGO, clk_dir, clock,
 				&clock_local_fops))
 		goto error;
+
+	if (!debugfs_create_file("has_hw_gating", S_IRUGO, clk_dir, clock,
+				&clock_hwcg_fops))
+		goto error;
+
+	if (measure &&
+	    !clk_set_parent(measure, clock) &&
+	    !debugfs_create_file("measure", S_IRUGO, clk_dir, clock,
+				&clock_measure_fops))
+		goto error;
+
+	if (clock->ops->list_rate)
+		if (!debugfs_create_file("list_rates",
+				S_IRUGO, clk_dir, clock, &list_rates_fops))
+			goto error;
+
 	return 0;
 error:
 	debugfs_remove_recursive(clk_dir);
diff --git a/arch/arm/mach-msm/clock-dss-8960.c b/arch/arm/mach-msm/clock-dss-8960.c
new file mode 100644
index 0000000..8331899
--- /dev/null
+++ b/arch/arm/mach-msm/clock-dss-8960.c
@@ -0,0 +1,330 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <asm/processor.h>
+#include <mach/msm_iomap.h>
+#include "clock-dss-8960.h"
+
+/* HDMI PLL macros */
+#define HDMI_PHY_PLL_REFCLK_CFG          (MSM_HDMI_BASE + 0x00000500)
+#define HDMI_PHY_PLL_CHRG_PUMP_CFG       (MSM_HDMI_BASE + 0x00000504)
+#define HDMI_PHY_PLL_LOOP_FLT_CFG0       (MSM_HDMI_BASE + 0x00000508)
+#define HDMI_PHY_PLL_LOOP_FLT_CFG1       (MSM_HDMI_BASE + 0x0000050c)
+#define HDMI_PHY_PLL_IDAC_ADJ_CFG        (MSM_HDMI_BASE + 0x00000510)
+#define HDMI_PHY_PLL_I_VI_KVCO_CFG       (MSM_HDMI_BASE + 0x00000514)
+#define HDMI_PHY_PLL_PWRDN_B             (MSM_HDMI_BASE + 0x00000518)
+#define HDMI_PHY_PLL_SDM_CFG0            (MSM_HDMI_BASE + 0x0000051c)
+#define HDMI_PHY_PLL_SDM_CFG1            (MSM_HDMI_BASE + 0x00000520)
+#define HDMI_PHY_PLL_SDM_CFG2            (MSM_HDMI_BASE + 0x00000524)
+#define HDMI_PHY_PLL_SDM_CFG3            (MSM_HDMI_BASE + 0x00000528)
+#define HDMI_PHY_PLL_SDM_CFG4            (MSM_HDMI_BASE + 0x0000052c)
+#define HDMI_PHY_PLL_SSC_CFG0            (MSM_HDMI_BASE + 0x00000530)
+#define HDMI_PHY_PLL_SSC_CFG1            (MSM_HDMI_BASE + 0x00000534)
+#define HDMI_PHY_PLL_SSC_CFG2            (MSM_HDMI_BASE + 0x00000538)
+#define HDMI_PHY_PLL_SSC_CFG3            (MSM_HDMI_BASE + 0x0000053c)
+#define HDMI_PHY_PLL_LOCKDET_CFG0        (MSM_HDMI_BASE + 0x00000540)
+#define HDMI_PHY_PLL_LOCKDET_CFG1        (MSM_HDMI_BASE + 0x00000544)
+#define HDMI_PHY_PLL_LOCKDET_CFG2        (MSM_HDMI_BASE + 0x00000548)
+#define HDMI_PHY_PLL_VCOCAL_CFG0         (MSM_HDMI_BASE + 0x0000054c)
+#define HDMI_PHY_PLL_VCOCAL_CFG1         (MSM_HDMI_BASE + 0x00000550)
+#define HDMI_PHY_PLL_VCOCAL_CFG2         (MSM_HDMI_BASE + 0x00000554)
+#define HDMI_PHY_PLL_VCOCAL_CFG3         (MSM_HDMI_BASE + 0x00000558)
+#define HDMI_PHY_PLL_VCOCAL_CFG4         (MSM_HDMI_BASE + 0x0000055c)
+#define HDMI_PHY_PLL_VCOCAL_CFG5         (MSM_HDMI_BASE + 0x00000560)
+#define HDMI_PHY_PLL_VCOCAL_CFG6         (MSM_HDMI_BASE + 0x00000564)
+#define HDMI_PHY_PLL_VCOCAL_CFG7         (MSM_HDMI_BASE + 0x00000568)
+#define HDMI_PHY_PLL_DEBUG_SEL           (MSM_HDMI_BASE + 0x0000056c)
+#define HDMI_PHY_PLL_MISC0               (MSM_HDMI_BASE + 0x00000570)
+#define HDMI_PHY_PLL_MISC1               (MSM_HDMI_BASE + 0x00000574)
+#define HDMI_PHY_PLL_MISC2               (MSM_HDMI_BASE + 0x00000578)
+#define HDMI_PHY_PLL_MISC3               (MSM_HDMI_BASE + 0x0000057c)
+#define HDMI_PHY_PLL_MISC4               (MSM_HDMI_BASE + 0x00000580)
+#define HDMI_PHY_PLL_MISC5               (MSM_HDMI_BASE + 0x00000584)
+#define HDMI_PHY_PLL_MISC6               (MSM_HDMI_BASE + 0x00000588)
+#define HDMI_PHY_PLL_DEBUG_BUS0          (MSM_HDMI_BASE + 0x0000058c)
+#define HDMI_PHY_PLL_DEBUG_BUS1          (MSM_HDMI_BASE + 0x00000590)
+#define HDMI_PHY_PLL_DEBUG_BUS2          (MSM_HDMI_BASE + 0x00000594)
+#define HDMI_PHY_PLL_STATUS0             (MSM_HDMI_BASE + 0x00000598)
+#define HDMI_PHY_PLL_STATUS1             (MSM_HDMI_BASE + 0x0000059c)
+#define HDMI_PHY_CTRL                    (MSM_HDMI_BASE + 0x000002D4)
+#define HDMI_PHY_REG_0                   (MSM_HDMI_BASE + 0x00000400)
+#define HDMI_PHY_REG_1                   (MSM_HDMI_BASE + 0x00000404)
+#define HDMI_PHY_REG_2                   (MSM_HDMI_BASE + 0x00000408)
+#define HDMI_PHY_REG_3                   (MSM_HDMI_BASE + 0x0000040c)
+#define HDMI_PHY_REG_4                   (MSM_HDMI_BASE + 0x00000410)
+#define HDMI_PHY_REG_5                   (MSM_HDMI_BASE + 0x00000414)
+#define HDMI_PHY_REG_6                   (MSM_HDMI_BASE + 0x00000418)
+#define HDMI_PHY_REG_7                   (MSM_HDMI_BASE + 0x0000041c)
+#define HDMI_PHY_REG_8                   (MSM_HDMI_BASE + 0x00000420)
+#define HDMI_PHY_REG_9                   (MSM_HDMI_BASE + 0x00000424)
+#define HDMI_PHY_REG_10                  (MSM_HDMI_BASE + 0x00000428)
+#define HDMI_PHY_REG_11                  (MSM_HDMI_BASE + 0x0000042c)
+#define HDMI_PHY_REG_12                  (MSM_HDMI_BASE + 0x00000430)
+#define HDMI_PHY_REG_BIST_CFG            (MSM_HDMI_BASE + 0x00000434)
+#define HDMI_PHY_DEBUG_BUS_SEL           (MSM_HDMI_BASE + 0x00000438)
+#define HDMI_PHY_REG_MISC0               (MSM_HDMI_BASE + 0x0000043c)
+#define HDMI_PHY_REG_13                  (MSM_HDMI_BASE + 0x00000440)
+#define HDMI_PHY_REG_14                  (MSM_HDMI_BASE + 0x00000444)
+#define HDMI_PHY_REG_15                  (MSM_HDMI_BASE + 0x00000448)
+
+#define AHB_EN_REG                       (MSM_MMSS_CLK_CTL_BASE + 0x0008)
+
+/* HDMI PHY/PLL bit field macros */
+#define SW_RESET BIT(2)
+#define SW_RESET_PLL BIT(0)
+#define PWRDN_B BIT(7)
+
+#define PLL_PWRDN_B BIT(3)
+#define PD_PLL BIT(1)
+
+static unsigned current_rate;
+static unsigned hdmi_pll_on;
+
+int hdmi_pll_enable(void)
+{
+	unsigned int val;
+	u32 ahb_en_reg, ahb_enabled;
+
+	ahb_en_reg = readl_relaxed(AHB_EN_REG);
+	ahb_enabled = ahb_en_reg & BIT(4);
+	if (!ahb_enabled) {
+		writel_relaxed(ahb_en_reg | BIT(4), AHB_EN_REG);
+		/* Make sure iface clock is enabled before register access */
+		mb();
+	}
+
+	/* Assert PLL S/W reset */
+	writel_relaxed(0x8D, HDMI_PHY_PLL_LOCKDET_CFG2);
+	writel_relaxed(0x10, HDMI_PHY_PLL_LOCKDET_CFG0);
+	writel_relaxed(0x1A, HDMI_PHY_PLL_LOCKDET_CFG1);
+	/* De-assert PLL S/W reset */
+	writel_relaxed(0x0D, HDMI_PHY_PLL_LOCKDET_CFG2);
+
+	val = readl_relaxed(HDMI_PHY_REG_12);
+	val |= BIT(5);
+	/* Assert PHY S/W reset */
+	writel_relaxed(val, HDMI_PHY_REG_12);
+	val &= ~BIT(5);
+	/* De-assert PHY S/W reset */
+	writel_relaxed(val, HDMI_PHY_REG_12);
+	writel_relaxed(0x3f, HDMI_PHY_REG_2);
+
+	val = readl_relaxed(HDMI_PHY_REG_12);
+	val |= PWRDN_B;
+	writel_relaxed(val, HDMI_PHY_REG_12);
+	/* Wait 10 us for enabling global power for PHY */
+	mb();
+	udelay(10);
+
+	val = readl_relaxed(HDMI_PHY_PLL_PWRDN_B);
+	val |= PLL_PWRDN_B;
+	val &= ~PD_PLL;
+	writel_relaxed(val, HDMI_PHY_PLL_PWRDN_B);
+	writel_relaxed(0x80, HDMI_PHY_REG_2);
+
+	while (!(readl_relaxed(HDMI_PHY_PLL_STATUS0) & BIT(0)))
+		cpu_relax();
+
+	if (!ahb_enabled)
+		writel_relaxed(ahb_en_reg & ~BIT(4), AHB_EN_REG);
+	hdmi_pll_on = 1;
+	return 0;
+}
+
+void hdmi_pll_disable(void)
+{
+	unsigned int val;
+	u32 ahb_en_reg, ahb_enabled;
+
+	ahb_en_reg = readl_relaxed(AHB_EN_REG);
+	ahb_enabled = ahb_en_reg & BIT(4);
+	if (!ahb_enabled) {
+		writel_relaxed(ahb_en_reg | BIT(4), AHB_EN_REG);
+		mb();
+	}
+
+	val = readl_relaxed(HDMI_PHY_REG_12);
+	val &= (~PWRDN_B);
+	writel_relaxed(val, HDMI_PHY_REG_12);
+
+	val = readl_relaxed(HDMI_PHY_PLL_PWRDN_B);
+	val |= PD_PLL;
+	val &= (~PLL_PWRDN_B);
+	writel_relaxed(val, HDMI_PHY_PLL_PWRDN_B);
+	/* Make sure HDMI PHY/PLL are powered down */
+	mb();
+
+	if (!ahb_enabled)
+		writel_relaxed(ahb_en_reg & ~BIT(4), AHB_EN_REG);
+	hdmi_pll_on = 0;
+}
+
+unsigned hdmi_pll_get_rate(void)
+{
+	return current_rate;
+}
+
+int hdmi_pll_set_rate(unsigned rate)
+{
+	unsigned int set_power_dwn = 0;
+	u32 ahb_en_reg = readl_relaxed(AHB_EN_REG);
+	u32 ahb_enabled = ahb_en_reg & BIT(4);
+
+	if (!ahb_enabled) {
+		writel_relaxed(ahb_en_reg | BIT(4), AHB_EN_REG);
+		/* Make sure iface clock is enabled before register access */
+		mb();
+	}
+
+	if (hdmi_pll_on) {
+		hdmi_pll_disable();
+		set_power_dwn = 1;
+	}
+
+	switch (rate) {
+	case 27030000:
+		/* 480p60/480i60 case */
+		writel_relaxed(0x32, HDMI_PHY_PLL_REFCLK_CFG);
+		writel_relaxed(0x2, HDMI_PHY_PLL_CHRG_PUMP_CFG);
+		writel_relaxed(0x08, HDMI_PHY_PLL_LOOP_FLT_CFG0);
+		writel_relaxed(0x77, HDMI_PHY_PLL_LOOP_FLT_CFG1);
+		writel_relaxed(0x2C, HDMI_PHY_PLL_IDAC_ADJ_CFG);
+		writel_relaxed(0x6, HDMI_PHY_PLL_I_VI_KVCO_CFG);
+		writel_relaxed(0x7b, HDMI_PHY_PLL_SDM_CFG0);
+		writel_relaxed(0x01, HDMI_PHY_PLL_SDM_CFG1);
+		writel_relaxed(0x4C, HDMI_PHY_PLL_SDM_CFG2);
+		writel_relaxed(0xC0, HDMI_PHY_PLL_SDM_CFG3);
+		writel_relaxed(0x00, HDMI_PHY_PLL_SDM_CFG4);
+		writel_relaxed(0x9A, HDMI_PHY_PLL_SSC_CFG0);
+		writel_relaxed(0x00, HDMI_PHY_PLL_SSC_CFG1);
+		writel_relaxed(0x00, HDMI_PHY_PLL_SSC_CFG2);
+		writel_relaxed(0x00, HDMI_PHY_PLL_SSC_CFG3);
+		writel_relaxed(0x2A, HDMI_PHY_PLL_VCOCAL_CFG0);
+		writel_relaxed(0x03, HDMI_PHY_PLL_VCOCAL_CFG1);
+		writel_relaxed(0x2B, HDMI_PHY_PLL_VCOCAL_CFG2);
+		writel_relaxed(0x00, HDMI_PHY_PLL_VCOCAL_CFG3);
+		writel_relaxed(0x86, HDMI_PHY_PLL_VCOCAL_CFG4);
+		writel_relaxed(0x00, HDMI_PHY_PLL_VCOCAL_CFG5);
+		writel_relaxed(0x33, HDMI_PHY_PLL_VCOCAL_CFG6);
+		writel_relaxed(0x00, HDMI_PHY_PLL_VCOCAL_CFG7);
+	break;
+
+	case 25200000:
+		/* 640x480p60 */
+		writel_relaxed(0x32, HDMI_PHY_PLL_REFCLK_CFG);
+		writel_relaxed(0x2, HDMI_PHY_PLL_CHRG_PUMP_CFG);
+		writel_relaxed(0x01, HDMI_PHY_PLL_LOOP_FLT_CFG0);
+		writel_relaxed(0x33, HDMI_PHY_PLL_LOOP_FLT_CFG1);
+		writel_relaxed(0x2C, HDMI_PHY_PLL_IDAC_ADJ_CFG);
+		writel_relaxed(0x6, HDMI_PHY_PLL_I_VI_KVCO_CFG);
+		writel_relaxed(0x77, HDMI_PHY_PLL_SDM_CFG0);
+		writel_relaxed(0x4C, HDMI_PHY_PLL_SDM_CFG1);
+		writel_relaxed(0x00, HDMI_PHY_PLL_SDM_CFG2);
+		writel_relaxed(0xC0, HDMI_PHY_PLL_SDM_CFG3);
+		writel_relaxed(0x00, HDMI_PHY_PLL_SDM_CFG4);
+		writel_relaxed(0x9A, HDMI_PHY_PLL_SSC_CFG0);
+		writel_relaxed(0x00, HDMI_PHY_PLL_SSC_CFG1);
+		writel_relaxed(0x00, HDMI_PHY_PLL_SSC_CFG2);
+		writel_relaxed(0x20, HDMI_PHY_PLL_SSC_CFG3);
+		writel_relaxed(0xF4, HDMI_PHY_PLL_VCOCAL_CFG0);
+		writel_relaxed(0x02, HDMI_PHY_PLL_VCOCAL_CFG1);
+		writel_relaxed(0x2B, HDMI_PHY_PLL_VCOCAL_CFG2);
+		writel_relaxed(0x00, HDMI_PHY_PLL_VCOCAL_CFG3);
+		writel_relaxed(0x86, HDMI_PHY_PLL_VCOCAL_CFG4);
+		writel_relaxed(0x00, HDMI_PHY_PLL_VCOCAL_CFG5);
+		writel_relaxed(0x33, HDMI_PHY_PLL_VCOCAL_CFG6);
+		writel_relaxed(0x00, HDMI_PHY_PLL_VCOCAL_CFG7);
+	break;
+
+	case 27000000:
+		/* 576p50/576i50 case */
+		writel_relaxed(0x32, HDMI_PHY_PLL_REFCLK_CFG);
+		writel_relaxed(0x2, HDMI_PHY_PLL_CHRG_PUMP_CFG);
+		writel_relaxed(0x01, HDMI_PHY_PLL_LOOP_FLT_CFG0);
+		writel_relaxed(0x33, HDMI_PHY_PLL_LOOP_FLT_CFG1);
+		writel_relaxed(0x2C, HDMI_PHY_PLL_IDAC_ADJ_CFG);
+		writel_relaxed(0x6, HDMI_PHY_PLL_I_VI_KVCO_CFG);
+		writel_relaxed(0x7B, HDMI_PHY_PLL_SDM_CFG0);
+		writel_relaxed(0x01, HDMI_PHY_PLL_SDM_CFG1);
+		writel_relaxed(0x4C, HDMI_PHY_PLL_SDM_CFG2);
+		writel_relaxed(0xC0, HDMI_PHY_PLL_SDM_CFG3);
+		writel_relaxed(0x00, HDMI_PHY_PLL_SDM_CFG4);
+		writel_relaxed(0x9A, HDMI_PHY_PLL_SSC_CFG0);
+		writel_relaxed(0x00, HDMI_PHY_PLL_SSC_CFG1);
+		writel_relaxed(0x00, HDMI_PHY_PLL_SSC_CFG2);
+		writel_relaxed(0x00, HDMI_PHY_PLL_SSC_CFG3);
+		writel_relaxed(0x2a, HDMI_PHY_PLL_VCOCAL_CFG0);
+		writel_relaxed(0x03, HDMI_PHY_PLL_VCOCAL_CFG1);
+		writel_relaxed(0x2B, HDMI_PHY_PLL_VCOCAL_CFG2);
+		writel_relaxed(0x00, HDMI_PHY_PLL_VCOCAL_CFG3);
+		writel_relaxed(0x86, HDMI_PHY_PLL_VCOCAL_CFG4);
+		writel_relaxed(0x00, HDMI_PHY_PLL_VCOCAL_CFG5);
+		writel_relaxed(0x33, HDMI_PHY_PLL_VCOCAL_CFG6);
+		writel_relaxed(0x00, HDMI_PHY_PLL_VCOCAL_CFG7);
+	break;
+
+	case 74250000:
+		/* 720p60/720p50/1080i60/1080i50
+		 * 1080p24/1080p30/1080p25 case
+		 */
+		writel_relaxed(0x12, HDMI_PHY_PLL_REFCLK_CFG);
+		writel_relaxed(0x01, HDMI_PHY_PLL_LOOP_FLT_CFG0);
+		writel_relaxed(0x33, HDMI_PHY_PLL_LOOP_FLT_CFG1);
+		writel_relaxed(0x76, HDMI_PHY_PLL_SDM_CFG0);
+		writel_relaxed(0xE6, HDMI_PHY_PLL_VCOCAL_CFG0);
+		writel_relaxed(0x02, HDMI_PHY_PLL_VCOCAL_CFG1);
+	break;
+
+	case 148500000:
+		/* 1080p60/1080p50 case */
+		writel_relaxed(0x2, HDMI_PHY_PLL_REFCLK_CFG);
+		writel_relaxed(0x2, HDMI_PHY_PLL_CHRG_PUMP_CFG);
+		writel_relaxed(0x01, HDMI_PHY_PLL_LOOP_FLT_CFG0);
+		writel_relaxed(0x33, HDMI_PHY_PLL_LOOP_FLT_CFG1);
+		writel_relaxed(0x2C, HDMI_PHY_PLL_IDAC_ADJ_CFG);
+		writel_relaxed(0x6, HDMI_PHY_PLL_I_VI_KVCO_CFG);
+		writel_relaxed(0x76, HDMI_PHY_PLL_SDM_CFG0);
+		writel_relaxed(0x01, HDMI_PHY_PLL_SDM_CFG1);
+		writel_relaxed(0x4C, HDMI_PHY_PLL_SDM_CFG2);
+		writel_relaxed(0xC0, HDMI_PHY_PLL_SDM_CFG3);
+		writel_relaxed(0x00, HDMI_PHY_PLL_SDM_CFG4);
+		writel_relaxed(0x9A, HDMI_PHY_PLL_SSC_CFG0);
+		writel_relaxed(0x00, HDMI_PHY_PLL_SSC_CFG1);
+		writel_relaxed(0x00, HDMI_PHY_PLL_SSC_CFG2);
+		writel_relaxed(0x00, HDMI_PHY_PLL_SSC_CFG3);
+		writel_relaxed(0xe6, HDMI_PHY_PLL_VCOCAL_CFG0);
+		writel_relaxed(0x02, HDMI_PHY_PLL_VCOCAL_CFG1);
+		writel_relaxed(0x2B, HDMI_PHY_PLL_VCOCAL_CFG2);
+		writel_relaxed(0x00, HDMI_PHY_PLL_VCOCAL_CFG3);
+		writel_relaxed(0x86, HDMI_PHY_PLL_VCOCAL_CFG4);
+		writel_relaxed(0x00, HDMI_PHY_PLL_VCOCAL_CFG5);
+		writel_relaxed(0x33, HDMI_PHY_PLL_VCOCAL_CFG6);
+		writel_relaxed(0x00, HDMI_PHY_PLL_VCOCAL_CFG7);
+	break;
+	}
+
+	/* Make sure writes complete before disabling iface clock */
+	mb();
+
+	if (set_power_dwn)
+		hdmi_pll_enable();
+
+	current_rate = rate;
+	if (!ahb_enabled)
+		writel_relaxed(ahb_en_reg & ~BIT(4), AHB_EN_REG);
+
+	return 0;
+}
diff --git a/arch/arm/mach-msm/clock-dss-8960.h b/arch/arm/mach-msm/clock-dss-8960.h
new file mode 100644
index 0000000..4734cde
--- /dev/null
+++ b/arch/arm/mach-msm/clock-dss-8960.h
@@ -0,0 +1,21 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_CLOCK_DSS_8960
+#define __ARCH_ARM_MACH_MSM_CLOCK_DSS_8960
+
+int hdmi_pll_enable(void);
+void hdmi_pll_disable(void);
+unsigned hdmi_pll_get_rate(void);
+int hdmi_pll_set_rate(unsigned rate);
+
+#endif
diff --git a/arch/arm/mach-msm/clock-dummy.c b/arch/arm/mach-msm/clock-dummy.c
new file mode 100644
index 0000000..54c9de8
--- /dev/null
+++ b/arch/arm/mach-msm/clock-dummy.c
@@ -0,0 +1,58 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "clock.h"
+
+static int dummy_clk_reset(struct clk *clk, enum clk_reset_action action)
+{
+	return 0;
+}
+
+static int dummy_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	return 0;
+}
+
+static int dummy_clk_set_max_rate(struct clk *clk, unsigned long rate)
+{
+	return 0;
+}
+
+static int dummy_clk_set_flags(struct clk *clk, unsigned flags)
+{
+	return 0;
+}
+
+static unsigned long dummy_clk_get_rate(struct clk *clk)
+{
+	return 0;
+}
+
+static long dummy_clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	return rate;
+}
+
+static struct clk_ops clk_ops_dummy = {
+	.reset = dummy_clk_reset,
+	.set_rate = dummy_clk_set_rate,
+	.set_max_rate = dummy_clk_set_max_rate,
+	.set_flags = dummy_clk_set_flags,
+	.get_rate = dummy_clk_get_rate,
+	.round_rate = dummy_clk_round_rate,
+};
+
+struct clk dummy_clk = {
+	.dbg_name = "dummy_clk",
+	.ops = &clk_ops_dummy,
+	CLK_INIT(dummy_clk),
+};
diff --git a/arch/arm/mach-msm/clock-fsm9xxx.c b/arch/arm/mach-msm/clock-fsm9xxx.c
new file mode 100644
index 0000000..13a5b65
--- /dev/null
+++ b/arch/arm/mach-msm/clock-fsm9xxx.c
@@ -0,0 +1,35 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/clk.h>
+
+#include <mach/clk.h>
+
+#include "clock.h"
+
+/*
+ * Clocks
+ */
+
+static struct clk_lookup msm_clocks_fsm9xxx[] = {
+	CLK_DUMMY("core_clk",	ADM0_CLK,	"msm_dmov", OFF),
+	CLK_DUMMY("core_clk",	UART1_CLK,	"msm_serial.0", OFF),
+	CLK_DUMMY("core_clk",	CE_CLK,		"qce.0", OFF),
+	CLK_DUMMY("core_clk",	CE_CLK,		"qcota.0", OFF),
+	CLK_DUMMY("core_clk",	CE_CLK,		"qcrypto.0", OFF),
+};
+
+struct clock_init_data fsm9xxx_clock_init_data __initdata = {
+	.table = msm_clocks_fsm9xxx,
+	.size = ARRAY_SIZE(msm_clocks_fsm9xxx),
+};
diff --git a/arch/arm/mach-msm/clock-local.c b/arch/arm/mach-msm/clock-local.c
new file mode 100644
index 0000000..4f365fa
--- /dev/null
+++ b/arch/arm/mach-msm/clock-local.c
@@ -0,0 +1,972 @@
+/* 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
+ * 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.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <mach/msm_iomap.h>
+#include <mach/clk.h>
+#include <mach/scm-io.h>
+
+#include "clock.h"
+#include "clock-local.h"
+
+#ifdef CONFIG_MSM_SECURE_IO
+#undef readl_relaxed
+#undef writel_relaxed
+#define readl_relaxed secure_readl
+#define writel_relaxed secure_writel
+#endif
+
+/*
+ * When enabling/disabling a clock, check the halt bit up to this number
+ * number of times (with a 1 us delay in between) before continuing.
+ */
+#define HALT_CHECK_MAX_LOOPS	200
+/* For clock without halt checking, wait this long after enables/disables. */
+#define HALT_CHECK_DELAY_US	10
+
+DEFINE_SPINLOCK(local_clock_reg_lock);
+struct clk_freq_tbl rcg_dummy_freq = F_END;
+
+/*
+ * Common Set-Rate Functions
+ */
+
+/* For clocks with MND dividers. */
+void set_rate_mnd(struct rcg_clk *clk, struct clk_freq_tbl *nf)
+{
+	uint32_t ns_reg_val, ctl_reg_val;
+
+	/* Assert MND reset. */
+	ns_reg_val = readl_relaxed(clk->ns_reg);
+	ns_reg_val |= BIT(7);
+	writel_relaxed(ns_reg_val, clk->ns_reg);
+
+	/* Program M and D values. */
+	writel_relaxed(nf->md_val, clk->md_reg);
+
+	/* If the clock has a separate CC register, program it. */
+	if (clk->ns_reg != clk->b.ctl_reg) {
+		ctl_reg_val = readl_relaxed(clk->b.ctl_reg);
+		ctl_reg_val &= ~(clk->ctl_mask);
+		ctl_reg_val |= nf->ctl_val;
+		writel_relaxed(ctl_reg_val, clk->b.ctl_reg);
+	}
+
+	/* Deassert MND reset. */
+	ns_reg_val &= ~BIT(7);
+	writel_relaxed(ns_reg_val, clk->ns_reg);
+}
+
+void set_rate_nop(struct rcg_clk *clk, struct clk_freq_tbl *nf)
+{
+	/*
+	 * Nothing to do for fixed-rate or integer-divider clocks. Any settings
+	 * in NS registers are applied in the enable path, since power can be
+	 * saved by leaving an un-clocked or slowly-clocked source selected
+	 * until the clock is enabled.
+	 */
+}
+
+void set_rate_mnd_8(struct rcg_clk *clk, struct clk_freq_tbl *nf)
+{
+	uint32_t ctl_reg_val;
+
+	/* Assert MND reset. */
+	ctl_reg_val = readl_relaxed(clk->b.ctl_reg);
+	ctl_reg_val |= BIT(8);
+	writel_relaxed(ctl_reg_val, clk->b.ctl_reg);
+
+	/* Program M and D values. */
+	writel_relaxed(nf->md_val, clk->md_reg);
+
+	/* Program MN counter Enable and Mode. */
+	ctl_reg_val &= ~(clk->ctl_mask);
+	ctl_reg_val |= nf->ctl_val;
+	writel_relaxed(ctl_reg_val, clk->b.ctl_reg);
+
+	/* Deassert MND reset. */
+	ctl_reg_val &= ~BIT(8);
+	writel_relaxed(ctl_reg_val, clk->b.ctl_reg);
+}
+
+void set_rate_mnd_banked(struct rcg_clk *clk, struct clk_freq_tbl *nf)
+{
+	struct bank_masks *banks = clk->bank_info;
+	const struct bank_mask_info *new_bank_masks;
+	const struct bank_mask_info *old_bank_masks;
+	uint32_t ns_reg_val, ctl_reg_val;
+	uint32_t bank_sel;
+
+	/*
+	 * Determine active bank and program the other one. If the clock is
+	 * off, program the active bank since bank switching won't work if
+	 * both banks aren't running.
+	 */
+	ctl_reg_val = readl_relaxed(clk->b.ctl_reg);
+	bank_sel = !!(ctl_reg_val & banks->bank_sel_mask);
+	 /* If clock isn't running, don't switch banks. */
+	bank_sel ^= (!clk->enabled || clk->current_freq->freq_hz == 0);
+	if (bank_sel == 0) {
+		new_bank_masks = &banks->bank1_mask;
+		old_bank_masks = &banks->bank0_mask;
+	} else {
+		new_bank_masks = &banks->bank0_mask;
+		old_bank_masks = &banks->bank1_mask;
+	}
+
+	ns_reg_val = readl_relaxed(clk->ns_reg);
+
+	/* Assert bank MND reset. */
+	ns_reg_val |= new_bank_masks->rst_mask;
+	writel_relaxed(ns_reg_val, clk->ns_reg);
+
+	/*
+	 * Program NS only if the clock is enabled, since the NS will be set
+	 * as part of the enable procedure and should remain with a low-power
+	 * MUX input selected until then.
+	 */
+	if (clk->enabled) {
+		ns_reg_val &= ~(new_bank_masks->ns_mask);
+		ns_reg_val |= (nf->ns_val & new_bank_masks->ns_mask);
+		writel_relaxed(ns_reg_val, clk->ns_reg);
+	}
+
+	writel_relaxed(nf->md_val, new_bank_masks->md_reg);
+
+	/* Enable counter only if clock is enabled. */
+	if (clk->enabled)
+		ctl_reg_val |= new_bank_masks->mnd_en_mask;
+	else
+		ctl_reg_val &= ~(new_bank_masks->mnd_en_mask);
+
+	ctl_reg_val &= ~(new_bank_masks->mode_mask);
+	ctl_reg_val |= (nf->ctl_val & new_bank_masks->mode_mask);
+	writel_relaxed(ctl_reg_val, clk->b.ctl_reg);
+
+	/* Deassert bank MND reset. */
+	ns_reg_val &= ~(new_bank_masks->rst_mask);
+	writel_relaxed(ns_reg_val, clk->ns_reg);
+
+	/*
+	 * Switch to the new bank if clock is running.  If it isn't, then
+	 * no switch is necessary since we programmed the active bank.
+	 */
+	if (clk->enabled && clk->current_freq->freq_hz) {
+		ctl_reg_val ^= banks->bank_sel_mask;
+		writel_relaxed(ctl_reg_val, clk->b.ctl_reg);
+		/*
+		 * Wait at least 6 cycles of slowest bank's clock
+		 * for the glitch-free MUX to fully switch sources.
+		 */
+		mb();
+		udelay(1);
+
+		/* Disable old bank's MN counter. */
+		ctl_reg_val &= ~(old_bank_masks->mnd_en_mask);
+		writel_relaxed(ctl_reg_val, clk->b.ctl_reg);
+
+		/* Program old bank to a low-power source and divider. */
+		ns_reg_val &= ~(old_bank_masks->ns_mask);
+		ns_reg_val |= (clk->freq_tbl->ns_val & old_bank_masks->ns_mask);
+		writel_relaxed(ns_reg_val, clk->ns_reg);
+	}
+
+	/* Update the MND_EN and NS masks to match the current bank. */
+	clk->mnd_en_mask = new_bank_masks->mnd_en_mask;
+	clk->ns_mask = new_bank_masks->ns_mask;
+}
+
+void set_rate_div_banked(struct rcg_clk *clk, struct clk_freq_tbl *nf)
+{
+	struct bank_masks *banks = clk->bank_info;
+	const struct bank_mask_info *new_bank_masks;
+	const struct bank_mask_info *old_bank_masks;
+	uint32_t ns_reg_val, bank_sel;
+
+	/*
+	 * Determine active bank and program the other one. If the clock is
+	 * off, program the active bank since bank switching won't work if
+	 * both banks aren't running.
+	 */
+	ns_reg_val = readl_relaxed(clk->ns_reg);
+	bank_sel = !!(ns_reg_val & banks->bank_sel_mask);
+	 /* If clock isn't running, don't switch banks. */
+	bank_sel ^= (!clk->enabled || clk->current_freq->freq_hz == 0);
+	if (bank_sel == 0) {
+		new_bank_masks = &banks->bank1_mask;
+		old_bank_masks = &banks->bank0_mask;
+	} else {
+		new_bank_masks = &banks->bank0_mask;
+		old_bank_masks = &banks->bank1_mask;
+	}
+
+	/*
+	 * Program NS only if the clock is enabled, since the NS will be set
+	 * as part of the enable procedure and should remain with a low-power
+	 * MUX input selected until then.
+	 */
+	if (clk->enabled) {
+		ns_reg_val &= ~(new_bank_masks->ns_mask);
+		ns_reg_val |= (nf->ns_val & new_bank_masks->ns_mask);
+		writel_relaxed(ns_reg_val, clk->ns_reg);
+	}
+
+	/*
+	 * Switch to the new bank if clock is running.  If it isn't, then
+	 * no switch is necessary since we programmed the active bank.
+	 */
+	if (clk->enabled && clk->current_freq->freq_hz) {
+		ns_reg_val ^= banks->bank_sel_mask;
+		writel_relaxed(ns_reg_val, clk->ns_reg);
+		/*
+		 * Wait at least 6 cycles of slowest bank's clock
+		 * for the glitch-free MUX to fully switch sources.
+		 */
+		mb();
+		udelay(1);
+
+		/* Program old bank to a low-power source and divider. */
+		ns_reg_val &= ~(old_bank_masks->ns_mask);
+		ns_reg_val |= (clk->freq_tbl->ns_val & old_bank_masks->ns_mask);
+		writel_relaxed(ns_reg_val, clk->ns_reg);
+	}
+
+	/* Update the NS mask to match the current bank. */
+	clk->ns_mask = new_bank_masks->ns_mask;
+}
+
+/*
+ * Clock enable/disable functions
+ */
+
+/* Return non-zero if a clock status registers shows the clock is halted. */
+static int branch_clk_is_halted(const struct branch *clk)
+{
+	int invert = (clk->halt_check == ENABLE);
+	int status_bit = readl_relaxed(clk->halt_reg) & BIT(clk->halt_bit);
+	return invert ? !status_bit : status_bit;
+}
+
+static int branch_in_hwcg_mode(const struct branch *b)
+{
+	if (!b->hwcg_mask)
+		return 0;
+
+	return !!(readl_relaxed(b->hwcg_reg) & b->hwcg_mask);
+}
+
+void __branch_clk_enable_reg(const struct branch *clk, const char *name)
+{
+	u32 reg_val;
+
+	if (clk->en_mask) {
+		reg_val = readl_relaxed(clk->ctl_reg);
+		reg_val |= clk->en_mask;
+		writel_relaxed(reg_val, clk->ctl_reg);
+	}
+
+	/*
+	 * Use a memory barrier since some halt status registers are
+	 * not within the same 1K segment as the branch/root enable
+	 * registers.  It's also needed in the udelay() case to ensure
+	 * the delay starts after the branch enable.
+	 */
+	mb();
+
+	/* Skip checking halt bit if the clock is in hardware gated mode */
+	if (branch_in_hwcg_mode(clk))
+		return;
+
+	/* Wait for clock to enable before returning. */
+	if (clk->halt_check == DELAY)
+		udelay(HALT_CHECK_DELAY_US);
+	else if (clk->halt_check == ENABLE || clk->halt_check == HALT
+			|| clk->halt_check == ENABLE_VOTED
+			|| clk->halt_check == HALT_VOTED) {
+		int count;
+
+		/* Wait up to HALT_CHECK_MAX_LOOPS for clock to enable. */
+		for (count = HALT_CHECK_MAX_LOOPS; branch_clk_is_halted(clk)
+					&& count > 0; count--)
+			udelay(1);
+		WARN(count == 0, "%s status stuck at 'off'", name);
+	}
+}
+
+/* Perform any register operations required to enable the clock. */
+static void __rcg_clk_enable_reg(struct rcg_clk *clk)
+{
+	u32 reg_val;
+	void __iomem *const reg = clk->b.ctl_reg;
+
+	WARN(clk->current_freq == &rcg_dummy_freq,
+		"Attempting to enable %s before setting its rate. "
+		"Set the rate first!\n", clk->c.dbg_name);
+
+	/*
+	 * Program the NS register, if applicable. NS registers are not
+	 * set in the set_rate path because power can be saved by deferring
+	 * the selection of a clocked source until the clock is enabled.
+	 */
+	if (clk->ns_mask) {
+		reg_val = readl_relaxed(clk->ns_reg);
+		reg_val &= ~(clk->ns_mask);
+		reg_val |= (clk->current_freq->ns_val & clk->ns_mask);
+		writel_relaxed(reg_val, clk->ns_reg);
+	}
+
+	/* Enable MN counter, if applicable. */
+	reg_val = readl_relaxed(reg);
+	if (clk->current_freq->md_val) {
+		reg_val |= clk->mnd_en_mask;
+		writel_relaxed(reg_val, reg);
+	}
+	/* Enable root. */
+	if (clk->root_en_mask) {
+		reg_val |= clk->root_en_mask;
+		writel_relaxed(reg_val, reg);
+	}
+	__branch_clk_enable_reg(&clk->b, clk->c.dbg_name);
+}
+
+/* Perform any register operations required to disable the branch. */
+u32 __branch_clk_disable_reg(const struct branch *clk, const char *name)
+{
+	u32 reg_val;
+
+	reg_val = readl_relaxed(clk->ctl_reg);
+	if (clk->en_mask) {
+		reg_val &= ~(clk->en_mask);
+		writel_relaxed(reg_val, clk->ctl_reg);
+	}
+
+	/*
+	 * Use a memory barrier since some halt status registers are
+	 * not within the same K segment as the branch/root enable
+	 * registers.  It's also needed in the udelay() case to ensure
+	 * the delay starts after the branch disable.
+	 */
+	mb();
+
+	/* Skip checking halt bit if the clock is in hardware gated mode */
+	if (branch_in_hwcg_mode(clk))
+		return reg_val;
+
+	/* Wait for clock to disable before continuing. */
+	if (clk->halt_check == DELAY || clk->halt_check == ENABLE_VOTED
+				     || clk->halt_check == HALT_VOTED)
+		udelay(HALT_CHECK_DELAY_US);
+	else if (clk->halt_check == ENABLE || clk->halt_check == HALT) {
+		int count;
+
+		/* Wait up to HALT_CHECK_MAX_LOOPS for clock to disable. */
+		for (count = HALT_CHECK_MAX_LOOPS; !branch_clk_is_halted(clk)
+					&& count > 0; count--)
+			udelay(1);
+		WARN(count == 0, "%s status stuck at 'on'", name);
+	}
+
+	return reg_val;
+}
+
+/* Perform any register operations required to disable the generator. */
+static void __rcg_clk_disable_reg(struct rcg_clk *clk)
+{
+	void __iomem *const reg = clk->b.ctl_reg;
+	uint32_t reg_val;
+
+	reg_val = __branch_clk_disable_reg(&clk->b, clk->c.dbg_name);
+	/* Disable root. */
+	if (clk->root_en_mask) {
+		reg_val &= ~(clk->root_en_mask);
+		writel_relaxed(reg_val, reg);
+	}
+	/* Disable MN counter, if applicable. */
+	if (clk->current_freq->md_val) {
+		reg_val &= ~(clk->mnd_en_mask);
+		writel_relaxed(reg_val, reg);
+	}
+	/*
+	 * Program NS register to low-power value with an un-clocked or
+	 * slowly-clocked source selected.
+	 */
+	if (clk->ns_mask) {
+		reg_val = readl_relaxed(clk->ns_reg);
+		reg_val &= ~(clk->ns_mask);
+		reg_val |= (clk->freq_tbl->ns_val & clk->ns_mask);
+		writel_relaxed(reg_val, clk->ns_reg);
+	}
+}
+
+/* Enable a rate-settable clock. */
+static int rcg_clk_enable(struct clk *c)
+{
+	unsigned long flags;
+	struct rcg_clk *clk = to_rcg_clk(c);
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	__rcg_clk_enable_reg(clk);
+	clk->enabled = true;
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	return 0;
+}
+
+/* Disable a rate-settable clock. */
+static void rcg_clk_disable(struct clk *c)
+{
+	unsigned long flags;
+	struct rcg_clk *clk = to_rcg_clk(c);
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	__rcg_clk_disable_reg(clk);
+	clk->enabled = false;
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+}
+
+/*
+ * Frequency-related functions
+ */
+
+/* Set a clock to an exact rate. */
+static int rcg_clk_set_rate(struct clk *c, unsigned long rate)
+{
+	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;
+	if (nf == cf)
+		return 0;
+
+	if (clk->enabled) {
+		/* Enable source clock dependency for the new freq. */
+		rc = clk_enable(nf->src_clk);
+		if (rc)
+			return rc;
+	}
+
+	spin_lock(&local_clock_reg_lock);
+
+	/* Disable branch if clock isn't dual-banked with a glitch-free MUX. */
+	if (!clk->bank_info) {
+		/* Disable all branches to prevent glitches. */
+		list_for_each_entry(chld, &clk->c.children, siblings) {
+			struct branch_clk *x = to_branch_clk(chld);
+			/*
+			 * We don't need to grab the child's lock because
+			 * we hold the local_clock_reg_lock and 'enabled' is
+			 * only modified within lock.
+			 */
+			if (x->enabled)
+				__branch_clk_disable_reg(&x->b, x->c.dbg_name);
+		}
+		if (clk->enabled)
+			__rcg_clk_disable_reg(clk);
+	}
+
+	/* Perform clock-specific frequency switch operations. */
+	BUG_ON(!clk->set_rate);
+	clk->set_rate(clk, nf);
+
+	/*
+	 * Current freq must be updated before __rcg_clk_enable_reg()
+	 * is called to make sure the MNCNTR_EN bit is set correctly.
+	 */
+	clk->current_freq = nf;
+
+	/* Enable any clocks that were disabled. */
+	if (!clk->bank_info) {
+		if (clk->enabled)
+			__rcg_clk_enable_reg(clk);
+		/* Enable only branches that were ON before. */
+		list_for_each_entry(chld, &clk->c.children, siblings) {
+			struct branch_clk *x = to_branch_clk(chld);
+			if (x->enabled)
+				__branch_clk_enable_reg(&x->b, x->c.dbg_name);
+		}
+	}
+
+	spin_unlock(&local_clock_reg_lock);
+
+	/* Release source requirements of the old freq. */
+	if (clk->enabled)
+		clk_disable(cf->src_clk);
+
+	return rc;
+}
+
+/* Check if a clock is currently enabled. */
+static int rcg_clk_is_enabled(struct clk *clk)
+{
+	return to_rcg_clk(clk)->enabled;
+}
+
+/* Return a supported rate that's at least the specified rate. */
+static long rcg_clk_round_rate(struct clk *c, unsigned long rate)
+{
+	struct rcg_clk *clk = to_rcg_clk(c);
+	struct clk_freq_tbl *f;
+
+	for (f = clk->freq_tbl; f->freq_hz != FREQ_END; f++)
+		if (f->freq_hz >= rate)
+			return f->freq_hz;
+
+	return -EPERM;
+}
+
+/* Return the nth supported frequency for a given clock. */
+static int rcg_clk_list_rate(struct clk *c, unsigned n)
+{
+	struct rcg_clk *clk = to_rcg_clk(c);
+
+	if (!clk->freq_tbl || clk->freq_tbl->freq_hz == FREQ_END)
+		return -ENXIO;
+
+	return (clk->freq_tbl + n)->freq_hz;
+}
+
+static struct clk *rcg_clk_get_parent(struct clk *clk)
+{
+	return to_rcg_clk(clk)->current_freq->src_clk;
+}
+
+/* Disable hw clock gating if not set at boot */
+enum handoff branch_handoff(struct branch *clk, struct clk *c)
+{
+	if (!branch_in_hwcg_mode(clk)) {
+		clk->hwcg_mask = 0;
+		c->flags &= ~CLKFLAG_HWCG;
+		if (readl_relaxed(clk->ctl_reg) & clk->en_mask)
+			return HANDOFF_ENABLED_CLK;
+	} else {
+		c->flags |= CLKFLAG_HWCG;
+	}
+	return HANDOFF_DISABLED_CLK;
+}
+
+static enum handoff branch_clk_handoff(struct clk *c)
+{
+	struct branch_clk *clk = to_branch_clk(c);
+	return branch_handoff(&clk->b, &clk->c);
+}
+
+static enum handoff rcg_clk_handoff(struct clk *c)
+{
+	struct rcg_clk *clk = to_rcg_clk(c);
+	uint32_t ctl_val, ns_val, md_val, ns_mask;
+	struct clk_freq_tbl *freq;
+	enum handoff ret;
+
+	ctl_val = readl_relaxed(clk->b.ctl_reg);
+	ret = branch_handoff(&clk->b, &clk->c);
+	if (ret == HANDOFF_DISABLED_CLK)
+		return HANDOFF_DISABLED_CLK;
+
+	if (clk->bank_info) {
+		const struct bank_masks *bank_masks = clk->bank_info;
+		const struct bank_mask_info *bank_info;
+		if (!(ctl_val & bank_masks->bank_sel_mask))
+			bank_info = &bank_masks->bank0_mask;
+		else
+			bank_info = &bank_masks->bank1_mask;
+
+		ns_mask = bank_info->ns_mask;
+		md_val = bank_info->md_reg ?
+				readl_relaxed(bank_info->md_reg) : 0;
+	} else {
+		ns_mask = clk->ns_mask;
+		md_val = clk->md_reg ? readl_relaxed(clk->md_reg) : 0;
+	}
+	if (!ns_mask)
+		return HANDOFF_UNKNOWN_RATE;
+	ns_val = readl_relaxed(clk->ns_reg) & ns_mask;
+	for (freq = clk->freq_tbl; freq->freq_hz != FREQ_END; freq++) {
+		if ((freq->ns_val & ns_mask) == ns_val &&
+		    (!freq->md_val || freq->md_val == md_val)) {
+			pr_info("%s rate=%d\n", clk->c.dbg_name, freq->freq_hz);
+			break;
+		}
+	}
+	if (freq->freq_hz == FREQ_END)
+		return HANDOFF_UNKNOWN_RATE;
+
+	clk->current_freq = freq;
+	c->rate = freq->freq_hz;
+
+	return HANDOFF_ENABLED_CLK;
+}
+
+struct clk_ops clk_ops_empty;
+
+struct fixed_clk gnd_clk = {
+	.c = {
+		.dbg_name = "ground_clk",
+		.ops = &clk_ops_empty,
+		CLK_INIT(gnd_clk.c),
+	},
+};
+
+static int branch_clk_enable(struct clk *clk)
+{
+	unsigned long flags;
+	struct branch_clk *branch = to_branch_clk(clk);
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	__branch_clk_enable_reg(&branch->b, branch->c.dbg_name);
+	branch->enabled = true;
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	return 0;
+}
+
+static void branch_clk_disable(struct clk *clk)
+{
+	unsigned long flags;
+	struct branch_clk *branch = to_branch_clk(clk);
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	__branch_clk_disable_reg(&branch->b, branch->c.dbg_name);
+	branch->enabled = false;
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+}
+
+static struct clk *branch_clk_get_parent(struct clk *clk)
+{
+	struct branch_clk *branch = to_branch_clk(clk);
+	return branch->parent;
+}
+
+static int branch_clk_is_enabled(struct clk *clk)
+{
+	struct branch_clk *branch = to_branch_clk(clk);
+	return branch->enabled;
+}
+
+static void branch_enable_hwcg(struct branch *b)
+{
+	unsigned long flags;
+	u32 reg_val;
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	reg_val = readl_relaxed(b->hwcg_reg);
+	reg_val |= b->hwcg_mask;
+	writel_relaxed(reg_val, b->hwcg_reg);
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+}
+
+static void branch_disable_hwcg(struct branch *b)
+{
+	unsigned long flags;
+	u32 reg_val;
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	reg_val = readl_relaxed(b->hwcg_reg);
+	reg_val &= ~b->hwcg_mask;
+	writel_relaxed(reg_val, b->hwcg_reg);
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+}
+
+static void branch_clk_enable_hwcg(struct clk *clk)
+{
+	struct branch_clk *branch = to_branch_clk(clk);
+	branch_enable_hwcg(&branch->b);
+}
+
+static void branch_clk_disable_hwcg(struct clk *clk)
+{
+	struct branch_clk *branch = to_branch_clk(clk);
+	branch_disable_hwcg(&branch->b);
+}
+
+static int branch_set_flags(struct branch *b, unsigned flags)
+{
+	unsigned long irq_flags;
+	u32 reg_val;
+	int ret = 0;
+
+	if (!b->retain_reg)
+		return -EPERM;
+
+	spin_lock_irqsave(&local_clock_reg_lock, irq_flags);
+	reg_val = readl_relaxed(b->retain_reg);
+	switch (flags) {
+	case CLKFLAG_RETAIN:
+		reg_val |= b->retain_mask;
+		break;
+	case CLKFLAG_NORETAIN:
+		reg_val &= ~b->retain_mask;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	writel_relaxed(reg_val, b->retain_reg);
+	spin_unlock_irqrestore(&local_clock_reg_lock, irq_flags);
+
+	return ret;
+}
+
+static int branch_clk_set_flags(struct clk *clk, unsigned flags)
+{
+	return branch_set_flags(&to_branch_clk(clk)->b, flags);
+}
+
+static int branch_clk_in_hwcg_mode(struct clk *c)
+{
+	struct branch_clk *clk = to_branch_clk(c);
+	return branch_in_hwcg_mode(&clk->b);
+}
+
+static void rcg_clk_enable_hwcg(struct clk *clk)
+{
+	struct rcg_clk *rcg = to_rcg_clk(clk);
+	branch_enable_hwcg(&rcg->b);
+}
+
+static void rcg_clk_disable_hwcg(struct clk *clk)
+{
+	struct rcg_clk *rcg = to_rcg_clk(clk);
+	branch_disable_hwcg(&rcg->b);
+}
+
+static int rcg_clk_in_hwcg_mode(struct clk *c)
+{
+	struct rcg_clk *clk = to_rcg_clk(c);
+	return branch_in_hwcg_mode(&clk->b);
+}
+
+static int rcg_clk_set_flags(struct clk *clk, unsigned flags)
+{
+	return branch_set_flags(&to_rcg_clk(clk)->b, flags);
+}
+
+int branch_reset(struct branch *b, enum clk_reset_action action)
+{
+	int ret = 0;
+	u32 reg_val;
+	unsigned long flags;
+
+	if (!b->reset_reg)
+		return -EPERM;
+
+	/* Disable hw gating when asserting a reset */
+	if (b->hwcg_mask && action == CLK_RESET_ASSERT)
+		branch_disable_hwcg(b);
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	/* Assert/Deassert reset */
+	reg_val = readl_relaxed(b->reset_reg);
+	switch (action) {
+	case CLK_RESET_ASSERT:
+		reg_val |= b->reset_mask;
+		break;
+	case CLK_RESET_DEASSERT:
+		reg_val &= ~b->reset_mask;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	writel_relaxed(reg_val, b->reset_reg);
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	/* Enable hw gating when deasserting a reset */
+	if (b->hwcg_mask && action == CLK_RESET_DEASSERT)
+		branch_enable_hwcg(b);
+	/* Make sure write is issued before returning. */
+	mb();
+	return ret;
+}
+
+static int branch_clk_reset(struct clk *clk, enum clk_reset_action action)
+{
+	return branch_reset(&to_branch_clk(clk)->b, action);
+}
+
+struct clk_ops clk_ops_branch = {
+	.enable = branch_clk_enable,
+	.disable = branch_clk_disable,
+	.enable_hwcg = branch_clk_enable_hwcg,
+	.disable_hwcg = branch_clk_disable_hwcg,
+	.in_hwcg_mode = branch_clk_in_hwcg_mode,
+	.auto_off = branch_clk_disable,
+	.is_enabled = branch_clk_is_enabled,
+	.reset = branch_clk_reset,
+	.get_parent = branch_clk_get_parent,
+	.handoff = branch_clk_handoff,
+	.set_flags = branch_clk_set_flags,
+};
+
+struct clk_ops clk_ops_reset = {
+	.reset = branch_clk_reset,
+};
+
+static int rcg_clk_reset(struct clk *clk, enum clk_reset_action action)
+{
+	return branch_reset(&to_rcg_clk(clk)->b, action);
+}
+
+struct clk_ops clk_ops_rcg = {
+	.enable = rcg_clk_enable,
+	.disable = rcg_clk_disable,
+	.enable_hwcg = rcg_clk_enable_hwcg,
+	.disable_hwcg = rcg_clk_disable_hwcg,
+	.in_hwcg_mode = rcg_clk_in_hwcg_mode,
+	.auto_off = rcg_clk_disable,
+	.handoff = rcg_clk_handoff,
+	.set_rate = rcg_clk_set_rate,
+	.list_rate = rcg_clk_list_rate,
+	.is_enabled = rcg_clk_is_enabled,
+	.round_rate = rcg_clk_round_rate,
+	.reset = rcg_clk_reset,
+	.get_parent = rcg_clk_get_parent,
+	.set_flags = rcg_clk_set_flags,
+};
+
+static int cdiv_clk_enable(struct clk *c)
+{
+	unsigned long flags;
+	struct cdiv_clk *clk = to_cdiv_clk(c);
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	__branch_clk_enable_reg(&clk->b, clk->c.dbg_name);
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	return 0;
+}
+
+static void cdiv_clk_disable(struct clk *c)
+{
+	unsigned long flags;
+	struct cdiv_clk *clk = to_cdiv_clk(c);
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	__branch_clk_disable_reg(&clk->b, clk->c.dbg_name);
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+}
+
+static int cdiv_clk_set_rate(struct clk *c, unsigned long rate)
+{
+	struct cdiv_clk *clk = to_cdiv_clk(c);
+	u32 reg_val;
+
+	if (rate > clk->max_div)
+		return -EINVAL;
+	/* Check if frequency is actually changed. */
+	if (rate == clk->cur_div)
+		return 0;
+
+	spin_lock(&local_clock_reg_lock);
+	reg_val = readl_relaxed(clk->ns_reg);
+	reg_val &= ~(clk->ext_mask | (clk->max_div - 1) << clk->div_offset);
+	/* Non-zero rates mean set a divider, zero means use external input */
+	if (rate)
+		reg_val |= (rate - 1) << clk->div_offset;
+	else
+		reg_val |= clk->ext_mask;
+	writel_relaxed(reg_val, clk->ns_reg);
+	spin_unlock(&local_clock_reg_lock);
+
+	clk->cur_div = rate;
+	return 0;
+}
+
+static unsigned long cdiv_clk_get_rate(struct clk *c)
+{
+	struct cdiv_clk *clk = to_cdiv_clk(c);
+	return clk->cur_div;
+}
+
+static long cdiv_clk_round_rate(struct clk *c, unsigned long rate)
+{
+	struct cdiv_clk *clk = to_cdiv_clk(c);
+	return rate > clk->max_div ? -EPERM : rate;
+}
+
+static int cdiv_clk_list_rate(struct clk *c, unsigned n)
+{
+	struct cdiv_clk *clk = to_cdiv_clk(c);
+	return n > clk->max_div ? -ENXIO : n;
+}
+
+static enum handoff cdiv_clk_handoff(struct clk *c)
+{
+	struct cdiv_clk *clk = to_cdiv_clk(c);
+	enum handoff ret;
+	u32 reg_val;
+
+	ret = branch_handoff(&clk->b, &clk->c);
+	if (ret == HANDOFF_DISABLED_CLK)
+		return ret;
+
+	reg_val = readl_relaxed(clk->ns_reg);
+	if (reg_val & clk->ext_mask) {
+		clk->cur_div = 0;
+	} else {
+		reg_val >>= clk->div_offset;
+		clk->cur_div = (reg_val & (clk->max_div - 1)) + 1;
+	}
+
+	return HANDOFF_ENABLED_CLK;
+}
+
+static void cdiv_clk_enable_hwcg(struct clk *c)
+{
+	struct cdiv_clk *clk = to_cdiv_clk(c);
+	branch_enable_hwcg(&clk->b);
+}
+
+static void cdiv_clk_disable_hwcg(struct clk *c)
+{
+	struct cdiv_clk *clk = to_cdiv_clk(c);
+	branch_disable_hwcg(&clk->b);
+}
+
+static int cdiv_clk_in_hwcg_mode(struct clk *c)
+{
+	struct cdiv_clk *clk = to_cdiv_clk(c);
+	return branch_in_hwcg_mode(&clk->b);
+}
+
+struct clk_ops clk_ops_cdiv = {
+	.enable = cdiv_clk_enable,
+	.disable = cdiv_clk_disable,
+	.in_hwcg_mode = cdiv_clk_in_hwcg_mode,
+	.enable_hwcg = cdiv_clk_enable_hwcg,
+	.disable_hwcg = cdiv_clk_disable_hwcg,
+	.auto_off = cdiv_clk_disable,
+	.handoff = cdiv_clk_handoff,
+	.set_rate = cdiv_clk_set_rate,
+	.get_rate = cdiv_clk_get_rate,
+	.list_rate = cdiv_clk_list_rate,
+	.round_rate = cdiv_clk_round_rate,
+};
diff --git a/arch/arm/mach-msm/clock-local.h b/arch/arm/mach-msm/clock-local.h
new file mode 100644
index 0000000..ffc7057
--- /dev/null
+++ b/arch/arm/mach-msm/clock-local.h
@@ -0,0 +1,290 @@
+/* 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
+ * 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 __ARCH_ARM_MACH_MSM_CLOCK_LOCAL_H
+#define __ARCH_ARM_MACH_MSM_CLOCK_LOCAL_H
+
+#include <linux/spinlock.h>
+#include "clock.h"
+
+#define MN_MODE_DUAL_EDGE 0x2
+
+/* MD Registers */
+#define MD4(m_lsb, m, n_lsb, n) \
+		((BVAL((m_lsb+3), m_lsb, m) | BVAL((n_lsb+3), n_lsb, ~(n))) \
+		* !!(n))
+#define MD8(m_lsb, m, n_lsb, n) \
+		((BVAL((m_lsb+7), m_lsb, m) | BVAL((n_lsb+7), n_lsb, ~(n))) \
+		* !!(n))
+#define MD16(m, n) ((BVAL(31, 16, m) | BVAL(15, 0, ~(n))) * !!(n))
+
+/* 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) * !!(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) * !!(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) \
+		(BVAL(d_msb, d_lsb, (d-1)) | BVAL(s_msb, s_lsb, s))
+
+#define NS_DIV(d_msb, d_lsb, d) \
+		BVAL(d_msb, d_lsb, (d-1))
+
+#define NS_SRC_SEL(s_msb, s_lsb, s) \
+		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) * !!(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) * !!(n)) \
+		| BVAL((n1_lsb+7), n1_lsb, ~(n-m) * !!(n)) \
+		| BVAL((s0_lsb+2), s0_lsb, s) \
+		| BVAL((s1_lsb+2), s1_lsb, s))
+
+#define NS_DIVSRC_BANKED(d0_msb, d0_lsb, d1_msb, d1_lsb, d, \
+	s0_msb, s0_lsb, s1_msb, s1_lsb, s) \
+		 (BVAL(d0_msb, d0_lsb, (d-1)) | BVAL(d1_msb, d1_lsb, (d-1)) \
+		| BVAL(s0_msb, s0_lsb, s) \
+		| BVAL(s1_msb, s1_lsb, s))
+
+/* CC Registers */
+#define CC(mde_lsb, n) (BVAL((mde_lsb+1), mde_lsb, MN_MODE_DUAL_EDGE) * !!(n))
+#define CC_BANKED(mde0_lsb, mde1_lsb, n) \
+		((BVAL((mde0_lsb+1), mde0_lsb, MN_MODE_DUAL_EDGE) \
+		| BVAL((mde1_lsb+1), mde1_lsb, MN_MODE_DUAL_EDGE)) \
+		* !!(n))
+
+/*
+ * Clock Definition Macros
+ */
+#define DEFINE_CLK_MEASURE(name) \
+	struct clk name = { \
+		.ops = &clk_ops_empty, \
+		.dbg_name = #name, \
+		CLK_INIT(name), \
+	}; \
+
+/*
+ * Generic frequency-definition structs and macros
+ */
+struct clk_freq_tbl {
+	const uint32_t	freq_hz;
+	struct clk	*const src_clk;
+	const uint32_t	md_val;
+	const uint32_t	ns_val;
+	const uint32_t	ctl_val;
+	void		*const extra_freq_data;
+};
+
+/* Some clocks have two banks to avoid glitches when switching frequencies.
+ * The unused bank is programmed while running on the other bank, and
+ * switched to afterwards. The following two structs describe the banks. */
+struct bank_mask_info {
+	void *const md_reg;
+	const uint32_t	ns_mask;
+	const uint32_t	rst_mask;
+	const uint32_t	mnd_en_mask;
+	const uint32_t	mode_mask;
+};
+
+struct bank_masks {
+	const uint32_t			bank_sel_mask;
+	const struct bank_mask_info	bank0_mask;
+	const struct bank_mask_info	bank1_mask;
+};
+
+#define F_RAW(f, sc, m_v, n_v, c_v, e) { \
+	.freq_hz = f, \
+	.src_clk = sc, \
+	.md_val = m_v, \
+	.ns_val = n_v, \
+	.ctl_val = c_v, \
+	.extra_freq_data = e, \
+	}
+#define FREQ_END	(UINT_MAX-1)
+#define F_END { .freq_hz = FREQ_END }
+
+/**
+ * struct branch - branch on/off
+ * @ctl_reg: clock control register
+ * @en_mask: ORed with @ctl_reg to enable the clock
+ * @hwcg_reg: hardware clock gating register
+ * @hwcg_mask: ORed with @hwcg_reg to enable hardware clock gating
+ * @halt_reg: halt register
+ * @halt_check: type of halt check to perform
+ * @halt_bit: ANDed with @halt_reg to test for clock halted
+ * @reset_reg: reset register
+ * @reset_mask: ORed with @reset_reg to reset the clock domain
+ */
+struct branch {
+	void __iomem *const ctl_reg;
+	const u32 en_mask;
+
+	void __iomem *hwcg_reg;
+	u32 hwcg_mask;
+
+	void __iomem *const halt_reg;
+	const u16 halt_check;
+	const u16 halt_bit;
+
+	void __iomem *const reset_reg;
+	const u32 reset_mask;
+
+	void __iomem *const retain_reg;
+	const u32 retain_mask;
+};
+
+extern struct clk_ops clk_ops_branch;
+extern struct clk_ops clk_ops_reset;
+
+int branch_reset(struct branch *b, enum clk_reset_action action);
+void __branch_clk_enable_reg(const struct branch *clk, const char *name);
+u32 __branch_clk_disable_reg(const struct branch *clk, const char *name);
+enum handoff branch_handoff(struct branch *clk, struct clk *c);
+
+/*
+ * Generic clock-definition struct and macros
+ */
+struct rcg_clk {
+	bool		enabled;
+	void		*const ns_reg;
+	void		*const md_reg;
+
+	const uint32_t	root_en_mask;
+	uint32_t	ns_mask;
+	const uint32_t	ctl_mask;
+	uint32_t	mnd_en_mask;
+
+	void		*bank_info;
+	void   (*set_rate)(struct rcg_clk *, struct clk_freq_tbl *);
+
+	struct clk_freq_tbl *freq_tbl;
+	struct clk_freq_tbl *current_freq;
+
+	struct branch	b;
+	struct clk	c;
+};
+
+static inline struct rcg_clk *to_rcg_clk(struct clk *clk)
+{
+	return container_of(clk, struct rcg_clk, c);
+}
+
+extern struct clk_ops clk_ops_rcg;
+
+extern struct clk_freq_tbl rcg_dummy_freq;
+
+/**
+ * struct cdiv_clk - integer divider clock with external source selection
+ * @ns_reg: source select and divider settings register
+ * @ext_mask: bit to set to select an external source
+ * @cur_div: current divider setting (or 0 for external source)
+ * @max_div: maximum divider value supported (must be power of 2)
+ * @div_offset: number of bits to shift divider left by in @ns_reg
+ * @b: branch
+ * @c: clock
+ */
+struct cdiv_clk {
+	void __iomem *const ns_reg;
+	u32 ext_mask;
+
+	unsigned long cur_div;
+	u8 div_offset;
+	u32 max_div;
+
+	struct branch b;
+	struct clk c;
+};
+
+static inline struct cdiv_clk *to_cdiv_clk(struct clk *clk)
+{
+	return container_of(clk, struct cdiv_clk, c);
+}
+
+extern struct clk_ops clk_ops_cdiv;
+
+/**
+ * struct fixed_clk - fixed rate clock (used for crystal oscillators)
+ * @c: clk
+ */
+struct fixed_clk {
+	struct clk c;
+};
+
+/**
+ * struct branch_clk - branch
+ * @enabled: true if clock is on, false otherwise
+ * @b: branch
+ * @parent: clock source
+ * @c: clk
+ *
+ * An on/off switch with a rate derived from the parent.
+ */
+struct branch_clk {
+	bool enabled;
+	struct branch b;
+	struct clk *parent;
+	struct clk c;
+};
+
+static inline struct branch_clk *to_branch_clk(struct clk *clk)
+{
+	return container_of(clk, struct branch_clk, c);
+}
+
+/**
+ * struct measure_clk - for rate measurement debug use
+ * @sample_ticks: sample period in reference clock ticks
+ * @multiplier: measurement scale-up factor
+ * @divider: measurement scale-down factor
+ * @c: clk
+*/
+struct measure_clk {
+	u64 sample_ticks;
+	u32 multiplier;
+	u32 divider;
+	struct clk c;
+};
+
+extern struct clk_ops clk_ops_empty;
+
+static inline struct measure_clk *to_measure_clk(struct clk *clk)
+{
+	return container_of(clk, struct measure_clk, c);
+}
+
+/*
+ * Variables from clock-local driver
+ */
+extern spinlock_t		local_clock_reg_lock;
+extern struct fixed_clk		gnd_clk;
+
+/*
+ * Generic set-rate implementations
+ */
+void set_rate_mnd(struct rcg_clk *clk, struct clk_freq_tbl *nf);
+void set_rate_nop(struct rcg_clk *clk, struct clk_freq_tbl *nf);
+void set_rate_mnd_8(struct rcg_clk *clk, struct clk_freq_tbl *nf);
+void set_rate_mnd_banked(struct rcg_clk *clk, struct clk_freq_tbl *nf);
+void set_rate_div_banked(struct rcg_clk *clk, struct clk_freq_tbl *nf);
+
+#endif /* __ARCH_ARM_MACH_MSM_CLOCK_LOCAL_H */
+
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
new file mode 100644
index 0000000..e8e88d7
--- /dev/null
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -0,0 +1,591 @@
+/* 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.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <mach/clk.h>
+
+#include "clock.h"
+#include "clock-local2.h"
+
+/*
+ * When enabling/disabling a clock, check the halt bit up to this number
+ * number of times (with a 1 us delay in between) before continuing.
+ */
+#define HALT_CHECK_MAX_LOOPS	200
+/* For clock without halt checking, wait this long after enables/disables. */
+#define HALT_CHECK_DELAY_US	10
+
+/*
+ * When updating an RCG configuration, check the update bit up to this number
+ * number of times (with a 1 us delay in between) before continuing.
+ */
+#define UPDATE_CHECK_MAX_LOOPS	200
+
+DEFINE_SPINLOCK(local_clock_reg_lock);
+struct clk_freq_tbl rcg_dummy_freq = F_END;
+
+#define CMD_RCGR_REG(x) (*(x)->base + (x)->cmd_rcgr_reg)
+#define CFG_RCGR_REG(x) (*(x)->base + (x)->cmd_rcgr_reg + 0x4)
+#define M_REG(x)	(*(x)->base + (x)->cmd_rcgr_reg + 0x8)
+#define N_REG(x)	(*(x)->base + (x)->cmd_rcgr_reg + 0xC)
+#define D_REG(x)	(*(x)->base + (x)->cmd_rcgr_reg + 0x10)
+#define CBCR_REG(x)	(*(x)->base + (x)->cbcr_reg)
+#define BCR_REG(x)	(*(x)->base + (x)->bcr_reg)
+#define VOTE_REG(x)	(*(x)->base + (x)->vote_reg)
+
+/*
+ * Important clock bit positions and masks
+ */
+#define CMD_RCGR_ROOT_ENABLE_BIT	BIT(1)
+#define CBCR_BRANCH_ENABLE_BIT		BIT(0)
+#define CBCR_BRANCH_OFF_BIT		BIT(31)
+#define CMD_RCGR_CONFIG_UPDATE_BIT	BIT(0)
+#define CMD_RCGR_ROOT_STATUS_BIT	BIT(31)
+#define BCR_BLK_ARES_BIT		BIT(0)
+#define CBCR_HW_CTL_BIT			BIT(1)
+#define CFG_RCGR_DIV_MASK		BM(4, 0)
+#define CFG_RCGR_SRC_SEL_MASK		BM(10, 8)
+#define MND_MODE_MASK			BM(13, 12)
+#define MND_DUAL_EDGE_MODE_BVAL		BVAL(13, 12, 0x2)
+#define CMD_RCGR_CONFIG_DIRTY_MASK	BM(7, 4)
+#define CBCR_BRANCH_CDIV_MASK		BM(24, 16)
+#define CBCR_BRANCH_CDIV_MASKED(val)	BVAL(24, 16, (val));
+
+enum branch_state {
+	BRANCH_ON,
+	BRANCH_OFF,
+};
+
+/*
+ * RCG functions
+ */
+
+/*
+ * Update an RCG with a new configuration. This may include a new M, N, or D
+ * value, source selection or pre-divider value.
+ *
+ */
+static void rcg_update_config(struct rcg_clk *rcg)
+{
+	u32 cmd_rcgr_regval, count;
+
+	cmd_rcgr_regval = readl_relaxed(CMD_RCGR_REG(rcg));
+	cmd_rcgr_regval |= CMD_RCGR_CONFIG_UPDATE_BIT;
+	writel_relaxed(cmd_rcgr_regval, CMD_RCGR_REG(rcg));
+
+	/* Wait for update to take effect */
+	for (count = UPDATE_CHECK_MAX_LOOPS; count > 0; count--) {
+		if (!(readl_relaxed(CMD_RCGR_REG(rcg)) &
+				CMD_RCGR_CONFIG_UPDATE_BIT))
+			return;
+		udelay(1);
+	}
+
+	WARN(count == 0, "%s: rcg didn't update its configuration.",
+		rcg->c.dbg_name);
+}
+
+/* RCG set rate function for clocks with Half Integer Dividers. */
+void set_rate_hid(struct rcg_clk *rcg, struct clk_freq_tbl *nf)
+{
+	u32 cfg_regval;
+
+	cfg_regval = readl_relaxed(CFG_RCGR_REG(rcg));
+	cfg_regval &= ~(CFG_RCGR_DIV_MASK | CFG_RCGR_SRC_SEL_MASK);
+	cfg_regval |= nf->div_src_val;
+	writel_relaxed(cfg_regval, CFG_RCGR_REG(rcg));
+
+	rcg_update_config(rcg);
+}
+
+/* RCG set rate function for clocks with MND & Half Integer Dividers. */
+void set_rate_mnd(struct rcg_clk *rcg, struct clk_freq_tbl *nf)
+{
+	u32 cfg_regval;
+
+	writel_relaxed(nf->m_val, M_REG(rcg));
+	writel_relaxed(nf->n_val, N_REG(rcg));
+	writel_relaxed(nf->d_val, D_REG(rcg));
+
+	cfg_regval = readl_relaxed(CFG_RCGR_REG(rcg));
+	cfg_regval &= ~(CFG_RCGR_DIV_MASK | CFG_RCGR_SRC_SEL_MASK);
+	cfg_regval |= nf->div_src_val;
+
+	/* Activate or disable the M/N:D divider as necessary */
+	cfg_regval &= ~MND_MODE_MASK;
+	if (nf->n_val != 0)
+		cfg_regval |= MND_DUAL_EDGE_MODE_BVAL;
+	writel_relaxed(cfg_regval, CFG_RCGR_REG(rcg));
+
+	rcg_update_config(rcg);
+}
+
+static int rcg_clk_enable(struct clk *c)
+{
+	struct rcg_clk *rcg = to_rcg_clk(c);
+
+	WARN(rcg->current_freq == &rcg_dummy_freq,
+		"Attempting to enable %s before setting its rate. "
+		"Set the rate first!\n", rcg->c.dbg_name);
+
+	return 0;
+}
+
+static int rcg_clk_set_rate(struct clk *c, unsigned long rate)
+{
+	struct clk_freq_tbl *cf, *nf;
+	struct rcg_clk *rcg = to_rcg_clk(c);
+	int rc = 0;
+	unsigned long flags;
+
+	for (nf = rcg->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 = rcg->current_freq;
+	if (nf == cf)
+		return 0;
+
+	if (rcg->c.count) {
+		/* TODO: Modify to use the prepare API */
+		/* Enable source clock dependency for the new freq. */
+		rc = clk_enable(nf->src_clk);
+		if (rc)
+			goto out;
+	}
+
+	BUG_ON(!rcg->set_rate);
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+
+	/* Perform clock-specific frequency switch operations. */
+	rcg->set_rate(rcg, nf);
+
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	/* Release source requirements of the old freq. */
+	if (rcg->c.count)
+		clk_disable(cf->src_clk);
+
+	rcg->current_freq = nf;
+out:
+	return rc;
+}
+
+/* Return a supported rate that's at least the specified rate. */
+static long rcg_clk_round_rate(struct clk *c, unsigned long rate)
+{
+	struct rcg_clk *rcg = to_rcg_clk(c);
+	struct clk_freq_tbl *f;
+
+	for (f = rcg->freq_tbl; f->freq_hz != FREQ_END; f++)
+		if (f->freq_hz >= rate)
+			return f->freq_hz;
+
+	return -EPERM;
+}
+
+/* Return the nth supported frequency for a given clock. */
+static int rcg_clk_list_rate(struct clk *c, unsigned n)
+{
+	struct rcg_clk *rcg = to_rcg_clk(c);
+
+	if (!rcg->freq_tbl || rcg->freq_tbl->freq_hz == FREQ_END)
+		return -ENXIO;
+
+	return (rcg->freq_tbl + n)->freq_hz;
+}
+
+static struct clk *rcg_clk_get_parent(struct clk *c)
+{
+	return to_rcg_clk(c)->current_freq->src_clk;
+}
+
+static enum handoff _rcg_clk_handoff(struct rcg_clk *rcg, int has_mnd)
+{
+	u32 n_regval = 0, m_regval = 0, d_regval = 0;
+	u32 cfg_regval;
+	struct clk_freq_tbl *freq;
+	u32 cmd_rcgr_regval;
+
+	/* Is the root enabled? */
+	cmd_rcgr_regval = readl_relaxed(CMD_RCGR_REG(rcg));
+	if ((cmd_rcgr_regval & CMD_RCGR_ROOT_STATUS_BIT))
+		return HANDOFF_DISABLED_CLK;
+
+	/* Is there a pending configuration? */
+	if (cmd_rcgr_regval & CMD_RCGR_CONFIG_DIRTY_MASK)
+		return HANDOFF_UNKNOWN_RATE;
+
+	/* Get values of m, n, d, div and src_sel registers. */
+	if (has_mnd) {
+		m_regval = readl_relaxed(M_REG(rcg));
+		n_regval = readl_relaxed(N_REG(rcg));
+		d_regval = readl_relaxed(D_REG(rcg));
+
+		/*
+		 * The n and d values stored in the frequency tables are sign
+		 * extended to 32 bits. The n and d values in the registers are
+		 * sign extended to 8 or 16 bits. Sign extend the values read
+		 * from the registers so that they can be compared to the
+		 * values in the frequency tables.
+		 */
+		n_regval |= (n_regval >> 8) ? BM(31, 16) : BM(31, 8);
+		d_regval |= (d_regval >> 8) ? BM(31, 16) : BM(31, 8);
+	}
+
+	cfg_regval = readl_relaxed(CFG_RCGR_REG(rcg));
+	cfg_regval &= CFG_RCGR_SRC_SEL_MASK | CFG_RCGR_DIV_MASK
+				| MND_MODE_MASK;
+
+	/* If mnd counter is present, check if it's in use. */
+	has_mnd = (has_mnd) &&
+		((cfg_regval & MND_MODE_MASK) == MND_DUAL_EDGE_MODE_BVAL);
+
+	/*
+	 * Clear out the mn counter mode bits since we now want to compare only
+	 * the source mux selection and pre-divider values in the registers.
+	 */
+	cfg_regval &= ~MND_MODE_MASK;
+
+	/* Figure out what rate the rcg is running at */
+	for (freq = rcg->freq_tbl; freq->freq_hz != FREQ_END; freq++) {
+		if (freq->div_src_val != cfg_regval)
+			continue;
+		if (has_mnd) {
+			if (freq->m_val != m_regval)
+				continue;
+			if (freq->n_val != n_regval)
+				continue;
+			if (freq->d_val != d_regval)
+				continue;
+		}
+		pr_info("%s rate=%lu\n", rcg->c.dbg_name, freq->freq_hz);
+		break;
+	}
+
+	/* No known frequency found */
+	if (freq->freq_hz == FREQ_END)
+		return HANDOFF_UNKNOWN_RATE;
+
+	rcg->current_freq = freq;
+	rcg->c.rate = freq->freq_hz;
+
+	return HANDOFF_ENABLED_CLK;
+}
+
+static enum handoff rcg_mnd_clk_handoff(struct clk *c)
+{
+	return _rcg_clk_handoff(to_rcg_clk(c), 1);
+}
+
+static enum handoff rcg_clk_handoff(struct clk *c)
+{
+	return _rcg_clk_handoff(to_rcg_clk(c), 0);
+}
+
+/*
+ * Branch clock functions
+ */
+static void branch_clk_halt_check(u32 halt_check, const char *clk_name,
+				  void __iomem *cbcr_reg,
+				  enum branch_state br_status)
+{
+	char *status_str = (br_status == BRANCH_ON) ? "off" : "on";
+
+	/*
+	 * Use a memory barrier since some halt status registers are
+	 * not within the same 1K segment as the branch/root enable
+	 * registers.  It's also needed in the udelay() case to ensure
+	 * the delay starts after the branch disable.
+	 */
+	mb();
+
+	if (halt_check == DELAY || halt_check == HALT_VOTED) {
+		udelay(HALT_CHECK_DELAY_US);
+	} else if (halt_check == HALT) {
+		int count;
+		for (count = HALT_CHECK_MAX_LOOPS; count > 0; count--) {
+			if (br_status == BRANCH_ON
+				&& !(readl_relaxed(cbcr_reg)
+						& CBCR_BRANCH_OFF_BIT))
+				return;
+			if (br_status == BRANCH_OFF
+				&& (readl_relaxed(cbcr_reg)
+						& CBCR_BRANCH_OFF_BIT))
+				return;
+			udelay(1);
+		}
+		WARN(count == 0, "%s status stuck %s", clk_name, status_str);
+	}
+}
+
+static int branch_clk_enable(struct clk *c)
+{
+	unsigned long flags;
+	u32 cbcr_val;
+	struct branch_clk *branch = to_branch_clk(c);
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	cbcr_val = readl_relaxed(CBCR_REG(branch));
+	cbcr_val |= CBCR_BRANCH_ENABLE_BIT;
+	writel_relaxed(cbcr_val, CBCR_REG(branch));
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	/* Wait for clock to enable before continuing. */
+	branch_clk_halt_check(branch->halt_check, branch->c.dbg_name,
+				CBCR_REG(branch), BRANCH_ON);
+
+	return 0;
+}
+
+static void branch_clk_disable(struct clk *c)
+{
+	unsigned long flags;
+	struct branch_clk *branch = to_branch_clk(c);
+	u32 reg_val;
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	reg_val = readl_relaxed(CBCR_REG(branch));
+	reg_val &= ~CBCR_BRANCH_ENABLE_BIT;
+	writel_relaxed(reg_val, CBCR_REG(branch));
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	/* Wait for clock to disable before continuing. */
+	branch_clk_halt_check(branch->halt_check, branch->c.dbg_name,
+				CBCR_REG(branch), BRANCH_OFF);
+}
+
+static int branch_cdiv_set_rate(struct branch_clk *branch, unsigned long rate)
+{
+	unsigned long flags;
+	u32 regval;
+
+	if (rate > branch->max_div)
+		return -EINVAL;
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	regval = readl_relaxed(CBCR_REG(branch));
+	regval &= ~CBCR_BRANCH_CDIV_MASK;
+	regval |= CBCR_BRANCH_CDIV_MASKED(rate);
+	writel_relaxed(regval, CBCR_REG(branch));
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	return 0;
+}
+
+static int branch_clk_set_rate(struct clk *c, unsigned long rate)
+{
+	struct branch_clk *branch = to_branch_clk(c);
+
+	if (branch->max_div)
+		return branch_cdiv_set_rate(branch, rate);
+
+	if (!branch->has_sibling)
+		return clk_set_rate(branch->parent, rate);
+
+	return -EPERM;
+}
+
+static unsigned long branch_clk_get_rate(struct clk *c)
+{
+	struct branch_clk *branch = to_branch_clk(c);
+
+	if (branch->max_div)
+		return branch->c.rate;
+
+	if (!branch->has_sibling)
+		return clk_get_rate(branch->parent);
+
+	return 0;
+}
+
+static struct clk *branch_clk_get_parent(struct clk *c)
+{
+	return to_branch_clk(c)->parent;
+}
+
+static int branch_clk_list_rate(struct clk *c, unsigned n)
+{
+	struct branch_clk *branch = to_branch_clk(c);
+
+	if (branch->has_sibling == 1)
+		return -ENXIO;
+
+	if (branch->parent)
+		return rcg_clk_list_rate(branch->parent, n);
+	else
+		return 0;
+}
+
+static enum handoff branch_clk_handoff(struct clk *c)
+{
+	struct branch_clk *branch = to_branch_clk(c);
+	u32 cbcr_regval;
+
+	cbcr_regval = readl_relaxed(CBCR_REG(branch));
+	if ((cbcr_regval & CBCR_BRANCH_OFF_BIT))
+		return HANDOFF_DISABLED_CLK;
+	pr_info("%s enabled.\n", branch->c.dbg_name);
+
+	if (branch->parent) {
+		if (branch->parent->ops->handoff)
+			return branch->parent->ops->handoff(branch->parent);
+	}
+
+	return HANDOFF_ENABLED_CLK;
+}
+
+static int __branch_clk_reset(void __iomem *bcr_reg,
+				enum clk_reset_action action)
+{
+	int ret = 0;
+	unsigned long flags;
+	u32 reg_val;
+
+	if (!bcr_reg)
+		return -EPERM;
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	reg_val = readl_relaxed(bcr_reg);
+	switch (action) {
+	case CLK_RESET_ASSERT:
+		reg_val |= BCR_BLK_ARES_BIT;
+		break;
+	case CLK_RESET_DEASSERT:
+		reg_val &= ~BCR_BLK_ARES_BIT;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	writel_relaxed(reg_val, bcr_reg);
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	/* Make sure write is issued before returning. */
+	mb();
+
+	return ret;
+}
+
+static int branch_clk_reset(struct clk *c, enum clk_reset_action action)
+{
+	struct branch_clk *branch = to_branch_clk(c);
+	return __branch_clk_reset(BCR_REG(branch), action);
+}
+
+/*
+ * Voteable clock functions
+ */
+static int local_vote_clk_reset(struct clk *c, enum clk_reset_action action)
+{
+	struct branch_clk *vclk = to_branch_clk(c);
+	return __branch_clk_reset(BCR_REG(vclk), action);
+}
+
+static int local_vote_clk_enable(struct clk *c)
+{
+	unsigned long flags;
+	u32 ena;
+	struct local_vote_clk *vclk = to_local_vote_clk(c);
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	ena = readl_relaxed(VOTE_REG(vclk));
+	ena |= vclk->en_mask;
+	writel_relaxed(ena, VOTE_REG(vclk));
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	branch_clk_halt_check(vclk->halt_check, c->dbg_name, CBCR_REG(vclk),
+				BRANCH_ON);
+
+	return 0;
+}
+
+static void local_vote_clk_disable(struct clk *c)
+{
+	unsigned long flags;
+	u32 ena;
+	struct local_vote_clk *vclk = to_local_vote_clk(c);
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	ena = readl_relaxed(VOTE_REG(vclk));
+	ena &= ~vclk->en_mask;
+	writel_relaxed(ena, VOTE_REG(vclk));
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+}
+
+static enum handoff local_vote_clk_handoff(struct clk *c)
+{
+	struct local_vote_clk *vclk = to_local_vote_clk(c);
+	u32 vote_regval;
+
+	/* Is the branch voted on by apps? */
+	vote_regval = readl_relaxed(VOTE_REG(vclk));
+	if (!(vote_regval & vclk->en_mask))
+		return HANDOFF_DISABLED_CLK;
+	pr_info("%s enabled.\n", vclk->c.dbg_name);
+
+	return HANDOFF_ENABLED_CLK;
+}
+
+struct clk_ops clk_ops_rcg = {
+	.enable = rcg_clk_enable,
+	.set_rate = rcg_clk_set_rate,
+	.list_rate = rcg_clk_list_rate,
+	.round_rate = rcg_clk_round_rate,
+	.get_parent = rcg_clk_get_parent,
+	.handoff = rcg_clk_handoff,
+};
+
+struct clk_ops clk_ops_rcg_mnd = {
+	.enable = rcg_clk_enable,
+	.set_rate = rcg_clk_set_rate,
+	.list_rate = rcg_clk_list_rate,
+	.round_rate = rcg_clk_round_rate,
+	.get_parent = rcg_clk_get_parent,
+	.handoff = rcg_mnd_clk_handoff,
+};
+
+struct clk_ops clk_ops_branch = {
+	.enable = branch_clk_enable,
+	.disable = branch_clk_disable,
+	.auto_off = branch_clk_disable,
+	.set_rate = branch_clk_set_rate,
+	.get_rate = branch_clk_get_rate,
+	.list_rate = branch_clk_list_rate,
+	.reset = branch_clk_reset,
+	.get_parent = branch_clk_get_parent,
+	.handoff = branch_clk_handoff,
+};
+
+struct clk_ops clk_ops_vote = {
+	.enable = local_vote_clk_enable,
+	.disable = local_vote_clk_disable,
+	.auto_off = local_vote_clk_disable,
+	.reset = local_vote_clk_reset,
+	.handoff = local_vote_clk_handoff,
+};
diff --git a/arch/arm/mach-msm/clock-local2.h b/arch/arm/mach-msm/clock-local2.h
new file mode 100644
index 0000000..547e633
--- /dev/null
+++ b/arch/arm/mach-msm/clock-local2.h
@@ -0,0 +1,178 @@
+/* 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 __ARCH_ARM_MACH_MSM_CLOCK_LOCAL_2_H
+#define __ARCH_ARM_MACH_MSM_CLOCK_LOCAL_2_H
+
+#include <linux/spinlock.h>
+#include "clock.h"
+
+/*
+ * Generic frequency-definition structs and macros
+ */
+
+/**
+ * @freq_hz: output rate
+ * @src_clk: source clock for freq_hz
+ * @m_val: M value corresponding to freq_hz
+ * @n_val: N value corresponding to freq_hz
+ * @d_val: D value corresponding to freq_hz
+ * @div_src_val: Pre divider value and source selection mux index for freq_hz
+ * @sys_vdd: Voltage level required for freq_hz
+ */
+struct clk_freq_tbl {
+	unsigned long	freq_hz;
+	struct clk	*src_clk;
+	const u32	m_val;
+	const u32	n_val;
+	const u32	d_val;
+	const u32	div_src_val;
+	const unsigned	sys_vdd;
+};
+
+#define FREQ_END	(UINT_MAX-1)
+#define F_END { .freq_hz = FREQ_END }
+
+/*
+ * Generic clock-definition struct and macros
+ */
+/**
+ * struct rcg_clk - root clock generator
+ * @cmd_rcgr_reg: command register
+ * @set_rate: function to set frequency
+ * @freq_tbl: frequency table for this RCG
+ * @current_freq: current RCG frequency
+ * @c: generic clock data
+ * @base: pointer to base address of ioremapped registers.
+ */
+struct rcg_clk {
+	const u32 cmd_rcgr_reg;
+
+	void   (*set_rate)(struct rcg_clk *, struct clk_freq_tbl *);
+
+	struct clk_freq_tbl *freq_tbl;
+	struct clk_freq_tbl *current_freq;
+	struct clk	c;
+
+	void *const __iomem *base;
+};
+
+static inline struct rcg_clk *to_rcg_clk(struct clk *clk)
+{
+	return container_of(clk, struct rcg_clk, c);
+}
+
+extern struct clk_freq_tbl rcg_dummy_freq;
+
+/**
+ * struct fixed_clk - fixed rate clock (used for crystal oscillators)
+ * @rate: output rate
+ * @c: clk
+ */
+struct fixed_clk {
+	struct clk c;
+};
+
+/**
+ * struct branch_clk - branch clock
+ * @set_rate: Set the frequency of this branch clock.
+ * @parent: clock source
+ * @c: clk
+ * @cbcr_reg: branch control register
+ * @bcr_reg: block reset register
+ * @has_sibling: true if other branches are derived from this branch's source
+ * @cur_div: current branch divider value
+ * @max_div: maximum branch divider value (if zero, no divider exists)
+ * @halt_check: halt checking type
+ * @base: pointer to base address of ioremapped registers.
+ */
+struct branch_clk {
+	void   (*set_rate)(struct branch_clk *, struct clk_freq_tbl *);
+	struct clk *parent;
+	struct clk c;
+	const u32 cbcr_reg;
+	const u32 bcr_reg;
+	int has_sibling;
+	u32 cur_div;
+	const u32 max_div;
+	const u32 halt_check;
+	void *const __iomem *base;
+};
+
+static inline struct branch_clk *to_branch_clk(struct clk *clk)
+{
+	return container_of(clk, struct branch_clk, c);
+}
+
+/**
+ * struct local_vote_clk - Voteable branch clock
+ * @c: clk
+ * @cbcr_reg: branch control register
+ * @vote_reg: voting register
+ * @en_mask: enable mask
+ * @halt_check: halt checking type
+ * @base: pointer to base address of ioremapped registers.
+ * An on/off switch with a rate derived from the parent.
+ */
+struct local_vote_clk {
+	struct clk c;
+	const u32 cbcr_reg;
+	const u32 vote_reg;
+	const u32 bcr_reg;
+	const u32 en_mask;
+	const u32 halt_check;
+	void *const __iomem *base;
+};
+
+static inline struct local_vote_clk *to_local_vote_clk(struct clk *clk)
+{
+	return container_of(clk, struct local_vote_clk, c);
+}
+
+/**
+ * struct measure_clk - for rate measurement debug use
+ * @sample_ticks: sample period in reference clock ticks
+ * @multiplier: measurement scale-up factor
+ * @divider: measurement scale-down factor
+ * @c: clk
+*/
+struct measure_clk {
+	u64 sample_ticks;
+	u32 multiplier;
+	u32 divider;
+	struct clk c;
+};
+
+static inline struct measure_clk *to_measure_clk(struct clk *clk)
+{
+	return container_of(clk, struct measure_clk, c);
+}
+
+/*
+ * Generic set-rate implementations
+ */
+void set_rate_mnd(struct rcg_clk *clk, struct clk_freq_tbl *nf);
+void set_rate_hid(struct rcg_clk *clk, struct clk_freq_tbl *nf);
+
+/*
+ * Variables from the clock-local driver
+ */
+extern spinlock_t local_clock_reg_lock;
+
+extern struct clk_ops clk_ops_rcg;
+extern struct clk_ops clk_ops_rcg_mnd;
+extern struct clk_ops clk_ops_branch;
+extern struct clk_ops clk_ops_vote;
+
+#endif /* __ARCH_ARM_MACH_MSM_COPPER_CLOCK_LOCAL_H */
+
diff --git a/arch/arm/mach-msm/clock-pcom-lookup.c b/arch/arm/mach-msm/clock-pcom-lookup.c
new file mode 100644
index 0000000..09c16c7
--- /dev/null
+++ b/arch/arm/mach-msm/clock-pcom-lookup.c
@@ -0,0 +1,516 @@
+/* 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
+ * 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 "clock.h"
+#include "clock-pll.h"
+#include "clock-pcom.h"
+#include "clock-voter.h"
+#include <linux/io.h>
+
+#include <mach/msm_iomap.h>
+#include <mach/socinfo.h>
+
+#define PLLn_MODE(n)	(MSM_CLK_CTL_BASE + 0x300 + 28 * (n))
+#define PLL4_MODE	(MSM_CLK_CTL_BASE + 0x374)
+
+static DEFINE_CLK_PCOM(adm_clk,		ADM_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(adsp_clk,	ADSP_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(ahb_m_clk,	AHB_M_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(ahb_s_clk,	AHB_S_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(cam_m_clk,	CAM_M_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(axi_rotator_clk,	AXI_ROTATOR_CLK, 0);
+static DEFINE_CLK_PCOM(ce_clk,		CE_CLK,		CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(csi0_clk,	CSI0_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(csi0_p_clk,	CSI0_P_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(csi0_vfe_clk,	CSI0_VFE_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(csi1_clk,	CSI1_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(csi1_p_clk,	CSI1_P_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(csi1_vfe_clk,	CSI1_VFE_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+
+static struct pll_shared_clk pll0_clk = {
+	.id = PLL_0,
+	.mode_reg = PLLn_MODE(0),
+	.c = {
+		.ops = &clk_ops_pll,
+		.dbg_name = "pll0_clk",
+		CLK_INIT(pll0_clk.c),
+	},
+};
+
+static struct pll_shared_clk pll1_clk = {
+	.id = PLL_1,
+	.mode_reg = PLLn_MODE(1),
+	.c = {
+		.ops = &clk_ops_pll,
+		.dbg_name = "pll1_clk",
+		CLK_INIT(pll1_clk.c),
+	},
+};
+
+static struct pll_shared_clk pll2_clk = {
+	.id = PLL_2,
+	.mode_reg = PLLn_MODE(2),
+	.c = {
+		.ops = &clk_ops_pll,
+		.dbg_name = "pll2_clk",
+		CLK_INIT(pll2_clk.c),
+	},
+};
+
+static struct pll_shared_clk pll4_clk = {
+	.id = PLL_4,
+	.mode_reg = PLL4_MODE,
+	.c = {
+		.ops = &clk_ops_pll,
+		.dbg_name = "pll4_clk",
+		CLK_INIT(pll4_clk.c),
+	},
+};
+
+static struct pcom_clk dsi_byte_clk = {
+	.id = P_DSI_BYTE_CLK,
+	.c = {
+		.ops = &clk_ops_pcom_ext_config,
+		.dbg_name = "dsi_byte_clk",
+		CLK_INIT(dsi_byte_clk.c),
+	},
+};
+
+static struct pcom_clk dsi_clk = {
+	.id = P_DSI_CLK,
+	.c = {
+		.ops = &clk_ops_pcom_ext_config,
+		.dbg_name = "dsi_clk",
+		CLK_INIT(dsi_clk.c),
+	},
+};
+
+static struct pcom_clk dsi_esc_clk = {
+	.id = P_DSI_ESC_CLK,
+	.c = {
+		.ops = &clk_ops_pcom_ext_config,
+		.dbg_name = "dsi_esc_clk",
+		CLK_INIT(dsi_esc_clk.c),
+	},
+};
+
+static struct pcom_clk dsi_pixel_clk = {
+	.id = P_DSI_PIXEL_CLK,
+	.c = {
+		.ops = &clk_ops_pcom_ext_config,
+		.dbg_name = "dsi_pixel_clk",
+		CLK_INIT(dsi_pixel_clk.c),
+	},
+};
+
+static DEFINE_CLK_PCOM(dsi_ref_clk,	DSI_REF_CLK,	0);
+static DEFINE_CLK_PCOM(ebi1_clk,	EBI1_CLK,
+		CLKFLAG_SKIP_AUTO_OFF | CLKFLAG_MIN);
+static DEFINE_CLK_PCOM(ebi2_clk,	EBI2_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(ecodec_clk,	ECODEC_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(emdh_clk,	EMDH_CLK,   CLKFLAG_MIN | CLKFLAG_MAX);
+static DEFINE_CLK_PCOM(gp_clk,		GP_CLK,		CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(grp_2d_clk,	GRP_2D_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(grp_2d_p_clk,	GRP_2D_P_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(grp_3d_clk,	GRP_3D_CLK,	0);
+static DEFINE_CLK_PCOM(grp_3d_p_clk,	GRP_3D_P_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(gsbi1_qup_clk,	GSBI1_QUP_CLK,	0);
+static DEFINE_CLK_PCOM(gsbi1_qup_p_clk,	GSBI1_QUP_P_CLK, 0);
+static DEFINE_CLK_PCOM(gsbi2_qup_clk,	GSBI2_QUP_CLK,	0);
+static DEFINE_CLK_PCOM(gsbi2_qup_p_clk,	GSBI2_QUP_P_CLK, 0);
+static DEFINE_CLK_PCOM(gsbi_clk,	GSBI_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(gsbi_p_clk,	GSBI_P_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(hdmi_clk,	HDMI_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(i2c_clk,		I2C_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(icodec_rx_clk,	ICODEC_RX_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(icodec_tx_clk,	ICODEC_TX_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(imem_clk,	IMEM_CLK,	0);
+static DEFINE_CLK_PCOM(mdc_clk,		MDC_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(mdp_clk,		MDP_CLK,	CLKFLAG_MIN);
+static DEFINE_CLK_PCOM(mdp_lcdc_pad_pclk_clk, MDP_LCDC_PAD_PCLK_CLK,
+		CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(mdp_lcdc_pclk_clk, MDP_LCDC_PCLK_CLK,
+		CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(mdp_vsync_clk,	MDP_VSYNC_CLK,	0);
+static DEFINE_CLK_PCOM(mdp_dsi_p_clk,	MDP_DSI_P_CLK,	0);
+static DEFINE_CLK_PCOM(pbus_clk,	PBUS_CLK,
+		CLKFLAG_SKIP_AUTO_OFF | CLKFLAG_MIN);
+static DEFINE_CLK_PCOM(pcm_clk,		PCM_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(pmdh_clk,	PMDH_CLK,   CLKFLAG_MIN | CLKFLAG_MAX);
+static DEFINE_CLK_PCOM(sdac_clk,	SDAC_CLK,	0);
+static DEFINE_CLK_PCOM(sdc1_clk,	SDC1_CLK,	0);
+static DEFINE_CLK_PCOM(sdc1_p_clk,	SDC1_P_CLK,	0);
+static DEFINE_CLK_PCOM(sdc2_clk,	SDC2_CLK,	0);
+static DEFINE_CLK_PCOM(sdc2_p_clk,	SDC2_P_CLK,	0);
+static DEFINE_CLK_PCOM(sdc3_clk,	SDC3_CLK,	0);
+static DEFINE_CLK_PCOM(sdc3_p_clk,	SDC3_P_CLK,	0);
+static DEFINE_CLK_PCOM(sdc4_clk,	SDC4_CLK,	0);
+static DEFINE_CLK_PCOM(sdc4_p_clk,	SDC4_P_CLK,	0);
+static DEFINE_CLK_PCOM(spi_clk,		SPI_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(tsif_clk,	TSIF_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(tsif_p_clk,	TSIF_P_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(tsif_ref_clk,	TSIF_REF_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(tv_dac_clk,	TV_DAC_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(tv_enc_clk,	TV_ENC_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(uart1_clk,	UART1_CLK,	0);
+static DEFINE_CLK_PCOM(uart1dm_clk,	UART1DM_CLK,	0);
+static DEFINE_CLK_PCOM(uart2_clk,	UART2_CLK,	0);
+static DEFINE_CLK_PCOM(uart2dm_clk,	UART2DM_CLK,	0);
+static DEFINE_CLK_PCOM(uart3_clk,	UART3_CLK,	0);
+static DEFINE_CLK_PCOM(usb_hs2_clk,	USB_HS2_CLK,	0);
+static DEFINE_CLK_PCOM(usb_hs2_p_clk,	USB_HS2_P_CLK,	0);
+static DEFINE_CLK_PCOM(usb_hs3_clk,	USB_HS3_CLK,	0);
+static DEFINE_CLK_PCOM(usb_hs3_p_clk,	USB_HS3_P_CLK,	0);
+static DEFINE_CLK_PCOM(usb_hs_clk,	USB_HS_CLK,	0);
+static DEFINE_CLK_PCOM(usb_hs_core_clk,	USB_HS_CORE_CLK, 0);
+static DEFINE_CLK_PCOM(usb_hs_p_clk,	USB_HS_P_CLK,	0);
+static DEFINE_CLK_PCOM(usb_otg_clk,	USB_OTG_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(usb_phy_clk,	USB_PHY_CLK,	CLKFLAG_SKIP_AUTO_OFF);
+static DEFINE_CLK_PCOM(vdc_clk,		VDC_CLK,	CLKFLAG_MIN);
+static DEFINE_CLK_PCOM(vfe_axi_clk,	VFE_AXI_CLK,	0);
+static DEFINE_CLK_PCOM(vfe_clk,		VFE_CLK,	0);
+static DEFINE_CLK_PCOM(vfe_mdc_clk,	VFE_MDC_CLK,	0);
+
+static DEFINE_CLK_VOTER(ebi_acpu_clk,	&ebi1_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_grp_3d_clk,	&ebi1_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_grp_2d_clk,	&ebi1_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_lcdc_clk,	&ebi1_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_mddi_clk,	&ebi1_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_tv_clk,	&ebi1_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_usb_clk,	&ebi1_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_vfe_clk,	&ebi1_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi_adm_clk,	&ebi1_clk.c, 0);
+
+static struct clk_lookup msm_clocks_7x01a[] = {
+	CLK_LOOKUP("core_clk",		adm_clk.c,	"msm_dmov"),
+	CLK_LOOKUP("adsp_clk",		adsp_clk.c,	NULL),
+	CLK_LOOKUP("ebi1_clk",		ebi1_clk.c,	NULL),
+	CLK_LOOKUP("ebi2_clk",		ebi2_clk.c,	NULL),
+	CLK_LOOKUP("ecodec_clk",	ecodec_clk.c,	NULL),
+	CLK_LOOKUP("core_clk",		emdh_clk.c,	"msm_mddi.1"),
+	CLK_LOOKUP("core_clk",		gp_clk.c,	""),
+	CLK_LOOKUP("core_clk",		grp_3d_clk.c,	"kgsl-3d0.0"),
+	CLK_LOOKUP("core_clk",		i2c_clk.c,	"msm_i2c.0"),
+	CLK_LOOKUP("icodec_rx_clk",	icodec_rx_clk.c,	NULL),
+	CLK_LOOKUP("icodec_tx_clk",	icodec_tx_clk.c,	NULL),
+	CLK_LOOKUP("mem_clk",		imem_clk.c,	NULL),
+	CLK_LOOKUP("mdc_clk",		mdc_clk.c,	NULL),
+	CLK_LOOKUP("core_clk",		pmdh_clk.c,	"mddi.0"),
+	CLK_LOOKUP("core_clk",		mdp_clk.c,	"mdp.0"),
+	CLK_LOOKUP("pbus_clk",		pbus_clk.c,	NULL),
+	CLK_LOOKUP("pcm_clk",		pcm_clk.c,	NULL),
+	CLK_LOOKUP("sdac_clk",		sdac_clk.c,	NULL),
+	CLK_LOOKUP("core_clk",		sdc1_clk.c,	"msm_sdcc.1"),
+	CLK_LOOKUP("iface_clk",		sdc1_p_clk.c,	"msm_sdcc.1"),
+	CLK_LOOKUP("core_clk",		sdc2_clk.c,	"msm_sdcc.2"),
+	CLK_LOOKUP("iface_clk",		sdc2_p_clk.c,	"msm_sdcc.2"),
+	CLK_LOOKUP("core_clk",		sdc3_clk.c,	"msm_sdcc.3"),
+	CLK_LOOKUP("iface_clk",		sdc3_p_clk.c,	"msm_sdcc.3"),
+	CLK_LOOKUP("core_clk",		sdc4_clk.c,	"msm_sdcc.4"),
+	CLK_LOOKUP("iface_clk",		sdc4_p_clk.c,	"msm_sdcc.4"),
+	CLK_LOOKUP("core_clk",		tsif_clk.c,	"msm_tsif.0"),
+	CLK_LOOKUP("ref_clk",		tsif_ref_clk.c,	"msm_tsif.0"),
+	CLK_LOOKUP("tv_dac_clk",	tv_dac_clk.c,	NULL),
+	CLK_LOOKUP("tv_enc_clk",	tv_enc_clk.c,	NULL),
+	CLK_LOOKUP("core_clk",		uart1_clk.c,	"msm_serial.0"),
+	CLK_LOOKUP("core_clk",		uart2_clk.c,	"msm_serial.1"),
+	CLK_LOOKUP("core_clk",		uart3_clk.c,	"msm_serial.2"),
+	CLK_LOOKUP("core_clk",		uart1dm_clk.c,	"msm_serial_hs.0"),
+	CLK_LOOKUP("core_clk",		uart2dm_clk.c,	"msm_serial_hs.1"),
+	CLK_LOOKUP("alt_core_clk",	usb_hs_clk.c,	"msm_otg"),
+	CLK_LOOKUP("iface_clk",		usb_hs_p_clk.c,	"msm_otg"),
+	CLK_LOOKUP("alt_core_clk",	usb_hs_clk.c,	"msm_hsusb_otg"),
+	CLK_LOOKUP("iface_clk",		usb_hs_p_clk.c,	"msm_hsusb_otg"),
+	CLK_LOOKUP("alt_core_clk",	usb_hs_clk.c,	"msm_hsusb_peripheral"),
+	CLK_LOOKUP("iface_clk",		usb_hs_p_clk.c,	"msm_hsusb_peripheral"),
+	CLK_LOOKUP("alt_core_clk",	usb_otg_clk.c,	NULL),
+	CLK_LOOKUP("vdc_clk",		vdc_clk.c,	NULL),
+	CLK_LOOKUP("vfe_clk",		vfe_clk.c,	NULL),
+	CLK_LOOKUP("vfe_mdc_clk",	vfe_mdc_clk.c,	NULL),
+};
+
+struct clock_init_data msm7x01a_clock_init_data __initdata = {
+	.table = msm_clocks_7x01a,
+	.size = ARRAY_SIZE(msm_clocks_7x01a),
+};
+
+static struct clk_lookup msm_clocks_7x27[] = {
+	CLK_LOOKUP("core_clk",		adm_clk.c,	"msm_dmov"),
+	CLK_LOOKUP("adsp_clk",		adsp_clk.c,	NULL),
+	CLK_LOOKUP("ebi1_clk",		ebi1_clk.c,	NULL),
+	CLK_LOOKUP("ebi2_clk",		ebi2_clk.c,	NULL),
+	CLK_LOOKUP("ecodec_clk",	ecodec_clk.c,	NULL),
+	CLK_LOOKUP("core_clk",		gp_clk.c,	""),
+	CLK_LOOKUP("core_clk",		grp_3d_clk.c,	"kgsl-3d0.0"),
+	CLK_LOOKUP("core_clk",		grp_3d_clk.c,	"footswitch-pcom.2"),
+	CLK_LOOKUP("iface_clk",		grp_3d_p_clk.c,	"kgsl-3d0.0"),
+	CLK_LOOKUP("core_clk",		i2c_clk.c,	"msm_i2c.0"),
+	CLK_LOOKUP("iface_clk",		grp_3d_p_clk.c,	"footswitch-pcom.2"),
+	CLK_LOOKUP("icodec_rx_clk",	icodec_rx_clk.c,	NULL),
+	CLK_LOOKUP("icodec_tx_clk",	icodec_tx_clk.c,	NULL),
+	CLK_LOOKUP("mem_clk",		imem_clk.c,	NULL),
+	CLK_LOOKUP("mdc_clk",		mdc_clk.c,	NULL),
+	CLK_LOOKUP("core_clk",		pmdh_clk.c,	"mddi.0"),
+	CLK_LOOKUP("core_clk",		mdp_clk.c,	"mdp.0"),
+	CLK_LOOKUP("mdp_clk", mdp_lcdc_pclk_clk.c, "lcdc.0"),
+	CLK_LOOKUP("lcdc_clk", mdp_lcdc_pad_pclk_clk.c, "lcdc.0"),
+	CLK_LOOKUP("vsync_clk",	mdp_vsync_clk.c,  "mdp.0"),
+	CLK_LOOKUP("pbus_clk",		pbus_clk.c,	NULL),
+	CLK_LOOKUP("pcm_clk",		pcm_clk.c,	NULL),
+	CLK_LOOKUP("sdac_clk",		sdac_clk.c,	NULL),
+	CLK_LOOKUP("core_clk",		sdc1_clk.c,	"msm_sdcc.1"),
+	CLK_LOOKUP("iface_clk",		sdc1_p_clk.c,	"msm_sdcc.1"),
+	CLK_LOOKUP("core_clk",		sdc2_clk.c,	"msm_sdcc.2"),
+	CLK_LOOKUP("iface_clk",		sdc2_p_clk.c,	"msm_sdcc.2"),
+	CLK_LOOKUP("core_clk",		sdc3_clk.c,	"msm_sdcc.3"),
+	CLK_LOOKUP("iface_clk",		sdc3_p_clk.c,	"msm_sdcc.3"),
+	CLK_LOOKUP("core_clk",		sdc4_clk.c,	"msm_sdcc.4"),
+	CLK_LOOKUP("iface_clk",		sdc4_p_clk.c,	"msm_sdcc.4"),
+	CLK_LOOKUP("core_clk",		tsif_clk.c,	"msm_tsif.0"),
+	CLK_LOOKUP("ref_clk",		tsif_ref_clk.c,	"msm_tsif.0"),
+	CLK_LOOKUP("iface_clk",		tsif_p_clk.c,	"msm_tsif.0"),
+	CLK_LOOKUP("core_clk",		uart1_clk.c,	"msm_serial.0"),
+	CLK_LOOKUP("core_clk",		uart2_clk.c,	"msm_serial.1"),
+	CLK_LOOKUP("core_clk",		uart1dm_clk.c,	"msm_serial_hs.0"),
+	CLK_LOOKUP("core_clk",		uart2dm_clk.c,	"msm_serial_hs.1"),
+	CLK_LOOKUP("alt_core_clk",	usb_hs_clk.c,	"msm_otg"),
+	CLK_LOOKUP("iface_clk",		usb_hs_p_clk.c,	"msm_otg"),
+	CLK_LOOKUP("alt_core_clk",	usb_otg_clk.c,	NULL),
+	CLK_LOOKUP("phy_clk",		usb_phy_clk.c,	"msm_otg"),
+	CLK_LOOKUP("vdc_clk",		vdc_clk.c,	NULL),
+	CLK_LOOKUP("core_clk",		vdc_clk.c,	"footswitch-pcom.7"),
+	CLK_LOOKUP("vfe_clk",		vfe_clk.c,	NULL),
+	CLK_LOOKUP("core_clk",		vfe_clk.c,	"footswitch-pcom.8"),
+	CLK_LOOKUP("vfe_mdc_clk",	vfe_mdc_clk.c,	NULL),
+
+	CLK_LOOKUP("ebi1_acpu_clk",	ebi_acpu_clk.c,	NULL),
+	CLK_LOOKUP("bus_clk",		ebi_grp_3d_clk.c, "kgsl-3d0.0"),
+	CLK_LOOKUP("mem_clk",	ebi_lcdc_clk.c,	"lcdc.0"),
+	CLK_LOOKUP("mem_clk",	ebi_mddi_clk.c,	"mddi.0"),
+	CLK_LOOKUP("core_clk",		ebi_usb_clk.c,	"msm_otg"),
+	CLK_LOOKUP("ebi1_vfe_clk",	ebi_vfe_clk.c,	NULL),
+	CLK_LOOKUP("mem_clk",		ebi_adm_clk.c,	"msm_dmov"),
+
+	CLK_LOOKUP("pll0_clk",		pll0_clk.c,	"acpu"),
+	CLK_LOOKUP("pll1_clk",		pll1_clk.c,	"acpu"),
+	CLK_LOOKUP("pll2_clk",		pll2_clk.c,	"acpu"),
+};
+
+struct clock_init_data msm7x27_clock_init_data __initdata = {
+	.table = msm_clocks_7x27,
+	.size = ARRAY_SIZE(msm_clocks_7x27),
+	.pre_init = msm_shared_pll_control_init,
+};
+
+/* Clock table for common clocks between 7627a and 7625a */
+static struct clk_lookup msm_cmn_clk_7625a_7627a[] __initdata = {
+	CLK_LOOKUP("core_clk",		adm_clk.c,	"msm_dmov"),
+	CLK_LOOKUP("adsp_clk",		adsp_clk.c,	NULL),
+	CLK_LOOKUP("master_iface_clk",		ahb_m_clk.c,	"mipi_dsi.1"),
+	CLK_LOOKUP("slave_iface_clk",		ahb_s_clk.c,	"mipi_dsi.1"),
+	CLK_LOOKUP("cam_m_clk",		cam_m_clk.c,	NULL),
+	CLK_LOOKUP("cam_clk",		cam_m_clk.c,	"0-0036"),
+	CLK_LOOKUP("cam_clk",		cam_m_clk.c,	"0-001b"),
+	CLK_LOOKUP("cam_clk",		cam_m_clk.c,	"0-0010"),
+	CLK_LOOKUP("cam_clk",		cam_m_clk.c,	"0-0078"),
+	CLK_LOOKUP("cam_clk",		cam_m_clk.c,	"0-006c"),
+	CLK_LOOKUP("csi_clk",		csi0_clk.c,	"msm_camera_ov9726.0"),
+	CLK_LOOKUP("csi_pclk",		csi0_p_clk.c,	"msm_camera_ov9726.0"),
+	CLK_LOOKUP("csi_vfe_clk",	csi0_vfe_clk.c,	"msm_camera_ov9726.0"),
+	CLK_LOOKUP("csi_clk",		csi0_clk.c,	"msm_camera_ov7692.0"),
+	CLK_LOOKUP("csi_pclk",		csi0_p_clk.c,	"msm_camera_ov7692.0"),
+	CLK_LOOKUP("csi_vfe_clk",	csi0_vfe_clk.c,	"msm_camera_ov7692.0"),
+	CLK_LOOKUP("csi_clk",		csi1_clk.c,	NULL),
+	CLK_LOOKUP("csi_pclk",		csi1_p_clk.c,	NULL),
+	CLK_LOOKUP("csi_vfe_clk",	csi1_vfe_clk.c,	NULL),
+	CLK_LOOKUP("csi_clk",		csi0_clk.c,	"msm_csic.0"),
+	CLK_LOOKUP("csi_pclk",		csi0_p_clk.c,   "msm_csic.0"),
+	CLK_LOOKUP("csi_vfe_clk",	csi0_vfe_clk.c,	"msm_csic.0"),
+	CLK_LOOKUP("csi_clk",		csi1_clk.c,	"msm_csic.1"),
+	CLK_LOOKUP("csi_pclk",		csi1_p_clk.c,	"msm_csic.1"),
+	CLK_LOOKUP("csi_vfe_clk",	csi1_vfe_clk.c,	"msm_csic.1"),
+	CLK_LOOKUP("byte_clk",	dsi_byte_clk.c,	"mipi_dsi.1"),
+	CLK_LOOKUP("core_clk",		dsi_clk.c,	"mipi_dsi.1"),
+	CLK_LOOKUP("esc_clk",	dsi_esc_clk.c,	"mipi_dsi.1"),
+	CLK_LOOKUP("pixel_clk",	dsi_pixel_clk.c, "mipi_dsi.1"),
+	CLK_LOOKUP("ref_clk",	dsi_ref_clk.c,	"mipi_dsi.1"),
+	CLK_LOOKUP("ebi1_clk",		ebi1_clk.c,	NULL),
+	CLK_LOOKUP("ebi2_clk",		ebi2_clk.c,	NULL),
+	CLK_LOOKUP("ecodec_clk",	ecodec_clk.c,	NULL),
+	CLK_LOOKUP("core_clk",		gp_clk.c,	""),
+	CLK_LOOKUP("core_clk",		grp_3d_clk.c,	"kgsl-3d0.0"),
+	CLK_LOOKUP("core_clk",		grp_3d_clk.c,	"footswitch-pcom.2"),
+	CLK_LOOKUP("iface_clk",		grp_3d_p_clk.c,	"kgsl-3d0.0"),
+	CLK_LOOKUP("iface_clk",		grp_3d_p_clk.c,	"footswitch-pcom.2"),
+	CLK_LOOKUP("core_clk",		gsbi1_qup_clk.c, "qup_i2c.0"),
+	CLK_LOOKUP("core_clk",		gsbi2_qup_clk.c, "qup_i2c.1"),
+	CLK_LOOKUP("iface_clk",		gsbi1_qup_p_clk.c, "qup_i2c.0"),
+	CLK_LOOKUP("iface_clk",		gsbi2_qup_p_clk.c, "qup_i2c.1"),
+	CLK_LOOKUP("icodec_rx_clk",	icodec_rx_clk.c, NULL),
+	CLK_LOOKUP("icodec_tx_clk",	icodec_tx_clk.c, NULL),
+	CLK_LOOKUP("mem_clk",		imem_clk.c,	NULL),
+	CLK_LOOKUP("core_clk",		pmdh_clk.c,	"mddi.0"),
+	CLK_LOOKUP("core_clk",		mdp_clk.c,	"mdp.0"),
+	CLK_LOOKUP("mdp_clk",	mdp_lcdc_pclk_clk.c, "lcdc.0"),
+	CLK_LOOKUP("lcdc_clk", mdp_lcdc_pad_pclk_clk.c, "lcdc.0"),
+	CLK_LOOKUP("vsync_clk",	mdp_vsync_clk.c,	"mdp.0"),
+	CLK_LOOKUP("mdp_clk",	mdp_dsi_p_clk.c,	"mipi_dsi.1"),
+	CLK_LOOKUP("pbus_clk",		pbus_clk.c,	NULL),
+	CLK_LOOKUP("pcm_clk",		pcm_clk.c,	NULL),
+	CLK_LOOKUP("sdac_clk",		sdac_clk.c,	NULL),
+	CLK_LOOKUP("core_clk",		sdc1_clk.c,	"msm_sdcc.1"),
+	CLK_LOOKUP("iface_clk",		sdc1_p_clk.c,	"msm_sdcc.1"),
+	CLK_LOOKUP("core_clk",		sdc2_clk.c,	"msm_sdcc.2"),
+	CLK_LOOKUP("iface_clk",		sdc2_p_clk.c,	"msm_sdcc.2"),
+	CLK_LOOKUP("core_clk",		sdc3_clk.c,	"msm_sdcc.3"),
+	CLK_LOOKUP("iface_clk",		sdc3_p_clk.c,	"msm_sdcc.3"),
+	CLK_LOOKUP("core_clk",		sdc4_clk.c,	"msm_sdcc.4"),
+	CLK_LOOKUP("iface_clk",		sdc4_p_clk.c,	"msm_sdcc.4"),
+	CLK_LOOKUP("ref_clk",		tsif_ref_clk.c,	"msm_tsif.0"),
+	CLK_LOOKUP("iface_clk",		tsif_p_clk.c,	"msm_tsif.0"),
+	CLK_LOOKUP("core_clk",		uart1_clk.c,	"msm_serial.0"),
+	CLK_LOOKUP("core_clk",		uart2_clk.c,	"msm_serial.1"),
+	CLK_LOOKUP("core_clk",		uart1dm_clk.c,	"msm_serial_hs.0"),
+	CLK_LOOKUP("core_clk",		uart2dm_clk.c,	"msm_serial_hsl.0"),
+	CLK_LOOKUP("core_clk",		usb_hs_core_clk.c, "msm_otg"),
+	CLK_LOOKUP("alt_core_clk",	usb_hs_clk.c,	"msm_otg"),
+	CLK_LOOKUP("iface_clk",		usb_hs_p_clk.c,	"msm_otg"),
+	CLK_LOOKUP("phy_clk",		usb_phy_clk.c,	"msm_otg"),
+	CLK_LOOKUP("alt_core_clk",	usb_hs2_clk.c,	"msm_hsusb_host.0"),
+	CLK_LOOKUP("vdc_clk",		vdc_clk.c,	NULL),
+	CLK_LOOKUP("core_clk",		vdc_clk.c,	"footswitch-pcom.7"),
+	CLK_LOOKUP("vfe_clk",		vfe_clk.c,	NULL),
+	CLK_LOOKUP("vfe_clk",		vfe_clk.c,	"msm_vfe.0"),
+	CLK_LOOKUP("core_clk",		vfe_clk.c,	"footswitch-pcom.8"),
+	CLK_LOOKUP("vfe_mdc_clk",	vfe_mdc_clk.c,	NULL),
+
+	CLK_LOOKUP("ebi1_acpu_clk",	ebi_acpu_clk.c,	NULL),
+	CLK_LOOKUP("bus_clk",		ebi_grp_3d_clk.c, "kgsl-3d0.0"),
+	CLK_LOOKUP("mem_clk",	ebi_lcdc_clk.c,	"lcdc.0"),
+	CLK_LOOKUP("mem_clk",	ebi_lcdc_clk.c,	"mipi_dsi.1"),
+	CLK_LOOKUP("mem_clk",	ebi_mddi_clk.c,	"mddi.0"),
+	CLK_LOOKUP("ebi1_vfe_clk",	ebi_vfe_clk.c,	NULL),
+	CLK_LOOKUP("mem_clk",		ebi_adm_clk.c,	"msm_dmov"),
+
+	CLK_LOOKUP("pll0_clk",		pll0_clk.c,	"acpu"),
+	CLK_LOOKUP("pll1_clk",		pll1_clk.c,	"acpu"),
+	CLK_LOOKUP("pll2_clk",		pll2_clk.c,	"acpu"),
+
+};
+
+/* PLL 4 clock is available for 7627a target. */
+static struct clk_lookup msm_clk_7627a[] __initdata = {
+	CLK_LOOKUP("pll4_clk",		pll4_clk.c,	"acpu"),
+};
+
+static struct clk_lookup msm_clk_7627a_7625a[ARRAY_SIZE(msm_cmn_clk_7625a_7627a)
+					+ ARRAY_SIZE(msm_clk_7627a)];
+
+static void __init msm7627a_clock_pre_init(void)
+{
+	int size = ARRAY_SIZE(msm_cmn_clk_7625a_7627a);
+
+	/* Intialize shared PLL control structure */
+	msm_shared_pll_control_init();
+
+	memcpy(&msm_clk_7627a_7625a, &msm_cmn_clk_7625a_7627a,
+					sizeof(msm_cmn_clk_7625a_7627a));
+	if (!cpu_is_msm7x25a()) {
+		memcpy(&msm_clk_7627a_7625a[size],
+				&msm_clk_7627a, sizeof(msm_clk_7627a));
+		size += ARRAY_SIZE(msm_clk_7627a);
+	}
+	msm7x27a_clock_init_data.size = size;
+}
+
+struct clock_init_data msm7x27a_clock_init_data __initdata = {
+	.table = msm_clk_7627a_7625a,
+	.pre_init = msm7627a_clock_pre_init,
+};
+
+static struct clk_lookup msm_clocks_8x50[] = {
+	CLK_LOOKUP("core_clk",		adm_clk.c,	"msm_dmov"),
+	CLK_LOOKUP("core_clk",		ce_clk.c,	"qce.0"),
+	CLK_LOOKUP("ebi1_clk",		ebi1_clk.c,	NULL),
+	CLK_LOOKUP("ebi2_clk",		ebi2_clk.c,	NULL),
+	CLK_LOOKUP("ecodec_clk",	ecodec_clk.c,	NULL),
+	CLK_LOOKUP("core_clk",		emdh_clk.c,	"msm_mddi.1"),
+	CLK_LOOKUP("core_clk",		gp_clk.c,	""),
+	CLK_LOOKUP("core_clk",		grp_3d_clk.c,	"kgsl-3d0.0"),
+	CLK_LOOKUP("core_clk",		i2c_clk.c,	"msm_i2c.0"),
+	CLK_LOOKUP("icodec_rx_clk",	icodec_rx_clk.c,	NULL),
+	CLK_LOOKUP("icodec_tx_clk",	icodec_tx_clk.c,	NULL),
+	CLK_LOOKUP("mem_clk",		imem_clk.c,	NULL),
+	CLK_LOOKUP("mdc_clk",		mdc_clk.c,	NULL),
+	CLK_LOOKUP("core_clk",		pmdh_clk.c,	"mddi.0"),
+	CLK_LOOKUP("core_clk",		mdp_clk.c,	"mdp.0"),
+	CLK_LOOKUP("mdp_clk", mdp_lcdc_pclk_clk.c, "lcdc.0"),
+	CLK_LOOKUP("lcdc_clk", mdp_lcdc_pad_pclk_clk.c, "lcdc.0"),
+	CLK_LOOKUP("vsync_clk",	mdp_vsync_clk.c,	"mdp.0"),
+	CLK_LOOKUP("pbus_clk",		pbus_clk.c,	NULL),
+	CLK_LOOKUP("pcm_clk",		pcm_clk.c,	NULL),
+	CLK_LOOKUP("sdac_clk",		sdac_clk.c,	NULL),
+	CLK_LOOKUP("core_clk",		sdc1_clk.c,	"msm_sdcc.1"),
+	CLK_LOOKUP("iface_clk",		sdc1_p_clk.c,	"msm_sdcc.1"),
+	CLK_LOOKUP("core_clk",		sdc2_clk.c,	"msm_sdcc.2"),
+	CLK_LOOKUP("iface_clk",		sdc2_p_clk.c,	"msm_sdcc.2"),
+	CLK_LOOKUP("core_clk",		sdc3_clk.c,	"msm_sdcc.3"),
+	CLK_LOOKUP("iface_clk",		sdc3_p_clk.c,	"msm_sdcc.3"),
+	CLK_LOOKUP("core_clk",		sdc4_clk.c,	"msm_sdcc.4"),
+	CLK_LOOKUP("iface_clk",		sdc4_p_clk.c,	"msm_sdcc.4"),
+	CLK_LOOKUP("core_clk",		spi_clk.c,	"spi_qsd.0"),
+	CLK_DUMMY("iface_clk",		SPI_P_CLK,	"spi_qsd.0", 0),
+	CLK_LOOKUP("core_clk",		tsif_clk.c,	"msm_tsif.0"),
+	CLK_LOOKUP("ref_clk",		tsif_ref_clk.c,	"msm_tsif.0"),
+	CLK_LOOKUP("tv_dac_clk",	tv_dac_clk.c,	NULL),
+	CLK_LOOKUP("tv_enc_clk",	tv_enc_clk.c,	NULL),
+	CLK_LOOKUP("core_clk",		uart1_clk.c,	"msm_serial.0"),
+	CLK_LOOKUP("core_clk",		uart2_clk.c,	"msm_serial.1"),
+	CLK_LOOKUP("core_clk",		uart3_clk.c,	"msm_serial.2"),
+	CLK_LOOKUP("core_clk",		uart1dm_clk.c,	"msm_serial_hs.0"),
+	CLK_LOOKUP("core_clk",		uart2dm_clk.c,	"msm_serial_hs.1"),
+	CLK_LOOKUP("alt_core_clk",	usb_hs_clk.c,	"msm_otg"),
+	CLK_LOOKUP("iface_clk",		usb_hs_p_clk.c,	"msm_otg"),
+	CLK_LOOKUP("alt_core_clk",	usb_otg_clk.c,	NULL),
+	CLK_LOOKUP("vdc_clk",		vdc_clk.c,	NULL),
+	CLK_LOOKUP("vfe_clk",		vfe_clk.c,	NULL),
+	CLK_LOOKUP("vfe_mdc_clk",	vfe_mdc_clk.c,	NULL),
+	CLK_LOOKUP("vfe_axi_clk",	vfe_axi_clk.c,	NULL),
+	CLK_LOOKUP("alt_core_clk",	usb_hs2_clk.c,	 "msm_hsusb_host.0"),
+	CLK_LOOKUP("iface_clk",		usb_hs2_p_clk.c, "msm_hsusb_host.0"),
+	CLK_LOOKUP("alt_core_clk",	usb_hs3_clk.c,	 ""),
+	CLK_LOOKUP("iface_clk",		usb_hs3_p_clk.c, ""),
+	CLK_LOOKUP("phy_clk",		usb_phy_clk.c,	 "msm_otg"),
+
+	CLK_LOOKUP("ebi1_acpu_clk",	ebi_acpu_clk.c,	NULL),
+	CLK_LOOKUP("bus_clk",		ebi_grp_3d_clk.c, "kgsl-3d0.0"),
+	CLK_LOOKUP("bus_clk",		ebi_grp_2d_clk.c, "kgsl-2d0.0"),
+	CLK_LOOKUP("mem_clk",	ebi_lcdc_clk.c,	"lcdc.0"),
+	CLK_LOOKUP("mem_clk",	ebi_lcdc_clk.c,	"mipi_dsi.1"),
+	CLK_LOOKUP("mem_clk",	ebi_mddi_clk.c,	"mddi.0"),
+	CLK_LOOKUP("mem_clk",	ebi_tv_clk.c,	"tvenc.0"),
+	CLK_LOOKUP("core_clk",		ebi_usb_clk.c,	"msm_otg"),
+	CLK_LOOKUP("core_clk",		ebi_usb_clk.c,	"msm_hsusb_host.0"),
+	CLK_LOOKUP("ebi1_vfe_clk",	ebi_vfe_clk.c,	NULL),
+	CLK_LOOKUP("mem_clk",		ebi_adm_clk.c,	"msm_dmov"),
+
+	CLK_LOOKUP("iface_clk",		grp_3d_p_clk.c,	"kgsl-3d0.0"),
+	CLK_LOOKUP("core_clk",		grp_2d_clk.c,	"kgsl-2d0.0"),
+	CLK_LOOKUP("iface_clk",		grp_2d_p_clk.c,	"kgsl-2d0.0"),
+	CLK_LOOKUP("core_clk",		gsbi_clk.c,	"qup_i2c.4"),
+	CLK_LOOKUP("iface_clk",		gsbi_p_clk.c,	"qup_i2c.4"),
+};
+
+struct clock_init_data qds8x50_clock_init_data __initdata = {
+	.table = msm_clocks_8x50,
+	.size = ARRAY_SIZE(msm_clocks_8x50),
+};
diff --git a/arch/arm/mach-msm/clock-pcom.c b/arch/arm/mach-msm/clock-pcom.c
index 63b7113..02c8765 100644
--- a/arch/arm/mach-msm/clock-pcom.c
+++ b/arch/arm/mach-msm/clock-pcom.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2007-2011, Code Aurora Forum. 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
@@ -13,29 +13,43 @@
  *
  */
 
+#include <linux/kernel.h>
 #include <linux/err.h>
-#include <linux/ctype.h>
-#include <linux/stddef.h>
-#include <mach/clk.h>
 
-#include "proc_comm.h"
+#include <mach/clk.h>
+#include <mach/socinfo.h>
+#include <mach/proc_comm.h>
+
 #include "clock.h"
 #include "clock-pcom.h"
 
 /*
  * glue for the proc_comm interface
  */
-int pc_clk_enable(unsigned id)
+static int pc_clk_enable(struct clk *clk)
 {
-	int rc = msm_proc_comm(PCOM_CLKCTL_RPC_ENABLE, &id, NULL);
+	int rc;
+	int id = to_pcom_clk(clk)->id;
+
+	/* Ignore clocks that are always on */
+	if (id == P_EBI1_CLK || id == P_EBI1_FIXED_CLK)
+		return 0;
+
+	rc = msm_proc_comm(PCOM_CLKCTL_RPC_ENABLE, &id, NULL);
 	if (rc < 0)
 		return rc;
 	else
 		return (int)id < 0 ? -EINVAL : 0;
 }
 
-void pc_clk_disable(unsigned id)
+static void pc_clk_disable(struct clk *clk)
 {
+	int id = to_pcom_clk(clk)->id;
+
+	/* Ignore clocks that are always on */
+	if (id == P_EBI1_CLK || id == P_EBI1_FIXED_CLK)
+		return;
+
 	msm_proc_comm(PCOM_CLKCTL_RPC_DISABLE, &id, NULL);
 }
 
@@ -54,39 +68,65 @@
 		return (int)id < 0 ? -EINVAL : 0;
 }
 
-int pc_clk_set_rate(unsigned id, unsigned rate)
+static int pc_reset(struct clk *clk, enum clk_reset_action action)
+{
+	int id = to_pcom_clk(clk)->id;
+	return pc_clk_reset(id, action);
+}
+
+static int _pc_clk_set_rate(struct clk *clk, unsigned long rate)
 {
 	/* The rate _might_ be rounded off to the nearest KHz value by the
 	 * remote function. So a return value of 0 doesn't necessarily mean
 	 * that the exact rate was set successfully.
 	 */
-	int rc = msm_proc_comm(PCOM_CLKCTL_RPC_SET_RATE, &id, &rate);
+	unsigned r = rate;
+	int id = to_pcom_clk(clk)->id;
+	int rc = msm_proc_comm(PCOM_CLKCTL_RPC_SET_RATE, &id, &r);
 	if (rc < 0)
 		return rc;
 	else
 		return (int)id < 0 ? -EINVAL : 0;
 }
 
-int pc_clk_set_min_rate(unsigned id, unsigned rate)
+static int _pc_clk_set_min_rate(struct clk *clk, unsigned long rate)
 {
-	int rc = msm_proc_comm(PCOM_CLKCTL_RPC_MIN_RATE, &id, &rate);
+	int rc;
+	int id = to_pcom_clk(clk)->id;
+	bool ignore_error = (cpu_is_msm7x27() && id == P_EBI1_CLK &&
+				rate >= INT_MAX);
+	unsigned r = rate;
+	rc = msm_proc_comm(PCOM_CLKCTL_RPC_MIN_RATE, &id, &r);
+	if (rc < 0)
+		return rc;
+	else if (ignore_error)
+		return 0;
+	else
+		return (int)id < 0 ? -EINVAL : 0;
+}
+
+static int pc_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->flags & CLKFLAG_MIN)
+		return _pc_clk_set_min_rate(clk, rate);
+	else
+		return _pc_clk_set_rate(clk, rate);
+}
+
+static int pc_clk_set_max_rate(struct clk *clk, unsigned long rate)
+{
+	int id = to_pcom_clk(clk)->id;
+	unsigned r = rate;
+	int rc = msm_proc_comm(PCOM_CLKCTL_RPC_MAX_RATE, &id, &r);
 	if (rc < 0)
 		return rc;
 	else
 		return (int)id < 0 ? -EINVAL : 0;
 }
 
-int pc_clk_set_max_rate(unsigned id, unsigned rate)
+static int pc_clk_set_flags(struct clk *clk, unsigned flags)
 {
-	int rc = msm_proc_comm(PCOM_CLKCTL_RPC_MAX_RATE, &id, &rate);
-	if (rc < 0)
-		return rc;
-	else
-		return (int)id < 0 ? -EINVAL : 0;
-}
-
-int pc_clk_set_flags(unsigned id, unsigned flags)
-{
+	int id = to_pcom_clk(clk)->id;
 	int rc = msm_proc_comm(PCOM_CLKCTL_RPC_SET_FLAGS, &id, &flags);
 	if (rc < 0)
 		return rc;
@@ -94,45 +134,86 @@
 		return (int)id < 0 ? -EINVAL : 0;
 }
 
-unsigned pc_clk_get_rate(unsigned id)
+static int pc_clk_set_ext_config(struct clk *clk, unsigned long config)
 {
+	int id = to_pcom_clk(clk)->id;
+	unsigned c = config;
+	int rc = msm_proc_comm(PCOM_CLKCTL_RPC_SET_EXT_CONFIG, &id, &c);
+	if (rc < 0)
+		return rc;
+	else
+		return (int)id < 0 ? -EINVAL : 0;
+}
+
+static unsigned long pc_clk_get_rate(struct clk *clk)
+{
+	int id = to_pcom_clk(clk)->id;
 	if (msm_proc_comm(PCOM_CLKCTL_RPC_RATE, &id, NULL))
 		return 0;
 	else
 		return id;
 }
 
-unsigned pc_clk_is_enabled(unsigned id)
+static int pc_clk_is_enabled(struct clk *clk)
 {
+	int id = to_pcom_clk(clk)->id;
 	if (msm_proc_comm(PCOM_CLKCTL_RPC_ENABLED, &id, NULL))
 		return 0;
 	else
 		return id;
 }
 
-long pc_clk_round_rate(unsigned id, unsigned rate)
+static long pc_clk_round_rate(struct clk *clk, unsigned long rate)
 {
 
 	/* Not really supported; pc_clk_set_rate() does rounding on it's own. */
 	return rate;
 }
 
-static bool pc_clk_is_local(unsigned id)
+static bool pc_clk_is_local(struct clk *clk)
 {
 	return false;
 }
 
+static enum handoff pc_clk_handoff(struct clk *clk)
+{
+	/*
+	 * Handoff clock state only since querying and caching the rate here
+	 * would incur more overhead than it would ever save.
+	 */
+	if (pc_clk_is_enabled(clk))
+		return HANDOFF_ENABLED_CLK;
+
+	return HANDOFF_DISABLED_CLK;
+}
+
 struct clk_ops clk_ops_pcom = {
 	.enable = pc_clk_enable,
 	.disable = pc_clk_disable,
 	.auto_off = pc_clk_disable,
-	.reset = pc_clk_reset,
+	.reset = pc_reset,
 	.set_rate = pc_clk_set_rate,
-	.set_min_rate = pc_clk_set_min_rate,
 	.set_max_rate = pc_clk_set_max_rate,
 	.set_flags = pc_clk_set_flags,
 	.get_rate = pc_clk_get_rate,
 	.is_enabled = pc_clk_is_enabled,
 	.round_rate = pc_clk_round_rate,
 	.is_local = pc_clk_is_local,
+	.handoff = pc_clk_handoff,
 };
+
+struct clk_ops clk_ops_pcom_ext_config = {
+	.enable = pc_clk_enable,
+	.disable = pc_clk_disable,
+	.auto_off = pc_clk_disable,
+	.reset = pc_reset,
+	.set_rate = pc_clk_set_ext_config,
+	.set_max_rate = pc_clk_set_max_rate,
+	.set_flags = pc_clk_set_flags,
+	.get_rate = pc_clk_get_rate,
+	.is_enabled = pc_clk_is_enabled,
+	.round_rate = pc_clk_round_rate,
+	.is_local = pc_clk_is_local,
+	.handoff = pc_clk_handoff,
+};
+
diff --git a/arch/arm/mach-msm/clock-pcom.h b/arch/arm/mach-msm/clock-pcom.h
index 974d003..723c53c 100644
--- a/arch/arm/mach-msm/clock-pcom.h
+++ b/arch/arm/mach-msm/clock-pcom.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -117,24 +117,54 @@
 #define P_GSBI_P_CLK		99
 #define P_CE_CLK		100 /* Crypto engine */
 #define P_CODEC_SSBI_CLK	101
+#define P_TCXO_DIV4_CLK		102
+#define P_GSBI1_QUP_CLK		103
+#define P_GSBI2_QUP_CLK		104
+#define P_GSBI1_QUP_P_CLK	105
+#define P_GSBI2_QUP_P_CLK	106
+#define P_DSI_CLK		107
+#define P_DSI_ESC_CLK		108
+#define P_DSI_PIXEL_CLK		109
+#define P_DSI_BYTE_CLK		110
+#define P_EBI1_FIXED_CLK	111 /* Not dropped during power-collapse */
+#define P_DSI_REF_CLK		112
+#define P_MDP_DSI_P_CLK		113
+#define P_AHB_M_CLK		114
+#define P_AHB_S_CLK		115
 
-#define P_NR_CLKS		102
+#define P_NR_CLKS		116
+
+extern int pc_clk_reset(unsigned id, enum clk_reset_action action);
 
 struct clk_ops;
 extern struct clk_ops clk_ops_pcom;
+extern struct clk_ops clk_ops_pcom_div2;
+extern struct clk_ops clk_ops_pcom_ext_config;
 
-int pc_clk_reset(unsigned id, enum clk_reset_action action);
+/*
+ * struct pcom_clk - proc_comm controlled clock
+ * @id: proc_comm identifier
+ * @c:
+ */
+struct pcom_clk {
+	unsigned id;
+	struct clk c;
+};
 
-#define CLK_PCOM(clk_name, clk_id, clk_dev, clk_flags) {	\
-	.con_id = clk_name, \
-	.dev_id = clk_dev, \
-	.clk = &(struct clk){ \
+static inline struct pcom_clk *to_pcom_clk(struct clk *clk)
+{
+	return container_of(clk, struct pcom_clk, c);
+}
+
+#define DEFINE_CLK_PCOM(clk_name, clk_id, clk_flags) \
+	struct pcom_clk clk_name = { \
 		.id = P_##clk_id, \
-		.remote_id = P_##clk_id, \
-		.ops = &clk_ops_pcom, \
-		.flags = clk_flags, \
-		.dbg_name = #clk_id, \
-	}, \
+		.c = { \
+			.ops = &clk_ops_pcom, \
+			.flags = clk_flags, \
+			.dbg_name = #clk_id, \
+			CLK_INIT(clk_name.c), \
+		}, \
 	}
 
 #endif
diff --git a/arch/arm/mach-msm/clock-pll.c b/arch/arm/mach-msm/clock-pll.c
new file mode 100644
index 0000000..d839911
--- /dev/null
+++ b/arch/arm/mach-msm/clock-pll.c
@@ -0,0 +1,521 @@
+/*
+ * 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/kernel.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/remote_spinlock.h>
+
+#include <mach/scm-io.h>
+#include <mach/msm_iomap.h>
+
+#include "clock.h"
+#include "clock-pll.h"
+#include "smd_private.h"
+
+#ifdef CONFIG_MSM_SECURE_IO
+#undef readl_relaxed
+#undef writel_relaxed
+#define readl_relaxed secure_readl
+#define writel_relaxed secure_writel
+#endif
+
+#define PLL_OUTCTRL BIT(0)
+#define PLL_BYPASSNL BIT(1)
+#define PLL_RESET_N BIT(2)
+#define PLL_MODE_MASK BM(3, 0)
+
+#define PLL_EN_REG(x) ((x)->base ? (*(x)->base + (u32)((x)->en_reg)) : \
+				((x)->en_reg))
+#define PLL_STATUS_REG(x) ((x)->base ? (*(x)->base + (u32)((x)->status_reg)) : \
+				((x)->status_reg))
+#define PLL_MODE_REG(x) ((x)->base ? (*(x)->base + (u32)((x)->mode_reg)) : \
+				((x)->mode_reg))
+#define PLL_L_REG(x) ((x)->base ? (*(x)->base + (u32)((x)->l_reg)) : \
+				((x)->l_reg))
+#define PLL_M_REG(x) ((x)->base ? (*(x)->base + (u32)((x)->m_reg)) : \
+				((x)->m_reg))
+#define PLL_N_REG(x) ((x)->base ? (*(x)->base + (u32)((x)->n_reg)) : \
+				((x)->n_reg))
+#define PLL_CONFIG_REG(x) ((x)->base ? (*(x)->base + (u32)((x)->config_reg)) : \
+				((x)->config_reg))
+
+static DEFINE_SPINLOCK(pll_reg_lock);
+
+#define ENABLE_WAIT_MAX_LOOPS 200
+
+int pll_vote_clk_enable(struct clk *clk)
+{
+	u32 ena, count;
+	unsigned long flags;
+	struct pll_vote_clk *pll = to_pll_vote_clk(clk);
+
+	spin_lock_irqsave(&pll_reg_lock, flags);
+	ena = readl_relaxed(PLL_EN_REG(pll));
+	ena |= pll->en_mask;
+	writel_relaxed(ena, PLL_EN_REG(pll));
+	spin_unlock_irqrestore(&pll_reg_lock, flags);
+
+	/*
+	 * Use a memory barrier since some PLL status registers are
+	 * not within the same 1K segment as the voting registers.
+	 */
+	mb();
+
+	/* Wait for pll to enable. */
+	for (count = ENABLE_WAIT_MAX_LOOPS; count > 0; count--) {
+		if (readl_relaxed(PLL_STATUS_REG(pll)) & pll->status_mask)
+			return 0;
+		udelay(1);
+	}
+
+	WARN("PLL %s didn't enable after voting for it!\n", clk->dbg_name);
+
+	return -ETIMEDOUT;
+}
+
+void pll_vote_clk_disable(struct clk *clk)
+{
+	u32 ena;
+	unsigned long flags;
+	struct pll_vote_clk *pll = to_pll_vote_clk(clk);
+
+	spin_lock_irqsave(&pll_reg_lock, flags);
+	ena = readl_relaxed(PLL_EN_REG(pll));
+	ena &= ~(pll->en_mask);
+	writel_relaxed(ena, PLL_EN_REG(pll));
+	spin_unlock_irqrestore(&pll_reg_lock, flags);
+}
+
+struct clk *pll_vote_clk_get_parent(struct clk *clk)
+{
+	struct pll_vote_clk *pll = to_pll_vote_clk(clk);
+	return pll->parent;
+}
+
+int pll_vote_clk_is_enabled(struct clk *clk)
+{
+	struct pll_vote_clk *pll = to_pll_vote_clk(clk);
+	return !!(readl_relaxed(PLL_STATUS_REG(pll)) & pll->status_mask);
+}
+
+static enum handoff pll_vote_clk_handoff(struct clk *clk)
+{
+	struct pll_vote_clk *pll = to_pll_vote_clk(clk);
+	if (readl_relaxed(PLL_EN_REG(pll)) & pll->en_mask)
+		return HANDOFF_ENABLED_CLK;
+
+	return HANDOFF_DISABLED_CLK;
+}
+
+struct clk_ops clk_ops_pll_vote = {
+	.enable = pll_vote_clk_enable,
+	.disable = pll_vote_clk_disable,
+	.auto_off = pll_vote_clk_disable,
+	.is_enabled = pll_vote_clk_is_enabled,
+	.get_parent = pll_vote_clk_get_parent,
+	.handoff = pll_vote_clk_handoff,
+};
+
+static void __pll_clk_enable_reg(void __iomem *mode_reg)
+{
+	u32 mode = readl_relaxed(mode_reg);
+	/* Disable PLL bypass mode. */
+	mode |= PLL_BYPASSNL;
+	writel_relaxed(mode, mode_reg);
+
+	/*
+	 * H/W requires a 5us delay between disabling the bypass and
+	 * de-asserting the reset. Delay 10us just to be safe.
+	 */
+	mb();
+	udelay(10);
+
+	/* De-assert active-low PLL reset. */
+	mode |= PLL_RESET_N;
+	writel_relaxed(mode, mode_reg);
+
+	/* Wait until PLL is locked. */
+	mb();
+	udelay(50);
+
+	/* Enable PLL output. */
+	mode |= PLL_OUTCTRL;
+	writel_relaxed(mode, mode_reg);
+
+	/* Ensure that the write above goes through before returning. */
+	mb();
+}
+
+static int local_pll_clk_enable(struct clk *clk)
+{
+	unsigned long flags;
+	struct pll_clk *pll = to_pll_clk(clk);
+
+	spin_lock_irqsave(&pll_reg_lock, flags);
+	__pll_clk_enable_reg(PLL_MODE_REG(pll));
+	spin_unlock_irqrestore(&pll_reg_lock, flags);
+
+	return 0;
+}
+
+static void __pll_clk_disable_reg(void __iomem *mode_reg)
+{
+	u32 mode = readl_relaxed(mode_reg);
+	mode &= ~PLL_MODE_MASK;
+	writel_relaxed(mode, mode_reg);
+}
+
+static void local_pll_clk_disable(struct clk *clk)
+{
+	unsigned long flags;
+	struct pll_clk *pll = to_pll_clk(clk);
+
+	/*
+	 * Disable the PLL output, disable test mode, enable
+	 * the bypass mode, and assert the reset.
+	 */
+	spin_lock_irqsave(&pll_reg_lock, flags);
+	__pll_clk_disable_reg(PLL_MODE_REG(pll));
+	spin_unlock_irqrestore(&pll_reg_lock, flags);
+}
+
+static enum handoff local_pll_clk_handoff(struct clk *clk)
+{
+	struct pll_clk *pll = to_pll_clk(clk);
+	u32 mode = readl_relaxed(PLL_MODE_REG(pll));
+	u32 mask = PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL;
+
+	if ((mode & mask) == mask)
+		return HANDOFF_ENABLED_CLK;
+
+	return HANDOFF_DISABLED_CLK;
+}
+
+static struct clk *local_pll_clk_get_parent(struct clk *clk)
+{
+	struct pll_clk *pll = to_pll_clk(clk);
+	return pll->parent;
+}
+
+int sr_pll_clk_enable(struct clk *clk)
+{
+	u32 mode;
+	unsigned long flags;
+	struct pll_clk *pll = to_pll_clk(clk);
+
+	spin_lock_irqsave(&pll_reg_lock, flags);
+	mode = readl_relaxed(PLL_MODE_REG(pll));
+	/* De-assert active-low PLL reset. */
+	mode |= PLL_RESET_N;
+	writel_relaxed(mode, PLL_MODE_REG(pll));
+
+	/*
+	 * H/W requires a 5us delay between disabling the bypass and
+	 * de-asserting the reset. Delay 10us just to be safe.
+	 */
+	mb();
+	udelay(10);
+
+	/* Disable PLL bypass mode. */
+	mode |= PLL_BYPASSNL;
+	writel_relaxed(mode, PLL_MODE_REG(pll));
+
+	/* Wait until PLL is locked. */
+	mb();
+	udelay(60);
+
+	/* Enable PLL output. */
+	mode |= PLL_OUTCTRL;
+	writel_relaxed(mode, PLL_MODE_REG(pll));
+
+	/* Ensure that the write above goes through before returning. */
+	mb();
+
+	spin_unlock_irqrestore(&pll_reg_lock, flags);
+
+	return 0;
+}
+
+#define PLL_LOCKED_BIT BIT(16)
+
+int copper_pll_clk_enable(struct clk *clk)
+{
+	unsigned long flags;
+	struct pll_clk *pll = to_pll_clk(clk);
+	u32 count, mode;
+	int ret = 0;
+
+	spin_lock_irqsave(&pll_reg_lock, flags);
+	mode = readl_relaxed(PLL_MODE_REG(pll));
+	/* Disable PLL bypass mode. */
+	mode |= PLL_BYPASSNL;
+	writel_relaxed(mode, PLL_MODE_REG(pll));
+
+	/*
+	 * H/W requires a 5us delay between disabling the bypass and
+	 * de-asserting the reset. Delay 10us just to be safe.
+	 */
+	mb();
+	udelay(10);
+
+	/* De-assert active-low PLL reset. */
+	mode |= PLL_RESET_N;
+	writel_relaxed(mode, PLL_MODE_REG(pll));
+
+	/* Wait for pll to enable. */
+	for (count = ENABLE_WAIT_MAX_LOOPS; count > 0; count--) {
+		if (readl_relaxed(PLL_STATUS_REG(pll)) & PLL_LOCKED_BIT)
+			break;
+		udelay(1);
+	}
+
+	if (!(readl_relaxed(PLL_STATUS_REG(pll)) & PLL_LOCKED_BIT)) {
+		WARN("PLL %s didn't lock after enabling it!\n", clk->dbg_name);
+		ret = -ETIMEDOUT;
+		goto out;
+	}
+
+	/* Enable PLL output. */
+	mode |= PLL_OUTCTRL;
+	writel_relaxed(mode, PLL_MODE_REG(pll));
+
+	/* Ensure the write above goes through before returning. */
+	mb();
+
+out:
+	spin_unlock_irqrestore(&pll_reg_lock, flags);
+	return ret;
+}
+
+struct clk_ops clk_ops_local_pll = {
+	.enable = local_pll_clk_enable,
+	.disable = local_pll_clk_disable,
+	.auto_off = local_pll_clk_disable,
+	.handoff = local_pll_clk_handoff,
+	.get_parent = local_pll_clk_get_parent,
+};
+
+struct pll_rate {
+	unsigned int lvalue;
+	unsigned long rate;
+};
+
+static struct pll_rate pll_l_rate[] = {
+	{10, 196000000},
+	{12, 245760000},
+	{30, 589820000},
+	{38, 737280000},
+	{41, 800000000},
+	{50, 960000000},
+	{52, 1008000000},
+	{60, 1152000000},
+	{62, 1200000000},
+	{63, 1209600000},
+	{0, 0},
+};
+
+#define PLL_BASE	7
+
+struct shared_pll_control {
+	uint32_t	version;
+	struct {
+		/*
+		 * Denotes if the PLL is ON. Technically, this can be read
+		 * directly from the PLL registers, but this feild is here,
+		 * so let's use it.
+		 */
+		uint32_t	on;
+		/*
+		 * One bit for each processor core. The application processor
+		 * is allocated bit position 1. All other bits should be
+		 * considered as votes from other processors.
+		 */
+		uint32_t	votes;
+	} pll[PLL_BASE + PLL_END];
+};
+
+static remote_spinlock_t pll_lock;
+static struct shared_pll_control *pll_control;
+
+void __init msm_shared_pll_control_init(void)
+{
+#define PLL_REMOTE_SPINLOCK_ID "S:7"
+	unsigned smem_size;
+
+	remote_spin_lock_init(&pll_lock, PLL_REMOTE_SPINLOCK_ID);
+
+	pll_control = smem_get_entry(SMEM_CLKREGIM_SOURCES, &smem_size);
+	if (!pll_control) {
+		pr_err("Can't find shared PLL control data structure!\n");
+		BUG();
+	/*
+	 * There might be more PLLs than what the application processor knows
+	 * about. But the index used for each PLL is guaranteed to remain the
+	 * same.
+	 */
+	} else if (smem_size < sizeof(struct shared_pll_control)) {
+			pr_err("Shared PLL control data"
+					 "structure too small!\n");
+			BUG();
+	} else if (pll_control->version != 0xCCEE0001) {
+			pr_err("Shared PLL control version mismatch!\n");
+			BUG();
+	} else {
+		pr_info("Shared PLL control available.\n");
+		return;
+	}
+
+}
+
+static int pll_clk_enable(struct clk *clk)
+{
+	struct pll_shared_clk *pll = to_pll_shared_clk(clk);
+	unsigned int pll_id = pll->id;
+
+	remote_spin_lock(&pll_lock);
+
+	pll_control->pll[PLL_BASE + pll_id].votes |= BIT(1);
+	if (!pll_control->pll[PLL_BASE + pll_id].on) {
+		__pll_clk_enable_reg(PLL_MODE_REG(pll));
+		pll_control->pll[PLL_BASE + pll_id].on = 1;
+	}
+
+	remote_spin_unlock(&pll_lock);
+	return 0;
+}
+
+static void pll_clk_disable(struct clk *clk)
+{
+	struct pll_shared_clk *pll = to_pll_shared_clk(clk);
+	unsigned int pll_id = pll->id;
+
+	remote_spin_lock(&pll_lock);
+
+	pll_control->pll[PLL_BASE + pll_id].votes &= ~BIT(1);
+	if (pll_control->pll[PLL_BASE + pll_id].on
+	    && !pll_control->pll[PLL_BASE + pll_id].votes) {
+		__pll_clk_disable_reg(PLL_MODE_REG(pll));
+		pll_control->pll[PLL_BASE + pll_id].on = 0;
+	}
+
+	remote_spin_unlock(&pll_lock);
+}
+
+static int pll_clk_is_enabled(struct clk *clk)
+{
+	struct pll_shared_clk *pll = to_pll_shared_clk(clk);
+
+	return readl_relaxed(PLL_MODE_REG(pll)) & BIT(0);
+}
+
+static enum handoff pll_clk_handoff(struct clk *clk)
+{
+	struct pll_shared_clk *pll = to_pll_shared_clk(clk);
+	unsigned int pll_lval;
+	struct pll_rate *l;
+
+	/*
+	 * Wait for the PLLs to be initialized and then read their frequency.
+	 */
+	do {
+		pll_lval = readl_relaxed(PLL_MODE_REG(pll) + 4) & 0x3ff;
+		cpu_relax();
+		udelay(50);
+	} while (pll_lval == 0);
+
+	/* Convert PLL L values to PLL Output rate */
+	for (l = pll_l_rate; l->rate != 0; l++) {
+		if (l->lvalue == pll_lval) {
+			clk->rate = l->rate;
+			break;
+		}
+	}
+
+	if (!clk->rate) {
+		pr_crit("Unknown PLL's L value!\n");
+		BUG();
+	}
+
+	return HANDOFF_ENABLED_CLK;
+}
+
+struct clk_ops clk_ops_pll = {
+	.enable = pll_clk_enable,
+	.disable = pll_clk_disable,
+	.handoff = pll_clk_handoff,
+	.is_enabled = pll_clk_is_enabled,
+};
+
+static void __init __set_fsm_mode(void __iomem *mode_reg)
+{
+	u32 regval = readl_relaxed(mode_reg);
+
+	/* De-assert reset to FSM */
+	regval &= ~BIT(21);
+	writel_relaxed(regval, mode_reg);
+
+	/* Program bias count */
+	regval &= ~BM(19, 14);
+	regval |= BVAL(19, 14, 0x1);
+	writel_relaxed(regval, mode_reg);
+
+	/* Program lock count */
+	regval &= ~BM(13, 8);
+	regval |= BVAL(13, 8, 0x8);
+	writel_relaxed(regval, mode_reg);
+
+	/* Enable PLL FSM voting */
+	regval |= BIT(20);
+	writel_relaxed(regval, mode_reg);
+}
+
+void __init configure_pll(struct pll_config *config,
+		struct pll_config_regs *regs, u32 ena_fsm_mode)
+{
+	u32 regval;
+
+	writel_relaxed(config->l, PLL_L_REG(regs));
+	writel_relaxed(config->m, PLL_M_REG(regs));
+	writel_relaxed(config->n, PLL_N_REG(regs));
+
+	regval = readl_relaxed(PLL_CONFIG_REG(regs));
+
+	/* Enable the MN accumulator  */
+	if (config->mn_ena_mask) {
+		regval &= ~config->mn_ena_mask;
+		regval |= config->mn_ena_val;
+	}
+
+	/* Enable the main output */
+	if (config->main_output_mask) {
+		regval &= ~config->main_output_mask;
+		regval |= config->main_output_val;
+	}
+
+	/* Set pre-divider and post-divider values */
+	regval &= ~config->pre_div_mask;
+	regval |= config->pre_div_val;
+	regval &= ~config->post_div_mask;
+	regval |= config->post_div_val;
+
+	/* Select VCO setting */
+	regval &= ~config->vco_mask;
+	regval |= config->vco_val;
+	writel_relaxed(regval, PLL_CONFIG_REG(regs));
+
+	/* Configure in FSM mode if necessary */
+	if (ena_fsm_mode)
+		__set_fsm_mode(PLL_MODE_REG(regs));
+}
diff --git a/arch/arm/mach-msm/clock-pll.h b/arch/arm/mach-msm/clock-pll.h
new file mode 100644
index 0000000..a8c642f
--- /dev/null
+++ b/arch/arm/mach-msm/clock-pll.h
@@ -0,0 +1,151 @@
+/*
+ * 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 __ARCH_ARM_MACH_MSM_CLOCK_PLL_H
+#define __ARCH_ARM_MACH_MSM_CLOCK_PLL_H
+
+/**
+ * enum - For PLL IDs
+ */
+enum {
+	PLL_TCXO	= -1,
+	PLL_0	= 0,
+	PLL_1,
+	PLL_2,
+	PLL_3,
+	PLL_4,
+	PLL_END,
+};
+
+/**
+ * struct pll_shared_clk -  PLL shared with other processors without
+ * any HW voting
+ * @id: PLL ID
+ * @mode_reg: enable register
+ * @parent: clock source
+ * @c: clk
+ */
+struct pll_shared_clk {
+	unsigned int id;
+	void __iomem *const mode_reg;
+	struct clk c;
+	void *const __iomem *base;
+};
+
+extern struct clk_ops clk_ops_pll;
+
+static inline struct pll_shared_clk *to_pll_shared_clk(struct clk *clk)
+{
+	return container_of(clk, struct pll_shared_clk, c);
+}
+
+/**
+ * msm_shared_pll_control_init() - Initialize shared pll control structure
+ */
+void msm_shared_pll_control_init(void);
+
+/**
+ * struct pll_vote_clk - phase locked loop (HW voteable)
+ * @soft_vote: soft voting variable for multiple PLL software instances
+ * @soft_vote_mask: soft voting mask for multiple PLL software instances
+ * @en_reg: enable register
+ * @en_mask: ORed with @en_reg to enable the clock
+ * @status_mask: ANDed with @status_reg to determine if PLL is active.
+ * @status_reg: status register
+ * @parent: clock source
+ * @c: clk
+ */
+struct pll_vote_clk {
+	u32 *soft_vote;
+	const u32 soft_vote_mask;
+	void __iomem *const en_reg;
+	const u32 en_mask;
+	void __iomem *const status_reg;
+	const u32 status_mask;
+
+	struct clk *parent;
+	struct clk c;
+	void *const __iomem *base;
+};
+
+extern struct clk_ops clk_ops_pll_vote;
+
+static inline struct pll_vote_clk *to_pll_vote_clk(struct clk *clk)
+{
+	return container_of(clk, struct pll_vote_clk, c);
+}
+
+/**
+ * struct pll_clk - phase locked loop
+ * @mode_reg: enable register
+ * @status_reg: status register, contains the lock detection bit
+ * @parent: clock source
+ * @c: clk
+ * @base: pointer to base address of ioremapped registers.
+ */
+struct pll_clk {
+	void __iomem *const mode_reg;
+	void __iomem *const status_reg;
+
+	struct clk *parent;
+	struct clk c;
+	void *const __iomem *base;
+};
+
+extern struct clk_ops clk_ops_local_pll;
+
+static inline struct pll_clk *to_pll_clk(struct clk *clk)
+{
+	return container_of(clk, struct pll_clk, c);
+}
+
+int sr_pll_clk_enable(struct clk *clk);
+int copper_pll_clk_enable(struct clk *clk);
+
+/*
+ * PLL vote clock APIs
+ */
+int pll_vote_clk_enable(struct clk *clk);
+void pll_vote_clk_disable(struct clk *clk);
+struct clk *pll_vote_clk_get_parent(struct clk *clk);
+int pll_vote_clk_is_enabled(struct clk *clk);
+
+struct pll_config {
+	u32 l;
+	u32 m;
+	u32 n;
+	u32 vco_val;
+	u32 vco_mask;
+	u32 pre_div_val;
+	u32 pre_div_mask;
+	u32 post_div_val;
+	u32 post_div_mask;
+	u32 mn_ena_val;
+	u32 mn_ena_mask;
+	u32 main_output_val;
+	u32 main_output_mask;
+};
+
+struct pll_config_regs {
+	void __iomem *l_reg;
+	void __iomem *m_reg;
+	void __iomem *n_reg;
+	void __iomem *config_reg;
+	void __iomem *mode_reg;
+	void *const __iomem *base;
+};
+
+void __init configure_pll(struct pll_config *, struct pll_config_regs *, u32);
+
+#endif
diff --git a/arch/arm/mach-msm/clock-rpm.c b/arch/arm/mach-msm/clock-rpm.c
new file mode 100644
index 0000000..ae87bb7
--- /dev/null
+++ b/arch/arm/mach-msm/clock-rpm.c
@@ -0,0 +1,204 @@
+/* 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
+ * 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/err.h>
+#include <mach/clk.h>
+
+#include "rpm_resources.h"
+#include "clock.h"
+#include "clock-rpm.h"
+
+static DEFINE_SPINLOCK(rpm_clock_lock);
+
+static int rpm_clk_enable(struct clk *clk)
+{
+	unsigned long flags;
+	struct rpm_clk *r = to_rpm_clk(clk);
+	struct msm_rpm_iv_pair iv = { .id = r->rpm_clk_id };
+	int rc = 0;
+	unsigned long this_khz, this_sleep_khz;
+	unsigned long peer_khz = 0, peer_sleep_khz = 0;
+	struct rpm_clk *peer = r->peer;
+
+	spin_lock_irqsave(&rpm_clock_lock, flags);
+
+	this_khz = r->last_set_khz;
+	/* Don't send requests to the RPM if the rate has not been set. */
+	if (this_khz == 0)
+		goto out;
+
+	this_sleep_khz = r->last_set_sleep_khz;
+
+	/* Take peer clock's rate into account only if it's enabled. */
+	if (peer->enabled) {
+		peer_khz = peer->last_set_khz;
+		peer_sleep_khz = peer->last_set_sleep_khz;
+	}
+
+	iv.value = max(this_khz, peer_khz);
+	if (r->branch)
+		iv.value = !!iv.value;
+
+	rc = msm_rpmrs_set_noirq(MSM_RPM_CTX_SET_0, &iv, 1);
+	if (rc)
+		goto out;
+
+	iv.value = max(this_sleep_khz, peer_sleep_khz);
+	if (r->branch)
+		iv.value = !!iv.value;
+	rc = msm_rpmrs_set_noirq(MSM_RPM_CTX_SET_SLEEP, &iv, 1);
+	if (rc) {
+		iv.value = peer_khz;
+		msm_rpmrs_set_noirq(MSM_RPM_CTX_SET_0, &iv, 1);
+	}
+
+out:
+	if (!rc)
+		r->enabled = true;
+
+	spin_unlock_irqrestore(&rpm_clock_lock, flags);
+
+	return rc;
+}
+
+static void rpm_clk_disable(struct clk *clk)
+{
+	unsigned long flags;
+	struct rpm_clk *r = to_rpm_clk(clk);
+
+	spin_lock_irqsave(&rpm_clock_lock, flags);
+
+	if (r->last_set_khz) {
+		struct msm_rpm_iv_pair iv = { .id = r->rpm_clk_id };
+		struct rpm_clk *peer = r->peer;
+		unsigned long peer_khz = 0, peer_sleep_khz = 0;
+		int rc;
+
+		/* Take peer clock's rate into account only if it's enabled. */
+		if (peer->enabled) {
+			peer_khz = peer->last_set_khz;
+			peer_sleep_khz = peer->last_set_sleep_khz;
+		}
+
+		iv.value = r->branch ? !!peer_khz : peer_khz;
+		rc = msm_rpmrs_set_noirq(MSM_RPM_CTX_SET_0, &iv, 1);
+		if (rc)
+			goto out;
+
+		iv.value = r->branch ? !!peer_sleep_khz : peer_sleep_khz;
+		rc = msm_rpmrs_set_noirq(MSM_RPM_CTX_SET_SLEEP, &iv, 1);
+	}
+	r->enabled = false;
+out:
+	spin_unlock_irqrestore(&rpm_clock_lock, flags);
+
+	return;
+}
+
+static int rpm_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned long flags;
+	struct rpm_clk *r = to_rpm_clk(clk);
+	unsigned long this_khz, this_sleep_khz;
+	int rc = 0;
+
+	this_khz = DIV_ROUND_UP(rate, 1000);
+
+	spin_lock_irqsave(&rpm_clock_lock, flags);
+
+	/* Ignore duplicate requests. */
+	if (r->last_set_khz == this_khz)
+		goto out;
+
+	/* Active-only clocks don't care what the rate is during sleep. So,
+	 * they vote for zero. */
+	if (r->active_only)
+		this_sleep_khz = 0;
+	else
+		this_sleep_khz = this_khz;
+
+	if (r->enabled) {
+		struct msm_rpm_iv_pair iv;
+		struct rpm_clk *peer = r->peer;
+		unsigned long peer_khz = 0, peer_sleep_khz = 0;
+
+		iv.id = r->rpm_clk_id;
+
+		/* Take peer clock's rate into account only if it's enabled. */
+		if (peer->enabled) {
+			peer_khz = peer->last_set_khz;
+			peer_sleep_khz = peer->last_set_sleep_khz;
+		}
+
+		iv.value = max(this_khz, peer_khz);
+		rc = msm_rpmrs_set_noirq(MSM_RPM_CTX_SET_0, &iv, 1);
+		if (rc)
+			goto out;
+
+		iv.value = max(this_sleep_khz, peer_sleep_khz);
+		rc = msm_rpmrs_set_noirq(MSM_RPM_CTX_SET_SLEEP, &iv, 1);
+	}
+	if (!rc) {
+		r->last_set_khz = this_khz;
+		r->last_set_sleep_khz = this_sleep_khz;
+	}
+
+out:
+	spin_unlock_irqrestore(&rpm_clock_lock, flags);
+
+	return rc;
+}
+
+static unsigned long rpm_clk_get_rate(struct clk *clk)
+{
+	struct rpm_clk *r = to_rpm_clk(clk);
+	struct msm_rpm_iv_pair iv = { r->rpm_status_id };
+	int rc;
+
+	rc  = msm_rpm_get_status(&iv, 1);
+	if (rc < 0)
+		return rc;
+	return iv.value * 1000;
+}
+
+static int rpm_clk_is_enabled(struct clk *clk)
+{
+	return !!(rpm_clk_get_rate(clk));
+}
+
+static long rpm_clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	/* Not supported. */
+	return rate;
+}
+
+static bool rpm_clk_is_local(struct clk *clk)
+{
+	return false;
+}
+
+struct clk_ops clk_ops_rpm = {
+	.enable = rpm_clk_enable,
+	.disable = rpm_clk_disable,
+	.set_rate = rpm_clk_set_rate,
+	.get_rate = rpm_clk_get_rate,
+	.is_enabled = rpm_clk_is_enabled,
+	.round_rate = rpm_clk_round_rate,
+	.is_local = rpm_clk_is_local,
+};
+
+struct clk_ops clk_ops_rpm_branch = {
+	.enable = rpm_clk_enable,
+	.disable = rpm_clk_disable,
+	.is_local = rpm_clk_is_local,
+};
diff --git a/arch/arm/mach-msm/clock-rpm.h b/arch/arm/mach-msm/clock-rpm.h
new file mode 100644
index 0000000..b0d5693
--- /dev/null
+++ b/arch/arm/mach-msm/clock-rpm.h
@@ -0,0 +1,105 @@
+/* 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
+ * 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 __ARCH_ARM_MACH_MSM_CLOCK_RPM_H
+#define __ARCH_ARM_MACH_MSM_CLOCK_RPM_H
+
+#include <mach/rpm.h>
+
+struct clk_ops;
+extern struct clk_ops clk_ops_rpm;
+extern struct clk_ops clk_ops_rpm_branch;
+
+struct rpm_clk {
+	const int rpm_clk_id;
+	const int rpm_status_id;
+	const bool active_only;
+	unsigned last_set_khz;
+	/* 0 if active_only. Otherwise, same as last_set_khz. */
+	unsigned last_set_sleep_khz;
+	bool enabled;
+	bool branch; /* true: RPM only accepts 1 for ON and 0 for OFF */
+
+	struct rpm_clk *peer;
+	struct clk c;
+};
+
+static inline struct rpm_clk *to_rpm_clk(struct clk *clk)
+{
+	return container_of(clk, struct rpm_clk, c);
+}
+
+#define DEFINE_CLK_RPM(name, active, r_id, dep) \
+	static struct rpm_clk active; \
+	static struct rpm_clk name = { \
+		.rpm_clk_id = MSM_RPM_ID_##r_id##_CLK, \
+		.rpm_status_id = MSM_RPM_STATUS_ID_##r_id##_CLK, \
+		.peer = &active, \
+		.c = { \
+			.ops = &clk_ops_rpm, \
+			.flags = CLKFLAG_SKIP_AUTO_OFF, \
+			.dbg_name = #name, \
+			CLK_INIT(name.c), \
+			.depends = dep, \
+		}, \
+	}; \
+	static struct rpm_clk active = { \
+		.rpm_clk_id = MSM_RPM_ID_##r_id##_CLK, \
+		.rpm_status_id = MSM_RPM_STATUS_ID_##r_id##_CLK, \
+		.peer = &name, \
+		.active_only = true, \
+		.c = { \
+			.ops = &clk_ops_rpm, \
+			.flags = CLKFLAG_SKIP_AUTO_OFF, \
+			.dbg_name = #active, \
+			CLK_INIT(active.c), \
+			.depends = dep, \
+		}, \
+	};
+
+#define DEFINE_CLK_RPM_BRANCH(name, active, r_id, r) \
+	static struct rpm_clk active; \
+	static struct rpm_clk name = { \
+		.rpm_clk_id = MSM_RPM_ID_##r_id##_CLK, \
+		.rpm_status_id = MSM_RPM_STATUS_ID_##r_id##_CLK, \
+		.peer = &active, \
+		.last_set_khz = ((r) / 1000), \
+		.last_set_sleep_khz = ((r) / 1000), \
+		.branch = true, \
+		.c = { \
+			.ops = &clk_ops_rpm_branch, \
+			.flags = CLKFLAG_SKIP_AUTO_OFF, \
+			.dbg_name = #name, \
+			.rate = (r), \
+			CLK_INIT(name.c), \
+			.warned = true, \
+		}, \
+	}; \
+	static struct rpm_clk active = { \
+		.rpm_clk_id = MSM_RPM_ID_##r_id##_CLK, \
+		.rpm_status_id = MSM_RPM_STATUS_ID_##r_id##_CLK, \
+		.peer = &name, \
+		.last_set_khz = ((r) / 1000), \
+		.active_only = true, \
+		.branch = true, \
+		.c = { \
+			.ops = &clk_ops_rpm_branch, \
+			.flags = CLKFLAG_SKIP_AUTO_OFF, \
+			.dbg_name = #active, \
+			.rate = (r), \
+			CLK_INIT(active.c), \
+			.warned = true, \
+		}, \
+	};
+
+#endif
diff --git a/arch/arm/mach-msm/clock-voter.c b/arch/arm/mach-msm/clock-voter.c
new file mode 100644
index 0000000..4cd9b1c
--- /dev/null
+++ b/arch/arm/mach-msm/clock-voter.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+
+#include "clock.h"
+#include "clock-voter.h"
+
+static DEFINE_SPINLOCK(voter_clk_lock);
+
+/* Aggregate the rate of clocks that are currently on. */
+static unsigned long voter_clk_aggregate_rate(const struct clk *parent)
+{
+	struct clk *clk;
+	unsigned long rate = 0;
+
+	list_for_each_entry(clk, &parent->children, siblings) {
+		struct clk_voter *v = to_clk_voter(clk);
+		if (v->enabled)
+			rate = max(clk->rate, rate);
+	}
+	return rate;
+}
+
+static int voter_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	int ret = 0;
+	unsigned long flags;
+	struct clk *clkp;
+	struct clk_voter *clkh, *v = to_clk_voter(clk);
+	unsigned long cur_rate, new_rate, other_rate = 0;
+
+	spin_lock_irqsave(&voter_clk_lock, flags);
+
+	if (v->enabled) {
+		struct clk *parent = v->parent;
+
+		/*
+		 * Get the aggregate rate without this clock's vote and update
+		 * if the new rate is different than the current rate
+		 */
+		list_for_each_entry(clkp, &parent->children, siblings) {
+			clkh = to_clk_voter(clkp);
+			if (clkh->enabled && clkh != v)
+				other_rate = max(clkp->rate, other_rate);
+		}
+
+		cur_rate = max(other_rate, clk->rate);
+		new_rate = max(other_rate, rate);
+
+		if (new_rate != cur_rate) {
+			ret = clk_set_rate(parent, new_rate);
+			if (ret)
+				goto unlock;
+		}
+	}
+	clk->rate = rate;
+unlock:
+	spin_unlock_irqrestore(&voter_clk_lock, flags);
+
+	return ret;
+}
+
+static int voter_clk_enable(struct clk *clk)
+{
+	int ret = 0;
+	unsigned long flags;
+	unsigned long cur_rate;
+	struct clk *parent;
+	struct clk_voter *v = to_clk_voter(clk);
+
+	spin_lock_irqsave(&voter_clk_lock, flags);
+	parent = v->parent;
+
+	/*
+	 * Increase the rate if this clock is voting for a higher rate
+	 * than the current rate.
+	 */
+	cur_rate = voter_clk_aggregate_rate(parent);
+	if (clk->rate > cur_rate) {
+		ret = clk_set_rate(parent, clk->rate);
+		if (ret)
+			goto out;
+	}
+	v->enabled = true;
+out:
+	spin_unlock_irqrestore(&voter_clk_lock, flags);
+
+	return ret;
+}
+
+static void voter_clk_disable(struct clk *clk)
+{
+	unsigned long flags, cur_rate, new_rate;
+	struct clk *parent;
+	struct clk_voter *v = to_clk_voter(clk);
+
+	spin_lock_irqsave(&voter_clk_lock, flags);
+	parent = v->parent;
+
+	/*
+	 * Decrease the rate if this clock was the only one voting for
+	 * the highest rate.
+	 */
+	v->enabled = false;
+	new_rate = voter_clk_aggregate_rate(parent);
+	cur_rate = max(new_rate, clk->rate);
+
+	if (new_rate < cur_rate)
+		clk_set_rate(parent, new_rate);
+
+	spin_unlock_irqrestore(&voter_clk_lock, flags);
+}
+
+static int voter_clk_is_enabled(struct clk *clk)
+{
+	struct clk_voter *v = to_clk_voter(clk);
+	return v->enabled;
+}
+
+static long voter_clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	struct clk_voter *v = to_clk_voter(clk);
+	return clk_round_rate(v->parent, rate);
+}
+
+static struct clk *voter_clk_get_parent(struct clk *clk)
+{
+	struct clk_voter *v = to_clk_voter(clk);
+	return v->parent;
+}
+
+static bool voter_clk_is_local(struct clk *clk)
+{
+	return true;
+}
+
+static enum handoff voter_clk_handoff(struct clk *clk)
+{
+	/* Apply default rate vote */
+	if (clk->rate)
+		return HANDOFF_ENABLED_CLK;
+
+	return HANDOFF_DISABLED_CLK;
+}
+
+struct clk_ops clk_ops_voter = {
+	.enable = voter_clk_enable,
+	.disable = voter_clk_disable,
+	.set_rate = voter_clk_set_rate,
+	.is_enabled = voter_clk_is_enabled,
+	.round_rate = voter_clk_round_rate,
+	.get_parent = voter_clk_get_parent,
+	.is_local = voter_clk_is_local,
+	.handoff = voter_clk_handoff,
+};
diff --git a/arch/arm/mach-msm/clock-voter.h b/arch/arm/mach-msm/clock-voter.h
new file mode 100644
index 0000000..c9aebba
--- /dev/null
+++ b/arch/arm/mach-msm/clock-voter.h
@@ -0,0 +1,43 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_CLOCK_VOTER_H
+#define __ARCH_ARM_MACH_MSM_CLOCK_VOTER_H
+
+struct clk_ops;
+extern struct clk_ops clk_ops_voter;
+
+struct clk_voter {
+	bool enabled;
+	struct clk *parent;
+	struct clk c;
+};
+
+static inline struct clk_voter *to_clk_voter(struct clk *clk)
+{
+	return container_of(clk, struct clk_voter, c);
+}
+
+#define DEFINE_CLK_VOTER(clk_name, _parent, _default_rate) \
+	struct clk_voter clk_name = { \
+		.parent = _parent, \
+		.c = { \
+			.dbg_name = #clk_name, \
+			.ops = &clk_ops_voter, \
+			.flags = CLKFLAG_SKIP_AUTO_OFF, \
+			.rate = _default_rate, \
+			CLK_INIT(clk_name.c), \
+		}, \
+	}
+
+#endif
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index d9145df..fb5b580 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -1,7 +1,7 @@
 /* arch/arm/mach-msm/clock.c
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2007-2012, Code Aurora Forum. 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
@@ -15,170 +15,488 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/list.h>
 #include <linux/err.h>
 #include <linux/spinlock.h>
-#include <linux/pm_qos.h>
-#include <linux/mutex.h>
-#include <linux/clk.h>
 #include <linux/string.h>
 #include <linux/module.h>
+#include <linux/clk.h>
 #include <linux/clkdev.h>
+#include <trace/events/power.h>
 
 #include "clock.h"
 
-static DEFINE_MUTEX(clocks_mutex);
-static DEFINE_SPINLOCK(clocks_lock);
-static LIST_HEAD(clocks);
+/* Find the voltage level required for a given rate. */
+static int find_vdd_level(struct clk *clk, unsigned long rate)
+{
+	int level;
+
+	for (level = 0; level < ARRAY_SIZE(clk->fmax); level++)
+		if (rate <= clk->fmax[level])
+			break;
+
+	if (level == ARRAY_SIZE(clk->fmax)) {
+		pr_err("Rate %lu for %s is greater than highest Fmax\n", rate,
+			clk->dbg_name);
+		return -EINVAL;
+	}
+
+	return level;
+}
+
+/* Update voltage level given the current votes. */
+static int update_vdd(struct clk_vdd_class *vdd_class)
+{
+	int level, rc;
+
+	for (level = ARRAY_SIZE(vdd_class->level_votes)-1; level > 0; level--)
+		if (vdd_class->level_votes[level])
+			break;
+
+	if (level == vdd_class->cur_level)
+		return 0;
+
+	rc = vdd_class->set_vdd(vdd_class, level);
+	if (!rc)
+		vdd_class->cur_level = level;
+
+	return rc;
+}
+
+/* Vote for a voltage level. */
+int vote_vdd_level(struct clk_vdd_class *vdd_class, int level)
+{
+	unsigned long flags;
+	int rc;
+
+	spin_lock_irqsave(&vdd_class->lock, flags);
+	vdd_class->level_votes[level]++;
+	rc = update_vdd(vdd_class);
+	if (rc)
+		vdd_class->level_votes[level]--;
+	spin_unlock_irqrestore(&vdd_class->lock, flags);
+
+	return rc;
+}
+
+/* Remove vote for a voltage level. */
+int unvote_vdd_level(struct clk_vdd_class *vdd_class, int level)
+{
+	unsigned long flags;
+	int rc = 0;
+
+	spin_lock_irqsave(&vdd_class->lock, flags);
+	if (WARN(!vdd_class->level_votes[level],
+			"Reference counts are incorrect for %s level %d\n",
+			vdd_class->class_name, level))
+		goto out;
+	vdd_class->level_votes[level]--;
+	rc = update_vdd(vdd_class);
+	if (rc)
+		vdd_class->level_votes[level]++;
+out:
+	spin_unlock_irqrestore(&vdd_class->lock, flags);
+	return rc;
+}
+
+/* Vote for a voltage level corresponding to a clock's rate. */
+static int vote_rate_vdd(struct clk *clk, unsigned long rate)
+{
+	int level;
+
+	if (!clk->vdd_class)
+		return 0;
+
+	level = find_vdd_level(clk, rate);
+	if (level < 0)
+		return level;
+
+	return vote_vdd_level(clk->vdd_class, level);
+}
+
+/* Remove vote for a voltage level corresponding to a clock's rate. */
+static void unvote_rate_vdd(struct clk *clk, unsigned long rate)
+{
+	int level;
+
+	if (!clk->vdd_class)
+		return;
+
+	level = find_vdd_level(clk, rate);
+	if (level < 0)
+		return;
+
+	unvote_vdd_level(clk->vdd_class, level);
+}
+
+int clk_prepare(struct clk *clk)
+{
+	int ret = 0;
+	struct clk *parent;
+
+	if (!clk)
+		return 0;
+	if (IS_ERR(clk))
+		return -EINVAL;
+
+	mutex_lock(&clk->prepare_lock);
+	if (clk->prepare_count == 0) {
+		parent = clk_get_parent(clk);
+
+		ret = clk_prepare(parent);
+		if (ret)
+			goto out;
+		ret = clk_prepare(clk->depends);
+		if (ret)
+			goto err_prepare_depends;
+
+		if (clk->ops->prepare)
+			ret = clk->ops->prepare(clk);
+		if (ret)
+			goto err_prepare_clock;
+	}
+	clk->prepare_count++;
+out:
+	mutex_unlock(&clk->prepare_lock);
+	return ret;
+err_prepare_clock:
+	clk_unprepare(clk->depends);
+err_prepare_depends:
+	clk_unprepare(parent);
+	goto out;
+}
+EXPORT_SYMBOL(clk_prepare);
 
 /*
  * Standard clock functions defined in include/linux/clk.h
  */
 int clk_enable(struct clk *clk)
 {
+	int ret = 0;
 	unsigned long flags;
-	spin_lock_irqsave(&clocks_lock, flags);
+	struct clk *parent;
+
+	if (!clk)
+		return 0;
+	if (IS_ERR(clk))
+		return -EINVAL;
+
+	spin_lock_irqsave(&clk->lock, flags);
+	if (WARN(!clk->warned && !clk->prepare_count,
+				"%s: Don't call enable on unprepared clocks\n",
+				clk->dbg_name))
+		clk->warned = true;
+	if (clk->count == 0) {
+		parent = clk_get_parent(clk);
+
+		ret = clk_enable(parent);
+		if (ret)
+			goto err_enable_parent;
+		ret = clk_enable(clk->depends);
+		if (ret)
+			goto err_enable_depends;
+
+		ret = vote_rate_vdd(clk, clk->rate);
+		if (ret)
+			goto err_vote_vdd;
+		trace_clock_enable(clk->dbg_name, 1, smp_processor_id());
+		if (clk->ops->enable)
+			ret = clk->ops->enable(clk);
+		if (ret)
+			goto err_enable_clock;
+	} else if (clk->flags & CLKFLAG_HANDOFF_RATE) {
+		/*
+		 * The clock was already enabled by handoff code so there is no
+		 * need to enable it again here. Clearing the handoff flag will
+		 * prevent the lateinit handoff code from disabling the clock if
+		 * a client driver still has it enabled.
+		 */
+		clk->flags &= ~CLKFLAG_HANDOFF_RATE;
+		goto out;
+	}
 	clk->count++;
-	if (clk->count == 1)
-		clk->ops->enable(clk->id);
-	spin_unlock_irqrestore(&clocks_lock, flags);
+out:
+	spin_unlock_irqrestore(&clk->lock, flags);
+
 	return 0;
+
+err_enable_clock:
+	unvote_rate_vdd(clk, clk->rate);
+err_vote_vdd:
+	clk_disable(clk->depends);
+err_enable_depends:
+	clk_disable(parent);
+err_enable_parent:
+	spin_unlock_irqrestore(&clk->lock, flags);
+	return ret;
 }
 EXPORT_SYMBOL(clk_enable);
 
 void clk_disable(struct clk *clk)
 {
 	unsigned long flags;
-	spin_lock_irqsave(&clocks_lock, flags);
-	BUG_ON(clk->count == 0);
+
+	if (IS_ERR_OR_NULL(clk))
+		return;
+
+	spin_lock_irqsave(&clk->lock, flags);
+	if (WARN(!clk->warned && !clk->prepare_count,
+				"%s: Never called prepare or calling disable "
+				"after unprepare\n",
+				clk->dbg_name))
+		clk->warned = true;
+	if (WARN(clk->count == 0, "%s is unbalanced", clk->dbg_name))
+		goto out;
+	if (clk->count == 1) {
+		struct clk *parent = clk_get_parent(clk);
+
+		trace_clock_disable(clk->dbg_name, 0, smp_processor_id());
+		if (clk->ops->disable)
+			clk->ops->disable(clk);
+		unvote_rate_vdd(clk, clk->rate);
+		clk_disable(clk->depends);
+		clk_disable(parent);
+	}
 	clk->count--;
-	if (clk->count == 0)
-		clk->ops->disable(clk->id);
-	spin_unlock_irqrestore(&clocks_lock, flags);
+out:
+	spin_unlock_irqrestore(&clk->lock, flags);
 }
 EXPORT_SYMBOL(clk_disable);
 
+void clk_unprepare(struct clk *clk)
+{
+	if (IS_ERR_OR_NULL(clk))
+		return;
+
+	mutex_lock(&clk->prepare_lock);
+	if (!clk->prepare_count) {
+		if (WARN(!clk->warned, "%s is unbalanced (prepare)",
+				clk->dbg_name))
+			clk->warned = true;
+		goto out;
+	}
+	if (clk->prepare_count == 1) {
+		struct clk *parent = clk_get_parent(clk);
+
+		if (WARN(!clk->warned && clk->count,
+			"%s: Don't call unprepare when the clock is enabled\n",
+				clk->dbg_name))
+			clk->warned = true;
+
+		if (clk->ops->unprepare)
+			clk->ops->unprepare(clk);
+		clk_unprepare(clk->depends);
+		clk_unprepare(parent);
+	}
+	clk->prepare_count--;
+out:
+	mutex_unlock(&clk->prepare_lock);
+}
+EXPORT_SYMBOL(clk_unprepare);
+
 int clk_reset(struct clk *clk, enum clk_reset_action action)
 {
-	return clk->ops->reset(clk->remote_id, action);
+	if (IS_ERR_OR_NULL(clk))
+		return -EINVAL;
+
+	if (!clk->ops->reset)
+		return -ENOSYS;
+
+	return clk->ops->reset(clk, action);
 }
 EXPORT_SYMBOL(clk_reset);
 
 unsigned long clk_get_rate(struct clk *clk)
 {
-	return clk->ops->get_rate(clk->id);
+	if (IS_ERR_OR_NULL(clk))
+		return 0;
+
+	if (!clk->ops->get_rate)
+		return clk->rate;
+
+	return clk->ops->get_rate(clk);
 }
 EXPORT_SYMBOL(clk_get_rate);
 
 int clk_set_rate(struct clk *clk, unsigned long rate)
 {
-	int ret;
-	if (clk->flags & CLKFLAG_MAX) {
-		ret = clk->ops->set_max_rate(clk->id, rate);
-		if (ret)
-			return ret;
-	}
-	if (clk->flags & CLKFLAG_MIN) {
-		ret = clk->ops->set_min_rate(clk->id, rate);
-		if (ret)
-			return ret;
+	unsigned long start_rate, flags;
+	int rc;
+
+	if (IS_ERR_OR_NULL(clk))
+		return -EINVAL;
+
+	if (!clk->ops->set_rate)
+		return -ENOSYS;
+
+	spin_lock_irqsave(&clk->lock, flags);
+	trace_clock_set_rate(clk->dbg_name, rate, smp_processor_id());
+	if (clk->count) {
+		start_rate = clk->rate;
+		/* Enforce vdd requirements for target frequency. */
+		rc = vote_rate_vdd(clk, rate);
+		if (rc)
+			goto err_vote_vdd;
+		rc = clk->ops->set_rate(clk, rate);
+		if (rc)
+			goto err_set_rate;
+		/* Release vdd requirements for starting frequency. */
+		unvote_rate_vdd(clk, start_rate);
+	} else {
+		rc = clk->ops->set_rate(clk, rate);
 	}
 
-	if (clk->flags & CLKFLAG_MAX || clk->flags & CLKFLAG_MIN)
-		return ret;
+	if (!rc)
+		clk->rate = rate;
 
-	return clk->ops->set_rate(clk->id, rate);
+	spin_unlock_irqrestore(&clk->lock, flags);
+	return rc;
+
+err_set_rate:
+	unvote_rate_vdd(clk, rate);
+err_vote_vdd:
+	spin_unlock_irqrestore(&clk->lock, flags);
+	return rc;
 }
 EXPORT_SYMBOL(clk_set_rate);
 
 long clk_round_rate(struct clk *clk, unsigned long rate)
 {
-	return clk->ops->round_rate(clk->id, rate);
+	if (IS_ERR_OR_NULL(clk))
+		return -EINVAL;
+
+	if (!clk->ops->round_rate)
+		return -ENOSYS;
+
+	return clk->ops->round_rate(clk, rate);
 }
 EXPORT_SYMBOL(clk_round_rate);
 
-int clk_set_min_rate(struct clk *clk, unsigned long rate)
-{
-	return clk->ops->set_min_rate(clk->id, rate);
-}
-EXPORT_SYMBOL(clk_set_min_rate);
-
 int clk_set_max_rate(struct clk *clk, unsigned long rate)
 {
-	return clk->ops->set_max_rate(clk->id, rate);
+	if (IS_ERR_OR_NULL(clk))
+		return -EINVAL;
+
+	if (!clk->ops->set_max_rate)
+		return -ENOSYS;
+
+	return clk->ops->set_max_rate(clk, rate);
 }
 EXPORT_SYMBOL(clk_set_max_rate);
 
 int clk_set_parent(struct clk *clk, struct clk *parent)
 {
-	return -ENOSYS;
+	if (!clk->ops->set_parent)
+		return 0;
+
+	return clk->ops->set_parent(clk, parent);
 }
 EXPORT_SYMBOL(clk_set_parent);
 
 struct clk *clk_get_parent(struct clk *clk)
 {
-	return ERR_PTR(-ENOSYS);
+	if (IS_ERR_OR_NULL(clk))
+		return NULL;
+
+	if (!clk->ops->get_parent)
+		return NULL;
+
+	return clk->ops->get_parent(clk);
 }
 EXPORT_SYMBOL(clk_get_parent);
 
 int clk_set_flags(struct clk *clk, unsigned long flags)
 {
-	if (clk == NULL || IS_ERR(clk))
+	if (IS_ERR_OR_NULL(clk))
 		return -EINVAL;
-	return clk->ops->set_flags(clk->id, flags);
+	if (!clk->ops->set_flags)
+		return -ENOSYS;
+
+	return clk->ops->set_flags(clk, flags);
 }
 EXPORT_SYMBOL(clk_set_flags);
 
-/* EBI1 is the only shared clock that several clients want to vote on as of
- * this commit. If this changes in the future, then it might be better to
- * make clk_min_rate handle the voting or make ebi1_clk_set_min_rate more
- * generic to support different clocks.
- */
-static struct clk *ebi1_clk;
+static struct clock_init_data __initdata *clk_init_data;
 
-void __init msm_clock_init(struct clk_lookup *clock_tbl, unsigned num_clocks)
+void __init msm_clock_init(struct clock_init_data *data)
 {
 	unsigned n;
+	struct clk_lookup *clock_tbl;
+	size_t num_clocks;
+	struct clk *clk;
 
-	mutex_lock(&clocks_mutex);
+	clk_init_data = data;
+	if (clk_init_data->pre_init)
+		clk_init_data->pre_init();
+
+	clock_tbl = data->table;
+	num_clocks = data->size;
+
 	for (n = 0; n < num_clocks; n++) {
-		clkdev_add(&clock_tbl[n]);
-		list_add_tail(&clock_tbl[n].clk->list, &clocks);
+		struct clk *parent;
+		clk = clock_tbl[n].clk;
+		parent = clk_get_parent(clk);
+		if (parent && list_empty(&clk->siblings))
+			list_add(&clk->siblings, &parent->children);
 	}
-	mutex_unlock(&clocks_mutex);
 
-	ebi1_clk = clk_get(NULL, "ebi1_clk");
-	BUG_ON(ebi1_clk == NULL);
+	/*
+	 * Detect and preserve initial clock state until clock_late_init() or
+	 * a driver explicitly changes it, whichever is first.
+	 */
+	for (n = 0; n < num_clocks; n++) {
+		clk = clock_tbl[n].clk;
+		if (clk->ops->handoff && !(clk->flags & CLKFLAG_HANDOFF_RATE) &&
+		    (clk->ops->handoff(clk) == HANDOFF_ENABLED_CLK)) {
+			clk->flags |= CLKFLAG_HANDOFF_RATE;
+			clk_prepare_enable(clk);
+		}
+	}
 
+	clkdev_add_table(clock_tbl, num_clocks);
+
+	if (clk_init_data->post_init)
+		clk_init_data->post_init();
 }
 
-/* The bootloader and/or AMSS may have left various clocks enabled.
- * Disable any clocks that belong to us (CLKFLAG_AUTO_OFF) but have
- * not been explicitly enabled by a clk_enable() call.
+/*
+ * The bootloader and/or AMSS may have left various clocks enabled.
+ * Disable any clocks that have not been explicitly enabled by a
+ * clk_enable() call and don't have the CLKFLAG_SKIP_AUTO_OFF flag.
  */
 static int __init clock_late_init(void)
 {
+	unsigned n, count = 0;
 	unsigned long flags;
-	struct clk *clk;
-	unsigned count = 0;
+	int ret = 0;
 
-	clock_debug_init();
-	mutex_lock(&clocks_mutex);
-	list_for_each_entry(clk, &clocks, list) {
+	clock_debug_init(clk_init_data);
+	for (n = 0; n < clk_init_data->size; n++) {
+		struct clk *clk = clk_init_data->table[n].clk;
+		bool handoff = false;
+
 		clock_debug_add(clk);
-		if (clk->flags & CLKFLAG_AUTO_OFF) {
-			spin_lock_irqsave(&clocks_lock, flags);
-			if (!clk->count) {
+		spin_lock_irqsave(&clk->lock, flags);
+		if (!(clk->flags & CLKFLAG_SKIP_AUTO_OFF)) {
+			if (!clk->count && clk->ops->auto_off) {
 				count++;
-				clk->ops->auto_off(clk->id);
+				clk->ops->auto_off(clk);
 			}
-			spin_unlock_irqrestore(&clocks_lock, flags);
 		}
+		if (clk->flags & CLKFLAG_HANDOFF_RATE) {
+			clk->flags &= ~CLKFLAG_HANDOFF_RATE;
+			handoff = true;
+		}
+		spin_unlock_irqrestore(&clk->lock, flags);
+		/*
+		 * Calling this outside the lock is safe since
+		 * it doesn't need to be atomic with the flag change.
+		 */
+		if (handoff)
+			clk_disable_unprepare(clk);
 	}
-	mutex_unlock(&clocks_mutex);
 	pr_info("clock_late_init() disabled %d unused clocks\n", count);
-	return 0;
+	if (clk_init_data->late_init)
+		ret = clk_init_data->late_init();
+	return ret;
 }
-
 late_initcall(clock_late_init);
-
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index 2c007f6..1be05ad 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -1,7 +1,7 @@
 /* arch/arm/mach-msm/clock.h
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2007-2012, Code Aurora Forum. 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
@@ -17,56 +17,186 @@
 #ifndef __ARCH_ARM_MACH_MSM_CLOCK_H
 #define __ARCH_ARM_MACH_MSM_CLOCK_H
 
-#include <linux/init.h>
+#include <linux/types.h>
 #include <linux/list.h>
+#include <linux/clkdev.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+
 #include <mach/clk.h>
 
 #define CLKFLAG_INVERT			0x00000001
 #define CLKFLAG_NOINVERT		0x00000002
 #define CLKFLAG_NONEST			0x00000004
 #define CLKFLAG_NORESET			0x00000008
-
-#define CLK_FIRST_AVAILABLE_FLAG	0x00000100
-#define CLKFLAG_AUTO_OFF		0x00000200
+#define CLKFLAG_HANDOFF_RATE		0x00000010
+#define CLKFLAG_HWCG			0x00000020
+#define CLKFLAG_RETAIN			0x00000040
+#define CLKFLAG_NORETAIN		0x00000080
+#define CLKFLAG_SKIP_AUTO_OFF		0x00000200
 #define CLKFLAG_MIN			0x00000400
 #define CLKFLAG_MAX			0x00000800
 
-struct clk_ops {
-	int (*enable)(unsigned id);
-	void (*disable)(unsigned id);
-	void (*auto_off)(unsigned id);
-	int (*reset)(unsigned id, enum clk_reset_action action);
-	int (*set_rate)(unsigned id, unsigned rate);
-	int (*set_min_rate)(unsigned id, unsigned rate);
-	int (*set_max_rate)(unsigned id, unsigned rate);
-	int (*set_flags)(unsigned id, unsigned flags);
-	unsigned (*get_rate)(unsigned id);
-	unsigned (*is_enabled)(unsigned id);
-	long (*round_rate)(unsigned id, unsigned rate);
-	bool (*is_local)(unsigned id);
+/*
+ * Bit manipulation macros
+ */
+#define BM(msb, lsb)	(((((uint32_t)-1) << (31-msb)) >> (31-msb+lsb)) << lsb)
+#define BVAL(msb, lsb, val)	(((val) << lsb) & BM(msb, lsb))
+
+/*
+ * Halt/Status Checking Mode Macros
+ */
+#define HALT		0	/* Bit pol: 1 = halted */
+#define NOCHECK		1	/* No bit to check, do nothing */
+#define HALT_VOTED	2	/* Bit pol: 1 = halted; delay on disable */
+#define ENABLE		3	/* Bit pol: 1 = running */
+#define ENABLE_VOTED	4	/* Bit pol: 1 = running; delay on disable */
+#define DELAY		5	/* No bit to check, just delay */
+
+#define MAX_VDD_LEVELS			4
+
+/**
+ * struct clk_vdd_class - Voltage scaling class
+ * @class_name: name of the class
+ * @set_vdd: function to call when applying a new voltage setting
+ * @level_votes: array of votes for each level
+ * @cur_level: the currently set voltage level
+ * @lock: lock to protect this struct
+ */
+struct clk_vdd_class {
+	const char *class_name;
+	int (*set_vdd)(struct clk_vdd_class *v_class, int level);
+	int level_votes[MAX_VDD_LEVELS];
+	unsigned long cur_level;
+	spinlock_t lock;
 };
 
+#define DEFINE_VDD_CLASS(_name, _set_vdd) \
+	struct clk_vdd_class _name = { \
+		.class_name = #_name, \
+		.set_vdd = _set_vdd, \
+		.cur_level = ARRAY_SIZE(_name.level_votes), \
+		.lock = __SPIN_LOCK_UNLOCKED(lock) \
+	}
+
+enum handoff {
+	HANDOFF_ENABLED_CLK,
+	HANDOFF_DISABLED_CLK,
+	HANDOFF_UNKNOWN_RATE,
+};
+
+struct clk_ops {
+	int (*prepare)(struct clk *clk);
+	int (*enable)(struct clk *clk);
+	void (*disable)(struct clk *clk);
+	void (*unprepare)(struct clk *clk);
+	void (*auto_off)(struct clk *clk);
+	void (*enable_hwcg)(struct clk *clk);
+	void (*disable_hwcg)(struct clk *clk);
+	int (*in_hwcg_mode)(struct clk *clk);
+	enum handoff (*handoff)(struct clk *clk);
+	int (*reset)(struct clk *clk, enum clk_reset_action action);
+	int (*set_rate)(struct clk *clk, unsigned long rate);
+	int (*set_max_rate)(struct clk *clk, unsigned long rate);
+	int (*set_flags)(struct clk *clk, unsigned flags);
+	unsigned long (*get_rate)(struct clk *clk);
+	int (*list_rate)(struct clk *clk, unsigned n);
+	int (*is_enabled)(struct clk *clk);
+	long (*round_rate)(struct clk *clk, unsigned long rate);
+	int (*set_parent)(struct clk *clk, struct clk *parent);
+	struct clk *(*get_parent)(struct clk *clk);
+	bool (*is_local)(struct clk *clk);
+};
+
+/**
+ * struct clk
+ * @prepare_count: prepare refcount
+ * @prepare_lock: protects clk_prepare()/clk_unprepare() path and @prepare_count
+ * @count: enable refcount
+ * @lock: protects clk_enable()/clk_disable() path and @count
+ * @depends: non-direct parent of clock to enable when this clock is enabled
+ * @vdd_class: voltage scaling requirement class
+ * @fmax: maximum frequency in Hz supported at each voltage level
+ * @warned: true if the clock has warned of incorrect usage, false otherwise
+ */
 struct clk {
-	uint32_t id;
-	uint32_t remote_id;
-	uint32_t count;
 	uint32_t flags;
 	struct clk_ops *ops;
 	const char *dbg_name;
-	struct list_head list;
+	struct clk *depends;
+	struct clk_vdd_class *vdd_class;
+	unsigned long fmax[MAX_VDD_LEVELS];
+	unsigned long rate;
+
+	struct list_head children;
+	struct list_head siblings;
+
+	bool warned;
+	unsigned count;
+	spinlock_t lock;
+	unsigned prepare_count;
+	struct mutex prepare_lock;
 };
 
-#define OFF CLKFLAG_AUTO_OFF
-#define CLK_MIN CLKFLAG_MIN
-#define CLK_MAX CLKFLAG_MAX
-#define CLK_MINMAX (CLK_MIN | CLK_MAX)
+#define CLK_INIT(name) \
+	.lock = __SPIN_LOCK_UNLOCKED((name).lock), \
+	.prepare_lock = __MUTEX_INITIALIZER((name).prepare_lock), \
+	.children = LIST_HEAD_INIT((name).children), \
+	.siblings = LIST_HEAD_INIT((name).siblings)
+
+/**
+ * struct clock_init_data - SoC specific clock initialization data
+ * @table: table of lookups to add
+ * @size: size of @table
+ * @pre_init: called before initializing the clock driver.
+ * @post_init: called after registering @table. clock APIs can be called inside.
+ * @late_init: called during late init
+ */
+struct clock_init_data {
+	struct clk_lookup *table;
+	size_t size;
+	void (*pre_init)(void);
+	void (*post_init)(void);
+	int (*late_init)(void);
+};
+
+extern struct clock_init_data msm9615_clock_init_data;
+extern struct clock_init_data apq8064_clock_init_data;
+extern struct clock_init_data fsm9xxx_clock_init_data;
+extern struct clock_init_data msm7x01a_clock_init_data;
+extern struct clock_init_data msm7x27_clock_init_data;
+extern struct clock_init_data msm7x27a_clock_init_data;
+extern struct clock_init_data msm7x30_clock_init_data;
+extern struct clock_init_data msm8960_clock_init_data;
+extern struct clock_init_data msm8x60_clock_init_data;
+extern struct clock_init_data qds8x50_clock_init_data;
+extern struct clock_init_data msm8625_dummy_clock_init_data;
+extern struct clock_init_data msm8930_clock_init_data;
+extern struct clock_init_data msmcopper_clock_init_data;
+
+void msm_clock_init(struct clock_init_data *data);
+int vote_vdd_level(struct clk_vdd_class *vdd_class, int level);
+int unvote_vdd_level(struct clk_vdd_class *vdd_class, int level);
 
 #ifdef CONFIG_DEBUG_FS
-int __init clock_debug_init(void);
-int __init clock_debug_add(struct clk *clock);
+int clock_debug_init(struct clock_init_data *data);
+int clock_debug_add(struct clk *clock);
+void clock_debug_print_enabled(void);
 #else
-static inline int __init clock_debug_init(void) { return 0; }
-static inline int __init clock_debug_add(struct clk *clock) { return 0; }
+static inline int clock_debug_init(struct clk_init_data *data) { return 0; }
+static inline int clock_debug_add(struct clk *clock) { return 0; }
+static inline void clock_debug_print_enabled(void) { return; }
 #endif
 
+extern struct clk dummy_clk;
+
+#define CLK_DUMMY(clk_name, clk_id, clk_dev, flags) { \
+	.con_id = clk_name, \
+	.dev_id = clk_dev, \
+	.clk = &dummy_clk, \
+	}
+
+#define CLK_LOOKUP(con, c, dev) { .con_id = con, .clk = &c, .dev_id = dev }
+
 #endif
+
diff --git a/arch/arm/mach-msm/cp14.h b/arch/arm/mach-msm/cp14.h
new file mode 100644
index 0000000..d640412
--- /dev/null
+++ b/arch/arm/mach-msm/cp14.h
@@ -0,0 +1,540 @@
+/* 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
+ * 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 _ARCH_ARM_MACH_MSM_CP14_H_
+#define _ARCH_ARM_MACH_MSM_CP14_H_
+
+#include <linux/types.h>
+
+/* Accessors for CP14 registers */
+#define dbg_read(reg)			RCP14_##reg()
+#define dbg_write(val, reg)		WCP14_##reg(val)
+#define etm_read(reg)			RCP14_##reg()
+#define etm_write(val, reg)		WCP14_##reg(val)
+
+/* MRC14 and MCR14 */
+#define MRC14(op1, crn, crm, op2)					\
+({									\
+uint32_t val;								\
+asm volatile("mrc p14, "#op1", %0, "#crn", "#crm", "#op2 : "=r" (val));	\
+val;									\
+})
+
+#define MCR14(val, op1, crn, crm, op2)					\
+({									\
+asm volatile("mcr p14, "#op1", %0, "#crn", "#crm", "#op2 : : "r" (val));\
+})
+
+/* Debug Registers
+ *
+ * Available only in DBGv7
+ * DBGECR, DBGDSCCR, DBGDSMCR, DBGDRCR
+ *
+ * Available only in DBGv7.1
+ * DBGBXVRm, DBGOSDLR, DBGDEVID2, DBGDEVID1
+ *
+ * Read only
+ * DBGDIDR, DBGDSCRint, DBGDTRRXint, DBGDRAR, DBGOSLSR, DBGOSSRR, DBGPRSR,
+ * DBGPRSR, DBGDSAR, DBGAUTHSTATUS, DBGDEVID2, DBGDEVID1, DBGDEVID
+ *
+ * Write only
+ * DBGDTRTXint, DBGOSLAR
+ */
+#define RCP14_DBGDIDR()			MRC14(0, c0, c0, 0)
+#define RCP14_DBGDSCRint()		MRC14(0, c0, c1, 0)
+#define RCP14_DBGDTRRXint()		MRC14(0, c0, c5, 0)
+#define RCP14_DBGWFAR()			MRC14(0, c0, c6, 0)
+#define RCP14_DBGVCR()			MRC14(0, c0, c7, 0)
+#define RCP14_DBGECR()			MRC14(0, c0, c9, 0)
+#define RCP14_DBGDSCCR()		MRC14(0, c0, c10, 0)
+#define RCP14_DBGDSMCR()		MRC14(0, c0, c11, 0)
+#define RCP14_DBGDTRRXext()		MRC14(0, c0, c0, 2)
+#define RCP14_DBGDSCRext()		MRC14(0, c0, c2, 2)
+#define RCP14_DBGDTRTXext()		MRC14(0, c0, c3, 2)
+#define RCP14_DBGDRCR()			MRC14(0, c0, c4, 2)
+#define RCP14_DBGBVR0()			MRC14(0, c0, c0, 4)
+#define RCP14_DBGBVR1()			MRC14(0, c0, c1, 4)
+#define RCP14_DBGBVR2()			MRC14(0, c0, c2, 4)
+#define RCP14_DBGBVR3()			MRC14(0, c0, c3, 4)
+#define RCP14_DBGBVR4()			MRC14(0, c0, c4, 4)
+#define RCP14_DBGBVR5()			MRC14(0, c0, c5, 4)
+#define RCP14_DBGBVR6()			MRC14(0, c0, c6, 4)
+#define RCP14_DBGBVR7()			MRC14(0, c0, c7, 4)
+#define RCP14_DBGBVR8()			MRC14(0, c0, c8, 4)
+#define RCP14_DBGBVR9()			MRC14(0, c0, c9, 4)
+#define RCP14_DBGBVR10()		MRC14(0, c0, c10, 4)
+#define RCP14_DBGBVR11()		MRC14(0, c0, c11, 4)
+#define RCP14_DBGBVR12()		MRC14(0, c0, c12, 4)
+#define RCP14_DBGBVR13()		MRC14(0, c0, c13, 4)
+#define RCP14_DBGBVR14()		MRC14(0, c0, c14, 4)
+#define RCP14_DBGBVR15()		MRC14(0, c0, c15, 4)
+#define RCP14_DBGBCR0()			MRC14(0, c0, c0, 5)
+#define RCP14_DBGBCR1()			MRC14(0, c0, c1, 5)
+#define RCP14_DBGBCR2()			MRC14(0, c0, c2, 5)
+#define RCP14_DBGBCR3()			MRC14(0, c0, c3, 5)
+#define RCP14_DBGBCR4()			MRC14(0, c0, c4, 5)
+#define RCP14_DBGBCR5()			MRC14(0, c0, c5, 5)
+#define RCP14_DBGBCR6()			MRC14(0, c0, c6, 5)
+#define RCP14_DBGBCR7()			MRC14(0, c0, c7, 5)
+#define RCP14_DBGBCR8()			MRC14(0, c0, c8, 5)
+#define RCP14_DBGBCR9()			MRC14(0, c0, c9, 5)
+#define RCP14_DBGBCR10()		MRC14(0, c0, c10, 5)
+#define RCP14_DBGBCR11()		MRC14(0, c0, c11, 5)
+#define RCP14_DBGBCR12()		MRC14(0, c0, c12, 5)
+#define RCP14_DBGBCR13()		MRC14(0, c0, c13, 5)
+#define RCP14_DBGBCR14()		MRC14(0, c0, c14, 5)
+#define RCP14_DBGBCR15()		MRC14(0, c0, c15, 5)
+#define RCP14_DBGWVR0()			MRC14(0, c0, c0, 6)
+#define RCP14_DBGWVR1()			MRC14(0, c0, c1, 6)
+#define RCP14_DBGWVR2()			MRC14(0, c0, c2, 6)
+#define RCP14_DBGWVR3()			MRC14(0, c0, c3, 6)
+#define RCP14_DBGWVR4()			MRC14(0, c0, c4, 6)
+#define RCP14_DBGWVR5()			MRC14(0, c0, c5, 6)
+#define RCP14_DBGWVR6()			MRC14(0, c0, c6, 6)
+#define RCP14_DBGWVR7()			MRC14(0, c0, c7, 6)
+#define RCP14_DBGWVR8()			MRC14(0, c0, c8, 6)
+#define RCP14_DBGWVR9()			MRC14(0, c0, c9, 6)
+#define RCP14_DBGWVR10()		MRC14(0, c0, c10, 6)
+#define RCP14_DBGWVR11()		MRC14(0, c0, c11, 6)
+#define RCP14_DBGWVR12()		MRC14(0, c0, c12, 6)
+#define RCP14_DBGWVR13()		MRC14(0, c0, c13, 6)
+#define RCP14_DBGWVR14()		MRC14(0, c0, c14, 6)
+#define RCP14_DBGWVR15()		MRC14(0, c0, c15, 6)
+#define RCP14_DBGWCR0()			MRC14(0, c0, c0, 7)
+#define RCP14_DBGWCR1()			MRC14(0, c0, c1, 7)
+#define RCP14_DBGWCR2()			MRC14(0, c0, c2, 7)
+#define RCP14_DBGWCR3()			MRC14(0, c0, c3, 7)
+#define RCP14_DBGWCR4()			MRC14(0, c0, c4, 7)
+#define RCP14_DBGWCR5()			MRC14(0, c0, c5, 7)
+#define RCP14_DBGWCR6()			MRC14(0, c0, c6, 7)
+#define RCP14_DBGWCR7()			MRC14(0, c0, c7, 7)
+#define RCP14_DBGWCR8()			MRC14(0, c0, c8, 7)
+#define RCP14_DBGWCR9()			MRC14(0, c0, c9, 7)
+#define RCP14_DBGWCR10()		MRC14(0, c0, c10, 7)
+#define RCP14_DBGWCR11()		MRC14(0, c0, c11, 7)
+#define RCP14_DBGWCR12()		MRC14(0, c0, c12, 7)
+#define RCP14_DBGWCR13()		MRC14(0, c0, c13, 7)
+#define RCP14_DBGWCR14()		MRC14(0, c0, c14, 7)
+#define RCP14_DBGWCR15()		MRC14(0, c0, c15, 7)
+#define RCP14_DBGDRAR()			MRC14(0, c1, c0, 0)
+#define RCP14_DBGBXVR0()		MRC14(0, c1, c0, 1)
+#define RCP14_DBGBXVR1()		MRC14(0, c1, c1, 1)
+#define RCP14_DBGBXVR2()		MRC14(0, c1, c2, 1)
+#define RCP14_DBGBXVR3()		MRC14(0, c1, c3, 1)
+#define RCP14_DBGBXVR4()		MRC14(0, c1, c4, 1)
+#define RCP14_DBGBXVR5()		MRC14(0, c1, c5, 1)
+#define RCP14_DBGBXVR6()		MRC14(0, c1, c6, 1)
+#define RCP14_DBGBXVR7()		MRC14(0, c1, c7, 1)
+#define RCP14_DBGBXVR8()		MRC14(0, c1, c8, 1)
+#define RCP14_DBGBXVR9()		MRC14(0, c1, c9, 1)
+#define RCP14_DBGBXVR10()		MRC14(0, c1, c10, 1)
+#define RCP14_DBGBXVR11()		MRC14(0, c1, c11, 1)
+#define RCP14_DBGBXVR12()		MRC14(0, c1, c12, 1)
+#define RCP14_DBGBXVR13()		MRC14(0, c1, c13, 1)
+#define RCP14_DBGBXVR14()		MRC14(0, c1, c14, 1)
+#define RCP14_DBGBXVR15()		MRC14(0, c1, c15, 1)
+#define RCP14_DBGOSLSR()		MRC14(0, c1, c1, 4)
+#define RCP14_DBGOSSRR()		MRC14(0, c1, c2, 4)
+#define RCP14_DBGOSDLR()		MRC14(0, c1, c3, 4)
+#define RCP14_DBGPRCR()			MRC14(0, c1, c4, 4)
+#define RCP14_DBGPRSR()			MRC14(0, c1, c5, 4)
+#define RCP14_DBGDSAR()			MRC14(0, c2, c0, 0)
+#define RCP14_DBGITCTRL()		MRC14(0, c7, c0, 4)
+#define RCP14_DBGCLAIMSET()		MRC14(0, c7, c8, 6)
+#define RCP14_DBGCLAIMCLR()		MRC14(0, c7, c9, 6)
+#define RCP14_DBGAUTHSTATUS()		MRC14(0, c7, c14, 6)
+#define RCP14_DBGDEVID2()		MRC14(0, c7, c0, 7)
+#define RCP14_DBGDEVID1()		MRC14(0, c7, c1, 7)
+#define RCP14_DBGDEVID()		MRC14(0, c7, c2, 7)
+
+#define WCP14_DBGDTRTXint(val)		MCR14(val, 0, c0, c5, 0)
+#define WCP14_DBGWFAR(val)		MCR14(val, 0, c0, c6, 0)
+#define WCP14_DBGVCR(val)		MCR14(val, 0, c0, c7, 0)
+#define WCP14_DBGECR(val)		MCR14(val, 0, c0, c9, 0)
+#define WCP14_DBGDSCCR(val)		MCR14(val, 0, c0, c10, 0)
+#define WCP14_DBGDSMCR(val)		MCR14(val, 0, c0, c11, 0)
+#define WCP14_DBGDTRRXext(val)		MCR14(val, 0, c0, c0, 2)
+#define WCP14_DBGDSCRext(val)		MCR14(val, 0, c0, c2, 2)
+#define WCP14_DBGDTRTXext(val)		MCR14(val, 0, c0, c3, 2)
+#define WCP14_DBGDRCR(val)		MCR14(val, 0, c0, c4, 2)
+#define WCP14_DBGBVR0(val)		MCR14(val, 0, c0, c0, 4)
+#define WCP14_DBGBVR1(val)		MCR14(val, 0, c0, c1, 4)
+#define WCP14_DBGBVR2(val)		MCR14(val, 0, c0, c2, 4)
+#define WCP14_DBGBVR3(val)		MCR14(val, 0, c0, c3, 4)
+#define WCP14_DBGBVR4(val)		MCR14(val, 0, c0, c4, 4)
+#define WCP14_DBGBVR5(val)		MCR14(val, 0, c0, c5, 4)
+#define WCP14_DBGBVR6(val)		MCR14(val, 0, c0, c6, 4)
+#define WCP14_DBGBVR7(val)		MCR14(val, 0, c0, c7, 4)
+#define WCP14_DBGBVR8(val)		MCR14(val, 0, c0, c8, 4)
+#define WCP14_DBGBVR9(val)		MCR14(val, 0, c0, c9, 4)
+#define WCP14_DBGBVR10(val)		MCR14(val, 0, c0, c10, 4)
+#define WCP14_DBGBVR11(val)		MCR14(val, 0, c0, c11, 4)
+#define WCP14_DBGBVR12(val)		MCR14(val, 0, c0, c12, 4)
+#define WCP14_DBGBVR13(val)		MCR14(val, 0, c0, c13, 4)
+#define WCP14_DBGBVR14(val)		MCR14(val, 0, c0, c14, 4)
+#define WCP14_DBGBVR15(val)		MCR14(val, 0, c0, c15, 4)
+#define WCP14_DBGBCR0(val)		MCR14(val, 0, c0, c0, 5)
+#define WCP14_DBGBCR1(val)		MCR14(val, 0, c0, c1, 5)
+#define WCP14_DBGBCR2(val)		MCR14(val, 0, c0, c2, 5)
+#define WCP14_DBGBCR3(val)		MCR14(val, 0, c0, c3, 5)
+#define WCP14_DBGBCR4(val)		MCR14(val, 0, c0, c4, 5)
+#define WCP14_DBGBCR5(val)		MCR14(val, 0, c0, c5, 5)
+#define WCP14_DBGBCR6(val)		MCR14(val, 0, c0, c6, 5)
+#define WCP14_DBGBCR7(val)		MCR14(val, 0, c0, c7, 5)
+#define WCP14_DBGBCR8(val)		MCR14(val, 0, c0, c8, 5)
+#define WCP14_DBGBCR9(val)		MCR14(val, 0, c0, c9, 5)
+#define WCP14_DBGBCR10(val)		MCR14(val, 0, c0, c10, 5)
+#define WCP14_DBGBCR11(val)		MCR14(val, 0, c0, c11, 5)
+#define WCP14_DBGBCR12(val)		MCR14(val, 0, c0, c12, 5)
+#define WCP14_DBGBCR13(val)		MCR14(val, 0, c0, c13, 5)
+#define WCP14_DBGBCR14(val)		MCR14(val, 0, c0, c14, 5)
+#define WCP14_DBGBCR15(val)		MCR14(val, 0, c0, c15, 5)
+#define WCP14_DBGWVR0(val)		MCR14(val, 0, c0, c0, 6)
+#define WCP14_DBGWVR1(val)		MCR14(val, 0, c0, c1, 6)
+#define WCP14_DBGWVR2(val)		MCR14(val, 0, c0, c2, 6)
+#define WCP14_DBGWVR3(val)		MCR14(val, 0, c0, c3, 6)
+#define WCP14_DBGWVR4(val)		MCR14(val, 0, c0, c4, 6)
+#define WCP14_DBGWVR5(val)		MCR14(val, 0, c0, c5, 6)
+#define WCP14_DBGWVR6(val)		MCR14(val, 0, c0, c6, 6)
+#define WCP14_DBGWVR7(val)		MCR14(val, 0, c0, c7, 6)
+#define WCP14_DBGWVR8(val)		MCR14(val, 0, c0, c8, 6)
+#define WCP14_DBGWVR9(val)		MCR14(val, 0, c0, c9, 6)
+#define WCP14_DBGWVR10(val)		MCR14(val, 0, c0, c10, 6)
+#define WCP14_DBGWVR11(val)		MCR14(val, 0, c0, c11, 6)
+#define WCP14_DBGWVR12(val)		MCR14(val, 0, c0, c12, 6)
+#define WCP14_DBGWVR13(val)		MCR14(val, 0, c0, c13, 6)
+#define WCP14_DBGWVR14(val)		MCR14(val, 0, c0, c14, 6)
+#define WCP14_DBGWVR15(val)		MCR14(val, 0, c0, c15, 6)
+#define WCP14_DBGWCR0(val)		MCR14(val, 0, c0, c0, 7)
+#define WCP14_DBGWCR1(val)		MCR14(val, 0, c0, c1, 7)
+#define WCP14_DBGWCR2(val)		MCR14(val, 0, c0, c2, 7)
+#define WCP14_DBGWCR3(val)		MCR14(val, 0, c0, c3, 7)
+#define WCP14_DBGWCR4(val)		MCR14(val, 0, c0, c4, 7)
+#define WCP14_DBGWCR5(val)		MCR14(val, 0, c0, c5, 7)
+#define WCP14_DBGWCR6(val)		MCR14(val, 0, c0, c6, 7)
+#define WCP14_DBGWCR7(val)		MCR14(val, 0, c0, c7, 7)
+#define WCP14_DBGWCR8(val)		MCR14(val, 0, c0, c8, 7)
+#define WCP14_DBGWCR9(val)		MCR14(val, 0, c0, c9, 7)
+#define WCP14_DBGWCR10(val)		MCR14(val, 0, c0, c10, 7)
+#define WCP14_DBGWCR11(val)		MCR14(val, 0, c0, c11, 7)
+#define WCP14_DBGWCR12(val)		MCR14(val, 0, c0, c12, 7)
+#define WCP14_DBGWCR13(val)		MCR14(val, 0, c0, c13, 7)
+#define WCP14_DBGWCR14(val)		MCR14(val, 0, c0, c14, 7)
+#define WCP14_DBGWCR15(val)		MCR14(val, 0, c0, c15, 7)
+#define WCP14_DBGBXVR0(val)		MCR14(val, 0, c1, c0, 1)
+#define WCP14_DBGBXVR1(val)		MCR14(val, 0, c1, c1, 1)
+#define WCP14_DBGBXVR2(val)		MCR14(val, 0, c1, c2, 1)
+#define WCP14_DBGBXVR3(val)		MCR14(val, 0, c1, c3, 1)
+#define WCP14_DBGBXVR4(val)		MCR14(val, 0, c1, c4, 1)
+#define WCP14_DBGBXVR5(val)		MCR14(val, 0, c1, c5, 1)
+#define WCP14_DBGBXVR6(val)		MCR14(val, 0, c1, c6, 1)
+#define WCP14_DBGBXVR7(val)		MCR14(val, 0, c1, c7, 1)
+#define WCP14_DBGBXVR8(val)		MCR14(val, 0, c1, c8, 1)
+#define WCP14_DBGBXVR9(val)		MCR14(val, 0, c1, c9, 1)
+#define WCP14_DBGBXVR10(val)		MCR14(val, 0, c1, c10, 1)
+#define WCP14_DBGBXVR11(val)		MCR14(val, 0, c1, c11, 1)
+#define WCP14_DBGBXVR12(val)		MCR14(val, 0, c1, c12, 1)
+#define WCP14_DBGBXVR13(val)		MCR14(val, 0, c1, c13, 1)
+#define WCP14_DBGBXVR14(val)		MCR14(val, 0, c1, c14, 1)
+#define WCP14_DBGBXVR15(val)		MCR14(val, 0, c1, c15, 1)
+#define WCP14_DBGOSLAR(val)		MCR14(val, 0, c1, c0, 4)
+#define WCP14_DBGOSSRR(val)		MCR14(val, 0, c1, c2, 4)
+#define WCP14_DBGOSDLR(val)		MCR14(val, 0, c1, c3, 4)
+#define WCP14_DBGPRCR(val)		MCR14(val, 0, c1, c4, 4)
+#define WCP14_DBGITCTRL(val)		MCR14(val, 0, c7, c0, 4)
+#define WCP14_DBGCLAIMSET(val)		MCR14(val, 0, c7, c8, 6)
+#define WCP14_DBGCLAIMCLR(val)		MCR14(val, 0, c7, c9, 6)
+
+/* ETM Registers
+ *
+ * Available only in ETMv3.3, 3.4, 3.5
+ * ETMASICCR, ETMTECR2, ETMFFRR, ETMVDEVR, ETMVDCR1, ETMVDCR2, ETMVDCR3,
+ * ETMDCVRn, ETMDCMRn
+ *
+ * Available only in ETMv3.5 as read only
+ * ETMIDR2
+ *
+ * Available only in ETMv3.5, PFTv1.0, 1.1
+ * ETMTSEVR, ETMVMIDCVR, ETMPDCR
+ *
+ * Read only
+ * ETMCCR, ETMSCR, ETMIDR, ETMCCER, ETMOSLSR
+ * ETMLSR, ETMAUTHSTATUS, ETMDEVID, ETMDEVTYPE, ETMPIDR4, ETMPIDR5, ETMPIDR6,
+ * ETMPIDR7, ETMPIDR0, ETMPIDR1, ETMPIDR2, ETMPIDR2, ETMPIDR3, ETMCIDR0,
+ * ETMCIDR1, ETMCIDR2, ETMCIDR3
+ *
+ * Write only
+ * ETMOSLAR, ETMLAR
+ * Note: ETMCCER[11] controls WO nature of certain regs. Refer ETM arch spec.
+ */
+#define RCP14_ETMCR()			MRC14(1, c0, c0, 0)
+#define RCP14_ETMCCR()			MRC14(1, c0, c1, 0)
+#define RCP14_ETMTRIGGER()		MRC14(1, c0, c2, 0)
+#define RCP14_ETMASICCR()		MRC14(1, c0, c3, 0)
+#define RCP14_ETMSR()			MRC14(1, c0, c4, 0)
+#define RCP14_ETMSCR()			MRC14(1, c0, c5, 0)
+#define RCP14_ETMTSSCR()		MRC14(1, c0, c6, 0)
+#define RCP14_ETMTECR2()		MRC14(1, c0, c7, 0)
+#define RCP14_ETMTEEVR()		MRC14(1, c0, c8, 0)
+#define RCP14_ETMTECR1()		MRC14(1, c0, c9, 0)
+#define RCP14_ETMFFRR()			MRC14(1, c0, c10, 0)
+#define RCP14_ETMFFLR()			MRC14(1, c0, c11, 0)
+#define RCP14_ETMVDEVR()		MRC14(1, c0, c12, 0)
+#define RCP14_ETMVDCR1()		MRC14(1, c0, c13, 0)
+#define RCP14_ETMVDCR2()		MRC14(1, c0, c14, 0)
+#define RCP14_ETMVDCR3()		MRC14(1, c0, c15, 0)
+#define RCP14_ETMACVR0()		MRC14(1, c0, c0, 1)
+#define RCP14_ETMACVR1()		MRC14(1, c0, c1, 1)
+#define RCP14_ETMACVR2()		MRC14(1, c0, c2, 1)
+#define RCP14_ETMACVR3()		MRC14(1, c0, c3, 1)
+#define RCP14_ETMACVR4()		MRC14(1, c0, c4, 1)
+#define RCP14_ETMACVR5()		MRC14(1, c0, c5, 1)
+#define RCP14_ETMACVR6()		MRC14(1, c0, c6, 1)
+#define RCP14_ETMACVR7()		MRC14(1, c0, c7, 1)
+#define RCP14_ETMACVR8()		MRC14(1, c0, c8, 1)
+#define RCP14_ETMACVR9()		MRC14(1, c0, c9, 1)
+#define RCP14_ETMACVR10()		MRC14(1, c0, c10, 1)
+#define RCP14_ETMACVR11()		MRC14(1, c0, c11, 1)
+#define RCP14_ETMACVR12()		MRC14(1, c0, c12, 1)
+#define RCP14_ETMACVR13()		MRC14(1, c0, c13, 1)
+#define RCP14_ETMACVR14()		MRC14(1, c0, c14, 1)
+#define RCP14_ETMACVR15()		MRC14(1, c0, c15, 1)
+#define RCP14_ETMACTR0()		MRC14(1, c0, c0, 2)
+#define RCP14_ETMACTR1()		MRC14(1, c0, c1, 2)
+#define RCP14_ETMACTR2()		MRC14(1, c0, c2, 2)
+#define RCP14_ETMACTR3()		MRC14(1, c0, c3, 2)
+#define RCP14_ETMACTR4()		MRC14(1, c0, c4, 2)
+#define RCP14_ETMACTR5()		MRC14(1, c0, c5, 2)
+#define RCP14_ETMACTR6()		MRC14(1, c0, c6, 2)
+#define RCP14_ETMACTR7()		MRC14(1, c0, c7, 2)
+#define RCP14_ETMACTR8()		MRC14(1, c0, c8, 2)
+#define RCP14_ETMACTR9()		MRC14(1, c0, c9, 2)
+#define RCP14_ETMACTR10()		MRC14(1, c0, c10, 2)
+#define RCP14_ETMACTR11()		MRC14(1, c0, c11, 2)
+#define RCP14_ETMACTR12()		MRC14(1, c0, c12, 2)
+#define RCP14_ETMACTR13()		MRC14(1, c0, c13, 2)
+#define RCP14_ETMACTR14()		MRC14(1, c0, c14, 2)
+#define RCP14_ETMACTR15()		MRC14(1, c0, c15, 2)
+#define RCP14_ETMDCVR0()		MRC14(1, c0, c0, 3)
+#define RCP14_ETMDCVR2()		MRC14(1, c0, c2, 3)
+#define RCP14_ETMDCVR4()		MRC14(1, c0, c4, 3)
+#define RCP14_ETMDCVR6()		MRC14(1, c0, c6, 3)
+#define RCP14_ETMDCVR8()		MRC14(1, c0, c8, 3)
+#define RCP14_ETMDCVR10()		MRC14(1, c0, c10, 3)
+#define RCP14_ETMDCVR12()		MRC14(1, c0, c12, 3)
+#define RCP14_ETMDCVR14()		MRC14(1, c0, c14, 3)
+#define RCP14_ETMDCMR0()		MRC14(1, c0, c0, 4)
+#define RCP14_ETMDCMR2()		MRC14(1, c0, c2, 4)
+#define RCP14_ETMDCMR4()		MRC14(1, c0, c4, 4)
+#define RCP14_ETMDCMR6()		MRC14(1, c0, c6, 4)
+#define RCP14_ETMDCMR8()		MRC14(1, c0, c8, 4)
+#define RCP14_ETMDCMR10()		MRC14(1, c0, c10, 4)
+#define RCP14_ETMDCMR12()		MRC14(1, c0, c12, 4)
+#define RCP14_ETMDCMR14()		MRC14(1, c0, c14, 4)
+#define RCP14_ETMCNTRLDVR0()		MRC14(1, c0, c0, 5)
+#define RCP14_ETMCNTRLDVR1()		MRC14(1, c0, c1, 5)
+#define RCP14_ETMCNTRLDVR2()		MRC14(1, c0, c2, 5)
+#define RCP14_ETMCNTRLDVR3()		MRC14(1, c0, c3, 5)
+#define RCP14_ETMCNTENR0()		MRC14(1, c0, c4, 5)
+#define RCP14_ETMCNTENR1()		MRC14(1, c0, c5, 5)
+#define RCP14_ETMCNTENR2()		MRC14(1, c0, c6, 5)
+#define RCP14_ETMCNTENR3()		MRC14(1, c0, c7, 5)
+#define RCP14_ETMCNTRLDEVR0()		MRC14(1, c0, c8, 5)
+#define RCP14_ETMCNTRLDEVR1()		MRC14(1, c0, c9, 5)
+#define RCP14_ETMCNTRLDEVR2()		MRC14(1, c0, c10, 5)
+#define RCP14_ETMCNTRLDEVR3()		MRC14(1, c0, c11, 5)
+#define RCP14_ETMCNTVR0()		MRC14(1, c0, c12, 5)
+#define RCP14_ETMCNTVR1()		MRC14(1, c0, c13, 5)
+#define RCP14_ETMCNTVR2()		MRC14(1, c0, c14, 5)
+#define RCP14_ETMCNTVR3()		MRC14(1, c0, c15, 5)
+#define RCP14_ETMSQ12EVR()		MRC14(1, c0, c0, 6)
+#define RCP14_ETMSQ21EVR()		MRC14(1, c0, c1, 6)
+#define RCP14_ETMSQ23EVR()		MRC14(1, c0, c2, 6)
+#define RCP14_ETMSQ31EVR()		MRC14(1, c0, c3, 6)
+#define RCP14_ETMSQ32EVR()		MRC14(1, c0, c4, 6)
+#define RCP14_ETMSQ13EVR()		MRC14(1, c0, c5, 6)
+#define RCP14_ETMSQR()			MRC14(1, c0, c7, 6)
+#define RCP14_ETMEXTOUTEVR0()		MRC14(1, c0, c8, 6)
+#define RCP14_ETMEXTOUTEVR1()		MRC14(1, c0, c9, 6)
+#define RCP14_ETMEXTOUTEVR2()		MRC14(1, c0, c10, 6)
+#define RCP14_ETMEXTOUTEVR3()		MRC14(1, c0, c11, 6)
+#define RCP14_ETMCIDCVR0()		MRC14(1, c0, c12, 6)
+#define RCP14_ETMCIDCVR1()		MRC14(1, c0, c13, 6)
+#define RCP14_ETMCIDCVR2()		MRC14(1, c0, c14, 6)
+#define RCP14_ETMCIDCMR()		MRC14(1, c0, c15, 6)
+#define RCP14_ETMIMPSPEC0()		MRC14(1, c0, c0, 7)
+#define RCP14_ETMIMPSPEC1()		MRC14(1, c0, c1, 7)
+#define RCP14_ETMIMPSPEC2()		MRC14(1, c0, c2, 7)
+#define RCP14_ETMIMPSPEC3()		MRC14(1, c0, c3, 7)
+#define RCP14_ETMIMPSPEC4()		MRC14(1, c0, c4, 7)
+#define RCP14_ETMIMPSPEC5()		MRC14(1, c0, c5, 7)
+#define RCP14_ETMIMPSPEC6()		MRC14(1, c0, c6, 7)
+#define RCP14_ETMIMPSPEC7()		MRC14(1, c0, c7, 7)
+#define RCP14_ETMSYNCFR()		MRC14(1, c0, c8, 7)
+#define RCP14_ETMIDR()			MRC14(1, c0, c9, 7)
+#define RCP14_ETMCCER()			MRC14(1, c0, c10, 7)
+#define RCP14_ETMEXTINSELR()		MRC14(1, c0, c11, 7)
+#define RCP14_ETMTESSEICR()		MRC14(1, c0, c12, 7)
+#define RCP14_ETMEIBCR()		MRC14(1, c0, c13, 7)
+#define RCP14_ETMTSEVR()		MRC14(1, c0, c14, 7)
+#define RCP14_ETMAUXCR()		MRC14(1, c0, c15, 7)
+#define RCP14_ETMTRACEIDR()		MRC14(1, c1, c0, 0)
+#define RCP14_ETMIDR2()			MRC14(1, c1, c2, 0)
+#define RCP14_ETMVMIDCVR()		MRC14(1, c1, c0, 1)
+#define RCP14_ETMOSLSR()		MRC14(1, c1, c1, 4)
+/* not available in PFTv1.1 */
+#define RCP14_ETMOSSRR()		MRC14(1, c1, c2, 4)
+#define RCP14_ETMPDCR()			MRC14(1, c1, c4, 4)
+#define RCP14_ETMPDSR()			MRC14(1, c1, c5, 4)
+#define RCP14_ETMITCTRL()		MRC14(1, c7, c0, 4)
+#define RCP14_ETMCLAIMSET()		MRC14(1, c7, c8, 6)
+#define RCP14_ETMCLAIMCLR()		MRC14(1, c7, c9, 6)
+#define RCP14_ETMLSR()			MRC14(1, c7, c13, 6)
+#define RCP14_ETMAUTHSTATUS()		MRC14(1, c7, c14, 6)
+#define RCP14_ETMDEVID()		MRC14(1, c7, c2, 7)
+#define RCP14_ETMDEVTYPE()		MRC14(1, c7, c3, 7)
+#define RCP14_ETMPIDR4()		MRC14(1, c7, c4, 7)
+#define RCP14_ETMPIDR5()		MRC14(1, c7, c5, 7)
+#define RCP14_ETMPIDR6()		MRC14(1, c7, c6, 7)
+#define RCP14_ETMPIDR7()		MRC14(1, c7, c7, 7)
+#define RCP14_ETMPIDR0()		MRC14(1, c7, c8, 7)
+#define RCP14_ETMPIDR1()		MRC14(1, c7, c9, 7)
+#define RCP14_ETMPIDR2()		MRC14(1, c7, c10, 7)
+#define RCP14_ETMPIDR3()		MRC14(1, c7, c11, 7)
+#define RCP14_ETMCIDR0()		MRC14(1, c7, c12, 7)
+#define RCP14_ETMCIDR1()		MRC14(1, c7, c13, 7)
+#define RCP14_ETMCIDR2()		MRC14(1, c7, c14, 7)
+#define RCP14_ETMCIDR3()		MRC14(1, c7, c15, 7)
+
+#define WCP14_ETMCR(val)		MCR14(val, 1, c0, c0, 0)
+#define WCP14_ETMTRIGGER(val)		MCR14(val, 1, c0, c2, 0)
+#define WCP14_ETMASICCR(val)		MCR14(val, 1, c0, c3, 0)
+#define WCP14_ETMSR(val)		MCR14(val, 1, c0, c4, 0)
+#define WCP14_ETMTSSCR(val)		MCR14(val, 1, c0, c6, 0)
+#define WCP14_ETMTECR2(val)		MCR14(val, 1, c0, c7, 0)
+#define WCP14_ETMTEEVR(val)		MCR14(val, 1, c0, c8, 0)
+#define WCP14_ETMTECR1(val)		MCR14(val, 1, c0, c9, 0)
+#define WCP14_ETMFFRR(val)		MCR14(val, 1, c0, c10, 0)
+#define WCP14_ETMFFLR(val)		MCR14(val, 1, c0, c11, 0)
+#define WCP14_ETMVDEVR(val)		MCR14(val, 1, c0, c12, 0)
+#define WCP14_ETMVDCR1(val)		MCR14(val, 1, c0, c13, 0)
+#define WCP14_ETMVDCR2(val)		MCR14(val, 1, c0, c14, 0)
+#define WCP14_ETMVDCR3(val)		MCR14(val, 1, c0, c15, 0)
+#define WCP14_ETMACVR0(val)		MCR14(val, 1, c0, c0, 1)
+#define WCP14_ETMACVR1(val)		MCR14(val, 1, c0, c1, 1)
+#define WCP14_ETMACVR2(val)		MCR14(val, 1, c0, c2, 1)
+#define WCP14_ETMACVR3(val)		MCR14(val, 1, c0, c3, 1)
+#define WCP14_ETMACVR4(val)		MCR14(val, 1, c0, c4, 1)
+#define WCP14_ETMACVR5(val)		MCR14(val, 1, c0, c5, 1)
+#define WCP14_ETMACVR6(val)		MCR14(val, 1, c0, c6, 1)
+#define WCP14_ETMACVR7(val)		MCR14(val, 1, c0, c7, 1)
+#define WCP14_ETMACVR8(val)		MCR14(val, 1, c0, c8, 1)
+#define WCP14_ETMACVR9(val)		MCR14(val, 1, c0, c9, 1)
+#define WCP14_ETMACVR10(val)		MCR14(val, 1, c0, c10, 1)
+#define WCP14_ETMACVR11(val)		MCR14(val, 1, c0, c11, 1)
+#define WCP14_ETMACVR12(val)		MCR14(val, 1, c0, c12, 1)
+#define WCP14_ETMACVR13(val)		MCR14(val, 1, c0, c13, 1)
+#define WCP14_ETMACVR14(val)		MCR14(val, 1, c0, c14, 1)
+#define WCP14_ETMACVR15(val)		MCR14(val, 1, c0, c15, 1)
+#define WCP14_ETMACTR0(val)		MCR14(val, 1, c0, c0, 2)
+#define WCP14_ETMACTR1(val)		MCR14(val, 1, c0, c1, 2)
+#define WCP14_ETMACTR2(val)		MCR14(val, 1, c0, c2, 2)
+#define WCP14_ETMACTR3(val)		MCR14(val, 1, c0, c3, 2)
+#define WCP14_ETMACTR4(val)		MCR14(val, 1, c0, c4, 2)
+#define WCP14_ETMACTR5(val)		MCR14(val, 1, c0, c5, 2)
+#define WCP14_ETMACTR6(val)		MCR14(val, 1, c0, c6, 2)
+#define WCP14_ETMACTR7(val)		MCR14(val, 1, c0, c7, 2)
+#define WCP14_ETMACTR8(val)		MCR14(val, 1, c0, c8, 2)
+#define WCP14_ETMACTR9(val)		MCR14(val, 1, c0, c9, 2)
+#define WCP14_ETMACTR10(val)		MCR14(val, 1, c0, c10, 2)
+#define WCP14_ETMACTR11(val)		MCR14(val, 1, c0, c11, 2)
+#define WCP14_ETMACTR12(val)		MCR14(val, 1, c0, c12, 2)
+#define WCP14_ETMACTR13(val)		MCR14(val, 1, c0, c13, 2)
+#define WCP14_ETMACTR14(val)		MCR14(val, 1, c0, c14, 2)
+#define WCP14_ETMACTR15(val)		MCR14(val, 1, c0, c15, 2)
+#define WCP14_ETMDCVR0(val)		MCR14(val, 1, c0, c0, 3)
+#define WCP14_ETMDCVR2(val)		MCR14(val, 1, c0, c2, 3)
+#define WCP14_ETMDCVR4(val)		MCR14(val, 1, c0, c4, 3)
+#define WCP14_ETMDCVR6(val)		MCR14(val, 1, c0, c6, 3)
+#define WCP14_ETMDCVR8(val)		MCR14(val, 1, c0, c8, 3)
+#define WCP14_ETMDCVR10(val)		MCR14(val, 1, c0, c10, 3)
+#define WCP14_ETMDCVR12(val)		MCR14(val, 1, c0, c12, 3)
+#define WCP14_ETMDCVR14(val)		MCR14(val, 1, c0, c14, 3)
+#define WCP14_ETMDCMR0(val)		MCR14(val, 1, c0, c0, 4)
+#define WCP14_ETMDCMR2(val)		MCR14(val, 1, c0, c2, 4)
+#define WCP14_ETMDCMR4(val)		MCR14(val, 1, c0, c4, 4)
+#define WCP14_ETMDCMR6(val)		MCR14(val, 1, c0, c6, 4)
+#define WCP14_ETMDCMR8(val)		MCR14(val, 1, c0, c8, 4)
+#define WCP14_ETMDCMR10(val)		MCR14(val, 1, c0, c10, 4)
+#define WCP14_ETMDCMR12(val)		MCR14(val, 1, c0, c12, 4)
+#define WCP14_ETMDCMR14(val)		MCR14(val, 1, c0, c14, 4)
+#define WCP14_ETMCNTRLDVR0(val)		MCR14(val, 1, c0, c0, 5)
+#define WCP14_ETMCNTRLDVR1(val)		MCR14(val, 1, c0, c1, 5)
+#define WCP14_ETMCNTRLDVR2(val)		MCR14(val, 1, c0, c2, 5)
+#define WCP14_ETMCNTRLDVR3(val)		MCR14(val, 1, c0, c3, 5)
+#define WCP14_ETMCNTENR0(val)		MCR14(val, 1, c0, c4, 5)
+#define WCP14_ETMCNTENR1(val)		MCR14(val, 1, c0, c5, 5)
+#define WCP14_ETMCNTENR2(val)		MCR14(val, 1, c0, c6, 5)
+#define WCP14_ETMCNTENR3(val)		MCR14(val, 1, c0, c7, 5)
+#define WCP14_ETMCNTRLDEVR0(val)	MCR14(val, 1, c0, c8, 5)
+#define WCP14_ETMCNTRLDEVR1(val)	MCR14(val, 1, c0, c9, 5)
+#define WCP14_ETMCNTRLDEVR2(val)	MCR14(val, 1, c0, c10, 5)
+#define WCP14_ETMCNTRLDEVR3(val)	MCR14(val, 1, c0, c11, 5)
+#define WCP14_ETMCNTVR0(val)		MCR14(val, 1, c0, c12, 5)
+#define WCP14_ETMCNTVR1(val)		MCR14(val, 1, c0, c13, 5)
+#define WCP14_ETMCNTVR2(val)		MCR14(val, 1, c0, c14, 5)
+#define WCP14_ETMCNTVR3(val)		MCR14(val, 1, c0, c15, 5)
+#define WCP14_ETMSQ12EVR(val)		MCR14(val, 1, c0, c0, 6)
+#define WCP14_ETMSQ21EVR(val)		MCR14(val, 1, c0, c1, 6)
+#define WCP14_ETMSQ23EVR(val)		MCR14(val, 1, c0, c2, 6)
+#define WCP14_ETMSQ31EVR(val)		MCR14(val, 1, c0, c3, 6)
+#define WCP14_ETMSQ32EVR(val)		MCR14(val, 1, c0, c4, 6)
+#define WCP14_ETMSQ13EVR(val)		MCR14(val, 1, c0, c5, 6)
+#define WCP14_ETMSQR(val)		MCR14(val, 1, c0, c7, 6)
+#define WCP14_ETMEXTOUTEVR0(val)	MCR14(val, 1, c0, c8, 6)
+#define WCP14_ETMEXTOUTEVR1(val)	MCR14(val, 1, c0, c9, 6)
+#define WCP14_ETMEXTOUTEVR2(val)	MCR14(val, 1, c0, c10, 6)
+#define WCP14_ETMEXTOUTEVR3(val)	MCR14(val, 1, c0, c11, 6)
+#define WCP14_ETMCIDCVR0(val)		MCR14(val, 1, c0, c12, 6)
+#define WCP14_ETMCIDCVR1(val)		MCR14(val, 1, c0, c13, 6)
+#define WCP14_ETMCIDCVR2(val)		MCR14(val, 1, c0, c14, 6)
+#define WCP14_ETMCIDCMR(val)		MCR14(val, 1, c0, c15, 6)
+#define WCP14_ETMIMPSPEC0(val)		MCR14(val, 1, c0, c0, 7)
+#define WCP14_ETMIMPSPEC1(val)		MCR14(val, 1, c0, c1, 7)
+#define WCP14_ETMIMPSPEC2(val)		MCR14(val, 1, c0, c2, 7)
+#define WCP14_ETMIMPSPEC3(val)		MCR14(val, 1, c0, c3, 7)
+#define WCP14_ETMIMPSPEC4(val)		MCR14(val, 1, c0, c4, 7)
+#define WCP14_ETMIMPSPEC5(val)		MCR14(val, 1, c0, c5, 7)
+#define WCP14_ETMIMPSPEC6(val)		MCR14(val, 1, c0, c6, 7)
+#define WCP14_ETMIMPSPEC7(val)		MCR14(val, 1, c0, c7, 7)
+/* can be read only in ETMv3.4, ETMv3.5 */
+#define WCP14_ETMSYNCFR(val)		MCR14(val, 1, c0, c8, 7)
+#define WCP14_ETMEXTINSELR(val)		MCR14(val, 1, c0, c11, 7)
+#define WCP14_ETMTESSEICR(val)		MCR14(val, 1, c0, c12, 7)
+#define WCP14_ETMEIBCR(val)		MCR14(val, 1, c0, c13, 7)
+#define WCP14_ETMTSEVR(val)		MCR14(val, 1, c0, c14, 7)
+#define WCP14_ETMAUXCR(val)		MCR14(val, 1, c0, c15, 7)
+#define WCP14_ETMTRACEIDR(val)		MCR14(val, 1, c1, c0, 0)
+#define WCP14_ETMIDR2(val)		MCR14(val, 1, c1, c2, 0)
+#define WCP14_ETMVMIDCVR(val)		MCR14(val, 1, c1, c0, 1)
+#define WCP14_ETMOSLAR(val)		MCR14(val, 1, c1, c0, 4)
+/* not available in PFTv1.1 */
+#define WCP14_ETMOSSRR(val)		MCR14(val, 1, c1, c2, 4)
+#define WCP14_ETMPDCR(val)		MCR14(val, 1, c1, c4, 4)
+#define WCP14_ETMPDSR(val)		MCR14(val, 1, c1, c5, 4)
+#define WCP14_ETMITCTRL(val)		MCR14(val, 1, c7, c0, 4)
+#define WCP14_ETMCLAIMSET(val)		MCR14(val, 1, c7, c8, 6)
+#define WCP14_ETMCLAIMCLR(val)		MCR14(val, 1, c7, c9, 6)
+/* writes to this from CP14 interface are ignored */
+#define WCP14_ETMLAR(val)		MCR14(val, 1, c7, c12, 6)
+
+#endif
diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c
new file mode 100644
index 0000000..63534a4
--- /dev/null
+++ b/arch/arm/mach-msm/cpufreq.c
@@ -0,0 +1,303 @@
+/* arch/arm/mach-msm/cpufreq.c
+ *
+ * MSM architecture cpufreq driver
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2012, Code Aurora Forum. All rights reserved.
+ * Author: Mike A. Chan <mikechan@google.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/earlysuspend.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/workqueue.h>
+#include <linux/completion.h>
+#include <linux/cpu.h>
+#include <linux/cpumask.h>
+#include <linux/sched.h>
+#include <linux/suspend.h>
+#include <mach/socinfo.h>
+
+#include "acpuclock.h"
+
+#ifdef CONFIG_SMP
+struct cpufreq_work_struct {
+	struct work_struct work;
+	struct cpufreq_policy *policy;
+	struct completion complete;
+	int frequency;
+	int status;
+};
+
+static DEFINE_PER_CPU(struct cpufreq_work_struct, cpufreq_work);
+static struct workqueue_struct *msm_cpufreq_wq;
+#endif
+
+struct cpufreq_suspend_t {
+	struct mutex suspend_mutex;
+	int device_suspended;
+};
+
+static DEFINE_PER_CPU(struct cpufreq_suspend_t, cpufreq_suspend);
+
+static int set_cpu_freq(struct cpufreq_policy *policy, unsigned int new_freq)
+{
+	int ret = 0;
+	struct cpufreq_freqs freqs;
+
+	freqs.old = policy->cur;
+	freqs.new = new_freq;
+	freqs.cpu = policy->cpu;
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+	ret = acpuclk_set_rate(policy->cpu, new_freq, SETRATE_CPUFREQ);
+	if (!ret)
+		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+	return ret;
+}
+
+#ifdef CONFIG_SMP
+static void set_cpu_work(struct work_struct *work)
+{
+	struct cpufreq_work_struct *cpu_work =
+		container_of(work, struct cpufreq_work_struct, work);
+
+	cpu_work->status = set_cpu_freq(cpu_work->policy, cpu_work->frequency);
+	complete(&cpu_work->complete);
+}
+#endif
+
+static int msm_cpufreq_target(struct cpufreq_policy *policy,
+				unsigned int target_freq,
+				unsigned int relation)
+{
+	int ret = -EFAULT;
+	int index;
+	struct cpufreq_frequency_table *table;
+#ifdef CONFIG_SMP
+	struct cpufreq_work_struct *cpu_work = NULL;
+	cpumask_var_t mask;
+
+	if (!cpu_active(policy->cpu)) {
+		pr_info("cpufreq: cpu %d is not active.\n", policy->cpu);
+		return -ENODEV;
+	}
+
+	if (!alloc_cpumask_var(&mask, GFP_KERNEL))
+		return -ENOMEM;
+#endif
+
+	mutex_lock(&per_cpu(cpufreq_suspend, policy->cpu).suspend_mutex);
+
+	if (per_cpu(cpufreq_suspend, policy->cpu).device_suspended) {
+		pr_debug("cpufreq: cpu%d scheduling frequency change "
+				"in suspend.\n", policy->cpu);
+		ret = -EFAULT;
+		goto done;
+	}
+
+	table = cpufreq_frequency_get_table(policy->cpu);
+	if (cpufreq_frequency_table_target(policy, table, target_freq, relation,
+			&index)) {
+		pr_err("cpufreq: invalid target_freq: %d\n", target_freq);
+		ret = -EINVAL;
+		goto done;
+	}
+
+#ifdef CONFIG_CPU_FREQ_DEBUG
+	pr_debug("CPU[%d] target %d relation %d (%d-%d) selected %d\n",
+		policy->cpu, target_freq, relation,
+		policy->min, policy->max, table[index].frequency);
+#endif
+
+#ifdef CONFIG_SMP
+	cpu_work = &per_cpu(cpufreq_work, policy->cpu);
+	cpu_work->policy = policy;
+	cpu_work->frequency = table[index].frequency;
+	cpu_work->status = -ENODEV;
+
+	cpumask_clear(mask);
+	cpumask_set_cpu(policy->cpu, mask);
+	if (cpumask_equal(mask, &current->cpus_allowed)) {
+		ret = set_cpu_freq(cpu_work->policy, cpu_work->frequency);
+		goto done;
+	} else {
+		cancel_work_sync(&cpu_work->work);
+		INIT_COMPLETION(cpu_work->complete);
+		queue_work_on(policy->cpu, msm_cpufreq_wq, &cpu_work->work);
+		wait_for_completion(&cpu_work->complete);
+	}
+
+	ret = cpu_work->status;
+#else
+	ret = set_cpu_freq(policy, table[index].frequency);
+#endif
+
+done:
+#ifdef CONFIG_SMP
+	free_cpumask_var(mask);
+#endif
+	mutex_unlock(&per_cpu(cpufreq_suspend, policy->cpu).suspend_mutex);
+	return ret;
+}
+
+static int msm_cpufreq_verify(struct cpufreq_policy *policy)
+{
+	cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+			policy->cpuinfo.max_freq);
+	return 0;
+}
+
+static int __cpuinit msm_cpufreq_init(struct cpufreq_policy *policy)
+{
+	int cur_freq;
+	int index;
+	struct cpufreq_frequency_table *table;
+#ifdef CONFIG_SMP
+	struct cpufreq_work_struct *cpu_work = NULL;
+#endif
+
+
+	table = cpufreq_frequency_get_table(policy->cpu);
+	if (table == NULL)
+		return -ENODEV;
+	/*
+	 * In 8625 both cpu core's frequency can not
+	 * be changed independently. Each cpu is bound to
+	 * same frequency. Hence set the cpumask to all cpu.
+	 */
+	if (cpu_is_msm8625())
+		cpumask_setall(policy->cpus);
+
+	if (cpufreq_frequency_table_cpuinfo(policy, table)) {
+#ifdef CONFIG_MSM_CPU_FREQ_SET_MIN_MAX
+		policy->cpuinfo.min_freq = CONFIG_MSM_CPU_FREQ_MIN;
+		policy->cpuinfo.max_freq = CONFIG_MSM_CPU_FREQ_MAX;
+#endif
+	}
+#ifdef CONFIG_MSM_CPU_FREQ_SET_MIN_MAX
+	policy->min = CONFIG_MSM_CPU_FREQ_MIN;
+	policy->max = CONFIG_MSM_CPU_FREQ_MAX;
+#endif
+
+	cur_freq = acpuclk_get_rate(policy->cpu);
+	if (cpufreq_frequency_table_target(policy, table, cur_freq,
+	    CPUFREQ_RELATION_H, &index) &&
+	    cpufreq_frequency_table_target(policy, table, cur_freq,
+	    CPUFREQ_RELATION_L, &index)) {
+		pr_info("cpufreq: cpu%d at invalid freq: %d\n",
+				policy->cpu, cur_freq);
+		return -EINVAL;
+	}
+
+	if (cur_freq != table[index].frequency) {
+		int ret = 0;
+		ret = acpuclk_set_rate(policy->cpu, table[index].frequency,
+				SETRATE_CPUFREQ);
+		if (ret)
+			return ret;
+		pr_info("cpufreq: cpu%d init at %d switching to %d\n",
+				policy->cpu, cur_freq, table[index].frequency);
+		cur_freq = table[index].frequency;
+	}
+
+	policy->cur = cur_freq;
+
+	policy->cpuinfo.transition_latency =
+		acpuclk_get_switch_time() * NSEC_PER_USEC;
+#ifdef CONFIG_SMP
+	cpu_work = &per_cpu(cpufreq_work, policy->cpu);
+	INIT_WORK(&cpu_work->work, set_cpu_work);
+	init_completion(&cpu_work->complete);
+#endif
+
+	return 0;
+}
+
+static int msm_cpufreq_suspend(void)
+{
+	int cpu;
+
+	for_each_possible_cpu(cpu) {
+		mutex_lock(&per_cpu(cpufreq_suspend, cpu).suspend_mutex);
+		per_cpu(cpufreq_suspend, cpu).device_suspended = 1;
+		mutex_unlock(&per_cpu(cpufreq_suspend, cpu).suspend_mutex);
+	}
+
+	return NOTIFY_DONE;
+}
+
+static int msm_cpufreq_resume(void)
+{
+	int cpu;
+
+	for_each_possible_cpu(cpu) {
+		per_cpu(cpufreq_suspend, cpu).device_suspended = 0;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static int msm_cpufreq_pm_event(struct notifier_block *this,
+				unsigned long event, void *ptr)
+{
+	switch (event) {
+	case PM_POST_HIBERNATION:
+	case PM_POST_SUSPEND:
+		return msm_cpufreq_resume();
+	case PM_HIBERNATION_PREPARE:
+	case PM_SUSPEND_PREPARE:
+		return msm_cpufreq_suspend();
+	default:
+		return NOTIFY_DONE;
+	}
+}
+
+static struct freq_attr *msm_freq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
+static struct cpufreq_driver msm_cpufreq_driver = {
+	/* lps calculations are handled here. */
+	.flags		= CPUFREQ_STICKY | CPUFREQ_CONST_LOOPS,
+	.init		= msm_cpufreq_init,
+	.verify		= msm_cpufreq_verify,
+	.target		= msm_cpufreq_target,
+	.name		= "msm",
+	.attr		= msm_freq_attr,
+};
+
+static struct notifier_block msm_cpufreq_pm_notifier = {
+	.notifier_call = msm_cpufreq_pm_event,
+};
+
+static int __init msm_cpufreq_register(void)
+{
+	int cpu;
+
+	for_each_possible_cpu(cpu) {
+		mutex_init(&(per_cpu(cpufreq_suspend, cpu).suspend_mutex));
+		per_cpu(cpufreq_suspend, cpu).device_suspended = 0;
+	}
+
+#ifdef CONFIG_SMP
+	msm_cpufreq_wq = create_workqueue("msm-cpufreq");
+#endif
+
+	register_pm_notifier(&msm_cpufreq_pm_notifier);
+	return cpufreq_register_driver(&msm_cpufreq_driver);
+}
+
+late_initcall(msm_cpufreq_register);
+
diff --git a/arch/arm/mach-msm/cpuidle.c b/arch/arm/mach-msm/cpuidle.c
new file mode 100644
index 0000000..e4ec4d4
--- /dev/null
+++ b/arch/arm/mach-msm/cpuidle.c
@@ -0,0 +1,234 @@
+/* Copyright (c) 2010, 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/cpuidle.h>
+#include <linux/cpu_pm.h>
+
+#include <mach/cpuidle.h>
+
+#include "pm.h"
+
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct cpuidle_device, msm_cpuidle_devs);
+
+static struct cpuidle_driver msm_cpuidle_driver = {
+	.name = "msm_idle",
+	.owner = THIS_MODULE,
+};
+
+static struct msm_cpuidle_state msm_cstates[] = {
+	{0, 0, "C0", "WFI",
+		MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT},
+
+	{0, 1, "C1", "RETENTION",
+		MSM_PM_SLEEP_MODE_RETENTION},
+
+	{0, 2, "C2", "STANDALONE_POWER_COLLAPSE",
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE},
+
+	{0, 3, "C3", "POWER_COLLAPSE",
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE},
+
+	{1, 0, "C0", "WFI",
+		MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT},
+
+	{1, 1, "C1", "RETENTION",
+		MSM_PM_SLEEP_MODE_RETENTION},
+
+	{1, 2, "C2", "STANDALONE_POWER_COLLAPSE",
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE},
+
+	{2, 0, "C0", "WFI",
+		MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT},
+
+	{2, 1, "C1", "RETENTION",
+		MSM_PM_SLEEP_MODE_RETENTION},
+
+	{2, 2, "C2", "STANDALONE_POWER_COLLAPSE",
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE},
+
+	{3, 0, "C0", "WFI",
+		MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT},
+
+	{3, 1, "C1", "RETENTION",
+		MSM_PM_SLEEP_MODE_RETENTION},
+
+	{3, 2, "C2", "STANDALONE_POWER_COLLAPSE",
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE},
+};
+
+
+#ifdef CONFIG_MSM_SLEEP_STATS
+static DEFINE_PER_CPU(struct atomic_notifier_head, msm_cpuidle_notifiers);
+
+int msm_cpuidle_register_notifier(unsigned int cpu, struct notifier_block *nb)
+{
+	struct atomic_notifier_head *head =
+		&per_cpu(msm_cpuidle_notifiers, cpu);
+
+	return atomic_notifier_chain_register(head, nb);
+}
+EXPORT_SYMBOL(msm_cpuidle_register_notifier);
+
+int msm_cpuidle_unregister_notifier(unsigned int cpu, struct notifier_block *nb)
+{
+	struct atomic_notifier_head *head =
+		&per_cpu(msm_cpuidle_notifiers, cpu);
+
+	return atomic_notifier_chain_unregister(head, nb);
+}
+EXPORT_SYMBOL(msm_cpuidle_unregister_notifier);
+#endif
+
+static int msm_cpuidle_enter(
+	struct cpuidle_device *dev, struct cpuidle_driver *drv, int index)
+{
+	int ret = 0;
+	int i = 0;
+	enum msm_pm_sleep_mode pm_mode;
+	struct cpuidle_state_usage *st_usage = NULL;
+#ifdef CONFIG_MSM_SLEEP_STATS
+	struct atomic_notifier_head *head =
+			&__get_cpu_var(msm_cpuidle_notifiers);
+#endif
+
+	local_irq_disable();
+
+#ifdef CONFIG_MSM_SLEEP_STATS
+	atomic_notifier_call_chain(head, MSM_CPUIDLE_STATE_ENTER, NULL);
+#endif
+
+#ifdef CONFIG_CPU_PM
+	cpu_pm_enter();
+#endif
+
+	pm_mode = msm_pm_idle_prepare(dev, drv, index);
+	msm_pm_idle_enter(pm_mode);
+	for (i = 0; i < dev->state_count; i++) {
+		st_usage = &dev->states_usage[i];
+		if ((enum msm_pm_sleep_mode) cpuidle_get_statedata(st_usage)
+		    == pm_mode) {
+			ret = i;
+			break;
+		}
+	}
+
+#ifdef CONFIG_CPU_PM
+	cpu_pm_exit();
+#endif
+
+#ifdef CONFIG_MSM_SLEEP_STATS
+	atomic_notifier_call_chain(head, MSM_CPUIDLE_STATE_EXIT, NULL);
+#endif
+
+	local_irq_enable();
+
+	return ret;
+}
+
+static void __init msm_cpuidle_set_states(void)
+{
+	int i = 0;
+	int state_count = 0;
+	struct msm_cpuidle_state *cstate = NULL;
+	struct cpuidle_state *state = NULL;
+
+	for (i = 0; i < ARRAY_SIZE(msm_cstates); i++) {
+		cstate = &msm_cstates[i];
+		/* We have an asymmetric CPU C-State in MSMs.
+		 * The primary CPU can do PC while all secondary cpus
+		 * can only do standalone PC as part of their idle LPM.
+		 * However, the secondary cpus can do PC when hotplugged
+		 * We do not care about the hotplug here.
+		 * Register the C-States available for Core0.
+		 */
+		if (cstate->cpu)
+			continue;
+
+		state = &msm_cpuidle_driver.states[state_count];
+		snprintf(state->name, CPUIDLE_NAME_LEN, cstate->name);
+		snprintf(state->desc, CPUIDLE_DESC_LEN, cstate->desc);
+		state->flags = 0;
+		state->exit_latency = 0;
+		state->power_usage = 0;
+		state->target_residency = 0;
+		state->enter = msm_cpuidle_enter;
+
+		state_count++;
+		BUG_ON(state_count >= CPUIDLE_STATE_MAX);
+	}
+	msm_cpuidle_driver.state_count = state_count;
+	msm_cpuidle_driver.safe_state_index = 0;
+}
+
+static void __init msm_cpuidle_set_cpu_statedata(struct cpuidle_device *dev)
+{
+	int i = 0;
+	int state_count = 0;
+	struct cpuidle_state_usage *st_usage = NULL;
+	struct msm_cpuidle_state *cstate = NULL;
+
+	for (i = 0; i < ARRAY_SIZE(msm_cstates); i++) {
+		cstate = &msm_cstates[i];
+		if (cstate->cpu != dev->cpu)
+			continue;
+
+		st_usage = &dev->states_usage[state_count];
+		cpuidle_set_statedata(st_usage, (void *)cstate->mode_nr);
+		state_count++;
+		BUG_ON(state_count > msm_cpuidle_driver.state_count);
+	}
+
+	dev->state_count = state_count; /* Per cpu state count */
+}
+
+int __init msm_cpuidle_init(void)
+{
+	unsigned int cpu = 0;
+	int ret = 0;
+
+	msm_cpuidle_set_states();
+	ret = cpuidle_register_driver(&msm_cpuidle_driver);
+	if (ret)
+		pr_err("%s: failed to register cpuidle driver: %d\n",
+			__func__, ret);
+
+	for_each_possible_cpu(cpu) {
+		struct cpuidle_device *dev = &per_cpu(msm_cpuidle_devs, cpu);
+
+		dev->cpu = cpu;
+		msm_cpuidle_set_cpu_statedata(dev);
+		ret = cpuidle_register_device(dev);
+		if (ret) {
+			pr_err("%s: failed to register cpuidle device for "
+				"cpu %u: %d\n", __func__, cpu, ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int __init msm_cpuidle_early_init(void)
+{
+#ifdef CONFIG_MSM_SLEEP_STATS
+	unsigned int cpu;
+
+	for_each_possible_cpu(cpu)
+		ATOMIC_INIT_NOTIFIER_HEAD(&per_cpu(msm_cpuidle_notifiers, cpu));
+#endif
+	return 0;
+}
+
+early_initcall(msm_cpuidle_early_init);
diff --git a/arch/arm/mach-msm/dal.c b/arch/arm/mach-msm/dal.c
new file mode 100644
index 0000000..94c02f0
--- /dev/null
+++ b/arch/arm/mach-msm/dal.c
@@ -0,0 +1,1326 @@
+/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+/*
+ * Device access library (DAL) implementation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/completion.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/semaphore.h>
+
+#include <mach/dal.h>
+#include <mach/msm_smd.h>
+
+#define DALRPC_PROTOCOL_VERSION 0x11
+#define DALRPC_SUCCESS 0
+#define DALRPC_MAX_PORTNAME_LEN 64
+#define DALRPC_MAX_ATTACH_PARAM_LEN 64
+#define DALRPC_MAX_SERVICE_NAME_LEN 32
+#define DALRPC_MAX_PARAMS 128
+#define DALRPC_MAX_PARAMS_SIZE (DALRPC_MAX_PARAMS * 4)
+#define DALRPC_MAX_MSG_SIZE (sizeof(struct dalrpc_msg_hdr) + \
+			     DALRPC_MAX_PARAMS_SIZE)
+#define DALRPC_MSGID_DDI 0x0
+#define DALRPC_MSGID_DDI_REPLY 0x80
+#define DALRPC_MSGID_ATTACH_REPLY 0x81
+#define DALRPC_MSGID_DETACH_REPLY 0x82
+#define DALRPC_MSGID_ASYNCH 0xC0
+#define ROUND_BUFLEN(x) (((x + 3) & ~0x3))
+
+struct dalrpc_msg_hdr {
+	uint32_t len:16;
+	uint32_t proto_ver:8;
+	uint32_t prio:7;
+	uint32_t async:1;
+	uint32_t ddi_idx:16;
+	uint32_t proto_id:8;
+	uint32_t msgid:8;
+	void *from;
+	void *to;
+};
+
+struct dalrpc_msg {
+	struct dalrpc_msg_hdr hdr;
+	uint32_t param[DALRPC_MAX_PARAMS];
+};
+
+struct dalrpc_event_handle {
+	struct list_head list;
+
+	int flag;
+	spinlock_t lock;
+};
+
+struct dalrpc_cb_handle {
+	struct list_head list;
+
+	void (*fn)(void *, uint32_t, void *, uint32_t);
+	void *context;
+};
+
+struct daldevice_handle {;
+	struct list_head list;
+
+	void *remote_handle;
+	struct completion read_completion;
+	struct dalrpc_port *port;
+	struct dalrpc_msg msg;
+	struct mutex client_lock;
+};
+
+struct dalrpc_port {
+	struct list_head list;
+
+	char port[DALRPC_MAX_PORTNAME_LEN+1];
+	int refcount;
+
+	struct workqueue_struct *wq;
+	struct work_struct port_work;
+	struct mutex write_lock;
+
+	smd_channel_t *ch;
+
+	struct dalrpc_msg msg_in;
+	struct daldevice_handle *msg_owner;
+	unsigned msg_bytes_read;
+
+	struct list_head event_list;
+	struct mutex event_list_lock;
+
+	struct list_head cb_list;
+	struct mutex cb_list_lock;
+};
+
+static LIST_HEAD(port_list);
+static LIST_HEAD(client_list);
+static DEFINE_MUTEX(pc_lists_lock);
+
+static DECLARE_WAIT_QUEUE_HEAD(event_wq);
+
+static int client_exists(void *handle)
+{
+	struct daldevice_handle *h;
+
+	if (!handle)
+		return 0;
+
+	mutex_lock(&pc_lists_lock);
+
+	list_for_each_entry(h, &client_list, list)
+		if (h == handle) {
+			mutex_unlock(&pc_lists_lock);
+			return 1;
+		}
+
+	mutex_unlock(&pc_lists_lock);
+
+	return 0;
+}
+
+static int client_exists_locked(void *handle)
+{
+	struct daldevice_handle *h;
+
+	/* this function must be called with pc_lists_lock acquired */
+
+	if (!handle)
+		return 0;
+
+	list_for_each_entry(h, &client_list, list)
+		if (h == handle)
+			return 1;
+
+	return 0;
+}
+
+static int port_exists(struct dalrpc_port *p)
+{
+	struct dalrpc_port *p_iter;
+
+	/* this function must be called with pc_lists_lock acquired */
+
+	if (!p)
+		return 0;
+
+	list_for_each_entry(p_iter, &port_list, list)
+		if (p_iter == p)
+			return 1;
+
+	return 0;
+}
+
+static struct dalrpc_port *port_name_exists(char *port)
+{
+	struct dalrpc_port *p;
+
+	/* this function must be called with pc_lists_lock acquired */
+
+	list_for_each_entry(p, &port_list, list)
+		if (!strcmp(p->port, port))
+			return p;
+
+	return NULL;
+}
+
+static void port_close(struct dalrpc_port *p)
+{
+	mutex_lock(&pc_lists_lock);
+
+	p->refcount--;
+	if (p->refcount == 0)
+		list_del(&p->list);
+
+	mutex_unlock(&pc_lists_lock);
+
+	if (p->refcount == 0) {
+		destroy_workqueue(p->wq);
+		smd_close(p->ch);
+		kfree(p);
+	}
+}
+
+static int event_exists(struct dalrpc_port *p,
+			struct dalrpc_event_handle *ev)
+{
+	struct dalrpc_event_handle *ev_iter;
+
+	/* this function must be called with event_list_lock acquired */
+
+	list_for_each_entry(ev_iter, &p->event_list, list)
+		if (ev_iter == ev)
+			return 1;
+
+	return 0;
+}
+
+static int cb_exists(struct dalrpc_port *p,
+		     struct dalrpc_cb_handle *cb)
+{
+	struct dalrpc_cb_handle *cb_iter;
+
+	/* this function must be called with the cb_list_lock acquired */
+
+	list_for_each_entry(cb_iter, &p->cb_list, list)
+		if (cb_iter == cb)
+			return 1;
+
+	return 0;
+}
+
+static int check_version(struct dalrpc_msg_hdr *msg_hdr)
+{
+	static int version_msg = 1;
+
+	/* disabled because asynch events currently have no version */
+	return 0;
+
+	if (msg_hdr->proto_ver != DALRPC_PROTOCOL_VERSION) {
+		if (version_msg) {
+			printk(KERN_ERR "dalrpc: incompatible verison\n");
+			version_msg = 0;
+		}
+		return -1;
+	}
+	return 0;
+}
+
+static void process_asynch(struct dalrpc_port *p)
+{
+	struct dalrpc_event_handle *ev;
+	struct dalrpc_cb_handle *cb;
+
+	ev = (struct dalrpc_event_handle *)p->msg_in.param[0];
+	cb = (struct dalrpc_cb_handle *)p->msg_in.param[0];
+
+	mutex_lock(&p->event_list_lock);
+	if (event_exists(p, ev)) {
+		spin_lock(&ev->lock);
+		ev->flag = 1;
+		spin_unlock(&ev->lock);
+		smp_mb();
+		wake_up_all(&event_wq);
+		mutex_unlock(&p->event_list_lock);
+		return;
+	}
+	mutex_unlock(&p->event_list_lock);
+
+	mutex_lock(&p->cb_list_lock);
+	if (cb_exists(p, cb)) {
+		cb->fn(cb->context, p->msg_in.param[1],
+		       &p->msg_in.param[3], p->msg_in.param[2]);
+		mutex_unlock(&p->cb_list_lock);
+		return;
+	}
+	mutex_unlock(&p->cb_list_lock);
+}
+
+static void process_msg(struct dalrpc_port *p)
+{
+	switch (p->msg_in.hdr.msgid) {
+
+	case DALRPC_MSGID_DDI_REPLY:
+	case DALRPC_MSGID_ATTACH_REPLY:
+	case DALRPC_MSGID_DETACH_REPLY:
+		complete(&p->msg_owner->read_completion);
+		break;
+
+	case DALRPC_MSGID_ASYNCH:
+		process_asynch(p);
+		break;
+
+	default:
+		printk(KERN_ERR "process_msg: bad msgid %#x\n",
+		       p->msg_in.hdr.msgid);
+	}
+}
+
+static void flush_msg(struct dalrpc_port *p)
+{
+	int bytes_read, len;
+
+	len = p->msg_in.hdr.len - sizeof(struct dalrpc_msg_hdr);
+	while (len > 0) {
+		bytes_read = smd_read(p->ch, NULL, len);
+		if (bytes_read <= 0)
+			break;
+		len -= bytes_read;
+	}
+	p->msg_bytes_read = 0;
+}
+
+static int check_header(struct dalrpc_port *p)
+{
+	if (check_version(&p->msg_in.hdr) ||
+	    p->msg_in.hdr.len > DALRPC_MAX_MSG_SIZE ||
+	    (p->msg_in.hdr.msgid != DALRPC_MSGID_ASYNCH &&
+	     !client_exists_locked(p->msg_in.hdr.to))) {
+		printk(KERN_ERR "dalrpc_read_msg: bad msg\n");
+		flush_msg(p);
+		return 1;
+	}
+	p->msg_owner = (struct daldevice_handle *)p->msg_in.hdr.to;
+
+	if (p->msg_in.hdr.msgid != DALRPC_MSGID_ASYNCH)
+		memcpy(&p->msg_owner->msg.hdr, &p->msg_in.hdr,
+		       sizeof(p->msg_in.hdr));
+
+	return 0;
+}
+
+static int dalrpc_read_msg(struct dalrpc_port *p)
+{
+	uint8_t *read_ptr;
+	int bytes_read;
+
+	/* read msg header */
+	while (p->msg_bytes_read < sizeof(p->msg_in.hdr)) {
+		read_ptr = (uint8_t *)&p->msg_in.hdr + p->msg_bytes_read;
+
+		bytes_read = smd_read(p->ch, read_ptr,
+				      sizeof(p->msg_in.hdr) -
+				      p->msg_bytes_read);
+		if (bytes_read <= 0)
+			return 0;
+		p->msg_bytes_read += bytes_read;
+
+		if (p->msg_bytes_read == sizeof(p->msg_in.hdr) &&
+		    check_header(p))
+			return 1;
+	}
+
+	/* read remainder of msg */
+	if (p->msg_in.hdr.msgid != DALRPC_MSGID_ASYNCH)
+		read_ptr = (uint8_t *)&p->msg_owner->msg;
+	else
+		read_ptr = (uint8_t *)&p->msg_in;
+	read_ptr += p->msg_bytes_read;
+
+	while (p->msg_bytes_read < p->msg_in.hdr.len) {
+		bytes_read = smd_read(p->ch, read_ptr,
+				      p->msg_in.hdr.len - p->msg_bytes_read);
+		if (bytes_read <= 0)
+			return 0;
+		p->msg_bytes_read += bytes_read;
+		read_ptr += bytes_read;
+	}
+
+	process_msg(p);
+	p->msg_bytes_read = 0;
+	p->msg_owner = NULL;
+
+	return 1;
+}
+
+static void dalrpc_work(struct work_struct *work)
+{
+	struct dalrpc_port *p = container_of(work,
+					     struct dalrpc_port,
+					     port_work);
+
+	/* must lock port/client lists to ensure port doesn't disappear
+	   under an asynch event */
+	mutex_lock(&pc_lists_lock);
+	if (port_exists(p))
+		while (dalrpc_read_msg(p))
+			;
+	mutex_unlock(&pc_lists_lock);
+}
+
+static void dalrpc_smd_cb(void *priv, unsigned smd_flags)
+{
+	struct dalrpc_port *p = priv;
+
+	if (smd_flags != SMD_EVENT_DATA)
+		return;
+
+	queue_work(p->wq, &p->port_work);
+}
+
+static struct dalrpc_port *dalrpc_port_open(char *port, int cpu)
+{
+	struct dalrpc_port *p;
+	char wq_name[32];
+
+	p = port_name_exists(port);
+	if (p) {
+		p->refcount++;
+		return p;
+	}
+
+	p = kzalloc(sizeof(struct dalrpc_port), GFP_KERNEL);
+	if (!p)
+		return NULL;
+
+	strlcpy(p->port, port, sizeof(p->port));
+	p->refcount = 1;
+
+	snprintf(wq_name, sizeof(wq_name), "dalrpc_rcv_%s", port);
+	p->wq = create_singlethread_workqueue(wq_name);
+	if (!p->wq) {
+		printk(KERN_ERR "dalrpc_init: unable to create workqueue\n");
+		goto no_wq;
+	}
+	INIT_WORK(&p->port_work, dalrpc_work);
+
+	mutex_init(&p->write_lock);
+	mutex_init(&p->event_list_lock);
+	mutex_init(&p->cb_list_lock);
+
+	INIT_LIST_HEAD(&p->event_list);
+	INIT_LIST_HEAD(&p->cb_list);
+
+	p->msg_owner = NULL;
+	p->msg_bytes_read = 0;
+
+	if (smd_named_open_on_edge(port, cpu, &p->ch, p,
+				   dalrpc_smd_cb)) {
+		printk(KERN_ERR "dalrpc_port_init() failed to open port\n");
+		goto no_smd;
+	}
+
+	list_add(&p->list, &port_list);
+
+	return p;
+
+no_smd:
+	destroy_workqueue(p->wq);
+no_wq:
+	kfree(p);
+	return NULL;
+}
+
+static void dalrpc_sendwait(struct daldevice_handle *h)
+{
+	u8 *buf = (u8 *)&h->msg;
+	int len = h->msg.hdr.len;
+	int written;
+
+	mutex_lock(&h->port->write_lock);
+	do {
+		written = smd_write(h->port->ch, buf + (h->msg.hdr.len - len),
+				 len);
+		if (written < 0)
+			break;
+		len -= written;
+	} while (len);
+	mutex_unlock(&h->port->write_lock);
+
+	if (!h->msg.hdr.async)
+		wait_for_completion(&h->read_completion);
+}
+
+int daldevice_attach(uint32_t device_id, char *port, int cpu,
+		     void **handle_ptr)
+{
+	struct daldevice_handle *h;
+	char dyn_port[DALRPC_MAX_PORTNAME_LEN + 1] = "DAL00";
+	int ret;
+	int tries = 0;
+
+	if (!port)
+		port = dyn_port;
+
+	if (strlen(port) > DALRPC_MAX_PORTNAME_LEN)
+		return -EINVAL;
+
+	h = kzalloc(sizeof(struct daldevice_handle), GFP_KERNEL);
+	if (!h) {
+		*handle_ptr = NULL;
+		return -ENOMEM;
+	}
+
+	init_completion(&h->read_completion);
+	mutex_init(&h->client_lock);
+
+	mutex_lock(&pc_lists_lock);
+	list_add(&h->list, &client_list);
+	mutex_unlock(&pc_lists_lock);
+
+	/* 3 attempts, enough for one each on the user specified port, the
+	 * dynamic discovery port, and the port recommended by the dynamic
+	 * discovery port */
+	while (tries < 3) {
+		tries++;
+
+		mutex_lock(&pc_lists_lock);
+		h->port = dalrpc_port_open(port, cpu);
+		if (!h->port) {
+			list_del(&h->list);
+			mutex_unlock(&pc_lists_lock);
+			printk(KERN_ERR "daldevice_attach: could not "
+			       "open port\n");
+			kfree(h);
+			*handle_ptr = NULL;
+			return -EIO;
+		}
+		mutex_unlock(&pc_lists_lock);
+
+		h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 4 +
+			DALRPC_MAX_ATTACH_PARAM_LEN +
+			DALRPC_MAX_SERVICE_NAME_LEN;
+		h->msg.hdr.proto_ver = DALRPC_PROTOCOL_VERSION;
+		h->msg.hdr.ddi_idx = 0;
+		h->msg.hdr.msgid = 0x1;
+		h->msg.hdr.prio = 0;
+		h->msg.hdr.async = 0;
+		h->msg.hdr.from = h;
+		h->msg.hdr.to = 0;
+		h->msg.param[0] = device_id;
+
+		memset(&h->msg.param[1], 0,
+		       DALRPC_MAX_ATTACH_PARAM_LEN +
+		       DALRPC_MAX_SERVICE_NAME_LEN);
+
+		dalrpc_sendwait(h);
+		ret = h->msg.param[0];
+
+		if (ret == DALRPC_SUCCESS) {
+			h->remote_handle = h->msg.hdr.from;
+			*handle_ptr = h;
+			break;
+		} else if (strnlen((char *)&h->msg.param[1],
+				   DALRPC_MAX_PORTNAME_LEN)) {
+			/* another port was recommended in the response. */
+			strlcpy(dyn_port, (char *)&h->msg.param[1],
+				sizeof(dyn_port));
+			dyn_port[DALRPC_MAX_PORTNAME_LEN] = 0;
+			port = dyn_port;
+		} else if (port == dyn_port) {
+			/* the dynamic discovery port (or port that
+			 * was recommended by it) did not recognize
+			 * the device id, give up */
+			daldevice_detach(h);
+			break;
+		} else
+			/* the user specified port did not work, try
+			 * the dynamic discovery port */
+			port = dyn_port;
+
+		port_close(h->port);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(daldevice_attach);
+
+static void dalrpc_ddi_prologue(uint32_t ddi_idx, struct daldevice_handle *h,
+							uint32_t idx_async)
+{
+	h->msg.hdr.proto_ver = DALRPC_PROTOCOL_VERSION;
+	h->msg.hdr.prio = 0;
+	h->msg.hdr.async = idx_async;
+	h->msg.hdr.msgid = DALRPC_MSGID_DDI;
+	h->msg.hdr.from = h;
+	h->msg.hdr.to = h->remote_handle;
+	h->msg.hdr.ddi_idx = ddi_idx;
+}
+
+int daldevice_detach(void *handle)
+{
+	struct daldevice_handle *h = handle;
+
+	if (!client_exists(h))
+		return -EINVAL;
+
+	dalrpc_ddi_prologue(0, h, 0);
+
+	if (!h->remote_handle)
+		goto norpc;
+
+	h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 4;
+	h->msg.hdr.msgid = 0x2;
+	h->msg.param[0] = 0;
+
+	dalrpc_sendwait(h);
+
+norpc:
+	mutex_lock(&pc_lists_lock);
+	list_del(&h->list);
+	mutex_unlock(&pc_lists_lock);
+
+	port_close(h->port);
+
+	kfree(h);
+
+	return 0;
+}
+EXPORT_SYMBOL(daldevice_detach);
+
+uint32_t dalrpc_fcn_0(uint32_t ddi_idx, void *handle, uint32_t s1)
+{
+	struct daldevice_handle *h = handle;
+	uint32_t ret;
+
+	if (!client_exists(h))
+		return -EINVAL;
+
+	mutex_lock(&h->client_lock);
+
+	dalrpc_ddi_prologue(ddi_idx, h, 0);
+
+	h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 4;
+	h->msg.hdr.proto_id = 0;
+	h->msg.param[0] = s1;
+
+	dalrpc_sendwait(h);
+
+	ret = h->msg.param[0];
+	mutex_unlock(&h->client_lock);
+	return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_0);
+
+uint32_t dalrpc_fcn_1(uint32_t ddi_idx, void *handle, uint32_t s1,
+		      uint32_t s2)
+{
+	struct daldevice_handle *h = handle;
+	uint32_t ret;
+
+	if (!client_exists(h))
+		return -EINVAL;
+
+	mutex_lock(&h->client_lock);
+
+	dalrpc_ddi_prologue(ddi_idx, h, 0);
+
+	h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8;
+	h->msg.hdr.proto_id = 1;
+	h->msg.param[0] = s1;
+	h->msg.param[1] = s2;
+
+	dalrpc_sendwait(h);
+
+	ret = h->msg.param[0];
+	mutex_unlock(&h->client_lock);
+	return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_1);
+
+uint32_t dalrpc_fcn_2(uint32_t ddi_idx, void *handle, uint32_t s1,
+		      uint32_t *p_s2)
+{
+	struct daldevice_handle *h = handle;
+	uint32_t ret;
+
+	if (!client_exists(h))
+		return -EINVAL;
+
+	mutex_lock(&h->client_lock);
+
+	dalrpc_ddi_prologue(ddi_idx, h, 0);
+
+	h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 4;
+	h->msg.hdr.proto_id = 2;
+	h->msg.param[0] = s1;
+
+	dalrpc_sendwait(h);
+
+	if (h->msg.param[0] == DALRPC_SUCCESS)
+		*p_s2 = h->msg.param[1];
+
+	ret = h->msg.param[0];
+	mutex_unlock(&h->client_lock);
+	return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_2);
+
+uint32_t dalrpc_fcn_3(uint32_t ddi_idx, void *handle, uint32_t s1,
+		      uint32_t s2, uint32_t s3)
+{
+	struct daldevice_handle *h = handle;
+	uint32_t ret;
+
+	if (!client_exists(h))
+		return -EINVAL;
+
+	mutex_lock(&h->client_lock);
+
+	dalrpc_ddi_prologue(ddi_idx, h, 0);
+
+	h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 12;
+	h->msg.hdr.proto_id = 3;
+	h->msg.param[0] = s1;
+	h->msg.param[1] = s2;
+	h->msg.param[2] = s3;
+
+	dalrpc_sendwait(h);
+
+	ret = h->msg.param[0];
+	mutex_unlock(&h->client_lock);
+	return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_3);
+
+uint32_t dalrpc_fcn_4(uint32_t ddi_idx, void *handle, uint32_t s1,
+		      uint32_t s2, uint32_t *p_s3)
+{
+	struct daldevice_handle *h = handle;
+	uint32_t ret;
+
+	if (!client_exists(h))
+		return -EINVAL;
+
+	mutex_lock(&h->client_lock);
+
+	dalrpc_ddi_prologue(ddi_idx, h, 0);
+
+	h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8;
+	h->msg.hdr.proto_id = 4;
+	h->msg.param[0] = s1;
+	h->msg.param[1] = s2;
+
+	dalrpc_sendwait(h);
+
+	if (h->msg.param[0] == DALRPC_SUCCESS)
+		*p_s3 = h->msg.param[1];
+
+	ret = h->msg.param[0];
+	mutex_unlock(&h->client_lock);
+	return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_4);
+
+uint32_t dalrpc_fcn_5(uint32_t ddi_idx, void *handle, const void *ibuf,
+		      uint32_t ilen)
+{
+	struct daldevice_handle *h = handle;
+	uint32_t ret, idx_async;
+
+	if ((ilen + 4) > DALRPC_MAX_PARAMS_SIZE)
+		return -EINVAL;
+
+	if (!client_exists(h))
+		return -EINVAL;
+
+	idx_async = (ddi_idx & 0x80000000) >> 31;
+
+	mutex_lock(&h->client_lock);
+
+	dalrpc_ddi_prologue(ddi_idx, h, idx_async);
+
+	h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 4 +
+		ROUND_BUFLEN(ilen);
+	h->msg.hdr.proto_id = 5;
+	h->msg.param[0] = ilen;
+	memcpy(&h->msg.param[1], ibuf, ilen);
+
+	dalrpc_sendwait(h);
+
+	if (h->msg.hdr.async)
+		ret = DALRPC_SUCCESS;
+	else
+		ret = h->msg.param[0];
+	mutex_unlock(&h->client_lock);
+	return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_5);
+
+uint32_t dalrpc_fcn_6(uint32_t ddi_idx, void *handle, uint32_t s1,
+		      const void *ibuf, uint32_t ilen)
+{
+	struct daldevice_handle *h = handle;
+	uint32_t ret;
+
+	if ((ilen + 8) > DALRPC_MAX_PARAMS_SIZE)
+		return -EINVAL;
+
+	if (!client_exists(h))
+		return -EINVAL;
+
+	mutex_lock(&h->client_lock);
+
+	dalrpc_ddi_prologue(ddi_idx, h, 0);
+
+	h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8 +
+		ROUND_BUFLEN(ilen);
+	h->msg.hdr.proto_id = 6;
+	h->msg.param[0] = s1;
+	h->msg.param[1] = ilen;
+	memcpy(&h->msg.param[2], ibuf, ilen);
+
+	dalrpc_sendwait(h);
+
+	ret = h->msg.param[0];
+	mutex_unlock(&h->client_lock);
+	return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_6);
+
+uint32_t dalrpc_fcn_7(uint32_t ddi_idx, void *handle, const void *ibuf,
+		      uint32_t ilen, void *obuf, uint32_t olen,
+		      uint32_t *oalen)
+{
+	struct daldevice_handle *h = handle;
+	uint32_t ret;
+	int param_idx;
+
+	if ((ilen + 8) > DALRPC_MAX_PARAMS_SIZE ||
+	    (olen + 4) > DALRPC_MAX_PARAMS_SIZE)
+		return -EINVAL;
+
+
+	if (!client_exists(h))
+		return -EINVAL;
+
+	mutex_lock(&h->client_lock);
+
+	dalrpc_ddi_prologue(ddi_idx, h, 0);
+
+	h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8 +
+		ROUND_BUFLEN(ilen);
+	h->msg.hdr.proto_id = 7;
+	h->msg.param[0] = ilen;
+	memcpy(&h->msg.param[1], ibuf, ilen);
+	param_idx = (ROUND_BUFLEN(ilen) / 4) + 1;
+	h->msg.param[param_idx] = olen;
+
+	dalrpc_sendwait(h);
+
+	if (h->msg.param[0] == DALRPC_SUCCESS) {
+		if (h->msg.param[1] > olen) {
+			mutex_unlock(&h->client_lock);
+			return -EIO;
+		}
+		*oalen = h->msg.param[1];
+		memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
+	}
+
+	ret = h->msg.param[0];
+	mutex_unlock(&h->client_lock);
+	return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_7);
+
+uint32_t dalrpc_fcn_8(uint32_t ddi_idx, void *handle, const void *ibuf,
+		      uint32_t ilen, void *obuf, uint32_t olen)
+{
+	struct daldevice_handle *h = handle;
+	uint32_t ret;
+	int param_idx;
+
+	if ((ilen + 8) > DALRPC_MAX_PARAMS_SIZE ||
+	    (olen + 4) > DALRPC_MAX_PARAMS_SIZE)
+		return -EINVAL;
+
+	if (!client_exists(h))
+		return -EINVAL;
+
+	mutex_lock(&h->client_lock);
+
+	dalrpc_ddi_prologue(ddi_idx, h, 0);
+
+	h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8 +
+		ROUND_BUFLEN(ilen);
+	h->msg.hdr.proto_id = 8;
+	h->msg.param[0] = ilen;
+	memcpy(&h->msg.param[1], ibuf, ilen);
+	param_idx = (ROUND_BUFLEN(ilen) / 4) + 1;
+	h->msg.param[param_idx] = olen;
+
+	dalrpc_sendwait(h);
+
+	if (h->msg.param[0] == DALRPC_SUCCESS) {
+		if (h->msg.param[1] > olen) {
+			mutex_unlock(&h->client_lock);
+			return -EIO;
+		}
+		memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
+	}
+
+	ret = h->msg.param[0];
+	mutex_unlock(&h->client_lock);
+	return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_8);
+
+uint32_t dalrpc_fcn_9(uint32_t ddi_idx, void *handle, void *obuf,
+		      uint32_t olen)
+{
+	struct daldevice_handle *h = handle;
+	uint32_t ret;
+
+	if ((olen + 4) > DALRPC_MAX_PARAMS_SIZE)
+		return -EINVAL;
+
+	if (!client_exists(h))
+		return -EINVAL;
+
+	mutex_lock(&h->client_lock);
+
+	dalrpc_ddi_prologue(ddi_idx, h, 0);
+
+	h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 4;
+	h->msg.hdr.proto_id = 9;
+	h->msg.param[0] = olen;
+
+	dalrpc_sendwait(h);
+
+	if (h->msg.param[0] == DALRPC_SUCCESS) {
+		if (h->msg.param[1] > olen) {
+			mutex_unlock(&h->client_lock);
+			return -EIO;
+		}
+		memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
+	}
+
+	ret = h->msg.param[0];
+	mutex_unlock(&h->client_lock);
+	return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_9);
+
+uint32_t dalrpc_fcn_10(uint32_t ddi_idx, void *handle, uint32_t s1,
+		       const void *ibuf, uint32_t ilen, void *obuf,
+		       uint32_t olen, uint32_t *oalen)
+{
+	struct daldevice_handle *h = handle;
+	uint32_t ret;
+	int param_idx;
+
+	if ((ilen + 12) > DALRPC_MAX_PARAMS_SIZE ||
+	    (olen + 4) > DALRPC_MAX_PARAMS_SIZE)
+		return -EINVAL;
+
+	if (!client_exists(h))
+		return -EINVAL;
+
+	mutex_lock(&h->client_lock);
+
+	dalrpc_ddi_prologue(ddi_idx, h, 0);
+
+	h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 12 +
+		ROUND_BUFLEN(ilen);
+	h->msg.hdr.proto_id = 10;
+	h->msg.param[0] = s1;
+	h->msg.param[1] = ilen;
+	memcpy(&h->msg.param[2], ibuf, ilen);
+	param_idx = (ROUND_BUFLEN(ilen) / 4) + 2;
+	h->msg.param[param_idx] = olen;
+
+	dalrpc_sendwait(h);
+
+	if (h->msg.param[0] == DALRPC_SUCCESS) {
+		if (h->msg.param[1] > olen) {
+			mutex_unlock(&h->client_lock);
+			return -EIO;
+		}
+		*oalen = h->msg.param[1];
+		memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
+	}
+
+	ret = h->msg.param[0];
+	mutex_unlock(&h->client_lock);
+	return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_10);
+
+uint32_t dalrpc_fcn_11(uint32_t ddi_idx, void *handle, uint32_t s1,
+		       void *obuf, uint32_t olen)
+{
+	struct daldevice_handle *h = handle;
+	uint32_t ret;
+
+	if ((olen + 4) > DALRPC_MAX_PARAMS_SIZE)
+		return -EINVAL;
+
+	if (!client_exists(h))
+		return -EINVAL;
+
+	mutex_lock(&h->client_lock);
+
+	dalrpc_ddi_prologue(ddi_idx, h, 0);
+
+	h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8;
+	h->msg.hdr.proto_id = 11;
+	h->msg.param[0] = s1;
+	h->msg.param[1] = olen;
+
+	dalrpc_sendwait(h);
+
+	if (h->msg.param[0] == DALRPC_SUCCESS) {
+		if (h->msg.param[1] > olen) {
+			mutex_unlock(&h->client_lock);
+			return -EIO;
+		}
+		memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
+	}
+
+	ret = h->msg.param[0];
+	mutex_unlock(&h->client_lock);
+	return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_11);
+
+uint32_t dalrpc_fcn_12(uint32_t ddi_idx, void *handle, uint32_t s1,
+		       void *obuf, uint32_t olen, uint32_t *oalen)
+{
+	struct daldevice_handle *h = handle;
+	uint32_t ret;
+
+	if ((olen + 4) > DALRPC_MAX_PARAMS_SIZE)
+		return -EINVAL;
+
+	if (!client_exists(h))
+		return -EINVAL;
+
+	mutex_lock(&h->client_lock);
+
+	dalrpc_ddi_prologue(ddi_idx, h, 0);
+
+	h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8;
+	h->msg.hdr.proto_id = 12;
+	h->msg.param[0] = s1;
+	h->msg.param[1] = olen;
+
+	dalrpc_sendwait(h);
+
+	if (h->msg.param[0] == DALRPC_SUCCESS) {
+		if (h->msg.param[1] > olen) {
+			mutex_unlock(&h->client_lock);
+			return -EIO;
+		}
+		*oalen = h->msg.param[1];
+		memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
+	}
+
+	ret = h->msg.param[0];
+	mutex_unlock(&h->client_lock);
+	return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_12);
+
+uint32_t dalrpc_fcn_13(uint32_t ddi_idx, void *handle, const void *ibuf,
+		       uint32_t ilen, const void *ibuf2, uint32_t ilen2,
+		       void *obuf, uint32_t olen)
+{
+	struct daldevice_handle *h = handle;
+	uint32_t ret;
+	int param_idx;
+
+	if ((ilen + ilen2 + 12) > DALRPC_MAX_PARAMS_SIZE ||
+	    (olen + 4) > DALRPC_MAX_PARAMS_SIZE)
+		return -EINVAL;
+
+	if (!client_exists(h))
+		return -EINVAL;
+
+	mutex_lock(&h->client_lock);
+
+	dalrpc_ddi_prologue(ddi_idx, h, 0);
+
+	h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 12 +
+		ROUND_BUFLEN(ilen) + ROUND_BUFLEN(ilen2);
+	h->msg.hdr.proto_id = 13;
+	h->msg.param[0] = ilen;
+	memcpy(&h->msg.param[1], ibuf, ilen);
+	param_idx = (ROUND_BUFLEN(ilen) / 4) + 1;
+	h->msg.param[param_idx++] = ilen2;
+	memcpy(&h->msg.param[param_idx], ibuf2, ilen2);
+	param_idx += (ROUND_BUFLEN(ilen2) / 4);
+	h->msg.param[param_idx] = olen;
+
+	dalrpc_sendwait(h);
+
+	if (h->msg.param[0] == DALRPC_SUCCESS) {
+		if (h->msg.param[1] > olen) {
+			mutex_unlock(&h->client_lock);
+			return -EIO;
+		}
+		memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
+	}
+
+	ret = h->msg.param[0];
+	mutex_unlock(&h->client_lock);
+	return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_13);
+
+uint32_t dalrpc_fcn_14(uint32_t ddi_idx, void *handle, const void *ibuf,
+		       uint32_t ilen, void *obuf, uint32_t olen,
+		       void *obuf2, uint32_t olen2, uint32_t *oalen2)
+{
+	struct daldevice_handle *h = handle;
+	uint32_t ret;
+	int param_idx;
+
+	if ((ilen + 12) > DALRPC_MAX_PARAMS_SIZE ||
+	    (olen + olen2 + 8) > DALRPC_MAX_PARAMS_SIZE)
+		return -EINVAL;
+
+	if (!client_exists(h))
+		return -EINVAL;
+
+	mutex_lock(&h->client_lock);
+
+	dalrpc_ddi_prologue(ddi_idx, h, 0);
+
+	h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 12 +
+		ROUND_BUFLEN(ilen);
+	h->msg.hdr.proto_id = 14;
+	h->msg.param[0] = ilen;
+	memcpy(&h->msg.param[1], ibuf, ilen);
+	param_idx = (ROUND_BUFLEN(ilen) / 4) + 1;
+	h->msg.param[param_idx++] = olen;
+	h->msg.param[param_idx] = olen2;
+
+	dalrpc_sendwait(h);
+
+	if (h->msg.param[0] == DALRPC_SUCCESS) {
+		if (h->msg.param[1] > olen) {
+			mutex_unlock(&h->client_lock);
+			return -EIO;
+		}
+		param_idx = (ROUND_BUFLEN(h->msg.param[1]) / 4) + 2;
+		if (h->msg.param[param_idx] > olen2) {
+			mutex_unlock(&h->client_lock);
+			return -EIO;
+		}
+		memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
+		memcpy(obuf2, &h->msg.param[param_idx + 1],
+		       h->msg.param[param_idx]);
+		*oalen2 = h->msg.param[param_idx];
+	}
+
+	ret = h->msg.param[0];
+	mutex_unlock(&h->client_lock);
+	return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_14);
+
+uint32_t dalrpc_fcn_15(uint32_t ddi_idx, void *handle, const void *ibuf,
+		       uint32_t ilen, const void *ibuf2, uint32_t ilen2,
+		       void *obuf, uint32_t olen, uint32_t *oalen,
+		       void *obuf2, uint32_t olen2)
+{
+	struct daldevice_handle *h = handle;
+	uint32_t ret;
+	int param_idx;
+
+	if ((ilen + ilen2 + 16) > DALRPC_MAX_PARAMS_SIZE ||
+	    (olen + olen2 + 8) > DALRPC_MAX_PARAMS_SIZE)
+		return -EINVAL;
+
+	if (!client_exists(h))
+		return -EINVAL;
+
+	mutex_lock(&h->client_lock);
+
+	dalrpc_ddi_prologue(ddi_idx, h, 0);
+
+	h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 16 +
+		ROUND_BUFLEN(ilen) + ROUND_BUFLEN(ilen2);
+	h->msg.hdr.proto_id = 15;
+	h->msg.param[0] = ilen;
+	memcpy(&h->msg.param[1], ibuf, ilen);
+	param_idx = (ROUND_BUFLEN(ilen) / 4) + 1;
+	h->msg.param[param_idx++] = ilen2;
+	memcpy(&h->msg.param[param_idx], ibuf2, ilen2);
+	param_idx += (ROUND_BUFLEN(ilen2) / 4);
+	h->msg.param[param_idx++] = olen;
+	h->msg.param[param_idx] = olen2;
+
+	dalrpc_sendwait(h);
+
+	if (h->msg.param[0] == DALRPC_SUCCESS) {
+		if (h->msg.param[1] > olen) {
+			mutex_unlock(&h->client_lock);
+			return -EIO;
+		}
+		param_idx = (ROUND_BUFLEN(h->msg.param[1]) / 4) + 2;
+		if (h->msg.param[param_idx] > olen2) {
+			mutex_unlock(&h->client_lock);
+			return -EIO;
+		}
+		memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
+		memcpy(obuf2, &h->msg.param[param_idx + 1],
+		       h->msg.param[param_idx]);
+		*oalen = h->msg.param[1];
+	}
+
+	ret = h->msg.param[0];
+	mutex_unlock(&h->client_lock);
+	return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_15);
+
+void *dalrpc_alloc_event(void *handle)
+{
+	struct daldevice_handle *h;
+	struct dalrpc_event_handle *ev;
+
+	h = (struct daldevice_handle *)handle;
+
+	if (!client_exists(h))
+		return NULL;
+
+	ev = kmalloc(sizeof(struct dalrpc_event_handle), GFP_KERNEL);
+	if (!ev)
+		return NULL;
+
+	ev->flag = 0;
+	spin_lock_init(&ev->lock);
+
+	mutex_lock(&h->port->event_list_lock);
+	list_add(&ev->list, &h->port->event_list);
+	mutex_unlock(&h->port->event_list_lock);
+
+	return ev;
+}
+EXPORT_SYMBOL(dalrpc_alloc_event);
+
+void *dalrpc_alloc_cb(void *handle,
+		      void (*fn)(void *, uint32_t, void *, uint32_t),
+		      void *context)
+{
+	struct daldevice_handle *h;
+	struct dalrpc_cb_handle *cb;
+
+	h = (struct daldevice_handle *)handle;
+
+	if (!client_exists(h))
+		return NULL;
+
+	cb = kmalloc(sizeof(struct dalrpc_cb_handle), GFP_KERNEL);
+	if (!cb)
+		return NULL;
+
+	cb->fn = fn;
+	cb->context = context;
+
+	mutex_lock(&h->port->cb_list_lock);
+	list_add(&cb->list, &h->port->cb_list);
+	mutex_unlock(&h->port->cb_list_lock);
+
+	return cb;
+}
+EXPORT_SYMBOL(dalrpc_alloc_cb);
+
+void dalrpc_dealloc_event(void *handle,
+			  void *ev_h)
+{
+	struct daldevice_handle *h;
+	struct dalrpc_event_handle *ev;
+
+	h = (struct daldevice_handle *)handle;
+	ev = (struct dalrpc_event_handle *)ev_h;
+
+	mutex_lock(&h->port->event_list_lock);
+	list_del(&ev->list);
+	mutex_unlock(&h->port->event_list_lock);
+	kfree(ev);
+}
+EXPORT_SYMBOL(dalrpc_dealloc_event);
+
+void dalrpc_dealloc_cb(void *handle,
+		       void *cb_h)
+{
+	struct daldevice_handle *h;
+	struct dalrpc_cb_handle *cb;
+
+	h = (struct daldevice_handle *)handle;
+	cb = (struct dalrpc_cb_handle *)cb_h;
+
+	mutex_lock(&h->port->cb_list_lock);
+	list_del(&cb->list);
+	mutex_unlock(&h->port->cb_list_lock);
+	kfree(cb);
+}
+EXPORT_SYMBOL(dalrpc_dealloc_cb);
+
+static int event_occurred(int num_events, struct dalrpc_event_handle **events,
+			  int *occurred)
+{
+	int i;
+
+	for (i = 0; i < num_events; i++) {
+		spin_lock(&events[i]->lock);
+		if (events[i]->flag) {
+			events[i]->flag = 0;
+			spin_unlock(&events[i]->lock);
+			*occurred = i;
+			return 1;
+		}
+		spin_unlock(&events[i]->lock);
+	}
+
+	return 0;
+}
+
+int dalrpc_event_wait_multiple(int num, void **ev_h, int timeout)
+{
+	struct dalrpc_event_handle **events;
+	int ret, occurred;
+
+	events = (struct dalrpc_event_handle **)ev_h;
+
+	if (timeout == DALRPC_TIMEOUT_INFINITE) {
+		wait_event(event_wq,
+			   event_occurred(num, events, &occurred));
+		return occurred;
+	}
+
+	ret = wait_event_timeout(event_wq,
+				 event_occurred(num, events, &occurred),
+				 timeout);
+	if (ret > 0)
+		return occurred;
+	else
+		return -ETIMEDOUT;
+}
+EXPORT_SYMBOL(dalrpc_event_wait_multiple);
diff --git a/arch/arm/mach-msm/dal_axi.c b/arch/arm/mach-msm/dal_axi.c
new file mode 100644
index 0000000..739b7dc
--- /dev/null
+++ b/arch/arm/mach-msm/dal_axi.c
@@ -0,0 +1,102 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <mach/dal_axi.h>
+
+/* The AXI device ID */
+#define DALDEVICEID_AXI   0x02000053
+#define DALRPC_PORT_NAME  "DAL00"
+
+enum {
+	DALRPC_AXI_CONFIGURE_BRIDGE = DALDEVICE_FIRST_DEVICE_API_IDX + 11
+};
+
+enum {
+	DAL_AXI_BRIDGE_CFG_CGR_SS_2DGRP_SYNC_MODE = 14,
+	DAL_AXI_BRIDGE_CFG_CGR_SS_2DGRP_ASYNC_MODE,
+	DAL_AXI_BRIDGE_CFG_CGR_SS_2DGRP_ISOSYNC_MODE,
+	DAL_AXI_BRIDGE_CFG_CGR_SS_2DGRP_DEBUG_EN,
+	DAL_AXI_BRIDGE_CFG_CGR_SS_2DGRP_DEBUG_DIS,
+	DAL_AXI_BRIDGE_CFG_CGR_SS_3DGRP_SYNC_MODE,
+	DAL_AXI_BRIDGE_CFG_CGR_SS_3DGRP_ASYNC_MODE,
+	DAL_AXI_BRIDGE_CFG_CGR_SS_3DGRP_ISOSYNC_MODE,
+	DAL_AXI_BRIDGE_CFG_CGR_SS_3DGRP_DEBUG_EN,
+	DAL_AXI_BRIDGE_CFG_CGR_SS_3DGRP_DEBUG_DIS,
+	/* 7x27(A) Graphics Subsystem Bridge Configuration */
+	DAL_AXI_BRIDGE_CFG_GRPSS_XBAR_SYNC_MODE = 58,
+	DAL_AXI_BRIDGE_CFG_GRPSS_XBAR_ASYNC_MODE = 59,
+	DAL_AXI_BRIDGE_CFG_GRPSS_XBAR_ISOSYNC_MODE = 60
+
+};
+
+static int axi_configure_bridge_grfx_sync_mode(int bridge_mode)
+{
+	int rc;
+	void *dev_handle;
+
+	/* get device handle */
+	rc = daldevice_attach(
+		DALDEVICEID_AXI, DALRPC_PORT_NAME,
+		DALRPC_DEST_MODEM, &dev_handle
+	);
+	if (rc) {
+		printk(KERN_ERR "%s: failed to attach AXI bus device (%d)\n",
+			__func__, rc);
+		goto fail_dal_attach_detach;
+	}
+
+	/* call ConfigureBridge */
+	rc = dalrpc_fcn_0(
+		DALRPC_AXI_CONFIGURE_BRIDGE, dev_handle,
+		bridge_mode
+	);
+	if (rc) {
+		printk(KERN_ERR "%s: AXI bus device (%d) failed to be configured\n",
+			__func__, rc);
+		goto fail_dal_fcn_0;
+	}
+
+	/* close device handle */
+	rc = daldevice_detach(dev_handle);
+	if (rc) {
+		printk(KERN_ERR "%s: failed to detach AXI bus device (%d)\n",
+			__func__, rc);
+		goto fail_dal_attach_detach;
+	}
+
+	return 0;
+
+fail_dal_fcn_0:
+	(void)daldevice_detach(dev_handle);
+fail_dal_attach_detach:
+
+	return rc;
+}
+
+
+
+int set_grp2d_async(void)
+{
+	return axi_configure_bridge_grfx_sync_mode(
+		DAL_AXI_BRIDGE_CFG_CGR_SS_2DGRP_ASYNC_MODE);
+}
+
+int set_grp3d_async(void)
+{
+	return axi_configure_bridge_grfx_sync_mode(
+		DAL_AXI_BRIDGE_CFG_CGR_SS_3DGRP_ASYNC_MODE);
+}
+
+int set_grp_xbar_async(void)
+{	return axi_configure_bridge_grfx_sync_mode(
+		DAL_AXI_BRIDGE_CFG_GRPSS_XBAR_ASYNC_MODE);
+}
diff --git a/arch/arm/mach-msm/dal_remotetest.c b/arch/arm/mach-msm/dal_remotetest.c
new file mode 100644
index 0000000..d7a3f34
--- /dev/null
+++ b/arch/arm/mach-msm/dal_remotetest.c
@@ -0,0 +1,410 @@
+/* Copyright (c) 2008-2009, 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.
+ *
+ */
+/*
+ * DAL remote test device test suite.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/debugfs.h>
+
+#include "dal_remotetest.h"
+
+#define BYTEBUF_LEN 64
+
+#define rpc_error(num)							\
+	do {								\
+		errmask |= (1 << num);					\
+		printk(KERN_INFO "%s: remote_unittest_%d failed (%d)\n", \
+		       __func__, num, ret);				\
+	} while (0)
+
+#define verify_error(num, field)					\
+	do {								\
+		errmask |= (1 << num);					\
+		printk(KERN_INFO "%s: remote_unittest_%d failed (%s)\n", \
+		       __func__, num, field);				\
+	} while (0)
+
+
+static struct dentry *debugfs_dir_entry;
+static struct dentry *debugfs_modem_entry;
+static struct dentry *debugfs_dsp_entry;
+
+static uint8_t in_bytebuf[BYTEBUF_LEN];
+static uint8_t out_bytebuf[BYTEBUF_LEN];
+static uint8_t out_bytebuf2[BYTEBUF_LEN];
+static struct remote_test_data in_data;
+static struct remote_test_data out_data;
+static int block_until_cb = 1;
+
+static void init_data(struct remote_test_data *data)
+{
+	int i;
+	data->regular_event = REMOTE_UNITTEST_INPUT_HANDLE;
+	data->payload_event = REMOTE_UNITTEST_INPUT_HANDLE;
+	for (i = 0; i < 32; i++)
+		data->test[i] = i;
+}
+
+static int verify_data(struct remote_test_data *data)
+{
+	int i;
+	if (data->regular_event != REMOTE_UNITTEST_INPUT_HANDLE ||
+	    data->payload_event != REMOTE_UNITTEST_INPUT_HANDLE)
+		return -1;
+	for (i = 0; i < 32; i++)
+		if (data->test[i] != i)
+			return -1;
+
+	return 0;
+}
+
+static int verify_uint32_buffer(uint32_t *buf)
+{
+	int i;
+	for (i = 0; i < 32; i++)
+		if (buf[i] != i)
+			return -1;
+
+	return 0;
+}
+
+static void init_bytebuf(uint8_t *bytebuf)
+{
+	int i;
+	for (i = 0; i < BYTEBUF_LEN; i++)
+		bytebuf[i] = i & 0xff;
+}
+
+static int verify_bytebuf(uint8_t *bytebuf)
+{
+	int i;
+	for (i = 0; i < BYTEBUF_LEN; i++)
+		if (bytebuf[i] != (i & 0xff))
+			return -1;
+
+	return 0;
+}
+
+static void test_cb(void *context, uint32_t param, void *data, uint32_t len)
+{
+	block_until_cb = 0;
+}
+
+static int remotetest_exec(int dest, u64 *val)
+{
+	void *dev_handle;
+	void *event_handles[3];
+	void *cb_handle;
+	int ret;
+	u64 errmask = 0;
+	uint32_t ouint;
+	uint32_t oalen;
+
+	/* test daldevice_attach */
+	ret = daldevice_attach(REMOTE_UNITTEST_DEVICEID, NULL,
+			       dest, &dev_handle);
+	if (ret) {
+		printk(KERN_INFO "%s: failed to attach (%d)\n", __func__, ret);
+		*val = 0xffffffff;
+		return 0;
+	}
+
+	/* test remote_unittest_0 */
+	ret = remote_unittest_0(dev_handle, REMOTE_UNITTEST_INARG_1);
+	if (ret)
+		rpc_error(0);
+
+	/* test remote_unittest_1 */
+	ret = remote_unittest_1(dev_handle, REMOTE_UNITTEST_INARG_1,
+				REMOTE_UNITTEST_INARG_2);
+	if (ret)
+		rpc_error(1);
+
+	/* test remote_unittest_2 */
+	ouint = 0;
+	ret = remote_unittest_2(dev_handle, REMOTE_UNITTEST_INARG_1, &ouint);
+	if (ret)
+		rpc_error(2);
+	else if (ouint != REMOTE_UNITTEST_OUTARG_1)
+		verify_error(2, "ouint");
+
+	/* test remote_unittest_3 */
+	ret = remote_unittest_3(dev_handle, REMOTE_UNITTEST_INARG_1,
+				REMOTE_UNITTEST_INARG_2,
+				REMOTE_UNITTEST_INARG_3);
+	if (ret)
+		rpc_error(3);
+
+	/* test remote_unittest_4 */
+	ouint = 0;
+	ret = remote_unittest_4(dev_handle, REMOTE_UNITTEST_INARG_1,
+				REMOTE_UNITTEST_INARG_2, &ouint);
+	if (ret)
+		rpc_error(4);
+	else if (ouint != REMOTE_UNITTEST_OUTARG_1)
+		verify_error(4, "ouint");
+
+	/* test remote_unittest_5 */
+	init_data(&in_data);
+	ret = remote_unittest_5(dev_handle, &in_data, sizeof(in_data));
+	if (ret)
+		rpc_error(5);
+
+	/* test remote_unittest_6 */
+	init_data(&in_data);
+	ret = remote_unittest_6(dev_handle, REMOTE_UNITTEST_INARG_1,
+				&in_data.test, sizeof(in_data.test));
+	if (ret)
+		rpc_error(6);
+
+	/* test remote_unittest_7 */
+	init_data(&in_data);
+	memset(&out_data, 0, sizeof(out_data));
+	ret = remote_unittest_7(dev_handle, &in_data, sizeof(in_data),
+				&out_data.test, sizeof(out_data.test),
+				&oalen);
+	if (ret)
+		rpc_error(7);
+	else if (oalen != sizeof(out_data.test))
+		verify_error(7, "oalen");
+	else if (verify_uint32_buffer(out_data.test))
+		verify_error(7, "obuf");
+
+	/* test remote_unittest_8 */
+	init_bytebuf(in_bytebuf);
+	memset(&out_data, 0, sizeof(out_data));
+	ret = remote_unittest_8(dev_handle, in_bytebuf, sizeof(in_bytebuf),
+				&out_data, sizeof(out_data));
+	if (ret)
+		rpc_error(8);
+	else if (verify_data(&out_data))
+		verify_error(8, "obuf");
+
+	/* test remote_unittest_9 */
+	memset(&out_bytebuf, 0, sizeof(out_bytebuf));
+	ret = remote_unittest_9(dev_handle, out_bytebuf, sizeof(out_bytebuf));
+	if (ret)
+		rpc_error(9);
+	else if (verify_bytebuf(out_bytebuf))
+		verify_error(9, "obuf");
+
+	/* test remote_unittest_10 */
+	init_bytebuf(in_bytebuf);
+	memset(&out_bytebuf, 0, sizeof(out_bytebuf));
+	ret = remote_unittest_10(dev_handle, REMOTE_UNITTEST_INARG_1,
+				 in_bytebuf, sizeof(in_bytebuf),
+				 out_bytebuf, sizeof(out_bytebuf), &oalen);
+	if (ret)
+		rpc_error(10);
+	else if (oalen != sizeof(out_bytebuf))
+		verify_error(10, "oalen");
+	else if (verify_bytebuf(out_bytebuf))
+		verify_error(10, "obuf");
+
+	/* test remote_unittest_11 */
+	memset(&out_bytebuf, 0, sizeof(out_bytebuf));
+	ret = remote_unittest_11(dev_handle, REMOTE_UNITTEST_INARG_1,
+				 out_bytebuf, sizeof(out_bytebuf));
+	if (ret)
+		rpc_error(11);
+	else if (verify_bytebuf(out_bytebuf))
+		verify_error(11, "obuf");
+
+	/* test remote_unittest_12 */
+	memset(&out_bytebuf, 0, sizeof(out_bytebuf));
+	ret = remote_unittest_12(dev_handle, REMOTE_UNITTEST_INARG_1,
+				 out_bytebuf, sizeof(out_bytebuf), &oalen);
+	if (ret)
+		rpc_error(12);
+	else if (oalen != sizeof(out_bytebuf))
+		verify_error(12, "oalen");
+	else if (verify_bytebuf(out_bytebuf))
+		verify_error(12, "obuf");
+
+	/* test remote_unittest_13 */
+	init_data(&in_data);
+	memset(&out_data, 0, sizeof(out_data));
+	ret = remote_unittest_13(dev_handle, in_data.test, sizeof(in_data.test),
+				 &in_data, sizeof(in_data),
+				 &out_data, sizeof(out_data));
+	if (ret)
+		rpc_error(13);
+	else if (verify_data(&out_data))
+		verify_error(13, "obuf");
+
+	/* test remote_unittest_14 */
+	init_data(&in_data);
+	memset(out_bytebuf, 0, sizeof(out_bytebuf));
+	memset(out_bytebuf2, 0, sizeof(out_bytebuf2));
+	ret = remote_unittest_14(dev_handle,
+				 in_data.test, sizeof(in_data.test),
+				 out_bytebuf, sizeof(out_bytebuf),
+				 out_bytebuf2, sizeof(out_bytebuf2), &oalen);
+	if (ret)
+		rpc_error(14);
+	else if (verify_bytebuf(out_bytebuf))
+		verify_error(14, "obuf");
+	else if (oalen != sizeof(out_bytebuf2))
+		verify_error(14, "oalen");
+	else if (verify_bytebuf(out_bytebuf2))
+		verify_error(14, "obuf2");
+
+	/* test remote_unittest_15 */
+	init_data(&in_data);
+	memset(out_bytebuf, 0, sizeof(out_bytebuf));
+	memset(&out_data, 0, sizeof(out_data));
+	ret = remote_unittest_15(dev_handle,
+				 in_data.test, sizeof(in_data.test),
+				 &in_data, sizeof(in_data),
+				 &out_data, sizeof(out_data), &oalen,
+				 out_bytebuf, sizeof(out_bytebuf));
+	if (ret)
+		rpc_error(15);
+	else if (oalen != sizeof(out_data))
+		verify_error(15, "oalen");
+	else if (verify_bytebuf(out_bytebuf))
+		verify_error(15, "obuf");
+	else if (verify_data(&out_data))
+		verify_error(15, "obuf2");
+
+	/* test setting up asynch events */
+	event_handles[0] = dalrpc_alloc_event(dev_handle);
+	event_handles[1] = dalrpc_alloc_event(dev_handle);
+	event_handles[2] = dalrpc_alloc_event(dev_handle);
+	cb_handle = dalrpc_alloc_cb(dev_handle, test_cb, &out_data);
+	in_data.regular_event = (uint32_t)event_handles[2];
+	in_data.payload_event = (uint32_t)cb_handle;
+	ret = remote_unittest_eventcfg(dev_handle, &in_data, sizeof(in_data));
+	if (ret) {
+		errmask |= (1 << 16);
+		printk(KERN_INFO "%s: failed to configure asynch (%d)\n",
+		       __func__, ret);
+	}
+
+	/* test event */
+	ret = remote_unittest_eventtrig(dev_handle,
+					REMOTE_UNITTEST_REGULAR_EVENT);
+	if (ret) {
+		errmask |= (1 << 17);
+		printk(KERN_INFO "%s: failed to trigger event (%d)\n",
+		       __func__, ret);
+	}
+	ret = dalrpc_event_wait(event_handles[2], 1000);
+	if (ret) {
+		errmask |= (1 << 18);
+		printk(KERN_INFO "%s: failed to receive event (%d)\n",
+		       __func__, ret);
+	}
+
+	/* test event again */
+	ret = remote_unittest_eventtrig(dev_handle,
+					REMOTE_UNITTEST_REGULAR_EVENT);
+	if (ret) {
+		errmask |= (1 << 19);
+		printk(KERN_INFO "%s: failed to trigger event (%d)\n",
+		       __func__, ret);
+	}
+	ret = dalrpc_event_wait_multiple(3, event_handles, 1000);
+	if (ret != 2) {
+		errmask |= (1 << 20);
+		printk(KERN_INFO "%s: failed to receive event (%d)\n",
+		       __func__, ret);
+	}
+
+	/* test callback */
+	ret = remote_unittest_eventtrig(dev_handle,
+					REMOTE_UNITTEST_CALLBACK_EVENT);
+	if (ret) {
+		errmask |= (1 << 21);
+		printk(KERN_INFO "%s: failed to trigger callback (%d)\n",
+		       __func__, ret);
+	} else
+		while (block_until_cb)
+			;
+
+	dalrpc_dealloc_cb(dev_handle, cb_handle);
+	dalrpc_dealloc_event(dev_handle, event_handles[0]);
+	dalrpc_dealloc_event(dev_handle, event_handles[1]);
+	dalrpc_dealloc_event(dev_handle, event_handles[2]);
+
+	/* test daldevice_detach */
+	ret = daldevice_detach(dev_handle);
+	if (ret) {
+		errmask |= (1 << 22);
+		printk(KERN_INFO "%s: failed to detach (%d)\n", __func__, ret);
+	}
+
+	printk(KERN_INFO "%s: remote_unittest complete\n", __func__);
+
+	*val = errmask;
+	return 0;
+}
+
+static int remotetest_modem_exec(void *data, u64 *val)
+{
+	return remotetest_exec(DALRPC_DEST_MODEM, val);
+}
+
+static int remotetest_dsp_exec(void *data, u64 *val)
+{
+	return remotetest_exec(DALRPC_DEST_QDSP, val);
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(dal_modemtest_fops, remotetest_modem_exec,
+			NULL, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(dal_dsptest_fops, remotetest_dsp_exec,
+			NULL, "%llu\n");
+
+static int __init remotetest_init(void)
+{
+	debugfs_dir_entry = debugfs_create_dir("dal", 0);
+	if (IS_ERR(debugfs_dir_entry))
+		return PTR_ERR(debugfs_dir_entry);
+
+	debugfs_modem_entry = debugfs_create_file("modem_test", 0444,
+						  debugfs_dir_entry,
+						  NULL, &dal_modemtest_fops);
+	if (IS_ERR(debugfs_modem_entry)) {
+		debugfs_remove(debugfs_dir_entry);
+		return PTR_ERR(debugfs_modem_entry);
+	}
+
+	debugfs_dsp_entry = debugfs_create_file("dsp_test", 0444,
+					    debugfs_dir_entry,
+					    NULL, &dal_dsptest_fops);
+	if (IS_ERR(debugfs_dsp_entry)) {
+		debugfs_remove(debugfs_modem_entry);
+		debugfs_remove(debugfs_dir_entry);
+		return PTR_ERR(debugfs_dsp_entry);
+	}
+
+	return 0;
+}
+
+static void __exit remotetest_exit(void)
+{
+	debugfs_remove(debugfs_modem_entry);
+	debugfs_remove(debugfs_dsp_entry);
+	debugfs_remove(debugfs_dir_entry);
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Test for DAL RPC");
+MODULE_VERSION("1.0");
+
+module_init(remotetest_init);
+module_exit(remotetest_exit);
diff --git a/arch/arm/mach-msm/dal_remotetest.h b/arch/arm/mach-msm/dal_remotetest.h
new file mode 100644
index 0000000..cb998c9
--- /dev/null
+++ b/arch/arm/mach-msm/dal_remotetest.h
@@ -0,0 +1,172 @@
+/* Copyright (c) 2008-2009, 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.
+ *
+ */
+/*
+ * DAL remote test device API.
+ */
+
+#include <linux/kernel.h>
+
+#include <mach/dal.h>
+
+#define REMOTE_UNITTEST_DEVICEID 0xDA1DA1DA
+
+enum {
+	DALRPC_TEST_API_0 = DALDEVICE_FIRST_DEVICE_API_IDX,
+	DALRPC_TEST_API_1,
+	DALRPC_TEST_API_2,
+	DALRPC_TEST_API_3,
+	DALRPC_TEST_API_4,
+	DALRPC_TEST_API_5,
+	DALRPC_TEST_API_6,
+	DALRPC_TEST_API_7,
+	DALRPC_TEST_API_8,
+	DALRPC_TEST_API_9,
+	DALRPC_TEST_API_10,
+	DALRPC_TEST_API_11,
+	DALRPC_TEST_API_12,
+	DALRPC_TEST_API_13,
+	DALRPC_TEST_API_14,
+	DALRPC_TEST_API_15,
+	DALRPC_TEST_API_16,
+	DALRPC_TEST_API_17
+};
+
+#define REMOTE_UNITTEST_INARG_1 0x01010101
+#define REMOTE_UNITTEST_INARG_2 0x20202020
+#define REMOTE_UNITTEST_INARG_3 0x12121212
+#define REMOTE_UNITTEST_INPUT_HANDLE 0xDA1FDA1F
+#define REMOTE_UNITTEST_OUTARG_1 0xBEEFDEAD
+
+#define REMOTE_UNITTEST_REGULAR_EVENT 0
+#define REMOTE_UNITTEST_CALLBACK_EVENT 1
+
+#define REMOTE_UNITTEST_BAD_PARAM 0x10
+
+struct remote_test_data {
+	uint32_t regular_event;
+	uint32_t test[32];
+	uint32_t payload_event;
+};
+
+static int remote_unittest_0(void *handle, uint32_t s1)
+{
+	return dalrpc_fcn_0(DALRPC_TEST_API_0, handle, s1);
+}
+
+static int remote_unittest_1(void *handle, uint32_t s1, uint32_t s2)
+{
+	return dalrpc_fcn_1(DALRPC_TEST_API_1, handle, s1, s2);
+}
+
+static int remote_unittest_2(void *handle, uint32_t s1, uint32_t *p_s2)
+{
+	return dalrpc_fcn_2(DALRPC_TEST_API_2, handle, s1, p_s2);
+}
+
+static int remote_unittest_3(void *handle, uint32_t s1, uint32_t s2,
+			     uint32_t s3)
+{
+	return dalrpc_fcn_3(DALRPC_TEST_API_3, handle, s1, s2, s3);
+}
+
+static int remote_unittest_4(void *handle, uint32_t s1, uint32_t s2,
+			     uint32_t *p_s3)
+{
+	return dalrpc_fcn_4(DALRPC_TEST_API_4, handle, s1, s2, p_s3);
+}
+
+static int remote_unittest_5(void *handle, const void *ibuf, uint32_t ilen)
+{
+	return dalrpc_fcn_5(DALRPC_TEST_API_5, handle, ibuf, ilen);
+}
+
+static int remote_unittest_6(void *handle, uint32_t s1, const void *ibuf,
+			     uint32_t ilen)
+{
+	return dalrpc_fcn_6(DALRPC_TEST_API_6, handle, s1, ibuf, ilen);
+}
+
+static int remote_unittest_7(void *handle, const void *ibuf, uint32_t ilen,
+			     void *obuf, uint32_t olen, uint32_t *oalen)
+{
+	return dalrpc_fcn_7(DALRPC_TEST_API_7, handle, ibuf, ilen, obuf,
+			    olen, oalen);
+}
+
+static int remote_unittest_8(void *handle, const void *ibuf, uint32_t ilen,
+			     void *obuf, uint32_t olen)
+{
+	return dalrpc_fcn_8(DALRPC_TEST_API_8, handle, ibuf, ilen, obuf, olen);
+}
+
+static int remote_unittest_9(void *handle, void *obuf, uint32_t olen)
+{
+	return dalrpc_fcn_9(DALRPC_TEST_API_9, handle, obuf, olen);
+}
+
+static int remote_unittest_10(void *handle, uint32_t s1, const void *ibuf,
+			      uint32_t ilen, void *obuf, uint32_t olen,
+			      uint32_t *oalen)
+{
+	return dalrpc_fcn_10(DALRPC_TEST_API_10, handle, s1, ibuf, ilen, obuf,
+			     olen, oalen);
+}
+
+static int remote_unittest_11(void *handle, uint32_t s1, void *obuf,
+			      uint32_t olen)
+{
+	return dalrpc_fcn_11(DALRPC_TEST_API_11, handle, s1, obuf, olen);
+}
+
+static int remote_unittest_12(void *handle, uint32_t s1, void *obuf,
+			      uint32_t olen, uint32_t *oalen)
+{
+	return dalrpc_fcn_12(DALRPC_TEST_API_12, handle, s1, obuf, olen,
+			     oalen);
+}
+
+static int remote_unittest_13(void *handle, const void *ibuf, uint32_t ilen,
+			      const void *ibuf2, uint32_t ilen2, void *obuf,
+			      uint32_t olen)
+{
+	return dalrpc_fcn_13(DALRPC_TEST_API_13, handle, ibuf, ilen, ibuf2,
+			     ilen2, obuf, olen);
+}
+
+static int remote_unittest_14(void *handle, const void *ibuf, uint32_t ilen,
+			      void *obuf, uint32_t olen, void *obuf2,
+			      uint32_t olen2, uint32_t *oalen2)
+{
+	return dalrpc_fcn_14(DALRPC_TEST_API_14, handle, ibuf, ilen, obuf,
+			     olen, obuf2, olen2, oalen2);
+}
+
+static int remote_unittest_15(void *handle, const void *ibuf, uint32_t ilen,
+			      const void *ibuf2, uint32_t ilen2, void *obuf,
+			      uint32_t olen, uint32_t *oalen, void *obuf2,
+			      uint32_t olen2)
+{
+	return dalrpc_fcn_15(DALRPC_TEST_API_15, handle, ibuf, ilen, ibuf2,
+			     ilen2, obuf, olen, oalen, obuf2, olen2);
+}
+
+static int remote_unittest_eventcfg(void *handle, const void *ibuf,
+				    uint32_t ilen)
+{
+	return dalrpc_fcn_5(DALRPC_TEST_API_16, handle, ibuf, ilen);
+}
+
+static int remote_unittest_eventtrig(void *handle, uint32_t event_idx)
+{
+	return dalrpc_fcn_0(DALRPC_TEST_API_17, handle, event_idx);
+}
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
new file mode 100644
index 0000000..ef9b62a
--- /dev/null
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -0,0 +1,2611 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/msm_rotator.h>
+#include <linux/clkdev.h>
+#include <linux/dma-mapping.h>
+#include <mach/irqs-8064.h>
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+#include <mach/usbdiag.h>
+#include <mach/msm_sps.h>
+#include <mach/dma.h>
+#include <mach/msm_dsps.h>
+#include <sound/msm-dai-q6.h>
+#include <sound/apr_audio.h>
+#include <mach/msm_bus_board.h>
+#include <mach/rpm.h>
+#include <mach/mdm2.h>
+#include <mach/msm_smd.h>
+#include <mach/msm_dcvs.h>
+#include <mach/msm_rtb.h>
+#include <mach/qdss.h>
+#include <linux/ion.h>
+#include "clock.h"
+#include "devices.h"
+#include "footswitch.h"
+#include "msm_watchdog.h"
+#include "rpm_stats.h"
+#include "rpm_log.h"
+#include <mach/mpm.h>
+#include <mach/iommu_domains.h>
+#include <mach/msm_cache_dump.h>
+
+/* Address of GSBI blocks */
+#define MSM_GSBI1_PHYS		0x12440000
+#define MSM_GSBI3_PHYS		0x16200000
+#define MSM_GSBI4_PHYS		0x16300000
+#define MSM_GSBI5_PHYS		0x1A200000
+#define MSM_GSBI6_PHYS		0x16500000
+#define MSM_GSBI7_PHYS		0x16600000
+
+/* GSBI UART devices */
+#define MSM_UART1DM_PHYS	(MSM_GSBI1_PHYS + 0x10000)
+#define MSM_UART3DM_PHYS	(MSM_GSBI3_PHYS + 0x40000)
+#define MSM_UART7DM_PHYS	(MSM_GSBI7_PHYS + 0x40000)
+
+/* GSBI QUP devices */
+#define MSM_GSBI1_QUP_PHYS	(MSM_GSBI1_PHYS + 0x20000)
+#define MSM_GSBI3_QUP_PHYS	(MSM_GSBI3_PHYS + 0x80000)
+#define MSM_GSBI4_QUP_PHYS	(MSM_GSBI4_PHYS + 0x80000)
+#define MSM_GSBI5_QUP_PHYS	(MSM_GSBI5_PHYS + 0x80000)
+#define MSM_GSBI6_QUP_PHYS	(MSM_GSBI6_PHYS + 0x80000)
+#define MSM_GSBI7_QUP_PHYS	(MSM_GSBI7_PHYS + 0x80000)
+#define MSM_QUP_SIZE		SZ_4K
+
+/* Address of SSBI CMD */
+#define MSM_PMIC1_SSBI_CMD_PHYS	0x00500000
+#define MSM_PMIC2_SSBI_CMD_PHYS	0x00C00000
+#define MSM_PMIC_SSBI_SIZE	SZ_4K
+
+/* Address of HS USBOTG1 */
+#define MSM_HSUSB1_PHYS		0x12500000
+#define MSM_HSUSB1_SIZE		SZ_4K
+
+/* Address of HS USB3 */
+#define MSM_HSUSB3_PHYS		0x12520000
+#define MSM_HSUSB3_SIZE		SZ_4K
+
+/* Address of HS USB4 */
+#define MSM_HSUSB4_PHYS		0x12530000
+#define MSM_HSUSB4_SIZE		SZ_4K
+
+/* Address of PCIE20 PARF */
+#define PCIE20_PARF_PHYS   0x1b600000
+#define PCIE20_PARF_SIZE   SZ_128
+
+/* Address of PCIE20 ELBI */
+#define PCIE20_ELBI_PHYS   0x1b502000
+#define PCIE20_ELBI_SIZE   SZ_256
+
+/* Address of PCIE20 */
+#define PCIE20_PHYS   0x1b500000
+#define PCIE20_SIZE   SZ_4K
+
+/* AXI address for PCIE device BAR resources */
+#define PCIE_AXI_BAR_PHYS   0x08000000
+#define PCIE_AXI_BAR_SIZE   SZ_8M
+
+/* AXI address for PCIE device config space */
+#define PCIE_AXI_CONF_PHYS   0x08c00000
+#define PCIE_AXI_CONF_SIZE   SZ_4K
+
+static struct msm_watchdog_pdata msm_watchdog_pdata = {
+	.pet_time = 10000,
+	.bark_time = 11000,
+	.has_secure = true,
+	.needs_expired_enable = true,
+};
+
+struct platform_device msm8064_device_watchdog = {
+	.name = "msm_watchdog",
+	.id = -1,
+	.dev = {
+		.platform_data = &msm_watchdog_pdata,
+	},
+};
+
+static struct resource msm_dmov_resource[] = {
+	{
+		.start = ADM_0_SCSS_1_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = 0x18320000,
+		.end = 0x18320000 + SZ_1M - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct msm_dmov_pdata msm_dmov_pdata = {
+	.sd = 1,
+	.sd_size = 0x800,
+};
+
+struct platform_device apq8064_device_dmov = {
+	.name	= "msm_dmov",
+	.id	= -1,
+	.resource = msm_dmov_resource,
+	.num_resources = ARRAY_SIZE(msm_dmov_resource),
+	.dev = {
+		.platform_data = &msm_dmov_pdata,
+	},
+};
+
+static struct resource resources_uart_gsbi1[] = {
+	{
+		.start	= APQ8064_GSBI1_UARTDM_IRQ,
+		.end	= APQ8064_GSBI1_UARTDM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM_UART1DM_PHYS,
+		.end	= MSM_UART1DM_PHYS + PAGE_SIZE - 1,
+		.name	= "uartdm_resource",
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= MSM_GSBI1_PHYS,
+		.end	= MSM_GSBI1_PHYS + PAGE_SIZE - 1,
+		.name	= "gsbi_resource",
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+struct platform_device apq8064_device_uart_gsbi1 = {
+	.name	= "msm_serial_hsl",
+	.id	= 1,
+	.num_resources	= ARRAY_SIZE(resources_uart_gsbi1),
+	.resource	= resources_uart_gsbi1,
+};
+
+static struct resource resources_uart_gsbi3[] = {
+	{
+		.start	= GSBI3_UARTDM_IRQ,
+		.end	= GSBI3_UARTDM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM_UART3DM_PHYS,
+		.end	= MSM_UART3DM_PHYS + PAGE_SIZE - 1,
+		.name	= "uartdm_resource",
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= MSM_GSBI3_PHYS,
+		.end	= MSM_GSBI3_PHYS + PAGE_SIZE - 1,
+		.name	= "gsbi_resource",
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+struct platform_device apq8064_device_uart_gsbi3 = {
+	.name	= "msm_serial_hsl",
+	.id	= 0,
+	.num_resources	= ARRAY_SIZE(resources_uart_gsbi3),
+	.resource	= resources_uart_gsbi3,
+};
+
+static struct resource resources_qup_i2c_gsbi3[] = {
+	{
+		.name	= "gsbi_qup_i2c_addr",
+		.start	= MSM_GSBI3_PHYS,
+		.end	= MSM_GSBI3_PHYS + 4 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_phys_addr",
+		.start	= MSM_GSBI3_QUP_PHYS,
+		.end	= MSM_GSBI3_QUP_PHYS + MSM_QUP_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_err_intr",
+		.start	= GSBI3_QUP_IRQ,
+		.end	= GSBI3_QUP_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "i2c_clk",
+		.start	= 9,
+		.end	= 9,
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.name	= "i2c_sda",
+		.start	= 8,
+		.end	= 8,
+		.flags	= IORESOURCE_IO,
+	},
+};
+
+static struct resource resources_qup_i2c_gsbi1[] = {
+	{
+		.name	= "gsbi_qup_i2c_addr",
+		.start	= MSM_GSBI1_PHYS,
+		.end	= MSM_GSBI1_PHYS + 4 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_phys_addr",
+		.start	= MSM_GSBI1_QUP_PHYS,
+		.end	= MSM_GSBI1_QUP_PHYS + MSM_QUP_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_err_intr",
+		.start	= APQ8064_GSBI1_QUP_IRQ,
+		.end	= APQ8064_GSBI1_QUP_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "i2c_clk",
+		.start	= 21,
+		.end	= 21,
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.name	= "i2c_sda",
+		.start	= 20,
+		.end	= 20,
+		.flags	= IORESOURCE_IO,
+	},
+};
+
+struct platform_device apq8064_device_qup_i2c_gsbi1 = {
+	.name		= "qup_i2c",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(resources_qup_i2c_gsbi1),
+	.resource	= resources_qup_i2c_gsbi1,
+};
+
+struct platform_device apq8064_device_qup_i2c_gsbi3 = {
+	.name		= "qup_i2c",
+	.id		= 3,
+	.num_resources	= ARRAY_SIZE(resources_qup_i2c_gsbi3),
+	.resource	= resources_qup_i2c_gsbi3,
+};
+
+static struct resource resources_qup_i2c_gsbi4[] = {
+	{
+		.name	= "gsbi_qup_i2c_addr",
+		.start	= MSM_GSBI4_PHYS,
+		.end	= MSM_GSBI4_PHYS + 4 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_phys_addr",
+		.start	= MSM_GSBI4_QUP_PHYS,
+		.end	= MSM_GSBI4_QUP_PHYS + MSM_QUP_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_err_intr",
+		.start	= GSBI4_QUP_IRQ,
+		.end	= GSBI4_QUP_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "i2c_clk",
+		.start	= 11,
+		.end	= 11,
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.name	= "i2c_sda",
+		.start	= 10,
+		.end	= 10,
+		.flags	= IORESOURCE_IO,
+	},
+};
+
+struct platform_device apq8064_device_qup_i2c_gsbi4 = {
+	.name		= "qup_i2c",
+	.id		= 4,
+	.num_resources	= ARRAY_SIZE(resources_qup_i2c_gsbi4),
+	.resource	= resources_qup_i2c_gsbi4,
+};
+
+static struct resource resources_qup_spi_gsbi5[] = {
+	{
+		.name   = "spi_base",
+		.start  = MSM_GSBI5_QUP_PHYS,
+		.end    = MSM_GSBI5_QUP_PHYS + SZ_4K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "gsbi_base",
+		.start  = MSM_GSBI5_PHYS,
+		.end    = MSM_GSBI5_PHYS + 4 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "spi_irq_in",
+		.start  = GSBI5_QUP_IRQ,
+		.end    = GSBI5_QUP_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device apq8064_device_qup_spi_gsbi5 = {
+	.name		= "spi_qsd",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(resources_qup_spi_gsbi5),
+	.resource	= resources_qup_spi_gsbi5,
+};
+
+static struct resource resources_qup_i2c_gsbi5[] = {
+	{
+		.name	= "gsbi_qup_i2c_addr",
+		.start	= MSM_GSBI5_PHYS,
+		.end	= MSM_GSBI5_PHYS + 4 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_phys_addr",
+		.start	= MSM_GSBI5_QUP_PHYS,
+		.end	= MSM_GSBI5_QUP_PHYS + MSM_QUP_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_err_intr",
+		.start	= GSBI5_QUP_IRQ,
+		.end	= GSBI5_QUP_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "i2c_clk",
+		.start	= 54,
+		.end	= 54,
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.name	= "i2c_sda",
+		.start	= 53,
+		.end	= 53,
+		.flags	= IORESOURCE_IO,
+	},
+};
+
+struct platform_device mpq8064_device_qup_i2c_gsbi5 = {
+	.name		= "qup_i2c",
+	.id		= 5,
+	.num_resources	= ARRAY_SIZE(resources_qup_i2c_gsbi5),
+	.resource	= resources_qup_i2c_gsbi5,
+};
+
+static struct resource resources_uart_gsbi7[] = {
+	{
+		.start	= GSBI7_UARTDM_IRQ,
+		.end	= GSBI7_UARTDM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM_UART7DM_PHYS,
+		.end	= MSM_UART7DM_PHYS + PAGE_SIZE - 1,
+		.name	= "uartdm_resource",
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= MSM_GSBI7_PHYS,
+		.end	= MSM_GSBI7_PHYS + PAGE_SIZE - 1,
+		.name	= "gsbi_resource",
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+struct platform_device apq8064_device_uart_gsbi7 = {
+	.name	= "msm_serial_hsl",
+	.id	= 0,
+	.num_resources	= ARRAY_SIZE(resources_uart_gsbi7),
+	.resource	= resources_uart_gsbi7,
+};
+
+struct platform_device apq_pcm = {
+	.name	= "msm-pcm-dsp",
+	.id	= -1,
+};
+
+struct platform_device apq_pcm_routing = {
+	.name	= "msm-pcm-routing",
+	.id	= -1,
+};
+
+struct platform_device apq_cpudai0 = {
+	.name	= "msm-dai-q6",
+	.id	= 0x4000,
+};
+
+struct platform_device apq_cpudai1 = {
+	.name	= "msm-dai-q6",
+	.id	= 0x4001,
+};
+struct platform_device mpq_cpudai_sec_i2s_rx = {
+	.name = "msm-dai-q6",
+	.id = 4,
+};
+struct platform_device apq_cpudai_hdmi_rx = {
+	.name	= "msm-dai-q6-hdmi",
+	.id	= 8,
+};
+
+struct platform_device apq_cpudai_bt_rx = {
+	.name   = "msm-dai-q6",
+	.id     = 0x3000,
+};
+
+struct platform_device apq_cpudai_bt_tx = {
+	.name   = "msm-dai-q6",
+	.id     = 0x3001,
+};
+
+struct platform_device apq_cpudai_fm_rx = {
+	.name   = "msm-dai-q6",
+	.id     = 0x3004,
+};
+
+struct platform_device apq_cpudai_fm_tx = {
+	.name   = "msm-dai-q6",
+	.id     = 0x3005,
+};
+
+struct platform_device apq_cpudai_slim_4_rx = {
+	.name   = "msm-dai-q6",
+	.id     = 0x4008,
+};
+
+struct platform_device apq_cpudai_slim_4_tx = {
+	.name   = "msm-dai-q6",
+	.id     = 0x4009,
+};
+
+/*
+ * Machine specific data for AUX PCM Interface
+ * which the driver will  be unware of.
+ */
+struct msm_dai_auxpcm_pdata apq_auxpcm_pdata = {
+	.clk = "pcm_clk",
+	.mode_8k = {
+		.mode = AFE_PCM_CFG_MODE_PCM,
+		.sync = AFE_PCM_CFG_SYNC_INT,
+		.frame = AFE_PCM_CFG_FRM_256BPF,
+		.quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
+		.slot = 0,
+		.data = AFE_PCM_CFG_CDATAOE_MASTER,
+		.pcm_clk_rate = 2048000,
+	},
+	.mode_16k = {
+		.mode = AFE_PCM_CFG_MODE_PCM,
+		.sync = AFE_PCM_CFG_SYNC_INT,
+		.frame = AFE_PCM_CFG_FRM_256BPF,
+		.quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
+		.slot = 0,
+		.data = AFE_PCM_CFG_CDATAOE_MASTER,
+		.pcm_clk_rate = 4096000,
+	}
+};
+
+struct platform_device apq_cpudai_auxpcm_rx = {
+	.name = "msm-dai-q6",
+	.id = 2,
+	.dev = {
+		.platform_data = &apq_auxpcm_pdata,
+	},
+};
+
+struct platform_device apq_cpudai_auxpcm_tx = {
+	.name = "msm-dai-q6",
+	.id = 3,
+	.dev = {
+		.platform_data = &apq_auxpcm_pdata,
+	},
+};
+
+struct msm_mi2s_pdata mpq_mi2s_tx_data = {
+	.rx_sd_lines = 0,
+	.tx_sd_lines = MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2 |
+		       MSM_MI2S_SD3,
+};
+
+struct platform_device mpq_cpudai_mi2s_tx = {
+	.name	= "msm-dai-q6-mi2s",
+	.id	= -1, /*MI2S_TX */
+	.dev = {
+		.platform_data = &mpq_mi2s_tx_data,
+	},
+};
+
+struct platform_device apq_cpu_fe = {
+	.name	= "msm-dai-fe",
+	.id	= -1,
+};
+
+struct platform_device apq_stub_codec = {
+	.name	= "msm-stub-codec",
+	.id	= 1,
+};
+
+struct platform_device apq_voice = {
+	.name	= "msm-pcm-voice",
+	.id	= -1,
+};
+
+struct platform_device apq_voip = {
+	.name	= "msm-voip-dsp",
+	.id	= -1,
+};
+
+struct platform_device apq_lpa_pcm = {
+	.name   = "msm-pcm-lpa",
+	.id     = -1,
+};
+
+struct platform_device apq_compr_dsp = {
+	.name   = "msm-compr-dsp",
+	.id     = -1,
+};
+
+struct platform_device apq_multi_ch_pcm = {
+	.name   = "msm-multi-ch-pcm-dsp",
+	.id     = -1,
+};
+
+struct platform_device apq_pcm_hostless = {
+	.name	= "msm-pcm-hostless",
+	.id	= -1,
+};
+
+struct platform_device apq_cpudai_afe_01_rx = {
+	.name = "msm-dai-q6",
+	.id = 0xE0,
+};
+
+struct platform_device apq_cpudai_afe_01_tx = {
+	.name = "msm-dai-q6",
+	.id = 0xF0,
+};
+
+struct platform_device apq_cpudai_afe_02_rx = {
+	.name = "msm-dai-q6",
+	.id = 0xF1,
+};
+
+struct platform_device apq_cpudai_afe_02_tx = {
+	.name = "msm-dai-q6",
+	.id = 0xE1,
+};
+
+struct platform_device apq_pcm_afe = {
+	.name	= "msm-pcm-afe",
+	.id	= -1,
+};
+
+struct platform_device apq_cpudai_stub = {
+	.name = "msm-dai-stub",
+	.id = -1,
+};
+
+struct platform_device apq_cpudai_slimbus_1_rx = {
+	.name = "msm-dai-q6",
+	.id = 0x4002,
+};
+
+struct platform_device apq_cpudai_slimbus_1_tx = {
+	.name = "msm-dai-q6",
+	.id = 0x4003,
+};
+
+struct platform_device apq_cpudai_slimbus_2_tx = {
+	.name = "msm-dai-q6",
+	.id = 0x4005,
+};
+
+struct platform_device apq_cpudai_slimbus_3_rx = {
+	.name = "msm-dai-q6",
+	.id = 0x4006,
+};
+
+static struct resource resources_ssbi_pmic1[] = {
+	{
+		.start  = MSM_PMIC1_SSBI_CMD_PHYS,
+		.end    = MSM_PMIC1_SSBI_CMD_PHYS + MSM_PMIC_SSBI_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+#define LPASS_SLIMBUS_PHYS	0x28080000
+#define LPASS_SLIMBUS_BAM_PHYS	0x28084000
+#define LPASS_SLIMBUS_SLEW	(MSM8960_TLMM_PHYS + 0x207C)
+/* Board info for the slimbus slave device */
+static struct resource slimbus_res[] = {
+	{
+		.start	= LPASS_SLIMBUS_PHYS,
+		.end	= LPASS_SLIMBUS_PHYS + 8191,
+		.flags	= IORESOURCE_MEM,
+		.name	= "slimbus_physical",
+	},
+	{
+		.start	= LPASS_SLIMBUS_BAM_PHYS,
+		.end	= LPASS_SLIMBUS_BAM_PHYS + 8191,
+		.flags	= IORESOURCE_MEM,
+		.name	= "slimbus_bam_physical",
+	},
+	{
+		.start	= LPASS_SLIMBUS_SLEW,
+		.end	= LPASS_SLIMBUS_SLEW + 4 - 1,
+		.flags	= IORESOURCE_MEM,
+		.name	= "slimbus_slew_reg",
+	},
+	{
+		.start	= SLIMBUS0_CORE_EE1_IRQ,
+		.end	= SLIMBUS0_CORE_EE1_IRQ,
+		.flags	= IORESOURCE_IRQ,
+		.name	= "slimbus_irq",
+	},
+	{
+		.start	= SLIMBUS0_BAM_EE1_IRQ,
+		.end	= SLIMBUS0_BAM_EE1_IRQ,
+		.flags	= IORESOURCE_IRQ,
+		.name	= "slimbus_bam_irq",
+	},
+};
+
+struct platform_device apq8064_slim_ctrl = {
+	.name	= "msm_slim_ctrl",
+	.id	= 1,
+	.num_resources	= ARRAY_SIZE(slimbus_res),
+	.resource	= slimbus_res,
+	.dev            = {
+		.coherent_dma_mask      = 0xffffffffULL,
+	},
+};
+
+struct platform_device apq8064_device_ssbi_pmic1 = {
+	.name           = "msm_ssbi",
+	.id             = 0,
+	.resource       = resources_ssbi_pmic1,
+	.num_resources  = ARRAY_SIZE(resources_ssbi_pmic1),
+};
+
+static struct resource resources_ssbi_pmic2[] = {
+	{
+		.start  = MSM_PMIC2_SSBI_CMD_PHYS,
+		.end    = MSM_PMIC2_SSBI_CMD_PHYS + MSM_PMIC_SSBI_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device apq8064_device_ssbi_pmic2 = {
+	.name           = "msm_ssbi",
+	.id             = 1,
+	.resource       = resources_ssbi_pmic2,
+	.num_resources  = ARRAY_SIZE(resources_ssbi_pmic2),
+};
+
+static struct resource resources_otg[] = {
+	{
+		.start	= MSM_HSUSB1_PHYS,
+		.end	= MSM_HSUSB1_PHYS + MSM_HSUSB1_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= USB1_HS_IRQ,
+		.end	= USB1_HS_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device apq8064_device_otg = {
+	.name		= "msm_otg",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_otg),
+	.resource	= resources_otg,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+static struct resource resources_hsusb[] = {
+	{
+		.start	= MSM_HSUSB1_PHYS,
+		.end	= MSM_HSUSB1_PHYS + MSM_HSUSB1_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= USB1_HS_IRQ,
+		.end	= USB1_HS_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device apq8064_device_gadget_peripheral = {
+	.name		= "msm_hsusb",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_hsusb),
+	.resource	= resources_hsusb,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+static struct resource resources_hsusb_host[] = {
+	{
+		.start  = MSM_HSUSB1_PHYS,
+		.end    = MSM_HSUSB1_PHYS + MSM_HSUSB1_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = USB1_HS_IRQ,
+		.end    = USB1_HS_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct resource resources_hsic_host[] = {
+	{
+		.start	= 0x12510000,
+		.end	= 0x12510000 + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= USB2_HSIC_IRQ,
+		.end	= USB2_HSIC_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM_GPIO_TO_INT(49),
+		.end	= MSM_GPIO_TO_INT(49),
+		.name	= "peripheral_status_irq",
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= 47,
+		.end	= 47,
+		.name	= "wakeup",
+		.flags	= IORESOURCE_IO,
+	},
+};
+
+static u64 dma_mask = DMA_BIT_MASK(32);
+struct platform_device apq8064_device_hsusb_host = {
+	.name           = "msm_hsusb_host",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(resources_hsusb_host),
+	.resource       = resources_hsusb_host,
+	.dev            = {
+		.dma_mask               = &dma_mask,
+		.coherent_dma_mask      = 0xffffffff,
+	},
+};
+
+struct platform_device apq8064_device_hsic_host = {
+	.name		= "msm_hsic_host",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_hsic_host),
+	.resource	= resources_hsic_host,
+	.dev		= {
+		.dma_mask		= &dma_mask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+};
+
+static struct resource resources_ehci_host3[] = {
+{
+		.start  = MSM_HSUSB3_PHYS,
+		.end    = MSM_HSUSB3_PHYS + MSM_HSUSB3_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = USB3_HS_IRQ,
+		.end    = USB3_HS_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device apq8064_device_ehci_host3 = {
+	.name           = "msm_ehci_host",
+	.id             = 0,
+	.num_resources  = ARRAY_SIZE(resources_ehci_host3),
+	.resource       = resources_ehci_host3,
+	.dev            = {
+		.dma_mask               = &dma_mask,
+		.coherent_dma_mask      = 0xffffffff,
+	},
+};
+
+static struct resource resources_ehci_host4[] = {
+{
+		.start  = MSM_HSUSB4_PHYS,
+		.end    = MSM_HSUSB4_PHYS + MSM_HSUSB4_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = USB4_HS_IRQ,
+		.end    = USB4_HS_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device apq8064_device_ehci_host4 = {
+	.name           = "msm_ehci_host",
+	.id             = 1,
+	.num_resources  = ARRAY_SIZE(resources_ehci_host4),
+	.resource       = resources_ehci_host4,
+	.dev            = {
+		.dma_mask               = &dma_mask,
+		.coherent_dma_mask      = 0xffffffff,
+	},
+};
+
+/* MSM Video core device */
+#ifdef CONFIG_MSM_BUS_SCALING
+static struct msm_bus_vectors vidc_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_VIDEO_DEC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+static struct msm_bus_vectors vidc_venc_vga_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 54525952,
+		.ib  = 436207616,
+	},
+	{
+		.src = MSM_BUS_MASTER_VIDEO_DEC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 72351744,
+		.ib  = 289406976,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 500000,
+		.ib  = 1000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 500000,
+		.ib  = 1000000,
+	},
+};
+static struct msm_bus_vectors vidc_vdec_vga_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 40894464,
+		.ib  = 327155712,
+	},
+	{
+		.src = MSM_BUS_MASTER_VIDEO_DEC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 48234496,
+		.ib  = 192937984,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 500000,
+		.ib  = 2000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 500000,
+		.ib  = 2000000,
+	},
+};
+static struct msm_bus_vectors vidc_venc_720p_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 163577856,
+		.ib  = 1308622848,
+	},
+	{
+		.src = MSM_BUS_MASTER_VIDEO_DEC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 219152384,
+		.ib  = 876609536,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 1750000,
+		.ib  = 3500000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 1750000,
+		.ib  = 3500000,
+	},
+};
+static struct msm_bus_vectors vidc_vdec_720p_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 121634816,
+		.ib  = 973078528,
+	},
+	{
+		.src = MSM_BUS_MASTER_VIDEO_DEC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 155189248,
+		.ib  = 620756992,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 1750000,
+		.ib  = 7000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 1750000,
+		.ib  = 7000000,
+	},
+};
+static struct msm_bus_vectors vidc_venc_1080p_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 372244480,
+		.ib  = 2560000000U,
+	},
+	{
+		.src = MSM_BUS_MASTER_VIDEO_DEC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 501219328,
+		.ib  = 2560000000U,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 2500000,
+		.ib  = 5000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 2500000,
+		.ib  = 5000000,
+	},
+};
+static struct msm_bus_vectors vidc_vdec_1080p_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 222298112,
+		.ib  = 2560000000U,
+	},
+	{
+		.src = MSM_BUS_MASTER_VIDEO_DEC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 330301440,
+		.ib  = 2560000000U,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 2500000,
+		.ib  = 700000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 2500000,
+		.ib  = 10000000,
+	},
+};
+
+static struct msm_bus_paths vidc_bus_client_config[] = {
+	{
+		ARRAY_SIZE(vidc_init_vectors),
+		vidc_init_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_venc_vga_vectors),
+		vidc_venc_vga_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_vdec_vga_vectors),
+		vidc_vdec_vga_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_venc_720p_vectors),
+		vidc_venc_720p_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_vdec_720p_vectors),
+		vidc_vdec_720p_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_venc_1080p_vectors),
+		vidc_venc_1080p_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_vdec_1080p_vectors),
+		vidc_vdec_1080p_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata vidc_bus_client_data = {
+	vidc_bus_client_config,
+	ARRAY_SIZE(vidc_bus_client_config),
+	.name = "vidc",
+};
+#endif
+
+
+#define APQ8064_VIDC_BASE_PHYS 0x04400000
+#define APQ8064_VIDC_BASE_SIZE 0x00100000
+
+static struct resource apq8064_device_vidc_resources[] = {
+	{
+		.start	= APQ8064_VIDC_BASE_PHYS,
+		.end	= APQ8064_VIDC_BASE_PHYS + APQ8064_VIDC_BASE_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= VCODEC_IRQ,
+		.end	= VCODEC_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct msm_vidc_platform_data apq8064_vidc_platform_data = {
+#ifdef CONFIG_MSM_BUS_SCALING
+	.vidc_bus_client_pdata = &vidc_bus_client_data,
+#endif
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	.memtype = ION_CP_MM_HEAP_ID,
+	.enable_ion = 1,
+	.cp_enabled = 1,
+#else
+	.memtype = MEMTYPE_EBI1,
+	.enable_ion = 0,
+#endif
+	.disable_dmx = 0,
+	.disable_fullhd = 0,
+	.cont_mode_dpb_count = 18,
+};
+
+struct platform_device apq8064_msm_device_vidc = {
+	.name = "msm_vidc",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(apq8064_device_vidc_resources),
+	.resource = apq8064_device_vidc_resources,
+	.dev = {
+		.platform_data	= &apq8064_vidc_platform_data,
+	},
+};
+#define MSM_SDC1_BASE         0x12400000
+#define MSM_SDC1_DML_BASE     (MSM_SDC1_BASE + 0x800)
+#define MSM_SDC1_BAM_BASE     (MSM_SDC1_BASE + 0x2000)
+#define MSM_SDC2_BASE         0x12140000
+#define MSM_SDC2_DML_BASE     (MSM_SDC2_BASE + 0x800)
+#define MSM_SDC2_BAM_BASE     (MSM_SDC2_BASE + 0x2000)
+#define MSM_SDC3_BASE         0x12180000
+#define MSM_SDC3_DML_BASE     (MSM_SDC3_BASE + 0x800)
+#define MSM_SDC3_BAM_BASE     (MSM_SDC3_BASE + 0x2000)
+#define MSM_SDC4_BASE         0x121C0000
+#define MSM_SDC4_DML_BASE     (MSM_SDC4_BASE + 0x800)
+#define MSM_SDC4_BAM_BASE     (MSM_SDC4_BASE + 0x2000)
+
+static struct resource resources_sdc1[] = {
+	{
+		.name	= "core_mem",
+		.flags	= IORESOURCE_MEM,
+		.start	= MSM_SDC1_BASE,
+		.end	= MSM_SDC1_DML_BASE - 1,
+	},
+	{
+		.name	= "core_irq",
+		.flags	= IORESOURCE_IRQ,
+		.start	= SDC1_IRQ_0,
+		.end	= SDC1_IRQ_0
+	},
+#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
+	{
+		.name   = "sdcc_dml_addr",
+		.start	= MSM_SDC1_DML_BASE,
+		.end	= MSM_SDC1_BAM_BASE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_addr",
+		.start	= MSM_SDC1_BAM_BASE,
+		.end	= MSM_SDC1_BAM_BASE + (2 * SZ_4K) - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_irq",
+		.start	= SDC1_BAM_IRQ,
+		.end	= SDC1_BAM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+#endif
+};
+
+static struct resource resources_sdc2[] = {
+	{
+		.name	= "core_mem",
+		.flags	= IORESOURCE_MEM,
+		.start	= MSM_SDC2_BASE,
+		.end	= MSM_SDC2_DML_BASE - 1,
+	},
+	{
+		.name	= "core_irq",
+		.flags	= IORESOURCE_IRQ,
+		.start	= SDC2_IRQ_0,
+		.end	= SDC2_IRQ_0
+	},
+#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
+	{
+		.name   = "sdcc_dml_addr",
+		.start	= MSM_SDC2_DML_BASE,
+		.end	= MSM_SDC2_BAM_BASE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_addr",
+		.start	= MSM_SDC2_BAM_BASE,
+		.end	= MSM_SDC2_BAM_BASE + (2 * SZ_4K) - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_irq",
+		.start	= SDC2_BAM_IRQ,
+		.end	= SDC2_BAM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+#endif
+};
+
+static struct resource resources_sdc3[] = {
+	{
+		.name	= "core_mem",
+		.flags	= IORESOURCE_MEM,
+		.start	= MSM_SDC3_BASE,
+		.end	= MSM_SDC3_DML_BASE - 1,
+	},
+	{
+		.name	= "core_irq",
+		.flags	= IORESOURCE_IRQ,
+		.start	= SDC3_IRQ_0,
+		.end	= SDC3_IRQ_0
+	},
+#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
+	{
+		.name   = "sdcc_dml_addr",
+		.start	= MSM_SDC3_DML_BASE,
+		.end	= MSM_SDC3_BAM_BASE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_addr",
+		.start	= MSM_SDC3_BAM_BASE,
+		.end	= MSM_SDC3_BAM_BASE + (2 * SZ_4K) - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_irq",
+		.start	= SDC3_BAM_IRQ,
+		.end	= SDC3_BAM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+#endif
+};
+
+static struct resource resources_sdc4[] = {
+	{
+		.name	= "core_mem",
+		.flags	= IORESOURCE_MEM,
+		.start	= MSM_SDC4_BASE,
+		.end	= MSM_SDC4_DML_BASE - 1,
+	},
+	{
+		.name	= "core_irq",
+		.flags	= IORESOURCE_IRQ,
+		.start	= SDC4_IRQ_0,
+		.end	= SDC4_IRQ_0
+	},
+#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
+	{
+		.name   = "sdcc_dml_addr",
+		.start	= MSM_SDC4_DML_BASE,
+		.end	= MSM_SDC4_BAM_BASE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_addr",
+		.start	= MSM_SDC4_BAM_BASE,
+		.end	= MSM_SDC4_BAM_BASE + (2 * SZ_4K) - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_irq",
+		.start	= SDC4_BAM_IRQ,
+		.end	= SDC4_BAM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+#endif
+};
+
+struct platform_device apq8064_device_sdc1 = {
+	.name		= "msm_sdcc",
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(resources_sdc1),
+	.resource	= resources_sdc1,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device apq8064_device_sdc2 = {
+	.name		= "msm_sdcc",
+	.id		= 2,
+	.num_resources	= ARRAY_SIZE(resources_sdc2),
+	.resource	= resources_sdc2,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device apq8064_device_sdc3 = {
+	.name		= "msm_sdcc",
+	.id		= 3,
+	.num_resources	= ARRAY_SIZE(resources_sdc3),
+	.resource	= resources_sdc3,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device apq8064_device_sdc4 = {
+	.name		= "msm_sdcc",
+	.id		= 4,
+	.num_resources	= ARRAY_SIZE(resources_sdc4),
+	.resource	= resources_sdc4,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+static struct platform_device *apq8064_sdcc_devices[] __initdata = {
+	&apq8064_device_sdc1,
+	&apq8064_device_sdc2,
+	&apq8064_device_sdc3,
+	&apq8064_device_sdc4,
+};
+
+int __init apq8064_add_sdcc(unsigned int controller,
+				struct mmc_platform_data *plat)
+{
+	struct platform_device	*pdev;
+
+	if (!plat)
+		return 0;
+	if (controller < 1 || controller > 4)
+		return -EINVAL;
+
+	pdev = apq8064_sdcc_devices[controller-1];
+	pdev->dev.platform_data = plat;
+	return platform_device_register(pdev);
+}
+
+static struct resource resources_sps[] = {
+	{
+		.name	= "pipe_mem",
+		.start	= 0x12800000,
+		.end	= 0x12800000 + 0x4000 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "bamdma_dma",
+		.start	= 0x12240000,
+		.end	= 0x12240000 + 0x1000 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "bamdma_bam",
+		.start	= 0x12244000,
+		.end	= 0x12244000 + 0x4000 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "bamdma_irq",
+		.start	= SPS_BAM_DMA_IRQ,
+		.end	= SPS_BAM_DMA_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_bus_8064_sys_fabric = {
+	.name  = "msm_bus_fabric",
+	.id    =  MSM_BUS_FAB_SYSTEM,
+};
+struct platform_device msm_bus_8064_apps_fabric = {
+	.name  = "msm_bus_fabric",
+	.id    = MSM_BUS_FAB_APPSS,
+};
+struct platform_device msm_bus_8064_mm_fabric = {
+	.name  = "msm_bus_fabric",
+	.id    = MSM_BUS_FAB_MMSS,
+};
+struct platform_device msm_bus_8064_sys_fpb = {
+	.name  = "msm_bus_fabric",
+	.id    = MSM_BUS_FAB_SYSTEM_FPB,
+};
+struct platform_device msm_bus_8064_cpss_fpb = {
+	.name  = "msm_bus_fabric",
+	.id    = MSM_BUS_FAB_CPSS_FPB,
+};
+
+static struct msm_sps_platform_data msm_sps_pdata = {
+	.bamdma_restricted_pipes = 0x06,
+};
+
+struct platform_device msm_device_sps_apq8064 = {
+	.name		= "msm_sps",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_sps),
+	.resource	= resources_sps,
+	.dev.platform_data = &msm_sps_pdata,
+};
+
+static struct resource smd_resource[] = {
+	{
+		.name   = "a9_m2a_0",
+		.start  = INT_A9_M2A_0,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "a9_m2a_5",
+		.start  = INT_A9_M2A_5,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "adsp_a11",
+		.start  = INT_ADSP_A11,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "adsp_a11_smsm",
+		.start  = INT_ADSP_A11_SMSM,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "dsps_a11",
+		.start  = INT_DSPS_A11,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "dsps_a11_smsm",
+		.start  = INT_DSPS_A11_SMSM,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "wcnss_a11",
+		.start  = INT_WCNSS_A11,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "wcnss_a11_smsm",
+		.start  = INT_WCNSS_A11_SMSM,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct smd_subsystem_config smd_config_list[] = {
+	{
+		.irq_config_id = SMD_MODEM,
+		.subsys_name = "gss",
+		.edge = SMD_APPS_MODEM,
+
+		.smd_int.irq_name = "a9_m2a_0",
+		.smd_int.flags = IRQF_TRIGGER_RISING,
+		.smd_int.irq_id = -1,
+		.smd_int.device_name = "smd_dev",
+		.smd_int.dev_id = 0,
+		.smd_int.out_bit_pos =  1 << 3,
+		.smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smd_int.out_offset = 0x8,
+
+		.smsm_int.irq_name = "a9_m2a_5",
+		.smsm_int.flags = IRQF_TRIGGER_RISING,
+		.smsm_int.irq_id = -1,
+		.smsm_int.device_name = "smd_smsm",
+		.smsm_int.dev_id = 0,
+		.smsm_int.out_bit_pos =  1 << 4,
+		.smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smsm_int.out_offset = 0x8,
+	},
+	{
+		.irq_config_id = SMD_Q6,
+		.subsys_name = "q6",
+		.edge = SMD_APPS_QDSP,
+
+		.smd_int.irq_name = "adsp_a11",
+		.smd_int.flags = IRQF_TRIGGER_RISING,
+		.smd_int.irq_id = -1,
+		.smd_int.device_name = "smd_dev",
+		.smd_int.dev_id = 0,
+		.smd_int.out_bit_pos =  1 << 15,
+		.smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smd_int.out_offset = 0x8,
+
+		.smsm_int.irq_name = "adsp_a11_smsm",
+		.smsm_int.flags = IRQF_TRIGGER_RISING,
+		.smsm_int.irq_id = -1,
+		.smsm_int.device_name = "smd_smsm",
+		.smsm_int.dev_id = 0,
+		.smsm_int.out_bit_pos =  1 << 14,
+		.smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smsm_int.out_offset = 0x8,
+	},
+	{
+		.irq_config_id = SMD_DSPS,
+		.subsys_name = "dsps",
+		.edge = SMD_APPS_DSPS,
+
+		.smd_int.irq_name = "dsps_a11",
+		.smd_int.flags = IRQF_TRIGGER_RISING,
+		.smd_int.irq_id = -1,
+		.smd_int.device_name = "smd_dev",
+		.smd_int.dev_id = 0,
+		.smd_int.out_bit_pos =  1,
+		.smd_int.out_base = (void __iomem *)MSM_SIC_NON_SECURE_BASE,
+		.smd_int.out_offset = 0x4080,
+
+		.smsm_int.irq_name = "dsps_a11_smsm",
+		.smsm_int.flags = IRQF_TRIGGER_RISING,
+		.smsm_int.irq_id = -1,
+		.smsm_int.device_name = "smd_smsm",
+		.smsm_int.dev_id = 0,
+		.smsm_int.out_bit_pos =  1,
+		.smsm_int.out_base = (void __iomem *)MSM_SIC_NON_SECURE_BASE,
+		.smsm_int.out_offset = 0x4094,
+	},
+	{
+		.irq_config_id = SMD_WCNSS,
+		.subsys_name = "wcnss",
+		.edge = SMD_APPS_WCNSS,
+
+		.smd_int.irq_name = "wcnss_a11",
+		.smd_int.flags = IRQF_TRIGGER_RISING,
+		.smd_int.irq_id = -1,
+		.smd_int.device_name = "smd_dev",
+		.smd_int.dev_id = 0,
+		.smd_int.out_bit_pos =  1 << 25,
+		.smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smd_int.out_offset = 0x8,
+
+		.smsm_int.irq_name = "wcnss_a11_smsm",
+		.smsm_int.flags = IRQF_TRIGGER_RISING,
+		.smsm_int.irq_id = -1,
+		.smsm_int.device_name = "smd_smsm",
+		.smsm_int.dev_id = 0,
+		.smsm_int.out_bit_pos =  1 << 23,
+		.smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smsm_int.out_offset = 0x8,
+	},
+};
+
+static struct smd_subsystem_restart_config smd_ssr_config = {
+	.disable_smsm_reset_handshake = 1,
+};
+
+static struct smd_platform smd_platform_data = {
+	.num_ss_configs = ARRAY_SIZE(smd_config_list),
+	.smd_ss_configs = smd_config_list,
+	.smd_ssr_config = &smd_ssr_config,
+};
+
+struct platform_device msm_device_smd_apq8064 = {
+	.name		= "msm_smd",
+	.id		= -1,
+	.resource = smd_resource,
+	.num_resources = ARRAY_SIZE(smd_resource),
+	.dev = {
+		.platform_data = &smd_platform_data,
+	},
+};
+
+static struct resource resources_msm_pcie[] = {
+	{
+		.name   = "parf",
+		.start  = PCIE20_PARF_PHYS,
+		.end    = PCIE20_PARF_PHYS + PCIE20_PARF_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "elbi",
+		.start  = PCIE20_ELBI_PHYS,
+		.end    = PCIE20_ELBI_PHYS + PCIE20_ELBI_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "pcie20",
+		.start  = PCIE20_PHYS,
+		.end    = PCIE20_PHYS + PCIE20_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "axi_bar",
+		.start  = PCIE_AXI_BAR_PHYS,
+		.end    = PCIE_AXI_BAR_PHYS + PCIE_AXI_BAR_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "axi_conf",
+		.start  = PCIE_AXI_CONF_PHYS,
+		.end    = PCIE_AXI_CONF_PHYS + PCIE_AXI_CONF_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_device_pcie = {
+	.name           = "msm_pcie",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(resources_msm_pcie),
+	.resource       = resources_msm_pcie,
+};
+
+#ifdef CONFIG_HW_RANDOM_MSM
+/* PRNG device */
+#define MSM_PRNG_PHYS           0x1A500000
+static struct resource rng_resources = {
+	.flags = IORESOURCE_MEM,
+	.start = MSM_PRNG_PHYS,
+	.end   = MSM_PRNG_PHYS + SZ_512 - 1,
+};
+
+struct platform_device apq8064_device_rng = {
+	.name          = "msm_rng",
+	.id            = 0,
+	.num_resources = 1,
+	.resource      = &rng_resources,
+};
+#endif
+
+static struct resource msm_gss_resources[] = {
+	{
+		.start  = 0x10000000,
+		.end    = 0x10000000 + SZ_256 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = 0x10008000,
+		.end    = 0x10008000 + SZ_256 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_gss = {
+	.name = "pil_gss",
+	.id = -1,
+	.num_resources  = ARRAY_SIZE(msm_gss_resources),
+	.resource       = msm_gss_resources,
+};
+
+static struct fs_driver_data gfx3d_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk", .reset_rate = 27000000 },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_GRAPHICS_3D,
+	.bus_port1 = MSM_BUS_MASTER_GRAPHICS_3D_PORT1,
+};
+
+static struct fs_driver_data ijpeg_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_JPEG_ENC,
+};
+
+static struct fs_driver_data rot_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_ROTATOR,
+};
+
+static struct fs_driver_data ved_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_VIDEO_ENC,
+	.bus_port1 = MSM_BUS_MASTER_VIDEO_DEC,
+};
+
+static struct fs_driver_data vfe_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_VFE,
+};
+
+static struct fs_driver_data vpe_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_VPE,
+};
+
+static struct fs_driver_data vcap_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 },
+	},
+	.bus_port0 = MSM_BUS_MASTER_VIDEO_CAP,
+};
+
+struct platform_device *apq8064_footswitch[] __initdata = {
+	FS_8X60(FS_ROT,    "vdd",	"msm_rotator.0", &rot_fs_data),
+	FS_8X60(FS_IJPEG,  "vdd",	"msm_gemini.0",	&ijpeg_fs_data),
+	FS_8X60(FS_VFE,    "fs_vfe",	NULL,	&vfe_fs_data),
+	FS_8X60(FS_VPE,    "fs_vpe",	NULL,	&vpe_fs_data),
+	FS_8X60(FS_GFX3D,  "vdd",	"kgsl-3d0.0",	&gfx3d_fs_data),
+	FS_8X60(FS_VED,    "vdd",	"msm_vidc.0",	&ved_fs_data),
+	FS_8X60(FS_VCAP,   "vdd",	"msm_vcap.0",	&vcap_fs_data),
+};
+unsigned apq8064_num_footswitch __initdata = ARRAY_SIZE(apq8064_footswitch);
+
+struct msm_rpm_platform_data apq8064_rpm_data __initdata = {
+	.reg_base_addrs = {
+		[MSM_RPM_PAGE_STATUS] = MSM_RPM_BASE,
+		[MSM_RPM_PAGE_CTRL] = MSM_RPM_BASE + 0x400,
+		[MSM_RPM_PAGE_REQ] = MSM_RPM_BASE + 0x600,
+		[MSM_RPM_PAGE_ACK] = MSM_RPM_BASE + 0xa00,
+	},
+	.irq_ack = RPM_APCC_CPU0_GP_HIGH_IRQ,
+	.irq_err = RPM_APCC_CPU0_GP_LOW_IRQ,
+	.irq_wakeup = RPM_APCC_CPU0_WAKE_UP_IRQ,
+	.ipc_rpm_reg = MSM_APCS_GCC_BASE + 0x008,
+	.ipc_rpm_val = 4,
+	.target_id =  {
+		MSM_RPM_MAP(8064, NOTIFICATION_CONFIGURED_0, NOTIFICATION, 4),
+		MSM_RPM_MAP(8064, NOTIFICATION_REGISTERED_0, NOTIFICATION, 4),
+		MSM_RPM_MAP(8064, INVALIDATE_0, INVALIDATE, 8),
+		MSM_RPM_MAP(8064, TRIGGER_TIMED_TO, TRIGGER_TIMED, 1),
+		MSM_RPM_MAP(8064, TRIGGER_TIMED_SCLK_COUNT, TRIGGER_TIMED, 1),
+		MSM_RPM_MAP(8064, RPM_CTL, RPM_CTL, 1),
+		MSM_RPM_MAP(8064, CXO_CLK, CXO_CLK, 1),
+		MSM_RPM_MAP(8064, PXO_CLK, PXO_CLK, 1),
+		MSM_RPM_MAP(8064, APPS_FABRIC_CLK, APPS_FABRIC_CLK, 1),
+		MSM_RPM_MAP(8064, SYSTEM_FABRIC_CLK, SYSTEM_FABRIC_CLK, 1),
+		MSM_RPM_MAP(8064, MM_FABRIC_CLK, MM_FABRIC_CLK, 1),
+		MSM_RPM_MAP(8064, DAYTONA_FABRIC_CLK, DAYTONA_FABRIC_CLK, 1),
+		MSM_RPM_MAP(8064, SFPB_CLK, SFPB_CLK, 1),
+		MSM_RPM_MAP(8064, CFPB_CLK, CFPB_CLK, 1),
+		MSM_RPM_MAP(8064, MMFPB_CLK, MMFPB_CLK, 1),
+		MSM_RPM_MAP(8064, EBI1_CLK, EBI1_CLK, 1),
+		MSM_RPM_MAP(8064, APPS_FABRIC_CFG_HALT_0,
+				APPS_FABRIC_CFG_HALT, 2),
+		MSM_RPM_MAP(8064, APPS_FABRIC_CFG_CLKMOD_0,
+				APPS_FABRIC_CFG_CLKMOD, 3),
+		MSM_RPM_MAP(8064, APPS_FABRIC_CFG_IOCTL,
+				APPS_FABRIC_CFG_IOCTL, 1),
+		MSM_RPM_MAP(8064, APPS_FABRIC_ARB_0, APPS_FABRIC_ARB, 12),
+		MSM_RPM_MAP(8064, SYS_FABRIC_CFG_HALT_0,
+				SYS_FABRIC_CFG_HALT, 2),
+		MSM_RPM_MAP(8064, SYS_FABRIC_CFG_CLKMOD_0,
+				SYS_FABRIC_CFG_CLKMOD, 3),
+		MSM_RPM_MAP(8064, SYS_FABRIC_CFG_IOCTL,
+				SYS_FABRIC_CFG_IOCTL, 1),
+		MSM_RPM_MAP(8064, SYSTEM_FABRIC_ARB_0, SYSTEM_FABRIC_ARB, 30),
+		MSM_RPM_MAP(8064, MMSS_FABRIC_CFG_HALT_0,
+				MMSS_FABRIC_CFG_HALT, 2),
+		MSM_RPM_MAP(8064, MMSS_FABRIC_CFG_CLKMOD_0,
+				MMSS_FABRIC_CFG_CLKMOD, 3),
+		MSM_RPM_MAP(8064, MMSS_FABRIC_CFG_IOCTL,
+				MMSS_FABRIC_CFG_IOCTL, 1),
+		MSM_RPM_MAP(8064, MM_FABRIC_ARB_0, MM_FABRIC_ARB, 21),
+		MSM_RPM_MAP(8064, PM8921_S1_0, PM8921_S1, 2),
+		MSM_RPM_MAP(8064, PM8921_S2_0, PM8921_S2, 2),
+		MSM_RPM_MAP(8064, PM8921_S3_0, PM8921_S3, 2),
+		MSM_RPM_MAP(8064, PM8921_S4_0, PM8921_S4, 2),
+		MSM_RPM_MAP(8064, PM8921_S5_0, PM8921_S5, 2),
+		MSM_RPM_MAP(8064, PM8921_S6_0, PM8921_S6, 2),
+		MSM_RPM_MAP(8064, PM8921_S7_0, PM8921_S7, 2),
+		MSM_RPM_MAP(8064, PM8921_S8_0, PM8921_S8, 2),
+		MSM_RPM_MAP(8064, PM8921_L1_0, PM8921_L1, 2),
+		MSM_RPM_MAP(8064, PM8921_L2_0, PM8921_L2, 2),
+		MSM_RPM_MAP(8064, PM8921_L3_0, PM8921_L3, 2),
+		MSM_RPM_MAP(8064, PM8921_L4_0, PM8921_L4, 2),
+		MSM_RPM_MAP(8064, PM8921_L5_0, PM8921_L5, 2),
+		MSM_RPM_MAP(8064, PM8921_L6_0, PM8921_L6, 2),
+		MSM_RPM_MAP(8064, PM8921_L7_0, PM8921_L7, 2),
+		MSM_RPM_MAP(8064, PM8921_L8_0, PM8921_L8, 2),
+		MSM_RPM_MAP(8064, PM8921_L9_0, PM8921_L9, 2),
+		MSM_RPM_MAP(8064, PM8921_L10_0, PM8921_L10, 2),
+		MSM_RPM_MAP(8064, PM8921_L11_0, PM8921_L11, 2),
+		MSM_RPM_MAP(8064, PM8921_L12_0, PM8921_L12, 2),
+		MSM_RPM_MAP(8064, PM8921_L13_0, PM8921_L13, 2),
+		MSM_RPM_MAP(8064, PM8921_L14_0, PM8921_L14, 2),
+		MSM_RPM_MAP(8064, PM8921_L15_0, PM8921_L15, 2),
+		MSM_RPM_MAP(8064, PM8921_L16_0, PM8921_L16, 2),
+		MSM_RPM_MAP(8064, PM8921_L17_0, PM8921_L17, 2),
+		MSM_RPM_MAP(8064, PM8921_L18_0, PM8921_L18, 2),
+		MSM_RPM_MAP(8064, PM8921_L19_0, PM8921_L19, 2),
+		MSM_RPM_MAP(8064, PM8921_L20_0, PM8921_L20, 2),
+		MSM_RPM_MAP(8064, PM8921_L21_0, PM8921_L21, 2),
+		MSM_RPM_MAP(8064, PM8921_L22_0, PM8921_L22, 2),
+		MSM_RPM_MAP(8064, PM8921_L23_0, PM8921_L23, 2),
+		MSM_RPM_MAP(8064, PM8921_L24_0, PM8921_L24, 2),
+		MSM_RPM_MAP(8064, PM8921_L25_0, PM8921_L25, 2),
+		MSM_RPM_MAP(8064, PM8921_L26_0, PM8921_L26, 2),
+		MSM_RPM_MAP(8064, PM8921_L27_0, PM8921_L27, 2),
+		MSM_RPM_MAP(8064, PM8921_L28_0, PM8921_L28, 2),
+		MSM_RPM_MAP(8064, PM8921_L29_0, PM8921_L29, 2),
+		MSM_RPM_MAP(8064, PM8921_CLK1_0, PM8921_CLK1, 2),
+		MSM_RPM_MAP(8064, PM8921_CLK2_0, PM8921_CLK2, 2),
+		MSM_RPM_MAP(8064, PM8921_LVS1, PM8921_LVS1, 1),
+		MSM_RPM_MAP(8064, PM8921_LVS2, PM8921_LVS2, 1),
+		MSM_RPM_MAP(8064, PM8921_LVS3, PM8921_LVS3, 1),
+		MSM_RPM_MAP(8064, PM8921_LVS4, PM8921_LVS4, 1),
+		MSM_RPM_MAP(8064, PM8921_LVS5, PM8921_LVS5, 1),
+		MSM_RPM_MAP(8064, PM8921_LVS6, PM8921_LVS6, 1),
+		MSM_RPM_MAP(8064, PM8921_LVS7, PM8921_LVS7, 1),
+		MSM_RPM_MAP(8064, PM8821_S1_0, PM8821_S1, 2),
+		MSM_RPM_MAP(8064, PM8821_S2_0, PM8821_S2, 2),
+		MSM_RPM_MAP(8064, PM8821_L1_0, PM8821_L1, 2),
+		MSM_RPM_MAP(8064, NCP_0, NCP, 2),
+		MSM_RPM_MAP(8064, CXO_BUFFERS, CXO_BUFFERS, 1),
+		MSM_RPM_MAP(8064, USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
+		MSM_RPM_MAP(8064, HDMI_SWITCH, HDMI_SWITCH, 1),
+		MSM_RPM_MAP(8064, DDR_DMM_0, DDR_DMM, 2),
+		MSM_RPM_MAP(8064, QDSS_CLK, QDSS_CLK, 1),
+	},
+	.target_status = {
+		MSM_RPM_STATUS_ID_MAP(8064, VERSION_MAJOR),
+		MSM_RPM_STATUS_ID_MAP(8064, VERSION_MINOR),
+		MSM_RPM_STATUS_ID_MAP(8064, VERSION_BUILD),
+		MSM_RPM_STATUS_ID_MAP(8064, SUPPORTED_RESOURCES_0),
+		MSM_RPM_STATUS_ID_MAP(8064, SUPPORTED_RESOURCES_1),
+		MSM_RPM_STATUS_ID_MAP(8064, SUPPORTED_RESOURCES_2),
+		MSM_RPM_STATUS_ID_MAP(8064, RESERVED_SUPPORTED_RESOURCES_0),
+		MSM_RPM_STATUS_ID_MAP(8064, SEQUENCE),
+		MSM_RPM_STATUS_ID_MAP(8064, RPM_CTL),
+		MSM_RPM_STATUS_ID_MAP(8064, CXO_CLK),
+		MSM_RPM_STATUS_ID_MAP(8064, PXO_CLK),
+		MSM_RPM_STATUS_ID_MAP(8064, APPS_FABRIC_CLK),
+		MSM_RPM_STATUS_ID_MAP(8064, SYSTEM_FABRIC_CLK),
+		MSM_RPM_STATUS_ID_MAP(8064, MM_FABRIC_CLK),
+		MSM_RPM_STATUS_ID_MAP(8064, DAYTONA_FABRIC_CLK),
+		MSM_RPM_STATUS_ID_MAP(8064, SFPB_CLK),
+		MSM_RPM_STATUS_ID_MAP(8064, CFPB_CLK),
+		MSM_RPM_STATUS_ID_MAP(8064, MMFPB_CLK),
+		MSM_RPM_STATUS_ID_MAP(8064, EBI1_CLK),
+		MSM_RPM_STATUS_ID_MAP(8064, APPS_FABRIC_CFG_HALT),
+		MSM_RPM_STATUS_ID_MAP(8064, APPS_FABRIC_CFG_CLKMOD),
+		MSM_RPM_STATUS_ID_MAP(8064, APPS_FABRIC_CFG_IOCTL),
+		MSM_RPM_STATUS_ID_MAP(8064, APPS_FABRIC_ARB),
+		MSM_RPM_STATUS_ID_MAP(8064, SYS_FABRIC_CFG_HALT),
+		MSM_RPM_STATUS_ID_MAP(8064, SYS_FABRIC_CFG_CLKMOD),
+		MSM_RPM_STATUS_ID_MAP(8064, SYS_FABRIC_CFG_IOCTL),
+		MSM_RPM_STATUS_ID_MAP(8064, SYSTEM_FABRIC_ARB),
+		MSM_RPM_STATUS_ID_MAP(8064, MMSS_FABRIC_CFG_HALT),
+		MSM_RPM_STATUS_ID_MAP(8064, MMSS_FABRIC_CFG_CLKMOD),
+		MSM_RPM_STATUS_ID_MAP(8064, MMSS_FABRIC_CFG_IOCTL),
+		MSM_RPM_STATUS_ID_MAP(8064, MM_FABRIC_ARB),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_S1_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_S1_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_S2_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_S2_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_S3_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_S3_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_S4_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_S4_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_S5_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_S5_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_S6_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_S6_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_S7_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_S7_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_S8_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_S8_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L1_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L1_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L2_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L2_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L3_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L3_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L4_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L4_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L5_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L5_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L6_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L6_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L7_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L7_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L8_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L8_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L9_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L9_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L10_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L10_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L11_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L11_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L12_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L12_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L13_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L13_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L14_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L14_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L15_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L15_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L16_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L16_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L17_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L17_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L18_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L18_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L19_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L19_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L20_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L20_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L21_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L21_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L22_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L22_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L23_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L23_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L24_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L24_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L25_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L25_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L26_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L26_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L27_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L27_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L28_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L28_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L29_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_L29_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_CLK1_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_CLK1_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_CLK2_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_CLK2_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_LVS1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_LVS2),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_LVS3),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_LVS4),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_LVS5),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_LVS6),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8921_LVS7),
+		MSM_RPM_STATUS_ID_MAP(8064, NCP_0),
+		MSM_RPM_STATUS_ID_MAP(8064, NCP_1),
+		MSM_RPM_STATUS_ID_MAP(8064, CXO_BUFFERS),
+		MSM_RPM_STATUS_ID_MAP(8064, USB_OTG_SWITCH),
+		MSM_RPM_STATUS_ID_MAP(8064, HDMI_SWITCH),
+		MSM_RPM_STATUS_ID_MAP(8064, DDR_DMM_0),
+		MSM_RPM_STATUS_ID_MAP(8064, DDR_DMM_1),
+		MSM_RPM_STATUS_ID_MAP(8064, EBI1_CH0_RANGE),
+		MSM_RPM_STATUS_ID_MAP(8064, EBI1_CH1_RANGE),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8821_S1_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8821_S1_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8821_S2_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8821_S2_1),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8821_L1_0),
+		MSM_RPM_STATUS_ID_MAP(8064, PM8821_L1_1),
+	},
+	.target_ctrl_id = {
+		MSM_RPM_CTRL_MAP(8064, VERSION_MAJOR),
+		MSM_RPM_CTRL_MAP(8064, VERSION_MINOR),
+		MSM_RPM_CTRL_MAP(8064, VERSION_BUILD),
+		MSM_RPM_CTRL_MAP(8064, REQ_CTX_0),
+		MSM_RPM_CTRL_MAP(8064, REQ_SEL_0),
+		MSM_RPM_CTRL_MAP(8064, ACK_CTX_0),
+		MSM_RPM_CTRL_MAP(8064, ACK_SEL_0),
+	},
+	.sel_invalidate = MSM_RPM_8064_SEL_INVALIDATE,
+	.sel_notification = MSM_RPM_8064_SEL_NOTIFICATION,
+	.sel_last = MSM_RPM_8064_SEL_LAST,
+	.ver = {3, 0, 0},
+};
+
+struct platform_device apq8064_rpm_device = {
+	.name   = "msm_rpm",
+	.id     = -1,
+};
+
+static struct msm_rpmstats_platform_data msm_rpm_stat_pdata = {
+	.phys_addr_base = 0x0010D204,
+	.phys_size = SZ_8K,
+};
+
+struct platform_device apq8064_rpm_stat_device = {
+	.name = "msm_rpm_stat",
+	.id = -1,
+	.dev = {
+		.platform_data = &msm_rpm_stat_pdata,
+	},
+};
+
+static struct msm_rpm_log_platform_data msm_rpm_log_pdata = {
+	.phys_addr_base = 0x0010C000,
+	.reg_offsets = {
+		[MSM_RPM_LOG_PAGE_INDICES] = 0x00000080,
+		[MSM_RPM_LOG_PAGE_BUFFER]  = 0x000000A0,
+	},
+	.phys_size = SZ_8K,
+	.log_len = 4096,		  /* log's buffer length in bytes */
+	.log_len_mask = (4096 >> 2) - 1,  /* length mask in units of u32 */
+};
+
+struct platform_device apq8064_rpm_log_device = {
+	.name	= "msm_rpm_log",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &msm_rpm_log_pdata,
+	},
+};
+
+/* Sensors DSPS platform data */
+
+#define PPSS_REG_PHYS_BASE	0x12080000
+
+static struct dsps_clk_info dsps_clks[] = {};
+static struct dsps_regulator_info dsps_regs[] = {};
+
+/*
+ * Note: GPIOs field is	intialized in run-time at the function
+ * apq8064_init_dsps().
+ */
+
+struct msm_dsps_platform_data msm_dsps_pdata_8064 = {
+	.clks = dsps_clks,
+	.clks_num = ARRAY_SIZE(dsps_clks),
+	.gpios = NULL,
+	.gpios_num = 0,
+	.regs = dsps_regs,
+	.regs_num = ARRAY_SIZE(dsps_regs),
+	.dsps_pwr_ctl_en = 1,
+	.signature = DSPS_SIGNATURE,
+};
+
+static struct resource msm_dsps_resources[] = {
+	{
+		.start = PPSS_REG_PHYS_BASE,
+		.end   = PPSS_REG_PHYS_BASE + SZ_8K - 1,
+		.name  = "ppss_reg",
+		.flags = IORESOURCE_MEM,
+	},
+
+	{
+		.start = PPSS_WDOG_TIMER_IRQ,
+		.end   = PPSS_WDOG_TIMER_IRQ,
+		.name  = "ppss_wdog",
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_dsps_device_8064 = {
+	.name          = "msm_dsps",
+	.id            = 0,
+	.num_resources = ARRAY_SIZE(msm_dsps_resources),
+	.resource      = msm_dsps_resources,
+	.dev.platform_data = &msm_dsps_pdata_8064,
+};
+
+#ifdef CONFIG_MSM_MPM
+static uint16_t msm_mpm_irqs_m2a[MSM_MPM_NR_MPM_IRQS] __initdata = {
+	[1] = MSM_GPIO_TO_INT(26),
+	[2] = MSM_GPIO_TO_INT(88),
+	[4] = MSM_GPIO_TO_INT(73),
+	[5] = MSM_GPIO_TO_INT(74),
+	[6] = MSM_GPIO_TO_INT(75),
+	[7] = MSM_GPIO_TO_INT(76),
+	[8] = MSM_GPIO_TO_INT(77),
+	[9] = MSM_GPIO_TO_INT(36),
+	[10] = MSM_GPIO_TO_INT(84),
+	[11] = MSM_GPIO_TO_INT(7),
+	[12] = MSM_GPIO_TO_INT(11),
+	[13] = MSM_GPIO_TO_INT(52),
+	[14] = MSM_GPIO_TO_INT(15),
+	[15] = MSM_GPIO_TO_INT(83),
+	[16] = USB3_HS_IRQ,
+	[19] = MSM_GPIO_TO_INT(61),
+	[20] = MSM_GPIO_TO_INT(58),
+	[23] = MSM_GPIO_TO_INT(65),
+	[24] = MSM_GPIO_TO_INT(63),
+	[25] = USB1_HS_IRQ,
+	[27] = HDMI_IRQ,
+	[29] = MSM_GPIO_TO_INT(22),
+	[30] = MSM_GPIO_TO_INT(72),
+	[31] = USB4_HS_IRQ,
+	[33] = MSM_GPIO_TO_INT(44),
+	[34] = MSM_GPIO_TO_INT(39),
+	[35] = MSM_GPIO_TO_INT(19),
+	[36] = MSM_GPIO_TO_INT(23),
+	[37] = MSM_GPIO_TO_INT(41),
+	[38] = MSM_GPIO_TO_INT(30),
+	[41] = MSM_GPIO_TO_INT(42),
+	[42] = MSM_GPIO_TO_INT(56),
+	[43] = MSM_GPIO_TO_INT(55),
+	[44] = MSM_GPIO_TO_INT(50),
+	[45] = MSM_GPIO_TO_INT(49),
+	[46] = MSM_GPIO_TO_INT(47),
+	[47] = MSM_GPIO_TO_INT(45),
+	[48] = MSM_GPIO_TO_INT(38),
+	[49] = MSM_GPIO_TO_INT(34),
+	[50] = MSM_GPIO_TO_INT(32),
+	[51] = MSM_GPIO_TO_INT(29),
+	[52] = MSM_GPIO_TO_INT(18),
+	[53] = MSM_GPIO_TO_INT(10),
+	[54] = MSM_GPIO_TO_INT(81),
+	[55] = MSM_GPIO_TO_INT(6),
+};
+
+static uint16_t msm_mpm_bypassed_apps_irqs[] __initdata = {
+	TLMM_MSM_SUMMARY_IRQ,
+	RPM_APCC_CPU0_GP_HIGH_IRQ,
+	RPM_APCC_CPU0_GP_MEDIUM_IRQ,
+	RPM_APCC_CPU0_GP_LOW_IRQ,
+	RPM_APCC_CPU0_WAKE_UP_IRQ,
+	RPM_APCC_CPU1_GP_HIGH_IRQ,
+	RPM_APCC_CPU1_GP_MEDIUM_IRQ,
+	RPM_APCC_CPU1_GP_LOW_IRQ,
+	RPM_APCC_CPU1_WAKE_UP_IRQ,
+	MSS_TO_APPS_IRQ_0,
+	MSS_TO_APPS_IRQ_1,
+	MSS_TO_APPS_IRQ_2,
+	MSS_TO_APPS_IRQ_3,
+	MSS_TO_APPS_IRQ_4,
+	MSS_TO_APPS_IRQ_5,
+	MSS_TO_APPS_IRQ_6,
+	MSS_TO_APPS_IRQ_7,
+	MSS_TO_APPS_IRQ_8,
+	MSS_TO_APPS_IRQ_9,
+	LPASS_SCSS_GP_LOW_IRQ,
+	LPASS_SCSS_GP_MEDIUM_IRQ,
+	LPASS_SCSS_GP_HIGH_IRQ,
+	SPS_MTI_30,
+	SPS_MTI_31,
+	RIVA_APSS_SPARE_IRQ,
+	RIVA_APPS_WLAN_SMSM_IRQ,
+	RIVA_APPS_WLAN_RX_DATA_AVAIL_IRQ,
+	RIVA_APPS_WLAN_DATA_XFER_DONE_IRQ,
+};
+
+struct msm_mpm_device_data apq8064_mpm_dev_data __initdata = {
+	.irqs_m2a = msm_mpm_irqs_m2a,
+	.irqs_m2a_size = ARRAY_SIZE(msm_mpm_irqs_m2a),
+	.bypassed_apps_irqs = msm_mpm_bypassed_apps_irqs,
+	.bypassed_apps_irqs_size = ARRAY_SIZE(msm_mpm_bypassed_apps_irqs),
+	.mpm_request_reg_base = MSM_RPM_BASE + 0x9d8,
+	.mpm_status_reg_base = MSM_RPM_BASE + 0xdf8,
+	.mpm_apps_ipc_reg = MSM_APCS_GCC_BASE + 0x008,
+	.mpm_apps_ipc_val =  BIT(1),
+	.mpm_ipc_irq = RPM_APCC_CPU0_GP_MEDIUM_IRQ,
+
+};
+#endif
+
+/* AP2MDM_SOFT_RESET is implemented by the PON_RESET_N gpio */
+#define MDM2AP_ERRFATAL			19
+#define AP2MDM_ERRFATAL			18
+#define MDM2AP_STATUS			49
+#define AP2MDM_STATUS			48
+#define AP2MDM_SOFT_RESET		27
+#define AP2MDM_WAKEUP			35
+
+static struct resource mdm_resources[] = {
+	{
+		.start	= MDM2AP_ERRFATAL,
+		.end	= MDM2AP_ERRFATAL,
+		.name	= "MDM2AP_ERRFATAL",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= AP2MDM_ERRFATAL,
+		.end	= AP2MDM_ERRFATAL,
+		.name	= "AP2MDM_ERRFATAL",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= MDM2AP_STATUS,
+		.end	= MDM2AP_STATUS,
+		.name	= "MDM2AP_STATUS",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= AP2MDM_STATUS,
+		.end	= AP2MDM_STATUS,
+		.name	= "AP2MDM_STATUS",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= AP2MDM_SOFT_RESET,
+		.end	= AP2MDM_SOFT_RESET,
+		.name	= "AP2MDM_SOFT_RESET",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= AP2MDM_WAKEUP,
+		.end	= AP2MDM_WAKEUP,
+		.name	= "AP2MDM_WAKEUP",
+		.flags	= IORESOURCE_IO,
+	},
+};
+
+struct platform_device mdm_8064_device = {
+	.name		= "mdm2_modem",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(mdm_resources),
+	.resource	= mdm_resources,
+};
+
+static int apq8064_LPM_latency = 1000; /* >100 usec for WFI */
+
+struct platform_device apq8064_cpu_idle_device = {
+	.name   = "msm_cpu_idle",
+	.id     = -1,
+	.dev = {
+		.platform_data = &apq8064_LPM_latency,
+	},
+};
+
+static struct msm_dcvs_freq_entry apq8064_freq[] = {
+	{ 384000, 166981,  345600},
+	{ 702000, 213049,  632502},
+	{1026000, 285712,  925613},
+	{1242000, 383945, 1176550},
+	{1458000, 419729, 1465478},
+	{1512000, 434116, 1546674},
+
+};
+
+static struct msm_dcvs_core_info apq8064_core_info = {
+	.freq_tbl = &apq8064_freq[0],
+	.core_param = {
+		.max_time_us = 100000,
+		.num_freq = ARRAY_SIZE(apq8064_freq),
+	},
+	.algo_param = {
+		.slack_time_us = 58000,
+		.scale_slack_time = 0,
+		.scale_slack_time_pct = 0,
+		.disable_pc_threshold = 1458000,
+		.em_window_size = 100000,
+		.em_max_util_pct = 97,
+		.ss_window_size = 1000000,
+		.ss_util_pct = 95,
+		.ss_iobusy_conv = 100,
+	},
+};
+
+struct platform_device apq8064_msm_gov_device = {
+	.name = "msm_dcvs_gov",
+	.id = -1,
+	.dev = {
+		.platform_data = &apq8064_core_info,
+	},
+};
+
+#ifdef CONFIG_MSM_VCAP
+#define VCAP_HW_BASE         0x05900000
+
+static struct msm_bus_vectors vcap_init_vectors[]  = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_CAP,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+
+static struct msm_bus_vectors vcap_480_vectors[]  = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_CAP,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 1280 * 720 * 3 * 60,
+		.ib = 1280 * 720 * 3 * 60 * 1.5,
+	},
+};
+
+static struct msm_bus_vectors vcap_720_vectors[]  = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_CAP,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 1280 * 720 * 3 * 60,
+		.ib = 1280 * 720 * 3 * 60 * 1.5,
+	},
+};
+
+static struct msm_bus_vectors vcap_1080_vectors[]  = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_CAP,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 1920 * 1080 * 3 * 60,
+		.ib = 1920 * 1080 * 3 * 60 * 1.5,
+	},
+};
+
+static struct msm_bus_paths vcap_bus_usecases[]  = {
+	{
+		ARRAY_SIZE(vcap_init_vectors),
+		vcap_init_vectors,
+	},
+	{
+		ARRAY_SIZE(vcap_480_vectors),
+		vcap_480_vectors,
+	},
+	{
+		ARRAY_SIZE(vcap_720_vectors),
+		vcap_720_vectors,
+	},
+	{
+		ARRAY_SIZE(vcap_1080_vectors),
+		vcap_1080_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata vcap_axi_client_pdata = {
+	vcap_bus_usecases,
+	ARRAY_SIZE(vcap_bus_usecases),
+};
+
+static struct resource msm_vcap_resources[] = {
+	{
+		.name	= "vcap",
+		.start	= VCAP_HW_BASE,
+		.end	= VCAP_HW_BASE + SZ_1M - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "vc_irq",
+		.start	= VCAP_VC,
+		.end	= VCAP_VC,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "vp_irq",
+		.start	= VCAP_VP,
+		.end	= VCAP_VP,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static unsigned vcap_gpios[] = {
+	2, 3, 4, 5, 6, 7, 8, 9, 10,
+	11, 12, 13, 18, 19, 20, 21,
+	22, 23, 24, 25, 26, 80, 82,
+	83, 84, 85, 86, 87,
+};
+
+static struct vcap_platform_data vcap_pdata = {
+	.gpios = vcap_gpios,
+	.num_gpios = ARRAY_SIZE(vcap_gpios),
+	.bus_client_pdata = &vcap_axi_client_pdata
+};
+
+struct platform_device msm8064_device_vcap = {
+	.name           = "msm_vcap",
+	.id             = 0,
+	.resource       = msm_vcap_resources,
+	.num_resources  = ARRAY_SIZE(msm_vcap_resources),
+	.dev = {
+		.platform_data = &vcap_pdata,
+	},
+};
+#endif
+
+static struct resource msm_cache_erp_resources[] = {
+	{
+		.name = "l1_irq",
+		.start = SC_SICCPUXEXTFAULTIRPTREQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name = "l2_irq",
+		.start = APCC_QGICL2IRPTREQ,
+		.flags = IORESOURCE_IRQ,
+	}
+};
+
+struct platform_device apq8064_device_cache_erp = {
+	.name		= "msm_cache_erp",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(msm_cache_erp_resources),
+	.resource	= msm_cache_erp_resources,
+};
+
+#define MSM_QDSS_PHYS_BASE		0x01A00000
+#define MSM_ETM_PHYS_BASE		(MSM_QDSS_PHYS_BASE + 0x1C000)
+
+#define QDSS_SOURCE(src_name, fpm) { .name = src_name, .fport_mask = fpm, }
+
+static struct qdss_source msm_qdss_sources[] = {
+	QDSS_SOURCE("msm_etm", 0x33),
+	QDSS_SOURCE("msm_oxili", 0x80),
+};
+
+static struct msm_qdss_platform_data qdss_pdata = {
+	.src_table = msm_qdss_sources,
+	.size = ARRAY_SIZE(msm_qdss_sources),
+	.afamily = 1,
+};
+
+struct platform_device apq8064_qdss_device = {
+	.name          = "msm_qdss",
+	.id            = -1,
+	.dev           = {
+		.platform_data = &qdss_pdata,
+	},
+};
+
+static struct resource msm_etm_resources[] = {
+	{
+		.start = MSM_ETM_PHYS_BASE,
+		.end   = MSM_ETM_PHYS_BASE + (SZ_4K * 4) - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device apq8064_etm_device = {
+	.name          = "msm_etm",
+	.id            = 0,
+	.num_resources = ARRAY_SIZE(msm_etm_resources),
+	.resource      = msm_etm_resources,
+};
+
+struct msm_iommu_domain_name apq8064_iommu_ctx_names[] = {
+	/* Camera */
+	{
+		.name = "vpe_src",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Camera */
+	{
+		.name = "vpe_dst",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Camera */
+	{
+		.name = "vfe_imgwr",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Camera */
+	{
+		.name = "vfe_misc",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Camera */
+	{
+		.name = "ijpeg_src",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Camera */
+	{
+		.name = "ijpeg_dst",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Camera */
+	{
+		.name = "jpegd_src",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Camera */
+	{
+		.name = "jpegd_dst",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Rotator */
+	{
+		.name = "rot_src",
+		.domain = ROTATOR_DOMAIN,
+	},
+	/* Rotator */
+	{
+		.name = "rot_dst",
+		.domain = ROTATOR_DOMAIN,
+	},
+	/* Video */
+	{
+		.name = "vcodec_a_mm1",
+		.domain = VIDEO_DOMAIN,
+	},
+	/* Video */
+	{
+		.name = "vcodec_b_mm2",
+		.domain = VIDEO_DOMAIN,
+	},
+	/* Video */
+	{
+		.name = "vcodec_a_stream",
+		.domain = VIDEO_DOMAIN,
+	},
+};
+
+static struct mem_pool apq8064_video_pools[] =  {
+	/*
+	 * Video hardware has the following requirements:
+	 * 1. All video addresses used by the video hardware must be at a higher
+	 *    address than video firmware address.
+	 * 2. Video hardware can only access a range of 256MB from the base of
+	 *    the video firmware.
+	*/
+	[VIDEO_FIRMWARE_POOL] =
+	/* Low addresses, intended for video firmware */
+		{
+			.paddr	= SZ_128K,
+			.size	= SZ_16M - SZ_128K,
+		},
+	[VIDEO_MAIN_POOL] =
+	/* Main video pool */
+		{
+			.paddr	= SZ_16M,
+			.size	= SZ_256M - SZ_16M,
+		},
+	[GEN_POOL] =
+	/* Remaining address space up to 2G */
+		{
+			.paddr	= SZ_256M,
+			.size	= SZ_2G - SZ_256M,
+		},
+};
+
+static struct mem_pool apq8064_camera_pools[] =  {
+	[GEN_POOL] =
+	/* One address space for camera */
+		{
+			.paddr	= SZ_128K,
+			.size	= SZ_2G - SZ_128K,
+		},
+};
+
+static struct mem_pool apq8064_display_pools[] =  {
+	[GEN_POOL] =
+	/* One address space for display */
+		{
+			.paddr	= SZ_128K,
+			.size	= SZ_2G - SZ_128K,
+		},
+};
+
+static struct mem_pool apq8064_rotator_pools[] =  {
+	[GEN_POOL] =
+	/* One address space for rotator */
+		{
+			.paddr	= SZ_128K,
+			.size	= SZ_2G - SZ_128K,
+		},
+};
+
+static struct msm_iommu_domain apq8064_iommu_domains[] = {
+		[VIDEO_DOMAIN] = {
+			.iova_pools = apq8064_video_pools,
+			.npools = ARRAY_SIZE(apq8064_video_pools),
+		},
+		[CAMERA_DOMAIN] = {
+			.iova_pools = apq8064_camera_pools,
+			.npools = ARRAY_SIZE(apq8064_camera_pools),
+		},
+		[DISPLAY_DOMAIN] = {
+			.iova_pools = apq8064_display_pools,
+			.npools = ARRAY_SIZE(apq8064_display_pools),
+		},
+		[ROTATOR_DOMAIN] = {
+			.iova_pools = apq8064_rotator_pools,
+			.npools = ARRAY_SIZE(apq8064_rotator_pools),
+		},
+};
+
+struct iommu_domains_pdata apq8064_iommu_domain_pdata = {
+	.domains = apq8064_iommu_domains,
+	.ndomains = ARRAY_SIZE(apq8064_iommu_domains),
+	.domain_names = apq8064_iommu_ctx_names,
+	.nnames = ARRAY_SIZE(apq8064_iommu_ctx_names),
+	.domain_alloc_flags = 0,
+};
+
+struct platform_device apq8064_iommu_domain_device = {
+	.name = "iommu_domains",
+	.id = -1,
+	.dev = {
+		.platform_data = &apq8064_iommu_domain_pdata,
+	}
+};
+
+struct msm_rtb_platform_data apq8064_rtb_pdata = {
+	.size = SZ_1M,
+};
+
+static int __init msm_rtb_set_buffer_size(char *p)
+{
+	int s;
+
+	s = memparse(p, NULL);
+	apq8064_rtb_pdata.size = ALIGN(s, SZ_4K);
+	return 0;
+}
+early_param("msm_rtb_size", msm_rtb_set_buffer_size);
+
+struct platform_device apq8064_rtb_device = {
+	.name           = "msm_rtb",
+	.id             = -1,
+	.dev            = {
+		.platform_data = &apq8064_rtb_pdata,
+	},
+};
+
+#define APQ8064_L1_SIZE  SZ_1M
+/*
+ * The actual L2 size is smaller but we need a larger buffer
+ * size to store other dump information
+ */
+#define APQ8064_L2_SIZE  SZ_8M
+
+struct msm_cache_dump_platform_data apq8064_cache_dump_pdata = {
+	.l2_size = APQ8064_L2_SIZE,
+	.l1_size = APQ8064_L1_SIZE,
+};
+
+struct platform_device apq8064_cache_dump_device = {
+	.name           = "msm_cache_dump",
+	.id             = -1,
+	.dev            = {
+		.platform_data = &apq8064_cache_dump_pdata,
+	},
+};
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
new file mode 100644
index 0000000..2c4687f
--- /dev/null
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -0,0 +1,906 @@
+/* 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/kernel.h>
+#include <linux/platform_device.h>
+#include <asm/io.h>
+#include <linux/ion.h>
+#include <mach/msm_iomap.h>
+#include <mach/irqs-8930.h>
+#include <mach/rpm.h>
+#include <mach/msm_dcvs.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#include <mach/board.h>
+#include <mach/socinfo.h>
+#include <mach/iommu_domains.h>
+#include <mach/msm_rtb.h>
+
+#include "devices.h"
+#include "rpm_log.h"
+#include "rpm_stats.h"
+#include "footswitch.h"
+
+#ifdef CONFIG_MSM_MPM
+#include <mach/mpm.h>
+#endif
+
+struct msm_rpm_platform_data msm8930_rpm_data __initdata = {
+	.reg_base_addrs = {
+		[MSM_RPM_PAGE_STATUS] = MSM_RPM_BASE,
+		[MSM_RPM_PAGE_CTRL] = MSM_RPM_BASE + 0x400,
+		[MSM_RPM_PAGE_REQ] = MSM_RPM_BASE + 0x600,
+		[MSM_RPM_PAGE_ACK] = MSM_RPM_BASE + 0xa00,
+	},
+	.irq_ack = RPM_APCC_CPU0_GP_HIGH_IRQ,
+	.irq_err = RPM_APCC_CPU0_GP_LOW_IRQ,
+	.irq_wakeup = RPM_APCC_CPU0_WAKE_UP_IRQ,
+	.ipc_rpm_reg = MSM_APCS_GCC_BASE + 0x008,
+	.ipc_rpm_val = 4,
+	.target_id = {
+		MSM_RPM_MAP(8930, NOTIFICATION_CONFIGURED_0, NOTIFICATION, 4),
+		MSM_RPM_MAP(8930, NOTIFICATION_REGISTERED_0, NOTIFICATION, 4),
+		MSM_RPM_MAP(8930, INVALIDATE_0, INVALIDATE, 8),
+		MSM_RPM_MAP(8960, TRIGGER_TIMED_TO, TRIGGER_TIMED, 1),
+		MSM_RPM_MAP(8960, TRIGGER_TIMED_SCLK_COUNT, TRIGGER_TIMED, 1),
+		MSM_RPM_MAP(8930, RPM_CTL, RPM_CTL, 1),
+		MSM_RPM_MAP(8930, CXO_CLK, CXO_CLK, 1),
+		MSM_RPM_MAP(8930, PXO_CLK, PXO_CLK, 1),
+		MSM_RPM_MAP(8930, APPS_FABRIC_CLK, APPS_FABRIC_CLK, 1),
+		MSM_RPM_MAP(8930, SYSTEM_FABRIC_CLK, SYSTEM_FABRIC_CLK, 1),
+		MSM_RPM_MAP(8930, MM_FABRIC_CLK, MM_FABRIC_CLK, 1),
+		MSM_RPM_MAP(8930, DAYTONA_FABRIC_CLK, DAYTONA_FABRIC_CLK, 1),
+		MSM_RPM_MAP(8930, SFPB_CLK, SFPB_CLK, 1),
+		MSM_RPM_MAP(8930, CFPB_CLK, CFPB_CLK, 1),
+		MSM_RPM_MAP(8930, MMFPB_CLK, MMFPB_CLK, 1),
+		MSM_RPM_MAP(8930, EBI1_CLK, EBI1_CLK, 1),
+		MSM_RPM_MAP(8930, APPS_FABRIC_CFG_HALT_0,
+				APPS_FABRIC_CFG_HALT, 2),
+		MSM_RPM_MAP(8930, APPS_FABRIC_CFG_CLKMOD_0,
+				APPS_FABRIC_CFG_CLKMOD, 3),
+		MSM_RPM_MAP(8930, APPS_FABRIC_CFG_IOCTL,
+				APPS_FABRIC_CFG_IOCTL, 1),
+		MSM_RPM_MAP(8930, APPS_FABRIC_ARB_0, APPS_FABRIC_ARB, 6),
+		MSM_RPM_MAP(8930, SYS_FABRIC_CFG_HALT_0,
+				SYS_FABRIC_CFG_HALT, 2),
+		MSM_RPM_MAP(8930, SYS_FABRIC_CFG_CLKMOD_0,
+				SYS_FABRIC_CFG_CLKMOD, 3),
+		MSM_RPM_MAP(8930, SYS_FABRIC_CFG_IOCTL,
+				SYS_FABRIC_CFG_IOCTL, 1),
+		MSM_RPM_MAP(8930, SYSTEM_FABRIC_ARB_0,
+				SYSTEM_FABRIC_ARB, 20),
+		MSM_RPM_MAP(8930, MMSS_FABRIC_CFG_HALT_0,
+				MMSS_FABRIC_CFG_HALT, 2),
+		MSM_RPM_MAP(8930, MMSS_FABRIC_CFG_CLKMOD_0,
+				MMSS_FABRIC_CFG_CLKMOD, 3),
+		MSM_RPM_MAP(8930, MMSS_FABRIC_CFG_IOCTL,
+				MMSS_FABRIC_CFG_IOCTL, 1),
+		MSM_RPM_MAP(8930, MM_FABRIC_ARB_0, MM_FABRIC_ARB, 11),
+		MSM_RPM_MAP(8930, PM8038_S1_0, PM8038_S1, 2),
+		MSM_RPM_MAP(8930, PM8038_S2_0, PM8038_S2, 2),
+		MSM_RPM_MAP(8930, PM8038_S3_0, PM8038_S3, 2),
+		MSM_RPM_MAP(8930, PM8038_S4_0, PM8038_S4, 2),
+		MSM_RPM_MAP(8930, PM8038_S5_0, PM8038_S5, 2),
+		MSM_RPM_MAP(8930, PM8038_S6_0, PM8038_S6, 2),
+		MSM_RPM_MAP(8930, PM8038_L1_0, PM8038_L1, 2),
+		MSM_RPM_MAP(8930, PM8038_L2_0, PM8038_L2, 2),
+		MSM_RPM_MAP(8930, PM8038_L3_0, PM8038_L3, 2),
+		MSM_RPM_MAP(8930, PM8038_L4_0, PM8038_L4, 2),
+		MSM_RPM_MAP(8930, PM8038_L5_0, PM8038_L5, 2),
+		MSM_RPM_MAP(8930, PM8038_L6_0, PM8038_L6, 2),
+		MSM_RPM_MAP(8930, PM8038_L7_0, PM8038_L7, 2),
+		MSM_RPM_MAP(8930, PM8038_L8_0, PM8038_L8, 2),
+		MSM_RPM_MAP(8930, PM8038_L9_0, PM8038_L9, 2),
+		MSM_RPM_MAP(8930, PM8038_L10_0, PM8038_L10, 2),
+		MSM_RPM_MAP(8930, PM8038_L11_0, PM8038_L11, 2),
+		MSM_RPM_MAP(8930, PM8038_L12_0, PM8038_L12, 2),
+		MSM_RPM_MAP(8930, PM8038_L13_0, PM8038_L13, 2),
+		MSM_RPM_MAP(8930, PM8038_L14_0, PM8038_L14, 2),
+		MSM_RPM_MAP(8930, PM8038_L15_0, PM8038_L15, 2),
+		MSM_RPM_MAP(8930, PM8038_L16_0, PM8038_L16, 2),
+		MSM_RPM_MAP(8930, PM8038_L17_0, PM8038_L17, 2),
+		MSM_RPM_MAP(8930, PM8038_L18_0, PM8038_L18, 2),
+		MSM_RPM_MAP(8930, PM8038_L19_0, PM8038_L19, 2),
+		MSM_RPM_MAP(8930, PM8038_L20_0, PM8038_L20, 2),
+		MSM_RPM_MAP(8930, PM8038_L21_0, PM8038_L21, 2),
+		MSM_RPM_MAP(8930, PM8038_L22_0, PM8038_L22, 2),
+		MSM_RPM_MAP(8930, PM8038_L23_0, PM8038_L23, 2),
+		MSM_RPM_MAP(8930, PM8038_L24_0, PM8038_L24, 2),
+		MSM_RPM_MAP(8930, PM8038_L25_0, PM8038_L25, 2),
+		MSM_RPM_MAP(8930, PM8038_L26_0, PM8038_L26, 2),
+		MSM_RPM_MAP(8930, PM8038_L27_0, PM8038_L27, 2),
+		MSM_RPM_MAP(8930, PM8038_CLK1_0, PM8038_CLK1, 2),
+		MSM_RPM_MAP(8930, PM8038_CLK2_0, PM8038_CLK2, 2),
+		MSM_RPM_MAP(8930, PM8038_LVS1, PM8038_LVS1, 1),
+		MSM_RPM_MAP(8930, PM8038_LVS2, PM8038_LVS2, 1),
+		MSM_RPM_MAP(8930, NCP_0, NCP, 2),
+		MSM_RPM_MAP(8930, CXO_BUFFERS, CXO_BUFFERS, 1),
+		MSM_RPM_MAP(8930, USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
+		MSM_RPM_MAP(8930, HDMI_SWITCH, HDMI_SWITCH, 1),
+		MSM_RPM_MAP(8930, DDR_DMM_0, DDR_DMM, 2),
+		MSM_RPM_MAP(8930, QDSS_CLK, QDSS_CLK, 1),
+		MSM_RPM_MAP(8930, VOLTAGE_CORNER, VOLTAGE_CORNER, 1),
+	},
+	.target_status = {
+		MSM_RPM_STATUS_ID_MAP(8930, VERSION_MAJOR),
+		MSM_RPM_STATUS_ID_MAP(8930, VERSION_MINOR),
+		MSM_RPM_STATUS_ID_MAP(8930, VERSION_BUILD),
+		MSM_RPM_STATUS_ID_MAP(8930, SUPPORTED_RESOURCES_0),
+		MSM_RPM_STATUS_ID_MAP(8930, SUPPORTED_RESOURCES_1),
+		MSM_RPM_STATUS_ID_MAP(8930, SUPPORTED_RESOURCES_2),
+		MSM_RPM_STATUS_ID_MAP(8930, RESERVED_SUPPORTED_RESOURCES_0),
+		MSM_RPM_STATUS_ID_MAP(8930, SEQUENCE),
+		MSM_RPM_STATUS_ID_MAP(8930, RPM_CTL),
+		MSM_RPM_STATUS_ID_MAP(8930, CXO_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, PXO_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, APPS_FABRIC_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, SYSTEM_FABRIC_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, MM_FABRIC_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, DAYTONA_FABRIC_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, SFPB_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, CFPB_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, MMFPB_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, EBI1_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, APPS_FABRIC_CFG_HALT),
+		MSM_RPM_STATUS_ID_MAP(8930, APPS_FABRIC_CFG_CLKMOD),
+		MSM_RPM_STATUS_ID_MAP(8930, APPS_FABRIC_CFG_IOCTL),
+		MSM_RPM_STATUS_ID_MAP(8930, APPS_FABRIC_ARB),
+		MSM_RPM_STATUS_ID_MAP(8930, SYS_FABRIC_CFG_HALT),
+		MSM_RPM_STATUS_ID_MAP(8930, SYS_FABRIC_CFG_CLKMOD),
+		MSM_RPM_STATUS_ID_MAP(8930, SYS_FABRIC_CFG_IOCTL),
+		MSM_RPM_STATUS_ID_MAP(8930, SYSTEM_FABRIC_ARB),
+		MSM_RPM_STATUS_ID_MAP(8930, MMSS_FABRIC_CFG_HALT),
+		MSM_RPM_STATUS_ID_MAP(8930, MMSS_FABRIC_CFG_CLKMOD),
+		MSM_RPM_STATUS_ID_MAP(8930, MMSS_FABRIC_CFG_IOCTL),
+		MSM_RPM_STATUS_ID_MAP(8930, MM_FABRIC_ARB),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_S1_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_S1_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_S2_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_S2_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_S3_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_S3_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_S4_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_S4_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L1_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L1_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L2_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L2_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L3_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L3_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L4_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L4_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L5_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L5_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L6_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L6_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L7_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L7_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L8_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L8_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L9_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L9_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L10_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L10_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L11_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L11_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L12_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L12_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L13_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L13_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L14_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L14_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L15_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L15_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L16_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L16_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L17_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L17_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L18_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L18_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L19_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L19_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L20_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L20_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L21_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L21_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L22_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L22_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L23_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L23_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L24_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L24_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L25_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_L25_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_CLK1_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_CLK1_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_CLK2_0),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_CLK2_1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_LVS1),
+		MSM_RPM_STATUS_ID_MAP(8930, PM8038_LVS2),
+		MSM_RPM_STATUS_ID_MAP(8930, NCP_0),
+		MSM_RPM_STATUS_ID_MAP(8930, NCP_1),
+		MSM_RPM_STATUS_ID_MAP(8930, CXO_BUFFERS),
+		MSM_RPM_STATUS_ID_MAP(8930, USB_OTG_SWITCH),
+		MSM_RPM_STATUS_ID_MAP(8930, HDMI_SWITCH),
+		MSM_RPM_STATUS_ID_MAP(8930, DDR_DMM_0),
+		MSM_RPM_STATUS_ID_MAP(8930, DDR_DMM_1),
+		MSM_RPM_STATUS_ID_MAP(8930, QDSS_CLK),
+		MSM_RPM_STATUS_ID_MAP(8930, VOLTAGE_CORNER),
+	},
+	.target_ctrl_id = {
+		MSM_RPM_CTRL_MAP(8930, VERSION_MAJOR),
+		MSM_RPM_CTRL_MAP(8930, VERSION_MINOR),
+		MSM_RPM_CTRL_MAP(8930, VERSION_BUILD),
+		MSM_RPM_CTRL_MAP(8930, REQ_CTX_0),
+		MSM_RPM_CTRL_MAP(8930, REQ_SEL_0),
+		MSM_RPM_CTRL_MAP(8930, ACK_CTX_0),
+		MSM_RPM_CTRL_MAP(8930, ACK_SEL_0),
+	},
+	.sel_invalidate = MSM_RPM_8930_SEL_INVALIDATE,
+	.sel_notification = MSM_RPM_8930_SEL_NOTIFICATION,
+	.sel_last = MSM_RPM_8930_SEL_LAST,
+	.ver = {3, 0, 0},
+};
+
+struct platform_device msm8930_rpm_device = {
+	.name   = "msm_rpm",
+	.id     = -1,
+};
+
+static struct msm_rpm_log_platform_data msm_rpm_log_pdata = {
+	.phys_addr_base = 0x0010C000,
+	.reg_offsets = {
+		[MSM_RPM_LOG_PAGE_INDICES] = 0x00000080,
+		[MSM_RPM_LOG_PAGE_BUFFER]  = 0x000000A0,
+	},
+	.phys_size = SZ_8K,
+	.log_len = 4096,		  /* log's buffer length in bytes */
+	.log_len_mask = (4096 >> 2) - 1,  /* length mask in units of u32 */
+};
+
+struct platform_device msm8930_rpm_log_device = {
+	.name	= "msm_rpm_log",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &msm_rpm_log_pdata,
+	},
+};
+
+static struct msm_rpmstats_platform_data msm_rpm_stat_pdata = {
+	.phys_addr_base = 0x0010D204,
+	.phys_size = SZ_8K,
+};
+
+struct platform_device msm8930_rpm_stat_device = {
+	.name = "msm_rpm_stat",
+	.id = -1,
+	.dev = {
+		.platform_data = &msm_rpm_stat_pdata,
+	},
+};
+
+static int msm8930_LPM_latency = 1000; /* >100 usec for WFI */
+
+struct platform_device msm8930_cpu_idle_device = {
+	.name   = "msm_cpu_idle",
+	.id     = -1,
+	.dev = {
+		.platform_data = &msm8930_LPM_latency,
+	},
+};
+
+static struct msm_dcvs_freq_entry msm8930_freq[] = {
+	{ 384000, 166981,  345600},
+	{ 702000, 213049,  632502},
+	{1026000, 285712,  925613},
+	{1242000, 383945, 1176550},
+	{1458000, 419729, 1465478},
+	{1512000, 434116, 1546674},
+
+};
+
+static struct msm_dcvs_core_info msm8930_core_info = {
+	.freq_tbl = &msm8930_freq[0],
+	.core_param = {
+		.max_time_us = 100000,
+		.num_freq = ARRAY_SIZE(msm8930_freq),
+	},
+	.algo_param = {
+		.slack_time_us = 58000,
+		.scale_slack_time = 0,
+		.scale_slack_time_pct = 0,
+		.disable_pc_threshold = 1458000,
+		.em_window_size = 100000,
+		.em_max_util_pct = 97,
+		.ss_window_size = 1000000,
+		.ss_util_pct = 95,
+		.ss_iobusy_conv = 100,
+	},
+};
+
+struct platform_device msm8930_msm_gov_device = {
+	.name = "msm_dcvs_gov",
+	.id = -1,
+	.dev = {
+		.platform_data = &msm8930_core_info,
+	},
+};
+
+struct platform_device msm_bus_8930_sys_fabric = {
+	.name  = "msm_bus_fabric",
+	.id    =  MSM_BUS_FAB_SYSTEM,
+};
+struct platform_device msm_bus_8930_apps_fabric = {
+	.name  = "msm_bus_fabric",
+	.id    = MSM_BUS_FAB_APPSS,
+};
+struct platform_device msm_bus_8930_mm_fabric = {
+	.name  = "msm_bus_fabric",
+	.id    = MSM_BUS_FAB_MMSS,
+};
+struct platform_device msm_bus_8930_sys_fpb = {
+	.name  = "msm_bus_fabric",
+	.id    = MSM_BUS_FAB_SYSTEM_FPB,
+};
+struct platform_device msm_bus_8930_cpss_fpb = {
+	.name  = "msm_bus_fabric",
+	.id    = MSM_BUS_FAB_CPSS_FPB,
+};
+
+static struct fs_driver_data gfx3d_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk", .reset_rate = 27000000 },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_GRAPHICS_3D,
+};
+
+static struct fs_driver_data ijpeg_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_JPEG_ENC,
+};
+
+static struct fs_driver_data mdp_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ .name = "vsync_clk" },
+		{ .name = "lut_clk" },
+		{ .name = "tv_src_clk" },
+		{ .name = "tv_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_MDP_PORT0,
+	.bus_port1 = MSM_BUS_MASTER_MDP_PORT1,
+};
+
+static struct fs_driver_data rot_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_ROTATOR,
+};
+
+static struct fs_driver_data ved_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_HD_CODEC_PORT0,
+	.bus_port1 = MSM_BUS_MASTER_HD_CODEC_PORT1,
+};
+
+static struct fs_driver_data vfe_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_VFE,
+};
+
+static struct fs_driver_data vpe_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_VPE,
+};
+
+struct platform_device *msm8930_footswitch[] __initdata = {
+	FS_8X60(FS_MDP,    "vdd",	"mdp.0",	&mdp_fs_data),
+	FS_8X60(FS_ROT,    "vdd",	"msm_rotator.0", &rot_fs_data),
+	FS_8X60(FS_IJPEG,  "vdd",	"msm_gemini.0", &ijpeg_fs_data),
+	FS_8X60(FS_VFE,    "fs_vfe",	NULL,	&vfe_fs_data),
+	FS_8X60(FS_VPE,    "fs_vpe",	NULL,	&vpe_fs_data),
+	FS_8X60(FS_GFX3D,  "vdd",	"kgsl-3d0.0",	&gfx3d_fs_data),
+	FS_8X60(FS_VED,    "vdd",	"msm_vidc.0",	&ved_fs_data),
+};
+unsigned msm8930_num_footswitch __initdata = ARRAY_SIZE(msm8930_footswitch);
+
+/* MSM Video core device */
+#ifdef CONFIG_MSM_BUS_SCALING
+static struct msm_bus_vectors vidc_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+static struct msm_bus_vectors vidc_venc_vga_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 54525952,
+		.ib  = 436207616,
+	},
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 72351744,
+		.ib  = 289406976,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 500000,
+		.ib  = 1000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 500000,
+		.ib  = 1000000,
+	},
+};
+static struct msm_bus_vectors vidc_vdec_vga_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 40894464,
+		.ib  = 327155712,
+	},
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 48234496,
+		.ib  = 192937984,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 500000,
+		.ib  = 2000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 500000,
+		.ib  = 2000000,
+	},
+};
+static struct msm_bus_vectors vidc_venc_720p_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 163577856,
+		.ib  = 1308622848,
+	},
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 219152384,
+		.ib  = 876609536,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 1750000,
+		.ib  = 3500000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 1750000,
+		.ib  = 3500000,
+	},
+};
+static struct msm_bus_vectors vidc_vdec_720p_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 121634816,
+		.ib  = 973078528,
+	},
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 155189248,
+		.ib  = 620756992,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 1750000,
+		.ib  = 7000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 1750000,
+		.ib  = 7000000,
+	},
+};
+static struct msm_bus_vectors vidc_venc_1080p_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 372244480,
+		.ib  = 2560000000U,
+	},
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 501219328,
+		.ib  = 2560000000U,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 2500000,
+		.ib  = 5000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 2500000,
+		.ib  = 5000000,
+	},
+};
+static struct msm_bus_vectors vidc_vdec_1080p_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 222298112,
+		.ib  = 2560000000U,
+	},
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 330301440,
+		.ib  = 2560000000U,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 2500000,
+		.ib  = 700000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 2500000,
+		.ib  = 10000000,
+	},
+};
+
+static struct msm_bus_paths vidc_bus_client_config[] = {
+	{
+		ARRAY_SIZE(vidc_init_vectors),
+		vidc_init_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_venc_vga_vectors),
+		vidc_venc_vga_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_vdec_vga_vectors),
+		vidc_vdec_vga_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_venc_720p_vectors),
+		vidc_venc_720p_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_vdec_720p_vectors),
+		vidc_vdec_720p_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_venc_1080p_vectors),
+		vidc_venc_1080p_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_vdec_1080p_vectors),
+		vidc_vdec_1080p_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata vidc_bus_client_data = {
+	vidc_bus_client_config,
+	ARRAY_SIZE(vidc_bus_client_config),
+	.name = "vidc",
+};
+#endif
+
+#define MSM_VIDC_BASE_PHYS 0x04400000
+#define MSM_VIDC_BASE_SIZE 0x00100000
+
+static struct resource apq8930_device_vidc_resources[] = {
+	{
+		.start	= MSM_VIDC_BASE_PHYS,
+		.end	= MSM_VIDC_BASE_PHYS + MSM_VIDC_BASE_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= VCODEC_IRQ,
+		.end	= VCODEC_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct msm_vidc_platform_data apq8930_vidc_platform_data = {
+#ifdef CONFIG_MSM_BUS_SCALING
+	.vidc_bus_client_pdata = &vidc_bus_client_data,
+#endif
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	.memtype = ION_CP_MM_HEAP_ID,
+	.enable_ion = 1,
+	.cp_enabled = 1,
+#else
+	.memtype = MEMTYPE_EBI1,
+	.enable_ion = 0,
+#endif
+	.disable_dmx = 1,
+	.disable_fullhd = 0,
+};
+
+struct platform_device apq8930_msm_device_vidc = {
+	.name = "msm_vidc",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(apq8930_device_vidc_resources),
+	.resource = apq8930_device_vidc_resources,
+	.dev = {
+		.platform_data = &apq8930_vidc_platform_data,
+	},
+};
+
+struct platform_device *vidc_device[] __initdata = {
+	&apq8930_msm_device_vidc
+};
+
+void __init msm8930_add_vidc_device(void)
+{
+	if (cpu_is_msm8627()) {
+		struct msm_vidc_platform_data *pdata;
+		pdata = (struct msm_vidc_platform_data *)
+			apq8930_msm_device_vidc.dev.platform_data;
+		pdata->disable_fullhd = 1;
+	}
+	platform_add_devices(vidc_device, ARRAY_SIZE(vidc_device));
+}
+
+struct msm_iommu_domain_name msm8930_iommu_ctx_names[] = {
+	/* Camera */
+	{
+		.name = "vpe_src",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Camera */
+	{
+		.name = "vpe_dst",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Camera */
+	{
+		.name = "vfe_imgwr",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Camera */
+	{
+		.name = "vfe_misc",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Camera */
+	{
+		.name = "ijpeg_src",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Camera */
+	{
+		.name = "ijpeg_dst",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Camera */
+	{
+		.name = "jpegd_src",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Camera */
+	{
+		.name = "jpegd_dst",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Rotator */
+	{
+		.name = "rot_src",
+		.domain = ROTATOR_DOMAIN,
+	},
+	/* Rotator */
+	{
+		.name = "rot_dst",
+		.domain = ROTATOR_DOMAIN,
+	},
+	/* Video */
+	{
+		.name = "vcodec_a_mm1",
+		.domain = VIDEO_DOMAIN,
+	},
+	/* Video */
+	{
+		.name = "vcodec_b_mm2",
+		.domain = VIDEO_DOMAIN,
+	},
+	/* Video */
+	{
+		.name = "vcodec_a_stream",
+		.domain = VIDEO_DOMAIN,
+	},
+};
+
+static struct mem_pool msm8930_video_pools[] =  {
+	/*
+	 * Video hardware has the following requirements:
+	 * 1. All video addresses used by the video hardware must be at a higher
+	 *    address than video firmware address.
+	 * 2. Video hardware can only access a range of 256MB from the base of
+	 *    the video firmware.
+	*/
+	[VIDEO_FIRMWARE_POOL] =
+	/* Low addresses, intended for video firmware */
+		{
+			.paddr	= SZ_128K,
+			.size	= SZ_16M - SZ_128K,
+		},
+	[VIDEO_MAIN_POOL] =
+	/* Main video pool */
+		{
+			.paddr	= SZ_16M,
+			.size	= SZ_256M - SZ_16M,
+		},
+	[GEN_POOL] =
+	/* Remaining address space up to 2G */
+		{
+			.paddr	= SZ_256M,
+			.size	= SZ_2G - SZ_256M,
+		},
+};
+
+static struct mem_pool msm8930_camera_pools[] =  {
+	[GEN_POOL] =
+	/* One address space for camera */
+		{
+			.paddr	= SZ_128K,
+			.size	= SZ_2G - SZ_128K,
+		},
+};
+
+static struct mem_pool msm8930_display_pools[] =  {
+	[GEN_POOL] =
+	/* One address space for display */
+		{
+			.paddr	= SZ_128K,
+			.size	= SZ_2G - SZ_128K,
+		},
+};
+
+static struct mem_pool msm8930_rotator_pools[] =  {
+	[GEN_POOL] =
+	/* One address space for rotator */
+		{
+			.paddr	= SZ_128K,
+			.size	= SZ_2G - SZ_128K,
+		},
+};
+
+static struct msm_iommu_domain msm8930_iommu_domains[] = {
+		[VIDEO_DOMAIN] = {
+			.iova_pools = msm8930_video_pools,
+			.npools = ARRAY_SIZE(msm8930_video_pools),
+		},
+		[CAMERA_DOMAIN] = {
+			.iova_pools = msm8930_camera_pools,
+			.npools = ARRAY_SIZE(msm8930_camera_pools),
+		},
+		[DISPLAY_DOMAIN] = {
+			.iova_pools = msm8930_display_pools,
+			.npools = ARRAY_SIZE(msm8930_display_pools),
+		},
+		[ROTATOR_DOMAIN] = {
+			.iova_pools = msm8930_rotator_pools,
+			.npools = ARRAY_SIZE(msm8930_rotator_pools),
+		},
+};
+
+struct iommu_domains_pdata msm8930_iommu_domain_pdata = {
+	.domains = msm8930_iommu_domains,
+	.ndomains = ARRAY_SIZE(msm8930_iommu_domains),
+	.domain_names = msm8930_iommu_ctx_names,
+	.nnames = ARRAY_SIZE(msm8930_iommu_ctx_names),
+	.domain_alloc_flags = 0,
+};
+
+struct platform_device msm8930_iommu_domain_device = {
+	.name = "iommu_domains",
+	.id = -1,
+	.dev = {
+		.platform_data = &msm8930_iommu_domain_pdata,
+	}
+};
+
+struct msm_rtb_platform_data msm8930_rtb_pdata = {
+	.size = SZ_1M,
+};
+
+static int __init msm_rtb_set_buffer_size(char *p)
+{
+	int s;
+
+	s = memparse(p, NULL);
+	msm8930_rtb_pdata.size = ALIGN(s, SZ_4K);
+	return 0;
+}
+early_param("msm_rtb_size", msm_rtb_set_buffer_size);
+
+
+struct platform_device msm8930_rtb_device = {
+	.name           = "msm_rtb",
+	.id             = -1,
+	.dev            = {
+		.platform_data = &msm8930_rtb_pdata,
+	},
+};
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
new file mode 100644
index 0000000..be364e7
--- /dev/null
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -0,0 +1,3712 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/msm_rotator.h>
+#include <linux/ion.h>
+#include <linux/gpio.h>
+#include <asm/clkdev.h>
+#include <linux/msm_kgsl.h>
+#include <linux/android_pmem.h>
+#include <mach/irqs-8960.h>
+#include <mach/dma.h>
+#include <linux/dma-mapping.h>
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_hsusb.h>
+#include <mach/msm_sps.h>
+#include <mach/rpm.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_memtypes.h>
+#include <mach/msm_smd.h>
+#include <mach/msm_dcvs.h>
+#include <mach/msm_rtb.h>
+#include <mach/msm_cache_dump.h>
+#include <sound/msm-dai-q6.h>
+#include <sound/apr_audio.h>
+#include <mach/msm_tsif.h>
+#include <mach/qdss.h>
+#include <mach/msm_serial_hs_lite.h>
+#include "clock.h"
+#include "devices.h"
+#include "devices-msm8x60.h"
+#include "footswitch.h"
+#include "msm_watchdog.h"
+#include "rpm_log.h"
+#include "rpm_stats.h"
+#include "pil-q6v4.h"
+#include "scm-pas.h"
+#include <mach/msm_dcvs.h>
+#include <mach/iommu_domains.h>
+
+#ifdef CONFIG_MSM_MPM
+#include <mach/mpm.h>
+#endif
+#ifdef CONFIG_MSM_DSPS
+#include <mach/msm_dsps.h>
+#endif
+
+
+/* Address of GSBI blocks */
+#define MSM_GSBI1_PHYS		0x16000000
+#define MSM_GSBI2_PHYS		0x16100000
+#define MSM_GSBI3_PHYS		0x16200000
+#define MSM_GSBI4_PHYS		0x16300000
+#define MSM_GSBI5_PHYS		0x16400000
+#define MSM_GSBI6_PHYS		0x16500000
+#define MSM_GSBI7_PHYS		0x16600000
+#define MSM_GSBI8_PHYS		0x1A000000
+#define MSM_GSBI9_PHYS		0x1A100000
+#define MSM_GSBI10_PHYS		0x1A200000
+#define MSM_GSBI11_PHYS		0x12440000
+#define MSM_GSBI12_PHYS		0x12480000
+
+#define MSM_UART2DM_PHYS	(MSM_GSBI2_PHYS + 0x40000)
+#define MSM_UART5DM_PHYS	(MSM_GSBI5_PHYS + 0x40000)
+#define MSM_UART6DM_PHYS	(MSM_GSBI6_PHYS + 0x40000)
+#define MSM_UART8DM_PHYS	(MSM_GSBI8_PHYS + 0x40000)
+#define MSM_UART9DM_PHYS	(MSM_GSBI9_PHYS + 0x40000)
+
+/* GSBI QUP devices */
+#define MSM_GSBI1_QUP_PHYS	(MSM_GSBI1_PHYS + 0x80000)
+#define MSM_GSBI2_QUP_PHYS	(MSM_GSBI2_PHYS + 0x80000)
+#define MSM_GSBI3_QUP_PHYS	(MSM_GSBI3_PHYS + 0x80000)
+#define MSM_GSBI4_QUP_PHYS	(MSM_GSBI4_PHYS + 0x80000)
+#define MSM_GSBI5_QUP_PHYS	(MSM_GSBI5_PHYS + 0x80000)
+#define MSM_GSBI6_QUP_PHYS	(MSM_GSBI6_PHYS + 0x80000)
+#define MSM_GSBI7_QUP_PHYS	(MSM_GSBI7_PHYS + 0x80000)
+#define MSM_GSBI8_QUP_PHYS	(MSM_GSBI8_PHYS + 0x80000)
+#define MSM_GSBI9_QUP_PHYS	(MSM_GSBI9_PHYS + 0x80000)
+#define MSM_GSBI10_QUP_PHYS	(MSM_GSBI10_PHYS + 0x80000)
+#define MSM_GSBI11_QUP_PHYS	(MSM_GSBI11_PHYS + 0x20000)
+#define MSM_GSBI12_QUP_PHYS	(MSM_GSBI12_PHYS + 0x20000)
+#define MSM_QUP_SIZE		SZ_4K
+
+#define MSM_PMIC1_SSBI_CMD_PHYS	0x00500000
+#define MSM_PMIC2_SSBI_CMD_PHYS	0x00C00000
+#define MSM_PMIC_SSBI_SIZE	SZ_4K
+
+#define MSM8960_HSUSB_PHYS		0x12500000
+#define MSM8960_HSUSB_SIZE		SZ_4K
+
+static struct resource resources_otg[] = {
+	{
+		.start	= MSM8960_HSUSB_PHYS,
+		.end	= MSM8960_HSUSB_PHYS + MSM8960_HSUSB_SIZE,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= USB1_HS_IRQ,
+		.end	= USB1_HS_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8960_device_otg = {
+	.name		= "msm_otg",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_otg),
+	.resource	= resources_otg,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+static struct resource resources_hsusb[] = {
+	{
+		.start	= MSM8960_HSUSB_PHYS,
+		.end	= MSM8960_HSUSB_PHYS + MSM8960_HSUSB_SIZE,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= USB1_HS_IRQ,
+		.end	= USB1_HS_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8960_device_gadget_peripheral = {
+	.name		= "msm_hsusb",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_hsusb),
+	.resource	= resources_hsusb,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+static struct resource resources_hsusb_host[] = {
+	{
+		.start  = MSM8960_HSUSB_PHYS,
+		.end    = MSM8960_HSUSB_PHYS + MSM8960_HSUSB_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = USB1_HS_IRQ,
+		.end    = USB1_HS_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static u64 dma_mask = DMA_BIT_MASK(32);
+struct platform_device msm_device_hsusb_host = {
+	.name           = "msm_hsusb_host",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(resources_hsusb_host),
+	.resource       = resources_hsusb_host,
+	.dev            = {
+		.dma_mask               = &dma_mask,
+		.coherent_dma_mask      = 0xffffffff,
+	},
+};
+
+static struct resource resources_hsic_host[] = {
+	{
+		.start	= 0x12520000,
+		.end	= 0x12520000 + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= USB_HSIC_IRQ,
+		.end	= USB_HSIC_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM_GPIO_TO_INT(69),
+		.end	= MSM_GPIO_TO_INT(69),
+		.name	= "peripheral_status_irq",
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_hsic_host = {
+	.name		= "msm_hsic_host",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_hsic_host),
+	.resource	= resources_hsic_host,
+	.dev		= {
+		.dma_mask		= &dma_mask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+};
+
+#define SHARED_IMEM_TZ_BASE 0x2a03f720
+static struct resource tzlog_resources[] = {
+	{
+		.start = SHARED_IMEM_TZ_BASE,
+		.end = SHARED_IMEM_TZ_BASE + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_device_tz_log = {
+	.name		= "tz_log",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(tzlog_resources),
+	.resource	= tzlog_resources,
+};
+
+static struct resource resources_uart_gsbi2[] = {
+	{
+		.start	= MSM8960_GSBI2_UARTDM_IRQ,
+		.end	= MSM8960_GSBI2_UARTDM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM_UART2DM_PHYS,
+		.end	= MSM_UART2DM_PHYS + PAGE_SIZE - 1,
+		.name	= "uartdm_resource",
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= MSM_GSBI2_PHYS,
+		.end	= MSM_GSBI2_PHYS + PAGE_SIZE - 1,
+		.name	= "gsbi_resource",
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm8960_device_uart_gsbi2 = {
+	.name	= "msm_serial_hsl",
+	.id	= 0,
+	.num_resources	= ARRAY_SIZE(resources_uart_gsbi2),
+	.resource	= resources_uart_gsbi2,
+};
+/* GSBI 6 used into UARTDM Mode */
+static struct resource msm_uart_dm6_resources[] = {
+	{
+		.start	= MSM_UART6DM_PHYS,
+		.end	= MSM_UART6DM_PHYS + PAGE_SIZE - 1,
+		.name	= "uartdm_resource",
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= GSBI6_UARTDM_IRQ,
+		.end	= GSBI6_UARTDM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM_GSBI6_PHYS,
+		.end	= MSM_GSBI6_PHYS + 4 - 1,
+		.name	= "gsbi_resource",
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= DMOV_HSUART_GSBI6_TX_CHAN,
+		.end	= DMOV_HSUART_GSBI6_RX_CHAN,
+		.name	= "uartdm_channels",
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.start	= DMOV_HSUART_GSBI6_TX_CRCI,
+		.end	= DMOV_HSUART_GSBI6_RX_CRCI,
+		.name	= "uartdm_crci",
+		.flags	= IORESOURCE_DMA,
+	},
+};
+static u64 msm_uart_dm6_dma_mask = DMA_BIT_MASK(32);
+struct platform_device msm_device_uart_dm6 = {
+	.name	= "msm_serial_hs",
+	.id	= 0,
+	.num_resources	= ARRAY_SIZE(msm_uart_dm6_resources),
+	.resource	= msm_uart_dm6_resources,
+	.dev	= {
+		.dma_mask		= &msm_uart_dm6_dma_mask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+};
+/*
+ * GSBI 9 used into UARTDM Mode
+ * For 8960 Fusion 2.2 Primary IPC
+ */
+static struct resource msm_uart_dm9_resources[] = {
+	{
+		.start	= MSM_UART9DM_PHYS,
+		.end	= MSM_UART9DM_PHYS + PAGE_SIZE - 1,
+		.name	= "uartdm_resource",
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= GSBI9_UARTDM_IRQ,
+		.end	= GSBI9_UARTDM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM_GSBI9_PHYS,
+		.end	= MSM_GSBI9_PHYS + 4 - 1,
+		.name	= "gsbi_resource",
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= DMOV_HSUART_GSBI9_TX_CHAN,
+		.end	= DMOV_HSUART_GSBI9_RX_CHAN,
+		.name	= "uartdm_channels",
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.start	= DMOV_HSUART_GSBI9_TX_CRCI,
+		.end	= DMOV_HSUART_GSBI9_RX_CRCI,
+		.name	= "uartdm_crci",
+		.flags	= IORESOURCE_DMA,
+	},
+};
+static u64 msm_uart_dm9_dma_mask = DMA_BIT_MASK(32);
+struct platform_device msm_device_uart_dm9 = {
+	.name	= "msm_serial_hs",
+	.id	= 1,
+	.num_resources	= ARRAY_SIZE(msm_uart_dm9_resources),
+	.resource	= msm_uart_dm9_resources,
+	.dev	= {
+		.dma_mask		= &msm_uart_dm9_dma_mask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+};
+
+static struct resource resources_uart_gsbi5[] = {
+	{
+		.start	= GSBI5_UARTDM_IRQ,
+		.end	= GSBI5_UARTDM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM_UART5DM_PHYS,
+		.end	= MSM_UART5DM_PHYS + PAGE_SIZE - 1,
+		.name	= "uartdm_resource",
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= MSM_GSBI5_PHYS,
+		.end	= MSM_GSBI5_PHYS + PAGE_SIZE - 1,
+		.name	= "gsbi_resource",
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm8960_device_uart_gsbi5 = {
+	.name	= "msm_serial_hsl",
+	.id	= 0,
+	.num_resources	= ARRAY_SIZE(resources_uart_gsbi5),
+	.resource	= resources_uart_gsbi5,
+};
+
+static struct msm_serial_hslite_platform_data uart_gsbi8_pdata = {
+	.line		= 0,
+};
+
+static struct resource resources_uart_gsbi8[] = {
+	{
+		.start	= GSBI8_UARTDM_IRQ,
+		.end	= GSBI8_UARTDM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM_UART8DM_PHYS,
+		.end	= MSM_UART8DM_PHYS + PAGE_SIZE - 1,
+		.name	= "uartdm_resource",
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= MSM_GSBI8_PHYS,
+		.end	= MSM_GSBI8_PHYS + PAGE_SIZE - 1,
+		.name	= "gsbi_resource",
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm8960_device_uart_gsbi8 = {
+	.name	= "msm_serial_hsl",
+	.id	= 1,
+	.num_resources	   = ARRAY_SIZE(resources_uart_gsbi8),
+	.resource	   = resources_uart_gsbi8,
+	.dev.platform_data = &uart_gsbi8_pdata,
+};
+
+/* MSM Video core device */
+#ifdef CONFIG_MSM_BUS_SCALING
+static struct msm_bus_vectors vidc_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+static struct msm_bus_vectors vidc_venc_vga_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 54525952,
+		.ib  = 436207616,
+	},
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 72351744,
+		.ib  = 289406976,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 500000,
+		.ib  = 1000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 500000,
+		.ib  = 1000000,
+	},
+};
+static struct msm_bus_vectors vidc_vdec_vga_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 40894464,
+		.ib  = 327155712,
+	},
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 48234496,
+		.ib  = 192937984,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 500000,
+		.ib  = 2000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 500000,
+		.ib  = 2000000,
+	},
+};
+static struct msm_bus_vectors vidc_venc_720p_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 163577856,
+		.ib  = 1308622848,
+	},
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 219152384,
+		.ib  = 876609536,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 1750000,
+		.ib  = 3500000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 1750000,
+		.ib  = 3500000,
+	},
+};
+static struct msm_bus_vectors vidc_vdec_720p_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 121634816,
+		.ib  = 973078528,
+	},
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 155189248,
+		.ib  = 620756992,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 1750000,
+		.ib  = 7000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 1750000,
+		.ib  = 7000000,
+	},
+};
+static struct msm_bus_vectors vidc_venc_1080p_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 372244480,
+		.ib  = 2560000000U,
+	},
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 501219328,
+		.ib  = 2560000000U,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 2500000,
+		.ib  = 5000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 2500000,
+		.ib  = 5000000,
+	},
+};
+static struct msm_bus_vectors vidc_vdec_1080p_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 222298112,
+		.ib  = 2560000000U,
+	},
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 330301440,
+		.ib  = 2560000000U,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 2500000,
+		.ib  = 700000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 2500000,
+		.ib  = 10000000,
+	},
+};
+
+static struct msm_bus_paths vidc_bus_client_config[] = {
+	{
+		ARRAY_SIZE(vidc_init_vectors),
+		vidc_init_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_venc_vga_vectors),
+		vidc_venc_vga_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_vdec_vga_vectors),
+		vidc_vdec_vga_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_venc_720p_vectors),
+		vidc_venc_720p_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_vdec_720p_vectors),
+		vidc_vdec_720p_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_venc_1080p_vectors),
+		vidc_venc_1080p_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_vdec_1080p_vectors),
+		vidc_vdec_1080p_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata vidc_bus_client_data = {
+	vidc_bus_client_config,
+	ARRAY_SIZE(vidc_bus_client_config),
+	.name = "vidc",
+};
+#endif
+
+#ifdef CONFIG_HW_RANDOM_MSM
+/* PRNG device */
+#define MSM_PRNG_PHYS		0x1A500000
+static struct resource rng_resources = {
+	.flags = IORESOURCE_MEM,
+	.start = MSM_PRNG_PHYS,
+	.end   = MSM_PRNG_PHYS + SZ_512 - 1,
+};
+
+struct platform_device msm_device_rng = {
+	.name          = "msm_rng",
+	.id            = 0,
+	.num_resources = 1,
+	.resource      = &rng_resources,
+};
+#endif
+
+#define MSM_VIDC_BASE_PHYS 0x04400000
+#define MSM_VIDC_BASE_SIZE 0x00100000
+
+static struct resource msm_device_vidc_resources[] = {
+	{
+		.start	= MSM_VIDC_BASE_PHYS,
+		.end	= MSM_VIDC_BASE_PHYS + MSM_VIDC_BASE_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= VCODEC_IRQ,
+		.end	= VCODEC_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct msm_vidc_platform_data vidc_platform_data = {
+#ifdef CONFIG_MSM_BUS_SCALING
+	.vidc_bus_client_pdata = &vidc_bus_client_data,
+#endif
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	.memtype = ION_CP_MM_HEAP_ID,
+	.enable_ion = 1,
+	.cp_enabled = 1,
+#else
+	.memtype = MEMTYPE_EBI1,
+	.enable_ion = 0,
+#endif
+	.disable_dmx = 0,
+	.disable_fullhd = 0,
+	.cont_mode_dpb_count = 18,
+};
+
+struct platform_device msm_device_vidc = {
+	.name = "msm_vidc",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(msm_device_vidc_resources),
+	.resource = msm_device_vidc_resources,
+	.dev = {
+		.platform_data	= &vidc_platform_data,
+	},
+};
+
+#define MSM_SDC1_BASE         0x12400000
+#define MSM_SDC1_DML_BASE     (MSM_SDC1_BASE + 0x800)
+#define MSM_SDC1_BAM_BASE     (MSM_SDC1_BASE + 0x2000)
+#define MSM_SDC2_BASE         0x12140000
+#define MSM_SDC2_DML_BASE     (MSM_SDC2_BASE + 0x800)
+#define MSM_SDC2_BAM_BASE     (MSM_SDC2_BASE + 0x2000)
+#define MSM_SDC3_BASE         0x12180000
+#define MSM_SDC3_DML_BASE     (MSM_SDC3_BASE + 0x800)
+#define MSM_SDC3_BAM_BASE     (MSM_SDC3_BASE + 0x2000)
+#define MSM_SDC4_BASE         0x121C0000
+#define MSM_SDC4_DML_BASE     (MSM_SDC4_BASE + 0x800)
+#define MSM_SDC4_BAM_BASE     (MSM_SDC4_BASE + 0x2000)
+#define MSM_SDC5_BASE         0x12200000
+#define MSM_SDC5_DML_BASE     (MSM_SDC5_BASE + 0x800)
+#define MSM_SDC5_BAM_BASE     (MSM_SDC5_BASE + 0x2000)
+
+static struct resource resources_sdc1[] = {
+	{
+		.name	= "core_mem",
+		.flags	= IORESOURCE_MEM,
+		.start	= MSM_SDC1_BASE,
+		.end	= MSM_SDC1_DML_BASE - 1,
+	},
+	{
+		.name	= "core_irq",
+		.flags	= IORESOURCE_IRQ,
+		.start	= SDC1_IRQ_0,
+		.end	= SDC1_IRQ_0
+	},
+#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
+	{
+		.name   = "sdcc_dml_addr",
+		.start	= MSM_SDC1_DML_BASE,
+		.end	= MSM_SDC1_BAM_BASE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_addr",
+		.start	= MSM_SDC1_BAM_BASE,
+		.end	= MSM_SDC1_BAM_BASE + (2 * SZ_4K) - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_irq",
+		.start	= SDC1_BAM_IRQ,
+		.end	= SDC1_BAM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+#endif
+};
+
+static struct resource resources_sdc2[] = {
+	{
+		.name	= "core_mem",
+		.flags	= IORESOURCE_MEM,
+		.start	= MSM_SDC2_BASE,
+		.end	= MSM_SDC2_DML_BASE - 1,
+	},
+	{
+		.name	= "core_irq",
+		.flags	= IORESOURCE_IRQ,
+		.start	= SDC2_IRQ_0,
+		.end	= SDC2_IRQ_0
+	},
+#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
+	{
+		.name   = "sdcc_dml_addr",
+		.start	= MSM_SDC2_DML_BASE,
+		.end	= MSM_SDC2_BAM_BASE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_addr",
+		.start	= MSM_SDC2_BAM_BASE,
+		.end	= MSM_SDC2_BAM_BASE + (2 * SZ_4K) - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_irq",
+		.start	= SDC2_BAM_IRQ,
+		.end	= SDC2_BAM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+#endif
+};
+
+static struct resource resources_sdc3[] = {
+	{
+		.name	= "core_mem",
+		.flags	= IORESOURCE_MEM,
+		.start	= MSM_SDC3_BASE,
+		.end	= MSM_SDC3_DML_BASE - 1,
+	},
+	{
+		.name	= "core_irq",
+		.flags	= IORESOURCE_IRQ,
+		.start	= SDC3_IRQ_0,
+		.end	= SDC3_IRQ_0
+	},
+#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
+	{
+		.name   = "sdcc_dml_addr",
+		.start	= MSM_SDC3_DML_BASE,
+		.end	= MSM_SDC3_BAM_BASE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_addr",
+		.start	= MSM_SDC3_BAM_BASE,
+		.end	= MSM_SDC3_BAM_BASE + (2 * SZ_4K) - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_irq",
+		.start	= SDC3_BAM_IRQ,
+		.end	= SDC3_BAM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+#endif
+};
+
+static struct resource resources_sdc4[] = {
+	{
+		.name	= "core_mem",
+		.flags	= IORESOURCE_MEM,
+		.start	= MSM_SDC4_BASE,
+		.end	= MSM_SDC4_DML_BASE - 1,
+	},
+	{
+		.name	= "core_irq",
+		.flags	= IORESOURCE_IRQ,
+		.start	= SDC4_IRQ_0,
+		.end	= SDC4_IRQ_0
+	},
+#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
+	{
+		.name   = "sdcc_dml_addr",
+		.start	= MSM_SDC4_DML_BASE,
+		.end	= MSM_SDC4_BAM_BASE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_addr",
+		.start	= MSM_SDC4_BAM_BASE,
+		.end	= MSM_SDC4_BAM_BASE + (2 * SZ_4K) - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_irq",
+		.start	= SDC4_BAM_IRQ,
+		.end	= SDC4_BAM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+#endif
+};
+
+static struct resource resources_sdc5[] = {
+	{
+		.name	= "core_mem",
+		.flags	= IORESOURCE_MEM,
+		.start	= MSM_SDC5_BASE,
+		.end	= MSM_SDC5_DML_BASE - 1,
+	},
+	{
+		.name	= "core_irq",
+		.flags	= IORESOURCE_IRQ,
+		.start	= SDC5_IRQ_0,
+		.end	= SDC5_IRQ_0
+	},
+#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
+	{
+		.name   = "sdcc_dml_addr",
+		.start	= MSM_SDC5_DML_BASE,
+		.end	= MSM_SDC5_BAM_BASE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_addr",
+		.start	= MSM_SDC5_BAM_BASE,
+		.end	= MSM_SDC5_BAM_BASE + (2 * SZ_4K) - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_irq",
+		.start	= SDC5_BAM_IRQ,
+		.end	= SDC5_BAM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+#endif
+};
+
+struct platform_device msm_device_sdc1 = {
+	.name		= "msm_sdcc",
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(resources_sdc1),
+	.resource	= resources_sdc1,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_sdc2 = {
+	.name		= "msm_sdcc",
+	.id		= 2,
+	.num_resources	= ARRAY_SIZE(resources_sdc2),
+	.resource	= resources_sdc2,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_sdc3 = {
+	.name		= "msm_sdcc",
+	.id		= 3,
+	.num_resources	= ARRAY_SIZE(resources_sdc3),
+	.resource	= resources_sdc3,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_sdc4 = {
+	.name		= "msm_sdcc",
+	.id		= 4,
+	.num_resources	= ARRAY_SIZE(resources_sdc4),
+	.resource	= resources_sdc4,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_sdc5 = {
+	.name		= "msm_sdcc",
+	.id		= 5,
+	.num_resources	= ARRAY_SIZE(resources_sdc5),
+	.resource	= resources_sdc5,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+#define MSM_LPASS_QDSP6SS_PHYS	0x28800000
+#define SFAB_LPASS_Q6_ACLK_CTL	(MSM_CLK_CTL_BASE + 0x23A0)
+
+static struct resource msm_8960_q6_lpass_resources[] = {
+	{
+		.start  = MSM_LPASS_QDSP6SS_PHYS,
+		.end    = MSM_LPASS_QDSP6SS_PHYS + SZ_256 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+static struct pil_q6v4_pdata msm_8960_q6_lpass_data = {
+	.strap_tcm_base  = 0x01460000,
+	.strap_ahb_upper = 0x00290000,
+	.strap_ahb_lower = 0x00000280,
+	.aclk_reg = SFAB_LPASS_Q6_ACLK_CTL,
+	.name = "q6",
+	.pas_id = PAS_Q6,
+	.bus_port = MSM_BUS_MASTER_LPASS_PROC,
+};
+
+struct platform_device msm_8960_q6_lpass = {
+	.name = "pil_qdsp6v4",
+	.id = 0,
+	.num_resources  = ARRAY_SIZE(msm_8960_q6_lpass_resources),
+	.resource       = msm_8960_q6_lpass_resources,
+	.dev.platform_data = &msm_8960_q6_lpass_data,
+};
+
+#define MSM_MSS_ENABLE_PHYS	0x08B00000
+#define MSM_FW_QDSP6SS_PHYS	0x08800000
+#define MSS_Q6FW_JTAG_CLK_CTL	(MSM_CLK_CTL_BASE + 0x2C6C)
+#define SFAB_MSS_Q6_FW_ACLK_CTL (MSM_CLK_CTL_BASE + 0x2044)
+
+static struct resource msm_8960_q6_mss_fw_resources[] = {
+	{
+		.start  = MSM_FW_QDSP6SS_PHYS,
+		.end    = MSM_FW_QDSP6SS_PHYS + SZ_256 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = MSM_MSS_ENABLE_PHYS,
+		.end    = MSM_MSS_ENABLE_PHYS + 4 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+static struct pil_q6v4_pdata msm_8960_q6_mss_fw_data = {
+	.strap_tcm_base  = 0x00400000,
+	.strap_ahb_upper = 0x00090000,
+	.strap_ahb_lower = 0x00000080,
+	.aclk_reg = SFAB_MSS_Q6_FW_ACLK_CTL,
+	.jtag_clk_reg = MSS_Q6FW_JTAG_CLK_CTL,
+	.name = "modem_fw",
+	.depends = "q6",
+	.pas_id = PAS_MODEM_FW,
+	.bus_port = MSM_BUS_MASTER_MSS_FW_PROC,
+};
+
+struct platform_device msm_8960_q6_mss_fw = {
+	.name = "pil_qdsp6v4",
+	.id = 1,
+	.num_resources  = ARRAY_SIZE(msm_8960_q6_mss_fw_resources),
+	.resource       = msm_8960_q6_mss_fw_resources,
+	.dev.platform_data = &msm_8960_q6_mss_fw_data,
+};
+
+#define MSM_SW_QDSP6SS_PHYS	0x08900000
+#define SFAB_MSS_Q6_SW_ACLK_CTL	(MSM_CLK_CTL_BASE + 0x2040)
+#define MSS_Q6SW_JTAG_CLK_CTL	(MSM_CLK_CTL_BASE + 0x2C68)
+
+static struct resource msm_8960_q6_mss_sw_resources[] = {
+	{
+		.start  = MSM_SW_QDSP6SS_PHYS,
+		.end    = MSM_SW_QDSP6SS_PHYS + SZ_256 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = MSM_MSS_ENABLE_PHYS,
+		.end    = MSM_MSS_ENABLE_PHYS + 4 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+static struct pil_q6v4_pdata msm_8960_q6_mss_sw_data = {
+	.strap_tcm_base  = 0x00420000,
+	.strap_ahb_upper = 0x00090000,
+	.strap_ahb_lower = 0x00000080,
+	.aclk_reg = SFAB_MSS_Q6_SW_ACLK_CTL,
+	.jtag_clk_reg = MSS_Q6SW_JTAG_CLK_CTL,
+	.name = "modem",
+	.depends = "modem_fw",
+	.pas_id = PAS_MODEM_SW,
+	.bus_port = MSM_BUS_MASTER_MSS_SW_PROC,
+};
+
+struct platform_device msm_8960_q6_mss_sw = {
+	.name = "pil_qdsp6v4",
+	.id = 2,
+	.num_resources  = ARRAY_SIZE(msm_8960_q6_mss_sw_resources),
+	.resource       = msm_8960_q6_mss_sw_resources,
+	.dev.platform_data = &msm_8960_q6_mss_sw_data,
+};
+
+static struct resource msm_8960_riva_resources[] = {
+	{
+		.start  = 0x03204000,
+		.end    = 0x03204000 + SZ_256 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_8960_riva = {
+	.name = "pil_riva",
+	.id = -1,
+	.num_resources  = ARRAY_SIZE(msm_8960_riva_resources),
+	.resource       = msm_8960_riva_resources,
+};
+
+struct platform_device msm_pil_tzapps = {
+	.name = "pil_tzapps",
+	.id = -1,
+};
+
+struct platform_device msm_pil_dsps = {
+	.name          = "pil_dsps",
+	.id            = -1,
+	.dev.platform_data = "dsps",
+};
+
+struct platform_device msm_pil_vidc = {
+	.name = "pil_vidc",
+	.id = -1,
+};
+
+static struct resource smd_resource[] = {
+	{
+		.name   = "a9_m2a_0",
+		.start  = INT_A9_M2A_0,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "a9_m2a_5",
+		.start  = INT_A9_M2A_5,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "adsp_a11",
+		.start  = INT_ADSP_A11,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "adsp_a11_smsm",
+		.start  = INT_ADSP_A11_SMSM,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "dsps_a11",
+		.start  = INT_DSPS_A11,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "dsps_a11_smsm",
+		.start  = INT_DSPS_A11_SMSM,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "wcnss_a11",
+		.start  = INT_WCNSS_A11,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "wcnss_a11_smsm",
+		.start  = INT_WCNSS_A11_SMSM,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct smd_subsystem_config smd_config_list[] = {
+	{
+		.irq_config_id = SMD_MODEM,
+		.subsys_name = "modem",
+		.edge = SMD_APPS_MODEM,
+
+		.smd_int.irq_name = "a9_m2a_0",
+		.smd_int.flags = IRQF_TRIGGER_RISING,
+		.smd_int.irq_id = -1,
+		.smd_int.device_name = "smd_dev",
+		.smd_int.dev_id = 0,
+		.smd_int.out_bit_pos =  1 << 3,
+		.smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smd_int.out_offset = 0x8,
+
+		.smsm_int.irq_name = "a9_m2a_5",
+		.smsm_int.flags = IRQF_TRIGGER_RISING,
+		.smsm_int.irq_id = -1,
+		.smsm_int.device_name = "smd_smsm",
+		.smsm_int.dev_id = 0,
+		.smsm_int.out_bit_pos =  1 << 4,
+		.smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smsm_int.out_offset = 0x8,
+	},
+	{
+		.irq_config_id = SMD_Q6,
+		.subsys_name = "q6",
+		.edge = SMD_APPS_QDSP,
+
+		.smd_int.irq_name = "adsp_a11",
+		.smd_int.flags = IRQF_TRIGGER_RISING,
+		.smd_int.irq_id = -1,
+		.smd_int.device_name = "smd_dev",
+		.smd_int.dev_id = 0,
+		.smd_int.out_bit_pos =  1 << 15,
+		.smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smd_int.out_offset = 0x8,
+
+		.smsm_int.irq_name = "adsp_a11_smsm",
+		.smsm_int.flags = IRQF_TRIGGER_RISING,
+		.smsm_int.irq_id = -1,
+		.smsm_int.device_name = "smd_smsm",
+		.smsm_int.dev_id = 0,
+		.smsm_int.out_bit_pos =  1 << 14,
+		.smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smsm_int.out_offset = 0x8,
+	},
+	{
+		.irq_config_id = SMD_DSPS,
+		.subsys_name = "dsps",
+		.edge = SMD_APPS_DSPS,
+
+		.smd_int.irq_name = "dsps_a11",
+		.smd_int.flags = IRQF_TRIGGER_RISING,
+		.smd_int.irq_id = -1,
+		.smd_int.device_name = "smd_dev",
+		.smd_int.dev_id = 0,
+		.smd_int.out_bit_pos =  1,
+		.smd_int.out_base = (void __iomem *)MSM_SIC_NON_SECURE_BASE,
+		.smd_int.out_offset = 0x4080,
+
+		.smsm_int.irq_name = "dsps_a11_smsm",
+		.smsm_int.flags = IRQF_TRIGGER_RISING,
+		.smsm_int.irq_id = -1,
+		.smsm_int.device_name = "smd_smsm",
+		.smsm_int.dev_id = 0,
+		.smsm_int.out_bit_pos =  1,
+		.smsm_int.out_base = (void __iomem *)MSM_SIC_NON_SECURE_BASE,
+		.smsm_int.out_offset = 0x4094,
+	},
+	{
+		.irq_config_id = SMD_WCNSS,
+		.subsys_name = "wcnss",
+		.edge = SMD_APPS_WCNSS,
+
+		.smd_int.irq_name = "wcnss_a11",
+		.smd_int.flags = IRQF_TRIGGER_RISING,
+		.smd_int.irq_id = -1,
+		.smd_int.device_name = "smd_dev",
+		.smd_int.dev_id = 0,
+		.smd_int.out_bit_pos =  1 << 25,
+		.smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smd_int.out_offset = 0x8,
+
+		.smsm_int.irq_name = "wcnss_a11_smsm",
+		.smsm_int.flags = IRQF_TRIGGER_RISING,
+		.smsm_int.irq_id = -1,
+		.smsm_int.device_name = "smd_smsm",
+		.smsm_int.dev_id = 0,
+		.smsm_int.out_bit_pos =  1 << 23,
+		.smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smsm_int.out_offset = 0x8,
+	},
+};
+
+static struct smd_subsystem_restart_config smd_ssr_config = {
+	.disable_smsm_reset_handshake = 1,
+};
+
+static struct smd_platform smd_platform_data = {
+	.num_ss_configs = ARRAY_SIZE(smd_config_list),
+	.smd_ss_configs = smd_config_list,
+	.smd_ssr_config = &smd_ssr_config,
+};
+
+struct platform_device msm_device_smd = {
+	.name		= "msm_smd",
+	.id		= -1,
+	.resource = smd_resource,
+	.num_resources = ARRAY_SIZE(smd_resource),
+	.dev = {
+		.platform_data = &smd_platform_data,
+	},
+};
+
+struct platform_device msm_device_bam_dmux = {
+	.name		= "BAM_RMNT",
+	.id		= -1,
+};
+
+static struct msm_watchdog_pdata msm_watchdog_pdata = {
+	.pet_time = 10000,
+	.bark_time = 11000,
+	.has_secure = true,
+};
+
+struct platform_device msm8960_device_watchdog = {
+	.name = "msm_watchdog",
+	.id = -1,
+	.dev = {
+		.platform_data = &msm_watchdog_pdata,
+	},
+};
+
+static struct resource msm_dmov_resource[] = {
+	{
+		.start = ADM_0_SCSS_1_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = 0x18320000,
+		.end = 0x18320000 + SZ_1M - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct msm_dmov_pdata msm_dmov_pdata = {
+	.sd = 1,
+	.sd_size = 0x800,
+};
+
+struct platform_device msm8960_device_dmov = {
+	.name	= "msm_dmov",
+	.id	= -1,
+	.resource = msm_dmov_resource,
+	.num_resources = ARRAY_SIZE(msm_dmov_resource),
+	.dev = {
+		.platform_data = &msm_dmov_pdata,
+	},
+};
+
+static struct platform_device *msm_sdcc_devices[] __initdata = {
+	&msm_device_sdc1,
+	&msm_device_sdc2,
+	&msm_device_sdc3,
+	&msm_device_sdc4,
+	&msm_device_sdc5,
+};
+
+int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat)
+{
+	struct platform_device	*pdev;
+
+	if (controller < 1 || controller > 5)
+		return -EINVAL;
+
+	pdev = msm_sdcc_devices[controller-1];
+	pdev->dev.platform_data = plat;
+	return platform_device_register(pdev);
+}
+
+static struct resource resources_qup_i2c_gsbi4[] = {
+	{
+		.name	= "gsbi_qup_i2c_addr",
+		.start	= MSM_GSBI4_PHYS,
+		.end	= MSM_GSBI4_PHYS + 4 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_phys_addr",
+		.start	= MSM_GSBI4_QUP_PHYS,
+		.end	= MSM_GSBI4_QUP_PHYS + MSM_QUP_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_err_intr",
+		.start	= GSBI4_QUP_IRQ,
+		.end	= GSBI4_QUP_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8960_device_qup_i2c_gsbi4 = {
+	.name		= "qup_i2c",
+	.id		= 4,
+	.num_resources	= ARRAY_SIZE(resources_qup_i2c_gsbi4),
+	.resource	= resources_qup_i2c_gsbi4,
+};
+
+static struct resource resources_qup_i2c_gsbi3[] = {
+	{
+		.name	= "gsbi_qup_i2c_addr",
+		.start	= MSM_GSBI3_PHYS,
+		.end	= MSM_GSBI3_PHYS + 4 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_phys_addr",
+		.start	= MSM_GSBI3_QUP_PHYS,
+		.end	= MSM_GSBI3_QUP_PHYS + MSM_QUP_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_err_intr",
+		.start	= GSBI3_QUP_IRQ,
+		.end	= GSBI3_QUP_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8960_device_qup_i2c_gsbi3 = {
+	.name		= "qup_i2c",
+	.id		= 3,
+	.num_resources	= ARRAY_SIZE(resources_qup_i2c_gsbi3),
+	.resource	= resources_qup_i2c_gsbi3,
+};
+
+static struct resource resources_qup_i2c_gsbi9[] = {
+	{
+		.name	= "gsbi_qup_i2c_addr",
+		.start	= MSM_GSBI9_PHYS,
+		.end	= MSM_GSBI9_PHYS + 4 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_phys_addr",
+		.start	= MSM_GSBI9_QUP_PHYS,
+		.end	= MSM_GSBI9_QUP_PHYS + MSM_QUP_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_err_intr",
+		.start	= GSBI9_QUP_IRQ,
+		.end	= GSBI9_QUP_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8960_device_qup_i2c_gsbi9 = {
+	.name		= "qup_i2c",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(resources_qup_i2c_gsbi9),
+	.resource	= resources_qup_i2c_gsbi9,
+};
+
+static struct resource resources_qup_i2c_gsbi10[] = {
+	{
+		.name	= "gsbi_qup_i2c_addr",
+		.start	= MSM_GSBI10_PHYS,
+		.end	= MSM_GSBI10_PHYS + 4 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_phys_addr",
+		.start	= MSM_GSBI10_QUP_PHYS,
+		.end	= MSM_GSBI10_QUP_PHYS + MSM_QUP_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_err_intr",
+		.start	= GSBI10_QUP_IRQ,
+		.end	= GSBI10_QUP_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8960_device_qup_i2c_gsbi10 = {
+	.name		= "qup_i2c",
+	.id		= 10,
+	.num_resources	= ARRAY_SIZE(resources_qup_i2c_gsbi10),
+	.resource	= resources_qup_i2c_gsbi10,
+};
+
+static struct resource resources_qup_i2c_gsbi12[] = {
+	{
+		.name	= "gsbi_qup_i2c_addr",
+		.start	= MSM_GSBI12_PHYS,
+		.end	= MSM_GSBI12_PHYS + 4 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_phys_addr",
+		.start	= MSM_GSBI12_QUP_PHYS,
+		.end	= MSM_GSBI12_QUP_PHYS + MSM_QUP_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_err_intr",
+		.start	= GSBI12_QUP_IRQ,
+		.end	= GSBI12_QUP_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8960_device_qup_i2c_gsbi12 = {
+	.name		= "qup_i2c",
+	.id		= 12,
+	.num_resources	= ARRAY_SIZE(resources_qup_i2c_gsbi12),
+	.resource	= resources_qup_i2c_gsbi12,
+};
+
+#ifdef CONFIG_MSM_CAMERA
+static struct resource msm_cam_gsbi4_i2c_mux_resources[] = {
+	{
+		.name   = "i2c_mux_rw",
+		.start  = 0x008003E0,
+		.end    = 0x008003E0 + SZ_8 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "i2c_mux_ctl",
+		.start  = 0x008020B8,
+		.end    = 0x008020B8 + SZ_4 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm8960_device_i2c_mux_gsbi4 = {
+	.name           = "msm_cam_i2c_mux",
+	.id             = 0,
+	.resource       = msm_cam_gsbi4_i2c_mux_resources,
+	.num_resources  = ARRAY_SIZE(msm_cam_gsbi4_i2c_mux_resources),
+};
+
+static struct resource msm_csiphy0_resources[] = {
+	{
+		.name	= "csiphy",
+		.start	= 0x04800C00,
+		.end	= 0x04800C00 + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "csiphy",
+		.start	= CSIPHY_4LN_IRQ,
+		.end	= CSIPHY_4LN_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct resource msm_csiphy1_resources[] = {
+	{
+		.name	= "csiphy",
+		.start	= 0x04801000,
+		.end	= 0x04801000 + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "csiphy",
+		.start	= MSM8960_CSIPHY_2LN_IRQ,
+		.end	= MSM8960_CSIPHY_2LN_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct resource msm_csiphy2_resources[] = {
+	{
+		.name	= "csiphy",
+		.start	= 0x04801400,
+		.end	= 0x04801400 + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "csiphy",
+		.start	= MSM8960_CSIPHY_2_2LN_IRQ,
+		.end	= MSM8960_CSIPHY_2_2LN_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8960_device_csiphy0 = {
+	.name           = "msm_csiphy",
+	.id             = 0,
+	.resource       = msm_csiphy0_resources,
+	.num_resources  = ARRAY_SIZE(msm_csiphy0_resources),
+};
+
+struct platform_device msm8960_device_csiphy1 = {
+	.name           = "msm_csiphy",
+	.id             = 1,
+	.resource       = msm_csiphy1_resources,
+	.num_resources  = ARRAY_SIZE(msm_csiphy1_resources),
+};
+
+struct platform_device msm8960_device_csiphy2 = {
+	.name           = "msm_csiphy",
+	.id             = 2,
+	.resource       = msm_csiphy2_resources,
+	.num_resources  = ARRAY_SIZE(msm_csiphy2_resources),
+};
+
+static struct resource msm_csid0_resources[] = {
+	{
+		.name	= "csid",
+		.start	= 0x04800000,
+		.end	= 0x04800000 + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "csid",
+		.start	= CSI_0_IRQ,
+		.end	= CSI_0_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct resource msm_csid1_resources[] = {
+	{
+		.name	= "csid",
+		.start	= 0x04800400,
+		.end	= 0x04800400 + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "csid",
+		.start	= CSI_1_IRQ,
+		.end	= CSI_1_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct resource msm_csid2_resources[] = {
+	{
+		.name	= "csid",
+		.start	= 0x04801800,
+		.end	= 0x04801800 + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "csid",
+		.start	= CSI_2_IRQ,
+		.end	= CSI_2_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8960_device_csid0 = {
+	.name           = "msm_csid",
+	.id             = 0,
+	.resource       = msm_csid0_resources,
+	.num_resources  = ARRAY_SIZE(msm_csid0_resources),
+};
+
+struct platform_device msm8960_device_csid1 = {
+	.name           = "msm_csid",
+	.id             = 1,
+	.resource       = msm_csid1_resources,
+	.num_resources  = ARRAY_SIZE(msm_csid1_resources),
+};
+
+struct platform_device msm8960_device_csid2 = {
+	.name           = "msm_csid",
+	.id             = 2,
+	.resource       = msm_csid2_resources,
+	.num_resources  = ARRAY_SIZE(msm_csid2_resources),
+};
+
+struct resource msm_ispif_resources[] = {
+	{
+		.name	= "ispif",
+		.start	= 0x04800800,
+		.end	= 0x04800800 + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "ispif",
+		.start	= ISPIF_IRQ,
+		.end	= ISPIF_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8960_device_ispif = {
+	.name           = "msm_ispif",
+	.id             = 0,
+	.resource       = msm_ispif_resources,
+	.num_resources  = ARRAY_SIZE(msm_ispif_resources),
+};
+
+static struct resource msm_vfe_resources[] = {
+	{
+		.name	= "vfe32",
+		.start	= 0x04500000,
+		.end	= 0x04500000 + SZ_1M - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "vfe32",
+		.start	= VFE_IRQ,
+		.end	= VFE_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8960_device_vfe = {
+	.name           = "msm_vfe",
+	.id             = 0,
+	.resource       = msm_vfe_resources,
+	.num_resources  = ARRAY_SIZE(msm_vfe_resources),
+};
+
+static struct resource msm_vpe_resources[] = {
+	{
+		.name	= "vpe",
+		.start	= 0x05300000,
+		.end	= 0x05300000 + SZ_1M - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "vpe",
+		.start	= VPE_IRQ,
+		.end	= VPE_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8960_device_vpe = {
+	.name           = "msm_vpe",
+	.id             = 0,
+	.resource       = msm_vpe_resources,
+	.num_resources  = ARRAY_SIZE(msm_vpe_resources),
+};
+#endif
+
+#define MSM_TSIF0_PHYS       (0x18200000)
+#define MSM_TSIF1_PHYS       (0x18201000)
+#define MSM_TSIF_SIZE        (0x200)
+
+#define TSIF_0_CLK       GPIO_CFG(75, 1, GPIO_CFG_INPUT, \
+	GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_0_EN        GPIO_CFG(76, 1, GPIO_CFG_INPUT, \
+	GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_0_DATA      GPIO_CFG(77, 1, GPIO_CFG_INPUT, \
+	GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_0_SYNC      GPIO_CFG(82, 1, GPIO_CFG_INPUT, \
+	GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_1_CLK       GPIO_CFG(79, 1, GPIO_CFG_INPUT, \
+	GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_1_EN        GPIO_CFG(80, 1, GPIO_CFG_INPUT, \
+	GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_1_DATA      GPIO_CFG(81, 1, GPIO_CFG_INPUT, \
+	GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_1_SYNC      GPIO_CFG(78, 1, GPIO_CFG_INPUT, \
+	GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+
+static const struct msm_gpio tsif0_gpios[] = {
+	{ .gpio_cfg = TSIF_0_CLK,  .label =  "tsif_clk", },
+	{ .gpio_cfg = TSIF_0_EN,   .label =  "tsif_en", },
+	{ .gpio_cfg = TSIF_0_DATA, .label =  "tsif_data", },
+	{ .gpio_cfg = TSIF_0_SYNC, .label =  "tsif_sync", },
+};
+
+static const struct msm_gpio tsif1_gpios[] = {
+	{ .gpio_cfg = TSIF_1_CLK,  .label =  "tsif_clk", },
+	{ .gpio_cfg = TSIF_1_EN,   .label =  "tsif_en", },
+	{ .gpio_cfg = TSIF_1_DATA, .label =  "tsif_data", },
+	{ .gpio_cfg = TSIF_1_SYNC, .label =  "tsif_sync", },
+};
+
+struct msm_tsif_platform_data tsif1_platform_data = {
+	.num_gpios = ARRAY_SIZE(tsif1_gpios),
+	.gpios = tsif1_gpios,
+	.tsif_pclk = "tsif_pclk",
+	.tsif_ref_clk = "tsif_ref_clk",
+};
+
+struct resource tsif1_resources[] = {
+	[0] = {
+		.flags = IORESOURCE_IRQ,
+		.start = TSIF2_IRQ,
+		.end   = TSIF2_IRQ,
+	},
+	[1] = {
+		.flags = IORESOURCE_MEM,
+		.start = MSM_TSIF1_PHYS,
+		.end   = MSM_TSIF1_PHYS + MSM_TSIF_SIZE - 1,
+	},
+	[2] = {
+		.flags = IORESOURCE_DMA,
+		.start = DMOV_TSIF_CHAN,
+		.end   = DMOV_TSIF_CRCI,
+	},
+};
+
+struct msm_tsif_platform_data tsif0_platform_data = {
+	.num_gpios = ARRAY_SIZE(tsif0_gpios),
+	.gpios = tsif0_gpios,
+	.tsif_pclk = "tsif_pclk",
+	.tsif_ref_clk = "tsif_ref_clk",
+};
+struct resource tsif0_resources[] = {
+	[0] = {
+		.flags = IORESOURCE_IRQ,
+		.start = TSIF1_IRQ,
+		.end   = TSIF1_IRQ,
+	},
+	[1] = {
+		.flags = IORESOURCE_MEM,
+		.start = MSM_TSIF0_PHYS,
+		.end   = MSM_TSIF0_PHYS + MSM_TSIF_SIZE - 1,
+	},
+	[2] = {
+		.flags = IORESOURCE_DMA,
+		.start = DMOV_TSIF_CHAN,
+		.end   = DMOV_TSIF_CRCI,
+	},
+};
+
+struct platform_device msm_device_tsif[2] = {
+	{
+		.name          = "msm_tsif",
+		.id            = 0,
+		.num_resources = ARRAY_SIZE(tsif0_resources),
+		.resource      = tsif0_resources,
+		.dev = {
+			.platform_data = &tsif0_platform_data
+		},
+	},
+	{
+		.name          = "msm_tsif",
+		.id            = 1,
+		.num_resources = ARRAY_SIZE(tsif1_resources),
+		.resource      = tsif1_resources,
+		.dev = {
+			.platform_data = &tsif1_platform_data
+		},
+	}
+};
+
+static struct resource resources_ssbi_pmic[] = {
+	{
+		.start  = MSM_PMIC1_SSBI_CMD_PHYS,
+		.end    = MSM_PMIC1_SSBI_CMD_PHYS + MSM_PMIC_SSBI_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm8960_device_ssbi_pmic = {
+	.name           = "msm_ssbi",
+	.id             = 0,
+	.resource       = resources_ssbi_pmic,
+	.num_resources  = ARRAY_SIZE(resources_ssbi_pmic),
+};
+
+static struct resource resources_qup_spi_gsbi1[] = {
+	{
+		.name   = "spi_base",
+		.start  = MSM_GSBI1_QUP_PHYS,
+		.end    = MSM_GSBI1_QUP_PHYS + SZ_4K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "gsbi_base",
+		.start  = MSM_GSBI1_PHYS,
+		.end    = MSM_GSBI1_PHYS + 4 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "spi_irq_in",
+		.start  = MSM8960_GSBI1_QUP_IRQ,
+		.end    = MSM8960_GSBI1_QUP_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "spi_clk",
+		.start  = 9,
+		.end    = 9,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "spi_miso",
+		.start  = 7,
+		.end    = 7,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "spi_mosi",
+		.start  = 6,
+		.end    = 6,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "spi_cs",
+		.start  = 8,
+		.end    = 8,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "spi_cs1",
+		.start  = 14,
+		.end    = 14,
+		.flags  = IORESOURCE_IO,
+	},
+};
+
+struct platform_device msm8960_device_qup_spi_gsbi1 = {
+	.name	= "spi_qsd",
+	.id	= 0,
+	.num_resources	= ARRAY_SIZE(resources_qup_spi_gsbi1),
+	.resource	= resources_qup_spi_gsbi1,
+};
+
+struct platform_device msm_pcm = {
+	.name	= "msm-pcm-dsp",
+	.id	= -1,
+};
+
+struct platform_device msm_multi_ch_pcm = {
+	.name	= "msm-multi-ch-pcm-dsp",
+	.id	= -1,
+};
+
+struct platform_device msm_pcm_routing = {
+	.name	= "msm-pcm-routing",
+	.id	= -1,
+};
+
+struct platform_device msm_cpudai0 = {
+	.name	= "msm-dai-q6",
+	.id	= 0x4000,
+};
+
+struct platform_device msm_cpudai1 = {
+	.name	= "msm-dai-q6",
+	.id	= 0x4001,
+};
+
+struct platform_device msm8960_cpudai_slimbus_2_tx = {
+	.name = "msm-dai-q6",
+	.id = 0x4005,
+};
+
+struct platform_device msm_cpudai_hdmi_rx = {
+	.name	= "msm-dai-q6-hdmi",
+	.id	= 8,
+};
+
+struct platform_device msm_cpudai_bt_rx = {
+	.name   = "msm-dai-q6",
+	.id     = 0x3000,
+};
+
+struct platform_device msm_cpudai_bt_tx = {
+	.name   = "msm-dai-q6",
+	.id     = 0x3001,
+};
+
+struct platform_device msm_cpudai_fm_rx = {
+	.name   = "msm-dai-q6",
+	.id     = 0x3004,
+};
+
+struct platform_device msm_cpudai_fm_tx = {
+	.name   = "msm-dai-q6",
+	.id     = 0x3005,
+};
+
+struct platform_device msm_cpudai_incall_music_rx = {
+	.name   = "msm-dai-q6",
+	.id     = 0x8005,
+};
+
+struct platform_device msm_cpudai_incall_record_rx = {
+	.name   = "msm-dai-q6",
+	.id     = 0x8004,
+};
+
+struct platform_device msm_cpudai_incall_record_tx = {
+	.name   = "msm-dai-q6",
+	.id     = 0x8003,
+};
+
+/*
+ * Machine specific data for AUX PCM Interface
+ * which the driver will  be unware of.
+ */
+struct msm_dai_auxpcm_pdata auxpcm_pdata = {
+	.clk = "pcm_clk",
+	.mode_8k = {
+		.mode = AFE_PCM_CFG_MODE_PCM,
+		.sync = AFE_PCM_CFG_SYNC_INT,
+		.frame = AFE_PCM_CFG_FRM_256BPF,
+		.quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
+		.slot = 0,
+		.data = AFE_PCM_CFG_CDATAOE_MASTER,
+		.pcm_clk_rate = 2048000,
+	},
+	.mode_16k = {
+		.mode = AFE_PCM_CFG_MODE_PCM,
+		.sync = AFE_PCM_CFG_SYNC_INT,
+		.frame = AFE_PCM_CFG_FRM_256BPF,
+		.quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
+		.slot = 0,
+		.data = AFE_PCM_CFG_CDATAOE_MASTER,
+		.pcm_clk_rate = 4096000,
+	}
+};
+
+struct platform_device msm_cpudai_auxpcm_rx = {
+	.name = "msm-dai-q6",
+	.id = 2,
+	.dev = {
+		.platform_data = &auxpcm_pdata,
+	},
+};
+
+struct platform_device msm_cpudai_auxpcm_tx = {
+	.name = "msm-dai-q6",
+	.id = 3,
+	.dev = {
+		.platform_data = &auxpcm_pdata,
+	},
+};
+
+struct platform_device msm_cpu_fe = {
+	.name	= "msm-dai-fe",
+	.id	= -1,
+};
+
+struct platform_device msm_stub_codec = {
+	.name	= "msm-stub-codec",
+	.id	= 1,
+};
+
+struct platform_device msm_voice = {
+	.name	= "msm-pcm-voice",
+	.id	= -1,
+};
+
+struct platform_device msm_voip = {
+	.name	= "msm-voip-dsp",
+	.id	= -1,
+};
+
+struct platform_device msm_lpa_pcm = {
+	.name   = "msm-pcm-lpa",
+	.id     = -1,
+};
+
+struct platform_device msm_compr_dsp = {
+	.name	= "msm-compr-dsp",
+	.id	= -1,
+};
+
+struct platform_device msm_pcm_hostless = {
+	.name	= "msm-pcm-hostless",
+	.id	= -1,
+};
+
+struct platform_device msm_cpudai_afe_01_rx = {
+	.name = "msm-dai-q6",
+	.id = 0xE0,
+};
+
+struct platform_device msm_cpudai_afe_01_tx = {
+	.name = "msm-dai-q6",
+	.id = 0xF0,
+};
+
+struct platform_device msm_cpudai_afe_02_rx = {
+	.name = "msm-dai-q6",
+	.id = 0xF1,
+};
+
+struct platform_device msm_cpudai_afe_02_tx = {
+	.name = "msm-dai-q6",
+	.id = 0xE1,
+};
+
+struct platform_device msm_pcm_afe = {
+	.name	= "msm-pcm-afe",
+	.id	= -1,
+};
+
+static struct fs_driver_data gfx2d0_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_GRAPHICS_2D_CORE0,
+};
+
+static struct fs_driver_data gfx2d1_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_GRAPHICS_2D_CORE1,
+};
+
+static struct fs_driver_data gfx3d_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk", .reset_rate = 27000000 },
+		{ .name = "iface_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_GRAPHICS_3D,
+};
+
+static struct fs_driver_data ijpeg_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_JPEG_ENC,
+};
+
+static struct fs_driver_data mdp_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ .name = "vsync_clk" },
+		{ .name = "lut_clk" },
+		{ .name = "tv_src_clk" },
+		{ .name = "tv_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_MDP_PORT0,
+	.bus_port1 = MSM_BUS_MASTER_MDP_PORT1,
+};
+
+static struct fs_driver_data rot_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_ROTATOR,
+};
+
+static struct fs_driver_data ved_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_HD_CODEC_PORT0,
+	.bus_port1 = MSM_BUS_MASTER_HD_CODEC_PORT1,
+};
+
+static struct fs_driver_data vfe_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_VFE,
+};
+
+static struct fs_driver_data vpe_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_VPE,
+};
+
+struct platform_device *msm8960_footswitch[] __initdata = {
+	FS_8X60(FS_MDP,    "vdd",	"mdp.0",	&mdp_fs_data),
+	FS_8X60(FS_ROT,    "vdd",	"msm_rotator.0", &rot_fs_data),
+	FS_8X60(FS_IJPEG,  "vdd",	"msm_gemini.0",	&ijpeg_fs_data),
+	FS_8X60(FS_VFE,    "fs_vfe",	NULL,	&vfe_fs_data),
+	FS_8X60(FS_VPE,    "fs_vpe",	NULL,	&vpe_fs_data),
+	FS_8X60(FS_GFX3D,  "vdd",	"kgsl-3d0.0",	&gfx3d_fs_data),
+	FS_8X60(FS_GFX2D0, "vdd",	"kgsl-2d0.0",	&gfx2d0_fs_data),
+	FS_8X60(FS_GFX2D1, "vdd",	"kgsl-2d1.1",	&gfx2d1_fs_data),
+	FS_8X60(FS_VED,    "vdd",	"msm_vidc.0",	&ved_fs_data),
+};
+unsigned msm8960_num_footswitch __initdata = ARRAY_SIZE(msm8960_footswitch);
+
+#ifdef CONFIG_MSM_ROTATOR
+static struct msm_bus_vectors rotator_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_ROTATOR,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+static struct msm_bus_vectors rotator_ui_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_ROTATOR,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = (1024 * 600 * 4 * 2 * 60),
+		.ib  = (1024 * 600 * 4 * 2 * 60 * 1.5),
+	},
+};
+
+static struct msm_bus_vectors rotator_vga_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_ROTATOR,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = (640 * 480 * 2 * 2 * 30),
+		.ib  = (640 * 480 * 2 * 2 * 30 * 1.5),
+	},
+};
+static struct msm_bus_vectors rotator_720p_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_ROTATOR,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = (1280 * 736 * 2 * 2 * 30),
+		.ib  = (1280 * 736 * 2 * 2 * 30 * 1.5),
+	},
+};
+
+static struct msm_bus_vectors rotator_1080p_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_ROTATOR,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = (1920 * 1088 * 2 * 2 * 30),
+		.ib  = (1920 * 1088 * 2 * 2 * 30 * 1.5),
+	},
+};
+
+static struct msm_bus_paths rotator_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(rotator_init_vectors),
+		rotator_init_vectors,
+	},
+	{
+		ARRAY_SIZE(rotator_ui_vectors),
+		rotator_ui_vectors,
+	},
+	{
+		ARRAY_SIZE(rotator_vga_vectors),
+		rotator_vga_vectors,
+	},
+	{
+		ARRAY_SIZE(rotator_720p_vectors),
+		rotator_720p_vectors,
+	},
+	{
+		ARRAY_SIZE(rotator_1080p_vectors),
+		rotator_1080p_vectors,
+	},
+};
+
+struct msm_bus_scale_pdata rotator_bus_scale_pdata = {
+	rotator_bus_scale_usecases,
+	ARRAY_SIZE(rotator_bus_scale_usecases),
+	.name = "rotator",
+};
+
+void __init msm_rotator_update_bus_vectors(unsigned int xres,
+	unsigned int yres)
+{
+	rotator_ui_vectors[0].ab = xres * yres * 4 * 2 * 60;
+	rotator_ui_vectors[0].ib = xres * yres * 4 * 2 * 60 * 3 / 2;
+}
+
+#define ROTATOR_HW_BASE         0x04E00000
+static struct resource resources_msm_rotator[] = {
+	{
+		.start  = ROTATOR_HW_BASE,
+		.end    = ROTATOR_HW_BASE + 0x100000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = ROT_IRQ,
+		.end    = ROT_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct msm_rot_clocks rotator_clocks[] = {
+	{
+		.clk_name = "core_clk",
+		.clk_type = ROTATOR_CORE_CLK,
+		.clk_rate = 200 * 1000 * 1000,
+	},
+	{
+		.clk_name = "iface_clk",
+		.clk_type = ROTATOR_PCLK,
+		.clk_rate = 0,
+	},
+};
+
+static struct msm_rotator_platform_data rotator_pdata = {
+	.number_of_clocks = ARRAY_SIZE(rotator_clocks),
+	.hardware_version_number = 0x01020309,
+	.rotator_clks = rotator_clocks,
+#ifdef CONFIG_MSM_BUS_SCALING
+	.bus_scale_table = &rotator_bus_scale_pdata,
+#endif
+};
+
+struct platform_device msm_rotator_device = {
+	.name           = "msm_rotator",
+	.id             = 0,
+	.num_resources  = ARRAY_SIZE(resources_msm_rotator),
+	.resource       = resources_msm_rotator,
+	.dev            = {
+		.platform_data = &rotator_pdata,
+	},
+};
+#endif
+
+#define MIPI_DSI_HW_BASE        0x04700000
+#define MDP_HW_BASE             0x05100000
+
+static struct resource msm_mipi_dsi1_resources[] = {
+	{
+		.name   = "mipi_dsi",
+		.start  = MIPI_DSI_HW_BASE,
+		.end    = MIPI_DSI_HW_BASE + 0x000F0000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = DSI1_IRQ,
+		.end    = DSI1_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_mipi_dsi1_device = {
+	.name   = "mipi_dsi",
+	.id     = 1,
+	.num_resources  = ARRAY_SIZE(msm_mipi_dsi1_resources),
+	.resource       = msm_mipi_dsi1_resources,
+};
+
+static struct resource msm_mdp_resources[] = {
+	{
+		.name   = "mdp",
+		.start  = MDP_HW_BASE,
+		.end    = MDP_HW_BASE + 0x000F0000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = MDP_IRQ,
+		.end    = MDP_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device msm_mdp_device = {
+	.name   = "mdp",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_mdp_resources),
+	.resource       = msm_mdp_resources,
+};
+
+static void __init msm_register_device(struct platform_device *pdev, void *data)
+{
+	int ret;
+
+	pdev->dev.platform_data = data;
+	ret = platform_device_register(pdev);
+	if (ret)
+		dev_err(&pdev->dev,
+			"%s: platform_device_register() failed = %d\n",
+			__func__, ret);
+}
+
+#ifdef CONFIG_MSM_BUS_SCALING
+static struct platform_device msm_dtv_device = {
+	.name   = "dtv",
+	.id     = 0,
+};
+#endif
+
+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);
+#endif
+	else
+		printk(KERN_ERR "%s: unknown device! %s\n", __func__, name);
+}
+
+static struct resource resources_sps[] = {
+	{
+		.name	= "pipe_mem",
+		.start	= 0x12800000,
+		.end	= 0x12800000 + 0x4000 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "bamdma_dma",
+		.start	= 0x12240000,
+		.end	= 0x12240000 + 0x1000 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "bamdma_bam",
+		.start	= 0x12244000,
+		.end	= 0x12244000 + 0x4000 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "bamdma_irq",
+		.start	= SPS_BAM_DMA_IRQ,
+		.end	= SPS_BAM_DMA_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct msm_sps_platform_data msm_sps_pdata = {
+	.bamdma_restricted_pipes = 0x06,
+};
+
+struct platform_device msm_device_sps = {
+	.name		= "msm_sps",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_sps),
+	.resource	= resources_sps,
+	.dev.platform_data = &msm_sps_pdata,
+};
+
+#ifdef CONFIG_MSM_MPM
+static uint16_t msm_mpm_irqs_m2a[MSM_MPM_NR_MPM_IRQS] __initdata = {
+	[1] = MSM_GPIO_TO_INT(46),
+	[2] = MSM_GPIO_TO_INT(150),
+	[4] = MSM_GPIO_TO_INT(103),
+	[5] = MSM_GPIO_TO_INT(104),
+	[6] = MSM_GPIO_TO_INT(105),
+	[7] = MSM_GPIO_TO_INT(106),
+	[8] = MSM_GPIO_TO_INT(107),
+	[9] = MSM_GPIO_TO_INT(7),
+	[10] = MSM_GPIO_TO_INT(11),
+	[11] = MSM_GPIO_TO_INT(15),
+	[12] = MSM_GPIO_TO_INT(19),
+	[13] = MSM_GPIO_TO_INT(23),
+	[14] = MSM_GPIO_TO_INT(27),
+	[15] = MSM_GPIO_TO_INT(31),
+	[16] = MSM_GPIO_TO_INT(35),
+	[19] = MSM_GPIO_TO_INT(90),
+	[20] = MSM_GPIO_TO_INT(92),
+	[23] = MSM_GPIO_TO_INT(85),
+	[24] = MSM_GPIO_TO_INT(83),
+	[25] = USB1_HS_IRQ,
+	[27] = HDMI_IRQ,
+	[29] = MSM_GPIO_TO_INT(10),
+	[30] = MSM_GPIO_TO_INT(102),
+	[31] = MSM_GPIO_TO_INT(81),
+	[32] = MSM_GPIO_TO_INT(78),
+	[33] = MSM_GPIO_TO_INT(94),
+	[34] = MSM_GPIO_TO_INT(72),
+	[35] = MSM_GPIO_TO_INT(39),
+	[36] = MSM_GPIO_TO_INT(43),
+	[37] = MSM_GPIO_TO_INT(61),
+	[38] = MSM_GPIO_TO_INT(50),
+	[39] = MSM_GPIO_TO_INT(42),
+	[41] = MSM_GPIO_TO_INT(62),
+	[42] = MSM_GPIO_TO_INT(76),
+	[43] = MSM_GPIO_TO_INT(75),
+	[44] = MSM_GPIO_TO_INT(70),
+	[45] = MSM_GPIO_TO_INT(69),
+	[46] = MSM_GPIO_TO_INT(67),
+	[47] = MSM_GPIO_TO_INT(65),
+	[48] = MSM_GPIO_TO_INT(58),
+	[49] = MSM_GPIO_TO_INT(54),
+	[50] = MSM_GPIO_TO_INT(52),
+	[51] = MSM_GPIO_TO_INT(49),
+	[52] = MSM_GPIO_TO_INT(40),
+	[53] = MSM_GPIO_TO_INT(37),
+	[54] = MSM_GPIO_TO_INT(24),
+	[55] = MSM_GPIO_TO_INT(14),
+};
+
+static uint16_t msm_mpm_bypassed_apps_irqs[] __initdata = {
+	TLMM_MSM_SUMMARY_IRQ,
+	RPM_APCC_CPU0_GP_HIGH_IRQ,
+	RPM_APCC_CPU0_GP_MEDIUM_IRQ,
+	RPM_APCC_CPU0_GP_LOW_IRQ,
+	RPM_APCC_CPU0_WAKE_UP_IRQ,
+	RPM_APCC_CPU1_GP_HIGH_IRQ,
+	RPM_APCC_CPU1_GP_MEDIUM_IRQ,
+	RPM_APCC_CPU1_GP_LOW_IRQ,
+	RPM_APCC_CPU1_WAKE_UP_IRQ,
+	MSS_TO_APPS_IRQ_0,
+	MSS_TO_APPS_IRQ_1,
+	MSS_TO_APPS_IRQ_2,
+	MSS_TO_APPS_IRQ_3,
+	MSS_TO_APPS_IRQ_4,
+	MSS_TO_APPS_IRQ_5,
+	MSS_TO_APPS_IRQ_6,
+	MSS_TO_APPS_IRQ_7,
+	MSS_TO_APPS_IRQ_8,
+	MSS_TO_APPS_IRQ_9,
+	LPASS_SCSS_GP_LOW_IRQ,
+	LPASS_SCSS_GP_MEDIUM_IRQ,
+	LPASS_SCSS_GP_HIGH_IRQ,
+	SPS_MTI_30,
+	SPS_MTI_31,
+	RIVA_APSS_SPARE_IRQ,
+	RIVA_APPS_WLAN_SMSM_IRQ,
+	RIVA_APPS_WLAN_RX_DATA_AVAIL_IRQ,
+	RIVA_APPS_WLAN_DATA_XFER_DONE_IRQ,
+};
+
+struct msm_mpm_device_data msm8960_mpm_dev_data __initdata = {
+	.irqs_m2a = msm_mpm_irqs_m2a,
+	.irqs_m2a_size = ARRAY_SIZE(msm_mpm_irqs_m2a),
+	.bypassed_apps_irqs = msm_mpm_bypassed_apps_irqs,
+	.bypassed_apps_irqs_size = ARRAY_SIZE(msm_mpm_bypassed_apps_irqs),
+	.mpm_request_reg_base = MSM_RPM_BASE + 0x9d8,
+	.mpm_status_reg_base = MSM_RPM_BASE + 0xdf8,
+	.mpm_apps_ipc_reg = MSM_APCS_GCC_BASE + 0x008,
+	.mpm_apps_ipc_val =  BIT(1),
+	.mpm_ipc_irq = RPM_APCC_CPU0_GP_MEDIUM_IRQ,
+
+};
+#endif
+
+#define LPASS_SLIMBUS_PHYS	0x28080000
+#define LPASS_SLIMBUS_BAM_PHYS	0x28084000
+#define LPASS_SLIMBUS_SLEW	(MSM8960_TLMM_PHYS + 0x207C)
+/* Board info for the slimbus slave device */
+static struct resource slimbus_res[] = {
+	{
+		.start	= LPASS_SLIMBUS_PHYS,
+		.end	= LPASS_SLIMBUS_PHYS + 8191,
+		.flags	= IORESOURCE_MEM,
+		.name	= "slimbus_physical",
+	},
+	{
+		.start	= LPASS_SLIMBUS_BAM_PHYS,
+		.end	= LPASS_SLIMBUS_BAM_PHYS + 8191,
+		.flags	= IORESOURCE_MEM,
+		.name	= "slimbus_bam_physical",
+	},
+	{
+		.start	= LPASS_SLIMBUS_SLEW,
+		.end	= LPASS_SLIMBUS_SLEW + 4 - 1,
+		.flags	= IORESOURCE_MEM,
+		.name	= "slimbus_slew_reg",
+	},
+	{
+		.start	= SLIMBUS0_CORE_EE1_IRQ,
+		.end	= SLIMBUS0_CORE_EE1_IRQ,
+		.flags	= IORESOURCE_IRQ,
+		.name	= "slimbus_irq",
+	},
+	{
+		.start	= SLIMBUS0_BAM_EE1_IRQ,
+		.end	= SLIMBUS0_BAM_EE1_IRQ,
+		.flags	= IORESOURCE_IRQ,
+		.name	= "slimbus_bam_irq",
+	},
+};
+
+struct platform_device msm_slim_ctrl = {
+	.name	= "msm_slim_ctrl",
+	.id	= 1,
+	.num_resources	= ARRAY_SIZE(slimbus_res),
+	.resource	= slimbus_res,
+	.dev            = {
+		.coherent_dma_mask      = 0xffffffffULL,
+	},
+};
+
+static struct msm_dcvs_freq_entry grp3d_freq[] = {
+	{0, 0, 333932},
+	{0, 0, 497532},
+	{0, 0, 707610},
+	{0, 0, 844545},
+};
+
+static struct msm_dcvs_freq_entry grp2d_freq[] = {
+	{0, 0, 86000},
+	{0, 0, 200000},
+};
+
+static struct msm_dcvs_core_info grp3d_core_info = {
+	.freq_tbl = &grp3d_freq[0],
+	.core_param = {
+		.max_time_us = 100000,
+		.num_freq = ARRAY_SIZE(grp3d_freq),
+	},
+	.algo_param = {
+		.slack_time_us = 39000,
+		.disable_pc_threshold = 86000,
+		.ss_window_size = 1000000,
+		.ss_util_pct = 95,
+		.em_max_util_pct = 97,
+		.ss_iobusy_conv = 100,
+	},
+};
+
+static struct msm_dcvs_core_info grp2d_core_info = {
+	.freq_tbl = &grp2d_freq[0],
+	.core_param = {
+		.max_time_us = 100000,
+		.num_freq = ARRAY_SIZE(grp2d_freq),
+	},
+	.algo_param = {
+		.slack_time_us = 39000,
+		.disable_pc_threshold = 90000,
+		.ss_window_size = 1000000,
+		.ss_util_pct = 90,
+		.em_max_util_pct = 95,
+	},
+};
+
+#ifdef CONFIG_MSM_BUS_SCALING
+static struct msm_bus_vectors grp3d_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+static struct msm_bus_vectors grp3d_low_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(1000),
+	},
+};
+
+static struct msm_bus_vectors grp3d_nominal_low_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(2048),
+	},
+};
+
+static struct msm_bus_vectors grp3d_nominal_high_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(2656),
+	},
+};
+
+static struct msm_bus_vectors grp3d_max_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(3968),
+	},
+};
+
+static struct msm_bus_paths grp3d_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(grp3d_init_vectors),
+		grp3d_init_vectors,
+	},
+	{
+		ARRAY_SIZE(grp3d_low_vectors),
+		grp3d_low_vectors,
+	},
+	{
+		ARRAY_SIZE(grp3d_nominal_low_vectors),
+		grp3d_nominal_low_vectors,
+	},
+	{
+		ARRAY_SIZE(grp3d_nominal_high_vectors),
+		grp3d_nominal_high_vectors,
+	},
+	{
+		ARRAY_SIZE(grp3d_max_vectors),
+		grp3d_max_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata grp3d_bus_scale_pdata = {
+	grp3d_bus_scale_usecases,
+	ARRAY_SIZE(grp3d_bus_scale_usecases),
+	.name = "grp3d",
+};
+
+static struct msm_bus_vectors grp2d0_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_2D_CORE0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+static struct msm_bus_vectors grp2d0_nominal_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_2D_CORE0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(1000),
+	},
+};
+
+static struct msm_bus_vectors grp2d0_max_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_2D_CORE0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(2048),
+	},
+};
+
+static struct msm_bus_paths grp2d0_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(grp2d0_init_vectors),
+		grp2d0_init_vectors,
+	},
+	{
+		ARRAY_SIZE(grp2d0_nominal_vectors),
+		grp2d0_nominal_vectors,
+	},
+	{
+		ARRAY_SIZE(grp2d0_max_vectors),
+		grp2d0_max_vectors,
+	},
+};
+
+struct msm_bus_scale_pdata grp2d0_bus_scale_pdata = {
+	grp2d0_bus_scale_usecases,
+	ARRAY_SIZE(grp2d0_bus_scale_usecases),
+	.name = "grp2d0",
+};
+
+static struct msm_bus_vectors grp2d1_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_2D_CORE1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+static struct msm_bus_vectors grp2d1_nominal_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_2D_CORE1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(1000),
+	},
+};
+
+static struct msm_bus_vectors grp2d1_max_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_2D_CORE1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(2048),
+	},
+};
+
+static struct msm_bus_paths grp2d1_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(grp2d1_init_vectors),
+		grp2d1_init_vectors,
+	},
+	{
+		ARRAY_SIZE(grp2d1_nominal_vectors),
+		grp2d1_nominal_vectors,
+	},
+	{
+		ARRAY_SIZE(grp2d1_max_vectors),
+		grp2d1_max_vectors,
+	},
+};
+
+struct msm_bus_scale_pdata grp2d1_bus_scale_pdata = {
+	grp2d1_bus_scale_usecases,
+	ARRAY_SIZE(grp2d1_bus_scale_usecases),
+	.name = "grp2d1",
+};
+#endif
+
+static struct resource kgsl_3d0_resources[] = {
+	{
+		.name = KGSL_3D0_REG_MEMORY,
+		.start = 0x04300000, /* GFX3D address */
+		.end = 0x0431ffff,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = KGSL_3D0_IRQ,
+		.start = GFX3D_IRQ,
+		.end = GFX3D_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static const struct kgsl_iommu_ctx kgsl_3d0_iommu_ctxs[] = {
+	{ "gfx3d_user", 0 },
+	{ "gfx3d_priv", 1 },
+};
+
+static struct kgsl_device_iommu_data kgsl_3d0_iommu_data[] = {
+	{
+		.iommu_ctxs = kgsl_3d0_iommu_ctxs,
+		.iommu_ctx_count = ARRAY_SIZE(kgsl_3d0_iommu_ctxs),
+		.physstart = 0x07C00000,
+		.physend = 0x07C00000 + SZ_1M - 1,
+	},
+};
+
+static struct kgsl_device_platform_data kgsl_3d0_pdata = {
+	.pwrlevel = {
+		{
+			.gpu_freq = 400000000,
+			.bus_freq = 4,
+			.io_fraction = 0,
+		},
+		{
+			.gpu_freq = 300000000,
+			.bus_freq = 3,
+			.io_fraction = 33,
+		},
+		{
+			.gpu_freq = 200000000,
+			.bus_freq = 2,
+			.io_fraction = 100,
+		},
+		{
+			.gpu_freq = 128000000,
+			.bus_freq = 1,
+			.io_fraction = 100,
+		},
+		{
+			.gpu_freq = 27000000,
+			.bus_freq = 0,
+		},
+	},
+	.init_level = 1,
+	.num_levels = ARRAY_SIZE(grp3d_freq) + 1,
+	.set_grp_async = NULL,
+	.idle_timeout = HZ/12,
+	.nap_allowed = true,
+	.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM_IFACE,
+#ifdef CONFIG_MSM_BUS_SCALING
+	.bus_scale_table = &grp3d_bus_scale_pdata,
+#endif
+	.iommu_data = kgsl_3d0_iommu_data,
+	.iommu_count = ARRAY_SIZE(kgsl_3d0_iommu_data),
+	.core_info = &grp3d_core_info,
+};
+
+struct platform_device msm_kgsl_3d0 = {
+	.name = "kgsl-3d0",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(kgsl_3d0_resources),
+	.resource = kgsl_3d0_resources,
+	.dev = {
+		.platform_data = &kgsl_3d0_pdata,
+	},
+};
+
+static struct resource kgsl_2d0_resources[] = {
+	{
+		.name = KGSL_2D0_REG_MEMORY,
+		.start = 0x04100000, /* Z180 base address */
+		.end = 0x04100FFF,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name  = KGSL_2D0_IRQ,
+		.start = GFX2D0_IRQ,
+		.end = GFX2D0_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static const struct kgsl_iommu_ctx kgsl_2d0_iommu_ctxs[] = {
+	{ "gfx2d0_2d0", 0 },
+};
+
+static struct kgsl_device_iommu_data kgsl_2d0_iommu_data[] = {
+	{
+		.iommu_ctxs = kgsl_2d0_iommu_ctxs,
+		.iommu_ctx_count = ARRAY_SIZE(kgsl_2d0_iommu_ctxs),
+		.physstart = 0x07D00000,
+		.physend = 0x07D00000 + SZ_1M - 1,
+	},
+};
+
+static struct kgsl_device_platform_data kgsl_2d0_pdata = {
+	.pwrlevel = {
+		{
+			.gpu_freq = 200000000,
+			.bus_freq = 2,
+		},
+		{
+			.gpu_freq = 96000000,
+			.bus_freq = 1,
+		},
+		{
+			.gpu_freq = 27000000,
+			.bus_freq = 0,
+		},
+	},
+	.init_level = 0,
+	.num_levels = ARRAY_SIZE(grp2d_freq) + 1,
+	.set_grp_async = NULL,
+	.idle_timeout = HZ/5,
+	.nap_allowed = true,
+	.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE,
+#ifdef CONFIG_MSM_BUS_SCALING
+	.bus_scale_table = &grp2d0_bus_scale_pdata,
+#endif
+	.iommu_data = kgsl_2d0_iommu_data,
+	.iommu_count = ARRAY_SIZE(kgsl_2d0_iommu_data),
+	.core_info = &grp2d_core_info,
+};
+
+struct platform_device msm_kgsl_2d0 = {
+	.name = "kgsl-2d0",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(kgsl_2d0_resources),
+	.resource = kgsl_2d0_resources,
+	.dev = {
+		.platform_data = &kgsl_2d0_pdata,
+	},
+};
+
+static const struct kgsl_iommu_ctx kgsl_2d1_iommu_ctxs[] = {
+	{ "gfx2d1_2d1", 0 },
+};
+
+static struct kgsl_device_iommu_data kgsl_2d1_iommu_data[] = {
+	{
+		.iommu_ctxs = kgsl_2d1_iommu_ctxs,
+		.iommu_ctx_count = ARRAY_SIZE(kgsl_2d1_iommu_ctxs),
+		.physstart = 0x07E00000,
+		.physend = 0x07E00000 + SZ_1M - 1,
+	},
+};
+
+static struct resource kgsl_2d1_resources[] = {
+	{
+		.name = KGSL_2D1_REG_MEMORY,
+		.start = 0x04200000, /* Z180 device 1 base address */
+		.end =   0x04200FFF,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name  = KGSL_2D1_IRQ,
+		.start = GFX2D1_IRQ,
+		.end = GFX2D1_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct kgsl_device_platform_data kgsl_2d1_pdata = {
+	.pwrlevel = {
+		{
+			.gpu_freq = 200000000,
+			.bus_freq = 2,
+		},
+		{
+			.gpu_freq = 96000000,
+			.bus_freq = 1,
+		},
+		{
+			.gpu_freq = 27000000,
+			.bus_freq = 0,
+		},
+	},
+	.init_level = 0,
+	.num_levels = ARRAY_SIZE(grp2d_freq) + 1,
+	.set_grp_async = NULL,
+	.idle_timeout = HZ/5,
+	.nap_allowed = true,
+	.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE,
+#ifdef CONFIG_MSM_BUS_SCALING
+	.bus_scale_table = &grp2d1_bus_scale_pdata,
+#endif
+	.iommu_data = kgsl_2d1_iommu_data,
+	.iommu_count = ARRAY_SIZE(kgsl_2d1_iommu_data),
+	.core_info = &grp2d_core_info,
+};
+
+struct platform_device msm_kgsl_2d1 = {
+	.name = "kgsl-2d1",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(kgsl_2d1_resources),
+	.resource = kgsl_2d1_resources,
+	.dev = {
+		.platform_data = &kgsl_2d1_pdata,
+	},
+};
+
+#ifdef CONFIG_MSM_GEMINI
+static struct resource msm_gemini_resources[] = {
+	{
+		.start  = 0x04600000,
+		.end    = 0x04600000 + SZ_1M - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = JPEG_IRQ,
+		.end    = JPEG_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8960_gemini_device = {
+	.name           = "msm_gemini",
+	.resource       = msm_gemini_resources,
+	.num_resources  = ARRAY_SIZE(msm_gemini_resources),
+};
+#endif
+
+struct msm_rpm_platform_data msm8960_rpm_data __initdata = {
+	.reg_base_addrs = {
+		[MSM_RPM_PAGE_STATUS] = MSM_RPM_BASE,
+		[MSM_RPM_PAGE_CTRL] = MSM_RPM_BASE + 0x400,
+		[MSM_RPM_PAGE_REQ] = MSM_RPM_BASE + 0x600,
+		[MSM_RPM_PAGE_ACK] = MSM_RPM_BASE + 0xa00,
+	},
+	.irq_ack = RPM_APCC_CPU0_GP_HIGH_IRQ,
+	.irq_err = RPM_APCC_CPU0_GP_LOW_IRQ,
+	.irq_wakeup = RPM_APCC_CPU0_WAKE_UP_IRQ,
+	.ipc_rpm_reg = MSM_APCS_GCC_BASE + 0x008,
+	.ipc_rpm_val = 4,
+	.target_id = {
+		MSM_RPM_MAP(8960, NOTIFICATION_CONFIGURED_0, NOTIFICATION, 4),
+		MSM_RPM_MAP(8960, NOTIFICATION_REGISTERED_0, NOTIFICATION, 4),
+		MSM_RPM_MAP(8960, INVALIDATE_0, INVALIDATE, 8),
+		MSM_RPM_MAP(8960, TRIGGER_TIMED_TO, TRIGGER_TIMED, 1),
+		MSM_RPM_MAP(8960, TRIGGER_TIMED_SCLK_COUNT, TRIGGER_TIMED, 1),
+		MSM_RPM_MAP(8960, RPM_CTL, RPM_CTL, 1),
+		MSM_RPM_MAP(8960, CXO_CLK, CXO_CLK, 1),
+		MSM_RPM_MAP(8960, PXO_CLK, PXO_CLK, 1),
+		MSM_RPM_MAP(8960, APPS_FABRIC_CLK, APPS_FABRIC_CLK, 1),
+		MSM_RPM_MAP(8960, SYSTEM_FABRIC_CLK, SYSTEM_FABRIC_CLK, 1),
+		MSM_RPM_MAP(8960, MM_FABRIC_CLK, MM_FABRIC_CLK, 1),
+		MSM_RPM_MAP(8960, DAYTONA_FABRIC_CLK, DAYTONA_FABRIC_CLK, 1),
+		MSM_RPM_MAP(8960, SFPB_CLK, SFPB_CLK, 1),
+		MSM_RPM_MAP(8960, CFPB_CLK, CFPB_CLK, 1),
+		MSM_RPM_MAP(8960, MMFPB_CLK, MMFPB_CLK, 1),
+		MSM_RPM_MAP(8960, EBI1_CLK, EBI1_CLK, 1),
+		MSM_RPM_MAP(8960, APPS_FABRIC_CFG_HALT_0,
+				APPS_FABRIC_CFG_HALT, 2),
+		MSM_RPM_MAP(8960, APPS_FABRIC_CFG_CLKMOD_0,
+				APPS_FABRIC_CFG_CLKMOD, 3),
+		MSM_RPM_MAP(8960, APPS_FABRIC_CFG_IOCTL,
+				APPS_FABRIC_CFG_IOCTL, 1),
+		MSM_RPM_MAP(8960, APPS_FABRIC_ARB_0, APPS_FABRIC_ARB, 12),
+		MSM_RPM_MAP(8960, SYS_FABRIC_CFG_HALT_0,
+				SYS_FABRIC_CFG_HALT, 2),
+		MSM_RPM_MAP(8960, SYS_FABRIC_CFG_CLKMOD_0,
+				SYS_FABRIC_CFG_CLKMOD, 3),
+		MSM_RPM_MAP(8960, SYS_FABRIC_CFG_IOCTL,
+				SYS_FABRIC_CFG_IOCTL, 1),
+		MSM_RPM_MAP(8960, SYSTEM_FABRIC_ARB_0,
+				SYSTEM_FABRIC_ARB, 29),
+		MSM_RPM_MAP(8960, MMSS_FABRIC_CFG_HALT_0,
+				MMSS_FABRIC_CFG_HALT, 2),
+		MSM_RPM_MAP(8960, MMSS_FABRIC_CFG_CLKMOD_0,
+				MMSS_FABRIC_CFG_CLKMOD, 3),
+		MSM_RPM_MAP(8960, MMSS_FABRIC_CFG_IOCTL,
+				MMSS_FABRIC_CFG_IOCTL, 1),
+		MSM_RPM_MAP(8960, MM_FABRIC_ARB_0, MM_FABRIC_ARB, 23),
+		MSM_RPM_MAP(8960, PM8921_S1_0, PM8921_S1, 2),
+		MSM_RPM_MAP(8960, PM8921_S2_0, PM8921_S2, 2),
+		MSM_RPM_MAP(8960, PM8921_S3_0, PM8921_S3, 2),
+		MSM_RPM_MAP(8960, PM8921_S4_0, PM8921_S4, 2),
+		MSM_RPM_MAP(8960, PM8921_S5_0, PM8921_S5, 2),
+		MSM_RPM_MAP(8960, PM8921_S6_0, PM8921_S6, 2),
+		MSM_RPM_MAP(8960, PM8921_S7_0, PM8921_S7, 2),
+		MSM_RPM_MAP(8960, PM8921_S8_0, PM8921_S8, 2),
+		MSM_RPM_MAP(8960, PM8921_L1_0, PM8921_L1, 2),
+		MSM_RPM_MAP(8960, PM8921_L2_0, PM8921_L2, 2),
+		MSM_RPM_MAP(8960, PM8921_L3_0, PM8921_L3, 2),
+		MSM_RPM_MAP(8960, PM8921_L4_0, PM8921_L4, 2),
+		MSM_RPM_MAP(8960, PM8921_L5_0, PM8921_L5, 2),
+		MSM_RPM_MAP(8960, PM8921_L6_0, PM8921_L6, 2),
+		MSM_RPM_MAP(8960, PM8921_L7_0, PM8921_L7, 2),
+		MSM_RPM_MAP(8960, PM8921_L8_0, PM8921_L8, 2),
+		MSM_RPM_MAP(8960, PM8921_L9_0, PM8921_L9, 2),
+		MSM_RPM_MAP(8960, PM8921_L10_0, PM8921_L10, 2),
+		MSM_RPM_MAP(8960, PM8921_L11_0, PM8921_L11, 2),
+		MSM_RPM_MAP(8960, PM8921_L12_0, PM8921_L12, 2),
+		MSM_RPM_MAP(8960, PM8921_L13_0, PM8921_L13, 2),
+		MSM_RPM_MAP(8960, PM8921_L14_0, PM8921_L14, 2),
+		MSM_RPM_MAP(8960, PM8921_L15_0, PM8921_L15, 2),
+		MSM_RPM_MAP(8960, PM8921_L16_0, PM8921_L16, 2),
+		MSM_RPM_MAP(8960, PM8921_L17_0, PM8921_L17, 2),
+		MSM_RPM_MAP(8960, PM8921_L18_0, PM8921_L18, 2),
+		MSM_RPM_MAP(8960, PM8921_L19_0, PM8921_L19, 2),
+		MSM_RPM_MAP(8960, PM8921_L20_0, PM8921_L20, 2),
+		MSM_RPM_MAP(8960, PM8921_L21_0, PM8921_L21, 2),
+		MSM_RPM_MAP(8960, PM8921_L22_0, PM8921_L22, 2),
+		MSM_RPM_MAP(8960, PM8921_L23_0, PM8921_L23, 2),
+		MSM_RPM_MAP(8960, PM8921_L24_0, PM8921_L24, 2),
+		MSM_RPM_MAP(8960, PM8921_L25_0, PM8921_L25, 2),
+		MSM_RPM_MAP(8960, PM8921_L26_0, PM8921_L26, 2),
+		MSM_RPM_MAP(8960, PM8921_L27_0, PM8921_L27, 2),
+		MSM_RPM_MAP(8960, PM8921_L28_0, PM8921_L28, 2),
+		MSM_RPM_MAP(8960, PM8921_L29_0, PM8921_L29, 2),
+		MSM_RPM_MAP(8960, PM8921_CLK1_0, PM8921_CLK1, 2),
+		MSM_RPM_MAP(8960, PM8921_CLK2_0, PM8921_CLK2, 2),
+		MSM_RPM_MAP(8960, PM8921_LVS1, PM8921_LVS1, 1),
+		MSM_RPM_MAP(8960, PM8921_LVS2, PM8921_LVS2, 1),
+		MSM_RPM_MAP(8960, PM8921_LVS3, PM8921_LVS3, 1),
+		MSM_RPM_MAP(8960, PM8921_LVS4, PM8921_LVS4, 1),
+		MSM_RPM_MAP(8960, PM8921_LVS5, PM8921_LVS5, 1),
+		MSM_RPM_MAP(8960, PM8921_LVS6, PM8921_LVS6, 1),
+		MSM_RPM_MAP(8960, PM8921_LVS7, PM8921_LVS7, 1),
+		MSM_RPM_MAP(8960, NCP_0, NCP, 2),
+		MSM_RPM_MAP(8960, CXO_BUFFERS, CXO_BUFFERS, 1),
+		MSM_RPM_MAP(8960, USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
+		MSM_RPM_MAP(8960, HDMI_SWITCH, HDMI_SWITCH, 1),
+		MSM_RPM_MAP(8960, DDR_DMM_0, DDR_DMM, 2),
+		MSM_RPM_MAP(8960, QDSS_CLK, QDSS_CLK, 1),
+	},
+	.target_status = {
+		MSM_RPM_STATUS_ID_MAP(8960, VERSION_MAJOR),
+		MSM_RPM_STATUS_ID_MAP(8960, VERSION_MINOR),
+		MSM_RPM_STATUS_ID_MAP(8960, VERSION_BUILD),
+		MSM_RPM_STATUS_ID_MAP(8960, SUPPORTED_RESOURCES_0),
+		MSM_RPM_STATUS_ID_MAP(8960, SUPPORTED_RESOURCES_1),
+		MSM_RPM_STATUS_ID_MAP(8960, SUPPORTED_RESOURCES_2),
+		MSM_RPM_STATUS_ID_MAP(8960, RESERVED_SUPPORTED_RESOURCES_0),
+		MSM_RPM_STATUS_ID_MAP(8960, SEQUENCE),
+		MSM_RPM_STATUS_ID_MAP(8960, RPM_CTL),
+		MSM_RPM_STATUS_ID_MAP(8960, CXO_CLK),
+		MSM_RPM_STATUS_ID_MAP(8960, PXO_CLK),
+		MSM_RPM_STATUS_ID_MAP(8960, APPS_FABRIC_CLK),
+		MSM_RPM_STATUS_ID_MAP(8960, SYSTEM_FABRIC_CLK),
+		MSM_RPM_STATUS_ID_MAP(8960, MM_FABRIC_CLK),
+		MSM_RPM_STATUS_ID_MAP(8960, DAYTONA_FABRIC_CLK),
+		MSM_RPM_STATUS_ID_MAP(8960, SFPB_CLK),
+		MSM_RPM_STATUS_ID_MAP(8960, CFPB_CLK),
+		MSM_RPM_STATUS_ID_MAP(8960, MMFPB_CLK),
+		MSM_RPM_STATUS_ID_MAP(8960, EBI1_CLK),
+		MSM_RPM_STATUS_ID_MAP(8960, APPS_FABRIC_CFG_HALT),
+		MSM_RPM_STATUS_ID_MAP(8960, APPS_FABRIC_CFG_CLKMOD),
+		MSM_RPM_STATUS_ID_MAP(8960, APPS_FABRIC_CFG_IOCTL),
+		MSM_RPM_STATUS_ID_MAP(8960, APPS_FABRIC_ARB),
+		MSM_RPM_STATUS_ID_MAP(8960, SYS_FABRIC_CFG_HALT),
+		MSM_RPM_STATUS_ID_MAP(8960, SYS_FABRIC_CFG_CLKMOD),
+		MSM_RPM_STATUS_ID_MAP(8960, SYS_FABRIC_CFG_IOCTL),
+		MSM_RPM_STATUS_ID_MAP(8960, SYSTEM_FABRIC_ARB),
+		MSM_RPM_STATUS_ID_MAP(8960, MMSS_FABRIC_CFG_HALT),
+		MSM_RPM_STATUS_ID_MAP(8960, MMSS_FABRIC_CFG_CLKMOD),
+		MSM_RPM_STATUS_ID_MAP(8960, MMSS_FABRIC_CFG_IOCTL),
+		MSM_RPM_STATUS_ID_MAP(8960, MM_FABRIC_ARB),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_S1_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_S1_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_S2_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_S2_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_S3_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_S3_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_S4_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_S4_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_S5_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_S5_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_S6_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_S6_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_S7_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_S7_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_S8_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_S8_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L1_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L1_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L2_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L2_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L3_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L3_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L4_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L4_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L5_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L5_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L6_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L6_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L7_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L7_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L8_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L8_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L9_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L9_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L10_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L10_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L11_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L11_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L12_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L12_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L13_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L13_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L14_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L14_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L15_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L15_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L16_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L16_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L17_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L17_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L18_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L18_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L19_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L19_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L20_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L20_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L21_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L21_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L22_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L22_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L23_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L23_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L24_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L24_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L25_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L25_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L26_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L26_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L27_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L27_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L28_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L28_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L29_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_L29_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_CLK1_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_CLK1_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_CLK2_0),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_CLK2_1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_LVS1),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_LVS2),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_LVS3),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_LVS4),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_LVS5),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_LVS6),
+		MSM_RPM_STATUS_ID_MAP(8960, PM8921_LVS7),
+		MSM_RPM_STATUS_ID_MAP(8960, NCP_0),
+		MSM_RPM_STATUS_ID_MAP(8960, NCP_1),
+		MSM_RPM_STATUS_ID_MAP(8960, CXO_BUFFERS),
+		MSM_RPM_STATUS_ID_MAP(8960, USB_OTG_SWITCH),
+		MSM_RPM_STATUS_ID_MAP(8960, HDMI_SWITCH),
+		MSM_RPM_STATUS_ID_MAP(8960, DDR_DMM_0),
+		MSM_RPM_STATUS_ID_MAP(8960, DDR_DMM_1),
+		MSM_RPM_STATUS_ID_MAP(8960, EBI1_CH0_RANGE),
+		MSM_RPM_STATUS_ID_MAP(8960, EBI1_CH1_RANGE),
+	},
+	.target_ctrl_id = {
+		MSM_RPM_CTRL_MAP(8960, VERSION_MAJOR),
+		MSM_RPM_CTRL_MAP(8960, VERSION_MINOR),
+		MSM_RPM_CTRL_MAP(8960, VERSION_BUILD),
+		MSM_RPM_CTRL_MAP(8960, REQ_CTX_0),
+		MSM_RPM_CTRL_MAP(8960, REQ_SEL_0),
+		MSM_RPM_CTRL_MAP(8960, ACK_CTX_0),
+		MSM_RPM_CTRL_MAP(8960, ACK_SEL_0),
+	},
+	.sel_invalidate = MSM_RPM_8960_SEL_INVALIDATE,
+	.sel_notification = MSM_RPM_8960_SEL_NOTIFICATION,
+	.sel_last = MSM_RPM_8960_SEL_LAST,
+	.ver = {3, 0, 0},
+};
+
+struct platform_device msm8960_rpm_device = {
+	.name   = "msm_rpm",
+	.id     = -1,
+};
+
+static struct msm_rpm_log_platform_data msm_rpm_log_pdata = {
+	.phys_addr_base = 0x0010C000,
+	.reg_offsets = {
+		[MSM_RPM_LOG_PAGE_INDICES] = 0x00000080,
+		[MSM_RPM_LOG_PAGE_BUFFER]  = 0x000000A0,
+	},
+	.phys_size = SZ_8K,
+	.log_len = 4096,		  /* log's buffer length in bytes */
+	.log_len_mask = (4096 >> 2) - 1,  /* length mask in units of u32 */
+};
+
+struct platform_device msm8960_rpm_log_device = {
+	.name	= "msm_rpm_log",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &msm_rpm_log_pdata,
+	},
+};
+
+static struct msm_rpmstats_platform_data msm_rpm_stat_pdata = {
+	.phys_addr_base = 0x0010D204,
+	.phys_size = SZ_8K,
+};
+
+struct platform_device msm8960_rpm_stat_device = {
+	.name = "msm_rpm_stat",
+	.id = -1,
+	.dev = {
+		.platform_data = &msm_rpm_stat_pdata,
+	},
+};
+
+struct platform_device msm_bus_sys_fabric = {
+	.name  = "msm_bus_fabric",
+	.id    =  MSM_BUS_FAB_SYSTEM,
+};
+struct platform_device msm_bus_apps_fabric = {
+	.name  = "msm_bus_fabric",
+	.id    = MSM_BUS_FAB_APPSS,
+};
+struct platform_device msm_bus_mm_fabric = {
+	.name  = "msm_bus_fabric",
+	.id    = MSM_BUS_FAB_MMSS,
+};
+struct platform_device msm_bus_sys_fpb = {
+	.name  = "msm_bus_fabric",
+	.id    = MSM_BUS_FAB_SYSTEM_FPB,
+};
+struct platform_device msm_bus_cpss_fpb = {
+	.name  = "msm_bus_fabric",
+	.id    = MSM_BUS_FAB_CPSS_FPB,
+};
+
+/* Sensors DSPS platform data */
+#ifdef CONFIG_MSM_DSPS
+
+#define PPSS_REG_PHYS_BASE	0x12080000
+
+static struct dsps_clk_info dsps_clks[] = {};
+static struct dsps_regulator_info dsps_regs[] = {};
+
+/*
+ * Note: GPIOs field is	intialized in run-time at the function
+ * msm8960_init_dsps().
+ */
+
+struct msm_dsps_platform_data msm_dsps_pdata = {
+	.clks = dsps_clks,
+	.clks_num = ARRAY_SIZE(dsps_clks),
+	.gpios = NULL,
+	.gpios_num = 0,
+	.regs = dsps_regs,
+	.regs_num = ARRAY_SIZE(dsps_regs),
+	.dsps_pwr_ctl_en = 1,
+	.signature = DSPS_SIGNATURE,
+};
+
+static struct resource msm_dsps_resources[] = {
+	{
+		.start = PPSS_REG_PHYS_BASE,
+		.end   = PPSS_REG_PHYS_BASE + SZ_8K - 1,
+		.name  = "ppss_reg",
+		.flags = IORESOURCE_MEM,
+	},
+
+	{
+		.start = PPSS_WDOG_TIMER_IRQ,
+		.end   = PPSS_WDOG_TIMER_IRQ,
+		.name  = "ppss_wdog",
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_dsps_device = {
+	.name          = "msm_dsps",
+	.id            = 0,
+	.num_resources = ARRAY_SIZE(msm_dsps_resources),
+	.resource      = msm_dsps_resources,
+	.dev.platform_data = &msm_dsps_pdata,
+};
+
+#endif /* CONFIG_MSM_DSPS */
+
+#ifdef CONFIG_MSM_QDSS
+
+#define MSM_QDSS_PHYS_BASE		0x01A00000
+#define MSM_ETB_PHYS_BASE		(MSM_QDSS_PHYS_BASE + 0x1000)
+#define MSM_TPIU_PHYS_BASE		(MSM_QDSS_PHYS_BASE + 0x3000)
+#define MSM_FUNNEL_PHYS_BASE		(MSM_QDSS_PHYS_BASE + 0x4000)
+#define MSM_ETM_PHYS_BASE		(MSM_QDSS_PHYS_BASE + 0x1C000)
+
+#define QDSS_SOURCE(src_name, fpm) { .name = src_name, .fport_mask = fpm, }
+
+static struct qdss_source msm_qdss_sources[] = {
+	QDSS_SOURCE("msm_etm", 0x3),
+};
+
+static struct msm_qdss_platform_data qdss_pdata = {
+	.src_table = msm_qdss_sources,
+	.size = ARRAY_SIZE(msm_qdss_sources),
+	.afamily = 1,
+};
+
+struct platform_device msm_qdss_device = {
+	.name          = "msm_qdss",
+	.id            = -1,
+	.dev           = {
+		.platform_data = &qdss_pdata,
+	},
+};
+
+static struct resource msm_etb_resources[] = {
+	{
+		.start = MSM_ETB_PHYS_BASE,
+		.end   = MSM_ETB_PHYS_BASE + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_etb_device = {
+	.name          = "msm_etb",
+	.id            = 0,
+	.num_resources = ARRAY_SIZE(msm_etb_resources),
+	.resource      = msm_etb_resources,
+};
+
+static struct resource msm_tpiu_resources[] = {
+	{
+		.start = MSM_TPIU_PHYS_BASE,
+		.end   = MSM_TPIU_PHYS_BASE + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_tpiu_device = {
+	.name          = "msm_tpiu",
+	.id            = 0,
+	.num_resources = ARRAY_SIZE(msm_tpiu_resources),
+	.resource      = msm_tpiu_resources,
+};
+
+static struct resource msm_funnel_resources[] = {
+	{
+		.start = MSM_FUNNEL_PHYS_BASE,
+		.end   = MSM_FUNNEL_PHYS_BASE + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_funnel_device = {
+	.name          = "msm_funnel",
+	.id            = 0,
+	.num_resources = ARRAY_SIZE(msm_funnel_resources),
+	.resource      = msm_funnel_resources,
+};
+
+static struct resource msm_etm_resources[] = {
+	{
+		.start = MSM_ETM_PHYS_BASE,
+		.end   = MSM_ETM_PHYS_BASE + (SZ_4K * 2) - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_etm_device = {
+	.name          = "msm_etm",
+	.id            = 0,
+	.num_resources = ARRAY_SIZE(msm_etm_resources),
+	.resource      = msm_etm_resources,
+};
+
+#endif
+
+static int msm8960_LPM_latency = 1000; /* >100 usec for WFI */
+
+struct platform_device msm8960_cpu_idle_device = {
+	.name   = "msm_cpu_idle",
+	.id     = -1,
+	.dev = {
+		.platform_data = &msm8960_LPM_latency,
+	},
+};
+
+static struct msm_dcvs_freq_entry msm8960_freq[] = {
+	{ 384000, 166981,  345600},
+	{ 702000, 213049,  632502},
+	{1026000, 285712,  925613},
+	{1242000, 383945, 1176550},
+	{1458000, 419729, 1465478},
+	{1512000, 434116, 1546674},
+
+};
+
+static struct msm_dcvs_core_info msm8960_core_info = {
+	.freq_tbl = &msm8960_freq[0],
+	.core_param = {
+		.max_time_us = 100000,
+		.num_freq = ARRAY_SIZE(msm8960_freq),
+	},
+	.algo_param = {
+		.slack_time_us = 58000,
+		.scale_slack_time = 0,
+		.scale_slack_time_pct = 0,
+		.disable_pc_threshold = 1458000,
+		.em_window_size = 100000,
+		.em_max_util_pct = 97,
+		.ss_window_size = 1000000,
+		.ss_util_pct = 95,
+		.ss_iobusy_conv = 100,
+	},
+};
+
+struct platform_device msm8960_msm_gov_device = {
+	.name = "msm_dcvs_gov",
+	.id = -1,
+	.dev = {
+		.platform_data = &msm8960_core_info,
+	},
+};
+
+static struct resource msm_cache_erp_resources[] = {
+	{
+		.name = "l1_irq",
+		.start = SC_SICCPUXEXTFAULTIRPTREQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name = "l2_irq",
+		.start = APCC_QGICL2IRPTREQ,
+		.flags = IORESOURCE_IRQ,
+	}
+};
+
+struct platform_device msm8960_device_cache_erp = {
+	.name		= "msm_cache_erp",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(msm_cache_erp_resources),
+	.resource	= msm_cache_erp_resources,
+};
+
+struct msm_iommu_domain_name msm8960_iommu_ctx_names[] = {
+	/* Camera */
+	{
+		.name = "vpe_src",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Camera */
+	{
+		.name = "vpe_dst",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Camera */
+	{
+		.name = "vfe_imgwr",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Camera */
+	{
+		.name = "vfe_misc",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Camera */
+	{
+		.name = "ijpeg_src",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Camera */
+	{
+		.name = "ijpeg_dst",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Camera */
+	{
+		.name = "jpegd_src",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Camera */
+	{
+		.name = "jpegd_dst",
+		.domain = CAMERA_DOMAIN,
+	},
+	/* Rotator */
+	{
+		.name = "rot_src",
+		.domain = ROTATOR_DOMAIN,
+	},
+	/* Rotator */
+	{
+		.name = "rot_dst",
+		.domain = ROTATOR_DOMAIN,
+	},
+	/* Video */
+	{
+		.name = "vcodec_a_mm1",
+		.domain = VIDEO_DOMAIN,
+	},
+	/* Video */
+	{
+		.name = "vcodec_b_mm2",
+		.domain = VIDEO_DOMAIN,
+	},
+	/* Video */
+	{
+		.name = "vcodec_a_stream",
+		.domain = VIDEO_DOMAIN,
+	},
+};
+
+static struct mem_pool msm8960_video_pools[] =  {
+	/*
+	 * Video hardware has the following requirements:
+	 * 1. All video addresses used by the video hardware must be at a higher
+	 *    address than video firmware address.
+	 * 2. Video hardware can only access a range of 256MB from the base of
+	 *    the video firmware.
+	*/
+	[VIDEO_FIRMWARE_POOL] =
+	/* Low addresses, intended for video firmware */
+		{
+			.paddr	= SZ_128K,
+			.size	= SZ_16M - SZ_128K,
+		},
+	[VIDEO_MAIN_POOL] =
+	/* Main video pool */
+		{
+			.paddr	= SZ_16M,
+			.size	= SZ_256M - SZ_16M,
+		},
+	[GEN_POOL] =
+	/* Remaining address space up to 2G */
+		{
+			.paddr	= SZ_256M,
+			.size	= SZ_2G - SZ_256M,
+		},
+};
+
+static struct mem_pool msm8960_camera_pools[] =  {
+	[GEN_POOL] =
+	/* One address space for camera */
+		{
+			.paddr	= SZ_128K,
+			.size	= SZ_2G - SZ_128K,
+		},
+};
+
+static struct mem_pool msm8960_display_pools[] =  {
+	[GEN_POOL] =
+	/* One address space for display */
+		{
+			.paddr	= SZ_128K,
+			.size	= SZ_2G - SZ_128K,
+		},
+};
+
+static struct mem_pool msm8960_rotator_pools[] =  {
+	[GEN_POOL] =
+	/* One address space for rotator */
+		{
+			.paddr	= SZ_128K,
+			.size	= SZ_2G - SZ_128K,
+		},
+};
+
+static struct msm_iommu_domain msm8960_iommu_domains[] = {
+		[VIDEO_DOMAIN] = {
+			.iova_pools = msm8960_video_pools,
+			.npools = ARRAY_SIZE(msm8960_video_pools),
+		},
+		[CAMERA_DOMAIN] = {
+			.iova_pools = msm8960_camera_pools,
+			.npools = ARRAY_SIZE(msm8960_camera_pools),
+		},
+		[DISPLAY_DOMAIN] = {
+			.iova_pools = msm8960_display_pools,
+			.npools = ARRAY_SIZE(msm8960_display_pools),
+		},
+		[ROTATOR_DOMAIN] = {
+			.iova_pools = msm8960_rotator_pools,
+			.npools = ARRAY_SIZE(msm8960_rotator_pools),
+		},
+};
+
+struct iommu_domains_pdata msm8960_iommu_domain_pdata = {
+	.domains = msm8960_iommu_domains,
+	.ndomains = ARRAY_SIZE(msm8960_iommu_domains),
+	.domain_names = msm8960_iommu_ctx_names,
+	.nnames = ARRAY_SIZE(msm8960_iommu_ctx_names),
+	.domain_alloc_flags = 0,
+};
+
+struct platform_device msm8960_iommu_domain_device = {
+	.name = "iommu_domains",
+	.id = -1,
+	.dev = {
+		.platform_data = &msm8960_iommu_domain_pdata,
+	}
+};
+
+struct msm_rtb_platform_data msm8960_rtb_pdata = {
+	.size = SZ_1M,
+};
+
+static int __init msm_rtb_set_buffer_size(char *p)
+{
+	int s;
+
+	s = memparse(p, NULL);
+	msm8960_rtb_pdata.size = ALIGN(s, SZ_4K);
+	return 0;
+}
+early_param("msm_rtb_size", msm_rtb_set_buffer_size);
+
+
+struct platform_device msm8960_rtb_device = {
+	.name           = "msm_rtb",
+	.id             = -1,
+	.dev            = {
+		.platform_data = &msm8960_rtb_pdata,
+	},
+};
+
+#define MSM_8960_L1_SIZE  SZ_1M
+/*
+ * The actual L2 size is smaller but we need a larger buffer
+ * size to store other dump information
+ */
+#define MSM_8960_L2_SIZE  SZ_4M
+
+struct msm_cache_dump_platform_data msm8960_cache_dump_pdata = {
+	.l2_size = MSM_8960_L2_SIZE,
+	.l1_size = MSM_8960_L1_SIZE,
+};
+
+struct platform_device msm8960_cache_dump_device = {
+	.name           = "msm_cache_dump",
+	.id             = -1,
+	.dev            = {
+		.platform_data = &msm8960_cache_dump_pdata,
+	},
+};
+
+#define MDM2AP_ERRFATAL			40
+#define AP2MDM_ERRFATAL			80
+#define MDM2AP_STATUS			24
+#define AP2MDM_STATUS			77
+#define AP2MDM_PMIC_PWR_EN		22
+#define AP2MDM_KPDPWR_N			79
+#define AP2MDM_SOFT_RESET		78
+
+static struct resource sglte_resources[] = {
+	{
+		.start	= MDM2AP_ERRFATAL,
+		.end	= MDM2AP_ERRFATAL,
+		.name	= "MDM2AP_ERRFATAL",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= AP2MDM_ERRFATAL,
+		.end	= AP2MDM_ERRFATAL,
+		.name	= "AP2MDM_ERRFATAL",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= MDM2AP_STATUS,
+		.end	= MDM2AP_STATUS,
+		.name	= "MDM2AP_STATUS",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= AP2MDM_STATUS,
+		.end	= AP2MDM_STATUS,
+		.name	= "AP2MDM_STATUS",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= AP2MDM_PMIC_PWR_EN,
+		.end	= AP2MDM_PMIC_PWR_EN,
+		.name	= "AP2MDM_PMIC_PWR_EN",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= AP2MDM_KPDPWR_N,
+		.end	= AP2MDM_KPDPWR_N,
+		.name	= "AP2MDM_KPDPWR_N",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= AP2MDM_SOFT_RESET,
+		.end	= AP2MDM_SOFT_RESET,
+		.name	= "AP2MDM_SOFT_RESET",
+		.flags	= IORESOURCE_IO,
+	},
+};
+
+struct platform_device mdm_sglte_device = {
+	.name		= "mdm2_modem",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(sglte_resources),
+	.resource	= sglte_resources,
+};
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
new file mode 100644
index 0000000..76d79a6
--- /dev/null
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -0,0 +1,1381 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/platform_data/qcom_crypto_device.h>
+#include <linux/dma-mapping.h>
+#include <sound/msm-dai-q6.h>
+#include <sound/apr_audio.h>
+#include <linux/usb/android.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach/flash.h>
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_hsusb.h>
+#include <mach/irqs.h>
+#include <mach/socinfo.h>
+#include <mach/rpm.h>
+#include <mach/msm_bus_board.h>
+#include <asm/hardware/cache-l2x0.h>
+#include <mach/msm_sps.h>
+#include <mach/dma.h>
+#include "pm.h"
+#include "devices.h"
+#include <mach/mpm.h>
+#include "spm.h"
+#include "rpm_resources.h"
+#include "msm_watchdog.h"
+#include "rpm_stats.h"
+#include "rpm_log.h"
+
+/* Address of GSBI blocks */
+#define MSM_GSBI1_PHYS          0x16000000
+#define MSM_GSBI2_PHYS          0x16100000
+#define MSM_GSBI3_PHYS          0x16200000
+#define MSM_GSBI4_PHYS		0x16300000
+#define MSM_GSBI5_PHYS          0x16400000
+
+#define MSM_UART4DM_PHYS	(MSM_GSBI4_PHYS + 0x40000)
+
+/* GSBI QUP devices */
+#define MSM_GSBI1_QUP_PHYS      (MSM_GSBI1_PHYS + 0x80000)
+#define MSM_GSBI2_QUP_PHYS      (MSM_GSBI2_PHYS + 0x80000)
+#define MSM_GSBI3_QUP_PHYS      (MSM_GSBI3_PHYS + 0x80000)
+#define MSM_GSBI4_QUP_PHYS      (MSM_GSBI4_PHYS + 0x80000)
+#define MSM_GSBI5_QUP_PHYS      (MSM_GSBI5_PHYS + 0x80000)
+#define MSM_QUP_SIZE            SZ_4K
+
+/* Address of SSBI CMD */
+#define MSM_PMIC1_SSBI_CMD_PHYS	0x00500000
+#define MSM_PMIC_SSBI_SIZE	SZ_4K
+
+#define MSM_GPIO_I2C_CLK 16
+#define MSM_GPIO_I2C_SDA 17
+
+static struct msm_watchdog_pdata msm_watchdog_pdata = {
+	.pet_time = 10000,
+	.bark_time = 11000,
+	.has_secure = false,
+	.use_kernel_fiq = true,
+};
+
+struct platform_device msm9615_device_watchdog = {
+	.name = "msm_watchdog",
+	.id = -1,
+	.dev = {
+		.platform_data = &msm_watchdog_pdata,
+	},
+};
+
+static struct resource msm_dmov_resource[] = {
+	{
+		.start = ADM_0_SCSS_1_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = 0x18320000,
+		.end = 0x18320000 + SZ_1M - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct msm_dmov_pdata msm_dmov_pdata = {
+	.sd = 1,
+	.sd_size = 0x800,
+};
+
+struct platform_device msm9615_device_dmov = {
+	.name	= "msm_dmov",
+	.id	= -1,
+	.resource = msm_dmov_resource,
+	.num_resources = ARRAY_SIZE(msm_dmov_resource),
+	.dev = {
+		.platform_data = &msm_dmov_pdata,
+	},
+};
+
+#define MSM_USB_BAM_BASE     0x12502000
+#define MSM_USB_BAM_SIZE     SZ_16K
+#define MSM_HSIC_BAM_BASE    0x12542000
+#define MSM_HSIC_BAM_SIZE    SZ_16K
+
+static struct resource resources_otg[] = {
+	{
+		.start	= MSM9615_HSUSB_PHYS,
+		.end	= MSM9615_HSUSB_PHYS + MSM9615_HSUSB_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= USB1_HS_IRQ,
+		.end	= USB1_HS_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_otg = {
+	.name		= "msm_otg",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_otg),
+	.resource	= resources_otg,
+	.dev		= {
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+};
+
+#define MSM_HSUSB_RESUME_GPIO	79
+
+static struct resource resources_hsusb[] = {
+	{
+		.start	= MSM9615_HSUSB_PHYS,
+		.end	= MSM9615_HSUSB_PHYS + MSM9615_HSUSB_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= USB1_HS_IRQ,
+		.end	= USB1_HS_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM_HSUSB_RESUME_GPIO,
+		.end	= MSM_HSUSB_RESUME_GPIO,
+		.name	= "USB_RESUME",
+		.flags	= IORESOURCE_IO,
+	},
+};
+
+static struct resource resources_usb_bam[] = {
+	{
+		.name	= "usb_bam_addr",
+		.start	= MSM_USB_BAM_BASE,
+		.end	= MSM_USB_BAM_BASE + MSM_USB_BAM_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "usb_bam_irq",
+		.start	= USB1_HS_BAM_IRQ,
+		.end	= USB1_HS_BAM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "hsic_bam_addr",
+		.start	= MSM_HSIC_BAM_BASE,
+		.end	= MSM_HSIC_BAM_BASE + MSM_HSIC_BAM_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "hsic_bam_irq",
+		.start	= USB_HSIC_BAM_IRQ,
+		.end	= USB_HSIC_BAM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_usb_bam = {
+	.name		= "usb_bam",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_usb_bam),
+	.resource	= resources_usb_bam,
+};
+
+struct platform_device msm_device_gadget_peripheral = {
+	.name		= "msm_hsusb",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_hsusb),
+	.resource	= resources_hsusb,
+	.dev		= {
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+};
+
+static struct resource resources_hsic_peripheral[] = {
+	{
+		.start	= MSM9615_HSIC_PHYS,
+		.end	= MSM9615_HSIC_PHYS + MSM9615_HSIC_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= USB_HSIC_IRQ,
+		.end	= USB_HSIC_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_hsic_peripheral = {
+	.name		= "msm_hsic_peripheral",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_hsic_peripheral),
+	.resource	= resources_hsic_peripheral,
+	.dev		= {
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+};
+
+static struct resource resources_hsusb_host[] = {
+	{
+		.start  = MSM9615_HSUSB_PHYS,
+		.end    = MSM9615_HSUSB_PHYS + MSM9615_HSUSB_PHYS - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = USB1_HS_IRQ,
+		.end    = USB1_HS_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static u64 dma_mask = DMA_BIT_MASK(32);
+struct platform_device msm_device_hsusb_host = {
+	.name           = "msm_hsusb_host",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(resources_hsusb_host),
+	.resource       = resources_hsusb_host,
+	.dev            = {
+		.dma_mask               = &dma_mask,
+		.coherent_dma_mask      = 0xffffffff,
+	},
+};
+
+static struct resource resources_hsic_host[] = {
+	{
+		.start	= MSM9615_HSIC_PHYS,
+		.end	= MSM9615_HSIC_PHYS + MSM9615_HSIC_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= USB_HSIC_IRQ,
+		.end	= USB_HSIC_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_hsic_host = {
+	.name		= "msm_hsic_host",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_hsic_host),
+	.resource	= resources_hsic_host,
+	.dev		= {
+		.dma_mask               = &dma_mask,
+		.coherent_dma_mask      = 0xffffffff,
+	},
+};
+
+static struct resource resources_uart_gsbi4[] = {
+	{
+		.start	= GSBI4_UARTDM_IRQ,
+		.end	= GSBI4_UARTDM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM_UART4DM_PHYS,
+		.end	= MSM_UART4DM_PHYS + PAGE_SIZE - 1,
+		.name	= "uartdm_resource",
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= MSM_GSBI4_PHYS,
+		.end	= MSM_GSBI4_PHYS + PAGE_SIZE - 1,
+		.name	= "gsbi_resource",
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm9615_device_uart_gsbi4 = {
+	.name	= "msm_serial_hsl",
+	.id	= 0,
+	.num_resources	= ARRAY_SIZE(resources_uart_gsbi4),
+	.resource	= resources_uart_gsbi4,
+};
+
+static struct resource resources_qup_i2c_gsbi5[] = {
+	{
+		.name	= "gsbi_qup_i2c_addr",
+		.start	= MSM_GSBI5_PHYS,
+		.end	= MSM_GSBI5_PHYS + 4 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_phys_addr",
+		.start	= MSM_GSBI5_QUP_PHYS,
+		.end	= MSM_GSBI5_QUP_PHYS + MSM_QUP_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_err_intr",
+		.start	= GSBI5_QUP_IRQ,
+		.end	= GSBI5_QUP_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name   = "i2c_clk",
+		.start     = MSM_GPIO_I2C_CLK,
+		.end       = MSM_GPIO_I2C_CLK,
+		.flags     = IORESOURCE_IO,
+	},
+	{
+		.name   = "i2c_sda",
+		.start     = MSM_GPIO_I2C_SDA,
+		.end       = MSM_GPIO_I2C_SDA,
+		.flags     = IORESOURCE_IO,
+
+	},
+};
+
+struct platform_device msm9615_device_qup_i2c_gsbi5 = {
+	.name		= "qup_i2c",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(resources_qup_i2c_gsbi5),
+	.resource	= resources_qup_i2c_gsbi5,
+};
+
+static struct resource resources_qup_spi_gsbi3[] = {
+	{
+		.name   = "spi_base",
+		.start  = MSM_GSBI3_QUP_PHYS,
+		.end    = MSM_GSBI3_QUP_PHYS + SZ_4K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "gsbi_base",
+		.start  = MSM_GSBI3_PHYS,
+		.end    = MSM_GSBI3_PHYS + 4 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "spi_irq_in",
+		.start  = GSBI3_QUP_IRQ,
+		.end    = GSBI3_QUP_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm9615_device_qup_spi_gsbi3 = {
+	.name		= "spi_qsd",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(resources_qup_spi_gsbi3),
+	.resource	= resources_qup_spi_gsbi3,
+};
+
+#define LPASS_SLIMBUS_PHYS	0x28080000
+#define LPASS_SLIMBUS_BAM_PHYS	0x28084000
+#define LPASS_SLIMBUS_SLEW	(MSM9615_TLMM_PHYS + 0x207C)
+/* Board info for the slimbus slave device */
+static struct resource slimbus_res[] = {
+	{
+		.start	= LPASS_SLIMBUS_PHYS,
+		.end	= LPASS_SLIMBUS_PHYS + 8191,
+		.flags	= IORESOURCE_MEM,
+		.name	= "slimbus_physical",
+	},
+	{
+		.start	= LPASS_SLIMBUS_BAM_PHYS,
+		.end	= LPASS_SLIMBUS_BAM_PHYS + 8191,
+		.flags	= IORESOURCE_MEM,
+		.name	= "slimbus_bam_physical",
+	},
+	{
+		.start	= LPASS_SLIMBUS_SLEW,
+		.end	= LPASS_SLIMBUS_SLEW + 4 - 1,
+		.flags	= IORESOURCE_MEM,
+		.name	= "slimbus_slew_reg",
+	},
+	{
+		.start	= SLIMBUS0_CORE_EE1_IRQ,
+		.end	= SLIMBUS0_CORE_EE1_IRQ,
+		.flags	= IORESOURCE_IRQ,
+		.name	= "slimbus_irq",
+	},
+	{
+		.start	= SLIMBUS0_BAM_EE1_IRQ,
+		.end	= SLIMBUS0_BAM_EE1_IRQ,
+		.flags	= IORESOURCE_IRQ,
+		.name	= "slimbus_bam_irq",
+	},
+};
+
+struct platform_device msm9615_slim_ctrl = {
+	.name	= "msm_slim_ctrl",
+	.id	= 1,
+	.num_resources	= ARRAY_SIZE(slimbus_res),
+	.resource	= slimbus_res,
+	.dev            = {
+		.coherent_dma_mask      = 0xffffffffULL,
+	},
+};
+
+struct platform_device msm_pcm = {
+	.name	= "msm-pcm-dsp",
+	.id	= -1,
+};
+
+struct platform_device msm_multi_ch_pcm = {
+	.name	= "msm-multi-ch-pcm-dsp",
+	.id	= -1,
+};
+
+struct platform_device msm_pcm_routing = {
+	.name	= "msm-pcm-routing",
+	.id	= -1,
+};
+
+struct platform_device msm_cpudai0 = {
+	.name	= "msm-dai-q6",
+	.id	= 0x4000,
+};
+
+struct platform_device msm_cpudai1 = {
+	.name	= "msm-dai-q6",
+	.id	= 0x4001,
+};
+
+struct platform_device msm_cpudai_bt_rx = {
+	.name   = "msm-dai-q6",
+	.id     = 0x3000,
+};
+
+struct platform_device msm_cpudai_bt_tx = {
+	.name   = "msm-dai-q6",
+	.id     = 0x3001,
+};
+
+/*
+ * Machine specific data for AUX PCM Interface
+ * which the driver will  be unware of.
+ */
+struct msm_dai_auxpcm_pdata auxpcm_pdata = {
+	.clk = "pcm_clk",
+	.mode_8k = {
+		.mode = AFE_PCM_CFG_MODE_PCM,
+		.sync = AFE_PCM_CFG_SYNC_INT,
+		.frame = AFE_PCM_CFG_FRM_256BPF,
+		.quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
+		.slot = 0,
+		.data = AFE_PCM_CFG_CDATAOE_MASTER,
+		.pcm_clk_rate = 2048000,
+	},
+	.mode_16k = {
+		.mode = AFE_PCM_CFG_MODE_PCM,
+		.sync = AFE_PCM_CFG_SYNC_INT,
+		.frame = AFE_PCM_CFG_FRM_256BPF,
+		.quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
+		.slot = 0,
+		.data = AFE_PCM_CFG_CDATAOE_MASTER,
+		.pcm_clk_rate = 4096000,
+	}
+};
+
+struct platform_device msm_cpudai_auxpcm_rx = {
+	.name = "msm-dai-q6",
+	.id = 2,
+	.dev = {
+		.platform_data = &auxpcm_pdata,
+	},
+};
+
+struct platform_device msm_cpudai_auxpcm_tx = {
+	.name = "msm-dai-q6",
+	.id = 3,
+	.dev = {
+		.platform_data = &auxpcm_pdata,
+	},
+};
+
+struct platform_device msm_cpu_fe = {
+	.name	= "msm-dai-fe",
+	.id	= -1,
+};
+
+struct platform_device msm_stub_codec = {
+	.name	= "msm-stub-codec",
+	.id	= 1,
+};
+
+struct platform_device msm_voice = {
+	.name	= "msm-pcm-voice",
+	.id	= -1,
+};
+
+struct platform_device msm_i2s_cpudai0 = {
+	.name   = "msm-dai-q6",
+	.id     = PRIMARY_I2S_RX,
+};
+
+struct platform_device msm_i2s_cpudai1 = {
+	.name   = "msm-dai-q6",
+	.id     = PRIMARY_I2S_TX,
+};
+struct platform_device msm_voip = {
+	.name	= "msm-voip-dsp",
+	.id	= -1,
+};
+
+struct platform_device msm_compr_dsp = {
+	.name	= "msm-compr-dsp",
+	.id	= -1,
+};
+
+struct platform_device msm_pcm_hostless = {
+	.name	= "msm-pcm-hostless",
+	.id	= -1,
+};
+
+struct platform_device msm_cpudai_afe_01_rx = {
+	.name = "msm-dai-q6",
+	.id = 0xE0,
+};
+
+struct platform_device msm_cpudai_afe_01_tx = {
+	.name = "msm-dai-q6",
+	.id = 0xF0,
+};
+
+struct platform_device msm_cpudai_afe_02_rx = {
+	.name = "msm-dai-q6",
+	.id = 0xF1,
+};
+
+struct platform_device msm_cpudai_afe_02_tx = {
+	.name = "msm-dai-q6",
+	.id = 0xE1,
+};
+
+struct platform_device msm_pcm_afe = {
+	.name	= "msm-pcm-afe",
+	.id	= -1,
+};
+
+static struct resource resources_ssbi_pmic1[] = {
+	{
+		.start  = MSM_PMIC1_SSBI_CMD_PHYS,
+		.end    = MSM_PMIC1_SSBI_CMD_PHYS + MSM_PMIC_SSBI_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm9615_device_ssbi_pmic1 = {
+	.name           = "msm_ssbi",
+	.id             = 0,
+	.resource       = resources_ssbi_pmic1,
+	.num_resources  = ARRAY_SIZE(resources_ssbi_pmic1),
+};
+
+static struct resource resources_sps[] = {
+	{
+		.name	= "pipe_mem",
+		.start	= 0x12800000,
+		.end	= 0x12800000 + 0x4000 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "bamdma_dma",
+		.start	= 0x12240000,
+		.end	= 0x12240000 + 0x1000 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "bamdma_bam",
+		.start	= 0x12244000,
+		.end	= 0x12244000 + 0x4000 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "bamdma_irq",
+		.start	= SPS_BAM_DMA_IRQ,
+		.end	= SPS_BAM_DMA_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct msm_sps_platform_data msm_sps_pdata = {
+	.bamdma_restricted_pipes = 0x06,
+};
+
+struct platform_device msm_device_sps = {
+	.name		= "msm_sps",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_sps),
+	.resource	= resources_sps,
+	.dev.platform_data = &msm_sps_pdata,
+};
+
+#define MSM_NAND_PHYS		0x1B400000
+static struct resource resources_nand[] = {
+	[0] = {
+		.name   = "msm_nand_dmac",
+		.start	= DMOV_NAND_CHAN,
+		.end	= DMOV_NAND_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	[1] = {
+		.name   = "msm_nand_phys",
+		.start  = MSM_NAND_PHYS,
+		.end    = MSM_NAND_PHYS + 0x7FF,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+struct flash_platform_data msm_nand_data = {
+	.parts		= NULL,
+	.nr_parts	= 0,
+};
+
+struct platform_device msm_device_nand = {
+	.name		= "msm_nand",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_nand),
+	.resource	= resources_nand,
+	.dev		= {
+		.platform_data	= &msm_nand_data,
+	},
+};
+
+struct platform_device msm_device_smd = {
+	.name		= "msm_smd",
+	.id		= -1,
+};
+
+struct platform_device msm_device_bam_dmux = {
+	.name		= "BAM_RMNT",
+	.id		= -1,
+};
+
+#ifdef CONFIG_HW_RANDOM_MSM
+/* PRNG device */
+#define MSM_PRNG_PHYS		0x1A500000
+static struct resource rng_resources = {
+	.flags = IORESOURCE_MEM,
+	.start = MSM_PRNG_PHYS,
+	.end   = MSM_PRNG_PHYS + SZ_512 - 1,
+};
+
+struct platform_device msm_device_rng = {
+	.name          = "msm_rng",
+	.id            = 0,
+	.num_resources = 1,
+	.resource      = &rng_resources,
+};
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+
+#define QCE_SIZE		0x10000
+#define QCE_0_BASE		0x18500000
+
+#define QCE_HW_KEY_SUPPORT	0
+#define QCE_SHA_HMAC_SUPPORT	1
+#define QCE_SHARE_CE_RESOURCE	1
+#define QCE_CE_SHARED		0
+
+static struct resource qcrypto_resources[] = {
+	[0] = {
+		.start = QCE_0_BASE,
+		.end = QCE_0_BASE + QCE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.name = "crypto_channels",
+		.start = DMOV_CE_IN_CHAN,
+		.end = DMOV_CE_OUT_CHAN,
+		.flags = IORESOURCE_DMA,
+	},
+	[2] = {
+		.name = "crypto_crci_in",
+		.start = DMOV_CE_IN_CRCI,
+		.end = DMOV_CE_IN_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+	[3] = {
+		.name = "crypto_crci_out",
+		.start = DMOV_CE_OUT_CRCI,
+		.end = DMOV_CE_OUT_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static struct resource qcedev_resources[] = {
+	[0] = {
+		.start = QCE_0_BASE,
+		.end = QCE_0_BASE + QCE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.name = "crypto_channels",
+		.start = DMOV_CE_IN_CHAN,
+		.end = DMOV_CE_OUT_CHAN,
+		.flags = IORESOURCE_DMA,
+	},
+	[2] = {
+		.name = "crypto_crci_in",
+		.start = DMOV_CE_IN_CRCI,
+		.end = DMOV_CE_IN_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+	[3] = {
+		.name = "crypto_crci_out",
+		.start = DMOV_CE_OUT_CRCI,
+		.end = DMOV_CE_OUT_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
+
+static struct msm_ce_hw_support qcrypto_ce_hw_suppport = {
+	.ce_shared = QCE_CE_SHARED,
+	.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
+	.hw_key_support = QCE_HW_KEY_SUPPORT,
+	.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+	.bus_scale_table = NULL,
+};
+
+struct platform_device msm9615_qcrypto_device = {
+	.name		= "qcrypto",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(qcrypto_resources),
+	.resource	= qcrypto_resources,
+	.dev		= {
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+		.platform_data = &qcrypto_ce_hw_suppport,
+	},
+};
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+
+static struct msm_ce_hw_support qcedev_ce_hw_suppport = {
+	.ce_shared = QCE_CE_SHARED,
+	.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
+	.hw_key_support = QCE_HW_KEY_SUPPORT,
+	.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+	.bus_scale_table = NULL,
+};
+
+struct platform_device msm9615_qcedev_device = {
+	.name		= "qce",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(qcedev_resources),
+	.resource	= qcedev_resources,
+	.dev		= {
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+		.platform_data = &qcedev_ce_hw_suppport,
+	},
+};
+#endif
+
+#define MSM_SDC1_BASE         0x12180000
+#define MSM_SDC1_DML_BASE     (MSM_SDC1_BASE + 0x800)
+#define MSM_SDC1_BAM_BASE     (MSM_SDC1_BASE + 0x2000)
+#define MSM_SDC2_BASE         0x12140000
+#define MSM_SDC2_DML_BASE     (MSM_SDC2_BASE + 0x800)
+#define MSM_SDC2_BAM_BASE     (MSM_SDC2_BASE + 0x2000)
+
+static struct resource resources_sdc1[] = {
+	{
+		.name   = "core_mem",
+		.flags  = IORESOURCE_MEM,
+		.start  = MSM_SDC1_BASE,
+		.end    = MSM_SDC1_DML_BASE - 1,
+	},
+	{
+		.name   = "core_irq",
+		.flags  = IORESOURCE_IRQ,
+		.start  = SDC1_IRQ_0,
+		.end    = SDC1_IRQ_0
+	},
+#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
+	{
+		.name   = "sdcc_dml_addr",
+		.start  = MSM_SDC1_DML_BASE,
+		.end    = MSM_SDC1_BAM_BASE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_addr",
+		.start  = MSM_SDC1_BAM_BASE,
+		.end    = MSM_SDC1_BAM_BASE + (2 * SZ_4K) - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_irq",
+		.start  = SDC1_BAM_IRQ,
+		.end    = SDC1_BAM_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+#endif
+};
+
+static struct resource resources_sdc2[] = {
+	{
+		.name   = "core_mem",
+		.flags  = IORESOURCE_MEM,
+		.start  = MSM_SDC2_BASE,
+		.end    = MSM_SDC2_DML_BASE - 1,
+	},
+	{
+		.name   = "core_irq",
+		.flags  = IORESOURCE_IRQ,
+		.start  = SDC2_IRQ_0,
+		.end    = SDC2_IRQ_0
+	},
+#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
+	{
+		.name   = "sdcc_dml_addr",
+		.start  = MSM_SDC2_DML_BASE,
+		.end    = MSM_SDC2_BAM_BASE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_addr",
+		.start  = MSM_SDC2_BAM_BASE,
+		.end    = MSM_SDC2_BAM_BASE + (2 * SZ_4K) - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_irq",
+		.start  = SDC2_BAM_IRQ,
+		.end    = SDC2_BAM_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+#endif
+};
+
+struct platform_device msm_device_sdc1 = {
+	.name           = "msm_sdcc",
+	.id             = 1,
+	.num_resources  = ARRAY_SIZE(resources_sdc1),
+	.resource       = resources_sdc1,
+	.dev            = {
+		.coherent_dma_mask      = 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_sdc2 = {
+	.name           = "msm_sdcc",
+	.id             = 2,
+	.num_resources  = ARRAY_SIZE(resources_sdc2),
+	.resource       = resources_sdc2,
+	.dev            = {
+		.coherent_dma_mask      = 0xffffffff,
+	},
+};
+
+static struct platform_device *msm_sdcc_devices[] __initdata = {
+	&msm_device_sdc1,
+	&msm_device_sdc2,
+};
+
+int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat)
+{
+	struct platform_device  *pdev;
+
+	if (controller < 1 || controller > 2)
+		return -EINVAL;
+
+	pdev = msm_sdcc_devices[controller - 1];
+	pdev->dev.platform_data = plat;
+	return platform_device_register(pdev);
+}
+
+#ifdef CONFIG_FB_MSM_EBI2
+static struct resource msm_ebi2_lcdc_resources[] = {
+	{
+		.name   = "base",
+		.start  = 0x1B300000,
+		.end    = 0x1B300000 + PAGE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "lcd01",
+		.start  = 0x1FC00000,
+		.end    = 0x1FC00000 + 0x80000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_ebi2_lcdc_device = {
+	.name   = "ebi2_lcd",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_ebi2_lcdc_resources),
+	.resource       = msm_ebi2_lcdc_resources,
+};
+#endif
+
+#ifdef CONFIG_CACHE_L2X0
+static int __init l2x0_cache_init(void)
+{
+	int aux_ctrl = 0;
+
+	/* Way Size 010(0x2) 32KB */
+	aux_ctrl = (0x1 << L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT) | \
+		   (0x2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) | \
+		   (0x1 << L2X0_AUX_CTRL_EVNT_MON_BUS_EN_SHIFT);
+
+	/* L2 Latency setting required by hardware. Default is 0x20
+	   which is no good.
+	 */
+	writel_relaxed(0x220, MSM_L2CC_BASE + L2X0_DATA_LATENCY_CTRL);
+	l2x0_init(MSM_L2CC_BASE, aux_ctrl, L2X0_AUX_CTRL_MASK);
+
+	return 0;
+}
+#else
+static int __init l2x0_cache_init(void){ return 0; }
+#endif
+
+struct msm_rpm_platform_data msm9615_rpm_data __initdata = {
+	.reg_base_addrs = {
+		[MSM_RPM_PAGE_STATUS] = MSM_RPM_BASE,
+		[MSM_RPM_PAGE_CTRL] = MSM_RPM_BASE + 0x400,
+		[MSM_RPM_PAGE_REQ] = MSM_RPM_BASE + 0x600,
+		[MSM_RPM_PAGE_ACK] = MSM_RPM_BASE + 0xa00,
+	},
+	.irq_ack = RPM_APCC_CPU0_GP_HIGH_IRQ,
+	.irq_err = RPM_APCC_CPU0_GP_LOW_IRQ,
+	.irq_wakeup = RPM_APCC_CPU0_WAKE_UP_IRQ,
+	.ipc_rpm_reg = MSM_APCS_GCC_BASE + 0x008,
+	.ipc_rpm_val = 4,
+	.target_id = {
+		MSM_RPM_MAP(9615, NOTIFICATION_CONFIGURED_0, NOTIFICATION, 4),
+		MSM_RPM_MAP(9615, NOTIFICATION_REGISTERED_0, NOTIFICATION, 4),
+		MSM_RPM_MAP(9615, INVALIDATE_0, INVALIDATE, 8),
+		MSM_RPM_MAP(9615, TRIGGER_TIMED_TO, TRIGGER_TIMED, 1),
+		MSM_RPM_MAP(9615, TRIGGER_TIMED_SCLK_COUNT, TRIGGER_TIMED, 1),
+		MSM_RPM_MAP(9615, RPM_CTL, RPM_CTL, 1),
+		MSM_RPM_MAP(9615, CXO_CLK, CXO_CLK, 1),
+		MSM_RPM_MAP(9615, SYSTEM_FABRIC_CLK, SYSTEM_FABRIC_CLK, 1),
+		MSM_RPM_MAP(9615, DAYTONA_FABRIC_CLK, DAYTONA_FABRIC_CLK, 1),
+		MSM_RPM_MAP(9615, SFPB_CLK, SFPB_CLK, 1),
+		MSM_RPM_MAP(9615, CFPB_CLK, CFPB_CLK, 1),
+		MSM_RPM_MAP(9615, EBI1_CLK, EBI1_CLK, 1),
+		MSM_RPM_MAP(9615, SYS_FABRIC_CFG_HALT_0,
+				SYS_FABRIC_CFG_HALT, 2),
+		MSM_RPM_MAP(9615, SYS_FABRIC_CFG_CLKMOD_0,
+				SYS_FABRIC_CFG_CLKMOD, 3),
+		MSM_RPM_MAP(9615, SYS_FABRIC_CFG_IOCTL,
+				SYS_FABRIC_CFG_IOCTL, 1),
+		MSM_RPM_MAP(9615, SYSTEM_FABRIC_ARB_0,
+				SYSTEM_FABRIC_ARB, 27),
+		MSM_RPM_MAP(9615, PM8018_S1_0, PM8018_S1, 2),
+		MSM_RPM_MAP(9615, PM8018_S2_0, PM8018_S2, 2),
+		MSM_RPM_MAP(9615, PM8018_S3_0, PM8018_S3, 2),
+		MSM_RPM_MAP(9615, PM8018_S4_0, PM8018_S4, 2),
+		MSM_RPM_MAP(9615, PM8018_S5_0, PM8018_S5, 2),
+		MSM_RPM_MAP(9615, PM8018_L1_0, PM8018_L1, 2),
+		MSM_RPM_MAP(9615, PM8018_L2_0, PM8018_L2, 2),
+		MSM_RPM_MAP(9615, PM8018_L3_0, PM8018_L3, 2),
+		MSM_RPM_MAP(9615, PM8018_L4_0, PM8018_L4, 2),
+		MSM_RPM_MAP(9615, PM8018_L5_0, PM8018_L5, 2),
+		MSM_RPM_MAP(9615, PM8018_L6_0, PM8018_L6, 2),
+		MSM_RPM_MAP(9615, PM8018_L7_0, PM8018_L7, 2),
+		MSM_RPM_MAP(9615, PM8018_L8_0, PM8018_L8, 2),
+		MSM_RPM_MAP(9615, PM8018_L9_0, PM8018_L9, 2),
+		MSM_RPM_MAP(9615, PM8018_L10_0, PM8018_L10, 2),
+		MSM_RPM_MAP(9615, PM8018_L11_0, PM8018_L11, 2),
+		MSM_RPM_MAP(9615, PM8018_L12_0, PM8018_L12, 2),
+		MSM_RPM_MAP(9615, PM8018_L13_0, PM8018_L13, 2),
+		MSM_RPM_MAP(9615, PM8018_L14_0, PM8018_L14, 2),
+		MSM_RPM_MAP(9615, PM8018_LVS1, PM8018_LVS1, 1),
+		MSM_RPM_MAP(9615, NCP_0, NCP, 2),
+		MSM_RPM_MAP(9615, CXO_BUFFERS, CXO_BUFFERS, 1),
+		MSM_RPM_MAP(9615, USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
+		MSM_RPM_MAP(9615, HDMI_SWITCH, HDMI_SWITCH, 1),
+	},
+	.target_status = {
+		MSM_RPM_STATUS_ID_MAP(9615, VERSION_MAJOR),
+		MSM_RPM_STATUS_ID_MAP(9615, VERSION_MINOR),
+		MSM_RPM_STATUS_ID_MAP(9615, VERSION_BUILD),
+		MSM_RPM_STATUS_ID_MAP(9615, SUPPORTED_RESOURCES_0),
+		MSM_RPM_STATUS_ID_MAP(9615, SUPPORTED_RESOURCES_1),
+		MSM_RPM_STATUS_ID_MAP(9615, SUPPORTED_RESOURCES_2),
+		MSM_RPM_STATUS_ID_MAP(9615, RESERVED_SUPPORTED_RESOURCES_0),
+		MSM_RPM_STATUS_ID_MAP(9615, SEQUENCE),
+		MSM_RPM_STATUS_ID_MAP(9615, RPM_CTL),
+		MSM_RPM_STATUS_ID_MAP(9615, CXO_CLK),
+		MSM_RPM_STATUS_ID_MAP(9615, SYSTEM_FABRIC_CLK),
+		MSM_RPM_STATUS_ID_MAP(9615, DAYTONA_FABRIC_CLK),
+		MSM_RPM_STATUS_ID_MAP(9615, SFPB_CLK),
+		MSM_RPM_STATUS_ID_MAP(9615, CFPB_CLK),
+		MSM_RPM_STATUS_ID_MAP(9615, EBI1_CLK),
+		MSM_RPM_STATUS_ID_MAP(9615, SYS_FABRIC_CFG_HALT),
+		MSM_RPM_STATUS_ID_MAP(9615, SYS_FABRIC_CFG_CLKMOD),
+		MSM_RPM_STATUS_ID_MAP(9615, SYS_FABRIC_CFG_IOCTL),
+		MSM_RPM_STATUS_ID_MAP(9615, SYSTEM_FABRIC_ARB),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_S1_0),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_S1_1),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_S2_0),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_S2_1),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_S3_0),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_S3_1),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_S4_0),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_S4_1),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_S5_0),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_S5_1),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_L1_0),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_L1_1),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_L2_0),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_L2_1),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_L3_0),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_L3_1),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_L4_0),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_L4_1),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_L5_0),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_L5_1),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_L6_0),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_L6_1),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_L7_0),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_L7_1),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_L8_0),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_L8_1),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_L9_0),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_L9_1),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_L10_0),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_L10_1),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_L11_0),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_L11_1),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_L12_0),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_L12_1),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_L13_0),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_L13_1),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_L14_0),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_L14_1),
+		MSM_RPM_STATUS_ID_MAP(9615, PM8018_LVS1),
+		MSM_RPM_STATUS_ID_MAP(9615, NCP_0),
+		MSM_RPM_STATUS_ID_MAP(9615, NCP_1),
+		MSM_RPM_STATUS_ID_MAP(9615, CXO_BUFFERS),
+		MSM_RPM_STATUS_ID_MAP(9615, USB_OTG_SWITCH),
+		MSM_RPM_STATUS_ID_MAP(9615, HDMI_SWITCH),
+	},
+	.target_ctrl_id = {
+		MSM_RPM_CTRL_MAP(9615, VERSION_MAJOR),
+		MSM_RPM_CTRL_MAP(9615, VERSION_MINOR),
+		MSM_RPM_CTRL_MAP(9615, VERSION_BUILD),
+		MSM_RPM_CTRL_MAP(9615, REQ_CTX_0),
+		MSM_RPM_CTRL_MAP(9615, REQ_SEL_0),
+		MSM_RPM_CTRL_MAP(9615, ACK_CTX_0),
+		MSM_RPM_CTRL_MAP(9615, ACK_SEL_0),
+	},
+	.sel_invalidate = MSM_RPM_9615_SEL_INVALIDATE,
+	.sel_notification = MSM_RPM_9615_SEL_NOTIFICATION,
+	.sel_last = MSM_RPM_9615_SEL_LAST,
+	.ver = {3, 0, 0},
+};
+
+struct platform_device msm9615_rpm_device = {
+	.name   = "msm_rpm",
+	.id     = -1,
+};
+
+static uint16_t msm_mpm_irqs_m2a[MSM_MPM_NR_MPM_IRQS] __initdata = {
+	[4] = MSM_GPIO_TO_INT(30),
+	[5] = MSM_GPIO_TO_INT(59),
+	[6] = MSM_GPIO_TO_INT(81),
+	[7] = MSM_GPIO_TO_INT(87),
+	[8] = MSM_GPIO_TO_INT(86),
+	[9] = MSM_GPIO_TO_INT(2),
+	[10] = MSM_GPIO_TO_INT(6),
+	[11] = MSM_GPIO_TO_INT(10),
+	[12] = MSM_GPIO_TO_INT(14),
+	[13] = MSM_GPIO_TO_INT(18),
+	[14] = MSM_GPIO_TO_INT(7),
+	[15] = MSM_GPIO_TO_INT(11),
+	[16] = MSM_GPIO_TO_INT(15),
+	[19] = MSM_GPIO_TO_INT(26),
+	[20] = MSM_GPIO_TO_INT(28),
+	[22] = USB_HSIC_IRQ,
+	[23] = MSM_GPIO_TO_INT(19),
+	[24] = MSM_GPIO_TO_INT(23),
+	[26] = MSM_GPIO_TO_INT(3),
+	[27] = MSM_GPIO_TO_INT(68),
+	[29] = MSM_GPIO_TO_INT(78),
+	[31] = MSM_GPIO_TO_INT(0),
+	[32] = MSM_GPIO_TO_INT(4),
+	[33] = MSM_GPIO_TO_INT(22),
+	[34] = MSM_GPIO_TO_INT(17),
+	[37] = MSM_GPIO_TO_INT(20),
+	[39] = MSM_GPIO_TO_INT(84),
+	[40] = USB1_HS_IRQ,
+	[42] = MSM_GPIO_TO_INT(24),
+	[43] = MSM_GPIO_TO_INT(79),
+	[44] = MSM_GPIO_TO_INT(80),
+	[45] = MSM_GPIO_TO_INT(82),
+	[46] = MSM_GPIO_TO_INT(85),
+	[47] = MSM_GPIO_TO_INT(45),
+	[48] = MSM_GPIO_TO_INT(50),
+	[49] = MSM_GPIO_TO_INT(51),
+	[50] = MSM_GPIO_TO_INT(69),
+	[51] = MSM_GPIO_TO_INT(77),
+	[52] = MSM_GPIO_TO_INT(1),
+	[53] = MSM_GPIO_TO_INT(5),
+	[54] = MSM_GPIO_TO_INT(40),
+	[55] = MSM_GPIO_TO_INT(27),
+};
+
+static uint16_t msm_mpm_bypassed_apps_irqs[] __initdata = {
+	TLMM_MSM_SUMMARY_IRQ,
+	RPM_APCC_CPU0_GP_HIGH_IRQ,
+	RPM_APCC_CPU0_GP_MEDIUM_IRQ,
+	RPM_APCC_CPU0_GP_LOW_IRQ,
+	RPM_APCC_CPU0_WAKE_UP_IRQ,
+	MSS_TO_APPS_IRQ_0,
+	MSS_TO_APPS_IRQ_1,
+	LPASS_SCSS_GP_LOW_IRQ,
+	LPASS_SCSS_GP_MEDIUM_IRQ,
+	LPASS_SCSS_GP_HIGH_IRQ,
+	SPS_MTI_31,
+	A2_BAM_IRQ,
+};
+
+struct msm_mpm_device_data msm9615_mpm_dev_data __initdata = {
+	.irqs_m2a = msm_mpm_irqs_m2a,
+	.irqs_m2a_size = ARRAY_SIZE(msm_mpm_irqs_m2a),
+	.bypassed_apps_irqs = msm_mpm_bypassed_apps_irqs,
+	.bypassed_apps_irqs_size = ARRAY_SIZE(msm_mpm_bypassed_apps_irqs),
+	.mpm_request_reg_base = MSM_RPM_BASE + 0x9d8,
+	.mpm_status_reg_base = MSM_RPM_BASE + 0xdf8,
+	.mpm_apps_ipc_reg = MSM_APCS_GCC_BASE + 0x008,
+	.mpm_apps_ipc_val =  BIT(1),
+	.mpm_ipc_irq = RPM_APCC_CPU0_GP_MEDIUM_IRQ,
+};
+
+static uint8_t spm_wfi_cmd_sequence[] __initdata = {
+	0x00, 0x03, 0x00, 0x0f,
+};
+
+static uint8_t spm_power_collapse_without_rpm[] __initdata = {
+	0x34, 0x24, 0x14, 0x04,
+	0x54, 0x03, 0x54, 0x04,
+	0x14, 0x24, 0x3e, 0x0f,
+};
+
+static uint8_t spm_power_collapse_with_rpm[] __initdata = {
+	0x34, 0x24, 0x14, 0x04,
+	0x54, 0x07, 0x54, 0x04,
+	0x14, 0x24, 0x3e, 0x0f,
+};
+
+static struct msm_spm_seq_entry msm_spm_seq_list[] __initdata = {
+	[0] = {
+		.mode = MSM_SPM_MODE_CLOCK_GATING,
+		.notify_rpm = false,
+		.cmd = spm_wfi_cmd_sequence,
+	},
+	[1] = {
+		.mode = MSM_SPM_MODE_POWER_COLLAPSE,
+		.notify_rpm = false,
+		.cmd = spm_power_collapse_without_rpm,
+	},
+	[2] = {
+		.mode = MSM_SPM_MODE_POWER_COLLAPSE,
+		.notify_rpm = true,
+		.cmd = spm_power_collapse_with_rpm,
+	},
+};
+
+static struct msm_spm_platform_data msm_spm_data[] __initdata = {
+	[0] = {
+		.reg_base_addr = MSM_SAW0_BASE,
+		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
+		.reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1001,
+		.num_modes = ARRAY_SIZE(msm_spm_seq_list),
+		.modes = msm_spm_seq_list,
+	},
+};
+
+static struct msm_rpmrs_level msm_rpmrs_levels[] __initdata = {
+	{
+		MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT,
+		MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
+		true,
+		100, 8000, 100000, 1,
+	},
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
+		MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
+		true,
+		2000, 5000, 60100000, 3000,
+	},
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+		MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
+		false,
+		6300, 5000, 60350000, 3500,
+	},
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, MAX, ACTIVE),
+		false,
+		13300, 2000, 71850000, 6800,
+	},
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, RET_HIGH, RET_LOW),
+		false,
+		28300, 0, 76350000, 9800,
+	},
+};
+
+static struct msm_rpmrs_platform_data msm_rpmrs_data __initdata = {
+	.levels = &msm_rpmrs_levels[0],
+	.num_levels = ARRAY_SIZE(msm_rpmrs_levels),
+	.vdd_mem_levels  = {
+		[MSM_RPMRS_VDD_MEM_RET_LOW]     = 750000,
+		[MSM_RPMRS_VDD_MEM_RET_HIGH]    = 750000,
+		[MSM_RPMRS_VDD_MEM_ACTIVE]      = 1050000,
+		[MSM_RPMRS_VDD_MEM_MAX]         = 1150000,
+	},
+	.vdd_dig_levels = {
+		[MSM_RPMRS_VDD_DIG_RET_LOW]     = 500000,
+		[MSM_RPMRS_VDD_DIG_RET_HIGH]    = 750000,
+		[MSM_RPMRS_VDD_DIG_ACTIVE]      = 950000,
+		[MSM_RPMRS_VDD_DIG_MAX]         = 1150000,
+	},
+	.vdd_mask = 0x7FFFFF,
+	.rpmrs_target_id = {
+		[MSM_RPMRS_ID_PXO_CLK]          = MSM_RPM_ID_CXO_CLK,
+		[MSM_RPMRS_ID_L2_CACHE_CTL]     = MSM_RPM_ID_LAST,
+		[MSM_RPMRS_ID_VDD_DIG_0]        = MSM_RPM_ID_PM8018_S1_0,
+		[MSM_RPMRS_ID_VDD_DIG_1]        = MSM_RPM_ID_PM8018_S1_1,
+		[MSM_RPMRS_ID_VDD_MEM_0]        = MSM_RPM_ID_PM8018_L9_0,
+		[MSM_RPMRS_ID_VDD_MEM_1]        = MSM_RPM_ID_PM8018_L9_1,
+		[MSM_RPMRS_ID_RPM_CTL]          = MSM_RPM_ID_RPM_CTL,
+	},
+};
+
+static struct msm_rpmstats_platform_data msm_rpm_stat_pdata = {
+	.phys_addr_base = 0x0010D204,
+	.phys_size = SZ_8K,
+};
+
+struct platform_device msm9615_rpm_stat_device = {
+	.name = "msm_rpm_stat",
+	.id = -1,
+	.dev = {
+		.platform_data = &msm_rpm_stat_pdata,
+	},
+};
+
+static struct msm_rpm_log_platform_data msm_rpm_log_pdata = {
+	.phys_addr_base = 0x0010AC00,
+	.reg_offsets = {
+		[MSM_RPM_LOG_PAGE_INDICES] = 0x00000080,
+		[MSM_RPM_LOG_PAGE_BUFFER]  = 0x000000A0,
+	},
+	.phys_size = SZ_8K,
+	.log_len = 4096,		  /* log's buffer length in bytes */
+	.log_len_mask = (4096 >> 2) - 1,  /* length mask in units of u32 */
+};
+
+struct platform_device msm9615_rpm_log_device = {
+	.name	= "msm_rpm_log",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &msm_rpm_log_pdata,
+	},
+};
+
+uint32_t __init msm9615_rpm_get_swfi_latency(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(msm_rpmrs_levels); i++) {
+		if (msm_rpmrs_levels[i].sleep_mode ==
+			MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)
+				return msm_rpmrs_levels[i].latency_us;
+	}
+	return 0;
+}
+
+struct android_usb_platform_data msm_android_usb_pdata;
+
+struct platform_device msm_android_usb_device = {
+	.name	= "android_usb",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &msm_android_usb_pdata,
+	},
+};
+
+void __init msm9615_device_init(void)
+{
+	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
+	BUG_ON(msm_rpm_init(&msm9615_rpm_data));
+	BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
+	msm_android_usb_pdata.swfi_latency =
+		msm_rpmrs_levels[0].latency_us;
+
+}
+
+#define MSM_SHARED_RAM_PHYS 0x40000000
+void __init msm9615_map_io(void)
+{
+	msm_shared_ram_phys = MSM_SHARED_RAM_PHYS;
+	msm_map_msm9615_io();
+	l2x0_cache_init();
+	if (socinfo_init() < 0)
+		pr_err("socinfo_init() failed!\n");
+}
+
+void __init msm9615_init_irq(void)
+{
+	struct msm_mpm_device_data *data = NULL;
+
+#ifdef CONFIG_MSM_MPM
+	data = &msm9615_mpm_dev_data;
+#endif
+
+	msm_mpm_irq_extn_init(data);
+	gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE,
+						(void *)MSM_QGIC_CPU_BASE);
+}
+
+struct platform_device msm_bus_9615_sys_fabric = {
+	.name  = "msm_bus_fabric",
+	.id    =  MSM_BUS_FAB_SYSTEM,
+};
+
+struct platform_device msm_bus_def_fab = {
+	.name  = "msm_bus_fabric",
+	.id    =  MSM_BUS_FAB_DEFAULT,
+};
+
+#ifdef CONFIG_FB_MSM_EBI2
+static void __init msm_register_device(struct platform_device *pdev, void *data)
+{
+	int ret;
+
+	pdev->dev.platform_data = data;
+
+	ret = platform_device_register(pdev);
+	if (ret)
+		dev_err(&pdev->dev,
+			  "%s: platform_device_register() failed = %d\n",
+			  __func__, ret);
+}
+
+void __init msm_fb_register_device(char *name, void *data)
+{
+	if (!strncmp(name, "ebi2", 4))
+		msm_register_device(&msm_ebi2_lcdc_device, data);
+	else
+		pr_err("%s: unknown device! %s\n", __func__, name);
+}
+#endif
diff --git a/arch/arm/mach-msm/devices-fsm9xxx.c b/arch/arm/mach-msm/devices-fsm9xxx.c
new file mode 100644
index 0000000..777b6d6
--- /dev/null
+++ b/arch/arm/mach-msm/devices-fsm9xxx.c
@@ -0,0 +1,411 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/platform_device.h>
+
+#include <linux/dma-mapping.h>
+#include <mach/irqs.h>
+#include <mach/msm_iomap.h>
+#include <mach/dma.h>
+#include <mach/board.h>
+
+#include "devices.h"
+#include "smd_private.h"
+#include "clock-local.h"
+#include "msm_watchdog.h"
+
+#include <asm/mach/flash.h>
+#include <asm/mach/mmc.h>
+
+/*
+ * UARTs
+ */
+
+static struct resource resources_uart1[] = {
+	{
+		.start	= INT_UART1,
+		.end	= INT_UART1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM_UART1_PHYS,
+		.end	= MSM_UART1_PHYS + MSM_UART1_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_device_uart1 = {
+	.name	= "msm_serial",
+	.id	= 0,
+	.num_resources	= ARRAY_SIZE(resources_uart1),
+	.resource	= resources_uart1,
+};
+
+static struct resource resources_uart2[] = {
+	{
+		.start	= INT_UART2,
+		.end	= INT_UART2,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM_UART2_PHYS,
+		.end	= MSM_UART2_PHYS + MSM_UART2_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_device_uart2 = {
+	.name	= "msm_serial",
+	.id	= 1,
+	.num_resources	= ARRAY_SIZE(resources_uart2),
+	.resource	= resources_uart2,
+};
+
+/*
+ * SSBIs
+ */
+
+#ifdef CONFIG_MSM_SSBI
+#define MSM_SSBI1_PHYS          0x94080000
+#define MSM_SSBI_PMIC1_PHYS     MSM_SSBI1_PHYS
+static struct resource msm_ssbi_pmic1_resources[] = {
+	{
+		.start  = MSM_SSBI_PMIC1_PHYS,
+		.end    = MSM_SSBI_PMIC1_PHYS + SZ_4K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_device_ssbi_pmic1 = {
+	.name           = "msm_ssbi",
+	.id             = 0,
+	.resource       = msm_ssbi_pmic1_resources,
+	.num_resources  = ARRAY_SIZE(msm_ssbi_pmic1_resources),
+};
+#endif
+
+#ifdef CONFIG_I2C_SSBI
+#define MSM_SSBI2_PHYS		0x94090000
+#define MSM_SSBI2_SIZE		SZ_4K
+
+static struct resource msm_ssbi2_resources[] = {
+	{
+		.name   = "ssbi_base",
+		.start  = MSM_SSBI2_PHYS,
+		.end    = MSM_SSBI2_PHYS + MSM_SSBI2_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_device_ssbi2 = {
+	.name		= "i2c_ssbi",
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(msm_ssbi2_resources),
+	.resource	= msm_ssbi2_resources,
+};
+
+#define MSM_SSBI3_PHYS		0x940c0000
+#define MSM_SSBI3_SIZE		SZ_4K
+
+static struct resource msm_ssbi3_resources[] = {
+	{
+		.name   = "ssbi_base",
+		.start	= MSM_SSBI3_PHYS,
+		.end	= MSM_SSBI3_PHYS + MSM_SSBI3_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_device_ssbi3 = {
+	.name		= "i2c_ssbi",
+	.id		= 2,
+	.num_resources	= ARRAY_SIZE(msm_ssbi3_resources),
+	.resource	= msm_ssbi3_resources,
+};
+
+#endif /* CONFIG_I2C_SSBI */
+
+/*
+ * GSBI
+ */
+
+#ifdef CONFIG_I2C_QUP
+
+#define MSM_GSBI1_PHYS		0x81200000
+#define MSM_GSBI1_QUP_PHYS	0x81a00000
+
+static struct resource gsbi1_qup_i2c_resources[] = {
+	{
+		.name	= "qup_phys_addr",
+		.start	= MSM_GSBI1_QUP_PHYS,
+		.end	= MSM_GSBI1_QUP_PHYS + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "gsbi_qup_i2c_addr",
+		.start	= MSM_GSBI1_PHYS,
+		.end	= MSM_GSBI1_PHYS + 4 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_err_intr",
+		.start	= INT_GSBI_QUP_ERROR,
+		.end	= INT_GSBI_QUP_ERROR,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_gsbi1_qup_i2c_device = {
+	.name		= "qup_i2c",
+	.id		= 3,
+	.num_resources	= ARRAY_SIZE(gsbi1_qup_i2c_resources),
+	.resource	= gsbi1_qup_i2c_resources,
+};
+
+#endif /* CONFIG_I2C_QUP */
+
+/*
+ * NAND
+ */
+
+#define MSM_NAND_PHYS		0x81600000
+#define MSM_NAND_SIZE		SZ_4K
+#define MSM_EBI2_CTRL_PHYS      0x81400000
+#define MSM_EBI2_CTRL_SIZE	SZ_4K
+
+static struct resource resources_nand[] = {
+	[0] = {
+		.name   = "msm_nand_dmac",
+		.start	= DMOV_NAND_CHAN,
+		.end	= DMOV_NAND_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	[1] = {
+		.name   = "msm_nand_phys",
+		.start  = MSM_NAND_PHYS,
+		.end    = MSM_NAND_PHYS + MSM_NAND_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	[3] = {
+		.name   = "ebi2_reg_base",
+		.start  = MSM_EBI2_CTRL_PHYS,
+		.end    = MSM_EBI2_CTRL_PHYS + MSM_EBI2_CTRL_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+struct flash_platform_data msm_nand_data = {
+	.parts		= NULL,
+	.nr_parts	= 0,
+	.interleave     = 0,
+};
+
+struct platform_device msm_device_nand = {
+	.name		= "msm_nand",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_nand),
+	.resource	= resources_nand,
+	.dev		= {
+		.platform_data	= &msm_nand_data,
+	},
+};
+
+/*
+ * SMD
+ */
+
+struct platform_device msm_device_smd = {
+	.name	= "msm_smd",
+	.id	= -1,
+};
+
+/*
+ * ADM
+ */
+
+static struct resource msm_dmov_resource[] = {
+	{
+		.start = INT_ADM_AARM,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = 0x94610000,
+		.end = 0x94610000 + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct msm_dmov_pdata msm_dmov_pdata = {
+	.sd = 3,
+	.sd_size = 0x400,
+};
+
+struct platform_device msm_device_dmov = {
+	.name	= "msm_dmov",
+	.id	= -1,
+	.resource = msm_dmov_resource,
+	.num_resources = ARRAY_SIZE(msm_dmov_resource),
+	.dev = {
+		.platform_data = &msm_dmov_pdata,
+	},
+};
+
+/*
+ * SDC
+ */
+
+#define MSM_SDC1_PHYS		0x80A00000
+#define MSM_SDC1_SIZE		SZ_4K
+
+static struct resource resources_sdc1[] = {
+	{
+		.start	= MSM_SDC1_PHYS,
+		.end	= MSM_SDC1_PHYS + MSM_SDC1_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SDC1_0,
+		.end	= INT_SDC1_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= DMOV_SDC1_CHAN,
+		.end	= DMOV_SDC1_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+struct platform_device msm_device_sdc1 = {
+	.name		= "msm_sdcc",
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(resources_sdc1),
+	.resource	= resources_sdc1,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+static struct platform_device *msm_sdcc_devices[] __initdata = {
+	&msm_device_sdc1,
+};
+
+int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat)
+{
+	struct platform_device	*pdev;
+
+	if (controller != 1)
+		return -EINVAL;
+
+	pdev = msm_sdcc_devices[controller-1];
+	pdev->dev.platform_data = plat;
+	return platform_device_register(pdev);
+}
+
+/*
+ * QFEC
+ */
+
+# define QFEC_MAC_IRQ           INT_SBD_IRQ
+# define QFEC_MAC_BASE          0x40000000
+# define QFEC_CLK_BASE          0x94020000
+
+# define QFEC_MAC_SIZE          0x2000
+# define QFEC_CLK_SIZE          0x18100
+
+# define QFEC_MAC_FUSE_BASE     0x80004210
+# define QFEC_MAC_FUSE_SIZE     16
+
+static struct resource qfec_resources[] = {
+	[0] = {
+		.start = QFEC_MAC_BASE,
+		.end   = QFEC_MAC_BASE + QFEC_MAC_SIZE,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = QFEC_MAC_IRQ,
+		.end   = QFEC_MAC_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	[2] = {
+		.start = QFEC_CLK_BASE,
+		.end   = QFEC_CLK_BASE + QFEC_CLK_SIZE,
+		.flags = IORESOURCE_IO,
+	},
+	[3] = {
+		.start = QFEC_MAC_FUSE_BASE,
+		.end   = QFEC_MAC_FUSE_BASE + QFEC_MAC_FUSE_SIZE,
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+struct platform_device qfec_device = {
+	.name           = "qfec",
+	.id             = 0,
+	.num_resources  = ARRAY_SIZE(qfec_resources),
+	.resource       = qfec_resources,
+};
+
+/*
+ * FUSE
+ */
+
+#if defined(CONFIG_QFP_FUSE)
+
+char fuse_regulator_name[] = "8058_lvs0";
+
+struct resource qfp_fuse_resources[] = {
+	{
+		.start = (uint32_t) MSM_QFP_FUSE_BASE,
+		.end   = (uint32_t) MSM_QFP_FUSE_BASE + MSM_QFP_FUSE_SIZE,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device fsm_qfp_fuse_device = {
+	.name           = "qfp_fuse_driver",
+	.id             = 0,
+	.dev = {.platform_data = fuse_regulator_name},
+	.num_resources  = ARRAY_SIZE(qfp_fuse_resources),
+	.resource       = qfp_fuse_resources,
+};
+
+#endif
+
+/*
+ * XO
+ */
+
+struct platform_device fsm_xo_device = {
+	.name   = "fsm_xo_driver",
+	.id     = -1,
+};
+
+/*
+ * Watchdog
+ */
+
+static struct msm_watchdog_pdata fsm_watchdog_pdata = {
+	.pet_time = 10000,
+	.bark_time = 11000,
+	.has_secure = false,
+	.has_vic = true,
+};
+
+struct platform_device fsm9xxx_device_watchdog = {
+	.name = "msm_watchdog",
+	.id = -1,
+	.dev = {
+		.platform_data = &fsm_watchdog_pdata,
+	},
+};
+
diff --git a/arch/arm/mach-msm/devices-iommu.c b/arch/arm/mach-msm/devices-iommu.c
index 0fb7a17..1432902 100644
--- a/arch/arm/mach-msm/devices-iommu.c
+++ b/arch/arm/mach-msm/devices-iommu.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
@@ -8,11 +8,6 @@
  * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
  */
 
 #include <linux/kernel.h>
@@ -21,6 +16,7 @@
 #include <linux/module.h>
 #include <mach/irqs.h>
 #include <mach/iommu.h>
+#include <mach/socinfo.h>
 
 static struct resource msm_iommu_jpegd_resources[] = {
 	{
@@ -31,14 +27,14 @@
 	},
 	{
 		.name = "nonsecure_irq",
-		.start = SMMU_JPEGD_CB_SC_NON_SECURE_IRQ,
-		.end   = SMMU_JPEGD_CB_SC_NON_SECURE_IRQ,
+		.start = 98,
+		.end   = 98,
 		.flags = IORESOURCE_IRQ,
 	},
 	{
 		.name = "secure_irq",
-		.start = SMMU_JPEGD_CB_SC_SECURE_IRQ,
-		.end   = SMMU_JPEGD_CB_SC_SECURE_IRQ,
+		.start = 97,
+		.end   = 97,
 		.flags = IORESOURCE_IRQ,
 	},
 };
@@ -52,14 +48,14 @@
 	},
 	{
 		.name = "nonsecure_irq",
-		.start = SMMU_VPE_CB_SC_NON_SECURE_IRQ,
-		.end   = SMMU_VPE_CB_SC_NON_SECURE_IRQ,
+		.start = 84,
+		.end   = 84,
 		.flags = IORESOURCE_IRQ,
 	},
 	{
 		.name = "secure_irq",
-		.start = SMMU_VPE_CB_SC_SECURE_IRQ,
-		.end   = SMMU_VPE_CB_SC_SECURE_IRQ,
+		.start = 83,
+		.end   = 83,
 		.flags = IORESOURCE_IRQ,
 	},
 };
@@ -73,14 +69,14 @@
 	},
 	{
 		.name = "nonsecure_irq",
-		.start = SMMU_MDP0_CB_SC_NON_SECURE_IRQ,
-		.end   = SMMU_MDP0_CB_SC_NON_SECURE_IRQ,
+		.start = 96,
+		.end   = 96,
 		.flags = IORESOURCE_IRQ,
 	},
 	{
 		.name = "secure_irq",
-		.start = SMMU_MDP0_CB_SC_SECURE_IRQ,
-		.end   = SMMU_MDP0_CB_SC_SECURE_IRQ,
+		.start = 95,
+		.end   = 95,
 		.flags = IORESOURCE_IRQ,
 	},
 };
@@ -94,14 +90,14 @@
 	},
 	{
 		.name = "nonsecure_irq",
-		.start = SMMU_MDP1_CB_SC_NON_SECURE_IRQ,
-		.end   = SMMU_MDP1_CB_SC_NON_SECURE_IRQ,
+		.start = 94,
+		.end   = 94,
 		.flags = IORESOURCE_IRQ,
 	},
 	{
 		.name = "secure_irq",
-		.start = SMMU_MDP1_CB_SC_SECURE_IRQ,
-		.end   = SMMU_MDP1_CB_SC_SECURE_IRQ,
+		.start = 93,
+		.end   = 93,
 		.flags = IORESOURCE_IRQ,
 	},
 };
@@ -115,14 +111,14 @@
 	},
 	{
 		.name = "nonsecure_irq",
-		.start = SMMU_ROT_CB_SC_NON_SECURE_IRQ,
-		.end   = SMMU_ROT_CB_SC_NON_SECURE_IRQ,
+		.start = 92,
+		.end   = 92,
 		.flags = IORESOURCE_IRQ,
 	},
 	{
 		.name = "secure_irq",
-		.start = SMMU_ROT_CB_SC_SECURE_IRQ,
-		.end   = SMMU_ROT_CB_SC_SECURE_IRQ,
+		.start = 91,
+		.end   = 91,
 		.flags = IORESOURCE_IRQ,
 	},
 };
@@ -136,14 +132,14 @@
 	},
 	{
 		.name = "nonsecure_irq",
-		.start = SMMU_IJPEG_CB_SC_NON_SECURE_IRQ,
-		.end   = SMMU_IJPEG_CB_SC_NON_SECURE_IRQ,
+		.start = 100,
+		.end   = 100,
 		.flags = IORESOURCE_IRQ,
 	},
 	{
 		.name = "secure_irq",
-		.start = SMMU_IJPEG_CB_SC_SECURE_IRQ,
-		.end   = SMMU_IJPEG_CB_SC_SECURE_IRQ,
+		.start = 99,
+		.end   = 99,
 		.flags = IORESOURCE_IRQ,
 	},
 };
@@ -157,14 +153,14 @@
 	},
 	{
 		.name = "nonsecure_irq",
-		.start = SMMU_VFE_CB_SC_NON_SECURE_IRQ,
-		.end   = SMMU_VFE_CB_SC_NON_SECURE_IRQ,
+		.start = 86,
+		.end   = 86,
 		.flags = IORESOURCE_IRQ,
 	},
 	{
 		.name = "secure_irq",
-		.start = SMMU_VFE_CB_SC_SECURE_IRQ,
-		.end   = SMMU_VFE_CB_SC_SECURE_IRQ,
+		.start = 85,
+		.end   = 85,
 		.flags = IORESOURCE_IRQ,
 	},
 };
@@ -178,14 +174,14 @@
 	},
 	{
 		.name = "nonsecure_irq",
-		.start = SMMU_VCODEC_A_CB_SC_NON_SECURE_IRQ,
-		.end   = SMMU_VCODEC_A_CB_SC_NON_SECURE_IRQ,
+		.start = 90,
+		.end   = 90,
 		.flags = IORESOURCE_IRQ,
 	},
 	{
 		.name = "secure_irq",
-		.start = SMMU_VCODEC_A_CB_SC_SECURE_IRQ,
-		.end   = SMMU_VCODEC_A_CB_SC_SECURE_IRQ,
+		.start = 89,
+		.end   = 89,
 		.flags = IORESOURCE_IRQ,
 	},
 };
@@ -199,14 +195,14 @@
 	},
 	{
 		.name = "nonsecure_irq",
-		.start = SMMU_VCODEC_B_CB_SC_NON_SECURE_IRQ,
-		.end   = SMMU_VCODEC_B_CB_SC_NON_SECURE_IRQ,
+		.start = 88,
+		.end   = 88,
 		.flags = IORESOURCE_IRQ,
 	},
 	{
 		.name = "secure_irq",
-		.start = SMMU_VCODEC_B_CB_SC_SECURE_IRQ,
-		.end   = SMMU_VCODEC_B_CB_SC_SECURE_IRQ,
+		.start = 87,
+		.end   = 87,
 		.flags = IORESOURCE_IRQ,
 	},
 };
@@ -220,14 +216,35 @@
 	},
 	{
 		.name = "nonsecure_irq",
-		.start = SMMU_GFX3D_CB_SC_NON_SECURE_IRQ,
-		.end   = SMMU_GFX3D_CB_SC_NON_SECURE_IRQ,
+		.start = 102,
+		.end   = 102,
 		.flags = IORESOURCE_IRQ,
 	},
 	{
 		.name = "secure_irq",
-		.start = SMMU_GFX3D_CB_SC_SECURE_IRQ,
-		.end   = SMMU_GFX3D_CB_SC_SECURE_IRQ,
+		.start = 101,
+		.end   = 101,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct resource msm_iommu_gfx3d1_resources[] = {
+	{
+		.start = 0x07D00000,
+		.end   = 0x07D00000 + SZ_1M - 1,
+		.name  = "physbase",
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = "nonsecure_irq",
+		.start = 243,
+		.end   = 243,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name = "secure_irq",
+		.start = 242,
+		.end   = 242,
 		.flags = IORESOURCE_IRQ,
 	},
 };
@@ -241,14 +258,14 @@
 	},
 	{
 		.name = "nonsecure_irq",
-		.start = SMMU_GFX2D0_CB_SC_NON_SECURE_IRQ,
-		.end   = SMMU_GFX2D0_CB_SC_NON_SECURE_IRQ,
+		.start = 104,
+		.end   = 104,
 		.flags = IORESOURCE_IRQ,
 	},
 	{
 		.name = "secure_irq",
-		.start = SMMU_GFX2D0_CB_SC_SECURE_IRQ,
-		.end   = SMMU_GFX2D0_CB_SC_SECURE_IRQ,
+		.start = 103,
+		.end   = 103,
 		.flags = IORESOURCE_IRQ,
 	},
 };
@@ -262,14 +279,35 @@
 	},
 	{
 		.name = "nonsecure_irq",
-		.start = SMMU_GFX2D1_CB_SC_NON_SECURE_IRQ,
-		.end   = SMMU_GFX2D1_CB_SC_NON_SECURE_IRQ,
+		.start = 243,
+		.end   = 243,
 		.flags = IORESOURCE_IRQ,
 	},
 	{
 		.name = "secure_irq",
-		.start = SMMU_GFX2D1_CB_SC_SECURE_IRQ,
-		.end   = SMMU_GFX2D1_CB_SC_SECURE_IRQ,
+		.start = 242,
+		.end   = 242,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct resource msm_iommu_vcap_resources[] = {
+	{
+		.start = 0x07200000,
+		.end   = 0x07200000 + SZ_1M - 1,
+		.name  = "physbase",
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = "nonsecure_irq",
+		.start = 269,
+		.end   = 269,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name = "secure_irq",
+		.start = 268,
+		.end   = 268,
 		.flags = IORESOURCE_IRQ,
 	},
 };
@@ -327,16 +365,30 @@
 static struct msm_iommu_dev gfx3d_iommu = {
 	.name = "gfx3d",
 	.ncb = 3,
+	.ttbr_split = 2,
+};
+
+static struct msm_iommu_dev gfx3d1_iommu = {
+	.name = "gfx3d1",
+	.ncb = 3,
+	.ttbr_split = 2,
 };
 
 static struct msm_iommu_dev gfx2d0_iommu = {
 	.name = "gfx2d0",
 	.ncb = 2,
+	.ttbr_split = 2,
 };
 
 static struct msm_iommu_dev gfx2d1_iommu = {
 	.name = "gfx2d1",
 	.ncb = 2,
+	.ttbr_split = 2,
+};
+
+static struct msm_iommu_dev vcap_iommu = {
+	.name = "vcap",
+	.ncb = 2,
 };
 
 static struct platform_device msm_device_iommu_jpegd = {
@@ -344,6 +396,7 @@
 	.id = 0,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &jpegd_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_jpegd_resources),
 	.resource = msm_iommu_jpegd_resources,
@@ -354,6 +407,7 @@
 	.id = 1,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &vpe_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_vpe_resources),
 	.resource = msm_iommu_vpe_resources,
@@ -364,6 +418,7 @@
 	.id = 2,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &mdp0_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_mdp0_resources),
 	.resource = msm_iommu_mdp0_resources,
@@ -374,6 +429,7 @@
 	.id = 3,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &mdp1_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_mdp1_resources),
 	.resource = msm_iommu_mdp1_resources,
@@ -384,6 +440,7 @@
 	.id = 4,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &rot_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_rot_resources),
 	.resource = msm_iommu_rot_resources,
@@ -394,6 +451,7 @@
 	.id = 5,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &ijpeg_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_ijpeg_resources),
 	.resource = msm_iommu_ijpeg_resources,
@@ -404,6 +462,7 @@
 	.id = 6,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &vfe_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_vfe_resources),
 	.resource = msm_iommu_vfe_resources,
@@ -414,6 +473,7 @@
 	.id = 7,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &vcodec_a_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_vcodec_a_resources),
 	.resource = msm_iommu_vcodec_a_resources,
@@ -424,6 +484,7 @@
 	.id = 8,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &vcodec_b_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_vcodec_b_resources),
 	.resource = msm_iommu_vcodec_b_resources,
@@ -434,31 +495,56 @@
 	.id = 9,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &gfx3d_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_gfx3d_resources),
 	.resource = msm_iommu_gfx3d_resources,
 };
 
+static struct platform_device msm_device_iommu_gfx3d1 = {
+	.name = "msm_iommu",
+	.id = 10,
+	.dev = {
+		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &gfx3d1_iommu,
+	},
+	.num_resources = ARRAY_SIZE(msm_iommu_gfx3d1_resources),
+	.resource = msm_iommu_gfx3d1_resources,
+};
+
 static struct platform_device msm_device_iommu_gfx2d0 = {
 	.name = "msm_iommu",
 	.id = 10,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &gfx2d0_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_gfx2d0_resources),
 	.resource = msm_iommu_gfx2d0_resources,
 };
 
-struct platform_device msm_device_iommu_gfx2d1 = {
+static struct platform_device msm_device_iommu_gfx2d1 = {
 	.name = "msm_iommu",
 	.id = 11,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &gfx2d1_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_gfx2d1_resources),
 	.resource = msm_iommu_gfx2d1_resources,
 };
 
+static struct platform_device msm_device_iommu_vcap = {
+	.name = "msm_iommu",
+	.id = 11,
+	.dev = {
+		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &vcap_iommu,
+	},
+	.num_resources = ARRAY_SIZE(msm_iommu_vcap_resources),
+	.resource = msm_iommu_vcap_resources,
+};
+
 static struct msm_iommu_ctx_dev jpegd_src_ctx = {
 	.name = "jpegd_src",
 	.num = 0,
@@ -483,26 +569,26 @@
 	.mids = {1, -1}
 };
 
-static struct msm_iommu_ctx_dev mdp_vg1_ctx = {
-	.name = "mdp_vg1",
+static struct msm_iommu_ctx_dev mdp_port0_cb0_ctx = {
+	.name = "mdp_port0_cb0",
 	.num = 0,
 	.mids = {0, 2, -1}
 };
 
-static struct msm_iommu_ctx_dev mdp_rgb1_ctx = {
-	.name = "mdp_rgb1",
+static struct msm_iommu_ctx_dev mdp_port0_cb1_ctx = {
+	.name = "mdp_port0_cb1",
 	.num = 1,
 	.mids = {1, 3, 4, 5, 6, 7, 8, 9, 10, -1}
 };
 
-static struct msm_iommu_ctx_dev mdp_vg2_ctx = {
-	.name = "mdp_vg2",
+static struct msm_iommu_ctx_dev mdp_port1_cb0_ctx = {
+	.name = "mdp_port1_cb0",
 	.num = 0,
 	.mids = {0, 2, -1}
 };
 
-static struct msm_iommu_ctx_dev mdp_rgb2_ctx = {
-	.name = "mdp_rgb2",
+static struct msm_iommu_ctx_dev mdp_port1_cb1_ctx = {
+	.name = "mdp_port1_cb1",
 	.num = 1,
 	.mids = {1, 3, 4, 5, 6, 7, 8, 9, 10, -1}
 };
@@ -574,6 +660,19 @@
 		 31, -1}
 };
 
+static struct msm_iommu_ctx_dev gfx3d1_user_ctx = {
+	.name = "gfx3d1_user",
+	.num = 0,
+	.mids = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, -1}
+};
+
+static struct msm_iommu_ctx_dev gfx3d1_priv_ctx = {
+	.name = "gfx3d1_priv",
+	.num = 1,
+	.mids = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+		 31, -1}
+};
+
 static struct msm_iommu_ctx_dev gfx2d0_2d0_ctx = {
 	.name = "gfx2d0_2d0",
 	.num = 0,
@@ -586,11 +685,24 @@
 	.mids = {0, 1, 2, 3, 4, 5, 6, 7, -1}
 };
 
+static struct msm_iommu_ctx_dev vcap_vc_ctx = {
+	.name = "vcap_vc",
+	.num = 0,
+	.mids = {0, -1}
+};
+
+static struct msm_iommu_ctx_dev vcap_vp_ctx = {
+	.name = "vcap_vp",
+	.num = 1,
+	.mids = {1, -1}
+};
+
 static struct platform_device msm_device_jpegd_src_ctx = {
 	.name = "msm_iommu_ctx",
 	.id = 0,
 	.dev = {
 		.parent = &msm_device_iommu_jpegd.dev,
+		.platform_data = &jpegd_src_ctx,
 	},
 };
 
@@ -599,6 +711,7 @@
 	.id = 1,
 	.dev = {
 		.parent = &msm_device_iommu_jpegd.dev,
+		.platform_data = &jpegd_dst_ctx,
 	},
 };
 
@@ -607,6 +720,7 @@
 	.id = 2,
 	.dev = {
 		.parent = &msm_device_iommu_vpe.dev,
+		.platform_data = &vpe_src_ctx,
 	},
 };
 
@@ -615,38 +729,43 @@
 	.id = 3,
 	.dev = {
 		.parent = &msm_device_iommu_vpe.dev,
+		.platform_data = &vpe_dst_ctx,
 	},
 };
 
-static struct platform_device msm_device_mdp_vg1_ctx = {
+static struct platform_device msm_device_mdp_port0_cb0_ctx = {
 	.name = "msm_iommu_ctx",
 	.id = 4,
 	.dev = {
 		.parent = &msm_device_iommu_mdp0.dev,
+		.platform_data = &mdp_port0_cb0_ctx,
 	},
 };
 
-static struct platform_device msm_device_mdp_rgb1_ctx = {
+static struct platform_device msm_device_mdp_port0_cb1_ctx = {
 	.name = "msm_iommu_ctx",
 	.id = 5,
 	.dev = {
 		.parent = &msm_device_iommu_mdp0.dev,
+		.platform_data = &mdp_port0_cb1_ctx,
 	},
 };
 
-static struct platform_device msm_device_mdp_vg2_ctx = {
+static struct platform_device msm_device_mdp_port1_cb0_ctx = {
 	.name = "msm_iommu_ctx",
 	.id = 6,
 	.dev = {
 		.parent = &msm_device_iommu_mdp1.dev,
+		.platform_data = &mdp_port1_cb0_ctx,
 	},
 };
 
-static struct platform_device msm_device_mdp_rgb2_ctx = {
+static struct platform_device msm_device_mdp_port1_cb1_ctx = {
 	.name = "msm_iommu_ctx",
 	.id = 7,
 	.dev = {
 		.parent = &msm_device_iommu_mdp1.dev,
+		.platform_data = &mdp_port1_cb1_ctx,
 	},
 };
 
@@ -655,6 +774,7 @@
 	.id = 8,
 	.dev = {
 		.parent = &msm_device_iommu_rot.dev,
+		.platform_data = &rot_src_ctx,
 	},
 };
 
@@ -663,6 +783,7 @@
 	.id = 9,
 	.dev = {
 		.parent = &msm_device_iommu_rot.dev,
+		.platform_data = &rot_dst_ctx,
 	},
 };
 
@@ -671,6 +792,7 @@
 	.id = 10,
 	.dev = {
 		.parent = &msm_device_iommu_ijpeg.dev,
+		.platform_data = &ijpeg_src_ctx,
 	},
 };
 
@@ -679,6 +801,7 @@
 	.id = 11,
 	.dev = {
 		.parent = &msm_device_iommu_ijpeg.dev,
+		.platform_data = &ijpeg_dst_ctx,
 	},
 };
 
@@ -687,6 +810,7 @@
 	.id = 12,
 	.dev = {
 		.parent = &msm_device_iommu_vfe.dev,
+		.platform_data = &vfe_imgwr_ctx,
 	},
 };
 
@@ -695,6 +819,7 @@
 	.id = 13,
 	.dev = {
 		.parent = &msm_device_iommu_vfe.dev,
+		.platform_data = &vfe_misc_ctx,
 	},
 };
 
@@ -703,6 +828,7 @@
 	.id = 14,
 	.dev = {
 		.parent = &msm_device_iommu_vcodec_a.dev,
+		.platform_data = &vcodec_a_stream_ctx,
 	},
 };
 
@@ -711,6 +837,7 @@
 	.id = 15,
 	.dev = {
 		.parent = &msm_device_iommu_vcodec_a.dev,
+		.platform_data = &vcodec_a_mm1_ctx,
 	},
 };
 
@@ -719,6 +846,7 @@
 	.id = 16,
 	.dev = {
 		.parent = &msm_device_iommu_vcodec_b.dev,
+		.platform_data = &vcodec_b_mm2_ctx,
 	},
 };
 
@@ -727,6 +855,7 @@
 	.id = 17,
 	.dev = {
 		.parent = &msm_device_iommu_gfx3d.dev,
+		.platform_data = &gfx3d_user_ctx,
 	},
 };
 
@@ -735,6 +864,25 @@
 	.id = 18,
 	.dev = {
 		.parent = &msm_device_iommu_gfx3d.dev,
+		.platform_data = &gfx3d_priv_ctx,
+	},
+};
+
+static struct platform_device msm_device_gfx3d1_user_ctx = {
+	.name = "msm_iommu_ctx",
+	.id = 19,
+	.dev = {
+		.parent = &msm_device_iommu_gfx3d1.dev,
+		.platform_data = &gfx3d1_user_ctx,
+	},
+};
+
+static struct platform_device msm_device_gfx3d1_priv_ctx = {
+	.name = "msm_iommu_ctx",
+	.id = 20,
+	.dev = {
+		.parent = &msm_device_iommu_gfx3d1.dev,
+		.platform_data = &gfx3d1_priv_ctx,
 	},
 };
 
@@ -743,6 +891,7 @@
 	.id = 19,
 	.dev = {
 		.parent = &msm_device_iommu_gfx2d0.dev,
+		.platform_data = &gfx2d0_2d0_ctx,
 	},
 };
 
@@ -751,11 +900,29 @@
 	.id = 20,
 	.dev = {
 		.parent = &msm_device_iommu_gfx2d1.dev,
+		.platform_data = &gfx2d1_2d1_ctx,
 	},
 };
 
-static struct platform_device *msm_iommu_devs[] = {
-	&msm_device_iommu_jpegd,
+static struct platform_device msm_device_vcap_vc_ctx = {
+	.name = "msm_iommu_ctx",
+	.id = 21,
+	.dev = {
+		.parent = &msm_device_iommu_vcap.dev,
+		.platform_data = &vcap_vc_ctx,
+	},
+};
+
+static struct platform_device msm_device_vcap_vp_ctx = {
+	.name = "msm_iommu_ctx",
+	.id = 22,
+	.dev = {
+		.parent = &msm_device_iommu_vcap.dev,
+		.platform_data = &vcap_vp_ctx,
+	},
+};
+
+static struct platform_device *msm_iommu_common_devs[] = {
 	&msm_device_iommu_vpe,
 	&msm_device_iommu_mdp0,
 	&msm_device_iommu_mdp1,
@@ -765,34 +932,29 @@
 	&msm_device_iommu_vcodec_a,
 	&msm_device_iommu_vcodec_b,
 	&msm_device_iommu_gfx3d,
+};
+
+static struct platform_device *msm_iommu_gfx2d_devs[] = {
 	&msm_device_iommu_gfx2d0,
 	&msm_device_iommu_gfx2d1,
 };
 
-static struct msm_iommu_dev *msm_iommu_data[] = {
-	&jpegd_iommu,
-	&vpe_iommu,
-	&mdp0_iommu,
-	&mdp1_iommu,
-	&rot_iommu,
-	&ijpeg_iommu,
-	&vfe_iommu,
-	&vcodec_a_iommu,
-	&vcodec_b_iommu,
-	&gfx3d_iommu,
-	&gfx2d0_iommu,
-	&gfx2d1_iommu,
+static struct platform_device *msm_iommu_8064_devs[] = {
+	&msm_device_iommu_gfx3d1,
+	&msm_device_iommu_vcap,
 };
 
-static struct platform_device *msm_iommu_ctx_devs[] = {
-	&msm_device_jpegd_src_ctx,
-	&msm_device_jpegd_dst_ctx,
+static struct platform_device *msm_iommu_jpegd_devs[] = {
+	&msm_device_iommu_jpegd,
+};
+
+static struct platform_device *msm_iommu_common_ctx_devs[] = {
 	&msm_device_vpe_src_ctx,
 	&msm_device_vpe_dst_ctx,
-	&msm_device_mdp_vg1_ctx,
-	&msm_device_mdp_rgb1_ctx,
-	&msm_device_mdp_vg2_ctx,
-	&msm_device_mdp_rgb2_ctx,
+	&msm_device_mdp_port0_cb0_ctx,
+	&msm_device_mdp_port0_cb1_ctx,
+	&msm_device_mdp_port1_cb0_ctx,
+	&msm_device_mdp_port1_cb1_ctx,
 	&msm_device_rot_src_ctx,
 	&msm_device_rot_dst_ctx,
 	&msm_device_ijpeg_src_ctx,
@@ -804,37 +966,32 @@
 	&msm_device_vcodec_b_mm2_ctx,
 	&msm_device_gfx3d_user_ctx,
 	&msm_device_gfx3d_priv_ctx,
+};
+
+static struct platform_device *msm_iommu_gfx2d_ctx_devs[] = {
 	&msm_device_gfx2d0_2d0_ctx,
 	&msm_device_gfx2d1_2d1_ctx,
 };
 
-static struct msm_iommu_ctx_dev *msm_iommu_ctx_data[] = {
-	&jpegd_src_ctx,
-	&jpegd_dst_ctx,
-	&vpe_src_ctx,
-	&vpe_dst_ctx,
-	&mdp_vg1_ctx,
-	&mdp_rgb1_ctx,
-	&mdp_vg2_ctx,
-	&mdp_rgb2_ctx,
-	&rot_src_ctx,
-	&rot_dst_ctx,
-	&ijpeg_src_ctx,
-	&ijpeg_dst_ctx,
-	&vfe_imgwr_ctx,
-	&vfe_misc_ctx,
-	&vcodec_a_stream_ctx,
-	&vcodec_a_mm1_ctx,
-	&vcodec_b_mm2_ctx,
-	&gfx3d_user_ctx,
-	&gfx3d_priv_ctx,
-	&gfx2d0_2d0_ctx,
-	&gfx2d1_2d1_ctx,
+static struct platform_device *msm_iommu_8064_ctx_devs[] = {
+	&msm_device_gfx3d1_user_ctx,
+	&msm_device_gfx3d1_priv_ctx,
+	&msm_device_vcap_vc_ctx,
+	&msm_device_vcap_vp_ctx,
 };
 
-static int __init msm8x60_iommu_init(void)
+static struct platform_device *msm_iommu_jpegd_ctx_devs[] = {
+	&msm_device_jpegd_src_ctx,
+	&msm_device_jpegd_dst_ctx,
+};
+
+static int __init iommu_init(void)
 {
-	int ret, i;
+	int ret;
+	if (!msm_soc_version_supports_iommu_v1()) {
+		pr_err("IOMMU v1 is not supported on this SoC version.\n");
+		return -ENODEV;
+	}
 
 	ret = platform_device_register(&msm_root_iommu_dev);
 	if (ret != 0) {
@@ -842,71 +999,95 @@
 		goto failure;
 	}
 
-	for (i = 0; i < ARRAY_SIZE(msm_iommu_devs); i++) {
-		ret = platform_device_add_data(msm_iommu_devs[i],
-					       msm_iommu_data[i],
-					       sizeof(struct msm_iommu_dev));
-		if (ret != 0) {
-			pr_err("platform_device_add_data failed, "
-			       "i = %d\n", i);
-			goto failure_unwind;
-		}
+	/* Initialize common devs */
+	platform_add_devices(msm_iommu_common_devs,
+				ARRAY_SIZE(msm_iommu_common_devs));
 
-		ret = platform_device_register(msm_iommu_devs[i]);
-
-		if (ret != 0) {
-			pr_err("platform_device_register iommu failed, "
-			       "i = %d\n", i);
-			goto failure_unwind;
-		}
+	/* Initialize soc-specific devs */
+	if (cpu_is_msm8x60() || cpu_is_msm8960()) {
+		platform_add_devices(msm_iommu_jpegd_devs,
+				ARRAY_SIZE(msm_iommu_jpegd_devs));
+		platform_add_devices(msm_iommu_gfx2d_devs,
+				ARRAY_SIZE(msm_iommu_gfx2d_devs));
 	}
 
-	for (i = 0; i < ARRAY_SIZE(msm_iommu_ctx_devs); i++) {
-		ret = platform_device_add_data(msm_iommu_ctx_devs[i],
-					       msm_iommu_ctx_data[i],
-					       sizeof(*msm_iommu_ctx_devs[i]));
-		if (ret != 0) {
-			pr_err("platform_device_add_data iommu failed, "
-			       "i = %d\n", i);
-			goto failure_unwind2;
-		}
-
-		ret = platform_device_register(msm_iommu_ctx_devs[i]);
-		if (ret != 0) {
-			pr_err("platform_device_register ctx failed, "
-			       "i = %d\n", i);
-			goto failure_unwind2;
-		}
+	if (cpu_is_apq8064()) {
+		platform_add_devices(msm_iommu_jpegd_devs,
+				ARRAY_SIZE(msm_iommu_jpegd_devs));
+		platform_add_devices(msm_iommu_8064_devs,
+				ARRAY_SIZE(msm_iommu_8064_devs));
 	}
+
+	/* Initialize common ctx_devs */
+	ret = platform_add_devices(msm_iommu_common_ctx_devs,
+				ARRAY_SIZE(msm_iommu_common_ctx_devs));
+
+	/* Initialize soc-specific ctx_devs */
+	if (cpu_is_msm8x60() || cpu_is_msm8960()) {
+		platform_add_devices(msm_iommu_jpegd_ctx_devs,
+				ARRAY_SIZE(msm_iommu_jpegd_ctx_devs));
+		platform_add_devices(msm_iommu_gfx2d_ctx_devs,
+				ARRAY_SIZE(msm_iommu_gfx2d_ctx_devs));
+	}
+
+	if (cpu_is_apq8064()) {
+		platform_add_devices(msm_iommu_jpegd_ctx_devs,
+				ARRAY_SIZE(msm_iommu_jpegd_ctx_devs));
+		platform_add_devices(msm_iommu_8064_ctx_devs,
+				ARRAY_SIZE(msm_iommu_8064_ctx_devs));
+	}
+
 	return 0;
 
-failure_unwind2:
-	while (--i >= 0)
-		platform_device_unregister(msm_iommu_ctx_devs[i]);
-failure_unwind:
-	while (--i >= 0)
-		platform_device_unregister(msm_iommu_devs[i]);
-
-	platform_device_unregister(&msm_root_iommu_dev);
 failure:
 	return ret;
 }
 
-static void __exit msm8x60_iommu_exit(void)
+static void __exit iommu_exit(void)
 {
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(msm_iommu_ctx_devs); i++)
-		platform_device_unregister(msm_iommu_ctx_devs[i]);
+	/* Common ctx_devs */
+	for (i = 0; i < ARRAY_SIZE(msm_iommu_common_ctx_devs); i++)
+		platform_device_unregister(msm_iommu_common_ctx_devs[i]);
 
-	for (i = 0; i < ARRAY_SIZE(msm_iommu_devs); ++i)
-		platform_device_unregister(msm_iommu_devs[i]);
+	/* Common devs. */
+	for (i = 0; i < ARRAY_SIZE(msm_iommu_common_devs); ++i)
+		platform_device_unregister(msm_iommu_common_devs[i]);
+
+	if (cpu_is_msm8x60() || cpu_is_msm8960()) {
+		for (i = 0; i < ARRAY_SIZE(msm_iommu_gfx2d_ctx_devs); i++)
+			platform_device_unregister(msm_iommu_gfx2d_ctx_devs[i]);
+
+		for (i = 0; i < ARRAY_SIZE(msm_iommu_jpegd_ctx_devs); i++)
+			platform_device_unregister(msm_iommu_jpegd_ctx_devs[i]);
+
+		for (i = 0; i < ARRAY_SIZE(msm_iommu_gfx2d_devs); i++)
+			platform_device_unregister(msm_iommu_gfx2d_devs[i]);
+
+		for (i = 0; i < ARRAY_SIZE(msm_iommu_jpegd_devs); i++)
+			platform_device_unregister(msm_iommu_jpegd_devs[i]);
+	}
+
+	if (cpu_is_apq8064()) {
+		for (i = 0; i < ARRAY_SIZE(msm_iommu_8064_ctx_devs); i++)
+			platform_device_unregister(msm_iommu_8064_ctx_devs[i]);
+
+		for (i = 0; i < ARRAY_SIZE(msm_iommu_jpegd_ctx_devs); i++)
+			platform_device_unregister(msm_iommu_jpegd_ctx_devs[i]);
+
+		for (i = 0; i < ARRAY_SIZE(msm_iommu_8064_devs); i++)
+			platform_device_unregister(msm_iommu_8064_devs[i]);
+
+		for (i = 0; i < ARRAY_SIZE(msm_iommu_jpegd_devs); i++)
+			platform_device_unregister(msm_iommu_jpegd_devs[i]);
+	}
 
 	platform_device_unregister(&msm_root_iommu_dev);
 }
 
-subsys_initcall(msm8x60_iommu_init);
-module_exit(msm8x60_iommu_exit);
+subsys_initcall(iommu_init);
+module_exit(iommu_exit);
 
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Stepan Moskovchenko <stepanm@codeaurora.org>");
diff --git a/arch/arm/mach-msm/devices-msm7x00.c b/arch/arm/mach-msm/devices-msm7x00.c
index 993780f..54ed401 100644
--- a/arch/arm/mach-msm/devices-msm7x00.c
+++ b/arch/arm/mach-msm/devices-msm7x00.c
@@ -15,18 +15,20 @@
 
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
-#include <linux/clkdev.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
 
 #include <mach/irqs.h>
 #include <mach/msm_iomap.h>
+#include <mach/dma.h>
+#include <mach/proc_comm.h>
+#include <asm/clkdev.h>
 #include "devices.h"
 
 #include <asm/mach/flash.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 
-#include "clock.h"
-#include "clock-pcom.h"
 #include <mach/mmc.h>
 
 static struct resource resources_uart1[] = {
@@ -92,6 +94,92 @@
 	.resource	= resources_uart3,
 };
 
+static struct resource msm_uart1_dm_resources[] = {
+	{
+		.start = MSM_UART1DM_PHYS,
+		.end   = MSM_UART1DM_PHYS + PAGE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = INT_UART1DM_IRQ,
+		.end   = INT_UART1DM_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = INT_UART1DM_RX,
+		.end   = INT_UART1DM_RX,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = DMOV_HSUART1_TX_CHAN,
+		.end   = DMOV_HSUART1_RX_CHAN,
+		.name  = "uartdm_channels",
+		.flags = IORESOURCE_DMA,
+	},
+	{
+		.start = DMOV_HSUART1_TX_CRCI,
+		.end   = DMOV_HSUART1_RX_CRCI,
+		.name  = "uartdm_crci",
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static u64 msm_uart_dm1_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device msm_device_uart_dm1 = {
+	.name = "msm_serial_hs",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(msm_uart1_dm_resources),
+	.resource = msm_uart1_dm_resources,
+	.dev		= {
+		.dma_mask = &msm_uart_dm1_dma_mask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
+
+static struct resource msm_uart2_dm_resources[] = {
+	{
+		.start = MSM_UART2DM_PHYS,
+		.end   = MSM_UART2DM_PHYS + PAGE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = INT_UART2DM_IRQ,
+		.end   = INT_UART2DM_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = INT_UART2DM_RX,
+		.end   = INT_UART2DM_RX,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = DMOV_HSUART2_TX_CHAN,
+		.end   = DMOV_HSUART2_RX_CHAN,
+		.name  = "uartdm_channels",
+		.flags = IORESOURCE_DMA,
+	},
+	{
+		.start = DMOV_HSUART2_TX_CRCI,
+		.end   = DMOV_HSUART2_RX_CRCI,
+		.name  = "uartdm_crci",
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static u64 msm_uart_dm2_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device msm_device_uart_dm2 = {
+	.name = "msm_serial_hs",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(msm_uart2_dm_resources),
+	.resource = msm_uart2_dm_resources,
+	.dev		= {
+		.dma_mask = &msm_uart_dm2_dma_mask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
+
 static struct resource resources_i2c[] = {
 	{
 		.start	= MSM_I2C_PHYS,
@@ -112,6 +200,30 @@
 	.resource	= resources_i2c,
 };
 
+#define GPIO_I2C_CLK 60
+#define GPIO_I2C_DAT 61
+void msm_set_i2c_mux(bool gpio, int *gpio_clk, int *gpio_dat)
+{
+	unsigned id;
+	if (gpio) {
+		id = PCOM_GPIO_CFG(GPIO_I2C_CLK, 0, GPIO_OUTPUT,
+				   GPIO_NO_PULL, GPIO_2MA);
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+		id = PCOM_GPIO_CFG(GPIO_I2C_DAT, 0, GPIO_OUTPUT,
+				   GPIO_NO_PULL, GPIO_2MA);
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+		*gpio_clk = GPIO_I2C_CLK;
+		*gpio_dat = GPIO_I2C_DAT;
+	} else {
+		id = PCOM_GPIO_CFG(GPIO_I2C_CLK, 1, GPIO_INPUT,
+				   GPIO_NO_PULL, GPIO_8MA);
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+		id = PCOM_GPIO_CFG(GPIO_I2C_DAT , 1, GPIO_INPUT,
+				   GPIO_NO_PULL, GPIO_8MA);
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+	}
+}
+
 static struct resource resources_hsusb[] = {
 	{
 		.start	= MSM_HSUSB_PHYS,
@@ -302,8 +414,7 @@
 	&msm_device_sdc4,
 };
 
-int __init msm_add_sdcc(unsigned int controller,
-			struct msm_mmc_platform_data *plat,
+int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat,
 			unsigned int stat_irq, unsigned long stat_irq_flags)
 {
 	struct platform_device	*pdev;
@@ -394,48 +505,30 @@
 	.resource = resources_mdp,
 };
 
-struct clk_lookup msm_clocks_7x01a[] = {
-	CLK_PCOM("adm_clk",	ADM_CLK,	NULL, 0),
-	CLK_PCOM("adsp_clk",	ADSP_CLK,	NULL, 0),
-	CLK_PCOM("ebi1_clk",	EBI1_CLK,	NULL, 0),
-	CLK_PCOM("ebi2_clk",	EBI2_CLK,	NULL, 0),
-	CLK_PCOM("ecodec_clk",	ECODEC_CLK,	NULL, 0),
-	CLK_PCOM("emdh_clk",	EMDH_CLK,	NULL, OFF),
-	CLK_PCOM("gp_clk",		GP_CLK,		NULL, 0),
-	CLK_PCOM("grp_clk",	GRP_3D_CLK,	NULL, OFF),
-	CLK_PCOM("i2c_clk",	I2C_CLK,	"msm_i2c.0", 0),
-	CLK_PCOM("icodec_rx_clk",	ICODEC_RX_CLK,	NULL, 0),
-	CLK_PCOM("icodec_tx_clk",	ICODEC_TX_CLK,	NULL, 0),
-	CLK_PCOM("imem_clk",	IMEM_CLK,	NULL, OFF),
-	CLK_PCOM("mdc_clk",	MDC_CLK,	NULL, 0),
-	CLK_PCOM("mdp_clk",	MDP_CLK,	NULL, OFF),
-	CLK_PCOM("pbus_clk",	PBUS_CLK,	NULL, 0),
-	CLK_PCOM("pcm_clk",	PCM_CLK,	NULL, 0),
-	CLK_PCOM("mddi_clk",	PMDH_CLK,	NULL, OFF | CLK_MINMAX),
-	CLK_PCOM("sdac_clk",	SDAC_CLK,	NULL, OFF),
-	CLK_PCOM("sdc_clk",	SDC1_CLK,	"msm_sdcc.1", OFF),
-	CLK_PCOM("sdc_pclk",	SDC1_P_CLK,	"msm_sdcc.1", OFF),
-	CLK_PCOM("sdc_clk",	SDC2_CLK,	"msm_sdcc.2", OFF),
-	CLK_PCOM("sdc_pclk",	SDC2_P_CLK,	"msm_sdcc.2", OFF),
-	CLK_PCOM("sdc_clk",	SDC3_CLK,	"msm_sdcc.3", OFF),
-	CLK_PCOM("sdc_pclk",	SDC3_P_CLK,	"msm_sdcc.3", OFF),
-	CLK_PCOM("sdc_clk",	SDC4_CLK,	"msm_sdcc.4", OFF),
-	CLK_PCOM("sdc_pclk",	SDC4_P_CLK,	"msm_sdcc.4", OFF),
-	CLK_PCOM("tsif_clk",	TSIF_CLK,	NULL, 0),
-	CLK_PCOM("tsif_ref_clk",	TSIF_REF_CLK,	NULL, 0),
-	CLK_PCOM("tv_dac_clk",	TV_DAC_CLK,	NULL, 0),
-	CLK_PCOM("tv_enc_clk",	TV_ENC_CLK,	NULL, 0),
-	CLK_PCOM("uart_clk",	UART1_CLK,	"msm_serial.0", OFF),
-	CLK_PCOM("uart_clk",	UART2_CLK,	"msm_serial.1", 0),
-	CLK_PCOM("uart_clk",	UART3_CLK,	"msm_serial.2", OFF),
-	CLK_PCOM("uart1dm_clk",	UART1DM_CLK,	NULL, OFF),
-	CLK_PCOM("uart2dm_clk",	UART2DM_CLK,	NULL, 0),
-	CLK_PCOM("usb_hs_clk",	USB_HS_CLK,	"msm_hsusb", OFF),
-	CLK_PCOM("usb_hs_pclk",	USB_HS_P_CLK,	"msm_hsusb", OFF),
-	CLK_PCOM("usb_otg_clk",	USB_OTG_CLK,	NULL, 0),
-	CLK_PCOM("vdc_clk",	VDC_CLK,	NULL, OFF ),
-	CLK_PCOM("vfe_clk",	VFE_CLK,	NULL, OFF),
-	CLK_PCOM("vfe_mdc_clk",	VFE_MDC_CLK,	NULL, OFF),
+static struct resource resources_tssc[] = {
+	{
+		.start	= MSM_TSSC_PHYS,
+		.end	= MSM_TSSC_PHYS + MSM_TSSC_SIZE - 1,
+		.name	= "tssc",
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_TCHSCRN1,
+		.end	= INT_TCHSCRN1,
+		.name	= "tssc1",
+		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_RISING,
+	},
+	{
+		.start	= INT_TCHSCRN2,
+		.end	= INT_TCHSCRN2,
+		.name	= "tssc2",
+		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_RISING,
+	},
 };
 
-unsigned msm_num_clocks_7x01a = ARRAY_SIZE(msm_clocks_7x01a);
+struct platform_device msm_device_touchscreen = {
+	.name = "msm_touchscreen",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(resources_tssc),
+	.resource = resources_tssc,
+};
diff --git a/arch/arm/mach-msm/devices-msm7x01a.c b/arch/arm/mach-msm/devices-msm7x01a.c
new file mode 100644
index 0000000..1b9eb86
--- /dev/null
+++ b/arch/arm/mach-msm/devices-msm7x01a.c
@@ -0,0 +1,776 @@
+/*
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2008-2011, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#include <linux/dma-mapping.h>
+#include <asm/clkdev.h>
+#include <mach/irqs.h>
+#include <mach/msm_iomap.h>
+#include <mach/dma.h>
+#include <mach/board.h>
+
+#include "devices.h"
+
+#include <asm/mach/flash.h>
+
+#include <asm/mach/mmc.h>
+#include <mach/msm_hsusb.h>
+
+static struct resource resources_uart1[] = {
+	{
+		.start	= INT_UART1,
+		.end	= INT_UART1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM_UART1_PHYS,
+		.end	= MSM_UART1_PHYS + MSM_UART1_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct resource resources_uart2[] = {
+	{
+		.start	= INT_UART2,
+		.end	= INT_UART2,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM_UART2_PHYS,
+		.end	= MSM_UART2_PHYS + MSM_UART2_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct resource resources_uart3[] = {
+	{
+		.start	= INT_UART3,
+		.end	= INT_UART3,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM_UART3_PHYS,
+		.end	= MSM_UART3_PHYS + MSM_UART3_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_device_uart1 = {
+	.name	= "msm_serial",
+	.id	= 0,
+	.num_resources	= ARRAY_SIZE(resources_uart1),
+	.resource	= resources_uart1,
+};
+
+struct platform_device msm_device_uart2 = {
+	.name	= "msm_serial",
+	.id	= 1,
+	.num_resources	= ARRAY_SIZE(resources_uart2),
+	.resource	= resources_uart2,
+};
+
+struct platform_device msm_device_uart3 = {
+	.name	= "msm_serial",
+	.id	= 2,
+	.num_resources	= ARRAY_SIZE(resources_uart3),
+	.resource	= resources_uart3,
+};
+
+#define MSM_UART1DM_PHYS      0xA0200000
+#define MSM_UART2DM_PHYS      0xA0300000
+static struct resource msm_uart1_dm_resources[] = {
+	{
+		.start = MSM_UART1DM_PHYS,
+		.end   = MSM_UART1DM_PHYS + PAGE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = INT_UART1DM_IRQ,
+		.end   = INT_UART1DM_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = INT_UART1DM_RX,
+		.end   = INT_UART1DM_RX,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = DMOV_HSUART1_TX_CHAN,
+		.end   = DMOV_HSUART1_RX_CHAN,
+		.name  = "uartdm_channels",
+		.flags = IORESOURCE_DMA,
+	},
+	{
+		.start = DMOV_HSUART1_TX_CRCI,
+		.end   = DMOV_HSUART1_RX_CRCI,
+		.name  = "uartdm_crci",
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static u64 msm_uart_dm1_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device msm_device_uart_dm1 = {
+	.name = "msm_serial_hs",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(msm_uart1_dm_resources),
+	.resource = msm_uart1_dm_resources,
+	.dev		= {
+		.dma_mask = &msm_uart_dm1_dma_mask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
+
+static struct resource msm_uart2_dm_resources[] = {
+	{
+		.start = MSM_UART2DM_PHYS,
+		.end   = MSM_UART2DM_PHYS + PAGE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = INT_UART2DM_IRQ,
+		.end   = INT_UART2DM_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = INT_UART2DM_RX,
+		.end   = INT_UART2DM_RX,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = DMOV_HSUART2_TX_CHAN,
+		.end   = DMOV_HSUART2_RX_CHAN,
+		.name  = "uartdm_channels",
+		.flags = IORESOURCE_DMA,
+	},
+	{
+		.start = DMOV_HSUART2_TX_CRCI,
+		.end   = DMOV_HSUART2_RX_CRCI,
+		.name  = "uartdm_crci",
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static u64 msm_uart_dm2_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device msm_device_uart_dm2 = {
+	.name = "msm_serial_hs",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(msm_uart2_dm_resources),
+	.resource = msm_uart2_dm_resources,
+	.dev		= {
+		.dma_mask = &msm_uart_dm2_dma_mask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
+
+#define MSM_I2C_SIZE          SZ_4K
+#define MSM_I2C_PHYS          0xA9900000
+static struct resource resources_i2c[] = {
+	{
+		.start	= MSM_I2C_PHYS,
+		.end	= MSM_I2C_PHYS + MSM_I2C_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_PWB_I2C,
+		.end	= INT_PWB_I2C,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_i2c = {
+	.name		= "msm_i2c",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(resources_i2c),
+	.resource	= resources_i2c,
+};
+
+#define MSM_HSUSB_PHYS        0xA0800000
+static struct resource resources_hsusb_otg[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_USB_HS,
+		.end	= INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static u64 dma_mask = 0xffffffffULL;
+struct platform_device msm_device_hsusb_otg = {
+	.name		= "msm_hsusb_otg",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_hsusb_otg),
+	.resource	= resources_hsusb_otg,
+	.dev		= {
+		.dma_mask 		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+static struct resource resources_hsusb_peripheral[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_USB_HS,
+		.end	= INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "vbus_interrupt",
+		.start	= MSM_GPIO_TO_INT(112),
+		.end	= MSM_GPIO_TO_INT(112),
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "id_interrupt",
+		.start	= MSM_GPIO_TO_INT(114),
+		.end	= MSM_GPIO_TO_INT(114),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct resource resources_gadget_peripheral[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_USB_HS,
+		.end	= INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_hsusb_peripheral = {
+	.name		= "msm_hsusb_peripheral",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_hsusb_peripheral),
+	.resource	= resources_hsusb_peripheral,
+	.dev		= {
+		.dma_mask 		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+struct platform_device msm_device_gadget_peripheral = {
+	.name		= "msm_hsusb",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_gadget_peripheral),
+	.resource	= resources_gadget_peripheral,
+	.dev		= {
+		.dma_mask 		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+static struct resource resources_hsusb_host[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_USB_HS,
+		.end	= INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_hsusb_host = {
+	.name		= "msm_hsusb_host",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(resources_hsusb_host),
+	.resource	= resources_hsusb_host,
+	.dev		= {
+		.dma_mask 		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+static struct platform_device *msm_host_devices[] = {
+	&msm_device_hsusb_host,
+};
+
+int msm_add_host(unsigned int host, struct msm_usb_host_platform_data *plat)
+{
+	struct platform_device	*pdev;
+
+	pdev = msm_host_devices[host];
+	if (!pdev)
+		return -ENODEV;
+	pdev->dev.platform_data = plat;
+	return platform_device_register(pdev);
+}
+
+#define MSM_NAND_PHYS		0xA0A00000
+static struct resource resources_nand[] = {
+	[0] = {
+		.name   = "msm_nand_dmac",
+		.start	= DMOV_NAND_CHAN,
+		.end	= DMOV_NAND_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	[1] = {
+		.name   = "msm_nand_phys",
+		.start  = MSM_NAND_PHYS,
+		.end    = MSM_NAND_PHYS + 0x7FF,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+static struct resource resources_otg[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_USB_HS,
+		.end	= INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_otg = {
+	.name		= "msm_otg",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_otg),
+	.resource	= resources_otg,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+struct flash_platform_data msm_nand_data = {
+	.parts		= NULL,
+	.nr_parts	= 0,
+};
+
+struct platform_device msm_device_nand = {
+	.name		= "msm_nand",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_nand),
+	.resource	= resources_nand,
+	.dev		= {
+		.platform_data	= &msm_nand_data,
+	},
+};
+
+struct platform_device msm_device_smd = {
+	.name	= "msm_smd",
+	.id	= -1,
+};
+
+static struct resource msm_dmov_resource[] = {
+	{
+		.start = INT_ADM_AARM,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = 0xA9700000,
+		.end = 0xA9700000 + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct msm_dmov_pdata msm_dmov_pdata = {
+	.sd = 3,
+	.sd_size = 0x400,
+};
+
+struct platform_device msm_device_dmov = {
+	.name	= "msm_dmov",
+	.id	= -1,
+	.resource = msm_dmov_resource,
+	.num_resources = ARRAY_SIZE(msm_dmov_resource),
+	.dev = {
+		.platform_data = &msm_dmov_pdata,
+	},
+};
+
+#define MSM_SDC1_BASE         0xA0400000
+#define MSM_SDC2_BASE         0xA0500000
+#define MSM_SDC3_BASE         0xA0600000
+#define MSM_SDC4_BASE         0xA0700000
+static struct resource resources_sdc1[] = {
+	{
+		.start	= MSM_SDC1_BASE,
+		.end	= MSM_SDC1_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SDC1_0,
+		.end	= INT_SDC1_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= 8,
+		.end	= 8,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+static struct resource resources_sdc2[] = {
+	{
+		.start	= MSM_SDC2_BASE,
+		.end	= MSM_SDC2_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SDC2_0,
+		.end	= INT_SDC2_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= 8,
+		.end	= 8,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+static struct resource resources_sdc3[] = {
+	{
+		.start	= MSM_SDC3_BASE,
+		.end	= MSM_SDC3_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SDC3_0,
+		.end	= INT_SDC3_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= 8,
+		.end	= 8,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+static struct resource resources_sdc4[] = {
+	{
+		.start	= MSM_SDC4_BASE,
+		.end	= MSM_SDC4_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SDC4_0,
+		.end	= INT_SDC4_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= 8,
+		.end	= 8,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+struct platform_device msm_device_sdc1 = {
+	.name		= "msm_sdcc",
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(resources_sdc1),
+	.resource	= resources_sdc1,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_sdc2 = {
+	.name		= "msm_sdcc",
+	.id		= 2,
+	.num_resources	= ARRAY_SIZE(resources_sdc2),
+	.resource	= resources_sdc2,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_sdc3 = {
+	.name		= "msm_sdcc",
+	.id		= 3,
+	.num_resources	= ARRAY_SIZE(resources_sdc3),
+	.resource	= resources_sdc3,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_sdc4 = {
+	.name		= "msm_sdcc",
+	.id		= 4,
+	.num_resources	= ARRAY_SIZE(resources_sdc4),
+	.resource	= resources_sdc4,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+static struct platform_device *msm_sdcc_devices[] __initdata = {
+	&msm_device_sdc1,
+	&msm_device_sdc2,
+	&msm_device_sdc3,
+	&msm_device_sdc4,
+};
+
+int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat)
+{
+	struct platform_device	*pdev;
+
+	if (controller < 1 || controller > 4)
+		return -EINVAL;
+
+	pdev = msm_sdcc_devices[controller-1];
+	pdev->dev.platform_data = plat;
+	return platform_device_register(pdev);
+}
+
+#if defined(CONFIG_FB_MSM_MDP40)
+#define MDP_BASE          0xA3F00000
+#define PMDH_BASE         0xAD600000
+#define EMDH_BASE         0xAD700000
+#define TVENC_BASE        0xAD400000
+#else
+#define MDP_BASE          0xAA200000
+#define PMDH_BASE         0xAA600000
+#define EMDH_BASE         0xAA700000
+#define TVENC_BASE        0xAA400000
+#endif
+
+static struct resource msm_mdp_resources[] = {
+	{
+		.name   = "mdp",
+		.start  = MDP_BASE,
+		.end    = MDP_BASE + 0x000F0000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = INT_MDP,
+		.end    = INT_MDP,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct resource msm_mddi_resources[] = {
+	{
+		.name   = "pmdh",
+		.start  = PMDH_BASE,
+		.end    = PMDH_BASE + PAGE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	}
+};
+
+static struct resource msm_mddi_ext_resources[] = {
+	{
+		.name   = "emdh",
+		.start  = EMDH_BASE,
+		.end    = EMDH_BASE + PAGE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	}
+};
+
+static struct resource msm_ebi2_lcd_resources[] = {
+	{
+		.name   = "base",
+		.start  = 0xa0d00000,
+		.end    = 0xa0d00000 + PAGE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "lcd01",
+		.start  = 0x98000000,
+		.end    = 0x98000000 + 0x80000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "lcd02",
+		.start  = 0x9c000000,
+		.end    = 0x9c000000 + 0x80000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+static struct resource msm_tvenc_resources[] = {
+	{
+		.name   = "tvenc",
+		.start  = TVENC_BASE,
+		.end    = TVENC_BASE + PAGE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device msm_mdp_device = {
+	.name   = "mdp",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_mdp_resources),
+	.resource       = msm_mdp_resources,
+};
+
+static struct platform_device msm_mddi_device = {
+	.name   = "mddi",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_mddi_resources),
+	.resource       = msm_mddi_resources,
+};
+
+static struct platform_device msm_mddi_ext_device = {
+	.name   = "mddi_ext",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_mddi_ext_resources),
+	.resource       = msm_mddi_ext_resources,
+};
+
+static struct platform_device msm_ebi2_lcd_device = {
+	.name   = "ebi2_lcd",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_ebi2_lcd_resources),
+	.resource       = msm_ebi2_lcd_resources,
+};
+
+static struct platform_device msm_lcdc_device = {
+	.name   = "lcdc",
+	.id     = 0,
+};
+
+static struct platform_device msm_tvenc_device = {
+	.name   = "tvenc",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_tvenc_resources),
+	.resource       = msm_tvenc_resources,
+};
+
+/* TSIF begin */
+#if defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE)
+
+#define MSM_TSIF_PHYS        (0xa0100000)
+#define MSM_TSIF_SIZE        (0x200)
+
+static struct resource tsif_resources[] = {
+	[0] = {
+		.flags = IORESOURCE_IRQ,
+		.start = INT_TSIF_IRQ,
+		.end   = INT_TSIF_IRQ,
+	},
+	[1] = {
+		.flags = IORESOURCE_MEM,
+		.start = MSM_TSIF_PHYS,
+		.end   = MSM_TSIF_PHYS + MSM_TSIF_SIZE - 1,
+	},
+	[2] = {
+		.flags = IORESOURCE_DMA,
+		.start = DMOV_TSIF_CHAN,
+		.end   = DMOV_TSIF_CRCI,
+	},
+};
+
+static void tsif_release(struct device *dev)
+{
+	dev_info(dev, "release\n");
+}
+
+struct platform_device msm_device_tsif = {
+	.name          = "msm_tsif",
+	.id            = 0,
+	.num_resources = ARRAY_SIZE(tsif_resources),
+	.resource      = tsif_resources,
+	.dev = {
+		.release       = tsif_release,
+	},
+};
+#endif /* defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE) */
+/* TSIF end   */
+
+#define MSM_TSSC_PHYS         0xAA300000
+static struct resource resources_tssc[] = {
+	{
+		.start	= MSM_TSSC_PHYS,
+		.end	= MSM_TSSC_PHYS + SZ_4K - 1,
+		.name	= "tssc",
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_TCHSCRN1,
+		.end	= INT_TCHSCRN1,
+		.name	= "tssc1",
+		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_RISING,
+	},
+	{
+		.start	= INT_TCHSCRN2,
+		.end	= INT_TCHSCRN2,
+		.name	= "tssc2",
+		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_RISING,
+	},
+};
+
+struct platform_device msm_device_tssc = {
+	.name = "msm_touchscreen",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(resources_tssc),
+	.resource = resources_tssc,
+};
+
+static void __init msm_register_device(struct platform_device *pdev, void *data)
+{
+	int ret;
+
+	pdev->dev.platform_data = data;
+
+	ret = platform_device_register(pdev);
+	if (ret)
+		dev_err(&pdev->dev,
+			  "%s: platform_device_register() failed = %d\n",
+			  __func__, ret);
+}
+
+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, "pmdh", 4))
+		msm_register_device(&msm_mddi_device, data);
+	else if (!strncmp(name, "emdh", 4))
+		msm_register_device(&msm_mddi_ext_device, data);
+	else if (!strncmp(name, "ebi2", 4))
+		msm_register_device(&msm_ebi2_lcd_device, data);
+	else if (!strncmp(name, "tvenc", 5))
+		msm_register_device(&msm_tvenc_device, data);
+	else if (!strncmp(name, "lcdc", 4))
+		msm_register_device(&msm_lcdc_device, data);
+	else
+		printk(KERN_ERR "%s: unknown device! %s\n", __func__, name);
+}
+
+static struct platform_device msm_camera_device = {
+	.name	= "msm_camera",
+	.id	= 0,
+};
+
+void __init msm_camera_register_device(void *res, uint32_t num,
+	void *data)
+{
+	msm_camera_device.num_resources = num;
+	msm_camera_device.resource = res;
+
+	msm_register_device(&msm_camera_device, data);
+}
diff --git a/arch/arm/mach-msm/devices-msm7x25.c b/arch/arm/mach-msm/devices-msm7x25.c
new file mode 100644
index 0000000..2be7d5e
--- /dev/null
+++ b/arch/arm/mach-msm/devices-msm7x25.c
@@ -0,0 +1,982 @@
+/*
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2008-2012, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#include <linux/dma-mapping.h>
+#include <asm/clkdev.h>
+#include <mach/irqs.h>
+#include <mach/msm_iomap.h>
+#include <mach/dma.h>
+#include <mach/board.h>
+
+#include "devices.h"
+#include "smd_private.h"
+
+#include <asm/mach/flash.h>
+
+#include <asm/mach/mmc.h>
+#include <mach/msm_hsusb.h>
+#include <mach/usbdiag.h>
+#include <mach/rpc_hsusb.h>
+
+#include "clock-pcom.h"
+
+static struct resource resources_uart1[] = {
+	{
+		.start	= INT_UART1,
+		.end	= INT_UART1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM_UART1_PHYS,
+		.end	= MSM_UART1_PHYS + MSM_UART1_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct resource resources_uart2[] = {
+	{
+		.start	= INT_UART2,
+		.end	= INT_UART2,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM_UART2_PHYS,
+		.end	= MSM_UART2_PHYS + MSM_UART2_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct resource resources_uart3[] = {
+	{
+		.start	= INT_UART3,
+		.end	= INT_UART3,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM_UART3_PHYS,
+		.end	= MSM_UART3_PHYS + MSM_UART3_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_device_uart1 = {
+	.name	= "msm_serial",
+	.id	= 0,
+	.num_resources	= ARRAY_SIZE(resources_uart1),
+	.resource	= resources_uart1,
+};
+
+struct platform_device msm_device_uart2 = {
+	.name	= "msm_serial",
+	.id	= 1,
+	.num_resources	= ARRAY_SIZE(resources_uart2),
+	.resource	= resources_uart2,
+};
+
+struct platform_device msm_device_uart3 = {
+	.name	= "msm_serial",
+	.id	= 2,
+	.num_resources	= ARRAY_SIZE(resources_uart3),
+	.resource	= resources_uart3,
+};
+
+#define MSM_UART1DM_PHYS      0xA0200000
+#define MSM_UART2DM_PHYS      0xA0300000
+static struct resource msm_uart1_dm_resources[] = {
+	{
+		.start = MSM_UART1DM_PHYS,
+		.end   = MSM_UART1DM_PHYS + PAGE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = INT_UART1DM_IRQ,
+		.end   = INT_UART1DM_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = INT_UART1DM_RX,
+		.end   = INT_UART1DM_RX,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = DMOV_HSUART1_TX_CHAN,
+		.end   = DMOV_HSUART1_RX_CHAN,
+		.name  = "uartdm_channels",
+		.flags = IORESOURCE_DMA,
+	},
+	{
+		.start = DMOV_HSUART1_TX_CRCI,
+		.end   = DMOV_HSUART1_RX_CRCI,
+		.name  = "uartdm_crci",
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static u64 msm_uart_dm1_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device msm_device_uart_dm1 = {
+	.name = "msm_serial_hs",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(msm_uart1_dm_resources),
+	.resource = msm_uart1_dm_resources,
+	.dev		= {
+		.dma_mask = &msm_uart_dm1_dma_mask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
+
+static struct resource msm_uart2_dm_resources[] = {
+	{
+		.start = MSM_UART2DM_PHYS,
+		.end   = MSM_UART2DM_PHYS + PAGE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = INT_UART2DM_IRQ,
+		.end   = INT_UART2DM_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = INT_UART2DM_RX,
+		.end   = INT_UART2DM_RX,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = DMOV_HSUART2_TX_CHAN,
+		.end   = DMOV_HSUART2_RX_CHAN,
+		.name  = "uartdm_channels",
+		.flags = IORESOURCE_DMA,
+	},
+	{
+		.start = DMOV_HSUART2_TX_CRCI,
+		.end   = DMOV_HSUART2_RX_CRCI,
+		.name  = "uartdm_crci",
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static u64 msm_uart_dm2_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device msm_device_uart_dm2 = {
+	.name = "msm_serial_hs",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(msm_uart2_dm_resources),
+	.resource = msm_uart2_dm_resources,
+	.dev		= {
+		.dma_mask = &msm_uart_dm2_dma_mask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
+
+#define MSM_I2C_SIZE          SZ_4K
+#define MSM_I2C_PHYS          0xA9900000
+static struct resource resources_i2c[] = {
+	{
+		.start	= MSM_I2C_PHYS,
+		.end	= MSM_I2C_PHYS + MSM_I2C_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_PWB_I2C,
+		.end	= INT_PWB_I2C,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_i2c = {
+	.name		= "msm_i2c",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(resources_i2c),
+	.resource	= resources_i2c,
+};
+
+#define MSM_HSUSB_PHYS        0xA0800000
+static struct resource resources_hsusb_otg[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_USB_HS,
+		.end	= INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static u64 dma_mask = 0xffffffffULL;
+struct platform_device msm_device_hsusb_otg = {
+	.name		= "msm_hsusb_otg",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_hsusb_otg),
+	.resource	= resources_hsusb_otg,
+	.dev		= {
+		.dma_mask 		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+static struct resource resources_hsusb_peripheral[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_USB_HS,
+		.end	= INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct resource resources_gadget_peripheral[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_USB_HS,
+		.end	= INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_hsusb_peripheral = {
+	.name		= "msm_hsusb_peripheral",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_hsusb_peripheral),
+	.resource	= resources_hsusb_peripheral,
+	.dev		= {
+		.dma_mask 		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+struct platform_device msm_device_gadget_peripheral = {
+	.name		= "msm_hsusb",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_gadget_peripheral),
+	.resource	= resources_gadget_peripheral,
+	.dev		= {
+		.dma_mask 		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+static struct resource resources_hsusb_host[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_USB_HS,
+		.end	= INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_hsusb_host = {
+	.name		= "msm_hsusb_host",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(resources_hsusb_host),
+	.resource	= resources_hsusb_host,
+	.dev		= {
+		.dma_mask 		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+static struct platform_device *msm_host_devices[] = {
+	&msm_device_hsusb_host,
+};
+
+int msm_add_host(unsigned int host, struct msm_usb_host_platform_data *plat)
+{
+	struct platform_device	*pdev;
+
+	pdev = msm_host_devices[host];
+	if (!pdev)
+		return -ENODEV;
+	pdev->dev.platform_data = plat;
+	return platform_device_register(pdev);
+}
+
+#ifdef CONFIG_USB_ANDROID_DIAG
+struct usb_diag_platform_data usb_diag_pdata = {
+	.ch_name = DIAG_LEGACY,
+	.update_pid_and_serial_num = usb_diag_update_pid_and_serial_num,
+};
+
+struct platform_device usb_diag_device = {
+	.name	= "usb_diag",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &usb_diag_pdata,
+	},
+};
+#endif
+
+#ifdef CONFIG_USB_F_SERIAL
+static struct usb_gadget_fserial_platform_data fserial_pdata = {
+	.no_ports	= 2,
+};
+
+struct platform_device usb_gadget_fserial_device = {
+	.name	= "usb_fserial",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &fserial_pdata,
+	},
+};
+#endif
+
+#define MSM_NAND_PHYS		0xA0A00000
+static struct resource resources_nand[] = {
+	[0] = {
+		.name   = "msm_nand_dmac",
+		.start	= DMOV_NAND_CHAN,
+		.end	= DMOV_NAND_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	[1] = {
+		.name   = "msm_nand_phys",
+		.start  = MSM_NAND_PHYS,
+		.end    = MSM_NAND_PHYS + 0x7FF,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+static struct resource resources_otg[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_USB_HS,
+		.end	= INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_otg = {
+	.name		= "msm_otg",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_otg),
+	.resource	= resources_otg,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+struct flash_platform_data msm_nand_data = {
+	.parts		= NULL,
+	.nr_parts	= 0,
+};
+
+struct platform_device msm_device_nand = {
+	.name		= "msm_nand",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_nand),
+	.resource	= resources_nand,
+	.dev		= {
+		.platform_data	= &msm_nand_data,
+	},
+};
+
+struct platform_device msm_device_smd = {
+	.name	= "msm_smd",
+	.id	= -1,
+};
+
+static struct resource msm_dmov_resource[] = {
+	{
+		.start = INT_ADM_AARM,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = 0xA9700000,
+		.end = 0xA9700000 + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct msm_dmov_pdata msm_dmov_pdata = {
+	.sd = 3,
+	.sd_size = 0x400,
+};
+
+struct platform_device msm_device_dmov = {
+	.name	= "msm_dmov",
+	.id	= -1,
+	.resource = msm_dmov_resource,
+	.num_resources = ARRAY_SIZE(msm_dmov_resource),
+	.dev = {
+		.platform_data = &msm_dmov_pdata,
+	},
+};
+
+#define MSM_SDC1_BASE         0xA0400000
+#define MSM_SDC2_BASE         0xA0500000
+#define MSM_SDC3_BASE         0xA0600000
+#define MSM_SDC4_BASE         0xA0700000
+static struct resource resources_sdc1[] = {
+	{
+		.start	= MSM_SDC1_BASE,
+		.end	= MSM_SDC1_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SDC1_0,
+		.end	= INT_SDC1_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC1_CHAN,
+		.end	= DMOV_SDC1_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC1_CRCI,
+		.end	= DMOV_SDC1_CRCI,
+		.flags	= IORESOURCE_DMA,
+	}
+};
+
+static struct resource resources_sdc2[] = {
+	{
+		.start	= MSM_SDC2_BASE,
+		.end	= MSM_SDC2_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SDC2_0,
+		.end	= INT_SDC2_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC2_CHAN,
+		.end	= DMOV_SDC2_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC2_CRCI,
+		.end	= DMOV_SDC2_CRCI,
+		.flags	= IORESOURCE_DMA,
+	}
+};
+
+static struct resource resources_sdc3[] = {
+	{
+		.start	= MSM_SDC3_BASE,
+		.end	= MSM_SDC3_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SDC3_0,
+		.end	= INT_SDC3_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC3_CHAN,
+		.end	= DMOV_SDC3_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC3_CRCI,
+		.end	= DMOV_SDC3_CRCI,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+static struct resource resources_sdc4[] = {
+	{
+		.start	= MSM_SDC4_BASE,
+		.end	= MSM_SDC4_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SDC4_0,
+		.end	= INT_SDC4_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC4_CHAN,
+		.end	= DMOV_SDC4_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC4_CRCI,
+		.end	= DMOV_SDC4_CRCI,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+struct platform_device msm_device_sdc1 = {
+	.name		= "msm_sdcc",
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(resources_sdc1),
+	.resource	= resources_sdc1,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_sdc2 = {
+	.name		= "msm_sdcc",
+	.id		= 2,
+	.num_resources	= ARRAY_SIZE(resources_sdc2),
+	.resource	= resources_sdc2,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_sdc3 = {
+	.name		= "msm_sdcc",
+	.id		= 3,
+	.num_resources	= ARRAY_SIZE(resources_sdc3),
+	.resource	= resources_sdc3,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_sdc4 = {
+	.name		= "msm_sdcc",
+	.id		= 4,
+	.num_resources	= ARRAY_SIZE(resources_sdc4),
+	.resource	= resources_sdc4,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+static struct platform_device *msm_sdcc_devices[] __initdata = {
+	&msm_device_sdc1,
+	&msm_device_sdc2,
+	&msm_device_sdc3,
+	&msm_device_sdc4,
+};
+
+int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat)
+{
+	struct platform_device	*pdev;
+
+	if (controller < 1 || controller > 4)
+		return -EINVAL;
+
+	pdev = msm_sdcc_devices[controller-1];
+	pdev->dev.platform_data = plat;
+	return platform_device_register(pdev);
+}
+
+#define RAMFS_INFO_MAGICNUMBER		0x654D4D43
+#define RAMFS_INFO_VERSION		0x00000001
+#define RAMFS_MODEMSTORAGE_ID		0x4D454653
+
+static struct resource rmt_storage_resources[] = {
+       {
+		.flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device rmt_storage_device = {
+       .name           = "rmt_storage",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(rmt_storage_resources),
+       .resource       = rmt_storage_resources,
+};
+
+struct shared_ramfs_entry {
+	uint32_t client_id;   	/* Client id to uniquely identify a client */
+	uint32_t base_addr;	/* Base address of shared RAMFS memory */
+	uint32_t size;		/* Size of the shared RAMFS memory */
+	uint32_t reserved;	/* Reserved attribute for future use */
+};
+struct shared_ramfs_table {
+	uint32_t magic_id;  	/* Identify RAMFS details in SMEM */
+	uint32_t version;	/* Version of shared_ramfs_table */
+	uint32_t entries;	/* Total number of valid entries   */
+	struct shared_ramfs_entry ramfs_entry[3];	/* List all entries */
+};
+
+int __init rmt_storage_add_ramfs(void)
+{
+	struct shared_ramfs_table *ramfs_table;
+	struct shared_ramfs_entry *ramfs_entry;
+	int index;
+
+	ramfs_table = smem_alloc(SMEM_SEFS_INFO,
+			sizeof(struct shared_ramfs_table));
+
+	if (!ramfs_table) {
+		printk(KERN_WARNING "%s: No RAMFS table in SMEM\n", __func__);
+		return -ENOENT;
+	}
+
+	if ((ramfs_table->magic_id != (u32) RAMFS_INFO_MAGICNUMBER) ||
+		(ramfs_table->version != (u32) RAMFS_INFO_VERSION)) {
+		printk(KERN_WARNING "%s: Magic / Version mismatch:, "
+		       "magic_id=%#x, format_version=%#x\n", __func__,
+		       ramfs_table->magic_id, ramfs_table->version);
+		return -ENOENT;
+	}
+
+	for (index = 0; index < ramfs_table->entries; index++) {
+		ramfs_entry = &ramfs_table->ramfs_entry[index];
+
+		/* Find a match for the Modem Storage RAMFS area */
+		if (ramfs_entry->client_id == (u32) RAMFS_MODEMSTORAGE_ID) {
+			printk(KERN_INFO "%s: RAMFS Info (from SMEM): "
+				"Baseaddr = 0x%08x, Size = 0x%08x\n", __func__,
+				ramfs_entry->base_addr, ramfs_entry->size);
+
+			rmt_storage_resources[0].start = ramfs_entry->base_addr;
+			rmt_storage_resources[0].end = ramfs_entry->base_addr +
+							ramfs_entry->size - 1;
+			platform_device_register(&rmt_storage_device);
+			return 0;
+		}
+	}
+	return -ENOENT;
+}
+
+#if defined(CONFIG_FB_MSM_MDP40)
+#define MDP_BASE          0xA3F00000
+#define PMDH_BASE         0xAD600000
+#define EMDH_BASE         0xAD700000
+#define TVENC_BASE        0xAD400000
+#else
+#define MDP_BASE          0xAA200000
+#define PMDH_BASE         0xAA600000
+#define EMDH_BASE         0xAA700000
+#define TVENC_BASE        0xAA400000
+#endif
+
+static struct resource msm_mdp_resources[] = {
+	{
+		.name   = "mdp",
+		.start  = MDP_BASE,
+		.end    = MDP_BASE + 0x000F0000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = INT_MDP,
+		.end    = INT_MDP,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct resource msm_mddi_resources[] = {
+	{
+		.name   = "pmdh",
+		.start  = PMDH_BASE,
+		.end    = PMDH_BASE + PAGE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	}
+};
+
+static struct resource msm_mddi_ext_resources[] = {
+	{
+		.name   = "emdh",
+		.start  = EMDH_BASE,
+		.end    = EMDH_BASE + PAGE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	}
+};
+
+static struct resource msm_ebi2_lcd_resources[] = {
+	{
+		.name   = "base",
+		.start  = 0xa0d00000,
+		.end    = 0xa0d00000 + PAGE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "lcd01",
+		.start  = 0x98000000,
+		.end    = 0x98000000 + 0x80000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "lcd02",
+		.start  = 0x9c000000,
+		.end    = 0x9c000000 + 0x80000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+static struct resource msm_tvenc_resources[] = {
+	{
+		.name   = "tvenc",
+		.start  = TVENC_BASE,
+		.end    = TVENC_BASE + PAGE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device msm_mdp_device = {
+	.name   = "mdp",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_mdp_resources),
+	.resource       = msm_mdp_resources,
+};
+
+static struct platform_device msm_mddi_device = {
+	.name   = "mddi",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_mddi_resources),
+	.resource       = msm_mddi_resources,
+};
+
+static struct platform_device msm_mddi_ext_device = {
+	.name   = "mddi_ext",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_mddi_ext_resources),
+	.resource       = msm_mddi_ext_resources,
+};
+
+static struct platform_device msm_ebi2_lcd_device = {
+	.name   = "ebi2_lcd",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_ebi2_lcd_resources),
+	.resource       = msm_ebi2_lcd_resources,
+};
+
+static struct platform_device msm_lcdc_device = {
+	.name   = "lcdc",
+	.id     = 0,
+};
+
+static struct platform_device msm_tvenc_device = {
+	.name   = "tvenc",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_tvenc_resources),
+	.resource       = msm_tvenc_resources,
+};
+
+/* TSIF begin */
+#if defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE)
+
+#define MSM_TSIF_PHYS        (0xa0100000)
+#define MSM_TSIF_SIZE        (0x200)
+
+static struct resource tsif_resources[] = {
+	[0] = {
+		.flags = IORESOURCE_IRQ,
+		.start = INT_TSIF_IRQ,
+		.end   = INT_TSIF_IRQ,
+	},
+	[1] = {
+		.flags = IORESOURCE_MEM,
+		.start = MSM_TSIF_PHYS,
+		.end   = MSM_TSIF_PHYS + MSM_TSIF_SIZE - 1,
+	},
+	[2] = {
+		.flags = IORESOURCE_DMA,
+		.start = DMOV_TSIF_CHAN,
+		.end   = DMOV_TSIF_CRCI,
+	},
+};
+
+static void tsif_release(struct device *dev)
+{
+	dev_info(dev, "release\n");
+}
+
+struct platform_device msm_device_tsif = {
+	.name          = "msm_tsif",
+	.id            = 0,
+	.num_resources = ARRAY_SIZE(tsif_resources),
+	.resource      = tsif_resources,
+	.dev = {
+		.release       = tsif_release,
+	},
+};
+#endif /* defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE) */
+/* TSIF end   */
+
+#define MSM_TSSC_PHYS         0xAA300000
+static struct resource resources_tssc[] = {
+	{
+		.start	= MSM_TSSC_PHYS,
+		.end	= MSM_TSSC_PHYS + SZ_4K - 1,
+		.name	= "tssc",
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_TCHSCRN1,
+		.end	= INT_TCHSCRN1,
+		.name	= "tssc1",
+		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_RISING,
+	},
+	{
+		.start	= INT_TCHSCRN2,
+		.end	= INT_TCHSCRN2,
+		.name	= "tssc2",
+		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_RISING,
+	},
+};
+
+struct platform_device msm_device_tssc = {
+	.name = "msm_touchscreen",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(resources_tssc),
+	.resource = resources_tssc,
+};
+
+static void __init msm_register_device(struct platform_device *pdev, void *data)
+{
+	int ret;
+
+	pdev->dev.platform_data = data;
+
+	ret = platform_device_register(pdev);
+	if (ret)
+		dev_err(&pdev->dev,
+			  "%s: platform_device_register() failed = %d\n",
+			  __func__, ret);
+}
+
+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, "pmdh", 4))
+		msm_register_device(&msm_mddi_device, data);
+	else if (!strncmp(name, "emdh", 4))
+		msm_register_device(&msm_mddi_ext_device, data);
+	else if (!strncmp(name, "ebi2", 4))
+		msm_register_device(&msm_ebi2_lcd_device, data);
+	else if (!strncmp(name, "tvenc", 5))
+		msm_register_device(&msm_tvenc_device, data);
+	else if (!strncmp(name, "lcdc", 4))
+		msm_register_device(&msm_lcdc_device, data);
+	else
+		printk(KERN_ERR "%s: unknown device! %s\n", __func__, name);
+}
+
+static struct platform_device msm_camera_device = {
+	.name	= "msm_camera",
+	.id	= 0,
+};
+
+void __init msm_camera_register_device(void *res, uint32_t num,
+	void *data)
+{
+	msm_camera_device.num_resources = num;
+	msm_camera_device.resource = res;
+
+	msm_register_device(&msm_camera_device, data);
+}
+
+static DEFINE_CLK_PCOM(adm_clk,		ADM_CLK, 0);
+static DEFINE_CLK_PCOM(adsp_clk,	ADSP_CLK, 0);
+static DEFINE_CLK_PCOM(ebi1_clk,	EBI1_CLK, CLK_MIN);
+static DEFINE_CLK_PCOM(ebi2_clk,	EBI2_CLK, 0);
+static DEFINE_CLK_PCOM(ecodec_clk,	ECODEC_CLK, 0);
+static DEFINE_CLK_PCOM(gp_clk,		GP_CLK,	 0);
+static DEFINE_CLK_PCOM(i2c_clk,		I2C_CLK, 0);
+static DEFINE_CLK_PCOM(icodec_rx_clk,	ICODEC_RX_CLK, 0);
+static DEFINE_CLK_PCOM(icodec_tx_clk,	ICODEC_TX_CLK, 0);
+static DEFINE_CLK_PCOM(imem_clk,	IMEM_CLK, OFF);
+static DEFINE_CLK_PCOM(mdc_clk,		MDC_CLK, 0);
+static DEFINE_CLK_PCOM(pmdh_clk,	PMDH_CLK, OFF | CLK_MINMAX);
+static DEFINE_CLK_PCOM(mdp_clk,		MDP_CLK, OFF);
+static DEFINE_CLK_PCOM(mdp_lcdc_pclk_clk, MDP_LCDC_PCLK_CLK, 0);
+static DEFINE_CLK_PCOM(mdp_lcdc_pad_pclk_clk, MDP_LCDC_PAD_PCLK_CLK, 0);
+static DEFINE_CLK_PCOM(mdp_vsync_clk,	MDP_VSYNC_CLK,  OFF);
+static DEFINE_CLK_PCOM(pbus_clk,	PBUS_CLK, CLK_MIN);
+static DEFINE_CLK_PCOM(pcm_clk,		PCM_CLK, 0);
+static DEFINE_CLK_PCOM(sdac_clk,	SDAC_CLK, OFF);
+static DEFINE_CLK_PCOM(sdc1_clk,	SDC1_CLK, OFF);
+static DEFINE_CLK_PCOM(sdc1_p_clk,	SDC1_P_CLK, OFF);
+static DEFINE_CLK_PCOM(sdc2_clk,	SDC2_CLK, OFF);
+static DEFINE_CLK_PCOM(sdc2_p_clk,	SDC2_P_CLK, OFF);
+static DEFINE_CLK_PCOM(sdc3_clk,	SDC3_CLK, OFF);
+static DEFINE_CLK_PCOM(sdc3_p_clk,	SDC3_P_CLK, OFF);
+static DEFINE_CLK_PCOM(sdc4_clk,	SDC4_CLK, OFF);
+static DEFINE_CLK_PCOM(sdc4_p_clk,	SDC4_P_CLK, OFF);
+static DEFINE_CLK_PCOM(uart1_clk,	UART1_CLK, OFF);
+static DEFINE_CLK_PCOM(uart2_clk,	UART2_CLK, 0);
+static DEFINE_CLK_PCOM(uart3_clk,	UART3_CLK, OFF);
+static DEFINE_CLK_PCOM(uart1dm_clk,	UART1DM_CLK, OFF);
+static DEFINE_CLK_PCOM(uart2dm_clk,	UART2DM_CLK, 0);
+static DEFINE_CLK_PCOM(usb_hs_clk,	USB_HS_CLK, OFF);
+static DEFINE_CLK_PCOM(usb_hs_p_clk,	USB_HS_P_CLK, OFF);
+static DEFINE_CLK_PCOM(usb_otg_clk,	USB_OTG_CLK, 0);
+static DEFINE_CLK_PCOM(vdc_clk,		VDC_CLK, OFF | CLK_MIN);
+static DEFINE_CLK_PCOM(vfe_clk,		VFE_CLK, OFF);
+static DEFINE_CLK_PCOM(vfe_mdc_clk,	VFE_MDC_CLK, OFF);
+
+struct clk_lookup msm_clocks_7x25[] = {
+	CLK_LOOKUP("core_clk",		adm_clk.c,	"msm_dmov"),
+	CLK_LOOKUP("adsp_clk",		adsp_clk.c,	NULL),
+	CLK_LOOKUP("ebi1_clk",		ebi1_clk.c,	NULL),
+	CLK_LOOKUP("ebi2_clk",		ebi2_clk.c,	NULL),
+	CLK_LOOKUP("ecodec_clk",	ecodec_clk.c,	NULL),
+	CLK_LOOKUP("core_clk",		gp_clk.c,		NULL),
+	CLK_LOOKUP("core_clk",		i2c_clk.c,	"msm_i2c.0"),
+	CLK_LOOKUP("icodec_rx_clk",	icodec_rx_clk.c,	NULL),
+	CLK_LOOKUP("icodec_tx_clk",	icodec_tx_clk.c,	NULL),
+	CLK_LOOKUP("mem_clk",		imem_clk.c,	NULL),
+	CLK_LOOKUP("mdc_clk",		mdc_clk.c,	NULL),
+	CLK_LOOKUP("mddi_clk",		pmdh_clk.c,	NULL),
+	CLK_LOOKUP("mdp_clk",		mdp_clk.c,	NULL),
+	CLK_LOOKUP("mdp_lcdc_pclk_clk", mdp_lcdc_pclk_clk.c, NULL),
+	CLK_LOOKUP("mdp_lcdc_pad_pclk_clk", mdp_lcdc_pad_pclk_clk.c, NULL),
+	CLK_LOOKUP("mdp_vsync_clk",	mdp_vsync_clk.c,  NULL),
+	CLK_LOOKUP("pbus_clk",		pbus_clk.c,	NULL),
+	CLK_LOOKUP("pcm_clk",		pcm_clk.c,	NULL),
+	CLK_LOOKUP("sdac_clk",		sdac_clk.c,	NULL),
+	CLK_LOOKUP("core_clk",		sdc1_clk.c,	"msm_sdcc.1"),
+	CLK_LOOKUP("iface_clk",		sdc1_p_clk.c,	"msm_sdcc.1"),
+	CLK_LOOKUP("core_clk",		sdc2_clk.c,	"msm_sdcc.2"),
+	CLK_LOOKUP("iface_clk",		sdc2_p_clk.c,	"msm_sdcc.2"),
+	CLK_LOOKUP("core_clk",		sdc3_clk.c,	"msm_sdcc.3"),
+	CLK_LOOKUP("iface_clk",		sdc3_p_clk.c,	"msm_sdcc.3"),
+	CLK_LOOKUP("core_clk",		sdc4_clk.c,	"msm_sdcc.4"),
+	CLK_LOOKUP("iface_clk",		sdc4_p_clk.c,	"msm_sdcc.4"),
+	CLK_LOOKUP("core_clk",		uart1_clk.c,	"msm_serial.0"),
+	CLK_LOOKUP("core_clk",		uart2_clk.c,	"msm_serial.1"),
+	CLK_LOOKUP("core_clk",		uart3_clk.c,	"msm_serial.2"),
+	CLK_LOOKUP("core_clk",		uart1dm_clk.c,	"msm_serial_hs.0"),
+	CLK_LOOKUP("core_clk",		uart2dm_clk.c,	"msm_serial_hs.1"),
+	CLK_LOOKUP("alt_core_clk",	usb_hs_clk.c,	"msm_otg"),
+	CLK_LOOKUP("iface_clk",		usb_hs_p_clk.c,	"msm_otg"),
+	CLK_LOOKUP("alt_core_clk",	usb_hs_clk.c,	"msm_hsusb_peripheral"),
+	CLK_LOOKUP("iface_clk",		usb_hs_p_clk.c,	"msm_hsusb_peripheral"),
+	CLK_LOOKUP("alt_core_clk",	usb_otg_clk.c,	NULL),
+	CLK_LOOKUP("vdc_clk",		vdc_clk.c,	NULL),
+	CLK_LOOKUP("vfe_clk",		vfe_clk.c,	NULL),
+	CLK_LOOKUP("vfe_mdc_clk",	vfe_mdc_clk.c,	NULL),
+};
+
+unsigned msm_num_clocks_7x25 = ARRAY_SIZE(msm_clocks_7x25);
+
diff --git a/arch/arm/mach-msm/devices-msm7x27.c b/arch/arm/mach-msm/devices-msm7x27.c
new file mode 100644
index 0000000..ffd10fa
--- /dev/null
+++ b/arch/arm/mach-msm/devices-msm7x27.c
@@ -0,0 +1,900 @@
+/*
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2008-2012, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/msm_kgsl.h>
+#include <linux/regulator/machine.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <asm/clkdev.h>
+#include <mach/irqs.h>
+#include <mach/msm_iomap.h>
+#include <mach/dma.h>
+#include <mach/board.h>
+
+#include "devices.h"
+#include "footswitch.h"
+
+#include <asm/mach/flash.h>
+
+#include <asm/mach/mmc.h>
+#include <mach/msm_hsusb.h>
+#include <mach/usbdiag.h>
+#include <mach/rpc_hsusb.h>
+#include "irq.h"
+#include "pm.h"
+
+static struct resource resources_uart1[] = {
+	{
+		.start	= INT_UART1,
+		.end	= INT_UART1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM7XXX_UART1_PHYS,
+		.end	= MSM7XXX_UART1_PHYS + MSM7XXX_UART1_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct resource resources_uart2[] = {
+	{
+		.start	= INT_UART2,
+		.end	= INT_UART2,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM7XXX_UART2_PHYS,
+		.end	= MSM7XXX_UART2_PHYS + MSM7XXX_UART2_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_device_uart1 = {
+	.name	= "msm_serial",
+	.id	= 0,
+	.num_resources	= ARRAY_SIZE(resources_uart1),
+	.resource	= resources_uart1,
+};
+
+struct platform_device msm_device_uart2 = {
+	.name	= "msm_serial",
+	.id	= 1,
+	.num_resources	= ARRAY_SIZE(resources_uart2),
+	.resource	= resources_uart2,
+};
+
+static struct resource resources_adsp[] = {
+	{
+		.start  = INT_ADSP_A9_A11,
+		.end    = INT_ADSP_A9_A11,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_adsp_device = {
+	.name           = "msm_adsp",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(resources_adsp),
+	.resource       = resources_adsp,
+};
+
+#define MSM_UART1DM_PHYS      0xA0200000
+#define MSM_UART2DM_PHYS      0xA0300000
+static struct resource msm_uart1_dm_resources[] = {
+	{
+		.start = MSM_UART1DM_PHYS,
+		.end   = MSM_UART1DM_PHYS + PAGE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = INT_UART1DM_IRQ,
+		.end   = INT_UART1DM_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = INT_UART1DM_RX,
+		.end   = INT_UART1DM_RX,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = DMOV_HSUART1_TX_CHAN,
+		.end   = DMOV_HSUART1_RX_CHAN,
+		.name  = "uartdm_channels",
+		.flags = IORESOURCE_DMA,
+	},
+	{
+		.start = DMOV_HSUART1_TX_CRCI,
+		.end   = DMOV_HSUART1_RX_CRCI,
+		.name  = "uartdm_crci",
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static u64 msm_uart_dm1_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device msm_device_uart_dm1 = {
+	.name = "msm_serial_hs",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(msm_uart1_dm_resources),
+	.resource = msm_uart1_dm_resources,
+	.dev		= {
+		.dma_mask = &msm_uart_dm1_dma_mask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
+
+static struct resource msm_uart2_dm_resources[] = {
+	{
+		.start = MSM_UART2DM_PHYS,
+		.end   = MSM_UART2DM_PHYS + PAGE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = INT_UART2DM_IRQ,
+		.end   = INT_UART2DM_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = INT_UART2DM_RX,
+		.end   = INT_UART2DM_RX,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = DMOV_HSUART2_TX_CHAN,
+		.end   = DMOV_HSUART2_RX_CHAN,
+		.name  = "uartdm_channels",
+		.flags = IORESOURCE_DMA,
+	},
+	{
+		.start = DMOV_HSUART2_TX_CRCI,
+		.end   = DMOV_HSUART2_RX_CRCI,
+		.name  = "uartdm_crci",
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static u64 msm_uart_dm2_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device msm_device_uart_dm2 = {
+	.name = "msm_serial_hs",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(msm_uart2_dm_resources),
+	.resource = msm_uart2_dm_resources,
+	.dev		= {
+		.dma_mask = &msm_uart_dm2_dma_mask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
+
+#define MSM_I2C_SIZE          SZ_4K
+#define MSM_I2C_PHYS          0xA9900000
+static struct resource resources_i2c[] = {
+	{
+		.start	= MSM_I2C_PHYS,
+		.end	= MSM_I2C_PHYS + MSM_I2C_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_PWB_I2C,
+		.end	= INT_PWB_I2C,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_i2c = {
+	.name		= "msm_i2c",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(resources_i2c),
+	.resource	= resources_i2c,
+};
+
+#define MSM_HSUSB_PHYS        0xA0800000
+static struct resource resources_hsusb_otg[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_USB_HS,
+		.end	= INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static u64 dma_mask = 0xffffffffULL;
+struct platform_device msm_device_hsusb_otg = {
+	.name		= "msm_hsusb_otg",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_hsusb_otg),
+	.resource	= resources_hsusb_otg,
+	.dev		= {
+		.dma_mask 		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+static struct resource resources_hsusb_peripheral[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_USB_HS,
+		.end	= INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct resource resources_gadget_peripheral[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_USB_HS,
+		.end	= INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_hsusb_peripheral = {
+	.name		= "msm_hsusb_peripheral",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_hsusb_peripheral),
+	.resource	= resources_hsusb_peripheral,
+	.dev		= {
+		.dma_mask 		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+struct platform_device msm_device_gadget_peripheral = {
+	.name		= "msm_hsusb",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_gadget_peripheral),
+	.resource	= resources_gadget_peripheral,
+	.dev		= {
+		.dma_mask 		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+static struct resource resources_hsusb_host[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_USB_HS,
+		.end	= INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_hsusb_host = {
+	.name		= "msm_hsusb_host",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(resources_hsusb_host),
+	.resource	= resources_hsusb_host,
+	.dev		= {
+		.dma_mask 		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+static struct platform_device *msm_host_devices[] = {
+	&msm_device_hsusb_host,
+};
+
+int msm_add_host(unsigned int host, struct msm_usb_host_platform_data *plat)
+{
+	struct platform_device	*pdev;
+
+	pdev = msm_host_devices[host];
+	if (!pdev)
+		return -ENODEV;
+	pdev->dev.platform_data = plat;
+	return platform_device_register(pdev);
+}
+
+struct platform_device asoc_msm_pcm = {
+	.name   = "msm-dsp-audio",
+	.id     = 0,
+};
+
+struct platform_device asoc_msm_dai0 = {
+	.name   = "msm-codec-dai",
+	.id     = 0,
+};
+
+struct platform_device asoc_msm_dai1 = {
+	.name   = "msm-cpu-dai",
+	.id     = 0,
+};
+
+#define MSM_NAND_PHYS		0xA0A00000
+static struct resource resources_nand[] = {
+	[0] = {
+		.name   = "msm_nand_dmac",
+		.start	= DMOV_NAND_CHAN,
+		.end	= DMOV_NAND_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	[1] = {
+		.name   = "msm_nand_phys",
+		.start  = MSM_NAND_PHYS,
+		.end    = MSM_NAND_PHYS + 0x7FF,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+static struct resource resources_otg[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_USB_HS,
+		.end	= INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_otg = {
+	.name		= "msm_otg",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_otg),
+	.resource	= resources_otg,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+struct flash_platform_data msm_nand_data = {
+	.parts		= NULL,
+	.nr_parts	= 0,
+};
+
+struct platform_device msm_device_nand = {
+	.name		= "msm_nand",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_nand),
+	.resource	= resources_nand,
+	.dev		= {
+		.platform_data	= &msm_nand_data,
+	},
+};
+
+struct platform_device msm_device_smd = {
+	.name	= "msm_smd",
+	.id	= -1,
+};
+
+static struct resource msm_dmov_resource[] = {
+	{
+		.start = INT_ADM_AARM,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = 0xA9700000,
+		.end = 0xA9700000 + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct msm_dmov_pdata msm_dmov_pdata = {
+	.sd = 3,
+	.sd_size = 0x400,
+};
+
+struct platform_device msm_device_dmov = {
+	.name	= "msm_dmov",
+	.id	= -1,
+	.resource = msm_dmov_resource,
+	.num_resources = ARRAY_SIZE(msm_dmov_resource),
+	.dev = {
+		.platform_data = &msm_dmov_pdata,
+	},
+};
+
+static struct msm_pm_irq_calls msm7x27_pm_irq_calls = {
+	.irq_pending = msm_irq_pending,
+	.idle_sleep_allowed = msm_irq_idle_sleep_allowed,
+	.enter_sleep1 = msm_irq_enter_sleep1,
+	.enter_sleep2 = msm_irq_enter_sleep2,
+	.exit_sleep1 = msm_irq_exit_sleep1,
+	.exit_sleep2 = msm_irq_exit_sleep2,
+	.exit_sleep3 = msm_irq_exit_sleep3,
+};
+
+void __init msm_pm_register_irqs(void)
+{
+	msm_pm_set_irq_extns(&msm7x27_pm_irq_calls);
+}
+
+#define MSM_SDC1_BASE         0xA0400000
+#define MSM_SDC2_BASE         0xA0500000
+#define MSM_SDC3_BASE         0xA0600000
+#define MSM_SDC4_BASE         0xA0700000
+static struct resource resources_sdc1[] = {
+	{
+		.start	= MSM_SDC1_BASE,
+		.end	= MSM_SDC1_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SDC1_0,
+		.end	= INT_SDC1_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC1_CHAN,
+		.end	= DMOV_SDC1_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC1_CRCI,
+		.end	= DMOV_SDC1_CRCI,
+		.flags	= IORESOURCE_DMA,
+	}
+};
+
+static struct resource resources_sdc2[] = {
+	{
+		.start	= MSM_SDC2_BASE,
+		.end	= MSM_SDC2_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SDC2_0,
+		.end	= INT_SDC2_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC2_CHAN,
+		.end	= DMOV_SDC2_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC2_CRCI,
+		.end	= DMOV_SDC2_CRCI,
+		.flags	= IORESOURCE_DMA,
+	}
+};
+
+static struct resource resources_sdc3[] = {
+	{
+		.start	= MSM_SDC3_BASE,
+		.end	= MSM_SDC3_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SDC3_0,
+		.end	= INT_SDC3_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC3_CHAN,
+		.end	= DMOV_SDC3_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC3_CRCI,
+		.end	= DMOV_SDC3_CRCI,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+static struct resource resources_sdc4[] = {
+	{
+		.start	= MSM_SDC4_BASE,
+		.end	= MSM_SDC4_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SDC4_0,
+		.end	= INT_SDC4_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC4_CHAN,
+		.end	= DMOV_SDC4_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC4_CRCI,
+		.end	= DMOV_SDC4_CRCI,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+struct platform_device msm_device_sdc1 = {
+	.name		= "msm_sdcc",
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(resources_sdc1),
+	.resource	= resources_sdc1,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_sdc2 = {
+	.name		= "msm_sdcc",
+	.id		= 2,
+	.num_resources	= ARRAY_SIZE(resources_sdc2),
+	.resource	= resources_sdc2,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_sdc3 = {
+	.name		= "msm_sdcc",
+	.id		= 3,
+	.num_resources	= ARRAY_SIZE(resources_sdc3),
+	.resource	= resources_sdc3,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_sdc4 = {
+	.name		= "msm_sdcc",
+	.id		= 4,
+	.num_resources	= ARRAY_SIZE(resources_sdc4),
+	.resource	= resources_sdc4,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+static struct platform_device *msm_sdcc_devices[] __initdata = {
+	&msm_device_sdc1,
+	&msm_device_sdc2,
+	&msm_device_sdc3,
+	&msm_device_sdc4,
+};
+
+int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat)
+{
+	struct platform_device	*pdev;
+
+	if (controller < 1 || controller > 4)
+		return -EINVAL;
+
+	pdev = msm_sdcc_devices[controller-1];
+	pdev->dev.platform_data = plat;
+	return platform_device_register(pdev);
+}
+
+#if defined(CONFIG_FB_MSM_MDP40)
+#define MDP_BASE          0xA3F00000
+#define PMDH_BASE         0xAD600000
+#define EMDH_BASE         0xAD700000
+#define TVENC_BASE        0xAD400000
+#else
+#define MDP_BASE          0xAA200000
+#define PMDH_BASE         0xAA600000
+#define EMDH_BASE         0xAA700000
+#define TVENC_BASE        0xAA400000
+#endif
+
+static struct resource msm_mdp_resources[] = {
+	{
+		.name   = "mdp",
+		.start  = MDP_BASE,
+		.end    = MDP_BASE + 0x000F0000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = INT_MDP,
+		.end    = INT_MDP,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct resource msm_mddi_resources[] = {
+	{
+		.name   = "pmdh",
+		.start  = PMDH_BASE,
+		.end    = PMDH_BASE + PAGE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	}
+};
+
+static struct resource msm_mddi_ext_resources[] = {
+	{
+		.name   = "emdh",
+		.start  = EMDH_BASE,
+		.end    = EMDH_BASE + PAGE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	}
+};
+
+static struct resource msm_ebi2_lcd_resources[] = {
+	{
+		.name   = "base",
+		.start  = 0xa0d00000,
+		.end    = 0xa0d00000 + PAGE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "lcd01",
+		.start  = 0x98000000,
+		.end    = 0x98000000 + 0x80000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "lcd02",
+		.start  = 0x9c000000,
+		.end    = 0x9c000000 + 0x80000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+static struct resource msm_tvenc_resources[] = {
+	{
+		.name   = "tvenc",
+		.start  = TVENC_BASE,
+		.end    = TVENC_BASE + PAGE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device msm_mdp_device = {
+	.name   = "mdp",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_mdp_resources),
+	.resource       = msm_mdp_resources,
+};
+
+static struct platform_device msm_mddi_device = {
+	.name   = "mddi",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_mddi_resources),
+	.resource       = msm_mddi_resources,
+};
+
+static struct platform_device msm_mddi_ext_device = {
+	.name   = "mddi_ext",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_mddi_ext_resources),
+	.resource       = msm_mddi_ext_resources,
+};
+
+static struct platform_device msm_ebi2_lcd_device = {
+	.name   = "ebi2_lcd",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_ebi2_lcd_resources),
+	.resource       = msm_ebi2_lcd_resources,
+};
+
+static struct platform_device msm_lcdc_device = {
+	.name   = "lcdc",
+	.id     = 0,
+};
+
+static struct platform_device msm_tvenc_device = {
+	.name   = "tvenc",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_tvenc_resources),
+	.resource       = msm_tvenc_resources,
+};
+
+/* TSIF begin */
+#if defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE)
+
+#define MSM_TSIF_PHYS        (0xa0100000)
+#define MSM_TSIF_SIZE        (0x200)
+
+static struct resource tsif_resources[] = {
+	[0] = {
+		.flags = IORESOURCE_IRQ,
+		.start = INT_TSIF_IRQ,
+		.end   = INT_TSIF_IRQ,
+	},
+	[1] = {
+		.flags = IORESOURCE_MEM,
+		.start = MSM_TSIF_PHYS,
+		.end   = MSM_TSIF_PHYS + MSM_TSIF_SIZE - 1,
+	},
+	[2] = {
+		.flags = IORESOURCE_DMA,
+		.start = DMOV_TSIF_CHAN,
+		.end   = DMOV_TSIF_CRCI,
+	},
+};
+
+static void tsif_release(struct device *dev)
+{
+	dev_info(dev, "release\n");
+}
+
+struct platform_device msm_device_tsif = {
+	.name          = "msm_tsif",
+	.id            = 0,
+	.num_resources = ARRAY_SIZE(tsif_resources),
+	.resource      = tsif_resources,
+	.dev = {
+		.release       = tsif_release,
+	},
+};
+#endif /* defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE) */
+/* TSIF end   */
+
+#define MSM_TSSC_PHYS         0xAA300000
+static struct resource resources_tssc[] = {
+	{
+		.start	= MSM_TSSC_PHYS,
+		.end	= MSM_TSSC_PHYS + SZ_4K - 1,
+		.name	= "tssc",
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_TCHSCRN1,
+		.end	= INT_TCHSCRN1,
+		.name	= "tssc1",
+		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_RISING,
+	},
+	{
+		.start	= INT_TCHSCRN2,
+		.end	= INT_TCHSCRN2,
+		.name	= "tssc2",
+		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_RISING,
+	},
+};
+
+struct platform_device msm_device_tssc = {
+	.name = "msm_touchscreen",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(resources_tssc),
+	.resource = resources_tssc,
+};
+
+static void __init msm_register_device(struct platform_device *pdev, void *data)
+{
+	int ret;
+
+	pdev->dev.platform_data = data;
+
+	ret = platform_device_register(pdev);
+	if (ret)
+		dev_err(&pdev->dev,
+			  "%s: platform_device_register() failed = %d\n",
+			  __func__, ret);
+}
+
+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, "pmdh", 4))
+		msm_register_device(&msm_mddi_device, data);
+	else if (!strncmp(name, "emdh", 4))
+		msm_register_device(&msm_mddi_ext_device, data);
+	else if (!strncmp(name, "ebi2", 4))
+		msm_register_device(&msm_ebi2_lcd_device, data);
+	else if (!strncmp(name, "tvenc", 5))
+		msm_register_device(&msm_tvenc_device, data);
+	else if (!strncmp(name, "lcdc", 4))
+		msm_register_device(&msm_lcdc_device, data);
+	else
+		printk(KERN_ERR "%s: unknown device! %s\n", __func__, name);
+}
+
+static struct platform_device msm_camera_device = {
+	.name	= "msm_camera",
+	.id	= 0,
+};
+
+void __init msm_camera_register_device(void *res, uint32_t num,
+	void *data)
+{
+	msm_camera_device.num_resources = num;
+	msm_camera_device.resource = res;
+
+	msm_register_device(&msm_camera_device, data);
+}
+
+static struct resource kgsl_3d0_resources[] = {
+	{
+		.name  = KGSL_3D0_REG_MEMORY,
+		.start = 0xA0000000,
+		.end = 0xA001ffff,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = KGSL_3D0_IRQ,
+		.start = INT_GRAPHICS,
+		.end = INT_GRAPHICS,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct kgsl_device_platform_data kgsl_3d0_pdata = {
+	/* bus_freq has been set to 160000 for power savings.
+	* OEMs may modify the value at their discretion for performance
+	* The appropriate maximum replacement for 160000 is:
+	* msm7x2x_clock_data.max_axi_khz
+	*/
+	.pwrlevel = {
+		{
+			.gpu_freq = 0,
+			.bus_freq = 160000000,
+		},
+	},
+	.init_level = 0,
+	.num_levels = 1,
+	.set_grp_async = NULL,
+	.idle_timeout = HZ,
+	.strtstp_sleepwake = true,
+	.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM,
+};
+
+struct platform_device msm_kgsl_3d0 = {
+	.name = "kgsl-3d0",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(kgsl_3d0_resources),
+	.resource = kgsl_3d0_resources,
+	.dev = {
+		.platform_data = &kgsl_3d0_pdata,
+	},
+};
+
+struct platform_device *msm_footswitch_devices[] = {
+	FS_PCOM(FS_GFX3D,  "vdd", "kgsl-3d0.0"),
+};
+unsigned msm_num_footswitch_devices = ARRAY_SIZE(msm_footswitch_devices);
+
+static struct resource gpio_resources[] = {
+	{
+		.start  = INT_GPIO_GROUP1,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.start  = INT_GPIO_GROUP2,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device msm_device_gpio = {
+	.name	   = "msmgpio",
+	.id	     = -1,
+	.resource       = gpio_resources,
+	.num_resources  = ARRAY_SIZE(gpio_resources),
+};
+
+static int __init msm7627_init_gpio(void)
+{
+	platform_device_register(&msm_device_gpio);
+	return 0;
+}
+
+postcore_initcall(msm7627_init_gpio);
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
new file mode 100644
index 0000000..2d79f62
--- /dev/null
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -0,0 +1,1728 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/msm_kgsl.h>
+#include <linux/regulator/machine.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/notifier.h>
+#include <mach/irqs.h>
+#include <mach/msm_iomap.h>
+#include <mach/board.h>
+#include <mach/dma.h>
+#include <mach/dal_axi.h>
+#include <asm/mach/flash.h>
+#include <asm/hardware/gic.h>
+#include <asm/hardware/cache-l2x0.h>
+#include <asm/mach/mmc.h>
+#include <asm/cacheflush.h>
+#include <mach/rpc_hsusb.h>
+#include <mach/socinfo.h>
+
+#include "devices.h"
+#include "devices-msm7x2xa.h"
+#include "footswitch.h"
+#include "acpuclock.h"
+#include "spm.h"
+#include "mpm-8625.h"
+#include "irq.h"
+#include "pm.h"
+
+/* Address of GSBI blocks */
+#define MSM_GSBI0_PHYS		0xA1200000
+#define MSM_GSBI1_PHYS		0xA1300000
+
+/* GSBI QUPe devices */
+#define MSM_GSBI0_QUP_PHYS	(MSM_GSBI0_PHYS + 0x80000)
+#define MSM_GSBI1_QUP_PHYS	(MSM_GSBI1_PHYS + 0x80000)
+
+static struct resource gsbi0_qup_i2c_resources[] = {
+	{
+		.name	= "qup_phys_addr",
+		.start	= MSM_GSBI0_QUP_PHYS,
+		.end	= MSM_GSBI0_QUP_PHYS + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "gsbi_qup_i2c_addr",
+		.start	= MSM_GSBI0_PHYS,
+		.end	= MSM_GSBI0_PHYS + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_err_intr",
+		.start	= INT_PWB_I2C,
+		.end	= INT_PWB_I2C,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+/* Use GSBI0 QUP for /dev/i2c-0 */
+struct platform_device msm_gsbi0_qup_i2c_device = {
+	.name		= "qup_i2c",
+	.id		= MSM_GSBI0_QUP_I2C_BUS_ID,
+	.num_resources	= ARRAY_SIZE(gsbi0_qup_i2c_resources),
+	.resource	= gsbi0_qup_i2c_resources,
+};
+
+static struct resource gsbi1_qup_i2c_resources[] = {
+	{
+		.name	= "qup_phys_addr",
+		.start	= MSM_GSBI1_QUP_PHYS,
+		.end	= MSM_GSBI1_QUP_PHYS + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "gsbi_qup_i2c_addr",
+		.start	= MSM_GSBI1_PHYS,
+		.end	= MSM_GSBI1_PHYS + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_err_intr",
+		.start	= INT_ARM11_DMA,
+		.end	= INT_ARM11_DMA,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+/* Use GSBI1 QUP for /dev/i2c-1 */
+struct platform_device msm_gsbi1_qup_i2c_device = {
+	.name		= "qup_i2c",
+	.id		= MSM_GSBI1_QUP_I2C_BUS_ID,
+	.num_resources	= ARRAY_SIZE(gsbi1_qup_i2c_resources),
+	.resource	= gsbi1_qup_i2c_resources,
+};
+
+#define MSM_HSUSB_PHYS        0xA0800000
+static struct resource resources_hsusb_otg[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_USB_HS,
+		.end	= INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static u64 dma_mask = 0xffffffffULL;
+struct platform_device msm_device_otg = {
+	.name		= "msm_otg",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_hsusb_otg),
+	.resource	= resources_hsusb_otg,
+	.dev		= {
+		.dma_mask		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+static struct resource resources_gadget_peripheral[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_USB_HS,
+		.end	= INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_gadget_peripheral = {
+	.name		= "msm_hsusb",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_gadget_peripheral),
+	.resource	= resources_gadget_peripheral,
+	.dev		= {
+		.dma_mask		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+static struct resource resources_hsusb_host[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_USB_HS,
+		.end	= INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_hsusb_host = {
+	.name		= "msm_hsusb_host",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(resources_hsusb_host),
+	.resource	= resources_hsusb_host,
+	.dev		= {
+		.dma_mask		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+static struct platform_device *msm_host_devices[] = {
+	&msm_device_hsusb_host,
+};
+
+static struct resource msm_dmov_resource[] = {
+	{
+		.start = INT_ADM_AARM,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = 0xA9700000,
+		.end = 0xA9700000 + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct msm_dmov_pdata msm_dmov_pdata = {
+	.sd = 3,
+	.sd_size = 0x400,
+};
+
+struct platform_device msm_device_dmov = {
+	.name	= "msm_dmov",
+	.id	= -1,
+	.resource = msm_dmov_resource,
+	.num_resources = ARRAY_SIZE(msm_dmov_resource),
+	.dev = {
+		.platform_data = &msm_dmov_pdata,
+	},
+};
+
+struct platform_device msm_device_smd = {
+	.name	= "msm_smd",
+	.id	= -1,
+};
+
+static struct resource smd_8625_resource[] = {
+	{
+		.name   = "a9_m2a_0",
+		.start  = MSM8625_INT_A9_M2A_0,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "a9_m2a_5",
+		.start  = MSM8625_INT_A9_M2A_5,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct smd_subsystem_config smd_8625_config_list[] = {
+	{
+		.irq_config_id = SMD_MODEM,
+		.subsys_name = "modem",
+		.edge = SMD_APPS_MODEM,
+
+		.smd_int.irq_name = "a9_m2a_0",
+		.smd_int.flags = IRQF_TRIGGER_RISING,
+		.smd_int.irq_id = -1,
+		.smd_int.device_name = "smd_dev",
+		.smd_int.dev_id = 0,
+
+		.smd_int.out_bit_pos =  1,
+		.smd_int.out_base = (void __iomem *)MSM_CSR_BASE,
+		.smd_int.out_offset = 0x400 + (0) * 4,
+
+		.smsm_int.irq_name = "a9_m2a_5",
+		.smsm_int.flags = IRQF_TRIGGER_RISING,
+		.smsm_int.irq_id = -1,
+		.smsm_int.device_name = "smsm_dev",
+		.smsm_int.dev_id = 0,
+
+		.smsm_int.out_bit_pos =  1,
+		.smsm_int.out_base = (void __iomem *)MSM_CSR_BASE,
+		.smsm_int.out_offset = 0x400 + (5) * 4,
+
+	}
+};
+
+static struct smd_platform smd_8625_platform_data = {
+	.num_ss_configs = ARRAY_SIZE(smd_8625_config_list),
+	.smd_ss_configs = smd_8625_config_list,
+};
+
+struct platform_device msm8625_device_smd = {
+	.name	= "msm_smd",
+	.id	= -1,
+	.resource = smd_8625_resource,
+	.num_resources = ARRAY_SIZE(smd_8625_resource),
+	.dev = {
+		.platform_data = &smd_8625_platform_data,
+	}
+};
+
+static struct resource resources_adsp[] = {
+	{
+		.start  = INT_ADSP_A9_A11,
+		.end    = INT_ADSP_A9_A11,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_adsp_device = {
+	.name           = "msm_adsp",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(resources_adsp),
+	.resource       = resources_adsp,
+};
+
+static struct resource resources_uart1[] = {
+	{
+		.start	= INT_UART1,
+		.end	= INT_UART1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM7XXX_UART1_PHYS,
+		.end	= MSM7XXX_UART1_PHYS + MSM7XXX_UART1_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_device_uart1 = {
+	.name	= "msm_serial",
+	.id	= 0,
+	.num_resources	= ARRAY_SIZE(resources_uart1),
+	.resource	= resources_uart1,
+};
+
+#define MSM_UART1DM_PHYS      0xA0200000
+static struct resource msm_uart1_dm_resources[] = {
+	{
+		.start	= MSM_UART1DM_PHYS,
+		.end	= MSM_UART1DM_PHYS + PAGE_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_UART1DM_IRQ,
+		.end	= INT_UART1DM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= INT_UART1DM_RX,
+		.end	= INT_UART1DM_RX,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= DMOV_HSUART1_TX_CHAN,
+		.end	= DMOV_HSUART1_RX_CHAN,
+		.name	= "uartdm_channels",
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.start	= DMOV_HSUART1_TX_CRCI,
+		.end	= DMOV_HSUART1_RX_CRCI,
+		.name	= "uartdm_crci",
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+static u64 msm_uart_dm1_dma_mask = DMA_BIT_MASK(32);
+struct platform_device msm_device_uart_dm1 = {
+	.name	= "msm_serial_hs",
+	.id	= 0,
+	.num_resources	= ARRAY_SIZE(msm_uart1_dm_resources),
+	.resource	= msm_uart1_dm_resources,
+	.dev	= {
+		.dma_mask		= &msm_uart_dm1_dma_mask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+};
+
+#define MSM_UART2DM_PHYS	0xA0300000
+static struct resource msm_uart2dm_resources[] = {
+	{
+		.start	= MSM_UART2DM_PHYS,
+		.end	= MSM_UART2DM_PHYS + PAGE_SIZE - 1,
+		.name	= "uartdm_resource",
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_UART2DM_IRQ,
+		.end	= INT_UART2DM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_uart_dm2 = {
+	.name	= "msm_serial_hsl",
+	.id	= 0,
+	.num_resources	= ARRAY_SIZE(msm_uart2dm_resources),
+	.resource	= msm_uart2dm_resources,
+};
+
+#define MSM_NAND_PHYS		0xA0A00000
+#define MSM_NANDC01_PHYS	0xA0A40000
+#define MSM_NANDC10_PHYS	0xA0A80000
+#define MSM_NANDC11_PHYS	0xA0AC0000
+#define EBI2_REG_BASE		0xA0D00000
+static struct resource resources_nand[] = {
+	[0] = {
+		.name   = "msm_nand_dmac",
+		.start	= DMOV_NAND_CHAN,
+		.end	= DMOV_NAND_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	[1] = {
+		.name   = "msm_nand_phys",
+		.start  = MSM_NAND_PHYS,
+		.end    = MSM_NAND_PHYS + 0x7FF,
+		.flags  = IORESOURCE_MEM,
+	},
+	[2] = {
+		.name   = "msm_nandc01_phys",
+		.start  = MSM_NANDC01_PHYS,
+		.end    = MSM_NANDC01_PHYS + 0x7FF,
+		.flags  = IORESOURCE_MEM,
+	},
+	[3] = {
+		.name   = "msm_nandc10_phys",
+		.start  = MSM_NANDC10_PHYS,
+		.end    = MSM_NANDC10_PHYS + 0x7FF,
+		.flags  = IORESOURCE_MEM,
+	},
+	[4] = {
+		.name   = "msm_nandc11_phys",
+		.start  = MSM_NANDC11_PHYS,
+		.end    = MSM_NANDC11_PHYS + 0x7FF,
+		.flags  = IORESOURCE_MEM,
+	},
+	[5] = {
+		.name   = "ebi2_reg_base",
+		.start  = EBI2_REG_BASE,
+		.end    = EBI2_REG_BASE + 0x60,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+struct flash_platform_data msm_nand_data;
+
+struct platform_device msm_device_nand = {
+	.name		= "msm_nand",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_nand),
+	.resource	= resources_nand,
+	.dev		= {
+		.platform_data	= &msm_nand_data,
+	},
+};
+
+static struct msm_pm_irq_calls msm7x27a_pm_irq_calls = {
+	.irq_pending = msm_irq_pending,
+	.idle_sleep_allowed = msm_irq_idle_sleep_allowed,
+	.enter_sleep1 = msm_irq_enter_sleep1,
+	.enter_sleep2 = msm_irq_enter_sleep2,
+	.exit_sleep1 = msm_irq_exit_sleep1,
+	.exit_sleep2 = msm_irq_exit_sleep2,
+	.exit_sleep3 = msm_irq_exit_sleep3,
+};
+
+static struct msm_pm_irq_calls msm8625_pm_irq_calls = {
+	.irq_pending = msm_gic_spi_ppi_pending,
+	.idle_sleep_allowed = msm_gic_irq_idle_sleep_allowed,
+	.enter_sleep1 = msm_gic_irq_enter_sleep1,
+	.enter_sleep2 = msm_gic_irq_enter_sleep2,
+	.exit_sleep1 = msm_gic_irq_exit_sleep1,
+	.exit_sleep2 = msm_gic_irq_exit_sleep2,
+	.exit_sleep3 = msm_gic_irq_exit_sleep3,
+};
+
+void __init msm_pm_register_irqs(void)
+{
+	if (cpu_is_msm8625())
+		msm_pm_set_irq_extns(&msm8625_pm_irq_calls);
+	else
+		msm_pm_set_irq_extns(&msm7x27a_pm_irq_calls);
+
+}
+
+#define MSM_SDC1_BASE         0xA0400000
+#define MSM_SDC2_BASE         0xA0500000
+#define MSM_SDC3_BASE         0xA0600000
+#define MSM_SDC4_BASE         0xA0700000
+static struct resource resources_sdc1[] = {
+	{
+		.start	= MSM_SDC1_BASE,
+		.end	= MSM_SDC1_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SDC1_0,
+		.end	= INT_SDC1_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC1_CHAN,
+		.end	= DMOV_SDC1_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC1_CRCI,
+		.end	= DMOV_SDC1_CRCI,
+		.flags	= IORESOURCE_DMA,
+	}
+};
+
+static struct resource resources_sdc2[] = {
+	{
+		.start	= MSM_SDC2_BASE,
+		.end	= MSM_SDC2_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SDC2_0,
+		.end	= INT_SDC2_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC2_CHAN,
+		.end	= DMOV_SDC2_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC2_CRCI,
+		.end	= DMOV_SDC2_CRCI,
+		.flags	= IORESOURCE_DMA,
+	}
+};
+
+static struct resource resources_sdc3[] = {
+	{
+		.start	= MSM_SDC3_BASE,
+		.end	= MSM_SDC3_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SDC3_0,
+		.end	= INT_SDC3_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC3_CHAN,
+		.end	= DMOV_SDC3_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC3_CRCI,
+		.end	= DMOV_SDC3_CRCI,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+static struct resource resources_sdc4[] = {
+	{
+		.start	= MSM_SDC4_BASE,
+		.end	= MSM_SDC4_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SDC4_0,
+		.end	= INT_SDC4_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC4_CHAN,
+		.end	= DMOV_SDC4_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC4_CRCI,
+		.end	= DMOV_SDC4_CRCI,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+struct platform_device msm_device_sdc1 = {
+	.name		= "msm_sdcc",
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(resources_sdc1),
+	.resource	= resources_sdc1,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_sdc2 = {
+	.name		= "msm_sdcc",
+	.id		= 2,
+	.num_resources	= ARRAY_SIZE(resources_sdc2),
+	.resource	= resources_sdc2,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_sdc3 = {
+	.name		= "msm_sdcc",
+	.id		= 3,
+	.num_resources	= ARRAY_SIZE(resources_sdc3),
+	.resource	= resources_sdc3,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_sdc4 = {
+	.name		= "msm_sdcc",
+	.id		= 4,
+	.num_resources	= ARRAY_SIZE(resources_sdc4),
+	.resource	= resources_sdc4,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+static struct platform_device *msm_sdcc_devices[] __initdata = {
+	&msm_device_sdc1,
+	&msm_device_sdc2,
+	&msm_device_sdc3,
+	&msm_device_sdc4,
+};
+
+#ifdef CONFIG_MSM_CAMERA_V4L2
+static int apps_reset;
+static struct resource msm_csic0_resources[] = {
+	{
+		.name   = "csic",
+		.start  = 0xA0F00000,
+		.end    = 0xA0F00000 + 0x00100000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "csic",
+		.start  = INT_CSI_IRQ_0,
+		.end    = INT_CSI_IRQ_0,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct resource msm_csic1_resources[] = {
+	{
+		.name   = "csic",
+		.start  = 0xA1000000,
+		.end    = 0xA1000000 + 0x00100000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "csic",
+		.start  = INT_CSI_IRQ_1,
+		.end    = INT_CSI_IRQ_1,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm7x27a_device_csic0 = {
+	.name           = "msm_csic",
+	.id             = 0,
+	.resource       = msm_csic0_resources,
+	.num_resources  = ARRAY_SIZE(msm_csic0_resources),
+};
+
+struct platform_device msm7x27a_device_csic1 = {
+	.name           = "msm_csic",
+	.id             = 1,
+	.resource       = msm_csic1_resources,
+	.num_resources  = ARRAY_SIZE(msm_csic1_resources),
+};
+
+static struct resource msm_clkctl_resources[] = {
+	{
+		.name   = "clk_ctl",
+		.start  = MSM7XXX_CLK_CTL_PHYS,
+		.end    = MSM7XXX_CLK_CTL_PHYS + MSM7XXX_CLK_CTL_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+struct platform_device msm7x27a_device_clkctl = {
+	.name           = "msm_clk_ctl",
+	.id             = 0,
+	.resource       = msm_clkctl_resources,
+	.num_resources  = ARRAY_SIZE(msm_clkctl_resources),
+	.dev = {
+		.platform_data = &apps_reset,
+	},
+};
+
+struct platform_device msm7x27a_device_vfe = {
+	.name           = "msm_vfe",
+	.id             = 0,
+};
+
+#endif
+
+/* Command sequence for simple WFI */
+static uint8_t spm_wfi_cmd_sequence[] __initdata = {
+	0x04, 0x03, 0x04, 0x0f,
+};
+
+/* Command sequence for GDFS, this won't send any interrupt to the modem */
+static uint8_t spm_pc_without_modem[] __initdata = {
+	0x20, 0x00, 0x30, 0x10,
+	0x03, 0x1e, 0x0e, 0x3e,
+	0x4e, 0x4e, 0x4e, 0x4e,
+	0x4e, 0x4e, 0x4e, 0x4e,
+	0x4e, 0x4e, 0x4e, 0x4e,
+	0x4e, 0x4e, 0x4e, 0x4e,
+	0x2E, 0x0f,
+};
+
+static struct msm_spm_seq_entry msm_spm_seq_list[] __initdata = {
+	[0] = {
+		.mode = MSM_SPM_MODE_CLOCK_GATING,
+		.notify_rpm = false,
+		.cmd = spm_wfi_cmd_sequence,
+	},
+	[1] = {
+		.mode = MSM_SPM_MODE_POWER_COLLAPSE,
+		.notify_rpm = false,
+		.cmd = spm_pc_without_modem,
+	},
+};
+
+static struct msm_spm_platform_data msm_spm_data[] __initdata = {
+	[0] = {
+		.reg_base_addr = MSM_SAW0_BASE,
+		.reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x0,
+		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
+		.num_modes = ARRAY_SIZE(msm_spm_seq_list),
+		.modes = msm_spm_seq_list,
+	},
+	[1] = {
+		.reg_base_addr = MSM_SAW1_BASE,
+		.reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x0,
+		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
+		.num_modes = ARRAY_SIZE(msm_spm_seq_list),
+		.modes = msm_spm_seq_list,
+	},
+};
+
+void __init msm8x25_spm_device_init(void)
+{
+	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
+}
+
+#define MDP_BASE		0xAA200000
+#define MIPI_DSI_HW_BASE	0xA1100000
+
+static struct resource msm_mipi_dsi_resources[] = {
+	{
+		.name   = "mipi_dsi",
+		.start  = MIPI_DSI_HW_BASE,
+		.end    = MIPI_DSI_HW_BASE + 0x000F0000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = INT_DSI_IRQ,
+		.end    = INT_DSI_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device msm_mipi_dsi_device = {
+	.name   = "mipi_dsi",
+	.id     = 1,
+	.num_resources  = ARRAY_SIZE(msm_mipi_dsi_resources),
+	.resource       = msm_mipi_dsi_resources,
+};
+
+static struct resource msm_mdp_resources[] = {
+	{
+		.name   = "mdp",
+		.start  = MDP_BASE,
+		.end    = MDP_BASE + 0x000F1008 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = INT_MDP,
+		.end    = INT_MDP,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device msm_mdp_device = {
+	.name   = "mdp",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_mdp_resources),
+	.resource       = msm_mdp_resources,
+};
+
+static struct platform_device msm_lcdc_device = {
+	.name   = "lcdc",
+	.id     = 0,
+};
+
+static struct resource kgsl_3d0_resources[] = {
+	{
+		.name  = KGSL_3D0_REG_MEMORY,
+		.start = 0xA0000000,
+		.end = 0xA001ffff,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = KGSL_3D0_IRQ,
+		.start = INT_GRAPHICS,
+		.end = INT_GRAPHICS,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct kgsl_device_platform_data kgsl_3d0_pdata = {
+	.pwrlevel = {
+		{
+			.gpu_freq = 245760000,
+			.bus_freq = 200000000,
+		},
+		{
+			.gpu_freq = 192000000,
+			.bus_freq = 160000000,
+		},
+		{
+			.gpu_freq = 133330000,
+			.bus_freq = 0,
+		},
+	},
+	.init_level = 0,
+	.num_levels = 3,
+	.set_grp_async = set_grp_xbar_async,
+	.idle_timeout = HZ,
+	.strtstp_sleepwake = true,
+	.nap_allowed = false,
+	.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM,
+};
+
+struct platform_device msm_kgsl_3d0 = {
+	.name = "kgsl-3d0",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(kgsl_3d0_resources),
+	.resource = kgsl_3d0_resources,
+	.dev = {
+		.platform_data = &kgsl_3d0_pdata,
+	},
+};
+
+void __init msm7x25a_kgsl_3d0_init(void)
+{
+	if (cpu_is_msm7x25a() || cpu_is_msm7x25aa() || cpu_is_msm7x25ab()) {
+		kgsl_3d0_pdata.num_levels = 2;
+		kgsl_3d0_pdata.pwrlevel[0].gpu_freq = 133330000;
+		kgsl_3d0_pdata.pwrlevel[0].bus_freq = 160000000;
+		kgsl_3d0_pdata.pwrlevel[1].gpu_freq = 96000000;
+		kgsl_3d0_pdata.pwrlevel[1].bus_freq = 0;
+	}
+}
+
+void __init msm8x25_kgsl_3d0_init(void)
+{
+	if (cpu_is_msm8625()) {
+		kgsl_3d0_pdata.idle_timeout = HZ/5;
+		kgsl_3d0_pdata.strtstp_sleepwake = false;
+		/* 8x25 supports a higher GPU frequency */
+		kgsl_3d0_pdata.pwrlevel[0].gpu_freq = 300000000;
+		kgsl_3d0_pdata.pwrlevel[0].bus_freq = 200000000;
+	}
+}
+
+static void __init msm_register_device(struct platform_device *pdev, void *data)
+{
+	int ret;
+
+	pdev->dev.platform_data = data;
+
+	ret = platform_device_register(pdev);
+
+	if (ret)
+		dev_err(&pdev->dev,
+			"%s: platform_device_register() failed = %d\n",
+				__func__, ret);
+}
+
+
+#define PERPH_WEB_BLOCK_ADDR (0xA9D00040)
+#define PDM0_CTL_OFFSET (0x04)
+#define SIZE_8B (0x08)
+
+static struct resource resources_led[] = {
+	{
+		.start	= PERPH_WEB_BLOCK_ADDR,
+		.end	= PERPH_WEB_BLOCK_ADDR + (SIZE_8B) - 1,
+		.name	= "led-gpio-pdm",
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct led_info msm_kpbl_pdm_led_pdata = {
+	.name = "keyboard-backlight",
+};
+
+struct platform_device led_pdev = {
+	.name	= "leds-msm-pdm",
+	/* use pdev id to represent pdm id */
+	.id	= 0,
+	.num_resources	= ARRAY_SIZE(resources_led),
+	.resource	= resources_led,
+	.dev	= {
+		.platform_data	= &msm_kpbl_pdm_led_pdata,
+	},
+};
+
+struct platform_device asoc_msm_pcm = {
+	.name   = "msm-dsp-audio",
+	.id     = 0,
+};
+
+struct platform_device asoc_msm_dai0 = {
+	.name   = "msm-codec-dai",
+	.id     = 0,
+};
+
+struct platform_device asoc_msm_dai1 = {
+	.name   = "msm-cpu-dai",
+	.id     = 0,
+};
+
+static struct resource gpio_resources[] = {
+	{
+		.start	= INT_GPIO_GROUP1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= INT_GPIO_GROUP2,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device msm_device_gpio = {
+	.name		= "msmgpio",
+	.id		= -1,
+	.resource	= gpio_resources,
+	.num_resources	= ARRAY_SIZE(gpio_resources),
+};
+
+struct platform_device *msm_footswitch_devices[] = {
+	FS_PCOM(FS_GFX3D,  "vdd", "kgsl-3d0.0"),
+};
+unsigned msm_num_footswitch_devices = ARRAY_SIZE(msm_footswitch_devices);
+
+/* MSM8625 Devices */
+
+static struct resource msm8625_resources_uart1[] = {
+	{
+		.start  = MSM8625_INT_UART1,
+		.end    = MSM8625_INT_UART1,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM7XXX_UART1_PHYS,
+		.end    = MSM7XXX_UART1_PHYS + MSM7XXX_UART1_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm8625_device_uart1 = {
+	.name		= "msm_serial",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(msm8625_resources_uart1),
+	.resource	= msm8625_resources_uart1,
+};
+
+static struct resource msm8625_uart1_dm_resources[] = {
+	{
+		.start	= MSM_UART1DM_PHYS,
+		.end	= MSM_UART1DM_PHYS + PAGE_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= MSM8625_INT_UART1DM_IRQ,
+		.end	= MSM8625_INT_UART1DM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM8625_INT_UART1DM_RX,
+		.end	= MSM8625_INT_UART1DM_RX,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= DMOV_HSUART1_TX_CHAN,
+		.end	= DMOV_HSUART1_RX_CHAN,
+		.name	= "uartdm_channels",
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.start	= DMOV_HSUART1_TX_CRCI,
+		.end	= DMOV_HSUART1_RX_CRCI,
+		.name	= "uartdm_crci",
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+struct platform_device msm8625_device_uart_dm1 = {
+	.name	= "msm_serial_hs",
+	.id	= 0,
+	.num_resources	= ARRAY_SIZE(msm8625_uart1_dm_resources),
+	.resource	= msm8625_uart1_dm_resources,
+	.dev	= {
+		.dma_mask		= &msm_uart_dm1_dma_mask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+};
+
+static struct resource msm8625_uart2dm_resources[] = {
+	{
+		.start	= MSM_UART2DM_PHYS,
+		.end	= MSM_UART2DM_PHYS + PAGE_SIZE - 1,
+		.name	= "uartdm_resource",
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= MSM8625_INT_UART2DM_IRQ,
+		.end	= MSM8625_INT_UART2DM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8625_device_uart_dm2 = {
+	.name	= "msm_serial_hsl",
+	.id	= 0,
+	.num_resources	= ARRAY_SIZE(msm8625_uart2dm_resources),
+	.resource	= msm8625_uart2dm_resources,
+};
+
+static struct resource msm8625_resources_adsp[] = {
+	{
+		.start  = MSM8625_INT_ADSP_A9_A11,
+		.end    = MSM8625_INT_ADSP_A9_A11,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8625_device_adsp = {
+	.name           = "msm_adsp",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(msm8625_resources_adsp),
+	.resource       = msm8625_resources_adsp,
+};
+
+static struct resource msm8625_dmov_resource[] = {
+	{
+		.start	= MSM8625_INT_ADM_AARM,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= 0xA9700000,
+		.end	= 0xA9700000 + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm8625_device_dmov = {
+	.name		= "msm_dmov",
+	.id		= -1,
+	.resource	= msm8625_dmov_resource,
+	.num_resources	= ARRAY_SIZE(msm8625_dmov_resource),
+	.dev		= {
+		.platform_data = &msm_dmov_pdata,
+	},
+};
+
+static struct resource gsbi0_msm8625_qup_resources[] = {
+	{
+		.name	= "qup_phys_addr",
+		.start	= MSM_GSBI0_QUP_PHYS,
+		.end	= MSM_GSBI0_QUP_PHYS + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "gsbi_qup_i2c_addr",
+		.start	= MSM_GSBI0_PHYS,
+		.end	= MSM_GSBI0_PHYS + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_err_intr",
+		.start	= MSM8625_INT_PWB_I2C,
+		.end	= MSM8625_INT_PWB_I2C,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+/* Use GSBI0 QUP for /dev/i2c-0 */
+struct platform_device msm8625_gsbi0_qup_i2c_device = {
+	.name		= "qup_i2c",
+	.id		= MSM_GSBI0_QUP_I2C_BUS_ID,
+	.num_resources	= ARRAY_SIZE(gsbi0_msm8625_qup_resources),
+	.resource	= gsbi0_msm8625_qup_resources,
+};
+
+static struct resource gsbi1_msm8625_qup_i2c_resources[] = {
+	{
+		.name	= "qup_phys_addr",
+		.start	= MSM_GSBI1_QUP_PHYS,
+		.end	= MSM_GSBI1_QUP_PHYS + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "gsbi_qup_i2c_addr",
+		.start	= MSM_GSBI1_PHYS,
+		.end	= MSM_GSBI1_PHYS + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_err_intr",
+		.start	= MSM8625_INT_ARM11_DMA,
+		.end	= MSM8625_INT_ARM11_DMA,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+/* Use GSBI1 QUP for /dev/i2c-1 */
+struct platform_device msm8625_gsbi1_qup_i2c_device = {
+	.name		= "qup_i2c",
+	.id		= MSM_GSBI1_QUP_I2C_BUS_ID,
+	.num_resources	= ARRAY_SIZE(gsbi1_qup_i2c_resources),
+	.resource	= gsbi1_msm8625_qup_i2c_resources,
+};
+
+static struct resource msm8625_gpio_resources[] = {
+	{
+		.start	= MSM8625_INT_GPIO_GROUP1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM8625_INT_GPIO_GROUP2,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device msm8625_device_gpio = {
+	.name		= "msmgpio",
+	.id		= -1,
+	.resource	= msm8625_gpio_resources,
+	.num_resources	= ARRAY_SIZE(msm8625_gpio_resources),
+};
+
+static struct resource msm8625_resources_sdc1[] = {
+	{
+		.start	= MSM_SDC1_BASE,
+		.end	= MSM_SDC1_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= MSM8625_INT_SDC1_0,
+		.end	= MSM8625_INT_SDC1_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC1_CHAN,
+		.end	= DMOV_SDC1_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC1_CRCI,
+		.end	= DMOV_SDC1_CRCI,
+		.flags	= IORESOURCE_DMA,
+	}
+};
+
+static struct resource msm8625_resources_sdc2[] = {
+	{
+		.start	= MSM_SDC2_BASE,
+		.end	= MSM_SDC2_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= MSM8625_INT_SDC2_0,
+		.end	= MSM8625_INT_SDC2_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC2_CHAN,
+		.end	= DMOV_SDC2_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC2_CRCI,
+		.end	= DMOV_SDC2_CRCI,
+		.flags	= IORESOURCE_DMA,
+	}
+};
+
+static struct resource msm8625_resources_sdc3[] = {
+	{
+		.start	= MSM_SDC3_BASE,
+		.end	= MSM_SDC3_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= MSM8625_INT_SDC3_0,
+		.end	= MSM8625_INT_SDC3_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC3_CHAN,
+		.end	= DMOV_SDC3_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC3_CRCI,
+		.end	= DMOV_SDC3_CRCI,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+static struct resource msm8625_resources_sdc4[] = {
+	{
+		.start	= MSM_SDC4_BASE,
+		.end	= MSM_SDC4_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= MSM8625_INT_SDC4_0,
+		.end	= MSM8625_INT_SDC4_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC4_CHAN,
+		.end	= DMOV_SDC4_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC4_CRCI,
+		.end	= DMOV_SDC4_CRCI,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+struct platform_device msm8625_device_sdc1 = {
+	.name		= "msm_sdcc",
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(msm8625_resources_sdc1),
+	.resource	= msm8625_resources_sdc1,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm8625_device_sdc2 = {
+	.name		= "msm_sdcc",
+	.id		= 2,
+	.num_resources	= ARRAY_SIZE(msm8625_resources_sdc2),
+	.resource	= msm8625_resources_sdc2,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm8625_device_sdc3 = {
+	.name		= "msm_sdcc",
+	.id		= 3,
+	.num_resources	= ARRAY_SIZE(msm8625_resources_sdc3),
+	.resource	= msm8625_resources_sdc3,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm8625_device_sdc4 = {
+	.name		= "msm_sdcc",
+	.id		= 4,
+	.num_resources	= ARRAY_SIZE(msm8625_resources_sdc4),
+	.resource	= msm8625_resources_sdc4,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+static struct platform_device *msm8625_sdcc_devices[] __initdata = {
+	&msm8625_device_sdc1,
+	&msm8625_device_sdc2,
+	&msm8625_device_sdc3,
+	&msm8625_device_sdc4,
+};
+
+int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat)
+{
+	struct platform_device	*pdev;
+
+	if (controller < 1 || controller > 4)
+		return -EINVAL;
+
+	if (cpu_is_msm8625())
+		pdev = msm8625_sdcc_devices[controller-1];
+	else
+		pdev = msm_sdcc_devices[controller-1];
+
+	pdev->dev.platform_data = plat;
+	return platform_device_register(pdev);
+}
+
+static struct resource msm8625_resources_hsusb_otg[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= MSM8625_INT_USB_HS,
+		.end	= MSM8625_INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8625_device_otg = {
+	.name		= "msm_otg",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(msm8625_resources_hsusb_otg),
+	.resource	= msm8625_resources_hsusb_otg,
+	.dev		= {
+		.dma_mask		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+static struct resource msm8625_resources_gadget_peripheral[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= MSM8625_INT_USB_HS,
+		.end	= MSM8625_INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8625_device_gadget_peripheral = {
+	.name		= "msm_hsusb",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(msm8625_resources_gadget_peripheral),
+	.resource	= msm8625_resources_gadget_peripheral,
+	.dev		= {
+		.dma_mask		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+static struct resource msm8625_resources_hsusb_host[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= MSM8625_INT_USB_HS,
+		.end	= MSM8625_INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8625_device_hsusb_host = {
+	.name		= "msm_hsusb_host",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(msm8625_resources_hsusb_host),
+	.resource	= msm8625_resources_hsusb_host,
+	.dev		= {
+		.dma_mask		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+static struct platform_device *msm8625_host_devices[] = {
+	&msm8625_device_hsusb_host,
+};
+
+int msm_add_host(unsigned int host, struct msm_usb_host_platform_data *plat)
+{
+	struct platform_device	*pdev;
+
+	if (cpu_is_msm8625())
+		pdev = msm8625_host_devices[host];
+	else
+		pdev = msm_host_devices[host];
+	if (!pdev)
+		return -ENODEV;
+	pdev->dev.platform_data = plat;
+	return platform_device_register(pdev);
+}
+
+#ifdef CONFIG_MSM_CAMERA_V4L2
+static struct resource msm8625_csic0_resources[] = {
+	{
+		.name   = "csic",
+		.start  = 0xA0F00000,
+		.end    = 0xA0F00000 + 0x00100000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "csic",
+		.start  = MSM8625_INT_CSI_IRQ_0,
+		.end    = MSM8625_INT_CSI_IRQ_0,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct resource msm8625_csic1_resources[] = {
+	{
+		.name   = "csic",
+		.start  = 0xA1000000,
+		.end    = 0xA1000000 + 0x00100000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "csic",
+		.start  = MSM8625_INT_CSI_IRQ_1,
+		.end    = MSM8625_INT_CSI_IRQ_1,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8625_device_csic0 = {
+	.name           = "msm_csic",
+	.id             = 0,
+	.resource       = msm8625_csic0_resources,
+	.num_resources  = ARRAY_SIZE(msm8625_csic0_resources),
+};
+
+struct platform_device msm8625_device_csic1 = {
+	.name           = "msm_csic",
+	.id             = 1,
+	.resource       = msm8625_csic1_resources,
+	.num_resources  = ARRAY_SIZE(msm8625_csic1_resources),
+};
+#endif
+
+static struct resource msm8625_mipi_dsi_resources[] = {
+	{
+		.name   = "mipi_dsi",
+		.start  = MIPI_DSI_HW_BASE,
+		.end    = MIPI_DSI_HW_BASE + 0x000F0000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = MSM8625_INT_DSI_IRQ,
+		.end    = MSM8625_INT_DSI_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device msm8625_mipi_dsi_device = {
+	.name   = "mipi_dsi",
+	.id     = 1,
+	.num_resources  = ARRAY_SIZE(msm8625_mipi_dsi_resources),
+	.resource       = msm8625_mipi_dsi_resources,
+};
+
+static struct resource msm8625_mdp_resources[] = {
+	{
+		.name   = "mdp",
+		.start  = MDP_BASE,
+		.end    = MDP_BASE + 0x000F1008 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = MSM8625_INT_MDP,
+		.end    = MSM8625_INT_MDP,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device msm8625_mdp_device = {
+	.name   = "mdp",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm8625_mdp_resources),
+	.resource       = msm8625_mdp_resources,
+};
+
+void __init msm_fb_register_device(char *name, void *data)
+{
+	if (!strncmp(name, "mdp", 3)) {
+		if (cpu_is_msm8625())
+			msm_register_device(&msm8625_mdp_device, data);
+		else
+			msm_register_device(&msm_mdp_device, data);
+	} else if (!strncmp(name, "mipi_dsi", 8)) {
+		if (cpu_is_msm8625())
+			msm_register_device(&msm8625_mipi_dsi_device, data);
+		else
+			msm_register_device(&msm_mipi_dsi_device, data);
+	} else if (!strncmp(name, "lcdc", 4)) {
+			msm_register_device(&msm_lcdc_device, data);
+	} else {
+		printk(KERN_ERR "%s: unknown device! %s\n", __func__, name);
+	}
+}
+
+static struct resource msm8625_kgsl_3d0_resources[] = {
+	{
+		.name  = KGSL_3D0_REG_MEMORY,
+		.start = 0xA0000000,
+		.end = 0xA001ffff,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = KGSL_3D0_IRQ,
+		.start = MSM8625_INT_GRAPHICS,
+		.end = MSM8625_INT_GRAPHICS,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8625_kgsl_3d0 = {
+	.name = "kgsl-3d0",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(msm8625_kgsl_3d0_resources),
+	.resource = msm8625_kgsl_3d0_resources,
+	.dev = {
+		.platform_data = &kgsl_3d0_pdata,
+	},
+};
+
+static struct clk_lookup msm_clock_8625_dummy[] = {
+	CLK_DUMMY("core_clk",		adm_clk.c,	"msm_dmov", 0),
+	CLK_DUMMY("adsp_clk",		adsp_clk.c,	NULL, 0),
+	CLK_DUMMY("ahb_m_clk",		ahb_m_clk.c,	NULL, 0),
+	CLK_DUMMY("ahb_s_clk",		ahb_s_clk.c,	NULL, 0),
+	CLK_DUMMY("cam_m_clk",		cam_m_clk.c,	NULL, 0),
+	CLK_DUMMY("csi_clk",		csi1_clk.c,	NULL, 0),
+	CLK_DUMMY("csi_pclk",		csi1_p_clk.c,	NULL, 0),
+	CLK_DUMMY("csi_vfe_clk",	csi1_vfe_clk.c,	NULL, 0),
+	CLK_DUMMY("dsi_byte_clk",	dsi_byte_clk.c,	NULL, 0),
+	CLK_DUMMY("dsi_clk",		dsi_clk.c,	NULL, 0),
+	CLK_DUMMY("dsi_esc_clk",	dsi_esc_clk.c,	NULL, 0),
+	CLK_DUMMY("dsi_pixel_clk",	dsi_pixel_clk.c, NULL, 0),
+	CLK_DUMMY("dsi_ref_clk",	dsi_ref_clk.c,	NULL, 0),
+	CLK_DUMMY("ebi1_clk",		ebi1_clk.c,	NULL, 0),
+	CLK_DUMMY("ebi2_clk",		ebi2_clk.c,	NULL, 0),
+	CLK_DUMMY("ecodec_clk",		ecodec_clk.c,	NULL, 0),
+	CLK_DUMMY("gp_clk",		gp_clk.c,	NULL, 0),
+	CLK_DUMMY("core_clk",		gsbi1_qup_clk.c, "qup_i2c.0", 0),
+	CLK_DUMMY("core_clk",		gsbi2_qup_clk.c, "qup_i2c.1", 0),
+	CLK_DUMMY("iface_clk",		gsbi1_qup_p_clk.c, "qup_i2c.0", 0),
+	CLK_DUMMY("iface_clk",		gsbi2_qup_p_clk.c, "qup_i2c.1", 0),
+	CLK_DUMMY("icodec_rx_clk",	icodec_rx_clk.c, NULL, 0),
+	CLK_DUMMY("icodec_tx_clk",	icodec_tx_clk.c, NULL, 0),
+	CLK_DUMMY("mem_clk",		imem_clk.c,	NULL, 0),
+	CLK_DUMMY("mddi_clk",		pmdh_clk.c,	NULL, 0),
+	CLK_DUMMY("mdp_clk",		mdp_clk.c,	NULL, 0),
+	CLK_DUMMY("mdp_lcdc_pclk_clk",	mdp_lcdc_pclk_clk.c, NULL, 0),
+	CLK_DUMMY("mdp_lcdc_pad_pclk_clk", mdp_lcdc_pad_pclk_clk.c, NULL, 0),
+	CLK_DUMMY("mdp_vsync_clk",	mdp_vsync_clk.c,	NULL, 0),
+	CLK_DUMMY("mdp_dsi_pclk",	mdp_dsi_p_clk.c,	NULL, 0),
+	CLK_DUMMY("pbus_clk",		pbus_clk.c,	NULL, 0),
+	CLK_DUMMY("pcm_clk",		pcm_clk.c,	NULL, 0),
+	CLK_DUMMY("sdac_clk",		sdac_clk.c,	NULL, 0),
+	CLK_DUMMY("core_clk",		sdc1_clk.c,	"msm_sdcc.1", 0),
+	CLK_DUMMY("iface_clk",		sdc1_p_clk.c,	"msm_sdcc.1", 0),
+	CLK_DUMMY("core_clk",		sdc2_clk.c,	"msm_sdcc.2", 0),
+	CLK_DUMMY("iface_clk",		sdc2_p_clk.c,	"msm_sdcc.2", 0),
+	CLK_DUMMY("core_clk",		sdc3_clk.c,	"msm_sdcc.3", 0),
+	CLK_DUMMY("iface_clk",		sdc3_p_clk.c,	"msm_sdcc.3", 0),
+	CLK_DUMMY("core_clk",		sdc4_clk.c,	"msm_sdcc.4", 0),
+	CLK_DUMMY("iface_clk",		sdc4_p_clk.c,	"msm_sdcc.4", 0),
+	CLK_DUMMY("ref_clk",		tsif_ref_clk.c,	"msm_tsif.0", 0),
+	CLK_DUMMY("iface_clk",		tsif_p_clk.c,	"msm_tsif.0", 0),
+	CLK_DUMMY("core_clk",		uart1_clk.c,	"msm_serial.0", 0),
+	CLK_DUMMY("core_clk",		uart2_clk.c,	"msm_serial.1", 0),
+	CLK_DUMMY("core_clk",		uart1dm_clk.c,	"msm_serial_hs.0", 0),
+	CLK_DUMMY("core_clk",		uart2dm_clk.c,	"msm_serial_hsl.0", 0),
+	CLK_DUMMY("usb_hs_core_clk",	usb_hs_core_clk.c, NULL, 0),
+	CLK_DUMMY("usb_hs2_clk",	usb_hs2_clk.c,	NULL, 0),
+	CLK_DUMMY("usb_hs_clk",		usb_hs_clk.c,	NULL, 0),
+	CLK_DUMMY("usb_hs_pclk",	usb_hs_p_clk.c,	NULL, 0),
+	CLK_DUMMY("usb_phy_clk",	usb_phy_clk.c,	NULL, 0),
+	CLK_DUMMY("vdc_clk",		vdc_clk.c,	NULL, 0),
+	CLK_DUMMY("ebi1_acpu_clk",	ebi_acpu_clk.c,	NULL, 0),
+	CLK_DUMMY("ebi1_lcdc_clk",	ebi_lcdc_clk.c,	NULL, 0),
+	CLK_DUMMY("ebi1_mddi_clk",	ebi_mddi_clk.c,	NULL, 0),
+	CLK_DUMMY("ebi1_usb_clk",	ebi_usb_clk.c,	NULL, 0),
+	CLK_DUMMY("ebi1_vfe_clk",	ebi_vfe_clk.c,	NULL, 0),
+	CLK_DUMMY("mem_clk",		ebi_adm_clk.c,	"msm_dmov", 0),
+};
+
+struct clock_init_data msm8625_dummy_clock_init_data __initdata = {
+	.table = msm_clock_8625_dummy,
+	.size = ARRAY_SIZE(msm_clock_8625_dummy),
+};
+
+enum {
+	MSM8625,
+	MSM8625A,
+};
+
+static int __init msm8625_cpu_id(void)
+{
+	int raw_id, cpu;
+
+	raw_id = socinfo_get_raw_id();
+	switch (raw_id) {
+	/* Part number for 1GHz part */
+	case 0x770:
+	case 0x771:
+	case 0x780:
+		cpu = MSM8625;
+		break;
+	/* Part number for 1.2GHz part */
+	case 0x773:
+	case 0x774:
+	case 0x781:
+		cpu = MSM8625A;
+		break;
+	default:
+		pr_err("Invalid Raw ID\n");
+		return -ENODEV;
+	}
+	return cpu;
+}
+
+int __init msm7x2x_misc_init(void)
+{
+	if (machine_is_msm8625_rumi3()) {
+		msm_clock_init(&msm8625_dummy_clock_init_data);
+		return 0;
+	}
+
+	msm_clock_init(&msm7x27a_clock_init_data);
+	if (cpu_is_msm7x27aa() || cpu_is_msm7x25ab())
+		acpuclk_init(&acpuclk_7x27aa_soc_data);
+	else if (cpu_is_msm8625()) {
+		if (msm8625_cpu_id() == MSM8625)
+			acpuclk_init(&acpuclk_7x27aa_soc_data);
+		else if (msm8625_cpu_id() == MSM8625A)
+			acpuclk_init(&acpuclk_8625_soc_data);
+	 } else {
+		acpuclk_init(&acpuclk_7x27a_soc_data);
+	 }
+
+
+	return 0;
+}
+
+#ifdef CONFIG_CACHE_L2X0
+static int __init msm7x27x_cache_init(void)
+{
+	int aux_ctrl = 0;
+	int pctrl = 0;
+
+	/* Way Size 010(0x2) 32KB */
+	aux_ctrl = (0x1 << L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT) | \
+		   (0x2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) | \
+		   (0x1 << L2X0_AUX_CTRL_EVNT_MON_BUS_EN_SHIFT);
+
+	if (cpu_is_msm8625()) {
+		/* Way Size 011(0x3) 64KB */
+		aux_ctrl |= (0x3 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) | \
+			    (0x1 << L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT) | \
+			    (0X1 << L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT) | \
+			    (0x1 << L2X0_AUX_CTRL_L2_FORCE_NWA_SHIFT);
+
+		/* Write Prefetch Control settings */
+		pctrl = readl_relaxed(MSM_L2CC_BASE + L2X0_PREFETCH_CTRL);
+		pctrl |= (0x3 << L2X0_PREFETCH_CTRL_OFFSET_SHIFT) | \
+			 (0x1 << L2X0_PREFETCH_CTRL_WRAP8_INC_SHIFT) | \
+			 (0x1 << L2X0_PREFETCH_CTRL_WRAP8_SHIFT);
+		writel_relaxed(pctrl , MSM_L2CC_BASE + L2X0_PREFETCH_CTRL);
+	}
+
+	l2x0_init(MSM_L2CC_BASE, aux_ctrl, L2X0_AUX_CTRL_MASK);
+	if (cpu_is_msm8625()) {
+		pctrl = readl_relaxed(MSM_L2CC_BASE + L2X0_PREFETCH_CTRL);
+		pr_info("Prfetch Ctrl: 0x%08x\n", pctrl);
+	}
+
+	return 0;
+}
+#else
+static int __init msm7x27x_cache_init(void){ return 0; }
+#endif
+
+void __init msm_common_io_init(void)
+{
+	msm_map_common_io();
+	if (socinfo_init() < 0)
+		pr_err("%s: socinfo_init() failed!\n", __func__);
+	msm7x27x_cache_init();
+}
+
+void __init msm8625_init_irq(void)
+{
+	msm_gic_irq_extn_init(MSM_QGIC_DIST_BASE, MSM_QGIC_CPU_BASE);
+	gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE,
+			(void *)MSM_QGIC_CPU_BASE);
+}
+
+void __init msm8625_map_io(void)
+{
+	msm_map_msm8625_io();
+
+	if (socinfo_init() < 0)
+		pr_err("%s: socinfo_init() failed!\n", __func__);
+	msm7x27x_cache_init();
+}
+
+static int msm7627a_init_gpio(void)
+{
+	if (cpu_is_msm8625())
+		platform_device_register(&msm8625_device_gpio);
+	else
+		platform_device_register(&msm_device_gpio);
+	return 0;
+}
+postcore_initcall(msm7627a_init_gpio);
+
+static int msm7627a_panic_handler(struct notifier_block *this,
+		unsigned long event, void *ptr)
+{
+	flush_cache_all();
+	outer_flush_all();
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block panic_handler = {
+	.notifier_call = msm7627a_panic_handler,
+};
+
+static int __init panic_register(void)
+{
+	atomic_notifier_chain_register(&panic_notifier_list,
+			&panic_handler);
+	return 0;
+}
+module_init(panic_register);
diff --git a/arch/arm/mach-msm/devices-msm7x2xa.h b/arch/arm/mach-msm/devices-msm7x2xa.h
new file mode 100644
index 0000000..4184a86
--- /dev/null
+++ b/arch/arm/mach-msm/devices-msm7x2xa.h
@@ -0,0 +1,36 @@
+/* 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
+ * 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 __ARCH_ARM_MACH_MSM_DEVICES_MSM7X2XA_H
+#define __ARCH_ARM_MACH_MSM_DEVICES_MSM7X2XA_H
+
+#define MSM_GSBI0_QUP_I2C_BUS_ID	0
+#define MSM_GSBI1_QUP_I2C_BUS_ID	1
+
+void __init msm_common_io_init(void);
+void __init msm_init_pmic_vibrator(void);
+void __init msm7x25a_kgsl_3d0_init(void);
+int __init msm7x2x_misc_init(void);
+extern struct platform_device msm7x27a_device_vfe;
+extern struct platform_device msm7x27a_device_csic0;
+extern struct platform_device msm7x27a_device_csic1;
+extern struct platform_device msm7x27a_device_clkctl;
+
+extern struct platform_device msm8625_device_csic0;
+extern struct platform_device msm8625_device_csic1;
+
+void __init msm8625_init_irq(void);
+void __init msm8625_map_io(void);
+int  ar600x_wlan_power(bool on);
+void __init msm8x25_spm_device_init(void);
+void __init msm8x25_kgsl_3d0_init(void);
+void __iomem *core1_reset_base(void);
+#endif
diff --git a/arch/arm/mach-msm/devices-msm7x30.c b/arch/arm/mach-msm/devices-msm7x30.c
index 09b4f14..00768a3 100644
--- a/arch/arm/mach-msm/devices-msm7x30.c
+++ b/arch/arm/mach-msm/devices-msm7x30.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. 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
@@ -15,23 +15,93 @@
 
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
-
+#include <linux/msm_rotator.h>
 #include <linux/dma-mapping.h>
-#include <linux/clkdev.h>
+#include <linux/msm_kgsl.h>
+#include <linux/android_pmem.h>
+#include <linux/regulator/machine.h>
+#include <linux/init.h>
 #include <mach/irqs.h>
 #include <mach/msm_iomap.h>
 #include <mach/dma.h>
 #include <mach/board.h>
+#include <asm/clkdev.h>
 
 #include "devices.h"
-#include "smd_private.h"
+#include "footswitch.h"
 
 #include <asm/mach/flash.h>
 
-#include "clock-pcom.h"
-#include "clock-7x30.h"
+#include <asm/mach/mmc.h>
+#include <mach/msm_hsusb.h>
+#ifdef CONFIG_PMIC8058
+#include <linux/mfd/pmic8058.h>
+#endif
+#include <mach/dal_axi.h>
+#include <mach/msm_memtypes.h>
+#include "pm.h"
+#include "irq.h"
 
-#include <mach/mmc.h>
+/* EBI THERMAL DRIVER */
+static struct resource msm_ebi0_thermal_resources[] = {
+	{
+		.start  = 0xA8600000,
+		.end    = 0xA86005FF,
+		.name   = "physbase",
+		.flags  = IORESOURCE_MEM
+	}
+};
+
+struct platform_device msm_ebi0_thermal = {
+	.name           = "msm_popmem-tm",
+	.id             = 0,
+	.num_resources  = 1,
+	.resource       = msm_ebi0_thermal_resources
+};
+
+static struct resource msm_ebi1_thermal_resources[] = {
+	{
+		.start  = 0xA8700000,
+		.end    = 0xA87005FF,
+		.name   = "physbase",
+		.flags  = IORESOURCE_MEM
+	}
+};
+
+struct platform_device msm_ebi1_thermal = {
+	.name           = "msm_popmem-tm",
+	.id             = 1,
+	.num_resources  = 1,
+	.resource       = msm_ebi1_thermal_resources
+};
+
+static struct resource resources_adsp[] = {
+{
+	.start  = INT_ADSP_A9_A11,
+	.end    = INT_ADSP_A9_A11,
+	.flags  = IORESOURCE_IRQ,
+},
+};
+
+struct platform_device msm_adsp_device = {
+	.name           = "msm_adsp",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(resources_adsp),
+	.resource       = resources_adsp,
+};
+
+static struct resource resources_uart1[] = {
+	{
+		.start	= INT_UART1,
+		.end	= INT_UART1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM7X30_UART1_PHYS,
+		.end	= MSM7X30_UART1_PHYS + MSM7X30_UART1_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
 
 static struct resource resources_uart2[] = {
 	{
@@ -40,13 +110,33 @@
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.start	= MSM_UART2_PHYS,
-		.end	= MSM_UART2_PHYS + MSM_UART2_SIZE - 1,
+		.start	= MSM7X30_UART2_PHYS,
+		.end	= MSM7X30_UART2_PHYS + MSM7X30_UART2_SIZE - 1,
 		.flags	= IORESOURCE_MEM,
 		.name  = "uart_resource"
 	},
 };
 
+static struct resource resources_uart3[] = {
+	{
+		.start	= INT_UART3,
+		.end	= INT_UART3,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM7X30_UART3_PHYS,
+		.end	= MSM7X30_UART3_PHYS + MSM7X30_UART3_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_device_uart1 = {
+	.name	= "msm_serial",
+	.id	= 0,
+	.num_resources	= ARRAY_SIZE(resources_uart1),
+	.resource	= resources_uart1,
+};
+
 struct platform_device msm_device_uart2 = {
 	.name	= "msm_serial",
 	.id	= 1,
@@ -54,15 +144,303 @@
 	.resource	= resources_uart2,
 };
 
-struct platform_device msm_device_smd = {
-	.name   = "msm_smd",
-	.id     = -1,
+struct platform_device msm_device_uart3 = {
+	.name	= "msm_serial",
+	.id	= 2,
+	.num_resources	= ARRAY_SIZE(resources_uart3),
+	.resource	= resources_uart3,
 };
 
-static struct resource resources_otg[] = {
+#define MSM_UART1DM_PHYS      0xA3300000
+#define MSM_UART2DM_PHYS      0xA3200000
+static struct resource msm_uart1_dm_resources[] = {
+	{
+		.start = MSM_UART1DM_PHYS,
+		.end   = MSM_UART1DM_PHYS + PAGE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = INT_UART1DM_IRQ,
+		.end   = INT_UART1DM_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = INT_UART1DM_RX,
+		.end   = INT_UART1DM_RX,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = DMOV_HSUART1_TX_CHAN,
+		.end   = DMOV_HSUART1_RX_CHAN,
+		.name  = "uartdm_channels",
+		.flags = IORESOURCE_DMA,
+	},
+	{
+		.start = DMOV_HSUART1_TX_CRCI,
+		.end   = DMOV_HSUART1_RX_CRCI,
+		.name  = "uartdm_crci",
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static u64 msm_uart_dm1_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device msm_device_uart_dm1 = {
+	.name = "msm_serial_hs",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(msm_uart1_dm_resources),
+	.resource = msm_uart1_dm_resources,
+	.dev		= {
+		.dma_mask = &msm_uart_dm1_dma_mask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
+
+static struct resource msm_uart2_dm_resources[] = {
+	{
+		.start = MSM_UART2DM_PHYS,
+		.end   = MSM_UART2DM_PHYS + PAGE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = INT_UART2DM_IRQ,
+		.end   = INT_UART2DM_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = INT_UART2DM_RX,
+		.end   = INT_UART2DM_RX,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = DMOV_HSUART2_TX_CHAN,
+		.end   = DMOV_HSUART2_RX_CHAN,
+		.name  = "uartdm_channels",
+		.flags = IORESOURCE_DMA,
+	},
+	{
+		.start = DMOV_HSUART2_TX_CRCI,
+		.end   = DMOV_HSUART2_RX_CRCI,
+		.name  = "uartdm_crci",
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static u64 msm_uart_dm2_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device msm_device_uart_dm2 = {
+	.name = "msm_serial_hs",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(msm_uart2_dm_resources),
+	.resource = msm_uart2_dm_resources,
+	.dev		= {
+		.dma_mask = &msm_uart_dm2_dma_mask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
+
+#define MSM_I2C_SIZE          SZ_4K
+#define MSM_I2C_PHYS          0xACD00000
+#define MSM_I2C_2_PHYS        0xACF00000
+static struct resource resources_i2c_2[] = {
+	{
+		.start	= MSM_I2C_2_PHYS,
+		.end	= MSM_I2C_2_PHYS + MSM_I2C_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_PWB_I2C_2,
+		.end	= INT_PWB_I2C_2,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_i2c_2 = {
+	.name		= "msm_i2c",
+	.id		= 2,
+	.num_resources	= ARRAY_SIZE(resources_i2c_2),
+	.resource	= resources_i2c_2,
+};
+
+static struct resource resources_i2c[] = {
+	{
+		.start	= MSM_I2C_PHYS,
+		.end	= MSM_I2C_PHYS + MSM_I2C_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_PWB_I2C,
+		.end	= INT_PWB_I2C,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_i2c = {
+	.name		= "msm_i2c",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(resources_i2c),
+	.resource	= resources_i2c,
+};
+
+#ifdef CONFIG_MSM_CAMERA_V4L2
+static struct resource msm_csic_resources[] = {
+	{
+		.name   = "csic",
+		.start  = 0xA6100000,
+		.end    = 0xA6100000 + 0x00000400 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "csic",
+		.start  = INT_CSI,
+		.end    = INT_CSI,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+struct resource msm_vfe_resources[] = {
+	{
+		.name   = "msm_vfe",
+		.start	= 0xA6000000,
+		.end	= 0xA6000000 + SZ_1M - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "msm_vfe",
+		.start	= INT_VFE,
+		.end	= INT_VFE,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name   = "msm_camif",
+		.start	= 0xAB000000,
+		.end	= 0xAB000000 + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct resource msm_vpe_resources[] = {
+	{
+		.name   = "vpe",
+		.start	= 0xAD200000,
+		.end	= 0xAD200000 + SZ_1M - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "vpe",
+		.start	= INT_VPE,
+		.end	= INT_VPE,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_csic0 = {
+	.name           = "msm_csic",
+	.id             = 0,
+	.resource       = msm_csic_resources,
+	.num_resources  = ARRAY_SIZE(msm_csic_resources),
+};
+
+struct platform_device msm_device_vfe = {
+	.name           = "msm_vfe",
+	.id             = 0,
+	.resource       = msm_vfe_resources,
+	.num_resources  = ARRAY_SIZE(msm_vfe_resources),
+};
+
+struct platform_device msm_device_vpe = {
+	.name           = "msm_vpe",
+	.id             = 0,
+	.resource       = msm_vpe_resources,
+	.num_resources  = ARRAY_SIZE(msm_vpe_resources),
+};
+#endif
+
+#define MSM_QUP_PHYS           0xA8301000
+#define MSM_GSBI_QUP_I2C_PHYS  0xA8300000
+#define MSM_QUP_SIZE           SZ_4K
+static struct resource resources_qup[] = {
+	{
+		.name   = "qup_phys_addr",
+		.start	= MSM_QUP_PHYS,
+		.end	= MSM_QUP_PHYS + MSM_QUP_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "gsbi_qup_i2c_addr",
+		.start	= MSM_GSBI_QUP_I2C_PHYS,
+		.end	= MSM_GSBI_QUP_I2C_PHYS + 4 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "qup_in_intr",
+		.start	= INT_PWB_QUP_IN,
+		.end	= INT_PWB_QUP_IN,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name   = "qup_out_intr",
+		.start	= INT_PWB_QUP_OUT,
+		.end	= INT_PWB_QUP_OUT,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name   = "qup_err_intr",
+		.start	= INT_PWB_QUP_ERR,
+		.end	= INT_PWB_QUP_ERR,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device qup_device_i2c = {
+	.name		= "qup_i2c",
+	.id		= 4,
+	.num_resources	= ARRAY_SIZE(resources_qup),
+	.resource	= resources_qup,
+};
+
+#ifdef CONFIG_MSM_SSBI
+#define MSM_SSBI_PMIC1_PHYS	0xAD900000
+static struct resource msm_ssbi_pmic1_resources[] = {
+	{
+		.start  = MSM_SSBI_PMIC1_PHYS,
+		.end    = MSM_SSBI_PMIC1_PHYS + SZ_4K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_device_ssbi_pmic1 = {
+	.name           = "msm_ssbi",
+	.id             = 0,
+	.resource       = msm_ssbi_pmic1_resources,
+	.num_resources  = ARRAY_SIZE(msm_ssbi_pmic1_resources),
+};
+#endif
+
+#ifdef CONFIG_I2C_SSBI
+#define MSM_SSBI7_PHYS  0xAC800000
+static struct resource msm_ssbi7_resources[] = {
+	{
+		.name   = "ssbi_base",
+		.start  = MSM_SSBI7_PHYS,
+		.end    = MSM_SSBI7_PHYS + SZ_4K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_device_ssbi7 = {
+	.name		= "i2c_ssbi",
+	.id		= 7,
+	.num_resources	= ARRAY_SIZE(msm_ssbi7_resources),
+	.resource	= msm_ssbi7_resources,
+};
+#endif /* CONFIG_I2C_SSBI */
+
+#define MSM_HSUSB_PHYS        0xA3600000
+static struct resource resources_hsusb_otg[] = {
 	{
 		.start	= MSM_HSUSB_PHYS,
-		.end	= MSM_HSUSB_PHYS + MSM_HSUSB_SIZE,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
@@ -72,44 +450,70 @@
 	},
 };
 
-struct platform_device msm_device_otg = {
-	.name		= "msm_otg",
-	.id		= -1,
-	.num_resources	= ARRAY_SIZE(resources_otg),
-	.resource	= resources_otg,
-	.dev		= {
-		.coherent_dma_mask	= 0xffffffff,
-	},
-};
-
-static struct resource resources_hsusb[] = {
-	{
-		.start	= MSM_HSUSB_PHYS,
-		.end	= MSM_HSUSB_PHYS + MSM_HSUSB_SIZE,
-		.flags	= IORESOURCE_MEM,
-	},
-	{
-		.start	= INT_USB_HS,
-		.end	= INT_USB_HS,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-struct platform_device msm_device_hsusb = {
-	.name		= "msm_hsusb",
-	.id		= -1,
-	.num_resources	= ARRAY_SIZE(resources_hsusb),
-	.resource	= resources_hsusb,
-	.dev		= {
-		.coherent_dma_mask	= 0xffffffff,
-	},
-};
-
 static u64 dma_mask = 0xffffffffULL;
+struct platform_device msm_device_hsusb_otg = {
+	.name		= "msm_hsusb_otg",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_hsusb_otg),
+	.resource	= resources_hsusb_otg,
+	.dev		= {
+		.dma_mask 		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+static struct resource resources_hsusb_peripheral[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_USB_HS,
+		.end	= INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct resource resources_gadget_peripheral[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_USB_HS,
+		.end	= INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_hsusb_peripheral = {
+	.name		= "msm_hsusb_peripheral",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_hsusb_peripheral),
+	.resource	= resources_hsusb_peripheral,
+	.dev		= {
+		.dma_mask 		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+struct platform_device msm_device_gadget_peripheral = {
+	.name		= "msm_hsusb",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_gadget_peripheral),
+	.resource	= resources_gadget_peripheral,
+	.dev		= {
+		.dma_mask 		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
 static struct resource resources_hsusb_host[] = {
 	{
 		.start	= MSM_HSUSB_PHYS,
-		.end	= MSM_HSUSB_PHYS + MSM_HSUSB_SIZE,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
@@ -121,90 +525,856 @@
 
 struct platform_device msm_device_hsusb_host = {
 	.name		= "msm_hsusb_host",
-	.id		= -1,
+	.id		= 0,
 	.num_resources	= ARRAY_SIZE(resources_hsusb_host),
 	.resource	= resources_hsusb_host,
 	.dev		= {
-		.dma_mask               = &dma_mask,
-		.coherent_dma_mask      = 0xffffffffULL,
+		.dma_mask 		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
 	},
 };
 
-struct clk_lookup msm_clocks_7x30[] = {
-	CLK_PCOM("adm_clk",	ADM_CLK,	NULL, 0),
-	CLK_PCOM("adsp_clk",	ADSP_CLK,	NULL, 0),
-	CLK_PCOM("cam_m_clk",	CAM_M_CLK,	NULL, 0),
-	CLK_PCOM("camif_pad_pclk",	CAMIF_PAD_P_CLK,	NULL, OFF),
-	CLK_PCOM("ce_clk",	CE_CLK,	NULL, 0),
-	CLK_PCOM("codec_ssbi_clk",	CODEC_SSBI_CLK,	NULL, 0),
-	CLK_PCOM("ebi1_clk",	EBI1_CLK,	NULL, CLK_MIN),
-	CLK_PCOM("ecodec_clk",	ECODEC_CLK,	NULL, 0),
-	CLK_PCOM("emdh_clk",	EMDH_CLK,	NULL, OFF | CLK_MINMAX),
-	CLK_PCOM("emdh_pclk",	EMDH_P_CLK,	NULL, OFF),
-	CLK_PCOM("gp_clk",	GP_CLK,		NULL, 0),
-	CLK_PCOM("grp_2d_clk",	GRP_2D_CLK,	NULL, 0),
-	CLK_PCOM("grp_2d_pclk",	GRP_2D_P_CLK,	NULL, 0),
-	CLK_PCOM("grp_clk",	GRP_3D_CLK,	NULL, 0),
-	CLK_PCOM("grp_pclk",	GRP_3D_P_CLK,	NULL, 0),
-	CLK_7X30S("grp_src_clk", GRP_3D_SRC_CLK, GRP_3D_CLK,	NULL, 0),
-	CLK_PCOM("hdmi_clk",	HDMI_CLK,	NULL, 0),
-	CLK_PCOM("imem_clk",	IMEM_CLK,	NULL, OFF),
-	CLK_PCOM("jpeg_clk",	JPEG_CLK,	NULL, OFF),
-	CLK_PCOM("jpeg_pclk",	JPEG_P_CLK,	NULL, OFF),
-	CLK_PCOM("lpa_codec_clk",	LPA_CODEC_CLK,		NULL, 0),
-	CLK_PCOM("lpa_core_clk",	LPA_CORE_CLK,		NULL, 0),
-	CLK_PCOM("lpa_pclk",		LPA_P_CLK,		NULL, 0),
-	CLK_PCOM("mdc_clk",	MDC_CLK,	NULL, 0),
-	CLK_PCOM("mddi_clk",	PMDH_CLK,	NULL, OFF | CLK_MINMAX),
-	CLK_PCOM("mddi_pclk",	PMDH_P_CLK,	NULL, 0),
-	CLK_PCOM("mdp_clk",	MDP_CLK,	NULL, OFF),
-	CLK_PCOM("mdp_pclk",	MDP_P_CLK,	NULL, 0),
-	CLK_PCOM("mdp_lcdc_pclk_clk", MDP_LCDC_PCLK_CLK, NULL, 0),
-	CLK_PCOM("mdp_lcdc_pad_pclk_clk", MDP_LCDC_PAD_PCLK_CLK, NULL, 0),
-	CLK_PCOM("mdp_vsync_clk",	MDP_VSYNC_CLK,  NULL, 0),
-	CLK_PCOM("mfc_clk",		MFC_CLK,		NULL, 0),
-	CLK_PCOM("mfc_div2_clk",	MFC_DIV2_CLK,		NULL, 0),
-	CLK_PCOM("mfc_pclk",		MFC_P_CLK,		NULL, 0),
-	CLK_PCOM("mi2s_m_clk",		MI2S_M_CLK,  		NULL, 0),
-	CLK_PCOM("mi2s_s_clk",		MI2S_S_CLK,  		NULL, 0),
-	CLK_PCOM("mi2s_codec_rx_m_clk",	MI2S_CODEC_RX_M_CLK,  NULL, 0),
-	CLK_PCOM("mi2s_codec_rx_s_clk",	MI2S_CODEC_RX_S_CLK,  NULL, 0),
-	CLK_PCOM("mi2s_codec_tx_m_clk",	MI2S_CODEC_TX_M_CLK,  NULL, 0),
-	CLK_PCOM("mi2s_codec_tx_s_clk",	MI2S_CODEC_TX_S_CLK,  NULL, 0),
-	CLK_PCOM("pbus_clk",	PBUS_CLK,	NULL, CLK_MIN),
-	CLK_PCOM("pcm_clk",	PCM_CLK,	NULL, 0),
-	CLK_PCOM("rotator_clk",	AXI_ROTATOR_CLK,		NULL, 0),
-	CLK_PCOM("rotator_imem_clk",	ROTATOR_IMEM_CLK,	NULL, OFF),
-	CLK_PCOM("rotator_pclk",	ROTATOR_P_CLK,		NULL, OFF),
-	CLK_PCOM("sdac_clk",	SDAC_CLK,	NULL, OFF),
-	CLK_PCOM("spi_clk",	SPI_CLK,	NULL, 0),
-	CLK_PCOM("spi_pclk",	SPI_P_CLK,	NULL, 0),
-	CLK_7X30S("tv_src_clk",	TV_CLK, 	TV_ENC_CLK,	NULL, 0),
-	CLK_PCOM("tv_dac_clk",	TV_DAC_CLK,	NULL, 0),
-	CLK_PCOM("tv_enc_clk",	TV_ENC_CLK,	NULL, 0),
-	CLK_PCOM("uart_clk",	UART2_CLK,	"msm_serial.1", 0),
-	CLK_PCOM("usb_phy_clk",	USB_PHY_CLK,	NULL, 0),
-	CLK_PCOM("usb_hs_clk",		USB_HS_CLK,		NULL, OFF),
-	CLK_PCOM("usb_hs_pclk",		USB_HS_P_CLK,		NULL, OFF),
-	CLK_PCOM("usb_hs_core_clk",	USB_HS_CORE_CLK,	NULL, OFF),
-	CLK_PCOM("usb_hs2_clk",		USB_HS2_CLK,		NULL, OFF),
-	CLK_PCOM("usb_hs2_pclk",	USB_HS2_P_CLK,		NULL, OFF),
-	CLK_PCOM("usb_hs2_core_clk",	USB_HS2_CORE_CLK,	NULL, OFF),
-	CLK_PCOM("usb_hs3_clk",		USB_HS3_CLK,		NULL, OFF),
-	CLK_PCOM("usb_hs3_pclk",	USB_HS3_P_CLK,		NULL, OFF),
-	CLK_PCOM("usb_hs3_core_clk",	USB_HS3_CORE_CLK,	NULL, OFF),
-	CLK_PCOM("vdc_clk",	VDC_CLK,	NULL, OFF | CLK_MIN),
-	CLK_PCOM("vfe_camif_clk",	VFE_CAMIF_CLK, 	NULL, 0),
-	CLK_PCOM("vfe_clk",	VFE_CLK,	NULL, 0),
-	CLK_PCOM("vfe_mdc_clk",	VFE_MDC_CLK,	NULL, 0),
-	CLK_PCOM("vfe_pclk",	VFE_P_CLK,	NULL, OFF),
-	CLK_PCOM("vpe_clk",	VPE_CLK,	NULL, 0),
-
-	/* 7x30 v2 hardware only. */
-	CLK_PCOM("csi_clk",	CSI0_CLK,	NULL, 0),
-	CLK_PCOM("csi_pclk",	CSI0_P_CLK,	NULL, 0),
-	CLK_PCOM("csi_vfe_clk",	CSI0_VFE_CLK,	NULL, 0),
+static struct platform_device *msm_host_devices[] = {
+	&msm_device_hsusb_host,
 };
 
-unsigned msm_num_clocks_7x30 = ARRAY_SIZE(msm_clocks_7x30);
+int msm_add_host(unsigned int host, struct msm_usb_host_platform_data *plat)
+{
+	struct platform_device	*pdev;
 
+	pdev = msm_host_devices[host];
+	if (!pdev)
+		return -ENODEV;
+	pdev->dev.platform_data = plat;
+	return platform_device_register(pdev);
+}
+
+struct platform_device asoc_msm_pcm = {
+	.name   = "msm-dsp-audio",
+	.id     = 0,
+};
+
+struct platform_device asoc_msm_dai0 = {
+	.name   = "msm-codec-dai",
+	.id     = 0,
+};
+
+struct platform_device asoc_msm_dai1 = {
+	.name   = "msm-cpu-dai",
+	.id     = 0,
+};
+
+#if defined (CONFIG_SND_MSM_MVS_DAI_SOC)
+struct platform_device asoc_msm_mvs = {
+	.name   = "msm-mvs-audio",
+	.id     = 0,
+};
+
+struct platform_device asoc_mvs_dai0 = {
+	.name   = "mvs-codec-dai",
+	.id     = 0,
+};
+
+struct platform_device asoc_mvs_dai1 = {
+	.name   = "mvs-cpu-dai",
+	.id     = 0,
+};
+#endif
+
+#define MSM_NAND_PHYS		0xA0200000
+#define MSM_NANDC01_PHYS	0xA0240000
+#define MSM_NANDC10_PHYS	0xA0280000
+#define MSM_NANDC11_PHYS	0xA02C0000
+#define EBI2_REG_BASE		0xA0000000
+static struct resource resources_nand[] = {
+	[0] = {
+		.name   = "msm_nand_dmac",
+		.start	= DMOV_NAND_CHAN,
+		.end	= DMOV_NAND_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	[1] = {
+		.name   = "msm_nand_phys",
+		.start  = MSM_NAND_PHYS,
+		.end    = MSM_NAND_PHYS + 0x7FF,
+		.flags  = IORESOURCE_MEM,
+	},
+	[2] = {
+		.name   = "msm_nandc01_phys",
+		.start  = MSM_NANDC01_PHYS,
+		.end    = MSM_NANDC01_PHYS + 0x7FF,
+		.flags  = IORESOURCE_MEM,
+	},
+	[3] = {
+		.name   = "msm_nandc10_phys",
+		.start  = MSM_NANDC10_PHYS,
+		.end    = MSM_NANDC10_PHYS + 0x7FF,
+		.flags  = IORESOURCE_MEM,
+	},
+	[4] = {
+		.name   = "msm_nandc11_phys",
+		.start  = MSM_NANDC11_PHYS,
+		.end    = MSM_NANDC11_PHYS + 0x7FF,
+		.flags  = IORESOURCE_MEM,
+	},
+	[5] = {
+		.name   = "ebi2_reg_base",
+		.start  = EBI2_REG_BASE,
+		.end    = EBI2_REG_BASE + 0x60,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+static struct resource resources_otg[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_USB_HS,
+		.end	= INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "vbus_on",
+		.start	= PMIC8058_IRQ_BASE + PM8058_CHGVAL_IRQ,
+		.end	= PMIC8058_IRQ_BASE + PM8058_CHGVAL_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_otg = {
+	.name		= "msm_otg",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_otg),
+	.resource	= resources_otg,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+struct flash_platform_data msm_nand_data = {
+	.parts		= NULL,
+	.nr_parts	= 0,
+	.interleave     = 0,
+};
+
+struct platform_device msm_device_nand = {
+	.name		= "msm_nand",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_nand),
+	.resource	= resources_nand,
+	.dev		= {
+		.platform_data	= &msm_nand_data,
+	},
+};
+
+static struct msm_pm_irq_calls msm7x30_pm_irq_calls = {
+	.irq_pending = msm_irq_pending,
+	.idle_sleep_allowed = msm_irq_idle_sleep_allowed,
+	.enter_sleep1 = msm_irq_enter_sleep1,
+	.enter_sleep2 = msm_irq_enter_sleep2,
+	.exit_sleep1 = msm_irq_exit_sleep1,
+	.exit_sleep2 = msm_irq_exit_sleep2,
+	.exit_sleep3 = msm_irq_exit_sleep3,
+};
+
+void __init msm_pm_register_irqs(void)
+{
+	msm_pm_set_irq_extns(&msm7x30_pm_irq_calls);
+}
+
+static struct resource smd_resource[] = {
+	{
+		.name   = "a9_m2a_0",
+		.start  = INT_A9_M2A_0,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "a9_m2a_5",
+		.start  = INT_A9_M2A_5,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "adsp_a11_smsm",
+		.start  = INT_ADSP_A11,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct smd_subsystem_config smd_config_list[] = {
+	{
+		.irq_config_id = SMD_MODEM,
+		.subsys_name = "modem",
+		.edge = SMD_APPS_MODEM,
+
+		.smd_int.irq_name = "a9_m2a_0",
+		.smd_int.flags = IRQF_TRIGGER_RISING,
+		.smd_int.irq_id = -1,
+		.smd_int.device_name = "smd_dev",
+		.smd_int.dev_id = 0,
+
+		.smd_int.out_bit_pos =  1 << 0,
+		.smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smd_int.out_offset = 0x8,
+
+		.smsm_int.irq_name = "a9_m2a_5",
+		.smsm_int.flags = IRQF_TRIGGER_RISING,
+		.smsm_int.irq_id = -1,
+		.smsm_int.device_name = "smd_dev",
+		.smsm_int.dev_id = 0,
+
+		.smsm_int.out_bit_pos =  1 << 5,
+		.smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smsm_int.out_offset = 0x8,
+
+	}
+};
+
+static struct smd_platform smd_platform_data = {
+	.num_ss_configs = ARRAY_SIZE(smd_config_list),
+	.smd_ss_configs = smd_config_list,
+};
+
+struct platform_device msm_device_smd = {
+	.name	= "msm_smd",
+	.id	= -1,
+	.resource = smd_resource,
+	.num_resources = ARRAY_SIZE(smd_resource),
+	.dev = {
+		.platform_data = &smd_platform_data,
+	}
+
+};
+
+static struct resource msm_dmov_resource[] = {
+	{
+		.start = INT_ADM_AARM,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = 0xAC400000,
+		.end = 0xAC400000 + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct msm_dmov_pdata msm_dmov_pdata = {
+	.sd = 2,
+	.sd_size = 0x400,
+};
+
+struct platform_device msm_device_dmov = {
+	.name	= "msm_dmov",
+	.id	= -1,
+	.resource = msm_dmov_resource,
+	.num_resources = ARRAY_SIZE(msm_dmov_resource),
+	.dev = {
+		.platform_data = &msm_dmov_pdata,
+	},
+};
+
+#define MSM_SDC1_BASE         0xA0400000
+#define MSM_SDC2_BASE         0xA0500000
+#define MSM_SDC3_BASE         0xA3000000
+#define MSM_SDC4_BASE         0xA3100000
+static struct resource resources_sdc1[] = {
+	{
+		.start	= MSM_SDC1_BASE,
+		.end	= MSM_SDC1_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SDC1_0,
+		.end	= INT_SDC1_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC1_CHAN,
+		.end	= DMOV_SDC1_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC1_CRCI,
+		.end	= DMOV_SDC1_CRCI,
+		.flags	= IORESOURCE_DMA,
+	}
+};
+
+static struct resource resources_sdc2[] = {
+	{
+		.start	= MSM_SDC2_BASE,
+		.end	= MSM_SDC2_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SDC2_0,
+		.end	= INT_SDC2_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC2_CHAN,
+		.end	= DMOV_SDC2_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC2_CRCI,
+		.end	= DMOV_SDC2_CRCI,
+		.flags	= IORESOURCE_DMA,
+	}
+};
+
+static struct resource resources_sdc3[] = {
+	{
+		.start	= MSM_SDC3_BASE,
+		.end	= MSM_SDC3_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SDC3_0,
+		.end	= INT_SDC3_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC3_CHAN,
+		.end	= DMOV_SDC3_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC3_CRCI,
+		.end	= DMOV_SDC3_CRCI,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+static struct resource resources_sdc4[] = {
+	{
+		.start	= MSM_SDC4_BASE,
+		.end	= MSM_SDC4_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_SDC4_0,
+		.end	= INT_SDC4_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC4_CHAN,
+		.end	= DMOV_SDC4_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC4_CRCI,
+		.end	= DMOV_SDC4_CRCI,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+struct platform_device msm_device_sdc1 = {
+	.name		= "msm_sdcc",
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(resources_sdc1),
+	.resource	= resources_sdc1,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_sdc2 = {
+	.name		= "msm_sdcc",
+	.id		= 2,
+	.num_resources	= ARRAY_SIZE(resources_sdc2),
+	.resource	= resources_sdc2,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_sdc3 = {
+	.name		= "msm_sdcc",
+	.id		= 3,
+	.num_resources	= ARRAY_SIZE(resources_sdc3),
+	.resource	= resources_sdc3,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_sdc4 = {
+	.name		= "msm_sdcc",
+	.id		= 4,
+	.num_resources	= ARRAY_SIZE(resources_sdc4),
+	.resource	= resources_sdc4,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+static struct platform_device *msm_sdcc_devices[] __initdata = {
+	&msm_device_sdc1,
+	&msm_device_sdc2,
+	&msm_device_sdc3,
+	&msm_device_sdc4,
+};
+
+int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat)
+{
+	struct platform_device	*pdev;
+
+	if (controller < 1 || controller > 4)
+		return -EINVAL;
+
+	pdev = msm_sdcc_devices[controller-1];
+	pdev->dev.platform_data = plat;
+	return platform_device_register(pdev);
+}
+
+static struct resource msm_vidc_720p_resources[] = {
+	{
+		.start	= 0xA3B00000,
+		.end	= 0xA3B00000 + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_MFC720,
+		.end	= INT_MFC720,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct msm_vidc_platform_data vidc_platform_data = {
+	.memtype = MEMTYPE_EBI0,
+	.enable_ion = 0,
+	.disable_dmx = 0,
+	.cont_mode_dpb_count = 8
+};
+
+struct platform_device msm_device_vidc_720p = {
+	.name = "msm_vidc",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(msm_vidc_720p_resources),
+	.resource = msm_vidc_720p_resources,
+	.dev = {
+		.platform_data	= &vidc_platform_data,
+	},
+};
+
+#if defined(CONFIG_FB_MSM_MDP40)
+#define MDP_BASE          0xA3F00000
+#define PMDH_BASE         0xAD600000
+#define EMDH_BASE         0xAD700000
+#define TVENC_BASE        0xAD400000
+#else
+#define MDP_BASE          0xAA200000
+#define PMDH_BASE         0xAA600000
+#define EMDH_BASE         0xAA700000
+#define TVENC_BASE        0xAA400000
+#endif
+
+static struct resource msm_mdp_resources[] = {
+	{
+		.name   = "mdp",
+		.start  = MDP_BASE,
+		.end    = MDP_BASE + 0x000F0000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = INT_MDP,
+		.end    = INT_MDP,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct resource msm_mddi_resources[] = {
+	{
+		.name   = "pmdh",
+		.start  = PMDH_BASE,
+		.end    = PMDH_BASE + PAGE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	}
+};
+
+static struct resource msm_mddi_ext_resources[] = {
+	{
+		.name   = "emdh",
+		.start  = EMDH_BASE,
+		.end    = EMDH_BASE + PAGE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	}
+};
+
+static struct resource msm_ebi2_lcd_resources[] = {
+	{
+		.name   = "base",
+		.start  = 0xa0d00000,
+		.end    = 0xa0d00000 + PAGE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "lcd01",
+		.start  = 0x98000000,
+		.end    = 0x98000000 + 0x80000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "lcd02",
+		.start  = 0x9c000000,
+		.end    = 0x9c000000 + 0x80000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+static struct resource msm_tvenc_resources[] = {
+	{
+		.name   = "tvenc",
+		.start  = TVENC_BASE,
+		.end    = TVENC_BASE + PAGE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	}
+};
+
+#ifdef CONFIG_FB_MSM_TVOUT
+static struct resource tvout_device_resources[] = {
+	{
+		.name  = "tvout_device_irq",
+		.start = INT_TV_ENC,
+		.end   = INT_TV_ENC,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+#endif
+
+static struct platform_device msm_mdp_device = {
+	.name   = "mdp",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_mdp_resources),
+	.resource       = msm_mdp_resources,
+};
+
+static struct platform_device msm_mddi_device = {
+	.name   = "mddi",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_mddi_resources),
+	.resource       = msm_mddi_resources,
+};
+
+static struct platform_device msm_mddi_ext_device = {
+	.name   = "mddi_ext",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_mddi_ext_resources),
+	.resource       = msm_mddi_ext_resources,
+};
+
+static struct platform_device msm_ebi2_lcd_device = {
+	.name   = "ebi2_lcd",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_ebi2_lcd_resources),
+	.resource       = msm_ebi2_lcd_resources,
+};
+
+static struct platform_device msm_lcdc_device = {
+	.name   = "lcdc",
+	.id     = 0,
+};
+
+static struct platform_device msm_dtv_device = {
+	.name   = "dtv",
+	.id     = 0,
+};
+
+static struct platform_device msm_tvenc_device = {
+	.name   = "tvenc",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_tvenc_resources),
+	.resource       = msm_tvenc_resources,
+};
+
+#ifdef CONFIG_FB_MSM_TVOUT
+static struct platform_device tvout_msm_device = {
+	.name = "tvout_device",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(tvout_device_resources),
+	.resource = tvout_device_resources,
+};
+#endif
+
+/* TSIF begin */
+#if defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE)
+
+#define MSM_TSIF_PHYS        (0xa3400000)
+#define MSM_TSIF_SIZE        (0x200)
+
+static struct resource tsif_resources[] = {
+	[0] = {
+		.flags = IORESOURCE_IRQ,
+		.start = INT_TSIF,
+		.end   = INT_TSIF,
+	},
+	[1] = {
+		.flags = IORESOURCE_MEM,
+		.start = MSM_TSIF_PHYS,
+		.end   = MSM_TSIF_PHYS + MSM_TSIF_SIZE - 1,
+	},
+	[2] = {
+		.flags = IORESOURCE_DMA,
+		.start = DMOV_TSIF_CHAN,
+		.end   = DMOV_TSIF_CRCI,
+	},
+};
+
+static void tsif_release(struct device *dev)
+{
+	dev_info(dev, "release\n");
+}
+
+struct platform_device msm_device_tsif = {
+	.name          = "msm_tsif",
+	.id            = 0,
+	.num_resources = ARRAY_SIZE(tsif_resources),
+	.resource      = tsif_resources,
+	.dev = {
+		.release       = tsif_release,
+	},
+};
+#endif /* defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE) */
+/* TSIF end   */
+
+
+
+#ifdef CONFIG_MSM_ROTATOR
+static struct resource resources_msm_rotator[] = {
+	{
+		.start	= 0xA3E00000,
+		.end	= 0xA3F00000 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_ROTATOR,
+		.end	= INT_ROTATOR,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct msm_rot_clocks rotator_clocks[] = {
+	{
+		.clk_name = "core_clk",
+		.clk_type = ROTATOR_CORE_CLK,
+		.clk_rate = 0,
+	},
+	{
+		.clk_name = "iface_clk",
+		.clk_type = ROTATOR_PCLK,
+		.clk_rate = 0,
+	},
+	{
+		.clk_name = "mem_clk",
+		.clk_type = ROTATOR_IMEM_CLK,
+		.clk_rate = 0,
+	},
+};
+
+static struct msm_rotator_platform_data rotator_pdata = {
+	.number_of_clocks = ARRAY_SIZE(rotator_clocks),
+	.hardware_version_number = 0x1000303,
+	.rotator_clks = rotator_clocks,
+};
+
+struct platform_device msm_rotator_device = {
+	.name		= "msm_rotator",
+	.id		= 0,
+	.num_resources  = ARRAY_SIZE(resources_msm_rotator),
+	.resource       = resources_msm_rotator,
+	.dev = {
+		.platform_data = &rotator_pdata,
+	},
+};
+#endif
+
+static void __init msm_register_device(struct platform_device *pdev, void *data)
+{
+	int ret;
+
+	pdev->dev.platform_data = data;
+
+	ret = platform_device_register(pdev);
+	if (ret)
+		dev_err(&pdev->dev,
+			  "%s: platform_device_register() failed = %d\n",
+			  __func__, ret);
+}
+
+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, "pmdh", 4))
+		msm_register_device(&msm_mddi_device, data);
+	else if (!strncmp(name, "emdh", 4))
+		msm_register_device(&msm_mddi_ext_device, data);
+	else if (!strncmp(name, "ebi2", 4))
+		msm_register_device(&msm_ebi2_lcd_device, data);
+	else if (!strncmp(name, "tvenc", 5))
+		msm_register_device(&msm_tvenc_device, data);
+	else if (!strncmp(name, "lcdc", 4))
+		msm_register_device(&msm_lcdc_device, data);
+	else if (!strncmp(name, "dtv", 3))
+		msm_register_device(&msm_dtv_device, data);
+#ifdef CONFIG_FB_MSM_TVOUT
+	else if (!strncmp(name, "tvout_device", 12))
+		msm_register_device(&tvout_msm_device, data);
+#endif
+	else
+		printk(KERN_ERR "%s: unknown device! %s\n", __func__, name);
+}
+
+static struct platform_device msm_camera_device = {
+	.name	= "msm_camera",
+	.id	= 0,
+};
+
+void __init msm_camera_register_device(void *res, uint32_t num,
+	void *data)
+{
+	msm_camera_device.num_resources = num;
+	msm_camera_device.resource = res;
+
+	msm_register_device(&msm_camera_device, data);
+}
+
+struct resource kgsl_3d0_resources[] = {
+	{
+		.name  = KGSL_3D0_REG_MEMORY,
+		.start = 0xA3500000, /* 3D GRP address */
+		.end = 0xA351ffff,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = KGSL_3D0_IRQ,
+		.start = INT_GRP_3D,
+		.end = INT_GRP_3D,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct kgsl_device_platform_data kgsl_3d0_pdata = {
+	.pwrlevel = {
+		{
+			.gpu_freq = 245760000,
+			.bus_freq = 192000000,
+		},
+		{
+			.gpu_freq = 192000000,
+			.bus_freq = 152000000,
+		},
+		{
+			.gpu_freq = 192000000,
+			.bus_freq = 0,
+		},
+	},
+	.init_level = 0,
+	.num_levels = 3,
+	.set_grp_async = set_grp3d_async,
+	.idle_timeout = HZ/20,
+	.nap_allowed = true,
+	.idle_needed = true,
+	.clk_map = KGSL_CLK_SRC | KGSL_CLK_CORE |
+		KGSL_CLK_IFACE | KGSL_CLK_MEM,
+};
+
+struct platform_device msm_kgsl_3d0 = {
+	.name = "kgsl-3d0",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(kgsl_3d0_resources),
+	.resource = kgsl_3d0_resources,
+	.dev = {
+		.platform_data = &kgsl_3d0_pdata,
+	},
+};
+
+static struct resource kgsl_2d0_resources[] = {
+	{
+		.name = KGSL_2D0_REG_MEMORY,
+		.start = 0xA3900000, /* Z180 base address */
+		.end = 0xA3900FFF,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = KGSL_2D0_IRQ,
+		.start = INT_GRP_2D,
+		.end = INT_GRP_2D,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct kgsl_device_platform_data kgsl_2d0_pdata = {
+	.pwrlevel = {
+		{
+			.gpu_freq = 0,
+			.bus_freq = 192000000,
+		},
+	},
+	.init_level = 0,
+	.num_levels = 1,
+	/* HW workaround, run Z180 SYNC @ 192 MHZ */
+	.set_grp_async = NULL,
+	.idle_timeout = HZ/10,
+	.nap_allowed = true,
+	.idle_needed = true,
+	.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE,
+};
+
+struct platform_device msm_kgsl_2d0 = {
+	.name = "kgsl-2d0",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(kgsl_2d0_resources),
+	.resource = kgsl_2d0_resources,
+	.dev = {
+		.platform_data = &kgsl_2d0_pdata,
+	},
+};
+
+struct platform_device *msm_footswitch_devices[] = {
+	FS_PCOM(FS_GFX2D0, "vdd", "kgsl-2d0.0"),
+	FS_PCOM(FS_GFX3D,  "vdd", "kgsl-3d0.0"),
+	FS_PCOM(FS_MDP,    "vdd", "mdp.0"),
+	FS_PCOM(FS_MFC,    "fs_mfc",    NULL),
+	FS_PCOM(FS_ROT,    "vdd",  "msm_rotator.0"),
+	FS_PCOM(FS_VFE,    "fs_vfe",    NULL),
+	FS_PCOM(FS_VPE,    "fs_vpe",    NULL),
+};
+unsigned msm_num_footswitch_devices = ARRAY_SIZE(msm_footswitch_devices);
+
+static struct resource gpio_resources[] = {
+	{
+		.start	= INT_GPIO_GROUP1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= INT_GPIO_GROUP2,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device msm_device_gpio = {
+	.name		= "msmgpio",
+	.id		= -1,
+	.resource	= gpio_resources,
+	.num_resources	= ARRAY_SIZE(gpio_resources),
+};
+
+static int __init msm7630_init_gpio(void)
+{
+	platform_device_register(&msm_device_gpio);
+	return 0;
+}
+
+postcore_initcall(msm7630_init_gpio);
diff --git a/arch/arm/mach-msm/devices-msm8960.c b/arch/arm/mach-msm/devices-msm8960.c
deleted file mode 100644
index d9e1f26..0000000
--- a/arch/arm/mach-msm/devices-msm8960.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-
-#include <linux/dma-mapping.h>
-#include <mach/irqs-8960.h>
-#include <mach/board.h>
-
-#include "devices.h"
-
-#define MSM_GSBI2_PHYS		0x16100000
-#define MSM_UART2DM_PHYS	(MSM_GSBI2_PHYS + 0x40000)
-
-#define MSM_GSBI5_PHYS		0x16400000
-#define MSM_UART5DM_PHYS	(MSM_GSBI5_PHYS + 0x40000)
-
-static struct resource resources_uart_gsbi2[] = {
-	{
-		.start	= GSBI2_UARTDM_IRQ,
-		.end	= GSBI2_UARTDM_IRQ,
-		.flags	= IORESOURCE_IRQ,
-	},
-	{
-		.start	= MSM_UART2DM_PHYS,
-		.end	= MSM_UART2DM_PHYS + PAGE_SIZE - 1,
-		.name	= "uart_resource",
-		.flags	= IORESOURCE_MEM,
-	},
-	{
-		.start	= MSM_GSBI2_PHYS,
-		.end	= MSM_GSBI2_PHYS + PAGE_SIZE - 1,
-		.name	= "gsbi_resource",
-		.flags	= IORESOURCE_MEM,
-	},
-};
-
-struct platform_device msm8960_device_uart_gsbi2 = {
-	.name	= "msm_serial",
-	.id	= 0,
-	.num_resources	= ARRAY_SIZE(resources_uart_gsbi2),
-	.resource	= resources_uart_gsbi2,
-};
-
-static struct resource resources_uart_gsbi5[] = {
-	{
-		.start	= GSBI5_UARTDM_IRQ,
-		.end	= GSBI5_UARTDM_IRQ,
-		.flags	= IORESOURCE_IRQ,
-	},
-	{
-		.start	= MSM_UART5DM_PHYS,
-		.end	= MSM_UART5DM_PHYS + PAGE_SIZE - 1,
-		.name	= "uart_resource",
-		.flags	= IORESOURCE_MEM,
-	},
-	{
-		.start	= MSM_GSBI5_PHYS,
-		.end	= MSM_GSBI5_PHYS + PAGE_SIZE - 1,
-		.name	= "gsbi_resource",
-		.flags	= IORESOURCE_MEM,
-	},
-};
-
-struct platform_device msm8960_device_uart_gsbi5 = {
-	.name	= "msm_serial",
-	.id	= 0,
-	.num_resources	= ARRAY_SIZE(resources_uart_gsbi5),
-	.resource	= resources_uart_gsbi5,
-};
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
new file mode 100644
index 0000000..d622af2
--- /dev/null
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -0,0 +1,2934 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/consumer.h>
+#include <linux/ion.h>
+#include <mach/irqs.h>
+#include <mach/dma.h>
+#include <asm/mach/mmc.h>
+#include <asm/clkdev.h>
+#include <linux/msm_kgsl.h>
+#include <linux/msm_rotator.h>
+#include <mach/msm_hsusb.h>
+#include "footswitch.h"
+#include "clock.h"
+#include "clock-rpm.h"
+#include "clock-voter.h"
+#include "devices.h"
+#include "devices-msm8x60.h"
+#include <linux/dma-mapping.h>
+#include <linux/irq.h>
+#include <linux/clk.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach-types.h>
+#include <asm/clkdev.h>
+#include <mach/msm_serial_hs_lite.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#include <mach/socinfo.h>
+#include <mach/msm_memtypes.h>
+#include <mach/msm_tsif.h>
+#include <mach/scm-io.h>
+#ifdef CONFIG_MSM_DSPS
+#include <mach/msm_dsps.h>
+#endif
+#include <linux/android_pmem.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <mach/mdm.h>
+#include <mach/rpm.h>
+#include <mach/board.h>
+#include <sound/apr_audio.h>
+#include "rpm_log.h"
+#include "rpm_stats.h"
+#include <mach/mpm.h>
+#include "msm_watchdog.h"
+
+/* Address of GSBI blocks */
+#define MSM_GSBI1_PHYS	0x16000000
+#define MSM_GSBI2_PHYS	0x16100000
+#define MSM_GSBI3_PHYS	0x16200000
+#define MSM_GSBI4_PHYS	0x16300000
+#define MSM_GSBI5_PHYS	0x16400000
+#define MSM_GSBI6_PHYS	0x16500000
+#define MSM_GSBI7_PHYS	0x16600000
+#define MSM_GSBI8_PHYS	0x19800000
+#define MSM_GSBI9_PHYS	0x19900000
+#define MSM_GSBI10_PHYS	0x19A00000
+#define MSM_GSBI11_PHYS	0x19B00000
+#define MSM_GSBI12_PHYS	0x19C00000
+
+/* GSBI QUPe devices */
+#define MSM_GSBI1_QUP_PHYS	0x16080000
+#define MSM_GSBI2_QUP_PHYS	0x16180000
+#define MSM_GSBI3_QUP_PHYS	0x16280000
+#define MSM_GSBI4_QUP_PHYS	0x16380000
+#define MSM_GSBI5_QUP_PHYS	0x16480000
+#define MSM_GSBI6_QUP_PHYS	0x16580000
+#define MSM_GSBI7_QUP_PHYS	0x16680000
+#define MSM_GSBI8_QUP_PHYS	0x19880000
+#define MSM_GSBI9_QUP_PHYS	0x19980000
+#define MSM_GSBI10_QUP_PHYS	0x19A80000
+#define MSM_GSBI11_QUP_PHYS	0x19B80000
+#define MSM_GSBI12_QUP_PHYS	0x19C80000
+
+/* GSBI UART devices */
+#define MSM_UART1DM_PHYS    (MSM_GSBI6_PHYS + 0x40000)
+#define INT_UART1DM_IRQ     GSBI6_UARTDM_IRQ
+#define INT_UART2DM_IRQ     GSBI12_UARTDM_IRQ
+#define MSM_UART2DM_PHYS    0x19C40000
+#define MSM_UART3DM_PHYS    (MSM_GSBI3_PHYS + 0x40000)
+#define INT_UART3DM_IRQ     GSBI3_UARTDM_IRQ
+#define TCSR_BASE_PHYS      0x16b00000
+
+/* PRNG device */
+#define MSM_PRNG_PHYS		0x16C00000
+#define MSM_UART9DM_PHYS    (MSM_GSBI9_PHYS + 0x40000)
+#define INT_UART9DM_IRQ     GSBI9_UARTDM_IRQ
+
+static void charm_ap2mdm_kpdpwr_on(void)
+{
+	gpio_direction_output(AP2MDM_PMIC_RESET_N, 0);
+	gpio_direction_output(AP2MDM_KPDPWR_N, 1);
+}
+
+static void charm_ap2mdm_kpdpwr_off(void)
+{
+	int i;
+
+	gpio_direction_output(AP2MDM_ERRFATAL, 1);
+
+	for (i = 20; i > 0; i--) {
+		if (gpio_get_value(MDM2AP_STATUS) == 0)
+			break;
+		msleep(100);
+	}
+	gpio_direction_output(AP2MDM_ERRFATAL, 0);
+
+	if (i == 0) {
+		pr_err("%s: MDM2AP_STATUS never went low. Doing a hard reset \
+			of the charm modem.\n", __func__);
+		gpio_direction_output(AP2MDM_PMIC_RESET_N, 1);
+		/*
+		* Currently, there is a debounce timer on the charm PMIC. It is
+		* necessary to hold the AP2MDM_PMIC_RESET low for ~3.5 seconds
+		* for the reset to fully take place. Sleep here to ensure the
+		* reset has occured before the function exits.
+		*/
+		msleep(4000);
+		gpio_direction_output(AP2MDM_PMIC_RESET_N, 0);
+	}
+}
+
+static struct resource charm_resources[] = {
+	/* MDM2AP_ERRFATAL */
+	{
+		.start	= MSM_GPIO_TO_INT(MDM2AP_ERRFATAL),
+		.end	= MSM_GPIO_TO_INT(MDM2AP_ERRFATAL),
+		.flags = IORESOURCE_IRQ,
+	},
+	/* MDM2AP_STATUS */
+	{
+		.start	= MSM_GPIO_TO_INT(MDM2AP_STATUS),
+		.end	= MSM_GPIO_TO_INT(MDM2AP_STATUS),
+		.flags = IORESOURCE_IRQ,
+	}
+};
+
+static struct charm_platform_data mdm_platform_data = {
+	.charm_modem_on		= charm_ap2mdm_kpdpwr_on,
+	.charm_modem_off	= charm_ap2mdm_kpdpwr_off,
+};
+
+struct platform_device msm_charm_modem = {
+	.name		= "charm_modem",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(charm_resources),
+	.resource	= charm_resources,
+	.dev		= {
+		.platform_data = &mdm_platform_data,
+	},
+};
+
+#ifdef CONFIG_MSM_DSPS
+#define GSBI12_DEV (&msm_dsps_device.dev)
+#else
+#define GSBI12_DEV (&msm_gsbi12_qup_i2c_device.dev)
+#endif
+
+void __init msm8x60_init_irq(void)
+{
+	struct msm_mpm_device_data *data = NULL;
+
+#ifdef CONFIG_MSM_MPM
+	data = &msm8660_mpm_dev_data;
+#endif
+
+	msm_mpm_irq_extn_init(data);
+	gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE, (void *)MSM_QGIC_CPU_BASE);
+}
+
+#define MSM_LPASS_QDSP6SS_PHYS 0x28800000
+
+static struct resource msm_8660_q6_resources[] = {
+	{
+		.start  = MSM_LPASS_QDSP6SS_PHYS,
+		.end    = MSM_LPASS_QDSP6SS_PHYS + SZ_256 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_pil_q6v3 = {
+	.name = "pil_qdsp6v3",
+	.id = -1,
+	.num_resources  = ARRAY_SIZE(msm_8660_q6_resources),
+	.resource       = msm_8660_q6_resources,
+};
+
+#define MSM_MSS_REGS_PHYS 0x10200000
+
+static struct resource msm_8660_modem_resources[] = {
+	{
+		.start  = MSM_MSS_REGS_PHYS,
+		.end    = MSM_MSS_REGS_PHYS + SZ_256 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_pil_modem = {
+	.name = "pil_modem",
+	.id = -1,
+	.num_resources  = ARRAY_SIZE(msm_8660_modem_resources),
+	.resource       = msm_8660_modem_resources,
+};
+
+struct platform_device msm_pil_tzapps = {
+	.name = "pil_tzapps",
+	.id = -1,
+};
+
+struct platform_device msm_pil_dsps = {
+	.name          = "pil_dsps",
+	.id            = -1,
+	.dev.platform_data = "dsps",
+};
+
+static struct resource msm_uart1_dm_resources[] = {
+	{
+		.start = MSM_UART1DM_PHYS,
+		.end   = MSM_UART1DM_PHYS + PAGE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = INT_UART1DM_IRQ,
+		.end   = INT_UART1DM_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		/* GSBI6 is UARTDM1 */
+		.start = MSM_GSBI6_PHYS,
+		.end   = MSM_GSBI6_PHYS + 4 - 1,
+		.name  = "gsbi_resource",
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = DMOV_HSUART1_TX_CHAN,
+		.end   = DMOV_HSUART1_RX_CHAN,
+		.name  = "uartdm_channels",
+		.flags = IORESOURCE_DMA,
+	},
+	{
+		.start = DMOV_HSUART1_TX_CRCI,
+		.end   = DMOV_HSUART1_RX_CRCI,
+		.name  = "uartdm_crci",
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static u64 msm_uart_dm1_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device msm_device_uart_dm1 = {
+	.name = "msm_serial_hs",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(msm_uart1_dm_resources),
+	.resource = msm_uart1_dm_resources,
+	.dev            = {
+		.dma_mask = &msm_uart_dm1_dma_mask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
+
+static struct resource msm_uart3_dm_resources[] = {
+	{
+		.start = MSM_UART3DM_PHYS,
+		.end   = MSM_UART3DM_PHYS + PAGE_SIZE - 1,
+		.name  = "uartdm_resource",
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = INT_UART3DM_IRQ,
+		.end   = INT_UART3DM_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = MSM_GSBI3_PHYS,
+		.end   = MSM_GSBI3_PHYS + PAGE_SIZE - 1,
+		.name  = "gsbi_resource",
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_device_uart_dm3 = {
+	.name = "msm_serial_hsl",
+	.id = 2,
+	.num_resources = ARRAY_SIZE(msm_uart3_dm_resources),
+	.resource = msm_uart3_dm_resources,
+};
+
+static struct resource msm_uart12_dm_resources[] = {
+	{
+		.start = MSM_UART2DM_PHYS,
+		.end   = MSM_UART2DM_PHYS + PAGE_SIZE - 1,
+		.name  = "uartdm_resource",
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = INT_UART2DM_IRQ,
+		.end   = INT_UART2DM_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		/* GSBI 12 is UARTDM2 */
+		.start = MSM_GSBI12_PHYS,
+		.end   = MSM_GSBI12_PHYS + PAGE_SIZE - 1,
+		.name  = "gsbi_resource",
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_device_uart_dm12 = {
+	.name = "msm_serial_hsl",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(msm_uart12_dm_resources),
+	.resource = msm_uart12_dm_resources,
+};
+
+#ifdef CONFIG_MSM_GSBI9_UART
+static struct msm_serial_hslite_platform_data uart_gsbi9_pdata = {
+	.config_gpio	= 1,
+	.uart_tx_gpio	= 67,
+	.uart_rx_gpio	= 66,
+	.line		= 1,
+};
+
+static struct resource msm_uart_gsbi9_resources[] = {
+       {
+		.start	= MSM_UART9DM_PHYS,
+		.end	= MSM_UART9DM_PHYS + PAGE_SIZE - 1,
+		.name	= "uartdm_resource",
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_UART9DM_IRQ,
+		.end	= INT_UART9DM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		/* GSBI 9 is UART_GSBI9 */
+		.start	= MSM_GSBI9_PHYS,
+		.end	= MSM_GSBI9_PHYS + PAGE_SIZE - 1,
+		.name	= "gsbi_resource",
+		.flags	= IORESOURCE_MEM,
+	},
+};
+struct platform_device *msm_device_uart_gsbi9;
+struct platform_device *msm_add_gsbi9_uart(void)
+{
+	return platform_device_register_resndata(NULL, "msm_serial_hsl",
+					1, msm_uart_gsbi9_resources,
+					ARRAY_SIZE(msm_uart_gsbi9_resources),
+					&uart_gsbi9_pdata,
+					sizeof(uart_gsbi9_pdata));
+}
+#endif
+
+static struct resource gsbi3_qup_i2c_resources[] = {
+	{
+		.name	= "qup_phys_addr",
+		.start	= MSM_GSBI3_QUP_PHYS,
+		.end	= MSM_GSBI3_QUP_PHYS + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "gsbi_qup_i2c_addr",
+		.start	= MSM_GSBI3_PHYS,
+		.end	= MSM_GSBI3_PHYS + 4 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_err_intr",
+		.start	= GSBI3_QUP_IRQ,
+		.end	= GSBI3_QUP_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "i2c_clk",
+		.start	= 44,
+		.end	= 44,
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.name	= "i2c_sda",
+		.start	= 43,
+		.end	= 43,
+		.flags	= IORESOURCE_IO,
+	},
+};
+
+static struct resource gsbi4_qup_i2c_resources[] = {
+	{
+		.name	= "qup_phys_addr",
+		.start	= MSM_GSBI4_QUP_PHYS,
+		.end	= MSM_GSBI4_QUP_PHYS + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "gsbi_qup_i2c_addr",
+		.start	= MSM_GSBI4_PHYS,
+		.end	= MSM_GSBI4_PHYS + 4 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_err_intr",
+		.start	= GSBI4_QUP_IRQ,
+		.end	= GSBI4_QUP_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct resource gsbi7_qup_i2c_resources[] = {
+	{
+		.name	= "qup_phys_addr",
+		.start	= MSM_GSBI7_QUP_PHYS,
+		.end	= MSM_GSBI7_QUP_PHYS + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "gsbi_qup_i2c_addr",
+		.start	= MSM_GSBI7_PHYS,
+		.end	= MSM_GSBI7_PHYS + 4 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_err_intr",
+		.start	= GSBI7_QUP_IRQ,
+		.end	= GSBI7_QUP_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "i2c_clk",
+		.start	= 60,
+		.end	= 60,
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.name	= "i2c_sda",
+		.start	= 59,
+		.end	= 59,
+		.flags	= IORESOURCE_IO,
+	},
+};
+
+static struct resource gsbi8_qup_i2c_resources[] = {
+	{
+		.name	= "qup_phys_addr",
+		.start	= MSM_GSBI8_QUP_PHYS,
+		.end	= MSM_GSBI8_QUP_PHYS + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "gsbi_qup_i2c_addr",
+		.start	= MSM_GSBI8_PHYS,
+		.end	= MSM_GSBI8_PHYS + 4 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_err_intr",
+		.start	= GSBI8_QUP_IRQ,
+		.end	= GSBI8_QUP_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct resource gsbi9_qup_i2c_resources[] = {
+	{
+		.name	= "qup_phys_addr",
+		.start	= MSM_GSBI9_QUP_PHYS,
+		.end	= MSM_GSBI9_QUP_PHYS + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "gsbi_qup_i2c_addr",
+		.start	= MSM_GSBI9_PHYS,
+		.end	= MSM_GSBI9_PHYS + 4 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_err_intr",
+		.start	= GSBI9_QUP_IRQ,
+		.end	= GSBI9_QUP_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct resource gsbi12_qup_i2c_resources[] = {
+	{
+		.name	= "qup_phys_addr",
+		.start	= MSM_GSBI12_QUP_PHYS,
+		.end	= MSM_GSBI12_QUP_PHYS + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "gsbi_qup_i2c_addr",
+		.start	= MSM_GSBI12_PHYS,
+		.end	= MSM_GSBI12_PHYS + 4 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "qup_err_intr",
+		.start	= GSBI12_QUP_IRQ,
+		.end	= GSBI12_QUP_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+#ifdef CONFIG_MSM_BUS_SCALING
+static struct msm_bus_vectors grp3d_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+static struct msm_bus_vectors grp3d_low_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(990),
+	},
+};
+
+static struct msm_bus_vectors grp3d_nominal_low_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(1300),
+	},
+};
+
+static struct msm_bus_vectors grp3d_nominal_high_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(2008),
+	},
+};
+
+static struct msm_bus_vectors grp3d_max_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_3D,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(2484),
+	},
+};
+
+static struct msm_bus_paths grp3d_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(grp3d_init_vectors),
+		grp3d_init_vectors,
+	},
+	{
+		ARRAY_SIZE(grp3d_low_vectors),
+		grp3d_low_vectors,
+	},
+	{
+		ARRAY_SIZE(grp3d_nominal_low_vectors),
+		grp3d_nominal_low_vectors,
+	},
+	{
+		ARRAY_SIZE(grp3d_nominal_high_vectors),
+		grp3d_nominal_high_vectors,
+	},
+	{
+		ARRAY_SIZE(grp3d_max_vectors),
+		grp3d_max_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata grp3d_bus_scale_pdata = {
+	grp3d_bus_scale_usecases,
+	ARRAY_SIZE(grp3d_bus_scale_usecases),
+	.name = "grp3d",
+};
+
+static struct msm_bus_vectors grp2d0_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_2D_CORE0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+static struct msm_bus_vectors grp2d0_max_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_2D_CORE0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(990),
+	},
+};
+
+static struct msm_bus_paths grp2d0_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(grp2d0_init_vectors),
+		grp2d0_init_vectors,
+	},
+	{
+		ARRAY_SIZE(grp2d0_max_vectors),
+		grp2d0_max_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata grp2d0_bus_scale_pdata = {
+	grp2d0_bus_scale_usecases,
+	ARRAY_SIZE(grp2d0_bus_scale_usecases),
+	.name = "grp2d0",
+};
+
+static struct msm_bus_vectors grp2d1_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_2D_CORE1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+static struct msm_bus_vectors grp2d1_max_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_2D_CORE1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(990),
+	},
+};
+
+static struct msm_bus_paths grp2d1_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(grp2d1_init_vectors),
+		grp2d1_init_vectors,
+	},
+	{
+		ARRAY_SIZE(grp2d1_max_vectors),
+		grp2d1_max_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata grp2d1_bus_scale_pdata = {
+	grp2d1_bus_scale_usecases,
+	ARRAY_SIZE(grp2d1_bus_scale_usecases),
+	.name = "grp2d1",
+};
+#endif
+
+#ifdef CONFIG_HW_RANDOM_MSM
+static struct resource rng_resources = {
+	.flags = IORESOURCE_MEM,
+	.start = MSM_PRNG_PHYS,
+	.end   = MSM_PRNG_PHYS + SZ_512 - 1,
+};
+
+struct platform_device msm_device_rng = {
+	.name          = "msm_rng",
+	.id            = 0,
+	.num_resources = 1,
+	.resource      = &rng_resources,
+};
+#endif
+
+static struct resource kgsl_3d0_resources[] = {
+	{
+		.name = KGSL_3D0_REG_MEMORY,
+		.start = 0x04300000, /* GFX3D address */
+		.end = 0x0431ffff,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = KGSL_3D0_IRQ,
+		.start = GFX3D_IRQ,
+		.end = GFX3D_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct kgsl_device_platform_data kgsl_3d0_pdata = {
+	.pwrlevel = {
+		{
+			.gpu_freq = 266667000,
+			.bus_freq = 4,
+			.io_fraction = 0,
+		},
+		{
+			.gpu_freq = 228571000,
+			.bus_freq = 3,
+			.io_fraction = 33,
+		},
+		{
+			.gpu_freq = 200000000,
+			.bus_freq = 2,
+			.io_fraction = 100,
+		},
+		{
+			.gpu_freq = 177778000,
+			.bus_freq = 1,
+			.io_fraction = 100,
+		},
+		{
+			.gpu_freq = 27000000,
+			.bus_freq = 0,
+		},
+	},
+	.init_level = 0,
+	.num_levels = 5,
+	.set_grp_async = NULL,
+	.idle_timeout = HZ/5,
+	.nap_allowed = true,
+	.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM_IFACE,
+#ifdef CONFIG_MSM_BUS_SCALING
+	.bus_scale_table = &grp3d_bus_scale_pdata,
+#endif
+};
+
+struct platform_device msm_kgsl_3d0 = {
+	.name = "kgsl-3d0",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(kgsl_3d0_resources),
+	.resource = kgsl_3d0_resources,
+	.dev = {
+		.platform_data = &kgsl_3d0_pdata,
+	},
+};
+
+static struct resource kgsl_2d0_resources[] = {
+	{
+		.name = KGSL_2D0_REG_MEMORY,
+		.start = 0x04100000, /* Z180 base address */
+		.end = 0x04100FFF,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name  = KGSL_2D0_IRQ,
+		.start = GFX2D0_IRQ,
+		.end = GFX2D0_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct kgsl_device_platform_data kgsl_2d0_pdata = {
+	.pwrlevel = {
+		{
+			.gpu_freq = 200000000,
+			.bus_freq = 1,
+		},
+		{
+			.gpu_freq = 200000000,
+			.bus_freq = 0,
+		},
+	},
+	.init_level = 0,
+	.num_levels = 2,
+	.set_grp_async = NULL,
+	.idle_timeout = HZ/10,
+	.nap_allowed = true,
+	.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE,
+#ifdef CONFIG_MSM_BUS_SCALING
+	.bus_scale_table = &grp2d0_bus_scale_pdata,
+#endif
+};
+
+struct platform_device msm_kgsl_2d0 = {
+	.name = "kgsl-2d0",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(kgsl_2d0_resources),
+	.resource = kgsl_2d0_resources,
+	.dev = {
+		.platform_data = &kgsl_2d0_pdata,
+	},
+};
+
+static struct resource kgsl_2d1_resources[] = {
+	{
+		.name = KGSL_2D1_REG_MEMORY,
+		.start = 0x04200000, /* Z180 device 1 base address */
+		.end =   0x04200FFF,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name  = KGSL_2D1_IRQ,
+		.start = GFX2D1_IRQ,
+		.end = GFX2D1_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct kgsl_device_platform_data kgsl_2d1_pdata = {
+	.pwrlevel = {
+		{
+			.gpu_freq = 200000000,
+			.bus_freq = 1,
+		},
+		{
+			.gpu_freq = 200000000,
+			.bus_freq = 0,
+		},
+	},
+	.init_level = 0,
+	.num_levels = 2,
+	.set_grp_async = NULL,
+	.idle_timeout = HZ/10,
+	.nap_allowed = true,
+	.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE,
+#ifdef CONFIG_MSM_BUS_SCALING
+	.bus_scale_table = &grp2d1_bus_scale_pdata,
+#endif
+};
+
+struct platform_device msm_kgsl_2d1 = {
+	.name = "kgsl-2d1",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(kgsl_2d1_resources),
+	.resource = kgsl_2d1_resources,
+	.dev = {
+		.platform_data = &kgsl_2d1_pdata,
+	},
+};
+
+/*
+ * this a software workaround for not having two distinct board
+ * files for 8660v1 and 8660v2. 8660v1 has a faulty 2d clock, and
+ * this workaround detects the cpu version to tell if the kernel is on a
+ * 8660v1, and should disable the 2d core. it is called from the board file
+ */
+void __init msm8x60_check_2d_hardware(void)
+{
+	if ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1) &&
+	    (SOCINFO_VERSION_MINOR(socinfo_get_version()) == 0)) {
+		printk(KERN_WARNING "kgsl: 2D cores disabled on 8660v1\n");
+		kgsl_2d0_pdata.clk_map = 0;
+	}
+}
+
+/* Use GSBI3 QUP for /dev/i2c-0 */
+struct platform_device msm_gsbi3_qup_i2c_device = {
+	.name		= "qup_i2c",
+	.id		= MSM_GSBI3_QUP_I2C_BUS_ID,
+	.num_resources	= ARRAY_SIZE(gsbi3_qup_i2c_resources),
+	.resource	= gsbi3_qup_i2c_resources,
+};
+
+/* Use GSBI4 QUP for /dev/i2c-1 */
+struct platform_device msm_gsbi4_qup_i2c_device = {
+	.name		= "qup_i2c",
+	.id		= MSM_GSBI4_QUP_I2C_BUS_ID,
+	.num_resources	= ARRAY_SIZE(gsbi4_qup_i2c_resources),
+	.resource	= gsbi4_qup_i2c_resources,
+};
+
+/* Use GSBI8 QUP for /dev/i2c-3 */
+struct platform_device msm_gsbi8_qup_i2c_device = {
+	.name		= "qup_i2c",
+	.id		= MSM_GSBI8_QUP_I2C_BUS_ID,
+	.num_resources	= ARRAY_SIZE(gsbi8_qup_i2c_resources),
+	.resource	= gsbi8_qup_i2c_resources,
+};
+
+/* Use GSBI9 QUP for /dev/i2c-2 */
+struct platform_device msm_gsbi9_qup_i2c_device = {
+	.name		= "qup_i2c",
+	.id		= MSM_GSBI9_QUP_I2C_BUS_ID,
+	.num_resources	= ARRAY_SIZE(gsbi9_qup_i2c_resources),
+	.resource	= gsbi9_qup_i2c_resources,
+};
+
+/* Use GSBI7 QUP for /dev/i2c-4 (Marimba) */
+struct platform_device msm_gsbi7_qup_i2c_device = {
+	.name		= "qup_i2c",
+	.id		= MSM_GSBI7_QUP_I2C_BUS_ID,
+	.num_resources	= ARRAY_SIZE(gsbi7_qup_i2c_resources),
+	.resource	= gsbi7_qup_i2c_resources,
+};
+
+/* Use GSBI12 QUP for /dev/i2c-5 (Sensors) */
+struct platform_device msm_gsbi12_qup_i2c_device = {
+	.name		= "qup_i2c",
+	.id		= MSM_GSBI12_QUP_I2C_BUS_ID,
+	.num_resources	= ARRAY_SIZE(gsbi12_qup_i2c_resources),
+	.resource	= gsbi12_qup_i2c_resources,
+};
+
+#ifdef CONFIG_MSM_SSBI
+#define MSM_SSBI_PMIC1_PHYS	0x00500000
+static struct resource resources_ssbi_pmic1_resource[] = {
+	{
+		.start  = MSM_SSBI_PMIC1_PHYS,
+		.end    = MSM_SSBI_PMIC1_PHYS + SZ_4K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_device_ssbi_pmic1 = {
+	.name           = "msm_ssbi",
+	.id             = 0,
+	.resource       = resources_ssbi_pmic1_resource,
+	.num_resources  = ARRAY_SIZE(resources_ssbi_pmic1_resource),
+};
+
+#define MSM_SSBI2_PMIC2B_PHYS	0x00C00000
+static struct resource resources_ssbi_pmic2_resource[] = {
+	{
+		.start	= MSM_SSBI2_PMIC2B_PHYS,
+		.end	= MSM_SSBI2_PMIC2B_PHYS + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_device_ssbi_pmic2 = {
+	.name		= "msm_ssbi",
+	.id		= 1,
+	.resource	= resources_ssbi_pmic2_resource,
+	.num_resources	= ARRAY_SIZE(resources_ssbi_pmic2_resource),
+};
+#endif
+
+#ifdef CONFIG_I2C_SSBI
+/* CODEC SSBI on /dev/i2c-8 */
+#define MSM_SSBI3_PHYS  0x18700000
+static struct resource msm_ssbi3_resources[] = {
+	{
+		.name   = "ssbi_base",
+		.start  = MSM_SSBI3_PHYS,
+		.end    = MSM_SSBI3_PHYS + SZ_4K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_device_ssbi3 = {
+	.name		= "i2c_ssbi",
+	.id		= MSM_SSBI3_I2C_BUS_ID,
+	.num_resources	= ARRAY_SIZE(msm_ssbi3_resources),
+	.resource	= msm_ssbi3_resources,
+};
+#endif /* CONFIG_I2C_SSBI */
+
+static struct resource gsbi1_qup_spi_resources[] = {
+	{
+		.name	= "spi_base",
+		.start	= MSM_GSBI1_QUP_PHYS,
+		.end	= MSM_GSBI1_QUP_PHYS + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "gsbi_base",
+		.start	= MSM_GSBI1_PHYS,
+		.end	= MSM_GSBI1_PHYS + 4 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "spi_irq_in",
+		.start	= GSBI1_QUP_IRQ,
+		.end	= GSBI1_QUP_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name   = "spidm_channels",
+		.start  = 5,
+		.end    = 6,
+		.flags  = IORESOURCE_DMA,
+	},
+	{
+		.name   = "spidm_crci",
+		.start  = 8,
+		.end    = 7,
+		.flags  = IORESOURCE_DMA,
+	},
+	{
+		.name   = "spi_clk",
+		.start  = 36,
+		.end    = 36,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "spi_miso",
+		.start  = 34,
+		.end    = 34,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "spi_mosi",
+		.start  = 33,
+		.end    = 33,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "spi_cs",
+		.start  = 35,
+		.end    = 35,
+		.flags  = IORESOURCE_IO,
+	},
+};
+
+/* Use GSBI1 QUP for SPI-0 */
+struct platform_device msm_gsbi1_qup_spi_device = {
+	.name		= "spi_qsd",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(gsbi1_qup_spi_resources),
+	.resource	= gsbi1_qup_spi_resources,
+};
+
+
+static struct resource gsbi10_qup_spi_resources[] = {
+	{
+		.name	= "spi_base",
+		.start	= MSM_GSBI10_QUP_PHYS,
+		.end	= MSM_GSBI10_QUP_PHYS + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "gsbi_base",
+		.start	= MSM_GSBI10_PHYS,
+		.end	= MSM_GSBI10_PHYS + 4 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "spi_irq_in",
+		.start	= GSBI10_QUP_IRQ,
+		.end	= GSBI10_QUP_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name   = "spi_clk",
+		.start  = 73,
+		.end    = 73,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "spi_cs",
+		.start  = 72,
+		.end    = 72,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "spi_mosi",
+		.start  = 70,
+		.end    = 70,
+		.flags  = IORESOURCE_IO,
+	},
+};
+
+/* Use GSBI10 QUP for SPI-1 */
+struct platform_device msm_gsbi10_qup_spi_device = {
+	.name		= "spi_qsd",
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(gsbi10_qup_spi_resources),
+	.resource	= gsbi10_qup_spi_resources,
+};
+#define MSM_SDC1_BASE         0x12400000
+#define MSM_SDC1_DML_BASE     (MSM_SDC1_BASE + 0x800)
+#define MSM_SDC1_BAM_BASE     (MSM_SDC1_BASE + 0x2000)
+#define MSM_SDC2_BASE         0x12140000
+#define MSM_SDC2_DML_BASE     (MSM_SDC2_BASE + 0x800)
+#define MSM_SDC2_BAM_BASE     (MSM_SDC2_BASE + 0x2000)
+#define MSM_SDC3_BASE         0x12180000
+#define MSM_SDC3_DML_BASE     (MSM_SDC3_BASE + 0x800)
+#define MSM_SDC3_BAM_BASE     (MSM_SDC3_BASE + 0x2000)
+#define MSM_SDC4_BASE         0x121C0000
+#define MSM_SDC4_DML_BASE     (MSM_SDC4_BASE + 0x800)
+#define MSM_SDC4_BAM_BASE     (MSM_SDC4_BASE + 0x2000)
+#define MSM_SDC5_BASE         0x12200000
+#define MSM_SDC5_DML_BASE     (MSM_SDC5_BASE + 0x800)
+#define MSM_SDC5_BAM_BASE     (MSM_SDC5_BASE + 0x2000)
+
+static struct resource resources_sdc1[] = {
+	{
+		.start	= MSM_SDC1_BASE,
+		.end	= MSM_SDC1_DML_BASE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= SDC1_IRQ_0,
+		.end	= SDC1_IRQ_0,
+		.flags	= IORESOURCE_IRQ,
+	},
+#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
+	{
+		.name   = "sdcc_dml_addr",
+		.start	= MSM_SDC1_DML_BASE,
+		.end	= MSM_SDC1_BAM_BASE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_addr",
+		.start	= MSM_SDC1_BAM_BASE,
+		.end	= MSM_SDC1_BAM_BASE + (2 * SZ_4K) - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_irq",
+		.start	= SDC1_BAM_IRQ,
+		.end	= SDC1_BAM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+#else
+	{
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC1_CHAN,
+		.end	= DMOV_SDC1_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC1_CRCI,
+		.end	= DMOV_SDC1_CRCI,
+		.flags	= IORESOURCE_DMA,
+	}
+#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
+};
+
+static struct resource resources_sdc2[] = {
+	{
+		.start	= MSM_SDC2_BASE,
+		.end	= MSM_SDC2_DML_BASE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= SDC2_IRQ_0,
+		.end	= SDC2_IRQ_0,
+		.flags	= IORESOURCE_IRQ,
+	},
+#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
+	{
+		.name   = "sdcc_dml_addr",
+		.start	= MSM_SDC2_DML_BASE,
+		.end	= MSM_SDC2_BAM_BASE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_addr",
+		.start	= MSM_SDC2_BAM_BASE,
+		.end	= MSM_SDC2_BAM_BASE + (2 * SZ_4K) - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_irq",
+		.start	= SDC2_BAM_IRQ,
+		.end	= SDC2_BAM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+#else
+	{
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC2_CHAN,
+		.end	= DMOV_SDC2_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC2_CRCI,
+		.end	= DMOV_SDC2_CRCI,
+		.flags	= IORESOURCE_DMA,
+	}
+#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
+};
+
+static struct resource resources_sdc3[] = {
+	{
+		.start	= MSM_SDC3_BASE,
+		.end	= MSM_SDC3_DML_BASE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= SDC3_IRQ_0,
+		.end	= SDC3_IRQ_0,
+		.flags	= IORESOURCE_IRQ,
+	},
+#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
+	{
+		.name   = "sdcc_dml_addr",
+		.start	= MSM_SDC3_DML_BASE,
+		.end	= MSM_SDC3_BAM_BASE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_addr",
+		.start	= MSM_SDC3_BAM_BASE,
+		.end	= MSM_SDC3_BAM_BASE + (2 * SZ_4K) - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_irq",
+		.start	= SDC3_BAM_IRQ,
+		.end	= SDC3_BAM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+#else
+	{
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC3_CHAN,
+		.end	= DMOV_SDC3_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC3_CRCI,
+		.end	= DMOV_SDC3_CRCI,
+		.flags	= IORESOURCE_DMA,
+	},
+#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
+};
+
+static struct resource resources_sdc4[] = {
+	{
+		.start	= MSM_SDC4_BASE,
+		.end	= MSM_SDC4_DML_BASE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= SDC4_IRQ_0,
+		.end	= SDC4_IRQ_0,
+		.flags	= IORESOURCE_IRQ,
+	},
+#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
+	{
+		.name   = "sdcc_dml_addr",
+		.start	= MSM_SDC4_DML_BASE,
+		.end	= MSM_SDC4_BAM_BASE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_addr",
+		.start	= MSM_SDC4_BAM_BASE,
+		.end	= MSM_SDC4_BAM_BASE + (2 * SZ_4K) - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_irq",
+		.start	= SDC4_BAM_IRQ,
+		.end	= SDC4_BAM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+#else
+	{
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC4_CHAN,
+		.end	= DMOV_SDC4_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC4_CRCI,
+		.end	= DMOV_SDC4_CRCI,
+		.flags	= IORESOURCE_DMA,
+	},
+#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
+};
+
+static struct resource resources_sdc5[] = {
+	{
+		.start	= MSM_SDC5_BASE,
+		.end	= MSM_SDC5_DML_BASE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= SDC5_IRQ_0,
+		.end	= SDC5_IRQ_0,
+		.flags	= IORESOURCE_IRQ,
+	},
+#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
+	{
+		.name   = "sdcc_dml_addr",
+		.start	= MSM_SDC5_DML_BASE,
+		.end	= MSM_SDC5_BAM_BASE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_addr",
+		.start	= MSM_SDC5_BAM_BASE,
+		.end	= MSM_SDC5_BAM_BASE + (2 * SZ_4K) - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "sdcc_bam_irq",
+		.start	= SDC5_BAM_IRQ,
+		.end	= SDC5_BAM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+#else
+	{
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC5_CHAN,
+		.end	= DMOV_SDC5_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC5_CRCI,
+		.end	= DMOV_SDC5_CRCI,
+		.flags	= IORESOURCE_DMA,
+	},
+#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
+};
+
+struct platform_device msm_device_sdc1 = {
+	.name		= "msm_sdcc",
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(resources_sdc1),
+	.resource	= resources_sdc1,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_sdc2 = {
+	.name		= "msm_sdcc",
+	.id		= 2,
+	.num_resources	= ARRAY_SIZE(resources_sdc2),
+	.resource	= resources_sdc2,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_sdc3 = {
+	.name		= "msm_sdcc",
+	.id		= 3,
+	.num_resources	= ARRAY_SIZE(resources_sdc3),
+	.resource	= resources_sdc3,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_sdc4 = {
+	.name		= "msm_sdcc",
+	.id		= 4,
+	.num_resources	= ARRAY_SIZE(resources_sdc4),
+	.resource	= resources_sdc4,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+struct platform_device msm_device_sdc5 = {
+	.name		= "msm_sdcc",
+	.id		= 5,
+	.num_resources	= ARRAY_SIZE(resources_sdc5),
+	.resource	= resources_sdc5,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+static struct platform_device *msm_sdcc_devices[] __initdata = {
+	&msm_device_sdc1,
+	&msm_device_sdc2,
+	&msm_device_sdc3,
+	&msm_device_sdc4,
+	&msm_device_sdc5,
+};
+
+int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat)
+{
+	struct platform_device	*pdev;
+
+	if (controller < 1 || controller > 5)
+		return -EINVAL;
+
+	pdev = msm_sdcc_devices[controller-1];
+	pdev->dev.platform_data = plat;
+	return platform_device_register(pdev);
+}
+
+#ifdef CONFIG_MSM_CAMERA_V4L2
+static struct resource msm_csic0_resources[] = {
+	{
+		.name   = "csic",
+		.start  = 0x04800000,
+		.end    = 0x04800000 + 0x00000400 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "csic",
+		.start  = CSI_0_IRQ,
+		.end    = CSI_0_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct resource msm_csic1_resources[] = {
+	{
+		.name   = "csic",
+		.start  = 0x04900000,
+		.end    = 0x04900000 + 0x00000400 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "csic",
+		.start  = CSI_1_IRQ,
+		.end    = CSI_1_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+struct resource msm_vfe_resources[] = {
+	{
+		.name   = "msm_vfe",
+		.start	= 0x04500000,
+		.end	= 0x04500000 + SZ_1M - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "msm_vfe",
+		.start	= VFE_IRQ,
+		.end	= VFE_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct resource msm_vpe_resources[] = {
+	{
+		.name   = "vpe",
+		.start	= 0x05300000,
+		.end	= 0x05300000 + SZ_1M - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "vpe",
+		.start	= INT_VPE,
+		.end	= INT_VPE,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_csic0 = {
+	.name           = "msm_csic",
+	.id             = 0,
+	.resource       = msm_csic0_resources,
+	.num_resources  = ARRAY_SIZE(msm_csic0_resources),
+};
+
+struct platform_device msm_device_csic1 = {
+	.name           = "msm_csic",
+	.id             = 1,
+	.resource       = msm_csic1_resources,
+	.num_resources  = ARRAY_SIZE(msm_csic1_resources),
+};
+
+struct platform_device msm_device_vfe = {
+	.name           = "msm_vfe",
+	.id             = 0,
+	.resource       = msm_vfe_resources,
+	.num_resources  = ARRAY_SIZE(msm_vfe_resources),
+};
+
+struct platform_device msm_device_vpe = {
+	.name           = "msm_vpe",
+	.id             = 0,
+	.resource       = msm_vpe_resources,
+	.num_resources  = ARRAY_SIZE(msm_vpe_resources),
+};
+
+#endif
+
+
+#define MIPI_DSI_HW_BASE	0x04700000
+#define ROTATOR_HW_BASE		0x04E00000
+#define TVENC_HW_BASE		0x04F00000
+#define MDP_HW_BASE		0x05100000
+
+static struct resource msm_mipi_dsi_resources[] = {
+	{
+		.name   = "mipi_dsi",
+		.start  = MIPI_DSI_HW_BASE,
+		.end    = MIPI_DSI_HW_BASE + 0x000F0000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = DSI_IRQ,
+		.end    = DSI_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device msm_mipi_dsi_device = {
+	.name   = "mipi_dsi",
+	.id     = 1,
+	.num_resources  = ARRAY_SIZE(msm_mipi_dsi_resources),
+	.resource       = msm_mipi_dsi_resources,
+};
+
+static struct resource msm_mdp_resources[] = {
+	{
+		.name   = "mdp",
+		.start  = MDP_HW_BASE,
+		.end    = MDP_HW_BASE + 0x000F0000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = INT_MDP,
+		.end    = INT_MDP,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device msm_mdp_device = {
+	.name   = "mdp",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_mdp_resources),
+	.resource       = msm_mdp_resources,
+};
+#ifdef CONFIG_MSM_ROTATOR
+static struct resource resources_msm_rotator[] = {
+	{
+		.start	= 0x04E00000,
+		.end	= 0x04F00000 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= ROT_IRQ,
+		.end	= ROT_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct msm_rot_clocks rotator_clocks[] = {
+	{
+		.clk_name = "core_clk",
+		.clk_type = ROTATOR_CORE_CLK,
+		.clk_rate = 160 * 1000 * 1000,
+	},
+	{
+		.clk_name = "iface_clk",
+		.clk_type = ROTATOR_PCLK,
+		.clk_rate = 0,
+	},
+};
+
+static struct msm_rotator_platform_data rotator_pdata = {
+	.number_of_clocks = ARRAY_SIZE(rotator_clocks),
+	.hardware_version_number = 0x01010307,
+	.rotator_clks = rotator_clocks,
+#ifdef CONFIG_MSM_BUS_SCALING
+	.bus_scale_table = &rotator_bus_scale_pdata,
+#endif
+
+};
+
+struct platform_device msm_rotator_device = {
+	.name		= "msm_rotator",
+	.id		= 0,
+	.num_resources  = ARRAY_SIZE(resources_msm_rotator),
+	.resource       = resources_msm_rotator,
+	.dev		= {
+		.platform_data = &rotator_pdata,
+	},
+};
+#endif
+
+
+/* Sensors DSPS platform data */
+#ifdef CONFIG_MSM_DSPS
+
+#define PPSS_REG_PHYS_BASE	0x12080000
+
+#define MHZ (1000*1000)
+
+#define TCSR_GSBI_IRQ_MUX_SEL	0x0044
+
+#define GSBI_IRQ_MUX_SEL_MASK	0xF
+#define GSBI_IRQ_MUX_SEL_DSPS	0xB
+
+static void dsps_init1(struct msm_dsps_platform_data *data)
+{
+	int val;
+
+	/* route GSBI12 interrutps to DSPS */
+	val = secure_readl(MSM_TCSR_BASE +  TCSR_GSBI_IRQ_MUX_SEL);
+	val &= ~GSBI_IRQ_MUX_SEL_MASK;
+	val |= GSBI_IRQ_MUX_SEL_DSPS;
+	secure_writel(val, MSM_TCSR_BASE + TCSR_GSBI_IRQ_MUX_SEL);
+}
+
+static struct dsps_clk_info dsps_clks[] = {
+	{
+		.name = "iface_clk",
+		.rate =	0, /* no rate just on/off */
+	},
+	{
+		.name = "mem_clk",
+		.rate =	0, /* no rate just on/off */
+	},
+	{
+		.name = "gsbi_qup_clk",
+		.rate =	24 * MHZ, /* See clk_tbl_gsbi_qup[] */
+	},
+	{
+		.name = "dfab_dsps_clk",
+		.rate =	64 * MHZ, /* Same rate as USB. */
+	}
+};
+
+static struct dsps_regulator_info dsps_regs[] = {
+	{
+		.name = "8058_l5",
+		.volt = 2850000, /* in uV */
+	},
+	{
+		.name = "8058_s3",
+		.volt = 1800000, /* in uV */
+	}
+};
+
+/*
+ * Note: GPIOs field is	intialized in run-time at the function
+ * msm8x60_init_dsps().
+ */
+
+struct msm_dsps_platform_data msm_dsps_pdata = {
+	.clks = dsps_clks,
+	.clks_num = ARRAY_SIZE(dsps_clks),
+	.gpios = NULL,
+	.gpios_num = 0,
+	.regs = dsps_regs,
+	.regs_num = ARRAY_SIZE(dsps_regs),
+	.init = dsps_init1,
+	.signature = DSPS_SIGNATURE,
+};
+
+static struct resource msm_dsps_resources[] = {
+	{
+		.start = PPSS_REG_PHYS_BASE,
+		.end   = PPSS_REG_PHYS_BASE + SZ_8K - 1,
+		.name  = "ppss_reg",
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_dsps_device = {
+	.name          = "msm_dsps",
+	.id            = 0,
+	.num_resources = ARRAY_SIZE(msm_dsps_resources),
+	.resource      = msm_dsps_resources,
+	.dev.platform_data = &msm_dsps_pdata,
+};
+
+#endif /* CONFIG_MSM_DSPS */
+
+#ifdef CONFIG_FB_MSM_TVOUT
+static struct resource msm_tvenc_resources[] = {
+	{
+		.name   = "tvenc",
+		.start  = TVENC_HW_BASE,
+		.end    = TVENC_HW_BASE + PAGE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	}
+};
+
+static struct resource tvout_device_resources[] = {
+	{
+		.name  = "tvout_device_irq",
+		.start = TV_ENC_IRQ,
+		.end   = TV_ENC_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+#endif
+static void __init msm_register_device(struct platform_device *pdev, void *data)
+{
+	int ret;
+
+	pdev->dev.platform_data = data;
+
+	ret = platform_device_register(pdev);
+	if (ret)
+		dev_err(&pdev->dev,
+			  "%s: platform_device_register() failed = %d\n",
+			  __func__, ret);
+}
+
+static struct platform_device msm_lcdc_device = {
+	.name   = "lcdc",
+	.id     = 0,
+};
+
+#ifdef CONFIG_FB_MSM_TVOUT
+static struct platform_device msm_tvenc_device = {
+	.name   = "tvenc",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_tvenc_resources),
+	.resource       = msm_tvenc_resources,
+};
+
+static struct platform_device msm_tvout_device = {
+	.name = "tvout_device",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(tvout_device_resources),
+	.resource = tvout_device_resources,
+};
+#endif
+
+#ifdef CONFIG_MSM_BUS_SCALING
+static struct platform_device msm_dtv_device = {
+	.name   = "dtv",
+	.id     = 0,
+};
+#endif
+
+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, "lcdc", 4))
+		msm_register_device(&msm_lcdc_device, data);
+	else if (!strncmp(name, "mipi_dsi", 8))
+		msm_register_device(&msm_mipi_dsi_device, data);
+#ifdef CONFIG_FB_MSM_TVOUT
+	else if (!strncmp(name, "tvenc", 5))
+		msm_register_device(&msm_tvenc_device, data);
+	else if (!strncmp(name, "tvout_device", 12))
+		msm_register_device(&msm_tvout_device, data);
+#endif
+#ifdef CONFIG_MSM_BUS_SCALING
+	else if (!strncmp(name, "dtv", 3))
+		msm_register_device(&msm_dtv_device, data);
+#endif
+	else
+		printk(KERN_ERR "%s: unknown device! %s\n", __func__, name);
+}
+
+static struct resource resources_otg[] = {
+	{
+		.start	= 0x12500000,
+		.end	= 0x12500000 + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= USB1_HS_IRQ,
+		.end	= USB1_HS_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_otg = {
+	.name		= "msm_otg",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_otg),
+	.resource	= resources_otg,
+};
+
+static u64 dma_mask = 0xffffffffULL;
+struct platform_device msm_device_gadget_peripheral = {
+	.name		= "msm_hsusb",
+	.id		= -1,
+	.dev		= {
+		.dma_mask 		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+#ifdef CONFIG_USB_EHCI_MSM_72K
+static struct resource resources_hsusb_host[] = {
+	{
+		.start	= 0x12500000,
+		.end	= 0x12500000 + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= USB1_HS_IRQ,
+		.end	= USB1_HS_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_hsusb_host = {
+	.name		= "msm_hsusb_host",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(resources_hsusb_host),
+	.resource	= resources_hsusb_host,
+	.dev		= {
+		.dma_mask 		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+static struct platform_device *msm_host_devices[] = {
+	&msm_device_hsusb_host,
+};
+
+int msm_add_host(unsigned int host, struct msm_usb_host_platform_data *plat)
+{
+	struct platform_device	*pdev;
+
+	pdev = msm_host_devices[host];
+	if (!pdev)
+		return -ENODEV;
+	pdev->dev.platform_data = plat;
+	return platform_device_register(pdev);
+}
+#endif
+
+#define MSM_TSIF0_PHYS       (0x18200000)
+#define MSM_TSIF1_PHYS       (0x18201000)
+#define MSM_TSIF_SIZE        (0x200)
+#define TCSR_ADM_0_A_CRCI_MUX_SEL 0x0070
+
+#define TSIF_0_CLK       GPIO_CFG(93, 1, GPIO_CFG_INPUT, \
+	GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_0_EN        GPIO_CFG(94, 1, GPIO_CFG_INPUT, \
+	GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_0_DATA      GPIO_CFG(95, 1, GPIO_CFG_INPUT, \
+	GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_0_SYNC      GPIO_CFG(96, 1, GPIO_CFG_INPUT, \
+	GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_1_CLK       GPIO_CFG(97, 1, GPIO_CFG_INPUT, \
+	GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_1_EN        GPIO_CFG(98, 1, GPIO_CFG_INPUT, \
+	GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_1_DATA      GPIO_CFG(99, 1, GPIO_CFG_INPUT, \
+	GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_1_SYNC      GPIO_CFG(100, 1, GPIO_CFG_INPUT, \
+	GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+
+static const struct msm_gpio tsif0_gpios[] = {
+	{ .gpio_cfg = TSIF_0_CLK,  .label =  "tsif_clk", },
+	{ .gpio_cfg = TSIF_0_EN,   .label =  "tsif_en", },
+	{ .gpio_cfg = TSIF_0_DATA, .label =  "tsif_data", },
+	{ .gpio_cfg = TSIF_0_SYNC, .label =  "tsif_sync", },
+};
+
+static const struct msm_gpio tsif1_gpios[] = {
+	{ .gpio_cfg = TSIF_1_CLK,  .label =  "tsif_clk", },
+	{ .gpio_cfg = TSIF_1_EN,   .label =  "tsif_en", },
+	{ .gpio_cfg = TSIF_1_DATA, .label =  "tsif_data", },
+	{ .gpio_cfg = TSIF_1_SYNC, .label =  "tsif_sync", },
+};
+
+static void tsif_release(struct device *dev)
+{
+}
+
+static void tsif_init1(struct msm_tsif_platform_data *data)
+{
+	int val;
+
+	/* configure mux to use correct tsif instance */
+	val = secure_readl(MSM_TCSR_BASE + TCSR_ADM_0_A_CRCI_MUX_SEL);
+	val |= 0x80000000;
+	secure_writel(val, MSM_TCSR_BASE + TCSR_ADM_0_A_CRCI_MUX_SEL);
+}
+
+struct msm_tsif_platform_data tsif1_platform_data = {
+	.num_gpios = ARRAY_SIZE(tsif1_gpios),
+	.gpios = tsif1_gpios,
+	.tsif_pclk = "iface_clk",
+	.tsif_ref_clk = "ref_clk",
+	.init = tsif_init1
+};
+
+struct resource tsif1_resources[] = {
+	[0] = {
+		.flags = IORESOURCE_IRQ,
+		.start = TSIF2_IRQ,
+		.end   = TSIF2_IRQ,
+	},
+	[1] = {
+		.flags = IORESOURCE_MEM,
+		.start = MSM_TSIF1_PHYS,
+		.end   = MSM_TSIF1_PHYS + MSM_TSIF_SIZE - 1,
+	},
+	[2] = {
+		.flags = IORESOURCE_DMA,
+		.start = DMOV_TSIF_CHAN,
+		.end   = DMOV_TSIF_CRCI,
+	},
+};
+
+static void tsif_init0(struct msm_tsif_platform_data *data)
+{
+	int val;
+
+	/* configure mux to use correct tsif instance */
+	val = secure_readl(MSM_TCSR_BASE + TCSR_ADM_0_A_CRCI_MUX_SEL);
+	val &= 0x7FFFFFFF;
+	secure_writel(val, MSM_TCSR_BASE + TCSR_ADM_0_A_CRCI_MUX_SEL);
+}
+
+struct msm_tsif_platform_data tsif0_platform_data = {
+	.num_gpios = ARRAY_SIZE(tsif0_gpios),
+	.gpios = tsif0_gpios,
+	.tsif_pclk = "iface_clk",
+	.tsif_ref_clk = "ref_clk",
+	.init = tsif_init0
+};
+struct resource tsif0_resources[] = {
+	[0] = {
+		.flags = IORESOURCE_IRQ,
+		.start = TSIF1_IRQ,
+		.end   = TSIF1_IRQ,
+	},
+	[1] = {
+		.flags = IORESOURCE_MEM,
+		.start = MSM_TSIF0_PHYS,
+		.end   = MSM_TSIF0_PHYS + MSM_TSIF_SIZE - 1,
+	},
+	[2] = {
+		.flags = IORESOURCE_DMA,
+		.start = DMOV_TSIF_CHAN,
+		.end   = DMOV_TSIF_CRCI,
+	},
+};
+
+struct platform_device msm_device_tsif[2] = {
+	{
+		.name          = "msm_tsif",
+		.id            = 0,
+		.num_resources = ARRAY_SIZE(tsif0_resources),
+		.resource      = tsif0_resources,
+		.dev = {
+			.release       = tsif_release,
+			.platform_data = &tsif0_platform_data
+		},
+	},
+	{
+		.name          = "msm_tsif",
+		.id            = 1,
+		.num_resources = ARRAY_SIZE(tsif1_resources),
+		.resource      = tsif1_resources,
+		.dev = {
+			.release       = tsif_release,
+			.platform_data = &tsif1_platform_data
+		},
+	}
+};
+
+struct platform_device msm_device_smd = {
+	.name           = "msm_smd",
+	.id             = -1,
+};
+
+static struct msm_watchdog_pdata msm_watchdog_pdata = {
+	.pet_time = 10000,
+	.bark_time = 11000,
+	.has_secure = true,
+};
+
+struct platform_device msm8660_device_watchdog = {
+	.name = "msm_watchdog",
+	.id = -1,
+	.dev = {
+		.platform_data = &msm_watchdog_pdata,
+	},
+};
+
+static struct resource msm_dmov_resource_adm0[] = {
+	{
+		.start = INT_ADM0_AARM,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = 0x18320000,
+		.end = 0x18320000 + SZ_1M - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct resource msm_dmov_resource_adm1[] = {
+	{
+		.start = INT_ADM1_AARM,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = 0x18420000,
+		.end = 0x18420000 + SZ_1M - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct msm_dmov_pdata msm_dmov_pdata_adm0 = {
+	.sd = 1,
+	.sd_size = 0x800,
+};
+
+static struct msm_dmov_pdata msm_dmov_pdata_adm1 = {
+	.sd = 1,
+	.sd_size = 0x800,
+};
+
+struct platform_device msm_device_dmov_adm0 = {
+	.name	= "msm_dmov",
+	.id	= 0,
+	.resource = msm_dmov_resource_adm0,
+	.num_resources = ARRAY_SIZE(msm_dmov_resource_adm0),
+	.dev = {
+		.platform_data = &msm_dmov_pdata_adm0,
+	},
+};
+
+struct platform_device msm_device_dmov_adm1 = {
+	.name	= "msm_dmov",
+	.id	= 1,
+	.resource = msm_dmov_resource_adm1,
+	.num_resources = ARRAY_SIZE(msm_dmov_resource_adm1),
+	.dev = {
+		.platform_data = &msm_dmov_pdata_adm1,
+	},
+};
+
+/* MSM Video core device */
+#ifdef CONFIG_MSM_BUS_SCALING
+static struct msm_bus_vectors vidc_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+static struct msm_bus_vectors vidc_venc_vga_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 54525952,
+		.ib  = 436207616,
+	},
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 72351744,
+		.ib  = 289406976,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 500000,
+		.ib  = 1000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 500000,
+		.ib  = 1000000,
+	},
+};
+static struct msm_bus_vectors vidc_vdec_vga_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 40894464,
+		.ib  = 327155712,
+	},
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 48234496,
+		.ib  = 192937984,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 500000,
+		.ib  = 2000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 500000,
+		.ib  = 2000000,
+	},
+};
+static struct msm_bus_vectors vidc_venc_720p_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 163577856,
+		.ib  = 1308622848,
+	},
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 219152384,
+		.ib  = 876609536,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 1750000,
+		.ib  = 3500000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 1750000,
+		.ib  = 3500000,
+	},
+};
+static struct msm_bus_vectors vidc_vdec_720p_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 121634816,
+		.ib  = 973078528,
+	},
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 155189248,
+		.ib  = 620756992,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 1750000,
+		.ib  = 7000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 1750000,
+		.ib  = 7000000,
+	},
+};
+static struct msm_bus_vectors vidc_venc_1080p_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 372244480,
+		.ib  = 1861222400,
+	},
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 501219328,
+		.ib  = 2004877312,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 2500000,
+		.ib  = 5000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 2500000,
+		.ib  = 5000000,
+	},
+};
+static struct msm_bus_vectors vidc_vdec_1080p_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 222298112,
+		.ib  = 1778384896,
+	},
+	{
+		.src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 330301440,
+		.ib  = 1321205760,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 2500000,
+		.ib  = 700000000,
+	},
+	{
+		.src = MSM_BUS_MASTER_AMPSS_M0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab  = 2500000,
+		.ib  = 10000000,
+	},
+};
+
+static struct msm_bus_paths vidc_bus_client_config[] = {
+	{
+		ARRAY_SIZE(vidc_init_vectors),
+		vidc_init_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_venc_vga_vectors),
+		vidc_venc_vga_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_vdec_vga_vectors),
+		vidc_vdec_vga_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_venc_720p_vectors),
+		vidc_venc_720p_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_vdec_720p_vectors),
+		vidc_vdec_720p_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_venc_1080p_vectors),
+		vidc_venc_1080p_vectors,
+	},
+	{
+		ARRAY_SIZE(vidc_vdec_1080p_vectors),
+		vidc_vdec_1080p_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata vidc_bus_client_data = {
+	vidc_bus_client_config,
+	ARRAY_SIZE(vidc_bus_client_config),
+	.name = "vidc",
+};
+
+#endif
+
+#define MSM_VIDC_BASE_PHYS 0x04400000
+#define MSM_VIDC_BASE_SIZE 0x00100000
+
+static struct resource msm_device_vidc_resources[] = {
+	{
+		.start	= MSM_VIDC_BASE_PHYS,
+		.end	= MSM_VIDC_BASE_PHYS + MSM_VIDC_BASE_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= VCODEC_IRQ,
+		.end	= VCODEC_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct msm_vidc_platform_data vidc_platform_data = {
+#ifdef CONFIG_MSM_BUS_SCALING
+	.vidc_bus_client_pdata = &vidc_bus_client_data,
+#endif
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	.memtype = ION_CP_MM_HEAP_ID,
+	.enable_ion = 1,
+	.cp_enabled = 0,
+#else
+	.memtype = MEMTYPE_SMI_KERNEL,
+	.enable_ion = 0,
+#endif
+	.disable_dmx = 0,
+	.disable_fullhd = 0,
+	.cont_mode_dpb_count = 8
+};
+
+struct platform_device msm_device_vidc = {
+	.name = "msm_vidc",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(msm_device_vidc_resources),
+	.resource = msm_device_vidc_resources,
+	.dev = {
+		.platform_data	= &vidc_platform_data,
+	},
+};
+
+#if defined(CONFIG_MSM_RPM_LOG) || defined(CONFIG_MSM_RPM_LOG_MODULE)
+static struct msm_rpm_log_platform_data msm_rpm_log_pdata = {
+	.phys_addr_base = 0x00106000,
+	.reg_offsets = {
+		[MSM_RPM_LOG_PAGE_INDICES] = 0x00000C80,
+		[MSM_RPM_LOG_PAGE_BUFFER]  = 0x00000CA0,
+	},
+	.phys_size = SZ_8K,
+	.log_len = 4096,		  /* log's buffer length in bytes */
+	.log_len_mask = (4096 >> 2) - 1,  /* length mask in units of u32 */
+};
+
+struct platform_device msm8660_rpm_log_device = {
+	.name	= "msm_rpm_log",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &msm_rpm_log_pdata,
+	},
+};
+#endif
+
+#if defined(CONFIG_MSM_RPM_STATS_LOG)
+static struct msm_rpmstats_platform_data msm_rpm_stat_pdata = {
+	.phys_addr_base = 0x00107E04,
+	.phys_size = SZ_8K,
+};
+
+struct platform_device msm8660_rpm_stat_device = {
+	.name = "msm_rpm_stat",
+	.id = -1,
+	.dev = {
+		.platform_data = &msm_rpm_stat_pdata,
+	},
+};
+#endif
+
+#define SHARED_IMEM_TZ_BASE 0x2a05f720
+static struct resource tzlog_resources[] = {
+	{
+		.start = SHARED_IMEM_TZ_BASE,
+		.end = SHARED_IMEM_TZ_BASE + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_device_tz_log = {
+	.name		= "tz_log",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(tzlog_resources),
+	.resource	= tzlog_resources,
+};
+
+#ifdef CONFIG_MSM_MPM
+static uint16_t msm_mpm_irqs_m2a[MSM_MPM_NR_MPM_IRQS]  __initdata = {
+	[1] = MSM_GPIO_TO_INT(61),
+	[4] = MSM_GPIO_TO_INT(87),
+	[5] = MSM_GPIO_TO_INT(88),
+	[6] = MSM_GPIO_TO_INT(89),
+	[7] = MSM_GPIO_TO_INT(90),
+	[8] = MSM_GPIO_TO_INT(91),
+	[9] = MSM_GPIO_TO_INT(34),
+	[10] = MSM_GPIO_TO_INT(38),
+	[11] = MSM_GPIO_TO_INT(42),
+	[12] = MSM_GPIO_TO_INT(46),
+	[13] = MSM_GPIO_TO_INT(50),
+	[14] = MSM_GPIO_TO_INT(54),
+	[15] = MSM_GPIO_TO_INT(58),
+	[16] = MSM_GPIO_TO_INT(63),
+	[17] = MSM_GPIO_TO_INT(160),
+	[18] = MSM_GPIO_TO_INT(162),
+	[19] = MSM_GPIO_TO_INT(144),
+	[20] = MSM_GPIO_TO_INT(146),
+	[25] = USB1_HS_IRQ,
+	[26] = TV_ENC_IRQ,
+	[27] = HDMI_IRQ,
+	[29] = MSM_GPIO_TO_INT(123),
+	[30] = MSM_GPIO_TO_INT(172),
+	[31] = MSM_GPIO_TO_INT(99),
+	[32] = MSM_GPIO_TO_INT(96),
+	[33] = MSM_GPIO_TO_INT(67),
+	[34] = MSM_GPIO_TO_INT(71),
+	[35] = MSM_GPIO_TO_INT(105),
+	[36] = MSM_GPIO_TO_INT(117),
+	[37] = MSM_GPIO_TO_INT(29),
+	[38] = MSM_GPIO_TO_INT(30),
+	[39] = MSM_GPIO_TO_INT(31),
+	[40] = MSM_GPIO_TO_INT(37),
+	[41] = MSM_GPIO_TO_INT(40),
+	[42] = MSM_GPIO_TO_INT(41),
+	[43] = MSM_GPIO_TO_INT(45),
+	[44] = MSM_GPIO_TO_INT(51),
+	[45] = MSM_GPIO_TO_INT(52),
+	[46] = MSM_GPIO_TO_INT(57),
+	[47] = MSM_GPIO_TO_INT(73),
+	[48] = MSM_GPIO_TO_INT(93),
+	[49] = MSM_GPIO_TO_INT(94),
+	[50] = MSM_GPIO_TO_INT(103),
+	[51] = MSM_GPIO_TO_INT(104),
+	[52] = MSM_GPIO_TO_INT(106),
+	[53] = MSM_GPIO_TO_INT(115),
+	[54] = MSM_GPIO_TO_INT(124),
+	[55] = MSM_GPIO_TO_INT(125),
+	[56] = MSM_GPIO_TO_INT(126),
+	[57] = MSM_GPIO_TO_INT(127),
+	[58] = MSM_GPIO_TO_INT(128),
+	[59] = MSM_GPIO_TO_INT(129),
+};
+
+static uint16_t msm_mpm_bypassed_apps_irqs[] __initdata = {
+	TLMM_MSM_SUMMARY_IRQ,
+	RPM_SCSS_CPU0_GP_HIGH_IRQ,
+	RPM_SCSS_CPU0_GP_MEDIUM_IRQ,
+	RPM_SCSS_CPU0_GP_LOW_IRQ,
+	RPM_SCSS_CPU0_WAKE_UP_IRQ,
+	RPM_SCSS_CPU1_GP_HIGH_IRQ,
+	RPM_SCSS_CPU1_GP_MEDIUM_IRQ,
+	RPM_SCSS_CPU1_GP_LOW_IRQ,
+	RPM_SCSS_CPU1_WAKE_UP_IRQ,
+	MARM_SCSS_GP_IRQ_0,
+	MARM_SCSS_GP_IRQ_1,
+	MARM_SCSS_GP_IRQ_2,
+	MARM_SCSS_GP_IRQ_3,
+	MARM_SCSS_GP_IRQ_4,
+	MARM_SCSS_GP_IRQ_5,
+	MARM_SCSS_GP_IRQ_6,
+	MARM_SCSS_GP_IRQ_7,
+	MARM_SCSS_GP_IRQ_8,
+	MARM_SCSS_GP_IRQ_9,
+	LPASS_SCSS_GP_LOW_IRQ,
+	LPASS_SCSS_GP_MEDIUM_IRQ,
+	LPASS_SCSS_GP_HIGH_IRQ,
+	SDC4_IRQ_0,
+	SPS_MTI_31,
+};
+
+struct msm_mpm_device_data msm8660_mpm_dev_data __initdata = {
+	.irqs_m2a = msm_mpm_irqs_m2a,
+	.irqs_m2a_size = ARRAY_SIZE(msm_mpm_irqs_m2a),
+	.bypassed_apps_irqs = msm_mpm_bypassed_apps_irqs,
+	.bypassed_apps_irqs_size = ARRAY_SIZE(msm_mpm_bypassed_apps_irqs),
+	.mpm_request_reg_base = MSM_RPM_BASE + 0x9d8,
+	.mpm_status_reg_base = MSM_RPM_BASE + 0xdf8,
+	.mpm_apps_ipc_reg = MSM_GCC_BASE + 0x008,
+	.mpm_apps_ipc_val =  BIT(1),
+	.mpm_ipc_irq = RPM_SCSS_CPU0_GP_MEDIUM_IRQ,
+
+};
+#endif
+
+
+#ifdef CONFIG_MSM_BUS_SCALING
+struct platform_device msm_bus_sys_fabric = {
+	.name  = "msm_bus_fabric",
+	.id    =  MSM_BUS_FAB_SYSTEM,
+};
+struct platform_device msm_bus_apps_fabric = {
+	.name  = "msm_bus_fabric",
+	.id    = MSM_BUS_FAB_APPSS,
+};
+struct platform_device msm_bus_mm_fabric = {
+	.name  = "msm_bus_fabric",
+	.id    = MSM_BUS_FAB_MMSS,
+};
+struct platform_device msm_bus_sys_fpb = {
+	.name  = "msm_bus_fabric",
+	.id    = MSM_BUS_FAB_SYSTEM_FPB,
+};
+struct platform_device msm_bus_cpss_fpb = {
+	.name  = "msm_bus_fabric",
+	.id    = MSM_BUS_FAB_CPSS_FPB,
+};
+#endif
+
+#ifdef CONFIG_SND_SOC_MSM8660_APQ
+struct platform_device msm_pcm = {
+	.name   = "msm-pcm-dsp",
+	.id     = -1,
+};
+
+struct platform_device msm_pcm_routing = {
+	.name   = "msm-pcm-routing",
+	.id     = -1,
+};
+
+struct platform_device msm_cpudai0 = {
+	.name   = "msm-dai-q6",
+	.id     = PRIMARY_I2S_RX,
+};
+
+struct platform_device msm_cpudai1 = {
+	.name   = "msm-dai-q6",
+	.id     = PRIMARY_I2S_TX,
+};
+
+struct platform_device msm_cpudai_hdmi_rx = {
+	.name   = "msm-dai-q6",
+	.id     = HDMI_RX,
+};
+
+struct platform_device msm_cpudai_bt_rx = {
+	.name   = "msm-dai-q6",
+	.id     = INT_BT_SCO_RX,
+};
+
+struct platform_device msm_cpudai_bt_tx = {
+	.name   = "msm-dai-q6",
+	.id     = INT_BT_SCO_TX,
+};
+
+struct platform_device msm_cpudai_fm_rx = {
+	.name   = "msm-dai-q6",
+	.id     = INT_FM_RX,
+};
+
+struct platform_device msm_cpudai_fm_tx = {
+	.name   = "msm-dai-q6",
+	.id     = INT_FM_TX,
+};
+
+struct platform_device msm_cpu_fe = {
+	.name   = "msm-dai-fe",
+	.id     = -1,
+};
+
+struct platform_device msm_stub_codec = {
+	.name   = "msm-stub-codec",
+	.id     = 1,
+};
+
+struct platform_device msm_voice = {
+	.name   = "msm-pcm-voice",
+	.id     = -1,
+};
+
+struct platform_device msm_voip = {
+	.name   = "msm-voip-dsp",
+	.id     = -1,
+};
+
+struct platform_device msm_lpa_pcm = {
+	.name   = "msm-pcm-lpa",
+	.id     = -1,
+};
+
+struct platform_device msm_pcm_hostless = {
+	.name   = "msm-pcm-hostless",
+	.id     = -1,
+};
+#endif
+
+struct platform_device asoc_msm_pcm = {
+	.name   = "msm-dsp-audio",
+	.id     = 0,
+};
+
+struct platform_device asoc_msm_dai0 = {
+	.name   = "msm-codec-dai",
+	.id     = 0,
+};
+
+struct platform_device asoc_msm_dai1 = {
+	.name   = "msm-cpu-dai",
+	.id     = 0,
+};
+
+#if defined (CONFIG_MSM_8x60_VOIP)
+struct platform_device asoc_msm_mvs = {
+	.name   = "msm-mvs-audio",
+	.id     = 0,
+};
+
+struct platform_device asoc_mvs_dai0 = {
+	.name   = "mvs-codec-dai",
+	.id     = 0,
+};
+
+struct platform_device asoc_mvs_dai1 = {
+	.name   = "mvs-cpu-dai",
+	.id     = 0,
+};
+#endif
+
+static struct fs_driver_data gfx2d0_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_GRAPHICS_2D_CORE0,
+};
+
+static struct fs_driver_data gfx2d1_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_GRAPHICS_2D_CORE1,
+};
+
+static struct fs_driver_data gfx3d_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk", .reset_rate = 27000000 },
+		{ .name = "iface_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_GRAPHICS_3D,
+};
+
+static struct fs_driver_data ijpeg_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_JPEG_ENC,
+};
+
+static struct fs_driver_data mdp_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ .name = "vsync_clk" },
+		{ .name = "tv_src_clk" },
+		{ .name = "tv_clk" },
+		{ .name = "pixel_mdp_clk" },
+		{ .name = "pixel_lcdc_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_MDP_PORT0,
+	.bus_port1 = MSM_BUS_MASTER_MDP_PORT1,
+};
+
+static struct fs_driver_data rot_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_ROTATOR,
+};
+
+static struct fs_driver_data ved_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_HD_CODEC_PORT0,
+	.bus_port1 = MSM_BUS_MASTER_HD_CODEC_PORT1,
+};
+
+static struct fs_driver_data vfe_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_VFE,
+};
+
+static struct fs_driver_data vpe_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_VPE,
+};
+
+struct platform_device *msm8660_footswitch[] __initdata = {
+	FS_8X60(FS_IJPEG,  "vdd",	"msm_gemini.0",	&ijpeg_fs_data),
+	FS_8X60(FS_MDP,    "vdd",	"mdp.0",	&mdp_fs_data),
+	FS_8X60(FS_ROT,    "vdd",	"msm_rotator.0", &rot_fs_data),
+	FS_8X60(FS_VED,    "vdd",	"msm_vidc.0",	&ved_fs_data),
+	FS_8X60(FS_VFE,    "fs_vfe",	NULL,	&vfe_fs_data),
+	FS_8X60(FS_VPE,    "fs_vpe",	NULL,	&vpe_fs_data),
+	FS_8X60(FS_GFX3D,  "vdd",	"kgsl-3d0.0",	&gfx3d_fs_data),
+	FS_8X60(FS_GFX2D0, "vdd",	"kgsl-2d0.0",	&gfx2d0_fs_data),
+	FS_8X60(FS_GFX2D1, "vdd",	"kgsl-2d1.1",	&gfx2d1_fs_data),
+};
+unsigned msm8660_num_footswitch __initdata = ARRAY_SIZE(msm8660_footswitch);
+
+struct msm_rpm_platform_data msm8660_rpm_data __initdata = {
+	.reg_base_addrs = {
+		[MSM_RPM_PAGE_STATUS] = MSM_RPM_BASE,
+		[MSM_RPM_PAGE_CTRL] = MSM_RPM_BASE + 0x400,
+		[MSM_RPM_PAGE_REQ] = MSM_RPM_BASE + 0x600,
+		[MSM_RPM_PAGE_ACK] = MSM_RPM_BASE + 0xa00,
+	},
+	.irq_ack = RPM_SCSS_CPU0_GP_HIGH_IRQ,
+	.irq_err = RPM_SCSS_CPU0_GP_LOW_IRQ,
+	.irq_wakeup = RPM_SCSS_CPU0_WAKE_UP_IRQ,
+	.ipc_rpm_reg = MSM_GCC_BASE + 0x008,
+	.ipc_rpm_val = 4,
+	.target_id = {
+		MSM_RPM_MAP(8660, NOTIFICATION_CONFIGURED_0, NOTIFICATION, 8),
+		MSM_RPM_MAP(8660, NOTIFICATION_REGISTERED_0, NOTIFICATION, 8),
+		MSM_RPM_MAP(8660, INVALIDATE_0, INVALIDATE, 8),
+		MSM_RPM_MAP(8660, TRIGGER_TIMED_TO, TRIGGER_TIMED, 1),
+		MSM_RPM_MAP(8660, TRIGGER_TIMED_SCLK_COUNT, TRIGGER_TIMED, 1),
+		MSM_RPM_MAP(8660, TRIGGER_SET_FROM, TRIGGER_SET, 1),
+		MSM_RPM_MAP(8660, TRIGGER_SET_TO, TRIGGER_SET, 1),
+		MSM_RPM_MAP(8660, TRIGGER_SET_TRIGGER, TRIGGER_SET, 1),
+		MSM_RPM_MAP(8660, TRIGGER_CLEAR_FROM, TRIGGER_CLEAR, 1),
+		MSM_RPM_MAP(8660, TRIGGER_CLEAR_TO, TRIGGER_CLEAR, 1),
+		MSM_RPM_MAP(8660, TRIGGER_CLEAR_TRIGGER, TRIGGER_CLEAR, 1),
+
+		MSM_RPM_MAP(8660, CXO_CLK, CXO_CLK, 1),
+		MSM_RPM_MAP(8660, PXO_CLK, PXO_CLK, 1),
+		MSM_RPM_MAP(8660, PLL_4, PLL_4, 1),
+		MSM_RPM_MAP(8660, APPS_FABRIC_CLK, APPS_FABRIC_CLK, 1),
+		MSM_RPM_MAP(8660, SYSTEM_FABRIC_CLK, SYSTEM_FABRIC_CLK, 1),
+		MSM_RPM_MAP(8660, MM_FABRIC_CLK, MM_FABRIC_CLK, 1),
+		MSM_RPM_MAP(8660, DAYTONA_FABRIC_CLK, DAYTONA_FABRIC_CLK, 1),
+		MSM_RPM_MAP(8660, SFPB_CLK, SFPB_CLK, 1),
+		MSM_RPM_MAP(8660, CFPB_CLK, CFPB_CLK, 1),
+		MSM_RPM_MAP(8660, MMFPB_CLK, MMFPB_CLK, 1),
+		MSM_RPM_MAP(8660, SMI_CLK, SMI_CLK, 1),
+		MSM_RPM_MAP(8660, EBI1_CLK, EBI1_CLK, 1),
+
+		MSM_RPM_MAP(8660, APPS_L2_CACHE_CTL, APPS_L2_CACHE_CTL, 1),
+
+		MSM_RPM_MAP(8660, APPS_FABRIC_HALT_0, APPS_FABRIC_HALT, 2),
+		MSM_RPM_MAP(8660, APPS_FABRIC_CLOCK_MODE_0,
+				APPS_FABRIC_CLOCK_MODE, 3),
+		MSM_RPM_MAP(8660, APPS_FABRIC_ARB_0, APPS_FABRIC_ARB, 6),
+
+		MSM_RPM_MAP(8660, SYSTEM_FABRIC_HALT_0, SYSTEM_FABRIC_HALT, 2),
+		MSM_RPM_MAP(8660, SYSTEM_FABRIC_CLOCK_MODE_0,
+				SYSTEM_FABRIC_CLOCK_MODE, 3),
+		MSM_RPM_MAP(8660, SYSTEM_FABRIC_ARB_0, SYSTEM_FABRIC_ARB, 22),
+
+		MSM_RPM_MAP(8660, MM_FABRIC_HALT_0, MM_FABRIC_HALT, 2),
+		MSM_RPM_MAP(8660, MM_FABRIC_CLOCK_MODE_0,
+				MM_FABRIC_CLOCK_MODE, 3),
+		MSM_RPM_MAP(8660, MM_FABRIC_ARB_0, MM_FABRIC_ARB, 23),
+
+		MSM_RPM_MAP(8660, SMPS0B_0, SMPS0B, 2),
+		MSM_RPM_MAP(8660, SMPS1B_0, SMPS1B, 2),
+		MSM_RPM_MAP(8660, SMPS2B_0, SMPS2B, 2),
+		MSM_RPM_MAP(8660, SMPS3B_0, SMPS3B, 2),
+		MSM_RPM_MAP(8660, SMPS4B_0, SMPS4B, 2),
+		MSM_RPM_MAP(8660, LDO0B_0, LDO0B, 2),
+		MSM_RPM_MAP(8660, LDO1B_0, LDO1B, 2),
+		MSM_RPM_MAP(8660, LDO2B_0, LDO2B, 2),
+		MSM_RPM_MAP(8660, LDO3B_0, LDO3B, 2),
+		MSM_RPM_MAP(8660, LDO4B_0, LDO4B, 2),
+		MSM_RPM_MAP(8660, LDO5B_0, LDO5B, 2),
+		MSM_RPM_MAP(8660, LDO6B_0, LDO6B, 2),
+		MSM_RPM_MAP(8660, LVS0B, LVS0B, 1),
+		MSM_RPM_MAP(8660, LVS1B, LVS1B, 1),
+		MSM_RPM_MAP(8660, LVS2B, LVS2B, 1),
+		MSM_RPM_MAP(8660, LVS3B, LVS3B, 1),
+		MSM_RPM_MAP(8660, MVS, MVS, 1),
+
+		MSM_RPM_MAP(8660, SMPS0_0, SMPS0, 2),
+		MSM_RPM_MAP(8660, SMPS1_0, SMPS1, 2),
+		MSM_RPM_MAP(8660, SMPS2_0, SMPS2, 2),
+		MSM_RPM_MAP(8660, SMPS3_0, SMPS3, 2),
+		MSM_RPM_MAP(8660, SMPS4_0, SMPS4, 2),
+		MSM_RPM_MAP(8660, LDO0_0, LDO0, 2),
+		MSM_RPM_MAP(8660, LDO1_0, LDO1, 2),
+		MSM_RPM_MAP(8660, LDO2_0, LDO2, 2),
+		MSM_RPM_MAP(8660, LDO3_0, LDO3, 2),
+		MSM_RPM_MAP(8660, LDO4_0, LDO4, 2),
+		MSM_RPM_MAP(8660, LDO5_0, LDO5, 2),
+		MSM_RPM_MAP(8660, LDO6_0, LDO6, 2),
+		MSM_RPM_MAP(8660, LDO7_0, LDO7, 2),
+		MSM_RPM_MAP(8660, LDO8_0, LDO8, 2),
+		MSM_RPM_MAP(8660, LDO9_0, LDO9, 2),
+		MSM_RPM_MAP(8660, LDO10_0, LDO10, 2),
+		MSM_RPM_MAP(8660, LDO11_0, LDO11, 2),
+		MSM_RPM_MAP(8660, LDO12_0, LDO12, 2),
+		MSM_RPM_MAP(8660, LDO13_0, LDO13, 2),
+		MSM_RPM_MAP(8660, LDO14_0, LDO14, 2),
+		MSM_RPM_MAP(8660, LDO15_0, LDO15, 2),
+		MSM_RPM_MAP(8660, LDO16_0, LDO16, 2),
+		MSM_RPM_MAP(8660, LDO17_0, LDO17, 2),
+		MSM_RPM_MAP(8660, LDO18_0, LDO18, 2),
+		MSM_RPM_MAP(8660, LDO19_0, LDO19, 2),
+		MSM_RPM_MAP(8660, LDO20_0, LDO20, 2),
+		MSM_RPM_MAP(8660, LDO21_0, LDO21, 2),
+		MSM_RPM_MAP(8660, LDO22_0, LDO22, 2),
+		MSM_RPM_MAP(8660, LDO23_0, LDO23, 2),
+		MSM_RPM_MAP(8660, LDO24_0, LDO24, 2),
+		MSM_RPM_MAP(8660, LDO25_0, LDO25, 2),
+		MSM_RPM_MAP(8660, LVS0, LVS0, 1),
+		MSM_RPM_MAP(8660, LVS1, LVS1, 1),
+		MSM_RPM_MAP(8660, NCP_0, NCP, 2),
+		MSM_RPM_MAP(8660, CXO_BUFFERS, CXO_BUFFERS, 1),
+	},
+	.target_status = {
+		MSM_RPM_STATUS_ID_MAP(8660, VERSION_MAJOR),
+		MSM_RPM_STATUS_ID_MAP(8660, VERSION_MINOR),
+		MSM_RPM_STATUS_ID_MAP(8660, VERSION_BUILD),
+		MSM_RPM_STATUS_ID_MAP(8660, SUPPORTED_RESOURCES_0),
+		MSM_RPM_STATUS_ID_MAP(8660, SUPPORTED_RESOURCES_1),
+		MSM_RPM_STATUS_ID_MAP(8660, SUPPORTED_RESOURCES_2),
+		MSM_RPM_STATUS_ID_MAP(8660, SEQUENCE),
+
+		MSM_RPM_STATUS_ID_MAP(8660, CXO_CLK),
+		MSM_RPM_STATUS_ID_MAP(8660, PXO_CLK),
+		MSM_RPM_STATUS_ID_MAP(8660, PLL_4),
+		MSM_RPM_STATUS_ID_MAP(8660, APPS_FABRIC_CLK),
+		MSM_RPM_STATUS_ID_MAP(8660, SYSTEM_FABRIC_CLK),
+		MSM_RPM_STATUS_ID_MAP(8660, MM_FABRIC_CLK),
+		MSM_RPM_STATUS_ID_MAP(8660, DAYTONA_FABRIC_CLK),
+		MSM_RPM_STATUS_ID_MAP(8660, SFPB_CLK),
+		MSM_RPM_STATUS_ID_MAP(8660, CFPB_CLK),
+		MSM_RPM_STATUS_ID_MAP(8660, MMFPB_CLK),
+		MSM_RPM_STATUS_ID_MAP(8660, SMI_CLK),
+		MSM_RPM_STATUS_ID_MAP(8660, EBI1_CLK),
+
+		MSM_RPM_STATUS_ID_MAP(8660, APPS_L2_CACHE_CTL),
+
+		MSM_RPM_STATUS_ID_MAP(8660, APPS_FABRIC_HALT),
+		MSM_RPM_STATUS_ID_MAP(8660, APPS_FABRIC_CLOCK_MODE),
+		MSM_RPM_STATUS_ID_MAP(8660, APPS_FABRIC_ARB),
+
+		MSM_RPM_STATUS_ID_MAP(8660, SYSTEM_FABRIC_HALT),
+		MSM_RPM_STATUS_ID_MAP(8660, SYSTEM_FABRIC_CLOCK_MODE),
+		MSM_RPM_STATUS_ID_MAP(8660, SYSTEM_FABRIC_ARB),
+
+		MSM_RPM_STATUS_ID_MAP(8660, MM_FABRIC_HALT),
+		MSM_RPM_STATUS_ID_MAP(8660, MM_FABRIC_CLOCK_MODE),
+		MSM_RPM_STATUS_ID_MAP(8660, MM_FABRIC_ARB),
+
+
+		MSM_RPM_STATUS_ID_MAP(8660, SMPS0B_0),
+		MSM_RPM_STATUS_ID_MAP(8660, SMPS0B_1),
+		MSM_RPM_STATUS_ID_MAP(8660, SMPS1B_0),
+		MSM_RPM_STATUS_ID_MAP(8660, SMPS1B_1),
+		MSM_RPM_STATUS_ID_MAP(8660, SMPS2B_0),
+		MSM_RPM_STATUS_ID_MAP(8660, SMPS2B_1),
+		MSM_RPM_STATUS_ID_MAP(8660, SMPS3B_0),
+		MSM_RPM_STATUS_ID_MAP(8660, SMPS3B_1),
+		MSM_RPM_STATUS_ID_MAP(8660, SMPS4B_0),
+		MSM_RPM_STATUS_ID_MAP(8660, SMPS4B_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO0B_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO0B_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO1B_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO1B_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO2B_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO2B_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO3B_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO3B_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO4B_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO4B_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO5B_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO5B_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO6B_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO6B_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LVS0B),
+		MSM_RPM_STATUS_ID_MAP(8660, LVS1B),
+		MSM_RPM_STATUS_ID_MAP(8660, LVS2B),
+		MSM_RPM_STATUS_ID_MAP(8660, LVS3B),
+		MSM_RPM_STATUS_ID_MAP(8660, MVS),
+
+
+		MSM_RPM_STATUS_ID_MAP(8660, SMPS0_0),
+		MSM_RPM_STATUS_ID_MAP(8660, SMPS0_1),
+		MSM_RPM_STATUS_ID_MAP(8660, SMPS1_0),
+		MSM_RPM_STATUS_ID_MAP(8660, SMPS1_1),
+		MSM_RPM_STATUS_ID_MAP(8660, SMPS2_0),
+		MSM_RPM_STATUS_ID_MAP(8660, SMPS2_1),
+		MSM_RPM_STATUS_ID_MAP(8660, SMPS3_0),
+		MSM_RPM_STATUS_ID_MAP(8660, SMPS3_1),
+		MSM_RPM_STATUS_ID_MAP(8660, SMPS4_0),
+		MSM_RPM_STATUS_ID_MAP(8660, SMPS4_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO0_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO0_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO1_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO1_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO2_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO2_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO3_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO3_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO4_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO4_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO5_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO5_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO6_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO6_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO7_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO7_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO8_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO8_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO9_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO9_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO10_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO10_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO11_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO11_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO12_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO12_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO13_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO13_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO14_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO14_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO15_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO15_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO16_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO16_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO17_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO17_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO18_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO18_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO19_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO19_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO20_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO20_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO21_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO21_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO22_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO22_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO23_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO23_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO24_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO24_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO25_0),
+		MSM_RPM_STATUS_ID_MAP(8660, LDO25_1),
+		MSM_RPM_STATUS_ID_MAP(8660, LVS0),
+		MSM_RPM_STATUS_ID_MAP(8660, LVS1),
+		MSM_RPM_STATUS_ID_MAP(8660, NCP_0),
+		MSM_RPM_STATUS_ID_MAP(8660, NCP_1),
+		MSM_RPM_STATUS_ID_MAP(8660, CXO_BUFFERS),
+	},
+	.target_ctrl_id = {
+		MSM_RPM_CTRL_MAP(8660, VERSION_MAJOR),
+		MSM_RPM_CTRL_MAP(8660, VERSION_MINOR),
+		MSM_RPM_CTRL_MAP(8660, VERSION_BUILD),
+		MSM_RPM_CTRL_MAP(8660, REQ_CTX_0),
+		MSM_RPM_CTRL_MAP(8660, REQ_SEL_0),
+		MSM_RPM_CTRL_MAP(8660, ACK_CTX_0),
+		MSM_RPM_CTRL_MAP(8660, ACK_SEL_0),
+	},
+	.sel_invalidate = MSM_RPM_8660_SEL_INVALIDATE,
+	.sel_notification = MSM_RPM_8660_SEL_NOTIFICATION,
+	.sel_last = MSM_RPM_8660_SEL_LAST,
+	.ver = {2, 0, 0},
+};
+
+struct platform_device msm8660_rpm_device = {
+	.name = "msm_rpm",
+	.id = -1,
+};
diff --git a/arch/arm/mach-msm/devices-msm8x60.h b/arch/arm/mach-msm/devices-msm8x60.h
new file mode 100644
index 0000000..9bfaeee
--- /dev/null
+++ b/arch/arm/mach-msm/devices-msm8x60.h
@@ -0,0 +1,77 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __ARCH_ARM_MACH_MSM_DEVICES_MSM8X60_H
+#define __ARCH_ARM_MACH_MSM_DEVICES_MSM8X60_H
+
+#define MSM_GSBI3_QUP_I2C_BUS_ID 0
+#define MSM_GSBI4_QUP_I2C_BUS_ID 1
+#define MSM_GSBI9_QUP_I2C_BUS_ID 2
+#define MSM_GSBI8_QUP_I2C_BUS_ID 3
+#define MSM_GSBI7_QUP_I2C_BUS_ID 4
+#define MSM_GSBI12_QUP_I2C_BUS_ID 5
+#define MSM_SSBI1_I2C_BUS_ID     6
+#define MSM_SSBI2_I2C_BUS_ID     7
+#define MSM_SSBI3_I2C_BUS_ID     8
+
+#ifdef CONFIG_SND_SOC_MSM8660_APQ
+extern struct platform_device msm_pcm;
+extern struct platform_device msm_pcm_routing;
+extern struct platform_device msm_cpudai0;
+extern struct platform_device msm_cpudai1;
+extern struct platform_device msm_cpudai_hdmi_rx;
+extern struct platform_device msm_cpudai_bt_rx;
+extern struct platform_device msm_cpudai_bt_tx;
+extern struct platform_device msm_cpudai_fm_rx;
+extern struct platform_device msm_cpudai_fm_tx;
+extern struct platform_device msm_cpu_fe;
+extern struct platform_device msm_stub_codec;
+extern struct platform_device msm_voice;
+extern struct platform_device msm_voip;
+extern struct platform_device msm_lpa_pcm;
+extern struct platform_device msm_pcm_hostless;
+#endif
+
+#ifdef CONFIG_SPI_QUP
+extern struct platform_device msm_gsbi1_qup_spi_device;
+extern struct platform_device msm_gsbi10_qup_spi_device;
+#endif
+
+extern struct platform_device msm_bus_apps_fabric;
+extern struct platform_device msm_bus_sys_fabric;
+extern struct platform_device msm_bus_mm_fabric;
+extern struct platform_device msm_bus_sys_fpb;
+extern struct platform_device msm_bus_cpss_fpb;
+extern struct platform_device msm_bus_def_fab;
+
+extern struct platform_device msm_device_smd;
+extern struct platform_device msm_device_gpio;
+extern struct platform_device msm_device_vidc;
+extern struct platform_device apq8064_msm_device_vidc;
+
+extern struct platform_device msm_charm_modem;
+extern struct platform_device msm_device_tz_log;
+#ifdef CONFIG_HW_RANDOM_MSM
+extern struct platform_device msm_device_rng;
+#endif
+
+void __init msm8x60_init_irq(void);
+void __init msm8x60_check_2d_hardware(void);
+
+#ifdef CONFIG_MSM_DSPS
+extern struct platform_device msm_dsps_device;
+#endif
+
+#if defined(CONFIG_MSM_RPM_STATS_LOG)
+extern struct platform_device msm_rpm_stat_device;
+#endif
+#endif
diff --git a/arch/arm/mach-msm/devices-qsd8x50.c b/arch/arm/mach-msm/devices-qsd8x50.c
index 131633b..ee8a2cf 100644
--- a/arch/arm/mach-msm/devices-qsd8x50.c
+++ b/arch/arm/mach-msm/devices-qsd8x50.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. 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
@@ -15,9 +15,10 @@
 
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
-#include <linux/clkdev.h>
-#include <linux/dma-mapping.h>
+#include <linux/msm_kgsl.h>
 
+#include <linux/dma-mapping.h>
+#include <asm/clkdev.h>
 #include <mach/irqs.h>
 #include <mach/msm_iomap.h>
 #include <mach/dma.h>
@@ -27,8 +28,37 @@
 
 #include <asm/mach/flash.h>
 
-#include <mach/mmc.h>
-#include "clock-pcom.h"
+#include <asm/mach/mmc.h>
+#include <mach/msm_hsusb.h>
+#include <mach/usbdiag.h>
+#include <mach/rpc_hsusb.h>
+#include "pm.h"
+
+static struct resource resources_uart1[] = {
+	{
+		.start	= INT_UART1,
+		.end	= INT_UART1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM_UART1_PHYS,
+		.end	= MSM_UART1_PHYS + MSM_UART1_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct resource resources_uart2[] = {
+	{
+		.start	= INT_UART2,
+		.end	= INT_UART2,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= MSM_UART2_PHYS,
+		.end	= MSM_UART2_PHYS + MSM_UART2_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
 
 static struct resource resources_uart3[] = {
 	{
@@ -44,6 +74,20 @@
 	},
 };
 
+struct platform_device msm_device_uart1 = {
+	.name	= "msm_serial",
+	.id	= 0,
+	.num_resources	= ARRAY_SIZE(resources_uart1),
+	.resource	= resources_uart1,
+};
+
+struct platform_device msm_device_uart2 = {
+	.name	= "msm_serial",
+	.id	= 1,
+	.num_resources	= ARRAY_SIZE(resources_uart2),
+	.resource	= resources_uart2,
+};
+
 struct platform_device msm_device_uart3 = {
 	.name	= "msm_serial",
 	.id	= 2,
@@ -51,15 +95,309 @@
 	.resource	= resources_uart3,
 };
 
-struct platform_device msm_device_smd = {
-	.name   = "msm_smd",
-	.id     = -1,
+#define MSM_UART1DM_PHYS      0xA0200000
+#define MSM_UART2DM_PHYS      0xA0900000
+static struct resource msm_uart1_dm_resources[] = {
+	{
+		.start = MSM_UART1DM_PHYS,
+		.end   = MSM_UART1DM_PHYS + PAGE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = INT_UART1DM_IRQ,
+		.end   = INT_UART1DM_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = INT_UART1DM_RX,
+		.end   = INT_UART1DM_RX,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = DMOV_HSUART1_TX_CHAN,
+		.end   = DMOV_HSUART1_RX_CHAN,
+		.name  = "uartdm_channels",
+		.flags = IORESOURCE_DMA,
+	},
+	{
+		.start = DMOV_HSUART1_TX_CRCI,
+		.end   = DMOV_HSUART1_RX_CRCI,
+		.name  = "uartdm_crci",
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static u64 msm_uart_dm1_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device msm_device_uart_dm1 = {
+	.name = "msm_serial_hs",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(msm_uart1_dm_resources),
+	.resource = msm_uart1_dm_resources,
+	.dev		= {
+		.dma_mask = &msm_uart_dm1_dma_mask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
+
+static struct resource msm_uart2_dm_resources[] = {
+	{
+		.start = MSM_UART2DM_PHYS,
+		.end   = MSM_UART2DM_PHYS + PAGE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = INT_UART2DM_IRQ,
+		.end   = INT_UART2DM_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = INT_UART2DM_RX,
+		.end   = INT_UART2DM_RX,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = DMOV_HSUART2_TX_CHAN,
+		.end   = DMOV_HSUART2_RX_CHAN,
+		.name  = "uartdm_channels",
+		.flags = IORESOURCE_DMA,
+	},
+	{
+		.start = DMOV_HSUART2_TX_CRCI,
+		.end   = DMOV_HSUART2_RX_CRCI,
+		.name  = "uartdm_crci",
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static u64 msm_uart_dm2_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device msm_device_uart_dm2 = {
+	.name = "msm_serial_hs",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(msm_uart2_dm_resources),
+	.resource = msm_uart2_dm_resources,
+	.dev		= {
+		.dma_mask = &msm_uart_dm2_dma_mask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
+
+#define MSM_I2C_SIZE          SZ_4K
+#define MSM_I2C_PHYS          0xA9900000
+
+static struct resource resources_i2c[] = {
+	{
+		.start	= MSM_I2C_PHYS,
+		.end	= MSM_I2C_PHYS + MSM_I2C_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_PWB_I2C,
+		.end	= INT_PWB_I2C,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_i2c = {
+	.name		= "msm_i2c",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(resources_i2c),
+	.resource	= resources_i2c,
+};
+
+#define MSM_HSUSB_PHYS        0xA0800000
+static struct resource resources_hsusb_otg[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_USB_HS,
+		.end	= INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static u64 dma_mask = 0xffffffffULL;
+struct platform_device msm_device_hsusb_otg = {
+	.name		= "msm_hsusb_otg",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_hsusb_otg),
+	.resource	= resources_hsusb_otg,
+	.dev		= {
+		.dma_mask 		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+static struct resource resources_hsusb_peripheral[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_USB_HS,
+		.end	= INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct resource resources_gadget_peripheral[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_USB_HS,
+		.end	= INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_hsusb_peripheral = {
+	.name		= "msm_hsusb_peripheral",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_hsusb_peripheral),
+	.resource	= resources_hsusb_peripheral,
+	.dev		= {
+		.dma_mask 		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+struct platform_device msm_device_gadget_peripheral = {
+	.name		= "msm_hsusb",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_gadget_peripheral),
+	.resource	= resources_gadget_peripheral,
+	.dev		= {
+		.dma_mask 		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+#ifdef CONFIG_USB_FS_HOST
+#define MSM_HS2USB_PHYS        0xA0800400
+static struct resource resources_hsusb_host2[] = {
+	{
+		.start	= MSM_HS2USB_PHYS,
+		.end	= MSM_HS2USB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_USB_OTG,
+		.end	= INT_USB_OTG,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_hsusb_host2 = {
+	.name		= "msm_hsusb_host",
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(resources_hsusb_host2),
+	.resource	= resources_hsusb_host2,
+	.dev		= {
+		.dma_mask 		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+#endif
+
+static struct resource resources_hsusb_host[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_USB_HS,
+		.end	= INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_hsusb_host = {
+	.name		= "msm_hsusb_host",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(resources_hsusb_host),
+	.resource	= resources_hsusb_host,
+	.dev		= {
+		.dma_mask 		= &dma_mask,
+		.coherent_dma_mask	= 0xffffffffULL,
+	},
+};
+
+static struct platform_device *msm_host_devices[] = {
+	&msm_device_hsusb_host,
+#ifdef CONFIG_USB_FS_HOST
+	&msm_device_hsusb_host2,
+#endif
+};
+
+int msm_add_host(unsigned int host, struct msm_usb_host_platform_data *plat)
+{
+	struct platform_device	*pdev;
+
+	pdev = msm_host_devices[host];
+	if (!pdev)
+		return -ENODEV;
+	pdev->dev.platform_data = plat;
+	return platform_device_register(pdev);
+}
+
+#ifdef CONFIG_USB_ANDROID
+struct usb_diag_platform_data usb_diag_pdata = {
+	.ch_name = DIAG_LEGACY,
+	.update_pid_and_serial_num = usb_diag_update_pid_and_serial_num,
+};
+
+struct platform_device usb_diag_device = {
+	.name	= "usb_diag",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &usb_diag_pdata,
+	},
+};
+#endif
+
+#ifdef CONFIG_USB_F_SERIAL
+static struct usb_gadget_fserial_platform_data fserial_pdata = {
+	.no_ports	= 2,
+};
+
+struct platform_device usb_gadget_fserial_device = {
+	.name	= "usb_fserial",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &fserial_pdata,
+	},
+};
+#endif
+
+#define MSM_NAND_PHYS		0xA0A00000
+static struct resource resources_nand[] = {
+	[0] = {
+		.name   = "msm_nand_dmac",
+		.start	= DMOV_NAND_CHAN,
+		.end	= DMOV_NAND_CHAN,
+		.flags	= IORESOURCE_DMA,
+	},
+	[1] = {
+		.name   = "msm_nand_phys",
+		.start  = MSM_NAND_PHYS,
+		.end    = MSM_NAND_PHYS + 0x7FF,
+		.flags  = IORESOURCE_MEM,
+	},
 };
 
 static struct resource resources_otg[] = {
 	{
 		.start	= MSM_HSUSB_PHYS,
-		.end	= MSM_HSUSB_PHYS + MSM_HSUSB_SIZE,
+		.end	= MSM_HSUSB_PHYS + SZ_1K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
@@ -75,146 +413,172 @@
 	.num_resources	= ARRAY_SIZE(resources_otg),
 	.resource	= resources_otg,
 	.dev		= {
-		.coherent_dma_mask	= 0xffffffff,
+		.coherent_dma_mask	= 0xffffffffULL,
 	},
 };
 
-static struct resource resources_hsusb[] = {
-	{
-		.start	= MSM_HSUSB_PHYS,
-		.end	= MSM_HSUSB_PHYS + MSM_HSUSB_SIZE,
-		.flags	= IORESOURCE_MEM,
-	},
-	{
-		.start	= INT_USB_HS,
-		.end	= INT_USB_HS,
-		.flags	= IORESOURCE_IRQ,
-	},
+struct flash_platform_data msm_nand_data = {
+	.parts		= NULL,
+	.nr_parts	= 0,
 };
 
-struct platform_device msm_device_hsusb = {
-	.name		= "msm_hsusb",
+struct platform_device msm_device_nand = {
+	.name		= "msm_nand",
 	.id		= -1,
-	.num_resources	= ARRAY_SIZE(resources_hsusb),
-	.resource	= resources_hsusb,
+	.num_resources	= ARRAY_SIZE(resources_nand),
+	.resource	= resources_nand,
 	.dev		= {
-		.coherent_dma_mask	= 0xffffffff,
+		.platform_data	= &msm_nand_data,
 	},
 };
 
-static u64 dma_mask = 0xffffffffULL;
-static struct resource resources_hsusb_host[] = {
+static struct msm_pm_irq_calls qsd8x50_pm_irq_calls = {
+	.irq_pending = msm_irq_pending,
+	.idle_sleep_allowed = msm_irq_idle_sleep_allowed,
+	.enter_sleep1 = msm_irq_enter_sleep1,
+	.enter_sleep2 = msm_irq_enter_sleep2,
+	.exit_sleep1 = msm_irq_exit_sleep1,
+	.exit_sleep2 = msm_irq_exit_sleep2,
+	.exit_sleep3 = msm_irq_exit_sleep3,
+};
+
+void __init msm_pm_register_irqs(void)
+{
+	msm_pm_set_irq_extns(&qsd8x50_pm_irq_calls);
+}
+
+struct platform_device msm_device_smd = {
+	.name	= "msm_smd",
+	.id	= -1,
+};
+
+static struct resource msm_dmov_resource[] = {
 	{
-		.start	= MSM_HSUSB_PHYS,
-		.end	= MSM_HSUSB_PHYS + MSM_HSUSB_SIZE,
-		.flags	= IORESOURCE_MEM,
+		.start = INT_ADM_AARM,
+		.flags = IORESOURCE_IRQ,
 	},
 	{
-		.start	= INT_USB_HS,
-		.end	= INT_USB_HS,
-		.flags	= IORESOURCE_IRQ,
+		.start = 0xA9700000,
+		.end = 0xA9700000 + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
 	},
 };
 
-struct platform_device msm_device_hsusb_host = {
-	.name		= "msm_hsusb_host",
-	.id		= -1,
-	.num_resources	= ARRAY_SIZE(resources_hsusb_host),
-	.resource	= resources_hsusb_host,
-	.dev		= {
-		.dma_mask               = &dma_mask,
-		.coherent_dma_mask      = 0xffffffffULL,
+static struct msm_dmov_pdata msm_dmov_pdata = {
+	.sd = 3,
+	.sd_size = 0x400,
+};
+
+struct platform_device msm_device_dmov = {
+	.name	= "msm_dmov",
+	.id	= -1,
+	.resource = msm_dmov_resource,
+	.num_resources = ARRAY_SIZE(msm_dmov_resource),
+	.dev = {
+		.platform_data = &msm_dmov_pdata,
 	},
 };
 
+#define MSM_SDC1_BASE         0xA0300000
+#define MSM_SDC2_BASE         0xA0400000
+#define MSM_SDC3_BASE         0xA0500000
+#define MSM_SDC4_BASE         0xA0600000
 static struct resource resources_sdc1[] = {
 	{
-		.start	= MSM_SDC1_PHYS,
-		.end	= MSM_SDC1_PHYS + MSM_SDC1_SIZE - 1,
+		.start	= MSM_SDC1_BASE,
+		.end	= MSM_SDC1_BASE + SZ_4K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
 		.start	= INT_SDC1_0,
-		.end	= INT_SDC1_0,
+		.end	= INT_SDC1_1,
 		.flags	= IORESOURCE_IRQ,
-		.name	= "cmd_irq",
 	},
 	{
-		.flags	= IORESOURCE_IRQ | IORESOURCE_DISABLED,
-		.name	= "status_irq"
-	},
-	{
-		.start	= 8,
-		.end	= 8,
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC1_CHAN,
+		.end	= DMOV_SDC1_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC1_CRCI,
+		.end	= DMOV_SDC1_CRCI,
+		.flags	= IORESOURCE_DMA,
+	}
 };
 
 static struct resource resources_sdc2[] = {
 	{
-		.start	= MSM_SDC2_PHYS,
-		.end	= MSM_SDC2_PHYS + MSM_SDC2_SIZE - 1,
+		.start	= MSM_SDC2_BASE,
+		.end	= MSM_SDC2_BASE + SZ_4K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
 		.start	= INT_SDC2_0,
-		.end	= INT_SDC2_0,
+		.end	= INT_SDC2_1,
 		.flags	= IORESOURCE_IRQ,
-		.name	= "cmd_irq",
 	},
 	{
-		.flags	= IORESOURCE_IRQ | IORESOURCE_DISABLED,
-		.name	= "status_irq"
-	},
-	{
-		.start	= 8,
-		.end	= 8,
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC2_CHAN,
+		.end	= DMOV_SDC2_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
+	{
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC2_CRCI,
+		.end	= DMOV_SDC2_CRCI,
+		.flags	= IORESOURCE_DMA,
+	}
 };
 
 static struct resource resources_sdc3[] = {
 	{
-		.start	= MSM_SDC3_PHYS,
-		.end	= MSM_SDC3_PHYS + MSM_SDC3_SIZE - 1,
+		.start	= MSM_SDC3_BASE,
+		.end	= MSM_SDC3_BASE + SZ_4K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
 		.start	= INT_SDC3_0,
-		.end	= INT_SDC3_0,
+		.end	= INT_SDC3_1,
 		.flags	= IORESOURCE_IRQ,
-		.name	= "cmd_irq",
 	},
 	{
-		.flags	= IORESOURCE_IRQ | IORESOURCE_DISABLED,
-		.name	= "status_irq"
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC3_CHAN,
+		.end	= DMOV_SDC3_CHAN,
+		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.start	= 8,
-		.end	= 8,
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC3_CRCI,
+		.end	= DMOV_SDC3_CRCI,
 		.flags	= IORESOURCE_DMA,
 	},
 };
 
 static struct resource resources_sdc4[] = {
 	{
-		.start	= MSM_SDC4_PHYS,
-		.end	= MSM_SDC4_PHYS + MSM_SDC4_SIZE - 1,
+		.start	= MSM_SDC4_BASE,
+		.end	= MSM_SDC4_BASE + SZ_4K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
 		.start	= INT_SDC4_0,
-		.end	= INT_SDC4_0,
+		.end	= INT_SDC4_1,
 		.flags	= IORESOURCE_IRQ,
-		.name	= "cmd_irq",
 	},
 	{
-		.flags	= IORESOURCE_IRQ | IORESOURCE_DISABLED,
-		.name	= "status_irq"
+		.name	= "sdcc_dma_chnl",
+		.start	= DMOV_SDC4_CHAN,
+		.end	= DMOV_SDC4_CHAN,
+		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.start	= 8,
-		.end	= 8,
+		.name	= "sdcc_dma_crci",
+		.start	= DMOV_SDC4_CRCI,
+		.end	= DMOV_SDC4_CRCI,
 		.flags	= IORESOURCE_DMA,
 	},
 };
@@ -266,84 +630,321 @@
 	&msm_device_sdc4,
 };
 
-int __init msm_add_sdcc(unsigned int controller,
-			struct msm_mmc_platform_data *plat,
-			unsigned int stat_irq, unsigned long stat_irq_flags)
+int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat)
 {
 	struct platform_device	*pdev;
-	struct resource *res;
 
 	if (controller < 1 || controller > 4)
 		return -EINVAL;
 
 	pdev = msm_sdcc_devices[controller-1];
 	pdev->dev.platform_data = plat;
-
-	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "status_irq");
-	if (!res)
-		return -EINVAL;
-	else if (stat_irq) {
-		res->start = res->end = stat_irq;
-		res->flags &= ~IORESOURCE_DISABLED;
-		res->flags |= stat_irq_flags;
-	}
-
 	return platform_device_register(pdev);
 }
 
-struct clk_lookup msm_clocks_8x50[] = {
-	CLK_PCOM("adm_clk",	ADM_CLK,	NULL, 0),
-	CLK_PCOM("ce_clk",	CE_CLK,		NULL, 0),
-	CLK_PCOM("ebi1_clk",	EBI1_CLK,	NULL, CLK_MIN),
-	CLK_PCOM("ebi2_clk",	EBI2_CLK,	NULL, 0),
-	CLK_PCOM("ecodec_clk",	ECODEC_CLK,	NULL, 0),
-	CLK_PCOM("emdh_clk",	EMDH_CLK,	NULL, OFF | CLK_MINMAX),
-	CLK_PCOM("gp_clk",	GP_CLK,		NULL, 0),
-	CLK_PCOM("grp_clk",	GRP_3D_CLK,	NULL, 0),
-	CLK_PCOM("i2c_clk",	I2C_CLK,	NULL, 0),
-	CLK_PCOM("icodec_rx_clk",	ICODEC_RX_CLK,	NULL, 0),
-	CLK_PCOM("icodec_tx_clk",	ICODEC_TX_CLK,	NULL, 0),
-	CLK_PCOM("imem_clk",	IMEM_CLK,	NULL, OFF),
-	CLK_PCOM("mdc_clk",	MDC_CLK,	NULL, 0),
-	CLK_PCOM("mddi_clk",	PMDH_CLK,	NULL, OFF | CLK_MINMAX),
-	CLK_PCOM("mdp_clk",	MDP_CLK,	NULL, OFF),
-	CLK_PCOM("mdp_lcdc_pclk_clk", MDP_LCDC_PCLK_CLK, NULL, 0),
-	CLK_PCOM("mdp_lcdc_pad_pclk_clk", MDP_LCDC_PAD_PCLK_CLK, NULL, 0),
-	CLK_PCOM("mdp_vsync_clk",	MDP_VSYNC_CLK,	NULL, 0),
-	CLK_PCOM("pbus_clk",	PBUS_CLK,	NULL, CLK_MIN),
-	CLK_PCOM("pcm_clk",	PCM_CLK,	NULL, 0),
-	CLK_PCOM("sdac_clk",	SDAC_CLK,	NULL, OFF),
-	CLK_PCOM("sdc_clk",	SDC1_CLK,	"msm_sdcc.1", OFF),
-	CLK_PCOM("sdc_pclk",	SDC1_P_CLK,	"msm_sdcc.1", OFF),
-	CLK_PCOM("sdc_clk",	SDC2_CLK,	"msm_sdcc.2", OFF),
-	CLK_PCOM("sdc_pclk",	SDC2_P_CLK,	"msm_sdcc.2", OFF),
-	CLK_PCOM("sdc_clk",	SDC3_CLK,	"msm_sdcc.3", OFF),
-	CLK_PCOM("sdc_pclk",	SDC3_P_CLK,	"msm_sdcc.3", OFF),
-	CLK_PCOM("sdc_clk",	SDC4_CLK,	"msm_sdcc.4", OFF),
-	CLK_PCOM("sdc_pclk",	SDC4_P_CLK,	"msm_sdcc.4", OFF),
-	CLK_PCOM("spi_clk",	SPI_CLK,	NULL, 0),
-	CLK_PCOM("tsif_clk",	TSIF_CLK,	NULL, 0),
-	CLK_PCOM("tsif_ref_clk",	TSIF_REF_CLK,	NULL, 0),
-	CLK_PCOM("tv_dac_clk",	TV_DAC_CLK,	NULL, 0),
-	CLK_PCOM("tv_enc_clk",	TV_ENC_CLK,	NULL, 0),
-	CLK_PCOM("uart_clk",	UART1_CLK,	NULL, OFF),
-	CLK_PCOM("uart_clk",	UART2_CLK,	NULL, 0),
-	CLK_PCOM("uart_clk",	UART3_CLK,	"msm_serial.2", OFF),
-	CLK_PCOM("uartdm_clk",	UART1DM_CLK,	NULL, OFF),
-	CLK_PCOM("uartdm_clk",	UART2DM_CLK,	NULL, 0),
-	CLK_PCOM("usb_hs_clk",	USB_HS_CLK,	NULL, OFF),
-	CLK_PCOM("usb_hs_pclk",	USB_HS_P_CLK,	NULL, OFF),
-	CLK_PCOM("usb_otg_clk",	USB_OTG_CLK,	NULL, 0),
-	CLK_PCOM("vdc_clk",	VDC_CLK,	NULL, OFF | CLK_MIN),
-	CLK_PCOM("vfe_clk",	VFE_CLK,	NULL, OFF),
-	CLK_PCOM("vfe_mdc_clk",	VFE_MDC_CLK,	NULL, OFF),
-	CLK_PCOM("vfe_axi_clk",	VFE_AXI_CLK,	NULL, OFF),
-	CLK_PCOM("usb_hs2_clk",	USB_HS2_CLK,	NULL, OFF),
-	CLK_PCOM("usb_hs2_pclk",	USB_HS2_P_CLK,	NULL, OFF),
-	CLK_PCOM("usb_hs3_clk",	USB_HS3_CLK,	NULL, OFF),
-	CLK_PCOM("usb_hs3_pclk",	USB_HS3_P_CLK,	NULL, OFF),
-	CLK_PCOM("usb_phy_clk",	USB_PHY_CLK,	NULL, 0),
+#if defined(CONFIG_FB_MSM_MDP40)
+#define MDP_BASE          0xA3F00000
+#define PMDH_BASE         0xAD600000
+#define EMDH_BASE         0xAD700000
+#define TVENC_BASE        0xAD400000
+#else
+#define MDP_BASE          0xAA200000
+#define PMDH_BASE         0xAA600000
+#define EMDH_BASE         0xAA700000
+#define TVENC_BASE        0xAA400000
+#endif
+
+static struct resource msm_mdp_resources[] = {
+	{
+		.name   = "mdp",
+		.start  = MDP_BASE,
+		.end    = MDP_BASE + 0x000F0000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = INT_MDP,
+		.end    = INT_MDP,
+		.flags  = IORESOURCE_IRQ,
+	},
 };
 
-unsigned msm_num_clocks_8x50 = ARRAY_SIZE(msm_clocks_8x50);
+static struct resource msm_mddi_resources[] = {
+	{
+		.name   = "pmdh",
+		.start  = PMDH_BASE,
+		.end    = PMDH_BASE + PAGE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	}
+};
+
+static struct resource msm_mddi_ext_resources[] = {
+	{
+		.name   = "emdh",
+		.start  = EMDH_BASE,
+		.end    = EMDH_BASE + PAGE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	}
+};
+
+static struct resource msm_ebi2_lcd_resources[] = {
+	{
+		.name   = "base",
+		.start  = 0xa0d00000,
+		.end    = 0xa0d00000 + PAGE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "lcd01",
+		.start  = 0x98000000,
+		.end    = 0x98000000 + 0x80000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.name   = "lcd02",
+		.start  = 0x9c000000,
+		.end    = 0x9c000000 + 0x80000 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+static struct resource msm_tvenc_resources[] = {
+	{
+		.name   = "tvenc",
+		.start  = TVENC_BASE,
+		.end    = TVENC_BASE + PAGE_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device msm_mdp_device = {
+	.name   = "mdp",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_mdp_resources),
+	.resource       = msm_mdp_resources,
+};
+
+static struct platform_device msm_mddi_device = {
+	.name   = "mddi",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_mddi_resources),
+	.resource       = msm_mddi_resources,
+};
+
+static struct platform_device msm_mddi_ext_device = {
+	.name   = "mddi_ext",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_mddi_ext_resources),
+	.resource       = msm_mddi_ext_resources,
+};
+
+static struct platform_device msm_ebi2_lcd_device = {
+	.name   = "ebi2_lcd",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_ebi2_lcd_resources),
+	.resource       = msm_ebi2_lcd_resources,
+};
+
+static struct platform_device msm_lcdc_device = {
+	.name   = "lcdc",
+	.id     = 0,
+};
+
+static struct platform_device msm_tvenc_device = {
+	.name   = "tvenc",
+	.id     = 0,
+	.num_resources  = ARRAY_SIZE(msm_tvenc_resources),
+	.resource       = msm_tvenc_resources,
+};
+
+#if defined(CONFIG_MSM_SOC_REV_A)
+#define MSM_QUP_PHYS           0xA1680000
+#define MSM_GSBI_QUP_I2C_PHYS  0xA1600000
+#define INT_PWB_QUP_ERR        INT_GSBI_QUP
+#else
+#define MSM_QUP_PHYS           0xA9900000
+#define MSM_GSBI_QUP_I2C_PHYS  0xA9900000
+#define INT_PWB_QUP_ERR        INT_PWB_I2C
+#endif
+#define MSM_QUP_SIZE           SZ_4K
+static struct resource resources_qup[] = {
+	{
+		.name   = "qup_phys_addr",
+		.start	= MSM_QUP_PHYS,
+		.end	= MSM_QUP_PHYS + MSM_QUP_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "gsbi_qup_i2c_addr",
+		.start	= MSM_GSBI_QUP_I2C_PHYS,
+		.end	= MSM_GSBI_QUP_I2C_PHYS + 4 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name   = "qup_err_intr",
+		.start	= INT_PWB_QUP_ERR,
+		.end	= INT_PWB_QUP_ERR,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device qup_device_i2c = {
+	.name		= "qup_i2c",
+	.id		= 4,
+	.num_resources	= ARRAY_SIZE(resources_qup),
+	.resource	= resources_qup,
+};
+
+/* TSIF begin */
+#if defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE)
+
+#define MSM_TSIF_PHYS        (0xa0100000)
+#define MSM_TSIF_SIZE        (0x200)
+
+static struct resource tsif_resources[] = {
+	[0] = {
+		.flags = IORESOURCE_IRQ,
+		.start = INT_TSIF_IRQ,
+		.end   = INT_TSIF_IRQ,
+	},
+	[1] = {
+		.flags = IORESOURCE_MEM,
+		.start = MSM_TSIF_PHYS,
+		.end   = MSM_TSIF_PHYS + MSM_TSIF_SIZE - 1,
+	},
+	[2] = {
+		.flags = IORESOURCE_DMA,
+		.start = DMOV_TSIF_CHAN,
+		.end   = DMOV_TSIF_CRCI,
+	},
+};
+
+static void tsif_release(struct device *dev)
+{
+	dev_info(dev, "release\n");
+}
+
+struct platform_device msm_device_tsif = {
+	.name          = "msm_tsif",
+	.id            = 0,
+	.num_resources = ARRAY_SIZE(tsif_resources),
+	.resource      = tsif_resources,
+	.dev = {
+		.release       = tsif_release,
+	},
+};
+#endif /* defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE) */
+/* TSIF end   */
+
+#define MSM_TSSC_PHYS         0xAA300000
+static struct resource resources_tssc[] = {
+	{
+		.start	= MSM_TSSC_PHYS,
+		.end	= MSM_TSSC_PHYS + SZ_4K - 1,
+		.name	= "tssc",
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_TCHSCRN1,
+		.end	= INT_TCHSCRN1,
+		.name	= "tssc1",
+		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_RISING,
+	},
+	{
+		.start	= INT_TCHSCRN2,
+		.end	= INT_TCHSCRN2,
+		.name	= "tssc2",
+		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_RISING,
+	},
+};
+
+struct platform_device msm_device_tssc = {
+	.name = "msm_touchscreen",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(resources_tssc),
+	.resource = resources_tssc,
+};
+
+static void __init msm_register_device(struct platform_device *pdev, void *data)
+{
+	int ret;
+
+	pdev->dev.platform_data = data;
+
+	ret = platform_device_register(pdev);
+	if (ret)
+		dev_err(&pdev->dev,
+			  "%s: platform_device_register() failed = %d\n",
+			  __func__, ret);
+}
+
+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, "pmdh", 4))
+		msm_register_device(&msm_mddi_device, data);
+	else if (!strncmp(name, "emdh", 4))
+		msm_register_device(&msm_mddi_ext_device, data);
+	else if (!strncmp(name, "ebi2", 4))
+		msm_register_device(&msm_ebi2_lcd_device, data);
+	else if (!strncmp(name, "tvenc", 5))
+		msm_register_device(&msm_tvenc_device, data);
+	else if (!strncmp(name, "lcdc", 4))
+		msm_register_device(&msm_lcdc_device, data);
+	else
+		printk(KERN_ERR "%s: unknown device! %s\n", __func__, name);
+}
+
+static struct platform_device msm_camera_device = {
+	.name	= "msm_camera",
+	.id	= 0,
+};
+
+void __init msm_camera_register_device(void *res, uint32_t num,
+	void *data)
+{
+	msm_camera_device.num_resources = num;
+	msm_camera_device.resource = res;
+
+	msm_register_device(&msm_camera_device, data);
+}
+
+static struct resource kgsl_3d0_resources[] = {
+	{
+		.name  = KGSL_3D0_REG_MEMORY,
+		.start = 0xA0000000,
+		.end = 0xA001ffff,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = KGSL_3D0_IRQ,
+		.start = INT_GRAPHICS,
+		.end = INT_GRAPHICS,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct kgsl_device_platform_data kgsl_3d0_pdata = {
+	.pwrlevel = {
+		{
+			.gpu_freq = 0,
+			.bus_freq = 128000000,
+		},
+	},
+	.init_level = 0,
+	.num_levels = 1,
+	.set_grp_async = NULL,
+	.idle_timeout = HZ/5,
+	.clk_map = KGSL_CLK_CORE | KGSL_CLK_MEM,
+};
+
+struct platform_device msm_kgsl_3d0 = {
+	.name = "kgsl-3d0",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(kgsl_3d0_resources),
+	.resource = kgsl_3d0_resources,
+	.dev = {
+		.platform_data = &kgsl_3d0_pdata,
+	},
+};
 
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 9545c19..f8ab18a 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -1,6 +1,7 @@
 /* linux/arch/arm/mach-msm/devices.h
  *
  * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2009-2012, Code Aurora Forum. 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
@@ -17,42 +18,386 @@
 #define __ARCH_ARM_MACH_MSM_DEVICES_H
 
 #include <linux/clkdev.h>
-
+#include <linux/platform_device.h>
 #include "clock.h"
 
+void __init msm9615_device_init(void);
+void __init msm9615_map_io(void);
+void __init msm_map_msm9615_io(void);
+void __init msm9615_init_irq(void);
+void __init msm_rotator_update_bus_vectors(unsigned int xres,
+	unsigned int yres);
+
+extern struct platform_device asoc_msm_pcm;
+extern struct platform_device asoc_msm_dai0;
+extern struct platform_device asoc_msm_dai1;
+#if defined (CONFIG_SND_MSM_MVS_DAI_SOC)
+extern struct platform_device asoc_msm_mvs;
+extern struct platform_device asoc_mvs_dai0;
+extern struct platform_device asoc_mvs_dai1;
+#endif
+
+extern struct platform_device msm_ebi0_thermal;
+extern struct platform_device msm_ebi1_thermal;
+
+extern struct platform_device msm_adsp_device;
 extern struct platform_device msm_device_uart1;
 extern struct platform_device msm_device_uart2;
 extern struct platform_device msm_device_uart3;
+extern struct platform_device msm8625_device_uart1;
+
+extern struct platform_device msm_device_uart_dm1;
+extern struct platform_device msm_device_uart_dm2;
+extern struct platform_device msm_device_uart_dm3;
+extern struct platform_device msm_device_uart_dm12;
+extern struct platform_device *msm_device_uart_gsbi9;
+extern struct platform_device msm_device_uart_dm6;
+extern struct platform_device msm_device_uart_dm9;
 
 extern struct platform_device msm8960_device_uart_gsbi2;
 extern struct platform_device msm8960_device_uart_gsbi5;
+extern struct platform_device msm8960_device_uart_gsbi8;
+extern struct platform_device msm8960_device_ssbi_pmic;
+extern struct platform_device msm8960_device_qup_i2c_gsbi3;
+extern struct platform_device msm8960_device_qup_i2c_gsbi4;
+extern struct platform_device msm8960_device_qup_i2c_gsbi9;
+extern struct platform_device msm8960_device_qup_i2c_gsbi10;
+extern struct platform_device msm8960_device_qup_i2c_gsbi12;
+extern struct platform_device msm8960_device_qup_spi_gsbi1;
+extern struct platform_device msm8960_gemini_device;
+extern struct platform_device msm8960_device_i2c_mux_gsbi4;
+extern struct platform_device msm8960_device_csiphy0;
+extern struct platform_device msm8960_device_csiphy1;
+extern struct platform_device msm8960_device_csiphy2;
+extern struct platform_device msm8960_device_csid0;
+extern struct platform_device msm8960_device_csid1;
+extern struct platform_device msm8960_device_csid2;
+extern struct platform_device msm8960_device_ispif;
+extern struct platform_device msm8960_device_vfe;
+extern struct platform_device msm8960_device_vpe;
+extern struct platform_device msm8960_device_cache_erp;
+
+extern struct platform_device apq8064_device_uart_gsbi1;
+extern struct platform_device apq8064_device_uart_gsbi3;
+extern struct platform_device apq8064_device_uart_gsbi7;
+extern struct platform_device apq8064_device_qup_i2c_gsbi1;
+extern struct platform_device apq8064_device_qup_i2c_gsbi3;
+extern struct platform_device apq8064_device_qup_i2c_gsbi4;
+extern struct platform_device apq8064_device_qup_spi_gsbi5;
+extern struct platform_device apq8064_slim_ctrl;
+extern struct platform_device apq8064_device_ssbi_pmic1;
+extern struct platform_device apq8064_device_ssbi_pmic2;
+extern struct platform_device apq8064_device_cache_erp;
+
+extern struct platform_device msm9615_device_uart_gsbi4;
+extern struct platform_device msm9615_device_qup_i2c_gsbi5;
+extern struct platform_device msm9615_device_qup_spi_gsbi3;
+extern struct platform_device msm9615_slim_ctrl;
+extern struct platform_device msm9615_device_ssbi_pmic1;
+extern struct platform_device msm9615_device_tsens;
+extern struct platform_device msm_bus_9615_sys_fabric;
+extern struct platform_device msm_bus_def_fab;
 
 extern struct platform_device msm_device_sdc1;
 extern struct platform_device msm_device_sdc2;
 extern struct platform_device msm_device_sdc3;
 extern struct platform_device msm_device_sdc4;
 
-extern struct platform_device msm_device_hsusb;
-extern struct platform_device msm_device_otg;
+extern struct platform_device msm_device_gadget_peripheral;
 extern struct platform_device msm_device_hsusb_host;
+extern struct platform_device msm_device_hsusb_host2;
+extern struct platform_device msm_device_hsic_host;
+
+extern struct platform_device msm_device_otg;
+extern struct platform_device msm_android_usb_device;
+extern struct platform_device msm_device_hsic_peripheral;
+extern struct platform_device msm8960_device_otg;
+extern struct platform_device msm8960_device_gadget_peripheral;
+
+extern struct platform_device apq8064_device_otg;
+extern struct platform_device apq8064_usb_diag_device;
+extern struct platform_device apq8064_device_gadget_peripheral;
+extern struct platform_device apq8064_device_hsusb_host;
+extern struct platform_device apq8064_device_hsic_host;
+extern struct platform_device apq8064_device_ehci_host3;
+extern struct platform_device apq8064_device_ehci_host4;
 
 extern struct platform_device msm_device_i2c;
 
+extern struct platform_device msm_device_i2c_2;
+
+extern struct platform_device qup_device_i2c;
+
+extern struct platform_device msm_gsbi0_qup_i2c_device;
+extern struct platform_device msm_gsbi1_qup_i2c_device;
+extern struct platform_device msm_gsbi3_qup_i2c_device;
+extern struct platform_device msm_gsbi4_qup_i2c_device;
+extern struct platform_device msm_gsbi7_qup_i2c_device;
+extern struct platform_device msm_gsbi8_qup_i2c_device;
+extern struct platform_device msm_gsbi9_qup_i2c_device;
+extern struct platform_device msm_gsbi12_qup_i2c_device;
+
+extern struct platform_device msm8625_gsbi0_qup_i2c_device;
+extern struct platform_device msm8625_gsbi1_qup_i2c_device;
+extern struct platform_device msm8625_device_uart_dm1;
+extern struct platform_device msm8625_device_uart_dm2;
+extern struct platform_device msm8625_device_sdc1;
+extern struct platform_device msm8625_device_sdc2;
+extern struct platform_device msm8625_device_sdc3;
+extern struct platform_device msm8625_device_sdc4;
+extern struct platform_device msm8625_device_gadget_peripheral;
+extern struct platform_device msm8625_device_hsusb_host;
+extern struct platform_device msm8625_device_otg;
+extern struct platform_device msm8625_kgsl_3d0;
+extern struct platform_device msm8625_device_adsp;
+
+extern struct platform_device msm_slim_ctrl;
+extern struct platform_device msm_device_sps;
+extern struct platform_device msm_device_usb_bam;
+extern struct platform_device msm_device_sps_apq8064;
+extern struct platform_device msm_device_bam_dmux;
 extern struct platform_device msm_device_smd;
+extern struct platform_device msm_device_smd_apq8064;
+extern struct platform_device msm8625_device_smd;
+extern struct platform_device msm_device_dmov;
+extern struct platform_device msm8960_device_dmov;
+extern struct platform_device apq8064_device_dmov;
+extern struct platform_device msm9615_device_dmov;
+extern struct platform_device msm8625_device_dmov;
+extern struct platform_device msm_device_dmov_adm0;
+extern struct platform_device msm_device_dmov_adm1;
+
+extern struct platform_device msm_device_pcie;
 
 extern struct platform_device msm_device_nand;
 
-extern struct platform_device msm_device_mddi0;
-extern struct platform_device msm_device_mddi1;
-extern struct platform_device msm_device_mdp;
+extern struct platform_device msm_device_tssc;
 
-extern struct clk_lookup msm_clocks_7x01a[];
-extern unsigned msm_num_clocks_7x01a;
-
-extern struct clk_lookup msm_clocks_7x30[];
-extern unsigned msm_num_clocks_7x30;
-
-extern struct clk_lookup msm_clocks_8x50[];
-extern unsigned msm_num_clocks_8x50;
-
+extern struct platform_device msm_rotator_device;
+#ifdef CONFIG_MSM_VCAP
+extern struct platform_device msm8064_device_vcap;
 #endif
+
+#ifdef CONFIG_MSM_BUS_SCALING
+extern struct msm_bus_scale_pdata rotator_bus_scale_pdata;
+#endif
+
+extern struct platform_device msm_device_tsif[2];
+
+extern struct platform_device msm_device_ssbi_pmic1;
+extern struct platform_device msm_device_ssbi_pmic2;
+extern struct platform_device msm_device_ssbi1;
+extern struct platform_device msm_device_ssbi2;
+extern struct platform_device msm_device_ssbi3;
+extern struct platform_device msm_device_ssbi6;
+extern struct platform_device msm_device_ssbi7;
+
+extern struct platform_device msm_gsbi1_qup_spi_device;
+
+extern struct platform_device msm_device_vidc_720p;
+
+extern struct platform_device msm_pcm;
+extern struct platform_device msm_multi_ch_pcm;
+extern struct platform_device msm_pcm_routing;
+extern struct platform_device msm_cpudai0;
+extern struct platform_device msm_cpudai1;
+extern struct platform_device mpq_cpudai_sec_i2s_rx;
+extern struct platform_device msm8960_cpudai_slimbus_2_tx;
+extern struct platform_device msm_cpudai_hdmi_rx;
+extern struct platform_device msm_cpudai_bt_rx;
+extern struct platform_device msm_cpudai_bt_tx;
+extern struct platform_device msm_cpudai_fm_rx;
+extern struct platform_device msm_cpudai_fm_tx;
+extern struct platform_device msm_cpudai_auxpcm_rx;
+extern struct platform_device msm_cpudai_auxpcm_tx;
+extern struct platform_device msm_cpu_fe;
+extern struct platform_device msm_stub_codec;
+extern struct platform_device msm_voice;
+extern struct platform_device msm_voip;
+extern struct platform_device msm_lpa_pcm;
+extern struct platform_device msm_pcm_hostless;
+extern struct platform_device msm_cpudai_afe_01_rx;
+extern struct platform_device msm_cpudai_afe_01_tx;
+extern struct platform_device msm_cpudai_afe_02_rx;
+extern struct platform_device msm_cpudai_afe_02_tx;
+extern struct platform_device msm_pcm_afe;
+extern struct platform_device msm_compr_dsp;
+extern struct platform_device msm_cpudai_incall_music_rx;
+extern struct platform_device msm_cpudai_incall_record_rx;
+extern struct platform_device msm_cpudai_incall_record_tx;
+extern struct platform_device msm_i2s_cpudai0;
+extern struct platform_device msm_i2s_cpudai1;
+
+extern struct platform_device msm_pil_q6v3;
+extern struct platform_device msm_pil_modem;
+extern struct platform_device msm_pil_tzapps;
+extern struct platform_device msm_pil_dsps;
+extern struct platform_device msm_pil_vidc;
+extern struct platform_device msm_8960_q6_lpass;
+extern struct platform_device msm_8960_q6_mss_fw;
+extern struct platform_device msm_8960_q6_mss_sw;
+extern struct platform_device msm_8960_riva;
+extern struct platform_device msm_gss;
+
+extern struct platform_device apq_pcm;
+extern struct platform_device apq_pcm_routing;
+extern struct platform_device apq_cpudai0;
+extern struct platform_device apq_cpudai1;
+extern struct platform_device mpq_cpudai_mi2s_tx;
+extern struct platform_device apq_cpudai_hdmi_rx;
+extern struct platform_device apq_cpudai_bt_rx;
+extern struct platform_device apq_cpudai_bt_tx;
+extern struct platform_device apq_cpudai_fm_rx;
+extern struct platform_device apq_cpudai_fm_tx;
+extern struct platform_device apq_cpudai_auxpcm_rx;
+extern struct platform_device apq_cpudai_auxpcm_tx;
+extern struct platform_device apq_cpu_fe;
+extern struct platform_device apq_stub_codec;
+extern struct platform_device apq_voice;
+extern struct platform_device apq_voip;
+extern struct platform_device apq_lpa_pcm;
+extern struct platform_device apq_compr_dsp;
+extern struct platform_device apq_multi_ch_pcm;
+extern struct platform_device apq_pcm_hostless;
+extern struct platform_device apq_cpudai_afe_01_rx;
+extern struct platform_device apq_cpudai_afe_01_tx;
+extern struct platform_device apq_cpudai_afe_02_rx;
+extern struct platform_device apq_cpudai_afe_02_tx;
+extern struct platform_device apq_pcm_afe;
+extern struct platform_device apq_cpudai_stub;
+extern struct platform_device apq_cpudai_slimbus_1_rx;
+extern struct platform_device apq_cpudai_slimbus_1_tx;
+extern struct platform_device apq_cpudai_slimbus_2_tx;
+extern struct platform_device apq_cpudai_slimbus_3_rx;
+extern struct platform_device apq_cpudai_slim_4_rx;
+extern struct platform_device apq_cpudai_slim_4_tx;
+
+extern struct platform_device *msm_footswitch_devices[];
+extern unsigned msm_num_footswitch_devices;
+extern struct platform_device *msm8660_footswitch[];
+extern unsigned msm8660_num_footswitch;
+extern struct platform_device *msm8960_footswitch[];
+extern unsigned msm8960_num_footswitch;
+extern struct platform_device *apq8064_footswitch[];
+extern unsigned apq8064_num_footswitch;
+extern struct platform_device *msm8930_footswitch[];
+extern unsigned msm8930_num_footswitch;
+
+extern struct platform_device fsm_qfp_fuse_device;
+
+extern struct platform_device fsm_xo_device;
+
+extern struct platform_device qfec_device;
+
+extern struct platform_device msm_kgsl_3d0;
+extern struct platform_device msm_kgsl_2d0;
+extern struct platform_device msm_kgsl_2d1;
+
+extern struct platform_device msm_mipi_dsi1_device;
+extern struct platform_device msm_lvds_device;
+extern struct platform_device msm_ebi2_lcdc_device;
+
+extern struct clk_lookup msm_clocks_fsm9xxx[];
+extern unsigned msm_num_clocks_fsm9xxx;
+
+extern struct platform_device msm_footswitch;
+
+void __init msm_fb_register_device(char *name, void *data);
+void __init msm_camera_register_device(void *, uint32_t, void *);
+struct platform_device *msm_add_gsbi9_uart(void);
+extern struct platform_device msm_device_touchscreen;
+
+extern struct platform_device led_pdev;
+
+extern struct platform_device msm8960_rpm_device;
+extern struct platform_device msm8960_rpm_stat_device;
+extern struct platform_device msm8960_rpm_log_device;
+
+extern struct platform_device msm8930_rpm_device;
+extern struct platform_device msm8930_rpm_stat_device;
+extern struct platform_device msm8930_rpm_log_device;
+
+extern struct platform_device msm8660_rpm_device;
+extern struct platform_device msm8660_rpm_stat_device;
+extern struct platform_device msm8660_rpm_log_device;
+
+extern struct platform_device msm9615_rpm_device;
+extern struct platform_device msm9615_rpm_stat_device;
+extern struct platform_device msm9615_rpm_log_device;
+
+extern struct platform_device apq8064_rpm_device;
+extern struct platform_device apq8064_rpm_stat_device;
+extern struct platform_device apq8064_rpm_log_device;
+
+extern struct platform_device msm_device_rng;
+extern struct platform_device apq8064_device_rng;
+
+#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
+		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
+extern struct platform_device msm9615_qcrypto_device;
+#endif
+
+#if defined(CONFIG_CRYPTO_DEV_QCEDEV) || \
+		defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
+extern struct platform_device msm9615_qcedev_device;
+#endif
+extern struct platform_device msm8960_device_watchdog;
+extern struct platform_device msm8660_device_watchdog;
+extern struct platform_device msm8064_device_watchdog;
+extern struct platform_device msm9615_device_watchdog;
+extern struct platform_device fsm9xxx_device_watchdog;
+
+extern struct platform_device apq8064_qdss_device;
+extern struct platform_device msm_qdss_device;
+extern struct platform_device msm_etb_device;
+extern struct platform_device msm_tpiu_device;
+extern struct platform_device msm_funnel_device;
+extern struct platform_device msm_etm_device;
+extern struct platform_device apq8064_etm_device;
+#endif
+
+extern struct platform_device msm_bus_8064_apps_fabric;
+extern struct platform_device msm_bus_8064_sys_fabric;
+extern struct platform_device msm_bus_8064_mm_fabric;
+extern struct platform_device msm_bus_8064_sys_fpb;
+extern struct platform_device msm_bus_8064_cpss_fpb;
+
+extern struct platform_device mdm_8064_device;
+extern struct platform_device msm_dsps_device_8064;
+extern struct platform_device *msm_copper_stub_regulator_devices[];
+extern int msm_copper_stub_regulator_devices_len;
+
+extern struct platform_device msm8960_cpu_idle_device;
+extern struct platform_device msm8930_cpu_idle_device;
+extern struct platform_device apq8064_cpu_idle_device;
+
+extern struct platform_device msm8960_msm_gov_device;
+extern struct platform_device msm8930_msm_gov_device;
+extern struct platform_device apq8064_msm_gov_device;
+
+extern struct platform_device msm_bus_8930_apps_fabric;
+extern struct platform_device msm_bus_8930_sys_fabric;
+extern struct platform_device msm_bus_8930_mm_fabric;
+extern struct platform_device msm_bus_8930_sys_fpb;
+extern struct platform_device msm_bus_8930_cpss_fpb;
+
+extern struct platform_device msm_device_csic0;
+extern struct platform_device msm_device_csic1;
+extern struct platform_device msm_device_vfe;
+extern struct platform_device msm_device_vpe;
+extern struct platform_device mpq8064_device_qup_i2c_gsbi5;
+
+extern struct platform_device msm8960_iommu_domain_device;
+extern struct platform_device msm8930_iommu_domain_device;
+extern struct platform_device apq8064_iommu_domain_device;
+
+extern struct platform_device msm8960_rtb_device;
+extern struct platform_device msm8930_rtb_device;
+extern struct platform_device apq8064_rtb_device;
+
+extern struct platform_device msm8960_cache_dump_device;
+extern struct platform_device apq8064_cache_dump_device;
+
+extern struct platform_device copper_device_tz_log;
+
+extern struct platform_device mdm_sglte_device;
diff --git a/arch/arm/mach-msm/devices_htc.c b/arch/arm/mach-msm/devices_htc.c
new file mode 100644
index 0000000..b2b4572
--- /dev/null
+++ b/arch/arm/mach-msm/devices_htc.c
@@ -0,0 +1,450 @@
+/* linux/arch/arm/mach-msm/devices.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2007-2009 HTC Corporation.
+ * Author: Thomas Tsai <thomas_tsai@htc.com>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#include <linux/dma-mapping.h>
+#include <mach/msm_iomap.h>
+#include <mach/dma.h>
+#include "gpio_chip.h"
+#include "devices.h"
+#include <mach/board.h>
+#include <mach/board_htc.h>
+#include <mach/msm_hsusb.h>
+#include <linux/usb/mass_storage_function.h>
+#include <linux/usb/android.h>
+
+#include <asm/mach/flash.h>
+#include <asm/setup.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/delay.h>
+#include <linux/android_pmem.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/msm_iomap.h>
+#include <asm/mach/mmc.h>
+
+static char *df_serialno = "000000000000";
+
+#if 0
+struct platform_device *devices[] __initdata = {
+	&msm_device_nand,
+	&msm_device_smd,
+	&msm_device_i2c,
+};
+
+void __init msm_add_devices(void)
+{
+	platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+#endif
+
+#define HSUSB_API_INIT_PHY_PROC	2
+#define HSUSB_API_PROG		0x30000064
+#define HSUSB_API_VERS		0x10001
+static void internal_phy_reset(void)
+{
+	struct msm_rpc_endpoint *usb_ep;
+	int rc;
+	struct hsusb_phy_start_req {
+		struct rpc_request_hdr hdr;
+	} req;
+
+	printk(KERN_INFO "msm_hsusb_phy_reset\n");
+
+	usb_ep = msm_rpc_connect(HSUSB_API_PROG, HSUSB_API_VERS, 0);
+	if (IS_ERR(usb_ep)) {
+		printk(KERN_ERR "%s: init rpc failed! error: %ld\n",
+				__func__, PTR_ERR(usb_ep));
+		goto close;
+	}
+	rc = msm_rpc_call(usb_ep, HSUSB_API_INIT_PHY_PROC,
+			&req, sizeof(req), 5 * HZ);
+	if (rc < 0)
+		printk(KERN_ERR "%s: rpc call failed! (%d)\n", __func__, rc);
+
+close:
+	msm_rpc_close(usb_ep);
+}
+
+/* adjust eye diagram, disable vbusvalid interrupts */
+static int hsusb_phy_init_seq[] = { 0x40, 0x31, 0x1D, 0x0D, 0x1D, 0x10, -1 };
+
+#ifdef CONFIG_USB_FUNCTION
+static char *usb_functions[] = {
+#if defined(CONFIG_USB_FUNCTION_MASS_STORAGE) || defined(CONFIG_USB_FUNCTION_UMS)
+	"usb_mass_storage",
+#endif
+#ifdef CONFIG_USB_FUNCTION_ADB
+	"adb",
+#endif
+};
+
+static struct msm_hsusb_product usb_products[] = {
+	{
+		.product_id	= 0x0c01,
+		.functions	= 0x00000041, /* usb_mass_storage */
+	},
+	{
+		.product_id	= 0x0c02,
+		.functions	= 0x00000043, /* usb_mass_storage + adb */
+	},
+};
+#endif
+
+struct msm_hsusb_platform_data msm_hsusb_pdata = {
+	.phy_reset = internal_phy_reset,
+	.phy_init_seq = hsusb_phy_init_seq,
+#ifdef CONFIG_USB_FUNCTION
+	.vendor_id = 0x0bb4,
+	.product_id = 0x0c02,
+	.version = 0x0100,
+	.product_name = "Android Phone",
+	.manufacturer_name = "HTC",
+
+	.functions = usb_functions,
+	.num_functions = ARRAY_SIZE(usb_functions),
+	.products = usb_products,
+	.num_products = ARRAY_SIZE(usb_products),
+#endif
+};
+
+#ifdef CONFIG_USB_FUNCTION
+static struct usb_mass_storage_platform_data mass_storage_pdata = {
+	.nluns = 1,
+	.buf_size = 16384,
+	.vendor = "HTC     ",
+	.product = "Android Phone   ",
+	.release = 0x0100,
+};
+
+static struct platform_device usb_mass_storage_device = {
+	.name = "usb_mass_storage",
+	.id = -1,
+	.dev = {
+		.platform_data = &mass_storage_pdata,
+		},
+};
+#endif
+
+#ifdef CONFIG_USB_ANDROID
+static struct android_usb_platform_data android_usb_pdata = {
+	.vendor_id	= 0x0bb4,
+	.product_id	= 0x0c01,
+	.adb_product_id	= 0x0c02,
+	.version	= 0x0100,
+	.product_name	= "Android Phone",
+	.manufacturer_name = "HTC",
+	.nluns = 1,
+};
+
+static struct platform_device android_usb_device = {
+	.name	= "android_usb",
+	.id		= -1,
+	.dev		= {
+		.platform_data = &android_usb_pdata,
+	},
+};
+#endif
+
+void __init msm_add_usb_devices(void (*phy_reset) (void))
+{
+	/* setup */
+	if (phy_reset)
+		msm_hsusb_pdata.phy_reset = phy_reset;
+	msm_device_hsusb.dev.platform_data = &msm_hsusb_pdata;
+	platform_device_register(&msm_device_hsusb);
+#ifdef CONFIG_USB_FUNCTION_MASS_STORAGE
+	platform_device_register(&usb_mass_storage_device);
+#endif
+#ifdef CONFIG_USB_ANDROID
+	platform_device_register(&android_usb_device);
+#endif
+}
+
+static struct android_pmem_platform_data pmem_pdata = {
+	.name = "pmem",
+	.allocator_type = PMEM_ALLOCATORTYPE_ALLORNOTHING,
+	.cached = 1,
+};
+
+static struct android_pmem_platform_data pmem_adsp_pdata = {
+	.name = "pmem_adsp",
+	.allocator_type = PMEM_ALLOCATORTYPE_BUDDYBESTFIT,
+	.cached = 0,
+};
+
+static struct android_pmem_platform_data pmem_camera_pdata = {
+	.name = "pmem_camera",
+	.allocator_type = PMEM_ALLOCATORTYPE_BUDDYBESTFIT,
+	.cached = 0,
+};
+
+static struct android_pmem_platform_data pmem_gpu0_pdata = {
+	.name = "pmem_gpu0",
+	.allocator_type = PMEM_ALLOCATORTYPE_ALLORNOTHING,
+	.cached = 0,
+	.buffered = 1,
+};
+
+static struct android_pmem_platform_data pmem_gpu1_pdata = {
+	.name = "pmem_gpu1",
+	.allocator_type = PMEM_ALLOCATORTYPE_ALLORNOTHING,
+	.cached = 0,
+	.buffered = 1,
+};
+
+static struct platform_device pmem_device = {
+	.name = "android_pmem",
+	.id = 0,
+	.dev = { .platform_data = &pmem_pdata },
+};
+
+static struct platform_device pmem_adsp_device = {
+	.name = "android_pmem",
+	.id = 1,
+	.dev = { .platform_data = &pmem_adsp_pdata },
+};
+
+static struct platform_device pmem_gpu0_device = {
+	.name = "android_pmem",
+	.id = 2,
+	.dev = { .platform_data = &pmem_gpu0_pdata },
+};
+
+static struct platform_device pmem_gpu1_device = {
+	.name = "android_pmem",
+	.id = 3,
+	.dev = { .platform_data = &pmem_gpu1_pdata },
+};
+
+static struct platform_device pmem_camera_device = {
+	.name = "android_pmem",
+	.id = 4,
+	.dev = { .platform_data = &pmem_camera_pdata },
+};
+
+static struct resource ram_console_resource[] = {
+	{
+		.flags	= IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device ram_console_device = {
+	.name = "ram_console",
+	.id = -1,
+	.num_resources  = ARRAY_SIZE(ram_console_resource),
+	.resource       = ram_console_resource,
+};
+
+void __init msm_add_mem_devices(struct msm_pmem_setting *setting)
+{
+	if (setting->pmem_size) {
+		pmem_pdata.start = setting->pmem_start;
+		pmem_pdata.size = setting->pmem_size;
+		platform_device_register(&pmem_device);
+	}
+
+	if (setting->pmem_adsp_size) {
+		pmem_adsp_pdata.start = setting->pmem_adsp_start;
+		pmem_adsp_pdata.size = setting->pmem_adsp_size;
+		platform_device_register(&pmem_adsp_device);
+	}
+
+	if (setting->pmem_gpu0_size) {
+		pmem_gpu0_pdata.start = setting->pmem_gpu0_start;
+		pmem_gpu0_pdata.size = setting->pmem_gpu0_size;
+		platform_device_register(&pmem_gpu0_device);
+	}
+
+	if (setting->pmem_gpu1_size) {
+		pmem_gpu1_pdata.start = setting->pmem_gpu1_start;
+		pmem_gpu1_pdata.size = setting->pmem_gpu1_size;
+		platform_device_register(&pmem_gpu1_device);
+	}
+
+	if (setting->pmem_camera_size) {
+		pmem_camera_pdata.start = setting->pmem_camera_start;
+		pmem_camera_pdata.size = setting->pmem_camera_size;
+		platform_device_register(&pmem_camera_device);
+	}
+
+	if (setting->ram_console_size) {
+		ram_console_resource[0].start = setting->ram_console_start;
+		ram_console_resource[0].end = setting->ram_console_start
+			+ setting->ram_console_size - 1;
+		platform_device_register(&ram_console_device);
+	}
+}
+
+#define PM_LIBPROG      0x30000061
+#if (CONFIG_MSM_AMSS_VERSION == 6220) || (CONFIG_MSM_AMSS_VERSION == 6225)
+#define PM_LIBVERS      0xfb837d0b
+#else
+#define PM_LIBVERS      0x10001
+#endif
+
+#if 0
+static struct platform_device *msm_serial_devices[] __initdata = {
+	&msm_device_uart1,
+	&msm_device_uart2,
+	&msm_device_uart3,
+	#ifdef CONFIG_SERIAL_MSM_HS
+	&msm_device_uart_dm1,
+	&msm_device_uart_dm2,
+	#endif
+};
+
+int __init msm_add_serial_devices(unsigned num)
+{
+	if (num > MSM_SERIAL_NUM)
+		return -EINVAL;
+
+	return platform_device_register(msm_serial_devices[num]);
+}
+#endif
+
+#define ATAG_SMI 0x4d534D71
+/* setup calls mach->fixup, then parse_tags, parse_cmdline
+ * We need to setup meminfo in mach->fixup, so this function
+ * will need to traverse each tag to find smi tag.
+ */
+int __init parse_tag_smi(const struct tag *tags)
+{
+	int smi_sz = 0, find = 0;
+	struct tag *t = (struct tag *)tags;
+
+	for (; t->hdr.size; t = tag_next(t)) {
+		if (t->hdr.tag == ATAG_SMI) {
+			printk(KERN_DEBUG "find the smi tag\n");
+			find = 1;
+			break;
+		}
+	}
+	if (!find)
+		return -1;
+
+	printk(KERN_DEBUG "parse_tag_smi: smi size = %d\n", t->u.mem.size);
+	smi_sz = t->u.mem.size;
+	return smi_sz;
+}
+__tagtable(ATAG_SMI, parse_tag_smi);
+
+
+#define ATAG_HWID 0x4d534D72
+int __init parse_tag_hwid(const struct tag *tags)
+{
+	int hwid = 0, find = 0;
+	struct tag *t = (struct tag *)tags;
+
+	for (; t->hdr.size; t = tag_next(t)) {
+		if (t->hdr.tag == ATAG_HWID) {
+			printk(KERN_DEBUG "find the hwid tag\n");
+			find = 1;
+			break;
+		}
+	}
+
+	if (find)
+		hwid = t->u.revision.rev;
+	printk(KERN_DEBUG "parse_tag_hwid: hwid = 0x%x\n", hwid);
+	return hwid;
+}
+__tagtable(ATAG_HWID, parse_tag_hwid);
+
+#define ATAG_SKUID 0x4d534D73
+int __init parse_tag_skuid(const struct tag *tags)
+{
+	int skuid = 0, find = 0;
+	struct tag *t = (struct tag *)tags;
+
+	for (; t->hdr.size; t = tag_next(t)) {
+		if (t->hdr.tag == ATAG_SKUID) {
+			printk(KERN_DEBUG "find the skuid tag\n");
+			find = 1;
+			break;
+		}
+	}
+
+	if (find)
+		skuid = t->u.revision.rev;
+	printk(KERN_DEBUG "parse_tag_skuid: hwid = 0x%x\n", skuid);
+	return skuid;
+}
+__tagtable(ATAG_SKUID, parse_tag_skuid);
+
+#define ATAG_ENGINEERID 0x4d534D75
+int __init parse_tag_engineerid(const struct tag *tags)
+{
+	int engineerid = 0, find = 0;
+	struct tag *t = (struct tag *)tags;
+
+	for (; t->hdr.size; t = tag_next(t)) {
+		if (t->hdr.tag == ATAG_ENGINEERID) {
+			printk(KERN_DEBUG "find the engineer tag\n");
+			find = 1;
+			break;
+		}
+	}
+
+	if (find)
+		engineerid = t->u.revision.rev;
+	printk(KERN_DEBUG "parse_tag_engineerid: hwid = 0x%x\n", engineerid);
+	return engineerid;
+}
+__tagtable(ATAG_ENGINEERID, parse_tag_engineerid);
+
+static int mfg_mode;
+int __init board_mfg_mode_init(char *s)
+{
+	if (!strcmp(s, "normal"))
+		mfg_mode = 0;
+	else if (!strcmp(s, "factory2"))
+		mfg_mode = 1;
+	else if (!strcmp(s, "recovery"))
+		mfg_mode = 2;
+	else if (!strcmp(s, "charge"))
+		mfg_mode = 3;
+
+	return 1;
+}
+__setup("androidboot.mode=", board_mfg_mode_init);
+
+
+int board_mfg_mode(void)
+{
+	return mfg_mode;
+}
+
+static int __init board_serialno_setup(char *serialno)
+{
+	char *str;
+
+	if (board_mfg_mode() || !strlen(serialno))
+		str = df_serialno;
+	else
+		str = serialno;
+#ifdef CONFIG_USB_FUNCTION
+	msm_hsusb_pdata.serial_number = str;
+#endif
+#ifdef CONFIG_USB_ANDROID
+	android_usb_pdata.serial_number = str;
+#endif
+	return 1;
+}
+
+__setup("androidboot.serialno=", board_serialno_setup);
diff --git a/arch/arm/mach-msm/dfe-fsm9xxx.c b/arch/arm/mach-msm/dfe-fsm9xxx.c
new file mode 100644
index 0000000..1a956e3
--- /dev/null
+++ b/arch/arm/mach-msm/dfe-fsm9xxx.c
@@ -0,0 +1,433 @@
+/* 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
+ * 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/module.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/miscdevice.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/poll.h>
+#include <mach/msm_iomap.h>
+
+#include <linux/fsm_dfe_hh.h>
+
+/*
+ * DFE of FSM9XXX
+ */
+
+#define HH_ADDR_MASK			0x000ffffc
+#define HH_OFFSET_VALID(offset)		(((offset) & ~HH_ADDR_MASK) == 0)
+#define HH_REG_IOADDR(offset)		((uint8_t *) MSM_HH_BASE + (offset))
+#define HH_MAKE_OFFSET(blk, adr)	(((blk)&0x1F)<<15|((adr)&0x1FFF)<<2)
+
+#define HH_REG_SCPN_IREQ_MASK		HH_REG_IOADDR(HH_MAKE_OFFSET(5, 0x12))
+#define HH_REG_SCPN_IREQ_FLAG		HH_REG_IOADDR(HH_MAKE_OFFSET(5, 0x13))
+
+/*
+ * Device private information per device node
+ */
+
+#define HH_IRQ_FIFO_SIZE		64
+#define HH_IRQ_FIFO_EMPTY(pdev)		((pdev)->irq_fifo_head == \
+					(pdev)->irq_fifo_tail)
+#define HH_IRQ_FIFO_FULL(pdev)		((((pdev)->irq_fifo_tail + 1) % \
+					HH_IRQ_FIFO_SIZE) == \
+					(pdev)->irq_fifo_head)
+
+static struct hh_dev_node_info {
+	spinlock_t hh_lock;
+	char irq_fifo[HH_IRQ_FIFO_SIZE];
+	unsigned int irq_fifo_head, irq_fifo_tail;
+	wait_queue_head_t wq;
+} hh_dev_info;
+
+/*
+ * Device private information per file
+ */
+
+struct hh_dev_file_info {
+	/* Buffer */
+	unsigned int *parray;
+	unsigned int array_num;
+
+	struct dfe_command_entry *pcmd;
+	unsigned int cmd_num;
+};
+
+/*
+ * File interface
+ */
+
+static int hh_open(struct inode *inode, struct file *file)
+{
+	struct hh_dev_file_info *pdfi;
+
+	/* private data allocation */
+	pdfi = kmalloc(sizeof(*pdfi), GFP_KERNEL);
+	if (pdfi == NULL)
+		return -ENOMEM;
+	file->private_data = pdfi;
+
+	/* buffer initialization */
+	pdfi->parray = NULL;
+	pdfi->array_num = 0;
+	pdfi->pcmd = NULL;
+	pdfi->cmd_num = 0;
+
+	return 0;
+}
+
+static int hh_release(struct inode *inode, struct file *file)
+{
+	struct hh_dev_file_info *pdfi;
+
+	pdfi = (struct hh_dev_file_info *) file->private_data;
+
+	kfree(pdfi->parray);
+	pdfi->parray = NULL;
+	pdfi->array_num = 0;
+
+	kfree(pdfi->pcmd);
+	pdfi->pcmd = NULL;
+	pdfi->cmd_num = 0;
+
+	kfree(file->private_data);
+	file->private_data = NULL;
+
+	return 0;
+}
+
+static ssize_t hh_read(struct file *filp, char __user *buf, size_t count,
+	loff_t *f_pos)
+{
+	signed char irq = -1;
+	unsigned long irq_flags;
+
+	do {
+		spin_lock_irqsave(&hh_dev_info.hh_lock, irq_flags);
+		if (!HH_IRQ_FIFO_EMPTY(&hh_dev_info)) {
+			irq = hh_dev_info.irq_fifo[hh_dev_info.irq_fifo_head];
+			if (++hh_dev_info.irq_fifo_head == HH_IRQ_FIFO_SIZE)
+				hh_dev_info.irq_fifo_head = 0;
+		}
+		spin_unlock_irqrestore(&hh_dev_info.hh_lock, irq_flags);
+
+		if (irq < 0)
+			if (wait_event_interruptible(hh_dev_info.wq,
+				!HH_IRQ_FIFO_EMPTY(&hh_dev_info)) < 0)
+				break;
+	} while (irq < 0);
+
+	if (irq < 0) {
+		/* No pending interrupt */
+		return 0;
+	} else {
+		put_user(irq, buf);
+		return 1;
+	}
+
+	return 0;
+}
+
+static ssize_t hh_write(struct file *file, const char __user *buffer,
+	size_t count, loff_t *ppos)
+{
+	return 0;
+}
+
+static long hh_ioctl(struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	unsigned int __user *argp = (unsigned int __user *) arg;
+	struct hh_dev_file_info *pdfi =
+		(struct hh_dev_file_info *) file->private_data;
+
+	switch (cmd) {
+	case DFE_IOCTL_READ_REGISTER:
+		{
+			unsigned int offset, value;
+
+			if (get_user(offset, argp))
+				return -EFAULT;
+			if (!HH_OFFSET_VALID(offset))
+				return -EINVAL;
+			value = __raw_readl(HH_REG_IOADDR(offset));
+			if (put_user(value, argp))
+				return -EFAULT;
+		}
+		break;
+
+	case DFE_IOCTL_WRITE_REGISTER:
+		{
+			struct dfe_write_register_param param;
+
+			if (copy_from_user(&param, argp, sizeof param))
+				return -EFAULT;
+			if (!HH_OFFSET_VALID(param.offset))
+				return -EINVAL;
+			__raw_writel(param.value,
+				HH_REG_IOADDR(param.offset));
+		}
+		break;
+
+	case DFE_IOCTL_WRITE_REGISTER_WITH_MASK:
+		{
+			struct dfe_write_register_mask_param param;
+			unsigned int value;
+			unsigned long irq_flags;
+
+			if (copy_from_user(&param, argp, sizeof param))
+				return -EFAULT;
+			if (!HH_OFFSET_VALID(param.offset))
+				return -EINVAL;
+			spin_lock_irqsave(&hh_dev_info.hh_lock,
+				irq_flags);
+			value = __raw_readl(HH_REG_IOADDR(param.offset));
+			value &= ~param.mask;
+			value |= param.value & param.mask;
+			__raw_writel(value, HH_REG_IOADDR(param.offset));
+			spin_unlock_irqrestore(&hh_dev_info.hh_lock,
+				irq_flags);
+		}
+		break;
+
+	case DFE_IOCTL_READ_REGISTER_ARRAY:
+	case DFE_IOCTL_WRITE_REGISTER_ARRAY:
+		{
+			struct dfe_read_write_array_param param;
+			unsigned int req_sz;
+			unsigned long irq_flags;
+			unsigned int i;
+			void *addr;
+
+			if (copy_from_user(&param, argp, sizeof param))
+				return -EFAULT;
+			if (!HH_OFFSET_VALID(param.offset))
+				return -EINVAL;
+			if (param.num == 0)
+				break;
+			req_sz = sizeof(unsigned int) * param.num;
+
+			if (pdfi->array_num < param.num) {
+				void *pmem;
+
+				pmem = kmalloc(req_sz, GFP_KERNEL);
+				if (pmem == NULL)
+					return -ENOMEM;
+				pdfi->parray = (unsigned int *) pmem;
+				pdfi->array_num = param.num;
+			}
+
+			if (cmd == DFE_IOCTL_WRITE_REGISTER_ARRAY)
+				if (copy_from_user(pdfi->parray,
+					param.pArray, req_sz))
+					return -EFAULT;
+
+			addr = HH_REG_IOADDR(param.offset);
+
+			spin_lock_irqsave(&hh_dev_info.hh_lock,
+				irq_flags);
+			for (i = 0; i < param.num; ++i, addr += 4) {
+				if (cmd == DFE_IOCTL_READ_REGISTER_ARRAY)
+					pdfi->parray[i] = __raw_readl(addr);
+				else
+					__raw_writel(pdfi->parray[i], addr);
+			}
+			spin_unlock_irqrestore(&hh_dev_info.hh_lock,
+				irq_flags);
+
+			if (cmd == DFE_IOCTL_READ_REGISTER_ARRAY)
+				if (copy_to_user(pdfi->parray,
+					param.pArray, req_sz))
+					return -EFAULT;
+		}
+		break;
+
+	case DFE_IOCTL_COMMAND:
+		{
+			struct dfe_command_param param;
+			unsigned int req_sz;
+			unsigned long irq_flags;
+			unsigned int i, value;
+			struct dfe_command_entry *pcmd;
+			void *addr;
+
+			if (copy_from_user(&param, argp, sizeof param))
+				return -EFAULT;
+			if (param.num == 0)
+				break;
+			req_sz = sizeof(struct dfe_command_entry) * param.num;
+
+			if (pdfi->cmd_num < param.num) {
+				void *pmem;
+
+				pmem = kmalloc(req_sz, GFP_KERNEL);
+				if (pmem == NULL)
+					return -ENOMEM;
+				pdfi->pcmd = (struct dfe_command_entry *) pmem;
+				pdfi->cmd_num = param.num;
+			}
+
+			if (copy_from_user(pdfi->pcmd, param.pEntry, req_sz))
+				return -EFAULT;
+
+			pcmd = pdfi->pcmd;
+
+			spin_lock_irqsave(&hh_dev_info.hh_lock,
+				irq_flags);
+			for (i = 0; i < param.num; ++i, ++pcmd) {
+				if (!HH_OFFSET_VALID(pcmd->offset))
+					return -EINVAL;
+				addr = HH_REG_IOADDR(pcmd->offset);
+
+				switch (pcmd->code) {
+				case DFE_IOCTL_COMMAND_CODE_WRITE:
+					__raw_writel(pcmd->value, addr);
+					break;
+				case DFE_IOCTL_COMMAND_CODE_WRITE_WITH_MASK:
+					value = __raw_readl(addr);
+					value &= ~pcmd->mask;
+					value |= pcmd->value & pcmd->mask;
+					__raw_writel(value, addr);
+					break;
+				}
+			}
+			spin_unlock_irqrestore(&hh_dev_info.hh_lock,
+				irq_flags);
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static unsigned int hh_poll(struct file *filp,
+	struct poll_table_struct *wait)
+{
+	unsigned mask = 0;
+
+	if (!HH_IRQ_FIFO_EMPTY(&hh_dev_info))
+		mask |= POLLIN;
+
+	if (mask == 0) {
+		poll_wait(filp, &hh_dev_info.wq, wait);
+		if (!HH_IRQ_FIFO_EMPTY(&hh_dev_info))
+			mask |= POLLIN;
+	}
+
+	return mask;
+}
+
+static const struct file_operations hh_fops = {
+	.owner = THIS_MODULE,
+	.open = hh_open,
+	.release = hh_release,
+	.read = hh_read,
+	.write = hh_write,
+	.unlocked_ioctl = hh_ioctl,
+	.poll = hh_poll,
+};
+
+/*
+ * Interrupt handling
+ */
+
+static irqreturn_t hh_irq_handler(int irq, void *data)
+{
+	unsigned int irq_enable, irq_flag, irq_mask;
+	int i;
+
+	irq_enable = __raw_readl(HH_REG_SCPN_IREQ_MASK);
+	irq_flag = __raw_readl(HH_REG_SCPN_IREQ_FLAG);
+	irq_flag &= irq_enable;
+
+	/* Disables interrupts */
+	irq_enable &= ~irq_flag;
+	__raw_writel(irq_enable, HH_REG_SCPN_IREQ_MASK);
+
+	/* Adds the pending interrupts to irq_fifo */
+	spin_lock(&hh_dev_info.hh_lock);
+	for (i = 0, irq_mask = 1; i < 32; ++i, irq_mask <<= 1) {
+		if (HH_IRQ_FIFO_FULL(&hh_dev_info))
+			break;
+		if (irq_flag & irq_mask) {
+			hh_dev_info.irq_fifo[hh_dev_info.irq_fifo_tail] = \
+				(char) i;
+			if (++hh_dev_info.irq_fifo_tail == HH_IRQ_FIFO_SIZE)
+				hh_dev_info.irq_fifo_tail = 0;
+		}
+	}
+	spin_unlock(&hh_dev_info.hh_lock);
+
+	/* Wakes up pending processes */
+	wake_up_interruptible(&hh_dev_info.wq);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * Driver initialization & cleanup
+ */
+
+static struct miscdevice hh_misc_dev = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = DFE_HH_DEVICE_NAME,
+	.fops = &hh_fops,
+};
+
+static int __init hh_init(void)
+{
+	int ret;
+
+	/* lock initialization */
+	spin_lock_init(&hh_dev_info.hh_lock);
+
+	/* interrupt handler */
+	hh_dev_info.irq_fifo_head = 0;
+	hh_dev_info.irq_fifo_tail = 0;
+	ret = request_irq(INT_HH_SUPSS_IRQ, hh_irq_handler,
+		IRQF_TRIGGER_RISING, "hh_dev", 0);
+	if (ret < 0) {
+		pr_err("Cannot register HH interrupt handler.\n");
+		return ret;
+	}
+
+	/* wait queue */
+	init_waitqueue_head(&hh_dev_info.wq);
+
+	return misc_register(&hh_misc_dev);
+}
+
+static void __exit hh_exit(void)
+{
+	misc_deregister(&hh_misc_dev);
+	free_irq(INT_HH_SUPSS_IRQ, 0);
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Rohit Vaswani <rvaswani@codeaurora.org>");
+MODULE_DESCRIPTION("Qualcomm Hammerhead Digital Front End driver");
+MODULE_VERSION("1.0");
+
+module_init(hh_init);
+module_exit(hh_exit);
+
diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c
index 02cae5e..d3b2274 100644
--- a/arch/arm/mach-msm/dma.c
+++ b/arch/arm/mach-msm/dma.c
@@ -1,6 +1,7 @@
 /* linux/arch/arm/mach-msm/dma.c
  *
  * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008-2010, 2012 Code Aurora Forum. 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
@@ -17,10 +18,190 @@
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/interrupt.h>
-#include <linux/completion.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/pm_runtime.h>
 #include <mach/dma.h>
 
+#define MODULE_NAME "msm_dmov"
+
 #define MSM_DMOV_CHANNEL_COUNT 16
+#define MSM_DMOV_CRCI_COUNT 16
+
+enum {
+	CLK_DIS,
+	CLK_TO_BE_DIS,
+	CLK_EN
+};
+
+struct msm_dmov_ci_conf {
+	int start;
+	int end;
+	int burst;
+};
+
+struct msm_dmov_crci_conf {
+	int sd;
+	int blk_size;
+};
+
+struct msm_dmov_chan_conf {
+	int sd;
+	int block;
+	int priority;
+};
+
+struct msm_dmov_conf {
+	void *base;
+	struct msm_dmov_crci_conf *crci_conf;
+	struct msm_dmov_chan_conf *chan_conf;
+	int channel_active;
+	int sd;
+	size_t sd_size;
+	struct list_head ready_commands[MSM_DMOV_CHANNEL_COUNT];
+	struct list_head active_commands[MSM_DMOV_CHANNEL_COUNT];
+	spinlock_t lock;
+	unsigned int irq;
+	struct clk *clk;
+	struct clk *pclk;
+	struct clk *ebiclk;
+	unsigned int clk_ctl;
+	struct timer_list timer;
+};
+
+static void msm_dmov_clock_timer(unsigned long);
+static int msm_dmov_clk_toggle(int, int);
+
+#ifdef CONFIG_ARCH_MSM8X60
+
+#define DMOV_CHANNEL_DEFAULT_CONF { .sd = 1, .block = 0, .priority = 0 }
+#define DMOV_CHANNEL_MODEM_CONF { .sd = 3, .block = 0, .priority = 0 }
+#define DMOV_CHANNEL_CONF(secd, blk, pri) \
+	{ .sd = secd, .block = blk, .priority = pri }
+
+static struct msm_dmov_chan_conf adm0_chan_conf[] = {
+	DMOV_CHANNEL_DEFAULT_CONF,
+	DMOV_CHANNEL_DEFAULT_CONF,
+	DMOV_CHANNEL_DEFAULT_CONF,
+	DMOV_CHANNEL_DEFAULT_CONF,
+	DMOV_CHANNEL_DEFAULT_CONF,
+	DMOV_CHANNEL_DEFAULT_CONF,
+	DMOV_CHANNEL_DEFAULT_CONF,
+	DMOV_CHANNEL_DEFAULT_CONF,
+	DMOV_CHANNEL_DEFAULT_CONF,
+	DMOV_CHANNEL_DEFAULT_CONF,
+	DMOV_CHANNEL_MODEM_CONF,
+	DMOV_CHANNEL_MODEM_CONF,
+	DMOV_CHANNEL_MODEM_CONF,
+	DMOV_CHANNEL_MODEM_CONF,
+	DMOV_CHANNEL_MODEM_CONF,
+	DMOV_CHANNEL_DEFAULT_CONF,
+};
+
+static struct msm_dmov_chan_conf adm1_chan_conf[] = {
+	DMOV_CHANNEL_DEFAULT_CONF,
+	DMOV_CHANNEL_DEFAULT_CONF,
+	DMOV_CHANNEL_DEFAULT_CONF,
+	DMOV_CHANNEL_DEFAULT_CONF,
+	DMOV_CHANNEL_DEFAULT_CONF,
+	DMOV_CHANNEL_DEFAULT_CONF,
+	DMOV_CHANNEL_DEFAULT_CONF,
+	DMOV_CHANNEL_DEFAULT_CONF,
+	DMOV_CHANNEL_DEFAULT_CONF,
+	DMOV_CHANNEL_DEFAULT_CONF,
+	DMOV_CHANNEL_MODEM_CONF,
+	DMOV_CHANNEL_MODEM_CONF,
+	DMOV_CHANNEL_MODEM_CONF,
+	DMOV_CHANNEL_MODEM_CONF,
+	DMOV_CHANNEL_MODEM_CONF,
+	DMOV_CHANNEL_MODEM_CONF,
+};
+
+#define DMOV_CRCI_DEFAULT_CONF { .sd = 1, .blk_size = 0 }
+#define DMOV_CRCI_CONF(secd, blk) { .sd = secd, .blk_size = blk }
+
+static struct msm_dmov_crci_conf adm0_crci_conf[] = {
+	DMOV_CRCI_DEFAULT_CONF,
+	DMOV_CRCI_DEFAULT_CONF,
+	DMOV_CRCI_DEFAULT_CONF,
+	DMOV_CRCI_DEFAULT_CONF,
+	DMOV_CRCI_DEFAULT_CONF,
+	DMOV_CRCI_DEFAULT_CONF,
+	DMOV_CRCI_CONF(1, 4),
+	DMOV_CRCI_DEFAULT_CONF,
+	DMOV_CRCI_DEFAULT_CONF,
+	DMOV_CRCI_DEFAULT_CONF,
+	DMOV_CRCI_DEFAULT_CONF,
+	DMOV_CRCI_DEFAULT_CONF,
+	DMOV_CRCI_DEFAULT_CONF,
+	DMOV_CRCI_DEFAULT_CONF,
+	DMOV_CRCI_DEFAULT_CONF,
+	DMOV_CRCI_DEFAULT_CONF,
+};
+
+static struct msm_dmov_crci_conf adm1_crci_conf[] = {
+	DMOV_CRCI_DEFAULT_CONF,
+	DMOV_CRCI_CONF(1, 1),
+	DMOV_CRCI_CONF(1, 1),
+	DMOV_CRCI_DEFAULT_CONF,
+	DMOV_CRCI_CONF(1, 1),
+	DMOV_CRCI_CONF(1, 1),
+	DMOV_CRCI_DEFAULT_CONF,
+	DMOV_CRCI_DEFAULT_CONF,
+	DMOV_CRCI_DEFAULT_CONF,
+	DMOV_CRCI_DEFAULT_CONF,
+	DMOV_CRCI_DEFAULT_CONF,
+	DMOV_CRCI_DEFAULT_CONF,
+	DMOV_CRCI_DEFAULT_CONF,
+	DMOV_CRCI_DEFAULT_CONF,
+	DMOV_CRCI_CONF(1, 1),
+	DMOV_CRCI_DEFAULT_CONF,
+};
+
+static struct msm_dmov_conf dmov_conf[] = {
+	{
+		.crci_conf = adm0_crci_conf,
+		.chan_conf = adm0_chan_conf,
+		.lock = __SPIN_LOCK_UNLOCKED(dmov_lock),
+		.clk_ctl = CLK_DIS,
+		.timer = TIMER_INITIALIZER(msm_dmov_clock_timer, 0, 0),
+	}, {
+		.crci_conf = adm1_crci_conf,
+		.chan_conf = adm1_chan_conf,
+		.lock = __SPIN_LOCK_UNLOCKED(dmov_lock),
+		.clk_ctl = CLK_DIS,
+		.timer = TIMER_INITIALIZER(msm_dmov_clock_timer, 0, 1),
+	}
+};
+#else
+static struct msm_dmov_conf dmov_conf[] = {
+	{
+		.crci_conf = NULL,
+		.chan_conf = NULL,
+		.lock = __SPIN_LOCK_UNLOCKED(dmov_lock),
+		.clk_ctl = CLK_DIS,
+		.timer = TIMER_INITIALIZER(msm_dmov_clock_timer, 0, 0),
+	}
+};
+#endif
+
+#define MSM_DMOV_ID_COUNT (MSM_DMOV_CHANNEL_COUNT * ARRAY_SIZE(dmov_conf))
+#define DMOV_REG(name, adm)    ((name) + (dmov_conf[adm].base) +\
+	(dmov_conf[adm].sd * dmov_conf[adm].sd_size))
+#define DMOV_ID_TO_ADM(id)   ((id) / MSM_DMOV_CHANNEL_COUNT)
+#define DMOV_ID_TO_CHAN(id)   ((id) % MSM_DMOV_CHANNEL_COUNT)
+#define DMOV_CHAN_ADM_TO_ID(ch, adm) ((ch) + (adm) * MSM_DMOV_CHANNEL_COUNT)
+
+#ifdef CONFIG_MSM_ADM3
+#define DMOV_IRQ_TO_ADM(irq)   \
+({ \
+	typeof(irq) _irq = irq; \
+	((_irq == INT_ADM1_MASTER) || (_irq == INT_ADM1_AARM)); \
+})
+#else
+#define DMOV_IRQ_TO_ADM(irq) 0
+#endif
 
 enum {
 	MSM_DMOV_PRINT_ERRORS = 1,
@@ -28,11 +209,6 @@
 	MSM_DMOV_PRINT_FLOW = 4
 };
 
-static DEFINE_SPINLOCK(msm_dmov_lock);
-static struct clk *msm_dmov_clk;
-static unsigned int channel_active;
-static struct list_head ready_commands[MSM_DMOV_CHANNEL_COUNT];
-static struct list_head active_commands[MSM_DMOV_CHANNEL_COUNT];
 unsigned int msm_dmov_print_mask = MSM_DMOV_PRINT_ERRORS;
 
 #define MSM_DMOV_DPRINTF(mask, format, args...) \
@@ -47,48 +223,122 @@
 #define PRINT_FLOW(format, args...) \
 	MSM_DMOV_DPRINTF(MSM_DMOV_PRINT_FLOW, format, args);
 
-void msm_dmov_stop_cmd(unsigned id, struct msm_dmov_cmd *cmd, int graceful)
+static int msm_dmov_clk_toggle(int adm, int on)
 {
-	writel((graceful << 31), DMOV_FLUSH0(id));
+	int ret = 0;
+
+	if (on) {
+		ret = clk_enable(dmov_conf[adm].clk);
+		if (ret)
+			goto err;
+		if (dmov_conf[adm].pclk) {
+			ret = clk_enable(dmov_conf[adm].pclk);
+			if (ret) {
+				clk_disable(dmov_conf[adm].clk);
+				goto err;
+			}
+		}
+		if (dmov_conf[adm].ebiclk) {
+			ret = clk_enable(dmov_conf[adm].ebiclk);
+			if (ret) {
+				if (dmov_conf[adm].pclk)
+					clk_disable(dmov_conf[adm].pclk);
+				clk_disable(dmov_conf[adm].clk);
+			}
+		}
+	} else {
+		clk_disable(dmov_conf[adm].clk);
+		if (dmov_conf[adm].pclk)
+			clk_disable(dmov_conf[adm].pclk);
+		if (dmov_conf[adm].ebiclk)
+			clk_disable(dmov_conf[adm].ebiclk);
+	}
+err:
+	return ret;
 }
 
-void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd)
+static void msm_dmov_clock_timer(unsigned long adm)
+{
+	unsigned long irq_flags;
+	spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
+	if (dmov_conf[adm].clk_ctl == CLK_TO_BE_DIS) {
+		BUG_ON(dmov_conf[adm].channel_active);
+		msm_dmov_clk_toggle(adm, 0);
+		dmov_conf[adm].clk_ctl = CLK_DIS;
+	}
+	spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
+}
+
+void msm_dmov_enqueue_cmd_ext(unsigned id, struct msm_dmov_cmd *cmd)
 {
 	unsigned long irq_flags;
 	unsigned int status;
+	int adm = DMOV_ID_TO_ADM(id);
+	int ch = DMOV_ID_TO_CHAN(id);
 
-	spin_lock_irqsave(&msm_dmov_lock, irq_flags);
-	if (!channel_active)
-		clk_enable(msm_dmov_clk);
-	dsb();
-	status = readl(DMOV_STATUS(id));
-	if (list_empty(&ready_commands[id]) &&
-		(status & DMOV_STATUS_CMD_PTR_RDY)) {
-#if 0
-		if (list_empty(&active_commands[id])) {
-			PRINT_FLOW("msm_dmov_enqueue_cmd(%d), enable interrupt\n", id);
-			writel(DMOV_CONFIG_IRQ_EN, DMOV_CONFIG(id));
-		}
-#endif
-		if (cmd->execute_func)
-			cmd->execute_func(cmd);
-		PRINT_IO("msm_dmov_enqueue_cmd(%d), start command, status %x\n", id, status);
-		list_add_tail(&cmd->list, &active_commands[id]);
-		if (!channel_active)
-			enable_irq(INT_ADM_AARM);
-		channel_active |= 1U << id;
-		writel(cmd->cmdptr, DMOV_CMD_PTR(id));
+	spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
+	if (dmov_conf[adm].clk_ctl == CLK_DIS) {
+		status = msm_dmov_clk_toggle(adm, 1);
+		if (status != 0)
+			goto error;
+	} else if (dmov_conf[adm].clk_ctl == CLK_TO_BE_DIS)
+		del_timer(&dmov_conf[adm].timer);
+	dmov_conf[adm].clk_ctl = CLK_EN;
+
+	status = readl_relaxed(DMOV_REG(DMOV_STATUS(ch), adm));
+	if (status & DMOV_STATUS_CMD_PTR_RDY) {
+		PRINT_IO("msm_dmov_enqueue_cmd(%d), start command, status %x\n",
+			id, status);
+		if (cmd->exec_func)
+			cmd->exec_func(cmd);
+		list_add_tail(&cmd->list, &dmov_conf[adm].active_commands[ch]);
+		if (!dmov_conf[adm].channel_active)
+			enable_irq(dmov_conf[adm].irq);
+		dmov_conf[adm].channel_active |= 1U << ch;
+		PRINT_IO("Writing %x exactly to register", cmd->cmdptr);
+		writel_relaxed(cmd->cmdptr, DMOV_REG(DMOV_CMD_PTR(ch), adm));
 	} else {
-		if (!channel_active)
-			clk_disable(msm_dmov_clk);
-		if (list_empty(&active_commands[id]))
-			PRINT_ERROR("msm_dmov_enqueue_cmd(%d), error datamover stalled, status %x\n", id, status);
-
-		PRINT_IO("msm_dmov_enqueue_cmd(%d), enqueue command, status %x\n", id, status);
-		list_add_tail(&cmd->list, &ready_commands[id]);
+		if (!dmov_conf[adm].channel_active) {
+			dmov_conf[adm].clk_ctl = CLK_TO_BE_DIS;
+			mod_timer(&dmov_conf[adm].timer, jiffies + HZ);
+		}
+		if (list_empty(&dmov_conf[adm].active_commands[ch]))
+			PRINT_ERROR("msm_dmov_enqueue_cmd_ext(%d), stalled, "
+				"status %x\n", id, status);
+		PRINT_IO("msm_dmov_enqueue_cmd(%d), enqueue command, status "
+		    "%x\n", id, status);
+		list_add_tail(&cmd->list, &dmov_conf[adm].ready_commands[ch]);
 	}
-	spin_unlock_irqrestore(&msm_dmov_lock, irq_flags);
+error:
+	spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
 }
+EXPORT_SYMBOL(msm_dmov_enqueue_cmd_ext);
+
+void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd)
+{
+	/* Disable callback function (for backwards compatibility) */
+	cmd->exec_func = NULL;
+
+	msm_dmov_enqueue_cmd_ext(id, cmd);
+}
+EXPORT_SYMBOL(msm_dmov_enqueue_cmd);
+
+void msm_dmov_flush(unsigned int id, int graceful)
+{
+	unsigned long irq_flags;
+	int ch = DMOV_ID_TO_CHAN(id);
+	int adm = DMOV_ID_TO_ADM(id);
+	int flush = graceful ? DMOV_FLUSH_TYPE : 0;
+	spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
+	/* XXX not checking if flush cmd sent already */
+	if (!list_empty(&dmov_conf[adm].active_commands[ch])) {
+		PRINT_IO("msm_dmov_flush(%d), send flush cmd\n", id);
+		writel_relaxed(flush, DMOV_REG(DMOV_FLUSH0(ch), adm));
+	}
+	/* spin_unlock_irqrestore has the necessary barrier */
+	spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
+}
+EXPORT_SYMBOL(msm_dmov_flush);
 
 struct msm_dmov_exec_cmdptr_cmd {
 	struct msm_dmov_cmd dmov_cmd;
@@ -119,12 +369,13 @@
 
 	cmd.dmov_cmd.cmdptr = cmdptr;
 	cmd.dmov_cmd.complete_func = dmov_exec_cmdptr_complete_func;
-	cmd.dmov_cmd.execute_func = NULL;
+	cmd.dmov_cmd.exec_func = NULL;
 	cmd.id = id;
+	cmd.result = 0;
 	init_completion(&cmd.complete);
 
 	msm_dmov_enqueue_cmd(id, &cmd.dmov_cmd);
-	wait_for_completion(&cmd.complete);
+	wait_for_completion_io(&cmd.complete);
 
 	if (cmd.result != 0x80000002) {
 		PRINT_ERROR("dmov_exec_cmdptr(%d): ERROR, result: %x\n", id, cmd.result);
@@ -135,40 +386,61 @@
 	PRINT_FLOW("dmov_exec_cmdptr(%d, %x) done\n", id, cmdptr);
 	return 0;
 }
+EXPORT_SYMBOL(msm_dmov_exec_cmd);
 
+static void fill_errdata(struct msm_dmov_errdata *errdata, int ch, int adm)
+{
+	errdata->flush[0] = readl_relaxed(DMOV_REG(DMOV_FLUSH0(ch), adm));
+	errdata->flush[1] = readl_relaxed(DMOV_REG(DMOV_FLUSH1(ch), adm));
+	errdata->flush[2] = 0;
+	errdata->flush[3] = readl_relaxed(DMOV_REG(DMOV_FLUSH3(ch), adm));
+	errdata->flush[4] = readl_relaxed(DMOV_REG(DMOV_FLUSH4(ch), adm));
+	errdata->flush[5] = readl_relaxed(DMOV_REG(DMOV_FLUSH5(ch), adm));
+}
 
 static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id)
 {
-	unsigned int int_status, mask, id;
+	unsigned int int_status;
+	unsigned int mask;
+	unsigned int id;
+	unsigned int ch;
 	unsigned long irq_flags;
 	unsigned int ch_status;
 	unsigned int ch_result;
+	unsigned int valid = 0;
 	struct msm_dmov_cmd *cmd;
+	int adm = DMOV_IRQ_TO_ADM(irq);
 
-	spin_lock_irqsave(&msm_dmov_lock, irq_flags);
-
-	int_status = readl(DMOV_ISR); /* read and clear interrupt */
+	spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
+	/* read and clear isr */
+	int_status = readl_relaxed(DMOV_REG(DMOV_ISR, adm));
 	PRINT_FLOW("msm_datamover_irq_handler: DMOV_ISR %x\n", int_status);
 
 	while (int_status) {
 		mask = int_status & -int_status;
-		id = fls(mask) - 1;
+		ch = fls(mask) - 1;
+		id = DMOV_CHAN_ADM_TO_ID(ch, adm);
 		PRINT_FLOW("msm_datamover_irq_handler %08x %08x id %d\n", int_status, mask, id);
 		int_status &= ~mask;
-		ch_status = readl(DMOV_STATUS(id));
+		ch_status = readl_relaxed(DMOV_REG(DMOV_STATUS(ch), adm));
 		if (!(ch_status & DMOV_STATUS_RSLT_VALID)) {
-			PRINT_FLOW("msm_datamover_irq_handler id %d, result not valid %x\n", id, ch_status);
+			PRINT_FLOW("msm_datamover_irq_handler id %d, "
+				"result not valid %x\n", id, ch_status);
 			continue;
 		}
 		do {
-			ch_result = readl(DMOV_RSLT(id));
-			if (list_empty(&active_commands[id])) {
+			valid = 1;
+			ch_result = readl_relaxed(DMOV_REG(DMOV_RSLT(ch), adm));
+			if (list_empty(&dmov_conf[adm].active_commands[ch])) {
 				PRINT_ERROR("msm_datamover_irq_handler id %d, got result "
 					"with no active command, status %x, result %x\n",
 					id, ch_status, ch_result);
 				cmd = NULL;
-			} else
-				cmd = list_entry(active_commands[id].next, typeof(*cmd), list);
+			} else {
+				cmd = list_entry(dmov_conf[adm].
+					active_commands[ch].next, typeof(*cmd),
+					list);
+			}
 			PRINT_FLOW("msm_datamover_irq_handler id %d, status %x, result %x\n", id, ch_status, ch_result);
 			if (ch_result & DMOV_RSLT_DONE) {
 				PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n",
@@ -177,95 +449,253 @@
 					"for %p, result %x\n", id, cmd, ch_result);
 				if (cmd) {
 					list_del(&cmd->list);
-					dsb();
 					cmd->complete_func(cmd, ch_result, NULL);
 				}
 			}
 			if (ch_result & DMOV_RSLT_FLUSH) {
 				struct msm_dmov_errdata errdata;
 
-				errdata.flush[0] = readl(DMOV_FLUSH0(id));
-				errdata.flush[1] = readl(DMOV_FLUSH1(id));
-				errdata.flush[2] = readl(DMOV_FLUSH2(id));
-				errdata.flush[3] = readl(DMOV_FLUSH3(id));
-				errdata.flush[4] = readl(DMOV_FLUSH4(id));
-				errdata.flush[5] = readl(DMOV_FLUSH5(id));
+				fill_errdata(&errdata, ch, adm);
 				PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status);
 				PRINT_FLOW("msm_datamover_irq_handler id %d, flush, result %x, flush0 %x\n", id, ch_result, errdata.flush[0]);
 				if (cmd) {
 					list_del(&cmd->list);
-					dsb();
 					cmd->complete_func(cmd, ch_result, &errdata);
 				}
 			}
 			if (ch_result & DMOV_RSLT_ERROR) {
 				struct msm_dmov_errdata errdata;
 
-				errdata.flush[0] = readl(DMOV_FLUSH0(id));
-				errdata.flush[1] = readl(DMOV_FLUSH1(id));
-				errdata.flush[2] = readl(DMOV_FLUSH2(id));
-				errdata.flush[3] = readl(DMOV_FLUSH3(id));
-				errdata.flush[4] = readl(DMOV_FLUSH4(id));
-				errdata.flush[5] = readl(DMOV_FLUSH5(id));
+				fill_errdata(&errdata, ch, adm);
 
 				PRINT_ERROR("msm_datamover_irq_handler id %d, status %x\n", id, ch_status);
 				PRINT_ERROR("msm_datamover_irq_handler id %d, error, result %x, flush0 %x\n", id, ch_result, errdata.flush[0]);
 				if (cmd) {
 					list_del(&cmd->list);
-					dsb();
 					cmd->complete_func(cmd, ch_result, &errdata);
 				}
 				/* this does not seem to work, once we get an error */
 				/* the datamover will no longer accept commands */
-				writel(0, DMOV_FLUSH0(id));
+				writel_relaxed(0, DMOV_REG(DMOV_FLUSH0(ch),
+					       adm));
 			}
-			ch_status = readl(DMOV_STATUS(id));
+			rmb();
+			ch_status = readl_relaxed(DMOV_REG(DMOV_STATUS(ch),
+						  adm));
 			PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status);
-			if ((ch_status & DMOV_STATUS_CMD_PTR_RDY) && !list_empty(&ready_commands[id])) {
-				cmd = list_entry(ready_commands[id].next, typeof(*cmd), list);
+			if ((ch_status & DMOV_STATUS_CMD_PTR_RDY) &&
+			    !list_empty(&dmov_conf[adm].ready_commands[ch])) {
+				cmd = list_entry(dmov_conf[adm].
+					ready_commands[ch].next, typeof(*cmd),
+					list);
 				list_del(&cmd->list);
-				list_add_tail(&cmd->list, &active_commands[id]);
-				if (cmd->execute_func)
-					cmd->execute_func(cmd);
-				PRINT_FLOW("msm_datamover_irq_handler id %d, start command\n", id);
-				writel(cmd->cmdptr, DMOV_CMD_PTR(id));
+				if (cmd->exec_func)
+					cmd->exec_func(cmd);
+				list_add_tail(&cmd->list,
+					&dmov_conf[adm].active_commands[ch]);
+				PRINT_FLOW("msm_datamover_irq_handler id %d,"
+						 "start command\n", id);
+				writel_relaxed(cmd->cmdptr,
+					       DMOV_REG(DMOV_CMD_PTR(ch), adm));
 			}
 		} while (ch_status & DMOV_STATUS_RSLT_VALID);
-		if (list_empty(&active_commands[id]) && list_empty(&ready_commands[id]))
-			channel_active &= ~(1U << id);
+		if (list_empty(&dmov_conf[adm].active_commands[ch]) &&
+				list_empty(&dmov_conf[adm].ready_commands[ch]))
+			dmov_conf[adm].channel_active &= ~(1U << ch);
 		PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status);
 	}
 
-	if (!channel_active) {
-		disable_irq_nosync(INT_ADM_AARM);
-		clk_disable(msm_dmov_clk);
+	if (!dmov_conf[adm].channel_active && valid) {
+		disable_irq_nosync(dmov_conf[adm].irq);
+		dmov_conf[adm].clk_ctl = CLK_TO_BE_DIS;
+		mod_timer(&dmov_conf[adm].timer, jiffies + HZ);
 	}
 
-	spin_unlock_irqrestore(&msm_dmov_lock, irq_flags);
-	return IRQ_HANDLED;
+	spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
+	return valid ? IRQ_HANDLED : IRQ_NONE;
 }
 
-static int __init msm_init_datamover(void)
+static int msm_dmov_suspend_late(struct device *dev)
 {
-	int i;
-	int ret;
-	struct clk *clk;
-
-	for (i = 0; i < MSM_DMOV_CHANNEL_COUNT; i++) {
-		INIT_LIST_HEAD(&ready_commands[i]);
-		INIT_LIST_HEAD(&active_commands[i]);
-		writel(DMOV_CONFIG_IRQ_EN | DMOV_CONFIG_FORCE_TOP_PTR_RSLT | DMOV_CONFIG_FORCE_FLUSH_RSLT, DMOV_CONFIG(i));
+	unsigned long irq_flags;
+	struct platform_device *pdev = to_platform_device(dev);
+	int adm = (pdev->id >= 0) ? pdev->id : 0;
+	spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
+	if (dmov_conf[adm].clk_ctl == CLK_TO_BE_DIS) {
+		BUG_ON(dmov_conf[adm].channel_active);
+		del_timer(&dmov_conf[adm].timer);
+		msm_dmov_clk_toggle(adm, 0);
+		dmov_conf[adm].clk_ctl = CLK_DIS;
 	}
-	clk = clk_get(NULL, "adm_clk");
-	if (IS_ERR(clk))
-		return PTR_ERR(clk);
-	msm_dmov_clk = clk;
-	ret = request_irq(INT_ADM_AARM, msm_datamover_irq_handler, 0, "msmdatamover", NULL);
-	if (ret)
-		return ret;
-	disable_irq(INT_ADM_AARM);
+	spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
 	return 0;
 }
 
-arch_initcall(msm_init_datamover);
+static int msm_dmov_runtime_suspend(struct device *dev)
+{
+	dev_dbg(dev, "pm_runtime: suspending...\n");
+	return 0;
+}
 
+static int msm_dmov_runtime_resume(struct device *dev)
+{
+	dev_dbg(dev, "pm_runtime: resuming...\n");
+	return 0;
+}
+
+static int msm_dmov_runtime_idle(struct device *dev)
+{
+	dev_dbg(dev, "pm_runtime: idling...\n");
+	return 0;
+}
+
+static struct dev_pm_ops msm_dmov_dev_pm_ops = {
+	.runtime_suspend = msm_dmov_runtime_suspend,
+	.runtime_resume = msm_dmov_runtime_resume,
+	.runtime_idle = msm_dmov_runtime_idle,
+	.suspend = msm_dmov_suspend_late,
+};
+
+static int msm_dmov_init_clocks(struct platform_device *pdev)
+{
+	int adm = (pdev->id >= 0) ? pdev->id : 0;
+	int ret;
+
+	dmov_conf[adm].clk = clk_get(&pdev->dev, "core_clk");
+	if (IS_ERR(dmov_conf[adm].clk)) {
+		printk(KERN_ERR "%s: Error getting adm_clk\n", __func__);
+		dmov_conf[adm].clk = NULL;
+		return -ENOENT;
+	}
+
+	dmov_conf[adm].pclk = clk_get(&pdev->dev, "iface_clk");
+	if (IS_ERR(dmov_conf[adm].pclk)) {
+		dmov_conf[adm].pclk = NULL;
+		/* pclk not present on all SoCs, don't bail on failure */
+	}
+
+	dmov_conf[adm].ebiclk = clk_get(&pdev->dev, "mem_clk");
+	if (IS_ERR(dmov_conf[adm].ebiclk)) {
+		dmov_conf[adm].ebiclk = NULL;
+		/* ebiclk not present on all SoCs, don't bail on failure */
+	} else {
+		ret = clk_set_rate(dmov_conf[adm].ebiclk, 27000000);
+		if (ret)
+			return -ENOENT;
+	}
+
+	return 0;
+}
+
+static void config_datamover(int adm)
+{
+#ifdef CONFIG_MSM_ADM3
+	int i;
+	for (i = 0; i < MSM_DMOV_CHANNEL_COUNT; i++) {
+		struct msm_dmov_chan_conf *chan_conf =
+			dmov_conf[adm].chan_conf;
+		unsigned conf;
+		/* Only configure scorpion channels */
+		if (chan_conf[i].sd <= 1) {
+			conf = readl_relaxed(DMOV_REG(DMOV_CONF(i), adm));
+			conf &= ~DMOV_CONF_SD(7);
+			conf |= DMOV_CONF_SD(chan_conf[i].sd);
+			writel_relaxed(conf | DMOV_CONF_SHADOW_EN,
+			       DMOV_REG(DMOV_CONF(i), adm));
+		}
+	}
+	for (i = 0; i < MSM_DMOV_CRCI_COUNT; i++) {
+		struct msm_dmov_crci_conf *crci_conf =
+			dmov_conf[adm].crci_conf;
+
+		writel_relaxed(DMOV_CRCI_CTL_BLK_SZ(crci_conf[i].blk_size),
+		       DMOV_REG(DMOV_CRCI_CTL(i), adm));
+	}
+#endif
+}
+
+static int msm_dmov_probe(struct platform_device *pdev)
+{
+	int adm = (pdev->id >= 0) ? pdev->id : 0;
+	int i;
+	int ret;
+	struct msm_dmov_pdata *pdata = pdev->dev.platform_data;
+	struct resource *irqres =
+		platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	struct resource *mres =
+		platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	if (pdata) {
+		dmov_conf[adm].sd = pdata->sd;
+		dmov_conf[adm].sd_size = pdata->sd_size;
+	}
+	if (!dmov_conf[adm].sd_size)
+		return -ENXIO;
+
+	if (!irqres || !irqres->start)
+		return -ENXIO;
+	dmov_conf[adm].irq = irqres->start;
+
+	if (!mres || !mres->start)
+		return -ENXIO;
+	dmov_conf[adm].base = ioremap_nocache(mres->start, resource_size(mres));
+	if (!dmov_conf[adm].base)
+		return -ENOMEM;
+
+	ret = request_irq(dmov_conf[adm].irq, msm_datamover_irq_handler,
+		0, "msmdatamover", NULL);
+	if (ret) {
+		PRINT_ERROR("Requesting ADM%d irq %d failed\n", adm,
+			dmov_conf[adm].irq);
+		goto out_map;
+	}
+	disable_irq(dmov_conf[adm].irq);
+	ret = msm_dmov_init_clocks(pdev);
+	if (ret) {
+		PRINT_ERROR("Requesting ADM%d clocks failed\n", adm);
+		goto out_irq;
+	}
+	ret = msm_dmov_clk_toggle(adm, 1);
+	if (ret) {
+		PRINT_ERROR("Enabling ADM%d clocks failed\n", adm);
+		goto out_irq;
+	}
+
+	config_datamover(adm);
+	for (i = 0; i < MSM_DMOV_CHANNEL_COUNT; i++) {
+		INIT_LIST_HEAD(&dmov_conf[adm].ready_commands[i]);
+		INIT_LIST_HEAD(&dmov_conf[adm].active_commands[i]);
+
+		writel_relaxed(DMOV_RSLT_CONF_IRQ_EN
+		     | DMOV_RSLT_CONF_FORCE_FLUSH_RSLT,
+		     DMOV_REG(DMOV_RSLT_CONF(i), adm));
+	}
+	wmb();
+	msm_dmov_clk_toggle(adm, 0);
+	return ret;
+out_irq:
+	free_irq(dmov_conf[adm].irq, NULL);
+out_map:
+	iounmap(dmov_conf[adm].base);
+	return ret;
+}
+
+static struct platform_driver msm_dmov_driver = {
+	.probe = msm_dmov_probe,
+	.driver = {
+		.name = MODULE_NAME,
+		.owner = THIS_MODULE,
+		.pm = &msm_dmov_dev_pm_ops,
+	},
+};
+
+/* static int __init */
+static int __init msm_init_datamover(void)
+{
+	int ret;
+	ret = platform_driver_register(&msm_dmov_driver);
+	if (ret)
+		return ret;
+	return 0;
+}
+arch_initcall(msm_init_datamover);
diff --git a/arch/arm/mach-msm/dma_test.c b/arch/arm/mach-msm/dma_test.c
new file mode 100644
index 0000000..de1ee0a
--- /dev/null
+++ b/arch/arm/mach-msm/dma_test.c
@@ -0,0 +1,360 @@
+/* Copyright (c) 2008-2009, 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/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+
+#include <mach/dma.h>
+#include <mach/dma_test.h>
+
+
+/**********************************************************************
+ * User-space testing of the DMA driver.
+ * Intended to be loaded as a module.  We have a bunch of static
+ * buffers that the user-side can refer to.  The main DMA is simply
+ * used memory-to-memory.  Device DMA is best tested with the specific
+ * device driver in question.
+ */
+#define MAX_TEST_BUFFERS 40
+#define MAX_TEST_BUFFER_SIZE 65536
+static void *(buffers[MAX_TEST_BUFFERS]);
+static int sizes[MAX_TEST_BUFFERS];
+
+/* Anything that allocates or deallocates buffers must lock with this
+ * mutex. */
+static DEFINE_SEMAPHORE(buffer_lock);
+
+/* Each buffer has a semaphore associated with it that will be held
+ * for the duration of any operations on that buffer.  It also must be
+ * available to free the given buffer. */
+static struct semaphore buffer_sems[MAX_TEST_BUFFERS];
+
+#define buffer_up(num)  up(&buffer_sems[num])
+#define buffer_down(num)  down(&buffer_sems[num])
+
+/* Use the General Purpose DMA channel as our test channel.  This channel
+ * should be available on any target. */
+#define TEST_CHANNEL    DMOV_GP_CHAN
+
+struct private {
+	/* Each open instance is allowed a single pending
+	 * operation. */
+	struct semaphore sem;
+
+	/* Simple command buffer.  Allocated and freed by driver. */
+	/* TODO: Allocate these together. */
+	dmov_s *command_ptr;
+
+	/* Indirect. */
+	u32 *command_ptr_ptr;
+
+	/* Indicates completion with pending request. */
+	struct completion complete;
+};
+
+static void free_buffers(void)
+{
+	int i;
+
+	for (i = 0; i < MAX_TEST_BUFFERS; i++) {
+		if (sizes[i] > 0) {
+			kfree(buffers[i]);
+			sizes[i] = 0;
+		}
+	}
+}
+
+/* Copy between two buffers, using the DMA. */
+
+/* Allocate a buffer of a requested size. */
+static int buffer_req(struct msm_dma_alloc_req *req)
+{
+	int i;
+
+	if (req->size <= 0 || req->size > MAX_TEST_BUFFER_SIZE)
+		return -EINVAL;
+
+	down(&buffer_lock);
+
+	/* Find a free buffer. */
+	for (i = 0; i < MAX_TEST_BUFFERS; i++)
+		if (sizes[i] == 0)
+			break;
+
+	if (i >= MAX_TEST_BUFFERS)
+		goto error;
+
+	buffers[i] = kmalloc(req->size, GFP_KERNEL | __GFP_DMA);
+	if (buffers[i] == 0)
+		goto error;
+	sizes[i] = req->size;
+
+	req->bufnum = i;
+
+	up(&buffer_lock);
+	return 0;
+
+error:
+	up(&buffer_lock);
+	return -ENOSPC;
+}
+
+static int dma_scopy(struct msm_dma_scopy *scopy, struct private *priv)
+{
+	int err = 0;
+	dma_addr_t mapped_cmd;
+	dma_addr_t mapped_cmd_ptr;
+
+	buffer_down(scopy->srcbuf);
+	if (scopy->srcbuf != scopy->destbuf)
+		buffer_down(scopy->destbuf);
+
+	priv->command_ptr->cmd = CMD_PTR_LP | CMD_MODE_SINGLE;
+	priv->command_ptr->src = dma_map_single(NULL, buffers[scopy->srcbuf],
+						scopy->size, DMA_TO_DEVICE);
+	priv->command_ptr->dst = dma_map_single(NULL, buffers[scopy->destbuf],
+						scopy->size, DMA_FROM_DEVICE);
+	priv->command_ptr->len = scopy->size;
+
+	mapped_cmd =
+	    dma_map_single(NULL, priv->command_ptr, sizeof(*priv->command_ptr),
+			   DMA_TO_DEVICE);
+	*(priv->command_ptr_ptr) = CMD_PTR_ADDR(mapped_cmd) | CMD_PTR_LP;
+
+	mapped_cmd_ptr = dma_map_single(NULL, priv->command_ptr_ptr,
+					sizeof(*priv->command_ptr_ptr),
+					DMA_TO_DEVICE);
+
+	msm_dmov_exec_cmd(TEST_CHANNEL,
+			  DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(mapped_cmd_ptr));
+
+	dma_unmap_single(NULL, (dma_addr_t) mapped_cmd_ptr,
+			 sizeof(*priv->command_ptr_ptr), DMA_TO_DEVICE);
+	dma_unmap_single(NULL, (dma_addr_t) mapped_cmd,
+			 sizeof(*priv->command_ptr), DMA_TO_DEVICE);
+	dma_unmap_single(NULL, (dma_addr_t) priv->command_ptr->dst,
+			 scopy->size, DMA_FROM_DEVICE);
+	dma_unmap_single(NULL, (dma_addr_t) priv->command_ptr->src,
+			 scopy->size, DMA_TO_DEVICE);
+
+	if (scopy->srcbuf != scopy->destbuf)
+		buffer_up(scopy->destbuf);
+	buffer_up(scopy->srcbuf);
+
+	return err;
+}
+
+static int dma_test_open(struct inode *inode, struct file *file)
+{
+	struct private *priv;
+
+	printk(KERN_ALERT "%s\n", __func__);
+
+	priv = kmalloc(sizeof(struct private), GFP_KERNEL);
+	if (priv == NULL)
+		return -ENOMEM;
+	file->private_data = priv;
+
+	sema_init(&priv->sem, 1);
+
+	/* Note, that these should be allocated together so we don't
+	 * waste 32 bytes for each. */
+
+	/* Allocate the command pointer. */
+	priv->command_ptr = kmalloc(sizeof(&priv->command_ptr),
+				    GFP_KERNEL | __GFP_DMA);
+	if (priv->command_ptr == NULL) {
+		kfree(priv);
+		return -ENOSPC;
+	}
+
+	/* And the indirect pointer. */
+	priv->command_ptr_ptr = kmalloc(sizeof(u32), GFP_KERNEL | __GFP_DMA);
+	if (priv->command_ptr_ptr == NULL) {
+		kfree(priv->command_ptr);
+		kfree(priv);
+		return -ENOSPC;
+	}
+
+	return 0;
+}
+
+static int dma_test_release(struct inode *inode, struct file *file)
+{
+	struct private *priv;
+
+	printk(KERN_ALERT "%s\n", __func__);
+
+	if (file->private_data != NULL) {
+		priv = file->private_data;
+		kfree(priv->command_ptr_ptr);
+		kfree(priv->command_ptr);
+	}
+	kfree(file->private_data);
+	file->private_data = NULL;
+
+	return 0;
+}
+
+static long dma_test_ioctl(struct file *file, unsigned cmd, unsigned long arg)
+{
+	int err = 0;
+	int tmp;
+	struct msm_dma_alloc_req alloc_req;
+	struct msm_dma_bufxfer xfer;
+	struct msm_dma_scopy scopy;
+	struct private *priv = file->private_data;
+
+	/* Verify user arguments. */
+	if (_IOC_TYPE(cmd) != MSM_DMA_IOC_MAGIC)
+		return -ENOTTY;
+
+	switch (cmd) {
+	case MSM_DMA_IOALLOC:
+		if (!access_ok(VERIFY_WRITE, (void __user *)arg,
+			       sizeof(alloc_req)))
+			return -EFAULT;
+		if (__copy_from_user(&alloc_req, (void __user *)arg,
+				     sizeof(alloc_req)))
+			return -EFAULT;
+		err = buffer_req(&alloc_req);
+		if (err < 0)
+			return err;
+		if (__copy_to_user((void __user *)arg, &alloc_req,
+				   sizeof(alloc_req)))
+			return -EFAULT;
+		break;
+
+	case MSM_DMA_IOFREEALL:
+		down(&buffer_lock);
+		for (tmp = 0; tmp < MAX_TEST_BUFFERS; tmp++) {
+			buffer_down(tmp);
+			if (sizes[tmp] > 0) {
+				kfree(buffers[tmp]);
+				sizes[tmp] = 0;
+			}
+			buffer_up(tmp);
+		}
+		up(&buffer_lock);
+		break;
+
+	case MSM_DMA_IOWBUF:
+		if (copy_from_user(&xfer, (void __user *)arg, sizeof(xfer)))
+			return -EFAULT;
+		if (xfer.bufnum < 0 || xfer.bufnum >= MAX_TEST_BUFFERS)
+			return -EINVAL;
+		buffer_down(xfer.bufnum);
+		if (sizes[xfer.bufnum] == 0 ||
+		    xfer.size <= 0 || xfer.size > sizes[xfer.bufnum]) {
+			buffer_up(xfer.bufnum);
+			return -EINVAL;
+		}
+		if (copy_from_user(buffers[xfer.bufnum],
+				   (void __user *)xfer.data, xfer.size))
+			err = -EFAULT;
+		buffer_up(xfer.bufnum);
+		break;
+
+	case MSM_DMA_IORBUF:
+		if (copy_from_user(&xfer, (void __user *)arg, sizeof(xfer)))
+			return -EFAULT;
+		if (xfer.bufnum < 0 || xfer.bufnum >= MAX_TEST_BUFFERS)
+			return -EINVAL;
+		buffer_down(xfer.bufnum);
+		if (sizes[xfer.bufnum] == 0 ||
+		    xfer.size <= 0 || xfer.size > sizes[xfer.bufnum]) {
+			buffer_up(xfer.bufnum);
+			return -EINVAL;
+		}
+		if (copy_to_user((void __user *)xfer.data, buffers[xfer.bufnum],
+				 xfer.size))
+			err = -EFAULT;
+		buffer_up(xfer.bufnum);
+		break;
+
+	case MSM_DMA_IOSCOPY:
+		if (copy_from_user(&scopy, (void __user *)arg, sizeof(scopy)))
+			return -EFAULT;
+		if (scopy.srcbuf < 0 || scopy.srcbuf >= MAX_TEST_BUFFERS ||
+		    sizes[scopy.srcbuf] == 0 ||
+		    scopy.destbuf < 0 || scopy.destbuf >= MAX_TEST_BUFFERS ||
+		    sizes[scopy.destbuf] == 0 ||
+		    scopy.size > sizes[scopy.destbuf] ||
+		    scopy.size > sizes[scopy.srcbuf])
+			return -EINVAL;
+#if 0
+		/* Test interface using memcpy. */
+		memcpy(buffers[scopy.destbuf],
+		       buffers[scopy.srcbuf], scopy.size);
+#else
+		err = dma_scopy(&scopy, priv);
+#endif
+		break;
+
+	default:
+		return -ENOTTY;
+	}
+
+	return err;
+}
+
+/**********************************************************************
+ * Register ourselves as a misc device to be able to test the DMA code
+ * from userspace. */
+
+static const struct file_operations dma_test_fops = {
+	.owner = THIS_MODULE,
+	.unlocked_ioctl = dma_test_ioctl,
+	.open = dma_test_open,
+	.release = dma_test_release,
+};
+
+static struct miscdevice dma_test_dev = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msmdma",
+	.fops = &dma_test_fops,
+};
+static int dma_test_init(void)
+{
+	int ret, i;
+
+	ret = misc_register(&dma_test_dev);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < MAX_TEST_BUFFERS; i++)
+		sema_init(&buffer_sems[i], 1);
+
+	printk(KERN_ALERT "%s, minor number %d\n", __func__, dma_test_dev.minor);
+	return 0;
+}
+
+static void dma_test_exit(void)
+{
+	free_buffers();
+	misc_deregister(&dma_test_dev);
+	printk(KERN_ALERT "%s\n", __func__);
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("David Brown, Qualcomm, Incorporated");
+MODULE_DESCRIPTION("Test for MSM DMA driver");
+MODULE_VERSION("1.01");
+
+module_init(dma_test_init);
+module_exit(dma_test_exit);
diff --git a/arch/arm/mach-msm/etm.c b/arch/arm/mach-msm/etm.c
new file mode 100644
index 0000000..6cceff2
--- /dev/null
+++ b/arch/arm/mach-msm/etm.c
@@ -0,0 +1,1037 @@
+/* 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
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/miscdevice.h>
+#include <linux/cpu.h>
+#include <linux/smp.h>
+#include <linux/percpu.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/wakelock.h>
+#include <linux/pm_qos.h>
+
+#include <asm/atomic.h>
+
+#include "cp14.h"
+
+#define LOG_BUF_LEN			32768
+/* each slot is 4 bytes, 8kb total */
+#define ETB_RAM_SLOTS			2048
+
+#define DATALOG_SYNC			0xB5C7
+#define ETM_DUMP_MSG_ID			0x000A6960
+#define ETB_DUMP_MSG_ID			0x000A6961
+
+/* ETB Registers */
+#define ETB_REG_CONTROL			ETMIMPSPEC1
+#define ETB_REG_STATUS			ETMIMPSPEC2
+#define ETB_REG_COUNT			ETMIMPSPEC3
+#define ETB_REG_ADDRESS			ETMIMPSPEC4
+#define ETB_REG_DATA			ETMIMPSPEC5
+
+/* Having etb macro accessors allows macro expansion for ETB reg defines */
+#define etb_read(reg)			etm_read(reg)
+#define etb_write(val, reg)		etm_write(val, reg)
+
+/* Bitmasks for the ETM control register */
+#define ETM_CONTROL_POWERDOWN		0x00000001
+#define ETM_CONTROL_PROGRAM		0x00000400
+
+/* Bitmasks for the ETM status register */
+#define ETM_STATUS_PROGRAMMING		0x00000002
+
+/* ETB Status Register bit definitions */
+#define OV				0x00200000
+
+/* ETB Control Register bit definitions */
+#define AIR				0x00000008
+#define AIW				0x00000004
+#define CPTM				0x00000002
+#define CPTEN				0x00000001
+
+/* Bitmasks for the swconfig field of ETM_CONFIG
+ * ETM trigger propagated to ETM instances on all cores
+ */
+#define TRIGGER_ALL			0x00000002
+
+#define PROG_TIMEOUT_MS			500
+
+static int trace_enabled;
+static int cpu_to_dump;
+static int next_cpu_to_dump;
+static struct wake_lock etm_wake_lock;
+static struct pm_qos_request etm_qos_req;
+static int trace_on_boot;
+module_param_named(
+	trace_on_boot, trace_on_boot, int, S_IRUGO
+);
+
+struct b {
+	uint8_t etm_log_buf[LOG_BUF_LEN];
+	uint32_t log_end;
+};
+
+static struct b buf[NR_CPUS];
+static struct b __percpu * *alloc_b;
+static atomic_t etm_dev_in_use;
+
+/* These default settings will be used to configure the ETM/ETB
+ * when the driver loads. */
+struct etm_config_struct {
+	uint32_t etm_00_control;
+	uint32_t etm_02_trigger_event;
+	uint32_t etm_06_te_start_stop;
+	uint32_t etm_07_te_single_addr_comp;
+	uint32_t etm_08_te_event;
+	uint32_t etm_09_te_control;
+	uint32_t etm_0a_fifofull_region;
+	uint32_t etm_0b_fifofull_level;
+	uint32_t etm_0c_vd_event;
+	uint32_t etm_0d_vd_single_addr_comp;
+	uint32_t etm_0e_vd_mmd;
+	uint32_t etm_0f_vd_control;
+	uint32_t etm_addr_comp_value[8]; /* 10 to 17 */
+	uint32_t etm_addr_access_type[8]; /* 20 to 27 */
+	uint32_t etm_data_comp_value[2]; /* 30 and 32 */
+	uint32_t etm_data_comp_mask[2]; /* 40 and 42 */
+	uint32_t etm_counter_reload_value[2]; /* 50 to 51 */
+	uint32_t etm_counter_enable[2]; /* 54 to 55 */
+	uint32_t etm_counter_reload_event[2]; /* 58 to 59 */
+	uint32_t etm_60_seq_event_1_to_2;
+	uint32_t etm_61_seq_event_2_to_1;
+	uint32_t etm_62_seq_event_2_to_3;
+	uint32_t etm_63_seq_event_3_to_1;
+	uint32_t etm_64_seq_event_3_to_2;
+	uint32_t etm_65_seq_event_1_to_3;
+	uint32_t etm_6c_cid_comp_value_1;
+	uint32_t etm_6f_cid_comp_mask;
+	uint32_t etm_78_sync_freq;
+	uint32_t swconfig;
+	uint32_t etb_trig_cnt;
+	uint32_t etb_init_ptr;
+};
+
+static struct etm_config_struct etm_config = {
+	/* etm_00_control 0x0000D84E: 32-bit CID, cycle-accurate,
+	 * monitorCPRT */
+	.etm_00_control			= 0x0000D84E,
+	/* etm_02_trigger_event 0x00000000: address comparator 0 matches */
+	.etm_02_trigger_event		= 0x00000000,
+	.etm_06_te_start_stop		= 0x00000000,
+	.etm_07_te_single_addr_comp	= 0x00000000,
+	/* etm_08_te_event 0x0000006F: always true */
+	.etm_08_te_event		= 0x0000006F,
+	/* etm_09_te_control 0x01000000: exclude none */
+	.etm_09_te_control		= 0x01000000,
+	.etm_0a_fifofull_region		= 0x00000000,
+	.etm_0b_fifofull_level		= 0x00000000,
+	/* etm_0c_vd_event 0x0000006F: always true */
+	.etm_0c_vd_event                = 0x0000006F,
+	.etm_0d_vd_single_addr_comp     = 0x00000000,
+	.etm_0e_vd_mmd                  = 0x00000000,
+	/* etm_0f_vd_control 0x00010000: exclude none */
+	.etm_0f_vd_control              = 0x00010000,
+	.etm_addr_comp_value[0]         = 0x00000000,
+	.etm_addr_comp_value[1]         = 0x00000000,
+	.etm_addr_comp_value[2]         = 0x00000000,
+	.etm_addr_comp_value[3]         = 0x00000000,
+	.etm_addr_comp_value[4]         = 0x00000000,
+	.etm_addr_comp_value[5]         = 0x00000000,
+	.etm_addr_comp_value[6]         = 0x00000000,
+	.etm_addr_comp_value[7]         = 0x00000000,
+	.etm_addr_access_type[0]        = 0x00000000,
+	.etm_addr_access_type[1]        = 0x00000000,
+	.etm_addr_access_type[2]        = 0x00000000,
+	.etm_addr_access_type[3]        = 0x00000000,
+	.etm_addr_access_type[4]        = 0x00000000,
+	.etm_addr_access_type[5]        = 0x00000000,
+	.etm_addr_access_type[6]        = 0x00000000,
+	.etm_addr_access_type[7]        = 0x00000000,
+	.etm_data_comp_value[0]         = 0x00000000,
+	.etm_data_comp_value[1]         = 0x00000000,
+	.etm_data_comp_mask[0]          = 0x00000000,
+	.etm_data_comp_mask[1]          = 0x00000000,
+	.etm_counter_reload_value[0]    = 0x00000000,
+	.etm_counter_reload_value[1]    = 0x00000000,
+	.etm_counter_enable[0]          = 0x0002406F,
+	.etm_counter_enable[1]          = 0x0002406F,
+	.etm_counter_reload_event[0]    = 0x0000406F,
+	.etm_counter_reload_event[1]    = 0x0000406F,
+	.etm_60_seq_event_1_to_2        = 0x0000406F,
+	.etm_61_seq_event_2_to_1        = 0x0000406F,
+	.etm_62_seq_event_2_to_3        = 0x0000406F,
+	.etm_63_seq_event_3_to_1        = 0x0000406F,
+	.etm_64_seq_event_3_to_2        = 0x0000406F,
+	.etm_65_seq_event_1_to_3        = 0x0000406F,
+	.etm_6c_cid_comp_value_1        = 0x00000000,
+	.etm_6f_cid_comp_mask           = 0x00000000,
+	.etm_78_sync_freq               = 0x00000400,
+	.swconfig                       = 0x00000002,
+	/* etb_trig_cnt 0x00000000: ignore trigger */
+	.etb_trig_cnt                   = 0x00000000,
+	/* etb_init_ptr 0x00000010: 16 marker bytes */
+	.etb_init_ptr                   = 0x00000010,
+};
+
+/* ETM clock is derived from the processor clock and gets enabled on a
+ * logical OR of below items on Scorpion:
+ * 1.CPMR[ETMCLKEN] is set
+ * 2.ETM is not idle. Also means ETMCR[PD] is 0
+ * 3.Reset is asserted (core or debug)
+ * 4.MRC/MCR to ETM reg (CP14 access)
+ * 5.Debugger access to a ETM register in the core power domain
+ *
+ * 1. and 2. above are permanent enables whereas 3., 4. and 5. are
+ * temporary enables
+ *
+ * We rely on 4. to be able to access ETMCR and then use 2. above for ETM
+ * clock vote in the driver and the save-restore code uses 1. above
+ * for its vote.
+ */
+static inline void __cpu_set_etm_pwrdwn(void)
+{
+	uint32_t etm_control;
+
+	isb();
+	etm_control = etm_read(ETMCR);
+	etm_control |= ETM_CONTROL_POWERDOWN;
+	etm_write(etm_control, ETMCR);
+}
+
+static inline void __cpu_clear_etm_pwrdwn(void)
+{
+	uint32_t etm_control;
+
+	etm_control = etm_read(ETMCR);
+	etm_control &= ~ETM_CONTROL_POWERDOWN;
+	etm_write(etm_control, ETMCR);
+	isb();
+}
+
+static void emit_log_char(uint8_t c)
+{
+	int this_cpu = get_cpu();
+	struct b *mybuf = *per_cpu_ptr(alloc_b, this_cpu);
+	char *log_buf = mybuf->etm_log_buf;
+	int index = (mybuf->log_end)++ & (LOG_BUF_LEN - 1);
+	log_buf[index] = c;
+	put_cpu();
+}
+
+static void emit_log_word(uint32_t word)
+{
+	emit_log_char(word >> 24);
+	emit_log_char(word >> 16);
+	emit_log_char(word >> 8);
+	emit_log_char(word >> 0);
+}
+
+static void __cpu_enable_etb(void)
+{
+	uint32_t etb_control;
+	uint32_t i;
+
+	/* enable auto-increment on reads and writes */
+	etb_control = AIR | AIW;
+	etb_write(etb_control, ETB_REG_CONTROL);
+
+	/* write tags to the slots before the write pointer so we can
+	 * detect overflow */
+	etb_write(0x00000000, ETB_REG_ADDRESS);
+	for (i = 0; i < (etm_config.etb_init_ptr >> 2); i++)
+		etb_write(0xDEADBEEF, ETB_REG_DATA);
+
+	etb_write(0x00000000, ETB_REG_STATUS);
+
+	/* initialize write pointer */
+	etb_write(etm_config.etb_init_ptr, ETB_REG_ADDRESS);
+
+	/* multiple of 16 */
+	etb_write(etm_config.etb_trig_cnt & 0xFFFFFFF0, ETB_REG_COUNT);
+
+	/* Enable ETB and enable the trigger counter as appropriate. A
+	 * trigger count of 0 will be used to signify that the user wants to
+	 * ignore the trigger (just keep writing to the ETB and overwriting
+	 * the oldest data).  For "trace before trigger" captures the user
+	 * should set the trigger count to a small number. */
+
+	etb_control |= CPTEN;
+	if (etm_config.etb_trig_cnt)
+		etb_control |= CPTM;
+	etb_write(etb_control, ETB_REG_CONTROL);
+}
+
+static void __cpu_disable_etb(void)
+{
+	uint32_t etb_control;
+	etb_control = etb_read(ETB_REG_CONTROL);
+	etb_control &= ~CPTEN;
+	etb_write(etb_control, ETB_REG_CONTROL);
+}
+
+static void __cpu_enable_etm(void)
+{
+	uint32_t etm_control;
+	unsigned long timeout = jiffies + msecs_to_jiffies(PROG_TIMEOUT_MS);
+
+	etm_control = etm_read(ETMCR);
+	etm_control &= ~ETM_CONTROL_PROGRAM;
+	etm_write(etm_control, ETMCR);
+
+	while ((etm_read(ETMSR) & ETM_STATUS_PROGRAMMING) == 1) {
+		cpu_relax();
+		if (time_after(jiffies, timeout)) {
+			pr_err("etm: timeout while clearing prog bit\n");
+			break;
+		}
+	}
+}
+
+static void __cpu_disable_etm(void)
+{
+	uint32_t etm_control;
+	unsigned long timeout = jiffies + msecs_to_jiffies(PROG_TIMEOUT_MS);
+
+	etm_control = etm_read(ETMCR);
+	etm_control |= ETM_CONTROL_PROGRAM;
+	etm_write(etm_control, ETMCR);
+
+	while ((etm_read(ETMSR) & ETM_STATUS_PROGRAMMING) == 0) {
+		cpu_relax();
+		if (time_after(jiffies, timeout)) {
+			pr_err("etm: timeout while setting prog bit\n");
+			break;
+		}
+	}
+}
+
+static void __cpu_enable_trace(void *unused)
+{
+	uint32_t etm_control;
+	uint32_t etm_trigger;
+	uint32_t etm_external_output;
+
+	get_cpu();
+
+	__cpu_disable_etb();
+	/* vote for ETM power/clock enable */
+	__cpu_clear_etm_pwrdwn();
+	__cpu_disable_etm();
+
+	etm_control = (etm_config.etm_00_control & ~ETM_CONTROL_POWERDOWN)
+						| ETM_CONTROL_PROGRAM;
+	etm_write(etm_control, ETMCR);
+
+	etm_trigger = etm_config.etm_02_trigger_event;
+	etm_external_output = 0x406F; /* always FALSE */
+
+	if (etm_config.swconfig & TRIGGER_ALL) {
+		uint32_t function = 0x5; /*  A OR B */
+		uint32_t resource_b = 0x60; /* external input 1 */
+
+		etm_trigger &= 0x7F; /* keep resource A, clear function and
+				      * resource B */
+		etm_trigger |= (function << 14);
+		etm_trigger |= (resource_b << 7);
+		etm_external_output = etm_trigger;
+	}
+
+	etm_write(etm_trigger, ETMTRIGGER);
+	etm_write(etm_config.etm_06_te_start_stop, ETMTSSCR);
+	etm_write(etm_config.etm_07_te_single_addr_comp, ETMTECR2);
+	etm_write(etm_config.etm_08_te_event, ETMTEEVR);
+	etm_write(etm_config.etm_09_te_control, ETMTECR1);
+	etm_write(etm_config.etm_0a_fifofull_region, ETMFFRR);
+	etm_write(etm_config.etm_0b_fifofull_level, ETMFFLR);
+	etm_write(etm_config.etm_0c_vd_event, ETMVDEVR);
+	etm_write(etm_config.etm_0d_vd_single_addr_comp, ETMVDCR1);
+	etm_write(etm_config.etm_0e_vd_mmd, ETMVDCR2);
+	etm_write(etm_config.etm_0f_vd_control, ETMVDCR3);
+	etm_write(etm_config.etm_addr_comp_value[0], ETMACVR0);
+	etm_write(etm_config.etm_addr_comp_value[1], ETMACVR1);
+	etm_write(etm_config.etm_addr_comp_value[2], ETMACVR2);
+	etm_write(etm_config.etm_addr_comp_value[3], ETMACVR3);
+	etm_write(etm_config.etm_addr_comp_value[4], ETMACVR4);
+	etm_write(etm_config.etm_addr_comp_value[5], ETMACVR5);
+	etm_write(etm_config.etm_addr_comp_value[6], ETMACVR6);
+	etm_write(etm_config.etm_addr_comp_value[7], ETMACVR7);
+	etm_write(etm_config.etm_addr_access_type[0], ETMACTR0);
+	etm_write(etm_config.etm_addr_access_type[1], ETMACTR1);
+	etm_write(etm_config.etm_addr_access_type[2], ETMACTR2);
+	etm_write(etm_config.etm_addr_access_type[3], ETMACTR3);
+	etm_write(etm_config.etm_addr_access_type[4], ETMACTR4);
+	etm_write(etm_config.etm_addr_access_type[5], ETMACTR5);
+	etm_write(etm_config.etm_addr_access_type[6], ETMACTR6);
+	etm_write(etm_config.etm_addr_access_type[7], ETMACTR7);
+	etm_write(etm_config.etm_data_comp_value[0], ETMDCVR0);
+	etm_write(etm_config.etm_data_comp_value[1], ETMDCVR2);
+	etm_write(etm_config.etm_data_comp_mask[0], ETMDCMR0);
+	etm_write(etm_config.etm_data_comp_mask[1], ETMDCMR2);
+	etm_write(etm_config.etm_counter_reload_value[0], ETMCNTRLDVR0);
+	etm_write(etm_config.etm_counter_reload_value[1], ETMCNTRLDVR1);
+	etm_write(etm_config.etm_counter_enable[0], ETMCNTENR0);
+	etm_write(etm_config.etm_counter_enable[1], ETMCNTENR1);
+	etm_write(etm_config.etm_counter_reload_event[0], ETMCNTRLDEVR0);
+	etm_write(etm_config.etm_counter_reload_event[1], ETMCNTRLDEVR1);
+	etm_write(etm_config.etm_60_seq_event_1_to_2, ETMSQ12EVR);
+	etm_write(etm_config.etm_61_seq_event_2_to_1, ETMSQ21EVR);
+	etm_write(etm_config.etm_62_seq_event_2_to_3, ETMSQ23EVR);
+	etm_write(etm_config.etm_63_seq_event_3_to_1, ETMSQ31EVR);
+	etm_write(etm_config.etm_64_seq_event_3_to_2, ETMSQ32EVR);
+	etm_write(etm_config.etm_65_seq_event_1_to_3, ETMSQ13EVR);
+	etm_write(etm_external_output, ETMEXTOUTEVR0);
+	etm_write(etm_config.etm_6c_cid_comp_value_1, ETMCIDCVR0);
+	etm_write(etm_config.etm_6f_cid_comp_mask, ETMCIDCMR);
+	etm_write(etm_config.etm_78_sync_freq, ETMSYNCFR);
+
+	/* Note that we must enable the ETB before we enable the ETM if we
+	 * want to capture the "always true" trigger event. */
+
+	__cpu_enable_etb();
+	__cpu_enable_etm();
+
+	put_cpu();
+}
+
+static void __cpu_disable_trace(void *unused)
+{
+	get_cpu();
+
+	__cpu_disable_etm();
+
+	/* program trace enable to be low by using always false event */
+	etm_write(0x6F | BIT(14), ETMTEEVR);
+	/* vote for ETM power/clock disable */
+	__cpu_set_etm_pwrdwn();
+
+	__cpu_disable_etb();
+
+	put_cpu();
+}
+
+static void enable_trace(void)
+{
+	wake_lock(&etm_wake_lock);
+	pm_qos_update_request(&etm_qos_req, 0);
+
+	if (etm_config.swconfig & TRIGGER_ALL) {
+		/* This register is accessible from either core.
+		 * CPU1_extout[0] -> CPU0_extin[0]
+		 * CPU_extout[0] -> CPU1_extin[0] */
+		asm volatile("mcr p15, 3, %0, c15, c5, 2" : : "r" (0x1));
+		asm volatile("isb");
+	}
+
+	get_cpu();
+	__cpu_enable_trace(NULL);
+	smp_call_function(__cpu_enable_trace, NULL, 1);
+	put_cpu();
+
+	/* 1. causes all online cpus to come out of idle PC
+	 * 2. prevents idle PC until save restore flag is enabled atomically
+	 *
+	 * we rely on the user to prevent hotplug on/off racing with this
+	 * operation and to ensure cores where trace is expected to be turned
+	 * on are already hotplugged on
+	 */
+	trace_enabled = 1;
+
+	pm_qos_update_request(&etm_qos_req, PM_QOS_DEFAULT_VALUE);
+	wake_unlock(&etm_wake_lock);
+}
+
+static void disable_trace(void)
+{
+	wake_lock(&etm_wake_lock);
+	pm_qos_update_request(&etm_qos_req, 0);
+
+	get_cpu();
+	__cpu_disable_trace(NULL);
+	smp_call_function(__cpu_disable_trace, NULL, 1);
+	put_cpu();
+
+	/* 1. causes all online cpus to come out of idle PC
+	 * 2. prevents idle PC until save restore flag is disabled atomically
+	 *
+	 * we rely on the user to prevent hotplug on/off racing with this
+	 * operation and to ensure cores where trace is expected to be turned
+	 * off are already hotplugged on
+	 */
+	trace_enabled = 0;
+
+	cpu_to_dump = next_cpu_to_dump = 0;
+
+	pm_qos_update_request(&etm_qos_req, PM_QOS_DEFAULT_VALUE);
+	wake_unlock(&etm_wake_lock);
+}
+
+static void generate_etb_dump(void)
+{
+	uint32_t i;
+	uint32_t full_slots;
+	uint32_t etb_control;
+	uint32_t prim_len;
+	uint32_t uptime = 0;
+
+	etb_control = etb_read(ETB_REG_CONTROL);
+	etb_control |= AIR;
+	etb_write(etb_control, ETB_REG_CONTROL);
+
+	if (etb_read(ETB_REG_STATUS) & OV)
+		full_slots = ETB_RAM_SLOTS;
+	else
+		full_slots = etb_read(ETB_REG_ADDRESS) >> 2;
+
+	prim_len = 28 + (full_slots * 4);
+
+	emit_log_char((DATALOG_SYNC >> 8) & 0xFF);
+	emit_log_char((DATALOG_SYNC >> 0) & 0xFF);
+	emit_log_char((prim_len >> 8) & 0xFF);
+	emit_log_char((prim_len >> 0) & 0xFF);
+	emit_log_word(uptime);
+	emit_log_word(ETB_DUMP_MSG_ID);
+	emit_log_word(etm_read(ETMCR));
+	emit_log_word(etm_config.etb_init_ptr >> 2);
+	emit_log_word(etb_read(ETB_REG_ADDRESS) >> 2);
+	emit_log_word((etb_read(ETB_REG_STATUS) & OV) >> 21);
+
+	etb_write(0x00000000, ETB_REG_ADDRESS);
+	for (i = 0; i < full_slots; i++)
+		emit_log_word(etb_read(ETB_REG_DATA));
+}
+
+/* This should match the number of ETM registers being dumped below */
+#define ETM_NUM_REGS_TO_DUMP	54
+static void generate_etm_dump(void)
+{
+	uint32_t prim_len;
+	uint32_t uptime = 0;
+
+	prim_len = 12 + (4 * ETM_NUM_REGS_TO_DUMP);
+
+	emit_log_char((DATALOG_SYNC >> 8) & 0xFF);
+	emit_log_char((DATALOG_SYNC >> 0) & 0xFF);
+	emit_log_char((prim_len >> 8) & 0xFF);
+	emit_log_char((prim_len >> 0) & 0xFF);
+	emit_log_word(uptime);
+	emit_log_word(ETM_DUMP_MSG_ID);
+
+	emit_log_word(etm_read(ETMCR));
+	emit_log_word(etm_read(ETMSR));
+	emit_log_word(etb_read(ETB_REG_CONTROL));
+	emit_log_word(etb_read(ETB_REG_STATUS));
+	emit_log_word(etb_read(ETB_REG_COUNT));
+	emit_log_word(etb_read(ETB_REG_ADDRESS));
+	emit_log_word(0); /* don't read ETB_REG_DATA, changes ETB_REG_ADDRESS */
+	emit_log_word(etm_read(ETMTRIGGER));
+	emit_log_word(etm_read(ETMTSSCR));
+	emit_log_word(etm_read(ETMTECR2));
+	emit_log_word(etm_read(ETMTEEVR));
+	emit_log_word(etm_read(ETMTECR1));
+	emit_log_word(etm_read(ETMFFRR));
+	emit_log_word(etm_read(ETMFFLR));
+	emit_log_word(etm_read(ETMVDEVR));
+	emit_log_word(etm_read(ETMVDCR1));
+	emit_log_word(etm_read(ETMVDCR2));
+	emit_log_word(etm_read(ETMVDCR3));
+	emit_log_word(etm_read(ETMACVR0));
+	emit_log_word(etm_read(ETMACVR1));
+	emit_log_word(etm_read(ETMACVR2));
+	emit_log_word(etm_read(ETMACVR3));
+	emit_log_word(etm_read(ETMACVR4));
+	emit_log_word(etm_read(ETMACVR5));
+	emit_log_word(etm_read(ETMACVR6));
+	emit_log_word(etm_read(ETMACVR7));
+	emit_log_word(etm_read(ETMACTR0));
+	emit_log_word(etm_read(ETMACTR1));
+	emit_log_word(etm_read(ETMACTR2));
+	emit_log_word(etm_read(ETMACTR3));
+	emit_log_word(etm_read(ETMACTR4));
+	emit_log_word(etm_read(ETMACTR5));
+	emit_log_word(etm_read(ETMACTR6));
+	emit_log_word(etm_read(ETMACTR7));
+	emit_log_word(etm_read(ETMDCVR0));
+	emit_log_word(etm_read(ETMDCVR2));
+	emit_log_word(etm_read(ETMDCMR0));
+	emit_log_word(etm_read(ETMDCMR2));
+	emit_log_word(etm_read(ETMCNTRLDVR0));
+	emit_log_word(etm_read(ETMCNTRLDVR1));
+	emit_log_word(etm_read(ETMCNTENR0));
+	emit_log_word(etm_read(ETMCNTENR1));
+	emit_log_word(etm_read(ETMCNTRLDEVR0));
+	emit_log_word(etm_read(ETMCNTRLDEVR1));
+	emit_log_word(etm_read(ETMSQ12EVR));
+	emit_log_word(etm_read(ETMSQ21EVR));
+	emit_log_word(etm_read(ETMSQ23EVR));
+	emit_log_word(etm_read(ETMSQ31EVR));
+	emit_log_word(etm_read(ETMSQ32EVR));
+	emit_log_word(etm_read(ETMSQ13EVR));
+	emit_log_word(etm_read(ETMEXTOUTEVR0));
+	emit_log_word(etm_read(ETMCIDCVR0));
+	emit_log_word(etm_read(ETMCIDCMR));
+	emit_log_word(etm_read(ETMSYNCFR));
+}
+
+static void dump_all(void *unused)
+{
+	get_cpu();
+	__cpu_disable_etb();
+	generate_etm_dump();
+	generate_etb_dump();
+	if (trace_enabled)
+		__cpu_enable_etb();
+	put_cpu();
+}
+
+static void dump_trace(void)
+{
+	get_cpu();
+	dump_all(NULL);
+	smp_call_function(dump_all, NULL, 1);
+	put_cpu();
+}
+
+static int bytes_to_dump;
+static uint8_t *etm_buf_ptr;
+
+static int etm_dev_open(struct inode *inode, struct file *file)
+{
+	if (atomic_cmpxchg(&etm_dev_in_use, 0, 1))
+		return -EBUSY;
+
+	pr_debug("%s: successfully opened\n", __func__);
+	return 0;
+}
+
+static ssize_t etm_dev_read(struct file *file, char __user *data,
+				size_t len, loff_t *ppos)
+{
+	if (cpu_to_dump == next_cpu_to_dump) {
+		if (cpu_to_dump == 0)
+			dump_trace();
+		bytes_to_dump = buf[cpu_to_dump].log_end;
+		buf[cpu_to_dump].log_end = 0;
+		etm_buf_ptr = buf[cpu_to_dump].etm_log_buf;
+		next_cpu_to_dump++;
+		if (next_cpu_to_dump >= num_possible_cpus())
+			next_cpu_to_dump = 0;
+	}
+
+	if (len > bytes_to_dump)
+		len = bytes_to_dump;
+
+	if (copy_to_user(data, etm_buf_ptr, len)) {
+		pr_debug("%s: copy_to_user failed\n", __func__);
+		return -EFAULT;
+	}
+
+	bytes_to_dump -= len;
+	etm_buf_ptr += len;
+
+	pr_debug("%s: %d bytes copied, %d bytes left (cpu %d)\n",
+		 __func__, len, bytes_to_dump, next_cpu_to_dump);
+	return len;
+}
+
+static void setup_range_filter(char addr_type, char range, uint32_t reg1,
+				uint32_t addr1, uint32_t reg2, uint32_t addr2)
+{
+	etm_config.etm_addr_comp_value[reg1] = addr1;
+	etm_config.etm_addr_comp_value[reg2] = addr2;
+
+	etm_config.etm_07_te_single_addr_comp |= (1 << reg1);
+	etm_config.etm_07_te_single_addr_comp |= (1 << reg2);
+
+	etm_config.etm_09_te_control |= (1 << (reg1/2));
+	if (range == 'i')
+		etm_config.etm_09_te_control &= ~(1 << 24);
+	else if (range == 'e')
+		etm_config.etm_09_te_control |= (1 << 24);
+
+	if (addr_type == 'i') {
+		etm_config.etm_addr_access_type[reg1] = 0x99;
+		etm_config.etm_addr_access_type[reg2] = 0x99;
+	} else if (addr_type == 'd') {
+		etm_config.etm_addr_access_type[reg1] = 0x9C;
+		etm_config.etm_addr_access_type[reg2] = 0x9C;
+	}
+}
+
+static void setup_start_stop_filter(char addr_type, char start_stop,
+				uint32_t reg, uint32_t addr)
+{
+	etm_config.etm_addr_comp_value[reg] = addr;
+
+	if (start_stop == 's')
+		etm_config.etm_06_te_start_stop |= (1 << reg);
+	else if (start_stop == 't')
+		etm_config.etm_06_te_start_stop |= (1 << (reg + 16));
+
+	etm_config.etm_09_te_control |= (1 << 25);
+
+	if (addr_type == 'i')
+		etm_config.etm_addr_access_type[reg] = 0x99;
+	else if (addr_type == 'd')
+		etm_config.etm_addr_access_type[reg] = 0x9C;
+}
+
+static void setup_viewdata_range_filter(char range, uint32_t reg1,
+				uint32_t addr1, uint32_t reg2, uint32_t addr2)
+{
+	etm_config.etm_addr_comp_value[reg1] = addr1;
+	etm_config.etm_addr_comp_value[reg2] = addr2;
+
+	if (range == 'i') {
+		etm_config.etm_0d_vd_single_addr_comp |= (1 << reg1);
+		etm_config.etm_0d_vd_single_addr_comp |= (1 << reg2);
+		etm_config.etm_0f_vd_control |= (1 << (reg1/2));
+	} else if (range == 'e') {
+		etm_config.etm_0d_vd_single_addr_comp |= (1 << (reg1 + 16));
+		etm_config.etm_0d_vd_single_addr_comp |= (1 << (reg2 + 16));
+		etm_config.etm_0f_vd_control |= (1 << ((reg1/2) + 8));
+	}
+	etm_config.etm_0f_vd_control &= ~(1 << 16);
+
+	etm_config.etm_addr_access_type[reg1] = 0x9C;
+	etm_config.etm_addr_access_type[reg2] = 0x9C;
+}
+
+static void setup_viewdata_start_stop_filter(char start_stop, uint32_t reg,
+				uint32_t addr)
+{
+	etm_config.etm_addr_comp_value[reg] = addr;
+
+	if (start_stop == 's')
+		etm_config.etm_06_te_start_stop |= (1 << reg);
+	else if (start_stop == 't')
+		etm_config.etm_06_te_start_stop |= (1 << (reg + 16));
+
+	etm_config.etm_addr_access_type[reg] = 0x9C;
+}
+
+static void setup_access_type(uint32_t reg, uint32_t value)
+{
+	etm_config.etm_addr_access_type[reg] &= 0xFFFFFFF8;
+	value &= 0x7;
+	etm_config.etm_addr_access_type[reg] |= value;
+}
+
+static void reset_filter(void)
+{
+	etm_config.etm_00_control			= 0x0000D84E;
+	/* etm_02_trigger_event 0x00000000: address comparator 0 matches */
+	etm_config.etm_02_trigger_event		= 0x00000000;
+	etm_config.etm_06_te_start_stop		= 0x00000000;
+	etm_config.etm_07_te_single_addr_comp	= 0x00000000;
+	/* etm_08_te_event 0x0000006F: always true */
+	etm_config.etm_08_te_event		= 0x0000006F;
+	/* etm_09_te_control 0x01000000: exclude none */
+	etm_config.etm_09_te_control		= 0x01000000;
+	etm_config.etm_0a_fifofull_region		= 0x00000000;
+	etm_config.etm_0b_fifofull_level		= 0x00000000;
+	/* etm_0c_vd_event 0x0000006F: always true */
+	etm_config.etm_0c_vd_event                = 0x0000006F;
+	etm_config.etm_0d_vd_single_addr_comp     = 0x00000000;
+	etm_config.etm_0e_vd_mmd                  = 0x00000000;
+	/* etm_0f_vd_control 0x00010000: exclude none */
+	etm_config.etm_0f_vd_control              = 0x00010000;
+	etm_config.etm_addr_comp_value[0]         = 0x00000000;
+	etm_config.etm_addr_comp_value[1]         = 0x00000000;
+	etm_config.etm_addr_comp_value[2]         = 0x00000000;
+	etm_config.etm_addr_comp_value[3]         = 0x00000000;
+	etm_config.etm_addr_comp_value[4]         = 0x00000000;
+	etm_config.etm_addr_comp_value[5]         = 0x00000000;
+	etm_config.etm_addr_comp_value[6]         = 0x00000000;
+	etm_config.etm_addr_comp_value[7]         = 0x00000000;
+	etm_config.etm_addr_access_type[0]        = 0x00000000;
+	etm_config.etm_addr_access_type[1]        = 0x00000000;
+	etm_config.etm_addr_access_type[2]        = 0x00000000;
+	etm_config.etm_addr_access_type[3]        = 0x00000000;
+	etm_config.etm_addr_access_type[4]        = 0x00000000;
+	etm_config.etm_addr_access_type[5]        = 0x00000000;
+	etm_config.etm_addr_access_type[6]        = 0x00000000;
+	etm_config.etm_addr_access_type[7]        = 0x00000000;
+	etm_config.etm_data_comp_value[0]         = 0x00000000;
+	etm_config.etm_data_comp_value[1]         = 0x00000000;
+	etm_config.etm_data_comp_mask[0]          = 0x00000000;
+	etm_config.etm_data_comp_mask[1]          = 0x00000000;
+	etm_config.etm_counter_reload_value[0]    = 0x00000000;
+	etm_config.etm_counter_reload_value[1]    = 0x00000000;
+	etm_config.etm_counter_enable[0]          = 0x0002406F;
+	etm_config.etm_counter_enable[1]          = 0x0002406F;
+	etm_config.etm_counter_reload_event[0]    = 0x0000406F;
+	etm_config.etm_counter_reload_event[1]    = 0x0000406F;
+	etm_config.etm_60_seq_event_1_to_2        = 0x0000406F;
+	etm_config.etm_61_seq_event_2_to_1        = 0x0000406F;
+	etm_config.etm_62_seq_event_2_to_3        = 0x0000406F;
+	etm_config.etm_63_seq_event_3_to_1        = 0x0000406F;
+	etm_config.etm_64_seq_event_3_to_2        = 0x0000406F;
+	etm_config.etm_65_seq_event_1_to_3        = 0x0000406F;
+	etm_config.etm_6c_cid_comp_value_1        = 0x00000000;
+	etm_config.etm_6f_cid_comp_mask           = 0x00000000;
+	etm_config.etm_78_sync_freq               = 0x00000400;
+	etm_config.swconfig                       = 0x00000002;
+	/* etb_trig_cnt 0x00000020: ignore trigger */
+	etm_config.etb_trig_cnt                   = 0x00000000;
+	/* etb_init_ptr 0x00000010: 16 marker bytes */
+	etm_config.etb_init_ptr                   = 0x00000010;
+}
+
+#define MAX_COMMAND_STRLEN  40
+static ssize_t etm_dev_write(struct file *file, const char __user *data,
+				size_t len, loff_t *ppos)
+{
+	char command[MAX_COMMAND_STRLEN];
+	int strlen;
+	unsigned long value;
+	unsigned long reg1, reg2;
+	unsigned long addr1, addr2;
+
+	strlen = strnlen_user(data, MAX_COMMAND_STRLEN);
+	pr_debug("etm: string length: %d", strlen);
+	if (strlen == 0 || strlen == (MAX_COMMAND_STRLEN+1)) {
+		pr_err("etm: error in strlen: %d", strlen);
+		return -EFAULT;
+	}
+	/* includes the null character */
+	if (copy_from_user(command, data, strlen)) {
+		pr_err("etm: error in copy_from_user: %d", strlen);
+		return -EFAULT;
+	}
+
+	pr_debug("etm: input = %s", command);
+
+	switch (command[0]) {
+	case '0':
+		if (trace_enabled) {
+			disable_trace();
+			pr_info("etm: tracing disabled\n");
+		}
+		break;
+	case '1':
+		if (!trace_enabled) {
+			enable_trace();
+			pr_info("etm: tracing enabled\n");
+		}
+		break;
+	case 'f':
+		switch (command[2]) {
+		case 'i':
+		case 'd':
+			switch (command[4]) {
+			case 'i':
+				if (sscanf(&command[6], "%lx:%lx:%lx:%lx\\0",
+					&reg1, &addr1, &reg2, &addr2) != 4)
+					goto err_out;
+				if (reg1 > 7 || reg2 > 7 || (reg1 % 2))
+					goto err_out;
+				setup_range_filter(command[2], 'i',
+					reg1, addr1, reg2, addr2);
+				break;
+			case 'e':
+				if (sscanf(&command[6], "%lx:%lx:%lx:%lx\\0",
+					&reg1, &addr1, &reg2, &addr2) != 4)
+					goto err_out;
+				if (reg1 > 7 || reg2 > 7 || (reg1 % 2)
+					|| command[2] == 'd')
+					goto err_out;
+				setup_range_filter(command[2], 'e',
+					reg1, addr1, reg2, addr2);
+				break;
+			case 's':
+				if (sscanf(&command[6], "%lx:%lx\\0",
+					&reg1, &addr1) != 2)
+					goto err_out;
+				if (reg1 > 7)
+					goto err_out;
+				setup_start_stop_filter(command[2], 's',
+					reg1, addr1);
+				break;
+			case 't':
+				if (sscanf(&command[6], "%lx:%lx\\0",
+						&reg1, &addr1) != 2)
+					goto err_out;
+				if (reg1 > 7)
+					goto err_out;
+				setup_start_stop_filter(command[2], 't',
+					reg1, addr1);
+				break;
+			default:
+				goto err_out;
+			}
+			break;
+		case 'r':
+			reset_filter();
+			break;
+		default:
+			goto err_out;
+		}
+		break;
+	case 'v':
+		switch (command[2]) {
+		case 'd':
+			switch (command[4]) {
+			case 'i':
+				if (sscanf(&command[6], "%lx:%lx:%lx:%lx\\0",
+					&reg1, &addr1, &reg2, &addr2) != 4)
+					goto err_out;
+				if (reg1 > 7 || reg2 > 7 || (reg1 % 2))
+					goto err_out;
+				setup_viewdata_range_filter('i',
+					reg1, addr1, reg2, addr2);
+				break;
+			case 'e':
+				if (sscanf(&command[6], "%lx:%lx:%lx:%lx\\0",
+					&reg1, &addr1, &reg2, &addr2) != 4)
+					goto err_out;
+				if (reg1 > 7 || reg2 > 7 || (reg1 % 2))
+					goto err_out;
+				setup_viewdata_range_filter('e',
+					reg1, addr1, reg2, addr2);
+				break;
+			case 's':
+				if (sscanf(&command[6], "%lx:%lx\\0",
+					&reg1, &addr1) != 2)
+					goto err_out;
+				if (reg1 > 7)
+					goto err_out;
+				setup_viewdata_start_stop_filter('s',
+					reg1, addr1);
+				break;
+			case 't':
+				if (sscanf(&command[6], "%lx:%lx\\0",
+					&reg1, &addr1) != 2)
+					goto err_out;
+				if (reg1 > 7)
+					goto err_out;
+				setup_viewdata_start_stop_filter('t',
+					reg1, addr1);
+				break;
+			default:
+				goto err_out;
+			}
+			break;
+		default:
+			goto err_out;
+		}
+		break;
+	case 'a':
+		switch (command[2]) {
+		case 't':
+			if (sscanf(&command[4], "%lx:%lx\\0",
+					&reg1, &value) != 2)
+				goto err_out;
+			if (reg1 > 7 || value > 6)
+				goto err_out;
+			setup_access_type(reg1, value);
+			break;
+		default:
+			goto err_out;
+		}
+		break;
+	default:
+		goto err_out;
+	}
+
+	return len;
+
+err_out:
+	return -EFAULT;
+}
+
+static int etm_dev_release(struct inode *inode, struct file *file)
+{
+	if (cpu_to_dump == next_cpu_to_dump)
+		next_cpu_to_dump = 0;
+	cpu_to_dump = next_cpu_to_dump;
+
+	atomic_set(&etm_dev_in_use, 0);
+	pr_debug("%s: released\n", __func__);
+	return 0;
+}
+
+static const struct file_operations etm_dev_fops = {
+	.owner = THIS_MODULE,
+	.open = etm_dev_open,
+	.read = etm_dev_read,
+	.write = etm_dev_write,
+	.release = etm_dev_release,
+};
+
+static struct miscdevice etm_dev = {
+	.name = "msm_etm",
+	.minor = MISC_DYNAMIC_MINOR,
+	.fops = &etm_dev_fops,
+};
+
+static void __cpu_clear_sticky(void *unused)
+{
+	etm_read(ETMPDSR); /* clear sticky bit in PDSR */
+	isb();
+}
+
+static int __init etm_init(void)
+{
+	int ret, cpu;
+
+	ret = misc_register(&etm_dev);
+	if (ret)
+		return -ENODEV;
+
+	alloc_b = alloc_percpu(typeof(*alloc_b));
+	if (!alloc_b)
+		goto err1;
+
+	for_each_possible_cpu(cpu)
+		*per_cpu_ptr(alloc_b, cpu) = &buf[cpu];
+
+	wake_lock_init(&etm_wake_lock, WAKE_LOCK_SUSPEND, "msm_etm");
+	pm_qos_add_request(&etm_qos_req, PM_QOS_CPU_DMA_LATENCY,
+						PM_QOS_DEFAULT_VALUE);
+
+	/* No need to explicity turn on ETM clock since CP14 access go
+	 * through via the autoclock turn on/off
+	 */
+	__cpu_clear_sticky(NULL);
+	smp_call_function(__cpu_clear_sticky, NULL, 1);
+
+	cpu_to_dump = next_cpu_to_dump = 0;
+
+	pr_info("ETM/ETB intialized.\n");
+
+	if (trace_on_boot)
+		enable_trace();
+
+	return 0;
+
+err1:
+	misc_deregister(&etm_dev);
+	return -ENOMEM;
+}
+module_init(etm_init);
+
+static void __exit etm_exit(void)
+{
+	disable_trace();
+	pm_qos_remove_request(&etm_qos_req);
+	wake_lock_destroy(&etm_wake_lock);
+	free_percpu(alloc_b);
+	misc_deregister(&etm_dev);
+}
+module_exit(etm_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("embedded trace driver");
diff --git a/arch/arm/mach-msm/fiq.h b/arch/arm/mach-msm/fiq.h
new file mode 100644
index 0000000..cd90390
--- /dev/null
+++ b/arch/arm/mach-msm/fiq.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ *
+ * 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 _ARCH_ARM_MACH_MSM_FIQ_H
+#define _ARCH_ARM_MACH_MSM_FIQ_H
+
+extern unsigned char fiq_glue, fiq_glue_end;
+void fiq_glue_setup(void *func, void *data, void *sp);
+
+#endif
diff --git a/arch/arm/mach-msm/fiq_glue.S b/arch/arm/mach-msm/fiq_glue.S
new file mode 100644
index 0000000..df1c708
--- /dev/null
+++ b/arch/arm/mach-msm/fiq_glue.S
@@ -0,0 +1,112 @@
+/* arch/arm/mach-msm/fiq_glue.S
+ *
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+		.text
+
+		.global fiq_glue_end
+
+		/* fiq stack: r0-r15,cpsr,spsr of interrupted mode */
+
+ENTRY(fiq_glue)
+		/* store pc, cpsr from previous mode */
+		mrs	r12, spsr
+		sub	r11, lr, #4
+		subs	r10, #1
+		bne	nested_fiq
+
+		stmfd	sp!, {r11-r12, lr}
+
+		/* store r8-r14 from previous mode */
+		sub	sp, sp, #(7 * 4)
+		stmia	sp, {r8-r14}^
+		nop
+
+		/* store r0-r7 from previous mode */
+		stmfd	sp!, {r0-r7}
+
+		/* setup func(data,regs) arguments */
+		mov	r0, r9
+		mov	r1, sp
+		mov	r3, r8
+
+		mov	r7, sp
+
+		/* Get sp and lr from non-user modes */
+		and	r4, r12, #MODE_MASK
+		cmp	r4, #USR_MODE
+		beq	fiq_from_usr_mode
+
+		mov	r7, sp
+		orr	r4, r4, #(PSR_I_BIT | PSR_F_BIT)
+		msr	cpsr_c, r4
+		str	sp, [r7, #(4 * 13)]
+		str	lr, [r7, #(4 * 14)]
+		mrs	r5, spsr
+		str	r5, [r7, #(4 * 17)]
+
+		cmp	r4, #(SVC_MODE | PSR_I_BIT | PSR_F_BIT)
+		/* use fiq stack if we reenter this mode */
+		subne	sp, r7, #(4 * 3)
+
+fiq_from_usr_mode:
+		msr	cpsr_c, #(SVC_MODE | PSR_I_BIT | PSR_F_BIT)
+		mov	r2, sp
+		sub	sp, r7, #12
+		stmfd	sp!, {r2, ip, lr}
+		/* call func(data,regs) */
+		blx	r3
+		ldmfd	sp, {r2, ip, lr}
+		mov	sp, r2
+
+		/* restore/discard saved state */
+		cmp	r4, #USR_MODE
+		beq	fiq_from_usr_mode_exit
+
+		msr	cpsr_c, r4
+		ldr	sp, [r7, #(4 * 13)]
+		ldr	lr, [r7, #(4 * 14)]
+		msr	spsr_cxsf, r5
+
+fiq_from_usr_mode_exit:
+		msr	cpsr_c, #(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)
+
+		ldmfd	sp!, {r0-r7}
+		add	sp, sp, #(7 * 4)
+		ldmfd	sp!, {r11-r12, lr}
+exit_fiq:
+		msr	spsr_cxsf, r12
+		add	r10, #1
+		movs	pc, r11
+
+nested_fiq:
+		orr	r12, r12, #(PSR_F_BIT)
+		b	exit_fiq
+
+fiq_glue_end:
+
+ENTRY(fiq_glue_setup) /* func, data, sp */
+		mrs		r3, cpsr
+		msr		cpsr_c, #(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)
+		movs		r8, r0
+		mov		r9, r1
+		mov		sp, r2
+		moveq		r10, #0
+		movne		r10, #1
+		msr		cpsr_c, r3
+		bx		lr
+
diff --git a/arch/arm/mach-msm/fish_battery.c b/arch/arm/mach-msm/fish_battery.c
new file mode 100644
index 0000000..19fbb91
--- /dev/null
+++ b/arch/arm/mach-msm/fish_battery.c
@@ -0,0 +1,145 @@
+/* arch/arm/mach-msm/fish_battery.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * 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.
+ *
+ * based on: arch/arm/mach-msm/htc_battery.c
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/power_supply.h>
+#include <linux/platform_device.h>
+
+static enum power_supply_property fish_battery_properties[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_HEALTH,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_TECHNOLOGY,
+	POWER_SUPPLY_PROP_CAPACITY,
+};
+
+static enum power_supply_property fish_power_properties[] = {
+	POWER_SUPPLY_PROP_ONLINE,
+};
+
+static char *supply_list[] = {
+	"battery",
+};
+
+static int fish_power_get_property(struct power_supply *psy,
+				   enum power_supply_property psp,
+				   union power_supply_propval *val);
+
+static int fish_battery_get_property(struct power_supply *psy,
+				     enum power_supply_property psp,
+				     union power_supply_propval *val);
+
+static struct power_supply fish_power_supplies[] = {
+	{
+		.name = "battery",
+		.type = POWER_SUPPLY_TYPE_BATTERY,
+		.properties = fish_battery_properties,
+		.num_properties = ARRAY_SIZE(fish_battery_properties),
+		.get_property = fish_battery_get_property,
+	},
+	{
+		.name = "ac",
+		.type = POWER_SUPPLY_TYPE_MAINS,
+		.supplied_to = supply_list,
+		.num_supplicants = ARRAY_SIZE(supply_list),
+		.properties = fish_power_properties,
+		.num_properties = ARRAY_SIZE(fish_power_properties),
+		.get_property = fish_power_get_property,
+	},
+};
+
+static int fish_power_get_property(struct power_supply *psy,
+				   enum power_supply_property psp,
+				   union power_supply_propval *val)
+{
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		if (psy->type == POWER_SUPPLY_TYPE_MAINS)
+			val->intval = 1;
+		else
+			val->intval = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int fish_battery_get_property(struct power_supply *psy,
+				     enum power_supply_property psp,
+				     union power_supply_propval *val)
+{
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		val->intval = POWER_SUPPLY_STATUS_FULL;
+		break;
+	case POWER_SUPPLY_PROP_HEALTH:
+		val->intval = POWER_SUPPLY_HEALTH_GOOD;
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = 1;
+		break;
+	case POWER_SUPPLY_PROP_TECHNOLOGY:
+		val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY:
+		val->intval = 100;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int fish_battery_probe(struct platform_device *pdev)
+{
+	int i;
+	int rc;
+
+	/* init power supplier framework */
+	for (i = 0; i < ARRAY_SIZE(fish_power_supplies); i++) {
+		rc = power_supply_register(&pdev->dev, &fish_power_supplies[i]);
+		if (rc)
+			pr_err("%s: Failed to register power supply (%d)\n",
+			       __func__, rc);
+	}
+
+	return 0;
+}
+
+static struct platform_driver fish_battery_driver = {
+	.probe	= fish_battery_probe,
+	.driver	= {
+		.name	= "fish_battery",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init fish_battery_init(void)
+{
+	platform_driver_register(&fish_battery_driver);
+	return 0;
+}
+
+module_init(fish_battery_init);
+MODULE_DESCRIPTION("Qualcomm fish battery driver");
+MODULE_LICENSE("GPL");
+
diff --git a/arch/arm/mach-msm/footswitch-8x60.c b/arch/arm/mach-msm/footswitch-8x60.c
new file mode 100644
index 0000000..84735aa
--- /dev/null
+++ b/arch/arm/mach-msm/footswitch-8x60.c
@@ -0,0 +1,592 @@
+/* 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
+ * 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/clk.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_bus.h>
+#include <mach/scm-io.h>
+#include "clock.h"
+#include "footswitch.h"
+
+#ifdef CONFIG_MSM_SECURE_IO
+#undef readl_relaxed
+#undef writel_relaxed
+#define readl_relaxed secure_readl
+#define writel_relaxed secure_writel
+#endif
+
+#define REG(off) (MSM_MMSS_CLK_CTL_BASE + (off))
+#define GEMINI_GFS_CTL_REG	REG(0x01A0)
+#define GFX2D0_GFS_CTL_REG	REG(0x0180)
+#define GFX2D1_GFS_CTL_REG	REG(0x0184)
+#define GFX3D_GFS_CTL_REG	REG(0x0188)
+#define MDP_GFS_CTL_REG		REG(0x0190)
+#define ROT_GFS_CTL_REG		REG(0x018C)
+#define VED_GFS_CTL_REG		REG(0x0194)
+#define VFE_GFS_CTL_REG		REG(0x0198)
+#define VPE_GFS_CTL_REG		REG(0x019C)
+#define VCAP_GFS_CTL_REG	REG(0x0254)
+
+#define CLAMP_BIT		BIT(5)
+#define ENABLE_BIT		BIT(8)
+#define RETENTION_BIT		BIT(9)
+
+#define GFS_DELAY_CNT		31
+
+#define RESET_DELAY_US		1
+/* Clock rate to use if one has not previously been set. */
+#define DEFAULT_RATE		27000000
+#define MAX_CLKS		10
+
+/*
+ * Lock is only needed to protect against the first footswitch_enable()
+ * call occuring concurrently with late_footswitch_init().
+ */
+static DEFINE_MUTEX(claim_lock);
+
+struct footswitch {
+	struct regulator_dev	*rdev;
+	struct regulator_desc	desc;
+	void			*gfs_ctl_reg;
+	int			bus_port0, bus_port1;
+	bool			is_enabled;
+	bool			is_claimed;
+	struct fs_clk_data	*clk_data;
+	struct clk		*core_clk;
+};
+
+static int setup_clocks(struct footswitch *fs)
+{
+	int rc = 0;
+	struct fs_clk_data *clock;
+	long rate;
+
+	/*
+	 * Enable all clocks in the power domain. If a specific clock rate is
+	 * required for reset timing, set that rate before enabling the clocks.
+	 */
+	for (clock = fs->clk_data; clock->clk; clock++) {
+		clock->rate = clk_get_rate(clock->clk);
+		if (!clock->rate || clock->reset_rate) {
+			rate = clock->reset_rate ?
+					clock->reset_rate : DEFAULT_RATE;
+			rc = clk_set_rate(clock->clk, rate);
+			if (rc && rc != -ENOSYS) {
+				pr_err("Failed to set %s %s rate to %lu Hz.\n",
+				       fs->desc.name, clock->name, clock->rate);
+				for (clock--; clock >= fs->clk_data; clock--) {
+					if (clock->enabled)
+						clk_disable_unprepare(
+								clock->clk);
+					clk_set_rate(clock->clk, clock->rate);
+				}
+				return rc;
+			}
+		}
+		/*
+		 * Some clocks are for reset purposes only. These clocks will
+		 * fail to enable. Ignore the failures but keep track of them so
+		 * we don't try to disable them later and crash due to
+		 * unbalanced calls.
+		 */
+		clock->enabled = !clk_prepare_enable(clock->clk);
+	}
+
+	return 0;
+}
+
+static void restore_clocks(struct footswitch *fs)
+{
+	struct fs_clk_data *clock;
+
+	/* Restore clocks to their orignal states before setup_clocks(). */
+	for (clock = fs->clk_data; clock->clk; clock++) {
+		if (clock->enabled)
+			clk_disable_unprepare(clock->clk);
+		if (clock->rate && clk_set_rate(clock->clk, clock->rate))
+			pr_err("Failed to restore %s %s rate to %lu Hz.\n",
+			       fs->desc.name, clock->name, clock->rate);
+	}
+}
+
+static int footswitch_is_enabled(struct regulator_dev *rdev)
+{
+	struct footswitch *fs = rdev_get_drvdata(rdev);
+
+	return fs->is_enabled;
+}
+
+static int footswitch_enable(struct regulator_dev *rdev)
+{
+	struct footswitch *fs = rdev_get_drvdata(rdev);
+	struct fs_clk_data *clock;
+	uint32_t regval, rc = 0;
+
+	mutex_lock(&claim_lock);
+	fs->is_claimed = true;
+	mutex_unlock(&claim_lock);
+
+	/* Return early if already enabled. */
+	regval = readl_relaxed(fs->gfs_ctl_reg);
+	if ((regval & (ENABLE_BIT | CLAMP_BIT)) == ENABLE_BIT)
+		return 0;
+
+	/* Make sure required clocks are on at the correct rates. */
+	rc = setup_clocks(fs);
+	if (rc)
+		return rc;
+
+	/* Un-halt all bus ports in the power domain. */
+	if (fs->bus_port0) {
+		rc = msm_bus_axi_portunhalt(fs->bus_port0);
+		if (rc) {
+			pr_err("%s port 0 unhalt failed.\n", fs->desc.name);
+			goto err;
+		}
+	}
+	if (fs->bus_port1) {
+		rc = msm_bus_axi_portunhalt(fs->bus_port1);
+		if (rc) {
+			pr_err("%s port 1 unhalt failed.\n", fs->desc.name);
+			goto err_port2_halt;
+		}
+	}
+
+	/*
+	 * (Re-)Assert resets for all clocks in the clock domain, since
+	 * footswitch_enable() is first called before footswitch_disable()
+	 * and resets should be asserted before power is restored.
+	 */
+	for (clock = fs->clk_data; clock->clk; clock++)
+		; /* Do nothing */
+	for (clock--; clock >= fs->clk_data; clock--)
+		clk_reset(clock->clk, CLK_RESET_ASSERT);
+	/* Wait for synchronous resets to propagate. */
+	udelay(RESET_DELAY_US);
+
+	/* Enable the power rail at the footswitch. */
+	regval |= ENABLE_BIT;
+	writel_relaxed(regval, fs->gfs_ctl_reg);
+	/* Wait for the rail to fully charge. */
+	mb();
+	udelay(1);
+
+	/* Un-clamp the I/O ports. */
+	regval &= ~CLAMP_BIT;
+	writel_relaxed(regval, fs->gfs_ctl_reg);
+
+	/* Deassert resets for all clocks in the power domain. */
+	for (clock = fs->clk_data; clock->clk; clock++)
+		clk_reset(clock->clk, CLK_RESET_DEASSERT);
+	/* Toggle core reset again after first power-on (required for GFX3D). */
+	if (fs->desc.id == FS_GFX3D) {
+		clk_reset(fs->core_clk, CLK_RESET_ASSERT);
+		udelay(RESET_DELAY_US);
+		clk_reset(fs->core_clk, CLK_RESET_DEASSERT);
+		udelay(RESET_DELAY_US);
+	}
+
+	/* Prevent core memory from collapsing when its clock is gated. */
+	clk_set_flags(fs->core_clk, CLKFLAG_RETAIN);
+
+	/* Return clocks to their state before this function. */
+	restore_clocks(fs);
+
+	fs->is_enabled = true;
+	return 0;
+
+err_port2_halt:
+	msm_bus_axi_porthalt(fs->bus_port0);
+err:
+	restore_clocks(fs);
+	return rc;
+}
+
+static int footswitch_disable(struct regulator_dev *rdev)
+{
+	struct footswitch *fs = rdev_get_drvdata(rdev);
+	struct fs_clk_data *clock;
+	uint32_t regval, rc = 0;
+
+	/* Return early if already disabled. */
+	regval = readl_relaxed(fs->gfs_ctl_reg);
+	if ((regval & ENABLE_BIT) == 0)
+		return 0;
+
+	/* Make sure required clocks are on at the correct rates. */
+	rc = setup_clocks(fs);
+	if (rc)
+		return rc;
+
+	/* Allow core memory to collapse when its clock is gated. */
+	clk_set_flags(fs->core_clk, CLKFLAG_NORETAIN);
+
+	/* Halt all bus ports in the power domain. */
+	if (fs->bus_port0) {
+		rc = msm_bus_axi_porthalt(fs->bus_port0);
+		if (rc) {
+			pr_err("%s port 0 halt failed.\n", fs->desc.name);
+			goto err;
+		}
+	}
+	if (fs->bus_port1) {
+		rc = msm_bus_axi_porthalt(fs->bus_port1);
+		if (rc) {
+			pr_err("%s port 1 halt failed.\n", fs->desc.name);
+			goto err_port2_halt;
+		}
+	}
+
+	/*
+	 * Assert resets for all clocks in the clock domain so that
+	 * outputs settle prior to clamping.
+	 */
+	for (clock = fs->clk_data; clock->clk; clock++)
+		; /* Do nothing */
+	for (clock--; clock >= fs->clk_data; clock--)
+		clk_reset(clock->clk, CLK_RESET_ASSERT);
+	/* Wait for synchronous resets to propagate. */
+	udelay(RESET_DELAY_US);
+
+	/*
+	 * Return clocks to their state before this function. For robustness
+	 * if memory-retention across collapses is required, clocks should
+	 * be disabled before asserting the clamps. Assuming clocks were off
+	 * before entering footswitch_disable(), this will be true.
+	 */
+	restore_clocks(fs);
+
+	/*
+	 * Clamp the I/O ports of the core to ensure the values
+	 * remain fixed while the core is collapsed.
+	 */
+	regval |= CLAMP_BIT;
+	writel_relaxed(regval, fs->gfs_ctl_reg);
+
+	/* Collapse the power rail at the footswitch. */
+	regval &= ~ENABLE_BIT;
+	writel_relaxed(regval, fs->gfs_ctl_reg);
+
+	fs->is_enabled = false;
+	return 0;
+
+err_port2_halt:
+	msm_bus_axi_portunhalt(fs->bus_port0);
+err:
+	clk_set_flags(fs->core_clk, CLKFLAG_RETAIN);
+	restore_clocks(fs);
+	return rc;
+}
+
+static int gfx2d_footswitch_enable(struct regulator_dev *rdev)
+{
+	struct footswitch *fs = rdev_get_drvdata(rdev);
+	struct fs_clk_data *clock;
+	uint32_t regval, rc = 0;
+
+	mutex_lock(&claim_lock);
+	fs->is_claimed = true;
+	mutex_unlock(&claim_lock);
+
+	/* Return early if already enabled. */
+	regval = readl_relaxed(fs->gfs_ctl_reg);
+	if ((regval & (ENABLE_BIT | CLAMP_BIT)) == ENABLE_BIT)
+		return 0;
+
+	/* Make sure required clocks are on at the correct rates. */
+	rc = setup_clocks(fs);
+	if (rc)
+		return rc;
+
+	/* Un-halt all bus ports in the power domain. */
+	if (fs->bus_port0) {
+		rc = msm_bus_axi_portunhalt(fs->bus_port0);
+		if (rc) {
+			pr_err("%s port 0 unhalt failed.\n", fs->desc.name);
+			goto err;
+		}
+	}
+
+	/* Disable core clock. */
+	clk_disable_unprepare(fs->core_clk);
+
+	/*
+	 * (Re-)Assert resets for all clocks in the clock domain, since
+	 * footswitch_enable() is first called before footswitch_disable()
+	 * and resets should be asserted before power is restored.
+	 */
+	for (clock = fs->clk_data; clock->clk; clock++)
+		; /* Do nothing */
+	for (clock--; clock >= fs->clk_data; clock--)
+		clk_reset(clock->clk, CLK_RESET_ASSERT);
+	/* Wait for synchronous resets to propagate. */
+	udelay(RESET_DELAY_US);
+
+	/* Enable the power rail at the footswitch. */
+	regval |= ENABLE_BIT;
+	writel_relaxed(regval, fs->gfs_ctl_reg);
+	mb();
+	udelay(1);
+
+	/* Un-clamp the I/O ports. */
+	regval &= ~CLAMP_BIT;
+	writel_relaxed(regval, fs->gfs_ctl_reg);
+
+	/* Deassert resets for all clocks in the power domain. */
+	for (clock = fs->clk_data; clock->clk; clock++)
+		clk_reset(clock->clk, CLK_RESET_DEASSERT);
+	udelay(RESET_DELAY_US);
+
+	/* Re-enable core clock. */
+	clk_prepare_enable(fs->core_clk);
+
+	/* Prevent core memory from collapsing when its clock is gated. */
+	clk_set_flags(fs->core_clk, CLKFLAG_RETAIN);
+
+	/* Return clocks to their state before this function. */
+	restore_clocks(fs);
+
+	fs->is_enabled = true;
+	return 0;
+
+err:
+	restore_clocks(fs);
+	return rc;
+}
+
+static int gfx2d_footswitch_disable(struct regulator_dev *rdev)
+{
+	struct footswitch *fs = rdev_get_drvdata(rdev);
+	struct fs_clk_data *clock;
+	uint32_t regval, rc = 0;
+
+	/* Return early if already disabled. */
+	regval = readl_relaxed(fs->gfs_ctl_reg);
+	if ((regval & ENABLE_BIT) == 0)
+		return 0;
+
+	/* Make sure required clocks are on at the correct rates. */
+	rc = setup_clocks(fs);
+	if (rc)
+		return rc;
+
+	/* Allow core memory to collapse when its clock is gated. */
+	clk_set_flags(fs->core_clk, CLKFLAG_NORETAIN);
+
+	/* Halt all bus ports in the power domain. */
+	if (fs->bus_port0) {
+		rc = msm_bus_axi_porthalt(fs->bus_port0);
+		if (rc) {
+			pr_err("%s port 0 halt failed.\n", fs->desc.name);
+			goto err;
+		}
+	}
+
+	/* Disable core clock. */
+	clk_disable_unprepare(fs->core_clk);
+
+	/*
+	 * Assert resets for all clocks in the clock domain so that
+	 * outputs settle prior to clamping.
+	 */
+	for (clock = fs->clk_data; clock->clk; clock++)
+		; /* Do nothing */
+	for (clock--; clock >= fs->clk_data; clock--)
+		clk_reset(clock->clk, CLK_RESET_ASSERT);
+	/* Wait for synchronous resets to propagate. */
+	udelay(5);
+
+	/*
+	 * Clamp the I/O ports of the core to ensure the values
+	 * remain fixed while the core is collapsed.
+	 */
+	regval |= CLAMP_BIT;
+	writel_relaxed(regval, fs->gfs_ctl_reg);
+
+	/* Collapse the power rail at the footswitch. */
+	regval &= ~ENABLE_BIT;
+	writel_relaxed(regval, fs->gfs_ctl_reg);
+
+	/* Re-enable core clock. */
+	clk_prepare_enable(fs->core_clk);
+
+	/* Return clocks to their state before this function. */
+	restore_clocks(fs);
+
+	fs->is_enabled = false;
+	return 0;
+
+err:
+	clk_set_flags(fs->core_clk, CLKFLAG_RETAIN);
+	restore_clocks(fs);
+	return rc;
+}
+
+static struct regulator_ops standard_fs_ops = {
+	.is_enabled = footswitch_is_enabled,
+	.enable = footswitch_enable,
+	.disable = footswitch_disable,
+};
+
+static struct regulator_ops gfx2d_fs_ops = {
+	.is_enabled = footswitch_is_enabled,
+	.enable = gfx2d_footswitch_enable,
+	.disable = gfx2d_footswitch_disable,
+};
+
+#define FOOTSWITCH(_id, _name, _ops, _gfs_ctl_reg) \
+	[(_id)] = { \
+		.desc = { \
+			.id = (_id), \
+			.name = (_name), \
+			.ops = (_ops), \
+			.type = REGULATOR_VOLTAGE, \
+			.owner = THIS_MODULE, \
+		}, \
+		.gfs_ctl_reg = (_gfs_ctl_reg), \
+	}
+static struct footswitch footswitches[] = {
+	FOOTSWITCH(FS_GFX2D0, "fs_gfx2d0", &gfx2d_fs_ops, GFX2D0_GFS_CTL_REG),
+	FOOTSWITCH(FS_GFX2D1, "fs_gfx2d1", &gfx2d_fs_ops, GFX2D1_GFS_CTL_REG),
+	FOOTSWITCH(FS_GFX3D,  "fs_gfx3d", &standard_fs_ops, GFX3D_GFS_CTL_REG),
+	FOOTSWITCH(FS_IJPEG,  "fs_ijpeg", &standard_fs_ops, GEMINI_GFS_CTL_REG),
+	FOOTSWITCH(FS_MDP,    "fs_mdp",   &standard_fs_ops, MDP_GFS_CTL_REG),
+	FOOTSWITCH(FS_ROT,    "fs_rot",   &standard_fs_ops, ROT_GFS_CTL_REG),
+	FOOTSWITCH(FS_VED,    "fs_ved",   &standard_fs_ops, VED_GFS_CTL_REG),
+	FOOTSWITCH(FS_VFE,    "fs_vfe",   &standard_fs_ops, VFE_GFS_CTL_REG),
+	FOOTSWITCH(FS_VPE,    "fs_vpe",   &standard_fs_ops, VPE_GFS_CTL_REG),
+	FOOTSWITCH(FS_VCAP,   "fs_vcap",  &standard_fs_ops, VCAP_GFS_CTL_REG),
+};
+
+static int footswitch_probe(struct platform_device *pdev)
+{
+	struct footswitch *fs;
+	struct regulator_init_data *init_data;
+	struct fs_driver_data *driver_data;
+	struct fs_clk_data *clock;
+	uint32_t regval, rc = 0;
+
+	if (pdev == NULL)
+		return -EINVAL;
+
+	if (pdev->id >= MAX_FS)
+		return -ENODEV;
+
+	init_data = pdev->dev.platform_data;
+	driver_data = init_data->driver_data;
+	fs = &footswitches[pdev->id];
+	fs->clk_data = driver_data->clks;
+	fs->bus_port0 = driver_data->bus_port0;
+	fs->bus_port1 = driver_data->bus_port1;
+
+	for (clock = fs->clk_data; clock->name; clock++) {
+		clock->clk = clk_get(&pdev->dev, clock->name);
+		if (IS_ERR(clock->clk)) {
+			rc = PTR_ERR(clock->clk);
+			pr_err("%s clk_get(%s) failed\n", fs->desc.name,
+			       clock->name);
+			goto err;
+		}
+		if (!strncmp(clock->name, "core_clk", 8))
+			fs->core_clk = clock->clk;
+	}
+
+	/*
+	 * Set number of AHB_CLK cycles to delay the assertion of gfs_en_all
+	 * after enabling the footswitch.  Also ensure the retention bit is
+	 * clear so disabling the footswitch will power-collapse the core.
+	 */
+	regval = readl_relaxed(fs->gfs_ctl_reg);
+	regval |= GFS_DELAY_CNT;
+	regval &= ~RETENTION_BIT;
+	writel_relaxed(regval, fs->gfs_ctl_reg);
+
+	fs->rdev = regulator_register(&fs->desc, &pdev->dev,
+							init_data, fs, NULL);
+	if (IS_ERR(footswitches[pdev->id].rdev)) {
+		pr_err("regulator_register(\"%s\") failed\n",
+			fs->desc.name);
+		rc = PTR_ERR(footswitches[pdev->id].rdev);
+		goto err;
+	}
+
+	return 0;
+
+err:
+	for (clock = fs->clk_data; clock->clk; clock++)
+		clk_put(clock->clk);
+
+	return rc;
+}
+
+static int __devexit footswitch_remove(struct platform_device *pdev)
+{
+	struct footswitch *fs = &footswitches[pdev->id];
+	struct fs_clk_data *clock;
+
+	for (clock = fs->clk_data; clock->clk; clock++)
+		clk_put(clock->clk);
+	regulator_unregister(fs->rdev);
+
+	return 0;
+}
+
+static struct platform_driver footswitch_driver = {
+	.probe		= footswitch_probe,
+	.remove		= __devexit_p(footswitch_remove),
+	.driver		= {
+		.name		= "footswitch-8x60",
+		.owner		= THIS_MODULE,
+	},
+};
+
+static int __init late_footswitch_init(void)
+{
+	int i;
+
+	mutex_lock(&claim_lock);
+	/* Turn off all registered but unused footswitches. */
+	for (i = 0; i < ARRAY_SIZE(footswitches); i++)
+		if (footswitches[i].rdev && !footswitches[i].is_claimed)
+			footswitches[i].rdev->desc->ops->
+				disable(footswitches[i].rdev);
+	mutex_unlock(&claim_lock);
+
+	return 0;
+}
+late_initcall(late_footswitch_init);
+
+static int __init footswitch_init(void)
+{
+	return platform_driver_register(&footswitch_driver);
+}
+subsys_initcall(footswitch_init);
+
+static void __exit footswitch_exit(void)
+{
+	platform_driver_unregister(&footswitch_driver);
+}
+module_exit(footswitch_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MSM8x60 rail footswitch");
+MODULE_ALIAS("platform:footswitch-msm8x60");
diff --git a/arch/arm/mach-msm/footswitch-pcom.c b/arch/arm/mach-msm/footswitch-pcom.c
new file mode 100644
index 0000000..07d7118
--- /dev/null
+++ b/arch/arm/mach-msm/footswitch-pcom.c
@@ -0,0 +1,335 @@
+/* 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
+ * 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <mach/socinfo.h>
+#include <mach/proc_comm.h>
+#include "footswitch.h"
+
+/* PCOM power rail IDs */
+#define PCOM_FS_GRP		8
+#define PCOM_FS_GRP_2D		58
+#define PCOM_FS_MDP		14
+#define PCOM_FS_MFC		68
+#define PCOM_FS_ROTATOR		90
+#define PCOM_FS_VFE		41
+#define PCOM_FS_VPE		76
+
+#define PCOM_RAIL_MODE_AUTO	0
+#define PCOM_RAIL_MODE_MANUAL	1
+
+/**
+ * struct footswitch - Per-footswitch data and state
+ * @rdev: Regulator framework device
+ * @desc: Regulator descriptor
+ * @init_data: Regulator platform data
+ * @pcom_id: Proc-comm ID of the footswitch
+ * @is_enabled: Flag set when footswitch is enabled
+ * @is_manual: Flag set when footswitch is in manual proc-comm mode
+ * @has_ahb_clk: Flag set if footswitched core has an ahb_clk
+ * @has_src_clk: Flag set if footswitched core has a src_clk
+ * @src_clk: Controls the core clock's rate
+ * @core_clk: Clocks the core
+ * @ahb_clk: Clocks the core's register interface
+ * @src_clk_init_rate: Rate to use for src_clk if it has not been set yet
+ * @is_rate_set: Flag set if core_clk's rate has been set
+ */
+struct footswitch {
+	struct regulator_dev			*rdev;
+	struct regulator_desc			desc;
+	struct regulator_init_data		init_data;
+	unsigned				pcom_id;
+	bool					is_enabled;
+	bool					is_manual;
+	struct clk				*src_clk;
+	struct clk				*core_clk;
+	struct clk				*ahb_clk;
+	const bool				has_ahb_clk;
+	const bool				has_src_clk;
+	const int				src_clk_init_rate;
+	bool					is_rate_set;
+};
+
+static inline int set_rail_mode(int pcom_id, int mode)
+{
+	int  rc;
+
+	rc = msm_proc_comm(PCOM_CLKCTL_RPC_RAIL_CONTROL, &pcom_id, &mode);
+	if (!rc && pcom_id)
+		rc = -EINVAL;
+
+	return rc;
+}
+
+static inline int set_rail_state(int pcom_id, int state)
+{
+	int  rc;
+
+	rc = msm_proc_comm(state, &pcom_id, NULL);
+	if (!rc && pcom_id)
+		rc = -EINVAL;
+
+	return rc;
+}
+
+static int enable_clocks(struct footswitch *fs)
+{
+	fs->is_rate_set = !!(clk_get_rate(fs->src_clk));
+	if (!fs->is_rate_set)
+		clk_set_rate(fs->src_clk, fs->src_clk_init_rate);
+	clk_prepare_enable(fs->core_clk);
+
+	if (fs->ahb_clk)
+		clk_prepare_enable(fs->ahb_clk);
+
+	return 0;
+}
+
+static void disable_clocks(struct footswitch *fs)
+{
+	if (fs->ahb_clk)
+		clk_disable_unprepare(fs->ahb_clk);
+	clk_disable_unprepare(fs->core_clk);
+}
+
+static int footswitch_is_enabled(struct regulator_dev *rdev)
+{
+	struct footswitch *fs = rdev_get_drvdata(rdev);
+
+	return fs->is_enabled;
+}
+
+static int footswitch_enable(struct regulator_dev *rdev)
+{
+	struct footswitch *fs = rdev_get_drvdata(rdev);
+	int rc;
+
+	rc = enable_clocks(fs);
+	if (rc)
+		return rc;
+
+	rc = set_rail_state(fs->pcom_id, PCOM_CLKCTL_RPC_RAIL_ENABLE);
+	if (!rc)
+		fs->is_enabled = true;
+
+	disable_clocks(fs);
+
+	return rc;
+}
+
+static int footswitch_disable(struct regulator_dev *rdev)
+{
+	struct footswitch *fs = rdev_get_drvdata(rdev);
+	int rc;
+
+	rc = enable_clocks(fs);
+	if (rc)
+		return rc;
+
+	rc = set_rail_state(fs->pcom_id, PCOM_CLKCTL_RPC_RAIL_DISABLE);
+	if (!rc)
+		fs->is_enabled = false;
+
+	disable_clocks(fs);
+
+	return rc;
+}
+
+static struct regulator_ops footswitch_ops = {
+	.is_enabled = footswitch_is_enabled,
+	.enable = footswitch_enable,
+	.disable = footswitch_disable,
+};
+
+#define FOOTSWITCH(_id, _pcom_id, _name, _src_clk, _rate, _ahb_clk) \
+	[_id] = { \
+		.desc = { \
+			.id = _id, \
+			.name = _name, \
+			.ops = &footswitch_ops, \
+			.type = REGULATOR_VOLTAGE, \
+			.owner = THIS_MODULE, \
+		}, \
+		.pcom_id = _pcom_id, \
+		.has_src_clk = _src_clk, \
+		.src_clk_init_rate = _rate, \
+		.has_ahb_clk = _ahb_clk, \
+	}
+static struct footswitch footswitches[] = {
+	FOOTSWITCH(FS_GFX3D,  PCOM_FS_GRP,
+		"fs_gfx3d",   true, 24576000, true),
+	FOOTSWITCH(FS_GFX2D0, PCOM_FS_GRP_2D,
+		"fs_gfx2d0", false, 24576000, true),
+	FOOTSWITCH(FS_MDP,    PCOM_FS_MDP,
+		"fs_mdp",    false, 24576000, true),
+	FOOTSWITCH(FS_MFC,    PCOM_FS_MFC,
+		"fs_mfc",    false, 24576000, true),
+	FOOTSWITCH(FS_ROT,    PCOM_FS_ROTATOR,
+		"fs_rot",    false,        0, true),
+	FOOTSWITCH(FS_VFE,    PCOM_FS_VFE,
+		"fs_vfe",    false, 24576000, true),
+	FOOTSWITCH(FS_VPE,    PCOM_FS_VPE,
+		"fs_vpe",    false, 24576000, false),
+};
+
+static int get_clocks(struct device *dev, struct footswitch *fs)
+{
+	int rc;
+
+	/*
+	 * Some SoCs may not have a separate rate-settable clock.
+	 * If one can't be found, try to use the core clock for
+	 * rate-setting instead.
+	 */
+	if (fs->has_src_clk) {
+		fs->src_clk = clk_get(dev, "src_clk");
+		if (IS_ERR(fs->src_clk))
+			fs->src_clk = clk_get(dev, "core_clk");
+	} else {
+		fs->src_clk = clk_get(dev, "core_clk");
+	}
+	if (IS_ERR(fs->src_clk)) {
+		pr_err("%s clk_get(src_clk) failed\n", fs->desc.name);
+		rc = PTR_ERR(fs->src_clk);
+		goto err_src_clk;
+	}
+
+	fs->core_clk = clk_get(dev, "core_clk");
+	if (IS_ERR(fs->core_clk)) {
+		pr_err("%s clk_get(core_clk) failed\n", fs->desc.name);
+		rc = PTR_ERR(fs->core_clk);
+		goto err_core_clk;
+	}
+
+	if (fs->has_ahb_clk) {
+		fs->ahb_clk = clk_get(dev, "iface_clk");
+		if (IS_ERR(fs->ahb_clk)) {
+			pr_err("%s clk_get(iface_clk) failed\n", fs->desc.name);
+			rc = PTR_ERR(fs->ahb_clk);
+			goto err_ahb_clk;
+		}
+	}
+
+	return 0;
+
+err_ahb_clk:
+	clk_put(fs->core_clk);
+err_core_clk:
+	clk_put(fs->src_clk);
+err_src_clk:
+	return rc;
+}
+
+static void put_clocks(struct footswitch *fs)
+{
+	clk_put(fs->src_clk);
+	clk_put(fs->core_clk);
+	clk_put(fs->ahb_clk);
+}
+
+static int footswitch_probe(struct platform_device *pdev)
+{
+	struct footswitch *fs;
+	struct regulator_init_data *init_data;
+	int rc;
+
+	if (pdev == NULL)
+		return -EINVAL;
+
+	if (pdev->id >= MAX_FS)
+		return -ENODEV;
+
+	fs = &footswitches[pdev->id];
+	if (!fs->is_manual) {
+		pr_err("%s is not in manual mode\n", fs->desc.name);
+		return -EINVAL;
+	}
+	init_data = pdev->dev.platform_data;
+
+	rc = get_clocks(&pdev->dev, fs);
+	if (rc)
+		return rc;
+
+	fs->rdev = regulator_register(&fs->desc, &pdev->dev,
+							init_data, fs, NULL);
+	if (IS_ERR(fs->rdev)) {
+		pr_err("regulator_register(%s) failed\n", fs->desc.name);
+		rc = PTR_ERR(fs->rdev);
+		goto err_register;
+	}
+
+	return 0;
+
+err_register:
+	put_clocks(fs);
+
+	return rc;
+}
+
+static int __devexit footswitch_remove(struct platform_device *pdev)
+{
+	struct footswitch *fs = &footswitches[pdev->id];
+
+	regulator_unregister(fs->rdev);
+	set_rail_mode(fs->pcom_id, PCOM_RAIL_MODE_AUTO);
+	put_clocks(fs);
+
+	return 0;
+}
+
+static struct platform_driver footswitch_driver = {
+	.probe		= footswitch_probe,
+	.remove		= __devexit_p(footswitch_remove),
+	.driver		= {
+		.name		= "footswitch-pcom",
+		.owner		= THIS_MODULE,
+	},
+};
+
+static int __init footswitch_init(void)
+{
+	struct footswitch *fs;
+	int ret;
+
+	/*
+	 * Enable all footswitches in manual mode (ie. not controlled along
+	 * with pcom clocks).
+	 */
+	for (fs = footswitches; fs < footswitches + ARRAY_SIZE(footswitches);
+	     fs++) {
+		set_rail_state(fs->pcom_id, PCOM_CLKCTL_RPC_RAIL_ENABLE);
+		ret = set_rail_mode(fs->pcom_id, PCOM_RAIL_MODE_MANUAL);
+		if (!ret)
+			fs->is_manual = 1;
+	}
+
+	return platform_driver_register(&footswitch_driver);
+}
+subsys_initcall(footswitch_init);
+
+static void __exit footswitch_exit(void)
+{
+	platform_driver_unregister(&footswitch_driver);
+}
+module_exit(footswitch_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("proc_comm rail footswitch");
+MODULE_ALIAS("platform:footswitch-pcom");
diff --git a/arch/arm/mach-msm/footswitch.h b/arch/arm/mach-msm/footswitch.h
new file mode 100644
index 0000000..1809b2e
--- /dev/null
+++ b/arch/arm/mach-msm/footswitch.h
@@ -0,0 +1,69 @@
+/* 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
+ * 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 __MSM_FOOTSWITCH__
+#define __MSM_FOOTSWITCH__
+
+#include <linux/regulator/machine.h>
+
+/* Device IDs */
+#define FS_GFX2D0	0
+#define FS_GFX2D1	1
+#define FS_GFX3D	2
+#define FS_IJPEG	3
+#define FS_MDP		4
+#define FS_MFC		5
+#define FS_ROT		6
+#define FS_VED		7
+#define FS_VFE		8
+#define FS_VPE		9
+#define FS_VCAP		10
+#define MAX_FS		11
+
+struct fs_clk_data {
+	const char *name;
+	struct clk *clk;
+	unsigned long rate;
+	unsigned long reset_rate;
+	bool enabled;
+};
+
+struct fs_driver_data {
+	int bus_port0, bus_port1;
+	struct fs_clk_data *clks;
+};
+
+#define FS_GENERIC(_drv_name, _id, _name, _dev_id, _data) \
+(&(struct platform_device){ \
+	.name	= (_drv_name), \
+	.id	= (_id), \
+	.dev	= { \
+		.platform_data = &(struct regulator_init_data){ \
+			.constraints = { \
+				.valid_modes_mask = REGULATOR_MODE_NORMAL, \
+				.valid_ops_mask   = REGULATOR_CHANGE_STATUS, \
+			}, \
+			.num_consumer_supplies = 1, \
+			.consumer_supplies = \
+				&(struct regulator_consumer_supply) \
+				REGULATOR_SUPPLY((_name), (_dev_id)), \
+			.driver_data = (_data), \
+		} \
+	}, \
+})
+#define FS_PCOM(_id, _name, _dev_id) \
+		FS_GENERIC("footswitch-pcom", _id, _name, _dev_id, NULL)
+#define FS_8X60(_id, _name, _dev_id, _data) \
+		FS_GENERIC("footswitch-8x60", _id, _name, _dev_id, _data)
+
+#endif
diff --git a/arch/arm/mach-msm/gdsc.c b/arch/arm/mach-msm/gdsc.c
new file mode 100644
index 0000000..df3a92d
--- /dev/null
+++ b/arch/arm/mach-msm/gdsc.c
@@ -0,0 +1,192 @@
+/*
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
+#define PWR_ON_MASK		BIT(31)
+#define EN_REST_WAIT_MASK	(0xF << 20)
+#define EN_FEW_WAIT_MASK	(0xF << 16)
+#define CLK_DIS_WAIT_MASK	(0xF << 12)
+#define SW_OVERRIDE_MASK	BIT(2)
+#define HW_CONTROL_MASK		BIT(1)
+#define SW_COLLAPSE_MASK	BIT(0)
+
+/* Wait 2^n CXO cycles between all states. Here, n=2 (4 cycles). */
+#define EN_REST_WAIT_VAL	(0x2 << 20)
+#define EN_FEW_WAIT_VAL		(0x2 << 16)
+#define CLK_DIS_WAIT_VAL	(0x2 << 12)
+
+#define TIMEOUT_US		10
+
+struct gdsc {
+	struct regulator_dev	*rdev;
+	struct regulator_desc	rdesc;
+	void __iomem		*gdscr;
+};
+
+static int gdsc_is_enabled(struct regulator_dev *rdev)
+{
+	struct gdsc *sc = rdev_get_drvdata(rdev);
+
+	return !!(readl_relaxed(sc->gdscr) & PWR_ON_MASK);
+}
+
+static int gdsc_enable(struct regulator_dev *rdev)
+{
+	struct gdsc *sc = rdev_get_drvdata(rdev);
+	uint32_t regval;
+	int ret;
+
+	regval = readl_relaxed(sc->gdscr);
+	regval &= ~SW_COLLAPSE_MASK;
+	writel_relaxed(regval, sc->gdscr);
+
+	ret = readl_tight_poll_timeout(sc->gdscr, regval, regval & PWR_ON_MASK,
+				       TIMEOUT_US);
+	if (ret)
+		dev_err(&rdev->dev, "%s enable timed out\n", sc->rdesc.name);
+
+	return ret;
+}
+
+static int gdsc_disable(struct regulator_dev *rdev)
+{
+	struct gdsc *sc = rdev_get_drvdata(rdev);
+	uint32_t regval;
+	int ret;
+
+	regval = readl_relaxed(sc->gdscr);
+	regval |= SW_COLLAPSE_MASK;
+	writel_relaxed(regval, sc->gdscr);
+
+	ret = readl_tight_poll_timeout(sc->gdscr, regval,
+				       !(regval & PWR_ON_MASK), TIMEOUT_US);
+	if (ret)
+		dev_err(&rdev->dev, "%s disable timed out\n", sc->rdesc.name);
+
+	return ret;
+}
+
+static struct regulator_ops gdsc_ops = {
+	.is_enabled = gdsc_is_enabled,
+	.enable = gdsc_enable,
+	.disable = gdsc_disable,
+};
+
+static int __devinit gdsc_probe(struct platform_device *pdev)
+{
+	static atomic_t gdsc_count = ATOMIC_INIT(-1);
+	struct regulator_init_data *init_data;
+	struct resource *res;
+	struct gdsc *sc;
+	uint32_t regval;
+	int ret;
+
+	sc = devm_kzalloc(&pdev->dev, sizeof(struct gdsc), GFP_KERNEL);
+	if (sc == NULL)
+		return -ENOMEM;
+
+	init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node);
+	if (init_data == NULL)
+		return -ENOMEM;
+
+	if (of_get_property(pdev->dev.of_node, "parent-supply", NULL))
+		init_data->supply_regulator = "parent";
+
+	ret = of_property_read_string(pdev->dev.of_node, "regulator-name",
+				      &sc->rdesc.name);
+	if (ret)
+		return ret;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL)
+		return -EINVAL;
+	sc->gdscr = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (sc->gdscr == NULL)
+		return -ENOMEM;
+
+	sc->rdesc.id = atomic_inc_return(&gdsc_count);
+	sc->rdesc.ops = &gdsc_ops;
+	sc->rdesc.type = REGULATOR_VOLTAGE;
+	sc->rdesc.owner = THIS_MODULE;
+	platform_set_drvdata(pdev, sc);
+
+	/*
+	 * Disable HW trigger: collapse/restore occur based on registers writes.
+	 * Disable SW override: Use hardware state-machine for sequencing.
+	 */
+	regval = readl_relaxed(sc->gdscr);
+	regval &= ~(HW_CONTROL_MASK | SW_OVERRIDE_MASK);
+
+	/* Configure wait time between states. */
+	regval &= ~(EN_REST_WAIT_MASK | EN_FEW_WAIT_MASK | CLK_DIS_WAIT_MASK);
+	regval |= EN_REST_WAIT_VAL | EN_FEW_WAIT_VAL | CLK_DIS_WAIT_VAL;
+	writel_relaxed(regval, sc->gdscr);
+
+	sc->rdev = regulator_register(&sc->rdesc, &pdev->dev, init_data, sc,
+				      pdev->dev.of_node);
+	if (IS_ERR(sc->rdev)) {
+		dev_err(&pdev->dev, "regulator_register(\"%s\") failed.\n",
+			sc->rdesc.name);
+		return PTR_ERR(sc->rdev);
+	}
+
+	return 0;
+}
+
+static int __devexit gdsc_remove(struct platform_device *pdev)
+{
+	struct gdsc *sc = platform_get_drvdata(pdev);
+	regulator_unregister(sc->rdev);
+	return 0;
+}
+
+static struct of_device_id gdsc_match_table[] = {
+	{ .compatible = "qcom,gdsc" },
+	{}
+};
+
+static struct platform_driver gdsc_driver = {
+	.probe		= gdsc_probe,
+	.remove		= __devexit_p(gdsc_remove),
+	.driver		= {
+		.name		= "gdsc",
+		.of_match_table = gdsc_match_table,
+		.owner		= THIS_MODULE,
+	},
+};
+
+static int __init gdsc_init(void)
+{
+	return platform_driver_register(&gdsc_driver);
+}
+subsys_initcall(gdsc_init);
+
+static void __exit gdsc_exit(void)
+{
+	platform_driver_unregister(&gdsc_driver);
+}
+module_exit(gdsc_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Copper GDSC power rail regulator driver");
diff --git a/arch/arm/mach-msm/gpio.h b/arch/arm/mach-msm/gpio.h
new file mode 100644
index 0000000..59ee8f8
--- /dev/null
+++ b/arch/arm/mach-msm/gpio.h
@@ -0,0 +1,28 @@
+/* Copyright (c) 2008-2009, 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 _ARCH_ARM_MACH_MSM_GPIO_H_
+#define _ARCH_ARM_MACH_MSM_GPIO_H_
+
+void msm_gpio_enter_sleep(int from_idle);
+void msm_gpio_exit_sleep(void);
+
+/* Locate the GPIO_OUT register for the given GPIO and return its address
+ * and the bit position of the gpio's bit within the register.
+ *
+ * This function is used by gpiomux-v1 in order to support output transitions.
+ */
+void msm_gpio_find_out(const unsigned gpio, void __iomem **out,
+	unsigned *offset);
+
+#endif
diff --git a/arch/arm/mach-msm/gpiomux-7x27.c b/arch/arm/mach-msm/gpiomux-7x27.c
new file mode 100644
index 0000000..822cd04
--- /dev/null
+++ b/arch/arm/mach-msm/gpiomux-7x27.c
@@ -0,0 +1,20 @@
+/* Copyright (c) 2010, 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/module.h>
+#include <mach/irqs.h>
+#include <mach/gpiomux.h>
+
+static int __init gpiomux_init(void)
+{
+	return msm_gpiomux_init(NR_GPIO_IRQS);
+}
+postcore_initcall(gpiomux_init);
diff --git a/arch/arm/mach-msm/gpiomux-7x30.c b/arch/arm/mach-msm/gpiomux-7x30.c
new file mode 100644
index 0000000..822cd04
--- /dev/null
+++ b/arch/arm/mach-msm/gpiomux-7x30.c
@@ -0,0 +1,20 @@
+/* Copyright (c) 2010, 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/module.h>
+#include <mach/irqs.h>
+#include <mach/gpiomux.h>
+
+static int __init gpiomux_init(void)
+{
+	return msm_gpiomux_init(NR_GPIO_IRQS);
+}
+postcore_initcall(gpiomux_init);
diff --git a/arch/arm/mach-msm/gpiomux-8x50.c b/arch/arm/mach-msm/gpiomux-8x50.c
index f7a4ea5..822cd04 100644
--- a/arch/arm/mach-msm/gpiomux-8x50.c
+++ b/arch/arm/mach-msm/gpiomux-8x50.c
@@ -8,44 +8,13 @@
  * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
  */
-#include "gpiomux.h"
+#include <linux/module.h>
+#include <mach/irqs.h>
+#include <mach/gpiomux.h>
 
-#if defined(CONFIG_MMC_MSM) || defined(CONFIG_MMC_MSM_MODULE)
-	#define SDCC_DAT_0_3_CMD_ACTV_CFG (GPIOMUX_VALID | GPIOMUX_PULL_UP\
-					| GPIOMUX_FUNC_1 | GPIOMUX_DRV_8MA)
-	#define SDCC_CLK_ACTV_CFG (GPIOMUX_VALID | GPIOMUX_PULL_NONE\
-					| GPIOMUX_FUNC_1 | GPIOMUX_DRV_8MA)
-#else
-	#define SDCC_DAT_0_3_CMD_ACTV_CFG 0
-	#define SDCC_CLK_ACTV_CFG 0
-#endif
-
-#define SDC1_SUSPEND_CONFIG (GPIOMUX_VALID | GPIOMUX_PULL_DOWN\
-				| GPIOMUX_FUNC_GPIO | GPIOMUX_DRV_2MA)
-
-struct msm_gpiomux_config msm_gpiomux_configs[GPIOMUX_NGPIOS] = {
-	[86] = { /* UART3 RX */
-		.suspended = GPIOMUX_DRV_2MA | GPIOMUX_PULL_DOWN |
-			     GPIOMUX_FUNC_1 | GPIOMUX_VALID,
-	},
-	[87] = { /* UART3 TX */
-		.suspended = GPIOMUX_DRV_2MA | GPIOMUX_PULL_DOWN |
-			     GPIOMUX_FUNC_1 | GPIOMUX_VALID,
-	},
-	/* SDC1 data[3:0] & CMD */
-	[51 ... 55] = {
-		.active = SDCC_DAT_0_3_CMD_ACTV_CFG,
-		.suspended = SDC1_SUSPEND_CONFIG
-	},
-	/* SDC1 CLK */
-	[56] = {
-		.active = SDCC_CLK_ACTV_CFG,
-		.suspended = SDC1_SUSPEND_CONFIG
-	},
-};
+static int __init gpiomux_init(void)
+{
+	return msm_gpiomux_init(NR_GPIO_IRQS);
+}
+postcore_initcall(gpiomux_init);
diff --git a/arch/arm/mach-msm/gpiomux-8x60.c b/arch/arm/mach-msm/gpiomux-8x60.c
index 7b380b3..c23a41c 100644
--- a/arch/arm/mach-msm/gpiomux-8x60.c
+++ b/arch/arm/mach-msm/gpiomux-8x60.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -8,12 +8,1724 @@
  * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
  */
-#include "gpiomux.h"
+#include <linux/module.h>
+#include <mach/irqs.h>
+#include <asm/mach-types.h>
+#include <mach/gpiomux.h>
+#include "gpiomux-8x60.h"
 
-struct msm_gpiomux_config msm_gpiomux_configs[GPIOMUX_NGPIOS] = {};
+static struct gpiomux_setting console_uart = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+/* The SPI configurations apply to GSBI1 and GSBI10 */
+static struct gpiomux_setting spi_active = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting spi_suspended_config = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting spi_suspended_cs_config = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+/* This I2C active configuration applies to GSBI3 and GSBI4 */
+static struct gpiomux_setting i2c_active = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting i2c_active_gsbi7 = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_12MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+/* This I2C suspended configuration applies to GSBI3, GSBI4 and GSBI7 */
+static struct gpiomux_setting i2c_suspended_config = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi8 = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting ps_hold = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_12MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting msm_snddev_active_config = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting msm_snddev_suspend_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting ebi2_a_d = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting ebi2_oe = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting ebi2_we = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting ebi2_cs2 = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting ebi2_cs3 = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+#if defined(CONFIG_USB_PEHCI_HCD) || defined(CONFIG_USB_PEHCI_HCD_MODULE)
+static struct gpiomux_setting ebi2_cs4 = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+#endif
+
+static struct gpiomux_setting ebi2_adv = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+#if defined(CONFIG_USB_PEHCI_HCD) || defined(CONFIG_USB_PEHCI_HCD_MODULE)
+static struct gpiomux_setting usb_isp1763_actv_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting usb_isp1763_susp_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+#endif
+
+static struct gpiomux_setting sdcc1_dat_0_3_cmd_actv_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_10MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting sdcc1_dat_4_7_cmd_actv_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_10MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting sdcc1_clk_actv_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_16MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting sdcc1_suspend_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting sdcc2_dat_0_3_cmd_actv_cfg = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_10MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting sdcc2_dat_4_7_cmd_actv_cfg = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_10MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting sdcc2_clk_actv_cfg = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_16MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting sdcc2_suspend_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting sdcc5_dat_0_3_cmd_actv_cfg = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_10MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting sdcc5_clk_actv_cfg = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_16MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting sdcc5_suspend_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting aux_pcm_active_config = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting aux_pcm_suspend_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting uart1dm_active = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting uart1dm_suspended = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting mi2s_active_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting mi2s_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting lcdc_active_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_16MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting lcdc_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting mdp_vsync_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting hdmi_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting mdm2ap_status_active_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting mdm2ap_status_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting cam_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting mdm2ap_sync_active_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting mdm2ap_sync_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting tm_active = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting tm_suspended = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting tma_active = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting ts_suspended = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting mdp_vsync_active_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting hdmi_active_1_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting hdmi_active_2_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_16MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting hdmi_active_3_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_16MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting pmic_suspended_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting cam_active_1_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting cam_active_2_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting cam_active_3_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting cam_active_4_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting cam_active_5_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_4MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+#ifdef CONFIG_MSM_GSBI9_UART
+static struct gpiomux_setting uart9dm_active = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA ,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting gsbi9 = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+#endif
+
+static struct gpiomux_setting ap2mdm_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting mdm2ap_status_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting mdm2ap_vfr_active_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting mdm2ap_vfr_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting mdm2ap_errfatal_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_16MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting ap2mdm_kpdpwr_n_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+
+static struct gpiomux_setting mdm2ap_vddmin_active_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting mdm2ap_vddmin_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct msm_gpiomux_config msm8x60_gsbi_configs[] __initdata = {
+	{
+		.gpio      = 33,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &spi_suspended_config,
+			[GPIOMUX_ACTIVE]    = &spi_active,
+		},
+	},
+	{
+		.gpio      = 34,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &spi_suspended_config,
+			[GPIOMUX_ACTIVE]    = &spi_active,
+		},
+	},
+	{
+		.gpio      = 35,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &spi_suspended_cs_config,
+			[GPIOMUX_ACTIVE]    = &spi_active,
+		},
+	},
+	{
+		.gpio      = 36,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &spi_suspended_config,
+			[GPIOMUX_ACTIVE]    = &spi_active,
+		},
+	},
+	{
+		.gpio      = 43,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &i2c_suspended_config,
+			[GPIOMUX_ACTIVE]    = &i2c_active,
+		},
+	},
+	{
+		.gpio      = 44,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &i2c_suspended_config,
+			[GPIOMUX_ACTIVE]    = &i2c_active,
+		},
+	},
+	{
+		.gpio      = 47,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &i2c_suspended_config,
+			[GPIOMUX_ACTIVE]    = &i2c_active,
+		},
+	},
+	{
+		.gpio      = 48,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &i2c_suspended_config,
+			[GPIOMUX_ACTIVE]    = &i2c_active,
+		},
+	},
+	{
+		.gpio      = 59,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &i2c_suspended_config,
+			[GPIOMUX_ACTIVE]    = &i2c_active_gsbi7,
+		},
+	},
+	{
+		.gpio      = 60,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &i2c_suspended_config,
+			[GPIOMUX_ACTIVE]    = &i2c_active_gsbi7,
+		},
+	},
+	{
+		.gpio      = 64,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi8,
+		},
+	},
+	{
+		.gpio      = 65,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi8,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8x60_fluid_gsbi_configs[] __initdata = {
+	{
+		.gpio      = 70,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &spi_suspended_config,
+			[GPIOMUX_ACTIVE]    = &spi_active,
+		},
+	},
+	{
+		.gpio      = 72,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &spi_suspended_cs_config,
+			[GPIOMUX_ACTIVE]    = &spi_active,
+		},
+	},
+	{
+		.gpio      = 73,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &spi_suspended_config,
+			[GPIOMUX_ACTIVE]    = &spi_active,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8x60_ebi2_configs[] __initdata = {
+	{
+		.gpio      = 40,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_cs2,
+		},
+	},
+	{
+		.gpio      = 123,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_a_d,
+		},
+	},
+	{
+		.gpio      = 124,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_a_d,
+		},
+	},
+	{
+		.gpio      = 125,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_a_d,
+		},
+	},
+	{
+		.gpio      = 126,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_a_d,
+		},
+	},
+	{
+		.gpio      = 127,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_a_d,
+		},
+	},
+	{
+		.gpio      = 128,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_a_d,
+		},
+	},
+	{
+		.gpio      = 129,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_a_d,
+		},
+	},
+	{
+		.gpio      = 130,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_a_d,
+		},
+	},
+#if defined(CONFIG_USB_PEHCI_HCD) || defined(CONFIG_USB_PEHCI_HCD_MODULE)
+	/* ISP VDD_3V3_EN */
+	{
+		.gpio      = 132,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_cs4,
+		},
+	},
+#endif
+	{
+		.gpio      = 133,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_cs3,
+		},
+	},
+	{
+		.gpio      = 135,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_a_d,
+		},
+	},
+	{
+		.gpio      = 136,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_a_d,
+		},
+	},
+	{
+		.gpio      = 137,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_a_d,
+		},
+	},
+	{
+		.gpio      = 138,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_a_d,
+		},
+	},
+	{
+		.gpio      = 139,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_a_d,
+		},
+	},
+	{
+		.gpio      = 140,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_a_d,
+		},
+	},
+	{
+		.gpio      = 141,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_a_d,
+		},
+	},
+	{
+		.gpio      = 142,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_a_d,
+		},
+	},
+	{
+		.gpio      = 143,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_a_d,
+		},
+	},
+	{
+		.gpio      = 144,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_a_d,
+		},
+	},
+	{
+		.gpio      = 145,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_a_d,
+		},
+	},
+	{
+		.gpio      = 146,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_a_d,
+		},
+	},
+	{
+		.gpio      = 147,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_a_d,
+		},
+	},
+	{
+		.gpio      = 148,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_a_d,
+		},
+	},
+	{
+		.gpio      = 149,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_a_d,
+		},
+	},
+	{
+		.gpio      = 150,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_a_d,
+		},
+	},
+	{
+		.gpio      = 151,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_oe,
+		},
+	},
+	{
+		.gpio      = 153,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_adv,
+		},
+	},
+	{
+		.gpio      = 157,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ebi2_we,
+		},
+	},
+};
+
+#if defined(CONFIG_USB_PEHCI_HCD) || defined(CONFIG_USB_PEHCI_HCD_MODULE)
+static struct msm_gpiomux_config msm8x60_isp_usb_configs[] __initdata = {
+	{
+		.gpio      = 117,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &usb_isp1763_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &usb_isp1763_susp_cfg,
+		},
+	},
+	{
+		.gpio      = 152,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &usb_isp1763_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &usb_isp1763_susp_cfg,
+		},
+	},
+
+};
+#endif
+
+static struct msm_gpiomux_config msm8x60_uart_configs[] __initdata = {
+	{ /* UARTDM_TX */
+		.gpio      = 53,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &uart1dm_active,
+			[GPIOMUX_SUSPENDED] = &uart1dm_suspended,
+		},
+	},
+	{ /* UARTDM_RX */
+		.gpio      = 54,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &uart1dm_active,
+			[GPIOMUX_SUSPENDED] = &uart1dm_suspended,
+		},
+	},
+	{ /* UARTDM_CTS */
+		.gpio      = 55,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &uart1dm_active,
+			[GPIOMUX_SUSPENDED] = &uart1dm_suspended,
+		},
+	},
+	{ /* UARTDM_RFR */
+		.gpio      = 56,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &uart1dm_active,
+			[GPIOMUX_SUSPENDED] = &uart1dm_suspended,
+		},
+	},
+	{
+		.gpio      = 115,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &console_uart,
+		},
+	},
+	{
+		.gpio      = 116,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &console_uart,
+		},
+	},
+#if !defined(CONFIG_USB_PEHCI_HCD) && !defined(CONFIG_USB_PEHCI_HCD_MODULE)
+	/* USB ISP1763 may also use 117 GPIO */
+	{
+		.gpio      = 117,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &console_uart,
+		},
+	},
+#endif
+	{
+		.gpio      = 118,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &console_uart,
+		},
+	},
+};
+
+#ifdef CONFIG_MSM_GSBI9_UART
+static struct msm_gpiomux_config msm8x60_charm_uart_configs[] __initdata = {
+	{ /* UART9DM  RX */
+		.gpio	   = 66,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &uart9dm_active,
+			[GPIOMUX_SUSPENDED] = &gsbi9,
+		},
+	},
+	{ /* UART9DM TX */
+		.gpio	   = 67,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &uart9dm_active,
+			[GPIOMUX_SUSPENDED] = &gsbi9,
+		},
+	},
+};
+#endif
+
+static struct msm_gpiomux_config msm8x60_ts_configs[] __initdata = {
+	{
+		/* TS_ATTN */
+		.gpio = 58,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ts_suspended,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8x60_tmg200_configs[] __initdata = {
+	{
+		.gpio = 61,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &tm_active,
+			[GPIOMUX_SUSPENDED] = &tm_suspended,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8x60_tma300_configs[] __initdata = {
+	{
+		.gpio = 61,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &tma_active,
+			[GPIOMUX_SUSPENDED] = &tm_suspended,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8x60_aux_pcm_configs[] __initdata = {
+	{
+		.gpio = 111,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &aux_pcm_active_config,
+			[GPIOMUX_SUSPENDED] = &aux_pcm_suspend_config,
+		},
+	},
+	{
+		.gpio = 112,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &aux_pcm_active_config,
+			[GPIOMUX_SUSPENDED] = &aux_pcm_suspend_config,
+		},
+	},
+	{
+		.gpio = 113,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &aux_pcm_active_config,
+			[GPIOMUX_SUSPENDED] = &aux_pcm_suspend_config,
+		},
+	},
+	{
+		.gpio = 114,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &aux_pcm_active_config,
+			[GPIOMUX_SUSPENDED] = &aux_pcm_suspend_config,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8x60_sdc_configs[] __initdata = {
+	/* SDCC1 data[0] */
+	{
+		.gpio = 159,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc1_dat_0_3_cmd_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc1_suspend_config,
+		},
+	},
+	/* SDCC1 data[1] */
+	{
+		.gpio = 160,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc1_dat_0_3_cmd_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc1_suspend_config,
+		},
+	},
+	/* SDCC1 data[2] */
+	{
+		.gpio = 161,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc1_dat_0_3_cmd_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc1_suspend_config,
+		},
+	},
+	/* SDCC1 data[3] */
+	{
+		.gpio = 162,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc1_dat_0_3_cmd_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc1_suspend_config,
+		},
+	},
+	/* SDCC1 data[4] */
+	{
+		.gpio = 163,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc1_dat_4_7_cmd_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc1_suspend_config,
+		},
+	},
+	/* SDCC1 data[5] */
+	{
+		.gpio = 164,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc1_dat_4_7_cmd_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc1_suspend_config,
+		},
+	},
+	/* SDCC1 data[6] */
+	{
+		.gpio = 165,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc1_dat_4_7_cmd_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc1_suspend_config,
+		},
+	},
+	/* SDCC1 data[7] */
+	{
+		.gpio = 166,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc1_dat_4_7_cmd_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc1_suspend_config,
+		},
+	},
+	/* SDCC1 CLK */
+	{
+		.gpio = 167,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc1_clk_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc1_suspend_config,
+		},
+	},
+	/* SDCC1 CMD */
+	{
+		.gpio = 168,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc1_dat_0_3_cmd_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc1_suspend_config,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8x60_charm_sdc_configs[] __initdata = {
+	/* SDCC5 cmd */
+	{
+		.gpio = 95,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc5_dat_0_3_cmd_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc5_suspend_config,
+		},
+	},
+	/* SDCC5 data[3]*/
+	{
+		.gpio = 96,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc5_dat_0_3_cmd_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc5_suspend_config,
+		},
+	},
+	/* SDCC5 clk */
+	{
+		.gpio = 97,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc5_clk_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc5_suspend_config,
+		},
+	},
+	/* SDCC5 data[2]*/
+	{
+		.gpio = 98,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc5_dat_0_3_cmd_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc5_suspend_config,
+		},
+	},
+	/* SDCC5 data[1]*/
+	{
+		.gpio = 99,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc5_dat_0_3_cmd_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc5_suspend_config,
+		},
+	},
+	/* SDCC5 data[0]*/
+	{
+		.gpio = 100,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc5_dat_0_3_cmd_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc5_suspend_config,
+		},
+	},
+	/* MDM2AP_SYNC */
+	{
+		.gpio = 129,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &mdm2ap_sync_active_cfg,
+			[GPIOMUX_SUSPENDED] = &mdm2ap_sync_suspend_cfg,
+		},
+	},
+
+	/* MDM2AP_VDDMIN */
+	{
+		.gpio = 140,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &mdm2ap_vddmin_active_cfg,
+			[GPIOMUX_SUSPENDED] = &mdm2ap_vddmin_suspend_cfg,
+		},
+	},
+	/* SDCC2 data[0] */
+	{
+		.gpio = 143,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_dat_0_3_cmd_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_config,
+		},
+	},
+	/* SDCC2 data[1] */
+	{
+		.gpio = 144,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_dat_0_3_cmd_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_config,
+		},
+	},
+	/* SDCC2 data[2] */
+	{
+		.gpio = 145,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_dat_0_3_cmd_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_config,
+		},
+	},
+	/* SDCC2 data[3] */
+	{
+		.gpio = 146,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_dat_0_3_cmd_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_config,
+		},
+	},
+	/* SDCC2 data[4] */
+	{
+		.gpio = 147,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_dat_4_7_cmd_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_config,
+		},
+	},
+	/* SDCC2 data[5] */
+	{
+		.gpio = 148,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_dat_4_7_cmd_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_config,
+		},
+	},
+	/* SDCC2 data[6] */
+	{
+		.gpio = 149,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_dat_4_7_cmd_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_config,
+		},
+	},
+	/* SDCC2 data[7] */
+	{
+		.gpio = 150,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_dat_4_7_cmd_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_config,
+		},
+	},
+	/* SDCC2 CMD */
+	{
+		.gpio = 151,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_dat_0_3_cmd_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_config,
+		},
+	},
+
+	/* SDCC2 CLK */
+	{
+		.gpio = 152,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_clk_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_config,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8x60_snd_configs[] __initdata = {
+	{
+		.gpio = 108,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &msm_snddev_active_config,
+			[GPIOMUX_SUSPENDED] = &msm_snddev_suspend_config,
+		},
+	},
+	{
+		.gpio = 109,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &msm_snddev_active_config,
+			[GPIOMUX_SUSPENDED] = &msm_snddev_suspend_config,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8x60_mi2s_configs[] __initdata = {
+	/* MI2S WS */
+	{
+		.gpio = 101,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &mi2s_active_cfg,
+			[GPIOMUX_SUSPENDED] = &mi2s_suspend_cfg,
+		},
+	},
+	/* MI2S SCLK */
+	{
+		.gpio = 102,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &mi2s_active_cfg,
+			[GPIOMUX_SUSPENDED] = &mi2s_suspend_cfg,
+		},
+	},
+	/* MI2S MCLK */
+	{
+		.gpio = 103,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &mi2s_active_cfg,
+			[GPIOMUX_SUSPENDED] = &mi2s_suspend_cfg,
+		},
+	},
+	/* MI2S SD3 */
+	{
+		.gpio = 107,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &mi2s_active_cfg,
+			[GPIOMUX_SUSPENDED] = &mi2s_suspend_cfg,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8x60_lcdc_configs[] __initdata = {
+	/* lcdc_pclk */
+	{
+		.gpio = 0,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcdc_active_cfg,
+			[GPIOMUX_SUSPENDED] = &lcdc_suspend_cfg,
+		},
+	},
+	/* lcdc_hsync */
+	{
+		.gpio = 1,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcdc_active_cfg,
+			[GPIOMUX_SUSPENDED] = &lcdc_suspend_cfg,
+		},
+	},
+	/* lcdc_vsync */
+	{
+		.gpio = 2,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcdc_active_cfg,
+			[GPIOMUX_SUSPENDED] = &lcdc_suspend_cfg,
+		},
+	},
+	/* lcdc_den */
+	{
+		.gpio = 3,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcdc_active_cfg,
+			[GPIOMUX_SUSPENDED] = &lcdc_suspend_cfg,
+		},
+	},
+	/* lcdc_red7 */
+	{
+		.gpio = 4,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcdc_active_cfg,
+			[GPIOMUX_SUSPENDED] = &lcdc_suspend_cfg,
+		},
+	},
+	/* lcdc_red6 */
+	{
+		.gpio = 5,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcdc_active_cfg,
+			[GPIOMUX_SUSPENDED] = &lcdc_suspend_cfg,
+		},
+	},
+	/* lcdc_red5 */
+	{
+		.gpio = 6,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcdc_active_cfg,
+			[GPIOMUX_SUSPENDED] = &lcdc_suspend_cfg,
+		},
+	},
+	/* lcdc_red4 */
+	{
+		.gpio = 7,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcdc_active_cfg,
+			[GPIOMUX_SUSPENDED] = &lcdc_suspend_cfg,
+		},
+	},
+	/* lcdc_red3 */
+	{
+		.gpio = 8,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcdc_active_cfg,
+			[GPIOMUX_SUSPENDED] = &lcdc_suspend_cfg,
+		},
+	},
+	/* lcdc_red2 */
+	{
+		.gpio = 9,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcdc_active_cfg,
+			[GPIOMUX_SUSPENDED] = &lcdc_suspend_cfg,
+		},
+	},
+	/* lcdc_red1 */
+	{
+		.gpio = 10,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcdc_active_cfg,
+			[GPIOMUX_SUSPENDED] = &lcdc_suspend_cfg,
+		},
+	},
+	/* lcdc_red0 */
+	{
+		.gpio = 11,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcdc_active_cfg,
+			[GPIOMUX_SUSPENDED] = &lcdc_suspend_cfg,
+		},
+	},
+	/* lcdc_grn7 */
+	{
+		.gpio = 12,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcdc_active_cfg,
+			[GPIOMUX_SUSPENDED] = &lcdc_suspend_cfg,
+		},
+	},
+	/* lcdc_grn6 */
+	{
+		.gpio = 13,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcdc_active_cfg,
+			[GPIOMUX_SUSPENDED] = &lcdc_suspend_cfg,
+		},
+	},
+	/* lcdc_grn5 */
+	{
+		.gpio = 14,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcdc_active_cfg,
+			[GPIOMUX_SUSPENDED] = &lcdc_suspend_cfg,
+		},
+	},
+	/* lcdc_grn4 */
+	{
+		.gpio = 15,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcdc_active_cfg,
+			[GPIOMUX_SUSPENDED] = &lcdc_suspend_cfg,
+		},
+	},
+	/* lcdc_grn3 */
+	{
+		.gpio = 16,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcdc_active_cfg,
+			[GPIOMUX_SUSPENDED] = &lcdc_suspend_cfg,
+		},
+	},
+	/* lcdc_grn2 */
+	{
+		.gpio = 17,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcdc_active_cfg,
+			[GPIOMUX_SUSPENDED] = &lcdc_suspend_cfg,
+		},
+	},
+	/* lcdc_grn1 */
+	{
+		.gpio = 18,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcdc_active_cfg,
+			[GPIOMUX_SUSPENDED] = &lcdc_suspend_cfg,
+		},
+	},
+	/* lcdc_grn0 */
+	{
+		.gpio = 19,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcdc_active_cfg,
+			[GPIOMUX_SUSPENDED] = &lcdc_suspend_cfg,
+		},
+	},
+	/* lcdc_blu7 */
+	{
+		.gpio = 20,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcdc_active_cfg,
+			[GPIOMUX_SUSPENDED] = &lcdc_suspend_cfg,
+		},
+	},
+	/* lcdc_blu6 */
+	{
+		.gpio = 21,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcdc_active_cfg,
+			[GPIOMUX_SUSPENDED] = &lcdc_suspend_cfg,
+		},
+	},
+	/* lcdc_blu5 */
+	{
+		.gpio = 22,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcdc_active_cfg,
+			[GPIOMUX_SUSPENDED] = &lcdc_suspend_cfg,
+		},
+	},
+	/* lcdc_blu4 */
+	{
+		.gpio = 23,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcdc_active_cfg,
+			[GPIOMUX_SUSPENDED] = &lcdc_suspend_cfg,
+		},
+	},
+	/* lcdc_blu3 */
+	{
+		.gpio = 24,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcdc_active_cfg,
+			[GPIOMUX_SUSPENDED] = &lcdc_suspend_cfg,
+		},
+	},
+	/* lcdc_blu2 */
+	{
+		.gpio = 25,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcdc_active_cfg,
+			[GPIOMUX_SUSPENDED] = &lcdc_suspend_cfg,
+		},
+	},
+	/* lcdc_blu1 */
+	{
+		.gpio = 26,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcdc_active_cfg,
+			[GPIOMUX_SUSPENDED] = &lcdc_suspend_cfg,
+		},
+	},
+	/* lcdc_blu0 */
+	{
+		.gpio = 27,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcdc_active_cfg,
+			[GPIOMUX_SUSPENDED] = &lcdc_suspend_cfg,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8x60_mdp_vsync_configs[] __initdata = {
+	{
+		.gpio = 28,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &mdp_vsync_active_cfg,
+			[GPIOMUX_SUSPENDED] = &mdp_vsync_suspend_cfg,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8x60_hdmi_configs[] __initdata = {
+	{
+		.gpio = 169,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_1_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 170,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_2_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 171,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_2_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 172,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_3_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+};
+
+/* Because PMIC drivers do not use gpio-management routines and PMIC
+ * gpios must never sleep, a "good enough" config is obtained by placing
+ * the active config in the 'suspended' slot and leaving the active
+ * config invalid: the suspended config will be installed at boot
+ * and never replaced.
+ */
+
+static struct msm_gpiomux_config msm8x60_pmic_configs[] __initdata = {
+	{
+		.gpio = 88,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &pmic_suspended_cfg,
+		},
+	},
+	{
+		.gpio = 91,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &pmic_suspended_cfg,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8x60_common_configs[] __initdata = {
+	/* MDM2AP_STATUS */
+	{
+		.gpio = 77,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &mdm2ap_status_active_cfg,
+			[GPIOMUX_SUSPENDED] = &mdm2ap_status_suspend_cfg,
+		},
+	},
+	/* PS_HOLD */
+	{
+		.gpio      = 92,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ps_hold,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8x60_cam_configs[] __initdata = {
+	{
+		.gpio = 29,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_active_2_cfg,
+			[GPIOMUX_SUSPENDED] = &cam_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 30,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_active_1_cfg,
+			[GPIOMUX_SUSPENDED] = &cam_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 31,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_active_2_cfg,
+			[GPIOMUX_SUSPENDED] = &cam_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 32,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_active_5_cfg,
+			[GPIOMUX_SUSPENDED] = &cam_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 42,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_active_2_cfg,
+			[GPIOMUX_SUSPENDED] = &cam_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 47,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_active_3_cfg,
+			[GPIOMUX_SUSPENDED] = &cam_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 48,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_active_3_cfg,
+			[GPIOMUX_SUSPENDED] = &cam_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 105,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_active_4_cfg,
+			[GPIOMUX_SUSPENDED] = &cam_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 106,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_active_4_cfg,
+			[GPIOMUX_SUSPENDED] = &cam_suspend_cfg,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm8x60_charm_configs[] __initdata = {
+	/* AP2MDM_WAKEUP */
+	{
+		.gpio = 135,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
+		}
+	},
+	/* MDM2AP_VFR */
+	{
+		.gpio = 94,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &mdm2ap_vfr_active_cfg,
+			[GPIOMUX_SUSPENDED] = &mdm2ap_vfr_suspend_cfg,
+		}
+	},
+	/* AP2MDM_STATUS */
+	{
+		.gpio = 136,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
+		}
+	},
+	/* MDM2AP_STATUS */
+	{
+		.gpio = 134,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &mdm2ap_status_cfg,
+		}
+	},
+	/* MDM2AP_WAKEUP */
+	{
+		.gpio = 40,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
+		}
+	},
+	/* MDM2AP_ERRFATAL */
+	{
+		.gpio = 133,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &mdm2ap_errfatal_cfg,
+		}
+	},
+	/* AP2MDM_ERRFATAL */
+	{
+		.gpio = 93,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
+		}
+	},
+	/* AP2MDM_KPDPWR_N */
+	{
+		.gpio = 132,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_kpdpwr_n_cfg,
+		}
+	},
+	/* AP2MDM_PMIC_RESET_N */
+	{
+		.gpio = 131,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_kpdpwr_n_cfg,
+		}
+	}
+};
+
+struct msm_gpiomux_configs
+msm8x60_surf_ffa_gpiomux_cfgs[] __initdata = {
+	{msm8x60_gsbi_configs, ARRAY_SIZE(msm8x60_gsbi_configs)},
+	{msm8x60_ebi2_configs, ARRAY_SIZE(msm8x60_ebi2_configs)},
+	{msm8x60_uart_configs, ARRAY_SIZE(msm8x60_uart_configs)},
+#if defined(CONFIG_USB_PEHCI_HCD) || defined(CONFIG_USB_PEHCI_HCD_MODULE)
+	{msm8x60_isp_usb_configs, ARRAY_SIZE(msm8x60_isp_usb_configs)},
+#endif
+	{msm8x60_ts_configs, ARRAY_SIZE(msm8x60_ts_configs)},
+	{msm8x60_aux_pcm_configs, ARRAY_SIZE(msm8x60_aux_pcm_configs)},
+	{msm8x60_sdc_configs, ARRAY_SIZE(msm8x60_sdc_configs)},
+	{msm8x60_snd_configs, ARRAY_SIZE(msm8x60_snd_configs)},
+	{msm8x60_mi2s_configs, ARRAY_SIZE(msm8x60_mi2s_configs)},
+	{msm8x60_lcdc_configs, ARRAY_SIZE(msm8x60_lcdc_configs)},
+	{msm8x60_mdp_vsync_configs, ARRAY_SIZE(msm8x60_mdp_vsync_configs)},
+	{msm8x60_hdmi_configs, ARRAY_SIZE(msm8x60_hdmi_configs)},
+	{msm8x60_pmic_configs, ARRAY_SIZE(msm8x60_pmic_configs)},
+	{msm8x60_common_configs, ARRAY_SIZE(msm8x60_common_configs)},
+	{msm8x60_cam_configs, ARRAY_SIZE(msm8x60_cam_configs)},
+	{msm8x60_tmg200_configs, ARRAY_SIZE(msm8x60_tmg200_configs)},
+	{NULL, 0},
+};
+
+struct msm_gpiomux_configs
+msm8x60_fluid_gpiomux_cfgs[] __initdata = {
+	{msm8x60_gsbi_configs, ARRAY_SIZE(msm8x60_gsbi_configs)},
+	{msm8x60_fluid_gsbi_configs, ARRAY_SIZE(msm8x60_fluid_gsbi_configs)},
+	{msm8x60_ebi2_configs, ARRAY_SIZE(msm8x60_ebi2_configs)},
+	{msm8x60_uart_configs, ARRAY_SIZE(msm8x60_uart_configs)},
+	{msm8x60_ts_configs, ARRAY_SIZE(msm8x60_ts_configs)},
+	{msm8x60_aux_pcm_configs, ARRAY_SIZE(msm8x60_aux_pcm_configs)},
+	{msm8x60_sdc_configs, ARRAY_SIZE(msm8x60_sdc_configs)},
+	{msm8x60_snd_configs, ARRAY_SIZE(msm8x60_snd_configs)},
+	{msm8x60_mi2s_configs, ARRAY_SIZE(msm8x60_mi2s_configs)},
+	{msm8x60_lcdc_configs, ARRAY_SIZE(msm8x60_lcdc_configs)},
+	{msm8x60_mdp_vsync_configs, ARRAY_SIZE(msm8x60_mdp_vsync_configs)},
+	{msm8x60_hdmi_configs, ARRAY_SIZE(msm8x60_hdmi_configs)},
+	{msm8x60_pmic_configs, ARRAY_SIZE(msm8x60_pmic_configs)},
+	{msm8x60_common_configs, ARRAY_SIZE(msm8x60_common_configs)},
+	{msm8x60_cam_configs, ARRAY_SIZE(msm8x60_cam_configs)},
+	{msm8x60_tma300_configs, ARRAY_SIZE(msm8x60_tma300_configs)},
+	{NULL, 0},
+};
+
+struct msm_gpiomux_configs
+msm8x60_charm_gpiomux_cfgs[] __initdata = {
+	{msm8x60_gsbi_configs, ARRAY_SIZE(msm8x60_gsbi_configs)},
+	{msm8x60_uart_configs, ARRAY_SIZE(msm8x60_uart_configs)},
+#ifdef CONFIG_MSM_GSBI9_UART
+	{msm8x60_charm_uart_configs, ARRAY_SIZE(msm8x60_charm_uart_configs)},
+#endif
+	{msm8x60_ts_configs, ARRAY_SIZE(msm8x60_ts_configs)},
+	{msm8x60_aux_pcm_configs, ARRAY_SIZE(msm8x60_aux_pcm_configs)},
+	{msm8x60_sdc_configs, ARRAY_SIZE(msm8x60_sdc_configs)},
+	{msm8x60_snd_configs, ARRAY_SIZE(msm8x60_snd_configs)},
+	{msm8x60_mi2s_configs, ARRAY_SIZE(msm8x60_mi2s_configs)},
+	{msm8x60_lcdc_configs, ARRAY_SIZE(msm8x60_lcdc_configs)},
+	{msm8x60_mdp_vsync_configs, ARRAY_SIZE(msm8x60_mdp_vsync_configs)},
+	{msm8x60_hdmi_configs, ARRAY_SIZE(msm8x60_hdmi_configs)},
+	{msm8x60_pmic_configs, ARRAY_SIZE(msm8x60_pmic_configs)},
+	{msm8x60_common_configs, ARRAY_SIZE(msm8x60_common_configs)},
+	{msm8x60_cam_configs, ARRAY_SIZE(msm8x60_cam_configs)},
+	{msm8x60_tmg200_configs, ARRAY_SIZE(msm8x60_tmg200_configs)},
+	{msm8x60_charm_sdc_configs, ARRAY_SIZE(msm8x60_charm_sdc_configs)},
+	{msm8x60_charm_configs, ARRAY_SIZE(msm8x60_charm_configs)},
+	{NULL, 0},
+};
+
+struct msm_gpiomux_configs
+msm8x60_dragon_gpiomux_cfgs[] __initdata = {
+	{msm8x60_gsbi_configs, ARRAY_SIZE(msm8x60_gsbi_configs)},
+	{msm8x60_ebi2_configs, ARRAY_SIZE(msm8x60_ebi2_configs)},
+	{msm8x60_uart_configs, ARRAY_SIZE(msm8x60_uart_configs)},
+#if defined(CONFIG_USB_PEHCI_HCD) || defined(CONFIG_USB_PEHCI_HCD_MODULE)
+	{msm8x60_isp_usb_configs, ARRAY_SIZE(msm8x60_isp_usb_configs)},
+#endif
+	{msm8x60_ts_configs, ARRAY_SIZE(msm8x60_ts_configs)},
+	{msm8x60_aux_pcm_configs, ARRAY_SIZE(msm8x60_aux_pcm_configs)},
+	{msm8x60_sdc_configs, ARRAY_SIZE(msm8x60_sdc_configs)},
+	{msm8x60_snd_configs, ARRAY_SIZE(msm8x60_snd_configs)},
+	{msm8x60_mi2s_configs, ARRAY_SIZE(msm8x60_mi2s_configs)},
+	{msm8x60_lcdc_configs, ARRAY_SIZE(msm8x60_lcdc_configs)},
+	{msm8x60_mdp_vsync_configs, ARRAY_SIZE(msm8x60_mdp_vsync_configs)},
+	{msm8x60_hdmi_configs, ARRAY_SIZE(msm8x60_hdmi_configs)},
+	{msm8x60_pmic_configs, ARRAY_SIZE(msm8x60_pmic_configs)},
+	{msm8x60_common_configs, ARRAY_SIZE(msm8x60_common_configs)},
+	{msm8x60_cam_configs, ARRAY_SIZE(msm8x60_cam_configs)},
+	{msm8x60_tmg200_configs, ARRAY_SIZE(msm8x60_tmg200_configs)},
+	{NULL, 0},
+};
+
+void __init msm8x60_init_gpiomux(struct msm_gpiomux_configs *cfgs)
+{
+	int rc;
+
+	rc = msm_gpiomux_init(NR_GPIO_IRQS);
+	if (rc) {
+		pr_err("%s failure: %d\n", __func__, rc);
+		return;
+	}
+
+	while (cfgs->cfg) {
+		msm_gpiomux_install(cfgs->cfg, cfgs->ncfg);
+		++cfgs;
+	}
+}
diff --git a/arch/arm/mach-msm/gpiomux-8x60.h b/arch/arm/mach-msm/gpiomux-8x60.h
new file mode 100644
index 0000000..cacd1ba
--- /dev/null
+++ b/arch/arm/mach-msm/gpiomux-8x60.h
@@ -0,0 +1,22 @@
+/* Copyright (c) 2010, 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 __ARCH_ARM_MACH_MSM_GPIOMUX_8X60_H
+#define __ARCH_ARM_MACH_MSM_GPIOMUX_8X60_H
+
+void __init msm8x60_init_gpiomux(struct msm_gpiomux_configs *cfgs);
+
+extern struct msm_gpiomux_configs msm8x60_surf_ffa_gpiomux_cfgs[] __initdata;
+extern struct msm_gpiomux_configs msm8x60_fluid_gpiomux_cfgs[] __initdata;
+extern struct msm_gpiomux_configs msm8x60_charm_gpiomux_cfgs[] __initdata;
+extern struct msm_gpiomux_configs msm8x60_dragon_gpiomux_cfgs[] __initdata;
+
+#endif
diff --git a/arch/arm/mach-msm/gpiomux-v1.c b/arch/arm/mach-msm/gpiomux-v1.c
index 27de2ab..1163669 100644
--- a/arch/arm/mach-msm/gpiomux-v1.c
+++ b/arch/arm/mach-msm/gpiomux-v1.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2011 Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -8,23 +8,37 @@
  * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
  */
+#include <linux/bitops.h>
 #include <linux/kernel.h>
-#include "gpiomux.h"
-#include "proc_comm.h"
+#include <linux/io.h>
+#include <mach/gpiomux.h>
+#include <mach/proc_comm.h>
+#include "gpio.h"
 
-void __msm_gpiomux_write(unsigned gpio, gpiomux_config_t val)
+void __msm_gpiomux_write(unsigned gpio, struct gpiomux_setting val)
 {
-	unsigned tlmm_config  = (val & ~GPIOMUX_CTL_MASK) |
-				((gpio & 0x3ff) << 4);
+	unsigned tlmm_config;
 	unsigned tlmm_disable = 0;
+	void __iomem *out_reg;
+	unsigned offset;
+	uint32_t bits;
 	int rc;
 
+	tlmm_config  = (val.drv << 17) |
+		(val.pull << 15) |
+		((gpio & 0x3ff) << 4) |
+		val.func;
+	if (val.func == GPIOMUX_FUNC_GPIO) {
+		tlmm_config |= (val.dir > GPIOMUX_IN ? BIT(14) : 0);
+		msm_gpio_find_out(gpio, &out_reg, &offset);
+		bits = __raw_readl(out_reg);
+		if (val.dir == GPIOMUX_OUT_HIGH)
+			__raw_writel(bits | BIT(offset), out_reg);
+		else
+			__raw_writel(bits & ~BIT(offset), out_reg);
+	}
+	mb();
 	rc = msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX,
 			   &tlmm_config, &tlmm_disable);
 	if (rc)
diff --git a/arch/arm/mach-msm/gpiomux-v1.h b/arch/arm/mach-msm/gpiomux-v1.h
index 71d86fe..7cf4582 100644
--- a/arch/arm/mach-msm/gpiomux-v1.h
+++ b/arch/arm/mach-msm/gpiomux-v1.h
@@ -8,11 +8,6 @@
  * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
  */
 #ifndef __ARCH_ARM_MACH_MSM_GPIOMUX_V1_H
 #define __ARCH_ARM_MACH_MSM_GPIOMUX_V1_H
diff --git a/arch/arm/mach-msm/gpiomux-v2.c b/arch/arm/mach-msm/gpiomux-v2.c
index 273396d..ee1e17a 100644
--- a/arch/arm/mach-msm/gpiomux-v2.c
+++ b/arch/arm/mach-msm/gpiomux-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -8,18 +8,25 @@
  * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
  */
+#include <linux/bitops.h>
 #include <linux/io.h>
 #include <mach/msm_iomap.h>
-#include "gpiomux.h"
+#include <mach/gpiomux.h>
 
-void __msm_gpiomux_write(unsigned gpio, gpiomux_config_t val)
+#define GPIO_CFG(n)    (MSM_TLMM_BASE + 0x1000 + (0x10 * n))
+#define GPIO_IN_OUT(n) (MSM_TLMM_BASE + 0x1004 + (0x10 * n))
+
+void __msm_gpiomux_write(unsigned gpio, struct gpiomux_setting val)
 {
-	writel(val & ~GPIOMUX_CTL_MASK,
-	       MSM_TLMM_BASE + 0x1000 + (0x10 * gpio));
+	uint32_t bits;
+
+	bits = (val.drv << 6) | (val.func << 2) | val.pull;
+	if (val.func == GPIOMUX_FUNC_GPIO) {
+		bits |= val.dir > GPIOMUX_IN ? BIT(9) : 0;
+		__raw_writel(val.dir == GPIOMUX_OUT_HIGH ? BIT(1) : 0,
+			GPIO_IN_OUT(gpio));
+	}
+	__raw_writel(bits, GPIO_CFG(gpio));
+	mb();
 }
diff --git a/arch/arm/mach-msm/gpiomux-v2.h b/arch/arm/mach-msm/gpiomux-v2.h
index 3bf10e7..b200501 100644
--- a/arch/arm/mach-msm/gpiomux-v2.h
+++ b/arch/arm/mach-msm/gpiomux-v2.h
@@ -8,11 +8,6 @@
  * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
  */
 #ifndef __ARCH_ARM_MACH_MSM_GPIOMUX_V2_H
 #define __ARCH_ARM_MACH_MSM_GPIOMUX_V2_H
diff --git a/arch/arm/mach-msm/gpiomux.c b/arch/arm/mach-msm/gpiomux.c
index 53af21a..85936ba 100644
--- a/arch/arm/mach-msm/gpiomux.c
+++ b/arch/arm/mach-msm/gpiomux.c
@@ -8,57 +8,76 @@
  * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
  */
 #include <linux/module.h>
+#include <linux/slab.h>
 #include <linux/spinlock.h>
-#include "gpiomux.h"
+#include <mach/gpiomux.h>
 
+struct msm_gpiomux_rec {
+	struct gpiomux_setting *sets[GPIOMUX_NSETTINGS];
+	int ref;
+};
 static DEFINE_SPINLOCK(gpiomux_lock);
+static struct msm_gpiomux_rec *msm_gpiomux_recs;
+static struct gpiomux_setting *msm_gpiomux_sets;
+static unsigned msm_gpiomux_ngpio;
 
-int msm_gpiomux_write(unsigned gpio,
-		      gpiomux_config_t active,
-		      gpiomux_config_t suspended)
+int msm_gpiomux_write(unsigned gpio, enum msm_gpiomux_setting which,
+	struct gpiomux_setting *setting, struct gpiomux_setting *old_setting)
 {
-	struct msm_gpiomux_config *cfg = msm_gpiomux_configs + gpio;
+	struct msm_gpiomux_rec *rec = msm_gpiomux_recs + gpio;
+	unsigned set_slot = gpio * GPIOMUX_NSETTINGS + which;
 	unsigned long irq_flags;
-	gpiomux_config_t setting;
+	struct gpiomux_setting *new_set;
+	int status = 0;
 
-	if (gpio >= GPIOMUX_NGPIOS)
+	if (!msm_gpiomux_recs)
+		return -EFAULT;
+
+	if (gpio >= msm_gpiomux_ngpio)
 		return -EINVAL;
 
 	spin_lock_irqsave(&gpiomux_lock, irq_flags);
 
-	if (active & GPIOMUX_VALID)
-		cfg->active = active;
+	if (old_setting) {
+		if (rec->sets[which] == NULL)
+			status = 1;
+		else
+			*old_setting =  *(rec->sets[which]);
+	}
 
-	if (suspended & GPIOMUX_VALID)
-		cfg->suspended = suspended;
+	if (setting) {
+		msm_gpiomux_sets[set_slot] = *setting;
+		rec->sets[which] = &msm_gpiomux_sets[set_slot];
+	} else {
+		rec->sets[which] = NULL;
+	}
 
-	setting = cfg->ref ? active : suspended;
-	if (setting & GPIOMUX_VALID)
-		__msm_gpiomux_write(gpio, setting);
+	new_set = rec->ref ? rec->sets[GPIOMUX_ACTIVE] :
+		rec->sets[GPIOMUX_SUSPENDED];
+	if (new_set)
+		__msm_gpiomux_write(gpio, *new_set);
 
 	spin_unlock_irqrestore(&gpiomux_lock, irq_flags);
-	return 0;
+	return status;
 }
 EXPORT_SYMBOL(msm_gpiomux_write);
 
 int msm_gpiomux_get(unsigned gpio)
 {
-	struct msm_gpiomux_config *cfg = msm_gpiomux_configs + gpio;
+	struct msm_gpiomux_rec *rec = msm_gpiomux_recs + gpio;
 	unsigned long irq_flags;
 
-	if (gpio >= GPIOMUX_NGPIOS)
+	if (!msm_gpiomux_recs)
+		return -EFAULT;
+
+	if (gpio >= msm_gpiomux_ngpio)
 		return -EINVAL;
 
 	spin_lock_irqsave(&gpiomux_lock, irq_flags);
-	if (cfg->ref++ == 0 && cfg->active & GPIOMUX_VALID)
-		__msm_gpiomux_write(gpio, cfg->active);
+	if (rec->ref++ == 0 && rec->sets[GPIOMUX_ACTIVE])
+		__msm_gpiomux_write(gpio, *rec->sets[GPIOMUX_ACTIVE]);
 	spin_unlock_irqrestore(&gpiomux_lock, irq_flags);
 	return 0;
 }
@@ -66,31 +85,66 @@
 
 int msm_gpiomux_put(unsigned gpio)
 {
-	struct msm_gpiomux_config *cfg = msm_gpiomux_configs + gpio;
+	struct msm_gpiomux_rec *rec = msm_gpiomux_recs + gpio;
 	unsigned long irq_flags;
 
-	if (gpio >= GPIOMUX_NGPIOS)
+	if (!msm_gpiomux_recs)
+		return -EFAULT;
+
+	if (gpio >= msm_gpiomux_ngpio)
 		return -EINVAL;
 
 	spin_lock_irqsave(&gpiomux_lock, irq_flags);
-	BUG_ON(cfg->ref == 0);
-	if (--cfg->ref == 0 && cfg->suspended & GPIOMUX_VALID)
-		__msm_gpiomux_write(gpio, cfg->suspended);
+	BUG_ON(rec->ref == 0);
+	if (--rec->ref == 0 && rec->sets[GPIOMUX_SUSPENDED])
+		__msm_gpiomux_write(gpio, *rec->sets[GPIOMUX_SUSPENDED]);
 	spin_unlock_irqrestore(&gpiomux_lock, irq_flags);
 	return 0;
 }
 EXPORT_SYMBOL(msm_gpiomux_put);
 
-static int __init gpiomux_init(void)
+int msm_gpiomux_init(size_t ngpio)
 {
-	unsigned n;
+	if (!ngpio)
+		return -EINVAL;
 
-	for (n = 0; n < GPIOMUX_NGPIOS; ++n) {
-		msm_gpiomux_configs[n].ref = 0;
-		if (!(msm_gpiomux_configs[n].suspended & GPIOMUX_VALID))
-			continue;
-		__msm_gpiomux_write(n, msm_gpiomux_configs[n].suspended);
+	if (msm_gpiomux_recs)
+		return -EPERM;
+
+	msm_gpiomux_recs = kzalloc(sizeof(struct msm_gpiomux_rec) * ngpio,
+				   GFP_KERNEL);
+	if (!msm_gpiomux_recs)
+		return -ENOMEM;
+
+	/* There is no need to zero this memory, as clients will be blindly
+	 * installing settings on top of it.
+	 */
+	msm_gpiomux_sets = kmalloc(sizeof(struct gpiomux_setting) * ngpio *
+		GPIOMUX_NSETTINGS, GFP_KERNEL);
+	if (!msm_gpiomux_sets) {
+		kfree(msm_gpiomux_recs);
+		msm_gpiomux_recs = NULL;
+		return -ENOMEM;
 	}
+
+	msm_gpiomux_ngpio = ngpio;
+
 	return 0;
 }
-postcore_initcall(gpiomux_init);
+EXPORT_SYMBOL(msm_gpiomux_init);
+
+void msm_gpiomux_install(struct msm_gpiomux_config *configs, unsigned nconfigs)
+{
+	unsigned c, s;
+	int rc;
+
+	for (c = 0; c < nconfigs; ++c) {
+		for (s = 0; s < GPIOMUX_NSETTINGS; ++s) {
+			rc = msm_gpiomux_write(configs[c].gpio, s,
+				configs[c].settings[s], NULL);
+			if (rc)
+				pr_err("%s: write failure: %d\n", __func__, rc);
+		}
+	}
+}
+EXPORT_SYMBOL(msm_gpiomux_install);
diff --git a/arch/arm/mach-msm/gpiomux.h b/arch/arm/mach-msm/gpiomux.h
deleted file mode 100644
index 00459f6..0000000
--- a/arch/arm/mach-msm/gpiomux.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/* Copyright (c) 2010, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-#ifndef __ARCH_ARM_MACH_MSM_GPIOMUX_H
-#define __ARCH_ARM_MACH_MSM_GPIOMUX_H
-
-#include <linux/bitops.h>
-#include <linux/errno.h>
-#include <mach/msm_gpiomux.h>
-
-#if defined(CONFIG_MSM_V2_TLMM)
-#include "gpiomux-v2.h"
-#else
-#include "gpiomux-v1.h"
-#endif
-
-/**
- * struct msm_gpiomux_config: gpiomux settings for one gpio line.
- *
- * A complete gpiomux config is the bitwise-or of a drive-strength,
- * function, and pull.  For functions other than GPIO, the OE
- * is hard-wired according to the function.  For GPIO mode,
- * OE is controlled by gpiolib.
- *
- * Available settings differ by target; see the gpiomux header
- * specific to your target arch for available configurations.
- *
- * @active: The configuration to be installed when the line is
- * active, or its reference count is > 0.
- * @suspended: The configuration to be installed when the line
- * is suspended, or its reference count is 0.
- * @ref: The reference count of the line.  For internal use of
- * the gpiomux framework only.
- */
-struct msm_gpiomux_config {
-	gpiomux_config_t active;
-	gpiomux_config_t suspended;
-	unsigned         ref;
-};
-
-/**
- * @GPIOMUX_VALID:	If set, the config field contains 'good data'.
- *                      The absence of this bit will prevent the gpiomux
- *			system from applying the configuration under all
- *			circumstances.
- */
-enum {
-	GPIOMUX_VALID	 = BIT(sizeof(gpiomux_config_t) * BITS_PER_BYTE - 1),
-	GPIOMUX_CTL_MASK = GPIOMUX_VALID,
-};
-
-#ifdef CONFIG_MSM_GPIOMUX
-
-/* Each architecture must provide its own instance of this table.
- * To avoid having gpiomux manage any given gpio, one or both of
- * the entries can avoid setting GPIOMUX_VALID - the absence
- * of that flag will prevent the configuration from being applied
- * during state transitions.
- */
-extern struct msm_gpiomux_config msm_gpiomux_configs[GPIOMUX_NGPIOS];
-
-/* Install a new configuration to the gpio line.  To avoid overwriting
- * a configuration, leave the VALID bit out.
- */
-int msm_gpiomux_write(unsigned gpio,
-		      gpiomux_config_t active,
-		      gpiomux_config_t suspended);
-
-/* Architecture-internal function for use by the framework only.
- * This function can assume the following:
- * - the gpio value has passed a bounds-check
- * - the gpiomux spinlock has been obtained
- *
- * This function is not for public consumption.  External users
- * should use msm_gpiomux_write.
- */
-void __msm_gpiomux_write(unsigned gpio, gpiomux_config_t val);
-#else
-static inline int msm_gpiomux_write(unsigned gpio,
-				    gpiomux_config_t active,
-				    gpiomux_config_t suspended)
-{
-	return -ENOSYS;
-}
-#endif
-#endif
diff --git a/arch/arm/mach-msm/gss-8064.c b/arch/arm/mach-msm/gss-8064.c
new file mode 100644
index 0000000..126f8e0
--- /dev/null
+++ b/arch/arm/mach-msm/gss-8064.c
@@ -0,0 +1,289 @@
+/* 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/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/workqueue.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/stringify.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+
+#include <mach/irqs.h>
+#include <mach/msm_smsm.h>
+#include <mach/scm.h>
+#include <mach/peripheral-loader.h>
+#include <mach/subsystem_restart.h>
+#include <mach/subsystem_notif.h>
+#include <mach/socinfo.h>
+
+#include "smd_private.h"
+#include "modem_notifier.h"
+#include "ramdump.h"
+
+static struct gss_8064_data {
+	struct miscdevice gss_dev;
+	void *pil_handle;
+	void *gss_ramdump_dev;
+	void *smem_ramdump_dev;
+} gss_data;
+
+static int crash_shutdown;
+
+#define MAX_SSR_REASON_LEN 81U
+
+static void log_gss_sfr(void)
+{
+	u32 size;
+	char *smem_reason, reason[MAX_SSR_REASON_LEN];
+
+	smem_reason = smem_get_entry(SMEM_SSR_REASON_MSS0, &size);
+	if (!smem_reason || !size) {
+		pr_err("GSS subsystem failure reason: (unknown, smem_get_entry failed).\n");
+		return;
+	}
+	if (!smem_reason[0]) {
+		pr_err("GSS subsystem failure reason: (unknown, init string found).\n");
+		return;
+	}
+
+	size = min(size, MAX_SSR_REASON_LEN-1);
+	memcpy(reason, smem_reason, size);
+	reason[size] = '\0';
+	pr_err("GSS subsystem failure reason: %s.\n", reason);
+
+	smem_reason[0] = '\0';
+	wmb();
+}
+
+static void gss_fatal_fn(struct work_struct *work)
+{
+	uint32_t panic_smsm_states = SMSM_RESET | SMSM_SYSTEM_DOWNLOAD;
+	uint32_t reset_smsm_states = SMSM_SYSTEM_REBOOT_USR |
+					SMSM_SYSTEM_PWRDWN_USR;
+	uint32_t gss_state;
+
+	pr_err("Watchdog bite received from GSS!\n");
+
+	gss_state = smsm_get_state(SMSM_MODEM_STATE);
+
+	if (gss_state & panic_smsm_states) {
+
+		pr_err("GSS SMSM state changed to SMSM_RESET.\n"
+			"Probable err_fatal on the GSS. "
+			"Calling subsystem restart...\n");
+		log_gss_sfr();
+		subsystem_restart("gss");
+
+	} else if (gss_state & reset_smsm_states) {
+
+		pr_err("%s: User-invoked system reset/powerdown. "
+			"Resetting the SoC now.\n",
+			__func__);
+		kernel_restart(NULL);
+	} else {
+		/* TODO: Bus unlock code/sequence goes _here_ */
+		log_gss_sfr();
+		subsystem_restart("gss");
+	}
+}
+
+static DECLARE_WORK(gss_fatal_work, gss_fatal_fn);
+
+static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
+{
+	/* Ignore if we're the one that set SMSM_RESET */
+	if (crash_shutdown)
+		return;
+
+	if (new_state & SMSM_RESET) {
+		pr_err("GSS SMSM state changed to SMSM_RESET.\n"
+			"Probable err_fatal on the GSS. "
+			"Calling subsystem restart...\n");
+		log_gss_sfr();
+		subsystem_restart("gss");
+	}
+}
+
+#define Q6_FW_WDOG_ENABLE		0x08882024
+#define Q6_SW_WDOG_ENABLE		0x08982024
+static int gss_shutdown(const struct subsys_data *subsys)
+{
+	pil_force_shutdown("gss");
+	disable_irq_nosync(GSS_A5_WDOG_EXPIRED);
+
+	return 0;
+}
+
+static int gss_powerup(const struct subsys_data *subsys)
+{
+	pil_force_boot("gss");
+	enable_irq(GSS_A5_WDOG_EXPIRED);
+	return 0;
+}
+
+void gss_crash_shutdown(const struct subsys_data *subsys)
+{
+	crash_shutdown = 1;
+	smsm_reset_modem(SMSM_RESET);
+}
+
+/* FIXME: Get address, size from PIL */
+static struct ramdump_segment gss_segments[] = {
+	{0x89000000, 0x00D00000}
+};
+
+static struct ramdump_segment smem_segments[] = {
+	{0x80000000, 0x00200000},
+};
+
+static int gss_ramdump(int enable,
+				const struct subsys_data *crashed_subsys)
+{
+	int ret = 0;
+
+	if (enable) {
+		ret = do_ramdump(gss_data.gss_ramdump_dev, gss_segments,
+			ARRAY_SIZE(gss_segments));
+
+		if (ret < 0) {
+			pr_err("Unable to dump gss memory (rc = %d).\n",
+			       ret);
+			goto out;
+		}
+
+		ret = do_ramdump(gss_data.smem_ramdump_dev, smem_segments,
+			ARRAY_SIZE(smem_segments));
+
+		if (ret < 0) {
+			pr_err("Unable to dump smem memory (rc = %d).\n", ret);
+			goto out;
+		}
+	}
+
+out:
+	return ret;
+}
+
+static irqreturn_t gss_wdog_bite_irq(int irq, void *dev_id)
+{
+	schedule_work(&gss_fatal_work);
+	disable_irq_nosync(GSS_A5_WDOG_EXPIRED);
+
+	return IRQ_HANDLED;
+}
+
+static struct subsys_data gss_8064 = {
+	.name = "gss",
+	.shutdown = gss_shutdown,
+	.powerup = gss_powerup,
+	.ramdump = gss_ramdump,
+	.crash_shutdown = gss_crash_shutdown
+};
+
+static int gss_subsystem_restart_init(void)
+{
+	return ssr_register_subsystem(&gss_8064);
+}
+
+static int gss_open(struct inode *inode, struct file *filep)
+{
+	void *ret;
+	gss_data.pil_handle = ret = pil_get("gss");
+	if (!ret)
+		pr_debug("%s - pil_get returned NULL\n", __func__);
+	return 0;
+}
+
+static int gss_release(struct inode *inode, struct file *filep)
+{
+	pil_put(gss_data.pil_handle);
+	pr_debug("%s pil_put called on GSS\n", __func__);
+	return 0;
+}
+
+const struct file_operations gss_file_ops = {
+	.open = gss_open,
+	.release = gss_release,
+};
+
+static int __init gss_8064_init(void)
+{
+	int ret;
+
+	if (!cpu_is_apq8064())
+		return -ENODEV;
+
+	ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
+		smsm_state_cb, 0);
+
+	if (ret < 0)
+		pr_err("%s: Unable to register SMSM callback! (%d)\n",
+				__func__, ret);
+
+	ret = request_irq(GSS_A5_WDOG_EXPIRED, gss_wdog_bite_irq,
+			IRQF_TRIGGER_RISING, "gss_a5_wdog", NULL);
+
+	if (ret < 0) {
+		pr_err("%s: Unable to request gss watchdog IRQ. (%d)\n",
+				__func__, ret);
+		disable_irq_nosync(GSS_A5_WDOG_EXPIRED);
+		goto out;
+	}
+
+	ret = gss_subsystem_restart_init();
+
+	if (ret < 0) {
+		pr_err("%s: Unable to reg with subsystem restart. (%d)\n",
+				__func__, ret);
+		goto out;
+	}
+
+	gss_data.gss_dev.minor = MISC_DYNAMIC_MINOR;
+	gss_data.gss_dev.name = "gss";
+	gss_data.gss_dev.fops = &gss_file_ops;
+	ret = misc_register(&gss_data.gss_dev);
+
+	if (ret) {
+		pr_err("%s: misc_registers failed for %s (%d)", __func__,
+				gss_data.gss_dev.name, ret);
+		goto out;
+	}
+
+	gss_data.gss_ramdump_dev = create_ramdump_device("gss");
+
+	if (!gss_data.gss_ramdump_dev) {
+		pr_err("%s: Unable to create gss ramdump device. (%d)\n",
+				__func__, -ENOMEM);
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	gss_data.smem_ramdump_dev = create_ramdump_device("smem");
+
+	if (!gss_data.smem_ramdump_dev) {
+		pr_err("%s: Unable to create smem ramdump device. (%d)\n",
+				__func__, -ENOMEM);
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	pr_info("%s: gss fatal driver init'ed.\n", __func__);
+out:
+	return ret;
+}
+
+module_init(gss_8064_init);
diff --git a/arch/arm/mach-msm/headsmp.S b/arch/arm/mach-msm/headsmp.S
index bcd5af2..50d2060 100644
--- a/arch/arm/mach-msm/headsmp.S
+++ b/arch/arm/mach-msm/headsmp.S
@@ -1,8 +1,7 @@
 /*
- *  linux/arch/arm/mach-realview/headsmp.S
- *
  *  Copyright (c) 2003 ARM Limited
  *  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 as
@@ -11,31 +10,39 @@
 #include <linux/linkage.h>
 #include <linux/init.h>
 
-	__CPUINIT
+__CPUINIT
 
 /*
  * MSM specific entry point for secondary CPUs.  This provides
  * a "holding pen" into which all secondary cores are held until we're
  * ready for them to initialise.
+ *
+ * This is executing in physical space with cache's off.
  */
 ENTRY(msm_secondary_startup)
-	mrc	p15, 0, r0, c0, c0, 5
-	and	r0, r0, #15
-	adr	r4, 1f
-	ldmia	r4, {r5, r6}
-	sub	r4, r4, r5
-	add	r6, r6, r4
-pen:	ldr	r7, [r6]
-	cmp	r7, r0
+	mrc	p15, 0, r0, c0, c0, 5 	@ MPIDR
+	and	r0, r0, #15		@ What CPU am I
+	adr	r4, 1f			@ address of
+	ldmia	r4, {r5, r6}		@ load curr addr and pen_rel addr
+	sub	r4, r4, r5		@ determine virtual/phys offsets
+	add	r6, r6, r4		@ apply
+pen:
+	wfe
+	dsb				@ ensure subsequent access is
+					@ after event
+
+	ldr	r7, [r6]		@ pen_rel has cpu to remove from reset
+	cmp	r7, r0			@ are we lucky?
 	bne	pen
 
 	/*
 	 * we've been released from the holding pen: secondary_stack
 	 * should now contain the SVC stack for this core
 	 */
+	mvn	r7, #0			@ -1 to registers
+	str r7,[r6]			@ back to the pen for ack
 	b	secondary_startup
 ENDPROC(msm_secondary_startup)
 
-	.align
 1:	.long	.
 	.long	pen_release
diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c
index a446fc1..46e835f 100644
--- a/arch/arm/mach-msm/hotplug.c
+++ b/arch/arm/mach-msm/hotplug.c
@@ -1,6 +1,7 @@
 /*
  *  Copyright (C) 2002 ARM Ltd.
  *  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 as
@@ -9,12 +10,28 @@
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/smp.h>
+#include <linux/cpu.h>
 
 #include <asm/cacheflush.h>
 #include <asm/smp_plat.h>
+#include <asm/vfp.h>
+
+#include <mach/qdss.h>
+#include <mach/msm_rtb.h>
+
+#include "pm.h"
+#include "spm.h"
 
 extern volatile int pen_release;
 
+struct msm_hotplug_device {
+	struct completion cpu_killed;
+	unsigned int warm_boot;
+};
+
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct msm_hotplug_device,
+			msm_hotplug_devices);
+
 static inline void cpu_enter_lowpower(void)
 {
 	/* Just flush the cache. Changing the coherency is not yet
@@ -30,18 +47,15 @@
 {
 	/* Just enter wfi for now. TODO: Properly shut off the cpu. */
 	for (;;) {
-		/*
-		 * here's the WFI
-		 */
-		asm("wfi"
-		    :
-		    :
-		    : "memory", "cc");
 
+		msm_pm_cpu_enter_lowpower(cpu);
 		if (pen_release == cpu_logical_map(cpu)) {
 			/*
 			 * OK, proper wakeup, we're done
 			 */
+			pen_release = -1;
+			dmac_flush_range((void *)&pen_release,
+				(void *)(&pen_release + sizeof(pen_release)));
 			break;
 		}
 
@@ -53,6 +67,8 @@
 		 * possible, since we are currently running incoherently, and
 		 * therefore cannot safely call printk() or anything else
 		 */
+		dmac_inv_range((void *)&pen_release,
+			       (void *)(&pen_release + sizeof(pen_release)));
 		pr_debug("CPU%u: spurious wakeup call\n", cpu);
 	}
 }
@@ -69,16 +85,19 @@
  */
 void platform_cpu_die(unsigned int cpu)
 {
+	if (unlikely(cpu != smp_processor_id())) {
+		pr_crit("%s: running on %u, should be %u\n",
+			__func__, smp_processor_id(), cpu);
+		BUG();
+	}
+	complete(&__get_cpu_var(msm_hotplug_devices).cpu_killed);
 	/*
 	 * we're ready for shutdown now, so do it
 	 */
 	cpu_enter_lowpower();
 	platform_do_lowpower(cpu);
 
-	/*
-	 * bring this CPU back into the world of cache
-	 * coherency, and then restore interrupts
-	 */
+	pr_debug("CPU%u: %s: normal wakeup\n", cpu, __func__);
 	cpu_leave_lowpower();
 }
 
@@ -90,3 +109,70 @@
 	 */
 	return cpu == 0 ? -EPERM : 0;
 }
+
+#define CPU_SHIFT	0
+#define CPU_MASK	0xF
+#define CPU_OF(n)	(((n) & CPU_MASK) << CPU_SHIFT)
+#define CPUSET_SHIFT	4
+#define CPUSET_MASK	0xFFFF
+#define CPUSET_OF(n)	(((n) & CPUSET_MASK) << CPUSET_SHIFT)
+
+static int hotplug_rtb_callback(struct notifier_block *nfb,
+				unsigned long action, void *hcpu)
+{
+	/*
+	 * Bits [19:4] of the data are the online mask, lower 4 bits are the
+	 * cpu number that is being changed. Additionally, changes to the
+	 * online_mask that will be done by the current hotplug will be made
+	 * even though they aren't necessarily in the online mask yet.
+	 *
+	 * XXX: This design is limited to supporting at most 16 cpus
+	 */
+	int this_cpumask = CPUSET_OF(1 << (int)hcpu);
+	int cpumask = CPUSET_OF(cpumask_bits(cpu_online_mask)[0]);
+	int cpudata = CPU_OF((int)hcpu) | cpumask;
+
+	switch (action & (~CPU_TASKS_FROZEN)) {
+	case CPU_STARTING:
+		uncached_logk(LOGK_HOTPLUG, (void *)(cpudata | this_cpumask));
+		break;
+	case CPU_DYING:
+		uncached_logk(LOGK_HOTPLUG, (void *)(cpudata & ~this_cpumask));
+		break;
+	default:
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+static struct notifier_block hotplug_rtb_notifier = {
+	.notifier_call = hotplug_rtb_callback,
+};
+
+int msm_platform_secondary_init(unsigned int cpu)
+{
+	int ret;
+	struct msm_hotplug_device *dev = &__get_cpu_var(msm_hotplug_devices);
+
+	if (!dev->warm_boot) {
+		dev->warm_boot = 1;
+		init_completion(&dev->cpu_killed);
+		return 0;
+	}
+	msm_jtag_restore_state();
+#if defined(CONFIG_VFP) && defined (CONFIG_CPU_PM)
+	vfp_pm_resume();
+#endif
+	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
+
+	return ret;
+}
+
+static int __init init_hotplug(void)
+{
+
+	struct msm_hotplug_device *dev = &__get_cpu_var(msm_hotplug_devices);
+	init_completion(&dev->cpu_killed);
+	return register_hotcpu_notifier(&hotplug_rtb_notifier);
+}
+early_initcall(init_hotplug);
diff --git a/arch/arm/mach-msm/hsic_sysmon.c b/arch/arm/mach-msm/hsic_sysmon.c
new file mode 100644
index 0000000..2dedbac
--- /dev/null
+++ b/arch/arm/mach-msm/hsic_sysmon.c
@@ -0,0 +1,449 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/* add additional information to our printk's */
+#define pr_fmt(fmt) "%s: " fmt "\n", __func__
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/debugfs.h>
+
+#include "hsic_sysmon.h"
+#include "sysmon.h"
+
+#define DRIVER_DESC	"HSIC System monitor driver"
+
+enum hsic_sysmon_op {
+	HSIC_SYSMON_OP_READ = 0,
+	HSIC_SYSMON_OP_WRITE,
+	NUM_OPS
+};
+
+struct hsic_sysmon {
+	struct usb_device	*udev;
+	struct usb_interface	*ifc;
+	__u8			in_epaddr;
+	__u8			out_epaddr;
+	unsigned int		pipe[NUM_OPS];
+	struct kref		kref;
+	struct platform_device	pdev;
+	int			id;
+
+	/* debugging counters */
+	atomic_t		dbg_bytecnt[NUM_OPS];
+	atomic_t		dbg_pending[NUM_OPS];
+};
+static struct hsic_sysmon *hsic_sysmon_devices[NUM_HSIC_SYSMON_DEVS];
+
+static void hsic_sysmon_delete(struct kref *kref)
+{
+	struct hsic_sysmon *hs = container_of(kref, struct hsic_sysmon, kref);
+
+	usb_put_dev(hs->udev);
+	hsic_sysmon_devices[hs->id] = NULL;
+	kfree(hs);
+}
+
+/**
+ * hsic_sysmon_open() - Opens the system monitor bridge.
+ * @id: the HSIC system monitor device to open
+ *
+ * This should only be called after the platform_device "sys_mon" with id
+ * SYSMON_SS_EXT_MODEM has been added. The simplest way to do that is to
+ * register a platform_driver and its probe will be called when the HSIC
+ * device is ready.
+ */
+int hsic_sysmon_open(enum hsic_sysmon_device_id id)
+{
+	struct hsic_sysmon	*hs;
+
+	if (id >= NUM_HSIC_SYSMON_DEVS) {
+		pr_err("invalid dev id(%d)", id);
+		return -ENODEV;
+	}
+
+	hs = hsic_sysmon_devices[id];
+	if (!hs) {
+		pr_err("dev is null");
+		return -ENODEV;
+	}
+
+	kref_get(&hs->kref);
+
+	return 0;
+}
+EXPORT_SYMBOL(hsic_sysmon_open);
+
+/**
+ * hsic_sysmon_close() - Closes the system monitor bridge.
+ * @id: the HSIC system monitor device to close
+ */
+void hsic_sysmon_close(enum hsic_sysmon_device_id id)
+{
+	struct hsic_sysmon	*hs;
+
+	if (id >= NUM_HSIC_SYSMON_DEVS) {
+		pr_err("invalid dev id(%d)", id);
+		return;
+	}
+
+	hs = hsic_sysmon_devices[id];
+	kref_put(&hs->kref, hsic_sysmon_delete);
+}
+EXPORT_SYMBOL(hsic_sysmon_close);
+
+/**
+ * hsic_sysmon_readwrite() - Common function to send read/write over HSIC
+ */
+static int hsic_sysmon_readwrite(enum hsic_sysmon_device_id id, void *data,
+				 size_t len, size_t *actual_len, int timeout,
+				 enum hsic_sysmon_op op)
+{
+	struct hsic_sysmon	*hs;
+	int			ret;
+	const char		*opstr = (op == HSIC_SYSMON_OP_READ) ?
+						"read" : "write";
+
+	pr_debug("%s: id:%d, data len:%d, timeout:%d", opstr, id, len, timeout);
+
+	if (id >= NUM_HSIC_SYSMON_DEVS) {
+		pr_err("invalid dev id(%d)", id);
+		return -ENODEV;
+	}
+
+	if (!len) {
+		pr_err("length(%d) must be greater than 0", len);
+		return -EINVAL;
+	}
+
+	hs = hsic_sysmon_devices[id];
+	if (!hs) {
+		pr_err("device was not opened");
+		return -ENODEV;
+	}
+
+	if (!hs->ifc) {
+		dev_err(&hs->udev->dev, "can't %s, device disconnected\n",
+				opstr);
+		return -ENODEV;
+	}
+
+	ret = usb_autopm_get_interface(hs->ifc);
+	if (ret < 0) {
+		dev_err(&hs->udev->dev, "can't %s, autopm_get failed:%d\n",
+			opstr, ret);
+		return ret;
+	}
+
+	atomic_inc(&hs->dbg_pending[op]);
+
+	ret = usb_bulk_msg(hs->udev, hs->pipe[op], data, len, actual_len,
+				timeout);
+
+	atomic_dec(&hs->dbg_pending[op]);
+
+	if (ret)
+		dev_err(&hs->udev->dev,
+			"can't %s, usb_bulk_msg failed, err:%d\n", opstr, ret);
+	else
+		atomic_add(*actual_len, &hs->dbg_bytecnt[op]);
+
+	usb_autopm_put_interface(hs->ifc);
+	return ret;
+}
+
+/**
+ * hsic_sysmon_read() - Read data from the HSIC sysmon interface.
+ * @id: the HSIC system monitor device to open
+ * @data: pointer to caller-allocated buffer to fill in
+ * @len: length in bytes of the buffer
+ * @actual_len: pointer to a location to put the actual length read
+ *	in bytes
+ * @timeout: time in msecs to wait for the message to complete before
+ *	timing out (if 0 the wait is forever)
+ *
+ * Context: !in_interrupt ()
+ *
+ * Synchronously reads data from the HSIC interface. The call will return
+ * after the read has completed, encountered an error, or timed out. Upon
+ * successful return actual_len will reflect the number of bytes read.
+ *
+ * If successful, it returns 0, otherwise a negative error number.  The number
+ * of actual bytes transferred will be stored in the actual_len paramater.
+ */
+int hsic_sysmon_read(enum hsic_sysmon_device_id id, char *data, size_t len,
+		     size_t *actual_len, int timeout)
+{
+	return hsic_sysmon_readwrite(id, data, len, actual_len,
+					timeout, HSIC_SYSMON_OP_READ);
+}
+EXPORT_SYMBOL(hsic_sysmon_read);
+
+/**
+ * hsic_sysmon_write() - Write data to the HSIC sysmon interface.
+ * @id: the HSIC system monitor device to open
+ * @data: pointer to caller-allocated buffer to write
+ * @len: length in bytes of the data in buffer to write
+ * @actual_len: pointer to a location to put the actual length written
+ *	in bytes
+ * @timeout: time in msecs to wait for the message to complete before
+ *	timing out (if 0 the wait is forever)
+ *
+ * Context: !in_interrupt ()
+ *
+ * Synchronously writes data to the HSIC interface. The call will return
+ * after the write has completed, encountered an error, or timed out. Upon
+ * successful return actual_len will reflect the number of bytes written.
+ *
+ * If successful, it returns 0, otherwise a negative error number.  The number
+ * of actual bytes transferred will be stored in the actual_len paramater.
+ */
+int hsic_sysmon_write(enum hsic_sysmon_device_id id, const char *data,
+		      size_t len, int timeout)
+{
+	size_t actual_len;
+	return hsic_sysmon_readwrite(id, (void *)data, len, &actual_len,
+					timeout, HSIC_SYSMON_OP_WRITE);
+}
+EXPORT_SYMBOL(hsic_sysmon_write);
+
+#if defined(CONFIG_DEBUG_FS)
+#define DEBUG_BUF_SIZE	512
+static ssize_t sysmon_debug_read_stats(struct file *file, char __user *ubuf,
+					size_t count, loff_t *ppos)
+{
+	char	*buf;
+	int	i, ret = 0;
+
+	buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	for (i = 0; i < NUM_HSIC_SYSMON_DEVS; i++) {
+		struct hsic_sysmon *hs = hsic_sysmon_devices[i];
+		if (!hs)
+			continue;
+
+		ret += scnprintf(buf, DEBUG_BUF_SIZE,
+				"---HSIC Sysmon #%d---\n"
+				"epin:%d, epout:%d\n"
+				"bytes to host: %d\n"
+				"bytes to mdm: %d\n"
+				"pending reads: %d\n"
+				"pending writes: %d\n",
+				i, hs->in_epaddr & ~0x80, hs->out_epaddr,
+				atomic_read(
+				    &hs->dbg_bytecnt[HSIC_SYSMON_OP_READ]),
+				atomic_read(
+				    &hs->dbg_bytecnt[HSIC_SYSMON_OP_WRITE]),
+				atomic_read(
+				    &hs->dbg_pending[HSIC_SYSMON_OP_READ]),
+				atomic_read(
+				    &hs->dbg_pending[HSIC_SYSMON_OP_WRITE])
+				);
+	}
+
+	ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t sysmon_debug_reset_stats(struct file *file,
+					const char __user *buf,
+					size_t count, loff_t *ppos)
+{
+	int	i;
+
+	for (i = 0; i < NUM_HSIC_SYSMON_DEVS; i++) {
+		struct hsic_sysmon *hs = hsic_sysmon_devices[i];
+		if (hs) {
+			atomic_set(&hs->dbg_bytecnt[HSIC_SYSMON_OP_READ], 0);
+			atomic_set(&hs->dbg_bytecnt[HSIC_SYSMON_OP_WRITE], 0);
+			atomic_set(&hs->dbg_pending[HSIC_SYSMON_OP_READ], 0);
+			atomic_set(&hs->dbg_pending[HSIC_SYSMON_OP_WRITE], 0);
+		}
+	}
+
+	return count;
+}
+
+const struct file_operations sysmon_stats_ops = {
+	.read = sysmon_debug_read_stats,
+	.write = sysmon_debug_reset_stats,
+};
+
+static struct dentry *dent;
+
+static void hsic_sysmon_debugfs_init(void)
+{
+	struct dentry *dfile;
+
+	dent = debugfs_create_dir("hsic_sysmon", 0);
+	if (IS_ERR(dent))
+		return;
+
+	dfile = debugfs_create_file("status", 0444, dent, 0, &sysmon_stats_ops);
+	if (!dfile || IS_ERR(dfile))
+		debugfs_remove(dent);
+}
+
+static void hsic_sysmon_debugfs_cleanup(void)
+{
+	if (dent) {
+		debugfs_remove_recursive(dent);
+		dent = NULL;
+	}
+}
+#else
+static inline void hsic_sysmon_debugfs_init(void) { }
+static inline void hsic_sysmon_debugfs_cleanup(void) { }
+#endif
+
+static int
+hsic_sysmon_probe(struct usb_interface *ifc, const struct usb_device_id *id)
+{
+	struct hsic_sysmon		*hs;
+	struct usb_host_interface	*ifc_desc;
+	struct usb_endpoint_descriptor	*ep_desc;
+	int				i;
+	int				ret = -ENOMEM;
+	__u8				ifc_num;
+
+	pr_debug("id:%lu", id->driver_info);
+
+	ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
+
+	/* is this the interface we're looking for? */
+	if (ifc_num != id->driver_info)
+		return -ENODEV;
+
+	hs = kzalloc(sizeof(*hs), GFP_KERNEL);
+	if (!hs) {
+		pr_err("unable to allocate hsic_sysmon");
+		return -ENOMEM;
+	}
+
+	hs->udev = usb_get_dev(interface_to_usbdev(ifc));
+	hs->ifc = ifc;
+	kref_init(&hs->kref);
+
+	ifc_desc = ifc->cur_altsetting;
+	for (i = 0; i < ifc_desc->desc.bNumEndpoints; i++) {
+		ep_desc = &ifc_desc->endpoint[i].desc;
+
+		if (!hs->in_epaddr && usb_endpoint_is_bulk_in(ep_desc)) {
+			hs->in_epaddr = ep_desc->bEndpointAddress;
+			hs->pipe[HSIC_SYSMON_OP_READ] =
+				usb_rcvbulkpipe(hs->udev, hs->in_epaddr);
+		}
+
+		if (!hs->out_epaddr && usb_endpoint_is_bulk_out(ep_desc)) {
+			hs->out_epaddr = ep_desc->bEndpointAddress;
+			hs->pipe[HSIC_SYSMON_OP_WRITE] =
+				usb_sndbulkpipe(hs->udev, hs->out_epaddr);
+		}
+	}
+
+	if (!(hs->in_epaddr && hs->out_epaddr)) {
+		pr_err("could not find bulk in and bulk out endpoints");
+		ret = -ENODEV;
+		goto error;
+	}
+
+	hs->id = HSIC_SYSMON_DEV_EXT_MODEM;
+	hsic_sysmon_devices[HSIC_SYSMON_DEV_EXT_MODEM] = hs;
+	usb_set_intfdata(ifc, hs);
+
+	hs->pdev.name = "sys_mon";
+	hs->pdev.id = SYSMON_SS_EXT_MODEM;
+	platform_device_register(&hs->pdev);
+
+	pr_debug("complete");
+
+	return 0;
+
+error:
+	if (hs)
+		kref_put(&hs->kref, hsic_sysmon_delete);
+
+	return ret;
+}
+
+static void hsic_sysmon_disconnect(struct usb_interface *ifc)
+{
+	struct hsic_sysmon	*hs = usb_get_intfdata(ifc);
+
+	platform_device_unregister(&hs->pdev);
+	kref_put(&hs->kref, hsic_sysmon_delete);
+	usb_set_intfdata(ifc, NULL);
+}
+
+static int hsic_sysmon_suspend(struct usb_interface *ifc, pm_message_t message)
+{
+	return 0;
+}
+
+static int hsic_sysmon_resume(struct usb_interface *ifc)
+{
+	return 0;
+}
+
+/* driver_info maps to the interface number corresponding to sysmon */
+static const struct usb_device_id hsic_sysmon_ids[] = {
+	{ USB_DEVICE(0x5c6, 0x9048), .driver_info = 1, },
+	{ USB_DEVICE(0x5c6, 0x904C), .driver_info = 1, },
+	{} /* terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, hsic_sysmon_ids);
+
+static struct usb_driver hsic_sysmon_driver = {
+	.name =		"hsic_sysmon",
+	.probe =	hsic_sysmon_probe,
+	.disconnect =	hsic_sysmon_disconnect,
+	.suspend =	hsic_sysmon_suspend,
+	.resume =	hsic_sysmon_resume,
+	.id_table =	hsic_sysmon_ids,
+	.supports_autosuspend = 1,
+};
+
+static int __init hsic_sysmon_init(void)
+{
+	int ret;
+
+	ret = usb_register(&hsic_sysmon_driver);
+	if (ret) {
+		pr_err("unable to register " DRIVER_DESC);
+		return ret;
+	}
+
+	hsic_sysmon_debugfs_init();
+	return 0;
+}
+
+static void __exit hsic_sysmon_exit(void)
+{
+	hsic_sysmon_debugfs_cleanup();
+	usb_deregister(&hsic_sysmon_driver);
+}
+
+module_init(hsic_sysmon_init);
+module_exit(hsic_sysmon_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/hsic_sysmon.h b/arch/arm/mach-msm/hsic_sysmon.h
new file mode 100644
index 0000000..aa57b93
--- /dev/null
+++ b/arch/arm/mach-msm/hsic_sysmon.h
@@ -0,0 +1,56 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __HSIC_SYSMON_H__
+#define __HSIC_SYSMON_H__
+
+/**
+ * enum hsic_sysmon_device_id - Supported HSIC subsystem devices
+ */
+enum hsic_sysmon_device_id {
+	HSIC_SYSMON_DEV_EXT_MODEM,
+	NUM_HSIC_SYSMON_DEVS
+};
+
+#if defined(CONFIG_MSM_HSIC_SYSMON) || defined(CONFIG_MSM_HSIC_SYSMON_MODULE)
+
+extern int hsic_sysmon_open(enum hsic_sysmon_device_id id);
+extern void hsic_sysmon_close(enum hsic_sysmon_device_id id);
+extern int hsic_sysmon_read(enum hsic_sysmon_device_id id, char *data,
+			    size_t len, size_t *actual_len, int timeout);
+extern int hsic_sysmon_write(enum hsic_sysmon_device_id id, const char *data,
+			     size_t len, int timeout);
+
+#else /* CONFIG_MSM_HSIC_SYSMON || CONFIG_MSM_HSIC_SYSMON_MODULE */
+
+static inline int hsic_sysmon_open(enum hsic_sysmon_device_id id)
+{
+	return -ENODEV;
+}
+
+static inline void hsic_sysmon_close(enum hsic_sysmon_device_id id) { }
+
+static inline int hsic_sysmon_read(enum hsic_sysmon_device_id id, char *data,
+				   size_t len, size_t *actual_len, int timeout)
+{
+	return -ENODEV;
+}
+
+static inline int hsic_sysmon_write(enum hsic_sysmon_device_id id,
+				    const char *data, size_t len, int timeout)
+{
+	return -ENODEV;
+}
+
+#endif /* CONFIG_MSM_HSIC_SYSMON || CONFIG_MSM_HSIC_SYSMON_MODULE */
+
+#endif /* __HSIC_SYSMON_H__ */
diff --git a/arch/arm/mach-msm/hsic_sysmon_test.c b/arch/arm/mach-msm/hsic_sysmon_test.c
new file mode 100644
index 0000000..9929cb7
--- /dev/null
+++ b/arch/arm/mach-msm/hsic_sysmon_test.c
@@ -0,0 +1,118 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/* add additional information to our printk's */
+#define pr_fmt(fmt) "%s: " fmt "\n", __func__
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+#include "hsic_sysmon.h"
+#include "sysmon.h"
+
+#define DRIVER_DESC	"HSIC System monitor driver test"
+
+#define RD_BUF_SIZE	4096
+
+struct sysmon_test_dev {
+	int			buflen;
+	char			buf[RD_BUF_SIZE];
+};
+static struct sysmon_test_dev *sysmon_dev;
+
+static ssize_t sysmon_test_read(struct file *file, char __user *ubuf,
+				 size_t count, loff_t *ppos)
+{
+	struct sysmon_test_dev *dev = sysmon_dev;
+	int ret;
+
+	if (!dev)
+		return -ENODEV;
+
+	ret = hsic_sysmon_read(HSIC_SYSMON_DEV_EXT_MODEM, dev->buf, RD_BUF_SIZE,
+				&dev->buflen, 3000);
+	if (!ret)
+		return simple_read_from_buffer(ubuf, count, ppos,
+					dev->buf, dev->buflen);
+
+	return 0;
+}
+
+static ssize_t sysmon_test_write(struct file *file, const char __user *ubuf,
+				 size_t count, loff_t *ppos)
+{
+	struct sysmon_test_dev	*dev = sysmon_dev;
+	int ret;
+
+	if (!dev)
+		return -ENODEV;
+
+	if (copy_from_user(dev->buf, ubuf, count)) {
+		pr_err("error copying for writing");
+		return 0;
+	}
+
+	ret = hsic_sysmon_write(HSIC_SYSMON_DEV_EXT_MODEM,
+				dev->buf, count, 1000);
+	if (ret < 0) {
+		pr_err("error writing to hsic_sysmon");
+		return ret;
+	}
+
+	return count;
+}
+
+static int sysmon_test_open(struct inode *inode, struct file *file)
+{
+	return hsic_sysmon_open(HSIC_SYSMON_DEV_EXT_MODEM);
+}
+
+static int sysmon_test_release(struct inode *inode, struct file *file)
+{
+	hsic_sysmon_close(HSIC_SYSMON_DEV_EXT_MODEM);
+	return 0;
+}
+
+static struct dentry *dfile;
+const struct file_operations sysmon_test_ops = {
+	.read = sysmon_test_read,
+	.write = sysmon_test_write,
+	.open = sysmon_test_open,
+	.release = sysmon_test_release
+};
+
+static int __init sysmon_test_init(void)
+{
+	sysmon_dev = kzalloc(sizeof(*sysmon_dev), GFP_KERNEL);
+	if (!sysmon_dev)
+		return -ENOMEM;
+
+	dfile = debugfs_create_file("hsic_sysmon_test", 0666, NULL,
+			0, &sysmon_test_ops);
+	return 0;
+}
+
+static void __exit sysmon_test_exit(void)
+{
+	if (dfile)
+		debugfs_remove(dfile);
+	kfree(sysmon_dev);
+}
+
+module_init(sysmon_test_init);
+module_exit(sysmon_test_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/htc_35mm_jack.c b/arch/arm/mach-msm/htc_35mm_jack.c
new file mode 100644
index 0000000..3f95ff2
--- /dev/null
+++ b/arch/arm/mach-msm/htc_35mm_jack.c
@@ -0,0 +1,397 @@
+/* arch/arm/mach-msm/htc_35mm_jack.c
+ *
+ * Copyright (C) 2009 HTC, Inc.
+ * Author: Arec Kao <Arec_Kao@htc.com>
+ * Copyright (C) 2009 Google, Inc.
+ * Author: Eric Olsen <eolsen@android.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/sysdev.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/hrtimer.h>
+#include <linux/debugfs.h>
+#include <linux/jiffies.h>
+#include <linux/switch.h>
+#include <linux/input.h>
+#include <linux/wakelock.h>
+#include <asm/gpio.h>
+#include <asm/atomic.h>
+#include <mach/board.h>
+#include <mach/vreg.h>
+#include <asm/mach-types.h>
+#include <mach/htc_acoustic_qsd.h>
+#include <mach/htc_35mm_jack.h>
+#include <mach/htc_headset.h>
+
+#ifdef CONFIG_HTC_AUDIOJACK
+#include <mach/audio_jack.h>
+#endif
+
+/* #define CONFIG_DEBUG_H2W */
+
+#define H2WI(fmt, arg...) \
+	printk(KERN_INFO "[H2W] %s " fmt "\r\n", __func__, ## arg)
+#define H2WE(fmt, arg...) \
+	printk(KERN_ERR "[H2W] %s " fmt "\r\n", __func__, ## arg)
+
+#ifdef CONFIG_DEBUG_H2W
+#define H2W_DBG(fmt, arg...) \
+	printk(KERN_INFO "[H2W] %s " fmt "\r\n", __func__, ## arg)
+#else
+#define H2W_DBG(fmt, arg...) do {} while (0)
+#endif
+
+void detect_h2w_do_work(struct work_struct *w);
+
+static struct workqueue_struct *detect_wq;
+static struct workqueue_struct *button_wq;
+
+static DECLARE_DELAYED_WORK(detect_h2w_work, detect_h2w_do_work);
+
+static void insert_35mm_do_work(struct work_struct *work);
+static DECLARE_WORK(insert_35mm_work, insert_35mm_do_work);
+static void remove_35mm_do_work(struct work_struct *work);
+static DECLARE_WORK(remove_35mm_work, remove_35mm_do_work);
+static void button_35mm_do_work(struct work_struct *work);
+static DECLARE_WORK(button_35mm_work, button_35mm_do_work);
+
+struct h35_info {
+	struct mutex mutex_lock;
+	struct switch_dev hs_change;
+	unsigned long insert_jiffies;
+	int ext_35mm_status;
+	int is_ext_insert;
+	int key_code;
+	int mic_bias_state;
+	int *is_hpin_stable;
+	struct input_dev *input;
+
+	struct wake_lock headset_wake_lock;
+};
+
+static struct h35mm_platform_data *pd;
+static struct h35_info *hi;
+
+static ssize_t h35mm_print_name(struct switch_dev *sdev, char *buf)
+{
+	return sprintf(buf, "Headset\n");
+}
+
+static void button_35mm_do_work(struct work_struct *work)
+{
+	int key = 0;
+	int pressed = 0;
+
+	if (!hi->is_ext_insert) {
+		/* no headset ignor key event */
+		H2WI("3.5mm headset is plugged out, skip report key event");
+		return;
+	}
+
+	switch (hi->key_code) {
+	case 0x1: /* Play/Pause */
+		H2WI("3.5mm RC: Play Pressed");
+		key = KEY_MEDIA;
+		pressed = 1;
+		break;
+	case 0x2:
+		H2WI("3.5mm RC: BACKWARD Pressed");
+		key = KEY_PREVIOUSSONG;
+		pressed = 1;
+		break;
+	case 0x3:
+		H2WI("3.5mm RC: FORWARD Pressed");
+		key = KEY_NEXTSONG;
+		pressed = 1;
+		break;
+	case 0x81: /* Play/Pause */
+		H2WI("3.5mm RC: Play Released");
+		key = KEY_MEDIA;
+		pressed = 0;
+		break;
+	case 0x82:
+		H2WI("3.5mm RC: BACKWARD Released");
+		key = KEY_PREVIOUSSONG;
+		pressed = 0;
+		break;
+	case 0x83:
+		H2WI("3.5mm RC: FORWARD Released");
+		key = KEY_NEXTSONG;
+		pressed = 0;
+		break;
+	default:
+		H2WI("3.5mm RC: Unknown Button (0x%x) Pressed", hi->key_code);
+		return;
+	}
+	input_report_key(hi->input, key, pressed);
+	input_sync(hi->input);
+
+	wake_lock_timeout(&hi->headset_wake_lock, 1.5*HZ);
+}
+
+static void remove_35mm_do_work(struct work_struct *work)
+{
+	wake_lock_timeout(&hi->headset_wake_lock, 2.5*HZ);
+
+	H2W_DBG("");
+	/*To solve the insert, remove, insert headset problem*/
+	if (time_before_eq(jiffies, hi->insert_jiffies))
+		msleep(800);
+
+	if (hi->is_ext_insert) {
+		H2WI("Skip 3.5mm headset plug out!!!");
+		if (hi->is_hpin_stable)
+			*(hi->is_hpin_stable) = 1;
+		return;
+	}
+
+	pr_info("3.5mm_headset plug out\n");
+
+	if (pd->key_event_disable != NULL)
+		pd->key_event_disable();
+
+	if (hi->mic_bias_state) {
+		turn_mic_bias_on(0);
+		hi->mic_bias_state = 0;
+	}
+	hi->ext_35mm_status = 0;
+	if (hi->is_hpin_stable)
+		*(hi->is_hpin_stable) = 0;
+
+	/* Notify framework via switch class */
+	mutex_lock(&hi->mutex_lock);
+	switch_set_state(&hi->hs_change, hi->ext_35mm_status);
+	mutex_unlock(&hi->mutex_lock);
+}
+
+static void insert_35mm_do_work(struct work_struct *work)
+{
+	H2W_DBG("");
+	hi->insert_jiffies = jiffies + 1*HZ;
+
+	wake_lock_timeout(&hi->headset_wake_lock, 1.5*HZ);
+
+	if (hi->is_ext_insert) {
+		pr_info("3.5mm_headset plug in\n");
+
+	if (pd->key_event_enable != NULL)
+		pd->key_event_enable();
+
+		/* Turn On Mic Bias */
+		if (!hi->mic_bias_state) {
+			turn_mic_bias_on(1);
+			hi->mic_bias_state = 1;
+			/* Wait for pin stable */
+			msleep(300);
+		}
+
+		/* Detect headset with or without microphone */
+		if(pd->headset_has_mic) {
+			if (pd->headset_has_mic() == 0) {
+				/* without microphone */
+				pr_info("3.5mm without microphone\n");
+				hi->ext_35mm_status = BIT_HEADSET_NO_MIC;
+			} else { /* with microphone */
+				pr_info("3.5mm with microphone\n");
+				hi->ext_35mm_status = BIT_HEADSET;
+			}
+		} else {
+			/* Assume no mic */
+			pr_info("3.5mm without microphone\n");
+			hi->ext_35mm_status = BIT_HEADSET_NO_MIC;
+		}
+		hi->ext_35mm_status |= BIT_35MM_HEADSET;
+
+		/* Notify framework via switch class */
+		mutex_lock(&hi->mutex_lock);
+		switch_set_state(&hi->hs_change, hi->ext_35mm_status);
+		mutex_unlock(&hi->mutex_lock);
+
+		if (hi->is_hpin_stable)
+			*(hi->is_hpin_stable) = 1;
+	}
+}
+
+int htc_35mm_key_event(int keycode, int *hpin_stable)
+{
+	hi->key_code = keycode;
+	hi->is_hpin_stable = hpin_stable;
+
+	if ((hi->ext_35mm_status & BIT_HEADSET) == 0) {
+		*(hi->is_hpin_stable) = 0;
+
+		pr_info("Key press with no mic.  Retrying detection\n");
+		queue_work(detect_wq, &insert_35mm_work);
+	} else
+		queue_work(button_wq, &button_35mm_work);
+
+	return 0;
+}
+
+int htc_35mm_jack_plug_event(int insert, int *hpin_stable)
+{
+	if (!hi) {
+		pr_err("Plug event before driver init\n");
+		return -1;
+	}
+
+	mutex_lock(&hi->mutex_lock);
+	hi->is_ext_insert = insert;
+	hi->is_hpin_stable = hpin_stable;
+	mutex_unlock(&hi->mutex_lock);
+
+	H2WI(" %d", hi->is_ext_insert);
+	if (!hi->is_ext_insert)
+		queue_work(detect_wq, &remove_35mm_work);
+	else
+		queue_work(detect_wq, &insert_35mm_work);
+	return 1;
+}
+
+static int htc_35mm_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	pd = pdev->dev.platform_data;
+
+	pr_info("H2W: htc_35mm_jack driver register\n");
+
+	hi = kzalloc(sizeof(struct h35_info), GFP_KERNEL);
+	if (!hi)
+		return -ENOMEM;
+
+	hi->ext_35mm_status = 0;
+	hi->is_ext_insert = 0;
+	hi->mic_bias_state = 0;
+
+	mutex_init(&hi->mutex_lock);
+
+	wake_lock_init(&hi->headset_wake_lock, WAKE_LOCK_SUSPEND, "headset");
+
+	hi->hs_change.name = "h2w";
+	hi->hs_change.print_name = h35mm_print_name;
+	ret = switch_dev_register(&hi->hs_change);
+	if (ret < 0)
+		goto err_switch_dev_register;
+
+	detect_wq = create_workqueue("detection");
+	if (detect_wq  == NULL) {
+		ret = -ENOMEM;
+		goto err_create_detect_work_queue;
+	}
+
+	button_wq = create_workqueue("button");
+	if (button_wq  == NULL) {
+			ret = -ENOMEM;
+			goto err_create_button_work_queue;
+	}
+
+	hi->input = input_allocate_device();
+	if (!hi->input) {
+		ret = -ENOMEM;
+		goto err_request_input_dev;
+	}
+
+	hi->input->name = "h2w headset";
+	set_bit(EV_SYN, hi->input->evbit);
+	set_bit(EV_KEY, hi->input->evbit);
+	set_bit(KEY_MEDIA, hi->input->keybit);
+	set_bit(KEY_NEXTSONG, hi->input->keybit);
+	set_bit(KEY_PLAYPAUSE, hi->input->keybit);
+	set_bit(KEY_PREVIOUSSONG, hi->input->keybit);
+	set_bit(KEY_MUTE, hi->input->keybit);
+	set_bit(KEY_VOLUMEUP, hi->input->keybit);
+	set_bit(KEY_VOLUMEDOWN, hi->input->keybit);
+	set_bit(KEY_END, hi->input->keybit);
+	set_bit(KEY_SEND, hi->input->keybit);
+
+	ret = input_register_device(hi->input);
+	if (ret < 0)
+	goto err_register_input_dev;
+
+	/* Enable plug events*/
+	if (pd->plug_event_enable == NULL) {
+		ret = -ENOMEM;
+		goto err_enable_plug_event;
+	}
+	if (pd->plug_event_enable() != 1)  {
+		ret = -ENOMEM;
+		goto err_enable_plug_event;
+	}
+
+	return 0;
+
+err_enable_plug_event:
+err_register_input_dev:
+	input_free_device(hi->input);
+err_request_input_dev:
+	destroy_workqueue(button_wq);
+err_create_button_work_queue:
+	destroy_workqueue(detect_wq);
+err_create_detect_work_queue:
+	switch_dev_unregister(&hi->hs_change);
+err_switch_dev_register:
+	kzfree(hi);
+	pr_err("H2W: Failed to register driver\n");
+
+	return ret;
+}
+
+static int htc_35mm_remove(struct platform_device *pdev)
+{
+	H2W_DBG("");
+	switch_dev_unregister(&hi->hs_change);
+	kzfree(hi);
+
+#if 0 /* Add keys later */
+	input_unregister_device(hi->input);
+#endif
+	return 0;
+}
+
+static struct platform_driver htc_35mm_driver = {
+	.probe		= htc_35mm_probe,
+	.remove		= htc_35mm_remove,
+	.driver		= {
+		.name		= "htc_headset",
+		.owner		= THIS_MODULE,
+	},
+};
+
+static int __init htc_35mm_init(void)
+{
+	H2W_DBG("");
+	return platform_driver_register(&htc_35mm_driver);
+}
+
+static void __exit htc_35mm_exit(void)
+{
+	platform_driver_unregister(&htc_35mm_driver);
+}
+
+module_init(htc_35mm_init);
+module_exit(htc_35mm_exit);
+
+MODULE_AUTHOR("Eric Olsen <eolsen@android.com>");
+MODULE_DESCRIPTION("HTC 3.5MM Driver");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/htc_acoustic.c b/arch/arm/mach-msm/htc_acoustic.c
new file mode 100644
index 0000000..3de71dd
--- /dev/null
+++ b/arch/arm/mach-msm/htc_acoustic.c
@@ -0,0 +1,239 @@
+/* arch/arm/mach-msm/htc_acoustic.c
+ *
+ * Copyright (C) 2007-2008 HTC Corporation
+ * Author: Laurence Chen <Laurence_Chen@htc.com>
+ *
+ * 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.
+ *
+ */
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+
+#include <mach/msm_smd.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/msm_iomap.h>
+
+#include "smd_private.h"
+
+#define ACOUSTIC_IOCTL_MAGIC 'p'
+#define ACOUSTIC_ARM11_DONE	_IOW(ACOUSTIC_IOCTL_MAGIC, 22, unsigned int)
+
+#define HTCRPOG 0x30100002
+#define HTCVERS 0
+#define ONCRPC_SET_MIC_BIAS_PROC       (1)
+#define ONCRPC_ACOUSTIC_INIT_PROC      (5)
+#define ONCRPC_ALLOC_ACOUSTIC_MEM_PROC (6)
+
+#define HTC_ACOUSTIC_TABLE_SIZE        (0x10000)
+
+#define D(fmt, args...) printk(KERN_INFO "htc-acoustic: "fmt, ##args)
+#define E(fmt, args...) printk(KERN_ERR "htc-acoustic: "fmt, ##args)
+
+struct set_smem_req {
+	struct rpc_request_hdr hdr;
+	uint32_t size;
+};
+
+struct set_smem_rep {
+	struct rpc_reply_hdr hdr;
+	int n;
+};
+
+struct set_acoustic_req {
+	struct rpc_request_hdr hdr;
+};
+
+struct set_acoustic_rep {
+	struct rpc_reply_hdr hdr;
+	int n;
+};
+
+static uint32_t htc_acoustic_vir_addr;
+static struct msm_rpc_endpoint *endpoint;
+static struct mutex api_lock;
+
+static int acoustic_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	unsigned long pgoff, delta;
+	int rc = -EINVAL;
+	size_t size;
+
+	D("mmap\n");
+
+	mutex_lock(&api_lock);
+
+	size = vma->vm_end - vma->vm_start;
+
+	if (vma->vm_pgoff != 0) {
+		E("mmap failed: page offset %lx\n", vma->vm_pgoff);
+		goto done;
+	}
+
+	if (!htc_acoustic_vir_addr) {
+		E("mmap failed: smem region not allocated\n");
+		rc = -EIO;
+		goto done;
+	}
+
+	pgoff = MSM_SHARED_RAM_PHYS +
+		(htc_acoustic_vir_addr - (uint32_t)MSM_SHARED_RAM_BASE);
+	delta = PAGE_ALIGN(pgoff) - pgoff;
+
+	if (size + delta > HTC_ACOUSTIC_TABLE_SIZE) {
+		E("mmap failed: size %d\n", size);
+		goto done;
+	}
+
+	pgoff += delta;
+	vma->vm_flags |= VM_IO | VM_RESERVED;
+
+	rc = io_remap_pfn_range(vma, vma->vm_start, pgoff >> PAGE_SHIFT,
+		      size, vma->vm_page_prot);
+
+	if (rc < 0)
+		E("mmap failed: remap error %d\n", rc);
+
+done:	mutex_unlock(&api_lock);
+	return rc;
+}
+
+static int acoustic_open(struct inode *inode, struct file *file)
+{
+	int rc = -EIO;
+	struct set_smem_req req_smem;
+	struct set_smem_rep rep_smem;
+
+	D("open\n");
+
+	mutex_lock(&api_lock);
+
+	if (!htc_acoustic_vir_addr) {
+		if (endpoint == NULL) {
+			endpoint = msm_rpc_connect(HTCRPOG, HTCVERS, 0);
+			if (IS_ERR(endpoint)) {
+				E("init rpc failed! rc = %ld\n",
+					PTR_ERR(endpoint));
+				endpoint = NULL;
+				goto done;
+			}
+		}
+
+		req_smem.size = cpu_to_be32(HTC_ACOUSTIC_TABLE_SIZE);
+		rc = msm_rpc_call_reply(endpoint,
+					ONCRPC_ALLOC_ACOUSTIC_MEM_PROC,
+					&req_smem, sizeof(req_smem),
+					&rep_smem, sizeof(rep_smem),
+					5 * HZ);
+
+		if (rep_smem.n != 0 || rc < 0) {
+			E("open failed: ALLOC_ACOUSTIC_MEM_PROC error %d.\n",
+				rc);
+			goto done;
+		}
+		htc_acoustic_vir_addr =
+			(uint32_t)smem_alloc(SMEM_ID_VENDOR1,
+					HTC_ACOUSTIC_TABLE_SIZE);
+		if (!htc_acoustic_vir_addr) {
+			E("open failed: smem_alloc error\n");
+			goto done;
+		}
+	}
+
+	rc = 0;
+done:
+	mutex_unlock(&api_lock);
+	return rc;
+}
+
+static int acoustic_release(struct inode *inode, struct file *file)
+{
+	D("release\n");
+	return 0;
+}
+
+static long acoustic_ioctl(struct file *file, unsigned int cmd,
+			   unsigned long arg)
+{
+	int rc, reply_value;
+	struct set_acoustic_req req;
+	struct set_acoustic_rep rep;
+
+	D("ioctl\n");
+
+	mutex_lock(&api_lock);
+
+	switch (cmd) {
+	case ACOUSTIC_ARM11_DONE:
+		D("ioctl: ACOUSTIC_ARM11_DONE called %d.\n", current->pid);
+		rc = msm_rpc_call_reply(endpoint,
+					ONCRPC_ACOUSTIC_INIT_PROC, &req,
+					sizeof(req), &rep, sizeof(rep),
+					5 * HZ);
+
+		reply_value = be32_to_cpu(rep.n);
+		if (reply_value != 0 || rc < 0) {
+			E("ioctl failed: ONCRPC_ACOUSTIC_INIT_PROC "\
+				"error %d.\n", rc);
+			if (rc >= 0)
+				rc = -EIO;
+			break;
+		}
+		D("ioctl: ONCRPC_ACOUSTIC_INIT_PROC success.\n");
+		break;
+	default:
+		E("ioctl: invalid command\n");
+		rc = -EINVAL;
+	}
+
+	mutex_unlock(&api_lock);
+	return 0;
+}
+
+
+static struct file_operations acoustic_fops = {
+	.owner = THIS_MODULE,
+	.open = acoustic_open,
+	.release = acoustic_release,
+	.mmap = acoustic_mmap,
+	.unlocked_ioctl = acoustic_ioctl,
+};
+
+static struct miscdevice acoustic_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "htc-acoustic",
+	.fops = &acoustic_fops,
+};
+
+static int __init acoustic_init(void)
+{
+	mutex_init(&api_lock);
+	return misc_register(&acoustic_misc);
+}
+
+static void __exit acoustic_exit(void)
+{
+	misc_deregister(&acoustic_misc);
+}
+
+module_init(acoustic_init);
+module_exit(acoustic_exit);
+
+MODULE_AUTHOR("Laurence Chen <Laurence_Chen@htc.com>");
+MODULE_DESCRIPTION("HTC acoustic driver");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/htc_acoustic_qsd.c b/arch/arm/mach-msm/htc_acoustic_qsd.c
new file mode 100644
index 0000000..ce3c3a0
--- /dev/null
+++ b/arch/arm/mach-msm/htc_acoustic_qsd.c
@@ -0,0 +1,315 @@
+/* arch/arm/mach-msm/htc_acoustic_qsd.c
+ *
+ * Copyright (C) 2009 HTC Corporation
+ *
+ * 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.
+ *
+ */
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+#include <linux/gpio.h>
+
+#include <mach/msm_smd.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/msm_iomap.h>
+#include <mach/htc_acoustic_qsd.h>
+#include <mach/msm_qdsp6_audio.h>
+
+#include "smd_private.h"
+
+#define ACOUSTIC_IOCTL_MAGIC 'p'
+#define ACOUSTIC_UPDATE_ADIE \
+	_IOW(ACOUSTIC_IOCTL_MAGIC, 24, unsigned int)
+
+#define HTCACOUSTICPROG 0x30100003
+#define HTCACOUSTICVERS 0
+#define ONCRPC_ALLOC_ACOUSTIC_MEM_PROC		(1)
+#define ONCRPC_UPDATE_ADIE_PROC			(2)
+#define ONCRPC_ENABLE_AUX_PGA_LOOPBACK_PROC	(3)
+#define ONCRPC_FORCE_HEADSET_SPEAKER_PROC	(4)
+
+#define HTC_ACOUSTIC_TABLE_SIZE        (0x20000)
+
+#define D(fmt, args...) printk(KERN_INFO "htc-acoustic: "fmt, ##args)
+#define E(fmt, args...) printk(KERN_ERR "htc-acoustic: "fmt, ##args)
+
+static uint32_t htc_acoustic_vir_addr;
+static struct msm_rpc_endpoint *endpoint;
+static struct mutex api_lock;
+static struct mutex rpc_connect_lock;
+static struct qsd_acoustic_ops *the_ops;
+
+void acoustic_register_ops(struct qsd_acoustic_ops *ops)
+{
+	the_ops = ops;
+}
+
+static int is_rpc_connect(void)
+{
+	mutex_lock(&rpc_connect_lock);
+	if (endpoint == NULL) {
+		endpoint = msm_rpc_connect(HTCACOUSTICPROG,
+				HTCACOUSTICVERS, 0);
+		if (IS_ERR(endpoint)) {
+			pr_err("%s: init rpc failed! rc = %ld\n",
+				__func__, PTR_ERR(endpoint));
+			mutex_unlock(&rpc_connect_lock);
+			return -1;
+		}
+	}
+	mutex_unlock(&rpc_connect_lock);
+	return 0;
+}
+
+int turn_mic_bias_on(int on)
+{
+	D("%s called %d\n", __func__, on);
+	if (the_ops->enable_mic_bias)
+		the_ops->enable_mic_bias(on);
+
+	return 0;
+}
+EXPORT_SYMBOL(turn_mic_bias_on);
+
+int force_headset_speaker_on(int enable)
+{
+	struct speaker_headset_req {
+		struct rpc_request_hdr hdr;
+		uint32_t enable;
+	} spkr_req;
+
+	D("%s called %d\n", __func__, enable);
+
+	if (is_rpc_connect() == -1)
+		return -1;
+
+	spkr_req.enable = cpu_to_be32(enable);
+	return  msm_rpc_call(endpoint,
+		ONCRPC_FORCE_HEADSET_SPEAKER_PROC,
+		&spkr_req, sizeof(spkr_req), 5 * HZ);
+}
+EXPORT_SYMBOL(force_headset_speaker_on);
+
+int enable_aux_loopback(uint32_t enable)
+{
+	struct aux_loopback_req {
+		struct rpc_request_hdr hdr;
+		uint32_t enable;
+	} aux_req;
+
+	D("%s called %d\n", __func__, enable);
+
+	if (is_rpc_connect() == -1)
+		return -1;
+
+	aux_req.enable = cpu_to_be32(enable);
+	return  msm_rpc_call(endpoint,
+		ONCRPC_ENABLE_AUX_PGA_LOOPBACK_PROC,
+		&aux_req, sizeof(aux_req), 5 * HZ);
+}
+EXPORT_SYMBOL(enable_aux_loopback);
+
+static int acoustic_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	unsigned long pgoff;
+	int rc = -EINVAL;
+	size_t size;
+
+	D("mmap\n");
+
+	mutex_lock(&api_lock);
+
+	size = vma->vm_end - vma->vm_start;
+
+	if (vma->vm_pgoff != 0) {
+		E("mmap failed: page offset %lx\n", vma->vm_pgoff);
+		goto done;
+	}
+
+	if (!htc_acoustic_vir_addr) {
+		E("mmap failed: smem region not allocated\n");
+		rc = -EIO;
+		goto done;
+	}
+
+	pgoff = MSM_SHARED_RAM_PHYS +
+		(htc_acoustic_vir_addr - (uint32_t)MSM_SHARED_RAM_BASE);
+	pgoff = ((pgoff + 4095) & ~4095);
+	htc_acoustic_vir_addr = ((htc_acoustic_vir_addr + 4095) & ~4095);
+
+	if (pgoff <= 0) {
+		E("pgoff wrong. %ld\n", pgoff);
+		goto done;
+	}
+
+	if (size <= HTC_ACOUSTIC_TABLE_SIZE) {
+		pgoff = pgoff >> PAGE_SHIFT;
+	} else {
+		E("size > HTC_ACOUSTIC_TABLE_SIZE  %d\n", size);
+		goto done;
+	}
+
+	vma->vm_flags |= VM_IO | VM_RESERVED;
+	rc = io_remap_pfn_range(vma, vma->vm_start, pgoff,
+				size, vma->vm_page_prot);
+
+	if (rc < 0)
+		E("mmap failed: remap error %d\n", rc);
+
+done:	mutex_unlock(&api_lock);
+	return rc;
+}
+
+static int acoustic_open(struct inode *inode, struct file *file)
+{
+	int reply_value;
+	int rc = -EIO;
+	struct set_smem_req {
+		struct rpc_request_hdr hdr;
+		uint32_t size;
+	} req_smem;
+
+	struct set_smem_rep {
+		struct rpc_reply_hdr hdr;
+		int n;
+	} rep_smem;
+
+	D("open\n");
+
+	mutex_lock(&api_lock);
+
+	if (!htc_acoustic_vir_addr) {
+		if (is_rpc_connect() == -1)
+			goto done;
+
+		req_smem.size = cpu_to_be32(HTC_ACOUSTIC_TABLE_SIZE);
+		rc = msm_rpc_call_reply(endpoint,
+					ONCRPC_ALLOC_ACOUSTIC_MEM_PROC,
+					&req_smem, sizeof(req_smem),
+					&rep_smem, sizeof(rep_smem),
+					5 * HZ);
+
+		reply_value = be32_to_cpu(rep_smem.n);
+		if (reply_value != 0 || rc < 0) {
+			E("open failed: ALLOC_ACOUSTIC_MEM_PROC error %d.\n",
+			rc);
+			goto done;
+		}
+		htc_acoustic_vir_addr =
+			(uint32_t)smem_alloc(SMEM_ID_VENDOR1,
+					HTC_ACOUSTIC_TABLE_SIZE);
+		if (!htc_acoustic_vir_addr) {
+			E("open failed: smem_alloc error\n");
+			goto done;
+		}
+	}
+
+	rc = 0;
+done:
+	mutex_unlock(&api_lock);
+	return rc;
+}
+
+static int acoustic_release(struct inode *inode, struct file *file)
+{
+	D("release\n");
+	return 0;
+}
+
+static long acoustic_ioctl(struct file *file, unsigned int cmd,
+			   unsigned long arg)
+{
+	int rc, reply_value;
+
+	D("ioctl\n");
+
+	mutex_lock(&api_lock);
+
+	switch (cmd) {
+	case ACOUSTIC_UPDATE_ADIE: {
+		struct update_adie_req {
+			struct rpc_request_hdr hdr;
+			int id;
+		} adie_req;
+
+		struct update_adie_rep {
+			struct rpc_reply_hdr hdr;
+			int ret;
+		} adie_rep;
+
+		D("ioctl: ACOUSTIC_UPDATE_ADIE called %d.\n", current->pid);
+
+		adie_req.id = cpu_to_be32(-1); /* update all codecs */
+		rc = msm_rpc_call_reply(endpoint,
+					ONCRPC_UPDATE_ADIE_PROC, &adie_req,
+					sizeof(adie_req), &adie_rep,
+					sizeof(adie_rep), 5 * HZ);
+
+		reply_value = be32_to_cpu(adie_rep.ret);
+		if (reply_value != 0 || rc < 0) {
+			E("ioctl failed: ONCRPC_UPDATE_ADIE_PROC "\
+				"error %d.\n", rc);
+			if (rc >= 0)
+				rc = -EIO;
+			break;
+		}
+		D("ioctl: ONCRPC_UPDATE_ADIE_PROC success.\n");
+		break;
+	}
+	default:
+		E("ioctl: invalid command\n");
+		rc = -EINVAL;
+	}
+
+	mutex_unlock(&api_lock);
+	return rc;
+}
+
+struct rpc_set_uplink_mute_args {
+	int mute;
+};
+
+static struct file_operations acoustic_fops = {
+	.owner = THIS_MODULE,
+	.open = acoustic_open,
+	.release = acoustic_release,
+	.mmap = acoustic_mmap,
+	.unlocked_ioctl = acoustic_ioctl,
+};
+
+static struct miscdevice acoustic_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "htc-acoustic",
+	.fops = &acoustic_fops,
+};
+
+static int __init acoustic_init(void)
+{
+	mutex_init(&api_lock);
+	mutex_init(&rpc_connect_lock);
+	return misc_register(&acoustic_misc);
+}
+
+static void __exit acoustic_exit(void)
+{
+	misc_deregister(&acoustic_misc);
+}
+
+module_init(acoustic_init);
+module_exit(acoustic_exit);
+
diff --git a/arch/arm/mach-msm/htc_akm_cal.c b/arch/arm/mach-msm/htc_akm_cal.c
new file mode 100644
index 0000000..943083f
--- /dev/null
+++ b/arch/arm/mach-msm/htc_akm_cal.c
@@ -0,0 +1,64 @@
+/* arch/arm/mach-msm/htc_akm_cal.c
+ *
+ * Code to extract compass calibration information from ATAG set up 
+ * by the bootloader.
+ *
+ * Copyright (C) 2007-2008 HTC Corporation
+ * Author: Farmer Tseng <farmer_tseng@htc.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/setup.h>
+
+/* configuration tags specific to AKM8976 */
+#define ATAG_AKM8976	0x89768976 /* AKM8976 */
+
+#define MAX_CALI_SIZE	0x1000U
+
+static char akm_cal_ram[MAX_CALI_SIZE];
+
+char *get_akm_cal_ram(void)
+{
+	return(akm_cal_ram);
+}
+EXPORT_SYMBOL(get_akm_cal_ram);
+
+static int __init parse_tag_akm(const struct tag *tag)
+{
+	unsigned char *dptr = (unsigned char *)(&tag->u);
+	unsigned size;
+
+	size = min((tag->hdr.size - 2) * sizeof(__u32), MAX_CALI_SIZE);
+
+	printk(KERN_INFO "AKM Data size = %d , 0x%x, size = %d\n",
+			tag->hdr.size, tag->hdr.tag, size);
+
+#ifdef ATAG_COMPASS_DEBUG
+	unsigned i;
+	unsigned char *ptr;
+
+	ptr = dptr;
+	printk(KERN_INFO
+	       "AKM Data size = %d , 0x%x\n",
+	       tag->hdr.size, tag->hdr.tag);
+	for (i = 0; i < size; i++)
+		printk(KERN_INFO "%02x ", *ptr++);
+#endif
+	memcpy((void *)akm_cal_ram, (void *)dptr, size);
+	return 0;
+}
+
+__tagtable(ATAG_AKM8976, parse_tag_akm);
diff --git a/arch/arm/mach-msm/htc_battery.c b/arch/arm/mach-msm/htc_battery.c
new file mode 100644
index 0000000..d49c23e
--- /dev/null
+++ b/arch/arm/mach-msm/htc_battery.c
@@ -0,0 +1,771 @@
+/* arch/arm/mach-msm/htc_battery.c
+ *
+ * Copyright (C) 2008 HTC Corporation.
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/power_supply.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/wakelock.h>
+#include <asm/gpio.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/board.h>
+
+static struct wake_lock vbus_wake_lock;
+
+#define TRACE_BATT 0
+
+#if TRACE_BATT
+#define BATT(x...) printk(KERN_INFO "[BATT] " x)
+#else
+#define BATT(x...) do {} while (0)
+#endif
+
+/* rpc related */
+#define APP_BATT_PDEV_NAME		"rs30100001"
+#define APP_BATT_PROG			0x30100001
+#define APP_BATT_VER			0
+#define HTC_PROCEDURE_BATTERY_NULL	0
+#define HTC_PROCEDURE_GET_BATT_LEVEL	1
+#define HTC_PROCEDURE_GET_BATT_INFO	2
+#define HTC_PROCEDURE_GET_CABLE_STATUS	3
+#define HTC_PROCEDURE_SET_BATT_DELTA	4
+
+/* module debugger */
+#define HTC_BATTERY_DEBUG		1
+#define BATTERY_PREVENTION		1
+
+/* Enable this will shut down if no battery */
+#define ENABLE_BATTERY_DETECTION	0
+
+#define GPIO_BATTERY_DETECTION		21
+#define GPIO_BATTERY_CHARGER_EN		128
+
+/* Charge current selection */
+#define GPIO_BATTERY_CHARGER_CURRENT	129
+
+typedef enum {
+	DISABLE = 0,
+	ENABLE_SLOW_CHG,
+	ENABLE_FAST_CHG
+} batt_ctl_t;
+
+/* This order is the same as htc_power_supplies[]
+ * And it's also the same as htc_cable_status_update()
+ */
+typedef enum {
+	CHARGER_BATTERY = 0,
+	CHARGER_USB,
+	CHARGER_AC
+} charger_type_t;
+
+struct battery_info_reply {
+	u32 batt_id;		/* Battery ID from ADC */
+	u32 batt_vol;		/* Battery voltage from ADC */
+	u32 batt_temp;		/* Battery Temperature (C) from formula and ADC */
+	u32 batt_current;	/* Battery current from ADC */
+	u32 level;		/* formula */
+	u32 charging_source;	/* 0: no cable, 1:usb, 2:AC */
+	u32 charging_enabled;	/* 0: Disable, 1: Enable */
+	u32 full_bat;		/* Full capacity of battery (mAh) */
+};
+
+struct htc_battery_info {
+	int present;
+	unsigned long update_time;
+
+	/* lock to protect the battery info */
+	struct mutex lock;
+
+	/* lock held while calling the arm9 to query the battery info */
+	struct mutex rpc_lock;
+	struct battery_info_reply rep;
+};
+
+static struct msm_rpc_endpoint *endpoint;
+
+static struct htc_battery_info htc_batt_info;
+
+static unsigned int cache_time = 1000;
+
+static int htc_battery_initial = 0;
+
+static enum power_supply_property htc_battery_properties[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_HEALTH,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_TECHNOLOGY,
+	POWER_SUPPLY_PROP_CAPACITY,
+};
+
+static enum power_supply_property htc_power_properties[] = {
+	POWER_SUPPLY_PROP_ONLINE,
+};
+
+static char *supply_list[] = {
+	"battery",
+};
+
+/* HTC dedicated attributes */
+static ssize_t htc_battery_show_property(struct device *dev,
+					  struct device_attribute *attr,
+					  char *buf);
+
+static int htc_power_get_property(struct power_supply *psy, 
+				    enum power_supply_property psp,
+				    union power_supply_propval *val);
+
+static int htc_battery_get_property(struct power_supply *psy, 
+				    enum power_supply_property psp,
+				    union power_supply_propval *val);
+
+static struct power_supply htc_power_supplies[] = {
+	{
+		.name = "battery",
+		.type = POWER_SUPPLY_TYPE_BATTERY,
+		.properties = htc_battery_properties,
+		.num_properties = ARRAY_SIZE(htc_battery_properties),
+		.get_property = htc_battery_get_property,
+	},
+	{
+		.name = "usb",
+		.type = POWER_SUPPLY_TYPE_USB,
+		.supplied_to = supply_list,
+		.num_supplicants = ARRAY_SIZE(supply_list),
+		.properties = htc_power_properties,
+		.num_properties = ARRAY_SIZE(htc_power_properties),
+		.get_property = htc_power_get_property,
+	},
+	{
+		.name = "ac",
+		.type = POWER_SUPPLY_TYPE_MAINS,
+		.supplied_to = supply_list,
+		.num_supplicants = ARRAY_SIZE(supply_list),
+		.properties = htc_power_properties,
+		.num_properties = ARRAY_SIZE(htc_power_properties),
+		.get_property = htc_power_get_property,
+	},
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+#if defined(CONFIG_DEBUG_FS)
+int htc_battery_set_charging(batt_ctl_t ctl);
+static int batt_debug_set(void *data, u64 val)
+{
+	return htc_battery_set_charging((batt_ctl_t) val);
+}
+
+static int batt_debug_get(void *data, u64 *val)
+{
+	return -ENOSYS;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(batt_debug_fops, batt_debug_get, batt_debug_set, "%llu\n");
+static int __init batt_debug_init(void)
+{
+	struct dentry *dent;
+
+	dent = debugfs_create_dir("htc_battery", 0);
+	if (IS_ERR(dent))
+		return PTR_ERR(dent);
+
+	debugfs_create_file("charger_state", 0644, dent, NULL, &batt_debug_fops);
+
+	return 0;
+}
+
+device_initcall(batt_debug_init);
+#endif
+
+static int init_batt_gpio(void)
+{
+	if (gpio_request(GPIO_BATTERY_DETECTION, "batt_detect") < 0)
+		goto gpio_failed;
+	if (gpio_request(GPIO_BATTERY_CHARGER_EN, "charger_en") < 0)
+		goto gpio_failed;
+	if (gpio_request(GPIO_BATTERY_CHARGER_CURRENT, "charge_current") < 0)
+		goto gpio_failed;
+
+	return 0;
+
+gpio_failed:	
+	return -EINVAL;
+	
+}
+
+/* 
+ *	battery_charging_ctrl - battery charing control.
+ * 	@ctl:			battery control command
+ *
+ */
+static int battery_charging_ctrl(batt_ctl_t ctl)
+{
+	int result = 0;
+
+	switch (ctl) {
+	case DISABLE:
+		BATT("charger OFF\n");
+		/* 0 for enable; 1 disable */
+		result = gpio_direction_output(GPIO_BATTERY_CHARGER_EN, 1);
+		break;
+	case ENABLE_SLOW_CHG:
+		BATT("charger ON (SLOW)\n");
+		result = gpio_direction_output(GPIO_BATTERY_CHARGER_CURRENT, 0);
+		result = gpio_direction_output(GPIO_BATTERY_CHARGER_EN, 0);
+		break;
+	case ENABLE_FAST_CHG:
+		BATT("charger ON (FAST)\n");
+		result = gpio_direction_output(GPIO_BATTERY_CHARGER_CURRENT, 1);
+		result = gpio_direction_output(GPIO_BATTERY_CHARGER_EN, 0);
+		break;
+	default:
+		printk(KERN_ERR "Not supported battery ctr called.!\n");
+		result = -EINVAL;
+		break;
+	}
+	
+	return result;
+}
+
+int htc_battery_set_charging(batt_ctl_t ctl)
+{
+	int rc;
+	
+	if ((rc = battery_charging_ctrl(ctl)) < 0)
+		goto result;
+	
+	if (!htc_battery_initial) {
+		htc_batt_info.rep.charging_enabled = ctl & 0x3;
+	} else {
+		mutex_lock(&htc_batt_info.lock);
+		htc_batt_info.rep.charging_enabled = ctl & 0x3;
+		mutex_unlock(&htc_batt_info.lock);
+	}
+result:	
+	return rc;
+}
+
+int htc_battery_status_update(u32 curr_level)
+{
+	int notify;
+	if (!htc_battery_initial)
+		return 0;
+
+	mutex_lock(&htc_batt_info.lock);
+	notify = (htc_batt_info.rep.level != curr_level);
+	htc_batt_info.rep.level = curr_level;
+	mutex_unlock(&htc_batt_info.lock);
+
+	if (notify)
+		power_supply_changed(&htc_power_supplies[CHARGER_BATTERY]);
+	return 0;
+}
+
+int htc_cable_status_update(int status)
+{
+	int rc = 0;
+	unsigned source;
+
+	if (!htc_battery_initial)
+		return 0;
+	
+	mutex_lock(&htc_batt_info.lock);
+	switch(status) {
+	case CHARGER_BATTERY:
+		BATT("cable NOT PRESENT\n");
+		htc_batt_info.rep.charging_source = CHARGER_BATTERY;
+		break;
+	case CHARGER_USB:
+		BATT("cable USB\n");
+		htc_batt_info.rep.charging_source = CHARGER_USB;
+		break;
+	case CHARGER_AC:
+		BATT("cable AC\n");
+		htc_batt_info.rep.charging_source = CHARGER_AC;
+		break;
+	default:
+		printk(KERN_ERR "%s: Not supported cable status received!\n",
+				__FUNCTION__);
+		rc = -EINVAL;
+	}
+	source = htc_batt_info.rep.charging_source;
+	mutex_unlock(&htc_batt_info.lock);
+
+	msm_hsusb_set_vbus_state(source == CHARGER_USB);
+	if (source == CHARGER_USB) {
+		wake_lock(&vbus_wake_lock);
+	} else {
+		/* give userspace some time to see the uevent and update
+		 * LED state or whatnot...
+		 */
+		wake_lock_timeout(&vbus_wake_lock, HZ / 2);
+	}
+
+	/* if the power source changes, all power supplies may change state */
+	power_supply_changed(&htc_power_supplies[CHARGER_BATTERY]);
+	power_supply_changed(&htc_power_supplies[CHARGER_USB]);
+	power_supply_changed(&htc_power_supplies[CHARGER_AC]);
+
+	return rc;
+}
+
+static int htc_get_batt_info(struct battery_info_reply *buffer)
+{
+	struct rpc_request_hdr req;
+	
+	struct htc_get_batt_info_rep {
+		struct rpc_reply_hdr hdr;
+		struct battery_info_reply info;
+	} rep;
+	
+	int rc;
+
+	if (buffer == NULL) 
+		return -EINVAL;
+
+	rc = msm_rpc_call_reply(endpoint, HTC_PROCEDURE_GET_BATT_INFO,
+				&req, sizeof(req),
+				&rep, sizeof(rep),
+				5 * HZ);
+	if ( rc < 0 ) 
+		return rc;
+	
+	mutex_lock(&htc_batt_info.lock);
+	buffer->batt_id 		= be32_to_cpu(rep.info.batt_id);
+	buffer->batt_vol 		= be32_to_cpu(rep.info.batt_vol);
+	buffer->batt_temp 		= be32_to_cpu(rep.info.batt_temp);
+	buffer->batt_current 		= be32_to_cpu(rep.info.batt_current);
+	buffer->level 			= be32_to_cpu(rep.info.level);
+	buffer->charging_source 	= be32_to_cpu(rep.info.charging_source);
+	buffer->charging_enabled 	= be32_to_cpu(rep.info.charging_enabled);
+	buffer->full_bat 		= be32_to_cpu(rep.info.full_bat);
+	mutex_unlock(&htc_batt_info.lock);
+
+	return 0;
+}
+
+#if 0
+static int htc_get_cable_status(void)
+{
+	
+	struct rpc_request_hdr req;
+	
+	struct htc_get_cable_status_rep {
+		struct rpc_reply_hdr hdr;
+		int status;
+	} rep;
+
+	int rc;
+
+	rc = msm_rpc_call_reply(endpoint, HTC_PROCEDURE_GET_CABLE_STATUS,
+				&req, sizeof(req),
+				&rep, sizeof(rep),
+				5 * HZ);
+	if (rc < 0) 
+		return rc;
+
+	return be32_to_cpu(rep.status);
+}
+#endif
+
+/* -------------------------------------------------------------------------- */
+static int htc_power_get_property(struct power_supply *psy, 
+				    enum power_supply_property psp,
+				    union power_supply_propval *val)
+{
+	charger_type_t charger;
+	
+	mutex_lock(&htc_batt_info.lock);
+	charger = htc_batt_info.rep.charging_source;
+	mutex_unlock(&htc_batt_info.lock);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		if (psy->type == POWER_SUPPLY_TYPE_MAINS)
+			val->intval = (charger ==  CHARGER_AC ? 1 : 0);
+		else if (psy->type == POWER_SUPPLY_TYPE_USB)
+			val->intval = (charger ==  CHARGER_USB ? 1 : 0);
+		else
+			val->intval = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+	
+	return 0;
+}
+
+static int htc_battery_get_charging_status(void)
+{
+	u32 level;
+	charger_type_t charger;	
+	int ret;
+	
+	mutex_lock(&htc_batt_info.lock);
+	charger = htc_batt_info.rep.charging_source;
+	
+	switch (charger) {
+	case CHARGER_BATTERY:
+		ret = POWER_SUPPLY_STATUS_NOT_CHARGING;
+		break;
+	case CHARGER_USB:
+	case CHARGER_AC:
+		level = htc_batt_info.rep.level;
+		if (level == 100)
+			ret = POWER_SUPPLY_STATUS_FULL;
+		else
+			ret = POWER_SUPPLY_STATUS_CHARGING;
+		break;
+	default:
+		ret = POWER_SUPPLY_STATUS_UNKNOWN;
+	}
+	mutex_unlock(&htc_batt_info.lock);
+	return ret;
+}
+
+static int htc_battery_get_property(struct power_supply *psy, 
+				    enum power_supply_property psp,
+				    union power_supply_propval *val)
+{
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		val->intval = htc_battery_get_charging_status();
+		break;
+	case POWER_SUPPLY_PROP_HEALTH:
+		val->intval = POWER_SUPPLY_HEALTH_GOOD;
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = htc_batt_info.present;
+		break;
+	case POWER_SUPPLY_PROP_TECHNOLOGY:
+		val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY:
+		mutex_lock(&htc_batt_info.lock);
+		val->intval = htc_batt_info.rep.level;
+		mutex_unlock(&htc_batt_info.lock);
+		break;
+	default:		
+		return -EINVAL;
+	}
+	
+	return 0;
+}
+
+#define HTC_BATTERY_ATTR(_name)							\
+{										\
+	.attr = { .name = #_name, .mode = S_IRUGO, .owner = THIS_MODULE },	\
+	.show = htc_battery_show_property,					\
+	.store = NULL,								\
+}
+
+static struct device_attribute htc_battery_attrs[] = {
+	HTC_BATTERY_ATTR(batt_id),
+	HTC_BATTERY_ATTR(batt_vol),
+	HTC_BATTERY_ATTR(batt_temp),
+	HTC_BATTERY_ATTR(batt_current),
+	HTC_BATTERY_ATTR(charging_source),
+	HTC_BATTERY_ATTR(charging_enabled),
+	HTC_BATTERY_ATTR(full_bat),
+};
+
+enum {
+	BATT_ID = 0,
+	BATT_VOL,
+	BATT_TEMP,
+	BATT_CURRENT,
+	CHARGING_SOURCE,
+	CHARGING_ENABLED,
+	FULL_BAT,
+};
+
+static int htc_rpc_set_delta(unsigned delta)
+{
+	struct set_batt_delta_req {
+		struct rpc_request_hdr hdr;
+		uint32_t data;
+	} req;
+
+	req.data = cpu_to_be32(delta);
+	return msm_rpc_call(endpoint, HTC_PROCEDURE_SET_BATT_DELTA,
+			    &req, sizeof(req), 5 * HZ);
+}
+
+
+static ssize_t htc_battery_set_delta(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	int rc;
+	unsigned long delta = 0;
+	
+	delta = simple_strtoul(buf, NULL, 10);
+
+	if (delta > 100)
+		return -EINVAL;
+
+	mutex_lock(&htc_batt_info.rpc_lock);
+	rc = htc_rpc_set_delta(delta);
+	mutex_unlock(&htc_batt_info.rpc_lock);
+	if (rc < 0)
+		return rc;
+	return count;
+}
+
+static struct device_attribute htc_set_delta_attrs[] = {
+	__ATTR(delta, S_IWUSR | S_IWGRP, NULL, htc_battery_set_delta),
+};
+
+static int htc_battery_create_attrs(struct device * dev)
+{
+	int i, j, rc;
+	
+	for (i = 0; i < ARRAY_SIZE(htc_battery_attrs); i++) {
+		rc = device_create_file(dev, &htc_battery_attrs[i]);
+		if (rc)
+			goto htc_attrs_failed;
+	}
+
+	for (j = 0; j < ARRAY_SIZE(htc_set_delta_attrs); j++) {
+		rc = device_create_file(dev, &htc_set_delta_attrs[j]);
+		if (rc)
+			goto htc_delta_attrs_failed;
+	}
+	
+	goto succeed;
+	
+htc_attrs_failed:
+	while (i--)
+		device_remove_file(dev, &htc_battery_attrs[i]);
+htc_delta_attrs_failed:
+	while (j--)
+		device_remove_file(dev, &htc_set_delta_attrs[i]);
+succeed:	
+	return rc;
+}
+
+static ssize_t htc_battery_show_property(struct device *dev,
+					 struct device_attribute *attr,
+					 char *buf)
+{
+	int i = 0;
+	const ptrdiff_t off = attr - htc_battery_attrs;
+	
+	/* rpc lock is used to prevent two threads from calling
+	 * into the get info rpc at the same time
+	 */
+
+	mutex_lock(&htc_batt_info.rpc_lock);
+	/* check cache time to decide if we need to update */
+	if (htc_batt_info.update_time &&
+            time_before(jiffies, htc_batt_info.update_time +
+                                msecs_to_jiffies(cache_time)))
+                goto dont_need_update;
+	
+	if (htc_get_batt_info(&htc_batt_info.rep) < 0)
+		printk(KERN_ERR "%s: rpc failed!!!\n", __FUNCTION__);
+	else
+		htc_batt_info.update_time = jiffies;
+dont_need_update:
+	mutex_unlock(&htc_batt_info.rpc_lock);
+
+	mutex_lock(&htc_batt_info.lock);
+	switch (off) {
+	case BATT_ID:
+		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+			       htc_batt_info.rep.batt_id);
+		break;
+	case BATT_VOL:
+		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+			       htc_batt_info.rep.batt_vol);
+		break;
+	case BATT_TEMP:
+		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+			       htc_batt_info.rep.batt_temp);
+		break;
+	case BATT_CURRENT:
+		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+			       htc_batt_info.rep.batt_current);
+		break;
+	case CHARGING_SOURCE:
+		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+			       htc_batt_info.rep.charging_source);
+		break;
+	case CHARGING_ENABLED:
+		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+			       htc_batt_info.rep.charging_enabled);
+		break;		
+	case FULL_BAT:
+		i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+			       htc_batt_info.rep.full_bat);
+		break;
+	default:
+		i = -EINVAL;
+	}	
+	mutex_unlock(&htc_batt_info.lock);
+	
+	return i;
+}
+
+static int htc_battery_probe(struct platform_device *pdev)
+{
+	int i, rc;
+
+	if (pdev->id != (APP_BATT_VER & RPC_VERSION_MAJOR_MASK))
+		return -EINVAL;
+
+	/* init battery gpio */
+	if ((rc = init_batt_gpio()) < 0) {
+		printk(KERN_ERR "%s: init battery gpio failed!\n", __FUNCTION__);
+		return rc;
+	}
+
+	/* init structure data member */
+	htc_batt_info.update_time 	= jiffies;
+	htc_batt_info.present 		= gpio_get_value(GPIO_BATTERY_DETECTION);
+	
+	/* init rpc */
+	endpoint = msm_rpc_connect(APP_BATT_PROG, APP_BATT_VER, 0);
+	if (IS_ERR(endpoint)) {
+		printk(KERN_ERR "%s: init rpc failed! rc = %ld\n",
+		       __FUNCTION__, PTR_ERR(endpoint));
+		return rc;
+	}
+
+	/* init power supplier framework */
+	for (i = 0; i < ARRAY_SIZE(htc_power_supplies); i++) {
+		rc = power_supply_register(&pdev->dev, &htc_power_supplies[i]);
+		if (rc)
+			printk(KERN_ERR "Failed to register power supply (%d)\n", rc);	
+	}
+
+	/* create htc detail attributes */
+	htc_battery_create_attrs(htc_power_supplies[CHARGER_BATTERY].dev);
+
+	/* After battery driver gets initialized, send rpc request to inquiry
+	 * the battery status in case of we lost some info
+	 */
+	htc_battery_initial = 1;
+
+	mutex_lock(&htc_batt_info.rpc_lock);
+	if (htc_get_batt_info(&htc_batt_info.rep) < 0)
+		printk(KERN_ERR "%s: get info failed\n", __FUNCTION__);
+
+	htc_cable_status_update(htc_batt_info.rep.charging_source);
+	battery_charging_ctrl(htc_batt_info.rep.charging_enabled ?
+			      ENABLE_SLOW_CHG : DISABLE);
+
+	if (htc_rpc_set_delta(1) < 0)
+		printk(KERN_ERR "%s: set delta failed\n", __FUNCTION__);
+	htc_batt_info.update_time = jiffies;
+	mutex_unlock(&htc_batt_info.rpc_lock);
+
+	if (htc_batt_info.rep.charging_enabled == 0)
+		battery_charging_ctrl(DISABLE);
+	
+	return 0;
+}
+
+static struct platform_driver htc_battery_driver = {
+	.probe	= htc_battery_probe,
+	.driver	= {
+		.name	= APP_BATT_PDEV_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+/* batt_mtoa server definitions */
+#define BATT_MTOA_PROG				0x30100000
+#define BATT_MTOA_VERS				0
+#define RPC_BATT_MTOA_NULL			0
+#define RPC_BATT_MTOA_SET_CHARGING_PROC		1
+#define RPC_BATT_MTOA_CABLE_STATUS_UPDATE_PROC	2
+#define RPC_BATT_MTOA_LEVEL_UPDATE_PROC		3
+
+struct rpc_batt_mtoa_set_charging_args {
+	int enable;
+};
+
+struct rpc_batt_mtoa_cable_status_update_args {
+	int status;
+};
+
+struct rpc_dem_battery_update_args {
+	uint32_t level;
+};
+
+static int handle_battery_call(struct msm_rpc_server *server,
+			       struct rpc_request_hdr *req, unsigned len)
+{	
+	switch (req->procedure) {
+	case RPC_BATT_MTOA_NULL:
+		return 0;
+
+	case RPC_BATT_MTOA_SET_CHARGING_PROC: {
+		struct rpc_batt_mtoa_set_charging_args *args;
+		args = (struct rpc_batt_mtoa_set_charging_args *)(req + 1);
+		args->enable = be32_to_cpu(args->enable);
+		BATT("set_charging: enable=%d\n",args->enable);
+		htc_battery_set_charging(args->enable);
+		return 0;
+	}
+	case RPC_BATT_MTOA_CABLE_STATUS_UPDATE_PROC: {
+		struct rpc_batt_mtoa_cable_status_update_args *args;
+		args = (struct rpc_batt_mtoa_cable_status_update_args *)(req + 1);
+		args->status = be32_to_cpu(args->status);
+		BATT("cable_status_update: status=%d\n",args->status);
+		htc_cable_status_update(args->status);
+		return 0;
+	}
+	case RPC_BATT_MTOA_LEVEL_UPDATE_PROC: {
+		struct rpc_dem_battery_update_args *args;
+		args = (struct rpc_dem_battery_update_args *)(req + 1);
+		args->level = be32_to_cpu(args->level);
+		BATT("dem_battery_update: level=%d\n",args->level);
+		htc_battery_status_update(args->level);
+		return 0;
+	}
+	default:
+		printk(KERN_ERR "%s: program 0x%08x:%d: unknown procedure %d\n",
+		       __FUNCTION__, req->prog, req->vers, req->procedure);
+		return -ENODEV;
+	}
+}
+
+static struct msm_rpc_server battery_server = {
+	.prog = BATT_MTOA_PROG,
+	.vers = BATT_MTOA_VERS,
+	.rpc_call = handle_battery_call,
+};
+
+static int __init htc_battery_init(void)
+{
+	wake_lock_init(&vbus_wake_lock, WAKE_LOCK_SUSPEND, "vbus_present");
+	mutex_init(&htc_batt_info.lock);
+	mutex_init(&htc_batt_info.rpc_lock);
+	msm_rpc_create_server(&battery_server);
+	platform_driver_register(&htc_battery_driver);
+	return 0;
+}
+
+module_init(htc_battery_init);
+MODULE_DESCRIPTION("HTC Battery Driver");
+MODULE_LICENSE("GPL");
+
diff --git a/arch/arm/mach-msm/htc_headset.c b/arch/arm/mach-msm/htc_headset.c
new file mode 100644
index 0000000..a69a2e1
--- /dev/null
+++ b/arch/arm/mach-msm/htc_headset.c
@@ -0,0 +1,1246 @@
+/*
+ *  H2W device detection driver.
+ *
+ *  Copyright (C) 2008 Google, Inc.
+ *  Copyright (C) 2008 HTC, Inc.
+ *
+ *  Authors:
+ *      Laurence Chen <Laurence_Chen@htc.com>
+ *      Nick Pelly <npelly@google.com>
+ *      Thomas Tsai <thomas_tsai@htc.com>
+ *      Farmer Tseng <farmer_tseng@htc.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ */
+
+/*  For detecting HTC 2 Wire devices, such as wired headset.
+
+    Logically, the H2W driver is always present, and H2W state (hi->state)
+    indicates what is currently plugged into the H2W interface.
+
+    When the headset is plugged in, CABLE_IN1 is pulled low. When the headset
+    button is pressed, CABLE_IN2 is pulled low. These two lines are shared with
+    the TX and RX (respectively) of UART3 - used for serial debugging.
+
+    This headset driver keeps the CPLD configured as UART3 for as long as
+    possible, so that we can do serial FIQ debugging even when the kernel is
+    locked and this driver no longer runs. So it only configures the CPLD to
+    GPIO while the headset is plugged in, and for 10ms during detection work.
+
+    Unfortunately we can't leave the CPLD as UART3 while a headset is plugged
+    in, UART3 is pullup on TX but the headset is pull-down, causing a 55 mA
+    drain on trout.
+
+    The headset detection work involves setting CPLD to GPIO, and then pulling
+    CABLE_IN1 high with a stronger pullup than usual. A H2W headset will still
+    pull this line low, whereas other attachments such as a serial console
+    would get pulled up by this stronger pullup.
+
+    Headset insertion/removal causes UEvent's to be sent, and
+    /sys/class/switch/h2w/state to be updated.
+
+    Button presses are interpreted as input event (KEY_MEDIA). Button presses
+    are ignored if the headset is plugged in, so the buttons on 11 pin -> 3.5mm
+    jack adapters do not work until a headset is plugged into the adapter. This
+    is to avoid serial RX traffic causing spurious button press events.
+
+    We tend to check the status of CABLE_IN1 a few more times than strictly
+    necessary during headset detection, to avoid spurious headset insertion
+    events caused by serial debugger TX traffic.
+*/
+
+#include <linux/module.h>
+#include <linux/sysdev.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/hrtimer.h>
+#include <linux/switch.h>
+#include <linux/input.h>
+#include <linux/debugfs.h>
+#include <asm/gpio.h>
+#include <asm/atomic.h>
+#include <mach/board.h>
+#include <mach/vreg.h>
+#include <asm/mach-types.h>
+
+#include <mach/htc_headset.h>
+
+#define H2WI(fmt, arg...) \
+	printk(KERN_INFO "[H2W] %s " fmt "\r\n", __func__, ## arg)
+#define H2WE(fmt, arg...) \
+	printk(KERN_ERR "[H2W] %s " fmt "\r\n", __func__, ## arg)
+
+#ifdef CONFIG_DEBUG_H2W
+#define H2W_DBG(fmt, arg...) printk(KERN_INFO "[H2W] %s " fmt "\r\n", __func__, ## arg)
+#else
+#define H2W_DBG(fmt, arg...) do {} while (0)
+#endif
+
+static struct workqueue_struct *g_detection_work_queue;
+static void detection_work(struct work_struct *work);
+static DECLARE_WORK(g_detection_work, detection_work);
+
+struct h2w_info {
+	struct switch_dev sdev;
+	struct input_dev *input;
+	struct mutex mutex_lock;
+
+	atomic_t btn_state;
+	int ignore_btn;
+
+	unsigned int irq;
+	unsigned int irq_btn;
+
+	int cable_in1;
+	int cable_in2;
+	int h2w_clk;
+	int h2w_data;
+	int debug_uart;
+
+	void (*config_cpld) (int);
+	void (*init_cpld) (void);
+	/* for h2w */
+	void (*set_dat)(int);
+	void (*set_clk)(int);
+	void (*set_dat_dir)(int);
+	void (*set_clk_dir)(int);
+	int (*get_dat)(void);
+	int (*get_clk)(void);
+
+	int htc_headset_flag;
+
+	struct hrtimer timer;
+	ktime_t debounce_time;
+
+	struct hrtimer btn_timer;
+	ktime_t btn_debounce_time;
+
+	H2W_INFO h2w_info;
+	H2W_SPEED speed;
+	struct vreg *vreg_h2w;
+};
+static struct h2w_info *hi;
+
+static ssize_t h2w_print_name(struct switch_dev *sdev, char *buf)
+{
+	switch (switch_get_state(&hi->sdev)) {
+	case H2W_NO_DEVICE:
+		return sprintf(buf, "No Device\n");
+	case H2W_HTC_HEADSET:
+		return sprintf(buf, "Headset\n");
+	}
+	return -EINVAL;
+}
+
+static void button_pressed(void)
+{
+	H2W_DBG("button_pressed \n");
+	atomic_set(&hi->btn_state, 1);
+	input_report_key(hi->input, KEY_MEDIA, 1);
+	input_sync(hi->input);
+}
+
+static void button_released(void)
+{
+	H2W_DBG("button_released \n");
+	atomic_set(&hi->btn_state, 0);
+	input_report_key(hi->input, KEY_MEDIA, 0);
+	input_sync(hi->input);
+}
+
+/*****************
+ * H2W proctocol *
+ *****************/
+static inline void h2w_begin_command(void)
+{
+	/* Disable H2W interrupt */
+	set_irq_type(hi->irq_btn, IRQF_TRIGGER_HIGH);
+	disable_irq(hi->irq);
+	disable_irq(hi->irq_btn);
+
+	/* Set H2W_CLK as output low */
+	hi->set_clk(0);
+	hi->set_clk_dir(1);
+}
+
+static inline void h2w_end_command(void)
+{
+	/* Set H2W_CLK as input */
+	hi->set_clk_dir(0);
+
+	/* Enable H2W interrupt */
+	enable_irq(hi->irq);
+	enable_irq(hi->irq_btn);
+	set_irq_type(hi->irq_btn, IRQF_TRIGGER_RISING);
+}
+
+/*
+ * One bit write data
+ *                     ________
+ *       SCLK O ______|        |______O(L)
+ *
+ *
+ *	     SDAT I <XXXXXXXXXXXXXXXXXXXX>
+ */
+static inline void one_clock_write(unsigned short flag)
+{
+	if (flag)
+		hi->set_dat(1);
+	else
+		hi->set_dat(0);
+
+	udelay(hi->speed);
+	hi->set_clk(1);
+	udelay(hi->speed);
+	hi->set_clk(0);
+}
+
+/*
+ * One bit write data R/W bit
+ *                   ________
+ *       SCLK ______|        |______O(L)
+ *            1---->         1----->
+ *                  2-------> ______
+ *	 SDAT <XXXXXXXXXXXXXX>      I
+ *                         O(H/L)
+ */
+static inline void one_clock_write_RWbit(unsigned short flag)
+{
+	if (flag)
+		hi->set_dat(1);
+	else
+		hi->set_dat(0);
+
+	udelay(hi->speed);
+	hi->set_clk(1);
+	udelay(hi->speed);
+	hi->set_clk(0);
+	hi->set_dat_dir(0);
+	udelay(hi->speed);
+}
+
+/*
+ * H2W Reset
+ *                       ___________
+ *       SCLK O(L)______|           |___O(L)
+ *                1---->
+ *                      4-->1-->1-->1us-->
+ *                          ____
+ *       SDAT O(L)________ |    |_______O(L)
+ *
+ * H2w reset command needs to be issued before every access
+ */
+static inline void h2w_reset(void)
+{
+	/* Set H2W_DAT as output low */
+	hi->set_dat(0);
+	hi->set_dat_dir(1);
+
+	udelay(hi->speed);
+	hi->set_clk(1);
+	udelay(4 * hi->speed);
+	hi->set_dat(1);
+	udelay(hi->speed);
+	hi->set_dat(0);
+	udelay(hi->speed);
+	hi->set_clk(0);
+	udelay(hi->speed);
+}
+
+/*
+ * H2W Start
+ *                       ___________
+ *       SCLK O(L)______|           |___O(L)
+ *                1---->
+ *                      2----------->1-->
+ *
+ *       SDAT O(L)______________________O(L)
+ */
+static inline void h2w_start(void)
+{
+	udelay(hi->speed);
+	hi->set_clk(1);
+	udelay(2 * hi->speed);
+	hi->set_clk(0);
+	udelay(hi->speed);
+}
+
+/*
+ * H2W Ack
+ *                  __________
+ *       SCLK _____|          |_______O(L)
+ *            1---->	      1------>
+ *		           2--------->
+ *            ________________________
+ *	 SDAT  become Input mode here I
+ */
+static inline int h2w_ack(void)
+{
+	int retry_times = 0;
+
+ack_resend:
+	if (retry_times == MAX_ACK_RESEND_TIMES)
+		return -1;
+
+	udelay(hi->speed);
+	hi->set_clk(1);
+	udelay(2 * hi->speed);
+
+	if (!hi->get_dat()) {
+		retry_times++;
+		hi->set_clk(0);
+		udelay(hi->speed);
+		goto ack_resend;
+	}
+
+	hi->set_clk(0);
+	udelay(hi->speed);
+	return 0;
+}
+
+/*
+ * One bit read data
+ *                   ________
+ *       SCLK ______|        |______O(L)
+ *            2---->         2----->
+ *                  2------->
+ *	 SDAT <XXXXXXXXXXXXXXXXXXXX>I
+ */
+static unsigned char h2w_readc(void)
+{
+	unsigned char h2w_read_data = 0x0;
+	int index;
+
+	for (index = 0; index < 8; index++) {
+		hi->set_clk(0);
+		udelay(hi->speed);
+		hi->set_clk(1);
+		udelay(hi->speed);
+		if (hi->get_dat())
+			h2w_read_data |= (1 << (7 - index));
+	}
+	hi->set_clk(0);
+	udelay(hi->speed);
+
+	return h2w_read_data;
+}
+
+static int h2w_readc_cmd(H2W_ADDR address)
+{
+	int ret = -1, retry_times = 0;
+	unsigned char read_data;
+
+read_resend:
+	if (retry_times == MAX_HOST_RESEND_TIMES)
+		goto err_read;
+
+	h2w_reset();
+	h2w_start();
+	/* Write address */
+	one_clock_write(address & 0x1000);
+	one_clock_write(address & 0x0800);
+	one_clock_write(address & 0x0400);
+	one_clock_write(address & 0x0200);
+	one_clock_write(address & 0x0100);
+	one_clock_write(address & 0x0080);
+	one_clock_write(address & 0x0040);
+	one_clock_write(address & 0x0020);
+	one_clock_write(address & 0x0010);
+	one_clock_write(address & 0x0008);
+	one_clock_write(address & 0x0004);
+	one_clock_write(address & 0x0002);
+	one_clock_write(address & 0x0001);
+	one_clock_write_RWbit(1);
+	if (h2w_ack() < 0) {
+		H2W_DBG("Addr NO ACK(%d).\n", retry_times);
+		retry_times++;
+		hi->set_clk(0);
+		mdelay(RESEND_DELAY);
+		goto read_resend;
+	}
+
+	read_data = h2w_readc();
+
+	if (h2w_ack() < 0) {
+		H2W_DBG("Data NO ACK(%d).\n", retry_times);
+		retry_times++;
+		hi->set_clk(0);
+		mdelay(RESEND_DELAY);
+		goto read_resend;
+	}
+	ret = (int)read_data;
+
+err_read:
+	if (ret < 0)
+		H2WE("NO ACK.\n");
+
+	return ret;
+}
+
+static int h2w_writec_cmd(H2W_ADDR address, unsigned char data)
+{
+	int ret = -1;
+	int retry_times = 0;
+
+write_resend:
+	if (retry_times == MAX_HOST_RESEND_TIMES)
+		goto err_write;
+
+	h2w_reset();
+	h2w_start();
+
+	/* Write address */
+	one_clock_write(address & 0x1000);
+	one_clock_write(address & 0x0800);
+	one_clock_write(address & 0x0400);
+	one_clock_write(address & 0x0200);
+	one_clock_write(address & 0x0100);
+	one_clock_write(address & 0x0080);
+	one_clock_write(address & 0x0040);
+	one_clock_write(address & 0x0020);
+	one_clock_write(address & 0x0010);
+	one_clock_write(address & 0x0008);
+	one_clock_write(address & 0x0004);
+	one_clock_write(address & 0x0002);
+	one_clock_write(address & 0x0001);
+	one_clock_write_RWbit(0);
+	if (h2w_ack() < 0) {
+		H2W_DBG("Addr NO ACK(%d).\n", retry_times);
+		retry_times++;
+		hi->set_clk(0);
+		mdelay(RESEND_DELAY);
+		goto write_resend;
+	}
+
+	/* Write data */
+	hi->set_dat_dir(1);
+	one_clock_write(data & 0x0080);
+	one_clock_write(data & 0x0040);
+	one_clock_write(data & 0x0020);
+	one_clock_write(data & 0x0010);
+	one_clock_write(data & 0x0008);
+	one_clock_write(data & 0x0004);
+	one_clock_write(data & 0x0002);
+	one_clock_write_RWbit(data & 0x0001);
+	if (h2w_ack() < 0) {
+		H2W_DBG("Data NO ACK(%d).\n", retry_times);
+		retry_times++;
+		hi->set_clk(0);
+		mdelay(RESEND_DELAY);
+		goto write_resend;
+	}
+	ret = 0;
+
+err_write:
+	if (ret < 0)
+		H2WE("NO ACK.\n");
+
+	return ret;
+}
+
+static int h2w_get_fnkey(void)
+{
+	int ret;
+	h2w_begin_command();
+	ret = h2w_readc_cmd(H2W_FNKEY_UPDOWN);
+	h2w_end_command();
+	return ret;
+}
+
+static int h2w_dev_init(H2W_INFO *ph2w_info)
+{
+	int ret = -1;
+	unsigned char ascr0 = 0;
+	int h2w_sys = 0, maxgpadd = 0, maxadd = 0, key = 0;
+
+	hi->speed = H2W_50KHz;
+	h2w_begin_command();
+
+	/* read H2W_SYSTEM */
+	h2w_sys = h2w_readc_cmd(H2W_SYSTEM);
+	if (h2w_sys == -1) {
+		H2WE("read H2W_SYSTEM(0x0000) failed.\n");
+		goto err_plugin;
+	}
+	ph2w_info->ACC_CLASS = (h2w_sys & 0x03);
+	ph2w_info->AUDIO_DEVICE  = (h2w_sys & 0x04) > 0 ? 1 : 0;
+	ph2w_info->HW_REV = (h2w_sys & 0x18) >> 3;
+	ph2w_info->SLEEP_PR  = (h2w_sys & 0x20) >> 5;
+	ph2w_info->CLK_SP = (h2w_sys & 0xC0) >> 6;
+
+	/* enter init mode */
+	if (h2w_writec_cmd(H2W_ASCR0, H2W_ASCR_DEVICE_INI) < 0) {
+		H2WE("write H2W_ASCR0(0x0002) failed.\n");
+		goto err_plugin;
+	}
+	udelay(10);
+
+	/* read H2W_MAX_GP_ADD */
+	maxgpadd = h2w_readc_cmd(H2W_MAX_GP_ADD);
+	if (maxgpadd == -1) {
+		H2WE("write H2W_MAX_GP_ADD(0x0001) failed.\n");
+		goto err_plugin;
+	}
+	ph2w_info->CLK_SP += (maxgpadd & 0x60) >> 3;
+	ph2w_info->MAX_GP_ADD = (maxgpadd & 0x1F);
+
+	/* read key group */
+	if (ph2w_info->MAX_GP_ADD >= 1) {
+		ph2w_info->KEY_MAXADD = h2w_readc_cmd(H2W_KEY_MAXADD);
+		if (ph2w_info->KEY_MAXADD == -1)
+			goto err_plugin;
+		if (ph2w_info->KEY_MAXADD >= 1) {
+			key = h2w_readc_cmd(H2W_ASCII_DOWN);
+			if (key < 0)
+				goto err_plugin;
+			ph2w_info->ASCII_DOWN = (key == 0xFF) ? 1 : 0;
+		}
+		if (ph2w_info->KEY_MAXADD >= 2) {
+			key = h2w_readc_cmd(H2W_ASCII_UP);
+			if (key == -1)
+				goto err_plugin;
+			ph2w_info->ASCII_UP = (key == 0xFF) ? 1 : 0;
+		}
+		if (ph2w_info->KEY_MAXADD >= 3) {
+			key = h2w_readc_cmd(H2W_FNKEY_UPDOWN);
+			if (key == -1)
+				goto err_plugin;
+			ph2w_info->FNKEY_UPDOWN = (key == 0xFF) ? 1 : 0;
+		}
+		if (ph2w_info->KEY_MAXADD >= 4) {
+			key = h2w_readc_cmd(H2W_KD_STATUS);
+			if (key == -1)
+				goto err_plugin;
+			ph2w_info->KD_STATUS = (key == 0x01) ? 1 : 0;
+		}
+	}
+
+	/* read led group */
+	if (ph2w_info->MAX_GP_ADD >= 2) {
+		ph2w_info->LED_MAXADD = h2w_readc_cmd(H2W_LED_MAXADD);
+		if (ph2w_info->LED_MAXADD == -1)
+			goto err_plugin;
+		if (ph2w_info->LED_MAXADD >= 1) {
+			key = h2w_readc_cmd(H2W_LEDCT0);
+			if (key == -1)
+				goto err_plugin;
+			ph2w_info->LEDCT0 = (key == 0x02) ? 1 : 0;
+		}
+	}
+
+	/* read group 3, 4, 5 */
+	if (ph2w_info->MAX_GP_ADD >= 3) {
+		maxadd = h2w_readc_cmd(H2W_CRDL_MAXADD);
+		if (maxadd == -1)
+			goto err_plugin;
+	}
+	if (ph2w_info->MAX_GP_ADD >= 4) {
+		maxadd = h2w_readc_cmd(H2W_CARKIT_MAXADD);
+		if (maxadd == -1)
+			goto err_plugin;
+	}
+	if (ph2w_info->MAX_GP_ADD >= 5) {
+		maxadd = h2w_readc_cmd(H2W_USBHOST_MAXADD);
+		if (maxadd == -1)
+			goto err_plugin;
+	}
+
+	/* read medical group */
+	if (ph2w_info->MAX_GP_ADD >= 6) {
+		ph2w_info->MED_MAXADD = h2w_readc_cmd(H2W_MED_MAXADD);
+		if (ph2w_info->MED_MAXADD == -1)
+			goto err_plugin;
+		if (ph2w_info->MED_MAXADD >= 1) {
+			key = h2w_readc_cmd(H2W_MED_CONTROL);
+			if (key == -1)
+				goto err_plugin;
+		ph2w_info->DATA_EN = (key & 0x01);
+		ph2w_info->AP_EN = (key & 0x02) >> 1;
+		ph2w_info->AP_ID = (key & 0x1c) >> 2;
+		}
+		if (ph2w_info->MED_MAXADD >= 2) {
+			key = h2w_readc_cmd(H2W_MED_IN_DATA);
+			if (key == -1)
+				goto err_plugin;
+		}
+	}
+
+	if (ph2w_info->AUDIO_DEVICE)
+		ascr0 = H2W_ASCR_AUDIO_IN | H2W_ASCR_ACT_EN;
+	else
+		ascr0 = H2W_ASCR_ACT_EN;
+
+	if (h2w_writec_cmd(H2W_ASCR0, ascr0) < 0)
+		goto err_plugin;
+	udelay(10);
+
+	ret = 0;
+
+	/* adjust speed */
+	if (ph2w_info->MAX_GP_ADD == 2) {
+		/* Remote control */
+		hi->speed = H2W_250KHz;
+	} else if (ph2w_info->MAX_GP_ADD == 6) {
+		if (ph2w_info->MED_MAXADD >= 1) {
+			key = h2w_readc_cmd(H2W_MED_CONTROL);
+			if (key == -1)
+				goto err_plugin;
+			ph2w_info->DATA_EN   = (key & 0x01);
+			ph2w_info->AP_EN = (key & 0x02) >> 1;
+			ph2w_info->AP_ID = (key & 0x1c) >> 2;
+		}
+	}
+
+err_plugin:
+	h2w_end_command();
+
+	return ret;
+}
+
+static inline void h2w_dev_power_on(int on)
+{
+	if (!hi->vreg_h2w)
+		return;
+
+	if (on)
+		vreg_enable(hi->vreg_h2w);
+	else
+		vreg_disable(hi->vreg_h2w);
+}
+
+static int h2w_dev_detect(void)
+{
+	int ret = -1;
+	int retry_times;
+
+	for (retry_times = 5; retry_times; retry_times--) {
+		/* Enable H2W Power */
+		h2w_dev_power_on(1);
+		msleep(100);
+		memset(&hi->h2w_info, 0, sizeof(H2W_INFO));
+		if (h2w_dev_init(&hi->h2w_info) < 0) {
+			h2w_dev_power_on(0);
+			msleep(100);
+		} else if (hi->h2w_info.MAX_GP_ADD == 2) {
+			ret = 0;
+			break;
+		} else {
+			printk(KERN_INFO "h2w_detect: detect error(%d)\n"
+				, hi->h2w_info.MAX_GP_ADD);
+			h2w_dev_power_on(0);
+			msleep(100);
+		}
+		printk(KERN_INFO "h2w_detect(%d)\n"
+				, hi->h2w_info.MAX_GP_ADD);
+	}
+	H2W_DBG("h2w_detect:(%d)\n", retry_times);
+	return ret;
+}
+
+static void remove_headset(void)
+{
+	unsigned long irq_flags;
+
+	H2W_DBG("");
+
+	mutex_lock(&hi->mutex_lock);
+	switch_set_state(&hi->sdev, switch_get_state(&hi->sdev) &
+			~(BIT_HEADSET | BIT_HEADSET_NO_MIC));
+	mutex_unlock(&hi->mutex_lock);
+	hi->init_cpld();
+
+	/* Disable button */
+	switch (hi->htc_headset_flag) {
+	case H2W_HTC_HEADSET:
+		local_irq_save(irq_flags);
+		disable_irq(hi->irq_btn);
+		local_irq_restore(irq_flags);
+
+		if (atomic_read(&hi->btn_state))
+			button_released();
+		break;
+	case H2W_DEVICE:
+		h2w_dev_power_on(0);
+		set_irq_type(hi->irq_btn, IRQF_TRIGGER_LOW);
+		disable_irq(hi->irq_btn);
+		/* 10ms (5-15 with 10ms tick) */
+		hi->btn_debounce_time = ktime_set(0, 10000000);
+		hi->set_clk_dir(0);
+		hi->set_dat_dir(0);
+		break;
+	}
+
+	hi->htc_headset_flag = 0;
+	hi->debounce_time = ktime_set(0, 100000000);  /* 100 ms */
+
+}
+
+#ifdef CONFIG_MSM_SERIAL_DEBUGGER
+extern void msm_serial_debug_enable(int);
+#endif
+
+static void insert_headset(int type)
+{
+	unsigned long irq_flags;
+	int state;
+
+	H2W_DBG("");
+
+	hi->htc_headset_flag = type;
+	state = BIT_HEADSET | BIT_HEADSET_NO_MIC;
+
+	state = switch_get_state(&hi->sdev);
+	state &= ~(BIT_HEADSET_NO_MIC | BIT_HEADSET);
+	switch (type) {
+	case H2W_HTC_HEADSET:
+		printk(KERN_INFO "insert_headset H2W_HTC_HEADSET\n");
+		state |= BIT_HEADSET;
+		hi->ignore_btn = !gpio_get_value(hi->cable_in2);
+		/* Enable button irq */
+		local_irq_save(irq_flags);
+		enable_irq(hi->irq_btn);
+		local_irq_restore(irq_flags);
+		hi->debounce_time = ktime_set(0, 200000000); /* 20 ms */
+		break;
+	case H2W_DEVICE:
+		if (h2w_dev_detect() < 0) {
+			printk(KERN_INFO "H2W_DEVICE -- Non detect\n");
+			remove_headset();
+		} else {
+			printk(KERN_INFO "H2W_DEVICE -- detect\n");
+			hi->btn_debounce_time = ktime_set(0, 0);
+			local_irq_save(irq_flags);
+			enable_irq(hi->irq_btn);
+			set_irq_type(hi->irq_btn, IRQF_TRIGGER_RISING);
+			local_irq_restore(irq_flags);
+			state |= BIT_HEADSET;
+		}
+		break;
+	case H2W_USB_CRADLE:
+		state |= BIT_HEADSET_NO_MIC;
+		break;
+	case H2W_UART_DEBUG:
+		hi->config_cpld(hi->debug_uart);
+		printk(KERN_INFO "switch to H2W_UART_DEBUG\n");
+	default:
+		return;
+	}
+	mutex_lock(&hi->mutex_lock);
+	switch_set_state(&hi->sdev, state);
+	mutex_unlock(&hi->mutex_lock);
+
+#ifdef CONFIG_MSM_SERIAL_DEBUGGER
+	msm_serial_debug_enable(false);
+#endif
+
+}
+#if 0
+static void remove_headset(void)
+{
+	unsigned long irq_flags;
+
+	H2W_DBG("");
+
+	switch_set_state(&hi->sdev, H2W_NO_DEVICE);
+
+	hi->init_cpld();
+
+	/* Disable button */
+	local_irq_save(irq_flags);
+	disable_irq(hi->irq_btn);
+	local_irq_restore(irq_flags);
+
+	if (atomic_read(&hi->btn_state))
+		button_released();
+
+	hi->debounce_time = ktime_set(0, 100000000);  /* 100 ms */
+}
+#endif
+static int is_accessary_pluged_in(void)
+{
+	int type = 0;
+	int clk1 = 0, dat1 = 0, clk2 = 0, dat2 = 0, clk3 = 0, dat3 = 0;
+
+	/* Step1: save H2W_CLK and H2W_DAT */
+	/* Delay 10ms for pin stable. */
+	msleep(10);
+	clk1 = gpio_get_value(hi->h2w_clk);
+	dat1 = gpio_get_value(hi->h2w_data);
+
+	/*
+	 * Step2: set GPIO_CABLE_IN1 as output high and GPIO_CABLE_IN2 as
+	 * input
+	 */
+	gpio_direction_output(hi->cable_in1, 1);
+	gpio_direction_input(hi->cable_in2);
+	/* Delay 10ms for pin stable. */
+	msleep(10);
+	/* Step 3: save H2W_CLK and H2W_DAT */
+	clk2 = gpio_get_value(hi->h2w_clk);
+	dat2 = gpio_get_value(hi->h2w_data);
+
+	/*
+	 * Step 4: set GPIO_CABLE_IN1 as input and GPIO_CABLE_IN2 as output
+	 * high
+	 */
+	gpio_direction_input(hi->cable_in1);
+	gpio_direction_output(hi->cable_in2, 1);
+	/* Delay 10ms for pin stable. */
+	msleep(10);
+	/* Step 5: save H2W_CLK and H2W_DAT */
+	clk3 = gpio_get_value(hi->h2w_clk);
+	dat3 = gpio_get_value(hi->h2w_data);
+
+	/* Step 6: set both GPIO_CABLE_IN1 and GPIO_CABLE_IN2 as input */
+	gpio_direction_input(hi->cable_in1);
+	gpio_direction_input(hi->cable_in2);
+
+	H2W_DBG("(%d,%d) (%d,%d) (%d,%d)\n",
+		clk1, dat1, clk2, dat2, clk3, dat3);
+
+	if ((clk1 == 0) && (dat1 == 1) &&
+	    (clk2 == 0) && (dat2 == 1) &&
+	    (clk3 == 0) && (dat3 == 1))
+		type = H2W_HTC_HEADSET;
+	else if ((clk1 == 0) && (dat1 == 0) &&
+		 (clk2 == 0) && (dat2 == 0) &&
+		 (clk3 == 0) &&  (dat3 == 0))
+		type = NORMAL_HEARPHONE;
+	else if ((clk1 == 0) && (dat1 == 0) &&
+		 (clk2 == 1) && (dat2 == 0) &&
+		 (clk3 == 0) && (dat3 == 1))
+		type = H2W_DEVICE;
+	else if ((clk1 == 0) && (dat1 == 0) &&
+		 (clk2 == 1) && (dat2 == 1) &&
+		 (clk3 == 1) && (dat3 == 1))
+		type = H2W_USB_CRADLE;
+	else if ((clk1 == 0) && (dat1 == 1) &&
+		 (clk2 == 1) && (dat2 == 1) &&
+		 (clk3 == 0) && (dat3 == 1))
+		type = H2W_UART_DEBUG;
+	else
+		type = H2W_NO_DEVICE;
+
+	return type;
+}
+
+
+static void detection_work(struct work_struct *work)
+{
+	unsigned long irq_flags;
+	int type;
+
+	H2W_DBG("");
+
+	if (gpio_get_value(hi->cable_in1) != 0) {
+		/* Headset not plugged in */
+		if (switch_get_state(&hi->sdev) != H2W_NO_DEVICE)
+			remove_headset();
+		return;
+	}
+
+	/* Something plugged in, lets make sure its a headset */
+
+	/* Switch CPLD to GPIO to do detection */
+	hi->config_cpld(H2W_GPIO);
+
+	/* Disable headset interrupt while detecting.*/
+	local_irq_save(irq_flags);
+	disable_irq(hi->irq);
+	local_irq_restore(irq_flags);
+
+	/* Something plugged in, lets make sure its a headset */
+	type = is_accessary_pluged_in();
+
+	/* Restore IRQs */
+	local_irq_save(irq_flags);
+	enable_irq(hi->irq);
+	local_irq_restore(irq_flags);
+
+	insert_headset(type);
+}
+
+static enum hrtimer_restart button_event_timer_func(struct hrtimer *data)
+{
+	int key, press, keyname, h2w_key = 1;
+
+	H2W_DBG("");
+
+	if (switch_get_state(&hi->sdev) == H2W_HTC_HEADSET) {
+		switch (hi->htc_headset_flag) {
+		case H2W_HTC_HEADSET:
+			if (gpio_get_value(hi->cable_in2)) {
+				if (hi->ignore_btn)
+					hi->ignore_btn = 0;
+				else if (atomic_read(&hi->btn_state))
+					button_released();
+			} else {
+				if (!hi->ignore_btn &&
+				    !atomic_read(&hi->btn_state))
+					button_pressed();
+			}
+			break;
+		case H2W_DEVICE:
+			if ((hi->get_dat() == 1) && (hi->get_clk() == 1)) {
+				/* Don't do anything because H2W pull out. */
+				H2WE("Remote Control pull out.\n");
+			} else {
+				key = h2w_get_fnkey();
+				press = (key > 0x7F) ? 0 : 1;
+				keyname = key & 0x7F;
+				 /* H2WI("key = %d, press = %d,
+					 keyname = %d \n",
+					 key, press, keyname); */
+				switch (keyname) {
+				case H2W_KEY_PLAY:
+					H2WI("H2W_KEY_PLAY");
+					key = KEY_PLAYPAUSE;
+					break;
+				case H2W_KEY_FORWARD:
+					H2WI("H2W_KEY_FORWARD");
+					key = KEY_NEXTSONG;
+					break;
+				case H2W_KEY_BACKWARD:
+					H2WI("H2W_KEY_BACKWARD");
+					key = KEY_PREVIOUSSONG;
+					break;
+				case H2W_KEY_VOLUP:
+					H2WI("H2W_KEY_VOLUP");
+					key = KEY_VOLUMEUP;
+					break;
+				case H2W_KEY_VOLDOWN:
+					H2WI("H2W_KEY_VOLDOWN");
+					key = KEY_VOLUMEDOWN;
+					break;
+				case H2W_KEY_PICKUP:
+					H2WI("H2W_KEY_PICKUP");
+					key = KEY_SEND;
+					break;
+				case H2W_KEY_HANGUP:
+					H2WI("H2W_KEY_HANGUP");
+					key = KEY_END;
+					break;
+				case H2W_KEY_MUTE:
+					H2WI("H2W_KEY_MUTE");
+					key = KEY_MUTE;
+					break;
+				case H2W_KEY_HOLD:
+					H2WI("H2W_KEY_HOLD");
+					break;
+				default:
+				H2WI("default");
+					h2w_key = 0;
+				}
+				if (h2w_key) {
+					if (press)
+						H2WI("Press\n");
+					else
+						H2WI("Release\n");
+					input_report_key(hi->input, key, press);
+				}
+			}
+			break;
+		} /* end switch */
+	}
+
+	return HRTIMER_NORESTART;
+}
+
+static enum hrtimer_restart detect_event_timer_func(struct hrtimer *data)
+{
+	H2W_DBG("");
+
+	queue_work(g_detection_work_queue, &g_detection_work);
+	return HRTIMER_NORESTART;
+}
+
+static irqreturn_t detect_irq_handler(int irq, void *dev_id)
+{
+	int value1, value2;
+	int retry_limit = 10;
+
+	H2W_DBG("");
+	set_irq_type(hi->irq_btn, IRQF_TRIGGER_LOW);
+	do {
+		value1 = gpio_get_value(hi->cable_in1);
+		set_irq_type(hi->irq, value1 ?
+				IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH);
+		value2 = gpio_get_value(hi->cable_in1);
+	} while (value1 != value2 && retry_limit-- > 0);
+
+	H2W_DBG("value2 = %d (%d retries), device=%d",
+		value2, (10-retry_limit), switch_get_state(&hi->sdev));
+
+	if ((switch_get_state(&hi->sdev) == H2W_NO_DEVICE) ^ value2) {
+		if (switch_get_state(&hi->sdev) == H2W_HTC_HEADSET)
+			hi->ignore_btn = 1;
+		/* Do the rest of the work in timer context */
+		hrtimer_start(&hi->timer, hi->debounce_time, HRTIMER_MODE_REL);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t button_irq_handler(int irq, void *dev_id)
+{
+	int value1, value2;
+	int retry_limit = 10;
+
+	H2W_DBG("");
+	do {
+		value1 = gpio_get_value(hi->cable_in2);
+		if (hi->htc_headset_flag != H2W_DEVICE)
+		set_irq_type(hi->irq_btn, value1 ?
+				IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH);
+		value2 = gpio_get_value(hi->cable_in2);
+	} while (value1 != value2 && retry_limit-- > 0);
+
+	H2W_DBG("value2 = %d (%d retries)", value2, (10-retry_limit));
+
+	hrtimer_start(&hi->btn_timer, hi->btn_debounce_time, HRTIMER_MODE_REL);
+
+	return IRQ_HANDLED;
+}
+
+#if defined(CONFIG_DEBUG_FS)
+static int h2w_debug_set(void *data, u64 val)
+{
+	mutex_lock(&hi->mutex_lock);
+	switch_set_state(&hi->sdev, (int)val);
+	mutex_unlock(&hi->mutex_lock);
+	return 0;
+}
+
+static int h2w_debug_get(void *data, u64 *val)
+{
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(h2w_debug_fops, h2w_debug_get, h2w_debug_set, "%llu\n");
+static int __init h2w_debug_init(void)
+{
+	struct dentry *dent;
+
+	dent = debugfs_create_dir("h2w", 0);
+	if (IS_ERR(dent))
+		return PTR_ERR(dent);
+
+	debugfs_create_file("state", 0644, dent, NULL, &h2w_debug_fops);
+
+	return 0;
+}
+
+device_initcall(h2w_debug_init);
+#endif
+
+static int h2w_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct h2w_platform_data *pdata = pdev->dev.platform_data;
+
+	printk(KERN_INFO "H2W: Registering H2W (headset) driver\n");
+	hi = kzalloc(sizeof(struct h2w_info), GFP_KERNEL);
+	if (!hi)
+		return -ENOMEM;
+
+	atomic_set(&hi->btn_state, 0);
+	hi->ignore_btn = 0;
+
+	hi->debounce_time = ktime_set(0, 100000000);  /* 100 ms */
+	hi->btn_debounce_time = ktime_set(0, 10000000); /* 10 ms */
+
+	hi->htc_headset_flag = 0;
+	hi->cable_in1 = pdata->cable_in1;
+	hi->cable_in2 = pdata->cable_in2;
+	hi->h2w_clk = pdata->h2w_clk;
+	hi->h2w_data = pdata->h2w_data;
+	hi->debug_uart = pdata->debug_uart;
+	hi->config_cpld = pdata->config_cpld;
+	hi->init_cpld = pdata->init_cpld;
+	hi->set_dat = pdata->set_dat;
+	hi->set_clk = pdata->set_clk;
+	hi->set_dat_dir	= pdata->set_dat_dir;
+	hi->set_clk_dir	= pdata->set_clk_dir;
+	hi->get_dat = pdata->get_dat;
+	hi->get_clk = pdata->get_clk;
+	hi->speed = H2W_50KHz;
+	/* obtain needed VREGs */
+	if (pdata->power_name)
+		hi->vreg_h2w = vreg_get(0, pdata->power_name);
+
+	mutex_init(&hi->mutex_lock);
+
+	hi->sdev.name = "h2w";
+	hi->sdev.print_name = h2w_print_name;
+
+	ret = switch_dev_register(&hi->sdev);
+	if (ret < 0)
+		goto err_switch_dev_register;
+
+	g_detection_work_queue = create_workqueue("detection");
+	if (g_detection_work_queue == NULL) {
+		ret = -ENOMEM;
+		goto err_create_work_queue;
+	}
+
+	ret = gpio_request(hi->cable_in1, "h2w_detect");
+	if (ret < 0)
+		goto err_request_detect_gpio;
+
+	ret = gpio_request(hi->cable_in2, "h2w_button");
+	if (ret < 0)
+		goto err_request_button_gpio;
+
+	ret = gpio_direction_input(hi->cable_in1);
+	if (ret < 0)
+		goto err_set_detect_gpio;
+
+	ret = gpio_direction_input(hi->cable_in2);
+	if (ret < 0)
+		goto err_set_button_gpio;
+
+	hi->irq = gpio_to_irq(hi->cable_in1);
+	if (hi->irq < 0) {
+		ret = hi->irq;
+		goto err_get_h2w_detect_irq_num_failed;
+	}
+
+	hi->irq_btn = gpio_to_irq(hi->cable_in2);
+	if (hi->irq_btn < 0) {
+		ret = hi->irq_btn;
+		goto err_get_button_irq_num_failed;
+	}
+
+	/* Set CPLD MUX to H2W <-> CPLD GPIO */
+	hi->init_cpld();
+
+	hrtimer_init(&hi->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	hi->timer.function = detect_event_timer_func;
+	hrtimer_init(&hi->btn_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	hi->btn_timer.function = button_event_timer_func;
+
+	ret = request_irq(hi->irq, detect_irq_handler,
+			  IRQF_TRIGGER_LOW, "h2w_detect", NULL);
+	if (ret < 0)
+		goto err_request_detect_irq;
+
+	/* Disable button until plugged in */
+	set_irq_flags(hi->irq_btn, IRQF_VALID | IRQF_NOAUTOEN);
+	ret = request_irq(hi->irq_btn, button_irq_handler,
+			  IRQF_TRIGGER_LOW, "h2w_button", NULL);
+	if (ret < 0)
+		goto err_request_h2w_headset_button_irq;
+
+	ret = set_irq_wake(hi->irq, 1);
+	if (ret < 0)
+		goto err_request_input_dev;
+
+	ret = set_irq_wake(hi->irq_btn, 1);
+	if (ret < 0)
+		goto err_request_input_dev;
+
+
+
+	hi->input = input_allocate_device();
+	if (!hi->input) {
+		ret = -ENOMEM;
+		goto err_request_input_dev;
+	}
+
+	hi->input->name = "h2w headset";
+	set_bit(EV_SYN, hi->input->evbit);
+	set_bit(EV_KEY, hi->input->evbit);
+	set_bit(KEY_MEDIA, hi->input->keybit);
+	set_bit(KEY_NEXTSONG, hi->input->keybit);
+	set_bit(KEY_PLAYPAUSE, hi->input->keybit);
+	set_bit(KEY_PREVIOUSSONG, hi->input->keybit);
+	set_bit(KEY_MUTE, hi->input->keybit);
+	set_bit(KEY_VOLUMEUP, hi->input->keybit);
+	set_bit(KEY_VOLUMEDOWN, hi->input->keybit);
+	set_bit(KEY_END, hi->input->keybit);
+	set_bit(KEY_SEND, hi->input->keybit);
+
+	ret = input_register_device(hi->input);
+	if (ret < 0)
+		goto err_register_input_dev;
+
+	return 0;
+
+err_register_input_dev:
+	input_free_device(hi->input);
+err_request_input_dev:
+	free_irq(hi->irq_btn, 0);
+err_request_h2w_headset_button_irq:
+	free_irq(hi->irq, 0);
+err_request_detect_irq:
+err_get_button_irq_num_failed:
+err_get_h2w_detect_irq_num_failed:
+err_set_button_gpio:
+err_set_detect_gpio:
+	gpio_free(hi->cable_in2);
+err_request_button_gpio:
+	gpio_free(hi->cable_in1);
+err_request_detect_gpio:
+	destroy_workqueue(g_detection_work_queue);
+err_create_work_queue:
+	switch_dev_unregister(&hi->sdev);
+err_switch_dev_register:
+	printk(KERN_ERR "H2W: Failed to register driver\n");
+
+	return ret;
+}
+
+static int h2w_remove(struct platform_device *pdev)
+{
+	H2W_DBG("");
+	if (switch_get_state(&hi->sdev))
+		remove_headset();
+	input_unregister_device(hi->input);
+	gpio_free(hi->cable_in2);
+	gpio_free(hi->cable_in1);
+	free_irq(hi->irq_btn, 0);
+	free_irq(hi->irq, 0);
+	destroy_workqueue(g_detection_work_queue);
+	switch_dev_unregister(&hi->sdev);
+
+	return 0;
+}
+
+
+static struct platform_driver h2w_driver = {
+	.probe		= h2w_probe,
+	.remove		= h2w_remove,
+	.driver		= {
+		.name		= "h2w",
+		.owner		= THIS_MODULE,
+	},
+};
+
+static int __init h2w_init(void)
+{
+	H2W_DBG("");
+	return platform_driver_register(&h2w_driver);
+}
+
+static void __exit h2w_exit(void)
+{
+	platform_driver_unregister(&h2w_driver);
+}
+
+module_init(h2w_init);
+module_exit(h2w_exit);
+
+MODULE_AUTHOR("Laurence Chen <Laurence_Chen@htc.com>");
+MODULE_DESCRIPTION("HTC 2 Wire detection driver");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/htc_power_supply.c b/arch/arm/mach-msm/htc_power_supply.c
new file mode 100644
index 0000000..bd286c9
--- /dev/null
+++ b/arch/arm/mach-msm/htc_power_supply.c
@@ -0,0 +1,616 @@
+/* arch/arm/mach-msm/htc_battery.c
+ *
+ * Copyright (C) 2008 HTC Corporation.
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/power_supply.h>
+#include <linux/platform_device.h>
+#include <mach/msm_fast_timer.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/board.h>
+
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/switch.h>
+
+#include "board-mahimahi.h"
+
+extern void notify_usb_connected(int);
+
+static char *supply_list[] = {
+	"battery",
+};
+
+static struct switch_dev dock_switch = {
+	.name = "dock",
+};
+
+static int vbus_present;
+static int usb_status;
+static bool dock_mains;
+
+struct dock_state {
+	struct mutex lock;
+	u32 t;
+	u32 last_edge_t[2];
+	u32 last_edge_i[2];
+	bool level;
+	bool dock_connected_unknown;
+};
+
+static struct workqueue_struct *dock_wq;
+static struct work_struct dock_work;
+static struct wake_lock dock_work_wake_lock;
+static struct dock_state ds = {
+	.lock = __MUTEX_INITIALIZER(ds.lock),
+};
+
+#define _GPIO_DOCK MAHIMAHI_GPIO_DOCK
+
+#define dock_out(n) gpio_direction_output(_GPIO_DOCK, n)
+#define dock_out2(n) gpio_set_value(_GPIO_DOCK, n)
+#define dock_in() gpio_direction_input(_GPIO_DOCK)
+#define dock_read() gpio_get_value(_GPIO_DOCK)
+
+#define MFM_DELAY_NS 10000
+
+static int dock_get_edge(struct dock_state *s, u32 timeout, u32 tmin, u32 tmax)
+{
+	bool lin;
+	bool in = s->level;
+	u32 t;
+	do {
+		lin = in;
+		in = dock_read();
+		t = msm_read_fast_timer();
+		if (in != lin) {
+			s->last_edge_t[in] = t;
+			s->last_edge_i[in] = 0;
+			s->level = in;
+			if ((s32)(t - tmin) < 0 || (s32)(t - tmax) > 0)
+				return -1;
+			return 1;
+		}
+	} while((s32)(t - timeout) < 0);
+	return 0;
+}
+
+static bool dock_sync(struct dock_state *s, u32 timeout)
+{
+	u32 t;
+
+	s->level = dock_read();
+	t = msm_read_fast_timer();
+
+	if (!dock_get_edge(s, t + timeout, 0, 0))
+		return false;
+	s->last_edge_i[s->level] = 2;
+	return !!dock_get_edge(s,
+			s->last_edge_t[s->level] + MFM_DELAY_NS * 4, 0, 0);
+}
+
+static int dock_get_next_bit(struct dock_state *s)
+{
+	u32 i = s->last_edge_i[!s->level] + ++s->last_edge_i[s->level];
+	u32 target = s->last_edge_t[!s->level] + MFM_DELAY_NS * i;
+	u32 timeout = target + MFM_DELAY_NS / 2;
+	u32 tmin = target - MFM_DELAY_NS / 4;
+	u32 tmax = target + MFM_DELAY_NS / 4;
+	return dock_get_edge(s, timeout, tmin, tmax);
+}
+
+static u32 dock_get_bits(struct dock_state *s, int count, int *errp)
+{
+	u32 data = 0;
+	u32 m = 1;
+	int ret;
+	int err = 0;
+	while (count--) {
+		ret = dock_get_next_bit(s);
+		if (ret)
+			data |= m;
+		if (ret < 0)
+			err++;
+		m <<= 1;
+	}
+	if (errp)
+		*errp = err;
+	return data;
+}
+
+static void dock_delay(u32 timeout)
+{
+	timeout += msm_read_fast_timer();
+	while (((s32)(msm_read_fast_timer() - timeout)) < 0)
+		;
+}
+
+static int dock_send_bits(struct dock_state *s, u32 data, int count, int period)
+{
+	u32 t, t0, to;
+
+	dock_out2(s->level);
+	t = to = 0;
+	t0 = msm_read_fast_timer();
+
+	while (count--) {
+		if (data & 1)
+			dock_out2((s->level = !s->level));
+
+		t = msm_read_fast_timer() - t0;
+		if (t - to > period / 2) {
+			pr_info("dock: to = %d, t = %d\n", to, t);
+			return -EIO;
+		}
+
+		to += MFM_DELAY_NS;
+		do {
+			t = msm_read_fast_timer() - t0;
+		} while (t < to);
+		if (t - to > period / 4) {
+			pr_info("dock: to = %d, t = %d\n", to, t);
+			return -EIO;
+		}
+		data >>= 1;
+	}
+	return 0;
+}
+
+static u32 mfm_encode(u16 data, int count, bool p)
+{
+	u32 mask;
+	u32 mfm = 0;
+	u32 clock = ~data & ~(data << 1 | !!p);
+	for (mask = 1UL << (count - 1); mask; mask >>= 1) {
+		mfm |= (data & mask);
+		mfm <<= 1;
+		mfm |= (clock & mask);
+	}
+	return mfm;
+}
+
+static u32 mfm_decode(u32 mfm)
+{
+	u32 data = 0;
+	u32 clock = 0;
+	u32 mask = 1;
+	while (mfm) {
+		if (mfm & 1)
+			clock |= mask;
+		mfm >>= 1;
+		if (mfm & 1)
+			data |= mask;
+		mfm >>= 1;
+		mask <<= 1;
+	}
+	return data;
+}
+
+static int dock_command(struct dock_state *s, u16 cmd, int len, int retlen)
+{
+	u32 mfm;
+	int count;
+	u32 data = cmd;
+	int ret;
+	int err = -1;
+	unsigned long flags;
+
+	data = data << 2 | 3; /* add 0101 mfm data*/
+	mfm = mfm_encode(data, len, false);
+	count = len * 2 + 2;
+
+	msm_enable_fast_timer();
+	local_irq_save(flags);
+	ret = dock_send_bits(s, mfm, count, MFM_DELAY_NS);
+	if (!ret) {
+		dock_in();
+		if (dock_sync(s, MFM_DELAY_NS * 5))
+			ret = dock_get_bits(s, retlen * 2, &err);
+		else
+			ret = -1;
+		dock_out(s->level);
+	}
+	local_irq_restore(flags);
+
+	dock_delay((ret < 0) ? MFM_DELAY_NS * 6 : MFM_DELAY_NS * 2);
+	msm_disable_fast_timer();
+	if (ret < 0) {
+		pr_warning("dock_command: %x: no response\n", cmd);
+		return ret;
+	}
+	data = mfm_decode(ret);
+	mfm = mfm_encode(data, retlen, true);
+	if (mfm != ret || err) {
+		pr_warning("dock_command: %x: bad response, "
+			   "data %x, mfm %x %x, err %d\n",
+			   cmd, data, mfm, ret, err);
+		return -EIO;
+	}
+	return data;
+}
+
+static int dock_command_retry(struct dock_state *s, u16 cmd, size_t len, size_t retlen)
+{
+	int retry = 20;
+	int ret;
+	while (retry--) {
+		ret = dock_command(s, cmd, len, retlen);
+		if (ret >= 0)
+			return ret;
+		if (retry != 19)
+			msleep(10);
+	}
+	s->dock_connected_unknown = true;
+	return -EIO;
+}
+
+static int dock_read_single(struct dock_state *s, int addr)
+{
+	int ret = -1, last;
+	int retry = 20;
+	while (retry--) {
+		last = ret;
+		ret = dock_command_retry(s, addr << 1, 6, 8);
+		if (ret < 0 || ret == last)
+			return ret;
+	}
+	return -EIO;
+}
+
+static int dock_read_multi(struct dock_state *s, int addr, u8 *data, size_t len)
+{
+	int ret;
+	int i;
+	u8 suml, sumr = -1;
+	int retry = 20;
+	while (retry--) {
+		suml = 0;
+		for (i = 0; i <= len; i++) {
+			ret = dock_command_retry(s, (addr + i) << 1, 6, 8);
+			if (ret < 0)
+				return ret;
+			if (i < len) {
+				data[i] = ret;
+				suml += ret;
+			} else
+				sumr = ret;
+		}
+		if (sumr == suml)
+			return 0;
+
+		pr_warning("dock_read_multi(%x): bad checksum, %x != %x\n",
+			   addr, sumr, suml);
+	}
+	return -EIO;
+}
+
+static int dock_write_byte(struct dock_state *s, int addr, u8 data)
+{
+	return dock_command_retry(s, 1 | addr << 1 | data << 4, 6 + 8, 1);
+}
+
+static int dock_write_multi(struct dock_state *s, int addr, u8 *data, size_t len)
+{
+	int ret;
+	int i;
+	u8 sum;
+	int retry = 2;
+	while (retry--) {
+		sum = 0;
+		for (i = 0; i < len; i++) {
+			sum += data[i];
+			ret = dock_write_byte(s, addr + i, data[i]);
+			if (ret < 0)
+				return ret;
+		}
+		ret = dock_write_byte(s, addr + len, sum);
+		if (ret <= 0)
+			return ret;
+	}
+	return -EIO;
+}
+
+static int dock_acquire(struct dock_state *s)
+{
+	mutex_lock(&s->lock);
+	dock_in();
+	if (dock_read()) {
+		/* Allow some time for the dock pull-down resistor to discharge
+		 * the capasitor.
+		 */
+		msleep(20);
+		if (dock_read()) {
+			mutex_unlock(&s->lock);
+			return -ENOENT;
+		}
+	}
+	dock_out(0);
+	s->level = false;
+	return 0;
+}
+
+static void dock_release(struct dock_state *s)
+{
+	dock_in();
+	mutex_unlock(&s->lock);
+}
+
+enum {
+	DOCK_TYPE = 0x0,
+	DOCK_BT_ADDR = 0x1, /* - 0x7 */
+
+	DOCK_PIN_CODE = 0x0,
+};
+
+static ssize_t bt_addr_show(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	int ret;
+	u8 bt_addr[6];
+
+	ret = dock_acquire(&ds);
+	if (ret < 0)
+		return ret;
+	ret = dock_read_multi(&ds, DOCK_BT_ADDR, bt_addr, 6);
+	dock_release(&ds);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n",
+		bt_addr[0], bt_addr[1], bt_addr[2],
+		bt_addr[3], bt_addr[4], bt_addr[5]);
+}
+static DEVICE_ATTR(bt_addr, S_IRUGO | S_IWUSR, bt_addr_show, NULL);
+
+static ssize_t bt_pin_store(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t size)
+{
+	int ret, i;
+	u8 pin[4];
+
+	if (size < 4)
+		return -EINVAL;
+
+	for (i = 0; i < sizeof(pin); i++) {
+		if ((pin[i] = buf[i] - '0') > 10)
+			return -EINVAL;
+	}
+
+	ret = dock_acquire(&ds);
+	if (ret < 0)
+		return ret;
+	ret = dock_write_multi(&ds, DOCK_PIN_CODE, pin, 4);
+	dock_release(&ds);
+	if (ret < 0)
+		return ret;
+
+	return size;
+}
+static DEVICE_ATTR(bt_pin, S_IRUGO | S_IWUSR, NULL, bt_pin_store);
+
+
+static int power_get_property(struct power_supply *psy,
+			      enum power_supply_property psp,
+			      union power_supply_propval *val)
+{
+	if (psp != POWER_SUPPLY_PROP_ONLINE)
+		return -EINVAL;
+
+	if (psy->type == POWER_SUPPLY_TYPE_MAINS)
+		val->intval = (vbus_present && (usb_status == 2 || dock_mains));
+	else
+		val->intval = vbus_present;
+	return 0;
+}
+
+static enum power_supply_property power_properties[] = {
+	POWER_SUPPLY_PROP_ONLINE,
+};
+
+static struct power_supply ac_supply = {
+	.name = "ac",
+	.type = POWER_SUPPLY_TYPE_MAINS,
+	.supplied_to = supply_list,
+	.num_supplicants = ARRAY_SIZE(supply_list),
+	.properties = power_properties,
+	.num_properties = ARRAY_SIZE(power_properties),
+	.get_property = power_get_property,
+};
+
+static struct power_supply usb_supply = {
+	.name = "usb",
+	.type = POWER_SUPPLY_TYPE_USB,
+	.supplied_to = supply_list,
+	.num_supplicants = ARRAY_SIZE(supply_list),
+	.properties = power_properties,
+	.num_properties = ARRAY_SIZE(power_properties),
+	.get_property = power_get_property,
+};
+
+/* rpc related */
+#define APP_BATT_PDEV_NAME		"rs30100001:00000000"
+#define APP_BATT_PROG			0x30100001
+#define APP_BATT_VER			MSM_RPC_VERS(0,0)
+#define HTC_PROCEDURE_BATTERY_NULL	0
+#define HTC_PROCEDURE_GET_BATT_LEVEL	1
+#define HTC_PROCEDURE_GET_BATT_INFO	2
+#define HTC_PROCEDURE_GET_CABLE_STATUS	3
+#define HTC_PROCEDURE_SET_BATT_DELTA	4
+
+static struct msm_rpc_endpoint *endpoint;
+
+struct battery_info_reply {
+	u32 batt_id;		/* Battery ID from ADC */
+	u32 batt_vol;		/* Battery voltage from ADC */
+	u32 batt_temp;		/* Battery Temperature (C) from formula and ADC */
+	u32 batt_current;	/* Battery current from ADC */
+	u32 level;		/* formula */
+	u32 charging_source;	/* 0: no cable, 1:usb, 2:AC */
+	u32 charging_enabled;	/* 0: Disable, 1: Enable */
+	u32 full_bat;		/* Full capacity of battery (mAh) */
+};
+
+static void dock_work_proc(struct work_struct *work)
+{
+	int dockid;
+
+	if (!vbus_present || dock_acquire(&ds))
+		goto no_dock;
+
+	if (ds.dock_connected_unknown) {
+		/* force a new dock notification if a command failed */
+		switch_set_state(&dock_switch, 0);
+		ds.dock_connected_unknown = false;
+	}
+
+	dockid = dock_read_single(&ds, DOCK_TYPE);
+	dock_release(&ds);
+
+	pr_info("Detected dock with ID %02x\n", dockid);
+	if (dockid >= 0) {
+		msm_hsusb_set_vbus_state(0);
+		dock_mains = !!(dockid & 0x80);
+		switch_set_state(&dock_switch, (dockid & 1) ? 2 : 1);
+		goto done;
+	}
+no_dock:
+	dock_mains = false;
+	switch_set_state(&dock_switch, 0);
+	msm_hsusb_set_vbus_state(vbus_present);
+done:
+	power_supply_changed(&ac_supply);
+	power_supply_changed(&usb_supply);
+	wake_unlock(&dock_work_wake_lock);
+}
+
+static int htc_battery_probe(struct platform_device *pdev)
+{
+	struct rpc_request_hdr req;	
+	struct htc_get_batt_info_rep {
+		struct rpc_reply_hdr hdr;
+		struct battery_info_reply info;
+	} rep;
+
+	int rc;
+
+	endpoint = msm_rpc_connect(APP_BATT_PROG, APP_BATT_VER, 0);
+	if (IS_ERR(endpoint)) {
+		printk(KERN_ERR "%s: init rpc failed! rc = %ld\n",
+		       __FUNCTION__, PTR_ERR(endpoint));
+		return PTR_ERR(endpoint);
+	}
+
+	/* must do this or we won't get cable status updates */
+	rc = msm_rpc_call_reply(endpoint, HTC_PROCEDURE_GET_BATT_INFO,
+				&req, sizeof(req),
+				&rep, sizeof(rep),
+				5 * HZ);
+	if (rc < 0)
+		printk(KERN_ERR "%s: get info failed\n", __FUNCTION__);
+
+	power_supply_register(&pdev->dev, &ac_supply);
+	power_supply_register(&pdev->dev, &usb_supply);
+
+	INIT_WORK(&dock_work, dock_work_proc);
+	dock_wq = create_singlethread_workqueue("dock");
+
+	return 0;
+}
+
+static struct platform_driver htc_battery_driver = {
+	.probe	= htc_battery_probe,
+	.driver	= {
+		.name	= APP_BATT_PDEV_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+/* batt_mtoa server definitions */
+#define BATT_MTOA_PROG				0x30100000
+#define BATT_MTOA_VERS				0
+#define RPC_BATT_MTOA_NULL			0
+#define RPC_BATT_MTOA_SET_CHARGING_PROC		1
+#define RPC_BATT_MTOA_CABLE_STATUS_UPDATE_PROC	2
+#define RPC_BATT_MTOA_LEVEL_UPDATE_PROC		3
+
+struct rpc_batt_mtoa_cable_status_update_args {
+	int status;
+};
+
+static int handle_battery_call(struct msm_rpc_server *server,
+			       struct rpc_request_hdr *req, unsigned len)
+{	
+	struct rpc_batt_mtoa_cable_status_update_args *args;
+
+	if (req->procedure != RPC_BATT_MTOA_CABLE_STATUS_UPDATE_PROC)
+		return 0;
+
+	args = (struct rpc_batt_mtoa_cable_status_update_args *)(req + 1);
+	args->status = be32_to_cpu(args->status);
+	pr_info("cable_status_update: status=%d\n",args->status);
+
+	args->status = !!args->status;
+
+	vbus_present = args->status;
+	wake_lock(&dock_work_wake_lock);
+	queue_work(dock_wq, &dock_work);
+	return 0;
+}
+
+void notify_usb_connected(int status)
+{
+	printk("### notify_usb_connected(%d) ###\n", status);
+	usb_status = status;
+	power_supply_changed(&ac_supply);
+	power_supply_changed(&usb_supply);
+}
+
+int is_ac_power_supplied(void)
+{
+	return vbus_present && (usb_status == 2 || dock_mains);
+}
+
+static struct msm_rpc_server battery_server = {
+	.prog = BATT_MTOA_PROG,
+	.vers = BATT_MTOA_VERS,
+	.rpc_call = handle_battery_call,
+};
+
+static int __init htc_battery_init(void)
+{
+	int ret;
+	gpio_request(_GPIO_DOCK, "dock");
+	dock_in();
+	wake_lock_init(&dock_work_wake_lock, WAKE_LOCK_SUSPEND, "dock");
+	platform_driver_register(&htc_battery_driver);
+	msm_rpc_create_server(&battery_server);
+	if (switch_dev_register(&dock_switch) == 0) {
+		ret = device_create_file(dock_switch.dev, &dev_attr_bt_addr);
+		WARN_ON(ret);
+		ret = device_create_file(dock_switch.dev, &dev_attr_bt_pin);
+		WARN_ON(ret);
+	}
+
+	return 0;
+}
+
+module_init(htc_battery_init);
+MODULE_DESCRIPTION("HTC Battery Driver");
+MODULE_LICENSE("GPL");
+
diff --git a/arch/arm/mach-msm/htc_pwrsink.c b/arch/arm/mach-msm/htc_pwrsink.c
new file mode 100644
index 0000000..2ec2c7f
--- /dev/null
+++ b/arch/arm/mach-msm/htc_pwrsink.c
@@ -0,0 +1,281 @@
+/* arch/arm/mach-msm/htc_pwrsink.c
+ *
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (C) 2008 Google, Inc.
+ * Author: San Mehat <san@google.com>
+ *         Kant Kang <kant_kang@htc.com>
+ *         Eiven Peng <eiven_peng@htc.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/earlysuspend.h>
+#include <mach/msm_smd.h>
+#include <mach/htc_pwrsink.h>
+
+#include "smd_private.h"
+
+enum {
+	PWRSINK_DEBUG_CURR_CHANGE = 1U << 0,
+	PWRSINK_DEBUG_CURR_CHANGE_AUDIO = 1U << 1,
+};
+static int pwrsink_debug_mask;
+module_param_named(debug_mask, pwrsink_debug_mask, int,
+		S_IRUGO | S_IWUSR | S_IWGRP);
+
+static int initialized;
+static unsigned audio_path = 1;	/* HTC_SND_DEVICE_SPEAKER = 1 */
+static struct pwr_sink_audio audio_sink_array[PWRSINK_AUDIO_LAST + 1];
+static struct pwr_sink *sink_array[PWRSINK_LAST + 1];
+static DEFINE_SPINLOCK(sink_lock);
+static DEFINE_SPINLOCK(audio_sink_lock);
+static unsigned long total_sink;
+static uint32_t *smem_total_sink;
+
+int htc_pwrsink_set(pwrsink_id_type id, unsigned percent_utilized)
+{
+	unsigned long flags;
+
+	if (!smem_total_sink)
+		smem_total_sink = smem_alloc(SMEM_ID_VENDOR0, sizeof(uint32_t));
+
+	if (!initialized)
+		return -EAGAIN;
+
+	if (id < 0 || id > PWRSINK_LAST)
+		return -EINVAL;
+
+	spin_lock_irqsave(&sink_lock, flags);
+
+	if (!sink_array[id]) {
+		spin_unlock_irqrestore(&sink_lock, flags);
+		return -ENOENT;
+	}
+
+	if (sink_array[id]->percent_util == percent_utilized) {
+		spin_unlock_irqrestore(&sink_lock, flags);
+		return 0;
+	}
+
+	total_sink -= (sink_array[id]->ua_max *
+		       sink_array[id]->percent_util / 100);
+	sink_array[id]->percent_util = percent_utilized;
+	total_sink += (sink_array[id]->ua_max *
+		       sink_array[id]->percent_util / 100);
+
+	if (smem_total_sink)
+		*smem_total_sink = total_sink / 1000;
+
+	pr_debug("htc_pwrsink: ID %d, Util %d%%, Total %lu uA %s\n",
+		 id, percent_utilized, total_sink,
+		 smem_total_sink ? "SET" : "");
+
+	spin_unlock_irqrestore(&sink_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(htc_pwrsink_set);
+
+static void compute_audio_current(void)
+{
+	/* unsigned long flags; */
+	unsigned max_percent = 0;
+	int i, active_audio_sinks = 0;
+	pwrsink_audio_id_type last_active_audio_sink = 0;
+
+	/* Make sure this segment will be spinlocked
+	before computing by calling function. */
+	/* spin_lock_irqsave(&audio_sink_lock, flags); */
+	for (i = 0; i <= PWRSINK_AUDIO_LAST; ++i) {
+		max_percent = (audio_sink_array[i].percent > max_percent) ?
+				audio_sink_array[i].percent : max_percent;
+		if (audio_sink_array[i].percent > 0) {
+			active_audio_sinks++;
+			last_active_audio_sink = i;
+		}
+	}
+	if (active_audio_sinks == 0)
+		htc_pwrsink_set(PWRSINK_AUDIO, 0);
+	else if (active_audio_sinks == 1) {
+		pwrsink_audio_id_type laas =  last_active_audio_sink;
+		/* TODO: add volume and routing path current. */
+		if (audio_path == 1)	/* Speaker */
+			htc_pwrsink_set(PWRSINK_AUDIO,
+				audio_sink_array[laas].percent);
+		else
+			htc_pwrsink_set(PWRSINK_AUDIO,
+				audio_sink_array[laas].percent * 9 / 10);
+	} else if (active_audio_sinks > 1) {
+		/* TODO: add volume and routing path current. */
+		if (audio_path == 1)	/* Speaker */
+			htc_pwrsink_set(PWRSINK_AUDIO, max_percent);
+		else
+			htc_pwrsink_set(PWRSINK_AUDIO, max_percent * 9 / 10);
+	}
+	/* spin_unlock_irqrestore(&audio_sink_lock, flags); */
+
+	if (pwrsink_debug_mask & PWRSINK_DEBUG_CURR_CHANGE_AUDIO)
+		pr_info("%s: active_audio_sinks=%d, audio_path=%d\n", __func__,
+				active_audio_sinks, audio_path);
+}
+
+int htc_pwrsink_audio_set(pwrsink_audio_id_type id, unsigned percent_utilized)
+{
+	unsigned long flags;
+
+	if (id < 0 || id > PWRSINK_AUDIO_LAST)
+		return -EINVAL;
+
+	if (pwrsink_debug_mask & PWRSINK_DEBUG_CURR_CHANGE_AUDIO)
+		pr_info("%s: id=%d, percent=%d, percent_old=%d\n", __func__,
+			id, percent_utilized, audio_sink_array[id].percent);
+
+	spin_lock_irqsave(&audio_sink_lock, flags);
+	if (audio_sink_array[id].percent == percent_utilized) {
+		spin_unlock_irqrestore(&audio_sink_lock, flags);
+		return 0;
+	}
+	audio_sink_array[id].percent = percent_utilized;
+	spin_unlock_irqrestore(&audio_sink_lock, flags);
+	compute_audio_current();
+	return 0;
+}
+EXPORT_SYMBOL(htc_pwrsink_audio_set);
+
+int htc_pwrsink_audio_volume_set(pwrsink_audio_id_type id, unsigned volume)
+{
+	unsigned long flags;
+
+	if (id < 0 || id > PWRSINK_AUDIO_LAST)
+		return -EINVAL;
+
+	if (pwrsink_debug_mask & PWRSINK_DEBUG_CURR_CHANGE_AUDIO)
+		pr_info("%s: id=%d, volume=%d, volume_old=%d\n", __func__,
+			id, volume, audio_sink_array[id].volume);
+
+	spin_lock_irqsave(&audio_sink_lock, flags);
+	if (audio_sink_array[id].volume == volume) {
+		spin_unlock_irqrestore(&audio_sink_lock, flags);
+		return 0;
+	}
+	audio_sink_array[id].volume = volume;
+	spin_unlock_irqrestore(&audio_sink_lock, flags);
+	compute_audio_current();
+	return 0;
+}
+EXPORT_SYMBOL(htc_pwrsink_audio_volume_set);
+
+int htc_pwrsink_audio_path_set(unsigned path)
+{
+	unsigned long flags;
+
+	if (pwrsink_debug_mask & PWRSINK_DEBUG_CURR_CHANGE_AUDIO)
+		pr_info("%s: path=%d, path_old=%d\n",
+			__func__, path, audio_path);
+
+	spin_lock_irqsave(&audio_sink_lock, flags);
+	if (audio_path == path) {
+		spin_unlock_irqrestore(&audio_sink_lock, flags);
+		return 0;
+	}
+	audio_path = path;
+	spin_unlock_irqrestore(&audio_sink_lock, flags);
+	compute_audio_current();
+	return 0;
+}
+EXPORT_SYMBOL(htc_pwrsink_audio_path_set);
+
+void htc_pwrsink_suspend_early(struct early_suspend *h)
+{
+	htc_pwrsink_set(PWRSINK_SYSTEM_LOAD, 70);
+}
+
+int htc_pwrsink_suspend_late(struct platform_device *pdev, pm_message_t state)
+{
+	struct pwr_sink_platform_data *pdata = pdev->dev.platform_data;
+
+	if (pdata && pdata->suspend_late)
+		pdata->suspend_late(pdev, state);
+	else
+		htc_pwrsink_set(PWRSINK_SYSTEM_LOAD, 13);
+	return 0;
+}
+
+int htc_pwrsink_resume_early(struct platform_device *pdev)
+{
+	struct pwr_sink_platform_data *pdata = pdev->dev.platform_data;
+
+	if (pdata && pdata->resume_early)
+		pdata->resume_early(pdev);
+	else
+		htc_pwrsink_set(PWRSINK_SYSTEM_LOAD, 70);
+	return 0;
+}
+
+void htc_pwrsink_resume_late(struct early_suspend *h)
+{
+	htc_pwrsink_set(PWRSINK_SYSTEM_LOAD, 100);
+}
+
+struct early_suspend htc_pwrsink_early_suspend = {
+	.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1,
+	.suspend = htc_pwrsink_suspend_early,
+	.resume = htc_pwrsink_resume_late,
+};
+
+static int __init htc_pwrsink_probe(struct platform_device *pdev)
+{
+	struct pwr_sink_platform_data *pdata = pdev->dev.platform_data;
+	int i;
+
+	if (!pdata)
+		return -EINVAL;
+
+	total_sink = 0;
+	for (i = 0; i < pdata->num_sinks; i++) {
+		sink_array[pdata->sinks[i].id] = &pdata->sinks[i];
+		total_sink += (pdata->sinks[i].ua_max *
+			       pdata->sinks[i].percent_util / 100);
+	}
+
+	initialized = 1;
+
+	if (pdata->suspend_early)
+		htc_pwrsink_early_suspend.suspend = pdata->suspend_early;
+	if (pdata->resume_late)
+		htc_pwrsink_early_suspend.resume = pdata->resume_late;
+	register_early_suspend(&htc_pwrsink_early_suspend);
+
+	return 0;
+}
+
+static struct platform_driver htc_pwrsink_driver = {
+	.probe = htc_pwrsink_probe,
+	.suspend_late = htc_pwrsink_suspend_late,
+	.resume_early = htc_pwrsink_resume_early,
+	.driver = {
+		.name = "htc_pwrsink",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init htc_pwrsink_init(void)
+{
+	initialized = 0;
+	memset(sink_array, 0, sizeof(sink_array));
+	return platform_driver_register(&htc_pwrsink_driver);
+}
+
+module_init(htc_pwrsink_init);
diff --git a/arch/arm/mach-msm/htc_wifi_nvs.c b/arch/arm/mach-msm/htc_wifi_nvs.c
new file mode 100644
index 0000000..2d381a9
--- /dev/null
+++ b/arch/arm/mach-msm/htc_wifi_nvs.c
@@ -0,0 +1,55 @@
+/* arch/arm/mach-msm/htc_wifi_nvs.c
+ *
+ * Code to extract WiFi calibration information from ATAG set up 
+ * by the bootloader.
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Dmitry Shmidt <dimitrysh@google.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/setup.h>
+
+/* configuration tags specific to msm */
+#define ATAG_MSM_WIFI	0x57494649 /* MSM WiFi */
+
+#define MAX_NVS_SIZE	0x800U
+static unsigned char wifi_nvs_ram[MAX_NVS_SIZE];
+
+unsigned char *get_wifi_nvs_ram( void )
+{
+	return( wifi_nvs_ram );
+}
+EXPORT_SYMBOL(get_wifi_nvs_ram);
+
+static int __init parse_tag_msm_wifi(const struct tag *tag)
+{
+	unsigned char *dptr = (unsigned char *)(&tag->u);
+	unsigned size;
+	
+	size = min((tag->hdr.size - 2) * sizeof(__u32), MAX_NVS_SIZE);
+#ifdef ATAG_MSM_WIFI_DEBUG	
+	unsigned i;
+	
+	printk("WiFi Data size = %d , 0x%x\n", tag->hdr.size, tag->hdr.tag);
+	for (i = 0; i < size; i++)
+		printk("%02x ", *dptr++);
+#endif	
+	memcpy( (void *)wifi_nvs_ram, (void *)dptr, size );
+	return 0;
+}
+
+__tagtable(ATAG_MSM_WIFI, parse_tag_msm_wifi);
diff --git a/arch/arm/mach-msm/hw3d.c b/arch/arm/mach-msm/hw3d.c
new file mode 100644
index 0000000..c2592ec
--- /dev/null
+++ b/arch/arm/mach-msm/hw3d.c
@@ -0,0 +1,407 @@
+/* arch/arm/mach-msm/hw3d.c
+ *
+ * Register/Interrupt access for userspace 3D library.
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/poll.h>
+#include <linux/time.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/mm.h>
+#include <linux/clk.h>
+#include <linux/android_pmem.h>
+#include <mach/board.h>
+
+static DEFINE_SPINLOCK(hw3d_lock);
+static DECLARE_WAIT_QUEUE_HEAD(hw3d_queue);
+static int hw3d_pending;
+static int hw3d_disabled;
+
+static struct clk *grp_clk;
+static struct clk *imem_clk;
+DECLARE_MUTEX(hw3d_sem);
+static unsigned int hw3d_granted;
+static struct file *hw3d_granted_file;
+
+static irqreturn_t hw3d_irq_handler(int irq, void *data)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&hw3d_lock, flags);
+	if (!hw3d_disabled) {
+		disable_irq(INT_GRAPHICS);
+		hw3d_disabled = 1;
+	}
+	hw3d_pending = 1;
+	spin_unlock_irqrestore(&hw3d_lock, flags);
+
+	wake_up(&hw3d_queue);
+
+	return IRQ_HANDLED;
+}
+
+static void hw3d_disable_interrupt(void)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&hw3d_lock, flags);
+	if (!hw3d_disabled) {
+		disable_irq(INT_GRAPHICS);
+		hw3d_disabled = 1;
+	}
+	spin_unlock_irqrestore(&hw3d_lock, flags);
+}
+
+static long hw3d_wait_for_interrupt(void)
+{
+	unsigned long flags;
+	int ret;
+
+	for (;;) {
+		spin_lock_irqsave(&hw3d_lock, flags);
+		if (hw3d_pending) {
+			hw3d_pending = 0;
+			spin_unlock_irqrestore(&hw3d_lock, flags);
+			return 0;
+		}
+		if (hw3d_disabled) {
+			hw3d_disabled = 0;
+			enable_irq(INT_GRAPHICS);
+		}
+		spin_unlock_irqrestore(&hw3d_lock, flags);
+
+		ret = wait_event_interruptible(hw3d_queue, hw3d_pending);
+		if (ret < 0) {
+			hw3d_disable_interrupt();
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+#define HW3D_REGS_LEN 0x100000
+static long hw3d_wait_for_revoke(struct hw3d_info *info, struct file *filp)
+{
+	struct hw3d_data *data = filp->private_data;
+	int ret;
+
+	if (is_master(info, filp)) {
+		pr_err("%s: cannot revoke on master node\n", __func__);
+		return -EPERM;
+	}
+
+	ret = wait_event_interruptible(info->revoke_wq,
+				       info->revoking ||
+				       data->closing);
+	if (ret == 0 && data->closing)
+		ret = -EPIPE;
+	if (ret < 0)
+		return ret;
+	return 0;
+}
+
+static void locked_hw3d_client_done(struct hw3d_info *info, int had_timer)
+{
+	if (info->enabled) {
+		pr_debug("hw3d: was enabled\n");
+		info->enabled = 0;
+		clk_disable(info->grp_clk);
+		clk_disable(info->imem_clk);
+	}
+	info->revoking = 0;
+
+	/* double check that the irqs are disabled */
+	locked_hw3d_irq_disable(info);
+
+	if (had_timer)
+		wake_unlock(&info->wake_lock);
+	wake_up(&info->revoke_done_wq);
+}
+
+static void do_force_revoke(struct hw3d_info *info)
+{
+	unsigned long flags;
+
+	/* at this point, the task had a chance to relinquish the gpu, but
+	 * it hasn't. So, we kill it */
+	spin_lock_irqsave(&info->lock, flags);
+	pr_debug("hw3d: forcing revoke\n");
+	locked_hw3d_irq_disable(info);
+	if (info->client_task) {
+		pr_info("hw3d: force revoke from pid=%d\n",
+			info->client_task->pid);
+		force_sig(SIGKILL, info->client_task);
+		put_task_struct(info->client_task);
+		info->client_task = NULL;
+	}
+	locked_hw3d_client_done(info, 1);
+	pr_debug("hw3d: done forcing revoke\n");
+	spin_unlock_irqrestore(&info->lock, flags);
+}
+
+#define REVOKE_TIMEOUT		(2 * HZ)
+static void locked_hw3d_revoke(struct hw3d_info *info)
+{
+	/* force us to wait to suspend until the revoke is done. If the
+	 * user doesn't release the gpu, the timer will turn off the gpu,
+	 * and force kill the process. */
+	wake_lock(&info->wake_lock);
+	info->revoking = 1;
+	wake_up(&info->revoke_wq);
+	mod_timer(&info->revoke_timer, jiffies + REVOKE_TIMEOUT);
+}
+
+bool is_msm_hw3d_file(struct file *file)
+{
+	struct hw3d_info *info = hw3d_info;
+	if (MAJOR(file->f_dentry->d_inode->i_rdev) == MAJOR(info->devno) &&
+	    (is_master(info, file) || is_client(info, file)))
+		return 1;
+	return 0;
+}
+
+void put_msm_hw3d_file(struct file *file)
+{
+	if (!is_msm_hw3d_file(file))
+		return;
+	fput(file);
+}
+
+static long hw3d_revoke_gpu(struct file *file)
+{
+	int ret = 0;
+	unsigned long user_start, user_len;
+	struct pmem_region region = {.offset = 0x0, .len = HW3D_REGS_LEN};
+
+	down(&hw3d_sem);
+	if (!hw3d_granted)
+		goto end;
+	/* revoke the pmem region completely */
+	if ((ret = pmem_remap(&region, file, PMEM_UNMAP)))
+		goto end;
+	get_pmem_user_addr(file, &user_start, &user_len);
+	/* reset the gpu */
+	clk_disable(grp_clk);
+	clk_disable(imem_clk);
+	hw3d_granted = 0;
+end:
+	up(&hw3d_sem);
+	return ret;
+}
+
+static long hw3d_grant_gpu(struct file *file)
+{
+	int ret = 0;
+	struct pmem_region region = {.offset = 0x0, .len = HW3D_REGS_LEN};
+
+	down(&hw3d_sem);
+	if (hw3d_granted) {
+		ret = -1;
+		goto end;
+	}
+	/* map the registers */
+	if ((ret = pmem_remap(&region, file, PMEM_MAP)))
+		goto end;
+	clk_enable(grp_clk);
+	clk_enable(imem_clk);
+	hw3d_granted = 1;
+	hw3d_granted_file = file;
+end:
+	up(&hw3d_sem);
+	return ret;
+}
+
+static int hw3d_release(struct inode *inode, struct file *file)
+{
+	down(&hw3d_sem);
+	/* if the gpu is in use, and its inuse by the file that was released */
+	if (hw3d_granted && (file == hw3d_granted_file)) {
+		clk_disable(grp_clk);
+		clk_disable(imem_clk);
+		hw3d_granted = 0;
+		hw3d_granted_file = NULL;
+	}
+	up(&hw3d_sem);
+	return 0;
+}
+
+static void hw3d_vma_open(struct vm_area_struct *vma)
+{
+	/* XXX: should the master be allowed to fork and keep the mappings? */
+
+	/* TODO: remap garbage page into here.
+	 *
+	 * For now, just pull the mapping. The user shouldn't be forking
+	 * and using it anyway. */
+	zap_page_range(vma, vma->vm_start, vma->vm_end - vma->vm_start, NULL);
+}
+
+static void hw3d_vma_close(struct vm_area_struct *vma)
+{
+	struct file *file = vma->vm_file;
+	struct hw3d_data *data = file->private_data;
+	int i;
+
+	pr_debug("hw3d: current %u ppid %u file %p count %ld\n",
+		 current->pid, current->parent->pid, file, file_count(file));
+
+	BUG_ON(!data);
+
+	mutex_lock(&data->mutex);
+	for (i = 0; i < HW3D_NUM_REGIONS; ++i) {
+		if (data->vmas[i] == vma) {
+			data->vmas[i] = NULL;
+			goto done;
+		}
+	}
+	pr_warning("%s: vma %p not of ours during vma_close\n", __func__, vma);
+done:
+	mutex_unlock(&data->mutex);
+}
+
+static int hw3d_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct hw3d_info *info = hw3d_info;
+	struct hw3d_data *data = file->private_data;
+	unsigned long vma_size = vma->vm_end - vma->vm_start;
+	int ret = 0;
+	int region = REGION_PAGE_ID(vma->vm_pgoff);
+
+	if (region >= HW3D_NUM_REGIONS) {
+		pr_err("%s: Trying to mmap unknown region %d\n", __func__,
+		       region);
+		return -EINVAL;
+	} else if (vma_size > info->regions[region].size) {
+		pr_err("%s: VMA size %ld exceeds region %d size %ld\n",
+			__func__, vma_size, region,
+			info->regions[region].size);
+		return -EINVAL;
+	} else if (REGION_PAGE_OFFS(vma->vm_pgoff) != 0 ||
+		   (vma_size & ~PAGE_MASK)) {
+		pr_err("%s: Can't remap part of the region %d\n", __func__,
+		       region);
+		return -EINVAL;
+	} else if (!is_master(info, file) &&
+		   current->group_leader != info->client_task) {
+		pr_err("%s: current(%d) != client_task(%d)\n", __func__,
+		       current->group_leader->pid, info->client_task->pid);
+		return -EPERM;
+	} else if (!is_master(info, file) &&
+		   (info->revoking || info->suspending)) {
+		pr_err("%s: cannot mmap while revoking(%d) or suspending(%d)\n",
+		       __func__, info->revoking, info->suspending);
+		return -EPERM;
+	}
+
+	mutex_lock(&data->mutex);
+	if (data->vmas[region] != NULL) {
+		pr_err("%s: Region %d already mapped (pid=%d tid=%d)\n",
+		       __func__, region, current->group_leader->pid,
+		       current->pid);
+		ret = -EBUSY;
+		goto done;
+	}
+
+	/* our mappings are always noncached */
+#ifdef pgprot_noncached
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+#endif
+
+	ret = io_remap_pfn_range(vma, vma->vm_start,
+				 info->regions[region].pbase >> PAGE_SHIFT,
+				 vma_size, vma->vm_page_prot);
+	if (ret) {
+		pr_err("%s: Cannot remap page range for region %d!\n", __func__,
+		       region);
+		ret = -EAGAIN;
+		goto done;
+	}
+
+	/* Prevent a malicious client from stealing another client's data
+	 * by forcing a revoke on it and then mmapping the GPU buffers.
+	 */
+	if (region != HW3D_REGS)
+		memset(info->regions[region].vbase, 0,
+		       info->regions[region].size);
+
+	vma->vm_ops = &hw3d_vm_ops;
+
+	/* mark this region as mapped */
+	data->vmas[region] = vma;
+
+done:
+	mutex_unlock(&data->mutex);
+	return ret;
+}
+
+static long hw3d_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	switch (cmd) {
+		case HW3D_REVOKE_GPU:
+			return hw3d_revoke_gpu(file);
+			break;
+		case HW3D_GRANT_GPU:
+			return hw3d_grant_gpu(file);
+			break;
+		case HW3D_WAIT_FOR_INTERRUPT:
+			return hw3d_wait_for_interrupt();
+			break;
+		default:
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static struct android_pmem_platform_data pmem_data = {
+	.name = "hw3d",
+	.start = 0xA0000000,
+	.size = 0x100000,
+	.allocator_type = PMEM_ALLOCATORTYPE_ALLORNOTHING,
+	.cached = 0,
+};
+
+static int __init hw3d_init(void)
+{
+	int ret;
+
+	grp_clk = clk_get(NULL, "grp_clk");
+	if (IS_ERR(grp_clk))
+		return PTR_ERR(grp_clk);
+	
+	imem_clk = clk_get(NULL, "imem_clk");
+	if (IS_ERR(imem_clk)) {
+		clk_put(grp_clk);
+		return PTR_ERR(imem_clk);
+	}
+	ret = request_irq(INT_GRAPHICS, hw3d_irq_handler,
+			  IRQF_TRIGGER_HIGH, "hw3d", 0);
+	if (ret) {
+		clk_put(grp_clk);
+		clk_put(imem_clk);
+		return ret;
+	}
+	hw3d_disable_interrupt();
+	hw3d_granted = 0;
+
+	return pmem_setup(&pmem_data, hw3d_ioctl, hw3d_release);
+}
+
+device_initcall(hw3d_init);
diff --git a/arch/arm/mach-msm/idle-macros.S b/arch/arm/mach-msm/idle-macros.S
new file mode 100644
index 0000000..1622e13
--- /dev/null
+++ b/arch/arm/mach-msm/idle-macros.S
@@ -0,0 +1,153 @@
+/* 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 <asm/hardware/cache-l2x0.h>
+
+/* Add 300 NOPs after 'wfi' for 8x25 target */
+.macro DELAY_8x25, rept
+#ifdef CONFIG_ARCH_MSM8625
+	.rept   \rept
+	nop
+	.endr
+#endif
+.endm
+
+/* Switch between smp_to_amp/amp_to_smp configuration */
+.macro SET_SMP_COHERENCY, on = 0
+	ldr     r0, =target_type
+	ldr     r0, [r0]
+	mov     r1, #TARGET_IS_8625
+	cmp     r0, r1
+	bne     skip\@
+	mrc	p15, 0, r0, c1, c0, 1	/* read ACTLR register */
+	.if     \on
+	orr	r0, r0, #(1 << 6)	/* Set the SMP bit in ACTLR */
+	.else
+	bic	r0, r0, #(1 << 6)	/* Clear the SMP bit */
+	.endif
+	mcr	p15, 0, r0, c1, c0, 1	/* write ACTLR register */
+	isb
+skip\@:
+.endm
+
+/*
+ * Enable the "L2" cache, not require to restore the controller registers
+ */
+.macro ENABLE_8x25_L2
+	ldr     r0, =target_type
+	ldr     r0, [r0]
+	mov     r1, #TARGET_IS_8625
+	cmp     r0, r1
+	bne     skip_enable\@
+	ldr     r0, =apps_power_collapse
+	ldr     r0, [r0]
+	cmp     r0, #POWER_COLLAPSED
+	bne     skip_enable\@
+	ldr     r0, =l2x0_base_addr
+	ldr	r0, [r0]
+	mov	r1, #0x1
+	str	r1, [r0, #L2X0_CTRL]
+	dmb
+skip_enable\@:
+.endm
+
+/*
+ * Perform the required operation
+ * operation: type of operation on l2 cache (e.g: clean&inv or inv)
+ * l2_enable: enable or disable
+ */
+.macro DO_CACHE_OPERATION, operation, l2_enable
+	ldr     r2, =l2x0_base_addr
+	ldr	r2, [r2]
+	ldr     r0, =0xffff
+	str     r0, [r2, #\operation]
+wait\@:
+	ldr	r0, [r2, #\operation]
+	ldr	r1, =0xffff
+	ands    r0, r0, r1
+	bne     wait\@
+l2x_sync\@:
+	mov	r0, #0x0
+	str	r0, [r2, #L2X0_CACHE_SYNC]
+sync\@:
+	ldr	r0, [r2, #L2X0_CACHE_SYNC]
+	ands	r0, r0, #0x1
+	bne	sync\@
+	mov     r1, #\l2_enable
+	str     r1, [r2, #L2X0_CTRL]
+.endm
+
+/*
+ * Clean and invalidate the L2 cache.
+ * 1. Check the target type
+ * 2. Check whether we are coming from PC are not
+ * 3. Save 'aux', 'data latency', & 'prefetch ctlr' registers
+ * 4. Start L2 clean & invalidation operation
+ * 5. Disable the L2 cache
+ */
+.macro SUSPEND_8x25_L2
+	ldr     r0, =target_type
+	ldr     r0, [r0]
+	mov     r1, #TARGET_IS_8625
+	cmp     r0, r1
+	bne     skip_suspend\@
+	ldr	r0, =apps_power_collapse
+	ldr	r0, [r0]
+	cmp	r0, #POWER_COLLAPSED
+	bne	skip_suspend\@
+	ldr	r0, =l2x0_saved_ctrl_reg_val
+	ldr	r1, =l2x0_base_addr
+	ldr	r1, [r1]
+	ldr	r2, [r1, #L2X0_AUX_CTRL]
+	str	r2, [r0, #0x0] /* store aux_ctlr reg value */
+	ldr     r2, [r1, #L2X0_DATA_LATENCY_CTRL]
+	str     r2, [r0, #0x4] /* store data latency reg value */
+	ldr     r2, [r1, #L2X0_PREFETCH_CTRL]
+	str     r2, [r0, #0x8] /* store prefetch_ctlr reg value */
+	DO_CACHE_OPERATION L2X0_CLEAN_INV_WAY OFF
+	dmb
+skip_suspend\@:
+.endm
+
+/*
+ * Coming back from a successful PC
+ * 1. Check the target type
+ * 2. Check whether we are going to PC are not
+ * 3. Disable the L2 cache
+ * 4. Restore 'aux', 'data latency', & 'prefetch ctlr' reg
+ * 5. Invalidate the cache
+ * 6. Enable the L2 cache
+ */
+.macro RESUME_8x25_L2
+	ldr     r0, =target_type
+	ldr     r0, [r0]
+	mov     r1, #TARGET_IS_8625
+	cmp     r0, r1
+	bne     skip_resume\@
+	ldr	r0, =apps_power_collapse
+	ldr	r0, [r0]
+	cmp	r0, #POWER_COLLAPSED
+	bne	skip_resume\@
+	ldr     r1, =l2x0_base_addr
+	ldr	r1, [r1]
+	mov     r0, #0x0
+	str     r0, [r1, #L2X0_CTRL]
+	ldr     r0, =l2x0_saved_ctrl_reg_val
+	ldr     r2, [r0, #0x0]
+	str	r2, [r1, #L2X0_AUX_CTRL] /* restore aux_ctlr reg value */
+	ldr	r2, [r0, #0x4]
+	str	r2, [r1, #L2X0_DATA_LATENCY_CTRL]
+	ldr	r2, [r0, #0x8]
+	str     r2, [r1, #L2X0_PREFETCH_CTRL]
+	DO_CACHE_OPERATION L2X0_INV_WAY ON
+skip_resume\@:
+.endm
diff --git a/arch/arm/mach-msm/idle-v6.S b/arch/arm/mach-msm/idle-v6.S
new file mode 100644
index 0000000..8160877
--- /dev/null
+++ b/arch/arm/mach-msm/idle-v6.S
@@ -0,0 +1,194 @@
+/*
+ * Idle processing for ARMv6-based Qualcomm SoCs.
+ * Work around bugs with SWFI.
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2009, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+.extern write_to_strongly_ordered_memory
+
+ENTRY(msm_arch_idle)
+	mrs	r2, cpsr		/* save the CPSR state */
+	cpsid   iaf			/* explictly disable I,A and F */
+
+#if defined(CONFIG_ARCH_MSM7X27)
+	mov     r0, #0
+	mcr     p15, 0, r0, c7, c10, 0   /* flush entire data cache */
+	mcr     p15, 0, r0, c7, c10, 4   /* dsb                */
+	stmfd   sp!, {r2, lr}            /* preserve r2, thus CPSR and LR */
+	bl      write_to_strongly_ordered_memory  /* flush AXI bus buffer */
+	ldmfd   sp!, {r2, lr}
+	mcr     p15, 0, r0, c7, c0, 4    /* wait for interrupt */
+#else
+	mrc     p15, 0, r1, c1, c0, 0    /* read current CR    */
+	bic     r0, r1, #(1 << 2)        /* clear dcache bit   */
+	bic     r0, r0, #(1 << 12)       /* clear icache bit   */
+	mcr     p15, 0, r0, c1, c0, 0    /* disable d/i cache  */
+
+	mov     r0, #0
+	mcr     p15, 0, r0, c7, c5, 0    /* invalidate icache and flush */
+	                                 /* branch target cache */
+	mcr     p15, 0, r0, c7, c14, 0   /* clean and invalidate dcache */
+
+	mcr     p15, 0, r0, c7, c10, 4   /* dsb                */
+	mcr     p15, 0, r0, c7, c0, 4    /* wait for interrupt */
+
+	mcr     p15, 0, r1, c1, c0, 0    /* restore d/i cache  */
+	mcr     p15, 0, r0, c7, c5, 4    /* isb                */
+#endif
+
+	msr	cpsr_c, r2		/* restore the CPSR state */
+	mov     pc, lr
+
+ENTRY(msm_pm_collapse)
+	ldr     r0, =saved_state
+	stmia   r0!, {r4-r14}
+
+	cpsid   f
+
+	mrc     p15, 0, r1, c1, c0, 0 /* MMU control */
+	mrc     p15, 0, r2, c2, c0, 0 /* ttb */
+	mrc     p15, 0, r3, c3, c0, 0 /* dacr */
+	mrc     p15, 0, ip, c13, c0, 1 /* context ID */
+	stmia   r0!, {r1-r3, ip}
+#if defined(CONFIG_OPROFILE)
+	mrc     p15, 0, r1, c15, c12, 0 /* pmnc */
+	mrc     p15, 0, r2, c15, c12, 1 /* ccnt */
+	mrc     p15, 0, r3, c15, c12, 2 /* pmn0 */
+	mrc     p15, 0, ip, c15, c12, 3 /* pmn1 */
+	stmia   r0!, {r1-r3, ip}
+#endif
+	mrc	p15, 0, r1, c1, c0, 2	/* read CACR */
+	stmia   r0!, {r1}
+
+	mrc     p15, 0, r1, c1, c0, 0    /* read current CR    */
+	bic     r0, r1, #(1 << 2)        /* clear dcache bit   */
+	bic     r0, r0, #(1 << 12)       /* clear icache bit   */
+	mcr     p15, 0, r0, c1, c0, 0    /* disable d/i cache  */
+
+	mov     r0, #0
+	mcr     p15, 0, r0, c7, c5, 0    /* invalidate icache and flush */
+	                                 /* branch target cache */
+	mcr     p15, 0, r0, c7, c14, 0   /* clean and invalidate dcache */
+
+	mcr     p15, 0, r0, c7, c10, 4   /* dsb                */
+	mcr     p15, 0, r0, c7, c0, 4    /* wait for interrupt */
+
+	mcr     p15, 0, r1, c1, c0, 0    /* restore d/i cache  */
+	mcr     p15, 0, r0, c7, c5, 4    /* isb                */
+
+	cpsie   f
+
+	ldr     r0, =saved_state         /* restore registers */
+	ldmfd   r0, {r4-r14}
+	mov     r0, #0                   /* return power collapse failed */
+	mov     pc, lr
+
+ENTRY(msm_pm_collapse_exit)
+#if 0 /* serial debug */
+	mov     r0, #0x80000016
+	mcr     p15, 0, r0, c15, c2, 4
+	mov     r0, #0xA9000000
+	add     r0, r0, #0x00A00000 /* UART1 */
+	/*add     r0, r0, #0x00C00000*/ /* UART3 */
+	mov     r1, #'A'
+	str     r1, [r0, #0x00C]
+#endif
+	ldr     r1, =saved_state_end
+	ldr     r2, =msm_pm_collapse_exit
+	adr     r3, msm_pm_collapse_exit
+	add     r1, r1, r3
+	sub     r1, r1, r2
+
+	ldmdb   r1!, {r2}
+	mcr	p15, 0, r2, c1, c0, 2	/* restore CACR */
+#if defined(CONFIG_OPROFILE)
+	ldmdb   r1!, {r2-r5}
+	mcr     p15, 0, r3, c15, c12, 1 /* ccnt */
+	mcr     p15, 0, r4, c15, c12, 2 /* pmn0 */
+	mcr     p15, 0, r5, c15, c12, 3 /* pmn1 */
+	mcr     p15, 0, r2, c15, c12, 0 /* pmnc */
+#endif
+	ldmdb   r1!, {r2-r5}
+	mcr     p15, 0, r4, c3, c0, 0 /* dacr */
+	mcr     p15, 0, r3, c2, c0, 0 /* ttb */
+	mcr     p15, 0, r5, c13, c0, 1	/* context ID */
+	mov     r0, #0
+	mcr     p15, 0, r0, c7, c5, 4   /* isb */
+	ldmdb   r1!, {r4-r14}
+
+	/* Add 1:1 map in the PMD to allow smooth switch when turning on MMU */
+	and     r3, r3, #~0x7F  /* mask off lower 7 bits of TTB */
+	adr     r0, msm_pm_mapped_pa /* get address of the mapped instr */
+	lsr     r1, r0, #20     /* get the addr range of addr in MB */
+	lsl     r1, r1, #2      /* multiply by 4 to get to the pg index */
+	add     r3, r3, r1      /* pgd + pgd_index(addr) */
+	ldr     r1, [r3]        /* save current entry to r1 */
+	lsr     r0, #20         /* align current addr to 1MB boundary */
+	lsl     r0, #20
+	/* Create new entry for this 1MB page */
+	orr     r0, r0, #0x400   /* PMD_SECT_AP_WRITE */
+	orr     r0, r0, #0x2     /* PMD_TYPE_SECT|PMD_DOMAIN(DOMAIN_KERNEL) */
+	str     r0, [r3]         /* put new entry into the MMU table */
+	mov     r0, #0
+	mcr     p15, 0, r0, c7, c10, 4  /* dsb */
+	mcr     p15, 0, r2, c1, c0, 0   /* MMU control */
+	mcr     p15, 0, r0, c7, c5, 4   /* isb */
+msm_pm_mapped_pa:
+	/* Switch to virtual */
+	adr     r2, msm_pm_pa_to_va
+	ldr     r0, =msm_pm_pa_to_va
+	mov     pc, r0
+msm_pm_pa_to_va:
+	sub     r0, r0, r2
+	/* Restore r1 in MMU table */
+	add     r3, r3, r0
+	str     r1, [r3]
+
+	mov     r0, #0
+	mcr     p15, 0, r0, c7, c10, 0 /* flush entire data cache */
+	mcr     p15, 0, r0, c7, c10, 4 /* dsb */
+	mcr     p15, 0, r0, c7, c5, 4  /* isb */
+	mcr     p15, 0, r0, c8, c7, 0  /* invalidate entire unified TLB */
+	mcr     p15, 0, r0, c7, c5, 6  /* invalidate entire branch target
+					* cache */
+	mcr     p15, 0, r0, c7, c7, 0  /* invalidate both data and instruction
+					* cache */
+	mcr     p15, 0, r0, c7, c10, 4 /* dsb */
+	mcr     p15, 0, r0, c7, c5, 4  /* isb */
+
+	mov     r0, #1
+	mov     pc, lr
+	nop
+	nop
+	nop
+	nop
+	nop
+1:	b       1b
+
+
+	.data
+
+saved_state:
+	.space  4 * 11 /* r4-14 */
+	.space  4 * 4  /* cp15 - MMU control, ttb, dacr, context ID */
+#if defined(CONFIG_OPROFILE)
+	.space  4 * 4  /* more cp15 - pmnc, ccnt, pmn0, pmn1 */
+#endif
+	.space  4	/* cacr */
+saved_state_end:
+
diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S
new file mode 100644
index 0000000..b75f76f
--- /dev/null
+++ b/arch/arm/mach-msm/idle-v7.S
@@ -0,0 +1,309 @@
+/*
+ * Idle processing for ARMv7-based Qualcomm SoCs.
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2009, 2011-2012 Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/linkage.h>
+#include <linux/threads.h>
+#include <asm/assembler.h>
+
+#include "idle.h"
+#include "idle-macros.S"
+
+#ifdef CONFIG_ARCH_MSM_KRAIT
+#define SCM_SVC_BOOT 0x1
+#define SCM_CMD_TERMINATE_PC 0x2
+#endif
+
+ENTRY(msm_arch_idle)
+	wfi
+#ifdef CONFIG_ARCH_MSM8X60
+	mrc	p14, 1, r1, c1, c5, 4 /* read ETM PDSR to clear sticky bit */
+	mrc     p14, 0, r1, c1, c5, 4 /* read DBG PRSR to clear sticky bit */
+	isb
+#endif
+	bx	lr
+
+ENTRY(msm_pm_collapse)
+#if defined(CONFIG_MSM_FIQ_SUPPORT)
+	cpsid   f
+#endif
+
+	ldr     r0, =msm_saved_state	/* address of msm_saved_state ptr */
+	ldr	r0, [r0]		/* load ptr */
+#if (NR_CPUS >= 2)
+	mrc	p15, 0, r1, c0, c0, 5	/* MPIDR */
+	ands	r1, r1, #15		/* What CPU am I */
+	mov	r2, #CPU_SAVED_STATE_SIZE
+	mul	r1, r1, r2
+	add	r0, r0, r1
+#endif
+
+	stmia   r0!, {r4-r14}
+	mrc     p15, 0, r1, c1, c0, 0 /* MMU control */
+	mrc     p15, 0, r2, c2, c0, 0 /* TTBR0 */
+	mrc     p15, 0, r3, c3, c0, 0 /* dacr */
+#ifdef CONFIG_ARCH_MSM_SCORPION
+	/* This instruction is not valid for non scorpion processors */
+	mrc     p15, 3, r4, c15, c0, 3 /* L2CR1 is the L2 cache control reg 1 */
+#endif
+	mrc     p15, 0, r5, c10, c2, 0 /* PRRR */
+	mrc     p15, 0, r6, c10, c2, 1 /* NMRR */
+	mrc     p15, 0, r7, c1, c0, 1 /* ACTLR */
+	mrc     p15, 0, r8, c2, c0, 1 /* TTBR1 */
+	mrc     p15, 0, r9, c13, c0, 3 /* TPIDRURO */
+	mrc     p15, 0, ip, c13, c0, 1 /* context ID */
+	stmia   r0!, {r1-r9, ip}
+#ifdef CONFIG_MSM_CPU_AVS
+	mrc     p15, 7, r1, c15, c1, 7 /* AVSCSR is the Adaptive Voltage Scaling
+	                                * Control and Status Register */
+	mrc     p15, 7, r2, c15, c0, 6 /* AVSDSCR is the Adaptive Voltage
+	                                * Scaling Delay Synthesizer Control
+					* Register */
+#ifndef CONFIG_ARCH_MSM_KRAIT
+	mrc     p15, 7, r3, c15, c1, 0 /* TSCSR is the Temperature Status and
+	                                * Control Register
+					*/
+#endif
+
+	stmia   r0!, {r1-r3}
+#endif
+
+#ifdef CONFIG_MSM_JTAG
+	bl      msm_jtag_save_state
+#endif
+
+	ldr	r0, =msm_pm_flush_l2_flag
+	ldr	r0, [r0]
+	mov	r1, #0
+	mcr	p15, 2, r1, c0, c0, 0 /*CCSELR*/
+	isb
+	mrc	p15, 1, r1, c0, c0, 0 /*CCSIDR*/
+	mov	r2, #1
+	and	r1, r2, r1, ASR #30 /* Check if the cache is write back */
+	orr	r1, r0, r1
+	cmp	r1, #1
+	bne	skip
+	bl	v7_flush_dcache_all
+skip:
+#ifdef CONFIG_ARCH_MSM_KRAIT
+	ldr	r0, =SCM_SVC_BOOT
+	ldr	r1, =SCM_CMD_TERMINATE_PC
+	ldr	r2, =msm_pm_flush_l2_flag
+	ldr	r2, [r2]
+	bl	scm_call_atomic1
+#else
+	mrc     p15, 0, r4, c1, c0, 0    /* read current CR    */
+	bic     r0, r4, #(1 << 2)        /* clear dcache bit   */
+	bic     r0, r0, #(1 << 12)       /* clear icache bit   */
+	mcr     p15, 0, r0, c1, c0, 0    /* disable d/i cache  */
+	isb
+
+	SUSPEND_8x25_L2
+	SET_SMP_COHERENCY OFF
+	wfi
+	DELAY_8x25 300
+
+	mcr     p15, 0, r4, c1, c0, 0    /* restore d/i cache  */
+	isb
+	ENABLE_8x25_L2 /* enable only l2, no need to restore the reg back */
+	SET_SMP_COHERENCY ON
+#endif
+
+#if defined(CONFIG_MSM_FIQ_SUPPORT)
+	cpsie   f
+#endif
+#ifdef CONFIG_MSM_JTAG
+	bl	msm_jtag_restore_state
+#endif
+	ldr     r0, =msm_saved_state	/* address of msm_saved_state ptr */
+	ldr	r0, [r0]		/* load ptr */
+#if (NR_CPUS >= 2)
+	mrc	p15, 0, r1, c0, c0, 5	/* MPIDR */
+	ands	r1, r1, #15		/* What CPU am I */
+	mov	r2, #CPU_SAVED_STATE_SIZE
+	mul	r2, r2, r1
+	add	r0, r0, r2
+#endif
+	ldmfd   r0, {r4-r14}		 /* restore registers */
+	mov     r0, #0                   /* return power collapse failed */
+	bx      lr
+
+ENTRY(msm_pm_collapse_exit)
+#if 0 /* serial debug */
+	mov     r0, #0x80000016
+	mcr     p15, 0, r0, c15, c2, 4
+	mov     r0, #0xA9000000
+	add     r0, r0, #0x00A00000 /* UART1 */
+	/*add     r0, r0, #0x00C00000*/ /* UART3 */
+	mov     r1, #'A'
+	str     r1, [r0, #0x00C]
+#endif
+	ldr     r1, =msm_saved_state_phys
+	ldr     r2, =msm_pm_collapse_exit
+	adr     r3, msm_pm_collapse_exit
+	add     r1, r1, r3
+	sub     r1, r1, r2
+	ldr	r1, [r1]
+	add	r1, r1, #CPU_SAVED_STATE_SIZE
+#if (NR_CPUS >= 2)
+	mrc	p15, 0, r2, c0, c0, 5	/* MPIDR */
+	ands	r2, r2, #15		/* What CPU am I */
+	mov	r3, #CPU_SAVED_STATE_SIZE
+	mul	r2, r2, r3
+	add	r1, r1, r2
+#endif
+
+#ifdef CONFIG_MSM_CPU_AVS
+	ldmdb   r1!, {r2-r4}
+#ifndef CONFIG_ARCH_MSM_KRAIT
+	mcr     p15, 7, r4, c15, c1, 0 /* TSCSR */
+#endif
+	mcr     p15, 7, r3, c15, c0, 6 /* AVSDSCR */
+	mcr     p15, 7, r2, c15, c1, 7 /* AVSCSR */
+#endif
+	ldmdb   r1!, {r2-r11}
+	mcr     p15, 0, r4, c3, c0, 0 /* dacr */
+	mcr     p15, 0, r3, c2, c0, 0 /* TTBR0 */
+#ifdef CONFIG_ARCH_MSM_SCORPION
+	/* This instruction is not valid for non scorpion processors */
+	mcr     p15, 3, r5, c15, c0, 3 /* L2CR1 */
+#endif
+	mcr     p15, 0, r6, c10, c2, 0 /* PRRR */
+	mcr     p15, 0, r7, c10, c2, 1 /* NMRR */
+	mcr     p15, 0, r8, c1, c0, 1 /* ACTLR */
+	mcr     p15, 0, r9, c2, c0, 1 /* TTBR1 */
+	mcr     p15, 0, r10, c13, c0, 3 /* TPIDRURO */
+	mcr     p15, 0, r11, c13, c0, 1 /* context ID */
+	isb
+	ldmdb   r1!, {r4-r14}
+	ldr	r0, =msm_pm_pc_pgd
+	ldr	r1, =msm_pm_collapse_exit
+	adr	r3, msm_pm_collapse_exit
+	add	r0, r0, r3
+	sub	r0, r0, r1
+	ldr	r0, [r0]
+	mrc     p15, 0, r1, c2, c0, 0 /* save current TTBR0 */
+	and	r3, r1, #0x7f /* mask to get TTB flags */
+	orr	r0, r0, r3 /* add TTB flags to switch TTBR value */
+	mcr     p15, 0, r0, c2, c0, 0 /* temporary switch TTBR0 */
+	isb
+	mcr     p15, 0, r2, c1, c0, 0   /* MMU control */
+	isb
+msm_pm_mapped_pa:
+	/* Switch to virtual */
+	ldr     r0, =msm_pm_pa_to_va
+	mov     pc, r0
+msm_pm_pa_to_va:
+	mcr     p15, 0, r1, c2, c0, 0 /* restore TTBR0 */
+	isb
+	mcr     p15, 0, r3, c8, c7, 0   /* UTLBIALL */
+	mcr     p15, 0, r3, c7, c5, 6   /* BPIALL */
+	dsb
+	isb
+
+#ifdef CONFIG_ARCH_MSM_KRAIT
+	mrc	p15, 0, r1, c0, c0, 0
+	ldr	r3, =0xff00fc00
+	and	r3, r1, r3
+	ldr 	r1, =0x51000400
+	cmp	r3, r1
+	mrceq	p15, 7, r3, c15, c0, 2
+	biceq	r3, r3, #0x400
+	mcreq	p15, 7, r3, c15, c0, 2
+#else
+	RESUME_8x25_L2
+	SET_SMP_COHERENCY ON
+#endif
+
+#ifdef CONFIG_MSM_JTAG
+	stmfd   sp!, {lr}
+	bl      msm_jtag_restore_state
+	ldmfd   sp!, {lr}
+#endif
+	mov     r0, #1
+	bx      lr
+	nop
+	nop
+	nop
+	nop
+	nop
+1:	b       1b
+
+ENTRY(msm_pm_boot_entry)
+	mrc     p15, 0, r0, c0, c0, 5    /* MPIDR                          */
+	and     r0, r0, #15              /* what CPU am I                  */
+
+	ldr     r1, =msm_pm_boot_vector
+	ldr     r2, =msm_pm_boot_entry
+	adr     r3, msm_pm_boot_entry
+	add     r1, r1, r3               /* translate virt to phys addr    */
+	sub     r1, r1, r2
+
+	add     r1, r1, r0, LSL #2       /* locate boot vector for our cpu */
+	ldr     pc, [r1]                 /* jump                           */
+
+ENTRY(msm_pm_set_l2_flush_flag)
+	ldr r1, =msm_pm_flush_l2_flag
+	str r0, [r1]
+	bx lr
+
+	.data
+
+	.globl msm_pm_pc_pgd
+msm_pm_pc_pgd:
+	.long	0x0
+
+	.globl msm_saved_state
+msm_saved_state:
+	.long	0x0
+
+	.globl msm_saved_state_phys
+msm_saved_state_phys:
+	.long	0x0
+
+	.globl msm_pm_boot_vector
+msm_pm_boot_vector:
+	.space  4 * NR_CPUS
+
+	.globl target_type
+target_type:
+	.long  0x0
+
+	.globl apps_power_collapse
+apps_power_collapse:
+	.long 0x0
+
+	.globl l2x0_base_addr
+l2x0_base_addr:
+	.long 0x0
+
+/*
+ * Default the l2 flush flag to 1 so that caches are flushed during power
+ * collapse unless the  L2 driver decides to flush them only during L2
+ * Power collapse.
+ */
+msm_pm_flush_l2_flag:
+	.long 0x1
+
+/*
+ * Save & restore l2x0 registers while system is entering and resuming
+ * from Power Collapse.
+ * 1. aux_ctrl_save (0x0)
+ * 2. data_latency_ctrl (0x4)
+ * 3. prefetch control (0x8)
+ */
+l2x0_saved_ctrl_reg_val:
+	.space 4 * 3
diff --git a/arch/arm/mach-msm/idle.h b/arch/arm/mach-msm/idle.h
new file mode 100644
index 0000000..4abdd04
--- /dev/null
+++ b/arch/arm/mach-msm/idle.h
@@ -0,0 +1,62 @@
+/* Copyright (c) 2007-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
+ * 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 _ARCH_ARM_MACH_MSM_IDLE_H_
+#define _ARCH_ARM_MACH_MSM_IDLE_H_
+
+#ifdef CONFIG_MSM_CPU_AVS
+/* 11 general purpose registers (r4-r14), 10 cp15 registers, 3 AVS registers */
+#define CPU_SAVED_STATE_SIZE (4 * 11 + 4 * 10 + 4 * 3)
+#else
+/* 11 general purpose registers (r4-r14), 10 cp15 registers */
+#define CPU_SAVED_STATE_SIZE (4 * 11 + 4 * 10)
+#endif
+
+#define ON	1
+#define OFF	0
+#define TARGET_IS_8625	1
+#define POWER_COLLAPSED 1
+
+#ifndef __ASSEMBLY__
+
+int msm_arch_idle(void);
+int msm_pm_collapse(void);
+void msm_pm_collapse_exit(void);
+extern void *msm_saved_state;
+extern unsigned long msm_saved_state_phys;
+
+#ifdef CONFIG_CPU_V7
+void msm_pm_boot_entry(void);
+void msm_pm_set_l2_flush_flag(unsigned int flag);
+extern unsigned long msm_pm_pc_pgd;
+extern unsigned long msm_pm_boot_vector[NR_CPUS];
+extern uint32_t target_type;
+extern uint32_t apps_power_collapse;
+extern uint32_t *l2x0_base_addr;
+#else
+static inline void msm_pm_set_l2_flush_flag(unsigned int flag)
+{
+	/* empty */
+}
+static inline void msm_pm_boot_entry(void)
+{
+	/* empty */
+}
+static inline void msm_pm_write_boot_vector(unsigned int cpu,
+						unsigned long address)
+{
+	/* empty */
+}
+#endif
+#endif
+#endif
diff --git a/arch/arm/mach-msm/idle_stats.c b/arch/arm/mach-msm/idle_stats.c
new file mode 100644
index 0000000..f4d3a27
--- /dev/null
+++ b/arch/arm/mach-msm/idle_stats.c
@@ -0,0 +1,545 @@
+/* Copyright (c) 2010, 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/module.h>
+#include <linux/types.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/hrtimer.h>
+#include <linux/interrupt.h>
+#include <linux/ktime.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/sched.h>
+#include <asm/uaccess.h>
+
+#include "idle_stats.h"
+#include <mach/cpuidle.h>
+
+/******************************************************************************
+ * Debug Definitions
+ *****************************************************************************/
+
+enum {
+	MSM_IDLE_STATS_DEBUG_API = BIT(0),
+	MSM_IDLE_STATS_DEBUG_SIGNAL = BIT(1),
+	MSM_IDLE_STATS_DEBUG_MIGRATION = BIT(2),
+};
+
+static int msm_idle_stats_debug_mask;
+module_param_named(
+	debug_mask, msm_idle_stats_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
+);
+
+/******************************************************************************
+ * Driver Definitions
+ *****************************************************************************/
+
+#define MSM_IDLE_STATS_DRIVER_NAME "msm_idle_stats"
+
+static dev_t msm_idle_stats_dev_nr;
+static struct cdev msm_idle_stats_cdev;
+static struct class *msm_idle_stats_class;
+
+/******************************************************************************
+ * Device Definitions
+ *****************************************************************************/
+
+struct msm_idle_stats_device {
+	unsigned int cpu;
+	struct mutex mutex;
+	struct notifier_block notifier;
+
+	int64_t collection_expiration;
+	struct msm_idle_stats stats;
+	struct hrtimer timer;
+
+	wait_queue_head_t wait_q;
+	atomic_t collecting;
+};
+
+static DEFINE_SPINLOCK(msm_idle_stats_devs_lock);
+static DEFINE_PER_CPU(struct msm_idle_stats_device *, msm_idle_stats_devs);
+
+/******************************************************************************
+ *
+ *****************************************************************************/
+
+static inline int64_t msm_idle_stats_bound_interval(int64_t interval)
+{
+	if (interval <= 0)
+		return 1;
+
+	if (interval > UINT_MAX)
+		return UINT_MAX;
+
+	return interval;
+}
+
+static enum hrtimer_restart msm_idle_stats_timer(struct hrtimer *timer)
+{
+	struct msm_idle_stats_device *stats_dev;
+	unsigned int cpu;
+	int64_t now;
+	int64_t interval;
+
+	stats_dev = container_of(timer, struct msm_idle_stats_device, timer);
+	cpu = get_cpu();
+
+	if (cpu != stats_dev->cpu) {
+		if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_MIGRATION)
+			pr_info("%s: timer migrated from cpu%u to cpu%u\n",
+				__func__, stats_dev->cpu, cpu);
+
+		stats_dev->stats.event = MSM_IDLE_STATS_EVENT_TIMER_MIGRATED;
+		goto timer_exit;
+	}
+
+	now = ktime_to_us(ktime_get());
+	interval = now - stats_dev->stats.last_busy_start;
+
+	if (stats_dev->stats.busy_timer > 0 &&
+			interval >= stats_dev->stats.busy_timer - 1)
+		stats_dev->stats.event =
+			MSM_IDLE_STATS_EVENT_BUSY_TIMER_EXPIRED;
+	else
+		stats_dev->stats.event =
+			MSM_IDLE_STATS_EVENT_COLLECTION_TIMER_EXPIRED;
+
+timer_exit:
+	atomic_set(&stats_dev->collecting, 0);
+	wake_up_interruptible(&stats_dev->wait_q);
+
+	put_cpu();
+	return HRTIMER_NORESTART;
+}
+
+static void msm_idle_stats_pre_idle(struct msm_idle_stats_device *stats_dev)
+{
+	int64_t now;
+	int64_t interval;
+
+	if (smp_processor_id() != stats_dev->cpu) {
+		WARN_ON(1);
+		return;
+	}
+
+	if (!atomic_read(&stats_dev->collecting))
+		return;
+
+	hrtimer_cancel(&stats_dev->timer);
+
+	now = ktime_to_us(ktime_get());
+	interval = now - stats_dev->stats.last_busy_start;
+	interval = msm_idle_stats_bound_interval(interval);
+
+	stats_dev->stats.busy_intervals[stats_dev->stats.nr_collected]
+		= (__u32) interval;
+	stats_dev->stats.last_idle_start = now;
+}
+
+static void msm_idle_stats_post_idle(struct msm_idle_stats_device *stats_dev)
+{
+	int64_t now;
+	int64_t interval;
+	int64_t timer_interval;
+	int rc;
+
+	if (smp_processor_id() != stats_dev->cpu) {
+		WARN_ON(1);
+		return;
+	}
+
+	if (!atomic_read(&stats_dev->collecting))
+		return;
+
+	now = ktime_to_us(ktime_get());
+	interval = now - stats_dev->stats.last_idle_start;
+	interval = msm_idle_stats_bound_interval(interval);
+
+	stats_dev->stats.idle_intervals[stats_dev->stats.nr_collected]
+		= (__u32) interval;
+	stats_dev->stats.nr_collected++;
+	stats_dev->stats.last_busy_start = now;
+
+	if (stats_dev->stats.nr_collected >= MSM_IDLE_STATS_NR_MAX_INTERVALS) {
+		stats_dev->stats.event = MSM_IDLE_STATS_EVENT_COLLECTION_FULL;
+		goto post_idle_collection_done;
+	}
+
+	timer_interval = stats_dev->collection_expiration - now;
+	if (timer_interval <= 0) {
+		stats_dev->stats.event =
+			MSM_IDLE_STATS_EVENT_COLLECTION_TIMER_EXPIRED;
+		goto post_idle_collection_done;
+	}
+
+	if (stats_dev->stats.busy_timer > 0 &&
+			timer_interval > stats_dev->stats.busy_timer)
+		timer_interval = stats_dev->stats.busy_timer;
+
+	rc = hrtimer_start(&stats_dev->timer,
+		ktime_set(0, timer_interval * 1000), HRTIMER_MODE_REL_PINNED);
+	WARN_ON(rc);
+
+	return;
+
+post_idle_collection_done:
+	atomic_set(&stats_dev->collecting, 0);
+	wake_up_interruptible(&stats_dev->wait_q);
+}
+
+static int msm_idle_stats_notified(struct notifier_block *nb,
+	unsigned long val, void *v)
+{
+	struct msm_idle_stats_device *stats_dev = container_of(
+				nb, struct msm_idle_stats_device, notifier);
+
+	if (val == MSM_CPUIDLE_STATE_EXIT)
+		msm_idle_stats_post_idle(stats_dev);
+	else
+		msm_idle_stats_pre_idle(stats_dev);
+
+	return 0;
+}
+
+static int msm_idle_stats_collect(struct file *filp,
+				  unsigned int cmd, unsigned long arg)
+{
+	struct msm_idle_stats_device *stats_dev;
+	struct msm_idle_stats *stats;
+	int rc;
+
+	stats_dev = (struct msm_idle_stats_device *) filp->private_data;
+	stats = &stats_dev->stats;
+
+	rc = mutex_lock_interruptible(&stats_dev->mutex);
+	if (rc) {
+		if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_SIGNAL)
+			pr_info("%s: interrupted while waiting on device "
+				"mutex\n", __func__);
+
+		rc = -EINTR;
+		goto collect_exit;
+	}
+
+	if (atomic_read(&stats_dev->collecting)) {
+		pr_err("%s: inconsistent state\n", __func__);
+		rc = -EBUSY;
+		goto collect_unlock_exit;
+	}
+
+	rc = copy_from_user(stats, (void *)arg, sizeof(*stats));
+	if (rc) {
+		rc = -EFAULT;
+		goto collect_unlock_exit;
+	}
+
+	if (stats->nr_collected >= MSM_IDLE_STATS_NR_MAX_INTERVALS ||
+			stats->busy_timer > MSM_IDLE_STATS_MAX_TIMER ||
+			stats->collection_timer > MSM_IDLE_STATS_MAX_TIMER) {
+		rc = -EINVAL;
+		goto collect_unlock_exit;
+	}
+
+	if (get_cpu() != stats_dev->cpu) {
+		put_cpu();
+		rc = -EACCES;
+		goto collect_unlock_exit;
+	}
+
+	/*
+	 * When collection_timer == 0, stop collecting at the next
+	 * post idle.
+	 */
+	stats_dev->collection_expiration =
+		ktime_to_us(ktime_get()) + stats->collection_timer;
+
+	/*
+	 * Enable collection before starting any timer.
+	 */
+	atomic_set(&stats_dev->collecting, 1);
+
+	/*
+	 * When busy_timer == 0, do not set any busy timer.
+	 */
+	if (stats->busy_timer > 0) {
+		rc = hrtimer_start(&stats_dev->timer,
+			ktime_set(0, stats->busy_timer * 1000),
+			HRTIMER_MODE_REL_PINNED);
+		WARN_ON(rc);
+	}
+
+	put_cpu();
+	if (wait_event_interruptible(stats_dev->wait_q,
+			!atomic_read(&stats_dev->collecting))) {
+		if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_SIGNAL)
+			pr_info("%s: interrupted while waiting on "
+				"collection\n", __func__);
+
+		hrtimer_cancel(&stats_dev->timer);
+		atomic_set(&stats_dev->collecting, 0);
+
+		rc = -EINTR;
+		goto collect_unlock_exit;
+	}
+
+	stats->return_timestamp = ktime_to_us(ktime_get());
+
+	rc = copy_to_user((void *)arg, stats, sizeof(*stats));
+	if (rc) {
+		rc = -EFAULT;
+		goto collect_unlock_exit;
+	}
+
+collect_unlock_exit:
+	mutex_unlock(&stats_dev->mutex);
+
+collect_exit:
+	return rc;
+}
+
+static int msm_idle_stats_open(struct inode *inode, struct file *filp)
+{
+	struct msm_idle_stats_device *stats_dev;
+	int rc;
+
+	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
+		pr_info("%s: enter\n", __func__);
+
+	rc = nonseekable_open(inode, filp);
+	if (rc) {
+		pr_err("%s: failed to set nonseekable\n", __func__);
+		goto open_bail;
+	}
+
+	stats_dev = (struct msm_idle_stats_device *)
+			kzalloc(sizeof(*stats_dev), GFP_KERNEL);
+	if (!stats_dev) {
+		pr_err("%s: failed to allocate device struct\n", __func__);
+		rc = -ENOMEM;
+		goto open_bail;
+	}
+
+	stats_dev->cpu = MINOR(inode->i_rdev);
+	mutex_init(&stats_dev->mutex);
+	stats_dev->notifier.notifier_call = msm_idle_stats_notified;
+	hrtimer_init(&stats_dev->timer,
+			CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
+	stats_dev->timer.function = msm_idle_stats_timer;
+	init_waitqueue_head(&stats_dev->wait_q);
+	atomic_set(&stats_dev->collecting, 0);
+
+	filp->private_data = stats_dev;
+
+	/*
+	 * Make sure only one device exists per cpu.
+	 */
+	spin_lock(&msm_idle_stats_devs_lock);
+	if (per_cpu(msm_idle_stats_devs, stats_dev->cpu)) {
+		spin_unlock(&msm_idle_stats_devs_lock);
+		rc = -EBUSY;
+		goto open_free_bail;
+	}
+
+	per_cpu(msm_idle_stats_devs, stats_dev->cpu) = stats_dev;
+	spin_unlock(&msm_idle_stats_devs_lock);
+
+	rc = msm_cpuidle_register_notifier(stats_dev->cpu,
+						&stats_dev->notifier);
+	if (rc) {
+		pr_err("%s: failed to register idle notification\n", __func__);
+		goto open_null_bail;
+	}
+
+	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
+		pr_info("%s: done\n", __func__);
+	return 0;
+
+open_null_bail:
+	spin_lock(&msm_idle_stats_devs_lock);
+	per_cpu(msm_idle_stats_devs, stats_dev->cpu) = NULL;
+	spin_unlock(&msm_idle_stats_devs_lock);
+
+open_free_bail:
+	kfree(stats_dev);
+
+open_bail:
+	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
+		pr_info("%s: exit, %d\n", __func__, rc);
+	return rc;
+}
+
+static int msm_idle_stats_release(struct inode *inode, struct file *filp)
+{
+	struct msm_idle_stats_device *stats_dev;
+	int rc;
+
+	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
+		pr_info("%s: enter\n", __func__);
+
+	stats_dev = (struct msm_idle_stats_device *) filp->private_data;
+	rc = msm_cpuidle_unregister_notifier(stats_dev->cpu,
+						&stats_dev->notifier);
+	WARN_ON(rc);
+
+	spin_lock(&msm_idle_stats_devs_lock);
+	per_cpu(msm_idle_stats_devs, stats_dev->cpu) = NULL;
+	spin_unlock(&msm_idle_stats_devs_lock);
+	filp->private_data = NULL;
+
+	hrtimer_cancel(&stats_dev->timer);
+	kfree(stats_dev);
+
+	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
+		pr_info("%s: done\n", __func__);
+	return 0;
+}
+
+static long msm_idle_stats_ioctl(struct file *filp, unsigned int cmd,
+				unsigned long arg)
+{
+	int rc;
+
+	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
+		pr_info("%s: enter\n", __func__);
+
+	switch (cmd) {
+	case MSM_IDLE_STATS_IOC_COLLECT:
+		rc = msm_idle_stats_collect(filp, cmd, arg);
+		break;
+
+	default:
+		rc = -ENOTTY;
+		break;
+	}
+
+	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
+		pr_info("%s: exit, %d\n", __func__, rc);
+	return rc;
+}
+
+/******************************************************************************
+ *
+ *****************************************************************************/
+
+static const struct file_operations msm_idle_stats_fops = {
+	.owner   = THIS_MODULE,
+	.open    = msm_idle_stats_open,
+	.release = msm_idle_stats_release,
+	.unlocked_ioctl   = msm_idle_stats_ioctl,
+};
+
+static int __init msm_idle_stats_init(void)
+{
+	unsigned int nr_cpus = num_possible_cpus();
+	struct device *dev;
+	int rc;
+	int i;
+
+	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
+		pr_info("%s: enter\n", __func__);
+
+	rc = alloc_chrdev_region(&msm_idle_stats_dev_nr,
+			0, nr_cpus, MSM_IDLE_STATS_DRIVER_NAME);
+	if (rc) {
+		pr_err("%s: failed to allocate device number, rc %d\n",
+			__func__, rc);
+		goto init_bail;
+	}
+
+	msm_idle_stats_class = class_create(THIS_MODULE,
+					MSM_IDLE_STATS_DRIVER_NAME);
+	if (IS_ERR(msm_idle_stats_class)) {
+		pr_err("%s: failed to create device class\n", __func__);
+		rc = -ENOMEM;
+		goto init_unreg_bail;
+	}
+
+	for (i = 0; i < nr_cpus; i++) {
+		dev = device_create(msm_idle_stats_class, NULL,
+				msm_idle_stats_dev_nr + i, NULL,
+				MSM_IDLE_STATS_DRIVER_NAME "%d", i);
+
+		if (!dev) {
+			pr_err("%s: failed to create device %d\n",
+				__func__, i);
+			rc = -ENOMEM;
+			goto init_remove_bail;
+		}
+	}
+
+	cdev_init(&msm_idle_stats_cdev, &msm_idle_stats_fops);
+	msm_idle_stats_cdev.owner = THIS_MODULE;
+
+	/*
+	 * Call cdev_add() last, after everything else is initialized and
+	 * the driver is ready to accept system calls.
+	 */
+	rc = cdev_add(&msm_idle_stats_cdev, msm_idle_stats_dev_nr, nr_cpus);
+	if (rc) {
+		pr_err("%s: failed to register char device, rc %d\n",
+			__func__, rc);
+		goto init_remove_bail;
+	}
+
+	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
+		pr_info("%s: done\n", __func__);
+	return 0;
+
+init_remove_bail:
+	for (i = i - 1; i >= 0; i--)
+		device_destroy(
+			msm_idle_stats_class, msm_idle_stats_dev_nr + i);
+
+	class_destroy(msm_idle_stats_class);
+
+init_unreg_bail:
+	unregister_chrdev_region(msm_idle_stats_dev_nr, nr_cpus);
+
+init_bail:
+	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
+		pr_info("%s: exit, %d\n", __func__, rc);
+	return rc;
+}
+
+static void __exit msm_idle_stats_exit(void)
+{
+	unsigned int nr_cpus = num_possible_cpus();
+	int i;
+
+	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
+		pr_info("%s: enter\n", __func__);
+
+	cdev_del(&msm_idle_stats_cdev);
+
+	for (i = nr_cpus - 1; i >= 0; i--)
+		device_destroy(
+			msm_idle_stats_class, msm_idle_stats_dev_nr + i);
+
+	class_destroy(msm_idle_stats_class);
+	unregister_chrdev_region(msm_idle_stats_dev_nr, nr_cpus);
+
+	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
+		pr_info("%s: done\n", __func__);
+}
+
+module_init(msm_idle_stats_init);
+module_exit(msm_idle_stats_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("idle stats driver");
+MODULE_VERSION("1.0");
diff --git a/arch/arm/mach-msm/idle_stats.h b/arch/arm/mach-msm/idle_stats.h
new file mode 100644
index 0000000..6c8db1e
--- /dev/null
+++ b/arch/arm/mach-msm/idle_stats.h
@@ -0,0 +1,52 @@
+/* Copyright (c) 2010, 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 __ARCH_ARM_MACH_MSM_IDLE_STATS_H
+#define __ARCH_ARM_MACH_MSM_IDLE_STATS_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+enum msm_idle_stats_event {
+	MSM_IDLE_STATS_EVENT_BUSY_TIMER_EXPIRED = 1,
+	MSM_IDLE_STATS_EVENT_COLLECTION_TIMER_EXPIRED = 2,
+	MSM_IDLE_STATS_EVENT_COLLECTION_FULL = 3,
+	MSM_IDLE_STATS_EVENT_TIMER_MIGRATED = 4,
+};
+
+/*
+ * All time, timer, and time interval values are in units of
+ * microseconds unless stated otherwise.
+ */
+#define MSM_IDLE_STATS_NR_MAX_INTERVALS 100
+#define MSM_IDLE_STATS_MAX_TIMER 1000000
+
+struct msm_idle_stats {
+	__u32 busy_timer;
+	__u32 collection_timer;
+
+	__u32 busy_intervals[MSM_IDLE_STATS_NR_MAX_INTERVALS];
+	__u32 idle_intervals[MSM_IDLE_STATS_NR_MAX_INTERVALS];
+	__u32 nr_collected;
+	__s64 last_busy_start;
+	__s64 last_idle_start;
+
+	enum msm_idle_stats_event event;
+	__s64 return_timestamp;
+};
+
+#define MSM_IDLE_STATS_IOC_MAGIC  0xD8
+#define MSM_IDLE_STATS_IOC_COLLECT  \
+		_IOWR(MSM_IDLE_STATS_IOC_MAGIC, 1, struct msm_idle_stats)
+
+#endif  /* __ARCH_ARM_MACH_MSM_IDLE_STATS_H */
diff --git a/arch/arm/mach-msm/idle_stats_device.c b/arch/arm/mach-msm/idle_stats_device.c
new file mode 100644
index 0000000..01b464a
--- /dev/null
+++ b/arch/arm/mach-msm/idle_stats_device.c
@@ -0,0 +1,378 @@
+/* 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
+ * 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/sched.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/miscdevice.h>
+#include <linux/poll.h>
+#include <linux/uaccess.h>
+#include <linux/idle_stats_device.h>
+#include <linux/module.h>
+
+DEFINE_MUTEX(device_list_lock);
+LIST_HEAD(device_list);
+
+static ktime_t us_to_ktime(__u32 us)
+{
+	return ns_to_ktime((u64)us * NSEC_PER_USEC);
+}
+
+static struct msm_idle_stats_device *_device_from_minor(unsigned int minor)
+{
+	struct msm_idle_stats_device *device, *ret = NULL;
+
+
+	mutex_lock(&device_list_lock);
+	list_for_each_entry(device, &device_list, list) {
+		if (minor == device->miscdev.minor) {
+			ret = device;
+			break;
+		}
+	}
+	mutex_unlock(&device_list_lock);
+	return ret;
+}
+
+void msm_idle_stats_update_event(struct msm_idle_stats_device *device,
+	__u32 event)
+{
+	__u32 wake_up = !device->stats->event;
+
+	device->stats->event |= event;
+	if (wake_up)
+		wake_up_interruptible(&device->wait);
+}
+EXPORT_SYMBOL(msm_idle_stats_update_event);
+
+static enum hrtimer_restart msm_idle_stats_busy_timer(struct hrtimer *timer)
+{
+	struct msm_idle_stats_device *device =
+		container_of(timer, struct msm_idle_stats_device, busy_timer);
+
+
+	/* This is the only case that the event is modified without a device
+	 * lock. However, since the timer is cancelled in the other cases we are
+	 * assured that we have exclusive access to the event at this time.
+	 */
+	hrtimer_set_expires(&device->busy_timer, us_to_ktime(0));
+	msm_idle_stats_update_event(device,
+		MSM_IDLE_STATS_EVENT_BUSY_TIMER_EXPIRED);
+	return HRTIMER_NORESTART;
+}
+
+static void start_busy_timer(struct msm_idle_stats_device *device,
+						     ktime_t relative_time)
+{
+	hrtimer_cancel(&device->busy_timer);
+	hrtimer_set_expires(&device->busy_timer, us_to_ktime(0));
+	if (!((device->stats->event &
+		   MSM_IDLE_STATS_EVENT_BUSY_TIMER_EXPIRED) ||
+	      (device->stats->event & MSM_IDLE_STATS_EVENT_COLLECTION_FULL))) {
+		if (ktime_to_us(relative_time) > 0) {
+			hrtimer_start(&device->busy_timer,
+						  relative_time,
+						  HRTIMER_MODE_REL);
+		}
+	}
+}
+
+static unsigned int msm_idle_stats_device_poll(struct file *file,
+						poll_table *wait)
+{
+	struct msm_idle_stats_device *device = file->private_data;
+	unsigned int mask = 0;
+
+	poll_wait(file, &device->wait, wait);
+	if (device->stats->event)
+		mask = POLLIN | POLLRDNORM;
+	return mask;
+}
+
+static void msm_idle_stats_add_sample(struct msm_idle_stats_device *device,
+		struct msm_idle_pulse *pulse)
+{
+	hrtimer_cancel(&device->busy_timer);
+	hrtimer_set_expires(&device->busy_timer, us_to_ktime(0));
+	if (device->stats->nr_collected >= MSM_IDLE_STATS_NR_MAX_INTERVALS) {
+		pr_warning("idle_stats_device: Overwriting samples\n");
+		device->stats->nr_collected = 0;
+	}
+	device->stats->pulse_chain[device->stats->nr_collected] = *pulse;
+	device->stats->nr_collected++;
+
+	if (device->stats->nr_collected == device->max_samples) {
+		msm_idle_stats_update_event(device,
+			MSM_IDLE_STATS_EVENT_COLLECTION_FULL);
+	} else if (device->stats->nr_collected ==
+				((device->max_samples * 3) / 4)) {
+		msm_idle_stats_update_event(device,
+			MSM_IDLE_STATS_EVENT_COLLECTION_NEARLY_FULL);
+	}
+}
+
+static long ioctl_read_stats(struct msm_idle_stats_device *device,
+		unsigned long arg)
+{
+	int remaining;
+	int requested;
+	struct msm_idle_pulse pulse;
+	struct msm_idle_read_stats *stats;
+	__s64 remaining_time =
+		ktime_to_us(hrtimer_get_remaining(&device->busy_timer));
+
+	device->get_sample(device, &pulse);
+	spin_lock(&device->lock);
+	hrtimer_cancel(&device->busy_timer);
+	stats = device->stats;
+	if (stats == &device->stats_vector[0])
+		device->stats = &device->stats_vector[1];
+	else
+		device->stats = &device->stats_vector[0];
+	device->stats->event = 0;
+	device->stats->nr_collected = 0;
+	spin_unlock(&device->lock);
+	if (stats->nr_collected >= device->max_samples) {
+		stats->nr_collected = device->max_samples;
+	} else {
+	    stats->pulse_chain[stats->nr_collected] = pulse;
+	    stats->nr_collected++;
+	    if (stats->nr_collected == device->max_samples)
+			stats->event |= MSM_IDLE_STATS_EVENT_COLLECTION_FULL;
+	    else if (stats->nr_collected ==
+				 ((device->max_samples * 3) / 4))
+			stats->event |=
+				MSM_IDLE_STATS_EVENT_COLLECTION_NEARLY_FULL;
+	}
+	if (remaining_time < 0) {
+		stats->busy_timer_remaining = 0;
+	} else {
+	    stats->busy_timer_remaining = remaining_time;
+		if ((__s64)stats->busy_timer_remaining != remaining_time)
+			stats->busy_timer_remaining = -1;
+	}
+	stats->return_timestamp = ktime_to_us(ktime_get());
+	requested =
+		((sizeof(*stats) - sizeof(stats->pulse_chain)) +
+		 (sizeof(stats->pulse_chain[0]) * stats->nr_collected));
+	remaining = copy_to_user((void __user *)arg, stats, requested);
+	if (remaining > 0)
+		return -EFAULT;
+
+	return 0;
+}
+
+static long ioctl_write_stats(struct msm_idle_stats_device *device,
+		unsigned long arg)
+{
+	struct msm_idle_write_stats stats;
+	int remaining;
+	int ret = 0;
+
+	remaining = copy_from_user(&stats,  (void __user *) arg, sizeof(stats));
+	if (remaining > 0) {
+		ret = -EFAULT;
+	} else {
+	    spin_lock(&device->lock);
+	    device->busy_timer_interval = us_to_ktime(stats.next_busy_timer);
+	    if (ktime_to_us(device->idle_start) == 0)
+			start_busy_timer(device, us_to_ktime(stats.busy_timer));
+		if ((stats.max_samples > 0) &&
+			(stats.max_samples <= MSM_IDLE_STATS_NR_MAX_INTERVALS))
+			device->max_samples = stats.max_samples;
+	    spin_unlock(&device->lock);
+	}
+	return ret;
+}
+
+void msm_idle_stats_prepare_idle_start(struct msm_idle_stats_device *device)
+{
+	spin_lock(&device->lock);
+	hrtimer_cancel(&device->busy_timer);
+	spin_unlock(&device->lock);
+}
+EXPORT_SYMBOL(msm_idle_stats_prepare_idle_start);
+
+void msm_idle_stats_abort_idle_start(struct msm_idle_stats_device *device)
+{
+	spin_lock(&device->lock);
+	if (ktime_to_us(hrtimer_get_expires(&device->busy_timer)) > 0)
+		hrtimer_restart(&device->busy_timer);
+	spin_unlock(&device->lock);
+}
+EXPORT_SYMBOL(msm_idle_stats_abort_idle_start);
+
+void msm_idle_stats_idle_start(struct msm_idle_stats_device *device)
+{
+	spin_lock(&device->lock);
+	hrtimer_cancel(&device->busy_timer);
+	device->idle_start = ktime_get();
+	if (ktime_to_us(hrtimer_get_expires(&device->busy_timer)) > 0) {
+		device->remaining_time =
+				hrtimer_get_remaining(&device->busy_timer);
+		if (ktime_to_us(device->remaining_time) <= 0)
+			device->remaining_time = us_to_ktime(0);
+	} else {
+		device->remaining_time = us_to_ktime(0);
+	}
+	spin_unlock(&device->lock);
+}
+EXPORT_SYMBOL(msm_idle_stats_idle_start);
+
+void msm_idle_stats_idle_end(struct msm_idle_stats_device *device,
+				struct msm_idle_pulse *pulse)
+{
+	int tmp;
+	u32 idle_time = 0;
+	spin_lock(&device->lock);
+	if (ktime_to_us(device->idle_start) != 0) {
+		idle_time = ktime_to_us(ktime_get())
+			- ktime_to_us(device->idle_start);
+		device->idle_start = us_to_ktime(0);
+	    msm_idle_stats_add_sample(device, pulse);
+		if (device->stats->event &
+			MSM_IDLE_STATS_EVENT_BUSY_TIMER_EXPIRED) {
+			device->stats->event &=
+				~MSM_IDLE_STATS_EVENT_BUSY_TIMER_EXPIRED;
+			msm_idle_stats_update_event(device,
+				MSM_IDLE_STATS_EVENT_BUSY_TIMER_EXPIRED_RESET);
+		} else if (ktime_to_us(device->busy_timer_interval) > 0) {
+			ktime_t busy_timer = device->busy_timer_interval;
+			/* if it is serialized, it would be full busy,
+			 * checking 80%
+			 */
+			if ((pulse->wait_interval*5 >= idle_time*4) &&
+				(ktime_to_us(device->remaining_time) > 0) &&
+				(ktime_to_us(device->remaining_time) <
+				 ktime_to_us(busy_timer)))
+				busy_timer = device->remaining_time;
+		    start_busy_timer(device, busy_timer);
+		    /* If previous busy interval exceeds the current submit,
+		     * raise a busy timer expired event intentionally.
+		     */
+		    tmp = device->stats->nr_collected - 1;
+		    if (tmp > 0) {
+			if ((device->stats->pulse_chain[tmp - 1].busy_start_time
+			+ device->stats->pulse_chain[tmp - 1].busy_interval) >
+			  device->stats->pulse_chain[tmp].busy_start_time)
+				msm_idle_stats_update_event(device,
+				   MSM_IDLE_STATS_EVENT_BUSY_TIMER_EXPIRED);
+		    }
+		}
+	}
+	spin_unlock(&device->lock);
+}
+EXPORT_SYMBOL(msm_idle_stats_idle_end);
+
+static long msm_idle_stats_device_ioctl(struct file *file, unsigned int cmd,
+		unsigned long arg)
+{
+	struct msm_idle_stats_device *device = file->private_data;
+	int ret;
+
+	switch (cmd) {
+	case MSM_IDLE_STATS_IOC_READ_STATS:
+		ret = ioctl_read_stats(device, arg);
+		break;
+	case MSM_IDLE_STATS_IOC_WRITE_STATS:
+		ret = ioctl_write_stats(device, arg);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int msm_idle_stats_device_release
+			  (struct inode *inode, struct file *filep)
+{
+	return 0;
+}
+
+static int msm_idle_stats_device_open(struct inode *inode, struct file *filep)
+{
+	struct msm_idle_stats_device *device;
+
+
+	device = _device_from_minor(iminor(inode));
+
+	if (device == NULL)
+		return -EPERM;
+
+	filep->private_data = device;
+	return 0;
+}
+
+static const struct file_operations msm_idle_stats_fops = {
+	.open = msm_idle_stats_device_open,
+	.release = msm_idle_stats_device_release,
+	.unlocked_ioctl = msm_idle_stats_device_ioctl,
+	.poll = msm_idle_stats_device_poll,
+};
+
+int msm_idle_stats_register_device(struct msm_idle_stats_device *device)
+{
+	int ret = -ENOMEM;
+
+	spin_lock_init(&device->lock);
+	init_waitqueue_head(&device->wait);
+	hrtimer_init(&device->busy_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	device->busy_timer.function = msm_idle_stats_busy_timer;
+
+	device->stats_vector[0].event         = 0;
+	device->stats_vector[0].nr_collected  = 0;
+	device->stats_vector[1].event         = 0;
+	device->stats_vector[1].nr_collected  = 0;
+	device->stats = &device->stats_vector[0];
+	device->busy_timer_interval = us_to_ktime(0);
+	device->max_samples = MSM_IDLE_STATS_NR_MAX_INTERVALS;
+
+	mutex_lock(&device_list_lock);
+	list_add(&device->list, &device_list);
+	mutex_unlock(&device_list_lock);
+
+	device->miscdev.minor = MISC_DYNAMIC_MINOR;
+	device->miscdev.name = device->name;
+	device->miscdev.fops = &msm_idle_stats_fops;
+
+	ret = misc_register(&device->miscdev);
+
+	if (ret)
+		goto err_list;
+
+	return ret;
+
+err_list:
+	mutex_lock(&device_list_lock);
+	list_del(&device->list);
+	mutex_unlock(&device_list_lock);
+	return ret;
+}
+EXPORT_SYMBOL(msm_idle_stats_register_device);
+
+int msm_idle_stats_deregister_device(struct msm_idle_stats_device *device)
+{
+	if (device == NULL)
+		return 0;
+
+	mutex_lock(&device_list_lock);
+	spin_lock(&device->lock);
+	hrtimer_cancel(&device->busy_timer);
+	list_del(&device->list);
+	spin_unlock(&device->lock);
+	mutex_unlock(&device_list_lock);
+
+	return misc_deregister(&device->miscdev);
+}
+EXPORT_SYMBOL(msm_idle_stats_deregister_device);
diff --git a/arch/arm/mach-msm/include/mach/audio_dma_msm8k.h b/arch/arm/mach-msm/include/mach/audio_dma_msm8k.h
new file mode 100644
index 0000000..1970d0b
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/audio_dma_msm8k.h
@@ -0,0 +1,221 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_AUDIO_DMA_H
+
+
+#define BANK_OFFSET			0x1000
+
+#define LPAIF_PCM_CTL_OFFSET		0x0000
+	#define CTRL_DATA_OE		(1 << 18)
+	#define RATE_8KHZ		(0 << 15)
+	#define RATE_16KHZ		(1 << 15)
+	#define RATE_32KHZ		(2 << 15)
+	#define RATE_64KHZ		(4 << 15)
+	#define RATE_128KHZ		(8 << 15)
+	#define RATE_256KHZ		(9 << 15)
+	#define PCM_LOOPBACK		(1 << 14)
+	#define SYNC_SRC_INT		(0 << 13)
+	#define SYNC_SRC_EXT		(1 << 13)
+	#define PCM_MODE		(0 << 12)
+	#define AUX_MODE		(1 << 12)
+	#define RPCM_WIDTH_8		(0 << 11)
+	#define RPCM_WIDTH_16		(1 << 11)
+	#define TPCM_WIDTH_8		(0 << 10)
+	#define TPCM_WIDTH_16		(1 << 10)
+	#define	RPCM_SLOT(x)		(x << 5)
+	#define	TPCM_SLOT(x)		 x
+
+#define LPAIF_I2S_CTL_OFFSET(x)		(0x0004 + (0x4 * x))
+	#define I2S_LOOPBACK		(1 << 15)
+	#define SPK_EN_DISABLE		(0 << 14)
+	#define SPK_EN_ENABLE		(1 << 14)
+	#define SPK_MODE_NONE		(0 << 10)
+	#define SPK_MODE_SD0		(1 << 10)
+	#define SPK_MODE_SD1		(2 << 10)
+	#define SPK_MODE_SD2		(3 << 10)
+	#define SPK_MODE_SD3		(4 << 10)
+	#define SPK_MODE_QUAD01		(5 << 10)
+	#define SPK_MODE_QUAD23		(6 << 10)
+	#define SPK_MODE_6CH		(7 << 10)
+	#define SPK_MODE_8CH		(8 << 10)
+	#define	SPK_MONO_STEREO		(0 << 9)
+	#define	SPK_MONO_MONO		(1 << 9)
+	#define MIC_EN_DISABLE		(0 << 8)
+	#define MIC_EN_ENABLE		(1 << 8)
+	#define MIC_MODE_NONE		(0 << 4)
+	#define MIC_MODE_SD0		(1 << 4)
+	#define MIC_MODE_SD1		(2 << 4)
+	#define MIC_MODE_SD2		(3 << 4)
+	#define MIC_MODE_SD3		(4 << 4)
+	#define MIC_MODE_QUAD01		(5 << 4)
+	#define MIC_MODE_QUAD23		(6 << 4)
+	#define MIC_MODE_6CH		(7 << 4)
+	#define MIC_MODE_8CH		(8 << 4)
+	#define	MIC_MONO_STEREO		(0 << 3)
+	#define	MIC_MONO_MONO		(1 << 3)
+	#define WS_SRC_INT		(0 << 2)
+	#define WS_SRC_EXT		(1 << 2)
+	#define BIT_WIDTH_16		(0 << 0)
+	#define BIT_WIDTH_24		(1 << 0)
+	#define BIT_WIDTH_32		(2 << 0)
+
+#define LPAIF_DMIC_CTL			0x0018
+	#define DMIC_EN_DISABLE		(0 << 4)
+	#define DMIC_EN_ENABLE		(1 << 4)
+	#define DMIC_MODE_NONE		(0 << 1)
+	#define DMIC_MODE_LEFT0		(1 << 1)
+	#define DMIC_MODE_RIGHT0	(2 << 1)
+	#define DMIC_MODE_LEFT1		(3 << 1)
+	#define DMIC_MODE_RIGHT1	(4 << 1)
+	#define DMIC_MODE_STEREO0	(5 << 1)
+	#define DMIC_MODE_STEREO1	(6 << 1)
+	#define DMIC_MODE_QUAD		(7 << 1)
+	#define BIT_WIDTH_DMIC_16	(0 << 0)
+	#define BIT_WIDTH_DMIC_20	(1 << 0)
+
+#define LPAIF_DMIC_VOL_CTL(x)		(0x001c + (0x4 * x))
+	#define UPDATE_STATUS_COMP	(0 << 20)
+	#define UPDATE_STATUS_PEND	(1 << 20) /* Timeout or Zero Crossing */
+	#define UPDATE_GAIN_NO		(0 << 19)
+	#define UPDATE_GAIN_YES		(1 << 19)
+	#define TX_HPF_BP_DC_BLOCK	(0 << 18)
+	#define TX_HPF_BP_BYPASS_DC_BLOCK	(1 << 18)
+	#define DMIC_GAIN_BP_GAIN	(0 << 17)
+	#define DMIC_GAIN_BP_BYPASS_GAIN	(1 << 17)
+	#define MUTE_EN_NORMAL		(0 << 16)
+	#define MUTE_EN_MUTE		(1 << 16)
+	#define TIMEOUT_VAL(x)		(x << 8)
+	#define DMIC_GAIN_MUL(x)	(x << 0)
+
+#define LPAIF_SPARE			0x0030
+
+#define LPAIF_WRDMA_LPBK_MIX		0x1000
+	#define WRDMA_LPBK_MIX_BLOCK(x)	(0 << (x - 5))
+	#define WRDMA_LPBK_MIX_ALLOW(x)	(1 << (x - 5))
+
+#define LPAIF_DEBUG_CTL			0x1004
+	#define TESTMODE_OFF		(0 << 4)
+	#define TESTMODE_ON		(1 << 4)
+	#define TESTSEL_CH0		(0 << 0)
+	#define TESTSEL_CH1		(1 << 0)
+	#define TESTSEL_CH2		(2 << 0)
+	#define TESTSEL_CH3		(3 << 0)
+	#define TESTSEL_CH4		(4 << 0)
+	#define TESTSEL_CH5		(5 << 0)
+	#define TESTSEL_CH6		(6 << 0)
+	#define TESTSEL_CH7		(7 << 0)
+	#define TESTSEL_CH8		(8 << 0)
+	#define TESTSEL_MIXER		(9 << 0)
+	#define TESTSEL_CODEC_SPKR	(10 << 0)
+	#define TESTSEL_CODEC_MIC	(11 << 0)
+	#define TESTSEL_MI2S		(12 << 0)
+	#define TESTSEL_SEC_SPKR	(13 << 0)
+	#define TESTSEL_SEC_MIC		(14 << 0)
+	#define TESTSEL_DMIC		(15 << 0)
+
+#define LPAIF_MIXER_CTL			0x2000
+	#define OVR_DETECTED_NO		(0 << 10)
+	#define OVR_DETECTED_YES	(1 << 10)
+	#define OVR_CLR_NO		(0 << 9)
+	#define OVR_CLR_YES		(1 << 9)
+	#define SAT_EN_DISABLE		(0 << 8)
+	#define SAT_EN_ENABLE		(1 << 8)
+	#define MIXER_BIT_WIDTH_8	(0 << 6)
+	#define MIXER_BIT_WIDTH_16	(1 << 6)
+	#define MIXER_BIT_WIDTH_24	(2 << 6)
+	#define MIXER_BIT_WIDTH_32	(3 << 6)
+	#define PORT1_CH_NONE		(0 << 3)
+	#define PORT1_CH_0		(1 << 3)
+	#define PORT1_CH_1		(2 << 3)
+	#define PORT1_CH_2		(3 << 3)
+	#define PORT1_CH_3		(4 << 3)
+	#define PORT1_CH_4		(5 << 3)
+	#define PORT0_CH_NONE		(0 << 0)
+	#define PORT0_CH_0		(1 << 0)
+	#define PORT0_CH_1		(2 << 0)
+	#define PORT0_CH_2		(3 << 0)
+	#define PORT0_CH_3		(4 << 0)
+	#define PORT0_CH_4		(5 << 0)
+
+#define DMA_IRQ_BASE			0x3000
+#define DMA_IRQ_INDEX(x)		(BANK_OFFSET * x)
+#define DMA_IRQ_ADDR(irq, addr)		(DMA_IRQ_BASE  \
+					+ DMA_IRQ_INDEX(irq) + addr)
+
+/* Audio Interrupt registers for DMA channel confuguration */
+#define LPAIF_IRQ_EN(x)			DMA_IRQ_ADDR(x, 0x00)
+#define LPAIF_IRQ_STAT(x)		DMA_IRQ_ADDR(x, 0x04)
+#define	LPAIF_IRQ_RAW_STAT(x)		DMA_IRQ_ADDR(x, 0x08)
+#define LPAIF_IRQ_CLEAR(x)		DMA_IRQ_ADDR(x, 0x0c)
+#define LPAIF_IRQ_FORCE(x)		DMA_IRQ_ADDR(x, 0x10)
+	#define PER_CH(x)		(1 << (3 * x))
+	#define UNDER_CH(x)		(2 << (3 * x))
+	#define ERR_CH(x)		(4 << (3 * x))
+
+/* Audio DMA registers for DMA channel confuguration */
+#define DMA_CH_CTL_BASE			0x6000
+#define DMA_CH_INDEX(ch)		(BANK_OFFSET * ch)
+
+#define DMA_CTRL_ADDR(ch, addr)		(DMA_CH_CTL_BASE \
+					+ (DMA_CH_INDEX(ch) + addr))
+
+#define LPAIF_DMA_CTL(x)		DMA_CTRL_ADDR(x, 0x00)
+	#define BURST_EN		(1 << 11)
+	#define WPSCNT_ONE		(0 << 8)
+	#define WPSCNT_TWO		(1 << 8)
+	#define WPSCNT_THREE		(2 << 8)
+	#define WPSCNT_FOUR		(3 << 8)
+	#define WPSCNT_SIX		(5 << 8)
+	#define WPSCNT_EIGHT		(7 << 8)
+	#define AUDIO_INTF_NONE		(0 << 4)
+	#define AUDIO_INTF_CODEC	(1 << 4)
+	#define AUDIO_INTF_PCM		(2 << 4)
+	#define AUDIO_INTF_SEC_I2S	(3 << 4)
+	#define AUDIO_INTF_MI2S		(4 << 4)
+	#define AUDIO_INTF_HDMI		(5 << 4)
+	#define AUDIO_INTF_MIXOUT	(6 << 4)
+	#define AUDIO_INTF_LOOPBACK1	(7 << 4)
+	#define AUDIO_INTF_LOOPBACK2    (8 << 4)
+	#define FIFO_WATERMRK(x)	((x & 0x7) << 1)
+	#define ENABLE			(1 << 0)
+
+#define LPAIF_DMA_BASE(x)		DMA_CTRL_ADDR(x, 0x04)
+	#define BASE_ADDR		(0xFFFFFFFF << 4)
+
+#define	LPAIF_DMA_BUFF_LEN(x)		DMA_CTRL_ADDR(x, 0x08)
+#define LPAIF_DMA_CURR_ADDR(x)		DMA_CTRL_ADDR(x, 0x0c)
+#define	LPAIF_DMA_PER_LEN(x)		DMA_CTRL_ADDR(x, 0x10)
+#define	LPAIF_DMA_PER_CNT(x)		DMA_CTRL_ADDR(x, 0x14)
+#define	LPAIF_DMA_FRM(x)		DMA_CTRL_ADDR(x, 0x18)
+#define LPAIF_DMA_FRMCLR(x)		DMA_CTRL_ADDR(x, 0x1c)
+#define LPAIF_DMA_SET_BUFF_CNT(x)	DMA_CTRL_ADDR(x, 0x20)
+#define	LPAIF_DMA_SET_PER_CNT(x)	DMA_CTRL_ADDR(x, 0x24)
+
+#define LPAIF_DMA_PER_CNT_PER_CNT_MASK		0x000FFFFF
+#define LPAIF_DMA_PER_CNT_PER_CNT_SHIFT		0
+#define LPAIF_DMA_PER_CNT_FIFO_WORDCNT_MASK	0x00F00000
+#define LPAIF_DMA_PER_CNT_FIFO_WORDCNT_SHIFT	20
+
+/* channel assignments */
+
+#define DMA_CH_0		0
+#define DMA_CH_1		1
+#define DMA_CH_2		2
+#define DMA_CH_3		3
+#define DMA_CH_4		4
+#define DMA_CH_5		5
+#define DMA_CH_6		6
+#define DMA_CH_7		7
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/bam_dmux.h b/arch/arm/mach-msm/include/mach/bam_dmux.h
new file mode 100644
index 0000000..f02a882
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/bam_dmux.h
@@ -0,0 +1,124 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/skbuff.h>
+
+#ifndef _BAM_DMUX_H
+#define _BAM_DMUX_H
+
+#define BAM_DMUX_CH_NAME_MAX_LEN	20
+
+enum {
+	BAM_DMUX_DATA_RMNET_0,
+	BAM_DMUX_DATA_RMNET_1,
+	BAM_DMUX_DATA_RMNET_2,
+	BAM_DMUX_DATA_RMNET_3,
+	BAM_DMUX_DATA_RMNET_4,
+	BAM_DMUX_DATA_RMNET_5,
+	BAM_DMUX_DATA_RMNET_6,
+	BAM_DMUX_DATA_RMNET_7,
+	BAM_DMUX_USB_RMNET_0,
+	BAM_DMUX_NUM_CHANNELS
+};
+
+/* event type enum */
+enum {
+	BAM_DMUX_RECEIVE, /* data is struct sk_buff */
+	BAM_DMUX_WRITE_DONE, /* data is struct sk_buff */
+	BAM_DMUX_UL_CONNECTED, /* data is null */
+	BAM_DMUX_UL_DISCONNECTED, /*data is null */
+};
+
+/*
+ * Open a bam_dmux logical channel
+ *     id - the logical channel to open
+ *     priv - private data pointer to be passed to the notify callback
+ *     notify - event callback function
+ *          priv - private data pointer passed to msm_bam_dmux_open()
+ *          event_type - type of event
+ *          data - data relevant to event.  May not be valid. See event_type
+ *                    enum for valid cases.
+ */
+#ifdef CONFIG_MSM_BAM_DMUX
+int msm_bam_dmux_open(uint32_t id, void *priv,
+		       void (*notify)(void *priv, int event_type,
+						unsigned long data));
+
+int msm_bam_dmux_close(uint32_t id);
+
+int msm_bam_dmux_write(uint32_t id, struct sk_buff *skb);
+
+int msm_bam_dmux_kickoff_ul_wakeup(void);
+
+int msm_bam_dmux_ul_power_vote(void);
+
+int msm_bam_dmux_ul_power_unvote(void);
+
+int msm_bam_dmux_is_ch_full(uint32_t id);
+
+int msm_bam_dmux_is_ch_low(uint32_t id);
+
+int msm_bam_dmux_reg_notify(void *priv,
+		       void (*notify)(void *priv, int event_type,
+						unsigned long data));
+#else
+static inline int msm_bam_dmux_open(uint32_t id, void *priv,
+		       void (*notify)(void *priv, int event_type,
+						unsigned long data))
+{
+	return -ENODEV;
+}
+
+static inline int msm_bam_dmux_close(uint32_t id)
+{
+	return -ENODEV;
+}
+
+static inline int msm_bam_dmux_write(uint32_t id, struct sk_buff *skb)
+{
+	return -ENODEV;
+}
+
+static inline int msm_bam_dmux_kickoff_ul_wakeup(void)
+{
+	return -ENODEV;
+}
+
+static inline int msm_bam_dmux_ul_power_vote(void)
+{
+	return -ENODEV;
+}
+
+static inline int msm_bam_dmux_ul_power_unvote(void)
+{
+	return -ENODEV;
+}
+
+static inline int msm_bam_dmux_is_ch_full(uint32_t id)
+{
+	return -ENODEV;
+}
+
+static inline int msm_bam_dmux_is_ch_low(uint32_t id)
+{
+	return -ENODEV;
+}
+
+static inline int msm_bam_dmux_reg_notify(void *priv,
+		       void (*notify)(void *priv, int event_type,
+						unsigned long data))
+{
+	return -ENODEV;
+}
+#endif
+#endif /* _BAM_DMUX_H */
diff --git a/arch/arm/mach-msm/include/mach/barriers.h b/arch/arm/mach-msm/include/mach/barriers.h
new file mode 100644
index 0000000..2d4792c
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/barriers.h
@@ -0,0 +1,22 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <mach/memory.h>
+
+#define mb() do \
+	{ \
+		dsb();\
+		outer_sync(); \
+		write_to_strongly_ordered_memory(); \
+	} while (0)
+#define rmb()	do { dmb(); write_to_strongly_ordered_memory(); } while (0)
+#define wmb()	mb()
diff --git a/arch/arm/mach-msm/include/mach/bcm_bt_lpm.h b/arch/arm/mach-msm/include/mach/bcm_bt_lpm.h
new file mode 100644
index 0000000..c224297
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/bcm_bt_lpm.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2009 Google, Inc.
+ *
+ * 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_BCM_BT_LPM_H
+#define __ASM_ARCH_BCM_BT_LPM_H
+
+#include <linux/serial_core.h>
+
+/* Uart driver must call this every time it beings TX, to ensure
+ * this driver keeps WAKE asserted during TX. Called with uart
+ * spinlock held. */
+extern void bcm_bt_lpm_exit_lpm_locked(struct uart_port *uport);
+
+struct bcm_bt_lpm_platform_data {
+	unsigned int gpio_wake;   /* CPU -> BCM wakeup gpio */
+	unsigned int gpio_host_wake;  /* BCM -> CPU wakeup gpio */
+
+	/* Callback to request the uart driver to clock off.
+         * Called with uart spinlock held. */
+	void (*request_clock_off_locked)(struct uart_port *uport);
+	/* Callback to request the uart driver to clock on.
+         * Called with uart spinlock held. */
+	void (*request_clock_on_locked)(struct uart_port *uport);
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/board-msm8660.h b/arch/arm/mach-msm/include/mach/board-msm8660.h
new file mode 100644
index 0000000..22e378c
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/board-msm8660.h
@@ -0,0 +1,41 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_BOARD_MSM8660_H
+#define __ARCH_ARM_MACH_MSM_BOARD_MSM8660_H
+
+#include <linux/mfd/pmic8058.h>
+#include <linux/mfd/pmic8901.h>
+#include <mach/irqs.h>
+
+/* Macros assume PMIC GPIOs start at 0 */
+#define PM8058_GPIO_BASE			NR_MSM_GPIOS
+#define PM8058_GPIO_PM_TO_SYS(pm_gpio)		(pm_gpio + PM8058_GPIO_BASE)
+#define PM8058_GPIO_SYS_TO_PM(sys_gpio)		(sys_gpio - PM8058_GPIO_BASE)
+#define PM8058_MPP_BASE			(PM8058_GPIO_BASE + PM8058_GPIOS)
+#define PM8058_MPP_PM_TO_SYS(pm_gpio)		(pm_gpio + PM8058_MPP_BASE)
+#define PM8058_MPP_SYS_TO_PM(sys_gpio)		(sys_gpio - PM8058_MPP_BASE)
+#define PM8058_IRQ_BASE				(NR_MSM_IRQS + NR_GPIO_IRQS)
+
+#define PM8901_MPP_BASE				(PM8058_GPIO_BASE + \
+						PM8058_GPIOS + PM8058_MPPS)
+#define PM8901_MPP_PM_TO_SYS(pm_gpio)		(pm_gpio + PM8901_MPP_BASE)
+#define PM8901_MPP_SYS_TO_PM(sys_gpio)		(sys_gpio - PM901_MPP_BASE)
+#define PM8901_IRQ_BASE				(PM8058_IRQ_BASE + \
+						NR_PMIC8058_IRQS)
+
+#ifdef CONFIG_MSM_CAMERA_V4L2
+extern struct msm_camera_board_info msm8x60_camera_board_info;
+void msm8x60_init_cam(void);
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 2ce8f1f..5e2eaf1 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -1,6 +1,7 @@
 /* arch/arm/mach-msm/include/mach/board.h
  *
  * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -18,33 +19,576 @@
 #define __ASM_ARCH_MSM_BOARD_H
 
 #include <linux/types.h>
-#include <mach/mmc.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/leds-pmic8058.h>
+#include <linux/clkdev.h>
+#include <linux/of_platform.h>
+#include <linux/msm_ssbi.h>
+#include <mach/msm_bus.h>
 
-/* platform device data structures */
-
-struct msm_acpu_clock_platform_data
-{
-	uint32_t acpu_switch_time_us;
-	uint32_t max_speed_delta_khz;
-	uint32_t vdd_switch_time_us;
-	unsigned long power_collapse_khz;
-	unsigned long wait_for_irq_khz;
+struct msm_camera_io_ext {
+	uint32_t mdcphy;
+	uint32_t mdcsz;
+	uint32_t appphy;
+	uint32_t appsz;
+	uint32_t camifpadphy;
+	uint32_t camifpadsz;
+	uint32_t csiphy;
+	uint32_t csisz;
+	uint32_t csiirq;
+	uint32_t csiphyphy;
+	uint32_t csiphysz;
+	uint32_t csiphyirq;
+	uint32_t ispifphy;
+	uint32_t ispifsz;
+	uint32_t ispifirq;
 };
 
+struct msm_camera_io_clk {
+	uint32_t mclk_clk_rate;
+	uint32_t vfe_clk_rate;
+};
+
+struct msm_cam_expander_info {
+	struct i2c_board_info const *board_info;
+	int bus_id;
+};
+
+struct msm_camera_device_platform_data {
+	int (*camera_gpio_on) (void);
+	void (*camera_gpio_off)(void);
+	struct msm_camera_io_ext ioext;
+	struct msm_camera_io_clk ioclk;
+	uint8_t csid_core;
+	uint8_t is_csiphy;
+	uint8_t is_csic;
+	uint8_t is_csid;
+	uint8_t is_ispif;
+	uint8_t is_vpe;
+	struct msm_bus_scale_pdata *cam_bus_scale_table;
+};
+enum msm_camera_csi_data_format {
+	CSI_8BIT,
+	CSI_10BIT,
+	CSI_12BIT,
+};
+struct msm_camera_csi_params {
+	enum msm_camera_csi_data_format data_format;
+	uint8_t lane_cnt;
+	uint8_t lane_assign;
+	uint8_t settle_cnt;
+	uint8_t dpcm_scheme;
+};
+
+#ifdef CONFIG_SENSORS_MT9T013
+struct msm_camera_legacy_device_platform_data {
+	int sensor_reset;
+	int sensor_pwd;
+	int vcm_pwd;
+	void (*config_gpio_on) (void);
+	void (*config_gpio_off)(void);
+};
+#endif
+
+#define MSM_CAMERA_FLASH_NONE 0
+#define MSM_CAMERA_FLASH_LED  1
+
+#define MSM_CAMERA_FLASH_SRC_PMIC (0x00000001<<0)
+#define MSM_CAMERA_FLASH_SRC_PWM  (0x00000001<<1)
+#define MSM_CAMERA_FLASH_SRC_CURRENT_DRIVER	(0x00000001<<2)
+#define MSM_CAMERA_FLASH_SRC_EXT     (0x00000001<<3)
+#define MSM_CAMERA_FLASH_SRC_LED (0x00000001<<3)
+#define MSM_CAMERA_FLASH_SRC_LED1 (0x00000001<<4)
+
+struct msm_camera_sensor_flash_pmic {
+	uint8_t num_of_src;
+	uint32_t low_current;
+	uint32_t high_current;
+	enum pmic8058_leds led_src_1;
+	enum pmic8058_leds led_src_2;
+	int (*pmic_set_current)(enum pmic8058_leds id, unsigned mA);
+};
+
+struct msm_camera_sensor_flash_pwm {
+	uint32_t freq;
+	uint32_t max_load;
+	uint32_t low_load;
+	uint32_t high_load;
+	uint32_t channel;
+};
+
+struct pmic8058_leds_platform_data;
+struct msm_camera_sensor_flash_current_driver {
+	uint32_t low_current;
+	uint32_t high_current;
+	const struct pmic8058_leds_platform_data *driver_channel;
+};
+
+enum msm_camera_ext_led_flash_id {
+	MAM_CAMERA_EXT_LED_FLASH_SC628A,
+	MAM_CAMERA_EXT_LED_FLASH_TPS61310,
+};
+
+struct msm_camera_sensor_flash_external {
+	uint32_t led_en;
+	uint32_t led_flash_en;
+	enum msm_camera_ext_led_flash_id flash_id;
+	struct msm_cam_expander_info *expander_info;
+};
+
+struct msm_camera_sensor_flash_led {
+	const char *led_name;
+	const int led_name_len;
+};
+
+struct msm_camera_sensor_flash_src {
+	int flash_sr_type;
+
+	union {
+		struct msm_camera_sensor_flash_pmic pmic_src;
+		struct msm_camera_sensor_flash_pwm pwm_src;
+		struct msm_camera_sensor_flash_current_driver
+			current_driver_src;
+		struct msm_camera_sensor_flash_external
+			ext_driver_src;
+		struct msm_camera_sensor_flash_led led_src;
+	} _fsrc;
+};
+
+struct msm_camera_sensor_flash_data {
+	int flash_type;
+	struct msm_camera_sensor_flash_src *flash_src;
+};
+
+struct msm_camera_sensor_strobe_flash_data {
+	uint8_t flash_trigger;
+	uint8_t flash_charge; /* pin for charge */
+	uint8_t flash_charge_done;
+	uint32_t flash_recharge_duration;
+	uint32_t irq;
+	spinlock_t spin_lock;
+	spinlock_t timer_lock;
+	int state;
+};
+
+enum msm_camera_type {
+	BACK_CAMERA_2D,
+	FRONT_CAMERA_2D,
+	BACK_CAMERA_3D,
+	BACK_CAMERA_INT_3D,
+};
+
+enum msm_sensor_type {
+	BAYER_SENSOR,
+	YUV_SENSOR,
+};
+
+enum camera_vreg_type {
+	REG_LDO,
+	REG_VS,
+};
+
+struct camera_vreg_t {
+	char *reg_name;
+	enum camera_vreg_type type;
+	int min_voltage;
+	int max_voltage;
+	int op_mode;
+};
+
+struct msm_gpio_set_tbl {
+	unsigned gpio;
+	unsigned long flags;
+	uint32_t delay;
+};
+
+struct msm_camera_csi_lane_params {
+	uint8_t csi_lane_assign;
+	uint8_t csi_lane_mask;
+};
+
+struct msm_camera_gpio_conf {
+	void *cam_gpiomux_conf_tbl;
+	uint8_t cam_gpiomux_conf_tbl_size;
+	struct gpio *cam_gpio_common_tbl;
+	uint8_t cam_gpio_common_tbl_size;
+	struct gpio *cam_gpio_req_tbl;
+	uint8_t cam_gpio_req_tbl_size;
+	struct msm_gpio_set_tbl *cam_gpio_set_tbl;
+	uint8_t cam_gpio_set_tbl_size;
+	uint32_t gpio_no_mux;
+	uint32_t *camera_off_table;
+	uint8_t camera_off_table_size;
+	uint32_t *camera_on_table;
+	uint8_t camera_on_table_size;
+};
+
+enum msm_camera_i2c_mux_mode {
+	MODE_R,
+	MODE_L,
+	MODE_DUAL
+};
+
+struct msm_camera_i2c_conf {
+	uint8_t use_i2c_mux;
+	struct platform_device *mux_dev;
+	enum msm_camera_i2c_mux_mode i2c_mux_mode;
+};
+
+struct msm_camera_sensor_platform_info {
+	int mount_angle;
+	int sensor_reset;
+	struct camera_vreg_t *cam_vreg;
+	int num_vreg;
+	int32_t (*ext_power_ctrl) (int enable);
+	struct msm_camera_gpio_conf *gpio_conf;
+	struct msm_camera_i2c_conf *i2c_conf;
+	struct msm_camera_csi_lane_params *csi_lane_params;
+};
+
+enum msm_camera_actuator_name {
+	MSM_ACTUATOR_MAIN_CAM_0,
+	MSM_ACTUATOR_MAIN_CAM_1,
+	MSM_ACTUATOR_MAIN_CAM_2,
+	MSM_ACTUATOR_MAIN_CAM_3,
+	MSM_ACTUATOR_MAIN_CAM_4,
+	MSM_ACTUATOR_MAIN_CAM_5,
+	MSM_ACTUATOR_WEB_CAM_0,
+	MSM_ACTUATOR_WEB_CAM_1,
+	MSM_ACTUATOR_WEB_CAM_2,
+};
+
+struct msm_actuator_info {
+	struct i2c_board_info const *board_info;
+	enum msm_camera_actuator_name cam_name;
+	int bus_id;
+	int vcm_pwd;
+	int vcm_enable;
+};
+
+struct msm_eeprom_info {
+	struct i2c_board_info const *board_info;
+	int bus_id;
+};
+
+struct msm_camera_sensor_info {
+	const char *sensor_name;
+	int sensor_reset_enable;
+	int sensor_reset;
+	int sensor_pwd;
+	int vcm_pwd;
+	int vcm_enable;
+	int mclk;
+	int flash_type;
+	struct msm_camera_sensor_platform_info *sensor_platform_info;
+	struct msm_camera_device_platform_data *pdata;
+	struct resource *resource;
+	uint8_t num_resources;
+	struct msm_camera_sensor_flash_data *flash_data;
+	int csi_if;
+	struct msm_camera_csi_params csi_params;
+	struct msm_camera_sensor_strobe_flash_data *strobe_flash_data;
+	char *eeprom_data;
+	enum msm_camera_type camera_type;
+	enum msm_sensor_type sensor_type;
+	struct msm_actuator_info *actuator_info;
+	int pmic_gpio_enable;
+	int (*sensor_lcd_gpio_onoff)(int on);
+	struct msm_eeprom_info *eeprom_info;
+};
+
+struct msm_camera_board_info {
+	struct i2c_board_info *board_info;
+	uint8_t num_i2c_board_info;
+};
+
+int msm_get_cam_resources(struct msm_camera_sensor_info *);
+
 struct clk_lookup;
 
-extern struct sys_timer msm_timer;
+struct snd_endpoint {
+	int id;
+	const char *name;
+};
 
+struct msm_snd_endpoints {
+	struct snd_endpoint *endpoints;
+	unsigned num;
+};
+
+#define MSM_MAX_DEC_CNT 14
+/* 7k target ADSP information */
+/* Bit 23:0, for codec identification like mp3, wav etc *
+ * Bit 27:24, for mode identification like tunnel, non tunnel*
+ * bit 31:28, for operation support like DM, DMA */
+enum msm_adspdec_concurrency {
+	MSM_ADSP_CODEC_WAV = 0,
+	MSM_ADSP_CODEC_ADPCM = 1,
+	MSM_ADSP_CODEC_MP3 = 2,
+	MSM_ADSP_CODEC_REALAUDIO = 3,
+	MSM_ADSP_CODEC_WMA = 4,
+	MSM_ADSP_CODEC_AAC = 5,
+	MSM_ADSP_CODEC_RESERVED = 6,
+	MSM_ADSP_CODEC_MIDI = 7,
+	MSM_ADSP_CODEC_YADPCM = 8,
+	MSM_ADSP_CODEC_QCELP = 9,
+	MSM_ADSP_CODEC_AMRNB = 10,
+	MSM_ADSP_CODEC_AMRWB = 11,
+	MSM_ADSP_CODEC_EVRC = 12,
+	MSM_ADSP_CODEC_WMAPRO = 13,
+	MSM_ADSP_MODE_TUNNEL = 24,
+	MSM_ADSP_MODE_NONTUNNEL = 25,
+	MSM_ADSP_MODE_LP = 26,
+	MSM_ADSP_OP_DMA = 28,
+	MSM_ADSP_OP_DM = 29,
+};
+
+struct msm_adspdec_info {
+	const char *module_name;
+	unsigned module_queueid;
+	int module_decid; /* objid */
+	unsigned nr_codec_support;
+};
+
+/* Carries information about number codec
+ * supported if same codec or different codecs
+ */
+struct dec_instance_table {
+	uint8_t max_instances_same_dec;
+	uint8_t max_instances_diff_dec;
+};
+
+struct msm_adspdec_database {
+	unsigned num_dec;
+	unsigned num_concurrency_support;
+	unsigned int *dec_concurrency_table; /* Bit masked entry to *
+					      *	represents codec, mode etc */
+	struct msm_adspdec_info  *dec_info_list;
+	struct dec_instance_table *dec_instance_list;
+};
+
+enum msm_mdp_hw_revision {
+	MDP_REV_20 = 1,
+	MDP_REV_22,
+	MDP_REV_30,
+	MDP_REV_303,
+	MDP_REV_31,
+	MDP_REV_40,
+	MDP_REV_41,
+	MDP_REV_42,
+	MDP_REV_43,
+	MDP_REV_44,
+};
+
+struct msm_panel_common_pdata {
+	uintptr_t hw_revision_addr;
+	int gpio;
+	bool bl_lock;
+	spinlock_t bl_spinlock;
+	int (*backlight_level)(int level, int max, int min);
+	int (*pmic_backlight)(int level);
+	int (*rotate_panel)(void);
+	int (*panel_num)(void);
+	void (*panel_config_gpio)(int);
+	int (*vga_switch)(int select_vga);
+	int *gpio_num;
+	int mdp_core_clk_rate;
+	unsigned num_mdp_clk;
+	int *mdp_core_clk_table;
+#ifdef CONFIG_MSM_BUS_SCALING
+	struct msm_bus_scale_pdata *mdp_bus_scale_table;
+#endif
+	int mdp_rev;
+	u32 ov0_wb_size;  /* overlay0 writeback size */
+	u32 ov1_wb_size;  /* overlay1 writeback size */
+	u32 mem_hid;
+	char cont_splash_enabled;
+};
+
+
+
+struct lcdc_platform_data {
+	int (*lcdc_gpio_config)(int on);
+	int (*lcdc_power_save)(int);
+	unsigned int (*lcdc_get_clk)(void);
+#ifdef CONFIG_MSM_BUS_SCALING
+	struct msm_bus_scale_pdata *bus_scale_table;
+#endif
+	int (*lvds_pixel_remap)(void);
+};
+
+struct tvenc_platform_data {
+	int poll;
+	int (*pm_vid_en)(int on);
+#ifdef CONFIG_MSM_BUS_SCALING
+	struct msm_bus_scale_pdata *bus_scale_table;
+#endif
+};
+
+struct mddi_platform_data {
+	int (*mddi_power_save)(int on);
+	int (*mddi_sel_clk)(u32 *clk_rate);
+	int (*mddi_client_power)(u32 client_id);
+};
+
+struct mipi_dsi_platform_data {
+	int vsync_gpio;
+	int (*dsi_power_save)(int on);
+	int (*dsi_client_reset)(void);
+	int (*get_lane_config)(void);
+	char (*splash_is_enabled)(void);
+	int target_type;
+};
+
+enum mipi_dsi_3d_ctrl {
+	FPGA_EBI2_INTF,
+	FPGA_SPI_INTF,
+};
+
+/* DSI PHY configuration */
+struct mipi_dsi_phy_ctrl {
+	uint32_t regulator[5];
+	uint32_t timing[12];
+	uint32_t ctrl[4];
+	uint32_t strength[4];
+	uint32_t pll[21];
+};
+
+struct mipi_dsi_panel_platform_data {
+	int fpga_ctrl_mode;
+	int fpga_3d_config_addr;
+	int *gpio;
+	struct mipi_dsi_phy_ctrl *phy_ctrl_settings;
+	char dlane_swap;
+	void (*dsi_pwm_cfg)(void);
+	char enable_wled_bl_ctrl;
+};
+
+struct lvds_panel_platform_data {
+	int *gpio;
+};
+
+#define PANEL_NAME_MAX_LEN 50
+struct msm_fb_platform_data {
+	int (*detect_client)(const char *name);
+	int mddi_prescan;
+	int (*allow_set_offset)(void);
+	char prim_panel_name[PANEL_NAME_MAX_LEN];
+	char ext_panel_name[PANEL_NAME_MAX_LEN];
+};
+
+struct msm_hdmi_platform_data {
+	int irq;
+	int (*cable_detect)(int insert);
+	int (*comm_power)(int on, int show);
+	int (*enable_5v)(int on);
+	int (*core_power)(int on, int show);
+	int (*cec_power)(int on);
+	int (*init_irq)(void);
+	bool (*check_hdcp_hw_support)(void);
+};
+
+struct msm_mhl_platform_data {
+	int irq;
+	int (*gpio_setup)(int on);
+	void (*reset_pin)(int on);
+};
+
+struct msm_i2c_platform_data {
+	int clk_freq;
+	uint32_t rmutex;
+	const char *rsl_id;
+	uint32_t pm_lat;
+	int pri_clk;
+	int pri_dat;
+	int aux_clk;
+	int aux_dat;
+	int src_clk_rate;
+	int use_gsbi_shared_mode;
+	void (*msm_i2c_config_gpio)(int iface, int config_type);
+};
+
+struct msm_i2c_ssbi_platform_data {
+	const char *rsl_id;
+	enum msm_ssbi_controller_type controller_type;
+};
+
+struct msm_vidc_platform_data {
+	int memtype;
+	u32 enable_ion;
+	int disable_dmx;
+	int disable_fullhd;
+	u32 cp_enabled;
+#ifdef CONFIG_MSM_BUS_SCALING
+	struct msm_bus_scale_pdata *vidc_bus_client_pdata;
+#endif
+	int cont_mode_dpb_count;
+};
+
+struct vcap_platform_data {
+	unsigned *gpios;
+	int num_gpios;
+	struct msm_bus_scale_pdata *bus_client_pdata;
+};
+
+#if defined(CONFIG_USB_PEHCI_HCD) || defined(CONFIG_USB_PEHCI_HCD_MODULE)
+struct isp1763_platform_data {
+	unsigned reset_gpio;
+	int (*setup_gpio)(int enable);
+};
+#endif
 /* common init routines for use by arch/arm/mach-msm/board-*.c */
 
-void __init msm_add_devices(void);
-void __init msm_map_common_io(void);
-void __init msm_init_irq(void);
-void __init msm_init_gpio(void);
-void __init msm_clock_init(struct clk_lookup *clock_tbl, unsigned num_clocks);
-void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *);
-int __init msm_add_sdcc(unsigned int controller,
-			struct msm_mmc_platform_data *plat,
-			unsigned int stat_irq, unsigned long stat_irq_flags);
+#ifdef CONFIG_OF_DEVICE
+void msm_copper_init(struct of_dev_auxdata **);
+#endif
+void msm_add_devices(void);
+void msm_copper_add_devices(void);
+void msm_copper_add_drivers(void);
+void msm_map_common_io(void);
+void msm_map_qsd8x50_io(void);
+void msm_map_msm8x60_io(void);
+void msm_map_msm8960_io(void);
+void msm_map_msm8930_io(void);
+void msm_map_apq8064_io(void);
+void msm_map_msm7x30_io(void);
+void msm_map_fsm9xxx_io(void);
+void msm_map_copper_io(void);
+void msm_map_msm8625_io(void);
+void msm_map_msm9625_io(void);
+void msm_init_irq(void);
+void msm_copper_init_irq(void);
+void vic_handle_irq(struct pt_regs *regs);
+void msm_copper_reserve(void);
+void msm_copper_very_early(void);
+void msm_copper_init_gpiomux(void);
+
+struct mmc_platform_data;
+int msm_add_sdcc(unsigned int controller,
+		struct mmc_platform_data *plat);
+
+void msm_pm_register_irqs(void);
+struct msm_usb_host_platform_data;
+int msm_add_host(unsigned int host,
+		struct msm_usb_host_platform_data *plat);
+#if defined(CONFIG_USB_FUNCTION_MSM_HSUSB) \
+	|| defined(CONFIG_USB_MSM_72K) || defined(CONFIG_USB_MSM_72K_MODULE)
+void msm_hsusb_set_vbus_state(int online);
+#else
+static inline void msm_hsusb_set_vbus_state(int online) {}
+#endif
+
+void msm_snddev_init(void);
+void msm_snddev_init_timpani(void);
+void msm_snddev_poweramp_on(void);
+void msm_snddev_poweramp_off(void);
+void msm_snddev_hsed_voltage_on(void);
+void msm_snddev_hsed_voltage_off(void);
+void msm_snddev_tx_route_config(void);
+void msm_snddev_tx_route_deconfig(void);
+
+extern unsigned int msm_shared_ram_phys; /* defined in arch/arm/mach-msm/io.c */
+
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/board_htc.h b/arch/arm/mach-msm/include/mach/board_htc.h
new file mode 100644
index 0000000..b537c91
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/board_htc.h
@@ -0,0 +1,78 @@
+/* arch/arm/mach-msm/include/mach/BOARD_HTC.h
+ * Copyright (C) 2007-2009 HTC Corporation.
+ * Author: Thomas Tsai <thomas_tsai@htc.com>
+ *
+ * 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_BOARD_HTC_H
+#define __ASM_ARCH_MSM_BOARD_HTC_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <asm/setup.h>
+
+struct msm_pmem_setting{
+	resource_size_t pmem_start;
+	resource_size_t pmem_size;
+	resource_size_t pmem_adsp_start;
+	resource_size_t pmem_adsp_size;
+	resource_size_t pmem_gpu0_start;
+	resource_size_t pmem_gpu0_size;
+	resource_size_t pmem_gpu1_start;
+	resource_size_t pmem_gpu1_size;
+	resource_size_t pmem_camera_start;
+	resource_size_t pmem_camera_size;
+	resource_size_t ram_console_start;
+	resource_size_t ram_console_size;
+};
+
+enum {
+	MSM_SERIAL_UART1	= 0,
+	MSM_SERIAL_UART2,
+	MSM_SERIAL_UART3,
+#ifdef CONFIG_SERIAL_MSM_HS
+	MSM_SERIAL_UART1DM,
+	MSM_SERIAL_UART2DM,
+#endif
+	MSM_SERIAL_NUM,
+};
+
+
+/* common init routines for use by arch/arm/mach-msm/board-*.c */
+
+void __init msm_add_usb_devices(void (*phy_reset) (void));
+void __init msm_add_mem_devices(struct msm_pmem_setting *setting);
+void __init msm_init_pmic_vibrator(void);
+
+struct mmc_platform_data;
+int __init msm_add_sdcc_devices(unsigned int controller, struct mmc_platform_data *plat);
+int __init msm_add_serial_devices(unsigned uart);
+
+#if defined(CONFIG_USB_FUNCTION_MSM_HSUSB)
+/* START: add USB connected notify function */
+struct t_usb_status_notifier{
+	struct list_head notifier_link;
+	const char *name;
+	void (*func)(int online);
+};
+	int usb_register_notifier(struct t_usb_status_notifier *);
+	static LIST_HEAD(g_lh_usb_notifier_list);
+/* END: add USB connected notify function */
+#endif
+
+int __init board_mfg_mode(void);
+int __init parse_tag_smi(const struct tag *tags);
+int __init parse_tag_hwid(const struct tag * tags);
+int __init parse_tag_skuid(const struct tag * tags);
+int parse_tag_engineerid(const struct tag * tags);
+
+char *board_serialno(void);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
new file mode 100644
index 0000000..47d9b5f
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -0,0 +1,701 @@
+/* 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
+ * 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 __ASM__ARCH_CAMERA_H
+#define __ASM__ARCH_CAMERA_H
+
+#include <linux/list.h>
+#include <linux/poll.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+#include <linux/wakelock.h>
+#include <linux/regulator/consumer.h>
+#include "linux/types.h"
+
+#include <mach/board.h>
+#include <media/msm_camera.h>
+#include <linux/ion.h>
+#include <mach/iommu_domains.h>
+
+#define CONFIG_MSM_CAMERA_DEBUG
+#ifdef CONFIG_MSM_CAMERA_DEBUG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+#else
+#define CDBG(fmt, args...) do { } while (0)
+#endif
+
+#define PAD_TO_2K(a, b) ((!b) ? a : (((a)+2047) & ~2047))
+
+#define MSM_CAMERA_MSG 0
+#define MSM_CAMERA_EVT 1
+#define NUM_WB_EXP_NEUTRAL_REGION_LINES 4
+#define NUM_WB_EXP_STAT_OUTPUT_BUFFERS  3
+#define NUM_AUTOFOCUS_MULTI_WINDOW_GRIDS 16
+#define NUM_STAT_OUTPUT_BUFFERS      3
+#define NUM_AF_STAT_OUTPUT_BUFFERS      3
+#define max_control_command_size 512
+#define CROP_LEN 36
+
+enum vfe_mode_of_operation{
+	VFE_MODE_OF_OPERATION_CONTINUOUS,
+	VFE_MODE_OF_OPERATION_SNAPSHOT,
+	VFE_MODE_OF_OPERATION_VIDEO,
+	VFE_MODE_OF_OPERATION_RAW_SNAPSHOT,
+	VFE_MODE_OF_OPERATION_ZSL,
+	VFE_MODE_OF_OPERATION_JPEG_SNAPSHOT,
+	VFE_LAST_MODE_OF_OPERATION_ENUM
+};
+
+enum msm_queue {
+	MSM_CAM_Q_CTRL,     /* control command or control command status */
+	MSM_CAM_Q_VFE_EVT,  /* adsp event */
+	MSM_CAM_Q_VFE_MSG,  /* adsp message */
+	MSM_CAM_Q_V4L2_REQ, /* v4l2 request */
+	MSM_CAM_Q_VPE_MSG,  /* vpe message */
+	MSM_CAM_Q_PP_MSG,  /* pp message */
+};
+
+enum vfe_resp_msg {
+	VFE_EVENT,
+	VFE_MSG_GENERAL,
+	VFE_MSG_SNAPSHOT,
+	VFE_MSG_OUTPUT_P,   /* preview (continuous mode ) */
+	VFE_MSG_OUTPUT_T,   /* thumbnail (snapshot mode )*/
+	VFE_MSG_OUTPUT_S,   /* main image (snapshot mode )*/
+	VFE_MSG_OUTPUT_V,   /* video   (continuous mode ) */
+	VFE_MSG_STATS_AEC,
+	VFE_MSG_STATS_AF,
+	VFE_MSG_STATS_AWB,
+	VFE_MSG_STATS_RS, /* 10 */
+	VFE_MSG_STATS_CS,
+	VFE_MSG_STATS_IHIST,
+	VFE_MSG_STATS_SKIN,
+	VFE_MSG_STATS_WE, /* AEC + AWB */
+	VFE_MSG_SYNC_TIMER0,
+	VFE_MSG_SYNC_TIMER1,
+	VFE_MSG_SYNC_TIMER2,
+	VFE_MSG_COMMON,
+	VFE_MSG_V32_START,
+	VFE_MSG_V32_START_RECORDING, /* 20 */
+	VFE_MSG_V32_CAPTURE,
+	VFE_MSG_V32_JPEG_CAPTURE,
+	VFE_MSG_OUTPUT_IRQ,
+	VFE_MSG_V2X_PREVIEW,
+	VFE_MSG_V2X_CAPTURE,
+	VFE_MSG_OUTPUT_PRIMARY,
+	VFE_MSG_OUTPUT_SECONDARY,
+};
+
+enum vpe_resp_msg {
+	VPE_MSG_GENERAL,
+	VPE_MSG_OUTPUT_V,   /* video   (continuous mode ) */
+	VPE_MSG_OUTPUT_ST_L,
+	VPE_MSG_OUTPUT_ST_R,
+};
+
+enum msm_stereo_state {
+	STEREO_VIDEO_IDLE,
+	STEREO_VIDEO_ACTIVE,
+	STEREO_SNAP_IDLE,
+	STEREO_SNAP_STARTED,
+	STEREO_SNAP_BUFFER1_PROCESSING,
+	STEREO_SNAP_BUFFER2_PROCESSING,
+	STEREO_RAW_SNAP_IDLE,
+	STEREO_RAW_SNAP_STARTED,
+};
+
+enum msm_ispif_intftype {
+	PIX0,
+	RDI0,
+	PIX1,
+	RDI1,
+	PIX2,
+	RDI2,
+};
+
+enum msm_ispif_vc {
+	VC0,
+	VC1,
+	VC2,
+	VC3,
+};
+
+enum msm_ispif_cid {
+	CID0,
+	CID1,
+	CID2,
+	CID3,
+	CID4,
+	CID5,
+	CID6,
+	CID7,
+	CID8,
+	CID9,
+	CID10,
+	CID11,
+	CID12,
+	CID13,
+	CID14,
+	CID15,
+};
+
+struct msm_ispif_params {
+	uint8_t intftype;
+	uint16_t cid_mask;
+	uint8_t csid;
+};
+
+struct msm_ispif_params_list {
+	uint32_t len;
+	struct msm_ispif_params params[3];
+};
+
+struct msm_vpe_phy_info {
+	uint32_t sbuf_phy;
+	uint32_t planar0_off;
+	uint32_t planar1_off;
+	uint32_t planar2_off;
+	uint32_t p0_phy;
+	uint32_t p1_phy;
+	uint32_t p2_phy;
+	uint8_t  output_id; /* VFE31_OUTPUT_MODE_PT/S/V */
+	uint32_t frame_id;
+};
+
+struct msm_camera_csid_vc_cfg {
+	uint8_t cid;
+	uint8_t dt;
+	uint8_t decode_format;
+};
+
+struct msm_camera_csid_lut_params {
+	uint8_t num_cid;
+	struct msm_camera_csid_vc_cfg *vc_cfg;
+};
+
+struct msm_camera_csid_params {
+	uint8_t lane_cnt;
+	uint8_t lane_assign;
+	struct msm_camera_csid_lut_params lut_params;
+};
+
+struct msm_camera_csiphy_params {
+	uint8_t lane_cnt;
+	uint8_t settle_cnt;
+	uint8_t lane_mask;
+};
+
+struct msm_camera_csi2_params {
+	struct msm_camera_csid_params csid_params;
+	struct msm_camera_csiphy_params csiphy_params;
+};
+
+#ifndef CONFIG_MSM_CAMERA_V4L2
+#define VFE31_OUTPUT_MODE_PT (0x1 << 0)
+#define VFE31_OUTPUT_MODE_S (0x1 << 1)
+#define VFE31_OUTPUT_MODE_V (0x1 << 2)
+#define VFE31_OUTPUT_MODE_P (0x1 << 3)
+#define VFE31_OUTPUT_MODE_T (0x1 << 4)
+#define VFE31_OUTPUT_MODE_P_ALL_CHNLS (0x1 << 5)
+#endif
+
+#define CSI_EMBED_DATA 0x12
+#define CSI_RESERVED_DATA_0 0x13
+#define CSI_YUV422_8  0x1E
+#define CSI_RAW8    0x2A
+#define CSI_RAW10   0x2B
+#define CSI_RAW12   0x2C
+
+#define CSI_DECODE_6BIT 0
+#define CSI_DECODE_8BIT 1
+#define CSI_DECODE_10BIT 2
+#define CSI_DECODE_DPCM_10_8_10 5
+
+struct msm_vfe_phy_info {
+	uint32_t sbuf_phy;
+	uint32_t planar0_off;
+	uint32_t planar1_off;
+	uint32_t planar2_off;
+	uint32_t p0_phy;
+	uint32_t p1_phy;
+	uint32_t p2_phy;
+	uint8_t  output_id; /* VFE31_OUTPUT_MODE_PT/S/V */
+	uint32_t frame_id;
+};
+
+struct msm_vfe_stats_msg {
+	uint8_t awb_ymin;
+	uint32_t aec_buff;
+	uint32_t awb_buff;
+	uint32_t af_buff;
+	uint32_t ihist_buff;
+	uint32_t rs_buff;
+	uint32_t cs_buff;
+	uint32_t skin_buff;
+	uint32_t status_bits;
+	uint32_t frame_id;
+};
+
+struct video_crop_t{
+	uint32_t  in1_w;
+	uint32_t  out1_w;
+	uint32_t  in1_h;
+	uint32_t  out1_h;
+	uint32_t  in2_w;
+	uint32_t  out2_w;
+	uint32_t  in2_h;
+	uint32_t  out2_h;
+	uint8_t update_flag;
+};
+
+struct msm_vpe_buf_info {
+	uint32_t p0_phy;
+	uint32_t p1_phy;
+	struct   timespec ts;
+	uint32_t frame_id;
+	struct	 video_crop_t vpe_crop;
+};
+
+struct msm_vfe_resp {
+	enum vfe_resp_msg type;
+	struct msm_cam_evt_msg evt_msg;
+	struct msm_vfe_phy_info phy;
+	struct msm_vfe_stats_msg stats_msg;
+	struct msm_vpe_buf_info vpe_bf;
+	void    *extdata;
+	int32_t extlen;
+};
+
+struct msm_vpe_resp {
+	enum vpe_resp_msg type;
+	struct msm_cam_evt_msg evt_msg;
+	struct msm_vpe_phy_info phy;
+	void    *extdata;
+	int32_t extlen;
+};
+
+struct msm_vpe_callback {
+	void (*vpe_resp)(struct msm_vpe_resp *,
+					enum msm_queue, void *syncdata,
+		void *time_stamp, gfp_t gfp);
+	void* (*vpe_alloc)(int, void *syncdata, gfp_t gfp);
+	void (*vpe_free)(void *ptr);
+};
+
+struct msm_vfe_callback {
+	void (*vfe_resp)(struct msm_vfe_resp *,
+		enum msm_queue, void *syncdata,
+		gfp_t gfp);
+	void* (*vfe_alloc)(int, void *syncdata, gfp_t gfp);
+	void (*vfe_free)(void *ptr);
+};
+
+struct msm_camvfe_fn {
+	int (*vfe_init)(struct msm_vfe_callback *,
+			struct platform_device *);
+	int (*vfe_enable)(struct camera_enable_cmd *);
+	int (*vfe_config)(struct msm_vfe_cfg_cmd *, void *);
+	int (*vfe_disable)(struct camera_enable_cmd *,
+			struct platform_device *dev);
+	void (*vfe_release)(struct platform_device *);
+	void (*vfe_stop)(void);
+};
+
+struct msm_camvfe_params {
+	struct msm_vfe_cfg_cmd *vfe_cfg;
+	void *data;
+};
+
+struct msm_mctl_pp_params {
+	struct msm_mctl_pp_cmd *cmd;
+	void *data;
+};
+
+struct msm_camvpe_fn {
+	int (*vpe_reg)(struct msm_vpe_callback *);
+	int (*vpe_cfg_update) (void *);
+	void (*send_frame_to_vpe) (uint32_t planar0_off, uint32_t planar1_off,
+		struct timespec *ts, int output_id);
+	int (*vpe_config)(struct msm_vpe_cfg_cmd *, void *);
+	void (*vpe_cfg_offset)(int frame_pack, uint32_t pyaddr,
+		uint32_t pcbcraddr, struct timespec *ts, int output_id,
+		struct msm_st_half st_half, int frameid);
+	int *dis;
+};
+
+struct msm_sensor_ctrl {
+	int (*s_init)(const struct msm_camera_sensor_info *);
+	int (*s_release)(void);
+	int (*s_config)(void __user *);
+	enum msm_camera_type s_camera_type;
+	uint32_t s_mount_angle;
+	enum msm_st_frame_packing s_video_packing;
+	enum msm_st_frame_packing s_snap_packing;
+};
+
+struct msm_strobe_flash_ctrl {
+	int (*strobe_flash_init)
+		(struct msm_camera_sensor_strobe_flash_data *);
+	int (*strobe_flash_release)
+		(struct msm_camera_sensor_strobe_flash_data *, int32_t);
+	int (*strobe_flash_charge)(int32_t, int32_t, uint32_t);
+};
+
+/* this structure is used in kernel */
+struct msm_queue_cmd {
+	struct list_head list_config;
+	struct list_head list_control;
+	struct list_head list_frame;
+	struct list_head list_pict;
+	struct list_head list_vpe_frame;
+	struct list_head list_eventdata;
+	enum msm_queue type;
+	void *command;
+	atomic_t on_heap;
+	struct timespec ts;
+	uint32_t error_code;
+};
+
+struct msm_device_queue {
+	struct list_head list;
+	spinlock_t lock;
+	wait_queue_head_t wait;
+	int max;
+	int len;
+	const char *name;
+};
+
+struct msm_mctl_stats_t {
+	struct hlist_head pmem_stats_list;
+	spinlock_t pmem_stats_spinlock;
+};
+
+struct msm_sync {
+	/* These two queues are accessed from a process context only
+	 * They contain pmem descriptors for the preview frames and the stats
+	 * coming from the camera sensor.
+	*/
+	struct hlist_head pmem_frames;
+	struct hlist_head pmem_stats;
+
+	/* The message queue is used by the control thread to send commands
+	 * to the config thread, and also by the DSP to send messages to the
+	 * config thread.  Thus it is the only queue that is accessed from
+	 * both interrupt and process context.
+	 */
+	struct msm_device_queue event_q;
+
+	/* This queue contains preview frames. It is accessed by the DSP (in
+	 * in interrupt context, and by the frame thread.
+	 */
+	struct msm_device_queue frame_q;
+	int unblock_poll_frame;
+	int unblock_poll_pic_frame;
+
+	/* This queue contains snapshot frames.  It is accessed by the DSP (in
+	 * interrupt context, and by the control thread.
+	 */
+	struct msm_device_queue pict_q;
+	int get_pic_abort;
+	struct msm_device_queue vpe_q;
+
+	struct msm_camera_sensor_info *sdata;
+	struct msm_camvfe_fn vfefn;
+	struct msm_camvpe_fn vpefn;
+	struct msm_sensor_ctrl sctrl;
+	struct msm_strobe_flash_ctrl sfctrl;
+	struct wake_lock wake_lock;
+	struct platform_device *pdev;
+	int16_t ignore_qcmd_type;
+	uint8_t ignore_qcmd;
+	uint8_t opencnt;
+	void *cropinfo;
+	int  croplen;
+	int  core_powered_on;
+
+	struct fd_roi_info fdroiinfo;
+
+	atomic_t vpe_enable;
+	uint32_t pp_mask;
+	uint8_t pp_frame_avail;
+	struct msm_queue_cmd *pp_prev;
+	struct msm_queue_cmd *pp_snap;
+	struct msm_queue_cmd *pp_thumb;
+	int video_fd;
+
+	const char *apps_id;
+
+	struct mutex lock;
+	struct list_head list;
+	uint8_t liveshot_enabled;
+	struct msm_cam_v4l2_device *pcam_sync;
+
+	uint8_t stereocam_enabled;
+	struct msm_queue_cmd *pp_stereocam;
+	struct msm_queue_cmd *pp_stereocam2;
+	struct msm_queue_cmd *pp_stereosnap;
+	enum msm_stereo_state stereo_state;
+	int stcam_quality_ind;
+	uint32_t stcam_conv_value;
+
+	spinlock_t pmem_frame_spinlock;
+	spinlock_t pmem_stats_spinlock;
+	spinlock_t abort_pict_lock;
+	int snap_count;
+	int thumb_count;
+};
+
+#define MSM_APPS_ID_V4L2 "msm_v4l2"
+#define MSM_APPS_ID_PROP "msm_qct"
+
+struct msm_cam_device {
+	struct msm_sync *sync; /* most-frequently accessed */
+	struct device *device;
+	struct cdev cdev;
+	/* opened is meaningful only for the config and frame nodes,
+	 * which may be opened only once.
+	 */
+	atomic_t opened;
+};
+
+struct msm_control_device {
+	struct msm_cam_device *pmsm;
+
+	/* Used for MSM_CAM_IOCTL_CTRL_CMD_DONE responses */
+	uint8_t ctrl_data[max_control_command_size];
+	struct msm_ctrl_cmd ctrl;
+	struct msm_queue_cmd qcmd;
+
+	/* This queue used by the config thread to send responses back to the
+	 * control thread.  It is accessed only from a process context.
+	 */
+	struct msm_device_queue ctrl_q;
+};
+
+struct register_address_value_pair {
+	uint16_t register_address;
+	uint16_t register_value;
+};
+
+struct msm_pmem_region {
+	struct hlist_node list;
+	unsigned long paddr;
+	unsigned long len;
+	struct file *file;
+	struct msm_pmem_info info;
+	struct ion_handle *handle;
+};
+
+struct axidata {
+	uint32_t bufnum1;
+	uint32_t bufnum2;
+	uint32_t bufnum3;
+	struct msm_pmem_region *region;
+};
+
+#ifdef CONFIG_MSM_CAMERA_FLASH
+int msm_camera_flash_set_led_state(
+	struct msm_camera_sensor_flash_data *fdata,
+	unsigned led_state);
+int msm_strobe_flash_init(struct msm_sync *sync, uint32_t sftype);
+int msm_flash_ctrl(struct msm_camera_sensor_info *sdata,
+			struct flash_ctrl_data *flash_info);
+#else
+static inline int msm_camera_flash_set_led_state(
+	struct msm_camera_sensor_flash_data *fdata,
+	unsigned led_state)
+{
+	return -ENOTSUPP;
+}
+static inline int msm_strobe_flash_init(
+	struct msm_sync *sync, uint32_t sftype)
+{
+	return -ENOTSUPP;
+}
+static inline int msm_flash_ctrl(
+		struct msm_camera_sensor_info *sdata,
+		struct flash_ctrl_data *flash_info)
+{
+	return -ENOTSUPP;
+}
+#endif
+
+
+
+void msm_camvfe_init(void);
+int msm_camvfe_check(void *);
+void msm_camvfe_fn_init(struct msm_camvfe_fn *, void *);
+void msm_camvpe_fn_init(struct msm_camvpe_fn *, void *);
+int msm_camera_drv_start(struct platform_device *dev,
+		int (*sensor_probe)(const struct msm_camera_sensor_info *,
+					struct msm_sensor_ctrl *));
+
+enum msm_camio_clk_type {
+	CAMIO_VFE_MDC_CLK,
+	CAMIO_MDC_CLK,
+	CAMIO_VFE_CLK,
+	CAMIO_VFE_AXI_CLK,
+
+	CAMIO_VFE_CAMIF_CLK,
+	CAMIO_VFE_PBDG_CLK,
+	CAMIO_CAM_MCLK_CLK,
+	CAMIO_CAMIF_PAD_PBDG_CLK,
+
+	CAMIO_CSI0_VFE_CLK,
+	CAMIO_CSI1_VFE_CLK,
+	CAMIO_VFE_PCLK,
+
+	CAMIO_CSI_SRC_CLK,
+	CAMIO_CSI0_CLK,
+	CAMIO_CSI1_CLK,
+	CAMIO_CSI0_PCLK,
+	CAMIO_CSI1_PCLK,
+
+	CAMIO_CSI1_SRC_CLK,
+	CAMIO_CSI_PIX_CLK,
+	CAMIO_CSI_PIX1_CLK,
+	CAMIO_CSI_RDI_CLK,
+	CAMIO_CSI_RDI1_CLK,
+	CAMIO_CSI_RDI2_CLK,
+	CAMIO_CSIPHY0_TIMER_CLK,
+	CAMIO_CSIPHY1_TIMER_CLK,
+
+	CAMIO_JPEG_CLK,
+	CAMIO_JPEG_PCLK,
+	CAMIO_VPE_CLK,
+	CAMIO_VPE_PCLK,
+
+	CAMIO_CSI0_PHY_CLK,
+	CAMIO_CSI1_PHY_CLK,
+	CAMIO_CSIPHY_TIMER_SRC_CLK,
+	CAMIO_IMEM_CLK,
+
+	CAMIO_MAX_CLK
+};
+
+enum msm_camio_clk_src_type {
+	MSM_CAMIO_CLK_SRC_INTERNAL,
+	MSM_CAMIO_CLK_SRC_EXTERNAL,
+	MSM_CAMIO_CLK_SRC_MAX
+};
+
+enum msm_s_test_mode {
+	S_TEST_OFF,
+	S_TEST_1,
+	S_TEST_2,
+	S_TEST_3
+};
+
+enum msm_s_resolution {
+	S_QTR_SIZE,
+	S_FULL_SIZE,
+	S_INVALID_SIZE
+};
+
+enum msm_s_reg_update {
+	/* Sensor egisters that need to be updated during initialization */
+	S_REG_INIT,
+	/* Sensor egisters that needs periodic I2C writes */
+	S_UPDATE_PERIODIC,
+	/* All the sensor Registers will be updated */
+	S_UPDATE_ALL,
+	/* Not valid update */
+	S_UPDATE_INVALID
+};
+
+enum msm_s_setting {
+	S_RES_PREVIEW,
+	S_RES_CAPTURE
+};
+
+enum msm_bus_perf_setting {
+	S_INIT,
+	S_PREVIEW,
+	S_VIDEO,
+	S_CAPTURE,
+	S_ZSL,
+	S_STEREO_VIDEO,
+	S_STEREO_CAPTURE,
+	S_DEFAULT,
+	S_EXIT
+};
+
+struct msm_cam_clk_info {
+	const char *clk_name;
+	long clk_rate;
+};
+
+int msm_camio_enable(struct platform_device *dev);
+int msm_camio_vpe_clk_enable(uint32_t);
+int msm_camio_vpe_clk_disable(void);
+
+void msm_camio_mode_config(enum msm_camera_i2c_mux_mode mode);
+int  msm_camio_clk_enable(enum msm_camio_clk_type clk);
+int  msm_camio_clk_disable(enum msm_camio_clk_type clk);
+int  msm_camio_clk_config(uint32_t freq);
+void msm_camio_clk_rate_set(int rate);
+int msm_camio_vfe_clk_rate_set(int rate);
+void msm_camio_clk_rate_set_2(struct clk *clk, int rate);
+void msm_camio_clk_axi_rate_set(int rate);
+void msm_disable_io_gpio_clk(struct platform_device *);
+
+void msm_camio_camif_pad_reg_reset(void);
+void msm_camio_camif_pad_reg_reset_2(void);
+
+void msm_camio_vfe_blk_reset(void);
+void msm_camio_vfe_blk_reset_2(void);
+void msm_camio_vfe_blk_reset_3(void);
+
+int32_t msm_camio_3d_enable(const struct msm_camera_sensor_info *sinfo);
+void msm_camio_3d_disable(void);
+void msm_camio_clk_sel(enum msm_camio_clk_src_type);
+void msm_camio_disable(struct platform_device *);
+int msm_camio_probe_on(struct platform_device *);
+int msm_camio_probe_off(struct platform_device *);
+int msm_camio_sensor_clk_off(struct platform_device *);
+int msm_camio_sensor_clk_on(struct platform_device *);
+int msm_camio_csi_config(struct msm_camera_csi_params *csi_params);
+int msm_camio_csiphy_config(struct msm_camera_csiphy_params *csiphy_params);
+int msm_camio_csid_config(struct msm_camera_csid_params *csid_params);
+int add_axi_qos(void);
+int update_axi_qos(uint32_t freq);
+void release_axi_qos(void);
+void msm_camera_io_w(u32 data, void __iomem *addr);
+void msm_camera_io_w_mb(u32 data, void __iomem *addr);
+u32 msm_camera_io_r(void __iomem *addr);
+u32 msm_camera_io_r_mb(void __iomem *addr);
+void msm_camera_io_dump(void __iomem *addr, int size);
+void msm_camera_io_memcpy(void __iomem *dest_addr,
+		void __iomem *src_addr, u32 len);
+void msm_camio_set_perf_lvl(enum msm_bus_perf_setting);
+void msm_camio_bus_scale_cfg(
+	struct msm_bus_scale_pdata *, enum msm_bus_perf_setting);
+
+void *msm_isp_sync_alloc(int size, gfp_t gfp);
+
+void msm_isp_sync_free(void *ptr);
+
+int msm_cam_clk_enable(struct device *dev, struct msm_cam_clk_info *clk_info,
+		struct clk **clk_ptr, int num_clk, int enable);
+int msm_cam_core_reset(void);
+
+int msm_camera_config_vreg(struct device *dev, struct camera_vreg_t *cam_vreg,
+		int num_vreg, struct regulator **reg_ptr, int config);
+int msm_camera_enable_vreg(struct device *dev, struct camera_vreg_t *cam_vreg,
+		int num_vreg, struct regulator **reg_ptr, int enable);
+
+int msm_camera_config_gpio_table
+	(struct msm_camera_sensor_info *sinfo, int gpio_en);
+int msm_camera_request_gpio_table
+	(struct msm_camera_sensor_info *sinfo, int gpio_en);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/clk.h b/arch/arm/mach-msm/include/mach/clk.h
index e8d3842..8c0ebfa 100644
--- a/arch/arm/mach-msm/include/mach/clk.h
+++ b/arch/arm/mach-msm/include/mach/clk.h
@@ -25,9 +25,6 @@
 
 struct clk;
 
-/* Rate is minimum clock rate in Hz */
-int clk_set_min_rate(struct clk *clk, unsigned long rate);
-
 /* Rate is maximum clock rate in Hz */
 int clk_set_max_rate(struct clk *clk, unsigned long rate);
 
diff --git a/arch/arm/mach-msm/include/mach/cpu.h b/arch/arm/mach-msm/include/mach/cpu.h
deleted file mode 100644
index a9481b0..0000000
--- a/arch/arm/mach-msm/include/mach/cpu.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-
-#ifndef __ARCH_ARM_MACH_MSM_CPU_H__
-#define __ARCH_ARM_MACH_MSM_CPU_H__
-
-/* TODO: For now, only one CPU can be compiled at a time. */
-
-#define cpu_is_msm7x01()	0
-#define cpu_is_msm7x30()	0
-#define cpu_is_qsd8x50()	0
-#define cpu_is_msm8x60()	0
-#define cpu_is_msm8960()	0
-
-#ifdef CONFIG_ARCH_MSM7X00A
-# undef cpu_is_msm7x01
-# define cpu_is_msm7x01()	1
-#endif
-
-#ifdef CONFIG_ARCH_MSM7X30
-# undef cpu_is_msm7x30
-# define cpu_is_msm7x30()	1
-#endif
-
-#ifdef CONFIG_ARCH_QSD8X50
-# undef cpu_is_qsd8x50
-# define cpu_is_qsd8x50()	1
-#endif
-
-#ifdef CONFIG_ARCH_MSM8X60
-# undef cpu_is_msm8x60
-# define cpu_is_msm8x60()	1
-#endif
-
-#ifdef CONFIG_ARCH_MSM8960
-# undef cpu_is_msm8960
-# define cpu_is_msm8960()	1
-#endif
-
-#endif
diff --git a/arch/arm/mach-msm/include/mach/cpuidle.h b/arch/arm/mach-msm/include/mach/cpuidle.h
new file mode 100644
index 0000000..654121f
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/cpuidle.h
@@ -0,0 +1,54 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_CPUIDLE_H
+#define __ARCH_ARM_MACH_MSM_CPUIDLE_H
+
+#include <linux/notifier.h>
+#include "../../pm.h"
+
+struct msm_cpuidle_state {
+	unsigned int cpu;
+	int state_nr;
+	char *name;
+	char *desc;
+	enum msm_pm_sleep_mode mode_nr;
+};
+
+#ifdef CONFIG_CPU_IDLE
+int msm_cpuidle_init(void);
+#else
+static inline int msm_cpuidle_init(void)
+{ return -ENOSYS; }
+#endif
+
+#ifdef CONFIG_MSM_SLEEP_STATS
+enum {
+	MSM_CPUIDLE_STATE_ENTER,
+	MSM_CPUIDLE_STATE_EXIT
+};
+
+int msm_cpuidle_register_notifier(unsigned int cpu,
+		struct notifier_block *nb);
+int msm_cpuidle_unregister_notifier(unsigned int cpu,
+		struct notifier_block *nb);
+#else
+static inline int msm_cpuidle_register_notifier(unsigned int cpu,
+		struct notifier_block *nb)
+{ return -ENODEV; }
+static inline int msm_cpuidle_unregister_notifier(unsigned int cpu,
+		struct notifier_block *nb)
+{ return -ENODEV; }
+#endif
+
+#endif /* __ARCH_ARM_MACH_MSM_CPUIDLE_H */
diff --git a/arch/arm/mach-msm/include/mach/dal.h b/arch/arm/mach-msm/include/mach/dal.h
new file mode 100644
index 0000000..d0c754d
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/dal.h
@@ -0,0 +1,150 @@
+/* Copyright (c) 2008-2009, 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 __DAL_H__
+#define __DAL_H__
+
+#include <linux/kernel.h>
+#include <mach/msm_smd.h>
+
+#define DALRPC_DEST_MODEM SMD_APPS_MODEM
+#define DALRPC_DEST_QDSP SMD_APPS_QDSP
+
+#define DALRPC_TIMEOUT_INFINITE -1
+
+enum {
+	DALDEVICE_ATTACH_IDX = 0,
+	DALDEVICE_DETACH_IDX,
+	DALDEVICE_INIT_IDX,
+	DALDEVICE_DEINIT_IDX,
+	DALDEVICE_OPEN_IDX,
+	DALDEVICE_CLOSE_IDX,
+	DALDEVICE_INFO_IDX,
+	DALDEVICE_POWEREVENT_IDX,
+	DALDEVICE_SYSREQUEST_IDX,
+	DALDEVICE_FIRST_DEVICE_API_IDX
+};
+
+struct daldevice_info_t {
+	uint32_t size;
+	uint32_t version;
+	char name[32];
+};
+
+#define DAL_CHUNK_NAME_LENGTH 12
+struct dal_chunk_header {
+	uint32_t size;
+	char name[DAL_CHUNK_NAME_LENGTH];
+	uint32_t lock;
+	uint32_t reserved;
+	uint32_t type;
+	uint32_t version;
+};
+
+int daldevice_attach(uint32_t device_id, char *port, int cpu,
+		     void **handle_ptr);
+
+/* The caller must ensure there are no outstanding dalrpc calls on
+ * the client before (and while) calling daldevice_detach. */
+int daldevice_detach(void *handle);
+
+uint32_t dalrpc_fcn_0(uint32_t ddi_idx, void *handle, uint32_t s1);
+uint32_t dalrpc_fcn_1(uint32_t ddi_idx, void *handle, uint32_t s1,
+		      uint32_t s2);
+uint32_t dalrpc_fcn_2(uint32_t ddi_idx, void *handle, uint32_t s1,
+		      uint32_t *p_s2);
+uint32_t dalrpc_fcn_3(uint32_t ddi_idx, void *handle, uint32_t s1,
+		      uint32_t s2, uint32_t s3);
+uint32_t dalrpc_fcn_4(uint32_t ddi_idx, void *handle, uint32_t s1,
+		      uint32_t s2, uint32_t *p_s3);
+uint32_t dalrpc_fcn_5(uint32_t ddi_idx, void *handle, const void *ibuf,
+		      uint32_t ilen);
+uint32_t dalrpc_fcn_6(uint32_t ddi_idx, void *handle, uint32_t s1,
+		      const void *ibuf, uint32_t ilen);
+uint32_t dalrpc_fcn_7(uint32_t ddi_idx, void *handle, const void *ibuf,
+		      uint32_t ilen, void *obuf, uint32_t olen,
+		      uint32_t *oalen);
+uint32_t dalrpc_fcn_8(uint32_t ddi_idx, void *handle, const void *ibuf,
+		      uint32_t ilen, void *obuf, uint32_t olen);
+uint32_t dalrpc_fcn_9(uint32_t ddi_idx, void *handle, void *obuf,
+		      uint32_t olen);
+uint32_t dalrpc_fcn_10(uint32_t ddi_idx, void *handle, uint32_t s1,
+		       const void *ibuf, uint32_t ilen, void *obuf,
+		       uint32_t olen, uint32_t *oalen);
+uint32_t dalrpc_fcn_11(uint32_t ddi_idx, void *handle, uint32_t s1,
+		       void *obuf, uint32_t olen);
+uint32_t dalrpc_fcn_12(uint32_t ddi_idx, void *handle, uint32_t s1,
+		       void *obuf, uint32_t olen, uint32_t *oalen);
+uint32_t dalrpc_fcn_13(uint32_t ddi_idx, void *handle, const void *ibuf,
+		       uint32_t ilen, const void *ibuf2, uint32_t ilen2,
+		       void *obuf, uint32_t olen);
+uint32_t dalrpc_fcn_14(uint32_t ddi_idx, void *handle, const void *ibuf,
+		       uint32_t ilen, void *obuf1, uint32_t olen1,
+		       void *obuf2, uint32_t olen2, uint32_t *oalen2);
+uint32_t dalrpc_fcn_15(uint32_t ddi_idx, void *handle, const void *ibuf,
+		       uint32_t ilen, const void *ibuf2, uint32_t ilen2,
+		       void *obuf, uint32_t olen, uint32_t *oalen,
+		       void *obuf2, uint32_t olen2);
+
+static inline uint32_t daldevice_info(void *handle,
+				      struct daldevice_info_t *info,
+				      uint32_t info_size)
+{
+	return dalrpc_fcn_9(DALDEVICE_INFO_IDX, handle, info, info_size);
+}
+
+static inline uint32_t daldevice_sysrequest(void *handle, uint32_t req_id,
+					    const void *src_ptr,
+					    uint32_t src_len, void *dest_ptr,
+					    uint32_t dest_len,
+					    uint32_t *dest_alen)
+{
+	return dalrpc_fcn_10(DALDEVICE_SYSREQUEST_IDX, handle, req_id,
+			     src_ptr, src_len, dest_ptr, dest_len, dest_alen);
+}
+
+static inline uint32_t daldevice_init(void *handle)
+{
+	return dalrpc_fcn_0(DALDEVICE_INIT_IDX, handle, 0);
+}
+
+static inline uint32_t daldevice_deinit(void *handle)
+{
+	return dalrpc_fcn_0(DALDEVICE_DEINIT_IDX, handle, 0);
+}
+
+static inline uint32_t daldevice_open(void *handle, uint32_t mode)
+{
+	return dalrpc_fcn_0(DALDEVICE_OPEN_IDX, handle, mode);
+}
+
+static inline uint32_t daldevice_close(void *handle)
+{
+	return dalrpc_fcn_0(DALDEVICE_CLOSE_IDX, handle, 0);
+}
+
+void *dalrpc_alloc_event(void *handle);
+void *dalrpc_alloc_cb(void *handle,
+		      void (*fn)(void *, uint32_t, void *, uint32_t),
+		      void *context);
+void dalrpc_dealloc_event(void *handle,
+			  void *ev_h);
+void dalrpc_dealloc_cb(void *handle,
+		       void *cb_h);
+
+#define dalrpc_event_wait(ev_h, timeout) \
+	dalrpc_event_wait_multiple(1, &ev_h, timeout)
+
+int dalrpc_event_wait_multiple(int num, void **ev_h, int timeout);
+
+#endif /* __DAL_H__ */
diff --git a/arch/arm/mach-msm/include/mach/dal_axi.h b/arch/arm/mach-msm/include/mach/dal_axi.h
new file mode 100644
index 0000000..4e32aa3
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/dal_axi.h
@@ -0,0 +1,21 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _DAL_AXI_H
+#define _DAL_AXI_H
+
+#include <mach/dal.h>
+
+int set_grp2d_async(void);
+int set_grp3d_async(void);
+int set_grp_xbar_async(void);
+
+#endif  /* _DAL_AXI_H */
diff --git a/arch/arm/mach-msm/include/mach/debug-macro.S b/arch/arm/mach-msm/include/mach/debug-macro.S
index 3ffd866..c760953 100644
--- a/arch/arm/mach-msm/include/mach/debug-macro.S
+++ b/arch/arm/mach-msm/include/mach/debug-macro.S
@@ -1,7 +1,6 @@
 /*
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -15,52 +14,67 @@
  *
  */
 
+
+
 #include <mach/hardware.h>
 #include <mach/msm_iomap.h>
+#include <mach/msm_serial_hsl_regs.h>
 
-	.macro	addruart, rp, rv, tmp
 #ifdef MSM_DEBUG_UART_PHYS
-	ldr	\rp, =MSM_DEBUG_UART_PHYS
-	ldr	\rv, =MSM_DEBUG_UART_BASE
-#endif
+       .macro  addruart, rp, rv, tmp
+	ldr     \rp, =MSM_DEBUG_UART_PHYS
+	ldr     \rv, =MSM_DEBUG_UART_BASE
 	.endm
 
-	.macro	senduart, rd, rx
+	.macro	senduart,rd,rx
 #ifdef CONFIG_MSM_HAS_DEBUG_UART_HS
+	@ Clear TX_READY by writing to the UARTDM_CR register
+	mov	r12, #0x300
+	str	r12, [\rx, #UARTDM_CR_OFFSET]
+	@ Write 0x1 to NCF register
+	mov 	r12, #0x1
+	str	r12, [\rx, #UARTDM_NCF_TX_OFFSET]
+	@ UARTDM reg. Read to induce delay
+	ldr	r12, [\rx, #UARTDM_SR_OFFSET]
 	@ Write the 1 character to UARTDM_TF
-	str	\rd, [\rx, #0x70]
+	str	\rd, [\rx, #UARTDM_TF_OFFSET]
 #else
-	teq	\rx, #0
-	strne	\rd, [\rx, #0x0C]
+	teq     \rx, #0
+	strne   \rd, [\rx, #0x0C]
 #endif
 	.endm
 
-	.macro	waituart, rd, rx
+	.macro	waituart,rd,rx
 #ifdef CONFIG_MSM_HAS_DEBUG_UART_HS
 	@ check for TX_EMT in UARTDM_SR
-	ldr	\rd, [\rx, #0x08]
+	ldr	\rd, [\rx, #UARTDM_SR_OFFSET]
 	tst	\rd, #0x08
 	bne	1002f
 	@ wait for TXREADY in UARTDM_ISR
-1001:	ldr	\rd, [\rx, #0x14]
+1001:	ldreq	\rd, [\rx, #UARTDM_ISR_OFFSET]
 	tst	\rd, #0x80
+	dsb
 	beq 	1001b
-1002:
-	@ Clear TX_READY by writing to the UARTDM_CR register
-	mov	\rd, #0x300
-	str	\rd, [\rx, #0x10]
-	@ Write 0x1 to NCF register
-	mov 	\rd, #0x1
-	str	\rd, [\rx, #0x40]
-	@ UARTDM reg. Read to induce delay
-	ldr	\rd, [\rx, #0x08]
 #else
 	@ wait for TX_READY
-1001:	ldr	\rd, [\rx, #0x08]
-	tst	\rd, #0x04
-	beq	1001b
+1001:   ldr \rd, [\rx, #0x08]
+	tst     \rd, #0x04
+	beq     1001b
 #endif
+1002:
 	.endm
 
-	.macro	busyuart, rd, rx
+#else
+
+	.macro  addruart, rp, rv
+	.endm
+
+	.macro	senduart,rd,rx
+	.endm
+
+	.macro	waituart,rd,rx
+	.endm
+#endif
+
+	.macro	busyuart,rd,rx
 	.endm
diff --git a/arch/arm/mach-msm/include/mach/debug_mm.h b/arch/arm/mach-msm/include/mach/debug_mm.h
new file mode 100644
index 0000000..091798c
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/debug_mm.h
@@ -0,0 +1,33 @@
+/* Copyright (c) 2009, 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 __ARCH_ARM_MACH_MSM_DEBUG_MM_H_
+#define __ARCH_ARM_MACH_MSM_DEBUG_MM_H_
+
+#include <linux/string.h>
+
+/* The below macro removes the directory path name and retains only the
+ * file name to avoid long path names in log messages that comes as
+ * part of __FILE__ to compiler.
+ */
+#define __MM_FILE__ strrchr(__FILE__, '/') ? (strrchr(__FILE__, '/')+1) : \
+	__FILE__
+
+#define MM_DBG(fmt, args...) pr_debug("[%s] " fmt,\
+		__func__, ##args)
+
+#define MM_INFO(fmt, args...) pr_info("[%s:%s] " fmt,\
+	       __MM_FILE__, __func__, ##args)
+
+#define MM_ERR(fmt, args...) pr_err("[%s:%s] " fmt,\
+	       __MM_FILE__, __func__, ##args)
+#endif /* __ARCH_ARM_MACH_MSM_DEBUG_MM_H_ */
diff --git a/arch/arm/mach-msm/include/mach/diag_bridge.h b/arch/arm/mach-msm/include/mach/diag_bridge.h
new file mode 100644
index 0000000..b06f020
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/diag_bridge.h
@@ -0,0 +1,55 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LINUX_USB_DIAG_BRIDGE_H__
+#define __LINUX_USB_DIAG_BRIDGE_H__
+
+struct diag_bridge_ops {
+	void *ctxt;
+	void (*read_complete_cb)(void *ctxt, char *buf,
+			int buf_size, int actual);
+	void (*write_complete_cb)(void *ctxt, char *buf,
+			int buf_size, int actual);
+	int (*suspend)(void *ctxt);
+	void (*resume)(void *ctxt);
+};
+
+#if defined(CONFIG_USB_QCOM_DIAG_BRIDGE) \
+	|| defined(CONFIG_USB_QCOM_DIAG_BRIDGE_MODULE)
+
+extern int diag_bridge_read(char *data, int size);
+extern int diag_bridge_write(char *data, int size);
+extern int diag_bridge_open(struct diag_bridge_ops *ops);
+extern void diag_bridge_close(void);
+
+#else
+
+static int __maybe_unused diag_bridge_read(char *data, int size)
+{
+	return -ENODEV;
+}
+
+static int __maybe_unused diag_bridge_write(char *data, int size)
+{
+	return -ENODEV;
+}
+
+static int __maybe_unused diag_bridge_open(struct diag_bridge_ops *ops)
+{
+	return -ENODEV;
+}
+
+static void __maybe_unused diag_bridge_close(void) { }
+
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/dma-fsm9xxx.h b/arch/arm/mach-msm/include/mach/dma-fsm9xxx.h
new file mode 100644
index 0000000..e284267
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/dma-fsm9xxx.h
@@ -0,0 +1,56 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_ARCH_MSM_DMA_FSM9XXX_H
+#define __ASM_ARCH_MSM_DMA_FSM9XXX_H
+
+/* DMA channels allocated to Scorpion */
+#define DMOV_GP_CHAN            4
+#define DMOV_CE1_IN_CHAN        5
+#define DMOV_CE1_OUT_CHAN       6
+#define DMOV_NAND_CHAN          7
+#define DMOV_SDC1_CHAN          8
+#define DMOV_GP2_CHAN           10
+#define DMOV_CE2_IN_CHAN        12
+#define DMOV_CE2_OUT_CHAN       13
+#define DMOV_CE3_IN_CHAN        14
+#define DMOV_CE3_OUT_CHAN       15
+
+/* CRCIs */
+#define DMOV_CE1_IN_CRCI        1
+#define DMOV_CE1_OUT_CRCI       2
+#define DMOV_CE1_HASH_CRCI      3
+
+#define DMOV_NAND_CRCI_DATA     4
+#define DMOV_NAND_CRCI_CMD      5
+
+#define DMOV_SDC1_CRCI          6
+
+#define DMOV_HSUART_TX_CRCI     7
+#define DMOV_HSUART_RX_CRCI     8
+
+#define DMOV_CE2_IN_CRCI        9
+#define DMOV_CE2_OUT_CRCI       10
+#define DMOV_CE2_HASH_CRCI      11
+
+#define DMOV_CE3_IN_CRCI        12
+#define DMOV_CE3_OUT_CRCI       13
+#define DMOV_CE3_HASH_DONE_CRCI 14
+
+/* Following CRCIs are not defined in FSM9XXX, but these are added to keep
+ * the existing SDCC host controller driver compatible with FSM9XXX.
+ */
+#define DMOV_SDC2_CRCI         DMOV_SDC1_CRCI
+#define DMOV_SDC3_CRCI         DMOV_SDC1_CRCI
+#define DMOV_SDC4_CRCI         DMOV_SDC1_CRCI
+
+#endif /* __ASM_ARCH_MSM_DMA_FSM9XXX_H */
diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h
index 05583f5..70519ff 100644
--- a/arch/arm/mach-msm/include/mach/dma.h
+++ b/arch/arm/mach-msm/include/mach/dma.h
@@ -1,6 +1,7 @@
 /* linux/include/asm-arm/arch-msm/dma.h
  *
  * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008-2012, Code Aurora Forum. 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
@@ -14,10 +15,15 @@
  */
 
 #ifndef __ASM_ARCH_MSM_DMA_H
+#define __ASM_ARCH_MSM_DMA_H
 
 #include <linux/list.h>
 #include <mach/msm_iomap.h>
 
+#if defined(CONFIG_ARCH_FSM9XXX)
+#include <mach/dma-fsm9xxx.h>
+#endif
+
 struct msm_dmov_errdata {
 	uint32_t flush[6];
 };
@@ -28,71 +34,191 @@
 	void (*complete_func)(struct msm_dmov_cmd *cmd,
 			      unsigned int result,
 			      struct msm_dmov_errdata *err);
-	void (*execute_func)(struct msm_dmov_cmd *cmd);
-	void *data;
+	void (*exec_func)(struct msm_dmov_cmd *cmd);
+	void *user;	/* Pointer for caller's reference */
 };
 
-#ifndef CONFIG_ARCH_MSM8X60
+struct msm_dmov_pdata {
+	int sd;
+	size_t sd_size;
+};
+
 void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd);
-void msm_dmov_stop_cmd(unsigned id, struct msm_dmov_cmd *cmd, int graceful);
+void msm_dmov_enqueue_cmd_ext(unsigned id, struct msm_dmov_cmd *cmd);
+void msm_dmov_flush(unsigned int id, int graceful);
 int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr);
-#else
-static inline
-void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd) { }
-static inline
-void msm_dmov_stop_cmd(unsigned id, struct msm_dmov_cmd *cmd, int graceful) { }
-static inline
-int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr) { return -EIO; }
-#endif
 
+#define DMOV_CRCIS_PER_CONF 10
 
-#define DMOV_SD0(off, ch) (MSM_DMOV_BASE + 0x0000 + (off) + ((ch) << 2))
-#define DMOV_SD1(off, ch) (MSM_DMOV_BASE + 0x0400 + (off) + ((ch) << 2))
-#define DMOV_SD2(off, ch) (MSM_DMOV_BASE + 0x0800 + (off) + ((ch) << 2))
-#define DMOV_SD3(off, ch) (MSM_DMOV_BASE + 0x0C00 + (off) + ((ch) << 2))
+#define DMOV_ADDR(off, ch) ((off) + ((ch) << 2))
 
-#if defined(CONFIG_ARCH_MSM7X30)
-#define DMOV_SD_AARM DMOV_SD2
-#else
-#define DMOV_SD_AARM DMOV_SD3
-#endif
-
-#define DMOV_CMD_PTR(ch)      DMOV_SD_AARM(0x000, ch)
+#define DMOV_CMD_PTR(ch)      DMOV_ADDR(0x000, ch)
 #define DMOV_CMD_LIST         (0 << 29) /* does not work */
 #define DMOV_CMD_PTR_LIST     (1 << 29) /* works */
 #define DMOV_CMD_INPUT_CFG    (2 << 29) /* untested */
 #define DMOV_CMD_OUTPUT_CFG   (3 << 29) /* untested */
 #define DMOV_CMD_ADDR(addr)   ((addr) >> 3)
 
-#define DMOV_RSLT(ch)         DMOV_SD_AARM(0x040, ch)
+#define DMOV_RSLT(ch)         DMOV_ADDR(0x040, ch)
 #define DMOV_RSLT_VALID       (1 << 31) /* 0 == host has empties result fifo */
 #define DMOV_RSLT_ERROR       (1 << 3)
 #define DMOV_RSLT_FLUSH       (1 << 2)
 #define DMOV_RSLT_DONE        (1 << 1)  /* top pointer done */
 #define DMOV_RSLT_USER        (1 << 0)  /* command with FR force result */
 
-#define DMOV_FLUSH0(ch)       DMOV_SD_AARM(0x080, ch)
-#define DMOV_FLUSH1(ch)       DMOV_SD_AARM(0x0C0, ch)
-#define DMOV_FLUSH2(ch)       DMOV_SD_AARM(0x100, ch)
-#define DMOV_FLUSH3(ch)       DMOV_SD_AARM(0x140, ch)
-#define DMOV_FLUSH4(ch)       DMOV_SD_AARM(0x180, ch)
-#define DMOV_FLUSH5(ch)       DMOV_SD_AARM(0x1C0, ch)
+#define DMOV_FLUSH0(ch)       DMOV_ADDR(0x080, ch)
+#define DMOV_FLUSH1(ch)       DMOV_ADDR(0x0C0, ch)
+#define DMOV_FLUSH2(ch)       DMOV_ADDR(0x100, ch)
+#define DMOV_FLUSH3(ch)       DMOV_ADDR(0x140, ch)
+#define DMOV_FLUSH4(ch)       DMOV_ADDR(0x180, ch)
+#define DMOV_FLUSH5(ch)       DMOV_ADDR(0x1C0, ch)
+#define DMOV_FLUSH_TYPE       (1 << 31)
 
-#define DMOV_STATUS(ch)       DMOV_SD_AARM(0x200, ch)
+#define DMOV_STATUS(ch)       DMOV_ADDR(0x200, ch)
 #define DMOV_STATUS_RSLT_COUNT(n)    (((n) >> 29))
 #define DMOV_STATUS_CMD_COUNT(n)     (((n) >> 27) & 3)
 #define DMOV_STATUS_RSLT_VALID       (1 << 1)
 #define DMOV_STATUS_CMD_PTR_RDY      (1 << 0)
 
-#define DMOV_ISR              DMOV_SD_AARM(0x380, 0)
-  
-#define DMOV_CONFIG(ch)       DMOV_SD_AARM(0x300, ch)
-#define DMOV_CONFIG_FORCE_TOP_PTR_RSLT (1 << 2)
-#define DMOV_CONFIG_FORCE_FLUSH_RSLT   (1 << 1)
-#define DMOV_CONFIG_IRQ_EN             (1 << 0)
+#define DMOV_CONF(ch)         DMOV_ADDR(0x240, ch)
+#define DMOV_CONF_SD(sd)      (((sd & 4) << 11) | ((sd & 3) << 4))
+#define DMOV_CONF_IRQ_EN             (1 << 6)
+#define DMOV_CONF_FORCE_RSLT_EN      (1 << 7)
+#define DMOV_CONF_SHADOW_EN          (1 << 12)
+#define DMOV_CONF_MPU_DISABLE        (1 << 11)
+#define DMOV_CONF_PRIORITY(n)        (n << 0)
+
+#define DMOV_DBG_ERR(ci)      DMOV_ADDR(0x280, ci)
+
+#define DMOV_RSLT_CONF(ch)    DMOV_ADDR(0x300, ch)
+#define DMOV_RSLT_CONF_FORCE_TOP_PTR_RSLT (1 << 2)
+#define DMOV_RSLT_CONF_FORCE_FLUSH_RSLT   (1 << 1)
+#define DMOV_RSLT_CONF_IRQ_EN             (1 << 0)
+
+#define DMOV_ISR              DMOV_ADDR(0x380, 0)
+
+#define DMOV_CI_CONF(ci)      DMOV_ADDR(0x390, ci)
+#define DMOV_CI_CONF_RANGE_END(n)      ((n) << 24)
+#define DMOV_CI_CONF_RANGE_START(n)    ((n) << 16)
+#define DMOV_CI_CONF_MAX_BURST(n)      ((n) << 0)
+
+#define DMOV_CI_DBG_ERR(ci)   DMOV_ADDR(0x3B0, ci)
+
+#define DMOV_CRCI_CONF0       DMOV_ADDR(0x3D0, 0)
+#define DMOV_CRCI_CONF1       DMOV_ADDR(0x3D4, 0)
+#define DMOV_CRCI_CONF0_SD(crci, sd) (sd << (crci*3))
+#define DMOV_CRCI_CONF1_SD(crci, sd) (sd << ((crci-DMOV_CRCIS_PER_CONF)*3))
+
+#define DMOV_CRCI_CTL(crci)   DMOV_ADDR(0x400, crci)
+#define DMOV_CRCI_CTL_BLK_SZ(n)        ((n) << 0)
+#define DMOV_CRCI_CTL_RST              (1 << 17)
+#define DMOV_CRCI_MUX                  (1 << 18)
 
 /* channel assignments */
 
+/*
+ * Format of CRCI numbers: crci number + (muxsel << 4)
+ */
+
+#if defined(CONFIG_ARCH_MSM8X60)
+#define DMOV_GP_CHAN           15
+
+#define DMOV_NAND_CHAN         17
+#define DMOV_NAND_CHAN_MODEM   26
+#define DMOV_NAND_CHAN_Q6      27
+#define DMOV_NAND_CRCI_CMD     15
+#define DMOV_NAND_CRCI_DATA    3
+
+#define DMOV_CE_IN_CHAN        2
+#define DMOV_CE_IN_CRCI        4
+
+#define DMOV_CE_OUT_CHAN       3
+#define DMOV_CE_OUT_CRCI       5
+
+#define DMOV_CE_HASH_CRCI      15
+
+#define DMOV_SDC1_CHAN         18
+#define DMOV_SDC1_CRCI         1
+
+#define DMOV_SDC2_CHAN         19
+#define DMOV_SDC2_CRCI         4
+
+#define DMOV_SDC3_CHAN         20
+#define DMOV_SDC3_CRCI         2
+
+#define DMOV_SDC4_CHAN         21
+#define DMOV_SDC4_CRCI         5
+
+#define DMOV_SDC5_CHAN         21
+#define DMOV_SDC5_CRCI         14
+
+#define DMOV_TSIF_CHAN         4
+#define DMOV_TSIF_CRCI         6
+
+#define DMOV_HSUART1_TX_CHAN   22
+#define DMOV_HSUART1_TX_CRCI   8
+
+#define DMOV_HSUART1_RX_CHAN   23
+#define DMOV_HSUART1_RX_CRCI   9
+
+#define DMOV_HSUART2_TX_CHAN   8
+#define DMOV_HSUART2_TX_CRCI   13
+
+#define DMOV_HSUART2_RX_CHAN   8
+#define DMOV_HSUART2_RX_CRCI   14
+
+#elif defined(CONFIG_ARCH_MSM8960)
+#define DMOV_GP_CHAN           9
+
+#define DMOV_CE_IN_CHAN        0
+#define DMOV_CE_IN_CRCI        2
+
+#define DMOV_CE_OUT_CHAN       1
+#define DMOV_CE_OUT_CRCI       3
+
+#define DMOV_TSIF_CHAN         2
+#define DMOV_TSIF_CRCI         11
+
+#define DMOV_HSUART_GSBI6_TX_CHAN	7
+#define DMOV_HSUART_GSBI6_TX_CRCI	6
+
+#define DMOV_HSUART_GSBI6_RX_CHAN	8
+#define DMOV_HSUART_GSBI6_RX_CRCI	11
+
+#define DMOV_HSUART_GSBI9_TX_CHAN	4
+#define DMOV_HSUART_GSBI9_TX_CRCI	13
+
+#define DMOV_HSUART_GSBI9_RX_CHAN	3
+#define DMOV_HSUART_GSBI9_RX_CRCI	12
+
+#elif defined(CONFIG_ARCH_MSM9615)
+
+#define DMOV_GP_CHAN          4
+
+#define DMOV_CE_IN_CHAN       0
+#define DMOV_CE_IN_CRCI       12
+
+#define DMOV_CE_OUT_CHAN      1
+#define DMOV_CE_OUT_CRCI      13
+
+#define DMOV_NAND_CHAN        3
+#define DMOV_NAND_CRCI_CMD    15
+#define DMOV_NAND_CRCI_DATA   3
+
+#elif defined(CONFIG_ARCH_FSM9XXX)
+/* defined in dma-fsm9xxx.h */
+
+#else
+#define DMOV_GP_CHAN          4
+
+#define DMOV_CE_IN_CHAN       5
+#define DMOV_CE_IN_CRCI       1
+
+#define DMOV_CE_OUT_CHAN      6
+#define DMOV_CE_OUT_CRCI      2
+
+#define DMOV_CE_HASH_CRCI     3
+
 #define DMOV_NAND_CHAN        7
 #define DMOV_NAND_CRCI_CMD    5
 #define DMOV_NAND_CRCI_DATA   4
@@ -103,11 +229,38 @@
 #define DMOV_SDC2_CHAN        8
 #define DMOV_SDC2_CRCI        7
 
+#define DMOV_SDC3_CHAN        8
+#define DMOV_SDC3_CRCI        12
+
+#define DMOV_SDC4_CHAN        8
+#define DMOV_SDC4_CRCI        13
+
 #define DMOV_TSIF_CHAN        10
 #define DMOV_TSIF_CRCI        10
 
 #define DMOV_USB_CHAN         11
 
+#define DMOV_HSUART1_TX_CHAN   4
+#define DMOV_HSUART1_TX_CRCI   8
+
+#define DMOV_HSUART1_RX_CHAN   9
+#define DMOV_HSUART1_RX_CRCI   9
+
+#define DMOV_HSUART2_TX_CHAN   4
+#define DMOV_HSUART2_TX_CRCI   14
+
+#define DMOV_HSUART2_RX_CHAN   11
+#define DMOV_HSUART2_RX_CRCI   15
+#endif
+
+/* channels for APQ8064 */
+#define DMOV8064_CE_IN_CHAN        0
+#define DMOV8064_CE_IN_CRCI       14
+
+#define DMOV8064_CE_OUT_CHAN       1
+#define DMOV8064_CE_OUT_CRCI       15
+
+
 /* no client rate control ifc (eg, ram) */
 #define DMOV_NONE_CRCI        0
 
diff --git a/arch/arm/mach-msm/include/mach/dma_test.h b/arch/arm/mach-msm/include/mach/dma_test.h
new file mode 100644
index 0000000..c0464fa
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/dma_test.h
@@ -0,0 +1,52 @@
+/* Copyright (c) 2008-2009, 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 __MSM_DMA_TEST__
+#define __MSM_DMA_TEST__
+
+#include <linux/ioctl.h>
+
+#define MSM_DMA_IOC_MAGIC     0x83
+
+/* The testing driver can manage a series of buffers.  These are
+ * allocated and freed using these calls. */
+struct msm_dma_alloc_req {
+	int size;		/* Size of this request, in bytes. */
+	int bufnum;		/* OUT: Number of buffer allocated. */
+};
+#define MSM_DMA_IOALLOC _IOWR(MSM_DMA_IOC_MAGIC, 2, struct msm_dma_alloc_req)
+
+/* Free the specified buffer. */
+#define MSM_DMA_IOFREE _IOW(MSM_DMA_IOC_MAGIC, 3, int)
+
+/* Free all used buffers. */
+#define MSM_DMA_IOFREEALL  _IO(MSM_DMA_IOC_MAGIC, 7)
+
+/* Read/write data into kernel buffer. */
+struct msm_dma_bufxfer {
+	void *data;
+	int size;
+	int bufnum;
+};
+#define MSM_DMA_IOWBUF _IOW(MSM_DMA_IOC_MAGIC, 4, struct msm_dma_bufxfer)
+#define MSM_DMA_IORBUF _IOW(MSM_DMA_IOC_MAGIC, 5, struct msm_dma_bufxfer)
+
+/* Use the data mover to copy from one buffer to another. */
+struct msm_dma_scopy {
+	int srcbuf;
+	int destbuf;
+	int size;
+};
+#define MSM_DMA_IOSCOPY _IOW(MSM_DMA_IOC_MAGIC, 6, struct msm_dma_scopy)
+
+#endif /* __MSM_DMA_TEST__ */
diff --git a/arch/arm/mach-msm/include/mach/entry-macro.S b/arch/arm/mach-msm/include/mach/entry-macro.S
index f2ae908..dd1b54d 100644
--- a/arch/arm/mach-msm/include/mach/entry-macro.S
+++ b/arch/arm/mach-msm/include/mach/entry-macro.S
@@ -1,4 +1,5 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/*
+ * Copyright (c) 2009-2010, 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
@@ -8,12 +9,6 @@
  * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
  */
 
 #if !defined(CONFIG_ARM_GIC)
diff --git a/arch/arm/mach-msm/include/mach/fiq.h b/arch/arm/mach-msm/include/mach/fiq.h
new file mode 100644
index 0000000..29a3ba1
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/fiq.h
@@ -0,0 +1,33 @@
+/* linux/include/asm-arm/arch-msm/irqs.h
+ *
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * 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_FIQ_H
+#define __ASM_ARCH_MSM_FIQ_H
+
+/* cause an interrupt to be an FIQ instead of a regular IRQ */
+void msm_fiq_select(int number);
+void msm_fiq_unselect(int number);
+
+/* enable/disable an interrupt that is an FIQ (not safe from FIQ context) */
+void msm_fiq_enable(int number);
+void msm_fiq_disable(int number);
+
+/* install an FIQ handler */
+int msm_fiq_set_handler(void (*func)(void *data, void *regs), void *data);
+
+/* cause an edge triggered interrupt to fire (safe from FIQ context */
+void msm_trigger_irq(int number);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/gpio-tlmm-v1.h b/arch/arm/mach-msm/include/mach/gpio-tlmm-v1.h
new file mode 100644
index 0000000..e41fe72
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/gpio-tlmm-v1.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+ * Author: Mike Lockwood <lockwood@android.com>
+ *
+ * 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_GPIO_TLMM_V1_H
+#define __ASM_ARCH_MSM_GPIO_TLMM_V1_H
+
+/* GPIO TLMM (Top Level Multiplexing) Definitions */
+
+/* GPIO TLMM: Function -- GPIO specific */
+
+/* GPIO TLMM: Direction */
+enum {
+	GPIO_CFG_INPUT,
+	GPIO_CFG_OUTPUT,
+};
+
+/* GPIO TLMM: Pullup/Pulldown */
+enum {
+	GPIO_CFG_NO_PULL,
+	GPIO_CFG_PULL_DOWN,
+	GPIO_CFG_KEEPER,
+	GPIO_CFG_PULL_UP,
+};
+
+/* GPIO TLMM: Drive Strength */
+enum {
+	GPIO_CFG_2MA,
+	GPIO_CFG_4MA,
+	GPIO_CFG_6MA,
+	GPIO_CFG_8MA,
+	GPIO_CFG_10MA,
+	GPIO_CFG_12MA,
+	GPIO_CFG_14MA,
+	GPIO_CFG_16MA,
+};
+
+enum {
+	GPIO_CFG_ENABLE,
+	GPIO_CFG_DISABLE,
+};
+
+#define GPIO_CFG(gpio, func, dir, pull, drvstr) \
+	((((gpio) & 0x3FF) << 4)        |	\
+	((func) & 0xf)                  |	\
+	(((dir) & 0x1) << 14)           |	\
+	(((pull) & 0x3) << 15)          |	\
+	(((drvstr) & 0xF) << 17))
+
+/**
+ * extract GPIO pin from bit-field used for gpio_tlmm_config
+ */
+#define GPIO_PIN(gpio_cfg)    (((gpio_cfg) >>  4) & 0x3ff)
+#define GPIO_FUNC(gpio_cfg)   (((gpio_cfg) >>  0) & 0xf)
+#define GPIO_DIR(gpio_cfg)    (((gpio_cfg) >> 14) & 0x1)
+#define GPIO_PULL(gpio_cfg)   (((gpio_cfg) >> 15) & 0x3)
+#define GPIO_DRVSTR(gpio_cfg) (((gpio_cfg) >> 17) & 0xf)
+
+int gpio_tlmm_config(unsigned config, unsigned disable);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/gpio-v1.h b/arch/arm/mach-msm/include/mach/gpio-v1.h
new file mode 100644
index 0000000..eea4c88
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/gpio-v1.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+ * Author: Mike Lockwood <lockwood@android.com>
+ *
+ * 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_GPIO_V1_H
+#define __ASM_ARCH_MSM_GPIO_V1_H
+
+#include <linux/interrupt.h>
+#include <asm-generic/gpio.h>
+#include <mach/irqs.h>
+
+#define FIRST_BOARD_GPIO	NR_GPIO_IRQS
+
+static inline int gpio_get_value(unsigned gpio)
+{
+	return __gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned gpio, int value)
+{
+	__gpio_set_value(gpio, value);
+}
+
+static inline int gpio_cansleep(unsigned gpio)
+{
+	return __gpio_cansleep(gpio);
+}
+
+static inline int gpio_to_irq(unsigned gpio)
+{
+	return __gpio_to_irq(gpio);
+}
+
+void msm_gpio_enter_sleep(int from_idle);
+void msm_gpio_exit_sleep(void);
+
+/**
+ * struct msm_gpio - GPIO pin description
+ * @gpio_cfg - configuration bitmap, as per gpio_tlmm_config()
+ * @label - textual label
+ *
+ * Usually, GPIO's are operated by sets.
+ * This struct accumulate all GPIO information in single source
+ * and facilitete group operations provided by msm_gpios_xxx()
+ */
+struct msm_gpio {
+	u32 gpio_cfg;
+	const char *label;
+};
+
+/**
+ * msm_gpios_request_enable() - request and enable set of GPIOs
+ *
+ * Request and configure set of GPIO's
+ * In case of error, all operations rolled back.
+ * Return error code.
+ *
+ * @table: GPIO table
+ * @size:  number of entries in @table
+ */
+int msm_gpios_request_enable(const struct msm_gpio *table, int size);
+
+/**
+ * msm_gpios_disable_free() - disable and free set of GPIOs
+ *
+ * @table: GPIO table
+ * @size:  number of entries in @table
+ */
+void msm_gpios_disable_free(const struct msm_gpio *table, int size);
+
+/**
+ * msm_gpios_request() - request set of GPIOs
+ * In case of error, all operations rolled back.
+ * Return error code.
+ *
+ * @table: GPIO table
+ * @size:  number of entries in @table
+ */
+int msm_gpios_request(const struct msm_gpio *table, int size);
+
+/**
+ * msm_gpios_free() - free set of GPIOs
+ *
+ * @table: GPIO table
+ * @size:  number of entries in @table
+ */
+void msm_gpios_free(const struct msm_gpio *table, int size);
+
+/**
+ * msm_gpios_enable() - enable set of GPIOs
+ * In case of error, all operations rolled back.
+ * Return error code.
+ *
+ * @table: GPIO table
+ * @size:  number of entries in @table
+ */
+int msm_gpios_enable(const struct msm_gpio *table, int size);
+
+/**
+ * msm_gpios_disable() - disable set of GPIOs
+ *
+ * @table: GPIO table
+ * @size:  number of entries in @table
+ */
+int msm_gpios_disable(const struct msm_gpio *table, int size);
+
+/* GPIO TLMM (Top Level Multiplexing) Definitions */
+
+/* GPIO TLMM: Function -- GPIO specific */
+
+/* GPIO TLMM: Direction */
+enum {
+	GPIO_CFG_INPUT,
+	GPIO_CFG_OUTPUT,
+};
+
+/* GPIO TLMM: Pullup/Pulldown */
+enum {
+	GPIO_CFG_NO_PULL,
+	GPIO_CFG_PULL_DOWN,
+	GPIO_CFG_KEEPER,
+	GPIO_CFG_PULL_UP,
+};
+
+/* GPIO TLMM: Drive Strength */
+enum {
+	GPIO_CFG_2MA,
+	GPIO_CFG_4MA,
+	GPIO_CFG_6MA,
+	GPIO_CFG_8MA,
+	GPIO_CFG_10MA,
+	GPIO_CFG_12MA,
+	GPIO_CFG_14MA,
+	GPIO_CFG_16MA,
+};
+
+enum {
+	GPIO_CFG_ENABLE,
+	GPIO_CFG_DISABLE,
+};
+
+#define GPIO_CFG(gpio, func, dir, pull, drvstr) \
+	((((gpio) & 0x3FF) << 4)        |	  \
+	 ((func) & 0xf)                  |	  \
+	 (((dir) & 0x1) << 14)           |	  \
+	 (((pull) & 0x3) << 15)          |	  \
+	 (((drvstr) & 0xF) << 17))
+
+/**
+ * extract GPIO pin from bit-field used for gpio_tlmm_config
+ */
+#define GPIO_PIN(gpio_cfg)    (((gpio_cfg) >>  4) & 0x3ff)
+#define GPIO_FUNC(gpio_cfg)   (((gpio_cfg) >>  0) & 0xf)
+#define GPIO_DIR(gpio_cfg)    (((gpio_cfg) >> 14) & 0x1)
+#define GPIO_PULL(gpio_cfg)   (((gpio_cfg) >> 15) & 0x3)
+#define GPIO_DRVSTR(gpio_cfg) (((gpio_cfg) >> 17) & 0xf)
+
+int gpio_tlmm_config(unsigned config, unsigned disable);
+
+#endif /* __ASM_ARCH_MSM_GPIO_V1_H */
diff --git a/arch/arm/mach-msm/include/mach/gpio.h b/arch/arm/mach-msm/include/mach/gpio.h
index 40a8c17..8aed079 100644
--- a/arch/arm/mach-msm/include/mach/gpio.h
+++ b/arch/arm/mach-msm/include/mach/gpio.h
@@ -1 +1,224 @@
-/* empty */
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+ * Author: Mike Lockwood <lockwood@android.com>
+ *
+ * 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_GPIO_H
+#define __ASM_ARCH_MSM_GPIO_H
+
+#define ARCH_NR_GPIOS 512
+
+#include <linux/interrupt.h>
+#include <asm-generic/gpio.h>
+#include <mach/irqs.h>
+
+#define FIRST_BOARD_GPIO	NR_GPIO_IRQS
+
+extern struct irq_chip msm_gpio_irq_extn;
+
+/**
+ * struct msm_gpio - GPIO pin description
+ * @gpio_cfg - configuration bitmap, as per gpio_tlmm_config()
+ * @label - textual label
+ *
+ * Usually, GPIO's are operated by sets.
+ * This struct accumulate all GPIO information in single source
+ * and facilitete group operations provided by msm_gpios_xxx()
+ */
+struct msm_gpio {
+	u32 gpio_cfg;
+	const char *label;
+};
+
+/**
+ * msm_gpios_request_enable() - request and enable set of GPIOs
+ *
+ * Request and configure set of GPIO's
+ * In case of error, all operations rolled back.
+ * Return error code.
+ *
+ * @table: GPIO table
+ * @size:  number of entries in @table
+ */
+int msm_gpios_request_enable(const struct msm_gpio *table, int size);
+
+/**
+ * msm_gpios_disable_free() - disable and free set of GPIOs
+ *
+ * @table: GPIO table
+ * @size:  number of entries in @table
+ */
+void msm_gpios_disable_free(const struct msm_gpio *table, int size);
+
+/**
+ * msm_gpios_request() - request set of GPIOs
+ * In case of error, all operations rolled back.
+ * Return error code.
+ *
+ * @table: GPIO table
+ * @size:  number of entries in @table
+ */
+int msm_gpios_request(const struct msm_gpio *table, int size);
+
+/**
+ * msm_gpios_free() - free set of GPIOs
+ *
+ * @table: GPIO table
+ * @size:  number of entries in @table
+ */
+void msm_gpios_free(const struct msm_gpio *table, int size);
+
+/**
+ * msm_gpios_enable() - enable set of GPIOs
+ * In case of error, all operations rolled back.
+ * Return error code.
+ *
+ * @table: GPIO table
+ * @size:  number of entries in @table
+ */
+int msm_gpios_enable(const struct msm_gpio *table, int size);
+
+/**
+ * msm_gpios_disable() - disable set of GPIOs
+ *
+ * @table: GPIO table
+ * @size:  number of entries in @table
+ */
+int msm_gpios_disable(const struct msm_gpio *table, int size);
+
+/**
+ * msm_gpios_show_resume_irq() - show the interrupts that could have triggered
+ * resume
+ */
+void msm_gpio_show_resume_irq(void);
+
+/* GPIO TLMM (Top Level Multiplexing) Definitions */
+
+/* GPIO TLMM: Function -- GPIO specific */
+
+/* GPIO TLMM: Direction */
+enum {
+	GPIO_CFG_INPUT,
+	GPIO_CFG_OUTPUT,
+};
+
+/* GPIO TLMM: Pullup/Pulldown */
+enum {
+	GPIO_CFG_NO_PULL,
+	GPIO_CFG_PULL_DOWN,
+	GPIO_CFG_KEEPER,
+	GPIO_CFG_PULL_UP,
+};
+
+/* GPIO TLMM: Drive Strength */
+enum {
+	GPIO_CFG_2MA,
+	GPIO_CFG_4MA,
+	GPIO_CFG_6MA,
+	GPIO_CFG_8MA,
+	GPIO_CFG_10MA,
+	GPIO_CFG_12MA,
+	GPIO_CFG_14MA,
+	GPIO_CFG_16MA,
+};
+
+enum {
+	GPIO_CFG_ENABLE,
+	GPIO_CFG_DISABLE,
+};
+
+#define GPIO_CFG(gpio, func, dir, pull, drvstr) \
+	((((gpio) & 0x3FF) << 4)        |	  \
+	 ((func) & 0xf)                  |	  \
+	 (((dir) & 0x1) << 14)           |	  \
+	 (((pull) & 0x3) << 15)          |	  \
+	 (((drvstr) & 0xF) << 17))
+
+/**
+ * extract GPIO pin from bit-field used for gpio_tlmm_config
+ */
+#define GPIO_PIN(gpio_cfg)    (((gpio_cfg) >>  4) & 0x3ff)
+#define GPIO_FUNC(gpio_cfg)   (((gpio_cfg) >>  0) & 0xf)
+#define GPIO_DIR(gpio_cfg)    (((gpio_cfg) >> 14) & 0x1)
+#define GPIO_PULL(gpio_cfg)   (((gpio_cfg) >> 15) & 0x3)
+#define GPIO_DRVSTR(gpio_cfg) (((gpio_cfg) >> 17) & 0xf)
+
+int gpio_tlmm_config(unsigned config, unsigned disable);
+
+enum msm_tlmm_hdrive_tgt {
+	TLMM_HDRV_SDC4_CLK = 0,
+	TLMM_HDRV_SDC4_CMD,
+	TLMM_HDRV_SDC4_DATA,
+	TLMM_HDRV_SDC3_CLK,
+	TLMM_HDRV_SDC3_CMD,
+	TLMM_HDRV_SDC3_DATA,
+	TLMM_HDRV_SDC1_CLK,
+	TLMM_HDRV_SDC1_CMD,
+	TLMM_HDRV_SDC1_DATA,
+};
+
+enum msm_tlmm_pull_tgt {
+	TLMM_PULL_SDC4_CMD = 0,
+	TLMM_PULL_SDC4_DATA,
+	TLMM_PULL_SDC3_CLK,
+	TLMM_PULL_SDC3_CMD,
+	TLMM_PULL_SDC3_DATA,
+	TLMM_PULL_SDC1_CLK,
+	TLMM_PULL_SDC1_CMD,
+	TLMM_PULL_SDC1_DATA,
+};
+
+#ifdef CONFIG_GPIO_MSM_V2
+void msm_tlmm_set_hdrive(enum msm_tlmm_hdrive_tgt tgt, int drv_str);
+void msm_tlmm_set_pull(enum msm_tlmm_pull_tgt tgt, int pull);
+
+/*
+ * A GPIO can be set as a direct-connect IRQ.  This can be used to bypass
+ * the normal summary-interrupt mechanism for those GPIO lines deemed to be
+ * higher priority or otherwise worthy of special treatment, but resources
+ * are limited: only a few DC interrupt lines are available.
+ * Care must be taken when usurping a GPIO in this manner, as the summary
+ * interrupt controller has no idea that the GPIO has been taken away from it.
+ * Clients can still register to receive the summary interrupt assigned
+ * to that GPIO, which will uninstall it as a direct connect IRQ with
+ * no warning.
+ *
+ * The irq passed to this function is the DC IRQ number, not the
+ * irq number seen by the scorpion when the interrupt triggers.  For example,
+ * if 0 is specified, then when DC IRQ 0 triggers, the scorpion will see
+ * interrupt TLMM_MSM_DIR_CONN_IRQ_0.
+ *
+ * input_polarity parameter specifies when the gpio should raise the direct
+ * interrupt. A value of 0 means that it is active low, anything else means
+ * active high
+ *
+ */
+int msm_gpio_install_direct_irq(unsigned gpio, unsigned irq,
+						unsigned int input_polarity);
+#else
+static inline void msm_tlmm_set_hdrive(enum msm_tlmm_hdrive_tgt tgt,
+				       int drv_str) {}
+static inline void msm_tlmm_set_pull(enum msm_tlmm_pull_tgt tgt, int pull) {}
+static inline int msm_gpio_install_direct_irq(unsigned gpio, unsigned irq,
+						unsigned int input_polarity)
+{
+	return -ENOSYS;
+}
+#endif
+
+#ifdef CONFIG_OF
+int __init msm_gpio_of_init(struct device_node *node,
+			    struct device_node *parent);
+#endif
+
+#endif /* __ASM_ARCH_MSM_GPIO_H */
diff --git a/arch/arm/mach-msm/include/mach/gpiomux.h b/arch/arm/mach-msm/include/mach/gpiomux.h
new file mode 100644
index 0000000..f75b0e0
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/gpiomux.h
@@ -0,0 +1,177 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __ARCH_ARM_MACH_MSM_GPIOMUX_H
+#define __ARCH_ARM_MACH_MSM_GPIOMUX_H
+
+#include <linux/bitops.h>
+#include <linux/errno.h>
+
+enum msm_gpiomux_setting {
+	GPIOMUX_ACTIVE = 0,
+	GPIOMUX_SUSPENDED,
+	GPIOMUX_NSETTINGS
+};
+
+enum gpiomux_drv {
+	GPIOMUX_DRV_2MA = 0,
+	GPIOMUX_DRV_4MA,
+	GPIOMUX_DRV_6MA,
+	GPIOMUX_DRV_8MA,
+	GPIOMUX_DRV_10MA,
+	GPIOMUX_DRV_12MA,
+	GPIOMUX_DRV_14MA,
+	GPIOMUX_DRV_16MA,
+};
+
+enum gpiomux_func {
+	GPIOMUX_FUNC_GPIO = 0,
+	GPIOMUX_FUNC_1,
+	GPIOMUX_FUNC_2,
+	GPIOMUX_FUNC_3,
+	GPIOMUX_FUNC_4,
+	GPIOMUX_FUNC_5,
+	GPIOMUX_FUNC_6,
+	GPIOMUX_FUNC_7,
+	GPIOMUX_FUNC_8,
+	GPIOMUX_FUNC_9,
+	GPIOMUX_FUNC_A,
+	GPIOMUX_FUNC_B,
+	GPIOMUX_FUNC_C,
+	GPIOMUX_FUNC_D,
+	GPIOMUX_FUNC_E,
+	GPIOMUX_FUNC_F,
+};
+
+enum gpiomux_pull {
+	GPIOMUX_PULL_NONE = 0,
+	GPIOMUX_PULL_DOWN,
+	GPIOMUX_PULL_KEEPER,
+	GPIOMUX_PULL_UP,
+};
+
+/* Direction settings are only meaningful when GPIOMUX_FUNC_GPIO is selected.
+ * This element is ignored for all other FUNC selections, as the output-
+ * enable pin is not under software control in those cases.  See the SWI
+ * for your target for more details.
+ */
+enum gpiomux_dir {
+	GPIOMUX_IN = 0,
+	GPIOMUX_OUT_HIGH,
+	GPIOMUX_OUT_LOW,
+};
+
+struct gpiomux_setting {
+	enum gpiomux_func func;
+	enum gpiomux_drv  drv;
+	enum gpiomux_pull pull;
+	enum gpiomux_dir  dir;
+};
+
+/**
+ * struct msm_gpiomux_config: gpiomux settings for one gpio line.
+ *
+ * A complete gpiomux config is the combination of a drive-strength,
+ * function, pull, and (sometimes) direction.  For functions other than GPIO,
+ * the input/output setting is hard-wired according to the function.
+ *
+ * @gpio: The index number of the gpio being described.
+ * @settings: The settings to be installed, specifically:
+ *           GPIOMUX_ACTIVE: The setting to be installed when the
+ *           line is active, or its reference count is > 0.
+ *           GPIOMUX_SUSPENDED: The setting to be installed when
+ *           the line is suspended, or its reference count is 0.
+ */
+struct msm_gpiomux_config {
+	unsigned gpio;
+	struct gpiomux_setting *settings[GPIOMUX_NSETTINGS];
+};
+
+/**
+ * struct msm_gpiomux_configs: a collection of gpiomux configs.
+ *
+ * It is so common to manage blocks of gpiomux configs that the data structure
+ * for doing so has been standardized here as a convenience.
+ *
+ * @cfg:  A pointer to the first config in an array of configs.
+ * @ncfg: The number of configs in the array.
+ */
+struct msm_gpiomux_configs {
+	struct msm_gpiomux_config *cfg;
+	size_t                     ncfg;
+};
+
+#ifdef CONFIG_MSM_GPIOMUX
+
+/* Before using gpiomux, initialize the subsystem by telling it how many
+ * gpios are going to be managed.  Calling any other gpiomux functions before
+ * msm_gpiomux_init is unsupported.
+ */
+int msm_gpiomux_init(size_t ngpio);
+
+/* Install a block of gpiomux configurations in gpiomux.  This is functionally
+ * identical to calling msm_gpiomux_write many times.
+ */
+void msm_gpiomux_install(struct msm_gpiomux_config *configs, unsigned nconfigs);
+
+/* Increment a gpio's reference count, possibly activating the line. */
+int __must_check msm_gpiomux_get(unsigned gpio);
+
+/* Decrement a gpio's reference count, possibly suspending the line. */
+int msm_gpiomux_put(unsigned gpio);
+
+/* Install a new setting in a gpio.  To erase a slot, use NULL.
+ * The old setting that was overwritten can be passed back to the caller
+ * old_setting can be NULL if the caller is not interested in the previous
+ * setting
+ * If a previous setting was not available to return (NULL configuration)
+ * - the function returns 1
+ * else function returns 0
+ */
+int msm_gpiomux_write(unsigned gpio, enum msm_gpiomux_setting which,
+	struct gpiomux_setting *setting, struct gpiomux_setting *old_setting);
+
+/* Architecture-internal function for use by the framework only.
+ * This function can assume the following:
+ * - the gpio value has passed a bounds-check
+ * - the gpiomux spinlock has been obtained
+ *
+ * This function is not for public consumption.  External users
+ * should use msm_gpiomux_write.
+ */
+void __msm_gpiomux_write(unsigned gpio, struct gpiomux_setting val);
+#else
+static inline int msm_gpiomux_init(size_t ngpio)
+{
+	return -ENOSYS;
+}
+
+static inline void
+msm_gpiomux_install(struct msm_gpiomux_config *configs, unsigned nconfigs) {}
+
+static inline int __must_check msm_gpiomux_get(unsigned gpio)
+{
+	return -ENOSYS;
+}
+
+static inline int msm_gpiomux_put(unsigned gpio)
+{
+	return -ENOSYS;
+}
+
+static inline int msm_gpiomux_write(unsigned gpio,
+	enum msm_gpiomux_setting which, struct gpiomux_setting *setting,
+	struct gpiomux_setting *old_setting)
+{
+	return -ENOSYS;
+}
+#endif
+#endif
diff --git a/arch/arm/mach-msm/include/mach/hardware.h b/arch/arm/mach-msm/include/mach/hardware.h
index 2d12609..7b7cbaa 100644
--- a/arch/arm/mach-msm/include/mach/hardware.h
+++ b/arch/arm/mach-msm/include/mach/hardware.h
@@ -1,6 +1,7 @@
 /* arch/arm/mach-msm/include/mach/hardware.h
  *
  * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2012, Code Aurora Forum. 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
@@ -14,5 +15,8 @@
  */
 
 #ifndef __ASM_ARCH_MSM_HARDWARE_H
+#define __ASM_ARCH_MSM_HARDWARE_H
+
+#define pcibios_assign_all_busses()     1
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/htc_35mm_jack.h b/arch/arm/mach-msm/include/mach/htc_35mm_jack.h
new file mode 100644
index 0000000..5ce1e2a
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/htc_35mm_jack.h
@@ -0,0 +1,31 @@
+/* arch/arm/mach-msm/include/mach/htc_35mm_jack.h
+ *
+ * Copyright (C) 2009 HTC, Inc.
+ * Author: Arec Kao <Arec_Kao@htc.com>
+ *
+ * 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 HTC_35MM_REMOTE_H
+#define HTC_35MM_REMOTE_H
+
+/* Driver interfaces */
+int htc_35mm_jack_plug_event(int insert, int *hpin_stable);
+int htc_35mm_key_event(int key, int *hpin_stable);
+
+/* Platform Specific Callbacks */
+struct h35mm_platform_data {
+	int (*plug_event_enable)(void);
+	int (*headset_has_mic)(void);
+	int (*key_event_enable)(void);
+	int (*key_event_disable)(void);
+};
+#endif
diff --git a/arch/arm/mach-msm/include/mach/htc_acoustic_qsd.h b/arch/arm/mach-msm/include/mach/htc_acoustic_qsd.h
new file mode 100644
index 0000000..2139bf9
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/htc_acoustic_qsd.h
@@ -0,0 +1,29 @@
+/* include/asm/mach-msm/htc_acoustic_qsd.h
+ *
+ * Copyright (C) 2009 HTC Corporation.
+ *
+ * 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 _ARCH_ARM_MACH_MSM_HTC_ACOUSTIC_QSD_H_
+#define _ARCH_ARM_MACH_MSM_HTC_ACOUSTIC_QSD_H_
+
+struct qsd_acoustic_ops {
+	void (*enable_mic_bias)(int en);
+};
+
+void acoustic_register_ops(struct qsd_acoustic_ops *ops);
+
+int turn_mic_bias_on(int on);
+int force_headset_speaker_on(int enable);
+int enable_aux_loopback(uint32_t enable);
+
+#endif
+
diff --git a/arch/arm/mach-msm/include/mach/htc_headset.h b/arch/arm/mach-msm/include/mach/htc_headset.h
new file mode 100644
index 0000000..2f4c18d
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/htc_headset.h
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2008 HTC, Inc.
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * 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_HTC_HEADSET_H
+#define __ASM_ARCH_HTC_HEADSET_H
+
+struct h2w_platform_data {
+	char *power_name;
+	int cable_in1;
+	int cable_in2;
+	int h2w_clk;
+	int h2w_data;
+	int debug_uart;
+	void (*config_cpld)(int);
+	void (*init_cpld)(void);
+	void (*set_dat)(int);
+	void (*set_clk)(int);
+	void (*set_dat_dir)(int);
+	void (*set_clk_dir)(int);
+	int (*get_dat)(void);
+	int (*get_clk)(void);
+};
+
+#define BIT_HEADSET		(1 << 0)
+#define BIT_HEADSET_NO_MIC	(1 << 1)
+#define BIT_TTY			(1 << 2)
+#define BIT_FM_HEADSET 		(1 << 3)
+#define BIT_FM_SPEAKER		(1 << 4)
+
+enum {
+	H2W_NO_DEVICE	= 0,
+	H2W_HTC_HEADSET	= 1,
+/*	H2W_TTY_DEVICE	= 2,*/
+	NORMAL_HEARPHONE= 2,
+	H2W_DEVICE		= 3,
+	H2W_USB_CRADLE	= 4,
+	H2W_UART_DEBUG	= 5,
+};
+
+enum {
+	H2W_GPIO	= 0,
+	H2W_UART1	= 1,
+	H2W_UART3	= 2,
+	H2W_BT		= 3
+};
+
+#define RESEND_DELAY		(3)	/* ms */
+#define MAX_ACK_RESEND_TIMES	(6)	/* follow spec */
+#define MAX_HOST_RESEND_TIMES	(3)	/* follow spec */
+#define MAX_HYGEIA_RESEND_TIMES	(5)
+
+#define H2W_ASCR_DEVICE_INI	(0x01)
+#define H2W_ASCR_ACT_EN		(0x02)
+#define H2W_ASCR_PHONE_IN	(0x04)
+#define H2W_ASCR_RESET		(0x08)
+#define H2W_ASCR_AUDIO_IN	(0x10)
+
+#define H2W_LED_OFF		(0x0)
+#define H2W_LED_BKL		(0x1)
+#define H2W_LED_MTL		(0x2)
+
+typedef enum {
+	/* === system group 0x0000~0x00FF === */
+	/* (R) Accessory type register */
+	H2W_SYSTEM		= 0x0000,
+	/* (R) Maximum group address */
+	H2W_MAX_GP_ADD		= 0x0001,
+	/* (R/W) Accessory system control register0 */
+	H2W_ASCR0		= 0x0002,
+
+	/* === key group 0x0100~0x01FF === */
+	/* (R) Key group maximum sub address */
+	H2W_KEY_MAXADD		= 0x0100,
+	/* (R) ASCII key press down flag */
+	H2W_ASCII_DOWN		= 0x0101,
+	/* (R) ASCII key release up flag */
+	H2W_ASCII_UP		= 0x0102,
+	/* (R) Function key status flag */
+	H2W_FNKEY_UPDOWN	= 0x0103,
+	/* (R/W) Key device status */
+	H2W_KD_STATUS		= 0x0104,
+
+	/* === led group 0x0200~0x02FF === */
+	/* (R) LED group maximum sub address */
+	H2W_LED_MAXADD		= 0x0200,
+	/* (R/W) LED control register0 */
+	H2W_LEDCT0		= 0x0201,
+
+	/* === crdl group 0x0300~0x03FF === */
+	/* (R) Cardle group maximum sub address */
+	H2W_CRDL_MAXADD		= 0x0300,
+	/* (R/W) Cardle group function control register0 */
+	H2W_CRDLCT0		= 0x0301,
+
+	/* === car kit group 0x0400~0x04FF === */
+	H2W_CARKIT_MAXADD	= 0x0400,
+
+	/* === usb host group 0x0500~0x05FF === */
+	H2W_USBHOST_MAXADD	= 0x0500,
+
+	/* === medical group 0x0600~0x06FF === */
+	H2W_MED_MAXADD		= 0x0600,
+	H2W_MED_CONTROL		= 0x0601,
+	H2W_MED_IN_DATA		= 0x0602,
+} H2W_ADDR;
+
+
+typedef struct H2W_INFO {
+	/* system group */
+	unsigned char CLK_SP;
+	int SLEEP_PR;
+	unsigned char HW_REV;
+	int AUDIO_DEVICE;
+	unsigned char ACC_CLASS;
+	unsigned char MAX_GP_ADD;
+
+	/* key group */
+	int KEY_MAXADD;
+	int ASCII_DOWN;
+	int ASCII_UP;
+	int FNKEY_UPDOWN;
+	int KD_STATUS;
+
+	/* led group */
+	int LED_MAXADD;
+	int LEDCT0;
+
+	/* medical group */
+	int MED_MAXADD;
+	unsigned char AP_ID;
+	unsigned char AP_EN;
+	unsigned char DATA_EN;
+} H2W_INFO;
+
+typedef enum {
+	H2W_500KHz	= 1,
+	H2W_250KHz	= 2,
+	H2W_166KHz	= 3,
+	H2W_125KHz	= 4,
+	H2W_100KHz	= 5,
+	H2W_83KHz	= 6,
+	H2W_71KHz	= 7,
+	H2W_62KHz	= 8,
+	H2W_55KHz	= 9,
+	H2W_50KHz	= 10,
+} H2W_SPEED;
+
+typedef enum {
+	H2W_KEY_INVALID	 = -1,
+	H2W_KEY_PLAY	 = 0,
+	H2W_KEY_FORWARD  = 1,
+	H2W_KEY_BACKWARD = 2,
+	H2W_KEY_VOLUP	 = 3,
+	H2W_KEY_VOLDOWN	 = 4,
+	H2W_KEY_PICKUP	 = 5,
+	H2W_KEY_HANGUP	 = 6,
+	H2W_KEY_MUTE	 = 7,
+	H2W_KEY_HOLD	 = 8,
+	H2W_NUM_KEYFUNC	 = 9,
+} KEYFUNC;
+#endif
diff --git a/arch/arm/mach-msm/include/mach/htc_pwrsink.h b/arch/arm/mach-msm/include/mach/htc_pwrsink.h
new file mode 100644
index 0000000..c7a91f1
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/htc_pwrsink.h
@@ -0,0 +1,87 @@
+/* include/asm/mach-msm/htc_pwrsink.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation.
+ *
+ * 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 _ARCH_ARM_MACH_MSM_HTC_PWRSINK_H_
+#define _ARCH_ARM_MACH_MSM_HTC_PWRSINK_H_
+
+#include <linux/platform_device.h>
+#include <linux/earlysuspend.h>
+
+typedef enum {
+	PWRSINK_AUDIO_PCM = 0,
+	PWRSINK_AUDIO_MP3,
+	PWRSINK_AUDIO_AAC,
+
+	PWRSINK_AUDIO_LAST = PWRSINK_AUDIO_AAC,
+	PWRSINK_AUDIO_INVALID
+} pwrsink_audio_id_type;
+
+struct pwr_sink_audio {
+	unsigned volume;
+	unsigned percent;
+};
+
+typedef enum {
+	PWRSINK_SYSTEM_LOAD = 0,
+	PWRSINK_AUDIO,
+	PWRSINK_BACKLIGHT,
+	PWRSINK_LED_BUTTON,
+	PWRSINK_LED_KEYBOARD,
+	PWRSINK_GP_CLK,
+	PWRSINK_BLUETOOTH,
+	PWRSINK_CAMERA,
+	PWRSINK_SDCARD,
+	PWRSINK_VIDEO,
+	PWRSINK_WIFI,
+
+	PWRSINK_LAST = PWRSINK_WIFI,
+	PWRSINK_INVALID
+} pwrsink_id_type;
+
+struct pwr_sink {
+	pwrsink_id_type	id;
+	unsigned	ua_max;
+	unsigned	percent_util;
+};
+
+struct pwr_sink_platform_data {
+	unsigned	num_sinks;
+	struct pwr_sink	*sinks;
+	int (*suspend_late)(struct platform_device *, pm_message_t state);
+	int (*resume_early)(struct platform_device *);
+	void (*suspend_early)(struct early_suspend *);
+	void (*resume_late)(struct early_suspend *);
+};
+
+#ifndef CONFIG_HTC_PWRSINK
+static inline int htc_pwrsink_set(pwrsink_id_type id, unsigned percent)
+{
+	return 0;
+}
+static inline int htc_pwrsink_audio_set(pwrsink_audio_id_type id,
+	unsigned percent_utilized) { return 0; }
+static inline int htc_pwrsink_audio_volume_set(
+	pwrsink_audio_id_type id, unsigned volume) { return 0; }
+static inline int htc_pwrsink_audio_path_set(unsigned path) { return 0; }
+#else
+extern int htc_pwrsink_set(pwrsink_id_type id, unsigned percent);
+extern int htc_pwrsink_audio_set(pwrsink_audio_id_type id,
+	unsigned percent_utilized);
+extern int htc_pwrsink_audio_volume_set(pwrsink_audio_id_type id,
+	unsigned volume);
+extern int htc_pwrsink_audio_path_set(unsigned path);
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/io.h b/arch/arm/mach-msm/include/mach/io.h
new file mode 100644
index 0000000..445e175
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/io.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ *
+ * 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_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+#define __io(a)		__typesafe_io(a)
+#define __mem_pci(a)	(a)
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index 5c7c955..b57ae10 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -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
@@ -8,11 +8,6 @@
  * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
  */
 
 #ifndef MSM_IOMMU_H
@@ -20,16 +15,13 @@
 
 #include <linux/interrupt.h>
 #include <linux/clk.h>
+#include <mach/socinfo.h>
 
-/* Sharability attributes of MSM IOMMU mappings */
-#define MSM_IOMMU_ATTR_NON_SH		0x0
-#define MSM_IOMMU_ATTR_SH		0x4
+extern pgprot_t     pgprot_kernel;
+extern struct platform_device *msm_iommu_root_dev;
 
-/* Cacheability attributes of MSM IOMMU mappings */
-#define MSM_IOMMU_ATTR_NONCACHED	0x0
-#define MSM_IOMMU_ATTR_CACHED_WB_WA	0x1
-#define MSM_IOMMU_ATTR_CACHED_WB_NWA	0x2
-#define MSM_IOMMU_ATTR_CACHED_WT	0x3
+/* Domain attributes */
+#define MSM_IOMMU_DOMAIN_PT_CACHEABLE	0x1
 
 /* Mask for the cache policy attribute */
 #define MSM_IOMMU_CP_MASK		0x03
@@ -50,6 +42,7 @@
 struct msm_iommu_dev {
 	const char *name;
 	int ncb;
+	int ttbr_split;
 };
 
 /**
@@ -81,10 +74,11 @@
  */
 struct msm_iommu_drvdata {
 	void __iomem *base;
-	int irq;
 	int ncb;
+	int ttbr_split;
 	struct clk *clk;
 	struct clk *pclk;
+	const char *name;
 };
 
 /**
@@ -101,20 +95,53 @@
 	int num;
 	struct platform_device *pdev;
 	struct list_head attached_elm;
+	struct iommu_domain *attached_domain;
+	const char *name;
 };
 
 /*
- * Look up an IOMMU context device by its context name. NULL if none found.
- * Useful for testing and drivers that do not yet fully have IOMMU stuff in
- * their platform devices.
- */
-struct device *msm_iommu_get_ctx(const char *ctx_name);
-
-/*
  * Interrupt handler for the IOMMU context fault interrupt. Hooking the
  * interrupt is not supported in the API yet, but this will print an error
  * message and dump useful IOMMU registers.
  */
 irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id);
+irqreturn_t msm_iommu_fault_handler_v2(int irq, void *dev_id);
+
+#ifdef CONFIG_MSM_IOMMU
+/*
+ * Look up an IOMMU context device by its context name. NULL if none found.
+ * Useful for testing and drivers that do not yet fully have IOMMU stuff in
+ * their platform devices.
+ */
+struct device *msm_iommu_get_ctx(const char *ctx_name);
+#else
+static inline struct device *msm_iommu_get_ctx(const char *ctx_name)
+{
+	return NULL;
+}
+#endif
 
 #endif
+
+static inline int msm_soc_version_supports_iommu_v1(void)
+{
+#ifdef CONFIG_OF
+	struct device_node *node;
+
+	node = of_find_compatible_node(NULL, NULL, "qcom,msm-smmu-v2");
+	if (node) {
+		of_node_put(node);
+		return 0;
+	}
+#endif
+	if (cpu_is_msm8960() &&
+	    SOCINFO_VERSION_MAJOR(socinfo_get_version()) < 2)
+		return 0;
+
+	if (cpu_is_msm8x60() &&
+	    (SOCINFO_VERSION_MAJOR(socinfo_get_version()) != 2 ||
+	    SOCINFO_VERSION_MINOR(socinfo_get_version()) < 1))	{
+		return 0;
+	}
+	return 1;
+}
diff --git a/arch/arm/mach-msm/include/mach/iommu_domains.h b/arch/arm/mach-msm/include/mach/iommu_domains.h
new file mode 100644
index 0000000..1a3a022
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/iommu_domains.h
@@ -0,0 +1,180 @@
+/* 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
+ * 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 _ARCH_IOMMU_DOMAINS_H
+#define _ARCH_IOMMU_DOMAINS_H
+
+#include <linux/memory_alloc.h>
+
+enum {
+	VIDEO_DOMAIN,
+	CAMERA_DOMAIN,
+	DISPLAY_DOMAIN,
+	ROTATOR_DOMAIN,
+	MAX_DOMAINS
+};
+
+enum {
+	VIDEO_FIRMWARE_POOL,
+	VIDEO_MAIN_POOL,
+	GEN_POOL,
+};
+
+struct msm_iommu_domain_name {
+	char *name;
+	int domain;
+};
+
+struct msm_iommu_domain {
+	/* iommu domain to map in */
+	struct iommu_domain *domain;
+	/* total number of allocations from this domain */
+	atomic_t allocation_cnt;
+	/* number of iova pools */
+	int npools;
+	/*
+	 * array of gen_pools for allocating iovas.
+	 * behavior is undefined if these overlap
+	 */
+	struct mem_pool *iova_pools;
+};
+
+struct iommu_domains_pdata {
+	struct msm_iommu_domain *domains;
+	int ndomains;
+	struct msm_iommu_domain_name *domain_names;
+	int nnames;
+	unsigned int domain_alloc_flags;
+};
+
+
+struct msm_iova_partition {
+	unsigned long start;
+	unsigned long size;
+};
+
+struct msm_iova_layout {
+	struct msm_iova_partition *partitions;
+	int npartitions;
+	const char *client_name;
+	unsigned int domain_flags;
+};
+
+#if defined(CONFIG_MSM_IOMMU)
+
+extern struct iommu_domain *msm_get_iommu_domain(int domain_num);
+
+extern int msm_allocate_iova_address(unsigned int iommu_domain,
+					unsigned int partition_no,
+					unsigned long size,
+					unsigned long align,
+					unsigned long *iova);
+
+extern void msm_free_iova_address(unsigned long iova,
+			unsigned int iommu_domain,
+			unsigned int partition_no,
+			unsigned long size);
+
+extern int msm_use_iommu(void);
+
+extern int msm_iommu_map_extra(struct iommu_domain *domain,
+						unsigned long start_iova,
+						unsigned long size,
+						unsigned long page_size,
+						int cached);
+
+extern void msm_iommu_unmap_extra(struct iommu_domain *domain,
+						unsigned long start_iova,
+						unsigned long size,
+						unsigned long page_size);
+
+extern int msm_iommu_map_contig_buffer(unsigned long phys,
+				unsigned int domain_no,
+				unsigned int partition_no,
+				unsigned long size,
+				unsigned long align,
+				unsigned long cached,
+				unsigned long *iova_val);
+
+
+extern void msm_iommu_unmap_contig_buffer(unsigned long iova,
+					unsigned int domain_no,
+					unsigned int partition_no,
+					unsigned long size);
+
+extern int msm_register_domain(struct msm_iova_layout *layout);
+
+#else
+static inline struct iommu_domain
+	*msm_get_iommu_domain(int subsys_id) { return NULL; }
+
+
+
+static inline int msm_allocate_iova_address(unsigned int iommu_domain,
+					unsigned int partition_no,
+					unsigned long size,
+					unsigned long align,
+					unsigned long *iova) { return -ENOMEM; }
+
+static inline void msm_free_iova_address(unsigned long iova,
+			unsigned int iommu_domain,
+			unsigned int partition_no,
+			unsigned long size) { return; }
+
+static inline int msm_use_iommu(void)
+{
+	return 0;
+}
+
+static inline int msm_iommu_map_extra(struct iommu_domain *domain,
+						unsigned long start_iova,
+						unsigned long size,
+						unsigned long page_size,
+						int cached)
+{
+	return -ENODEV;
+}
+
+static inline void msm_iommu_unmap_extra(struct iommu_domain *domain,
+						unsigned long start_iova,
+						unsigned long size,
+						unsigned long page_size)
+{
+}
+
+static inline int msm_iommu_map_contig_buffer(unsigned long phys,
+				unsigned int domain_no,
+				unsigned int partition_no,
+				unsigned long size,
+				unsigned long align,
+				unsigned long cached,
+				unsigned long *iova_val)
+{
+	*iova_val = phys;
+	return 0;
+}
+
+static inline void msm_iommu_unmap_contig_buffer(unsigned long iova,
+					unsigned int domain_no,
+					unsigned int partition_no,
+					unsigned long size)
+{
+	return;
+}
+
+static inline int msm_register_domain(struct msm_iova_layout *layout)
+{
+	return -ENODEV;
+}
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/iommu_hw-8xxx.h b/arch/arm/mach-msm/include/mach/iommu_hw-8xxx.h
index fc16010..af82fd9 100644
--- a/arch/arm/mach-msm/include/mach/iommu_hw-8xxx.h
+++ b/arch/arm/mach-msm/include/mach/iommu_hw-8xxx.h
@@ -8,11 +8,6 @@
  * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
  */
 
 #ifndef __ARCH_ARM_MACH_MSM_IOMMU_HW_8XXX_H
@@ -20,14 +15,14 @@
 
 #define CTX_SHIFT 12
 
-#define GET_GLOBAL_REG(reg, base) (readl((base) + (reg)))
+#define GET_GLOBAL_REG(reg, base) (readl_relaxed((base) + (reg)))
 #define GET_CTX_REG(reg, base, ctx) \
-				(readl((base) + (reg) + ((ctx) << CTX_SHIFT)))
+			(readl_relaxed((base) + (reg) + ((ctx) << CTX_SHIFT)))
 
-#define SET_GLOBAL_REG(reg, base, val)	writel((val), ((base) + (reg)))
+#define SET_GLOBAL_REG(reg, base, val)	writel_relaxed((val), ((base) + (reg)))
 
 #define SET_CTX_REG(reg, base, ctx, val) \
-			writel((val), ((base) + (reg) + ((ctx) << CTX_SHIFT)))
+		writel_relaxed((val), ((base) + (reg) + ((ctx) << CTX_SHIFT)))
 
 /* Wrappers for numbered registers */
 #define SET_GLOBAL_REG_N(b, n, r, v) SET_GLOBAL_REG(b, ((r) + (n << 2)), (v))
@@ -43,12 +38,13 @@
 #define SET_CONTEXT_FIELD(b, c, r, F, v)	\
 	SET_FIELD(((b) + (r) + ((c) << CTX_SHIFT)), F##_MASK, F##_SHIFT, (v))
 
-#define GET_FIELD(addr, mask, shift)  ((readl(addr) >> (shift)) & (mask))
+#define GET_FIELD(addr, mask, shift) ((readl_relaxed(addr) >> (shift)) & (mask))
 
 #define SET_FIELD(addr, mask, shift, v) \
 do { \
-	int t = readl(addr); \
-	writel((t & ~((mask) << (shift))) + (((v) & (mask)) << (shift)), addr);\
+	int t = readl_relaxed(addr); \
+	writel_relaxed((t & ~((mask) << (shift))) + (((v) & \
+		       (mask)) << (shift)), addr);\
 } while (0)
 
 
@@ -61,8 +57,9 @@
 #define FL_TYPE_TABLE		(1 << 0)
 #define FL_TYPE_SECT		(2 << 0)
 #define FL_SUPERSECTION		(1 << 18)
-#define FL_AP_WRITE		(1 << 10)
-#define FL_AP_READ		(1 << 11)
+#define FL_AP0			(1 << 10)
+#define FL_AP1			(1 << 11)
+#define FL_AP2			(1 << 15)
 #define FL_SHARED		(1 << 16)
 #define FL_BUFFERABLE		(1 << 2)
 #define FL_CACHEABLE		(1 << 3)
@@ -77,6 +74,7 @@
 #define SL_TYPE_SMALL		(2 << 0)
 #define SL_AP0			(1 << 4)
 #define SL_AP1			(2 << 4)
+#define SL_AP2			(1 << 9)
 #define SL_SHARED		(1 << 10)
 #define SL_BUFFERABLE		(1 << 2)
 #define SL_CACHEABLE		(1 << 3)
diff --git a/arch/arm/mach-msm/include/mach/iommu_hw-v2.h b/arch/arm/mach-msm/include/mach/iommu_hw-v2.h
new file mode 100644
index 0000000..fac13b3
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/iommu_hw-v2.h
@@ -0,0 +1,2111 @@
+/* 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 __ARCH_ARM_MACH_MSM_IOMMU_HW_V2_H
+#define __ARCH_ARM_MACH_MSM_IOMMU_HW_V2_H
+
+#define CTX_SHIFT  12
+#define CTX_OFFSET 0x8000
+
+#define MAX_NUM_SMR 128
+
+#define GET_GLOBAL_REG(reg, base) (readl_relaxed((base) + (reg)))
+#define GET_CTX_REG(reg, base, ctx) \
+	(readl_relaxed((base) + CTX_OFFSET + (reg) + ((ctx) << CTX_SHIFT)))
+
+#define SET_GLOBAL_REG(reg, base, val)	writel_relaxed((val), ((base) + (reg)))
+
+#define SET_CTX_REG(reg, base, ctx, val) \
+	writel_relaxed((val), \
+		((base) + CTX_OFFSET + (reg) + ((ctx) << CTX_SHIFT)))
+
+/* Wrappers for numbered registers */
+#define SET_GLOBAL_REG_N(b, n, r, v) SET_GLOBAL_REG((b), ((r) + (n << 2)), (v))
+#define GET_GLOBAL_REG_N(b, n, r)    GET_GLOBAL_REG((b), ((r) + (n << 2)))
+
+/* Field wrappers */
+#define GET_GLOBAL_FIELD(b, r, F) \
+	GET_FIELD(((b) + (r)), r##_##F##_MASK, r##_##F##_SHIFT)
+#define GET_CONTEXT_FIELD(b, c, r, F) \
+	GET_FIELD(((b) + CTX_OFFSET + (r) + ((c) << CTX_SHIFT)), \
+			r##_##F##_MASK, r##_##F##_SHIFT)
+
+#define SET_GLOBAL_FIELD(b, r, F, v) \
+	SET_FIELD(((b) + (r)), r##_##F##_MASK, r##_##F##_SHIFT, (v))
+#define SET_CONTEXT_FIELD(b, c, r, F, v) \
+	SET_FIELD(((b) + CTX_OFFSET + (r) + ((c) << CTX_SHIFT)), \
+			r##_##F##_MASK, r##_##F##_SHIFT, (v))
+
+/* Wrappers for numbered field registers */
+#define SET_GLOBAL_FIELD_N(b, n, r, F, v) \
+	SET_FIELD(((b) + ((n) << 2) + (r)), r##_##F##_MASK, r##_##F##_SHIFT, v)
+#define GET_GLOBAL_FIELD_N(b, n, r, F) \
+	GET_FIELD(((b) + ((n) << 2) + (r)), r##_##F##_MASK, r##_##F##_SHIFT)
+
+#define GET_FIELD(addr, mask, shift) ((readl_relaxed(addr) >> (shift)) & (mask))
+
+#define SET_FIELD(addr, mask, shift, v) \
+do { \
+	int t = readl_relaxed(addr); \
+	writel_relaxed((t & ~((mask) << (shift))) + (((v) & \
+			(mask)) << (shift)), addr); \
+} while (0)
+
+
+/* Global register space 0 setters / getters */
+#define SET_CR0(b, v)            SET_GLOBAL_REG(CR0, (b), (v))
+#define SET_SCR1(b, v)           SET_GLOBAL_REG(SCR1, (b), (v))
+#define SET_CR2(b, v)            SET_GLOBAL_REG(CR2, (b), (v))
+#define SET_ACR(b, v)            SET_GLOBAL_REG(ACR, (b), (v))
+#define SET_IDR0(b, N, v)        SET_GLOBAL_REG(IDR0, (b), (v))
+#define SET_IDR1(b, N, v)        SET_GLOBAL_REG(IDR1, (b), (v))
+#define SET_IDR2(b, N, v)        SET_GLOBAL_REG(IDR2, (b), (v))
+#define SET_IDR7(b, N, v)        SET_GLOBAL_REG(IDR7, (b), (v))
+#define SET_GFAR(b, v)           SET_GLOBAL_REG(GFAR, (b), (v))
+#define SET_GFSR(b, v)           SET_GLOBAL_REG(GFSR, (b), (v))
+#define SET_GFSRRESTORE(b, v)    SET_GLOBAL_REG(GFSRRESTORE, (b), (v))
+#define SET_GFSYNR0(b, v)        SET_GLOBAL_REG(GFSYNR0, (b), (v))
+#define SET_GFSYNR1(b, v)        SET_GLOBAL_REG(GFSYNR1, (b), (v))
+#define SET_GFSYNR2(b, v)        SET_GLOBAL_REG(GFSYNR2, (b), (v))
+#define SET_TLBIVMID(b, v)       SET_GLOBAL_REG(TLBIVMID, (b), (v))
+#define SET_TLBIALLNSNH(b, v)    SET_GLOBAL_REG(TLBIALLNSNH, (b), (v))
+#define SET_TLBIALLH(b, v)       SET_GLOBAL_REG(TLBIALLH, (b), (v))
+#define SET_TLBGSYNC(b, v)       SET_GLOBAL_REG(TLBGSYNC, (b), (v))
+#define SET_TLBGSTATUS(b, v)     SET_GLOBAL_REG(TLBSTATUS, (b), (v))
+#define SET_TLBIVAH(b, v)        SET_GLOBAL_REG(TLBIVAH, (b), (v))
+#define SET_GATS1UR(b, v)        SET_GLOBAL_REG(GATS1UR, (b), (v))
+#define SET_GATS1UW(b, v)        SET_GLOBAL_REG(GATS1UW, (b), (v))
+#define SET_GATS1PR(b, v)        SET_GLOBAL_REG(GATS1PR, (b), (v))
+#define SET_GATS1PW(b, v)        SET_GLOBAL_REG(GATS1PW, (b), (v))
+#define SET_GATS12UR(b, v)       SET_GLOBAL_REG(GATS12UR, (b), (v))
+#define SET_GATS12UW(b, v)       SET_GLOBAL_REG(GATS12UW, (b), (v))
+#define SET_GATS12PR(b, v)       SET_GLOBAL_REG(GATS12PR, (b), (v))
+#define SET_GATS12PW(b, v)       SET_GLOBAL_REG(GATS12PW, (b), (v))
+#define SET_GPAR(b, v)           SET_GLOBAL_REG(GPAR, (b), (v))
+#define SET_GATSR(b, v)          SET_GLOBAL_REG(GATSR, (b), (v))
+#define SET_NSCR0(b, v)          SET_GLOBAL_REG(NSCR0, (b), (v))
+#define SET_NSCR2(b, v)          SET_GLOBAL_REG(NSCR2, (b), (v))
+#define SET_NSACR(b, v)          SET_GLOBAL_REG(NSACR, (b), (v))
+#define SET_PMCR(b, v)           SET_GLOBAL_REG(PMCR, (b), (v))
+#define SET_SMR_N(b, N, v)       SET_GLOBAL_REG_N(SMR, N, (b), (v))
+#define SET_S2CR_N(b, N, v)      SET_GLOBAL_REG_N(S2CR, N, (b), (v))
+
+#define GET_CR0(b)               GET_GLOBAL_REG(CR0, (b))
+#define GET_SCR1(b)              GET_GLOBAL_REG(SCR1, (b))
+#define GET_CR2(b)               GET_GLOBAL_REG(CR2, (b))
+#define GET_ACR(b)               GET_GLOBAL_REG(ACR, (b))
+#define GET_IDR0(b, N)           GET_GLOBAL_REG(IDR0, (b))
+#define GET_IDR1(b, N)           GET_GLOBAL_REG(IDR1, (b))
+#define GET_IDR2(b, N)           GET_GLOBAL_REG(IDR2, (b))
+#define GET_IDR7(b, N)           GET_GLOBAL_REG(IDR7, (b))
+#define GET_GFAR(b)              GET_GLOBAL_REG(GFAR, (b))
+#define GET_GFSR(b)              GET_GLOBAL_REG(GFSR, (b))
+#define GET_GFSRRESTORE(b)       GET_GLOBAL_REG(GFSRRESTORE, (b))
+#define GET_GFSYNR0(b)           GET_GLOBAL_REG(GFSYNR0, (b))
+#define GET_GFSYNR1(b)           GET_GLOBAL_REG(GFSYNR1, (b))
+#define GET_GFSYNR2(b)           GET_GLOBAL_REG(GFSYNR2, (b))
+#define GET_TLBIVMID(b)          GET_GLOBAL_REG(TLBIVMID, (b))
+#define GET_TLBIALLNSNH(b)       GET_GLOBAL_REG(TLBIALLNSNH, (b))
+#define GET_TLBIALLH(b)          GET_GLOBAL_REG(TLBIALLH, (b))
+#define GET_TLBGSYNC(b)          GET_GLOBAL_REG(TLBGSYNC, (b))
+#define GET_TLBGSTATUS(b)        GET_GLOBAL_REG(TLBSTATUS, (b))
+#define GET_TLBIVAH(b)           GET_GLOBAL_REG(TLBIVAH, (b))
+#define GET_GATS1UR(b)           GET_GLOBAL_REG(GATS1UR, (b))
+#define GET_GATS1UW(b)           GET_GLOBAL_REG(GATS1UW, (b))
+#define GET_GATS1PR(b)           GET_GLOBAL_REG(GATS1PR, (b))
+#define GET_GATS1PW(b)           GET_GLOBAL_REG(GATS1PW, (b))
+#define GET_GATS12UR(b)          GET_GLOBAL_REG(GATS12UR, (b))
+#define GET_GATS12UW(b)          GET_GLOBAL_REG(GATS12UW, (b))
+#define GET_GATS12PR(b)          GET_GLOBAL_REG(GATS12PR, (b))
+#define GET_GATS12PW(b)          GET_GLOBAL_REG(GATS12PW, (b))
+#define GET_GPAR(b)              GET_GLOBAL_REG(GPAR, (b))
+#define GET_GATSR(b)             GET_GLOBAL_REG(GATSR, (b))
+#define GET_NSCR0(b)             GET_GLOBAL_REG(NSCR0, (b))
+#define GET_NSCR2(b)             GET_GLOBAL_REG(NSCR2, (b))
+#define GET_NSACR(b)             GET_GLOBAL_REG(NSACR, (b))
+#define GET_PMCR(b, v)           GET_GLOBAL_REG(PMCR, (b))
+#define GET_SMR_N(b, N)          GET_GLOBAL_REG_N(SMR, N, (b))
+#define GET_S2CR_N(b, N)         GET_GLOBAL_REG_N(S2CR, N, (b))
+
+/* Global register space 1 setters / getters */
+#define SET_CBAR_N(b, N, v)      SET_GLOBAL_REG_N(CBAR, N, (b), (v))
+#define SET_CBFRSYNRA_N(b, N, v) SET_GLOBAL_REG_N(CBFRSYNRA, N, (b), (v))
+
+#define GET_CBAR_N(b, N)         GET_GLOBAL_REG_N(CBAR, N, (b))
+#define GET_CBFRSYNRA_N(b, N)    GET_GLOBAL_REG_N(CBFRSYNRA, N, (b))
+
+/* Implementation defined register setters/getters */
+#define SET_PREDICTIONDIS0(b, v) SET_GLOBAL_REG(PREDICTIONDIS0, (b), (v))
+#define SET_PREDICTIONDIS1(b, v) SET_GLOBAL_REG(PREDICTIONDIS1, (b), (v))
+#define SET_S1L1BFBLP0(b, v)     SET_GLOBAL_REG(S1L1BFBLP0, (b), (v))
+
+/* SSD register setters/getters */
+#define SET_SSDR_N(b, N, v)      SET_GLOBAL_REG_N(SSDR_N, N, (b), (v))
+
+#define GET_SSDR_N(b, N)         GET_GLOBAL_REG_N(SSDR_N, N, (b))
+
+/* Context bank register setters/getters */
+#define SET_SCTLR(b, c, v)       SET_CTX_REG(CB_SCTLR, (b), (c), (v))
+#define SET_ACTLR(b, c, v)       SET_CTX_REG(CB_ACTLR, (b), (c), (v))
+#define SET_RESUME(b, c, v)      SET_CTX_REG(CB_RESUME, (b), (c), (v))
+#define SET_TTBR0(b, c, v)       SET_CTX_REG(CB_TTBR0, (b), (c), (v))
+#define SET_TTBR1(b, c, v)       SET_CTX_REG(CB_TTBR1, (b), (c), (v))
+#define SET_TTBCR(b, c, v)       SET_CTX_REG(CB_TTBCR, (b), (c), (v))
+#define SET_CONTEXTIDR(b, c, v)  SET_CTX_REG(CB_CONTEXTIDR, (b), (c), (v))
+#define SET_PRRR(b, c, v)        SET_CTX_REG(CB_PRRR, (b), (c), (v))
+#define SET_NMRR(b, c, v)        SET_CTX_REG(CB_NMRR, (b), (c), (v))
+#define SET_PAR(b, c, v)         SET_CTX_REG(CB_PAR, (b), (c), (v))
+#define SET_FSR(b, c, v)         SET_CTX_REG(CB_FSR, (b), (c), (v))
+#define SET_FSRRESTORE(b, c, v)  SET_CTX_REG(CB_FSRRESTORE, (b), (c), (v))
+#define SET_FAR(b, c, v)         SET_CTX_REG(CB_FAR, (b), (c), (v))
+#define SET_FSYNR0(b, c, v)      SET_CTX_REG(CB_FSYNR0, (b), (c), (v))
+#define SET_FSYNR1(b, c, v)      SET_CTX_REG(CB_FSYNR1, (b), (c), (v))
+#define SET_TLBIVA(b, c, v)      SET_CTX_REG(CB_TLBIVA, (b), (c), (v))
+#define SET_TLBIVAA(b, c, v)     SET_CTX_REG(CB_TLBIVAA, (b), (c), (v))
+#define SET_TLBIASID(b, c, v)    SET_CTX_REG(CB_TLBIASID, (b), (c), (v))
+#define SET_TLBIALL(b, c, v)     SET_CTX_REG(CB_TLBIALL, (b), (c), (v))
+#define SET_TLBIVAL(b, c, v)     SET_CTX_REG(CB_TLBIVAL, (b), (c), (v))
+#define SET_TLBIVAAL(b, c, v)    SET_CTX_REG(CB_TLBIVAAL, (b), (c), (v))
+#define SET_TLBSYNC(b, c, v)     SET_CTX_REG(CB_TLBSYNC, (b), (c), (v))
+#define SET_TLBSTATUS(b, c, v)   SET_CTX_REG(CB_TLBSTATUS, (b), (c), (v))
+#define SET_ATS1PR(b, c, v)      SET_CTX_REG(CB_ATS1PR, (b), (c), (v))
+#define SET_ATS1PW(b, c, v)      SET_CTX_REG(CB_ATS1PW, (b), (c), (v))
+#define SET_ATS1UR(b, c, v)      SET_CTX_REG(CB_ATS1UR, (b), (c), (v))
+#define SET_ATS1UW(b, c, v)      SET_CTX_REG(CB_ATS1UW, (b), (c), (v))
+#define SET_ATSR(b, c, v)        SET_CTX_REG(CB_ATSR, (b), (c), (v))
+
+#define GET_SCTLR(b, c)          GET_CTX_REG(CB_SCTLR, (b), (c))
+#define GET_ACTLR(b, c)          GET_CTX_REG(CB_ACTLR, (b), (c))
+#define GET_RESUME(b, c)         GET_CTX_REG(CB_RESUME, (b), (c))
+#define GET_TTBR0(b, c)          GET_CTX_REG(CB_TTBR0, (b), (c))
+#define GET_TTBR1(b, c)          GET_CTX_REG(CB_TTBR1, (b), (c))
+#define GET_TTBCR(b, c)          GET_CTX_REG(CB_TTBCR, (b), (c))
+#define GET_CONTEXTIDR(b, c)     GET_CTX_REG(CB_CONTEXTIDR, (b), (c))
+#define GET_PRRR(b, c)           GET_CTX_REG(CB_PRRR, (b), (c))
+#define GET_NMRR(b, c)           GET_CTX_REG(CB_NMRR, (b), (c))
+#define GET_PAR(b, c)            GET_CTX_REG(CB_PAR, (b), (c))
+#define GET_FSR(b, c)            GET_CTX_REG(CB_FSR, (b), (c))
+#define GET_FSRRESTORE(b, c)     GET_CTX_REG(CB_FSRRESTORE, (b), (c))
+#define GET_FAR(b, c)            GET_CTX_REG(CB_FAR, (b), (c))
+#define GET_FSYNR0(b, c)         GET_CTX_REG(CB_FSYNR0, (b), (c))
+#define GET_FSYNR1(b, c)         GET_CTX_REG(CB_FSYNR1, (b), (c))
+#define GET_TLBIVA(b, c)         GET_CTX_REG(CB_TLBIVA, (b), (c))
+#define GET_TLBIVAA(b, c)        GET_CTX_REG(CB_TLBIVAA, (b), (c))
+#define GET_TLBIASID(b, c)       GET_CTX_REG(CB_TLBIASID, (b), (c))
+#define GET_TLBIALL(b, c)        GET_CTX_REG(CB_TLBIALL, (b), (c))
+#define GET_TLBIVAL(b, c)        GET_CTX_REG(CB_TLBIVAL, (b), (c))
+#define GET_TLBIVAAL(b, c)       GET_CTX_REG(CB_TLBIVAAL, (b), (c))
+#define GET_TLBSYNC(b, c)        GET_CTX_REG(CB_TLBSYNC, (b), (c))
+#define GET_TLBSTATUS(b, c)      GET_CTX_REG(CB_TLBSTATUS, (b), (c))
+#define GET_ATS1PR(b, c)         GET_CTX_REG(CB_ATS1PR, (b), (c))
+#define GET_ATS1PW(b, c)         GET_CTX_REG(CB_ATS1PW, (b), (c))
+#define GET_ATS1UR(b, c)         GET_CTX_REG(CB_ATS1UR, (b), (c))
+#define GET_ATS1UW(b, c)         GET_CTX_REG(CB_ATS1UW, (b), (c))
+#define GET_ATSR(b, c)           GET_CTX_REG(CB_ATSR, (b), (c))
+
+/* Global Register field setters / getters */
+/* Configuration Register: CR0 */
+#define SET_CR0_NSCFG(b, v)        SET_GLOBAL_FIELD(b, CR0, NSCFG, v)
+#define SET_CR0_WACFG(b, v)        SET_GLOBAL_FIELD(b, CR0, WACFG, v)
+#define SET_CR0_RACFG(b, v)        SET_GLOBAL_FIELD(b, CR0, RACFG, v)
+#define SET_CR0_SHCFG(b, v)        SET_GLOBAL_FIELD(b, CR0, SHCFG, v)
+#define SET_CR0_SMCFCFG(b, v)      SET_GLOBAL_FIELD(b, CR0, SMCFCFG, v)
+#define SET_CR0_MTCFG(b, v)        SET_GLOBAL_FIELD(b, CR0, MTCFG, v)
+#define SET_CR0_BSU(b, v)          SET_GLOBAL_FIELD(b, CR0, BSU, v)
+#define SET_CR0_FB(b, v)           SET_GLOBAL_FIELD(b, CR0, FB, v)
+#define SET_CR0_PTM(b, v)          SET_GLOBAL_FIELD(b, CR0, PTM, v)
+#define SET_CR0_VMIDPNE(b, v)      SET_GLOBAL_FIELD(b, CR0, VMIDPNE, v)
+#define SET_CR0_USFCFG(b, v)       SET_GLOBAL_FIELD(b, CR0, USFCFG, v)
+#define SET_CR0_GSE(b, v)          SET_GLOBAL_FIELD(b, CR0, GSE, v)
+#define SET_CR0_STALLD(b, v)       SET_GLOBAL_FIELD(b, CR0, STALLD, v)
+#define SET_CR0_TRANSIENTCFG(b, v) SET_GLOBAL_FIELD(b, CR0, TRANSIENTCFG, v)
+#define SET_CR0_GCFGFIE(b, v)      SET_GLOBAL_FIELD(b, CR0, GCFGFIE, v)
+#define SET_CR0_GCFGFRE(b, v)      SET_GLOBAL_FIELD(b, CR0, GCFGFRE, v)
+#define SET_CR0_GFIE(b, v)         SET_GLOBAL_FIELD(b, CR0, GFIE, v)
+#define SET_CR0_GFRE(b, v)         SET_GLOBAL_FIELD(b, CR0, GFRE, v)
+#define SET_CR0_CLIENTPD(b, v)     SET_GLOBAL_FIELD(b, CR0, CLIENTPD, v)
+
+#define GET_CR0_NSCFG(b)           GET_GLOBAL_FIELD(b, CR0, NSCFG)
+#define GET_CR0_WACFG(b)           GET_GLOBAL_FIELD(b, CR0, WACFG)
+#define GET_CR0_RACFG(b)           GET_GLOBAL_FIELD(b, CR0, RACFG)
+#define GET_CR0_SHCFG(b)           GET_GLOBAL_FIELD(b, CR0, SHCFG)
+#define GET_CR0_SMCFCFG(b)         GET_GLOBAL_FIELD(b, CR0, SMCFCFG)
+#define GET_CR0_MTCFG(b)           GET_GLOBAL_FIELD(b, CR0, MTCFG)
+#define GET_CR0_BSU(b)             GET_GLOBAL_FIELD(b, CR0, BSU)
+#define GET_CR0_FB(b)              GET_GLOBAL_FIELD(b, CR0, FB)
+#define GET_CR0_PTM(b)             GET_GLOBAL_FIELD(b, CR0, PTM)
+#define GET_CR0_VMIDPNE(b)         GET_GLOBAL_FIELD(b, CR0, VMIDPNE)
+#define GET_CR0_USFCFG(b)          GET_GLOBAL_FIELD(b, CR0, USFCFG)
+#define GET_CR0_GSE(b)             GET_GLOBAL_FIELD(b, CR0, GSE)
+#define GET_CR0_STALLD(b)          GET_GLOBAL_FIELD(b, CR0, STALLD)
+#define GET_CR0_TRANSIENTCFG(b)    GET_GLOBAL_FIELD(b, CR0, TRANSIENTCFG)
+#define GET_CR0_GCFGFIE(b)         GET_GLOBAL_FIELD(b, CR0, GCFGFIE)
+#define GET_CR0_GCFGFRE(b)         GET_GLOBAL_FIELD(b, CR0, GCFGFRE)
+#define GET_CR0_GFIE(b)            GET_GLOBAL_FIELD(b, CR0, GFIE)
+#define GET_CR0_GFRE(b)            GET_GLOBAL_FIELD(b, CR0, GFRE)
+#define GET_CR0_CLIENTPD(b)        GET_GLOBAL_FIELD(b, CR0, CLIENTPD)
+
+/* Configuration Register: CR2 */
+#define SET_CR2_BPVMID(b, v)     SET_GLOBAL_FIELD(b, CR2, BPVMID, v)
+
+#define GET_CR2_BPVMID(b)        GET_GLOBAL_FIELD(b, CR2, BPVMID)
+
+/* Global Address Translation, Stage 1, Privileged Read: GATS1PR */
+#define SET_GATS1PR_ADDR(b, v)   SET_GLOBAL_FIELD(b, GATS1PR, ADDR, v)
+#define SET_GATS1PR_NDX(b, v)    SET_GLOBAL_FIELD(b, GATS1PR, NDX, v)
+
+#define GET_GATS1PR_ADDR(b)      GET_GLOBAL_FIELD(b, GATS1PR, ADDR)
+#define GET_GATS1PR_NDX(b)       GET_GLOBAL_FIELD(b, GATS1PR, NDX)
+
+/* Global Address Translation, Stage 1, Privileged Write: GATS1PW */
+#define SET_GATS1PW_ADDR(b, v)   SET_GLOBAL_FIELD(b, GATS1PW, ADDR, v)
+#define SET_GATS1PW_NDX(b, v)    SET_GLOBAL_FIELD(b, GATS1PW, NDX, v)
+
+#define GET_GATS1PW_ADDR(b)      GET_GLOBAL_FIELD(b, GATS1PW, ADDR)
+#define GET_GATS1PW_NDX(b)       GET_GLOBAL_FIELD(b, GATS1PW, NDX)
+
+/* Global Address Translation, Stage 1, User Read: GATS1UR */
+#define SET_GATS1UR_ADDR(b, v)   SET_GLOBAL_FIELD(b, GATS1UR, ADDR, v)
+#define SET_GATS1UR_NDX(b, v)    SET_GLOBAL_FIELD(b, GATS1UR, NDX, v)
+
+#define GET_GATS1UR_ADDR(b)      GET_GLOBAL_FIELD(b, GATS1UR, ADDR)
+#define GET_GATS1UR_NDX(b)       GET_GLOBAL_FIELD(b, GATS1UR, NDX)
+
+/* Global Address Translation, Stage 1, User Read: GATS1UW */
+#define SET_GATS1UW_ADDR(b, v)   SET_GLOBAL_FIELD(b, GATS1UW, ADDR, v)
+#define SET_GATS1UW_NDX(b, v)    SET_GLOBAL_FIELD(b, GATS1UW, NDX, v)
+
+#define GET_GATS1UW_ADDR(b)      GET_GLOBAL_FIELD(b, GATS1UW, ADDR)
+#define GET_GATS1UW_NDX(b)       GET_GLOBAL_FIELD(b, GATS1UW, NDX)
+
+/* Global Address Translation, Stage 1 and 2, Privileged Read: GATS12PR */
+#define SET_GATS12PR_ADDR(b, v)  SET_GLOBAL_FIELD(b, GATS12PR, ADDR, v)
+#define SET_GATS12PR_NDX(b, v)   SET_GLOBAL_FIELD(b, GATS12PR, NDX, v)
+
+#define GET_GATS12PR_ADDR(b)     GET_GLOBAL_FIELD(b, GATS12PR, ADDR)
+#define GET_GATS12PR_NDX(b)      GET_GLOBAL_FIELD(b, GATS12PR, NDX)
+
+/* Global Address Translation, Stage 1, Privileged Write: GATS1PW */
+#define SET_GATS12PW_ADDR(b, v)  SET_GLOBAL_FIELD(b, GATS12PW, ADDR, v)
+#define SET_GATS12PW_NDX(b, v)   SET_GLOBAL_FIELD(b, GATS12PW, NDX, v)
+
+#define GET_GATS12PW_ADDR(b)     GET_GLOBAL_FIELD(b, GATS12PW, ADDR)
+#define GET_GATS12PW_NDX(b)      GET_GLOBAL_FIELD(b, GATS12PW, NDX)
+
+/* Global Address Translation, Stage 1, User Read: GATS1UR */
+#define SET_GATS12UR_ADDR(b, v)  SET_GLOBAL_FIELD(b, GATS12UR, ADDR, v)
+#define SET_GATS12UR_NDX(b, v)   SET_GLOBAL_FIELD(b, GATS12UR, NDX, v)
+
+#define GET_GATS12UR_ADDR(b)     GET_GLOBAL_FIELD(b, GATS12UR, ADDR)
+#define GET_GATS12UR_NDX(b)      GET_GLOBAL_FIELD(b, GATS12UR, NDX)
+
+/* Global Address Translation, Stage 1, User Read: GATS1UW */
+#define SET_GATS12UW_ADDR(b, v)  SET_GLOBAL_FIELD(b, GATS12UW, ADDR, v)
+#define SET_GATS12UW_NDX(b, v)   SET_GLOBAL_FIELD(b, GATS12UW, NDX, v)
+
+#define GET_GATS12UW_ADDR(b)     GET_GLOBAL_FIELD(b, GATS12UW, ADDR)
+#define GET_GATS12UW_NDX(b)      GET_GLOBAL_FIELD(b, GATS12UW, NDX)
+
+/* Global Address Translation Status Register: GATSR */
+#define SET_GATSR_ACTIVE(b, v)   SET_GLOBAL_FIELD(b, GATSR, ACTIVE, v)
+
+#define GET_GATSR_ACTIVE(b)      GET_GLOBAL_FIELD(b, GATSR, ACTIVE)
+
+/* Global Fault Address Register: GFAR */
+#define SET_GFAR_FADDR(b, v)     SET_GLOBAL_FIELD(b, GFAR, FADDR, v)
+
+#define GET_GFAR_FADDR(b)        GET_GLOBAL_FIELD(b, GFAR, FADDR)
+
+/* Global Fault Status Register: GFSR */
+#define SET_GFSR_ICF(b, v)        SET_GLOBAL_FIELD(b, GFSR, ICF, v)
+#define SET_GFSR_USF(b, v)        SET_GLOBAL_FIELD(b, GFSR, USF, v)
+#define SET_GFSR_SMCF(b, v)       SET_GLOBAL_FIELD(b, GFSR, SMCF, v)
+#define SET_GFSR_UCBF(b, v)       SET_GLOBAL_FIELD(b, GFSR, UCBF, v)
+#define SET_GFSR_UCIF(b, v)       SET_GLOBAL_FIELD(b, GFSR, UCIF, v)
+#define SET_GFSR_CAF(b, v)        SET_GLOBAL_FIELD(b, GFSR, CAF, v)
+#define SET_GFSR_EF(b, v)         SET_GLOBAL_FIELD(b, GFSR, EF, v)
+#define SET_GFSR_PF(b, v)         SET_GLOBAL_FIELD(b, GFSR, PF, v)
+#define SET_GFSR_MULTI(b, v)      SET_GLOBAL_FIELD(b, GFSR, MULTI, v)
+
+#define GET_GFSR_ICF(b)           GET_GLOBAL_FIELD(b, GFSR, ICF)
+#define GET_GFSR_USF(b)           GET_GLOBAL_FIELD(b, GFSR, USF)
+#define GET_GFSR_SMCF(b)          GET_GLOBAL_FIELD(b, GFSR, SMCF)
+#define GET_GFSR_UCBF(b)          GET_GLOBAL_FIELD(b, GFSR, UCBF)
+#define GET_GFSR_UCIF(b)          GET_GLOBAL_FIELD(b, GFSR, UCIF)
+#define GET_GFSR_CAF(b)           GET_GLOBAL_FIELD(b, GFSR, CAF)
+#define GET_GFSR_EF(b)            GET_GLOBAL_FIELD(b, GFSR, EF)
+#define GET_GFSR_PF(b)            GET_GLOBAL_FIELD(b, GFSR, PF)
+#define GET_GFSR_MULTI(b)         GET_GLOBAL_FIELD(b, GFSR, MULTI)
+
+/* Global Fault Syndrome Register 0: GFSYNR0 */
+#define SET_GFSYNR0_NESTED(b, v)  SET_GLOBAL_FIELD(b, GFSYNR0, NESTED, v)
+#define SET_GFSYNR0_WNR(b, v)     SET_GLOBAL_FIELD(b, GFSYNR0, WNR, v)
+#define SET_GFSYNR0_PNU(b, v)     SET_GLOBAL_FIELD(b, GFSYNR0, PNU, v)
+#define SET_GFSYNR0_IND(b, v)     SET_GLOBAL_FIELD(b, GFSYNR0, IND, v)
+#define SET_GFSYNR0_NSSTATE(b, v) SET_GLOBAL_FIELD(b, GFSYNR0, NSSTATE, v)
+#define SET_GFSYNR0_NSATTR(b, v)  SET_GLOBAL_FIELD(b, GFSYNR0, NSATTR, v)
+
+#define GET_GFSYNR0_NESTED(b)     GET_GLOBAL_FIELD(b, GFSYNR0, NESTED)
+#define GET_GFSYNR0_WNR(b)        GET_GLOBAL_FIELD(b, GFSYNR0, WNR)
+#define GET_GFSYNR0_PNU(b)        GET_GLOBAL_FIELD(b, GFSYNR0, PNU)
+#define GET_GFSYNR0_IND(b)        GET_GLOBAL_FIELD(b, GFSYNR0, IND)
+#define GET_GFSYNR0_NSSTATE(b)    GET_GLOBAL_FIELD(b, GFSYNR0, NSSTATE)
+#define GET_GFSYNR0_NSATTR(b)     GET_GLOBAL_FIELD(b, GFSYNR0, NSATTR)
+
+/* Global Fault Syndrome Register 1: GFSYNR1 */
+#define SET_GFSYNR1_SID(b, v)     SET_GLOBAL_FIELD(b, GFSYNR1, SID, v)
+
+#define GET_GFSYNR1_SID(b)        GET_GLOBAL_FIELD(b, GFSYNR1, SID)
+
+/* Global Physical Address Register: GPAR */
+#define SET_GPAR_F(b, v)          SET_GLOBAL_FIELD(b, GPAR, F, v)
+#define SET_GPAR_SS(b, v)         SET_GLOBAL_FIELD(b, GPAR, SS, v)
+#define SET_GPAR_OUTER(b, v)      SET_GLOBAL_FIELD(b, GPAR, OUTER, v)
+#define SET_GPAR_INNER(b, v)      SET_GLOBAL_FIELD(b, GPAR, INNER, v)
+#define SET_GPAR_SH(b, v)         SET_GLOBAL_FIELD(b, GPAR, SH, v)
+#define SET_GPAR_NS(b, v)         SET_GLOBAL_FIELD(b, GPAR, NS, v)
+#define SET_GPAR_NOS(b, v)        SET_GLOBAL_FIELD(b, GPAR, NOS, v)
+#define SET_GPAR_PA(b, v)         SET_GLOBAL_FIELD(b, GPAR, PA, v)
+#define SET_GPAR_TF(b, v)         SET_GLOBAL_FIELD(b, GPAR, TF, v)
+#define SET_GPAR_AFF(b, v)        SET_GLOBAL_FIELD(b, GPAR, AFF, v)
+#define SET_GPAR_PF(b, v)         SET_GLOBAL_FIELD(b, GPAR, PF, v)
+#define SET_GPAR_EF(b, v)         SET_GLOBAL_FIELD(b, GPAR, EF, v)
+#define SET_GPAR_TLCMCF(b, v)     SET_GLOBAL_FIELD(b, GPAR, TLCMCF, v)
+#define SET_GPAR_TLBLKF(b, v)     SET_GLOBAL_FIELD(b, GPAR, TLBLKF, v)
+#define SET_GPAR_UCBF(b, v)       SET_GLOBAL_FIELD(b, GPAR, UCBF, v)
+
+#define GET_GPAR_F(b)             GET_GLOBAL_FIELD(b, GPAR, F)
+#define GET_GPAR_SS(b)            GET_GLOBAL_FIELD(b, GPAR, SS)
+#define GET_GPAR_OUTER(b)         GET_GLOBAL_FIELD(b, GPAR, OUTER)
+#define GET_GPAR_INNER(b)         GET_GLOBAL_FIELD(b, GPAR, INNER)
+#define GET_GPAR_SH(b)            GET_GLOBAL_FIELD(b, GPAR, SH)
+#define GET_GPAR_NS(b)            GET_GLOBAL_FIELD(b, GPAR, NS)
+#define GET_GPAR_NOS(b)           GET_GLOBAL_FIELD(b, GPAR, NOS)
+#define GET_GPAR_PA(b)            GET_GLOBAL_FIELD(b, GPAR, PA)
+#define GET_GPAR_TF(b)            GET_GLOBAL_FIELD(b, GPAR, TF)
+#define GET_GPAR_AFF(b)           GET_GLOBAL_FIELD(b, GPAR, AFF)
+#define GET_GPAR_PF(b)            GET_GLOBAL_FIELD(b, GPAR, PF)
+#define GET_GPAR_EF(b)            GET_GLOBAL_FIELD(b, GPAR, EF)
+#define GET_GPAR_TLCMCF(b)        GET_GLOBAL_FIELD(b, GPAR, TLCMCF)
+#define GET_GPAR_TLBLKF(b)        GET_GLOBAL_FIELD(b, GPAR, TLBLKF)
+#define GET_GPAR_UCBF(b)          GET_GLOBAL_FIELD(b, GPAR, UCBF)
+
+/* Identification Register: IDR0 */
+#define SET_IDR0_NUMSMRG(b, v)    SET_GLOBAL_FIELD(b, IDR0, NUMSMRG, v)
+#define SET_IDR0_NUMSIDB(b, v)    SET_GLOBAL_FIELD(b, IDR0, NUMSIDB, v)
+#define SET_IDR0_BTM(b, v)        SET_GLOBAL_FIELD(b, IDR0, BTM, v)
+#define SET_IDR0_CTTW(b, v)       SET_GLOBAL_FIELD(b, IDR0, CTTW, v)
+#define SET_IDR0_NUMIRPT(b, v)    SET_GLOBAL_FIELD(b, IDR0, NUMIRPT, v)
+#define SET_IDR0_PTFS(b, v)       SET_GLOBAL_FIELD(b, IDR0, PTFS, v)
+#define SET_IDR0_SMS(b, v)        SET_GLOBAL_FIELD(b, IDR0, SMS, v)
+#define SET_IDR0_NTS(b, v)        SET_GLOBAL_FIELD(b, IDR0, NTS, v)
+#define SET_IDR0_S2TS(b, v)       SET_GLOBAL_FIELD(b, IDR0, S2TS, v)
+#define SET_IDR0_S1TS(b, v)       SET_GLOBAL_FIELD(b, IDR0, S1TS, v)
+#define SET_IDR0_SES(b, v)        SET_GLOBAL_FIELD(b, IDR0, SES, v)
+
+#define GET_IDR0_NUMSMRG(b)       GET_GLOBAL_FIELD(b, IDR0, NUMSMRG)
+#define GET_IDR0_NUMSIDB(b)       GET_GLOBAL_FIELD(b, IDR0, NUMSIDB)
+#define GET_IDR0_BTM(b)           GET_GLOBAL_FIELD(b, IDR0, BTM)
+#define GET_IDR0_CTTW(b)          GET_GLOBAL_FIELD(b, IDR0, CTTW)
+#define GET_IDR0_NUMIRPT(b)       GET_GLOBAL_FIELD(b, IDR0, NUMIRPT)
+#define GET_IDR0_PTFS(b)          GET_GLOBAL_FIELD(b, IDR0, PTFS)
+#define GET_IDR0_SMS(b)           GET_GLOBAL_FIELD(b, IDR0, SMS)
+#define GET_IDR0_NTS(b)           GET_GLOBAL_FIELD(b, IDR0, NTS)
+#define GET_IDR0_S2TS(b)          GET_GLOBAL_FIELD(b, IDR0, S2TS)
+#define GET_IDR0_S1TS(b)          GET_GLOBAL_FIELD(b, IDR0, S1TS)
+#define GET_IDR0_SES(b)           GET_GLOBAL_FIELD(b, IDR0, SES)
+
+/* Identification Register: IDR1 */
+#define SET_IDR1_NUMCB(b, v)       SET_GLOBAL_FIELD(b, IDR1, NUMCB, v)
+#define SET_IDR1_NUMSSDNDXB(b, v)  SET_GLOBAL_FIELD(b, IDR1, NUMSSDNDXB, v)
+#define SET_IDR1_SSDTP(b, v)       SET_GLOBAL_FIELD(b, IDR1, SSDTP, v)
+#define SET_IDR1_SMCD(b, v)        SET_GLOBAL_FIELD(b, IDR1, SMCD, v)
+#define SET_IDR1_NUMS2CB(b, v)     SET_GLOBAL_FIELD(b, IDR1, NUMS2CB, v)
+#define SET_IDR1_NUMPAGENDXB(b, v) SET_GLOBAL_FIELD(b, IDR1, NUMPAGENDXB, v)
+#define SET_IDR1_PAGESIZE(b, v)    SET_GLOBAL_FIELD(b, IDR1, PAGESIZE, v)
+
+#define GET_IDR1_NUMCB(b)          GET_GLOBAL_FIELD(b, IDR1, NUMCB)
+#define GET_IDR1_NUMSSDNDXB(b)     GET_GLOBAL_FIELD(b, IDR1, NUMSSDNDXB)
+#define GET_IDR1_SSDTP(b)          GET_GLOBAL_FIELD(b, IDR1, SSDTP)
+#define GET_IDR1_SMCD(b)           GET_GLOBAL_FIELD(b, IDR1, SMCD)
+#define GET_IDR1_NUMS2CB(b)        GET_GLOBAL_FIELD(b, IDR1, NUMS2CB)
+#define GET_IDR1_NUMPAGENDXB(b)    GET_GLOBAL_FIELD(b, IDR1, NUMPAGENDXB)
+#define GET_IDR1_PAGESIZE(b)       GET_GLOBAL_FIELD(b, IDR1, PAGESIZE)
+
+/* Identification Register: IDR2 */
+#define SET_IDR2_IAS(b, v)       SET_GLOBAL_FIELD(b, IDR2, IAS, v)
+#define SET_IDR2_OAS(b, v)       SET_GLOBAL_FIELD(b, IDR2, OAS, v)
+
+#define GET_IDR2_IAS(b)          GET_GLOBAL_FIELD(b, IDR2, IAS)
+#define GET_IDR2_OAS(b)          GET_GLOBAL_FIELD(b, IDR2, OAS)
+
+/* Identification Register: IDR7 */
+#define SET_IDR7_MINOR(b, v)     SET_GLOBAL_FIELD(b, IDR7, MINOR, v)
+#define SET_IDR7_MAJOR(b, v)     SET_GLOBAL_FIELD(b, IDR7, MAJOR, v)
+
+#define GET_IDR7_MINOR(b)        GET_GLOBAL_FIELD(b, IDR7, MINOR)
+#define GET_IDR7_MAJOR(b)        GET_GLOBAL_FIELD(b, IDR7, MAJOR)
+
+/* Stream to Context Register: S2CR_N */
+#define SET_S2CR_CBNDX(b, n, v)   SET_GLOBAL_FIELD_N(b, n, S2CR, CBNDX, v)
+#define SET_S2CR_SHCFG(b, n, v)   SET_GLOBAL_FIELD_N(b, n, S2CR, SHCFG, v)
+#define SET_S2CR_MTCFG(b, n, v)   SET_GLOBAL_FIELD_N(b, n, S2CR, MTCFG, v)
+#define SET_S2CR_MEMATTR(b, n, v) SET_GLOBAL_FIELD_N(b, n, S2CR, MEMATTR, v)
+#define SET_S2CR_TYPE(b, n, v)    SET_GLOBAL_FIELD_N(b, n, S2CR, TYPE, v)
+#define SET_S2CR_NSCFG(b, n, v)   SET_GLOBAL_FIELD_N(b, n, S2CR, NSCFG, v)
+#define SET_S2CR_RACFG(b, n, v)   SET_GLOBAL_FIELD_N(b, n, S2CR, RACFG, v)
+#define SET_S2CR_WACFG(b, n, v)   SET_GLOBAL_FIELD_N(b, n, S2CR, WACFG, v)
+#define SET_S2CR_PRIVCFG(b, n, v) SET_GLOBAL_FIELD_N(b, n, S2CR, PRIVCFG, v)
+#define SET_S2CR_INSTCFG(b, n, v) SET_GLOBAL_FIELD_N(b, n, S2CR, INSTCFG, v)
+#define SET_S2CR_TRANSIENTCFG(b, n, v) \
+				SET_GLOBAL_FIELD_N(b, n, S2CR, TRANSIENTCFG, v)
+#define SET_S2CR_VMID(b, n, v)    SET_GLOBAL_FIELD_N(b, n, S2CR, VMID, v)
+#define SET_S2CR_BSU(b, n, v)     SET_GLOBAL_FIELD_N(b, n, S2CR, BSU, v)
+#define SET_S2CR_FB(b, n, v)      SET_GLOBAL_FIELD_N(b, n, S2CR, FB, v)
+
+#define GET_S2CR_CBNDX(b, n)      GET_GLOBAL_FIELD_N(b, n, S2CR, CBNDX)
+#define GET_S2CR_SHCFG(b, n)      GET_GLOBAL_FIELD_N(b, n, S2CR, SHCFG)
+#define GET_S2CR_MTCFG(b, n)      GET_GLOBAL_FIELD_N(b, n, S2CR, MTCFG)
+#define GET_S2CR_MEMATTR(b, n)    GET_GLOBAL_FIELD_N(b, n, S2CR, MEMATTR)
+#define GET_S2CR_TYPE(b, n)       GET_GLOBAL_FIELD_N(b, n, S2CR, TYPE)
+#define GET_S2CR_NSCFG(b, n)      GET_GLOBAL_FIELD_N(b, n, S2CR, NSCFG)
+#define GET_S2CR_RACFG(b, n)      GET_GLOBAL_FIELD_N(b, n, S2CR, RACFG)
+#define GET_S2CR_WACFG(b, n)      GET_GLOBAL_FIELD_N(b, n, S2CR, WACFG)
+#define GET_S2CR_PRIVCFG(b, n)    GET_GLOBAL_FIELD_N(b, n, S2CR, PRIVCFG)
+#define GET_S2CR_INSTCFG(b, n)    GET_GLOBAL_FIELD_N(b, n, S2CR, INSTCFG)
+#define GET_S2CR_TRANSIENTCFG(b, n) \
+				GET_GLOBAL_FIELD_N(b, n, S2CR, TRANSIENTCFG)
+#define GET_S2CR_VMID(b, n)       GET_GLOBAL_FIELD_N(b, n, S2CR, VMID)
+#define GET_S2CR_BSU(b, n)        GET_GLOBAL_FIELD_N(b, n, S2CR, BSU)
+#define GET_S2CR_FB(b, n)         GET_GLOBAL_FIELD_N(b, n, S2CR, FB)
+
+/* Stream Match Register: SMR_N */
+#define SET_SMR_ID(b, n, v)       SET_GLOBAL_FIELD_N(b, n, SMR, ID, v)
+#define SET_SMR_MASK(b, n, v)     SET_GLOBAL_FIELD_N(b, n, SMR, MASK, v)
+#define SET_SMR_VALID(b, n, v)    SET_GLOBAL_FIELD_N(b, n, SMR, VALID, v)
+
+#define GET_SMR_ID(b, n)          GET_GLOBAL_FIELD_N(b, n, SMR, ID)
+#define GET_SMR_MASK(b, n)        GET_GLOBAL_FIELD_N(b, n, SMR, MASK)
+#define GET_SMR_VALID(b, n)       GET_GLOBAL_FIELD_N(b, n, SMR, VALID)
+
+/* Global TLB Status: TLBGSTATUS */
+#define SET_TLBGSTATUS_GSACTIVE(b, v) \
+				SET_GLOBAL_FIELD(b, TLBGSTATUS, GSACTIVE, v)
+
+#define GET_TLBGSTATUS_GSACTIVE(b)    \
+				GET_GLOBAL_FIELD(b, TLBGSTATUS, GSACTIVE)
+
+/* Invalidate Hyp TLB by VA: TLBIVAH */
+#define SET_TLBIVAH_ADDR(b, v)  SET_GLOBAL_FIELD(b, TLBIVAH, ADDR, v)
+
+#define GET_TLBIVAH_ADDR(b)     GET_GLOBAL_FIELD(b, TLBIVAH, ADDR)
+
+/* Invalidate TLB by VMID: TLBIVMID */
+#define SET_TLBIVMID_VMID(b, v) SET_GLOBAL_FIELD(b, TLBIVMID, VMID, v)
+
+#define GET_TLBIVMID_VMID(b)    GET_GLOBAL_FIELD(b, TLBIVMID, VMID)
+
+/* Global Register Space 1 Field setters/getters*/
+/* Context Bank Attribute Register: CBAR_N */
+#define SET_CBAR_VMID(b, n, v)     SET_GLOBAL_FIELD_N(b, n, CBAR, VMID, v)
+#define SET_CBAR_CBNDX(b, n, v)    SET_GLOBAL_FIELD_N(b, n, CBAR, CBNDX, v)
+#define SET_CBAR_BPSHCFG(b, n, v)  SET_GLOBAL_FIELD_N(b, n, CBAR, BPSHCFG, v)
+#define SET_CBAR_HYPC(b, n, v)     SET_GLOBAL_FIELD_N(b, n, CBAR, HYPC, v)
+#define SET_CBAR_FB(b, n, v)       SET_GLOBAL_FIELD_N(b, n, CBAR, FB, v)
+#define SET_CBAR_MEMATTR(b, n, v)  SET_GLOBAL_FIELD_N(b, n, CBAR, MEMATTR, v)
+#define SET_CBAR_TYPE(b, n, v)     SET_GLOBAL_FIELD_N(b, n, CBAR, TYPE, v)
+#define SET_CBAR_BSU(b, n, v)      SET_GLOBAL_FIELD_N(b, n, CBAR, BSU, v)
+#define SET_CBAR_RACFG(b, n, v)    SET_GLOBAL_FIELD_N(b, n, CBAR, RACFG, v)
+#define SET_CBAR_WACFG(b, n, v)    SET_GLOBAL_FIELD_N(b, n, CBAR, WACFG, v)
+#define SET_CBAR_IRPTNDX(b, n, v)  SET_GLOBAL_FIELD_N(b, n, CBAR, IRPTNDX, v)
+
+#define GET_CBAR_VMID(b, n)        GET_GLOBAL_FIELD_N(b, n, CBAR, VMID)
+#define GET_CBAR_CBNDX(b, n)       GET_GLOBAL_FIELD_N(b, n, CBAR, CBNDX)
+#define GET_CBAR_BPSHCFG(b, n)     GET_GLOBAL_FIELD_N(b, n, CBAR, BPSHCFG)
+#define GET_CBAR_HYPC(b, n)        GET_GLOBAL_FIELD_N(b, n, CBAR, HYPC)
+#define GET_CBAR_FB(b, n)          GET_GLOBAL_FIELD_N(b, n, CBAR, FB)
+#define GET_CBAR_MEMATTR(b, n)     GET_GLOBAL_FIELD_N(b, n, CBAR, MEMATTR)
+#define GET_CBAR_TYPE(b, n)        GET_GLOBAL_FIELD_N(b, n, CBAR, TYPE)
+#define GET_CBAR_BSU(b, n)         GET_GLOBAL_FIELD_N(b, n, CBAR, BSU)
+#define GET_CBAR_RACFG(b, n)       GET_GLOBAL_FIELD_N(b, n, CBAR, RACFG)
+#define GET_CBAR_WACFG(b, n)       GET_GLOBAL_FIELD_N(b, n, CBAR, WACFG)
+#define GET_CBAR_IRPTNDX(b, n)     GET_GLOBAL_FIELD_N(b, n, CBAR, IRPTNDX)
+
+/* Context Bank Fault Restricted Syndrome Register A: CBFRSYNRA_N */
+#define SET_CBFRSYNRA_SID(b, n, v) SET_GLOBAL_FIELD_N(b, n, CBFRSYNRA, SID, v)
+
+#define GET_CBFRSYNRA_SID(b, n)    GET_GLOBAL_FIELD_N(b, n, CBFRSYNRA, SID)
+
+/* Stage 1 Context Bank Format Fields */
+#define SET_CB_ACTLR_REQPRIORITY (b, c, v) \
+		SET_CONTEXT_FIELD(b, c, CB_ACTLR, REQPRIORITY, v)
+#define SET_CB_ACTLR_REQPRIORITYCFG(b, c, v) \
+		SET_CONTEXT_FIELD(b, c, CB_ACTLR, REQPRIORITYCFG, v)
+#define SET_CB_ACTLR_PRIVCFG(b, c, v) \
+		SET_CONTEXT_FIELD(b, c, CB_ACTLR, PRIVCFG, v)
+#define SET_CB_ACTLR_BPRCOSH(b, c, v) \
+		SET_CONTEXT_FIELD(b, c, CB_ACTLR, BPRCOSH, v)
+#define SET_CB_ACTLR_BPRCISH(b, c, v) \
+		SET_CONTEXT_FIELD(b, c, CB_ACTLR, BPRCISH, v)
+#define SET_CB_ACTLR_BPRCNSH(b, c, v) \
+		SET_CONTEXT_FIELD(b, c, CB_ACTLR, BPRCNSH, v)
+
+#define GET_CB_ACTLR_REQPRIORITY (b, c) \
+		GET_CONTEXT_FIELD(b, c, CB_ACTLR, REQPRIORITY)
+#define GET_CB_ACTLR_REQPRIORITYCFG(b, c) \
+		GET_CONTEXT_FIELD(b, c, CB_ACTLR, REQPRIORITYCFG)
+#define GET_CB_ACTLR_PRIVCFG(b, c)  GET_CONTEXT_FIELD(b, c, CB_ACTLR, PRIVCFG)
+#define GET_CB_ACTLR_BPRCOSH(b, c)  GET_CONTEXT_FIELD(b, c, CB_ACTLR, BPRCOSH)
+#define GET_CB_ACTLR_BPRCISH(b, c)  GET_CONTEXT_FIELD(b, c, CB_ACTLR, BPRCISH)
+#define GET_CB_ACTLR_BPRCNSH(b, c)  GET_CONTEXT_FIELD(b, c, CB_ACTLR, BPRCNSH)
+
+/* Address Translation, Stage 1, Privileged Read: CB_ATS1PR */
+#define SET_CB_ATS1PR_ADDR(b, c, v) SET_CONTEXT_FIELD(b, c, CB_ATS1PR, ADDR, v)
+
+#define GET_CB_ATS1PR_ADDR(b, c)    GET_CONTEXT_FIELD(b, c, CB_ATS1PR, ADDR)
+
+/* Address Translation, Stage 1, Privileged Write: CB_ATS1PW */
+#define SET_CB_ATS1PW_ADDR(b, c, v) SET_CONTEXT_FIELD(b, c, CB_ATS1PW, ADDR, v)
+
+#define GET_CB_ATS1PW_ADDR(b, c)    GET_CONTEXT_FIELD(b, c, CB_ATS1PW, ADDR)
+
+/* Address Translation, Stage 1, User Read: CB_ATS1UR */
+#define SET_CB_ATS1UR_ADDR(b, c, v) SET_CONTEXT_FIELD(b, c, CB_ATS1UR, ADDR, v)
+
+#define GET_CB_ATS1UR_ADDR(b, c)    GET_CONTEXT_FIELD(b, c, CB_ATS1UR, ADDR)
+
+/* Address Translation, Stage 1, User Write: CB_ATS1UW */
+#define SET_CB_ATS1UW_ADDR(b, c, v) SET_CONTEXT_FIELD(b, c, CB_ATS1UW, ADDR, v)
+
+#define GET_CB_ATS1UW_ADDR(b, c)    GET_CONTEXT_FIELD(b, c, CB_ATS1UW, ADDR)
+
+/* Address Translation Status Register: CB_ATSR */
+#define SET_CB_ATSR_ACTIVE(b, c, v) SET_CONTEXT_FIELD(b, c, CB_ATSR, ACTIVE, v)
+
+#define GET_CB_ATSR_ACTIVE(b, c)    GET_CONTEXT_FIELD(b, c, CB_ATSR, ACTIVE)
+
+/* Context ID Register: CB_CONTEXTIDR */
+#define SET_CB_CONTEXTIDR_ASID(b, c, v) \
+			SET_CONTEXT_FIELD(b, c, CB_CONTEXTIDR, ASID, v)
+#define SET_CB_CONTEXTIDR_PROCID(b, c, v) \
+			SET_CONTEXT_FIELD(b, c, CB_CONTEXTIDR, PROCID, v)
+
+#define GET_CB_CONTEXTIDR_ASID(b, c)    \
+			GET_CONTEXT_FIELD(b, c, CB_CONTEXTIDR, ASID)
+#define GET_CB_CONTEXTIDR_PROCID(b, c)    \
+			GET_CONTEXT_FIELD(b, c, CB_CONTEXTIDR, PROCID)
+
+/* Fault Address Register: CB_FAR */
+#define SET_CB_FAR_FADDR(b, c, v) SET_CONTEXT_FIELD(b, c, CB_FAR, FADDR, v)
+
+#define GET_CB_FAR_FADDR(b, c)    GET_CONTEXT_FIELD(b, c, CB_FAR, FADDR)
+
+/* Fault Status Register: CB_FSR */
+#define SET_CB_FSR_TF(b, c, v)     SET_CONTEXT_FIELD(b, c, CB_FSR, TF, v)
+#define SET_CB_FSR_AFF(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_FSR, AFF, v)
+#define SET_CB_FSR_PF(b, c, v)     SET_CONTEXT_FIELD(b, c, CB_FSR, PF, v)
+#define SET_CB_FSR_EF(b, c, v)     SET_CONTEXT_FIELD(b, c, CB_FSR, EF, v)
+#define SET_CB_FSR_TLBMCF(b, c, v) SET_CONTEXT_FIELD(b, c, CB_FSR, TLBMCF, v)
+#define SET_CB_FSR_TLBLKF(b, c, v) SET_CONTEXT_FIELD(b, c, CB_FSR, TLBLKF, v)
+#define SET_CB_FSR_SS(b, c, v)     SET_CONTEXT_FIELD(b, c, CB_FSR, SS, v)
+#define SET_CB_FSR_MULTI(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_FSR, MULTI, v)
+
+#define GET_CB_FSR_TF(b, c)        GET_CONTEXT_FIELD(b, c, CB_FSR, TF)
+#define GET_CB_FSR_AFF(b, c)       GET_CONTEXT_FIELD(b, c, CB_FSR, AFF)
+#define GET_CB_FSR_PF(b, c)        GET_CONTEXT_FIELD(b, c, CB_FSR, PF)
+#define GET_CB_FSR_EF(b, c)        GET_CONTEXT_FIELD(b, c, CB_FSR, EF)
+#define GET_CB_FSR_TLBMCF(b, c)    GET_CONTEXT_FIELD(b, c, CB_FSR, TLBMCF)
+#define GET_CB_FSR_TLBLKF(b, c)    GET_CONTEXT_FIELD(b, c, CB_FSR, TLBLKF)
+#define GET_CB_FSR_SS(b, c)        GET_CONTEXT_FIELD(b, c, CB_FSR, SS)
+#define GET_CB_FSR_MULTI(b, c)     GET_CONTEXT_FIELD(b, c, CB_FSR, MULTI)
+
+/* Fault Syndrome Register 0: CB_FSYNR0 */
+#define SET_CB_FSYNR0_PLVL(b, c, v) SET_CONTEXT_FIELD(b, c, CB_FSYNR0, PLVL, v)
+#define SET_CB_FSYNR0_S1PTWF(b, c, v) \
+				SET_CONTEXT_FIELD(b, c, CB_FSYNR0, S1PTWF, v)
+#define SET_CB_FSYNR0_WNR(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_FSYNR0, WNR, v)
+#define SET_CB_FSYNR0_PNU(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_FSYNR0, PNU, v)
+#define SET_CB_FSYNR0_IND(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_FSYNR0, IND, v)
+#define SET_CB_FSYNR0_NSSTATE(b, c, v) \
+				SET_CONTEXT_FIELD(b, c, CB_FSYNR0, NSSTATE, v)
+#define SET_CB_FSYNR0_NSATTR(b, c, v) \
+				SET_CONTEXT_FIELD(b, c, CB_FSYNR0, NSATTR, v)
+#define SET_CB_FSYNR0_ATOF(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_FSYNR0, ATOF, v)
+#define SET_CB_FSYNR0_PTWF(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_FSYNR0, PTWF, v)
+#define SET_CB_FSYNR0_AFR(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_FSYNR0, AFR, v)
+#define SET_CB_FSYNR0_S1CBNDX(b, c, v) \
+				SET_CONTEXT_FIELD(b, c, CB_FSYNR0, S1CBNDX, v)
+
+#define GET_CB_FSYNR0_PLVL(b, c)    GET_CONTEXT_FIELD(b, c, CB_FSYNR0, PLVL)
+#define GET_CB_FSYNR0_S1PTWF(b, c)    \
+				GET_CONTEXT_FIELD(b, c, CB_FSYNR0, S1PTWF)
+#define GET_CB_FSYNR0_WNR(b, c)     GET_CONTEXT_FIELD(b, c, CB_FSYNR0, WNR)
+#define GET_CB_FSYNR0_PNU(b, c)     GET_CONTEXT_FIELD(b, c, CB_FSYNR0, PNU)
+#define GET_CB_FSYNR0_IND(b, c)     GET_CONTEXT_FIELD(b, c, CB_FSYNR0, IND)
+#define GET_CB_FSYNR0_NSSTATE(b, c)    \
+				GET_CONTEXT_FIELD(b, c, CB_FSYNR0, NSSTATE)
+#define GET_CB_FSYNR0_NSATTR(b, c)    \
+				GET_CONTEXT_FIELD(b, c, CB_FSYNR0, NSATTR)
+#define GET_CB_FSYNR0_ATOF(b, c)     GET_CONTEXT_FIELD(b, c, CB_FSYNR0, ATOF)
+#define GET_CB_FSYNR0_PTWF(b, c)     GET_CONTEXT_FIELD(b, c, CB_FSYNR0, PTWF)
+#define GET_CB_FSYNR0_AFR(b, c)      GET_CONTEXT_FIELD(b, c, CB_FSYNR0, AFR)
+#define GET_CB_FSYNR0_S1CBNDX(b, c)    \
+				GET_CONTEXT_FIELD(b, c, CB_FSYNR0, S1CBNDX)
+
+/* Normal Memory Remap Register: CB_NMRR */
+#define SET_CB_NMRR_IR0(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, IR0, v)
+#define SET_CB_NMRR_IR1(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, IR1, v)
+#define SET_CB_NMRR_IR2(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, IR2, v)
+#define SET_CB_NMRR_IR3(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, IR3, v)
+#define SET_CB_NMRR_IR4(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, IR4, v)
+#define SET_CB_NMRR_IR5(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, IR5, v)
+#define SET_CB_NMRR_IR6(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, IR6, v)
+#define SET_CB_NMRR_IR7(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, IR7, v)
+#define SET_CB_NMRR_OR0(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, OR0, v)
+#define SET_CB_NMRR_OR1(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, OR1, v)
+#define SET_CB_NMRR_OR2(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, OR2, v)
+#define SET_CB_NMRR_OR3(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, OR3, v)
+#define SET_CB_NMRR_OR4(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, OR4, v)
+#define SET_CB_NMRR_OR5(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, OR5, v)
+#define SET_CB_NMRR_OR6(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, OR6, v)
+#define SET_CB_NMRR_OR7(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_NMRR, OR7, v)
+
+#define GET_CB_NMRR_IR0(b, c)       GET_CONTEXT_FIELD(b, c, CB_NMRR, IR0)
+#define GET_CB_NMRR_IR1(b, c)       GET_CONTEXT_FIELD(b, c, CB_NMRR, IR1)
+#define GET_CB_NMRR_IR2(b, c)       GET_CONTEXT_FIELD(b, c, CB_NMRR, IR2)
+#define GET_CB_NMRR_IR3(b, c)       GET_CONTEXT_FIELD(b, c, CB_NMRR, IR3)
+#define GET_CB_NMRR_IR4(b, c)       GET_CONTEXT_FIELD(b, c, CB_NMRR, IR4)
+#define GET_CB_NMRR_IR5(b, c)       GET_CONTEXT_FIELD(b, c, CB_NMRR, IR5)
+#define GET_CB_NMRR_IR6(b, c)       GET_CONTEXT_FIELD(b, c, CB_NMRR, IR6)
+#define GET_CB_NMRR_IR7(b, c)       GET_CONTEXT_FIELD(b, c, CB_NMRR, IR7)
+#define GET_CB_NMRR_OR0(b, c)       GET_CONTEXT_FIELD(b, c, CB_NMRR, OR0)
+#define GET_CB_NMRR_OR1(b, c)       GET_CONTEXT_FIELD(b, c, CB_NMRR, OR1)
+#define GET_CB_NMRR_OR2(b, c)       GET_CONTEXT_FIELD(b, c, CB_NMRR, OR2)
+#define GET_CB_NMRR_OR3(b, c)       GET_CONTEXT_FIELD(b, c, CB_NMRR, OR3)
+#define GET_CB_NMRR_OR4(b, c)       GET_CONTEXT_FIELD(b, c, CB_NMRR, OR4)
+#define GET_CB_NMRR_OR5(b, c)       GET_CONTEXT_FIELD(b, c, CB_NMRR, OR5)
+
+/* Physical Address Register: CB_PAR */
+#define SET_CB_PAR_F(b, c, v)       SET_CONTEXT_FIELD(b, c, CB_PAR, F, v)
+#define SET_CB_PAR_SS(b, c, v)      SET_CONTEXT_FIELD(b, c, CB_PAR, SS, v)
+#define SET_CB_PAR_OUTER(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_PAR, OUTER, v)
+#define SET_CB_PAR_INNER(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_PAR, INNER, v)
+#define SET_CB_PAR_SH(b, c, v)      SET_CONTEXT_FIELD(b, c, CB_PAR, SH, v)
+#define SET_CB_PAR_NS(b, c, v)      SET_CONTEXT_FIELD(b, c, CB_PAR, NS, v)
+#define SET_CB_PAR_NOS(b, c, v)     SET_CONTEXT_FIELD(b, c, CB_PAR, NOS, v)
+#define SET_CB_PAR_PA(b, c, v)      SET_CONTEXT_FIELD(b, c, CB_PAR, PA, v)
+#define SET_CB_PAR_TF(b, c, v)      SET_CONTEXT_FIELD(b, c, CB_PAR, TF, v)
+#define SET_CB_PAR_AFF(b, c, v)     SET_CONTEXT_FIELD(b, c, CB_PAR, AFF, v)
+#define SET_CB_PAR_PF(b, c, v)      SET_CONTEXT_FIELD(b, c, CB_PAR, PF, v)
+#define SET_CB_PAR_TLBMCF(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_PAR, TLBMCF, v)
+#define SET_CB_PAR_TLBLKF(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_PAR, TLBLKF, v)
+#define SET_CB_PAR_ATOT(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_PAR, ATOT, v)
+#define SET_CB_PAR_PLVL(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_PAR, PLVL, v)
+#define SET_CB_PAR_STAGE(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_PAR, STAGE, v)
+
+#define GET_CB_PAR_F(b, c)          GET_CONTEXT_FIELD(b, c, CB_PAR, F)
+#define GET_CB_PAR_SS(b, c)         GET_CONTEXT_FIELD(b, c, CB_PAR, SS)
+#define GET_CB_PAR_OUTER(b, c)      GET_CONTEXT_FIELD(b, c, CB_PAR, OUTER)
+#define GET_CB_PAR_INNER(b, c)      GET_CONTEXT_FIELD(b, c, CB_PAR, INNER)
+#define GET_CB_PAR_SH(b, c)         GET_CONTEXT_FIELD(b, c, CB_PAR, SH)
+#define GET_CB_PAR_NS(b, c)         GET_CONTEXT_FIELD(b, c, CB_PAR, NS)
+#define GET_CB_PAR_NOS(b, c)        GET_CONTEXT_FIELD(b, c, CB_PAR, NOS)
+#define GET_CB_PAR_PA(b, c)         GET_CONTEXT_FIELD(b, c, CB_PAR, PA)
+#define GET_CB_PAR_TF(b, c)         GET_CONTEXT_FIELD(b, c, CB_PAR, TF)
+#define GET_CB_PAR_AFF(b, c)        GET_CONTEXT_FIELD(b, c, CB_PAR, AFF)
+#define GET_CB_PAR_PF(b, c)         GET_CONTEXT_FIELD(b, c, CB_PAR, PF)
+#define GET_CB_PAR_TLBMCF(b, c)     GET_CONTEXT_FIELD(b, c, CB_PAR, TLBMCF)
+#define GET_CB_PAR_TLBLKF(b, c)     GET_CONTEXT_FIELD(b, c, CB_PAR, TLBLKF)
+#define GET_CB_PAR_ATOT(b, c)       GET_CONTEXT_FIELD(b, c, CB_PAR, ATOT)
+#define GET_CB_PAR_PLVL(b, c)       GET_CONTEXT_FIELD(b, c, CB_PAR, PLVL)
+#define GET_CB_PAR_STAGE(b, c)      GET_CONTEXT_FIELD(b, c, CB_PAR, STAGE)
+
+/* Primary Region Remap Register: CB_PRRR */
+#define SET_CB_PRRR_TR0(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_PRRR, TR0, v)
+#define SET_CB_PRRR_TR1(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_PRRR, TR1, v)
+#define SET_CB_PRRR_TR2(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_PRRR, TR2, v)
+#define SET_CB_PRRR_TR3(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_PRRR, TR3, v)
+#define SET_CB_PRRR_TR4(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_PRRR, TR4, v)
+#define SET_CB_PRRR_TR5(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_PRRR, TR5, v)
+#define SET_CB_PRRR_TR6(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_PRRR, TR6, v)
+#define SET_CB_PRRR_TR7(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_PRRR, TR7, v)
+#define SET_CB_PRRR_DS0(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_PRRR, DS0, v)
+#define SET_CB_PRRR_DS1(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_PRRR, DS1, v)
+#define SET_CB_PRRR_NS0(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_PRRR, NS0, v)
+#define SET_CB_PRRR_NS1(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_PRRR, NS1, v)
+#define SET_CB_PRRR_NOS0(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_PRRR, NOS0, v)
+#define SET_CB_PRRR_NOS1(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_PRRR, NOS1, v)
+#define SET_CB_PRRR_NOS2(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_PRRR, NOS2, v)
+#define SET_CB_PRRR_NOS3(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_PRRR, NOS3, v)
+#define SET_CB_PRRR_NOS4(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_PRRR, NOS4, v)
+#define SET_CB_PRRR_NOS5(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_PRRR, NOS5, v)
+#define SET_CB_PRRR_NOS6(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_PRRR, NOS6, v)
+#define SET_CB_PRRR_NOS7(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_PRRR, NOS7, v)
+
+#define GET_CB_PRRR_TR0(b, c)       GET_CONTEXT_FIELD(b, c, CB_PRRR, TR0)
+#define GET_CB_PRRR_TR1(b, c)       GET_CONTEXT_FIELD(b, c, CB_PRRR, TR1)
+#define GET_CB_PRRR_TR2(b, c)       GET_CONTEXT_FIELD(b, c, CB_PRRR, TR2)
+#define GET_CB_PRRR_TR3(b, c)       GET_CONTEXT_FIELD(b, c, CB_PRRR, TR3)
+#define GET_CB_PRRR_TR4(b, c)       GET_CONTEXT_FIELD(b, c, CB_PRRR, TR4)
+#define GET_CB_PRRR_TR5(b, c)       GET_CONTEXT_FIELD(b, c, CB_PRRR, TR5)
+#define GET_CB_PRRR_TR6(b, c)       GET_CONTEXT_FIELD(b, c, CB_PRRR, TR6)
+#define GET_CB_PRRR_TR7(b, c)       GET_CONTEXT_FIELD(b, c, CB_PRRR, TR7)
+#define GET_CB_PRRR_DS0(b, c)       GET_CONTEXT_FIELD(b, c, CB_PRRR, DS0)
+#define GET_CB_PRRR_DS1(b, c)       GET_CONTEXT_FIELD(b, c, CB_PRRR, DS1)
+#define GET_CB_PRRR_NS0(b, c)       GET_CONTEXT_FIELD(b, c, CB_PRRR, NS0)
+#define GET_CB_PRRR_NS1(b, c)       GET_CONTEXT_FIELD(b, c, CB_PRRR, NS1)
+#define GET_CB_PRRR_NOS0(b, c)      GET_CONTEXT_FIELD(b, c, CB_PRRR, NOS0)
+#define GET_CB_PRRR_NOS1(b, c)      GET_CONTEXT_FIELD(b, c, CB_PRRR, NOS1)
+#define GET_CB_PRRR_NOS2(b, c)      GET_CONTEXT_FIELD(b, c, CB_PRRR, NOS2)
+#define GET_CB_PRRR_NOS3(b, c)      GET_CONTEXT_FIELD(b, c, CB_PRRR, NOS3)
+#define GET_CB_PRRR_NOS4(b, c)      GET_CONTEXT_FIELD(b, c, CB_PRRR, NOS4)
+#define GET_CB_PRRR_NOS5(b, c)      GET_CONTEXT_FIELD(b, c, CB_PRRR, NOS5)
+#define GET_CB_PRRR_NOS6(b, c)      GET_CONTEXT_FIELD(b, c, CB_PRRR, NOS6)
+#define GET_CB_PRRR_NOS7(b, c)      GET_CONTEXT_FIELD(b, c, CB_PRRR, NOS7)
+
+/* Transaction Resume: CB_RESUME */
+#define SET_CB_RESUME_TNR(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_RESUME, TNR, v)
+
+#define GET_CB_RESUME_TNR(b, c)     GET_CONTEXT_FIELD(b, c, CB_RESUME, TNR)
+
+/* System Control Register: CB_SCTLR */
+#define SET_CB_SCTLR_M(b, c, v)     SET_CONTEXT_FIELD(b, c, CB_SCTLR, M, v)
+#define SET_CB_SCTLR_TRE(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_SCTLR, TRE, v)
+#define SET_CB_SCTLR_AFE(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_SCTLR, AFE, v)
+#define SET_CB_SCTLR_AFFD(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_SCTLR, AFFD, v)
+#define SET_CB_SCTLR_E(b, c, v)     SET_CONTEXT_FIELD(b, c, CB_SCTLR, E, v)
+#define SET_CB_SCTLR_CFRE(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_SCTLR, CFRE, v)
+#define SET_CB_SCTLR_CFIE(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_SCTLR, CFIE, v)
+#define SET_CB_SCTLR_CFCFG(b, c, v) SET_CONTEXT_FIELD(b, c, CB_SCTLR, CFCFG, v)
+#define SET_CB_SCTLR_HUPCF(b, c, v) SET_CONTEXT_FIELD(b, c, CB_SCTLR, HUPCF, v)
+#define SET_CB_SCTLR_WXN(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_SCTLR, WXN, v)
+#define SET_CB_SCTLR_UWXN(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_SCTLR, UWXN, v)
+#define SET_CB_SCTLR_ASIDPNE(b, c, v) \
+			SET_CONTEXT_FIELD(b, c, CB_SCTLR, ASIDPNE, v)
+#define SET_CB_SCTLR_TRANSIENTCFG(b, c, v) \
+			SET_CONTEXT_FIELD(b, c, CB_SCTLR, TRANSIENTCFG, v)
+#define SET_CB_SCTLR_MEMATTR(b, c, v) \
+			SET_CONTEXT_FIELD(b, c, CB_SCTLR, MEMATTR, v)
+#define SET_CB_SCTLR_MTCFG(b, c, v) SET_CONTEXT_FIELD(b, c, CB_SCTLR, MTCFG, v)
+#define SET_CB_SCTLR_SHCFG(b, c, v) SET_CONTEXT_FIELD(b, c, CB_SCTLR, SHCFG, v)
+#define SET_CB_SCTLR_RACFG(b, c, v) SET_CONTEXT_FIELD(b, c, CB_SCTLR, RACFG, v)
+#define SET_CB_SCTLR_WACFG(b, c, v) SET_CONTEXT_FIELD(b, c, CB_SCTLR, WACFG, v)
+#define SET_CB_SCTLR_NSCFG(b, c, v) SET_CONTEXT_FIELD(b, c, CB_SCTLR, NSCFG, v)
+
+#define GET_CB_SCTLR_M(b, c)        GET_CONTEXT_FIELD(b, c, CB_SCTLR, M)
+#define GET_CB_SCTLR_TRE(b, c)      GET_CONTEXT_FIELD(b, c, CB_SCTLR, TRE)
+#define GET_CB_SCTLR_AFE(b, c)      GET_CONTEXT_FIELD(b, c, CB_SCTLR, AFE)
+#define GET_CB_SCTLR_AFFD(b, c)     GET_CONTEXT_FIELD(b, c, CB_SCTLR, AFFD)
+#define GET_CB_SCTLR_E(b, c)        GET_CONTEXT_FIELD(b, c, CB_SCTLR, E)
+#define GET_CB_SCTLR_CFRE(b, c)     GET_CONTEXT_FIELD(b, c, CB_SCTLR, CFRE)
+#define GET_CB_SCTLR_CFIE(b, c)     GET_CONTEXT_FIELD(b, c, CB_SCTLR, CFIE)
+#define GET_CB_SCTLR_CFCFG(b, c)    GET_CONTEXT_FIELD(b, c, CB_SCTLR, CFCFG)
+#define GET_CB_SCTLR_HUPCF(b, c)    GET_CONTEXT_FIELD(b, c, CB_SCTLR, HUPCF)
+#define GET_CB_SCTLR_WXN(b, c)      GET_CONTEXT_FIELD(b, c, CB_SCTLR, WXN)
+#define GET_CB_SCTLR_UWXN(b, c)     GET_CONTEXT_FIELD(b, c, CB_SCTLR, UWXN)
+#define GET_CB_SCTLR_ASIDPNE(b, c)    \
+			GET_CONTEXT_FIELD(b, c, CB_SCTLR, ASIDPNE)
+#define GET_CB_SCTLR_TRANSIENTCFG(b, c)    \
+			GET_CONTEXT_FIELD(b, c, CB_SCTLR, TRANSIENTCFG)
+#define GET_CB_SCTLR_MEMATTR(b, c)    \
+			GET_CONTEXT_FIELD(b, c, CB_SCTLR, MEMATTR)
+#define GET_CB_SCTLR_MTCFG(b, c)    GET_CONTEXT_FIELD(b, c, CB_SCTLR, MTCFG)
+#define GET_CB_SCTLR_SHCFG(b, c)    GET_CONTEXT_FIELD(b, c, CB_SCTLR, SHCFG)
+#define GET_CB_SCTLR_RACFG(b, c)    GET_CONTEXT_FIELD(b, c, CB_SCTLR, RACFG)
+#define GET_CB_SCTLR_WACFG(b, c)    GET_CONTEXT_FIELD(b, c, CB_SCTLR, WACFG)
+#define GET_CB_SCTLR_NSCFG(b, c)    GET_CONTEXT_FIELD(b, c, CB_SCTLR, NSCFG)
+
+/* Invalidate TLB by ASID: CB_TLBIASID */
+#define SET_CB_TLBIASID_ASID(b, c, v) \
+				SET_CONTEXT_FIELD(b, c, CB_TLBIASID, ASID, v)
+
+#define GET_CB_TLBIASID_ASID(b, c)    \
+				GET_CONTEXT_FIELD(b, c, CB_TLBIASID, ASID)
+
+/* Invalidate TLB by VA: CB_TLBIVA */
+#define SET_CB_TLBIVA_ASID(b, c, v) SET_CONTEXT_FIELD(b, c, CB_TLBIVA, ASID, v)
+#define SET_CB_TLBIVA_VA(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_TLBIVA, VA, v)
+
+#define GET_CB_TLBIVA_ASID(b, c)    GET_CONTEXT_FIELD(b, c, CB_TLBIVA, ASID)
+#define GET_CB_TLBIVA_VA(b, c)      GET_CONTEXT_FIELD(b, c, CB_TLBIVA, VA)
+
+/* Invalidate TLB by VA, All ASID: CB_TLBIVAA */
+#define SET_CB_TLBIVAA_VA(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_TLBIVAA, VA, v)
+
+#define GET_CB_TLBIVAA_VA(b, c)     GET_CONTEXT_FIELD(b, c, CB_TLBIVAA, VA)
+
+/* Invalidate TLB by VA, All ASID, Last Level: CB_TLBIVAAL */
+#define SET_CB_TLBIVAAL_VA(b, c, v) SET_CONTEXT_FIELD(b, c, CB_TLBIVAAL, VA, v)
+
+#define GET_CB_TLBIVAAL_VA(b, c)    GET_CONTEXT_FIELD(b, c, CB_TLBIVAAL, VA)
+
+/* Invalidate TLB by VA, Last Level: CB_TLBIVAL */
+#define SET_CB_TLBIVAL_ASID(b, c, v) \
+			SET_CONTEXT_FIELD(b, c, CB_TLBIVAL, ASID, v)
+#define SET_CB_TLBIVAL_VA(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_TLBIVAL, VA, v)
+
+#define GET_CB_TLBIVAL_ASID(b, c)    \
+			GET_CONTEXT_FIELD(b, c, CB_TLBIVAL, ASID)
+#define GET_CB_TLBIVAL_VA(b, c)      GET_CONTEXT_FIELD(b, c, CB_TLBIVAL, VA)
+
+/* TLB Status: CB_TLBSTATUS */
+#define SET_CB_TLBSTATUS_SACTIVE(b, c, v) \
+			SET_CONTEXT_FIELD(b, c, CB_TLBSTATUS, SACTIVE, v)
+
+#define GET_CB_TLBSTATUS_SACTIVE(b, c)    \
+			GET_CONTEXT_FIELD(b, c, CB_TLBSTATUS, SACTIVE)
+
+/* Translation Table Base Control Register: CB_TTBCR */
+#define SET_CB_TTBCR_T0SZ(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_TTBCR, T0SZ, v)
+#define SET_CB_TTBCR_PD0(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_TTBCR, PD0, v)
+#define SET_CB_TTBCR_PD1(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_TTBCR, PD1, v)
+#define SET_CB_TTBCR_NSCFG0(b, c, v) \
+			SET_CONTEXT_FIELD(b, c, CB_TTBCR, NSCFG0, v)
+#define SET_CB_TTBCR_NSCFG1(b, c, v) \
+			SET_CONTEXT_FIELD(b, c, CB_TTBCR, NSCFG1, v)
+#define SET_CB_TTBCR_EAE(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_TTBCR, EAE, v)
+
+#define GET_CB_TTBCR_T0SZ(b, c)      GET_CONTEXT_FIELD(b, c, CB_TTBCR, T0SZ)
+#define GET_CB_TTBCR_PD0(b, c)       GET_CONTEXT_FIELD(b, c, CB_TTBCR, PD0)
+#define GET_CB_TTBCR_PD1(b, c)       GET_CONTEXT_FIELD(b, c, CB_TTBCR, PD1)
+#define GET_CB_TTBCR_NSCFG0(b, c)    \
+			GET_CONTEXT_FIELD(b, c, CB_TTBCR, NSCFG0)
+#define GET_CB_TTBCR_NSCFG1(b, c)    \
+			GET_CONTEXT_FIELD(b, c, CB_TTBCR, NSCFG1)
+#define GET_CB_TTBCR_EAE(b, c)       GET_CONTEXT_FIELD(b, c, CB_TTBCR, EAE)
+
+/* Translation Table Base Register 0: CB_TTBR */
+#define SET_CB_TTBR0_IRGN1(b, c, v) SET_CONTEXT_FIELD(b, c, CB_TTBR0, IRGN1, v)
+#define SET_CB_TTBR0_S(b, c, v)     SET_CONTEXT_FIELD(b, c, CB_TTBR0, S, v)
+#define SET_CB_TTBR0_RGN(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_TTBR0, RGN, v)
+#define SET_CB_TTBR0_NOS(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_TTBR0, NOS, v)
+#define SET_CB_TTBR0_IRGN0(b, c, v) SET_CONTEXT_FIELD(b, c, CB_TTBR0, IRGN0, v)
+#define SET_CB_TTBR0_ADDR(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_TTBR0, ADDR, v)
+
+#define GET_CB_TTBR0_IRGN1(b, c)    GET_CONTEXT_FIELD(b, c, CB_TTBR0, IRGN1)
+#define GET_CB_TTBR0_S(b, c)        GET_CONTEXT_FIELD(b, c, CB_TTBR0, S)
+#define GET_CB_TTBR0_RGN(b, c)      GET_CONTEXT_FIELD(b, c, CB_TTBR0, RGN)
+#define GET_CB_TTBR0_NOS(b, c)      GET_CONTEXT_FIELD(b, c, CB_TTBR0, NOS)
+#define GET_CB_TTBR0_IRGN0(b, c)    GET_CONTEXT_FIELD(b, c, CB_TTBR0, IRGN0)
+#define GET_CB_TTBR0_ADDR(b, c)     GET_CONTEXT_FIELD(b, c, CB_TTBR0, ADDR)
+
+/* Translation Table Base Register 1: CB_TTBR1 */
+#define SET_CB_TTBR1_IRGN1(b, c, v) SET_CONTEXT_FIELD(b, c, CB_TTBR1, IRGN1, v)
+#define SET_CB_TTBR1_0S(b, c, v)    SET_CONTEXT_FIELD(b, c, CB_TTBR1, S, v)
+#define SET_CB_TTBR1_RGN(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_TTBR1, RGN, v)
+#define SET_CB_TTBR1_NOS(b, c, v)   SET_CONTEXT_FIELD(b, c, CB_TTBR1, NOS, v)
+#define SET_CB_TTBR1_IRGN0(b, c, v) SET_CONTEXT_FIELD(b, c, CB_TTBR1, IRGN0, v)
+#define SET_CB_TTBR1_ADDR(b, c, v)  SET_CONTEXT_FIELD(b, c, CB_TTBR1, ADDR, v)
+
+#define GET_CB_TTBR1_IRGN1(b, c)    GET_CONTEXT_FIELD(b, c, CB_TTBR1, IRGN1)
+#define GET_CB_TTBR1_0S(b, c)       GET_CONTEXT_FIELD(b, c, CB_TTBR1, S)
+#define GET_CB_TTBR1_RGN(b, c)      GET_CONTEXT_FIELD(b, c, CB_TTBR1, RGN)
+#define GET_CB_TTBR1_NOS(b, c)      GET_CONTEXT_FIELD(b, c, CB_TTBR1, NOS)
+#define GET_CB_TTBR1_IRGN0(b, c)    GET_CONTEXT_FIELD(b, c, CB_TTBR1, IRGN0)
+#define GET_CB_TTBR1_ADDR(b, c)     GET_CONTEXT_FIELD(b, c, CB_TTBR1, ADDR)
+
+/* Global Register Space 0 */
+#define CR0		(0x0000)
+#define SCR1		(0x0004)
+#define CR2		(0x0008)
+#define ACR		(0x0010)
+#define IDR0		(0x0020)
+#define IDR1		(0x0024)
+#define IDR2		(0x0028)
+#define IDR7		(0x003C)
+#define GFAR		(0x0040)
+#define GFSR		(0x0044)
+#define GFSRRESTORE	(0x004C)
+#define GFSYNR0		(0x0050)
+#define GFSYNR1		(0x0054)
+#define GFSYNR2		(0x0058)
+#define TLBIVMID	(0x0064)
+#define TLBIALLNSNH	(0x0068)
+#define TLBIALLH	(0x006C)
+#define TLBGSYNC	(0x0070)
+#define TLBGSTATUS	(0x0074)
+#define TLBIVAH		(0x0078)
+#define GATS1UR		(0x0100)
+#define GATS1UW		(0x0108)
+#define GATS1PR		(0x0110)
+#define GATS1PW		(0x0118)
+#define GATS12UR	(0x0120)
+#define GATS12UW	(0x0128)
+#define GATS12PR	(0x0130)
+#define GATS12PW	(0x0138)
+#define GPAR		(0x0180)
+#define GATSR		(0x0188)
+#define NSCR0		(0x0400)
+#define NSCR2		(0x0408)
+#define NSACR		(0x0410)
+#define SMR		(0x0800)
+#define S2CR		(0x0C00)
+
+/* Global Register Space 1 */
+#define CBAR		(0x1000)
+#define CBFRSYNRA	(0x1400)
+
+/* Implementation defined Register Space */
+#define PREDICTIONDIS0	(0x204C)
+#define PREDICTIONDIS1	(0x2050)
+#define S1L1BFBLP0	(0x215C)
+
+/* Performance Monitoring Register Space */
+#define PMEVCNTR_N	(0x3000)
+#define PMEVTYPER_N	(0x3400)
+#define PMCGCR_N	(0x3800)
+#define PMCGSMR_N	(0x3A00)
+#define PMCNTENSET_N	(0x3C00)
+#define PMCNTENCLR_N	(0x3C20)
+#define PMINTENSET_N	(0x3C40)
+#define PMINTENCLR_N	(0x3C60)
+#define PMOVSCLR_N	(0x3C80)
+#define PMOVSSET_N	(0x3CC0)
+#define PMCFGR		(0x3E00)
+#define PMCR		(0x3E04)
+#define PMCEID0		(0x3E20)
+#define PMCEID1		(0x3E24)
+#define PMAUTHSTATUS	(0x3FB8)
+#define PMDEVTYPE	(0x3FCC)
+
+/* Secure Status Determination Address Space */
+#define SSDR_N		(0x4000)
+
+/* Stage 1 Context Bank Format */
+#define CB_SCTLR	(0x000)
+#define CB_ACTLR	(0x004)
+#define CB_RESUME	(0x008)
+#define CB_TTBR0	(0x020)
+#define CB_TTBR1	(0x028)
+#define CB_TTBCR	(0x030)
+#define CB_CONTEXTIDR	(0x034)
+#define CB_PRRR		(0x038)
+#define CB_NMRR		(0x03C)
+#define CB_PAR		(0x050)
+#define CB_FSR		(0x058)
+#define CB_FSRRESTORE	(0x05C)
+#define CB_FAR		(0x060)
+#define CB_FSYNR0	(0x068)
+#define CB_FSYNR1	(0x06C)
+#define CB_TLBIVA	(0x600)
+#define CB_TLBIVAA	(0x608)
+#define CB_TLBIASID	(0x610)
+#define CB_TLBIALL	(0x618)
+#define CB_TLBIVAL	(0x620)
+#define CB_TLBIVAAL	(0x628)
+#define CB_TLBSYNC	(0x7F0)
+#define CB_TLBSTATUS	(0x7F4)
+#define CB_ATS1PR	(0x800)
+#define CB_ATS1PW	(0x808)
+#define CB_ATS1UR	(0x810)
+#define CB_ATS1UW	(0x818)
+#define CB_ATSR		(0x8F0)
+#define CB_PMXEVCNTR_N	(0xE00)
+#define CB_PMXEVTYPER_N	(0xE80)
+#define CB_PMCFGR	(0xF00)
+#define CB_PMCR		(0xF04)
+#define CB_PMCEID0	(0xF20)
+#define CB_PMCEID1	(0xF24)
+#define CB_PMCNTENSET	(0xF40)
+#define CB_PMCNTENCLR	(0xF44)
+#define CB_PMINTENSET	(0xF48)
+#define CB_PMINTENCLR	(0xF4C)
+#define CB_PMOVSCLR	(0xF50)
+#define CB_PMOVSSET	(0xF58)
+#define CB_PMAUTHSTATUS	(0xFB8)
+
+/* Global Register Fields */
+/* Configuration Register: CR0 */
+#define CR0_NSCFG         (CR0_NSCFG_MASK         << CR0_NSCFG_SHIFT)
+#define CR0_WACFG         (CR0_WACFG_MASK         << CR0_WACFG_SHIFT)
+#define CR0_RACFG         (CR0_RACFG_MASK         << CR0_RACFG_SHIFT)
+#define CR0_SHCFG         (CR0_SHCFG_MASK         << CR0_SHCFG_SHIFT)
+#define CR0_SMCFCFG       (CR0_SMCFCFG_MASK       << CR0_SMCFCFG_SHIFT)
+#define CR0_MTCFG         (CR0_MTCFG_MASK         << CR0_MTCFG_SHIFT)
+#define CR0_MEMATTR       (CR0_MEMATTR_MASK       << CR0_MEMATTR_SHIFT)
+#define CR0_BSU           (CR0_BSU_MASK           << CR0_BSU_SHIFT)
+#define CR0_FB            (CR0_FB_MASK            << CR0_FB_SHIFT)
+#define CR0_PTM           (CR0_PTM_MASK           << CR0_PTM_SHIFT)
+#define CR0_VMIDPNE       (CR0_VMIDPNE_MASK       << CR0_VMIDPNE_SHIFT)
+#define CR0_USFCFG        (CR0_USFCFG_MASK        << CR0_USFCFG_SHIFT)
+#define CR0_GSE           (CR0_GSE_MASK           << CR0_GSE_SHIFT)
+#define CR0_STALLD        (CR0_STALLD_MASK        << CR0_STALLD_SHIFT)
+#define CR0_TRANSIENTCFG  (CR0_TRANSIENTCFG_MASK  << CR0_TRANSIENTCFG_SHIFT)
+#define CR0_GCFGFIE       (CR0_GCFGFIE_MASK       << CR0_GCFGFIE_SHIFT)
+#define CR0_GCFGFRE       (CR0_GCFGFRE_MASK       << CR0_GCFGFRE_SHIFT)
+#define CR0_GFIE          (CR0_GFIE_MASK          << CR0_GFIE_SHIFT)
+#define CR0_GFRE          (CR0_GFRE_MASK          << CR0_GFRE_SHIFT)
+#define CR0_CLIENTPD      (CR0_CLIENTPD_MASK      << CR0_CLIENTPD_SHIFT)
+
+/* Configuration Register: CR2 */
+#define CR2_BPVMID        (CR2_BPVMID_MASK << CR2_BPVMID_SHIFT)
+
+/* Global Address Translation, Stage 1, Privileged Read: GATS1PR */
+#define GATS1PR_ADDR  (GATS1PR_ADDR_MASK  << GATS1PR_ADDR_SHIFT)
+#define GATS1PR_NDX   (GATS1PR_NDX_MASK   << GATS1PR_NDX_SHIFT)
+
+/* Global Address Translation, Stage 1, Privileged Write: GATS1PW */
+#define GATS1PW_ADDR  (GATS1PW_ADDR_MASK  << GATS1PW_ADDR_SHIFT)
+#define GATS1PW_NDX   (GATS1PW_NDX_MASK   << GATS1PW_NDX_SHIFT)
+
+/* Global Address Translation, Stage 1, User Read: GATS1UR */
+#define GATS1UR_ADDR  (GATS1UR_ADDR_MASK  << GATS1UR_ADDR_SHIFT)
+#define GATS1UR_NDX   (GATS1UR_NDX_MASK   << GATS1UR_NDX_SHIFT)
+
+/* Global Address Translation, Stage 1, User Write: GATS1UW */
+#define GATS1UW_ADDR  (GATS1UW_ADDR_MASK  << GATS1UW_ADDR_SHIFT)
+#define GATS1UW_NDX   (GATS1UW_NDX_MASK   << GATS1UW_NDX_SHIFT)
+
+/* Global Address Translation, Stage 1 and 2, Privileged Read: GATS1PR */
+#define GATS12PR_ADDR (GATS12PR_ADDR_MASK << GATS12PR_ADDR_SHIFT)
+#define GATS12PR_NDX  (GATS12PR_NDX_MASK  << GATS12PR_NDX_SHIFT)
+
+/* Global Address Translation, Stage 1 and 2, Privileged Write: GATS1PW */
+#define GATS12PW_ADDR (GATS12PW_ADDR_MASK << GATS12PW_ADDR_SHIFT)
+#define GATS12PW_NDX  (GATS12PW_NDX_MASK  << GATS12PW_NDX_SHIFT)
+
+/* Global Address Translation, Stage 1 and 2, User Read: GATS1UR */
+#define GATS12UR_ADDR (GATS12UR_ADDR_MASK << GATS12UR_ADDR_SHIFT)
+#define GATS12UR_NDX  (GATS12UR_NDX_MASK  << GATS12UR_NDX_SHIFT)
+
+/* Global Address Translation, Stage 1 and 2, User Write: GATS1UW */
+#define GATS12UW_ADDR (GATS12UW_ADDR_MASK << GATS12UW_ADDR_SHIFT)
+#define GATS12UW_NDX  (GATS12UW_NDX_MASK  << GATS12UW_NDX_SHIFT)
+
+/* Global Address Translation Status Register: GATSR */
+#define GATSR_ACTIVE  (GATSR_ACTIVE_MASK  << GATSR_ACTIVE_SHIFT)
+
+/* Global Fault Address Register: GFAR */
+#define GFAR_FADDR    (GFAR_FADDR_MASK << GFAR_FADDR_SHIFT)
+
+/* Global Fault Status Register: GFSR */
+#define GFSR_ICF      (GFSR_ICF_MASK   << GFSR_ICF_SHIFT)
+#define GFSR_USF      (GFSR_USF_MASK   << GFSR_USF_SHIFT)
+#define GFSR_SMCF     (GFSR_SMCF_MASK  << GFSR_SMCF_SHIFT)
+#define GFSR_UCBF     (GFSR_UCBF_MASK  << GFSR_UCBF_SHIFT)
+#define GFSR_UCIF     (GFSR_UCIF_MASK  << GFSR_UCIF_SHIFT)
+#define GFSR_CAF      (GFSR_CAF_MASK   << GFSR_CAF_SHIFT)
+#define GFSR_EF       (GFSR_EF_MASK    << GFSR_EF_SHIFT)
+#define GFSR_PF       (GFSR_PF_MASK    << GFSR_PF_SHIFT)
+#define GFSR_MULTI    (GFSR_MULTI_MASK << GFSR_MULTI_SHIFT)
+
+/* Global Fault Syndrome Register 0: GFSYNR0 */
+#define GFSYNR0_NESTED  (GFSYNR0_NESTED_MASK  << GFSYNR0_NESTED_SHIFT)
+#define GFSYNR0_WNR     (GFSYNR0_WNR_MASK     << GFSYNR0_WNR_SHIFT)
+#define GFSYNR0_PNU     (GFSYNR0_PNU_MASK     << GFSYNR0_PNU_SHIFT)
+#define GFSYNR0_IND     (GFSYNR0_IND_MASK     << GFSYNR0_IND_SHIFT)
+#define GFSYNR0_NSSTATE (GFSYNR0_NSSTATE_MASK << GFSYNR0_NSSTATE_SHIFT)
+#define GFSYNR0_NSATTR  (GFSYNR0_NSATTR_MASK  << GFSYNR0_NSATTR_SHIFT)
+
+/* Global Fault Syndrome Register 1: GFSYNR1 */
+#define GFSYNR1_SID     (GFSYNR1_SID_MASK     << GFSYNR1_SID_SHIFT)
+
+/* Global Physical Address Register: GPAR */
+#define GPAR_F          (GPAR_F_MASK      << GPAR_F_SHIFT)
+#define GPAR_SS         (GPAR_SS_MASK     << GPAR_SS_SHIFT)
+#define GPAR_OUTER      (GPAR_OUTER_MASK  << GPAR_OUTER_SHIFT)
+#define GPAR_INNER      (GPAR_INNER_MASK  << GPAR_INNER_SHIFT)
+#define GPAR_SH         (GPAR_SH_MASK     << GPAR_SH_SHIFT)
+#define GPAR_NS         (GPAR_NS_MASK     << GPAR_NS_SHIFT)
+#define GPAR_NOS        (GPAR_NOS_MASK    << GPAR_NOS_SHIFT)
+#define GPAR_PA         (GPAR_PA_MASK     << GPAR_PA_SHIFT)
+#define GPAR_TF         (GPAR_TF_MASK     << GPAR_TF_SHIFT)
+#define GPAR_AFF        (GPAR_AFF_MASK    << GPAR_AFF_SHIFT)
+#define GPAR_PF         (GPAR_PF_MASK     << GPAR_PF_SHIFT)
+#define GPAR_EF         (GPAR_EF_MASK     << GPAR_EF_SHIFT)
+#define GPAR_TLCMCF     (GPAR_TLBMCF_MASK << GPAR_TLCMCF_SHIFT)
+#define GPAR_TLBLKF     (GPAR_TLBLKF_MASK << GPAR_TLBLKF_SHIFT)
+#define GPAR_UCBF       (GPAR_UCBF_MASK   << GFAR_UCBF_SHIFT)
+
+/* Identification Register: IDR0 */
+#define IDR0_NUMSMRG    (IDR0_NUMSMRG_MASK  << IDR0_NUMSMGR_SHIFT)
+#define IDR0_NUMSIDB    (IDR0_NUMSIDB_MASK  << IDR0_NUMSIDB_SHIFT)
+#define IDR0_BTM        (IDR0_BTM_MASK      << IDR0_BTM_SHIFT)
+#define IDR0_CTTW       (IDR0_CTTW_MASK     << IDR0_CTTW_SHIFT)
+#define IDR0_NUMIRPT    (IDR0_NUMIPRT_MASK  << IDR0_NUMIRPT_SHIFT)
+#define IDR0_PTFS       (IDR0_PTFS_MASK     << IDR0_PTFS_SHIFT)
+#define IDR0_SMS        (IDR0_SMS_MASK      << IDR0_SMS_SHIFT)
+#define IDR0_NTS        (IDR0_NTS_MASK      << IDR0_NTS_SHIFT)
+#define IDR0_S2TS       (IDR0_S2TS_MASK     << IDR0_S2TS_SHIFT)
+#define IDR0_S1TS       (IDR0_S1TS_MASK     << IDR0_S1TS_SHIFT)
+#define IDR0_SES        (IDR0_SES_MASK      << IDR0_SES_SHIFT)
+
+/* Identification Register: IDR1 */
+#define IDR1_NUMCB       (IDR1_NUMCB_MASK       << IDR1_NUMCB_SHIFT)
+#define IDR1_NUMSSDNDXB  (IDR1_NUMSSDNDXB_MASK  << IDR1_NUMSSDNDXB_SHIFT)
+#define IDR1_SSDTP       (IDR1_SSDTP_MASK       << IDR1_SSDTP_SHIFT)
+#define IDR1_SMCD        (IDR1_SMCD_MASK        << IDR1_SMCD_SHIFT)
+#define IDR1_NUMS2CB     (IDR1_NUMS2CB_MASK     << IDR1_NUMS2CB_SHIFT)
+#define IDR1_NUMPAGENDXB (IDR1_NUMPAGENDXB_MASK << IDR1_NUMPAGENDXB_SHIFT)
+#define IDR1_PAGESIZE    (IDR1_PAGESIZE_MASK    << IDR1_PAGESIZE_SHIFT)
+
+/* Identification Register: IDR2 */
+#define IDR2_IAS         (IDR2_IAS_MASK << IDR2_IAS_SHIFT)
+#define IDR1_OAS         (IDR2_OAS_MASK << IDR2_OAS_SHIFT)
+
+/* Identification Register: IDR7 */
+#define IDR7_MINOR       (IDR7_MINOR_MASK << IDR7_MINOR_SHIFT)
+#define IDR7_MAJOR       (IDR7_MAJOR_MASK << IDR7_MAJOR_SHIFT)
+
+/* Stream to Context Register: S2CR */
+#define S2CR_CBNDX        (S2CR_CBNDX_MASK         << S2cR_CBNDX_SHIFT)
+#define S2CR_SHCFG        (S2CR_SHCFG_MASK         << s2CR_SHCFG_SHIFT)
+#define S2CR_MTCFG        (S2CR_MTCFG_MASK         << S2CR_MTCFG_SHIFT)
+#define S2CR_MEMATTR      (S2CR_MEMATTR_MASK       << S2CR_MEMATTR_SHIFT)
+#define S2CR_TYPE         (S2CR_TYPE_MASK          << S2CR_TYPE_SHIFT)
+#define S2CR_NSCFG        (S2CR_NSCFG_MASK         << S2CR_NSCFG_SHIFT)
+#define S2CR_RACFG        (S2CR_RACFG_MASK         << S2CR_RACFG_SHIFT)
+#define S2CR_WACFG        (S2CR_WACFG_MASK         << S2CR_WACFG_SHIFT)
+#define S2CR_PRIVCFG      (S2CR_PRIVCFG_MASK       << S2CR_PRIVCFG_SHIFT)
+#define S2CR_INSTCFG      (S2CR_INSTCFG_MASK       << S2CR_INSTCFG_SHIFT)
+#define S2CR_TRANSIENTCFG (S2CR_TRANSIENTCFG_MASK  << S2CR_TRANSIENTCFG_SHIFT)
+#define S2CR_VMID         (S2CR_VMID_MASK          << S2CR_VMID_SHIFT)
+#define S2CR_BSU          (S2CR_BSU_MASK           << S2CR_BSU_SHIFT)
+#define S2CR_FB           (S2CR_FB_MASK            << S2CR_FB_SHIFT)
+
+/* Stream Match Register: SMR */
+#define SMR_ID            (SMR_ID_MASK    << SMR_ID_SHIFT)
+#define SMR_MASK          (SMR_MASK_MASK  << SMR_MASK_SHIFT)
+#define SMR_VALID         (SMR_VALID_MASK << SMR_VALID_SHIFT)
+
+/* Global TLB Status: TLBGSTATUS */
+#define TLBGSTATUS_GSACTIVE (TLBGSTATUS_GSACTIVE_MASK << \
+					TLBGSTATUS_GSACTIVE_SHIFT)
+/* Invalidate Hyp TLB by VA: TLBIVAH */
+#define TLBIVAH_ADDR  (TLBIVAH_ADDR_MASK << TLBIVAH_ADDR_SHIFT)
+
+/* Invalidate TLB by VMID: TLBIVMID */
+#define TLBIVMID_VMID (TLBIVMID_VMID_MASK << TLBIVMID_VMID_SHIFT)
+
+/* Context Bank Attribute Register: CBAR */
+#define CBAR_VMID       (CBAR_VMID_MASK    << CBAR_VMID_SHIFT)
+#define CBAR_CBNDX      (CBAR_CBNDX_MASK   << CBAR_CBNDX_SHIFT)
+#define CBAR_BPSHCFG    (CBAR_BPSHCFG_MASK << CBAR_BPSHCFG_SHIFT)
+#define CBAR_HYPC       (CBAR_HYPC_MASK    << CBAR_HYPC_SHIFT)
+#define CBAR_FB         (CBAR_FB_MASK      << CBAR_FB_SHIFT)
+#define CBAR_MEMATTR    (CBAR_MEMATTR_MASK << CBAR_MEMATTR_SHIFT)
+#define CBAR_TYPE       (CBAR_TYPE_MASK    << CBAR_TYPE_SHIFT)
+#define CBAR_BSU        (CBAR_BSU_MASK     << CBAR_BSU_SHIFT)
+#define CBAR_RACFG      (CBAR_RACFG_MASK   << CBAR_RACFG_SHIFT)
+#define CBAR_WACFG      (CBAR_WACFG_MASK   << CBAR_WACFG_SHIFT)
+#define CBAR_IRPTNDX    (CBAR_IRPTNDX_MASK << CBAR_IRPTNDX_SHIFT)
+
+/* Context Bank Fault Restricted Syndrome Register A: CBFRSYNRA */
+#define CBFRSYNRA_SID   (CBFRSYNRA_SID_MASK << CBFRSYNRA_SID_SHIFT)
+
+/* Performance Monitoring Register Fields */
+
+/* Stage 1 Context Bank Format Fields */
+/* Auxiliary Control Register: CB_ACTLR */
+#define CB_ACTLR_REQPRIORITY \
+		(CB_ACTLR_REQPRIORITY_MASK << CB_ACTLR_REQPRIORITY_SHIFT)
+#define CB_ACTLR_REQPRIORITYCFG \
+		(CB_ACTLR_REQPRIORITYCFG_MASK << CB_ACTLR_REQPRIORITYCFG_SHIFT)
+#define CB_ACTLR_PRIVCFG (CB_ACTLR_PRIVCFG_MASK << CB_ACTLR_PRIVCFG_SHIFT)
+#define CB_ACTLR_BPRCOSH (CB_ACTLR_BPRCOSH_MASK << CB_ACTLR_BPRCOSH_SHIFT)
+#define CB_ACTLR_BPRCISH (CB_ACTLR_BPRCISH_MASK << CB_ACTLR_BPRCISH_SHIFT)
+#define CB_ACTLR_BPRCNSH (CB_ACTLR_BPRCNSH_MASK << CB_ACTLR_BPRCNSH_SHIFT)
+
+/* Address Translation, Stage 1, Privileged Read: CB_ATS1PR */
+#define CB_ATS1PR_ADDR  (CB_ATS1PR_ADDR_MASK << CB_ATS1PR_ADDR_SHIFT)
+
+/* Address Translation, Stage 1, Privileged Write: CB_ATS1PW */
+#define CB_ATS1PW_ADDR  (CB_ATS1PW_ADDR_MASK << CB_ATS1PW_ADDR_SHIFT)
+
+/* Address Translation, Stage 1, User Read: CB_ATS1UR */
+#define CB_ATS1UR_ADDR  (CB_ATS1UR_ADDR_MASK << CB_ATS1UR_ADDR_SHIFT)
+
+/* Address Translation, Stage 1, User Write: CB_ATS1UW */
+#define CB_ATS1UW_ADDR  (CB_ATS1UW_ADDR_MASK << CB_ATS1UW_ADDR_SHIFT)
+
+/* Address Translation Status Register: CB_ATSR */
+#define CB_ATSR_ACTIVE  (CB_ATSR_ACTIVE_MASK << CB_ATSR_ACTIVE_SHIFT)
+
+/* Context ID Register: CB_CONTEXTIDR */
+#define CB_CONTEXTIDR_ASID    (CB_CONTEXTIDR_ASID_MASK << \
+				CB_CONTEXTIDR_ASID_SHIFT)
+#define CB_CONTEXTIDR_PROCID  (CB_CONTEXTIDR_PROCID_MASK << \
+				CB_CONTEXTIDR_PROCID_SHIFT)
+
+/* Fault Address Register: CB_FAR */
+#define CB_FAR_FADDR  (CB_FAR_FADDR_MASK << CB_FAR_FADDR_SHIFT)
+
+/* Fault Status Register: CB_FSR */
+#define CB_FSR_TF     (CB_FSR_TF_MASK     << CB_FSR_TF_SHIFT)
+#define CB_FSR_AFF    (CB_FSR_AFF_MASK    << CB_FSR_AFF_SHIFT)
+#define CB_FSR_PF     (CB_FSR_PF_MASK     << CB_FSR_PF_SHIFT)
+#define CB_FSR_EF     (CB_FSR_EF_MASK     << CB_FSR_EF_SHIFT)
+#define CB_FSR_TLBMCF (CB_FSR_TLBMCF_MASK << CB_FSR_TLBMCF_SHIFT)
+#define CB_FSR_TLBLKF (CB_FSR_TLBLKF_MASK << CB_FSR_TLBLKF_SHIFT)
+#define CB_FSR_SS     (CB_FSR_SS_MASK     << CB_FSR_SS_SHIFT)
+#define CB_FSR_MULTI  (CB_FSR_MULTI_MASK  << CB_FSR_MULTI_SHIFT)
+
+/* Fault Syndrome Register 0: CB_FSYNR0 */
+#define CB_FSYNR0_PLVL     (CB_FSYNR0_PLVL_MASK    << CB_FSYNR0_PLVL_SHIFT)
+#define CB_FSYNR0_S1PTWF   (CB_FSYNR0_S1PTWF_MASK  << CB_FSYNR0_S1PTWF_SHIFT)
+#define CB_FSYNR0_WNR      (CB_FSYNR0_WNR_MASK     << CB_FSYNR0_WNR_SHIFT)
+#define CB_FSYNR0_PNU      (CB_FSYNR0_PNU_MASK     << CB_FSYNR0_PNU_SHIFT)
+#define CB_FSYNR0_IND      (CB_FSYNR0_IND_MASK     << CB_FSYNR0_IND_SHIFT)
+#define CB_FSYNR0_NSSTATE  (CB_FSYNR0_NSSTATE_MASK << CB_FSYNR0_NSSTATE_SHIFT)
+#define CB_FSYNR0_NSATTR   (CB_FSYNR0_NSATTR_MASK  << CB_FSYNR0_NSATTR_SHIFT)
+#define CB_FSYNR0_ATOF     (CB_FSYNR0_ATOF_MASK    << CB_FSYNR0_ATOF_SHIFT)
+#define CB_FSYNR0_PTWF     (CB_FSYNR0_PTWF_MASK    << CB_FSYNR0_PTWF_SHIFT)
+#define CB_FSYNR0_AFR      (CB_FSYNR0_AFR_MASK     << CB_FSYNR0_AFR_SHIFT)
+#define CB_FSYNR0_S1CBNDX  (CB_FSYNR0_S1CBNDX_MASK << CB_FSYNR0_S1CBNDX_SHIFT)
+
+/* Normal Memory Remap Register: CB_NMRR */
+#define CB_NMRR_IR0        (CB_NMRR_IR0_MASK   << CB_NMRR_IR0_SHIFT)
+#define CB_NMRR_IR1        (CB_NMRR_IR1_MASK   << CB_NMRR_IR1_SHIFT)
+#define CB_NMRR_IR2        (CB_NMRR_IR2_MASK   << CB_NMRR_IR2_SHIFT)
+#define CB_NMRR_IR3        (CB_NMRR_IR3_MASK   << CB_NMRR_IR3_SHIFT)
+#define CB_NMRR_IR4        (CB_NMRR_IR4_MASK   << CB_NMRR_IR4_SHIFT)
+#define CB_NMRR_IR5        (CB_NMRR_IR5_MASK   << CB_NMRR_IR5_SHIFT)
+#define CB_NMRR_IR6        (CB_NMRR_IR6_MASK   << CB_NMRR_IR6_SHIFT)
+#define CB_NMRR_IR7        (CB_NMRR_IR7_MASK   << CB_NMRR_IR7_SHIFT)
+#define CB_NMRR_OR0        (CB_NMRR_OR0_MASK   << CB_NMRR_OR0_SHIFT)
+#define CB_NMRR_OR1        (CB_NMRR_OR1_MASK   << CB_NMRR_OR1_SHIFT)
+#define CB_NMRR_OR2        (CB_NMRR_OR2_MASK   << CB_NMRR_OR2_SHIFT)
+#define CB_NMRR_OR3        (CB_NMRR_OR3_MASK   << CB_NMRR_OR3_SHIFT)
+#define CB_NMRR_OR4        (CB_NMRR_OR4_MASK   << CB_NMRR_OR4_SHIFT)
+#define CB_NMRR_OR5        (CB_NMRR_OR5_MASK   << CB_NMRR_OR5_SHIFT)
+#define CB_NMRR_OR6        (CB_NMRR_OR6_MASK   << CB_NMRR_OR6_SHIFT)
+#define CB_NMRR_OR7        (CB_NMRR_OR7_MASK   << CB_NMRR_OR7_SHIFT)
+
+/* Physical Address Register: CB_PAR */
+#define CB_PAR_F           (CB_PAR_F_MASK      << CB_PAR_F_SHIFT)
+#define CB_PAR_SS          (CB_PAR_SS_MASK     << CB_PAR_SS_SHIFT)
+#define CB_PAR_OUTER       (CB_PAR_OUTER_MASK  << CB_PAR_OUTER_SHIFT)
+#define CB_PAR_INNER       (CB_PAR_INNER_MASK  << CB_PAR_INNER_SHIFT)
+#define CB_PAR_SH          (CB_PAR_SH_MASK     << CB_PAR_SH_SHIFT)
+#define CB_PAR_NS          (CB_PAR_NS_MASK     << CB_PAR_NS_SHIFT)
+#define CB_PAR_NOS         (CB_PAR_NOS_MASK    << CB_PAR_NOS_SHIFT)
+#define CB_PAR_PA          (CB_PAR_PA_MASK     << CB_PAR_PA_SHIFT)
+#define CB_PAR_TF          (CB_PAR_TF_MASK     << CB_PAR_TF_SHIFT)
+#define CB_PAR_AFF         (CB_PAR_AFF_MASK    << CB_PAR_AFF_SHIFT)
+#define CB_PAR_PF          (CB_PAR_PF_MASK     << CB_PAR_PF_SHIFT)
+#define CB_PAR_TLBMCF      (CB_PAR_TLBMCF_MASK << CB_PAR_TLBMCF_SHIFT)
+#define CB_PAR_TLBLKF      (CB_PAR_TLBLKF_MASK << CB_PAR_TLBLKF_SHIFT)
+#define CB_PAR_ATOT        (CB_PAR_ATOT_MASK   << CB_PAR_ATOT_SHIFT)
+#define CB_PAR_PLVL        (CB_PAR_PLVL_MASK   << CB_PAR_PLVL_SHIFT)
+#define CB_PAR_STAGE       (CB_PAR_STAGE_MASK  << CB_PAR_STAGE_SHIFT)
+
+/* Primary Region Remap Register: CB_PRRR */
+#define CB_PRRR_TR0        (CB_PRRR_TR0_MASK   << CB_PRRR_TR0_SHIFT)
+#define CB_PRRR_TR1        (CB_PRRR_TR1_MASK   << CB_PRRR_TR1_SHIFT)
+#define CB_PRRR_TR2        (CB_PRRR_TR2_MASK   << CB_PRRR_TR2_SHIFT)
+#define CB_PRRR_TR3        (CB_PRRR_TR3_MASK   << CB_PRRR_TR3_SHIFT)
+#define CB_PRRR_TR4        (CB_PRRR_TR4_MASK   << CB_PRRR_TR4_SHIFT)
+#define CB_PRRR_TR5        (CB_PRRR_TR5_MASK   << CB_PRRR_TR5_SHIFT)
+#define CB_PRRR_TR6        (CB_PRRR_TR6_MASK   << CB_PRRR_TR6_SHIFT)
+#define CB_PRRR_TR7        (CB_PRRR_TR7_MASK   << CB_PRRR_TR7_SHIFT)
+#define CB_PRRR_DS0        (CB_PRRR_DS0_MASK   << CB_PRRR_DS0_SHIFT)
+#define CB_PRRR_DS1        (CB_PRRR_DS1_MASK   << CB_PRRR_DS1_SHIFT)
+#define CB_PRRR_NS0        (CB_PRRR_NS0_MASK   << CB_PRRR_NS0_SHIFT)
+#define CB_PRRR_NS1        (CB_PRRR_NS1_MASK   << CB_PRRR_NS1_SHIFT)
+#define CB_PRRR_NOS0       (CB_PRRR_NOS0_MASK  << CB_PRRR_NOS0_SHIFT)
+#define CB_PRRR_NOS1       (CB_PRRR_NOS1_MASK  << CB_PRRR_NOS1_SHIFT)
+#define CB_PRRR_NOS2       (CB_PRRR_NOS2_MASK  << CB_PRRR_NOS2_SHIFT)
+#define CB_PRRR_NOS3       (CB_PRRR_NOS3_MASK  << CB_PRRR_NOS3_SHIFT)
+#define CB_PRRR_NOS4       (CB_PRRR_NOS4_MASK  << CB_PRRR_NOS4_SHIFT)
+#define CB_PRRR_NOS5       (CB_PRRR_NOS5_MASK  << CB_PRRR_NOS5_SHIFT)
+#define CB_PRRR_NOS6       (CB_PRRR_NOS6_MASK  << CB_PRRR_NOS6_SHIFT)
+#define CB_PRRR_NOS7       (CB_PRRR_NOS7_MASK  << CB_PRRR_NOS7_SHIFT)
+
+/* Transaction Resume: CB_RESUME */
+#define CB_RESUME_TNR      (CB_RESUME_TNR_MASK << CB_RESUME_TNR_SHIFT)
+
+/* System Control Register: CB_SCTLR */
+#define CB_SCTLR_M           (CB_SCTLR_M_MASK       << CB_SCTLR_M_SHIFT)
+#define CB_SCTLR_TRE         (CB_SCTLR_TRE_MASK     << CB_SCTLR_TRE_SHIFT)
+#define CB_SCTLR_AFE         (CB_SCTLR_AFE_MASK     << CB_SCTLR_AFE_SHIFT)
+#define CB_SCTLR_AFFD        (CB_SCTLR_AFFD_MASK    << CB_SCTLR_AFFD_SHIFT)
+#define CB_SCTLR_E           (CB_SCTLR_E_MASK       << CB_SCTLR_E_SHIFT)
+#define CB_SCTLR_CFRE        (CB_SCTLR_CFRE_MASK    << CB_SCTLR_CFRE_SHIFT)
+#define CB_SCTLR_CFIE        (CB_SCTLR_CFIE_MASK    << CB_SCTLR_CFIE_SHIFT)
+#define CB_SCTLR_CFCFG       (CB_SCTLR_CFCFG_MASK   << CB_SCTLR_CFCFG_SHIFT)
+#define CB_SCTLR_HUPCF       (CB_SCTLR_HUPCF_MASK   << CB_SCTLR_HUPCF_SHIFT)
+#define CB_SCTLR_WXN         (CB_SCTLR_WXN_MASK     << CB_SCTLR_WXN_SHIFT)
+#define CB_SCTLR_UWXN        (CB_SCTLR_UWXN_MASK    << CB_SCTLR_UWXN_SHIFT)
+#define CB_SCTLR_ASIDPNE     (CB_SCTLR_ASIDPNE_MASK << CB_SCTLR_ASIDPNE_SHIFT)
+#define CB_SCTLR_TRANSIENTCFG (CB_SCTLR_TRANSIENTCFG_MASK << \
+						CB_SCTLR_TRANSIENTCFG_SHIFT)
+#define CB_SCTLR_MEMATTR     (CB_SCTLR_MEMATTR_MASK << CB_SCTLR_MEMATTR_SHIFT)
+#define CB_SCTLR_MTCFG       (CB_SCTLR_MTCFG_MASK   << CB_SCTLR_MTCFG_SHIFT)
+#define CB_SCTLR_SHCFG       (CB_SCTLR_SHCFG_MASK   << CB_SCTLR_SHCFG_SHIFT)
+#define CB_SCTLR_RACFG       (CB_SCTLR_RACFG_MASK   << CB_SCTLR_RACFG_SHIFT)
+#define CB_SCTLR_WACFG       (CB_SCTLR_WACFG_MASK   << CB_SCTLR_WACFG_SHIFT)
+#define CB_SCTLR_NSCFG       (CB_SCTLR_NSCFG_MASK   << CB_SCTLR_NSCFG_SHIFT)
+
+/* Invalidate TLB by ASID: CB_TLBIASID */
+#define CB_TLBIASID_ASID     (CB_TLBIASID_ASID_MASK << CB_TLBIASID_ASID_SHIFT)
+
+/* Invalidate TLB by VA: CB_TLBIVA */
+#define CB_TLBIVA_ASID       (CB_TLBIVA_ASID_MASK   << CB_TLBIVA_ASID_SHIFT)
+#define CB_TLBIVA_VA         (CB_TLBIVA_VA_MASK     << CB_TLBIVA_VA_SHIFT)
+
+/* Invalidate TLB by VA, All ASID: CB_TLBIVAA */
+#define CB_TLBIVAA_VA        (CB_TLBIVAA_VA_MASK    << CB_TLBIVAA_VA_SHIFT)
+
+/* Invalidate TLB by VA, All ASID, Last Level: CB_TLBIVAAL */
+#define CB_TLBIVAAL_VA       (CB_TLBIVAAL_VA_MASK   << CB_TLBIVAAL_VA_SHIFT)
+
+/* Invalidate TLB by VA, Last Level: CB_TLBIVAL */
+#define CB_TLBIVAL_ASID      (CB_TLBIVAL_ASID_MASK  << CB_TLBIVAL_ASID_SHIFT)
+#define CB_TLBIVAL_VA        (CB_TLBIVAL_VA_MASK    << CB_TLBIVAL_VA_SHIFT)
+
+/* TLB Status: CB_TLBSTATUS */
+#define CB_TLBSTATUS_SACTIVE (CB_TLBSTATUS_SACTIVE_MASK << \
+						CB_TLBSTATUS_SACTIVE_SHIFT)
+
+/* Translation Table Base Control Register: CB_TTBCR */
+#define CB_TTBCR_T0SZ        (CB_TTBCR_T0SZ_MASK    << CB_TTBCR_T0SZ_SHIFT)
+#define CB_TTBCR_PD0         (CB_TTBCR_PD0_MASK     << CB_TTBCR_PD0_SHIFT)
+#define CB_TTBCR_PD1         (CB_TTBCR_PD1_MASK     << CB_TTBCR_PD1_SHIFT)
+#define CB_TTBCR_NSCFG0      (CB_TTBCR_NSCFG0_MASK  << CB_TTBCR_NSCFG0_SHIFT)
+#define CB_TTBCR_NSCFG1      (CB_TTBCR_NSCFG1_MASK  << CB_TTBCR_NSCFG1_SHIFT)
+#define CB_TTBCR_EAE         (CB_TTBCR_EAE_MASK     << CB_TTBCR_EAE_SHIFT)
+
+/* Translation Table Base Register 0: CB_TTBR0 */
+#define CB_TTBR0_IRGN1       (CB_TTBR0_IRGN1_MASK   << CB_TTBR0_IRGN1_SHIFT)
+#define CB_TTBR0_S           (CB_TTBR0_S_MASK       << CB_TTBR0_S_SHIFT)
+#define CB_TTBR0_RGN         (CB_TTBR0_RGN_MASK     << CB_TTBR0_RGN_SHIFT)
+#define CB_TTBR0_NOS         (CB_TTBR0_NOS_MASK     << CB_TTBR0_NOS_SHIFT)
+#define CB_TTBR0_IRGN0       (CB_TTBR0_IRGN0_MASK   << CB_TTBR0_IRGN0_SHIFT)
+#define CB_TTBR0_ADDR        (CB_TTBR0_ADDR_MASK    << CB_TTBR0_ADDR_SHIFT)
+
+/* Translation Table Base Register 1: CB_TTBR1 */
+#define CB_TTBR1_IRGN1       (CB_TTBR1_IRGN1_MASK   << CB_TTBR1_IRGN1_SHIFT)
+#define CB_TTBR1_S           (CB_TTBR1_S_MASK       << CB_TTBR1_S_SHIFT)
+#define CB_TTBR1_RGN         (CB_TTBR1_RGN_MASK     << CB_TTBR1_RGN_SHIFT)
+#define CB_TTBR1_NOS         (CB_TTBR1_NOS_MASK     << CB_TTBR1_NOS_SHIFT)
+#define CB_TTBR1_IRGN0       (CB_TTBR1_IRGN0_MASK   << CB_TTBR1_IRGN0_SHIFT)
+#define CB_TTBR1_ADDR        (CB_TTBR1_ADDR_MASK    << CB_TTBR1_ADDR_SHIFT)
+
+/* Global Register Masks */
+/* Configuration Register 0 */
+#define CR0_NSCFG_MASK          0x03
+#define CR0_WACFG_MASK          0x03
+#define CR0_RACFG_MASK          0x03
+#define CR0_SHCFG_MASK          0x03
+#define CR0_SMCFCFG_MASK        0x01
+#define CR0_MTCFG_MASK          0x01
+#define CR0_MEMATTR_MASK        0x0F
+#define CR0_BSU_MASK            0x03
+#define CR0_FB_MASK             0x01
+#define CR0_PTM_MASK            0x01
+#define CR0_VMIDPNE_MASK        0x01
+#define CR0_USFCFG_MASK         0x01
+#define CR0_GSE_MASK            0x01
+#define CR0_STALLD_MASK         0x01
+#define CR0_TRANSIENTCFG_MASK   0x03
+#define CR0_GCFGFIE_MASK        0x01
+#define CR0_GCFGFRE_MASK        0x01
+#define CR0_GFIE_MASK           0x01
+#define CR0_GFRE_MASK           0x01
+#define CR0_CLIENTPD_MASK       0x01
+
+/* Configuration Register 2 */
+#define CR2_BPVMID_MASK         0xFF
+
+/* Global Address Translation, Stage 1, Privileged Read: GATS1PR */
+#define GATS1PR_ADDR_MASK       0xFFFFF
+#define GATS1PR_NDX_MASK        0xFF
+
+/* Global Address Translation, Stage 1, Privileged Write: GATS1PW */
+#define GATS1PW_ADDR_MASK       0xFFFFF
+#define GATS1PW_NDX_MASK        0xFF
+
+/* Global Address Translation, Stage 1, User Read: GATS1UR */
+#define GATS1UR_ADDR_MASK       0xFFFFF
+#define GATS1UR_NDX_MASK        0xFF
+
+/* Global Address Translation, Stage 1, User Write: GATS1UW */
+#define GATS1UW_ADDR_MASK       0xFFFFF
+#define GATS1UW_NDX_MASK        0xFF
+
+/* Global Address Translation, Stage 1 and 2, Privileged Read: GATS1PR */
+#define GATS12PR_ADDR_MASK      0xFFFFF
+#define GATS12PR_NDX_MASK       0xFF
+
+/* Global Address Translation, Stage 1 and 2, Privileged Write: GATS1PW */
+#define GATS12PW_ADDR_MASK      0xFFFFF
+#define GATS12PW_NDX_MASK       0xFF
+
+/* Global Address Translation, Stage 1 and 2, User Read: GATS1UR */
+#define GATS12UR_ADDR_MASK      0xFFFFF
+#define GATS12UR_NDX_MASK       0xFF
+
+/* Global Address Translation, Stage 1 and 2, User Write: GATS1UW */
+#define GATS12UW_ADDR_MASK      0xFFFFF
+#define GATS12UW_NDX_MASK       0xFF
+
+/* Global Address Translation Status Register: GATSR */
+#define GATSR_ACTIVE_MASK       0x01
+
+/* Global Fault Address Register: GFAR */
+#define GFAR_FADDR_MASK         0xFFFFFFFF
+
+/* Global Fault Status Register: GFSR */
+#define GFSR_ICF_MASK           0x01
+#define GFSR_USF_MASK           0x01
+#define GFSR_SMCF_MASK          0x01
+#define GFSR_UCBF_MASK          0x01
+#define GFSR_UCIF_MASK          0x01
+#define GFSR_CAF_MASK           0x01
+#define GFSR_EF_MASK            0x01
+#define GFSR_PF_MASK            0x01
+#define GFSR_MULTI_MASK         0x01
+
+/* Global Fault Syndrome Register 0: GFSYNR0 */
+#define GFSYNR0_NESTED_MASK     0x01
+#define GFSYNR0_WNR_MASK        0x01
+#define GFSYNR0_PNU_MASK        0x01
+#define GFSYNR0_IND_MASK        0x01
+#define GFSYNR0_NSSTATE_MASK    0x01
+#define GFSYNR0_NSATTR_MASK     0x01
+
+/* Global Fault Syndrome Register 1: GFSYNR1 */
+#define GFSYNR1_SID_MASK        0x7FFF
+#define GFSYNr1_SSD_IDX_MASK    0x7FFF
+
+/* Global Physical Address Register: GPAR */
+#define GPAR_F_MASK             0x01
+#define GPAR_SS_MASK            0x01
+#define GPAR_OUTER_MASK         0x03
+#define GPAR_INNER_MASK         0x03
+#define GPAR_SH_MASK            0x01
+#define GPAR_NS_MASK            0x01
+#define GPAR_NOS_MASK           0x01
+#define GPAR_PA_MASK            0xFFFFF
+#define GPAR_TF_MASK            0x01
+#define GPAR_AFF_MASK           0x01
+#define GPAR_PF_MASK            0x01
+#define GPAR_EF_MASK            0x01
+#define GPAR_TLBMCF_MASK        0x01
+#define GPAR_TLBLKF_MASK        0x01
+#define GPAR_UCBF_MASK          0x01
+
+/* Identification Register: IDR0 */
+#define IDR0_NUMSMRG_MASK       0xFF
+#define IDR0_NUMSIDB_MASK       0x0F
+#define IDR0_BTM_MASK           0x01
+#define IDR0_CTTW_MASK          0x01
+#define IDR0_NUMIPRT_MASK       0xFF
+#define IDR0_PTFS_MASK          0x01
+#define IDR0_SMS_MASK           0x01
+#define IDR0_NTS_MASK           0x01
+#define IDR0_S2TS_MASK          0x01
+#define IDR0_S1TS_MASK          0x01
+#define IDR0_SES_MASK           0x01
+
+/* Identification Register: IDR1 */
+#define IDR1_NUMCB_MASK         0xFF
+#define IDR1_NUMSSDNDXB_MASK    0x0F
+#define IDR1_SSDTP_MASK         0x01
+#define IDR1_SMCD_MASK          0x01
+#define IDR1_NUMS2CB_MASK       0xFF
+#define IDR1_NUMPAGENDXB_MASK   0x07
+#define IDR1_PAGESIZE_MASK      0x01
+
+/* Identification Register: IDR2 */
+#define IDR2_IAS_MASK           0x0F
+#define IDR2_OAS_MASK           0x0F
+
+/* Identification Register: IDR7 */
+#define IDR7_MINOR_MASK         0x0F
+#define IDR7_MAJOR_MASK         0x0F
+
+/* Stream to Context Register: S2CR */
+#define S2CR_CBNDX_MASK         0xFF
+#define S2CR_SHCFG_MASK         0x03
+#define S2CR_MTCFG_MASK         0x01
+#define S2CR_MEMATTR_MASK       0x0F
+#define S2CR_TYPE_MASK          0x03
+#define S2CR_NSCFG_MASK         0x03
+#define S2CR_RACFG_MASK         0x03
+#define S2CR_WACFG_MASK         0x03
+#define S2CR_PRIVCFG_MASK       0x03
+#define S2CR_INSTCFG_MASK       0x03
+#define S2CR_TRANSIENTCFG_MASK  0x03
+#define S2CR_VMID_MASK          0xFF
+#define S2CR_BSU_MASK           0x03
+#define S2CR_FB_MASK            0x01
+
+/* Stream Match Register: SMR */
+#define SMR_ID_MASK             0x7FFF
+#define SMR_MASK_MASK           0x7FFF
+#define SMR_VALID_MASK          0x01
+
+/* Global TLB Status: TLBGSTATUS */
+#define TLBGSTATUS_GSACTIVE_MASK 0x01
+
+/* Invalidate Hyp TLB by VA: TLBIVAH */
+#define TLBIVAH_ADDR_MASK       0xFFFFF
+
+/* Invalidate TLB by VMID: TLBIVMID */
+#define TLBIVMID_VMID_MASK      0xFF
+
+/* Global Register Space 1 Mask */
+/* Context Bank Attribute Register: CBAR */
+#define CBAR_VMID_MASK          0xFF
+#define CBAR_CBNDX_MASK         0x03
+#define CBAR_BPSHCFG_MASK       0x03
+#define CBAR_HYPC_MASK          0x01
+#define CBAR_FB_MASK            0x01
+#define CBAR_MEMATTR_MASK       0x0F
+#define CBAR_TYPE_MASK          0x03
+#define CBAR_BSU_MASK           0x03
+#define CBAR_RACFG_MASK         0x03
+#define CBAR_WACFG_MASK         0x03
+#define CBAR_IRPTNDX_MASK       0xFF
+
+/* Context Bank Fault Restricted Syndrome Register A: CBFRSYNRA */
+#define CBFRSYNRA_SID_MASK      0x7FFF
+
+/* Stage 1 Context Bank Format Masks */
+/* Auxiliary Control Register: CB_ACTLR */
+#define CB_ACTLR_REQPRIORITY_MASK    0x3
+#define CB_ACTLR_REQPRIORITYCFG_MASK 0x1
+#define CB_ACTLR_PRIVCFG_MASK        0x3
+#define CB_ACTLR_BPRCOSH_MASK        0x1
+#define CB_ACTLR_BPRCISH_MASK        0x1
+#define CB_ACTLR_BPRCNSH_MASK        0x1
+
+/* Address Translation, Stage 1, Privileged Read: CB_ATS1PR */
+#define CB_ATS1PR_ADDR_MASK     0xFFFFF
+
+/* Address Translation, Stage 1, Privileged Write: CB_ATS1PW */
+#define CB_ATS1PW_ADDR_MASK     0xFFFFF
+
+/* Address Translation, Stage 1, User Read: CB_ATS1UR */
+#define CB_ATS1UR_ADDR_MASK     0xFFFFF
+
+/* Address Translation, Stage 1, User Write: CB_ATS1UW */
+#define CB_ATS1UW_ADDR_MASK     0xFFFFF
+
+/* Address Translation Status Register: CB_ATSR */
+#define CB_ATSR_ACTIVE_MASK     0x01
+
+/* Context ID Register: CB_CONTEXTIDR */
+#define CB_CONTEXTIDR_ASID_MASK   0xFF
+#define CB_CONTEXTIDR_PROCID_MASK 0xFFFFFF
+
+/* Fault Address Register: CB_FAR */
+#define CB_FAR_FADDR_MASK       0xFFFFFFFF
+
+/* Fault Status Register: CB_FSR */
+#define CB_FSR_TF_MASK          0x01
+#define CB_FSR_AFF_MASK         0x01
+#define CB_FSR_PF_MASK          0x01
+#define CB_FSR_EF_MASK          0x01
+#define CB_FSR_TLBMCF_MASK      0x01
+#define CB_FSR_TLBLKF_MASK      0x01
+#define CB_FSR_SS_MASK          0x01
+#define CB_FSR_MULTI_MASK       0x01
+
+/* Fault Syndrome Register 0: CB_FSYNR0 */
+#define CB_FSYNR0_PLVL_MASK     0x03
+#define CB_FSYNR0_S1PTWF_MASK   0x01
+#define CB_FSYNR0_WNR_MASK      0x01
+#define CB_FSYNR0_PNU_MASK      0x01
+#define CB_FSYNR0_IND_MASK      0x01
+#define CB_FSYNR0_NSSTATE_MASK  0x01
+#define CB_FSYNR0_NSATTR_MASK   0x01
+#define CB_FSYNR0_ATOF_MASK     0x01
+#define CB_FSYNR0_PTWF_MASK     0x01
+#define CB_FSYNR0_AFR_MASK      0x01
+#define CB_FSYNR0_S1CBNDX_MASK  0xFF
+
+/* Normal Memory Remap Register: CB_NMRR */
+#define CB_NMRR_IR0_MASK        0x03
+#define CB_NMRR_IR1_MASK        0x03
+#define CB_NMRR_IR2_MASK        0x03
+#define CB_NMRR_IR3_MASK        0x03
+#define CB_NMRR_IR4_MASK        0x03
+#define CB_NMRR_IR5_MASK        0x03
+#define CB_NMRR_IR6_MASK        0x03
+#define CB_NMRR_IR7_MASK        0x03
+#define CB_NMRR_OR0_MASK        0x03
+#define CB_NMRR_OR1_MASK        0x03
+#define CB_NMRR_OR2_MASK        0x03
+#define CB_NMRR_OR3_MASK        0x03
+#define CB_NMRR_OR4_MASK        0x03
+#define CB_NMRR_OR5_MASK        0x03
+#define CB_NMRR_OR6_MASK        0x03
+#define CB_NMRR_OR7_MASK        0x03
+
+/* Physical Address Register: CB_PAR */
+#define CB_PAR_F_MASK           0x01
+#define CB_PAR_SS_MASK          0x01
+#define CB_PAR_OUTER_MASK       0x03
+#define CB_PAR_INNER_MASK       0x07
+#define CB_PAR_SH_MASK          0x01
+#define CB_PAR_NS_MASK          0x01
+#define CB_PAR_NOS_MASK         0x01
+#define CB_PAR_PA_MASK          0xFFFFF
+#define CB_PAR_TF_MASK          0x01
+#define CB_PAR_AFF_MASK         0x01
+#define CB_PAR_PF_MASK          0x01
+#define CB_PAR_TLBMCF_MASK      0x01
+#define CB_PAR_TLBLKF_MASK      0x01
+#define CB_PAR_ATOT_MASK        0x01
+#define CB_PAR_PLVL_MASK        0x03
+#define CB_PAR_STAGE_MASK       0x01
+
+/* Primary Region Remap Register: CB_PRRR */
+#define CB_PRRR_TR0_MASK        0x03
+#define CB_PRRR_TR1_MASK        0x03
+#define CB_PRRR_TR2_MASK        0x03
+#define CB_PRRR_TR3_MASK        0x03
+#define CB_PRRR_TR4_MASK        0x03
+#define CB_PRRR_TR5_MASK        0x03
+#define CB_PRRR_TR6_MASK        0x03
+#define CB_PRRR_TR7_MASK        0x03
+#define CB_PRRR_DS0_MASK        0x01
+#define CB_PRRR_DS1_MASK        0x01
+#define CB_PRRR_NS0_MASK        0x01
+#define CB_PRRR_NS1_MASK        0x01
+#define CB_PRRR_NOS0_MASK       0x01
+#define CB_PRRR_NOS1_MASK       0x01
+#define CB_PRRR_NOS2_MASK       0x01
+#define CB_PRRR_NOS3_MASK       0x01
+#define CB_PRRR_NOS4_MASK       0x01
+#define CB_PRRR_NOS5_MASK       0x01
+#define CB_PRRR_NOS6_MASK       0x01
+#define CB_PRRR_NOS7_MASK       0x01
+
+/* Transaction Resume: CB_RESUME */
+#define CB_RESUME_TNR_MASK      0x01
+
+/* System Control Register: CB_SCTLR */
+#define CB_SCTLR_M_MASK            0x01
+#define CB_SCTLR_TRE_MASK          0x01
+#define CB_SCTLR_AFE_MASK          0x01
+#define CB_SCTLR_AFFD_MASK         0x01
+#define CB_SCTLR_E_MASK            0x01
+#define CB_SCTLR_CFRE_MASK         0x01
+#define CB_SCTLR_CFIE_MASK         0x01
+#define CB_SCTLR_CFCFG_MASK        0x01
+#define CB_SCTLR_HUPCF_MASK        0x01
+#define CB_SCTLR_WXN_MASK          0x01
+#define CB_SCTLR_UWXN_MASK         0x01
+#define CB_SCTLR_ASIDPNE_MASK      0x01
+#define CB_SCTLR_TRANSIENTCFG_MASK 0x03
+#define CB_SCTLR_MEMATTR_MASK      0x0F
+#define CB_SCTLR_MTCFG_MASK        0x01
+#define CB_SCTLR_SHCFG_MASK        0x03
+#define CB_SCTLR_RACFG_MASK        0x03
+#define CB_SCTLR_WACFG_MASK        0x03
+#define CB_SCTLR_NSCFG_MASK        0x03
+
+/* Invalidate TLB by ASID: CB_TLBIASID */
+#define CB_TLBIASID_ASID_MASK      0xFF
+
+/* Invalidate TLB by VA: CB_TLBIVA */
+#define CB_TLBIVA_ASID_MASK        0xFF
+#define CB_TLBIVA_VA_MASK          0xFFFFF
+
+/* Invalidate TLB by VA, All ASID: CB_TLBIVAA */
+#define CB_TLBIVAA_VA_MASK         0xFFFFF
+
+/* Invalidate TLB by VA, All ASID, Last Level: CB_TLBIVAAL */
+#define CB_TLBIVAAL_VA_MASK        0xFFFFF
+
+/* Invalidate TLB by VA, Last Level: CB_TLBIVAL */
+#define CB_TLBIVAL_ASID_MASK       0xFF
+#define CB_TLBIVAL_VA_MASK         0xFFFFF
+
+/* TLB Status: CB_TLBSTATUS */
+#define CB_TLBSTATUS_SACTIVE_MASK  0x01
+
+/* Translation Table Base Control Register: CB_TTBCR */
+#define CB_TTBCR_T0SZ_MASK         0x07
+#define CB_TTBCR_PD0_MASK          0x01
+#define CB_TTBCR_PD1_MASK          0x01
+#define CB_TTBCR_NSCFG0_MASK       0x01
+#define CB_TTBCR_NSCFG1_MASK       0x01
+#define CB_TTBCR_EAE_MASK          0x01
+
+/* Translation Table Base Register 0/1: CB_TTBR */
+#define CB_TTBR0_IRGN1_MASK        0x01
+#define CB_TTBR0_S_MASK            0x01
+#define CB_TTBR0_RGN_MASK          0x01
+#define CB_TTBR0_NOS_MASK          0x01
+#define CB_TTBR0_IRGN0_MASK        0x01
+#define CB_TTBR0_ADDR_MASK         0xFFFFFF
+
+#define CB_TTBR1_IRGN1_MASK        0x1
+#define CB_TTBR1_S_MASK            0x1
+#define CB_TTBR1_RGN_MASK          0x1
+#define CB_TTBR1_NOS_MASK          0X1
+#define CB_TTBR1_IRGN0_MASK        0X1
+#define CB_TTBR1_ADDR_MASK         0xFFFFFF
+
+/* Global Register Shifts */
+/* Configuration Register: CR0 */
+#define CR0_NSCFG_SHIFT            28
+#define CR0_WACFG_SHIFT            26
+#define CR0_RACFG_SHIFT            24
+#define CR0_SHCFG_SHIFT            22
+#define CR0_SMCFCFG_SHIFT          21
+#define CR0_MTCFG_SHIFT            20
+#define CR0_MEMATTR_SHIFT          16
+#define CR0_BSU_SHIFT              14
+#define CR0_FB_SHIFT               13
+#define CR0_PTM_SHIFT              12
+#define CR0_VMIDPNE_SHIFT          11
+#define CR0_USFCFG_SHIFT           10
+#define CR0_GSE_SHIFT              9
+#define CR0_STALLD_SHIFT           8
+#define CR0_TRANSIENTCFG_SHIFT     6
+#define CR0_GCFGFIE_SHIFT          5
+#define CR0_GCFGFRE_SHIFT          4
+#define CR0_GFIE_SHIFT             2
+#define CR0_GFRE_SHIFT             1
+#define CR0_CLIENTPD_SHIFT         0
+
+/* Configuration Register: CR2 */
+#define CR2_BPVMID_SHIFT           0
+
+/* Global Address Translation, Stage 1, Privileged Read: GATS1PR */
+#define GATS1PR_ADDR_SHIFT         12
+#define GATS1PR_NDX_SHIFT          0
+
+/* Global Address Translation, Stage 1, Privileged Write: GATS1PW */
+#define GATS1PW_ADDR_SHIFT         12
+#define GATS1PW_NDX_SHIFT          0
+
+/* Global Address Translation, Stage 1, User Read: GATS1UR */
+#define GATS1UR_ADDR_SHIFT         12
+#define GATS1UR_NDX_SHIFT          0
+
+/* Global Address Translation, Stage 1, User Write: GATS1UW */
+#define GATS1UW_ADDR_SHIFT         12
+#define GATS1UW_NDX_SHIFT          0
+
+/* Global Address Translation, Stage 1 and 2, Privileged Read: GATS12PR */
+#define GATS12PR_ADDR_SHIFT        12
+#define GATS12PR_NDX_SHIFT         0
+
+/* Global Address Translation, Stage 1 and 2, Privileged Write: GATS12PW */
+#define GATS12PW_ADDR_SHIFT        12
+#define GATS12PW_NDX_SHIFT         0
+
+/* Global Address Translation, Stage 1 and 2, User Read: GATS12UR */
+#define GATS12UR_ADDR_SHIFT        12
+#define GATS12UR_NDX_SHIFT         0
+
+/* Global Address Translation, Stage 1 and 2, User Write: GATS12UW */
+#define GATS12UW_ADDR_SHIFT        12
+#define GATS12UW_NDX_SHIFT         0
+
+/* Global Address Translation Status Register: GATSR */
+#define GATSR_ACTIVE_SHIFT         0
+
+/* Global Fault Address Register: GFAR */
+#define GFAR_FADDR_SHIFT           0
+
+/* Global Fault Status Register: GFSR */
+#define GFSR_ICF_SHIFT             0
+#define GFSR_USF_SHIFT             1
+#define GFSR_SMCF_SHIFT            2
+#define GFSR_UCBF_SHIFT            3
+#define GFSR_UCIF_SHIFT            4
+#define GFSR_CAF_SHIFT             5
+#define GFSR_EF_SHIFT              6
+#define GFSR_PF_SHIFT              7
+#define GFSR_MULTI_SHIFT           31
+
+/* Global Fault Syndrome Register 0: GFSYNR0 */
+#define GFSYNR0_NESTED_SHIFT       0
+#define GFSYNR0_WNR_SHIFT          1
+#define GFSYNR0_PNU_SHIFT          2
+#define GFSYNR0_IND_SHIFT          3
+#define GFSYNR0_NSSTATE_SHIFT      4
+#define GFSYNR0_NSATTR_SHIFT       5
+
+/* Global Fault Syndrome Register 1: GFSYNR1 */
+#define GFSYNR1_SID_SHIFT          0
+
+/* Global Physical Address Register: GPAR */
+#define GPAR_F_SHIFT               0
+#define GPAR_SS_SHIFT              1
+#define GPAR_OUTER_SHIFT           2
+#define GPAR_INNER_SHIFT           4
+#define GPAR_SH_SHIFT              7
+#define GPAR_NS_SHIFT              9
+#define GPAR_NOS_SHIFT             10
+#define GPAR_PA_SHIFT              12
+#define GPAR_TF_SHIFT              1
+#define GPAR_AFF_SHIFT             2
+#define GPAR_PF_SHIFT              3
+#define GPAR_EF_SHIFT              4
+#define GPAR_TLCMCF_SHIFT          5
+#define GPAR_TLBLKF_SHIFT          6
+#define GFAR_UCBF_SHIFT            30
+
+/* Identification Register: IDR0 */
+#define IDR0_NUMSMRG_SHIFT         0
+#define IDR0_NUMSIDB_SHIFT         9
+#define IDR0_BTM_SHIFT             13
+#define IDR0_CTTW_SHIFT            14
+#define IDR0_NUMIRPT_SHIFT         16
+#define IDR0_PTFS_SHIFT            24
+#define IDR0_SMS_SHIFT             27
+#define IDR0_NTS_SHIFT             28
+#define IDR0_S2TS_SHIFT            29
+#define IDR0_S1TS_SHIFT            30
+#define IDR0_SES_SHIFT             31
+
+/* Identification Register: IDR1 */
+#define IDR1_NUMCB_SHIFT           0
+#define IDR1_NUMSSDNDXB_SHIFT      8
+#define IDR1_SSDTP_SHIFT           12
+#define IDR1_SMCD_SHIFT            15
+#define IDR1_NUMS2CB_SHIFT         16
+#define IDR1_NUMPAGENDXB_SHIFT     28
+#define IDR1_PAGESIZE_SHIFT        31
+
+/* Identification Register: IDR2 */
+#define IDR2_IAS_SHIFT             0
+#define IDR2_OAS_SHIFT             4
+
+/* Identification Register: IDR7 */
+#define IDR7_MINOR_SHIFT           0
+#define IDR7_MAJOR_SHIFT           4
+
+/* Stream to Context Register: S2CR */
+#define S2CR_CBNDX_SHIFT           0
+#define s2CR_SHCFG_SHIFT           8
+#define S2CR_MTCFG_SHIFT           11
+#define S2CR_MEMATTR_SHIFT         12
+#define S2CR_TYPE_SHIFT            16
+#define S2CR_NSCFG_SHIFT           18
+#define S2CR_RACFG_SHIFT           20
+#define S2CR_WACFG_SHIFT           22
+#define S2CR_PRIVCFG_SHIFT         24
+#define S2CR_INSTCFG_SHIFT         26
+#define S2CR_TRANSIENTCFG_SHIFT    28
+#define S2CR_VMID_SHIFT            0
+#define S2CR_BSU_SHIFT             24
+#define S2CR_FB_SHIFT              26
+
+/* Stream Match Register: SMR */
+#define SMR_ID_SHIFT               0
+#define SMR_MASK_SHIFT             16
+#define SMR_VALID_SHIFT            31
+
+/* Global TLB Status: TLBGSTATUS */
+#define TLBGSTATUS_GSACTIVE_SHIFT  0
+
+/* Invalidate Hyp TLB by VA: TLBIVAH */
+#define TLBIVAH_ADDR_SHIFT         12
+
+/* Invalidate TLB by VMID: TLBIVMID */
+#define TLBIVMID_VMID_SHIFT        0
+
+/* Context Bank Attribute Register: CBAR */
+#define CBAR_VMID_SHIFT            0
+#define CBAR_CBNDX_SHIFT           8
+#define CBAR_BPSHCFG_SHIFT         8
+#define CBAR_HYPC_SHIFT            10
+#define CBAR_FB_SHIFT              11
+#define CBAR_MEMATTR_SHIFT         12
+#define CBAR_TYPE_SHIFT            16
+#define CBAR_BSU_SHIFT             18
+#define CBAR_RACFG_SHIFT           20
+#define CBAR_WACFG_SHIFT           22
+#define CBAR_IRPTNDX_SHIFT         24
+
+/* Context Bank Fault Restricted Syndrome Register A: CBFRSYNRA */
+#define CBFRSYNRA_SID_SHIFT        0
+
+/* Stage 1 Context Bank Format Shifts */
+/* Auxiliary Control Register: CB_ACTLR */
+#define CB_ACTLR_REQPRIORITY_SHIFT     0
+#define CB_ACTLR_REQPRIORITYCFG_SHIFT  4
+#define CB_ACTLR_PRIVCFG_SHIFT         8
+#define CB_ACTLR_BPRCOSH_SHIFT         28
+#define CB_ACTLR_BPRCISH_SHIFT         29
+#define CB_ACTLR_BPRCNSH_SHIFT         30
+
+/* Address Translation, Stage 1, Privileged Read: CB_ATS1PR */
+#define CB_ATS1PR_ADDR_SHIFT       12
+
+/* Address Translation, Stage 1, Privileged Write: CB_ATS1PW */
+#define CB_ATS1PW_ADDR_SHIFT       12
+
+/* Address Translation, Stage 1, User Read: CB_ATS1UR */
+#define CB_ATS1UR_ADDR_SHIFT       12
+
+/* Address Translation, Stage 1, User Write: CB_ATS1UW */
+#define CB_ATS1UW_ADDR_SHIFT       12
+
+/* Address Translation Status Register: CB_ATSR */
+#define CB_ATSR_ACTIVE_SHIFT       0
+
+/* Context ID Register: CB_CONTEXTIDR */
+#define CB_CONTEXTIDR_ASID_SHIFT   0
+#define CB_CONTEXTIDR_PROCID_SHIFT 8
+
+/* Fault Address Register: CB_FAR */
+#define CB_FAR_FADDR_SHIFT         0
+
+/* Fault Status Register: CB_FSR */
+#define CB_FSR_TF_SHIFT            1
+#define CB_FSR_AFF_SHIFT           2
+#define CB_FSR_PF_SHIFT            3
+#define CB_FSR_EF_SHIFT            4
+#define CB_FSR_TLBMCF_SHIFT        5
+#define CB_FSR_TLBLKF_SHIFT        6
+#define CB_FSR_SS_SHIFT            30
+#define CB_FSR_MULTI_SHIFT         31
+
+/* Fault Syndrome Register 0: CB_FSYNR0 */
+#define CB_FSYNR0_PLVL_SHIFT       0
+#define CB_FSYNR0_S1PTWF_SHIFT     3
+#define CB_FSYNR0_WNR_SHIFT        4
+#define CB_FSYNR0_PNU_SHIFT        5
+#define CB_FSYNR0_IND_SHIFT        6
+#define CB_FSYNR0_NSSTATE_SHIFT    7
+#define CB_FSYNR0_NSATTR_SHIFT     8
+#define CB_FSYNR0_ATOF_SHIFT       9
+#define CB_FSYNR0_PTWF_SHIFT       10
+#define CB_FSYNR0_AFR_SHIFT        11
+#define CB_FSYNR0_S1CBNDX_SHIFT    16
+
+/* Normal Memory Remap Register: CB_NMRR */
+#define CB_NMRR_IR0_SHIFT          0
+#define CB_NMRR_IR1_SHIFT          2
+#define CB_NMRR_IR2_SHIFT          4
+#define CB_NMRR_IR3_SHIFT          6
+#define CB_NMRR_IR4_SHIFT          8
+#define CB_NMRR_IR5_SHIFT          10
+#define CB_NMRR_IR6_SHIFT          12
+#define CB_NMRR_IR7_SHIFT          14
+#define CB_NMRR_OR0_SHIFT          16
+#define CB_NMRR_OR1_SHIFT          18
+#define CB_NMRR_OR2_SHIFT          20
+#define CB_NMRR_OR3_SHIFT          22
+#define CB_NMRR_OR4_SHIFT          24
+#define CB_NMRR_OR5_SHIFT          26
+#define CB_NMRR_OR6_SHIFT          28
+#define CB_NMRR_OR7_SHIFT          30
+
+/* Physical Address Register: CB_PAR */
+#define CB_PAR_F_SHIFT             0
+#define CB_PAR_SS_SHIFT            1
+#define CB_PAR_OUTER_SHIFT         2
+#define CB_PAR_INNER_SHIFT         4
+#define CB_PAR_SH_SHIFT            7
+#define CB_PAR_NS_SHIFT            9
+#define CB_PAR_NOS_SHIFT           10
+#define CB_PAR_PA_SHIFT            12
+#define CB_PAR_TF_SHIFT            1
+#define CB_PAR_AFF_SHIFT           2
+#define CB_PAR_PF_SHIFT            3
+#define CB_PAR_TLBMCF_SHIFT        5
+#define CB_PAR_TLBLKF_SHIFT        6
+#define CB_PAR_ATOT_SHIFT          31
+#define CB_PAR_PLVL_SHIFT          0
+#define CB_PAR_STAGE_SHIFT         3
+
+/* Primary Region Remap Register: CB_PRRR */
+#define CB_PRRR_TR0_SHIFT          0
+#define CB_PRRR_TR1_SHIFT          2
+#define CB_PRRR_TR2_SHIFT          4
+#define CB_PRRR_TR3_SHIFT          6
+#define CB_PRRR_TR4_SHIFT          8
+#define CB_PRRR_TR5_SHIFT          10
+#define CB_PRRR_TR6_SHIFT          12
+#define CB_PRRR_TR7_SHIFT          14
+#define CB_PRRR_DS0_SHIFT          16
+#define CB_PRRR_DS1_SHIFT          17
+#define CB_PRRR_NS0_SHIFT          18
+#define CB_PRRR_NS1_SHIFT          19
+#define CB_PRRR_NOS0_SHIFT         24
+#define CB_PRRR_NOS1_SHIFT         25
+#define CB_PRRR_NOS2_SHIFT         26
+#define CB_PRRR_NOS3_SHIFT         27
+#define CB_PRRR_NOS4_SHIFT         28
+#define CB_PRRR_NOS5_SHIFT         29
+#define CB_PRRR_NOS6_SHIFT         30
+#define CB_PRRR_NOS7_SHIFT         31
+
+/* Transaction Resume: CB_RESUME */
+#define CB_RESUME_TNR_SHIFT        0
+
+/* System Control Register: CB_SCTLR */
+#define CB_SCTLR_M_SHIFT            0
+#define CB_SCTLR_TRE_SHIFT          1
+#define CB_SCTLR_AFE_SHIFT          2
+#define CB_SCTLR_AFFD_SHIFT         3
+#define CB_SCTLR_E_SHIFT            4
+#define CB_SCTLR_CFRE_SHIFT         5
+#define CB_SCTLR_CFIE_SHIFT         6
+#define CB_SCTLR_CFCFG_SHIFT        7
+#define CB_SCTLR_HUPCF_SHIFT        8
+#define CB_SCTLR_WXN_SHIFT          9
+#define CB_SCTLR_UWXN_SHIFT         10
+#define CB_SCTLR_ASIDPNE_SHIFT      12
+#define CB_SCTLR_TRANSIENTCFG_SHIFT 14
+#define CB_SCTLR_MEMATTR_SHIFT      16
+#define CB_SCTLR_MTCFG_SHIFT        20
+#define CB_SCTLR_SHCFG_SHIFT        22
+#define CB_SCTLR_RACFG_SHIFT        24
+#define CB_SCTLR_WACFG_SHIFT        26
+#define CB_SCTLR_NSCFG_SHIFT        28
+
+/* Invalidate TLB by ASID: CB_TLBIASID */
+#define CB_TLBIASID_ASID_SHIFT      0
+
+/* Invalidate TLB by VA: CB_TLBIVA */
+#define CB_TLBIVA_ASID_SHIFT        0
+#define CB_TLBIVA_VA_SHIFT          12
+
+/* Invalidate TLB by VA, All ASID: CB_TLBIVAA */
+#define CB_TLBIVAA_VA_SHIFT         12
+
+/* Invalidate TLB by VA, All ASID, Last Level: CB_TLBIVAAL */
+#define CB_TLBIVAAL_VA_SHIFT        12
+
+/* Invalidate TLB by VA, Last Level: CB_TLBIVAL */
+#define CB_TLBIVAL_ASID_SHIFT       0
+#define CB_TLBIVAL_VA_SHIFT         12
+
+/* TLB Status: CB_TLBSTATUS */
+#define CB_TLBSTATUS_SACTIVE_SHIFT  0
+
+/* Translation Table Base Control Register: CB_TTBCR */
+#define CB_TTBCR_T0SZ_SHIFT         0
+#define CB_TTBCR_PD0_SHIFT          4
+#define CB_TTBCR_PD1_SHIFT          5
+#define CB_TTBCR_NSCFG0_SHIFT       14
+#define CB_TTBCR_NSCFG1_SHIFT       30
+#define CB_TTBCR_EAE_SHIFT          31
+
+/* Translation Table Base Register 0/1: CB_TTBR */
+#define CB_TTBR0_IRGN1_SHIFT        0
+#define CB_TTBR0_S_SHIFT            1
+#define CB_TTBR0_RGN_SHIFT          3
+#define CB_TTBR0_NOS_SHIFT          5
+#define CB_TTBR0_IRGN0_SHIFT        6
+#define CB_TTBR0_ADDR_SHIFT         14
+
+#define CB_TTBR1_IRGN1_SHIFT        0
+#define CB_TTBR1_S_SHIFT            1
+#define CB_TTBR1_RGN_SHIFT          3
+#define CB_TTBR1_NOS_SHIFT          5
+#define CB_TTBR1_IRGN0_SHIFT        6
+#define CB_TTBR1_ADDR_SHIFT         14
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/ion.h b/arch/arm/mach-msm/include/mach/ion.h
new file mode 100644
index 0000000..9fbc720
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/ion.h
@@ -0,0 +1,29 @@
+/**
+ *
+ * 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
+ * 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 __MACH_ION_H_
+#define __MACH_ION_H_
+
+enum ion_memory_types {
+	ION_EBI_TYPE,
+	ION_SMI_TYPE,
+};
+
+enum ion_permission_type {
+	IPT_TYPE_MM_CARVEOUT = 0,
+	IPT_TYPE_MFC_SHAREDMEM = 1,
+	IPT_TYPE_MDP_WRITEBACK = 2,
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-7x00.h b/arch/arm/mach-msm/include/mach/irqs-7x00.h
index f1fe706..a8e1da2 100644
--- a/arch/arm/mach-msm/include/mach/irqs-7x00.h
+++ b/arch/arm/mach-msm/include/mach/irqs-7x00.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  */
 
@@ -71,5 +71,7 @@
 #define NR_MSM_IRQS 64
 #define NR_GPIO_IRQS 122
 #define NR_BOARD_IRQS 64
+#define NR_SIRC_IRQS 0
 
+#define INT_ADSP_A11_SMSM    INT_ADSP_A11
 #endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-7x30.h b/arch/arm/mach-msm/include/mach/irqs-7x30.h
index 1f15902..a624bbf 100644
--- a/arch/arm/mach-msm/include/mach/irqs-7x30.h
+++ b/arch/arm/mach-msm/include/mach/irqs-7x30.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -24,7 +24,7 @@
 #define INT_AVS_SVIC_SW_DONE	6
 #define INT_SC_DBG_RX_FULL	7
 #define INT_SC_DBG_TX_EMPTY	8
-#define INT_ARM11_PM		9
+#define INT_ARMQC_PERFMON	9
 #define INT_AVS_REQ_DOWN	10
 #define INT_AVS_REQ_UP		11
 #define INT_SC_ACG		12
@@ -131,8 +131,8 @@
 #define INT_TCHSCRN1 		INT_TSSC_SAMPLE
 #define INT_TCHSCRN2 		INT_TSSC_PENUP
 #define INT_GP_TIMER_EXP 	INT_GPT0_TIMER_EXP
-#define INT_ADSP_A11 		INT_AD5A_MPROC_APPS_0
-#define INT_ADSP_A9_A11 	INT_AD5A_MPROC_APPS_1
+#define INT_ADSP_A9_A11 	INT_AD5A_MPROC_APPS_0
+#define INT_ADSP_A11		INT_AD5A_MPROC_APPS_1
 #define INT_MDDI_EXT		INT_EMDH
 #define INT_MDDI_PRI		INT_PMDH
 #define INT_MDDI_CLIENT		INT_MDC
@@ -142,12 +142,9 @@
 #define NR_MSM_IRQS		128
 #define NR_GPIO_IRQS		182
 #define PMIC8058_IRQ_BASE	(NR_MSM_IRQS + NR_GPIO_IRQS)
-#define NR_PMIC8058_GPIO_IRQS	40
-#define NR_PMIC8058_MPP_IRQS	12
-#define NR_PMIC8058_MISC_IRQS	8
-#define NR_PMIC8058_IRQS	(NR_PMIC8058_GPIO_IRQS +\
-				NR_PMIC8058_MPP_IRQS +\
-				NR_PMIC8058_MISC_IRQS)
+#define NR_PMIC8058_IRQS	256
 #define NR_BOARD_IRQS		NR_PMIC8058_IRQS
 
+#define INT_ADSP_A11_SMSM	INT_ADSP_A11
+
 #endif /* __ASM_ARCH_MSM_IRQS_7X30_H */
diff --git a/arch/arm/mach-msm/include/mach/irqs-7xxx.h b/arch/arm/mach-msm/include/mach/irqs-7xxx.h
new file mode 100644
index 0000000..c90b4ee
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/irqs-7xxx.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+ * Author: Brian Swetland <swetland@google.com>
+ */
+
+#ifndef __ASM_ARCH_MSM_IRQS_7XXX_H
+#define __ASM_ARCH_MSM_IRQS_7XXX_H
+
+/* MSM ARM11 Interrupt Numbers */
+/* See 80-VE113-1 A, pp219-221     */
+
+#define INT_A9_M2A_0         0
+#define INT_A9_M2A_1         1
+#define INT_A9_M2A_2         2
+#define INT_A9_M2A_3         3
+#define INT_A9_M2A_4         4
+#define INT_A9_M2A_5         5
+#define INT_A9_M2A_6         6
+#define INT_GP_TIMER_EXP     7
+#define INT_DEBUG_TIMER_EXP  8
+#define INT_UART1            9
+#define INT_UART2            10
+#define INT_UART3            11
+#define INT_UART1_RX         12
+#define INT_UART2_RX         13
+#define INT_UART3_RX         14
+#define INT_USB_OTG          15
+#if defined(CONFIG_ARCH_MSM7X27A)
+#define INT_DSI_IRQ          16
+#define INT_CSI_IRQ_1        17
+#define INT_CSI_IRQ_0        18
+#else
+#define INT_MDDI_PRI         16
+#define INT_MDDI_EXT         17
+#define INT_MDDI_CLIENT      18
+#endif
+#define INT_MDP              19
+#define INT_GRAPHICS         20
+#define INT_ADM_AARM         21
+#define INT_ADSP_A11         22
+#define INT_ADSP_A9_A11      23
+#define INT_SDC1_0           24
+#define INT_SDC1_1           25
+#define INT_SDC2_0           26
+#define INT_SDC2_1           27
+#define INT_KEYSENSE         28
+#define INT_TCHSCRN_SSBI     29
+#define INT_TCHSCRN1         30
+#define INT_TCHSCRN2         31
+
+#define INT_GPIO_GROUP1      (32 + 0)
+#define INT_GPIO_GROUP2      (32 + 1)
+#define INT_PWB_I2C          (32 + 2)
+#define INT_SOFTRESET        (32 + 3)
+#define INT_NAND_WR_ER_DONE  (32 + 4)
+#define INT_NAND_OP_DONE     (32 + 5)
+#define INT_PBUS_ARM11       (32 + 6)
+#define INT_AXI_MPU_SMI      (32 + 7)
+#define INT_AXI_MPU_EBI1     (32 + 8)
+#define INT_AD_HSSD          (32 + 9)
+#define INT_ARMQC_PERFMON    (32 + 10)
+#define INT_ARM11_DMA        (32 + 11)
+#define INT_TSIF_IRQ         (32 + 12)
+#define INT_UART1DM_IRQ      (32 + 13)
+#define INT_UART1DM_RX       (32 + 14)
+#define INT_USB_HS           (32 + 15)
+#define INT_SDC3_0           (32 + 16)
+#define INT_SDC3_1           (32 + 17)
+#define INT_SDC4_0           (32 + 18)
+#define INT_SDC4_1           (32 + 19)
+#define INT_UART2DM_IRQ      (32 + 20)
+#define INT_UART2DM_RX       (32 + 21)
+
+/* 22-31 are reserved except 7x27a*/
+#if defined(CONFIG_ARCH_MSM7X27A)
+#define INT_L2CC_EM          (32 + 22)
+#define INT_L2CC_INTR        (32 + 23)
+#define INT_CE_IRQ           (32 + 24)
+#endif
+
+#define INT_ADSP_A11_SMSM    INT_ADSP_A11
+#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-8064.h b/arch/arm/mach-msm/include/mach/irqs-8064.h
new file mode 100644
index 0000000..a5f78f5
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/irqs-8064.h
@@ -0,0 +1,312 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_ARCH_MSM_IRQS_8064_H
+#define __ASM_ARCH_MSM_IRQS_8064_H
+
+/* MSM ACPU Interrupt Numbers */
+
+/*
+ * 0-15:  STI/SGI (software triggered/generated interrupts)
+ * 16-31: PPI (private peripheral interrupts)
+ * 32+:   SPI (shared peripheral interrupts)
+ */
+
+#define GIC_PPI_START 16
+#define GIC_SPI_START 32
+
+#define INT_VGIC				(GIC_PPI_START + 0)
+#define INT_DEBUG_TIMER_EXP			(GIC_PPI_START + 1)
+#define INT_GP_TIMER_EXP			(GIC_PPI_START + 2)
+#define INT_GP_TIMER2_EXP			(GIC_PPI_START + 3)
+#define WDT0_ACCSCSSNBARK_INT			(GIC_PPI_START + 4)
+#define WDT1_ACCSCSSNBARK_INT			(GIC_PPI_START + 5)
+#define AVS_SVICINT				(GIC_PPI_START + 6)
+#define AVS_SVICINTSWDONE			(GIC_PPI_START + 7)
+#define CPU_DBGCPUXCOMMRXFULL			(GIC_PPI_START + 8)
+#define CPU_DBGCPUXCOMMTXEMPTY			(GIC_PPI_START + 9)
+#define INT_ARMQC_PERFMON			(GIC_PPI_START + 10)
+#define SC_AVSCPUXDOWN				(GIC_PPI_START + 11)
+#define SC_AVSCPUXUP				(GIC_PPI_START + 12)
+#define SC_SICCPUXACGIRPTREQ			(GIC_PPI_START + 13)
+#define SC_SICCPUXEXTFAULTIRPTREQ		(GIC_PPI_START + 14)
+/* PPI 15 is unused */
+
+#define APCC_QGICACGIRPTREQ			(GIC_SPI_START + 0)
+#define APCC_QGICL2PERFMONIRPTREQ		(GIC_SPI_START + 1)
+#define SC_SICL2PERFMONIRPTREQ			APCC_QGICL2PERFMONIRPTREQ
+#define APCC_QGICL2IRPTREQ			(GIC_SPI_START + 2)
+#define APCC_QGICMPUIRPTREQ			(GIC_SPI_START + 3)
+#define TLMM_MSM_DIR_CONN_IRQ_0			(GIC_SPI_START + 4)
+#define TLMM_MSM_DIR_CONN_IRQ_1			(GIC_SPI_START + 5)
+#define TLMM_MSM_DIR_CONN_IRQ_2			(GIC_SPI_START + 6)
+#define TLMM_MSM_DIR_CONN_IRQ_3			(GIC_SPI_START + 7)
+#define TLMM_MSM_DIR_CONN_IRQ_4			(GIC_SPI_START + 8)
+#define TLMM_MSM_DIR_CONN_IRQ_5			(GIC_SPI_START + 9)
+#define TLMM_MSM_DIR_CONN_IRQ_6			(GIC_SPI_START + 10)
+#define TLMM_MSM_DIR_CONN_IRQ_7			(GIC_SPI_START + 11)
+#define TLMM_MSM_DIR_CONN_IRQ_8			(GIC_SPI_START + 12)
+#define TLMM_MSM_DIR_CONN_IRQ_9			(GIC_SPI_START + 13)
+#define PM8921_SEC_IRQ_N			(GIC_SPI_START + 14)
+#define PM8821_SEC_IRQ_N			(GIC_SPI_START + 15)
+#define TLMM_MSM_SUMMARY_IRQ			(GIC_SPI_START + 16)
+#define SPDM_RT_1_IRQ				(GIC_SPI_START + 17)
+#define SPDM_DIAG_IRQ				(GIC_SPI_START + 18)
+#define RPM_APCC_CPU0_GP_HIGH_IRQ		(GIC_SPI_START + 19)
+#define RPM_APCC_CPU0_GP_MEDIUM_IRQ		(GIC_SPI_START + 20)
+#define RPM_APCC_CPU0_GP_LOW_IRQ		(GIC_SPI_START + 21)
+#define RPM_APCC_CPU0_WAKE_UP_IRQ		(GIC_SPI_START + 22)
+#define RPM_APCC_CPU1_GP_HIGH_IRQ		(GIC_SPI_START + 23)
+#define RPM_APCC_CPU1_GP_MEDIUM_IRQ		(GIC_SPI_START + 24)
+#define RPM_APCC_CPU1_GP_LOW_IRQ		(GIC_SPI_START + 25)
+#define RPM_APCC_CPU1_WAKE_UP_IRQ		(GIC_SPI_START + 26)
+#define SSBI2_2_SC_CPU0_SECURE_IRQ		(GIC_SPI_START + 27)
+#define SSBI2_2_SC_CPU0_NON_SECURE_IRQ		(GIC_SPI_START + 28)
+#define SSBI2_1_SC_CPU0_SECURE_IRQ		(GIC_SPI_START + 29)
+#define SSBI2_1_SC_CPU0_NON_SECURE_IRQ		(GIC_SPI_START + 30)
+#define MSMC_SC_SEC_CE_IRQ			(GIC_SPI_START + 31)
+#define MSMC_SC_PRI_CE_IRQ			(GIC_SPI_START + 32)
+#define SLIMBUS0_CORE_EE1_IRQ			(GIC_SPI_START + 33)
+#define SLIMBUS0_BAM_EE1_IRQ			(GIC_SPI_START + 34)
+#define KPSS_SPARE_0				(GIC_SPI_START + 35)
+#define GSS_A5_WDOG_EXPIRED			(GIC_SPI_START + 36)
+#define GSS_TO_APPS_IRQ_0			(GIC_SPI_START + 37)
+#define GSS_TO_APPS_IRQ_1			(GIC_SPI_START + 38)
+#define GSS_TO_APPS_IRQ_2			(GIC_SPI_START + 39)
+#define GSS_TO_APPS_IRQ_3			(GIC_SPI_START + 40)
+#define GSS_TO_APPS_IRQ_4			(GIC_SPI_START + 41)
+#define GSS_TO_APPS_IRQ_5			(GIC_SPI_START + 42)
+#define GSS_TO_APPS_IRQ_6			(GIC_SPI_START + 43)
+#define GSS_TO_APPS_IRQ_7			(GIC_SPI_START + 44)
+#define GSS_TO_APPS_IRQ_8			(GIC_SPI_START + 45)
+#define GSS_TO_APPS_IRQ_9			(GIC_SPI_START + 46)
+#define VPE_IRQ					(GIC_SPI_START + 47)
+#define VFE_IRQ					(GIC_SPI_START + 48)
+#define VCODEC_IRQ				(GIC_SPI_START + 49)
+#define KPSS_SPARE_1				(GIC_SPI_START + 50)
+#define SMMU_VPE_CB_SC_SECURE_IRQ		(GIC_SPI_START + 51)
+#define SMMU_VPE_CB_SC_NON_SECURE_IRQ		(GIC_SPI_START + 52)
+#define SMMU_VFE_CB_SC_SECURE_IRQ		(GIC_SPI_START + 53)
+#define SMMU_VFE_CB_SC_NON_SECURE_IRQ		(GIC_SPI_START + 54)
+#define SMMU_VCODEC_B_CB_SC_SECURE_IRQ		(GIC_SPI_START + 55)
+#define SMMU_VCODEC_B_CB_SC_NON_SECURE_IRQ	(GIC_SPI_START + 56)
+#define SMMU_VCODEC_A_CB_SC_SECURE_IRQ		(GIC_SPI_START + 57)
+#define SMMU_VCODEC_A_CB_SC_NON_SECURE_IRQ	(GIC_SPI_START + 58)
+#define SMMU_ROT_CB_SC_SECURE_IRQ		(GIC_SPI_START + 59)
+#define SMMU_ROT_CB_SC_NON_SECURE_IRQ		(GIC_SPI_START + 60)
+#define SMMU_MDP1_CB_SC_SECURE_IRQ		(GIC_SPI_START + 61)
+#define SMMU_MDP1_CB_SC_NON_SECURE_IRQ		(GIC_SPI_START + 62)
+#define SMMU_MDP0_CB_SC_SECURE_IRQ		(GIC_SPI_START + 63)
+#define SMMU_MDP0_CB_SC_NON_SECURE_IRQ		(GIC_SPI_START + 64)
+#define SMMU_JPEGD_CB_SC_SECURE_IRQ		(GIC_SPI_START + 65)
+#define SMMU_JPEGD_CB_SC_NON_SECURE_IRQ		(GIC_SPI_START + 66)
+#define SMMU_IJPEG_CB_SC_SECURE_IRQ		(GIC_SPI_START + 67)
+#define SMMU_IJPEG_CB_SC_NON_SECURE_IRQ		(GIC_SPI_START + 68)
+#define SMMU_GFX3D_CB_SC_SECURE_IRQ		(GIC_SPI_START + 69)
+#define SMMU_GFX3D_CB_SC_NON_SECURE_IRQ		(GIC_SPI_START + 70)
+#define VCAP_VP					(GIC_SPI_START + 71)
+#define VCAP_VC					(GIC_SPI_START + 72)
+#define ROT_IRQ					(GIC_SPI_START + 73)
+#define MMSS_FABRIC_IRQ				(GIC_SPI_START + 74)
+#define MDP_IRQ					(GIC_SPI_START + 75)
+#define JPEGD_IRQ				(GIC_SPI_START + 76)
+#define JPEG_IRQ				(GIC_SPI_START + 77)
+#define MMSS_IMEM_IRQ				(GIC_SPI_START + 78)
+#define HDMI_IRQ				(GIC_SPI_START + 79)
+#define GFX3D_IRQ				(GIC_SPI_START + 80)
+#define GFX3d_VBIF_IRQ				(GIC_SPI_START + 81)
+#define DSI1_IRQ				(GIC_SPI_START + 82)
+#define CSI_1_IRQ				(GIC_SPI_START + 83)
+#define CSI_0_IRQ				(GIC_SPI_START + 84)
+#define LPASS_SCSS_AUDIO_IF_OUT0_IRQ		(GIC_SPI_START + 85)
+#define LPASS_SCSS_MIDI_IRQ			(GIC_SPI_START + 86)
+#define LPASS_Q6SS_WDOG_EXPIRED			(GIC_SPI_START + 87)
+#define LPASS_SCSS_GP_LOW_IRQ			(GIC_SPI_START + 88)
+#define LPASS_SCSS_GP_MEDIUM_IRQ		(GIC_SPI_START + 89)
+#define LPASS_SCSS_GP_HIGH_IRQ			(GIC_SPI_START + 90)
+#define TOP_IMEM_IRQ				(GIC_SPI_START + 91)
+#define FABRIC_SYS_IRQ				(GIC_SPI_START + 92)
+#define FABRIC_APPS_IRQ				(GIC_SPI_START + 93)
+#define USB1_HS_BAM_IRQ				(GIC_SPI_START + 94)
+#define SDC4_BAM_IRQ				(GIC_SPI_START + 95)
+#define SDC3_BAM_IRQ				(GIC_SPI_START + 96)
+#define SDC2_BAM_IRQ				(GIC_SPI_START + 97)
+#define SDC1_BAM_IRQ				(GIC_SPI_START + 98)
+#define FABRIC_SPS_IRQ				(GIC_SPI_START + 99)
+#define USB1_HS_IRQ				(GIC_SPI_START + 100)
+#define SDC4_IRQ_0				(GIC_SPI_START + 101)
+#define SDC3_IRQ_0				(GIC_SPI_START + 102)
+#define SDC2_IRQ_0				(GIC_SPI_START + 103)
+#define SDC1_IRQ_0				(GIC_SPI_START + 104)
+#define SPS_BAM_DMA_IRQ				(GIC_SPI_START + 105)
+#define SPS_SEC_VIOL_IRQ			(GIC_SPI_START + 106)
+#define SPS_MTI_0				(GIC_SPI_START + 107)
+#define SPS_MTI_1				(GIC_SPI_START + 108)
+#define SPS_MTI_2				(GIC_SPI_START + 109)
+#define SPS_MTI_3				(GIC_SPI_START + 110)
+#define SPS_MTI_4				(GIC_SPI_START + 111)
+#define SPS_MTI_5				(GIC_SPI_START + 112)
+#define SPS_MTI_6				(GIC_SPI_START + 113)
+#define SPS_MTI_7				(GIC_SPI_START + 114)
+#define SPS_MTI_8				(GIC_SPI_START + 115)
+#define SPS_MTI_9				(GIC_SPI_START + 116)
+#define SPS_MTI_10				(GIC_SPI_START + 117)
+#define SPS_MTI_11				(GIC_SPI_START + 118)
+#define SPS_MTI_12				(GIC_SPI_START + 119)
+#define SPS_MTI_13				(GIC_SPI_START + 120)
+#define SPS_MTI_14				(GIC_SPI_START + 121)
+#define SPS_MTI_15				(GIC_SPI_START + 122)
+#define SPS_MTI_16				(GIC_SPI_START + 123)
+#define SPS_MTI_17				(GIC_SPI_START + 124)
+#define SPS_MTI_18				(GIC_SPI_START + 125)
+#define SPS_MTI_19				(GIC_SPI_START + 126)
+#define SPS_MTI_20				(GIC_SPI_START + 127)
+#define SPS_MTI_21				(GIC_SPI_START + 128)
+#define SPS_MTI_22				(GIC_SPI_START + 129)
+#define SPS_MTI_23				(GIC_SPI_START + 130)
+#define SPS_MTI_24				(GIC_SPI_START + 131)
+#define SPS_MTI_25				(GIC_SPI_START + 132)
+#define SPS_MTI_26				(GIC_SPI_START + 133)
+#define SPS_MTI_27				(GIC_SPI_START + 134)
+#define SPS_MTI_28				(GIC_SPI_START + 135)
+#define SPS_MTI_29				(GIC_SPI_START + 136)
+#define SPS_MTI_30				(GIC_SPI_START + 137)
+#define SPS_MTI_31				(GIC_SPI_START + 138)
+#define CSIPHY_0_4LN_IRQ			(GIC_SPI_START + 139)
+#define CSIPHY_1_2LN_IRQ			(GIC_SPI_START + 140)
+#define KPSS_SPARE_2				(GIC_SPI_START + 141)
+#define USB1_IRQ				(GIC_SPI_START + 142)
+#define TSSC_SSBI_IRQ				(GIC_SPI_START + 143)
+#define TSSC_SAMPLE_IRQ				(GIC_SPI_START + 144)
+#define TSSC_PENUP_IRQ				(GIC_SPI_START + 145)
+#define KPSS_SPARE_3				(GIC_SPI_START + 146)
+#define KPSS_SPARE_4				(GIC_SPI_START + 147)
+#define KPSS_SPARE_5				(GIC_SPI_START + 148)
+#define KPSS_SPARE_6			        (GIC_SPI_START + 149)
+#define GSBI3_UARTDM_IRQ			(GIC_SPI_START + 150)
+#define GSBI3_QUP_IRQ				(GIC_SPI_START + 151)
+#define GSBI4_UARTDM_IRQ			(GIC_SPI_START + 152)
+#define GSBI4_QUP_IRQ				(GIC_SPI_START + 153)
+#define GSBI5_UARTDM_IRQ			(GIC_SPI_START + 154)
+#define GSBI5_QUP_IRQ				(GIC_SPI_START + 155)
+#define GSBI6_UARTDM_IRQ			(GIC_SPI_START + 156)
+#define GSBI6_QUP_IRQ				(GIC_SPI_START + 157)
+#define GSBI7_UARTDM_IRQ			(GIC_SPI_START + 158)
+#define GSBI7_QUP_IRQ				(GIC_SPI_START + 159)
+#define KPSS_SPARE_7				(GIC_SPI_START + 160)
+#define KPSS_SPARE_8				(GIC_SPI_START + 161)
+#define TSIF_TSPP_IRQ				(GIC_SPI_START + 162)
+#define TSIF_BAM_IRQ				(GIC_SPI_START + 163)
+#define TSIF2_IRQ				(GIC_SPI_START + 164)
+#define TSIF1_IRQ				(GIC_SPI_START + 165)
+#define DSI2_IRQ				(GIC_SPI_START + 166)
+#define ISPIF_IRQ				(GIC_SPI_START + 167)
+#define MSMC_SC_SEC_TMR_IRQ			(GIC_SPI_START + 168)
+#define MSMC_SC_SEC_WDOG_BARK_IRQ		(GIC_SPI_START + 169)
+#define ADM_0_SCSS_0_IRQ			(GIC_SPI_START + 170)
+#define ADM_0_SCSS_1_IRQ			(GIC_SPI_START + 171)
+#define ADM_0_SCSS_2_IRQ			(GIC_SPI_START + 172)
+#define ADM_0_SCSS_3_IRQ			(GIC_SPI_START + 173)
+#define CC_SCSS_WDT1CPU1BITEEXPIRED		(GIC_SPI_START + 174)
+#define CC_SCSS_WDT1CPU0BITEEXPIRED		(GIC_SPI_START + 175)
+#define CC_SCSS_WDT0CPU1BITEEXPIRED		(GIC_SPI_START + 176)
+#define CC_SCSS_WDT0CPU0BITEEXPIRED		(GIC_SPI_START + 177)
+#define TSENS_UPPER_LOWER_INT			(GIC_SPI_START + 178)
+#define SSBI2_2_SC_CPU1_SECURE_INT		(GIC_SPI_START + 179)
+#define SSBI2_2_SC_CPU1_NON_SECURE_INT		(GIC_SPI_START + 180)
+#define SSBI2_1_SC_CPU1_SECURE_INT		(GIC_SPI_START + 181)
+#define SSBI2_1_SC_CPU1_NON_SECURE_INT		(GIC_SPI_START + 182)
+#define XPU_SUMMARY_IRQ				(GIC_SPI_START + 183)
+#define BUS_EXCEPTION_SUMMARY_IRQ		(GIC_SPI_START + 184)
+#define HSDDRX_EBI1CH0_IRQ			(GIC_SPI_START + 185)
+#define HSDDRX_EBI1CH1_IRQ			(GIC_SPI_START + 186)
+#define USB3_HS_BAM_IRQ				(GIC_SPI_START + 187)
+#define USB3_HS_IRQ				(GIC_SPI_START + 188)
+#define CC_SCSS_WDT1CPU3BITEEXPIRED		(GIC_SPI_START + 189)
+#define CC_SCSS_WDT1CPU2BITEEXPIRED		(GIC_SPI_START + 190)
+#define CC_SCSS_WDT0CPU3BITEEXPIRED		(GIC_SPI_START + 191)
+#define CC_SCSS_WDT0CPU2BITEEXPIRED		(GIC_SPI_START + 192)
+#define APQ8064_GSBI1_UARTDM_IRQ		(GIC_SPI_START + 193)
+#define APQ8064_GSBI1_QUP_IRQ			(GIC_SPI_START + 194)
+#define APQ8064_GSBI2_UARTDM_IRQ		(GIC_SPI_START + 195)
+#define APQ8064_GSBI2_QUP_IRQ			(GIC_SPI_START + 196)
+#define RIVA_APSS_LTECOEX_IRQ			(GIC_SPI_START + 197)
+#define RIVA_APSS_SPARE_IRQ			(GIC_SPI_START + 198)
+#define RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ	(GIC_SPI_START + 199)
+#define RIVA_APSS_RESET_DONE_IRQ		(GIC_SPI_START + 200)
+#define RIVA_APSS_ASIC_IRQ			(GIC_SPI_START + 201)
+#define RIVA_APPS_WLAN_RX_DATA_AVAIL_IRQ	(GIC_SPI_START + 202)
+#define RIVA_APPS_WLAN_DATA_XFER_DONE_IRQ	(GIC_SPI_START + 203)
+#define RIVA_APPS_WLAN_SMSM_IRQ			(GIC_SPI_START + 204)
+#define RIVA_APPS_LOG_CTRL_IRQ			(GIC_SPI_START + 205)
+#define RIVA_APPS_FM_CTRL_IRQ			(GIC_SPI_START + 206)
+#define RIVA_APPS_HCI_IRQ			(GIC_SPI_START + 207)
+#define RIVA_APPS_WLAN_CTRL_IRQ			(GIC_SPI_START + 208)
+#define SATA_CONTROLLER_IRQ			(GIC_SPI_START + 209)
+#define SMMU_GFX3D1_CB_SC_SECURE_IRQ		(GIC_SPI_START + 210)
+#define SMMU_GFX3D1_CB_SC_NON_SECURE_IRQ	(GIC_SPI_START + 211)
+#define KPSS_SPARE_9				(GIC_SPI_START + 212)
+#define PPSS_WDOG_TIMER_IRQ			(GIC_SPI_START + 213)
+#define USB4_HS_BAM_IRQ				(GIC_SPI_START + 214)
+#define USB4_HS_IRQ				(GIC_SPI_START + 215)
+#define QDSS_ETB_IRQ				(GIC_SPI_START + 216)
+#define QDSS_CTI2KPSS_CPU1_IRQ			(GIC_SPI_START + 217)
+#define QDSS_CTI2KPSS_CPU0_IRQ			(GIC_SPI_START + 218)
+#define TLMM_MSM_DIR_CONN_IRQ_16		(GIC_SPI_START + 219)
+#define TLMM_MSM_DIR_CONN_IRQ_17		(GIC_SPI_START + 220)
+#define TLMM_MSM_DIR_CONN_IRQ_18		(GIC_SPI_START + 221)
+#define TLMM_MSM_DIR_CONN_IRQ_19		(GIC_SPI_START + 222)
+#define TLMM_MSM_DIR_CONN_IRQ_20		(GIC_SPI_START + 223)
+#define TLMM_MSM_DIR_CONN_IRQ_21		(GIC_SPI_START + 224)
+#define PM8921_USR_IRQ_N			(GIC_SPI_START + 225)
+#define PM8821_USR_IRQ_N			(GIC_SPI_START + 226)
+
+#define	CSI_2_IRQ				(GIC_SPI_START + 227)
+#define	APQ8064_CSIPHY_2LN_IRQ			(GIC_SPI_START + 228)
+#define	USB2_HSIC_IRQ				(GIC_SPI_START + 229)
+#define	CE2_BAM_XPU_IRQ				(GIC_SPI_START + 230)
+#define	CE1_BAM_XPU_IRQ				(GIC_SPI_START + 231)
+#define	RPM_SCSS_CPU2_WAKE_UP_IRQ		(GIC_SPI_START + 232)
+#define	RPM_SCSS_CPU3_WAKE_UP_IRQ		(GIC_SPI_START + 233)
+#define	CS3_BAM_XPU_IRQ				(GIC_SPI_START + 234)
+#define	CE3_IRQ					(GIC_SPI_START + 235)
+#define	SMMU_VCAP_CB_SC_SECURE_IRQ		(GIC_SPI_START + 236)
+#define	SMMU_VCAP_CB_SC_NON_SECURE_IRQ		(GIC_SPI_START + 237)
+#define	PCIE20_INT_MSI				(GIC_SPI_START + 238)
+#define	PCIE20_INTA				(GIC_SPI_START + 239)
+#define	PCIE20_INTB				(GIC_SPI_START + 240)
+#define	PCIE20_INTC				(GIC_SPI_START + 241)
+#define	PCIE20_INTD				(GIC_SPI_START + 242)
+#define	PCIE20_INT_PLS_HP			(GIC_SPI_START + 243)
+#define	PCIE20_INT_PLS_PME			(GIC_SPI_START + 244)
+#define	PCIE20_INT_LINK_UP			(GIC_SPI_START + 245)
+#define	PCIE20_INT_LINK_DOWN			(GIC_SPI_START + 246)
+#define	PCIE20_INT_HP_LEGACY			(GIC_SPI_START + 247)
+#define	PCIE20_AER_LEGACY			(GIC_SPI_START + 248)
+#define	PCIE20_INT_PME_LEGACY			(GIC_SPI_START + 249)
+#define	PCIE20_INT_BRIDGE_FLUSH_N		(GIC_SPI_START + 250)
+
+/* Backwards compatible IRQ macros. */
+#define INT_ADM_AARM				ADM_0_SCSS_0_IRQ
+
+/* smd/smsm interrupts */
+#define INT_A9_M2A_0		(GIC_SPI_START + 37) /*GSS_TO_APPS_IRQ_0*/
+#define INT_A9_M2A_5		(GIC_SPI_START + 38) /*GSS_TO_APPS_IRQ_1*/
+#define INT_ADSP_A11		LPASS_SCSS_GP_HIGH_IRQ
+#define INT_ADSP_A11_SMSM	LPASS_SCSS_GP_MEDIUM_IRQ
+#define INT_DSPS_A11		SPS_MTI_31
+#define INT_DSPS_A11_SMSM	SPS_MTI_30
+#define INT_WCNSS_A11		RIVA_APSS_SPARE_IRQ
+#define INT_WCNSS_A11_SMSM	RIVA_APPS_WLAN_SMSM_IRQ
+
+#endif
+
diff --git a/arch/arm/mach-msm/include/mach/irqs-8625.h b/arch/arm/mach-msm/include/mach/irqs-8625.h
new file mode 100644
index 0000000..3ff73eb
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/irqs-8625.h
@@ -0,0 +1,89 @@
+/* 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 __ASM_ARCH_MSM_IRQS_8625_H
+#define __ASM_ARCH_MSM_IRQS_8625_H
+
+#define GIC_PPI_START		16
+#define GIC_SPI_START		32
+
+/* As per QGIC2 PPI 16 aka 0 is reserved */
+#define MSM8625_INT_A5_PMU_IRQ		(GIC_PPI_START + 1)
+#define MSM8625_INT_DEBUG_TIMER_EXP	(GIC_PPI_START + 2)
+#define MSM8625_INT_GP_TIMER_EXP	(GIC_PPI_START + 3)
+#define MSM8625_INT_COMMRX		(GIC_PPI_START + 4)
+#define MSM8625_INT_COMMTX		(GIC_PPI_START + 5)
+
+/* rest of the PPI's not used
+ */
+
+#define MSM8625_INT_A9_M2A_0		(GIC_SPI_START + 0)
+#define MSM8625_INT_A9_M2A_1		(GIC_SPI_START + 1)
+#define MSM8625_INT_A9_M2A_2		(GIC_SPI_START + 2)
+#define MSM8625_INT_A9_M2A_3		(GIC_SPI_START + 3)
+#define MSM8625_INT_A9_M2A_4		(GIC_SPI_START + 4)
+#define MSM8625_INT_A9_M2A_5		(GIC_SPI_START + 5)
+#define MSM8625_INT_A9_M2A_6		(GIC_SPI_START + 6)
+#define MSM8625_INT_ACSR_MP_CORE_IPC0	(GIC_SPI_START + 7)
+#define MSM8625_INT_ACSR_MP_CORE_IPC1	(GIC_SPI_START + 8)
+#define MSM8625_INT_UART1		(GIC_SPI_START + 9)
+#define MSM8625_INT_UART2		(GIC_SPI_START + 10)
+#define MSM8625_INT_UART3		(GIC_SPI_START + 11)
+#define MSM8625_INT_UART1_RX		(GIC_SPI_START + 12)
+#define MSM8625_INT_UART2_RX		(GIC_SPI_START + 13)
+#define MSM8625_INT_UART3_RX		(GIC_SPI_START + 14)
+#define MSM8625_INT_USB_OTG		(GIC_SPI_START + 15)
+#define MSM8625_INT_DSI_IRQ		(GIC_SPI_START + 16)
+#define MSM8625_INT_CSI_IRQ_1		(GIC_SPI_START + 17)
+#define MSM8625_INT_CSI_IRQ_0		(GIC_SPI_START + 18)
+#define MSM8625_INT_MDP			(GIC_SPI_START + 19)
+#define MSM8625_INT_GRAPHICS		(GIC_SPI_START + 20)
+#define MSM8625_INT_ADM_AARM		(GIC_SPI_START + 21)
+#define MSM8625_INT_ADSP_A11		(GIC_SPI_START + 22)
+#define MSM8625_INT_ADSP_A9_A11		(GIC_SPI_START + 23)
+#define MSM8625_INT_SDC1_0		(GIC_SPI_START + 24)
+#define MSM8625_INT_SDC1_1		(GIC_SPI_START + 25)
+#define MSM8625_INT_SDC2_0		(GIC_SPI_START + 26)
+#define MSM8625_INT_SDC2_1		(GIC_SPI_START + 27)
+#define MSM8625_INT_KEYSENSE		(GIC_SPI_START + 28)
+#define MSM8625_INT_TCHSCRN_SSBI	(GIC_SPI_START + 29)
+#define MSM8625_INT_TCHSCRN1		(GIC_SPI_START + 30)
+#define MSM8625_INT_TCHSCRN2		(GIC_SPI_START + 31)
+
+#define MSM8625_INT_GPIO_GROUP1		(GIC_SPI_START + 32 + 0)
+#define MSM8625_INT_GPIO_GROUP2		(GIC_SPI_START + 32 + 1)
+#define MSM8625_INT_PWB_I2C		(GIC_SPI_START + 32 + 2)
+#define MSM8625_INT_SOFTRESET		(GIC_SPI_START + 32 + 3)
+#define MSM8625_INT_NAND_WR_ER_DONE	(GIC_SPI_START + 32 + 4)
+#define MSM8625_INT_NAND_OP_DONE	(GIC_SPI_START + 32 + 5)
+#define MSM8625_INT_PBUS_ARM11		(GIC_SPI_START + 32 + 6)
+#define MSM8625_INT_AXI_MPU_SMI		(GIC_SPI_START + 32 + 7)
+#define MSM8625_INT_AXI_MPU_EBI1	(GIC_SPI_START + 32 + 8)
+#define MSM8625_INT_AD_HSSD		(GIC_SPI_START + 32 + 9)
+#define MSM8625_INT_NOTUSED		(GIC_SPI_START + 32 + 10)
+#define MSM8625_INT_ARM11_DMA		(GIC_SPI_START + 32 + 11)
+#define MSM8625_INT_TSIF_IRQ		(GIC_SPI_START + 32 + 12)
+#define MSM8625_INT_UART1DM_IRQ		(GIC_SPI_START + 32 + 13)
+#define MSM8625_INT_UART1DM_RX		(GIC_SPI_START + 32 + 14)
+#define MSM8625_INT_USB_HS		(GIC_SPI_START + 32 + 15)
+#define MSM8625_INT_SDC3_0		(GIC_SPI_START + 32 + 16)
+#define MSM8625_INT_SDC3_1		(GIC_SPI_START + 32 + 17)
+#define MSM8625_INT_SDC4_0		(GIC_SPI_START + 32 + 18)
+#define MSM8625_INT_SDC4_1		(GIC_SPI_START + 32 + 19)
+#define MSM8625_INT_UART2DM_IRQ		(GIC_SPI_START + 32 + 20)
+#define MSM8625_INT_UART2DM_RX		(GIC_SPI_START + 32 + 21)
+#define MSM8625_INT_L2CC_EM		(GIC_SPI_START + 32 + 22)
+#define MSM8625_INT_L2CC_INTR		(GIC_SPI_START + 32 + 23)
+#define MSM8625_INT_CE_IRQ		(GIC_SPI_START + 32 + 24)
+
+#define MSM8625_INT_ADSP_A11_SMSM	MSM8625_INT_ADSP_A11
+#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-8930.h b/arch/arm/mach-msm/include/mach/irqs-8930.h
new file mode 100644
index 0000000..bfc32f6
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/irqs-8930.h
@@ -0,0 +1,292 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_ARCH_MSM_IRQS_8930_H
+#define __ASM_ARCH_MSM_IRQS_8930_H
+
+/* MSM ACPU Interrupt Numbers */
+
+/* 0-15:  STI/SGI (software triggered/generated interrupts)
+   16-31: PPI (private peripheral interrupts)
+   32+:   SPI (shared peripheral interrupts) */
+
+#define GIC_PPI_START 16
+#define GIC_SPI_START 32
+
+#define INT_VGIC				(GIC_PPI_START + 0)
+#define INT_DEBUG_TIMER_EXP			(GIC_PPI_START + 1)
+#define INT_GP_TIMER_EXP			(GIC_PPI_START + 2)
+#define INT_GP_TIMER2_EXP			(GIC_PPI_START + 3)
+#define WDT0_ACCSCSSNBARK_INT			(GIC_PPI_START + 4)
+#define WDT1_ACCSCSSNBARK_INT			(GIC_PPI_START + 5)
+#define AVS_SVICINT				(GIC_PPI_START + 6)
+#define AVS_SVICINTSWDONE			(GIC_PPI_START + 7)
+#define CPU_DBGCPUXCOMMRXFULL			(GIC_PPI_START + 8)
+#define CPU_DBGCPUXCOMMTXEMPTY			(GIC_PPI_START + 9)
+#define INT_ARMQC_PERFMON			(GIC_PPI_START + 10)
+#define SC_AVSCPUXDOWN				(GIC_PPI_START + 11)
+#define SC_AVSCPUXUP				(GIC_PPI_START + 12)
+#define SC_SICCPUXACGIRPTREQ			(GIC_PPI_START + 13)
+#define SC_SICCPUXEXTFAULTIRPTREQ		(GIC_PPI_START + 14)
+/* PPI 15 is unused */
+
+#define APCC_QGICACGIRPTREQ			(GIC_SPI_START + 0)
+#define APCC_QGICL2PERFMONIRPTREQ		(GIC_SPI_START + 1)
+#define SC_SICL2PERFMONIRPTREQ			APCC_QGICL2PERFMONIRPTREQ
+#define APCC_QGICL2IRPTREQ			(GIC_SPI_START + 2)
+#define APCC_QGICMPUIRPTREQ			(GIC_SPI_START + 3)
+#define TLMM_MSM_DIR_CONN_IRQ_0			(GIC_SPI_START + 4)
+#define TLMM_MSM_DIR_CONN_IRQ_1			(GIC_SPI_START + 5)
+#define TLMM_MSM_DIR_CONN_IRQ_2			(GIC_SPI_START + 6)
+#define TLMM_MSM_DIR_CONN_IRQ_3			(GIC_SPI_START + 7)
+#define TLMM_MSM_DIR_CONN_IRQ_4			(GIC_SPI_START + 8)
+#define TLMM_MSM_DIR_CONN_IRQ_5			(GIC_SPI_START + 9)
+#define TLMM_MSM_DIR_CONN_IRQ_6			(GIC_SPI_START + 10)
+#define TLMM_MSM_DIR_CONN_IRQ_7			(GIC_SPI_START + 11)
+#define TLMM_MSM_DIR_CONN_IRQ_8			(GIC_SPI_START + 12)
+#define TLMM_MSM_DIR_CONN_IRQ_9			(GIC_SPI_START + 13)
+#define PM8921_SEC_IRQ_103			(GIC_SPI_START + 14)
+#define PM8018_SEC_IRQ_106			(GIC_SPI_START + 15)
+#define TLMM_MSM_SUMMARY_IRQ			(GIC_SPI_START + 16)
+#define SPDM_RT_1_IRQ				(GIC_SPI_START + 17)
+#define SPDM_DIAG_IRQ				(GIC_SPI_START + 18)
+#define RPM_APCC_CPU0_GP_HIGH_IRQ		(GIC_SPI_START + 19)
+#define RPM_APCC_CPU0_GP_MEDIUM_IRQ		(GIC_SPI_START + 20)
+#define RPM_APCC_CPU0_GP_LOW_IRQ		(GIC_SPI_START + 21)
+#define RPM_APCC_CPU0_WAKE_UP_IRQ		(GIC_SPI_START + 22)
+#define RPM_APCC_CPU1_GP_HIGH_IRQ		(GIC_SPI_START + 23)
+#define RPM_APCC_CPU1_GP_MEDIUM_IRQ		(GIC_SPI_START + 24)
+#define RPM_APCC_CPU1_GP_LOW_IRQ		(GIC_SPI_START + 25)
+#define RPM_APCC_CPU1_WAKE_UP_IRQ		(GIC_SPI_START + 26)
+#define SSBI2_2_SC_CPU0_SECURE_IRQ		(GIC_SPI_START + 27)
+#define SSBI2_2_SC_CPU0_NON_SECURE_IRQ		(GIC_SPI_START + 28)
+#define SSBI2_1_SC_CPU0_SECURE_IRQ		(GIC_SPI_START + 29)
+#define SSBI2_1_SC_CPU0_NON_SECURE_IRQ		(GIC_SPI_START + 30)
+#define MSMC_SC_SEC_CE_IRQ			(GIC_SPI_START + 31)
+#define MSMC_SC_PRI_CE_IRQ			(GIC_SPI_START + 32)
+#define SLIMBUS0_CORE_EE1_IRQ			(GIC_SPI_START + 33)
+#define SLIMBUS0_BAM_EE1_IRQ			(GIC_SPI_START + 34)
+#define Q6FW_WDOG_EXPIRED_IRQ			(GIC_SPI_START + 35)
+#define Q6SW_WDOG_EXPIRED_IRQ			(GIC_SPI_START + 36)
+#define MSS_TO_APPS_IRQ_0			(GIC_SPI_START + 37)
+#define MSS_TO_APPS_IRQ_1			(GIC_SPI_START + 38)
+#define MSS_TO_APPS_IRQ_2			(GIC_SPI_START + 39)
+#define MSS_TO_APPS_IRQ_3			(GIC_SPI_START + 40)
+#define MSS_TO_APPS_IRQ_4			(GIC_SPI_START + 41)
+#define MSS_TO_APPS_IRQ_5			(GIC_SPI_START + 42)
+#define MSS_TO_APPS_IRQ_6			(GIC_SPI_START + 43)
+#define MSS_TO_APPS_IRQ_7			(GIC_SPI_START + 44)
+#define MSS_TO_APPS_IRQ_8			(GIC_SPI_START + 45)
+#define MSS_TO_APPS_IRQ_9			(GIC_SPI_START + 46)
+#define VPE_IRQ					(GIC_SPI_START + 47)
+#define VFE_IRQ					(GIC_SPI_START + 48)
+#define VCODEC_IRQ				(GIC_SPI_START + 49)
+/* SPI IRQ 50 is unused */
+#define SMMU_VPE_CB_SC_SECURE_IRQ		(GIC_SPI_START + 51)
+#define SMMU_VPE_CB_SC_NON_SECURE_IRQ		(GIC_SPI_START + 52)
+#define SMMU_VFE_CB_SC_SECURE_IRQ		(GIC_SPI_START + 53)
+#define SMMU_VFE_CB_SC_NON_SECURE_IRQ		(GIC_SPI_START + 54)
+#define SMMU_VCODEC_B_CB_SC_SECURE_IRQ		(GIC_SPI_START + 55)
+#define SMMU_VCODEC_B_CB_SC_NON_SECURE_IRQ	(GIC_SPI_START + 56)
+#define SMMU_VCODEC_A_CB_SC_SECURE_IRQ		(GIC_SPI_START + 57)
+#define SMMU_VCODEC_A_CB_SC_NON_SECURE_IRQ	(GIC_SPI_START + 58)
+#define SMMU_ROT_CB_SC_SECURE_IRQ		(GIC_SPI_START + 59)
+#define SMMU_ROT_CB_SC_NON_SECURE_IRQ		(GIC_SPI_START + 60)
+#define SMMU_MDP1_CB_SC_SECURE_IRQ		(GIC_SPI_START + 61)
+#define SMMU_MDP1_CB_SC_NON_SECURE_IRQ		(GIC_SPI_START + 62)
+#define SMMU_MDP0_CB_SC_SECURE_IRQ		(GIC_SPI_START + 63)
+#define SMMU_MDP0_CB_SC_NON_SECURE_IRQ		(GIC_SPI_START + 64)
+/* SPI IRQ 65 is unused */
+/* SPI IRQ 66 is unused */
+#define SMMU_IJPEG_CB_SC_SECURE_IRQ		(GIC_SPI_START + 67)
+#define SMMU_IJPEG_CB_SC_NON_SECURE_IRQ		(GIC_SPI_START + 68)
+#define SMMU_GFX3D_CB_SC_SECURE_IRQ		(GIC_SPI_START + 69)
+#define SMMU_GFX3D_CB_SC_NON_SECURE_IRQ		(GIC_SPI_START + 70)
+/* SPI IRQ 71 is unused */
+/* SPI IRQ 72 is unused */
+#define ROT_IRQ					(GIC_SPI_START + 73)
+#define MMSS_FABRIC_IRQ				(GIC_SPI_START + 74)
+#define MDP_IRQ					(GIC_SPI_START + 75)
+/* SPI IRQ 76 is unused */
+#define JPEG_IRQ				(GIC_SPI_START + 77)
+#define MMSS_IMEM_IRQ				(GIC_SPI_START + 78)
+#define HDMI_IRQ				(GIC_SPI_START + 79)
+#define GFX3D_IRQ				(GIC_SPI_START + 80)
+/* SPI IRQ 81 is unused */
+#define DSI1_IRQ				(GIC_SPI_START + 82)
+#define CSI_1_IRQ				(GIC_SPI_START + 83)
+#define CSI_0_IRQ				(GIC_SPI_START + 84)
+#define LPASS_SCSS_AUDIO_IF_OUT0_IRQ		(GIC_SPI_START + 85)
+#define LPASS_SCSS_MIDI_IRQ			(GIC_SPI_START + 86)
+#define LPASS_Q6SS_WDOG_EXPIRED			(GIC_SPI_START + 87)
+#define LPASS_SCSS_GP_LOW_IRQ			(GIC_SPI_START + 88)
+#define LPASS_SCSS_GP_MEDIUM_IRQ		(GIC_SPI_START + 89)
+#define LPASS_SCSS_GP_HIGH_IRQ			(GIC_SPI_START + 90)
+#define TOP_IMEM_IRQ				(GIC_SPI_START + 91)
+#define FABRIC_SYS_IRQ				(GIC_SPI_START + 92)
+#define FABRIC_APPS_IRQ				(GIC_SPI_START + 93)
+#define USB1_HS_BAM_IRQ				(GIC_SPI_START + 94)
+#define SDC4_BAM_IRQ				(GIC_SPI_START + 95)
+#define SDC3_BAM_IRQ				(GIC_SPI_START + 96)
+#define SDC2_BAM_IRQ				(GIC_SPI_START + 97)
+#define SDC1_BAM_IRQ				(GIC_SPI_START + 98)
+#define FABRIC_SPS_IRQ				(GIC_SPI_START + 99)
+#define USB1_HS_IRQ				(GIC_SPI_START + 100)
+#define SDC4_IRQ_0				(GIC_SPI_START + 101)
+#define SDC3_IRQ_0				(GIC_SPI_START + 102)
+#define SDC2_IRQ_0				(GIC_SPI_START + 103)
+#define SDC1_IRQ_0				(GIC_SPI_START + 104)
+#define SPS_BAM_DMA_IRQ				(GIC_SPI_START + 105)
+#define SPS_SEC_VIOL_IRQ			(GIC_SPI_START + 106)
+#define SPS_MTI_0				(GIC_SPI_START + 107)
+#define SPS_MTI_1				(GIC_SPI_START + 108)
+#define SPS_MTI_2				(GIC_SPI_START + 109)
+#define SPS_MTI_3				(GIC_SPI_START + 110)
+#define GPS_PPS_OUT				(GIC_SPI_START + 111)
+/* SPI IRQ 112 is unused */
+/* SPI IRQ 113 is unused */
+/* SPI IRQ 114 is unused */
+/* SPI IRQ 115 is unused */
+#define TLMM_MSM_DIR_CONN_IRQ_11		(GIC_SPI_START + 116)
+#define TLMM_MSM_DIR_CONN_IRQ_10		(GIC_SPI_START + 117)
+#define BAM_DMA1				(GIC_SPI_START + 118)
+#define BAM_DMA2				(GIC_SPI_START + 119)
+#define SDC1_IRQ				(GIC_SPI_START + 120)
+#define SDC2_IRQ				(GIC_SPI_START + 121)
+#define SDC3_IRQ				(GIC_SPI_START + 122)
+#define SPS_MTI_16				(GIC_SPI_START + 123)
+#define SPS_MTI_17				(GIC_SPI_START + 124)
+#define SPS_MTI_18				(GIC_SPI_START + 125)
+#define SPS_MTI_19				(GIC_SPI_START + 126)
+#define SPS_MTI_20				(GIC_SPI_START + 127)
+#define SPS_MTI_21				(GIC_SPI_START + 128)
+#define SPS_MTI_22				(GIC_SPI_START + 129)
+#define SPS_MTI_23				(GIC_SPI_START + 130)
+#define SPS_MTI_24				(GIC_SPI_START + 131)
+#define SPS_MTI_25				(GIC_SPI_START + 132)
+#define SPS_MTI_26				(GIC_SPI_START + 133)
+#define SPS_MTI_27				(GIC_SPI_START + 134)
+#define SPS_MTI_28				(GIC_SPI_START + 135)
+#define SPS_MTI_29				(GIC_SPI_START + 136)
+#define SPS_MTI_30				(GIC_SPI_START + 137)
+#define SPS_MTI_31				(GIC_SPI_START + 138)
+#define CSIPHY_4LN_IRQ				(GIC_SPI_START + 139)
+#define MSM8930_CSIPHY_2LN_IRQ			(GIC_SPI_START + 140)
+#define USB2_IRQ				(GIC_SPI_START + 141)
+#define USB1_IRQ				(GIC_SPI_START + 142)
+#define TSSC_SSBI_IRQ				(GIC_SPI_START + 143)
+#define TSSC_SAMPLE_IRQ				(GIC_SPI_START + 144)
+#define TSSC_PENUP_IRQ				(GIC_SPI_START + 145)
+#define MSM8930_GSBI1_UARTDM_IRQ		(GIC_SPI_START + 146)
+#define MSM8930_GSBI1_QUP_IRQ			(GIC_SPI_START + 147)
+#define MSM8930_GSBI2_UARTDM_IRQ		(GIC_SPI_START + 148)
+#define MSM8930_GSBI2_QUP_IRQ		        (GIC_SPI_START + 149)
+#define GSBI3_UARTDM_IRQ			(GIC_SPI_START + 150)
+#define GSBI3_QUP_IRQ				(GIC_SPI_START + 151)
+#define GSBI4_UARTDM_IRQ			(GIC_SPI_START + 152)
+#define GSBI4_QUP_IRQ				(GIC_SPI_START + 153)
+#define GSBI5_UARTDM_IRQ			(GIC_SPI_START + 154)
+#define GSBI5_QUP_IRQ				(GIC_SPI_START + 155)
+#define GSBI6_UARTDM_IRQ			(GIC_SPI_START + 156)
+#define GSBI6_QUP_IRQ				(GIC_SPI_START + 157)
+#define GSBI7_UARTDM_IRQ			(GIC_SPI_START + 158)
+#define GSBI7_QUP_IRQ				(GIC_SPI_START + 159)
+#define GSBI8_UARTDM_IRQ			(GIC_SPI_START + 160)
+#define GSBI8_QUP_IRQ				(GIC_SPI_START + 161)
+#define TSIF_TSPP_IRQ				(GIC_SPI_START + 162)
+#define TSIF_BAM_IRQ				(GIC_SPI_START + 163)
+#define TSIF2_IRQ				(GIC_SPI_START + 164)
+#define TSIF1_IRQ				(GIC_SPI_START + 165)
+/* SPI IRQ 166 is unused */
+#define ISPIF_IRQ				(GIC_SPI_START + 167)
+#define MSMC_SC_SEC_TMR_IRQ			(GIC_SPI_START + 168)
+#define MSMC_SC_SEC_WDOG_BARK_IRQ		(GIC_SPI_START + 169)
+#define ADM_0_SCSS_0_IRQ			(GIC_SPI_START + 170)
+#define ADM_0_SCSS_1_IRQ			(GIC_SPI_START + 171)
+#define ADM_0_SCSS_2_IRQ			(GIC_SPI_START + 172)
+#define ADM_0_SCSS_3_IRQ			(GIC_SPI_START + 173)
+#define CC_SCSS_WDT1CPU1BITEEXPIRED		(GIC_SPI_START + 174)
+#define CC_SCSS_WDT1CPU0BITEEXPIRED		(GIC_SPI_START + 175)
+#define CC_SCSS_WDT0CPU1BITEEXPIRED		(GIC_SPI_START + 176)
+#define CC_SCSS_WDT0CPU0BITEEXPIRED		(GIC_SPI_START + 177)
+#define TSENS_UPPER_LOWER_INT			(GIC_SPI_START + 178)
+#define SSBI2_2_SC_CPU1_SECURE_INT		(GIC_SPI_START + 179)
+#define SSBI2_2_SC_CPU1_NON_SECURE_INT		(GIC_SPI_START + 180)
+#define SSBI2_1_SC_CPU1_SECURE_INT		(GIC_SPI_START + 181)
+#define SSBI2_1_SC_CPU1_NON_SECURE_INT		(GIC_SPI_START + 182)
+#define XPU_SUMMARY_IRQ				(GIC_SPI_START + 183)
+#define BUS_EXCEPTION_SUMMARY_IRQ		(GIC_SPI_START + 184)
+#define HSDDRX_EBI1CH0_IRQ			(GIC_SPI_START + 185)
+/* SPI IRQ 186 is unused */
+#define SDC5_BAM_IRQ				(GIC_SPI_START + 187)
+#define SDC5_IRQ_0				(GIC_SPI_START + 188)
+#define GSBI9_UARTDM_IRQ			(GIC_SPI_START + 189)
+#define GSBI9_QUP_IRQ				(GIC_SPI_START + 190)
+#define GSBI10_UARTDM_IRQ			(GIC_SPI_START + 191)
+#define GSBI10_QUP_IRQ				(GIC_SPI_START + 192)
+#define GSBI11_UARTDM_IRQ			(GIC_SPI_START + 193)
+#define GSBI11_QUP_IRQ				(GIC_SPI_START + 194)
+#define GSBI12_UARTDM_IRQ			(GIC_SPI_START + 195)
+#define GSBI12_QUP_IRQ				(GIC_SPI_START + 196)
+#define RIVA_APSS_LTECOEX_IRQ			(GIC_SPI_START + 197)
+#define RIVA_APSS_SPARE_IRQ			(GIC_SPI_START + 198)
+#define RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ	(GIC_SPI_START + 199)
+#define RIVA_APSS_RESET_DONE_IRQ		(GIC_SPI_START + 200)
+#define RIVA_APSS_ASIC_IRQ			(GIC_SPI_START + 201)
+#define RIVA_APPS_WLAN_RX_DATA_AVAIL_IRQ	(GIC_SPI_START + 202)
+#define RIVA_APPS_WLAN_DATA_XFER_DONE_IRQ	(GIC_SPI_START + 203)
+#define RIVA_APPS_WLAN_SMSM_IRQ			(GIC_SPI_START + 204)
+#define RIVA_APPS_LOG_CTRL_IRQ			(GIC_SPI_START + 205)
+#define RIVA_APPS_FM_CTRL_IRQ			(GIC_SPI_START + 206)
+#define RIVA_APPS_HCI_IRQ			(GIC_SPI_START + 207)
+#define RIVA_APPS_WLAN_CTRL_IRQ			(GIC_SPI_START + 208)
+#define A2_BAM_IRQ				(GIC_SPI_START + 209)
+/* SPI IRQ 210 is unused */
+/* SPI IRQ 211 is unused */
+/* SPI IRQ 212 is unused */
+#define PPSS_WDOG_TIMER_IRQ			(GIC_SPI_START + 213)
+#define SPS_SLIMBUS_CORE_EE0_IRQ		(GIC_SPI_START + 214)
+#define SPS_SLIMBUS_BAM_EE0_IRQ			(GIC_SPI_START + 215)
+#define QDSS_ETB_IRQ				(GIC_SPI_START + 216)
+#define QDSS_CTI2KPSS_CPU1_IRQ			(GIC_SPI_START + 217)
+#define QDSS_CTI2KPSS_CPU0_IRQ			(GIC_SPI_START + 218)
+#define TLMM_MSM_DIR_CONN_IRQ_16		(GIC_SPI_START + 219)
+#define TLMM_MSM_DIR_CONN_IRQ_17		(GIC_SPI_START + 220)
+#define TLMM_MSM_DIR_CONN_IRQ_18		(GIC_SPI_START + 221)
+#define TLMM_MSM_DIR_CONN_IRQ_19		(GIC_SPI_START + 222)
+#define TLMM_MSM_DIR_CONN_IRQ_20		(GIC_SPI_START + 223)
+#define TLMM_MSM_DIR_CONN_IRQ_21		(GIC_SPI_START + 224)
+#define PM8921_SEC_IRQ_104			(GIC_SPI_START + 225)
+#define PM8018_SEC_IRQ_107			(GIC_SPI_START + 226)
+#define USB_HSIC_IRQ				(GIC_SPI_START + 229)
+#define CE2_BAM_XPU_IRQ				(GIC_SPI_START + 230)
+#define CE1_BAM_XPU_IRQ				(GIC_SPI_START + 231)
+#define GFX3D_VBIF_IRPT				(GIC_SPI_START + 232)
+#define RBIF_IRQ_0				(GIC_SPI_START + 233)
+#define RBIF_IRQ_1				(GIC_SPI_START + 234)
+#define RBIF_IRQ_2				(GIC_SPI_START + 235)
+
+/* Backwards compatible IRQ macros. */
+#define INT_ADM_AARM				ADM_0_SCSS_0_IRQ
+
+/* smd/smsm interrupts */
+#define INT_A9_M2A_0		(GIC_SPI_START + 37) /*MSS_TO_APPS_IRQ_0*/
+#define INT_A9_M2A_5		(GIC_SPI_START + 38) /*MSS_TO_APPS_IRQ_1*/
+#define INT_ADSP_A11		LPASS_SCSS_GP_HIGH_IRQ
+#define INT_ADSP_A11_SMSM	LPASS_SCSS_GP_MEDIUM_IRQ
+#define INT_DSPS_A11		SPS_MTI_31
+#define INT_DSPS_A11_SMSM	SPS_MTI_30
+#define INT_WCNSS_A11		RIVA_APSS_SPARE_IRQ
+#define INT_WCNSS_A11_SMSM	RIVA_APPS_WLAN_SMSM_IRQ
+
+#endif
+
diff --git a/arch/arm/mach-msm/include/mach/irqs-8960.h b/arch/arm/mach-msm/include/mach/irqs-8960.h
index 81ab2a6..012dd74 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8960.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8960.h
@@ -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
@@ -32,30 +32,31 @@
 #define AVS_SVICINTSWDONE			(GIC_PPI_START + 7)
 #define CPU_DBGCPUXCOMMRXFULL			(GIC_PPI_START + 8)
 #define CPU_DBGCPUXCOMMTXEMPTY			(GIC_PPI_START + 9)
-#define CPU_SICCPUXPERFMONIRPTREQ		(GIC_PPI_START + 10)
+#define INT_ARMQC_PERFMON			(GIC_PPI_START + 10)
 #define SC_AVSCPUXDOWN				(GIC_PPI_START + 11)
 #define SC_AVSCPUXUP				(GIC_PPI_START + 12)
 #define SC_SICCPUXACGIRPTREQ			(GIC_PPI_START + 13)
 #define SC_SICCPUXEXTFAULTIRPTREQ		(GIC_PPI_START + 14)
 /* PPI 15 is unused */
 
-#define SC_SICMPUIRPTREQ			(GIC_SPI_START + 0)
-#define SC_SICL2IRPTREQ				(GIC_SPI_START + 1)
-#define SC_SICL2PERFMONIRPTREQ			(GIC_SPI_START + 2)
-#define SC_SICAGCIRPTREQ			(GIC_SPI_START + 3)
-#define TLMM_APCC_DIR_CONN_IRQ_0		(GIC_SPI_START + 4)
-#define TLMM_APCC_DIR_CONN_IRQ_1		(GIC_SPI_START + 5)
-#define TLMM_APCC_DIR_CONN_IRQ_2		(GIC_SPI_START + 6)
-#define TLMM_APCC_DIR_CONN_IRQ_3		(GIC_SPI_START + 7)
-#define TLMM_APCC_DIR_CONN_IRQ_4		(GIC_SPI_START + 8)
-#define TLMM_APCC_DIR_CONN_IRQ_5		(GIC_SPI_START + 9)
-#define TLMM_APCC_DIR_CONN_IRQ_6		(GIC_SPI_START + 10)
-#define TLMM_APCC_DIR_CONN_IRQ_7		(GIC_SPI_START + 11)
-#define TLMM_APCC_DIR_CONN_IRQ_8		(GIC_SPI_START + 12)
-#define TLMM_APCC_DIR_CONN_IRQ_9		(GIC_SPI_START + 13)
+#define APCC_QGICACGIRPTREQ			(GIC_SPI_START + 0)
+#define APCC_QGICL2PERFMONIRPTREQ		(GIC_SPI_START + 1)
+#define SC_SICL2PERFMONIRPTREQ			APCC_QGICL2PERFMONIRPTREQ
+#define APCC_QGICL2IRPTREQ			(GIC_SPI_START + 2)
+#define APCC_QGICMPUIRPTREQ			(GIC_SPI_START + 3)
+#define TLMM_MSM_DIR_CONN_IRQ_0			(GIC_SPI_START + 4)
+#define TLMM_MSM_DIR_CONN_IRQ_1			(GIC_SPI_START + 5)
+#define TLMM_MSM_DIR_CONN_IRQ_2			(GIC_SPI_START + 6)
+#define TLMM_MSM_DIR_CONN_IRQ_3			(GIC_SPI_START + 7)
+#define TLMM_MSM_DIR_CONN_IRQ_4			(GIC_SPI_START + 8)
+#define TLMM_MSM_DIR_CONN_IRQ_5			(GIC_SPI_START + 9)
+#define TLMM_MSM_DIR_CONN_IRQ_6			(GIC_SPI_START + 10)
+#define TLMM_MSM_DIR_CONN_IRQ_7			(GIC_SPI_START + 11)
+#define TLMM_MSM_DIR_CONN_IRQ_8			(GIC_SPI_START + 12)
+#define TLMM_MSM_DIR_CONN_IRQ_9			(GIC_SPI_START + 13)
 #define PM8921_SEC_IRQ_103			(GIC_SPI_START + 14)
 #define PM8018_SEC_IRQ_106			(GIC_SPI_START + 15)
-#define TLMM_APCC_SUMMARY_IRQ			(GIC_SPI_START + 16)
+#define TLMM_MSM_SUMMARY_IRQ			(GIC_SPI_START + 16)
 #define SPDM_RT_1_IRQ				(GIC_SPI_START + 17)
 #define SPDM_DIAG_IRQ				(GIC_SPI_START + 18)
 #define RPM_APCC_CPU0_GP_HIGH_IRQ		(GIC_SPI_START + 19)
@@ -179,16 +180,16 @@
 #define SPS_MTI_30				(GIC_SPI_START + 137)
 #define SPS_MTI_31				(GIC_SPI_START + 138)
 #define CSIPHY_4LN_IRQ				(GIC_SPI_START + 139)
-#define CSIPHY_2LN_IRQ				(GIC_SPI_START + 140)
+#define MSM8960_CSIPHY_2LN_IRQ			(GIC_SPI_START + 140)
 #define USB2_IRQ				(GIC_SPI_START + 141)
 #define USB1_IRQ				(GIC_SPI_START + 142)
 #define TSSC_SSBI_IRQ				(GIC_SPI_START + 143)
 #define TSSC_SAMPLE_IRQ				(GIC_SPI_START + 144)
 #define TSSC_PENUP_IRQ				(GIC_SPI_START + 145)
-#define GSBI1_UARTDM_IRQ			(GIC_SPI_START + 146)
-#define GSBI1_QUP_IRQ				(GIC_SPI_START + 147)
-#define GSBI2_UARTDM_IRQ			(GIC_SPI_START + 148)
-#define GSBI2_QUP_IRQ			        (GIC_SPI_START + 149)
+#define MSM8960_GSBI1_UARTDM_IRQ		(GIC_SPI_START + 146)
+#define MSM8960_GSBI1_QUP_IRQ			(GIC_SPI_START + 147)
+#define MSM8960_GSBI2_UARTDM_IRQ		(GIC_SPI_START + 148)
+#define MSM8960_GSBI2_QUP_IRQ		        (GIC_SPI_START + 149)
 #define GSBI3_UARTDM_IRQ			(GIC_SPI_START + 150)
 #define GSBI3_QUP_IRQ				(GIC_SPI_START + 151)
 #define GSBI4_UARTDM_IRQ			(GIC_SPI_START + 152)
@@ -209,10 +210,10 @@
 #define ISPIF_IRQ				(GIC_SPI_START + 167)
 #define MSMC_SC_SEC_TMR_IRQ			(GIC_SPI_START + 168)
 #define MSMC_SC_SEC_WDOG_BARK_IRQ		(GIC_SPI_START + 169)
-#define INT_ADM0_SCSS_0_IRQ			(GIC_SPI_START + 170)
-#define INT_ADM0_SCSS_1_IRQ			(GIC_SPI_START + 171)
-#define INT_ADM0_SCSS_2_IRQ			(GIC_SPI_START + 172)
-#define INT_ADM0_SCSS_3_IRQ			(GIC_SPI_START + 173)
+#define ADM_0_SCSS_0_IRQ			(GIC_SPI_START + 170)
+#define ADM_0_SCSS_1_IRQ			(GIC_SPI_START + 171)
+#define ADM_0_SCSS_2_IRQ			(GIC_SPI_START + 172)
+#define ADM_0_SCSS_3_IRQ			(GIC_SPI_START + 173)
 #define CC_SCSS_WDT1CPU1BITEEXPIRED		(GIC_SPI_START + 174)
 #define CC_SCSS_WDT1CPU0BITEEXPIRED		(GIC_SPI_START + 175)
 #define CC_SCSS_WDT0CPU1BITEEXPIRED		(GIC_SPI_START + 176)
@@ -239,11 +240,11 @@
 #define RIVA_APSS_LTECOEX_IRQ			(GIC_SPI_START + 197)
 #define RIVA_APSS_SPARE_IRQ			(GIC_SPI_START + 198)
 #define RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ	(GIC_SPI_START + 199)
-#define RIVA_ASS_RESET_DONE_IRQ			(GIC_SPI_START + 200)
+#define RIVA_APSS_RESET_DONE_IRQ		(GIC_SPI_START + 200)
 #define RIVA_APSS_ASIC_IRQ			(GIC_SPI_START + 201)
 #define RIVA_APPS_WLAN_RX_DATA_AVAIL_IRQ	(GIC_SPI_START + 202)
 #define RIVA_APPS_WLAN_DATA_XFER_DONE_IRQ	(GIC_SPI_START + 203)
-#define RIVA_APPS_WLAM_SMSM_IRQ			(GIC_SPI_START + 204)
+#define RIVA_APPS_WLAN_SMSM_IRQ			(GIC_SPI_START + 204)
 #define RIVA_APPS_LOG_CTRL_IRQ			(GIC_SPI_START + 205)
 #define RIVA_APPS_FM_CTRL_IRQ			(GIC_SPI_START + 206)
 #define RIVA_APPS_HCI_IRQ			(GIC_SPI_START + 207)
@@ -258,20 +259,30 @@
 #define QDSS_ETB_IRQ				(GIC_SPI_START + 216)
 #define QDSS_CTI2KPSS_CPU1_IRQ			(GIC_SPI_START + 217)
 #define QDSS_CTI2KPSS_CPU0_IRQ			(GIC_SPI_START + 218)
-#define TLMM_APCC_DIR_CONN_IRQ_16		(GIC_SPI_START + 219)
-#define TLMM_APCC_DIR_CONN_IRQ_17		(GIC_SPI_START + 220)
-#define TLMM_APCC_DIR_CONN_IRQ_18		(GIC_SPI_START + 221)
-#define TLMM_APCC_DIR_CONN_IRQ_19		(GIC_SPI_START + 222)
-#define TLMM_APCC_DIR_CONN_IRQ_20		(GIC_SPI_START + 223)
-#define TLMM_APCC_DIR_CONN_IRQ_21		(GIC_SPI_START + 224)
+#define TLMM_MSM_DIR_CONN_IRQ_16		(GIC_SPI_START + 219)
+#define TLMM_MSM_DIR_CONN_IRQ_17		(GIC_SPI_START + 220)
+#define TLMM_MSM_DIR_CONN_IRQ_18		(GIC_SPI_START + 221)
+#define TLMM_MSM_DIR_CONN_IRQ_19		(GIC_SPI_START + 222)
+#define TLMM_MSM_DIR_CONN_IRQ_20		(GIC_SPI_START + 223)
+#define TLMM_MSM_DIR_CONN_IRQ_21		(GIC_SPI_START + 224)
 #define PM8921_SEC_IRQ_104			(GIC_SPI_START + 225)
 #define PM8018_SEC_IRQ_107			(GIC_SPI_START + 226)
+#define USB_HSIC_IRQ				(GIC_SPI_START + 229)
+#define MSM8960_CSIPHY_2_2LN_IRQ		(GIC_SPI_START + 228)
+#define CSI_2_IRQ				(GIC_SPI_START + 227)
 
-/* For now, use the maximum number of interrupts until a pending GIC issue
- * is sorted out */
-#define NR_MSM_IRQS 1020
-#define NR_BOARD_IRQS 0
-#define NR_GPIO_IRQS 0
+/* Backwards compatible IRQ macros. */
+#define INT_ADM_AARM				ADM_0_SCSS_0_IRQ
+
+/* smd/smsm interrupts */
+#define INT_A9_M2A_0		(GIC_SPI_START + 37) /*MSS_TO_APPS_IRQ_0*/
+#define INT_A9_M2A_5		(GIC_SPI_START + 38) /*MSS_TO_APPS_IRQ_1*/
+#define INT_ADSP_A11		LPASS_SCSS_GP_HIGH_IRQ
+#define INT_ADSP_A11_SMSM	LPASS_SCSS_GP_MEDIUM_IRQ
+#define INT_DSPS_A11		SPS_MTI_31
+#define INT_DSPS_A11_SMSM	SPS_MTI_30
+#define INT_WCNSS_A11		RIVA_APSS_SPARE_IRQ
+#define INT_WCNSS_A11_SMSM	RIVA_APPS_WLAN_SMSM_IRQ
 
 #endif
 
diff --git a/arch/arm/mach-msm/include/mach/irqs-8x50.h b/arch/arm/mach-msm/include/mach/irqs-8x50.h
index 26adbe0..f0d70f9 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8x50.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8x50.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2010, 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
@@ -57,7 +57,7 @@
 #define INT_TCSR_MPRPH_SC2   (32 + 6)
 #define INT_OP_PEN           (32 + 7)
 #define INT_AD_HSSD          (32 + 8)
-#define INT_ARM11_PM         (32 + 9)
+#define INT_ARMQC_PERFMON    (32 + 9)
 #define INT_SDMA_NON_SECURE  (32 + 10)
 #define INT_TSIF_IRQ         (32 + 11)
 #define INT_UART1DM_IRQ      (32 + 12)
@@ -85,4 +85,5 @@
 #define NR_MSM_IRQS 64
 #define NR_BOARD_IRQS 64
 
+#define INT_ADSP_A11_SMSM    INT_ADSP_A11
 #endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-8x60.h b/arch/arm/mach-msm/include/mach/irqs-8x60.h
index f65841c..c9729f4 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8x60.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8x60.h
@@ -1,8 +1,8 @@
-/* Copyright (c) 2010 Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2011 Code Aurora Forum. 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 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
@@ -17,9 +17,8 @@
 /* MSM ACPU Interrupt Numbers */
 
 /* 0-15:  STI/SGI (software triggered/generated interrupts)
- * 16-31: PPI (private peripheral interrupts)
- * 32+:   SPI (shared peripheral interrupts)
- */
+   16-31: PPI (private peripheral interrupts)
+   32+:   SPI (shared peripheral interrupts) */
 
 #define GIC_PPI_START 16
 #define GIC_SPI_START 32
@@ -33,7 +32,7 @@
 #define AVS_SVICINTSWDONE			(GIC_PPI_START + 6)
 #define CPU_DBGCPUXCOMMRXFULL			(GIC_PPI_START + 7)
 #define CPU_DBGCPUXCOMMTXEMPTY			(GIC_PPI_START + 8)
-#define CPU_SICCPUXPERFMONIRPTREQ		(GIC_PPI_START + 9)
+#define INT_ARMQC_PERFMON			(GIC_PPI_START + 9)
 #define SC_AVSCPUXDOWN				(GIC_PPI_START + 10)
 #define SC_AVSCPUXUP				(GIC_PPI_START + 11)
 #define SC_SICCPUXACGIRPTREQ			(GIC_PPI_START + 12)
@@ -42,21 +41,21 @@
 
 #define SC_SICMPUIRPTREQ			(GIC_SPI_START + 0)
 #define SC_SICL2IRPTREQ				(GIC_SPI_START + 1)
-#define SC_SICL2ACGIRPTREQ			(GIC_SPI_START + 2)
+#define SC_SICL2PERFMONIRPTREQ			(GIC_SPI_START + 2)
 #define NC					(GIC_SPI_START + 3)
-#define TLMM_SCSS_DIR_CONN_IRQ_0		(GIC_SPI_START + 4)
-#define TLMM_SCSS_DIR_CONN_IRQ_1		(GIC_SPI_START + 5)
-#define TLMM_SCSS_DIR_CONN_IRQ_2		(GIC_SPI_START + 6)
-#define TLMM_SCSS_DIR_CONN_IRQ_3		(GIC_SPI_START + 7)
-#define TLMM_SCSS_DIR_CONN_IRQ_4		(GIC_SPI_START + 8)
-#define TLMM_SCSS_DIR_CONN_IRQ_5		(GIC_SPI_START + 9)
-#define TLMM_SCSS_DIR_CONN_IRQ_6		(GIC_SPI_START + 10)
-#define TLMM_SCSS_DIR_CONN_IRQ_7		(GIC_SPI_START + 11)
-#define TLMM_SCSS_DIR_CONN_IRQ_8		(GIC_SPI_START + 12)
-#define TLMM_SCSS_DIR_CONN_IRQ_9		(GIC_SPI_START + 13)
+#define TLMM_MSM_DIR_CONN_IRQ_0			(GIC_SPI_START + 4)
+#define TLMM_MSM_DIR_CONN_IRQ_1			(GIC_SPI_START + 5)
+#define TLMM_MSM_DIR_CONN_IRQ_2			(GIC_SPI_START + 6)
+#define TLMM_MSM_DIR_CONN_IRQ_3			(GIC_SPI_START + 7)
+#define TLMM_MSM_DIR_CONN_IRQ_4			(GIC_SPI_START + 8)
+#define TLMM_MSM_DIR_CONN_IRQ_5			(GIC_SPI_START + 9)
+#define TLMM_MSM_DIR_CONN_IRQ_6			(GIC_SPI_START + 10)
+#define TLMM_MSM_DIR_CONN_IRQ_7			(GIC_SPI_START + 11)
+#define TLMM_MSM_DIR_CONN_IRQ_8			(GIC_SPI_START + 12)
+#define TLMM_MSM_DIR_CONN_IRQ_9			(GIC_SPI_START + 13)
 #define PM8058_SEC_IRQ_N			(GIC_SPI_START + 14)
 #define PM8901_SEC_IRQ_N			(GIC_SPI_START + 15)
-#define TLMM_SCSS_SUMMARY_IRQ			(GIC_SPI_START + 16)
+#define TLMM_MSM_SUMMARY_IRQ			(GIC_SPI_START + 16)
 #define SPDM_RT_1_IRQ				(GIC_SPI_START + 17)
 #define SPDM_DIAG_IRQ				(GIC_SPI_START + 18)
 #define RPM_SCSS_CPU0_GP_HIGH_IRQ		(GIC_SPI_START + 19)
@@ -87,7 +86,7 @@
 #define MARM_SCSS_GP_IRQ_7			(GIC_SPI_START + 44)
 #define MARM_SCSS_GP_IRQ_8			(GIC_SPI_START + 45)
 #define MARM_SCSS_GP_IRQ_9			(GIC_SPI_START + 46)
-#define VPE_IRQ					(GIC_SPI_START + 47)
+#define INT_VPE					(GIC_SPI_START + 47)
 #define VFE_IRQ					(GIC_SPI_START + 48)
 #define VCODEC_IRQ				(GIC_SPI_START + 49)
 #define TV_ENC_IRQ				(GIC_SPI_START + 50)
@@ -115,9 +114,9 @@
 #define SMMU_GFX2D0_CB_SC_NON_SECURE_IRQ	(GIC_SPI_START + 72)
 #define ROT_IRQ					(GIC_SPI_START + 73)
 #define MMSS_FABRIC_IRQ				(GIC_SPI_START + 74)
-#define MDP_IRQ					(GIC_SPI_START + 75)
+#define INT_MDP					(GIC_SPI_START + 75)
 #define JPEGD_IRQ				(GIC_SPI_START + 76)
-#define JPEG_IRQ				(GIC_SPI_START + 77)
+#define INT_JPEG				(GIC_SPI_START + 77)
 #define MMSS_IMEM_IRQ				(GIC_SPI_START + 78)
 #define HDMI_IRQ				(GIC_SPI_START + 79)
 #define GFX3D_IRQ				(GIC_SPI_START + 80)
@@ -186,21 +185,21 @@
 #define TSSC_SSBI_IRQ				(GIC_SPI_START + 143)
 #define TSSC_SAMPLE_IRQ				(GIC_SPI_START + 144)
 #define TSSC_PENUP_IRQ				(GIC_SPI_START + 145)
-#define INT_UART1DM_IRQ				(GIC_SPI_START + 146)
-#define GSBI1_QUP_IRQ				(GIC_SPI_START + 147)
-#define INT_UART2DM_IRQ				(GIC_SPI_START + 148)
-#define GSBI2_QUP_IRQ				(GIC_SPI_START + 149)
-#define INT_UART3DM_IRQ				(GIC_SPI_START + 150)
+#define GSBI1_UARTDM_IRQ			(GIC_SPI_START + 146)
+#define GSBI1_QUP_IRQ		         	(GIC_SPI_START + 147)
+#define GSBI2_UARTDM_IRQ			(GIC_SPI_START + 148)
+#define GSBI2_QUP_IRQ			        (GIC_SPI_START + 149)
+#define GSBI3_UARTDM_IRQ			(GIC_SPI_START + 150)
 #define GSBI3_QUP_IRQ				(GIC_SPI_START + 151)
-#define INT_UART4DM_IRQ				(GIC_SPI_START + 152)
+#define GSBI4_UARTDM_IRQ			(GIC_SPI_START + 152)
 #define GSBI4_QUP_IRQ				(GIC_SPI_START + 153)
-#define INT_UART5DM_IRQ				(GIC_SPI_START + 154)
+#define GSBI5_UARTDM_IRQ			(GIC_SPI_START + 154)
 #define GSBI5_QUP_IRQ				(GIC_SPI_START + 155)
-#define INT_UART6DM_IRQ				(GIC_SPI_START + 156)
+#define GSBI6_UARTDM_IRQ			(GIC_SPI_START + 156)
 #define GSBI6_QUP_IRQ				(GIC_SPI_START + 157)
-#define INT_UART7DM_IRQ				(GIC_SPI_START + 158)
+#define GSBI7_UARTDM_IRQ			(GIC_SPI_START + 158)
 #define GSBI7_QUP_IRQ				(GIC_SPI_START + 159)
-#define INT_UART8DM_IRQ				(GIC_SPI_START + 160)
+#define GSBI8_UARTDM_IRQ			(GIC_SPI_START + 160)
 #define GSBI8_QUP_IRQ				(GIC_SPI_START + 161)
 #define TSIF_TSPP_IRQ				(GIC_SPI_START + 162)
 #define TSIF_BAM_IRQ				(GIC_SPI_START + 163)
@@ -229,20 +228,19 @@
 #define HSDDRX_EBI1_IRQ				(GIC_SPI_START + 186)
 #define SDC5_BAM_IRQ				(GIC_SPI_START + 187)
 #define SDC5_IRQ_0				(GIC_SPI_START + 188)
-#define INT_UART9DM_IRQ				(GIC_SPI_START + 189)
+#define GSBI9_UARTDM_IRQ			(GIC_SPI_START + 189)
 #define GSBI9_QUP_IRQ				(GIC_SPI_START + 190)
-#define INT_UART10DM_IRQ			(GIC_SPI_START + 191)
+#define GSBI10_UARTDM_IRQ			(GIC_SPI_START + 191)
 #define GSBI10_QUP_IRQ				(GIC_SPI_START + 192)
-#define INT_UART11DM_IRQ			(GIC_SPI_START + 193)
+#define GSBI11_UARTDM_IRQ			(GIC_SPI_START + 193)
 #define GSBI11_QUP_IRQ				(GIC_SPI_START + 194)
-#define INT_UART12DM_IRQ			(GIC_SPI_START + 195)
+#define GSBI12_UARTDM_IRQ			(GIC_SPI_START + 195)
 #define GSBI12_QUP_IRQ				(GIC_SPI_START + 196)
 
-/*SPI 197 to 209 arent used in 8x60*/
-#define SMMU_GFX2D1_CB_SC_SECURE_IRQ            (GIC_SPI_START + 210)
-#define SMMU_GFX2D1_CB_SC_NON_SECURE_IRQ        (GIC_SPI_START + 211)
+#define SMMU_GFX2D1_CB_SC_SECURE_IRQ		(GIC_SPI_START + 210)
+#define SMMU_GFX2D1_CB_SC_NON_SECURE_IRQ	(GIC_SPI_START + 211)
+#define GFX2D1_IRQ				(GIC_SPI_START + 212)
 
-/*SPI 212 to 216 arent used in 8x60*/
 #define SMPSS_SPARE_1				(GIC_SPI_START + 217)
 #define SMPSS_SPARE_2				(GIC_SPI_START + 218)
 #define SMPSS_SPARE_3				(GIC_SPI_START + 219)
@@ -251,8 +249,21 @@
 #define SMPSS_SPARE_6				(GIC_SPI_START + 222)
 #define SMPSS_SPARE_7				(GIC_SPI_START + 223)
 
+#define NR_TLMM_MSM_DIR_CONN_IRQ 10
 #define NR_GPIO_IRQS 173
+#define NR_MSM_GPIOS NR_GPIO_IRQS
 #define NR_MSM_IRQS 256
-#define NR_BOARD_IRQS 0
+#define NR_PMIC8058_IRQS 256
+#define NR_PMIC8901_IRQS 72
+#define NR_GPIO_EXPANDER_IRQS 98
+#define NR_BOARD_IRQS (NR_PMIC8058_IRQS + NR_PMIC8901_IRQS +\
+		NR_GPIO_EXPANDER_IRQS)
+
+/* smd/smsm interrupts */
+#define INT_A9_M2A_0                    MARM_SCSS_GP_IRQ_0
+#define INT_A9_M2A_5                    MARM_SCSS_GP_IRQ_1
+#define INT_ADSP_A11                    LPASS_SCSS_GP_HIGH_IRQ
+#define INT_ADSP_A11_SMSM               LPASS_SCSS_GP_MEDIUM_IRQ
+#define INT_DSPS_A11                    SPS_MTI_31
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-9615.h b/arch/arm/mach-msm/include/mach/irqs-9615.h
new file mode 100644
index 0000000..39058a6
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/irqs-9615.h
@@ -0,0 +1,204 @@
+/* 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
+ * 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 __ASM_ARCH_MSM_IRQS_9615_H
+#define __ASM_ARCH_MSM_IRQS_9615_H
+
+/* MSM ACPU Interrupt Numbers */
+
+/*
+ * 0-15:  STI/SGI (software triggered/generated interrupts)
+ * 16-31: PPI (private peripheral interrupts)
+ * 32+:   SPI (shared peripheral interrupts)
+ */
+
+#define FIQ_START     16
+#define GIC_PPI_START 16
+#define GIC_SPI_START 32
+
+#define INT_DEBUG_TIMER_EXP			(GIC_PPI_START + 1)
+#define INT_GP_TIMER_EXP			(GIC_PPI_START + 2)
+#define INT_GP_TIMER2_EXP			(GIC_PPI_START + 3)
+#define WDT0_ACCSCSSNBARK_INT			(GIC_PPI_START + 4)
+#define WDT1_ACCSCSSNBARK_INT			(GIC_PPI_START + 5)
+#define AVS_SVICINT				(GIC_PPI_START + 6)
+#define AVS_SVICINTSWDONE			(GIC_PPI_START + 7)
+#define CPU_DBGCPUXCOMMRXFULL			(GIC_PPI_START + 8)
+#define CPU_DBGCPUXCOMMTXEMPTY			(GIC_PPI_START + 9)
+#define INT_ARMQC_PERFMON			(GIC_PPI_START + 10)
+#define SC_AVSCPUXDOWN				(GIC_PPI_START + 11)
+#define SC_AVSCPUXUP				(GIC_PPI_START + 12)
+#define SC_SICCPUXACGIRPTREQ			(GIC_PPI_START + 13)
+#define SC_SICCPUXEXTFAULTIRPTREQ		(GIC_PPI_START + 14)
+/* PPI 15 is unused */
+
+#define APCC_QGICACGIRPTREQ			(GIC_SPI_START + 0)
+#define APCC_QGICL2PERFMONIRPTREQ		(GIC_SPI_START + 1)
+#define SC_SICL2PERFMONIRPTREQ			APCC_QGICL2PERFMONIRPTREQ
+#define APCC_QGICL2IRPTREQ			(GIC_SPI_START + 2)
+#define APCC_QGICMPUIRPTREQ			(GIC_SPI_START + 3)
+#define TLMM_MSM_DIR_CONN_IRQ_0			(GIC_SPI_START + 4)
+#define TLMM_MSM_DIR_CONN_IRQ_1			(GIC_SPI_START + 5)
+#define TLMM_MSM_DIR_CONN_IRQ_2			(GIC_SPI_START + 6)
+#define TLMM_MSM_DIR_CONN_IRQ_3			(GIC_SPI_START + 7)
+#define TLMM_MSM_DIR_CONN_IRQ_4			(GIC_SPI_START + 8)
+#define TLMM_MSM_DIR_CONN_IRQ_5			(GIC_SPI_START + 9)
+#define TLMM_MSM_DIR_CONN_IRQ_6			(GIC_SPI_START + 10)
+#define TLMM_MSM_DIR_CONN_IRQ_7			(GIC_SPI_START + 11)
+#define TLMM_MSM_DIR_CONN_IRQ_8			(GIC_SPI_START + 12)
+#define TLMM_MSM_DIR_CONN_IRQ_9			(GIC_SPI_START + 13)
+/* 14 Reserved */
+#define PM8018_SEC_IRQ_N			(GIC_SPI_START + 15)
+#define TLMM_MSM_SUMMARY_IRQ			(GIC_SPI_START + 16)
+#define SPDM_RT_1_IRQ				(GIC_SPI_START + 17)
+#define SPDM_DIAG_IRQ				(GIC_SPI_START + 18)
+#define RPM_APCC_CPU0_GP_HIGH_IRQ		(GIC_SPI_START + 19)
+#define RPM_APCC_CPU0_GP_MEDIUM_IRQ		(GIC_SPI_START + 20)
+#define RPM_APCC_CPU0_GP_LOW_IRQ		(GIC_SPI_START + 21)
+#define RPM_APCC_CPU0_WAKE_UP_IRQ		(GIC_SPI_START + 22)
+/* 23-28 Reserved */
+#define SSBI2_1_SC_CPU0_SECURE_IRQ		(GIC_SPI_START + 29)
+#define SSBI2_1_SC_CPU0_NON_SECURE_IRQ		(GIC_SPI_START + 30)
+/* 31 Reserved */
+#define MSMC_SC_PRI_CE_IRQ			(GIC_SPI_START + 32)
+#define SLIMBUS0_CORE_EE1_IRQ			(GIC_SPI_START + 33)
+#define SLIMBUS0_BAM_EE1_IRQ			(GIC_SPI_START + 34)
+#define Q6FW_WDOG_EXPIRED_IRQ			(GIC_SPI_START + 35)
+#define Q6SW_WDOG_EXPIRED_IRQ			(GIC_SPI_START + 36)
+#define MSS_TO_APPS_IRQ_0			(GIC_SPI_START + 37)
+#define MSS_TO_APPS_IRQ_1			(GIC_SPI_START + 38)
+#define MSS_TO_APPS_IRQ_2			(GIC_SPI_START + 39)
+#define MSS_TO_APPS_IRQ_3			(GIC_SPI_START + 40)
+#define MSS_TO_APPS_IRQ_4			(GIC_SPI_START + 41)
+#define MSS_TO_APPS_IRQ_5			(GIC_SPI_START + 42)
+#define MSS_TO_APPS_IRQ_6			(GIC_SPI_START + 43)
+#define MSS_TO_APPS_IRQ_7			(GIC_SPI_START + 44)
+#define MSS_TO_APPS_IRQ_8			(GIC_SPI_START + 45)
+#define MSS_TO_APPS_IRQ_9			(GIC_SPI_START + 46)
+/* 47-84  Reserved */
+#define LPASS_SCSS_AUDIO_IF_OUT0_IRQ		(GIC_SPI_START + 85)
+#define LPASS_SCSS_MIDI_IRQ			(GIC_SPI_START + 86)
+#define LPASS_Q6SS_WDOG_EXPIRED			(GIC_SPI_START + 87)
+#define LPASS_SCSS_GP_LOW_IRQ			(GIC_SPI_START + 88)
+#define LPASS_SCSS_GP_MEDIUM_IRQ		(GIC_SPI_START + 89)
+#define LPASS_SCSS_GP_HIGH_IRQ			(GIC_SPI_START + 90)
+#define TOP_IMEM_IRQ				(GIC_SPI_START + 91)
+#define FABRIC_SYS_IRQ				(GIC_SPI_START + 92)
+/* 93 Reserved */
+#define USB1_HS_BAM_IRQ				(GIC_SPI_START + 94)
+/* 95,96 unnamed */
+#define SDC2_BAM_IRQ				(GIC_SPI_START + 97)
+#define SDC1_BAM_IRQ				(GIC_SPI_START + 98)
+#define FABRIC_SPS_IRQ				(GIC_SPI_START + 99)
+#define USB1_HS_IRQ				(GIC_SPI_START + 100)
+/* 101,102 unnamed */
+#define SDC2_IRQ_0				(GIC_SPI_START + 103)
+#define SDC1_IRQ_0				(GIC_SPI_START + 104)
+#define SPS_BAM_DMA_IRQ				(GIC_SPI_START + 105)
+#define SPS_SEC_VIOL_IRQ			(GIC_SPI_START + 106)
+#define SPS_MTI_0				(GIC_SPI_START + 107)
+#define SPS_MTI_1				(GIC_SPI_START + 108)
+#define SPS_MTI_2				(GIC_SPI_START + 109)
+#define SPS_MTI_3				(GIC_SPI_START + 110)
+#define SPS_MTI_4				(GIC_SPI_START + 111)
+#define SPS_MTI_5				(GIC_SPI_START + 112)
+#define SPS_MTI_6				(GIC_SPI_START + 113)
+#define SPS_MTI_7				(GIC_SPI_START + 114)
+#define SPS_MTI_8				(GIC_SPI_START + 115)
+#define SPS_MTI_9				(GIC_SPI_START + 116)
+#define SPS_MTI_10				(GIC_SPI_START + 117)
+#define SPS_MTI_11				(GIC_SPI_START + 118)
+#define SPS_MTI_12				(GIC_SPI_START + 119)
+#define SPS_MTI_13				(GIC_SPI_START + 120)
+#define SPS_MTI_14				(GIC_SPI_START + 121)
+#define SPS_MTI_15				(GIC_SPI_START + 122)
+#define SPS_MTI_16				(GIC_SPI_START + 123)
+#define SPS_MTI_17				(GIC_SPI_START + 124)
+#define SPS_MTI_18				(GIC_SPI_START + 125)
+#define SPS_MTI_19				(GIC_SPI_START + 126)
+#define SPS_MTI_20				(GIC_SPI_START + 127)
+#define SPS_MTI_21				(GIC_SPI_START + 128)
+#define SPS_MTI_22				(GIC_SPI_START + 129)
+#define SPS_MTI_23				(GIC_SPI_START + 130)
+#define SPS_MTI_24				(GIC_SPI_START + 131)
+#define SPS_MTI_25				(GIC_SPI_START + 132)
+#define SPS_MTI_26				(GIC_SPI_START + 133)
+#define SPS_MTI_27				(GIC_SPI_START + 134)
+#define SPS_MTI_28				(GIC_SPI_START + 135)
+#define SPS_MTI_29				(GIC_SPI_START + 136)
+#define SPS_MTI_30				(GIC_SPI_START + 137)
+#define SPS_MTI_31				(GIC_SPI_START + 138)
+#define CSIPHY_0_4LN_IRQ			(GIC_SPI_START + 139)
+#define CSIPHY_1_2LN_IRQ			(GIC_SPI_START + 140)
+/* 141-145 Reserved */
+#define GSBI1_UARTDM_IRQ			(GIC_SPI_START + 146)
+#define GSBI1_QUP_IRQ				(GIC_SPI_START + 147)
+#define GSBI2_UARTDM_IRQ			(GIC_SPI_START + 148)
+#define GSBI2_QUP_IRQ			        (GIC_SPI_START + 149)
+#define GSBI3_UARTDM_IRQ			(GIC_SPI_START + 150)
+#define GSBI3_QUP_IRQ				(GIC_SPI_START + 151)
+#define GSBI4_UARTDM_IRQ			(GIC_SPI_START + 152)
+#define GSBI4_QUP_IRQ				(GIC_SPI_START + 153)
+#define GSBI5_UARTDM_IRQ			(GIC_SPI_START + 154)
+#define GSBI5_QUP_IRQ				(GIC_SPI_START + 155)
+/* 156-167 Reserved */
+#define MSMC_SC_SEC_TMR_IRQ			(GIC_SPI_START + 168)
+#define MSMC_SC_SEC_WDOG_BARK_IRQ		(GIC_SPI_START + 169)
+#define ADM_0_SCSS_0_IRQ			(GIC_SPI_START + 170)
+#define ADM_0_SCSS_1_IRQ			(GIC_SPI_START + 171)
+#define ADM_0_SCSS_2_IRQ			(GIC_SPI_START + 172)
+#define ADM_0_SCSS_3_IRQ			(GIC_SPI_START + 173)
+/* 174 Reserved */
+#define CC_SCSS_WDT1CPU0BITEEXPIRED		(GIC_SPI_START + 175)
+/* 176 Reserved */
+#define CC_SCSS_WDT0CPU0BITEEXPIRED		(GIC_SPI_START + 177)
+#define TSENS_UPPER_LOWER_INT			(GIC_SPI_START + 178)
+/* 179-182 Reserved */
+#define XPU_SUMMARY_IRQ				(GIC_SPI_START + 183)
+#define BUS_EXCEPTION_SUMMARY_IRQ		(GIC_SPI_START + 184)
+#define HSDDRX_EBI1CH0_IRQ			(GIC_SPI_START + 185)
+/* 186-208 Reserved */
+#define A2_BAM_IRQ				(GIC_SPI_START + 209)
+/* 210-215 Reserved */
+#define QDSS_ETB_IRQ				(GIC_SPI_START + 216)
+/* 216 Reserved */
+#define QDSS_CTI2KPSS_CPU0_IRQ			(GIC_SPI_START + 218)
+#define TLMM_MSM_DIR_CONN_IRQ_16		(GIC_SPI_START + 219)
+#define TLMM_MSM_DIR_CONN_IRQ_17		(GIC_SPI_START + 220)
+#define TLMM_MSM_DIR_CONN_IRQ_18		(GIC_SPI_START + 221)
+#define TLMM_MSM_DIR_CONN_IRQ_19		(GIC_SPI_START + 222)
+#define TLMM_MSM_DIR_CONN_IRQ_20		(GIC_SPI_START + 223)
+#define TLMM_MSM_DIR_CONN_IRQ_21		(GIC_SPI_START + 224)
+#define MSM_SPARE0_IRQ				(GIC_SPI_START + 225)
+#define PMIC_SEC_IRQ_N				(GIC_SPI_START + 226)
+#define USB_HSIC_BAM_IRQ			(GIC_SPI_START + 231)
+#define USB_HSIC_IRQ				(GIC_SPI_START + 232)
+
+#define NR_MSM_IRQS 288
+#define NR_GPIO_IRQS 88
+#define NR_PM8018_IRQS 256
+#define NR_WCD9XXX_IRQS 49
+#define NR_TABLA_IRQS NR_WCD9XXX_IRQS
+#define NR_BOARD_IRQS (NR_PM8018_IRQS + NR_WCD9XXX_IRQS)
+#define NR_TLMM_MSM_DIR_CONN_IRQ 8 /*Need to Verify this Count*/
+#define NR_MSM_GPIOS NR_GPIO_IRQS
+
+/* Backwards compatible IRQ macros. */
+#define INT_ADM_AARM				ADM_0_SCSS_0_IRQ
+
+/* smd/smsm interrupts */
+#define INT_A9_M2A_0                    MSS_TO_APPS_IRQ_0
+#define INT_A9_M2A_5                    MSS_TO_APPS_IRQ_1
+#define INT_ADSP_A11                    LPASS_SCSS_GP_HIGH_IRQ
+#define INT_ADSP_A11_SMSM               LPASS_SCSS_GP_MEDIUM_IRQ
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-9625.h b/arch/arm/mach-msm/include/mach/irqs-9625.h
new file mode 100644
index 0000000..91b4d07
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/irqs-9625.h
@@ -0,0 +1,36 @@
+/* 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 __ASM_ARCH_MSM_IRQS_9625_H
+#define __ASM_ARCH_MSM_IRQS_9625_H
+
+/* MSM ACPU Interrupt Numbers */
+
+/*
+ * 0-15:  STI/SGI (software triggered/generated interrupts)
+ * 16-31: PPI (private peripheral interrupts)
+ * 32+:   SPI (shared peripheral interrupts)
+ */
+
+
+#define APCC_QGICL2PERFMONIRPTREQ	(GIC_SPI_START + 1)
+#define SC_SICL2PERFMONIRPTREQ		APCC_QGICL2PERFMONIRPTREQ
+#define TLMM_MSM_SUMMARY_IRQ		(GIC_SPI_START + 16)
+#define SPS_BAM_DMA_IRQ			(GIC_SPI_START + 208)
+
+#define NR_MSM_IRQS 288
+#define NR_GPIO_IRQS 88
+#define NR_BOARD_IRQS 0
+#define NR_TLMM_MSM_DIR_CONN_IRQ 8 /*Need to Verify this Count*/
+#define NR_MSM_GPIOS NR_GPIO_IRQS
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-copper.h b/arch/arm/mach-msm/include/mach/irqs-copper.h
new file mode 100644
index 0000000..6d27d69
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/irqs-copper.h
@@ -0,0 +1,45 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_ARCH_MSM_IRQS_COPPER_H
+#define __ASM_ARCH_MSM_IRQS_COPPER_H
+
+/* MSM ACPU Interrupt Numbers */
+
+/*
+ * 0-15:  STI/SGI (software triggered/generated interrupts)
+ * 16-31: PPI (private peripheral interrupts)
+ * 32+:   SPI (shared peripheral interrupts)
+ */
+
+#define GIC_PPI_START 16
+#define GIC_SPI_START 32
+
+#define AVS_SVICINT				(GIC_PPI_START + 6)
+#define AVS_SVICINTSWDONE			(GIC_PPI_START + 7)
+#define INT_ARMQC_PERFMON			(GIC_PPI_START + 10)
+/* PPI 15 is unused */
+
+#define APCC_QGICL2PERFMONIRPTREQ	(GIC_SPI_START + 1)
+#define SC_SICL2PERFMONIRPTREQ		APCC_QGICL2PERFMONIRPTREQ
+#define TLMM_MSM_SUMMARY_IRQ		(GIC_SPI_START + 208)
+#define SPS_BAM_DMA_IRQ			(GIC_SPI_START + 105)
+
+#define NR_MSM_IRQS 1020 /* Should be 256 - but higher due to bug in sim */
+#define NR_GPIO_IRQS 156
+#define NR_QPNP_IRQS 32768 /* SPARSE_IRQ is required to support this */
+#define NR_BOARD_IRQS NR_QPNP_IRQS
+#define NR_TLMM_MSM_DIR_CONN_IRQ 8
+#define NR_MSM_GPIOS NR_GPIO_IRQS
+
+#endif
+
diff --git a/arch/arm/mach-msm/include/mach/irqs-fsm9xxx.h b/arch/arm/mach-msm/include/mach/irqs-fsm9xxx.h
new file mode 100644
index 0000000..721db1d
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/irqs-fsm9xxx.h
@@ -0,0 +1,99 @@
+/* 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
+ * 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 __ASM_ARCH_MSM_IRQS_FSM9XXX_H
+#define __ASM_ARCH_MSM_IRQS_FSM9XXX_H
+
+/* MSM ACPU Interrupt Numbers */
+
+#define INT_DEBUG_TIMER_EXP	0
+#define INT_GPT0_TIMER_EXP	1
+#define INT_GPT1_TIMER_EXP	2
+#define INT_WDT0_ACCSCSSBARK	3
+#define INT_WDT1_ACCSCSSBARK	4
+#define INT_AVS_SVIC		5
+#define INT_AVS_SVIC_SW_DONE	6
+#define INT_SC_DBG_RX_FULL	7
+#define INT_SC_DBG_TX_EMPTY	8
+#define INT_ARMQC_PERFMON	9
+#define INT_AVS_REQ_DOWN	10
+#define INT_AVS_REQ_UP		11
+#define INT_SC_ACG		12
+/* SCSS_VICFIQSTS0[13:15] are RESERVED */
+#define INT_BPU_CPU		16
+#define INT_L2_SVICDMANSIRPTREQ 17
+#define INT_L2_SVICDMASIRPTREQ  18
+#define INT_L2_SVICSLVIRPTREQ	19
+#define INT_SEAWOLF_IRQ0	20
+#define INT_SEAWOLF_IRQ1	21
+#define INT_SEAWOLF_IRQ2	22
+#define INT_SEAWOLF_IRQ3	23
+#define INT_CARIBE_SUPSS_IRQ	24
+#define INT_ADM_SEC0_IRQ	25
+/* SCSS_VICFIQSTS0[26] is RESERVED */
+#define INT_GMII_PHY		27
+#define INT_SBD_IRQ		28
+#define INT_HH_SUPSS_IRQ	29
+#define INT_EMAC_SBD_IRQ	30
+#define INT_PERPH_SUPSS_IRQ	31
+
+#define INT_Q6_SW_IRQ_0		(32 + 0)
+#define INT_Q6_SW_IRQ_1		(32 + 1)
+#define INT_Q6_SW_IRQ_2		(32 + 2)
+#define INT_Q6_SW_IRQ_3		(32 + 3)
+#define INT_Q6_SW_IRQ_4		(32 + 4)
+#define INT_Q6_SW_IRQ_5		(32 + 5)
+#define INT_Q6_SW_IRQ_6		(32 + 6)
+#define INT_Q6_SW_IRQ_7		(32 + 7)
+#define INT_IMEM_IRQ		(32 + 8)
+#define INT_IMEM_ECC_IRQ	(32 + 9)
+#define INT_HSDDRX_IRQ		(32 + 10)
+#define INT_BUFMEM_XPU_IRQ	(32 + 11)
+#define INT_A9_M2A_0		(32 + 12)
+#define INT_A9_M2A_1		(32 + 13)
+#define INT_A9_M2A_2		(32 + 14)
+#define INT_A9_M2A_3		(32 + 15)
+#define INT_A9_M2A_4		(32 + 16)
+#define INT_A9_M2A_5		(32 + 17)
+#define INT_A9_M2A_6		(32 + 18)
+#define INT_A9_M2A_7		(32 + 19)
+#define INT_SC_PRI_IRQ		(32 + 20)
+#define INT_SC_SEC_IRQ		(32 + 21)
+#define INT_Q6_WDOG_IRQ		(32 + 22)
+#define INT_ADM_SEC3_IRQ	(32 + 23)
+#define INT_ARM_WAKE_IRQ	(32 + 24)
+#define INT_ARM_WDOG_IRQ	(32 + 25)
+#define INT_SUPSS_CFG_XPU_IRQ	(32 + 26)
+#define INT_SPB_XPU_IRQ		(32 + 27)
+#define INT_FPB_XPU_IRQ		(32 + 28)
+#define INT_Q6_XPU_IRQ		(32 + 29)
+/* SCSS_VICFIQSTS1[30:31] are RESERVED */
+/* SCSS_VICFIQSTS2[0:31] are RESERVED */
+/* SCSS_VICFIQSTS3[0:31] are RESERVED */
+
+/* Retrofit universal macro names */
+#define INT_ADM_AARM		INT_ADM_SEC3_IRQ
+#define INT_GP_TIMER_EXP	INT_GPT0_TIMER_EXP
+#define INT_ADSP_A11		INT_Q6_SW_IRQ_0
+#define INT_ADSP_A11_SMSM	INT_ADSP_A11
+#define INT_SIRC_0		INT_PERPH_SUPSS_IRQ
+#define WDT0_ACCSCSSNBARK_INT	INT_WDT0_ACCSCSSBARK
+
+#define NR_MSM_IRQS		128
+#define NR_GPIO_IRQS		0
+#define PMIC8058_IRQ_BASE	(NR_MSM_IRQS + NR_GPIO_IRQS + NR_SIRC_IRQS)
+#define NR_PMIC8058_IRQS	256
+#define NR_BOARD_IRQS		(NR_SIRC_IRQS + NR_PMIC8058_IRQS)
+
+#define NR_MSM_GPIOS		168
+
+#endif /* __ASM_ARCH_MSM_IRQS_FSM9XXX_H */
diff --git a/arch/arm/mach-msm/include/mach/irqs.h b/arch/arm/mach-msm/include/mach/irqs.h
index 3cd78b1..fdf6786 100644
--- a/arch/arm/mach-msm/include/mach/irqs.h
+++ b/arch/arm/mach-msm/include/mach/irqs.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -19,24 +19,85 @@
 
 #define MSM_IRQ_BIT(irq)     (1 << ((irq) & 31))
 
-#if defined(CONFIG_ARCH_MSM7X30)
+#include "irqs-8625.h"
+
+#if defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_APQ8064) || \
+	defined(CONFIG_ARCH_MSM8930)
+
+#ifdef CONFIG_ARCH_MSM8960
+#include "irqs-8960.h"
+#endif
+
+#ifdef CONFIG_ARCH_MSM8930
+#include "irqs-8930.h"
+#endif
+
+#ifdef CONFIG_ARCH_APQ8064
+#include "irqs-8064.h"
+#endif
+
+/* For now, use the maximum number of interrupts until a pending GIC issue
+ * is sorted out */
+#define NR_MSM_IRQS 288
+#define NR_GPIO_IRQS 152
+#define NR_PM8921_IRQS 256
+#define NR_PM8821_IRQS 64
+#define NR_WCD9XXX_IRQS 49
+#define NR_TABLA_IRQS NR_WCD9XXX_IRQS
+#define NR_GPIO_EXPANDER_IRQS 64
+#ifdef CONFIG_PCI_MSI
+#define NR_PCIE_MSI_IRQS 256
+#define NR_BOARD_IRQS (NR_PM8921_IRQS + NR_PM8821_IRQS + \
+		NR_WCD9XXX_IRQS + NR_GPIO_EXPANDER_IRQS + NR_PCIE_MSI_IRQS)
+#else
+#define NR_BOARD_IRQS (NR_PM8921_IRQS + NR_PM8821_IRQS + \
+		NR_WCD9XXX_IRQS + NR_GPIO_EXPANDER_IRQS)
+#endif
+#define NR_TLMM_MSM_DIR_CONN_IRQ 8 /*Need to Verify this Count*/
+#define NR_MSM_GPIOS NR_GPIO_IRQS
+
+#else
+
+#if defined(CONFIG_ARCH_MSMCOPPER)
+#include "irqs-copper.h"
+#elif defined(CONFIG_ARCH_MSM9615)
+#include "irqs-9615.h"
+#elif defined(CONFIG_ARCH_MSM9625)
+#include "irqs-9625.h"
+#elif defined(CONFIG_ARCH_MSM7X30)
 #include "irqs-7x30.h"
 #elif defined(CONFIG_ARCH_QSD8X50)
 #include "irqs-8x50.h"
 #include "sirc.h"
 #elif defined(CONFIG_ARCH_MSM8X60)
 #include "irqs-8x60.h"
-#elif defined(CONFIG_ARCH_MSM8960)
-/* TODO: Make these not generic. */
-#include "irqs-8960.h"
-#elif defined(CONFIG_ARCH_MSM_ARM11)
-#include "irqs-7x00.h"
+#elif defined(CONFIG_ARCH_MSM7X01A) || defined(CONFIG_ARCH_MSM7X25) \
+	|| defined(CONFIG_ARCH_MSM7X27)
+#include "irqs-7xxx.h"
+
+#define NR_GPIO_IRQS 133
+#define NR_MSM_IRQS 256
+#define NR_BOARD_IRQS 256
+#define NR_MSM_GPIOS NR_GPIO_IRQS
+#elif defined(CONFIG_ARCH_FSM9XXX)
+#include "irqs-fsm9xxx.h"
+#include "sirc.h"
 #else
 #error "Unknown architecture specification"
 #endif
 
+#endif
+
+#if !defined(CONFIG_SPARSE_IRQ)
 #define NR_IRQS (NR_MSM_IRQS + NR_GPIO_IRQS + NR_BOARD_IRQS)
 #define MSM_GPIO_TO_INT(n) (NR_MSM_IRQS + (n))
+#define FIRST_GPIO_IRQ MSM_GPIO_TO_INT(0)
 #define MSM_INT_TO_REG(base, irq) (base + irq / 32)
+#endif
+
+#if defined(CONFIG_PCI_MSI) && defined(CONFIG_MSM_PCIE)
+#define MSM_PCIE_MSI_INT(n) (NR_MSM_IRQS + NR_GPIO_IRQS + NR_PM8921_IRQS +  \
+		NR_PM8821_IRQS + NR_TABLA_IRQS + NR_GPIO_EXPANDER_IRQS + (n))
+#endif
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/mdm-peripheral.h b/arch/arm/mach-msm/include/mach/mdm-peripheral.h
new file mode 100644
index 0000000..0f3bd33
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/mdm-peripheral.h
@@ -0,0 +1,19 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _ARCH_ARM_MACH_MSM_MDM_PERIPHERAL_H
+#define _ARCH_ARM_MACH_MSM_MDM_PERIPHERAL_H_
+
+extern void peripheral_connect(void);
+extern void peripheral_disconnect(void);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/mdm.h b/arch/arm/mach-msm/include/mach/mdm.h
new file mode 100644
index 0000000..f0100fe
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/mdm.h
@@ -0,0 +1,35 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _ARCH_ARM_MACH_MSM_MDM_H
+#define _ARXH_ARM_MACH_MSM_MDM_H
+
+
+struct charm_platform_data {
+	void (*charm_modem_on)(void);
+	void (*charm_modem_off)(void);
+};
+
+#define AP2MDM_STATUS   136
+#define MDM2AP_STATUS   134
+#define MDM2AP_WAKEUP   40
+#define MDM2AP_ERRFATAL 133
+#define AP2MDM_ERRFATAL 93
+
+#define AP2MDM_PMIC_RESET_N     131
+#define AP2MDM_KPDPWR_N 132
+#define AP2PMIC_TMPNI_CKEN      141
+#define AP2MDM_WAKEUP	135
+
+extern void (*charm_intentional_reset)(void);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/mdm2.h b/arch/arm/mach-msm/include/mach/mdm2.h
new file mode 100644
index 0000000..997b3be
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/mdm2.h
@@ -0,0 +1,26 @@
+/* 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
+ * 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 _ARCH_ARM_MACH_MSM_MDM2_H
+#define _ARCH_ARM_MACH_MSM_MDM2_H
+
+struct mdm_platform_data {
+	char *mdm_version;
+	int ramdump_delay_ms;
+	int soft_reset_inverted;
+	int early_power_on;
+	int sfr_query;
+	struct platform_device *peripheral_platform_device;
+};
+
+#endif
+
diff --git a/arch/arm/mach-msm/include/mach/memory.h b/arch/arm/mach-msm/include/mach/memory.h
new file mode 100644
index 0000000..2596364
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/memory.h
@@ -0,0 +1,138 @@
+/* arch/arm/mach-msm/include/mach/memory.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009-2012, Code Aurora Forum. 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_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+#include <linux/types.h>
+
+/* physical offset of RAM */
+#define PLAT_PHYS_OFFSET UL(CONFIG_PHYS_OFFSET)
+
+#define MAX_PHYSMEM_BITS 32
+#define SECTION_SIZE_BITS 28
+
+/* Maximum number of Memory Regions
+*  The largest system can have 4 memory banks, each divided into 8 regions
+*/
+#define MAX_NR_REGIONS 32
+
+/* The number of regions each memory bank is divided into */
+#define NR_REGIONS_PER_BANK 8
+
+/* Certain configurations of MSM7x30 have multiple memory banks.
+*  One or more of these banks can contain holes in the memory map as well.
+*  These macros define appropriate conversion routines between the physical
+*  and virtual address domains for supporting these configurations using
+*  SPARSEMEM and a 3G/1G VM split.
+*/
+
+#if defined(CONFIG_ARCH_MSM7X30)
+
+#define EBI0_PHYS_OFFSET PHYS_OFFSET
+#define EBI0_PAGE_OFFSET PAGE_OFFSET
+#define EBI0_SIZE 0x10000000
+
+#ifndef __ASSEMBLY__
+
+extern unsigned long ebi1_phys_offset;
+
+#define EBI1_PHYS_OFFSET (ebi1_phys_offset)
+#define EBI1_PAGE_OFFSET (EBI0_PAGE_OFFSET + EBI0_SIZE)
+
+#if (defined(CONFIG_SPARSEMEM) && defined(CONFIG_VMSPLIT_3G))
+
+#define __phys_to_virt(phys)				\
+	((phys) >= EBI1_PHYS_OFFSET ?			\
+	(phys) - EBI1_PHYS_OFFSET + EBI1_PAGE_OFFSET :	\
+	(phys) - EBI0_PHYS_OFFSET + EBI0_PAGE_OFFSET)
+
+#define __virt_to_phys(virt)				\
+	((virt) >= EBI1_PAGE_OFFSET ?			\
+	(virt) - EBI1_PAGE_OFFSET + EBI1_PHYS_OFFSET :	\
+	(virt) - EBI0_PAGE_OFFSET + EBI0_PHYS_OFFSET)
+
+#endif
+#endif
+
+#endif
+
+#ifndef __ASSEMBLY__
+void *alloc_bootmem_aligned(unsigned long size, unsigned long alignment);
+void *allocate_contiguous_ebi(unsigned long, unsigned long, int);
+unsigned long allocate_contiguous_ebi_nomap(unsigned long, unsigned long);
+void clean_and_invalidate_caches(unsigned long, unsigned long, unsigned long);
+void clean_caches(unsigned long, unsigned long, unsigned long);
+void invalidate_caches(unsigned long, unsigned long, unsigned long);
+int platform_physical_remove_pages(u64, u64);
+int platform_physical_active_pages(u64, u64);
+int platform_physical_low_power_pages(u64, u64);
+
+extern int (*change_memory_power)(u64, u64, int);
+
+#if defined(CONFIG_ARCH_MSM_ARM11) || defined(CONFIG_ARCH_MSM_CORTEX_A5)
+void write_to_strongly_ordered_memory(void);
+void map_page_strongly_ordered(void);
+#endif
+
+#ifdef CONFIG_CACHE_L2X0
+extern void l2x0_cache_sync(void);
+#define finish_arch_switch(prev)     do { l2x0_cache_sync(); } while (0)
+#endif
+
+#if defined(CONFIG_ARCH_MSM8X60) || defined(CONFIG_ARCH_MSM8960)
+extern void store_ttbr0(void);
+#define finish_arch_switch(prev)	do { store_ttbr0(); } while (0)
+#endif
+
+#ifdef CONFIG_DONT_MAP_HOLE_AFTER_MEMBANK0
+extern unsigned long membank0_size;
+extern unsigned long membank1_start;
+void find_membank0_hole(void);
+
+#define MEMBANK0_PHYS_OFFSET PHYS_OFFSET
+#define MEMBANK0_PAGE_OFFSET PAGE_OFFSET
+
+#define MEMBANK1_PHYS_OFFSET (membank1_start)
+#define MEMBANK1_PAGE_OFFSET (MEMBANK0_PAGE_OFFSET + (membank0_size))
+
+#define __phys_to_virt(phys)				\
+	((MEMBANK1_PHYS_OFFSET && ((phys) >= MEMBANK1_PHYS_OFFSET)) ?	\
+	(phys) - MEMBANK1_PHYS_OFFSET + MEMBANK1_PAGE_OFFSET :	\
+	(phys) - MEMBANK0_PHYS_OFFSET + MEMBANK0_PAGE_OFFSET)
+
+#define __virt_to_phys(virt)				\
+	((MEMBANK1_PHYS_OFFSET && ((virt) >= MEMBANK1_PAGE_OFFSET)) ?	\
+	(virt) - MEMBANK1_PAGE_OFFSET + MEMBANK1_PHYS_OFFSET :	\
+	(virt) - MEMBANK0_PAGE_OFFSET + MEMBANK0_PHYS_OFFSET)
+#endif
+
+#endif
+
+#if defined CONFIG_ARCH_MSM_SCORPION || defined CONFIG_ARCH_MSM_KRAIT
+#define arch_has_speculative_dfetch()	1
+#endif
+
+#endif
+
+/* these correspond to values known by the modem */
+#define MEMORY_DEEP_POWERDOWN	0
+#define MEMORY_SELF_REFRESH	1
+#define MEMORY_ACTIVE		2
+
+#define NPA_MEMORY_NODE_NAME	"/mem/apps/ddr_dpd"
+
+#ifndef CONFIG_ARCH_MSM7X27
+#define CONSISTENT_DMA_SIZE	(SZ_1M * 14)
+#endif
diff --git a/arch/arm/mach-msm/include/mach/mpm.h b/arch/arm/mach-msm/include/mach/mpm.h
new file mode 100644
index 0000000..10a6fb0
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/mpm.h
@@ -0,0 +1,73 @@
+/* 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
+ * 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 __ARCH_ARM_MACH_MSM_MPM_H
+#define __ARCH_ARM_MACH_MSM_MPM_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+#define MSM_MPM_NR_MPM_IRQS  64
+
+struct msm_mpm_device_data {
+	uint16_t *irqs_m2a;
+	unsigned int irqs_m2a_size;
+	uint16_t *bypassed_apps_irqs;
+	unsigned int bypassed_apps_irqs_size;
+	void __iomem *mpm_request_reg_base;
+	void __iomem *mpm_status_reg_base;
+	void __iomem *mpm_apps_ipc_reg;
+	unsigned int mpm_apps_ipc_val;
+	unsigned int mpm_ipc_irq;
+};
+
+extern struct msm_mpm_device_data msm8660_mpm_dev_data;
+extern struct msm_mpm_device_data msm8960_mpm_dev_data;
+extern struct msm_mpm_device_data msm9615_mpm_dev_data;
+extern struct msm_mpm_device_data apq8064_mpm_dev_data;
+
+void msm_mpm_irq_extn_init(struct msm_mpm_device_data *mpm_data);
+
+#ifdef CONFIG_MSM_MPM
+int msm_mpm_enable_pin(unsigned int pin, unsigned int enable);
+int msm_mpm_set_pin_wake(unsigned int pin, unsigned int on);
+int msm_mpm_set_pin_type(unsigned int pin, unsigned int flow_type);
+bool msm_mpm_irqs_detectable(bool from_idle);
+bool msm_mpm_gpio_irqs_detectable(bool from_idle);
+void msm_mpm_enter_sleep(bool from_idle);
+void msm_mpm_exit_sleep(bool from_idle);
+#else
+static inline int msm_mpm_enable_irq(unsigned int irq, unsigned int enable)
+{ return -ENODEV; }
+static inline int msm_mpm_set_irq_wake(unsigned int irq, unsigned int on)
+{ return -ENODEV; }
+static inline int msm_mpm_set_irq_type(unsigned int irq, unsigned int flow_type)
+{ return -ENODEV; }
+static inline int msm_mpm_enable_pin(unsigned int pin, unsigned int enable)
+{ return -ENODEV; }
+static inline int msm_mpm_set_pin_wake(unsigned int pin, unsigned int on)
+{ return -ENODEV; }
+static inline int msm_mpm_set_pin_type(unsigned int pin,
+				       unsigned int flow_type)
+{ return -ENODEV; }
+static inline bool msm_mpm_irqs_detectable(bool from_idle)
+{ return false; }
+static inline bool msm_mpm_gpio_irqs_detectable(bool from_idle)
+{ return false; }
+static inline void msm_mpm_enter_sleep(bool from_idle) {}
+static inline void msm_mpm_exit_sleep(bool from_idle) {}
+#endif
+
+
+
+#endif /* __ARCH_ARM_MACH_MSM_MPM_H */
diff --git a/arch/arm/mach-msm/include/mach/mpp.h b/arch/arm/mach-msm/include/mach/mpp.h
new file mode 100644
index 0000000..8ac1f54
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/mpp.h
@@ -0,0 +1,276 @@
+/* Copyright (c) 2008-2010, 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 __ARCH_ARM_MACH_MSM_MPP_H
+#define __ARCH_ARM_MACH_MSM_MPP_H
+
+#ifdef CONFIG_PMIC8058
+#define	MPPS		12
+#else
+#define	MPPS		22
+#endif
+
+/* Digital Logical Output Level */
+enum {
+	MPP_DLOGIC_LVL_MSME,
+	MPP_DLOGIC_LVL_MSMP,
+	MPP_DLOGIC_LVL_RUIM,
+	MPP_DLOGIC_LVL_MMC,
+	MPP_DLOGIC_LVL_VDD,
+};
+
+/* Digital Logical Output Control Value */
+enum {
+	MPP_DLOGIC_OUT_CTRL_LOW,
+	MPP_DLOGIC_OUT_CTRL_HIGH,
+	MPP_DLOGIC_OUT_CTRL_MPP,	/* MPP Output = MPP Input */
+	MPP_DLOGIC_OUT_CTRL_NOT_MPP,	/* MPP Output = Inverted MPP Input */
+};
+
+/* Digital Logical Input Value */
+enum {
+	MPP_DLOGIC_IN_DBUS_NONE,
+	MPP_DLOGIC_IN_DBUS_1,
+	MPP_DLOGIC_IN_DBUS_2,
+	MPP_DLOGIC_IN_DBUS_3,
+};
+
+#define MPP_CFG(level, control) ((((level) & 0x0FFFF) << 16) | \
+				 ((control) & 0x0FFFF))
+#define MPP_CFG_INPUT(level, dbus) ((((level) & 0x0FFFF) << 16) | \
+				 ((dbus) & 0x0FFFF))
+
+/* Use mpp number starting from 0 */
+int mpp_config_digital_out(unsigned mpp, unsigned config);
+int mpp_config_digital_in(unsigned mpp, unsigned config);
+
+/* PM8058/PM8901 definitions */
+
+/* APIs */
+#ifdef CONFIG_PMIC8058
+int pm8058_mpp_config(unsigned mpp, unsigned type, unsigned level,
+		      unsigned control);
+#else
+static inline int pm8058_mpp_config(unsigned mpp, unsigned type,
+				    unsigned level, unsigned control)
+{
+	return -EINVAL;
+}
+#endif
+
+#ifdef CONFIG_PMIC8901
+int pm8901_mpp_config(unsigned mpp, unsigned type, unsigned level,
+		      unsigned control);
+#else
+static inline int pm8901_mpp_config(unsigned mpp, unsigned type,
+				    unsigned level, unsigned control)
+{
+	return -EINVAL;
+}
+#endif
+
+/* MPP Type: type */
+#define	PM_MPP_TYPE_D_INPUT		0
+#define	PM_MPP_TYPE_D_OUTPUT		1
+#define	PM_MPP_TYPE_D_BI_DIR		2
+#define	PM_MPP_TYPE_A_INPUT		3
+#define	PM_MPP_TYPE_A_OUTPUT		4
+#define	PM_MPP_TYPE_SINK		5
+#define	PM_MPP_TYPE_DTEST_SINK		6
+#define	PM_MPP_TYPE_DTEST_OUTPUT	7
+
+
+/* Digital Input/Output: level [8058] */
+#define	PM8058_MPP_DIG_LEVEL_VPH	0
+#define	PM8058_MPP_DIG_LEVEL_S3		1
+#define	PM8058_MPP_DIG_LEVEL_L2		2
+#define	PM8058_MPP_DIG_LEVEL_L3		3
+
+/* Digital Input/Output: level [8901] */
+#define	PM8901_MPP_DIG_LEVEL_MSMIO	0
+#define	PM8901_MPP_DIG_LEVEL_DIG	1
+#define	PM8901_MPP_DIG_LEVEL_L5		2
+#define	PM8901_MPP_DIG_LEVEL_S4		3
+#define	PM8901_MPP_DIG_LEVEL_VPH	4
+
+/* Digital Input: control */
+#define	PM_MPP_DIN_TO_INT		0
+#define	PM_MPP_DIN_TO_DBUS1		1
+#define	PM_MPP_DIN_TO_DBUS2		2
+#define	PM_MPP_DIN_TO_DBUS3		3
+
+/* Digital Output: control */
+#define	PM_MPP_DOUT_CTL_LOW		0
+#define	PM_MPP_DOUT_CTL_HIGH		1
+#define	PM_MPP_DOUT_CTL_MPP		2
+#define	PM_MPP_DOUT_CTL_INV_MPP		3
+
+/* Bidirectional: control */
+#define	PM_MPP_BI_PULLUP_1KOHM		0
+#define	PM_MPP_BI_PULLUP_OPEN		1
+#define	PM_MPP_BI_PULLUP_10KOHM		2
+#define	PM_MPP_BI_PULLUP_30KOHM		3
+
+/* Analog Input: level */
+#define	PM_MPP_AIN_AMUX_CH5		0
+#define	PM_MPP_AIN_AMUX_CH6		1
+#define	PM_MPP_AIN_AMUX_CH7		2
+#define	PM_MPP_AIN_AMUX_CH8		3
+#define	PM_MPP_AIN_AMUX_CH9		4
+#define	PM_MPP_AIN_AMUX_ABUS1		5
+#define	PM_MPP_AIN_AMUX_ABUS2		6
+#define	PM_MPP_AIN_AMUX_ABUS3		7
+
+/* Analog Output: level */
+#define	PM_MPP_AOUT_LVL_1V25		0
+#define	PM_MPP_AOUT_LVL_1V25_2		1
+#define	PM_MPP_AOUT_LVL_0V625		2
+#define	PM_MPP_AOUT_LVL_0V3125		3
+#define	PM_MPP_AOUT_LVL_MPP		4
+#define	PM_MPP_AOUT_LVL_ABUS1		5
+#define	PM_MPP_AOUT_LVL_ABUS2		6
+#define	PM_MPP_AOUT_LVL_ABUS3		7
+
+/* Analog Output: control */
+#define	PM_MPP_AOUT_CTL_DISABLE		0
+#define	PM_MPP_AOUT_CTL_ENABLE		1
+#define	PM_MPP_AOUT_CTL_MPP_HIGH_EN	2
+#define	PM_MPP_AOUT_CTL_MPP_LOW_EN	3
+
+/* Current Sink: level */
+#define	PM_MPP_CS_OUT_5MA		0
+#define	PM_MPP_CS_OUT_10MA		1
+#define	PM_MPP_CS_OUT_15MA		2
+#define	PM_MPP_CS_OUT_20MA		3
+#define	PM_MPP_CS_OUT_25MA		4
+#define	PM_MPP_CS_OUT_30MA		5
+#define	PM_MPP_CS_OUT_35MA		6
+#define	PM_MPP_CS_OUT_40MA		7
+
+/* Current Sink: control */
+#define	PM_MPP_CS_CTL_DISABLE		0
+#define	PM_MPP_CS_CTL_ENABLE		1
+#define	PM_MPP_CS_CTL_MPP_HIGH_EN	2
+#define	PM_MPP_CS_CTL_MPP_LOW_EN	3
+
+/* DTEST Current Sink: control */
+#define	PM_MPP_DTEST_CS_CTL_EN1		0
+#define	PM_MPP_DTEST_CS_CTL_EN2		1
+#define	PM_MPP_DTEST_CS_CTL_EN3		2
+#define	PM_MPP_DTEST_CS_CTL_EN4		3
+
+/* DTEST Digital Output: control */
+#define	PM_MPP_DTEST_DBUS1		0
+#define	PM_MPP_DTEST_DBUS2		1
+#define	PM_MPP_DTEST_DBUS3		2
+#define	PM_MPP_DTEST_DBUS4		3
+
+/* Helper APIs */
+static inline int pm8058_mpp_config_digital_in(unsigned mpp, unsigned level,
+					       unsigned control)
+{
+	return pm8058_mpp_config(mpp, PM_MPP_TYPE_D_INPUT, level, control);
+}
+
+static inline int pm8058_mpp_config_digital_out(unsigned mpp, unsigned level,
+						unsigned control)
+{
+	return pm8058_mpp_config(mpp, PM_MPP_TYPE_D_OUTPUT, level, control);
+}
+
+static inline int pm8058_mpp_config_bi_dir(unsigned mpp, unsigned level,
+					   unsigned control)
+{
+	return pm8058_mpp_config(mpp, PM_MPP_TYPE_D_BI_DIR, level, control);
+}
+
+static inline int pm8058_mpp_config_analog_input(unsigned mpp, unsigned level,
+						 unsigned control)
+{
+	return pm8058_mpp_config(mpp, PM_MPP_TYPE_A_INPUT, level, control);
+}
+
+static inline int pm8058_mpp_config_analog_output(unsigned mpp, unsigned level,
+						  unsigned control)
+{
+	return pm8058_mpp_config(mpp, PM_MPP_TYPE_A_OUTPUT, level, control);
+}
+
+static inline int pm8058_mpp_config_current_sink(unsigned mpp, unsigned level,
+						 unsigned control)
+{
+	return pm8058_mpp_config(mpp, PM_MPP_TYPE_SINK, level, control);
+}
+
+static inline int pm8058_mpp_config_dtest_sink(unsigned mpp, unsigned level,
+					       unsigned control)
+{
+	return pm8058_mpp_config(mpp, PM_MPP_TYPE_DTEST_SINK, level, control);
+}
+
+static inline int pm8058_mpp_config_dtest_output(unsigned mpp, unsigned level,
+						 unsigned control)
+{
+	return pm8058_mpp_config(mpp, PM_MPP_TYPE_DTEST_OUTPUT,
+				 level, control);
+}
+
+static inline int pm8901_mpp_config_digital_in(unsigned mpp, unsigned level,
+					       unsigned control)
+{
+	return pm8901_mpp_config(mpp, PM_MPP_TYPE_D_INPUT, level, control);
+}
+
+static inline int pm8901_mpp_config_digital_out(unsigned mpp, unsigned level,
+						unsigned control)
+{
+	return pm8901_mpp_config(mpp, PM_MPP_TYPE_D_OUTPUT, level, control);
+}
+
+static inline int pm8901_mpp_config_bi_dir(unsigned mpp, unsigned level,
+					   unsigned control)
+{
+	return pm8901_mpp_config(mpp, PM_MPP_TYPE_D_BI_DIR, level, control);
+}
+
+static inline int pm8901_mpp_config_analog_input(unsigned mpp, unsigned level,
+						 unsigned control)
+{
+	return pm8901_mpp_config(mpp, PM_MPP_TYPE_A_INPUT, level, control);
+}
+
+static inline int pm8901_mpp_config_analog_output(unsigned mpp, unsigned level,
+						  unsigned control)
+{
+	return pm8901_mpp_config(mpp, PM_MPP_TYPE_A_OUTPUT, level, control);
+}
+
+static inline int pm8901_mpp_config_current_sink(unsigned mpp, unsigned level,
+						 unsigned control)
+{
+	return pm8901_mpp_config(mpp, PM_MPP_TYPE_SINK, level, control);
+}
+
+static inline int pm8901_mpp_config_dtest_sink(unsigned mpp, unsigned level,
+					       unsigned control)
+{
+	return pm8901_mpp_config(mpp, PM_MPP_TYPE_DTEST_SINK, level, control);
+}
+
+static inline int pm8901_mpp_config_dtest_output(unsigned mpp, unsigned level,
+						 unsigned control)
+{
+	return pm8901_mpp_config(mpp, PM_MPP_TYPE_DTEST_OUTPUT,
+				 level, control);
+}
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm-krait-l2-accessors.h b/arch/arm/mach-msm/include/mach/msm-krait-l2-accessors.h
new file mode 100644
index 0000000..f835e82
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm-krait-l2-accessors.h
@@ -0,0 +1,20 @@
+#ifndef __ASM_ARCH_MSM_MSM_KRAIT_L2_ACCESSORS_H
+#define __ASM_ARCH_MSM_MSM_KRAIT_L2_ACCESSORS_H
+
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+extern void set_l2_indirect_reg(u32 reg_addr, u32 val);
+extern u32 get_l2_indirect_reg(u32 reg_addr);
+extern u32 set_get_l2_indirect_reg(u32 reg_addr, u32 val);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm72k_otg.h b/arch/arm/mach-msm/include/mach/msm72k_otg.h
new file mode 100644
index 0000000..623de2a
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm72k_otg.h
@@ -0,0 +1,171 @@
+/* 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
+ * 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 __LINUX_USB_GADGET_MSM72K_OTG_H__
+#define __LINUX_USB_GADGET_MSM72K_OTG_H__
+
+#include <linux/usb.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <linux/wakelock.h>
+#include <mach/msm_hsusb.h>
+
+#include <asm/mach-types.h>
+#include <mach/msm_hsusb.h>
+
+#define OTGSC_BSVIE            (1 << 27)
+#define OTGSC_IDIE             (1 << 24)
+#define OTGSC_IDPU             (1 << 5)
+#define OTGSC_BSVIS            (1 << 19)
+#define OTGSC_ID               (1 << 8)
+#define OTGSC_IDIS             (1 << 16)
+#define OTGSC_BSV              (1 << 11)
+#define OTGSC_DPIE             (1 << 30)
+#define OTGSC_DPIS             (1 << 22)
+#define OTGSC_HADP             (1 << 6)
+#define OTGSC_IDPU             (1 << 5)
+
+#define ULPI_STP_CTRL   (1 << 30)
+#define ASYNC_INTR_CTRL (1 << 29)
+#define ULPI_SYNC_STATE (1 << 27)
+
+#define PORTSC_PHCD     (1 << 23)
+#define PORTSC_CSC	(1 << 1)
+#define disable_phy_clk() (writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC))
+#define enable_phy_clk() (writel(readl(USB_PORTSC) & ~PORTSC_PHCD, USB_PORTSC))
+#define is_phy_clk_disabled() (readl(USB_PORTSC) & PORTSC_PHCD)
+#define is_phy_active()       (readl_relaxed(USB_ULPI_VIEWPORT) &\
+						ULPI_SYNC_STATE)
+#define is_usb_active()       (!(readl(USB_PORTSC) & PORTSC_SUSP))
+
+/* Timeout (in msec) values (min - max) associated with OTG timers */
+
+#define TA_WAIT_VRISE	100	/* ( - 100)  */
+#define TA_WAIT_VFALL	500	/* ( - 1000) */
+
+/*
+ * This option is set for embedded hosts or OTG devices in which leakage
+ * currents are very minimal.
+ */
+#ifdef CONFIG_MSM_OTG_ENABLE_A_WAIT_BCON_TIMEOUT
+#define TA_WAIT_BCON	30000	/* (1100 - 30000) */
+#else
+#define TA_WAIT_BCON	-1
+#endif
+
+/* AIDL_BDIS should be 500 */
+#define TA_AIDL_BDIS	200	/* (200 - ) */
+#define TA_BIDL_ADIS	155	/* (155 - 200) */
+#define TB_SRP_FAIL	6000	/* (5000 - 6000) */
+#define TB_ASE0_BRST	155	/* (155 - ) */
+
+/* TB_SSEND_SRP and TB_SE0_SRP are combined */
+#define TB_SRP_INIT	2000	/* (1500 - ) */
+
+/* Timeout variables */
+
+#define A_WAIT_VRISE	0
+#define A_WAIT_VFALL	1
+#define A_WAIT_BCON	2
+#define A_AIDL_BDIS	3
+#define A_BIDL_ADIS	4
+#define B_SRP_FAIL	5
+#define B_ASE0_BRST	6
+
+/* Internal flags like a_set_b_hnp_en, b_hnp_en are maintained
+ * in usb_bus and usb_gadget
+ */
+
+#define A_BUS_DROP		0
+#define A_BUS_REQ		1
+#define A_SRP_DET		2
+#define A_VBUS_VLD		3
+#define B_CONN			4
+#define ID			5
+#define ADP_CHANGE		6
+#define POWER_UP		7
+#define A_CLR_ERR		8
+#define A_BUS_RESUME		9
+#define A_BUS_SUSPEND		10
+#define A_CONN			11
+#define B_BUS_REQ		12
+#define B_SESS_VLD		13
+#define ID_A			14
+#define ID_B			15
+#define ID_C			16
+
+#define USB_IDCHG_MIN	500
+#define USB_IDCHG_MAX	1500
+#define USB_IB_UNCFG	2
+#define OTG_ID_POLL_MS	1000
+
+struct msm_otg {
+	struct usb_phy phy;
+
+	/* usb clocks */
+	struct clk		*alt_core_clk;
+	struct clk		*iface_clk;
+	struct clk		*core_clk;
+
+	/* clk regime has created dummy clock id for phy so
+	 * that generic clk_reset api can be used to reset phy
+	 */
+	struct clk		*phy_reset_clk;
+
+	int			irq;
+	int			vbus_on_irq;
+	int			id_irq;
+	void __iomem		*regs;
+	atomic_t		in_lpm;
+	/* charger-type is modified by gadget for legacy chargers
+	 * and OTG modifies it for ACA
+	 */
+	atomic_t 		chg_type;
+
+	void (*start_host)	(struct usb_bus *bus, int suspend);
+	/* Enable/disable the clocks */
+	int (*set_clk)		(struct usb_phy *phy, int on);
+	/* Reset phy and link */
+	void (*reset)		(struct usb_phy *phy, int phy_reset);
+	/* pmic notfications apis */
+	u8 pmic_vbus_notif_supp;
+	u8 pmic_id_notif_supp;
+	struct msm_otg_platform_data *pdata;
+
+	spinlock_t lock; /* protects OTG state */
+	struct wake_lock wlock;
+	unsigned long b_last_se0_sess; /* SRP initial condition check */
+	unsigned long inputs;
+	unsigned long tmouts;
+	u8 active_tmout;
+	struct hrtimer timer;
+	struct workqueue_struct *wq;
+	struct work_struct sm_work; /* state machine work */
+	struct work_struct otg_resume_work;
+	struct notifier_block usbdev_nb;
+	struct msm_xo_voter *xo_handle; /*handle to vote for TCXO D1 buffer*/
+#ifdef CONFIG_USB_MSM_ACA
+	struct timer_list	id_timer;	/* drives id_status polling */
+	unsigned		b_max_power;	/* ACA: max power of accessory*/
+#endif
+};
+
+static inline int can_phy_power_collapse(struct msm_otg *dev)
+{
+	if (!dev || !dev->pdata)
+		return -ENODEV;
+
+	return dev->pdata->phy_can_powercollapse;
+}
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_adsp.h b/arch/arm/mach-msm/include/mach/msm_adsp.h
new file mode 100644
index 0000000..e40c07d
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_adsp.h
@@ -0,0 +1,111 @@
+/* include/asm-arm/arch-msm/msm_adsp.h
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2009-2010, 2012 Code Aurora Forum. 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_ADSP_H
+#define __ASM__ARCH_MSM_ADSP_H
+
+struct msm_adsp_module;
+
+struct msm_adsp_ops {
+	/* event is called from interrupt context when a message
+	 * arrives from the DSP.  Use the provided function pointer
+	 * to copy the message into a local buffer.  Do NOT call
+	 * it multiple times.
+	 */
+	void (*event)(void *driver_data, unsigned id, size_t len,
+		      void (*getevent)(void *ptr, size_t len));
+};
+
+/* Get, Put, Enable, and Disable are synchronous and must only
+ * be called from thread context.  Enable and Disable will block
+ * up to one second in the event of a fatal DSP error but are
+ * much faster otherwise.
+ */
+int msm_adsp_get(const char *name, struct msm_adsp_module **module,
+		 struct msm_adsp_ops *ops, void *driver_data);
+void msm_adsp_put(struct msm_adsp_module *module);
+int msm_adsp_enable(struct msm_adsp_module *module);
+int msm_adsp_disable(struct msm_adsp_module *module);
+int adsp_set_clkrate(struct msm_adsp_module *module, unsigned long clk_rate);
+int msm_adsp_disable_event_rsp(struct msm_adsp_module *module);
+int32_t get_adsp_resource(unsigned short client_idx,
+				void *cmd_buf, size_t cmd_size);
+int32_t put_adsp_resource(unsigned short client_idx,
+				void *cmd_buf, size_t cmd_size);
+
+/* Write is safe to call from interrupt context.
+ */
+int msm_adsp_write(struct msm_adsp_module *module,
+		   unsigned queue_id,
+		   void *data, size_t len);
+
+/*Explicitly gererate adsp event */
+int msm_adsp_generate_event(void *data,
+			struct msm_adsp_module *mod,
+			unsigned event_id,
+			unsigned event_length,
+			unsigned event_size,
+			void *msg);
+
+#define ADSP_MESSAGE_ID 0xFFFF
+
+/* Command Queue Indexes */
+#define QDSP_lpmCommandQueue              0
+#define QDSP_mpuAfeQueue                  1
+#define QDSP_mpuGraphicsCmdQueue          2
+#define QDSP_mpuModmathCmdQueue           3
+#define QDSP_mpuVDecCmdQueue              4
+#define QDSP_mpuVDecPktQueue              5
+#define QDSP_mpuVEncCmdQueue              6
+#define QDSP_rxMpuDecCmdQueue             7
+#define QDSP_rxMpuDecPktQueue             8
+#define QDSP_txMpuEncQueue                9
+#define QDSP_uPAudPPCmd1Queue             10
+#define QDSP_uPAudPPCmd2Queue             11
+#define QDSP_uPAudPPCmd3Queue             12
+#define QDSP_uPAudPlay0BitStreamCtrlQueue 13
+#define QDSP_uPAudPlay1BitStreamCtrlQueue 14
+#define QDSP_uPAudPlay2BitStreamCtrlQueue 15
+#define QDSP_uPAudPlay3BitStreamCtrlQueue 16
+#define QDSP_uPAudPlay4BitStreamCtrlQueue 17
+#define QDSP_uPAudPreProcCmdQueue         18
+#define QDSP_uPAudRecBitStreamQueue       19
+#define QDSP_uPAudRecCmdQueue             20
+#define QDSP_uPDiagQueue                  21
+#define QDSP_uPJpegActionCmdQueue         22
+#define QDSP_uPJpegCfgCmdQueue            23
+#define QDSP_uPVocProcQueue               24
+#define QDSP_vfeCommandQueue              25
+#define QDSP_vfeCommandScaleQueue         26
+#define QDSP_vfeCommandTableQueue         27
+#define QDSP_vfeFtmCmdQueue               28
+#define QDSP_vfeFtmCmdScaleQueue          29
+#define QDSP_vfeFtmCmdTableQueue          30
+#define QDSP_uPJpegFtmCfgCmdQueue         31
+#define QDSP_uPJpegFtmActionCmdQueue      32
+#define QDSP_apuAfeQueue                  33
+#define QDSP_mpuRmtQueue                  34
+#define QDSP_uPAudPreProcAudRecCmdQueue   35
+#define QDSP_uPAudRec0BitStreamQueue      36
+#define QDSP_uPAudRec0CmdQueue            37
+#define QDSP_uPAudRec1BitStreamQueue      38
+#define QDSP_uPAudRec1CmdQueue            39
+#define QDSP_apuRmtQueue                  40
+#define QDSP_uPAudRec2BitStreamQueue      41
+#define QDSP_uPAudRec2CmdQueue            42
+#define QDSP_MAX_NUM_QUEUES               43
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_audio_aac.h b/arch/arm/mach-msm/include/mach/msm_audio_aac.h
new file mode 100644
index 0000000..8c4d91b
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_audio_aac.h
@@ -0,0 +1,71 @@
+/* arch/arm/mach-msm/include/mach/msm_audio_aac.h
+ *
+ * Copyright (c) 2009 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 __MSM_AUDIO_AAC_H
+#define __MSM_AUDIO_AAC_H
+
+#include <linux/msm_audio.h>
+
+#define AUDIO_SET_AAC_CONFIG  _IOW(AUDIO_IOCTL_MAGIC, \
+  (AUDIO_MAX_COMMON_IOCTL_NUM+0), unsigned)
+#define AUDIO_GET_AAC_CONFIG  _IOR(AUDIO_IOCTL_MAGIC, \
+  (AUDIO_MAX_COMMON_IOCTL_NUM+1), unsigned)
+
+#define AUDIO_AAC_FORMAT_ADTS		-1
+#define	AUDIO_AAC_FORMAT_RAW		0x0000
+#define	AUDIO_AAC_FORMAT_PSUEDO_RAW	0x0001
+#define AUDIO_AAC_FORMAT_LOAS		0x0002
+
+#define AUDIO_AAC_OBJECT_LC            	0x0002
+#define AUDIO_AAC_OBJECT_LTP		0x0004
+#define AUDIO_AAC_OBJECT_ERLC  		0x0011
+
+#define AUDIO_AAC_SEC_DATA_RES_ON       0x0001
+#define AUDIO_AAC_SEC_DATA_RES_OFF      0x0000
+
+#define AUDIO_AAC_SCA_DATA_RES_ON       0x0001
+#define AUDIO_AAC_SCA_DATA_RES_OFF      0x0000
+
+#define AUDIO_AAC_SPEC_DATA_RES_ON      0x0001
+#define AUDIO_AAC_SPEC_DATA_RES_OFF     0x0000
+
+#define AUDIO_AAC_SBR_ON_FLAG_ON	0x0001
+#define AUDIO_AAC_SBR_ON_FLAG_OFF	0x0000
+
+#define AUDIO_AAC_SBR_PS_ON_FLAG_ON	0x0001
+#define AUDIO_AAC_SBR_PS_ON_FLAG_OFF	0x0000
+
+/* Primary channel on both left and right channels */
+#define AUDIO_AAC_DUAL_MONO_PL_PR  0
+/* Secondary channel on both left and right channels */
+#define AUDIO_AAC_DUAL_MONO_SL_SR  1
+/* Primary channel on right channel and 2nd on left channel */
+#define AUDIO_AAC_DUAL_MONO_SL_PR  2
+/* 2nd channel on right channel and primary on left channel */
+#define AUDIO_AAC_DUAL_MONO_PL_SR  3
+
+struct msm_audio_aac_config {
+	signed short format;
+	unsigned short audio_object;
+	unsigned short ep_config;	/* 0 ~ 3 useful only obj = ERLC */
+	unsigned short aac_section_data_resilience_flag;
+	unsigned short aac_scalefactor_data_resilience_flag;
+	unsigned short aac_spectral_data_resilience_flag;
+	unsigned short sbr_on_flag;
+	unsigned short sbr_ps_on_flag;
+	unsigned short dual_mono_mode;
+	unsigned short channel_configuration;
+};
+
+#endif /* __MSM_AUDIO_AAC_H */
diff --git a/arch/arm/mach-msm/include/mach/msm_battery.h b/arch/arm/mach-msm/include/mach/msm_battery.h
new file mode 100644
index 0000000..c54e7d8
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_battery.h
@@ -0,0 +1,29 @@
+/* Copyright (c) 2009, 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 __MSM_BATTERY_H__
+#define __MSM_BATTERY_H__
+
+#define AC_CHG     0x00000001
+#define USB_CHG    0x00000002
+
+struct msm_psy_batt_pdata {
+	u32 voltage_max_design;
+	u32 voltage_min_design;
+	u32 avail_chg_sources;
+	u32 batt_technology;
+	u32 (*calculate_capacity)(u32 voltage);
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_bus.h b/arch/arm/mach-msm/include/mach/msm_bus.h
new file mode 100644
index 0000000..6d7a533
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_bus.h
@@ -0,0 +1,113 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _ARCH_ARM_MACH_MSM_BUS_H
+#define _ARCH_ARM_MACH_MSM_BUS_H
+
+#include <linux/types.h>
+#include <linux/input.h>
+
+/*
+ * Macros for clients to convert their data to ib and ab
+ * Ws : Time window over which to transfer the data in SECONDS
+ * Bs : Size of the data block in bytes
+ * Per : Recurrence period
+ * Tb : Throughput bandwidth to prevent stalling
+ * R  : Ratio of actual bandwidth used to Tb
+ * Ib : Instantaneous bandwidth
+ * Ab : Arbitrated bandwidth
+ *
+ * IB_RECURRBLOCK and AB_RECURRBLOCK:
+ * These are used if the requirement is to transfer a
+ * recurring block of data over a known time window.
+ *
+ * IB_THROUGHPUTBW and AB_THROUGHPUTBW:
+ * These are used for CPU style masters. Here the requirement
+ * is to have minimum throughput bandwidth available to avoid
+ * stalling.
+ */
+#define IB_RECURRBLOCK(Ws, Bs) ((Ws) == 0 ? 0 : ((Bs)/(Ws)))
+#define AB_RECURRBLOCK(Ws, Per) ((Ws) == 0 ? 0 : ((Bs)/(Per)))
+#define IB_THROUGHPUTBW(Tb) (Tb)
+#define AB_THROUGHPUTBW(Tb, R) ((Tb) * (R))
+
+struct msm_bus_vectors {
+	int src; /* Master */
+	int dst; /* Slave */
+	unsigned int ab; /* Arbitrated bandwidth */
+	unsigned int ib; /* Instantaneous bandwidth */
+};
+
+struct msm_bus_paths {
+	int num_paths;
+	struct msm_bus_vectors *vectors;
+};
+
+struct msm_bus_scale_pdata {
+	struct msm_bus_paths *usecase;
+	int num_usecases;
+	const char *name;
+	/*
+	 * If the active_only flag is set to 1, the BW request is applied
+	 * only when at least one CPU is active (powered on). If the flag
+	 * is set to 0, then the BW request is always applied irrespective
+	 * of the CPU state.
+	 */
+	unsigned int active_only;
+};
+
+/* Scaling APIs */
+
+/*
+ * This function returns a handle to the client. This should be used to
+ * call msm_bus_scale_client_update_request.
+ * The function returns 0 if bus driver is unable to register a client
+ */
+
+#ifdef CONFIG_MSM_BUS_SCALING
+uint32_t msm_bus_scale_register_client(struct msm_bus_scale_pdata *pdata);
+int msm_bus_scale_client_update_request(uint32_t cl, unsigned int index);
+void msm_bus_scale_unregister_client(uint32_t cl);
+/* AXI Port configuration APIs */
+int msm_bus_axi_porthalt(int master_port);
+int msm_bus_axi_portunhalt(int master_port);
+
+#else
+static inline uint32_t
+msm_bus_scale_register_client(struct msm_bus_scale_pdata *pdata)
+{
+	return 1;
+}
+
+static inline int
+msm_bus_scale_client_update_request(uint32_t cl, unsigned int index)
+{
+	return 0;
+}
+
+static inline void
+msm_bus_scale_unregister_client(uint32_t cl)
+{
+}
+
+static inline int msm_bus_axi_porthalt(int master_port)
+{
+	return 0;
+}
+
+static inline int msm_bus_axi_portunhalt(int master_port)
+{
+	return 0;
+}
+#endif
+
+#endif /*_ARCH_ARM_MACH_MSM_BUS_H*/
diff --git a/arch/arm/mach-msm/include/mach/msm_bus_board.h b/arch/arm/mach-msm/include/mach/msm_bus_board.h
new file mode 100644
index 0000000..956d44e
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_bus_board.h
@@ -0,0 +1,433 @@
+/* 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
+ * 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 __ASM_ARCH_MSM_BUS_BOARD_H
+#define __ASM_ARCH_MSM_BUS_BOARD_H
+
+#include <linux/types.h>
+#include <linux/input.h>
+
+enum context {
+	DUAL_CTX,
+	ACTIVE_CTX,
+	NUM_CTX
+};
+
+struct msm_bus_fabric_registration {
+	unsigned int id;
+	char *name;
+	struct msm_bus_node_info *info;
+	unsigned int len;
+	int ahb;
+	const char *fabclk[NUM_CTX];
+	unsigned int offset;
+	unsigned int haltid;
+	unsigned int rpm_enabled;
+	const unsigned int nmasters;
+	const unsigned int nslaves;
+	const unsigned int ntieredslaves;
+	bool il_flag;
+	const struct msm_bus_board_algorithm *board_algo;
+	int hw_sel;
+	void *hw_data;
+};
+
+enum msm_bus_bw_tier_type {
+	MSM_BUS_BW_TIER1 = 1,
+	MSM_BUS_BW_TIER2,
+	MSM_BUS_BW_COUNT,
+	MSM_BUS_BW_SIZE = 0x7FFFFFFF,
+};
+
+struct msm_bus_halt_vector {
+	uint32_t haltval;
+	uint32_t haltmask;
+};
+
+extern struct msm_bus_fabric_registration msm_bus_apps_fabric_pdata;
+extern struct msm_bus_fabric_registration msm_bus_sys_fabric_pdata;
+extern struct msm_bus_fabric_registration msm_bus_mm_fabric_pdata;
+extern struct msm_bus_fabric_registration msm_bus_sys_fpb_pdata;
+extern struct msm_bus_fabric_registration msm_bus_cpss_fpb_pdata;
+extern struct msm_bus_fabric_registration msm_bus_def_fab_pdata;
+
+extern struct msm_bus_fabric_registration msm_bus_8960_apps_fabric_pdata;
+extern struct msm_bus_fabric_registration msm_bus_8960_sys_fabric_pdata;
+extern struct msm_bus_fabric_registration msm_bus_8960_mm_fabric_pdata;
+extern struct msm_bus_fabric_registration msm_bus_8960_sys_fpb_pdata;
+extern struct msm_bus_fabric_registration msm_bus_8960_cpss_fpb_pdata;
+
+extern struct msm_bus_fabric_registration msm_bus_8064_apps_fabric_pdata;
+extern struct msm_bus_fabric_registration msm_bus_8064_sys_fabric_pdata;
+extern struct msm_bus_fabric_registration msm_bus_8064_mm_fabric_pdata;
+extern struct msm_bus_fabric_registration msm_bus_8064_sys_fpb_pdata;
+extern struct msm_bus_fabric_registration msm_bus_8064_cpss_fpb_pdata;
+
+extern struct msm_bus_fabric_registration msm_bus_9615_sys_fabric_pdata;
+extern struct msm_bus_fabric_registration msm_bus_9615_def_fab_pdata;
+
+extern struct msm_bus_fabric_registration msm_bus_8930_apps_fabric_pdata;
+extern struct msm_bus_fabric_registration msm_bus_8930_sys_fabric_pdata;
+extern struct msm_bus_fabric_registration msm_bus_8930_mm_fabric_pdata;
+extern struct msm_bus_fabric_registration msm_bus_8930_sys_fpb_pdata;
+extern struct msm_bus_fabric_registration msm_bus_8930_cpss_fpb_pdata;
+
+void msm_bus_rpm_set_mt_mask(void);
+int msm_bus_board_rpm_get_il_ids(uint16_t *id);
+int msm_bus_board_get_iid(int id);
+
+/*
+ * These macros specify the convention followed for allocating
+ * ids to fabrics, masters and slaves for 8x60.
+ *
+ * A node can be identified as a master/slave/fabric by using
+ * these ids.
+ */
+#define FABRIC_ID_KEY 1024
+#define SLAVE_ID_KEY ((FABRIC_ID_KEY) >> 1)
+#define NUM_FAB 5
+#define MAX_FAB_KEY 7168  /* OR(All fabric ids) */
+
+#define GET_FABID(id) ((id) & MAX_FAB_KEY)
+
+#define NODE_ID(id) ((id) & (FABRIC_ID_KEY - 1))
+#define IS_SLAVE(id) ((NODE_ID(id)) >= SLAVE_ID_KEY ? 1 : 0)
+#define CHECK_ID(iid, id) (((iid & id) != id) ? -ENXIO : iid)
+
+/*
+ * The following macros are used to format the data for port halt
+ * and unhalt requests.
+ */
+#define MSM_BUS_CLK_HALT 0x1
+#define MSM_BUS_CLK_HALT_MASK 0x1
+#define MSM_BUS_CLK_HALT_FIELDSIZE 0x1
+#define MSM_BUS_CLK_UNHALT 0x0
+
+#define MSM_BUS_MASTER_SHIFT(master, fieldsize) \
+	((master) * (fieldsize))
+
+#define MSM_BUS_SET_BITFIELD(word, fieldmask, fieldvalue) \
+	{	\
+		(word) &= ~(fieldmask);	\
+		(word) |= (fieldvalue);	\
+	}
+
+
+#define MSM_BUS_MASTER_HALT(u32haltmask, u32haltval, master) \
+	MSM_BUS_SET_BITFIELD(u32haltmask, \
+		MSM_BUS_CLK_HALT_MASK<<MSM_BUS_MASTER_SHIFT((master),\
+		MSM_BUS_CLK_HALT_FIELDSIZE), \
+		MSM_BUS_CLK_HALT_MASK<<MSM_BUS_MASTER_SHIFT((master),\
+		MSM_BUS_CLK_HALT_FIELDSIZE))\
+	MSM_BUS_SET_BITFIELD(u32haltval, \
+		MSM_BUS_CLK_HALT_MASK<<MSM_BUS_MASTER_SHIFT((master),\
+		MSM_BUS_CLK_HALT_FIELDSIZE), \
+		MSM_BUS_CLK_HALT<<MSM_BUS_MASTER_SHIFT((master),\
+		MSM_BUS_CLK_HALT_FIELDSIZE))\
+
+#define MSM_BUS_MASTER_UNHALT(u32haltmask, u32haltval, master) \
+	MSM_BUS_SET_BITFIELD(u32haltmask, \
+		MSM_BUS_CLK_HALT_MASK<<MSM_BUS_MASTER_SHIFT((master),\
+		MSM_BUS_CLK_HALT_FIELDSIZE), \
+		MSM_BUS_CLK_HALT_MASK<<MSM_BUS_MASTER_SHIFT((master),\
+		MSM_BUS_CLK_HALT_FIELDSIZE))\
+	MSM_BUS_SET_BITFIELD(u32haltval, \
+		MSM_BUS_CLK_HALT_MASK<<MSM_BUS_MASTER_SHIFT((master),\
+		MSM_BUS_CLK_HALT_FIELDSIZE), \
+		MSM_BUS_CLK_UNHALT<<MSM_BUS_MASTER_SHIFT((master),\
+		MSM_BUS_CLK_HALT_FIELDSIZE))\
+
+/* Topology related enums */
+enum msm_bus_fabric_type {
+	MSM_BUS_FAB_DEFAULT = 0,
+	MSM_BUS_FAB_APPSS = 0,
+	MSM_BUS_FAB_SYSTEM = 1024,
+	MSM_BUS_FAB_MMSS = 2048,
+	MSM_BUS_FAB_SYSTEM_FPB = 3072,
+	MSM_BUS_FAB_CPSS_FPB = 4096,
+};
+
+enum msm_bus_fab_noc_bimc_type {
+	MSM_BUS_FAB_BIMC = 0,
+	MSM_BUS_FAB_SYS_NOC = 1024,
+	MSM_BUS_FAB_MMSS_NOC = 2048,
+	MSM_BUS_FAB_OCMEM_NOC = 3072,
+	MSM_BUS_FAB_PERIPH_NOC = 4096,
+	MSM_BUS_FAB_CONFIG_NOC = 5120,
+	MSM_BUS_FAB_OCMEM_VNOC = 6144,
+};
+
+enum msm_bus_fabric_master_type {
+	MSM_BUS_MASTER_FIRST = 1,
+	MSM_BUS_MASTER_AMPSS_M0 = 1,
+	MSM_BUS_MASTER_AMPSS_M1,
+	MSM_BUS_APPSS_MASTER_FAB_MMSS,
+	MSM_BUS_APPSS_MASTER_FAB_SYSTEM,
+
+	MSM_BUS_SYSTEM_MASTER_FAB_APPSS,
+	MSM_BUS_MASTER_SPS,
+	MSM_BUS_MASTER_ADM_PORT0,
+	MSM_BUS_MASTER_ADM_PORT1,
+	MSM_BUS_SYSTEM_MASTER_ADM1_PORT0,
+	MSM_BUS_MASTER_ADM1_PORT1,
+	MSM_BUS_MASTER_LPASS_PROC,
+	MSM_BUS_MASTER_MSS_PROCI,
+	MSM_BUS_MASTER_MSS_PROCD,
+	MSM_BUS_MASTER_MSS_MDM_PORT0,
+	MSM_BUS_MASTER_LPASS,
+	MSM_BUS_SYSTEM_MASTER_CPSS_FPB,
+	MSM_BUS_SYSTEM_MASTER_SYSTEM_FPB,
+	MSM_BUS_SYSTEM_MASTER_MMSS_FPB,
+	MSM_BUS_MASTER_ADM1_CI,
+	MSM_BUS_MASTER_ADM0_CI,
+	MSM_BUS_MASTER_MSS_MDM_PORT1,
+
+	MSM_BUS_MASTER_MDP_PORT0,
+	MSM_BUS_MASTER_MDP_PORT1,
+	MSM_BUS_MMSS_MASTER_ADM1_PORT0,
+	MSM_BUS_MASTER_ROTATOR,
+	MSM_BUS_MASTER_GRAPHICS_3D,
+	MSM_BUS_MASTER_JPEG_DEC,
+	MSM_BUS_MASTER_GRAPHICS_2D_CORE0,
+	MSM_BUS_MASTER_VFE,
+	MSM_BUS_MASTER_VPE,
+	MSM_BUS_MASTER_JPEG_ENC,
+	MSM_BUS_MASTER_GRAPHICS_2D_CORE1,
+	MSM_BUS_MMSS_MASTER_APPS_FAB,
+	MSM_BUS_MASTER_HD_CODEC_PORT0,
+	MSM_BUS_MASTER_HD_CODEC_PORT1,
+
+	MSM_BUS_MASTER_SPDM,
+	MSM_BUS_MASTER_RPM,
+
+	MSM_BUS_MASTER_MSS,
+	MSM_BUS_MASTER_RIVA,
+	MSM_BUS_SYSTEM_MASTER_UNUSED_6,
+	MSM_BUS_MASTER_MSS_SW_PROC,
+	MSM_BUS_MASTER_MSS_FW_PROC,
+	MSM_BUS_MMSS_MASTER_UNUSED_2,
+	MSM_BUS_MASTER_GSS_NAV,
+	MSM_BUS_MASTER_PCIE,
+	MSM_BUS_MASTER_SATA,
+	MSM_BUS_MASTER_CRYPTO,
+
+	MSM_BUS_MASTER_VIDEO_CAP,
+	MSM_BUS_MASTER_GRAPHICS_3D_PORT1,
+	MSM_BUS_MASTER_VIDEO_ENC,
+	MSM_BUS_MASTER_VIDEO_DEC,
+
+	MSM_BUS_MASTER_LPASS_AHB,
+	MSM_BUS_MASTER_QDSS_BAM,
+	MSM_BUS_MASTER_SNOC_CFG,
+	MSM_BUS_MASTER_CRYPTO_CORE0,
+	MSM_BUS_MASTER_CRYPTO_CORE1,
+	MSM_BUS_MASTER_MSS_NAV,
+	MSM_BUS_MASTER_OCMEM_DMA,
+	MSM_BUS_MASTER_WCSS,
+	MSM_BUS_MASTER_QDSS_ETR,
+	MSM_BUS_MASTER_USB3,
+
+	MSM_BUS_MASTER_JPEG,
+	MSM_BUS_MASTER_VIDEO_P0,
+	MSM_BUS_MASTER_VIDEO_P1,
+
+	MSM_BUS_MASTER_MSS_PROC,
+	MSM_BUS_MASTER_JPEG_OCMEM,
+	MSM_BUS_MASTER_MDP_OCMEM,
+	MSM_BUS_MASTER_VIDEO_P0_OCMEM,
+	MSM_BUS_MASTER_VIDEO_P1_OCMEM,
+	MSM_BUS_MASTER_VFE_OCMEM,
+	MSM_BUS_MASTER_CNOC_ONOC_CFG,
+	MSM_BUS_MASTER_RPM_INST,
+	MSM_BUS_MASTER_RPM_DATA,
+	MSM_BUS_MASTER_RPM_SYS,
+	MSM_BUS_MASTER_DEHR,
+	MSM_BUS_MASTER_QDSS_DAP,
+	MSM_BUS_MASTER_TIC,
+
+	MSM_BUS_MASTER_SDCC_1,
+	MSM_BUS_MASTER_SDCC_3,
+	MSM_BUS_MASTER_SDCC_4,
+	MSM_BUS_MASTER_SDCC_2,
+	MSM_BUS_MASTER_TSIF,
+	MSM_BUS_MASTER_BAM_DMA,
+	MSM_BUS_MASTER_BLSP_2,
+	MSM_BUS_MASTER_USB_HSIC,
+	MSM_BUS_MASTER_BLSP_1,
+	MSM_BUS_MASTER_USB_HS,
+	MSM_BUS_MASTER_PNOC_CFG,
+	MSM_BUS_MASTER_V_OCMEM_GFX3D,
+
+	MSM_BUS_MASTER_LAST = MSM_BUS_MASTER_V_OCMEM_GFX3D,
+
+	MSM_BUS_SYSTEM_FPB_MASTER_SYSTEM =
+		MSM_BUS_SYSTEM_MASTER_SYSTEM_FPB,
+	MSM_BUS_CPSS_FPB_MASTER_SYSTEM =
+		MSM_BUS_SYSTEM_MASTER_CPSS_FPB,
+};
+
+enum msm_bus_fabric_slave_type {
+	MSM_BUS_SLAVE_FIRST = SLAVE_ID_KEY,
+	MSM_BUS_SLAVE_EBI_CH0 = SLAVE_ID_KEY,
+	MSM_BUS_SLAVE_EBI_CH1,
+	MSM_BUS_SLAVE_AMPSS_L2,
+	MSM_BUS_APPSS_SLAVE_FAB_MMSS,
+	MSM_BUS_APPSS_SLAVE_FAB_SYSTEM,
+
+	MSM_BUS_SYSTEM_SLAVE_FAB_APPS,
+	MSM_BUS_SLAVE_SPS,
+	MSM_BUS_SLAVE_SYSTEM_IMEM,
+	MSM_BUS_SLAVE_AMPSS,
+	MSM_BUS_SLAVE_MSS,
+	MSM_BUS_SLAVE_LPASS,
+	MSM_BUS_SYSTEM_SLAVE_CPSS_FPB,
+	MSM_BUS_SYSTEM_SLAVE_SYSTEM_FPB,
+	MSM_BUS_SYSTEM_SLAVE_MMSS_FPB,
+	MSM_BUS_SLAVE_CORESIGHT,
+	MSM_BUS_SLAVE_RIVA,
+
+	MSM_BUS_SLAVE_SMI,
+	MSM_BUS_MMSS_SLAVE_FAB_APPS,
+	MSM_BUS_MMSS_SLAVE_FAB_APPS_1,
+	MSM_BUS_SLAVE_MM_IMEM,
+	MSM_BUS_SLAVE_CRYPTO,
+
+	MSM_BUS_SLAVE_SPDM,
+	MSM_BUS_SLAVE_RPM,
+	MSM_BUS_SLAVE_RPM_MSG_RAM,
+	MSM_BUS_SLAVE_MPM,
+	MSM_BUS_SLAVE_PMIC1_SSBI1_A,
+	MSM_BUS_SLAVE_PMIC1_SSBI1_B,
+	MSM_BUS_SLAVE_PMIC1_SSBI1_C,
+	MSM_BUS_SLAVE_PMIC2_SSBI2_A,
+	MSM_BUS_SLAVE_PMIC2_SSBI2_B,
+
+	MSM_BUS_SLAVE_GSBI1_UART,
+	MSM_BUS_SLAVE_GSBI2_UART,
+	MSM_BUS_SLAVE_GSBI3_UART,
+	MSM_BUS_SLAVE_GSBI4_UART,
+	MSM_BUS_SLAVE_GSBI5_UART,
+	MSM_BUS_SLAVE_GSBI6_UART,
+	MSM_BUS_SLAVE_GSBI7_UART,
+	MSM_BUS_SLAVE_GSBI8_UART,
+	MSM_BUS_SLAVE_GSBI9_UART,
+	MSM_BUS_SLAVE_GSBI10_UART,
+	MSM_BUS_SLAVE_GSBI11_UART,
+	MSM_BUS_SLAVE_GSBI12_UART,
+	MSM_BUS_SLAVE_GSBI1_QUP,
+	MSM_BUS_SLAVE_GSBI2_QUP,
+	MSM_BUS_SLAVE_GSBI3_QUP,
+	MSM_BUS_SLAVE_GSBI4_QUP,
+	MSM_BUS_SLAVE_GSBI5_QUP,
+	MSM_BUS_SLAVE_GSBI6_QUP,
+	MSM_BUS_SLAVE_GSBI7_QUP,
+	MSM_BUS_SLAVE_GSBI8_QUP,
+	MSM_BUS_SLAVE_GSBI9_QUP,
+	MSM_BUS_SLAVE_GSBI10_QUP,
+	MSM_BUS_SLAVE_GSBI11_QUP,
+	MSM_BUS_SLAVE_GSBI12_QUP,
+	MSM_BUS_SLAVE_EBI2_NAND,
+	MSM_BUS_SLAVE_EBI2_CS0,
+	MSM_BUS_SLAVE_EBI2_CS1,
+	MSM_BUS_SLAVE_EBI2_CS2,
+	MSM_BUS_SLAVE_EBI2_CS3,
+	MSM_BUS_SLAVE_EBI2_CS4,
+	MSM_BUS_SLAVE_EBI2_CS5,
+	MSM_BUS_SLAVE_USB_FS1,
+	MSM_BUS_SLAVE_USB_FS2,
+	MSM_BUS_SLAVE_TSIF,
+	MSM_BUS_SLAVE_MSM_TSSC,
+	MSM_BUS_SLAVE_MSM_PDM,
+	MSM_BUS_SLAVE_MSM_DIMEM,
+	MSM_BUS_SLAVE_MSM_TCSR,
+	MSM_BUS_SLAVE_MSM_PRNG,
+	MSM_BUS_SLAVE_GSS,
+	MSM_BUS_SLAVE_SATA,
+
+	MSM_BUS_SLAVE_USB3,
+	MSM_BUS_SLAVE_WCSS,
+	MSM_BUS_SLAVE_OCIMEM,
+	MSM_BUS_SLAVE_SNOC_OCMEM,
+	MSM_BUS_SLAVE_SERVICE_SNOC,
+	MSM_BUS_SLAVE_QDSS_STM,
+
+	MSM_BUS_SLAVE_CAMERA_CFG,
+	MSM_BUS_SLAVE_DISPLAY_CFG,
+	MSM_BUS_SLAVE_OCMEM_CFG,
+	MSM_BUS_SLAVE_CPR_CFG,
+	MSM_BUS_SLAVE_CPR_XPU_CFG,
+	MSM_BUS_SLAVE_MISC_CFG,
+	MSM_BUS_SLAVE_MISC_XPU_CFG,
+	MSM_BUS_SLAVE_VENUS_CFG,
+	MSM_BUS_SLAVE_MISC_VENUS_CFG,
+	MSM_BUS_SLAVE_GRAPHICS_3D_CFG,
+	MSM_BUS_SLAVE_MMSS_CLK_CFG,
+	MSM_BUS_SLAVE_MMSS_CLK_XPU_CFG,
+	MSM_BUS_SLAVE_MNOC_MPU_CFG,
+	MSM_BUS_SLAVE_ONOC_MPU_CFG,
+	MSM_BUS_SLAVE_SERVICE_MNOC,
+
+	MSM_BUS_SLAVE_OCMEM,
+	MSM_BUS_SLAVE_SERVICE_ONOC,
+
+	MSM_BUS_SLAVE_SDCC_1,
+	MSM_BUS_SLAVE_SDCC_3,
+	MSM_BUS_SLAVE_SDCC_2,
+	MSM_BUS_SLAVE_SDCC_4,
+	MSM_BUS_SLAVE_BAM_DMA,
+	MSM_BUS_SLAVE_BLSP_2,
+	MSM_BUS_SLAVE_USB_HSIC,
+	MSM_BUS_SLAVE_BLSP_1,
+	MSM_BUS_SLAVE_USB_HS,
+	MSM_BUS_SLAVE_PDM,
+	MSM_BUS_SLAVE_PERIPH_APU_CFG,
+	MSM_BUS_SLAVE_PNOC_MPU_CFG,
+	MSM_BUS_SLAVE_PRNG,
+	MSM_BUS_SLAVE_SERVICE_PNOC,
+
+	MSM_BUS_SLAVE_CLK_CTL,
+	MSM_BUS_SLAVE_CNOC_MSS,
+	MSM_BUS_SLAVE_SECURITY,
+	MSM_BUS_SLAVE_TCSR,
+	MSM_BUS_SLAVE_TLMM,
+	MSM_BUS_SLAVE_CRYPTO_0_CFG,
+	MSM_BUS_SLAVE_CRYPTO_1_CFG,
+	MSM_BUS_SLAVE_IMEM_CFG,
+	MSM_BUS_SLAVE_MESSAGE_RAM,
+	MSM_BUS_SLAVE_BIMC_CFG,
+	MSM_BUS_SLAVE_BOOT_ROM,
+	MSM_BUS_SLAVE_CNOC_MNOC_MMSS_CFG,
+	MSM_BUS_SLAVE_PMIC_ARB,
+	MSM_BUS_SLAVE_SPDM_WRAPPER,
+	MSM_BUS_SLAVE_DEHR_CFG,
+	MSM_BUS_SLAVE_QDSS_CFG,
+	MSM_BUS_SLAVE_RBCPR_CFG,
+	MSM_BUS_SLAVE_RBCPR_QDSS_APU_CFG,
+	MSM_BUS_SLAVE_SNOC_MPU_CFG,
+	MSM_BUS_SLAVE_CNOC_ONOC_CFG,
+	MSM_BUS_SLAVE_CNOC_MNOC_CFG,
+	MSM_BUS_SLAVE_PNOC_CFG,
+	MSM_BUS_SLAVE_SNOC_CFG,
+	MSM_BUS_SLAVE_EBI1_DLL_CFG,
+	MSM_BUS_SLAVE_PHY_APU_CFG,
+	MSM_BUS_SLAVE_EBI1_PHY_CFG,
+	MSM_BUS_SLAVE_SERVICE_CNOC,
+
+	MSM_BUS_SLAVE_LAST = MSM_BUS_SLAVE_SERVICE_CNOC,
+
+	MSM_BUS_SYSTEM_FPB_SLAVE_SYSTEM =
+		MSM_BUS_SYSTEM_SLAVE_SYSTEM_FPB,
+	MSM_BUS_CPSS_FPB_SLAVE_SYSTEM =
+		MSM_BUS_SYSTEM_SLAVE_CPSS_FPB,
+};
+
+#endif /*__ASM_ARCH_MSM_BUS_BOARD_H */
diff --git a/arch/arm/mach-msm/include/mach/msm_cache_dump.h b/arch/arm/mach-msm/include/mach/msm_cache_dump.h
new file mode 100644
index 0000000..80f4159
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_cache_dump.h
@@ -0,0 +1,69 @@
+/*
+ * 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 _MACH_MSM_CACHE_DUMP_
+#define _MACH_MSM_CACHE_DUMP_
+
+#include <asm-generic/sizes.h>
+
+
+struct l2_cache_line_dump {
+	unsigned int l2dcrtr0_val;
+	unsigned int l2dcrtr1_val;
+	unsigned int cache_line_data[32];
+	unsigned int ddr_data[32];
+} __packed;
+
+struct l2_cache_dump {
+	unsigned int magic_number;
+	unsigned int version;
+	unsigned int tag_size;
+	unsigned int line_size;
+	unsigned int total_lines;
+	struct l2_cache_line_dump cache[8*1024];
+	unsigned int l2esr;
+} __packed;
+
+
+struct l1_cache_dump {
+	unsigned int magic;
+	unsigned int version;
+	unsigned int flags;
+	unsigned int cpu_count;
+	unsigned int i_tag_size;
+	unsigned int i_line_size;
+	unsigned int i_num_sets;
+	unsigned int i_num_ways;
+	unsigned int d_tag_size;
+	unsigned int d_line_size;
+	unsigned int d_num_sets;
+	unsigned int d_num_ways;
+	unsigned int spare[32];
+	unsigned int lines[];
+} __packed;
+
+
+struct msm_cache_dump_platform_data {
+	unsigned int l1_size;
+	unsigned int l2_size;
+};
+
+#define CACHE_BUFFER_DUMP_SIZE (L1_BUFFER_SIZE + L2_BUFFER_SIZE)
+
+#define L1C_SERVICE_ID 3
+#define L1C_BUFFER_SET_COMMAND_ID 4
+#define CACHE_BUFFER_DUMP_COMMAND_ID 5
+#define L1C_BUFFER_GET_SIZE_COMMAND_ID	6
+#define L2C_BUFFER_SET_COMMAND_ID 7
+#define L2C_BUFFER_GET_SIZE_COMMAND_ID 8
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_dcvs.h b/arch/arm/mach-msm/include/mach/msm_dcvs.h
new file mode 100644
index 0000000..fa7e6f0
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_dcvs.h
@@ -0,0 +1,150 @@
+/* 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 _ARCH_ARM_MACH_MSM_MSM_DCVS_H
+#define _ARCH_ARM_MACH_MSM_MSM_DCVS_H
+
+#include <mach/msm_dcvs_scm.h>
+
+#define CORE_NAME_MAX (32)
+#define CORES_MAX (10)
+
+enum msm_core_idle_state {
+	MSM_DCVS_IDLE_ENTER,
+	MSM_DCVS_IDLE_EXIT,
+};
+
+enum msm_core_control_event {
+	MSM_DCVS_ENABLE_IDLE_PULSE,
+	MSM_DCVS_DISABLE_IDLE_PULSE,
+	MSM_DCVS_ENABLE_HIGH_LATENCY_MODES,
+	MSM_DCVS_DISABLE_HIGH_LATENCY_MODES,
+};
+
+/**
+ * struct msm_dcvs_idle
+ *
+ * API for idle code to register and send idle enter/exit
+ * notifications to msm_dcvs driver.
+ */
+struct msm_dcvs_idle {
+	const char *core_name;
+	/* Enable/Disable idle state/notifications */
+	int (*enable)(struct msm_dcvs_idle *self,
+			enum msm_core_control_event event);
+};
+
+/**
+ * msm_dcvs_idle_source_register
+ * @drv: Pointer to the source driver
+ * @return: Handle to be used for sending idle state notifications.
+ *
+ * Register the idle driver with the msm_dcvs driver to send idle
+ * state notifications for the core.
+ */
+extern int msm_dcvs_idle_source_register(struct msm_dcvs_idle *drv);
+
+/**
+ * msm_dcvs_idle_source_unregister
+ * @drv: Pointer to the source driver
+ * @return:
+ *	0 on success
+ *	-EINVAL
+ *
+ * Description: Unregister the idle driver with the msm_dcvs driver
+ */
+extern int msm_dcvs_idle_source_unregister(struct msm_dcvs_idle *drv);
+
+/**
+ * msm_dcvs_idle
+ * @handle: Handle provided back at registration
+ * @state: The enter/exit idle state the core is in
+ * @iowaited: iowait in us
+ * on iMSM_DCVS_IDLE_EXIT.
+ * @return:
+ *	0 on success,
+ *	-ENOSYS,
+ *	-EINVAL,
+ *	SCM return values
+ *
+ * Send idle state notifications to the msm_dcvs driver
+ */
+int msm_dcvs_idle(int handle, enum msm_core_idle_state state,
+		uint32_t iowaited);
+
+/**
+ * struct msm_dcvs_core_info
+ *
+ * Core specific information used by algorithm. Need to provide this
+ * before the sink driver can be registered.
+ */
+struct msm_dcvs_core_info {
+	struct msm_dcvs_freq_entry *freq_tbl;
+	struct msm_dcvs_core_param core_param;
+	struct msm_dcvs_algo_param algo_param;
+};
+
+/**
+ * msm_dcvs_register_core
+ * @core_name: Unique name identifier for the core.
+ * @group_id: Cores that are to be grouped for synchronized frequency scaling
+ * @info: The core specific algorithm parameters.
+ * @return :
+ *	0 on success,
+ *	-ENOSYS,
+ *	-ENOMEM
+ *
+ * Register the core with msm_dcvs driver. Done once at init before calling
+ * msm_dcvs_freq_sink_register
+ * Cores that need to run synchronously must share the same group id.
+ * If a core doesnt care to be in any group, the group_id should be 0.
+ */
+extern int msm_dcvs_register_core(const char *core_name, uint32_t group_id,
+		struct msm_dcvs_core_info *info);
+
+/**
+ * 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
+ * @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);
+
+/**
+ * msm_dcvs_freq_sink_unregister
+ * @drv: The sink driver
+ * @return:
+ *	0 on success,
+ *	-EINVAL
+ *
+ * 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);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_dcvs_scm.h b/arch/arm/mach-msm/include/mach/msm_dcvs_scm.h
new file mode 100644
index 0000000..3cc2595
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_dcvs_scm.h
@@ -0,0 +1,168 @@
+/* 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 _ARCH_ARM_MACH_MSM_MSM_DCVS_SCM_H
+#define _ARCH_ARM_MACH_MSM_MSM_DCVS_SCM_H
+
+enum msm_dcvs_scm_event {
+	MSM_DCVS_SCM_IDLE_ENTER,
+	MSM_DCVS_SCM_IDLE_EXIT,
+	MSM_DCVS_SCM_QOS_TIMER_EXPIRED,
+	MSM_DCVS_SCM_CLOCK_FREQ_UPDATE,
+	MSM_DCVS_SCM_ENABLE_CORE,
+	MSM_DCVS_SCM_RESET_CORE,
+};
+
+struct msm_dcvs_algo_param {
+	uint32_t slack_time_us;
+	uint32_t scale_slack_time;
+	uint32_t scale_slack_time_pct;
+	uint32_t disable_pc_threshold;
+	uint32_t em_window_size;
+	uint32_t em_max_util_pct;
+	uint32_t ss_window_size;
+	uint32_t ss_util_pct;
+	uint32_t ss_iobusy_conv;
+};
+
+struct msm_dcvs_freq_entry {
+	uint32_t freq; /* Core freq in MHz */
+	uint32_t idle_energy;
+	uint32_t active_energy;
+};
+
+struct msm_dcvs_core_param {
+	uint32_t max_time_us;
+	uint32_t num_freq; /* number of msm_dcvs_freq_entry passed */
+};
+
+
+#ifdef CONFIG_MSM_DCVS
+/**
+ * Initialize DCVS algorithm in TrustZone.
+ * Must call before invoking any other DCVS call into TZ.
+ *
+ * @size: Size of buffer in bytes
+ *
+ * @return:
+ *	0 on success.
+ *	-EEXIST: DCVS algorithm already initialized.
+ *	-EINVAL: Invalid args.
+ */
+extern int msm_dcvs_scm_init(size_t size);
+
+/**
+ * Create an empty core group
+ *
+ * @return:
+ *	0 on success.
+ *	-ENOMEM: Insufficient memory.
+ *	-EINVAL: Invalid args.
+ */
+extern int msm_dcvs_scm_create_group(uint32_t id);
+
+/**
+ * Registers cores as part of a group
+ *
+ * @core_id: The core identifier that will be used for communication with DCVS
+ * @group_id: The group to which this core will be added to.
+ * @param: The core parameters
+ * @freq: Array of frequency and energy values
+ *
+ * @return:
+ *	0 on success.
+ *	-ENOMEM: Insufficient memory.
+ *	-EINVAL: Invalid args.
+ */
+extern int msm_dcvs_scm_register_core(uint32_t core_id, uint32_t group_id,
+		struct msm_dcvs_core_param *param,
+		struct msm_dcvs_freq_entry *freq);
+
+/**
+ * Set DCVS algorithm parameters
+ *
+ * @core_id: The algorithm parameters specific for the core
+ * @param: The param data structure
+ *
+ * @return:
+ *	0 on success.
+ *	-EINVAL: Invalid args.
+ */
+extern int msm_dcvs_scm_set_algo_params(uint32_t core_id,
+		struct msm_dcvs_algo_param *param);
+
+/**
+ * Do an SCM call.
+ *
+ * @core_id: The core identifier.
+ * @event_id: The event that occured.
+ *	Possible values:
+ *	MSM_DCVS_SCM_IDLE_ENTER
+ *		@param0: unused
+ *		@param1: unused
+ *		@ret0: unused
+ *		@ret1: unused
+ *	MSM_DCVS_SCM_IDLE_EXIT
+ *		@param0: Did the core iowait
+ *		@param1: unused
+ *		@ret0: New clock frequency for the core in KHz
+ *		@ret1: New QoS timer value for the core in usec
+ *	MSM_DCVS_SCM_QOS_TIMER_EXPIRED
+ *		@param0: unused
+ *		@param1: unused
+ *		@ret0: New clock frequency for the core in KHz
+ *		@ret1: unused
+ *	MSM_DCVS_SCM_CLOCK_FREQ_UPDATE
+ *		@param0: active clock frequency of the core in KHz
+ *		@param1: time taken in usec to switch to the frequency
+ *		@ret0: New QoS timer value for the core in usec
+ *		@ret1: unused
+ *	MSM_DCVS_SCM_ENABLE_CORE
+ *		@param0: enable(1) or disable(0) core
+ *		@param1: active clock frequency of the core in KHz
+ *		@ret0: New clock frequency for the core in KHz
+ *		@ret1: unused
+ *	MSM_DCVS_SCM_RESET_CORE
+ *		@param0: active clock frequency of the core in KHz
+ *		@param1: unused
+ *		@ret0: New clock frequency for the core in KHz
+ *		@ret1: unused
+ * @return:
+ *	0 on success,
+ *	SCM return values
+ */
+extern int msm_dcvs_scm_event(uint32_t core_id,
+		enum msm_dcvs_scm_event event_id,
+		uint32_t param0, uint32_t param1,
+		uint32_t *ret0, uint32_t *ret1);
+
+#else
+static inline int msm_dcvs_scm_init(uint32_t phy, size_t bytes)
+{ return -ENOSYS; }
+static inline int msm_dcvs_scm_create_group(uint32_t id)
+{ return -ENOSYS; }
+static inline int msm_dcvs_scm_register_core(uint32_t core_id,
+		uint32_t group_id,
+		struct msm_dcvs_core_param *param,
+		struct msm_dcvs_freq_entry *freq)
+{ return -ENOSYS; }
+static inline int msm_dcvs_scm_set_algo_params(uint32_t core_id,
+		struct msm_dcvs_algo_param *param)
+{ return -ENOSYS; }
+static inline int msm_dcvs_scm_event(uint32_t core_id,
+		enum msm_dcvs_scm_event event_id,
+		uint32_t param0, uint32_t param1,
+		uint32_t *ret0, uint32_t *ret1)
+{ return -ENOSYS; }
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_dsps.h b/arch/arm/mach-msm/include/mach/msm_dsps.h
new file mode 100644
index 0000000..cfb2024
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_dsps.h
@@ -0,0 +1,93 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _MSM_DSPS_H_
+#define _MSM_DSPS_H_
+
+#include <linux/types.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+
+#define DSPS_SIGNATURE	0x12345678
+
+/**
+ * DSPS Clocks Platform data.
+ *
+ * @name - clock name.
+ * @rate - rate to set. zero if not relevant.
+ * @clock - clock handle, reserved for the driver.
+ */
+struct dsps_clk_info {
+	const char *name;
+	u32 rate;
+	struct clk *clock;
+};
+
+/**
+ * DSPS GPIOs Platform data.
+ *
+ * @name - clock name.
+ * @num - GPIO number.
+ * @on_val - value to ouptput for ON (depends on polarity).
+ * @off_val - value to ouptput for OFF (depends on polarity).
+ * @is_owner - reserved for the driver.
+ */
+struct dsps_gpio_info {
+	const char *name;
+	int num;
+	int on_val;
+	int off_val;
+	int is_owner;
+};
+
+/**
+ * DSPS Power regulators Platform data.
+ *
+ * @name - regulator name.
+ * @volt - required voltage (in uV).
+ * @reg - reserved for the driver.
+ */
+struct dsps_regulator_info {
+	const char *name;
+	int volt;
+	struct regulator *reg;
+};
+
+/**
+ * DSPS Platform data.
+ *
+ * @pil_name - peripheral image name
+ * @clks - array of clocks.
+ * @clks_num - number of clocks in array.
+ * @gpios - array of gpios.
+ * @gpios_num - number of gpios.
+ * @regs - array of regulators.
+ * @regs_num - number of regulators.
+ * @dsps_pwr_ctl_en - to enable DSPS to do power control if set 1
+ *  otherwise the apps will do power control
+ * @signature - signature for validity check.
+ */
+struct msm_dsps_platform_data {
+	const char *pil_name;
+	struct dsps_clk_info *clks;
+	int clks_num;
+	struct dsps_gpio_info *gpios;
+	int gpios_num;
+	struct dsps_regulator_info *regs;
+	int regs_num;
+	int dsps_pwr_ctl_en;
+	void (*init)(struct msm_dsps_platform_data *data);
+	u32 signature;
+};
+
+#endif /* _MSM_DSPS_H_ */
diff --git a/arch/arm/mach-msm/include/mach/msm_fast_timer.h b/arch/arm/mach-msm/include/mach/msm_fast_timer.h
new file mode 100644
index 0000000..e1660c1
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_fast_timer.h
@@ -0,0 +1,19 @@
+/* arch/arm/mach-msm/include/mach/msm_fast_timer.h
+ *
+ * Copyright (C) 2009 Google, Inc.
+ *
+ * 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.
+ *
+ */
+
+void msm_enable_fast_timer(void);
+void msm_disable_fast_timer(void);
+u32 msm_read_fast_timer(void);
+
diff --git a/arch/arm/mach-msm/include/mach/msm_fb.h b/arch/arm/mach-msm/include/mach/msm_fb.h
index 1f4fc81..3bbaa25 100644
--- a/arch/arm/mach-msm/include/mach/msm_fb.h
+++ b/arch/arm/mach-msm/include/mach/msm_fb.h
@@ -21,6 +21,10 @@
 
 struct mddi_info;
 
+/* output interface format */
+#define MSM_MDP_OUT_IF_FMT_RGB565 0
+#define MSM_MDP_OUT_IF_FMT_RGB666 1
+
 struct msm_fb_data {
 	int xres;	/* x resolution in pixels */
 	int yres;	/* y resolution in pixels */
@@ -34,9 +38,12 @@
 };
 
 enum {
-	MSM_MDDI_PMDH_INTERFACE,
+	MSM_MDDI_PMDH_INTERFACE = 0,
 	MSM_MDDI_EMDH_INTERFACE,
 	MSM_EBI2_INTERFACE,
+	MSM_LCDC_INTERFACE,
+
+	MSM_MDP_NUM_INTERFACES = MSM_LCDC_INTERFACE + 1,
 };
 
 #define MSMFB_CAP_PARTIAL_UPDATES	(1 << 0)
@@ -85,6 +92,8 @@
 	/* fixup the mfr name, product id */
 	void (*fixup)(uint16_t *mfr_name, uint16_t *product_id);
 
+	int vsync_irq;
+
 	struct resource *fb_resource; /*optional*/
 	/* number of clients in the list that follows */
 	int num_clients;
@@ -110,17 +119,50 @@
 	} client_platform_data[];
 };
 
+struct msm_lcdc_timing {
+	unsigned int clk_rate;		/* dclk freq */
+	unsigned int hsync_pulse_width;	/* in dclks */
+	unsigned int hsync_back_porch;	/* in dclks */
+	unsigned int hsync_front_porch;	/* in dclks */
+	unsigned int hsync_skew;	/* in dclks */
+	unsigned int vsync_pulse_width;	/* in lines */
+	unsigned int vsync_back_porch;	/* in lines */
+	unsigned int vsync_front_porch;	/* in lines */
+
+	/* control signal polarity */
+	unsigned int vsync_act_low:1;
+	unsigned int hsync_act_low:1;
+	unsigned int den_act_low:1;
+};
+
+struct msm_lcdc_panel_ops {
+	int	(*init)(struct msm_lcdc_panel_ops *);
+	int	(*uninit)(struct msm_lcdc_panel_ops *);
+	int	(*blank)(struct msm_lcdc_panel_ops *);
+	int	(*unblank)(struct msm_lcdc_panel_ops *);
+};
+
+struct msm_lcdc_platform_data {
+	struct msm_lcdc_panel_ops	*panel_ops;
+	struct msm_lcdc_timing		*timing;
+	int				fb_id;
+	struct msm_fb_data		*fb_data;
+	struct resource			*fb_resource;
+};
+
 struct mdp_blit_req;
 struct fb_info;
 struct mdp_device {
 	struct device dev;
-	void (*dma)(struct mdp_device *mpd, uint32_t addr,
+	void (*dma)(struct mdp_device *mdp, uint32_t addr,
 		    uint32_t stride, uint32_t w, uint32_t h, uint32_t x,
 		    uint32_t y, struct msmfb_callback *callback, int interface);
-	void (*dma_wait)(struct mdp_device *mdp);
+	void (*dma_wait)(struct mdp_device *mdp, int interface);
 	int (*blit)(struct mdp_device *mdp, struct fb_info *fb,
 		    struct mdp_blit_req *req);
 	void (*set_grp_disp)(struct mdp_device *mdp, uint32_t disp_id);
+	int (*check_output_format)(struct mdp_device *mdp, int bpp);
+	int (*set_output_format)(struct mdp_device *mdp, int bpp);
 };
 
 struct class_interface;
@@ -140,8 +182,17 @@
 	int (*unblank)(struct msm_mddi_bridge_platform_data *,
 		       struct msm_mddi_client_data *);
 	struct msm_fb_data fb_data;
+
+	/* board file will identify what capabilities the panel supports */
+	uint32_t panel_caps;
 };
 
 
+struct mdp_v4l2_req;
+int msm_fb_v4l2_enable(struct mdp_overlay *req, bool enable, void **par);
+int msm_fb_v4l2_update(void *par,
+	unsigned long srcp0_addr, unsigned long srcp0_size,
+	unsigned long srcp1_addr, unsigned long srcp1_size,
+	unsigned long srcp2_addr, unsigned long srcp2_size);
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_hdmi_audio.h b/arch/arm/mach-msm/include/mach/msm_hdmi_audio.h
new file mode 100644
index 0000000..57e794f
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_hdmi_audio.h
@@ -0,0 +1,42 @@
+/* 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
+ * 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 __MSM_HDMI_AUDIO_H
+#define __MSM_HDMI_AUDIO_H
+
+/* Supported HDMI Audio channels */
+#define MSM_HDMI_AUDIO_CHANNEL_2		0
+#define MSM_HDMI_AUDIO_CHANNEL_4		1
+#define MSM_HDMI_AUDIO_CHANNEL_6		2
+#define MSM_HDMI_AUDIO_CHANNEL_8		3
+
+#define TRUE   1
+#define FALSE  0
+
+enum hdmi_supported_sample_rates {
+	HDMI_SAMPLE_RATE_32KHZ,
+	HDMI_SAMPLE_RATE_44_1KHZ,
+	HDMI_SAMPLE_RATE_48KHZ,
+	HDMI_SAMPLE_RATE_88_2KHZ,
+	HDMI_SAMPLE_RATE_96KHZ,
+	HDMI_SAMPLE_RATE_176_4KHZ,
+	HDMI_SAMPLE_RATE_192KHZ
+};
+
+int hdmi_audio_enable(bool on , u32 fifo_water_mark);
+int hdmi_audio_packet_enable(bool on);
+void hdmi_msm_audio_sample_rate_reset(int rate);
+int hdmi_msm_audio_get_sample_rate(void);
+int hdmi_msm_audio_info_setup(bool enabled, u32 num_of_channels,
+	u32 channel_allocation, u32 level_shift, bool down_mix);
+
+#endif /* __MSM_HDMI_AUDIO_H*/
diff --git a/arch/arm/mach-msm/include/mach/msm_hsusb.h b/arch/arm/mach-msm/include/mach/msm_hsusb.h
new file mode 100644
index 0000000..4f140cc
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_hsusb.h
@@ -0,0 +1,209 @@
+/* linux/include/mach/hsusb.h
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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_HSUSB_H
+#define __ASM_ARCH_MSM_HSUSB_H
+
+#include <linux/types.h>
+#include <linux/pm_qos.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#define PHY_TYPE_MASK		0x0F
+#define PHY_TYPE_MODE		0xF0
+#define PHY_MODEL_MASK		0xFF00
+#define PHY_TYPE(x)		((x) & PHY_TYPE_MASK)
+#define PHY_MODEL(x)		((x) & PHY_MODEL_MASK)
+
+#define USB_PHY_MODEL_65NM	0x100
+#define USB_PHY_MODEL_180NM	0x200
+#define USB_PHY_MODEL_45NM	0x400
+#define USB_PHY_UNDEFINED	0x00
+#define USB_PHY_INTEGRATED	0x01
+#define USB_PHY_EXTERNAL	0x02
+#define USB_PHY_SERIAL_PMIC     0x04
+
+#define REQUEST_STOP		0
+#define REQUEST_START		1
+#define REQUEST_RESUME		2
+#define REQUEST_HNP_SUSPEND	3
+#define REQUEST_HNP_RESUME	4
+
+/* Flags required to read ID state of PHY for ACA */
+#define PHY_ID_MASK		0xB0
+#define PHY_ID_GND		0
+#define PHY_ID_C		0x10
+#define PHY_ID_B		0x30
+#define PHY_ID_A		0x90
+
+#define phy_id_state(ints)	((ints) & PHY_ID_MASK)
+#define phy_id_state_gnd(ints)	(phy_id_state((ints)) == PHY_ID_GND)
+#define phy_id_state_a(ints)	(phy_id_state((ints)) == PHY_ID_A)
+/* RID_B and RID_C states does not exist with standard ACA */
+#ifdef CONFIG_USB_MSM_STANDARD_ACA
+#define phy_id_state_b(ints)	0
+#define phy_id_state_c(ints)	0
+#else
+#define phy_id_state_b(ints)	(phy_id_state((ints)) == PHY_ID_B)
+#define phy_id_state_c(ints)	(phy_id_state((ints)) == PHY_ID_C)
+#endif
+
+/*
+ * The following are bit fields describing the usb_request.udc_priv word.
+ * These bit fields are set by function drivers that wish to queue
+ * usb_requests with sps/bam parameters.
+ */
+#define MSM_PIPE_ID_MASK		(0x1F)
+#define MSM_TX_PIPE_ID_OFS		(16)
+#define MSM_SPS_MODE			BIT(5)
+#define MSM_IS_FINITE_TRANSFER		BIT(6)
+#define MSM_PRODUCER			BIT(7)
+#define MSM_DISABLE_WB			BIT(8)
+#define MSM_ETD_IOC			BIT(9)
+#define MSM_INTERNAL_MEM		BIT(10)
+#define MSM_VENDOR_ID			BIT(16)
+
+/* used to detect the OTG Mode */
+enum otg_mode {
+	OTG_ID = 0,   		/* ID pin detection */
+	OTG_USER_CONTROL,  	/* User configurable */
+	OTG_VCHG,     		/* Based on VCHG interrupt */
+};
+
+/* used to configure the default mode,if otg_mode is USER_CONTROL */
+enum usb_mode {
+	USB_HOST_MODE,
+	USB_PERIPHERAL_MODE,
+};
+
+enum chg_type {
+	USB_CHG_TYPE__SDP,
+	USB_CHG_TYPE__CARKIT,
+	USB_CHG_TYPE__WALLCHARGER,
+	USB_CHG_TYPE__INVALID
+};
+
+enum pre_emphasis_level {
+	PRE_EMPHASIS_DEFAULT,
+	PRE_EMPHASIS_DISABLE,
+	PRE_EMPHASIS_WITH_10_PERCENT = (1 << 5),
+	PRE_EMPHASIS_WITH_20_PERCENT = (3 << 4),
+};
+enum cdr_auto_reset {
+	CDR_AUTO_RESET_DEFAULT,
+	CDR_AUTO_RESET_ENABLE,
+	CDR_AUTO_RESET_DISABLE,
+};
+
+enum se1_gate_state {
+	SE1_GATING_DEFAULT,
+	SE1_GATING_ENABLE,
+	SE1_GATING_DISABLE,
+};
+
+enum hs_drv_amplitude {
+	HS_DRV_AMPLITUDE_DEFAULT,
+	HS_DRV_AMPLITUDE_ZERO_PERCENT,
+	HS_DRV_AMPLITUDE_25_PERCENTI = (1 << 2),
+	HS_DRV_AMPLITUDE_5_PERCENT = (1 << 3),
+	HS_DRV_AMPLITUDE_75_PERCENT = (3 << 2),
+};
+
+#define HS_DRV_SLOPE_DEFAULT	(-1)
+
+/* used to configure the analog switch to select b/w host and peripheral */
+enum usb_switch_control {
+	USB_SWITCH_PERIPHERAL = 0,	/* Configure switch in peripheral mode*/
+	USB_SWITCH_HOST,		/* Host mode */
+	USB_SWITCH_DISABLE,		/* No mode selected, shutdown power */
+};
+
+struct msm_hsusb_gadget_platform_data {
+	int *phy_init_seq;
+	void (*phy_reset)(void);
+
+	int self_powered;
+	int is_phy_status_timer_on;
+};
+
+struct msm_otg_platform_data {
+	int (*rpc_connect)(int);
+	int (*phy_reset)(void __iomem *);
+	int pmic_vbus_irq;
+	int pmic_id_irq;
+	/* if usb link is in sps there is no need for
+	 * usb pclk as dayatona fabric clock will be
+	 * used instead
+	 */
+	int usb_in_sps;
+	enum pre_emphasis_level	pemp_level;
+	enum cdr_auto_reset	cdr_autoreset;
+	enum hs_drv_amplitude	drv_ampl;
+	enum se1_gate_state	se1_gating;
+	int			hsdrvslope;
+	int			phy_reset_sig_inverted;
+	int			phy_can_powercollapse;
+	int			pclk_required_during_lpm;
+	int			bam_disable;
+	/* HSUSB core in 8660 has the capability to gate the
+	 * pclk when not being used. Though this feature is
+	 * now being disabled because of H/w issues
+	 */
+	int			pclk_is_hw_gated;
+
+	int (*ldo_init) (int init);
+	int (*ldo_enable) (int enable);
+	int (*ldo_set_voltage) (int mV);
+
+	u32 			swfi_latency;
+	/* pmic notfications apis */
+	int (*pmic_vbus_notif_init) (void (*callback)(int online), int init);
+	int (*pmic_id_notif_init) (void (*callback)(int online), int init);
+	int (*phy_id_setup_init) (int init);
+	int (*pmic_register_vbus_sn) (void (*callback)(int online));
+	void (*pmic_unregister_vbus_sn) (void (*callback)(int online));
+	int (*pmic_enable_ldo) (int);
+	int (*init_gpio)(int on);
+	void (*setup_gpio)(enum usb_switch_control mode);
+	u8      otg_mode;
+	u8	usb_mode;
+	void (*vbus_power) (unsigned phy_info, int on);
+
+	/* charger notification apis */
+	void (*chg_connected)(enum chg_type chg_type);
+	void (*chg_vbus_draw)(unsigned ma);
+	int  (*chg_init)(int init);
+	int (*config_vddcx)(int high);
+	int (*init_vddcx)(int init);
+
+	struct pm_qos_request pm_qos_req_dma;
+};
+
+struct msm_usb_host_platform_data {
+	unsigned phy_info;
+	unsigned int power_budget;
+	void (*config_gpio)(unsigned int config);
+	void (*vbus_power) (unsigned phy_info, int on);
+	int  (*vbus_init)(int init);
+	struct clk *ebi1_clk;
+};
+
+int msm_ep_config(struct usb_ep *ep);
+int msm_ep_unconfig(struct usb_ep *ep);
+int msm_data_fifo_config(struct usb_ep *ep, u32 addr, u32 size);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_hsusb_hw.h b/arch/arm/mach-msm/include/mach/msm_hsusb_hw.h
new file mode 100644
index 0000000..82542b2
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_hsusb_hw.h
@@ -0,0 +1,286 @@
+ /*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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 __LINUX_USB_GADGET_MSM72K_UDC_H__
+#define __LINUX_USB_GADGET_MSM72K_UDC_H__
+
+#define USB_ID               (MSM_USB_BASE + 0x0000)
+#define USB_HWGENERAL        (MSM_USB_BASE + 0x0004)
+#define USB_HWHOST           (MSM_USB_BASE + 0x0008)
+#define USB_HWDEVICE         (MSM_USB_BASE + 0x000C)
+#define USB_HWTXBUF          (MSM_USB_BASE + 0x0010)
+#define USB_HWRXBUF          (MSM_USB_BASE + 0x0014)
+#define USB_AHB_BURST        (MSM_USB_BASE + 0x0090)
+#define USB_AHB_MODE         (MSM_USB_BASE + 0x0098)
+#define USB_GEN_CONFIG       (MSM_USB_BASE + 0x009C)
+#define USB_BAM_DISABLE      (1 << 13)
+#define USB_ROC_AHB_MODE     (MSM_USB_BASE + 0x0090)
+#define USB_SBUSCFG          (MSM_USB_BASE + 0x0090)
+
+#define USB_CAPLENGTH        (MSM_USB_BASE + 0x0100) /* 8 bit */
+#define USB_HCIVERSION       (MSM_USB_BASE + 0x0102) /* 16 bit */
+#define USB_HCSPARAMS        (MSM_USB_BASE + 0x0104)
+#define USB_HCCPARAMS        (MSM_USB_BASE + 0x0108)
+#define USB_DCIVERSION       (MSM_USB_BASE + 0x0120) /* 16 bit */
+#define USB_USBCMD           (MSM_USB_BASE + 0x0140)
+#define USB_USBSTS           (MSM_USB_BASE + 0x0144)
+#define USB_USBINTR          (MSM_USB_BASE + 0x0148)
+#define USB_FRINDEX          (MSM_USB_BASE + 0x014C)
+#define USB_DEVICEADDR       (MSM_USB_BASE + 0x0154)
+#define USB_ENDPOINTLISTADDR (MSM_USB_BASE + 0x0158)
+#define USB_BURSTSIZE        (MSM_USB_BASE + 0x0160)
+#define USB_TXFILLTUNING     (MSM_USB_BASE + 0x0164)
+#define USB_ULPI_VIEWPORT    (MSM_USB_BASE + 0x0170)
+#define USB_ENDPTNAK         (MSM_USB_BASE + 0x0178)
+#define USB_ENDPTNAKEN       (MSM_USB_BASE + 0x017C)
+#define USB_PORTSC           (MSM_USB_BASE + 0x0184)
+#define USB_OTGSC            (MSM_USB_BASE + 0x01A4)
+#define USB_USBMODE          (MSM_USB_BASE + 0x01A8)
+#define USB_ENDPTSETUPSTAT   (MSM_USB_BASE + 0x01AC)
+#define USB_ENDPTPRIME       (MSM_USB_BASE + 0x01B0)
+#define USB_ENDPTFLUSH       (MSM_USB_BASE + 0x01B4)
+#define USB_ENDPTSTAT        (MSM_USB_BASE + 0x01B8)
+#define USB_ENDPTCOMPLETE    (MSM_USB_BASE + 0x01BC)
+#define USB_ENDPTCTRL(n)     (MSM_USB_BASE + 0x01C0 + (4 * (n)))
+
+
+#define USBCMD_RESET   2
+#define USBCMD_ATTACH  1
+#define USBCMD_RS	(1 << 0) /* run/stop bit */
+#define USBCMD_ATDTW   (1 << 14)
+#define USBCMD_ITC(n)	(n << 16)
+#define USBCMD_ITC_MASK (0xFF << 16)
+#define ASYNC_INTR_CTRL	(1 << 29)
+#define ULPI_STP_CTRL	(1 << 30)
+
+#define USBMODE_DEVICE 2
+#define USBMODE_HOST   3
+#define USBMODE_VBUS	(1 << 5)	/* vbus power select */
+
+/* Redefining SDIS bit as it defined incorrectly in ehci.h. */
+#ifdef USBMODE_SDIS
+#undef USBMODE_SDIS
+#endif
+#define USBMODE_SDIS	(1 << 4)	/* stream disable */
+
+struct ept_queue_head {
+    unsigned config;
+    unsigned active; /* read-only */
+
+    unsigned next;
+    unsigned info;
+    unsigned page0;
+    unsigned page1;
+    unsigned page2;
+    unsigned page3;
+    unsigned page4;
+    unsigned reserved_0;
+
+    unsigned char setup_data[8];
+
+    unsigned reserved_1;
+    unsigned reserved_2;
+    unsigned reserved_3;
+    unsigned reserved_4;
+};
+
+#define CONFIG_MAX_PKT(n)     ((n) << 16)
+#define CONFIG_ZLT            (1 << 29)    /* stop on zero-len xfer */
+#define CONFIG_IOS            (1 << 15)    /* IRQ on setup */
+
+struct ept_queue_item {
+    unsigned next;
+    unsigned info;
+    unsigned page0;
+    unsigned page1;
+    unsigned page2;
+    unsigned page3;
+    unsigned page4;
+    unsigned reserved;
+};
+
+#define TERMINATE 1
+
+#define INFO_BYTES(n)         ((n) << 16)
+#define INFO_IOC              (1 << 15)
+#define INFO_ACTIVE           (1 << 7)
+#define INFO_HALTED           (1 << 6)
+#define INFO_BUFFER_ERROR     (1 << 5)
+#define INFO_TXN_ERROR        (1 << 3)
+
+
+#define STS_NAKI              (1 << 16)  /* */
+#define STS_SLI               (1 << 8)   /* R/WC - suspend state entered */
+#define STS_SRI               (1 << 7)   /* R/WC - SOF recv'd */
+#define STS_URI               (1 << 6)   /* R/WC - RESET recv'd */
+#define STS_FRI               (1 << 3)   /* R/WC - Frame List Rollover */
+#define STS_PCI               (1 << 2)   /* R/WC - Port Change Detect */
+#define STS_UEI               (1 << 1)   /* R/WC - USB Error */
+#define STS_UI                (1 << 0)   /* R/WC - USB Transaction Complete */
+
+
+/* bits used in all the endpoint status registers */
+#define EPT_TX(n) (1 << ((n) + 16))
+#define EPT_RX(n) (1 << (n))
+
+
+#define CTRL_TXE              (1 << 23)
+#define CTRL_TXR              (1 << 22)
+#define CTRL_TXI              (1 << 21)
+#define CTRL_TXD              (1 << 17)
+#define CTRL_TXS              (1 << 16)
+#define CTRL_RXE              (1 << 7)
+#define CTRL_RXR              (1 << 6)
+#define CTRL_RXI              (1 << 5)
+#define CTRL_RXD              (1 << 1)
+#define CTRL_RXS              (1 << 0)
+
+#define CTRL_TXT_MASK         (3 << 18)
+#define CTRL_TXT_CTRL         (0 << 18)
+#define CTRL_TXT_ISOCH        (1 << 18)
+#define CTRL_TXT_BULK         (2 << 18)
+#define CTRL_TXT_INT          (3 << 18)
+#define CTRL_TXT_EP_TYPE_SHIFT 18
+
+#define CTRL_RXT_MASK         (3 << 2)
+#define CTRL_RXT_CTRL         (0 << 2)
+#define CTRL_RXT_ISOCH        (1 << 2)
+#define CTRL_RXT_BULK         (2 << 2)
+#define CTRL_RXT_INT          (3 << 2)
+#define CTRL_RXT_EP_TYPE_SHIFT 2
+
+#define ULPI_CONFIG_REG		0x31
+#if (defined(CONFIG_ARCH_MSM7X27) && !defined(CONFIG_ARCH_MSM7X27A)) \
+					|| defined(CONFIG_ARCH_QSD8X50)
+#define ULPI_DIGOUT_CTRL	0X31
+#define ULPI_CDR_AUTORESET	(1 << 5)
+#else
+#define ULPI_DIGOUT_CTRL	0X36
+#define ULPI_CDR_AUTORESET	(1 << 1)
+#endif
+#define ULPI_SE1_GATE		(1 << 2)
+#define ULPI_CONFIG_REG1	0x30
+#define ULPI_CONFIG_REG2	0X31
+#define ULPI_CONFIG_REG3	0X32
+#define ULPI_IFC_CTRL_CLR	0x09
+#define ULPI_AMPLITUDE_MAX	0x0C
+#define ULPI_OTG_CTRL		0x0B
+#define ULPI_OTG_CTRL_CLR       0x0C
+#define ULPI_INT_RISE_CLR       0x0F
+#define ULPI_INT_FALL_CLR       0x12
+#define ULPI_PRE_EMPHASIS_MASK	(3 << 4)
+#define ULPI_HSDRVSLOPE_MASK	(0x0F)
+#define ULPI_DRV_AMPL_MASK	(3 << 2)
+#define ULPI_ONCLOCK	       (1 << 6)
+#define ULPI_IDPU	      (1 << 0)
+#define ULPI_HOST_DISCONNECT  (1 << 0)
+#define ULPI_VBUS_VALID       (1 << 1)
+#define ULPI_SESS_END         (1 << 3)
+#define ULPI_ID_GND  	      (1 << 4)
+#define ULPI_WAKEUP           (1 << 31)
+#define ULPI_RUN              (1 << 30)
+#define ULPI_WRITE            (1 << 29)
+#define ULPI_READ             (0 << 29)
+#define ULPI_STATE_NORMAL     (1 << 27)
+#define ULPI_ADDR(n)          (((n) & 255) << 16)
+#define ULPI_DATA(n)          ((n) & 255)
+#define ULPI_DATA_READ(n)     (((n) >> 8) & 255)
+
+/* USB_PORTSC bits for determining port speed */
+#define PORTSC_PSPD_FS        (0 << 26)
+#define PORTSC_PSPD_LS        (1 << 26)
+#define PORTSC_PSPD_HS        (2 << 26)
+#define PORTSC_PSPD_MASK      (3 << 26)
+
+
+#define OTGSC_BSVIE            (1 << 27) /* R/W - BSV Interrupt Enable */
+#define OTGSC_DPIE             (1 << 30) /* R/W - DataPulse Interrupt Enable */
+#define OTGSC_1MSE             (1 << 29) /* R/W - 1ms Interrupt Enable */
+#define OTGSC_BSEIE            (1 << 28) /* R/W - BSE Interrupt Enable */
+#define OTGSC_ASVIE            (1 << 26) /* R/W - ASV Interrupt Enable */
+#define OTGSC_ASEIE            (1 << 25) /* R/W - ASE Interrupt Enable */
+#define OTGSC_IDIE             (1 << 24) /* R/W - ID Interrupt Enable */
+#define OTGSC_BSVIS            (1 << 19) /* R/W - BSV Interrupt Status */
+#define OTGSC_IDPU	       (1 << 5)
+#define OTGSC_ID               (1 << 8)
+#define OTGSC_IDIS             (1 << 16)
+#define B_SESSION_VALID        (1 << 11)
+#define OTGSC_INTR_MASK        (OTGSC_BSVIE | OTGSC_DPIE | OTGSC_1MSE | \
+				OTGSC_BSEIE | OTGSC_ASVIE | OTGSC_ASEIE | \
+				OTGSC_IDIE)
+#define OTGSC_INTR_STS_MASK    (0x7f << 16)
+#define CURRENT_CONNECT_STATUS (1 << 0)
+
+#define PORTSC_FPR             (1 << 6)  /* R/W - State normal => suspend */
+#define PORTSC_SUSP            (1 << 7)  /* Read - Port in suspend state */
+#define PORTSC_LS              (3 << 10) /* Read - Port's Line status */
+#define PORTSC_PHCD	       (1 << 23) /* phy suspend mode */
+#define PORTSC_CCS	       (1 << 0)  /* current connect status */
+#define PORTSC_PORT_RESET      0x00000100
+#define PORTSC_PTS		(3 << 30)
+#define PORTSC_PTS_ULPI		(2 << 30)
+#define PORTSC_PTS_SERIAL	(3 << 30)
+
+#define PORTSC_PORT_SPEED_FULL    0x00000000
+#define PORTSC_PORT_SPEED_LOW     0x04000000
+#define PORTSC_PORT_SPEED_HIGH    0x08000000
+#define PORTSC_PORT_SPEED_MASK    0x0c000000
+
+#define SBUSCFG_AHBBRST_INCR4	0x01
+#define ULPI_USBINTR_ENABLE_RASING_C  0x0F
+#define ULPI_USBINTR_ENABLE_FALLING_C 0x12
+#define ULPI_USBINTR_STATUS           0x13
+#define ULPI_USBINTR_ENABLE_RASING_S  0x0E
+#define ULPI_USBINTR_ENABLE_FALLING_S 0x11
+#define ULPI_SESSION_END_RAISE        (1 << 3)
+#define ULPI_SESSION_END_FALL         (1 << 3)
+#define ULPI_SESSION_VALID_RAISE      (1 << 2)
+#define ULPI_SESSION_VALID_FALL       (1 << 2)
+#define ULPI_VBUS_VALID_RAISE         (1 << 1)
+#define ULPI_VBUS_VALID_FALL          (1 << 1)
+
+#define ULPI_CHG_DETECT_REG     0x34
+/* control charger detection by ULPI or externally */
+#define ULPI_EXTCHGCTRL_65NM	(1 << 2)
+#define ULPI_EXTCHGCTRL_180NM	(1 << 3)
+/* charger detection power on control */
+#define ULPI_CHGDETON           (1 << 1)
+ /* enable charger detection */
+#define ULPI_CHGDETEN           (1 << 0)
+#define ULPI_CHGTYPE_65NM	(1 << 3)
+#define ULPI_CHGTYPE_180NM	(1 << 4)
+
+/* test mode support */
+#define J_TEST			(0x0100)
+#define K_TEST			(0x0200)
+#define SE0_NAK_TEST		(0x0300)
+#define TST_PKT_TEST		(0x0400)
+#define PORTSC_PTC		(0xf << 16)
+#define PORTSC_PTC_J_STATE	(0x01 << 16)
+#define PORTSC_PTC_K_STATE	(0x02 << 16)
+#define PORTSC_PTC_SE0_NAK	(0x03 << 16)
+#define PORTSC_PTC_TST_PKT	(0x04 << 16)
+
+#define USBH                     (1 << 15)
+#define USB_PHY                  (1 << 18)
+
+#define ULPI_DEBUG               0x15
+#define ULPI_FUNC_CTRL_CLR       0x06
+#define ULPI_SUSPENDM            (1 << 6)
+#define ULPI_CLOCK_SUSPENDM     (1 << 3)
+#define ULPI_CALIB_STS          (1 << 7)
+#define ULPI_CALIB_VAL(x)       (x & 0x7C)
+#endif /* __LINUX_USB_GADGET_MSM72K_UDC_H__ */
diff --git a/arch/arm/mach-msm/include/mach/msm_i2ckbd.h b/arch/arm/mach-msm/include/mach/msm_i2ckbd.h
new file mode 100644
index 0000000..dc33c75
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_i2ckbd.h
@@ -0,0 +1,27 @@
+/* Copyright (c) 2008-2009, 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 _MSM_I2CKBD_H_
+#define _MSM_I2CKBD_H_
+
+struct msm_i2ckbd_platform_data {
+	uint8_t hwrepeat;
+	uint8_t scanset1;
+	int  gpioreset;
+	int  gpioirq;
+	int  (*gpio_setup) (void);
+	void (*gpio_shutdown)(void);
+	void (*hw_reset) (int);
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-7x00.h b/arch/arm/mach-msm/include/mach/msm_iomap-7x00.h
index 6c4046c..44f0a8b 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-7x00.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-7x00.h
@@ -1,7 +1,6 @@
 /* arch/arm/mach-msm/include/mach/msm_iomap.h
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -38,28 +37,34 @@
  *
  */
 
-#define MSM_VIC_BASE          IOMEM(0xE0000000)
+#define MSM_VIC_BASE          IOMEM(0xF8000000)
 #define MSM_VIC_PHYS          0xC0000000
 #define MSM_VIC_SIZE          SZ_4K
 
-#define MSM7X00_CSR_PHYS      0xC0100000
-#define MSM7X00_CSR_SIZE      SZ_4K
+#define MSM_CSR_BASE          IOMEM(0xF8001000)
+#define MSM_CSR_PHYS          0xC0100000
+#define MSM_CSR_SIZE          SZ_4K
 
-#define MSM_DMOV_BASE         IOMEM(0xE0002000)
-#define MSM_DMOV_PHYS         0xA9700000
-#define MSM_DMOV_SIZE         SZ_4K
+#define MSM_TMR_PHYS          MSM_CSR_PHYS
+#define MSM_TMR_BASE          MSM_CSR_BASE
+#define MSM_TMR_SIZE          SZ_4K
 
-#define MSM7X00_GPIO1_PHYS        0xA9200000
-#define MSM7X00_GPIO1_SIZE        SZ_4K
+#define MSM_GPT_BASE          MSM_TMR_BASE
+#define MSM_DGT_BASE          (MSM_TMR_BASE + 0x10)
 
-#define MSM7X00_GPIO2_PHYS        0xA9300000
-#define MSM7X00_GPIO2_SIZE        SZ_4K
+#define MSM_GPIO1_BASE        IOMEM(0xF8003000)
+#define MSM_GPIO1_PHYS        0xA9200000
+#define MSM_GPIO1_SIZE        SZ_4K
 
-#define MSM_CLK_CTL_BASE      IOMEM(0xE0005000)
+#define MSM_GPIO2_BASE        IOMEM(0xF8004000)
+#define MSM_GPIO2_PHYS        0xA9300000
+#define MSM_GPIO2_SIZE        SZ_4K
+
+#define MSM_CLK_CTL_BASE      IOMEM(0xF8005000)
 #define MSM_CLK_CTL_PHYS      0xA8600000
 #define MSM_CLK_CTL_SIZE      SZ_4K
 
-#define MSM_SHARED_RAM_BASE   IOMEM(0xE0100000)
+#define MSM_SHARED_RAM_BASE   IOMEM(0xF8100000)
 #define MSM_SHARED_RAM_PHYS   0x01F00000
 #define MSM_SHARED_RAM_SIZE   SZ_1M
 
@@ -84,6 +89,9 @@
 #define MSM_SDC4_PHYS         0xA0700000
 #define MSM_SDC4_SIZE         SZ_4K
 
+#define MSM_NAND_PHYS         0xA0A00000
+#define MSM_NAND_SIZE         SZ_4K
+
 #define MSM_I2C_PHYS          0xA9900000
 #define MSM_I2C_SIZE          SZ_4K
 
@@ -99,17 +107,30 @@
 #define MSM_MDP_PHYS          0xAA200000
 #define MSM_MDP_SIZE          0x000F0000
 
+#define MSM_MDC_BASE	      IOMEM(0xF8200000)
 #define MSM_MDC_PHYS	      0xAA500000
 #define MSM_MDC_SIZE	      SZ_1M
 
+#define MSM_AD5_BASE          IOMEM(0xF8300000)
 #define MSM_AD5_PHYS          0xAC000000
 #define MSM_AD5_SIZE          (SZ_1M*13)
 
-#ifndef __ASSEMBLY__
+#define MSM_VFE_PHYS          0xA0F00000
+#define MSM_VFE_SIZE          SZ_1M
 
-extern void __iomem *__msm_ioremap_caller(unsigned long phys_addr, size_t size,
-					  unsigned int mtype, void *caller);
+#define MSM_UART1DM_PHYS      0xA0200000
+#define MSM_UART2DM_PHYS      0xA0300000
 
+#define MSM_SSBI_PHYS         0xA8100000
+#define MSM_SSBI_SIZE         SZ_4K
+
+#define MSM_TSSC_PHYS         0xAA300000
+#define MSM_TSSC_SIZE         SZ_4K
+
+#if defined(CONFIG_ARCH_MSM7X30)
+#define MSM_GCC_BASE          IOMEM(0xF8009000)
+#define MSM_GCC_PHYS          0xC0182000
+#define MSM_GCC_SIZE          SZ_4K
 #endif
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-7x30.h b/arch/arm/mach-msm/include/mach/msm_iomap-7x30.h
index f944fe6..dfc6f23 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-7x30.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-7x30.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2011 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012 Code Aurora Forum. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -35,70 +35,53 @@
  *
  */
 
-#define MSM_VIC_BASE          IOMEM(0xE0000000)
-#define MSM_VIC_PHYS          0xC0080000
-#define MSM_VIC_SIZE          SZ_4K
+#define MSM7X30_VIC_PHYS		0xC0080000
+#define MSM7X30_VIC_SIZE		SZ_4K
 
-#define MSM7X30_CSR_PHYS      0xC0100000
-#define MSM7X30_CSR_SIZE      SZ_4K
+#define MSM7X30_CSR_PHYS		0xC0100000
+#define MSM7X30_CSR_SIZE		SZ_4K
 
-#define MSM_DMOV_BASE         IOMEM(0xE0002000)
-#define MSM_DMOV_PHYS         0xAC400000
-#define MSM_DMOV_SIZE         SZ_4K
+#define MSM7X30_TMR_PHYS		MSM7X30_CSR_PHYS
+#define MSM7X30_TMR_SIZE		SZ_4K
 
-#define MSM7X30_GPIO1_PHYS        0xAC001000
-#define MSM7X30_GPIO1_SIZE        SZ_4K
+#define MSM7X30_GPIO1_PHYS		0xAC001000
+#define MSM7X30_GPIO1_SIZE		SZ_4K
 
-#define MSM7X30_GPIO2_PHYS        0xAC101000
-#define MSM7X30_GPIO2_SIZE        SZ_4K
+#define MSM7X30_GPIO2_PHYS		0xAC101000
+#define MSM7X30_GPIO2_SIZE		SZ_4K
 
-#define MSM_CLK_CTL_BASE      IOMEM(0xE0005000)
-#define MSM_CLK_CTL_PHYS      0xAB800000
-#define MSM_CLK_CTL_SIZE      SZ_4K
+#define MSM7X30_CLK_CTL_PHYS		0xAB800000
+#define MSM7X30_CLK_CTL_SIZE		SZ_4K
 
-#define MSM_CLK_CTL_SH2_BASE  IOMEM(0xE0006000)
-#define MSM_CLK_CTL_SH2_PHYS  0xABA01000
-#define MSM_CLK_CTL_SH2_SIZE  SZ_4K
+#define MSM7X30_CLK_CTL_SH2_PHYS	0xABA01000
+#define MSM7X30_CLK_CTL_SH2_SIZE	SZ_4K
 
-#define MSM_ACC_BASE          IOMEM(0xE0007000)
-#define MSM_ACC_PHYS          0xC0101000
-#define MSM_ACC_SIZE          SZ_4K
+#define MSM7X30_ACC0_PHYS		0xC0101000
+#define MSM7X30_ACC0_SIZE		SZ_4K
 
-#define MSM_SAW_BASE          IOMEM(0xE0008000)
-#define MSM_SAW_PHYS          0xC0102000
-#define MSM_SAW_SIZE          SZ_4K
+#define MSM7X30_SAW0_PHYS		0xC0102000
+#define MSM7X30_SAW0_SIZE		SZ_4K
 
-#define MSM_GCC_BASE	      IOMEM(0xE0009000)
-#define MSM_GCC_PHYS	      0xC0182000
-#define MSM_GCC_SIZE	      SZ_4K
+#define MSM7X30_APCS_GCC_PHYS		0xC0182000
+#define MSM7X30_APCS_GCC_SIZE		SZ_4K
 
-#define MSM_TCSR_BASE	      IOMEM(0xE000A000)
-#define MSM_TCSR_PHYS	      0xAB600000
-#define MSM_TCSR_SIZE	      SZ_4K
+#define MSM7X30_TCSR_PHYS		0xAB600000
+#define MSM7X30_TCSR_SIZE		SZ_4K
 
-#define MSM_SHARED_RAM_BASE   IOMEM(0xE0100000)
-#define MSM_SHARED_RAM_PHYS   0x00100000
-#define MSM_SHARED_RAM_SIZE   SZ_1M
+#define MSM7X30_UART1_PHYS		0xACA00000
+#define MSM7X30_UART1_SIZE		SZ_4K
 
-#define MSM_UART1_PHYS        0xACA00000
-#define MSM_UART1_SIZE        SZ_4K
+#define MSM7X30_UART2_PHYS		0xACB00000
+#define MSM7X30_UART2_SIZE		SZ_4K
 
-#define MSM_UART2_PHYS        0xACB00000
-#define MSM_UART2_SIZE        SZ_4K
+#define MSM7X30_UART3_PHYS		0xACC00000
+#define MSM7X30_UART3_SIZE		SZ_4K
 
-#define MSM_UART3_PHYS        0xACC00000
-#define MSM_UART3_SIZE        SZ_4K
+#define MSM7X30_MDC_PHYS		0xAA500000
+#define MSM7X30_MDC_SIZE		SZ_1M
 
-#define MSM_MDC_BASE	      IOMEM(0xE0200000)
-#define MSM_MDC_PHYS	      0xAA500000
-#define MSM_MDC_SIZE	      SZ_1M
-
-#define MSM_AD5_BASE          IOMEM(0xE0300000)
-#define MSM_AD5_PHYS          0xA7000000
-#define MSM_AD5_SIZE          (SZ_1M*13)
-
-#define MSM_HSUSB_PHYS        0xA3600000
-#define MSM_HSUSB_SIZE        SZ_1K
+#define MSM7X30_AD5_PHYS		0xA7000000
+#define MSM7X30_AD5_SIZE		(SZ_1M*13)
 
 #ifndef __ASSEMBLY__
 extern void msm_map_msm7x30_io(void);
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-7xxx.h b/arch/arm/mach-msm/include/mach/msm_iomap-7xxx.h
new file mode 100644
index 0000000..4c26d08
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-7xxx.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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.
+ *
+ *
+ * The MSM peripherals are spread all over across 768MB of physical
+ * space, which makes just having a simple IO_ADDRESS macro to slide
+ * them into the right virtual location rough.  Instead, we will
+ * provide a master phys->virt mapping for peripherals here.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_IOMAP_7XXX_H
+#define __ASM_ARCH_MSM_IOMAP_7XXX_H
+
+/* Physical base address and size of peripherals.
+ * Ordered by the virtual base addresses they will be mapped at.
+ *
+ * MSM_VIC_BASE must be an value that can be loaded via a "mov"
+ * instruction, otherwise entry-macro.S will not compile.
+ *
+ * If you add or remove entries here, you'll want to edit the
+ * msm_io_desc array in arch/arm/mach-msm/io.c to reflect your
+ * changes.
+ *
+ */
+
+#define MSM7XXX_VIC_PHYS          0xC0000000
+#define MSM7XXX_VIC_SIZE          SZ_4K
+
+#define MSM7XXX_CSR_PHYS          0xC0100000
+#define MSM7XXX_CSR_SIZE          SZ_4K
+
+#define MSM7XXX_TMR_PHYS          MSM7XXX_CSR_PHYS
+#define MSM7XXX_TMR_SIZE          SZ_4K
+
+#define MSM7XXX_GPIO1_PHYS        0xA9200000
+#define MSM7XXX_GPIO1_SIZE        SZ_4K
+
+#define MSM7XXX_GPIO2_PHYS        0xA9300000
+#define MSM7XXX_GPIO2_SIZE        SZ_4K
+
+#define MSM7XXX_CLK_CTL_PHYS      0xA8600000
+#define MSM7XXX_CLK_CTL_SIZE      SZ_4K
+
+#define MSM7XXX_L2CC_PHYS         0xC0400000
+#define MSM7XXX_L2CC_SIZE         SZ_4K
+
+#define MSM7XXX_UART1_PHYS        0xA9A00000
+#define MSM7XXX_UART1_SIZE        SZ_4K
+
+#define MSM7XXX_UART2_PHYS        0xA9B00000
+#define MSM7XXX_UART2_SIZE        SZ_4K
+
+#define MSM7XXX_UART3_PHYS        0xA9C00000
+#define MSM7XXX_UART3_SIZE        SZ_4K
+
+#define MSM7XXX_MDC_PHYS	  0xAA500000
+#define MSM7XXX_MDC_SIZE          SZ_1M
+
+#define MSM7XXX_AD5_PHYS          0xAC000000
+#define MSM7XXX_AD5_SIZE          (SZ_1M*13)
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8064.h b/arch/arm/mach-msm/include/mach/msm_iomap-8064.h
new file mode 100644
index 0000000..10e2b74
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8064.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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.
+ *
+ *
+ * The MSM peripherals are spread all over across 768MB of physical
+ * space, which makes just having a simple IO_ADDRESS macro to slide
+ * them into the right virtual location rough.  Instead, we will
+ * provide a master phys->virt mapping for peripherals here.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_IOMAP_8064_H
+#define __ASM_ARCH_MSM_IOMAP_8064_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
+ * msm_io_desc array in arch/arm/mach-msm/io.c to reflect your
+ * changes.
+ *
+ */
+
+#define APQ8064_TMR_PHYS		0x0200A000
+#define APQ8064_TMR_SIZE		SZ_4K
+
+#define APQ8064_TMR0_PHYS		0x0208A000
+#define APQ8064_TMR0_SIZE		SZ_4K
+
+#define APQ8064_QGIC_DIST_PHYS		0x02000000
+#define APQ8064_QGIC_DIST_SIZE		SZ_4K
+
+#define APQ8064_QGIC_CPU_PHYS		0x02002000
+#define APQ8064_QGIC_CPU_SIZE		SZ_4K
+
+#define APQ8064_TLMM_PHYS		0x00800000
+#define APQ8064_TLMM_SIZE		SZ_16K
+
+#define APQ8064_ACC0_PHYS		0x02088000
+#define APQ8064_ACC0_SIZE		SZ_4K
+
+#define APQ8064_ACC1_PHYS		0x02098000
+#define APQ8064_ACC1_SIZE		SZ_4K
+
+#define APQ8064_ACC2_PHYS		0x020A8000
+#define APQ8064_ACC2_SIZE		SZ_4K
+
+#define APQ8064_ACC3_PHYS		0x020B8000
+#define APQ8064_ACC3_SIZE		SZ_4K
+
+#define APQ8064_APCS_GCC_PHYS		0x02011000
+#define APQ8064_APCS_GCC_SIZE		SZ_4K
+
+#define APQ8064_CLK_CTL_PHYS		0x00900000
+#define APQ8064_CLK_CTL_SIZE		SZ_16K
+
+#define APQ8064_MMSS_CLK_CTL_PHYS	0x04000000
+#define APQ8064_MMSS_CLK_CTL_SIZE	SZ_4K
+
+#define APQ8064_LPASS_CLK_CTL_PHYS	0x28000000
+#define APQ8064_LPASS_CLK_CTL_SIZE	SZ_4K
+
+#define APQ8064_HFPLL_PHYS		0x00903000
+#define APQ8064_HFPLL_SIZE		SZ_4K
+
+#define APQ8064_IMEM_PHYS		0x2A03F000
+#define APQ8064_IMEM_SIZE		SZ_4K
+
+#define APQ8064_RPM_PHYS		0x00108000
+#define APQ8064_RPM_SIZE		SZ_4K
+
+#define APQ8064_RPM_MPM_PHYS		0x00200000
+#define APQ8064_RPM_MPM_SIZE		SZ_4K
+
+#define APQ8064_SAW0_PHYS		0x02089000
+#define APQ8064_SAW0_SIZE		SZ_4K
+
+#define APQ8064_SAW1_PHYS		0x02099000
+#define APQ8064_SAW1_SIZE		SZ_4K
+
+#define APQ8064_SAW2_PHYS		0x020A9000
+#define APQ8064_SAW2_SIZE		SZ_4K
+
+#define APQ8064_SAW3_PHYS		0x020B9000
+#define APQ8064_SAW3_SIZE		SZ_4K
+
+#define APQ8064_SAW_L2_PHYS		0x02012000
+#define APQ8064_SAW_L2_SIZE		SZ_4K
+#define APQ8064_QFPROM_PHYS		0x00700000
+#define APQ8064_QFPROM_SIZE		SZ_4K
+
+#define APQ8064_SIC_NON_SECURE_PHYS	0x12100000
+#define APQ8064_SIC_NON_SECURE_SIZE	SZ_64K
+
+#define APQ8064_HDMI_PHYS		0x04A00000
+#define APQ8064_HDMI_SIZE		SZ_4K
+
+#ifdef CONFIG_DEBUG_APQ8064_UART
+#define MSM_DEBUG_UART_BASE		IOMEM(0xFA740000)
+#define MSM_DEBUG_UART_PHYS		0x16640000
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8625.h b/arch/arm/mach-msm/include/mach/msm_iomap-8625.h
new file mode 100644
index 0000000..3435c2a
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8625.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. 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.
+ *
+ *
+ * The MSM peripherals are spread all over across 768MB of physical
+ * space, which makes just having a simple IO_ADDRESS macro to slide
+ * them into the right virtual location rough.  Instead, we will
+ * provide a master phys->virt mapping for peripherals here.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_IOMAP_8625_H
+#define __ASM_ARCH_MSM_IOMAP_8625_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
+ * msm_io_desc array in arch/arm/mach-msm/io.c to reflect your
+ * changes.
+ *
+ */
+
+#define MSM8625_TMR_PHYS		0xC0800000
+#define MSM8625_TMR_SIZE		SZ_4K
+
+#define MSM8625_TMR0_PHYS		0xC0100000
+#define MSM8625_TMR0_SIZE		SZ_4K
+
+#define MSM8625_CLK_CTL_PHYS		0xA8600000
+#define MSM8625_CLK_CTL_SIZE		SZ_4K
+
+#define MSM8625_QGIC_DIST_PHYS		0xC0000000
+#define MSM8625_QGIC_DIST_SIZE		SZ_4K
+
+#define MSM8625_QGIC_CPU_PHYS		0xC0002000
+#define MSM8625_QGIC_CPU_SIZE		SZ_4K
+
+#define MSM8625_SCU_PHYS		0xC0600000
+#define MSM8625_SCU_SIZE		SZ_256
+
+#define MSM8625_SAW0_PHYS		0xC0200000
+#define MSM8625_SAW0_SIZE		SZ_4K
+
+#define MSM8625_SAW1_PHYS		0xC0700000
+#define MSM8625_SAW1_SIZE		SZ_4K
+
+#define MSM8625_CFG_CTL_PHYS		0xA9800000
+#define MSM8625_CFG_CTL_SIZE		SZ_4K
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8930.h b/arch/arm/mach-msm/include/mach/msm_iomap-8930.h
new file mode 100644
index 0000000..f3f8b8f
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8930.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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.
+ *
+ *
+ * The MSM peripherals are spread all over across 768MB of physical
+ * space, which makes just having a simple IO_ADDRESS macro to slide
+ * them into the right virtual location rough.  Instead, we will
+ * provide a master phys->virt mapping for peripherals here.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_IOMAP_8930_H
+#define __ASM_ARCH_MSM_IOMAP_8930_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
+ * msm_io_desc array in arch/arm/mach-msm/io.c to reflect your
+ * changes.
+ *
+ */
+
+#define MSM8930_TMR_PHYS		0x0200A000
+#define MSM8930_TMR_SIZE		SZ_4K
+
+#define MSM8930_TMR0_PHYS		0x0208A000
+#define MSM8930_TMR0_SIZE		SZ_4K
+
+#define MSM8930_RPM_PHYS		0x00108000
+#define MSM8930_RPM_SIZE		SZ_4K
+
+#define MSM8930_RPM_MPM_PHYS		0x00200000
+#define MSM8930_RPM_MPM_SIZE		SZ_4K
+
+#define MSM8930_TCSR_PHYS		0x1A400000
+#define MSM8930_TCSR_SIZE		SZ_4K
+
+#define MSM8930_APCS_GCC_PHYS		0x02011000
+#define MSM8930_APCS_GCC_SIZE		SZ_4K
+
+#define MSM8930_SAW_L2_PHYS		0x02012000
+#define MSM8930_SAW_L2_SIZE		SZ_4K
+
+#define MSM8930_SAW0_PHYS		0x02089000
+#define MSM8930_SAW0_SIZE		SZ_4K
+
+#define MSM8930_SAW1_PHYS		0x02099000
+#define MSM8930_SAW1_SIZE		SZ_4K
+
+#define MSM8930_IMEM_PHYS		0x2A03F000
+#define MSM8930_IMEM_SIZE		SZ_4K
+
+#define MSM8930_ACC0_PHYS		0x02088000
+#define MSM8930_ACC0_SIZE		SZ_4K
+
+#define MSM8930_ACC1_PHYS		0x02098000
+#define MSM8930_ACC1_SIZE		SZ_4K
+
+#define MSM8930_QGIC_DIST_PHYS		0x02000000
+#define MSM8930_QGIC_DIST_SIZE		SZ_4K
+
+#define MSM8930_QGIC_CPU_PHYS		0x02002000
+#define MSM8930_QGIC_CPU_SIZE		SZ_4K
+
+#define MSM8930_CLK_CTL_PHYS		0x00900000
+#define MSM8930_CLK_CTL_SIZE		SZ_16K
+
+#define MSM8930_MMSS_CLK_CTL_PHYS	0x04000000
+#define MSM8930_MMSS_CLK_CTL_SIZE	SZ_4K
+
+#define MSM8930_LPASS_CLK_CTL_PHYS	0x28000000
+#define MSM8930_LPASS_CLK_CTL_SIZE	SZ_4K
+
+#define MSM8930_HFPLL_PHYS		0x00903000
+#define MSM8930_HFPLL_SIZE		SZ_4K
+
+#define MSM8930_TLMM_PHYS		0x00800000
+#define MSM8930_TLMM_SIZE		SZ_16K
+
+#define MSM8930_DMOV_PHYS		0x18320000
+#define MSM8930_DMOV_SIZE		SZ_1M
+
+#define MSM8930_SIC_NON_SECURE_PHYS	0x12100000
+#define MSM8930_SIC_NON_SECURE_SIZE	SZ_64K
+
+#define MSM_GPT_BASE			(MSM_TMR_BASE + 0x4)
+#define MSM_DGT_BASE			(MSM_TMR_BASE + 0x24)
+
+#define MSM8930_HDMI_PHYS		0x04A00000
+#define MSM8930_HDMI_SIZE		SZ_4K
+
+#ifdef CONFIG_DEBUG_MSM8930_UART
+#define MSM_DEBUG_UART_BASE		IOMEM(0xFA740000)
+#define MSM_DEBUG_UART_PHYS		0x16440000
+#endif
+
+#define MSM8930_QFPROM_PHYS		0x00700000
+#define MSM8930_QFPROM_SIZE		SZ_4K
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8960.h b/arch/arm/mach-msm/include/mach/msm_iomap-8960.h
index a1752c0..54c901f 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8960.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8960.h
@@ -32,18 +32,79 @@
  *
  */
 
+#define MSM8960_TMR_PHYS		0x0200A000
+#define MSM8960_TMR_SIZE		SZ_4K
 
-#define MSM8960_QGIC_DIST_PHYS	0x02000000
-#define MSM8960_QGIC_DIST_SIZE	SZ_4K
+#define MSM8960_TMR0_PHYS		0x0208A000
+#define MSM8960_TMR0_SIZE		SZ_4K
 
-#define MSM8960_QGIC_CPU_PHYS	0x02002000
-#define MSM8960_QGIC_CPU_SIZE	SZ_4K
+#define MSM8960_RPM_PHYS		0x00108000
+#define MSM8960_RPM_SIZE		SZ_4K
 
-#define MSM8960_TMR_PHYS	0x0200A000
-#define MSM8960_TMR_SIZE	SZ_4K
+#define MSM8960_RPM_MPM_PHYS		0x00200000
+#define MSM8960_RPM_MPM_SIZE		SZ_4K
 
-#define MSM8960_TMR0_PHYS	0x0208A000
-#define MSM8960_TMR0_SIZE	SZ_4K
+#define MSM8960_TCSR_PHYS		0x1A400000
+#define MSM8960_TCSR_SIZE		SZ_4K
+
+#define MSM8960_APCS_GCC_PHYS		0x02011000
+#define MSM8960_APCS_GCC_SIZE		SZ_4K
+
+#define MSM8960_SAW_L2_PHYS		0x02012000
+#define MSM8960_SAW_L2_SIZE		SZ_4K
+
+#define MSM8960_SAW0_PHYS		0x02089000
+#define MSM8960_SAW0_SIZE		SZ_4K
+
+#define MSM8960_SAW1_PHYS		0x02099000
+#define MSM8960_SAW1_SIZE		SZ_4K
+
+#define MSM8960_IMEM_PHYS		0x2A03F000
+#define MSM8960_IMEM_SIZE		SZ_4K
+
+#define MSM8960_ACC0_PHYS		0x02088000
+#define MSM8960_ACC0_SIZE		SZ_4K
+
+#define MSM8960_ACC1_PHYS		0x02098000
+#define MSM8960_ACC1_SIZE		SZ_4K
+
+#define MSM8960_QGIC_DIST_PHYS		0x02000000
+#define MSM8960_QGIC_DIST_SIZE		SZ_4K
+
+#define MSM8960_QGIC_CPU_PHYS		0x02002000
+#define MSM8960_QGIC_CPU_SIZE		SZ_4K
+
+#define MSM8960_CLK_CTL_PHYS		0x00900000
+#define MSM8960_CLK_CTL_SIZE		SZ_16K
+
+#define MSM8960_MMSS_CLK_CTL_PHYS	0x04000000
+#define MSM8960_MMSS_CLK_CTL_SIZE	SZ_4K
+
+#define MSM8960_LPASS_CLK_CTL_PHYS	0x28000000
+#define MSM8960_LPASS_CLK_CTL_SIZE	SZ_4K
+
+#define MSM8960_HFPLL_PHYS		0x00903000
+#define MSM8960_HFPLL_SIZE		SZ_4K
+
+#define MSM8960_TLMM_PHYS		0x00800000
+#define MSM8960_TLMM_SIZE		SZ_16K
+
+#define MSM8960_SIC_NON_SECURE_PHYS	0x12100000
+#define MSM8960_SIC_NON_SECURE_SIZE	SZ_64K
+
+#define MSM_GPT_BASE			(MSM_TMR_BASE + 0x4)
+#define MSM_DGT_BASE			(MSM_TMR_BASE + 0x24)
+
+#define MSM8960_HDMI_PHYS		0x04A00000
+#define MSM8960_HDMI_SIZE		SZ_4K
+
+#ifdef CONFIG_DEBUG_MSM8960_UART
+#define MSM_DEBUG_UART_BASE		IOMEM(0xFA740000)
+#define MSM_DEBUG_UART_PHYS		0x16440000
+#endif
+
+#define MSM8960_QFPROM_PHYS		0x00700000
+#define MSM8960_QFPROM_SIZE		SZ_4K
 
 #ifdef CONFIG_DEBUG_MSM8960_UART
 #define MSM_DEBUG_UART_BASE	0xE1040000
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8x50.h b/arch/arm/mach-msm/include/mach/msm_iomap-8x50.h
index da77cc1..a1b32ec 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8x50.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8x50.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2011 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -35,43 +35,43 @@
  *
  */
 
-#define MSM_VIC_BASE          IOMEM(0xE0000000)
+#define MSM_VIC_BASE          IOMEM(0xFA000000)
 #define MSM_VIC_PHYS          0xAC000000
 #define MSM_VIC_SIZE          SZ_4K
 
-#define QSD8X50_CSR_PHYS      0xAC100000
-#define QSD8X50_CSR_SIZE      SZ_4K
+#define MSM_CSR_BASE          IOMEM(0xFA001000)
+#define MSM_CSR_PHYS          0xAC100000
+#define MSM_CSR_SIZE          SZ_4K
 
-#define MSM_DMOV_BASE         IOMEM(0xE0002000)
-#define MSM_DMOV_PHYS         0xA9700000
-#define MSM_DMOV_SIZE         SZ_4K
+#define MSM_TMR_PHYS          MSM_CSR_PHYS
+#define MSM_TMR_BASE          MSM_CSR_BASE
+#define MSM_TMR_SIZE          SZ_4K
 
-#define QSD8X50_GPIO1_PHYS        0xA9000000
-#define QSD8X50_GPIO1_SIZE        SZ_4K
+#define MSM_GPIO1_BASE        IOMEM(0xFA003000)
+#define MSM_GPIO1_PHYS        0xA9000000
+#define MSM_GPIO1_SIZE        SZ_4K
 
-#define QSD8X50_GPIO2_PHYS        0xA9100000
-#define QSD8X50_GPIO2_SIZE        SZ_4K
+#define MSM_GPIO2_BASE        IOMEM(0xFA004000)
+#define MSM_GPIO2_PHYS        0xA9100000
+#define MSM_GPIO2_SIZE        SZ_4K
 
-#define MSM_CLK_CTL_BASE      IOMEM(0xE0005000)
+#define MSM_CLK_CTL_BASE      IOMEM(0xFA005000)
 #define MSM_CLK_CTL_PHYS      0xA8600000
 #define MSM_CLK_CTL_SIZE      SZ_4K
 
-#define MSM_SIRC_BASE         IOMEM(0xE1006000)
+#define MSM_SIRC_BASE         IOMEM(0xFB006000)
 #define MSM_SIRC_PHYS         0xAC200000
 #define MSM_SIRC_SIZE         SZ_4K
 
-#define MSM_SCPLL_BASE        IOMEM(0xE1007000)
+#define MSM_SCPLL_BASE        IOMEM(0xFB007000)
 #define MSM_SCPLL_PHYS        0xA8800000
 #define MSM_SCPLL_SIZE        SZ_4K
 
-#ifdef CONFIG_MSM_SOC_REV_A
-#define MSM_SMI_BASE 0xE0000000
-#else
-#define MSM_SMI_BASE 0x00000000
-#endif
+#define MSM_TCSR_BASE         IOMEM(0xFB008000)
+#define MSM_TCSR_PHYS         0xA8700000
+#define MSM_TCSR_SIZE         SZ_4K
 
-#define MSM_SHARED_RAM_BASE   IOMEM(0xE0100000)
-#define MSM_SHARED_RAM_PHYS (MSM_SMI_BASE + 0x00100000)
+#define MSM_SHARED_RAM_BASE   IOMEM(0xFA100000)
 #define MSM_SHARED_RAM_SIZE   SZ_1M
 
 #define MSM_UART1_PHYS        0xA9A00000
@@ -83,47 +83,12 @@
 #define MSM_UART3_PHYS        0xA9C00000
 #define MSM_UART3_SIZE        SZ_4K
 
-#define MSM_MDC_BASE	      IOMEM(0xE0200000)
+#define MSM_MDC_BASE	      IOMEM(0xFA200000)
 #define MSM_MDC_PHYS	      0xAA500000
 #define MSM_MDC_SIZE	      SZ_1M
 
-#define MSM_AD5_BASE          IOMEM(0xE0300000)
+#define MSM_AD5_BASE          IOMEM(0xFA300000)
 #define MSM_AD5_PHYS          0xAC000000
 #define MSM_AD5_SIZE          (SZ_1M*13)
 
-
-#define MSM_I2C_SIZE          SZ_4K
-#define MSM_I2C_PHYS          0xA9900000
-
-#define MSM_HSUSB_PHYS        0xA0800000
-#define MSM_HSUSB_SIZE        SZ_1K
-
-#define MSM_NAND_PHYS           0xA0A00000
-
-
-#define MSM_TSIF_PHYS        (0xa0100000)
-#define MSM_TSIF_SIZE        (0x200)
-
-#define MSM_TSSC_PHYS         0xAA300000
-
-#define MSM_UART1DM_PHYS      0xA0200000
-#define MSM_UART2DM_PHYS      0xA0900000
-
-
-#define MSM_SDC1_PHYS          0xA0300000
-#define MSM_SDC1_SIZE          SZ_4K
-
-#define MSM_SDC2_PHYS          0xA0400000
-#define MSM_SDC2_SIZE          SZ_4K
-
-#define MSM_SDC3_PHYS          0xA0500000
-#define MSM_SDC3_SIZE           SZ_4K
-
-#define MSM_SDC4_PHYS          0xA0600000
-#define MSM_SDC4_SIZE          SZ_4K
-
-#ifndef __ASSEMBLY__
-extern void msm_map_qsd8x50_io(void);
-#endif
-
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h b/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
index 5aed57d..4f90ea5 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
@@ -35,35 +35,99 @@
  *
  */
 
-#define MSM8X60_QGIC_DIST_PHYS	0x02080000
-#define MSM8X60_QGIC_DIST_SIZE	SZ_4K
+#define MSM_QGIC_DIST_BASE	IOMEM(0xFA000000)
+#define MSM_QGIC_DIST_PHYS	0x02080000
+#define MSM_QGIC_DIST_SIZE	SZ_4K
 
-#define MSM8X60_QGIC_CPU_PHYS	0x02081000
-#define MSM8X60_QGIC_CPU_SIZE	SZ_4K
+#define MSM_QGIC_CPU_BASE	IOMEM(0xFA001000)
+#define MSM_QGIC_CPU_PHYS	0x02081000
+#define MSM_QGIC_CPU_SIZE	SZ_4K
 
-#define MSM_ACC_BASE		IOMEM(0xF0002000)
+#define MSM_ACC_BASE		IOMEM(0xFA002000)
 #define MSM_ACC_PHYS		0x02001000
 #define MSM_ACC_SIZE		SZ_4K
 
-#define MSM_GCC_BASE		IOMEM(0xF0003000)
+#define MSM_GCC_BASE		IOMEM(0xFA003000)
 #define MSM_GCC_PHYS		0x02082000
 #define MSM_GCC_SIZE		SZ_4K
 
-#define MSM_TLMM_BASE		IOMEM(0xF0004000)
+#define MSM_TLMM_BASE		IOMEM(0xFA004000)
 #define MSM_TLMM_PHYS		0x00800000
 #define MSM_TLMM_SIZE		SZ_16K
 
-#define MSM_SHARED_RAM_BASE	IOMEM(0xF0100000)
+#define MSM_RPM_BASE		IOMEM(0xFA008000)
+#define MSM_RPM_PHYS		0x00104000
+#define MSM_RPM_SIZE		SZ_4K
+
+#define MSM_CLK_CTL_BASE	IOMEM(0xFA010000)
+#define MSM_CLK_CTL_PHYS	0x00900000
+#define MSM_CLK_CTL_SIZE	SZ_16K
+
+#define MSM_MMSS_CLK_CTL_BASE	IOMEM(0xFA014000)
+#define MSM_MMSS_CLK_CTL_PHYS	0x04000000
+#define MSM_MMSS_CLK_CTL_SIZE	SZ_4K
+
+#define MSM_LPASS_CLK_CTL_BASE	IOMEM(0xFA015000)
+#define MSM_LPASS_CLK_CTL_PHYS	0x28000000
+#define MSM_LPASS_CLK_CTL_SIZE	SZ_4K
+
+#define MSM_TMR_BASE		IOMEM(0xFA016000)
+#define MSM_TMR_PHYS		0x02000000
+#define MSM_TMR_SIZE		SZ_4K
+
+#define MSM_TMR0_BASE		IOMEM(0xFA017000)
+#define MSM_TMR0_PHYS		0x02040000
+#define MSM_TMR0_SIZE		SZ_4K
+
+#define MSM_SCPLL_BASE		IOMEM(0xFA018000)
+#define MSM_SCPLL_PHYS		0x00903000
+#define MSM_SCPLL_SIZE		SZ_1K
+
+#define MSM_SHARED_RAM_BASE	IOMEM(0xFA200000)
 #define MSM_SHARED_RAM_SIZE	SZ_1M
 
-#define MSM8X60_TMR_PHYS	0x02000000
-#define MSM8X60_TMR_SIZE	SZ_4K
+#define MSM_ACC0_BASE           IOMEM(0xFA300000)
+#define MSM_ACC0_PHYS           0x02041000
+#define MSM_ACC0_SIZE           SZ_4K
 
-#define MSM8X60_TMR0_PHYS	0x02040000
-#define MSM8X60_TMR0_SIZE	SZ_4K
+#define MSM_ACC1_BASE           IOMEM(0xFA301000)
+#define MSM_ACC1_PHYS           0x02051000
+#define MSM_ACC1_SIZE           SZ_4K
+
+#define MSM_RPM_MPM_BASE        IOMEM(0xFA302000)
+#define MSM_RPM_MPM_PHYS        0x00200000
+#define MSM_RPM_MPM_SIZE        SZ_4K
+
+#define MSM_SAW0_BASE		IOMEM(0xFA303000)
+#define MSM_SAW0_PHYS		0x02042000
+#define MSM_SAW0_SIZE		SZ_4K
+
+#define MSM_SAW1_BASE		IOMEM(0xFA304000)
+#define MSM_SAW1_PHYS		0x02052000
+#define MSM_SAW1_SIZE		SZ_4K
+
+#define MSM_SIC_NON_SECURE_BASE	IOMEM(0xFA600000)
+#define MSM_SIC_NON_SECURE_PHYS	0x12100000
+#define MSM_SIC_NON_SECURE_SIZE	SZ_64K
+
+#define MSM_QFPROM_BASE	IOMEM(0xFA700000)
+#define MSM_QFPROM_PHYS	0x00700000
+#define MSM_QFPROM_SIZE	SZ_4K
+
+#define MSM_TCSR_BASE	IOMEM(0xFA701000)
+#define MSM_TCSR_PHYS	0x16B00000
+#define MSM_TCSR_SIZE	SZ_4K
+
+#define MSM_IMEM_BASE		IOMEM(0xFA702000)
+#define MSM_IMEM_PHYS		0x2A05F000
+#define MSM_IMEM_SIZE		SZ_4K
+
+#define MSM_HDMI_BASE		IOMEM(0xFA800000)
+#define MSM_HDMI_PHYS		0x04A00000
+#define MSM_HDMI_SIZE		SZ_4K
 
 #ifdef CONFIG_DEBUG_MSM8660_UART
-#define MSM_DEBUG_UART_BASE	0xE1040000
+#define MSM_DEBUG_UART_BASE	0xFBC40000
 #define MSM_DEBUG_UART_PHYS	0x19C40000
 #endif
 
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-9615.h b/arch/arm/mach-msm/include/mach/msm_iomap-9615.h
new file mode 100644
index 0000000..fc9b198
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-9615.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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.
+ *
+ *
+ * The MSM peripherals are spread all over across 768MB of physical
+ * space, which makes just having a simple IO_ADDRESS macro to slide
+ * them into the right virtual location rough.  Instead, we will
+ * provide a master phys->virt mapping for peripherals here.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_IOMAP_9615_H
+#define __ASM_ARCH_MSM_IOMAP_9615_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
+ * msm_io_desc array in arch/arm/mach-msm/io.c to reflect your
+ * changes.
+ *
+ */
+
+#define MSM9615_TMR_PHYS		0x0200A000
+#define MSM9615_TMR_SIZE		SZ_4K
+
+#define MSM9615_QGIC_DIST_PHYS		0x02000000
+#define MSM9615_QGIC_DIST_SIZE		SZ_4K
+
+#define MSM9615_QGIC_CPU_PHYS		0x02002000
+#define MSM9615_QGIC_CPU_SIZE		SZ_4K
+
+#define MSM9615_TLMM_PHYS		0x00800000
+#define MSM9615_TLMM_SIZE		SZ_1M
+
+#define MSM9615_ACC0_PHYS		0x02008000
+#define MSM9615_ACC0_SIZE		SZ_4K
+
+#define MSM9615_APCS_GCC_PHYS		0x02011000
+#define MSM9615_APCS_GCC_SIZE		SZ_4K
+
+#define MSM9615_SAW0_PHYS		0x02009000
+#define MSM9615_SAW0_SIZE		SZ_4K
+
+#define MSM9615_TCSR_PHYS		0x1A400000
+#define MSM9615_TCSR_SIZE		SZ_4K
+
+#define MSM9615_L2CC_PHYS		0x02040000
+#define MSM9615_L2CC_SIZE		SZ_4K
+
+#define MSM9615_CLK_CTL_PHYS            0x00900000
+#define MSM9615_CLK_CTL_SIZE            SZ_16K
+
+#define MSM9615_LPASS_CLK_CTL_PHYS      0x28000000
+#define MSM9615_LPASS_CLK_CTL_SIZE      SZ_4K
+
+#define MSM9615_RPM_PHYS		0x00108000
+#define MSM9615_RPM_SIZE		SZ_4K
+
+#define MSM9615_RPM_MPM_PHYS		0x00200000
+#define MSM9615_RPM_MPM_SIZE		SZ_4K
+
+#define MSM9615_APCS_GLB_PHYS		0x02010000
+#define MSM9615_APCS_GLB_SIZE		SZ_4K
+
+#define MSM9615_HSUSB_PHYS		0x12500000
+#define MSM9615_HSUSB_SIZE		SZ_4K
+
+#define MSM9615_HSIC_PHYS		0x12540000
+#define MSM9615_HSIC_SIZE		SZ_4K
+
+#define MSM9615_QFPROM_PHYS		0x00700000
+#define MSM9615_QFPROM_SIZE		SZ_4K
+
+#define MSM9615_IMEM_PHYS		0x2B000000
+#define MSM9615_IMEM_SIZE		SZ_4K
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-9625.h b/arch/arm/mach-msm/include/mach/msm_iomap-9625.h
new file mode 100644
index 0000000..493cf36
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-9625.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. 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_MSM9625_H
+#define __ASM_ARCH_MSM_IOMAP_MSM9625_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 MSM9625_SHARED_RAM_PHYS	0x18D00000
+
+#define MSM9625_APCS_GCC_PHYS	0xF9011000
+#define MSM9625_APCS_GCC_SIZE	SZ_4K
+
+#define MSM9625_TMR_PHYS	0xF9021000
+#define MSM9625_TMR_SIZE	SZ_4K
+
+#define MSM9625_TLMM_PHYS	0xFD510000
+#define MSM9625_TLMM_SIZE	SZ_16K
+
+#ifdef CONFIG_DEBUG_MSM9625_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-copper.h b/arch/arm/mach-msm/include/mach/msm_iomap-copper.h
new file mode 100644
index 0000000..441f82a
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-copper.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2008-2012, Code Aurora Forum. 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_COPPER_H
+#define __ASM_ARCH_MSM_IOMAP_COPPER_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 COPPER_MSM_SHARED_RAM_PHYS	0x0FA00000
+
+#define COPPER_QGIC_DIST_PHYS	0xF9000000
+#define COPPER_QGIC_DIST_SIZE	SZ_4K
+
+#define COPPER_QGIC_CPU_PHYS	0xF9002000
+#define COPPER_QGIC_CPU_SIZE	SZ_4K
+
+#define COPPER_APCS_GCC_PHYS	0xF9011000
+#define COPPER_APCS_GCC_SIZE	SZ_4K
+
+#define COPPER_TLMM_PHYS	0xFD510000
+#define COPPER_TLMM_SIZE	SZ_16K
+
+#ifdef CONFIG_DEBUG_MSMCOPPER_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-fsm9xxx.h b/arch/arm/mach-msm/include/mach/msm_iomap-fsm9xxx.h
new file mode 100644
index 0000000..c30c9e4
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-fsm9xxx.h
@@ -0,0 +1,84 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __ASM_ARCH_MSM_IOMAP_FSM9XXX_H
+#define __ASM_ARCH_MSM_IOMAP_FSM9XXX_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
+ * msm_io_desc array in arch/arm/mach-msm/io.c to reflect your
+ * changes.
+ *
+ */
+
+#define MSM_VIC_BASE          IOMEM(0xFA000000)
+#define MSM_VIC_PHYS          0x9C080000
+#define MSM_VIC_SIZE          SZ_4K
+
+#define MSM_SIRC_BASE         IOMEM(0xFA001000)
+#define MSM_SIRC_PHYS         0x94190000
+#define MSM_SIRC_SIZE         SZ_4K
+
+#define MSM_CSR_BASE          IOMEM(0xFA002000)
+#define MSM_CSR_PHYS          0x9C000000
+#define MSM_CSR_SIZE          SZ_4K
+
+#define MSM_TMR_BASE          MSM_CSR_BASE
+
+#define MSM_TLMM_BASE         IOMEM(0xFA003000)
+#define MSM_TLMM_PHYS         0x94040000
+#define MSM_TLMM_SIZE         SZ_4K
+
+#define MSM_TCSR_BASE	      IOMEM(0xFA004000)
+#define MSM_TCSR_PHYS	      0x94030000
+#define MSM_TCSR_SIZE	      SZ_4K
+
+#define MSM_CLK_CTL_BASE      IOMEM(0xFA005000)
+#define MSM_CLK_CTL_PHYS      0x94020000
+#define MSM_CLK_CTL_SIZE      SZ_4K
+
+#define MSM_ACC_BASE          IOMEM(0xFA006000)
+#define MSM_ACC_PHYS          0x9C001000
+#define MSM_ACC_SIZE          SZ_4K
+
+#define MSM_SAW_BASE          IOMEM(0xFA007000)
+#define MSM_SAW_PHYS          0x9C002000
+#define MSM_SAW_SIZE          SZ_4K
+
+#define MSM_GCC_BASE	      IOMEM(0xFA008000)
+#define MSM_GCC_PHYS	      0x9C082000
+#define MSM_GCC_SIZE	      SZ_4K
+
+#define MSM_GRFC_BASE	      IOMEM(0xFA009000)
+#define MSM_GRFC_PHYS	      0x94038000
+#define MSM_GRFC_SIZE	      SZ_4K
+
+#define MSM_QFP_FUSE_BASE     IOMEM(0xFA010000)
+#define MSM_QFP_FUSE_PHYS     0x80000000
+#define MSM_QFP_FUSE_SIZE     SZ_32K
+
+#define MSM_HH_BASE	      IOMEM(0xFA100000)
+#define MSM_HH_PHYS	      0x94200000
+#define MSM_HH_SIZE	      SZ_1M
+
+#define MSM_SHARED_RAM_BASE   IOMEM(0xFA200000)
+#define MSM_SHARED_RAM_SIZE   SZ_1M
+
+#define MSM_UART1_PHYS        0x94000000
+#define MSM_UART1_SIZE        SZ_4K
+
+#define MSM_UART2_PHYS        0x94100000
+#define MSM_UART2_SIZE        SZ_4K
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index 00afdfb..75cc43a 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -37,37 +37,99 @@
  *
  */
 
-#if defined(CONFIG_ARCH_MSM7X30)
+#define MSM_DEBUG_UART_SIZE	SZ_4K
+
+#if defined(CONFIG_DEBUG_MSM_UART1) || defined(CONFIG_DEBUG_MSM_UART2) \
+				|| defined(CONFIG_DEBUG_MSM_UART3)
+#define MSM_DEBUG_UART_BASE	0xFC000000
+#define MSM_DEBUG_UART_PHYS	CONFIG_MSM_DEBUG_UART_PHYS
+#endif
+
+#define MSM8625_WARM_BOOT_PHYS  0x0FD00000
+
+
+#if defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_APQ8064) || \
+	defined(CONFIG_ARCH_MSM8930) || defined(CONFIG_ARCH_MSM9615) || \
+	defined(CONFIG_ARCH_MSMCOPPER) || defined(CONFIG_ARCH_MSM7X27) || \
+	defined(CONFIG_ARCH_MSM7X25) || defined(CONFIG_ARCH_MSM7X01A) || \
+	defined(CONFIG_ARCH_MSM8625) || defined(CONFIG_ARCH_MSM7X30) || \
+	defined(CONFIG_ARCH_MSM9625)
+
+/* Unified iomap */
+
+#define MSM_TMR_BASE		IOMEM(0xFA000000)	/*  4K	*/
+#define MSM_TMR0_BASE		IOMEM(0xFA001000)	/*  4K	*/
+#define MSM_QGIC_DIST_BASE	IOMEM(0xFA002000)	/*  4K	*/
+#define MSM_QGIC_CPU_BASE	IOMEM(0xFA003000)	/*  4K	*/
+#define MSM_TCSR_BASE		IOMEM(0xFA004000)	/*  4K	*/
+#define MSM_APCS_GCC_BASE	IOMEM(0xFA006000)	/*  4K	*/
+#define MSM_SAW_L2_BASE		IOMEM(0xFA007000)	/*  4K	*/
+#define MSM_SAW0_BASE		IOMEM(0xFA008000)	/*  4K	*/
+#define MSM_SAW1_BASE		IOMEM(0xFA009000)	/*  4K	*/
+#define MSM_IMEM_BASE		IOMEM(0xFA00A000)	/*  4K	*/
+#define MSM_ACC0_BASE		IOMEM(0xFA00B000)	/*  4K	*/
+#define MSM_ACC1_BASE		IOMEM(0xFA00C000)	/*  4K	*/
+#define MSM_ACC2_BASE		IOMEM(0xFA00D000)	/*  4K	*/
+#define MSM_ACC3_BASE		IOMEM(0xFA00E000)	/*  4K	*/
+#define MSM_CLK_CTL_BASE	IOMEM(0xFA010000)	/* 16K	*/
+#define MSM_MMSS_CLK_CTL_BASE	IOMEM(0xFA014000)	/*  4K	*/
+#define MSM_LPASS_CLK_CTL_BASE	IOMEM(0xFA015000)	/*  4K	*/
+#define MSM_HFPLL_BASE		IOMEM(0xFA016000)	/*  4K	*/
+#define MSM_TLMM_BASE		IOMEM(0xFA017000)	/* 16K	*/
+#define MSM_SHARED_RAM_BASE	IOMEM(0xFA300000)	/*  2M  */
+#define MSM_SIC_NON_SECURE_BASE	IOMEM(0xFA600000)	/* 64K	*/
+#define MSM_HDMI_BASE		IOMEM(0xFA800000)	/*  4K  */
+#define MSM_RPM_BASE		IOMEM(0xFA801000)	/*  4K	*/
+#define MSM_RPM_MPM_BASE	IOMEM(0xFA802000)	/*  4K	*/
+#define MSM_QFPROM_BASE		IOMEM(0xFA700000)	/*  4K  */
+#define MSM_L2CC_BASE		IOMEM(0xFA701000)	/*  4K  */
+#define MSM_APCS_GLB_BASE	IOMEM(0xFA702000)	/*  4K  */
+#define MSM_SAW2_BASE		IOMEM(0xFA703000)	/*  4k  */
+#define MSM_SAW3_BASE		IOMEM(0xFA704000)	/*  4k  */
+#define MSM_VIC_BASE		IOMEM(0xFA100000)	/*  4K */
+#define MSM_CSR_BASE		IOMEM(0xFA101000)	/*  4K */
+#define MSM_GPIO1_BASE		IOMEM(0xFA102000)	/*  4K */
+#define MSM_GPIO2_BASE		IOMEM(0xFA103000)	/*  4K */
+#define MSM_SCU_BASE		IOMEM(0xFA104000)	/*  4K */
+#define MSM_CFG_CTL_BASE	IOMEM(0xFA105000)	/*  4K */
+#define MSM_CLK_CTL_SH2_BASE	IOMEM(0xFA106000)	/*  4K */
+#define MSM_MDC_BASE		IOMEM(0xFA400000)	/*  1M */
+#define MSM_AD5_BASE		IOMEM(0xFA900000)	/*  13M (D00000)
+							  0xFB600000 */
+
+#define MSM_STRONGLY_ORDERED_PAGE	0xFA0F0000
+#define MSM8625_SECONDARY_PHYS		0x0FE00000
+
+
+#if defined(CONFIG_ARCH_MSM9615) || defined(CONFIG_ARCH_MSM7X27) \
+	|| defined(CONFIG_ARCH_MSM7X30)
+#define MSM_SHARED_RAM_SIZE	SZ_1M
+#else
+#define MSM_SHARED_RAM_SIZE	SZ_2M
+#endif
+
+#include "msm_iomap-7xxx.h"
 #include "msm_iomap-7x30.h"
-#elif defined(CONFIG_ARCH_QSD8X50)
+#include "msm_iomap-8625.h"
+#include "msm_iomap-8960.h"
+#include "msm_iomap-8930.h"
+#include "msm_iomap-8064.h"
+#include "msm_iomap-9615.h"
+#include "msm_iomap-copper.h"
+#include "msm_iomap-9625.h"
+
+#else
+/* Legacy single-target iomap */
+#if defined(CONFIG_ARCH_QSD8X50)
 #include "msm_iomap-8x50.h"
 #elif defined(CONFIG_ARCH_MSM8X60)
 #include "msm_iomap-8x60.h"
+#elif defined(CONFIG_ARCH_FSM9XXX)
+#include "msm_iomap-fsm9xxx.h"
 #else
-#include "msm_iomap-7x00.h"
+#error "Target compiled without IO map\n"
 #endif
 
-#include "msm_iomap-8960.h"
-
-#define MSM_DEBUG_UART_SIZE	SZ_4K
-#if defined(CONFIG_DEBUG_MSM_UART1)
-#define MSM_DEBUG_UART_BASE	0xE1000000
-#define MSM_DEBUG_UART_PHYS	MSM_UART1_PHYS
-#elif defined(CONFIG_DEBUG_MSM_UART2)
-#define MSM_DEBUG_UART_BASE	0xE1000000
-#define MSM_DEBUG_UART_PHYS	MSM_UART2_PHYS
-#elif defined(CONFIG_DEBUG_MSM_UART3)
-#define MSM_DEBUG_UART_BASE	0xE1000000
-#define MSM_DEBUG_UART_PHYS	MSM_UART3_PHYS
 #endif
 
-/* Virtual addresses shared across all MSM targets. */
-#define MSM_CSR_BASE		IOMEM(0xE0001000)
-#define MSM_QGIC_DIST_BASE	IOMEM(0xF0000000)
-#define MSM_QGIC_CPU_BASE	IOMEM(0xF0001000)
-#define MSM_TMR_BASE		IOMEM(0xF0200000)
-#define MSM_TMR0_BASE		IOMEM(0xF0201000)
-#define MSM_GPIO1_BASE		IOMEM(0xE0003000)
-#define MSM_GPIO2_BASE		IOMEM(0xE0004000)
-
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_ipc_logging.h b/arch/arm/mach-msm/include/mach/msm_ipc_logging.h
new file mode 100644
index 0000000..0a203a5
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_ipc_logging.h
@@ -0,0 +1,235 @@
+/* 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 _MSM_IPC_LOGGING_H
+#define _MSM_IPC_LOGGING_H
+
+#include <linux/types.h>
+
+#define MAX_MSG_SIZE 255
+
+enum {
+	TSV_TYPE_MSG_START = 1,
+	TSV_TYPE_SKB = TSV_TYPE_MSG_START,
+	TSV_TYPE_STRING,
+	TSV_TYPE_MSG_END = TSV_TYPE_STRING,
+};
+
+struct tsv_header {
+	unsigned char type;
+	unsigned char size; /* size of data field */
+};
+
+struct encode_context {
+	struct tsv_header hdr;
+	char buff[MAX_MSG_SIZE];
+	int offset;
+};
+
+struct decode_context {
+	int output_format;      /* 0 = debugfs */
+	char *buff;             /* output buffer */
+	int size;               /* size of output buffer */
+};
+
+#if defined(CONFIG_MSM_IPC_LOGGING)
+/*
+ * ipc_log_context_create: Create a debug log context
+ *                         Should not be called from atomic context
+ *
+ * @max_num_pages: Number of pages of logging space required (max. 10)
+ * @mod_name     : Name of the directory entry under DEBUGFS
+ *
+ * returns context id on success, NULL on failure
+ */
+void *ipc_log_context_create(int max_num_pages, const char *modname);
+
+/*
+ * msg_encode_start: Start encoding a log message
+ *
+ * @ectxt: Temporary storage to hold the encoded message
+ * @type:  Root event type defined by the module which is logging
+ */
+void msg_encode_start(struct encode_context *ectxt, uint32_t type);
+
+/*
+ * tsv_timestamp_write: Writes the current timestamp count
+ *
+ * @ectxt: Context initialized by calling msg_encode_start()
+ */
+int tsv_timestamp_write(struct encode_context *ectxt);
+
+/*
+ * tsv_pointer_write: Writes a data pointer
+ *
+ * @ectxt:   Context initialized by calling msg_encode_start()
+ * @pointer: Pointer value to write
+ */
+int tsv_pointer_write(struct encode_context *ectxt, void *pointer);
+
+/*
+ * tsv_int32_write: Writes a 32-bit integer value
+ *
+ * @ectxt: Context initialized by calling msg_encode_start()
+ * @n:     Integer to write
+ */
+int tsv_int32_write(struct encode_context *ectxt, int32_t n);
+
+/*
+ * tsv_int32_write: Writes a 32-bit integer value
+ *
+ * @ectxt: Context initialized by calling msg_encode_start()
+ * @n:     Integer to write
+ */
+int tsv_byte_array_write(struct encode_context *ectxt,
+			 void *data, int data_size);
+
+/*
+ * msg_encode_end: Complete the message encode process
+ *
+ * @ectxt: Temporary storage which holds the encoded message
+ */
+void msg_encode_end(struct encode_context *ectxt);
+
+/*
+ * msg_encode_end: Complete the message encode process
+ *
+ * @ectxt: Temporary storage which holds the encoded message
+ */
+void ipc_log_write(void *ctxt, struct encode_context *ectxt);
+
+/*
+ * ipc_log_string: Helper function to log a string
+ *
+ * @ilctxt: Debug Log Context created using ipc_log_context_create()
+ * @fmt:    Data specified using format specifiers
+ */
+int ipc_log_string(void *ilctxt, const char *fmt, ...);
+
+/*
+ * Print a string to decode context.
+ * @dctxt   Decode context
+ * @args   printf args
+ */
+#define IPC_SPRINTF_DECODE(dctxt, args...) \
+do { \
+	int i; \
+	i = scnprintf(dctxt->buff, dctxt->size, args); \
+	dctxt->buff += i; \
+	dctxt->size -= i; \
+} while (0)
+
+/*
+ * tsv_timestamp_read: Reads a timestamp
+ *
+ * @ectxt:  Context retrieved by reading from log space
+ * @dctxt:  Temporary storage to hold the decoded message
+ * @format: Output format while dumping through DEBUGFS
+ */
+void tsv_timestamp_read(struct encode_context *ectxt,
+			struct decode_context *dctxt, const char *format);
+
+/*
+ * tsv_pointer_read: Reads a data pointer
+ *
+ * @ectxt:  Context retrieved by reading from log space
+ * @dctxt:  Temporary storage to hold the decoded message
+ * @format: Output format while dumping through DEBUGFS
+ */
+void tsv_pointer_read(struct encode_context *ectxt,
+		      struct decode_context *dctxt, const char *format);
+
+/*
+ * tsv_int32_read: Reads a 32-bit integer value
+ *
+ * @ectxt:  Context retrieved by reading from log space
+ * @dctxt:  Temporary storage to hold the decoded message
+ * @format: Output format while dumping through DEBUGFS
+ */
+int32_t tsv_int32_read(struct encode_context *ectxt,
+		       struct decode_context *dctxt, const char *format);
+
+/*
+ * tsv_int32_read: Reads a 32-bit integer value
+ *
+ * @ectxt:  Context retrieved by reading from log space
+ * @dctxt:  Temporary storage to hold the decoded message
+ * @format: Output format while dumping through DEBUGFS
+ */
+void tsv_byte_array_read(struct encode_context *ectxt,
+			 struct decode_context *dctxt, const char *format);
+
+/*
+ * add_deserialization_func: Register a deserialization function to
+ *                           to unpack the subevents of a main event
+ *
+ * @ctxt: Debug log context to which the deserialization function has
+ *        to be registered
+ * @type: Main/Root event, defined by the module which is logging, to
+ *        which this deserialization function has to be registered.
+ * @dfune: Deserialization function to be registered
+ *
+ * return 0 on success, -ve value on FAILURE
+ */
+int add_deserialization_func(void *ctxt, int type,
+			void (*dfunc)(struct encode_context *,
+				      struct decode_context *));
+#else
+
+void *ipc_log_context_create(int max_num_pages, const char *modname)
+{ return NULL; }
+
+void msg_encode_start(struct encode_context *ectxt, uint32_t type) { }
+
+int tsv_timestamp_write(struct encode_context *ectxt)
+{ return -EINVAL; }
+
+int tsv_pointer_write(struct encode_context *ectxt, void *pointer)
+{ return -EINVAL; }
+
+int tsv_int32_write(struct encode_context *ectxt, int32_t n)
+{ return -EINVAL; }
+
+int tsv_byte_array_write(struct encode_context *ectxt,
+			 void *data, int data_size)
+{ return -EINVAL; }
+
+void msg_encode_end(struct encode_context *ectxt) { }
+
+void ipc_log_write(void *ctxt, struct encode_context *ectxt) { }
+
+int ipc_log_string(void *ilctxt, const char *fmt, ...)
+{ return -EINVAL; }
+
+#define IPC_SPRINTF_DECODE(dctxt, args...) do { } while (0)
+
+void tsv_timestamp_read(struct encode_context *ectxt,
+			struct decode_context *dctxt, const char *format) { }
+
+void tsv_pointer_read(struct encode_context *ectxt,
+		      struct decode_context *dctxt, const char *format) { }
+
+int32_t tsv_int32_read(struct encode_context *ectxt,
+		       struct decode_context *dctxt, const char *format)
+{ return 0; }
+
+void tsv_byte_array_read(struct encode_context *ectxt,
+			 struct decode_context *dctxt, const char *format) { }
+
+int add_deserialization_func(void *ctxt, int type,
+			void (*dfunc)(struct encode_context *,
+				      struct decode_context *))
+{ return 0; }
+
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_memtypes.h b/arch/arm/mach-msm/include/mach/msm_memtypes.h
new file mode 100644
index 0000000..7afb38d
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_memtypes.h
@@ -0,0 +1,70 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+*/
+
+/* The MSM Hardware supports multiple flavors of physical memory.
+ * This file captures hardware specific information of these types.
+*/
+
+#ifndef __ASM_ARCH_MSM_MEMTYPES_H
+#define __ASM_ARCH_MSM_MEMTYPES_H
+
+#include <mach/memory.h>
+#include <linux/init.h>
+
+int __init meminfo_init(unsigned int, unsigned int);
+/* Redundant check to prevent this from being included outside of 7x30 */
+#if defined(CONFIG_ARCH_MSM7X30)
+unsigned int get_num_populated_chipselects(void);
+#endif
+
+unsigned int get_num_memory_banks(void);
+unsigned int get_memory_bank_size(unsigned int);
+unsigned int get_memory_bank_start(unsigned int);
+int soc_change_memory_power(u64, u64, int);
+
+enum {
+	MEMTYPE_NONE = -1,
+	MEMTYPE_SMI_KERNEL = 0,
+	MEMTYPE_SMI,
+	MEMTYPE_EBI0,
+	MEMTYPE_EBI1,
+	MEMTYPE_MAX,
+};
+
+void msm_reserve(void);
+
+#define MEMTYPE_FLAGS_FIXED	0x1
+#define MEMTYPE_FLAGS_1M_ALIGN	0x2
+
+struct memtype_reserve {
+	unsigned long start;
+	unsigned long size;
+	unsigned long limit;
+	int flags;
+};
+
+struct reserve_info {
+	struct memtype_reserve *memtype_reserve_table;
+	void (*calculate_reserve_sizes)(void);
+	void (*reserve_fixed_area)(unsigned long);
+	int (*paddr_to_memtype)(unsigned int);
+	unsigned long low_unstable_address;
+	unsigned long max_unstable_size;
+	unsigned long bank_size;
+	unsigned long fixed_area_start;
+	unsigned long fixed_area_size;
+};
+
+extern struct reserve_info *reserve_info;
+
+unsigned long __init reserve_memory_for_fmem(unsigned long, unsigned long);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_migrate_pages.h b/arch/arm/mach-msm/include/mach/msm_migrate_pages.h
new file mode 100644
index 0000000..5812a64
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_migrate_pages.h
@@ -0,0 +1,17 @@
+/* Copyright (c) 2010, 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 _MACH_MSM_MIGRATE_PAGES_H_
+#define _MACH_MSM_MIGRATE_PAGES_H_
+
+unsigned long get_msm_migrate_pages_status(void);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_otg.h b/arch/arm/mach-msm/include/mach/msm_otg.h
new file mode 100644
index 0000000..178b65a
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_otg.h
@@ -0,0 +1,78 @@
+/* Copyright (c) 2009, Code Aurora Forum. 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 __ARCH_ARM_MACH_MSM_OTG_H
+#define __ARCH_ARM_MACH_MSM_OTG_H
+
+#include <linux/workqueue.h>
+#include <linux/wakelock.h>
+
+/*
+ * The otg driver needs to interact with both device side and host side
+ * usb controllers.  it decides which controller is active at a given
+ * moment, using the transceiver, ID signal.
+ */
+
+struct msm_otg_transceiver {
+	struct device		*dev;
+	struct clk		*clk;
+	struct clk		*pclk;
+	int			in_lpm;
+	struct msm_otg_ops	*dcd_ops;
+	struct msm_otg_ops	*hcd_ops;
+	int			irq;
+	int			flags;
+	int			state;
+	int			active;
+	void __iomem		*regs;		/* device memory/io */
+	struct work_struct	work;
+	spinlock_t		lock;
+	struct wake_lock	wlock;
+
+	/* bind/unbind the host controller */
+	int	(*set_host)(struct msm_otg_transceiver *otg,
+				struct msm_otg_ops *hcd_ops);
+
+	/* bind/unbind the peripheral controller */
+	int	(*set_peripheral)(struct msm_otg_transceiver *otg,
+				struct msm_otg_ops *dcd_ops);
+	int	(*set_suspend)(struct msm_otg_transceiver *otg,
+				int suspend);
+
+};
+
+struct msm_otg_ops {
+	void		(*request)(void *, int);
+	void		*handle;
+};
+
+/* for usb host and peripheral controller drivers */
+#ifdef CONFIG_USB_MSM_OTG
+
+extern struct msm_otg_transceiver *msm_otg_get_transceiver(void);
+extern void msm_otg_put_transceiver(struct msm_otg_transceiver *xceiv);
+
+#else
+
+static inline struct msm_otg_transceiver *msm_otg_get_transceiver(void)
+{
+	return NULL;
+}
+
+static inline void msm_otg_put_transceiver(struct msm_otg_transceiver *xceiv)
+{
+}
+
+#endif /*CONFIG_USB_MSM_OTG*/
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_pcie.h b/arch/arm/mach-msm/include/mach/msm_pcie.h
new file mode 100644
index 0000000..008c984
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_pcie.h
@@ -0,0 +1,37 @@
+/* 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 __ASM_ARCH_MSM_PCIE_H
+#define __ASM_ARCH_MSM_PCIE_H
+
+#include <linux/types.h>
+
+/* gpios */
+enum msm_pcie_gpio {
+	MSM_PCIE_GPIO_RST_N,
+	MSM_PCIE_GPIO_PWR_EN,
+	MSM_PCIE_MAX_GPIO
+};
+
+/* gpio info structrue */
+struct msm_pcie_gpio_info_t {
+	char      *name;
+	uint32_t   num;
+	uint32_t   on;
+};
+
+/* msm pcie platfrom data */
+struct msm_pcie_platform {
+	struct msm_pcie_gpio_info_t  *gpio;
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_qdsp6_audio.h b/arch/arm/mach-msm/include/mach/msm_qdsp6_audio.h
new file mode 100644
index 0000000..da2abe2
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_qdsp6_audio.h
@@ -0,0 +1,120 @@
+/* arch/arm/mach-msm/include/mach/msm_qdsp6_audio.h
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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 _MACH_MSM_QDSP6_Q6AUDIO_
+#define _MACH_MSM_QDSP6_Q6AUDIO_
+
+#define AUDIO_FLAG_READ		0
+#define AUDIO_FLAG_WRITE	1
+#define AUDIO_FLAG_INCALL_MIXED	2
+
+#include <linux/wait.h>
+
+enum {
+	DEVICE_UNMUTE = 0,
+	DEVICE_MUTE,
+	STREAM_UNMUTE,
+	STREAM_MUTE,
+};
+
+struct audio_buffer {
+	dma_addr_t phys;
+	void *data;
+	uint32_t size;
+	uint32_t used;	/* 1 = CPU is waiting for DSP to consume this buf */
+	uint32_t actual_size; /* actual number of bytes read by DSP */
+};
+
+struct audio_client {
+	struct audio_buffer buf[2];
+	int cpu_buf;	/* next buffer the CPU will touch */
+	int dsp_buf;	/* next buffer the DSP will touch */
+	int running;
+	int session;
+
+	wait_queue_head_t wait;
+	struct dal_client *client;
+
+	int cb_status;
+	uint32_t flags;
+};
+
+/* Obtain a 16bit signed, interleaved audio channel of the specified
+ * rate (Hz) and channels (1 or 2), with two buffers of bufsz bytes.
+ */
+struct audio_client *q6audio_open_pcm(uint32_t bufsz, uint32_t rate,
+				      uint32_t channels, uint32_t flags,
+				      uint32_t acdb_id);
+
+struct audio_client *q6audio_open_auxpcm(uint32_t rate, uint32_t channels,
+					uint32_t flags, uint32_t acdb_id);
+
+struct audio_client *q6voice_open(uint32_t flags);
+
+struct audio_client *q6audio_open_mp3(uint32_t bufsz, uint32_t rate,
+				      uint32_t channels, uint32_t acdb_id);
+
+struct audio_client *q6audio_open_dtmf(uint32_t rate, uint32_t channels,
+							uint32_t acdb_id);
+int q6audio_play_dtmf(struct audio_client *ac, uint16_t dtmf_hi,
+			uint16_t dtmf_low, uint16_t duration, uint16_t rx_gain);
+
+struct audio_client *q6audio_open_aac(uint32_t bufsz, uint32_t samplerate,
+					uint32_t channels, uint32_t bitrate,
+					uint32_t stream_format, uint32_t flags,
+					uint32_t acdb_id);
+
+struct audio_client *q6audio_open_qcp(uint32_t bufsz, uint32_t min_rate,
+					uint32_t max_rate, uint32_t flags,
+					uint32_t format, uint32_t acdb_id);
+
+struct audio_client *q6audio_open_amrnb(uint32_t bufsz, uint32_t enc_mode,
+					uint32_t dtx_enable, uint32_t flags,
+					uint32_t acdb_id);
+
+int q6audio_close(struct audio_client *ac);
+int q6audio_auxpcm_close(struct audio_client *ac);
+int q6voice_close(struct audio_client *ac);
+int q6audio_mp3_close(struct audio_client *ac);
+
+int q6audio_read(struct audio_client *ac, struct audio_buffer *ab);
+int q6audio_write(struct audio_client *ac, struct audio_buffer *ab);
+int q6audio_async(struct audio_client *ac);
+
+int q6audio_do_routing(uint32_t route, uint32_t acdb_id);
+int q6audio_set_tx_mute(int mute);
+int q6audio_reinit_acdb(char* filename);
+int q6audio_update_acdb(uint32_t id_src, uint32_t id_dst);
+int q6audio_set_rx_volume(int level);
+int q6audio_set_stream_volume(struct audio_client *ac, int vol);
+int q6audio_set_stream_eq_pcm(struct audio_client *ac, void *eq_config);
+
+struct q6audio_analog_ops {
+	void (*init)(void);
+	void (*speaker_enable)(int en);
+	void (*headset_enable)(int en);
+	void (*receiver_enable)(int en);
+	void (*bt_sco_enable)(int en);
+	void (*int_mic_enable)(int en);
+	void (*ext_mic_enable)(int en);
+};
+
+void q6audio_register_analog_ops(struct q6audio_analog_ops *ops);
+
+/* signal non-recoverable DSP error so we can log and/or panic */
+void q6audio_dsp_not_responding(void);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_qdsp6_audiov2.h b/arch/arm/mach-msm/include/mach/msm_qdsp6_audiov2.h
new file mode 100644
index 0000000..90a6b56
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_qdsp6_audiov2.h
@@ -0,0 +1,87 @@
+/* arch/arm/mach-msm/include/mach/msm_qdsp6_audio.h
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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 _MACH_MSM_QDSP6_Q6AUDIO_
+#define _MACH_MSM_QDSP6_Q6AUDIO_
+
+#define AUDIO_FLAG_READ		0
+#define AUDIO_FLAG_WRITE	1
+
+extern char *audio_data;
+extern int32_t audio_phys;
+extern uint32_t tx_clk_freq;
+
+struct audio_buffer {
+	dma_addr_t phys;
+	void *data;
+	uint32_t size;
+	uint32_t used;	/* 1 = CPU is waiting for DSP to consume this buf */
+	uint32_t actual_size; /* actual number of bytes read by DSP */
+};
+
+struct audio_client {
+	struct audio_buffer buf[2];
+	int cpu_buf;	/* next buffer the CPU will touch */
+	int dsp_buf;	/* next buffer the DSP will touch */
+	int running;
+	int session;
+
+	wait_queue_head_t wait;
+	struct dal_client *client;
+
+	int cb_status;
+	uint32_t flags;
+};
+
+/* Obtain a 16bit signed, interleaved audio channel of the specified
+ * rate (Hz) and channels (1 or 2), with two buffers of bufsz bytes.
+ */
+
+struct audio_client *q6voice_open(void);
+int q6voice_setup(void);
+int q6voice_teardown(void);
+int q6voice_close(struct audio_client *ac);
+
+
+struct audio_client *q6audio_open(uint32_t bufsz, uint32_t flags);
+int q6audio_start(struct audio_client *ac, void *rpc, uint32_t len);
+
+int q6audio_close(struct audio_client *ac);
+int q6audio_read(struct audio_client *ac, struct audio_buffer *ab);
+int q6audio_write(struct audio_client *ac, struct audio_buffer *ab);
+int q6audio_async(struct audio_client *ac);
+
+int q6audio_do_routing(uint32_t route);
+int q6audio_set_tx_mute(int mute);
+int q6audio_update_acdb(uint32_t id_src, uint32_t id_dst);
+int q6audio_set_rx_volume(int level);
+int q6audio_set_route(const char *name);
+
+struct q6audio_analog_ops {
+	void (*init)(void);
+	void (*speaker_enable)(int en);
+	void (*headset_enable)(int en);
+	void (*receiver_enable)(int en);
+	void (*bt_sco_enable)(int en);
+	void (*int_mic_enable)(int en);
+	void (*ext_mic_enable)(int en);
+};
+
+void q6audio_register_analog_ops(struct q6audio_analog_ops *ops);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_rotator_imem.h b/arch/arm/mach-msm/include/mach/msm_rotator_imem.h
new file mode 100644
index 0000000..580bc81
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_rotator_imem.h
@@ -0,0 +1,28 @@
+/* Copyright (c) 2009, 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 __MSM_ROTATOR_IMEM_H__
+
+enum {
+	ROTATOR_REQUEST,
+	JPEG_REQUEST
+};
+
+/* Allocates imem for the requested owner.
+   Aquires a mutex, so DO NOT call from isr context */
+int msm_rotator_imem_allocate(int requestor);
+/* Frees imem if currently owned by requestor.
+   Unlocks a mutex, so DO NOT call from isr context */
+void msm_rotator_imem_free(int requestor);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_rpcrouter.h b/arch/arm/mach-msm/include/mach/msm_rpcrouter.h
new file mode 100644
index 0000000..28841a9
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_rpcrouter.h
@@ -0,0 +1,376 @@
+/** include/asm-arm/arch-msm/msm_rpcrouter.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2011, Code Aurora Forum. All rights reserved.
+ * Author: San Mehat <san@android.com>
+ *
+ * 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_RPCROUTER_H
+#define __ASM__ARCH_MSM_RPCROUTER_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+
+/* RPC API version structure
+ * Version bit 31 : 1->hashkey versioning,
+ *                  0->major-minor (backward compatible) versioning
+ * hashkey versioning:
+ *   Version bits 31-0 hashkey
+ * major-minor (backward compatible) versioning
+ *   Version bits 30-28 reserved (no match)
+ *   Version bits 27-16 major (must match)
+ *   Version bits 15-0  minor (greater or equal)
+ */
+#define RPC_VERSION_MODE_MASK  0x80000000
+#define RPC_VERSION_MAJOR_MASK 0x0fff0000
+#define RPC_VERSION_MINOR_MASK 0x0000ffff
+
+/* callback ID for NULL callback function is -1 */
+#define MSM_RPC_CLIENT_NULL_CB_ID 0xffffffff
+
+struct msm_rpc_endpoint;
+
+struct rpcsvr_platform_device
+{
+	struct platform_device base;
+	uint32_t prog;
+	uint32_t vers;
+};
+
+#define RPC_DATA_IN	0
+/*
+ * Structures for sending / receiving direct RPC requests
+ * XXX: Any cred/verif lengths > 0 not supported
+ */
+
+struct rpc_request_hdr
+{
+	uint32_t xid;
+	uint32_t type;	/* 0 */
+	uint32_t rpc_vers; /* 2 */
+	uint32_t prog;
+	uint32_t vers;
+	uint32_t procedure;
+	uint32_t cred_flavor;
+	uint32_t cred_length;
+	uint32_t verf_flavor;
+	uint32_t verf_length;
+};
+
+typedef struct
+{
+	uint32_t low;
+	uint32_t high;
+} rpc_reply_progmismatch_data;
+
+typedef struct
+{
+} rpc_denied_reply_hdr;
+
+typedef struct
+{
+	uint32_t verf_flavor;
+	uint32_t verf_length;
+	uint32_t accept_stat;
+#define RPC_ACCEPTSTAT_SUCCESS 0
+#define RPC_ACCEPTSTAT_PROG_UNAVAIL 1
+#define RPC_ACCEPTSTAT_PROG_MISMATCH 2
+#define RPC_ACCEPTSTAT_PROC_UNAVAIL 3
+#define RPC_ACCEPTSTAT_GARBAGE_ARGS 4
+#define RPC_ACCEPTSTAT_SYSTEM_ERR 5
+#define RPC_ACCEPTSTAT_PROG_LOCKED 6
+	/*
+	 * Following data is dependant on accept_stat
+	 * If ACCEPTSTAT == PROG_MISMATCH then there is a
+	 * 'rpc_reply_progmismatch_data' structure following the header.
+	 * Otherwise the data is procedure specific
+	 */
+} rpc_accepted_reply_hdr;
+
+struct rpc_reply_hdr
+{
+	uint32_t xid;
+	uint32_t type;
+	uint32_t reply_stat;
+#define RPCMSG_REPLYSTAT_ACCEPTED 0
+#define RPCMSG_REPLYSTAT_DENIED 1
+	union {
+		rpc_accepted_reply_hdr acc_hdr;
+		rpc_denied_reply_hdr dny_hdr;
+	} data;
+};
+
+struct rpc_board_dev {
+	uint32_t prog;
+	struct platform_device pdev;
+};
+
+/* flags for msm_rpc_connect() */
+#define MSM_RPC_UNINTERRUPTIBLE 0x0001
+
+/* use IS_ERR() to check for failure */
+struct msm_rpc_endpoint *msm_rpc_open(void);
+/* Connect with the specified server version */
+struct msm_rpc_endpoint *msm_rpc_connect(uint32_t prog, uint32_t vers, unsigned flags);
+/* Connect with a compatible server version */
+struct msm_rpc_endpoint *msm_rpc_connect_compatible(uint32_t prog,
+	uint32_t vers, unsigned flags);
+/* check if server version can handle client requested version */
+int msm_rpc_is_compatible_version(uint32_t server_version,
+				  uint32_t client_version);
+
+int msm_rpc_close(struct msm_rpc_endpoint *ept);
+int msm_rpc_write(struct msm_rpc_endpoint *ept,
+		  void *data, int len);
+int msm_rpc_read(struct msm_rpc_endpoint *ept,
+		 void **data, unsigned len, long timeout);
+void msm_rpc_read_wakeup(struct msm_rpc_endpoint *ept);
+void msm_rpc_setup_req(struct rpc_request_hdr *hdr,
+		       uint32_t prog, uint32_t vers, uint32_t proc);
+int msm_rpc_register_server(struct msm_rpc_endpoint *ept,
+			    uint32_t prog, uint32_t vers);
+int msm_rpc_unregister_server(struct msm_rpc_endpoint *ept,
+			      uint32_t prog, uint32_t vers);
+
+int msm_rpc_add_board_dev(struct rpc_board_dev *board_dev, int num);
+
+int msm_rpc_clear_netreset(struct msm_rpc_endpoint *ept);
+
+int msm_rpc_get_curr_pkt_size(struct msm_rpc_endpoint *ept);
+/* simple blocking rpc call
+ *
+ * request is mandatory and must have a rpc_request_hdr
+ * at the start.  The header will be filled out for you.
+ *
+ * reply provides a buffer for replies of reply_max_size
+ */
+int msm_rpc_call_reply(struct msm_rpc_endpoint *ept, uint32_t proc,
+		       void *request, int request_size,
+		       void *reply, int reply_max_size,
+		       long timeout);
+int msm_rpc_call(struct msm_rpc_endpoint *ept, uint32_t proc,
+		 void *request, int request_size,
+		 long timeout);
+
+struct msm_rpc_xdr {
+	void *in_buf;
+	uint32_t in_size;
+	uint32_t in_index;
+	wait_queue_head_t in_buf_wait_q;
+
+	void *out_buf;
+	uint32_t out_size;
+	uint32_t out_index;
+	struct mutex out_lock;
+
+	struct msm_rpc_endpoint *ept;
+};
+
+int xdr_send_int8(struct msm_rpc_xdr *xdr, const int8_t *value);
+int xdr_send_uint8(struct msm_rpc_xdr *xdr, const uint8_t *value);
+int xdr_send_int16(struct msm_rpc_xdr *xdr, const int16_t *value);
+int xdr_send_uint16(struct msm_rpc_xdr *xdr, const uint16_t *value);
+int xdr_send_int32(struct msm_rpc_xdr *xdr, const int32_t *value);
+int xdr_send_uint32(struct msm_rpc_xdr *xdr, const uint32_t *value);
+int xdr_send_bytes(struct msm_rpc_xdr *xdr, const void **data, uint32_t *size);
+
+int xdr_recv_int8(struct msm_rpc_xdr *xdr, int8_t *value);
+int xdr_recv_uint8(struct msm_rpc_xdr *xdr, uint8_t *value);
+int xdr_recv_int16(struct msm_rpc_xdr *xdr, int16_t *value);
+int xdr_recv_uint16(struct msm_rpc_xdr *xdr, uint16_t *value);
+int xdr_recv_int32(struct msm_rpc_xdr *xdr, int32_t *value);
+int xdr_recv_uint32(struct msm_rpc_xdr *xdr, uint32_t *value);
+int xdr_recv_bytes(struct msm_rpc_xdr *xdr, void **data, uint32_t *size);
+
+struct msm_rpc_server
+{
+	struct list_head list;
+	uint32_t flags;
+
+	uint32_t prog;
+	uint32_t vers;
+
+	struct mutex cb_req_lock;
+
+	struct msm_rpc_endpoint *cb_ept;
+
+	struct msm_rpc_xdr cb_xdr;
+
+	uint32_t version;
+
+	int (*rpc_call)(struct msm_rpc_server *server,
+			struct rpc_request_hdr *req, unsigned len);
+
+	int (*rpc_call2)(struct msm_rpc_server *server,
+			 struct rpc_request_hdr *req,
+			 struct msm_rpc_xdr *xdr);
+};
+
+int msm_rpc_create_server(struct msm_rpc_server *server);
+int msm_rpc_create_server2(struct msm_rpc_server *server);
+
+#define MSM_RPC_MSGSIZE_MAX 8192
+
+struct msm_rpc_client;
+
+struct msm_rpc_client {
+	struct task_struct *read_thread;
+	struct task_struct *cb_thread;
+
+	struct msm_rpc_endpoint *ept;
+	wait_queue_head_t reply_wait;
+
+	uint32_t prog, ver;
+
+	void *buf;
+
+	struct msm_rpc_xdr xdr;
+	struct msm_rpc_xdr cb_xdr;
+
+	uint32_t version;
+
+	int (*cb_func)(struct msm_rpc_client *, void *, int);
+	int (*cb_func2)(struct msm_rpc_client *, struct rpc_request_hdr *req,
+			struct msm_rpc_xdr *);
+	void *cb_buf;
+	int cb_size;
+
+	struct list_head cb_item_list;
+	struct mutex cb_item_list_lock;
+
+	wait_queue_head_t cb_wait;
+	int cb_avail;
+
+	atomic_t next_cb_id;
+	spinlock_t cb_list_lock;
+	struct list_head cb_list;
+
+	uint32_t exit_flag;
+	struct completion complete;
+	struct completion cb_complete;
+
+	struct mutex req_lock;
+
+	void (*cb_restart_teardown)(struct msm_rpc_client *client);
+	void (*cb_restart_setup)(struct msm_rpc_client *client);
+	int in_reset;
+};
+
+struct msm_rpc_client_info {
+	uint32_t pid;
+	uint32_t cid;
+	uint32_t prog;
+	uint32_t vers;
+};
+
+
+int msm_rpc_client_in_reset(struct msm_rpc_client *client);
+
+struct msm_rpc_client *msm_rpc_register_client(
+	const char *name,
+	uint32_t prog, uint32_t ver,
+	uint32_t create_cb_thread,
+	int (*cb_func)(struct msm_rpc_client *, void *, int));
+
+struct msm_rpc_client *msm_rpc_register_client2(
+	const char *name,
+	uint32_t prog, uint32_t ver,
+	uint32_t create_cb_thread,
+	int (*cb_func)(struct msm_rpc_client *, struct rpc_request_hdr *req,
+		       struct msm_rpc_xdr *xdr));
+
+int msm_rpc_unregister_client(struct msm_rpc_client *client);
+
+int msm_rpc_client_req(struct msm_rpc_client *client, uint32_t proc,
+		       int (*arg_func)(struct msm_rpc_client *,
+				       void *, void *), void *arg_data,
+		       int (*result_func)(struct msm_rpc_client *,
+					  void *, void *), void *result_data,
+		       long timeout);
+
+int msm_rpc_client_req2(struct msm_rpc_client *client, uint32_t proc,
+			int (*arg_func)(struct msm_rpc_client *,
+					struct msm_rpc_xdr *, void *),
+			void *arg_data,
+			int (*result_func)(struct msm_rpc_client *,
+					   struct msm_rpc_xdr *, void *),
+			void *result_data,
+			long timeout);
+
+int msm_rpc_register_reset_callbacks(
+	struct msm_rpc_client *client,
+	void (*teardown)(struct msm_rpc_client *client),
+	void (*setup)(struct msm_rpc_client *client)
+	);
+
+void *msm_rpc_start_accepted_reply(struct msm_rpc_client *client,
+				   uint32_t xid, uint32_t accept_status);
+
+int msm_rpc_send_accepted_reply(struct msm_rpc_client *client, uint32_t size);
+
+void *msm_rpc_server_start_accepted_reply(struct msm_rpc_server *server,
+					  uint32_t xid, uint32_t accept_status);
+
+int msm_rpc_server_send_accepted_reply(struct msm_rpc_server *server,
+				       uint32_t size);
+
+int msm_rpc_add_cb_func(struct msm_rpc_client *client, void *cb_func);
+
+void *msm_rpc_get_cb_func(struct msm_rpc_client *client, uint32_t cb_id);
+
+void msm_rpc_remove_cb_func(struct msm_rpc_client *client, void *cb_func);
+
+int msm_rpc_server_cb_req(struct msm_rpc_server *server,
+			  struct msm_rpc_client_info *clnt_info,
+			  uint32_t cb_proc,
+			  int (*arg_func)(struct msm_rpc_server *server,
+					  void *buf, void *data),
+			  void *arg_data,
+			  int (*ret_func)(struct msm_rpc_server *server,
+					  void *buf, void *data),
+			  void *ret_data, long timeout);
+
+int msm_rpc_server_cb_req2(struct msm_rpc_server *server,
+			   struct msm_rpc_client_info *clnt_info,
+			   uint32_t cb_proc,
+			   int (*arg_func)(struct msm_rpc_server *server,
+					   struct msm_rpc_xdr *xdr, void *data),
+			   void *arg_data,
+			   int (*ret_func)(struct msm_rpc_server *server,
+					   struct msm_rpc_xdr *xdr, void *data),
+			   void *ret_data, long timeout);
+
+void msm_rpc_server_get_requesting_client(
+	struct msm_rpc_client_info *clnt_info);
+
+int xdr_send_pointer(struct msm_rpc_xdr *xdr, void **obj,
+		     uint32_t obj_size, void *xdr_op);
+
+int xdr_recv_pointer(struct msm_rpc_xdr *xdr, void **obj,
+		     uint32_t obj_size, void *xdr_op);
+
+int xdr_send_array(struct msm_rpc_xdr *xdr, void **addr, uint32_t *size,
+		   uint32_t maxsize, uint32_t elm_size, void *xdr_op);
+
+int xdr_recv_array(struct msm_rpc_xdr *xdr, void **addr, uint32_t *size,
+		   uint32_t maxsize, uint32_t elm_size, void *xdr_op);
+
+int xdr_recv_req(struct msm_rpc_xdr *xdr, struct rpc_request_hdr *req);
+int xdr_recv_reply(struct msm_rpc_xdr *xdr, struct rpc_reply_hdr *reply);
+int xdr_start_request(struct msm_rpc_xdr *xdr, uint32_t prog,
+		      uint32_t ver, uint32_t proc);
+int xdr_start_accepted_reply(struct msm_rpc_xdr *xdr, uint32_t accept_status);
+int xdr_send_msg(struct msm_rpc_xdr *xdr);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_rtb.h b/arch/arm/mach-msm/include/mach/msm_rtb.h
new file mode 100644
index 0000000..74ddfbd
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_rtb.h
@@ -0,0 +1,81 @@
+/*
+ * 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 __MSM_RTB_H__
+#define __MSM_RTB_H__
+
+/*
+ * These numbers are used from the kernel command line and sysfs
+ * to control filtering. Remove items from here with extreme caution.
+ */
+enum logk_event_type {
+	LOGK_NONE = 0,
+	LOGK_READL = 1,
+	LOGK_WRITEL = 2,
+	LOGK_LOGBUF = 3,
+	LOGK_HOTPLUG = 4,
+	LOGK_CTXID = 5,
+	LOGK_TIMESTAMP = 6,
+};
+
+#define LOGTYPE_NOPC 0x80
+
+struct msm_rtb_platform_data {
+	unsigned int size;
+};
+
+#if defined(CONFIG_MSM_RTB)
+/*
+ * returns 1 if data was logged, 0 otherwise
+ */
+int uncached_logk_pc(enum logk_event_type log_type, void *caller,
+				void *data);
+
+/*
+ * returns 1 if data was logged, 0 otherwise
+ */
+int uncached_logk(enum logk_event_type log_type, void *data);
+
+#define ETB_WAYPOINT  do { \
+				BRANCH_TO_NEXT_ISTR; \
+				nop(); \
+				BRANCH_TO_NEXT_ISTR; \
+				nop(); \
+			} while (0)
+
+#define BRANCH_TO_NEXT_ISTR  asm volatile("b .+4\n" : : : "memory")
+/*
+ * both the mb and the isb are needed to ensure enough waypoints for
+ * etb tracing
+ */
+#define LOG_BARRIER	do { \
+				mb(); \
+				isb();\
+			 } while (0)
+#else
+
+static inline int uncached_logk_pc(enum logk_event_type log_type,
+					void *caller,
+					void *data) { return 0; }
+
+static inline int uncached_logk(enum logk_event_type log_type,
+					void *data) { return 0; }
+
+#define ETB_WAYPOINT
+#define BRANCH_TO_NEXT_ISTR
+/*
+ * Due to a GCC bug, we need to have a nop here in order to prevent an extra
+ * read from being generated after the write.
+ */
+#define LOG_BARRIER		nop()
+#endif
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_serial_debugger.h b/arch/arm/mach-msm/include/mach/msm_serial_debugger.h
new file mode 100644
index 0000000..f490b1b
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_serial_debugger.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2009 Google, Inc.
+ *
+ * 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_SERIAL_DEBUGGER_H
+#define __ASM_ARCH_MSM_SERIAL_DEBUGGER_H
+
+#if defined(CONFIG_MSM_SERIAL_DEBUGGER)
+void msm_serial_debug_init(unsigned int base, int irq,
+		struct device *clk_device, int signal_irq, int wakeup_irq);
+#else
+static inline void msm_serial_debug_init(unsigned int base, int irq,
+		struct device *clk_device, int signal_irq, int wakeup_irq) {}
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_serial_hs.h b/arch/arm/mach-msm/include/mach/msm_serial_hs.h
new file mode 100644
index 0000000..b96640d
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_serial_hs.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Nick Pelly <npelly@google.com>
+ *
+ * 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_SERIAL_HS_H
+#define __ASM_ARCH_MSM_SERIAL_HS_H
+
+#include<linux/serial_core.h>
+
+/* Optional platform device data for msm_serial_hs driver.
+ * Used to configure low power wakeup */
+struct msm_serial_hs_platform_data {
+	int wakeup_irq;  /* wakeup irq */
+	/* bool: inject char into rx tty on wakeup */
+	unsigned char inject_rx_on_wakeup;
+	char rx_to_inject;
+	int (*gpio_config)(int);
+};
+
+unsigned int msm_hs_tx_empty(struct uart_port *uport);
+void msm_hs_request_clock_off(struct uart_port *uport);
+void msm_hs_request_clock_on(struct uart_port *uport);
+void msm_hs_set_mctrl(struct uart_port *uport,
+				    unsigned int mctrl);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_serial_hs_lite.h b/arch/arm/mach-msm/include/mach/msm_serial_hs_lite.h
new file mode 100644
index 0000000..577a097
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_serial_hs_lite.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_SERIAL_HS_LITE_H
+#define __ASM_ARCH_MSM_SERIAL_HS_LITE_H
+
+struct msm_serial_hslite_platform_data {
+	unsigned config_gpio;
+	unsigned uart_tx_gpio;
+	unsigned uart_rx_gpio;
+	int line;
+};
+
+#endif
+
diff --git a/arch/arm/mach-msm/include/mach/msm_serial_hsl_regs.h b/arch/arm/mach-msm/include/mach/msm_serial_hsl_regs.h
new file mode 100644
index 0000000..b465b56
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_serial_hsl_regs.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. 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_SERIAL_HSL_REGS_H
+#define __ASM_ARCH_MSM_SERIAL_HSL_REGS_H
+
+#ifdef CONFIG_MSM_HAS_DEBUG_UART_HS_V14
+#define UARTDM_MR2_OFFSET	0x4
+#define UARTDM_CSR_OFFSET	0xa0
+#define UARTDM_SR_OFFSET	0xa4
+#define UARTDM_CR_OFFSET	0xa8
+#define UARTDM_ISR_OFFSET	0xb4
+#define UARTDM_NCF_TX_OFFSET	0x40
+#define UARTDM_TF_OFFSET	0x100
+#else
+#define UARTDM_MR2_OFFSET	0x4
+#define UARTDM_CSR_OFFSET	0x8
+#define UARTDM_SR_OFFSET	0x8
+#define UARTDM_CR_OFFSET	0x10
+#define UARTDM_ISR_OFFSET	0x14
+#define UARTDM_NCF_TX_OFFSET	0x40
+#define UARTDM_TF_OFFSET	0x70
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_serial_pdata.h b/arch/arm/mach-msm/include/mach/msm_serial_pdata.h
new file mode 100644
index 0000000..4153cb2
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_serial_pdata.h
@@ -0,0 +1,27 @@
+/* Copyright (c) 2010, 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 __ASM_ARCH_MSM_SERIAL_HS_H
+#define __ASM_ARCH_MSM_SERIAL_HS_H
+
+#include <linux/serial_core.h>
+
+/* Optional platform device data for msm_serial driver.
+ * Used to configure low power wakeup */
+struct msm_serial_platform_data {
+	int wakeup_irq;  /* wakeup irq */
+	/* bool: inject char into rx tty on wakeup */
+	unsigned char inject_rx_on_wakeup;
+	char rx_to_inject;
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h
index 029463e..dc633fb 100644
--- a/arch/arm/mach-msm/include/mach/msm_smd.h
+++ b/arch/arm/mach-msm/include/mach/msm_smd.h
@@ -1,6 +1,7 @@
 /* linux/include/asm-arm/arch-msm/msm_smd.h
  *
  * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -17,22 +18,155 @@
 #ifndef __ASM_ARCH_MSM_SMD_H
 #define __ASM_ARCH_MSM_SMD_H
 
+#include <linux/io.h>
+#include <mach/msm_smsm.h>
+
 typedef struct smd_channel smd_channel_t;
 
-extern int (*msm_check_for_modem_crash)(void);
-
-/* warning: notify() may be called before open returns */
-int smd_open(const char *name, smd_channel_t **ch, void *priv,
-	     void (*notify)(void *priv, unsigned event));
+#define SMD_MAX_CH_NAME_LEN 20 /* includes null char at end */
 
 #define SMD_EVENT_DATA 1
 #define SMD_EVENT_OPEN 2
 #define SMD_EVENT_CLOSE 3
+#define SMD_EVENT_STATUS 4
+#define SMD_EVENT_REOPEN_READY 5
+
+/*
+ * SMD Processor ID's.
+ *
+ * For all processors that have both SMSM and SMD clients,
+ * the SMSM Processor ID and the SMD Processor ID will
+ * be the same.  In cases where a processor only supports
+ * SMD, the entry will only exist in this enum.
+ */
+enum {
+	SMD_APPS = SMSM_APPS,
+	SMD_MODEM = SMSM_MODEM,
+	SMD_Q6 = SMSM_Q6,
+	SMD_WCNSS = SMSM_WCNSS,
+	SMD_DSPS = SMSM_DSPS,
+	SMD_MODEM_Q6_FW,
+	SMD_RPM,
+	NUM_SMD_SUBSYSTEMS,
+};
+
+enum {
+	SMD_APPS_MODEM = 0,
+	SMD_APPS_QDSP,
+	SMD_MODEM_QDSP,
+	SMD_APPS_DSPS,
+	SMD_MODEM_DSPS,
+	SMD_QDSP_DSPS,
+	SMD_APPS_WCNSS,
+	SMD_MODEM_WCNSS,
+	SMD_QDSP_WCNSS,
+	SMD_DSPS_WCNSS,
+	SMD_APPS_Q6FW,
+	SMD_MODEM_Q6FW,
+	SMD_QDSP_Q6FW,
+	SMD_DSPS_Q6FW,
+	SMD_WCNSS_Q6FW,
+	SMD_APPS_RPM,
+	SMD_MODEM_RPM,
+	SMD_QDSP_RPM,
+	SMD_WCNSS_RPM,
+	SMD_NUM_TYPE,
+	SMD_LOOPBACK_TYPE = 100,
+
+};
+
+/*
+ * SMD IRQ Configuration
+ *
+ * Used to initialize IRQ configurations from platform data
+ *
+ * @irq_name: irq_name to query platform data
+ * @irq_id: initialized to -1 in platform data, stores actual irq id on
+ *		successful registration
+ * @out_base: if not null then settings used for outgoing interrupt
+ *		initialied from platform data
+ */
+
+struct smd_irq_config {
+	/* incoming interrupt config */
+	const char *irq_name;
+	unsigned long flags;
+	int irq_id;
+	const char *device_name;
+	const void *dev_id;
+
+	/* outgoing interrupt config */
+	uint32_t out_bit_pos;
+	void __iomem *out_base;
+	uint32_t out_offset;
+};
+
+/*
+ * SMD subsystem configurations
+ *
+ * SMD subsystems configurations for platform data. This contains the
+ * M2A and A2M interrupt configurations for both SMD and SMSM per
+ * subsystem.
+ *
+ * @subsys_name: name of subsystem passed to PIL
+ * @irq_config_id: unique id for each subsystem
+ * @edge: maps to actual remote subsystem edge
+ *
+ */
+struct smd_subsystem_config {
+	unsigned irq_config_id;
+	const char *subsys_name;
+	int edge;
+
+	struct smd_irq_config smd_int;
+	struct smd_irq_config smsm_int;
+
+};
+
+/*
+ * Subsystem Restart Configuration
+ *
+ * @disable_smsm_reset_handshake
+ */
+struct smd_subsystem_restart_config {
+	int disable_smsm_reset_handshake;
+};
+
+/*
+ * Shared Memory Regions
+ *
+ * the array of these regions is expected to be in ascending order by phys_addr
+ *
+ * @phys_addr: physical base address of the region
+ * @size: size of the region in bytes
+ */
+struct smd_smem_regions {
+	void *phys_addr;
+	unsigned size;
+};
+
+struct smd_platform {
+	uint32_t num_ss_configs;
+	struct smd_subsystem_config *smd_ss_configs;
+	struct smd_subsystem_restart_config *smd_ssr_config;
+	uint32_t num_smem_areas;
+	struct smd_smem_regions *smd_smem_areas;
+};
+
+#ifdef CONFIG_MSM_SMD
+/* warning: notify() may be called before open returns */
+int smd_open(const char *name, smd_channel_t **ch, void *priv,
+	     void (*notify)(void *priv, unsigned event));
 
 int smd_close(smd_channel_t *ch);
 
 /* passing a null pointer for data reads and discards */
 int smd_read(smd_channel_t *ch, void *data, int len);
+int smd_read_from_cb(smd_channel_t *ch, void *data, int len);
+/* Same as smd_read() but takes a data buffer from userspace
+ * The function might sleep.  Only safe to call from user context
+ */
+int smd_read_user_buffer(smd_channel_t *ch, void *data, int len);
 
 /* Write to stream channels may do a partial write and return
 ** the length actually written.
@@ -40,7 +174,10 @@
 ** it will return the requested length written or an error.
 */
 int smd_write(smd_channel_t *ch, const void *data, int len);
-int smd_write_atomic(smd_channel_t *ch, const void *data, int len);
+/* Same as smd_write() but takes a data buffer from userspace
+ * The function might sleep.  Only safe to call from user context
+ */
+int smd_write_user_buffer(smd_channel_t *ch, const void *data, int len);
 
 int smd_write_avail(smd_channel_t *ch);
 int smd_read_avail(smd_channel_t *ch);
@@ -50,12 +187,6 @@
 */
 int smd_cur_packet_size(smd_channel_t *ch);
 
-/* used for tty unthrottling and the like -- causes the notify()
-** callback to be called from the same lock context as is used
-** when it is called from channel updates
-*/
-void smd_kick(smd_channel_t *ch);
-
 
 #if 0
 /* these are interruptable waits which will block you until the specified
@@ -65,45 +196,234 @@
 int smd_wait_until_writable(smd_channel_t *ch, int bytes);
 #endif
 
-typedef enum {
-	SMD_PORT_DS = 0,
-	SMD_PORT_DIAG,
-	SMD_PORT_RPC_CALL,
-	SMD_PORT_RPC_REPLY,
-	SMD_PORT_BT,
-	SMD_PORT_CONTROL,
-	SMD_PORT_MEMCPY_SPARE1,
-	SMD_PORT_DATA1,
-	SMD_PORT_DATA2,
-	SMD_PORT_DATA3,
-	SMD_PORT_DATA4,
-	SMD_PORT_DATA5,
-	SMD_PORT_DATA6,
-	SMD_PORT_DATA7,
-	SMD_PORT_DATA8,
-	SMD_PORT_DATA9,
-	SMD_PORT_DATA10,
-	SMD_PORT_DATA11,
-	SMD_PORT_DATA12,
-	SMD_PORT_DATA13,
-	SMD_PORT_DATA14,
-	SMD_PORT_DATA15,
-	SMD_PORT_DATA16,
-	SMD_PORT_DATA17,
-	SMD_PORT_DATA18,
-	SMD_PORT_DATA19,
-	SMD_PORT_DATA20,
-	SMD_PORT_GPS_NMEA,
-	SMD_PORT_BRIDGE_1,
-	SMD_PORT_BRIDGE_2,
-	SMD_PORT_BRIDGE_3,
-	SMD_PORT_BRIDGE_4,
-	SMD_PORT_BRIDGE_5,
-	SMD_PORT_LOOPBACK,
-	SMD_PORT_CS_APPS_MODEM,
-	SMD_PORT_CS_APPS_DSP,
-	SMD_PORT_CS_MODEM_DSP,
-	SMD_NUM_PORTS,
-} smd_port_id_type;
+/* these are used to get and set the IF sigs of a channel.
+ * DTR and RTS can be set; DSR, CTS, CD and RI can be read.
+ */
+int smd_tiocmget(smd_channel_t *ch);
+int smd_tiocmset(smd_channel_t *ch, unsigned int set, unsigned int clear);
+int
+smd_tiocmset_from_cb(smd_channel_t *ch, unsigned int set, unsigned int clear);
+int smd_named_open_on_edge(const char *name, uint32_t edge, smd_channel_t **_ch,
+			   void *priv, void (*notify)(void *, unsigned));
+
+/* Tells the other end of the smd channel that this end wants to recieve
+ * interrupts when the written data is read.  Read interrupts should only
+ * enabled when there is no space left in the buffer to write to, thus the
+ * interrupt acts as notification that space may be avaliable.  If the
+ * other side does not support enabling/disabling interrupts on demand,
+ * then this function has no effect if called.
+ */
+void smd_enable_read_intr(smd_channel_t *ch);
+
+/* Tells the other end of the smd channel that this end does not want
+ * interrupts when written data is read.  The interrupts should be
+ * disabled by default.  If the other side does not support enabling/
+ * disabling interrupts on demand, then this function has no effect if
+ * called.
+ */
+void smd_disable_read_intr(smd_channel_t *ch);
+
+/* Starts a packet transaction.  The size of the packet may exceed the total
+ * size of the smd ring buffer.
+ *
+ * @ch: channel to write the packet to
+ * @len: total length of the packet
+ *
+ * Returns:
+ *      0 - success
+ *      -ENODEV - invalid smd channel
+ *      -EACCES - non-packet channel specified
+ *      -EINVAL - invalid length
+ *      -EBUSY - transaction already in progress
+ *      -EAGAIN - no enough memory in ring buffer to start transaction
+ *      -EPERM - unable to sucessfully start transaction due to write error
+ */
+int smd_write_start(smd_channel_t *ch, int len);
+
+/* Writes a segment of the packet for a packet transaction.
+ *
+ * @ch: channel to write packet to
+ * @data: buffer of data to write
+ * @len: length of data buffer
+ * @user_buf: (0) - buffer from kernelspace    (1) - buffer from userspace
+ *
+ * Returns:
+ *      number of bytes written
+ *      -ENODEV - invalid smd channel
+ *      -EINVAL - invalid length
+ *      -ENOEXEC - transaction not started
+ */
+int smd_write_segment(smd_channel_t *ch, void *data, int len, int user_buf);
+
+/* Completes a packet transaction.  Do not call from interrupt context.
+ *
+ * @ch: channel to complete transaction on
+ *
+ * Returns:
+ *      0 - success
+ *      -ENODEV - invalid smd channel
+ *      -E2BIG - some ammount of packet is not yet written
+ */
+int smd_write_end(smd_channel_t *ch);
+
+/*
+ * Returns a pointer to the subsystem name or NULL if no
+ * subsystem name is available.
+ *
+ * @type - Edge definition
+ */
+const char *smd_edge_to_subsystem(uint32_t type);
+
+/*
+ * Returns a pointer to the subsystem name given the
+ * remote processor ID.
+ *
+ * @pid     Remote processor ID
+ * @returns Pointer to subsystem name or NULL if not found
+ */
+const char *smd_pid_to_subsystem(uint32_t pid);
+
+/*
+ * Checks to see if a new packet has arrived on the channel.  Only to be
+ * called with interrupts disabled.
+ *
+ * @ch: channel to check if a packet has arrived
+ *
+ * Returns:
+ *      0 - packet not available
+ *      1 - packet available
+ *      -EINVAL - NULL parameter or non-packet based channel provided
+ */
+int smd_is_pkt_avail(smd_channel_t *ch);
+
+/*
+ * SMD initialization function that registers for a SMD platform driver.
+ *
+ * returns success on successful driver registration.
+ */
+int __init msm_smd_init(void);
+
+#else
+
+static inline int smd_open(const char *name, smd_channel_t **ch, void *priv,
+	     void (*notify)(void *priv, unsigned event))
+{
+	return -ENODEV;
+}
+
+static inline int smd_close(smd_channel_t *ch)
+{
+	return -ENODEV;
+}
+
+static inline int smd_read(smd_channel_t *ch, void *data, int len)
+{
+	return -ENODEV;
+}
+
+static inline int smd_read_from_cb(smd_channel_t *ch, void *data, int len)
+{
+	return -ENODEV;
+}
+
+static inline int smd_read_user_buffer(smd_channel_t *ch, void *data, int len)
+{
+	return -ENODEV;
+}
+
+static inline int smd_write(smd_channel_t *ch, const void *data, int len)
+{
+	return -ENODEV;
+}
+
+static inline int
+smd_write_user_buffer(smd_channel_t *ch, const void *data, int len)
+{
+	return -ENODEV;
+}
+
+static inline int smd_write_avail(smd_channel_t *ch)
+{
+	return -ENODEV;
+}
+
+static inline int smd_read_avail(smd_channel_t *ch)
+{
+	return -ENODEV;
+}
+
+static inline int smd_cur_packet_size(smd_channel_t *ch)
+{
+	return -ENODEV;
+}
+
+static inline int smd_tiocmget(smd_channel_t *ch)
+{
+	return -ENODEV;
+}
+
+static inline int
+smd_tiocmset(smd_channel_t *ch, unsigned int set, unsigned int clear)
+{
+	return -ENODEV;
+}
+
+static inline int
+smd_tiocmset_from_cb(smd_channel_t *ch, unsigned int set, unsigned int clear)
+{
+	return -ENODEV;
+}
+
+static inline int
+smd_named_open_on_edge(const char *name, uint32_t edge, smd_channel_t **_ch,
+			   void *priv, void (*notify)(void *, unsigned))
+{
+	return -ENODEV;
+}
+
+static inline void smd_enable_read_intr(smd_channel_t *ch)
+{
+}
+
+static inline void smd_disable_read_intr(smd_channel_t *ch)
+{
+}
+
+static inline int smd_write_start(smd_channel_t *ch, int len)
+{
+	return -ENODEV;
+}
+
+static inline int
+smd_write_segment(smd_channel_t *ch, void *data, int len, int user_buf)
+{
+	return -ENODEV;
+}
+
+static inline int smd_write_end(smd_channel_t *ch)
+{
+	return -ENODEV;
+}
+
+static inline const char *smd_edge_to_subsystem(uint32_t type)
+{
+	return NULL;
+}
+
+static inline const char *smd_pid_to_subsystem(uint32_t pid)
+{
+	return NULL;
+}
+
+static inline int smd_is_pkt_avail(smd_channel_t *ch)
+{
+	return -ENODEV;
+}
+
+static inline int __init msm_smd_init(void)
+{
+	return 0;
+}
+#endif
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_smsm.h b/arch/arm/mach-msm/include/mach/msm_smsm.h
new file mode 100644
index 0000000..fbb8502
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_smsm.h
@@ -0,0 +1,259 @@
+/* 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
+ * 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 _ARCH_ARM_MACH_MSM_SMSM_H_
+#define _ARCH_ARM_MACH_MSM_SMSM_H_
+
+#include <linux/notifier.h>
+#if defined(CONFIG_MSM_N_WAY_SMSM)
+enum {
+	SMSM_APPS_STATE,
+	SMSM_MODEM_STATE,
+	SMSM_Q6_STATE,
+	SMSM_APPS_DEM,
+	SMSM_WCNSS_STATE = SMSM_APPS_DEM,
+	SMSM_MODEM_DEM,
+	SMSM_DSPS_STATE = SMSM_MODEM_DEM,
+	SMSM_Q6_DEM,
+	SMSM_POWER_MASTER_DEM,
+	SMSM_TIME_MASTER_DEM,
+};
+extern uint32_t SMSM_NUM_ENTRIES;
+#else
+enum {
+	SMSM_APPS_STATE = 1,
+	SMSM_MODEM_STATE = 3,
+	SMSM_NUM_ENTRIES,
+};
+#endif
+
+enum {
+	SMSM_APPS,
+	SMSM_MODEM,
+	SMSM_Q6,
+	SMSM_WCNSS,
+	SMSM_DSPS,
+};
+extern uint32_t SMSM_NUM_HOSTS;
+
+#define SMSM_INIT              0x00000001
+#define SMSM_OSENTERED         0x00000002
+#define SMSM_SMDWAIT           0x00000004
+#define SMSM_SMDINIT           0x00000008
+#define SMSM_RPCWAIT           0x00000010
+#define SMSM_RPCINIT           0x00000020
+#define SMSM_RESET             0x00000040
+#define SMSM_RSA               0x00000080
+#define SMSM_RUN               0x00000100
+#define SMSM_PWRC              0x00000200
+#define SMSM_TIMEWAIT          0x00000400
+#define SMSM_TIMEINIT          0x00000800
+#define SMSM_PWRC_EARLY_EXIT   0x00001000
+#define SMSM_LTE_COEX_AWAKE    0x00001000
+#define SMSM_WFPI              0x00002000
+#define SMSM_SLEEP             0x00004000
+#define SMSM_SLEEPEXIT         0x00008000
+#define SMSM_OEMSBL_RELEASE    0x00010000
+#define SMSM_APPS_REBOOT       0x00020000
+#define SMSM_SYSTEM_POWER_DOWN 0x00040000
+#define SMSM_SYSTEM_REBOOT     0x00080000
+#define SMSM_SYSTEM_DOWNLOAD   0x00100000
+#define SMSM_PWRC_SUSPEND      0x00200000
+#define SMSM_APPS_SHUTDOWN     0x00400000
+#define SMSM_SMD_LOOPBACK      0x00800000
+#define SMSM_RUN_QUIET         0x01000000
+#define SMSM_MODEM_WAIT        0x02000000
+#define SMSM_MODEM_BREAK       0x04000000
+#define SMSM_MODEM_CONTINUE    0x08000000
+#define SMSM_SYSTEM_REBOOT_USR 0x20000000
+#define SMSM_SYSTEM_PWRDWN_USR 0x40000000
+#define SMSM_UNKNOWN           0x80000000
+
+#define SMSM_WKUP_REASON_RPC	0x00000001
+#define SMSM_WKUP_REASON_INT	0x00000002
+#define SMSM_WKUP_REASON_GPIO	0x00000004
+#define SMSM_WKUP_REASON_TIMER	0x00000008
+#define SMSM_WKUP_REASON_ALARM	0x00000010
+#define SMSM_WKUP_REASON_RESET	0x00000020
+#define SMSM_A2_FORCE_SHUTDOWN 0x00002000
+#define SMSM_A2_RESET_BAM      0x00004000
+
+#define SMSM_VENDOR             0x00020000
+
+#define SMSM_A2_POWER_CONTROL  0x00000002
+#define SMSM_A2_POWER_CONTROL_ACK  0x00000800
+
+#define SMSM_WLAN_TX_RINGS_EMPTY 0x00000200
+#define SMSM_WLAN_TX_ENABLE	0x00000400
+
+#define SMSM_ERR_SRV_READY         0x00008000
+
+#ifdef CONFIG_MSM_SMD
+void *smem_alloc(unsigned id, unsigned size);
+#else
+void *smem_alloc(unsigned id, unsigned size)
+{
+	return NULL;
+}
+#endif
+void *smem_alloc2(unsigned id, unsigned size_in);
+void *smem_get_entry(unsigned id, unsigned *size);
+int smsm_change_state(uint32_t smsm_entry,
+		      uint32_t clear_mask, uint32_t set_mask);
+
+/*
+ * Changes the global interrupt mask.  The set and clear masks are re-applied
+ * every time the global interrupt mask is updated for callback registration
+ * and de-registration.
+ *
+ * The clear mask is applied first, so if a bit is set to 1 in both the clear
+ * mask and the set mask, the result will be that the interrupt is set.
+ *
+ * @smsm_entry  SMSM entry to change
+ * @clear_mask  1 = clear bit, 0 = no-op
+ * @set_mask    1 = set bit, 0 = no-op
+ *
+ * @returns 0 for success, < 0 for error
+ */
+int smsm_change_intr_mask(uint32_t smsm_entry,
+			  uint32_t clear_mask, uint32_t set_mask);
+int smsm_get_intr_mask(uint32_t smsm_entry, uint32_t *intr_mask);
+uint32_t smsm_get_state(uint32_t smsm_entry);
+int smsm_state_cb_register(uint32_t smsm_entry, uint32_t mask,
+	void (*notify)(void *, uint32_t old_state, uint32_t new_state),
+	void *data);
+int smsm_state_cb_deregister(uint32_t smsm_entry, uint32_t mask,
+	void (*notify)(void *, uint32_t, uint32_t), void *data);
+int smsm_driver_state_notifier_register(struct notifier_block *nb);
+int smsm_driver_state_notifier_unregister(struct notifier_block *nb);
+void smsm_print_sleep_info(uint32_t sleep_delay, uint32_t sleep_limit,
+	uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs);
+void smsm_reset_modem(unsigned mode);
+void smsm_reset_modem_cont(void);
+void smd_sleep_exit(void);
+
+#define SMEM_NUM_SMD_STREAM_CHANNELS        64
+#define SMEM_NUM_SMD_BLOCK_CHANNELS         64
+
+enum {
+	/* fixed items */
+	SMEM_PROC_COMM = 0,
+	SMEM_HEAP_INFO,
+	SMEM_ALLOCATION_TABLE,
+	SMEM_VERSION_INFO,
+	SMEM_HW_RESET_DETECT,
+	SMEM_AARM_WARM_BOOT,
+	SMEM_DIAG_ERR_MESSAGE,
+	SMEM_SPINLOCK_ARRAY,
+	SMEM_MEMORY_BARRIER_LOCATION,
+	SMEM_FIXED_ITEM_LAST = SMEM_MEMORY_BARRIER_LOCATION,
+
+	/* dynamic items */
+	SMEM_AARM_PARTITION_TABLE,
+	SMEM_AARM_BAD_BLOCK_TABLE,
+	SMEM_RESERVE_BAD_BLOCKS,
+	SMEM_WM_UUID,
+	SMEM_CHANNEL_ALLOC_TBL,
+	SMEM_SMD_BASE_ID,
+	SMEM_SMEM_LOG_IDX = SMEM_SMD_BASE_ID + SMEM_NUM_SMD_STREAM_CHANNELS,
+	SMEM_SMEM_LOG_EVENTS,
+	SMEM_SMEM_STATIC_LOG_IDX,
+	SMEM_SMEM_STATIC_LOG_EVENTS,
+	SMEM_SMEM_SLOW_CLOCK_SYNC,
+	SMEM_SMEM_SLOW_CLOCK_VALUE,
+	SMEM_BIO_LED_BUF,
+	SMEM_SMSM_SHARED_STATE,
+	SMEM_SMSM_INT_INFO,
+	SMEM_SMSM_SLEEP_DELAY,
+	SMEM_SMSM_LIMIT_SLEEP,
+	SMEM_SLEEP_POWER_COLLAPSE_DISABLED,
+	SMEM_KEYPAD_KEYS_PRESSED,
+	SMEM_KEYPAD_STATE_UPDATED,
+	SMEM_KEYPAD_STATE_IDX,
+	SMEM_GPIO_INT,
+	SMEM_MDDI_LCD_IDX,
+	SMEM_MDDI_HOST_DRIVER_STATE,
+	SMEM_MDDI_LCD_DISP_STATE,
+	SMEM_LCD_CUR_PANEL,
+	SMEM_MARM_BOOT_SEGMENT_INFO,
+	SMEM_AARM_BOOT_SEGMENT_INFO,
+	SMEM_SLEEP_STATIC,
+	SMEM_SCORPION_FREQUENCY,
+	SMEM_SMD_PROFILES,
+	SMEM_TSSC_BUSY,
+	SMEM_HS_SUSPEND_FILTER_INFO,
+	SMEM_BATT_INFO,
+	SMEM_APPS_BOOT_MODE,
+	SMEM_VERSION_FIRST,
+	SMEM_VERSION_SMD = SMEM_VERSION_FIRST,
+	SMEM_VERSION_LAST = SMEM_VERSION_FIRST + 24,
+	SMEM_OSS_RRCASN1_BUF1,
+	SMEM_OSS_RRCASN1_BUF2,
+	SMEM_ID_VENDOR0,
+	SMEM_ID_VENDOR1,
+	SMEM_ID_VENDOR2,
+	SMEM_HW_SW_BUILD_ID,
+	SMEM_SMD_BLOCK_PORT_BASE_ID,
+	SMEM_SMD_BLOCK_PORT_PROC0_HEAP = SMEM_SMD_BLOCK_PORT_BASE_ID +
+						SMEM_NUM_SMD_BLOCK_CHANNELS,
+	SMEM_SMD_BLOCK_PORT_PROC1_HEAP = SMEM_SMD_BLOCK_PORT_PROC0_HEAP +
+						SMEM_NUM_SMD_BLOCK_CHANNELS,
+	SMEM_I2C_MUTEX = SMEM_SMD_BLOCK_PORT_PROC1_HEAP +
+						SMEM_NUM_SMD_BLOCK_CHANNELS,
+	SMEM_SCLK_CONVERSION,
+	SMEM_SMD_SMSM_INTR_MUX,
+	SMEM_SMSM_CPU_INTR_MASK,
+	SMEM_APPS_DEM_SLAVE_DATA,
+	SMEM_QDSP6_DEM_SLAVE_DATA,
+	SMEM_CLKREGIM_BSP,
+	SMEM_CLKREGIM_SOURCES,
+	SMEM_SMD_FIFO_BASE_ID,
+	SMEM_USABLE_RAM_PARTITION_TABLE = SMEM_SMD_FIFO_BASE_ID +
+						SMEM_NUM_SMD_STREAM_CHANNELS,
+	SMEM_POWER_ON_STATUS_INFO,
+	SMEM_DAL_AREA,
+	SMEM_SMEM_LOG_POWER_IDX,
+	SMEM_SMEM_LOG_POWER_WRAP,
+	SMEM_SMEM_LOG_POWER_EVENTS,
+	SMEM_ERR_CRASH_LOG,
+	SMEM_ERR_F3_TRACE_LOG,
+	SMEM_SMD_BRIDGE_ALLOC_TABLE,
+	SMEM_SMDLITE_TABLE,
+	SMEM_SD_IMG_UPGRADE_STATUS,
+	SMEM_SEFS_INFO,
+	SMEM_RESET_LOG,
+	SMEM_RESET_LOG_SYMBOLS,
+	SMEM_MODEM_SW_BUILD_ID,
+	SMEM_SMEM_LOG_MPROC_WRAP,
+	SMEM_BOOT_INFO_FOR_APPS,
+	SMEM_SMSM_SIZE_INFO,
+	SMEM_SMD_LOOPBACK_REGISTER,
+	SMEM_SSR_REASON_MSS0,
+	SMEM_SSR_REASON_WCNSS0,
+	SMEM_SSR_REASON_LPASS0,
+	SMEM_SSR_REASON_DSPS0,
+	SMEM_SSR_REASON_VCODEC0,
+	SMEM_MEM_LAST = SMEM_SSR_REASON_VCODEC0,
+	SMEM_NUM_ITEMS,
+};
+
+enum {
+	SMEM_APPS_Q6_SMSM = 3,
+	SMEM_Q6_APPS_SMSM = 5,
+	SMSM_NUM_INTR_MUX = 8,
+};
+
+int smsm_check_for_modem_crash(void);
+void *smem_find(unsigned id, unsigned size);
+void *smem_get_entry(unsigned id, unsigned *size);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_spi.h b/arch/arm/mach-msm/include/mach/msm_spi.h
new file mode 100644
index 0000000..51081b6
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_spi.h
@@ -0,0 +1,24 @@
+/* Copyright (c) 2008-2009, 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.
+ *
+ */
+/*
+ * SPI driver for Qualcomm MSM platforms.
+ */
+
+struct msm_spi_platform_data {
+	u32 max_clock_speed;
+	int (*gpio_config)(void);
+	void (*gpio_release)(void);
+	int (*dma_config)(void);
+	const char *rsl_id;
+	uint32_t pm_lat;
+};
diff --git a/arch/arm/mach-msm/include/mach/msm_sps.h b/arch/arm/mach-msm/include/mach/msm_sps.h
new file mode 100644
index 0000000..3af6f71
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_sps.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _MSM_SPS_H_
+#define _MSM_SPS_H_
+
+/**
+ * struct msm_sps_platform_data - SPS Platform specific data.
+ * @bamdma_restricted_pipes - Bitmask of pipes restricted from local use.
+ *
+ */
+struct msm_sps_platform_data {
+	u32 bamdma_restricted_pipes;
+};
+
+#endif /* _MSM_SPS_H_ */
+
diff --git a/arch/arm/mach-msm/include/mach/msm_subsystem_map.h b/arch/arm/mach-msm/include/mach/msm_subsystem_map.h
new file mode 100644
index 0000000..ebb2327
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_subsystem_map.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __ARCH_MACH_MSM_SUBSYSTEM_MAP_H
+#define __ARCH_MACH_MSM_SUBSYSTEM_MAP_H
+
+#include <linux/iommu.h>
+#include <mach/iommu_domains.h>
+
+/* map the physical address in the kernel vaddr space */
+#define MSM_SUBSYSTEM_MAP_KADDR		0x1
+/* map the physical address in the iova address space */
+#define MSM_SUBSYSTEM_MAP_IOVA		0x2
+/* ioremaps in the kernel address space are cached */
+#define	MSM_SUBSYSTEM_MAP_CACHED	0x4
+/* ioremaps in the kernel address space are uncached */
+#define MSM_SUBSYSTEM_MAP_UNCACHED	0x8
+/*
+ * Will map 2x the length requested.
+ */
+#define MSM_SUBSYSTEM_MAP_IOMMU_2X 0x10
+
+/*
+ * Shortcut flags for alignment.
+ * The flag must be equal to the alignment requested.
+ * e.g. for 8k alignment the flags must be (0x2000 | other flags)
+ */
+#define	MSM_SUBSYSTEM_ALIGN_IOVA_8K	SZ_8K
+#define MSM_SUBSYSTEM_ALIGN_IOVA_1M	SZ_1M
+
+
+enum msm_subsystem_id {
+	INVALID_SUBSYS_ID = -1,
+	MSM_SUBSYSTEM_VIDEO,
+	MSM_SUBSYSTEM_VIDEO_FWARE,
+	MSM_SUBSYSTEM_CAMERA,
+	MSM_SUBSYSTEM_DISPLAY,
+	MSM_SUBSYSTEM_ROTATOR,
+	MAX_SUBSYSTEM_ID
+};
+
+static inline int msm_subsystem_check_id(int subsys_id)
+{
+	return subsys_id > INVALID_SUBSYS_ID && subsys_id < MAX_SUBSYSTEM_ID;
+}
+
+struct msm_mapped_buffer {
+	/*
+	 * VA mapped in the kernel address space. This field shall be NULL if
+	 * MSM_SUBSYSTEM_MAP_KADDR was not passed to the map buffer function.
+	 */
+	void *vaddr;
+	/*
+	 * iovas mapped in the iommu address space. The ith entry of this array
+	 * corresponds to the iova mapped in the ith subsystem in the array
+	 * pased in to msm_subsystem_map_buffer. This field shall be NULL if
+	 * MSM_SUBSYSTEM_MAP_IOVA was not passed to the map buffer function,
+	 */
+	unsigned long *iova;
+};
+
+extern struct msm_mapped_buffer *msm_subsystem_map_buffer(
+				unsigned long phys,
+				unsigned int length,
+				unsigned int flags,
+				int *subsys_ids,
+				unsigned int nsubsys);
+
+extern int msm_subsystem_unmap_buffer(struct msm_mapped_buffer *buf);
+
+extern phys_addr_t msm_subsystem_check_iova_mapping(int subsys_id,
+						unsigned long iova);
+
+#endif /* __ARCH_MACH_MSM_SUBSYSTEM_MAP_H */
diff --git a/arch/arm/mach-msm/include/mach/msm_touch.h b/arch/arm/mach-msm/include/mach/msm_touch.h
new file mode 100644
index 0000000..763d6a8
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_touch.h
@@ -0,0 +1,26 @@
+/* arch/arm/mach-msm/include/mach/msm_touch.h
+ *
+ * Platform data for MSM touchscreen driver.
+ *
+ * Copyright (c) 2008-2009, Code Aurora Forum. 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 _MACH_MSM_TOUCH_H_
+#define _MACH_MSM_TOUCH_H_
+
+struct msm_ts_platform_data {
+	unsigned int x_max;
+	unsigned int y_max;
+	unsigned int pressure_max;
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_touchpad.h b/arch/arm/mach-msm/include/mach/msm_touchpad.h
new file mode 100644
index 0000000..4b2d537
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_touchpad.h
@@ -0,0 +1,22 @@
+/* Copyright (c) 2008-2009, 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.
+ *
+ */
+/*
+ * Touchpad driver for QSD platform.
+ */
+
+struct msm_touchpad_platform_data {
+	int gpioirq;
+	int gpiosuspend;
+	int (*gpio_setup) (void);
+	void (*gpio_shutdown)(void);
+};
diff --git a/arch/arm/mach-msm/include/mach/msm_tsif.h b/arch/arm/mach-msm/include/mach/msm_tsif.h
new file mode 100644
index 0000000..62595e3
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_tsif.h
@@ -0,0 +1,26 @@
+/* Copyright (c) 2009, 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef _MSM_TSIF_H_
+#define _MSM_TSIF_H_
+
+struct msm_tsif_platform_data {
+	int num_gpios;
+	const struct msm_gpio *gpios;
+	const char *tsif_clk;
+	const char *tsif_pclk;
+	const char *tsif_ref_clk;
+	void (*init)(struct msm_tsif_platform_data *);
+};
+
+#endif /* _MSM_TSIF_H_ */
+
diff --git a/arch/arm/mach-msm/include/mach/msm_tspp.h b/arch/arm/mach-msm/include/mach/msm_tspp.h
new file mode 100644
index 0000000..6912f0c
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_tspp.h
@@ -0,0 +1,24 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MSM_TSPP_H_
+#define _MSM_TSPP_H_
+
+struct msm_tspp_platform_data {
+	int num_gpios;
+	const struct msm_gpio *gpios;
+	const char *tsif_pclk;
+	const char *tsif_ref_clk;
+};
+
+#endif /* _MSM_TSPP_H_ */
+
diff --git a/arch/arm/mach-msm/include/mach/msm_xo.h b/arch/arm/mach-msm/include/mach/msm_xo.h
new file mode 100644
index 0000000..f9795b4
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_xo.h
@@ -0,0 +1,56 @@
+/* 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
+ * 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 __MACH_MSM_XO_H
+#define __MACH_MSM_XO_H
+
+enum msm_xo_ids {
+	MSM_XO_TCXO_D0,
+	MSM_XO_TCXO_D1,
+	MSM_XO_TCXO_A0,
+	MSM_XO_TCXO_A1,
+	MSM_XO_TCXO_A2,
+	MSM_XO_CORE,
+	NUM_MSM_XO_IDS
+};
+
+enum msm_xo_modes {
+	MSM_XO_MODE_OFF,
+	MSM_XO_MODE_PIN_CTRL,
+	MSM_XO_MODE_ON,
+	NUM_MSM_XO_MODES
+};
+
+struct msm_xo_voter;
+
+#ifdef CONFIG_MSM_XO
+struct msm_xo_voter *msm_xo_get(enum msm_xo_ids xo_id, const char *voter);
+void msm_xo_put(struct msm_xo_voter *xo_voter);
+int msm_xo_mode_vote(struct msm_xo_voter *xo_voter, enum msm_xo_modes xo_mode);
+int __init msm_xo_init(void);
+#else
+static inline struct msm_xo_voter *msm_xo_get(enum msm_xo_ids xo_id,
+		const char *voter)
+{
+	return NULL;
+}
+
+static inline void msm_xo_put(struct msm_xo_voter *xo_voter) { }
+
+static inline int msm_xo_mode_vote(struct msm_xo_voter *xo_voter,
+		enum msm_xo_modes xo_mode)
+{
+	return 0;
+}
+static inline int msm_xo_init(void) { return 0; }
+#endif /* CONFIG_MSM_XO */
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/ocmem.h b/arch/arm/mach-msm/include/mach/ocmem.h
new file mode 100644
index 0000000..bf7c338
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/ocmem.h
@@ -0,0 +1,109 @@
+/* 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 _ARCH_ARM_MACH_MSM_OCMEM_H
+#define _ARCH_ARM_MACH_MSM_OCMEM_H
+
+#include <asm/page.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+
+#define OCMEM_MIN_ALLOC SZ_64K
+#define OCMEM_MIN_ALIGN SZ_64K
+
+/* Maximum number of slots in DM */
+#define OCMEM_MAX_CHUNKS 32
+#define MIN_CHUNK_SIZE (SZ_1K/8)
+
+struct ocmem_buf {
+	unsigned long addr;
+	unsigned long len;
+};
+
+struct ocmem_buf_attr {
+	unsigned long paddr;
+	unsigned long len;
+};
+
+struct ocmem_chunk {
+	bool ro;
+	unsigned long ddr_paddr;
+	unsigned long size;
+};
+
+struct ocmem_map_list {
+	int num_chunks;
+	struct ocmem_chunk chunks[OCMEM_MAX_CHUNKS];
+};
+
+/* List of clients that allocate/interact with OCMEM */
+/* Must be in sync with client_names */
+enum ocmem_client {
+	/* GMEM clients */
+	OCMEM_GRAPHICS = 0x0,
+	/* TCMEM clients */
+	OCMEM_VIDEO,
+	OCMEM_CAMERA,
+	/* Dummy Clients */
+	OCMEM_HP_AUDIO,
+	OCMEM_VOICE,
+	/* IMEM Clients */
+	OCMEM_LP_AUDIO,
+	OCMEM_SENSORS,
+	OCMEM_BLAST,
+	OCMEM_CLIENT_MAX,
+};
+
+/**
+ * List of OCMEM notification events which will be broadcasted
+ * to clients that optionally register for these notifications
+ * on a per allocation basis.
+ **/
+enum ocmem_notif_type {
+	OCMEM_MAP_DONE = 1,
+	OCMEM_MAP_FAIL,
+	OCMEM_UNMAP_DONE,
+	OCMEM_UNMAP_FAIL,
+	OCMEM_ALLOC_GROW,
+	OCMEM_ALLOC_SHRINK,
+	OCMEM_NOTIF_TYPE_COUNT,
+};
+
+/* APIS */
+/* Notification APIs */
+void *ocmem_notifier_register(int client_id, struct notifier_block *nb);
+
+int ocmem_notifier_unregister(void *notif_hndl, struct notifier_block *nb);
+
+/* Allocation APIs */
+struct ocmem_buf *ocmem_allocate(int client_id, unsigned long size);
+
+struct ocmem_buf *ocmem_allocate_nb(int client_id, unsigned long size);
+
+struct ocmem_buf *ocmem_allocate_range(int client_id, unsigned long min,
+			unsigned long goal, unsigned long step);
+
+/* Free APIs */
+int ocmem_free(int client_id, struct ocmem_buf *buf);
+
+/* Dynamic Resize APIs */
+int ocmem_shrink(int client_id, struct ocmem_buf *buf,
+			unsigned long new_size);
+
+int ocmem_expand(int client_id, struct ocmem_buf *buf,
+			unsigned long new_size);
+
+/* Priority Enforcement APIs */
+int ocmem_evict(int client_id);
+
+int ocmem_restore(int client_id);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
new file mode 100644
index 0000000..daf32a5
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -0,0 +1,81 @@
+/* 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 _ARCH_ARM_MACH_MSM_OCMEM_CORE_H
+#define _ARCH_ARM_MACH_MSM_OCMEM_CORE_H
+
+/** All interfaces in this header should only be used by OCMEM driver
+ *  Client drivers should use wrappers available in ocmem.h
+ **/
+
+#include "ocmem.h"
+#include <mach/msm_iomap.h>
+#include <asm/io.h>
+
+#define OCMEM_PHYS_BASE 0xFEC00000
+#define OCMEM_PHYS_SIZE 0x180000
+
+struct ocmem_zone;
+
+struct ocmem_zone_ops {
+	unsigned long (*allocate) (struct ocmem_zone *, unsigned long);
+	int (*free) (struct ocmem_zone *, unsigned long, unsigned long);
+};
+
+struct ocmem_zone {
+	int owner;
+	int active_regions;
+	int max_regions;
+	struct list_head region_list;
+	unsigned long z_start;
+	unsigned long z_end;
+	unsigned long z_head;
+	unsigned long z_tail;
+	unsigned long z_free;
+	struct gen_pool *z_pool;
+	struct ocmem_zone_ops *z_ops;
+};
+
+struct ocmem_req {
+	struct rw_semaphore rw_sem;
+	/* Chain in sched queue */
+	struct list_head sched_list;
+	/* Chain in zone list */
+	struct list_head zone_list;
+	int owner;
+	int prio;
+	uint32_t req_id;
+	unsigned long req_min;
+	unsigned long req_max;
+	unsigned long req_step;
+	/* reverse pointers */
+	struct ocmem_zone *zone;
+	struct ocmem_buf *buffer;
+	unsigned long state;
+	/* Request assignments */
+	unsigned long req_start;
+	unsigned long req_end;
+	unsigned long req_sz;
+};
+
+struct ocmem_handle {
+	struct ocmem_buf buffer;
+	struct mutex handle_mutex;
+	struct ocmem_req *req;
+};
+
+struct ocmem_zone *get_zone(unsigned);
+unsigned long allocate_head(struct ocmem_zone *, unsigned long);
+int free_head(struct ocmem_zone *, unsigned long, unsigned long);
+unsigned long allocate_tail(struct ocmem_zone *, unsigned long);
+int free_tail(struct ocmem_zone *, unsigned long, unsigned long);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/oem_rapi_client.h b/arch/arm/mach-msm/include/mach/oem_rapi_client.h
new file mode 100644
index 0000000..d7a2416
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/oem_rapi_client.h
@@ -0,0 +1,76 @@
+/* Copyright (c) 2009, 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 __ASM__ARCH_OEM_RAPI_CLIENT_H
+#define __ASM__ARCH_OEM_RAPI_CLIENT_H
+
+/*
+ * OEM RAPI CLIENT Driver header file
+ */
+
+#include <linux/types.h>
+#include <mach/msm_rpcrouter.h>
+
+enum {
+	OEM_RAPI_CLIENT_EVENT_NONE = 0,
+
+	/*
+	 * list of oem rapi client events
+	 */
+
+	OEM_RAPI_CLIENT_EVENT_MAX
+
+};
+
+struct oem_rapi_client_streaming_func_cb_arg {
+	uint32_t  event;
+	void      *handle;
+	uint32_t  in_len;
+	char      *input;
+	uint32_t out_len_valid;
+	uint32_t output_valid;
+	uint32_t output_size;
+};
+
+struct oem_rapi_client_streaming_func_cb_ret {
+	uint32_t *out_len;
+	char *output;
+};
+
+struct oem_rapi_client_streaming_func_arg {
+	uint32_t event;
+	int (*cb_func)(struct oem_rapi_client_streaming_func_cb_arg *,
+		       struct oem_rapi_client_streaming_func_cb_ret *);
+	void *handle;
+	uint32_t in_len;
+	char *input;
+	uint32_t out_len_valid;
+	uint32_t output_valid;
+	uint32_t output_size;
+};
+
+struct oem_rapi_client_streaming_func_ret {
+	uint32_t *out_len;
+	char *output;
+};
+
+int oem_rapi_client_streaming_function(
+	struct msm_rpc_client *client,
+	struct oem_rapi_client_streaming_func_arg *arg,
+	struct oem_rapi_client_streaming_func_ret *ret);
+
+int oem_rapi_client_close(void);
+
+struct msm_rpc_client *oem_rapi_client_init(void);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/peripheral-loader.h b/arch/arm/mach-msm/include/mach/peripheral-loader.h
new file mode 100644
index 0000000..327c82f
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/peripheral-loader.h
@@ -0,0 +1,27 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __MACH_PERIPHERAL_LOADER_H
+#define __MACH_PERIPHERAL_LOADER_H
+
+#ifdef CONFIG_MSM_PIL
+extern void *pil_get(const char *name);
+extern void pil_put(void *peripheral_handle);
+extern void pil_force_shutdown(const char *name);
+extern int pil_force_boot(const char *name);
+#else
+static inline void *pil_get(const char *name) { return NULL; }
+static inline void pil_put(void *peripheral_handle) { }
+static inline void pil_force_shutdown(const char *name) { }
+static inline int pil_force_boot(const char *name) { return -ENOSYS; }
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/pmic.h b/arch/arm/mach-msm/include/mach/pmic.h
new file mode 100644
index 0000000..b143a59
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/pmic.h
@@ -0,0 +1,748 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_PMIC_H
+#define __ARCH_ARM_MACH_PMIC_H
+
+#include <linux/types.h>
+
+enum spkr_ldo_v_sel {
+	VOLT_LEVEL_1_1V,
+	VOLT_LEVEL_1_2V,
+	VOLT_LEVEL_2_0V,
+};
+
+enum hp_spkr_left_right {
+	LEFT_HP_SPKR,
+	RIGHT_HP_SPKR,
+};
+
+enum spkr_left_right {
+	LEFT_SPKR,
+	RIGHT_SPKR,
+};
+
+enum spkr_gain {
+	SPKR_GAIN_MINUS16DB,      /* -16 db */
+	SPKR_GAIN_MINUS12DB,      /* -12 db */
+	SPKR_GAIN_MINUS08DB,      /* -08 db */
+	SPKR_GAIN_MINUS04DB,      /* -04 db */
+	SPKR_GAIN_00DB,           /*  00 db */
+	SPKR_GAIN_PLUS04DB,       /* +04 db */
+	SPKR_GAIN_PLUS08DB,       /* +08 db */
+	SPKR_GAIN_PLUS12DB,       /* +12 db */
+};
+
+enum spkr_dly {
+	SPKR_DLY_10MS,            /* ~10  ms delay */
+	SPKR_DLY_100MS,           /* ~100 ms delay */
+};
+
+enum spkr_hpf_corner_freq {
+	SPKR_FREQ_1_39KHZ,         /* 1.39 kHz */
+	SPKR_FREQ_0_64KHZ,         /* 0.64 kHz */
+	SPKR_FREQ_0_86KHZ,         /* 0.86 kHz */
+	SPKR_FREQ_0_51KHZ,         /* 0.51 kHz */
+	SPKR_FREQ_1_06KHZ,         /* 1.06 kHz */
+	SPKR_FREQ_0_57KHZ,         /* 0.57 kHz */
+	SPKR_FREQ_0_73KHZ,         /* 0.73 kHz */
+	SPKR_FREQ_0_47KHZ,         /* 0.47 kHz */
+	SPKR_FREQ_1_20KHZ,         /* 1.20 kHz */
+	SPKR_FREQ_0_60KHZ,         /* 0.60 kHz */
+	SPKR_FREQ_0_76KHZ,         /* 0.76 kHz */
+	SPKR_FREQ_0_49KHZ,         /* 0.49 kHz */
+	SPKR_FREQ_0_95KHZ,         /* 0.95 kHz */
+	SPKR_FREQ_0_54KHZ,         /* 0.54 kHz */
+	SPKR_FREQ_0_68KHZ,         /* 0.68 kHz */
+	SPKR_FREQ_0_45KHZ,         /* 0.45 kHz */
+};
+
+/* Turn the speaker on or off and enables or disables mute.*/
+enum spkr_cmd {
+	SPKR_DISABLE,  /* Enable Speaker */
+	SPKR_ENABLE,   /* Disable Speaker */
+	SPKR_MUTE_OFF, /* turn speaker mute off, SOUND ON */
+	SPKR_MUTE_ON,  /* turn speaker mute on, SOUND OFF */
+	SPKR_OFF,      /* turn speaker OFF (speaker disable and mute on) */
+	SPKR_ON,        /* turn speaker ON (speaker enable and mute off)  */
+	SPKR_SET_FREQ_CMD,    /* set speaker frequency */
+	SPKR_GET_FREQ_CMD,    /* get speaker frequency */
+	SPKR_SET_GAIN_CMD,    /* set speaker gain */
+	SPKR_GET_GAIN_CMD,    /* get speaker gain */
+	SPKR_SET_DELAY_CMD,   /* set speaker delay */
+	SPKR_GET_DELAY_CMD,   /* get speaker delay */
+	SPKR_SET_PDM_MODE,
+	SPKR_SET_PWM_MODE,
+};
+
+struct spkr_config_mode {
+	uint32_t is_right_chan_en;
+	uint32_t is_left_chan_en;
+	uint32_t is_right_left_chan_added;
+	uint32_t is_stereo_en;
+	uint32_t is_usb_with_hpf_20hz;
+	uint32_t is_mux_bypassed;
+	uint32_t is_hpf_en;
+	uint32_t is_sink_curr_from_ref_volt_cir_en;
+};
+
+enum mic_volt {
+	MIC_VOLT_2_00V,            /*  2.00 V  */
+	MIC_VOLT_1_93V,            /*  1.93 V  */
+	MIC_VOLT_1_80V,            /*  1.80 V  */
+	MIC_VOLT_1_73V,            /*  1.73 V  */
+};
+
+enum ledtype {
+	LED_LCD,
+	LED_KEYPAD,
+};
+
+enum flash_led_mode {
+	FLASH_LED_MODE__MANUAL,
+	FLASH_LED_MODE__DBUS1,
+	FLASH_LED_MODE__DBUS2,
+	FLASH_LED_MODE__DBUS3,
+};
+
+enum flash_led_pol {
+	FLASH_LED_POL__ACTIVE_HIGH,
+	FLASH_LED_POL__ACTIVE_LOW,
+};
+
+enum switch_cmd {
+	OFF_CMD,
+	ON_CMD
+};
+
+enum vreg_lp_id {
+	PM_VREG_LP_MSMA_ID,
+	PM_VREG_LP_MSMP_ID,
+	PM_VREG_LP_MSME1_ID,
+	PM_VREG_LP_GP3_ID,
+	PM_VREG_LP_MSMC_ID,
+	PM_VREG_LP_MSME2_ID,
+	PM_VREG_LP_GP4_ID,
+	PM_VREG_LP_GP1_ID,
+	PM_VREG_LP_RFTX_ID,
+	PM_VREG_LP_RFRX1_ID,
+	PM_VREG_LP_RFRX2_ID,
+	PM_VREG_LP_WLAN_ID,
+	PM_VREG_LP_MMC_ID,
+	PM_VREG_LP_RUIM_ID,
+	PM_VREG_LP_MSMC0_ID,
+	PM_VREG_LP_GP2_ID,
+	PM_VREG_LP_GP5_ID,
+	PM_VREG_LP_GP6_ID,
+	PM_VREG_LP_MPLL_ID,
+	PM_VREG_LP_RFUBM_ID,
+	PM_VREG_LP_RFA_ID,
+	PM_VREG_LP_CDC2_ID,
+	PM_VREG_LP_RFTX2_ID,
+	PM_VREG_LP_USIM_ID,
+	PM_VREG_LP_USB2P6_ID,
+	PM_VREG_LP_TCXO_ID,
+	PM_VREG_LP_USB3P3_ID,
+
+	PM_VREG_LP_MSME_ID = PM_VREG_LP_MSME1_ID,
+	/* backward compatible enums only */
+	PM_VREG_LP_CAM_ID = PM_VREG_LP_GP1_ID,
+	PM_VREG_LP_MDDI_ID = PM_VREG_LP_GP2_ID,
+	PM_VREG_LP_RUIM2_ID = PM_VREG_LP_GP3_ID,
+	PM_VREG_LP_AUX_ID = PM_VREG_LP_GP4_ID,
+	PM_VREG_LP_AUX2_ID = PM_VREG_LP_GP5_ID,
+	PM_VREG_LP_BT_ID = PM_VREG_LP_GP6_ID,
+	PM_VREG_LP_MSMC_LDO_ID = PM_VREG_LP_MSMC_ID,
+	PM_VREG_LP_MSME1_LDO_ID = PM_VREG_LP_MSME1_ID,
+	PM_VREG_LP_MSME2_LDO_ID = PM_VREG_LP_MSME2_ID,
+	PM_VREG_LP_RFA1_ID = PM_VREG_LP_RFRX2_ID,
+	PM_VREG_LP_RFA2_ID = PM_VREG_LP_RFTX2_ID,
+	PM_VREG_LP_XO_ID = PM_VREG_LP_TCXO_ID
+};
+
+enum vreg_id {
+	PM_VREG_MSMA_ID = 0,
+	PM_VREG_MSMP_ID,
+	PM_VREG_MSME1_ID,
+	PM_VREG_MSMC1_ID,
+	PM_VREG_MSMC2_ID,
+	PM_VREG_GP3_ID,
+	PM_VREG_MSME2_ID,
+	PM_VREG_GP4_ID,
+	PM_VREG_GP1_ID,
+	PM_VREG_TCXO_ID,
+	PM_VREG_PA_ID,
+	PM_VREG_RFTX_ID,
+	PM_VREG_RFRX1_ID,
+	PM_VREG_RFRX2_ID,
+	PM_VREG_SYNT_ID,
+	PM_VREG_WLAN_ID,
+	PM_VREG_USB_ID,
+	PM_VREG_BOOST_ID,
+	PM_VREG_MMC_ID,
+	PM_VREG_RUIM_ID,
+	PM_VREG_MSMC0_ID,
+	PM_VREG_GP2_ID,
+	PM_VREG_GP5_ID,
+	PM_VREG_GP6_ID,
+	PM_VREG_RF_ID,
+	PM_VREG_RF_VCO_ID,
+	PM_VREG_MPLL_ID,
+	PM_VREG_S2_ID,
+	PM_VREG_S3_ID,
+	PM_VREG_RFUBM_ID,
+	PM_VREG_NCP_ID,
+	PM_VREG_RF2_ID,
+	PM_VREG_RFA_ID,
+	PM_VREG_CDC2_ID,
+	PM_VREG_RFTX2_ID,
+	PM_VREG_USIM_ID,
+	PM_VREG_USB2P6_ID,
+	PM_VREG_USB3P3_ID,
+	PM_VREG_EXTCDC1_ID,
+	PM_VREG_EXTCDC2_ID,
+
+	/* backward compatible enums only */
+	PM_VREG_MSME_ID = PM_VREG_MSME1_ID,
+	PM_VREG_MSME_BUCK_SMPS_ID = PM_VREG_MSME1_ID,
+	PM_VREG_MSME1_LDO_ID = PM_VREG_MSME1_ID,
+	PM_VREG_MSMC_ID = PM_VREG_MSMC1_ID,
+	PM_VREG_MSMC_LDO_ID = PM_VREG_MSMC1_ID,
+	PM_VREG_MSMC1_BUCK_SMPS_ID = PM_VREG_MSMC1_ID,
+	PM_VREG_MSME2_LDO_ID = PM_VREG_MSME2_ID,
+	PM_VREG_CAM_ID = PM_VREG_GP1_ID,
+	PM_VREG_MDDI_ID = PM_VREG_GP2_ID,
+	PM_VREG_RUIM2_ID = PM_VREG_GP3_ID,
+	PM_VREG_AUX_ID = PM_VREG_GP4_ID,
+	PM_VREG_AUX2_ID = PM_VREG_GP5_ID,
+	PM_VREG_BT_ID = PM_VREG_GP6_ID,
+	PM_VREG_RF1_ID = PM_VREG_RF_ID,
+	PM_VREG_S1_ID = PM_VREG_RF1_ID,
+	PM_VREG_5V_ID = PM_VREG_BOOST_ID,
+	PM_VREG_RFA1_ID = PM_VREG_RFRX2_ID,
+	PM_VREG_RFA2_ID = PM_VREG_RFTX2_ID,
+	PM_VREG_XO_ID = PM_VREG_TCXO_ID
+};
+
+enum vreg_pdown_id {
+	PM_VREG_PDOWN_MSMA_ID,
+	PM_VREG_PDOWN_MSMP_ID,
+	PM_VREG_PDOWN_MSME1_ID,
+	PM_VREG_PDOWN_MSMC1_ID,
+	PM_VREG_PDOWN_MSMC2_ID,
+	PM_VREG_PDOWN_GP3_ID,
+	PM_VREG_PDOWN_MSME2_ID,
+	PM_VREG_PDOWN_GP4_ID,
+	PM_VREG_PDOWN_GP1_ID,
+	PM_VREG_PDOWN_TCXO_ID,
+	PM_VREG_PDOWN_PA_ID,
+	PM_VREG_PDOWN_RFTX_ID,
+	PM_VREG_PDOWN_RFRX1_ID,
+	PM_VREG_PDOWN_RFRX2_ID,
+	PM_VREG_PDOWN_SYNT_ID,
+	PM_VREG_PDOWN_WLAN_ID,
+	PM_VREG_PDOWN_USB_ID,
+	PM_VREG_PDOWN_MMC_ID,
+	PM_VREG_PDOWN_RUIM_ID,
+	PM_VREG_PDOWN_MSMC0_ID,
+	PM_VREG_PDOWN_GP2_ID,
+	PM_VREG_PDOWN_GP5_ID,
+	PM_VREG_PDOWN_GP6_ID,
+	PM_VREG_PDOWN_RF_ID,
+	PM_VREG_PDOWN_RF_VCO_ID,
+	PM_VREG_PDOWN_MPLL_ID,
+	PM_VREG_PDOWN_S2_ID,
+	PM_VREG_PDOWN_S3_ID,
+	PM_VREG_PDOWN_RFUBM_ID,
+	/* new for HAN */
+	PM_VREG_PDOWN_RF1_ID,
+	PM_VREG_PDOWN_RF2_ID,
+	PM_VREG_PDOWN_RFA_ID,
+	PM_VREG_PDOWN_CDC2_ID,
+	PM_VREG_PDOWN_RFTX2_ID,
+	PM_VREG_PDOWN_USIM_ID,
+	PM_VREG_PDOWN_USB2P6_ID,
+	PM_VREG_PDOWN_USB3P3_ID,
+
+	/* backward compatible enums only */
+	PM_VREG_PDOWN_CAM_ID = PM_VREG_PDOWN_GP1_ID,
+	PM_VREG_PDOWN_MDDI_ID = PM_VREG_PDOWN_GP2_ID,
+	PM_VREG_PDOWN_RUIM2_ID = PM_VREG_PDOWN_GP3_ID,
+	PM_VREG_PDOWN_AUX_ID = PM_VREG_PDOWN_GP4_ID,
+	PM_VREG_PDOWN_AUX2_ID = PM_VREG_PDOWN_GP5_ID,
+	PM_VREG_PDOWN_BT_ID = PM_VREG_PDOWN_GP6_ID,
+	PM_VREG_PDOWN_MSME_ID = PM_VREG_PDOWN_MSME1_ID,
+	PM_VREG_PDOWN_MSMC_ID = PM_VREG_PDOWN_MSMC1_ID,
+	PM_VREG_PDOWN_RFA1_ID = PM_VREG_PDOWN_RFRX2_ID,
+	PM_VREG_PDOWN_RFA2_ID = PM_VREG_PDOWN_RFTX2_ID,
+	PM_VREG_PDOWN_XO_ID = PM_VREG_PDOWN_TCXO_ID
+};
+
+enum mpp_which {
+	PM_MPP_1,
+	PM_MPP_2,
+	PM_MPP_3,
+	PM_MPP_4,
+	PM_MPP_5,
+	PM_MPP_6,
+	PM_MPP_7,
+	PM_MPP_8,
+	PM_MPP_9,
+	PM_MPP_10,
+	PM_MPP_11,
+	PM_MPP_12,
+	PM_MPP_13,
+	PM_MPP_14,
+	PM_MPP_15,
+	PM_MPP_16,
+	PM_MPP_17,
+	PM_MPP_18,
+	PM_MPP_19,
+	PM_MPP_20,
+	PM_MPP_21,
+	PM_MPP_22,
+
+	PM_NUM_MPP_HAN = PM_MPP_4 + 1,
+	PM_NUM_MPP_KIP = PM_MPP_4 + 1,
+	PM_NUM_MPP_EPIC = PM_MPP_4 + 1,
+	PM_NUM_MPP_PM7500 = PM_MPP_22 + 1,
+	PM_NUM_MPP_PM6650 = PM_MPP_12 + 1,
+	PM_NUM_MPP_PM6658 = PM_MPP_12 + 1,
+	PM_NUM_MPP_PANORAMIX = PM_MPP_2 + 1,
+	PM_NUM_MPP_PM6640 = PM_NUM_MPP_PANORAMIX,
+	PM_NUM_MPP_PM6620 = PM_NUM_MPP_PANORAMIX
+};
+
+enum mpp_dlogic_level {
+	PM_MPP__DLOGIC__LVL_MSME,
+	PM_MPP__DLOGIC__LVL_MSMP,
+	PM_MPP__DLOGIC__LVL_RUIM,
+	PM_MPP__DLOGIC__LVL_MMC,
+	PM_MPP__DLOGIC__LVL_VDD,
+};
+
+enum mpp_dlogic_in_dbus {
+	PM_MPP__DLOGIC_IN__DBUS_NONE,
+	PM_MPP__DLOGIC_IN__DBUS1,
+	PM_MPP__DLOGIC_IN__DBUS2,
+	PM_MPP__DLOGIC_IN__DBUS3,
+};
+
+enum mpp_dlogic_out_ctrl {
+	PM_MPP__DLOGIC_OUT__CTRL_LOW,
+	PM_MPP__DLOGIC_OUT__CTRL_HIGH,
+	PM_MPP__DLOGIC_OUT__CTRL_MPP,
+	PM_MPP__DLOGIC_OUT__CTRL_NOT_MPP,
+};
+
+enum mpp_i_sink_level {
+	PM_MPP__I_SINK__LEVEL_5mA,
+	PM_MPP__I_SINK__LEVEL_10mA,
+	PM_MPP__I_SINK__LEVEL_15mA,
+	PM_MPP__I_SINK__LEVEL_20mA,
+	PM_MPP__I_SINK__LEVEL_25mA,
+	PM_MPP__I_SINK__LEVEL_30mA,
+	PM_MPP__I_SINK__LEVEL_35mA,
+	PM_MPP__I_SINK__LEVEL_40mA,
+};
+
+enum mpp_i_sink_switch {
+	PM_MPP__I_SINK__SWITCH_DIS,
+	PM_MPP__I_SINK__SWITCH_ENA,
+	PM_MPP__I_SINK__SWITCH_ENA_IF_MPP_HIGH,
+	PM_MPP__I_SINK__SWITCH_ENA_IF_MPP_LOW,
+};
+
+enum pm_vib_mot_mode {
+	PM_VIB_MOT_MODE__MANUAL,
+	PM_VIB_MOT_MODE__DBUS1,
+	PM_VIB_MOT_MODE__DBUS2,
+	PM_VIB_MOT_MODE__DBUS3,
+};
+
+enum pm_vib_mot_pol {
+	PM_VIB_MOT_POL__ACTIVE_HIGH,
+	PM_VIB_MOT_POL__ACTIVE_LOW,
+};
+
+struct rtc_time {
+	uint  sec;
+};
+
+enum rtc_alarm {
+	PM_RTC_ALARM_1,
+};
+
+enum hsed_controller {
+	PM_HSED_CONTROLLER_0,
+	PM_HSED_CONTROLLER_1,
+	PM_HSED_CONTROLLER_2,
+};
+
+enum hsed_switch {
+	PM_HSED_SC_SWITCH_TYPE,
+	PM_HSED_OC_SWITCH_TYPE,
+};
+
+enum hsed_enable {
+	PM_HSED_ENABLE_OFF,
+	PM_HSED_ENABLE_TCXO,
+	PM_HSED_ENABLE_PWM_TCXO,
+	PM_HSED_ENABLE_ALWAYS,
+};
+
+enum hsed_hyst_pre_div {
+	PM_HSED_HYST_PRE_DIV_1,
+	PM_HSED_HYST_PRE_DIV_2,
+	PM_HSED_HYST_PRE_DIV_4,
+	PM_HSED_HYST_PRE_DIV_8,
+	PM_HSED_HYST_PRE_DIV_16,
+	PM_HSED_HYST_PRE_DIV_32,
+	PM_HSED_HYST_PRE_DIV_64,
+	PM_HSED_HYST_PRE_DIV_128,
+};
+
+enum hsed_hyst_time {
+	PM_HSED_HYST_TIME_1_CLK_CYCLES,
+	PM_HSED_HYST_TIME_2_CLK_CYCLES,
+	PM_HSED_HYST_TIME_3_CLK_CYCLES,
+	PM_HSED_HYST_TIME_4_CLK_CYCLES,
+	PM_HSED_HYST_TIME_5_CLK_CYCLES,
+	PM_HSED_HYST_TIME_6_CLK_CYCLES,
+	PM_HSED_HYST_TIME_7_CLK_CYCLES,
+	PM_HSED_HYST_TIME_8_CLK_CYCLES,
+	PM_HSED_HYST_TIME_9_CLK_CYCLES,
+	PM_HSED_HYST_TIME_10_CLK_CYCLES,
+	PM_HSED_HYST_TIME_11_CLK_CYCLES,
+	PM_HSED_HYST_TIME_12_CLK_CYCLES,
+	PM_HSED_HYST_TIME_13_CLK_CYCLES,
+	PM_HSED_HYST_TIME_14_CLK_CYCLES,
+	PM_HSED_HYST_TIME_15_CLK_CYCLES,
+	PM_HSED_HYST_TIME_16_CLK_CYCLES,
+};
+
+enum hsed_period_pre_div {
+	PM_HSED_PERIOD_PRE_DIV_2,
+	PM_HSED_PERIOD_PRE_DIV_4,
+	PM_HSED_PERIOD_PRE_DIV_8,
+	PM_HSED_PERIOD_PRE_DIV_16,
+	PM_HSED_PERIOD_PRE_DIV_32,
+	PM_HSED_PERIOD_PRE_DIV_64,
+	PM_HSED_PERIOD_PRE_DIV_128,
+	PM_HSED_PERIOD_PRE_DIV_256,
+};
+
+enum hsed_period_time {
+	PM_HSED_PERIOD_TIME_1_CLK_CYCLES,
+	PM_HSED_PERIOD_TIME_2_CLK_CYCLES,
+	PM_HSED_PERIOD_TIME_3_CLK_CYCLES,
+	PM_HSED_PERIOD_TIME_4_CLK_CYCLES,
+	PM_HSED_PERIOD_TIME_5_CLK_CYCLES,
+	PM_HSED_PERIOD_TIME_6_CLK_CYCLES,
+	PM_HSED_PERIOD_TIME_7_CLK_CYCLES,
+	PM_HSED_PERIOD_TIME_8_CLK_CYCLES,
+	PM_HSED_PERIOD_TIME_9_CLK_CYCLES,
+	PM_HSED_PERIOD_TIME_10_CLK_CYCLES,
+	PM_HSED_PERIOD_TIME_11_CLK_CYCLES,
+	PM_HSED_PERIOD_TIME_12_CLK_CYCLES,
+	PM_HSED_PERIOD_TIME_13_CLK_CYCLES,
+	PM_HSED_PERIOD_TIME_14_CLK_CYCLES,
+	PM_HSED_PERIOD_TIME_15_CLK_CYCLES,
+	PM_HSED_PERIOD_TIME_16_CLK_CYCLES,
+};
+
+enum vreg_lpm_id {
+	VREG_GP1_ID,
+	VREG_GP2_ID,
+	VREG_GP3_ID,
+	VREG_GP4_ID,
+	VREG_GP5_ID,
+	VREG_GP6_ID,
+	VREG_GP7_ID,
+	VREG_GP8_ID,
+	VREG_GP9_ID,
+	VREG_GP10_ID,
+	VREG_GP11_ID,
+	VREG_GP12_ID,
+	VREG_GP13_ID,
+	VREG_GP14_ID,
+	VREG_GP15_ID,
+	VREG_GP16_ID,
+	VREG_GP17_ID,
+	VREG_MDDI_ID,
+	VREG_MPLL_ID,
+	VREG_MSMC1_ID,
+	VREG_MSMC2_ID,
+	VREG_MSME_ID,
+	VREG_RF_ID,
+	VREG_RF1_ID,
+	VREG_RF2_ID,
+	VREG_RFA_ID,
+	VREG_SDCC1_ID,
+	VREG_TCXO_ID,
+	VREG_USB1P8_ID,
+	VREG_USB3P3_ID,
+	VREG_USIM_ID,
+	VREG_WLAN1_ID,
+	VREG_WLAN2_ID,
+	VREG_XO_OUT_D0_ID,
+	VREG_NCP_ID,
+	VREG_LVSW0_ID,
+	VREG_LVSW1_ID,
+};
+
+enum low_current_led {
+	LOW_CURRENT_LED_DRV0,
+	LOW_CURRENT_LED_DRV1,
+	LOW_CURRENT_LED_DRV2,
+};
+
+enum ext_signal {
+	EXT_SIGNAL_CURRENT_SINK_MANUAL_MODE,
+	EXT_SIGNAL_CURRENT_SINK_PWM1,
+	EXT_SIGNAL_CURRENT_SINK_PWM2,
+	EXT_SIGNAL_CURRENT_SINK_PWM3,
+	EXT_SIGNAL_CURRENT_SINK_DTEST1,
+	EXT_SIGNAL_CURRENT_SINK_DTEST2,
+	EXT_SIGNAL_CURRENT_SINK_DTEST3,
+	EXT_SIGNAL_CURRENT_SINK_DTEST4,
+};
+
+enum high_current_led {
+	HIGH_CURRENT_LED_FLASH_DRV0,
+	HIGH_CURRENT_LED_FLASH_DRV1,
+	HIGH_CURRENT_LED_KBD_DRV,
+};
+
+/* PMIC GPIO */
+enum pmic_gpio {
+	PMIC_GPIO_1,
+	PMIC_GPIO_2,
+	PMIC_GPIO_3,
+	PMIC_GPIO_4,
+	PMIC_GPIO_5,
+	PMIC_GPIO_6,
+	PMIC_GPIO_7,
+	PMIC_GPIO_8,
+	PMIC_GPIO_9,
+	PMIC_GPIO_10,
+	PMIC_GPIO_11,
+};
+
+enum pmic_voltage_src {
+	PMIC_GPIO_VIN0,
+	PMIC_GPIO_VIN1,
+	PMIC_GPIO_VIN2,
+	PMIC_GPIO_VIN3,
+	PMIC_GPIO_VIN4,
+	PMIC_GPIO_VIN5,
+	PMIC_GPIO_VIN6,
+	PMIC_GPIO_VIN7,
+};
+
+enum pmic_io_mode {
+	INPUT_ON,
+	INPUT_OUTPUT_ON,
+	OUTPUT_ON,
+	INPUT_OUTPUT_OFF,
+};
+
+enum pmic_current_pull_up {
+	PULL_UP_30uA,
+	PULL_UP_1_5uA,
+	PULL_UP_31_5uA,
+	PULL_UP_1_5uA_PLUS_30uA_BOOST,
+	PULL_DOWN_10uA,
+	PULL_NO_PULL,
+};
+
+enum pmic_op_buf_drv_strength {
+	BUFFER_OFF,
+	BUFFER_HIGH,
+	BUFFER_MEDIUM,
+	BUFFER_LOW,
+};
+
+enum pmic_output_buffer_config {
+	CONFIG_CMOS,
+	CONFIG_OPEN_DRAIN,
+};
+
+enum pmic_dtest_buf_onoff {
+	DTEST_DISABLE,
+	DTEST_ENABLE,
+};
+
+enum pmic_ext_pin_config {
+	EXT_PIN_ENABLE,
+	/*! Puts EXT_PIN at high Z state & disables the block */
+	EXT_PIN_DISABLE,
+};
+
+enum pmic_source_config {
+	SOURCE_GND,
+	SOURCE_PAIRED_GPIO,
+	SOURCE_SPECIAL_FUNCTION1,
+	SOURCE_SPECIAL_FUNCTION2,
+	SOURCE_DTEST1,
+	SOURCE_DTEST2,
+	SOURCE_DTEST3,
+	SOURCE_DTEST4,
+};
+
+enum pmic_direction_mode {
+	MODE_INPUT,
+	MODE_OTPUT_AND_INPUT_ON,
+	MODE_OUTPUT,
+	MODE_INPUT_AND_OUTPUT_OFF,
+};
+
+struct pm8xxx_gpio_rpc_cfg {
+	enum pmic_gpio			gpio;
+	bool				config_gpio;
+	enum pmic_voltage_src		volt_src;
+	bool				mode_on;
+	enum pmic_io_mode		mode;
+	enum pmic_output_buffer_config	buf_config;
+	bool				invert_ext_pin;
+	enum pmic_current_pull_up	src_pull;
+	enum pmic_op_buf_drv_strength	drv_strength;
+	enum pmic_dtest_buf_onoff	dtest_on;
+	enum pmic_ext_pin_config	ext_config;
+	enum pmic_source_config		src_config;
+	bool				int_polarity;
+};
+
+int pmic_lp_mode_control(enum switch_cmd cmd, enum vreg_lp_id id);
+int pmic_vreg_set_level(enum vreg_id vreg, int level);
+int pmic_vreg_pull_down_switch(enum switch_cmd cmd, enum vreg_pdown_id id);
+int pmic_secure_mpp_control_digital_output(enum mpp_which which,
+		enum mpp_dlogic_level level, enum mpp_dlogic_out_ctrl out);
+int pmic_secure_mpp_config_i_sink(enum mpp_which which,
+		enum mpp_i_sink_level level, enum mpp_i_sink_switch onoff);
+int pmic_secure_mpp_config_digital_input(enum mpp_which	which,
+		enum mpp_dlogic_level level, enum mpp_dlogic_in_dbus dbus);
+int pmic_rtc_start(struct rtc_time *time);
+int pmic_rtc_stop(void);
+int pmic_rtc_get_time(struct rtc_time *time);
+int pmic_rtc_enable_alarm(enum rtc_alarm alarm,
+				struct rtc_time *time);
+int pmic_rtc_disable_alarm(enum rtc_alarm alarm);
+int pmic_rtc_get_alarm_time(enum rtc_alarm alarm,
+				struct rtc_time *time);
+int pmic_rtc_get_alarm_status(uint *status);
+int pmic_rtc_set_time_adjust(uint adjust);
+int pmic_rtc_get_time_adjust(uint *adjust);
+int pmic_speaker_cmd(const enum spkr_cmd cmd);
+int pmic_set_spkr_configuration(struct spkr_config_mode	*cfg);
+int pmic_get_spkr_configuration(struct spkr_config_mode	*cfg);
+int pmic_spkr_en_right_chan(uint enable);
+int pmic_spkr_is_right_chan_en(uint *enabled);
+int pmic_spkr_en_left_chan(uint enable);
+int pmic_spkr_is_left_chan_en(uint *enabled);
+int pmic_spkr_en(enum spkr_left_right left_right, uint enabled);
+int pmic_spkr_is_en(enum spkr_left_right left_right, uint *enabled);
+int pmic_spkr_set_gain(enum spkr_left_right left_right, enum spkr_gain gain);
+int pmic_spkr_get_gain(enum spkr_left_right left_right, enum spkr_gain *gain);
+int pmic_set_speaker_gain(enum spkr_gain gain);
+int pmic_set_speaker_delay(enum spkr_dly delay);
+int pmic_speaker_1k6_zin_enable(uint enable);
+int pmic_spkr_set_mux_hpf_corner_freq(enum spkr_hpf_corner_freq	freq);
+int pmic_spkr_get_mux_hpf_corner_freq(enum spkr_hpf_corner_freq	*freq);
+int pmic_spkr_select_usb_with_hpf_20hz(uint enable);
+int pmic_spkr_is_usb_with_hpf_20hz(uint *enabled);
+int pmic_spkr_bypass_mux(uint enable);
+int pmic_spkr_is_mux_bypassed(uint *enabled);
+int pmic_spkr_en_hpf(uint enable);
+int pmic_spkr_is_hpf_en(uint *enabled);
+int pmic_spkr_en_sink_curr_from_ref_volt_cir(uint enable);
+int pmic_spkr_is_sink_curr_from_ref_volt_cir_en(uint *enabled);
+int pmic_spkr_set_delay(enum spkr_left_right left_right, enum spkr_dly delay);
+int pmic_spkr_get_delay(enum spkr_left_right left_right, enum spkr_dly *delay);
+int pmic_spkr_en_mute(enum spkr_left_right left_right, uint enabled);
+int pmic_spkr_is_mute_en(enum spkr_left_right left_right, uint *enabled);
+int pmic_mic_en(uint enable);
+int pmic_mic_is_en(uint *enabled);
+int pmic_mic_set_volt(enum mic_volt vol);
+int pmic_mic_get_volt(enum mic_volt *voltage);
+int pmic_set_led_intensity(enum ledtype type, int level);
+int pmic_flash_led_set_current(uint16_t milliamps);
+int pmic_flash_led_set_mode(enum flash_led_mode mode);
+int pmic_flash_led_set_polarity(enum flash_led_pol pol);
+int pmic_spkr_add_right_left_chan(uint enable);
+int pmic_spkr_is_right_left_chan_added(uint *enabled);
+int pmic_spkr_en_stereo(uint enable);
+int pmic_spkr_is_stereo_en(uint	*enabled);
+int pmic_vib_mot_set_volt(uint vol);
+int pmic_vib_mot_set_mode(enum pm_vib_mot_mode mode);
+int pmic_vib_mot_set_polarity(enum pm_vib_mot_pol pol);
+int pmic_vid_en(uint enable);
+int pmic_vid_is_en(uint *enabled);
+int pmic_vid_load_detect_en(uint enable);
+
+int pmic_hsed_set_period(
+	enum hsed_controller controller,
+	enum hsed_period_pre_div period_pre_div,
+	enum hsed_period_time period_time
+);
+
+int pmic_hsed_set_hysteresis(
+	enum hsed_controller controller,
+	enum hsed_hyst_pre_div hyst_pre_div,
+	enum hsed_hyst_time hyst_time
+);
+
+int pmic_hsed_set_current_threshold(
+	enum hsed_controller controller,
+	enum hsed_switch switch_hsed,
+	uint32_t current_threshold
+);
+
+int pmic_hsed_enable(
+	enum hsed_controller controller,
+	enum hsed_enable enable
+);
+
+int pmic_high_current_led_set_current(enum high_current_led led,
+		uint16_t milliamps);
+int pmic_high_current_led_set_polarity(enum high_current_led led,
+		enum flash_led_pol polarity);
+int pmic_high_current_led_set_mode(enum high_current_led led,
+		enum flash_led_mode mode);
+int pmic_lp_force_lpm_control(enum switch_cmd cmd,
+		enum vreg_lpm_id vreg);
+int pmic_low_current_led_set_ext_signal(enum low_current_led led,
+		enum ext_signal sig);
+int pmic_low_current_led_set_current(enum low_current_led led,
+		uint16_t milliamps);
+
+int pmic_spkr_set_vsel_ldo(enum spkr_left_right left_right,
+					enum spkr_ldo_v_sel vlt_cntrl);
+int pmic_spkr_set_boost(enum spkr_left_right left_right, uint enable);
+int pmic_spkr_bypass_en(enum spkr_left_right left_right, uint enable);
+int pmic_hp_spkr_mstr_en(enum hp_spkr_left_right left_right, uint enable);
+int pmic_hp_spkr_mute_en(enum hp_spkr_left_right left_right, uint enable);
+int pmic_hp_spkr_prm_in_en(enum hp_spkr_left_right left_right, uint enable);
+int pmic_hp_spkr_aux_in_en(enum hp_spkr_left_right left_right, uint enable);
+int pmic_hp_spkr_ctrl_prm_gain_input(enum hp_spkr_left_right left_right,
+							uint prm_gain_ctl);
+int pmic_hp_spkr_ctrl_aux_gain_input(enum hp_spkr_left_right left_right,
+							uint aux_gain_ctl);
+int pmic_xo_core_force_enable(uint enable);
+int pmic_gpio_direction_input(unsigned gpio);
+int pmic_gpio_direction_output(unsigned gpio);
+int pmic_gpio_set_value(unsigned gpio, int value);
+int pmic_gpio_get_value(unsigned gpio);
+int pmic_gpio_get_direction(unsigned gpio);
+int pmic_gpio_config(struct pm8xxx_gpio_rpc_cfg *);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/proc_comm.h b/arch/arm/mach-msm/include/mach/proc_comm.h
new file mode 100644
index 0000000..8a0a218
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/proc_comm.h
@@ -0,0 +1,181 @@
+/* arch/arm/mach-msm/include/mach/proc_comm.h
+ *
+ * Copyright (c) 2007-2009,2011 Code Aurora Forum. 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 _ARCH_ARM_MACH_MSM_MSM_PROC_COMM_H_
+#define _ARCH_ARM_MACH_MSM_MSM_PROC_COMM_H_
+
+enum {
+	PCOM_CMD_IDLE = 0x0,
+	PCOM_CMD_DONE,
+	PCOM_RESET_APPS,
+	PCOM_RESET_CHIP,
+	PCOM_CONFIG_NAND_MPU,
+	PCOM_CONFIG_USB_CLKS,
+	PCOM_GET_POWER_ON_STATUS,
+	PCOM_GET_WAKE_UP_STATUS,
+	PCOM_GET_BATT_LEVEL,
+	PCOM_CHG_IS_CHARGING,
+	PCOM_POWER_DOWN,
+	PCOM_USB_PIN_CONFIG,
+	PCOM_USB_PIN_SEL,
+	PCOM_SET_RTC_ALARM,
+	PCOM_NV_READ,
+	PCOM_NV_WRITE,
+	PCOM_GET_UUID_HIGH,
+	PCOM_GET_UUID_LOW,
+	PCOM_GET_HW_ENTROPY,
+	PCOM_RPC_GPIO_TLMM_CONFIG_REMOTE,
+	PCOM_CLKCTL_RPC_ENABLE,
+	PCOM_CLKCTL_RPC_DISABLE,
+	PCOM_CLKCTL_RPC_RESET,
+	PCOM_CLKCTL_RPC_SET_FLAGS,
+	PCOM_CLKCTL_RPC_SET_RATE,
+	PCOM_CLKCTL_RPC_MIN_RATE,
+	PCOM_CLKCTL_RPC_MAX_RATE,
+	PCOM_CLKCTL_RPC_RATE,
+	PCOM_CLKCTL_RPC_PLL_REQUEST,
+	PCOM_CLKCTL_RPC_ENABLED,
+	PCOM_VREG_SWITCH,
+	PCOM_VREG_SET_LEVEL,
+	PCOM_GPIO_TLMM_CONFIG_GROUP,
+	PCOM_GPIO_TLMM_UNCONFIG_GROUP,
+	PCOM_NV_WRITE_BYTES_4_7,
+	PCOM_CONFIG_DISP,
+	PCOM_GET_FTM_BOOT_COUNT,
+	PCOM_RPC_GPIO_TLMM_CONFIG_EX,
+	PCOM_PM_MPP_CONFIG,
+	PCOM_GPIO_IN,
+	PCOM_GPIO_OUT,
+	PCOM_RESET_MODEM,
+	PCOM_RESET_CHIP_IMM,
+	PCOM_PM_VID_EN,
+	PCOM_VREG_PULLDOWN,
+	PCOM_GET_MODEM_VERSION,
+	PCOM_CLK_REGIME_SEC_RESET,
+	PCOM_CLK_REGIME_SEC_RESET_ASSERT,
+	PCOM_CLK_REGIME_SEC_RESET_DEASSERT,
+	PCOM_CLK_REGIME_SEC_PLL_REQUEST_WRP,
+	PCOM_CLK_REGIME_SEC_ENABLE,
+	PCOM_CLK_REGIME_SEC_DISABLE,
+	PCOM_CLK_REGIME_SEC_IS_ON,
+	PCOM_CLK_REGIME_SEC_SEL_CLK_INV,
+	PCOM_CLK_REGIME_SEC_SEL_CLK_SRC,
+	PCOM_CLK_REGIME_SEC_SEL_CLK_DIV,
+	PCOM_CLK_REGIME_SEC_ICODEC_CLK_ENABLE,
+	PCOM_CLK_REGIME_SEC_ICODEC_CLK_DISABLE,
+	PCOM_CLK_REGIME_SEC_SEL_SPEED,
+	PCOM_CLK_REGIME_SEC_CONFIG_GP_CLK_WRP,
+	PCOM_CLK_REGIME_SEC_CONFIG_MDH_CLK_WRP,
+	PCOM_CLK_REGIME_SEC_USB_XTAL_ON,
+	PCOM_CLK_REGIME_SEC_USB_XTAL_OFF,
+	PCOM_CLK_REGIME_SEC_SET_QDSP_DME_MODE,
+	PCOM_CLK_REGIME_SEC_SWITCH_ADSP_CLK,
+	PCOM_CLK_REGIME_SEC_GET_MAX_ADSP_CLK_KHZ,
+	PCOM_CLK_REGIME_SEC_GET_I2C_CLK_KHZ,
+	PCOM_CLK_REGIME_SEC_MSM_GET_CLK_FREQ_KHZ,
+	PCOM_CLK_REGIME_SEC_SEL_VFE_SRC,
+	PCOM_CLK_REGIME_SEC_MSM_SEL_CAMCLK,
+	PCOM_CLK_REGIME_SEC_MSM_SEL_LCDCLK,
+	PCOM_CLK_REGIME_SEC_VFE_RAIL_OFF,
+	PCOM_CLK_REGIME_SEC_VFE_RAIL_ON,
+	PCOM_CLK_REGIME_SEC_GRP_RAIL_OFF,
+	PCOM_CLK_REGIME_SEC_GRP_RAIL_ON,
+	PCOM_CLK_REGIME_SEC_VDC_RAIL_OFF,
+	PCOM_CLK_REGIME_SEC_VDC_RAIL_ON,
+	PCOM_CLK_REGIME_SEC_LCD_CTRL,
+	PCOM_CLK_REGIME_SEC_REGISTER_FOR_CPU_RESOURCE,
+	PCOM_CLK_REGIME_SEC_DEREGISTER_FOR_CPU_RESOURCE,
+	PCOM_CLK_REGIME_SEC_RESOURCE_REQUEST_WRP,
+	PCOM_CLK_REGIME_MSM_SEC_SEL_CLK_OWNER,
+	PCOM_CLK_REGIME_SEC_DEVMAN_REQUEST_WRP,
+	PCOM_GPIO_CONFIG,
+	PCOM_GPIO_CONFIGURE_GROUP,
+	PCOM_GPIO_TLMM_SET_PORT,
+	PCOM_GPIO_TLMM_CONFIG_EX,
+	PCOM_SET_FTM_BOOT_COUNT,
+	PCOM_RESERVED0,
+	PCOM_RESERVED1,
+	PCOM_CUSTOMER_CMD1,
+	PCOM_CUSTOMER_CMD2,
+	PCOM_CUSTOMER_CMD3,
+	PCOM_CLK_REGIME_ENTER_APPSBL_CHG_MODE,
+	PCOM_CLK_REGIME_EXIT_APPSBL_CHG_MODE,
+	PCOM_CLK_REGIME_SEC_RAIL_DISABLE,
+	PCOM_CLK_REGIME_SEC_RAIL_ENABLE,
+	PCOM_CLK_REGIME_SEC_RAIL_CONTROL,
+	PCOM_SET_SW_WATCHDOG_STATE,
+	PCOM_PM_MPP_CONFIG_DIGITAL_INPUT,
+	PCOM_PM_MPP_CONFIG_I_SINK,
+	PCOM_RESERVED_101,
+	PCOM_MSM_HSUSB_PHY_RESET,
+	PCOM_GET_BATT_MV_LEVEL,
+	PCOM_CHG_USB_IS_PC_CONNECTED,
+	PCOM_CHG_USB_IS_CHARGER_CONNECTED,
+	PCOM_CHG_USB_IS_DISCONNECTED,
+	PCOM_CHG_USB_IS_AVAILABLE,
+	PCOM_CLK_REGIME_SEC_MSM_SEL_FREQ,
+	PCOM_CLK_REGIME_SEC_SET_PCLK_AXI_POLICY,
+	PCOM_CLKCTL_RPC_RESET_ASSERT,
+	PCOM_CLKCTL_RPC_RESET_DEASSERT,
+	PCOM_CLKCTL_RPC_RAIL_ON,
+	PCOM_CLKCTL_RPC_RAIL_OFF,
+	PCOM_CLKCTL_RPC_RAIL_ENABLE,
+	PCOM_CLKCTL_RPC_RAIL_DISABLE,
+	PCOM_CLKCTL_RPC_RAIL_CONTROL,
+	PCOM_CLKCTL_RPC_MIN_MSMC1,
+	PCOM_CLKCTL_RPC_SRC_REQUEST,
+	PCOM_NPA_INIT,
+	PCOM_NPA_ISSUE_REQUIRED_REQUEST,
+	PCOM_CLKCTL_RPC_SET_EXT_CONFIG,
+};
+
+enum {
+	PCOM_OEM_FIRST_CMD = 0x10000000,
+	PCOM_OEM_TEST_CMD = PCOM_OEM_FIRST_CMD,
+
+	/* add OEM PROC COMM commands here */
+
+	PCOM_OEM_LAST = PCOM_OEM_TEST_CMD,
+};
+
+enum {
+	PCOM_INVALID_STATUS = 0x0,
+	PCOM_READY,
+	PCOM_CMD_RUNNING,
+	PCOM_CMD_SUCCESS,
+	PCOM_CMD_FAIL,
+	PCOM_CMD_FAIL_FALSE_RETURNED,
+	PCOM_CMD_FAIL_CMD_OUT_OF_BOUNDS_SERVER,
+	PCOM_CMD_FAIL_CMD_OUT_OF_BOUNDS_CLIENT,
+	PCOM_CMD_FAIL_CMD_UNREGISTERED,
+	PCOM_CMD_FAIL_CMD_LOCKED,
+	PCOM_CMD_FAIL_SERVER_NOT_YET_READY,
+	PCOM_CMD_FAIL_BAD_DESTINATION,
+	PCOM_CMD_FAIL_SERVER_RESET,
+	PCOM_CMD_FAIL_SMSM_NOT_INIT,
+	PCOM_CMD_FAIL_PROC_COMM_BUSY,
+	PCOM_CMD_FAIL_PROC_COMM_NOT_INIT,
+};
+
+#ifdef CONFIG_MSM_PROC_COMM
+void msm_proc_comm_reset_modem_now(void);
+int msm_proc_comm(unsigned cmd, unsigned *data1, unsigned *data2);
+#else
+static inline void msm_proc_comm_reset_modem_now(void) { }
+static inline int msm_proc_comm(unsigned cmd, unsigned *data1, unsigned *data2)
+{ return 0; }
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audplaycmdi.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audplaycmdi.h
new file mode 100644
index 0000000..575a286
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audplaycmdi.h
@@ -0,0 +1,129 @@
+#ifndef QDSP5AUDPLAYCMDI_H
+#define QDSP5AUDPLAYCMDI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+       Q D S P 5  A U D I O   P L A Y  T A S K   C O M M A N D S
+
+GENERAL DESCRIPTION
+  Command Interface for AUDPLAYTASK on QDSP5
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+
+  audplay_cmd_dec_data_avail
+    Send buffer to AUDPLAY task
+	
+  
+Copyright (c) 1992-2009, Code Aurora Forum. 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+$Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audplaycmdi.h#2 $
+  
+===========================================================================*/
+
+#define AUDPLAY_CMD_BITSTREAM_DATA_AVAIL		0x0000
+#define AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_LEN	\
+	sizeof(audplay_cmd_bitstream_data_avail)
+
+/* Type specification of dec_data_avail message sent to AUDPLAYTASK
+*/
+typedef struct {
+  /*command ID*/
+  unsigned int cmd_id;        
+
+  /* Decoder ID for which message is being sent */
+  unsigned int decoder_id;        
+
+  /* Start address of data in ARM global memory */
+  unsigned int buf_ptr;    
+
+  /* Number of 16-bit words of bit-stream data contiguously available at the
+   * above-mentioned address 
+   */
+  unsigned int buf_size;
+          
+  /* Partition number used by audPlayTask to communicate with DSP's RTOS
+   * kernel 
+  */
+  unsigned int partition_number;    
+
+} __attribute__((packed)) audplay_cmd_bitstream_data_avail;
+
+#define AUDPLAY_CMD_HPCM_BUF_CFG 0x0003
+#define AUDPLAY_CMD_HPCM_BUF_CFG_LEN \
+  sizeof(struct audplay_cmd_hpcm_buf_cfg)
+
+struct audplay_cmd_hpcm_buf_cfg {
+  unsigned int cmd_id;
+  unsigned int hostpcm_config;
+  unsigned int feedback_frequency;
+  unsigned int byte_swap;
+  unsigned int max_buffers;
+  unsigned int partition_number;
+} __attribute__((packed));
+
+#define AUDPLAY_CMD_BUFFER_REFRESH 0x0004
+#define AUDPLAY_CMD_BUFFER_REFRESH_LEN \
+  sizeof(struct audplay_cmd_buffer_update)
+
+struct audplay_cmd_buffer_refresh {
+  unsigned int cmd_id;
+  unsigned int num_buffers;
+  unsigned int buf_read_count;
+  unsigned int buf0_address;
+  unsigned int buf0_length;
+  unsigned int buf1_address;
+  unsigned int buf1_length;
+} __attribute__((packed));
+
+#define AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_NT2            0x0005
+#define AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_NT2_LEN    \
+	sizeof(audplay_cmd_bitstream_data_avail_nt2)
+
+/* Type specification of dec_data_avail message sent to AUDPLAYTASK
+ * for NT2 */
+struct audplay_cmd_bitstream_data_avail_nt2 {
+  /*command ID*/
+  unsigned int cmd_id;
+
+  /* Decoder ID for which message is being sent */
+  unsigned int decoder_id;
+
+  /* Start address of data in ARM global memory */
+  unsigned int buf_ptr;
+
+  /* Number of 16-bit words of bit-stream data contiguously available at the
+   * above-mentioned address
+   */
+  unsigned int buf_size;
+
+  /* Partition number used by audPlayTask to communicate with DSP's RTOS
+   * kernel
+   */
+  unsigned int partition_number;
+
+ /* bitstream write pointer */
+  unsigned int dspBitstreamWritePtr;
+
+} __attribute__((packed));
+
+#endif /* QDSP5AUDPLAYCMD_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audplaymsg.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audplaymsg.h
new file mode 100644
index 0000000..0bf2468
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audplaymsg.h
@@ -0,0 +1,84 @@
+#ifndef QDSP5AUDPLAYMSG_H
+#define QDSP5AUDPLAYMSG_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+       Q D S P 5  A U D I O   P L A Y  T A S K   M S G
+
+GENERAL DESCRIPTION
+  Message sent by AUDPLAY task
+
+REFERENCES
+  None
+
+  
+Copyright (c) 1992-2009, Code Aurora Forum. 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+  
+$Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audplaymsg.h#3 $
+
+===========================================================================*/
+#define AUDPLAY_MSG_DEC_NEEDS_DATA		0x0001
+#define AUDPLAY_MSG_DEC_NEEDS_DATA_MSG_LEN	\
+	sizeof(audplay_msg_dec_needs_data)
+
+typedef struct{
+   /* reserved*/
+  unsigned int dec_id;           
+
+  /*The read pointer offset of external memory till which bitstream 
+    has been dmeÂ’d in*/
+  unsigned int adecDataReadPtrOffset;  
+
+  /*	The buffer size of external memory. */
+  unsigned int adecDataBufSize;
+  
+  unsigned int 	bitstream_free_len;
+  unsigned int	bitstream_write_ptr;
+  unsigned int	bitstarem_buf_start;
+  unsigned int	bitstream_buf_len;
+} __attribute__((packed)) audplay_msg_dec_needs_data;
+
+#define AUDPLAY_UP_STREAM_INFO 0x0003
+#define AUDPLAY_UP_STREAM_INFO_LEN \
+  sizeof(struct audplay_msg_stream_info)
+
+struct audplay_msg_stream_info {
+  unsigned int decoder_id;
+  unsigned int channel_info;
+  unsigned int sample_freq;
+  unsigned int bitstream_info;
+  unsigned int bit_rate;
+} __attribute__((packed));
+
+#define AUDPLAY_MSG_BUFFER_UPDATE 0x0004
+#define AUDPLAY_MSG_BUFFER_UPDATE_LEN \
+  sizeof(struct audplay_msg_buffer_update)
+
+struct audplay_msg_buffer_update {
+  unsigned int buffer_write_count;
+  unsigned int num_of_buffer;
+  unsigned int buf0_address;
+  unsigned int buf0_length;
+  unsigned int buf1_address;
+  unsigned int buf1_length;
+} __attribute__((packed));
+
+#define ADSP_MESSAGE_ID 0xFFFF
+#endif /* QDSP5AUDPLAYMSG_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppcmdi.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppcmdi.h
new file mode 100644
index 0000000..86216d4
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppcmdi.h
@@ -0,0 +1,1037 @@
+#ifndef QDSP5AUDPPCMDI_H
+#define QDSP5AUDPPCMDI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+    A U D I O   P O S T   P R O C E S S I N G  I N T E R N A L  C O M M A N D S
+
+GENERAL DESCRIPTION
+  This file contains defintions of format blocks of commands 
+  that are accepted by AUDPP Task
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+
+Copyright(c) 1992-2009, 2012 Code Aurora Forum. 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+   
+$Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audppcmdi.h#2 $   
+  
+===========================================================================*/
+
+/*
+ * ARM to AUDPPTASK Commands 
+ *
+ * ARM uses three command queues to communicate with AUDPPTASK
+ * 1)uPAudPPCmd1Queue : Used for more frequent and shorter length commands
+ * 	Location : MEMA
+ * 	Buffer Size : 6 words
+ * 	No of buffers in a queue : 20 for gaming audio and 5 for other images
+ * 2)uPAudPPCmd2Queue : Used for commands which are not much lengthier
+ * 	Location : MEMA
+ * 	Buffer Size : 23
+ * 	No of buffers in a queue : 2
+ * 3)uPAudOOCmd3Queue : Used for lengthier and more frequent commands
+ * 	Location : MEMA
+ * 	Buffer Size : 145
+ * 	No of buffers in a queue : 3
+ */
+
+/*
+ * Commands Related to uPAudPPCmd1Queue
+ */
+
+/*
+ * Command Structure to enable or disable the active decoders 
+ */
+
+#define AUDPP_CMD_CFG_DEC_TYPE 		0x0001
+#define AUDPP_CMD_CFG_DEC_TYPE_LEN 	sizeof(audpp_cmd_cfg_dec_type)
+
+/* Enable the decoder */
+#define AUDPP_CMD_DEC_TYPE_M           	0x000F
+
+#define AUDPP_CMD_ENA_DEC_V         	0x4000
+#define AUDPP_CMD_DIS_DEC_V        	0x0000
+#define AUDPP_CMD_DEC_STATE_M          	0x4000
+
+#define AUDPP_CMD_UPDATDE_CFG_DEC	0x8000
+#define AUDPP_CMD_DONT_UPDATE_CFG_DEC	0x0000
+
+
+/* Type specification of cmd_cfg_dec */
+ 
+typedef struct {
+  unsigned short cmd_id;
+  unsigned short dec0_cfg;
+  unsigned short dec1_cfg;
+  unsigned short dec2_cfg;
+  unsigned short dec3_cfg;
+  unsigned short dec4_cfg;
+} __attribute__((packed)) audpp_cmd_cfg_dec_type;
+
+/*
+ * Command Structure to Pause , Resume and flushes the selected audio decoders
+ */
+
+#define AUDPP_CMD_DEC_CTRL		0x0002
+#define AUDPP_CMD_DEC_CTRL_LEN		sizeof(audpp_cmd_dec_ctrl)
+
+/* Decoder control commands for pause, resume and flush */
+#define AUDPP_CMD_FLUSH_V         		0x2000
+
+#define AUDPP_CMD_PAUSE_V		        0x4000
+#define AUDPP_CMD_RESUME_V		        0x0000
+
+#define AUDPP_CMD_UPDATE_V		        0x8000
+#define AUDPP_CMD_IGNORE_V		        0x0000
+
+
+/* Type Spec for decoder control command*/
+
+typedef struct {
+  unsigned short cmd_id;
+  unsigned short dec0_ctrl;
+  unsigned short dec1_ctrl;
+  unsigned short dec2_ctrl;
+  unsigned short dec3_ctrl;
+  unsigned short dec4_ctrl;
+} __attribute__((packed)) audpp_cmd_dec_ctrl;
+
+/*
+ * Command Structure to Configure the AVSync FeedBack Mechanism
+ */
+
+#define AUDPP_CMD_AVSYNC	0x0003
+#define AUDPP_CMD_AVSYNC_LEN	sizeof(audpp_cmd_avsync)
+
+typedef struct {
+	unsigned short cmd_id;
+	unsigned short object_number;
+	unsigned short interrupt_interval_lsw;
+	unsigned short interrupt_interval_msw;
+} __attribute__((packed)) audpp_cmd_avsync;
+
+/*
+ * Command Structure to enable or disable(sleep) the   AUDPPTASK 
+ */
+
+#define AUDPP_CMD_CFG	0x0004
+#define AUDPP_CMD_CFG_LEN	sizeof(audpp_cmd_cfg)
+
+#define AUDPP_CMD_CFG_SLEEP   				0x0000
+#define AUDPP_CMD_CFG_ENABLE  				0xFFFF
+
+typedef struct {
+  unsigned short cmd_id;
+  unsigned short cfg;
+} __attribute__((packed)) audpp_cmd_cfg;
+
+/*
+ * Command Structure to Inject or drop the specified no of samples
+ */
+
+#define AUDPP_CMD_ADJUST_SAMP		0x0005
+#define AUDPP_CMD_ADJUST_SAMP_LEN	sizeof(audpp_cmd_adjust_samp)
+
+#define AUDPP_CMD_SAMP_DROP		-1
+#define AUDPP_CMD_SAMP_INSERT		0x0001
+
+#define AUDPP_CMD_NUM_SAMPLES		0x0001
+
+typedef struct {
+	unsigned short cmd_id;
+	unsigned short object_no;
+	signed short sample_insert_or_drop;
+	unsigned short num_samples;
+} __attribute__((packed)) audpp_cmd_adjust_samp;
+
+/*
+ * Command Structure to Configure AVSync Feedback Mechanism
+ */
+
+#define AUDPP_CMD_AVSYNC_CMD_2		0x0006
+#define AUDPP_CMD_AVSYNC_CMD_2_LEN	sizeof(audpp_cmd_avsync_cmd_2)
+
+typedef struct {
+	unsigned short cmd_id;
+	unsigned short object_number;
+	unsigned short interrupt_interval_lsw;
+	unsigned short interrupt_interval_msw;
+	unsigned short sample_counter_dlsw;
+	unsigned short sample_counter_dmsw;
+	unsigned short sample_counter_msw;
+	unsigned short byte_counter_dlsw;
+	unsigned short byte_counter_dmsw;
+	unsigned short byte_counter_msw;
+} __attribute__((packed)) audpp_cmd_avsync_cmd_2;
+
+/*
+ * Command Structure to Configure AVSync Feedback Mechanism
+ */
+
+#define AUDPP_CMD_AVSYNC_CMD_3		0x0007
+#define AUDPP_CMD_AVSYNC_CMD_3_LEN	sizeof(audpp_cmd_avsync_cmd_3)
+
+typedef struct {
+	unsigned short cmd_id;
+	unsigned short object_number;
+	unsigned short interrupt_interval_lsw;
+	unsigned short interrupt_interval_msw;
+	unsigned short sample_counter_dlsw;
+	unsigned short sample_counter_dmsw;
+	unsigned short sample_counter_msw;
+	unsigned short byte_counter_dlsw;
+	unsigned short byte_counter_dmsw;
+	unsigned short byte_counter_msw;
+} __attribute__((packed)) audpp_cmd_avsync_cmd_3;
+
+#define AUDPP_CMD_ROUTING_MODE      0x0008
+#define AUDPP_CMD_ROUTING_MODE_LEN  \
+sizeof(struct audpp_cmd_routing_mode)
+
+struct audpp_cmd_routing_mode {
+  unsigned short cmd_id;
+  unsigned short object_number;
+  unsigned short routing_mode;
+} __attribute__((packed));
+
+/*
+ * Commands Related to uPAudPPCmd2Queue
+ */
+
+/*
+ * Command Structure to configure Per decoder Parameters (Common)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS 		0x0000
+#define AUDPP_CMD_CFG_ADEC_PARAMS_COMMON_LEN	\
+	sizeof(audpp_cmd_cfg_adec_params_common)
+
+#define AUDPP_CMD_STATUS_MSG_FLAG_ENA_FCM	0x4000
+#define AUDPP_CMD_STATUS_MSG_FLAG_DIS_FCM	0x0000
+
+#define AUDPP_CMD_STATUS_MSG_FLAG_ENA_DCM	0x8000
+#define AUDPP_CMD_STATUS_MSG_FLAG_DIS_DCM	0x0000
+
+/* Sampling frequency*/
+#define  AUDPP_CMD_SAMP_RATE_96000 	0x0000
+#define  AUDPP_CMD_SAMP_RATE_88200 	0x0001
+#define  AUDPP_CMD_SAMP_RATE_64000 	0x0002
+#define  AUDPP_CMD_SAMP_RATE_48000 	0x0003
+#define  AUDPP_CMD_SAMP_RATE_44100 	0x0004
+#define  AUDPP_CMD_SAMP_RATE_32000 	0x0005
+#define  AUDPP_CMD_SAMP_RATE_24000 	0x0006
+#define  AUDPP_CMD_SAMP_RATE_22050 	0x0007
+#define  AUDPP_CMD_SAMP_RATE_16000 	0x0008
+#define  AUDPP_CMD_SAMP_RATE_12000 	0x0009
+#define  AUDPP_CMD_SAMP_RATE_11025 	0x000A
+#define  AUDPP_CMD_SAMP_RATE_8000  	0x000B
+
+
+/* 
+ * Type specification of cmd_adec_cfg sent to all decoder
+ */
+
+typedef struct {
+  unsigned short cmd_id;
+  unsigned short  length;
+  unsigned short  dec_id;
+  unsigned short  status_msg_flag;
+  unsigned short  decoder_frame_counter_msg_period;
+  unsigned short  input_sampling_frequency;
+} __attribute__((packed)) audpp_cmd_cfg_adec_params_common;
+
+/*
+ * Command Structure to configure Per decoder Parameters (Wav)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_WAV_LEN	\
+	sizeof(audpp_cmd_cfg_adec_params_wav)
+
+
+#define	AUDPP_CMD_WAV_STEREO_CFG_MONO	0x0001
+#define AUDPP_CMD_WAV_STEREO_CFG_STEREO	0x0002
+
+#define AUDPP_CMD_WAV_PCM_WIDTH_8	0x0000
+#define AUDPP_CMD_WAV_PCM_WIDTH_16	0x0001
+#define AUDPP_CMD_WAV_PCM_WIDTH_24	0x0002
+
+typedef struct {
+	audpp_cmd_cfg_adec_params_common		common;
+	unsigned short					stereo_cfg;
+	unsigned short					pcm_width;
+	unsigned short 					sign;
+} __attribute__((packed)) audpp_cmd_cfg_adec_params_wav;
+
+/*
+ * Command Structure to configure Per decoder Parameters (ADPCM)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_ADPCM_LEN	\
+	sizeof(audpp_cmd_cfg_adec_params_adpcm)
+
+
+#define	AUDPP_CMD_ADPCM_STEREO_CFG_MONO		0x0001
+#define AUDPP_CMD_ADPCM_STEREO_CFG_STEREO	0x0002
+
+typedef struct {
+	audpp_cmd_cfg_adec_params_common		common;
+	unsigned short					stereo_cfg;
+	unsigned short 					block_size;
+} __attribute__((packed)) audpp_cmd_cfg_adec_params_adpcm;
+
+/*
+ * Command Structure to configure Per decoder Parameters (WMA)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_WMA_LEN	\
+	sizeof(struct audpp_cmd_cfg_adec_params_wma)
+
+struct audpp_cmd_cfg_adec_params_wma {
+	audpp_cmd_cfg_adec_params_common    common;
+	unsigned short 	armdatareqthr;
+	unsigned short 	channelsdecoded;
+	unsigned short 	wmabytespersec;
+	unsigned short	wmasamplingfreq;
+	unsigned short	wmaencoderopts;
+} __attribute__((packed));
+
+/*
+ * Command Structure to configure Per decoder Parameters (WMAPRO)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_WMAPRO_LEN	\
+	sizeof(struct audpp_cmd_cfg_adec_params_wmapro)
+
+struct audpp_cmd_cfg_adec_params_wmapro {
+	audpp_cmd_cfg_adec_params_common    common;
+	unsigned short 	armdatareqthr;
+	uint8_t         validbitspersample;
+	uint8_t         numchannels;
+	unsigned short  formattag;
+	unsigned short  samplingrate;
+	unsigned short  avgbytespersecond;
+	unsigned short  asfpacketlength;
+	unsigned short 	channelmask;
+	unsigned short 	encodeopt;
+	unsigned short	advancedencodeopt;
+	uint32_t	advancedencodeopt2;
+} __attribute__((packed));
+
+/*
+ * Command Structure to configure Per decoder Parameters (MP3)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_MP3_LEN	\
+	sizeof(audpp_cmd_cfg_adec_params_mp3)
+
+typedef struct {
+   audpp_cmd_cfg_adec_params_common    common;
+} __attribute__((packed)) audpp_cmd_cfg_adec_params_mp3;
+
+
+/*
+ * Command Structure to configure Per decoder Parameters (AAC)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_AAC_LEN	\
+	sizeof(audpp_cmd_cfg_adec_params_aac)
+
+
+#define AUDPP_CMD_AAC_FORMAT_ADTS		-1
+#define	AUDPP_CMD_AAC_FORMAT_RAW		0x0000
+#define	AUDPP_CMD_AAC_FORMAT_PSUEDO_RAW		0x0001
+#define	AUDPP_CMD_AAC_FORMAT_LOAS		0x0002
+
+#define AUDPP_CMD_AAC_AUDIO_OBJECT_LC		0x0002
+#define AUDPP_CMD_AAC_AUDIO_OBJECT_LTP		0x0004
+#define AUDPP_CMD_AAC_AUDIO_OBJECT_ERLC	0x0011
+
+#define AUDPP_CMD_AAC_SBR_ON_FLAG_ON		0x0001
+#define AUDPP_CMD_AAC_SBR_ON_FLAG_OFF		0x0000
+
+#define AUDPP_CMD_AAC_SBR_PS_ON_FLAG_ON		0x0001
+#define AUDPP_CMD_AAC_SBR_PS_ON_FLAG_OFF	0x0000
+
+typedef struct {
+  audpp_cmd_cfg_adec_params_common	common;
+  signed short				format;
+  unsigned short			audio_object;
+  unsigned short			ep_config;
+  unsigned short                        aac_section_data_resilience_flag;
+  unsigned short                        aac_scalefactor_data_resilience_flag;
+  unsigned short                        aac_spectral_data_resilience_flag;
+  unsigned short                        sbr_on_flag;
+  unsigned short                        sbr_ps_on_flag;
+  unsigned short                        channel_configuration;
+} __attribute__((packed)) audpp_cmd_cfg_adec_params_aac;
+
+/*
+ * Command Structure to configure Per decoder Parameters (V13K)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_V13K_LEN	\
+	sizeof(struct audpp_cmd_cfg_adec_params_v13k)
+
+
+#define AUDPP_CMD_STEREO_CFG_MONO		0x0001
+#define AUDPP_CMD_STEREO_CFG_STEREO		0x0002
+
+struct audpp_cmd_cfg_adec_params_v13k {
+   audpp_cmd_cfg_adec_params_common    	common;
+   unsigned short			stereo_cfg;
+} __attribute__((packed));
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_EVRC_LEN \
+	sizeof(struct audpp_cmd_cfg_adec_params_evrc)
+
+struct audpp_cmd_cfg_adec_params_evrc {
+	audpp_cmd_cfg_adec_params_common common;
+	unsigned short stereo_cfg;
+} __attribute__ ((packed));
+
+/*
+ * Command Structure to configure Per decoder Parameters (AMRWB)
+ */
+
+struct audpp_cmd_cfg_adec_params_amrwb {
+	   audpp_cmd_cfg_adec_params_common     common;
+	      unsigned short                       stereo_cfg;
+} __attribute__((packed)) ;
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_AMRWB_LEN \
+	sizeof(struct audpp_cmd_cfg_adec_params_amrwb)
+
+/*
+ * Command Structure to configure the  HOST PCM interface
+ */
+
+#define AUDPP_CMD_PCM_INTF	0x0001
+#define AUDPP_CMD_PCM_INTF_2	0x0002
+#define AUDPP_CMD_PCM_INTF_LEN	sizeof(audpp_cmd_pcm_intf)
+
+#define AUDPP_CMD_PCM_INTF_MONO_V		        0x0001
+#define AUDPP_CMD_PCM_INTF_STEREO_V         	0x0002
+
+/* These two values differentiate the two types of commands that could be issued
+ * Interface configuration command and Buffer update command */
+
+#define AUDPP_CMD_PCM_INTF_CONFIG_CMD_V	       	0x0000
+#define AUDPP_CMD_PCM_INTF_BUFFER_CMD_V	        -1
+
+#define AUDPP_CMD_PCM_INTF_RX_ENA_M              0x000F
+#define AUDPP_CMD_PCM_INTF_RX_ENA_ARMTODSP_V     0x0008
+#define AUDPP_CMD_PCM_INTF_RX_ENA_DSPTOARM_V     0x0004
+
+/* These flags control the enabling and disabling of the interface together
+ *  with host interface bit mask. */
+
+#define AUDPP_CMD_PCM_INTF_ENA_V            -1
+#define AUDPP_CMD_PCM_INTF_DIS_V            0x0000
+
+
+#define  AUDPP_CMD_PCM_INTF_FULL_DUPLEX           0x0
+#define  AUDPP_CMD_PCM_INTF_HALF_DUPLEX_TODSP     0x1
+
+
+#define  AUDPP_CMD_PCM_INTF_OBJECT_NUM           0x5
+#define  AUDPP_CMD_PCM_INTF_COMMON_OBJECT_NUM    0x6
+  
+
+typedef struct {
+  unsigned short  cmd_id;
+  unsigned short  object_num;
+  signed short  config;
+  unsigned short  intf_type;
+  
+  /* DSP -> ARM Configuration */
+  unsigned short  read_buf1LSW;
+  unsigned short  read_buf1MSW;
+  unsigned short  read_buf1_len;
+
+  unsigned short  read_buf2LSW;
+  unsigned short  read_buf2MSW;
+  unsigned short  read_buf2_len;
+  /*   0:HOST_PCM_INTF disable
+   **  0xFFFF: HOST_PCM_INTF enable
+   */
+  signed short  dsp_to_arm_flag;
+  unsigned short  partition_number;
+
+  /* ARM -> DSP Configuration */
+  unsigned short  write_buf1LSW;
+  unsigned short  write_buf1MSW;
+  unsigned short  write_buf1_len;
+ 
+  unsigned short  write_buf2LSW;
+  unsigned short  write_buf2MSW;
+  unsigned short  write_buf2_len;
+
+  /*   0:HOST_PCM_INTF disable
+   **  0xFFFF: HOST_PCM_INTF enable
+   */
+  signed short  arm_to_rx_flag;
+  unsigned short  weight_decoder_to_rx;
+  unsigned short  weight_arm_to_rx;
+
+  unsigned short  partition_number_arm_to_dsp;
+  unsigned short  sample_rate;
+  unsigned short  channel_mode;
+} __attribute__((packed)) audpp_cmd_pcm_intf;
+
+/*
+ **  BUFFER UPDATE COMMAND
+ */
+#define AUDPP_CMD_PCM_INTF_SEND_BUF_PARAMS_LEN	\
+	sizeof(audpp_cmd_pcm_intf_send_buffer)
+
+typedef struct {
+  unsigned short  cmd_id;
+  unsigned short  host_pcm_object;
+  /* set config = 0xFFFF for configuration*/
+  signed short  config;
+  unsigned short  intf_type;
+  unsigned short  dsp_to_arm_buf_id;
+  unsigned short  arm_to_dsp_buf_id;
+  unsigned short  arm_to_dsp_buf_len;
+} __attribute__((packed)) audpp_cmd_pcm_intf_send_buffer;
+
+
+/*
+ * Commands Related to uPAudPPCmd3Queue
+ */
+
+/*
+ * Command Structure to configure post processing params (Commmon)
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS		0x0000
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN		\
+	sizeof(audpp_cmd_cfg_object_params_common)
+
+#define AUDPP_CMD_OBJ0_UPDATE		0x8000
+#define AUDPP_CMD_OBJ0_DONT_UPDATE	0x0000
+
+#define AUDPP_CMD_OBJ1_UPDATE		0x8000
+#define AUDPP_CMD_OBJ1_DONT_UPDATE	0x0000
+
+#define AUDPP_CMD_OBJ2_UPDATE		0x8000
+#define AUDPP_CMD_OBJ2_DONT_UPDATE	0x0000
+
+#define AUDPP_CMD_OBJ3_UPDATE		0x8000
+#define AUDPP_CMD_OBJ3_DONT_UPDATE	0x0000
+
+#define AUDPP_CMD_OBJ4_UPDATE		0x8000
+#define AUDPP_CMD_OBJ4_DONT_UPDATE	0x0000
+
+#define AUDPP_CMD_HPCM_UPDATE		0x8000
+#define AUDPP_CMD_HPCM_DONT_UPDATE	0x0000
+
+#define AUDPP_CMD_COMMON_CFG_UPDATE		0x8000
+#define AUDPP_CMD_COMMON_CFG_DONT_UPDATE	0x0000
+
+typedef struct {
+	unsigned short  cmd_id;
+	unsigned short	obj0_cfg;
+	unsigned short	obj1_cfg;
+	unsigned short	obj2_cfg;
+	unsigned short	obj3_cfg;
+	unsigned short	obj4_cfg;
+	unsigned short	host_pcm_obj_cfg;
+	unsigned short	comman_cfg;
+	unsigned short  command_type;
+} __attribute__((packed)) audpp_cmd_cfg_object_params_common;
+
+/*
+ * Command Structure to configure post processing params (Volume)
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_VOLUME_LEN		\
+	sizeof(audpp_cmd_cfg_object_params_volume)
+
+typedef struct {
+	audpp_cmd_cfg_object_params_common 	common;
+	unsigned short					volume;
+	unsigned short					pan;
+} __attribute__((packed)) audpp_cmd_cfg_object_params_volume;
+
+/*
+ * Command Structure to configure post processing params (PCM Filter) --DOUBT
+ */
+
+typedef struct {
+	unsigned short			numerator_b0_filter_lsw;
+	unsigned short			numerator_b0_filter_msw;
+	unsigned short			numerator_b1_filter_lsw;
+	unsigned short			numerator_b1_filter_msw;
+	unsigned short			numerator_b2_filter_lsw;
+	unsigned short			numerator_b2_filter_msw;
+} __attribute__((packed)) numerator;
+
+typedef struct {
+	unsigned short			denominator_a0_filter_lsw;
+	unsigned short			denominator_a0_filter_msw;
+	unsigned short			denominator_a1_filter_lsw;
+	unsigned short			denominator_a1_filter_msw;
+} __attribute__((packed)) denominator;
+
+typedef struct {
+	unsigned short			shift_factor_0;
+} __attribute__((packed)) shift_factor;
+
+typedef struct {
+	unsigned short			pan_filter_0;
+} __attribute__((packed)) pan;
+
+typedef struct {
+		numerator		numerator_filter;
+		denominator		denominator_filter;
+		shift_factor		shift_factor_filter;
+		pan			pan_filter;
+} __attribute__((packed)) filter_1;
+
+typedef struct {
+		numerator		numerator_filter[2];
+		denominator		denominator_filter[2];
+		shift_factor		shift_factor_filter[2];
+		pan			pan_filter[2];
+} __attribute__((packed)) filter_2;
+
+typedef struct {
+		numerator		numerator_filter[3];
+		denominator		denominator_filter[3];
+		shift_factor		shift_factor_filter[3];
+		pan			pan_filter[3];
+} __attribute__((packed)) filter_3;
+
+typedef struct {
+		numerator		numerator_filter[4];
+		denominator		denominator_filter[4];
+		shift_factor		shift_factor_filter[4];
+		pan			pan_filter[4];
+} __attribute__((packed)) filter_4;
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_PCM_LEN		\
+	sizeof(audpp_cmd_cfg_object_params_pcm)
+
+
+typedef struct {
+	audpp_cmd_cfg_object_params_common 	common;
+	unsigned short				active_flag;
+	unsigned short 				num_bands;
+	union {
+		filter_1			filter_1_params;
+		filter_2			filter_2_params;
+		filter_3			filter_3_params;
+		filter_4			filter_4_params;
+	} __attribute__((packed)) params_filter;
+} __attribute__((packed)) audpp_cmd_cfg_object_params_pcm;
+
+
+/*
+ * Command Structure to configure post processing parameters (equalizer) 
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_EQALIZER_LEN		\
+	sizeof(audpp_cmd_cfg_object_params_eqalizer)
+
+typedef struct {
+	unsigned short			numerator_coeff_0_lsw;
+	unsigned short			numerator_coeff_0_msw;
+	unsigned short			numerator_coeff_1_lsw;
+	unsigned short			numerator_coeff_1_msw;
+	unsigned short			numerator_coeff_2_lsw;
+	unsigned short			numerator_coeff_2_msw;
+} __attribute__((packed)) eq_numerator;
+
+typedef struct {
+	unsigned short			denominator_coeff_0_lsw;
+	unsigned short			denominator_coeff_0_msw;
+	unsigned short			denominator_coeff_1_lsw;
+	unsigned short			denominator_coeff_1_msw;
+} __attribute__((packed)) eq_denominator;
+
+typedef struct {
+	unsigned short			shift_factor;
+} __attribute__((packed)) eq_shiftfactor;
+
+typedef struct {
+	eq_numerator	numerator;
+	eq_denominator	denominator;
+	eq_shiftfactor	shiftfactor;
+} __attribute__((packed)) eq_coeff_1;
+
+typedef struct {
+	eq_numerator	numerator[2];
+	eq_denominator	denominator[2];
+	eq_shiftfactor	shiftfactor[2];
+} __attribute__((packed)) eq_coeff_2;
+
+typedef struct {
+	eq_numerator	numerator[3];
+	eq_denominator	denominator[3];
+	eq_shiftfactor	shiftfactor[3];
+} __attribute__((packed)) eq_coeff_3;
+
+typedef struct {
+	eq_numerator	numerator[4];
+	eq_denominator	denominator[4];
+	eq_shiftfactor	shiftfactor[4];
+} __attribute__((packed)) eq_coeff_4;
+
+typedef struct {
+	eq_numerator	numerator[5];
+	eq_denominator	denominator[5];
+	eq_shiftfactor	shiftfactor[5];
+} __attribute__((packed)) eq_coeff_5;
+
+typedef struct {
+	eq_numerator	numerator[6];
+	eq_denominator	denominator[6];
+	eq_shiftfactor	shiftfactor[6];
+} __attribute__((packed)) eq_coeff_6;
+
+typedef struct {
+	eq_numerator	numerator[7];
+	eq_denominator	denominator[7];
+	eq_shiftfactor	shiftfactor[7];
+} __attribute__((packed)) eq_coeff_7;
+
+typedef struct {
+	eq_numerator	numerator[8];
+	eq_denominator	denominator[8];
+	eq_shiftfactor	shiftfactor[8];
+} __attribute__((packed)) eq_coeff_8;
+
+typedef struct {
+	eq_numerator	numerator[9];
+	eq_denominator	denominator[9];
+	eq_shiftfactor	shiftfactor[9];
+} __attribute__((packed)) eq_coeff_9;
+
+typedef struct {
+	eq_numerator	numerator[10];
+	eq_denominator	denominator[10];
+	eq_shiftfactor	shiftfactor[10];
+} __attribute__((packed)) eq_coeff_10;
+
+typedef struct {
+	eq_numerator	numerator[11];
+	eq_denominator	denominator[11];
+	eq_shiftfactor	shiftfactor[11];
+} __attribute__((packed)) eq_coeff_11;
+
+typedef struct {
+	eq_numerator	numerator[12];
+	eq_denominator	denominator[12];
+	eq_shiftfactor	shiftfactor[12];
+} __attribute__((packed)) eq_coeff_12;
+
+
+typedef struct {
+	audpp_cmd_cfg_object_params_common 	common;
+	unsigned short				eq_flag;
+	unsigned short				num_bands;
+	union {
+		eq_coeff_1	eq_coeffs_1;
+		eq_coeff_2	eq_coeffs_2;
+		eq_coeff_3	eq_coeffs_3;
+		eq_coeff_4	eq_coeffs_4;
+		eq_coeff_5	eq_coeffs_5;
+		eq_coeff_6	eq_coeffs_6;
+		eq_coeff_7	eq_coeffs_7;
+		eq_coeff_8	eq_coeffs_8;
+		eq_coeff_9	eq_coeffs_9;
+		eq_coeff_10	eq_coeffs_10;
+		eq_coeff_11	eq_coeffs_11;
+		eq_coeff_12	eq_coeffs_12;
+	} __attribute__((packed)) eq_coeff;
+} __attribute__((packed)) audpp_cmd_cfg_object_params_eqalizer;
+
+
+/*
+ * Command Structure to configure post processing parameters (ADRC) 
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_ADRC_LEN		\
+	sizeof(audpp_cmd_cfg_object_params_adrc)
+
+
+#define AUDPP_CMD_ADRC_FLAG_DIS		0x0000
+#define AUDPP_CMD_ADRC_FLAG_ENA		-1
+
+#define	AUDPP_MAX_MBADRC_BANDS		5
+#define	AUDPP_MBADRC_EXTERNAL_BUF_SIZE	196
+
+struct adrc_config {
+	uint16_t subband_enable;
+	uint16_t adrc_sub_mute;
+	uint16_t rms_time;
+	uint16_t compression_th;
+	uint16_t compression_slope;
+	uint16_t attack_const_lsw;
+	uint16_t attack_const_msw;
+	uint16_t release_const_lsw;
+	uint16_t release_const_msw;
+	uint16_t makeup_gain;
+};
+
+typedef struct {
+	audpp_cmd_cfg_object_params_common 	common;
+	uint16_t enable;
+	uint16_t num_bands;
+	uint16_t down_samp_level;
+	uint16_t adrc_delay;
+	uint16_t ext_buf_size;
+	uint16_t ext_partition;
+	uint16_t ext_buf_msw;
+	uint16_t ext_buf_lsw;
+	struct adrc_config adrc_band[AUDPP_MAX_MBADRC_BANDS];
+} __attribute__((packed)) audpp_cmd_cfg_object_params_mbadrc;
+
+struct audpp_cmd_cfg_object_params_adrc {
+	unsigned short	adrc_flag;
+	unsigned short	compression_th;
+	unsigned short	compression_slope;
+	unsigned short	rms_time;
+	unsigned short	attack_const_lsw;
+	unsigned short	attack_const_msw;
+	unsigned short	release_const_lsw;
+	unsigned short	release_const_msw;
+	unsigned short	adrc_delay;
+};
+
+/*
+ * Command Structure to configure post processing parameters(Spectrum Analizer)
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_SPECTRAM_LEN		\
+	sizeof(audpp_cmd_cfg_object_params_spectram)
+
+
+typedef struct {
+	audpp_cmd_cfg_object_params_common 	common;
+	unsigned short				sample_interval;
+	unsigned short				num_coeff;
+} __attribute__((packed)) audpp_cmd_cfg_object_params_spectram;
+
+/*
+ * Command Structure to configure post processing parameters (QConcert) 
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_QCONCERT_LEN		\
+	sizeof(audpp_cmd_cfg_object_params_qconcert)
+
+
+#define AUDPP_CMD_QCON_ENA_FLAG_ENA		-1
+#define AUDPP_CMD_QCON_ENA_FLAG_DIS		0x0000
+
+#define AUDPP_CMD_QCON_OP_MODE_HEADPHONE	-1
+#define AUDPP_CMD_QCON_OP_MODE_SPEAKER_FRONT	0x0000
+#define AUDPP_CMD_QCON_OP_MODE_SPEAKER_SIDE	0x0001
+#define AUDPP_CMD_QCON_OP_MODE_SPEAKER_DESKTOP	0x0002
+
+#define AUDPP_CMD_QCON_GAIN_UNIT			0x7FFF
+#define AUDPP_CMD_QCON_GAIN_SIX_DB			0x4027
+
+
+#define AUDPP_CMD_QCON_EXPANSION_MAX		0x7FFF
+
+
+typedef struct {
+	audpp_cmd_cfg_object_params_common 	common;
+	signed short				enable_flag;
+	signed short				op_mode;
+	signed short				gain;
+	signed short				expansion;
+	signed short				delay;
+	unsigned short				stages_per_mode;
+	unsigned short				reverb_enable;
+	unsigned short				decay_msw;
+	unsigned short				decay_lsw;
+	unsigned short				decay_time_ratio_msw;
+	unsigned short				decay_time_ratio_lsw;
+	unsigned short				reflection_delay_time;
+	unsigned short				late_reverb_gain;
+	unsigned short				late_reverb_delay;
+	unsigned short                          delay_buff_size_msw;
+	unsigned short                          delay_buff_size_lsw;
+	unsigned short                          partition_num;
+	unsigned short                          delay_buff_start_msw;
+	unsigned short                          delay_buff_start_lsw;
+} __attribute__((packed)) audpp_cmd_cfg_object_params_qconcert;
+
+/*
+ * Command Structure to configure post processing parameters (Side Chain) 
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_SIDECHAIN_LEN		\
+	sizeof(audpp_cmd_cfg_object_params_sidechain)
+
+
+#define AUDPP_CMD_SIDECHAIN_ACTIVE_FLAG_DIS	0x0000
+#define AUDPP_CMD_SIDECHAIN_ACTIVE_FLAG_ENA	-1
+
+typedef struct {
+	audpp_cmd_cfg_object_params_common 	common;
+	signed short				active_flag;
+	unsigned short				num_bands;
+	union {
+		filter_1			filter_1_params;
+		filter_2			filter_2_params;
+		filter_3			filter_3_params;
+		filter_4			filter_4_params;
+	} __attribute__((packed)) params_filter;
+} __attribute__((packed)) audpp_cmd_cfg_object_params_sidechain;
+
+
+/*
+ * Command Structure to configure post processing parameters (QAFX)
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_QAFX_LEN		\
+	sizeof(audpp_cmd_cfg_object_params_qafx)
+
+#define AUDPP_CMD_QAFX_ENA_DISA		0x0000
+#define AUDPP_CMD_QAFX_ENA_ENA_CFG	-1
+#define AUDPP_CMD_QAFX_ENA_DIS_CFG	0x0001
+
+#define AUDPP_CMD_QAFX_CMD_TYPE_ENV	0x0100
+#define AUDPP_CMD_QAFX_CMD_TYPE_OBJ	0x0010
+#define AUDPP_CMD_QAFX_CMD_TYPE_QUERY	0x1000
+
+#define AUDPP_CMD_QAFX_CMDS_ENV_OP_MODE	0x0100
+#define AUDPP_CMD_QAFX_CMDS_ENV_LIS_POS	0x0101
+#define AUDPP_CMD_QAFX_CMDS_ENV_LIS_ORI	0x0102
+#define AUDPP_CMD_QAFX_CMDS_ENV_LIS_VEL	0X0103
+#define AUDPP_CMD_QAFX_CMDS_ENV_ENV_RES	0x0107
+
+#define AUDPP_CMD_QAFX_CMDS_OBJ_SAMP_FREQ	0x0010
+#define AUDPP_CMD_QAFX_CMDS_OBJ_VOL		0x0011
+#define AUDPP_CMD_QAFX_CMDS_OBJ_DIST		0x0012
+#define AUDPP_CMD_QAFX_CMDS_OBJ_POS		0x0013
+#define AUDPP_CMD_QAFX_CMDS_OBJ_VEL		0x0014
+
+
+typedef struct {
+	audpp_cmd_cfg_object_params_common 	common;
+	signed short				enable;
+	unsigned short				command_type;
+	unsigned short				num_commands;
+	unsigned short				commands;
+} __attribute__((packed)) audpp_cmd_cfg_object_params_qafx;
+
+/*
+ * Command Structure to enable , disable or configure the reverberation effect
+ * (Common)
+ */
+
+#define AUDPP_CMD_REVERB_CONFIG		0x0001
+#define	AUDPP_CMD_REVERB_CONFIG_COMMON_LEN	\
+	sizeof(audpp_cmd_reverb_config_common)
+
+#define AUDPP_CMD_ENA_ENA	0xFFFF
+#define AUDPP_CMD_ENA_DIS	0x0000
+#define AUDPP_CMD_ENA_CFG	0x0001
+
+#define AUDPP_CMD_CMD_TYPE_ENV		0x0104
+#define AUDPP_CMD_CMD_TYPE_OBJ		0x0015
+#define AUDPP_CMD_CMD_TYPE_QUERY	0x1000
+
+#define SRS_PARAMS_MAX_G 8
+#define SRS_PARAMS_MAX_W 55
+#define SRS_PARAMS_MAX_C 51
+#define SRS_PARAMS_MAX_H 53
+#define SRS_PARAMS_MAX_P 116
+#define SRS_PARAMS_MAX_L 8
+
+typedef struct {
+	unsigned short			cmd_id;
+	unsigned short			enable;
+	unsigned short			cmd_type;
+} __attribute__((packed)) audpp_cmd_reverb_config_common;
+
+/*
+ * Command Structure to enable , disable or configure the reverberation effect
+ * (ENV-0x0104)
+ */
+
+#define	AUDPP_CMD_REVERB_CONFIG_ENV_104_LEN	\
+	sizeof(audpp_cmd_reverb_config_env_104)
+
+typedef struct {
+	audpp_cmd_reverb_config_common	common;
+	unsigned short			env_gain;
+	unsigned short			decay_msw;
+	unsigned short			decay_lsw;
+	unsigned short			decay_timeratio_msw;
+	unsigned short			decay_timeratio_lsw;
+	unsigned short			delay_time;
+	unsigned short			reverb_gain;
+	unsigned short			reverb_delay;
+} __attribute__((packed)) audpp_cmd_reverb_config_env_104;
+
+/*
+ * Command Structure to enable , disable or configure the reverberation effect
+ * (ENV-0x0015)
+ */
+
+#define	AUDPP_CMD_REVERB_CONFIG_ENV_15_LEN	\
+	sizeof(audpp_cmd_reverb_config_env_15)
+
+typedef struct {
+	audpp_cmd_reverb_config_common	common;
+	unsigned short			object_num;
+	unsigned short			absolute_gain;
+} __attribute__((packed)) audpp_cmd_reverb_config_env_15;
+
+/*
+ * Command Structure to configure post processing params (SRS TruMedia)
+ */
+struct audpp_cmd_cfg_object_params_srstm_g {
+	audpp_cmd_cfg_object_params_common	common;
+	unsigned short				v[SRS_PARAMS_MAX_G];
+} __packed;
+struct audpp_cmd_cfg_object_params_srstm_w {
+	audpp_cmd_cfg_object_params_common	common;
+	unsigned short				v[SRS_PARAMS_MAX_W];
+} __packed;
+struct audpp_cmd_cfg_object_params_srstm_c {
+	audpp_cmd_cfg_object_params_common	common;
+	unsigned short				v[SRS_PARAMS_MAX_C];
+} __packed;
+struct audpp_cmd_cfg_object_params_srstm_h {
+	audpp_cmd_cfg_object_params_common	common;
+	unsigned short				v[SRS_PARAMS_MAX_H];
+} __packed;
+struct audpp_cmd_cfg_object_params_srstm_p {
+	audpp_cmd_cfg_object_params_common	common;
+	unsigned short				v[SRS_PARAMS_MAX_P];
+} __packed;
+struct audpp_cmd_cfg_object_params_srstm_l {
+	audpp_cmd_cfg_object_params_common	common;
+	unsigned short				v[SRS_PARAMS_MAX_L];
+} __packed;
+
+#endif /* QDSP5AUDPPCMDI_H */
+
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppmsg.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppmsg.h
new file mode 100644
index 0000000..0ba8261
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppmsg.h
@@ -0,0 +1,321 @@
+#ifndef QDSP5AUDPPMSG_H
+#define QDSP5AUDPPMSG_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+       Q D S P 5  A U D I O   P O S T   P R O C E S S I N G   M S G
+
+GENERAL DESCRIPTION
+  Messages sent by AUDPPTASK to ARM 
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None  
+  
+Copyright (c) 1992-2009, Code Aurora Forum. 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+  
+ $Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audppmsg.h#4 $
+
+===========================================================================*/
+
+/*
+ * AUDPPTASK uses audPPuPRlist to send messages to the ARM
+ * Location : MEMA
+ * Buffer Size : 45
+ * No of Buffers in a queue : 5 for gaming audio and 1 for other images 
+ */
+
+/*
+ * MSG to Informs the ARM os Success/Failure of bringing up the decoder
+ */
+
+#define AUDPP_MSG_STATUS_MSG		0x0001
+#define AUDPP_MSG_STATUS_MSG_LEN	\
+	sizeof(audpp_msg_status_msg)
+
+#define AUDPP_MSG_STATUS_SLEEP		0x0000
+#define AUDPP_MSG_STATUS_INIT		0x0001
+#define AUDPP_MSG_STATUS_CFG		0x0002
+#define AUDPP_MSG_STATUS_PLAY		0x0003
+
+#define AUDPP_MSG_REASON_NONE	0x0000
+#define AUDPP_MSG_REASON_MEM	0x0001
+#define AUDPP_MSG_REASON_NODECODER 0x0002
+
+typedef struct{
+	unsigned short dec_id;
+	unsigned short status;
+	unsigned short reason;
+} __attribute__((packed)) audpp_msg_status_msg;
+
+/*
+ * MSG to communicate the spectrum analyzer output bands to the ARM
+ */
+#define AUDPP_MSG_SPA_BANDS		0x0002
+#define AUDPP_MSG_SPA_BANDS_LEN	\
+	sizeof(audpp_msg_spa_bands)
+
+typedef struct {
+	unsigned short			current_object;
+	unsigned short			spa_band_1;
+	unsigned short			spa_band_2;
+	unsigned short			spa_band_3;
+	unsigned short			spa_band_4;
+	unsigned short			spa_band_5;
+	unsigned short			spa_band_6;
+	unsigned short			spa_band_7;
+	unsigned short			spa_band_8;
+	unsigned short			spa_band_9;
+	unsigned short			spa_band_10;
+	unsigned short			spa_band_11;
+	unsigned short			spa_band_12;
+	unsigned short			spa_band_13;
+	unsigned short			spa_band_14;
+	unsigned short			spa_band_15;
+	unsigned short			spa_band_16;
+	unsigned short			spa_band_17;
+	unsigned short			spa_band_18;
+	unsigned short			spa_band_19;
+	unsigned short			spa_band_20;
+	unsigned short			spa_band_21;
+	unsigned short			spa_band_22;
+	unsigned short			spa_band_23;
+	unsigned short			spa_band_24;
+	unsigned short			spa_band_25;
+	unsigned short			spa_band_26;
+	unsigned short			spa_band_27;
+	unsigned short			spa_band_28;
+	unsigned short			spa_band_29;
+	unsigned short			spa_band_30;
+	unsigned short			spa_band_31;
+	unsigned short			spa_band_32;
+} __attribute__((packed)) audpp_msg_spa_bands;
+
+/*
+ * MSG to communicate the PCM I/O buffer status to ARM
+ */
+#define  AUDPP_MSG_HOST_PCM_INTF_MSG		0x0003
+#define  AUDPP_MSG_HOST_PCM_INTF_MSG_LEN	\
+	sizeof(audpp_msg_host_pcm_intf_msg)
+
+#define AUDPP_MSG_HOSTPCM_ID_TX_ARM	0x0000
+#define AUDPP_MSG_HOSTPCM_ID_ARM_TX	0x0001
+#define AUDPP_MSG_HOSTPCM_ID_RX_ARM	0x0002
+#define AUDPP_MSG_HOSTPCM_ID_ARM_RX	0x0003
+
+#define AUDPP_MSG_SAMP_FREQ_INDX_96000	0x0000
+#define AUDPP_MSG_SAMP_FREQ_INDX_88200	0x0001
+#define AUDPP_MSG_SAMP_FREQ_INDX_64000	0x0002
+#define AUDPP_MSG_SAMP_FREQ_INDX_48000	0x0003
+#define AUDPP_MSG_SAMP_FREQ_INDX_44100	0x0004
+#define AUDPP_MSG_SAMP_FREQ_INDX_32000	0x0005
+#define AUDPP_MSG_SAMP_FREQ_INDX_24000	0x0006
+#define AUDPP_MSG_SAMP_FREQ_INDX_22050	0x0007
+#define AUDPP_MSG_SAMP_FREQ_INDX_16000	0x0008
+#define AUDPP_MSG_SAMP_FREQ_INDX_12000	0x0009
+#define AUDPP_MSG_SAMP_FREQ_INDX_11025	0x000A
+#define AUDPP_MSG_SAMP_FREQ_INDX_8000	0x000B
+
+#define AUDPP_MSG_CHANNEL_MODE_MONO		0x0001
+#define AUDPP_MSG_CHANNEL_MODE_STEREO	0x0002
+
+typedef struct{
+	unsigned short obj_num;
+	unsigned short numbers_of_samples;
+	unsigned short host_pcm_id;
+	unsigned short buf_indx;
+	unsigned short samp_freq_indx;
+	unsigned short channel_mode;
+} __attribute__((packed)) audpp_msg_host_pcm_intf_msg;
+
+
+/*
+ * MSG to communicate 3D position of the source and listener , source volume
+ * source rolloff, source orientation
+ */
+
+#define AUDPP_MSG_QAFX_POS		0x0004
+#define AUDPP_MSG_QAFX_POS_LEN		\
+	sizeof(audpp_msg_qafx_pos)
+
+typedef struct {
+	unsigned short	current_object;
+	unsigned short	x_pos_lis_msw;
+	unsigned short	x_pos_lis_lsw;
+	unsigned short	y_pos_lis_msw;
+	unsigned short	y_pos_lis_lsw;
+	unsigned short	z_pos_lis_msw;
+	unsigned short	z_pos_lis_lsw;
+	unsigned short	x_fwd_msw;
+	unsigned short	x_fwd_lsw;
+	unsigned short	y_fwd_msw;
+	unsigned short	y_fwd_lsw;
+	unsigned short	z_fwd_msw;
+	unsigned short	z_fwd_lsw;
+	unsigned short 	x_up_msw;
+	unsigned short	x_up_lsw;
+	unsigned short 	y_up_msw;
+	unsigned short	y_up_lsw;
+	unsigned short 	z_up_msw;
+	unsigned short	z_up_lsw;
+	unsigned short 	x_vel_lis_msw;
+	unsigned short 	x_vel_lis_lsw;
+	unsigned short 	y_vel_lis_msw;
+	unsigned short 	y_vel_lis_lsw;
+	unsigned short 	z_vel_lis_msw;
+	unsigned short 	z_vel_lis_lsw;
+	unsigned short	threed_enable_flag;
+	unsigned short 	volume;
+	unsigned short	x_pos_source_msw;
+	unsigned short	x_pos_source_lsw;
+	unsigned short	y_pos_source_msw;
+	unsigned short	y_pos_source_lsw;
+	unsigned short	z_pos_source_msw;
+	unsigned short	z_pos_source_lsw;
+	unsigned short	max_dist_0_msw;
+	unsigned short	max_dist_0_lsw;
+	unsigned short	min_dist_0_msw;
+	unsigned short	min_dist_0_lsw;
+	unsigned short	roll_off_factor;
+	unsigned short	mute_after_max_flag;
+	unsigned short	x_vel_source_msw;
+	unsigned short	x_vel_source_lsw;
+	unsigned short	y_vel_source_msw;
+	unsigned short	y_vel_source_lsw;
+	unsigned short	z_vel_source_msw;
+	unsigned short	z_vel_source_lsw;
+} __attribute__((packed)) audpp_msg_qafx_pos;
+
+/*
+ * MSG to provide AVSYNC feedback from DSP to ARM
+ */
+
+#define AUDPP_MSG_AVSYNC_MSG		0x0005
+#define AUDPP_MSG_AVSYNC_MSG_LEN	\
+	sizeof(audpp_msg_avsync_msg)
+
+typedef struct {
+	unsigned short	active_flag;
+	unsigned short	num_samples_counter0_HSW;
+	unsigned short	num_samples_counter0_MSW;
+	unsigned short	num_samples_counter0_LSW;
+	unsigned short	num_bytes_counter0_HSW;
+	unsigned short	num_bytes_counter0_MSW;
+	unsigned short	num_bytes_counter0_LSW;
+	unsigned short	samp_freq_obj_0;
+	unsigned short	samp_freq_obj_1;
+	unsigned short	samp_freq_obj_2;
+	unsigned short	samp_freq_obj_3;
+	unsigned short	samp_freq_obj_4;
+	unsigned short	samp_freq_obj_5;
+	unsigned short	samp_freq_obj_6;
+	unsigned short	samp_freq_obj_7;
+	unsigned short	samp_freq_obj_8;
+	unsigned short	samp_freq_obj_9;
+	unsigned short	samp_freq_obj_10;
+	unsigned short	samp_freq_obj_11;
+	unsigned short	samp_freq_obj_12;
+	unsigned short	samp_freq_obj_13;
+	unsigned short	samp_freq_obj_14;
+	unsigned short	samp_freq_obj_15;
+	unsigned short	num_samples_counter4_HSW;
+	unsigned short	num_samples_counter4_MSW;
+	unsigned short	num_samples_counter4_LSW;
+	unsigned short	num_bytes_counter4_HSW;
+	unsigned short	num_bytes_counter4_MSW;
+	unsigned short	num_bytes_counter4_LSW;
+} __attribute__((packed)) audpp_msg_avsync_msg;
+
+/*
+ * MSG to provide PCM DMA Missed feedback from the DSP to ARM
+ */
+
+#define  AUDPP_MSG_PCMDMAMISSED	0x0006
+#define  AUDPP_MSG_PCMDMAMISSED_LEN	\
+	sizeof(audpp_msg_pcmdmamissed);
+
+typedef struct{
+  /*
+  ** Bit 0	0 = PCM DMA not missed for object 0
+  **        1 = PCM DMA missed for object0
+  ** Bit 1	0 = PCM DMA not missed for object 1
+  **        1 = PCM DMA missed for object1
+  ** Bit 2	0 = PCM DMA not missed for object 2
+  **        1 = PCM DMA missed for object2
+  ** Bit 3	0 = PCM DMA not missed for object 3
+  **        1 = PCM DMA missed for object3
+  ** Bit 4	0 = PCM DMA not missed for object 4
+  **        1 = PCM DMA missed for object4
+  */
+  unsigned short pcmdmamissed;
+} __attribute__((packed)) audpp_msg_pcmdmamissed;
+
+/*
+ * MSG to AUDPP enable or disable feedback form DSP to ARM
+ */
+
+#define AUDPP_MSG_CFG_MSG	0x0007  
+#define AUDPP_MSG_CFG_MSG_LEN	\
+    sizeof(audpp_msg_cfg_msg)
+
+#define AUDPP_MSG_ENA_ENA	0xFFFF
+#define AUDPP_MSG_ENA_DIS	0x0000
+
+typedef struct{
+  /*   Enabled  - 0xffff 
+   **  Disabled - 0
+   */
+  unsigned short enabled;
+} __attribute__((packed)) audpp_msg_cfg_msg;
+
+/*
+ * MSG to communicate the reverb  per object volume
+ */
+
+#define AUDPP_MSG_QREVERB_VOLUME	0x0008
+#define AUDPP_MSG_QREVERB_VOLUME_LEN	\
+	sizeof(audpp_msg_qreverb_volume)
+
+
+typedef struct {
+	unsigned short	obj_0_gain;
+	unsigned short	obj_1_gain;
+	unsigned short	obj_2_gain;
+	unsigned short	obj_3_gain;
+	unsigned short	obj_4_gain;
+	unsigned short	hpcm_obj_volume;
+} __attribute__((packed)) audpp_msg_qreverb_volume;
+
+#define AUDPP_MSG_ROUTING_ACK 0x0009
+#define AUDPP_MSG_ROUTING_ACK_LEN \
+  sizeof(struct audpp_msg_routing_ack)
+
+struct audpp_msg_routing_ack {
+  unsigned short dec_id;
+  unsigned short routing_mode;
+} __attribute__((packed));
+
+#define AUDPP_MSG_FLUSH_ACK 0x000A
+
+#define ADSP_MESSAGE_ID 0xFFFF
+
+#endif /* QDSP5AUDPPMSG_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreproc.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreproc.h
new file mode 100644
index 0000000..234c4ac
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreproc.h
@@ -0,0 +1,33 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef QDSP5AUDPREPROC_H
+#define _QDSP5AUDPREPROC_H
+
+#include <mach/qdsp5/qdsp5audpreproccmdi.h>
+#include <mach/qdsp5/qdsp5audpreprocmsg.h>
+
+#define MSM_AUD_ENC_MODE_TUNNEL  0x00000100
+#define MSM_AUD_ENC_MODE_NONTUNNEL  0x00000200
+
+#define AUDPREPROC_CODEC_MASK 0x00FF
+#define AUDPREPROC_MODE_MASK 0xFF00
+
+#define MSM_ADSP_ENC_MODE_TUNNEL 24
+#define MSM_ADSP_ENC_MODE_NON_TUNNEL 25
+
+/* Exported common api's from audpreproc layer */
+int audpreproc_aenc_alloc(unsigned enc_type, const char **module_name,
+		unsigned *queue_id);
+void audpreproc_aenc_free(int enc_id);
+
+#endif /* QDSP5AUDPREPROC_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreproccmdi.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreproccmdi.h
new file mode 100644
index 0000000..8efc916
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreproccmdi.h
@@ -0,0 +1,256 @@
+#ifndef QDSP5AUDPREPROCCMDI_H
+#define QDSP5AUDPREPROCCMDI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+    A U D I O   P R E   P R O C E S S I N G  I N T E R N A L  C O M M A N D S
+
+GENERAL DESCRIPTION
+  This file contains defintions of format blocks of commands 
+  that are accepted by AUDPREPROC Task
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+
+Copyright (c) 1992-2009, Code Aurora Forum. 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+   
+$Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audpreproccmdi.h#2 $ 
+  
+===========================================================================*/
+
+/*
+ * AUDIOPREPROC COMMANDS:
+ * ARM uses uPAudPreProcCmdQueue to communicate with AUDPREPROCTASK
+ * Location : MEMB
+ * Buffer size : 51
+ * Number of buffers in a queue : 3
+ */
+
+/*
+ * Command to configure the parameters of AGC
+ */
+
+#define	AUDPREPROC_CMD_CFG_AGC_PARAMS	0x0000
+#define	AUDPREPROC_CMD_CFG_AGC_PARAMS_LEN	\
+	sizeof(audpreproc_cmd_cfg_agc_params)
+
+#define	AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_SLOPE	0x0009
+#define	AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_TH	0x000A
+#define	AUDPREPROC_CMD_TX_AGC_PARAM_MASK_EXP_SLOPE	0x000B
+#define	AUDPREPROC_CMD_TX_AGC_PARAM_MASK_EXP_TH		0x000C
+#define	AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_AIG_FLAG		0x000D
+#define	AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_STATIC_GAIN	0x000E
+#define	AUDPREPROC_CMD_TX_AGC_PARAM_MASK_TX_AGC_ENA_FLAG	0x000F
+
+#define	AUDPREPROC_CMD_TX_AGC_ENA_FLAG_ENA	-1
+#define	AUDPREPROC_CMD_TX_AGC_ENA_FLAG_DIS	0x0000
+
+#define	AUDPREPROC_CMD_ADP_GAIN_FLAG_ENA_ADP_GAIN	-1
+#define	AUDPREPROC_CMD_ADP_GAIN_FLAG_ENA_STATIC_GAIN	0x0000
+
+#define	AUDPREPROC_CMD_PARAM_MASK_RMS_TAY	0x0004
+#define	AUDPREPROC_CMD_PARAM_MASK_RELEASEK	0x0005
+#define	AUDPREPROC_CMD_PARAM_MASK_DELAY		0x0006
+#define	AUDPREPROC_CMD_PARAM_MASK_ATTACKK	0x0007
+#define	AUDPREPROC_CMD_PARAM_MASK_LEAKRATE_SLOW	0x0008
+#define	AUDPREPROC_CMD_PARAM_MASK_LEAKRATE_FAST	0x0009
+#define	AUDPREPROC_CMD_PARAM_MASK_AIG_RELEASEK 	0x000A
+#define	AUDPREPROC_CMD_PARAM_MASK_AIG_MIN	0x000B
+#define	AUDPREPROC_CMD_PARAM_MASK_AIG_MAX	0x000C
+#define	AUDPREPROC_CMD_PARAM_MASK_LEAK_UP	0x000D
+#define	AUDPREPROC_CMD_PARAM_MASK_LEAK_DOWN	0x000E
+#define	AUDPREPROC_CMD_PARAM_MASK_AIG_ATTACKK	0x000F
+
+typedef struct {
+	unsigned short	cmd_id;
+	unsigned short	tx_agc_param_mask;
+	unsigned short	tx_agc_enable_flag;
+	unsigned short	static_gain;
+	signed short	adaptive_gain_flag;
+	unsigned short	expander_th;
+	unsigned short	expander_slope;
+	unsigned short	compressor_th;
+	unsigned short	compressor_slope;
+	unsigned short	param_mask;
+	unsigned short	aig_attackk;
+	unsigned short	aig_leak_down;
+	unsigned short	aig_leak_up;
+	unsigned short	aig_max;
+	unsigned short	aig_min;
+	unsigned short	aig_releasek;
+	unsigned short	aig_leakrate_fast;
+	unsigned short	aig_leakrate_slow;
+	unsigned short	attackk_msw;
+	unsigned short	attackk_lsw;
+	unsigned short	delay;
+	unsigned short	releasek_msw;
+	unsigned short	releasek_lsw;
+	unsigned short	rms_tav;
+} __attribute__((packed)) audpreproc_cmd_cfg_agc_params;
+
+
+/*
+ * Command to configure the params of Advanved AGC
+ */
+
+#define	AUDPREPROC_CMD_CFG_AGC_PARAMS_2		0x0001
+#define	AUDPREPROC_CMD_CFG_AGC_PARAMS_2_LEN		\
+	sizeof(audpreproc_cmd_cfg_agc_params_2)
+
+#define	AUDPREPROC_CMD_2_TX_AGC_ENA_FLAG_ENA	-1;
+#define	AUDPREPROC_CMD_2_TX_AGC_ENA_FLAG_DIS	0x0000;
+
+typedef struct {
+	unsigned short	cmd_id;
+	unsigned short	agc_param_mask;
+	signed short	tx_agc_enable_flag;
+	unsigned short	comp_static_gain;
+	unsigned short	exp_th;
+	unsigned short	exp_slope;
+	unsigned short	comp_th;
+	unsigned short	comp_slope;
+	unsigned short	comp_rms_tav;
+	unsigned short	comp_samp_mask;
+	unsigned short	comp_attackk_msw;
+	unsigned short	comp_attackk_lsw;
+	unsigned short	comp_releasek_msw;
+	unsigned short	comp_releasek_lsw;
+	unsigned short	comp_delay;
+	unsigned short	comp_makeup_gain;
+} __attribute__((packed)) audpreproc_cmd_cfg_agc_params_2;
+
+/*
+ * Command to configure params for ns
+ */
+
+#define	AUDPREPROC_CMD_CFG_NS_PARAMS		0x0002
+#define	AUDPREPROC_CMD_CFG_NS_PARAMS_LEN	\
+	sizeof(audpreproc_cmd_cfg_ns_params)
+
+#define	AUDPREPROC_CMD_EC_MODE_NEW_NLMS_ENA	0x0001
+#define	AUDPREPROC_CMD_EC_MODE_NEW_NLMS_DIS 	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_NEW_DES_ENA	0x0002
+#define	AUDPREPROC_CMD_EC_MODE_NEW_DES_DIS	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_NEW_NS_ENA	0x0004
+#define	AUDPREPROC_CMD_EC_MODE_NEW_NS_DIS	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_NEW_CNI_ENA	0x0008
+#define	AUDPREPROC_CMD_EC_MODE_NEW_CNI_DIS	0x0000
+
+#define	AUDPREPROC_CMD_EC_MODE_NEW_NLES_ENA	0x0010
+#define	AUDPREPROC_CMD_EC_MODE_NEW_NLES_DIS	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_NEW_HB_ENA	0x0020
+#define	AUDPREPROC_CMD_EC_MODE_NEW_HB_DIS	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_NEW_VA_ENA	0x0040
+#define	AUDPREPROC_CMD_EC_MODE_NEW_VA_DIS	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_NEW_PCD_ENA	0x0080
+#define	AUDPREPROC_CMD_EC_MODE_NEW_PCD_DIS	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_NEW_FEHI_ENA	0x0100
+#define	AUDPREPROC_CMD_EC_MODE_NEW_FEHI_DIS 	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_NEW_NEHI_ENA	0x0200
+#define	AUDPREPROC_CMD_EC_MODE_NEW_NEHI_DIS 	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_NEW_NLPP_ENA	0x0400
+#define	AUDPREPROC_CMD_EC_MODE_NEW_NLPP_DIS	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_NEW_FNE_ENA	0x0800
+#define	AUDPREPROC_CMD_EC_MODE_NEW_FNE_DIS	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_NEW_PRENLMS_ENA 	0x1000
+#define	AUDPREPROC_CMD_EC_MODE_NEW_PRENLMS_DIS 	0x0000
+
+typedef struct {
+	unsigned short	cmd_id;
+	unsigned short	ec_mode_new;
+	unsigned short	dens_gamma_n;
+	unsigned short	dens_nfe_block_size;
+	unsigned short	dens_limit_ns;
+	unsigned short	dens_limit_ns_d;
+	unsigned short	wb_gamma_e;
+	unsigned short	wb_gamma_n;
+} __attribute__((packed)) audpreproc_cmd_cfg_ns_params;
+
+/*
+ * Command to configure parameters for IIR tuning filter
+ */
+
+#define	AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS		0x0003
+#define	AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS_LEN	\
+	sizeof(audpreproc_cmd_cfg_iir_tuning_filter_params)
+
+#define	AUDPREPROC_CMD_IIR_ACTIVE_FLAG_DIS	0x0000
+#define	AUDPREPROC_CMD_IIR_ACTIVE_FLAG_ENA	0x0001
+
+typedef struct {
+	unsigned short	cmd_id;
+	unsigned short	active_flag;
+	unsigned short	num_bands;
+	unsigned short	numerator_coeff_b0_filter0_lsw;
+	unsigned short	numerator_coeff_b0_filter0_msw;
+	unsigned short	numerator_coeff_b1_filter0_lsw;
+	unsigned short	numerator_coeff_b1_filter0_msw;
+	unsigned short	numerator_coeff_b2_filter0_lsw;
+	unsigned short	numerator_coeff_b2_filter0_msw;
+	unsigned short	numerator_coeff_b0_filter1_lsw;
+	unsigned short	numerator_coeff_b0_filter1_msw;
+	unsigned short	numerator_coeff_b1_filter1_lsw;
+	unsigned short	numerator_coeff_b1_filter1_msw;
+	unsigned short	numerator_coeff_b2_filter1_lsw;
+	unsigned short	numerator_coeff_b2_filter1_msw;
+	unsigned short	numerator_coeff_b0_filter2_lsw;
+	unsigned short	numerator_coeff_b0_filter2_msw;
+	unsigned short	numerator_coeff_b1_filter2_lsw;
+	unsigned short	numerator_coeff_b1_filter2_msw;
+	unsigned short	numerator_coeff_b2_filter2_lsw;
+	unsigned short	numerator_coeff_b2_filter2_msw;
+	unsigned short	numerator_coeff_b0_filter3_lsw;
+	unsigned short	numerator_coeff_b0_filter3_msw;
+	unsigned short	numerator_coeff_b1_filter3_lsw;
+	unsigned short	numerator_coeff_b1_filter3_msw;
+	unsigned short	numerator_coeff_b2_filter3_lsw;
+	unsigned short	numerator_coeff_b2_filter3_msw;
+	unsigned short 	denominator_coeff_a0_filter0_lsw;
+	unsigned short 	denominator_coeff_a0_filter0_msw;
+	unsigned short 	denominator_coeff_a1_filter0_lsw;
+	unsigned short 	denominator_coeff_a1_filter0_msw; 
+	unsigned short 	denominator_coeff_a0_filter1_lsw;
+	unsigned short 	denominator_coeff_a0_filter1_msw;
+	unsigned short 	denominator_coeff_a1_filter1_lsw;
+	unsigned short 	denominator_coeff_a1_filter1_msw;
+  unsigned short 	denominator_coeff_a0_filter2_lsw;
+	unsigned short 	denominator_coeff_a0_filter2_msw;
+	unsigned short 	denominator_coeff_a1_filter2_lsw;
+	unsigned short 	denominator_coeff_a1_filter2_msw;
+  unsigned short 	denominator_coeff_a0_filter3_lsw;
+	unsigned short 	denominator_coeff_a0_filter3_msw;
+	unsigned short 	denominator_coeff_a1_filter3_lsw;
+	unsigned short 	denominator_coeff_a1_filter3_msw;
+
+	unsigned short	shift_factor_filter0;
+	unsigned short	shift_factor_filter1;
+	unsigned short	shift_factor_filter2;
+	unsigned short	shift_factor_filter3;
+
+	unsigned short	channel_selected0;
+	unsigned short	channel_selected1;
+	unsigned short	channel_selected2;
+	unsigned short	channel_selected3;
+} __attribute__((packed))audpreproc_cmd_cfg_iir_tuning_filter_params;
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreprocmsg.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreprocmsg.h
new file mode 100644
index 0000000..0696066
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreprocmsg.h
@@ -0,0 +1,85 @@
+#ifndef QDSP5AUDPREPROCMSG_H
+#define QDSP5AUDPREPROCMSG_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+    A U D I O   P R E   P R O C E S S I N G  M E S S A G E S
+
+GENERAL DESCRIPTION
+  This file contains defintions of format blocks of messages 
+  that are rcvd by AUDPREPROC Task
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+
+Copyright (c) 1992-2009, Code Aurora Forum. 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+   
+ $Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audpreprocmsg.h#3 $
+  
+===========================================================================*/
+
+/*
+ * ADSPREPROCTASK Messages
+ * AUDPREPROCTASK uses audPreProcUpRlist to communicate with ARM
+ * Location	: MEMA
+ * Message Length  : 2
+ */
+
+/*
+ * Message to indicate particular feature has been enabled or disabled
+ */
+
+
+#define	AUDPREPROC_MSG_CMD_CFG_DONE_MSG	0x0001
+#define	AUDPREPROC_MSG_CMD_CFG_DONE_MSG_LEN	\
+	sizeof(audpreproc_msg_cmd_cfg_done_msg)
+
+#define	AUDPREPROC_MSG_TYPE_AGC			0x0000
+#define	AUDPREPROC_MSG_TYPE_NOISE_REDUCTION	0x0001
+#define	AUDPREPROC_MSG_TYPE_IIR_FILTER		0x0002
+
+
+#define	AUDPREPROC_MSG_STATUS_FLAG_ENA		-1
+#define	AUDPREPROC_MSG_STATUS_FLAG_DIS		0x0000
+
+typedef struct {
+	unsigned short	type;
+	signed short	status_flag;
+} __attribute__((packed)) audpreproc_msg_cmd_cfg_done_msg;
+
+
+/*
+ * Message to indicate particular feature has selected for wrong samp freq
+ */
+
+#define	AUDPREPROC_MSG_ERROR_MSG_ID		0x0002
+#define	AUDPREPROC_MSG_ERROR_MSG_ID_LEN	\
+	sizeof(audpreproc_msg_error_msg_id)
+
+#define	AUDPREPROC_MSG_ERR_INDEX_NS		0x0000
+
+typedef struct {
+	 unsigned short	err_index;
+} __attribute__((packed)) audpreproc_msg_error_msg_id;
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audreccmdi.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audreccmdi.h
new file mode 100644
index 0000000..5045de0
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audreccmdi.h
@@ -0,0 +1,401 @@
+#ifndef QDSP5AUDRECCMDI_H
+#define QDSP5AUDRECCMDI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+ *
+ *    A U D I O   R E C O R D  I N T E R N A L  C O M M A N D S
+ *
+ * GENERAL DESCRIPTION
+ *   This file contains defintions of format blocks of commands
+ *   that are accepted by AUDREC Task
+ *
+ * REFERENCES
+ *   None
+ *
+ * EXTERNALIZED FUNCTIONS
+ *  None
+ *
+ * Copyright (c) 1992-2009, 2011 Code Aurora Forum. 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.
+ *
+ *====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+   
+ $Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audreccmdi.h#3 $
+  
+============================================================================*/
+
+/*
+ * AUDRECTASK COMMANDS
+ * ARM uses 2 queues to communicate with the AUDRECTASK
+ * 1.uPAudRecCmdQueue
+ * Location :MEMC
+ * Buffer Size : 8
+ * No of Buffers in a queue : 3
+ * 2.audRecUpBitStreamQueue
+ * Location : MEMC
+ * Buffer Size : 4
+ * No of buffers in a queue : 2
+ */
+
+/*
+ * Commands on uPAudRecCmdQueue 
+ */
+
+/*
+ * Command to initiate and terminate the audio recording section
+ */
+
+#define AUDREC_CMD_CFG		0x0000
+#define	AUDREC_CMD_CFG_LEN	sizeof(audrec_cmd_cfg)
+
+#define	AUDREC_CMD_TYPE_0_INDEX_WAV	0x0000
+#define	AUDREC_CMD_TYPE_0_INDEX_AAC	0x0001
+#define	AUDREC_CMD_TYPE_0_INDEX_AMRNB	0x000A
+#define	AUDREC_CMD_TYPE_0_INDEX_EVRC	0x000B
+#define	AUDREC_CMD_TYPE_0_INDEX_QCELP	0x000C
+
+#define AUDREC_CMD_TYPE_0_ENA		0x4000
+#define AUDREC_CMD_TYPE_0_DIS		0x0000
+
+#define AUDREC_CMD_TYPE_0_NOUPDATE	0x0000
+#define AUDREC_CMD_TYPE_0_UPDATE	0x8000
+
+#define	AUDREC_CMD_TYPE_1_INDEX_SBC	0x0002
+
+#define AUDREC_CMD_TYPE_1_ENA		0x4000
+#define AUDREC_CMD_TYPE_1_DIS		0x0000
+
+#define AUDREC_CMD_TYPE_1_NOUPDATE	0x0000
+#define AUDREC_CMD_TYPE_1_UPDATE	0x8000
+
+typedef struct {
+	unsigned short 	cmd_id;
+	unsigned short	type_0;
+	unsigned short	type_1;
+} __attribute__((packed)) audrec_cmd_cfg;
+
+
+/*
+ * Command to configure the recording parameters for RecType0(AAC/WAV) encoder
+ */
+
+#define	AUDREC_CMD_AREC0PARAM_CFG	0x0001
+#define	AUDREC_CMD_AREC0PARAM_CFG_LEN	\
+	sizeof(audrec_cmd_arec0param_cfg)
+
+#define	AUDREC_CMD_SAMP_RATE_INDX_8000		0x000B
+#define	AUDREC_CMD_SAMP_RATE_INDX_11025		0x000A
+#define	AUDREC_CMD_SAMP_RATE_INDX_12000		0x0009
+#define	AUDREC_CMD_SAMP_RATE_INDX_16000		0x0008
+#define	AUDREC_CMD_SAMP_RATE_INDX_22050		0x0007
+#define	AUDREC_CMD_SAMP_RATE_INDX_24000		0x0006
+#define	AUDREC_CMD_SAMP_RATE_INDX_32000		0x0005
+#define	AUDREC_CMD_SAMP_RATE_INDX_44100		0x0004
+#define	AUDREC_CMD_SAMP_RATE_INDX_48000		0x0003
+
+#define AUDREC_CMD_STEREO_MODE_MONO		0x0000
+#define AUDREC_CMD_STEREO_MODE_STEREO		0x0001
+
+typedef struct {
+	unsigned short 	cmd_id;
+	unsigned short	ptr_to_extpkt_buffer_msw;
+	unsigned short	ptr_to_extpkt_buffer_lsw;
+	unsigned short	buf_len;
+	unsigned short	samp_rate_index;
+	unsigned short	stereo_mode;
+	unsigned short 	rec_quality;
+} __attribute__((packed)) audrec_cmd_arec0param_cfg;
+
+/*
+ * Command to configure the recording parameters for RecType1(SBC) encoder
+ */
+
+#define AUDREC_CMD_AREC1PARAM_CFG	0x0002
+#define AUDREC_CMD_AREC1PARAM_CFG_LEN	\
+	sizeof(audrec_cmd_arec1param_cfg)
+
+#define AUDREC_CMD_PARAM_BUF_BLOCKS_4	0x0000
+#define AUDREC_CMD_PARAM_BUF_BLOCKS_8	0x0001
+#define AUDREC_CMD_PARAM_BUF_BLOCKS_12	0x0002
+#define AUDREC_CMD_PARAM_BUF_BLOCKS_16	0x0003
+
+#define AUDREC_CMD_PARAM_BUF_SUB_BANDS_8	0x0010
+#define AUDREC_CMD_PARAM_BUF_MODE_MONO		0x0000
+#define AUDREC_CMD_PARAM_BUF_MODE_DUAL		0x0040
+#define AUDREC_CMD_PARAM_BUF_MODE_STEREO	0x0050
+#define AUDREC_CMD_PARAM_BUF_MODE_JSTEREO	0x0060
+#define AUDREC_CMD_PARAM_BUF_LOUDNESS		0x0000
+#define AUDREC_CMD_PARAM_BUF_SNR		0x0100
+#define AUDREC_CMD_PARAM_BUF_BASIC_VER		0x0000
+
+typedef struct {
+	unsigned short 	cmd_id;
+	unsigned short	ptr_to_extpkt_buffer_msw;
+	unsigned short	ptr_to_extpkt_buffer_lsw;
+	unsigned short	buf_len;
+	unsigned short	param_buf;
+	unsigned short	bit_rate_0;
+	unsigned short	bit_rate_1;
+} __attribute__((packed)) audrec_cmd_arec1param_cfg;
+
+/*
+ * Command to enable encoder for the recording
+ */
+
+#define AUDREC_CMD_ENC_CFG	0x0003
+#define AUDREC_CMD_ENC_CFG_LEN	\
+	sizeof(struct audrec_cmd_enc_cfg)
+
+
+#define AUDREC_CMD_ENC_ENA		0x8000
+#define AUDREC_CMD_ENC_DIS		0x0000
+
+#define AUDREC_CMD_ENC_TYPE_MASK	0x001F
+
+struct audrec_cmd_enc_cfg {
+	unsigned short 	cmd_id;
+	unsigned short	audrec_enc_type;
+	unsigned short	audrec_obj_idx;
+} __attribute__((packed));
+
+/*
+ * Command to set external memory config for the selected encoder
+ */
+
+#define AUDREC_CMD_ARECMEM_CFG	0x0004
+#define AUDREC_CMD_ARECMEM_CFG_LEN	\
+	sizeof(struct audrec_cmd_arecmem_cfg)
+
+
+struct audrec_cmd_arecmem_cfg {
+	unsigned short 	cmd_id;
+	unsigned short	audrec_obj_idx;
+	unsigned short	audrec_up_pkt_intm_cnt;
+	unsigned short	audrec_extpkt_buffer_msw;
+	unsigned short	audrec_extpkt_buffer_lsw;
+	unsigned short	audrec_extpkt_buffer_num;
+} __attribute__((packed));
+
+/*
+ * Command to configure the recording parameters for selected encoder
+ */
+
+#define AUDREC_CMD_ARECPARAM_CFG	0x0005
+#define AUDREC_CMD_ARECPARAM_COMMON_CFG_LEN	\
+	sizeof(struct audrec_cmd_arecparam_common_cfg)
+
+
+struct audrec_cmd_arecparam_common_cfg {
+	unsigned short 	cmd_id;
+	unsigned short	audrec_obj_idx;
+} __attribute__((packed));
+
+#define AUDREC_CMD_ARECPARAM_WAV_CFG_LEN	\
+	sizeof(struct audrec_cmd_arecparam_wav_cfg)
+
+
+struct audrec_cmd_arecparam_wav_cfg {
+	struct audrec_cmd_arecparam_common_cfg common;
+	unsigned short 	samp_rate_idx;
+	unsigned short  stereo_mode;
+} __attribute__((packed));
+
+#define AUDREC_CMD_ARECPARAM_AAC_CFG_LEN	\
+	sizeof(struct audrec_cmd_arecparam_aac_cfg)
+
+
+struct audrec_cmd_arecparam_aac_cfg {
+	struct audrec_cmd_arecparam_common_cfg common;
+	unsigned short 	samp_rate_idx;
+	unsigned short  stereo_mode;
+	unsigned short  rec_quality;
+} __attribute__((packed));
+
+#define AUDREC_CMD_ARECPARAM_SBC_CFG_LEN	\
+	sizeof(struct audrec_cmd_arecparam_sbc_cfg)
+
+
+struct audrec_cmd_arecparam_sbc_cfg {
+	struct audrec_cmd_arecparam_common_cfg common;
+	unsigned short 	param_buf;
+	unsigned short  bit_rate_0;
+	unsigned short  bit_rate_1;
+} __attribute__((packed));
+
+#define AUDREC_CMD_ARECPARAM_AMRNB_CFG_LEN	\
+	sizeof(struct audrec_cmd_arecparam_amrnb_cfg)
+
+
+struct audrec_cmd_arecparam_amrnb_cfg {
+	struct audrec_cmd_arecparam_common_cfg common;
+	unsigned short 	samp_rate_idx;
+	unsigned short 	voicememoencweight1;
+	unsigned short 	voicememoencweight2;
+	unsigned short 	voicememoencweight3;
+	unsigned short 	voicememoencweight4;
+	unsigned short 	update_mode;
+	unsigned short 	dtx_mode;
+	unsigned short 	test_mode;
+	unsigned short 	used_mode;
+} __attribute__((packed));
+
+#define AUDREC_CMD_ARECPARAM_EVRC_CFG_LEN	\
+	sizeof(struct audrec_cmd_arecparam_evrc_cfg)
+
+
+struct audrec_cmd_arecparam_evrc_cfg {
+	struct audrec_cmd_arecparam_common_cfg common;
+	unsigned short 	samp_rate_idx;
+	unsigned short 	voicememoencweight1;
+	unsigned short 	voicememoencweight2;
+	unsigned short 	voicememoencweight3;
+	unsigned short 	voicememoencweight4;
+	unsigned short 	update_mode;
+	unsigned short 	enc_min_rate;
+	unsigned short 	enc_max_rate;
+	unsigned short 	rate_modulation_cmd;
+} __attribute__((packed));
+
+#define AUDREC_CMD_ARECPARAM_QCELP_CFG_LEN	\
+	sizeof(struct audrec_cmd_arecparam_qcelp_cfg)
+
+
+struct audrec_cmd_arecparam_qcelp_cfg {
+	struct audrec_cmd_arecparam_common_cfg common;
+	unsigned short 	samp_rate_idx;
+	unsigned short 	voicememoencweight1;
+	unsigned short 	voicememoencweight2;
+	unsigned short 	voicememoencweight3;
+	unsigned short 	voicememoencweight4;
+	unsigned short 	update_mode;
+	unsigned short 	enc_min_rate;
+	unsigned short 	enc_max_rate;
+	unsigned short 	rate_modulation_cmd;
+	unsigned short 	reduced_rate_level;
+} __attribute__((packed));
+
+#define AUDREC_CMD_ARECPARAM_FGVNB_CFG_LEN	\
+	sizeof(struct audrec_cmd_arecparam_fgvnb_cfg)
+
+
+struct audrec_cmd_arecparam_fgvnb_cfg {
+	struct audrec_cmd_arecparam_common_cfg common;
+	unsigned short 	samp_rate_idx;
+	unsigned short 	voicememoencweight1;
+	unsigned short 	voicememoencweight2;
+	unsigned short 	voicememoencweight3;
+	unsigned short 	voicememoencweight4;
+	unsigned short 	update_mode;
+	unsigned short 	fgv_min_rate;
+	unsigned short 	fgv_max_rate;
+	unsigned short 	reduced_rate_level;
+} __attribute__((packed));
+
+/*
+ * Command to configure Tunnel(RT) or Non-Tunnel(FTRT) mode
+ */
+
+#define AUDREC_CMD_ROUTING_MODE		0x0006
+#define	AUDREC_CMD_ROUTING_MODE_LEN	\
+	sizeof(struct audpreproc_audrec_cmd_routing_mode)
+
+#define AUDIO_ROUTING_MODE_FTRT		0x0001
+#define AUDIO_ROUTING_MODE_RT		0x0002
+
+struct audrec_cmd_routing_mode {
+	unsigned short cmd_id;
+	unsigned short routing_mode;
+} __packed;
+
+/*
+ * Command to configure pcm input memory
+ */
+
+#define AUDREC_CMD_PCM_CFG_ARM_TO_ENC 0x0007
+#define AUDREC_CMD_PCM_CFG_ARM_TO_ENC_LEN	\
+	sizeof(struct audrec_cmd_pcm_cfg_arm_to_enc)
+
+struct audrec_cmd_pcm_cfg_arm_to_enc {
+	unsigned short cmd_id;
+	unsigned short config_update_flag;
+	unsigned short enable_flag;
+	unsigned short sampling_freq;
+	unsigned short channels;
+	unsigned short frequency_of_intimation;
+	unsigned short max_number_of_buffers;
+} __packed;
+
+#define AUDREC_PCM_CONFIG_UPDATE_FLAG_ENABLE -1
+#define AUDREC_PCM_CONFIG_UPDATE_FLAG_DISABLE 0
+
+#define AUDREC_ENABLE_FLAG_VALUE -1
+#define AUDREC_DISABLE_FLAG_VALUE 0
+
+/*
+ * Command to intimate available pcm buffer
+ */
+
+#define AUDREC_CMD_PCM_BUFFER_PTR_REFRESH_ARM_TO_ENC 0x0008
+#define AUDREC_CMD_PCM_BUFFER_PTR_REFRESH_ARM_TO_ENC_LEN \
+	sizeof(struct audrec_cmd_pcm_buffer_ptr_refresh_arm_enc)
+
+struct audrec_cmd_pcm_buffer_ptr_refresh_arm_enc {
+	unsigned short cmd_id;
+	unsigned short num_buffers;
+	unsigned short buffer_write_cnt_msw;
+	unsigned short buffer_write_cnt_lsw;
+	unsigned short buf_address_length[8];/*this array holds address
+						and length details of
+						two buffers*/
+} __packed;
+
+/*
+ * Command to flush
+ */
+
+#define AUDREC_CMD_FLUSH 0x009
+#define AUDREC_CMD_FLUSH_LEN	\
+	sizeof(struct audrec_cmd_flush)
+
+struct audrec_cmd_flush {
+	unsigned short cmd_id;
+} __packed;
+
+/*
+ * Commands on audRecUpBitStreamQueue
+ */
+
+/*
+ * Command to indicate the current packet read count
+ */
+
+#define AUDREC_CMD_PACKET_EXT_PTR		0x0000
+#define AUDREC_CMD_PACKET_EXT_PTR_LEN	\
+	sizeof(audrec_cmd_packet_ext_ptr)
+
+#define AUDREC_CMD_TYPE_0	0x0000
+#define AUDREC_CMD_TYPE_1	0x0001
+
+typedef struct {
+	unsigned short  cmd_id;
+	unsigned short	type; /* audrec_obj_idx */
+	unsigned short 	curr_rec_count_msw;
+	unsigned short 	curr_rec_count_lsw;
+} __attribute__((packed)) audrec_cmd_packet_ext_ptr;
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audrecmsg.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audrecmsg.h
new file mode 100644
index 0000000..339e4f7
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audrecmsg.h
@@ -0,0 +1,223 @@
+#ifndef QDSP5AUDRECMSGI_H
+#define QDSP5AUDRECMSGI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+ *
+ *    A U D I O   R E C O R D  M E S S A G E S
+ *
+ * GENERAL DESCRIPTION
+ *  This file contains defintions of format blocks of messages
+ *  that are sent by AUDREC Task
+ *
+ * REFERENCES
+ *   None
+ *
+ * EXTERNALIZED FUNCTIONS
+ *  None
+ *
+ * Copyright (c) 1992-2009, 2011 Code Aurora Forum. 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.
+ *
+ *====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+   
+ $Header: //source/qcom/qct/multimedia2/Audio/drivers/QDSP5Driver/QDSP5Interface/main/latest/qdsp5audrecmsg.h#3 $
+
+============================================================================*/
+
+/*
+ * AUDRECTASK MESSAGES
+ * AUDRECTASK uses audRecUpRlist to communicate with ARM
+ * Location : MEMC
+ * Buffer size : 4
+ * No of buffers in a queue : 2
+ */
+
+/*
+ * Message to notify that config command is done
+ */
+
+#define AUDREC_MSG_CMD_CFG_DONE_MSG	0x0002
+#define AUDREC_MSG_CMD_CFG_DONE_MSG_LEN	\
+	sizeof(struct audrec_msg_cmd_cfg_done_msg)
+
+
+#define AUDREC_MSG_CFG_DONE_TYPE_0_ENA		0x4000
+#define AUDREC_MSG_CFG_DONE_TYPE_0_DIS		0x0000
+
+#define AUDREC_MSG_CFG_DONE_TYPE_0_NO_UPDATE	0x0000
+#define AUDREC_MSG_CFG_DONE_TYPE_0_UPDATE	0x8000
+
+#define AUDREC_MSG_CFG_DONE_TYPE_1_ENA		0x4000
+#define AUDREC_MSG_CFG_DONE_TYPE_1_DIS		0x0000
+
+#define AUDREC_MSG_CFG_DONE_TYPE_1_NO_UPDATE	0x0000
+#define AUDREC_MSG_CFG_DONE_TYPE_1_UPDATE	0x8000
+
+#define AUDREC_MSG_CFG_DONE_ENC_ENA		0x8000
+#define AUDREC_MSG_CFG_DONE_ENC_DIS		0x0000
+
+struct audrec_msg_cmd_cfg_done_msg {
+	unsigned short	audrec_enc_type;
+	unsigned short	audrec_obj_idx;
+} __attribute__((packed));
+
+/*
+ * Message to notify arec0/1 or concurrent encoder cfg done
+ * and recording params recieved by task
+ */
+
+#define	AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG		0x0003
+#define	AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG_LEN	\
+	sizeof(struct audrec_msg_cmd_arec_param_cfg_done_msg)
+
+
+#define	AUDREC_MSG_AREC_PARAM_TYPE_0	0x0000
+#define	AUDREC_MSG_AREC_PARAM_TYPE_1	0x0001
+
+struct audrec_msg_cmd_arec_param_cfg_done_msg {
+	unsigned short	audrec_obj_idx;
+} __attribute__((packed));
+
+/*
+ * Message to notify no more buffers are available in ext mem to DME
+ * Or no concurrent encoder supported
+ */
+/* for 7x27 */
+#define AUDREC_MSG_FATAL_ERR_MSG		0x0004
+#define AUDREC_MSG_FATAL_ERR_MSG_LEN	\
+	sizeof(struct audrec_msg_fatal_err_msg)
+
+
+#define AUDREC_MSG_FATAL_ERR_TYPE_0	0x0000
+#define AUDREC_MSG_FATAL_ERR_TYPE_1	0x0001
+
+struct audrec_msg_fatal_err_msg {
+	unsigned short	audrec_obj_idx;
+	unsigned short	audrec_err_id;
+} __attribute__((packed));
+
+/* for 7x27A */
+#define AUDREC_MSG_NO_EXT_PKT_AVAILABLE_MSG		0x0004
+#define AUDREC_MSG_NO_EXT_PKT_AVAILABLE_MSG_LEN	\
+	sizeof(struct audrec_msg_no_ext_pkt_avail_msg)
+
+#define AUDREC_MSG_NO_EXT_PKT_AVAILABLE_TYPE_0	0x0000
+#define AUDREC_MSG_NO_EXT_PKT_AVAILABLE_TYPE_1	0x0001
+
+struct audrec_msg_no_ext_pkt_avail_msg {
+	unsigned short	audrec_obj_idx;
+	unsigned short	audrec_err_id;
+} __packed;
+
+/*
+ * Message to notify DME deliverd the encoded pkt to ext pkt buffer
+ */
+
+#define AUDREC_MSG_PACKET_READY_MSG		0x0005
+#define AUDREC_MSG_PACKET_READY_MSG_LEN	\
+	sizeof(struct audrec_msg_packet_ready_msg)
+
+
+#define AUDREC_MSG_PACKET_READY_TYPE_0	0x0000
+#define AUDREC_MSG_PACKET_READY_TYPE_1	0x0001
+
+struct audrec_msg_packet_ready_msg {
+	unsigned short	audrec_obj_idx;
+	unsigned short	pkt_counter_msw;
+	unsigned short	pkt_counter_lsw;
+	unsigned short	pkt_read_cnt_msw;
+	unsigned short	pkt_read_cnt_lsw;
+} __attribute__((packed));
+
+/*
+ * Message to notify external memory cfg done and recieved by task
+ */
+
+#define	AUDREC_MSG_CMD_AREC_MEM_CFG_DONE_MSG		0x0006
+#define	AUDREC_MSG_CMD_AREC_MEM_CFG_DONE_MSG_LEN	\
+	sizeof(struct audrec_msg_cmd_arec_mem_cfg_done_msg)
+
+
+struct audrec_msg_cmd_arec_mem_cfg_done_msg {
+	unsigned short	audrec_obj_idx;
+} __attribute__((packed));
+
+/*
+ * Message to indicate Routing mode
+ * configuration success or failure
+ */
+
+#define AUDREC_MSG_CMD_ROUTING_MODE_DONE_MSG		 0x0007
+#define AUDREC_MSG_CMD_ROUTING_MODE_DONE_MSG_LEN	 \
+	sizeof(struct audrec_msg_cmd_routing_mode_done_msg)
+
+struct audrec_msg_cmd_routing_mode_done_msg {
+	unsigned short configuration;
+} __packed;
+
+/*
+ * Message to indicate pcm buffer configured
+ */
+
+#define AUDREC_CMD_PCM_CFG_ARM_TO_ENC_DONE_MSG		0x0008
+#define AUDREC_CMD_PCM_CFG_ARM_TO_ENC_DONE_MSG_LEN	\
+	sizeof(struct audrec_cmd_pcm_cfg_arm_to_enc_msg)
+
+struct  audrec_cmd_pcm_cfg_arm_to_enc_msg {
+	unsigned short configuration;
+} __packed;
+
+/*
+ * Message to indicate encoded packet is delivered to external buffer in FTRT
+ */
+
+#define AUDREC_UP_NT_PACKET_READY_MSG			0x0009
+#define AUDREC_UP_NT_PACKET_READY_MSG_LEN	\
+	sizeof(struct audrec_up_nt_packet_ready_msg)
+
+struct  audrec_up_nt_packet_ready_msg {
+	unsigned short audrec_packetwrite_cnt_lsw;
+	unsigned short audrec_packetwrite_cnt_msw;
+	unsigned short audrec_upprev_readcount_lsw;
+	unsigned short audrec_upprev_readcount_msw;
+} __packed;
+
+/*
+ * Message to indicate pcm buffer is consumed
+ */
+
+#define AUDREC_CMD_PCM_BUFFER_PTR_UPDATE_ARM_TO_ENC_MSG 0x000A
+#define AUDREC_CMD_PCM_BUFFER_PTR_UPDATE_ARM_TO_ENC_MSG_LEN	\
+	sizeof(struct audrec_cmd_pcm_buffer_ptr_update_arm_to_enc_msg)
+
+struct  audrec_cmd_pcm_buffer_ptr_update_arm_to_enc_msg {
+	unsigned short buffer_readcnt_msw;
+	unsigned short buffer_readcnt_lsw;
+	unsigned short number_of_buffers;
+	unsigned short buffer_address_length[];
+} __packed;
+
+/*
+ * Message to indicate flush acknowledgement
+ */
+
+#define AUDREC_CMD_FLUSH_DONE_MSG			0x000B
+
+#define ADSP_MESSAGE_ID 0xFFFF
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5jpegcmdi.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5jpegcmdi.h
new file mode 100644
index 0000000..7f25f47
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5jpegcmdi.h
@@ -0,0 +1,377 @@
+#ifndef QDSP5VIDJPEGCMDI_H
+#define QDSP5VIDJPEGCMDI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+    J P E G  I N T E R N A L  C O M M A N D S
+
+GENERAL DESCRIPTION
+  This file contains defintions of format blocks of commands 
+  that are accepted by JPEG Task
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+
+Copyright (c) 1992-2009, Code Aurora Forum. 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+   
+ 
+$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5jpegcmdi.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $                     
+Revision History:                                            
+when       who     what, where, why
+--------   ---     ----------------------------------------------------------
+06/09/08   sv      initial version
+===========================================================================*/
+
+/*
+ * ARM to JPEG configuration commands are passed through the
+ * uPJpegCfgCmdQueue
+ */
+
+/*
+ * Command to configure JPEG Encoder
+ */
+
+#define	JPEG_CMD_ENC_CFG		0x0000
+#define	JPEG_CMD_ENC_CFG_LEN	sizeof(jpeg_cmd_enc_cfg)
+
+#define	JPEG_CMD_ENC_PROCESS_CFG_OP_ROTATION_0		0x0000
+#define	JPEG_CMD_ENC_PROCESS_CFG_OP_ROTATION_90		0x0100
+#define	JPEG_CMD_ENC_PROCESS_CFG_OP_ROTATION_180	0x0200
+#define	JPEG_CMD_ENC_PROCESS_CFG_OP_ROTATION_270	0x0300
+#define	JPEG_CMD_ENC_PROCESS_CFG_IP_DATA_FORMAT_M	0x0003
+#define	JPEG_CMD_ENC_PROCESS_CFG_IP_DATA_FORMAT_H2V2	0x0000
+#define	JPEG_CMD_ENC_PROCESS_CFG_IP_DATA_FORMAT_H2V1	0x0001
+#define	JPEG_CMD_ENC_PROCESS_CFG_IP_DATA_FORMAT_H1V2	0x0002
+
+#define	JPEG_CMD_IP_SIZE_CFG_LUMA_HEIGHT_M		0x0000FFFF
+#define	JPEG_CMD_IP_SIZE_CFG_LUMA_WIDTH_M		0xFFFF0000
+#define	JPEG_CMD_ENC_UPSAMP_IP_SIZE_CFG_ENA		0x0001
+#define	JPEG_CMD_ENC_UPSAMP_IP_SIZE_CFG_DIS		0x0000
+
+#define	JPEG_CMD_FRAG_SIZE_LUMA_HEIGHT_M		0xFFFF
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	process_cfg;
+	unsigned int	ip_size_cfg;
+	unsigned int	op_size_cfg;
+	unsigned int	frag_cfg;
+	unsigned int	frag_cfg_part[16];
+
+	unsigned int    part_num;
+
+	unsigned int	op_buf_0_cfg_part1;
+	unsigned int	op_buf_0_cfg_part2;
+	unsigned int	op_buf_1_cfg_part1;
+	unsigned int	op_buf_1_cfg_part2;
+
+	unsigned int	luma_qunt_table[32];
+	unsigned int	chroma_qunt_table[32];
+
+	unsigned int	upsamp_ip_size_cfg;
+	unsigned int	upsamp_ip_frame_off;
+	unsigned int	upsamp_pp_filter_coeff[64];
+} __attribute__((packed)) jpeg_cmd_enc_cfg;
+
+/*
+ * Command to configure JPEG Decoder
+ */
+
+#define	JPEG_CMD_DEC_CFG		0x0001
+#define	JPEG_CMD_DEC_CFG_LEN		sizeof(jpeg_cmd_dec_cfg)
+
+#define	JPEG_CMD_DEC_OP_DATA_FORMAT_M		0x0001
+#define JPEG_CMD_DEC_OP_DATA_FORMAT_H2V2	0x0000
+#define JPEG_CMD_DEC_OP_DATA_FORMAT_H2V1	0x0001
+
+#define JPEG_CMD_DEC_OP_DATA_FORMAT_SCALE_FACTOR_8	0x000000
+#define JPEG_CMD_DEC_OP_DATA_FORMAT_SCALE_FACTOR_4	0x010000
+#define JPEG_CMD_DEC_OP_DATA_FORMAT_SCALE_FACTOR_2	0x020000
+#define JPEG_CMD_DEC_OP_DATA_FORMAT_SCALE_FACTOR_1	0x030000
+
+#define	JPEG_CMD_DEC_IP_STREAM_BUF_CFG_PART3_NOT_FINAL	0x0000
+#define	JPEG_CMD_DEC_IP_STREAM_BUF_CFG_PART3_FINAL	0x0001
+
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	img_dimension_cfg;
+	unsigned int	op_data_format;
+	unsigned int	restart_interval;
+	unsigned int	ip_buf_partition_num;
+	unsigned int	ip_stream_buf_cfg_part1;
+	unsigned int	ip_stream_buf_cfg_part2;
+	unsigned int	ip_stream_buf_cfg_part3;
+	unsigned int	op_stream_buf_0_cfg_part1;
+	unsigned int	op_stream_buf_0_cfg_part2;
+	unsigned int	op_stream_buf_0_cfg_part3;
+	unsigned int	op_stream_buf_1_cfg_part1;
+	unsigned int	op_stream_buf_1_cfg_part2;
+	unsigned int	op_stream_buf_1_cfg_part3;
+	unsigned int	luma_qunt_table_0_3;
+	unsigned int	luma_qunt_table_4_7;
+	unsigned int	luma_qunt_table_8_11;
+	unsigned int	luma_qunt_table_12_15;
+	unsigned int	luma_qunt_table_16_19;
+	unsigned int	luma_qunt_table_20_23;
+	unsigned int	luma_qunt_table_24_27;
+	unsigned int	luma_qunt_table_28_31;
+	unsigned int	luma_qunt_table_32_35;
+	unsigned int	luma_qunt_table_36_39;
+	unsigned int	luma_qunt_table_40_43;
+	unsigned int	luma_qunt_table_44_47;
+	unsigned int	luma_qunt_table_48_51;
+	unsigned int	luma_qunt_table_52_55;
+	unsigned int	luma_qunt_table_56_59;
+	unsigned int	luma_qunt_table_60_63;
+	unsigned int	chroma_qunt_table_0_3;
+	unsigned int	chroma_qunt_table_4_7;
+	unsigned int	chroma_qunt_table_8_11;
+	unsigned int	chroma_qunt_table_12_15;
+	unsigned int	chroma_qunt_table_16_19;
+	unsigned int	chroma_qunt_table_20_23;
+	unsigned int	chroma_qunt_table_24_27;
+	unsigned int	chroma_qunt_table_28_31;
+	unsigned int	chroma_qunt_table_32_35;
+	unsigned int	chroma_qunt_table_36_39;
+	unsigned int	chroma_qunt_table_40_43;
+	unsigned int	chroma_qunt_table_44_47;
+	unsigned int	chroma_qunt_table_48_51;
+	unsigned int	chroma_qunt_table_52_55;
+	unsigned int	chroma_qunt_table_56_59;
+	unsigned int	chroma_qunt_table_60_63;
+	unsigned int	luma_dc_hm_code_cnt_table_0_3;
+	unsigned int	luma_dc_hm_code_cnt_table_4_7;
+	unsigned int	luma_dc_hm_code_cnt_table_8_11;
+	unsigned int	luma_dc_hm_code_cnt_table_12_15;
+	unsigned int	luma_dc_hm_code_val_table_0_3;
+	unsigned int	luma_dc_hm_code_val_table_4_7;
+	unsigned int	luma_dc_hm_code_val_table_8_11;
+	unsigned int	chroma_dc_hm_code_cnt_table_0_3;
+	unsigned int	chroma_dc_hm_code_cnt_table_4_7;
+	unsigned int	chroma_dc_hm_code_cnt_table_8_11;
+	unsigned int	chroma_dc_hm_code_cnt_table_12_15;
+	unsigned int	chroma_dc_hm_code_val_table_0_3;
+	unsigned int	chroma_dc_hm_code_val_table_4_7;
+	unsigned int	chroma_dc_hm_code_val_table_8_11;
+	unsigned int	luma_ac_hm_code_cnt_table_0_3;
+	unsigned int	luma_ac_hm_code_cnt_table_4_7;
+	unsigned int	luma_ac_hm_code_cnt_table_8_11;
+	unsigned int	luma_ac_hm_code_cnt_table_12_15;
+	unsigned int	luma_ac_hm_code_val_table_0_3;
+	unsigned int	luma_ac_hm_code_val_table_4_7;
+	unsigned int	luma_ac_hm_code_val_table_8_11;
+	unsigned int	luma_ac_hm_code_val_table_12_15;
+	unsigned int	luma_ac_hm_code_val_table_16_19;
+	unsigned int	luma_ac_hm_code_val_table_20_23;
+	unsigned int	luma_ac_hm_code_val_table_24_27;
+	unsigned int	luma_ac_hm_code_val_table_28_31;
+	unsigned int	luma_ac_hm_code_val_table_32_35;
+	unsigned int	luma_ac_hm_code_val_table_36_39;
+	unsigned int	luma_ac_hm_code_val_table_40_43;
+	unsigned int	luma_ac_hm_code_val_table_44_47;
+	unsigned int	luma_ac_hm_code_val_table_48_51;
+	unsigned int	luma_ac_hm_code_val_table_52_55;
+	unsigned int	luma_ac_hm_code_val_table_56_59;
+	unsigned int	luma_ac_hm_code_val_table_60_63;
+	unsigned int	luma_ac_hm_code_val_table_64_67;
+	unsigned int	luma_ac_hm_code_val_table_68_71;
+	unsigned int	luma_ac_hm_code_val_table_72_75;
+	unsigned int	luma_ac_hm_code_val_table_76_79;
+	unsigned int	luma_ac_hm_code_val_table_80_83;
+	unsigned int	luma_ac_hm_code_val_table_84_87;
+	unsigned int	luma_ac_hm_code_val_table_88_91;
+	unsigned int	luma_ac_hm_code_val_table_92_95;
+	unsigned int	luma_ac_hm_code_val_table_96_99;
+	unsigned int	luma_ac_hm_code_val_table_100_103;
+	unsigned int	luma_ac_hm_code_val_table_104_107;
+	unsigned int	luma_ac_hm_code_val_table_108_111;
+	unsigned int	luma_ac_hm_code_val_table_112_115;
+	unsigned int	luma_ac_hm_code_val_table_116_119;
+	unsigned int	luma_ac_hm_code_val_table_120_123;
+	unsigned int	luma_ac_hm_code_val_table_124_127;
+	unsigned int	luma_ac_hm_code_val_table_128_131;
+	unsigned int	luma_ac_hm_code_val_table_132_135;
+	unsigned int	luma_ac_hm_code_val_table_136_139;
+	unsigned int	luma_ac_hm_code_val_table_140_143;
+	unsigned int	luma_ac_hm_code_val_table_144_147;
+	unsigned int	luma_ac_hm_code_val_table_148_151;
+	unsigned int	luma_ac_hm_code_val_table_152_155;
+	unsigned int	luma_ac_hm_code_val_table_156_159;
+	unsigned int	luma_ac_hm_code_val_table_160_161;
+	unsigned int	chroma_ac_hm_code_cnt_table_0_3;
+	unsigned int	chroma_ac_hm_code_cnt_table_4_7;
+	unsigned int	chroma_ac_hm_code_cnt_table_8_11;
+	unsigned int	chroma_ac_hm_code_cnt_table_12_15;
+	unsigned int	chroma_ac_hm_code_val_table_0_3;
+	unsigned int	chroma_ac_hm_code_val_table_4_7;
+	unsigned int	chroma_ac_hm_code_val_table_8_11;
+	unsigned int	chroma_ac_hm_code_val_table_12_15;
+	unsigned int	chroma_ac_hm_code_val_table_16_19;
+	unsigned int	chroma_ac_hm_code_val_table_20_23;
+	unsigned int	chroma_ac_hm_code_val_table_24_27;
+	unsigned int	chroma_ac_hm_code_val_table_28_31;
+	unsigned int	chroma_ac_hm_code_val_table_32_35;
+	unsigned int	chroma_ac_hm_code_val_table_36_39;
+	unsigned int	chroma_ac_hm_code_val_table_40_43;
+	unsigned int	chroma_ac_hm_code_val_table_44_47;
+	unsigned int	chroma_ac_hm_code_val_table_48_51;
+	unsigned int	chroma_ac_hm_code_val_table_52_55;
+	unsigned int	chroma_ac_hm_code_val_table_56_59;
+	unsigned int	chroma_ac_hm_code_val_table_60_63;
+	unsigned int	chroma_ac_hm_code_val_table_64_67;
+	unsigned int	chroma_ac_hm_code_val_table_68_71;
+	unsigned int	chroma_ac_hm_code_val_table_72_75;
+	unsigned int	chroma_ac_hm_code_val_table_76_79;
+	unsigned int	chroma_ac_hm_code_val_table_80_83;
+	unsigned int	chroma_ac_hm_code_val_table_84_87;
+	unsigned int	chroma_ac_hm_code_val_table_88_91;
+	unsigned int	chroma_ac_hm_code_val_table_92_95;
+	unsigned int	chroma_ac_hm_code_val_table_96_99;
+	unsigned int	chroma_ac_hm_code_val_table_100_103;
+	unsigned int	chroma_ac_hm_code_val_table_104_107;
+	unsigned int	chroma_ac_hm_code_val_table_108_111;
+	unsigned int	chroma_ac_hm_code_val_table_112_115;
+	unsigned int	chroma_ac_hm_code_val_table_116_119;
+	unsigned int	chroma_ac_hm_code_val_table_120_123;
+	unsigned int	chroma_ac_hm_code_val_table_124_127;
+	unsigned int	chroma_ac_hm_code_val_table_128_131;
+	unsigned int	chroma_ac_hm_code_val_table_132_135;
+	unsigned int	chroma_ac_hm_code_val_table_136_139;
+	unsigned int	chroma_ac_hm_code_val_table_140_143;
+	unsigned int	chroma_ac_hm_code_val_table_144_147;
+	unsigned int	chroma_ac_hm_code_val_table_148_151;
+	unsigned int	chroma_ac_hm_code_val_table_152_155;
+	unsigned int	chroma_ac_hm_code_val_table_156_159;
+	unsigned int	chroma_ac_hm_code_val_table_160_161;
+} __attribute__((packed)) jpeg_cmd_dec_cfg;
+
+
+/*
+ * ARM to JPEG configuration commands are passed through the
+ * uPJpegActionCmdQueue
+ */
+
+/*
+ * Command to start the encode process
+ */
+
+#define	JPEG_CMD_ENC_ENCODE		0x0001
+#define	JPEG_CMD_ENC_ENCODE_LEN		sizeof(jpeg_cmd_enc_encode)
+
+
+typedef struct {
+	unsigned short	cmd_id;
+} __attribute__((packed)) jpeg_cmd_enc_encode;
+
+
+/*
+ * Command to transition from current state of encoder to IDLE state
+ */
+
+#define	JPEG_CMD_ENC_IDLE		0x0006
+#define	JPEG_CMD_ENC_IDLE_LEN		sizeof(jpeg_cmd_enc_idle)
+
+
+typedef struct {
+	unsigned short	cmd_id;
+} __attribute__((packed)) jpeg_cmd_enc_idle;
+
+
+/*
+ * Command to inform the encoder that another buffer is ready
+ */
+
+#define	JPEG_CMD_ENC_OP_CONSUMED	0x0002
+#define	JPEG_CMD_ENC_OP_CONSUMED_LEN	sizeof(jpeg_cmd_enc_op_consumed)
+
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	op_buf_addr;
+	unsigned int	op_buf_size;
+} __attribute__((packed)) jpeg_cmd_enc_op_consumed; 
+
+
+/*
+ * Command to start the decoding process
+ */
+
+#define	JPEG_CMD_DEC_DECODE		0x0003
+#define	JPEG_CMD_DEC_DECODE_LEN	sizeof(jpeg_cmd_dec_decode)
+
+
+typedef struct {
+	unsigned short	cmd_id;
+} __attribute__((packed)) jpeg_cmd_dec_decode;
+
+
+/*
+ * Command to transition from the current state of decoder to IDLE
+ */
+
+#define	JPEG_CMD_DEC_IDLE	0x0007
+#define	JPEG_CMD_DEC_IDLE_LEN	sizeof(jpeg_cmd_dec_idle)
+
+
+typedef struct {
+	unsigned short	cmd_id;
+} __attribute__((packed)) jpeg_cmd_dec_idle;
+
+
+/*
+ * Command to inform that an op buffer is ready for use
+ */
+
+#define	JPEG_CMD_DEC_OP_CONSUMED	0x0004
+#define	JPEG_CMD_DEC_OP_CONSUMED_LEN	sizeof(jpeg_cmd_dec_op_consumed)
+
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	luma_op_buf_addr;
+	unsigned int	luma_op_buf_size;
+	unsigned int	chroma_op_buf_addr;
+} __attribute__((packed)) jpeg_cmd_dec_op_consumed;
+
+
+/*
+ * Command to pass a new ip buffer to the jpeg decoder
+ */
+
+#define	JPEG_CMD_DEC_IP	0x0005
+#define	JPEG_CMD_DEC_IP_LEN	sizeof(jpeg_cmd_dec_ip_len)
+
+#define	JPEG_CMD_EOI_INDICATOR_NOT_END	0x0000
+#define	JPEG_CMD_EOI_INDICATOR_END	0x0001
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	ip_buf_addr;
+	unsigned int	ip_buf_size;
+	unsigned int	eoi_indicator;
+} __attribute__((packed)) jpeg_cmd_dec_ip;
+
+
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5jpegmsg.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5jpegmsg.h
new file mode 100644
index 0000000..993af42
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5jpegmsg.h
@@ -0,0 +1,177 @@
+#ifndef QDSP5VIDJPEGMSGI_H
+#define QDSP5VIDJPEGMSGI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+   J P E G  I N T E R N A L  M E S S A G E S
+
+GENERAL DESCRIPTION
+  This file contains defintions of format blocks of messages 
+  that are sent by JPEG Task
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+
+Copyright (c) 1992-2009, Code Aurora Forum. 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+   
+$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5jpegmsg.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $                     
+Revision History:                                            
+  
+when       who     what, where, why
+--------   ---     ----------------------------------------------------------
+05/10/08   sv      initial version
+===========================================================================*/
+
+/*
+ * Messages from JPEG task to ARM through jpeguPMsgQueue
+ */
+
+/*
+ * Message is ACK for CMD_JPEGE_ENCODE cmd
+ */
+
+#define	JPEG_MSG_ENC_ENCODE_ACK	0x0000
+#define	JPEG_MSG_ENC_ENCODE_ACK_LEN	\
+	sizeof(jpeg_msg_enc_encode_ack)
+
+typedef struct {
+} __attribute__((packed)) jpeg_msg_enc_encode_ack;
+
+
+/*
+ * Message informs the up when op buffer is ready for consumption and
+ * when encoding is complete or errors
+ */
+
+#define	JPEG_MSG_ENC_OP_PRODUCED	0x0001
+#define	JPEG_MSG_ENC_OP_PRODUCED_LEN	\
+	sizeof(jpeg_msg_enc_op_produced)
+
+#define	JPEG_MSGOP_OP_BUF_STATUS_ENC_DONE_PROGRESS	0x0000
+#define	JPEG_MSGOP_OP_BUF_STATUS_ENC_DONE_COMPLETE	0x0001
+#define	JPEG_MSGOP_OP_BUF_STATUS_ENC_ERR		0x10000
+
+typedef struct {
+	unsigned int	op_buf_addr;
+	unsigned int	op_buf_size;
+	unsigned int	op_buf_status;
+} __attribute__((packed)) jpeg_msg_enc_op_produced;
+
+
+/*
+ * Message to ack CMD_JPEGE_IDLE
+ */
+
+#define	JPEG_MSG_ENC_IDLE_ACK	0x0002
+#define	JPEG_MSG_ENC_IDLE_ACK_LEN	sizeof(jpeg_msg_enc_idle_ack)
+
+
+typedef struct {
+} __attribute__ ((packed)) jpeg_msg_enc_idle_ack;
+
+
+/*
+ * Message to indicate the illegal command
+ */
+
+#define	JPEG_MSG_ENC_ILLEGAL_COMMAND	0x0003
+#define	JPEG_MSG_ENC_ILLEGAL_COMMAND_LEN	\
+	sizeof(jpeg_msg_enc_illegal_command)
+
+typedef struct {
+	unsigned int	status;
+} __attribute__((packed)) jpeg_msg_enc_illegal_command;
+
+
+/*
+ * Message to ACK CMD_JPEGD_DECODE
+ */
+
+#define	JPEG_MSG_DEC_DECODE_ACK		0x0004
+#define	JPEG_MSG_DEC_DECODE_ACK_LEN	\
+	sizeof(jpeg_msg_dec_decode_ack)
+
+
+typedef struct {
+} __attribute__((packed)) jpeg_msg_dec_decode_ack;
+
+
+/*
+ * Message to inform up that an op buffer is ready for consumption and when
+ * decoding is complete or an error occurs
+ */
+
+#define	JPEG_MSG_DEC_OP_PRODUCED		0x0005
+#define	JPEG_MSG_DEC_OP_PRODUCED_LEN	\
+	sizeof(jpeg_msg_dec_op_produced)
+
+#define	JPEG_MSG_DEC_OP_BUF_STATUS_PROGRESS	0x0000
+#define	JPEG_MSG_DEC_OP_BUF_STATUS_DONE		0x0001
+
+typedef struct {
+	unsigned int	luma_op_buf_addr;
+	unsigned int	chroma_op_buf_addr;
+	unsigned int	num_mcus;
+	unsigned int	op_buf_status;
+} __attribute__((packed)) jpeg_msg_dec_op_produced;
+
+/*
+ * Message to ack CMD_JPEGD_IDLE cmd
+ */
+
+#define	JPEG_MSG_DEC_IDLE_ACK	0x0006
+#define	JPEG_MSG_DEC_IDLE_ACK_LEN	sizeof(jpeg_msg_dec_idle_ack)
+
+
+typedef struct {
+} __attribute__((packed)) jpeg_msg_dec_idle_ack;
+
+
+/*
+ * Message to indicate illegal cmd was received
+ */
+
+#define	JPEG_MSG_DEC_ILLEGAL_COMMAND	0x0007
+#define	JPEG_MSG_DEC_ILLEGAL_COMMAND_LEN	\
+	sizeof(jpeg_msg_dec_illegal_command)
+
+
+typedef struct {
+	unsigned int	status;
+} __attribute__((packed)) jpeg_msg_dec_illegal_command;
+
+/*
+ * Message to request up for the next segment of ip bit stream
+ */
+
+#define	JPEG_MSG_DEC_IP_REQUEST		0x0008
+#define	JPEG_MSG_DEC_IP_REQUEST_LEN	\
+	sizeof(jpeg_msg_dec_ip_request)
+
+
+typedef struct {
+} __attribute__((packed)) jpeg_msg_dec_ip_request;
+
+
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5lpmcmdi.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5lpmcmdi.h
new file mode 100644
index 0000000..4ab6cbf4
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5lpmcmdi.h
@@ -0,0 +1,82 @@
+#ifndef QDSP5LPMCMDI_H
+#define QDSP5LPMCMDI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+    L P M   I N T E R N A L   C O M M A N D S
+
+GENERAL DESCRIPTION
+  This file contains defintions of format blocks of commands 
+  that are accepted by LPM Task
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+
+Copyright (c) 1992-2009, Code Aurora Forum. 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+   
+  
+$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5lpmcmdi.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $                     
+Revision History:                                            
+  
+when       who     what, where, why
+--------   ---     ----------------------------------------------------------
+06/12/08   sv      initial version
+===========================================================================*/
+
+
+/*
+ * Command to start LPM processing based on the config params
+ */
+
+#define	LPM_CMD_START		0x0000
+#define	LPM_CMD_START_LEN	sizeof(lpm_cmd_start)
+
+#define	LPM_CMD_SPATIAL_FILTER_PART_OPMODE_0	0x00000000
+#define	LPM_CMD_SPATIAL_FILTER_PART_OPMODE_1	0x00010000
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	ip_data_cfg_part1;
+	unsigned int	ip_data_cfg_part2;
+	unsigned int	ip_data_cfg_part3;
+	unsigned int	ip_data_cfg_part4;
+	unsigned int	op_data_cfg_part1;
+	unsigned int	op_data_cfg_part2;
+	unsigned int	op_data_cfg_part3;
+	unsigned int	spatial_filter_part[32];
+} __attribute__((packed)) lpm_cmd_start;
+
+
+
+/*
+ * Command to stop LPM processing
+ */
+
+#define	LPM_CMD_IDLE		0x0001
+#define	LPM_CMD_IDLE_LEN	sizeof(lpm_cmd_idle)
+
+typedef struct {
+	unsigned int	cmd_id;
+} __attribute__((packed)) lpm_cmd_idle;
+
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5lpmmsg.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5lpmmsg.h
new file mode 100644
index 0000000..68f8874
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5lpmmsg.h
@@ -0,0 +1,80 @@
+#ifndef QDSP5LPMMSGI_H
+#define QDSP5LPMMSGI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+    L P M   I N T E R N A L   M E S S A G E S
+
+GENERAL DESCRIPTION
+  This file contains defintions of format blocks of commands 
+  that are accepted by LPM Task
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+
+Copyright (c) 1992-2009, Code Aurora Forum. 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+   
+$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5lpmmsg.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $                     
+Revision History:                                              
+  
+when       who     what, where, why
+--------   ---     ----------------------------------------------------------
+06/12/08   sv      initial version
+===========================================================================*/
+
+/*
+ * Message to acknowledge CMD_LPM_IDLE command
+ */
+
+#define	LPM_MSG_IDLE_ACK	0x0000
+#define	LPM_MSG_IDLE_ACK_LEN	sizeof(lpm_msg_idle_ack)
+
+typedef struct {
+} __attribute__((packed)) lpm_msg_idle_ack;
+
+
+/*
+ * Message to acknowledge CMD_LPM_START command
+ */
+
+
+#define	LPM_MSG_START_ACK	0x0001
+#define	LPM_MSG_START_ACK_LEN	sizeof(lpm_msg_start_ack)
+
+
+typedef struct {
+} __attribute__((packed)) lpm_msg_start_ack;
+
+
+/*
+ * Message to notify the ARM that LPM processing is complete
+ */
+
+#define	LPM_MSG_DONE		0x0002
+#define	LPM_MSG_DONE_LEN	sizeof(lpm_msg_done)
+
+typedef struct {
+} __attribute__((packed)) lpm_msg_done;
+
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5rmtcmdi.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5rmtcmdi.h
new file mode 100644
index 0000000..7a66b68
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5rmtcmdi.h
@@ -0,0 +1,55 @@
+/* Copyright (c) 2010, 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 QDSP5RMTCMDI_H
+#define QDSP5RMTCMDI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+    R M T A S K I N T E R N A L  C O M M A N D S
+
+GENERAL DESCRIPTION
+  This file contains defintions of format blocks of commands
+  that are accepted by RM Task
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+
+/*
+ * ARM to RMTASK Commands
+ *
+ * ARM uses one command queue to communicate with AUDPPTASK
+ * 1) apuRmtQueue: Used to send commands to RMTASK from APPS processor
+ * Location : MEMA
+ * Buffer Size : 3 words
+ */
+
+#define RM_CMD_AUD_CODEC_CFG	0x0
+
+#define RM_AUD_CLIENT_ID	0x0
+#define RMT_ENABLE		0x1
+#define RMT_DISABLE		0x0
+
+struct aud_codec_config_cmd {
+	unsigned short			cmd_id;
+	unsigned char			task_id;
+	unsigned char			client_id;
+	unsigned short			enable;
+	unsigned short			dec_type;
+} __attribute__((packed));
+
+#endif /* QDSP5RMTCMDI_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5rmtmsg.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5rmtmsg.h
new file mode 100644
index 0000000..a890e76
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5rmtmsg.h
@@ -0,0 +1,55 @@
+/* Copyright (c) 2010, 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 QDSP5RMTMSG_H
+#define QDSP5RMTMSG_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+       R M T A S K   M S G
+
+GENERAL DESCRIPTION
+  Messages sent by RMTASK to APPS PROCESSOR
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+
+/*
+ * RMTASK uses RmtApuRlist to send messages to the APPS PROCESSOR
+ * Location : MEMA
+ * Buffer Size : 3
+ */
+
+#define RMT_CODEC_CONFIG_ACK	0x1
+
+struct aud_codec_config_ack {
+	unsigned char			task_id;
+	unsigned char			client_id;
+	unsigned char			reason;
+	unsigned char			enable;
+	unsigned short			dec_type;
+} __attribute__((packed));
+
+#define RMT_DSP_OUT_OF_MIPS	0x2
+
+struct rmt_dsp_out_of_mips {
+	unsigned short			dec_info;
+	unsigned short			rvd_0;
+	unsigned short			rvd_1;
+} __attribute__((packed));
+
+#endif /* QDSP5RMTMSG_H */
+
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5vdeccmdi.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5vdeccmdi.h
new file mode 100644
index 0000000..1064b17
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5vdeccmdi.h
@@ -0,0 +1,189 @@
+#ifndef QDSP5VIDDECCMDI_H
+#define QDSP5VIDDECCMDI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+    V I D E O  D E C O D E R  I N T E R N A L  C O M M A N D S
+
+GENERAL DESCRIPTION
+  This file contains defintions of format blocks of commands 
+  that are accepted by VIDDEC Task
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+
+Copyright (c) 1992-2009, Code Aurora Forum. 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+   
+$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5vdeccmdi.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $                     
+Revision History:                                              
+  
+when       who     what, where, why
+--------   ---     ----------------------------------------------------------
+05/10/08   ac      initial version
+===========================================================================*/
+
+
+/*
+ * Command to inform VIDDEC that new subframe packet is ready
+ */
+
+#define	VIDDEC_CMD_SUBFRAME_PKT		0x0000
+#define	VIDDEC_CMD_SUBFRAME_PKT_LEN \
+	sizeof(viddec_cmd_subframe_pkt)
+
+#define	VIDDEC_CMD_SF_INFO_1_DM_DMA_STATS_EXCHANGE_FLAG_DM		0x0000
+#define	VIDDEC_CMD_SF_INFO_1_DM_DMA_STATS_EXCHANGE_FLAG_DMA 	0x0001
+
+#define	VIDDEC_CMD_SF_INFO_0_SUBFRAME_CONTI		0x0000
+#define	VIDDEC_CMD_SF_INFO_0_SUBFRAME_FIRST		0x0001
+#define	VIDDEC_CMD_SF_INFO_0_SUBFRAME_LAST		0x0002
+#define	VIDDEC_CMD_SF_INFO_0_SUBFRAME_FIRST_AND_LAST 	0x0003
+
+#define	VIDDEC_CMD_CODEC_SELECTION_WORD_MPEG_4		0x0000
+#define	VIDDEC_CMD_CODEC_SELECTION_WORD_H_263_P0	0x0001
+#define	VIDDEC_CMD_CODEC_SELECTION_WORD_H_264		0x0002
+#define	VIDDEC_CMD_CODEC_SELECTION_WORD_H_263_p3	0x0003
+#define	VIDDEC_CMD_CODEC_SELECTION_WORD_RV9		0x0004
+#define	VIDDEC_CMD_CODEC_SELECTION_WORD_WMV9		0x0005
+#define	VIDDEC_CMD_CODEC_SELECTION_WORD_SMCDB		0x0006
+#define	VIDDEC_CMD_CODEC_SELECTION_WORD_QFRE		0x0007
+#define	VIDDEC_CMD_CODEC_SELECTION_WORD_VLD		0x0008
+
+typedef struct {
+	unsigned short	cmd_id;
+	unsigned short	packet_seq_number;
+	unsigned short	codec_instance_id;
+	unsigned short	subframe_packet_size_high;
+	unsigned short	subframe_packet_size_low;
+	unsigned short	subframe_packet_high;
+	unsigned short	subframe_packet_low;
+	unsigned short	subframe_packet_partition;
+	unsigned short	statistics_packet_size_high;
+	unsigned short	statistics_packet_size_low;
+	unsigned short	statistics_packet_high;
+	unsigned short	statistics_packet_low;
+	unsigned short	statistics_partition;
+	unsigned short	subframe_info_1;
+	unsigned short	subframe_info_0;
+	unsigned short	codec_selection_word;
+	unsigned short	num_mbs;
+} __attribute__((packed)) viddec_cmd_subframe_pkt;
+
+
+/*
+ * Command to inform VIDDEC task that post processing is required for the frame
+ */
+
+#define	VIDDEC_CMD_PP_ENABLE		0x0001
+#define	VIDDEC_CMD_PP_ENABLE_LEN \
+	sizeof(viddec_cmd_pp_enable)
+
+#define	VIDDEC_CMD_PP_INFO_0_DM_DMA_LS_EXCHANGE_FLAG_DM		0x0000
+#define	VIDDEC_CMD_PP_INFO_0_DM_DMA_LS_EXCHANGE_FLAG_DMA	0x0001
+
+typedef struct {
+	unsigned short	cmd_id;
+	unsigned short	packet_seq_num;
+	unsigned short	codec_instance_id;
+	unsigned short	postproc_info_0;
+	unsigned short	codec_selection_word;
+	unsigned short	pp_output_addr_high;
+	unsigned short	pp_output_addr_low;
+	unsigned short	postproc_info_1;
+	unsigned short	load_sharing_packet_size_high;
+	unsigned short	load_sharing_packet_size_low;
+	unsigned short	load_sharing_packet_high;
+	unsigned short	load_sharing_packet_low;
+	unsigned short	load_sharing_partition;
+	unsigned short	pp_param_0;
+	unsigned short	pp_param_1;
+	unsigned short	pp_param_2;
+	unsigned short	pp_param_3;
+} __attribute__((packed)) viddec_cmd_pp_enable;
+
+
+/*
+ * FRAME Header Packet : It is at the start of new frame
+ */
+
+#define	VIDDEC_CMD_FRAME_HEADER_PACKET	0x0002
+
+#define	VIDDEC_CMD_FRAME_INFO_0_ERROR_SKIP	0x0000
+#define	VIDDEC_CMD_FRAME_INFO_0_ERROR_BLACK	0x0800
+
+/*
+ * SLICE HEADER PACKET 
+ * I-Slice and P-Slice
+ */
+
+#define	VIDDEC_CMD_SLICE_HEADER_PKT_ISLICE		0x0003
+#define	VIDDEC_CMD_SLICE_HEADER_PKT_ISLICE_LEN	\
+	sizeof(viddec_cmd_slice_header_pkt_islice)
+
+#define	VIDDEC_CMD_ISLICE_INFO_1_MOD_SLICE_TYPE_PSLICE	0x0000
+#define	VIDDEC_CMD_ISLICE_INFO_1_MOD_SLICE_TYPE_BSLICE	0x0100
+#define	VIDDEC_CMD_ISLICE_INFO_1_MOD_SLICE_TYPE_ISLICE	0x0200
+#define	VIDDEC_CMD_ISLICE_INFO_1_MOD_SLICE_TYPE_SPSLICE	0x0300
+#define	VIDDEC_CMD_ISLICE_INFO_1_MOD_SLICE_TYPE_SISLICE	0x0400
+#define	VIDDEC_CMD_ISLICE_INFO_1_NOPADDING	0x0000
+#define	VIDDEC_CMD_ISLICE_INFO_1_PADDING	0x0800
+
+#define	VIDDEC_CMD_ISLICE_EOP_MARKER		0x7FFF
+
+typedef struct {
+	unsigned short	cmd_id;
+	unsigned short	packet_id;
+	unsigned short	slice_info_0;
+	unsigned short	slice_info_1;
+	unsigned short	slice_info_2;
+	unsigned short	num_bytes_in_rbsp_high;
+	unsigned short	num_bytes_in_rbsp_low;
+	unsigned short	num_bytes_in_rbsp_consumed;
+	unsigned short	end_of_packet_marker;
+} __attribute__((packed)) viddec_cmd_slice_header_pkt_islice;
+
+
+#define	VIDDEC_CMD_SLICE_HEADER_PKT_PSLICE		0x0003
+#define	VIDDEC_CMD_SLICE_HEADER_PKT_PSLICE_LEN	\
+	sizeof(viddec_cmd_slice_header_pkt_pslice)
+
+
+typedef struct {
+	unsigned short	cmd_id;
+	unsigned short	packet_id;
+	unsigned short	slice_info_0;
+	unsigned short	slice_info_1;
+	unsigned short	slice_info_2;
+	unsigned short	slice_info_3;
+	unsigned short	refidx_l0_map_tab_info_0;
+	unsigned short	refidx_l0_map_tab_info_1;
+	unsigned short	refidx_l0_map_tab_info_2;
+	unsigned short	refidx_l0_map_tab_info_3;
+	unsigned short	num_bytes_in_rbsp_high;
+	unsigned short	num_bytes_in_rbsp_low;
+	unsigned short	num_bytes_in_rbsp_consumed;
+	unsigned short	end_of_packet_marker;
+} __attribute__((packed)) viddec_cmd_slice_header_pkt_pslice;
+
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5vdecmsg.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5vdecmsg.h
new file mode 100644
index 0000000..2d3ab89
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5vdecmsg.h
@@ -0,0 +1,107 @@
+#ifndef QDSP5VIDDECMSGI_H
+#define QDSP5VIDDECMSGI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+    V I D E O  D E C O D E R   I N T E R N A L  M E S S A G E S
+
+GENERAL DESCRIPTION
+  This file contains defintions of format blocks of messages 
+  that are sent by VIDDEC Task
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+
+Copyright (c) 1992-2009, Code Aurora Forum. 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+   
+$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5vdecmsg.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $                     
+Revision History:                                              
+  
+when       who     what, where, why
+--------   ---     ----------------------------------------------------------
+05/10/08   ac      initial version
+===========================================================================*/
+
+/*
+ * Message to inform ARM which VDEC_SUBFRAME_PKT_CMD processed by VIDDEC TASK
+ */
+
+#define	VIDDEC_MSG_SUBF_DONE	0x0000
+#define	VIDDEC_MSG_SUBF_DONE_LEN	\
+	sizeof(viddec_msg_subf_done)
+
+typedef struct {
+	unsigned short	packet_seq_number;
+	unsigned short	codec_instance_id;
+} __attribute__((packed)) viddec_msg_subf_done;
+
+
+/*
+ * Message to inform ARM one frame has been decoded
+ */
+
+#define	VIDDEC_MSG_FRAME_DONE	0x0001
+#define	VIDDEC_MSG_FRAME_DONE_LEN	\
+	sizeof(viddec_msg_frame_done)
+
+typedef struct {
+	unsigned short	packet_seq_number;
+	unsigned short	codec_instance_id;
+} __attribute__((packed)) viddec_msg_frame_done;
+
+
+/*
+ * Message to inform ARM that post processing frame has been decoded
+ */
+
+#define	VIDDEC_MSG_PP_ENABLE_CMD_DONE	0x0002
+#define	VIDDEC_MSG_PP_ENABLE_CMD_DONE_LEN	\
+	sizeof(viddec_msg_pp_enable_cmd_done)
+
+typedef struct {
+	unsigned short	packet_seq_number;
+	unsigned short	codec_instance_id;
+} __attribute__((packed)) viddec_msg_pp_enable_cmd_done;
+
+
+/*
+ * Message to inform ARM that one post processing frame has been decoded
+ */
+
+
+#define	VIDDEC_MSG_PP_FRAME_DONE		0x0003
+#define	VIDDEC_MSG_PP_FRAME_DONE_LEN	\
+	sizeof(viddec_msg_pp_frame_done)
+
+#define	VIDDEC_MSG_DISP_WORTHY_DISP		0x0000
+#define	VIDDEC_MSG_DISP_WORTHY_DISP_NONE	0xFFFF
+
+
+typedef struct {
+	unsigned short	packet_seq_number;
+	unsigned short	codec_instance_id;
+	unsigned short	display_worthy;
+} __attribute__((packed)) viddec_msg_pp_frame_done;
+
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5venccmdi.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5venccmdi.h
new file mode 100644
index 0000000..b3c018f
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5venccmdi.h
@@ -0,0 +1,231 @@
+#ifndef QDSP5VIDENCCMDI_H
+#define QDSP5VIDENCCMDI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+    V I D E O  E N C O D E R  I N T E R N A L  C O M M A N D S
+
+GENERAL DESCRIPTION
+  This file contains defintions of format blocks of commands
+  that are accepted by VIDENC Task
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+
+Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+			EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+
+Revision History:
+
+when       who     what, where, why
+--------   ---     ----------------------------------------------------------
+09/25/08   umeshp      initial version
+===========================================================================*/
+
+  #define VIDENC_CMD_CFG           0x0000
+  #define VIDENC_CMD_ACTIVE        0x0001
+  #define VIDENC_CMD_IDLE          0x0002
+  #define VIDENC_CMD_FRAME_START   0x0003
+  #define VIDENC_CMD_STATUS_QUERY  0x0004
+  #define VIDENC_CMD_RC_CFG        0x0005
+  #define VIDENC_CMD_INTRA_REFRESH 0x0006
+  #define VIDENC_CMD_CODEC_CONFIG  0x0007
+  #define VIDENC_CMD_VIDEO_CONFIG  0x0008
+  #define VIDENC_CMD_PARAMETER_UPDATE       0x0009
+  #define VIDENC_CMD_VENC_CLOCK    0x000A
+  #define VIDENC_CMD_DIS_CFG       0x000B
+  #define VIDENC_CMD_DIS           0x000C
+  #define VIDENC_CMD_DIGITAL_ZOOM  0x000D
+
+
+
+
+/*
+ * Command to pass the frame message information to VIDENC
+ */
+
+
+#define VIDENC_CMD_FRAME_START_LEN \
+	sizeof(videnc_cmd_frame_start)
+
+typedef struct {
+    unsigned short  cmd_id;
+    unsigned short  frame_info;
+    unsigned short  frame_rho_budget_word_high;
+    unsigned short  frame_rho_budget_word_low;
+    unsigned short  input_luma_addr_high;
+    unsigned short  input_luma_addr_low;
+    unsigned short  input_chroma_addr_high;
+    unsigned short  input_chroma_addr_low;
+    unsigned short  ref_vop_buf_ptr_high;
+    unsigned short  ref_vop_buf_ptr_low;
+    unsigned short  enc_pkt_buf_ptr_high;
+    unsigned short  enc_pkt_buf_ptr_low;
+    unsigned short  enc_pkt_buf_size_high;
+    unsigned short  enc_pkt_buf_size_low;
+    unsigned short  unfilt_recon_vop_buf_ptr_high;
+    unsigned short  unfilt_recon_vop_buf_ptr_low;
+    unsigned short  filt_recon_vop_buf_ptr_high;
+    unsigned short  filt_recon_vop_buf_ptr_low;
+} __attribute__((packed)) videnc_cmd_frame_start;
+
+/*
+ * Command to pass the frame-level digital stabilization parameters to VIDENC
+ */
+
+
+#define VIDENC_CMD_DIS_LEN \
+    sizeof(videnc_cmd_dis)
+
+typedef struct {
+    unsigned short  cmd_id;
+    unsigned short  vfe_out_prev_luma_addr_high;
+    unsigned short  vfe_out_prev_luma_addr_low;
+    unsigned short  stabilization_info;
+} __attribute__((packed)) videnc_cmd_dis;
+
+/*
+ * Command to pass the codec related parameters to VIDENC
+ */
+
+
+#define VIDENC_CMD_CFG_LEN \
+    sizeof(videnc_cmd_cfg)
+
+typedef struct {
+    unsigned short  cmd_id;
+    unsigned short  cfg_info_0;
+    unsigned short  cfg_info_1;
+    unsigned short  four_mv_threshold;
+    unsigned short  ise_fse_mv_cost_fac;
+	unsigned short  venc_frame_dim;
+	unsigned short  venc_DM_partition;
+} __attribute__((packed)) videnc_cmd_cfg;
+
+/*
+ * Command to start the video encoding
+ */
+
+
+#define VIDENC_CMD_ACTIVE_LEN \
+    sizeof(videnc_cmd_active)
+
+typedef struct {
+    unsigned short  cmd_id;
+} __attribute__((packed)) videnc_cmd_active;
+
+/*
+ * Command to stop the video encoding
+ */
+
+
+#define VIDENC_CMD_IDLE_LEN \
+    sizeof(videnc_cmd_idle)
+
+typedef struct {
+    unsigned short  cmd_id;
+} __attribute__((packed)) videnc_cmd_idle;
+
+/*
+ * Command to query staus of VIDENC
+ */
+
+
+#define VIDENC_CMD_STATUS_QUERY_LEN \
+    sizeof(videnc_cmd_status_query)
+
+typedef struct {
+    unsigned short  cmd_id;
+} __attribute__((packed)) videnc_cmd_status_query;
+
+/*
+ * Command to set rate control for a frame
+ */
+
+
+#define VIDENC_CMD_RC_CFG_LEN \
+    sizeof(videnc_cmd_rc_cfg)
+
+typedef struct {
+    unsigned short  cmd_id;
+	unsigned short  max_frame_qp_delta;
+	unsigned short  max_min_frame_qp;
+} __attribute__((packed)) videnc_cmd_rc_cfg;
+
+/*
+ * Command to set intra-refreshing
+ */
+
+
+#define VIDENC_CMD_INTRA_REFRESH_LEN \
+    sizeof(videnc_cmd_intra_refresh)
+
+typedef struct {
+    unsigned short  cmd_id;
+	unsigned short  num_mb_refresh;
+	unsigned short  mb_index[15];
+} __attribute__((packed)) videnc_cmd_intra_refresh;
+
+/*
+ * Command to pass digital zoom information to the VIDENC
+ */
+#define VIDENC_CMD_DIGITAL_ZOOM_LEN \
+    sizeof(videnc_cmd_digital_zoom)
+
+typedef struct {
+    unsigned short  cmd_id;
+    unsigned short  digital_zoom_en;
+    unsigned short  luma_frame_shift_X;
+    unsigned short  luma_frame_shift_Y;
+    unsigned short  up_ip_luma_rows;
+    unsigned short  up_ip_luma_cols;
+    unsigned short  up_ip_chroma_rows;
+    unsigned short  up_ip_chroma_cols;
+    unsigned short  luma_ph_incr_V_low;
+    unsigned short  luma_ph_incr_V_high;
+    unsigned short  luma_ph_incr_H_low;
+    unsigned short  luma_ph_incr_H_high;
+    unsigned short  chroma_ph_incr_V_low;
+    unsigned short  chroma_ph_incr_V_high;
+    unsigned short  chroma_ph_incr_H_low;
+    unsigned short  chroma_ph_incr_H_high;
+} __attribute__((packed)) videnc_cmd_digital_zoom;
+
+/*
+ * Command to configure digital stabilization parameters
+ */
+
+#define VIDENC_CMD_DIS_CFG_LEN \
+    sizeof(videnc_cmd_dis_cfg)
+
+typedef struct {
+    unsigned short  cmd_id;
+    unsigned short  image_stab_subf_start_row_col;
+    unsigned short  image_stab_subf_dim;
+    unsigned short  image_stab_info_0;
+} __attribute__((packed)) videnc_cmd_dis_cfg;
+
+
+/*
+ * Command to set VIDENC_CMD_VENC_CLOCK
+ */
+
+
+#define VIDENC_CMD_VENC_CLOCK_LEN \
+    sizeof(struct videnc_cmd_venc_clock)
+
+struct videnc_cmd_venc_clock {
+    unsigned short  cmd_id;
+    unsigned short  payload;
+} __attribute__((packed)) ;
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5vfecmdi.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5vfecmdi.h
new file mode 100644
index 0000000..4c5d752
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5vfecmdi.h
@@ -0,0 +1,910 @@
+#ifndef QDSP5VFECMDI_H
+#define QDSP5VFECMDI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+    V F E   I N T E R N A L   C O M M A N D S
+
+GENERAL DESCRIPTION
+  This file contains defintions of format blocks of commands 
+  that are accepted by VFE Task
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+
+Copyright (c) 1992-2009, Code Aurora Forum. 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+   
+$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5vfecmdi.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $                     
+Revision History:                                              
+  
+when       who     what, where, why
+--------   ---     ----------------------------------------------------------
+06/12/08   sv      initial version
+===========================================================================*/
+
+/******************************************************************************
+ * Commands through vfeCommandScaleQueue
+ *****************************************************************************/
+
+/*
+ * Command to program scaler for op1 . max op of scaler is VGA
+ */
+
+
+#define	VFE_CMD_SCALE_OP1_CFG		0x0000
+#define	VFE_CMD_SCALE_OP1_CFG_LEN	\
+	sizeof(vfe_cmd_scale_op1_cfg)
+
+#define	VFE_CMD_SCALE_OP1_SEL_IP_SEL_Y_STANDARD	0x0000
+#define	VFE_CMD_SCALE_OP1_SEL_IP_SEL_Y_CASCADED	0x0001
+#define	VFE_CMD_SCALE_OP1_SEL_H_Y_SCALER_DIS	0x0000
+#define	VFE_CMD_SCALE_OP1_SEL_H_Y_SCALER_ENA	0x0002
+#define	VFE_CMD_SCALE_OP1_SEL_H_PP_Y_SCALER_DIS	0x0000
+#define	VFE_CMD_SCALE_OP1_SEL_H_PP_Y_SCALER_ENA	0x0004
+#define	VFE_CMD_SCALE_OP1_SEL_V_Y_SCALER_DIS	0x0000
+#define	VFE_CMD_SCALE_OP1_SEL_V_Y_SCALER_ENA	0x0008
+#define	VFE_CMD_SCALE_OP1_SEL_V_PP_Y_SCALER_DIS	0x0000
+#define	VFE_CMD_SCALE_OP1_SEL_V_PP_Y_SCALER_ENA	0x0010
+#define	VFE_CMD_SCALE_OP1_SEL_IP_SEL_CBCR_STANDARD	0x0000
+#define	VFE_CMD_SCALE_OP1_SEL_IP_SEL_CBCR_CASCADED	0x0020
+#define	VFE_CMD_SCALE_OP1_SEL_H_CBCR_SCALER_DIS		0x0000
+#define	VFE_CMD_SCALE_OP1_SEL_H_CBCR_SCALER_ENA		0x0040
+#define	VFE_CMD_SCALE_OP1_SEL_V_CBCR_SCALER_DIS		0x0000
+#define	VFE_CMD_SCALE_OP1_SEL_V_CBCR_SCALER_ENA		0x0080
+
+#define	VFE_CMD_OP1_PP_Y_SCALER_CFG_PART1_DONT_LOAD_COEFFS	0x80000000
+#define	VFE_CMD_OP1_PP_Y_SCALER_CFG_PART1_LOAD_COEFFS	0x80000000
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	scale_op1_sel;
+	unsigned int	y_scaler_cfg_part1;
+	unsigned int	y_scaler_cfg_part2;
+	unsigned int	cbcr_scaler_cfg_part1;
+	unsigned int	cbcr_scaler_cfg_part2;
+	unsigned int	cbcr_scaler_cfg_part3;
+	unsigned int	pp_y_scaler_cfg_part1;
+	unsigned int	pp_y_scaler_cfg_part2;
+	unsigned int	y_scaler_v_coeff_bank_part1[16];
+	unsigned int	y_scaler_v_coeff_bank_part2[16];
+	unsigned int	y_scaler_h_coeff_bank_part1[16];
+	unsigned int	y_scaler_h_coeff_bank_part2[16];
+} __attribute__((packed)) vfe_cmd_scale_op1_cfg;
+
+
+/*
+ * Command to program scaler for op2
+ */
+
+#define	VFE_CMD_SCALE_OP2_CFG		0x0001
+#define	VFE_CMD_SCALE_OP2_CFG_LEN	\
+	sizeof(vfe_cmd_scale_op2_cfg)
+
+#define	VFE_CMD_SCALE_OP2_SEL_IP_SEL_Y_STANDARD	0x0000
+#define	VFE_CMD_SCALE_OP2_SEL_IP_SEL_Y_CASCADED	0x0001
+#define	VFE_CMD_SCALE_OP2_SEL_H_Y_SCALER_DIS	0x0000
+#define	VFE_CMD_SCALE_OP2_SEL_H_Y_SCALER_ENA	0x0002
+#define	VFE_CMD_SCALE_OP2_SEL_H_PP_Y_SCALER_DIS	0x0000
+#define	VFE_CMD_SCALE_OP2_SEL_H_PP_Y_SCALER_ENA	0x0004
+#define	VFE_CMD_SCALE_OP2_SEL_V_Y_SCALER_DIS	0x0000
+#define	VFE_CMD_SCALE_OP2_SEL_V_Y_SCALER_ENA	0x0008
+#define	VFE_CMD_SCALE_OP2_SEL_V_PP_Y_SCALER_DIS	0x0000
+#define	VFE_CMD_SCALE_OP2_SEL_V_PP_Y_SCALER_ENA	0x0010
+#define	VFE_CMD_SCALE_OP2_SEL_IP_SEL_CBCR_STANDARD	0x0000
+#define	VFE_CMD_SCALE_OP2_SEL_IP_SEL_CBCR_CASCADED	0x0020
+#define	VFE_CMD_SCALE_OP2_SEL_H_CBCR_SCALER_DIS		0x0000
+#define	VFE_CMD_SCALE_OP2_SEL_H_CBCR_SCALER_ENA		0x0040
+#define	VFE_CMD_SCALE_OP2_SEL_V_CBCR_SCALER_DIS		0x0000
+#define	VFE_CMD_SCALE_OP2_SEL_V_CBCR_SCALER_ENA		0x0080
+
+#define	VFE_CMD_OP2_PP_Y_SCALER_CFG_PART1_DONT_LOAD_COEFFS	0x80000000
+#define	VFE_CMD_OP2_PP_Y_SCALER_CFG_PART1_LOAD_COEFFS		0x80000000
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	scale_op2_sel;
+	unsigned int	y_scaler_cfg_part1;
+	unsigned int	y_scaler_cfg_part2;
+	unsigned int	cbcr_scaler_cfg_part1;
+	unsigned int	cbcr_scaler_cfg_part2;
+	unsigned int	cbcr_scaler_cfg_part3;
+	unsigned int	pp_y_scaler_cfg_part1;
+	unsigned int	pp_y_scaler_cfg_part2;
+	unsigned int	y_scaler_v_coeff_bank_part1[16];
+	unsigned int	y_scaler_v_coeff_bank_part2[16];
+	unsigned int	y_scaler_h_coeff_bank_part1[16];
+	unsigned int	y_scaler_h_coeff_bank_part2[16];
+} __attribute__((packed)) vfe_cmd_scale_op2_cfg;
+
+
+/******************************************************************************
+ * Commands through vfeCommandTableQueue
+ *****************************************************************************/
+
+/*
+ * Command to program the AXI ip paths
+ */
+
+#define	VFE_CMD_AXI_IP_CFG		0x0000
+#define	VFE_CMD_AXI_IP_CFG_LEN		sizeof(vfe_cmd_axi_ip_cfg)
+
+#define	VFE_CMD_IP_SEL_IP_FORMAT_8	0x0000
+#define	VFE_CMD_IP_SEL_IP_FORMAT_10	0x0001
+#define	VFE_CMD_IP_SEL_IP_FORMAT_12	0x0002
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	ip_sel;
+	unsigned int	ip_cfg_part1;
+	unsigned int	ip_cfg_part2;
+	unsigned int	ip_unpack_cfg_part[6];
+	unsigned int	ip_buf_addr[8];
+} __attribute__ ((packed)) vfe_cmd_axi_ip_cfg;
+
+
+/*
+ * Command to program axi op paths
+ */
+
+#define	VFE_CMD_AXI_OP_CFG	0x0001
+#define	VFE_CMD_AXI_OP_CFG_LEN	sizeof(vfe_cmd_axi_op_cfg)
+
+#define	VFE_CMD_OP_SEL_OP1		0x0000
+#define	VFE_CMD_OP_SEL_OP2		0x0001
+#define	VFE_CMD_OP_SEL_OP1_OP2		0x0002
+#define	VFE_CMD_OP_SEL_CTOA		0x0003
+#define	VFE_CMD_OP_SEL_CTOA_OP1		0x0004
+#define	VFE_CMD_OP_SEL_CTOA_OP2		0x0005
+#define	VFE_CMD_OP_SEL_OP_FORMAT_8	0x0000
+#define	VFE_CMD_OP_SEL_OP_FORMAT_10	0x0008
+#define	VFE_CMD_OP_SEL_OP_FORMAT_12	0x0010
+
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	op_sel;
+	unsigned int	op1_y_cfg_part1;
+	unsigned int	op1_y_cfg_part2;
+	unsigned int	op1_cbcr_cfg_part1;
+	unsigned int	op1_cbcr_cfg_part2;
+	unsigned int	op2_y_cfg_part1;
+	unsigned int	op2_y_cfg_part2;
+	unsigned int	op2_cbcr_cfg_part1;
+	unsigned int	op2_cbcr_cfg_part2;
+	unsigned int	op1_buf1_addr[16];
+	unsigned int	op2_buf1_addr[16];
+} __attribute__((packed)) vfe_cmd_axi_op_cfg;
+
+
+
+
+/*
+ * Command to program the roll off correction module
+ */
+
+#define	VFE_CMD_ROLLOFF_CFG	0x0002
+#define	VFE_CMD_ROLLOFF_CFG_LEN	\
+	sizeof(vfe_cmd_rolloff_cfg)
+
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	correction_opt_center_pos;
+	unsigned int	radius_square_entry[32];
+	unsigned int	red_table_entry[32];
+	unsigned int	green_table_entry[32];
+	unsigned int	blue_table_entry[32];
+} __attribute__((packed)) vfe_cmd_rolloff_cfg;
+
+/*
+ * Command to program RGB gamma table
+ */
+
+#define	VFE_CMD_RGB_GAMMA_CFG		0x0003
+#define	VFE_CMD_RGB_GAMMA_CFG_LEN	\
+	sizeof(vfe_cmd_rgb_gamma_cfg)
+
+#define	VFE_CMD_RGB_GAMMA_SEL_LINEAR		0x0000
+#define	VFE_CMD_RGB_GAMMA_SEL_PW_LINEAR		0x0001
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	rgb_gamma_sel;
+	unsigned int	rgb_gamma_entry[256];
+} __attribute__((packed)) vfe_cmd_rgb_gamma_cfg;
+
+
+/*
+ * Command to program luma gamma table for the noise reduction path
+ */
+
+#define	VFE_CMD_Y_GAMMA_CFG		0x0004
+#define	VFE_CMD_Y_GAMMA_CFG_LEN		\
+	sizeof(vfe_cmd_y_gamma_cfg)
+
+#define	VFE_CMD_Y_GAMMA_SEL_LINEAR	0x0000
+#define	VFE_CMD_Y_GAMMA_SEL_PW_LINEAR	0x0001
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	y_gamma_sel;
+	unsigned int	y_gamma_entry[256];	
+} __attribute__((packed)) vfe_cmd_y_gamma_cfg;
+
+
+
+/******************************************************************************
+ * Commands through vfeCommandQueue
+ *****************************************************************************/
+
+/*
+ * Command to reset the VFE to a known good state.All previously programmed 
+ * Params will be lost
+ */
+
+
+#define	VFE_CMD_RESET		0x0000
+#define	VFE_CMD_RESET_LEN	sizeof(vfe_cmd_reset)
+
+
+typedef struct {
+	unsigned short	cmd_id;
+} __attribute__((packed)) vfe_cmd_reset;
+
+
+/*
+ * Command to start VFE processing based on the config params
+ */
+
+
+#define	VFE_CMD_START		0x0001
+#define	VFE_CMD_START_LEN	sizeof(vfe_cmd_start)
+
+#define	VFE_CMD_STARTUP_PARAMS_SRC_CAMIF	0x0000
+#define	VFE_CMD_STARTUP_PARAMS_SRC_AXI		0x0001
+#define	VFE_CMD_STARTUP_PARAMS_MODE_CONTINUOUS	0x0000
+#define	VFE_CMD_STARTUP_PARAMS_MODE_SNAPSHOT	0x0002
+
+#define	VFE_CMD_IMAGE_PL_BLACK_LVL_CORR_DIS	0x0000
+#define	VFE_CMD_IMAGE_PL_BLACK_LVL_CORR_ENA	0x0001
+#define	VFE_CMD_IMAGE_PL_ROLLOFF_CORR_DIS	0x0000
+#define	VFE_CMD_IMAGE_PL_ROLLOFF_CORR_ENA	0x0002
+#define	VFE_CMD_IMAGE_PL_WHITE_BAL_DIS		0x0000
+#define	VFE_CMD_IMAGE_PL_WHITE_BAL_ENA		0x0004
+#define	VFE_CMD_IMAGE_PL_RGB_GAMMA_DIS		0x0000
+#define	VFE_CMD_IMAGE_PL_RGB_GAMMA_ENA		0x0008
+#define	VFE_CMD_IMAGE_PL_LUMA_NOISE_RED_PATH_DIS	0x0000
+#define	VFE_CMD_IMAGE_PL_LUMA_NOISE_RED_PATH_ENA	0x0010
+#define	VFE_CMD_IMAGE_PL_ADP_FILTER_DIS		0x0000
+#define	VFE_CMD_IMAGE_PL_ADP_FILTER_ENA		0x0020
+#define	VFE_CMD_IMAGE_PL_CHROMA_SAMP_DIS	0x0000
+#define	VFE_CMD_IMAGE_PL_CHROMA_SAMP_ENA	0x0040
+
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	startup_params;
+	unsigned int	image_pipeline;
+	unsigned int	frame_dimension;
+} __attribute__((packed)) vfe_cmd_start;
+
+
+/*
+ * Command to halt all processing
+ */
+
+#define	VFE_CMD_STOP		0x0002
+#define	VFE_CMD_STOP_LEN	sizeof(vfe_cmd_stop)
+
+typedef struct {
+	unsigned short	cmd_id;
+} __attribute__((packed)) vfe_cmd_stop;
+
+
+/*
+ * Command to commit the params that have been programmed to take
+ * effect on the next frame
+ */
+
+#define	VFE_CMD_UPDATE		0x0003
+#define	VFE_CMD_UPDATE_LEN	sizeof(vfe_cmd_update)
+
+
+typedef struct {
+	unsigned short	cmd_id;
+} __attribute__((packed)) vfe_cmd_update;
+
+
+/*
+ * Command to program CAMIF module
+ */
+
+#define	VFE_CMD_CAMIF_CFG	0x0004
+#define	VFE_CMD_CAMIF_CFG_LEN	sizeof(vfe_cmd_camif_cfg)
+
+#define	VFE_CMD_CFG_VSYNC_SYNC_EDGE_HIGH	0x0000
+#define	VFE_CMD_CFG_VSYNC_SYNC_EDGE_LOW		0x0002
+#define	VFE_CMD_CFG_HSYNC_SYNC_EDGE_HIGH	0x0000
+#define	VFE_CMD_CFG_HSYNC_SYNC_EDGE_LOW		0x0004
+#define	VFE_CMD_CFG_SYNC_MODE_APS		0x0000
+#define	VFE_CMD_CFG_SYNC_MODE_EFS		0X0008
+#define	VFE_CMD_CFG_SYNC_MODE_ELS		0x0010
+#define	VFE_CMD_CFG_SYNC_MODE_RVD		0x0018
+#define	VFE_CMD_CFG_VFE_SUBSAMP_EN_DIS		0x0000
+#define	VFE_CMD_CFG_VFE_SUBSAMP_EN_ENA		0x0020
+#define	VFE_CMD_CFG_BUS_SUBSAMP_EN_DIS		0x0000
+#define	VFE_CMD_CFG_BUS_SUBSAMP_EN_ENA		0x0080
+#define	VFE_CMD_CFG_IRQ_SUBSAMP_EN_DIS		0x0000
+#define	VFE_CMD_CFG_IRQ_SUBSAMP_EN_ENA		0x0800
+
+#define	VFE_CMD_SUBSAMP2_CFG_PIXEL_SKIP_16	0x0000
+#define	VFE_CMD_SUBSAMP2_CFG_PIXEL_SKIP_12	0x0010
+
+#define	VFE_CMD_EPOCH_IRQ_1_DIS			0x0000
+#define	VFE_CMD_EPOCH_IRQ_1_ENA			0x4000
+#define	VFE_CMD_EPOCH_IRQ_2_DIS			0x0000
+#define	VFE_CMD_EPOCH_IRQ_2_ENA			0x8000
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	cfg;
+	unsigned int	efs_cfg;
+	unsigned int	frame_cfg;
+	unsigned int	window_width_cfg;
+	unsigned int	window_height_cfg;
+	unsigned int	subsamp1_cfg;
+	unsigned int	subsamp2_cfg;
+	unsigned int	epoch_irq;
+} __attribute__((packed)) vfe_cmd_camif_cfg;
+
+
+
+/*
+ * Command to program the black level module
+ */
+
+#define	VFE_CMD_BLACK_LVL_CFG		0x0005
+#define	VFE_CMD_BLACK_LVL_CFG_LEN	sizeof(vfe_cmd_black_lvl_cfg)
+
+#define	VFE_CMD_BL_SEL_MANUAL		0x0000
+#define	VFE_CMD_BL_SEL_AUTO		0x0001
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	black_lvl_sel;
+	unsigned int	cfg_part[3];
+} __attribute__((packed)) vfe_cmd_black_lvl_cfg;
+
+
+/*
+ * Command to program the active region by cropping the region of interest
+ */
+
+#define	VFE_CMD_ACTIVE_REGION_CFG	0x0006
+#define	VFE_CMD_ACTIVE_REGION_CFG_LEN	\
+	sizeof(vfe_cmd_active_region_cfg)
+
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	cfg_part1;
+	unsigned int	cfg_part2;
+} __attribute__((packed)) vfe_cmd_active_region_cfg;
+
+
+
+/*
+ * Command to program the defective pixel correction(DPC) ,
+ * adaptive bayer filter (ABF) and demosaic modules
+ */
+
+#define	VFE_CMD_DEMOSAIC_CFG		0x0007
+#define	VFE_CMD_DEMOSAIC_CFG_LEN	sizeof(vfe_cmd_demosaic_cfg)
+
+#define	VFE_CMD_DEMOSAIC_PART1_ABF_EN_DIS	0x0000
+#define	VFE_CMD_DEMOSAIC_PART1_ABF_EN_ENA	0x0001
+#define	VFE_CMD_DEMOSAIC_PART1_DPC_EN_DIS	0x0000
+#define	VFE_CMD_DEMOSAIC_PART1_DPC_EN_ENA	0x0002
+#define	VFE_CMD_DEMOSAIC_PART1_FORCE_ABF_OFF	0x0000
+#define	VFE_CMD_DEMOSAIC_PART1_FORCE_ABF_ON	0x0004
+#define	VFE_CMD_DEMOSAIC_PART1_SLOPE_SHIFT_1	0x00000000
+#define	VFE_CMD_DEMOSAIC_PART1_SLOPE_SHIFT_2	0x10000000
+#define	VFE_CMD_DEMOSAIC_PART1_SLOPE_SHIFT_4	0x20000000
+#define	VFE_CMD_DEMOSAIC_PART1_SLOPE_SHIFT_8	0x30000000
+#define	VFE_CMD_DEMOSAIC_PART1_SLOPE_SHIFT_1_2	0x50000000
+#define	VFE_CMD_DEMOSAIC_PART1_SLOPE_SHIFT_1_4	0x60000000
+#define	VFE_CMD_DEMOSAIC_PART1_SLOPE_SHIFT_1_8	0x70000000
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	demosaic_part1;
+	unsigned int	demosaic_part2;
+	unsigned int	demosaic_part3;
+	unsigned int	demosaic_part4;
+	unsigned int	demosaic_part5;
+} __attribute__((packed)) vfe_cmd_demosaic_cfg;
+
+
+/*
+ * Command to program the ip format
+ */
+
+#define	VFE_CMD_IP_FORMAT_CFG		0x0008
+#define	VFE_CMD_IP_FORMAT_CFG_LEN	\
+	sizeof(vfe_cmd_ip_format_cfg)
+
+#define	VFE_CMD_IP_FORMAT_SEL_RGRG	0x0000
+#define	VFE_CMD_IP_FORMAT_SEL_GRGR	0x0001
+#define	VFE_CMD_IP_FORMAT_SEL_BGBG	0x0002
+#define	VFE_CMD_IP_FORMAT_SEL_GBGB	0x0003
+#define	VFE_CMD_IP_FORMAT_SEL_YCBYCR	0x0004
+#define	VFE_CMD_IP_FORMAT_SEL_YCRYCB	0x0005
+#define	VFE_CMD_IP_FORMAT_SEL_CBYCRY	0x0006
+#define	VFE_CMD_IP_FORMAT_SEL_CRYCBY	0x0007
+#define	VFE_CMD_IP_FORMAT_SEL_NO_CHROMA	0x0000
+#define	VFE_CMD_IP_FORMAT_SEL_CHROMA	0x0008
+
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	ip_format_sel;
+	unsigned int	balance_gains_part1;
+	unsigned int	balance_gains_part2;
+} __attribute__((packed)) vfe_cmd_ip_format_cfg;
+
+
+
+/*
+ * Command to program max and min allowed op values
+ */
+
+#define	VFE_CMD_OP_CLAMP_CFG		0x0009
+#define	VFE_CMD_OP_CLAMP_CFG_LEN	\
+	sizeof(vfe_cmd_op_clamp_cfg)
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	op_clamp_max;
+	unsigned int	op_clamp_min;
+} __attribute__((packed)) vfe_cmd_op_clamp_cfg;
+
+
+/*
+ * Command to program chroma sub sample module
+ */
+
+#define	VFE_CMD_CHROMA_SUBSAMPLE_CFG		0x000A
+#define	VFE_CMD_CHROMA_SUBSAMPLE_CFG_LEN	\
+	sizeof(vfe_cmd_chroma_subsample_cfg)
+
+#define	VFE_CMD_CHROMA_SUBSAMP_SEL_H_INTERESTIAL_SAMPS	0x0000
+#define	VFE_CMD_CHROMA_SUBSAMP_SEL_H_COSITED_SAMPS	0x0001
+#define	VFE_CMD_CHROMA_SUBSAMP_SEL_V_INTERESTIAL_SAMPS	0x0000
+#define	VFE_CMD_CHROMA_SUBSAMP_SEL_V_COSITED_SAMPS	0x0002
+#define	VFE_CMD_CHROMA_SUBSAMP_SEL_H_SUBSAMP_DIS	0x0000
+#define	VFE_CMD_CHROMA_SUBSAMP_SEL_H_SUBSAMP_ENA	0x0004
+#define	VFE_CMD_CHROMA_SUBSAMP_SEL_V_SUBSAMP_DIS	0x0000
+#define	VFE_CMD_CHROMA_SUBSAMP_SEL_V_SUBSAMP_ENA	0x0008
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	chroma_subsamp_sel;
+} __attribute__((packed)) vfe_cmd_chroma_subsample_cfg;
+
+
+/*
+ * Command to program the white balance module
+ */
+
+#define	VFE_CMD_WHITE_BALANCE_CFG	0x000B
+#define	VFE_CMD_WHITE_BALANCE_CFG_LEN	\
+	sizeof(vfe_cmd_white_balance_cfg)
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	white_balance_gains;
+} __attribute__((packed)) vfe_cmd_white_balance_cfg;
+
+
+/*
+ * Command to program the color processing module
+ */
+
+#define	VFE_CMD_COLOR_PROCESS_CFG	0x000C
+#define	VFE_CMD_COLOR_PROCESS_CFG_LEN	\
+	sizeof(vfe_cmd_color_process_cfg)
+
+#define	VFE_CMD_COLOR_CORRE_PART7_Q7_FACTORS	0x0000
+#define	VFE_CMD_COLOR_CORRE_PART7_Q8_FACTORS	0x0001
+#define	VFE_CMD_COLOR_CORRE_PART7_Q9_FACTORS	0x0002
+#define	VFE_CMD_COLOR_CORRE_PART7_Q10_FACTORS	0x0003
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	color_correction_part1;
+	unsigned int	color_correction_part2;
+	unsigned int	color_correction_part3;
+	unsigned int	color_correction_part4;
+	unsigned int	color_correction_part5;
+	unsigned int	color_correction_part6;
+	unsigned int	color_correction_part7;
+	unsigned int	chroma_enhance_part1;
+	unsigned int	chroma_enhance_part2;
+	unsigned int	chroma_enhance_part3;
+	unsigned int	chroma_enhance_part4;
+	unsigned int	chroma_enhance_part5;
+	unsigned int	luma_calc_part1;
+	unsigned int	luma_calc_part2;
+} __attribute__((packed)) vfe_cmd_color_process_cfg;
+
+
+/*
+ * Command to program adaptive filter module
+ */
+
+#define	VFE_CMD_ADP_FILTER_CFG		0x000D
+#define	VFE_CMD_ADP_FILTER_CFG_LEN	\
+	sizeof(vfe_cmd_adp_filter_cfg)
+
+#define	VFE_CMD_ASF_CFG_PART_SMOOTH_FILTER_DIS		0x0000
+#define	VFE_CMD_ASF_CFG_PART_SMOOTH_FILTER_ENA		0x0001
+#define	VFE_CMD_ASF_CFG_PART_NO_SHARP_MODE		0x0000
+#define	VFE_CMD_ASF_CFG_PART_SINGLE_FILTER		0x0002
+#define	VFE_CMD_ASF_CFG_PART_DUAL_FILTER		0x0004
+#define	VFE_CMD_ASF_CFG_PART_SHARP_MODE			0x0007
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	asf_cfg_part[7];
+} __attribute__((packed)) vfe_cmd_adp_filter_cfg;
+
+
+/*
+ * Command to program for frame skip pattern for op1 and op2
+ */
+
+#define	VFE_CMD_FRAME_SKIP_CFG		0x000E
+#define	VFE_CMD_FRAME_SKIP_CFG_LEN	\
+	sizeof(vfe_cmd_frame_skip_cfg)
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	frame_skip_pattern_op1;
+	unsigned int	frame_skip_pattern_op2;
+} __attribute__((packed)) vfe_cmd_frame_skip_cfg;
+
+
+/*
+ * Command to program field-of-view crop for digital zoom
+ */
+
+#define	VFE_CMD_FOV_CROP	0x000F
+#define	VFE_CMD_FOV_CROP_LEN	sizeof(vfe_cmd_fov_crop)
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	fov_crop_part1;
+	unsigned int	fov_crop_part2;
+} __attribute__((packed)) vfe_cmd_fov_crop; 
+
+
+
+/*
+ * Command to program auto focus(AF) statistics module
+ */
+
+#define	VFE_CMD_STATS_AUTOFOCUS_CFG	0x0010
+#define	VFE_CMD_STATS_AUTOFOCUS_CFG_LEN	\
+	sizeof(vfe_cmd_stats_autofocus_cfg)
+
+#define	VFE_CMD_AF_STATS_SEL_STATS_DIS	0x0000
+#define	VFE_CMD_AF_STATS_SEL_STATS_ENA	0x0001
+#define	VFE_CMD_AF_STATS_SEL_PRI_FIXED	0x0000
+#define	VFE_CMD_AF_STATS_SEL_PRI_VAR	0x0002
+#define	VFE_CMD_AF_STATS_CFG_PART_METRIC_SUM	0x00000000
+#define	VFE_CMD_AF_STATS_CFG_PART_METRIC_MAX	0x00200000
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	af_stats_sel;
+	unsigned int	af_stats_cfg_part[8];
+	unsigned int	af_stats_op_buf_hdr;
+	unsigned int	af_stats_op_buf[3];
+} __attribute__((packed)) vfe_cmd_stats_autofocus_cfg;
+
+
+/*
+ * Command to program White balance(wb) and exposure (exp)
+ * statistics module
+ */
+
+#define	VFE_CMD_STATS_WB_EXP_CFG	0x0011
+#define	VFE_CMD_STATS_WB_EXP_CFG_LEN	\
+	sizeof(vfe_cmd_stats_wb_exp_cfg)
+
+#define	VFE_CMD_WB_EXP_STATS_SEL_STATS_DIS	0x0000
+#define	VFE_CMD_WB_EXP_STATS_SEL_STATS_ENA	0x0001
+#define	VFE_CMD_WB_EXP_STATS_SEL_PRI_FIXED	0x0000
+#define	VFE_CMD_WB_EXP_STATS_SEL_PRI_VAR	0x0002
+
+#define	VFE_CMD_WB_EXP_STATS_CFG_PART1_EXP_REG_8_8	0x0000
+#define	VFE_CMD_WB_EXP_STATS_CFG_PART1_EXP_REG_16_16	0x0001
+#define	VFE_CMD_WB_EXP_STATS_CFG_PART1_EXP_SREG_8_8	0x0000
+#define	VFE_CMD_WB_EXP_STATS_CFG_PART1_EXP_SREG_4_4	0x0002
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	wb_exp_stats_sel;
+	unsigned int	wb_exp_stats_cfg_part1;
+	unsigned int	wb_exp_stats_cfg_part2;
+	unsigned int	wb_exp_stats_cfg_part3;
+	unsigned int	wb_exp_stats_cfg_part4;
+	unsigned int	wb_exp_stats_op_buf_hdr;
+	unsigned int	wb_exp_stats_op_buf[3];
+} __attribute__((packed)) vfe_cmd_stats_wb_exp_cfg;
+
+
+/*
+ * Command to program histogram(hg) stats module
+ */
+
+#define	VFE_CMD_STATS_HG_CFG		0x0012
+#define	VFE_CMD_STATS_HG_CFG_LEN	\
+	sizeof(vfe_cmd_stats_hg_cfg)
+
+#define	VFE_CMD_HG_STATS_SEL_PRI_FIXED	0x0000
+#define	VFE_CMD_HG_STATS_SEL_PRI_VAR	0x0002
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	hg_stats_sel;
+	unsigned int	hg_stats_cfg_part1;
+	unsigned int	hg_stats_cfg_part2;
+	unsigned int	hg_stats_op_buf_hdr;
+	unsigned int	hg_stats_op_buf;
+} __attribute__((packed)) vfe_cmd_stats_hg_cfg;
+
+
+/*
+ * Command to acknowledge last MSG_VFE_OP1 message
+ */
+
+#define	VFE_CMD_OP1_ACK		0x0013
+#define	VFE_CMD_OP1_ACK_LEN	sizeof(vfe_cmd_op1_ack)
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	op1_buf_y_addr;
+	unsigned int	op1_buf_cbcr_addr;
+} __attribute__((packed)) vfe_cmd_op1_ack;
+
+
+
+/*
+ * Command to acknowledge last MSG_VFE_OP2 message
+ */
+
+#define	VFE_CMD_OP2_ACK		0x0014
+#define	VFE_CMD_OP2_ACK_LEN	sizeof(vfe_cmd_op2_ack)
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	op2_buf_y_addr;
+	unsigned int	op2_buf_cbcr_addr;
+} __attribute__((packed)) vfe_cmd_op2_ack;
+
+
+
+/*
+ * Command to acknowledge MSG_VFE_STATS_AUTOFOCUS msg
+ */
+
+#define	VFE_CMD_STATS_AF_ACK		0x0015
+#define	VFE_CMD_STATS_AF_ACK_LEN	sizeof(vfe_cmd_stats_af_ack)
+
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	af_stats_op_buf;
+} __attribute__((packed)) vfe_cmd_stats_af_ack;
+
+
+/*
+ * Command to acknowledge MSG_VFE_STATS_WB_EXP msg
+ */
+
+#define	VFE_CMD_STATS_WB_EXP_ACK	0x0016
+#define	VFE_CMD_STATS_WB_EXP_ACK_LEN	sizeof(vfe_cmd_stats_wb_exp_ack)
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	wb_exp_stats_op_buf;
+} __attribute__((packed)) vfe_cmd_stats_wb_exp_ack;
+
+
+/*
+ * Command to acknowledge MSG_VFE_EPOCH1 message
+ */
+
+#define	VFE_CMD_EPOCH1_ACK	0x0017
+#define	VFE_CMD_EPOCH1_ACK_LEN	sizeof(vfe_cmd_epoch1_ack)
+
+typedef struct {
+	unsigned short cmd_id;
+} __attribute__((packed)) vfe_cmd_epoch1_ack;
+
+
+/*
+ * Command to acknowledge MSG_VFE_EPOCH2 message
+ */
+
+#define	VFE_CMD_EPOCH2_ACK	0x0018
+#define	VFE_CMD_EPOCH2_ACK_LEN	sizeof(vfe_cmd_epoch2_ack)
+
+typedef struct {
+	unsigned short cmd_id;
+} __attribute__((packed)) vfe_cmd_epoch2_ack;
+
+
+
+/*
+ * Command to configure, enable or disable synchronous timer1
+ */
+
+#define	VFE_CMD_SYNC_TIMER1_CFG		0x0019
+#define	VFE_CMD_SYNC_TIMER1_CFG_LEN	\
+	sizeof(vfe_cmd_sync_timer1_cfg)
+
+#define	VFE_CMD_SYNC_T1_CFG_PART1_TIMER_DIS	0x0000
+#define	VFE_CMD_SYNC_T1_CFG_PART1_TIMER_ENA	0x0001
+#define	VFE_CMD_SYNC_T1_CFG_PART1_POL_HIGH	0x0000
+#define	VFE_CMD_SYNC_T1_CFG_PART1_POL_LOW	0x0002
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	sync_t1_cfg_part1;
+	unsigned int	sync_t1_h_sync_countdown;
+	unsigned int	sync_t1_pclk_countdown;
+	unsigned int	sync_t1_duration;
+} __attribute__((packed)) vfe_cmd_sync_timer1_cfg;
+
+
+/*
+ * Command to configure, enable or disable synchronous timer1
+ */
+
+#define	VFE_CMD_SYNC_TIMER2_CFG		0x001A
+#define	VFE_CMD_SYNC_TIMER2_CFG_LEN	\
+	sizeof(vfe_cmd_sync_timer2_cfg)
+
+#define	VFE_CMD_SYNC_T2_CFG_PART1_TIMER_DIS	0x0000
+#define	VFE_CMD_SYNC_T2_CFG_PART1_TIMER_ENA	0x0001
+#define	VFE_CMD_SYNC_T2_CFG_PART1_POL_HIGH	0x0000
+#define	VFE_CMD_SYNC_T2_CFG_PART1_POL_LOW	0x0002
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	sync_t2_cfg_part1;
+	unsigned int	sync_t2_h_sync_countdown;
+	unsigned int	sync_t2_pclk_countdown;
+	unsigned int	sync_t2_duration;
+} __attribute__((packed)) vfe_cmd_sync_timer2_cfg;
+
+
+/*
+ * Command to configure and start asynchronous timer1
+ */
+
+#define	VFE_CMD_ASYNC_TIMER1_START	0x001B
+#define	VFE_CMD_ASYNC_TIMER1_START_LEN	\
+	sizeof(vfe_cmd_async_timer1_start)
+
+#define	VFE_CMD_ASYNC_T1_POLARITY_A_HIGH	0x0000
+#define	VFE_CMD_ASYNC_T1_POLARITY_A_LOW		0x0001
+#define	VFE_CMD_ASYNC_T1_POLARITY_B_HIGH	0x0000
+#define	VFE_CMD_ASYNC_T1_POLARITY_B_LOW		0x0002
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	async_t1a_cfg;
+	unsigned int	async_t1b_cfg;
+	unsigned int	async_t1_polarity;
+} __attribute__((packed)) vfe_cmd_async_timer1_start;
+
+
+/*
+ * Command to configure and start asynchronous timer2
+ */
+
+#define	VFE_CMD_ASYNC_TIMER2_START	0x001C
+#define	VFE_CMD_ASYNC_TIMER2_START_LEN	\
+	sizeof(vfe_cmd_async_timer2_start)
+
+#define	VFE_CMD_ASYNC_T2_POLARITY_A_HIGH	0x0000
+#define	VFE_CMD_ASYNC_T2_POLARITY_A_LOW		0x0001
+#define	VFE_CMD_ASYNC_T2_POLARITY_B_HIGH	0x0000
+#define	VFE_CMD_ASYNC_T2_POLARITY_B_LOW		0x0002
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	async_t2a_cfg;
+	unsigned int	async_t2b_cfg;
+	unsigned int	async_t2_polarity;
+} __attribute__((packed)) vfe_cmd_async_timer2_start;
+
+
+/*
+ * Command to program partial configurations of auto focus(af)
+ */
+
+#define	VFE_CMD_STATS_AF_UPDATE		0x001D
+#define	VFE_CMD_STATS_AF_UPDATE_LEN	\
+	sizeof(vfe_cmd_stats_af_update)
+
+#define	VFE_CMD_AF_UPDATE_PART1_WINDOW_ONE	0x00000000
+#define	VFE_CMD_AF_UPDATE_PART1_WINDOW_MULTI	0x80000000
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	af_update_part1;
+	unsigned int	af_update_part2;
+} __attribute__((packed)) vfe_cmd_stats_af_update;
+
+
+/*
+ * Command to program partial cfg of wb and exp
+ */
+
+#define	VFE_CMD_STATS_WB_EXP_UPDATE	0x001E
+#define	VFE_CMD_STATS_WB_EXP_UPDATE_LEN	\
+	sizeof(vfe_cmd_stats_wb_exp_update)
+
+#define	VFE_CMD_WB_EXP_UPDATE_PART1_REGIONS_8_8		0x0000
+#define	VFE_CMD_WB_EXP_UPDATE_PART1_REGIONS_16_16	0x0001
+#define	VFE_CMD_WB_EXP_UPDATE_PART1_SREGIONS_8_8	0x0000
+#define	VFE_CMD_WB_EXP_UPDATE_PART1_SREGIONS_4_4	0x0002
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	wb_exp_update_part1;
+	unsigned int	wb_exp_update_part2;
+	unsigned int	wb_exp_update_part3;
+	unsigned int	wb_exp_update_part4;
+} __attribute__((packed)) vfe_cmd_stats_wb_exp_update;
+
+
+
+/*
+ * Command to re program the CAMIF FRAME CONFIG settings
+ */
+
+#define	VFE_CMD_UPDATE_CAMIF_FRAME_CFG		0x001F
+#define	VFE_CMD_UPDATE_CAMIF_FRAME_CFG_LEN	\
+	sizeof(vfe_cmd_update_camif_frame_cfg)
+
+typedef struct {
+	unsigned int	cmd_id;
+	unsigned int	camif_frame_cfg;
+} __attribute__((packed)) vfe_cmd_update_camif_frame_cfg;
+
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5vfemsg.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5vfemsg.h
new file mode 100644
index 0000000..a628f92
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5vfemsg.h
@@ -0,0 +1,290 @@
+#ifndef QDSP5VFEMSGI_H
+#define QDSP5VFEMSGI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+    V F E   I N T E R N A L   M E S S A G E S
+
+GENERAL DESCRIPTION
+  This file contains defintions of format blocks of commands 
+  that are sent by VFE Task
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+
+Copyright (c) 1992-2009, Code Aurora Forum. 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+/*===========================================================================
+
+                      EDIT HISTORY FOR FILE
+
+This section contains comments describing changes made to this file.
+Notice that changes are listed in reverse chronological order.
+   
+$Header: //source/qcom/qct/multimedia2/AdspSvc/7XXX/qdsp5cmd/video/qdsp5vfemsg.h#2 $ $DateTime: 2008/07/30 10:50:23 $ $Author: pavanr $                     
+Revision History:                                              
+  
+when       who     what, where, why
+--------   ---     ----------------------------------------------------------
+06/12/08   sv      initial version
+===========================================================================*/
+
+
+/*
+ * Message to acknowledge CMD_VFE_REST command
+ */
+
+#define	VFE_MSG_RESET_ACK	0x0000
+#define	VFE_MSG_RESET_ACK_LEN	sizeof(vfe_msg_reset_ack)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_reset_ack;
+
+
+/*
+ * Message to acknowledge CMD_VFE_START command
+ */
+
+#define	VFE_MSG_START_ACK	0x0001
+#define	VFE_MSG_START_ACK_LEN	sizeof(vfe_msg_start_ack)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_start_ack;
+
+/*
+ * Message to acknowledge CMD_VFE_STOP	command
+ */
+
+#define	VFE_MSG_STOP_ACK	0x0002
+#define	VFE_MSG_STOP_ACK_LEN	sizeof(vfe_msg_stop_ack)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_stop_ack;
+
+
+/*
+ * Message to acknowledge CMD_VFE_UPDATE command
+ */
+
+#define	VFE_MSG_UPDATE_ACK	0x0003
+#define	VFE_MSG_UPDATE_ACK_LEN	sizeof(vfe_msg_update_ack)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_update_ack;
+
+
+/*
+ * Message to notify the ARM that snapshot processing is complete
+ * and that the VFE is now STATE_VFE_IDLE
+ */
+
+#define	VFE_MSG_SNAPSHOT_DONE		0x0004
+#define	VFE_MSG_SNAPSHOT_DONE_LEN	\
+	sizeof(vfe_msg_snapshot_done)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_snapshot_done;
+
+
+
+/*
+ * Message to notify ARM that illegal cmd was received and 
+ * system is in the IDLE state
+ */
+
+#define	VFE_MSG_ILLEGAL_CMD	0x0005
+#define	VFE_MSG_ILLEGAL_CMD_LEN	\
+	sizeof(vfe_msg_illegal_cmd)
+
+typedef struct {
+	unsigned int	status;
+} __attribute__((packed)) vfe_msg_illegal_cmd;
+
+
+/*
+ * Message to notify ARM that op1 buf is full and ready
+ */
+
+#define	VFE_MSG_OP1		0x0006
+#define	VFE_MSG_OP1_LEN		sizeof(vfe_msg_op1)
+
+typedef struct {
+	unsigned int	op1_buf_y_addr;
+	unsigned int	op1_buf_cbcr_addr;
+	unsigned int	black_level_even_col;
+	unsigned int	black_level_odd_col;
+	unsigned int	defect_pixels_detected;
+	unsigned int	asf_max_edge;
+} __attribute__((packed)) vfe_msg_op1; 
+
+
+/*
+ * Message to notify ARM that op2 buf is full and ready
+ */
+
+#define	VFE_MSG_OP2		0x0007
+#define	VFE_MSG_OP2_LEN		sizeof(vfe_msg_op2)
+
+typedef struct {
+	unsigned int	op2_buf_y_addr;
+	unsigned int	op2_buf_cbcr_addr;
+	unsigned int	black_level_even_col;
+	unsigned int	black_level_odd_col;
+	unsigned int	defect_pixels_detected;
+	unsigned int	asf_max_edge;
+} __attribute__((packed)) vfe_msg_op2; 
+
+
+/*
+ * Message to notify ARM that autofocus(af) stats are ready
+ */
+
+#define	VFE_MSG_STATS_AF	0x0008
+#define	VFE_MSG_STATS_AF_LEN	sizeof(vfe_msg_stats_af)
+
+typedef struct {
+	unsigned int	af_stats_op_buffer;
+} __attribute__((packed)) vfe_msg_stats_af;
+
+
+/*
+ * Message to notify ARM that white balance(wb) and exposure (exp)
+ * stats are ready
+ */
+
+#define	VFE_MSG_STATS_WB_EXP		0x0009
+#define	VFE_MSG_STATS_WB_EXP_LEN	\
+	sizeof(vfe_msg_stats_wb_exp)
+
+typedef struct {
+	unsigned int	wb_exp_stats_op_buf;
+} __attribute__((packed)) vfe_msg_stats_wb_exp;
+
+
+/*
+ * Message to notify the ARM that histogram(hg) stats are ready
+ */
+
+#define	VFE_MSG_STATS_HG	0x000A
+#define	VFE_MSG_STATS_HG_LEN	sizeof(vfe_msg_stats_hg)
+
+typedef struct {
+	unsigned int	hg_stats_op_buf;
+} __attribute__((packed)) vfe_msg_stats_hg;
+
+
+/*
+ * Message to notify the ARM that epoch1 event occurred in the CAMIF
+ */
+
+#define	VFE_MSG_EPOCH1		0x000B
+#define	VFE_MSG_EPOCH1_LEN	sizeof(vfe_msg_epoch1)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_epoch1;
+
+
+/*
+ * Message to notify the ARM that epoch2 event occurred in the CAMIF
+ */
+
+#define	VFE_MSG_EPOCH2		0x000C
+#define	VFE_MSG_EPOCH2_LEN	sizeof(vfe_msg_epoch2)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_epoch2;
+
+
+/*
+ * Message to notify the ARM that sync timer1 op is completed
+ */
+
+#define	VFE_MSG_SYNC_T1_DONE		0x000D
+#define	VFE_MSG_SYNC_T1_DONE_LEN	sizeof(vfe_msg_sync_t1_done)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_sync_t1_done;
+
+
+/*
+ * Message to notify the ARM that sync timer2 op is completed
+ */
+
+#define	VFE_MSG_SYNC_T2_DONE		0x000E
+#define	VFE_MSG_SYNC_T2_DONE_LEN	sizeof(vfe_msg_sync_t2_done)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_sync_t2_done;
+
+
+/*
+ * Message to notify the ARM that async t1 operation completed
+ */
+
+#define	VFE_MSG_ASYNC_T1_DONE		0x000F
+#define	VFE_MSG_ASYNC_T1_DONE_LEN	sizeof(vfe_msg_async_t1_done)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_async_t1_done;
+
+
+
+/*
+ * Message to notify the ARM that async t2 operation completed
+ */
+
+#define	VFE_MSG_ASYNC_T2_DONE		0x0010
+#define	VFE_MSG_ASYNC_T2_DONE_LEN	sizeof(vfe_msg_async_t2_done)
+
+typedef struct {
+} __attribute__((packed)) vfe_msg_async_t2_done;
+
+
+
+/*
+ * Message to notify the ARM that an error has occurred
+ */
+
+#define	VFE_MSG_ERROR		0x0011
+#define	VFE_MSG_ERROR_LEN	sizeof(vfe_msg_error)
+
+#define	VFE_MSG_ERR_COND_NO_CAMIF_ERR		0x0000
+#define	VFE_MSG_ERR_COND_CAMIF_ERR		0x0001
+#define	VFE_MSG_ERR_COND_OP1_Y_NO_BUS_OF	0x0000
+#define	VFE_MSG_ERR_COND_OP1_Y_BUS_OF		0x0002
+#define	VFE_MSG_ERR_COND_OP1_CBCR_NO_BUS_OF	0x0000
+#define	VFE_MSG_ERR_COND_OP1_CBCR_BUS_OF	0x0004
+#define	VFE_MSG_ERR_COND_OP2_Y_NO_BUS_OF	0x0000
+#define	VFE_MSG_ERR_COND_OP2_Y_BUS_OF		0x0008
+#define	VFE_MSG_ERR_COND_OP2_CBCR_NO_BUS_OF	0x0000
+#define	VFE_MSG_ERR_COND_OP2_CBCR_BUS_OF	0x0010
+#define	VFE_MSG_ERR_COND_AF_NO_BUS_OF		0x0000
+#define	VFE_MSG_ERR_COND_AF_BUS_OF		0x0020
+#define	VFE_MSG_ERR_COND_WB_EXP_NO_BUS_OF	0x0000
+#define	VFE_MSG_ERR_COND_WB_EXP_BUS_OF		0x0040
+#define	VFE_MSG_ERR_COND_NO_AXI_ERR		0x0000
+#define	VFE_MSG_ERR_COND_AXI_ERR		0x0080
+
+#define	VFE_MSG_CAMIF_STS_IDLE			0x0000
+#define	VFE_MSG_CAMIF_STS_CAPTURE_DATA		0x0001
+
+typedef struct {
+	unsigned int	err_cond;
+	unsigned int	camif_sts;
+} __attribute__((packed)) vfe_msg_error;
+
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/snd_adie.h b/arch/arm/mach-msm/include/mach/qdsp5/snd_adie.h
new file mode 100644
index 0000000..bf1714e
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/snd_adie.h
@@ -0,0 +1,86 @@
+/* Copyright (c) 2009, 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 __SND_ADIE_SVC_H_
+#define __SND_ADIE_SVC_H_
+
+#define ADIE_SVC_PROG	0x30000002
+#define ADIE_SVC_VERS	0x00020003
+
+#define ADIE_SVC_CLIENT_STATUS_FUNC_PTR_TYPE_PROC 0xFFFFFF01
+#define SND_ADIE_SVC_CLIENT_REGISTER_PROC 	34
+#define SND_ADIE_SVC_CONFIG_ADIE_BLOCK_PROC 	35
+#define SND_ADIE_SVC_CLIENT_DEREGISTER_PROC 	36
+
+#define ADIE_SVC_MAX_CLIENTS 5
+
+enum adie_svc_client_operation{
+	ADIE_SVC_REGISTER_CLIENT,
+	ADIE_SVC_DEREGISTER_CLIENT,
+	ADIE_SVC_CONFIG_ADIE_BLOCK,
+};
+
+enum adie_svc_status_type{
+	ADIE_SVC_STATUS_SUCCESS,
+	ADIE_SVC_STATUS_FAILURE,
+	ADIE_SVC_STATUS_INUSE
+};
+
+enum adie_block_enum_type{
+	MIC_BIAS,
+	HSSD,
+	HPH_PA
+};
+
+enum adie_config_enum_type{
+	DISABLE,
+	ENABLE
+};
+
+struct adie_svc_client{
+	int client_id;
+	int cb_id;
+	enum adie_svc_status_type status;
+	bool adie_svc_cb_done;
+	struct mutex lock;
+	wait_queue_head_t wq;
+	struct msm_rpc_client *rpc_client;
+};
+
+struct adie_svc_client_register_cb_cb_args {
+	int cb_id;
+	uint32_t size;
+	int client_id;
+	enum adie_block_enum_type adie_block;
+	enum adie_svc_status_type status;
+	enum adie_svc_client_operation client_operation;
+};
+
+struct adie_svc_client_register_cb_args {
+	int cb_id;
+};
+
+struct adie_svc_client_deregister_cb_args {
+	int client_id;
+};
+
+struct adie_svc_config_adie_block_cb_args {
+	int client_id;
+	enum adie_block_enum_type adie_block;
+	enum adie_config_enum_type config;
+};
+
+int adie_svc_get(void);
+int adie_svc_put(int id);
+int adie_svc_config_adie_block(int id,
+	enum adie_block_enum_type adie_block_type, bool enable);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/acdb_commands.h b/arch/arm/mach-msm/include/mach/qdsp5v2/acdb_commands.h
new file mode 100644
index 0000000..2e6fcdb
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/acdb_commands.h
@@ -0,0 +1,303 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef _MACH_QDSP5_V2_ACDB_COMMANDS_H
+#define _MACH_QDSP5_V2_ACDB_COMMANDS_H
+
+#define ACDB_VOICE_NETWORK_ID_DEFAULT		0x00010037
+#define ACDB_INITIALISING			0
+#define ACDB_READY				1
+
+
+/* 4KB */
+#define ACDB_PAGE_SIZE				0x1000
+
+#define ACDB_CDMA_NB		0x0108b153
+#define ACDB_CDMA_WB		0x0108b154
+#define ACDB_GSM_NB		0x0108b155
+#define ACDB_GSM_WB		0x0108b156
+#define ACDB_WCDMA_NB		0x0108b157
+#define ACDB_WCDMA_WB		0x0108b158
+
+
+/* ACDB commands */
+
+
+/* struct acdb_cmd_install_device */
+#define ACDB_INSTALL_DEVICE		0x0108d245
+
+/* struct acdb_cmd_install_device */
+#define ACDB_UNINSTALL_DEVICE		0x0108d246
+
+/* struct acdb_cmd_device */
+#define ACDB_GET_DEVICE			0x0108bb92
+
+/* struct acdb_cmd_device */
+#define ACDB_SET_DEVICE			0x0108bb93
+
+/* struct acdb_cmd_get_device_table */
+#define ACDB_GET_DEVICE_TABLE		0x0108bb97
+
+/* struct acdb_cmd_get_device_capabilities */
+#define ACDB_GET_DEVICE_CAPABILITIES	0x0108f5ca
+
+/* struct acdb_cmd_get_device_info */
+#define ACDB_GET_DEVICE_INFO		0x0108f5cb
+
+/*command to intitialize ACDB based on codec type*/
+#define ACDB_CMD_INITIALIZE_FOR_ADIE	0x00011283
+
+
+/* ACDB Error codes */
+
+#define ACDB_RES_SUCCESS		0
+#define ACDB_RES_FAILURE		-1
+#define ACDB_RES_BADPARM		-2
+#define ACDB_RES_BADSTATE		-3
+
+#define TGTVERS_MSM7x30_BRING_UP	0x00010064
+
+
+
+/* Algorithm Aspect IDs */
+
+#define IID_ENABLE_FLAG			0x0108b6b9
+
+
+#define IID_ENABLE_FLAG_SIZE					1
+#define IID_ECHO_CANCELLER_VERSION_SIZE				2
+#define IID_ECHO_CANCELLER_MODE_SIZE				2
+#define IID_ECHO_CANCELLER_NOISE_SUPPRESSOR_ENABLE_SIZE		1
+#define IID_ECHO_CANCELLER_PARAMETERS_SIZE			32
+#define IID_ECHO_CANCELLER_NEXTGEN_NB_PARAMETERS_SIZE		(38 * 2)
+#define IID_ECHO_CANCELLER_NEXTGEN_WB_PARAMETERS_SIZE		(38 * 2)
+#define IID_FLUENCE_PARAMETERS_SIZE				486
+#define IID_AFE_VOLUME_CONTROL_SIZE				6
+#define IID_GAIN_SIZE						2
+#define IID_VOICE_FIR_FILTER_SIZE				14
+#define IID_VOICE_IIR_FILTER_SIZE				114
+#define IID_RX_DBM_OFFSET_SIZE					2
+#define IID_AGC_SIZE						36
+#define IID_AVC_SIZE						80
+
+#define IID_AUDIO_IIR_COEFF_SIZE				100
+#define IID_MBADRC_PARAMETERS_SIZE				8
+#define IID_MBADRC_EXT_BUFF_SIZE				392
+#define IID_MBADRC_BAND_CONFIG_SIZE				100
+#define IID_QAFX_PARAMETERS_SIZE				2
+#define IID_QCONCERT_PARAMETERS_SIZE				2
+#define IID_AUDIO_AGC_PARAMETERS_SIZE				42
+#define IID_NS_PARAMETERS_SIZE					14
+
+#define IID_ECHO_CANCELLER_VERSION			0x00010042
+#define IID_ECHO_CANCELLER_MODE				0x00010043
+#define IID_ECHO_CANCELLER_NOISE_SUPPRESSOR_ENABLE	0x00010044
+#define IID_ECHO_CANCELLER_PARAMETERS			0x00010045
+#define IID_ECHO_CANCELLER_NEXTGEN_NB_PARAMETERS	0x00010046
+#define IID_ECHO_CANCELLER_NEXTGEN_WB_PARAMETERS	0x00010047
+#define IID_FLUENCE_PARAMETERS				0x00010048
+#define IID_AFE_VOLUME_CONTROL				0x00010049
+#define IID_GAIN					0x0001004A
+#define IID_VOICE_FIR_FILTER				0x0001004B
+#define IID_VOICE_IIR_FILTER				0x0001004C
+#define IID_AGC						0x0001004E
+#define IID_AVC						0x0001004F
+#define ABID_SIDETONE_GAIN				0x00010050
+#define ABID_TX_VOICE_GAIN				0x00010051
+#define ABID_TX_DTMF_GAIN				0x00010052
+#define ABID_CODEC_TX_GAIN				0x00010053
+#define ABID_HSSD					0x00010054
+#define ABID_TX_AGC					0x00010055
+#define ABID_TX_VOICE_FIR				0x00010056
+#define ABID_TX_VOICE_IIR				0x00010057
+#define ABID_ECHO_CANCELLER				0x00010058
+#define ABID_ECHO_CANCELLER_NB_LVHF			0x00010059
+#define ABID_ECHO_CANCELLER_WB_LVHF			0x0001005A
+#define ABID_FLUENCE					0x0001005B
+#define ABID_CODEC_RX_GAIN				0x0001005C
+#define ABID_RX_DBM_OFFSET				0x0001005D
+#define ABID_RX_AGC					0x0001005E
+#define ABID_AVC					0x0001005F
+#define ABID_RX_VOICE_FIR				0x00010060
+#define ABID_RX_VOICE_IIR				0x00010061
+#define ABID_AFE_VOL_CTRL				0x00010067
+
+
+/* AUDIO IDs */
+#define ABID_AUDIO_AGC_TX		0x00010068
+#define ABID_AUDIO_NS_TX		0x00010069
+#define ABID_VOICE_NS			0x0001006A
+#define ABID_AUDIO_IIR_TX		0x0001006B
+#define ABID_AUDIO_IIR_RX		0x0001006C
+#define ABID_AUDIO_MBADRC_RX		0x0001006E
+#define ABID_AUDIO_QAFX_RX		0x0001006F
+#define ABID_AUDIO_QCONCERT_RX		0x00010070
+#define ABID_AUDIO_STF_RX		0x00010071
+#define ABID_AUDIO_CALIBRATION_GAIN_RX  0x00011162
+#define ABID_AUDIO_CALIBRATION_GAIN_TX  0x00011149
+#define ABID_AUDIO_PBE_RX               0x00011197
+#define ABID_AUDIO_RMC_TX		0x00011226
+#define ABID_AUDIO_FLUENCE_TX		0x00011244
+
+
+#define IID_AUDIO_AGC_PARAMETERS	0x0001007E
+#define IID_NS_PARAMETERS		0x00010072
+#define IID_AUDIO_IIR_COEFF		0x00010073
+#define IID_MBADRC_EXT_BUFF		0x00010075
+#define IID_MBADRC_BAND_CONFIG		0x00010076
+#define IID_MBADRC_PARAMETERS		0x00010077
+#define IID_QAFX_PARAMETERS		0x00010079
+#define IID_QCONCERT_PARAMETERS		0x0001007A
+#define IID_STF_COEFF			0x0001007B
+#define IID_AUDIO_CALIBRATION_GAIN_RX   0x00011163
+#define IID_AUDIO_CALIBRATION_GAIN_TX   0x00011171
+#define IID_PBE_CONFIG_PARAMETERS       0x00011198
+#define IID_AUDIO_PBE_RX_ENABLE_FLAG    0x00011199
+#define IID_AUDIO_RMC_PARAM		0x00011227
+#define IID_AUDIO_FLUENCE_TX		0x00011245
+
+
+#define TOPID_RX_TOPOLOGY_1		0x00010062
+#define TOPID_TX_TOPOLOGY_1		0x00010063
+#define AFERID_INT_SINK			0x00010065
+#define AFERID_INT_SOURCE		0x00010066
+#define AFERID_NO_SINK			0x00000000
+#define AFERID_NULL_SINK		0x0108ea92
+
+
+struct acdb_cmd_install_device {
+	u32	command_id;
+	u32	device_id;
+	u32	topology_id;
+	u32	afe_routing_id;
+	u32	cad_routing_id;		/* see "Sample Rate Bit Mask" below */
+	u32	sample_rate_mask;
+
+	/* represents device direction: Tx, Rx (aux pga - loopback) */
+	u8	device_type;
+	u8	channel_config;		/* Mono or Stereo */
+	u32	adie_codec_path_id;
+};
+
+
+struct acdb_cmd_get_device_capabilities {
+	u32	command_id;
+	u32	total_bytes;	/* Length in bytes allocated for buffer */
+	u32	*phys_buf;	/* Physical Address of data */
+};
+
+
+struct acdb_cmd_get_device_info {
+	u32	command_id;
+	u32	device_id;
+	u32	total_bytes;	/* Length in bytes allocated for buffer */
+	u32	*phys_buf;	/* Physical Address of data */
+};
+
+struct acdb_cmd_device {
+	u32	command_id;
+	u32	device_id;
+	u32	network_id;
+	u32	sample_rate_id;		/* Actual sample rate value */
+	u32	interface_id;		/* See interface id's above */
+	u32	algorithm_block_id;	/* See enumerations above */
+	u32	total_bytes;		/* Length in bytes used by buffer */
+	u32	*phys_buf;		/* Physical Address of data */
+};
+
+struct acdb_cmd_get_device_table {
+	u32	command_id;
+	u32	device_id;
+	u32	network_id;
+	u32	sample_rate_id;		/* Actual sample rate value */
+	u32	total_bytes;		/* Length in bytes used by buffer */
+	u32	*phys_buf;		/* Physical Address of data */
+};
+
+struct acdb_result {
+	/* This field is populated in response to the */
+	/* ACDB_GET_DEVICE_CAPABILITIES command and indicates the total */
+	/* devices whose capabilities are copied to the physical memory. */
+	u32	total_devices;
+	u32	*buf;			/* Physical Address of data */
+	u32	used_bytes;		/* The size in bytes of the data */
+	u32	result;			/* See ACDB Error codes above */
+};
+
+struct acdb_device_capability {
+	u32	device_id;
+	u32	sample_rate_mask;	/* See "Sample Rate Bit Mask" below */
+};
+
+struct acdb_dev_info {
+	u32	cad_routing_id;
+	u32	sample_rate_mask;	/* See "Sample Rate Bit Mask" below */
+	u32	adsp_device_id;		/* QDSP6 device ID */
+	u32	device_type;		/* Tx, Rx  (aux pga - loopback) */
+	u32	channel_config;		/* Mono or Stereo */
+	s32	min_volume;		/* Min volume (mB) */
+	s32	max_volume;		/* Max volume (mB) */
+};
+
+/*structure is used to intialize ACDB software on modem
+based on adie type detected*/
+struct acdb_cmd_init_adie {
+    u32 command_id;
+    u32 adie_type;
+};
+
+#define ACDB_CURRENT_ADIE_MODE_UNKNOWN 0
+#define ACDB_CURRENT_ADIE_MODE_TIMPANI 1
+#define ACDB_CURRENT_ADIE_MODE_MARIMBA 2
+
+/* Sample Rate Bit Mask */
+
+/* AUX PGA devices will have a sample rate mask of 0xFFFFFFFF */
+/* 8kHz              0x00000001 */
+/* 11.025kHz         0x00000002 */
+/* 12kHz             0x00000004 */
+/* 16kHz             0x00000008 */
+/* 22.5kHz           0x00000010 */
+/* 24kHz             0x00000020 */
+/* 32kHz             0x00000040 */
+/* 44.1kHz           0x00000080 */
+/* 48kHz             0x00000100 */
+
+
+/* Device type enumeration */
+enum {
+	RX_DEVICE = 1,
+	TX_DEVICE,
+	AUXPGA_DEVICE,
+	DEVICE_TYPE_MAX
+};
+
+#ifdef CONFIG_DEBUG_FS
+/*These are ABID used for RTC*/
+#define ABID_AUDIO_RTC_MBADRC_RX 0x0001118A
+#define ABID_AUDIO_RTC_VOLUME_PAN_RX 0x0001118C
+#define ABID_AUDIO_RTC_SPA 0x0001118E
+#define ABID_AUDIO_RTC_EQUALIZER_PARAMETERS 0x0001119F
+
+/*These are IID used for RTC*/
+#define IID_AUDIO_RTC_MBADRC_PARAMETERS 0x0001118B
+#define IID_AUDIO_RTC_VOLUME_PAN_PARAMETERS 0x0001118D
+#define IID_AUDIO_RTC_SPA_PARAMETERS 0x0001118F
+#define IID_AUDIO_RTC_EQUALIZER_PARAMETERS 0x0001119E
+#define IID_AUDIO_RTC_AGC_PARAMETERS 0x000111A7
+#define IID_AUDIO_RTC_TX_IIR_COEFF 0x000111A8
+
+#endif
+
+
+#endif
+
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/adie_marimba.h b/arch/arm/mach-msm/include/mach/qdsp5v2/adie_marimba.h
new file mode 100644
index 0000000..919da65
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/adie_marimba.h
@@ -0,0 +1,93 @@
+/* Copyright (c) 2009-2010, 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 __MACH_QDSP5_V2_ADIE_MARIMBA_H
+#define __MACH_QDSP5_V2_ADIE_MARIMBA_H
+
+#include <linux/types.h>
+
+/* Value Represents a entry */
+#define ADIE_CODEC_ACTION_ENTRY       0x1
+/* Value representing a delay wait */
+#define ADIE_CODEC_ACTION_DELAY_WAIT      0x2
+/* Value representing a stage reached */
+#define ADIE_CODEC_ACTION_STAGE_REACHED   0x3
+
+/* This value is the state after the client sets the path */
+#define ADIE_CODEC_PATH_OFF                                        0x0050
+
+/* State to which client asks the drv to proceed to where it can
+ * set up the clocks and 0-fill PCM buffers
+ */
+#define ADIE_CODEC_DIGITAL_READY                                   0x0100
+
+/* State to which client asks the drv to proceed to where it can
+ * start sending data after internal steady state delay
+ */
+#define ADIE_CODEC_DIGITAL_ANALOG_READY                            0x1000
+
+
+/*  Client Asks adie to switch off the Analog portion of the
+ *  the internal codec. After the use of this path
+ */
+#define ADIE_CODEC_ANALOG_OFF                                      0x0750
+
+
+/* Client Asks adie to switch off the digital portion of the
+ *  the internal codec. After switching off the analog portion.
+ *
+ *  0-fill PCM may or maynot be sent at this point
+ *
+ */
+#define ADIE_CODEC_DIGITAL_OFF                                     0x0600
+
+/* State to which client asks the drv to write the default values
+ * to the registers */
+#define ADIE_CODEC_FLASH_IMAGE 					   0x0001
+
+/* Path type */
+#define ADIE_CODEC_RX 0
+#define ADIE_CODEC_TX 1
+#define ADIE_CODEC_LB 3
+#define ADIE_CODEC_MAX 4
+
+#define ADIE_CODEC_PACK_ENTRY(reg, mask, val) ((val)|(mask << 8)|(reg << 16))
+
+#define ADIE_CODEC_UNPACK_ENTRY(packed, reg, mask, val) \
+	do { \
+		((reg) = ((packed >> 16) & (0xff))); \
+		((mask) = ((packed >> 8) & (0xff))); \
+		((val) = ((packed) & (0xff))); \
+	} while (0);
+
+struct adie_codec_action_unit {
+	u32 type;
+	u32 action;
+};
+
+struct adie_codec_hwsetting_entry{
+	struct adie_codec_action_unit *actions;
+	u32 action_sz;
+	u32 freq_plan;
+	u32 osr;
+	/* u32  VolMask;
+	 * u32  SidetoneMask;
+	 */
+};
+
+struct adie_codec_dev_profile {
+	u32 path_type; /* RX or TX */
+	u32 setting_sz;
+	struct adie_codec_hwsetting_entry *settings;
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/afe.h b/arch/arm/mach-msm/include/mach/qdsp5v2/afe.h
new file mode 100644
index 0000000..c15facc
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/afe.h
@@ -0,0 +1,52 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef _MACH_QDSP5_V2_AFE_H
+#define _MACH_QDSP5_V2_AFE_H
+
+#include <asm/types.h>
+#include <mach/qdsp5v2/audio_acdbi.h>
+
+#define AFE_HW_PATH_CODEC_RX    1
+#define AFE_HW_PATH_CODEC_TX    2
+#define AFE_HW_PATH_AUXPCM_RX   3
+#define AFE_HW_PATH_AUXPCM_TX   4
+#define AFE_HW_PATH_MI2S_RX     5
+#define AFE_HW_PATH_MI2S_TX     6
+
+#define AFE_VOLUME_UNITY 0x4000 /* Based on Q14 */
+
+struct msm_afe_config {
+	u16 sample_rate;
+	u16 channel_mode;
+	u16 volume;
+	/* To be expaned for AUX CODEC */
+};
+
+int afe_enable(u8 path_id, struct msm_afe_config *config);
+
+int afe_disable(u8 path_id);
+
+int afe_config_aux_codec(int pcm_ctl_value, int aux_codec_intf_value,
+			int data_format_pad);
+int afe_config_fm_codec(int fm_enable, uint16_t source);
+
+int afe_config_fm_volume(uint16_t volume);
+int afe_config_fm_calibration_gain(uint16_t device_id,
+			uint16_t calibration_gain);
+void afe_loopback(int enable);
+void afe_ext_loopback(int enable, int rx_copp_id, int tx_copp_id);
+
+void afe_device_volume_ctrl(u16 device_id, u16 device_volume);
+
+int afe_config_rmc_block(struct acdb_rmc_block *acdb_rmc);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/audio_acdb_def.h b/arch/arm/mach-msm/include/mach/qdsp5v2/audio_acdb_def.h
new file mode 100644
index 0000000..a2a15dc
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/audio_acdb_def.h
@@ -0,0 +1,51 @@
+/* Copyright (c) 2010 - 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef _MACH_QDSP5_V2_AUDIO_ACDB_DEF_H
+#define _MACH_QDSP5_V2_AUDIO_ACDB_DEF_H
+
+/* Define ACDB device ID */
+#define ACDB_ID_HANDSET_SPKR				1
+#define ACDB_ID_HANDSET_MIC				2
+#define ACDB_ID_HEADSET_MIC				3
+#define ACDB_ID_HEADSET_SPKR_MONO			4
+#define ACDB_ID_HEADSET_SPKR_STEREO			5
+#define ACDB_ID_SPKR_PHONE_MIC				6
+#define ACDB_ID_SPKR_PHONE_MONO				7
+#define ACDB_ID_SPKR_PHONE_STEREO			8
+#define ACDB_ID_BT_SCO_MIC				9
+#define ACDB_ID_BT_SCO_SPKR				0x0A
+#define ACDB_ID_BT_A2DP_SPKR				0x0B
+#define ACDB_ID_BT_A2DP_TX				0x10
+#define ACDB_ID_TTY_HEADSET_MIC				0x0C
+#define ACDB_ID_TTY_HEADSET_SPKR			0x0D
+#define ACDB_ID_HEADSET_MONO_PLUS_SPKR_MONO_RX		0x11
+#define ACDB_ID_HEADSET_STEREO_PLUS_SPKR_STEREO_RX	0x14
+#define ACDB_ID_FM_TX_LOOPBACK				0x17
+#define ACDB_ID_FM_TX					0x18
+#define ACDB_ID_LP_FM_SPKR_PHONE_STEREO_RX		0x19
+#define ACDB_ID_LP_FM_HEADSET_SPKR_STEREO_RX		0x1A
+#define ACDB_ID_I2S_RX					0x20
+#define ACDB_ID_SPKR_PHONE_MIC_BROADSIDE		0x2B
+#define ACDB_ID_HANDSET_MIC_BROADSIDE			0x2C
+#define ACDB_ID_SPKR_PHONE_MIC_ENDFIRE			0x2D
+#define ACDB_ID_HANDSET_MIC_ENDFIRE			0x2E
+#define ACDB_ID_I2S_TX					0x30
+#define ACDB_ID_HDMI					0x40
+#define ACDB_ID_FM_RX					0x4F
+/*Replace the max device ID,if any new device is added Specific to RTC only*/
+#define ACDB_ID_MAX                                 ACDB_ID_FM_RX
+
+/* ID used for virtual devices */
+#define PSEUDO_ACDB_ID 					0xFFFF
+
+#endif /* _MACH_QDSP5_V2_AUDIO_ACDB_DEF_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/audio_acdbi.h b/arch/arm/mach-msm/include/mach/qdsp5v2/audio_acdbi.h
new file mode 100644
index 0000000..559073c
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/audio_acdbi.h
@@ -0,0 +1,303 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef _MACH_QDSP5_V2_AUDIO_ACDBI_H
+#define _MACH_QDSP5_V2_AUDIO_ACDBI_H
+
+#define DBOR_SIGNATURE	0x524F4244
+
+#ifdef CONFIG_DEBUG_FS
+void acdb_rtc_set_err(u32 ErrCode);
+#endif
+
+
+struct header {
+	u32 dbor_signature;
+	u32 abid;
+	u32 iid;
+	u32 data_len;
+};
+
+enum {
+	ACDB_AGC_BLOCK			= 197,
+	ACDB_IIR_BLOCK			= 245,
+	ACDB_MBADRC_BLOCK		= 343
+};
+
+/* Structure to query for acdb parameter */
+struct acdb_get_block {
+	u32	acdb_id;
+	u32	sample_rate_id;		/* Actual sample rate value */
+	u32	interface_id;		/* Interface id's */
+	u32	algorithm_block_id;	/* Algorithm block id */
+	u32	total_bytes;		/* Length in bytes used by buffer for
+						configuration */
+	u32	*buf_ptr;		/* Address for storing configuration
+						data */
+};
+
+struct acdb_agc_block {
+	u16	enable_status;
+	u16	comp_rlink_static_gain;
+	u16	comp_rlink_aig_flag;
+	u16	exp_rlink_threshold;
+	u16	exp_rlink_slope;
+	u16	comp_rlink_threshold;
+	u16	comp_rlink_slope;
+	u16	comp_rlink_aig_attack_k;
+	u16	comp_rlink_aig_leak_down;
+	u16	comp_rlink_aig_leak_up;
+	u16	comp_rlink_aig_max;
+	u16	comp_rlink_aig_min;
+	u16	comp_rlink_aig_release_k;
+	u16	comp_rlink_aig_sm_leak_rate_fast;
+	u16	comp_rlink_aig_sm_leak_rate_slow;
+	u16	comp_rlink_attack_k_msw;
+	u16	comp_rlink_attack_k_lsw;
+	u16	comp_rlink_delay;
+	u16	comp_rlink_release_k_msw;
+	u16	comp_rlink_release_k_lsw;
+	u16	comp_rlink_rms_trav;
+};
+
+
+struct iir_coeff_type {
+	u16	b0_lo;
+	u16	b0_hi;
+	u16	b1_lo;
+	u16	b1_hi;
+	u16	b2_lo;
+	u16	b2_hi;
+};
+
+struct iir_coeff_stage_a {
+	u16	a1_lo;
+	u16	a1_hi;
+	u16	a2_lo;
+	u16	a2_hi;
+};
+
+struct acdb_iir_block {
+	u16			enable_flag;
+	u16			stage_count;
+	struct iir_coeff_type	stages[4];
+	struct iir_coeff_stage_a stages_a[4];
+	u16			shift_factor[4];
+	u16			pan[4];
+};
+
+
+
+struct mbadrc_band_config_type {
+	u16	mbadrc_sub_band_enable;
+	u16	mbadrc_sub_mute;
+	u16	mbadrc_comp_rms_tav;
+	u16	mbadrc_comp_threshold;
+	u16	mbadrc_comp_slop;
+	u16	mbadrc_comp_attack_msw;
+	u16	mbadrc_comp_attack_lsw;
+	u16	mbadrc_comp_release_msw;
+	u16	mbadrc_comp_release_lsw;
+	u16	mbadrc_make_up_gain;
+};
+
+struct mbadrc_parameter {
+	u16				mbadrc_enable;
+	u16				mbadrc_num_bands;
+	u16				mbadrc_down_sample_level;
+	u16				mbadrc_delay;
+};
+
+struct acdb_mbadrc_block {
+	u16				ext_buf[196];
+	struct mbadrc_band_config_type	band_config[5];
+	struct mbadrc_parameter		parameters;
+};
+
+struct  acdb_calib_gain_rx {
+	u16 audppcalgain;
+	u16 reserved;
+};
+
+struct acdb_calib_gain_tx {
+	u16 audprecalgain;
+	u16 reserved;
+};
+
+struct acdb_pbe_block {
+	s16 realbassmix;
+	s16 basscolorcontrol;
+	u16 mainchaindelay;
+	u16 xoverfltorder;
+	u16 bandpassfltorder;
+	s16 adrcdelay;
+	u16 downsamplelevel;
+	u16 comprmstav;
+	s16 expthreshold;
+	u16 expslope;
+	u16 compthreshold;
+	u16 compslope;
+	u16 cpmpattack_lsw;
+	u16 compattack_msw;
+	u16 comprelease_lsw;
+	u16 comprelease_msw;
+	u16 compmakeupgain;
+	s16 baselimthreshold;
+	s16 highlimthreshold;
+	s16 basslimmakeupgain;
+	s16 highlimmakeupgain;
+	s16 limbassgrc;
+	s16 limhighgrc;
+	s16 limdelay;
+	u16 filter_coeffs[90];
+};
+
+struct acdb_rmc_block  {
+	s16 rmc_enable;
+	u16 rmc_ipw_length_ms;
+	u16 rmc_detect_start_threshdb;
+	u16 rmc_peak_length_ms;
+	s16 rmc_init_pulse_threshdb;
+	u16 rmc_init_pulse_length_ms;
+	u16 rmc_total_int_length_ms;
+	u16 rmc_rampupdn_length_ms;
+	u16 rmc_delay_length_ms;
+	u16 reserved00;
+	u16 reserved01;
+	s16 reserved02;
+	s16 reserved03;
+	s16 reserved04;
+};
+
+struct acdb_fluence_block {
+	u16 csmode;
+	u16 cs_tuningMode;
+	u16 cs_echo_path_delay_by_80;
+	u16 cs_echo_path_delay;
+	u16 af1_twoalpha;
+	u16 af1_erl;
+	u16 af1_taps;
+	u16 af1_preset_coefs;
+	u16 af1_offset;
+	u16 af2_twoalpha;
+	u16 af2_erl;
+	u16 af2_taps;
+	u16 af2_preset_coefs;
+	u16 af2_offset;
+	u16 pcd_twoalpha;
+	u16 pcd_offset;
+	u16 cspcd_threshold;
+	u16 wgthreshold;
+	u16 mpthreshold;
+	u16 sf_init_table_0[8];
+	u16 sf_init_table_1[8];
+	u16 sf_taps;
+	u16 sf_twoalpha;
+	u16 dnns_echoalpharev;
+	u16 dnns_echoycomp;
+	u16 dnns_wbthreshold;
+	u16 dnns_echogammahi;
+	u16 dnns_echogammalo;
+	u16 dnns_noisegammas;
+	u16 dnns_noisegamman;
+	u16 dnns_noisegainmins;
+	u16 dnns_noisegainminn;
+	u16 dnns_noisebiascomp;
+	u16 dnns_acthreshold;
+	u16 wb_echo_ratio_2mic;
+	u16 wb_gamma_e;
+	u16 wb_gamma_nn;
+	u16 wb_gamma_sn;
+	u16 vcodec_delay0;
+	u16 vcodec_delay1;
+	u16 vcodec_len0;
+	u16 vcodec_len1;
+	u16 vcodec_thr0;
+	u16 vcodec_thr1;
+	u16 fixcalfactorleft;
+	u16 fixcalfactorright;
+	u16 csoutputgain;
+	u16 enh_meu_1;
+	u16 enh_meu_2;
+	u16 fixed_over_est;
+	u16 rx_nlpp_limit;
+	u16 rx_nlpp_gain;
+	u16 wnd_threshold;
+	u16 wnd_ns_hover;
+	u16 wnd_pwr_smalpha;
+	u16 wnd_det_esmalpha;
+	u16 wnd_ns_egoffset;
+	u16 wnd_sm_ratio;
+	u16 wnd_det_coefs[5];
+	u16 wnd_th1;
+	u16 wnd_th2;
+	u16 wnd_fq;
+	u16 wnd_dfc;
+	u16 wnd_sm_alphainc;
+	u16 wnd_sm_alphsdec;
+	u16 lvnv_spdet_far;
+	u16 lvnv_spdet_mic;
+	u16 lvnv_spdet_xclip;
+	u16 dnns_nl_atten;
+	u16 dnns_cni_level;
+	u16 dnns_echogammaalpha;
+	u16 dnns_echogammarescue;
+	u16 dnns_echogammadt;
+	u16 mf_noisegammafac;
+	u16 e_noisegammafac;
+	u16 dnns_noisegammainit;
+	u16 sm_noisegammas;
+	u16 wnd_noisegamman;
+	u16 af_taps_bg_spkr;
+	u16 af_erl_bg_spkr;
+	u16 minimum_erl_bg;
+	u16 erl_step_bg;
+	u16 upprisecalpha;
+	u16 upprisecthresh;
+	u16 uppriwindbias;
+	u16 e_pcd_threshold;
+	u16 nv_maxvadcount;
+	u16 crystalspeechreserved[38];
+	u16 cs_speaker[7];
+	u16 ns_fac;
+	u16 ns_blocksize;
+	u16 is_bias;
+	u16 is_bias_inp;
+	u16 sc_initb;
+	u16 ac_resetb;
+	u16 sc_avar;
+	u16 is_hover[5];
+	u16 is_cf_level;
+	u16 is_cf_ina;
+	u16 is_cf_inb;
+	u16 is_cf_a;
+	u16 is_cf_b;
+	u16 sc_th;
+	u16 sc_pscale;
+	u16 sc_nc;
+	u16 sc_hover;
+	u16 sc_alphas;
+	u16 sc_cfac;
+	u16 sc_sdmax;
+	u16 sc_sdmin;
+	u16 sc_initl;
+	u16 sc_maxval;
+	u16 sc_spmin;
+	u16 is_ec_th;
+	u16 is_fx_dl;
+	u16 coeffs_iva_filt_0[32];
+	u16 coeffs_iva_filt_1[32];
+};
+
+s32 acdb_get_calibration_data(struct acdb_get_block *get_block);
+void fluence_feature_update(int enable, int stream_id);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/audio_def.h b/arch/arm/mach-msm/include/mach/qdsp5v2/audio_def.h
new file mode 100644
index 0000000..236c6f6
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/audio_def.h
@@ -0,0 +1,35 @@
+/* Copyright (c) 2009,2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef _MACH_QDSP5_V2_AUDIO_DEF_H
+#define _MACH_QDSP5_V2_AUDIO_DEF_H
+
+/* Define sound device capability */
+#define SNDDEV_CAP_RX 0x1 /* RX direction */
+#define SNDDEV_CAP_TX 0x2 /* TX direction */
+#define SNDDEV_CAP_VOICE 0x4 /* Support voice call */
+#define SNDDEV_CAP_PLAYBACK 0x8 /* Support playback */
+#define SNDDEV_CAP_FM 0x10 /* Support FM radio */
+#define SNDDEV_CAP_TTY 0x20 /* Support TTY */
+#define SNDDEV_CAP_ANC 0x40 /* Support ANC */
+#define SNDDEV_CAP_LB 0x80 /* Loopback */
+#define VOC_NB_INDEX	0
+#define VOC_WB_INDEX	1
+#define VOC_RX_VOL_ARRAY_NUM	2
+
+/* Device volume types . In Current deisgn only one of these are supported. */
+#define SNDDEV_DEV_VOL_DIGITAL  0x1  /* Codec Digital volume control */
+#define SNDDEV_DEV_VOL_ANALOG   0x2  /* Codec Analog volume control */
+
+#define SIDE_TONE_MASK	0x01
+
+#endif /* _MACH_QDSP5_V2_AUDIO_DEF_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/audio_dev_ctl.h b/arch/arm/mach-msm/include/mach/qdsp5v2/audio_dev_ctl.h
new file mode 100644
index 0000000..7c0abcc
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/audio_dev_ctl.h
@@ -0,0 +1,206 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __MACH_QDSP5_V2_SNDDEV_H
+#define __MACH_QDSP5_V2_SNDDEV_H
+#include <mach/qdsp5v2/audio_def.h>
+
+#define AUDIO_DEV_CTL_MAX_DEV 64
+#define DIR_TX	2
+#define DIR_RX	1
+
+#define DEVICE_IGNORE	0xff
+#define SESSION_IGNORE 0x00000000
+
+#define VOICE_STATE_INVALID 0x0
+#define VOICE_STATE_INCALL 0x1
+#define VOICE_STATE_OFFCALL 0x2
+#define MAX_COPP_NODE_SUPPORTED 6
+#define MAX_AUDREC_SESSIONS 3
+
+#define REAL_STEREO_CHANNEL_MODE	9
+
+struct msm_snddev_info {
+	const char *name;
+	u32 capability;
+	u32 copp_id;
+	u32 acdb_id;
+	u32 dev_volume;
+	struct msm_snddev_ops {
+		int (*open)(struct msm_snddev_info *);
+		int (*close)(struct msm_snddev_info *);
+		int (*set_freq)(struct msm_snddev_info *, u32);
+		int (*enable_sidetone)(struct msm_snddev_info *, u32);
+		int (*set_device_volume)(struct msm_snddev_info *, u32);
+	} dev_ops;
+	u8 opened;
+	void *private_data;
+	bool state;
+	u32 sample_rate;
+	u32 set_sample_rate;
+	u32 sessions;
+	int usage_count;
+	s32 max_voc_rx_vol[VOC_RX_VOL_ARRAY_NUM]; /* [0] is for NB,[1] for WB */
+	s32 min_voc_rx_vol[VOC_RX_VOL_ARRAY_NUM];
+};
+
+struct msm_volume {
+	int volume; /* Volume parameter, in % Scale */
+	int pan;
+};
+
+extern struct msm_volume msm_vol_ctl;
+
+int msm_get_dual_mic_config(int enc_session_id);
+int msm_set_dual_mic_config(int enc_session_id, int config);
+int msm_reset_all_device(void);
+void msm_snddev_register(struct msm_snddev_info *);
+void msm_snddev_unregister(struct msm_snddev_info *);
+int msm_snddev_devcount(void);
+int msm_snddev_query(int dev_id);
+unsigned short msm_snddev_route_dec(int popp_id);
+unsigned short msm_snddev_route_enc(int enc_id);
+int msm_snddev_set_dec(int popp_id, int copp_id, int set);
+int msm_snddev_set_enc(int popp_id, int copp_id, int set);
+int msm_snddev_is_set(int popp_id, int copp_id);
+int msm_get_voc_route(u32 *rx_id, u32 *tx_id);
+int msm_set_voc_route(struct msm_snddev_info *dev_info, int stream_type,
+			int dev_id);
+int msm_snddev_enable_sidetone(u32 dev_id, u32 enable);
+
+struct msm_snddev_info *audio_dev_ctrl_find_dev(u32 dev_id);
+
+void msm_release_voc_thread(void);
+
+int snddev_voice_set_volume(int vol, int path);
+
+struct auddev_evt_voc_devinfo {
+	u32 dev_type;           /* Rx or Tx */
+	u32 acdb_dev_id;        /* acdb id of device */
+	u32 dev_sample;         /* Sample rate of device */
+	s32 max_rx_vol[VOC_RX_VOL_ARRAY_NUM]; 	/* unit is mb (milibel),
+						[0] is for NB, other for WB */
+	s32 min_rx_vol[VOC_RX_VOL_ARRAY_NUM];	/* unit is mb */
+	u32 dev_id;             /* registered device id */
+};
+
+struct auddev_evt_audcal_info {
+	u32 dev_id;
+	u32 acdb_id;
+	u32 sample_rate;
+	u32 dev_type;
+	u32 sessions;
+};
+
+struct auddev_evt_devinfo {
+	u32 dev_id;
+	u32 acdb_id;
+	u32 sample_rate;
+	u32 dev_type;
+	u32 sessions;
+};
+
+union msm_vol_mute {
+	int vol;
+	bool mute;
+};
+
+struct auddev_evt_voc_mute_info {
+	u32 dev_type;
+	u32 acdb_dev_id;
+	union msm_vol_mute dev_vm_val;
+};
+
+struct auddev_evt_freq_info {
+	u32 dev_type;
+	u32 acdb_dev_id;
+	u32 sample_rate;
+};
+
+union auddev_evt_data {
+	struct auddev_evt_voc_devinfo voc_devinfo;
+	struct auddev_evt_voc_mute_info voc_vm_info;
+	struct auddev_evt_freq_info freq_info;
+	u32 routing_id;
+	s32 session_vol;
+	s32 voice_state;
+	struct auddev_evt_audcal_info audcal_info;
+	struct auddev_evt_devinfo devinfo;
+};
+
+struct message_header {
+	uint32_t id;
+	uint32_t data_len;
+};
+
+#define AUDDEV_EVT_DEV_CHG_VOICE	0x01 	/* device change event */
+#define AUDDEV_EVT_DEV_RDY 		0x02 	/* device ready event */
+#define AUDDEV_EVT_DEV_RLS 		0x04 	/* device released event */
+#define AUDDEV_EVT_REL_PENDING		0x08 	/* device release pending */
+#define AUDDEV_EVT_DEVICE_VOL_MUTE_CHG	0x10 	/* device volume changed */
+#define AUDDEV_EVT_START_VOICE		0x20	/* voice call start */
+#define AUDDEV_EVT_END_VOICE		0x40	/* voice call end */
+#define AUDDEV_EVT_STREAM_VOL_CHG	0x80 	/* device volume changed */
+#define AUDDEV_EVT_FREQ_CHG		0x100	/* Change in freq */
+#define AUDDEV_EVT_VOICE_STATE_CHG	0x200   /* Change in voice state */
+#define AUDDEV_EVT_DEVICE_INFO		0x400	/* routed device information
+							event */
+
+#define AUDDEV_CLNT_VOC 		0x1	/* Vocoder clients */
+#define AUDDEV_CLNT_DEC 		0x2	/* Decoder clients */
+#define AUDDEV_CLNT_ENC 		0x3	/* Encoder clients */
+#define AUDDEV_CLNT_AUDIOCAL 		0x4	/* AudioCalibration client */
+
+#define AUDIO_DEV_CTL_MAX_LISTNER	20	/* Max Listeners Supported */
+
+struct msm_snd_evt_listner {
+	uint32_t evt_id;
+	uint32_t clnt_type;
+	uint32_t clnt_id;
+	void *private_data;
+	void (*auddev_evt_listener)(u32 evt_id,
+		union auddev_evt_data *evt_payload,
+		void *private_data);
+	struct msm_snd_evt_listner *cb_next;
+	struct msm_snd_evt_listner *cb_prev;
+};
+
+struct event_listner {
+	struct msm_snd_evt_listner *cb;
+	u32 num_listner;
+	int state; /* Call state */ /* TODO remove this if not req*/
+};
+
+extern struct event_listner event;
+int auddev_register_evt_listner(u32 evt_id, u32 clnt_type, u32 clnt_id,
+		void (*listner)(u32 evt_id,
+			union auddev_evt_data *evt_payload,
+			void *private_data),
+		void *private_data);
+int auddev_unregister_evt_listner(u32 clnt_type, u32 clnt_id);
+void mixer_post_event(u32 evt_id, u32 dev_id);
+void broadcast_event(u32 evt_id, u32 dev_id, u32 session_id);
+int msm_snddev_request_freq(int *freq, u32 session_id,
+			u32 capability, u32 clnt_type);
+int msm_snddev_withdraw_freq(u32 session_id,
+			u32 capability, u32 clnt_type);
+int msm_device_is_voice(int dev_id);
+int msm_get_voc_freq(int *tx_freq, int *rx_freq);
+int msm_snddev_get_enc_freq(int session_id);
+int msm_set_voice_vol(int dir, s32 volume);
+int msm_set_voice_mute(int dir, int mute);
+int msm_get_voice_state(void);
+#ifdef CONFIG_DEBUG_FS
+bool is_dev_opened(u32 acdb_id);
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/audio_interct.h b/arch/arm/mach-msm/include/mach/qdsp5v2/audio_interct.h
new file mode 100644
index 0000000..2a7b89e
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/audio_interct.h
@@ -0,0 +1,29 @@
+/* Copyright (c) 2009, 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 __MACH_QDSP5_V2_AUDIO_INTERCT_H
+#define __MACH_QDSP5_V2_AUDIO_INTERCT_H
+
+#define AUDIO_INTERCT_ADSP 0
+#define AUDIO_INTERCT_LPA 1
+#define AUDIO_ADSP_A 1
+#define AUDIO_ADSP_V 0
+
+void audio_interct_lpa(u32 source);
+void audio_interct_aux_regsel(u32 source);
+void audio_interct_rpcm_source(u32 source);
+void audio_interct_tpcm_source(u32 source);
+void audio_interct_pcmmi2s(u32 source);
+void audio_interct_codec(u32 source);
+void audio_interct_multichannel(u32 source);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/audpp.h b/arch/arm/mach-msm/include/mach/qdsp5v2/audpp.h
new file mode 100644
index 0000000..bdec256
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/audpp.h
@@ -0,0 +1,129 @@
+/*arch/arm/mach-msm/qdsp5iv2/audpp.h
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2008-2011, Code Aurora Forum. 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 _MACH_QDSP5_V2_AUDPP_H
+#define _MACH_QDSP5_V2_AUDPP_H
+
+#include <mach/qdsp5v2/qdsp5audppcmdi.h>
+
+typedef void (*audpp_event_func)(void *private, unsigned id, uint16_t *msg);
+
+/* worst case delay of 1sec for response */
+#define MSM_AUD_DECODER_WAIT_MS 1000
+#define MSM_AUD_MODE_TUNNEL  0x00000100
+#define MSM_AUD_MODE_NONTUNNEL  0x00000200
+#define MSM_AUD_MODE_LP  0x00000400
+#define MSM_AUD_DECODER_MASK  0x0000FFFF
+#define MSM_AUD_OP_MASK  0xFFFF0000
+
+/* read call timeout for error cases */
+#define MSM_AUD_BUFFER_UPDATE_WAIT_MS 2000
+
+/* stream info error message mask */
+#define AUDPLAY_STREAM_INFO_MSG_MASK 0xFFFF0000
+#define AUDPLAY_ERROR_THRESHOLD_ENABLE 0xFFFFFFFF
+
+#define NON_TUNNEL_MODE_PLAYBACK 1
+#define TUNNEL_MODE_PLAYBACK 0
+
+#define AUDPP_MIXER_ICODEC AUDPP_CMD_CFG_DEV_MIXER_DEV_0
+#define AUDPP_MIXER_1 AUDPP_CMD_CFG_DEV_MIXER_DEV_1
+#define AUDPP_MIXER_2 AUDPP_CMD_CFG_DEV_MIXER_DEV_2
+#define AUDPP_MIXER_3 AUDPP_CMD_CFG_DEV_MIXER_DEV_3
+#define AUDPP_MIXER_HLB AUDPP_CMD_CFG_DEV_MIXER_DEV_4
+#define AUDPP_MIXER_NONHLB (AUDPP_CMD_CFG_DEV_MIXER_DEV_0 | \
+			AUDPP_CMD_CFG_DEV_MIXER_DEV_1 | \
+			AUDPP_CMD_CFG_DEV_MIXER_DEV_2 | \
+			AUDPP_CMD_CFG_DEV_MIXER_DEV_3)
+#define AUDPP_MIXER_UPLINK_RX		AUDPP_CMD_CFG_DEV_MIXER_DEV_5
+#define AUDPP_MAX_COPP_DEVICES		6
+
+enum obj_type {
+	COPP,
+	POPP
+};
+
+enum msm_aud_decoder_state {
+	MSM_AUD_DECODER_STATE_NONE = 0,
+	MSM_AUD_DECODER_STATE_FAILURE = 1,
+	MSM_AUD_DECODER_STATE_SUCCESS = 2,
+	MSM_AUD_DECODER_STATE_CLOSE = 3,
+};
+
+int audpp_adec_alloc(unsigned dec_attrb, const char **module_name,
+			unsigned *queueid);
+void audpp_adec_free(int decid);
+
+struct audpp_event_callback {
+	audpp_event_func fn;
+	void *private;
+};
+
+int audpp_register_event_callback(struct audpp_event_callback *eh);
+int audpp_unregister_event_callback(struct audpp_event_callback *eh);
+int is_audpp_enable(void);
+
+int audpp_enable(int id, audpp_event_func func, void *private);
+void audpp_disable(int id, void *private);
+
+int audpp_send_queue1(void *cmd, unsigned len);
+int audpp_send_queue2(void *cmd, unsigned len);
+int audpp_send_queue3(void *cmd, unsigned len);
+
+void audpp_route_stream(unsigned short dec_id, unsigned short mixer_mask);
+
+int audpp_set_volume_and_pan(unsigned id, unsigned volume, int pan,
+					enum obj_type objtype);
+int audpp_pause(unsigned id, int pause);
+int audpp_flush(unsigned id);
+int audpp_query_avsync(int id);
+int audpp_restore_avsync(int id, uint16_t *avsync);
+
+int audpp_dsp_set_eq(unsigned id, unsigned enable,
+	struct audpp_cmd_cfg_object_params_eqalizer *eq,
+			enum obj_type objtype);
+
+int audpp_dsp_set_spa(unsigned id,
+	struct audpp_cmd_cfg_object_params_spectram *spa,
+			enum obj_type objtype);
+
+int audpp_dsp_set_stf(unsigned id, unsigned enable,
+     struct audpp_cmd_cfg_object_params_sidechain *stf,
+			enum obj_type objtype);
+
+int audpp_dsp_set_vol_pan(unsigned id,
+	struct audpp_cmd_cfg_object_params_volume *vol_pan,
+			enum obj_type objtype);
+
+int audpp_dsp_set_mbadrc(unsigned id, unsigned enable,
+	struct audpp_cmd_cfg_object_params_mbadrc *mbadrc,
+	enum obj_type objtype);
+
+int audpp_dsp_set_qconcert_plus(unsigned id, unsigned enable,
+	struct audpp_cmd_cfg_object_params_qconcert *qconcert_plus,
+	enum obj_type objtype);
+
+int audpp_dsp_set_rx_iir(unsigned id, unsigned enable,
+	struct audpp_cmd_cfg_object_params_pcm *iir,
+	enum obj_type objtype);
+
+int audpp_dsp_set_gain_rx(unsigned id,
+	struct audpp_cmd_cfg_cal_gain *calib_gain_rx,
+	enum obj_type objtype);
+int audpp_dsp_set_pbe(unsigned id, unsigned enable,
+	struct audpp_cmd_cfg_pbe *pbe_block,
+	enum obj_type objtype);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/audpreproc.h b/arch/arm/mach-msm/include/mach/qdsp5v2/audpreproc.h
new file mode 100644
index 0000000..6abeae1
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/audpreproc.h
@@ -0,0 +1,96 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _MACH_QDSP5_V2_AUDPREPROC_H
+#define _MACH_QDSP5_V2_AUDPREPROC_H
+
+#include <mach/qdsp5v2/qdsp5audpreproccmdi.h>
+#include <mach/qdsp5v2/qdsp5audpreprocmsg.h>
+
+#define MAX_ENC_COUNT 3
+
+#define MSM_ADSP_ENC_CODEC_WAV 0
+#define MSM_ADSP_ENC_CODEC_AAC 1
+#define MSM_ADSP_ENC_CODEC_SBC 2
+#define MSM_ADSP_ENC_CODEC_AMRNB 3
+#define MSM_ADSP_ENC_CODEC_EVRC 4
+#define MSM_ADSP_ENC_CODEC_QCELP 5
+#define MSM_ADSP_ENC_CODEC_EXT_WAV (15)
+
+#define MSM_ADSP_ENC_MODE_TUNNEL 24
+#define MSM_ADSP_ENC_MODE_NON_TUNNEL 25
+
+#define AUDPREPROC_CODEC_MASK 0x00FF
+#define AUDPREPROC_MODE_MASK 0xFF00
+
+#define MSM_AUD_ENC_MODE_TUNNEL  0x00000100
+#define MSM_AUD_ENC_MODE_NONTUNNEL  0x00000200
+
+#define SOURCE_PIPE_1	0x0001
+#define SOURCE_PIPE_0	0x0000
+
+/* event callback routine prototype*/
+typedef void (*audpreproc_event_func)(void *private, unsigned id, void *msg);
+
+struct audpreproc_event_callback {
+	audpreproc_event_func fn;
+	void *private;
+};
+
+/*holds audrec information*/
+struct audrec_session_info {
+	int session_id;
+	int sampling_freq;
+};
+
+/* Exported common api's from audpreproc layer */
+int audpreproc_aenc_alloc(unsigned enc_type, const char **module_name,
+		unsigned *queue_id);
+void audpreproc_aenc_free(int enc_id);
+
+int audpreproc_enable(int enc_id, audpreproc_event_func func, void *private);
+void audpreproc_disable(int enc_id, void *private);
+
+int audpreproc_send_audreccmdqueue(void *cmd, unsigned len);
+
+int audpreproc_send_preproccmdqueue(void *cmd, unsigned len);
+
+int audpreproc_dsp_set_agc(struct audpreproc_cmd_cfg_agc_params *agc,
+	unsigned len);
+int audpreproc_dsp_set_agc2(struct audpreproc_cmd_cfg_agc_params_2 *agc2,
+	unsigned len);
+int audpreproc_dsp_set_ns(struct audpreproc_cmd_cfg_ns_params *ns,
+	unsigned len);
+int audpreproc_dsp_set_iir(
+struct audpreproc_cmd_cfg_iir_tuning_filter_params *iir, unsigned len);
+
+int audpreproc_dsp_set_agc(struct audpreproc_cmd_cfg_agc_params *agc,
+ unsigned int len);
+
+int audpreproc_dsp_set_iir(
+struct audpreproc_cmd_cfg_iir_tuning_filter_params *iir, unsigned int len);
+
+int audpreproc_update_audrec_info(struct audrec_session_info
+						*audrec_session_info);
+int audpreproc_unregister_event_callback(struct audpreproc_event_callback *ecb);
+
+int audpreproc_register_event_callback(struct audpreproc_event_callback *ecb);
+
+int audpreproc_dsp_set_gain_tx(
+	struct audpreproc_cmd_cfg_cal_gain *calib_gain_tx, unsigned len);
+
+void get_audrec_session_info(int id, struct audrec_session_info *info);
+
+int audpreproc_dsp_set_lvnv(
+	struct audpreproc_cmd_cfg_lvnv_param *preproc_lvnv, unsigned len);
+#endif /* _MACH_QDSP5_V2_AUDPREPROC_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/aux_pcm.h b/arch/arm/mach-msm/include/mach/qdsp5v2/aux_pcm.h
new file mode 100644
index 0000000..100ddea
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/aux_pcm.h
@@ -0,0 +1,55 @@
+/* Copyright (c) 2009, 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 __MACH_QDSP5_V2_AUX_PCM_H
+#define __MACH_QDSP5_V2_AUX_PCM_H
+#include <mach/qdsp5v2/audio_def.h>
+
+/* define some values in AUX_CODEC_CTL register */
+#define AUX_CODEC_CTL__ADSP_CODEC_CTL_EN__MSM_V 0 /* default */
+#define AUX_CODEC_CTL__ADSP_CODEC_CTL_EN__ADSP_V 0x800
+#define AUX_CODEC_CTL__PCM_SYNC_LONG_OFFSET_V  0x400
+#define AUX_CODEC_CTL__PCM_SYNC_SHORT_OFFSET_V 0x200
+#define AUX_CODEC_CTL__I2S_SAMPLE_CLK_SRC__SDAC_V 0
+#define AUX_CODEC_CTL__I2S_SAMPLE_CLK_SRC__ICODEC_V 0x80
+#define AUX_CODEC_CTL__I2S_SAMPLE_CLK_MODE__MASTER_V 0
+#define AUX_CODEC_CTL__I2S_SAMPLE_CLK_MODE__SLAVE_V 0x40
+#define AUX_CODEC_CTL__I2S_RX_MODE__REV_V 0
+#define AUX_CODEC_CTL__I2S_RX_MODE__TRAN_V 0x20
+#define AUX_CODEC_CTL__I2S_CLK_MODE__MASTER_V 0
+#define AUX_CODEC_CTL__I2S_CLK_MODE__SLAVE_V 0x10
+#define AUX_CODEC_CTL__AUX_PCM_MODE__PRIM_MASTER_V 0
+#define AUX_CODEC_CTL__AUX_PCM_MODE__AUX_MASTER_V 0x4
+#define AUX_CODEC_CTL__AUX_PCM_MODE__PRIM_SLAVE_V 0x8
+#define AUX_CODEC_CTL__AUX_CODEC_MDOE__PCM_V 0
+#define AUX_CODEC_CTL__AUX_CODEC_MODE__I2S_V 0x2
+
+/* define some values in PCM_PATH_CTL register */
+#define PCM_PATH_CTL__ADSP_CTL_EN__MSM_V 0
+#define PCM_PATH_CTL__ADSP_CTL_EN__ADSP_V 0x8
+
+/* define some values for aux codec config of AFE*/
+/* PCM CTL */
+#define PCM_CTL__RPCM_WIDTH__LINEAR_V 0x1
+#define PCM_CTL__TPCM_WIDTH__LINEAR_V 0x2
+/* AUX_CODEC_INTF_CTL */
+#define AUX_CODEC_INTF_CTL__PCMINTF_DATA_EN_V 0x800
+/* DATA_FORMAT_PADDING_INFO */
+#define DATA_FORMAT_PADDING_INFO__RPCM_FORMAT_V 0x400
+#define DATA_FORMAT_PADDING_INFO__TPCM_FORMAT_V 0x2000
+
+void aux_codec_adsp_codec_ctl_en(bool msm_adsp_en);
+void aux_codec_pcm_path_ctl_en(bool msm_adsp_en);
+int aux_pcm_gpios_request(void);
+void aux_pcm_gpios_free(void);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/codec_utils.h b/arch/arm/mach-msm/include/mach/qdsp5v2/codec_utils.h
new file mode 100644
index 0000000..92dfe12
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/codec_utils.h
@@ -0,0 +1,139 @@
+/* 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
+ * 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 CODEC_UTILS_H
+#define CODEC_UTILS_H
+
+#include <linux/earlysuspend.h>
+
+#define ADRV_STATUS_AIO_INTF 0x00000001
+#define ADRV_STATUS_OBUF_GIVEN 0x00000002
+#define ADRV_STATUS_IBUF_GIVEN 0x00000004
+#define ADRV_STATUS_FSYNC 0x00000008
+
+#define PCM_BUFSZ_MIN 4800	/* Hold one stereo MP3 frame */
+#define PCM_BUF_MAX_COUNT 5	/* DSP only accepts 5 buffers at most
+				   but support 2 buffers currently */
+#define ROUTING_MODE_FTRT 1
+#define ROUTING_MODE_RT 2
+/* Decoder status received from AUDPPTASK */
+#define  AUDPP_DEC_STATUS_SLEEP	0
+#define	 AUDPP_DEC_STATUS_INIT  1
+#define  AUDPP_DEC_STATUS_CFG   2
+#define  AUDPP_DEC_STATUS_PLAY  3
+#define  AUDPP_DEC_STATUS_EOS   5
+
+/* worst case delay of 3secs(3000ms) for AV Sync Query response */
+#define AVSYNC_EVENT_TIMEOUT 3000
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+};
+struct audio;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct audio_suspend_ctl {
+	struct early_suspend node;
+	struct audio *audio;
+};
+#endif
+
+struct codec_operations {
+	long (*ioctl)(struct file *, unsigned int, unsigned long);
+	void (*adec_params)(struct audio *);
+};
+
+struct audio {
+	spinlock_t dsp_lock;
+
+	uint8_t out_needed; /* number of buffers the dsp is waiting for */
+	struct list_head out_queue; /* queue to retain output buffers */
+	atomic_t out_bytes;
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	struct msm_adsp_module *audplay;
+
+	/* configuration to use on next enable */
+	uint32_t out_sample_rate;
+	uint32_t out_channel_mode;
+	uint32_t out_bits; /* bits per sample (used by PCM decoder) */
+
+	/* data allocated for various buffers */
+	char *data;
+	int32_t phys; /* physical address of write buffer */
+
+	uint32_t drv_status;
+	int wflush; /* Write flush */
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+	int buf_refresh;
+	int teos; /* valid only if tunnel mode & no data left for decoder */
+	enum msm_aud_decoder_state dec_state;	/* Represents decoder state */
+	int reserved; /* A byte is being reserved */
+	char rsv_byte; /* Handle odd length user data */
+
+	const char *module_name;
+	unsigned queue_id;
+	uint16_t dec_id;
+	uint32_t read_ptr_offset;
+	int16_t source;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct audio_suspend_ctl suspend_ctl;
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+
+	wait_queue_head_t wait;
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	wait_queue_head_t event_wait;
+	spinlock_t event_queue_lock;
+	struct mutex get_event_lock;
+	int event_abort;
+	/* AV sync Info */
+	int avsync_flag;              /* Flag to indicate feedback from DSP */
+	wait_queue_head_t avsync_wait;/* Wait queue for AV Sync Message     */
+	/* flags, 48 bits sample/bytes counter per channel */
+	uint16_t avsync[AUDPP_AVSYNC_CH_COUNT * AUDPP_AVSYNC_NUM_WORDS + 1];
+
+	uint32_t device_events;
+	uint32_t device_switch;       /* Flag to indicate device switch */
+	uint64_t bytecount_consumed;
+	uint64_t bytecount_head;
+	uint64_t bytecount_given;
+	uint64_t bytecount_query;
+
+	struct list_head pmem_region_queue; /* protected by lock */
+
+	int eq_enable;
+	int eq_needs_commit;
+	struct audpp_cmd_cfg_object_params_eqalizer eq;
+	struct audpp_cmd_cfg_object_params_volume vol_pan;
+
+	unsigned int minor_no;
+	struct codec_operations codec_ops;
+	uint32_t buffer_size;
+	uint32_t buffer_count;
+};
+
+#endif /* !CODEC_UTILS_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/lpa.h b/arch/arm/mach-msm/include/mach/qdsp5v2/lpa.h
new file mode 100644
index 0000000..d71cf72
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/lpa.h
@@ -0,0 +1,36 @@
+/* Copyright (c) 2009, 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 __MACH_QDSP5_V2_LPA_H__
+#define __MACH_QDSP5_V2_LPA_H__
+
+#define LPA_OUTPUT_INTF_WB_CODEC 3
+#define LPA_OUTPUT_INTF_SDAC     1
+#define LPA_OUTPUT_INTF_MI2S     2
+
+struct lpa_codec_config {
+	uint32_t sample_rate;
+	uint32_t sample_width;
+	uint32_t output_interface;
+	uint32_t num_channels;
+};
+
+struct lpa_drv;
+
+struct lpa_drv *lpa_get(void);
+void lpa_put(struct lpa_drv *lpa);
+int lpa_cmd_codec_config(struct lpa_drv *lpa,
+	struct lpa_codec_config *config_ptr);
+int lpa_cmd_enable_codec(struct lpa_drv *lpa, bool enable);
+
+#endif
+
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/lpa_hw.h b/arch/arm/mach-msm/include/mach/qdsp5v2/lpa_hw.h
new file mode 100644
index 0000000..bfff384
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/lpa_hw.h
@@ -0,0 +1,236 @@
+/* Copyright (c) 2009, 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 __MACH_QDSP5_V2_LPA_HW_H__
+#define __MACH_QDSP5_V2_LPA_HW_H__
+
+#define LPA_MAX_BUF_SIZE 0x30000
+
+/* LPA Output config registers */
+enum {
+	LPA_OBUF_CONTROL	= 0x00000000,
+	LPA_OBUF_CODEC		= 0x00000004,
+	LPA_OBUF_HLB_MIN_ADDR	= 0x00000008,
+	LPA_OBUF_HLB_MAX_ADDR	= 0x0000000C,
+	LPA_OBUF_HLB_WPTR	= 0x00000010,
+	LPA_OBUF_HLB_VOLUME_CONTROL = 0x00000014,
+	LPA_OBUF_LLB_MIN_ADDR	= 0x00000018,
+	LPA_OBUF_LLB_MAX_ADDR	= 0x0000001C,
+	LPA_OBUF_SB_MIN_ADDR	= 0x00000020,
+	LPA_OBUF_SB_MAX_ADDR	= 0x00000024,
+	LPA_OBUF_INTR_ENABLE	= 0x00000028,
+	LPA_OBUF_INTR_STATUS	= 0x0000002C,
+	LPA_OBUF_WMARK_ASSIGN	= 0x00000030,
+	LPA_OBUF_WMARK_0_LLB	= 0x00000034,
+	LPA_OBUF_WMARK_1_LLB	= 0x00000038,
+	LPA_OBUF_WMARK_2_LLB	= 0x0000003C,
+	LPA_OBUF_WMARK_3_LLB	= 0x00000040,
+	LPA_OBUF_WMARK_HLB	= 0x00000044,
+	LPA_OBUF_WMARK_SB	= 0x00000048,
+	LPA_OBUF_RDPTR_LLB	= 0x0000004C,
+	LPA_OBUF_RDPTR_HLB	= 0x00000050,
+	LPA_OBUF_WRPTR_SB	= 0x00000054,
+	LPA_OBUF_UTC_CONFIG	= 0x00000058,
+	LPA_OBUF_UTC_INTR_LOW	= 0x0000005C,
+	LPA_OBUF_UTC_INTR_HIGH	= 0x00000060,
+	LPA_OBUF_UTC_LOW	= 0x00000064,
+	LPA_OBUF_UTC_HIGH	= 0x00000068,
+	LPA_OBUF_MISR		= 0x0000006C,
+	LPA_OBUF_STATUS		= 0x00000070,
+	LPA_OBUF_ACK		= 0x00000074,
+	LPA_OBUF_MEMORY_CONTROL	= 0x00000078,
+	LPA_OBUF_MEMORY_STATUS	= 0x0000007C,
+	LPA_OBUF_MEMORY_TIME_CONTROL	= 0x00000080,
+	LPA_OBUF_ACC_LV			= 0x00000084,
+	LPA_OBUF_ACC_HV			= 0x0000008c,
+	LPA_OBUF_RESETS			= 0x00000090,
+	LPA_OBUF_TESTBUS		= 0x00000094,
+};
+
+/* OBUF_CODEC definition */
+#define LPA_OBUF_CODEC_RESERVED31_22_BMSK        0xffc00000
+#define LPA_OBUF_CODEC_RESERVED31_22_SHFT        0x16
+#define LPA_OBUF_CODEC_LOAD_BMSK                 0x200000
+#define LPA_OBUF_CODEC_LOAD_SHFT                 0x15
+#define LPA_OBUF_CODEC_CODEC_INTF_EN_BMSK        0x100000
+#define LPA_OBUF_CODEC_CODEC_INTF_EN_SHFT        0x14
+#define LPA_OBUF_CODEC_SAMP_BMSK                 0xf0000
+#define LPA_OBUF_CODEC_SAMP_SHFT                 0x10
+#define LPA_OBUF_CODEC_BITS_PER_CHAN_BMSK        0xc000
+#define LPA_OBUF_CODEC_BITS_PER_CHAN_SHFT        0xe
+#define LPA_OBUF_CODEC_RESERVED_13_7_BMSK        0x3f80
+#define LPA_OBUF_CODEC_RESERVED_13_7_SHFT        0x7
+#define LPA_OBUF_CODEC_INTF_BMSK                 0x70
+#define LPA_OBUF_CODEC_INTF_SHFT                 0x4
+#define LPA_OBUF_CODEC_NUM_CHAN_BMSK             0xf
+#define LPA_OBUF_CODEC_NUM_CHAN_SHFT             0
+
+/* OBUF_CONTROL definition */
+#define LPA_OBUF_CONTROL_RESERVED31_9_BMSK       0xfffffe00
+#define LPA_OBUF_CONTROL_RESERVED31_9_SHFT       0x9
+#define LPA_OBUF_CONTROL_TEST_EN_BMSK            0x100
+#define LPA_OBUF_CONTROL_TEST_EN_SHFT            0x8
+#define LPA_OBUF_CONTROL_LLB_CLR_CMD_BMSK        0x80
+#define LPA_OBUF_CONTROL_LLB_CLR_CMD_SHFT        0x7
+#define LPA_OBUF_CONTROL_SB_SAT_EN_BMSK          0x40
+#define LPA_OBUF_CONTROL_SB_SAT_EN_SHFT          0x6
+#define LPA_OBUF_CONTROL_LLB_SAT_EN_BMSK         0x20
+#define LPA_OBUF_CONTROL_LLB_SAT_EN_SHFT         0x5
+#define LPA_OBUF_CONTROL_RESERVED4_BMSK          0x10
+#define LPA_OBUF_CONTROL_RESERVED4_SHFT          0x4
+#define LPA_OBUF_CONTROL_LLB_ACC_EN_BMSK         0x8
+#define LPA_OBUF_CONTROL_LLB_ACC_EN_SHFT         0x3
+#define LPA_OBUF_CONTROL_HLB_EN_BMSK             0x4
+#define LPA_OBUF_CONTROL_HLB_EN_SHFT             0x2
+#define LPA_OBUF_CONTROL_LLB_EN_BMSK             0x2
+#define LPA_OBUF_CONTROL_LLB_EN_SHFT             0x1
+#define LPA_OBUF_CONTROL_SB_EN_BMSK              0x1
+#define LPA_OBUF_CONTROL_SB_EN_SHFT              0
+
+/* OBUF_RESET definition */
+#define LPA_OBUF_RESETS_MISR_RESET 0x1
+#define LPA_OBUF_RESETS_OVERALL_RESET 0x2
+
+/* OBUF_STATUS definition */
+#define LPA_OBUF_STATUS_RESET_DONE 0x80000
+#define LPA_OBUF_STATUS_LLB_CLR_BMSK 0x40000
+#define LPA_OBUF_STATUS_LLB_CLR_SHFT 0x12
+
+/* OBUF_HLB_MIN_ADDR definition */
+#define LPA_OBUF_HLB_MIN_ADDR_LOAD_BMSK 0x40000
+#define LPA_OBUF_HLB_MIN_ADDR_SEG_BMSK 0x3e000
+
+/* OBUF_HLB_MAX_ADDR definition */
+#define LPA_OBUF_HLB_MAX_ADDR_SEG_BMSK 0x3fff8
+
+/* OBUF_LLB_MIN_ADDR definition */
+#define LPA_OBUF_LLB_MIN_ADDR_LOAD_BMSK 0x40000
+#define LPA_OBUF_LLB_MIN_ADDR_SEG_BMSK 0x3e000
+
+/* OBUF_LLB_MAX_ADDR definition */
+#define LPA_OBUF_LLB_MAX_ADDR_SEG_BMSK 0x3ff8
+#define LPA_OBUF_LLB_MAX_ADDR_SEG_SHFT 0x3
+
+/* OBUF_SB_MIN_ADDR definition */
+#define LPA_OBUF_SB_MIN_ADDR_LOAD_BMSK 0x4000
+#define LPA_OBUF_SB_MIN_ADDR_SEG_BMSK 0x3e00
+
+/* OBUF_SB_MAX_ADDR definition */
+#define LPA_OBUF_SB_MAX_ADDR_SEG_BMSK 0x3ff8
+
+/* OBUF_MEMORY_CONTROL definition */
+#define LPA_OBUF_MEM_CTL_PWRUP_BMSK 0xfff
+#define LPA_OBUF_MEM_CTL_PWRUP_SHFT 0x0
+
+/* OBUF_INTR_ENABLE definition */
+#define LPA_OBUF_INTR_EN_BMSK 0x3
+
+/* OBUF_WMARK_ASSIGN definition */
+#define LPA_OBUF_WMARK_ASSIGN_BMSK 0xF
+#define LPA_OBUF_WMARK_ASSIGN_DONE 0xF
+
+/* OBUF_WMARK_n_LLB definition */
+#define LPA_OBUF_WMARK_n_LLB_ADDR(n)  (0x00000034 + 0x4 * (n))
+#define LPA_OBUF_LLB_WMARK_CTRL_BMSK 0xc0000
+#define LPA_OBUF_LLB_WMARK_CTRL_SHFT 0x12
+#define LPA_OBUF_LLB_WMARK_MAP_BMSK  0xf00000
+#define LPA_OBUF_LLB_WMARK_MAP_SHFT  0x14
+
+/* OBUF_WMARK_SB definition */
+#define LPA_OBUF_SB_WMARK_CTRL_BMSK 0xc0000
+#define LPA_OBUF_SB_WMARK_CTRL_SHFT 0x12
+#define LPA_OBUF_SB_WMARK_MAP_BMSK  0xf00000
+#define LPA_OBUF_SB_WMARK_MAP_SHFT  0x14
+
+/* OBUF_WMARK_HLB definition */
+#define LPA_OBUF_HLB_WMARK_CTRL_BMSK 0xc0000
+#define LPA_OBUF_HLB_WMARK_CTRL_SHFT 0x12
+#define LPA_OBUF_HLB_WMARK_MAP_BMSK  0xf00000
+#define LPA_OBUF_HLB_WMARK_MAP_SHFT  0x14
+
+/* OBUF_UTC_CONFIG definition */
+#define LPA_OBUF_UTC_CONFIG_MAP_BMSK 0xf0
+#define LPA_OBUF_UTC_CONFIG_MAP_SHFT 0x4
+#define LPA_OBUF_UTC_CONFIG_EN_BMSK  0x1
+#define LPA_OBUF_UTC_CONFIG_EN_SHFT  0
+#define LPA_OBUF_UTC_CONFIG_NO_INTR 0xF
+
+/* OBUF_ACK definition */
+#define LPA_OBUF_ACK_RESET_DONE_BMSK   0x80000
+#define LPA_OBUF_ACK_RESET_DONE_SHFT   0x13
+enum {
+	LPA_SAMPLE_RATE_8KHZ		= 0x0000,
+	LPA_SAMPLE_RATE_11P025KHZ	= 0x0001,
+	LPA_SAMPLE_RATE_16KHZ		= 0x0002,
+	LPA_SAMPLE_RATE_22P05KHZ	= 0x0003,
+	LPA_SAMPLE_RATE_32KHZ		= 0x0004,
+	LPA_SAMPLE_RATE_44P1KHZ		= 0x0005,
+	LPA_SAMPLE_RATE_48KHZ		= 0x0006,
+	LPA_SAMPLE_RATE_64KHZ		= 0x0007,
+	LPA_SAMPLE_RATE_96KHZ		= 0x0008,
+};
+
+enum {
+	LPA_BITS_PER_CHAN_16BITS	= 0x0000,
+	LPA_BITS_PER_CHAN_24BITS	= 0x0001,
+	LPA_BITS_PER_CHAN_32BITS	= 0x0002,
+	LPA_BITS_PER_CHAN_RESERVED	= 0x0003,
+};
+
+enum {
+	LPA_INTF_WB_CODEC		= 0x0000,
+	LPA_INTF_SDAC			= 0x0001,
+	LPA_INTF_MI2S			= 0x0002,
+	LPA_INTF_RESERVED		= 0x0003,
+};
+
+enum {
+	LPA_BUF_ID_HLB,   /* HLB buffer */
+	LPA_BUF_ID_LLB,   /* LLB buffer */
+	LPA_BUF_ID_SB,    /* SB buffer */
+	LPA_BUF_ID_UTC,
+};
+
+/* WB_CODEC & SDAC can only support 16bit mono/stereo.
+ * MI2S can bit format and number of channel
+ */
+enum {
+	LPA_NUM_CHAN_MONO		= 0x0000,
+	LPA_NUM_CHAN_STEREO		= 0x0001,
+	LPA_NUM_CHAN_5P1		= 0x0002,
+	LPA_NUM_CHAN_7P1		= 0x0003,
+	LPA_NUM_CHAN_4_CHANNEL		= 0x0004,
+};
+
+enum {
+	LPA_WMARK_CTL_DISABLED = 0x0,
+	LPA_WMARK_CTL_NON_BLOCK = 0x1,
+	LPA_WMARK_CTL_ZERO_INSERT = 0x2,
+	LPA_WMARK_CTL_RESERVED = 0x3
+};
+
+struct lpa_mem_bank_select {
+  u32    b0:1;       /*RAM bank 0 16KB=2Kx64(0) */
+  u32    b1:1;       /*RAM bank 1 16KB=2Kx64(0) */
+  u32    b2:1;       /*RAM bank 2 16KB=2Kx64(0) */
+  u32    b3:1;       /*RAM bank 3 16KB=2Kx64(0) */
+  u32    b4:1;       /*RAM bank 4 16KB=2Kx64(1) */
+  u32    b5:1;       /*RAM bank 5 16KB=2Kx64(1) */
+  u32    b6:1;       /*RAM bank 6 16KB=2Kx64(1) */
+  u32    b7:1;       /*RAM bank 7 16KB=2Kx64(1) */
+  u32    b8:1;       /*RAM bank 8 16KB=4Kx32(0) */
+  u32    b9:1;       /*RAM bank 9 16KB=4Kx32(1) */
+  u32    b10:1;      /*RAM bank 10 16KB=4Kx32(2) */
+  u32    llb:1;      /*RAM bank 11 16KB=4Kx32(3) */
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/marimba_profile.h b/arch/arm/mach-msm/include/mach/qdsp5v2/marimba_profile.h
new file mode 100644
index 0000000..c1cb3fe
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/marimba_profile.h
@@ -0,0 +1,3201 @@
+/* Copyright (c) 2009-2011,  Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __MACH_QDSP5_V2_MARIMBA_PROFILE_H__
+#define __MACH_QDSP5_V2_MARIMBA_PROFILE_H__
+
+/***************************************************************************\
+				Handset
+\***************************************************************************/
+
+
+#define HANDSET_RX_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80,  0x02,  0x02)},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x44)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x04, 0xff, 0x8C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x4E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x25, 0x0F, 0x0b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x36, 0xc0, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0x2B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xff, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3d, 0xFF, 0xD5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x21, 0x21)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x2710}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x40, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x05, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x36, 0xc0, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x40, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HANDSET_RX_16000_OSR_256 HANDSET_RX_8000_OSR_256
+
+#define HANDSET_RX_48000_OSR_64\
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x47)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x04, 0xfF, 0x8C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x42)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x25, 0x0F, 0x0b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x36, 0xc0, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0x2B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xff, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3d, 0xFF, 0xD5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x21, 0x21)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x2710}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x40, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x05, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x36, 0xc0, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x40, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HANDSET_RX_48000_OSR_256\
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x44)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x04, 0xfF, 0x8C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x4e)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x25, 0x0F, 0x0b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x36, 0xc0, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0x2B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xff, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3d, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x21, 0x21)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x2710}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x40, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x05, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x36, 0xc0, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x40, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HANDSET_TX_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x13, 0xfc, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xff, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x15, 0xff, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xff, 0x5E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x10, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xF0, 0xd0)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x14, 0x14)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8b, 0xff, 0xE6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8c, 0x03, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x50, 0x40)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x10, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x14, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HANDSET_TX_16000_OSR_256 HANDSET_TX_8000_OSR_256
+
+#define HANDSET_TX_48000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x13, 0xfc, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xff, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x15, 0xff, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xff, 0x5A)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x10, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xF0, 0xd0)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x14, 0x14)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8b, 0xff, 0xE6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8c, 0x03, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x50, 0x40)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x10, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x14, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/***************************************************************************\
+				Headset
+\***************************************************************************/
+
+
+
+#define HEADSET_STEREO_TX_8000_OSR_256\
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x13, 0xfc, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xfd, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x15, 0xff, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x5E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x10, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xE8, 0xE8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xF0, 0xD0)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x1c, 0x1c)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8b, 0xff, 0xE7)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8c, 0x03, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0e, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0d, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x1c, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HEADSET_STEREO_TX_16000_OSR_256 HEADSET_STEREO_TX_8000_OSR_256
+
+#define HEADSET_STEREO_TX_48000_OSR_64\
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x13, 0xfc, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xfd, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x15, 0xfc, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x46)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x10, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xE8, 0xE8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xF0, 0xD0)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x1c, 0x1c)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8b, 0xff, 0xE7)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8c, 0x03, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0e, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0d, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x1c, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HEADSET_STEREO_TX_48000_OSR_256\
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FALSH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x13, 0xfc, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xfd, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x15, 0xfc, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xff, 0x5A)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x10, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xE8, 0xE8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xF0, 0xD0)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x1c, 0x1c)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8b, 0xff, 0xE7)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8c, 0x03, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0e, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0d, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x1c, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HEADSET_MONO_TX_16000_OSR_256\
+	{{ADIE_CODEC_ACTION_STAGE_REACHED,  ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY,  ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY,  ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY,  ADIE_CODEC_PACK_ENTRY(0x8A, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY,  ADIE_CODEC_PACK_ENTRY(0x11, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY,  ADIE_CODEC_PACK_ENTRY(0x13, 0xfc, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY,  ADIE_CODEC_PACK_ENTRY(0x14, 0xff, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY,  ADIE_CODEC_PACK_ENTRY(0x15, 0xfc, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY,  ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x5E)}, \
+	{ADIE_CODEC_ACTION_ENTRY,  ADIE_CODEC_PACK_ENTRY(0x10, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED,  ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY,  ADIE_CODEC_PACK_ENTRY(0x0D, 0xFf, 0xc8)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT,  0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY,  ADIE_CODEC_PACK_ENTRY(0x83, 0x14, 0x14)}, \
+	{ADIE_CODEC_ACTION_ENTRY,  ADIE_CODEC_PACK_ENTRY(0x8b, 0xff, 0xE7)}, \
+	{ADIE_CODEC_ACTION_ENTRY,  ADIE_CODEC_PACK_ENTRY(0x8c, 0x03, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY,  ADIE_CODEC_PACK_ENTRY(0x86, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY,  ADIE_CODEC_PACK_ENTRY(0x8A, 0x50, 0x40)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED,  ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY,  ADIE_CODEC_PACK_ENTRY(0x8A, 0x10, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY,  ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY,  ADIE_CODEC_PACK_ENTRY(0x83, 0x14, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED,  ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY,  ADIE_CODEC_PACK_ENTRY(0x11, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED,  ADIE_CODEC_DIGITAL_OFF} }
+
+#define HEADSET_MONO_TX_8000_OSR_256 HEADSET_MONO_TX_16000_OSR_256
+
+#define HEADSET_MONO_TX_48000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x13, 0xfc, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xff, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x15, 0xff, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xff, 0x5A)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x10, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xC8)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x14, 0x14)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8b, 0xff, 0xE7)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8c, 0x03, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x50, 0x40)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x10, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x14, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HEADSET_RX_CAPLESS_8000_OSR_256\
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x4E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x04, 0xff, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x25, 0x0F, 0x0b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xff, 0xa2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0xeb)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xf0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xff, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HEADSET_RX_CAPLESS_48000_OSR_64 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x42)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x04, 0xff, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x67)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x25, 0x0F, 0x0b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xff, 0xa2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0xab)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xf0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xff, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HEADSET_RX_CAPLESS_48000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x4e)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x04, 0xff, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x25, 0x0F, 0x0B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xff, 0xa2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0xab)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xf0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xff, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+#define HEADSET_RX_LEGACY_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x4E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x04, 0xff, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x25, 0x0F, 0x0b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xff, 0xa0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0x2b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xa0)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xf0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xff, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HEADSET_RX_LEGACY_16000_OSR_256 HEADSET_RX_LEGACY_8000_OSR_256
+
+#define HEADSET_RX_LEGACY_48000_OSR_64 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x42)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x04, 0xff, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x67)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x25, 0x0F, 0x0b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xff, 0xa0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0x2b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xa0)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xf0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xff, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+#define HEADSET_RX_LEGACY_48000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x4e)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x04, 0xff, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x25, 0x0F, 0x0B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xff, 0xa0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0x2b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xa0)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xf0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xff, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HEADSET_RX_CLASS_D_LEGACY_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0e)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xf8, 0xA8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x29, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x50, 0x50)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x40, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x41, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x42, 0xFF, 0xFF)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x43, 0xFF, 0xc4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x44, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0xFF, 0xDD)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3F, 0xFF, 0x0f)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x45, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x46, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x47, 0xFF, 0xc4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x48, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x49, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4a, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0a, 0x0a)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0f, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+#define HEADSET_RX_CLASS_D_LEGACY_11025_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0e)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xf8, 0xA8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x29, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x50, 0x50)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x40, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x41, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x42, 0xFF, 0xbb)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x43, 0xFF, 0xc2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x44, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0xFF, 0xDD)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3F, 0xFF, 0x0f)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x45, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x46, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x47, 0xFF, 0xc2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x48, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x49, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4a, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0a, 0x0a)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0f, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+#define HEADSET_RX_CLASS_D_LEGACY_16000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0e)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xf8, 0xA8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x29, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x50, 0x50)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x40, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x41, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x42, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x43, 0xFF, 0xd4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x44, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0xFF, 0xDD)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3F, 0xFF, 0x0f)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x45, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x46, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x47, 0xFF, 0xd4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x48, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x49, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4a, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0a, 0x0a)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0f, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+#define HEADSET_RX_CLASS_D_LEGACY_22050_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0e)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xf8, 0xA8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x29, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x50, 0x50)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x40, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x41, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x42, 0xFF, 0xbb)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x43, 0xFF, 0xd2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x44, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0xFF, 0xDD)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3F, 0xFF, 0x0f)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x45, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x46, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x47, 0xFF, 0xd2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x48, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x49, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4a, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0a, 0x0a)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0f, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+#define HEADSET_CLASS_D_LEGACY_32000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0e)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xf8, 0xA8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x29, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x50, 0x50)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x40, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x41, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x42, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x43, 0xFF, 0xf4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x44, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0xFF, 0xDD)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3F, 0xFF, 0x0f)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x45, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x46, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x47, 0xFF, 0xf4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x48, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x49, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4a, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0a, 0x0a)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0f, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HEADSET_RX_CLASS_D_LEGACY_48000_OSR_64 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xf8, 0xA8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x29, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x50, 0x50)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x40, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x41, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x42, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x43, 0xFF, 0xc5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x44, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0xFF, 0xDD)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3F, 0xFF, 0x0f)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x45, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x46, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x47, 0xFF, 0xc2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x48, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x49, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4a, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0a, 0x0a)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0f, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HEADSET_RX_CLASS_D_LEGACY_48000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0e)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xf8, 0xA8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x29, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x50, 0x50)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x40, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x41, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x42, 0xFF, 0xBB)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x43, 0xFF, 0xF2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x44, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0xFF, 0xDD)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3F, 0xFF, 0x0f)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x45, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x46, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x47, 0xFF, 0xF2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x48, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x49, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4a, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0a, 0x0a)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0f, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HEADSET_STEREO_RX_CAPLESS_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x4E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x04, 0xff, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x25, 0x0F, 0x0b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xff, 0x82)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0xeb)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xf0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xff, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HEADSET_STEREO_RX_CAPLESS_48000_OSR_64 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x42)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x04, 0xff, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x67)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x25, 0x0F, 0x0b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xff, 0x82)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0xab)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xf0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xff, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+
+#define HEADSET_STEREO_RX_CAPLESS_48000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x4e)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x04, 0xff, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x25, 0x0F, 0x0B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xff, 0x82)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0xab)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x82)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xf0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xff, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HEADSET_STEREO_RX_LEGACY_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x4E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x04, 0xff, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x25, 0x0F, 0x0b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xff, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0x2b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xa0)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xf0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xff, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFF, 0xaC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xaC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HEADSET_STEREO_RX_LEGACY_48000_OSR_64 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x42)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x04, 0xff, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x67)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x25, 0x0F, 0x0b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xff, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0x2b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xa0)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xf0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xff, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HEADSET_STEREO_RX_LEGACY_48000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x4e)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x04, 0xff, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x25, 0x0F, 0x0B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xff, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0x2b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xa0)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xf0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xff, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HEADSET_STEREO_RX_CLASS_D_LEGACY_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0e)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xf8, 0xA8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x29, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x40, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x40, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x41, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x42, 0xFF, 0xFF)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x43, 0xFF, 0xc4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x44, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0xFF, 0xDD)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3F, 0xFF, 0x0f)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x45, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x46, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x47, 0xFF, 0xc4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x48, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x49, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4a, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0a, 0x0a)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0f, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+#define HEADSET_STEREO_RX_CLASS_D_LEGACY_11025_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0e)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xf8, 0xA8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x29, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x40, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x40, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x41, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x42, 0xFF, 0xbb)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x43, 0xFF, 0xc2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x44, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0xFF, 0xDD)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3F, 0xFF, 0x0f)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x45, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x46, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x47, 0xFF, 0xc2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x48, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x49, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4a, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0a, 0x0a)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0f, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HEADSET_STEREO_RX_CLASS_D_LEGACY_16000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0e)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xf8, 0xA8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x29, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x40, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x40, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x41, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x42, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x43, 0xFF, 0xd4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x44, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0xFF, 0xDD)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3F, 0xFF, 0x0f)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x45, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x46, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x47, 0xFF, 0xd4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x48, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x49, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4a, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0a, 0x0a)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0f, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+#define HEADSET_STEREO_RX_CLASS_D_LEGACY_22050_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0e)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xf8, 0xA8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x29, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x40, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x40, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x41, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x42, 0xFF, 0xbb)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x43, 0xFF, 0xd2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x44, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0xFF, 0xDD)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3F, 0xFF, 0x0f)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x45, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x46, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x47, 0xFF, 0xd2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x48, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x49, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4a, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0a, 0x0a)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0f, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+#define HEADSET_STEREO_RX_CLASS_D_LEGACY_32000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0e)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xf8, 0xA8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x29, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x40, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x40, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x41, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x42, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x43, 0xFF, 0xf4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x44, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0xFF, 0xDD)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3F, 0xFF, 0x0f)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x45, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x46, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x47, 0xFF, 0xf4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x48, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x49, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4a, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0a, 0x0a)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0f, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HEADSET_STEREO_RX_CLASS_D_LEGACY_48000_OSR_64 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xf8, 0xA8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x29, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x40, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x40, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x41, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x42, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x43, 0xFF, 0xc5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x44, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0xFF, 0xDD)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3F, 0xFF, 0x0f)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x45, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x46, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x47, 0xFF, 0xc2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x48, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x49, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4a, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0a, 0x0a)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0f, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HEADSET_STEREO_RX_CLASS_D_LEGACY_48000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0e)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xf8, 0xA8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x29, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x40, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x40, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x41, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x42, 0xFF, 0xBB)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x43, 0xFF, 0xF2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x44, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0xFF, 0xDD)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3F, 0xFF, 0x0f)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x45, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x46, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x47, 0xFF, 0xF2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x48, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x49, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4a, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0a, 0x0a)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0f, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define SPEAKER_RX_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x4E)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x25, 0x0F, 0x0b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x37, 0xe2, 0xa2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0x2B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3d, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xff, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x8a, 0x8a)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x7530}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x05, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x40, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x7530}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+#define SPEAKER_RX_48000_OSR_64 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x42)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x67)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x25, 0x0F, 0x0b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x37, 0xe2, 0xa2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0x2B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3d, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xff, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x8a, 0x8a)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x7530}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x05, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x40, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x7530}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define SPEAKER_RX_48000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x25, 0x0F, 0x0B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x37, 0xe2, 0xa2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0x2B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3d, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xff, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x8a, 0x8a)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x7530}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x05, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x40, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x7530}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define SPEAKER_STEREO_RX_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x4E)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x25, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x37, 0xe6, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0x2B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3d, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xff, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x8a, 0x8a)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x7530}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x0f, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x40, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x7530}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+#define SPEAKER_STEREO_RX_48000_OSR_64 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x42)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x67)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x25, 0x0F, 0x0b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x37, 0xe6, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0x2B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3d, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xff, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x8a, 0x8a)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x7530}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x0f, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x40, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x7530}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define SPEAKER_STEREO_RX_48000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x25, 0x0F, 0x0B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x37, 0xe6, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0x2B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3d, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xff, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x8a, 0x8a)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x7530}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x0f, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x40, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x7530}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+#define SPEAKER_TX_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x13, 0xfc, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xff, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x15, 0xff, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xff, 0x5E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x10, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xF0, 0xD0)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x14, 0x14)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8c, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x50, 0x40)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x10, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x14, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define SPEAKER_TX_48000_OSR_64 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x13, 0xfc, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xff, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x15, 0xff, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xff, 0x46)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x10, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xF0, 0xD0)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x14, 0x14)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8c, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x50, 0x40)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x10, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x14, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+#define SPEAKER_TX_48000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x13, 0xfc, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xff, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x15, 0xff, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xff, 0x5A)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x10, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xF0, 0xD0)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x14, 0x14)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8c, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x50, 0x40)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x10, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x14, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define FM_HANDSET_OSR_64 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x47)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x04, 0xff, 0x8C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x92)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x25, 0x0F, 0x0b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x36, 0xc0, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0x2B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xff, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3d, 0xFF, 0xD5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x2710}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x40, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x05, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x36, 0xc0, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x40, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define FM_HEADSET_STEREO_CLASS_D_LEGACY_OSR_64 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x92)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xf8, 0xA8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x29, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x40, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x40, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x41, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x42, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x43, 0xFF, 0xD5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x44, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0xFF, 0xDD)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3F, 0xFF, 0x0f)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x45, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x46, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x47, 0xFF, 0xD5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x48, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x49, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4a, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0a, 0x0a)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0f, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define FM_HEADSET_CLASS_AB_STEREO_LEGACY_OSR_64 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x92)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x04, 0xff, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x67)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x25, 0x0F, 0x0b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xff, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0x2b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xa0)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xf0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xff, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define FM_HEADSET_CLASS_AB_STEREO_CAPLESS_OSR_64 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x92)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x04, 0xff, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x67)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x25, 0x0F, 0x0b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xff, 0x82)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0xeb)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xf0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xff, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define FM_SPEAKER_OSR_64 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x92)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x67)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x25, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x37, 0xe2, 0xa2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0x2B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xff, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3d, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x8a, 0x8a)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x2710}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x05, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x40, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+#define AUXPGA_HEADSET_STEREO_RX_LEGACY \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2B, 0xff, 0x09)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2C, 0xff, 0x09)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0x2b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2B, 0xff, 0x89)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2C, 0xff, 0x89)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xff, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xa0)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xf0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFF, 0x10)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0x18, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x40, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define AUXPGA_HEADSET_MONO_RX_LEGACY \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2B, 0xff, 0x09)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2C, 0xff, 0x09)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0x2b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2B, 0xff, 0x89)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2C, 0xff, 0x89)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xff, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xa0)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xf0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFF, 0x10)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0x18, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x40, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define AUXPGA_HEADSET_STEREO_RX_CAPLESS \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0xeb)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2B, 0xff, 0x89)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2C, 0xff, 0x89)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xff, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xa0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xf0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0x18, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x40, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define AUXPGA_HEADSET_MONO_RX_CAPLESS \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2B, 0xff, 0x09)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2C, 0xff, 0x09)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0xeb)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2B, 0xff, 0x89)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2C, 0xff, 0x89)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xff, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xa0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xf0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0x18, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x40, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define AUXPGA_HEADSET_STEREO_RX_CLASS_D \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2B, 0xff, 0x09)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2C, 0xff, 0x09)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2B, 0xff, 0x89)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2C, 0xff, 0x89)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x20, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x40, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x41, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x42, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x43, 0xFF, 0xD5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x44, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0xFF, 0xDD)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3F, 0xFF, 0x0f)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x45, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x46, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x47, 0xFF, 0xD5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x48, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x49, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4a, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0a, 0x0a)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFC, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFC, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x20, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+#define AUXPGA_HEADSET_MONO_RX_CLASS_D \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2B, 0xff, 0x09)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2C, 0xff, 0x09)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2B, 0xff, 0x89)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2C, 0xff, 0x89)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x40, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x41, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x42, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x43, 0xFF, 0xD5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x44, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0xFF, 0xDD)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3F, 0xFF, 0x0f)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x45, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x46, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x47, 0xFF, 0xD5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x48, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x49, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4a, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0a, 0x0a)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFC, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFC, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x20, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define AUXPGA_EAR \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2B, 0xff, 0x09)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2C, 0xff, 0x09)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2B, 0xff, 0x89)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2C, 0xff, 0x89)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x36, 0x20, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x2710}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x40, 0x40)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x36, 0x20, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x40, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+/***************************************************************************\
+				DigitalMicprofile
+\***************************************************************************/
+#define DIGITAL_MIC \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xfd, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x1A, 0xff, 0xc0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x66)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x1c, 0x1c)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x1c, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/***************************************************************************\
+				DualMicprofile
+\***************************************************************************/
+#define SPEAKER_MIC1_LEFT_LINE_IN_RIGHT_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x13, 0xfc, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xfd, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x15, 0xff, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x5E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x10, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xE2, 0xE2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xF0, 0xD0)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x1c, 0x1c)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8c, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xc0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0e, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0d, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x1c, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define SPEAKER_MIC1_LEFT_AUX_IN_RIGHT_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x13, 0xfc, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xfd, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x15, 0xff, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x5E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x10, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xE2, 0xE1)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xF0, 0xD0)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x1c, 0x1c)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8c, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xc0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0e, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0d, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x1c, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define MIC1_LEFT_LINE_IN_RIGHT_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x13, 0xfc, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xfd, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x15, 0xff, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x5E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x10, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xE2, 0xE2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xF0, 0xD0)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x1c, 0x1c)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8b, 0xff, 0xCE)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8c, 0x03, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xc0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0e, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0d, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x1c, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define MIC1_LEFT_AUX_IN_RIGHT_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x13, 0xfc, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xfd, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x15, 0xff, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x5E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x10, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xE1, 0xE1)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xF0, 0xD0)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x1c, 0x1c)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8b, 0xff, 0xCE)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8c, 0x03, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xc0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0e, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0d, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x1c, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+/***************************************************************************\
+				AnalogDualMicProfile
+\***************************************************************************/
+#define ANALOG_DUAL_MIC \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x13, 0xfc, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xfd, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x15, 0xff, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x5E)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xE2, 0xE2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xF0, 0xD0)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x1c, 0x1c)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0e, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0d, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x1c, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+/***************************************************************************\
+				TTY
+\***************************************************************************/
+#define TTY_HEADSET_MONO_TX_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x13, 0xfc, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xff, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x15, 0xfc, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x5E)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFf, 0xA8)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x14, 0x14)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8c, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xff, 0x0A)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x50, 0x40)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x10, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x14, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define TTY_HEADSET_MONO_TX_16000_OSR_256 TTY_HEADSET_MONO_TX_8000_OSR_256
+
+#define TTY_HEADSET_MONO_RX_CLASS_D_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0e)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xf8, 0xA8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x29, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x40, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x40, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x41, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x42, 0xFF, 0xFF)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x43, 0xFF, 0xc4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x44, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0xFF, 0xD5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3F, 0xFF, 0x0f)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x45, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x46, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x47, 0xFF, 0xc4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x48, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x49, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4a, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0a, 0x0a)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x05, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0xF4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0f, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define TTY_HEADSET_MONO_RX_CLASS_D_16000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0e)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xf8, 0xA8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x29, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x40, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x40, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x41, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x42, 0xFF, 0xFF)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x43, 0xFF, 0xd4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x44, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0xFF, 0xD5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3F, 0xFF, 0x0f)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x45, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x46, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x47, 0xFF, 0xd4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x48, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x49, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4a, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0a, 0x0a)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x05, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0xF4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0f, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define TTY_HEADSET_MONO_RX_CLASS_D_48000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0e)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xf8, 0xA8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x29, 0xfF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x40, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x40, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x41, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x42, 0xFF, 0xBB)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x43, 0xFF, 0xF2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x44, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0xFF, 0xD5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3F, 0xFF, 0x0f)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x45, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x46, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x47, 0xFF, 0xF2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x48, 0xFF, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x49, 0xFF, 0xff)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4a, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0a, 0x0a)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x05, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3E8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0xF4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0x0f, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/***************************************************************************\
+				FFA
+\***************************************************************************/
+#define HANDSET_RX_8000_OSR_256_FFA \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80,  0x02,  0x02)},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x44)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x04, 0xff, 0x8C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x4E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x25, 0x0F, 0x0b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x36, 0xc0, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0x2B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xff, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3d, 0xFF, 0xD5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x21, 0x21)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x2710}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x40, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x05, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x36, 0xc0, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x40, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HANDSET_RX_16000_OSR_256_FFA HANDSET_RX_8000_OSR_256_FFA
+
+#define HANDSET_RX_48000_OSR_64_FFA \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x47)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x04, 0xfF, 0x8C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x42)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x25, 0x0F, 0x0b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x36, 0xc0, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0x2B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xff, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3d, 0xFF, 0xD5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x21, 0x21)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x2710}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x40, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x05, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x36, 0xc0, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x40, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HANDSET_RX_48000_OSR_256_FFA \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x44)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x04, 0xfF, 0x8C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x4e)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x25, 0x0F, 0x0b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x36, 0xc0, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0x2B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xff, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3d, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x21, 0x21)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x2710}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x40, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x05, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x36, 0xc0, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x40, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HANDSET_TX_8000_OSR_256_FFA \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x13, 0xfc, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xff, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x15, 0xff, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xff, 0x5E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x10, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xF0, 0xd0)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x14, 0x14)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8b, 0xff, 0xCE)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8c, 0x03, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x50, 0x40)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x10, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x14, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HANDSET_TX_16000_OSR_256_FFA HANDSET_TX_8000_OSR_256_FFA
+
+#define HANDSET_TX_48000_OSR_256_FFA \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x13, 0xfc, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xff, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x15, 0xff, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xff, 0x5A)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x10, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xF0, 0xd0)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x14, 0x14)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8b, 0xff, 0xCE)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8c, 0x03, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x50, 0x40)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x10, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x14, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HEADSET_STEREO_SPEAKER_STEREO_RX_CAPLESS_48000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xac)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x4E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x04, 0xff, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x25, 0x0F, 0x0b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xff, 0x82)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x37, 0xe6, 0xa0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0x2b)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x23, 0x23)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x8A, 0x8A)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xa0)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x7530}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xf0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xff, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x98)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x88)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x78)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x68)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x58)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x38)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x28)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFF, 0xaC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0xaC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x7530}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+#endif /* __MARIMBA_PROFILE_H__ */
+
+
+
+
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/mi2s.h b/arch/arm/mach-msm/include/mach/qdsp5v2/mi2s.h
new file mode 100644
index 0000000..e304e25
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/mi2s.h
@@ -0,0 +1,50 @@
+/* Copyright (c) 2009, 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 _MACH_QDSP5_V2_MI2S_H
+#define _MACH_QDSP5_V2_MI2S_H
+
+#define WT_16_BIT 0
+#define WT_24_BIT 1
+#define WT_32_BIT 2
+#define WT_MAX 4
+
+enum mi2s_ret_enum_type {
+	MI2S_FALSE = 0,
+	MI2S_TRUE
+};
+
+#define MI2S_CHAN_MONO_RAW 0
+#define MI2S_CHAN_MONO_PACKED 1
+#define MI2S_CHAN_STEREO 2
+#define MI2S_CHAN_4CHANNELS 3
+#define MI2S_CHAN_6CHANNELS 4
+#define MI2S_CHAN_8CHANNELS 5
+#define MI2S_CHAN_MAX_OUTBOUND_CHANNELS MI2S__CHAN_8CHANNELS
+
+#define MI2S_SD_0    0x01
+#define MI2S_SD_1    0x02
+#define MI2S_SD_2    0x04
+#define MI2S_SD_3    0x08
+
+#define MI2S_SD_LINE_MASK    (MI2S_SD_0 | MI2S_SD_1 | MI2S_SD_2 |  MI2S_SD_3)
+
+bool mi2s_set_hdmi_output_path(uint8_t channels, uint8_t size,
+				uint8_t sd_line);
+
+bool mi2s_set_hdmi_input_path(uint8_t channels, uint8_t size, uint8_t sd_line);
+
+bool mi2s_set_codec_output_path(uint8_t channels, uint8_t size);
+
+bool mi2s_set_codec_input_path(uint8_t channels, uint8_t size);
+
+#endif /* #ifndef MI2S_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/mp3_funcs.h b/arch/arm/mach-msm/include/mach/qdsp5v2/mp3_funcs.h
new file mode 100644
index 0000000..ac06d3b
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/mp3_funcs.h
@@ -0,0 +1,20 @@
+/* Copyright (c) 2010, 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 MP3_FUNCS_H
+#define MP3_FUNCS_H
+
+/* Function Prototypes */
+long mp3_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+void audpp_cmd_cfg_mp3_params(struct audio *audio);
+
+#endif /* !MP3_FUNCS_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/msm_lpa.h b/arch/arm/mach-msm/include/mach/qdsp5v2/msm_lpa.h
new file mode 100644
index 0000000..0dced94
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/msm_lpa.h
@@ -0,0 +1,31 @@
+/* Copyright (c) 2009, 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 _MACH_QDSP5_V2_MSM_LPA_H
+#define _MACH_QDSP5_V2_MSM_LPA_H
+
+struct lpa_mem_config {
+	u32 llb_min_addr;
+	u32 llb_max_addr;
+	u32 sb_min_addr;
+	u32 sb_max_addr;
+};
+
+struct msm_lpa_platform_data {
+	u32 obuf_hlb_size;
+	u32 dsp_proc_id;
+	u32 app_proc_id;
+	struct lpa_mem_config nosb_config; /* no summing  */
+	struct lpa_mem_config sb_config; /* summing required */
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/pcm_funcs.h b/arch/arm/mach-msm/include/mach/qdsp5v2/pcm_funcs.h
new file mode 100644
index 0000000..fa65000
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/pcm_funcs.h
@@ -0,0 +1,19 @@
+/* Copyright (c) 2010, 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 PCM_FUNCS_H
+#define PCM_FUNCS_H
+
+long pcm_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+void audpp_cmd_cfg_pcm_params(struct audio *audio);
+
+#endif /* !PCM_FUNCS_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/qdsp5afecmdi.h b/arch/arm/mach-msm/include/mach/qdsp5v2/qdsp5afecmdi.h
new file mode 100644
index 0000000..25fe3a0
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/qdsp5afecmdi.h
@@ -0,0 +1,125 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __MACH_QDSP5_V2_QDSP5AFECMDI_H
+#define __MACH_QDSP5_V2_QDSP5AFECMDI_H
+
+#define QDSP5_DEVICE_mI2S_CODEC_RX 1     /* internal codec rx path  */
+#define QDSP5_DEVICE_mI2S_CODEC_TX 2     /* internal codec tx path  */
+#define QDSP5_DEVICE_AUX_CODEC_RX  3     /* external codec rx path  */
+#define QDSP5_DEVICE_AUX_CODEC_TX  4     /* external codec tx path  */
+#define QDSP5_DEVICE_mI2S_HDMI_RX  5     /* HDMI/FM block rx path   */
+#define QDSP5_DEVICE_mI2S_HDMI_TX  6     /* HDMI/FM block tx path   */
+#define QDSP5_DEVICE_ID_MAX        7
+
+#define AFE_CMD_CODEC_CONFIG_CMD     0x1
+#define AFE_CMD_CODEC_CONFIG_LEN sizeof(struct afe_cmd_codec_config)
+
+struct afe_cmd_codec_config{
+	uint16_t cmd_id;
+	uint16_t device_id;
+	uint16_t activity;
+	uint16_t sample_rate;
+	uint16_t channel_mode;
+	uint16_t volume;
+	uint16_t reserved;
+} __attribute__ ((packed));
+
+#define AFE_CMD_DEVICE_VOLUME_CTRL	0x2
+#define AFE_CMD_DEVICE_VOLUME_CTRL_LEN \
+		sizeof(struct afe_cmd_device_volume_ctrl)
+
+struct afe_cmd_device_volume_ctrl {
+	uint16_t cmd_id;
+	uint16_t device_id;
+	uint16_t device_volume;
+	uint16_t reserved;
+} __attribute__ ((packed));
+
+#define AFE_CMD_AUX_CODEC_CONFIG_CMD 	0x3
+#define AFE_CMD_AUX_CODEC_CONFIG_LEN sizeof(struct afe_cmd_aux_codec_config)
+
+struct afe_cmd_aux_codec_config{
+	uint16_t cmd_id;
+	uint16_t dma_path_ctl;
+	uint16_t pcm_ctl;
+	uint16_t eight_khz_int_mode;
+	uint16_t aux_codec_intf_ctl;
+	uint16_t data_format_padding_info;
+} __attribute__ ((packed));
+
+#define AFE_CMD_FM_RX_ROUTING_CMD	0x6
+#define AFE_CMD_FM_RX_ROUTING_LEN sizeof(struct afe_cmd_fm_codec_config)
+
+struct afe_cmd_fm_codec_config{
+	uint16_t cmd_id;
+	uint16_t enable;
+	uint16_t device_id;
+} __attribute__ ((packed));
+
+#define AFE_CMD_FM_PLAYBACK_VOLUME_CMD	0x8
+#define AFE_CMD_FM_PLAYBACK_VOLUME_LEN sizeof(struct afe_cmd_fm_volume_config)
+
+struct afe_cmd_fm_volume_config{
+	uint16_t cmd_id;
+	uint16_t volume;
+	uint16_t reserved;
+} __attribute__ ((packed));
+
+#define AFE_CMD_FM_CALIBRATION_GAIN_CMD	0x11
+#define AFE_CMD_FM_CALIBRATION_GAIN_LEN \
+	sizeof(struct afe_cmd_fm_calibgain_config)
+
+struct afe_cmd_fm_calibgain_config{
+	uint16_t cmd_id;
+	uint16_t device_id;
+	uint16_t calibration_gain;
+} __attribute__ ((packed));
+
+#define AFE_CMD_LOOPBACK	0xD
+#define AFE_CMD_EXT_LOOPBACK	0xE
+#define AFE_CMD_LOOPBACK_LEN sizeof(struct afe_cmd_loopback)
+#define AFE_LOOPBACK_ENABLE_COMMAND 0xFFFF
+#define AFE_LOOPBACK_DISABLE_COMMAND 0x0000
+
+struct afe_cmd_loopback {
+	uint16_t cmd_id;
+	uint16_t enable_flag;
+	uint16_t reserved[2];
+} __attribute__ ((packed));
+
+struct afe_cmd_ext_loopback {
+	uint16_t cmd_id;
+	uint16_t enable_flag;
+	uint16_t source_id;
+	uint16_t dst_id;
+	uint16_t reserved[2];
+} __packed;
+
+#define AFE_CMD_CFG_RMC_PARAMS 0x12
+#define AFE_CMD_CFG_RMC_LEN \
+	sizeof(struct afe_cmd_cfg_rmc)
+
+struct afe_cmd_cfg_rmc {
+	unsigned short cmd_id;
+	signed short   rmc_mode;
+	unsigned short rmc_ipw_length_ms;
+	unsigned short rmc_peak_length_ms;
+	unsigned short rmc_init_pulse_length_ms;
+	unsigned short rmc_total_int_length_ms;
+	unsigned short rmc_rampupdn_length_ms;
+	unsigned short rmc_delay_length_ms;
+	unsigned short rmc_detect_start_threshdb;
+	signed short   rmc_init_pulse_threshdb;
+}  __attribute__((packed));
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/qdsp5afemsg.h b/arch/arm/mach-msm/include/mach/qdsp5v2/qdsp5afemsg.h
new file mode 100644
index 0000000..16134e3
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/qdsp5afemsg.h
@@ -0,0 +1,31 @@
+/* Copyright (c) 2009, 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 __MACH_QDSP5_V2_QDSP5AFEMSG_H
+#define __MACH_QDSP5_V2_QDSP5AFEMSG_H
+
+#define AFE_APU_MSG_CODEC_CONFIG_ACK		0x0001
+#define AFE_APU_MSG_CODEC_CONFIG_ACK_LEN	\
+	sizeof(struct afe_msg_codec_config_ack)
+
+#define AFE_APU_MSG_VOC_TIMING_SUCCESS		0x0002
+
+#define AFE_MSG_CODEC_CONFIG_ENABLED 0x1
+#define AFE_MSG_CODEC_CONFIG_DISABLED 0xFFFF
+
+struct afe_msg_codec_config_ack {
+	uint16_t device_id;
+	uint16_t device_activity;
+	uint16_t reserved;
+} __attribute__((packed));
+
+#endif /* QDSP5AFEMSG_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/qdsp5audplaycmdi.h b/arch/arm/mach-msm/include/mach/qdsp5v2/qdsp5audplaycmdi.h
new file mode 100644
index 0000000..53128d3
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/qdsp5audplaycmdi.h
@@ -0,0 +1,145 @@
+#ifndef QDSP5AUDPLAYCMDI_H
+#define QDSP5AUDPLAYCMDI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+	Q D S P 5  A U D I O   P L A Y  T A S K   C O M M A N D S
+
+GENERAL DESCRIPTION
+   Command Interface for AUDPLAYTASK on QDSP5
+
+REFERENCES
+   None
+
+EXTERNALIZED FUNCTIONS
+
+  audplay_cmd_dec_data_avail
+  Send buffer to AUDPLAY task
+
+
+Copyright (c) 1992-2009, Code Aurora Forum. 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+
+#define AUDPLAY_CMD_BITSTREAM_DATA_AVAIL		0x0000
+#define AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_LEN	\
+	sizeof(struct audplay_cmd_bitstream_data_avail)
+
+/* Type specification of dec_data_avail message sent to AUDPLAYTASK
+*/
+struct audplay_cmd_bitstream_data_avail{
+	/*command ID*/
+	unsigned int cmd_id;
+
+	/* Decoder ID for which message is being sent */
+	unsigned int decoder_id;
+
+	/* Start address of data in ARM global memory */
+	unsigned int buf_ptr;
+
+	/* Number of 16-bit words of bit-stream data contiguously
+	* available at the above-mentioned address
+	*/
+	unsigned int buf_size;
+
+	/* Partition number used by audPlayTask to communicate with DSP's RTOS
+	* kernel
+	*/
+	unsigned int partition_number;
+
+} __attribute__((packed));
+
+#define AUDPLAY_CMD_CHANNEL_INFO 0x0001
+#define AUDPLAY_CMD_CHANNEL_INFO_LEN \
+  sizeof(struct audplay_cmd_channel_info)
+
+struct audplay_cmd_channel_select {
+  unsigned int cmd_id;
+  unsigned int stream_id;
+  unsigned int channel_select;
+} __attribute__((packed));
+
+struct audplay_cmd_threshold_update {
+  unsigned int cmd_id;
+  unsigned int threshold_update;
+  unsigned int threshold_value;
+} __attribute__((packed));
+
+union audplay_cmd_channel_info {
+  struct audplay_cmd_channel_select ch_select;
+  struct audplay_cmd_threshold_update thr_update;
+};
+
+#define AUDPLAY_CMD_HPCM_BUF_CFG 0x0003
+#define AUDPLAY_CMD_HPCM_BUF_CFG_LEN \
+  sizeof(struct audplay_cmd_hpcm_buf_cfg)
+
+struct audplay_cmd_hpcm_buf_cfg {
+	unsigned int cmd_id;
+	unsigned int hostpcm_config;
+	unsigned int feedback_frequency;
+	unsigned int byte_swap;
+	unsigned int max_buffers;
+	unsigned int partition_number;
+} __attribute__((packed));
+
+#define AUDPLAY_CMD_BUFFER_REFRESH 0x0004
+#define AUDPLAY_CMD_BUFFER_REFRESH_LEN \
+  sizeof(struct audplay_cmd_buffer_update)
+
+struct audplay_cmd_buffer_refresh {
+	unsigned int cmd_id;
+	unsigned int num_buffers;
+	unsigned int buf_read_count;
+	unsigned int buf0_address;
+	unsigned int buf0_length;
+	unsigned int buf1_address;
+	unsigned int buf1_length;
+} __attribute__((packed));
+
+#define AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_NT2            0x0005
+#define AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_NT2_LEN    \
+	sizeof(struct audplay_cmd_bitstream_data_avail_nt2)
+
+/* Type specification of dec_data_avail message sent to AUDPLAYTASK
+ * for NT2 */
+struct audplay_cmd_bitstream_data_avail_nt2 {
+	/*command ID*/
+	unsigned int cmd_id;
+
+	/* Decoder ID for which message is being sent */
+	unsigned int decoder_id;
+
+	/* Start address of data in ARM global memory */
+	unsigned int buf_ptr;
+
+	/* Number of 16-bit words of bit-stream data contiguously
+	*  available at the above-mentioned address
+	*/
+	unsigned int buf_size;
+
+	/* Partition number used by audPlayTask to communicate with DSP's RTOS
+	* kernel
+	*/
+	unsigned int partition_number;
+
+	/* bitstream write pointer */
+	unsigned int dspBitstreamWritePtr;
+
+} __attribute__((packed));
+
+#define AUDPLAY_CMD_OUTPORT_FLUSH 0x0006
+
+struct audplay_cmd_outport_flush {
+	unsigned int cmd_id;
+} __attribute__((packed));
+
+#endif /* QDSP5AUDPLAYCMD_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/qdsp5audplaymsg.h b/arch/arm/mach-msm/include/mach/qdsp5v2/qdsp5audplaymsg.h
new file mode 100644
index 0000000..2eeb557
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/qdsp5audplaymsg.h
@@ -0,0 +1,74 @@
+#ifndef QDSP5AUDPLAYMSG_H
+#define QDSP5AUDPLAYMSG_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+       Q D S P 5  A U D I O   P L A Y  T A S K   M S G
+
+GENERAL DESCRIPTION
+  Message sent by AUDPLAY task
+
+REFERENCES
+  None
+
+
+Copyright (c) 1992-2009, Code Aurora Forum. 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.
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+
+#define AUDPLAY_MSG_DEC_NEEDS_DATA		0x0001
+#define AUDPLAY_MSG_DEC_NEEDS_DATA_MSG_LEN	\
+	sizeof(audplay_msg_dec_needs_data)
+
+struct audplay_msg_dec_needs_data {
+	/* reserved*/
+	unsigned int dec_id;
+
+	/*The read pointer offset of external memory till which bitstream
+	has been dmed in*/
+	unsigned int adecDataReadPtrOffset;
+
+	/*The buffer size of external memory. */
+	unsigned int adecDataBufSize;
+
+	unsigned int 	bitstream_free_len;
+	unsigned int	bitstream_write_ptr;
+	unsigned int	bitstarem_buf_start;
+	unsigned int	bitstream_buf_len;
+} __attribute__((packed));
+
+#define AUDPLAY_UP_STREAM_INFO 0x0003
+#define AUDPLAY_UP_STREAM_INFO_LEN \
+	sizeof(struct audplay_msg_stream_info)
+
+struct audplay_msg_stream_info {
+	unsigned int decoder_id;
+	unsigned int channel_info;
+	unsigned int sample_freq;
+	unsigned int bitstream_info;
+	unsigned int bit_rate;
+} __attribute__((packed));
+
+#define AUDPLAY_MSG_BUFFER_UPDATE 0x0004
+#define AUDPLAY_MSG_BUFFER_UPDATE_LEN \
+	sizeof(struct audplay_msg_buffer_update)
+
+struct audplay_msg_buffer_update {
+	unsigned int buffer_write_count;
+	unsigned int num_of_buffer;
+	unsigned int buf0_address;
+	unsigned int buf0_length;
+	unsigned int buf1_address;
+	unsigned int buf1_length;
+} __attribute__((packed));
+
+#define AUDPLAY_UP_OUTPORT_FLUSH_ACK 0x0005
+
+#endif /* QDSP5AUDPLAYMSG_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/qdsp5audppcmdi.h b/arch/arm/mach-msm/include/mach/qdsp5v2/qdsp5audppcmdi.h
new file mode 100644
index 0000000..0416f52
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/qdsp5audppcmdi.h
@@ -0,0 +1,1088 @@
+#ifndef __MACH_QDSP5_V2_QDSP5AUDPPCMDI_H
+#define __MACH_QDSP5_V2_QDSP5AUDPPCMDI_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+    A U D I O   P O S T   P R O C E S S I N G  I N T E R N A L  C O M M A N D S
+
+GENERAL DESCRIPTION
+  This file contains defintions of format blocks of commands
+  that are accepted by AUDPP Task
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+
+Copyright(c) 1992-2011, Code Aurora Forum. 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+
+/*
+ * ARM to AUDPPTASK Commands
+ *
+ * ARM uses three command queues to communicate with AUDPPTASK
+ * 1)uPAudPPCmd1Queue : Used for more frequent and shorter length commands
+ * 	Location : MEMA
+ * 	Buffer Size : 6 words
+ * 	No of buffers in a queue : 20 for gaming audio and 5 for other images
+ * 2)uPAudPPCmd2Queue : Used for commands which are not much lengthier
+ * 	Location : MEMA
+ * 	Buffer Size : 23
+ * 	No of buffers in a queue : 2
+ * 3)uPAudOOCmd3Queue : Used for lengthier and more frequent commands
+ * 	Location : MEMA
+ * 	Buffer Size : 145
+ * 	No of buffers in a queue : 3
+ */
+
+/*
+ * Commands Related to uPAudPPCmd1Queue
+ */
+
+/*
+ * Command Structure to enable or disable the active decoders
+ */
+
+#define AUDPP_CMD_CFG_DEC_TYPE 		0x0001
+#define AUDPP_CMD_CFG_DEC_TYPE_LEN 	sizeof(struct audpp_cmd_cfg_dec_type)
+
+/* Enable the decoder */
+#define AUDPP_CMD_DEC_TYPE_M           	0x000F
+
+#define AUDPP_CMD_ENA_DEC_V         	0x4000
+#define AUDPP_CMD_DIS_DEC_V        	0x0000
+#define AUDPP_CMD_DEC_STATE_M          	0x4000
+
+#define AUDPP_CMD_UPDATDE_CFG_DEC	0x8000
+#define AUDPP_CMD_DONT_UPDATE_CFG_DEC	0x0000
+
+
+/* Type specification of cmd_cfg_dec */
+
+struct audpp_cmd_cfg_dec_type {
+	unsigned short cmd_id;
+	unsigned short stream_id;
+	unsigned short dec_cfg;
+	unsigned short dm_mode;
+} __attribute__((packed));
+
+/*
+ * Command Structure to Pause , Resume and flushes the selected audio decoders
+ */
+
+#define AUDPP_CMD_DEC_CTRL		0x0002
+#define AUDPP_CMD_DEC_CTRL_LEN		sizeof(struct audpp_cmd_dec_ctrl)
+
+/* Decoder control commands for pause, resume and flush */
+#define AUDPP_CMD_FLUSH_V         		0x2000
+
+#define AUDPP_CMD_PAUSE_V		        0x4000
+#define AUDPP_CMD_RESUME_V		        0x0000
+
+#define AUDPP_CMD_UPDATE_V		        0x8000
+#define AUDPP_CMD_IGNORE_V		        0x0000
+
+
+/* Type Spec for decoder control command*/
+
+struct audpp_cmd_dec_ctrl{
+	unsigned short cmd_id;
+	unsigned short stream_id;
+	unsigned short dec_ctrl;
+} __attribute__((packed));
+
+/*
+ * Command Structure to Configure the AVSync FeedBack Mechanism
+ */
+
+#define AUDPP_CMD_AVSYNC	0x0003
+#define AUDPP_CMD_AVSYNC_LEN	sizeof(struct audpp_cmd_avsync)
+
+struct audpp_cmd_avsync{
+	unsigned short cmd_id;
+	unsigned short stream_id;
+	unsigned short interrupt_interval;
+	unsigned short sample_counter_dlsw;
+	unsigned short sample_counter_dmsw;
+	unsigned short sample_counter_msw;
+	unsigned short byte_counter_dlsw;
+	unsigned short byte_counter_dmsw;
+	unsigned short byte_counter_msw;
+} __attribute__((packed));
+
+/*
+ * Macros used to store the AV Sync Info from DSP
+ */
+
+#define AUDPP_AVSYNC_CH_COUNT 1
+#define AUDPP_AVSYNC_NUM_WORDS 6
+/* Timeout of 3000ms for AV Sync Query response */
+#define AUDPP_AVSYNC_EVENT_TIMEOUT 3000
+
+/*
+ * Command Structure to Query AVSync Info from DSP
+ */
+
+#define AUDPP_CMD_QUERY_AVSYNC	0x0006
+
+struct audpp_cmd_query_avsync{
+	unsigned short cmd_id;
+	unsigned short stream_id;
+} __attribute__((packed));
+
+/*
+ * Command Structure to enable or disable(sleep) the AUDPPTASK
+ */
+
+#define AUDPP_CMD_CFG	0x0004
+#define AUDPP_CMD_CFG_LEN	sizeof(struct audpp_cmd_cfg)
+
+#define AUDPP_CMD_CFG_SLEEP   				0x0000
+#define AUDPP_CMD_CFG_ENABLE  				0xFFFF
+
+struct audpp_cmd_cfg {
+	unsigned short cmd_id;
+	unsigned short cfg;
+} __attribute__((packed));
+
+/*
+ * Command Structure to Inject or drop the specified no of samples
+ */
+
+#define AUDPP_CMD_ADJUST_SAMP		0x0005
+#define AUDPP_CMD_ADJUST_SAMP_LEN	sizeof(struct audpp_cmd_adjust_samp)
+
+#define AUDPP_CMD_SAMP_DROP		-1
+#define AUDPP_CMD_SAMP_INSERT		0x0001
+
+#define AUDPP_CMD_NUM_SAMPLES		0x0001
+
+struct audpp_cmd_adjust_samp {
+	unsigned short cmd_id;
+	unsigned short object_no;
+	signed short sample_insert_or_drop;
+	unsigned short num_samples;
+} __attribute__((packed));
+
+/*
+ * Command Structure to Configure AVSync Feedback Mechanism
+ */
+
+#define AUDPP_CMD_ROUTING_MODE      0x0007
+#define AUDPP_CMD_ROUTING_MODE_LEN  \
+sizeof(struct audpp_cmd_routing_mode)
+
+struct audpp_cmd_routing_mode {
+	unsigned short cmd_id;
+	unsigned short object_number;
+	unsigned short routing_mode;
+} __attribute__((packed));
+
+/*
+ * Commands Related to uPAudPPCmd2Queue
+ */
+
+/*
+ * Command Structure to configure Per decoder Parameters (Common)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS 		0x0000
+#define AUDPP_CMD_CFG_ADEC_PARAMS_COMMON_LEN	\
+	sizeof(struct audpp_cmd_cfg_adec_params_common)
+
+#define AUDPP_CMD_STATUS_MSG_FLAG_ENA_FCM	0x4000
+#define AUDPP_CMD_STATUS_MSG_FLAG_DIS_FCM	0x0000
+
+#define AUDPP_CMD_STATUS_MSG_FLAG_ENA_DCM	0x8000
+#define AUDPP_CMD_STATUS_MSG_FLAG_DIS_DCM	0x0000
+
+/* Sampling frequency*/
+#define  AUDPP_CMD_SAMP_RATE_96000 	0x0000
+#define  AUDPP_CMD_SAMP_RATE_88200 	0x0001
+#define  AUDPP_CMD_SAMP_RATE_64000 	0x0002
+#define  AUDPP_CMD_SAMP_RATE_48000 	0x0003
+#define  AUDPP_CMD_SAMP_RATE_44100 	0x0004
+#define  AUDPP_CMD_SAMP_RATE_32000 	0x0005
+#define  AUDPP_CMD_SAMP_RATE_24000 	0x0006
+#define  AUDPP_CMD_SAMP_RATE_22050 	0x0007
+#define  AUDPP_CMD_SAMP_RATE_16000 	0x0008
+#define  AUDPP_CMD_SAMP_RATE_12000 	0x0009
+#define  AUDPP_CMD_SAMP_RATE_11025 	0x000A
+#define  AUDPP_CMD_SAMP_RATE_8000  	0x000B
+
+
+/*
+ * Type specification of cmd_adec_cfg sent to all decoder
+ */
+
+struct audpp_cmd_cfg_adec_params_common {
+	unsigned short  cmd_id;
+	unsigned short  dec_id;
+	unsigned short  length;
+	unsigned short  reserved;
+	unsigned short  input_sampling_frequency;
+} __attribute__((packed));
+
+/*
+ * Command Structure to configure Per decoder Parameters (Wav)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_WAV_LEN \
+	sizeof(struct audpp_cmd_cfg_adec_params_wav)
+
+
+#define	AUDPP_CMD_WAV_STEREO_CFG_MONO	0x0001
+#define AUDPP_CMD_WAV_STEREO_CFG_STEREO	0x0002
+
+#define AUDPP_CMD_WAV_PCM_WIDTH_8	0x0000
+#define AUDPP_CMD_WAV_PCM_WIDTH_16	0x0001
+#define AUDPP_CMD_WAV_PCM_WIDTH_24	0x0002
+
+struct audpp_cmd_cfg_adec_params_wav {
+	struct audpp_cmd_cfg_adec_params_common		common;
+	unsigned short					stereo_cfg;
+	unsigned short					pcm_width;
+	unsigned short 					sign;
+} __attribute__((packed));
+
+/*
+ *  Command Structure for CMD_CFG_DEV_MIXER
+ */
+
+#define AUDPP_CMD_CFG_DEV_MIXER_PARAMS_LEN \
+	sizeof(struct audpp_cmd_cfg_dev_mixer_params)
+
+#define AUDPP_CMD_CFG_DEV_MIXER            0x0008
+
+#define AUDPP_CMD_CFG_DEV_MIXER_ID_0       0
+#define AUDPP_CMD_CFG_DEV_MIXER_ID_1       1
+#define AUDPP_CMD_CFG_DEV_MIXER_ID_2       2
+#define AUDPP_CMD_CFG_DEV_MIXER_ID_3       3
+#define AUDPP_CMD_CFG_DEV_MIXER_ID_4       4
+#define AUDPP_CMD_CFG_DEV_MIXER_ID_5       5
+
+#define AUDPP_CMD_CFG_DEV_MIXER_DEV_NONE   0x0000
+#define AUDPP_CMD_CFG_DEV_MIXER_DEV_0      \
+				(0x1 << AUDPP_CMD_CFG_DEV_MIXER_ID_0)
+#define AUDPP_CMD_CFG_DEV_MIXER_DEV_1      \
+				(0x1 << AUDPP_CMD_CFG_DEV_MIXER_ID_1)
+#define AUDPP_CMD_CFG_DEV_MIXER_DEV_2      \
+				(0x1 << AUDPP_CMD_CFG_DEV_MIXER_ID_2)
+#define AUDPP_CMD_CFG_DEV_MIXER_DEV_3      \
+				(0x1 << AUDPP_CMD_CFG_DEV_MIXER_ID_3)
+#define AUDPP_CMD_CFG_DEV_MIXER_DEV_4      \
+				(0x1 << AUDPP_CMD_CFG_DEV_MIXER_ID_4)
+#define AUDPP_CMD_CFG_DEV_MIXER_DEV_5      \
+				(0x1 << AUDPP_CMD_CFG_DEV_MIXER_ID_5)
+
+struct audpp_cmd_cfg_dev_mixer_params {
+	unsigned short cmd_id;
+	unsigned short stream_id;
+	unsigned short mixer_cmd;
+} __attribute__((packed));
+
+
+/*
+ * Command Structure to configure Per decoder Parameters (ADPCM)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_ADPCM_LEN \
+	sizeof(struct audpp_cmd_cfg_adec_params_adpcm)
+
+
+#define	AUDPP_CMD_ADPCM_STEREO_CFG_MONO		0x0001
+#define AUDPP_CMD_ADPCM_STEREO_CFG_STEREO	0x0002
+
+struct audpp_cmd_cfg_adec_params_adpcm {
+	struct audpp_cmd_cfg_adec_params_common		common;
+	unsigned short					stereo_cfg;
+	unsigned short 					block_size;
+} __attribute__((packed));
+
+/*
+ * Command Structure to configure Per decoder Parameters (WMA)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_WMA_LEN	\
+	sizeof(struct audpp_cmd_cfg_adec_params_wma)
+
+struct audpp_cmd_cfg_adec_params_wma {
+	struct audpp_cmd_cfg_adec_params_common    common;
+	unsigned short 	armdatareqthr;
+	unsigned short 	channelsdecoded;
+	unsigned short 	wmabytespersec;
+	unsigned short	wmasamplingfreq;
+	unsigned short	wmaencoderopts;
+} __attribute__((packed));
+
+
+/*
+ * Command Structure to configure Per decoder Parameters (MP3)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_MP3_LEN	\
+	sizeof(struct audpp_cmd_cfg_adec_params_mp3)
+
+struct audpp_cmd_cfg_adec_params_mp3 {
+	struct audpp_cmd_cfg_adec_params_common    common;
+} __attribute__((packed));
+
+
+/*
+ * Command Structure to configure Per decoder Parameters (AAC)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_AAC_LEN	\
+	sizeof(struct audpp_cmd_cfg_adec_params_aac)
+
+
+#define AUDPP_CMD_AAC_FORMAT_ADTS		-1
+#define	AUDPP_CMD_AAC_FORMAT_RAW		0x0000
+#define	AUDPP_CMD_AAC_FORMAT_PSUEDO_RAW		0x0001
+#define	AUDPP_CMD_AAC_FORMAT_LOAS		0x0002
+
+#define AUDPP_CMD_AAC_AUDIO_OBJECT_LC		0x0002
+#define AUDPP_CMD_AAC_AUDIO_OBJECT_LTP		0x0004
+#define AUDPP_CMD_AAC_AUDIO_OBJECT_ERLC	0x0011
+
+#define AUDPP_CMD_AAC_SBR_ON_FLAG_ON		0x0001
+#define AUDPP_CMD_AAC_SBR_ON_FLAG_OFF		0x0000
+
+#define AUDPP_CMD_AAC_SBR_PS_ON_FLAG_ON		0x0001
+#define AUDPP_CMD_AAC_SBR_PS_ON_FLAG_OFF	0x0000
+
+struct audpp_cmd_cfg_adec_params_aac {
+	struct audpp_cmd_cfg_adec_params_common	common;
+	signed short			format;
+	unsigned short			audio_object;
+	unsigned short			ep_config;
+	unsigned short                  aac_section_data_resilience_flag;
+	unsigned short                  aac_scalefactor_data_resilience_flag;
+	unsigned short                  aac_spectral_data_resilience_flag;
+	unsigned short                  sbr_on_flag;
+	unsigned short                  sbr_ps_on_flag;
+	unsigned short                  channel_configuration;
+} __attribute__((packed));
+
+/*
+ * Command Structure to configure Per decoder Parameters (V13K)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_V13K_LEN	\
+	sizeof(struct audpp_cmd_cfg_adec_params_v13k)
+
+
+#define AUDPP_CMD_STEREO_CFG_MONO		0x0001
+#define AUDPP_CMD_STEREO_CFG_STEREO		0x0002
+
+struct audpp_cmd_cfg_adec_params_v13k {
+	struct audpp_cmd_cfg_adec_params_common    	common;
+	unsigned short			stereo_cfg;
+} __attribute__((packed));
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_EVRC_LEN \
+	sizeof(struct audpp_cmd_cfg_adec_params_evrc)
+
+struct audpp_cmd_cfg_adec_params_evrc {
+	struct audpp_cmd_cfg_adec_params_common common;
+	unsigned short stereo_cfg;
+} __attribute__ ((packed));
+
+/*
+ * Command Structure to configure Per decoder Parameters (AMRWB)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_AMRWB_LEN \
+	sizeof(struct audpp_cmd_cfg_adec_params_amrwb)
+
+struct audpp_cmd_cfg_adec_params_amrwb {
+	struct audpp_cmd_cfg_adec_params_common    	common;
+	unsigned short			stereo_cfg;
+} __attribute__((packed));
+
+/*
+ * Command Structure to configure Per decoder Parameters (WMAPRO)
+ */
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_WMAPRO_LEN	\
+	sizeof(struct audpp_cmd_cfg_adec_params_wmapro)
+
+struct audpp_cmd_cfg_adec_params_wmapro {
+	struct audpp_cmd_cfg_adec_params_common    common;
+	unsigned short 	armdatareqthr;
+	uint8_t         validbitspersample;
+	uint8_t         numchannels;
+	unsigned short  formattag;
+	unsigned short  samplingrate;
+	unsigned short  avgbytespersecond;
+	unsigned short  asfpacketlength;
+	unsigned short 	channelmask;
+	unsigned short 	encodeopt;
+	unsigned short	advancedencodeopt;
+	uint32_t	advancedencodeopt2;
+} __attribute__((packed));
+
+/*
+ * Command Structure to configure the  HOST PCM interface
+ */
+
+#define AUDPP_CMD_PCM_INTF	0x0001
+#define AUDPP_CMD_PCM_INTF_2	0x0002
+#define AUDPP_CMD_PCM_INTF_LEN	sizeof(struct audpp_cmd_pcm_intf)
+
+#define AUDPP_CMD_PCM_INTF_MONO_V		        0x0001
+#define AUDPP_CMD_PCM_INTF_STEREO_V         	0x0002
+
+/* These two values differentiate the two types of commands that could be issued
+ * Interface configuration command and Buffer update command */
+
+#define AUDPP_CMD_PCM_INTF_CONFIG_CMD_V	       	0x0000
+#define AUDPP_CMD_PCM_INTF_BUFFER_CMD_V	        -1
+
+#define AUDPP_CMD_PCM_INTF_RX_ENA_M              0x000F
+#define AUDPP_CMD_PCM_INTF_RX_ENA_ARMTODSP_V     0x0008
+#define AUDPP_CMD_PCM_INTF_RX_ENA_DSPTOARM_V     0x0004
+
+/* These flags control the enabling and disabling of the interface together
+ *  with host interface bit mask. */
+
+#define AUDPP_CMD_PCM_INTF_ENA_V            -1
+#define AUDPP_CMD_PCM_INTF_DIS_V            0x0000
+
+
+#define  AUDPP_CMD_PCM_INTF_FULL_DUPLEX           0x0
+#define  AUDPP_CMD_PCM_INTF_HALF_DUPLEX_TODSP     0x1
+
+
+#define  AUDPP_CMD_PCM_INTF_OBJECT_NUM           0x5
+#define  AUDPP_CMD_PCM_INTF_COMMON_OBJECT_NUM    0x6
+
+struct audpp_cmd_pcm_intf {
+	unsigned short  cmd_id;
+	unsigned short  stream;
+	unsigned short  stream_id;
+	signed short  config;
+	unsigned short  intf_type;
+
+	/* DSP -> ARM Configuration */
+	unsigned short  read_buf1LSW;
+	unsigned short  read_buf1MSW;
+	unsigned short  read_buf1_len;
+
+	unsigned short  read_buf2LSW;
+	unsigned short  read_buf2MSW;
+	unsigned short  read_buf2_len;
+	/*   0:HOST_PCM_INTF disable
+	**  0xFFFF: HOST_PCM_INTF enable
+	*/
+	signed short  dsp_to_arm_flag;
+	unsigned short  partition_number;
+
+	/* ARM -> DSP Configuration */
+	unsigned short  write_buf1LSW;
+	unsigned short  write_buf1MSW;
+	unsigned short  write_buf1_len;
+
+	unsigned short  write_buf2LSW;
+	unsigned short  write_buf2MSW;
+	unsigned short  write_buf2_len;
+
+	/*   0:HOST_PCM_INTF disable
+	**  0xFFFF: HOST_PCM_INTF enable
+	*/
+	signed short  arm_to_rx_flag;
+	unsigned short  weight_decoder_to_rx;
+	unsigned short  weight_arm_to_rx;
+
+	unsigned short  partition_number_arm_to_dsp;
+	unsigned short  sample_rate;
+	unsigned short  channel_mode;
+} __attribute__((packed));
+
+/*
+ **  BUFFER UPDATE COMMAND
+ */
+#define AUDPP_CMD_PCM_INTF_SEND_BUF_PARAMS_LEN	\
+	sizeof(struct audpp_cmd_pcm_intf_send_buffer)
+
+struct audpp_cmd_pcm_intf_send_buffer {
+	unsigned short  cmd_id;
+	unsigned short  stream;
+	unsigned short  stream_id;
+	/* set config = 0xFFFF for configuration*/
+	signed short  config;
+	unsigned short  intf_type;
+	unsigned short  dsp_to_arm_buf_id;
+	unsigned short  arm_to_dsp_buf_id;
+	unsigned short  arm_to_dsp_buf_len;
+} __attribute__((packed));
+
+
+/*
+ * Commands Related to uPAudPPCmd3Queue
+ */
+
+/*
+ * Command Structure to configure post processing params (Commmon)
+ */
+
+#define AUDPP_CMD_CFG_OBJECT_PARAMS		0x0000
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN		\
+	sizeof(struct audpp_cmd_cfg_object_params_common)
+
+#define AUDPP_CMD_OBJ0_UPDATE		0x8000
+#define AUDPP_CMD_OBJ0_DONT_UPDATE	0x0000
+
+
+#define AUDPP_CMD_OBJ2_UPDATE		0x8000
+#define AUDPP_CMD_OBJ2_DONT_UPDATE	0x0000
+
+#define AUDPP_CMD_OBJ3_UPDATE		0x8000
+#define AUDPP_CMD_OBJ3_DONT_UPDATE	0x0000
+
+#define AUDPP_CMD_OBJ4_UPDATE		0x8000
+#define AUDPP_CMD_OBJ4_DONT_UPDATE	0x0000
+
+#define AUDPP_CMD_HPCM_UPDATE		0x8000
+#define AUDPP_CMD_HPCM_DONT_UPDATE	0x0000
+
+#define AUDPP_CMD_COMMON_CFG_UPDATE		0x8000
+#define AUDPP_CMD_COMMON_CFG_DONT_UPDATE	0x0000
+
+#define AUDPP_CMD_POPP_STREAM   0xFFFF
+#define AUDPP_CMD_COPP_STREAM   0x0000
+
+struct audpp_cmd_cfg_object_params_common{
+	unsigned short  cmd_id;
+	unsigned short	stream;
+	unsigned short	stream_id;
+	unsigned short	obj_cfg;
+	unsigned short	command_type;
+} __attribute__((packed));
+
+/*
+ * Command Structure to configure post processing params (Volume)
+ */
+#define AUDPP_CMD_VOLUME_PAN		0
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_VOLUME_LEN		\
+	sizeof(struct audpp_cmd_cfg_object_params_volume)
+
+struct audpp_cmd_cfg_object_params_volume {
+	struct audpp_cmd_cfg_object_params_common 	common;
+	unsigned short					volume;
+	unsigned short					pan;
+} __attribute__((packed));
+
+/*
+ * Command Structure to configure post processing params (PCM Filter)
+ */
+
+struct numerator {
+	unsigned short			numerator_b0_filter_lsw;
+	unsigned short			numerator_b0_filter_msw;
+	unsigned short			numerator_b1_filter_lsw;
+	unsigned short			numerator_b1_filter_msw;
+	unsigned short			numerator_b2_filter_lsw;
+	unsigned short			numerator_b2_filter_msw;
+} __attribute__((packed));
+
+struct denominator {
+	unsigned short			denominator_a0_filter_lsw;
+	unsigned short			denominator_a0_filter_msw;
+	unsigned short			denominator_a1_filter_lsw;
+	unsigned short			denominator_a1_filter_msw;
+} __attribute__((packed));
+
+struct shift_factor {
+	unsigned short			shift_factor_0;
+} __attribute__((packed));
+
+struct pan {
+	unsigned short			pan_filter_0;
+} __attribute__((packed));
+
+struct filter_1 {
+	struct numerator		numerator_filter;
+	struct denominator		denominator_filter;
+	struct shift_factor		shift_factor_filter;
+	struct pan			pan_filter;
+} __attribute__((packed));
+
+struct filter_2 {
+	struct numerator		numerator_filter[2];
+	struct denominator		denominator_filter[2];
+	struct shift_factor		shift_factor_filter[2];
+	struct pan			pan_filter[2];
+} __attribute__((packed));
+
+struct filter_3 {
+	struct numerator		numerator_filter[3];
+	struct denominator		denominator_filter[3];
+	struct shift_factor		shift_factor_filter[3];
+	struct pan			pan_filter[3];
+} __attribute__((packed));
+
+struct filter_4 {
+	struct numerator		numerator_filter[4];
+	struct denominator		denominator_filter[4];
+	struct shift_factor		shift_factor_filter[4];
+	struct pan			pan_filter[4];
+} __attribute__((packed));
+
+#define AUDPP_CMD_IIR_TUNING_FILTER	1
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_PCM_LEN		\
+	sizeof(struct audpp_cmd_cfg_object_params_pcm)
+
+
+struct audpp_cmd_cfg_object_params_pcm {
+	struct audpp_cmd_cfg_object_params_common 	common;
+	signed short				active_flag;
+	unsigned short 				num_bands;
+	union {
+		struct filter_1			filter_1_params;
+		struct filter_2			filter_2_params;
+		struct filter_3			filter_3_params;
+		struct filter_4			filter_4_params;
+	} __attribute__((packed)) params_filter;
+} __attribute__((packed));
+
+#define AUDPP_CMD_CALIB_GAIN_RX         15
+#define AUDPP_CMD_CFG_CAL_GAIN_LEN sizeof(struct audpp_cmd_cfg_cal_gain)
+
+
+struct audpp_cmd_cfg_cal_gain {
+	struct audpp_cmd_cfg_object_params_common common;
+	unsigned short audppcalgain;
+	unsigned short reserved;
+} __attribute__((packed));
+
+
+/*
+ * Command Structure to configure post processing parameters (equalizer)
+ */
+#define AUDPP_CMD_EQUALIZER		2
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_EQALIZER_LEN		\
+	sizeof(struct audpp_cmd_cfg_object_params_eqalizer)
+
+struct eq_numerator {
+	unsigned short			numerator_coeff_0_lsw;
+	unsigned short			numerator_coeff_0_msw;
+	unsigned short			numerator_coeff_1_lsw;
+	unsigned short			numerator_coeff_1_msw;
+	unsigned short			numerator_coeff_2_lsw;
+	unsigned short			numerator_coeff_2_msw;
+} __attribute__((packed));
+
+struct eq_denominator {
+	unsigned short			denominator_coeff_0_lsw;
+	unsigned short			denominator_coeff_0_msw;
+	unsigned short			denominator_coeff_1_lsw;
+	unsigned short			denominator_coeff_1_msw;
+} __attribute__((packed));
+
+struct eq_shiftfactor {
+	unsigned short			shift_factor;
+} __attribute__((packed));
+
+struct eq_coeff_1 {
+	struct eq_numerator	numerator;
+	struct eq_denominator	denominator;
+	struct eq_shiftfactor	shiftfactor;
+} __attribute__((packed));
+
+struct eq_coeff_2 {
+	struct eq_numerator	numerator[2];
+	struct eq_denominator	denominator[2];
+	struct eq_shiftfactor	shiftfactor[2];
+} __attribute__((packed));
+
+struct eq_coeff_3 {
+	struct eq_numerator	numerator[3];
+	struct eq_denominator	denominator[3];
+	struct eq_shiftfactor	shiftfactor[3];
+} __attribute__((packed));
+
+struct eq_coeff_4 {
+	struct eq_numerator	numerator[4];
+	struct eq_denominator	denominator[4];
+	struct eq_shiftfactor	shiftfactor[4];
+} __attribute__((packed));
+
+struct eq_coeff_5 {
+	struct eq_numerator	numerator[5];
+	struct eq_denominator	denominator[5];
+	struct eq_shiftfactor	shiftfactor[5];
+} __attribute__((packed));
+
+struct eq_coeff_6 {
+	struct eq_numerator	numerator[6];
+	struct eq_denominator	denominator[6];
+	struct eq_shiftfactor	shiftfactor[6];
+} __attribute__((packed));
+
+struct eq_coeff_7 {
+	struct eq_numerator	numerator[7];
+	struct eq_denominator	denominator[7];
+	struct eq_shiftfactor	shiftfactor[7];
+} __attribute__((packed));
+
+struct eq_coeff_8 {
+	struct eq_numerator	numerator[8];
+	struct eq_denominator	denominator[8];
+	struct eq_shiftfactor	shiftfactor[8];
+} __attribute__((packed));
+
+struct eq_coeff_9 {
+	struct eq_numerator	numerator[9];
+	struct eq_denominator	denominator[9];
+	struct eq_shiftfactor	shiftfactor[9];
+} __attribute__((packed));
+
+struct eq_coeff_10 {
+	struct eq_numerator	numerator[10];
+	struct eq_denominator	denominator[10];
+	struct eq_shiftfactor	shiftfactor[10];
+} __attribute__((packed));
+
+struct eq_coeff_11 {
+	struct eq_numerator	numerator[11];
+	struct eq_denominator	denominator[11];
+	struct eq_shiftfactor	shiftfactor[11];
+} __attribute__((packed));
+
+struct eq_coeff_12 {
+	struct eq_numerator	numerator[12];
+	struct eq_denominator	denominator[12];
+	struct eq_shiftfactor	shiftfactor[12];
+} __attribute__((packed));
+
+
+struct audpp_cmd_cfg_object_params_eqalizer {
+	struct audpp_cmd_cfg_object_params_common 	common;
+	signed short				eq_flag;
+	unsigned short				num_bands;
+	union {
+		struct eq_coeff_1	eq_coeffs_1;
+		struct eq_coeff_2	eq_coeffs_2;
+		struct eq_coeff_3	eq_coeffs_3;
+		struct eq_coeff_4	eq_coeffs_4;
+		struct eq_coeff_5	eq_coeffs_5;
+		struct eq_coeff_6	eq_coeffs_6;
+		struct eq_coeff_7	eq_coeffs_7;
+		struct eq_coeff_8	eq_coeffs_8;
+		struct eq_coeff_9	eq_coeffs_9;
+		struct eq_coeff_10	eq_coeffs_10;
+		struct eq_coeff_11	eq_coeffs_11;
+		struct eq_coeff_12	eq_coeffs_12;
+	} __attribute__((packed)) eq_coeff;
+} __attribute__((packed));
+
+/*
+ * Command Structure to configure post processing parameters (ADRC)
+ */
+#define AUDPP_CMD_ADRC			3
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_ADRC_LEN		\
+	sizeof(struct audpp_cmd_cfg_object_params_adrc)
+
+
+#define AUDPP_CMD_ADRC_FLAG_DIS		0x0000
+#define AUDPP_CMD_ADRC_FLAG_ENA		-1
+#define AUDPP_CMD_PBE_FLAG_DIS		0x0000
+#define AUDPP_CMD_PBE_FLAG_ENA		-1
+
+struct audpp_cmd_cfg_object_params_adrc {
+	struct audpp_cmd_cfg_object_params_common 	common;
+	signed short		adrc_flag;
+	unsigned short	compression_th;
+	unsigned short	compression_slope;
+	unsigned short	rms_time;
+	unsigned short	attack_const_lsw;
+	unsigned short	attack_const_msw;
+	unsigned short	release_const_lsw;
+	unsigned short	release_const_msw;
+	unsigned short	adrc_delay;
+};
+
+/*
+ * Command Structure to configure post processing parameters (MB - ADRC)
+ */
+#define AUDPP_CMD_MBADRC		10
+#define	AUDPP_MAX_MBADRC_BANDS		5
+
+struct adrc_config {
+	uint16_t subband_enable;
+	uint16_t adrc_sub_mute;
+	uint16_t rms_time;
+	uint16_t compression_th;
+	uint16_t compression_slope;
+	uint16_t attack_const_lsw;
+	uint16_t attack_const_msw;
+	uint16_t release_const_lsw;
+	uint16_t release_const_msw;
+	uint16_t makeup_gain;
+};
+
+struct audpp_cmd_cfg_object_params_mbadrc {
+	struct audpp_cmd_cfg_object_params_common 	common;
+	uint16_t enable;
+	uint16_t num_bands;
+	uint16_t down_samp_level;
+	uint16_t adrc_delay;
+	uint16_t ext_buf_size;
+	uint16_t ext_partition;
+	uint16_t ext_buf_msw;
+	uint16_t ext_buf_lsw;
+	struct adrc_config adrc_band[AUDPP_MAX_MBADRC_BANDS];
+} __attribute__((packed));
+
+/*
+ * Command Structure to configure post processing parameters(Spectrum Analizer)
+ */
+#define AUDPP_CMD_SPECTROGRAM		4
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_SPECTRAM_LEN		\
+	sizeof(struct audpp_cmd_cfg_object_params_spectram)
+
+
+struct audpp_cmd_cfg_object_params_spectram {
+	struct audpp_cmd_cfg_object_params_common 	common;
+	unsigned short				sample_interval;
+	unsigned short				num_coeff;
+} __attribute__((packed));
+
+/*
+ * Command Structure to configure post processing parameters (QConcert)
+ */
+#define AUDPP_CMD_QCONCERT		5
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_QCONCERT_LEN		\
+	sizeof(struct audpp_cmd_cfg_object_params_qconcert)
+
+
+#define AUDPP_CMD_QCON_ENA_FLAG_ENA		-1
+#define AUDPP_CMD_QCON_ENA_FLAG_DIS		0x0000
+
+#define AUDPP_CMD_QCON_OP_MODE_HEADPHONE	-1
+#define AUDPP_CMD_QCON_OP_MODE_SPEAKER_FRONT	0x0000
+#define AUDPP_CMD_QCON_OP_MODE_SPEAKER_SIDE	0x0001
+#define AUDPP_CMD_QCON_OP_MODE_SPEAKER_DESKTOP	0x0002
+
+#define AUDPP_CMD_QCON_GAIN_UNIT			0x7FFF
+#define AUDPP_CMD_QCON_GAIN_SIX_DB			0x4027
+
+
+#define AUDPP_CMD_QCON_EXPANSION_MAX		0x7FFF
+
+
+struct audpp_cmd_cfg_object_params_qconcert {
+	struct audpp_cmd_cfg_object_params_common 	common;
+	signed short				enable_flag;
+	signed short				op_mode;
+	signed short				gain;
+	signed short				expansion;
+	signed short				delay;
+	unsigned short				stages_per_mode;
+	unsigned short				reverb_enable;
+	unsigned short				decay_msw;
+	unsigned short				decay_lsw;
+	unsigned short				decay_time_ratio_msw;
+	unsigned short				decay_time_ratio_lsw;
+	unsigned short				reflection_delay_time;
+	unsigned short				late_reverb_gain;
+	unsigned short				late_reverb_delay;
+	unsigned short                          delay_buff_size_msw;
+	unsigned short                          delay_buff_size_lsw;
+	unsigned short                          partition_num;
+	unsigned short                          delay_buff_start_msw;
+	unsigned short                          delay_buff_start_lsw;
+} __attribute__((packed));
+
+/*
+ * Command Structure to configure post processing parameters (Side Chain)
+ */
+#define AUDPP_CMD_SIDECHAIN_TUNING_FILTER	6
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_SIDECHAIN_LEN		\
+	sizeof(struct audpp_cmd_cfg_object_params_sidechain)
+
+
+#define AUDPP_CMD_SIDECHAIN_ACTIVE_FLAG_DIS	0x0000
+#define AUDPP_CMD_SIDECHAIN_ACTIVE_FLAG_ENA	-1
+
+struct audpp_cmd_cfg_object_params_sidechain {
+	struct audpp_cmd_cfg_object_params_common 	common;
+	signed short				active_flag;
+	unsigned short				num_bands;
+	union {
+		struct filter_1			filter_1_params;
+		struct filter_2			filter_2_params;
+		struct filter_3			filter_3_params;
+		struct filter_4			filter_4_params;
+	} __attribute__((packed)) params_filter;
+} __attribute__((packed));
+
+
+/*
+ * Command Structure to configure post processing parameters (QAFX)
+ */
+#define AUDPP_CMD_QAFX			8
+#define AUDPP_CMD_CFG_OBJECT_PARAMS_QAFX_LEN		\
+	sizeof(struct audpp_cmd_cfg_object_params_qafx)
+
+#define AUDPP_CMD_QAFX_ENA_DISA		0x0000
+#define AUDPP_CMD_QAFX_ENA_ENA_CFG	-1
+#define AUDPP_CMD_QAFX_ENA_DIS_CFG	0x0001
+
+#define AUDPP_CMD_QAFX_CMD_TYPE_ENV	0x0100
+#define AUDPP_CMD_QAFX_CMD_TYPE_OBJ	0x0010
+#define AUDPP_CMD_QAFX_CMD_TYPE_QUERY	0x1000
+
+#define AUDPP_CMD_QAFX_CMDS_ENV_OP_MODE	0x0100
+#define AUDPP_CMD_QAFX_CMDS_ENV_LIS_POS	0x0101
+#define AUDPP_CMD_QAFX_CMDS_ENV_LIS_ORI	0x0102
+#define AUDPP_CMD_QAFX_CMDS_ENV_LIS_VEL	0X0103
+#define AUDPP_CMD_QAFX_CMDS_ENV_ENV_RES	0x0107
+
+#define AUDPP_CMD_QAFX_CMDS_OBJ_SAMP_FREQ	0x0010
+#define AUDPP_CMD_QAFX_CMDS_OBJ_VOL		0x0011
+#define AUDPP_CMD_QAFX_CMDS_OBJ_DIST		0x0012
+#define AUDPP_CMD_QAFX_CMDS_OBJ_POS		0x0013
+#define AUDPP_CMD_QAFX_CMDS_OBJ_VEL		0x0014
+
+
+struct audpp_cmd_cfg_object_params_qafx {
+	struct audpp_cmd_cfg_object_params_common 	common;
+	signed short				enable;
+	unsigned short				command_type;
+	unsigned short				num_commands;
+	unsigned short				commands;
+} __attribute__((packed));
+
+/*
+ * Command Structure to enable , disable or configure the reverberation effect
+ * (REVERB) (Common)
+ */
+
+#define AUDPP_CMD_REVERB_CONFIG		0x0001
+#define	AUDPP_CMD_REVERB_CONFIG_COMMON_LEN	\
+	sizeof(struct audpp_cmd_reverb_config_common)
+
+#define AUDPP_CMD_ENA_ENA	0xFFFF
+#define AUDPP_CMD_ENA_DIS	0x0000
+#define AUDPP_CMD_ENA_CFG	0x0001
+
+#define AUDPP_CMD_CMD_TYPE_ENV		0x0104
+#define AUDPP_CMD_CMD_TYPE_OBJ		0x0015
+#define AUDPP_CMD_CMD_TYPE_QUERY	0x1000
+
+
+struct audpp_cmd_reverb_config_common {
+	unsigned short			cmd_id;
+	unsigned short			enable;
+	unsigned short			cmd_type;
+} __attribute__((packed));
+
+/*
+ * Command Structure to enable , disable or configure the reverberation effect
+ * (ENV-0x0104)
+ */
+
+#define	AUDPP_CMD_REVERB_CONFIG_ENV_104_LEN	\
+	sizeof(struct audpp_cmd_reverb_config_env_104)
+
+struct audpp_cmd_reverb_config_env_104 {
+	struct audpp_cmd_reverb_config_common	common;
+	unsigned short			env_gain;
+	unsigned short			decay_msw;
+	unsigned short			decay_lsw;
+	unsigned short			decay_timeratio_msw;
+	unsigned short			decay_timeratio_lsw;
+	unsigned short			delay_time;
+	unsigned short			reverb_gain;
+	unsigned short			reverb_delay;
+} __attribute__((packed));
+
+/*
+ * Command Structure to enable , disable or configure the reverberation effect
+ * (ENV-0x0015)
+ */
+
+#define	AUDPP_CMD_REVERB_CONFIG_ENV_15_LEN	\
+	sizeof(struct audpp_cmd_reverb_config_env_15)
+
+struct audpp_cmd_reverb_config_env_15 {
+	struct audpp_cmd_reverb_config_common	common;
+	unsigned short			object_num;
+	unsigned short			absolute_gain;
+} __attribute__((packed));
+
+#define AUDPP_CMD_PBE                   16
+#define AUDPP_CMD_CFG_PBE_LEN sizeof(struct audpp_cmd_cfg_pbe)
+
+struct audpp_cmd_cfg_pbe {
+	struct audpp_cmd_cfg_object_params_common       common;
+	unsigned short pbe_enable;
+	signed short   realbassmix;
+	signed short   basscolorcontrol;
+	unsigned short mainchaindelay;
+	unsigned short xoverfltorder;
+	unsigned short bandpassfltorder;
+	signed short   adrcdelay;
+	unsigned short downsamplelevel;
+	unsigned short comprmstav;
+	signed short   expthreshold;
+	unsigned short expslope;
+	unsigned short compthreshold;
+	unsigned short compslope;
+	unsigned short cpmpattack_lsw;
+	unsigned short compattack_msw;
+	unsigned short comprelease_lsw;
+	unsigned short comprelease_msw;
+	unsigned short compmakeupgain;
+	signed short   baselimthreshold;
+	signed short   highlimthreshold;
+	signed short   basslimmakeupgain;
+	signed short   highlimmakeupgain;
+	signed short   limbassgrc;
+	signed short   limhighgrc;
+	signed short   limdelay;
+	unsigned short filter_coeffs[90];
+	unsigned short extbuffsize_lsw;
+	unsigned short extbuffsize_msw;
+	unsigned short extpartition;
+	unsigned short extbuffstart_lsw;
+	unsigned short extbuffstart_msw;
+} __attribute__((packed));
+
+#define AUDPP_CMD_PP_FEAT_QUERY_PARAMS  0x0002
+
+struct audpp_cmd_cfg_object_params_volpan {
+	struct audpp_cmd_cfg_object_params_common       common;
+	u16 volume ;
+	u16 pan;
+};
+
+struct rtc_audpp_read_data {
+	unsigned short  cmd_id;
+	unsigned short  obj_id;
+	unsigned short  route_id;
+	unsigned short  feature_id;
+	unsigned short  extbufsizemsw;
+	unsigned short  extbufsizelsw;
+	unsigned short	extpart;
+	unsigned short	extbufstartmsw;
+	unsigned short	extbufstartlsw;
+} __attribute__((packed)) ;
+
+#define AUDPP_CMD_SAMPLING_FREQUENCY	7
+#define AUDPP_CMD_QRUMBLE		9
+
+#endif /* __MACH_QDSP5_V2_QDSP5AUDPPCMDI_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/qdsp5audppmsg.h b/arch/arm/mach-msm/include/mach/qdsp5v2/qdsp5audppmsg.h
new file mode 100644
index 0000000..b27bd83
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/qdsp5audppmsg.h
@@ -0,0 +1,311 @@
+#ifndef QDSP5AUDPPMSG_H
+#define QDSP5AUDPPMSG_H
+
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+       Q D S P 5  A U D I O   P O S T   P R O C E S S I N G   M S G
+
+GENERAL DESCRIPTION
+  Messages sent by AUDPPTASK to ARM
+
+REFERENCES
+  None
+
+EXTERNALIZED FUNCTIONS
+  None
+
+Copyright (c) 1992-2009, Code Aurora Forum. 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.
+
+*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
+
+/*
+ * AUDPPTASK uses audPPuPRlist to send messages to the ARM
+ * Location : MEMA
+ * Buffer Size : 45
+ * No of Buffers in a queue : 5 for gaming audio and 1 for other images
+ */
+
+/*
+ * MSG to Informs the ARM os Success/Failure of bringing up the decoder
+ */
+
+#define AUDPP_MSG_FEAT_QUERY_DM_DONE 0x000b
+
+#define AUDPP_MSG_STATUS_MSG		0x0001
+#define AUDPP_MSG_STATUS_MSG_LEN	\
+	sizeof(struct audpp_msg_status_msg)
+
+#define AUDPP_MSG_STATUS_SLEEP		0x0000
+#define AUDPP_MSG_STATUS_INIT		0x0001
+#define AUDPP_MSG_STATUS_CFG		0x0002
+#define AUDPP_MSG_STATUS_PLAY		0x0003
+
+#define AUDPP_MSG_REASON_NONE	0x0000
+#define AUDPP_MSG_REASON_MEM	0x0001
+#define AUDPP_MSG_REASON_NODECODER 0x0002
+
+struct audpp_msg_status_msg {
+	unsigned short dec_id;
+	unsigned short status;
+	unsigned short reason;
+} __attribute__((packed));
+
+/*
+ * MSG to communicate the spectrum analyzer output bands to the ARM
+ */
+#define AUDPP_MSG_SPA_BANDS		0x0002
+#define AUDPP_MSG_SPA_BANDS_LEN	\
+	sizeof(struct audpp_msg_spa_bands)
+
+struct audpp_msg_spa_bands {
+	unsigned short			current_object;
+	unsigned short			spa_band_1;
+	unsigned short			spa_band_2;
+	unsigned short			spa_band_3;
+	unsigned short			spa_band_4;
+	unsigned short			spa_band_5;
+	unsigned short			spa_band_6;
+	unsigned short			spa_band_7;
+	unsigned short			spa_band_8;
+	unsigned short			spa_band_9;
+	unsigned short			spa_band_10;
+	unsigned short			spa_band_11;
+	unsigned short			spa_band_12;
+	unsigned short			spa_band_13;
+	unsigned short			spa_band_14;
+	unsigned short			spa_band_15;
+	unsigned short			spa_band_16;
+	unsigned short			spa_band_17;
+	unsigned short			spa_band_18;
+	unsigned short			spa_band_19;
+	unsigned short			spa_band_20;
+	unsigned short			spa_band_21;
+	unsigned short			spa_band_22;
+	unsigned short			spa_band_23;
+	unsigned short			spa_band_24;
+	unsigned short			spa_band_25;
+	unsigned short			spa_band_26;
+	unsigned short			spa_band_27;
+	unsigned short			spa_band_28;
+	unsigned short			spa_band_29;
+	unsigned short			spa_band_30;
+	unsigned short			spa_band_31;
+	unsigned short			spa_band_32;
+} __attribute__((packed));
+
+/*
+ * MSG to communicate the PCM I/O buffer status to ARM
+ */
+#define  AUDPP_MSG_HOST_PCM_INTF_MSG		0x0003
+#define  AUDPP_MSG_HOST_PCM_INTF_MSG_LEN	\
+	sizeof(struct audpp_msg_host_pcm_intf_msg)
+
+#define AUDPP_MSG_HOSTPCM_ID_TX_ARM	0x0000
+#define AUDPP_MSG_HOSTPCM_ID_ARM_TX	0x0001
+#define AUDPP_MSG_HOSTPCM_ID_RX_ARM	0x0002
+#define AUDPP_MSG_HOSTPCM_ID_ARM_RX	0x0003
+
+#define AUDPP_MSG_SAMP_FREQ_INDX_96000	0x0000
+#define AUDPP_MSG_SAMP_FREQ_INDX_88200	0x0001
+#define AUDPP_MSG_SAMP_FREQ_INDX_64000	0x0002
+#define AUDPP_MSG_SAMP_FREQ_INDX_48000	0x0003
+#define AUDPP_MSG_SAMP_FREQ_INDX_44100	0x0004
+#define AUDPP_MSG_SAMP_FREQ_INDX_32000	0x0005
+#define AUDPP_MSG_SAMP_FREQ_INDX_24000	0x0006
+#define AUDPP_MSG_SAMP_FREQ_INDX_22050	0x0007
+#define AUDPP_MSG_SAMP_FREQ_INDX_16000	0x0008
+#define AUDPP_MSG_SAMP_FREQ_INDX_12000	0x0009
+#define AUDPP_MSG_SAMP_FREQ_INDX_11025	0x000A
+#define AUDPP_MSG_SAMP_FREQ_INDX_8000	0x000B
+
+#define AUDPP_MSG_CHANNEL_MODE_MONO		0x0001
+#define AUDPP_MSG_CHANNEL_MODE_STEREO	0x0002
+
+struct audpp_msg_host_pcm_intf_msg {
+	unsigned short obj_num;
+	unsigned short numbers_of_samples;
+	unsigned short host_pcm_id;
+	unsigned short buf_indx;
+	unsigned short samp_freq_indx;
+	unsigned short channel_mode;
+} __attribute__((packed));
+
+
+/*
+ * MSG to communicate 3D position of the source and listener , source volume
+ * source rolloff, source orientation
+ */
+
+#define AUDPP_MSG_QAFX_POS		0x0004
+#define AUDPP_MSG_QAFX_POS_LEN		\
+	sizeof(struct audpp_msg_qafx_pos)
+
+struct audpp_msg_qafx_pos {
+	unsigned short	current_object;
+	unsigned short	x_pos_lis_msw;
+	unsigned short	x_pos_lis_lsw;
+	unsigned short	y_pos_lis_msw;
+	unsigned short	y_pos_lis_lsw;
+	unsigned short	z_pos_lis_msw;
+	unsigned short	z_pos_lis_lsw;
+	unsigned short	x_fwd_msw;
+	unsigned short	x_fwd_lsw;
+	unsigned short	y_fwd_msw;
+	unsigned short	y_fwd_lsw;
+	unsigned short	z_fwd_msw;
+	unsigned short	z_fwd_lsw;
+	unsigned short 	x_up_msw;
+	unsigned short	x_up_lsw;
+	unsigned short 	y_up_msw;
+	unsigned short	y_up_lsw;
+	unsigned short 	z_up_msw;
+	unsigned short	z_up_lsw;
+	unsigned short 	x_vel_lis_msw;
+	unsigned short 	x_vel_lis_lsw;
+	unsigned short 	y_vel_lis_msw;
+	unsigned short 	y_vel_lis_lsw;
+	unsigned short 	z_vel_lis_msw;
+	unsigned short 	z_vel_lis_lsw;
+	unsigned short	threed_enable_flag;
+	unsigned short 	volume;
+	unsigned short	x_pos_source_msw;
+	unsigned short	x_pos_source_lsw;
+	unsigned short	y_pos_source_msw;
+	unsigned short	y_pos_source_lsw;
+	unsigned short	z_pos_source_msw;
+	unsigned short	z_pos_source_lsw;
+	unsigned short	max_dist_0_msw;
+	unsigned short	max_dist_0_lsw;
+	unsigned short	min_dist_0_msw;
+	unsigned short	min_dist_0_lsw;
+	unsigned short	roll_off_factor;
+	unsigned short	mute_after_max_flag;
+	unsigned short	x_vel_source_msw;
+	unsigned short	x_vel_source_lsw;
+	unsigned short	y_vel_source_msw;
+	unsigned short	y_vel_source_lsw;
+	unsigned short	z_vel_source_msw;
+	unsigned short	z_vel_source_lsw;
+} __attribute__((packed));
+
+/*
+ * MSG to provide AVSYNC feedback from DSP to ARM
+ */
+
+#define AUDPP_MSG_AVSYNC_MSG		0x0005
+#define AUDPP_MSG_AVSYNC_MSG_LEN	\
+	sizeof(struct audpp_msg_avsync_msg)
+
+struct audpp_msg_avsync_msg {
+	unsigned short	active_flag;
+	unsigned short	num_samples_counter0_HSW;
+	unsigned short	num_samples_counter0_MSW;
+	unsigned short	num_samples_counter0_LSW;
+	unsigned short	num_bytes_counter0_HSW;
+	unsigned short	num_bytes_counter0_MSW;
+	unsigned short	num_bytes_counter0_LSW;
+	unsigned short	samp_freq_obj_0;
+	unsigned short	samp_freq_obj_1;
+	unsigned short	samp_freq_obj_2;
+	unsigned short	samp_freq_obj_3;
+	unsigned short	samp_freq_obj_4;
+	unsigned short	samp_freq_obj_5;
+	unsigned short	samp_freq_obj_6;
+	unsigned short	samp_freq_obj_7;
+	unsigned short	samp_freq_obj_8;
+	unsigned short	samp_freq_obj_9;
+	unsigned short	samp_freq_obj_10;
+	unsigned short	samp_freq_obj_11;
+	unsigned short	samp_freq_obj_12;
+	unsigned short	samp_freq_obj_13;
+	unsigned short	samp_freq_obj_14;
+	unsigned short	samp_freq_obj_15;
+	unsigned short	num_samples_counter4_HSW;
+	unsigned short	num_samples_counter4_MSW;
+	unsigned short	num_samples_counter4_LSW;
+	unsigned short	num_bytes_counter4_HSW;
+	unsigned short	num_bytes_counter4_MSW;
+	unsigned short	num_bytes_counter4_LSW;
+} __attribute__((packed));
+
+/*
+ * MSG to provide PCM DMA Missed feedback from the DSP to ARM
+ */
+
+#define  AUDPP_MSG_PCMDMAMISSED	0x0006
+#define  AUDPP_MSG_PCMDMAMISSED_LEN	\
+	sizeof(struct audpp_msg_pcmdmamissed);
+
+struct audpp_msg_pcmdmamissed {
+	/*
+	** Bit 0	0 = PCM DMA not missed for object 0
+	**        1 = PCM DMA missed for object0
+	** Bit 1	0 = PCM DMA not missed for object 1
+	**        1 = PCM DMA missed for object1
+	** Bit 2	0 = PCM DMA not missed for object 2
+	**        1 = PCM DMA missed for object2
+	** Bit 3	0 = PCM DMA not missed for object 3
+	**        1 = PCM DMA missed for object3
+	** Bit 4	0 = PCM DMA not missed for object 4
+	**        1 = PCM DMA missed for object4
+	*/
+	unsigned short pcmdmamissed;
+} __attribute__((packed));
+
+/*
+ * MSG to AUDPP enable or disable feedback form DSP to ARM
+ */
+
+#define AUDPP_MSG_CFG_MSG	0x0007
+#define AUDPP_MSG_CFG_MSG_LEN	\
+    sizeof(struct audpp_msg_cfg_msg)
+
+#define AUDPP_MSG_ENA_ENA	0xFFFF
+#define AUDPP_MSG_ENA_DIS	0x0000
+
+struct audpp_msg_cfg_msg {
+	/*   Enabled  - 0xffff
+	**  Disabled - 0
+	*/
+	unsigned short enabled;
+} __attribute__((packed));
+
+/*
+ * MSG to communicate the reverb  per object volume
+ */
+
+#define AUDPP_MSG_QREVERB_VOLUME	0x0008
+#define AUDPP_MSG_QREVERB_VOLUME_LEN	\
+	sizeof(struct audpp_msg_qreverb_volume)
+
+
+struct audpp_msg_qreverb_volume {
+	unsigned short	obj_0_gain;
+	unsigned short	obj_1_gain;
+	unsigned short	obj_2_gain;
+	unsigned short	obj_3_gain;
+	unsigned short	obj_4_gain;
+	unsigned short	hpcm_obj_volume;
+} __attribute__((packed));
+
+#define AUDPP_MSG_ROUTING_ACK 0x0009
+#define AUDPP_MSG_ROUTING_ACK_LEN \
+	sizeof(struct audpp_msg_routing_ack)
+
+struct audpp_msg_routing_ack {
+	unsigned short dec_id;
+	unsigned short routing_mode;
+} __attribute__((packed));
+
+#define AUDPP_MSG_FLUSH_ACK 0x000A
+
+#endif /* QDSP5AUDPPMSG_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/qdsp5audpreproccmdi.h b/arch/arm/mach-msm/include/mach/qdsp5v2/qdsp5audpreproccmdi.h
new file mode 100644
index 0000000..f579e1a
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/qdsp5audpreproccmdi.h
@@ -0,0 +1,519 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef QDSP5AUDPREPROCCMDI_H
+#define QDSP5AUDPREPROCCMDI_H
+
+/*
+ * AUDIOPREPROC COMMANDS:
+ * ARM uses uPAudPreProcAudRecCmdQueue to communicate with AUDPREPROCTASK
+ * Location : MEMB
+ * Buffer size : 7
+ * Number of buffers in a queue : 4
+ */
+
+/*
+ * Command to enable or disable particular encoder for new interface
+ */
+
+#define AUDPREPROC_AUDREC_CMD_ENC_CFG		0x0000
+#define	AUDPREPROC_AUDREC_CMD_ENC_CFG_LEN	\
+	sizeof(struct audpreproc_audrec_cmd_enc_cfg)
+#define AUDREC_TASK_0	0x00 /* SBC / PCM */
+#define AUDREC_TASK_1	0x01 /* AAC / PCM / VOICE ENC */
+
+#define ENCODE_ENABLE	0x8000
+
+/* encoder type supported */
+#define ENC_TYPE_WAV	0x00
+#define ENC_TYPE_AAC	0x01
+#define ENC_TYPE_SBC	0x02
+#define ENC_TYPE_AMRNB	0x03
+#define ENC_TYPE_EVRC	0x04
+#define ENC_TYPE_V13K	0x05
+#define ENC_TYPE_EXT_WAV   0x0F /* to dynamically configure frame size */
+
+/* structure definitions according to
+ * command description of ARM-DSP interface specifications
+ */
+struct audpreproc_audrec_cmd_enc_cfg {
+	unsigned short	cmd_id;
+	unsigned short  stream_id;
+	unsigned short  audrec_enc_type;
+} __attribute__((packed));
+
+/*
+ * Command to configure parameters of selected Encoder
+ */
+
+#define AUDPREPROC_AUDREC_CMD_PARAM_CFG	0x0001
+
+#define AUDPREPROC_AUDREC_CMD_PARAM_CFG_COMMON_LEN		\
+	sizeof(struct audpreproc_audrec_cmd_param_cfg_common)
+
+#define DUAL_MIC_STEREO_RECORDING      2
+
+struct audpreproc_audrec_cmd_param_cfg_common {
+	unsigned short cmd_id;
+	unsigned short stream_id;
+} __attribute__((packed));
+
+/*
+ * Command Structure to configure WAV Encoder
+ */
+
+#define AUDPREPROC_AUDREC_CMD_PARAM_CFG_WAV_LEN		\
+	sizeof(struct audpreproc_audrec_cmd_parm_cfg_wav)
+
+#define AUDREC_CMD_MODE_MONO 0
+#define AUDREC_CMD_MODE_STEREO 1
+
+struct audpreproc_audrec_cmd_parm_cfg_wav {
+	struct audpreproc_audrec_cmd_param_cfg_common common;
+	unsigned short aud_rec_samplerate_idx;
+	unsigned short aud_rec_stereo_mode;
+	unsigned short aud_rec_frame_size;
+} __attribute__((packed));
+
+/*
+ * Command Structure to configure AAC Encoder
+ */
+
+#define AUDPREPROC_AUDREC_CMD_PARAM_CFG_AAC_LEN		\
+	sizeof(struct audpreproc_audrec_cmd_parm_cfg_aac)
+
+struct audpreproc_audrec_cmd_parm_cfg_aac {
+	struct audpreproc_audrec_cmd_param_cfg_common common;
+	unsigned short aud_rec_samplerate_idx;
+	unsigned short aud_rec_stereo_mode;
+	signed short   recording_quality;
+} __attribute__((packed));
+
+/*
+ * Command Structure to configure SBC Encoder
+ */
+
+#define AUDPREPROC_AUDREC_CMD_PARAM_CFG_SBC_LEN		\
+	sizeof(struct audpreproc_audrec_cmd_parm_cfg_sbc)
+
+/* encoder parameters mask definitions*/
+
+#define AUDREC_SBC_ENC_PARAM_VER_MASK				0x000A
+#define AUDREC_SBC_ENC_PARAM_ENAHANCED_SBC_BASELINE_VERSION	0x0000
+#define AUDREC_SBC_ENC_PARAM_ENAHANCED_SBC_NA_MASK		0x0400
+#define AUDREC_SBC_ENC_PARAM_BIT_ALLOC_MASK			0x0008
+#define AUDREC_SBC_ENC_PARAM_SNR_MASK				0x0100
+#define AUDREC_SBC_ENC_PARAM_MODE_MASK				0x0006
+#define AUDREC_SBC_ENC_PARAM_MODE_DUAL_MASK			0x0040
+#define AUDREC_SBC_ENC_PARAM_MODE_STEREO_MASK			0x0080
+#define AUDREC_SBC_ENC_PARAM_MODE_JOINT_STEREO_MASK		0x00C0
+#define AUDREC_SBC_ENC_PARAM_NUM_SUB_BANDS_MASK 		0x0004
+#define AUDREC_SBC_ENC_PARAM_NUM_SUB_BANDS_8_MASK		0x0001
+#define AUDREC_SBC_ENC_PARAM_NUM_SUB_BLOCKS_MASK		0x0000
+#define AUDREC_SBC_ENC_PARAM_NUM_SUB_BLOCKS_4_MASK		0x0000
+#define AUDREC_SBC_ENC_PARAM_NUM_SUB_BLOCKS_8_MASK		0x0001
+#define AUDREC_SBC_ENC_PARAM_NUM_SUB_BLOCKS_12_MASK		0x0002
+#define AUDREC_SBC_ENC_PARAM_NUM_SUB_BLOCKS_16_MASK		0x0003
+
+struct audpreproc_audrec_cmd_parm_cfg_sbc {
+	struct audpreproc_audrec_cmd_param_cfg_common common;
+	unsigned short aud_rec_sbc_enc_param;
+	unsigned short aud_rec_sbc_bit_rate_msw;
+	unsigned short aud_rec_sbc_bit_rate_lsw;
+} __attribute__((packed));
+
+/*
+ * Command Structure to configure AMRNB Encoder
+ */
+
+#define AUDPREPROC_AUDREC_CMD_PARAM_CFG_AMRNB_LEN		\
+	sizeof(struct audpreproc_audrec_cmd_parm_cfg_amrnb)
+
+#define AMRNB_DTX_MODE_ENABLE		-1
+#define AMRNB_DTX_MODE_DISABLE		 0
+
+#define AMRNB_TEST_MODE_ENABLE		-1
+#define AMRNB_TEST_MODE_DISABLE		 0
+
+#define AMRNB_USED_MODE_MR475		0x0
+#define AMRNB_USED_MODE_MR515		0x1
+#define AMRNB_USED_MODE_MR59		0x2
+#define AMRNB_USED_MODE_MR67		0x3
+#define AMRNB_USED_MODE_MR74		0x4
+#define AMRNB_USED_MODE_MR795		0x5
+#define AMRNB_USED_MODE_MR102		0x6
+#define AMRNB_USED_MODE_MR122		0x7
+
+struct audpreproc_audrec_cmd_parm_cfg_amrnb {
+	struct audpreproc_audrec_cmd_param_cfg_common common;
+	signed short dtx_mode;
+	signed short test_mode;
+	unsigned short used_mode;
+} __attribute__((packed)) ;
+
+/*
+ * Command Structure to configure EVRC Encoder
+ */
+
+#define AUDPREPROC_AUDREC_CMD_PARAM_CFG_EVRC_LEN		\
+	sizeof(struct audpreproc_audrec_cmd_parm_cfg_evrc)
+
+struct audpreproc_audrec_cmd_parm_cfg_evrc {
+	struct audpreproc_audrec_cmd_param_cfg_common common;
+	unsigned short enc_min_rate;
+	unsigned short enc_max_rate;
+	unsigned short rate_modulation_cmd;
+} __attribute__((packed));
+
+/*
+ * Command Structure to configure QCELP_13K Encoder
+ */
+
+#define AUDPREPROC_AUDREC_CMD_PARAM_CFG_QCELP13K_LEN		\
+	sizeof(struct audpreproc_audrec_cmd_parm_cfg_qcelp13k)
+
+struct audpreproc_audrec_cmd_parm_cfg_qcelp13k {
+	struct audpreproc_audrec_cmd_param_cfg_common common;
+	unsigned short enc_min_rate;
+	unsigned short enc_max_rate;
+	unsigned short rate_modulation_cmd;
+	unsigned short reduced_rate_level;
+} __attribute__((packed));
+
+/*
+ * Command to configure AFE for recording paths
+ */
+#define AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG 0x0002
+
+#define AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG_LEN		\
+	sizeof(struct audpreproc_afe_cmd_audio_record_cfg)
+
+#define AUDIO_RECORDING_TURN_ON		0xFFFF
+#define AUDIO_RECORDING_TURN_OFF	0x0000
+
+#define AUDPP_A2DP_PIPE_SOURCE_MIX_MASK		0x0020
+#define VOICE_DL_SOURCE_MIX_MASK		0x0010
+#define VOICE_UL_SOURCE_MIX_MASK		0x0008
+#define FM_SOURCE_MIX_MASK			0x0004
+#define AUX_CODEC_TX_SOURCE_MIX_MASK		0x0002
+#define INTERNAL_CODEC_TX_SOURCE_MIX_MASK	0x0001
+
+struct audpreproc_afe_cmd_audio_record_cfg {
+	unsigned short cmd_id;
+	unsigned short stream_id;
+	unsigned short destination_activity;
+	unsigned short source_mix_mask;
+	unsigned short pipe_id;
+	unsigned short reserved;
+} __attribute__((packed));
+
+/*
+ * Command to configure Tunnel(RT) or Non-Tunnel(FTRT) mode
+ */
+#define AUDPREPROC_AUDREC_CMD_ROUTING_MODE 0x0003
+#define	AUDPREPROC_AUDREC_CMD_ROUTING_MODE_LEN	\
+	sizeof(struct audpreproc_audrec_cmd_routing_mode)
+
+#define AUDIO_ROUTING_MODE_FTRT		0x0001
+#define AUDIO_ROUTING_MODE_RT		0x0002
+
+struct audpreproc_audrec_cmd_routing_mode {
+	unsigned short cmd_id;
+	unsigned short stream_id;
+	unsigned short routing_mode;
+} __attribute__((packed));
+
+/*
+ * Command to configure DSP for topology where resampler moved
+ * in front of pre processing chain
+ */
+#define AUDPREPROC_AUDREC_CMD_ENC_CFG_2		0x0004
+#define	AUDPREPROC_AUDREC_CMD_ENC_CFG_2_LEN	\
+	sizeof(struct audpreproc_audrec_cmd_enc_cfg_2)
+
+
+struct audpreproc_audrec_cmd_enc_cfg_2 {
+	unsigned short	cmd_id;
+	unsigned short  stream_id;
+	unsigned short  audrec_enc_type;
+} __attribute__((packed));
+
+/*
+ * AUDIOPREPROC COMMANDS:
+ * ARM uses uPAudPreProcCmdQueue to communicate with AUDPREPROCTASK
+ * Location : MEMB
+ * Buffer size : 52
+ * Number of buffers in a queue : 3
+ */
+
+/*
+ * Command to configure the parameters of AGC
+ */
+
+#define	AUDPREPROC_CMD_CFG_AGC_PARAMS	0x0000
+#define	AUDPREPROC_CMD_CFG_AGC_PARAMS_LEN	\
+	sizeof(struct audpreproc_cmd_cfg_agc_params)
+
+#define	AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_SLOPE	0x0200
+#define	AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_TH	0x0400
+#define	AUDPREPROC_CMD_TX_AGC_PARAM_MASK_EXP_SLOPE	0x0800
+#define	AUDPREPROC_CMD_TX_AGC_PARAM_MASK_EXP_TH		0x1000
+#define	AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_AIG_FLAG		0x2000
+#define	AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_STATIC_GAIN	0x4000
+#define	AUDPREPROC_CMD_TX_AGC_PARAM_MASK_TX_AGC_ENA_FLAG	0x8000
+
+#define	AUDPREPROC_CMD_TX_AGC_ENA_FLAG_ENA	-1
+#define	AUDPREPROC_CMD_TX_AGC_ENA_FLAG_DIS	0x0000
+
+#define	AUDPREPROC_CMD_ADP_GAIN_FLAG_ENA_ADP_GAIN	-1
+#define	AUDPREPROC_CMD_ADP_GAIN_FLAG_ENA_STATIC_GAIN	0x0000
+
+#define	AUDPREPROC_CMD_PARAM_MASK_RMS_TAY	0x0010
+#define	AUDPREPROC_CMD_PARAM_MASK_RELEASEK	0x0020
+#define	AUDPREPROC_CMD_PARAM_MASK_DELAY		0x0040
+#define	AUDPREPROC_CMD_PARAM_MASK_ATTACKK	0x0080
+#define	AUDPREPROC_CMD_PARAM_MASK_LEAKRATE_SLOW	0x0100
+#define	AUDPREPROC_CMD_PARAM_MASK_LEAKRATE_FAST	0x0200
+#define	AUDPREPROC_CMD_PARAM_MASK_AIG_RELEASEK 	0x0400
+#define	AUDPREPROC_CMD_PARAM_MASK_AIG_MIN	0x0800
+#define	AUDPREPROC_CMD_PARAM_MASK_AIG_MAX	0x1000
+#define	AUDPREPROC_CMD_PARAM_MASK_LEAK_UP	0x2000
+#define	AUDPREPROC_CMD_PARAM_MASK_LEAK_DOWN	0x4000
+#define	AUDPREPROC_CMD_PARAM_MASK_AIG_ATTACKK	0x8000
+
+struct audpreproc_cmd_cfg_agc_params {
+	unsigned short	cmd_id;
+	unsigned short 	stream_id;
+	unsigned short	tx_agc_param_mask;
+	signed short	tx_agc_enable_flag;
+	unsigned short	comp_rlink_static_gain;
+	signed short	comp_rlink_aig_flag;
+	unsigned short	expander_rlink_th;
+	unsigned short	expander_rlink_slope;
+	unsigned short	compressor_rlink_th;
+	unsigned short	compressor_rlink_slope;
+	unsigned short	tx_adc_agc_param_mask;
+	unsigned short	comp_rlink_aig_attackk;
+	unsigned short	comp_rlink_aig_leak_down;
+	unsigned short	comp_rlink_aig_leak_up;
+	unsigned short	comp_rlink_aig_max;
+	unsigned short	comp_rlink_aig_min;
+	unsigned short	comp_rlink_aig_releasek;
+	unsigned short	comp_rlink_aig_leakrate_fast;
+	unsigned short	comp_rlink_aig_leakrate_slow;
+	unsigned short	comp_rlink_attackk_msw;
+	unsigned short	comp_rlink_attackk_lsw;
+	unsigned short	comp_rlink_delay;
+	unsigned short	comp_rlink_releasek_msw;
+	unsigned short	comp_rlink_releasek_lsw;
+	unsigned short	comp_rlink_rms_tav;
+} __attribute__((packed));
+
+/*
+ * Command to configure the params of Advanved AGC
+ */
+
+#define	AUDPREPROC_CMD_CFG_AGC_PARAMS_2		0x0001
+#define	AUDPREPROC_CMD_CFG_AGC_PARAMS_2_LEN		\
+	sizeof(struct audpreproc_cmd_cfg_agc_params_2)
+
+#define	AUDPREPROC_CMD_2_TX_AGC_ENA_FLAG_ENA	-1;
+#define	AUDPREPROC_CMD_2_TX_AGC_ENA_FLAG_DIS	0x0000;
+
+struct audpreproc_cmd_cfg_agc_params_2 {
+	unsigned short	cmd_id;
+	unsigned short 	stream_id;
+	unsigned short	agc_param_mask;
+	signed short	tx_agc_enable_flag;
+	unsigned short	comp_rlink_static_gain;
+	unsigned short	exp_rlink_th;
+	unsigned short	exp_rlink_slope;
+	unsigned short	comp_rlink_th;
+	unsigned short	comp_rlink_slope;
+	unsigned short	comp_rlink_rms_tav;
+	unsigned short	comp_rlink_down_samp_mask;
+	unsigned short	comp_rlink_attackk_msw;
+	unsigned short	comp_rlink_attackk_lsw;
+	unsigned short	comp_rlink_releasek_msw;
+	unsigned short	comp_rlink_releasek_lsw;
+	unsigned short	comp_rlink_delay;
+	unsigned short	comp_rlink_makeup_gain;
+} __attribute__((packed));
+
+/*
+ * Command to configure params for ns
+ */
+
+#define	AUDPREPROC_CMD_CFG_NS_PARAMS		0x0002
+#define	AUDPREPROC_CMD_CFG_NS_PARAMS_LEN	\
+	sizeof(struct audpreproc_cmd_cfg_ns_params)
+
+#define	AUDPREPROC_CMD_EC_MODE_NLMS_ENA	0x0001
+#define	AUDPREPROC_CMD_EC_MODE_NLMS_DIS 	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_DES_ENA	0x0002
+#define	AUDPREPROC_CMD_EC_MODE_DES_DIS	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_NS_ENA	0x0004
+#define	AUDPREPROC_CMD_EC_MODE_NS_DIS	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_CNI_ENA	0x0008
+#define	AUDPREPROC_CMD_EC_MODE_CNI_DIS	0x0000
+
+#define	AUDPREPROC_CMD_EC_MODE_NLES_ENA	0x0010
+#define	AUDPREPROC_CMD_EC_MODE_NLES_DIS	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_HB_ENA	0x0020
+#define	AUDPREPROC_CMD_EC_MODE_HB_DIS	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_VA_ENA	0x0040
+#define	AUDPREPROC_CMD_EC_MODE_VA_DIS	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_PCD_ENA	0x0080
+#define	AUDPREPROC_CMD_EC_MODE_PCD_DIS	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_FEHI_ENA	0x0100
+#define	AUDPREPROC_CMD_EC_MODE_FEHI_DIS 	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_NEHI_ENA	0x0200
+#define	AUDPREPROC_CMD_EC_MODE_NEHI_DIS 	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_NLPP_ENA	0x0400
+#define	AUDPREPROC_CMD_EC_MODE_NLPP_DIS	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_FNE_ENA	0x0800
+#define	AUDPREPROC_CMD_EC_MODE_FNE_DIS	0x0000
+#define	AUDPREPROC_CMD_EC_MODE_PRENLMS_ENA 	0x1000
+#define	AUDPREPROC_CMD_EC_MODE_PRENLMS_DIS 	0x0000
+
+struct audpreproc_cmd_cfg_ns_params {
+	unsigned short	cmd_id;
+	unsigned short  stream_id;
+	unsigned short	ec_mode_new;
+	unsigned short	dens_gamma_n;
+	unsigned short	dens_nfe_block_size;
+	unsigned short	dens_limit_ns;
+	unsigned short	dens_limit_ns_d;
+	unsigned short	wb_gamma_e;
+	unsigned short	wb_gamma_n;
+} __attribute__((packed));
+
+/*
+ * Command to configure parameters for IIR tuning filter
+ */
+
+#define	AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS		0x0003
+#define	AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS_LEN	\
+	sizeof(struct audpreproc_cmd_cfg_iir_tuning_filter_params)
+
+#define	AUDPREPROC_CMD_IIR_ACTIVE_FLAG_DIS	0x0000
+#define	AUDPREPROC_CMD_IIR_ACTIVE_FLAG_ENA	0x0001
+
+struct audpreproc_cmd_cfg_iir_tuning_filter_params {
+	unsigned short	cmd_id;
+	unsigned short  stream_id;
+	unsigned short	active_flag;
+	unsigned short	num_bands;
+
+	unsigned short	numerator_coeff_b0_filter0_lsw;
+	unsigned short	numerator_coeff_b0_filter0_msw;
+	unsigned short	numerator_coeff_b1_filter0_lsw;
+	unsigned short	numerator_coeff_b1_filter0_msw;
+	unsigned short	numerator_coeff_b2_filter0_lsw;
+	unsigned short	numerator_coeff_b2_filter0_msw;
+
+	unsigned short	numerator_coeff_b0_filter1_lsw;
+	unsigned short	numerator_coeff_b0_filter1_msw;
+	unsigned short	numerator_coeff_b1_filter1_lsw;
+	unsigned short	numerator_coeff_b1_filter1_msw;
+	unsigned short	numerator_coeff_b2_filter1_lsw;
+	unsigned short	numerator_coeff_b2_filter1_msw;
+
+	unsigned short	numerator_coeff_b0_filter2_lsw;
+	unsigned short	numerator_coeff_b0_filter2_msw;
+	unsigned short	numerator_coeff_b1_filter2_lsw;
+	unsigned short	numerator_coeff_b1_filter2_msw;
+	unsigned short	numerator_coeff_b2_filter2_lsw;
+	unsigned short	numerator_coeff_b2_filter2_msw;
+
+	unsigned short	numerator_coeff_b0_filter3_lsw;
+	unsigned short	numerator_coeff_b0_filter3_msw;
+	unsigned short	numerator_coeff_b1_filter3_lsw;
+	unsigned short	numerator_coeff_b1_filter3_msw;
+	unsigned short	numerator_coeff_b2_filter3_lsw;
+	unsigned short	numerator_coeff_b2_filter3_msw;
+
+	unsigned short 	denominator_coeff_a0_filter0_lsw;
+	unsigned short 	denominator_coeff_a0_filter0_msw;
+	unsigned short 	denominator_coeff_a1_filter0_lsw;
+	unsigned short 	denominator_coeff_a1_filter0_msw;
+
+	unsigned short 	denominator_coeff_a0_filter1_lsw;
+	unsigned short 	denominator_coeff_a0_filter1_msw;
+	unsigned short 	denominator_coeff_a1_filter1_lsw;
+	unsigned short 	denominator_coeff_a1_filter1_msw;
+
+	unsigned short	denominator_coeff_a0_filter2_lsw;
+	unsigned short	denominator_coeff_a0_filter2_msw;
+	unsigned short	denominator_coeff_a1_filter2_lsw;
+	unsigned short	denominator_coeff_a1_filter2_msw;
+
+	unsigned short	denominator_coeff_a0_filter3_lsw;
+	unsigned short	denominator_coeff_a0_filter3_msw;
+	unsigned short 	denominator_coeff_a1_filter3_lsw;
+	unsigned short 	denominator_coeff_a1_filter3_msw;
+
+	unsigned short	shift_factor_filter0;
+	unsigned short	shift_factor_filter1;
+	unsigned short	shift_factor_filter2;
+	unsigned short	shift_factor_filter3;
+
+	unsigned short	pan_of_filter0;
+	unsigned short	pan_of_filter1;
+	unsigned short	pan_of_filter2;
+	unsigned short	pan_of_filter3;
+} __attribute__((packed));
+
+/*
+ * Command to configure parameters for calibration gain rx
+ */
+
+#define AUDPREPROC_CMD_CFG_CAL_GAIN_PARAMS 0x0004
+#define AUDPREPROC_CMD_CFG_CAL_GAIN_LEN    \
+	sizeof(struct audpreproc_cmd_cfg_cal_gain)
+
+struct audpreproc_cmd_cfg_cal_gain {
+	unsigned short  cmd_id;
+	unsigned short  stream_id;
+	unsigned short  audprecalgain;
+	unsigned short  reserved;
+}  __attribute__((packed));
+
+#define AUDPREPROC_CMD_CFG_LVNV_PARMS	0x0006
+#define AUDPREPROC_CMD_CFG_LVNV_PARMS_LEN	\
+		sizeof(struct audpreproc_cmd_cfg_lvnv_param)
+
+struct audpreproc_cmd_cfg_lvnv_param {
+	unsigned short cmd_id;
+	unsigned short stream_id;
+	unsigned short cs_mode;
+	unsigned short lvnv_ext_buf_size;
+	unsigned short lvnv_ext_partition;
+	unsigned short lvnv_ext_buf_start_lsw;
+	unsigned short lvnv_ext_buf_start_msw;
+};
+
+#define AUDPREPROC_CMD_FEAT_QUERY_PARAMS 0x0005
+
+struct rtc_audpreproc_read_data {
+	unsigned short	cmd_id;
+	unsigned short	stream_id;
+	unsigned short  feature_id;
+	unsigned short  extbufsizemsw;
+	unsigned short  extbufsizelsw;
+	unsigned short  extpart;
+	unsigned short  extbufstartmsw;
+	unsigned short	extbufstartlsw;
+} __attribute__((packed)) ;
+
+#endif /* QDSP5AUDPREPROCCMDI_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/qdsp5audpreprocmsg.h b/arch/arm/mach-msm/include/mach/qdsp5v2/qdsp5audpreprocmsg.h
new file mode 100644
index 0000000..29da664
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/qdsp5audpreprocmsg.h
@@ -0,0 +1,127 @@
+/* Copyright (c) 2009-2010, 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 QDSP5AUDPREPROCMSG_H
+#define QDSP5AUDPREPROCMSG_H
+
+#define AUDPREPROC_MSG_FEAT_QUERY_DM_DONE 0x0006
+
+/*
+ * ADSPREPROCTASK Messages
+ * AUDPREPROCTASK uses audPreProcUpRlist to communicate with ARM
+ * Location	: MEMB
+ * Buffer size :  6
+ * No of buffers in queue : 4
+ */
+
+/*
+ * Message to indicate Pre processing config command is done
+ */
+
+#define AUDPREPROC_CMD_CFG_DONE_MSG 0x0001
+#define	AUDPREPROC_CMD_CFG_DONE_MSG_LEN	\
+	sizeof(struct audpreproc_cmd_cfg_done_msg)
+
+#define AUD_PREPROC_TYPE_AGC		0x0
+#define AUD_PREPROC_NOISE_REDUCTION	0x1
+#define AUD_PREPROC_IIR_TUNNING_FILTER	0x2
+
+#define AUD_PREPROC_CONFIG_ENABLED 	-1
+#define AUD_PREPROC_CONFIG_DISABLED	 0
+
+struct audpreproc_cmd_cfg_done_msg {
+	unsigned short stream_id;
+	unsigned short aud_preproc_type;
+	signed short aud_preproc_status_flag;
+} __attribute__((packed));
+
+/*
+ * Message to indicate Pre processing error messages
+ */
+
+#define AUDPREPROC_ERROR_MSG 0x0002
+#define AUDPREPROC_ERROR_MSG_LEN \
+	sizeof(struct audpreproc_err_msg)
+
+#define AUD_PREPROC_ERR_IDX_WRONG_SAMPLING_FREQUENCY	0x00
+#define AUD_PREPROC_ERR_IDX_ENC_NOT_SUPPORTED		0x01
+
+struct audpreproc_err_msg {
+	unsigned short stream_id;
+	signed short aud_preproc_err_idx;
+} __attribute__((packed));
+
+/*
+ * Message to indicate encoder config command
+ */
+
+#define AUDPREPROC_CMD_ENC_CFG_DONE_MSG	0x0003
+#define AUDPREPROC_CMD_ENC_CFG_DONE_MSG_LEN \
+	sizeof(struct audpreproc_cmd_enc_cfg_done_msg)
+
+struct audpreproc_cmd_enc_cfg_done_msg {
+	unsigned short stream_id;
+	unsigned short rec_enc_type;
+} __attribute__((packed));
+
+/*
+ * Message to indicate encoder param config command
+ */
+
+#define AUDPREPROC_CMD_ENC_PARAM_CFG_DONE_MSG	0x0004
+#define AUDPREPROC_CMD_ENC_PARAM_CFG_DONE_MSG_LEN \
+	sizeof(struct audpreproc_cmd_enc_param_cfg_done_msg)
+
+struct audpreproc_cmd_enc_param_cfg_done_msg {
+	unsigned short stream_id;
+} __attribute__((packed));
+
+
+/*
+ * Message to indicate AFE config cmd for
+ * audio recording is successfully recieved
+ */
+
+#define AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG  0x0005
+#define AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG_LEN \
+	sizeof(struct audpreproc_afe_cmd_audio_record_cfg_done)
+
+struct audpreproc_afe_cmd_audio_record_cfg_done {
+	unsigned short stream_id;
+} __attribute__((packed));
+
+/*
+ * Message to indicate Routing mode
+ * configuration success or failure
+ */
+
+#define AUDPREPROC_CMD_ROUTING_MODE_DONE_MSG  0x0007
+#define AUDPREPROC_CMD_ROUTING_MODE_DONE_MSG_LEN \
+	sizeof(struct audpreproc_cmd_routing_mode_done)
+
+struct audpreproc_cmd_routing_mode_done {
+	unsigned short stream_id;
+	unsigned short configuration;
+} __attribute__((packed));
+
+
+#define AUDPREPROC_CMD_PCM_CFG_ARM_TO_PREPROC_DONE_MSG	0x0008
+#define AUDPREPROC_CMD_PCM_CFG_ARM_TO_PREPROC_DONE_MSG_LEN \
+	sizeof(struct audreproc_cmd_pcm_cfg_arm_to_preproc_done)
+
+struct audreproc_cmd_pcm_cfg_arm_to_preproc_done {
+	unsigned short stream_id;
+	unsigned short configuration;
+} __attribute__((packed));
+
+#endif /* QDSP5AUDPREPROCMSG_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/qdsp5audreccmdi.h b/arch/arm/mach-msm/include/mach/qdsp5v2/qdsp5audreccmdi.h
new file mode 100644
index 0000000..9ba8645
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/qdsp5audreccmdi.h
@@ -0,0 +1,122 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef QDSP5AUDRECCMDI_H
+#define QDSP5AUDRECCMDI_H
+
+/*
+ * AUDRECTASK COMMANDS
+ * ARM uses 2 queues to communicate with the AUDRECTASK
+ * 1.uPAudRec[i]CmdQueue, where i=0,1,2
+ * Location :MEMC
+ * Buffer Size : 5
+ * No of Buffers in a queue : 2
+ * 2.uPAudRec[i]BitstreamQueue, where i=0,1,2
+ * Location : MEMC
+ * Buffer Size : 5
+ * No of buffers in a queue : 3
+ */
+
+/*
+ * Commands on uPAudRec[i]CmdQueue, where i=0,1,2
+ */
+
+/*
+ * Command to configure memory for enabled encoder
+ */
+
+#define AUDREC_CMD_MEM_CFG_CMD 0x0000
+#define AUDREC_CMD_ARECMEM_CFG_LEN	\
+	sizeof(struct audrec_cmd_arecmem_cfg)
+
+struct audrec_cmd_arecmem_cfg {
+	unsigned short cmd_id;
+	unsigned short audrec_up_pkt_intm_count;
+	unsigned short audrec_ext_pkt_start_addr_msw;
+	unsigned short audrec_ext_pkt_start_addr_lsw;
+	unsigned short audrec_ext_pkt_buf_number;
+} __attribute__((packed));
+
+/*
+ * Command to configure pcm input memory
+ */
+
+#define AUDREC_CMD_PCM_CFG_ARM_TO_ENC 0x0001
+#define AUDREC_CMD_PCM_CFG_ARM_TO_ENC_LEN	\
+	sizeof(struct audrec_cmd_pcm_cfg_arm_to_enc)
+
+struct audrec_cmd_pcm_cfg_arm_to_enc {
+	unsigned short cmd_id;
+	unsigned short config_update_flag;
+	unsigned short enable_flag;
+	unsigned short sampling_freq;
+	unsigned short channels;
+	unsigned short frequency_of_intimation;
+	unsigned short max_number_of_buffers;
+} __attribute__((packed));
+
+#define AUDREC_PCM_CONFIG_UPDATE_FLAG_ENABLE -1
+#define AUDREC_PCM_CONFIG_UPDATE_FLAG_DISABLE 0
+
+#define AUDREC_ENABLE_FLAG_VALUE -1
+#define AUDREC_DISABLE_FLAG_VALUE 0
+
+/*
+ * Command to intimate available pcm buffer
+ */
+
+#define AUDREC_CMD_PCM_BUFFER_PTR_REFRESH_ARM_TO_ENC 0x0002
+#define AUDREC_CMD_PCM_BUFFER_PTR_REFRESH_ARM_TO_ENC_LEN \
+  sizeof(struct audrec_cmd_pcm_buffer_ptr_refresh_arm_enc)
+
+struct audrec_cmd_pcm_buffer_ptr_refresh_arm_enc {
+	unsigned short cmd_id;
+	unsigned short num_buffers;
+	unsigned short buffer_write_cnt_msw;
+	unsigned short buffer_write_cnt_lsw;
+	unsigned short buf_address_length[8];/*this array holds address
+						and length details of
+						two buffers*/
+} __attribute__((packed));
+
+/*
+ * Command to flush
+ */
+
+#define AUDREC_CMD_FLUSH 0x0003
+#define AUDREC_CMD_FLUSH_LEN	\
+	sizeof(struct audrec_cmd_flush)
+
+struct audrec_cmd_flush {
+	unsigned short cmd_id;
+} __attribute__((packed));
+
+/*
+ * Commands on uPAudRec[i]BitstreamQueue, where i=0,1,2
+ */
+
+/*
+ * Command to indicate current packet read count
+ */
+
+#define UP_AUDREC_PACKET_EXT_PTR 0x0000
+#define UP_AUDREC_PACKET_EXT_PTR_LEN	\
+	sizeof(up_audrec_packet_ext_ptr)
+
+struct up_audrec_packet_ext_ptr {
+	unsigned short cmd_id;
+	unsigned short audrec_up_curr_read_count_lsw;
+	unsigned short audrec_up_curr_read_count_msw;
+} __attribute__((packed));
+
+#endif /* QDSP5AUDRECCMDI_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/qdsp5audrecmsg.h b/arch/arm/mach-msm/include/mach/qdsp5v2/qdsp5audrecmsg.h
new file mode 100644
index 0000000..32ccbbc
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/qdsp5audrecmsg.h
@@ -0,0 +1,115 @@
+/* Copyright (c) 2009-2010, 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 QDSP5AUDRECMSG_H
+#define QDSP5AUDRECMSG_H
+
+/*
+ * AUDRECTASK MESSAGES
+ * AUDRECTASK uses audRec[i]UpRlist, where i=0,1,2 to communicate with ARM
+ * Location : MEMC
+ * Buffer size : 5
+ * No of buffers in a queue : 10
+ */
+
+/*
+ * Message to notify 2 error conditions
+ */
+
+#define AUDREC_FATAL_ERR_MSG 0x0001
+#define AUDREC_FATAL_ERR_MSG_LEN	\
+	sizeof(struct audrec_fatal_err_msg)
+
+#define AUDREC_FATAL_ERR_MSG_NO_PKT	0x00
+
+struct audrec_fatal_err_msg {
+	unsigned short audrec_err_id;
+} __attribute__((packed));
+
+/*
+ * Message to indicate encoded packet is delivered to external buffer
+ */
+
+#define AUDREC_UP_PACKET_READY_MSG 0x0002
+#define AUDREC_UP_PACKET_READY_MSG_LEN	\
+	sizeof(struct audrec_up_pkt_ready_msg)
+
+struct  audrec_up_pkt_ready_msg {
+	unsigned short audrec_packet_write_cnt_lsw;
+	unsigned short audrec_packet_write_cnt_msw;
+	unsigned short audrec_up_prev_read_cnt_lsw;
+	unsigned short audrec_up_prev_read_cnt_msw;
+} __attribute__((packed));
+
+/*
+ * Message indicates arecmem cfg done
+ */
+#define AUDREC_CMD_MEM_CFG_DONE_MSG 0x0003
+
+/* buffer conntents are nill only message id is required */
+
+/*
+ * Message to indicate pcm buffer configured
+ */
+
+#define AUDREC_CMD_PCM_CFG_ARM_TO_ENC_DONE_MSG 0x0004
+#define AUDREC_CMD_PCM_CFG_ARM_TO_ENC_DONE_MSG_LEN	\
+	sizeof(struct audrec_cmd_pcm_cfg_arm_to_enc_msg)
+
+struct  audrec_cmd_pcm_cfg_arm_to_enc_msg {
+	unsigned short configuration;
+} __attribute__((packed));
+
+/*
+ * Message to indicate encoded packet is delivered to external buffer in FTRT
+ */
+
+#define AUDREC_UP_NT_PACKET_READY_MSG 0x0005
+#define AUDREC_UP_NT_PACKET_READY_MSG_LEN	\
+	sizeof(struct audrec_up_nt_packet_ready_msg)
+
+struct  audrec_up_nt_packet_ready_msg {
+	unsigned short audrec_packetwrite_cnt_lsw;
+	unsigned short audrec_packetwrite_cnt_msw;
+	unsigned short audrec_upprev_readcount_lsw;
+	unsigned short audrec_upprev_readcount_msw;
+} __attribute__((packed));
+
+/*
+ * Message to indicate pcm buffer is consumed
+ */
+
+#define AUDREC_CMD_PCM_BUFFER_PTR_UPDATE_ARM_TO_ENC_MSG 0x0006
+#define AUDREC_CMD_PCM_BUFFER_PTR_UPDATE_ARM_TO_ENC_MSG_LEN	\
+	sizeof(struct audrec_cmd_pcm_buffer_ptr_update_arm_to_enc_msg)
+
+struct  audrec_cmd_pcm_buffer_ptr_update_arm_to_enc_msg {
+	unsigned short buffer_readcnt_msw;
+	unsigned short buffer_readcnt_lsw;
+	unsigned short number_of_buffers;
+	unsigned short buffer_address_length[];
+} __attribute__((packed));
+
+/*
+ * Message to indicate flush acknowledgement
+ */
+
+#define AUDREC_CMD_FLUSH_DONE_MSG 0x0007
+
+/*
+ * Message to indicate End of Stream acknowledgement
+ */
+
+#define AUDREC_CMD_EOS_ACK_MSG 0x0008
+
+#endif /* QDSP5AUDRECMSG_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/snddev_ecodec.h b/arch/arm/mach-msm/include/mach/qdsp5v2/snddev_ecodec.h
new file mode 100644
index 0000000..35c1edb
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/snddev_ecodec.h
@@ -0,0 +1,29 @@
+/* Copyright (c) 2009, 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 __MACH_QDSP5_V2_SNDDEV_ECODEC_H
+#define __MACH_QDSP5_V2_SNDDEV_ECODEC_H
+#include <mach/qdsp5v2/audio_def.h>
+
+struct snddev_ecodec_data {
+	u32 capability; /* RX or TX */
+	const char *name;
+	u32 copp_id; /* audpp routing */
+	u32 acdb_id; /* Audio Cal purpose */
+	u8 channel_mode;
+	u32 conf_pcm_ctl_val;
+	u32 conf_aux_codec_intf;
+	u32 conf_data_format_padding_val;
+	s32 max_voice_rx_vol[VOC_RX_VOL_ARRAY_NUM]; /* [0]:NB, [1]:WB */
+	s32 min_voice_rx_vol[VOC_RX_VOL_ARRAY_NUM];
+};
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/snddev_icodec.h b/arch/arm/mach-msm/include/mach/qdsp5v2/snddev_icodec.h
new file mode 100644
index 0000000..7f9938e
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/snddev_icodec.h
@@ -0,0 +1,41 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __MACH_QDSP5_V2_SNDDEV_ICODEC_H
+#define __MACH_QDSP5_V2_SNDDEV_ICODEC_H
+#include <linux/mfd/msm-adie-codec.h>
+#include <mach/qdsp5v2/audio_def.h>
+#include <mach/pmic.h>
+
+struct snddev_icodec_data {
+	u32 capability; /* RX or TX */
+	const char *name;
+	u32 copp_id; /* audpp routing */
+	u32 acdb_id; /* Audio Cal purpose */
+	/* Adie profile */
+	struct adie_codec_dev_profile *profile;
+	/* Afe setting */
+	u8 channel_mode;
+	enum hsed_controller *pmctl_id; /* tx only enable mic bias */
+	u32 pmctl_id_sz;
+	u32 default_sample_rate;
+	void (*pamp_on) (void);
+	void (*pamp_off) (void);
+	void (*voltage_on) (void);
+	void (*voltage_off) (void);
+	s32 max_voice_rx_vol[VOC_RX_VOL_ARRAY_NUM]; /* [0]: NB,[1]: WB */
+	s32 min_voice_rx_vol[VOC_RX_VOL_ARRAY_NUM];
+	u32 dev_vol_type;
+	u32 property; /*variable used to hold the properties
+				internal to the device*/
+};
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/snddev_mi2s.h b/arch/arm/mach-msm/include/mach/qdsp5v2/snddev_mi2s.h
new file mode 100644
index 0000000..cd834a5
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/snddev_mi2s.h
@@ -0,0 +1,36 @@
+/* Copyright (c) 2010, 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 __MACH_QDSP5_V2_SNDDEV_MI2S_H
+#define __MACH_QDSP5_V2_SNDDEV_MI2S_H
+
+struct snddev_mi2s_data {
+	u32 capability; /* RX or TX */
+	const char *name;
+	u32 copp_id; /* audpp routing */
+	u32 acdb_id; /* Audio Cal purpose */
+	u8 channel_mode;
+	u8 sd_lines;
+	void (*route) (void);
+	void (*deroute) (void);
+	u32 default_sample_rate;
+};
+
+int mi2s_config_clk_gpio(void);
+
+int mi2s_config_data_gpio(u32 direction, u8 sd_line_mask);
+
+int mi2s_unconfig_clk_gpio(void);
+
+int mi2s_unconfig_data_gpio(u32 direction, u8 sd_line_mask);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/snddev_virtual.h b/arch/arm/mach-msm/include/mach/qdsp5v2/snddev_virtual.h
new file mode 100644
index 0000000..695b19d
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/snddev_virtual.h
@@ -0,0 +1,23 @@
+/* Copyright (c) 2010, 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 __MACH_QDSP5_V2_SNDDEV_VIRTUAL_H
+#define __MACH_QDSP5_V2_SNDDEV_VIRTUAL_H
+#include <mach/qdsp5v2/audio_def.h>
+
+struct snddev_virtual_data {
+	u32 capability; /* RX or TX */
+	const char *name;
+	u32 copp_id; /* audpp routing */
+	u32 acdb_id; /* Audio Cal purpose */
+};
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/voice.h b/arch/arm/mach-msm/include/mach/qdsp5v2/voice.h
new file mode 100644
index 0000000..5ca2d6d
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/voice.h
@@ -0,0 +1,117 @@
+/* Copyright (c) 2009-2010, 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 _MACH_QDSP5_V2_VOICE_H
+#define _MACH_QDSP5_V2_VOICE_H
+
+#define VOICE_DALRPC_DEVICEID 0x02000075
+#define VOICE_DALRPC_PORT_NAME "DAL00"
+#define VOICE_DALRPC_CPU 0
+
+
+/* Commands sent to Modem */
+#define CMD_VOICE_INIT                  0x1
+#define CMD_ACQUIRE_DONE                0x2
+#define CMD_RELEASE_DONE                0x3
+#define CMD_DEVICE_INFO                 0x4
+#define CMD_DEVICE_CHANGE               0x6
+
+/* EVENTS received from MODEM */
+#define EVENT_ACQUIRE_START             0x51
+#define EVENT_RELEASE_START             0x52
+#define EVENT_CHANGE_START              0x54
+#define EVENT_NETWORK_RECONFIG          0x53
+
+/* voice state */
+enum {
+	VOICE_INIT = 0,
+	VOICE_ACQUIRE,
+	VOICE_CHANGE,
+	VOICE_RELEASE,
+};
+
+enum {
+	NETWORK_CDMA = 0,
+	NETWORK_GSM,
+	NETWORK_WCDMA,
+	NETWORK_WCDMA_WB,
+};
+
+enum {
+	VOICE_DALRPC_CMD = DALDEVICE_FIRST_DEVICE_API_IDX
+};
+
+/* device state */
+enum {
+	DEV_INIT = 0,
+	DEV_READY,
+	DEV_CHANGE,
+	DEV_CONCUR,
+	DEV_REL_DONE,
+};
+
+/* Voice Event */
+enum{
+	VOICE_RELEASE_START = 1,
+	VOICE_CHANGE_START,
+	VOICE_ACQUIRE_START,
+	VOICE_NETWORK_RECONFIG,
+};
+
+/* Device Event */
+#define DEV_CHANGE_READY                0x1
+
+#define VOICE_CALL_START	0x1
+#define VOICE_CALL_END		0
+
+#define VOICE_DEV_ENABLED	0x1
+#define VOICE_DEV_DISABLED	0
+
+struct voice_header {
+	uint32_t id;
+	uint32_t data_len;
+};
+
+struct voice_init {
+	struct voice_header hdr;
+	void *cb_handle;
+};
+
+
+/* Device information payload structure */
+struct voice_device {
+	struct voice_header hdr;
+	uint32_t rx_device;
+	uint32_t tx_device;
+	uint32_t rx_volume;
+	uint32_t rx_mute;
+	uint32_t tx_mute;
+	uint32_t rx_sample;
+	uint32_t tx_sample;
+};
+
+/*Voice command structure*/
+struct voice_network {
+	struct voice_header hdr;
+	uint32_t network_info;
+};
+
+struct device_data {
+	uint32_t dev_acdb_id;
+	uint32_t volume; /* in percentage */
+	uint32_t mute;
+	uint32_t sample;
+	uint32_t enabled;
+	uint32_t dev_id;
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h b/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
new file mode 100644
index 0000000..62d7a33
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
@@ -0,0 +1,152 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __APR_H_
+#define __APR_H_
+
+#define APR_Q6_NOIMG   0
+#define APR_Q6_LOADING 1
+#define APR_Q6_LOADED  2
+
+struct apr_q6 {
+	void *pil;
+	uint32_t state;
+	struct mutex lock;
+};
+
+struct apr_hdr {
+	uint16_t hdr_field;
+	uint16_t pkt_size;
+	uint8_t src_svc;
+	uint8_t src_domain;
+	uint16_t src_port;
+	uint8_t dest_svc;
+	uint8_t dest_domain;
+	uint16_t dest_port;
+	uint32_t token;
+	uint32_t opcode;
+};
+
+#define APR_HDR_LEN(hdr_len) ((hdr_len)/4)
+#define APR_PKT_SIZE(hdr_len, payload_len) ((hdr_len) + (payload_len))
+#define APR_HDR_FIELD(msg_type, hdr_len, ver)\
+	(((msg_type & 0x3) << 8) | ((hdr_len & 0xF) << 4) | (ver & 0xF))
+
+#define APR_HDR_SIZE sizeof(struct apr_hdr)
+
+/* Version */
+#define APR_PKT_VER		0x0
+
+/* Command and Response Types */
+#define APR_MSG_TYPE_EVENT	0x0
+#define APR_MSG_TYPE_CMD_RSP	0x1
+#define APR_MSG_TYPE_SEQ_CMD	0x2
+#define APR_MSG_TYPE_NSEQ_CMD	0x3
+#define APR_MSG_TYPE_MAX	0x04
+
+/* APR Basic Response Message */
+#define APR_BASIC_RSP_RESULT 0x000110E8
+#define APR_RSP_ACCEPTED     0x000100BE
+
+/* Domain IDs */
+#define APR_DOMAIN_SIM	0x1
+#define APR_DOMAIN_PC		0x2
+#define APR_DOMAIN_MODEM	0x3
+#define APR_DOMAIN_ADSP	0x4
+#define APR_DOMAIN_APPS	0x5
+#define APR_DOMAIN_MAX	0x6
+
+/* ADSP service IDs */
+#define APR_SVC_TEST_CLIENT     0x2
+#define APR_SVC_ADSP_CORE	0x3
+#define APR_SVC_AFE		0x4
+#define APR_SVC_VSM		0x5
+#define APR_SVC_VPM		0x6
+#define APR_SVC_ASM		0x7
+#define APR_SVC_ADM		0x8
+#define APR_SVC_ADSP_MVM	0x09
+#define APR_SVC_ADSP_CVS	0x0A
+#define APR_SVC_ADSP_CVP	0x0B
+#define APR_SVC_USM		0x0C
+#define APR_SVC_MAX		0x0D
+
+/* Modem Service IDs */
+#define APR_SVC_MVS		0x3
+#define APR_SVC_MVM		0x4
+#define APR_SVC_CVS		0x5
+#define APR_SVC_CVP		0x6
+#define APR_SVC_SRD		0x7
+
+/* APR Port IDs */
+#define APR_MAX_PORTS		0x40
+
+#define APR_NAME_MAX		0x40
+
+#define RESET_EVENTS		0xFFFFFFFF
+
+#define LPASS_RESTART_EVENT	0x1000
+#define LPASS_RESTART_READY	0x1001
+
+struct apr_client_data {
+	uint16_t reset_event;
+	uint16_t reset_proc;
+	uint16_t payload_size;
+	uint16_t hdr_len;
+	uint16_t msg_type;
+	uint16_t src;
+	uint16_t dest_svc;
+	uint16_t src_port;
+	uint16_t dest_port;
+	uint32_t token;
+	uint32_t opcode;
+	void *payload;
+};
+
+typedef int32_t (*apr_fn)(struct apr_client_data *data, void *priv);
+
+struct apr_svc {
+	uint16_t id;
+	uint16_t dest_id;
+	uint16_t client_id;
+	uint8_t rvd;
+	uint8_t port_cnt;
+	uint8_t svc_cnt;
+	uint8_t need_reset;
+	apr_fn port_fn[APR_MAX_PORTS];
+	void *port_priv[APR_MAX_PORTS];
+	apr_fn fn;
+	void *priv;
+	struct mutex m_lock;
+	spinlock_t w_lock;
+};
+
+struct apr_client {
+	uint8_t id;
+	uint8_t svc_cnt;
+	uint8_t rvd;
+	struct mutex m_lock;
+	struct apr_svc_ch_dev *handle;
+	struct apr_svc svc[APR_SVC_MAX];
+};
+
+struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
+					uint32_t src_port, void *priv);
+inline int apr_fill_hdr(void *handle, uint32_t *buf, uint16_t src_port,
+			uint16_t msg_type, uint16_t dest_port,
+			uint32_t token, uint32_t opcode, uint16_t len);
+
+int apr_send_pkt(void *handle, uint32_t *buf);
+int apr_deregister(void *handle);
+void change_q6_state(int state);
+void q6audio_dsp_not_responding(void);
+void apr_reset(void *handle);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/apr_tal.h b/arch/arm/mach-msm/include/mach/qdsp6v2/apr_tal.h
new file mode 100644
index 0000000..163ba7b
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/apr_tal.h
@@ -0,0 +1,55 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __APR_TAL_H_
+#define __APR_TAL_H_
+
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/uaccess.h>
+
+/* APR Client IDs */
+#define APR_CLIENT_AUDIO	0x0
+#define APR_CLIENT_VOICE	0x1
+#define APR_CLIENT_MAX	0x2
+
+#define APR_DL_SMD    0
+#define APR_DL_MAX    1
+
+#define APR_DEST_MODEM 0
+#define APR_DEST_QDSP6 1
+#define APR_DEST_MAX   2
+
+#define APR_MAX_BUF   8192
+
+#define APR_OPEN_TIMEOUT_MS 5000
+
+typedef void (*apr_svc_cb_fn)(void *buf, int len, void *priv);
+struct apr_svc_ch_dev *apr_tal_open(uint32_t svc, uint32_t dest,
+			uint32_t dl, apr_svc_cb_fn func, void *priv);
+int apr_tal_write(struct apr_svc_ch_dev *apr_ch, void *data, int len);
+int apr_tal_close(struct apr_svc_ch_dev *apr_ch);
+struct apr_svc_ch_dev {
+	struct smd_channel *ch;
+	spinlock_t         lock;
+	spinlock_t         w_lock;
+	struct mutex       m_lock;
+	apr_svc_cb_fn      func;
+	char               data[APR_MAX_BUF];
+	wait_queue_head_t  wait;
+	void               *priv;
+	uint32_t           smd_state;
+	wait_queue_head_t  dest;
+	uint32_t           dest_state;
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.h b/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.h
new file mode 100644
index 0000000..487e814
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.h
@@ -0,0 +1,154 @@
+/* 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
+ * 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 __APR_US_H__
+#define __APR_US_H__
+
+#include <mach/qdsp6v2/apr.h>
+
+/* ======================================================================= */
+/*  Session Level commands */
+#define USM_SESSION_CMD_MEMORY_MAP			0x00012304
+struct usm_stream_cmd_memory_map {
+	struct apr_hdr	hdr;
+	u32		buf_add;
+	u32		buf_size;
+	u16		mempool_id;
+	u16		reserved;
+} __packed;
+
+#define USM_SESSION_CMD_MEMORY_UNMAP			0x00012305
+struct usm_stream_cmd_memory_unmap {
+	struct apr_hdr  hdr;
+	u32             buf_add;
+} __packed;
+
+#define USM_SESSION_CMD_RUN				0x00012306
+struct usm_stream_cmd_run {
+	struct apr_hdr hdr;
+	u32            flags;
+	u32            msw_ts;
+	u32            lsw_ts;
+} __packed;
+
+/* Stream level commands */
+#define USM_STREAM_CMD_OPEN_READ			0x00012309
+struct usm_stream_cmd_open_read {
+	struct apr_hdr hdr;
+	u32            uMode;
+	u32            src_endpoint;
+	u32            pre_proc_top;
+	u32            format;
+} __packed;
+
+#define USM_STREAM_CMD_OPEN_WRITE			0x00011271
+struct usm_stream_cmd_open_write {
+	struct apr_hdr hdr;
+	u32            format;
+} __packed;
+
+
+#define USM_STREAM_CMD_CLOSE				0x0001230A
+
+/* Encoder configuration definitions */
+#define USM_STREAM_CMD_SET_ENC_PARAM			0x0001230B
+/* Decoder configuration definitions */
+#define USM_DATA_CMD_MEDIA_FORMAT_UPDATE		0x00011272
+
+/* Encoder/decoder configuration block */
+#define USM_PARAM_ID_ENCDEC_ENC_CFG_BLK			0x0001230D
+
+/* Parameter structures used in  USM_STREAM_CMD_SET_ENCDEC_PARAM command */
+/* common declarations */
+struct usm_cfg_common {
+	u16 ch_cfg;
+	u16 bits_per_sample;
+	u32 sample_rate;
+	u32 dev_id;
+	u32 data_map;
+} __packed;
+
+/* Max number of static located transparent data (bytes) */
+#define USM_MAX_CFG_DATA_SIZE 20
+struct usm_encode_cfg_blk {
+	u32 frames_per_buf;
+	u32 format_id;
+	/* <cfg_size> = sizeof(usm_cfg_common)+|tarnsp_data| */
+	u32 cfg_size;
+	struct usm_cfg_common cfg_common;
+	/* Transparent configuration data for specific encoder */
+	u8  transp_data[USM_MAX_CFG_DATA_SIZE];
+} __packed;
+
+struct usm_stream_cmd_encdec_cfg_blk {
+	struct apr_hdr hdr;
+	u32 param_id;
+	u32 param_size;
+	struct usm_encode_cfg_blk enc_blk;
+} __packed;
+
+struct us_encdec_cfg {
+	u32 format_id;
+	struct usm_cfg_common cfg_common;
+	u16 params_size;
+	u8 *params;
+} __packed;
+
+struct usm_stream_media_format_update {
+	struct apr_hdr hdr;
+	u32 format_id;
+	/* <cfg_size> = sizeof(usm_cfg_common)+|tarnsp_data| */
+	u32 cfg_size;
+	struct usm_cfg_common cfg_common;
+	/* Transparent configuration data for specific encoder */
+	u8  transp_data[USM_MAX_CFG_DATA_SIZE];
+} __packed;
+
+
+#define USM_DATA_CMD_READ				0x0001230E
+struct usm_stream_cmd_read {
+	struct apr_hdr  hdr;
+	u32                 buf_add;
+	u32                 buf_size;
+	u32                 uid;
+	u32                 counter;
+} __packed;
+
+#define USM_DATA_EVENT_READ_DONE			0x0001230F
+
+#define USM_DATA_CMD_WRITE				0x00011273
+struct usm_stream_cmd_write {
+	struct apr_hdr hdr;
+	u32 buf_add;
+	u32 buf_size;
+	u32 uid;
+	u32 msw_ts;
+	u32 lsw_ts;
+	u32 flags;
+} __packed;
+
+#define USM_DATA_EVENT_WRITE_DONE			0x00011274
+
+/* Start/stop US signal detection */
+#define USM_SESSION_CMD_SIGNAL_DETECT_MODE		0x00012719
+
+struct usm_session_cmd_detect_info {
+	struct apr_hdr hdr;
+	u32 detect_mode;
+	u32 skip_interval;
+	u32 algorithm_cfg_size;
+} __packed;
+
+/* US signal detection result */
+#define USM_SESSION_EVENT_SIGNAL_DETECT_RESULT		0x00012720
+
+#endif /* __APR_US_H__ */
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/audio_acdb.h b/arch/arm/mach-msm/include/mach/qdsp6v2/audio_acdb.h
new file mode 100644
index 0000000..a55dee6
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/audio_acdb.h
@@ -0,0 +1,62 @@
+/* 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
+ * 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 _AUDIO_ACDB_H
+#define _AUDIO_ACDB_H
+
+#include <linux/msm_audio_acdb.h>
+#include <sound/q6adm.h>
+
+enum {
+	RX_CAL,
+	TX_CAL,
+	MAX_AUDPROC_TYPES
+};
+
+struct acdb_cal_block {
+	uint32_t		cal_size;
+	uint32_t		cal_kvaddr;
+	uint32_t		cal_paddr;
+};
+
+struct acdb_atomic_cal_block {
+	atomic_t		cal_size;
+	atomic_t		cal_kvaddr;
+	atomic_t		cal_paddr;
+};
+
+struct acdb_cal_data {
+	uint32_t			num_cal_blocks;
+	struct acdb_atomic_cal_block	*cal_blocks;
+};
+
+uint32_t get_voice_rx_topology(void);
+uint32_t get_voice_tx_topology(void);
+uint32_t get_adm_rx_topology(void);
+uint32_t get_adm_tx_topology(void);
+uint32_t get_asm_topology(void);
+void get_all_voice_cal(struct acdb_cal_block *cal_block);
+void get_all_cvp_cal(struct acdb_cal_block *cal_block);
+void get_all_vocproc_cal(struct acdb_cal_block *cal_block);
+void get_all_vocstrm_cal(struct acdb_cal_block *cal_block);
+void get_all_vocvol_cal(struct acdb_cal_block *cal_block);
+void get_anc_cal(struct acdb_cal_block *cal_block);
+void get_afe_cal(int32_t path, struct acdb_cal_block *cal_block);
+void get_audproc_cal(int32_t path, struct acdb_cal_block *cal_block);
+void get_audstrm_cal(int32_t path, struct acdb_cal_block *cal_block);
+void get_audvol_cal(int32_t path, struct acdb_cal_block *cal_block);
+void get_vocproc_cal(struct acdb_cal_data *cal_data);
+void get_vocstrm_cal(struct acdb_cal_data *cal_data);
+void get_vocvol_cal(struct acdb_cal_data *cal_data);
+void get_sidetone_cal(struct sidetone_cal *cal_data);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/audio_dev_ctl.h b/arch/arm/mach-msm/include/mach/qdsp6v2/audio_dev_ctl.h
new file mode 100644
index 0000000..20c6fc4
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/audio_dev_ctl.h
@@ -0,0 +1,221 @@
+/* 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
+ * 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 __MACH_QDSP6_V2_SNDDEV_H
+#define __MACH_QDSP6_V2_SNDDEV_H
+#include <mach/qdsp5v2/audio_def.h>
+#include <sound/q6afe.h>
+
+#define AUDIO_DEV_CTL_MAX_DEV 64
+#define DIR_TX	2
+#define DIR_RX	1
+
+#define DEVICE_IGNORE	0xffff
+#define COPP_IGNORE	0xffffffff
+#define SESSION_IGNORE 0x0UL
+
+/* 8 concurrent sessions with Q6 possible,  session:0
+   reserved in DSP */
+#define MAX_SESSIONS 0x09
+
+/* This represents Maximum bit needed for representing sessions
+   per clients, MAX_BIT_PER_CLIENT >= MAX_SESSIONS */
+#define MAX_BIT_PER_CLIENT 16
+
+#define VOICE_STATE_INVALID 0x0
+#define VOICE_STATE_INCALL 0x1
+#define VOICE_STATE_OFFCALL 0x2
+#define ONE_TO_MANY 1
+#define MANY_TO_ONE 2
+
+struct msm_snddev_info {
+	const char *name;
+	u32 capability;
+	u32 copp_id;
+	u32 acdb_id;
+	u32 dev_volume;
+	struct msm_snddev_ops {
+		int (*open)(struct msm_snddev_info *);
+		int (*close)(struct msm_snddev_info *);
+		int (*set_freq)(struct msm_snddev_info *, u32);
+		int (*enable_sidetone)(struct msm_snddev_info *, u32, uint16_t);
+		int (*set_device_volume)(struct msm_snddev_info *, u32);
+		int (*enable_anc)(struct msm_snddev_info *, u32);
+	} dev_ops;
+	u8 opened;
+	void *private_data;
+	bool state;
+	u32 sample_rate;
+	u32 channel_mode;
+	u32 set_sample_rate;
+	u64 sessions;
+	int usage_count;
+	s32 max_voc_rx_vol[VOC_RX_VOL_ARRAY_NUM]; /* [0] is for NB,[1] for WB */
+	s32 min_voc_rx_vol[VOC_RX_VOL_ARRAY_NUM];
+};
+
+struct msm_volume {
+	int volume; /* Volume parameter, in % Scale */
+	int pan;
+};
+
+extern struct msm_volume msm_vol_ctl;
+
+void msm_snddev_register(struct msm_snddev_info *);
+void msm_snddev_unregister(struct msm_snddev_info *);
+int msm_snddev_devcount(void);
+int msm_snddev_query(int dev_id);
+unsigned short msm_snddev_route_dec(int popp_id);
+unsigned short msm_snddev_route_enc(int enc_id);
+
+int msm_snddev_set_dec(int popp_id, int copp_id, int set,
+					int rate, int channel_mode);
+int msm_snddev_set_enc(int popp_id, int copp_id, int set,
+					int rate, int channel_mode);
+
+int msm_snddev_is_set(int popp_id, int copp_id);
+int msm_get_voc_route(u32 *rx_id, u32 *tx_id);
+int msm_set_voc_route(struct msm_snddev_info *dev_info, int stream_type,
+			int dev_id);
+int msm_snddev_enable_sidetone(u32 dev_id, u32 enable, uint16_t gain);
+
+int msm_set_copp_id(int session_id, int copp_id);
+
+int msm_clear_copp_id(int session_id, int copp_id);
+
+int msm_clear_session_id(int session_id);
+
+int msm_reset_all_device(void);
+
+int reset_device(void);
+
+int msm_clear_all_session(void);
+
+struct msm_snddev_info *audio_dev_ctrl_find_dev(u32 dev_id);
+
+void msm_release_voc_thread(void);
+
+int snddev_voice_set_volume(int vol, int path);
+
+struct auddev_evt_voc_devinfo {
+	u32 dev_type; /* Rx or Tx */
+	u32 acdb_dev_id; /* acdb id of device */
+	u32 dev_sample;  /* Sample rate of device */
+	s32 max_rx_vol[VOC_RX_VOL_ARRAY_NUM]; /* unit is mb (milibel),
+						[0] is for NB, other for WB */
+	s32 min_rx_vol[VOC_RX_VOL_ARRAY_NUM]; /* unit is mb */
+	u32 dev_id; /* registered device id */
+	u32 dev_port_id;
+};
+
+struct auddev_evt_audcal_info {
+	u32 dev_id;
+	u32 acdb_id;
+	u32 sample_rate;
+	u32 dev_type;
+	u32 sessions;
+};
+
+union msm_vol_mute {
+	int vol;
+	bool mute;
+};
+
+struct auddev_evt_voc_mute_info {
+	u32 dev_type;
+	u32 acdb_dev_id;
+	u32 voice_session_id;
+	union msm_vol_mute dev_vm_val;
+};
+
+struct auddev_evt_freq_info {
+	u32 dev_type;
+	u32 acdb_dev_id;
+	u32 sample_rate;
+};
+
+union auddev_evt_data {
+	struct auddev_evt_voc_devinfo voc_devinfo;
+	struct auddev_evt_voc_mute_info voc_vm_info;
+	struct auddev_evt_freq_info freq_info;
+	u32 routing_id;
+	s32 session_vol;
+	s32 voice_state;
+	struct auddev_evt_audcal_info audcal_info;
+	u32 voice_session_id;
+};
+
+struct message_header {
+	uint32_t id;
+	uint32_t data_len;
+};
+
+#define AUDDEV_EVT_DEV_CHG_VOICE 0x01 /* device change event */
+#define AUDDEV_EVT_DEV_RDY 0x02 /* device ready event */
+#define AUDDEV_EVT_DEV_RLS 0x04 /* device released event */
+#define AUDDEV_EVT_REL_PENDING 0x08 /* device release pending */
+#define AUDDEV_EVT_DEVICE_VOL_MUTE_CHG 0x10 /* device volume changed */
+#define AUDDEV_EVT_START_VOICE 0x20 /* voice call start */
+#define AUDDEV_EVT_END_VOICE 0x40 /* voice call end */
+#define AUDDEV_EVT_STREAM_VOL_CHG 0x80 /* device volume changed */
+#define AUDDEV_EVT_FREQ_CHG 0x100 /* Change in freq */
+#define AUDDEV_EVT_VOICE_STATE_CHG 0x200 /* Change in voice state */
+
+#define AUDDEV_CLNT_VOC 0x1 /*Vocoder clients*/
+#define AUDDEV_CLNT_DEC 0x2 /*Decoder clients*/
+#define AUDDEV_CLNT_ENC 0x3 /* Encoder clients */
+#define AUDDEV_CLNT_AUDIOCAL 0x4 /* AudioCalibration client */
+
+#define AUDIO_DEV_CTL_MAX_LISTNER 20 /* Max Listeners Supported */
+
+struct msm_snd_evt_listner {
+	uint32_t evt_id;
+	uint32_t clnt_type;
+	uint32_t clnt_id;
+	void *private_data;
+	void (*auddev_evt_listener)(u32 evt_id,
+		union auddev_evt_data *evt_payload,
+		void *private_data);
+	struct msm_snd_evt_listner *cb_next;
+	struct msm_snd_evt_listner *cb_prev;
+};
+
+struct event_listner {
+	struct msm_snd_evt_listner *cb;
+	u32 num_listner;
+	int state; /* Call state */ /* TODO remove this if not req*/
+};
+
+extern struct event_listner event;
+int auddev_register_evt_listner(u32 evt_id, u32 clnt_type, u32 clnt_id,
+		void (*listner)(u32 evt_id,
+			union auddev_evt_data *evt_payload,
+			void *private_data),
+		void *private_data);
+int auddev_unregister_evt_listner(u32 clnt_type, u32 clnt_id);
+void mixer_post_event(u32 evt_id, u32 dev_id);
+void broadcast_event(u32 evt_id, u32 dev_id, u64 session_id);
+int auddev_cfg_tx_copp_topology(int session_id, int cfg);
+int msm_snddev_request_freq(int *freq, u32 session_id,
+			u32 capability, u32 clnt_type);
+int msm_snddev_withdraw_freq(u32 session_id,
+			u32 capability, u32 clnt_type);
+int msm_device_is_voice(int dev_id);
+int msm_get_voc_freq(int *tx_freq, int *rx_freq);
+int msm_snddev_get_enc_freq(int session_id);
+int msm_set_voice_vol(int dir, s32 volume, u32 session_id);
+int msm_set_voice_mute(int dir, int mute, u32 session_id);
+int msm_get_voice_state(void);
+int msm_enable_incall_recording(int popp_id, int rec_mode, int rate,
+				int channel_mode);
+int msm_disable_incall_recording(uint32_t popp_id, uint32_t rec_mode);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/dsp_debug.h b/arch/arm/mach-msm/include/mach/qdsp6v2/dsp_debug.h
new file mode 100644
index 0000000..94f4ab4
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/dsp_debug.h
@@ -0,0 +1,22 @@
+/* Copyright (c) 2010, 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 __DSP_DEBUG_H_
+#define __DSP_DEBUG_H_
+
+typedef int (*dsp_state_cb)(int state);
+int dsp_debug_register(dsp_state_cb ptr);
+
+#define DSP_STATE_CRASHED         0x0
+#define DSP_STATE_CRASH_DUMP_DONE 0x1
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/q6voice.h b/arch/arm/mach-msm/include/mach/qdsp6v2/q6voice.h
new file mode 100644
index 0000000..674cfe8
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/q6voice.h
@@ -0,0 +1,778 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __QDSP6VOICE_H__
+#define __QDSP6VOICE_H__
+
+#include <mach/qdsp6v2/apr.h>
+
+/* Device Event */
+#define DEV_CHANGE_READY                0x1
+
+#define VOICE_CALL_START        0x1
+#define VOICE_CALL_END          0
+
+#define VOICE_DEV_ENABLED       0x1
+#define VOICE_DEV_DISABLED      0
+
+#define MAX_VOC_PKT_SIZE 642
+
+#define SESSION_NAME_LEN 20
+
+struct voice_header {
+	uint32_t id;
+	uint32_t data_len;
+};
+
+struct voice_init {
+	struct voice_header hdr;
+	void *cb_handle;
+};
+
+
+/* Device information payload structure */
+
+struct device_data {
+	uint32_t dev_acdb_id;
+	uint32_t volume; /* in percentage */
+	uint32_t mute;
+	uint32_t sample;
+	uint32_t enabled;
+	uint32_t dev_id;
+	uint32_t dev_port_id;
+};
+
+enum {
+	VOC_INIT = 0,
+	VOC_RUN,
+	VOC_CHANGE,
+	VOC_RELEASE,
+};
+
+/* TO MVM commands */
+#define VSS_IMVM_CMD_CREATE_PASSIVE_CONTROL_SESSION	0x000110FF
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IMVM_CMD_CREATE_FULL_CONTROL_SESSION	0x000110FE
+/* Create a new full control MVM session. */
+
+#define APRV2_IBASIC_CMD_DESTROY_SESSION		0x0001003C
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IMVM_CMD_ATTACH_STREAM			0x0001123C
+/* Attach a stream to the MVM. */
+
+#define VSS_IMVM_CMD_DETACH_STREAM			0x0001123D
+/* Detach a stream from the MVM. */
+
+#define VSS_IMVM_CMD_ATTACH_VOCPROC			0x0001123E
+/* Attach a vocproc to the MVM. The MVM will symmetrically connect this vocproc
+ * to all the streams currently attached to it.
+ */
+
+#define VSS_IMVM_CMD_DETACH_VOCPROC			0x0001123F
+/* Detach a vocproc from the MVM. The MVM will symmetrically disconnect this
+ * vocproc from all the streams to which it is currently attached.
+ */
+
+#define VSS_IMVM_CMD_START_VOICE			0x00011190
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IMVM_CMD_STOP_VOICE				0x00011192
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_ISTREAM_CMD_ATTACH_VOCPROC			0x000110F8
+/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_ISTREAM_CMD_DETACH_VOCPROC			0x000110F9
+/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+
+#define VSS_ISTREAM_CMD_SET_TTY_MODE			0x00011196
+/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_ICOMMON_CMD_SET_NETWORK			0x0001119C
+/* Set the network type. */
+
+#define VSS_ICOMMON_CMD_SET_VOICE_TIMING		0x000111E0
+/* Set the voice timing parameters. */
+
+struct vss_imvm_cmd_create_control_session_t {
+	char name[SESSION_NAME_LEN];
+	/*
+	 * A variable-sized stream name.
+	 *
+	 * The stream name size is the payload size minus the size of the other
+	 * fields.
+	 */
+} __packed;
+
+struct vss_istream_cmd_set_tty_mode_t {
+	uint32_t mode;
+	/**<
+	* TTY mode.
+	*
+	* 0 : TTY disabled
+	* 1 : HCO
+	* 2 : VCO
+	* 3 : FULL
+	*/
+} __attribute__((packed));
+
+struct vss_istream_cmd_attach_vocproc_t {
+	uint16_t handle;
+	/**< Handle of vocproc being attached. */
+} __attribute__((packed));
+
+struct vss_istream_cmd_detach_vocproc_t {
+	uint16_t handle;
+	/**< Handle of vocproc being detached. */
+} __attribute__((packed));
+
+struct vss_imvm_cmd_attach_stream_t {
+	uint16_t handle;
+	/* The stream handle to attach. */
+} __attribute__((packed));
+
+struct vss_imvm_cmd_detach_stream_t {
+	uint16_t handle;
+	/* The stream handle to detach. */
+} __attribute__((packed));
+
+struct vss_icommon_cmd_set_network_t {
+	uint32_t network_id;
+	/* Network ID. (Refer to VSS_NETWORK_ID_XXX). */
+} __attribute__((packed));
+
+struct vss_icommon_cmd_set_voice_timing_t {
+	uint16_t mode;
+	/*
+	 * The vocoder frame synchronization mode.
+	 *
+	 * 0 : No frame sync.
+	 * 1 : Hard VFR (20ms Vocoder Frame Reference interrupt).
+	 */
+	uint16_t enc_offset;
+	/*
+	 * The offset in microseconds from the VFR to deliver a Tx vocoder
+	 * packet. The offset should be less than 20000us.
+	 */
+	uint16_t dec_req_offset;
+	/*
+	 * The offset in microseconds from the VFR to request for an Rx vocoder
+	 * packet. The offset should be less than 20000us.
+	 */
+	uint16_t dec_offset;
+	/*
+	 * The offset in microseconds from the VFR to indicate the deadline to
+	 * receive an Rx vocoder packet. The offset should be less than 20000us.
+	 * Rx vocoder packets received after this deadline are not guaranteed to
+	 * be processed.
+	 */
+} __attribute__((packed));
+
+struct mvm_attach_vocproc_cmd {
+	struct apr_hdr hdr;
+	struct vss_istream_cmd_attach_vocproc_t mvm_attach_cvp_handle;
+} __attribute__((packed));
+
+struct mvm_detach_vocproc_cmd {
+	struct apr_hdr hdr;
+	struct vss_istream_cmd_detach_vocproc_t mvm_detach_cvp_handle;
+} __attribute__((packed));
+
+struct mvm_create_ctl_session_cmd {
+	struct apr_hdr hdr;
+	struct vss_imvm_cmd_create_control_session_t mvm_session;
+} __packed;
+
+struct mvm_set_tty_mode_cmd {
+	struct apr_hdr hdr;
+	struct vss_istream_cmd_set_tty_mode_t tty_mode;
+} __attribute__((packed));
+
+struct mvm_attach_stream_cmd {
+	struct apr_hdr hdr;
+	struct vss_imvm_cmd_attach_stream_t attach_stream;
+} __attribute__((packed));
+
+struct mvm_detach_stream_cmd {
+	struct apr_hdr hdr;
+	struct vss_imvm_cmd_detach_stream_t detach_stream;
+} __attribute__((packed));
+
+struct mvm_set_network_cmd {
+	struct apr_hdr hdr;
+	struct vss_icommon_cmd_set_network_t network;
+} __attribute__((packed));
+
+struct mvm_set_voice_timing_cmd {
+	struct apr_hdr hdr;
+	struct vss_icommon_cmd_set_voice_timing_t timing;
+} __attribute__((packed));
+
+/* TO CVS commands */
+#define VSS_ISTREAM_CMD_CREATE_PASSIVE_CONTROL_SESSION	0x00011140
+/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_ISTREAM_CMD_CREATE_FULL_CONTROL_SESSION	0x000110F7
+/* Create a new full control stream session. */
+
+#define APRV2_IBASIC_CMD_DESTROY_SESSION		0x0001003C
+
+#define VSS_ISTREAM_CMD_CACHE_CALIBRATION_DATA		0x000110FB
+
+#define VSS_ISTREAM_CMD_SET_MUTE			0x00011022
+
+#define VSS_ISTREAM_CMD_SET_MEDIA_TYPE			0x00011186
+/* Set media type on the stream. */
+
+#define VSS_ISTREAM_EVT_SEND_ENC_BUFFER			0x00011015
+/* Event sent by the stream to its client to provide an encoded packet. */
+
+#define VSS_ISTREAM_EVT_REQUEST_DEC_BUFFER		0x00011017
+/* Event sent by the stream to its client requesting for a decoder packet.
+ * The client should respond with a VSS_ISTREAM_EVT_SEND_DEC_BUFFER event.
+ */
+
+#define VSS_ISTREAM_EVT_SEND_DEC_BUFFER			0x00011016
+/* Event sent by the client to the stream in response to a
+ * VSS_ISTREAM_EVT_REQUEST_DEC_BUFFER event, providing a decoder packet.
+ */
+
+#define VSS_ISTREAM_CMD_VOC_AMR_SET_ENC_RATE		0x0001113E
+/* Set AMR encoder rate. */
+
+#define VSS_ISTREAM_CMD_VOC_AMRWB_SET_ENC_RATE		0x0001113F
+/* Set AMR-WB encoder rate. */
+
+#define VSS_ISTREAM_CMD_CDMA_SET_ENC_MINMAX_RATE	0x00011019
+/* Set encoder minimum and maximum rate. */
+
+#define VSS_ISTREAM_CMD_SET_ENC_DTX_MODE		0x0001101D
+/* Set encoder DTX mode. */
+
+#define VSS_ISTREAM_CMD_START_RECORD			0x00011236
+/* Start in-call conversation recording. */
+
+#define VSS_ISTREAM_CMD_STOP_RECORD			0x00011237
+/* Stop in-call conversation recording. */
+
+#define VSS_ISTREAM_CMD_START_PLAYBACK			0x00011238
+/* Start in-call music delivery on the Tx voice path. */
+
+#define VSS_ISTREAM_CMD_STOP_PLAYBACK			0x00011239
+/* Stop the in-call music delivery on the Tx voice path. */
+
+struct vss_istream_cmd_create_passive_control_session_t {
+	char name[SESSION_NAME_LEN];
+	/**<
+	* A variable-sized stream name.
+	*
+	* The stream name size is the payload size minus the size of the other
+	* fields.
+	*/
+} __attribute__((packed));
+
+struct vss_istream_cmd_set_mute_t {
+	uint16_t direction;
+	/**<
+	* 0 : TX only
+	* 1 : RX only
+	* 2 : TX and Rx
+	*/
+	uint16_t mute_flag;
+	/**<
+	* Mute, un-mute.
+	*
+	* 0 : Silence disable
+	* 1 : Silence enable
+	* 2 : CNG enable. Applicable to TX only. If set on RX behavior
+	*     will be the same as 1
+	*/
+} __attribute__((packed));
+
+struct vss_istream_cmd_create_full_control_session_t {
+	uint16_t direction;
+	/*
+	 * Stream direction.
+	 *
+	 * 0 : TX only
+	 * 1 : RX only
+	 * 2 : TX and RX
+	 * 3 : TX and RX loopback
+	 */
+	uint32_t enc_media_type;
+	/* Tx vocoder type. (Refer to VSS_MEDIA_ID_XXX). */
+	uint32_t dec_media_type;
+	/* Rx vocoder type. (Refer to VSS_MEDIA_ID_XXX). */
+	uint32_t network_id;
+	/* Network ID. (Refer to VSS_NETWORK_ID_XXX). */
+	char name[SESSION_NAME_LEN];
+	/*
+	 * A variable-sized stream name.
+	 *
+	 * The stream name size is the payload size minus the size of the other
+	 * fields.
+	 */
+} __attribute__((packed));
+
+struct vss_istream_cmd_set_media_type_t {
+	uint32_t rx_media_id;
+	/* Set the Rx vocoder type. (Refer to VSS_MEDIA_ID_XXX). */
+	uint32_t tx_media_id;
+	/* Set the Tx vocoder type. (Refer to VSS_MEDIA_ID_XXX). */
+} __attribute__((packed));
+
+struct vss_istream_evt_send_enc_buffer_t {
+	uint32_t media_id;
+      /* Media ID of the packet. */
+	uint8_t packet_data[MAX_VOC_PKT_SIZE];
+      /* Packet data buffer. */
+} __attribute__((packed));
+
+struct vss_istream_evt_send_dec_buffer_t {
+	uint32_t media_id;
+      /* Media ID of the packet. */
+	uint8_t packet_data[MAX_VOC_PKT_SIZE];
+      /* Packet data. */
+} __attribute__((packed));
+
+struct vss_istream_cmd_voc_amr_set_enc_rate_t {
+	uint32_t mode;
+	/* Set the AMR encoder rate.
+	 *
+	 * 0x00000000 : 4.75 kbps
+	 * 0x00000001 : 5.15 kbps
+	 * 0x00000002 : 5.90 kbps
+	 * 0x00000003 : 6.70 kbps
+	 * 0x00000004 : 7.40 kbps
+	 * 0x00000005 : 7.95 kbps
+	 * 0x00000006 : 10.2 kbps
+	 * 0x00000007 : 12.2 kbps
+	 */
+} __attribute__((packed));
+
+struct vss_istream_cmd_voc_amrwb_set_enc_rate_t {
+	uint32_t mode;
+	/* Set the AMR-WB encoder rate.
+	 *
+	 * 0x00000000 :  6.60 kbps
+	 * 0x00000001 :  8.85 kbps
+	 * 0x00000002 : 12.65 kbps
+	 * 0x00000003 : 14.25 kbps
+	 * 0x00000004 : 15.85 kbps
+	 * 0x00000005 : 18.25 kbps
+	 * 0x00000006 : 19.85 kbps
+	 * 0x00000007 : 23.05 kbps
+	 * 0x00000008 : 23.85 kbps
+	 */
+} __attribute__((packed));
+
+struct vss_istream_cmd_cdma_set_enc_minmax_rate_t {
+	uint16_t min_rate;
+	/* Set the lower bound encoder rate.
+	 *
+	 * 0x0000 : Blank frame
+	 * 0x0001 : Eighth rate
+	 * 0x0002 : Quarter rate
+	 * 0x0003 : Half rate
+	 * 0x0004 : Full rate
+	 */
+	uint16_t max_rate;
+	/* Set the upper bound encoder rate.
+	 *
+	 * 0x0000 : Blank frame
+	 * 0x0001 : Eighth rate
+	 * 0x0002 : Quarter rate
+	 * 0x0003 : Half rate
+	 * 0x0004 : Full rate
+	 */
+} __attribute__((packed));
+
+struct vss_istream_cmd_set_enc_dtx_mode_t {
+	uint32_t enable;
+	/* Toggle DTX on or off.
+	 *
+	 * 0 : Disables DTX
+	 * 1 : Enables DTX
+	 */
+} __attribute__((packed));
+
+#define VSS_TAP_POINT_NONE				0x00010F78
+/* Indicates no tapping for specified path. */
+
+#define VSS_TAP_POINT_STREAM_END			0x00010F79
+/* Indicates that specified path should be tapped at the end of the stream. */
+
+struct vss_istream_cmd_start_record_t {
+	uint32_t rx_tap_point;
+	/* Tap point to use on the Rx path. Supported values are:
+	 * VSS_TAP_POINT_NONE : Do not record Rx path.
+	 * VSS_TAP_POINT_STREAM_END : Rx tap point is at the end of the stream.
+	 */
+	uint32_t tx_tap_point;
+	/* Tap point to use on the Tx path. Supported values are:
+	 * VSS_TAP_POINT_NONE : Do not record tx path.
+	 * VSS_TAP_POINT_STREAM_END : Tx tap point is at the end of the stream.
+	 */
+} __attribute__((packed));
+
+struct cvs_create_passive_ctl_session_cmd {
+	struct apr_hdr hdr;
+	struct vss_istream_cmd_create_passive_control_session_t cvs_session;
+} __attribute__((packed));
+
+struct cvs_create_full_ctl_session_cmd {
+	struct apr_hdr hdr;
+	struct vss_istream_cmd_create_full_control_session_t cvs_session;
+} __attribute__((packed));
+
+struct cvs_destroy_session_cmd {
+	struct apr_hdr hdr;
+} __attribute__((packed));
+
+struct cvs_cache_calibration_data_cmd {
+	struct apr_hdr hdr;
+} __attribute__ ((packed));
+
+struct cvs_set_mute_cmd {
+	struct apr_hdr hdr;
+	struct vss_istream_cmd_set_mute_t cvs_set_mute;
+} __attribute__((packed));
+
+struct cvs_set_media_type_cmd {
+	struct apr_hdr hdr;
+	struct vss_istream_cmd_set_media_type_t media_type;
+} __attribute__((packed));
+
+struct cvs_send_dec_buf_cmd {
+	struct apr_hdr hdr;
+	struct vss_istream_evt_send_dec_buffer_t dec_buf;
+} __attribute__((packed));
+
+struct cvs_set_amr_enc_rate_cmd {
+	struct apr_hdr hdr;
+	struct vss_istream_cmd_voc_amr_set_enc_rate_t amr_rate;
+} __attribute__((packed));
+
+struct cvs_set_amrwb_enc_rate_cmd {
+	struct apr_hdr hdr;
+	struct vss_istream_cmd_voc_amrwb_set_enc_rate_t amrwb_rate;
+} __attribute__((packed));
+
+struct cvs_set_cdma_enc_minmax_rate_cmd {
+	struct apr_hdr hdr;
+	struct vss_istream_cmd_cdma_set_enc_minmax_rate_t cdma_rate;
+} __attribute__((packed));
+
+struct cvs_set_enc_dtx_mode_cmd {
+	struct apr_hdr hdr;
+	struct vss_istream_cmd_set_enc_dtx_mode_t dtx_mode;
+} __attribute__((packed));
+
+struct cvs_start_record_cmd {
+		struct apr_hdr hdr;
+		struct vss_istream_cmd_start_record_t rec_mode;
+} __attribute__((packed));
+
+/* TO CVP commands */
+
+#define VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION	0x000100C3
+/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define APRV2_IBASIC_CMD_DESTROY_SESSION		0x0001003C
+
+#define VSS_IVOCPROC_CMD_SET_DEVICE			0x000100C4
+
+#define VSS_IVOCPROC_CMD_CACHE_CALIBRATION_DATA		0x000110E3
+
+#define VSS_IVOCPROC_CMD_CACHE_VOLUME_CALIBRATION_TABLE	0x000110E4
+
+#define VSS_IVOCPROC_CMD_SET_VP3_DATA			0x000110EB
+
+#define VSS_IVOCPROC_CMD_SET_RX_VOLUME_INDEX		0x000110EE
+
+#define VSS_IVOCPROC_CMD_ENABLE				0x000100C6
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IVOCPROC_CMD_DISABLE			0x000110E1
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IVOCPROC_TOPOLOGY_ID_NONE			0x00010F70
+#define VSS_IVOCPROC_TOPOLOGY_ID_TX_SM_ECNS		0x00010F71
+#define VSS_IVOCPROC_TOPOLOGY_ID_TX_DM_FLUENCE		0x00010F72
+
+#define VSS_IVOCPROC_TOPOLOGY_ID_RX_DEFAULT		0x00010F77
+
+/* Newtwork IDs */
+#define VSS_NETWORK_ID_DEFAULT				0x00010037
+#define VSS_NETWORK_ID_VOIP_NB				0x00011240
+#define VSS_NETWORK_ID_VOIP_WB				0x00011241
+#define VSS_NETWORK_ID_VOIP_WV				0x00011242
+
+/* Media types */
+#define VSS_MEDIA_ID_13K_MODEM		0x00010FC1
+/* Qcelp vocoder modem format */
+#define VSS_MEDIA_ID_EVRC_MODEM		0x00010FC2
+/* 80-VF690-47 CDMA enhanced variable rate vocoder modem format. */
+#define VSS_MEDIA_ID_4GV_NB_MODEM  0x00010FC3
+/* 4GV Narrowband modem format */
+#define VSS_MEDIA_ID_4GV_WB_MODEM  0x00010FC4
+/* 4GV Wideband modem format */
+#define VSS_MEDIA_ID_AMR_NB_MODEM	0x00010FC6
+/* 80-VF690-47 UMTS AMR-NB vocoder modem format. */
+#define VSS_MEDIA_ID_AMR_WB_MODEM	0x00010FC7
+/* 80-VF690-47 UMTS AMR-WB vocoder modem format. */
+#define VSS_MEDIA_ID_EFR_MODEM		0x00010FC8
+/*EFR modem format */
+#define VSS_MEDIA_ID_FR_MODEM		0x00010FC9
+/*FR modem format */
+#define VSS_MEDIA_ID_HR_MODEM		0x00010FCA
+/*HR modem format */
+#define VSS_MEDIA_ID_PCM_NB		0x00010FCB
+/* Linear PCM (16-bit, little-endian). */
+#define VSS_MEDIA_ID_PCM_WB		0x00010FCC
+/* Linear wideband PCM vocoder modem format (16 bits, little endian). */
+#define VSS_MEDIA_ID_G711_ALAW		0x00010FCD
+/* G.711 a-law (contains two 10ms vocoder frames). */
+#define VSS_MEDIA_ID_G711_MULAW		0x00010FCE
+/* G.711 mu-law (contains two 10ms vocoder frames). */
+#define VSS_MEDIA_ID_G729		0x00010FD0
+/* G.729AB (contains two 10ms vocoder frames. */
+
+#define VOICE_CMD_SET_PARAM				0x00011006
+#define VOICE_CMD_GET_PARAM				0x00011007
+#define VOICE_EVT_GET_PARAM_ACK				0x00011008
+
+struct vss_ivocproc_cmd_create_full_control_session_t {
+	uint16_t direction;
+	/*
+	 * stream direction.
+	 * 0 : TX only
+	 * 1 : RX only
+	 * 2 : TX and RX
+	 */
+	uint32_t tx_port_id;
+	/*
+	 * TX device port ID which vocproc will connect to. If not supplying a
+	 * port ID set to VSS_IVOCPROC_PORT_ID_NONE.
+	 */
+	uint32_t tx_topology_id;
+	/*
+	 * Tx leg topology ID. If not supplying a topology ID set to
+	 * VSS_IVOCPROC_TOPOLOGY_ID_NONE.
+	 */
+	uint32_t rx_port_id;
+	/*
+	 * RX device port ID which vocproc will connect to. If not supplying a
+	 * port ID set to VSS_IVOCPROC_PORT_ID_NONE.
+	 */
+	uint32_t rx_topology_id;
+	/*
+	 * Rx leg topology ID. If not supplying a topology ID set to
+	 * VSS_IVOCPROC_TOPOLOGY_ID_NONE.
+	 */
+	int32_t network_id;
+	/*
+	 * Network ID. (Refer to VSS_NETWORK_ID_XXX). If not supplying a network
+	 * ID set to VSS_NETWORK_ID_DEFAULT.
+	 */
+} __attribute__((packed));
+
+struct vss_ivocproc_cmd_set_device_t {
+	uint32_t tx_port_id;
+	/**<
+	* TX device port ID which vocproc will connect to.
+	* VSS_IVOCPROC_PORT_ID_NONE means vocproc will not connect to any port.
+	*/
+	uint32_t tx_topology_id;
+	/**<
+	* TX leg topology ID.
+	* VSS_IVOCPROC_TOPOLOGY_ID_NONE means vocproc does not contain any
+	* pre/post-processing blocks and is pass-through.
+	*/
+	int32_t rx_port_id;
+	/**<
+	* RX device port ID which vocproc will connect to.
+	* VSS_IVOCPROC_PORT_ID_NONE means vocproc will not connect to any port.
+	*/
+	uint32_t rx_topology_id;
+	/**<
+	* RX leg topology ID.
+	* VSS_IVOCPROC_TOPOLOGY_ID_NONE means vocproc does not contain any
+	* pre/post-processing blocks and is pass-through.
+	*/
+} __attribute__((packed));
+
+struct vss_ivocproc_cmd_set_volume_index_t {
+	uint16_t vol_index;
+	/**<
+	* Volume index utilized by the vocproc to index into the volume table
+	* provided in VSS_IVOCPROC_CMD_CACHE_VOLUME_CALIBRATION_TABLE and set
+	* volume on the VDSP.
+	*/
+} __attribute__((packed));
+
+struct cvp_create_full_ctl_session_cmd {
+	struct apr_hdr hdr;
+	struct vss_ivocproc_cmd_create_full_control_session_t cvp_session;
+} __attribute__ ((packed));
+
+struct cvp_command {
+	struct apr_hdr hdr;
+} __attribute__((packed));
+
+struct cvp_set_device_cmd {
+	struct apr_hdr hdr;
+	struct vss_ivocproc_cmd_set_device_t cvp_set_device;
+} __attribute__ ((packed));
+
+struct cvp_cache_calibration_data_cmd {
+	struct apr_hdr hdr;
+} __attribute__((packed));
+
+struct cvp_cache_volume_calibration_table_cmd {
+	struct apr_hdr hdr;
+} __attribute__((packed));
+
+struct cvp_set_vp3_data_cmd {
+	struct apr_hdr hdr;
+} __attribute__((packed));
+
+struct cvp_set_rx_volume_index_cmd {
+	struct apr_hdr hdr;
+	struct vss_ivocproc_cmd_set_volume_index_t cvp_set_vol_idx;
+} __attribute__((packed));
+
+/* CB for up-link packets. */
+typedef void (*ul_cb_fn)(uint8_t *voc_pkt,
+			 uint32_t pkt_len,
+			 void *private_data);
+
+/* CB for down-link packets. */
+typedef void (*dl_cb_fn)(uint8_t *voc_pkt,
+			 uint32_t *pkt_len,
+			 void *private_data);
+
+struct q_min_max_rate {
+	uint32_t min_rate;
+	uint32_t max_rate;
+};
+
+struct mvs_driver_info {
+	uint32_t media_type;
+	uint32_t rate;
+	uint32_t network_type;
+	uint32_t dtx_mode;
+	struct q_min_max_rate q_min_max_rate;
+	ul_cb_fn ul_cb;
+	dl_cb_fn dl_cb;
+	void *private_data;
+};
+
+struct incall_rec_info {
+	uint32_t pending;
+	uint32_t rec_mode;
+};
+
+struct incall_music_info {
+	uint32_t pending;
+	uint32_t playing;
+};
+
+struct voice_data {
+	int voc_state;/*INIT, CHANGE, RELEASE, RUN */
+
+	wait_queue_head_t mvm_wait;
+	wait_queue_head_t cvs_wait;
+	wait_queue_head_t cvp_wait;
+
+	/* cache the values related to Rx and Tx */
+	struct device_data dev_rx;
+	struct device_data dev_tx;
+
+	/* call status */
+	int v_call_status; /* Start or End */
+
+	u32 mvm_state;
+	u32 cvs_state;
+	u32 cvp_state;
+
+	/* Handle to MVM */
+	u16 mvm_handle;
+	/* Handle to CVS */
+	u16 cvs_handle;
+	/* Handle to CVP */
+	u16 cvp_handle;
+
+	struct mutex lock;
+
+	struct incall_rec_info rec_info;
+
+	struct incall_music_info music_info;
+
+	u16 session_id;
+};
+
+#define MAX_VOC_SESSIONS 2
+#define SESSION_ID_BASE 0xFFF0
+
+struct common_data {
+	uint32_t voc_path;
+	uint32_t adsp_version;
+	uint32_t device_events;
+
+	/* These default values are for all devices */
+	uint32_t default_mute_val;
+	uint32_t default_vol_val;
+	uint32_t default_sample_val;
+
+	/* APR to MVM in the modem */
+	void *apr_mvm;
+	/* APR to CVS in the modem */
+	void *apr_cvs;
+	/* APR to CVP in the modem */
+	void *apr_cvp;
+
+	/* APR to MVM in the Q6 */
+	void *apr_q6_mvm;
+	/* APR to CVS in the Q6 */
+	void *apr_q6_cvs;
+	/* APR to CVP in the Q6 */
+	void *apr_q6_cvp;
+
+	struct mutex common_lock;
+
+	struct mvs_driver_info mvs_info;
+
+	struct voice_data voice[MAX_VOC_SESSIONS];
+};
+
+int voice_set_voc_path_full(uint32_t set);
+
+void voice_register_mvs_cb(ul_cb_fn ul_cb,
+			   dl_cb_fn dl_cb,
+			   void *private_data);
+
+void voice_config_vocoder(uint32_t media_type,
+			  uint32_t rate,
+			  uint32_t network_type,
+			  uint32_t dtx_mode,
+			  struct q_min_max_rate q_min_max_rate);
+
+int voice_start_record(uint32_t rec_mode, uint32_t set);
+
+int voice_start_playback(uint32_t set);
+
+u16 voice_get_session_id(const char *name);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/rtac.h b/arch/arm/mach-msm/include/mach/qdsp6v2/rtac.h
new file mode 100644
index 0000000..f5bea31
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/rtac.h
@@ -0,0 +1,39 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __RTAC_H__
+#define __RTAC_H__
+
+/* Voice Modes */
+#define RTAC_CVP		0
+#define RTAC_CVS		1
+#define RTAC_VOICE_MODES	2
+
+void rtac_add_adm_device(u32 port_id, u32 copp_id, u32 path_id, u32 popp_id);
+void rtac_remove_adm_device(u32 port_id);
+void rtac_remove_popp_from_adm_devices(u32 popp_id);
+void rtac_add_voice(u32 cvs_handle, u32 cvp_handle, u32 rx_afe_port,
+	u32 tx_afe_port, u32 session_id);
+void rtac_remove_voice(u32 cvs_handle);
+void rtac_set_adm_handle(void *handle);
+bool rtac_make_adm_callback(uint32_t *payload, u32 payload_size);
+void rtac_copy_adm_payload_to_user(void *payload, u32 payload_size);
+void rtac_set_asm_handle(u32 session_id, void *handle);
+bool rtac_make_asm_callback(u32 session_id, uint32_t *payload,
+	u32 payload_size);
+void rtac_copy_asm_payload_to_user(void *payload, u32 payload_size);
+void rtac_set_voice_handle(u32 mode, void *handle);
+bool rtac_make_voice_callback(u32 mode, uint32_t *payload, u32 payload_size);
+void rtac_copy_voice_payload_to_user(void *payload, u32 payload_size);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h b/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
new file mode 100644
index 0000000..bd303b2
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
@@ -0,0 +1,268 @@
+/* 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
+ * 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 __USF_H__
+#define __USF_H__
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define USF_IOCTL_MAGIC 'U'
+
+#define US_SET_TX_INFO   _IOW(USF_IOCTL_MAGIC, 0, \
+				struct us_tx_info_type)
+#define US_START_TX      _IO(USF_IOCTL_MAGIC, 1)
+#define US_GET_TX_UPDATE _IOWR(USF_IOCTL_MAGIC, 2, \
+				struct us_tx_update_info_type)
+#define US_SET_RX_INFO   _IOW(USF_IOCTL_MAGIC, 3, \
+				struct us_rx_info_type)
+#define US_SET_RX_UPDATE _IOWR(USF_IOCTL_MAGIC, 4, \
+				struct us_rx_update_info_type)
+#define US_START_RX      _IO(USF_IOCTL_MAGIC, 5)
+
+#define US_STOP_TX      _IO(USF_IOCTL_MAGIC, 6)
+#define US_STOP_RX      _IO(USF_IOCTL_MAGIC, 7)
+
+#define US_SET_DETECTION _IOWR(USF_IOCTL_MAGIC, 8, \
+				struct us_detect_info_type)
+
+#define US_GET_VERSION  _IOWR(USF_IOCTL_MAGIC, 9, \
+				struct us_version_info_type)
+
+/* Special timeout values */
+#define USF_NO_WAIT_TIMEOUT	0x00000000
+/* Infinitive */
+#define USF_INFINITIVE_TIMEOUT	0xffffffff
+/* Default value, used by the driver */
+#define USF_DEFAULT_TIMEOUT	0xfffffffe
+
+/* US detection place (HW|FW) */
+enum us_detect_place_enum {
+/* US is detected in HW */
+	US_DETECT_HW,
+/* US is detected in FW */
+	US_DETECT_FW
+};
+
+/* US detection mode */
+enum us_detect_mode_enum {
+/* US detection is disabled */
+	US_DETECT_DISABLED_MODE,
+/* US detection is enabled in continue mode */
+	US_DETECT_CONTINUE_MODE,
+/* US detection is enabled in one shot mode */
+	US_DETECT_SHOT_MODE
+};
+
+/* Encoder (TX), decoder (RX) supported US data formats */
+#define USF_POINT_EPOS_FORMAT	0
+#define USF_RAW_FORMAT		1
+
+/* Types of events, produced by the calculators */
+#define USF_NO_EVENT 0
+#define USF_TSC_EVENT 1
+#define USF_MOUSE_EVENT 2
+#define USF_KEYBOARD_EVENT 4
+#define USF_ALL_EVENTS (USF_TSC_EVENT | USF_MOUSE_EVENT | USF_KEYBOARD_EVENT)
+
+/* min, max array dimension */
+#define MIN_MAX_DIM 2
+
+/* coordinates (x,y,z) array dimension */
+#define COORDINATES_DIM 3
+
+/* tilts (x,y) array dimension */
+#define TILTS_DIM 2
+
+/* Max size of the client name */
+#define USF_MAX_CLIENT_NAME_SIZE	20
+/* Info structure common for TX and RX */
+struct us_xx_info_type {
+/* Input:  general info */
+/* Name of the client - event calculator */
+	const char *client_name;
+/* Selected device identification, accepted in the kernel's CAD */
+	uint32_t dev_id;
+/* 0 - point_epos type; (e.g. 1 - gr_mmrd) */
+	uint32_t stream_format;
+/* Required sample rate in Hz */
+	uint32_t sample_rate;
+/* Size of a buffer (bytes) for US data transfer between the module and USF */
+	uint32_t buf_size;
+/* Number of the buffers for the US data transfer */
+	uint16_t buf_num;
+/* Number of the microphones (TX) or speakers(RX) */
+	uint16_t port_cnt;
+/* Microphones(TX) or speakers(RX) indexes in their enumeration */
+	uint8_t  port_id[4];
+/* Bits per sample 16 or 32 */
+	uint16_t bits_per_sample;
+/* Input:  Transparent info for encoder in the LPASS */
+/* Parameters data size in bytes */
+	uint16_t params_data_size;
+/* Pointer to the parameters */
+	uint8_t *params_data;
+};
+
+/* Input events sources */
+enum us_input_event_src_type {
+	US_INPUT_SRC_PEN,
+	US_INPUT_SRC_FINGER,
+	US_INPUT_SRC_UNDEF
+};
+
+struct us_input_info_type {
+	/* Touch screen dimensions: min & max;for input module */
+	int tsc_x_dim[MIN_MAX_DIM];
+	int tsc_y_dim[MIN_MAX_DIM];
+	int tsc_z_dim[MIN_MAX_DIM];
+	/* Touch screen tilt dimensions: min & max;for input module */
+	int tsc_x_tilt[MIN_MAX_DIM];
+	int tsc_y_tilt[MIN_MAX_DIM];
+	/* Touch screen pressure limits: min & max; for input module */
+	int tsc_pressure[MIN_MAX_DIM];
+	/* Bitmap of types of events (USF_X_EVENT), produced by calculator */
+	uint16_t event_types;
+	/* Input event source */
+	enum us_input_event_src_type event_src;
+	/* Bitmap of types of events from devs, conflicting with USF */
+	uint16_t conflicting_event_types;
+};
+
+struct us_tx_info_type {
+	/* Common info */
+	struct us_xx_info_type us_xx_info;
+	/* Info specific for TX*/
+	struct us_input_info_type input_info;
+};
+
+struct us_rx_info_type {
+	/* Common info */
+	struct us_xx_info_type us_xx_info;
+	/* Info specific for RX*/
+};
+
+
+#define	USF_PIX_COORDINATE  0 /* unit is pixel */
+#define	USF_CMM_COORDINATE  1 /* unit is 0.01 mm */
+struct point_event_type {
+/* Pen coordinates (x, y, z) in units, defined by <coordinates_type>  */
+	int coordinates[COORDINATES_DIM];
+	/* {x;y}  in transparent units */
+	int inclinations[TILTS_DIM];
+/* [0-1023] (10bits); 0 - pen up */
+	uint32_t pressure;
+/* 0 - mapped in the display pixel. 1 - raw in 0.01 mm (only for log); */
+	uint8_t coordinates_type;
+};
+
+/* Mouse buttons, supported by USF */
+#define USF_BUTTON_LEFT_MASK   1
+#define USF_BUTTON_MIDDLE_MASK 2
+#define USF_BUTTON_RIGHT_MASK  4
+struct mouse_event_type {
+/* The mouse relative movement (dX, dY, dZ) */
+	int rels[COORDINATES_DIM];
+/* Bitmap of mouse buttons states: 1 - down, 0 - up; */
+	uint16_t buttons_states;
+};
+
+struct key_event_type {
+/*  Calculated MS key- see input.h. */
+	uint32_t key;
+/* Keyboard's key state: 1 - down, 0 - up; */
+	uint8_t key_state;
+};
+
+struct usf_event_type {
+/* Event sequence number */
+	uint32_t seq_num;
+/* Event generation system time */
+	uint32_t timestamp;
+/* Destination input event type (e.g. touch screen, mouse, key) */
+	uint16_t event_type;
+	union {
+		struct point_event_type point_event;
+		struct mouse_event_type mouse_event;
+		struct key_event_type   key_event;
+	} event_data;
+};
+
+struct us_tx_update_info_type {
+/* Input  general: */
+/* Number of calculated events */
+	uint16_t event_counter;
+/* Calculated events or NULL */
+	struct usf_event_type *event;
+/* Pointer (read index) to the end of available region */
+/* in the shared US data memory */
+	uint32_t free_region;
+/* Time (sec) to wait for data or special values: */
+/* USF_NO_WAIT_TIMEOUT, USF_INFINITIVE_TIMEOUT, USF_DEFAULT_TIMEOUT */
+	uint32_t timeout;
+/* Events (from conflicting devs) to be disabled/enabled */
+	uint16_t event_filters;
+
+/* Input  transparent data: */
+/* Parameters size */
+	uint16_t params_data_size;
+/* Pointer to the parameters */
+	uint8_t *params_data;
+/* Output parameters: */
+/* Pointer (write index) to the end of ready US data region */
+/* in the shared memory */
+	uint32_t ready_region;
+};
+
+struct us_rx_update_info_type {
+/* Input  general: */
+/* Pointer (write index) to the end of ready US data region */
+/* in the shared memory */
+	uint32_t ready_region;
+/* Input  transparent data: */
+/* Parameters size */
+	uint16_t params_data_size;
+/* pPointer to the parameters */
+	uint8_t *params_data;
+/* Output parameters: */
+/* Pointer (read index) to the end of available region */
+/* in the shared US data memory */
+	uint32_t free_region;
+};
+
+struct us_detect_info_type {
+/* US detection place (HW|FW) */
+/* NA in the Active and OFF states */
+	enum us_detect_place_enum us_detector;
+/* US detection mode */
+	enum us_detect_mode_enum  us_detect_mode;
+/* US data dropped during this time (msec) */
+	uint32_t skip_time;
+/* Transparent data size */
+	uint16_t params_data_size;
+/* Pointer to the transparent data */
+	uint8_t *params_data;
+/* Time (sec) to wait for US presence event */
+	uint32_t detect_timeout;
+/* Out parameter: US presence */
+	bool is_us;
+};
+
+struct us_version_info_type {
+/* Size of memory for the version string */
+	uint16_t buf_size;
+/* Pointer to the memory for the version string */
+	char *pbuf;
+};
+
+#endif /* __USF_H__ */
diff --git a/arch/arm/mach-msm/include/mach/qdss.h b/arch/arm/mach-msm/include/mach/qdss.h
new file mode 100644
index 0000000..05d8577
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdss.h
@@ -0,0 +1,54 @@
+/* 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 __MACH_QDSS_H
+#define __MACH_QDSS_H
+
+struct qdss_source {
+	struct list_head link;
+	const char *name;
+	uint32_t fport_mask;
+};
+
+struct msm_qdss_platform_data {
+	struct qdss_source *src_table;
+	size_t size;
+	uint8_t afamily;
+};
+
+#ifdef CONFIG_MSM_QDSS
+extern struct qdss_source *qdss_get(const char *name);
+extern void qdss_put(struct qdss_source *src);
+extern int qdss_enable(struct qdss_source *src);
+extern void qdss_disable(struct qdss_source *src);
+extern void qdss_disable_sink(void);
+extern int qdss_clk_enable(void);
+extern void qdss_clk_disable(void);
+#else
+static inline struct qdss_source *qdss_get(const char *name) { return NULL; }
+static inline void qdss_put(struct qdss_source *src) {}
+static inline int qdss_enable(struct qdss_source *src) { return -ENOSYS; }
+static inline void qdss_disable(struct qdss_source *src) {}
+static inline void qdss_disable_sink(void) {}
+static inline int qdss_clk_enable(void) { return -ENOSYS; }
+static inline void qdss_clk_disable(void) {}
+#endif
+
+#ifdef CONFIG_MSM_JTAG
+extern void msm_jtag_save_state(void);
+extern void msm_jtag_restore_state(void);
+#else
+static inline void msm_jtag_save_state(void) {}
+static inline void msm_jtag_restore_state(void) {}
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qpnp-int.h b/arch/arm/mach-msm/include/mach/qpnp-int.h
new file mode 100644
index 0000000..a79d2fc
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qpnp-int.h
@@ -0,0 +1,83 @@
+/* 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 QPNPINT_H
+#define QPNPINT_H
+
+#include <linux/spmi.h>
+
+struct qpnp_irq_spec {
+	uint8_t slave; /* 0-15 */
+	uint8_t per; /* 0-255 */
+	uint8_t irq; /* 0-7 */
+};
+
+struct qpnp_local_int {
+	 /* mask - Invoke PMIC Arbiter local mask handler */
+	int (*mask)(struct spmi_controller *spmi_ctrl,
+		    struct qpnp_irq_spec *spec,
+		    uint32_t priv_d);
+	 /* unmask - Invoke PMIC Arbiter local unmask handler */
+	int (*unmask)(struct spmi_controller *spmi_ctrl,
+		      struct qpnp_irq_spec *spec,
+		      uint32_t priv_d);
+	/* register_priv_data - Return per irq priv data */
+	int (*register_priv_data)(struct spmi_controller *spmi_ctrl,
+				  struct qpnp_irq_spec *spec,
+				  uint32_t *priv_d);
+};
+
+#ifdef CONFIG_MSM_QPNP_INT
+/**
+ * qpnpint_of_init() - Device Tree irq initialization
+ *
+ * Standard Device Tree init routine to be called from
+ * of_irq_init().
+ */
+int __init qpnpint_of_init(struct device_node *node,
+			   struct device_node *parent);
+
+/**
+ * qpnpint_register_controller() - Register local interrupt callbacks
+ *
+ * Used by the PMIC Arbiter driver or equivalent to register
+ * callbacks for interrupt events.
+ */
+int qpnpint_register_controller(unsigned int busno,
+				struct qpnp_local_int *li_cb);
+
+/**
+ * qpnpint_handle_irq - Main interrupt handling routine
+ *
+ * Pass a PMIC Arbiter interrupt to Linux.
+ */
+int qpnpint_handle_irq(struct spmi_controller *spmi_ctrl,
+		       struct qpnp_irq_spec *spec);
+#else
+static inline int __init qpnpint_of_init(struct device_node *node,
+				  struct device_node *parent)
+{
+	return -ENXIO;
+}
+static inline int qpnpint_register_controller(unsigned int busno,
+				struct qpnp_local_int *li_cb)
+{
+	return -ENXIO;
+}
+
+static inline int qpnpint_handle_irq(struct spmi_controller *spmi_ctrl,
+		       struct qpnp_irq_spec *spec)
+{
+	return -ENXIO;
+}
+#endif /* CONFIG_MSM_QPNP_INT */
+#endif /* QPNPINT_H */
diff --git a/arch/arm/mach-msm/include/mach/qpnp.h b/arch/arm/mach-msm/include/mach/qpnp.h
new file mode 100644
index 0000000..1d2e440
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qpnp.h
@@ -0,0 +1,19 @@
+ /* 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/spmi.h>
+
+struct resource *qpnp_get_resource(struct spmi_device *dev,
+				   unsigned int node_idx, unsigned int type,
+				   unsigned int res_num);
+int qpnp_get_irq(struct spmi_device *dev, unsigned int node_idx,
+					  unsigned int res_num);
diff --git a/arch/arm/mach-msm/include/mach/remote_spinlock.h b/arch/arm/mach-msm/include/mach/remote_spinlock.h
new file mode 100644
index 0000000..75b70f3
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/remote_spinlock.h
@@ -0,0 +1,299 @@
+/* Copyright (c) 2009, 2011 Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/*
+ * Part of this this code is based on the standard ARM spinlock
+ * implementation (asm/spinlock.h) found in the 2.6.29 kernel.
+ */
+
+#ifndef __ASM__ARCH_QC_REMOTE_SPINLOCK_H
+#define __ASM__ARCH_QC_REMOTE_SPINLOCK_H
+
+#include <linux/io.h>
+#include <linux/types.h>
+
+/* Remote spinlock definitions. */
+
+struct dek_spinlock {
+	volatile uint8_t self_lock;
+	volatile uint8_t other_lock;
+	volatile uint8_t next_yield;
+	uint8_t pad;
+};
+
+typedef union {
+	volatile uint32_t lock;
+	struct dek_spinlock dek;
+} raw_remote_spinlock_t;
+
+typedef raw_remote_spinlock_t *_remote_spinlock_t;
+
+#define remote_spinlock_id_t const char *
+#define SMEM_SPINLOCK_PID_APPS 1
+
+static inline void __raw_remote_ex_spin_lock(raw_remote_spinlock_t *lock)
+{
+	unsigned long tmp;
+
+	__asm__ __volatile__(
+"1:	ldrex	%0, [%1]\n"
+"	teq	%0, #0\n"
+"	strexeq	%0, %2, [%1]\n"
+"	teqeq	%0, #0\n"
+"	bne	1b"
+	: "=&r" (tmp)
+	: "r" (&lock->lock), "r" (1)
+	: "cc");
+
+	smp_mb();
+}
+
+static inline int __raw_remote_ex_spin_trylock(raw_remote_spinlock_t *lock)
+{
+	unsigned long tmp;
+
+	__asm__ __volatile__(
+"	ldrex	%0, [%1]\n"
+"	teq	%0, #0\n"
+"	strexeq	%0, %2, [%1]\n"
+	: "=&r" (tmp)
+	: "r" (&lock->lock), "r" (1)
+	: "cc");
+
+	if (tmp == 0) {
+		smp_mb();
+		return 1;
+	}
+	return 0;
+}
+
+static inline void __raw_remote_ex_spin_unlock(raw_remote_spinlock_t *lock)
+{
+	smp_mb();
+
+	__asm__ __volatile__(
+"	str	%1, [%0]\n"
+	:
+	: "r" (&lock->lock), "r" (0)
+	: "cc");
+}
+
+static inline void __raw_remote_swp_spin_lock(raw_remote_spinlock_t *lock)
+{
+	unsigned long tmp;
+
+	__asm__ __volatile__(
+"1:	swp	%0, %2, [%1]\n"
+"	teq	%0, #0\n"
+"	bne	1b"
+	: "=&r" (tmp)
+	: "r" (&lock->lock), "r" (1)
+	: "cc");
+
+	smp_mb();
+}
+
+static inline int __raw_remote_swp_spin_trylock(raw_remote_spinlock_t *lock)
+{
+	unsigned long tmp;
+
+	__asm__ __volatile__(
+"	swp	%0, %2, [%1]\n"
+	: "=&r" (tmp)
+	: "r" (&lock->lock), "r" (1)
+	: "cc");
+
+	if (tmp == 0) {
+		smp_mb();
+		return 1;
+	}
+	return 0;
+}
+
+static inline void __raw_remote_swp_spin_unlock(raw_remote_spinlock_t *lock)
+{
+	smp_mb();
+
+	__asm__ __volatile__(
+"	str	%1, [%0]"
+	:
+	: "r" (&lock->lock), "r" (0)
+	: "cc");
+}
+
+#define DEK_LOCK_REQUEST		1
+#define DEK_LOCK_YIELD			(!DEK_LOCK_REQUEST)
+#define DEK_YIELD_TURN_SELF		0
+static inline void __raw_remote_dek_spin_lock(raw_remote_spinlock_t *lock)
+{
+	lock->dek.self_lock = DEK_LOCK_REQUEST;
+
+	while (lock->dek.other_lock) {
+
+		if (lock->dek.next_yield == DEK_YIELD_TURN_SELF)
+			lock->dek.self_lock = DEK_LOCK_YIELD;
+
+		while (lock->dek.other_lock)
+			;
+
+		lock->dek.self_lock = DEK_LOCK_REQUEST;
+	}
+	lock->dek.next_yield = DEK_YIELD_TURN_SELF;
+
+	smp_mb();
+}
+
+static inline int __raw_remote_dek_spin_trylock(raw_remote_spinlock_t *lock)
+{
+	lock->dek.self_lock = DEK_LOCK_REQUEST;
+
+	if (lock->dek.other_lock) {
+		lock->dek.self_lock = DEK_LOCK_YIELD;
+		return 0;
+	}
+
+	lock->dek.next_yield = DEK_YIELD_TURN_SELF;
+
+	smp_mb();
+	return 1;
+}
+
+static inline void __raw_remote_dek_spin_unlock(raw_remote_spinlock_t *lock)
+{
+	smp_mb();
+
+	lock->dek.self_lock = DEK_LOCK_YIELD;
+}
+
+static inline int __raw_remote_dek_spin_release(raw_remote_spinlock_t *lock,
+		uint32_t pid)
+{
+	return -EINVAL;
+}
+
+static inline void __raw_remote_sfpb_spin_lock(raw_remote_spinlock_t *lock)
+{
+	do {
+		writel_relaxed(SMEM_SPINLOCK_PID_APPS, lock);
+		smp_mb();
+	} while (readl_relaxed(lock) != SMEM_SPINLOCK_PID_APPS);
+}
+
+static inline int __raw_remote_sfpb_spin_trylock(raw_remote_spinlock_t *lock)
+{
+	return 1;
+}
+
+static inline void __raw_remote_sfpb_spin_unlock(raw_remote_spinlock_t *lock)
+{
+	writel_relaxed(0, lock);
+	smp_mb();
+}
+
+/**
+ * Release spinlock if it is owned by @pid.
+ *
+ * This is only to be used for situations where the processor owning
+ * the spinlock has crashed and the spinlock must be released.
+ *
+ * @lock - lock structure
+ * @pid - processor ID of processor to release
+ */
+static inline int __raw_remote_gen_spin_release(raw_remote_spinlock_t *lock,
+		uint32_t pid)
+{
+	int ret = 1;
+
+	if (readl_relaxed(&lock->lock) == pid) {
+		writel_relaxed(0, &lock->lock);
+		wmb();
+		ret = 0;
+	}
+	return ret;
+}
+
+#if defined(CONFIG_MSM_SMD) || defined(CONFIG_MSM_REMOTE_SPINLOCK_SFPB)
+int _remote_spin_lock_init(remote_spinlock_id_t, _remote_spinlock_t *lock);
+void _remote_spin_release_all(uint32_t pid);
+#else
+static inline
+int _remote_spin_lock_init(remote_spinlock_id_t id, _remote_spinlock_t *lock)
+{
+	return -EINVAL;
+}
+static inline void _remote_spin_release_all(uint32_t pid) {}
+#endif
+
+#if defined(CONFIG_MSM_REMOTE_SPINLOCK_DEKKERS)
+/* Use Dekker's algorithm when LDREX/STREX and SWP are unavailable for
+ * shared memory */
+#define _remote_spin_lock(lock)		__raw_remote_dek_spin_lock(*lock)
+#define _remote_spin_unlock(lock)	__raw_remote_dek_spin_unlock(*lock)
+#define _remote_spin_trylock(lock)	__raw_remote_dek_spin_trylock(*lock)
+#define _remote_spin_release(lock, pid)	__raw_remote_dek_spin_release(*lock,\
+		pid)
+#elif defined(CONFIG_MSM_REMOTE_SPINLOCK_SWP)
+/* Use SWP-based locks when LDREX/STREX are unavailable for shared memory. */
+#define _remote_spin_lock(lock)		__raw_remote_swp_spin_lock(*lock)
+#define _remote_spin_unlock(lock)	__raw_remote_swp_spin_unlock(*lock)
+#define _remote_spin_trylock(lock)	__raw_remote_swp_spin_trylock(*lock)
+#define _remote_spin_release(lock, pid)	__raw_remote_gen_spin_release(*lock,\
+		pid)
+#elif defined(CONFIG_MSM_REMOTE_SPINLOCK_SFPB)
+/* Use SFPB Hardware Mutex Registers */
+#define _remote_spin_lock(lock)		__raw_remote_sfpb_spin_lock(*lock)
+#define _remote_spin_unlock(lock)	__raw_remote_sfpb_spin_unlock(*lock)
+#define _remote_spin_trylock(lock)	__raw_remote_sfpb_spin_trylock(*lock)
+#define _remote_spin_release(lock, pid)	__raw_remote_gen_spin_release(*lock,\
+		pid)
+#else
+/* Use LDREX/STREX for shared memory locking, when available */
+#define _remote_spin_lock(lock)		__raw_remote_ex_spin_lock(*lock)
+#define _remote_spin_unlock(lock)	__raw_remote_ex_spin_unlock(*lock)
+#define _remote_spin_trylock(lock)	__raw_remote_ex_spin_trylock(*lock)
+#define _remote_spin_release(lock, pid)	__raw_remote_gen_spin_release(*lock, \
+		pid)
+#endif
+
+/* Remote mutex definitions. */
+
+typedef struct {
+	_remote_spinlock_t	r_spinlock;
+	uint32_t		delay_us;
+} _remote_mutex_t;
+
+struct remote_mutex_id {
+	remote_spinlock_id_t	r_spinlock_id;
+	uint32_t		delay_us;
+};
+
+#ifdef CONFIG_MSM_SMD
+int _remote_mutex_init(struct remote_mutex_id *id, _remote_mutex_t *lock);
+void _remote_mutex_lock(_remote_mutex_t *lock);
+void _remote_mutex_unlock(_remote_mutex_t *lock);
+int _remote_mutex_trylock(_remote_mutex_t *lock);
+#else
+static inline
+int _remote_mutex_init(struct remote_mutex_id *id, _remote_mutex_t *lock)
+{
+	return -EINVAL;
+}
+static inline void _remote_mutex_lock(_remote_mutex_t *lock) {}
+static inline void _remote_mutex_unlock(_remote_mutex_t *lock) {}
+static inline int _remote_mutex_trylock(_remote_mutex_t *lock)
+{
+	return 0;
+}
+#endif
+
+#endif /* __ASM__ARCH_QC_REMOTE_SPINLOCK_H */
diff --git a/arch/arm/mach-msm/include/mach/restart.h b/arch/arm/mach-msm/include/mach/restart.h
new file mode 100644
index 0000000..84df9bc
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/restart.h
@@ -0,0 +1,29 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _ASM_ARCH_MSM_RESTART_H_
+#define _ASM_ARCH_MSM_RESTART_H_
+
+#define RESTART_NORMAL 0x0
+#define RESTART_DLOAD  0x1
+
+#ifdef CONFIG_MSM_NATIVE_RESTART
+void msm_set_restart_mode(int mode);
+#else
+#define msm_set_restart_mode(mode)
+#endif
+
+extern int pmic_reset_irq;
+
+#endif
+
diff --git a/arch/arm/mach-msm/include/mach/rpc_hsusb.h b/arch/arm/mach-msm/include/mach/rpc_hsusb.h
new file mode 100644
index 0000000..88d7650
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/rpc_hsusb.h
@@ -0,0 +1,99 @@
+/* linux/include/mach/rpc_hsusb.h
+ *
+ * Copyright (c) 2008-2010, 2012 Code Aurora Forum. All rights reserved.
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+
+#ifndef __ASM_ARCH_MSM_RPC_HSUSB_H
+#define __ASM_ARCH_MSM_RPC_HSUSB_H
+
+#include <mach/msm_rpcrouter.h>
+#include <mach/msm_otg.h>
+#include <mach/msm_hsusb.h>
+
+#if defined(CONFIG_MSM_ONCRPCROUTER) && !defined(CONFIG_ARCH_MSM8X60)
+int msm_hsusb_rpc_connect(void);
+int msm_hsusb_phy_reset(void);
+int msm_hsusb_vbus_powerup(void);
+int msm_hsusb_vbus_shutdown(void);
+int msm_hsusb_reset_rework_installed(void);
+int msm_hsusb_enable_pmic_ulpidata0(void);
+int msm_hsusb_disable_pmic_ulpidata0(void);
+int msm_hsusb_rpc_close(void);
+
+int msm_chg_rpc_connect(void);
+int msm_chg_usb_charger_connected(uint32_t type);
+int msm_chg_usb_i_is_available(uint32_t sample);
+int msm_chg_usb_i_is_not_available(void);
+int msm_chg_usb_charger_disconnected(void);
+int msm_chg_rpc_close(void);
+
+#ifdef CONFIG_USB_MSM_72K
+int hsusb_chg_init(int connect);
+void hsusb_chg_vbus_draw(unsigned mA);
+void hsusb_chg_connected(enum chg_type chgtype);
+#endif
+
+
+int msm_fsusb_rpc_init(struct msm_otg_ops *ops);
+int msm_fsusb_init_phy(void);
+int msm_fsusb_reset_phy(void);
+int msm_fsusb_suspend_phy(void);
+int msm_fsusb_resume_phy(void);
+int msm_fsusb_rpc_close(void);
+int msm_fsusb_remote_dev_disconnected(void);
+int msm_fsusb_set_remote_wakeup(void);
+void msm_fsusb_rpc_deinit(void);
+
+/* wrapper to send pid and serial# info to bootloader */
+int usb_diag_update_pid_and_serial_num(uint32_t pid, const char *snum);
+#else
+static inline int msm_hsusb_rpc_connect(void) { return 0; }
+static inline int msm_hsusb_phy_reset(void) { return 0; }
+static inline int msm_hsusb_vbus_powerup(void) { return 0; }
+static inline int msm_hsusb_vbus_shutdown(void) { return 0; }
+static inline int msm_hsusb_reset_rework_installed(void) { return 0; }
+static inline int msm_hsusb_enable_pmic_ulpidata0(void) { return 0; }
+static inline int msm_hsusb_disable_pmic_ulpidata0(void) { return 0; }
+static inline int msm_hsusb_rpc_close(void) { return 0; }
+
+static inline int msm_chg_rpc_connect(void) { return 0; }
+static inline int msm_chg_usb_charger_connected(uint32_t type) { return 0; }
+static inline int msm_chg_usb_i_is_available(uint32_t sample) { return 0; }
+static inline int msm_chg_usb_i_is_not_available(void) { return 0; }
+static inline int msm_chg_usb_charger_disconnected(void) { return 0; }
+static inline int msm_chg_rpc_close(void) { return 0; }
+
+#ifdef CONFIG_USB_MSM_72K
+static inline int hsusb_chg_init(int connect) { return 0; }
+static inline void hsusb_chg_vbus_draw(unsigned mA) { }
+static inline void hsusb_chg_connected(enum chg_type chgtype) { }
+#endif
+
+static inline int msm_fsusb_rpc_init(struct msm_otg_ops *ops) { return 0; }
+static inline int msm_fsusb_init_phy(void) { return 0; }
+static inline int msm_fsusb_reset_phy(void) { return 0; }
+static inline int msm_fsusb_suspend_phy(void) { return 0; }
+static inline int msm_fsusb_resume_phy(void) { return 0; }
+static inline int msm_fsusb_rpc_close(void) { return 0; }
+static inline int msm_fsusb_remote_dev_disconnected(void) { return 0; }
+static inline int msm_fsusb_set_remote_wakeup(void) { return 0; }
+static inline void msm_fsusb_rpc_deinit(void) { }
+static inline int
+usb_diag_update_pid_and_serial_num(uint32_t pid, const char *snum) { return 0; }
+#endif
+#endif
diff --git a/arch/arm/mach-msm/include/mach/rpc_pmapp.h b/arch/arm/mach-msm/include/mach/rpc_pmapp.h
new file mode 100644
index 0000000..86f04bf
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/rpc_pmapp.h
@@ -0,0 +1,76 @@
+/* Copyright (c) 2009-2010, 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 __ASM_ARCH_MSM_RPC_PMAPP_H
+#define __ASM_ARCH_MSM_RPC_PMAPP_H
+
+#include <mach/msm_rpcrouter.h>
+
+/* Clock voting ids */
+enum {
+	PMAPP_CLOCK_ID_DO = 0,
+	PMAPP_CLOCK_ID_D1,
+	PMAPP_CLOCK_ID_A0,
+	PMAPP_CLOCK_ID_A1,
+};
+
+/* Clock voting types */
+enum {
+	PMAPP_CLOCK_VOTE_OFF = 0,
+	PMAPP_CLOCK_VOTE_ON,
+	PMAPP_CLOCK_VOTE_PIN_CTRL,
+};
+
+/* vreg ids */
+enum {
+	PMAPP_VREG_LDO22 = 14,
+	PMAPP_VREG_S3 = 21,
+	PMAPP_VREG_S2 = 23,
+	PMAPP_VREG_S4 = 24,
+};
+
+/* SMPS clock voting types */
+enum {
+	PMAPP_SMPS_CLK_VOTE_DONTCARE = 0,
+	PMAPP_SMPS_CLK_VOTE_2P74,	/* 2.74 MHz */
+	PMAPP_SMPS_CLK_VOTE_1P6,	/* 1.6 MHz */
+};
+
+/* SMPS mode voting types */
+enum {
+	PMAPP_SMPS_MODE_VOTE_DONTCARE = 0,
+	PMAPP_SMPS_MODE_VOTE_PWM,
+	PMAPP_SMPS_MODE_VOTE_PFM,
+	PMAPP_SMPS_MODE_VOTE_AUTO
+};
+
+int msm_pm_app_rpc_init(void(*callback)(int online));
+void msm_pm_app_rpc_deinit(void(*callback)(int online));
+int msm_pm_app_register_vbus_sn(void (*callback)(int online));
+void msm_pm_app_unregister_vbus_sn(void (*callback)(int online));
+int msm_pm_app_enable_usb_ldo(int);
+int pmic_vote_3p3_pwr_sel_switch(int boost);
+
+int pmapp_display_clock_config(uint enable);
+
+int pmapp_clock_vote(const char *voter_id, uint clock_id, uint vote);
+int pmapp_smps_clock_vote(const char *voter_id, uint vreg_id, uint vote);
+int pmapp_vreg_level_vote(const char *voter_id, uint vreg_id, uint level);
+int pmapp_smps_mode_vote(const char *voter_id, uint vreg_id, uint mode);
+int pmapp_vreg_pincntrl_vote(const char *voter_id, uint vreg_id,
+					uint clock_id, uint vote);
+int pmapp_disp_backlight_set_brightness(int value);
+void pmapp_disp_backlight_init(void);
+int pmapp_vreg_lpm_pincntrl_vote(const char *voter_id, uint vreg_id,
+					uint clock_id, uint vote);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/rpc_server_handset.h b/arch/arm/mach-msm/include/mach/rpc_server_handset.h
new file mode 100644
index 0000000..e1dc841
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/rpc_server_handset.h
@@ -0,0 +1,24 @@
+/* Copyright (c) 2009-2010, 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 __ASM_ARCH_MSM_RPC_SERVER_HANDSET_H
+#define __ASM_ARCH_MSM_RPC_SERVER_HANDSET_H
+
+struct msm_handset_platform_data {
+	const char *hs_name;
+	uint32_t pwr_key_delay_ms; /* default 500ms */
+};
+
+void report_headset_status(bool connected);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/rpm-8064.h b/arch/arm/mach-msm/include/mach/rpm-8064.h
new file mode 100644
index 0000000..c4c6b0a
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/rpm-8064.h
@@ -0,0 +1,432 @@
+/* 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 __ARCH_ARM_MACH_MSM_RPM_8064_H
+#define __ARCH_ARM_MACH_MSM_RPM_8064_H
+
+/* RPM control message RAM enums */
+enum {
+	MSM_RPM_8064_CTRL_VERSION_MAJOR,
+	MSM_RPM_8064_CTRL_VERSION_MINOR,
+	MSM_RPM_8064_CTRL_VERSION_BUILD,
+
+	MSM_RPM_8064_CTRL_REQ_CTX_0,
+	MSM_RPM_8064_CTRL_REQ_CTX_7 = MSM_RPM_8064_CTRL_REQ_CTX_0 + 7,
+	MSM_RPM_8064_CTRL_REQ_SEL_0,
+	MSM_RPM_8064_CTRL_REQ_SEL_3 = MSM_RPM_8064_CTRL_REQ_SEL_0 + 3,
+	MSM_RPM_8064_CTRL_ACK_CTX_0,
+	MSM_RPM_8064_CTRL_ACK_CTX_7 = MSM_RPM_8064_CTRL_ACK_CTX_0 + 7,
+	MSM_RPM_8064_CTRL_ACK_SEL_0,
+	MSM_RPM_8064_CTRL_ACK_SEL_7 = MSM_RPM_8064_CTRL_ACK_SEL_0 + 7,
+};
+
+/* RPM resource select enums defined for RPM core
+   NOT IN SEQUENTIAL ORDER */
+enum {
+	MSM_RPM_8064_SEL_NOTIFICATION					= 0,
+	MSM_RPM_8064_SEL_INVALIDATE					= 1,
+	MSM_RPM_8064_SEL_TRIGGER_TIMED					= 2,
+	MSM_RPM_8064_SEL_RPM_CTL					= 3,
+
+	MSM_RPM_8064_SEL_CXO_CLK					= 5,
+	MSM_RPM_8064_SEL_PXO_CLK					= 6,
+	MSM_RPM_8064_SEL_QDSS_CLK					= 7,
+	MSM_RPM_8064_SEL_APPS_FABRIC_CLK				= 8,
+	MSM_RPM_8064_SEL_SYSTEM_FABRIC_CLK				= 9,
+	MSM_RPM_8064_SEL_MM_FABRIC_CLK					= 10,
+	MSM_RPM_8064_SEL_DAYTONA_FABRIC_CLK				= 11,
+	MSM_RPM_8064_SEL_SFPB_CLK					= 12,
+	MSM_RPM_8064_SEL_CFPB_CLK					= 13,
+	MSM_RPM_8064_SEL_MMFPB_CLK					= 14,
+	MSM_RPM_8064_SEL_EBI1_CLK					= 16,
+
+	MSM_RPM_8064_SEL_APPS_FABRIC_CFG_HALT				= 18,
+	MSM_RPM_8064_SEL_APPS_FABRIC_CFG_CLKMOD				= 19,
+	MSM_RPM_8064_SEL_APPS_FABRIC_CFG_IOCTL				= 20,
+	MSM_RPM_8064_SEL_APPS_FABRIC_ARB				= 21,
+
+	MSM_RPM_8064_SEL_SYS_FABRIC_CFG_HALT				= 22,
+	MSM_RPM_8064_SEL_SYS_FABRIC_CFG_CLKMOD				= 23,
+	MSM_RPM_8064_SEL_SYS_FABRIC_CFG_IOCTL				= 24,
+	MSM_RPM_8064_SEL_SYSTEM_FABRIC_ARB				= 25,
+
+	MSM_RPM_8064_SEL_MMSS_FABRIC_CFG_HALT				= 26,
+	MSM_RPM_8064_SEL_MMSS_FABRIC_CFG_CLKMOD				= 27,
+	MSM_RPM_8064_SEL_MMSS_FABRIC_CFG_IOCTL				= 28,
+	MSM_RPM_8064_SEL_MM_FABRIC_ARB					= 29,
+
+	MSM_RPM_8064_SEL_PM8921_S1					= 30,
+	MSM_RPM_8064_SEL_PM8921_S2					= 31,
+	MSM_RPM_8064_SEL_PM8921_S3					= 32,
+	MSM_RPM_8064_SEL_PM8921_S4					= 33,
+	MSM_RPM_8064_SEL_PM8921_S5					= 34,
+	MSM_RPM_8064_SEL_PM8921_S6					= 35,
+	MSM_RPM_8064_SEL_PM8921_S7					= 36,
+	MSM_RPM_8064_SEL_PM8921_S8					= 37,
+	MSM_RPM_8064_SEL_PM8921_L1					= 38,
+	MSM_RPM_8064_SEL_PM8921_L2					= 39,
+	MSM_RPM_8064_SEL_PM8921_L3					= 40,
+	MSM_RPM_8064_SEL_PM8921_L4					= 41,
+	MSM_RPM_8064_SEL_PM8921_L5					= 42,
+	MSM_RPM_8064_SEL_PM8921_L6					= 43,
+	MSM_RPM_8064_SEL_PM8921_L7					= 44,
+	MSM_RPM_8064_SEL_PM8921_L8					= 45,
+	MSM_RPM_8064_SEL_PM8921_L9					= 46,
+	MSM_RPM_8064_SEL_PM8921_L10					= 47,
+	MSM_RPM_8064_SEL_PM8921_L11					= 48,
+	MSM_RPM_8064_SEL_PM8921_L12					= 49,
+	MSM_RPM_8064_SEL_PM8921_L13					= 50,
+	MSM_RPM_8064_SEL_PM8921_L14					= 51,
+	MSM_RPM_8064_SEL_PM8921_L15					= 52,
+	MSM_RPM_8064_SEL_PM8921_L16					= 53,
+	MSM_RPM_8064_SEL_PM8921_L17					= 54,
+	MSM_RPM_8064_SEL_PM8921_L18					= 55,
+	MSM_RPM_8064_SEL_PM8921_L19					= 56,
+	MSM_RPM_8064_SEL_PM8921_L20					= 57,
+	MSM_RPM_8064_SEL_PM8921_L21					= 58,
+	MSM_RPM_8064_SEL_PM8921_L22					= 59,
+	MSM_RPM_8064_SEL_PM8921_L23					= 60,
+	MSM_RPM_8064_SEL_PM8921_L24					= 61,
+	MSM_RPM_8064_SEL_PM8921_L25					= 62,
+	MSM_RPM_8064_SEL_PM8921_L26					= 63,
+	MSM_RPM_8064_SEL_PM8921_L27					= 64,
+	MSM_RPM_8064_SEL_PM8921_L28					= 65,
+	MSM_RPM_8064_SEL_PM8921_L29					= 66,
+	MSM_RPM_8064_SEL_PM8921_CLK1					= 67,
+	MSM_RPM_8064_SEL_PM8921_CLK2					= 68,
+	MSM_RPM_8064_SEL_PM8921_LVS1					= 69,
+	MSM_RPM_8064_SEL_PM8921_LVS2					= 70,
+	MSM_RPM_8064_SEL_PM8921_LVS3					= 71,
+	MSM_RPM_8064_SEL_PM8921_LVS4					= 72,
+	MSM_RPM_8064_SEL_PM8921_LVS5					= 73,
+	MSM_RPM_8064_SEL_PM8921_LVS6					= 74,
+	MSM_RPM_8064_SEL_PM8921_LVS7					= 75,
+	MSM_RPM_8064_SEL_PM8821_S1					= 76,
+	MSM_RPM_8064_SEL_PM8821_S2					= 77,
+	MSM_RPM_8064_SEL_PM8821_L1					= 78,
+
+	MSM_RPM_8064_SEL_NCP						= 80,
+	MSM_RPM_8064_SEL_CXO_BUFFERS					= 81,
+	MSM_RPM_8064_SEL_USB_OTG_SWITCH					= 82,
+	MSM_RPM_8064_SEL_HDMI_SWITCH					= 83,
+	MSM_RPM_8064_SEL_DDR_DMM					= 84,
+
+	MSM_RPM_8064_SEL_LAST = MSM_RPM_8064_SEL_DDR_DMM,
+};
+
+/* RPM resource (4 byte) word ID enum */
+enum {
+	MSM_RPM_8064_ID_NOTIFICATION_CONFIGURED_0			= 0,
+	MSM_RPM_8064_ID_NOTIFICATION_CONFIGURED_3 =
+		MSM_RPM_8064_ID_NOTIFICATION_CONFIGURED_0 + 3,
+
+	MSM_RPM_8064_ID_NOTIFICATION_REGISTERED_0			= 4,
+	MSM_RPM_8064_ID_NOTIFICATION_REGISTERED_3 =
+		MSM_RPM_8064_ID_NOTIFICATION_REGISTERED_0 + 3,
+
+	MSM_RPM_8064_ID_INVALIDATE_0					= 8,
+	MSM_RPM_8064_ID_INVALIDATE_7 =
+		MSM_RPM_8064_ID_INVALIDATE_0 + 7,
+
+	MSM_RPM_8064_ID_TRIGGER_TIMED_TO				= 16,
+	MSM_RPM_8064_ID_TRIGGER_TIMED_SCLK_COUNT			= 17,
+
+	MSM_RPM_8064_ID_RPM_CTL						= 18,
+
+	/* TRIGGER_CLEAR/SET deprecated in these 24 RESERVED bytes */
+	MSM_RPM_8064_ID_RESERVED_0					= 19,
+	MSM_RPM_8064_ID_RESERVED_5 =
+		MSM_RPM_8064_ID_RESERVED_0 + 5,
+
+	MSM_RPM_8064_ID_CXO_CLK						= 25,
+	MSM_RPM_8064_ID_PXO_CLK						= 26,
+	MSM_RPM_8064_ID_APPS_FABRIC_CLK					= 27,
+	MSM_RPM_8064_ID_SYSTEM_FABRIC_CLK				= 28,
+	MSM_RPM_8064_ID_MM_FABRIC_CLK					= 29,
+	MSM_RPM_8064_ID_DAYTONA_FABRIC_CLK				= 30,
+	MSM_RPM_8064_ID_SFPB_CLK					= 31,
+	MSM_RPM_8064_ID_CFPB_CLK					= 32,
+	MSM_RPM_8064_ID_MMFPB_CLK					= 33,
+	MSM_RPM_8064_ID_EBI1_CLK					= 34,
+
+	MSM_RPM_8064_ID_APPS_FABRIC_CFG_HALT_0				= 35,
+	MSM_RPM_8064_ID_APPS_FABRIC_CFG_HALT_1				= 36,
+	MSM_RPM_8064_ID_APPS_FABRIC_CFG_CLKMOD_0			= 37,
+	MSM_RPM_8064_ID_APPS_FABRIC_CFG_CLKMOD_1			= 38,
+	MSM_RPM_8064_ID_APPS_FABRIC_CFG_CLKMOD_2			= 39,
+	MSM_RPM_8064_ID_APPS_FABRIC_CFG_IOCTL				= 40,
+	MSM_RPM_8064_ID_APPS_FABRIC_ARB_0				= 41,
+	MSM_RPM_8064_ID_APPS_FABRIC_ARB_11 =
+		MSM_RPM_8064_ID_APPS_FABRIC_ARB_0 + 11,
+
+	MSM_RPM_8064_ID_SYS_FABRIC_CFG_HALT_0				= 53,
+	MSM_RPM_8064_ID_SYS_FABRIC_CFG_HALT_1				= 54,
+	MSM_RPM_8064_ID_SYS_FABRIC_CFG_CLKMOD_0				= 55,
+	MSM_RPM_8064_ID_SYS_FABRIC_CFG_CLKMOD_1				= 56,
+	MSM_RPM_8064_ID_SYS_FABRIC_CFG_CLKMOD_2				= 57,
+	MSM_RPM_8064_ID_SYS_FABRIC_CFG_IOCTL				= 58,
+	MSM_RPM_8064_ID_SYSTEM_FABRIC_ARB_0				= 59,
+	MSM_RPM_8064_ID_SYSTEM_FABRIC_ARB_29 =
+		MSM_RPM_8064_ID_SYSTEM_FABRIC_ARB_0 + 29,
+
+	MSM_RPM_8064_ID_MMSS_FABRIC_CFG_HALT_0				= 89,
+	MSM_RPM_8064_ID_MMSS_FABRIC_CFG_HALT_1				= 90,
+	MSM_RPM_8064_ID_MMSS_FABRIC_CFG_CLKMOD_0			= 91,
+	MSM_RPM_8064_ID_MMSS_FABRIC_CFG_CLKMOD_1			= 92,
+	MSM_RPM_8064_ID_MMSS_FABRIC_CFG_CLKMOD_2			= 93,
+	MSM_RPM_8064_ID_MMSS_FABRIC_CFG_IOCTL				= 94,
+	MSM_RPM_8064_ID_MM_FABRIC_ARB_0					= 95,
+	MSM_RPM_8064_ID_MM_FABRIC_ARB_20 =
+		MSM_RPM_8064_ID_MM_FABRIC_ARB_0 + 20,
+
+	MSM_RPM_8064_ID_PM8921_S1_0					= 116,
+	MSM_RPM_8064_ID_PM8921_S1_1					= 117,
+	MSM_RPM_8064_ID_PM8921_S2_0					= 118,
+	MSM_RPM_8064_ID_PM8921_S2_1					= 119,
+	MSM_RPM_8064_ID_PM8921_S3_0					= 120,
+	MSM_RPM_8064_ID_PM8921_S3_1					= 121,
+	MSM_RPM_8064_ID_PM8921_S4_0					= 122,
+	MSM_RPM_8064_ID_PM8921_S4_1					= 123,
+	MSM_RPM_8064_ID_PM8921_S5_0					= 124,
+	MSM_RPM_8064_ID_PM8921_S5_1					= 125,
+	MSM_RPM_8064_ID_PM8921_S6_0					= 126,
+	MSM_RPM_8064_ID_PM8921_S6_1					= 127,
+	MSM_RPM_8064_ID_PM8921_S7_0					= 128,
+	MSM_RPM_8064_ID_PM8921_S7_1					= 129,
+	MSM_RPM_8064_ID_PM8921_S8_0					= 130,
+	MSM_RPM_8064_ID_PM8921_S8_1					= 131,
+	MSM_RPM_8064_ID_PM8921_L1_0					= 132,
+	MSM_RPM_8064_ID_PM8921_L1_1					= 133,
+	MSM_RPM_8064_ID_PM8921_L2_0					= 134,
+	MSM_RPM_8064_ID_PM8921_L2_1					= 135,
+	MSM_RPM_8064_ID_PM8921_L3_0					= 136,
+	MSM_RPM_8064_ID_PM8921_L3_1					= 137,
+	MSM_RPM_8064_ID_PM8921_L4_0					= 138,
+	MSM_RPM_8064_ID_PM8921_L4_1					= 139,
+	MSM_RPM_8064_ID_PM8921_L5_0					= 140,
+	MSM_RPM_8064_ID_PM8921_L5_1					= 141,
+	MSM_RPM_8064_ID_PM8921_L6_0					= 142,
+	MSM_RPM_8064_ID_PM8921_L6_1					= 143,
+	MSM_RPM_8064_ID_PM8921_L7_0					= 144,
+	MSM_RPM_8064_ID_PM8921_L7_1					= 145,
+	MSM_RPM_8064_ID_PM8921_L8_0					= 146,
+	MSM_RPM_8064_ID_PM8921_L8_1					= 147,
+	MSM_RPM_8064_ID_PM8921_L9_0					= 148,
+	MSM_RPM_8064_ID_PM8921_L9_1					= 149,
+	MSM_RPM_8064_ID_PM8921_L10_0					= 150,
+	MSM_RPM_8064_ID_PM8921_L10_1					= 151,
+	MSM_RPM_8064_ID_PM8921_L11_0					= 152,
+	MSM_RPM_8064_ID_PM8921_L11_1					= 153,
+	MSM_RPM_8064_ID_PM8921_L12_0					= 154,
+	MSM_RPM_8064_ID_PM8921_L12_1					= 155,
+	MSM_RPM_8064_ID_PM8921_L13_0					= 156,
+	MSM_RPM_8064_ID_PM8921_L13_1					= 157,
+	MSM_RPM_8064_ID_PM8921_L14_0					= 158,
+	MSM_RPM_8064_ID_PM8921_L14_1					= 159,
+	MSM_RPM_8064_ID_PM8921_L15_0					= 160,
+	MSM_RPM_8064_ID_PM8921_L15_1					= 161,
+	MSM_RPM_8064_ID_PM8921_L16_0					= 162,
+	MSM_RPM_8064_ID_PM8921_L16_1					= 163,
+	MSM_RPM_8064_ID_PM8921_L17_0					= 164,
+	MSM_RPM_8064_ID_PM8921_L17_1					= 165,
+	MSM_RPM_8064_ID_PM8921_L18_0					= 166,
+	MSM_RPM_8064_ID_PM8921_L18_1					= 167,
+	MSM_RPM_8064_ID_PM8921_L19_0					= 168,
+	MSM_RPM_8064_ID_PM8921_L19_1					= 169,
+	MSM_RPM_8064_ID_PM8921_L20_0					= 170,
+	MSM_RPM_8064_ID_PM8921_L20_1					= 171,
+	MSM_RPM_8064_ID_PM8921_L21_0					= 172,
+	MSM_RPM_8064_ID_PM8921_L21_1					= 173,
+	MSM_RPM_8064_ID_PM8921_L22_0					= 174,
+	MSM_RPM_8064_ID_PM8921_L22_1					= 175,
+	MSM_RPM_8064_ID_PM8921_L23_0					= 176,
+	MSM_RPM_8064_ID_PM8921_L23_1					= 177,
+	MSM_RPM_8064_ID_PM8921_L24_0					= 178,
+	MSM_RPM_8064_ID_PM8921_L24_1					= 179,
+	MSM_RPM_8064_ID_PM8921_L25_0					= 180,
+	MSM_RPM_8064_ID_PM8921_L25_1					= 181,
+	MSM_RPM_8064_ID_PM8921_L26_0					= 182,
+	MSM_RPM_8064_ID_PM8921_L26_1					= 183,
+	MSM_RPM_8064_ID_PM8921_L27_0					= 184,
+	MSM_RPM_8064_ID_PM8921_L27_1					= 185,
+	MSM_RPM_8064_ID_PM8921_L28_0					= 186,
+	MSM_RPM_8064_ID_PM8921_L28_1					= 187,
+	MSM_RPM_8064_ID_PM8921_L29_0					= 188,
+	MSM_RPM_8064_ID_PM8921_L29_1					= 189,
+	MSM_RPM_8064_ID_PM8921_CLK1_0					= 190,
+	MSM_RPM_8064_ID_PM8921_CLK1_1					= 191,
+	MSM_RPM_8064_ID_PM8921_CLK2_0					= 192,
+	MSM_RPM_8064_ID_PM8921_CLK2_1					= 193,
+	MSM_RPM_8064_ID_PM8921_LVS1					= 194,
+	MSM_RPM_8064_ID_PM8921_LVS2					= 195,
+	MSM_RPM_8064_ID_PM8921_LVS3					= 196,
+	MSM_RPM_8064_ID_PM8921_LVS4					= 197,
+	MSM_RPM_8064_ID_PM8921_LVS5					= 198,
+	MSM_RPM_8064_ID_PM8921_LVS6					= 199,
+	MSM_RPM_8064_ID_PM8921_LVS7					= 200,
+	MSM_RPM_8064_ID_PM8821_S1_0					= 201,
+	MSM_RPM_8064_ID_PM8821_S1_1					= 202,
+	MSM_RPM_8064_ID_PM8821_S2_0					= 203,
+	MSM_RPM_8064_ID_PM8821_S2_1					= 204,
+	MSM_RPM_8064_ID_PM8821_L1_0					= 205,
+	MSM_RPM_8064_ID_PM8821_L1_1					= 206,
+	MSM_RPM_8064_ID_NCP_0						= 207,
+	MSM_RPM_8064_ID_NCP_1						= 208,
+	MSM_RPM_8064_ID_CXO_BUFFERS					= 209,
+	MSM_RPM_8064_ID_USB_OTG_SWITCH					= 210,
+	MSM_RPM_8064_ID_HDMI_SWITCH					= 211,
+	MSM_RPM_8064_ID_DDR_DMM_0					= 212,
+	MSM_RPM_8064_ID_DDR_DMM_1					= 213,
+	MSM_RPM_8064_ID_QDSS_CLK					= 214,
+
+	MSM_RPM_8064_ID_LAST = MSM_RPM_8064_ID_QDSS_CLK,
+};
+
+
+/* RPM status ID enum */
+enum {
+	MSM_RPM_8064_STATUS_ID_VERSION_MAJOR				= 0,
+	MSM_RPM_8064_STATUS_ID_VERSION_MINOR				= 1,
+	MSM_RPM_8064_STATUS_ID_VERSION_BUILD				= 2,
+	MSM_RPM_8064_STATUS_ID_SUPPORTED_RESOURCES_0			= 3,
+	MSM_RPM_8064_STATUS_ID_SUPPORTED_RESOURCES_1			= 4,
+	MSM_RPM_8064_STATUS_ID_SUPPORTED_RESOURCES_2			= 5,
+	MSM_RPM_8064_STATUS_ID_RESERVED_SUPPORTED_RESOURCES_0		= 6,
+	MSM_RPM_8064_STATUS_ID_SEQUENCE					= 7,
+	MSM_RPM_8064_STATUS_ID_RPM_CTL					= 8,
+	MSM_RPM_8064_STATUS_ID_CXO_CLK					= 9,
+	MSM_RPM_8064_STATUS_ID_PXO_CLK					= 10,
+	MSM_RPM_8064_STATUS_ID_APPS_FABRIC_CLK				= 11,
+	MSM_RPM_8064_STATUS_ID_SYSTEM_FABRIC_CLK			= 12,
+	MSM_RPM_8064_STATUS_ID_MM_FABRIC_CLK				= 13,
+	MSM_RPM_8064_STATUS_ID_DAYTONA_FABRIC_CLK			= 14,
+	MSM_RPM_8064_STATUS_ID_SFPB_CLK					= 15,
+	MSM_RPM_8064_STATUS_ID_CFPB_CLK					= 16,
+	MSM_RPM_8064_STATUS_ID_MMFPB_CLK				= 17,
+	MSM_RPM_8064_STATUS_ID_EBI1_CLK					= 18,
+	MSM_RPM_8064_STATUS_ID_APPS_FABRIC_CFG_HALT			= 19,
+	MSM_RPM_8064_STATUS_ID_APPS_FABRIC_CFG_CLKMOD			= 20,
+	MSM_RPM_8064_STATUS_ID_APPS_FABRIC_CFG_IOCTL			= 21,
+	MSM_RPM_8064_STATUS_ID_APPS_FABRIC_ARB				= 22,
+	MSM_RPM_8064_STATUS_ID_SYS_FABRIC_CFG_HALT			= 23,
+	MSM_RPM_8064_STATUS_ID_SYS_FABRIC_CFG_CLKMOD			= 24,
+	MSM_RPM_8064_STATUS_ID_SYS_FABRIC_CFG_IOCTL			= 25,
+	MSM_RPM_8064_STATUS_ID_SYSTEM_FABRIC_ARB			= 26,
+	MSM_RPM_8064_STATUS_ID_MMSS_FABRIC_CFG_HALT			= 27,
+	MSM_RPM_8064_STATUS_ID_MMSS_FABRIC_CFG_CLKMOD			= 28,
+	MSM_RPM_8064_STATUS_ID_MMSS_FABRIC_CFG_IOCTL			= 29,
+	MSM_RPM_8064_STATUS_ID_MM_FABRIC_ARB				= 30,
+	MSM_RPM_8064_STATUS_ID_PM8921_S1_0				= 31,
+	MSM_RPM_8064_STATUS_ID_PM8921_S1_1				= 32,
+	MSM_RPM_8064_STATUS_ID_PM8921_S2_0				= 33,
+	MSM_RPM_8064_STATUS_ID_PM8921_S2_1				= 34,
+	MSM_RPM_8064_STATUS_ID_PM8921_S3_0				= 35,
+	MSM_RPM_8064_STATUS_ID_PM8921_S3_1				= 36,
+	MSM_RPM_8064_STATUS_ID_PM8921_S4_0				= 37,
+	MSM_RPM_8064_STATUS_ID_PM8921_S4_1				= 38,
+	MSM_RPM_8064_STATUS_ID_PM8921_S5_0				= 39,
+	MSM_RPM_8064_STATUS_ID_PM8921_S5_1				= 40,
+	MSM_RPM_8064_STATUS_ID_PM8921_S6_0				= 41,
+	MSM_RPM_8064_STATUS_ID_PM8921_S6_1				= 42,
+	MSM_RPM_8064_STATUS_ID_PM8921_S7_0				= 43,
+	MSM_RPM_8064_STATUS_ID_PM8921_S7_1				= 44,
+	MSM_RPM_8064_STATUS_ID_PM8921_S8_0				= 45,
+	MSM_RPM_8064_STATUS_ID_PM8921_S8_1				= 46,
+	MSM_RPM_8064_STATUS_ID_PM8921_L1_0				= 47,
+	MSM_RPM_8064_STATUS_ID_PM8921_L1_1				= 48,
+	MSM_RPM_8064_STATUS_ID_PM8921_L2_0				= 49,
+	MSM_RPM_8064_STATUS_ID_PM8921_L2_1				= 50,
+	MSM_RPM_8064_STATUS_ID_PM8921_L3_0				= 51,
+	MSM_RPM_8064_STATUS_ID_PM8921_L3_1				= 52,
+	MSM_RPM_8064_STATUS_ID_PM8921_L4_0				= 53,
+	MSM_RPM_8064_STATUS_ID_PM8921_L4_1				= 54,
+	MSM_RPM_8064_STATUS_ID_PM8921_L5_0				= 55,
+	MSM_RPM_8064_STATUS_ID_PM8921_L5_1				= 56,
+	MSM_RPM_8064_STATUS_ID_PM8921_L6_0				= 57,
+	MSM_RPM_8064_STATUS_ID_PM8921_L6_1				= 58,
+	MSM_RPM_8064_STATUS_ID_PM8921_L7_0				= 59,
+	MSM_RPM_8064_STATUS_ID_PM8921_L7_1				= 60,
+	MSM_RPM_8064_STATUS_ID_PM8921_L8_0				= 61,
+	MSM_RPM_8064_STATUS_ID_PM8921_L8_1				= 62,
+	MSM_RPM_8064_STATUS_ID_PM8921_L9_0				= 63,
+	MSM_RPM_8064_STATUS_ID_PM8921_L9_1				= 64,
+	MSM_RPM_8064_STATUS_ID_PM8921_L10_0				= 65,
+	MSM_RPM_8064_STATUS_ID_PM8921_L10_1				= 66,
+	MSM_RPM_8064_STATUS_ID_PM8921_L11_0				= 67,
+	MSM_RPM_8064_STATUS_ID_PM8921_L11_1				= 68,
+	MSM_RPM_8064_STATUS_ID_PM8921_L12_0				= 69,
+	MSM_RPM_8064_STATUS_ID_PM8921_L12_1				= 70,
+	MSM_RPM_8064_STATUS_ID_PM8921_L13_0				= 71,
+	MSM_RPM_8064_STATUS_ID_PM8921_L13_1				= 72,
+	MSM_RPM_8064_STATUS_ID_PM8921_L14_0				= 73,
+	MSM_RPM_8064_STATUS_ID_PM8921_L14_1				= 74,
+	MSM_RPM_8064_STATUS_ID_PM8921_L15_0				= 75,
+	MSM_RPM_8064_STATUS_ID_PM8921_L15_1				= 76,
+	MSM_RPM_8064_STATUS_ID_PM8921_L16_0				= 77,
+	MSM_RPM_8064_STATUS_ID_PM8921_L16_1				= 78,
+	MSM_RPM_8064_STATUS_ID_PM8921_L17_0				= 79,
+	MSM_RPM_8064_STATUS_ID_PM8921_L17_1				= 80,
+	MSM_RPM_8064_STATUS_ID_PM8921_L18_0				= 81,
+	MSM_RPM_8064_STATUS_ID_PM8921_L18_1				= 82,
+	MSM_RPM_8064_STATUS_ID_PM8921_L19_0				= 83,
+	MSM_RPM_8064_STATUS_ID_PM8921_L19_1				= 84,
+	MSM_RPM_8064_STATUS_ID_PM8921_L20_0				= 85,
+	MSM_RPM_8064_STATUS_ID_PM8921_L20_1				= 86,
+	MSM_RPM_8064_STATUS_ID_PM8921_L21_0				= 87,
+	MSM_RPM_8064_STATUS_ID_PM8921_L21_1				= 88,
+	MSM_RPM_8064_STATUS_ID_PM8921_L22_0				= 89,
+	MSM_RPM_8064_STATUS_ID_PM8921_L22_1				= 90,
+	MSM_RPM_8064_STATUS_ID_PM8921_L23_0				= 91,
+	MSM_RPM_8064_STATUS_ID_PM8921_L23_1				= 92,
+	MSM_RPM_8064_STATUS_ID_PM8921_L24_0				= 93,
+	MSM_RPM_8064_STATUS_ID_PM8921_L24_1				= 94,
+	MSM_RPM_8064_STATUS_ID_PM8921_L25_0				= 95,
+	MSM_RPM_8064_STATUS_ID_PM8921_L25_1				= 96,
+	MSM_RPM_8064_STATUS_ID_PM8921_L26_0				= 97,
+	MSM_RPM_8064_STATUS_ID_PM8921_L26_1				= 98,
+	MSM_RPM_8064_STATUS_ID_PM8921_L27_0				= 99,
+	MSM_RPM_8064_STATUS_ID_PM8921_L27_1				= 100,
+	MSM_RPM_8064_STATUS_ID_PM8921_L28_0				= 101,
+	MSM_RPM_8064_STATUS_ID_PM8921_L28_1				= 102,
+	MSM_RPM_8064_STATUS_ID_PM8921_L29_0				= 103,
+	MSM_RPM_8064_STATUS_ID_PM8921_L29_1				= 104,
+	MSM_RPM_8064_STATUS_ID_PM8921_CLK1_0				= 105,
+	MSM_RPM_8064_STATUS_ID_PM8921_CLK1_1				= 106,
+	MSM_RPM_8064_STATUS_ID_PM8921_CLK2_0				= 107,
+	MSM_RPM_8064_STATUS_ID_PM8921_CLK2_1				= 108,
+	MSM_RPM_8064_STATUS_ID_PM8921_LVS1				= 109,
+	MSM_RPM_8064_STATUS_ID_PM8921_LVS2				= 110,
+	MSM_RPM_8064_STATUS_ID_PM8921_LVS3				= 111,
+	MSM_RPM_8064_STATUS_ID_PM8921_LVS4				= 112,
+	MSM_RPM_8064_STATUS_ID_PM8921_LVS5				= 113,
+	MSM_RPM_8064_STATUS_ID_PM8921_LVS6				= 114,
+	MSM_RPM_8064_STATUS_ID_PM8921_LVS7				= 115,
+	MSM_RPM_8064_STATUS_ID_PM8821_S1_0				= 116,
+	MSM_RPM_8064_STATUS_ID_PM8821_S1_1				= 117,
+	MSM_RPM_8064_STATUS_ID_PM8821_S2_0				= 118,
+	MSM_RPM_8064_STATUS_ID_PM8821_S2_1				= 119,
+	MSM_RPM_8064_STATUS_ID_PM8821_L1_0				= 120,
+	MSM_RPM_8064_STATUS_ID_PM8821_L1_1				= 121,
+	MSM_RPM_8064_STATUS_ID_NCP_0					= 122,
+	MSM_RPM_8064_STATUS_ID_NCP_1					= 123,
+	MSM_RPM_8064_STATUS_ID_CXO_BUFFERS				= 124,
+	MSM_RPM_8064_STATUS_ID_USB_OTG_SWITCH				= 125,
+	MSM_RPM_8064_STATUS_ID_HDMI_SWITCH				= 126,
+	MSM_RPM_8064_STATUS_ID_DDR_DMM_0				= 127,
+	MSM_RPM_8064_STATUS_ID_DDR_DMM_1				= 128,
+	MSM_RPM_8064_STATUS_ID_EBI1_CH0_RANGE				= 129,
+	MSM_RPM_8064_STATUS_ID_EBI1_CH1_RANGE				= 130,
+
+	MSM_RPM_8064_STATUS_ID_LAST = MSM_RPM_8064_STATUS_ID_EBI1_CH1_RANGE,
+};
+
+#endif /* __ARCH_ARM_MACH_MSM_RPM_8064_H */
diff --git a/arch/arm/mach-msm/include/mach/rpm-8660.h b/arch/arm/mach-msm/include/mach/rpm-8660.h
new file mode 100644
index 0000000..5e3b404
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/rpm-8660.h
@@ -0,0 +1,455 @@
+/* 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
+ * 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 __ARCH_ARM_MACH_MSM_RPM_8660_H
+#define __ARCH_ARM_MACH_MSM_RPM_8660_H
+
+/* RPM control message RAM enums */
+enum {
+	MSM_RPM_8660_CTRL_VERSION_MAJOR,
+	MSM_RPM_8660_CTRL_VERSION_MINOR,
+	MSM_RPM_8660_CTRL_VERSION_BUILD,
+
+	MSM_RPM_8660_CTRL_REQ_CTX_0,
+	MSM_RPM_8660_CTRL_REQ_CTX_7 = MSM_RPM_8660_CTRL_REQ_CTX_0 + 7,
+	MSM_RPM_8660_CTRL_REQ_SEL_0,
+	MSM_RPM_8660_CTRL_REQ_SEL_7 = MSM_RPM_8660_CTRL_REQ_SEL_0 + 7,
+	MSM_RPM_8660_CTRL_ACK_CTX_0,
+	MSM_RPM_8660_CTRL_ACK_CTX_7 = MSM_RPM_8660_CTRL_ACK_CTX_0 + 7,
+	MSM_RPM_8660_CTRL_ACK_SEL_0,
+	MSM_RPM_8660_CTRL_ACK_SEL_7 = MSM_RPM_8660_CTRL_ACK_SEL_0 + 7,
+};
+
+enum {
+	MSM_RPM_8660_SEL_NOTIFICATION,
+	MSM_RPM_8660_SEL_INVALIDATE,
+	MSM_RPM_8660_SEL_TRIGGER_TIMED,
+	MSM_RPM_8660_SEL_TRIGGER_SET,
+	MSM_RPM_8660_SEL_TRIGGER_CLEAR,
+
+	MSM_RPM_8660_SEL_CXO_CLK,
+	MSM_RPM_8660_SEL_PXO_CLK,
+	MSM_RPM_8660_SEL_PLL_4,
+	MSM_RPM_8660_SEL_APPS_FABRIC_CLK,
+	MSM_RPM_8660_SEL_SYSTEM_FABRIC_CLK,
+	MSM_RPM_8660_SEL_MM_FABRIC_CLK,
+	MSM_RPM_8660_SEL_DAYTONA_FABRIC_CLK,
+	MSM_RPM_8660_SEL_SFPB_CLK,
+	MSM_RPM_8660_SEL_CFPB_CLK,
+	MSM_RPM_8660_SEL_MMFPB_CLK,
+	MSM_RPM_8660_SEL_SMI_CLK,
+	MSM_RPM_8660_SEL_EBI1_CLK,
+
+	MSM_RPM_8660_SEL_APPS_L2_CACHE_CTL,
+
+	MSM_RPM_8660_SEL_APPS_FABRIC_HALT,
+	MSM_RPM_8660_SEL_APPS_FABRIC_CLOCK_MODE,
+	MSM_RPM_8660_SEL_APPS_FABRIC_IOCTL,
+	MSM_RPM_8660_SEL_APPS_FABRIC_ARB,
+
+	MSM_RPM_8660_SEL_SYSTEM_FABRIC_HALT,
+	MSM_RPM_8660_SEL_SYSTEM_FABRIC_CLOCK_MODE,
+	MSM_RPM_8660_SEL_SYSTEM_FABRIC_IOCTL,
+	MSM_RPM_8660_SEL_SYSTEM_FABRIC_ARB,
+
+	MSM_RPM_8660_SEL_MM_FABRIC_HALT,
+	MSM_RPM_8660_SEL_MM_FABRIC_CLOCK_MODE,
+	MSM_RPM_8660_SEL_MM_FABRIC_IOCTL,
+	MSM_RPM_8660_SEL_MM_FABRIC_ARB,
+
+	MSM_RPM_8660_SEL_SMPS0B,
+	MSM_RPM_8660_SEL_SMPS1B,
+	MSM_RPM_8660_SEL_SMPS2B,
+	MSM_RPM_8660_SEL_SMPS3B,
+	MSM_RPM_8660_SEL_SMPS4B,
+	MSM_RPM_8660_SEL_LDO0B,
+	MSM_RPM_8660_SEL_LDO1B,
+	MSM_RPM_8660_SEL_LDO2B,
+	MSM_RPM_8660_SEL_LDO3B,
+	MSM_RPM_8660_SEL_LDO4B,
+	MSM_RPM_8660_SEL_LDO5B,
+	MSM_RPM_8660_SEL_LDO6B,
+	MSM_RPM_8660_SEL_LVS0B,
+	MSM_RPM_8660_SEL_LVS1B,
+	MSM_RPM_8660_SEL_LVS2B,
+	MSM_RPM_8660_SEL_LVS3B,
+	MSM_RPM_8660_SEL_MVS,
+
+	MSM_RPM_8660_SEL_SMPS0,
+	MSM_RPM_8660_SEL_SMPS1,
+	MSM_RPM_8660_SEL_SMPS2,
+	MSM_RPM_8660_SEL_SMPS3,
+	MSM_RPM_8660_SEL_SMPS4,
+
+	MSM_RPM_8660_SEL_LDO0,
+	MSM_RPM_8660_SEL_LDO1,
+	MSM_RPM_8660_SEL_LDO2,
+	MSM_RPM_8660_SEL_LDO3,
+	MSM_RPM_8660_SEL_LDO4,
+	MSM_RPM_8660_SEL_LDO5,
+	MSM_RPM_8660_SEL_LDO6,
+	MSM_RPM_8660_SEL_LDO7,
+	MSM_RPM_8660_SEL_LDO8,
+	MSM_RPM_8660_SEL_LDO9,
+	MSM_RPM_8660_SEL_LDO10,
+	MSM_RPM_8660_SEL_LDO11,
+	MSM_RPM_8660_SEL_LDO12,
+	MSM_RPM_8660_SEL_LDO13,
+	MSM_RPM_8660_SEL_LDO14,
+	MSM_RPM_8660_SEL_LDO15,
+	MSM_RPM_8660_SEL_LDO16,
+	MSM_RPM_8660_SEL_LDO17,
+	MSM_RPM_8660_SEL_LDO18,
+	MSM_RPM_8660_SEL_LDO19,
+	MSM_RPM_8660_SEL_LDO20,
+	MSM_RPM_8660_SEL_LDO21,
+	MSM_RPM_8660_SEL_LDO22,
+	MSM_RPM_8660_SEL_LDO23,
+	MSM_RPM_8660_SEL_LDO24,
+	MSM_RPM_8660_SEL_LDO25,
+	MSM_RPM_8660_SEL_LVS0,
+	MSM_RPM_8660_SEL_LVS1,
+	MSM_RPM_8660_SEL_NCP,
+
+	MSM_RPM_8660_SEL_CXO_BUFFERS,
+
+	MSM_RPM_8660_SEL_LAST = MSM_RPM_8660_SEL_CXO_BUFFERS,
+};
+
+
+enum {
+	MSM_RPM_8660_ID_NOTIFICATION_CONFIGURED_0,
+	MSM_RPM_8660_ID_NOTIFICATION_CONFIGURED_7 =
+		MSM_RPM_8660_ID_NOTIFICATION_CONFIGURED_0 + 7,
+
+	MSM_RPM_8660_ID_NOTIFICATION_REGISTERED_0,
+	MSM_RPM_8660_ID_NOTIFICATION_REGISTERED_7 =
+		MSM_RPM_8660_ID_NOTIFICATION_REGISTERED_0 + 7,
+
+	MSM_RPM_8660_ID_INVALIDATE_0,
+	MSM_RPM_8660_ID_INVALIDATE_7 =
+		MSM_RPM_8660_ID_INVALIDATE_0 + 7,
+
+	MSM_RPM_8660_ID_TRIGGER_TIMED_TO,
+	MSM_RPM_8660_ID_TRIGGER_TIMED_SCLK_COUNT,
+
+	MSM_RPM_8660_ID_TRIGGER_SET_FROM,
+	MSM_RPM_8660_ID_TRIGGER_SET_TO,
+	MSM_RPM_8660_ID_TRIGGER_SET_TRIGGER,
+
+	MSM_RPM_8660_ID_TRIGGER_CLEAR_FROM,
+	MSM_RPM_8660_ID_TRIGGER_CLEAR_TO,
+	MSM_RPM_8660_ID_TRIGGER_CLEAR_TRIGGER,
+
+	MSM_RPM_8660_ID_CXO_CLK,
+	MSM_RPM_8660_ID_PXO_CLK,
+	MSM_RPM_8660_ID_PLL_4,
+	MSM_RPM_8660_ID_APPS_FABRIC_CLK,
+	MSM_RPM_8660_ID_SYSTEM_FABRIC_CLK,
+	MSM_RPM_8660_ID_MM_FABRIC_CLK,
+	MSM_RPM_8660_ID_DAYTONA_FABRIC_CLK,
+	MSM_RPM_8660_ID_SFPB_CLK,
+	MSM_RPM_8660_ID_CFPB_CLK,
+	MSM_RPM_8660_ID_MMFPB_CLK,
+	MSM_RPM_8660_ID_SMI_CLK,
+	MSM_RPM_8660_ID_EBI1_CLK,
+
+	MSM_RPM_8660_ID_APPS_L2_CACHE_CTL,
+
+	MSM_RPM_8660_ID_APPS_FABRIC_HALT_0,
+	MSM_RPM_8660_ID_APPS_FABRIC_HALT_1,
+	MSM_RPM_8660_ID_APPS_FABRIC_CLOCK_MODE_0,
+	MSM_RPM_8660_ID_APPS_FABRIC_CLOCK_MODE_1,
+	MSM_RPM_8660_ID_APPS_FABRIC_CLOCK_MODE_2,
+	MSM_RPM_8660_ID_APPS_FABRIC_RESERVED_A,
+	MSM_RPM_8660_ID_APPS_FABRIC_ARB_0,
+	MSM_RPM_8660_ID_APPS_FABRIC_ARB_5 =
+		MSM_RPM_8660_ID_APPS_FABRIC_ARB_0 + 5,
+	MSM_RPM_8660_ID_APPS_FABRIC_RESERVED_B_0,
+	MSM_RPM_8660_ID_APPS_FABRIC_RESERVED_B_5 =
+		MSM_RPM_8660_ID_APPS_FABRIC_RESERVED_B_0 + 5,
+
+	MSM_RPM_8660_ID_SYSTEM_FABRIC_HALT_0,
+	MSM_RPM_8660_ID_SYSTEM_FABRIC_HALT_1,
+	MSM_RPM_8660_ID_SYSTEM_FABRIC_CLOCK_MODE_0,
+	MSM_RPM_8660_ID_SYSTEM_FABRIC_CLOCK_MODE_1,
+	MSM_RPM_8660_ID_SYSTEM_FABRIC_CLOCK_MODE_2,
+	MSM_RPM_8660_ID_SYSTEM_FABRIC_RESERVED_A,
+	MSM_RPM_8660_ID_SYSTEM_FABRIC_ARB_0,
+	MSM_RPM_8660_ID_SYSTEM_FABRIC_ARB_21 =
+		MSM_RPM_8660_ID_SYSTEM_FABRIC_ARB_0 + 21,
+	MSM_RPM_8660_ID_SYSTEM_FABRIC_RESERVED_B_0,
+	MSM_RPM_8660_ID_SYSTEM_FABRIC_RESERVED_B_13 =
+		MSM_RPM_8660_ID_SYSTEM_FABRIC_RESERVED_B_0 + 13,
+
+	MSM_RPM_8660_ID_MM_FABRIC_HALT_0,
+	MSM_RPM_8660_ID_MM_FABRIC_HALT_1,
+	MSM_RPM_8660_ID_MM_FABRIC_CLOCK_MODE_0,
+	MSM_RPM_8660_ID_MM_FABRIC_CLOCK_MODE_1,
+	MSM_RPM_8660_ID_MM_FABRIC_CLOCK_MODE_2,
+	MSM_RPM_8660_ID_MM_FABRIC_RESERVED_A,
+	MSM_RPM_8660_ID_MM_FABRIC_ARB_0,
+	MSM_RPM_8660_ID_MM_FABRIC_ARB_22 =
+		MSM_RPM_8660_ID_MM_FABRIC_ARB_0 + 22,
+
+	/* pmic 8901 */
+	MSM_RPM_8660_ID_SMPS0B_0,
+	MSM_RPM_8660_ID_SMPS0B_1,
+	MSM_RPM_8660_ID_SMPS1B_0,
+	MSM_RPM_8660_ID_SMPS1B_1,
+	MSM_RPM_8660_ID_SMPS2B_0,
+	MSM_RPM_8660_ID_SMPS2B_1,
+	MSM_RPM_8660_ID_SMPS3B_0,
+	MSM_RPM_8660_ID_SMPS3B_1,
+	MSM_RPM_8660_ID_SMPS4B_0,
+	MSM_RPM_8660_ID_SMPS4B_1,
+	MSM_RPM_8660_ID_LDO0B_0,
+	MSM_RPM_8660_ID_LDO0B_1,
+	MSM_RPM_8660_ID_LDO1B_0,
+	MSM_RPM_8660_ID_LDO1B_1,
+	MSM_RPM_8660_ID_LDO2B_0,
+	MSM_RPM_8660_ID_LDO2B_1,
+	MSM_RPM_8660_ID_LDO3B_0,
+	MSM_RPM_8660_ID_LDO3B_1,
+	MSM_RPM_8660_ID_LDO4B_0,
+	MSM_RPM_8660_ID_LDO4B_1,
+	MSM_RPM_8660_ID_LDO5B_0,
+	MSM_RPM_8660_ID_LDO5B_1,
+	MSM_RPM_8660_ID_LDO6B_0,
+	MSM_RPM_8660_ID_LDO6B_1,
+	MSM_RPM_8660_ID_LVS0B,
+	MSM_RPM_8660_ID_LVS1B,
+	MSM_RPM_8660_ID_LVS2B,
+	MSM_RPM_8660_ID_LVS3B,
+	MSM_RPM_8660_ID_MVS,
+
+	/* pmic 8058 */
+	MSM_RPM_8660_ID_SMPS0_0,
+	MSM_RPM_8660_ID_SMPS0_1,
+	MSM_RPM_8660_ID_SMPS1_0,
+	MSM_RPM_8660_ID_SMPS1_1,
+	MSM_RPM_8660_ID_SMPS2_0,
+	MSM_RPM_8660_ID_SMPS2_1,
+	MSM_RPM_8660_ID_SMPS3_0,
+	MSM_RPM_8660_ID_SMPS3_1,
+	MSM_RPM_8660_ID_SMPS4_0,
+	MSM_RPM_8660_ID_SMPS4_1,
+	MSM_RPM_8660_ID_LDO0_0,
+	MSM_RPM_8660_ID_LDO0_1,
+	MSM_RPM_8660_ID_LDO1_0,
+	MSM_RPM_8660_ID_LDO1_1,
+	MSM_RPM_8660_ID_LDO2_0,
+	MSM_RPM_8660_ID_LDO2_1,
+	MSM_RPM_8660_ID_LDO3_0,
+	MSM_RPM_8660_ID_LDO3_1,
+	MSM_RPM_8660_ID_LDO4_0,
+	MSM_RPM_8660_ID_LDO4_1,
+	MSM_RPM_8660_ID_LDO5_0,
+	MSM_RPM_8660_ID_LDO5_1,
+	MSM_RPM_8660_ID_LDO6_0,
+	MSM_RPM_8660_ID_LDO6_1,
+	MSM_RPM_8660_ID_LDO7_0,
+	MSM_RPM_8660_ID_LDO7_1,
+	MSM_RPM_8660_ID_LDO8_0,
+	MSM_RPM_8660_ID_LDO8_1,
+	MSM_RPM_8660_ID_LDO9_0,
+	MSM_RPM_8660_ID_LDO9_1,
+	MSM_RPM_8660_ID_LDO10_0,
+	MSM_RPM_8660_ID_LDO10_1,
+	MSM_RPM_8660_ID_LDO11_0,
+	MSM_RPM_8660_ID_LDO11_1,
+	MSM_RPM_8660_ID_LDO12_0,
+	MSM_RPM_8660_ID_LDO12_1,
+	MSM_RPM_8660_ID_LDO13_0,
+	MSM_RPM_8660_ID_LDO13_1,
+	MSM_RPM_8660_ID_LDO14_0,
+	MSM_RPM_8660_ID_LDO14_1,
+	MSM_RPM_8660_ID_LDO15_0,
+	MSM_RPM_8660_ID_LDO15_1,
+	MSM_RPM_8660_ID_LDO16_0,
+	MSM_RPM_8660_ID_LDO16_1,
+	MSM_RPM_8660_ID_LDO17_0,
+	MSM_RPM_8660_ID_LDO17_1,
+	MSM_RPM_8660_ID_LDO18_0,
+	MSM_RPM_8660_ID_LDO18_1,
+	MSM_RPM_8660_ID_LDO19_0,
+	MSM_RPM_8660_ID_LDO19_1,
+	MSM_RPM_8660_ID_LDO20_0,
+	MSM_RPM_8660_ID_LDO20_1,
+	MSM_RPM_8660_ID_LDO21_0,
+	MSM_RPM_8660_ID_LDO21_1,
+	MSM_RPM_8660_ID_LDO22_0,
+	MSM_RPM_8660_ID_LDO22_1,
+	MSM_RPM_8660_ID_LDO23_0,
+	MSM_RPM_8660_ID_LDO23_1,
+	MSM_RPM_8660_ID_LDO24_0,
+	MSM_RPM_8660_ID_LDO24_1,
+	MSM_RPM_8660_ID_LDO25_0,
+	MSM_RPM_8660_ID_LDO25_1,
+	MSM_RPM_8660_ID_LVS0,
+	MSM_RPM_8660_ID_LVS1,
+	MSM_RPM_8660_ID_NCP_0,
+	MSM_RPM_8660_ID_NCP_1,
+
+	MSM_RPM_8660_ID_CXO_BUFFERS,
+
+	MSM_RPM_8660_ID_LAST = MSM_RPM_8660_ID_CXO_BUFFERS
+};
+
+enum {
+	MSM_RPM_8660_STATUS_ID_VERSION_MAJOR,
+	MSM_RPM_8660_STATUS_ID_VERSION_MINOR,
+	MSM_RPM_8660_STATUS_ID_VERSION_BUILD,
+	MSM_RPM_8660_STATUS_ID_SUPPORTED_RESOURCES_0,
+	MSM_RPM_8660_STATUS_ID_SUPPORTED_RESOURCES_1,
+	MSM_RPM_8660_STATUS_ID_SUPPORTED_RESOURCES_2,
+	MSM_RPM_8660_STATUS_ID_RESERVED_0,
+	MSM_RPM_8660_STATUS_ID_RESERVED_4 =
+		MSM_RPM_8660_STATUS_ID_RESERVED_0 + 4,
+	MSM_RPM_8660_STATUS_ID_SEQUENCE,
+
+	MSM_RPM_8660_STATUS_ID_CXO_CLK,
+	MSM_RPM_8660_STATUS_ID_PXO_CLK,
+	MSM_RPM_8660_STATUS_ID_PLL_4,
+	MSM_RPM_8660_STATUS_ID_APPS_FABRIC_CLK,
+	MSM_RPM_8660_STATUS_ID_SYSTEM_FABRIC_CLK,
+	MSM_RPM_8660_STATUS_ID_MM_FABRIC_CLK,
+	MSM_RPM_8660_STATUS_ID_DAYTONA_FABRIC_CLK,
+	MSM_RPM_8660_STATUS_ID_SFPB_CLK,
+	MSM_RPM_8660_STATUS_ID_CFPB_CLK,
+	MSM_RPM_8660_STATUS_ID_MMFPB_CLK,
+	MSM_RPM_8660_STATUS_ID_SMI_CLK,
+	MSM_RPM_8660_STATUS_ID_EBI1_CLK,
+
+	MSM_RPM_8660_STATUS_ID_APPS_L2_CACHE_CTL,
+
+	MSM_RPM_8660_STATUS_ID_APPS_FABRIC_HALT,
+	MSM_RPM_8660_STATUS_ID_APPS_FABRIC_CLOCK_MODE,
+	MSM_RPM_8660_STATUS_ID_APPS_FABRIC_RESERVED,
+	MSM_RPM_8660_STATUS_ID_APPS_FABRIC_ARB,
+
+	MSM_RPM_8660_STATUS_ID_SYSTEM_FABRIC_HALT,
+	MSM_RPM_8660_STATUS_ID_SYSTEM_FABRIC_CLOCK_MODE,
+	MSM_RPM_8660_STATUS_ID_SYSTEM_FABRIC_RESERVED,
+	MSM_RPM_8660_STATUS_ID_SYSTEM_FABRIC_ARB,
+
+	MSM_RPM_8660_STATUS_ID_MM_FABRIC_HALT,
+	MSM_RPM_8660_STATUS_ID_MM_FABRIC_CLOCK_MODE,
+	MSM_RPM_8660_STATUS_ID_MM_FABRIC_RESERVED,
+	MSM_RPM_8660_STATUS_ID_MM_FABRIC_ARB,
+
+	/* pmic 8901 */
+	MSM_RPM_8660_STATUS_ID_SMPS0B_0,
+	MSM_RPM_8660_STATUS_ID_SMPS0B_1,
+	MSM_RPM_8660_STATUS_ID_SMPS1B_0,
+	MSM_RPM_8660_STATUS_ID_SMPS1B_1,
+	MSM_RPM_8660_STATUS_ID_SMPS2B_0,
+	MSM_RPM_8660_STATUS_ID_SMPS2B_1,
+	MSM_RPM_8660_STATUS_ID_SMPS3B_0,
+	MSM_RPM_8660_STATUS_ID_SMPS3B_1,
+	MSM_RPM_8660_STATUS_ID_SMPS4B_0,
+	MSM_RPM_8660_STATUS_ID_SMPS4B_1,
+	MSM_RPM_8660_STATUS_ID_LDO0B_0,
+	MSM_RPM_8660_STATUS_ID_LDO0B_1,
+	MSM_RPM_8660_STATUS_ID_LDO1B_0,
+	MSM_RPM_8660_STATUS_ID_LDO1B_1,
+	MSM_RPM_8660_STATUS_ID_LDO2B_0,
+	MSM_RPM_8660_STATUS_ID_LDO2B_1,
+	MSM_RPM_8660_STATUS_ID_LDO3B_0,
+	MSM_RPM_8660_STATUS_ID_LDO3B_1,
+	MSM_RPM_8660_STATUS_ID_LDO4B_0,
+	MSM_RPM_8660_STATUS_ID_LDO4B_1,
+	MSM_RPM_8660_STATUS_ID_LDO5B_0,
+	MSM_RPM_8660_STATUS_ID_LDO5B_1,
+	MSM_RPM_8660_STATUS_ID_LDO6B_0,
+	MSM_RPM_8660_STATUS_ID_LDO6B_1,
+	MSM_RPM_8660_STATUS_ID_LVS0B,
+	MSM_RPM_8660_STATUS_ID_LVS1B,
+	MSM_RPM_8660_STATUS_ID_LVS2B,
+	MSM_RPM_8660_STATUS_ID_LVS3B,
+	MSM_RPM_8660_STATUS_ID_MVS,
+
+	/* pmic 8058 */
+	MSM_RPM_8660_STATUS_ID_SMPS0_0,
+	MSM_RPM_8660_STATUS_ID_SMPS0_1,
+	MSM_RPM_8660_STATUS_ID_SMPS1_0,
+	MSM_RPM_8660_STATUS_ID_SMPS1_1,
+	MSM_RPM_8660_STATUS_ID_SMPS2_0,
+	MSM_RPM_8660_STATUS_ID_SMPS2_1,
+	MSM_RPM_8660_STATUS_ID_SMPS3_0,
+	MSM_RPM_8660_STATUS_ID_SMPS3_1,
+	MSM_RPM_8660_STATUS_ID_SMPS4_0,
+	MSM_RPM_8660_STATUS_ID_SMPS4_1,
+	MSM_RPM_8660_STATUS_ID_LDO0_0,
+	MSM_RPM_8660_STATUS_ID_LDO0_1,
+	MSM_RPM_8660_STATUS_ID_LDO1_0,
+	MSM_RPM_8660_STATUS_ID_LDO1_1,
+	MSM_RPM_8660_STATUS_ID_LDO2_0,
+	MSM_RPM_8660_STATUS_ID_LDO2_1,
+	MSM_RPM_8660_STATUS_ID_LDO3_0,
+	MSM_RPM_8660_STATUS_ID_LDO3_1,
+	MSM_RPM_8660_STATUS_ID_LDO4_0,
+	MSM_RPM_8660_STATUS_ID_LDO4_1,
+	MSM_RPM_8660_STATUS_ID_LDO5_0,
+	MSM_RPM_8660_STATUS_ID_LDO5_1,
+	MSM_RPM_8660_STATUS_ID_LDO6_0,
+	MSM_RPM_8660_STATUS_ID_LDO6_1,
+	MSM_RPM_8660_STATUS_ID_LDO7_0,
+	MSM_RPM_8660_STATUS_ID_LDO7_1,
+	MSM_RPM_8660_STATUS_ID_LDO8_0,
+	MSM_RPM_8660_STATUS_ID_LDO8_1,
+	MSM_RPM_8660_STATUS_ID_LDO9_0,
+	MSM_RPM_8660_STATUS_ID_LDO9_1,
+	MSM_RPM_8660_STATUS_ID_LDO10_0,
+	MSM_RPM_8660_STATUS_ID_LDO10_1,
+	MSM_RPM_8660_STATUS_ID_LDO11_0,
+	MSM_RPM_8660_STATUS_ID_LDO11_1,
+	MSM_RPM_8660_STATUS_ID_LDO12_0,
+	MSM_RPM_8660_STATUS_ID_LDO12_1,
+	MSM_RPM_8660_STATUS_ID_LDO13_0,
+	MSM_RPM_8660_STATUS_ID_LDO13_1,
+	MSM_RPM_8660_STATUS_ID_LDO14_0,
+	MSM_RPM_8660_STATUS_ID_LDO14_1,
+	MSM_RPM_8660_STATUS_ID_LDO15_0,
+	MSM_RPM_8660_STATUS_ID_LDO15_1,
+	MSM_RPM_8660_STATUS_ID_LDO16_0,
+	MSM_RPM_8660_STATUS_ID_LDO16_1,
+	MSM_RPM_8660_STATUS_ID_LDO17_0,
+	MSM_RPM_8660_STATUS_ID_LDO17_1,
+	MSM_RPM_8660_STATUS_ID_LDO18_0,
+	MSM_RPM_8660_STATUS_ID_LDO18_1,
+	MSM_RPM_8660_STATUS_ID_LDO19_0,
+	MSM_RPM_8660_STATUS_ID_LDO19_1,
+	MSM_RPM_8660_STATUS_ID_LDO20_0,
+	MSM_RPM_8660_STATUS_ID_LDO20_1,
+	MSM_RPM_8660_STATUS_ID_LDO21_0,
+	MSM_RPM_8660_STATUS_ID_LDO21_1,
+	MSM_RPM_8660_STATUS_ID_LDO22_0,
+	MSM_RPM_8660_STATUS_ID_LDO22_1,
+	MSM_RPM_8660_STATUS_ID_LDO23_0,
+	MSM_RPM_8660_STATUS_ID_LDO23_1,
+	MSM_RPM_8660_STATUS_ID_LDO24_0,
+	MSM_RPM_8660_STATUS_ID_LDO24_1,
+	MSM_RPM_8660_STATUS_ID_LDO25_0,
+	MSM_RPM_8660_STATUS_ID_LDO25_1,
+	MSM_RPM_8660_STATUS_ID_LVS0,
+	MSM_RPM_8660_STATUS_ID_LVS1,
+	MSM_RPM_8660_STATUS_ID_NCP_0,
+	MSM_RPM_8660_STATUS_ID_NCP_1,
+
+	MSM_RPM_8660_STATUS_ID_CXO_BUFFERS,
+
+	MSM_RPM_8660_STATUS_ID_LAST =
+		MSM_RPM_8660_STATUS_ID_CXO_BUFFERS
+};
+
+#endif /* __ARCH_ARM_MACH_MSM_RPM_8660_H */
diff --git a/arch/arm/mach-msm/include/mach/rpm-8930.h b/arch/arm/mach-msm/include/mach/rpm-8930.h
new file mode 100644
index 0000000..5ec3a74
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/rpm-8930.h
@@ -0,0 +1,363 @@
+/* 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
+ * 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 __ARCH_ARM_MACH_MSM_RPM_8930_H
+#define __ARCH_ARM_MACH_MSM_RPM_8930_H
+
+/* RPM control message RAM enums */
+enum {
+	MSM_RPM_8930_CTRL_VERSION_MAJOR,
+	MSM_RPM_8930_CTRL_VERSION_MINOR,
+	MSM_RPM_8930_CTRL_VERSION_BUILD,
+
+	MSM_RPM_8930_CTRL_REQ_CTX_0,
+	MSM_RPM_8930_CTRL_REQ_CTX_7 = MSM_RPM_8930_CTRL_REQ_CTX_0 + 7,
+	MSM_RPM_8930_CTRL_REQ_SEL_0,
+	MSM_RPM_8930_CTRL_REQ_SEL_3 = MSM_RPM_8930_CTRL_REQ_SEL_0 + 3,
+	MSM_RPM_8930_CTRL_ACK_CTX_0,
+	MSM_RPM_8930_CTRL_ACK_CTX_7 = MSM_RPM_8930_CTRL_ACK_CTX_0 + 7,
+	MSM_RPM_8930_CTRL_ACK_SEL_0,
+	MSM_RPM_8930_CTRL_ACK_SEL_7 = MSM_RPM_8930_CTRL_ACK_SEL_0 + 7,
+};
+
+/* RPM resource select enums defined for RPM core
+   NOT IN SEQUENTIAL ORDER */
+enum {
+	MSM_RPM_8930_SEL_NOTIFICATION				= 0,
+	MSM_RPM_8930_SEL_INVALIDATE				= 1,
+	MSM_RPM_8930_SEL_TRIGGER_TIMED_0			= 2,
+	MSM_RPM_8930_SEL_RPM_CTL				= 3,
+	MSM_RPM_8930_SEL_CXO_CLK				= 5,
+	MSM_RPM_8930_SEL_PXO_CLK				= 6,
+	MSM_RPM_8930_SEL_QDSS_CLK				= 7,
+	MSM_RPM_8930_SEL_APPS_FABRIC_CLK			= 8,
+	MSM_RPM_8930_SEL_SYSTEM_FABRIC_CLK			= 9,
+	MSM_RPM_8930_SEL_MM_FABRIC_CLK				= 10,
+	MSM_RPM_8930_SEL_DAYTONA_FABRIC_CLK			= 11,
+	MSM_RPM_8930_SEL_SFPB_CLK				= 12,
+	MSM_RPM_8930_SEL_CFPB_CLK				= 13,
+	MSM_RPM_8930_SEL_MMFPB_CLK				= 14,
+	MSM_RPM_8930_SEL_EBI1_CLK				= 16,
+	MSM_RPM_8930_SEL_APPS_FABRIC_CFG_HALT			= 18,
+	MSM_RPM_8930_SEL_APPS_FABRIC_CFG_CLKMOD			= 19,
+	MSM_RPM_8930_SEL_APPS_FABRIC_CFG_IOCTL			= 20,
+	MSM_RPM_8930_SEL_APPS_FABRIC_ARB			= 21,
+	MSM_RPM_8930_SEL_SYS_FABRIC_CFG_HALT			= 22,
+	MSM_RPM_8930_SEL_SYS_FABRIC_CFG_CLKMOD			= 23,
+	MSM_RPM_8930_SEL_SYS_FABRIC_CFG_IOCTL			= 24,
+	MSM_RPM_8930_SEL_SYSTEM_FABRIC_ARB			= 25,
+	MSM_RPM_8930_SEL_MMSS_FABRIC_CFG_HALT			= 26,
+	MSM_RPM_8930_SEL_MMSS_FABRIC_CFG_CLKMOD			= 27,
+	MSM_RPM_8930_SEL_MMSS_FABRIC_CFG_IOCTL			= 28,
+	MSM_RPM_8930_SEL_MM_FABRIC_ARB				= 29,
+	MSM_RPM_8930_SEL_PM8038_S1				= 30,
+	MSM_RPM_8930_SEL_PM8038_S2				= 31,
+	MSM_RPM_8930_SEL_PM8038_S3				= 32,
+	MSM_RPM_8930_SEL_PM8038_S4				= 33,
+	MSM_RPM_8930_SEL_PM8038_S5				= 34,
+	MSM_RPM_8930_SEL_PM8038_S6				= 35,
+	MSM_RPM_8930_SEL_PM8038_L1				= 36,
+	MSM_RPM_8930_SEL_PM8038_L2				= 37,
+	MSM_RPM_8930_SEL_PM8038_L3				= 38,
+	MSM_RPM_8930_SEL_PM8038_L4				= 39,
+	MSM_RPM_8930_SEL_PM8038_L5				= 40,
+	MSM_RPM_8930_SEL_PM8038_L6				= 41,
+	MSM_RPM_8930_SEL_PM8038_L7				= 42,
+	MSM_RPM_8930_SEL_PM8038_L8				= 43,
+	MSM_RPM_8930_SEL_PM8038_L9				= 44,
+	MSM_RPM_8930_SEL_PM8038_L10				= 45,
+	MSM_RPM_8930_SEL_PM8038_L11				= 46,
+	MSM_RPM_8930_SEL_PM8038_L12				= 47,
+	MSM_RPM_8930_SEL_PM8038_L13				= 48,
+	MSM_RPM_8930_SEL_PM8038_L14				= 49,
+	MSM_RPM_8930_SEL_PM8038_L15				= 50,
+	MSM_RPM_8930_SEL_PM8038_L16				= 51,
+	MSM_RPM_8930_SEL_PM8038_L17				= 52,
+	MSM_RPM_8930_SEL_PM8038_L18				= 53,
+	MSM_RPM_8930_SEL_PM8038_L19				= 54,
+	MSM_RPM_8930_SEL_PM8038_L20				= 55,
+	MSM_RPM_8930_SEL_PM8038_L21				= 56,
+	MSM_RPM_8930_SEL_PM8038_L22				= 57,
+	MSM_RPM_8930_SEL_PM8038_L23				= 58,
+	MSM_RPM_8930_SEL_PM8038_L24				= 59,
+	MSM_RPM_8930_SEL_PM8038_L25				= 60,
+	MSM_RPM_8930_SEL_PM8038_L26				= 61,
+	MSM_RPM_8930_SEL_PM8038_L27				= 62,
+	MSM_RPM_8930_SEL_PM8038_CLK1				= 63,
+	MSM_RPM_8930_SEL_PM8038_CLK2				= 64,
+	MSM_RPM_8930_SEL_PM8038_LVS1				= 65,
+	MSM_RPM_8930_SEL_PM8038_LVS2				= 66,
+	MSM_RPM_8930_SEL_NCP					= 80,
+	MSM_RPM_8930_SEL_CXO_BUFFERS				= 81,
+	MSM_RPM_8930_SEL_USB_OTG_SWITCH				= 82,
+	MSM_RPM_8930_SEL_HDMI_SWITCH				= 83,
+	MSM_RPM_8930_SEL_DDR_DMM				= 84,
+	MSM_RPM_8930_SEL_VOLTAGE_CORNER				= 87,
+	MSM_RPM_8930_SEL_LAST = MSM_RPM_8930_SEL_VOLTAGE_CORNER,
+};
+
+/* RPM resource (4 byte) word ID enum */
+enum {
+	MSM_RPM_8930_ID_NOTIFICATION_CONFIGURED_0		= 0,
+	MSM_RPM_8930_ID_NOTIFICATION_CONFIGURED_3 =
+		MSM_RPM_8930_ID_NOTIFICATION_CONFIGURED_0 + 3,
+
+	MSM_RPM_8930_ID_NOTIFICATION_REGISTERED_0		= 4,
+	MSM_RPM_8930_ID_NOTIFICATION_REGISTERED_3 =
+		MSM_RPM_8930_ID_NOTIFICATION_REGISTERED_0 + 3,
+
+	MSM_RPM_8930_ID_INVALIDATE_0				= 8,
+	MSM_RPM_8930_ID_INVALIDATE_7 =
+		MSM_RPM_8930_ID_INVALIDATE_0 + 7,
+
+	MSM_RPM_8930_ID_TRIGGER_TIMED_TO_			= 16,
+	MSM_RPM_8930_ID_TRIGGER_TIMED_SCLK_COUNT		= 17,
+	MSM_RPM_8930_ID_RPM_CTL					= 18,
+	MSM_RPM_8930_ID_RESERVED_0				= 19,
+	MSM_RPM_8930_ID_RESERVED_5 =
+		MSM_RPM_8930_ID_RESERVED_0 + 5,
+	MSM_RPM_8930_ID_CXO_CLK					= 25,
+	MSM_RPM_8930_ID_PXO_CLK					= 26,
+	MSM_RPM_8930_ID_APPS_FABRIC_CLK				= 27,
+	MSM_RPM_8930_ID_SYSTEM_FABRIC_CLK			= 28,
+	MSM_RPM_8930_ID_MM_FABRIC_CLK				= 29,
+	MSM_RPM_8930_ID_DAYTONA_FABRIC_CLK			= 30,
+	MSM_RPM_8930_ID_SFPB_CLK				= 31,
+	MSM_RPM_8930_ID_CFPB_CLK				= 32,
+	MSM_RPM_8930_ID_MMFPB_CLK				= 33,
+	MSM_RPM_8930_ID_EBI1_CLK				= 34,
+	MSM_RPM_8930_ID_APPS_FABRIC_CFG_HALT_0			= 35,
+	MSM_RPM_8930_ID_APPS_FABRIC_CFG_HALT_1			= 36,
+	MSM_RPM_8930_ID_APPS_FABRIC_CFG_CLKMOD_0		= 37,
+	MSM_RPM_8930_ID_APPS_FABRIC_CFG_CLKMOD_1		= 38,
+	MSM_RPM_8930_ID_APPS_FABRIC_CFG_CLKMOD_2		= 39,
+	MSM_RPM_8930_ID_APPS_FABRIC_CFG_IOCTL			= 40,
+	MSM_RPM_8930_ID_APPS_FABRIC_ARB_0			= 41,
+	MSM_RPM_8930_ID_APPS_FABRIC_ARB_5 =
+		MSM_RPM_8930_ID_APPS_FABRIC_ARB_0 + 5,
+	MSM_RPM_8930_ID_SYS_FABRIC_CFG_HALT_0			= 47,
+	MSM_RPM_8930_ID_SYS_FABRIC_CFG_HALT_1			= 48,
+	MSM_RPM_8930_ID_SYS_FABRIC_CFG_CLKMOD_0			= 49,
+	MSM_RPM_8930_ID_SYS_FABRIC_CFG_CLKMOD_1			= 50,
+	MSM_RPM_8930_ID_SYS_FABRIC_CFG_CLKMOD_2			= 51,
+	MSM_RPM_8930_ID_SYS_FABRIC_CFG_IOCTL			= 52,
+	MSM_RPM_8930_ID_SYSTEM_FABRIC_ARB_0			= 53,
+	MSM_RPM_8930_ID_SYSTEM_FABRIC_ARB_19 =
+		MSM_RPM_8930_ID_SYSTEM_FABRIC_ARB_0 + 19,
+	MSM_RPM_8930_ID_MMSS_FABRIC_CFG_HALT_0			= 73,
+	MSM_RPM_8930_ID_MMSS_FABRIC_CFG_HALT_1			= 74,
+	MSM_RPM_8930_ID_MMSS_FABRIC_CFG_CLKMOD_0		= 75,
+	MSM_RPM_8930_ID_MMSS_FABRIC_CFG_CLKMOD_1		= 76,
+	MSM_RPM_8930_ID_MMSS_FABRIC_CFG_CLKMOD_2		= 77,
+	MSM_RPM_8930_ID_MMSS_FABRIC_CFG_IOCTL			= 78,
+	MSM_RPM_8930_ID_MM_FABRIC_ARB_0				= 79,
+	MSM_RPM_8930_ID_MM_FABRIC_ARB_10 =
+		MSM_RPM_8930_ID_MM_FABRIC_ARB_0	+ 10,
+
+	MSM_RPM_8930_ID_PM8038_S1_0	= 90,
+	MSM_RPM_8930_ID_PM8038_S1_1	= 91,
+	MSM_RPM_8930_ID_PM8038_S2_0	= 92,
+	MSM_RPM_8930_ID_PM8038_S2_1	= 93,
+	MSM_RPM_8930_ID_PM8038_S3_0	= 94,
+	MSM_RPM_8930_ID_PM8038_S3_1	= 95,
+	MSM_RPM_8930_ID_PM8038_S4_0	= 96,
+	MSM_RPM_8930_ID_PM8038_S4_1	= 97,
+	MSM_RPM_8930_ID_PM8038_S5_0	= 98,
+	MSM_RPM_8930_ID_PM8038_S5_1	= 99,
+	MSM_RPM_8930_ID_PM8038_S6_0	= 100,
+	MSM_RPM_8930_ID_PM8038_S6_1	= 101,
+	MSM_RPM_8930_ID_PM8038_L1_0	= 102,
+	MSM_RPM_8930_ID_PM8038_L1_1	= 103,
+	MSM_RPM_8930_ID_PM8038_L2_0	= 104,
+	MSM_RPM_8930_ID_PM8038_L2_1	= 105,
+	MSM_RPM_8930_ID_PM8038_L3_0	= 106,
+	MSM_RPM_8930_ID_PM8038_L3_1	= 107,
+	MSM_RPM_8930_ID_PM8038_L4_0	= 108,
+	MSM_RPM_8930_ID_PM8038_L4_1	= 109,
+	MSM_RPM_8930_ID_PM8038_L5_0	= 110,
+	MSM_RPM_8930_ID_PM8038_L5_1	= 111,
+	MSM_RPM_8930_ID_PM8038_L6_0	= 112,
+	MSM_RPM_8930_ID_PM8038_L6_1	= 113,
+	MSM_RPM_8930_ID_PM8038_L7_0	= 114,
+	MSM_RPM_8930_ID_PM8038_L7_1	= 115,
+	MSM_RPM_8930_ID_PM8038_L8_0	= 116,
+	MSM_RPM_8930_ID_PM8038_L8_1	= 117,
+	MSM_RPM_8930_ID_PM8038_L9_0	= 118,
+	MSM_RPM_8930_ID_PM8038_L9_1	= 119,
+	MSM_RPM_8930_ID_PM8038_L10_0	= 120,
+	MSM_RPM_8930_ID_PM8038_L10_1	= 121,
+	MSM_RPM_8930_ID_PM8038_L11_0	= 122,
+	MSM_RPM_8930_ID_PM8038_L11_1	= 123,
+	MSM_RPM_8930_ID_PM8038_L12_0	= 124,
+	MSM_RPM_8930_ID_PM8038_L12_1	= 125,
+	MSM_RPM_8930_ID_PM8038_L13_0	= 126,
+	MSM_RPM_8930_ID_PM8038_L13_1	= 127,
+	MSM_RPM_8930_ID_PM8038_L14_0	= 128,
+	MSM_RPM_8930_ID_PM8038_L14_1	= 129,
+	MSM_RPM_8930_ID_PM8038_L15_0	= 130,
+	MSM_RPM_8930_ID_PM8038_L15_1	= 131,
+	MSM_RPM_8930_ID_PM8038_L16_0	= 132,
+	MSM_RPM_8930_ID_PM8038_L16_1	= 133,
+	MSM_RPM_8930_ID_PM8038_L17_0	= 134,
+	MSM_RPM_8930_ID_PM8038_L17_1	= 135,
+	MSM_RPM_8930_ID_PM8038_L18_0	= 136,
+	MSM_RPM_8930_ID_PM8038_L18_1	= 137,
+	MSM_RPM_8930_ID_PM8038_L19_0	= 138,
+	MSM_RPM_8930_ID_PM8038_L19_1	= 139,
+	MSM_RPM_8930_ID_PM8038_L20_0	= 140,
+	MSM_RPM_8930_ID_PM8038_L20_1	= 141,
+	MSM_RPM_8930_ID_PM8038_L21_0	= 142,
+	MSM_RPM_8930_ID_PM8038_L21_1	= 143,
+	MSM_RPM_8930_ID_PM8038_L22_0	= 144,
+	MSM_RPM_8930_ID_PM8038_L22_1	= 145,
+	MSM_RPM_8930_ID_PM8038_L23_0	= 146,
+	MSM_RPM_8930_ID_PM8038_L23_1	= 147,
+	MSM_RPM_8930_ID_PM8038_L24_0	= 148,
+	MSM_RPM_8930_ID_PM8038_L24_1	= 149,
+	MSM_RPM_8930_ID_PM8038_L25_0	= 150,
+	MSM_RPM_8930_ID_PM8038_L25_1	= 151,
+	MSM_RPM_8930_ID_PM8038_L26_0	= 152,
+	MSM_RPM_8930_ID_PM8038_L26_1	= 153,
+	MSM_RPM_8930_ID_PM8038_L27_0	= 154,
+	MSM_RPM_8930_ID_PM8038_L27_1	= 155,
+	MSM_RPM_8930_ID_PM8038_CLK1_0	= 156,
+	MSM_RPM_8930_ID_PM8038_CLK1_1	= 157,
+	MSM_RPM_8930_ID_PM8038_CLK2_0	= 158,
+	MSM_RPM_8930_ID_PM8038_CLK2_1	= 159,
+	MSM_RPM_8930_ID_PM8038_LVS1	= 160,
+	MSM_RPM_8930_ID_PM8038_LVS2	= 161,
+	MSM_RPM_8930_ID_NCP_0	= 162,
+	MSM_RPM_8930_ID_NCP_1	= 163,
+	MSM_RPM_8930_ID_CXO_BUFFERS	= 164,
+	MSM_RPM_8930_ID_USB_OTG_SWITCH	= 165,
+	MSM_RPM_8930_ID_HDMI_SWITCH	= 166,
+	MSM_RPM_8930_ID_DDR_DMM_0		= 167,
+	MSM_RPM_8930_ID_DDR_DMM_1		= 168,
+	MSM_RPM_8930_ID_QDSS_CLK	= 168,
+	MSM_RPM_8930_ID_VOLTAGE_CORNER	= 169,
+	MSM_RPM_8930_ID_LAST = MSM_RPM_8930_ID_VOLTAGE_CORNER,
+};
+
+/* RPM status ID enum */
+enum {
+	MSM_RPM_8930_STATUS_ID_VERSION_MAJOR			= 0,
+	MSM_RPM_8930_STATUS_ID_VERSION_MINOR			= 1,
+	MSM_RPM_8930_STATUS_ID_VERSION_BUILD			= 2,
+	MSM_RPM_8930_STATUS_ID_SUPPORTED_RESOURCES_0		= 3,
+	MSM_RPM_8930_STATUS_ID_SUPPORTED_RESOURCES_1		= 4,
+	MSM_RPM_8930_STATUS_ID_SUPPORTED_RESOURCES_2		= 5,
+	MSM_RPM_8930_STATUS_ID_RESERVED_SUPPORTED_RESOURCES_0	= 6,
+	MSM_RPM_8930_STATUS_ID_SEQUENCE				= 7,
+	MSM_RPM_8930_STATUS_ID_RPM_CTL				= 8,
+	MSM_RPM_8930_STATUS_ID_CXO_CLK				= 9,
+	MSM_RPM_8930_STATUS_ID_PXO_CLK				= 10,
+	MSM_RPM_8930_STATUS_ID_APPS_FABRIC_CLK			= 11,
+	MSM_RPM_8930_STATUS_ID_SYSTEM_FABRIC_CLK		= 12,
+	MSM_RPM_8930_STATUS_ID_MM_FABRIC_CLK			= 13,
+	MSM_RPM_8930_STATUS_ID_DAYTONA_FABRIC_CLK		= 14,
+	MSM_RPM_8930_STATUS_ID_SFPB_CLK				= 15,
+	MSM_RPM_8930_STATUS_ID_CFPB_CLK				= 16,
+	MSM_RPM_8930_STATUS_ID_MMFPB_CLK			= 17,
+	MSM_RPM_8930_STATUS_ID_EBI1_CLK				= 18,
+	MSM_RPM_8930_STATUS_ID_APPS_FABRIC_CFG_HALT		= 19,
+	MSM_RPM_8930_STATUS_ID_APPS_FABRIC_CFG_CLKMOD		= 20,
+	MSM_RPM_8930_STATUS_ID_APPS_FABRIC_CFG_IOCTL		= 21,
+	MSM_RPM_8930_STATUS_ID_APPS_FABRIC_ARB			= 22,
+	MSM_RPM_8930_STATUS_ID_SYS_FABRIC_CFG_HALT		= 23,
+	MSM_RPM_8930_STATUS_ID_SYS_FABRIC_CFG_CLKMOD		= 24,
+	MSM_RPM_8930_STATUS_ID_SYS_FABRIC_CFG_IOCTL		= 25,
+	MSM_RPM_8930_STATUS_ID_SYSTEM_FABRIC_ARB		= 26,
+	MSM_RPM_8930_STATUS_ID_MMSS_FABRIC_CFG_HALT		= 27,
+	MSM_RPM_8930_STATUS_ID_MMSS_FABRIC_CFG_CLKMOD		= 28,
+	MSM_RPM_8930_STATUS_ID_MMSS_FABRIC_CFG_IOCTL		= 29,
+	MSM_RPM_8930_STATUS_ID_MM_FABRIC_ARB			= 30,
+	MSM_RPM_8930_STATUS_ID_PM8038_S1_0			= 31,
+	MSM_RPM_8930_STATUS_ID_PM8038_S1_1			= 32,
+	MSM_RPM_8930_STATUS_ID_PM8038_S2_0			= 33,
+	MSM_RPM_8930_STATUS_ID_PM8038_S2_1			= 34,
+	MSM_RPM_8930_STATUS_ID_PM8038_S3_0			= 35,
+	MSM_RPM_8930_STATUS_ID_PM8038_S3_1			= 36,
+	MSM_RPM_8930_STATUS_ID_PM8038_S4_0			= 37,
+	MSM_RPM_8930_STATUS_ID_PM8038_S4_1			= 38,
+	MSM_RPM_8930_STATUS_ID_PM8038_L1_0			= 43,
+	MSM_RPM_8930_STATUS_ID_PM8038_L1_1			= 44,
+	MSM_RPM_8930_STATUS_ID_PM8038_L2_0			= 45,
+	MSM_RPM_8930_STATUS_ID_PM8038_L2_1			= 46,
+	MSM_RPM_8930_STATUS_ID_PM8038_L3_0			= 47,
+	MSM_RPM_8930_STATUS_ID_PM8038_L3_1			= 48,
+	MSM_RPM_8930_STATUS_ID_PM8038_L4_0			= 49,
+	MSM_RPM_8930_STATUS_ID_PM8038_L4_1			= 50,
+	MSM_RPM_8930_STATUS_ID_PM8038_L5_0			= 51,
+	MSM_RPM_8930_STATUS_ID_PM8038_L5_1			= 52,
+	MSM_RPM_8930_STATUS_ID_PM8038_L6_0			= 53,
+	MSM_RPM_8930_STATUS_ID_PM8038_L6_1			= 54,
+	MSM_RPM_8930_STATUS_ID_PM8038_L7_0			= 55,
+	MSM_RPM_8930_STATUS_ID_PM8038_L7_1			= 56,
+	MSM_RPM_8930_STATUS_ID_PM8038_L8_0			= 57,
+	MSM_RPM_8930_STATUS_ID_PM8038_L8_1			= 58,
+	MSM_RPM_8930_STATUS_ID_PM8038_L9_0			= 59,
+	MSM_RPM_8930_STATUS_ID_PM8038_L9_1			= 60,
+	MSM_RPM_8930_STATUS_ID_PM8038_L10_0			= 61,
+	MSM_RPM_8930_STATUS_ID_PM8038_L10_1			= 62,
+	MSM_RPM_8930_STATUS_ID_PM8038_L11_0			= 63,
+	MSM_RPM_8930_STATUS_ID_PM8038_L11_1			= 64,
+	MSM_RPM_8930_STATUS_ID_PM8038_L12_0			= 65,
+	MSM_RPM_8930_STATUS_ID_PM8038_L12_1			= 66,
+	MSM_RPM_8930_STATUS_ID_PM8038_L13_0			= 67,
+	MSM_RPM_8930_STATUS_ID_PM8038_L13_1			= 68,
+	MSM_RPM_8930_STATUS_ID_PM8038_L14_0			= 69,
+	MSM_RPM_8930_STATUS_ID_PM8038_L14_1			= 70,
+	MSM_RPM_8930_STATUS_ID_PM8038_L15_0			= 71,
+	MSM_RPM_8930_STATUS_ID_PM8038_L15_1			= 72,
+	MSM_RPM_8930_STATUS_ID_PM8038_L16_0			= 73,
+	MSM_RPM_8930_STATUS_ID_PM8038_L16_1			= 74,
+	MSM_RPM_8930_STATUS_ID_PM8038_L17_0			= 75,
+	MSM_RPM_8930_STATUS_ID_PM8038_L17_1			= 76,
+	MSM_RPM_8930_STATUS_ID_PM8038_L18_0			= 77,
+	MSM_RPM_8930_STATUS_ID_PM8038_L18_1			= 78,
+	MSM_RPM_8930_STATUS_ID_PM8038_L19_0			= 79,
+	MSM_RPM_8930_STATUS_ID_PM8038_L19_1			= 80,
+	MSM_RPM_8930_STATUS_ID_PM8038_L20_0			= 81,
+	MSM_RPM_8930_STATUS_ID_PM8038_L20_1			= 82,
+	MSM_RPM_8930_STATUS_ID_PM8038_L21_0			= 83,
+	MSM_RPM_8930_STATUS_ID_PM8038_L21_1			= 84,
+	MSM_RPM_8930_STATUS_ID_PM8038_L22_0			= 85,
+	MSM_RPM_8930_STATUS_ID_PM8038_L22_1			= 86,
+	MSM_RPM_8930_STATUS_ID_PM8038_L23_0			= 87,
+	MSM_RPM_8930_STATUS_ID_PM8038_L23_1			= 88,
+	MSM_RPM_8930_STATUS_ID_PM8038_L24_0			= 89,
+	MSM_RPM_8930_STATUS_ID_PM8038_L24_1			= 90,
+	MSM_RPM_8930_STATUS_ID_PM8038_L25_0			= 91,
+	MSM_RPM_8930_STATUS_ID_PM8038_L25_1			= 92,
+	MSM_RPM_8930_STATUS_ID_PM8038_L26_0			= 93,
+	MSM_RPM_8930_STATUS_ID_PM8038_L26_1			= 94,
+	MSM_RPM_8930_STATUS_ID_PM8038_L27_0			= 95,
+	MSM_RPM_8930_STATUS_ID_PM8038_L27_1			= 96,
+	MSM_RPM_8930_STATUS_ID_PM8038_CLK1_0			= 97,
+	MSM_RPM_8930_STATUS_ID_PM8038_CLK1_1			= 98,
+	MSM_RPM_8930_STATUS_ID_PM8038_CLK2_0			= 99,
+	MSM_RPM_8930_STATUS_ID_PM8038_CLK2_1			= 100,
+	MSM_RPM_8930_STATUS_ID_PM8038_LVS1			= 101,
+	MSM_RPM_8930_STATUS_ID_PM8038_LVS2			= 102,
+	MSM_RPM_8930_STATUS_ID_NCP_0				= 103,
+	MSM_RPM_8930_STATUS_ID_NCP_1				= 104,
+	MSM_RPM_8930_STATUS_ID_CXO_BUFFERS			= 105,
+	MSM_RPM_8930_STATUS_ID_USB_OTG_SWITCH			= 106,
+	MSM_RPM_8930_STATUS_ID_HDMI_SWITCH			= 107,
+	MSM_RPM_8930_STATUS_ID_DDR_DMM_0			= 108,
+	MSM_RPM_8930_STATUS_ID_DDR_DMM_1			= 109,
+	MSM_RPM_8930_STATUS_ID_QDSS_CLK				= 110,
+	MSM_RPM_8930_STATUS_ID_VOLTAGE_CORNER			= 111,
+	MSM_RPM_8930_STATUS_ID_LAST = MSM_RPM_8930_STATUS_ID_VOLTAGE_CORNER,
+};
+
+#endif /* __ARCH_ARM_MACH_MSM_RPM_8930_H */
diff --git a/arch/arm/mach-msm/include/mach/rpm-8960.h b/arch/arm/mach-msm/include/mach/rpm-8960.h
new file mode 100644
index 0000000..6fe8832
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/rpm-8960.h
@@ -0,0 +1,416 @@
+/* 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
+ * 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 __ARCH_ARM_MACH_MSM_RPM_8960_H
+#define __ARCH_ARM_MACH_MSM_RPM_8960_H
+
+/* RPM control message RAM enums */
+enum {
+	MSM_RPM_8960_CTRL_VERSION_MAJOR,
+	MSM_RPM_8960_CTRL_VERSION_MINOR,
+	MSM_RPM_8960_CTRL_VERSION_BUILD,
+
+	MSM_RPM_8960_CTRL_REQ_CTX_0,
+	MSM_RPM_8960_CTRL_REQ_CTX_7 = MSM_RPM_8960_CTRL_REQ_CTX_0 + 7,
+	MSM_RPM_8960_CTRL_REQ_SEL_0,
+	MSM_RPM_8960_CTRL_REQ_SEL_3 = MSM_RPM_8960_CTRL_REQ_SEL_0 + 3,
+	MSM_RPM_8960_CTRL_ACK_CTX_0,
+	MSM_RPM_8960_CTRL_ACK_CTX_7 = MSM_RPM_8960_CTRL_ACK_CTX_0 + 7,
+	MSM_RPM_8960_CTRL_ACK_SEL_0,
+	MSM_RPM_8960_CTRL_ACK_SEL_7 = MSM_RPM_8960_CTRL_ACK_SEL_0 + 7,
+};
+
+/* RPM resource select enums defined for RPM core
+   NOT IN SEQUENTIAL ORDER */
+enum {
+	MSM_RPM_8960_SEL_NOTIFICATION					= 0,
+	MSM_RPM_8960_SEL_INVALIDATE					= 1,
+	MSM_RPM_8960_SEL_TRIGGER_TIMED					= 2,
+	MSM_RPM_8960_SEL_RPM_CTL					= 3,
+
+	MSM_RPM_8960_SEL_CXO_CLK					= 5,
+	MSM_RPM_8960_SEL_PXO_CLK					= 6,
+	MSM_RPM_8960_SEL_QDSS_CLK					= 7,
+	MSM_RPM_8960_SEL_APPS_FABRIC_CLK				= 8,
+	MSM_RPM_8960_SEL_SYSTEM_FABRIC_CLK				= 9,
+	MSM_RPM_8960_SEL_MM_FABRIC_CLK					= 10,
+	MSM_RPM_8960_SEL_DAYTONA_FABRIC_CLK				= 11,
+	MSM_RPM_8960_SEL_SFPB_CLK					= 12,
+	MSM_RPM_8960_SEL_CFPB_CLK					= 13,
+	MSM_RPM_8960_SEL_MMFPB_CLK					= 14,
+	MSM_RPM_8960_SEL_EBI1_CLK					= 16,
+
+	MSM_RPM_8960_SEL_APPS_FABRIC_CFG_HALT				= 18,
+	MSM_RPM_8960_SEL_APPS_FABRIC_CFG_CLKMOD				= 19,
+	MSM_RPM_8960_SEL_APPS_FABRIC_CFG_IOCTL				= 20,
+	MSM_RPM_8960_SEL_APPS_FABRIC_ARB				= 21,
+
+	MSM_RPM_8960_SEL_SYS_FABRIC_CFG_HALT				= 22,
+	MSM_RPM_8960_SEL_SYS_FABRIC_CFG_CLKMOD				= 23,
+	MSM_RPM_8960_SEL_SYS_FABRIC_CFG_IOCTL				= 24,
+	MSM_RPM_8960_SEL_SYSTEM_FABRIC_ARB				= 25,
+
+	MSM_RPM_8960_SEL_MMSS_FABRIC_CFG_HALT				= 26,
+	MSM_RPM_8960_SEL_MMSS_FABRIC_CFG_CLKMOD				= 27,
+	MSM_RPM_8960_SEL_MMSS_FABRIC_CFG_IOCTL				= 28,
+	MSM_RPM_8960_SEL_MM_FABRIC_ARB					= 29,
+
+	MSM_RPM_8960_SEL_PM8921_S1					= 30,
+	MSM_RPM_8960_SEL_PM8921_S2					= 31,
+	MSM_RPM_8960_SEL_PM8921_S3					= 32,
+	MSM_RPM_8960_SEL_PM8921_S4					= 33,
+	MSM_RPM_8960_SEL_PM8921_S5					= 34,
+	MSM_RPM_8960_SEL_PM8921_S6					= 35,
+	MSM_RPM_8960_SEL_PM8921_S7					= 36,
+	MSM_RPM_8960_SEL_PM8921_S8					= 37,
+	MSM_RPM_8960_SEL_PM8921_L1					= 38,
+	MSM_RPM_8960_SEL_PM8921_L2					= 39,
+	MSM_RPM_8960_SEL_PM8921_L3					= 40,
+	MSM_RPM_8960_SEL_PM8921_L4					= 41,
+	MSM_RPM_8960_SEL_PM8921_L5					= 42,
+	MSM_RPM_8960_SEL_PM8921_L6					= 43,
+	MSM_RPM_8960_SEL_PM8921_L7					= 44,
+	MSM_RPM_8960_SEL_PM8921_L8					= 45,
+	MSM_RPM_8960_SEL_PM8921_L9					= 46,
+	MSM_RPM_8960_SEL_PM8921_L10					= 47,
+	MSM_RPM_8960_SEL_PM8921_L11					= 48,
+	MSM_RPM_8960_SEL_PM8921_L12					= 49,
+	MSM_RPM_8960_SEL_PM8921_L13					= 50,
+	MSM_RPM_8960_SEL_PM8921_L14					= 51,
+	MSM_RPM_8960_SEL_PM8921_L15					= 52,
+	MSM_RPM_8960_SEL_PM8921_L16					= 53,
+	MSM_RPM_8960_SEL_PM8921_L17					= 54,
+	MSM_RPM_8960_SEL_PM8921_L18					= 55,
+	MSM_RPM_8960_SEL_PM8921_L19					= 56,
+	MSM_RPM_8960_SEL_PM8921_L20					= 57,
+	MSM_RPM_8960_SEL_PM8921_L21					= 58,
+	MSM_RPM_8960_SEL_PM8921_L22					= 59,
+	MSM_RPM_8960_SEL_PM8921_L23					= 60,
+	MSM_RPM_8960_SEL_PM8921_L24					= 61,
+	MSM_RPM_8960_SEL_PM8921_L25					= 62,
+	MSM_RPM_8960_SEL_PM8921_L26					= 63,
+	MSM_RPM_8960_SEL_PM8921_L27					= 64,
+	MSM_RPM_8960_SEL_PM8921_L28					= 65,
+	MSM_RPM_8960_SEL_PM8921_L29					= 66,
+	MSM_RPM_8960_SEL_PM8921_CLK1					= 67,
+	MSM_RPM_8960_SEL_PM8921_CLK2					= 68,
+	MSM_RPM_8960_SEL_PM8921_LVS1					= 69,
+	MSM_RPM_8960_SEL_PM8921_LVS2					= 70,
+	MSM_RPM_8960_SEL_PM8921_LVS3					= 71,
+	MSM_RPM_8960_SEL_PM8921_LVS4					= 72,
+	MSM_RPM_8960_SEL_PM8921_LVS5					= 73,
+	MSM_RPM_8960_SEL_PM8921_LVS6					= 74,
+	MSM_RPM_8960_SEL_PM8921_LVS7					= 75,
+
+	MSM_RPM_8960_SEL_NCP						= 80,
+	MSM_RPM_8960_SEL_CXO_BUFFERS					= 81,
+	MSM_RPM_8960_SEL_USB_OTG_SWITCH					= 82,
+	MSM_RPM_8960_SEL_HDMI_SWITCH					= 83,
+	MSM_RPM_8960_SEL_DDR_DMM					= 84,
+
+	MSM_RPM_8960_SEL_LAST = MSM_RPM_8960_SEL_DDR_DMM,
+};
+
+/* RPM resource (4 byte) word ID enum */
+enum {
+	MSM_RPM_8960_ID_NOTIFICATION_CONFIGURED_0			= 0,
+	MSM_RPM_8960_ID_NOTIFICATION_CONFIGURED_3 =
+		MSM_RPM_8960_ID_NOTIFICATION_CONFIGURED_0 + 3,
+
+	MSM_RPM_8960_ID_NOTIFICATION_REGISTERED_0			= 4,
+	MSM_RPM_8960_ID_NOTIFICATION_REGISTERED_3 =
+		MSM_RPM_8960_ID_NOTIFICATION_REGISTERED_0 + 3,
+
+	MSM_RPM_8960_ID_INVALIDATE_0					= 8,
+	MSM_RPM_8960_ID_INVALIDATE_7 =
+		MSM_RPM_8960_ID_INVALIDATE_0 + 7,
+
+	MSM_RPM_8960_ID_TRIGGER_TIMED_TO				= 16,
+	MSM_RPM_8960_ID_TRIGGER_TIMED_SCLK_COUNT			= 17,
+
+	MSM_RPM_8960_ID_RPM_CTL						= 18,
+
+	/* TRIGGER_CLEAR/SET deprecated in these 24 RESERVED bytes */
+	MSM_RPM_8960_ID_RESERVED_0					= 19,
+	MSM_RPM_8960_ID_RESERVED_5 =
+		MSM_RPM_8960_ID_RESERVED_0 + 5,
+
+	MSM_RPM_8960_ID_CXO_CLK						= 25,
+	MSM_RPM_8960_ID_PXO_CLK						= 26,
+	MSM_RPM_8960_ID_APPS_FABRIC_CLK					= 27,
+	MSM_RPM_8960_ID_SYSTEM_FABRIC_CLK				= 28,
+	MSM_RPM_8960_ID_MM_FABRIC_CLK					= 29,
+	MSM_RPM_8960_ID_DAYTONA_FABRIC_CLK				= 30,
+	MSM_RPM_8960_ID_SFPB_CLK					= 31,
+	MSM_RPM_8960_ID_CFPB_CLK					= 32,
+	MSM_RPM_8960_ID_MMFPB_CLK					= 33,
+	MSM_RPM_8960_ID_EBI1_CLK					= 34,
+
+	MSM_RPM_8960_ID_APPS_FABRIC_CFG_HALT_0				= 35,
+	MSM_RPM_8960_ID_APPS_FABRIC_CFG_HALT_1				= 36,
+	MSM_RPM_8960_ID_APPS_FABRIC_CFG_CLKMOD_0			= 37,
+	MSM_RPM_8960_ID_APPS_FABRIC_CFG_CLKMOD_1			= 38,
+	MSM_RPM_8960_ID_APPS_FABRIC_CFG_CLKMOD_2			= 39,
+	MSM_RPM_8960_ID_APPS_FABRIC_CFG_IOCTL				= 40,
+	MSM_RPM_8960_ID_APPS_FABRIC_ARB_0				= 41,
+	MSM_RPM_8960_ID_APPS_FABRIC_ARB_11 =
+		MSM_RPM_8960_ID_APPS_FABRIC_ARB_0 + 11,
+
+	MSM_RPM_8960_ID_SYS_FABRIC_CFG_HALT_0				= 53,
+	MSM_RPM_8960_ID_SYS_FABRIC_CFG_HALT_1				= 54,
+	MSM_RPM_8960_ID_SYS_FABRIC_CFG_CLKMOD_0				= 55,
+	MSM_RPM_8960_ID_SYS_FABRIC_CFG_CLKMOD_1				= 56,
+	MSM_RPM_8960_ID_SYS_FABRIC_CFG_CLKMOD_2				= 57,
+	MSM_RPM_8960_ID_SYS_FABRIC_CFG_IOCTL				= 58,
+	MSM_RPM_8960_ID_SYSTEM_FABRIC_ARB_0				= 59,
+	MSM_RPM_8960_ID_SYSTEM_FABRIC_ARB_28 =
+		MSM_RPM_8960_ID_SYSTEM_FABRIC_ARB_0 + 28,
+
+	MSM_RPM_8960_ID_MMSS_FABRIC_CFG_HALT_0				= 88,
+	MSM_RPM_8960_ID_MMSS_FABRIC_CFG_HALT_1				= 89,
+	MSM_RPM_8960_ID_MMSS_FABRIC_CFG_CLKMOD_0			= 90,
+	MSM_RPM_8960_ID_MMSS_FABRIC_CFG_CLKMOD_1			= 91,
+	MSM_RPM_8960_ID_MMSS_FABRIC_CFG_CLKMOD_2			= 92,
+	MSM_RPM_8960_ID_MMSS_FABRIC_CFG_IOCTL				= 93,
+	MSM_RPM_8960_ID_MM_FABRIC_ARB_0					= 94,
+	MSM_RPM_8960_ID_MM_FABRIC_ARB_22 =
+		MSM_RPM_8960_ID_MM_FABRIC_ARB_0 + 22,
+
+	MSM_RPM_8960_ID_PM8921_S1_0					= 117,
+	MSM_RPM_8960_ID_PM8921_S1_1					= 118,
+	MSM_RPM_8960_ID_PM8921_S2_0					= 119,
+	MSM_RPM_8960_ID_PM8921_S2_1					= 120,
+	MSM_RPM_8960_ID_PM8921_S3_0					= 121,
+	MSM_RPM_8960_ID_PM8921_S3_1					= 122,
+	MSM_RPM_8960_ID_PM8921_S4_0					= 123,
+	MSM_RPM_8960_ID_PM8921_S4_1					= 124,
+	MSM_RPM_8960_ID_PM8921_S5_0					= 125,
+	MSM_RPM_8960_ID_PM8921_S5_1					= 126,
+	MSM_RPM_8960_ID_PM8921_S6_0					= 127,
+	MSM_RPM_8960_ID_PM8921_S6_1					= 128,
+	MSM_RPM_8960_ID_PM8921_S7_0					= 129,
+	MSM_RPM_8960_ID_PM8921_S7_1					= 130,
+	MSM_RPM_8960_ID_PM8921_S8_0					= 131,
+	MSM_RPM_8960_ID_PM8921_S8_1					= 132,
+	MSM_RPM_8960_ID_PM8921_L1_0					= 133,
+	MSM_RPM_8960_ID_PM8921_L1_1					= 134,
+	MSM_RPM_8960_ID_PM8921_L2_0					= 135,
+	MSM_RPM_8960_ID_PM8921_L2_1					= 136,
+	MSM_RPM_8960_ID_PM8921_L3_0					= 137,
+	MSM_RPM_8960_ID_PM8921_L3_1					= 138,
+	MSM_RPM_8960_ID_PM8921_L4_0					= 139,
+	MSM_RPM_8960_ID_PM8921_L4_1					= 140,
+	MSM_RPM_8960_ID_PM8921_L5_0					= 141,
+	MSM_RPM_8960_ID_PM8921_L5_1					= 142,
+	MSM_RPM_8960_ID_PM8921_L6_0					= 143,
+	MSM_RPM_8960_ID_PM8921_L6_1					= 144,
+	MSM_RPM_8960_ID_PM8921_L7_0					= 145,
+	MSM_RPM_8960_ID_PM8921_L7_1					= 146,
+	MSM_RPM_8960_ID_PM8921_L8_0					= 147,
+	MSM_RPM_8960_ID_PM8921_L8_1					= 148,
+	MSM_RPM_8960_ID_PM8921_L9_0					= 149,
+	MSM_RPM_8960_ID_PM8921_L9_1					= 150,
+	MSM_RPM_8960_ID_PM8921_L10_0					= 151,
+	MSM_RPM_8960_ID_PM8921_L10_1					= 152,
+	MSM_RPM_8960_ID_PM8921_L11_0					= 153,
+	MSM_RPM_8960_ID_PM8921_L11_1					= 154,
+	MSM_RPM_8960_ID_PM8921_L12_0					= 155,
+	MSM_RPM_8960_ID_PM8921_L12_1					= 156,
+	MSM_RPM_8960_ID_PM8921_L13_0					= 157,
+	MSM_RPM_8960_ID_PM8921_L13_1					= 158,
+	MSM_RPM_8960_ID_PM8921_L14_0					= 159,
+	MSM_RPM_8960_ID_PM8921_L14_1					= 160,
+	MSM_RPM_8960_ID_PM8921_L15_0					= 161,
+	MSM_RPM_8960_ID_PM8921_L15_1					= 162,
+	MSM_RPM_8960_ID_PM8921_L16_0					= 163,
+	MSM_RPM_8960_ID_PM8921_L16_1					= 164,
+	MSM_RPM_8960_ID_PM8921_L17_0					= 165,
+	MSM_RPM_8960_ID_PM8921_L17_1					= 166,
+	MSM_RPM_8960_ID_PM8921_L18_0					= 167,
+	MSM_RPM_8960_ID_PM8921_L18_1					= 168,
+	MSM_RPM_8960_ID_PM8921_L19_0					= 169,
+	MSM_RPM_8960_ID_PM8921_L19_1					= 170,
+	MSM_RPM_8960_ID_PM8921_L20_0					= 171,
+	MSM_RPM_8960_ID_PM8921_L20_1					= 172,
+	MSM_RPM_8960_ID_PM8921_L21_0					= 173,
+	MSM_RPM_8960_ID_PM8921_L21_1					= 174,
+	MSM_RPM_8960_ID_PM8921_L22_0					= 175,
+	MSM_RPM_8960_ID_PM8921_L22_1					= 176,
+	MSM_RPM_8960_ID_PM8921_L23_0					= 177,
+	MSM_RPM_8960_ID_PM8921_L23_1					= 178,
+	MSM_RPM_8960_ID_PM8921_L24_0					= 179,
+	MSM_RPM_8960_ID_PM8921_L24_1					= 180,
+	MSM_RPM_8960_ID_PM8921_L25_0					= 181,
+	MSM_RPM_8960_ID_PM8921_L25_1					= 182,
+	MSM_RPM_8960_ID_PM8921_L26_0					= 183,
+	MSM_RPM_8960_ID_PM8921_L26_1					= 184,
+	MSM_RPM_8960_ID_PM8921_L27_0					= 185,
+	MSM_RPM_8960_ID_PM8921_L27_1					= 186,
+	MSM_RPM_8960_ID_PM8921_L28_0					= 187,
+	MSM_RPM_8960_ID_PM8921_L28_1					= 188,
+	MSM_RPM_8960_ID_PM8921_L29_0					= 189,
+	MSM_RPM_8960_ID_PM8921_L29_1					= 190,
+	MSM_RPM_8960_ID_PM8921_CLK1_0					= 191,
+	MSM_RPM_8960_ID_PM8921_CLK1_1					= 192,
+	MSM_RPM_8960_ID_PM8921_CLK2_0					= 193,
+	MSM_RPM_8960_ID_PM8921_CLK2_1					= 194,
+	MSM_RPM_8960_ID_PM8921_LVS1					= 195,
+	MSM_RPM_8960_ID_PM8921_LVS2					= 196,
+	MSM_RPM_8960_ID_PM8921_LVS3					= 197,
+	MSM_RPM_8960_ID_PM8921_LVS4					= 198,
+	MSM_RPM_8960_ID_PM8921_LVS5					= 199,
+	MSM_RPM_8960_ID_PM8921_LVS6					= 200,
+	MSM_RPM_8960_ID_PM8921_LVS7					= 201,
+	MSM_RPM_8960_ID_NCP_0						= 202,
+	MSM_RPM_8960_ID_NCP_1						= 203,
+	MSM_RPM_8960_ID_CXO_BUFFERS					= 204,
+	MSM_RPM_8960_ID_USB_OTG_SWITCH					= 205,
+	MSM_RPM_8960_ID_HDMI_SWITCH					= 206,
+	MSM_RPM_8960_ID_DDR_DMM_0					= 207,
+	MSM_RPM_8960_ID_DDR_DMM_1					= 208,
+	MSM_RPM_8960_ID_QDSS_CLK					= 209,
+
+	MSM_RPM_8960_ID_LAST = MSM_RPM_8960_ID_QDSS_CLK,
+};
+
+/* RPM status ID enum */
+enum {
+	MSM_RPM_8960_STATUS_ID_VERSION_MAJOR				= 0,
+	MSM_RPM_8960_STATUS_ID_VERSION_MINOR				= 1,
+	MSM_RPM_8960_STATUS_ID_VERSION_BUILD				= 2,
+	MSM_RPM_8960_STATUS_ID_SUPPORTED_RESOURCES_0			= 3,
+	MSM_RPM_8960_STATUS_ID_SUPPORTED_RESOURCES_1			= 4,
+	MSM_RPM_8960_STATUS_ID_SUPPORTED_RESOURCES_2			= 5,
+	MSM_RPM_8960_STATUS_ID_RESERVED_SUPPORTED_RESOURCES_0		= 6,
+	MSM_RPM_8960_STATUS_ID_SEQUENCE					= 7,
+	MSM_RPM_8960_STATUS_ID_RPM_CTL					= 8,
+	MSM_RPM_8960_STATUS_ID_CXO_CLK					= 9,
+	MSM_RPM_8960_STATUS_ID_PXO_CLK					= 10,
+	MSM_RPM_8960_STATUS_ID_APPS_FABRIC_CLK				= 11,
+	MSM_RPM_8960_STATUS_ID_SYSTEM_FABRIC_CLK			= 12,
+	MSM_RPM_8960_STATUS_ID_MM_FABRIC_CLK				= 13,
+	MSM_RPM_8960_STATUS_ID_DAYTONA_FABRIC_CLK			= 14,
+	MSM_RPM_8960_STATUS_ID_SFPB_CLK					= 15,
+	MSM_RPM_8960_STATUS_ID_CFPB_CLK					= 16,
+	MSM_RPM_8960_STATUS_ID_MMFPB_CLK				= 17,
+	MSM_RPM_8960_STATUS_ID_EBI1_CLK					= 18,
+	MSM_RPM_8960_STATUS_ID_APPS_FABRIC_CFG_HALT			= 19,
+	MSM_RPM_8960_STATUS_ID_APPS_FABRIC_CFG_CLKMOD			= 20,
+	MSM_RPM_8960_STATUS_ID_APPS_FABRIC_CFG_IOCTL			= 21,
+	MSM_RPM_8960_STATUS_ID_APPS_FABRIC_ARB				= 22,
+	MSM_RPM_8960_STATUS_ID_SYS_FABRIC_CFG_HALT			= 23,
+	MSM_RPM_8960_STATUS_ID_SYS_FABRIC_CFG_CLKMOD			= 24,
+	MSM_RPM_8960_STATUS_ID_SYS_FABRIC_CFG_IOCTL			= 25,
+	MSM_RPM_8960_STATUS_ID_SYSTEM_FABRIC_ARB			= 26,
+	MSM_RPM_8960_STATUS_ID_MMSS_FABRIC_CFG_HALT			= 27,
+	MSM_RPM_8960_STATUS_ID_MMSS_FABRIC_CFG_CLKMOD			= 28,
+	MSM_RPM_8960_STATUS_ID_MMSS_FABRIC_CFG_IOCTL			= 29,
+	MSM_RPM_8960_STATUS_ID_MM_FABRIC_ARB				= 30,
+	MSM_RPM_8960_STATUS_ID_PM8921_S1_0				= 31,
+	MSM_RPM_8960_STATUS_ID_PM8921_S1_1				= 32,
+	MSM_RPM_8960_STATUS_ID_PM8921_S2_0				= 33,
+	MSM_RPM_8960_STATUS_ID_PM8921_S2_1				= 34,
+	MSM_RPM_8960_STATUS_ID_PM8921_S3_0				= 35,
+	MSM_RPM_8960_STATUS_ID_PM8921_S3_1				= 36,
+	MSM_RPM_8960_STATUS_ID_PM8921_S4_0				= 37,
+	MSM_RPM_8960_STATUS_ID_PM8921_S4_1				= 38,
+	MSM_RPM_8960_STATUS_ID_PM8921_S5_0				= 39,
+	MSM_RPM_8960_STATUS_ID_PM8921_S5_1				= 40,
+	MSM_RPM_8960_STATUS_ID_PM8921_S6_0				= 41,
+	MSM_RPM_8960_STATUS_ID_PM8921_S6_1				= 42,
+	MSM_RPM_8960_STATUS_ID_PM8921_S7_0				= 43,
+	MSM_RPM_8960_STATUS_ID_PM8921_S7_1				= 44,
+	MSM_RPM_8960_STATUS_ID_PM8921_S8_0				= 45,
+	MSM_RPM_8960_STATUS_ID_PM8921_S8_1				= 46,
+	MSM_RPM_8960_STATUS_ID_PM8921_L1_0				= 47,
+	MSM_RPM_8960_STATUS_ID_PM8921_L1_1				= 48,
+	MSM_RPM_8960_STATUS_ID_PM8921_L2_0				= 49,
+	MSM_RPM_8960_STATUS_ID_PM8921_L2_1				= 50,
+	MSM_RPM_8960_STATUS_ID_PM8921_L3_0				= 51,
+	MSM_RPM_8960_STATUS_ID_PM8921_L3_1				= 52,
+	MSM_RPM_8960_STATUS_ID_PM8921_L4_0				= 53,
+	MSM_RPM_8960_STATUS_ID_PM8921_L4_1				= 54,
+	MSM_RPM_8960_STATUS_ID_PM8921_L5_0				= 55,
+	MSM_RPM_8960_STATUS_ID_PM8921_L5_1				= 56,
+	MSM_RPM_8960_STATUS_ID_PM8921_L6_0				= 57,
+	MSM_RPM_8960_STATUS_ID_PM8921_L6_1				= 58,
+	MSM_RPM_8960_STATUS_ID_PM8921_L7_0				= 59,
+	MSM_RPM_8960_STATUS_ID_PM8921_L7_1				= 60,
+	MSM_RPM_8960_STATUS_ID_PM8921_L8_0				= 61,
+	MSM_RPM_8960_STATUS_ID_PM8921_L8_1				= 62,
+	MSM_RPM_8960_STATUS_ID_PM8921_L9_0				= 63,
+	MSM_RPM_8960_STATUS_ID_PM8921_L9_1				= 64,
+	MSM_RPM_8960_STATUS_ID_PM8921_L10_0				= 65,
+	MSM_RPM_8960_STATUS_ID_PM8921_L10_1				= 66,
+	MSM_RPM_8960_STATUS_ID_PM8921_L11_0				= 67,
+	MSM_RPM_8960_STATUS_ID_PM8921_L11_1				= 68,
+	MSM_RPM_8960_STATUS_ID_PM8921_L12_0				= 69,
+	MSM_RPM_8960_STATUS_ID_PM8921_L12_1				= 70,
+	MSM_RPM_8960_STATUS_ID_PM8921_L13_0				= 71,
+	MSM_RPM_8960_STATUS_ID_PM8921_L13_1				= 72,
+	MSM_RPM_8960_STATUS_ID_PM8921_L14_0				= 73,
+	MSM_RPM_8960_STATUS_ID_PM8921_L14_1				= 74,
+	MSM_RPM_8960_STATUS_ID_PM8921_L15_0				= 75,
+	MSM_RPM_8960_STATUS_ID_PM8921_L15_1				= 76,
+	MSM_RPM_8960_STATUS_ID_PM8921_L16_0				= 77,
+	MSM_RPM_8960_STATUS_ID_PM8921_L16_1				= 78,
+	MSM_RPM_8960_STATUS_ID_PM8921_L17_0				= 79,
+	MSM_RPM_8960_STATUS_ID_PM8921_L17_1				= 80,
+	MSM_RPM_8960_STATUS_ID_PM8921_L18_0				= 81,
+	MSM_RPM_8960_STATUS_ID_PM8921_L18_1				= 82,
+	MSM_RPM_8960_STATUS_ID_PM8921_L19_0				= 83,
+	MSM_RPM_8960_STATUS_ID_PM8921_L19_1				= 84,
+	MSM_RPM_8960_STATUS_ID_PM8921_L20_0				= 85,
+	MSM_RPM_8960_STATUS_ID_PM8921_L20_1				= 86,
+	MSM_RPM_8960_STATUS_ID_PM8921_L21_0				= 87,
+	MSM_RPM_8960_STATUS_ID_PM8921_L21_1				= 88,
+	MSM_RPM_8960_STATUS_ID_PM8921_L22_0				= 89,
+	MSM_RPM_8960_STATUS_ID_PM8921_L22_1				= 90,
+	MSM_RPM_8960_STATUS_ID_PM8921_L23_0				= 91,
+	MSM_RPM_8960_STATUS_ID_PM8921_L23_1				= 92,
+	MSM_RPM_8960_STATUS_ID_PM8921_L24_0				= 93,
+	MSM_RPM_8960_STATUS_ID_PM8921_L24_1				= 94,
+	MSM_RPM_8960_STATUS_ID_PM8921_L25_0				= 95,
+	MSM_RPM_8960_STATUS_ID_PM8921_L25_1				= 96,
+	MSM_RPM_8960_STATUS_ID_PM8921_L26_0				= 97,
+	MSM_RPM_8960_STATUS_ID_PM8921_L26_1				= 98,
+	MSM_RPM_8960_STATUS_ID_PM8921_L27_0				= 99,
+	MSM_RPM_8960_STATUS_ID_PM8921_L27_1				= 100,
+	MSM_RPM_8960_STATUS_ID_PM8921_L28_0				= 101,
+	MSM_RPM_8960_STATUS_ID_PM8921_L28_1				= 102,
+	MSM_RPM_8960_STATUS_ID_PM8921_L29_0				= 103,
+	MSM_RPM_8960_STATUS_ID_PM8921_L29_1				= 104,
+	MSM_RPM_8960_STATUS_ID_PM8921_CLK1_0				= 105,
+	MSM_RPM_8960_STATUS_ID_PM8921_CLK1_1				= 106,
+	MSM_RPM_8960_STATUS_ID_PM8921_CLK2_0				= 107,
+	MSM_RPM_8960_STATUS_ID_PM8921_CLK2_1				= 108,
+	MSM_RPM_8960_STATUS_ID_PM8921_LVS1				= 109,
+	MSM_RPM_8960_STATUS_ID_PM8921_LVS2				= 110,
+	MSM_RPM_8960_STATUS_ID_PM8921_LVS3				= 111,
+	MSM_RPM_8960_STATUS_ID_PM8921_LVS4				= 112,
+	MSM_RPM_8960_STATUS_ID_PM8921_LVS5				= 113,
+	MSM_RPM_8960_STATUS_ID_PM8921_LVS6				= 114,
+	MSM_RPM_8960_STATUS_ID_PM8921_LVS7				= 115,
+	MSM_RPM_8960_STATUS_ID_NCP_0					= 116,
+	MSM_RPM_8960_STATUS_ID_NCP_1					= 117,
+	MSM_RPM_8960_STATUS_ID_CXO_BUFFERS				= 118,
+	MSM_RPM_8960_STATUS_ID_USB_OTG_SWITCH				= 119,
+	MSM_RPM_8960_STATUS_ID_HDMI_SWITCH				= 120,
+	MSM_RPM_8960_STATUS_ID_DDR_DMM_0				= 121,
+	MSM_RPM_8960_STATUS_ID_DDR_DMM_1				= 122,
+	MSM_RPM_8960_STATUS_ID_EBI1_CH0_RANGE				= 123,
+	MSM_RPM_8960_STATUS_ID_EBI1_CH1_RANGE				= 124,
+
+	MSM_RPM_8960_STATUS_ID_LAST = MSM_RPM_8960_STATUS_ID_EBI1_CH1_RANGE,
+};
+
+#endif /* __ARCH_ARM_MACH_MSM_RPM_8960_H */
diff --git a/arch/arm/mach-msm/include/mach/rpm-9615.h b/arch/arm/mach-msm/include/mach/rpm-9615.h
new file mode 100644
index 0000000..6ae7bae
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/rpm-9615.h
@@ -0,0 +1,238 @@
+/* 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
+ * 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 __ARCH_ARM_MACH_MSM_RPM_9615_H
+#define __ARCH_ARM_MACH_MSM_RPM_9615_H
+
+/* RPM control message RAM enums */
+enum {
+	MSM_RPM_9615_CTRL_VERSION_MAJOR,
+	MSM_RPM_9615_CTRL_VERSION_MINOR,
+	MSM_RPM_9615_CTRL_VERSION_BUILD,
+
+	MSM_RPM_9615_CTRL_REQ_CTX_0,
+	MSM_RPM_9615_CTRL_REQ_CTX_7 = MSM_RPM_9615_CTRL_REQ_CTX_0 + 7,
+	MSM_RPM_9615_CTRL_REQ_SEL_0,
+	MSM_RPM_9615_CTRL_REQ_SEL_3 = MSM_RPM_9615_CTRL_REQ_SEL_0 + 3,
+	MSM_RPM_9615_CTRL_ACK_CTX_0,
+	MSM_RPM_9615_CTRL_ACK_CTX_7 = MSM_RPM_9615_CTRL_ACK_CTX_0 + 7,
+	MSM_RPM_9615_CTRL_ACK_SEL_0,
+	MSM_RPM_9615_CTRL_ACK_SEL_7 = MSM_RPM_9615_CTRL_ACK_SEL_0 + 7,
+};
+
+enum {
+	MSM_RPM_9615_SEL_NOTIFICATION				= 0,
+	MSM_RPM_9615_SEL_INVALIDATE				= 1,
+	MSM_RPM_9615_SEL_TRIGGER_TIMED				= 2,
+	MSM_RPM_9615_SEL_RPM_CTL				= 3,
+
+	MSM_RPM_9615_SEL_CXO_CLK				= 5,
+	MSM_RPM_9615_SEL_SYSTEM_FABRIC_CLK			= 9,
+	MSM_RPM_9615_SEL_DAYTONA_FABRIC_CLK			= 11,
+	MSM_RPM_9615_SEL_SFPB_CLK				= 12,
+	MSM_RPM_9615_SEL_CFPB_CLK				= 13,
+	MSM_RPM_9615_SEL_EBI1_CLK				= 16,
+
+	MSM_RPM_9615_SEL_SYS_FABRIC_CFG_HALT			= 22,
+	MSM_RPM_9615_SEL_SYS_FABRIC_CFG_CLKMOD			= 23,
+	MSM_RPM_9615_SEL_SYS_FABRIC_CFG_IOCTL			= 24,
+	MSM_RPM_9615_SEL_SYSTEM_FABRIC_ARB			= 25,
+
+	MSM_RPM_9615_SEL_PM8018_S1				= 30,
+	MSM_RPM_9615_SEL_PM8018_S2				= 31,
+	MSM_RPM_9615_SEL_PM8018_S3				= 32,
+	MSM_RPM_9615_SEL_PM8018_S4				= 33,
+	MSM_RPM_9615_SEL_PM8018_S5				= 34,
+	MSM_RPM_9615_SEL_PM8018_L1				= 35,
+	MSM_RPM_9615_SEL_PM8018_L2				= 36,
+	MSM_RPM_9615_SEL_PM8018_L3				= 37,
+	MSM_RPM_9615_SEL_PM8018_L4				= 38,
+	MSM_RPM_9615_SEL_PM8018_L5				= 39,
+	MSM_RPM_9615_SEL_PM8018_L6				= 40,
+	MSM_RPM_9615_SEL_PM8018_L7				= 41,
+	MSM_RPM_9615_SEL_PM8018_L8				= 42,
+	MSM_RPM_9615_SEL_PM8018_L9				= 43,
+	MSM_RPM_9615_SEL_PM8018_L10				= 44,
+	MSM_RPM_9615_SEL_PM8018_L11				= 45,
+	MSM_RPM_9615_SEL_PM8018_L12				= 46,
+	MSM_RPM_9615_SEL_PM8018_L13				= 47,
+	MSM_RPM_9615_SEL_PM8018_L14				= 48,
+	MSM_RPM_9615_SEL_PM8018_LVS1				= 49,
+
+	MSM_RPM_9615_SEL_NCP					= 80,
+	MSM_RPM_9615_SEL_CXO_BUFFERS				= 81,
+	MSM_RPM_9615_SEL_USB_OTG_SWITCH				= 82,
+	MSM_RPM_9615_SEL_HDMI_SWITCH				= 83,
+
+	MSM_RPM_9615_SEL_LAST = MSM_RPM_9615_SEL_HDMI_SWITCH,
+};
+
+/* RPM resource (4 byte) word ID enum */
+enum {
+	MSM_RPM_9615_ID_NOTIFICATION_CONFIGURED_0		= 0,
+	MSM_RPM_9615_ID_NOTIFICATION_CONFIGURED_3 =
+		MSM_RPM_9615_ID_NOTIFICATION_CONFIGURED_0 + 3,
+
+	MSM_RPM_9615_ID_NOTIFICATION_REGISTERED_0		= 4,
+	MSM_RPM_9615_ID_NOTIFICATION_REGISTERED_3 =
+		MSM_RPM_9615_ID_NOTIFICATION_REGISTERED_0 + 3,
+
+	MSM_RPM_9615_ID_INVALIDATE_0				= 8,
+	MSM_RPM_9615_ID_INVALIDATE_7 =
+		MSM_RPM_9615_ID_INVALIDATE_0 + 7,
+
+	MSM_RPM_9615_ID_TRIGGER_TIMED_TO			= 16,
+	MSM_RPM_9615_ID_TRIGGER_TIMED_SCLK_COUNT		= 17,
+
+	MSM_RPM_9615_ID_RPM_CTL					= 18,
+
+	/* TRIGGER_CLEAR/SET deprecated in these 24 RESERVED bytes */
+	MSM_RPM_9615_ID_RESERVED_0				= 19,
+	MSM_RPM_9615_ID_RESERVED_5 =
+		MSM_RPM_9615_ID_RESERVED_0 + 5,
+
+	MSM_RPM_9615_ID_CXO_CLK					= 25,
+	MSM_RPM_9615_ID_SYSTEM_FABRIC_CLK			= 26,
+	MSM_RPM_9615_ID_DAYTONA_FABRIC_CLK			= 27,
+	MSM_RPM_9615_ID_SFPB_CLK				= 28,
+	MSM_RPM_9615_ID_CFPB_CLK				= 29,
+	MSM_RPM_9615_ID_EBI1_CLK				= 30,
+
+	MSM_RPM_9615_ID_SYS_FABRIC_CFG_HALT_0			= 31,
+	MSM_RPM_9615_ID_SYS_FABRIC_CFG_HALT_1			= 32,
+	MSM_RPM_9615_ID_SYS_FABRIC_CFG_CLKMOD_0			= 33,
+	MSM_RPM_9615_ID_SYS_FABRIC_CFG_CLKMOD_1			= 34,
+	MSM_RPM_9615_ID_SYS_FABRIC_CFG_CLKMOD_2			= 35,
+	MSM_RPM_9615_ID_SYS_FABRIC_CFG_IOCTL			= 36,
+	MSM_RPM_9615_ID_SYSTEM_FABRIC_ARB_0			= 37,
+	MSM_RPM_9615_ID_SYSTEM_FABRIC_ARB_26 =
+		MSM_RPM_9615_ID_SYSTEM_FABRIC_ARB_0 + 26,
+
+	MSM_RPM_9615_ID_PM8018_S1_0				= 64,
+	MSM_RPM_9615_ID_PM8018_S1_1				= 65,
+	MSM_RPM_9615_ID_PM8018_S2_0				= 66,
+	MSM_RPM_9615_ID_PM8018_S2_1				= 67,
+	MSM_RPM_9615_ID_PM8018_S3_0				= 68,
+	MSM_RPM_9615_ID_PM8018_S3_1				= 69,
+	MSM_RPM_9615_ID_PM8018_S4_0				= 70,
+	MSM_RPM_9615_ID_PM8018_S4_1				= 71,
+	MSM_RPM_9615_ID_PM8018_S5_0				= 72,
+	MSM_RPM_9615_ID_PM8018_S5_1				= 73,
+	MSM_RPM_9615_ID_PM8018_L1_0				= 74,
+	MSM_RPM_9615_ID_PM8018_L1_1				= 75,
+	MSM_RPM_9615_ID_PM8018_L2_0				= 76,
+	MSM_RPM_9615_ID_PM8018_L2_1				= 77,
+	MSM_RPM_9615_ID_PM8018_L3_0				= 78,
+	MSM_RPM_9615_ID_PM8018_L3_1				= 79,
+	MSM_RPM_9615_ID_PM8018_L4_0				= 80,
+	MSM_RPM_9615_ID_PM8018_L4_1				= 81,
+	MSM_RPM_9615_ID_PM8018_L5_0				= 82,
+	MSM_RPM_9615_ID_PM8018_L5_1				= 83,
+	MSM_RPM_9615_ID_PM8018_L6_0				= 84,
+	MSM_RPM_9615_ID_PM8018_L6_1				= 85,
+	MSM_RPM_9615_ID_PM8018_L7_0				= 86,
+	MSM_RPM_9615_ID_PM8018_L7_1				= 87,
+	MSM_RPM_9615_ID_PM8018_L8_0				= 88,
+	MSM_RPM_9615_ID_PM8018_L8_1				= 89,
+	MSM_RPM_9615_ID_PM8018_L9_0				= 90,
+	MSM_RPM_9615_ID_PM8018_L9_1				= 91,
+	MSM_RPM_9615_ID_PM8018_L10_0				= 92,
+	MSM_RPM_9615_ID_PM8018_L10_1				= 93,
+	MSM_RPM_9615_ID_PM8018_L11_0				= 94,
+	MSM_RPM_9615_ID_PM8018_L11_1				= 95,
+	MSM_RPM_9615_ID_PM8018_L12_0				= 96,
+	MSM_RPM_9615_ID_PM8018_L12_1				= 97,
+	MSM_RPM_9615_ID_PM8018_L13_0				= 98,
+	MSM_RPM_9615_ID_PM8018_L13_1				= 99,
+	MSM_RPM_9615_ID_PM8018_L14_0				= 100,
+	MSM_RPM_9615_ID_PM8018_L14_1				= 101,
+	MSM_RPM_9615_ID_PM8018_LVS1				= 102,
+
+	MSM_RPM_9615_ID_NCP_0					= 103,
+	MSM_RPM_9615_ID_NCP_1					= 104,
+	MSM_RPM_9615_ID_CXO_BUFFERS				= 105,
+	MSM_RPM_9615_ID_USB_OTG_SWITCH				= 106,
+	MSM_RPM_9615_ID_HDMI_SWITCH				= 107,
+
+	MSM_RPM_9615_ID_LAST = MSM_RPM_9615_ID_HDMI_SWITCH,
+};
+
+/* RPM status ID enum */
+enum {
+	MSM_RPM_9615_STATUS_ID_VERSION_MAJOR			= 0,
+	MSM_RPM_9615_STATUS_ID_VERSION_MINOR			= 1,
+	MSM_RPM_9615_STATUS_ID_VERSION_BUILD			= 2,
+	MSM_RPM_9615_STATUS_ID_SUPPORTED_RESOURCES_0		= 3,
+	MSM_RPM_9615_STATUS_ID_SUPPORTED_RESOURCES_1		= 4,
+	MSM_RPM_9615_STATUS_ID_SUPPORTED_RESOURCES_2		= 5,
+	MSM_RPM_9615_STATUS_ID_RESERVED_SUPPORTED_RESOURCES_0	= 6,
+	MSM_RPM_9615_STATUS_ID_SEQUENCE				= 7,
+	MSM_RPM_9615_STATUS_ID_RPM_CTL				= 8,
+	MSM_RPM_9615_STATUS_ID_CXO_CLK				= 9,
+	MSM_RPM_9615_STATUS_ID_SYSTEM_FABRIC_CLK		= 10,
+	MSM_RPM_9615_STATUS_ID_DAYTONA_FABRIC_CLK		= 11,
+	MSM_RPM_9615_STATUS_ID_SFPB_CLK				= 12,
+	MSM_RPM_9615_STATUS_ID_CFPB_CLK				= 13,
+	MSM_RPM_9615_STATUS_ID_EBI1_CLK				= 14,
+	MSM_RPM_9615_STATUS_ID_SYS_FABRIC_CFG_HALT		= 15,
+	MSM_RPM_9615_STATUS_ID_SYS_FABRIC_CFG_CLKMOD		= 16,
+	MSM_RPM_9615_STATUS_ID_SYS_FABRIC_CFG_IOCTL		= 17,
+	MSM_RPM_9615_STATUS_ID_SYSTEM_FABRIC_ARB		= 18,
+	MSM_RPM_9615_STATUS_ID_PM8018_S1_0			= 19,
+	MSM_RPM_9615_STATUS_ID_PM8018_S1_1			= 20,
+	MSM_RPM_9615_STATUS_ID_PM8018_S2_0			= 21,
+	MSM_RPM_9615_STATUS_ID_PM8018_S2_1			= 22,
+	MSM_RPM_9615_STATUS_ID_PM8018_S3_0			= 23,
+	MSM_RPM_9615_STATUS_ID_PM8018_S3_1			= 24,
+	MSM_RPM_9615_STATUS_ID_PM8018_S4_0			= 25,
+	MSM_RPM_9615_STATUS_ID_PM8018_S4_1			= 26,
+	MSM_RPM_9615_STATUS_ID_PM8018_S5_0			= 27,
+	MSM_RPM_9615_STATUS_ID_PM8018_S5_1			= 28,
+	MSM_RPM_9615_STATUS_ID_PM8018_L1_0			= 29,
+	MSM_RPM_9615_STATUS_ID_PM8018_L1_1			= 30,
+	MSM_RPM_9615_STATUS_ID_PM8018_L2_0			= 31,
+	MSM_RPM_9615_STATUS_ID_PM8018_L2_1			= 32,
+	MSM_RPM_9615_STATUS_ID_PM8018_L3_0			= 33,
+	MSM_RPM_9615_STATUS_ID_PM8018_L3_1			= 34,
+	MSM_RPM_9615_STATUS_ID_PM8018_L4_0			= 35,
+	MSM_RPM_9615_STATUS_ID_PM8018_L4_1			= 36,
+	MSM_RPM_9615_STATUS_ID_PM8018_L5_0			= 37,
+	MSM_RPM_9615_STATUS_ID_PM8018_L5_1			= 38,
+	MSM_RPM_9615_STATUS_ID_PM8018_L6_0			= 39,
+	MSM_RPM_9615_STATUS_ID_PM8018_L6_1			= 40,
+	MSM_RPM_9615_STATUS_ID_PM8018_L7_0			= 41,
+	MSM_RPM_9615_STATUS_ID_PM8018_L7_1			= 42,
+	MSM_RPM_9615_STATUS_ID_PM8018_L8_0			= 43,
+	MSM_RPM_9615_STATUS_ID_PM8018_L8_1			= 44,
+	MSM_RPM_9615_STATUS_ID_PM8018_L9_0			= 45,
+	MSM_RPM_9615_STATUS_ID_PM8018_L9_1			= 46,
+	MSM_RPM_9615_STATUS_ID_PM8018_L10_0			= 47,
+	MSM_RPM_9615_STATUS_ID_PM8018_L10_1			= 48,
+	MSM_RPM_9615_STATUS_ID_PM8018_L11_0			= 49,
+	MSM_RPM_9615_STATUS_ID_PM8018_L11_1			= 50,
+	MSM_RPM_9615_STATUS_ID_PM8018_L12_0			= 51,
+	MSM_RPM_9615_STATUS_ID_PM8018_L12_1			= 52,
+	MSM_RPM_9615_STATUS_ID_PM8018_L13_0			= 53,
+	MSM_RPM_9615_STATUS_ID_PM8018_L13_1			= 54,
+	MSM_RPM_9615_STATUS_ID_PM8018_L14_0			= 55,
+	MSM_RPM_9615_STATUS_ID_PM8018_L14_1			= 56,
+	MSM_RPM_9615_STATUS_ID_PM8018_LVS1			= 57,
+	MSM_RPM_9615_STATUS_ID_NCP_0				= 58,
+	MSM_RPM_9615_STATUS_ID_NCP_1				= 59,
+	MSM_RPM_9615_STATUS_ID_CXO_BUFFERS			= 60,
+	MSM_RPM_9615_STATUS_ID_USB_OTG_SWITCH			= 61,
+	MSM_RPM_9615_STATUS_ID_HDMI_SWITCH			= 62,
+
+	MSM_RPM_9615_STATUS_ID_LAST = MSM_RPM_9615_STATUS_ID_HDMI_SWITCH,
+};
+
+#endif /* __ARCH_ARM_MACH_MSM_RPM_9615_H */
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator-8660.h b/arch/arm/mach-msm/include/mach/rpm-regulator-8660.h
new file mode 100644
index 0000000..85dcd89
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator-8660.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_8660_H
+#define __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_8660_H
+
+#define RPM_VREG_PIN_CTRL_PM8058_A0	0x01
+#define RPM_VREG_PIN_CTRL_PM8058_A1	0x02
+#define RPM_VREG_PIN_CTRL_PM8058_D0	0x04
+#define RPM_VREG_PIN_CTRL_PM8058_D1	0x08
+
+#define RPM_VREG_PIN_CTRL_PM8901_A0	0x01
+#define RPM_VREG_PIN_CTRL_PM8901_A1	0x02
+#define RPM_VREG_PIN_CTRL_PM8901_D0	0x04
+#define RPM_VREG_PIN_CTRL_PM8901_D1	0x08
+
+
+/**
+ * enum rpm_vreg_pin_fn_8660 - RPM regulator pin function choices
+ * %RPM_VREG_PIN_FN_8660_ENABLE:	pin control switches between disable and
+ *					enable
+ * %RPM_VREG_PIN_FN_8660_MODE:		pin control switches between LPM and HPM
+ * %RPM_VREG_PIN_FN_8660_SLEEP_B:	regulator is forced into LPM when
+ *					sleep_b signal is asserted
+ * %RPM_VREG_PIN_FN_8660_NONE:		do not use pin control for the regulator
+ *					and do not allow another master to
+ *					request pin control
+ *
+ * The pin function specified in platform data corresponds to the active state
+ * pin function value.  Pin function will be NONE until a consumer requests
+ * pin control to be enabled.
+ */
+enum rpm_vreg_pin_fn_8660 {
+	RPM_VREG_PIN_FN_8660_ENABLE = 0,
+	RPM_VREG_PIN_FN_8660_MODE,
+	RPM_VREG_PIN_FN_8660_SLEEP_B,
+	RPM_VREG_PIN_FN_8660_NONE,
+};
+
+/**
+ * enum rpm_vreg_force_mode_8660 - RPM regulator force mode choices
+ * %RPM_VREG_FORCE_MODE_8660_PIN_CTRL:	allow pin control usage
+ * %RPM_VREG_FORCE_MODE_8660_NONE:	do not force any mode
+ * %RPM_VREG_FORCE_MODE_8660_LPM:	force into low power mode
+ * %RPM_VREG_FORCE_MODE_8660_HPM:	force into high power mode
+ *
+ * Force mode is used to override aggregation with other masters and to set
+ * special operating modes.
+ */
+enum rpm_vreg_force_mode_8660 {
+	RPM_VREG_FORCE_MODE_8660_PIN_CTRL = 0,
+	RPM_VREG_FORCE_MODE_8660_NONE = 0,
+	RPM_VREG_FORCE_MODE_8660_LPM,
+	RPM_VREG_FORCE_MODE_8660_HPM,
+};
+
+enum rpm_vreg_id_8660 {
+	RPM_VREG_ID_PM8058_L0,
+	RPM_VREG_ID_PM8058_L1,
+	RPM_VREG_ID_PM8058_L2,
+	RPM_VREG_ID_PM8058_L3,
+	RPM_VREG_ID_PM8058_L4,
+	RPM_VREG_ID_PM8058_L5,
+	RPM_VREG_ID_PM8058_L6,
+	RPM_VREG_ID_PM8058_L7,
+	RPM_VREG_ID_PM8058_L8,
+	RPM_VREG_ID_PM8058_L9,
+	RPM_VREG_ID_PM8058_L10,
+	RPM_VREG_ID_PM8058_L11,
+	RPM_VREG_ID_PM8058_L12,
+	RPM_VREG_ID_PM8058_L13,
+	RPM_VREG_ID_PM8058_L14,
+	RPM_VREG_ID_PM8058_L15,
+	RPM_VREG_ID_PM8058_L16,
+	RPM_VREG_ID_PM8058_L17,
+	RPM_VREG_ID_PM8058_L18,
+	RPM_VREG_ID_PM8058_L19,
+	RPM_VREG_ID_PM8058_L20,
+	RPM_VREG_ID_PM8058_L21,
+	RPM_VREG_ID_PM8058_L22,
+	RPM_VREG_ID_PM8058_L23,
+	RPM_VREG_ID_PM8058_L24,
+	RPM_VREG_ID_PM8058_L25,
+	RPM_VREG_ID_PM8058_S0,
+	RPM_VREG_ID_PM8058_S1,
+	RPM_VREG_ID_PM8058_S2,
+	RPM_VREG_ID_PM8058_S3,
+	RPM_VREG_ID_PM8058_S4,
+	RPM_VREG_ID_PM8058_LVS0,
+	RPM_VREG_ID_PM8058_LVS1,
+	RPM_VREG_ID_PM8058_NCP,
+	RPM_VREG_ID_PM8901_L0,
+	RPM_VREG_ID_PM8901_L1,
+	RPM_VREG_ID_PM8901_L2,
+	RPM_VREG_ID_PM8901_L3,
+	RPM_VREG_ID_PM8901_L4,
+	RPM_VREG_ID_PM8901_L5,
+	RPM_VREG_ID_PM8901_L6,
+	RPM_VREG_ID_PM8901_S0,
+	RPM_VREG_ID_PM8901_S1,
+	RPM_VREG_ID_PM8901_S2,
+	RPM_VREG_ID_PM8901_S3,
+	RPM_VREG_ID_PM8901_S4,
+	RPM_VREG_ID_PM8901_LVS0,
+	RPM_VREG_ID_PM8901_LVS1,
+	RPM_VREG_ID_PM8901_LVS2,
+	RPM_VREG_ID_PM8901_LVS3,
+	RPM_VREG_ID_PM8901_MVS0,
+	RPM_VREG_ID_8660_MAX_REAL = RPM_VREG_ID_PM8901_MVS0,
+
+	/* The following are IDs for regulator devices to enable pin control. */
+	RPM_VREG_ID_PM8058_L0_PC,
+	RPM_VREG_ID_PM8058_L1_PC,
+	RPM_VREG_ID_PM8058_L2_PC,
+	RPM_VREG_ID_PM8058_L3_PC,
+	RPM_VREG_ID_PM8058_L4_PC,
+	RPM_VREG_ID_PM8058_L5_PC,
+	RPM_VREG_ID_PM8058_L6_PC,
+	RPM_VREG_ID_PM8058_L7_PC,
+	RPM_VREG_ID_PM8058_L8_PC,
+	RPM_VREG_ID_PM8058_L9_PC,
+	RPM_VREG_ID_PM8058_L10_PC,
+	RPM_VREG_ID_PM8058_L11_PC,
+	RPM_VREG_ID_PM8058_L12_PC,
+	RPM_VREG_ID_PM8058_L13_PC,
+	RPM_VREG_ID_PM8058_L14_PC,
+	RPM_VREG_ID_PM8058_L15_PC,
+	RPM_VREG_ID_PM8058_L16_PC,
+	RPM_VREG_ID_PM8058_L17_PC,
+	RPM_VREG_ID_PM8058_L18_PC,
+	RPM_VREG_ID_PM8058_L19_PC,
+	RPM_VREG_ID_PM8058_L20_PC,
+	RPM_VREG_ID_PM8058_L21_PC,
+	RPM_VREG_ID_PM8058_L22_PC,
+	RPM_VREG_ID_PM8058_L23_PC,
+	RPM_VREG_ID_PM8058_L24_PC,
+	RPM_VREG_ID_PM8058_L25_PC,
+	RPM_VREG_ID_PM8058_S0_PC,
+	RPM_VREG_ID_PM8058_S1_PC,
+	RPM_VREG_ID_PM8058_S2_PC,
+	RPM_VREG_ID_PM8058_S3_PC,
+	RPM_VREG_ID_PM8058_S4_PC,
+	RPM_VREG_ID_PM8058_LVS0_PC,
+	RPM_VREG_ID_PM8058_LVS1_PC,
+
+	RPM_VREG_ID_PM8901_L0_PC,
+	RPM_VREG_ID_PM8901_L1_PC,
+	RPM_VREG_ID_PM8901_L2_PC,
+	RPM_VREG_ID_PM8901_L3_PC,
+	RPM_VREG_ID_PM8901_L4_PC,
+	RPM_VREG_ID_PM8901_L5_PC,
+	RPM_VREG_ID_PM8901_L6_PC,
+	RPM_VREG_ID_PM8901_S0_PC,
+	RPM_VREG_ID_PM8901_S1_PC,
+	RPM_VREG_ID_PM8901_S2_PC,
+	RPM_VREG_ID_PM8901_S3_PC,
+	RPM_VREG_ID_PM8901_S4_PC,
+	RPM_VREG_ID_PM8901_LVS0_PC,
+	RPM_VREG_ID_PM8901_LVS1_PC,
+	RPM_VREG_ID_PM8901_LVS2_PC,
+	RPM_VREG_ID_PM8901_LVS3_PC,
+	RPM_VREG_ID_PM8901_MVS0_PC,
+	RPM_VREG_ID_8660_MAX = RPM_VREG_ID_PM8901_MVS0_PC,
+};
+
+/* Minimum high power mode loads in uA. */
+#define RPM_VREG_8660_LDO_50_HPM_MIN_LOAD	5000
+#define RPM_VREG_8660_LDO_150_HPM_MIN_LOAD	10000
+#define RPM_VREG_8660_LDO_300_HPM_MIN_LOAD	10000
+#define RPM_VREG_8660_SMPS_HPM_MIN_LOAD		50000
+#define RPM_VREG_8660_FTSMPS_HPM_MIN_LOAD	100000
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator-8930.h b/arch/arm/mach-msm/include/mach/rpm-regulator-8930.h
new file mode 100644
index 0000000..684f9d3
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator-8930.h
@@ -0,0 +1,165 @@
+/*
+ * 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 __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_8930_H
+#define __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_8930_H
+
+/* Pin control input signals. */
+#define RPM_VREG_PIN_CTRL_PM8038_D1	0x01
+#define RPM_VREG_PIN_CTRL_PM8038_A0	0x02
+#define RPM_VREG_PIN_CTRL_PM8038_A1	0x04
+#define RPM_VREG_PIN_CTRL_PM8038_A2	0x08
+
+/**
+ * enum rpm_vreg_pin_fn_8930 - RPM regulator pin function choices
+ * %RPM_VREG_PIN_FN_8930_DONT_CARE:	do not care about pin control state of
+ *					the regulator; allow another master
+ *					processor to specify pin control
+ * %RPM_VREG_PIN_FN_8930_ENABLE:	pin control switches between disable and
+ *					enable
+ * %RPM_VREG_PIN_FN_8930_MODE:		pin control switches between LPM and HPM
+ * %RPM_VREG_PIN_FN_8930_SLEEP_B:	regulator is forced into LPM when
+ *					sleep_b signal is asserted
+ * %RPM_VREG_PIN_FN_8930_NONE:		do not use pin control for the regulator
+ *					and do not allow another master to
+ *					request pin control
+ *
+ * The pin function specified in platform data corresponds to the active state
+ * pin function value.  Pin function will be NONE until a consumer requests
+ * pin control to be enabled.
+ */
+enum rpm_vreg_pin_fn_8930 {
+	RPM_VREG_PIN_FN_8930_DONT_CARE,
+	RPM_VREG_PIN_FN_8930_ENABLE,
+	RPM_VREG_PIN_FN_8930_MODE,
+	RPM_VREG_PIN_FN_8930_SLEEP_B,
+	RPM_VREG_PIN_FN_8930_NONE,
+};
+
+/**
+ * enum rpm_vreg_force_mode_8930 - RPM regulator force mode choices
+ * %RPM_VREG_FORCE_MODE_8930_PIN_CTRL:	allow pin control usage
+ * %RPM_VREG_FORCE_MODE_8930_NONE:	do not force any mode
+ * %RPM_VREG_FORCE_MODE_8930_LPM:	force into low power mode
+ * %RPM_VREG_FORCE_MODE_8930_AUTO:	allow regulator to automatically select
+ *					its own mode based on realtime current
+ *					draw (only available for SMPS
+ *					regulators)
+ * %RPM_VREG_FORCE_MODE_8930_HPM:	force into high power mode
+ * %RPM_VREG_FORCE_MODE_8930_BYPASS:	set regulator to use bypass mode, i.e.
+ *					to act as a switch and not regulate
+ *					(only available for LDO regulators)
+ *
+ * Force mode is used to override aggregation with other masters and to set
+ * special operating modes.
+ */
+enum rpm_vreg_force_mode_8930 {
+	RPM_VREG_FORCE_MODE_8930_PIN_CTRL = 0,
+	RPM_VREG_FORCE_MODE_8930_NONE = 0,
+	RPM_VREG_FORCE_MODE_8930_LPM,
+	RPM_VREG_FORCE_MODE_8930_AUTO,		/* SMPS only */
+	RPM_VREG_FORCE_MODE_8930_HPM,
+	RPM_VREG_FORCE_MODE_8930_BYPASS,	/* LDO only */
+};
+
+/**
+ * enum rpm_vreg_power_mode_8930 - power mode for SMPS regulators
+ * %RPM_VREG_POWER_MODE_8930_HYSTERETIC: Use hysteretic mode for HPM and when
+ *					 usage goes high in AUTO
+ * %RPM_VREG_POWER_MODE_8930_PWM:	 Use PWM mode for HPM and when usage
+ *					 goes high in AUTO
+ */
+enum rpm_vreg_power_mode_8930 {
+	RPM_VREG_POWER_MODE_8930_HYSTERETIC,
+	RPM_VREG_POWER_MODE_8930_PWM,
+};
+
+/**
+ * enum rpm_vreg_id - RPM regulator ID numbers (both real and pin control)
+ */
+enum rpm_vreg_id_8930 {
+	RPM_VREG_ID_PM8038_L1,
+	RPM_VREG_ID_PM8038_L2,
+	RPM_VREG_ID_PM8038_L3,
+	RPM_VREG_ID_PM8038_L4,
+	RPM_VREG_ID_PM8038_L5,
+	RPM_VREG_ID_PM8038_L6,
+	RPM_VREG_ID_PM8038_L7,
+	RPM_VREG_ID_PM8038_L8,
+	RPM_VREG_ID_PM8038_L9,
+	RPM_VREG_ID_PM8038_L10,
+	RPM_VREG_ID_PM8038_L11,
+	RPM_VREG_ID_PM8038_L12,
+	RPM_VREG_ID_PM8038_L14,
+	RPM_VREG_ID_PM8038_L15,
+	RPM_VREG_ID_PM8038_L16,
+	RPM_VREG_ID_PM8038_L17,
+	RPM_VREG_ID_PM8038_L18,
+	RPM_VREG_ID_PM8038_L19,
+	RPM_VREG_ID_PM8038_L20,
+	RPM_VREG_ID_PM8038_L21,
+	RPM_VREG_ID_PM8038_L22,
+	RPM_VREG_ID_PM8038_L23,
+	RPM_VREG_ID_PM8038_L24,
+	RPM_VREG_ID_PM8038_L26,
+	RPM_VREG_ID_PM8038_L27,
+	RPM_VREG_ID_PM8038_S1,
+	RPM_VREG_ID_PM8038_S2,
+	RPM_VREG_ID_PM8038_S3,
+	RPM_VREG_ID_PM8038_S4,
+	RPM_VREG_ID_PM8038_S5,
+	RPM_VREG_ID_PM8038_S6,
+	RPM_VREG_ID_PM8038_LVS1,
+	RPM_VREG_ID_PM8038_LVS2,
+	RPM_VREG_ID_PM8038_VDD_DIG_CORNER,
+	RPM_VREG_ID_PM8038_MAX_REAL = RPM_VREG_ID_PM8038_VDD_DIG_CORNER,
+
+	/* The following are IDs for regulator devices to enable pin control. */
+	RPM_VREG_ID_PM8038_L2_PC,
+	RPM_VREG_ID_PM8038_L3_PC,
+	RPM_VREG_ID_PM8038_L4_PC,
+	RPM_VREG_ID_PM8038_L5_PC,
+	RPM_VREG_ID_PM8038_L6_PC,
+	RPM_VREG_ID_PM8038_L7_PC,
+	RPM_VREG_ID_PM8038_L8_PC,
+	RPM_VREG_ID_PM8038_L9_PC,
+	RPM_VREG_ID_PM8038_L10_PC,
+	RPM_VREG_ID_PM8038_L11_PC,
+	RPM_VREG_ID_PM8038_L12_PC,
+	RPM_VREG_ID_PM8038_L14_PC,
+	RPM_VREG_ID_PM8038_L15_PC,
+	RPM_VREG_ID_PM8038_L17_PC,
+	RPM_VREG_ID_PM8038_L18_PC,
+	RPM_VREG_ID_PM8038_L21_PC,
+	RPM_VREG_ID_PM8038_L22_PC,
+	RPM_VREG_ID_PM8038_L23_PC,
+	RPM_VREG_ID_PM8038_L26_PC,
+	RPM_VREG_ID_PM8038_S1_PC,
+	RPM_VREG_ID_PM8038_S2_PC,
+	RPM_VREG_ID_PM8038_S3_PC,
+	RPM_VREG_ID_PM8038_S4_PC,
+	RPM_VREG_ID_PM8038_LVS1_PC,
+	RPM_VREG_ID_PM8038_LVS2_PC,
+	RPM_VREG_ID_PM8038_MAX = RPM_VREG_ID_PM8038_LVS2_PC,
+};
+
+/* Minimum high power mode loads in uA. */
+#define RPM_VREG_8930_LDO_50_HPM_MIN_LOAD		5000
+#define RPM_VREG_8930_LDO_150_HPM_MIN_LOAD		10000
+#define RPM_VREG_8930_LDO_300_HPM_MIN_LOAD		10000
+#define RPM_VREG_8930_LDO_600_HPM_MIN_LOAD		10000
+#define RPM_VREG_8930_LDO_1200_HPM_MIN_LOAD		10000
+#define RPM_VREG_8930_SMPS_1500_HPM_MIN_LOAD		100000
+#define RPM_VREG_8930_SMPS_2000_HPM_MIN_LOAD		100000
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator-8960.h b/arch/arm/mach-msm/include/mach/rpm-regulator-8960.h
new file mode 100644
index 0000000..6de47bd
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator-8960.h
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_8960_H
+#define __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_8960_H
+
+/* Pin control input signals. */
+#define RPM_VREG_PIN_CTRL_PM8921_D1	0x01
+#define RPM_VREG_PIN_CTRL_PM8921_A0	0x02
+#define RPM_VREG_PIN_CTRL_PM8921_A1	0x04
+#define RPM_VREG_PIN_CTRL_PM8921_A2	0x08
+
+/**
+ * enum rpm_vreg_pin_fn_8960 - RPM regulator pin function choices
+ * %RPM_VREG_PIN_FN_8960_DONT_CARE:	do not care about pin control state of
+ *					the regulator; allow another master
+ *					processor to specify pin control
+ * %RPM_VREG_PIN_FN_8960_ENABLE:	pin control switches between disable and
+ *					enable
+ * %RPM_VREG_PIN_FN_8960_MODE:		pin control switches between LPM and HPM
+ * %RPM_VREG_PIN_FN_8960_SLEEP_B:	regulator is forced into LPM when
+ *					sleep_b signal is asserted
+ * %RPM_VREG_PIN_FN_8960_NONE:		do not use pin control for the regulator
+ *					and do not allow another master to
+ *					request pin control
+ *
+ * The pin function specified in platform data corresponds to the active state
+ * pin function value.  Pin function will be NONE until a consumer requests
+ * pin control to be enabled.
+ */
+enum rpm_vreg_pin_fn_8960 {
+	RPM_VREG_PIN_FN_8960_DONT_CARE,
+	RPM_VREG_PIN_FN_8960_ENABLE,
+	RPM_VREG_PIN_FN_8960_MODE,
+	RPM_VREG_PIN_FN_8960_SLEEP_B,
+	RPM_VREG_PIN_FN_8960_NONE,
+};
+
+/**
+ * enum rpm_vreg_force_mode_8960 - RPM regulator force mode choices
+ * %RPM_VREG_FORCE_MODE_8960_PIN_CTRL:	allow pin control usage
+ * %RPM_VREG_FORCE_MODE_8960_NONE:	do not force any mode
+ * %RPM_VREG_FORCE_MODE_8960_LPM:	force into low power mode
+ * %RPM_VREG_FORCE_MODE_8960_AUTO:	allow regulator to automatically select
+ *					its own mode based on realtime current
+ *					draw (only available for SMPS
+ *					regulators)
+ * %RPM_VREG_FORCE_MODE_8960_HPM:	force into high power mode
+ * %RPM_VREG_FORCE_MODE_8960_BYPASS:	set regulator to use bypass mode, i.e.
+ *					to act as a switch and not regulate
+ *					(only available for LDO regulators)
+ *
+ * Force mode is used to override aggregation with other masters and to set
+ * special operating modes.
+ */
+enum rpm_vreg_force_mode_8960 {
+	RPM_VREG_FORCE_MODE_8960_PIN_CTRL = 0,
+	RPM_VREG_FORCE_MODE_8960_NONE = 0,
+	RPM_VREG_FORCE_MODE_8960_LPM,
+	RPM_VREG_FORCE_MODE_8960_AUTO,		/* SMPS only */
+	RPM_VREG_FORCE_MODE_8960_HPM,
+	RPM_VREG_FORCE_MODE_8960_BYPASS,	/* LDO only */
+};
+
+/**
+ * enum rpm_vreg_power_mode_8960 - power mode for SMPS regulators
+ * %RPM_VREG_POWER_MODE_8960_HYSTERETIC: Use hysteretic mode for HPM and when
+ *					 usage goes high in AUTO
+ * %RPM_VREG_POWER_MODE_8960_PWM:	 Use PWM mode for HPM and when usage
+ *					 goes high in AUTO
+ */
+enum rpm_vreg_power_mode_8960 {
+	RPM_VREG_POWER_MODE_8960_HYSTERETIC,
+	RPM_VREG_POWER_MODE_8960_PWM,
+};
+
+/**
+ * enum rpm_vreg_id - RPM regulator ID numbers (both real and pin control)
+ */
+enum rpm_vreg_id_8960 {
+	RPM_VREG_ID_PM8921_L1,
+	RPM_VREG_ID_PM8921_L2,
+	RPM_VREG_ID_PM8921_L3,
+	RPM_VREG_ID_PM8921_L4,
+	RPM_VREG_ID_PM8921_L5,
+	RPM_VREG_ID_PM8921_L6,
+	RPM_VREG_ID_PM8921_L7,
+	RPM_VREG_ID_PM8921_L8,
+	RPM_VREG_ID_PM8921_L9,
+	RPM_VREG_ID_PM8921_L10,
+	RPM_VREG_ID_PM8921_L11,
+	RPM_VREG_ID_PM8921_L12,
+	RPM_VREG_ID_PM8921_L14,
+	RPM_VREG_ID_PM8921_L15,
+	RPM_VREG_ID_PM8921_L16,
+	RPM_VREG_ID_PM8921_L17,
+	RPM_VREG_ID_PM8921_L18,
+	RPM_VREG_ID_PM8921_L21,
+	RPM_VREG_ID_PM8921_L22,
+	RPM_VREG_ID_PM8921_L23,
+	RPM_VREG_ID_PM8921_L24,
+	RPM_VREG_ID_PM8921_L25,
+	RPM_VREG_ID_PM8921_L26,
+	RPM_VREG_ID_PM8921_L27,
+	RPM_VREG_ID_PM8921_L28,
+	RPM_VREG_ID_PM8921_L29,
+	RPM_VREG_ID_PM8921_S1,
+	RPM_VREG_ID_PM8921_S2,
+	RPM_VREG_ID_PM8921_S3,
+	RPM_VREG_ID_PM8921_S4,
+	RPM_VREG_ID_PM8921_S5,
+	RPM_VREG_ID_PM8921_S6,
+	RPM_VREG_ID_PM8921_S7,
+	RPM_VREG_ID_PM8921_S8,
+	RPM_VREG_ID_PM8921_LVS1,
+	RPM_VREG_ID_PM8921_LVS2,
+	RPM_VREG_ID_PM8921_LVS3,
+	RPM_VREG_ID_PM8921_LVS4,
+	RPM_VREG_ID_PM8921_LVS5,
+	RPM_VREG_ID_PM8921_LVS6,
+	RPM_VREG_ID_PM8921_LVS7,
+	RPM_VREG_ID_PM8921_USB_OTG,
+	RPM_VREG_ID_PM8921_HDMI_MVS,
+	RPM_VREG_ID_PM8921_NCP,
+	RPM_VREG_ID_PM8921_MAX_REAL = RPM_VREG_ID_PM8921_NCP,
+
+	/* The following are IDs for regulator devices to enable pin control. */
+	RPM_VREG_ID_PM8921_L1_PC,
+	RPM_VREG_ID_PM8921_L2_PC,
+	RPM_VREG_ID_PM8921_L3_PC,
+	RPM_VREG_ID_PM8921_L4_PC,
+	RPM_VREG_ID_PM8921_L5_PC,
+	RPM_VREG_ID_PM8921_L6_PC,
+	RPM_VREG_ID_PM8921_L7_PC,
+	RPM_VREG_ID_PM8921_L8_PC,
+	RPM_VREG_ID_PM8921_L9_PC,
+	RPM_VREG_ID_PM8921_L10_PC,
+	RPM_VREG_ID_PM8921_L11_PC,
+	RPM_VREG_ID_PM8921_L12_PC,
+	RPM_VREG_ID_PM8921_L14_PC,
+	RPM_VREG_ID_PM8921_L15_PC,
+	RPM_VREG_ID_PM8921_L16_PC,
+	RPM_VREG_ID_PM8921_L17_PC,
+	RPM_VREG_ID_PM8921_L18_PC,
+	RPM_VREG_ID_PM8921_L21_PC,
+	RPM_VREG_ID_PM8921_L22_PC,
+	RPM_VREG_ID_PM8921_L23_PC,
+
+	RPM_VREG_ID_PM8921_L29_PC,
+	RPM_VREG_ID_PM8921_S1_PC,
+	RPM_VREG_ID_PM8921_S2_PC,
+	RPM_VREG_ID_PM8921_S3_PC,
+	RPM_VREG_ID_PM8921_S4_PC,
+
+	RPM_VREG_ID_PM8921_S7_PC,
+	RPM_VREG_ID_PM8921_S8_PC,
+	RPM_VREG_ID_PM8921_LVS1_PC,
+
+	RPM_VREG_ID_PM8921_LVS3_PC,
+	RPM_VREG_ID_PM8921_LVS4_PC,
+	RPM_VREG_ID_PM8921_LVS5_PC,
+	RPM_VREG_ID_PM8921_LVS6_PC,
+	RPM_VREG_ID_PM8921_LVS7_PC,
+
+	RPM_VREG_ID_PM8921_MAX = RPM_VREG_ID_PM8921_LVS7_PC,
+};
+
+/* Minimum high power mode loads in uA. */
+#define RPM_VREG_8960_LDO_50_HPM_MIN_LOAD		5000
+#define RPM_VREG_8960_LDO_150_HPM_MIN_LOAD		10000
+#define RPM_VREG_8960_LDO_300_HPM_MIN_LOAD		10000
+#define RPM_VREG_8960_LDO_600_HPM_MIN_LOAD		10000
+#define RPM_VREG_8960_LDO_1200_HPM_MIN_LOAD		10000
+#define RPM_VREG_8960_SMPS_1500_HPM_MIN_LOAD		100000
+#define RPM_VREG_8960_SMPS_2000_HPM_MIN_LOAD		100000
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator-9615.h b/arch/arm/mach-msm/include/mach/rpm-regulator-9615.h
new file mode 100644
index 0000000..f5fa8ca
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator-9615.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_9615_H
+#define __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_9615_H
+
+/* Pin control input signals. */
+#define RPM_VREG_PIN_CTRL_PM8018_D1	0x01
+#define RPM_VREG_PIN_CTRL_PM8018_A0	0x02
+#define RPM_VREG_PIN_CTRL_PM8018_A1	0x04
+#define RPM_VREG_PIN_CTRL_PM8018_A2	0x08
+
+/**
+ * enum rpm_vreg_pin_fn_9615 - RPM regulator pin function choices
+ * %RPM_VREG_PIN_FN_9615_DONT_CARE:	do not care about pin control state of
+ *					the regulator; allow another master
+ *					processor to specify pin control
+ * %RPM_VREG_PIN_FN_9615_ENABLE:	pin control switches between disable and
+ *					enable
+ * %RPM_VREG_PIN_FN_9615_MODE:		pin control switches between LPM and HPM
+ * %RPM_VREG_PIN_FN_9615_SLEEP_B:	regulator is forced into LPM when
+ *					sleep_b signal is asserted
+ * %RPM_VREG_PIN_FN_9615_NONE:		do not use pin control for the regulator
+ *					and do not allow another master to
+ *					request pin control
+ *
+ * The pin function specified in platform data corresponds to the active state
+ * pin function value.  Pin function will be NONE until a consumer requests
+ * pin control to be enabled.
+ */
+enum rpm_vreg_pin_fn_9615 {
+	RPM_VREG_PIN_FN_9615_DONT_CARE,
+	RPM_VREG_PIN_FN_9615_ENABLE,
+	RPM_VREG_PIN_FN_9615_MODE,
+	RPM_VREG_PIN_FN_9615_SLEEP_B,
+	RPM_VREG_PIN_FN_9615_NONE,
+};
+
+/**
+ * enum rpm_vreg_force_mode_9615 - RPM regulator force mode choices
+ * %RPM_VREG_FORCE_MODE_9615_PIN_CTRL:	allow pin control usage
+ * %RPM_VREG_FORCE_MODE_9615_NONE:	do not force any mode
+ * %RPM_VREG_FORCE_MODE_9615_LPM:	force into low power mode
+ * %RPM_VREG_FORCE_MODE_9615_AUTO:	allow regulator to automatically select
+ *					its own mode based on realtime current
+ *					draw (only available for SMPS
+ *					regulators)
+ * %RPM_VREG_FORCE_MODE_9615_HPM:	force into high power mode
+ * %RPM_VREG_FORCE_MODE_9615_BYPASS:	set regulator to use bypass mode, i.e.
+ *					to act as a switch and not regulate
+ *					(only available for LDO regulators)
+ *
+ * Force mode is used to override aggregation with other masters and to set
+ * special operating modes.
+ */
+enum rpm_vreg_force_mode_9615 {
+	RPM_VREG_FORCE_MODE_9615_PIN_CTRL = 0,
+	RPM_VREG_FORCE_MODE_9615_NONE = 0,
+	RPM_VREG_FORCE_MODE_9615_LPM,
+	RPM_VREG_FORCE_MODE_9615_AUTO,		/* SMPS only */
+	RPM_VREG_FORCE_MODE_9615_HPM,
+	RPM_VREG_FORCE_MODE_9615_BYPASS,	/* LDO only */
+};
+
+/**
+ * enum rpm_vreg_power_mode_9615 - power mode for SMPS regulators
+ * %RPM_VREG_POWER_MODE_9615_HYSTERETIC: Use hysteretic mode for HPM and when
+ *					 usage goes high in AUTO
+ * %RPM_VREG_POWER_MODE_9615_PWM:	 Use PWM mode for HPM and when usage
+ *					 goes high in AUTO
+ */
+enum rpm_vreg_power_mode_9615 {
+	RPM_VREG_POWER_MODE_9615_HYSTERETIC,
+	RPM_VREG_POWER_MODE_9615_PWM,
+};
+
+/**
+ * enum rpm_vreg_id - RPM regulator ID numbers (both real and pin control)
+ */
+enum rpm_vreg_id_9615 {
+	RPM_VREG_ID_PM8018_L2,
+	RPM_VREG_ID_PM8018_L3,
+	RPM_VREG_ID_PM8018_L4,
+	RPM_VREG_ID_PM8018_L5,
+	RPM_VREG_ID_PM8018_L6,
+	RPM_VREG_ID_PM8018_L7,
+	RPM_VREG_ID_PM8018_L8,
+	RPM_VREG_ID_PM8018_L9,
+	RPM_VREG_ID_PM8018_L10,
+	RPM_VREG_ID_PM8018_L11,
+	RPM_VREG_ID_PM8018_L12,
+	RPM_VREG_ID_PM8018_L13,
+	RPM_VREG_ID_PM8018_L14,
+	RPM_VREG_ID_PM8018_S1,
+	RPM_VREG_ID_PM8018_S2,
+	RPM_VREG_ID_PM8018_S3,
+	RPM_VREG_ID_PM8018_S4,
+	RPM_VREG_ID_PM8018_S5,
+	RPM_VREG_ID_PM8018_LVS1,
+	RPM_VREG_ID_PM8018_MAX_REAL = RPM_VREG_ID_PM8018_LVS1,
+
+	/* The following are IDs for regulator devices to enable pin control. */
+	RPM_VREG_ID_PM8018_L2_PC,
+	RPM_VREG_ID_PM8018_L3_PC,
+	RPM_VREG_ID_PM8018_L4_PC,
+	RPM_VREG_ID_PM8018_L5_PC,
+	RPM_VREG_ID_PM8018_L6_PC,
+	RPM_VREG_ID_PM8018_L7_PC,
+	RPM_VREG_ID_PM8018_L8_PC,
+	RPM_VREG_ID_PM8018_L13_PC,
+	RPM_VREG_ID_PM8018_L14_PC,
+	RPM_VREG_ID_PM8018_S1_PC,
+	RPM_VREG_ID_PM8018_S2_PC,
+	RPM_VREG_ID_PM8018_S3_PC,
+	RPM_VREG_ID_PM8018_S4_PC,
+	RPM_VREG_ID_PM8018_S5_PC,
+	RPM_VREG_ID_PM8018_LVS1_PC,
+	RPM_VREG_ID_PM8018_MAX = RPM_VREG_ID_PM8018_LVS1_PC,
+};
+
+/* Minimum high power mode loads in uA. */
+#define RPM_VREG_9615_LDO_50_HPM_MIN_LOAD	5000
+#define RPM_VREG_9615_LDO_150_HPM_MIN_LOAD	10000
+#define RPM_VREG_9615_LDO_300_HPM_MIN_LOAD	10000
+#define RPM_VREG_9615_LDO_1200_HPM_MIN_LOAD	10000
+#define RPM_VREG_9615_SMPS_1500_HPM_MIN_LOAD	100000
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator-copper.h b/arch/arm/mach-msm/include/mach/rpm-regulator-copper.h
new file mode 100644
index 0000000..2006ad3
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator-copper.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_COPPER_H
+#define __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_COPPER_H
+
+/**
+ * enum rpm_vreg_id - RPM regulator ID numbers (both real and pin control)
+ */
+enum rpm_vreg_id_copper {
+	RPM_VREG_ID_PM8941_S1,
+	RPM_VREG_ID_PM8941_S2,
+	RPM_VREG_ID_PM8941_L12,
+	RPM_VREG_ID_PM8941_MAX,
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator-smd.h b/arch/arm/mach-msm/include/mach/rpm-regulator-smd.h
new file mode 100644
index 0000000..2eb59f5
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator-smd.h
@@ -0,0 +1,55 @@
+/* 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 __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_SMD_H
+#define __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_SMD_H
+
+#include <linux/device.h>
+
+struct rpm_regulator;
+
+#if defined(CONFIG_MSM_RPM_REGULATOR_SMD) || defined(CONFIG_MSM_RPM_REGULATOR)
+
+struct rpm_regulator *rpm_regulator_get(struct device *dev, const char *supply);
+
+void rpm_regulator_put(struct rpm_regulator *regulator);
+
+int rpm_regulator_enable(struct rpm_regulator *regulator);
+
+int rpm_regulator_disable(struct rpm_regulator *regulator);
+
+int rpm_regulator_set_voltage(struct rpm_regulator *regulator, int min_uV,
+			      int max_uV);
+
+int __init rpm_regulator_smd_driver_init(void);
+
+#else
+
+static inline struct rpm_regulator *rpm_regulator_get(struct device *dev,
+					const char *supply) { return NULL; }
+
+static inline void rpm_regulator_put(struct rpm_regulator *regulator) { }
+
+static inline int rpm_regulator_enable(struct rpm_regulator *regulator)
+			{ return 0; }
+
+static inline int rpm_regulator_disable(struct rpm_regulator *regulator)
+			{ return 0; }
+
+static inline int rpm_regulator_set_voltage(struct rpm_regulator *regulator,
+					int min_uV, int max_uV) { return 0; }
+
+static inline int __init rpm_regulator_smd_driver_init(void) { return 0; }
+
+#endif /* CONFIG_MSM_RPM_REGULATOR_SMD */
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator.h b/arch/arm/mach-msm/include/mach/rpm-regulator.h
new file mode 100644
index 0000000..a010257
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator.h
@@ -0,0 +1,234 @@
+/* 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
+ * 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 __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_H
+#define __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_H
+
+#include <linux/regulator/machine.h>
+
+#define RPM_REGULATOR_DEV_NAME "rpm-regulator"
+
+#include <mach/rpm-regulator-8660.h>
+#include <mach/rpm-regulator-8960.h>
+#include <mach/rpm-regulator-9615.h>
+#include <mach/rpm-regulator-copper.h>
+#include <mach/rpm-regulator-8930.h>
+
+/**
+ * enum rpm_vreg_version - supported RPM regulator versions
+ */
+enum rpm_vreg_version {
+	RPM_VREG_VERSION_8660,
+	RPM_VREG_VERSION_8960,
+	RPM_VREG_VERSION_9615,
+	RPM_VREG_VERSION_8930,
+	RPM_VREG_VERSION_MAX = RPM_VREG_VERSION_8930,
+};
+
+#define RPM_VREG_PIN_CTRL_NONE		0x00
+
+/**
+ * enum rpm_vreg_state - enable state for switch or NCP
+ */
+enum rpm_vreg_state {
+	RPM_VREG_STATE_OFF,
+	RPM_VREG_STATE_ON,
+};
+
+/**
+ * enum rpm_vreg_freq - switching frequency for SMPS or NCP
+ */
+enum rpm_vreg_freq {
+	RPM_VREG_FREQ_NONE,
+	RPM_VREG_FREQ_19p20,
+	RPM_VREG_FREQ_9p60,
+	RPM_VREG_FREQ_6p40,
+	RPM_VREG_FREQ_4p80,
+	RPM_VREG_FREQ_3p84,
+	RPM_VREG_FREQ_3p20,
+	RPM_VREG_FREQ_2p74,
+	RPM_VREG_FREQ_2p40,
+	RPM_VREG_FREQ_2p13,
+	RPM_VREG_FREQ_1p92,
+	RPM_VREG_FREQ_1p75,
+	RPM_VREG_FREQ_1p60,
+	RPM_VREG_FREQ_1p48,
+	RPM_VREG_FREQ_1p37,
+	RPM_VREG_FREQ_1p28,
+	RPM_VREG_FREQ_1p20,
+};
+
+/**
+ * enum rpm_vreg_voltage_corner - possible voltage corner values
+ *
+ * These should be used in regulator_set_voltage and rpm_vreg_set_voltage calls
+ * for corner type regulators as if they had units of uV.
+ */
+enum rpm_vreg_voltage_corner {
+	RPM_VREG_CORNER_NONE = 1,
+	RPM_VREG_CORNER_LOW,
+	RPM_VREG_CORNER_NOMINAL,
+	RPM_VREG_CORNER_HIGH,
+};
+
+/**
+ * enum rpm_vreg_voter - RPM regulator voter IDs for private APIs
+ */
+enum rpm_vreg_voter {
+	RPM_VREG_VOTER_REG_FRAMEWORK,	/* for internal use only */
+	RPM_VREG_VOTER1,		/* for use by the acpu-clock driver */
+	RPM_VREG_VOTER2,		/* for use by the acpu-clock driver */
+	RPM_VREG_VOTER3,		/* for use by other drivers */
+	RPM_VREG_VOTER4,		/* for use by the acpu-clock driver */
+	RPM_VREG_VOTER5,		/* for use by the acpu-clock driver */
+	RPM_VREG_VOTER6,		/* for use by the acpu-clock driver */
+	RPM_VREG_VOTER_COUNT,
+};
+
+/**
+ * struct rpm_regulator_init_data - RPM regulator initialization data
+ * @init_data:		regulator constraints
+ * @id:			regulator id; from enum rpm_vreg_id
+ * @sleep_selectable:	flag which indicates that regulator should be accessable
+ *			by external private API and that spinlocks should be
+ *			used instead of mutex locks
+ * @system_uA:		current drawn from regulator not accounted for by any
+ *			regulator framework consumer
+ * @enable_time:	time in us taken to enable a regulator to the maximum
+ *			allowed voltage for the system.  This is dependent upon
+ *			the load and capacitance for a regulator on the board.
+ * @pull_down_enable:	0 = no pulldown, 1 = pulldown when regulator disabled
+ * @freq:		enum value representing the switching frequency of an
+ *			SMPS or NCP
+ * @pin_ctrl:		pin control inputs to use for the regulator; should be
+ *			a combination of RPM_VREG_PIN_CTRL_* values
+ * @pin_fn:		action to perform when pin control pin(s) is/are active
+ * @force_mode:		used to specify a force mode which overrides the votes
+ *			of other RPM masters.
+ * @sleep_set_force_mode: force mode to use in sleep-set requests
+ * @power_mode:		mode to use as HPM (typically PWM or hysteretic) when
+ *			utilizing Auto mode selection
+ * @default_uV:		initial voltage to set the regulator to if enable is
+ *			called before set_voltage (e.g. when boot_on or
+ *			always_on is set).
+ * @peak_uA:		initial peak load requirement sent in RPM request; used
+ *			to determine initial mode.
+ * @avg_uA:		average load requirement sent in RPM request
+ * @state:		initial enable state sent in RPM request for switch or
+ *			NCP
+ */
+struct rpm_regulator_init_data {
+	struct regulator_init_data	init_data;
+	int				id;
+	int				sleep_selectable;
+	int				system_uA;
+	int				enable_time;
+	unsigned			pull_down_enable;
+	enum rpm_vreg_freq		freq;
+	unsigned			pin_ctrl;
+	int				pin_fn;
+	int				force_mode;
+	int				sleep_set_force_mode;
+	int				power_mode;
+	int				default_uV;
+	unsigned			peak_uA;
+	unsigned			avg_uA;
+	enum rpm_vreg_state		state;
+};
+
+/**
+ * struct rpm_regulator_consumer_mapping - mapping used by private consumers
+ */
+struct rpm_regulator_consumer_mapping {
+	const char		*dev_name;
+	const char		*supply;
+	int			vreg_id;
+	enum rpm_vreg_voter	voter;
+	int			sleep_also;
+};
+
+/**
+ * struct rpm_regulator_platform_data - RPM regulator platform data
+ */
+struct rpm_regulator_platform_data {
+	struct rpm_regulator_init_data		*init_data;
+	int					num_regulators;
+	enum rpm_vreg_version			version;
+	int					vreg_id_vdd_mem;
+	int					vreg_id_vdd_dig;
+	struct rpm_regulator_consumer_mapping	*consumer_map;
+	int					consumer_map_len;
+};
+
+#ifdef CONFIG_MSM_RPM_REGULATOR
+/**
+ * rpm_vreg_set_voltage - vote for a min_uV value of specified regualtor
+ * @vreg: ID for regulator
+ * @voter: ID for the voter
+ * @min_uV: minimum acceptable voltage (in uV) that is voted for
+ * @max_uV: maximum acceptable voltage (in uV) that is voted for
+ * @sleep_also: 0 for active set only, non-0 for active set and sleep set
+ *
+ * Returns 0 on success or errno.
+ *
+ * This function is used to vote for the voltage of a regulator without
+ * using the regulator framework.  It is needed by consumers which hold spin
+ * locks or have interrupts disabled because the regulator framework can sleep.
+ * It is also needed by consumers which wish to only vote for active set
+ * regulator voltage.
+ *
+ * If sleep_also == 0, then a sleep-set value of 0V will be voted for.
+ *
+ * This function may only be called for regulators which have the sleep flag
+ * specified in their private data.
+ *
+ * Consumers can vote to disable a regulator with this function by passing
+ * min_uV = 0 and max_uV = 0.
+ *
+ * Voltage switch type regulators may be controlled via rpm_vreg_set_voltage
+ * as well.  For this type of regulator, max_uV > 0 is treated as an enable
+ * request and max_uV == 0 is treated as a disable request.
+ */
+int rpm_vreg_set_voltage(int vreg_id, enum rpm_vreg_voter voter, int min_uV,
+			 int max_uV, int sleep_also);
+
+/**
+ * rpm_vreg_set_frequency - sets the frequency of a switching regulator
+ * @vreg: ID for regulator
+ * @freq: enum corresponding to desired frequency
+ *
+ * Returns 0 on success or errno.
+ */
+int rpm_vreg_set_frequency(int vreg_id, enum rpm_vreg_freq freq);
+
+#else
+
+/*
+ * These stubs exist to allow consumers of these APIs to compile and run
+ * in absence of a real RPM regulator driver. It is assumed that they are
+ * aware of the state of their regulators and have either set them
+ * correctly by some other means or don't care about their state at all.
+ */
+static inline int rpm_vreg_set_voltage(int vreg_id, enum rpm_vreg_voter voter,
+				       int min_uV, int max_uV, int sleep_also)
+{
+	return 0;
+}
+
+static inline int rpm_vreg_set_frequency(int vreg_id, enum rpm_vreg_freq freq)
+{
+	return 0;
+}
+
+#endif /* CONFIG_MSM_RPM_REGULATOR */
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/rpm-smd.h b/arch/arm/mach-msm/include/mach/rpm-smd.h
new file mode 100644
index 0000000..ff58fed
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/rpm-smd.h
@@ -0,0 +1,254 @@
+/* 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 __ARCH_ARM_MACH_MSM_RPM_SMD_H
+#define __ARCH_ARM_MACH_MSM_RPM_SMD_H
+
+/**
+ * enum msm_rpm_set - RPM enumerations for sleep/active set
+ * %MSM_RPM_CTX_SET_0: Set resource parameters for active mode.
+ * %MSM_RPM_CTX_SET_SLEEP: Set resource parameters for sleep.
+ */
+enum msm_rpm_set {
+	MSM_RPM_CTX_ACTIVE_SET,
+	MSM_RPM_CTX_SLEEP_SET,
+};
+
+struct msm_rpm_request;
+
+struct msm_rpm_kvp {
+	uint32_t key;
+	uint32_t length;
+	uint8_t *data;
+};
+#ifdef CONFIG_MSM_RPM_SMD
+/**
+ * msm_rpm_request() - Creates a parent element to identify the
+ * resource on the RPM, that stores the KVPs for different fields modified
+ * for a hardware resource
+ *
+ * @set: if the device is setting the active/sleep set parameter
+ * for the resource
+ * @rsc_type: unsigned 32 bit integer that identifies the type of the resource
+ * @rsc_id: unsigned 32 bit that uniquely identifies a resource within a type
+ * @num_elements: number of KVPs pairs associated with the resource
+ *
+ * returns pointer to a msm_rpm_request on success, NULL on error
+ */
+struct msm_rpm_request *msm_rpm_create_request(
+		enum msm_rpm_set set, uint32_t rsc_type,
+		uint32_t rsc_id, int num_elements);
+
+/**
+ * msm_rpm_request_noirq() - Creates a parent element to identify the
+ * resource on the RPM, that stores the KVPs for different fields modified
+ * for a hardware resource. This function is similar to msm_rpm_create_request
+ * except that it has to be called with interrupts masked.
+ *
+ * @set: if the device is setting the active/sleep set parameter
+ * for the resource
+ * @rsc_type: unsigned 32 bit integer that identifies the type of the resource
+ * @rsc_id: unsigned 32 bit that uniquely identifies a resource within a type
+ * @num_elements: number of KVPs pairs associated with the resource
+ *
+ * returns pointer to a msm_rpm_request on success, NULL on error
+ */
+struct msm_rpm_request *msm_rpm_create_request_noirq(
+		enum msm_rpm_set set, uint32_t rsc_type,
+		uint32_t rsc_id, int num_elements);
+
+/**
+ * msm_rpm_add_kvp_data() - Adds a Key value pair to a existing RPM resource.
+ *
+ * @handle: RPM resource handle to which the data should be appended
+ * @key:  unsigned integer identify the parameter modified
+ * @data: byte array that contains the value corresponding to key.
+ * @size:   size of data in bytes.
+ *
+ * returns 0 on success or errno
+ */
+int msm_rpm_add_kvp_data(struct msm_rpm_request *handle,
+		uint32_t key, const uint8_t *data, int size);
+
+/**
+ * msm_rpm_add_kvp_data_noirq() - Adds a Key value pair to a existing RPM
+ * resource. This function is similar to msm_rpm_add_kvp_data except that it
+ * has to be called with interrupts masked.
+ *
+ * @handle: RPM resource handle to which the data should be appended
+ * @key:  unsigned integer identify the parameter modified
+ * @data: byte array that contains the value corresponding to key.
+ * @size:   size of data in bytes.
+ *
+ * returns 0 on success or errno
+ */
+int msm_rpm_add_kvp_data_noirq(struct msm_rpm_request *handle,
+		uint32_t key, const uint8_t *data, int size);
+
+/** msm_rpm_free_request() - clean up the RPM request handle created with
+ * msm_rpm_create_request
+ *
+ * @handle: RPM resource handle to be cleared.
+ */
+
+void msm_rpm_free_request(struct msm_rpm_request *handle);
+
+/**
+ * msm_rpm_send_request() - Send the RPM messages using SMD. The function
+ * assigns a message id before sending the data out to the RPM. RPM hardware
+ * uses the message id to acknowledge the messages.
+ *
+ * @handle: pointer to the msm_rpm_request for the resource being modified.
+ *
+ * returns non-zero message id on success and zero on a failed transaction.
+ * The drivers use message id to wait for ACK from RPM.
+ */
+int msm_rpm_send_request(struct msm_rpm_request *handle);
+
+/**
+ * msm_rpm_send_request_noirq() - Send the RPM messages using SMD. The
+ * function assigns a message id before sending the data out to the RPM.
+ * RPM hardware uses the message id to acknowledge the messages. This function
+ * is similar to msm_rpm_send_request except that it has to be called with
+ * interrupts masked.
+ *
+ * @handle: pointer to the msm_rpm_request for the resource being modified.
+ *
+ * returns non-zero message id on success and zero on a failed transaction.
+ * The drivers use message id to wait for ACK from RPM.
+ */
+int msm_rpm_send_request_noirq(struct msm_rpm_request *handle);
+
+/**
+ * msm_rpm_wait_for_ack() - A blocking call that waits for acknowledgment of
+ * a message from RPM.
+ *
+ * @msg_id: the return from msm_rpm_send_requests
+ *
+ * returns 0 on success or errno
+ */
+int msm_rpm_wait_for_ack(uint32_t msg_id);
+
+/**
+ * msm_rpm_wait_for_ack_noirq() - A blocking call that waits for acknowledgment
+ * of a message from RPM. This function is similar to msm_rpm_wait_for_ack
+ * except that it has to be called with interrupts masked.
+ *
+ * @msg_id: the return from msm_rpm_send_request
+ *
+ * returns 0 on success or errno
+ */
+int msm_rpm_wait_for_ack_noirq(uint32_t msg_id);
+
+/**
+ * msm_rpm_send_message() -Wrapper function for clients to send data given an
+ * array of key value pairs.
+ *
+ * @set: if the device is setting the active/sleep set parameter
+ * for the resource
+ * @rsc_type: unsigned 32 bit integer that identifies the type of the resource
+ * @rsc_id: unsigned 32 bit that uniquely identifies a resource within a type
+ * @kvp: array of KVP data.
+ * @nelem: number of KVPs pairs associated with the message.
+ *
+ * returns  0 on success and errno on failure.
+ */
+int msm_rpm_send_message(enum msm_rpm_set set, uint32_t rsc_type,
+		uint32_t rsc_id, struct msm_rpm_kvp *kvp, int nelems);
+
+/**
+ * msm_rpm_send_message_noirq() -Wrapper function for clients to send data
+ * given an array of key value pairs. This function is similar to the
+ * msm_rpm_send_message() except that it has to be called with interrupts
+ * disabled. Clients should choose the irq version when possible for system
+ * performance.
+ *
+ * @set: if the device is setting the active/sleep set parameter
+ * for the resource
+ * @rsc_type: unsigned 32 bit integer that identifies the type of the resource
+ * @rsc_id: unsigned 32 bit that uniquely identifies a resource within a type
+ * @kvp: array of KVP data.
+ * @nelem: number of KVPs pairs associated with the message.
+ *
+ * returns  0 on success and errno on failure.
+ */
+int msm_rpm_send_message_noirq(enum msm_rpm_set set, uint32_t rsc_type,
+		uint32_t rsc_id, struct msm_rpm_kvp *kvp, int nelems);
+
+/**
+ * msm_rpm_driver_init() - Initialization function that registers for a
+ * rpm platform driver.
+ *
+ * returns 0 on success.
+ */
+int __init msm_rpm_driver_init(void);
+
+#else
+
+static inline struct msm_rpm_request *msm_rpm_create_request(
+		enum msm_rpm_set set, uint32_t rsc_type,
+		uint32_t rsc_id, int num_elements)
+{
+	return NULL;
+}
+
+static inline struct msm_rpm_request *msm_rpm_create_request_noirq(
+		enum msm_rpm_set set, uint32_t rsc_type,
+		uint32_t rsc_id, int num_elements)
+{
+	return NULL;
+
+}
+static inline uint32_t msm_rpm_add_kvp_data(struct msm_rpm_request *handle,
+		uint32_t key, const uint8_t *data, int count)
+{
+	return 0;
+}
+static inline uint32_t msm_rpm_add_kvp_data_noirq(
+		struct msm_rpm_request *handle, uint32_t key,
+		const uint8_t *data, int count)
+{
+	return 0;
+}
+
+static inline void msm_rpm_free_request(struct msm_rpm_request *handle)
+{
+	return ;
+}
+
+static inline int msm_rpm_send_request(struct msm_rpm_request *handle)
+{
+	return 0;
+}
+
+static inline int msm_rpm_send_request_noirq(struct msm_rpm_request *handle)
+{
+	return 0;
+
+}
+static inline int msm_rpm_wait_for_ack(uint32_t msg_id)
+{
+	return 0;
+
+}
+static inline int msm_rpm_wait_for_ack_noirq(uint32_t msg_id)
+{
+	return 0;
+}
+
+static inline int __init msm_rpm_driver_init(void)
+{
+	return 0;
+}
+#endif
+#endif /*__ARCH_ARM_MACH_MSM_RPM_SMD_H*/
diff --git a/arch/arm/mach-msm/include/mach/rpm.h b/arch/arm/mach-msm/include/mach/rpm.h
new file mode 100644
index 0000000..98621be
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/rpm.h
@@ -0,0 +1,941 @@
+/* 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
+ * 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 __ARCH_ARM_MACH_MSM_RPM_H
+#define __ARCH_ARM_MACH_MSM_RPM_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/semaphore.h>
+
+#include <mach/rpm-8660.h>
+#include <mach/rpm-9615.h>
+#include <mach/rpm-8960.h>
+#include <mach/rpm-8930.h>
+#include <mach/rpm-8064.h>
+
+#define SEL_MASK_SIZE (5)
+
+enum {
+	MSM_RPM_PAGE_STATUS,
+	MSM_RPM_PAGE_CTRL,
+	MSM_RPM_PAGE_REQ,
+	MSM_RPM_PAGE_ACK,
+	MSM_RPM_PAGE_COUNT
+};
+
+enum {
+	MSM_RPM_CTX_SET_0,
+	MSM_RPM_CTX_SET_SLEEP,
+	MSM_RPM_CTX_SET_COUNT,
+
+	MSM_RPM_CTX_NOTIFICATION = 30,
+	MSM_RPM_CTX_REJECTED = 31,
+};
+
+/* RPM control message RAM enums */
+enum {
+	MSM_RPM_CTRL_VERSION_MAJOR,
+	MSM_RPM_CTRL_VERSION_MINOR,
+	MSM_RPM_CTRL_VERSION_BUILD,
+
+	MSM_RPM_CTRL_REQ_CTX_0,
+	MSM_RPM_CTRL_REQ_SEL_0,
+	MSM_RPM_CTRL_ACK_CTX_0,
+	MSM_RPM_CTRL_ACK_SEL_0,
+
+	MSM_RPM_CTRL_LAST,
+};
+
+enum {
+	MSM_RPM_ID_NOTIFICATION_CONFIGURED_0 = 0,
+	MSM_RPM_ID_NOTIFICATION_CONFIGURED_7 =
+		MSM_RPM_ID_NOTIFICATION_CONFIGURED_0 + 7,
+
+	MSM_RPM_ID_NOTIFICATION_REGISTERED_0,
+	MSM_RPM_ID_NOTIFICATION_REGISTERED_7 =
+		MSM_RPM_ID_NOTIFICATION_REGISTERED_0 + 7,
+
+	MSM_RPM_ID_INVALIDATE_0,
+	MSM_RPM_ID_INVALIDATE_7 =
+		MSM_RPM_ID_INVALIDATE_0 + 7,
+
+	MSM_RPM_ID_TRIGGER_TIMED_TO,
+	MSM_RPM_ID_TRIGGER_TIMED_0,
+	MSM_RPM_ID_TRIGGER_TIMED_SCLK_COUNT,
+
+	MSM_RPM_ID_RPM_CTL,
+
+	/* TRIGGER_CLEAR/SET deprecated in these 24 RESERVED bytes */
+	MSM_RPM_ID_RESERVED_0,
+	MSM_RPM_ID_RESERVED_5 =
+		MSM_RPM_ID_RESERVED_0 + 5,
+
+	MSM_RPM_ID_CXO_CLK,
+	MSM_RPM_ID_PXO_CLK,
+	MSM_RPM_ID_APPS_FABRIC_CLK,
+	MSM_RPM_ID_SYSTEM_FABRIC_CLK,
+	MSM_RPM_ID_MM_FABRIC_CLK,
+	MSM_RPM_ID_DAYTONA_FABRIC_CLK,
+	MSM_RPM_ID_SFPB_CLK,
+	MSM_RPM_ID_CFPB_CLK,
+	MSM_RPM_ID_MMFPB_CLK,
+	MSM_RPM_ID_EBI1_CLK,
+
+	MSM_RPM_ID_APPS_FABRIC_CFG_HALT_0,
+	MSM_RPM_ID_APPS_FABRIC_HALT_0 =
+		MSM_RPM_ID_APPS_FABRIC_CFG_HALT_0,
+	MSM_RPM_ID_APPS_FABRIC_CFG_HALT_1,
+	MSM_RPM_ID_APPS_FABRIC_CFG_CLKMOD_0,
+	MSM_RPM_ID_APPS_FABRIC_CLOCK_MODE_0 =
+		MSM_RPM_ID_APPS_FABRIC_CFG_CLKMOD_0,
+	MSM_RPM_ID_APPS_FABRIC_CFG_CLKMOD_1,
+	MSM_RPM_ID_APPS_FABRIC_CFG_CLKMOD_2,
+	MSM_RPM_ID_APPS_FABRIC_CFG_IOCTL,
+	MSM_RPM_ID_APPS_FABRIC_ARB_0,
+	MSM_RPM_ID_APPS_FABRIC_ARB_11 =
+		MSM_RPM_ID_APPS_FABRIC_ARB_0 + 11,
+
+	MSM_RPM_ID_SYS_FABRIC_CFG_HALT_0,
+	MSM_RPM_ID_SYSTEM_FABRIC_HALT_0 =
+		MSM_RPM_ID_SYS_FABRIC_CFG_HALT_0,
+	MSM_RPM_ID_SYS_FABRIC_CFG_HALT_1,
+	MSM_RPM_ID_SYS_FABRIC_CFG_CLKMOD_0,
+	MSM_RPM_ID_SYSTEM_FABRIC_CLOCK_MODE_0 =
+		MSM_RPM_ID_SYS_FABRIC_CFG_CLKMOD_0,
+	MSM_RPM_ID_SYS_FABRIC_CFG_CLKMOD_1,
+	MSM_RPM_ID_SYS_FABRIC_CFG_CLKMOD_2,
+	MSM_RPM_ID_SYS_FABRIC_CFG_IOCTL,
+	MSM_RPM_ID_SYSTEM_FABRIC_ARB_0,
+	MSM_RPM_ID_SYSTEM_FABRIC_ARB_29 =
+		MSM_RPM_ID_SYSTEM_FABRIC_ARB_0 + 29,
+
+	MSM_RPM_ID_MMSS_FABRIC_CFG_HALT_0,
+	MSM_RPM_ID_MM_FABRIC_HALT_0 =
+		MSM_RPM_ID_MMSS_FABRIC_CFG_HALT_0,
+	MSM_RPM_ID_MMSS_FABRIC_CFG_HALT_1,
+	MSM_RPM_ID_MMSS_FABRIC_CFG_CLKMOD_0,
+	MSM_RPM_ID_MM_FABRIC_CLOCK_MODE_0 =
+		MSM_RPM_ID_MMSS_FABRIC_CFG_CLKMOD_0,
+	MSM_RPM_ID_MMSS_FABRIC_CFG_CLKMOD_1,
+	MSM_RPM_ID_MMSS_FABRIC_CFG_CLKMOD_2,
+	MSM_RPM_ID_MMSS_FABRIC_CFG_IOCTL,
+	MSM_RPM_ID_MM_FABRIC_ARB_0,
+	MSM_RPM_ID_MM_FABRIC_ARB_22 =
+		MSM_RPM_ID_MM_FABRIC_ARB_0 + 22,
+
+	MSM_RPM_ID_PM8921_S1_0,
+	MSM_RPM_ID_PM8921_S1_1,
+	MSM_RPM_ID_PM8921_S2_0,
+	MSM_RPM_ID_PM8921_S2_1,
+	MSM_RPM_ID_PM8921_S3_0,
+	MSM_RPM_ID_PM8921_S3_1,
+	MSM_RPM_ID_PM8921_S4_0,
+	MSM_RPM_ID_PM8921_S4_1,
+	MSM_RPM_ID_PM8921_S5_0,
+	MSM_RPM_ID_PM8921_S5_1,
+	MSM_RPM_ID_PM8921_S6_0,
+	MSM_RPM_ID_PM8921_S6_1,
+	MSM_RPM_ID_PM8921_S7_0,
+	MSM_RPM_ID_PM8921_S7_1,
+	MSM_RPM_ID_PM8921_S8_0,
+	MSM_RPM_ID_PM8921_S8_1,
+	MSM_RPM_ID_PM8921_L1_0,
+	MSM_RPM_ID_PM8921_L1_1,
+	MSM_RPM_ID_PM8921_L2_0,
+	MSM_RPM_ID_PM8921_L2_1,
+	MSM_RPM_ID_PM8921_L3_0,
+	MSM_RPM_ID_PM8921_L3_1,
+	MSM_RPM_ID_PM8921_L4_0,
+	MSM_RPM_ID_PM8921_L4_1,
+	MSM_RPM_ID_PM8921_L5_0,
+	MSM_RPM_ID_PM8921_L5_1,
+	MSM_RPM_ID_PM8921_L6_0,
+	MSM_RPM_ID_PM8921_L6_1,
+	MSM_RPM_ID_PM8921_L7_0,
+	MSM_RPM_ID_PM8921_L7_1,
+	MSM_RPM_ID_PM8921_L8_0,
+	MSM_RPM_ID_PM8921_L8_1,
+	MSM_RPM_ID_PM8921_L9_0,
+	MSM_RPM_ID_PM8921_L9_1,
+	MSM_RPM_ID_PM8921_L10_0,
+	MSM_RPM_ID_PM8921_L10_1,
+	MSM_RPM_ID_PM8921_L11_0,
+	MSM_RPM_ID_PM8921_L11_1,
+	MSM_RPM_ID_PM8921_L12_0,
+	MSM_RPM_ID_PM8921_L12_1,
+	MSM_RPM_ID_PM8921_L13_0,
+	MSM_RPM_ID_PM8921_L13_1,
+	MSM_RPM_ID_PM8921_L14_0,
+	MSM_RPM_ID_PM8921_L14_1,
+	MSM_RPM_ID_PM8921_L15_0,
+	MSM_RPM_ID_PM8921_L15_1,
+	MSM_RPM_ID_PM8921_L16_0,
+	MSM_RPM_ID_PM8921_L16_1,
+	MSM_RPM_ID_PM8921_L17_0,
+	MSM_RPM_ID_PM8921_L17_1,
+	MSM_RPM_ID_PM8921_L18_0,
+	MSM_RPM_ID_PM8921_L18_1,
+	MSM_RPM_ID_PM8921_L19_0,
+	MSM_RPM_ID_PM8921_L19_1,
+	MSM_RPM_ID_PM8921_L20_0,
+	MSM_RPM_ID_PM8921_L20_1,
+	MSM_RPM_ID_PM8921_L21_0,
+	MSM_RPM_ID_PM8921_L21_1,
+	MSM_RPM_ID_PM8921_L22_0,
+	MSM_RPM_ID_PM8921_L22_1,
+	MSM_RPM_ID_PM8921_L23_0,
+	MSM_RPM_ID_PM8921_L23_1,
+	MSM_RPM_ID_PM8921_L24_0,
+	MSM_RPM_ID_PM8921_L24_1,
+	MSM_RPM_ID_PM8921_L25_0,
+	MSM_RPM_ID_PM8921_L25_1,
+	MSM_RPM_ID_PM8921_L26_0,
+	MSM_RPM_ID_PM8921_L26_1,
+	MSM_RPM_ID_PM8921_L27_0,
+	MSM_RPM_ID_PM8921_L27_1,
+	MSM_RPM_ID_PM8921_L28_0,
+	MSM_RPM_ID_PM8921_L28_1,
+	MSM_RPM_ID_PM8921_L29_0,
+	MSM_RPM_ID_PM8921_L29_1,
+	MSM_RPM_ID_PM8921_CLK1_0,
+	MSM_RPM_ID_PM8921_CLK1_1,
+	MSM_RPM_ID_PM8921_CLK2_0,
+	MSM_RPM_ID_PM8921_CLK2_1,
+	MSM_RPM_ID_PM8921_LVS1,
+	MSM_RPM_ID_PM8921_LVS2,
+	MSM_RPM_ID_PM8921_LVS3,
+	MSM_RPM_ID_PM8921_LVS4,
+	MSM_RPM_ID_PM8921_LVS5,
+	MSM_RPM_ID_PM8921_LVS6,
+	MSM_RPM_ID_PM8921_LVS7,
+	MSM_RPM_ID_NCP_0,
+	MSM_RPM_ID_NCP_1,
+	MSM_RPM_ID_CXO_BUFFERS,
+	MSM_RPM_ID_USB_OTG_SWITCH,
+	MSM_RPM_ID_HDMI_SWITCH,
+	MSM_RPM_ID_DDR_DMM_0,
+	MSM_RPM_ID_DDR_DMM_1,
+	MSM_RPM_ID_QDSS_CLK,
+
+	/* 8660 specific ids */
+	MSM_RPM_ID_TRIGGER_SET_FROM,
+	MSM_RPM_ID_TRIGGER_SET_TO,
+	MSM_RPM_ID_TRIGGER_SET_TRIGGER,
+
+	MSM_RPM_ID_TRIGGER_CLEAR_FROM,
+	MSM_RPM_ID_TRIGGER_CLEAR_TO,
+	MSM_RPM_ID_TRIGGER_CLEAR_TRIGGER,
+	MSM_RPM_ID_PLL_4,
+	MSM_RPM_ID_SMI_CLK,
+	MSM_RPM_ID_APPS_L2_CACHE_CTL,
+
+	/* pmic 8901 */
+	MSM_RPM_ID_SMPS0B_0,
+	MSM_RPM_ID_SMPS0B_1,
+	MSM_RPM_ID_SMPS1B_0,
+	MSM_RPM_ID_SMPS1B_1,
+	MSM_RPM_ID_SMPS2B_0,
+	MSM_RPM_ID_SMPS2B_1,
+	MSM_RPM_ID_SMPS3B_0,
+	MSM_RPM_ID_SMPS3B_1,
+	MSM_RPM_ID_SMPS4B_0,
+	MSM_RPM_ID_SMPS4B_1,
+	MSM_RPM_ID_LDO0B_0,
+	MSM_RPM_ID_LDO0B_1,
+	MSM_RPM_ID_LDO1B_0,
+	MSM_RPM_ID_LDO1B_1,
+	MSM_RPM_ID_LDO2B_0,
+	MSM_RPM_ID_LDO2B_1,
+	MSM_RPM_ID_LDO3B_0,
+	MSM_RPM_ID_LDO3B_1,
+	MSM_RPM_ID_LDO4B_0,
+	MSM_RPM_ID_LDO4B_1,
+	MSM_RPM_ID_LDO5B_0,
+	MSM_RPM_ID_LDO5B_1,
+	MSM_RPM_ID_LDO6B_0,
+	MSM_RPM_ID_LDO6B_1,
+	MSM_RPM_ID_LVS0B,
+	MSM_RPM_ID_LVS1B,
+	MSM_RPM_ID_LVS2B,
+	MSM_RPM_ID_LVS3B,
+	MSM_RPM_ID_MVS,
+
+	/* pmic 8058 */
+	MSM_RPM_ID_SMPS0_0,
+	MSM_RPM_ID_SMPS0_1,
+	MSM_RPM_ID_SMPS1_0,
+	MSM_RPM_ID_SMPS1_1,
+	MSM_RPM_ID_SMPS2_0,
+	MSM_RPM_ID_SMPS2_1,
+	MSM_RPM_ID_SMPS3_0,
+	MSM_RPM_ID_SMPS3_1,
+	MSM_RPM_ID_SMPS4_0,
+	MSM_RPM_ID_SMPS4_1,
+	MSM_RPM_ID_LDO0_0,
+	MSM_RPM_ID_LDO0_1,
+	MSM_RPM_ID_LDO1_0,
+	MSM_RPM_ID_LDO1_1,
+	MSM_RPM_ID_LDO2_0,
+	MSM_RPM_ID_LDO2_1,
+	MSM_RPM_ID_LDO3_0,
+	MSM_RPM_ID_LDO3_1,
+	MSM_RPM_ID_LDO4_0,
+	MSM_RPM_ID_LDO4_1,
+	MSM_RPM_ID_LDO5_0,
+	MSM_RPM_ID_LDO5_1,
+	MSM_RPM_ID_LDO6_0,
+	MSM_RPM_ID_LDO6_1,
+	MSM_RPM_ID_LDO7_0,
+	MSM_RPM_ID_LDO7_1,
+	MSM_RPM_ID_LDO8_0,
+	MSM_RPM_ID_LDO8_1,
+	MSM_RPM_ID_LDO9_0,
+	MSM_RPM_ID_LDO9_1,
+	MSM_RPM_ID_LDO10_0,
+	MSM_RPM_ID_LDO10_1,
+	MSM_RPM_ID_LDO11_0,
+	MSM_RPM_ID_LDO11_1,
+	MSM_RPM_ID_LDO12_0,
+	MSM_RPM_ID_LDO12_1,
+	MSM_RPM_ID_LDO13_0,
+	MSM_RPM_ID_LDO13_1,
+	MSM_RPM_ID_LDO14_0,
+	MSM_RPM_ID_LDO14_1,
+	MSM_RPM_ID_LDO15_0,
+	MSM_RPM_ID_LDO15_1,
+	MSM_RPM_ID_LDO16_0,
+	MSM_RPM_ID_LDO16_1,
+	MSM_RPM_ID_LDO17_0,
+	MSM_RPM_ID_LDO17_1,
+	MSM_RPM_ID_LDO18_0,
+	MSM_RPM_ID_LDO18_1,
+	MSM_RPM_ID_LDO19_0,
+	MSM_RPM_ID_LDO19_1,
+	MSM_RPM_ID_LDO20_0,
+	MSM_RPM_ID_LDO20_1,
+	MSM_RPM_ID_LDO21_0,
+	MSM_RPM_ID_LDO21_1,
+	MSM_RPM_ID_LDO22_0,
+	MSM_RPM_ID_LDO22_1,
+	MSM_RPM_ID_LDO23_0,
+	MSM_RPM_ID_LDO23_1,
+	MSM_RPM_ID_LDO24_0,
+	MSM_RPM_ID_LDO24_1,
+	MSM_RPM_ID_LDO25_0,
+	MSM_RPM_ID_LDO25_1,
+	MSM_RPM_ID_LVS0,
+	MSM_RPM_ID_LVS1,
+
+	/* 9615 specific */
+	MSM_RPM_ID_PM8018_S1_0,
+	MSM_RPM_ID_PM8018_S1_1,
+	MSM_RPM_ID_PM8018_S2_0,
+	MSM_RPM_ID_PM8018_S2_1,
+	MSM_RPM_ID_PM8018_S3_0,
+	MSM_RPM_ID_PM8018_S3_1,
+	MSM_RPM_ID_PM8018_S4_0,
+	MSM_RPM_ID_PM8018_S4_1,
+	MSM_RPM_ID_PM8018_S5_0,
+	MSM_RPM_ID_PM8018_S5_1,
+	MSM_RPM_ID_PM8018_L1_0,
+	MSM_RPM_ID_PM8018_L1_1,
+	MSM_RPM_ID_PM8018_L2_0,
+	MSM_RPM_ID_PM8018_L2_1,
+	MSM_RPM_ID_PM8018_L3_0,
+	MSM_RPM_ID_PM8018_L3_1,
+	MSM_RPM_ID_PM8018_L4_0,
+	MSM_RPM_ID_PM8018_L4_1,
+	MSM_RPM_ID_PM8018_L5_0,
+	MSM_RPM_ID_PM8018_L5_1,
+	MSM_RPM_ID_PM8018_L6_0,
+	MSM_RPM_ID_PM8018_L6_1,
+	MSM_RPM_ID_PM8018_L7_0,
+	MSM_RPM_ID_PM8018_L7_1,
+	MSM_RPM_ID_PM8018_L8_0,
+	MSM_RPM_ID_PM8018_L8_1,
+	MSM_RPM_ID_PM8018_L9_0,
+	MSM_RPM_ID_PM8018_L9_1,
+	MSM_RPM_ID_PM8018_L10_0,
+	MSM_RPM_ID_PM8018_L10_1,
+	MSM_RPM_ID_PM8018_L11_0,
+	MSM_RPM_ID_PM8018_L11_1,
+	MSM_RPM_ID_PM8018_L12_0,
+	MSM_RPM_ID_PM8018_L12_1,
+	MSM_RPM_ID_PM8018_L13_0,
+	MSM_RPM_ID_PM8018_L13_1,
+	MSM_RPM_ID_PM8018_L14_0,
+	MSM_RPM_ID_PM8018_L14_1,
+	MSM_RPM_ID_PM8018_LVS1,
+
+	/* 8930 specific */
+	MSM_RPM_ID_PM8038_S1_0,
+	MSM_RPM_ID_PM8038_S1_1,
+	MSM_RPM_ID_PM8038_S2_0,
+	MSM_RPM_ID_PM8038_S2_1,
+	MSM_RPM_ID_PM8038_S3_0,
+	MSM_RPM_ID_PM8038_S3_1,
+	MSM_RPM_ID_PM8038_S4_0,
+	MSM_RPM_ID_PM8038_S4_1,
+	MSM_RPM_ID_PM8038_S5_0,
+	MSM_RPM_ID_PM8038_S5_1,
+	MSM_RPM_ID_PM8038_S6_0,
+	MSM_RPM_ID_PM8038_S6_1,
+	MSM_RPM_ID_PM8038_L1_0,
+	MSM_RPM_ID_PM8038_L1_1,
+	MSM_RPM_ID_PM8038_L2_0,
+	MSM_RPM_ID_PM8038_L2_1,
+	MSM_RPM_ID_PM8038_L3_0,
+	MSM_RPM_ID_PM8038_L3_1,
+	MSM_RPM_ID_PM8038_L4_0,
+	MSM_RPM_ID_PM8038_L4_1,
+	MSM_RPM_ID_PM8038_L5_0,
+	MSM_RPM_ID_PM8038_L5_1,
+	MSM_RPM_ID_PM8038_L6_0,
+	MSM_RPM_ID_PM8038_L6_1,
+	MSM_RPM_ID_PM8038_L7_0,
+	MSM_RPM_ID_PM8038_L7_1,
+	MSM_RPM_ID_PM8038_L8_0,
+	MSM_RPM_ID_PM8038_L8_1,
+	MSM_RPM_ID_PM8038_L9_0,
+	MSM_RPM_ID_PM8038_L9_1,
+	MSM_RPM_ID_PM8038_L10_0,
+	MSM_RPM_ID_PM8038_L10_1,
+	MSM_RPM_ID_PM8038_L11_0,
+	MSM_RPM_ID_PM8038_L11_1,
+	MSM_RPM_ID_PM8038_L12_0,
+	MSM_RPM_ID_PM8038_L12_1,
+	MSM_RPM_ID_PM8038_L13_0,
+	MSM_RPM_ID_PM8038_L13_1,
+	MSM_RPM_ID_PM8038_L14_0,
+	MSM_RPM_ID_PM8038_L14_1,
+	MSM_RPM_ID_PM8038_L15_0,
+	MSM_RPM_ID_PM8038_L15_1,
+	MSM_RPM_ID_PM8038_L16_0,
+	MSM_RPM_ID_PM8038_L16_1,
+	MSM_RPM_ID_PM8038_L17_0,
+	MSM_RPM_ID_PM8038_L17_1,
+	MSM_RPM_ID_PM8038_L18_0,
+	MSM_RPM_ID_PM8038_L18_1,
+	MSM_RPM_ID_PM8038_L19_0,
+	MSM_RPM_ID_PM8038_L19_1,
+	MSM_RPM_ID_PM8038_L20_0,
+	MSM_RPM_ID_PM8038_L20_1,
+	MSM_RPM_ID_PM8038_L21_0,
+	MSM_RPM_ID_PM8038_L21_1,
+	MSM_RPM_ID_PM8038_L22_0,
+	MSM_RPM_ID_PM8038_L22_1,
+	MSM_RPM_ID_PM8038_L23_0,
+	MSM_RPM_ID_PM8038_L23_1,
+	MSM_RPM_ID_PM8038_L24_0,
+	MSM_RPM_ID_PM8038_L24_1,
+	MSM_RPM_ID_PM8038_L25_0,
+	MSM_RPM_ID_PM8038_L25_1,
+	MSM_RPM_ID_PM8038_L26_0,
+	MSM_RPM_ID_PM8038_L26_1,
+	MSM_RPM_ID_PM8038_L27_0,
+	MSM_RPM_ID_PM8038_L27_1,
+	MSM_RPM_ID_PM8038_CLK1_0,
+	MSM_RPM_ID_PM8038_CLK1_1,
+	MSM_RPM_ID_PM8038_CLK2_0,
+	MSM_RPM_ID_PM8038_CLK2_1,
+	MSM_RPM_ID_PM8038_LVS1,
+	MSM_RPM_ID_PM8038_LVS2,
+	MSM_RPM_ID_VOLTAGE_CORNER,
+
+	/* 8064 specific */
+	MSM_RPM_ID_PM8821_S1_0,
+	MSM_RPM_ID_PM8821_S1_1,
+	MSM_RPM_ID_PM8821_S2_0,
+	MSM_RPM_ID_PM8821_S2_1,
+	MSM_RPM_ID_PM8821_L1_0,
+	MSM_RPM_ID_PM8821_L1_1,
+
+	MSM_RPM_ID_LAST,
+};
+
+enum {
+	MSM_RPM_STATUS_ID_VERSION_MAJOR,
+	MSM_RPM_STATUS_ID_VERSION_MINOR,
+	MSM_RPM_STATUS_ID_VERSION_BUILD,
+	MSM_RPM_STATUS_ID_SUPPORTED_RESOURCES_0,
+	MSM_RPM_STATUS_ID_SUPPORTED_RESOURCES_1,
+	MSM_RPM_STATUS_ID_SUPPORTED_RESOURCES_2,
+	MSM_RPM_STATUS_ID_RESERVED_SUPPORTED_RESOURCES_0,
+	MSM_RPM_STATUS_ID_SEQUENCE,
+	MSM_RPM_STATUS_ID_RPM_CTL,
+	MSM_RPM_STATUS_ID_CXO_CLK,
+	MSM_RPM_STATUS_ID_PXO_CLK,
+	MSM_RPM_STATUS_ID_APPS_FABRIC_CLK,
+	MSM_RPM_STATUS_ID_SYSTEM_FABRIC_CLK,
+	MSM_RPM_STATUS_ID_MM_FABRIC_CLK,
+	MSM_RPM_STATUS_ID_DAYTONA_FABRIC_CLK,
+	MSM_RPM_STATUS_ID_SFPB_CLK,
+	MSM_RPM_STATUS_ID_CFPB_CLK,
+	MSM_RPM_STATUS_ID_MMFPB_CLK,
+	MSM_RPM_STATUS_ID_EBI1_CLK,
+	MSM_RPM_STATUS_ID_APPS_FABRIC_CFG_HALT,
+	MSM_RPM_STATUS_ID_APPS_FABRIC_HALT =
+		MSM_RPM_STATUS_ID_APPS_FABRIC_CFG_HALT,
+	MSM_RPM_STATUS_ID_APPS_FABRIC_CFG_CLKMOD,
+	MSM_RPM_STATUS_ID_APPS_FABRIC_CLOCK_MODE =
+		MSM_RPM_STATUS_ID_APPS_FABRIC_CFG_CLKMOD,
+	MSM_RPM_STATUS_ID_APPS_FABRIC_CFG_IOCTL,
+	MSM_RPM_STATUS_ID_APPS_FABRIC_ARB,
+	MSM_RPM_STATUS_ID_SYS_FABRIC_CFG_HALT,
+	MSM_RPM_STATUS_ID_SYSTEM_FABRIC_HALT =
+		MSM_RPM_STATUS_ID_SYS_FABRIC_CFG_HALT,
+	MSM_RPM_STATUS_ID_SYS_FABRIC_CFG_CLKMOD,
+	MSM_RPM_STATUS_ID_SYSTEM_FABRIC_CLOCK_MODE =
+		MSM_RPM_STATUS_ID_SYS_FABRIC_CFG_CLKMOD,
+	MSM_RPM_STATUS_ID_SYS_FABRIC_CFG_IOCTL,
+	MSM_RPM_STATUS_ID_SYSTEM_FABRIC_ARB,
+	MSM_RPM_STATUS_ID_MMSS_FABRIC_CFG_HALT,
+	MSM_RPM_STATUS_ID_MM_FABRIC_HALT =
+		MSM_RPM_STATUS_ID_MMSS_FABRIC_CFG_HALT,
+	MSM_RPM_STATUS_ID_MMSS_FABRIC_CFG_CLKMOD,
+	MSM_RPM_STATUS_ID_MM_FABRIC_CLOCK_MODE =
+		MSM_RPM_STATUS_ID_MMSS_FABRIC_CFG_CLKMOD,
+	MSM_RPM_STATUS_ID_MMSS_FABRIC_CFG_IOCTL,
+	MSM_RPM_STATUS_ID_MM_FABRIC_ARB,
+	MSM_RPM_STATUS_ID_PM8921_S1_0,
+	MSM_RPM_STATUS_ID_PM8921_S1_1,
+	MSM_RPM_STATUS_ID_PM8921_S2_0,
+	MSM_RPM_STATUS_ID_PM8921_S2_1,
+	MSM_RPM_STATUS_ID_PM8921_S3_0,
+	MSM_RPM_STATUS_ID_PM8921_S3_1,
+	MSM_RPM_STATUS_ID_PM8921_S4_0,
+	MSM_RPM_STATUS_ID_PM8921_S4_1,
+	MSM_RPM_STATUS_ID_PM8921_S5_0,
+	MSM_RPM_STATUS_ID_PM8921_S5_1,
+	MSM_RPM_STATUS_ID_PM8921_S6_0,
+	MSM_RPM_STATUS_ID_PM8921_S6_1,
+	MSM_RPM_STATUS_ID_PM8921_S7_0,
+	MSM_RPM_STATUS_ID_PM8921_S7_1,
+	MSM_RPM_STATUS_ID_PM8921_S8_0,
+	MSM_RPM_STATUS_ID_PM8921_S8_1,
+	MSM_RPM_STATUS_ID_PM8921_L1_0,
+	MSM_RPM_STATUS_ID_PM8921_L1_1,
+	MSM_RPM_STATUS_ID_PM8921_L2_0,
+	MSM_RPM_STATUS_ID_PM8921_L2_1,
+	MSM_RPM_STATUS_ID_PM8921_L3_0,
+	MSM_RPM_STATUS_ID_PM8921_L3_1,
+	MSM_RPM_STATUS_ID_PM8921_L4_0,
+	MSM_RPM_STATUS_ID_PM8921_L4_1,
+	MSM_RPM_STATUS_ID_PM8921_L5_0,
+	MSM_RPM_STATUS_ID_PM8921_L5_1,
+	MSM_RPM_STATUS_ID_PM8921_L6_0,
+	MSM_RPM_STATUS_ID_PM8921_L6_1,
+	MSM_RPM_STATUS_ID_PM8921_L7_0,
+	MSM_RPM_STATUS_ID_PM8921_L7_1,
+	MSM_RPM_STATUS_ID_PM8921_L8_0,
+	MSM_RPM_STATUS_ID_PM8921_L8_1,
+	MSM_RPM_STATUS_ID_PM8921_L9_0,
+	MSM_RPM_STATUS_ID_PM8921_L9_1,
+	MSM_RPM_STATUS_ID_PM8921_L10_0,
+	MSM_RPM_STATUS_ID_PM8921_L10_1,
+	MSM_RPM_STATUS_ID_PM8921_L11_0,
+	MSM_RPM_STATUS_ID_PM8921_L11_1,
+	MSM_RPM_STATUS_ID_PM8921_L12_0,
+	MSM_RPM_STATUS_ID_PM8921_L12_1,
+	MSM_RPM_STATUS_ID_PM8921_L13_0,
+	MSM_RPM_STATUS_ID_PM8921_L13_1,
+	MSM_RPM_STATUS_ID_PM8921_L14_0,
+	MSM_RPM_STATUS_ID_PM8921_L14_1,
+	MSM_RPM_STATUS_ID_PM8921_L15_0,
+	MSM_RPM_STATUS_ID_PM8921_L15_1,
+	MSM_RPM_STATUS_ID_PM8921_L16_0,
+	MSM_RPM_STATUS_ID_PM8921_L16_1,
+	MSM_RPM_STATUS_ID_PM8921_L17_0,
+	MSM_RPM_STATUS_ID_PM8921_L17_1,
+	MSM_RPM_STATUS_ID_PM8921_L18_0,
+	MSM_RPM_STATUS_ID_PM8921_L18_1,
+	MSM_RPM_STATUS_ID_PM8921_L19_0,
+	MSM_RPM_STATUS_ID_PM8921_L19_1,
+	MSM_RPM_STATUS_ID_PM8921_L20_0,
+	MSM_RPM_STATUS_ID_PM8921_L20_1,
+	MSM_RPM_STATUS_ID_PM8921_L21_0,
+	MSM_RPM_STATUS_ID_PM8921_L21_1,
+	MSM_RPM_STATUS_ID_PM8921_L22_0,
+	MSM_RPM_STATUS_ID_PM8921_L22_1,
+	MSM_RPM_STATUS_ID_PM8921_L23_0,
+	MSM_RPM_STATUS_ID_PM8921_L23_1,
+	MSM_RPM_STATUS_ID_PM8921_L24_0,
+	MSM_RPM_STATUS_ID_PM8921_L24_1,
+	MSM_RPM_STATUS_ID_PM8921_L25_0,
+	MSM_RPM_STATUS_ID_PM8921_L25_1,
+	MSM_RPM_STATUS_ID_PM8921_L26_0,
+	MSM_RPM_STATUS_ID_PM8921_L26_1,
+	MSM_RPM_STATUS_ID_PM8921_L27_0,
+	MSM_RPM_STATUS_ID_PM8921_L27_1,
+	MSM_RPM_STATUS_ID_PM8921_L28_0,
+	MSM_RPM_STATUS_ID_PM8921_L28_1,
+	MSM_RPM_STATUS_ID_PM8921_L29_0,
+	MSM_RPM_STATUS_ID_PM8921_L29_1,
+	MSM_RPM_STATUS_ID_PM8921_CLK1_0,
+	MSM_RPM_STATUS_ID_PM8921_CLK1_1,
+	MSM_RPM_STATUS_ID_PM8921_CLK2_0,
+	MSM_RPM_STATUS_ID_PM8921_CLK2_1,
+	MSM_RPM_STATUS_ID_PM8921_LVS1,
+	MSM_RPM_STATUS_ID_PM8921_LVS2,
+	MSM_RPM_STATUS_ID_PM8921_LVS3,
+	MSM_RPM_STATUS_ID_PM8921_LVS4,
+	MSM_RPM_STATUS_ID_PM8921_LVS5,
+	MSM_RPM_STATUS_ID_PM8921_LVS6,
+	MSM_RPM_STATUS_ID_PM8921_LVS7,
+	MSM_RPM_STATUS_ID_NCP_0,
+	MSM_RPM_STATUS_ID_NCP_1,
+	MSM_RPM_STATUS_ID_CXO_BUFFERS,
+	MSM_RPM_STATUS_ID_USB_OTG_SWITCH,
+	MSM_RPM_STATUS_ID_HDMI_SWITCH,
+	MSM_RPM_STATUS_ID_DDR_DMM_0,
+	MSM_RPM_STATUS_ID_DDR_DMM_1,
+	MSM_RPM_STATUS_ID_EBI1_CH0_RANGE,
+	MSM_RPM_STATUS_ID_EBI1_CH1_RANGE,
+	MSM_RPM_STATUS_ID_QDSS_CLK,
+
+	/* 8660 Specific */
+	MSM_RPM_STATUS_ID_PLL_4,
+	MSM_RPM_STATUS_ID_SMI_CLK,
+	MSM_RPM_STATUS_ID_APPS_L2_CACHE_CTL,
+	MSM_RPM_STATUS_ID_SMPS0B_0,
+	MSM_RPM_STATUS_ID_SMPS0B_1,
+	MSM_RPM_STATUS_ID_SMPS1B_0,
+	MSM_RPM_STATUS_ID_SMPS1B_1,
+	MSM_RPM_STATUS_ID_SMPS2B_0,
+	MSM_RPM_STATUS_ID_SMPS2B_1,
+	MSM_RPM_STATUS_ID_SMPS3B_0,
+	MSM_RPM_STATUS_ID_SMPS3B_1,
+	MSM_RPM_STATUS_ID_SMPS4B_0,
+	MSM_RPM_STATUS_ID_SMPS4B_1,
+	MSM_RPM_STATUS_ID_LDO0B_0,
+	MSM_RPM_STATUS_ID_LDO0B_1,
+	MSM_RPM_STATUS_ID_LDO1B_0,
+	MSM_RPM_STATUS_ID_LDO1B_1,
+	MSM_RPM_STATUS_ID_LDO2B_0,
+	MSM_RPM_STATUS_ID_LDO2B_1,
+	MSM_RPM_STATUS_ID_LDO3B_0,
+	MSM_RPM_STATUS_ID_LDO3B_1,
+	MSM_RPM_STATUS_ID_LDO4B_0,
+	MSM_RPM_STATUS_ID_LDO4B_1,
+	MSM_RPM_STATUS_ID_LDO5B_0,
+	MSM_RPM_STATUS_ID_LDO5B_1,
+	MSM_RPM_STATUS_ID_LDO6B_0,
+	MSM_RPM_STATUS_ID_LDO6B_1,
+	MSM_RPM_STATUS_ID_LVS0B,
+	MSM_RPM_STATUS_ID_LVS1B,
+	MSM_RPM_STATUS_ID_LVS2B,
+	MSM_RPM_STATUS_ID_LVS3B,
+	MSM_RPM_STATUS_ID_MVS,
+	MSM_RPM_STATUS_ID_SMPS0_0,
+	MSM_RPM_STATUS_ID_SMPS0_1,
+	MSM_RPM_STATUS_ID_SMPS1_0,
+	MSM_RPM_STATUS_ID_SMPS1_1,
+	MSM_RPM_STATUS_ID_SMPS2_0,
+	MSM_RPM_STATUS_ID_SMPS2_1,
+	MSM_RPM_STATUS_ID_SMPS3_0,
+	MSM_RPM_STATUS_ID_SMPS3_1,
+	MSM_RPM_STATUS_ID_SMPS4_0,
+	MSM_RPM_STATUS_ID_SMPS4_1,
+	MSM_RPM_STATUS_ID_LDO0_0,
+	MSM_RPM_STATUS_ID_LDO0_1,
+	MSM_RPM_STATUS_ID_LDO1_0,
+	MSM_RPM_STATUS_ID_LDO1_1,
+	MSM_RPM_STATUS_ID_LDO2_0,
+	MSM_RPM_STATUS_ID_LDO2_1,
+	MSM_RPM_STATUS_ID_LDO3_0,
+	MSM_RPM_STATUS_ID_LDO3_1,
+	MSM_RPM_STATUS_ID_LDO4_0,
+	MSM_RPM_STATUS_ID_LDO4_1,
+	MSM_RPM_STATUS_ID_LDO5_0,
+	MSM_RPM_STATUS_ID_LDO5_1,
+	MSM_RPM_STATUS_ID_LDO6_0,
+	MSM_RPM_STATUS_ID_LDO6_1,
+	MSM_RPM_STATUS_ID_LDO7_0,
+	MSM_RPM_STATUS_ID_LDO7_1,
+	MSM_RPM_STATUS_ID_LDO8_0,
+	MSM_RPM_STATUS_ID_LDO8_1,
+	MSM_RPM_STATUS_ID_LDO9_0,
+	MSM_RPM_STATUS_ID_LDO9_1,
+	MSM_RPM_STATUS_ID_LDO10_0,
+	MSM_RPM_STATUS_ID_LDO10_1,
+	MSM_RPM_STATUS_ID_LDO11_0,
+	MSM_RPM_STATUS_ID_LDO11_1,
+	MSM_RPM_STATUS_ID_LDO12_0,
+	MSM_RPM_STATUS_ID_LDO12_1,
+	MSM_RPM_STATUS_ID_LDO13_0,
+	MSM_RPM_STATUS_ID_LDO13_1,
+	MSM_RPM_STATUS_ID_LDO14_0,
+	MSM_RPM_STATUS_ID_LDO14_1,
+	MSM_RPM_STATUS_ID_LDO15_0,
+	MSM_RPM_STATUS_ID_LDO15_1,
+	MSM_RPM_STATUS_ID_LDO16_0,
+	MSM_RPM_STATUS_ID_LDO16_1,
+	MSM_RPM_STATUS_ID_LDO17_0,
+	MSM_RPM_STATUS_ID_LDO17_1,
+	MSM_RPM_STATUS_ID_LDO18_0,
+	MSM_RPM_STATUS_ID_LDO18_1,
+	MSM_RPM_STATUS_ID_LDO19_0,
+	MSM_RPM_STATUS_ID_LDO19_1,
+	MSM_RPM_STATUS_ID_LDO20_0,
+	MSM_RPM_STATUS_ID_LDO20_1,
+	MSM_RPM_STATUS_ID_LDO21_0,
+	MSM_RPM_STATUS_ID_LDO21_1,
+	MSM_RPM_STATUS_ID_LDO22_0,
+	MSM_RPM_STATUS_ID_LDO22_1,
+	MSM_RPM_STATUS_ID_LDO23_0,
+	MSM_RPM_STATUS_ID_LDO23_1,
+	MSM_RPM_STATUS_ID_LDO24_0,
+	MSM_RPM_STATUS_ID_LDO24_1,
+	MSM_RPM_STATUS_ID_LDO25_0,
+	MSM_RPM_STATUS_ID_LDO25_1,
+	MSM_RPM_STATUS_ID_LVS0,
+	MSM_RPM_STATUS_ID_LVS1,
+
+	/* 9615 Specific */
+	MSM_RPM_STATUS_ID_PM8018_S1_0,
+	MSM_RPM_STATUS_ID_PM8018_S1_1,
+	MSM_RPM_STATUS_ID_PM8018_S2_0,
+	MSM_RPM_STATUS_ID_PM8018_S2_1,
+	MSM_RPM_STATUS_ID_PM8018_S3_0,
+	MSM_RPM_STATUS_ID_PM8018_S3_1,
+	MSM_RPM_STATUS_ID_PM8018_S4_0,
+	MSM_RPM_STATUS_ID_PM8018_S4_1,
+	MSM_RPM_STATUS_ID_PM8018_S5_0,
+	MSM_RPM_STATUS_ID_PM8018_S5_1,
+	MSM_RPM_STATUS_ID_PM8018_L1_0,
+	MSM_RPM_STATUS_ID_PM8018_L1_1,
+	MSM_RPM_STATUS_ID_PM8018_L2_0,
+	MSM_RPM_STATUS_ID_PM8018_L2_1,
+	MSM_RPM_STATUS_ID_PM8018_L3_0,
+	MSM_RPM_STATUS_ID_PM8018_L3_1,
+	MSM_RPM_STATUS_ID_PM8018_L4_0,
+	MSM_RPM_STATUS_ID_PM8018_L4_1,
+	MSM_RPM_STATUS_ID_PM8018_L5_0,
+	MSM_RPM_STATUS_ID_PM8018_L5_1,
+	MSM_RPM_STATUS_ID_PM8018_L6_0,
+	MSM_RPM_STATUS_ID_PM8018_L6_1,
+	MSM_RPM_STATUS_ID_PM8018_L7_0,
+	MSM_RPM_STATUS_ID_PM8018_L7_1,
+	MSM_RPM_STATUS_ID_PM8018_L8_0,
+	MSM_RPM_STATUS_ID_PM8018_L8_1,
+	MSM_RPM_STATUS_ID_PM8018_L9_0,
+	MSM_RPM_STATUS_ID_PM8018_L9_1,
+	MSM_RPM_STATUS_ID_PM8018_L10_0,
+	MSM_RPM_STATUS_ID_PM8018_L10_1,
+	MSM_RPM_STATUS_ID_PM8018_L11_0,
+	MSM_RPM_STATUS_ID_PM8018_L11_1,
+	MSM_RPM_STATUS_ID_PM8018_L12_0,
+	MSM_RPM_STATUS_ID_PM8018_L12_1,
+	MSM_RPM_STATUS_ID_PM8018_L13_0,
+	MSM_RPM_STATUS_ID_PM8018_L13_1,
+	MSM_RPM_STATUS_ID_PM8018_L14_0,
+	MSM_RPM_STATUS_ID_PM8018_L14_1,
+	MSM_RPM_STATUS_ID_PM8018_LVS1,
+
+	/* 8930 specific */
+	MSM_RPM_STATUS_ID_PM8038_S1_0,
+	MSM_RPM_STATUS_ID_PM8038_S1_1,
+	MSM_RPM_STATUS_ID_PM8038_S2_0,
+	MSM_RPM_STATUS_ID_PM8038_S2_1,
+	MSM_RPM_STATUS_ID_PM8038_S3_0,
+	MSM_RPM_STATUS_ID_PM8038_S3_1,
+	MSM_RPM_STATUS_ID_PM8038_S4_0,
+	MSM_RPM_STATUS_ID_PM8038_S4_1,
+	MSM_RPM_STATUS_ID_PM8038_S5_0,
+	MSM_RPM_STATUS_ID_PM8038_S5_1,
+	MSM_RPM_STATUS_ID_PM8038_S6_0,
+	MSM_RPM_STATUS_ID_PM8038_S6_1,
+	MSM_RPM_STATUS_ID_PM8038_L1_0,
+	MSM_RPM_STATUS_ID_PM8038_L1_1,
+	MSM_RPM_STATUS_ID_PM8038_L2_0,
+	MSM_RPM_STATUS_ID_PM8038_L2_1,
+	MSM_RPM_STATUS_ID_PM8038_L3_0,
+	MSM_RPM_STATUS_ID_PM8038_L3_1,
+	MSM_RPM_STATUS_ID_PM8038_L4_0,
+	MSM_RPM_STATUS_ID_PM8038_L4_1,
+	MSM_RPM_STATUS_ID_PM8038_L5_0,
+	MSM_RPM_STATUS_ID_PM8038_L5_1,
+	MSM_RPM_STATUS_ID_PM8038_L6_0,
+	MSM_RPM_STATUS_ID_PM8038_L6_1,
+	MSM_RPM_STATUS_ID_PM8038_L7_0,
+	MSM_RPM_STATUS_ID_PM8038_L7_1,
+	MSM_RPM_STATUS_ID_PM8038_L8_0,
+	MSM_RPM_STATUS_ID_PM8038_L8_1,
+	MSM_RPM_STATUS_ID_PM8038_L9_0,
+	MSM_RPM_STATUS_ID_PM8038_L9_1,
+	MSM_RPM_STATUS_ID_PM8038_L10_0,
+	MSM_RPM_STATUS_ID_PM8038_L10_1,
+	MSM_RPM_STATUS_ID_PM8038_L11_0,
+	MSM_RPM_STATUS_ID_PM8038_L11_1,
+	MSM_RPM_STATUS_ID_PM8038_L12_0,
+	MSM_RPM_STATUS_ID_PM8038_L12_1,
+	MSM_RPM_STATUS_ID_PM8038_L13_0,
+	MSM_RPM_STATUS_ID_PM8038_L13_1,
+	MSM_RPM_STATUS_ID_PM8038_L14_0,
+	MSM_RPM_STATUS_ID_PM8038_L14_1,
+	MSM_RPM_STATUS_ID_PM8038_L15_0,
+	MSM_RPM_STATUS_ID_PM8038_L15_1,
+	MSM_RPM_STATUS_ID_PM8038_L16_0,
+	MSM_RPM_STATUS_ID_PM8038_L16_1,
+	MSM_RPM_STATUS_ID_PM8038_L17_0,
+	MSM_RPM_STATUS_ID_PM8038_L17_1,
+	MSM_RPM_STATUS_ID_PM8038_L18_0,
+	MSM_RPM_STATUS_ID_PM8038_L18_1,
+	MSM_RPM_STATUS_ID_PM8038_L19_0,
+	MSM_RPM_STATUS_ID_PM8038_L19_1,
+	MSM_RPM_STATUS_ID_PM8038_L20_0,
+	MSM_RPM_STATUS_ID_PM8038_L20_1,
+	MSM_RPM_STATUS_ID_PM8038_L21_0,
+	MSM_RPM_STATUS_ID_PM8038_L21_1,
+	MSM_RPM_STATUS_ID_PM8038_L22_0,
+	MSM_RPM_STATUS_ID_PM8038_L22_1,
+	MSM_RPM_STATUS_ID_PM8038_L23_0,
+	MSM_RPM_STATUS_ID_PM8038_L23_1,
+	MSM_RPM_STATUS_ID_PM8038_L24_0,
+	MSM_RPM_STATUS_ID_PM8038_L24_1,
+	MSM_RPM_STATUS_ID_PM8038_L25_0,
+	MSM_RPM_STATUS_ID_PM8038_L25_1,
+	MSM_RPM_STATUS_ID_PM8038_L26_0,
+	MSM_RPM_STATUS_ID_PM8038_L26_1,
+	MSM_RPM_STATUS_ID_PM8038_L27_0,
+	MSM_RPM_STATUS_ID_PM8038_L27_1,
+	MSM_RPM_STATUS_ID_PM8038_CLK1_0,
+	MSM_RPM_STATUS_ID_PM8038_CLK1_1,
+	MSM_RPM_STATUS_ID_PM8038_CLK2_0,
+	MSM_RPM_STATUS_ID_PM8038_CLK2_1,
+	MSM_RPM_STATUS_ID_PM8038_LVS1,
+	MSM_RPM_STATUS_ID_PM8038_LVS2,
+	MSM_RPM_STATUS_ID_VOLTAGE_CORNER,
+
+	/* 8064 specific */
+	MSM_RPM_STATUS_ID_PM8821_S1_0,
+	MSM_RPM_STATUS_ID_PM8821_S1_1,
+	MSM_RPM_STATUS_ID_PM8821_S2_0,
+	MSM_RPM_STATUS_ID_PM8821_S2_1,
+	MSM_RPM_STATUS_ID_PM8821_L1_0,
+	MSM_RPM_STATUS_ID_PM8821_L1_1,
+
+	MSM_RPM_STATUS_ID_LAST,
+};
+
+static inline uint32_t msm_rpm_get_ctx_mask(unsigned int ctx)
+{
+	return 1UL << ctx;
+}
+
+static inline unsigned int msm_rpm_get_sel_mask_reg(unsigned int sel)
+{
+	return sel / 32;
+}
+
+static inline uint32_t msm_rpm_get_sel_mask(unsigned int sel)
+{
+	return 1UL << (sel % 32);
+}
+
+struct msm_rpm_iv_pair {
+	uint32_t id;
+	uint32_t value;
+};
+
+struct msm_rpm_notification {
+	struct list_head list;  /* reserved for RPM use */
+	struct semaphore sem;
+	uint32_t sel_masks[SEL_MASK_SIZE];  /* reserved for RPM use */
+};
+
+struct msm_rpm_map_data {
+	uint32_t id;
+	uint32_t sel;
+	uint32_t count;
+};
+
+#define MSM_RPM_MAP(t, i, s, c) \
+	[MSM_RPM_ID_##i] = \
+	{\
+		.id = MSM_RPM_##t##_ID_##i, \
+		.sel = MSM_RPM_##t##_SEL_##s, \
+		.count = c, \
+	}
+
+#define MSM_RPM_STATUS_ID_VALID BIT(31)
+
+#define MSM_RPM_STATUS_ID_MAP(t, i) \
+	[MSM_RPM_STATUS_ID_## i] = (MSM_RPM_##t##_STATUS_ID_##i \
+					| MSM_RPM_STATUS_ID_VALID)
+
+#define MSM_RPM_CTRL_MAP(t, i) \
+	[MSM_RPM_CTRL_##i] = MSM_RPM_##t##_CTRL_##i
+
+
+struct msm_rpm_platform_data {
+	void __iomem *reg_base_addrs[MSM_RPM_PAGE_COUNT];
+	unsigned int irq_ack;
+	unsigned int irq_err;
+	unsigned int irq_wakeup;
+	void *ipc_rpm_reg;
+	unsigned int ipc_rpm_val;
+	struct msm_rpm_map_data target_id[MSM_RPM_ID_LAST];
+	unsigned int target_status[MSM_RPM_STATUS_ID_LAST];
+	unsigned int target_ctrl_id[MSM_RPM_CTRL_LAST];
+	unsigned int sel_invalidate, sel_notification, sel_last;
+	unsigned int ver[3];
+};
+
+extern struct msm_rpm_platform_data msm8660_rpm_data;
+extern struct msm_rpm_platform_data msm8960_rpm_data;
+extern struct msm_rpm_platform_data msm9615_rpm_data;
+extern struct msm_rpm_platform_data msm8930_rpm_data;
+extern struct msm_rpm_platform_data apq8064_rpm_data;
+
+int msm_rpm_local_request_is_outstanding(void);
+int msm_rpm_get_status(struct msm_rpm_iv_pair *status, int count);
+int msm_rpm_set(int ctx, struct msm_rpm_iv_pair *req, int count);
+int msm_rpm_set_noirq(int ctx, struct msm_rpm_iv_pair *req, int count);
+
+static inline int msm_rpm_set_nosleep(
+	int ctx, struct msm_rpm_iv_pair *req, int count)
+{
+	unsigned long flags;
+	int rc;
+
+	local_irq_save(flags);
+	rc = msm_rpm_set_noirq(ctx, req, count);
+	local_irq_restore(flags);
+
+	return rc;
+}
+
+int msm_rpm_clear(int ctx, struct msm_rpm_iv_pair *req, int count);
+int msm_rpm_clear_noirq(int ctx, struct msm_rpm_iv_pair *req, int count);
+
+static inline int msm_rpm_clear_nosleep(
+	int ctx, struct msm_rpm_iv_pair *req, int count)
+{
+	unsigned long flags;
+	int rc;
+
+	local_irq_save(flags);
+	rc = msm_rpm_clear_noirq(ctx, req, count);
+	local_irq_restore(flags);
+
+	return rc;
+}
+
+int msm_rpm_register_notification(struct msm_rpm_notification *n,
+	struct msm_rpm_iv_pair *req, int count);
+int msm_rpm_unregister_notification(struct msm_rpm_notification *n);
+int msm_rpm_init(struct msm_rpm_platform_data *data);
+
+#endif /* __ARCH_ARM_MACH_MSM_RPM_H */
diff --git a/arch/arm/mach-msm/include/mach/scm-io.h b/arch/arm/mach-msm/include/mach/scm-io.h
new file mode 100644
index 0000000..5393da1
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/scm-io.h
@@ -0,0 +1,29 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __MACH_SCM_IO_H
+#define __MACH_SCM_IO_H
+
+#include <linux/types.h>
+
+#ifdef CONFIG_MSM_SECURE_IO
+
+extern u32 secure_readl(void __iomem *c);
+extern void secure_writel(u32 v, void __iomem *c);
+
+#else
+
+#define secure_readl(c) readl(c)
+#define secure_writel(v, c) writel(v, c)
+
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/scm.h b/arch/arm/mach-msm/include/mach/scm.h
new file mode 100644
index 0000000..7cc5f7a
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/scm.h
@@ -0,0 +1,83 @@
+/* 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
+ * 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 __MACH_SCM_H
+#define __MACH_SCM_H
+
+#define SCM_SVC_BOOT			0x1
+#define SCM_SVC_PIL			0x2
+#define SCM_SVC_UTIL			0x3
+#define SCM_SVC_TZ			0x4
+#define SCM_SVC_IO			0x5
+#define SCM_SVC_INFO			0x6
+#define SCM_SVC_SSD			0x7
+#define SCM_SVC_FUSE			0x8
+#define SCM_SVC_PWR			0x9
+#define SCM_SVC_CP			0xC
+#define SCM_SVC_DCVS			0xD
+#define SCM_SVC_TZSCHEDULER		0xFC
+
+#ifdef CONFIG_MSM_SCM
+extern int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len,
+		void *resp_buf, size_t resp_len);
+
+extern s32 scm_call_atomic1(u32 svc, u32 cmd, u32 arg1);
+extern s32 scm_call_atomic2(u32 svc, u32 cmd, u32 arg1, u32 arg2);
+extern s32 scm_call_atomic4_3(u32 svc, u32 cmd, u32 arg1, u32 arg2, u32 arg3,
+		u32 arg4, u32 *ret1, u32 *ret2);
+
+#define SCM_VERSION(major, minor) (((major) << 16) | ((minor) & 0xFF))
+
+extern u32 scm_get_version(void);
+extern int scm_is_call_available(u32 svc_id, u32 cmd_id);
+extern int scm_get_feat_version(u32 feat);
+
+#else
+
+static inline int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf,
+		size_t cmd_len, void *resp_buf, size_t resp_len)
+{
+	return 0;
+}
+
+static inline s32 scm_call_atomic1(u32 svc, u32 cmd, u32 arg1)
+{
+	return 0;
+}
+
+static inline s32 scm_call_atomic2(u32 svc, u32 cmd, u32 arg1, u32 arg2)
+{
+	return 0;
+}
+
+static inline s32 scm_call_atomic4_3(u32 svc, u32 cmd, u32 arg1, u32 arg2,
+		u32 arg3, u32 arg4, u32 *ret1, u32 *ret2)
+{
+	return 0;
+}
+
+static inline u32 scm_get_version(void)
+{
+	return 0;
+}
+
+static inline int scm_is_call_available(u32 svc_id, u32 cmd_id)
+{
+	return 0;
+}
+
+static inline int scm_get_feat_version(u32 feat)
+{
+	return 0;
+}
+
+#endif
+#endif
diff --git a/arch/arm/mach-msm/include/mach/sdio_al.h b/arch/arm/mach-msm/include/mach/sdio_al.h
new file mode 100644
index 0000000..8b8ee5a
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/sdio_al.h
@@ -0,0 +1,153 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/*
+ * SDIO-Abstraction-Layer API.
+ */
+
+#ifndef __SDIO_AL__
+#define __SDIO_AL__
+
+#include <linux/mmc/card.h>
+
+struct sdio_channel; /* Forward Declaration */
+
+
+/**
+ *  Channel Events.
+ *  Available bytes notification.
+ */
+#define SDIO_EVENT_DATA_READ_AVAIL      0x01
+#define SDIO_EVENT_DATA_WRITE_AVAIL     0x02
+
+#ifdef CONFIG_MSM_SDIO_AL
+
+struct sdio_al_platform_data {
+	int (*config_mdm2ap_status)(int);
+	int (*get_mdm2ap_status)(void);
+	int allow_sdioc_version_major_2;
+	int peer_sdioc_version_minor;
+	int peer_sdioc_version_major;
+	int peer_sdioc_boot_version_minor;
+	int peer_sdioc_boot_version_major;
+};
+
+/**
+ * sdio_open - open a channel for read/write data.
+ *
+ * @name: channel name - identify the channel to open.
+ * @ch: channel handle returned.
+ * @priv: caller private context pointer, passed to the notify callback.
+ * @notify: notification callback for data available.
+ * @channel_event: SDIO_EVENT_DATA_READ_AVAIL or SDIO_EVENT_DATA_WRITE_AVAIL
+ * @return 0 on success, negative value on error.
+ *
+ * Warning: notify() may be called before open returns.
+ */
+int sdio_open(const char *name, struct sdio_channel **ch, void *priv,
+	     void (*notify)(void *priv, unsigned channel_event));
+
+
+/**
+ * sdio_close - close a channel.
+ *
+ * @ch: channel handle.
+ * @return 0 on success, negative value on error.
+ */
+int sdio_close(struct sdio_channel *ch);
+
+/**
+ * sdio_read - synchronous read.
+ *
+ * @ch: channel handle.
+ * @data: caller buffer pointer. should be non-cacheable.
+ * @len: byte count.
+ * @return 0 on success, negative value on error.
+ *
+ * May wait if no available bytes.
+ * May wait if other channel with higher priority has pending
+ * transfers.
+ * Client should check available bytes prior to calling this
+ * api.
+ */
+int sdio_read(struct sdio_channel *ch, void *data, int len);
+
+/**
+ * sdio_write - synchronous write.
+ *
+ * @ch: channel handle.
+ * @data: caller buffer pointer. should be non-cacheable.
+ * @len: byte count.
+ * @return 0 on success, negative value on error.
+ *
+ * May wait if no available bytes.
+ * May wait if other channel with higher priority has pending
+ * transfers.
+ * Client should check available bytes prior to calling this
+ * api.
+ */
+int sdio_write(struct sdio_channel *ch, const void *data, int len);
+
+/**
+ * sdio_write_avail - get available bytes to write.
+ *
+ * @ch: channel handle.
+ * @return byte count on success, negative value on error.
+ */
+int sdio_write_avail(struct sdio_channel *ch);
+
+/**
+ * sdio_read_avail - get available bytes to read.
+ *
+ * @ch: channel handle.
+ * @return byte count on success, negative value on error.
+ */
+int sdio_read_avail(struct sdio_channel *ch);
+
+#else
+
+static int __maybe_unused sdio_open(const char *name, struct sdio_channel **ch,
+		void *priv, void (*notify)(void *priv, unsigned channel_event))
+{
+	return -ENODEV;
+}
+
+static int __maybe_unused sdio_close(struct sdio_channel *ch)
+{
+	return -ENODEV;
+}
+
+static int __maybe_unused sdio_read(struct sdio_channel *ch, void *data,
+						int len)
+{
+	return -ENODEV;
+}
+
+static int __maybe_unused sdio_write(struct sdio_channel *ch, const void *data,
+						int len)
+{
+	return -ENODEV;
+}
+
+static int __maybe_unused sdio_write_avail(struct sdio_channel *ch)
+{
+	return -ENODEV;
+}
+
+static int __maybe_unused sdio_read_avail(struct sdio_channel *ch)
+{
+	return -ENODEV;
+}
+#endif
+
+#endif /* __SDIO_AL__ */
diff --git a/arch/arm/mach-msm/include/mach/sdio_cmux.h b/arch/arm/mach-msm/include/mach/sdio_cmux.h
new file mode 100644
index 0000000..4bcd607
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/sdio_cmux.h
@@ -0,0 +1,146 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/*
+ * SDIO CMUX API
+ */
+
+#ifndef __SDIO_CMUX__
+#define __SDIO_CMUX__
+
+#ifdef CONFIG_MSM_SDIO_CMUX
+
+enum {
+	SDIO_CMUX_DATA_CTL_0,
+	SDIO_CMUX_DATA_CTL_1,
+	SDIO_CMUX_DATA_CTL_2,
+	SDIO_CMUX_DATA_CTL_3,
+	SDIO_CMUX_DATA_CTL_4,
+	SDIO_CMUX_DATA_CTL_5,
+	SDIO_CMUX_DATA_CTL_6,
+	SDIO_CMUX_DATA_CTL_7,
+	SDIO_CMUX_USB_CTL_0,
+	SDIO_CMUX_USB_DUN_CTL_0,
+	SDIO_CMUX_CSVT_CTL_0,
+	SDIO_CMUX_NUM_CHANNELS
+};
+
+
+/*
+ * sdio_cmux_open - Open the mux channel
+ *
+ * @id: Mux Channel id to be opened
+ * @receive_cb: Notification when data arrives.  Parameters are data received,
+ *	size of data, private context pointer.
+ * @write_done: Notification when data is written.  Parameters are data written,
+ *	size of data, private context pointer.  Please note that the data
+ *	written pointer will always be NULL as the cmux makes an internal copy
+ *	of the data.
+ * @priv: caller's private context pointer
+ */
+int sdio_cmux_open(const int id,
+		   void (*receive_cb)(void *, int, void *),
+		   void (*write_done)(void *, int, void *),
+		   void (*status_callback)(int, void *),
+		   void *priv);
+
+/*
+ * sdio_cmux_close - Close the mux channel
+ *
+ * @id: Channel id to be closed
+ */
+int sdio_cmux_close(int id);
+
+/*
+ * sdio_cmux_write_avail - Write space avaialable for this channel
+ *
+ * @id: Channel id to look for the available write space
+ */
+int sdio_cmux_write_avail(int id);
+
+/*
+ * sdio_cmux_write - Write the data onto the CMUX channel
+ *
+ * @id: Channel id onto which the data has to be written
+ * @data: Starting address of the data buffer to be written
+ * @len: Length of the data to be written
+ */
+int sdio_cmux_write(int id, void *data, int len);
+
+/* these are used to get and set the IF sigs of a channel.
+ * DTR and RTS can be set; DSR, CTS, CD and RI can be read.
+ */
+int sdio_cmux_tiocmget(int id);
+int sdio_cmux_tiocmset(int id, unsigned int set, unsigned int clear);
+
+/*
+ * is_remote_open - Check whether the remote channel is open
+ *
+ * @id: Channel id to be checked
+ */
+int is_remote_open(int id);
+
+/*
+ * sdio_cmux_is_channel_reset - Check whether the channel is in reset state
+ *
+ * @id: Channel id to be checked
+ */
+int sdio_cmux_is_channel_reset(int id);
+
+#else
+
+static int __maybe_unused sdio_cmux_open(const int id,
+		   void (*receive_cb)(void *, int, void *),
+		   void (*write_done)(void *, int, void *),
+		   void (*status_callback)(int, void *),
+		   void *priv)
+{
+	return -ENODEV;
+}
+static int __maybe_unused sdio_cmux_close(int id)
+{
+	return -ENODEV;
+}
+
+static int __maybe_unused sdio_cmux_write_avail(int id)
+{
+	return -ENODEV;
+}
+
+static int __maybe_unused sdio_cmux_write(int id, void *data, int len)
+{
+	return -ENODEV;
+}
+
+static int __maybe_unused sdio_cmux_tiocmget(int id)
+{
+	return -ENODEV;
+}
+
+static int __maybe_unused sdio_cmux_tiocmset(int id, unsigned int set,
+							unsigned int clear)
+{
+	return -ENODEV;
+}
+
+static int __maybe_unused is_remote_open(int id)
+{
+	return -ENODEV;
+}
+
+static int __maybe_unused sdio_cmux_is_channel_reset(int id)
+{
+	return -ENODEV;
+}
+#endif
+#endif /* __SDIO_CMUX__ */
diff --git a/arch/arm/mach-msm/include/mach/sdio_dmux.h b/arch/arm/mach-msm/include/mach/sdio_dmux.h
new file mode 100644
index 0000000..afc1b11
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/sdio_dmux.h
@@ -0,0 +1,83 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/skbuff.h>
+
+#ifndef _SDIO_DMUX_H
+#define _SDIO_DMUX_H
+
+#ifdef CONFIG_MSM_SDIO_DMUX
+enum {
+	SDIO_DMUX_DATA_RMNET_0,
+	SDIO_DMUX_DATA_RMNET_1,
+	SDIO_DMUX_DATA_RMNET_2,
+	SDIO_DMUX_DATA_RMNET_3,
+	SDIO_DMUX_DATA_RMNET_4,
+	SDIO_DMUX_DATA_RMNET_5,
+	SDIO_DMUX_DATA_RMNET_6,
+	SDIO_DMUX_DATA_RMNET_7,
+	SDIO_DMUX_USB_RMNET_0,
+	SDIO_DMUX_NUM_CHANNELS
+};
+
+int msm_sdio_dmux_open(uint32_t id, void *priv,
+		       void (*receive_cb)(void *, struct sk_buff *),
+		       void (*write_done)(void *, struct sk_buff *));
+
+int msm_sdio_is_channel_in_reset(uint32_t id);
+
+int msm_sdio_dmux_close(uint32_t id);
+
+int msm_sdio_dmux_write(uint32_t id, struct sk_buff *skb);
+
+int msm_sdio_dmux_is_ch_full(uint32_t id);
+
+int msm_sdio_dmux_is_ch_low(uint32_t id);
+
+#else
+
+static int __maybe_unused msm_sdio_dmux_open(uint32_t id, void *priv,
+		       void (*receive_cb)(void *, struct sk_buff *),
+		       void (*write_done)(void *, struct sk_buff *))
+{
+	return -ENODEV;
+}
+
+static int __maybe_unused msm_sdio_is_channel_in_reset(uint32_t id)
+{
+	return -ENODEV;
+}
+
+static int __maybe_unused msm_sdio_dmux_close(uint32_t id)
+{
+	return -ENODEV;
+}
+
+static int __maybe_unused msm_sdio_dmux_write(uint32_t id, struct sk_buff *skb)
+{
+	return -ENODEV;
+}
+
+static int __maybe_unused msm_sdio_dmux_is_ch_full(uint32_t id)
+{
+	return -ENODEV;
+}
+
+static int __maybe_unused msm_sdio_dmux_is_ch_low(uint32_t id)
+{
+	return -ENODEV;
+}
+
+#endif
+
+#endif /* _SDIO_DMUX_H */
diff --git a/arch/arm/mach-msm/include/mach/sdio_smem.h b/arch/arm/mach-msm/include/mach/sdio_smem.h
new file mode 100644
index 0000000..b47001f
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/sdio_smem.h
@@ -0,0 +1,32 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __SDIO_SMEM_H
+#define __SDIO_SMEM_H
+
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+#define SDIO_SMEM_EVENT_READ_DONE	0
+#define SDIO_SMEM_EVENT_READ_ERR	1
+
+int sdio_smem_register_client(void);
+int sdio_smem_unregister_client(void);
+
+struct sdio_smem_client {
+	void *buf;
+	int size;
+	struct platform_device plat_dev;
+	int (*cb_func)(int event);
+};
+
+#endif	/* __SDIO_SMEM_H */
diff --git a/arch/arm/mach-msm/include/mach/sirc-fsm9xxx.h b/arch/arm/mach-msm/include/mach/sirc-fsm9xxx.h
new file mode 100644
index 0000000..b862211
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/sirc-fsm9xxx.h
@@ -0,0 +1,84 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_SIRC_FSM9XXX_H
+#define __ASM_ARCH_MSM_SIRC_FSM9XXX_H
+
+/* Group A */
+#define INT_EBI2_WR_ER_DONE           (FIRST_SIRC_IRQ + 0)
+#define INT_EBI2_OP_DONE              (FIRST_SIRC_IRQ + 1)
+#define INT_SDC1_0                    (FIRST_SIRC_IRQ + 2)
+#define INT_SDC1_1                    (FIRST_SIRC_IRQ + 3)
+#define INT_UARTDM                    (FIRST_SIRC_IRQ + 4)
+#define INT_UART1                     (FIRST_SIRC_IRQ + 5)
+/*  RESERVED 6 */
+#define INT_CE                        (FIRST_SIRC_IRQ + 7)
+#define INT_SYS_ENZO_IEQ              (FIRST_SIRC_IRQ + 8)
+#define INT_PERPH_ENZO                (FIRST_SIRC_IRQ + 9)
+#define INT_MXBAR_ENZO                (FIRST_SIRC_IRQ + 10)
+#define INT_AXIAGG_ENZO               (FIRST_SIRC_IRQ + 11)
+#define INT_UART3                     (FIRST_SIRC_IRQ + 12)
+#define INT_UART2                     (FIRST_SIRC_IRQ + 13)
+#define INT_PORT0_SSBI2               (FIRST_SIRC_IRQ + 14)
+#define INT_PORT1_SSBI2               (FIRST_SIRC_IRQ + 15)
+#define INT_PORT2_SSBI2               (FIRST_SIRC_IRQ + 16)
+#define INT_PORT3_SSBI2               (FIRST_SIRC_IRQ + 17)
+#define INT_GSBI_QUP_INBUF            (FIRST_SIRC_IRQ + 18)
+#define INT_GSBI_QUP_OUTBUF           (FIRST_SIRC_IRQ + 19)
+#define INT_GSBI_QUP_ERROR            (FIRST_SIRC_IRQ + 20)
+#define INT_SPB_DECODER               (FIRST_SIRC_IRQ + 21)
+#define INT_FPB_DEC                   (FIRST_SIRC_IRQ + 22)
+#define INT_BPM_HW                    (FIRST_SIRC_IRQ + 23)
+#define INT_GPIO_167                  (FIRST_SIRC_IRQ + 24)
+
+/* Group B */
+#define INT_GPIO_166                  (FIRST_SIRC_IRQ + 25)
+#define INT_GPIO_165                  (FIRST_SIRC_IRQ + 26)
+#define INT_GPIO_164                  (FIRST_SIRC_IRQ + 27)
+#define INT_GPIO_163                  (FIRST_SIRC_IRQ + 28)
+#define INT_GPIO_162                  (FIRST_SIRC_IRQ + 29)
+#define INT_GPIO_161                  (FIRST_SIRC_IRQ + 30)
+#define INT_GPIO_160                  (FIRST_SIRC_IRQ + 31)
+#define INT_GPIO_159                  (FIRST_SIRC_IRQ + 32)
+#define INT_GPIO_158                  (FIRST_SIRC_IRQ + 33)
+#define INT_GPIO_157                  (FIRST_SIRC_IRQ + 34)
+#define INT_GPIO_156                  (FIRST_SIRC_IRQ + 35)
+#define INT_GPIO_155                  (FIRST_SIRC_IRQ + 36)
+#define INT_GPIO_154                  (FIRST_SIRC_IRQ + 37)
+#define INT_GPIO_153                  (FIRST_SIRC_IRQ + 38)
+#define INT_GPIO_152                  (FIRST_SIRC_IRQ + 39)
+#define INT_GPIO_151                  (FIRST_SIRC_IRQ + 40)
+#define INT_GPIO_150                  (FIRST_SIRC_IRQ + 41)
+#define INT_GPIO_149                  (FIRST_SIRC_IRQ + 42)
+#define INT_GPIO_148                  (FIRST_SIRC_IRQ + 43)
+#define INT_GPIO_147                  (FIRST_SIRC_IRQ + 44)
+#define INT_GPIO_146                  (FIRST_SIRC_IRQ + 45)
+#define INT_GPIO_145                  (FIRST_SIRC_IRQ + 46)
+#define INT_GPIO_144                  (FIRST_SIRC_IRQ + 47)
+/* RESERVED 48 */
+
+#define NR_SIRC_IRQS_GROUPA           25
+#define NR_SIRC_IRQS_GROUPB           24
+#define NR_SIRC_IRQS                  49
+#define SIRC_MASK_GROUPA              0x01ffffff
+#define SIRC_MASK_GROUPB              0x00ffffff
+
+#define SPSS_SIRC_INT_CLEAR           (MSM_SIRC_BASE + 0x00)
+#define SPSS_SIRC_INT_POLARITY        (MSM_SIRC_BASE + 0x5C)
+#define SPSS_SIRC_INT_SET             (MSM_SIRC_BASE + 0x18)
+#define SPSS_SIRC_INT_ENABLE          (MSM_SIRC_BASE + 0x20)
+#define SPSS_SIRC_IRQ_STATUS          (MSM_SIRC_BASE + 0x38)
+#define SPSS_SIRC_INT_TYPE            (MSM_SIRC_BASE + 0x30)
+#define SPSS_SIRC_VEC_INDEX_RD        (MSM_SIRC_BASE + 0x48)
+
+#endif /* __ASM_ARCH_MSM_SIRC_FSM9XXX_H */
diff --git a/arch/arm/mach-msm/include/mach/sirc.h b/arch/arm/mach-msm/include/mach/sirc.h
index ef55868..607bab5 100644
--- a/arch/arm/mach-msm/include/mach/sirc.h
+++ b/arch/arm/mach-msm/include/mach/sirc.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -25,13 +25,12 @@
 struct sirc_cascade_regs {
 	void    *int_status;
 	unsigned int    cascade_irq;
+	unsigned int    cascade_fiq;
 };
 
 void msm_init_sirc(void);
-void msm_sirc_enter_sleep(void);
-void msm_sirc_exit_sleep(void);
 
-#if defined(CONFIG_ARCH_MSM_SCORPION)
+#if defined(CONFIG_ARCH_MSM_SCORPION) && !defined(CONFIG_MSM_SMP)
 
 #include <mach/msm_iomap.h>
 
@@ -41,6 +40,10 @@
 
 #define FIRST_SIRC_IRQ (NR_MSM_IRQS + NR_GPIO_IRQS)
 
+#if defined(CONFIG_ARCH_FSM9XXX)
+#include <mach/sirc-fsm9xxx.h>
+#else /* CONFIG_ARCH_FSM9XXX */
+
 #define INT_UART1                     (FIRST_SIRC_IRQ + 0)
 #define INT_UART2                     (FIRST_SIRC_IRQ + 1)
 #define INT_UART3                     (FIRST_SIRC_IRQ + 2)
@@ -78,8 +81,6 @@
 #define SIRC_MASK                     0x007FFFFF
 #endif
 
-#define LAST_SIRC_IRQ                 (FIRST_SIRC_IRQ + NR_SIRC_IRQS - 1)
-
 #define SPSS_SIRC_INT_SELECT          (MSM_SIRC_BASE + 0x00)
 #define SPSS_SIRC_INT_ENABLE          (MSM_SIRC_BASE + 0x04)
 #define SPSS_SIRC_INT_ENABLE_CLEAR    (MSM_SIRC_BASE + 0x08)
@@ -93,6 +94,10 @@
 #define SPSS_SIRC_INT_CLEAR           (MSM_SIRC_BASE + 0x28)
 #define SPSS_SIRC_SOFT_INT            (MSM_SIRC_BASE + 0x2C)
 
-#endif
+#endif /* CONFIG_ARCH_FSM9XXX */
+
+#define LAST_SIRC_IRQ                 (FIRST_SIRC_IRQ + NR_SIRC_IRQS - 1)
+
+#endif /* CONFIG_ARCH_MSM_SCORPION */
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/smem_log.h b/arch/arm/mach-msm/include/mach/smem_log.h
new file mode 100644
index 0000000..a94ae76
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/smem_log.h
@@ -0,0 +1,231 @@
+/* Copyright (c) 2008-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
+ * 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/ioctl.h>
+#include <linux/types.h>
+
+#define SMEM_LOG_BASE 0x30
+
+#define SMIOC_SETMODE _IOW(SMEM_LOG_BASE, 1, int)
+#define SMIOC_SETLOG _IOW(SMEM_LOG_BASE, 2, int)
+
+#define SMIOC_TEXT 0x00000001
+#define SMIOC_BINARY 0x00000002
+#define SMIOC_LOG 0x00000003
+#define SMIOC_STATIC_LOG 0x00000004
+
+/* Event indentifier format:
+ * bit  31-28 is processor ID 8 => apps, 4 => Q6, 0 => modem
+ * bits 27-16 are subsystem id (event base)
+ * bits 15-0  are event id
+ */
+
+#define PROC                            0xF0000000
+#define SUB                             0x0FFF0000
+#define ID                              0x0000FFFF
+
+#define SMEM_LOG_PROC_ID_MODEM          0x00000000
+#define SMEM_LOG_PROC_ID_Q6             0x40000000
+#define SMEM_LOG_PROC_ID_APPS           0x80000000
+#define SMEM_LOG_PROC_ID_WCNSS          0xC0000000
+
+#define SMEM_LOG_CONT                   0x10000000
+
+#define SMEM_LOG_DEBUG_EVENT_BASE       0x00000000
+#define SMEM_LOG_ONCRPC_EVENT_BASE      0x00010000
+#define SMEM_LOG_SMEM_EVENT_BASE        0x00020000
+#define SMEM_LOG_TMC_EVENT_BASE         0x00030000
+#define SMEM_LOG_TIMETICK_EVENT_BASE    0x00040000
+#define SMEM_LOG_DEM_EVENT_BASE         0x00050000
+#define SMEM_LOG_ERROR_EVENT_BASE       0x00060000
+#define SMEM_LOG_DCVS_EVENT_BASE        0x00070000
+#define SMEM_LOG_SLEEP_EVENT_BASE       0x00080000
+#define SMEM_LOG_RPC_ROUTER_EVENT_BASE  0x00090000
+#if defined(CONFIG_MSM_N_WAY_SMSM)
+#define DEM_SMSM_ISR                    (SMEM_LOG_DEM_EVENT_BASE + 0x1)
+#define DEM_STATE_CHANGE                (SMEM_LOG_DEM_EVENT_BASE + 0x2)
+#define DEM_STATE_MACHINE_ENTER         (SMEM_LOG_DEM_EVENT_BASE + 0x3)
+#define DEM_ENTER_SLEEP                 (SMEM_LOG_DEM_EVENT_BASE + 0x4)
+#define DEM_END_SLEEP                   (SMEM_LOG_DEM_EVENT_BASE + 0x5)
+#define DEM_SETUP_SLEEP                 (SMEM_LOG_DEM_EVENT_BASE + 0x6)
+#define DEM_SETUP_POWER_COLLAPSE        (SMEM_LOG_DEM_EVENT_BASE + 0x7)
+#define DEM_SETUP_SUSPEND               (SMEM_LOG_DEM_EVENT_BASE + 0x8)
+#define DEM_EARLY_EXIT                  (SMEM_LOG_DEM_EVENT_BASE + 0x9)
+#define DEM_WAKEUP_REASON               (SMEM_LOG_DEM_EVENT_BASE + 0xA)
+#define DEM_DETECT_WAKEUP               (SMEM_LOG_DEM_EVENT_BASE + 0xB)
+#define DEM_DETECT_RESET                (SMEM_LOG_DEM_EVENT_BASE + 0xC)
+#define DEM_DETECT_SLEEPEXIT            (SMEM_LOG_DEM_EVENT_BASE + 0xD)
+#define DEM_DETECT_RUN                  (SMEM_LOG_DEM_EVENT_BASE + 0xE)
+#define DEM_APPS_SWFI                   (SMEM_LOG_DEM_EVENT_BASE + 0xF)
+#define DEM_SEND_WAKEUP                 (SMEM_LOG_DEM_EVENT_BASE + 0x10)
+#define DEM_ASSERT_OKTS                 (SMEM_LOG_DEM_EVENT_BASE + 0x11)
+#define DEM_NEGATE_OKTS                 (SMEM_LOG_DEM_EVENT_BASE + 0x12)
+#define DEM_PROC_COMM_CMD               (SMEM_LOG_DEM_EVENT_BASE + 0x13)
+#define DEM_REMOVE_PROC_PWR             (SMEM_LOG_DEM_EVENT_BASE + 0x14)
+#define DEM_RESTORE_PROC_PWR            (SMEM_LOG_DEM_EVENT_BASE + 0x15)
+#define DEM_SMI_CLK_DISABLED            (SMEM_LOG_DEM_EVENT_BASE + 0x16)
+#define DEM_SMI_CLK_ENABLED             (SMEM_LOG_DEM_EVENT_BASE + 0x17)
+#define DEM_MAO_INTS                    (SMEM_LOG_DEM_EVENT_BASE + 0x18)
+#define DEM_APPS_WAKEUP_INT             (SMEM_LOG_DEM_EVENT_BASE + 0x19)
+#define DEM_PROC_WAKEUP                 (SMEM_LOG_DEM_EVENT_BASE + 0x1A)
+#define DEM_PROC_POWERUP                (SMEM_LOG_DEM_EVENT_BASE + 0x1B)
+#define DEM_TIMER_EXPIRED               (SMEM_LOG_DEM_EVENT_BASE + 0x1C)
+#define DEM_SEND_BATTERY_INFO           (SMEM_LOG_DEM_EVENT_BASE + 0x1D)
+#define DEM_REMOTE_PWR_CB               (SMEM_LOG_DEM_EVENT_BASE + 0x24)
+#define DEM_TIME_SYNC_START             (SMEM_LOG_DEM_EVENT_BASE + 0x1E)
+#define DEM_TIME_SYNC_SEND_VALUE        (SMEM_LOG_DEM_EVENT_BASE + 0x1F)
+#define DEM_TIME_SYNC_DONE              (SMEM_LOG_DEM_EVENT_BASE + 0x20)
+#define DEM_TIME_SYNC_REQUEST           (SMEM_LOG_DEM_EVENT_BASE + 0x21)
+#define DEM_TIME_SYNC_POLL              (SMEM_LOG_DEM_EVENT_BASE + 0x22)
+#define DEM_TIME_SYNC_INIT              (SMEM_LOG_DEM_EVENT_BASE + 0x23)
+#define DEM_INIT                        (SMEM_LOG_DEM_EVENT_BASE + 0x25)
+#else
+#define DEM_NO_SLEEP                    (SMEM_LOG_DEM_EVENT_BASE + 1)
+#define DEM_INSUF_TIME                  (SMEM_LOG_DEM_EVENT_BASE + 2)
+#define DEMAPPS_ENTER_SLEEP             (SMEM_LOG_DEM_EVENT_BASE + 3)
+#define DEMAPPS_DETECT_WAKEUP           (SMEM_LOG_DEM_EVENT_BASE + 4)
+#define DEMAPPS_END_APPS_TCXO           (SMEM_LOG_DEM_EVENT_BASE + 5)
+#define DEMAPPS_ENTER_SLEEPEXIT         (SMEM_LOG_DEM_EVENT_BASE + 6)
+#define DEMAPPS_END_APPS_SLEEP          (SMEM_LOG_DEM_EVENT_BASE + 7)
+#define DEMAPPS_SETUP_APPS_PWRCLPS      (SMEM_LOG_DEM_EVENT_BASE + 8)
+#define DEMAPPS_PWRCLPS_EARLY_EXIT      (SMEM_LOG_DEM_EVENT_BASE + 9)
+#define DEMMOD_SEND_WAKEUP              (SMEM_LOG_DEM_EVENT_BASE + 0xA)
+#define DEMMOD_NO_APPS_VOTE             (SMEM_LOG_DEM_EVENT_BASE + 0xB)
+#define DEMMOD_NO_TCXO_SLEEP            (SMEM_LOG_DEM_EVENT_BASE + 0xC)
+#define DEMMOD_BT_CLOCK                 (SMEM_LOG_DEM_EVENT_BASE + 0xD)
+#define DEMMOD_UART_CLOCK               (SMEM_LOG_DEM_EVENT_BASE + 0xE)
+#define DEMMOD_OKTS                     (SMEM_LOG_DEM_EVENT_BASE + 0xF)
+#define DEM_SLEEP_INFO                  (SMEM_LOG_DEM_EVENT_BASE + 0x10)
+#define DEMMOD_TCXO_END                 (SMEM_LOG_DEM_EVENT_BASE + 0x11)
+#define DEMMOD_END_SLEEP_SIG            (SMEM_LOG_DEM_EVENT_BASE + 0x12)
+#define DEMMOD_SETUP_APPSSLEEP          (SMEM_LOG_DEM_EVENT_BASE + 0x13)
+#define DEMMOD_ENTER_TCXO               (SMEM_LOG_DEM_EVENT_BASE + 0x14)
+#define DEMMOD_WAKE_APPS                (SMEM_LOG_DEM_EVENT_BASE + 0x15)
+#define DEMMOD_POWER_COLLAPSE_APPS      (SMEM_LOG_DEM_EVENT_BASE + 0x16)
+#define DEMMOD_RESTORE_APPS_PWR         (SMEM_LOG_DEM_EVENT_BASE + 0x17)
+#define DEMAPPS_ASSERT_OKTS             (SMEM_LOG_DEM_EVENT_BASE + 0x18)
+#define DEMAPPS_RESTART_START_TIMER     (SMEM_LOG_DEM_EVENT_BASE + 0x19)
+#define DEMAPPS_ENTER_RUN               (SMEM_LOG_DEM_EVENT_BASE + 0x1A)
+#define DEMMOD_MAO_INTS                 (SMEM_LOG_DEM_EVENT_BASE + 0x1B)
+#define DEMMOD_POWERUP_APPS_CALLED      (SMEM_LOG_DEM_EVENT_BASE + 0x1C)
+#define DEMMOD_PC_TIMER_EXPIRED         (SMEM_LOG_DEM_EVENT_BASE + 0x1D)
+#define DEM_DETECT_SLEEPEXIT            (SMEM_LOG_DEM_EVENT_BASE + 0x1E)
+#define DEM_DETECT_RUN                  (SMEM_LOG_DEM_EVENT_BASE + 0x1F)
+#define DEM_SET_APPS_TIMER              (SMEM_LOG_DEM_EVENT_BASE + 0x20)
+#define DEM_NEGATE_OKTS                 (SMEM_LOG_DEM_EVENT_BASE + 0x21)
+#define DEMMOD_APPS_WAKEUP_INT          (SMEM_LOG_DEM_EVENT_BASE + 0x22)
+#define DEMMOD_APPS_SWFI                (SMEM_LOG_DEM_EVENT_BASE + 0x23)
+#define DEM_SEND_BATTERY_INFO           (SMEM_LOG_DEM_EVENT_BASE + 0x24)
+#define DEM_SMI_CLK_DISABLED            (SMEM_LOG_DEM_EVENT_BASE + 0x25)
+#define DEM_SMI_CLK_ENABLED             (SMEM_LOG_DEM_EVENT_BASE + 0x26)
+#define DEMAPPS_SETUP_APPS_SUSPEND      (SMEM_LOG_DEM_EVENT_BASE + 0x27)
+#define DEM_RPC_EARLY_EXIT              (SMEM_LOG_DEM_EVENT_BASE + 0x28)
+#define DEMAPPS_WAKEUP_REASON           (SMEM_LOG_DEM_EVENT_BASE + 0x29)
+#define DEM_INIT                        (SMEM_LOG_DEM_EVENT_BASE + 0x30)
+#endif
+#define DEMMOD_UMTS_BASE                (SMEM_LOG_DEM_EVENT_BASE + 0x8000)
+#define DEMMOD_GL1_GO_TO_SLEEP          (DEMMOD_UMTS_BASE + 0x0000)
+#define DEMMOD_GL1_SLEEP_START          (DEMMOD_UMTS_BASE + 0x0001)
+#define DEMMOD_GL1_AFTER_GSM_CLK_ON     (DEMMOD_UMTS_BASE + 0x0002)
+#define DEMMOD_GL1_BEFORE_RF_ON         (DEMMOD_UMTS_BASE + 0x0003)
+#define DEMMOD_GL1_AFTER_RF_ON          (DEMMOD_UMTS_BASE + 0x0004)
+#define DEMMOD_GL1_FRAME_TICK           (DEMMOD_UMTS_BASE + 0x0005)
+#define DEMMOD_GL1_WCDMA_START          (DEMMOD_UMTS_BASE + 0x0006)
+#define DEMMOD_GL1_WCDMA_ENDING         (DEMMOD_UMTS_BASE + 0x0007)
+#define DEMMOD_UMTS_NOT_OKTS            (DEMMOD_UMTS_BASE + 0x0008)
+#define DEMMOD_UMTS_START_TCXO_SHUTDOWN (DEMMOD_UMTS_BASE + 0x0009)
+#define DEMMOD_UMTS_END_TCXO_SHUTDOWN   (DEMMOD_UMTS_BASE + 0x000A)
+#define DEMMOD_UMTS_START_ARM_HALT      (DEMMOD_UMTS_BASE + 0x000B)
+#define DEMMOD_UMTS_END_ARM_HALT        (DEMMOD_UMTS_BASE + 0x000C)
+#define DEMMOD_UMTS_NEXT_WAKEUP_SCLK    (DEMMOD_UMTS_BASE + 0x000D)
+#define TIME_REMOTE_LOG_EVENT_START     (SMEM_LOG_TIMETICK_EVENT_BASE + 0)
+#define TIME_REMOTE_LOG_EVENT_GOTO_WAIT (SMEM_LOG_TIMETICK_EVENT_BASE + 1)
+#define TIME_REMOTE_LOG_EVENT_GOTO_INIT (SMEM_LOG_TIMETICK_EVENT_BASE + 2)
+#define ERR_ERROR_FATAL                 (SMEM_LOG_ERROR_EVENT_BASE + 1)
+#define ERR_ERROR_FATAL_TASK            (SMEM_LOG_ERROR_EVENT_BASE + 2)
+#define DCVSAPPS_LOG_IDLE               (SMEM_LOG_DCVS_EVENT_BASE + 0x0)
+#define DCVSAPPS_LOG_ERR                (SMEM_LOG_DCVS_EVENT_BASE + 0x1)
+#define DCVSAPPS_LOG_CHG                (SMEM_LOG_DCVS_EVENT_BASE + 0x2)
+#define DCVSAPPS_LOG_REG                (SMEM_LOG_DCVS_EVENT_BASE + 0x3)
+#define DCVSAPPS_LOG_DEREG              (SMEM_LOG_DCVS_EVENT_BASE + 0x4)
+#define SMEM_LOG_EVENT_CB               (SMEM_LOG_SMEM_EVENT_BASE +  0)
+#define SMEM_LOG_EVENT_START            (SMEM_LOG_SMEM_EVENT_BASE +  1)
+#define SMEM_LOG_EVENT_INIT             (SMEM_LOG_SMEM_EVENT_BASE +  2)
+#define SMEM_LOG_EVENT_RUNNING          (SMEM_LOG_SMEM_EVENT_BASE +  3)
+#define SMEM_LOG_EVENT_STOP             (SMEM_LOG_SMEM_EVENT_BASE +  4)
+#define SMEM_LOG_EVENT_RESTART          (SMEM_LOG_SMEM_EVENT_BASE +  5)
+#define SMEM_LOG_EVENT_SS               (SMEM_LOG_SMEM_EVENT_BASE +  6)
+#define SMEM_LOG_EVENT_READ             (SMEM_LOG_SMEM_EVENT_BASE +  7)
+#define SMEM_LOG_EVENT_WRITE            (SMEM_LOG_SMEM_EVENT_BASE +  8)
+#define SMEM_LOG_EVENT_SIGS1            (SMEM_LOG_SMEM_EVENT_BASE +  9)
+#define SMEM_LOG_EVENT_SIGS2            (SMEM_LOG_SMEM_EVENT_BASE + 10)
+#define SMEM_LOG_EVENT_WRITE_DM         (SMEM_LOG_SMEM_EVENT_BASE + 11)
+#define SMEM_LOG_EVENT_READ_DM          (SMEM_LOG_SMEM_EVENT_BASE + 12)
+#define SMEM_LOG_EVENT_SKIP_DM          (SMEM_LOG_SMEM_EVENT_BASE + 13)
+#define SMEM_LOG_EVENT_STOP_DM          (SMEM_LOG_SMEM_EVENT_BASE + 14)
+#define SMEM_LOG_EVENT_ISR              (SMEM_LOG_SMEM_EVENT_BASE + 15)
+#define SMEM_LOG_EVENT_TASK             (SMEM_LOG_SMEM_EVENT_BASE + 16)
+#define SMEM_LOG_EVENT_RS               (SMEM_LOG_SMEM_EVENT_BASE + 17)
+#define ONCRPC_LOG_EVENT_SMD_WAIT       (SMEM_LOG_ONCRPC_EVENT_BASE +  0)
+#define ONCRPC_LOG_EVENT_RPC_WAIT       (SMEM_LOG_ONCRPC_EVENT_BASE +  1)
+#define ONCRPC_LOG_EVENT_RPC_BOTH_WAIT  (SMEM_LOG_ONCRPC_EVENT_BASE +  2)
+#define ONCRPC_LOG_EVENT_RPC_INIT       (SMEM_LOG_ONCRPC_EVENT_BASE +  3)
+#define ONCRPC_LOG_EVENT_RUNNING        (SMEM_LOG_ONCRPC_EVENT_BASE +  4)
+#define ONCRPC_LOG_EVENT_APIS_INITED    (SMEM_LOG_ONCRPC_EVENT_BASE +  5)
+#define ONCRPC_LOG_EVENT_AMSS_RESET     (SMEM_LOG_ONCRPC_EVENT_BASE +  6)
+#define ONCRPC_LOG_EVENT_SMD_RESET      (SMEM_LOG_ONCRPC_EVENT_BASE +  7)
+#define ONCRPC_LOG_EVENT_ONCRPC_RESET   (SMEM_LOG_ONCRPC_EVENT_BASE +  8)
+#define ONCRPC_LOG_EVENT_CB             (SMEM_LOG_ONCRPC_EVENT_BASE +  9)
+#define ONCRPC_LOG_EVENT_STD_CALL       (SMEM_LOG_ONCRPC_EVENT_BASE + 10)
+#define ONCRPC_LOG_EVENT_STD_REPLY      (SMEM_LOG_ONCRPC_EVENT_BASE + 11)
+#define ONCRPC_LOG_EVENT_STD_CALL_ASYNC (SMEM_LOG_ONCRPC_EVENT_BASE + 12)
+#define NO_SLEEP_OLD                    (SMEM_LOG_SLEEP_EVENT_BASE + 0x1)
+#define INSUF_TIME                      (SMEM_LOG_SLEEP_EVENT_BASE + 0x2)
+#define MOD_UART_CLOCK                  (SMEM_LOG_SLEEP_EVENT_BASE + 0x3)
+#define SLEEP_INFO                      (SMEM_LOG_SLEEP_EVENT_BASE + 0x4)
+#define MOD_TCXO_END                    (SMEM_LOG_SLEEP_EVENT_BASE + 0x5)
+#define MOD_ENTER_TCXO                  (SMEM_LOG_SLEEP_EVENT_BASE + 0x6)
+#define NO_SLEEP_NEW                    (SMEM_LOG_SLEEP_EVENT_BASE + 0x7)
+#define RPC_ROUTER_LOG_EVENT_UNKNOWN    (SMEM_LOG_RPC_ROUTER_EVENT_BASE)
+#define RPC_ROUTER_LOG_EVENT_MSG_READ   (SMEM_LOG_RPC_ROUTER_EVENT_BASE + 1)
+#define RPC_ROUTER_LOG_EVENT_MSG_WRITTEN (SMEM_LOG_RPC_ROUTER_EVENT_BASE + 2)
+#define RPC_ROUTER_LOG_EVENT_MSG_CFM_REQ (SMEM_LOG_RPC_ROUTER_EVENT_BASE + 3)
+#define RPC_ROUTER_LOG_EVENT_MSG_CFM_SNT (SMEM_LOG_RPC_ROUTER_EVENT_BASE + 4)
+#define RPC_ROUTER_LOG_EVENT_MID_READ    (SMEM_LOG_RPC_ROUTER_EVENT_BASE + 5)
+#define RPC_ROUTER_LOG_EVENT_MID_WRITTEN (SMEM_LOG_RPC_ROUTER_EVENT_BASE + 6)
+#define RPC_ROUTER_LOG_EVENT_MID_CFM_REQ (SMEM_LOG_RPC_ROUTER_EVENT_BASE + 7)
+
+#ifdef CONFIG_MSM_SMD_LOGGING
+void smem_log_event(uint32_t id, uint32_t data1, uint32_t data2,
+		    uint32_t data3);
+void smem_log_event6(uint32_t id, uint32_t data1, uint32_t data2,
+		     uint32_t data3, uint32_t data4, uint32_t data5,
+		     uint32_t data6);
+void smem_log_event_to_static(uint32_t id, uint32_t data1, uint32_t data2,
+			      uint32_t data3);
+void smem_log_event6_to_static(uint32_t id, uint32_t data1, uint32_t data2,
+			       uint32_t data3, uint32_t data4, uint32_t data5,
+			       uint32_t data6);
+#else
+void smem_log_event(uint32_t id, uint32_t data1, uint32_t data2,
+		    uint32_t data3) { }
+void smem_log_event6(uint32_t id, uint32_t data1, uint32_t data2,
+		     uint32_t data3, uint32_t data4, uint32_t data5,
+		     uint32_t data6) { }
+void smem_log_event_to_static(uint32_t id, uint32_t data1, uint32_t data2,
+			      uint32_t data3) { }
+void smem_log_event6_to_static(uint32_t id, uint32_t data1, uint32_t data2,
+			       uint32_t data3, uint32_t data4, uint32_t data5,
+			       uint32_t data6) { }
+#endif
+
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
new file mode 100644
index 0000000..c0ad65b
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -0,0 +1,312 @@
+/* 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
+ * 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 _ARCH_ARM_MACH_MSM_SOCINFO_H_
+#define _ARCH_ARM_MACH_MSM_SOCINFO_H_
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/of_fdt.h>
+#include <linux/of.h>
+
+#include <asm/cputype.h>
+#include <asm/mach-types.h>
+/*
+ * SOC version type with major number in the upper 16 bits and minor
+ * number in the lower 16 bits.  For example:
+ *   1.0 -> 0x00010000
+ *   2.3 -> 0x00020003
+ */
+#define SOCINFO_VERSION_MAJOR(ver) ((ver & 0xffff0000) >> 16)
+#define SOCINFO_VERSION_MINOR(ver) (ver & 0x0000ffff)
+
+#ifdef CONFIG_OF
+#define early_machine_is_copper()	\
+	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msmcopper")
+#define machine_is_copper()		\
+	of_machine_is_compatible("qcom,msmcopper")
+#define machine_is_copper_sim()		\
+	of_machine_is_compatible("qcom,msmcopper-sim")
+#define machine_is_copper_rumi()	\
+	of_machine_is_compatible("qcom,msmcopper-rumi")
+#define early_machine_is_msm9625()	\
+	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm9625")
+#define machine_is_msm9625()		\
+	of_machine_is_compatible("qcom,msm9625")
+#else
+#define early_machine_is_copper()	0
+#define machine_is_copper()		0
+#define machine_is_copper_sim()	0
+#define machine_is_copper_rumi()	0
+#define early_machine_is_msm9625()	0
+#define machine_is_msm9625()		0
+#endif
+
+#define PLATFORM_SUBTYPE_SGLTE	6
+
+enum msm_cpu {
+	MSM_CPU_UNKNOWN = 0,
+	MSM_CPU_7X01,
+	MSM_CPU_7X25,
+	MSM_CPU_7X27,
+	MSM_CPU_8X50,
+	MSM_CPU_8X50A,
+	MSM_CPU_7X30,
+	MSM_CPU_8X55,
+	MSM_CPU_8X60,
+	MSM_CPU_8960,
+	MSM_CPU_7X27A,
+	FSM_CPU_9XXX,
+	MSM_CPU_7X25A,
+	MSM_CPU_7X25AA,
+	MSM_CPU_7X25AB,
+	MSM_CPU_8064,
+	MSM_CPU_8930,
+	MSM_CPU_7X27AA,
+	MSM_CPU_9615,
+	MSM_CPU_COPPER,
+	MSM_CPU_8627,
+	MSM_CPU_8625,
+	MSM_CPU_9625
+};
+
+enum msm_cpu socinfo_get_msm_cpu(void);
+uint32_t socinfo_get_id(void);
+uint32_t socinfo_get_version(void);
+uint32_t socinfo_get_raw_id(void);
+char *socinfo_get_build_id(void);
+uint32_t socinfo_get_platform_type(void);
+uint32_t socinfo_get_platform_subtype(void);
+uint32_t socinfo_get_platform_version(void);
+int __init socinfo_init(void) __must_check;
+const int read_msm_cpu_type(void);
+const int get_core_count(void);
+const int cpu_is_krait_v1(void);
+
+static inline int cpu_is_msm7x01(void)
+{
+#ifdef CONFIG_ARCH_MSM7X01A
+	enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+	BUG_ON(cpu == MSM_CPU_UNKNOWN);
+	return cpu == MSM_CPU_7X01;
+#else
+	return 0;
+#endif
+}
+
+static inline int cpu_is_msm7x25(void)
+{
+#ifdef CONFIG_ARCH_MSM7X25
+	enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+	BUG_ON(cpu == MSM_CPU_UNKNOWN);
+	return cpu == MSM_CPU_7X25;
+#else
+	return 0;
+#endif
+}
+
+static inline int cpu_is_msm7x27(void)
+{
+#if defined(CONFIG_ARCH_MSM7X27) && !defined(CONFIG_ARCH_MSM7X27A)
+	enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+	BUG_ON(cpu == MSM_CPU_UNKNOWN);
+	return cpu == MSM_CPU_7X27;
+#else
+	return 0;
+#endif
+}
+
+static inline int cpu_is_msm7x27a(void)
+{
+#ifdef CONFIG_ARCH_MSM7X27A
+	enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+	BUG_ON(cpu == MSM_CPU_UNKNOWN);
+	return cpu == MSM_CPU_7X27A;
+#else
+	return 0;
+#endif
+}
+
+static inline int cpu_is_msm7x27aa(void)
+{
+#ifdef CONFIG_ARCH_MSM7X27A
+	enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+	BUG_ON(cpu == MSM_CPU_UNKNOWN);
+	return cpu == MSM_CPU_7X27AA;
+#else
+	return 0;
+#endif
+}
+
+static inline int cpu_is_msm7x25a(void)
+{
+#ifdef CONFIG_ARCH_MSM7X27A
+	enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+	BUG_ON(cpu == MSM_CPU_UNKNOWN);
+	return cpu == MSM_CPU_7X25A;
+#else
+	return 0;
+#endif
+}
+
+static inline int cpu_is_msm7x25aa(void)
+{
+#ifdef CONFIG_ARCH_MSM7X27A
+	enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+	BUG_ON(cpu == MSM_CPU_UNKNOWN);
+	return cpu == MSM_CPU_7X25AA;
+#else
+	return 0;
+#endif
+}
+
+static inline int cpu_is_msm7x25ab(void)
+{
+#ifdef CONFIG_ARCH_MSM7X27A
+	enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+	BUG_ON(cpu == MSM_CPU_UNKNOWN);
+	return cpu == MSM_CPU_7X25AB;
+#else
+	return 0;
+#endif
+}
+
+static inline int cpu_is_msm7x30(void)
+{
+#ifdef CONFIG_ARCH_MSM7X30
+	enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+	BUG_ON(cpu == MSM_CPU_UNKNOWN);
+	return cpu == MSM_CPU_7X30;
+#else
+	return 0;
+#endif
+}
+
+static inline int cpu_is_qsd8x50(void)
+{
+#ifdef CONFIG_ARCH_QSD8X50
+	enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+	BUG_ON(cpu == MSM_CPU_UNKNOWN);
+	return cpu == MSM_CPU_8X50;
+#else
+	return 0;
+#endif
+}
+
+static inline int cpu_is_msm8x55(void)
+{
+#ifdef CONFIG_ARCH_MSM7X30
+	enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+	BUG_ON(cpu == MSM_CPU_UNKNOWN);
+	return cpu == MSM_CPU_8X55;
+#else
+	return 0;
+#endif
+}
+
+static inline int cpu_is_msm8x60(void)
+{
+#ifdef CONFIG_ARCH_MSM8X60
+	return read_msm_cpu_type() == MSM_CPU_8X60;
+#else
+	return 0;
+#endif
+}
+
+static inline int cpu_is_msm8960(void)
+{
+#ifdef CONFIG_ARCH_MSM8960
+	return read_msm_cpu_type() == MSM_CPU_8960;
+#else
+	return 0;
+#endif
+}
+
+static inline int cpu_is_apq8064(void)
+{
+#ifdef CONFIG_ARCH_APQ8064
+	return read_msm_cpu_type() == MSM_CPU_8064;
+#else
+	return 0;
+#endif
+}
+
+static inline int cpu_is_msm8930(void)
+{
+#ifdef CONFIG_ARCH_MSM8930
+	return (read_msm_cpu_type() == MSM_CPU_8930) ||
+	       (read_msm_cpu_type() == MSM_CPU_8627);
+#else
+	return 0;
+#endif
+}
+
+static inline int cpu_is_msm8627(void)
+{
+/* 8930 and 8627 will share the same CONFIG_ARCH type unless otherwise needed */
+#ifdef CONFIG_ARCH_MSM8930
+	return read_msm_cpu_type() == MSM_CPU_8627;
+#else
+	return 0;
+#endif
+}
+
+static inline int cpu_is_fsm9xxx(void)
+{
+#ifdef CONFIG_ARCH_FSM9XXX
+	enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+	BUG_ON(cpu == MSM_CPU_UNKNOWN);
+	return cpu == FSM_CPU_9XXX;
+#else
+	return 0;
+#endif
+}
+
+static inline int cpu_is_msm9615(void)
+{
+#ifdef CONFIG_ARCH_MSM9615
+	enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+	BUG_ON(cpu == MSM_CPU_UNKNOWN);
+	return cpu == MSM_CPU_9615;
+#else
+	return 0;
+#endif
+}
+
+static inline int cpu_is_msm8625(void)
+{
+#ifdef CONFIG_ARCH_MSM8625
+	enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+	BUG_ON(cpu == MSM_CPU_UNKNOWN);
+	return cpu == MSM_CPU_8625;
+#else
+	return 0;
+#endif
+}
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/sps.h b/arch/arm/mach-msm/include/mach/sps.h
new file mode 100644
index 0000000..319a3ec
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/sps.h
@@ -0,0 +1,1393 @@
+/* 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
+ * 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.
+ */
+
+/* Smart-Peripheral-Switch (SPS) API. */
+
+#ifndef _SPS_H_
+#define _SPS_H_
+
+#include <linux/types.h>	/* u32 */
+
+/* SPS device handle indicating use of system memory */
+#define SPS_DEV_HANDLE_MEM       ((u32)0x7ffffffful)
+
+/* SPS device handle indicating use of BAM-DMA */
+
+/* SPS device handle invalid value */
+#define SPS_DEV_HANDLE_INVALID   ((u32)0)
+
+/* BAM invalid IRQ value */
+#define SPS_IRQ_INVALID          0
+
+/* Invalid address value */
+#define SPS_ADDR_INVALID      0
+
+/* Invalid peripheral device enumeration class */
+#define SPS_CLASS_INVALID     ((u32)-1)
+
+/*
+ * This value specifies different configurations for an SPS connection.
+ * A non-default value instructs the SPS driver to search for the configuration
+ * in the fixed connection mapping table.
+ */
+#define SPS_CONFIG_DEFAULT       0
+
+/*
+ * This value instructs the SPS driver to use the default BAM-DMA channel
+ * threshold
+ */
+#define SPS_DMA_THRESHOLD_DEFAULT   0
+
+/* Flag bits supported by SPS hardware for struct sps_iovec */
+#define SPS_IOVEC_FLAG_INT  0x8000  /* Generate interrupt */
+#define SPS_IOVEC_FLAG_EOT  0x4000  /* Generate end-of-transfer indication */
+#define SPS_IOVEC_FLAG_EOB  0x2000  /* Generate end-of-block indication */
+#define SPS_IOVEC_FLAG_NWD  0x1000  /* notify when done */
+#define SPS_IOVEC_FLAG_CMD  0x0800  /* command descriptor */
+#define SPS_IOVEC_FLAG_LOCK  0x0400  /* pipe lock */
+#define SPS_IOVEC_FLAG_UNLOCK  0x0200  /* pipe unlock */
+#define SPS_IOVEC_FLAG_IMME 0x0100  /* immediate command descriptor */
+#define SPS_IOVEC_FLAG_NO_SUBMIT 0x0002  /* Do not submit descriptor to HW */
+#define SPS_IOVEC_FLAG_DEFAULT   0x0001  /* Use driver default */
+
+/* BAM device options flags */
+
+/*
+ * BAM will be configured and enabled at boot.  Otherwise, BAM will be
+ * configured and enabled when first pipe connect occurs.
+ */
+#define SPS_BAM_OPT_ENABLE_AT_BOOT  1UL
+/* BAM IRQ is disabled */
+#define SPS_BAM_OPT_IRQ_DISABLED    (1UL << 1)
+/* BAM peripheral is a BAM-DMA */
+#define SPS_BAM_OPT_BAMDMA          (1UL << 2)
+/* BAM IRQ is registered for apps wakeup */
+#define SPS_BAM_OPT_IRQ_WAKEUP      (1UL << 3)
+
+/* BAM device management flags */
+
+/* BAM global device control is managed remotely */
+#define SPS_BAM_MGR_DEVICE_REMOTE   1UL
+/* BAM device supports multiple execution environments */
+#define SPS_BAM_MGR_MULTI_EE        (1UL << 1)
+/* BAM pipes are *not* allocated locally */
+#define SPS_BAM_MGR_PIPE_NO_ALLOC   (1UL << 2)
+/* BAM pipes are *not* configured locally */
+#define SPS_BAM_MGR_PIPE_NO_CONFIG  (1UL << 3)
+/* BAM pipes are *not* controlled locally */
+#define SPS_BAM_MGR_PIPE_NO_CTRL    (1UL << 4)
+/* "Globbed" management properties */
+#define SPS_BAM_MGR_NONE            \
+	(SPS_BAM_MGR_DEVICE_REMOTE | SPS_BAM_MGR_PIPE_NO_ALLOC | \
+	 SPS_BAM_MGR_PIPE_NO_CONFIG | SPS_BAM_MGR_PIPE_NO_CTRL)
+#define SPS_BAM_MGR_LOCAL           0
+#define SPS_BAM_MGR_LOCAL_SHARED    SPS_BAM_MGR_MULTI_EE
+#define SPS_BAM_MGR_REMOTE_SHARED   \
+	(SPS_BAM_MGR_DEVICE_REMOTE | SPS_BAM_MGR_MULTI_EE | \
+	 SPS_BAM_MGR_PIPE_NO_ALLOC)
+#define SPS_BAM_MGR_ACCESS_MASK     SPS_BAM_MGR_NONE
+
+/*
+ * BAM security configuration
+ */
+#define SPS_BAM_NUM_EES             4
+#define SPS_BAM_SEC_DO_NOT_CONFIG   0
+#define SPS_BAM_SEC_DO_CONFIG       0x0A434553
+
+/* This enum specifies the operational mode for an SPS connection */
+enum sps_mode {
+	SPS_MODE_SRC = 0,  /* end point is the source (producer) */
+	SPS_MODE_DEST,	   /* end point is the destination (consumer) */
+};
+
+
+/*
+ * This enum is a set of bit flag options for SPS connection.
+ * The enums should be OR'd together to create the option set
+ * for the SPS connection.
+ */
+enum sps_option {
+	/*
+	 * Options to enable specific SPS hardware interrupts.
+	 * These bit flags are also used to indicate interrupt source
+	 * for the SPS_EVENT_IRQ event.
+	 */
+	SPS_O_DESC_DONE = 0x00000001,  /* Descriptor processed */
+	SPS_O_INACTIVE  = 0x00000002,  /* Inactivity timeout */
+	SPS_O_WAKEUP    = 0x00000004,  /* Peripheral wake up */
+	SPS_O_OUT_OF_DESC = 0x00000008,/* Out of descriptors */
+	SPS_O_ERROR     = 0x00000010,  /* Error */
+	SPS_O_EOT       = 0x00000020,  /* End-of-transfer */
+
+	/* Options to enable hardware features */
+	SPS_O_STREAMING = 0x00010000,  /* Enable streaming mode (no EOT) */
+	/* Use MTI/SETPEND instead of BAM interrupt */
+	SPS_O_IRQ_MTI   = 0x00020000,
+	/* NWD bit written with EOT for BAM2BAM producer pipe */
+	SPS_O_WRITE_NWD   = 0x00040000,
+
+	/* Options to enable software features */
+	/* Transfer operation should be polled */
+	SPS_O_POLL      = 0x01000000,
+	/* Disable queuing of transfer events for the connection end point */
+	SPS_O_NO_Q      = 0x02000000,
+	SPS_O_FLOWOFF   = 0x04000000,  /* Graceful halt */
+	/* SPS_O_WAKEUP will be disabled after triggered */
+	SPS_O_WAKEUP_IS_ONESHOT = 0x08000000,
+	/**
+	 * Client must read each descriptor from the FIFO
+	 * using sps_get_iovec()
+	 */
+	SPS_O_ACK_TRANSFERS = 0x10000000,
+	/* Connection is automatically enabled */
+	SPS_O_AUTO_ENABLE = 0x20000000,
+	/* DISABLE endpoint synchronization for config/enable/disable */
+	SPS_O_NO_EP_SYNC = 0x40000000,
+};
+
+/**
+ * This enum specifies BAM DMA channel priority.  Clients should use
+ * SPS_DMA_PRI_DEFAULT unless a specific priority is required.
+ */
+enum sps_dma_priority {
+	SPS_DMA_PRI_DEFAULT = 0,
+	SPS_DMA_PRI_LOW,
+	SPS_DMA_PRI_MED,
+	SPS_DMA_PRI_HIGH,
+};
+
+/*
+ * This enum specifies the ownership of a connection resource.
+ * Remote or shared ownership is only possible/meaningful on the processor
+ * that controls resource.
+ */
+enum sps_owner {
+	SPS_OWNER_LOCAL = 0x1,	/* Resource is owned by local processor */
+	SPS_OWNER_REMOTE = 0x2,	/* Resource is owned by a satellite processor */
+};
+
+/* This enum indicates the event associated with a client event trigger */
+enum sps_event {
+	SPS_EVENT_INVALID = 0,
+
+	SPS_EVENT_EOT,		/* End-of-transfer */
+	SPS_EVENT_DESC_DONE,	/* Descriptor processed */
+	SPS_EVENT_OUT_OF_DESC,	/* Out of descriptors */
+	SPS_EVENT_WAKEUP,	/* Peripheral wake up */
+	SPS_EVENT_FLOWOFF,	/* Graceful halt (idle) */
+	SPS_EVENT_INACTIVE,	/* Inactivity timeout */
+	SPS_EVENT_ERROR,	/* Error */
+	SPS_EVENT_MAX,
+};
+
+/*
+ * This enum specifies the event trigger mode and is an argument for the
+ * sps_register_event() function.
+ */
+enum sps_trigger {
+	/* Trigger with payload for callback */
+	SPS_TRIGGER_CALLBACK = 0,
+	/* Trigger without payload for wait or poll */
+	SPS_TRIGGER_WAIT,
+};
+
+/*
+ * This enum indicates the desired halting mechanism and is an argument for the
+ * sps_flow_off() function
+ */
+enum sps_flow_off {
+	SPS_FLOWOFF_FORCED = 0,	/* Force hardware into halt state */
+	/* Allow hardware to empty pipe before halting */
+	SPS_FLOWOFF_GRACEFUL,
+};
+
+/*
+ * This enum indicates the target memory heap and is an argument for the
+ * sps_mem_alloc() function.
+ */
+enum sps_mem {
+	SPS_MEM_LOCAL = 0,  /* SPS subsystem local (pipe) memory */
+	SPS_MEM_UC,	    /* Microcontroller (ARM7) local memory */
+};
+
+/*
+ * This enum indicates a timer control operation and is an argument for the
+ * sps_timer_ctrl() function.
+ */
+enum sps_timer_op {
+	SPS_TIMER_OP_CONFIG = 0,
+	SPS_TIMER_OP_RESET,
+/*   SPS_TIMER_OP_START,   Not supported by hardware yet */
+/*   SPS_TIMER_OP_STOP,    Not supported by hardware yet */
+	SPS_TIMER_OP_READ,
+};
+
+/*
+ * This enum indicates the inactivity timer operating mode and is an
+ * argument for the sps_timer_ctrl() function.
+ */
+enum sps_timer_mode {
+	SPS_TIMER_MODE_ONESHOT = 0,
+/*   SPS_TIMER_MODE_PERIODIC,    Not supported by hardware yet */
+};
+
+/* This enum indicates the cases when callback the user of BAM */
+enum sps_callback_case {
+	SPS_CALLBACK_BAM_ERROR_IRQ = 1,     /* BAM ERROR IRQ */
+	SPS_CALLBACK_BAM_HRESP_ERR_IRQ,	    /* Erroneous HResponse */
+};
+
+/*
+ * This enum indicates the command type in a command element
+ */
+enum sps_command_type {
+	SPS_WRITE_COMMAND = 0,
+	SPS_READ_COMMAND,
+};
+
+/**
+ * This data type corresponds to the native I/O vector (BAM descriptor)
+ * supported by SPS hardware
+ *
+ * @addr - Buffer physical address.
+ * @size - Buffer size in bytes.
+ * @flags -Flag bitmask (see SPS_IOVEC_FLAG_ #defines).
+ *
+ */
+struct sps_iovec {
+	u32 addr;
+	u32 size:16;
+	u32 flags:16;
+};
+
+/**
+ * This data type corresponds to the native Command Element
+ * supported by SPS hardware
+ *
+ * @addr - register address.
+ * @command - command type.
+ * @data - for write command: content to be written into peripheral register.
+ *         for read command: dest addr to write peripheral register value to.
+ * @mask - register mask.
+ * @reserved - for future usage.
+ *
+ */
+struct sps_command_element {
+	u32 addr:24;
+	u32 command:8;
+	u32 data;
+	u32 mask;
+	u32 reserved;
+};
+
+/*
+ * BAM device's security configuation
+ */
+struct sps_bam_pipe_sec_config_props {
+	u32 pipe_mask;
+	u32 vmid;
+};
+
+struct sps_bam_sec_config_props {
+	/* Per-EE configuration - This is a pipe bit mask for each EE */
+	struct sps_bam_pipe_sec_config_props ees[SPS_BAM_NUM_EES];
+};
+
+/**
+ * This struct defines a BAM device. The client must memset() this struct to
+ * zero before writing device information.  A value of zero for uninitialized
+ * values will instruct the SPS driver to use general defaults or
+ * hardware/BIOS supplied values.
+ *
+ *
+ * @options - See SPS_BAM_OPT_* bit flag.
+ * @phys_addr - BAM base physical address (not peripheral address).
+ * @virt_addr - BAM base virtual address.
+ * @virt_size - For virtual mapping.
+ * @irq - IRQ enum for use in ISR vector install.
+ * @num_pipes - number of pipes. Can be read from hardware.
+ * @summing_threshold - BAM event threshold.
+ *
+ * @periph_class - Peripheral device enumeration class.
+ * @periph_dev_id - Peripheral global device ID.
+ * @periph_phys_addr - Peripheral base physical address, for BAM-DMA only.
+ * @periph_virt_addr - Peripheral base virtual address.
+ * @periph_virt_size - Size for virtual mapping.
+ *
+ * @callback - callback function for BAM user.
+ * @user - pointer to user data.
+ *
+ * @event_threshold - Pipe event threshold.
+ * @desc_size - Size (bytes) of descriptor FIFO.
+ * @data_size - Size (bytes) of data FIFO.
+ * @desc_mem_id - Heap ID for default descriptor FIFO allocations.
+ * @data_mem_id - Heap ID for default data FIFO allocations.
+ *
+ * @manage - BAM device management flags (see SPS_BAM_MGR_*).
+ * @restricted_pipes - Bitmask of pipes restricted from local use.
+ * @ee - Local execution environment index.
+ *
+ * @irq_gen_addr - MTI interrupt generation address. This configuration only
+ * applies to BAM rev 1 and 2 hardware. MTIs are only supported on BAMs when
+ * global config is controlled by a remote processor.
+ * NOTE: This address must correspond to the MTI associated with the "irq" IRQ
+ * enum specified above.
+ *
+ * @sec_config - must be set to SPS_BAM_SEC_DO_CONFIG to perform BAM security
+ * configuration.  Only the processor that manages the BAM is allowed to
+ * perform the configuration. The global (top-level) BAM interrupt will be
+ * assigned to the EE of the processor that manages the BAM.
+ *
+ * @p_sec_config_props - BAM device's security configuation
+ *
+ */
+struct sps_bam_props {
+
+	/* BAM device properties. */
+
+	u32 options;
+	u32 phys_addr;
+	void *virt_addr;
+	u32 virt_size;
+	u32 irq;
+	u32 num_pipes;
+	u32 summing_threshold;
+
+	/* Peripheral device properties */
+
+	u32 periph_class;
+	u32 periph_dev_id;
+	u32 periph_phys_addr;
+	void *periph_virt_addr;
+	u32 periph_virt_size;
+
+	/* Connection pipe parameter defaults. */
+
+	u32 event_threshold;
+	u32 desc_size;
+	u32 data_size;
+	u32 desc_mem_id;
+	u32 data_mem_id;
+
+	/* Feedback to BAM user */
+	void (*callback)(enum sps_callback_case, void *);
+	void *user;
+
+	/* Security properties */
+
+	u32 manage;
+	u32 restricted_pipes;
+	u32 ee;
+
+	/* BAM MTI interrupt generation */
+
+	u32 irq_gen_addr;
+
+	/* Security configuration properties */
+
+	u32 sec_config;
+	struct sps_bam_sec_config_props *p_sec_config_props;
+};
+
+/**
+ *  This struct specifies memory buffer properties.
+ *
+ * @base - Buffer virtual address.
+ * @phys_base - Buffer physical address.
+ * @size - Specifies buffer size (or maximum size).
+ * @min_size - If non-zero, specifies buffer minimum size.
+ *
+ */
+struct sps_mem_buffer {
+	void *base;
+	u32 phys_base;
+	u32 size;
+	u32 min_size;
+};
+
+/**
+ * This struct defines a connection's end point and is used as the argument
+ * for the sps_connect(), sps_get_config(), and sps_set_config() functions.
+ * For system mode pipe, use SPS_DEV_HANDLE_MEM for the end point that
+ * corresponds to system memory.
+ *
+ * The client can force SPS to reserve a specific pipe on a BAM.
+ * If the pipe is in use, the sps_connect/set_config() will fail.
+ *
+ * @source - Source BAM.
+ * @src_pipe_index - BAM pipe index, 0 to 30.
+ * @destination - Destination BAM.
+ * @dest_pipe_index - BAM pipe index, 0 to 30.
+ *
+ * @mode - specifies which end (source or destination) of the connection will
+ * be controlled/referenced by the client.
+ *
+ * @config - This value is for future use and should be set to
+ * SPS_CONFIG_DEFAULT or left as default from sps_get_config().
+ *
+ * @options - OR'd connection end point options (see SPS_O defines).
+ *
+ * WARNING: The memory provided should be physically contiguous and non-cached.
+ * The user can use one of the following:
+ * 1. sps_alloc_mem() - allocated from pipe-memory.
+ * 2. dma_alloc_coherent() - allocate coherent DMA memory.
+ * 3. dma_map_single() - for using memory allocated by kmalloc().
+ *
+ * @desc - Descriptor FIFO.
+ * @data - Data FIFO (BAM-to-BAM mode only).
+ *
+ * @event_thresh - Pipe event threshold or derivative.
+ * @lock_group - The lock group this pipe belongs to.
+ *
+ * @sps_reserved - Reserved word - client must not modify.
+ *
+ */
+struct sps_connect {
+	u32 source;
+	u32 src_pipe_index;
+	u32 destination;
+	u32 dest_pipe_index;
+
+	enum sps_mode mode;
+
+	u32 config;
+
+	enum sps_option options;
+
+	struct sps_mem_buffer desc;
+	struct sps_mem_buffer data;
+
+	u32 event_thresh;
+
+	u32 lock_group;
+
+	/* SETPEND/MTI interrupt generation parameters */
+
+	u32 irq_gen_addr;
+	u32 irq_gen_data;
+
+	u32 sps_reserved;
+
+};
+
+/**
+ * This struct defines a satellite connection's end point.  The client of the
+ * SPS driver on the satellite processor must call sps_get_config() to
+ * initialize a struct sps_connect, then copy the values from the struct
+ * sps_satellite to the struct sps_connect before making the sps_connect()
+ * call to the satellite SPS driver.
+ *
+ */
+struct sps_satellite {
+	/**
+	 * These values must be copied to either the source or destination
+	 * corresponding values in the connect struct.
+	 */
+	u32 dev;
+	u32 pipe_index;
+
+	/**
+	 * These values must be copied to the corresponding values in the
+	 * connect struct
+	 */
+	u32 config;
+	enum sps_option options;
+
+};
+
+/**
+ * This struct defines parameters for allocation of a BAM DMA channel. The
+ * client must memset() this struct to zero before writing allocation
+ * information.  A value of zero for uninitialized values will instruct
+ * the SPS driver to use defaults or "don't care".
+ *
+ * @dev - Associated BAM device handle, or SPS_DEV_HANDLE_DMA.
+ *
+ * @src_owner - Source owner processor ID.
+ * @dest_owner - Destination owner processor ID.
+ *
+ */
+struct sps_alloc_dma_chan {
+	u32 dev;
+
+	/* BAM DMA channel configuration parameters */
+
+	u32 threshold;
+	enum sps_dma_priority priority;
+
+	/**
+	 * Owner IDs are global host processor identifiers used by the system
+	 * SROT when establishing execution environments.
+	 */
+	u32 src_owner;
+	u32 dest_owner;
+
+};
+
+/**
+ * This struct defines parameters for an allocated BAM DMA channel.
+ *
+ * @dev - BAM DMA device handle.
+ * @dest_pipe_index - Destination/input/write pipe index.
+ * @src_pipe_index - Source/output/read pipe index.
+ *
+ */
+struct sps_dma_chan {
+	u32 dev;
+	u32 dest_pipe_index;
+	u32 src_pipe_index;
+};
+
+/**
+ * This struct is an argument passed payload when triggering a callback event
+ * object registered for an SPS connection end point.
+ *
+ * @user - Pointer registered with sps_register_event().
+ *
+ * @event_id - Which event.
+ *
+ * @iovec - The associated I/O vector. If the end point is a system-mode
+ * producer, the size will reflect the actual number of bytes written to the
+ * buffer by the pipe. NOTE: If this I/O vector was part of a set submitted to
+ * sps_transfer(), then the vector array itself will be	updated with all of
+ * the actual counts.
+ *
+ * @user - Pointer registered with the transfer.
+ *
+ */
+struct sps_event_notify {
+	void *user;
+
+	enum sps_event event_id;
+
+	/* Data associated with the event */
+
+	union {
+		/* Data for SPS_EVENT_IRQ */
+		struct {
+			u32 mask;
+		} irq;
+
+		/* Data for SPS_EVENT_EOT or SPS_EVENT_DESC_DONE */
+
+		struct {
+			struct sps_iovec iovec;
+			void *user;
+		} transfer;
+
+		/* Data for SPS_EVENT_ERROR */
+
+		struct {
+			u32 status;
+		} err;
+
+	} data;
+};
+
+/**
+ * This struct defines a event registration parameters and is used as the
+ * argument for the sps_register_event() function.
+ *
+ * @options - Event options that will trigger the event object.
+ * @mode - Event trigger mode.
+ *
+ * @xfer_done - a pointer to a completion object. NULL if not in use.
+ *
+ * @callback - a callback to call on completion. NULL if not in use.
+ *
+ * @user - User pointer that will be provided in event callback data.
+ *
+ */
+struct sps_register_event {
+	enum sps_option options;
+	enum sps_trigger mode;
+	struct completion *xfer_done;
+	void (*callback)(struct sps_event_notify *notify);
+	void *user;
+};
+
+/**
+ * This struct defines a system memory transfer's parameters and is used as the
+ * argument for the sps_transfer() function.
+ *
+ * @iovec_phys - Physical address of I/O vectors buffer.
+ * @iovec - Pointer to I/O vectors buffer.
+ * @iovec_count - Number of I/O vectors.
+ * @user - User pointer passed in callback event.
+ *
+ */
+struct sps_transfer {
+	u32 iovec_phys;
+	struct sps_iovec *iovec;
+	u32 iovec_count;
+	void *user;
+};
+
+/**
+ * This struct defines a timer control operation parameters and is used as an
+ * argument for the sps_timer_ctrl() function.
+ *
+ * @op - Timer control operation.
+ * @timeout_msec - Inactivity timeout (msec).
+ *
+ */
+struct sps_timer_ctrl {
+	enum sps_timer_op op;
+
+	/**
+	 * The following configuration parameters must be set when the timer
+	 * control operation is SPS_TIMER_OP_CONFIG.
+	 */
+	enum sps_timer_mode mode;
+	u32 timeout_msec;
+};
+
+/**
+ * This struct defines a timer control operation result and is used as an
+ * argument for the sps_timer_ctrl() function.
+ */
+struct sps_timer_result {
+	u32 current_timer;
+};
+
+
+/*----------------------------------------------------------------------------
+ * Functions specific to sps interface
+ * -------------------------------------------------------------------------*/
+struct sps_pipe;	/* Forward declaration */
+
+#ifdef CONFIG_SPS
+/**
+ * Register a BAM device
+ *
+ * This function registers a BAM device with the SPS driver. For each
+ *peripheral that includes a BAM, the peripheral driver must register
+ * the BAM with the SPS driver.
+ *
+ * A requirement is that the peripheral driver must remain attached
+ * to the SPS driver until the BAM is deregistered. Otherwise, the
+ * system may attempt to unload the SPS driver. BAM registrations would
+ * be lost.
+ *
+ * @bam_props - Pointer to struct for BAM device properties.
+ *
+ * @dev_handle - Device handle will be written to this location (output).
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_register_bam_device(const struct sps_bam_props *bam_props,
+			    u32 *dev_handle);
+
+/**
+ * Deregister a BAM device
+ *
+ * This function deregisters a BAM device from the SPS driver. The peripheral
+ * driver should deregister a BAM when the peripheral driver is shut down or
+ * when BAM use should be disabled.
+ *
+ * A BAM cannot be deregistered if any of its pipes is in an active connection.
+ *
+ * When all BAMs have been deregistered, the system is free to unload the
+ * SPS driver.
+ *
+ * @dev_handle - BAM device handle.
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_deregister_bam_device(u32 dev_handle);
+
+/**
+ * Allocate client state context
+ *
+ * This function allocate and initializes a client state context struct.
+ *
+ * @return pointer to client state context
+ *
+ */
+struct sps_pipe *sps_alloc_endpoint(void);
+
+/**
+ * Free client state context
+ *
+ * This function de-initializes and free a client state context struct.
+ *
+ * @ctx - client context for SPS connection end point
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_free_endpoint(struct sps_pipe *h);
+
+/**
+ * Get the configuration parameters for an SPS connection end point
+ *
+ * This function retrieves the configuration parameters for an SPS connection
+ * end point.
+ * This function may be called before the end point is connected (before
+ * sps_connect is called). This allows the client to specify parameters before
+ * the connection is established.
+ *
+ * The client must call this function to fill it's struct sps_connect
+ * struct before modifying values and passing the struct to sps_set_config().
+ *
+ * @h - client context for SPS connection end point
+ *
+ * @config - Pointer to buffer for the end point's configuration parameters.
+ * Must not be NULL.
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_get_config(struct sps_pipe *h, struct sps_connect *config);
+
+/**
+ * Allocate memory from the SPS Pipe-Memory.
+ *
+ * @h - client context for SPS connection end point
+ *
+ * @mem - memory type - N/A.
+ *
+ * @mem_buffer - Pointer to struct for allocated memory properties.
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_alloc_mem(struct sps_pipe *h, enum sps_mem mem,
+		  struct sps_mem_buffer *mem_buffer);
+
+/**
+ * Free memory from the SPS Pipe-Memory.
+ *
+ * @h - client context for SPS connection end point
+ *
+ * @mem_buffer - Pointer to struct for allocated memory properties.
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_free_mem(struct sps_pipe *h, struct sps_mem_buffer *mem_buffer);
+
+/**
+ * Connect an SPS connection end point
+ *
+ * This function creates a connection between two SPS peripherals or between
+ * an SPS peripheral and the local host processor (via system memory, end
+ *point SPS_DEV_HANDLE_MEM). Establishing the connection includes
+ * initialization of the SPS hardware and allocation of any other connection
+ * resources (buffer memory, etc.).
+ *
+ * This function requires the client to specify both the source and
+ * destination end points of the SPS connection. However, the handle
+ * returned applies only to the end point of the connection that the client
+ * controls. The end point under control must be specified by the
+ * enum sps_mode mode argument, either SPS_MODE_SRC, SPS_MODE_DEST, or
+ * SPS_MODE_CTL. Note that SPS_MODE_CTL is only supported for I/O
+ * accelerator connections, and only a limited set of control operations are
+ * allowed (TBD).
+ *
+ * For a connection involving system memory
+ * (SPS_DEV_HANDLE_MEM), the peripheral end point must be
+ * specified. For example, SPS_MODE_SRC must be specified for a
+ * BAM-to-system connection, since the BAM pipe is the data
+ * producer.
+ *
+ * For a specific peripheral-to-peripheral connection, there may be more than
+ * one required configuration. For example, there might be high-performance
+ * and low-power configurations for a connection between the two peripherals.
+ * The config argument allows the client to specify different configurations,
+ * which may require different system resource allocations and hardware
+ * initialization.
+ *
+ * A client is allowed to create one and only one connection for its
+ * struct sps_pipe. The handle is used to identify the connection end point
+ * in subsequent SPS driver calls. A specific connection source or
+ * destination end point can be associated with one and only one
+ * struct sps_pipe.
+ *
+ * The client must establish an open device handle to the SPS. To do so, the
+ * client must attach to the SPS driver and open the SPS device by calling
+ * the following functions.
+ *
+ * @h - client context for SPS connection end point
+ *
+ * @connect - Pointer to connection parameters
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_connect(struct sps_pipe *h, struct sps_connect *connect);
+
+/**
+ * Disconnect an SPS connection end point
+ *
+ * This function disconnects an SPS connection end point.
+ * The SPS hardware associated with that end point will be disabled.
+ * For a connection involving system memory (SPS_DEV_HANDLE_MEM), all
+ * connection resources are deallocated. For a peripheral-to-peripheral
+ * connection, the resources associated with the connection will not be
+ * deallocated until both end points are closed.
+ *
+ * The client must call sps_connect() for the handle before calling
+ * this function.
+ *
+ * @h - client context for SPS connection end point
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_disconnect(struct sps_pipe *h);
+
+/**
+ * Register an event object for an SPS connection end point
+ *
+ * This function registers a callback event object for an SPS connection end
+ *point. The registered event object will be triggered for the set of
+ * events specified in reg->options that are enabled for the end point.
+ *
+ * There can only be one registered event object for each event. If an event
+ * object is already registered for an event, it will be replaced. If
+ *reg->event handle is NULL, then any registered event object for the
+ * event will be deregistered. Option bits in reg->options not associated
+ * with events are ignored.
+ *
+ * The client must call sps_connect() for the handle before calling
+ * this function.
+ *
+ * @h - client context for SPS connection end point
+ *
+ * @reg - Pointer to event registration parameters
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_register_event(struct sps_pipe *h, struct sps_register_event *reg);
+
+/**
+ * Perform a single DMA transfer on an SPS connection end point
+ *
+ * This function submits a DMA transfer request consisting of a single buffer
+ * for an SPS connection end point associated with a peripheral-to/from-memory
+ * connection. The request will be submitted immediately to hardware if the
+ * hardware is idle (data flow off, no other pending transfers). Otherwise, it
+ * will be queued for later handling in the SPS driver work loop.
+ *
+ * The data buffer must be DMA ready. The client is responsible for insuring
+ *physically contiguous memory, cache maintenance, and memory barrier. For
+ * more information, see Appendix A.
+ *
+ * The client must not modify the data buffer until the completion indication is
+ * received.
+ *
+ * This function cannot be used if transfer queuing is disabled (see option
+ * SPS_O_NO_Q). The client must set the SPS_O_EOT option to receive a callback
+ * event trigger when the transfer is complete. The SPS driver will insure the
+ * appropriate flags in the I/O vectors are set to generate the completion
+ * indication.
+ *
+ * The return value from this function may indicate that an error occurred.
+ * Possible causes include invalid arguments.
+ *
+ * @h - client context for SPS connection end point
+ *
+ * @addr - Physical address of buffer to transfer.
+ *
+ * WARNING: The memory provided	should be physically contiguous and
+ * non-cached.
+ *
+ * The user can use one of the following:
+ * 1. sps_alloc_mem() - allocated from pipe-memory.
+ * 2. dma_alloc_coherent() - allocate DMA memory.
+ * 3. dma_map_single() for memory allocated by kmalloc().
+ *
+ * @size - Size in bytes of buffer to transfer
+ *
+ * @user - User pointer that will be returned to user as part of
+ *  event payload
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_transfer_one(struct sps_pipe *h, u32 addr, u32 size,
+		     void *user, u32 flags);
+
+/**
+ * Read event queue for an SPS connection end point
+ *
+ * This function reads event queue for an SPS connection end point.
+ *
+ * @h - client context for SPS connection end point
+ *
+ * @event - pointer to client's event data buffer
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_get_event(struct sps_pipe *h, struct sps_event_notify *event);
+
+/**
+ * Get processed I/O vector (completed transfers)
+ *
+ * This function fetches the next processed I/O vector.
+ *
+ * @h - client context for SPS connection end point
+ *
+ * @iovec - Pointer to I/O vector struct (output).
+ * This struct will be zeroed if there are no more processed I/O vectors.
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_get_iovec(struct sps_pipe *h, struct sps_iovec *iovec);
+
+/**
+ * Enable an SPS connection end point
+ *
+ * This function enables an SPS connection end point.
+ *
+ * @h - client context for SPS connection end point
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_flow_on(struct sps_pipe *h);
+
+/**
+ * Disable an SPS connection end point
+ *
+ * This function disables an SPS connection end point.
+ *
+ * @h - client context for SPS connection end point
+ *
+ * @mode - Desired mode for disabling pipe data flow
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_flow_off(struct sps_pipe *h, enum sps_flow_off mode);
+
+/**
+ * Perform a Multiple DMA transfer on an SPS connection end point
+ *
+ * This function submits a DMA transfer request for an SPS connection end point
+ * associated with a peripheral-to/from-memory connection. The request will be
+ * submitted immediately to hardware if the hardware is idle (data flow off, no
+ * other pending transfers). Otherwise, it will be queued for later handling in
+ * the SPS driver work loop.
+ *
+ * The data buffers referenced by the I/O vectors must be DMA ready.
+ * The client is responsible for insuring physically contiguous memory,
+ * any cache maintenance, and memory barrier. For more information,
+ * see Appendix A.
+ *
+ * The I/O vectors must specify physical addresses for the referenced buffers.
+ *
+ * The client must not modify the data buffers referenced by I/O vectors until
+ * the completion indication is received.
+ *
+ * If transfer queuing is disabled (see option SPS_O_NO_Q), the client is
+ * responsible for setting the appropriate flags in the I/O vectors to generate
+ * the completion indication. Also, the client is responsible for enabling the
+ * appropriate connection callback event options for completion indication (see
+ * sps_connect(), sps_set_config()).
+ *
+ * If transfer queuing is enabled, the client must set the SPS_O_EOT option to
+ * receive a callback event trigger when the transfer is complete. The SPS
+ * driver will insure the appropriate flags in the I/O vectors are set to
+ * generate the completion indication. The client must not set any flags in the
+ * I/O vectors, as this may cause the SPS driver to become out of sync with the
+ * hardware.
+ *
+ * The return value from this function may indicate that an error occurred.
+ * Possible causes include invalid arguments. If transfer queuing is disabled,
+ * an error will occur if the pipe is already processing a transfer.
+ *
+ * @h - client context for SPS connection end point
+ *
+ * @transfer - Pointer to transfer parameter struct
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_transfer(struct sps_pipe *h, struct sps_transfer *transfer);
+
+/**
+ * Determine whether an SPS connection end point FIFO is empty
+ *
+ * This function returns the empty state of an SPS connection end point.
+ *
+ * @h - client context for SPS connection end point
+ *
+ * @empty - pointer to client's empty status word (boolean)
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_is_pipe_empty(struct sps_pipe *h, u32 *empty);
+
+/**
+ * Reset an SPS BAM device
+ *
+ * This function resets an SPS BAM device.
+ *
+ * @dev - device handle for the BAM
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_device_reset(u32 dev);
+
+/**
+ * Set the configuration parameters for an SPS connection end point
+ *
+ * This function sets the configuration parameters for an SPS connection
+ * end point. This function may be called before the end point is connected
+ * (before sps_connect is called). This allows the client to specify
+ *parameters before the connection is established. The client is allowed
+ * to pre-allocate resources and override driver defaults.
+ *
+ * The client must call sps_get_config() to fill it's struct sps_connect
+ * struct before modifying values and passing the struct to this function.
+ * Only those parameters that differ from the current configuration will
+ * be processed.
+ *
+ * @h - client context for SPS connection end point
+ *
+ * @config - Pointer to the end point's new configuration parameters.
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_set_config(struct sps_pipe *h, struct sps_connect *config);
+
+/**
+ * Set ownership of an SPS connection end point
+ *
+ * This function sets the ownership of an SPS connection end point to
+ * either local (default) or non-local. This function is used to
+ * retrieve the struct sps_connect data that must be used by a
+ * satellite processor when calling sps_connect().
+ *
+ * Non-local ownership is only possible/meaningful on the processor
+ * that controls resource allocations (apps processor). Setting ownership
+ * to non-local on a satellite processor will fail.
+ *
+ * Setting ownership from non-local to local will succeed only if the
+ * owning satellite processor has properly brought the end point to
+ * an idle condition.
+ *
+ * This function will succeed if the connection end point is already in
+ * the specified ownership state.
+ *
+ * @h - client context for SPS connection end point
+ *
+ * @owner - New ownership of the connection end point
+ *
+ * @connect - Pointer to buffer for satellite processor connect data.
+ *  Can be NULL to avoid retrieving the connect data. Will be ignored
+ *  if the end point ownership is set to local.
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_set_owner(struct sps_pipe *h, enum sps_owner owner,
+		  struct sps_satellite *connect);
+
+/**
+ * Allocate a BAM DMA channel
+ *
+ * This function allocates a BAM DMA channel. A "BAM DMA" is a special
+ * DMA peripheral with a BAM front end. The DMA peripheral acts as a conduit
+ * for data to flow into a consumer pipe and then out of a producer pipe.
+ * It's primarily purpose is to serve as a path for interprocessor communication
+ * that allows each processor to control and protect it's own memory space.
+ *
+ * @alloc - Pointer to struct for BAM DMA channel allocation properties.
+ *
+ * @chan - Allocated channel information will be written to this
+ *  location (output).
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_alloc_dma_chan(const struct sps_alloc_dma_chan *alloc,
+		       struct sps_dma_chan *chan);
+
+/**
+ * Free a BAM DMA channel
+ *
+ * This function frees a BAM DMA channel.
+ *
+ * @chan - Pointer to information for channel to free
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_free_dma_chan(struct sps_dma_chan *chan);
+
+/**
+ * Get the BAM handle for BAM-DMA.
+ *
+ * The BAM handle should be use as source/destination in the sps_connect().
+ *
+ * @return handle on success, zero on error
+ *
+ */
+u32 sps_dma_get_bam_handle(void);
+
+/**
+ * Free the BAM handle for BAM-DMA.
+ *
+ */
+void sps_dma_free_bam_handle(u32 h);
+
+
+/**
+ * Get number of free transfer entries for an SPS connection end point
+ *
+ * This function returns the number of free transfer entries for an
+ * SPS connection end point.
+ *
+ * @h - client context for SPS connection end point
+ *
+ * @count - pointer to count status
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_get_free_count(struct sps_pipe *h, u32 *count);
+
+/**
+ * Perform timer control
+ *
+ * This function performs timer control operations.
+ *
+ * @h - client context for SPS connection end point
+ *
+ * @timer_ctrl - Pointer to timer control specification
+ *
+ * @timer_result - Pointer to buffer for timer operation result.
+ *  This argument can be NULL if no result is expected for the operation.
+ *  If non-NULL, the current timer value will always provided.
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_timer_ctrl(struct sps_pipe *h,
+		   struct sps_timer_ctrl *timer_ctrl,
+		   struct sps_timer_result *timer_result);
+
+/**
+ * Find the handle of a BAM device based on the physical address
+ *
+ * This function finds a BAM device in the BAM registration list that
+ * matches the specified physical address, and returns its handle.
+ *
+ * @phys_addr - physical address of the BAM
+ *
+ * @h - device handle of the BAM
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_phy2h(u32 phys_addr, u32 *handle);
+
+/**
+ * Setup desc/data FIFO for bam-to-bam connection
+ *
+ * @mem_buffer - Pointer to struct for allocated memory properties.
+ *
+ * @addr - address of FIFO
+ *
+ * @size - FIFO size
+ *
+ * @use_offset - use address offset instead of absolute address
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_setup_bam2bam_fifo(struct sps_mem_buffer *mem_buffer,
+		  u32 addr, u32 size, int use_offset);
+
+/**
+ * Get the number of unused descriptors in the descriptor FIFO
+ * of a pipe
+ *
+ * @h - client context for SPS connection end point
+ *
+ * @desc_num - number of unused descriptors
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_get_unused_desc_num(struct sps_pipe *h, u32 *desc_num);
+
+#else
+static inline int sps_register_bam_device(const struct sps_bam_props
+			*bam_props, u32 *dev_handle)
+{
+	return -EPERM;
+}
+
+static inline int sps_deregister_bam_device(u32 dev_handle)
+{
+	return -EPERM;
+}
+
+static inline struct sps_pipe *sps_alloc_endpoint(void)
+{
+	return NULL;
+}
+
+static inline int sps_free_endpoint(struct sps_pipe *h)
+{
+	return -EPERM;
+}
+
+static inline int sps_get_config(struct sps_pipe *h, struct sps_connect *config)
+{
+	return -EPERM;
+}
+
+static inline int sps_alloc_mem(struct sps_pipe *h, enum sps_mem mem,
+		  struct sps_mem_buffer *mem_buffer)
+{
+	return -EPERM;
+}
+
+static inline int sps_free_mem(struct sps_pipe *h,
+				struct sps_mem_buffer *mem_buffer)
+{
+	return -EPERM;
+}
+
+static inline int sps_connect(struct sps_pipe *h, struct sps_connect *connect)
+{
+	return -EPERM;
+}
+
+static inline int sps_disconnect(struct sps_pipe *h)
+{
+	return -EPERM;
+}
+
+static inline int sps_register_event(struct sps_pipe *h,
+					struct sps_register_event *reg)
+{
+	return -EPERM;
+}
+
+static inline int sps_transfer_one(struct sps_pipe *h, u32 addr, u32 size,
+		     void *user, u32 flags)
+{
+	return -EPERM;
+}
+
+static inline int sps_get_event(struct sps_pipe *h,
+				struct sps_event_notify *event)
+{
+	return -EPERM;
+}
+
+static inline int sps_get_iovec(struct sps_pipe *h, struct sps_iovec *iovec)
+{
+	return -EPERM;
+}
+
+static inline int sps_flow_on(struct sps_pipe *h)
+{
+	return -EPERM;
+}
+
+static inline int sps_flow_off(struct sps_pipe *h, enum sps_flow_off mode)
+{
+	return -EPERM;
+}
+
+static inline int sps_transfer(struct sps_pipe *h,
+				struct sps_transfer *transfer)
+{
+	return -EPERM;
+}
+
+static inline int sps_is_pipe_empty(struct sps_pipe *h, u32 *empty)
+{
+	return -EPERM;
+}
+
+static inline int sps_device_reset(u32 dev)
+{
+	return -EPERM;
+}
+
+static inline int sps_set_config(struct sps_pipe *h, struct sps_connect *config)
+{
+	return -EPERM;
+}
+
+static inline int sps_set_owner(struct sps_pipe *h, enum sps_owner owner,
+		  struct sps_satellite *connect)
+{
+	return -EPERM;
+}
+
+static inline int sps_get_free_count(struct sps_pipe *h, u32 *count)
+{
+	return -EPERM;
+}
+
+static inline int sps_alloc_dma_chan(const struct sps_alloc_dma_chan *alloc,
+		       struct sps_dma_chan *chan)
+{
+	return -EPERM;
+}
+
+static inline int sps_free_dma_chan(struct sps_dma_chan *chan)
+{
+	return -EPERM;
+}
+
+static inline u32 sps_dma_get_bam_handle(void)
+{
+	return 0;
+}
+
+static inline void sps_dma_free_bam_handle(u32 h)
+{
+}
+
+static inline int sps_timer_ctrl(struct sps_pipe *h,
+		   struct sps_timer_ctrl *timer_ctrl,
+		   struct sps_timer_result *timer_result)
+{
+	return -EPERM;
+}
+
+static inline int sps_phy2h(u32 phys_addr, u32 *handle)
+{
+	return -EPERM;
+}
+
+static inline int sps_setup_bam2bam_fifo(struct sps_mem_buffer *mem_buffer,
+		  u32 addr, u32 size, int use_offset)
+{
+	return -EPERM;
+}
+
+static inline int sps_get_unused_desc_num(struct sps_pipe *h, u32 *desc_num)
+{
+	return -EPERM;
+}
+#endif
+
+#endif /* _SPS_H_ */
diff --git a/arch/arm/mach-msm/include/mach/subsystem_notif.h b/arch/arm/mach-msm/include/mach/subsystem_notif.h
new file mode 100644
index 0000000..37d4eec
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/subsystem_notif.h
@@ -0,0 +1,80 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * Subsystem restart notifier API header
+ *
+ */
+
+#ifndef _SUBSYS_NOTIFIER_H
+#define _SUBSYS_NOTIFIER_H
+
+#include <linux/notifier.h>
+
+enum subsys_notif_type {
+	SUBSYS_BEFORE_SHUTDOWN,
+	SUBSYS_AFTER_SHUTDOWN,
+	SUBSYS_BEFORE_POWERUP,
+	SUBSYS_AFTER_POWERUP,
+	SUBSYS_NOTIF_TYPE_COUNT
+};
+
+#if defined(CONFIG_MSM_SUBSYSTEM_RESTART)
+/* Use the subsys_notif_register_notifier API to register for notifications for
+ * a particular subsystem. This API will return a handle that can be used to
+ * un-reg for notifications using the subsys_notif_unregister_notifier API by
+ * passing in that handle as an argument.
+ *
+ * On receiving a notification, the second (unsigned long) argument of the
+ * notifier callback will contain the notification type, and the third (void *)
+ * argument will contain the handle that was returned by
+ * subsys_notif_register_notifier.
+ */
+void *subsys_notif_register_notifier(
+			const char *subsys_name, struct notifier_block *nb);
+int subsys_notif_unregister_notifier(void *subsys_handle,
+				struct notifier_block *nb);
+
+/* Use the subsys_notif_init_subsys API to initialize the notifier chains form
+ * a particular subsystem. This API will return a handle that can be used to
+ * queue notifications using the subsys_notif_queue_notification API by passing
+ * in that handle as an argument.
+ */
+void *subsys_notif_add_subsys(const char *);
+int subsys_notif_queue_notification(void *subsys_handle,
+					enum subsys_notif_type notif_type);
+#else
+
+static inline void *subsys_notif_register_notifier(
+			const char *subsys_name, struct notifier_block *nb)
+{
+	return NULL;
+}
+
+static inline int subsys_notif_unregister_notifier(void *subsys_handle,
+					struct notifier_block *nb)
+{
+	return 0;
+}
+
+static inline void *subsys_notif_add_subsys(const char *subsys_name)
+{
+	return NULL;
+}
+
+static inline int subsys_notif_queue_notification(void *subsys_handle,
+					enum subsys_notif_type notif_type)
+{
+	return 0;
+}
+#endif /* CONFIG_MSM_SUBSYSTEM_RESTART */
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/subsystem_restart.h b/arch/arm/mach-msm/include/mach/subsystem_restart.h
new file mode 100644
index 0000000..51ace96
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/subsystem_restart.h
@@ -0,0 +1,71 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __SUBSYS_RESTART_H
+#define __SUBSYS_RESTART_H
+
+#include <linux/spinlock.h>
+
+#define SUBSYS_NAME_MAX_LENGTH 40
+
+enum {
+	RESET_SOC = 1,
+	RESET_SUBSYS_COUPLED,
+	RESET_SUBSYS_INDEPENDENT,
+	RESET_LEVEL_MAX
+};
+
+struct subsys_data {
+	const char *name;
+	int (*shutdown) (const struct subsys_data *);
+	int (*powerup) (const struct subsys_data *);
+	void (*crash_shutdown) (const struct subsys_data *);
+	int (*ramdump) (int, const struct subsys_data *);
+
+	/* Internal use only */
+	struct list_head list;
+	void *notif_handle;
+
+	struct mutex shutdown_lock;
+	struct mutex powerup_lock;
+
+	void *restart_order;
+	struct subsys_data *single_restart_list[1];
+};
+
+#if defined(CONFIG_MSM_SUBSYSTEM_RESTART)
+
+int get_restart_level(void);
+int subsystem_restart(const char *subsys_name);
+int ssr_register_subsystem(struct subsys_data *subsys);
+
+#else
+
+static inline int get_restart_level(void)
+{
+	return 0;
+}
+
+static inline int subsystem_restart(const char *subsystem_name)
+{
+	return 0;
+}
+
+static inline int ssr_register_subsystem(struct subsys_data *subsys)
+{
+	return 0;
+}
+
+#endif /* CONFIG_MSM_SUBSYSTEM_RESTART */
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/system.h b/arch/arm/mach-msm/include/mach/system.h
index f5fb2ec..490c17d 100644
--- a/arch/arm/mach-msm/include/mach/system.h
+++ b/arch/arm/mach-msm/include/mach/system.h
@@ -17,3 +17,6 @@
  * PSHOLD line on the PMIC to hard reset the system
  */
 extern void (*msm_hw_reset_hook)(void);
+
+void msm_set_i2c_mux(bool gpio, int *gpio_clk, int *gpio_dat);
+
diff --git a/arch/arm/mach-msm/include/mach/timex.h b/arch/arm/mach-msm/include/mach/timex.h
index a62e6b2..542aba3 100644
--- a/arch/arm/mach-msm/include/mach/timex.h
+++ b/arch/arm/mach-msm/include/mach/timex.h
@@ -18,4 +18,8 @@
 
 #define CLOCK_TICK_RATE		1000000
 
+#ifdef CONFIG_HAVE_ARCH_HAS_CURRENT_TIMER
+#define ARCH_HAS_READ_CURRENT_TIMER
+#endif
+
 #endif
diff --git a/arch/arm/mach-msm/include/mach/tpm_st_i2c.h b/arch/arm/mach-msm/include/mach/tpm_st_i2c.h
new file mode 100644
index 0000000..362acbb
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/tpm_st_i2c.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2010, 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 _TPM_ST_I2C_H_
+#define _TPM_ST_I2C_H_
+
+struct tpm_st_i2c_platform_data {
+	int accept_cmd_gpio;
+	int data_avail_gpio;
+	int accept_cmd_irq;
+	int data_avail_irq;
+	int (*gpio_setup)(void);
+	void (*gpio_release)(void);
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/uncompress.h b/arch/arm/mach-msm/include/mach/uncompress.h
index c14011f..dc20df5 100644
--- a/arch/arm/mach-msm/include/mach/uncompress.h
+++ b/arch/arm/mach-msm/include/mach/uncompress.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -16,9 +16,11 @@
 #ifndef __ASM_ARCH_MSM_UNCOMPRESS_H
 #define __ASM_ARCH_MSM_UNCOMPRESS_H
 
-#include <asm/barrier.h>
+#include <linux/io.h>
+#include <asm/mach-types.h>
 #include <asm/processor.h>
 #include <mach/msm_iomap.h>
+#include <mach/msm_serial_hsl_regs.h>
 
 #define UART_CSR      (*(volatile uint32_t *)(MSM_DEBUG_UART_PHYS + 0x08))
 #define UART_TF       (*(volatile uint32_t *)(MSM_DEBUG_UART_PHYS + 0x0c))
@@ -29,28 +31,33 @@
 #define UART_DM_NCHAR (*((volatile uint32_t *)(MSM_DEBUG_UART_PHYS + 0x40)))
 #define UART_DM_TF    (*((volatile uint32_t *)(MSM_DEBUG_UART_PHYS + 0x70)))
 
+#ifndef CONFIG_DEBUG_ICEDCC
 static void putc(int c)
 {
 #if defined(MSM_DEBUG_UART_PHYS)
+	unsigned long base = MSM_DEBUG_UART_PHYS;
+
 #ifdef CONFIG_MSM_HAS_DEBUG_UART_HS
 	/*
 	 * Wait for TX_READY to be set; but skip it if we have a
 	 * TX underrun.
 	 */
-	if (UART_DM_SR & 0x08)
-		while (!(UART_DM_ISR & 0x80))
+	if (!(__raw_readl_no_log(base + UARTDM_SR_OFFSET) & 0x08))
+		while (!(__raw_readl_no_log(base + UARTDM_ISR_OFFSET) & 0x80))
 			cpu_relax();
 
-	UART_DM_CR = 0x300;
-	UART_DM_NCHAR = 0x1;
-	UART_DM_TF = c;
+	__raw_writel_no_log(0x300, base + UARTDM_CR_OFFSET);
+	__raw_writel_no_log(0x1, base + UARTDM_NCF_TX_OFFSET);
+	__raw_writel_no_log(c, base + UARTDM_TF_OFFSET);
 #else
-	while (!(UART_CSR & 0x04))
+	/* Wait for TX_READY to be set */
+	while (!(__raw_readl_no_log(base + 0x08) & 0x04))
 		cpu_relax();
-	UART_TF = c;
+	__raw_writel_no_log(c, base + 0x0c);
 #endif
 #endif
 }
+#endif
 
 static inline void flush(void)
 {
diff --git a/arch/arm/mach-msm/include/mach/usb_bam.h b/arch/arm/mach-msm/include/mach/usb_bam.h
new file mode 100644
index 0000000..ec135a3
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/usb_bam.h
@@ -0,0 +1,73 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _USB_BAM_H_
+#define _USB_BAM_H_
+
+/**
+ * SPS Pipes direction.
+ *
+ * USB_TO_PEER_PERIPHERAL	USB (as Producer) to other
+ *                          peer peripheral.
+ * PEER_PERIPHERAL_TO_USB	Other Peripheral to
+ *                          USB (as consumer).
+ */
+enum usb_bam_pipe_dir {
+	USB_TO_PEER_PERIPHERAL,
+	PEER_PERIPHERAL_TO_USB,
+};
+
+#ifdef CONFIG_USB_BAM
+/**
+ * Connect USB-to-Periperal SPS connection.
+ *
+ * This function returns the allocated pipes number.
+ *
+ * @idx - Connection index.
+ *
+ * @src_pipe_idx - allocated pipe index - USB as a
+ *  source (output)
+ *
+ * @dst_pipe_idx - allocated pipe index - USB as a
+ * destination (output)
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int usb_bam_connect(u8 idx, u8 *src_pipe_idx, u8 *dst_pipe_idx);
+
+/**
+ * Register a wakeup callback from peer BAM.
+ *
+ * @idx - Connection index.
+ *
+ * @callback - the callback function
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int usb_bam_register_wake_cb(u8 idx,
+	 int (*callback)(void *), void* param);
+#else
+static inline int usb_bam_connect(u8 idx, u8 *src_pipe_idx, u8 *dst_pipe_idx)
+{
+	return -ENODEV;
+}
+
+static inline int usb_bam_register_wake_cb(u8 idx,
+	int (*callback)(void *), void* param)
+{
+	return -ENODEV;
+}
+#endif
+#endif				/* _USB_BAM_H_ */
+
diff --git a/arch/arm/mach-msm/include/mach/usb_bridge.h b/arch/arm/mach-msm/include/mach/usb_bridge.h
new file mode 100644
index 0000000..1a1c23b
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/usb_bridge.h
@@ -0,0 +1,156 @@
+/* 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
+ * 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 __LINUX_USB_BRIDGE_H__
+#define __LINUX_USB_BRIDGE_H__
+
+#include <linux/netdevice.h>
+#include <linux/usb.h>
+
+/* bridge device 0: DUN
+ * bridge device 1 : Tethered RMNET
+ */
+#define MAX_BRIDGE_DEVICES 2
+
+struct bridge_ops {
+	int (*send_pkt)(void *, void *, size_t actual);
+	void (*send_cbits)(void *, unsigned int);
+
+	/* flow control */
+	void (*unthrottle_tx)(void *);
+};
+
+#define TX_THROTTLED BIT(0)
+#define RX_THROTTLED BIT(1)
+
+struct bridge {
+	/* context of the gadget port using bridge driver */
+	void *ctx;
+
+	/* bridge device array index mapped to the gadget port array index.
+	 * data bridge[ch_id] <-- bridge --> gadget port[ch_id]
+	 */
+	unsigned int ch_id;
+
+	/* flow control bits */
+	unsigned long flags;
+
+	/* data/ctrl bridge callbacks */
+	struct bridge_ops ops;
+};
+
+/**
+ * timestamp_info: stores timestamp info for skb life cycle during data
+ * transfer for tethered rmnet/DUN.
+ * @created: stores timestamp at the time of creation of SKB.
+ * @rx_queued: stores timestamp when SKB queued to HW to receive
+ * data.
+ * @rx_done: stores timestamp when skb queued to h/w is completed.
+ * @rx_done_sent: stores timestamp when SKB is sent from gadget rmnet/DUN
+ * driver to bridge rmnet/DUN driver or vice versa.
+ * @tx_queued: stores timestamp when SKB is queued to send data.
+ *
+ * note that size of this struct shouldnt exceed 48bytes that's the max skb->cb
+ * holds.
+ */
+struct timestamp_info {
+	struct data_bridge	*dev;
+
+	unsigned int		created;
+	unsigned int		rx_queued;
+	unsigned int		rx_done;
+	unsigned int		rx_done_sent;
+	unsigned int		tx_queued;
+};
+
+/* Maximum timestamp message length */
+#define DBG_DATA_MSG	128UL
+
+/* Maximum timestamp messages */
+#define DBG_DATA_MAX	32UL
+
+/* timestamp buffer descriptor */
+struct timestamp_buf {
+	char		(buf[DBG_DATA_MAX])[DBG_DATA_MSG];   /* buffer */
+	unsigned	idx;   /* index */
+	rwlock_t	lck;   /* lock */
+};
+
+#if defined(CONFIG_USB_QCOM_MDM_BRIDGE) ||	\
+	defined(CONFIG_USB_QCOM_MDM_BRIDGE_MODULE)
+
+/* Bridge APIs called by gadget driver */
+int ctrl_bridge_open(struct bridge *);
+void ctrl_bridge_close(unsigned int);
+int ctrl_bridge_write(unsigned int, char *, size_t);
+int ctrl_bridge_set_cbits(unsigned int, unsigned int);
+unsigned int ctrl_bridge_get_cbits_tohost(unsigned int);
+int data_bridge_open(struct bridge *brdg);
+void data_bridge_close(unsigned int);
+int data_bridge_write(unsigned int , struct sk_buff *);
+int data_bridge_unthrottle_rx(unsigned int);
+
+/* defined in control bridge */
+int ctrl_bridge_probe(struct usb_interface *, struct usb_host_endpoint *, int);
+void ctrl_bridge_disconnect(unsigned int);
+int ctrl_bridge_resume(unsigned int);
+int ctrl_bridge_suspend(unsigned int);
+
+#else
+
+static inline int __maybe_unused ctrl_bridge_open(struct bridge *brdg)
+{
+	return -ENODEV;
+}
+
+static inline void __maybe_unused ctrl_bridge_close(unsigned int id) { }
+
+static inline int __maybe_unused ctrl_bridge_write(unsigned int id,
+						char *data, size_t size)
+{
+	return -ENODEV;
+}
+
+static inline int __maybe_unused ctrl_bridge_set_cbits(unsigned int id,
+					unsigned int cbits)
+{
+	return -ENODEV;
+}
+
+static inline unsigned int __maybe_unused
+ctrl_bridge_get_cbits_tohost(unsigned int id)
+{
+	return -ENODEV;
+}
+
+static inline int __maybe_unused data_bridge_open(struct bridge *brdg)
+{
+	return -ENODEV;
+}
+
+static inline void __maybe_unused data_bridge_close(unsigned int id) { }
+
+static inline int __maybe_unused data_bridge_write(unsigned int id,
+					    struct sk_buff *skb)
+{
+	return -ENODEV;
+}
+
+static inline int __maybe_unused data_bridge_unthrottle_rx(unsigned int id)
+{
+	return -ENODEV;
+}
+
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/usb_gadget_xport.h b/arch/arm/mach-msm/include/mach/usb_gadget_xport.h
new file mode 100644
index 0000000..be11989
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/usb_gadget_xport.h
@@ -0,0 +1,105 @@
+/* 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
+ * 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 __LINUX_USB_GADGET_XPORT_H__
+#define __LINUX_USB_GADGET_XPORT_H__
+
+enum transport_type {
+	USB_GADGET_XPORT_UNDEF,
+	USB_GADGET_XPORT_TTY,
+	USB_GADGET_XPORT_SDIO,
+	USB_GADGET_XPORT_SMD,
+	USB_GADGET_XPORT_BAM,
+	USB_GADGET_XPORT_BAM2BAM,
+	USB_GADGET_XPORT_HSIC,
+	USB_GADGET_XPORT_HSUART,
+	USB_GADGET_XPORT_NONE,
+};
+
+#define XPORT_STR_LEN	10
+
+static char *xport_to_str(enum transport_type t)
+{
+	switch (t) {
+	case USB_GADGET_XPORT_TTY:
+		return "TTY";
+	case USB_GADGET_XPORT_SDIO:
+		return "SDIO";
+	case USB_GADGET_XPORT_SMD:
+		return "SMD";
+	case USB_GADGET_XPORT_BAM:
+		return "BAM";
+	case USB_GADGET_XPORT_BAM2BAM:
+		return "BAM2BAM";
+	case USB_GADGET_XPORT_HSIC:
+		return "HSIC";
+	case USB_GADGET_XPORT_HSUART:
+		return "HSUART";
+	case USB_GADGET_XPORT_NONE:
+		return "NONE";
+	default:
+		return "UNDEFINED";
+	}
+}
+
+static enum transport_type str_to_xport(const char *name)
+{
+	if (!strncasecmp("TTY", name, XPORT_STR_LEN))
+		return USB_GADGET_XPORT_TTY;
+	if (!strncasecmp("SDIO", name, XPORT_STR_LEN))
+		return USB_GADGET_XPORT_SDIO;
+	if (!strncasecmp("SMD", name, XPORT_STR_LEN))
+		return USB_GADGET_XPORT_SMD;
+	if (!strncasecmp("BAM", name, XPORT_STR_LEN))
+		return USB_GADGET_XPORT_BAM;
+	if (!strncasecmp("BAM2BAM", name, XPORT_STR_LEN))
+		return USB_GADGET_XPORT_BAM2BAM;
+	if (!strncasecmp("HSIC", name, XPORT_STR_LEN))
+		return USB_GADGET_XPORT_HSIC;
+	if (!strncasecmp("HSUART", name, XPORT_STR_LEN))
+		return USB_GADGET_XPORT_HSUART;
+	if (!strncasecmp("", name, XPORT_STR_LEN))
+		return USB_GADGET_XPORT_NONE;
+
+	return USB_GADGET_XPORT_UNDEF;
+}
+
+enum gadget_type {
+	USB_GADGET_SERIAL,
+	USB_GADGET_RMNET,
+};
+
+#define NUM_RMNET_HSIC_PORTS 1
+#define NUM_DUN_HSIC_PORTS 1
+#define NUM_PORTS (NUM_RMNET_HSIC_PORTS \
+	+ NUM_DUN_HSIC_PORTS)
+
+#define NUM_RMNET_HSUART_PORTS 1
+#define NUM_DUN_HSUART_PORTS 1
+#define NUM_HSUART_PORTS (NUM_RMNET_HSUART_PORTS \
+	+ NUM_DUN_HSUART_PORTS)
+
+int ghsic_ctrl_connect(void *, int);
+void ghsic_ctrl_disconnect(void *, int);
+int ghsic_ctrl_setup(unsigned int, enum gadget_type);
+int ghsic_data_connect(void *, int);
+void ghsic_data_disconnect(void *, int);
+int ghsic_data_setup(unsigned int, enum gadget_type);
+
+int ghsuart_ctrl_connect(void *, int);
+void ghsuart_ctrl_disconnect(void *, int);
+int ghsuart_ctrl_setup(unsigned int, enum gadget_type);
+int ghsuart_data_connect(void *, int);
+void ghsuart_data_disconnect(void *, int);
+int ghsuart_data_setup(unsigned int, enum gadget_type);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/usbdiag.h b/arch/arm/mach-msm/include/mach/usbdiag.h
new file mode 100644
index 0000000..d1e3605
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/usbdiag.h
@@ -0,0 +1,58 @@
+/* include/asm-arm/arch-msm/usbdiag.h
+ *
+ * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+
+#ifndef _DRIVERS_USB_DIAG_H_
+#define _DRIVERS_USB_DIAG_H_
+
+#define DIAG_LEGACY		"diag"
+#define DIAG_MDM		"diag_mdm"
+
+#define USB_DIAG_CONNECT	0
+#define USB_DIAG_DISCONNECT	1
+#define USB_DIAG_WRITE_DONE	2
+#define USB_DIAG_READ_DONE	3
+
+struct diag_request {
+	char *buf;
+	int length;
+	int actual;
+	int status;
+	void *context;
+};
+
+struct usb_diag_ch {
+	const char *name;
+	struct list_head list;
+	void (*notify)(void *priv, unsigned event, struct diag_request *d_req);
+	void *priv;
+	void *priv_usb;
+};
+
+struct usb_diag_ch *usb_diag_open(const char *name, void *priv,
+		void (*notify)(void *, unsigned, struct diag_request *));
+void usb_diag_close(struct usb_diag_ch *ch);
+int usb_diag_alloc_req(struct usb_diag_ch *ch, int n_write, int n_read);
+void usb_diag_free_req(struct usb_diag_ch *ch);
+int usb_diag_read(struct usb_diag_ch *ch, struct diag_request *d_req);
+int usb_diag_write(struct usb_diag_ch *ch, struct diag_request *d_req);
+
+int diag_read_from_cb(unsigned char * , int);
+
+#endif /* _DRIVERS_USB_DIAG_H_ */
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index a1e7b11..86e06a4 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -3,7 +3,7 @@
  * MSM7K, QSD io support
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -26,10 +26,11 @@
 #include <asm/page.h>
 #include <mach/msm_iomap.h>
 #include <asm/mach/map.h>
+#include <linux/dma-mapping.h>
 
 #include <mach/board.h>
 
-#define MSM_CHIP_DEVICE(name, chip) {			      \
+#define MSM_CHIP_DEVICE(name, chip) { \
 		.virtual = (unsigned long) MSM_##name##_BASE, \
 		.pfn = __phys_to_pfn(chip##_##name##_PHYS), \
 		.length = chip##_##name##_SIZE, \
@@ -38,25 +39,48 @@
 
 #define MSM_DEVICE(name) MSM_CHIP_DEVICE(name, MSM)
 
-#if defined(CONFIG_ARCH_MSM7X00A) || defined(CONFIG_ARCH_MSM7X27) \
+/* msm_shared_ram_phys default value of 0x00100000 is the most common value
+ * and should work as-is for any target without stacked memory.
+ */
+unsigned int msm_shared_ram_phys = 0x00100000;
+
+static void __init msm_map_io(struct map_desc *io_desc, int size)
+{
+	int i;
+
+	BUG_ON(!size);
+	for (i = 0; i < size; i++)
+		if (io_desc[i].virtual == (unsigned long)MSM_SHARED_RAM_BASE)
+			io_desc[i].pfn = __phys_to_pfn(msm_shared_ram_phys);
+
+	iotable_init(io_desc, size);
+}
+
+#if defined(CONFIG_ARCH_MSM7X01A) || defined(CONFIG_ARCH_MSM7X27) \
 	|| defined(CONFIG_ARCH_MSM7X25)
 static struct map_desc msm_io_desc[] __initdata = {
-	MSM_DEVICE(VIC),
-	MSM_CHIP_DEVICE(CSR, MSM7X00),
-	MSM_DEVICE(DMOV),
-	MSM_CHIP_DEVICE(GPIO1, MSM7X00),
-	MSM_CHIP_DEVICE(GPIO2, MSM7X00),
-	MSM_DEVICE(CLK_CTL),
+	MSM_CHIP_DEVICE(VIC, MSM7XXX),
+	MSM_CHIP_DEVICE(CSR, MSM7XXX),
+	MSM_CHIP_DEVICE(TMR, MSM7XXX),
+	MSM_CHIP_DEVICE(GPIO1, MSM7XXX),
+	MSM_CHIP_DEVICE(GPIO2, MSM7XXX),
+	MSM_CHIP_DEVICE(CLK_CTL, MSM7XXX),
+	MSM_CHIP_DEVICE(AD5, MSM7XXX),
+	MSM_CHIP_DEVICE(MDC, MSM7XXX),
 #if defined(CONFIG_DEBUG_MSM_UART1) || defined(CONFIG_DEBUG_MSM_UART2) || \
 	defined(CONFIG_DEBUG_MSM_UART3)
 	MSM_DEVICE(DEBUG_UART),
 #endif
-#ifdef CONFIG_ARCH_MSM7X30
-	MSM_DEVICE(GCC),
+#ifdef CONFIG_CACHE_L2X0
+	{
+		.virtual =  (unsigned long) MSM_L2CC_BASE,
+		.pfn =      __phys_to_pfn(MSM7XXX_L2CC_PHYS),
+		.length =   MSM7XXX_L2CC_SIZE,
+		.type =     MT_DEVICE,
+	},
 #endif
 	{
 		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
-		.pfn = __phys_to_pfn(MSM_SHARED_RAM_PHYS),
 		.length =   MSM_SHARED_RAM_SIZE,
 		.type =     MT_DEVICE,
 	},
@@ -64,95 +88,32 @@
 
 void __init msm_map_common_io(void)
 {
+	/*Peripheral port memory remap, nothing looks to be there for
+	 * cortex a5.
+	 */
+#ifndef CONFIG_ARCH_MSM_CORTEX_A5
 	/* Make sure the peripheral register window is closed, since
 	 * we will use PTE flags (TEX[1]=1,B=0,C=1) to determine which
 	 * pages are peripheral interface or not.
 	 */
 	asm("mcr p15, 0, %0, c15, c2, 4" : : "r" (0));
-	iotable_init(msm_io_desc, ARRAY_SIZE(msm_io_desc));
+#endif
+	msm_map_io(msm_io_desc, ARRAY_SIZE(msm_io_desc));
 }
 #endif
 
 #ifdef CONFIG_ARCH_QSD8X50
 static struct map_desc qsd8x50_io_desc[] __initdata = {
 	MSM_DEVICE(VIC),
-	MSM_CHIP_DEVICE(CSR, QSD8X50),
-	MSM_DEVICE(DMOV),
-	MSM_CHIP_DEVICE(GPIO1, QSD8X50),
-	MSM_CHIP_DEVICE(GPIO2, QSD8X50),
+	MSM_DEVICE(CSR),
+	MSM_DEVICE(TMR),
+	MSM_DEVICE(GPIO1),
+	MSM_DEVICE(GPIO2),
 	MSM_DEVICE(CLK_CTL),
 	MSM_DEVICE(SIRC),
 	MSM_DEVICE(SCPLL),
 	MSM_DEVICE(AD5),
 	MSM_DEVICE(MDC),
-#if defined(CONFIG_DEBUG_MSM_UART1) || defined(CONFIG_DEBUG_MSM_UART2) || \
-	defined(CONFIG_DEBUG_MSM_UART3)
-	MSM_DEVICE(DEBUG_UART),
-#endif
-	{
-		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
-		.pfn = __phys_to_pfn(MSM_SHARED_RAM_PHYS),
-		.length =   MSM_SHARED_RAM_SIZE,
-		.type =     MT_DEVICE,
-	},
-};
-
-void __init msm_map_qsd8x50_io(void)
-{
-	iotable_init(qsd8x50_io_desc, ARRAY_SIZE(qsd8x50_io_desc));
-}
-#endif /* CONFIG_ARCH_QSD8X50 */
-
-#ifdef CONFIG_ARCH_MSM8X60
-static struct map_desc msm8x60_io_desc[] __initdata = {
-	MSM_CHIP_DEVICE(QGIC_DIST, MSM8X60),
-	MSM_CHIP_DEVICE(QGIC_CPU, MSM8X60),
-	MSM_CHIP_DEVICE(TMR, MSM8X60),
-	MSM_CHIP_DEVICE(TMR0, MSM8X60),
-	MSM_DEVICE(ACC),
-	MSM_DEVICE(GCC),
-#ifdef CONFIG_DEBUG_MSM8660_UART
-	MSM_DEVICE(DEBUG_UART),
-#endif
-};
-
-void __init msm_map_msm8x60_io(void)
-{
-	iotable_init(msm8x60_io_desc, ARRAY_SIZE(msm8x60_io_desc));
-}
-#endif /* CONFIG_ARCH_MSM8X60 */
-
-#ifdef CONFIG_ARCH_MSM8960
-static struct map_desc msm8960_io_desc[] __initdata = {
-	MSM_CHIP_DEVICE(QGIC_DIST, MSM8960),
-	MSM_CHIP_DEVICE(QGIC_CPU, MSM8960),
-	MSM_CHIP_DEVICE(TMR, MSM8960),
-	MSM_CHIP_DEVICE(TMR0, MSM8960),
-#ifdef CONFIG_DEBUG_MSM8960_UART
-	MSM_DEVICE(DEBUG_UART),
-#endif
-};
-
-void __init msm_map_msm8960_io(void)
-{
-	iotable_init(msm8960_io_desc, ARRAY_SIZE(msm8960_io_desc));
-}
-#endif /* CONFIG_ARCH_MSM8960 */
-
-#ifdef CONFIG_ARCH_MSM7X30
-static struct map_desc msm7x30_io_desc[] __initdata = {
-	MSM_DEVICE(VIC),
-	MSM_CHIP_DEVICE(CSR, MSM7X30),
-	MSM_DEVICE(DMOV),
-	MSM_CHIP_DEVICE(GPIO1, MSM7X30),
-	MSM_CHIP_DEVICE(GPIO2, MSM7X30),
-	MSM_DEVICE(CLK_CTL),
-	MSM_DEVICE(CLK_CTL_SH2),
-	MSM_DEVICE(AD5),
-	MSM_DEVICE(MDC),
-	MSM_DEVICE(ACC),
-	MSM_DEVICE(SAW),
-	MSM_DEVICE(GCC),
 	MSM_DEVICE(TCSR),
 #if defined(CONFIG_DEBUG_MSM_UART1) || defined(CONFIG_DEBUG_MSM_UART2) || \
 	defined(CONFIG_DEBUG_MSM_UART3)
@@ -160,7 +121,223 @@
 #endif
 	{
 		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
-		.pfn = __phys_to_pfn(MSM_SHARED_RAM_PHYS),
+		.length =   MSM_SHARED_RAM_SIZE,
+		.type =     MT_DEVICE,
+	},
+};
+
+void __init msm_map_qsd8x50_io(void)
+{
+	msm_map_io(qsd8x50_io_desc, ARRAY_SIZE(qsd8x50_io_desc));
+}
+#endif /* CONFIG_ARCH_QSD8X50 */
+
+#ifdef CONFIG_ARCH_MSM8X60
+static struct map_desc msm8x60_io_desc[] __initdata = {
+	MSM_DEVICE(QGIC_DIST),
+	MSM_DEVICE(QGIC_CPU),
+	MSM_DEVICE(TMR),
+	MSM_DEVICE(TMR0),
+	MSM_DEVICE(RPM_MPM),
+	MSM_DEVICE(ACC),
+	MSM_DEVICE(ACC0),
+	MSM_DEVICE(ACC1),
+	MSM_DEVICE(SAW0),
+	MSM_DEVICE(SAW1),
+	MSM_DEVICE(GCC),
+	MSM_DEVICE(TLMM),
+	MSM_DEVICE(SCPLL),
+	MSM_DEVICE(RPM),
+	MSM_DEVICE(CLK_CTL),
+	MSM_DEVICE(MMSS_CLK_CTL),
+	MSM_DEVICE(LPASS_CLK_CTL),
+	MSM_DEVICE(TCSR),
+	MSM_DEVICE(IMEM),
+	MSM_DEVICE(HDMI),
+#ifdef CONFIG_DEBUG_MSM8660_UART
+	MSM_DEVICE(DEBUG_UART),
+#endif
+	MSM_DEVICE(SIC_NON_SECURE),
+	{
+		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
+		.length =   MSM_SHARED_RAM_SIZE,
+		.type =     MT_DEVICE,
+	},
+	MSM_DEVICE(QFPROM),
+};
+
+void __init msm_map_msm8x60_io(void)
+{
+	msm_map_io(msm8x60_io_desc, ARRAY_SIZE(msm8x60_io_desc));
+	init_consistent_dma_size(14*SZ_1M);
+}
+#endif /* CONFIG_ARCH_MSM8X60 */
+
+#ifdef CONFIG_ARCH_MSM8960
+static struct map_desc msm8960_io_desc[] __initdata = {
+	MSM_CHIP_DEVICE(QGIC_DIST, MSM8960),
+	MSM_CHIP_DEVICE(QGIC_CPU, MSM8960),
+	MSM_CHIP_DEVICE(ACC0, MSM8960),
+	MSM_CHIP_DEVICE(ACC1, MSM8960),
+	MSM_CHIP_DEVICE(TMR, MSM8960),
+	MSM_CHIP_DEVICE(TMR0, MSM8960),
+	MSM_CHIP_DEVICE(RPM_MPM, MSM8960),
+	MSM_CHIP_DEVICE(CLK_CTL, MSM8960),
+	MSM_CHIP_DEVICE(MMSS_CLK_CTL, MSM8960),
+	MSM_CHIP_DEVICE(LPASS_CLK_CTL, MSM8960),
+	MSM_CHIP_DEVICE(RPM, MSM8960),
+	MSM_CHIP_DEVICE(TLMM, MSM8960),
+	MSM_CHIP_DEVICE(HFPLL, MSM8960),
+	MSM_CHIP_DEVICE(SAW0, MSM8960),
+	MSM_CHIP_DEVICE(SAW1, MSM8960),
+	MSM_CHIP_DEVICE(SAW_L2, MSM8960),
+	MSM_CHIP_DEVICE(SIC_NON_SECURE, MSM8960),
+	MSM_CHIP_DEVICE(APCS_GCC, MSM8960),
+	MSM_CHIP_DEVICE(IMEM, MSM8960),
+	MSM_CHIP_DEVICE(HDMI, MSM8960),
+	{
+		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
+		.length =   MSM_SHARED_RAM_SIZE,
+		.type =     MT_DEVICE,
+	},
+#ifdef CONFIG_DEBUG_MSM8960_UART
+	MSM_DEVICE(DEBUG_UART),
+#endif
+	MSM_CHIP_DEVICE(QFPROM, MSM8960),
+};
+
+void __init msm_map_msm8960_io(void)
+{
+	msm_map_io(msm8960_io_desc, ARRAY_SIZE(msm8960_io_desc));
+}
+#endif /* CONFIG_ARCH_MSM8960 */
+
+#ifdef CONFIG_ARCH_MSM8930
+static struct map_desc msm8930_io_desc[] __initdata = {
+	MSM_CHIP_DEVICE(QGIC_DIST, MSM8930),
+	MSM_CHIP_DEVICE(QGIC_CPU, MSM8930),
+	MSM_CHIP_DEVICE(ACC0, MSM8930),
+	MSM_CHIP_DEVICE(ACC1, MSM8930),
+	MSM_CHIP_DEVICE(TMR, MSM8930),
+	MSM_CHIP_DEVICE(TMR0, MSM8930),
+	MSM_CHIP_DEVICE(RPM_MPM, MSM8930),
+	MSM_CHIP_DEVICE(CLK_CTL, MSM8930),
+	MSM_CHIP_DEVICE(MMSS_CLK_CTL, MSM8930),
+	MSM_CHIP_DEVICE(LPASS_CLK_CTL, MSM8930),
+	MSM_CHIP_DEVICE(RPM, MSM8930),
+	MSM_CHIP_DEVICE(TLMM, MSM8930),
+	MSM_CHIP_DEVICE(HFPLL, MSM8930),
+	MSM_CHIP_DEVICE(SAW0, MSM8930),
+	MSM_CHIP_DEVICE(SAW1, MSM8930),
+	MSM_CHIP_DEVICE(SAW_L2, MSM8930),
+	MSM_CHIP_DEVICE(SIC_NON_SECURE, MSM8930),
+	MSM_CHIP_DEVICE(APCS_GCC, MSM8930),
+	MSM_CHIP_DEVICE(IMEM, MSM8930),
+	MSM_CHIP_DEVICE(HDMI, MSM8930),
+	{
+		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
+		.length =   MSM_SHARED_RAM_SIZE,
+		.type =     MT_DEVICE,
+	},
+#ifdef CONFIG_DEBUG_MSM8930_UART
+	MSM_DEVICE(DEBUG_UART),
+#endif
+	MSM_CHIP_DEVICE(QFPROM, MSM8930),
+};
+
+void __init msm_map_msm8930_io(void)
+{
+	msm_map_io(msm8930_io_desc, ARRAY_SIZE(msm8930_io_desc));
+}
+#endif /* CONFIG_ARCH_MSM8930 */
+
+#ifdef CONFIG_ARCH_APQ8064
+static struct map_desc apq8064_io_desc[] __initdata = {
+	MSM_CHIP_DEVICE(QGIC_DIST, APQ8064),
+	MSM_CHIP_DEVICE(QGIC_CPU, APQ8064),
+	MSM_CHIP_DEVICE(TMR, APQ8064),
+	MSM_CHIP_DEVICE(TMR0, APQ8064),
+	MSM_CHIP_DEVICE(TLMM, APQ8064),
+	MSM_CHIP_DEVICE(ACC0, APQ8064),
+	MSM_CHIP_DEVICE(ACC1, APQ8064),
+	MSM_CHIP_DEVICE(ACC2, APQ8064),
+	MSM_CHIP_DEVICE(ACC3, APQ8064),
+	MSM_CHIP_DEVICE(HFPLL, APQ8064),
+	MSM_CHIP_DEVICE(CLK_CTL, APQ8064),
+	MSM_CHIP_DEVICE(MMSS_CLK_CTL, APQ8064),
+	MSM_CHIP_DEVICE(LPASS_CLK_CTL, APQ8064),
+	MSM_CHIP_DEVICE(APCS_GCC, APQ8064),
+	MSM_CHIP_DEVICE(RPM, APQ8064),
+	MSM_CHIP_DEVICE(RPM_MPM, APQ8064),
+	MSM_CHIP_DEVICE(SAW0, APQ8064),
+	MSM_CHIP_DEVICE(SAW1, APQ8064),
+	MSM_CHIP_DEVICE(SAW2, APQ8064),
+	MSM_CHIP_DEVICE(SAW3, APQ8064),
+	MSM_CHIP_DEVICE(SAW_L2, APQ8064),
+	MSM_CHIP_DEVICE(IMEM, APQ8064),
+	MSM_CHIP_DEVICE(HDMI, APQ8064),
+	{
+		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
+		.length =   MSM_SHARED_RAM_SIZE,
+		.type =     MT_DEVICE,
+	},
+	MSM_CHIP_DEVICE(QFPROM, APQ8064),
+	MSM_CHIP_DEVICE(SIC_NON_SECURE, APQ8064),
+#ifdef CONFIG_DEBUG_APQ8064_UART
+	MSM_DEVICE(DEBUG_UART),
+#endif
+};
+
+void __init msm_map_apq8064_io(void)
+{
+	msm_map_io(apq8064_io_desc, ARRAY_SIZE(apq8064_io_desc));
+}
+#endif /* CONFIG_ARCH_APQ8064 */
+
+#ifdef CONFIG_ARCH_MSMCOPPER
+static struct map_desc msm_copper_io_desc[] __initdata = {
+	MSM_CHIP_DEVICE(QGIC_DIST, COPPER),
+	MSM_CHIP_DEVICE(QGIC_CPU, COPPER),
+	MSM_CHIP_DEVICE(APCS_GCC, COPPER),
+	MSM_CHIP_DEVICE(TLMM, COPPER),
+	{
+		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
+		.length =   MSM_SHARED_RAM_SIZE,
+		.type =     MT_DEVICE,
+	},
+#ifdef CONFIG_DEBUG_MSMCOPPER_UART
+	MSM_DEVICE(DEBUG_UART),
+#endif
+};
+
+void __init msm_map_copper_io(void)
+{
+	msm_shared_ram_phys = COPPER_MSM_SHARED_RAM_PHYS;
+	msm_map_io(msm_copper_io_desc, ARRAY_SIZE(msm_copper_io_desc));
+}
+#endif /* CONFIG_ARCH_MSMCOPPER */
+
+#ifdef CONFIG_ARCH_MSM7X30
+static struct map_desc msm7x30_io_desc[] __initdata = {
+	MSM_CHIP_DEVICE(VIC, MSM7X30),
+	MSM_CHIP_DEVICE(CSR, MSM7X30),
+	MSM_CHIP_DEVICE(TMR, MSM7X30),
+	MSM_CHIP_DEVICE(GPIO1, MSM7X30),
+	MSM_CHIP_DEVICE(GPIO2, MSM7X30),
+	MSM_CHIP_DEVICE(CLK_CTL, MSM7X30),
+	MSM_CHIP_DEVICE(CLK_CTL_SH2, MSM7X30),
+	MSM_CHIP_DEVICE(AD5, MSM7X30),
+	MSM_CHIP_DEVICE(MDC, MSM7X30),
+	MSM_CHIP_DEVICE(ACC0, MSM7X30),
+	MSM_CHIP_DEVICE(SAW0, MSM7X30),
+	MSM_CHIP_DEVICE(APCS_GCC, MSM7X30),
+	MSM_CHIP_DEVICE(TCSR, MSM7X30),
+#if defined(CONFIG_DEBUG_MSM_UART1) || defined(CONFIG_DEBUG_MSM_UART2) || \
+	defined(CONFIG_DEBUG_MSM_UART3)
+	MSM_DEVICE(DEBUG_UART),
+#endif
+	{
+		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
 		.length =   MSM_SHARED_RAM_SIZE,
 		.type =     MT_DEVICE,
 	},
@@ -168,21 +345,133 @@
 
 void __init msm_map_msm7x30_io(void)
 {
-	iotable_init(msm7x30_io_desc, ARRAY_SIZE(msm7x30_io_desc));
+	msm_map_io(msm7x30_io_desc, ARRAY_SIZE(msm7x30_io_desc));
 }
 #endif /* CONFIG_ARCH_MSM7X30 */
 
-void __iomem *__msm_ioremap_caller(unsigned long phys_addr, size_t size,
-				   unsigned int mtype, void *caller)
-{
-	if (mtype == MT_DEVICE) {
-		/* The peripherals in the 88000000 - D0000000 range
-		 * are only accessible by type MT_DEVICE_NONSHARED.
-		 * Adjust mtype as necessary to make this "just work."
-		 */
-		if ((phys_addr >= 0x88000000) && (phys_addr < 0xD0000000))
-			mtype = MT_DEVICE_NONSHARED;
-	}
+#ifdef CONFIG_ARCH_FSM9XXX
+static struct map_desc fsm9xxx_io_desc[] __initdata = {
+	MSM_DEVICE(VIC),
+	MSM_DEVICE(SIRC),
+	MSM_DEVICE(CSR),
+	MSM_DEVICE(TLMM),
+	MSM_DEVICE(TCSR),
+	MSM_DEVICE(CLK_CTL),
+	MSM_DEVICE(ACC),
+	MSM_DEVICE(SAW),
+	MSM_DEVICE(GCC),
+	MSM_DEVICE(GRFC),
+	MSM_DEVICE(QFP_FUSE),
+	MSM_DEVICE(HH),
+#if defined(CONFIG_DEBUG_MSM_UART1) || defined(CONFIG_DEBUG_MSM_UART2) || \
+	defined(CONFIG_DEBUG_MSM_UART3)
+	MSM_DEVICE(DEBUG_UART),
+#endif
+	{
+		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
+		.length =   MSM_SHARED_RAM_SIZE,
+		.type =     MT_DEVICE,
+	},
+};
 
-	return __arm_ioremap_caller(phys_addr, size, mtype, caller);
+void __init msm_map_fsm9xxx_io(void)
+{
+	msm_map_io(fsm9xxx_io_desc, ARRAY_SIZE(fsm9xxx_io_desc));
 }
+#endif /* CONFIG_ARCH_FSM9XXX */
+
+#ifdef CONFIG_ARCH_MSM9615
+static struct map_desc msm9615_io_desc[] __initdata = {
+	MSM_CHIP_DEVICE(QGIC_DIST, MSM9615),
+	MSM_CHIP_DEVICE(QGIC_CPU, MSM9615),
+	MSM_CHIP_DEVICE(ACC0, MSM9615),
+	MSM_CHIP_DEVICE(TMR, MSM9615),
+	MSM_CHIP_DEVICE(TLMM, MSM9615),
+	MSM_CHIP_DEVICE(SAW0, MSM9615),
+	MSM_CHIP_DEVICE(APCS_GCC, MSM9615),
+	MSM_CHIP_DEVICE(TCSR, MSM9615),
+	MSM_CHIP_DEVICE(L2CC, MSM9615),
+	MSM_CHIP_DEVICE(CLK_CTL, MSM9615),
+	MSM_CHIP_DEVICE(LPASS_CLK_CTL, MSM9615),
+	MSM_CHIP_DEVICE(RPM, MSM9615),
+	MSM_CHIP_DEVICE(RPM_MPM, MSM9615),
+	MSM_CHIP_DEVICE(APCS_GLB, MSM9615),
+	MSM_CHIP_DEVICE(IMEM, MSM9615),
+	{
+		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
+		.length =   MSM_SHARED_RAM_SIZE,
+		.type =     MT_DEVICE,
+	},
+	MSM_CHIP_DEVICE(QFPROM, MSM9615),
+};
+
+void __init msm_map_msm9615_io(void)
+{
+	msm_map_io(msm9615_io_desc, ARRAY_SIZE(msm9615_io_desc));
+}
+#endif /* CONFIG_ARCH_MSM9615 */
+
+#ifdef CONFIG_ARCH_MSM8625
+static struct map_desc msm8625_io_desc[] __initdata = {
+	MSM_CHIP_DEVICE(CSR, MSM7XXX),
+	MSM_CHIP_DEVICE(GPIO1, MSM7XXX),
+	MSM_CHIP_DEVICE(GPIO2, MSM7XXX),
+	MSM_CHIP_DEVICE(QGIC_DIST, MSM8625),
+	MSM_CHIP_DEVICE(QGIC_CPU, MSM8625),
+	MSM_CHIP_DEVICE(TMR, MSM8625),
+	MSM_CHIP_DEVICE(TMR0, MSM8625),
+	MSM_CHIP_DEVICE(SCU, MSM8625),
+	MSM_CHIP_DEVICE(CFG_CTL, MSM8625),
+	MSM_CHIP_DEVICE(CLK_CTL, MSM8625),
+	MSM_CHIP_DEVICE(SAW0, MSM8625),
+	MSM_CHIP_DEVICE(SAW1, MSM8625),
+	MSM_CHIP_DEVICE(AD5, MSM7XXX),
+	MSM_CHIP_DEVICE(MDC, MSM7XXX),
+#if defined(CONFIG_DEBUG_MSM_UART1) || defined(CONFIG_DEBUG_MSM_UART2) || \
+	defined(CONFIG_DEBUG_MSM_UART3)
+	MSM_DEVICE(DEBUG_UART),
+#endif
+#ifdef CONFIG_CACHE_L2X0
+	{
+		.virtual = (unsigned long) MSM_L2CC_BASE,
+		.pfn	 = __phys_to_pfn(MSM7XXX_L2CC_PHYS),
+		.length	 = MSM7XXX_L2CC_SIZE,
+		.type	 = MT_DEVICE,
+	},
+#endif
+	{
+		.virtual = (unsigned long) MSM_SHARED_RAM_BASE,
+		.length	 = MSM_SHARED_RAM_SIZE,
+		.type	 = MT_DEVICE,
+	},
+};
+
+void __init msm_map_msm8625_io(void)
+{
+	msm_map_io(msm8625_io_desc, ARRAY_SIZE(msm8625_io_desc));
+}
+#else
+void __init msm_map_msm8625_io(void) { return; }
+#endif /* CONFIG_ARCH_MSM8625 */
+
+#ifdef CONFIG_ARCH_MSM9625
+static struct map_desc msm9625_io_desc[] __initdata = {
+	MSM_CHIP_DEVICE(APCS_GCC, MSM9625),
+	MSM_CHIP_DEVICE(TLMM, MSM9625),
+	MSM_CHIP_DEVICE(TMR, MSM9625),
+	{
+		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
+		.length =   MSM_SHARED_RAM_SIZE,
+		.type =     MT_DEVICE,
+	},
+#ifdef CONFIG_DEBUG_MSM9625_UART
+	MSM_DEVICE(DEBUG_UART),
+#endif
+};
+
+void __init msm_map_msm9625_io(void)
+{
+	msm_shared_ram_phys = MSM9625_SHARED_RAM_PHYS;
+	msm_map_io(msm9625_io_desc, ARRAY_SIZE(msm9625_io_desc));
+}
+#endif /* CONFIG_ARCH_MSM9625 */
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
new file mode 100644
index 0000000..fec27bd
--- /dev/null
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -0,0 +1,443 @@
+/* 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
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/iommu.h>
+#include <linux/memory_alloc.h>
+#include <linux/platform_device.h>
+#include <linux/vmalloc.h>
+#include <linux/rbtree.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <asm/sizes.h>
+#include <asm/page.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/socinfo.h>
+#include <mach/msm_subsystem_map.h>
+
+/* dummy 64K for overmapping */
+char iommu_dummy[2*SZ_64K-4];
+
+struct msm_iova_data {
+	struct rb_node node;
+	struct mem_pool *pools;
+	int npools;
+	struct iommu_domain *domain;
+	int domain_num;
+};
+
+static struct rb_root domain_root;
+DEFINE_MUTEX(domain_mutex);
+static atomic_t domain_nums = ATOMIC_INIT(-1);
+
+int msm_iommu_map_extra(struct iommu_domain *domain,
+				unsigned long start_iova,
+				unsigned long size,
+				unsigned long page_size,
+				int cached)
+{
+	int i, ret_value = 0;
+	unsigned long order = get_order(page_size);
+	unsigned long aligned_size = ALIGN(size, page_size);
+	unsigned long nrpages = aligned_size >> (PAGE_SHIFT + order);
+	unsigned long phy_addr = ALIGN(virt_to_phys(iommu_dummy), page_size);
+	unsigned long temp_iova = start_iova;
+
+	for (i = 0; i < nrpages; i++) {
+		int ret = iommu_map(domain, temp_iova, phy_addr, page_size,
+					cached);
+		if (ret) {
+			pr_err("%s: could not map %lx in domain %p, error: %d\n",
+				__func__, start_iova, domain, ret);
+			ret_value = -EAGAIN;
+			goto out;
+		}
+		temp_iova += page_size;
+	}
+	return ret_value;
+out:
+	for (; i > 0; --i) {
+		temp_iova -= page_size;
+		iommu_unmap(domain, start_iova, page_size);
+	}
+	return ret_value;
+}
+
+void msm_iommu_unmap_extra(struct iommu_domain *domain,
+				unsigned long start_iova,
+				unsigned long size,
+				unsigned long page_size)
+{
+	int i;
+	unsigned long order = get_order(page_size);
+	unsigned long aligned_size = ALIGN(size, page_size);
+	unsigned long nrpages =  aligned_size >> (PAGE_SHIFT + order);
+	unsigned long temp_iova = start_iova;
+
+	for (i = 0; i < nrpages; ++i) {
+		iommu_unmap(domain, temp_iova, page_size);
+		temp_iova += page_size;
+	}
+}
+
+static int msm_iommu_map_iova_phys(struct iommu_domain *domain,
+				unsigned long iova,
+				unsigned long phys,
+				unsigned long size,
+				int cached)
+{
+	int ret;
+	struct scatterlist *sglist;
+
+	sglist = vmalloc(sizeof(*sglist));
+	if (!sglist) {
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	sg_init_table(sglist, 1);
+	sglist->length = size;
+	sglist->offset = 0;
+	sglist->dma_address = phys;
+
+	ret = iommu_map_range(domain, iova, sglist, size, cached);
+	if (ret) {
+		pr_err("%s: could not map extra %lx in domain %p\n",
+			__func__, iova, domain);
+	}
+
+	vfree(sglist);
+err1:
+	return ret;
+
+}
+
+int msm_iommu_map_contig_buffer(unsigned long phys,
+				unsigned int domain_no,
+				unsigned int partition_no,
+				unsigned long size,
+				unsigned long align,
+				unsigned long cached,
+				unsigned long *iova_val)
+{
+	unsigned long iova;
+	int ret;
+
+	if (size & (align - 1))
+		return -EINVAL;
+
+	ret = msm_allocate_iova_address(domain_no, partition_no, size, align,
+						&iova);
+
+	if (ret)
+		return -ENOMEM;
+
+	ret = msm_iommu_map_iova_phys(msm_get_iommu_domain(domain_no), iova,
+					phys, size, cached);
+
+	if (ret)
+		msm_free_iova_address(iova, domain_no, partition_no, size);
+	else
+		*iova_val = iova;
+
+	return ret;
+}
+
+void msm_iommu_unmap_contig_buffer(unsigned long iova,
+					unsigned int domain_no,
+					unsigned int partition_no,
+					unsigned long size)
+{
+	iommu_unmap_range(msm_get_iommu_domain(domain_no), iova, size);
+	msm_free_iova_address(iova, domain_no, partition_no, size);
+}
+
+static struct msm_iova_data *find_domain(int domain_num)
+{
+	struct rb_root *root = &domain_root;
+	struct rb_node *p = root->rb_node;
+
+	mutex_lock(&domain_mutex);
+
+	while (p) {
+		struct msm_iova_data *node;
+
+		node = rb_entry(p, struct msm_iova_data, node);
+		if (domain_num < node->domain_num)
+			p = p->rb_left;
+		else if (domain_num > domain_num)
+			p = p->rb_right;
+		else {
+			mutex_unlock(&domain_mutex);
+			return node;
+		}
+	}
+	mutex_unlock(&domain_mutex);
+	return NULL;
+}
+
+static int add_domain(struct msm_iova_data *node)
+{
+	struct rb_root *root = &domain_root;
+	struct rb_node **p = &root->rb_node;
+	struct rb_node *parent = NULL;
+
+	mutex_lock(&domain_mutex);
+	while (*p) {
+		struct msm_iova_data *tmp;
+		parent = *p;
+
+		tmp = rb_entry(parent, struct msm_iova_data, node);
+
+		if (node->domain_num < tmp->domain_num)
+			p = &(*p)->rb_left;
+		else if (node->domain_num > tmp->domain_num)
+			p = &(*p)->rb_right;
+		else
+			BUG();
+	}
+	rb_link_node(&node->node, parent, p);
+	rb_insert_color(&node->node, root);
+	mutex_unlock(&domain_mutex);
+	return 0;
+}
+
+struct iommu_domain *msm_get_iommu_domain(int domain_num)
+{
+	struct msm_iova_data *data;
+
+	data = find_domain(domain_num);
+
+	if (data)
+		return data->domain;
+	else
+		return NULL;
+}
+
+int msm_allocate_iova_address(unsigned int iommu_domain,
+					unsigned int partition_no,
+					unsigned long size,
+					unsigned long align,
+					unsigned long *iova)
+{
+	struct msm_iova_data *data;
+	struct mem_pool *pool;
+	unsigned long va;
+
+	data = find_domain(iommu_domain);
+
+	if (!data)
+		return -EINVAL;
+
+	if (partition_no >= data->npools)
+		return -EINVAL;
+
+	pool = &data->pools[partition_no];
+
+	if (!pool->gpool)
+		return -EINVAL;
+
+	va = gen_pool_alloc_aligned(pool->gpool, size, ilog2(align));
+	if (va) {
+		pool->free -= size;
+		/* Offset because genpool can't handle 0 addresses */
+		if (pool->paddr == 0)
+			va -= SZ_4K;
+		*iova = va;
+		return 0;
+	}
+
+	return -ENOMEM;
+}
+
+void msm_free_iova_address(unsigned long iova,
+				unsigned int iommu_domain,
+				unsigned int partition_no,
+				unsigned long size)
+{
+	struct msm_iova_data *data;
+	struct mem_pool *pool;
+
+	data = find_domain(iommu_domain);
+
+	if (!data) {
+		WARN(1, "Invalid domain %d\n", iommu_domain);
+		return;
+	}
+
+	if (partition_no >= data->npools) {
+		WARN(1, "Invalid partition %d for domain %d\n",
+			partition_no, iommu_domain);
+		return;
+	}
+
+	pool = &data->pools[partition_no];
+
+	if (!pool)
+		return;
+
+	pool->free += size;
+
+	/* Offset because genpool can't handle 0 addresses */
+	if (pool->paddr == 0)
+		iova += SZ_4K;
+
+	gen_pool_free(pool->gpool, iova, size);
+}
+
+int msm_register_domain(struct msm_iova_layout *layout)
+{
+	int i;
+	struct msm_iova_data *data;
+	struct mem_pool *pools;
+
+	if (!layout)
+		return -EINVAL;
+
+	data = kmalloc(sizeof(*data), GFP_KERNEL);
+
+	if (!data)
+		return -ENOMEM;
+
+	pools = kmalloc(sizeof(struct mem_pool) * layout->npartitions,
+			GFP_KERNEL);
+
+	if (!pools)
+		goto out;
+
+	for (i = 0; i < layout->npartitions; i++) {
+		if (layout->partitions[i].size == 0)
+			continue;
+
+		pools[i].gpool = gen_pool_create(PAGE_SHIFT, -1);
+
+		if (!pools[i].gpool)
+			continue;
+
+		pools[i].paddr = layout->partitions[i].start;
+		pools[i].size = layout->partitions[i].size;
+
+		/*
+		 * genalloc can't handle a pool starting at address 0.
+		 * For now, solve this problem by offsetting the value
+		 * put in by 4k.
+		 * gen pool address = actual address + 4k
+		 */
+		if (pools[i].paddr == 0)
+			layout->partitions[i].start += SZ_4K;
+
+		if (gen_pool_add(pools[i].gpool,
+			layout->partitions[i].start,
+			layout->partitions[i].size, -1)) {
+			gen_pool_destroy(pools[i].gpool);
+			pools[i].gpool = NULL;
+			continue;
+		}
+	}
+
+	data->pools = pools;
+	data->npools = layout->npartitions;
+	data->domain_num = atomic_inc_return(&domain_nums);
+	data->domain = iommu_domain_alloc(&platform_bus_type,
+					  layout->domain_flags);
+
+	add_domain(data);
+
+	return data->domain_num;
+
+out:
+	kfree(data);
+
+	return -EINVAL;
+}
+
+int msm_use_iommu()
+{
+	return iommu_present(&platform_bus_type);
+}
+
+static int __init iommu_domain_probe(struct platform_device *pdev)
+{
+	struct iommu_domains_pdata *p  = pdev->dev.platform_data;
+	int i, j;
+
+	if (!p)
+		return -ENODEV;
+
+	for (i = 0; i < p->ndomains; i++) {
+		struct msm_iova_layout l;
+		struct msm_iova_partition *part;
+		struct msm_iommu_domain *domains;
+
+		domains = p->domains;
+		l.npartitions = domains[i].npools;
+		part = kmalloc(
+			sizeof(struct msm_iova_partition) * l.npartitions,
+				GFP_KERNEL);
+
+		if (!part) {
+			pr_info("%s: could not allocate space for domain %d",
+				__func__, i);
+			continue;
+		}
+
+		for (j = 0; j < l.npartitions; j++) {
+			part[j].start = p->domains[i].iova_pools[j].paddr;
+			part[j].size = p->domains[i].iova_pools[j].size;
+		}
+
+		l.partitions = part;
+
+		msm_register_domain(&l);
+
+		kfree(part);
+	}
+
+	for (i = 0; i < p->nnames; i++) {
+		struct device *ctx = msm_iommu_get_ctx(
+						p->domain_names[i].name);
+		struct iommu_domain *domain;
+
+		if (!ctx)
+			continue;
+
+		domain = msm_get_iommu_domain(p->domain_names[i].domain);
+
+		if (!domain)
+			continue;
+
+		if (iommu_attach_device(domain, ctx)) {
+			WARN(1, "%s: could not attach domain %p to context %s."
+				" iommu programming will not occur.\n",
+				__func__, domain,
+				p->domain_names[i].name);
+			continue;
+		}
+	}
+
+	return 0;
+}
+
+static struct platform_driver iommu_domain_driver = {
+	.driver         = {
+		.name = "iommu_domains",
+		.owner = THIS_MODULE
+	},
+};
+
+static int __init msm_subsystem_iommu_init(void)
+{
+	return platform_driver_probe(&iommu_domain_driver, iommu_domain_probe);
+}
+device_initcall(msm_subsystem_iommu_init);
diff --git a/arch/arm/mach-msm/ipc_logging.c b/arch/arm/mach-msm/ipc_logging.c
new file mode 100644
index 0000000..2cd30de
--- /dev/null
+++ b/arch/arm/mach-msm/ipc_logging.c
@@ -0,0 +1,556 @@
+/* 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/slab.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/jiffies.h>
+#include <linux/debugfs.h>
+#include <linux/io.h>
+#include <linux/idr.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+
+#include <mach/msm_ipc_logging.h>
+
+#include "ipc_logging.h"
+
+static LIST_HEAD(ipc_log_context_list);
+DEFINE_SPINLOCK(ipc_log_context_list_lock);
+static atomic_t next_log_id = ATOMIC_INIT(0);
+
+static struct ipc_log_page *get_first_page(struct ipc_log_context *ilctxt)
+{
+	struct ipc_log_page_header *p_pghdr;
+	struct ipc_log_page *pg = NULL;
+
+	if (!ilctxt)
+		return NULL;
+	p_pghdr = list_first_entry(&ilctxt->page_list,
+				   struct ipc_log_page_header, list);
+	pg = container_of(p_pghdr, struct ipc_log_page, hdr);
+	return pg;
+}
+
+static struct ipc_log_page *get_next_page(struct ipc_log_context *ilctxt,
+					  struct ipc_log_page *cur_pg)
+{
+	struct ipc_log_page_header *p_pghdr;
+	struct ipc_log_page *pg = NULL;
+
+	if (!ilctxt || !cur_pg)
+		return NULL;
+
+	if (ilctxt->last_page == cur_pg)
+		return ilctxt->first_page;
+
+	p_pghdr = list_first_entry(&cur_pg->hdr.list,
+			struct ipc_log_page_header, list);
+	pg = container_of(p_pghdr, struct ipc_log_page, hdr);
+
+	return pg;
+}
+
+/* If data == NULL, drop the log of size data_size*/
+static void ipc_log_read(struct ipc_log_context *ilctxt,
+			 void *data, int data_size)
+{
+	int bytes_to_read;
+
+	bytes_to_read = MIN(((PAGE_SIZE - sizeof(struct ipc_log_page_header))
+				- ilctxt->read_page->hdr.read_offset),
+			      data_size);
+	if (data)
+		memcpy(data, (ilctxt->read_page->data +
+			ilctxt->read_page->hdr.read_offset), bytes_to_read);
+	if (bytes_to_read != data_size) {
+		ilctxt->read_page->hdr.read_offset = 0xFFFF;
+		ilctxt->read_page = get_next_page(ilctxt, ilctxt->read_page);
+		ilctxt->read_page->hdr.read_offset = 0;
+		if (data)
+			memcpy((data + bytes_to_read),
+			       (ilctxt->read_page->data +
+				ilctxt->read_page->hdr.read_offset),
+			       (data_size - bytes_to_read));
+		bytes_to_read = (data_size - bytes_to_read);
+	}
+	ilctxt->read_page->hdr.read_offset += bytes_to_read;
+	ilctxt->write_avail += data_size;
+}
+
+/*
+ * Reads a message.
+ *
+ * If a message is read successfully, then the the message context
+ * will be set to:
+ *     .hdr    message header .size and .type values
+ *     .offset beginning of message data
+ *
+ * @ectxt   Message context and if NULL, drops the message.
+ *
+ * @returns 0  - no message available
+ *          1  - message read
+ */
+int msg_read(struct ipc_log_context *ilctxt,
+	     struct encode_context *ectxt)
+{
+	struct tsv_header hdr;
+
+	ipc_log_read(ilctxt, &hdr, sizeof(hdr));
+	if (ectxt) {
+		ectxt->hdr.type = hdr.type;
+		ectxt->hdr.size = hdr.size;
+		ectxt->offset = sizeof(hdr);
+		ipc_log_read(ilctxt, (ectxt->buff + ectxt->offset),
+			     (int)hdr.size);
+	} else {
+		ipc_log_read(ilctxt, NULL, (int)hdr.size);
+	}
+	return sizeof(hdr) + (int)hdr.size;
+}
+
+/*
+ * Commits messages to the FIFO.  If the FIFO is full, then enough
+ * messages are dropped to create space for the new message.
+ */
+void ipc_log_write(void *ctxt, struct encode_context *ectxt)
+{
+	struct ipc_log_context *ilctxt = (struct ipc_log_context *)ctxt;
+	int bytes_to_write;
+	unsigned long flags;
+
+	if (!ilctxt || !ectxt) {
+		pr_err("%s: Invalid ipc_log or encode context\n", __func__);
+		return;
+	}
+
+	spin_lock_irqsave(&ipc_log_context_list_lock, flags);
+	spin_lock(&ilctxt->ipc_log_context_lock);
+	while (ilctxt->write_avail < ectxt->offset)
+		msg_read(ilctxt, NULL);
+
+	bytes_to_write = MIN(((PAGE_SIZE - sizeof(struct ipc_log_page_header))
+				- ilctxt->write_page->hdr.write_offset),
+				ectxt->offset);
+	memcpy((ilctxt->write_page->data +
+		ilctxt->write_page->hdr.write_offset),
+		ectxt->buff, bytes_to_write);
+	if (bytes_to_write != ectxt->offset) {
+		ilctxt->write_page->hdr.write_offset = 0xFFFF;
+		ilctxt->write_page = get_next_page(ilctxt, ilctxt->write_page);
+		ilctxt->write_page->hdr.write_offset = 0;
+		memcpy((ilctxt->write_page->data +
+			ilctxt->write_page->hdr.write_offset),
+		       (ectxt->buff + bytes_to_write),
+		       (ectxt->offset - bytes_to_write));
+		bytes_to_write = (ectxt->offset - bytes_to_write);
+	}
+	ilctxt->write_page->hdr.write_offset += bytes_to_write;
+	ilctxt->write_avail -= ectxt->offset;
+	complete(&ilctxt->read_avail);
+	spin_unlock(&ilctxt->ipc_log_context_lock);
+	spin_unlock_irqrestore(&ipc_log_context_list_lock, flags);
+}
+EXPORT_SYMBOL(ipc_log_write);
+
+/*
+ * Starts a new message after which you can add serialized data and
+ * then complete the message by calling msg_encode_end().
+ */
+void msg_encode_start(struct encode_context *ectxt, uint32_t type)
+{
+	if (!ectxt) {
+		pr_err("%s: Invalid encode context\n", __func__);
+		return;
+	}
+
+	ectxt->hdr.type = type;
+	ectxt->hdr.size = 0;
+	ectxt->offset = sizeof(ectxt->hdr);
+}
+EXPORT_SYMBOL(msg_encode_start);
+
+/*
+ * Completes the message
+ */
+void msg_encode_end(struct encode_context *ectxt)
+{
+	if (!ectxt) {
+		pr_err("%s: Invalid encode context\n", __func__);
+		return;
+	}
+
+	/* finalize data size */
+	ectxt->hdr.size = ectxt->offset - sizeof(ectxt->hdr);
+	BUG_ON(ectxt->hdr.size > MAX_MSG_SIZE);
+	memcpy(ectxt->buff, &ectxt->hdr, sizeof(ectxt->hdr));
+}
+EXPORT_SYMBOL(msg_encode_end);
+
+/*
+ * Helper funtion used to write data to a message context.
+ *
+ * @ectxt context initialized by calling msg_encode_start()
+ * @data  data to write
+ * @size  number of bytes of data to write
+ */
+static inline int tsv_write_data(struct encode_context *ectxt,
+				 void *data, uint32_t size)
+{
+	if (!ectxt) {
+		pr_err("%s: Invalid encode context\n", __func__);
+		return -EINVAL;
+	}
+	if ((ectxt->offset + size) > MAX_MSG_SIZE) {
+		pr_err("%s: No space to encode further\n", __func__);
+		return -EINVAL;
+	}
+
+	memcpy((void *)(ectxt->buff + ectxt->offset), data, size);
+	ectxt->offset += size;
+	return 0;
+}
+
+/*
+ * Helper function that writes a type to the context.
+ *
+ * @ectxt context initialized by calling msg_encode_start()
+ * @type  primitive type
+ * @size  size of primitive in bytes
+ */
+static inline int tsv_write_header(struct encode_context *ectxt,
+				   uint32_t type, uint32_t size)
+{
+	struct tsv_header hdr;
+
+	hdr.type = (unsigned char)type;
+	hdr.size = (unsigned char)size;
+	return tsv_write_data(ectxt, &hdr, sizeof(hdr));
+}
+
+/*
+ * Writes the current timestamp count.
+ *
+ * @ectxt   context initialized by calling msg_encode_start()
+ */
+int tsv_timestamp_write(struct encode_context *ectxt)
+{
+	int ret;
+	unsigned long long t_now = sched_clock();
+
+	ret = tsv_write_header(ectxt, TSV_TYPE_TIMESTAMP, sizeof(t_now));
+	if (ret)
+		return ret;
+	return tsv_write_data(ectxt, &t_now, sizeof(t_now));
+}
+EXPORT_SYMBOL(tsv_timestamp_write);
+
+/*
+ * Writes a data pointer.
+ *
+ * @ectxt   context initialized by calling msg_encode_start()
+ * @pointer pointer value to write
+ */
+int tsv_pointer_write(struct encode_context *ectxt, void *pointer)
+{
+	int ret;
+	ret = tsv_write_header(ectxt, TSV_TYPE_POINTER, sizeof(pointer));
+	if (ret)
+		return ret;
+	return tsv_write_data(ectxt, &pointer, sizeof(pointer));
+}
+EXPORT_SYMBOL(tsv_pointer_write);
+
+/*
+ * Writes a 32-bit integer value.
+ *
+ * @ectxt context initialized by calling msg_encode_start()
+ * @n     integer to write
+ */
+int tsv_int32_write(struct encode_context *ectxt, int32_t n)
+{
+	int ret;
+	ret = tsv_write_header(ectxt, TSV_TYPE_INT32, sizeof(n));
+	if (ret)
+		return ret;
+	return tsv_write_data(ectxt, &n, sizeof(n));
+}
+EXPORT_SYMBOL(tsv_int32_write);
+
+/*
+ * Writes a byte array.
+ *
+ * @ectxt context initialized by calling msg_write_start()
+ * @data  Beginning address of data
+ * @data_size Size of data to be written
+ */
+int tsv_byte_array_write(struct encode_context *ectxt,
+			 void *data, int data_size)
+{
+	int ret;
+	ret = tsv_write_header(ectxt, TSV_TYPE_BYTE_ARRAY, data_size);
+	if (ret)
+		return ret;
+	return tsv_write_data(ectxt, data, data_size);
+}
+EXPORT_SYMBOL(tsv_byte_array_write);
+
+/*
+ * Helper function to log a string
+ *
+ * @ilctxt ipc_log_context created using ipc_log_context_create()
+ * @fmt Data specified using format specifiers
+ */
+int ipc_log_string(void *ilctxt, const char *fmt, ...)
+{
+	struct encode_context ectxt;
+	int avail_size, data_size, hdr_size = sizeof(struct tsv_header);
+	va_list arg_list;
+
+	if (!ilctxt)
+		return -EINVAL;
+
+	msg_encode_start(&ectxt, TSV_TYPE_STRING);
+	tsv_timestamp_write(&ectxt);
+	avail_size = (MAX_MSG_SIZE - (ectxt.offset + hdr_size));
+	va_start(arg_list, fmt);
+	data_size = vsnprintf((ectxt.buff + ectxt.offset + hdr_size),
+			      avail_size, fmt, arg_list);
+	va_end(arg_list);
+	tsv_write_header(&ectxt, TSV_TYPE_BYTE_ARRAY, data_size);
+	ectxt.offset += data_size;
+	msg_encode_end(&ectxt);
+	ipc_log_write(ilctxt, &ectxt);
+	return 0;
+}
+
+/*
+ * Helper funtion used to read data from a message context.
+ *
+ * @ectxt  context initialized by calling msg_read()
+ * @data  data to read
+ * @size  number of bytes of data to read
+ */
+static void tsv_read_data(struct encode_context *ectxt,
+			  void *data, uint32_t size)
+{
+	BUG_ON((ectxt->offset + size) > MAX_MSG_SIZE);
+	memcpy(data, (ectxt->buff + ectxt->offset), size);
+	ectxt->offset += size;
+}
+
+/*
+ * Helper function that reads a type from the context and updates the
+ * context pointers.
+ *
+ * @ectxt  context initialized by calling msg_read()
+ * @hdr   type header
+ */
+static void tsv_read_header(struct encode_context *ectxt,
+			    struct tsv_header *hdr)
+{
+	BUG_ON((ectxt->offset + sizeof(*hdr)) > MAX_MSG_SIZE);
+	memcpy(hdr, (ectxt->buff + ectxt->offset), sizeof(*hdr));
+	ectxt->offset += sizeof(*hdr);
+}
+
+/*
+ * Reads a timestamp.
+ *
+ * @ectxt   context initialized by calling msg_read()
+ * @dctxt   deserialization context
+ * @format output format (appended to %6u.%09u timestamp format)
+ */
+void tsv_timestamp_read(struct encode_context *ectxt,
+			struct decode_context *dctxt, const char *format)
+{
+	struct tsv_header hdr;
+	unsigned long long val;
+	unsigned long nanosec_rem;
+
+	tsv_read_header(ectxt, &hdr);
+	BUG_ON(hdr.type != TSV_TYPE_TIMESTAMP);
+	tsv_read_data(ectxt, &val, sizeof(val));
+	nanosec_rem = do_div(val, 1000000000U);
+	IPC_SPRINTF_DECODE(dctxt, "[%6u.%09lu]%s",
+			(unsigned)val, nanosec_rem, format);
+}
+EXPORT_SYMBOL(tsv_timestamp_read);
+
+/*
+ * Reads a data pointer.
+ *
+ * @ectxt   context initialized by calling msg_read()
+ * @dctxt   deserialization context
+ * @format output format
+ */
+void tsv_pointer_read(struct encode_context *ectxt,
+		      struct decode_context *dctxt, const char *format)
+{
+	struct tsv_header hdr;
+	void *val;
+
+	tsv_read_header(ectxt, &hdr);
+	BUG_ON(hdr.type != TSV_TYPE_POINTER);
+	tsv_read_data(ectxt, &val, sizeof(val));
+
+	IPC_SPRINTF_DECODE(dctxt, format, val);
+}
+EXPORT_SYMBOL(tsv_pointer_read);
+
+/*
+ * Reads a 32-bit integer value.
+ *
+ * @ectxt   context initialized by calling msg_read()
+ * @dctxt   deserialization context
+ * @format output format
+ */
+int32_t tsv_int32_read(struct encode_context *ectxt,
+		       struct decode_context *dctxt, const char *format)
+{
+	struct tsv_header hdr;
+	int32_t val;
+
+	tsv_read_header(ectxt, &hdr);
+	BUG_ON(hdr.type != TSV_TYPE_INT32);
+	tsv_read_data(ectxt, &val, sizeof(val));
+
+	IPC_SPRINTF_DECODE(dctxt, format, val);
+	return val;
+}
+EXPORT_SYMBOL(tsv_int32_read);
+
+/*
+ * Reads a byte array/string.
+ *
+ * @ectxt   context initialized by calling msg_read()
+ * @dctxt   deserialization context
+ * @format output format
+ */
+void tsv_byte_array_read(struct encode_context *ectxt,
+			 struct decode_context *dctxt, const char *format)
+{
+	struct tsv_header hdr;
+
+	tsv_read_header(ectxt, &hdr);
+	BUG_ON(hdr.type != TSV_TYPE_BYTE_ARRAY);
+	tsv_read_data(ectxt, dctxt->buff, hdr.size);
+	dctxt->buff += hdr.size;
+	dctxt->size -= hdr.size;
+}
+EXPORT_SYMBOL(tsv_byte_array_read);
+
+int add_deserialization_func(void *ctxt, int type,
+			void (*dfunc)(struct encode_context *,
+				      struct decode_context *))
+{
+	struct ipc_log_context *ilctxt = (struct ipc_log_context *)ctxt;
+	struct dfunc_info *df_info;
+	unsigned long flags;
+
+	if (!ilctxt || !dfunc)
+		return -EINVAL;
+
+	df_info = kmalloc(sizeof(struct dfunc_info), GFP_KERNEL);
+	if (!df_info)
+		return -ENOSPC;
+
+	spin_lock_irqsave(&ipc_log_context_list_lock, flags);
+	spin_lock(&ilctxt->ipc_log_context_lock);
+	df_info->type = type;
+	df_info->dfunc = dfunc;
+	list_add_tail(&df_info->list, &ilctxt->dfunc_info_list);
+	spin_unlock(&ilctxt->ipc_log_context_lock);
+	spin_unlock_irqrestore(&ipc_log_context_list_lock, flags);
+	return 0;
+}
+EXPORT_SYMBOL(add_deserialization_func);
+
+void *ipc_log_context_create(int max_num_pages,
+			     const char *mod_name)
+{
+	struct ipc_log_context *ctxt;
+	struct ipc_log_page *pg = NULL;
+	int page_cnt, local_log_id;
+	unsigned long flags;
+
+	ctxt = kzalloc(sizeof(struct ipc_log_context), GFP_KERNEL);
+	if (!ctxt) {
+		pr_err("%s: cannot create ipc_log_context\n", __func__);
+		return 0;
+	}
+
+	local_log_id = atomic_add_return(1, &next_log_id);
+	init_completion(&ctxt->read_avail);
+	INIT_LIST_HEAD(&ctxt->page_list);
+	INIT_LIST_HEAD(&ctxt->dfunc_info_list);
+	spin_lock_init(&ctxt->ipc_log_context_lock);
+	for (page_cnt = 0; page_cnt < max_num_pages; page_cnt++) {
+		pg = kzalloc(sizeof(struct ipc_log_page), GFP_KERNEL);
+		if (!pg) {
+			pr_err("%s: cannot create ipc_log_page\n", __func__);
+			goto release_ipc_log_context;
+		}
+		pg->hdr.magic = IPC_LOGGING_MAGIC_NUM;
+		pg->hdr.nmagic = ~(IPC_LOGGING_MAGIC_NUM);
+		pg->hdr.log_id = (uint32_t)local_log_id;
+		pg->hdr.page_num = page_cnt;
+		pg->hdr.read_offset = 0xFFFF;
+		pg->hdr.write_offset = 0xFFFF;
+		spin_lock_irqsave(&ctxt->ipc_log_context_lock, flags);
+		list_add_tail(&pg->hdr.list, &ctxt->page_list);
+		spin_unlock_irqrestore(&ctxt->ipc_log_context_lock, flags);
+	}
+	ctxt->first_page = get_first_page(ctxt);
+	ctxt->last_page = pg;
+	ctxt->write_page = ctxt->first_page;
+	ctxt->read_page = ctxt->first_page;
+	ctxt->write_page->hdr.write_offset = 0;
+	ctxt->read_page->hdr.read_offset = 0;
+	ctxt->write_avail = max_num_pages * (PAGE_SIZE -
+					sizeof(struct ipc_log_page_header));
+
+	create_ctx_debugfs(ctxt, mod_name);
+
+	spin_lock_irqsave(&ipc_log_context_list_lock, flags);
+	list_add_tail(&ctxt->list, &ipc_log_context_list);
+	spin_unlock_irqrestore(&ipc_log_context_list_lock, flags);
+	return (void *)ctxt;
+
+release_ipc_log_context:
+	while (page_cnt-- > 0) {
+		pg = get_first_page(ctxt);
+		list_del(&pg->hdr.list);
+		kfree(pg);
+	}
+	kfree(ctxt);
+	return 0;
+}
+EXPORT_SYMBOL(ipc_log_context_create);
+
+static int __init ipc_logging_init(void)
+{
+	check_and_create_debugfs();
+	return 0;
+}
+
+module_init(ipc_logging_init);
+
+MODULE_DESCRIPTION("ipc logging");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/ipc_logging.h b/arch/arm/mach-msm/ipc_logging.h
new file mode 100644
index 0000000..5e614ab
--- /dev/null
+++ b/arch/arm/mach-msm/ipc_logging.h
@@ -0,0 +1,98 @@
+/* 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 _IPC_LOGGING_H
+#define _IPC_LOGGING_H
+
+struct ipc_log_page_header {
+	uint32_t magic;
+	uint32_t nmagic; /* inverse of magic number */
+	uint32_t log_id; /* owner of log */
+	uint32_t page_num;
+	uint16_t read_offset;
+	uint16_t write_offset;
+	struct list_head list;
+};
+
+struct ipc_log_page {
+	struct ipc_log_page_header hdr;
+	char data[PAGE_SIZE - sizeof(struct ipc_log_page_header)];
+};
+
+struct ipc_log_context {
+	struct list_head list;
+	struct list_head page_list;
+	struct ipc_log_page *first_page;
+	struct ipc_log_page *last_page;
+	struct ipc_log_page *write_page;
+	struct ipc_log_page *read_page;
+	uint32_t write_avail;
+	struct dentry *dent;
+	struct list_head dfunc_info_list;
+	spinlock_t ipc_log_context_lock;
+	struct completion read_avail;
+};
+
+struct dfunc_info {
+	struct list_head list;
+	int type;
+	void (*dfunc) (struct encode_context *, struct decode_context *);
+};
+
+enum {
+	TSV_TYPE_INVALID,
+	TSV_TYPE_TIMESTAMP,
+	TSV_TYPE_POINTER,
+	TSV_TYPE_INT32,
+	TSV_TYPE_BYTE_ARRAY,
+};
+
+enum {
+	OUTPUT_DEBUGFS,
+};
+
+#define IPC_LOGGING_MAGIC_NUM 0x52784425
+#define MIN(x, y) ((x) < (y) ? (x) : (y))
+#define IS_MSG_TYPE(x) (((x) > TSV_TYPE_MSG_START) && \
+			((x) < TSV_TYPE_MSG_END))
+
+extern spinlock_t ipc_log_context_list_lock;
+
+extern int msg_read(struct ipc_log_context *ilctxt,
+		    struct encode_context *ectxt);
+
+static inline int is_ilctxt_empty(struct ipc_log_context *ilctxt)
+{
+	if (!ilctxt)
+		return -EINVAL;
+
+	return ((ilctxt->read_page == ilctxt->write_page) &&
+		(ilctxt->read_page->hdr.read_offset ==
+		 ilctxt->write_page->hdr.write_offset));
+}
+
+#if (defined(CONFIG_DEBUG_FS))
+void check_and_create_debugfs(void);
+
+void create_ctx_debugfs(struct ipc_log_context *ctxt,
+			const char *mod_name);
+#else
+void check_and_create_debugfs(void)
+{
+}
+
+void create_ctx_debugfs(struct ipc_log_context *ctxt, const char *mod_name)
+{
+}
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/ipc_logging_debug.c b/arch/arm/mach-msm/ipc_logging_debug.c
new file mode 100644
index 0000000..5f7a95e
--- /dev/null
+++ b/arch/arm/mach-msm/ipc_logging_debug.c
@@ -0,0 +1,225 @@
+/* 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/slab.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/jiffies.h>
+#include <linux/debugfs.h>
+#include <linux/io.h>
+#include <linux/idr.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+
+#include <mach/msm_ipc_logging.h>
+
+#include "ipc_logging.h"
+
+static DEFINE_MUTEX(ipc_log_debugfs_init_lock);
+static struct dentry *root_dent;
+#define MAX_MSG_DECODED_SIZE (MAX_MSG_SIZE*4)
+
+static void *get_deserialization_func(struct ipc_log_context *ilctxt,
+				      int type)
+{
+	struct dfunc_info *df_info = NULL;
+
+	if (!ilctxt)
+		return NULL;
+
+	list_for_each_entry(df_info, &ilctxt->dfunc_info_list, list) {
+		if (df_info->type == type)
+			return df_info->dfunc;
+	}
+	return NULL;
+}
+
+static int deserialize_log(struct ipc_log_context *ilctxt,
+			   char *buff, int size)
+{
+	struct encode_context ectxt;
+	struct decode_context dctxt;
+	void (*deserialize_func)(struct encode_context *ectxt,
+				 struct decode_context *dctxt);
+	unsigned long flags;
+
+	dctxt.output_format = OUTPUT_DEBUGFS;
+	dctxt.buff = buff;
+	dctxt.size = size;
+	spin_lock_irqsave(&ipc_log_context_list_lock, flags);
+	spin_lock(&ilctxt->ipc_log_context_lock);
+	while (dctxt.size >= MAX_MSG_DECODED_SIZE &&
+	       !is_ilctxt_empty(ilctxt)) {
+		msg_read(ilctxt, &ectxt);
+		deserialize_func = get_deserialization_func(ilctxt,
+							ectxt.hdr.type);
+		spin_unlock(&ilctxt->ipc_log_context_lock);
+		spin_unlock_irqrestore(&ipc_log_context_list_lock, flags);
+		if (deserialize_func)
+			deserialize_func(&ectxt, &dctxt);
+		else
+			pr_err("%s: unknown message 0x%x\n",
+				__func__, ectxt.hdr.type);
+		spin_lock_irqsave(&ipc_log_context_list_lock, flags);
+		spin_lock(&ilctxt->ipc_log_context_lock);
+	}
+	if ((size - dctxt.size) == 0)
+		init_completion(&ilctxt->read_avail);
+	spin_unlock(&ilctxt->ipc_log_context_lock);
+	spin_unlock_irqrestore(&ipc_log_context_list_lock, flags);
+	return size - dctxt.size;
+}
+
+static int debug_log(struct ipc_log_context *ilctxt,
+		     char *buff, int size, int cont)
+{
+	int i = 0;
+
+	if (size < MAX_MSG_DECODED_SIZE) {
+		pr_err("%s: buffer size %d < %d\n", __func__, size,
+			MAX_MSG_DECODED_SIZE);
+		return -ENOMEM;
+	}
+	do {
+		i = deserialize_log(ilctxt, buff, size - 1);
+		if (cont && i == 0) {
+			wait_for_completion_interruptible(&ilctxt->read_avail);
+			if (signal_pending(current))
+				break;
+		}
+	} while (cont && i == 0);
+
+	return i;
+}
+
+/*
+ * VFS Read operation helper which dispatches the call to the debugfs
+ * read command stored in file->private_data.
+ *
+ * @file  File structure
+ * @buff   user buffer
+ * @count size of user buffer
+ * @ppos  file position to read from (only a value of 0 is accepted)
+ * @cont  1 = continuous mode (don't return 0 to signal end-of-file)
+ *
+ * @returns ==0 end of file
+ *           >0 number of bytes read
+ *           <0 error
+ */
+static ssize_t debug_read_helper(struct file *file, char __user *buff,
+				 size_t count, loff_t *ppos, int cont)
+{
+	struct ipc_log_context *ilctxt = file->private_data;
+	char *buffer;
+	int bsize;
+
+	buffer = kmalloc(count, GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	bsize = debug_log(ilctxt, buffer, count, cont);
+	if (bsize > 0) {
+		if (copy_to_user(buff, buffer, bsize)) {
+			kfree(buffer);
+			return -EFAULT;
+		}
+		*ppos += bsize;
+	}
+	kfree(buffer);
+	return bsize;
+}
+
+static ssize_t debug_read(struct file *file, char __user *buff,
+			  size_t count, loff_t *ppos)
+{
+	return debug_read_helper(file, buff, count, ppos, 0);
+}
+
+static ssize_t debug_read_cont(struct file *file, char __user *buff,
+			       size_t count, loff_t *ppos)
+{
+	return debug_read_helper(file, buff, count, ppos, 1);
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static const struct file_operations debug_ops = {
+	.read = debug_read,
+	.open = debug_open,
+};
+
+static const struct file_operations debug_ops_cont = {
+	.read = debug_read_cont,
+	.open = debug_open,
+};
+
+static void debug_create(const char *name, mode_t mode,
+			 struct dentry *dent,
+			 struct ipc_log_context *ilctxt,
+			 const struct file_operations *fops)
+{
+	debugfs_create_file(name, mode, dent, ilctxt, fops);
+}
+
+static void dfunc_string(struct encode_context *ectxt,
+			 struct decode_context *dctxt)
+{
+	tsv_timestamp_read(ectxt, dctxt, " ");
+	tsv_byte_array_read(ectxt, dctxt, "");
+}
+
+void check_and_create_debugfs(void)
+{
+	mutex_lock(&ipc_log_debugfs_init_lock);
+	if (!root_dent) {
+		root_dent = debugfs_create_dir("ipc_logging", 0);
+
+		if (IS_ERR(root_dent)) {
+			pr_err("%s: unable to create debugfs %ld\n",
+				__func__, IS_ERR(root_dent));
+			root_dent = NULL;
+		}
+	}
+	mutex_unlock(&ipc_log_debugfs_init_lock);
+}
+EXPORT_SYMBOL(check_and_create_debugfs);
+
+void create_ctx_debugfs(struct ipc_log_context *ctxt,
+			const char *mod_name)
+{
+	if (!root_dent)
+		check_and_create_debugfs();
+
+	if (root_dent) {
+		ctxt->dent = debugfs_create_dir(mod_name, root_dent);
+		if (!IS_ERR(ctxt->dent)) {
+			debug_create("log", 0444, ctxt->dent,
+				     ctxt, &debug_ops);
+			debug_create("log_cont", 0444, ctxt->dent,
+				     ctxt, &debug_ops_cont);
+		}
+	}
+	add_deserialization_func((void *)ctxt,
+				 TSV_TYPE_STRING, dfunc_string);
+}
+EXPORT_SYMBOL(create_ctx_debugfs);
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
new file mode 100644
index 0000000..6fa435a
--- /dev/null
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -0,0 +1,2555 @@
+/* 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
+ * 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.
+ */
+
+#define DEBUG
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/wakelock.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+
+#include <mach/smem_log.h>
+#include <mach/subsystem_notif.h>
+
+#include "ipc_router.h"
+#include "modem_notifier.h"
+
+enum {
+	SMEM_LOG = 1U << 0,
+	RTR_DBG = 1U << 1,
+	R2R_MSG = 1U << 2,
+	R2R_RAW = 1U << 3,
+	NTFY_MSG = 1U << 4,
+	R2R_RAW_HDR = 1U << 5,
+};
+
+static int msm_ipc_router_debug_mask;
+module_param_named(debug_mask, msm_ipc_router_debug_mask,
+		   int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#define DIAG(x...) pr_info("[RR] ERROR " x)
+
+#if defined(DEBUG)
+#define D(x...) do { \
+if (msm_ipc_router_debug_mask & RTR_DBG) \
+	pr_info(x); \
+} while (0)
+
+#define RR(x...) do { \
+if (msm_ipc_router_debug_mask & R2R_MSG) \
+	pr_info("[RR] "x); \
+} while (0)
+
+#define RAW(x...) do { \
+if (msm_ipc_router_debug_mask & R2R_RAW) \
+	pr_info("[RAW] "x); \
+} while (0)
+
+#define NTFY(x...) do { \
+if (msm_ipc_router_debug_mask & NTFY_MSG) \
+	pr_info("[NOTIFY] "x); \
+} while (0)
+
+#define RAW_HDR(x...) do { \
+if (msm_ipc_router_debug_mask & R2R_RAW_HDR) \
+	pr_info("[HDR] "x); \
+} while (0)
+#else
+#define D(x...) do { } while (0)
+#define RR(x...) do { } while (0)
+#define RAW(x...) do { } while (0)
+#define RAW_HDR(x...) do { } while (0)
+#define NTFY(x...) do { } while (0)
+#endif
+
+#define IPC_ROUTER_LOG_EVENT_ERROR      0x10
+#define IPC_ROUTER_LOG_EVENT_TX         0x11
+#define IPC_ROUTER_LOG_EVENT_RX         0x12
+
+static LIST_HEAD(control_ports);
+static DEFINE_MUTEX(control_ports_lock);
+
+#define LP_HASH_SIZE 32
+static struct list_head local_ports[LP_HASH_SIZE];
+static DEFINE_MUTEX(local_ports_lock);
+
+#define SRV_HASH_SIZE 32
+static struct list_head server_list[SRV_HASH_SIZE];
+static DEFINE_MUTEX(server_list_lock);
+static wait_queue_head_t newserver_wait;
+
+struct msm_ipc_server {
+	struct list_head list;
+	struct msm_ipc_port_name name;
+	struct list_head server_port_list;
+};
+
+struct msm_ipc_server_port {
+	struct list_head list;
+	struct msm_ipc_port_addr server_addr;
+	struct msm_ipc_router_xprt_info *xprt_info;
+};
+
+#define RP_HASH_SIZE 32
+struct msm_ipc_router_remote_port {
+	struct list_head list;
+	uint32_t node_id;
+	uint32_t port_id;
+	uint32_t restart_state;
+	wait_queue_head_t quota_wait;
+	uint32_t tx_quota_cnt;
+	struct mutex quota_lock;
+};
+
+struct msm_ipc_router_xprt_info {
+	struct list_head list;
+	struct msm_ipc_router_xprt *xprt;
+	uint32_t remote_node_id;
+	uint32_t initialized;
+	struct list_head pkt_list;
+	wait_queue_head_t read_wait;
+	struct wake_lock wakelock;
+	struct mutex rx_lock;
+	struct mutex tx_lock;
+	uint32_t need_len;
+	uint32_t abort_data_read;
+	struct work_struct read_data;
+	struct workqueue_struct *workqueue;
+};
+
+#define RT_HASH_SIZE 4
+struct msm_ipc_routing_table_entry {
+	struct list_head list;
+	uint32_t node_id;
+	uint32_t neighbor_node_id;
+	struct list_head remote_port_list[RP_HASH_SIZE];
+	struct msm_ipc_router_xprt_info *xprt_info;
+	struct mutex lock;
+	unsigned long num_tx_bytes;
+	unsigned long num_rx_bytes;
+};
+
+static struct list_head routing_table[RT_HASH_SIZE];
+static DEFINE_MUTEX(routing_table_lock);
+static int routing_table_inited;
+
+static LIST_HEAD(msm_ipc_board_dev_list);
+static DEFINE_MUTEX(msm_ipc_board_dev_list_lock);
+
+static void do_read_data(struct work_struct *work);
+
+#define RR_STATE_IDLE    0
+#define RR_STATE_HEADER  1
+#define RR_STATE_BODY    2
+#define RR_STATE_ERROR   3
+
+#define RESTART_NORMAL 0
+#define RESTART_PEND 1
+
+/* State for remote ep following restart */
+#define RESTART_QUOTA_ABORT  1
+
+static LIST_HEAD(xprt_info_list);
+static DEFINE_MUTEX(xprt_info_list_lock);
+
+DECLARE_COMPLETION(msm_ipc_remote_router_up);
+static DECLARE_COMPLETION(msm_ipc_local_router_up);
+#define IPC_ROUTER_INIT_TIMEOUT (10 * HZ)
+
+static uint32_t next_port_id;
+static DEFINE_MUTEX(next_port_id_lock);
+static atomic_t pending_close_count = ATOMIC_INIT(0);
+static wait_queue_head_t subsystem_restart_wait;
+static struct workqueue_struct *msm_ipc_router_workqueue;
+
+enum {
+	CLIENT_PORT,
+	SERVER_PORT,
+	CONTROL_PORT,
+};
+
+enum {
+	DOWN,
+	UP,
+};
+
+static void init_routing_table(void)
+{
+	int i;
+	for (i = 0; i < RT_HASH_SIZE; i++)
+		INIT_LIST_HEAD(&routing_table[i]);
+}
+
+static struct msm_ipc_routing_table_entry *alloc_routing_table_entry(
+	uint32_t node_id)
+{
+	int i;
+	struct msm_ipc_routing_table_entry *rt_entry;
+
+	rt_entry = kmalloc(sizeof(struct msm_ipc_routing_table_entry),
+			   GFP_KERNEL);
+	if (!rt_entry) {
+		pr_err("%s: rt_entry allocation failed for %d\n",
+			__func__, node_id);
+		return NULL;
+	}
+
+	for (i = 0; i < RP_HASH_SIZE; i++)
+		INIT_LIST_HEAD(&rt_entry->remote_port_list[i]);
+
+	mutex_init(&rt_entry->lock);
+	rt_entry->node_id = node_id;
+	rt_entry->xprt_info = NULL;
+	return rt_entry;
+}
+
+/*Please take routing_table_lock before calling this function*/
+static int add_routing_table_entry(
+	struct msm_ipc_routing_table_entry *rt_entry)
+{
+	uint32_t key;
+
+	if (!rt_entry)
+		return -EINVAL;
+
+	key = (rt_entry->node_id % RT_HASH_SIZE);
+	list_add_tail(&rt_entry->list, &routing_table[key]);
+	return 0;
+}
+
+/*Please take routing_table_lock before calling this function*/
+static struct msm_ipc_routing_table_entry *lookup_routing_table(
+	uint32_t node_id)
+{
+	uint32_t key = (node_id % RT_HASH_SIZE);
+	struct msm_ipc_routing_table_entry *rt_entry;
+
+	list_for_each_entry(rt_entry, &routing_table[key], list) {
+		if (rt_entry->node_id == node_id)
+			return rt_entry;
+	}
+	return NULL;
+}
+
+struct rr_packet *rr_read(struct msm_ipc_router_xprt_info *xprt_info)
+{
+	struct rr_packet *temp_pkt;
+
+	if (!xprt_info)
+		return NULL;
+
+	mutex_lock(&xprt_info->rx_lock);
+	while (!(xprt_info->abort_data_read) &&
+		list_empty(&xprt_info->pkt_list)) {
+		mutex_unlock(&xprt_info->rx_lock);
+		wait_event(xprt_info->read_wait,
+			   ((xprt_info->abort_data_read) ||
+			   !list_empty(&xprt_info->pkt_list)));
+		mutex_lock(&xprt_info->rx_lock);
+	}
+	if (xprt_info->abort_data_read) {
+		mutex_unlock(&xprt_info->rx_lock);
+		return NULL;
+	}
+
+	temp_pkt = list_first_entry(&xprt_info->pkt_list,
+				    struct rr_packet, list);
+	list_del(&temp_pkt->list);
+	if (list_empty(&xprt_info->pkt_list))
+		wake_unlock(&xprt_info->wakelock);
+	mutex_unlock(&xprt_info->rx_lock);
+	return temp_pkt;
+}
+
+struct rr_packet *clone_pkt(struct rr_packet *pkt)
+{
+	struct rr_packet *cloned_pkt;
+	struct sk_buff *temp_skb, *cloned_skb;
+	struct sk_buff_head *pkt_fragment_q;
+
+	cloned_pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
+	if (!cloned_pkt) {
+		pr_err("%s: failure\n", __func__);
+		return NULL;
+	}
+
+	pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
+	if (!pkt_fragment_q) {
+		pr_err("%s: pkt_frag_q alloc failure\n", __func__);
+		kfree(cloned_pkt);
+		return NULL;
+	}
+	skb_queue_head_init(pkt_fragment_q);
+
+	skb_queue_walk(pkt->pkt_fragment_q, temp_skb) {
+		cloned_skb = skb_clone(temp_skb, GFP_KERNEL);
+		if (!cloned_skb)
+			goto fail_clone;
+		skb_queue_tail(pkt_fragment_q, cloned_skb);
+	}
+	cloned_pkt->pkt_fragment_q = pkt_fragment_q;
+	cloned_pkt->length = pkt->length;
+	return cloned_pkt;
+
+fail_clone:
+	while (!skb_queue_empty(pkt_fragment_q)) {
+		temp_skb = skb_dequeue(pkt_fragment_q);
+		kfree_skb(temp_skb);
+	}
+	kfree(pkt_fragment_q);
+	kfree(cloned_pkt);
+	return NULL;
+}
+
+struct rr_packet *create_pkt(struct sk_buff_head *data)
+{
+	struct rr_packet *pkt;
+	struct sk_buff *temp_skb;
+
+	pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
+	if (!pkt) {
+		pr_err("%s: failure\n", __func__);
+		return NULL;
+	}
+
+	pkt->pkt_fragment_q = data;
+	skb_queue_walk(pkt->pkt_fragment_q, temp_skb)
+		pkt->length += temp_skb->len;
+	return pkt;
+}
+
+void release_pkt(struct rr_packet *pkt)
+{
+	struct sk_buff *temp_skb;
+
+	if (!pkt)
+		return;
+
+	if (!pkt->pkt_fragment_q) {
+		kfree(pkt);
+		return;
+	}
+
+	while (!skb_queue_empty(pkt->pkt_fragment_q)) {
+		temp_skb = skb_dequeue(pkt->pkt_fragment_q);
+		kfree_skb(temp_skb);
+	}
+	kfree(pkt->pkt_fragment_q);
+	kfree(pkt);
+	return;
+}
+
+static int post_control_ports(struct rr_packet *pkt)
+{
+	struct msm_ipc_port *port_ptr;
+	struct rr_packet *cloned_pkt;
+
+	if (!pkt)
+		return -EINVAL;
+
+	mutex_lock(&control_ports_lock);
+	list_for_each_entry(port_ptr, &control_ports, list) {
+		mutex_lock(&port_ptr->port_rx_q_lock);
+		cloned_pkt = clone_pkt(pkt);
+		wake_lock(&port_ptr->port_rx_wake_lock);
+		list_add_tail(&cloned_pkt->list, &port_ptr->port_rx_q);
+		wake_up(&port_ptr->port_rx_wait_q);
+		mutex_unlock(&port_ptr->port_rx_q_lock);
+	}
+	mutex_unlock(&control_ports_lock);
+	return 0;
+}
+
+static uint32_t allocate_port_id(void)
+{
+	uint32_t port_id = 0, prev_port_id, key;
+	struct msm_ipc_port *port_ptr;
+
+	mutex_lock(&next_port_id_lock);
+	prev_port_id = next_port_id;
+	mutex_lock(&local_ports_lock);
+	do {
+		next_port_id++;
+		if ((next_port_id & 0xFFFFFFFE) == 0xFFFFFFFE)
+			next_port_id = 1;
+
+		key = (next_port_id & (LP_HASH_SIZE - 1));
+		if (list_empty(&local_ports[key])) {
+			port_id = next_port_id;
+			break;
+		}
+		list_for_each_entry(port_ptr, &local_ports[key], list) {
+			if (port_ptr->this_port.port_id == next_port_id) {
+				port_id = next_port_id;
+				break;
+			}
+		}
+		if (!port_id) {
+			port_id = next_port_id;
+			break;
+		}
+		port_id = 0;
+	} while (next_port_id != prev_port_id);
+	mutex_unlock(&local_ports_lock);
+	mutex_unlock(&next_port_id_lock);
+
+	return port_id;
+}
+
+void msm_ipc_router_add_local_port(struct msm_ipc_port *port_ptr)
+{
+	uint32_t key;
+
+	if (!port_ptr)
+		return;
+
+	key = (port_ptr->this_port.port_id & (LP_HASH_SIZE - 1));
+	mutex_lock(&local_ports_lock);
+	list_add_tail(&port_ptr->list, &local_ports[key]);
+	mutex_unlock(&local_ports_lock);
+}
+
+struct msm_ipc_port *msm_ipc_router_create_raw_port(void *endpoint,
+		void (*notify)(unsigned event, void *data,
+			       void *addr, void *priv),
+		void *priv)
+{
+	struct msm_ipc_port *port_ptr;
+
+	port_ptr = kzalloc(sizeof(struct msm_ipc_port), GFP_KERNEL);
+	if (!port_ptr)
+		return NULL;
+
+	port_ptr->this_port.node_id = IPC_ROUTER_NID_LOCAL;
+	port_ptr->this_port.port_id = allocate_port_id();
+	if (!port_ptr->this_port.port_id) {
+		pr_err("%s: All port ids are in use\n", __func__);
+		kfree(port_ptr);
+		return NULL;
+	}
+
+	spin_lock_init(&port_ptr->port_lock);
+	INIT_LIST_HEAD(&port_ptr->incomplete);
+	mutex_init(&port_ptr->incomplete_lock);
+	INIT_LIST_HEAD(&port_ptr->port_rx_q);
+	mutex_init(&port_ptr->port_rx_q_lock);
+	init_waitqueue_head(&port_ptr->port_rx_wait_q);
+	snprintf(port_ptr->rx_wakelock_name, MAX_WAKELOCK_NAME_SZ,
+		 "msm_ipc_read%08x:%08x",
+		 port_ptr->this_port.node_id,
+		 port_ptr->this_port.port_id);
+	wake_lock_init(&port_ptr->port_rx_wake_lock,
+			WAKE_LOCK_SUSPEND, port_ptr->rx_wakelock_name);
+
+	port_ptr->endpoint = endpoint;
+	port_ptr->notify = notify;
+	port_ptr->priv = priv;
+
+	msm_ipc_router_add_local_port(port_ptr);
+	return port_ptr;
+}
+
+static struct msm_ipc_port *msm_ipc_router_lookup_local_port(uint32_t port_id)
+{
+	int key = (port_id & (LP_HASH_SIZE - 1));
+	struct msm_ipc_port *port_ptr;
+
+	mutex_lock(&local_ports_lock);
+	list_for_each_entry(port_ptr, &local_ports[key], list) {
+		if (port_ptr->this_port.port_id == port_id) {
+			mutex_unlock(&local_ports_lock);
+			return port_ptr;
+		}
+	}
+	mutex_unlock(&local_ports_lock);
+	return NULL;
+}
+
+static struct msm_ipc_router_remote_port *msm_ipc_router_lookup_remote_port(
+						uint32_t node_id,
+						uint32_t port_id)
+{
+	struct msm_ipc_router_remote_port *rport_ptr;
+	struct msm_ipc_routing_table_entry *rt_entry;
+	int key = (port_id & (RP_HASH_SIZE - 1));
+
+	mutex_lock(&routing_table_lock);
+	rt_entry = lookup_routing_table(node_id);
+	if (!rt_entry) {
+		mutex_unlock(&routing_table_lock);
+		pr_err("%s: Node is not up\n", __func__);
+		return NULL;
+	}
+
+	mutex_lock(&rt_entry->lock);
+	list_for_each_entry(rport_ptr,
+			    &rt_entry->remote_port_list[key], list) {
+		if (rport_ptr->port_id == port_id) {
+			if (rport_ptr->restart_state != RESTART_NORMAL)
+				rport_ptr = NULL;
+			mutex_unlock(&rt_entry->lock);
+			mutex_unlock(&routing_table_lock);
+			return rport_ptr;
+		}
+	}
+	mutex_unlock(&rt_entry->lock);
+	mutex_unlock(&routing_table_lock);
+	return NULL;
+}
+
+static struct msm_ipc_router_remote_port *msm_ipc_router_create_remote_port(
+						uint32_t node_id,
+						uint32_t port_id)
+{
+	struct msm_ipc_router_remote_port *rport_ptr;
+	struct msm_ipc_routing_table_entry *rt_entry;
+	int key = (port_id & (RP_HASH_SIZE - 1));
+
+	mutex_lock(&routing_table_lock);
+	rt_entry = lookup_routing_table(node_id);
+	if (!rt_entry) {
+		mutex_unlock(&routing_table_lock);
+		pr_err("%s: Node is not up\n", __func__);
+		return NULL;
+	}
+
+	mutex_lock(&rt_entry->lock);
+	rport_ptr = kmalloc(sizeof(struct msm_ipc_router_remote_port),
+			    GFP_KERNEL);
+	if (!rport_ptr) {
+		mutex_unlock(&rt_entry->lock);
+		mutex_unlock(&routing_table_lock);
+		pr_err("%s: Remote port alloc failed\n", __func__);
+		return NULL;
+	}
+	rport_ptr->port_id = port_id;
+	rport_ptr->node_id = node_id;
+	rport_ptr->restart_state = RESTART_NORMAL;
+	rport_ptr->tx_quota_cnt = 0;
+	init_waitqueue_head(&rport_ptr->quota_wait);
+	mutex_init(&rport_ptr->quota_lock);
+	list_add_tail(&rport_ptr->list,
+		      &rt_entry->remote_port_list[key]);
+	mutex_unlock(&rt_entry->lock);
+	mutex_unlock(&routing_table_lock);
+	return rport_ptr;
+}
+
+static void msm_ipc_router_destroy_remote_port(
+	struct msm_ipc_router_remote_port *rport_ptr)
+{
+	uint32_t node_id;
+	struct msm_ipc_routing_table_entry *rt_entry;
+
+	if (!rport_ptr)
+		return;
+
+	node_id = rport_ptr->node_id;
+	mutex_lock(&routing_table_lock);
+	rt_entry = lookup_routing_table(node_id);
+	if (!rt_entry) {
+		mutex_unlock(&routing_table_lock);
+		pr_err("%s: Node %d is not up\n", __func__, node_id);
+		return;
+	}
+
+	mutex_lock(&rt_entry->lock);
+	list_del(&rport_ptr->list);
+	kfree(rport_ptr);
+	mutex_unlock(&rt_entry->lock);
+	mutex_unlock(&routing_table_lock);
+	return;
+}
+
+static struct msm_ipc_server *msm_ipc_router_lookup_server(
+				uint32_t service,
+				uint32_t instance,
+				uint32_t node_id,
+				uint32_t port_id)
+{
+	struct msm_ipc_server *server;
+	struct msm_ipc_server_port *server_port;
+	int key = (instance & (SRV_HASH_SIZE - 1));
+
+	mutex_lock(&server_list_lock);
+	list_for_each_entry(server, &server_list[key], list) {
+		if ((server->name.service != service) ||
+		    (server->name.instance != instance))
+			continue;
+		if ((node_id == 0) && (port_id == 0)) {
+			mutex_unlock(&server_list_lock);
+			return server;
+		}
+		list_for_each_entry(server_port, &server->server_port_list,
+				    list) {
+			if ((server_port->server_addr.node_id == node_id) &&
+			    (server_port->server_addr.port_id == port_id)) {
+				mutex_unlock(&server_list_lock);
+				return server;
+			}
+		}
+	}
+	mutex_unlock(&server_list_lock);
+	return NULL;
+}
+
+static struct msm_ipc_server *msm_ipc_router_create_server(
+					uint32_t service,
+					uint32_t instance,
+					uint32_t node_id,
+					uint32_t port_id,
+		struct msm_ipc_router_xprt_info *xprt_info)
+{
+	struct msm_ipc_server *server = NULL;
+	struct msm_ipc_server_port *server_port;
+	int key = (instance & (SRV_HASH_SIZE - 1));
+
+	mutex_lock(&server_list_lock);
+	list_for_each_entry(server, &server_list[key], list) {
+		if ((server->name.service == service) &&
+		    (server->name.instance == instance))
+			goto create_srv_port;
+	}
+
+	server = kmalloc(sizeof(struct msm_ipc_server), GFP_KERNEL);
+	if (!server) {
+		mutex_unlock(&server_list_lock);
+		pr_err("%s: Server allocation failed\n", __func__);
+		return NULL;
+	}
+	server->name.service = service;
+	server->name.instance = instance;
+	INIT_LIST_HEAD(&server->server_port_list);
+	list_add_tail(&server->list, &server_list[key]);
+
+create_srv_port:
+	server_port = kmalloc(sizeof(struct msm_ipc_server_port), GFP_KERNEL);
+	if (!server_port) {
+		if (list_empty(&server->server_port_list)) {
+			list_del(&server->list);
+			kfree(server);
+		}
+		mutex_unlock(&server_list_lock);
+		pr_err("%s: Server Port allocation failed\n", __func__);
+		return NULL;
+	}
+	server_port->server_addr.node_id = node_id;
+	server_port->server_addr.port_id = port_id;
+	server_port->xprt_info = xprt_info;
+	list_add_tail(&server_port->list, &server->server_port_list);
+	mutex_unlock(&server_list_lock);
+
+	return server;
+}
+
+static void msm_ipc_router_destroy_server(struct msm_ipc_server *server,
+					  uint32_t node_id, uint32_t port_id)
+{
+	struct msm_ipc_server_port *server_port;
+
+	if (!server)
+		return;
+
+	mutex_lock(&server_list_lock);
+	list_for_each_entry(server_port, &server->server_port_list, list) {
+		if ((server_port->server_addr.node_id == node_id) &&
+		    (server_port->server_addr.port_id == port_id))
+			break;
+	}
+	if (server_port) {
+		list_del(&server_port->list);
+		kfree(server_port);
+	}
+	if (list_empty(&server->server_port_list)) {
+		list_del(&server->list);
+		kfree(server);
+	}
+	mutex_unlock(&server_list_lock);
+	return;
+}
+
+static int msm_ipc_router_send_control_msg(
+		struct msm_ipc_router_xprt_info *xprt_info,
+		union rr_control_msg *msg)
+{
+	struct rr_packet *pkt;
+	struct sk_buff *ipc_rtr_pkt;
+	struct rr_header *hdr;
+	int pkt_size;
+	void *data;
+	struct sk_buff_head *pkt_fragment_q;
+	int ret;
+
+	if (!xprt_info || ((msg->cmd != IPC_ROUTER_CTRL_CMD_HELLO) &&
+	    !xprt_info->initialized)) {
+		pr_err("%s: xprt_info not initialized\n", __func__);
+		return -EINVAL;
+	}
+
+	if (xprt_info->remote_node_id == IPC_ROUTER_NID_LOCAL)
+		return 0;
+
+	pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
+	if (!pkt) {
+		pr_err("%s: pkt alloc failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
+	if (!pkt_fragment_q) {
+		pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
+		kfree(pkt);
+		return -ENOMEM;
+	}
+	skb_queue_head_init(pkt_fragment_q);
+
+	pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
+	ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
+	if (!ipc_rtr_pkt) {
+		pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
+		kfree(pkt_fragment_q);
+		kfree(pkt);
+		return -ENOMEM;
+	}
+
+	skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
+	data = skb_put(ipc_rtr_pkt, sizeof(*msg));
+	memcpy(data, msg, sizeof(*msg));
+	hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
+	if (!hdr) {
+		pr_err("%s: skb_push failed\n", __func__);
+		kfree_skb(ipc_rtr_pkt);
+		kfree(pkt_fragment_q);
+		kfree(pkt);
+		return -ENOMEM;
+	}
+
+	hdr->version = IPC_ROUTER_VERSION;
+	hdr->type = msg->cmd;
+	hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
+	hdr->src_port_id = IPC_ROUTER_ADDRESS;
+	hdr->confirm_rx = 0;
+	hdr->size = sizeof(*msg);
+	hdr->dst_node_id = xprt_info->remote_node_id;
+	hdr->dst_port_id = IPC_ROUTER_ADDRESS;
+	skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
+	pkt->pkt_fragment_q = pkt_fragment_q;
+	pkt->length = pkt_size;
+
+	mutex_lock(&xprt_info->tx_lock);
+	ret = xprt_info->xprt->write(pkt, pkt_size, xprt_info->xprt);
+	mutex_unlock(&xprt_info->tx_lock);
+
+	release_pkt(pkt);
+	return ret;
+}
+
+static int msm_ipc_router_send_server_list(
+		struct msm_ipc_router_xprt_info *xprt_info)
+{
+	union rr_control_msg ctl;
+	struct msm_ipc_server *server;
+	struct msm_ipc_server_port *server_port;
+	int i;
+
+	if (!xprt_info || !xprt_info->initialized) {
+		pr_err("%s: Xprt info not initialized\n", __func__);
+		return -EINVAL;
+	}
+
+	ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
+
+	mutex_lock(&server_list_lock);
+	for (i = 0; i < SRV_HASH_SIZE; i++) {
+		list_for_each_entry(server, &server_list[i], list) {
+			ctl.srv.service = server->name.service;
+			ctl.srv.instance = server->name.instance;
+			list_for_each_entry(server_port,
+					    &server->server_port_list, list) {
+				if (server_port->server_addr.node_id ==
+				    xprt_info->remote_node_id)
+					continue;
+
+				ctl.srv.node_id =
+					server_port->server_addr.node_id;
+				ctl.srv.port_id =
+					server_port->server_addr.port_id;
+				msm_ipc_router_send_control_msg(xprt_info,
+								&ctl);
+			}
+		}
+	}
+	mutex_unlock(&server_list_lock);
+
+	return 0;
+}
+
+#if defined(DEBUG)
+static char *type_to_str(int i)
+{
+	switch (i) {
+	case IPC_ROUTER_CTRL_CMD_DATA:
+		return "data    ";
+	case IPC_ROUTER_CTRL_CMD_HELLO:
+		return "hello   ";
+	case IPC_ROUTER_CTRL_CMD_BYE:
+		return "bye     ";
+	case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
+		return "new_srvr";
+	case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
+		return "rmv_srvr";
+	case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
+		return "rmv_clnt";
+	case IPC_ROUTER_CTRL_CMD_RESUME_TX:
+		return "resum_tx";
+	case IPC_ROUTER_CTRL_CMD_EXIT:
+		return "cmd_exit";
+	default:
+		return "invalid";
+	}
+}
+#endif
+
+static int broadcast_ctl_msg_locally(union rr_control_msg *msg)
+{
+	struct rr_packet *pkt;
+	struct sk_buff *ipc_rtr_pkt;
+	struct rr_header *hdr;
+	int pkt_size;
+	void *data;
+	struct sk_buff_head *pkt_fragment_q;
+	int ret;
+
+	pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
+	if (!pkt) {
+		pr_err("%s: pkt alloc failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
+	if (!pkt_fragment_q) {
+		pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
+		kfree(pkt);
+		return -ENOMEM;
+	}
+	skb_queue_head_init(pkt_fragment_q);
+
+	pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
+	ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
+	if (!ipc_rtr_pkt) {
+		pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
+		kfree(pkt_fragment_q);
+		kfree(pkt);
+		return -ENOMEM;
+	}
+
+	skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
+	data = skb_put(ipc_rtr_pkt, sizeof(*msg));
+	memcpy(data, msg, sizeof(*msg));
+	hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
+	if (!hdr) {
+		pr_err("%s: skb_push failed\n", __func__);
+		kfree_skb(ipc_rtr_pkt);
+		kfree(pkt_fragment_q);
+		kfree(pkt);
+		return -ENOMEM;
+	}
+	hdr->version = IPC_ROUTER_VERSION;
+	hdr->type = msg->cmd;
+	hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
+	hdr->src_port_id = IPC_ROUTER_ADDRESS;
+	hdr->confirm_rx = 0;
+	hdr->size = sizeof(*msg);
+	hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
+	hdr->dst_port_id = IPC_ROUTER_ADDRESS;
+	skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
+	pkt->pkt_fragment_q = pkt_fragment_q;
+	pkt->length = pkt_size;
+
+	ret = post_control_ports(pkt);
+	release_pkt(pkt);
+	return ret;
+}
+
+static int broadcast_ctl_msg(union rr_control_msg *ctl)
+{
+	struct msm_ipc_router_xprt_info *xprt_info;
+
+	mutex_lock(&xprt_info_list_lock);
+	list_for_each_entry(xprt_info, &xprt_info_list, list) {
+		msm_ipc_router_send_control_msg(xprt_info, ctl);
+	}
+	mutex_unlock(&xprt_info_list_lock);
+
+	return 0;
+}
+
+static int relay_ctl_msg(struct msm_ipc_router_xprt_info *xprt_info,
+			 union rr_control_msg *ctl)
+{
+	struct msm_ipc_router_xprt_info *fwd_xprt_info;
+
+	if (!xprt_info || !ctl)
+		return -EINVAL;
+
+	mutex_lock(&xprt_info_list_lock);
+	list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
+		if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
+			msm_ipc_router_send_control_msg(fwd_xprt_info, ctl);
+	}
+	mutex_unlock(&xprt_info_list_lock);
+
+	return 0;
+}
+
+static int relay_msg(struct msm_ipc_router_xprt_info *xprt_info,
+		     struct rr_packet *pkt)
+{
+	struct msm_ipc_router_xprt_info *fwd_xprt_info;
+
+	if (!xprt_info || !pkt)
+		return -EINVAL;
+
+	mutex_lock(&xprt_info_list_lock);
+	list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
+		mutex_lock(&fwd_xprt_info->tx_lock);
+		if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
+			fwd_xprt_info->xprt->write(pkt, pkt->length,
+						   fwd_xprt_info->xprt);
+		mutex_unlock(&fwd_xprt_info->tx_lock);
+	}
+	mutex_unlock(&xprt_info_list_lock);
+	return 0;
+}
+
+static int forward_msg(struct msm_ipc_router_xprt_info *xprt_info,
+		       struct rr_packet *pkt)
+{
+	uint32_t dst_node_id;
+	struct sk_buff *head_pkt;
+	struct rr_header *hdr;
+	struct msm_ipc_router_xprt_info *fwd_xprt_info;
+	struct msm_ipc_routing_table_entry *rt_entry;
+
+	if (!xprt_info || !pkt)
+		return -EINVAL;
+
+	head_pkt = skb_peek(pkt->pkt_fragment_q);
+	if (!head_pkt)
+		return -EINVAL;
+
+	hdr = (struct rr_header *)head_pkt->data;
+	dst_node_id = hdr->dst_node_id;
+	mutex_lock(&routing_table_lock);
+	rt_entry = lookup_routing_table(dst_node_id);
+	if (!(rt_entry) || !(rt_entry->xprt_info)) {
+		mutex_unlock(&routing_table_lock);
+		pr_err("%s: Routing table not initialized\n", __func__);
+		return -ENODEV;
+	}
+
+	mutex_lock(&rt_entry->lock);
+	fwd_xprt_info = rt_entry->xprt_info;
+	mutex_lock(&fwd_xprt_info->tx_lock);
+	if (xprt_info->remote_node_id == fwd_xprt_info->remote_node_id) {
+		mutex_unlock(&fwd_xprt_info->tx_lock);
+		mutex_unlock(&rt_entry->lock);
+		mutex_unlock(&routing_table_lock);
+		pr_err("%s: Discarding Command to route back\n", __func__);
+		return -EINVAL;
+	}
+
+	if (xprt_info->xprt->link_id == fwd_xprt_info->xprt->link_id) {
+		mutex_unlock(&fwd_xprt_info->tx_lock);
+		mutex_unlock(&rt_entry->lock);
+		mutex_unlock(&routing_table_lock);
+		pr_err("%s: DST in the same cluster\n", __func__);
+		return 0;
+	}
+	fwd_xprt_info->xprt->write(pkt, pkt->length, fwd_xprt_info->xprt);
+	mutex_unlock(&fwd_xprt_info->tx_lock);
+	mutex_unlock(&rt_entry->lock);
+	mutex_unlock(&routing_table_lock);
+
+	return 0;
+}
+
+static void reset_remote_port_info(uint32_t node_id, uint32_t port_id)
+{
+	struct msm_ipc_router_remote_port *rport_ptr;
+
+	rport_ptr = msm_ipc_router_lookup_remote_port(node_id, port_id);
+	if (!rport_ptr) {
+		pr_err("%s: No such remote port %08x:%08x\n",
+			__func__, node_id, port_id);
+		return;
+	}
+	mutex_lock(&rport_ptr->quota_lock);
+	rport_ptr->restart_state = RESTART_PEND;
+	wake_up(&rport_ptr->quota_wait);
+	mutex_unlock(&rport_ptr->quota_lock);
+	return;
+}
+
+static void msm_ipc_cleanup_remote_server_info(
+		struct msm_ipc_router_xprt_info *xprt_info)
+{
+	struct msm_ipc_server *svr, *tmp_svr;
+	struct msm_ipc_server_port *svr_port, *tmp_svr_port;
+	int i;
+	union rr_control_msg ctl;
+
+	if (!xprt_info) {
+		pr_err("%s: Invalid xprt_info\n", __func__);
+		return;
+	}
+
+	ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
+	mutex_lock(&server_list_lock);
+	for (i = 0; i < SRV_HASH_SIZE; i++) {
+		list_for_each_entry_safe(svr, tmp_svr, &server_list[i], list) {
+			ctl.srv.service = svr->name.service;
+			ctl.srv.instance = svr->name.instance;
+			list_for_each_entry_safe(svr_port, tmp_svr_port,
+					 &svr->server_port_list, list) {
+				if (svr_port->xprt_info != xprt_info)
+					continue;
+				D("Remove server %08x:%08x - %08x:%08x",
+				   ctl.srv.service, ctl.srv.instance,
+				   svr_port->server_addr.node_id,
+				   svr_port->server_addr.port_id);
+				reset_remote_port_info(
+					svr_port->server_addr.node_id,
+					svr_port->server_addr.port_id);
+				ctl.srv.node_id = svr_port->server_addr.node_id;
+				ctl.srv.port_id = svr_port->server_addr.port_id;
+				relay_ctl_msg(xprt_info, &ctl);
+				broadcast_ctl_msg_locally(&ctl);
+				list_del(&svr_port->list);
+				kfree(svr_port);
+			}
+			if (list_empty(&svr->server_port_list)) {
+				list_del(&svr->list);
+				kfree(svr);
+			}
+		}
+	}
+	mutex_unlock(&server_list_lock);
+}
+
+static void msm_ipc_cleanup_remote_client_info(
+		struct msm_ipc_router_xprt_info *xprt_info)
+{
+	struct msm_ipc_routing_table_entry *rt_entry;
+	struct msm_ipc_router_remote_port *rport_ptr;
+	int i, j;
+	union rr_control_msg ctl;
+
+	if (!xprt_info) {
+		pr_err("%s: Invalid xprt_info\n", __func__);
+		return;
+	}
+
+	ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
+	mutex_lock(&routing_table_lock);
+	for (i = 0; i < RT_HASH_SIZE; i++) {
+		list_for_each_entry(rt_entry, &routing_table[i], list) {
+			mutex_lock(&rt_entry->lock);
+			if (rt_entry->xprt_info != xprt_info) {
+				mutex_unlock(&rt_entry->lock);
+				continue;
+			}
+			for (j = 0; j < RP_HASH_SIZE; j++) {
+				list_for_each_entry(rport_ptr,
+					&rt_entry->remote_port_list[j], list) {
+					if (rport_ptr->restart_state ==
+						RESTART_PEND)
+						continue;
+					mutex_lock(&rport_ptr->quota_lock);
+					rport_ptr->restart_state = RESTART_PEND;
+					wake_up(&rport_ptr->quota_wait);
+					mutex_unlock(&rport_ptr->quota_lock);
+					ctl.cli.node_id = rport_ptr->node_id;
+					ctl.cli.port_id = rport_ptr->port_id;
+					broadcast_ctl_msg_locally(&ctl);
+				}
+			}
+			mutex_unlock(&rt_entry->lock);
+		}
+	}
+	mutex_unlock(&routing_table_lock);
+}
+
+static void msm_ipc_cleanup_remote_port_info(uint32_t node_id)
+{
+	struct msm_ipc_routing_table_entry *rt_entry, *tmp_rt_entry;
+	struct msm_ipc_router_remote_port *rport_ptr, *tmp_rport_ptr;
+	int i, j;
+
+	mutex_lock(&routing_table_lock);
+	for (i = 0; i < RT_HASH_SIZE; i++) {
+		list_for_each_entry_safe(rt_entry, tmp_rt_entry,
+					 &routing_table[i], list) {
+			mutex_lock(&rt_entry->lock);
+			if (rt_entry->neighbor_node_id != node_id) {
+				mutex_unlock(&rt_entry->lock);
+				continue;
+			}
+			for (j = 0; j < RP_HASH_SIZE; j++) {
+				list_for_each_entry_safe(rport_ptr,
+					tmp_rport_ptr,
+					&rt_entry->remote_port_list[j], list) {
+					list_del(&rport_ptr->list);
+					kfree(rport_ptr);
+				}
+			}
+			mutex_unlock(&rt_entry->lock);
+		}
+	}
+	mutex_unlock(&routing_table_lock);
+}
+
+static void msm_ipc_cleanup_routing_table(
+	struct msm_ipc_router_xprt_info *xprt_info)
+{
+	int i;
+	struct msm_ipc_routing_table_entry *rt_entry;
+
+	if (!xprt_info) {
+		pr_err("%s: Invalid xprt_info\n", __func__);
+		return;
+	}
+
+	mutex_lock(&routing_table_lock);
+	for (i = 0; i < RT_HASH_SIZE; i++) {
+		list_for_each_entry(rt_entry, &routing_table[i], list) {
+			mutex_lock(&rt_entry->lock);
+			if (rt_entry->xprt_info == xprt_info)
+				rt_entry->xprt_info = NULL;
+			mutex_unlock(&rt_entry->lock);
+		}
+	}
+	mutex_unlock(&routing_table_lock);
+}
+
+static void modem_reset_cleanup(struct msm_ipc_router_xprt_info *xprt_info)
+{
+
+	if (!xprt_info) {
+		pr_err("%s: Invalid xprt_info\n", __func__);
+		return;
+	}
+
+	msm_ipc_cleanup_remote_server_info(xprt_info);
+	msm_ipc_cleanup_remote_client_info(xprt_info);
+	msm_ipc_cleanup_routing_table(xprt_info);
+}
+
+static int process_control_msg(struct msm_ipc_router_xprt_info *xprt_info,
+			       struct rr_packet *pkt)
+{
+	union rr_control_msg ctl;
+	union rr_control_msg *msg;
+	struct msm_ipc_router_remote_port *rport_ptr;
+	int rc = 0;
+	static uint32_t first = 1;
+	struct sk_buff *temp_ptr;
+	struct rr_header *hdr;
+	struct msm_ipc_server *server;
+	struct msm_ipc_routing_table_entry *rt_entry;
+
+	if (pkt->length != (IPC_ROUTER_HDR_SIZE + sizeof(*msg))) {
+		pr_err("%s: r2r msg size %d != %d\n", __func__, pkt->length,
+			(IPC_ROUTER_HDR_SIZE + sizeof(*msg)));
+		return -EINVAL;
+	}
+
+	temp_ptr = skb_peek(pkt->pkt_fragment_q);
+	if (!temp_ptr) {
+		pr_err("%s: pkt_fragment_q is empty\n", __func__);
+		return -EINVAL;
+	}
+	hdr = (struct rr_header *)temp_ptr->data;
+	if (!hdr) {
+		pr_err("%s: No data inside the skb\n", __func__);
+		return -EINVAL;
+	}
+	msg = (union rr_control_msg *)((char *)hdr + IPC_ROUTER_HDR_SIZE);
+
+	switch (msg->cmd) {
+	case IPC_ROUTER_CTRL_CMD_HELLO:
+		RR("o HELLO NID %d\n", hdr->src_node_id);
+		xprt_info->remote_node_id = hdr->src_node_id;
+
+		mutex_lock(&routing_table_lock);
+		rt_entry = lookup_routing_table(hdr->src_node_id);
+		if (!rt_entry) {
+			rt_entry = alloc_routing_table_entry(hdr->src_node_id);
+			if (!rt_entry) {
+				mutex_unlock(&routing_table_lock);
+				pr_err("%s: rt_entry allocation failed\n",
+					__func__);
+				return -ENOMEM;
+			}
+			add_routing_table_entry(rt_entry);
+		}
+		mutex_lock(&rt_entry->lock);
+		rt_entry->neighbor_node_id = xprt_info->remote_node_id;
+		rt_entry->xprt_info = xprt_info;
+		mutex_unlock(&rt_entry->lock);
+		mutex_unlock(&routing_table_lock);
+		msm_ipc_cleanup_remote_port_info(xprt_info->remote_node_id);
+
+		memset(&ctl, 0, sizeof(ctl));
+		ctl.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
+		msm_ipc_router_send_control_msg(xprt_info, &ctl);
+
+		xprt_info->initialized = 1;
+
+		/* Send list of servers one at a time */
+		msm_ipc_router_send_server_list(xprt_info);
+
+		if (first) {
+			first = 0;
+			complete_all(&msm_ipc_remote_router_up);
+		}
+		RR("HELLO message processed\n");
+		break;
+	case IPC_ROUTER_CTRL_CMD_RESUME_TX:
+		RR("o RESUME_TX id=%d:%08x\n",
+		   msg->cli.node_id, msg->cli.port_id);
+
+		rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
+							msg->cli.port_id);
+		if (!rport_ptr) {
+			pr_err("%s: Unable to resume client\n", __func__);
+			break;
+		}
+		mutex_lock(&rport_ptr->quota_lock);
+		rport_ptr->tx_quota_cnt = 0;
+		mutex_unlock(&rport_ptr->quota_lock);
+		wake_up(&rport_ptr->quota_wait);
+		break;
+
+	case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
+		if (msg->srv.instance == 0) {
+			pr_err(
+			"rpcrouter: Server create rejected, version = 0, "
+			"service = %08x\n", msg->srv.service);
+			break;
+		}
+
+		RR("o NEW_SERVER id=%d:%08x service=%08x:%08x\n",
+		   msg->srv.node_id, msg->srv.port_id,
+		   msg->srv.service, msg->srv.instance);
+
+		mutex_lock(&routing_table_lock);
+		rt_entry = lookup_routing_table(msg->srv.node_id);
+		if (!rt_entry) {
+			rt_entry = alloc_routing_table_entry(msg->srv.node_id);
+			if (!rt_entry) {
+				mutex_unlock(&routing_table_lock);
+				pr_err("%s: rt_entry allocation failed\n",
+					__func__);
+				return -ENOMEM;
+			}
+			mutex_lock(&rt_entry->lock);
+			rt_entry->neighbor_node_id = xprt_info->remote_node_id;
+			rt_entry->xprt_info = xprt_info;
+			mutex_unlock(&rt_entry->lock);
+			add_routing_table_entry(rt_entry);
+		}
+		mutex_unlock(&routing_table_lock);
+
+		server = msm_ipc_router_lookup_server(msg->srv.service,
+						      msg->srv.instance,
+						      msg->srv.node_id,
+						      msg->srv.port_id);
+		if (!server) {
+			server = msm_ipc_router_create_server(
+				msg->srv.service, msg->srv.instance,
+				msg->srv.node_id, msg->srv.port_id, xprt_info);
+			if (!server) {
+				pr_err("%s: Server Create failed\n", __func__);
+				return -ENOMEM;
+			}
+
+			if (!msm_ipc_router_lookup_remote_port(
+					msg->srv.node_id, msg->srv.port_id)) {
+				rport_ptr = msm_ipc_router_create_remote_port(
+					msg->srv.node_id, msg->srv.port_id);
+				if (!rport_ptr)
+					pr_err("%s: Remote port create "
+					       "failed\n", __func__);
+			}
+			wake_up(&newserver_wait);
+		}
+
+		relay_msg(xprt_info, pkt);
+		post_control_ports(pkt);
+		break;
+	case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
+		RR("o REMOVE_SERVER service=%08x:%d\n",
+		   msg->srv.service, msg->srv.instance);
+		server = msm_ipc_router_lookup_server(msg->srv.service,
+						      msg->srv.instance,
+						      msg->srv.node_id,
+						      msg->srv.port_id);
+		if (server) {
+			msm_ipc_router_destroy_server(server,
+						      msg->srv.node_id,
+						      msg->srv.port_id);
+			relay_msg(xprt_info, pkt);
+			post_control_ports(pkt);
+		}
+		break;
+	case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
+		RR("o REMOVE_CLIENT id=%d:%08x\n",
+		    msg->cli.node_id, msg->cli.port_id);
+		rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
+							msg->cli.port_id);
+		if (rport_ptr)
+			msm_ipc_router_destroy_remote_port(rport_ptr);
+
+		relay_msg(xprt_info, pkt);
+		post_control_ports(pkt);
+		break;
+	case IPC_ROUTER_CTRL_CMD_PING:
+		/* No action needed for ping messages received */
+		RR("o PING\n");
+		break;
+	default:
+		RR("o UNKNOWN(%08x)\n", msg->cmd);
+		rc = -ENOSYS;
+	}
+
+	return rc;
+}
+
+static void do_read_data(struct work_struct *work)
+{
+	struct rr_header *hdr;
+	struct rr_packet *pkt = NULL;
+	struct msm_ipc_port *port_ptr;
+	struct sk_buff *head_skb;
+	struct msm_ipc_port_addr *src_addr;
+	struct msm_ipc_router_remote_port *rport_ptr;
+	uint32_t resume_tx, resume_tx_node_id, resume_tx_port_id;
+
+	struct msm_ipc_router_xprt_info *xprt_info =
+		container_of(work,
+			     struct msm_ipc_router_xprt_info,
+			     read_data);
+
+	pkt = rr_read(xprt_info);
+	if (!pkt) {
+		pr_err("%s: rr_read failed\n", __func__);
+		goto fail_io;
+	}
+
+	if (pkt->length < IPC_ROUTER_HDR_SIZE ||
+	    pkt->length > MAX_IPC_PKT_SIZE) {
+		pr_err("%s: Invalid pkt length %d\n", __func__, pkt->length);
+		goto fail_data;
+	}
+
+	head_skb = skb_peek(pkt->pkt_fragment_q);
+	if (!head_skb) {
+		pr_err("%s: head_skb is invalid\n", __func__);
+		goto fail_data;
+	}
+
+	hdr = (struct rr_header *)(head_skb->data);
+	RR("- ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
+	   hdr->version, hdr->type, hdr->src_node_id, hdr->src_port_id,
+	   hdr->confirm_rx, hdr->size, hdr->dst_node_id, hdr->dst_port_id);
+	RAW_HDR("[r rr_h] "
+		"ver=%i,type=%s,src_node_id=%08x,src_port_id=%08x,"
+		"confirm_rx=%i,size=%3i,dst_node_id=%08x,dst_port_id=%08x\n",
+		hdr->version, type_to_str(hdr->type), hdr->src_node_id,
+		hdr->src_port_id, hdr->confirm_rx, hdr->size, hdr->dst_node_id,
+		hdr->dst_port_id);
+
+	if (hdr->version != IPC_ROUTER_VERSION) {
+		pr_err("version %d != %d\n", hdr->version, IPC_ROUTER_VERSION);
+		goto fail_data;
+	}
+
+	if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) &&
+	    ((hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX) ||
+	     (hdr->type == IPC_ROUTER_CTRL_CMD_DATA))) {
+		forward_msg(xprt_info, pkt);
+		release_pkt(pkt);
+		goto done;
+	}
+
+	if ((hdr->dst_port_id == IPC_ROUTER_ADDRESS) ||
+	    (hdr->type == IPC_ROUTER_CTRL_CMD_HELLO)) {
+		process_control_msg(xprt_info, pkt);
+		release_pkt(pkt);
+		goto done;
+	}
+#if defined(CONFIG_MSM_SMD_LOGGING)
+#if defined(DEBUG)
+	if (msm_ipc_router_debug_mask & SMEM_LOG) {
+		smem_log_event((SMEM_LOG_PROC_ID_APPS |
+			SMEM_LOG_RPC_ROUTER_EVENT_BASE |
+			IPC_ROUTER_LOG_EVENT_RX),
+			(hdr->src_node_id << 24) |
+			(hdr->src_port_id & 0xffffff),
+			(hdr->dst_node_id << 24) |
+			(hdr->dst_port_id & 0xffffff),
+			(hdr->type << 24) | (hdr->confirm_rx << 16) |
+			(hdr->size & 0xffff));
+	}
+#endif
+#endif
+
+	resume_tx = hdr->confirm_rx;
+	resume_tx_node_id = hdr->dst_node_id;
+	resume_tx_port_id = hdr->dst_port_id;
+
+	port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
+	if (!port_ptr) {
+		pr_err("%s: No local port id %08x\n", __func__,
+			hdr->dst_port_id);
+		release_pkt(pkt);
+		goto process_done;
+	}
+
+	rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
+						      hdr->src_port_id);
+	if (!rport_ptr) {
+		rport_ptr = msm_ipc_router_create_remote_port(
+							hdr->src_node_id,
+							hdr->src_port_id);
+		if (!rport_ptr) {
+			pr_err("%s: Remote port %08x:%08x creation failed\n",
+				__func__, hdr->src_node_id, hdr->src_port_id);
+			goto process_done;
+		}
+	}
+
+	if (!port_ptr->notify) {
+		mutex_lock(&port_ptr->port_rx_q_lock);
+		wake_lock(&port_ptr->port_rx_wake_lock);
+		list_add_tail(&pkt->list, &port_ptr->port_rx_q);
+		wake_up(&port_ptr->port_rx_wait_q);
+		mutex_unlock(&port_ptr->port_rx_q_lock);
+	} else {
+		src_addr = kmalloc(sizeof(struct msm_ipc_port_addr),
+				   GFP_KERNEL);
+		if (src_addr) {
+			src_addr->node_id = hdr->src_node_id;
+			src_addr->port_id = hdr->src_port_id;
+		}
+		skb_pull(head_skb, IPC_ROUTER_HDR_SIZE);
+		port_ptr->notify(MSM_IPC_ROUTER_READ_CB, pkt->pkt_fragment_q,
+				 src_addr, port_ptr->priv);
+		pkt->pkt_fragment_q = NULL;
+		src_addr = NULL;
+		release_pkt(pkt);
+	}
+
+process_done:
+	if (resume_tx) {
+		union rr_control_msg msg;
+
+		msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
+		msg.cli.node_id = resume_tx_node_id;
+		msg.cli.port_id = resume_tx_port_id;
+
+		RR("x RESUME_TX id=%d:%08x\n",
+		   msg.cli.node_id, msg.cli.port_id);
+		msm_ipc_router_send_control_msg(xprt_info, &msg);
+	}
+
+done:
+	queue_work(xprt_info->workqueue, &xprt_info->read_data);
+	return;
+
+fail_data:
+	release_pkt(pkt);
+fail_io:
+	pr_err("ipc_router has died\n");
+}
+
+int msm_ipc_router_register_server(struct msm_ipc_port *port_ptr,
+				   struct msm_ipc_addr *name)
+{
+	struct msm_ipc_server *server;
+	unsigned long flags;
+	union rr_control_msg ctl;
+
+	if (!port_ptr || !name)
+		return -EINVAL;
+
+	if (name->addrtype != MSM_IPC_ADDR_NAME)
+		return -EINVAL;
+
+	server = msm_ipc_router_lookup_server(name->addr.port_name.service,
+					      name->addr.port_name.instance,
+					      IPC_ROUTER_NID_LOCAL,
+					      port_ptr->this_port.port_id);
+	if (server) {
+		pr_err("%s: Server already present\n", __func__);
+		return -EINVAL;
+	}
+
+	server = msm_ipc_router_create_server(name->addr.port_name.service,
+					      name->addr.port_name.instance,
+					      IPC_ROUTER_NID_LOCAL,
+					      port_ptr->this_port.port_id,
+					      NULL);
+	if (!server) {
+		pr_err("%s: Server Creation failed\n", __func__);
+		return -EINVAL;
+	}
+
+	ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
+	ctl.srv.service = server->name.service;
+	ctl.srv.instance = server->name.instance;
+	ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
+	ctl.srv.port_id = port_ptr->this_port.port_id;
+	broadcast_ctl_msg(&ctl);
+	spin_lock_irqsave(&port_ptr->port_lock, flags);
+	port_ptr->type = SERVER_PORT;
+	port_ptr->port_name.service = server->name.service;
+	port_ptr->port_name.instance = server->name.instance;
+	spin_unlock_irqrestore(&port_ptr->port_lock, flags);
+	return 0;
+}
+
+int msm_ipc_router_unregister_server(struct msm_ipc_port *port_ptr)
+{
+	struct msm_ipc_server *server;
+	unsigned long flags;
+	union rr_control_msg ctl;
+
+	if (!port_ptr)
+		return -EINVAL;
+
+	if (port_ptr->type != SERVER_PORT) {
+		pr_err("%s: Trying to unregister a non-server port\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if (port_ptr->this_port.node_id != IPC_ROUTER_NID_LOCAL) {
+		pr_err("%s: Trying to unregister a remote server locally\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	server = msm_ipc_router_lookup_server(port_ptr->port_name.service,
+					      port_ptr->port_name.instance,
+					      port_ptr->this_port.node_id,
+					      port_ptr->this_port.port_id);
+	if (!server) {
+		pr_err("%s: Server lookup failed\n", __func__);
+		return -ENODEV;
+	}
+
+	ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
+	ctl.srv.service = server->name.service;
+	ctl.srv.instance = server->name.instance;
+	ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
+	ctl.srv.port_id = port_ptr->this_port.port_id;
+	broadcast_ctl_msg(&ctl);
+	msm_ipc_router_destroy_server(server, port_ptr->this_port.node_id,
+				      port_ptr->this_port.port_id);
+	spin_lock_irqsave(&port_ptr->port_lock, flags);
+	port_ptr->type = CLIENT_PORT;
+	spin_unlock_irqrestore(&port_ptr->port_lock, flags);
+	return 0;
+}
+
+static int loopback_data(struct msm_ipc_port *src,
+			uint32_t port_id,
+			struct sk_buff_head *data)
+{
+	struct sk_buff *head_skb;
+	struct rr_header *hdr;
+	struct msm_ipc_port *port_ptr;
+	struct rr_packet *pkt;
+
+	if (!data) {
+		pr_err("%s: Invalid pkt pointer\n", __func__);
+		return -EINVAL;
+	}
+
+	pkt = create_pkt(data);
+	if (!pkt) {
+		pr_err("%s: New pkt create failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	head_skb = skb_peek(pkt->pkt_fragment_q);
+	if (!head_skb) {
+		pr_err("%s: pkt_fragment_q is empty\n", __func__);
+		return -EINVAL;
+	}
+	hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
+	if (!hdr) {
+		pr_err("%s: Prepend Header failed\n", __func__);
+		release_pkt(pkt);
+		return -ENOMEM;
+	}
+	hdr->version = IPC_ROUTER_VERSION;
+	hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
+	hdr->src_node_id = src->this_port.node_id;
+	hdr->src_port_id = src->this_port.port_id;
+	hdr->size = pkt->length;
+	hdr->confirm_rx = 0;
+	hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
+	hdr->dst_port_id = port_id;
+	pkt->length += IPC_ROUTER_HDR_SIZE;
+
+	port_ptr = msm_ipc_router_lookup_local_port(port_id);
+	if (!port_ptr) {
+		pr_err("%s: Local port %d not present\n", __func__, port_id);
+		release_pkt(pkt);
+		return -ENODEV;
+	}
+
+	mutex_lock(&port_ptr->port_rx_q_lock);
+	wake_lock(&port_ptr->port_rx_wake_lock);
+	list_add_tail(&pkt->list, &port_ptr->port_rx_q);
+	wake_up(&port_ptr->port_rx_wait_q);
+	mutex_unlock(&port_ptr->port_rx_q_lock);
+
+	return pkt->length;
+}
+
+static int msm_ipc_router_write_pkt(struct msm_ipc_port *src,
+				struct msm_ipc_router_remote_port *rport_ptr,
+				struct rr_packet *pkt)
+{
+	struct sk_buff *head_skb;
+	struct rr_header *hdr;
+	struct msm_ipc_router_xprt_info *xprt_info;
+	struct msm_ipc_routing_table_entry *rt_entry;
+	int ret;
+	DEFINE_WAIT(__wait);
+
+	if (!rport_ptr || !src || !pkt)
+		return -EINVAL;
+
+	head_skb = skb_peek(pkt->pkt_fragment_q);
+	if (!head_skb) {
+		pr_err("%s: pkt_fragment_q is empty\n", __func__);
+		return -EINVAL;
+	}
+	hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
+	if (!hdr) {
+		pr_err("%s: Prepend Header failed\n", __func__);
+		return -ENOMEM;
+	}
+	hdr->version = IPC_ROUTER_VERSION;
+	hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
+	hdr->src_node_id = src->this_port.node_id;
+	hdr->src_port_id = src->this_port.port_id;
+	hdr->size = pkt->length;
+	hdr->confirm_rx = 0;
+	hdr->dst_node_id = rport_ptr->node_id;
+	hdr->dst_port_id = rport_ptr->port_id;
+	pkt->length += IPC_ROUTER_HDR_SIZE;
+
+	for (;;) {
+		prepare_to_wait(&rport_ptr->quota_wait, &__wait,
+				TASK_INTERRUPTIBLE);
+		mutex_lock(&rport_ptr->quota_lock);
+		if (rport_ptr->restart_state != RESTART_NORMAL)
+			break;
+		if (rport_ptr->tx_quota_cnt <
+		     IPC_ROUTER_DEFAULT_RX_QUOTA)
+			break;
+		if (signal_pending(current))
+			break;
+		mutex_unlock(&rport_ptr->quota_lock);
+		schedule();
+	}
+	finish_wait(&rport_ptr->quota_wait, &__wait);
+
+	if (rport_ptr->restart_state != RESTART_NORMAL) {
+		mutex_unlock(&rport_ptr->quota_lock);
+		return -ENETRESET;
+	}
+	if (signal_pending(current)) {
+		mutex_unlock(&rport_ptr->quota_lock);
+		return -ERESTARTSYS;
+	}
+	rport_ptr->tx_quota_cnt++;
+	if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
+		hdr->confirm_rx = 1;
+	mutex_unlock(&rport_ptr->quota_lock);
+
+	mutex_lock(&routing_table_lock);
+	rt_entry = lookup_routing_table(hdr->dst_node_id);
+	if (!rt_entry || !rt_entry->xprt_info) {
+		mutex_unlock(&routing_table_lock);
+		pr_err("%s: Remote node %d not up\n",
+			__func__, hdr->dst_node_id);
+		return -ENODEV;
+	}
+	mutex_lock(&rt_entry->lock);
+	xprt_info = rt_entry->xprt_info;
+	mutex_lock(&xprt_info->tx_lock);
+	ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
+	mutex_unlock(&xprt_info->tx_lock);
+	mutex_unlock(&rt_entry->lock);
+	mutex_unlock(&routing_table_lock);
+
+	if (ret < 0) {
+		pr_err("%s: Write on XPRT failed\n", __func__);
+		return ret;
+	}
+
+	RAW_HDR("[w rr_h] "
+		"ver=%i,type=%s,src_nid=%08x,src_port_id=%08x,"
+		"confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
+		hdr->version, type_to_str(hdr->type),
+		hdr->src_node_id, hdr->src_port_id,
+		hdr->confirm_rx, hdr->size,
+		hdr->dst_node_id, hdr->dst_port_id);
+
+#if defined(CONFIG_MSM_SMD_LOGGING)
+#if defined(DEBUG)
+	if (msm_ipc_router_debug_mask & SMEM_LOG) {
+		smem_log_event((SMEM_LOG_PROC_ID_APPS |
+			SMEM_LOG_RPC_ROUTER_EVENT_BASE |
+			IPC_ROUTER_LOG_EVENT_TX),
+			(hdr->src_node_id << 24) |
+			(hdr->src_port_id & 0xffffff),
+			(hdr->dst_node_id << 24) |
+			(hdr->dst_port_id & 0xffffff),
+			(hdr->type << 24) | (hdr->confirm_rx << 16) |
+			(hdr->size & 0xffff));
+	}
+#endif
+#endif
+
+	return pkt->length;
+}
+
+int msm_ipc_router_send_to(struct msm_ipc_port *src,
+			   struct sk_buff_head *data,
+			   struct msm_ipc_addr *dest)
+{
+	uint32_t dst_node_id = 0, dst_port_id = 0;
+	struct msm_ipc_server *server;
+	struct msm_ipc_server_port *server_port;
+	struct msm_ipc_router_remote_port *rport_ptr = NULL;
+	struct rr_packet *pkt;
+	int ret;
+
+	if (!src || !data || !dest) {
+		pr_err("%s: Invalid Parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	/* Resolve Address*/
+	if (dest->addrtype == MSM_IPC_ADDR_ID) {
+		dst_node_id = dest->addr.port_addr.node_id;
+		dst_port_id = dest->addr.port_addr.port_id;
+	} else if (dest->addrtype == MSM_IPC_ADDR_NAME) {
+		server = msm_ipc_router_lookup_server(
+					dest->addr.port_name.service,
+					dest->addr.port_name.instance,
+					0, 0);
+		if (!server) {
+			pr_err("%s: Destination not reachable\n", __func__);
+			return -ENODEV;
+		}
+		mutex_lock(&server_list_lock);
+		server_port = list_first_entry(&server->server_port_list,
+					       struct msm_ipc_server_port,
+					       list);
+		dst_node_id = server_port->server_addr.node_id;
+		dst_port_id = server_port->server_addr.port_id;
+		mutex_unlock(&server_list_lock);
+	}
+	if (dst_node_id == IPC_ROUTER_NID_LOCAL) {
+		ret = loopback_data(src, dst_port_id, data);
+		return ret;
+	}
+
+	/* Achieve Flow control */
+	rport_ptr = msm_ipc_router_lookup_remote_port(dst_node_id,
+						      dst_port_id);
+	if (!rport_ptr) {
+		pr_err("%s: Could not create remote port\n", __func__);
+		return -ENOMEM;
+	}
+
+	pkt = create_pkt(data);
+	if (!pkt) {
+		pr_err("%s: Pkt creation failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	ret = msm_ipc_router_write_pkt(src, rport_ptr, pkt);
+	release_pkt(pkt);
+
+	return ret;
+}
+
+int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
+			struct sk_buff_head **data,
+			size_t buf_len)
+{
+	struct rr_packet *pkt;
+	int ret;
+
+	if (!port_ptr || !data)
+		return -EINVAL;
+
+	mutex_lock(&port_ptr->port_rx_q_lock);
+	if (list_empty(&port_ptr->port_rx_q)) {
+		mutex_unlock(&port_ptr->port_rx_q_lock);
+		return -EAGAIN;
+	}
+
+	pkt = list_first_entry(&port_ptr->port_rx_q, struct rr_packet, list);
+	if ((buf_len) && ((pkt->length - IPC_ROUTER_HDR_SIZE) > buf_len)) {
+		mutex_unlock(&port_ptr->port_rx_q_lock);
+		return -ETOOSMALL;
+	}
+	list_del(&pkt->list);
+	if (list_empty(&port_ptr->port_rx_q))
+		wake_unlock(&port_ptr->port_rx_wake_lock);
+	*data = pkt->pkt_fragment_q;
+	ret = pkt->length;
+	kfree(pkt);
+	mutex_unlock(&port_ptr->port_rx_q_lock);
+
+	return ret;
+}
+
+int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
+			     struct sk_buff_head **data,
+			     struct msm_ipc_addr *src,
+			     unsigned long timeout)
+{
+	int ret, data_len, align_size;
+	struct sk_buff *temp_skb;
+	struct rr_header *hdr = NULL;
+
+	if (!port_ptr || !data) {
+		pr_err("%s: Invalid pointers being passed\n", __func__);
+		return -EINVAL;
+	}
+
+	*data = NULL;
+	mutex_lock(&port_ptr->port_rx_q_lock);
+	while (list_empty(&port_ptr->port_rx_q)) {
+		mutex_unlock(&port_ptr->port_rx_q_lock);
+		if (timeout < 0) {
+			ret = wait_event_interruptible(
+					port_ptr->port_rx_wait_q,
+					!list_empty(&port_ptr->port_rx_q));
+			if (ret)
+				return ret;
+		} else if (timeout > 0) {
+			timeout = wait_event_interruptible_timeout(
+					port_ptr->port_rx_wait_q,
+					!list_empty(&port_ptr->port_rx_q),
+					timeout);
+			if (timeout < 0)
+				return -EFAULT;
+		}
+		if (timeout == 0)
+			return -ETIMEDOUT;
+		mutex_lock(&port_ptr->port_rx_q_lock);
+	}
+	mutex_unlock(&port_ptr->port_rx_q_lock);
+
+	ret = msm_ipc_router_read(port_ptr, data, 0);
+	if (ret <= 0 || !(*data))
+		return ret;
+
+	temp_skb = skb_peek(*data);
+	hdr = (struct rr_header *)(temp_skb->data);
+	if (src) {
+		src->addrtype = MSM_IPC_ADDR_ID;
+		src->addr.port_addr.node_id = hdr->src_node_id;
+		src->addr.port_addr.port_id = hdr->src_port_id;
+	}
+
+	data_len = hdr->size;
+	skb_pull(temp_skb, IPC_ROUTER_HDR_SIZE);
+	align_size = ALIGN_SIZE(data_len);
+	if (align_size) {
+		temp_skb = skb_peek_tail(*data);
+		skb_trim(temp_skb, (temp_skb->len - align_size));
+	}
+	return data_len;
+}
+
+struct msm_ipc_port *msm_ipc_router_create_port(
+	void (*notify)(unsigned event, void *data, void *addr, void *priv),
+	void *priv)
+{
+	struct msm_ipc_port *port_ptr;
+
+	port_ptr = msm_ipc_router_create_raw_port(NULL, notify, priv);
+	if (!port_ptr)
+		pr_err("%s: port_ptr alloc failed\n", __func__);
+
+	return port_ptr;
+}
+
+int msm_ipc_router_close_port(struct msm_ipc_port *port_ptr)
+{
+	union rr_control_msg msg;
+	struct rr_packet *pkt, *temp_pkt;
+	struct msm_ipc_server *server;
+
+	if (!port_ptr)
+		return -EINVAL;
+
+	if (port_ptr->type == SERVER_PORT || port_ptr->type == CLIENT_PORT) {
+		if (port_ptr->type == SERVER_PORT) {
+			msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
+			msg.srv.service = port_ptr->port_name.service;
+			msg.srv.instance = port_ptr->port_name.instance;
+			msg.srv.node_id = port_ptr->this_port.node_id;
+			msg.srv.port_id = port_ptr->this_port.port_id;
+			RR("x REMOVE_SERVER Name=%d:%08x Id=%d:%08x\n",
+			   msg.srv.service, msg.srv.instance,
+			   msg.srv.node_id, msg.srv.port_id);
+		} else if (port_ptr->type == CLIENT_PORT) {
+			msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
+			msg.cli.node_id = port_ptr->this_port.node_id;
+			msg.cli.port_id = port_ptr->this_port.port_id;
+			RR("x REMOVE_CLIENT id=%d:%08x\n",
+			   msg.cli.node_id, msg.cli.port_id);
+		}
+		broadcast_ctl_msg(&msg);
+		broadcast_ctl_msg_locally(&msg);
+	}
+
+	mutex_lock(&port_ptr->port_rx_q_lock);
+	list_for_each_entry_safe(pkt, temp_pkt, &port_ptr->port_rx_q, list) {
+		list_del(&pkt->list);
+		release_pkt(pkt);
+	}
+	mutex_unlock(&port_ptr->port_rx_q_lock);
+
+	if (port_ptr->type == SERVER_PORT) {
+		server = msm_ipc_router_lookup_server(
+				port_ptr->port_name.service,
+				port_ptr->port_name.instance,
+				port_ptr->this_port.node_id,
+				port_ptr->this_port.port_id);
+		if (server)
+			msm_ipc_router_destroy_server(server,
+				port_ptr->this_port.node_id,
+				port_ptr->this_port.port_id);
+		mutex_lock(&local_ports_lock);
+		list_del(&port_ptr->list);
+		mutex_unlock(&local_ports_lock);
+	} else if (port_ptr->type == CLIENT_PORT) {
+		mutex_lock(&local_ports_lock);
+		list_del(&port_ptr->list);
+		mutex_unlock(&local_ports_lock);
+	} else if (port_ptr->type == CONTROL_PORT) {
+		mutex_lock(&control_ports_lock);
+		list_del(&port_ptr->list);
+		mutex_unlock(&control_ports_lock);
+	}
+
+	wake_lock_destroy(&port_ptr->port_rx_wake_lock);
+	kfree(port_ptr);
+	return 0;
+}
+
+int msm_ipc_router_get_curr_pkt_size(struct msm_ipc_port *port_ptr)
+{
+	struct rr_packet *pkt;
+	int rc = 0;
+
+	if (!port_ptr)
+		return -EINVAL;
+
+	mutex_lock(&port_ptr->port_rx_q_lock);
+	if (!list_empty(&port_ptr->port_rx_q)) {
+		pkt = list_first_entry(&port_ptr->port_rx_q,
+					struct rr_packet, list);
+		rc = pkt->length;
+	}
+	mutex_unlock(&port_ptr->port_rx_q_lock);
+
+	return rc;
+}
+
+int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr)
+{
+	if (!port_ptr)
+		return -EINVAL;
+
+	mutex_lock(&local_ports_lock);
+	list_del(&port_ptr->list);
+	mutex_unlock(&local_ports_lock);
+	port_ptr->type = CONTROL_PORT;
+	mutex_lock(&control_ports_lock);
+	list_add_tail(&port_ptr->list, &control_ports);
+	mutex_unlock(&control_ports_lock);
+
+	return 0;
+}
+
+int msm_ipc_router_lookup_server_name(struct msm_ipc_port_name *srv_name,
+				struct msm_ipc_port_addr *srv_addr,
+				int num_entries_in_array,
+				uint32_t lookup_mask)
+{
+	struct msm_ipc_server *server;
+	struct msm_ipc_server_port *server_port;
+	int key, i = 0; /*num_entries_found*/
+
+	if (!srv_name) {
+		pr_err("%s: Invalid srv_name\n", __func__);
+		return -EINVAL;
+	}
+
+	if (num_entries_in_array && !srv_addr) {
+		pr_err("%s: srv_addr NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&server_list_lock);
+	if (!lookup_mask)
+		lookup_mask = 0xFFFFFFFF;
+	for (key = 0; key < SRV_HASH_SIZE; key++) {
+		list_for_each_entry(server, &server_list[key], list) {
+			if ((server->name.service != srv_name->service) ||
+			    ((server->name.instance & lookup_mask) !=
+				srv_name->instance))
+				continue;
+
+			list_for_each_entry(server_port,
+				&server->server_port_list, list) {
+				if (i < num_entries_in_array) {
+					srv_addr[i].node_id =
+					  server_port->server_addr.node_id;
+					srv_addr[i].port_id =
+					  server_port->server_addr.port_id;
+				}
+				i++;
+			}
+		}
+	}
+	mutex_unlock(&server_list_lock);
+
+	return i;
+}
+
+int msm_ipc_router_close(void)
+{
+	struct msm_ipc_router_xprt_info *xprt_info, *tmp_xprt_info;
+
+	mutex_lock(&xprt_info_list_lock);
+	list_for_each_entry_safe(xprt_info, tmp_xprt_info,
+				 &xprt_info_list, list) {
+		xprt_info->xprt->close(xprt_info->xprt);
+		list_del(&xprt_info->list);
+		kfree(xprt_info);
+	}
+	mutex_unlock(&xprt_info_list_lock);
+	return 0;
+}
+
+#if defined(CONFIG_DEBUG_FS)
+static int dump_routing_table(char *buf, int max)
+{
+	int i = 0, j;
+	struct msm_ipc_routing_table_entry *rt_entry;
+
+	for (j = 0; j < RT_HASH_SIZE; j++) {
+		mutex_lock(&routing_table_lock);
+		list_for_each_entry(rt_entry, &routing_table[j], list) {
+			mutex_lock(&rt_entry->lock);
+			i += scnprintf(buf + i, max - i,
+				       "Node Id: 0x%08x\n", rt_entry->node_id);
+			if (j == IPC_ROUTER_NID_LOCAL) {
+				i += scnprintf(buf + i, max - i,
+				       "XPRT Name: Loopback\n");
+				i += scnprintf(buf + i, max - i,
+				       "Next Hop: %d\n", rt_entry->node_id);
+			} else {
+				i += scnprintf(buf + i, max - i,
+					"XPRT Name: %s\n",
+					rt_entry->xprt_info->xprt->name);
+				i += scnprintf(buf + i, max - i,
+					"Next Hop: 0x%08x\n",
+					rt_entry->xprt_info->remote_node_id);
+			}
+			i += scnprintf(buf + i, max - i, "\n");
+			mutex_unlock(&rt_entry->lock);
+		}
+		mutex_unlock(&routing_table_lock);
+	}
+
+	return i;
+}
+
+static int dump_xprt_info(char *buf, int max)
+{
+	int i = 0;
+	struct msm_ipc_router_xprt_info *xprt_info;
+
+	mutex_lock(&xprt_info_list_lock);
+	list_for_each_entry(xprt_info, &xprt_info_list, list) {
+		i += scnprintf(buf + i, max - i, "XPRT Name: %s\n",
+			       xprt_info->xprt->name);
+		i += scnprintf(buf + i, max - i, "Link Id: %d\n",
+			       xprt_info->xprt->link_id);
+		i += scnprintf(buf + i, max - i, "Initialized: %s\n",
+			       (xprt_info->initialized ? "Y" : "N"));
+		i += scnprintf(buf + i, max - i, "Remote Node Id: 0x%08x\n",
+			       xprt_info->remote_node_id);
+		i += scnprintf(buf + i, max - i, "\n");
+	}
+	mutex_unlock(&xprt_info_list_lock);
+
+	return i;
+}
+
+static int dump_servers(char *buf, int max)
+{
+	int i = 0, j;
+	struct msm_ipc_server *server;
+	struct msm_ipc_server_port *server_port;
+
+	mutex_lock(&server_list_lock);
+	for (j = 0; j < SRV_HASH_SIZE; j++) {
+		list_for_each_entry(server, &server_list[j], list) {
+			list_for_each_entry(server_port,
+					    &server->server_port_list,
+					    list) {
+				i += scnprintf(buf + i, max - i, "Service: "
+					"0x%08x\n", server->name.service);
+				i += scnprintf(buf + i, max - i, "Instance: "
+					"0x%08x\n", server->name.instance);
+				i += scnprintf(buf + i, max - i,
+					"Node_id: 0x%08x\n",
+					server_port->server_addr.node_id);
+				i += scnprintf(buf + i, max - i,
+					"Port_id: 0x%08x\n",
+					server_port->server_addr.port_id);
+				i += scnprintf(buf + i, max - i, "\n");
+			}
+		}
+	}
+	mutex_unlock(&server_list_lock);
+
+	return i;
+}
+
+static int dump_remote_ports(char *buf, int max)
+{
+	int i = 0, j, k;
+	struct msm_ipc_router_remote_port *rport_ptr;
+	struct msm_ipc_routing_table_entry *rt_entry;
+
+	for (j = 0; j < RT_HASH_SIZE; j++) {
+		mutex_lock(&routing_table_lock);
+		list_for_each_entry(rt_entry, &routing_table[j], list) {
+			mutex_lock(&rt_entry->lock);
+			for (k = 0; k < RP_HASH_SIZE; k++) {
+				list_for_each_entry(rport_ptr,
+					&rt_entry->remote_port_list[k],
+					list) {
+					i += scnprintf(buf + i, max - i,
+						"Node_id: 0x%08x\n",
+						rport_ptr->node_id);
+					i += scnprintf(buf + i, max - i,
+						"Port_id: 0x%08x\n",
+						rport_ptr->port_id);
+					i += scnprintf(buf + i, max - i,
+						"Quota_cnt: %d\n",
+						rport_ptr->tx_quota_cnt);
+				i += scnprintf(buf + i, max - i, "\n");
+				}
+			}
+			mutex_unlock(&rt_entry->lock);
+		}
+		mutex_unlock(&routing_table_lock);
+	}
+
+	return i;
+}
+
+static int dump_control_ports(char *buf, int max)
+{
+	int i = 0;
+	struct msm_ipc_port *port_ptr;
+
+	mutex_lock(&control_ports_lock);
+	list_for_each_entry(port_ptr, &control_ports, list) {
+		i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
+			       port_ptr->this_port.node_id);
+		i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
+			       port_ptr->this_port.port_id);
+		i += scnprintf(buf + i, max - i, "\n");
+	}
+	mutex_unlock(&control_ports_lock);
+
+	return i;
+}
+
+static int dump_local_ports(char *buf, int max)
+{
+	int i = 0, j;
+	unsigned long flags;
+	struct msm_ipc_port *port_ptr;
+
+	mutex_lock(&local_ports_lock);
+	for (j = 0; j < LP_HASH_SIZE; j++) {
+		list_for_each_entry(port_ptr, &local_ports[j], list) {
+			spin_lock_irqsave(&port_ptr->port_lock, flags);
+			i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
+				       port_ptr->this_port.node_id);
+			i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
+				       port_ptr->this_port.port_id);
+			i += scnprintf(buf + i, max - i, "# pkts tx'd %d\n",
+				       port_ptr->num_tx);
+			i += scnprintf(buf + i, max - i, "# pkts rx'd %d\n",
+				       port_ptr->num_rx);
+			i += scnprintf(buf + i, max - i, "# bytes tx'd %ld\n",
+				       port_ptr->num_tx_bytes);
+			i += scnprintf(buf + i, max - i, "# bytes rx'd %ld\n",
+				       port_ptr->num_rx_bytes);
+			spin_unlock_irqrestore(&port_ptr->port_lock, flags);
+			i += scnprintf(buf + i, max - i, "\n");
+		}
+	}
+	mutex_unlock(&local_ports_lock);
+
+	return i;
+}
+
+#define DEBUG_BUFMAX 4096
+static char debug_buffer[DEBUG_BUFMAX];
+
+static ssize_t debug_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *ppos)
+{
+	int (*fill)(char *buf, int max) = file->private_data;
+	int bsize = fill(debug_buffer, DEBUG_BUFMAX);
+	return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static const struct file_operations debug_ops = {
+	.read = debug_read,
+	.open = debug_open,
+};
+
+static void debug_create(const char *name, mode_t mode,
+			 struct dentry *dent,
+			 int (*fill)(char *buf, int max))
+{
+	debugfs_create_file(name, mode, dent, fill, &debug_ops);
+}
+
+static void debugfs_init(void)
+{
+	struct dentry *dent;
+
+	dent = debugfs_create_dir("msm_ipc_router", 0);
+	if (IS_ERR(dent))
+		return;
+
+	debug_create("dump_local_ports", 0444, dent,
+		      dump_local_ports);
+	debug_create("dump_remote_ports", 0444, dent,
+		      dump_remote_ports);
+	debug_create("dump_control_ports", 0444, dent,
+		      dump_control_ports);
+	debug_create("dump_servers", 0444, dent,
+		      dump_servers);
+	debug_create("dump_xprt_info", 0444, dent,
+		      dump_xprt_info);
+	debug_create("dump_routing_table", 0444, dent,
+		      dump_routing_table);
+}
+
+#else
+static void debugfs_init(void) {}
+#endif
+
+static int msm_ipc_router_add_xprt(struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_xprt_info *xprt_info;
+	struct msm_ipc_routing_table_entry *rt_entry;
+
+	xprt_info = kmalloc(sizeof(struct msm_ipc_router_xprt_info),
+			    GFP_KERNEL);
+	if (!xprt_info)
+		return -ENOMEM;
+
+	xprt_info->xprt = xprt;
+	xprt_info->initialized = 0;
+	xprt_info->remote_node_id = -1;
+	INIT_LIST_HEAD(&xprt_info->pkt_list);
+	init_waitqueue_head(&xprt_info->read_wait);
+	mutex_init(&xprt_info->rx_lock);
+	mutex_init(&xprt_info->tx_lock);
+	wake_lock_init(&xprt_info->wakelock,
+			WAKE_LOCK_SUSPEND, xprt->name);
+	xprt_info->need_len = 0;
+	xprt_info->abort_data_read = 0;
+	INIT_WORK(&xprt_info->read_data, do_read_data);
+	INIT_LIST_HEAD(&xprt_info->list);
+
+	xprt_info->workqueue = create_singlethread_workqueue(xprt->name);
+	if (!xprt_info->workqueue) {
+		kfree(xprt_info);
+		return -ENOMEM;
+	}
+
+	if (!strcmp(xprt->name, "msm_ipc_router_loopback_xprt")) {
+		xprt_info->remote_node_id = IPC_ROUTER_NID_LOCAL;
+		xprt_info->initialized = 1;
+	}
+
+	mutex_lock(&xprt_info_list_lock);
+	list_add_tail(&xprt_info->list, &xprt_info_list);
+	mutex_unlock(&xprt_info_list_lock);
+
+	mutex_lock(&routing_table_lock);
+	if (!routing_table_inited) {
+		init_routing_table();
+		rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
+		add_routing_table_entry(rt_entry);
+		routing_table_inited = 1;
+	}
+	mutex_unlock(&routing_table_lock);
+
+	queue_work(xprt_info->workqueue, &xprt_info->read_data);
+
+	xprt->priv = xprt_info;
+
+	return 0;
+}
+
+static void msm_ipc_router_remove_xprt(struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_xprt_info *xprt_info;
+
+	if (xprt && xprt->priv) {
+		xprt_info = xprt->priv;
+
+		xprt_info->abort_data_read = 1;
+		wake_up(&xprt_info->read_wait);
+
+		mutex_lock(&xprt_info_list_lock);
+		list_del(&xprt_info->list);
+		mutex_unlock(&xprt_info_list_lock);
+
+		flush_workqueue(xprt_info->workqueue);
+		destroy_workqueue(xprt_info->workqueue);
+		wake_lock_destroy(&xprt_info->wakelock);
+
+		xprt->priv = 0;
+		kfree(xprt_info);
+	}
+}
+
+
+struct msm_ipc_router_xprt_work {
+	struct msm_ipc_router_xprt *xprt;
+	struct work_struct work;
+};
+
+static void xprt_open_worker(struct work_struct *work)
+{
+	struct msm_ipc_router_xprt_work *xprt_work =
+		container_of(work, struct msm_ipc_router_xprt_work, work);
+
+	msm_ipc_router_add_xprt(xprt_work->xprt);
+	kfree(xprt_work);
+}
+
+static void xprt_close_worker(struct work_struct *work)
+{
+	struct msm_ipc_router_xprt_work *xprt_work =
+		container_of(work, struct msm_ipc_router_xprt_work, work);
+
+	modem_reset_cleanup(xprt_work->xprt->priv);
+	msm_ipc_router_remove_xprt(xprt_work->xprt);
+
+	if (atomic_dec_return(&pending_close_count) == 0)
+		wake_up(&subsystem_restart_wait);
+
+	kfree(xprt_work);
+}
+
+void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt,
+				unsigned event,
+				void *data)
+{
+	struct msm_ipc_router_xprt_info *xprt_info = xprt->priv;
+	struct msm_ipc_router_xprt_work *xprt_work;
+	struct rr_packet *pkt;
+	unsigned long ret;
+
+	if (!msm_ipc_router_workqueue) {
+		ret = wait_for_completion_timeout(&msm_ipc_local_router_up,
+						  IPC_ROUTER_INIT_TIMEOUT);
+		if (!ret || !msm_ipc_router_workqueue) {
+			pr_err("%s: IPC Router not initialized\n", __func__);
+			return;
+		}
+	}
+
+	switch (event) {
+	case IPC_ROUTER_XPRT_EVENT_OPEN:
+		D("open event for '%s'\n", xprt->name);
+		xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
+				GFP_ATOMIC);
+		xprt_work->xprt = xprt;
+		INIT_WORK(&xprt_work->work, xprt_open_worker);
+		queue_work(msm_ipc_router_workqueue, &xprt_work->work);
+		break;
+
+	case IPC_ROUTER_XPRT_EVENT_CLOSE:
+		D("close event for '%s'\n", xprt->name);
+		atomic_inc(&pending_close_count);
+		xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
+				GFP_ATOMIC);
+		xprt_work->xprt = xprt;
+		INIT_WORK(&xprt_work->work, xprt_close_worker);
+		queue_work(msm_ipc_router_workqueue, &xprt_work->work);
+		break;
+	}
+
+	if (!data)
+		return;
+
+	while (!xprt_info) {
+		msleep(100);
+		xprt_info = xprt->priv;
+	}
+
+	pkt = clone_pkt((struct rr_packet *)data);
+	if (!pkt)
+		return;
+
+	mutex_lock(&xprt_info->rx_lock);
+	list_add_tail(&pkt->list, &xprt_info->pkt_list);
+	wake_lock(&xprt_info->wakelock);
+	wake_up(&xprt_info->read_wait);
+	mutex_unlock(&xprt_info->rx_lock);
+}
+
+static int modem_restart_notifier_cb(struct notifier_block *this,
+				unsigned long code,
+				void *data);
+static struct notifier_block msm_ipc_router_nb = {
+	.notifier_call = modem_restart_notifier_cb,
+};
+
+static int modem_restart_notifier_cb(struct notifier_block *this,
+				unsigned long code,
+				void *data)
+{
+	switch (code) {
+	case SUBSYS_BEFORE_SHUTDOWN:
+		D("%s: SUBSYS_BEFORE_SHUTDOWN\n", __func__);
+		break;
+
+	case SUBSYS_BEFORE_POWERUP:
+		D("%s: waiting for RPC restart to complete\n", __func__);
+		wait_event(subsystem_restart_wait,
+			atomic_read(&pending_close_count) == 0);
+		D("%s: finished restart wait\n", __func__);
+		break;
+
+	default:
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static void *restart_notifier_handle;
+static __init int msm_ipc_router_modem_restart_late_init(void)
+{
+	restart_notifier_handle = subsys_notif_register_notifier("modem",
+							&msm_ipc_router_nb);
+	return 0;
+}
+late_initcall(msm_ipc_router_modem_restart_late_init);
+
+static int __init msm_ipc_router_init(void)
+{
+	int i, ret;
+	struct msm_ipc_routing_table_entry *rt_entry;
+
+	msm_ipc_router_debug_mask |= SMEM_LOG;
+	msm_ipc_router_workqueue =
+		create_singlethread_workqueue("msm_ipc_router");
+	if (!msm_ipc_router_workqueue)
+		return -ENOMEM;
+
+	debugfs_init();
+
+	for (i = 0; i < SRV_HASH_SIZE; i++)
+		INIT_LIST_HEAD(&server_list[i]);
+
+	for (i = 0; i < LP_HASH_SIZE; i++)
+		INIT_LIST_HEAD(&local_ports[i]);
+
+	mutex_lock(&routing_table_lock);
+	if (!routing_table_inited) {
+		init_routing_table();
+		rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
+		add_routing_table_entry(rt_entry);
+		routing_table_inited = 1;
+	}
+	mutex_unlock(&routing_table_lock);
+
+	init_waitqueue_head(&newserver_wait);
+	init_waitqueue_head(&subsystem_restart_wait);
+	ret = msm_ipc_router_init_sockets();
+	if (ret < 0)
+		pr_err("%s: Init sockets failed\n", __func__);
+
+	complete_all(&msm_ipc_local_router_up);
+	return ret;
+}
+
+module_init(msm_ipc_router_init);
+MODULE_DESCRIPTION("MSM IPC Router");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/ipc_router.h b/arch/arm/mach-msm/ipc_router.h
new file mode 100644
index 0000000..a90be23
--- /dev/null
+++ b/arch/arm/mach-msm/ipc_router.h
@@ -0,0 +1,220 @@
+/* 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
+ * 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 _ARCH_ARM_MACH_MSM_IPC_ROUTER_H
+#define _ARCH_ARM_MACH_MSM_IPC_ROUTER_H
+
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/list.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+#include <linux/wakelock.h>
+#include <linux/msm_ipc.h>
+
+#include <net/sock.h>
+
+/* definitions for the R2R wire protcol */
+#define IPC_ROUTER_VERSION			1
+#define IPC_ROUTER_PROCESSORS_MAX		4
+
+#define IPC_ROUTER_CLIENT_BCAST_ID		0xffffffff
+#define IPC_ROUTER_ADDRESS			0xfffffffe
+
+#define IPC_ROUTER_NID_LOCAL			1
+#define IPC_ROUTER_NID_REMOTE			0
+
+#define IPC_ROUTER_CTRL_CMD_DATA		1
+#define IPC_ROUTER_CTRL_CMD_HELLO		2
+#define IPC_ROUTER_CTRL_CMD_BYE			3
+#define IPC_ROUTER_CTRL_CMD_NEW_SERVER		4
+#define IPC_ROUTER_CTRL_CMD_REMOVE_SERVER	5
+#define IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT	6
+#define IPC_ROUTER_CTRL_CMD_RESUME_TX		7
+#define IPC_ROUTER_CTRL_CMD_EXIT		8
+#define IPC_ROUTER_CTRL_CMD_PING		9
+
+#define IPC_ROUTER_DEFAULT_RX_QUOTA	5
+
+#define IPC_ROUTER_XPRT_EVENT_DATA  1
+#define IPC_ROUTER_XPRT_EVENT_OPEN  2
+#define IPC_ROUTER_XPRT_EVENT_CLOSE 3
+
+#define NUM_NODES 2
+
+#define IPC_ROUTER_INFINITY -1
+#define DEFAULT_RCV_TIMEO IPC_ROUTER_INFINITY
+
+#define ALIGN_SIZE(x) ((4 - ((x) & 3)) & 3)
+
+enum {
+	MSM_IPC_ROUTER_READ_CB = 0,
+	MSM_IPC_ROUTER_WRITE_DONE,
+};
+
+union rr_control_msg {
+	uint32_t cmd;
+	struct {
+		uint32_t cmd;
+		uint32_t service;
+		uint32_t instance;
+		uint32_t node_id;
+		uint32_t port_id;
+	} srv;
+	struct {
+		uint32_t cmd;
+		uint32_t node_id;
+		uint32_t port_id;
+	} cli;
+};
+
+struct rr_header {
+	uint32_t version;
+	uint32_t type;
+	uint32_t src_node_id;
+	uint32_t src_port_id;
+	uint32_t confirm_rx;
+	uint32_t size;
+	uint32_t dst_node_id;
+	uint32_t dst_port_id;
+};
+
+#define IPC_ROUTER_HDR_SIZE sizeof(struct rr_header)
+#define MAX_IPC_PKT_SIZE 66000
+/* internals */
+
+#define IPC_ROUTER_MAX_REMOTE_SERVERS		100
+#define MAX_WAKELOCK_NAME_SZ 32
+
+struct rr_packet {
+	struct list_head list;
+	struct sk_buff_head *pkt_fragment_q;
+	uint32_t length;
+};
+
+struct msm_ipc_port {
+	struct list_head list;
+
+	struct msm_ipc_port_addr this_port;
+	struct msm_ipc_port_name port_name;
+	uint32_t type;
+	unsigned flags;
+	spinlock_t port_lock;
+
+	struct list_head incomplete;
+	struct mutex incomplete_lock;
+
+	struct list_head port_rx_q;
+	struct mutex port_rx_q_lock;
+	char rx_wakelock_name[MAX_WAKELOCK_NAME_SZ];
+	struct wake_lock port_rx_wake_lock;
+	wait_queue_head_t port_rx_wait_q;
+
+	int restart_state;
+	spinlock_t restart_lock;
+	wait_queue_head_t restart_wait;
+
+	void *endpoint;
+	void (*notify)(unsigned event, void *data, void *addr, void *priv);
+
+	uint32_t num_tx;
+	uint32_t num_rx;
+	unsigned long num_tx_bytes;
+	unsigned long num_rx_bytes;
+	void *priv;
+};
+
+struct msm_ipc_sock {
+	struct sock sk;
+	struct msm_ipc_port *port;
+	void *default_pil;
+};
+
+enum write_data_type {
+	HEADER = 1,
+	PACKMARK,
+	PAYLOAD,
+};
+
+struct msm_ipc_router_xprt {
+	char *name;
+	uint32_t link_id;
+	void *priv;
+
+	int (*read_avail)(struct msm_ipc_router_xprt *xprt);
+	int (*read)(void *data, uint32_t len,
+		    struct msm_ipc_router_xprt *xprt);
+	int (*write_avail)(struct msm_ipc_router_xprt *xprt);
+	int (*write)(void *data, uint32_t len,
+		     struct msm_ipc_router_xprt *xprt);
+	int (*close)(struct msm_ipc_router_xprt *xprt);
+};
+
+extern struct completion msm_ipc_remote_router_up;
+
+void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt,
+				unsigned event,
+				void *data);
+
+
+struct rr_packet *clone_pkt(struct rr_packet *pkt);
+void release_pkt(struct rr_packet *pkt);
+
+
+struct msm_ipc_port *msm_ipc_router_create_raw_port(void *endpoint,
+		void (*notify)(unsigned event, void *data,
+			       void *addr, void *priv),
+		void *priv);
+int msm_ipc_router_send_to(struct msm_ipc_port *src,
+			   struct sk_buff_head *data,
+			   struct msm_ipc_addr *dest);
+int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
+			struct sk_buff_head **data,
+			size_t buf_len);
+int msm_ipc_router_get_curr_pkt_size(struct msm_ipc_port *port_ptr);
+int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr);
+int msm_ipc_router_lookup_server_name(struct msm_ipc_port_name *srv_name,
+				      struct msm_ipc_port_addr *port_addr,
+				      int num_entries_in_array,
+				      uint32_t lookup_mask);
+int msm_ipc_router_close_port(struct msm_ipc_port *port_ptr);
+
+struct msm_ipc_port *msm_ipc_router_create_port(
+	void (*notify)(unsigned event, void *data,
+		       void *addr, void *priv),
+	void *priv);
+int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
+		      struct sk_buff_head **data,
+		      struct msm_ipc_addr *src_addr,
+		      unsigned long timeout);
+int msm_ipc_router_register_server(struct msm_ipc_port *server_port,
+			    struct msm_ipc_addr *name);
+int msm_ipc_router_unregister_server(struct msm_ipc_port *server_port);
+
+
+int msm_ipc_router_init_sockets(void);
+void msm_ipc_router_exit_sockets(void);
+
+#if defined CONFIG_MSM_IPC_ROUTER_SMD_XPRT
+extern void *msm_ipc_load_default_node(void);
+
+extern void msm_ipc_unload_default_node(void *pil);
+#else
+static inline void *msm_ipc_load_default_node(void)
+{ return NULL; }
+
+static inline void msm_ipc_unload_default_node(void *pil) { }
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/ipc_router_smd_xprt.c b/arch/arm/mach-msm/ipc_router_smd_xprt.c
new file mode 100644
index 0000000..5649784
--- /dev/null
+++ b/arch/arm/mach-msm/ipc_router_smd_xprt.c
@@ -0,0 +1,507 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * IPC ROUTER SMD XPRT module.
+ */
+#define DEBUG
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+#include <mach/msm_smd.h>
+#include <mach/peripheral-loader.h>
+
+#include "ipc_router.h"
+#include "smd_private.h"
+
+static int msm_ipc_router_smd_xprt_debug_mask;
+module_param_named(debug_mask, msm_ipc_router_smd_xprt_debug_mask,
+		   int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#if defined(DEBUG)
+#define D(x...) do { \
+if (msm_ipc_router_smd_xprt_debug_mask) \
+	pr_info(x); \
+} while (0)
+#else
+#define D(x...) do { } while (0)
+#endif
+
+#define MIN_FRAG_SZ (IPC_ROUTER_HDR_SIZE + sizeof(union rr_control_msg))
+
+#define NUM_SMD_XPRTS 3
+#define XPRT_NAME_LEN (SMD_MAX_CH_NAME_LEN + 12)
+
+struct msm_ipc_router_smd_xprt {
+	struct msm_ipc_router_xprt xprt;
+	smd_channel_t *channel;
+	struct workqueue_struct *smd_xprt_wq;
+	wait_queue_head_t write_avail_wait_q;
+	struct rr_packet *in_pkt;
+	int is_partial_in_pkt;
+	struct delayed_work read_work;
+	spinlock_t ss_reset_lock;	/*Subsystem reset lock*/
+	int ss_reset;
+};
+
+struct msm_ipc_router_smd_xprt_work {
+	struct msm_ipc_router_xprt *xprt;
+	struct work_struct work;
+};
+
+static void smd_xprt_read_data(struct work_struct *work);
+static void smd_xprt_open_event(struct work_struct *work);
+static void smd_xprt_close_event(struct work_struct *work);
+
+struct msm_ipc_router_smd_xprt_config {
+	char ch_name[SMD_MAX_CH_NAME_LEN];
+	char xprt_name[XPRT_NAME_LEN];
+	uint32_t edge;
+	uint32_t link_id;
+};
+
+struct msm_ipc_router_smd_xprt_config smd_xprt_cfg[] = {
+	{"RPCRPY_CNTL", "ipc_rtr_smd_rpcrpy_cntl", SMD_APPS_MODEM, 1},
+	{"IPCRTR", "ipc_rtr_smd_ipcrtr", SMD_APPS_MODEM, 1},
+	{"IPCRTR", "ipc_rtr_q6_ipcrtr", SMD_APPS_QDSP, 1},
+};
+
+static struct msm_ipc_router_smd_xprt smd_remote_xprt[NUM_SMD_XPRTS];
+
+static int find_smd_xprt_cfg(struct platform_device *pdev)
+{
+	int i;
+
+	for (i = 0; i < NUM_SMD_XPRTS; i++) {
+		if (!strncmp(pdev->name, smd_xprt_cfg[i].ch_name, 20) &&
+		    (pdev->id == smd_xprt_cfg[i].edge))
+			return i;
+	}
+
+	return -ENODEV;
+}
+
+static int msm_ipc_router_smd_remote_write_avail(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_smd_xprt *smd_xprtp =
+		container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
+
+	return smd_write_avail(smd_xprtp->channel);
+}
+
+static int msm_ipc_router_smd_remote_write(void *data,
+					   uint32_t len,
+					   struct msm_ipc_router_xprt *xprt)
+{
+	struct rr_packet *pkt = (struct rr_packet *)data;
+	struct sk_buff *ipc_rtr_pkt;
+	int align_sz, align_data = 0;
+	int offset, sz_written = 0;
+	int ret, num_retries = 0;
+	unsigned long flags;
+	struct msm_ipc_router_smd_xprt *smd_xprtp =
+		container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
+
+	if (!pkt)
+		return -EINVAL;
+
+	if (!len || pkt->length != len)
+		return -EINVAL;
+
+	align_sz = ALIGN_SIZE(pkt->length);
+	while ((ret = smd_write_start(smd_xprtp->channel,
+				      (len + align_sz))) < 0) {
+		spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
+		if (smd_xprtp->ss_reset) {
+			spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
+						flags);
+			pr_err("%s: %s chnl reset\n", __func__, xprt->name);
+			return -ENETRESET;
+		}
+		spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
+		if (num_retries >= 5) {
+			pr_err("%s: Error %d @smd_write_start for %s\n",
+				__func__, ret, xprt->name);
+			return ret;
+		}
+		msleep(50);
+		num_retries++;
+	}
+
+	D("%s: Ready to write\n", __func__);
+	skb_queue_walk(pkt->pkt_fragment_q, ipc_rtr_pkt) {
+		offset = 0;
+		while (offset < ipc_rtr_pkt->len) {
+			if (!smd_write_avail(smd_xprtp->channel))
+				smd_enable_read_intr(smd_xprtp->channel);
+
+			wait_event(smd_xprtp->write_avail_wait_q,
+				(smd_write_avail(smd_xprtp->channel) ||
+				smd_xprtp->ss_reset));
+			smd_disable_read_intr(smd_xprtp->channel);
+			spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
+			if (smd_xprtp->ss_reset) {
+				spin_unlock_irqrestore(
+					&smd_xprtp->ss_reset_lock, flags);
+				pr_err("%s: %s chnl reset\n",
+					__func__, xprt->name);
+				return -ENETRESET;
+			}
+			spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
+						flags);
+
+			sz_written = smd_write_segment(smd_xprtp->channel,
+					ipc_rtr_pkt->data + offset,
+					(ipc_rtr_pkt->len - offset), 0);
+			offset += sz_written;
+			sz_written = 0;
+		}
+		D("%s: Wrote %d bytes over %s\n",
+		  __func__, offset, xprt->name);
+	}
+
+	if (align_sz) {
+		if (smd_write_avail(smd_xprtp->channel) < align_sz)
+			smd_enable_read_intr(smd_xprtp->channel);
+
+		wait_event(smd_xprtp->write_avail_wait_q,
+			((smd_write_avail(smd_xprtp->channel) >=
+			 align_sz) || smd_xprtp->ss_reset));
+		smd_disable_read_intr(smd_xprtp->channel);
+		spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
+		if (smd_xprtp->ss_reset) {
+			spin_unlock_irqrestore(
+				&smd_xprtp->ss_reset_lock, flags);
+			pr_err("%s: %s chnl reset\n",
+				__func__, xprt->name);
+			return -ENETRESET;
+		}
+		spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
+					flags);
+
+		smd_write_segment(smd_xprtp->channel,
+				  &align_data, align_sz, 0);
+		D("%s: Wrote %d align bytes over %s\n",
+		  __func__, align_sz, xprt->name);
+	}
+	if (!smd_write_end(smd_xprtp->channel))
+		D("%s: Finished writing\n", __func__);
+	return len;
+}
+
+static int msm_ipc_router_smd_remote_close(struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_smd_xprt *smd_xprtp =
+		container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
+
+	return smd_close(smd_xprtp->channel);
+}
+
+static void smd_xprt_read_data(struct work_struct *work)
+{
+	int pkt_size, sz_read, sz;
+	struct sk_buff *ipc_rtr_pkt;
+	void *data;
+	unsigned long flags;
+	struct delayed_work *rwork = to_delayed_work(work);
+	struct msm_ipc_router_smd_xprt *smd_xprtp =
+		container_of(rwork, struct msm_ipc_router_smd_xprt, read_work);
+
+	spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
+	if (smd_xprtp->ss_reset) {
+		spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
+		if (smd_xprtp->in_pkt)
+			release_pkt(smd_xprtp->in_pkt);
+		smd_xprtp->is_partial_in_pkt = 0;
+		pr_err("%s: %s channel reset\n",
+			__func__, smd_xprtp->xprt.name);
+		return;
+	}
+	spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
+
+	D("%s pkt_size: %d, read_avail: %d\n", __func__,
+		smd_cur_packet_size(smd_xprtp->channel),
+		smd_read_avail(smd_xprtp->channel));
+	while ((pkt_size = smd_cur_packet_size(smd_xprtp->channel)) &&
+		smd_read_avail(smd_xprtp->channel)) {
+		if (!smd_xprtp->is_partial_in_pkt) {
+			smd_xprtp->in_pkt = kzalloc(sizeof(struct rr_packet),
+						    GFP_KERNEL);
+			if (!smd_xprtp->in_pkt) {
+				pr_err("%s: Couldn't alloc rr_packet\n",
+					__func__);
+				return;
+			}
+
+			smd_xprtp->in_pkt->pkt_fragment_q =
+				kmalloc(sizeof(struct sk_buff_head),
+					GFP_KERNEL);
+			if (!smd_xprtp->in_pkt->pkt_fragment_q) {
+				pr_err("%s: Couldn't alloc pkt_fragment_q\n",
+					__func__);
+				kfree(smd_xprtp->in_pkt);
+				return;
+			}
+			skb_queue_head_init(smd_xprtp->in_pkt->pkt_fragment_q);
+			smd_xprtp->is_partial_in_pkt = 1;
+			D("%s: Allocated rr_packet\n", __func__);
+		}
+
+		if (((pkt_size >= MIN_FRAG_SZ) &&
+		     (smd_read_avail(smd_xprtp->channel) < MIN_FRAG_SZ)) ||
+		    ((pkt_size < MIN_FRAG_SZ) &&
+		     (smd_read_avail(smd_xprtp->channel) < pkt_size)))
+			return;
+
+		sz = smd_read_avail(smd_xprtp->channel);
+		do {
+			ipc_rtr_pkt = alloc_skb(sz, GFP_KERNEL);
+			if (!ipc_rtr_pkt) {
+				if (sz <= (PAGE_SIZE/2)) {
+					queue_delayed_work(
+						smd_xprtp->smd_xprt_wq,
+						&smd_xprtp->read_work,
+						msecs_to_jiffies(100));
+					return;
+				}
+				sz = sz / 2;
+			}
+		} while (!ipc_rtr_pkt);
+
+		D("%s: Allocated the sk_buff of size %d\n", __func__, sz);
+		data = skb_put(ipc_rtr_pkt, sz);
+		sz_read = smd_read(smd_xprtp->channel, data, sz);
+		if (sz_read != sz) {
+			pr_err("%s: Couldn't read %s completely\n",
+				__func__, smd_xprtp->xprt.name);
+			kfree_skb(ipc_rtr_pkt);
+			release_pkt(smd_xprtp->in_pkt);
+			smd_xprtp->is_partial_in_pkt = 0;
+			return;
+		}
+		skb_queue_tail(smd_xprtp->in_pkt->pkt_fragment_q, ipc_rtr_pkt);
+		smd_xprtp->in_pkt->length += sz_read;
+		if (sz_read != pkt_size)
+			smd_xprtp->is_partial_in_pkt = 1;
+		else
+			smd_xprtp->is_partial_in_pkt = 0;
+
+		if (!smd_xprtp->is_partial_in_pkt) {
+			D("%s: Packet size read %d\n",
+			  __func__, smd_xprtp->in_pkt->length);
+			msm_ipc_router_xprt_notify(&smd_xprtp->xprt,
+						IPC_ROUTER_XPRT_EVENT_DATA,
+						(void *)smd_xprtp->in_pkt);
+			release_pkt(smd_xprtp->in_pkt);
+			smd_xprtp->in_pkt = NULL;
+		}
+	}
+}
+
+static void smd_xprt_open_event(struct work_struct *work)
+{
+	struct msm_ipc_router_smd_xprt_work *xprt_work =
+		container_of(work, struct msm_ipc_router_smd_xprt_work, work);
+
+	msm_ipc_router_xprt_notify(xprt_work->xprt,
+				IPC_ROUTER_XPRT_EVENT_OPEN, NULL);
+	D("%s: Notified IPC Router of %s OPEN\n",
+	   __func__, xprt_work->xprt->name);
+	kfree(xprt_work);
+}
+
+static void smd_xprt_close_event(struct work_struct *work)
+{
+	struct msm_ipc_router_smd_xprt_work *xprt_work =
+		container_of(work, struct msm_ipc_router_smd_xprt_work, work);
+
+	msm_ipc_router_xprt_notify(xprt_work->xprt,
+				IPC_ROUTER_XPRT_EVENT_CLOSE, NULL);
+	D("%s: Notified IPC Router of %s CLOSE\n",
+	   __func__, xprt_work->xprt->name);
+	kfree(xprt_work);
+}
+
+static void msm_ipc_router_smd_remote_notify(void *_dev, unsigned event)
+{
+	unsigned long flags;
+	struct msm_ipc_router_smd_xprt *smd_xprtp;
+	struct msm_ipc_router_smd_xprt_work *xprt_work;
+
+	smd_xprtp = (struct msm_ipc_router_smd_xprt *)_dev;
+	if (!smd_xprtp)
+		return;
+
+	switch (event) {
+	case SMD_EVENT_DATA:
+		if (smd_read_avail(smd_xprtp->channel))
+			queue_delayed_work(smd_xprtp->smd_xprt_wq,
+					   &smd_xprtp->read_work, 0);
+		if (smd_write_avail(smd_xprtp->channel))
+			wake_up(&smd_xprtp->write_avail_wait_q);
+		break;
+
+	case SMD_EVENT_OPEN:
+		spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
+		smd_xprtp->ss_reset = 0;
+		spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
+		xprt_work = kmalloc(sizeof(struct msm_ipc_router_smd_xprt_work),
+				    GFP_ATOMIC);
+		if (!xprt_work) {
+			pr_err("%s: Couldn't notify %d event to IPC Router\n",
+				__func__, event);
+			return;
+		}
+		xprt_work->xprt = &smd_xprtp->xprt;
+		INIT_WORK(&xprt_work->work, smd_xprt_open_event);
+		queue_work(smd_xprtp->smd_xprt_wq, &xprt_work->work);
+		break;
+
+	case SMD_EVENT_CLOSE:
+		spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
+		smd_xprtp->ss_reset = 1;
+		spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
+		wake_up(&smd_xprtp->write_avail_wait_q);
+		xprt_work = kmalloc(sizeof(struct msm_ipc_router_smd_xprt_work),
+				    GFP_ATOMIC);
+		if (!xprt_work) {
+			pr_err("%s: Couldn't notify %d event to IPC Router\n",
+				__func__, event);
+			return;
+		}
+		xprt_work->xprt = &smd_xprtp->xprt;
+		INIT_WORK(&xprt_work->work, smd_xprt_close_event);
+		queue_work(smd_xprtp->smd_xprt_wq, &xprt_work->work);
+		break;
+	}
+}
+
+static int msm_ipc_router_smd_remote_probe(struct platform_device *pdev)
+{
+	int rc;
+	int id;		/*Index into the smd_xprt_cfg table*/
+
+	id = find_smd_xprt_cfg(pdev);
+	if (id < 0) {
+		pr_err("%s: called for unknown ch %s\n",
+			__func__, pdev->name);
+		return id;
+	}
+
+	smd_remote_xprt[id].smd_xprt_wq =
+		create_singlethread_workqueue(pdev->name);
+	if (!smd_remote_xprt[id].smd_xprt_wq) {
+		pr_err("%s: WQ creation failed for %s\n",
+			__func__, pdev->name);
+		return -EFAULT;
+	}
+
+	smd_remote_xprt[id].xprt.name = smd_xprt_cfg[id].xprt_name;
+	smd_remote_xprt[id].xprt.link_id = smd_xprt_cfg[id].link_id;
+	smd_remote_xprt[id].xprt.read_avail = NULL;
+	smd_remote_xprt[id].xprt.read = NULL;
+	smd_remote_xprt[id].xprt.write_avail =
+		msm_ipc_router_smd_remote_write_avail;
+	smd_remote_xprt[id].xprt.write = msm_ipc_router_smd_remote_write;
+	smd_remote_xprt[id].xprt.close = msm_ipc_router_smd_remote_close;
+	smd_remote_xprt[id].xprt.priv = NULL;
+
+	init_waitqueue_head(&smd_remote_xprt[id].write_avail_wait_q);
+	smd_remote_xprt[id].in_pkt = NULL;
+	smd_remote_xprt[id].is_partial_in_pkt = 0;
+	INIT_DELAYED_WORK(&smd_remote_xprt[id].read_work, smd_xprt_read_data);
+	spin_lock_init(&smd_remote_xprt[id].ss_reset_lock);
+	smd_remote_xprt[id].ss_reset = 0;
+
+	rc = smd_named_open_on_edge(smd_xprt_cfg[id].ch_name,
+				    smd_xprt_cfg[id].edge,
+				    &smd_remote_xprt[id].channel,
+				    &smd_remote_xprt[id],
+				    msm_ipc_router_smd_remote_notify);
+	if (rc < 0) {
+		pr_err("%s: Channel open failed for %s\n",
+			__func__, smd_xprt_cfg[id].ch_name);
+		destroy_workqueue(smd_remote_xprt[id].smd_xprt_wq);
+		return rc;
+	}
+
+	smd_disable_read_intr(smd_remote_xprt[id].channel);
+
+	smsm_change_state(SMSM_APPS_STATE, 0, SMSM_RPCINIT);
+
+	return 0;
+}
+
+void *msm_ipc_load_default_node(void)
+{
+	void *pil = NULL;
+	const char *peripheral;
+
+	peripheral = smd_edge_to_subsystem(SMD_APPS_MODEM);
+	if (peripheral && !strncmp(peripheral, "modem", 6)) {
+		pil = pil_get(peripheral);
+		if (IS_ERR(pil)) {
+			pr_err("%s: Failed to load %s\n",
+				__func__, peripheral);
+			pil = NULL;
+		}
+	}
+	return pil;
+}
+EXPORT_SYMBOL(msm_ipc_load_default_node);
+
+void msm_ipc_unload_default_node(void *pil)
+{
+	if (pil)
+		pil_put(pil);
+}
+EXPORT_SYMBOL(msm_ipc_unload_default_node);
+
+static struct platform_driver msm_ipc_router_smd_remote_driver[] = {
+	{
+		.probe		= msm_ipc_router_smd_remote_probe,
+		.driver		= {
+				.name	= "RPCRPY_CNTL",
+				.owner	= THIS_MODULE,
+		},
+	},
+	{
+		.probe		= msm_ipc_router_smd_remote_probe,
+		.driver		= {
+				.name	= "IPCRTR",
+				.owner	= THIS_MODULE,
+		},
+	},
+};
+
+static int __init msm_ipc_router_smd_init(void)
+{
+	int i, ret, rc = 0;
+	BUG_ON(ARRAY_SIZE(smd_xprt_cfg) != NUM_SMD_XPRTS);
+	for (i = 0; i < ARRAY_SIZE(msm_ipc_router_smd_remote_driver); i++) {
+		ret = platform_driver_register(
+				&msm_ipc_router_smd_remote_driver[i]);
+		if (ret) {
+			pr_err("%s: Failed to register platform driver for"
+			       " xprt%d. Continuing...\n", __func__, i);
+			rc = ret;
+		}
+	}
+	return rc;
+}
+
+module_init(msm_ipc_router_smd_init);
+MODULE_DESCRIPTION("IPC Router SMD XPRT");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
new file mode 100644
index 0000000..d82ffe5
--- /dev/null
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -0,0 +1,548 @@
+/* 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
+ * 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/module.h>
+#include <linux/types.h>
+#include <linux/net.h>
+#include <linux/socket.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/poll.h>
+#include <linux/fcntl.h>
+#include <linux/gfp.h>
+#include <linux/msm_ipc.h>
+
+#ifdef CONFIG_ANDROID_PARANOID_NETWORK
+#include <linux/android_aid.h>
+#endif
+
+#include <asm/string.h>
+#include <asm/atomic.h>
+
+#include <net/sock.h>
+
+#include "ipc_router.h"
+
+#define msm_ipc_sk(sk) ((struct msm_ipc_sock *)(sk))
+#define msm_ipc_sk_port(sk) ((struct msm_ipc_port *)(msm_ipc_sk(sk)->port))
+
+static int sockets_enabled;
+static struct proto msm_ipc_proto;
+static const struct proto_ops msm_ipc_proto_ops;
+
+#ifdef CONFIG_ANDROID_PARANOID_NETWORK
+static inline int check_permissions(void)
+{
+	int rc = 0;
+	if (!current_euid() || in_egroup_p(AID_NET_RAW))
+		rc = 1;
+	return rc;
+}
+# else
+static inline int check_permissions(void)
+{
+	return 1;
+}
+#endif
+
+static struct sk_buff_head *msm_ipc_router_build_msg(unsigned int num_sect,
+					  struct iovec const *msg_sect,
+					  size_t total_len)
+{
+	struct sk_buff_head *msg_head;
+	struct sk_buff *msg;
+	int i, copied, first = 1;
+	int data_size = 0, request_size, offset;
+	void *data;
+
+	for (i = 0; i < num_sect; i++)
+		data_size += msg_sect[i].iov_len;
+
+	if (!data_size)
+		return NULL;
+
+	msg_head = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
+	if (!msg_head) {
+		pr_err("%s: cannot allocate skb_head\n", __func__);
+		return NULL;
+	}
+	skb_queue_head_init(msg_head);
+
+	for (copied = 1, i = 0; copied && (i < num_sect); i++) {
+		data_size = msg_sect[i].iov_len;
+		offset = 0;
+		while (offset != msg_sect[i].iov_len) {
+			request_size = data_size;
+			if (first)
+				request_size += IPC_ROUTER_HDR_SIZE;
+
+			msg = alloc_skb(request_size, GFP_KERNEL);
+			if (!msg) {
+				if (request_size <= (PAGE_SIZE/2)) {
+					pr_err("%s: cannot allocated skb\n",
+						__func__);
+					goto msg_build_failure;
+				}
+				data_size = data_size / 2;
+				continue;
+			}
+
+			if (first) {
+				skb_reserve(msg, IPC_ROUTER_HDR_SIZE);
+				first = 0;
+			}
+
+			data = skb_put(msg, data_size);
+			copied = !copy_from_user(msg->data,
+					msg_sect[i].iov_base + offset,
+					data_size);
+			if (!copied) {
+				pr_err("%s: copy_from_user failed\n",
+					__func__);
+				kfree_skb(msg);
+				goto msg_build_failure;
+			}
+			skb_queue_tail(msg_head, msg);
+			offset += data_size;
+			data_size = msg_sect[i].iov_len - offset;
+		}
+	}
+	return msg_head;
+
+msg_build_failure:
+	while (!skb_queue_empty(msg_head)) {
+		msg = skb_dequeue(msg_head);
+		kfree_skb(msg);
+	}
+	kfree(msg_head);
+	return NULL;
+}
+
+static int msm_ipc_router_extract_msg(struct msghdr *m,
+				      struct sk_buff_head *msg_head)
+{
+	struct sockaddr_msm_ipc *addr = (struct sockaddr_msm_ipc *)m->msg_name;
+	struct rr_header *hdr;
+	struct sk_buff *temp;
+	int offset = 0, data_len = 0, copy_len;
+
+	if (!m || !msg_head) {
+		pr_err("%s: Invalid pointers passed\n", __func__);
+		return -EINVAL;
+	}
+
+	temp = skb_peek(msg_head);
+	hdr = (struct rr_header *)(temp->data);
+	if (addr || (hdr->src_port_id != IPC_ROUTER_ADDRESS)) {
+		addr->family = AF_MSM_IPC;
+		addr->address.addrtype = MSM_IPC_ADDR_ID;
+		addr->address.addr.port_addr.node_id = hdr->src_node_id;
+		addr->address.addr.port_addr.port_id = hdr->src_port_id;
+		m->msg_namelen = sizeof(struct sockaddr_msm_ipc);
+	}
+
+	data_len = hdr->size;
+	skb_pull(temp, IPC_ROUTER_HDR_SIZE);
+	skb_queue_walk(msg_head, temp) {
+		copy_len = data_len < temp->len ? data_len : temp->len;
+		if (copy_to_user(m->msg_iov->iov_base + offset, temp->data,
+				 copy_len)) {
+			pr_err("%s: Copy to user failed\n", __func__);
+			return -EFAULT;
+		}
+		offset += copy_len;
+		data_len -= copy_len;
+	}
+	return offset;
+}
+
+static void msm_ipc_router_release_msg(struct sk_buff_head *msg_head)
+{
+	struct sk_buff *temp;
+
+	if (!msg_head) {
+		pr_err("%s: Invalid msg pointer\n", __func__);
+		return;
+	}
+
+	while (!skb_queue_empty(msg_head)) {
+		temp = skb_dequeue(msg_head);
+		kfree_skb(temp);
+	}
+	kfree(msg_head);
+}
+
+static int msm_ipc_router_create(struct net *net,
+				 struct socket *sock,
+				 int protocol,
+				 int kern)
+{
+	struct sock *sk;
+	struct msm_ipc_port *port_ptr;
+	void *pil;
+
+	if (!check_permissions()) {
+		pr_err("%s: Do not have permissions\n", __func__);
+		return -EPERM;
+	}
+
+	if (unlikely(protocol != 0)) {
+		pr_err("%s: Protocol not supported\n", __func__);
+		return -EPROTONOSUPPORT;
+	}
+
+	switch (sock->type) {
+	case SOCK_DGRAM:
+		break;
+	default:
+		pr_err("%s: Protocol type not supported\n", __func__);
+		return -EPROTOTYPE;
+	}
+
+	sk = sk_alloc(net, AF_MSM_IPC, GFP_KERNEL, &msm_ipc_proto);
+	if (!sk) {
+		pr_err("%s: sk_alloc failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	port_ptr = msm_ipc_router_create_raw_port(sk, NULL, NULL);
+	if (!port_ptr) {
+		pr_err("%s: port_ptr alloc failed\n", __func__);
+		sk_free(sk);
+		return -ENOMEM;
+	}
+
+	sock->ops = &msm_ipc_proto_ops;
+	sock_init_data(sock, sk);
+	sk->sk_rcvtimeo = DEFAULT_RCV_TIMEO;
+
+	pil = msm_ipc_load_default_node();
+	msm_ipc_sk(sk)->port = port_ptr;
+	msm_ipc_sk(sk)->default_pil = pil;
+
+	return 0;
+}
+
+int msm_ipc_router_bind(struct socket *sock, struct sockaddr *uaddr,
+			       int uaddr_len)
+{
+	struct sockaddr_msm_ipc *addr = (struct sockaddr_msm_ipc *)uaddr;
+	struct sock *sk = sock->sk;
+	struct msm_ipc_port *port_ptr;
+	int ret;
+
+	if (!sk)
+		return -EINVAL;
+
+	if (!uaddr_len) {
+		pr_err("%s: Invalid address length\n", __func__);
+		return -EINVAL;
+	}
+
+	if (addr->family != AF_MSM_IPC) {
+		pr_err("%s: Address family is incorrect\n", __func__);
+		return -EAFNOSUPPORT;
+	}
+
+	if (addr->address.addrtype != MSM_IPC_ADDR_NAME) {
+		pr_err("%s: Address type is incorrect\n", __func__);
+		return -EINVAL;
+	}
+
+	port_ptr = msm_ipc_sk_port(sk);
+	if (!port_ptr)
+		return -ENODEV;
+
+	lock_sock(sk);
+
+	ret = msm_ipc_router_register_server(port_ptr, &addr->address);
+
+	release_sock(sk);
+	return ret;
+}
+
+static int msm_ipc_router_sendmsg(struct kiocb *iocb, struct socket *sock,
+				  struct msghdr *m, size_t total_len)
+{
+	struct sock *sk = sock->sk;
+	struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
+	struct sockaddr_msm_ipc *dest = (struct sockaddr_msm_ipc *)m->msg_name;
+	struct sk_buff_head *msg;
+	int ret;
+
+	if (!dest)
+		return -EDESTADDRREQ;
+
+	if (m->msg_namelen < sizeof(*dest) || dest->family != AF_MSM_IPC)
+		return -EINVAL;
+
+	if (total_len > MAX_IPC_PKT_SIZE)
+		return -EINVAL;
+
+	lock_sock(sk);
+	msg = msm_ipc_router_build_msg(m->msg_iovlen, m->msg_iov, total_len);
+	if (!msg) {
+		pr_err("%s: Msg build failure\n", __func__);
+		ret = -ENOMEM;
+		goto out_sendmsg;
+	}
+
+	ret = msm_ipc_router_send_to(port_ptr, msg, &dest->address);
+	if (ret == (IPC_ROUTER_HDR_SIZE + total_len))
+		ret = total_len;
+
+out_sendmsg:
+	release_sock(sk);
+	return ret;
+}
+
+static int msm_ipc_router_recvmsg(struct kiocb *iocb, struct socket *sock,
+				  struct msghdr *m, size_t buf_len, int flags)
+{
+	struct sock *sk = sock->sk;
+	struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
+	struct sk_buff_head *msg;
+	long timeout;
+	int ret;
+
+	if (m->msg_iovlen != 1)
+		return -EOPNOTSUPP;
+
+	if (!buf_len)
+		return -EINVAL;
+
+	lock_sock(sk);
+	timeout = sk->sk_rcvtimeo;
+	mutex_lock(&port_ptr->port_rx_q_lock);
+	while (list_empty(&port_ptr->port_rx_q)) {
+		mutex_unlock(&port_ptr->port_rx_q_lock);
+		release_sock(sk);
+		if (timeout < 0) {
+			ret = wait_event_interruptible(
+					port_ptr->port_rx_wait_q,
+					!list_empty(&port_ptr->port_rx_q));
+			if (ret)
+				return ret;
+		} else if (timeout > 0) {
+			timeout = wait_event_interruptible_timeout(
+					port_ptr->port_rx_wait_q,
+					!list_empty(&port_ptr->port_rx_q),
+					timeout);
+			if (timeout < 0)
+				return -EFAULT;
+		}
+
+		if (timeout == 0)
+			return -ETIMEDOUT;
+		lock_sock(sk);
+		mutex_lock(&port_ptr->port_rx_q_lock);
+	}
+	mutex_unlock(&port_ptr->port_rx_q_lock);
+
+	ret = msm_ipc_router_read(port_ptr, &msg, buf_len);
+	if (ret <= 0 || !msg) {
+		release_sock(sk);
+		return ret;
+	}
+
+	ret = msm_ipc_router_extract_msg(m, msg);
+	msm_ipc_router_release_msg(msg);
+	msg = NULL;
+	release_sock(sk);
+	return ret;
+}
+
+static int msm_ipc_router_ioctl(struct socket *sock,
+				unsigned int cmd, unsigned long arg)
+{
+	struct sock *sk = sock->sk;
+	struct msm_ipc_port *port_ptr;
+	struct server_lookup_args server_arg;
+	struct msm_ipc_port_addr *port_addr = NULL;
+	unsigned int n, port_addr_sz = 0;
+	int ret;
+
+	if (!sk)
+		return -EINVAL;
+
+	lock_sock(sk);
+	port_ptr = msm_ipc_sk_port(sock->sk);
+	if (!port_ptr) {
+		release_sock(sk);
+		return -EINVAL;
+	}
+
+	switch (cmd) {
+	case IPC_ROUTER_IOCTL_GET_VERSION:
+		n = IPC_ROUTER_VERSION;
+		ret = put_user(n, (unsigned int *)arg);
+		break;
+
+	case IPC_ROUTER_IOCTL_GET_MTU:
+		n = (MAX_IPC_PKT_SIZE - IPC_ROUTER_HDR_SIZE);
+		ret = put_user(n, (unsigned int *)arg);
+		break;
+
+	case IPC_ROUTER_IOCTL_GET_CURR_PKT_SIZE:
+		ret = msm_ipc_router_get_curr_pkt_size(port_ptr);
+		break;
+
+	case IPC_ROUTER_IOCTL_LOOKUP_SERVER:
+		ret = copy_from_user(&server_arg, (void *)arg,
+				     sizeof(server_arg));
+		if (ret) {
+			ret = -EFAULT;
+			break;
+		}
+
+		if (server_arg.num_entries_in_array < 0) {
+			ret = -EINVAL;
+			break;
+		}
+		if (server_arg.num_entries_in_array) {
+			port_addr_sz = server_arg.num_entries_in_array *
+					sizeof(*port_addr);
+			port_addr = kmalloc(port_addr_sz, GFP_KERNEL);
+			if (!port_addr) {
+				ret = -ENOMEM;
+				break;
+			}
+		}
+		ret = msm_ipc_router_lookup_server_name(&server_arg.port_name,
+				port_addr, server_arg.num_entries_in_array,
+				server_arg.lookup_mask);
+		if (ret < 0) {
+			pr_err("%s: Server not found\n", __func__);
+			ret = -ENODEV;
+			kfree(port_addr);
+			break;
+		}
+		server_arg.num_entries_found = ret;
+
+		ret = copy_to_user((void *)arg, &server_arg,
+				   sizeof(server_arg));
+		if (port_addr_sz) {
+			ret = copy_to_user((void *)(arg + sizeof(server_arg)),
+					   port_addr, port_addr_sz);
+			if (ret)
+				ret = -EFAULT;
+			kfree(port_addr);
+		}
+		break;
+
+	case IPC_ROUTER_IOCTL_BIND_CONTROL_PORT:
+		ret = msm_ipc_router_bind_control_port(port_ptr);
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+	release_sock(sk);
+	return ret;
+}
+
+static unsigned int msm_ipc_router_poll(struct file *file,
+			struct socket *sock, poll_table *wait)
+{
+	struct sock *sk = sock->sk;
+	struct msm_ipc_port *port_ptr;
+	uint32_t mask = 0;
+
+	if (!sk)
+		return -EINVAL;
+
+	port_ptr = msm_ipc_sk_port(sk);
+	if (!port_ptr)
+		return -EINVAL;
+
+	poll_wait(file, &port_ptr->port_rx_wait_q, wait);
+
+	if (!list_empty(&port_ptr->port_rx_q))
+		mask |= (POLLRDNORM | POLLIN);
+
+	return mask;
+}
+
+static int msm_ipc_router_close(struct socket *sock)
+{
+	struct sock *sk = sock->sk;
+	struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
+	void *pil = msm_ipc_sk(sk)->default_pil;
+	int ret;
+
+	lock_sock(sk);
+	ret = msm_ipc_router_close_port(port_ptr);
+	msm_ipc_unload_default_node(pil);
+	release_sock(sk);
+	sock_put(sk);
+	sock->sk = NULL;
+
+	return ret;
+}
+
+static const struct net_proto_family msm_ipc_family_ops = {
+	.owner		= THIS_MODULE,
+	.family		= AF_MSM_IPC,
+	.create		= msm_ipc_router_create
+};
+
+static const struct proto_ops msm_ipc_proto_ops = {
+	.owner		= THIS_MODULE,
+	.family         = AF_MSM_IPC,
+	.bind		= msm_ipc_router_bind,
+	.connect	= sock_no_connect,
+	.sendmsg	= msm_ipc_router_sendmsg,
+	.recvmsg	= msm_ipc_router_recvmsg,
+	.ioctl		= msm_ipc_router_ioctl,
+	.poll		= msm_ipc_router_poll,
+	.setsockopt	= sock_no_setsockopt,
+	.getsockopt	= sock_no_getsockopt,
+	.release	= msm_ipc_router_close,
+};
+
+static struct proto msm_ipc_proto = {
+	.name           = "MSM_IPC",
+	.owner          = THIS_MODULE,
+	.obj_size       = sizeof(struct msm_ipc_sock),
+};
+
+int msm_ipc_router_init_sockets(void)
+{
+	int ret;
+
+	ret = proto_register(&msm_ipc_proto, 1);
+	if (ret) {
+		pr_err("Failed to register MSM_IPC protocol type\n");
+		goto out_init_sockets;
+	}
+
+	ret = sock_register(&msm_ipc_family_ops);
+	if (ret) {
+		pr_err("Failed to register MSM_IPC socket type\n");
+		proto_unregister(&msm_ipc_proto);
+		goto out_init_sockets;
+	}
+
+	sockets_enabled = 1;
+out_init_sockets:
+	return ret;
+}
+
+void msm_ipc_router_exit_sockets(void)
+{
+	if (!sockets_enabled)
+		return;
+
+	sockets_enabled = 0;
+	sock_unregister(msm_ipc_family_ops.family);
+	proto_unregister(&msm_ipc_proto);
+}
diff --git a/arch/arm/mach-msm/irq-vic.c b/arch/arm/mach-msm/irq-vic.c
index 1b54f80..489faa3 100644
--- a/arch/arm/mach-msm/irq-vic.c
+++ b/arch/arm/mach-msm/irq-vic.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009, 2011 Code Aurora Forum. 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
@@ -23,11 +23,16 @@
 #include <linux/io.h>
 
 #include <asm/cacheflush.h>
+#include <asm/io.h>
+#include <asm/exception.h>
+#include <asm/cp15.h>
 
 #include <mach/hardware.h>
 
 #include <mach/msm_iomap.h>
+#include <mach/fiq.h>
 
+#include "fiq.h"
 #include "smd_private.h"
 
 enum {
@@ -71,7 +76,7 @@
 #define VIC_INT_POLARITY3   VIC_REG(0x005C)  /* 1: NEG, 0: POS */
 #define VIC_NO_PEND_VAL     VIC_REG(0x0060)
 
-#if defined(CONFIG_ARCH_MSM_SCORPION)
+#if defined(CONFIG_ARCH_MSM_SCORPION) && !defined(CONFIG_MSM_SMP)
 #define VIC_NO_PEND_VAL_FIQ VIC_REG(0x0064)
 #define VIC_INT_MASTEREN    VIC_REG(0x0068)  /* 1: IRQ, 2: FIQ     */
 #define VIC_CONFIG          VIC_REG(0x006C)  /* 1: USE SC VIC */
@@ -105,7 +110,7 @@
 #define VIC_IRQ_VEC_PEND_RD VIC_REG(0x00D4)  /* pending vector addr */
 #define VIC_IRQ_VEC_WR      VIC_REG(0x00D8)
 
-#if defined(CONFIG_ARCH_MSM_SCORPION)
+#if defined(CONFIG_ARCH_MSM_SCORPION) && !defined(CONFIG_MSM_SMP)
 #define VIC_FIQ_VEC_RD      VIC_REG(0x00DC)
 #define VIC_FIQ_VEC_PEND_RD VIC_REG(0x00E0)
 #define VIC_FIQ_VEC_WR      VIC_REG(0x00E4)
@@ -124,7 +129,7 @@
 #define VIC_VECTPRIORITY(n) VIC_REG(0x0200+((n) * 4))
 #define VIC_VECTADDR(n)     VIC_REG(0x0400+((n) * 4))
 
-#if defined(CONFIG_ARCH_MSM7X30)
+#if defined(CONFIG_ARCH_MSM7X30) || defined(CONFIG_ARCH_FSM9XXX)
 #define VIC_NUM_REGS	    4
 #else
 #define VIC_NUM_REGS	    2
@@ -160,10 +165,13 @@
 static uint32_t msm_irq_idle_disable[VIC_NUM_REGS];
 
 #define SMSM_FAKE_IRQ (0xff)
+#if !defined(CONFIG_ARCH_FSM9XXX)
 static uint8_t msm_irq_to_smsm[NR_IRQS] = {
+#if !defined(CONFIG_ARCH_MSM7X27A)
 	[INT_MDDI_EXT] = 1,
 	[INT_MDDI_PRI] = 2,
 	[INT_MDDI_CLIENT] = 3,
+#endif
 	[INT_USB_OTG] = 4,
 
 	[INT_PWB_I2C] = 5,
@@ -217,6 +225,18 @@
 	[INT_SIRC_1] = SMSM_FAKE_IRQ,
 #endif
 };
+# else /* CONFIG_ARCH_FSM9XXX */
+static uint8_t msm_irq_to_smsm[NR_IRQS] = {
+	[INT_UART1] = 11,
+	[INT_A9_M2A_0] = SMSM_FAKE_IRQ,
+	[INT_A9_M2A_1] = SMSM_FAKE_IRQ,
+	[INT_A9_M2A_5] = SMSM_FAKE_IRQ,
+	[INT_GP_TIMER_EXP] = SMSM_FAKE_IRQ,
+	[INT_DEBUG_TIMER_EXP] = SMSM_FAKE_IRQ,
+	[INT_SIRC_0] = 10,
+	[INT_ADSP_A11] = SMSM_FAKE_IRQ,
+};
+#endif /* CONFIG_ARCH_FSM9XXX */
 
 static inline void msm_irq_write_all_regs(void __iomem *base, unsigned int val)
 {
@@ -228,8 +248,32 @@
 
 static void msm_irq_ack(struct irq_data *d)
 {
+	uint32_t mask;
+
 	void __iomem *reg = VIC_INT_TO_REG_ADDR(VIC_INT_CLEAR0, d->irq);
-	writel(1 << (d->irq & 31), reg);
+	mask = 1 << (d->irq & 31);
+	writel(mask, reg);
+	mb();
+}
+
+static void msm_irq_disable(struct irq_data *d)
+{
+	void __iomem *reg = VIC_INT_TO_REG_ADDR(VIC_INT_ENCLEAR0, d->irq);
+	unsigned index = VIC_INT_TO_REG_INDEX(d->irq);
+	uint32_t mask = 1UL << (d->irq & 31);
+	int smsm_irq = msm_irq_to_smsm[d->irq];
+
+	if (!(msm_irq_shadow_reg[index].int_en[1] & mask)) {
+		msm_irq_shadow_reg[index].int_en[0] &= ~mask;
+		writel(mask, reg);
+		mb();
+		if (smsm_irq == 0)
+			msm_irq_idle_disable[index] &= ~mask;
+		else {
+			mask = 1UL << (smsm_irq - 1);
+			msm_irq_smsm_wake_enable[0] &= ~mask;
+		}
+	}
 }
 
 static void msm_irq_mask(struct irq_data *d)
@@ -241,6 +285,7 @@
 
 	msm_irq_shadow_reg[index].int_en[0] &= ~mask;
 	writel(mask, reg);
+	mb();
 	if (smsm_irq == 0)
 		msm_irq_idle_disable[index] &= ~mask;
 	else {
@@ -258,6 +303,7 @@
 
 	msm_irq_shadow_reg[index].int_en[0] |= mask;
 	writel(mask, reg);
+	mb();
 
 	if (smsm_irq == 0)
 		msm_irq_idle_disable[index] |= mask;
@@ -295,7 +341,7 @@
 
 static int msm_irq_set_type(struct irq_data *d, unsigned int flow_type)
 {
-	void __iomem *treg = VIC_INT_TO_REG_ADDR(VIC_INT_TYPE0, d->irq);
+        void __iomem *treg = VIC_INT_TO_REG_ADDR(VIC_INT_TYPE0, d->irq);
 	void __iomem *preg = VIC_INT_TO_REG_ADDR(VIC_INT_POLARITY0, d->irq);
 	unsigned index = VIC_INT_TO_REG_INDEX(d->irq);
 	int b = 1 << (d->irq & 31);
@@ -320,18 +366,220 @@
 		__irq_set_handler_locked(d->irq, handle_level_irq);
 	}
 	writel(type, treg);
+	mb();
 	msm_irq_shadow_reg[index].int_type = type;
 	return 0;
 }
 
+unsigned int msm_irq_pending(void)
+{
+	unsigned int i, pending = 0;
+
+	for (i = 0; (i < VIC_NUM_REGS) && !pending; i++)
+		pending |= readl(VIC_IRQ_STATUS0 + (i * 4));
+
+	return pending;
+}
+
+int msm_irq_idle_sleep_allowed(void)
+{
+	uint32_t i, disable = 0;
+
+	if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_REQUEST)
+		DPRINT_ARRAY(msm_irq_idle_disable,
+			     "msm_irq_idle_sleep_allowed: disable");
+
+	for (i = 0; i < VIC_NUM_REGS; i++)
+		disable |= msm_irq_idle_disable[i];
+
+	return !disable;
+}
+
+/*
+ * Prepare interrupt subsystem for entering sleep -- phase 1.
+ * If modem_wake is true, return currently enabled interrupts in *irq_mask.
+ */
+void msm_irq_enter_sleep1(bool modem_wake, int from_idle, uint32_t *irq_mask)
+{
+	if (modem_wake) {
+		*irq_mask = msm_irq_smsm_wake_enable[!from_idle];
+		if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP)
+			printk(KERN_INFO
+				"%s irq_mask %x\n", __func__, *irq_mask);
+	}
+}
+
+/*
+ * Prepare interrupt subsystem for entering sleep -- phase 2.
+ * Detect any pending interrupts and configure interrupt hardware.
+ *
+ * Return value:
+ * -EAGAIN: there are pending interrupt(s); interrupt configuration
+ *          is not changed.
+ *       0: success
+ */
+int msm_irq_enter_sleep2(bool modem_wake, int from_idle)
+{
+	int i, limit = 10;
+	uint32_t pending[VIC_NUM_REGS];
+
+	if (from_idle && !modem_wake)
+		return 0;
+
+	/* edge triggered interrupt may get lost if this mode is used */
+	WARN_ON_ONCE(!modem_wake && !from_idle);
+
+	if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP)
+		DPRINT_REGS(VIC_IRQ_STATUS, "%s change irq, pend", __func__);
+
+	for (i = 0; i < VIC_NUM_REGS; i++) {
+		pending[i] = readl(VIC_IRQ_STATUS0 + (i * 4));
+		pending[i] &= msm_irq_shadow_reg[i].int_en[!from_idle];
+	}
+
+	/*
+	 * Clear INT_A9_M2A_5 since requesting sleep triggers it.
+	 * In some arch e.g. FSM9XXX, INT_A9_M2A_5 may not be in the first set.
+	 */
+	pending[INT_A9_M2A_5 / 32] &= ~(1U << (INT_A9_M2A_5 % 32));
+
+	for (i = 0; i < VIC_NUM_REGS; i++) {
+		if (pending[i]) {
+			if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_ABORT)
+				DPRINT_ARRAY(pending, "%s abort",
+						       __func__);
+			return -EAGAIN;
+		}
+	}
+
+	msm_irq_write_all_regs(VIC_INT_EN0, 0);
+
+	while (limit-- > 0) {
+		int pend_irq;
+		int irq = readl(VIC_IRQ_VEC_RD);
+		if (irq == -1)
+			break;
+		pend_irq = readl(VIC_IRQ_VEC_PEND_RD);
+		if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_INT)
+			printk(KERN_INFO "%s cleared int %d (%d)\n",
+				__func__, irq, pend_irq);
+	}
+
+	if (modem_wake) {
+		struct irq_data d = { .irq = INT_A9_M2A_6 };
+		msm_irq_set_type(&d, IRQF_TRIGGER_RISING);
+		__raw_writel(1U << (INT_A9_M2A_6 % 32),
+			VIC_INT_TO_REG_ADDR(VIC_INT_ENSET0, INT_A9_M2A_6));
+	} else {
+		for (i = 0; i < VIC_NUM_REGS; i++)
+			writel(msm_irq_shadow_reg[i].int_en[1],
+						VIC_INT_ENSET0 + (i * 4));
+	}
+	mb();
+
+	return 0;
+}
+
+/*
+ * Restore interrupt subsystem from sleep -- phase 1.
+ * Configure interrupt hardware.
+ */
+void msm_irq_exit_sleep1(uint32_t irq_mask, uint32_t wakeup_reason,
+	uint32_t pending_irqs)
+{
+	int i;
+	struct irq_data d = { .irq = INT_A9_M2A_6 };
+
+	msm_irq_ack(&d);
+
+	for (i = 0; i < VIC_NUM_REGS; i++) {
+		writel(msm_irq_shadow_reg[i].int_type,
+			VIC_INT_TYPE0 + i * 4);
+		writel(msm_irq_shadow_reg[i].int_polarity,
+			VIC_INT_POLARITY0 + i * 4);
+		writel(msm_irq_shadow_reg[i].int_en[0],
+			VIC_INT_EN0 + i * 4);
+		writel(msm_irq_shadow_reg[i].int_select,
+			VIC_INT_SELECT0 + i * 4);
+	}
+
+	writel(3, VIC_INT_MASTEREN);
+	mb();
+
+	if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP)
+		DPRINT_REGS(VIC_IRQ_STATUS, "%s %x %x %x now",
+			__func__, irq_mask, pending_irqs, wakeup_reason);
+}
+
+/*
+ * Restore interrupt subsystem from sleep -- phase 2.
+ * Poke the specified pending interrupts into interrupt hardware.
+ */
+void msm_irq_exit_sleep2(uint32_t irq_mask, uint32_t wakeup_reason,
+	uint32_t pending)
+{
+	int i;
+
+	if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP)
+		DPRINT_REGS(VIC_IRQ_STATUS, "%s %x %x %x now",
+			__func__, irq_mask, pending, wakeup_reason);
+
+	for (i = 0; pending && i < ARRAY_SIZE(msm_irq_to_smsm); i++) {
+		unsigned reg_offset = VIC_INT_TO_REG_ADDR(0, i);
+		uint32_t reg_mask = 1UL << (i & 31);
+		int smsm_irq = msm_irq_to_smsm[i];
+		uint32_t smsm_mask;
+
+		if (smsm_irq == 0)
+			continue;
+
+		smsm_mask = 1U << (smsm_irq - 1);
+		if (!(pending & smsm_mask))
+			continue;
+
+		pending &= ~smsm_mask;
+		if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_INT)
+			DPRINT_REGS(VIC_IRQ_STATUS,
+				"%s: irq %d still pending %x now",
+				__func__, i, pending);
+#ifdef DEBUG_INTERRUPT_TRIGGER
+		if (readl(VIC_IRQ_STATUS0 + reg_offset) & reg_mask)
+			writel(reg_mask, VIC_INT_CLEAR0 + reg_offset);
+#endif
+		if (readl(VIC_IRQ_STATUS0 + reg_offset) & reg_mask)
+			continue;
+
+		writel(reg_mask, VIC_SOFTINT0 + reg_offset);
+
+		if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_INT_TRIGGER)
+			DPRINT_REGS(VIC_IRQ_STATUS,
+				"%s: irq %d need trigger, now",
+				__func__, i);
+	}
+	mb();
+}
+
+/*
+ * Restore interrupt subsystem from sleep -- phase 3.
+ * Print debug information.
+ */
+void msm_irq_exit_sleep3(uint32_t irq_mask, uint32_t wakeup_reason,
+	uint32_t pending_irqs)
+{
+	if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP)
+		DPRINT_REGS(VIC_IRQ_STATUS, "%s %x %x %x state %x now",
+			__func__, irq_mask, pending_irqs, wakeup_reason,
+			smsm_get_state(SMSM_MODEM_STATE));
+}
+
 static struct irq_chip msm_irq_chip = {
-	.name          = "msm",
-	.irq_disable   = msm_irq_mask,
-	.irq_ack       = msm_irq_ack,
-	.irq_mask      = msm_irq_mask,
-	.irq_unmask    = msm_irq_unmask,
-	.irq_set_wake  = msm_irq_set_wake,
-	.irq_set_type  = msm_irq_set_type,
+	.name		= "msm",
+	.irq_disable	= msm_irq_disable,
+	.irq_ack	= msm_irq_ack,
+	.irq_mask	= msm_irq_mask,
+	.irq_unmask	= msm_irq_unmask,
+	.irq_set_wake	= msm_irq_set_wake,
+	.irq_set_type	= msm_irq_set_type,
 };
 
 void __init msm_init_irq(void)
@@ -353,11 +601,123 @@
 	/* don't use vic */
 	writel(0, VIC_CONFIG);
 
-	/* enable interrupt controller */
-	writel(3, VIC_INT_MASTEREN);
 
 	for (n = 0; n < NR_MSM_IRQS; n++) {
 		irq_set_chip_and_handler(n, &msm_irq_chip, handle_level_irq);
 		set_irq_flags(n, IRQF_VALID);
 	}
+
+	/* enable interrupt controller */
+	writel(3, VIC_INT_MASTEREN);
+	mb();
 }
+
+static inline void msm_vic_handle_irq(void __iomem *base_addr, struct pt_regs
+		*regs)
+{
+	u32 irqnr;
+
+	do {
+		/* 0xD0 has irq# or old irq# if the irq has been handled
+		 * 0xD4 has irq# or -1 if none pending *but* if you just
+		 * read 0xD4 you never get the first irq for some reason
+		 */
+		irqnr = readl_relaxed(base_addr + 0xD0);
+		irqnr = readl_relaxed(base_addr + 0xD4);
+		if (irqnr == -1)
+			break;
+		handle_IRQ(irqnr, regs);
+	} while (1);
+}
+
+/* enable imprecise aborts */
+#define local_cpsie_enable()  __asm__ __volatile__("cpsie a    @ enable")
+
+asmlinkage void __exception_irq_entry vic_handle_irq(struct pt_regs *regs)
+{
+	local_cpsie_enable();
+	msm_vic_handle_irq((void __iomem *)MSM_VIC_BASE, regs);
+}
+
+#if defined(CONFIG_MSM_FIQ_SUPPORT)
+void msm_trigger_irq(int irq)
+{
+	void __iomem *reg = VIC_INT_TO_REG_ADDR(VIC_SOFTINT0, irq);
+	uint32_t mask = 1UL << (irq & 31);
+	writel(mask, reg);
+	mb();
+}
+
+void msm_fiq_enable(int irq)
+{
+	struct irq_data d = { .irq = irq };
+	unsigned long flags;
+	local_irq_save(flags);
+	msm_irq_unmask(&d);
+	local_irq_restore(flags);
+}
+
+void msm_fiq_disable(int irq)
+{
+	struct irq_data d = { .irq = irq };
+	unsigned long flags;
+	local_irq_save(flags);
+	msm_irq_mask(&d);
+	local_irq_restore(flags);
+}
+
+void msm_fiq_select(int irq)
+{
+	void __iomem *reg = VIC_INT_TO_REG_ADDR(VIC_INT_SELECT0, irq);
+	unsigned index = VIC_INT_TO_REG_INDEX(irq);
+	uint32_t mask = 1UL << (irq & 31);
+	unsigned long flags;
+
+	local_irq_save(flags);
+	msm_irq_shadow_reg[index].int_select |= mask;
+	writel(msm_irq_shadow_reg[index].int_select, reg);
+	mb();
+	local_irq_restore(flags);
+}
+
+void msm_fiq_unselect(int irq)
+{
+	void __iomem *reg = VIC_INT_TO_REG_ADDR(VIC_INT_SELECT0, irq);
+	unsigned index = VIC_INT_TO_REG_INDEX(irq);
+	uint32_t mask = 1UL << (irq & 31);
+	unsigned long flags;
+
+	local_irq_save(flags);
+	msm_irq_shadow_reg[index].int_select &= (!mask);
+	writel(msm_irq_shadow_reg[index].int_select, reg);
+	mb();
+	local_irq_restore(flags);
+}
+/* set_fiq_handler originally from arch/arm/kernel/fiq.c */
+static void set_fiq_handler(void *start, unsigned int length)
+{
+	memcpy((void *)0xffff001c, start, length);
+	flush_icache_range(0xffff001c, 0xffff001c + length);
+	if (!vectors_high())
+		flush_icache_range(0x1c, 0x1c + length);
+}
+
+static void (*fiq_func)(void *data, void *regs);
+static unsigned long long fiq_stack[256];
+
+int msm_fiq_set_handler(void (*func)(void *data, void *regs), void *data)
+{
+	unsigned long flags;
+	int ret = -ENOMEM;
+
+	local_irq_save(flags);
+	if (fiq_func == 0) {
+		fiq_func = func;
+		fiq_glue_setup(func, data, fiq_stack + 255);
+		set_fiq_handler(&fiq_glue, (&fiq_glue_end - &fiq_glue));
+		ret = 0;
+	}
+	local_irq_restore(flags);
+	return ret;
+}
+#endif
diff --git a/arch/arm/mach-msm/irq.c b/arch/arm/mach-msm/irq.c
index ea514be..280160a 100644
--- a/arch/arm/mach-msm/irq.c
+++ b/arch/arm/mach-msm/irq.c
@@ -22,9 +22,25 @@
 #include <linux/irq.h>
 #include <linux/io.h>
 
+#include <asm/cacheflush.h>
+
 #include <mach/hardware.h>
 
 #include <mach/msm_iomap.h>
+#include <mach/fiq.h>
+
+#include "sirc.h"
+#include "smd_private.h"
+
+enum {
+	IRQ_DEBUG_SLEEP_INT_TRIGGER = 1U << 0,
+	IRQ_DEBUG_SLEEP_INT = 1U << 1,
+	IRQ_DEBUG_SLEEP_ABORT = 1U << 2,
+	IRQ_DEBUG_SLEEP = 1U << 3,
+	IRQ_DEBUG_SLEEP_REQUEST = 1U << 4,
+};
+static int msm_irq_debug_mask;
+module_param_named(debug_mask, msm_irq_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
 
 #define VIC_REG(off) (MSM_VIC_BASE + (off))
 
@@ -41,9 +57,16 @@
 #define VIC_INT_POLARITY0   VIC_REG(0x0050)  /* 1: NEG, 0: POS */
 #define VIC_INT_POLARITY1   VIC_REG(0x0054)  /* 1: NEG, 0: POS */
 #define VIC_NO_PEND_VAL     VIC_REG(0x0060)
+
+#if defined(CONFIG_ARCH_MSM_SCORPION) && !defined(CONFIG_MSM_SMP)
+#define VIC_NO_PEND_VAL_FIQ VIC_REG(0x0064)
+#define VIC_INT_MASTEREN    VIC_REG(0x0068)  /* 1: IRQ, 2: FIQ     */
+#define VIC_CONFIG          VIC_REG(0x006C)  /* 1: USE SC VIC */
+#else
 #define VIC_INT_MASTEREN    VIC_REG(0x0064)  /* 1: IRQ, 2: FIQ     */
-#define VIC_PROTECTION      VIC_REG(0x006C)  /* 1: ENABLE          */
 #define VIC_CONFIG          VIC_REG(0x0068)  /* 1: USE ARM1136 VIC */
+#define VIC_PROTECTION      VIC_REG(0x006C)  /* 1: ENABLE          */
+#endif
 #define VIC_IRQ_STATUS0     VIC_REG(0x0080)
 #define VIC_IRQ_STATUS1     VIC_REG(0x0084)
 #define VIC_FIQ_STATUS0     VIC_REG(0x0090)
@@ -57,65 +80,370 @@
 #define VIC_IRQ_VEC_RD      VIC_REG(0x00D0)  /* pending int # */
 #define VIC_IRQ_VEC_PEND_RD VIC_REG(0x00D4)  /* pending vector addr */
 #define VIC_IRQ_VEC_WR      VIC_REG(0x00D8)
+
+#if defined(CONFIG_ARCH_MSM_SCORPION) && !defined(CONFIG_MSM_SMP)
+#define VIC_FIQ_VEC_RD      VIC_REG(0x00DC)
+#define VIC_FIQ_VEC_PEND_RD VIC_REG(0x00E0)
+#define VIC_FIQ_VEC_WR      VIC_REG(0x00E4)
+#define VIC_IRQ_IN_SERVICE  VIC_REG(0x00E8)
+#define VIC_IRQ_IN_STACK    VIC_REG(0x00EC)
+#define VIC_FIQ_IN_SERVICE  VIC_REG(0x00F0)
+#define VIC_FIQ_IN_STACK    VIC_REG(0x00F4)
+#define VIC_TEST_BUS_SEL    VIC_REG(0x00F8)
+#define VIC_IRQ_CTRL_CONFIG VIC_REG(0x00FC)
+#else
 #define VIC_IRQ_IN_SERVICE  VIC_REG(0x00E0)
 #define VIC_IRQ_IN_STACK    VIC_REG(0x00E4)
 #define VIC_TEST_BUS_SEL    VIC_REG(0x00E8)
+#endif
 
 #define VIC_VECTPRIORITY(n) VIC_REG(0x0200+((n) * 4))
 #define VIC_VECTADDR(n)     VIC_REG(0x0400+((n) * 4))
 
-static void msm_irq_ack(struct irq_data *d)
+static uint32_t msm_irq_smsm_wake_enable[2];
+static struct {
+	uint32_t int_en[2];
+	uint32_t int_type;
+	uint32_t int_polarity;
+	uint32_t int_select;
+} msm_irq_shadow_reg[2];
+static uint32_t msm_irq_idle_disable[2];
+
+#if defined(CONFIG_ARCH_MSM_SCORPION) && !defined(CONFIG_MSM_SMP)
+#define INT_INFO_SMSM_ID SMEM_SMSM_INT_INFO
+struct smsm_interrupt_info *smsm_int_info;
+#else
+#define INT_INFO_SMSM_ID SMEM_APPS_DEM_SLAVE_DATA
+struct msm_dem_slave_data *smsm_int_info;
+#endif
+
+
+#define SMSM_FAKE_IRQ (0xff)
+static uint8_t msm_irq_to_smsm[NR_MSM_IRQS + NR_SIRC_IRQS] = {
+	[INT_MDDI_EXT] = 1,
+	[INT_MDDI_PRI] = 2,
+	[INT_MDDI_CLIENT] = 3,
+	[INT_USB_OTG] = 4,
+
+	/* [INT_PWB_I2C] = 5 -- not usable */
+	[INT_SDC1_0] = 6,
+	[INT_SDC1_1] = 7,
+	[INT_SDC2_0] = 8,
+
+	[INT_SDC2_1] = 9,
+	[INT_ADSP_A9_A11] = 10,
+	[INT_UART1] = 11,
+	[INT_UART2] = 12,
+
+	[INT_UART3] = 13,
+	[INT_UART1_RX] = 14,
+	[INT_UART2_RX] = 15,
+	[INT_UART3_RX] = 16,
+
+	[INT_UART1DM_IRQ] = 17,
+	[INT_UART1DM_RX] = 18,
+	[INT_KEYSENSE] = 19,
+	[INT_AD_HSSD] = 20,
+
+	[INT_NAND_WR_ER_DONE] = 21,
+	[INT_NAND_OP_DONE] = 22,
+	[INT_TCHSCRN1] = 23,
+	[INT_TCHSCRN2] = 24,
+
+	[INT_TCHSCRN_SSBI] = 25,
+	[INT_USB_HS] = 26,
+	[INT_UART2DM_RX] = 27,
+	[INT_UART2DM_IRQ] = 28,
+
+	[INT_SDC4_1] = 29,
+	[INT_SDC4_0] = 30,
+	[INT_SDC3_1] = 31,
+	[INT_SDC3_0] = 32,
+
+	/* fake wakeup interrupts */
+	[INT_GPIO_GROUP1] = SMSM_FAKE_IRQ,
+	[INT_GPIO_GROUP2] = SMSM_FAKE_IRQ,
+	[INT_A9_M2A_0] = SMSM_FAKE_IRQ,
+	[INT_A9_M2A_1] = SMSM_FAKE_IRQ,
+	[INT_A9_M2A_5] = SMSM_FAKE_IRQ,
+	[INT_GP_TIMER_EXP] = SMSM_FAKE_IRQ,
+	[INT_DEBUG_TIMER_EXP] = SMSM_FAKE_IRQ,
+	[INT_ADSP_A11] = SMSM_FAKE_IRQ,
+#if defined(CONFIG_ARCH_MSM_SCORPION) && !defined(CONFIG_MSM_SMP)
+	[INT_SIRC_0] = SMSM_FAKE_IRQ,
+	[INT_SIRC_1] = SMSM_FAKE_IRQ,
+#endif
+};
+
+static void msm_irq_ack(unsigned int irq)
 {
-	void __iomem *reg = VIC_INT_CLEAR0 + ((d->irq & 32) ? 4 : 0);
-	writel(1 << (d->irq & 31), reg);
+	void __iomem *reg = VIC_INT_CLEAR0 + ((irq & 32) ? 4 : 0);
+	irq = 1 << (irq & 31);
+	writel(irq, reg);
 }
 
-static void msm_irq_mask(struct irq_data *d)
+static void msm_irq_mask(unsigned int irq)
 {
-	void __iomem *reg = VIC_INT_ENCLEAR0 + ((d->irq & 32) ? 4 : 0);
-	writel(1 << (d->irq & 31), reg);
+	void __iomem *reg = VIC_INT_ENCLEAR0 + ((irq & 32) ? 4 : 0);
+	unsigned index = (irq >> 5) & 1;
+	uint32_t mask = 1UL << (irq & 31);
+	int smsm_irq = msm_irq_to_smsm[irq];
+
+	msm_irq_shadow_reg[index].int_en[0] &= ~mask;
+	writel(mask, reg);
+	if (smsm_irq == 0)
+		msm_irq_idle_disable[index] &= ~mask;
+	else {
+		mask = 1UL << (smsm_irq - 1);
+		msm_irq_smsm_wake_enable[0] &= ~mask;
+	}
 }
 
-static void msm_irq_unmask(struct irq_data *d)
+static void msm_irq_unmask(unsigned int irq)
 {
-	void __iomem *reg = VIC_INT_ENSET0 + ((d->irq & 32) ? 4 : 0);
-	writel(1 << (d->irq & 31), reg);
+	void __iomem *reg = VIC_INT_ENSET0 + ((irq & 32) ? 4 : 0);
+	unsigned index = (irq >> 5) & 1;
+	uint32_t mask = 1UL << (irq & 31);
+	int smsm_irq = msm_irq_to_smsm[irq];
+
+	msm_irq_shadow_reg[index].int_en[0] |= mask;
+	writel(mask, reg);
+
+	if (smsm_irq == 0)
+		msm_irq_idle_disable[index] |= mask;
+	else {
+		mask = 1UL << (smsm_irq - 1);
+		msm_irq_smsm_wake_enable[0] |= mask;
+	}
 }
 
-static int msm_irq_set_wake(struct irq_data *d, unsigned int on)
+static int msm_irq_set_wake(unsigned int irq, unsigned int on)
 {
-	return -EINVAL;
+	unsigned index = (irq >> 5) & 1;
+	uint32_t mask = 1UL << (irq & 31);
+	int smsm_irq = msm_irq_to_smsm[irq];
+
+	if (smsm_irq == 0) {
+		printk(KERN_ERR "msm_irq_set_wake: bad wakeup irq %d\n", irq);
+		return -EINVAL;
+	}
+	if (on)
+		msm_irq_shadow_reg[index].int_en[1] |= mask;
+	else
+		msm_irq_shadow_reg[index].int_en[1] &= ~mask;
+
+	if (smsm_irq == SMSM_FAKE_IRQ)
+		return 0;
+
+	mask = 1UL << (smsm_irq - 1);
+	if (on)
+		msm_irq_smsm_wake_enable[1] |= mask;
+	else
+		msm_irq_smsm_wake_enable[1] &= ~mask;
+	return 0;
 }
 
-static int msm_irq_set_type(struct irq_data *d, unsigned int flow_type)
+static int msm_irq_set_type(unsigned int irq, unsigned int flow_type)
 {
-	void __iomem *treg = VIC_INT_TYPE0 + ((d->irq & 32) ? 4 : 0);
-	void __iomem *preg = VIC_INT_POLARITY0 + ((d->irq & 32) ? 4 : 0);
-	int b = 1 << (d->irq & 31);
+	void __iomem *treg = VIC_INT_TYPE0 + ((irq & 32) ? 4 : 0);
+	void __iomem *preg = VIC_INT_POLARITY0 + ((irq & 32) ? 4 : 0);
+	unsigned index = (irq >> 5) & 1;
+	int b = 1 << (irq & 31);
+	uint32_t polarity;
+	uint32_t type;
 
+	polarity = msm_irq_shadow_reg[index].int_polarity;
 	if (flow_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW))
-		writel(readl(preg) | b, preg);
+		polarity |= b;
 	if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH))
-		writel(readl(preg) & (~b), preg);
+		polarity &= ~b;
+	writel(polarity, preg);
+	msm_irq_shadow_reg[index].int_polarity = polarity;
 
+	type = msm_irq_shadow_reg[index].int_type;
 	if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
-		writel(readl(treg) | b, treg);
+		type |= b;
 		__irq_set_handler_locked(d->irq, handle_edge_irq);
 	}
 	if (flow_type & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW)) {
-		writel(readl(treg) & (~b), treg);
+		type &= ~b;
 		__irq_set_handler_locked(d->irq, handle_level_irq);
 	}
+	writel(type, treg);
+	msm_irq_shadow_reg[index].int_type = type;
+	return 0;
+}
+
+int msm_irq_pending(void)
+{
+	return readl(VIC_IRQ_STATUS0) || readl(VIC_IRQ_STATUS1);
+}
+
+int msm_irq_idle_sleep_allowed(void)
+{
+	if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_REQUEST)
+		printk(KERN_INFO "msm_irq_idle_sleep_allowed: disable %x %x\n",
+		msm_irq_idle_disable[0], msm_irq_idle_disable[1]);
+	return !(msm_irq_idle_disable[0] || msm_irq_idle_disable[1] ||
+		 !smsm_int_info);
+}
+
+/* If arm9_wake is set: pass control to the other core.
+ * If from_idle is not set: disable non-wakeup interrupts.
+ */
+void msm_irq_enter_sleep1(bool arm9_wake, int from_idle)
+{
+	if (!arm9_wake || !smsm_int_info)
+		return;
+	smsm_int_info->interrupt_mask = msm_irq_smsm_wake_enable[!from_idle];
+	smsm_int_info->pending_interrupts = 0;
+}
+
+int msm_irq_enter_sleep2(bool arm9_wake, int from_idle)
+{
+	int limit = 10;
+	uint32_t pending0, pending1;
+
+	if (from_idle && !arm9_wake)
+		return 0;
+
+	/* edge triggered interrupt may get lost if this mode is used */
+	WARN_ON_ONCE(!arm9_wake && !from_idle);
+
+	if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP)
+		printk(KERN_INFO "msm_irq_enter_sleep change irq, pend %x %x\n",
+		       readl(VIC_IRQ_STATUS0), readl(VIC_IRQ_STATUS1));
+	pending0 = readl(VIC_IRQ_STATUS0);
+	pending1 = readl(VIC_IRQ_STATUS1);
+	pending0 &= msm_irq_shadow_reg[0].int_en[!from_idle];
+	/* Clear INT_A9_M2A_5 since requesting sleep triggers it */
+	pending0 &= ~(1U << INT_A9_M2A_5);
+	pending1 &= msm_irq_shadow_reg[1].int_en[!from_idle];
+	if (pending0 || pending1) {
+		if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_ABORT)
+			printk(KERN_INFO "msm_irq_enter_sleep2 abort %x %x\n",
+			      pending0, pending1);
+		return -EAGAIN;
+	}
+	    
+	writel(0, VIC_INT_EN0);
+	writel(0, VIC_INT_EN1);
+
+	while (limit-- > 0) {
+		int pend_irq;
+		int irq = readl(VIC_IRQ_VEC_RD);
+		if (irq == -1)
+			break;
+		pend_irq = readl(VIC_IRQ_VEC_PEND_RD);
+		if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_INT)
+			printk(KERN_INFO "msm_irq_enter_sleep cleared "
+			       "int %d (%d)\n", irq, pend_irq);
+	}
+
+	if (arm9_wake) {
+		msm_irq_set_type(INT_A9_M2A_6, IRQF_TRIGGER_RISING);
+		msm_irq_ack(INT_A9_M2A_6);
+		writel(1U << INT_A9_M2A_6, VIC_INT_ENSET0);
+	} else {
+		writel(msm_irq_shadow_reg[0].int_en[1], VIC_INT_ENSET0);
+		writel(msm_irq_shadow_reg[1].int_en[1], VIC_INT_ENSET1);
+	}
 	return 0;
 }
 
+void msm_irq_exit_sleep1(void)
+{
+	int i;
+
+	msm_irq_ack(INT_A9_M2A_6);
+	msm_irq_ack(INT_PWB_I2C);
+	for (i = 0; i < 2; i++) {
+		writel(msm_irq_shadow_reg[i].int_type, VIC_INT_TYPE0 + i * 4);
+		writel(msm_irq_shadow_reg[i].int_polarity, VIC_INT_POLARITY0 + i * 4);
+		writel(msm_irq_shadow_reg[i].int_en[0], VIC_INT_EN0 + i * 4);
+		writel(msm_irq_shadow_reg[i].int_select, VIC_INT_SELECT0 + i * 4);
+	}
+	writel(3, VIC_INT_MASTEREN);
+	if (!smsm_int_info) {
+		printk(KERN_ERR "msm_irq_exit_sleep <SM NO INT_INFO>\n");
+		return;
+	}
+	if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP)
+		printk(KERN_INFO "msm_irq_exit_sleep1 %x %x %x now %x %x\n",
+		       smsm_int_info->interrupt_mask,
+		       smsm_int_info->pending_interrupts,
+		       smsm_int_info->wakeup_reason,
+		       readl(VIC_IRQ_STATUS0), readl(VIC_IRQ_STATUS1));
+}
+
+void msm_irq_exit_sleep2(void)
+{
+	int i;
+	uint32_t pending;
+
+	if (!smsm_int_info) {
+		printk(KERN_ERR "msm_irq_exit_sleep <SM NO INT_INFO>\n");
+		return;
+	}
+	if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP)
+		printk(KERN_INFO "msm_irq_exit_sleep2 %x %x %x now %x %x\n",
+		       smsm_int_info->interrupt_mask,
+		       smsm_int_info->pending_interrupts,
+		       smsm_int_info->wakeup_reason,
+		       readl(VIC_IRQ_STATUS0), readl(VIC_IRQ_STATUS1));
+	pending = smsm_int_info->pending_interrupts;
+	for (i = 0; pending && i < ARRAY_SIZE(msm_irq_to_smsm); i++) {
+		unsigned reg_offset = (i & 32) ? 4 : 0;
+		uint32_t reg_mask = 1UL << (i & 31);
+		int smsm_irq = msm_irq_to_smsm[i];
+		uint32_t smsm_mask;
+		if (smsm_irq == 0)
+			continue;
+		smsm_mask = 1U << (smsm_irq - 1);
+		if (!(pending & smsm_mask))
+			continue;
+		pending &= ~smsm_mask;
+		if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_INT)
+			printk(KERN_INFO "msm_irq_exit_sleep2: irq %d "
+			       "still pending %x now %x %x\n", i, pending,
+			       readl(VIC_IRQ_STATUS0), readl(VIC_IRQ_STATUS1));
+#if 0 /* debug intetrrupt trigger */
+		if (readl(VIC_IRQ_STATUS0 + reg_offset) & reg_mask)
+			writel(reg_mask, VIC_INT_CLEAR0 + reg_offset);
+#endif
+		if (readl(VIC_IRQ_STATUS0 + reg_offset) & reg_mask)
+			continue;
+		writel(reg_mask, VIC_SOFTINT0 + reg_offset);
+		if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_INT_TRIGGER)
+			printk(KERN_INFO "msm_irq_exit_sleep2: irq %d need "
+			       "trigger, now %x %x\n", i,
+			       readl(VIC_IRQ_STATUS0), readl(VIC_IRQ_STATUS1));
+	}
+}
+
+void msm_irq_exit_sleep3(void)
+{
+	if (!smsm_int_info) {
+		printk(KERN_ERR "msm_irq_exit_sleep <SM NO INT_INFO>\n");
+		return;
+	}
+	if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP)
+		printk(KERN_INFO "msm_irq_exit_sleep3 %x %x %x now %x %x "
+		       "state %x\n", smsm_int_info->interrupt_mask,
+		       smsm_int_info->pending_interrupts,
+		       smsm_int_info->wakeup_reason, readl(VIC_IRQ_STATUS0),
+		       readl(VIC_IRQ_STATUS1),
+		       smsm_get_state(SMSM_STATE_MODEM));
+}
+
 static struct irq_chip msm_irq_chip = {
-	.name          = "msm",
-	.irq_ack       = msm_irq_ack,
-	.irq_mask      = msm_irq_mask,
-	.irq_unmask    = msm_irq_unmask,
-	.irq_set_wake  = msm_irq_set_wake,
-	.irq_set_type  = msm_irq_set_type,
+	.name      = "msm",
+	.disable   = msm_irq_mask,
+	.ack       = msm_irq_ack,
+	.mask      = msm_irq_mask,
+	.unmask    = msm_irq_unmask,
+	.set_wake  = msm_irq_set_wake,
+	.set_type  = msm_irq_set_type,
 };
 
 void __init msm_init_irq(void)
@@ -142,10 +470,138 @@
 	writel(0, VIC_CONFIG);
 
 	/* enable interrupt controller */
-	writel(1, VIC_INT_MASTEREN);
+	writel(3, VIC_INT_MASTEREN);
 
 	for (n = 0; n < NR_MSM_IRQS; n++) {
 		irq_set_chip_and_handler(n, &msm_irq_chip, handle_level_irq);
 		set_irq_flags(n, IRQF_VALID);
 	}
+
+	msm_init_sirc();
 }
+
+static int __init msm_init_irq_late(void)
+{
+	smsm_int_info = smem_alloc(INT_INFO_SMSM_ID, sizeof(*smsm_int_info));
+	if (!smsm_int_info)
+		pr_err("set_wakeup_mask NO INT_INFO (%d)\n", INT_INFO_SMSM_ID);
+	return 0;
+}
+late_initcall(msm_init_irq_late);
+
+#if defined(CONFIG_MSM_FIQ_SUPPORT)
+void msm_trigger_irq(int irq)
+{
+	void __iomem *reg = VIC_SOFTINT0 + ((irq & 32) ? 4 : 0);
+	uint32_t mask = 1UL << (irq & 31);
+	writel(mask, reg);
+}
+
+void msm_fiq_enable(int irq)
+{
+	unsigned long flags;
+	local_irq_save(flags);
+	irq_desc[irq].chip->unmask(irq);
+	local_irq_restore(flags);
+}
+
+void msm_fiq_disable(int irq)
+{
+	unsigned long flags;
+	local_irq_save(flags);
+	irq_desc[irq].chip->mask(irq);
+	local_irq_restore(flags);
+}
+
+static void _msm_fiq_select(int irq)
+{
+	void __iomem *reg = VIC_INT_SELECT0 + ((irq & 32) ? 4 : 0);
+	unsigned index = (irq >> 5) & 1;
+	uint32_t mask = 1UL << (irq & 31);
+	unsigned long flags;
+
+	local_irq_save(flags);
+	msm_irq_shadow_reg[index].int_select |= mask;
+	writel(msm_irq_shadow_reg[index].int_select, reg);
+	local_irq_restore(flags);
+}
+
+static void _msm_fiq_unselect(int irq)
+{
+	void __iomem *reg = VIC_INT_SELECT0 + ((irq & 32) ? 4 : 0);
+	unsigned index = (irq >> 5) & 1;
+	uint32_t mask = 1UL << (irq & 31);
+	unsigned long flags;
+
+	local_irq_save(flags);
+	msm_irq_shadow_reg[index].int_select &= (!mask);
+	writel(msm_irq_shadow_reg[index].int_select, reg);
+	local_irq_restore(flags);
+}
+
+void msm_fiq_select(int irq)
+{
+	if (irq < FIRST_SIRC_IRQ)
+		_msm_fiq_select(irq);
+	else if (irq < FIRST_GPIO_IRQ)
+		sirc_fiq_select(irq, true);
+	else
+		pr_err("unsupported fiq %d", irq);
+}
+
+void msm_fiq_unselect(int irq)
+{
+	if (irq < FIRST_SIRC_IRQ)
+		_msm_fiq_unselect(irq);
+	else if (irq < FIRST_GPIO_IRQ)
+		sirc_fiq_select(irq, false);
+	else
+		pr_err("unsupported fiq %d", irq);
+}
+
+/* set_fiq_handler originally from arch/arm/kernel/fiq.c */
+static void set_fiq_handler(void *start, unsigned int length)
+{
+	memcpy((void *)0xffff001c, start, length);
+	flush_icache_range(0xffff001c, 0xffff001c + length);
+	if (!vectors_high())
+		flush_icache_range(0x1c, 0x1c + length);
+}
+
+extern unsigned char fiq_glue, fiq_glue_end;
+
+static void (*fiq_func)(void *data, void *regs, void *svc_sp);
+static void *fiq_data;
+static void *fiq_stack;
+
+void fiq_glue_setup(void *func, void *data, void *sp);
+
+int msm_fiq_set_handler(void (*func)(void *data, void *regs, void *svc_sp),
+			void *data)
+{
+	unsigned long flags;
+	int ret = -ENOMEM;
+
+	if (!fiq_stack)
+		fiq_stack = kzalloc(THREAD_SIZE, GFP_KERNEL);
+	if (!fiq_stack)
+		return -ENOMEM;
+
+	local_irq_save(flags);
+	if (fiq_func == 0) {
+		fiq_func = func;
+		fiq_data = data;
+		fiq_glue_setup(func, data, fiq_stack + THREAD_START_SP);
+		set_fiq_handler(&fiq_glue, (&fiq_glue_end - &fiq_glue));
+		ret = 0;
+	}
+	local_irq_restore(flags);
+	return ret;
+}
+
+void msm_fiq_exit_sleep(void)
+{
+	if (fiq_stack)
+		fiq_glue_setup(fiq_func, fiq_data, fiq_stack + THREAD_START_SP);
+}
+#endif
diff --git a/arch/arm/mach-msm/irq.h b/arch/arm/mach-msm/irq.h
new file mode 100644
index 0000000..8b0fbc0
--- /dev/null
+++ b/arch/arm/mach-msm/irq.h
@@ -0,0 +1,28 @@
+/* Copyright (c) 2008-2009, 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 _ARCH_ARM_MACH_MSM_IRQ_H_
+#define _ARCH_ARM_MACH_MSM_IRQ_H_
+
+int msm_irq_idle_sleep_allowed(void);
+unsigned int msm_irq_pending(void);
+void msm_irq_enter_sleep1(bool arm9_wake, int from_idle, uint32_t *irq_mask);
+int msm_irq_enter_sleep2(bool arm9_wake, int from_idle);
+void msm_irq_exit_sleep1
+	(uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs);
+void msm_irq_exit_sleep2
+	(uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending);
+void msm_irq_exit_sleep3
+	(uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs);
+
+#endif
diff --git a/arch/arm/mach-msm/jtag.c b/arch/arm/mach-msm/jtag.c
new file mode 100644
index 0000000..8dae9c6
--- /dev/null
+++ b/arch/arm/mach-msm/jtag.c
@@ -0,0 +1,1171 @@
+/* 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/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/export.h>
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+#include <mach/scm.h>
+
+#include "qdss-priv.h"
+#include "cp14.h"
+
+/* no of dbg regs + 1 (for storing the reg count) */
+#define MAX_DBG_REGS		(90)
+#define MAX_DBG_STATE_SIZE	(MAX_DBG_REGS * num_possible_cpus())
+/* no of etm regs + 1 (for storing the reg count) */
+#define MAX_ETM_REGS		(78)
+#define MAX_ETM_STATE_SIZE	(MAX_ETM_REGS * num_possible_cpus())
+
+#define OSLOCK_MAGIC		(0xC5ACCE55)
+#define DBGDSCR_MASK		(0x6C30FC3C)
+#define CPMR_ETMCLKEN		(0x8)
+#define TZ_DBG_ETM_FEAT_ID	(0x8)
+#define TZ_DBG_ETM_VER		(0x400000)
+
+
+uint32_t msm_jtag_save_cntr[NR_CPUS];
+uint32_t msm_jtag_restore_cntr[NR_CPUS];
+
+struct dbg_ctx {
+	uint8_t		arch;
+	bool		save_restore_enabled;
+	uint8_t		nr_wp;
+	uint8_t		nr_bp;
+	uint8_t		nr_ctx_cmp;
+	uint32_t	*state;
+};
+static struct dbg_ctx dbg;
+
+struct etm_ctx {
+	uint8_t		arch;
+	bool		save_restore_enabled;
+	uint8_t		nr_addr_cmp;
+	uint8_t		nr_cntr;
+	uint8_t		nr_ext_inp;
+	uint8_t		nr_ext_out;
+	uint8_t		nr_ctxid_cmp;
+	uint32_t	*state;
+};
+static struct etm_ctx etm;
+
+static int dbg_read_bxr(uint32_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		state[i++] = dbg_read(DBGBVR0);
+		state[i++] = dbg_read(DBGBCR0);
+		break;
+	case 1:
+		state[i++] = dbg_read(DBGBVR1);
+		state[i++] = dbg_read(DBGBCR1);
+		break;
+	case 2:
+		state[i++] = dbg_read(DBGBVR2);
+		state[i++] = dbg_read(DBGBCR2);
+		break;
+	case 3:
+		state[i++] = dbg_read(DBGBVR3);
+		state[i++] = dbg_read(DBGBCR3);
+		break;
+	case 4:
+		state[i++] = dbg_read(DBGBVR4);
+		state[i++] = dbg_read(DBGBCR4);
+		break;
+	case 5:
+		state[i++] = dbg_read(DBGBVR5);
+		state[i++] = dbg_read(DBGBCR5);
+		break;
+	case 6:
+		state[i++] = dbg_read(DBGBVR6);
+		state[i++] = dbg_read(DBGBCR6);
+		break;
+	case 7:
+		state[i++] = dbg_read(DBGBVR7);
+		state[i++] = dbg_read(DBGBCR7);
+		break;
+	case 8:
+		state[i++] = dbg_read(DBGBVR8);
+		state[i++] = dbg_read(DBGBCR8);
+		break;
+	case 9:
+		state[i++] = dbg_read(DBGBVR9);
+		state[i++] = dbg_read(DBGBCR9);
+		break;
+	case 10:
+		state[i++] = dbg_read(DBGBVR10);
+		state[i++] = dbg_read(DBGBCR10);
+		break;
+	case 11:
+		state[i++] = dbg_read(DBGBVR11);
+		state[i++] = dbg_read(DBGBCR11);
+		break;
+	case 12:
+		state[i++] = dbg_read(DBGBVR12);
+		state[i++] = dbg_read(DBGBCR12);
+		break;
+	case 13:
+		state[i++] = dbg_read(DBGBVR13);
+		state[i++] = dbg_read(DBGBCR13);
+		break;
+	case 14:
+		state[i++] = dbg_read(DBGBVR14);
+		state[i++] = dbg_read(DBGBCR14);
+		break;
+	case 15:
+		state[i++] = dbg_read(DBGBVR15);
+		state[i++] = dbg_read(DBGBCR15);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int dbg_write_bxr(uint32_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		dbg_write(state[i++], DBGBVR0);
+		dbg_write(state[i++], DBGBCR0);
+		break;
+	case 1:
+		dbg_write(state[i++], DBGBVR1);
+		dbg_write(state[i++], DBGBCR1);
+		break;
+	case 2:
+		dbg_write(state[i++], DBGBVR2);
+		dbg_write(state[i++], DBGBCR2);
+		break;
+	case 3:
+		dbg_write(state[i++], DBGBVR3);
+		dbg_write(state[i++], DBGBCR3);
+		break;
+	case 4:
+		dbg_write(state[i++], DBGBVR4);
+		dbg_write(state[i++], DBGBCR4);
+		break;
+	case 5:
+		dbg_write(state[i++], DBGBVR5);
+		dbg_write(state[i++], DBGBCR5);
+		break;
+	case 6:
+		dbg_write(state[i++], DBGBVR6);
+		dbg_write(state[i++], DBGBCR6);
+		break;
+	case 7:
+		dbg_write(state[i++], DBGBVR7);
+		dbg_write(state[i++], DBGBCR7);
+		break;
+	case 8:
+		dbg_write(state[i++], DBGBVR8);
+		dbg_write(state[i++], DBGBCR8);
+		break;
+	case 9:
+		dbg_write(state[i++], DBGBVR9);
+		dbg_write(state[i++], DBGBCR9);
+		break;
+	case 10:
+		dbg_write(state[i++], DBGBVR10);
+		dbg_write(state[i++], DBGBCR10);
+		break;
+	case 11:
+		dbg_write(state[i++], DBGBVR11);
+		dbg_write(state[i++], DBGBCR11);
+		break;
+	case 12:
+		dbg_write(state[i++], DBGBVR12);
+		dbg_write(state[i++], DBGBCR12);
+		break;
+	case 13:
+		dbg_write(state[i++], DBGBVR13);
+		dbg_write(state[i++], DBGBCR13);
+		break;
+	case 14:
+		dbg_write(state[i++], DBGBVR14);
+		dbg_write(state[i++], DBGBCR14);
+		break;
+	case 15:
+		dbg_write(state[i++], DBGBVR15);
+		dbg_write(state[i++], DBGBCR15);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int dbg_read_wxr(uint32_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		state[i++] = dbg_read(DBGWVR0);
+		state[i++] = dbg_read(DBGWCR0);
+		break;
+	case 1:
+		state[i++] = dbg_read(DBGWVR1);
+		state[i++] = dbg_read(DBGWCR1);
+		break;
+	case 2:
+		state[i++] = dbg_read(DBGWVR2);
+		state[i++] = dbg_read(DBGWCR2);
+		break;
+	case 3:
+		state[i++] = dbg_read(DBGWVR3);
+		state[i++] = dbg_read(DBGWCR3);
+		break;
+	case 4:
+		state[i++] = dbg_read(DBGWVR4);
+		state[i++] = dbg_read(DBGWCR4);
+		break;
+	case 5:
+		state[i++] = dbg_read(DBGWVR5);
+		state[i++] = dbg_read(DBGWCR5);
+		break;
+	case 6:
+		state[i++] = dbg_read(DBGWVR6);
+		state[i++] = dbg_read(DBGWCR6);
+		break;
+	case 7:
+		state[i++] = dbg_read(DBGWVR7);
+		state[i++] = dbg_read(DBGWCR7);
+		break;
+	case 8:
+		state[i++] = dbg_read(DBGWVR8);
+		state[i++] = dbg_read(DBGWCR8);
+		break;
+	case 9:
+		state[i++] = dbg_read(DBGWVR9);
+		state[i++] = dbg_read(DBGWCR9);
+		break;
+	case 10:
+		state[i++] = dbg_read(DBGWVR10);
+		state[i++] = dbg_read(DBGWCR10);
+		break;
+	case 11:
+		state[i++] = dbg_read(DBGWVR11);
+		state[i++] = dbg_read(DBGWCR11);
+		break;
+	case 12:
+		state[i++] = dbg_read(DBGWVR12);
+		state[i++] = dbg_read(DBGWCR12);
+		break;
+	case 13:
+		state[i++] = dbg_read(DBGWVR13);
+		state[i++] = dbg_read(DBGWCR13);
+		break;
+	case 14:
+		state[i++] = dbg_read(DBGWVR14);
+		state[i++] = dbg_read(DBGWCR14);
+		break;
+	case 15:
+		state[i++] = dbg_read(DBGWVR15);
+		state[i++] = dbg_read(DBGWCR15);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int dbg_write_wxr(uint32_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		dbg_write(state[i++], DBGWVR0);
+		dbg_write(state[i++], DBGWCR0);
+		break;
+	case 1:
+		dbg_write(state[i++], DBGWVR1);
+		dbg_write(state[i++], DBGWCR1);
+		break;
+	case 2:
+		dbg_write(state[i++], DBGWVR2);
+		dbg_write(state[i++], DBGWCR2);
+		break;
+	case 3:
+		dbg_write(state[i++], DBGWVR3);
+		dbg_write(state[i++], DBGWCR3);
+		break;
+	case 4:
+		dbg_write(state[i++], DBGWVR4);
+		dbg_write(state[i++], DBGWCR4);
+		break;
+	case 5:
+		dbg_write(state[i++], DBGWVR5);
+		dbg_write(state[i++], DBGWCR5);
+		break;
+	case 6:
+		dbg_write(state[i++], DBGWVR6);
+		dbg_write(state[i++], DBGWCR6);
+		break;
+	case 7:
+		dbg_write(state[i++], DBGWVR7);
+		dbg_write(state[i++], DBGWCR7);
+		break;
+	case 8:
+		dbg_write(state[i++], DBGWVR8);
+		dbg_write(state[i++], DBGWCR8);
+		break;
+	case 9:
+		dbg_write(state[i++], DBGWVR9);
+		dbg_write(state[i++], DBGWCR9);
+		break;
+	case 10:
+		dbg_write(state[i++], DBGWVR10);
+		dbg_write(state[i++], DBGWCR10);
+		break;
+	case 11:
+		dbg_write(state[i++], DBGWVR11);
+		dbg_write(state[i++], DBGWCR11);
+		break;
+	case 12:
+		dbg_write(state[i++], DBGWVR12);
+		dbg_write(state[i++], DBGWCR12);
+		break;
+	case 13:
+		dbg_write(state[i++], DBGWVR13);
+		dbg_write(state[i++], DBGWCR13);
+		break;
+	case 14:
+		dbg_write(state[i++], DBGWVR14);
+		dbg_write(state[i++], DBGWCR14);
+		break;
+	case 15:
+		dbg_write(state[i++], DBGWVR15);
+		dbg_write(state[i++], DBGWCR15);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static inline bool dbg_arch_supported(uint8_t arch)
+{
+	switch (arch) {
+	case ARM_DEBUG_ARCH_V7_1:
+	case ARM_DEBUG_ARCH_V7:
+	case ARM_DEBUG_ARCH_V7B:
+		break;
+	default:
+		return false;
+	}
+	return true;
+}
+
+
+static inline void dbg_save_state(int cpu)
+{
+	int i, j, cnt;
+
+	i = cpu * MAX_DBG_REGS;
+
+	switch (dbg.arch) {
+	case ARM_DEBUG_ARCH_V7_1:
+		/* Set OS lock to inform the debugger that the OS is in the
+		 * process of saving debug registers. It prevents accidental
+		 * modification of the debug regs by the external debugger.
+		 */
+		dbg_write(OSLOCK_MAGIC, DBGOSLAR);
+		isb();
+
+		/* We skip saving DBGBXVRn since not supported on Krait */
+
+		dbg.state[i++] = dbg_read(DBGWFAR);
+		for (j = 0; j < dbg.nr_bp; j++)
+			i = dbg_read_bxr(dbg.state, i, j);
+		for (j = 0; j < dbg.nr_wp; j++)
+			i = dbg_read_wxr(dbg.state, i, j);
+		dbg.state[i++] = dbg_read(DBGVCR);
+		dbg.state[i++] = dbg_read(DBGCLAIMCLR);
+		dbg.state[i++] = dbg_read(DBGDTRTXext);
+		dbg.state[i++] = dbg_read(DBGDTRRXext);
+		dbg.state[i++] = dbg_read(DBGDSCRext);
+
+		/* Set the OS double lock */
+		isb();
+		dbg_write(0x1, DBGOSDLR);
+		isb();
+		break;
+	case ARM_DEBUG_ARCH_V7B:
+	case ARM_DEBUG_ARCH_V7:
+		/* Set OS lock to inform the debugger that the OS is in the
+		 * process of saving dbg registers. It prevents accidental
+		 * modification of the dbg regs by the external debugger
+		 * and resets the internal counter.
+		 */
+		dbg_write(OSLOCK_MAGIC, DBGOSLAR);
+		isb();
+
+		cnt = dbg_read(DBGOSSRR); /* save count for restore */
+		/* MAX_DBG_REGS = no of dbg regs + 1 (for storing the reg count)
+		 * check for state overflow, if not enough space, don't save
+		 */
+		if (cnt >= MAX_DBG_REGS)
+			cnt = 0;
+		dbg.state[i++] = cnt;
+		for (j = 0; j < cnt; j++)
+			dbg.state[i++] = dbg_read(DBGOSSRR);
+		break;
+	default:
+		pr_err_ratelimited("unsupported dbg arch %d in %s\n", dbg.arch,
+								__func__);
+	}
+}
+
+static inline void dbg_restore_state(int cpu)
+{
+	int i, j, cnt;
+
+	i = cpu * MAX_DBG_REGS;
+
+	switch (dbg.arch) {
+	case ARM_DEBUG_ARCH_V7_1:
+		/* Clear the OS double lock */
+		isb();
+		dbg_write(0x0, DBGOSDLR);
+		isb();
+
+		/* Set OS lock. Lock will already be set after power collapse
+		 * but this write is included to ensure it is set.
+		 */
+		dbg_write(OSLOCK_MAGIC, DBGOSLAR);
+		isb();
+
+		/* We skip restoring DBGBXVRn since not supported on Krait */
+
+		dbg_write(dbg.state[i++], DBGWFAR);
+		for (j = 0; j < dbg.nr_bp; j++)
+			i = dbg_write_bxr(dbg.state, i, j);
+		for (j = 0; j < dbg.nr_wp; j++)
+			i = dbg_write_wxr(dbg.state, i, j);
+		dbg_write(dbg.state[i++], DBGVCR);
+		dbg_write(dbg.state[i++], DBGCLAIMSET);
+		dbg_write(dbg.state[i++], DBGDTRTXext);
+		dbg_write(dbg.state[i++], DBGDTRRXext);
+		dbg_write(dbg.state[i++] & DBGDSCR_MASK, DBGDSCRext);
+
+		isb();
+		dbg_write(0x0, DBGOSLAR);
+		isb();
+		break;
+	case ARM_DEBUG_ARCH_V7B:
+	case ARM_DEBUG_ARCH_V7:
+		/* Clear sticky bit */
+		dbg_read(DBGPRSR);
+		isb();
+
+		/* Set OS lock. Lock will already be set after power collapse
+		 * but this write is required to reset the internal counter used
+		 * for DBG state restore.
+		 */
+		dbg_write(OSLOCK_MAGIC, DBGOSLAR);
+		isb();
+
+		dbg_read(DBGOSSRR); /* dummy read of OSSRR */
+		cnt = dbg.state[i++];
+		for (j = 0; j < cnt; j++) {
+			/* DBGDSCR special case
+			 * DBGDSCR = DBGDSCR & DBGDSCR_MASK
+			 */
+			if (j == 20)
+				dbg_write(dbg.state[i++] & DBGDSCR_MASK,
+								DBGOSSRR);
+			else
+				dbg_write(dbg.state[i++], DBGOSSRR);
+		}
+
+		/* Clear the OS lock */
+		isb();
+		dbg_write(0x0, DBGOSLAR);
+		isb();
+		break;
+	default:
+		pr_err_ratelimited("unsupported dbg arch %d in %s\n", dbg.arch,
+								__func__);
+	}
+
+}
+
+static int etm_read_acxr(uint32_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		state[i++] = etm_read(ETMACVR0);
+		state[i++] = etm_read(ETMACTR0);
+		break;
+	case 1:
+		state[i++] = etm_read(ETMACVR1);
+		state[i++] = etm_read(ETMACTR1);
+		break;
+	case 2:
+		state[i++] = etm_read(ETMACVR2);
+		state[i++] = etm_read(ETMACTR2);
+		break;
+	case 3:
+		state[i++] = etm_read(ETMACVR3);
+		state[i++] = etm_read(ETMACTR3);
+		break;
+	case 4:
+		state[i++] = etm_read(ETMACVR4);
+		state[i++] = etm_read(ETMACTR4);
+		break;
+	case 5:
+		state[i++] = etm_read(ETMACVR5);
+		state[i++] = etm_read(ETMACTR5);
+		break;
+	case 6:
+		state[i++] = etm_read(ETMACVR6);
+		state[i++] = etm_read(ETMACTR6);
+		break;
+	case 7:
+		state[i++] = etm_read(ETMACVR7);
+		state[i++] = etm_read(ETMACTR7);
+		break;
+	case 8:
+		state[i++] = etm_read(ETMACVR8);
+		state[i++] = etm_read(ETMACTR8);
+		break;
+	case 9:
+		state[i++] = etm_read(ETMACVR9);
+		state[i++] = etm_read(ETMACTR9);
+		break;
+	case 10:
+		state[i++] = etm_read(ETMACVR10);
+		state[i++] = etm_read(ETMACTR10);
+		break;
+	case 11:
+		state[i++] = etm_read(ETMACVR11);
+		state[i++] = etm_read(ETMACTR11);
+		break;
+	case 12:
+		state[i++] = etm_read(ETMACVR12);
+		state[i++] = etm_read(ETMACTR12);
+		break;
+	case 13:
+		state[i++] = etm_read(ETMACVR13);
+		state[i++] = etm_read(ETMACTR13);
+		break;
+	case 14:
+		state[i++] = etm_read(ETMACVR14);
+		state[i++] = etm_read(ETMACTR14);
+		break;
+	case 15:
+		state[i++] = etm_read(ETMACVR15);
+		state[i++] = etm_read(ETMACTR15);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int etm_write_acxr(uint32_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		etm_write(state[i++], ETMACVR0);
+		etm_write(state[i++], ETMACTR0);
+		break;
+	case 1:
+		etm_write(state[i++], ETMACVR1);
+		etm_write(state[i++], ETMACTR1);
+		break;
+	case 2:
+		etm_write(state[i++], ETMACVR2);
+		etm_write(state[i++], ETMACTR2);
+		break;
+	case 3:
+		etm_write(state[i++], ETMACVR3);
+		etm_write(state[i++], ETMACTR3);
+		break;
+	case 4:
+		etm_write(state[i++], ETMACVR4);
+		etm_write(state[i++], ETMACTR4);
+		break;
+	case 5:
+		etm_write(state[i++], ETMACVR5);
+		etm_write(state[i++], ETMACTR5);
+		break;
+	case 6:
+		etm_write(state[i++], ETMACVR6);
+		etm_write(state[i++], ETMACTR6);
+		break;
+	case 7:
+		etm_write(state[i++], ETMACVR7);
+		etm_write(state[i++], ETMACTR7);
+		break;
+	case 8:
+		etm_write(state[i++], ETMACVR8);
+		etm_write(state[i++], ETMACTR8);
+		break;
+	case 9:
+		etm_write(state[i++], ETMACVR9);
+		etm_write(state[i++], ETMACTR9);
+		break;
+	case 10:
+		etm_write(state[i++], ETMACVR10);
+		etm_write(state[i++], ETMACTR10);
+		break;
+	case 11:
+		etm_write(state[i++], ETMACVR11);
+		etm_write(state[i++], ETMACTR11);
+		break;
+	case 12:
+		etm_write(state[i++], ETMACVR12);
+		etm_write(state[i++], ETMACTR12);
+		break;
+	case 13:
+		etm_write(state[i++], ETMACVR13);
+		etm_write(state[i++], ETMACTR13);
+		break;
+	case 14:
+		etm_write(state[i++], ETMACVR14);
+		etm_write(state[i++], ETMACTR14);
+		break;
+	case 15:
+		etm_write(state[i++], ETMACVR15);
+		etm_write(state[i++], ETMACTR15);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int etm_read_cntx(uint32_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		state[i++] = etm_read(ETMCNTRLDVR0);
+		state[i++] = etm_read(ETMCNTENR0);
+		state[i++] = etm_read(ETMCNTRLDEVR0);
+		state[i++] = etm_read(ETMCNTVR0);
+		break;
+	case 1:
+		state[i++] = etm_read(ETMCNTRLDVR1);
+		state[i++] = etm_read(ETMCNTENR1);
+		state[i++] = etm_read(ETMCNTRLDEVR1);
+		state[i++] = etm_read(ETMCNTVR1);
+		break;
+	case 2:
+		state[i++] = etm_read(ETMCNTRLDVR2);
+		state[i++] = etm_read(ETMCNTENR2);
+		state[i++] = etm_read(ETMCNTRLDEVR2);
+		state[i++] = etm_read(ETMCNTVR2);
+		break;
+	case 3:
+		state[i++] = etm_read(ETMCNTRLDVR3);
+		state[i++] = etm_read(ETMCNTENR3);
+		state[i++] = etm_read(ETMCNTRLDEVR3);
+		state[i++] = etm_read(ETMCNTVR3);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int etm_write_cntx(uint32_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		etm_write(state[i++], ETMCNTRLDVR0);
+		etm_write(state[i++], ETMCNTENR0);
+		etm_write(state[i++], ETMCNTRLDEVR0);
+		etm_write(state[i++], ETMCNTVR0);
+		break;
+	case 1:
+		etm_write(state[i++], ETMCNTRLDVR1);
+		etm_write(state[i++], ETMCNTENR1);
+		etm_write(state[i++], ETMCNTRLDEVR1);
+		etm_write(state[i++], ETMCNTVR1);
+		break;
+	case 2:
+		etm_write(state[i++], ETMCNTRLDVR2);
+		etm_write(state[i++], ETMCNTENR2);
+		etm_write(state[i++], ETMCNTRLDEVR2);
+		etm_write(state[i++], ETMCNTVR2);
+		break;
+	case 3:
+		etm_write(state[i++], ETMCNTRLDVR3);
+		etm_write(state[i++], ETMCNTENR3);
+		etm_write(state[i++], ETMCNTRLDEVR3);
+		etm_write(state[i++], ETMCNTVR3);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int etm_read_extoutevr(uint32_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		state[i++] = etm_read(ETMEXTOUTEVR0);
+		break;
+	case 1:
+		state[i++] = etm_read(ETMEXTOUTEVR1);
+		break;
+	case 2:
+		state[i++] = etm_read(ETMEXTOUTEVR2);
+		break;
+	case 3:
+		state[i++] = etm_read(ETMEXTOUTEVR3);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int etm_write_extoutevr(uint32_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		etm_write(state[i++], ETMEXTOUTEVR0);
+		break;
+	case 1:
+		etm_write(state[i++], ETMEXTOUTEVR1);
+		break;
+	case 2:
+		etm_write(state[i++], ETMEXTOUTEVR2);
+		break;
+	case 3:
+		etm_write(state[i++], ETMEXTOUTEVR3);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int etm_read_cidcvr(uint32_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		state[i++] = etm_read(ETMCIDCVR0);
+		break;
+	case 1:
+		state[i++] = etm_read(ETMCIDCVR1);
+		break;
+	case 2:
+		state[i++] = etm_read(ETMCIDCVR2);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int etm_write_cidcvr(uint32_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		etm_write(state[i++], ETMCIDCVR0);
+		break;
+	case 1:
+		etm_write(state[i++], ETMCIDCVR1);
+		break;
+	case 2:
+		etm_write(state[i++], ETMCIDCVR2);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static inline void etm_clk_disable(void)
+{
+	uint32_t cpmr;
+
+	isb();
+	asm volatile("mrc p15, 7, %0, c15, c0, 5" : "=r" (cpmr));
+	cpmr  &= ~CPMR_ETMCLKEN;
+	asm volatile("mcr p15, 7, %0, c15, c0, 5" : : "r" (cpmr));
+}
+
+static inline void etm_clk_enable(void)
+{
+	uint32_t cpmr;
+
+	asm volatile("mrc p15, 7, %0, c15, c0, 5" : "=r" (cpmr));
+	cpmr  |= CPMR_ETMCLKEN;
+	asm volatile("mcr p15, 7, %0, c15, c0, 5" : : "r" (cpmr));
+	isb();
+}
+
+static inline bool etm_arch_supported(uint8_t arch)
+{
+	switch (arch) {
+	case ETM_ARCH_V3_3:
+	case PFT_ARCH_V1_1:
+		break;
+	default:
+		return false;
+	}
+	return true;
+}
+
+static inline void etm_save_state(int cpu)
+{
+	int i, j, cnt;
+
+	i = cpu * MAX_ETM_REGS;
+
+	/* Vote for ETM power/clock enable */
+	etm_clk_enable();
+
+	switch (etm.arch) {
+	case PFT_ARCH_V1_1:
+		/* Set OS lock to inform the debugger that the OS is in the
+		 * process of saving etm registers. It prevents accidental
+		 * modification of the etm regs by the external debugger.
+		 *
+		 * We don't poll for ETMSR[1] since it doesn't get set
+		 */
+		etm_write(OSLOCK_MAGIC, ETMOSLAR);
+		isb();
+
+		etm.state[i++] = etm_read(ETMCR);
+		etm.state[i++] = etm_read(ETMTRIGGER);
+		etm.state[i++] = etm_read(ETMSR);
+		etm.state[i++] = etm_read(ETMTSSCR);
+		etm.state[i++] = etm_read(ETMTEEVR);
+		etm.state[i++] = etm_read(ETMTECR1);
+		etm.state[i++] = etm_read(ETMFFLR);
+		for (j = 0; j < etm.nr_addr_cmp; j++)
+			i = etm_read_acxr(etm.state, i, j);
+		for (j = 0; j < etm.nr_cntr; j++)
+			i = etm_read_cntx(etm.state, i, j);
+		etm.state[i++] = etm_read(ETMSQ12EVR);
+		etm.state[i++] = etm_read(ETMSQ21EVR);
+		etm.state[i++] = etm_read(ETMSQ23EVR);
+		etm.state[i++] = etm_read(ETMSQ31EVR);
+		etm.state[i++] = etm_read(ETMSQ32EVR);
+		etm.state[i++] = etm_read(ETMSQ13EVR);
+		etm.state[i++] = etm_read(ETMSQR);
+		for (j = 0; j < etm.nr_ext_out; j++)
+			i = etm_read_extoutevr(etm.state, i, j);
+		for (j = 0; j < etm.nr_ctxid_cmp; j++)
+			i = etm_read_cidcvr(etm.state, i, j);
+		etm.state[i++] = etm_read(ETMCIDCMR);
+		etm.state[i++] = etm_read(ETMSYNCFR);
+		etm.state[i++] = etm_read(ETMEXTINSELR);
+		etm.state[i++] = etm_read(ETMTSEVR);
+		etm.state[i++] = etm_read(ETMAUXCR);
+		etm.state[i++] = etm_read(ETMTRACEIDR);
+		etm.state[i++] = etm_read(ETMVMIDCVR);
+		etm.state[i++] = etm_read(ETMCLAIMCLR);
+		break;
+	case ETM_ARCH_V3_3:
+		/* In ETMv3.3, it is possible for the coresight lock to be
+		 * implemented for CP14 interface but we currently assume that
+		 * it is not, so no need to unlock and lock coresight lock
+		 * (ETMLAR).
+		 *
+		 * Also since save and restore is not conditional i.e. always
+		 * occurs when enabled, there is no need to clear the sticky
+		 * PDSR bit while saving. It will be cleared during boot up/init
+		 * and then by the restore procedure.
+		 */
+
+		/* Set OS lock to inform the debugger that the OS is in the
+		 * process of saving etm registers. It prevents accidental
+		 * modification of the etm regs by the external debugger
+		 * and resets the internal counter.
+		 */
+		etm_write(OSLOCK_MAGIC, ETMOSLAR);
+		isb();
+
+		cnt = etm_read(ETMOSSRR); /* save count for restore */
+		/* MAX_ETM_REGS = no of etm regs + 1 (for storing the reg count)
+		 * check for state overflow, if not enough space, don't save
+		 */
+		if (cnt >= MAX_ETM_REGS)
+			cnt = 0;
+		etm.state[i++] = cnt;
+		for (j = 0; j < cnt; j++)
+			etm.state[i++] = etm_read(ETMOSSRR);
+		break;
+	default:
+		pr_err_ratelimited("unsupported etm arch %d in %s\n", etm.arch,
+								__func__);
+	}
+
+	/* Vote for ETM power/clock disable */
+	etm_clk_disable();
+}
+
+static inline void etm_restore_state(int cpu)
+{
+	int i, j, cnt;
+
+	i = cpu * MAX_ETM_REGS;
+
+	/* Vote for ETM power/clock enable */
+	etm_clk_enable();
+
+	switch (etm.arch) {
+	case PFT_ARCH_V1_1:
+		/* Set OS lock. Lock will already be set after power collapse
+		 * but this write is included to ensure it is set.
+		 *
+		 * We don't poll for ETMSR[1] since it doesn't get set
+		 */
+		etm_write(OSLOCK_MAGIC, ETMOSLAR);
+		isb();
+
+		etm_write(etm.state[i++], ETMCR);
+		etm_write(etm.state[i++], ETMTRIGGER);
+		etm_write(etm.state[i++], ETMSR);
+		etm_write(etm.state[i++], ETMTSSCR);
+		etm_write(etm.state[i++], ETMTEEVR);
+		etm_write(etm.state[i++], ETMTECR1);
+		etm_write(etm.state[i++], ETMFFLR);
+		for (j = 0; j < etm.nr_addr_cmp; j++)
+			i = etm_write_acxr(etm.state, i, j);
+		for (j = 0; j < etm.nr_cntr; j++)
+			i = etm_write_cntx(etm.state, i, j);
+		etm_write(etm.state[i++], ETMSQ12EVR);
+		etm_write(etm.state[i++], ETMSQ21EVR);
+		etm_write(etm.state[i++], ETMSQ23EVR);
+		etm_write(etm.state[i++], ETMSQ31EVR);
+		etm_write(etm.state[i++], ETMSQ32EVR);
+		etm_write(etm.state[i++], ETMSQ13EVR);
+		etm_write(etm.state[i++], ETMSQR);
+		for (j = 0; j < etm.nr_ext_out; j++)
+			i = etm_write_extoutevr(etm.state, i, j);
+		for (j = 0; j < etm.nr_ctxid_cmp; j++)
+			i = etm_write_cidcvr(etm.state, i, j);
+		etm_write(etm.state[i++], ETMCIDCMR);
+		etm_write(etm.state[i++], ETMSYNCFR);
+		etm_write(etm.state[i++], ETMEXTINSELR);
+		etm_write(etm.state[i++], ETMTSEVR);
+		etm_write(etm.state[i++], ETMAUXCR);
+		etm_write(etm.state[i++], ETMTRACEIDR);
+		etm_write(etm.state[i++], ETMVMIDCVR);
+		etm_write(etm.state[i++], ETMCLAIMSET);
+
+		/* Clear the OS lock */
+		isb();
+		etm_write(0x0, ETMOSLAR);
+		isb();
+		break;
+	case ETM_ARCH_V3_3:
+		/* In ETMv3.3, it is possible for the coresight lock to be
+		 * implemented for CP14 interface but we currently assume that
+		 * it is not, so no need to unlock and lock coresight lock
+		 * (ETMLAR).
+		 */
+
+		/* Clear sticky bit */
+		etm_read(ETMPDSR);
+		isb();
+
+		/* Set OS lock. Lock will already be set after power collapse
+		 * but this write is required to reset the internal counter used
+		 * for ETM state restore.
+		 */
+		etm_write(OSLOCK_MAGIC, ETMOSLAR);
+		isb();
+
+		etm_read(ETMOSSRR); /* dummy read of OSSRR */
+		cnt = etm.state[i++];
+		for (j = 0; j < cnt; j++)
+			etm_write(etm.state[i++], ETMOSSRR);
+
+		/* Clear the OS lock */
+		isb();
+		etm_write(0x0, ETMOSLAR);
+		isb();
+		break;
+	default:
+		pr_err_ratelimited("unsupported etm arch %d in %s\n", etm.arch,
+								__func__);
+	}
+
+	/* Vote for ETM power/clock disable */
+	etm_clk_disable();
+}
+
+/**
+ * msm_jtag_save_state - save debug and etm registers
+ *
+ * Debug and etm registers are saved before power collapse if debug
+ * and etm architecture is supported respectively and TZ isn't supporting
+ * the save and restore of debug and etm registers.
+ *
+ * CONTEXT:
+ * Called with preemption off and interrupts locked from:
+ * 1. per_cpu idle thread context for idle power collapses
+ * or
+ * 2. per_cpu idle thread context for hotplug/suspend power collapse
+ *    for nonboot cpus
+ * or
+ * 3. suspend thread context for suspend power collapse for core0
+ *
+ * In all cases we will run on the same cpu for the entire duration.
+ */
+void msm_jtag_save_state(void)
+{
+	int cpu;
+
+	cpu = raw_smp_processor_id();
+
+	msm_jtag_save_cntr[cpu]++;
+	/* ensure counter is updated before moving forward */
+	mb();
+
+	if (dbg.save_restore_enabled)
+		dbg_save_state(cpu);
+	if (etm.save_restore_enabled)
+		etm_save_state(cpu);
+}
+EXPORT_SYMBOL(msm_jtag_save_state);
+
+/**
+ * msm_jtag_restore_state - restore debug and etm registers
+ *
+ * Debug and etm registers are restored after power collapse if debug
+ * and etm architecture is supported respectively and TZ isn't supporting
+ * the save and restore of debug and etm registers.
+ *
+ * CONTEXT:
+ * Called with preemption off and interrupts locked from:
+ * 1. per_cpu idle thread context for idle power collapses
+ * or
+ * 2. per_cpu idle thread context for hotplug/suspend power collapse
+ *    for nonboot cpus
+ * or
+ * 3. suspend thread context for suspend power collapse for core0
+ *
+ * In all cases we will run on the same cpu for the entire duration.
+ */
+void msm_jtag_restore_state(void)
+{
+	int cpu;
+
+	cpu = raw_smp_processor_id();
+
+	msm_jtag_restore_cntr[cpu]++;
+	/* ensure counter is updated before moving forward */
+	mb();
+
+	if (dbg.save_restore_enabled)
+		dbg_restore_state(cpu);
+	if (etm.save_restore_enabled)
+		etm_restore_state(cpu);
+}
+EXPORT_SYMBOL(msm_jtag_restore_state);
+
+static int __init msm_jtag_dbg_init(void)
+{
+	int ret;
+	uint32_t dbgdidr;
+
+	/* This will run on core0 so use it to populate parameters */
+
+	/* Populate dbg_ctx data */
+
+	dbgdidr = dbg_read(DBGDIDR);
+	dbg.arch = BMVAL(dbgdidr, 16, 19);
+	dbg.nr_ctx_cmp = BMVAL(dbgdidr, 20, 23) + 1;
+	dbg.nr_bp = BMVAL(dbgdidr, 24, 27) + 1;
+	dbg.nr_wp = BMVAL(dbgdidr, 28, 31) + 1;
+
+	if (dbg_arch_supported(dbg.arch)) {
+		if (scm_get_feat_version(TZ_DBG_ETM_FEAT_ID) < TZ_DBG_ETM_VER) {
+			dbg.save_restore_enabled = true;
+		} else {
+			pr_info("dbg save-restore supported by TZ\n");
+			goto dbg_out;
+		}
+	} else {
+		pr_info("dbg arch %u not supported\n", dbg.arch);
+		goto dbg_out;
+	}
+
+	/* Allocate dbg state save space */
+	dbg.state = kzalloc(MAX_DBG_STATE_SIZE * sizeof(uint32_t), GFP_KERNEL);
+	if (!dbg.state) {
+		ret = -ENOMEM;
+		goto dbg_err;
+	}
+dbg_out:
+	return 0;
+dbg_err:
+	return ret;
+}
+arch_initcall(msm_jtag_dbg_init);
+
+static int __init msm_jtag_etm_init(void)
+{
+	int ret;
+	uint32_t etmidr;
+	uint32_t etmccr;
+
+	/* Vote for ETM power/clock enable */
+	etm_clk_enable();
+
+	/* Clear sticky bit in PDSR - required for ETMv3.3 (8660) */
+	etm_read(ETMPDSR);
+	isb();
+
+	/* Populate etm_ctx data */
+
+	etmidr = etm_read(ETMIDR);
+	etm.arch = BMVAL(etmidr, 4, 11);
+
+	etmccr = etm_read(ETMCCR);
+	etm.nr_addr_cmp = BMVAL(etmccr, 0, 3) * 2;
+	etm.nr_cntr = BMVAL(etmccr, 13, 15);
+	etm.nr_ext_inp = BMVAL(etmccr, 17, 19);
+	etm.nr_ext_out = BMVAL(etmccr, 20, 22);
+	etm.nr_ctxid_cmp = BMVAL(etmccr, 24, 25);
+
+	if (etm_arch_supported(etm.arch)) {
+		if (scm_get_feat_version(TZ_DBG_ETM_FEAT_ID) < TZ_DBG_ETM_VER) {
+			etm.save_restore_enabled = true;
+		} else {
+			pr_info("etm save-restore supported by TZ\n");
+			goto etm_out;
+		}
+	} else {
+		pr_info("etm arch %u not supported\n", etm.arch);
+		goto etm_out;
+	}
+
+	/* Vote for ETM power/clock disable */
+	etm_clk_disable();
+
+	/* Allocate etm state save space */
+	etm.state = kzalloc(MAX_ETM_STATE_SIZE * sizeof(uint32_t), GFP_KERNEL);
+	if (!etm.state) {
+		ret = -ENOMEM;
+		goto etm_err;
+	}
+etm_out:
+	etm_clk_disable();
+	return 0;
+etm_err:
+	return ret;
+}
+arch_initcall(msm_jtag_etm_init);
diff --git a/arch/arm/mach-msm/keypad-surf-ffa.c b/arch/arm/mach-msm/keypad-surf-ffa.c
new file mode 100644
index 0000000..711cdbb
--- /dev/null
+++ b/arch/arm/mach-msm/keypad-surf-ffa.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/gpio_event.h>
+
+#include <asm/mach-types.h>
+
+/* don't turn this on without updating the ffa support */
+#define SCAN_FUNCTION_KEYS 0
+
+/* FFA:
+ 36: KEYSENSE_N(0)
+ 37: KEYSENSE_N(1)
+ 38: KEYSENSE_N(2)
+ 39: KEYSENSE_N(3)
+ 40: KEYSENSE_N(4)
+
+ 31: KYPD_17
+ 32: KYPD_15
+ 33: KYPD_13
+ 34: KYPD_11
+ 35: KYPD_9
+ 41: KYPD_MEMO
+*/
+
+static unsigned int keypad_row_gpios[] = {
+	31, 32, 33, 34, 35, 41
+#if SCAN_FUNCTION_KEYS
+	, 42
+#endif
+};
+
+static unsigned int keypad_col_gpios[] = { 36, 37, 38, 39, 40 };
+
+static unsigned int keypad_row_gpios_8k_ffa[] = {31, 32, 33, 34, 35, 36};
+static unsigned int keypad_col_gpios_8k_ffa[] = {38, 39, 40, 41, 42};
+
+#define KEYMAP_INDEX(row, col) ((row)*ARRAY_SIZE(keypad_col_gpios) + (col))
+#define FFA_8K_KEYMAP_INDEX(row, col) ((row)* \
+				ARRAY_SIZE(keypad_col_gpios_8k_ffa) + (col))
+
+static const unsigned short keypad_keymap_surf[ARRAY_SIZE(keypad_col_gpios) *
+					  ARRAY_SIZE(keypad_row_gpios)] = {
+	[KEYMAP_INDEX(0, 0)] = KEY_5,
+	[KEYMAP_INDEX(0, 1)] = KEY_9,
+	[KEYMAP_INDEX(0, 2)] = 229,            /* SOFT1 */
+	[KEYMAP_INDEX(0, 3)] = KEY_6,
+	[KEYMAP_INDEX(0, 4)] = KEY_LEFT,
+
+	[KEYMAP_INDEX(1, 0)] = KEY_0,
+	[KEYMAP_INDEX(1, 1)] = KEY_RIGHT,
+	[KEYMAP_INDEX(1, 2)] = KEY_1,
+	[KEYMAP_INDEX(1, 3)] = 228,           /* KEY_SHARP */
+	[KEYMAP_INDEX(1, 4)] = KEY_SEND,
+
+	[KEYMAP_INDEX(2, 0)] = KEY_VOLUMEUP,
+	[KEYMAP_INDEX(2, 1)] = KEY_HOME,      /* FA   */
+	[KEYMAP_INDEX(2, 2)] = KEY_F8,        /* QCHT */
+	[KEYMAP_INDEX(2, 3)] = KEY_F6,        /* R+   */
+	[KEYMAP_INDEX(2, 4)] = KEY_F7,        /* R-   */
+
+	[KEYMAP_INDEX(3, 0)] = KEY_UP,
+	[KEYMAP_INDEX(3, 1)] = KEY_CLEAR,
+	[KEYMAP_INDEX(3, 2)] = KEY_4,
+	[KEYMAP_INDEX(3, 3)] = KEY_MUTE,      /* SPKR */
+	[KEYMAP_INDEX(3, 4)] = KEY_2,
+
+	[KEYMAP_INDEX(4, 0)] = 230,           /* SOFT2 */
+	[KEYMAP_INDEX(4, 1)] = 232,           /* KEY_CENTER */
+	[KEYMAP_INDEX(4, 2)] = KEY_DOWN,
+	[KEYMAP_INDEX(4, 3)] = KEY_BACK,      /* FB */
+	[KEYMAP_INDEX(4, 4)] = KEY_8,
+
+	[KEYMAP_INDEX(5, 0)] = KEY_VOLUMEDOWN,
+	[KEYMAP_INDEX(5, 1)] = 227,           /* KEY_STAR */
+	[KEYMAP_INDEX(5, 2)] = KEY_MAIL,      /* MESG */
+	[KEYMAP_INDEX(5, 3)] = KEY_3,
+	[KEYMAP_INDEX(5, 4)] = KEY_7,
+
+#if SCAN_FUNCTION_KEYS
+	[KEYMAP_INDEX(6, 0)] = KEY_F5,
+	[KEYMAP_INDEX(6, 1)] = KEY_F4,
+	[KEYMAP_INDEX(6, 2)] = KEY_F3,
+	[KEYMAP_INDEX(6, 3)] = KEY_F2,
+	[KEYMAP_INDEX(6, 4)] = KEY_F1
+#endif
+};
+
+static const unsigned short keypad_keymap_ffa[ARRAY_SIZE(keypad_col_gpios) *
+					      ARRAY_SIZE(keypad_row_gpios)] = {
+	/*[KEYMAP_INDEX(0, 0)] = ,*/
+	/*[KEYMAP_INDEX(0, 1)] = ,*/
+	[KEYMAP_INDEX(0, 2)] = KEY_1,
+	[KEYMAP_INDEX(0, 3)] = KEY_SEND,
+	[KEYMAP_INDEX(0, 4)] = KEY_LEFT,
+
+	[KEYMAP_INDEX(1, 0)] = KEY_3,
+	[KEYMAP_INDEX(1, 1)] = KEY_RIGHT,
+	[KEYMAP_INDEX(1, 2)] = KEY_VOLUMEUP,
+	/*[KEYMAP_INDEX(1, 3)] = ,*/
+	[KEYMAP_INDEX(1, 4)] = KEY_6,
+
+	[KEYMAP_INDEX(2, 0)] = KEY_HOME,      /* A */
+	[KEYMAP_INDEX(2, 1)] = KEY_BACK,      /* B */
+	[KEYMAP_INDEX(2, 2)] = KEY_0,
+	[KEYMAP_INDEX(2, 3)] = 228,           /* KEY_SHARP */
+	[KEYMAP_INDEX(2, 4)] = KEY_9,
+
+	[KEYMAP_INDEX(3, 0)] = KEY_UP,
+	[KEYMAP_INDEX(3, 1)] = 232, /* KEY_CENTER */ /* i */
+	[KEYMAP_INDEX(3, 2)] = KEY_4,
+	/*[KEYMAP_INDEX(3, 3)] = ,*/
+	[KEYMAP_INDEX(3, 4)] = KEY_2,
+
+	[KEYMAP_INDEX(4, 0)] = KEY_VOLUMEDOWN,
+	[KEYMAP_INDEX(4, 1)] = KEY_SOUND,
+	[KEYMAP_INDEX(4, 2)] = KEY_DOWN,
+	[KEYMAP_INDEX(4, 3)] = KEY_8,
+	[KEYMAP_INDEX(4, 4)] = KEY_5,
+
+	/*[KEYMAP_INDEX(5, 0)] = ,*/
+	[KEYMAP_INDEX(5, 1)] = 227,           /* KEY_STAR */
+	[KEYMAP_INDEX(5, 2)] = 230, /*SOFT2*/ /* 2 */
+	[KEYMAP_INDEX(5, 3)] = KEY_MENU,      /* 1 */
+	[KEYMAP_INDEX(5, 4)] = KEY_7,
+};
+
+#define QSD8x50_FFA_KEYMAP_SIZE (ARRAY_SIZE(keypad_col_gpios_8k_ffa) * \
+			ARRAY_SIZE(keypad_row_gpios_8k_ffa))
+
+static const unsigned short keypad_keymap_8k_ffa[QSD8x50_FFA_KEYMAP_SIZE] = {
+
+	[FFA_8K_KEYMAP_INDEX(0, 0)] = KEY_VOLUMEDOWN,
+	/*[KEYMAP_INDEX(0, 1)] = ,*/
+	[FFA_8K_KEYMAP_INDEX(0, 2)] = KEY_DOWN,
+	[FFA_8K_KEYMAP_INDEX(0, 3)] = KEY_8,
+	[FFA_8K_KEYMAP_INDEX(0, 4)] = KEY_5,
+
+	[FFA_8K_KEYMAP_INDEX(1, 0)] = KEY_UP,
+	[FFA_8K_KEYMAP_INDEX(1, 1)] = KEY_CLEAR,
+	[FFA_8K_KEYMAP_INDEX(1, 2)] = KEY_4,
+	/*[KEYMAP_INDEX(1, 3)] = ,*/
+	[FFA_8K_KEYMAP_INDEX(1, 4)] = KEY_2,
+
+	[FFA_8K_KEYMAP_INDEX(2, 0)] = KEY_HOME,      /* A */
+	[FFA_8K_KEYMAP_INDEX(2, 1)] = KEY_BACK,      /* B */
+	[FFA_8K_KEYMAP_INDEX(2, 2)] = KEY_0,
+	[FFA_8K_KEYMAP_INDEX(2, 3)] = 228,           /* KEY_SHARP */
+	[FFA_8K_KEYMAP_INDEX(2, 4)] = KEY_9,
+
+	[FFA_8K_KEYMAP_INDEX(3, 0)] = KEY_3,
+	[FFA_8K_KEYMAP_INDEX(3, 1)] = KEY_RIGHT,
+	[FFA_8K_KEYMAP_INDEX(3, 2)] = KEY_VOLUMEUP,
+	/*[KEYMAP_INDEX(3, 3)] = ,*/
+	[FFA_8K_KEYMAP_INDEX(3, 4)] = KEY_6,
+
+	[FFA_8K_KEYMAP_INDEX(4, 0)] = 232,		/* OK */
+	[FFA_8K_KEYMAP_INDEX(4, 1)] = KEY_SOUND,
+	[FFA_8K_KEYMAP_INDEX(4, 2)] = KEY_1,
+	[FFA_8K_KEYMAP_INDEX(4, 3)] = KEY_SEND,
+	[FFA_8K_KEYMAP_INDEX(4, 4)] = KEY_LEFT,
+
+	/*[KEYMAP_INDEX(5, 0)] = ,*/
+	[FFA_8K_KEYMAP_INDEX(5, 1)] = 227,           /* KEY_STAR */
+	[FFA_8K_KEYMAP_INDEX(5, 2)] = 230, /*SOFT2*/ /* 2 */
+	[FFA_8K_KEYMAP_INDEX(5, 3)] = 229,      /* 1 */
+	[FFA_8K_KEYMAP_INDEX(5, 4)] = KEY_7,
+};
+
+/* SURF keypad platform device information */
+static struct gpio_event_matrix_info surf_keypad_matrix_info = {
+	.info.func	= gpio_event_matrix_func,
+	.keymap		= keypad_keymap_surf,
+	.output_gpios	= keypad_row_gpios,
+	.input_gpios	= keypad_col_gpios,
+	.noutputs	= ARRAY_SIZE(keypad_row_gpios),
+	.ninputs	= ARRAY_SIZE(keypad_col_gpios),
+	.settle_time.tv64 = 40 * NSEC_PER_USEC,
+	.poll_time.tv64 = 20 * NSEC_PER_MSEC,
+	.flags		= GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE |
+			  GPIOKPF_PRINT_UNMAPPED_KEYS
+};
+
+static struct gpio_event_info *surf_keypad_info[] = {
+	&surf_keypad_matrix_info.info
+};
+
+static struct gpio_event_platform_data surf_keypad_data = {
+	.name		= "surf_keypad",
+	.info		= surf_keypad_info,
+	.info_count	= ARRAY_SIZE(surf_keypad_info)
+};
+
+struct platform_device keypad_device_surf = {
+	.name	= GPIO_EVENT_DEV_NAME,
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &surf_keypad_data,
+	},
+};
+
+/* 8k FFA keypad platform device information */
+static struct gpio_event_matrix_info keypad_matrix_info_8k_ffa = {
+	.info.func	= gpio_event_matrix_func,
+	.keymap		= keypad_keymap_8k_ffa,
+	.output_gpios	= keypad_row_gpios_8k_ffa,
+	.input_gpios	= keypad_col_gpios_8k_ffa,
+	.noutputs	= ARRAY_SIZE(keypad_row_gpios_8k_ffa),
+	.ninputs	= ARRAY_SIZE(keypad_col_gpios_8k_ffa),
+	.settle_time.tv64 = 40 * NSEC_PER_USEC,
+	.poll_time.tv64 = 20 * NSEC_PER_MSEC,
+	.flags		= GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE |
+			  GPIOKPF_PRINT_UNMAPPED_KEYS
+};
+
+static struct gpio_event_info *keypad_info_8k_ffa[] = {
+	&keypad_matrix_info_8k_ffa.info
+};
+
+static struct gpio_event_platform_data keypad_data_8k_ffa = {
+	.name		= "8k_ffa_keypad",
+	.info		= keypad_info_8k_ffa,
+	.info_count	= ARRAY_SIZE(keypad_info_8k_ffa)
+};
+
+struct platform_device keypad_device_8k_ffa = {
+	.name	= GPIO_EVENT_DEV_NAME,
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &keypad_data_8k_ffa,
+	},
+};
+
+/* 7k FFA keypad platform device information */
+static struct gpio_event_matrix_info keypad_matrix_info_7k_ffa = {
+	.info.func	= gpio_event_matrix_func,
+	.keymap		= keypad_keymap_ffa,
+	.output_gpios	= keypad_row_gpios,
+	.input_gpios	= keypad_col_gpios,
+	.noutputs	= ARRAY_SIZE(keypad_row_gpios),
+	.ninputs	= ARRAY_SIZE(keypad_col_gpios),
+	.settle_time.tv64 = 40 * NSEC_PER_USEC,
+	.poll_time.tv64 = 20 * NSEC_PER_MSEC,
+	.flags		= GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE |
+			  GPIOKPF_PRINT_UNMAPPED_KEYS
+};
+
+static struct gpio_event_info *keypad_info_7k_ffa[] = {
+	&keypad_matrix_info_7k_ffa.info
+};
+
+static struct gpio_event_platform_data keypad_data_7k_ffa = {
+	.name		= "7k_ffa_keypad",
+	.info		= keypad_info_7k_ffa,
+	.info_count	= ARRAY_SIZE(keypad_info_7k_ffa)
+};
+
+struct platform_device keypad_device_7k_ffa = {
+	.name	= GPIO_EVENT_DEV_NAME,
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &keypad_data_7k_ffa,
+	},
+};
+
diff --git a/arch/arm/mach-msm/lpass-8660.c b/arch/arm/mach-msm/lpass-8660.c
new file mode 100644
index 0000000..1018360
--- /dev/null
+++ b/arch/arm/mach-msm/lpass-8660.c
@@ -0,0 +1,166 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/workqueue.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/stringify.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+
+#include <mach/irqs.h>
+#include <mach/scm.h>
+#include <mach/peripheral-loader.h>
+#include <mach/subsystem_restart.h>
+#include <mach/subsystem_notif.h>
+
+#include "smd_private.h"
+#include "modem_notifier.h"
+#include "ramdump.h"
+
+#define Q6SS_WDOG_ENABLE		0x28882024
+#define Q6SS_SOFT_INTR_WAKEUP		0x288A001C
+#define MODULE_NAME			"lpass_8x60"
+#define SCM_Q6_NMI_CMD			0x1
+
+/* Subsystem restart: QDSP6 data, functions */
+static void *q6_ramdump_dev;
+static void q6_fatal_fn(struct work_struct *);
+static DECLARE_WORK(q6_fatal_work, q6_fatal_fn);
+static void __iomem *q6_wakeup_intr;
+
+static void q6_fatal_fn(struct work_struct *work)
+{
+	pr_err("%s: Watchdog bite received from Q6!\n", MODULE_NAME);
+	subsystem_restart("lpass");
+	enable_irq(LPASS_Q6SS_WDOG_EXPIRED);
+}
+
+static void send_q6_nmi(void)
+{
+	/* Send NMI to QDSP6 via an SCM call. */
+	scm_call_atomic1(SCM_SVC_UTIL, SCM_Q6_NMI_CMD, 0x1);
+
+	/* Wakeup the Q6 */
+	if (q6_wakeup_intr)
+		writel_relaxed(0x2000, q6_wakeup_intr);
+	else
+		pr_warn("lpass-8660: Unable to send wakeup interrupt to Q6.\n");
+
+	/* Q6 requires atleast 100ms to dump caches etc.*/
+	mdelay(100);
+
+	pr_info("subsystem-fatal-8x60: Q6 NMI was sent.\n");
+}
+
+int subsys_q6_shutdown(const struct subsys_data *crashed_subsys)
+{
+	void __iomem *q6_wdog_addr =
+		ioremap_nocache(Q6SS_WDOG_ENABLE, 8);
+
+	send_q6_nmi();
+	writel_relaxed(0x0, q6_wdog_addr);
+	/* The write needs to go through before the q6 is shutdown. */
+	mb();
+	iounmap(q6_wdog_addr);
+
+	pil_force_shutdown("q6");
+	disable_irq_nosync(LPASS_Q6SS_WDOG_EXPIRED);
+
+	return 0;
+}
+
+int subsys_q6_powerup(const struct subsys_data *crashed_subsys)
+{
+	int ret = pil_force_boot("q6");
+	enable_irq(LPASS_Q6SS_WDOG_EXPIRED);
+	return ret;
+}
+
+/* FIXME: Get address, size from PIL */
+static struct ramdump_segment q6_segments[] = { {0x46700000, 0x47F00000 -
+					0x46700000}, {0x28400000, 0x12800} };
+static int subsys_q6_ramdump(int enable,
+				const struct subsys_data *crashed_subsys)
+{
+	if (enable)
+		return do_ramdump(q6_ramdump_dev, q6_segments,
+				ARRAY_SIZE(q6_segments));
+	else
+		return 0;
+}
+
+void subsys_q6_crash_shutdown(const struct subsys_data *crashed_subsys)
+{
+	send_q6_nmi();
+}
+
+static irqreturn_t lpass_wdog_bite_irq(int irq, void *dev_id)
+{
+	int ret;
+
+	ret = schedule_work(&q6_fatal_work);
+	disable_irq_nosync(LPASS_Q6SS_WDOG_EXPIRED);
+
+	return IRQ_HANDLED;
+}
+
+static struct subsys_data subsys_8x60_q6 = {
+	.name = "lpass",
+	.shutdown = subsys_q6_shutdown,
+	.powerup = subsys_q6_powerup,
+	.ramdump = subsys_q6_ramdump,
+	.crash_shutdown = subsys_q6_crash_shutdown
+};
+
+static void __exit lpass_fatal_exit(void)
+{
+	iounmap(q6_wakeup_intr);
+	free_irq(LPASS_Q6SS_WDOG_EXPIRED, NULL);
+}
+
+static int __init lpass_fatal_init(void)
+{
+	int ret;
+
+	ret = request_irq(LPASS_Q6SS_WDOG_EXPIRED, lpass_wdog_bite_irq,
+			IRQF_TRIGGER_RISING, "q6_wdog", NULL);
+
+	if (ret < 0) {
+		pr_err("%s: Unable to request LPASS_Q6SS_WDOG_EXPIRED irq.",
+			__func__);
+		goto out;
+	}
+
+	q6_ramdump_dev = create_ramdump_device("lpass");
+
+	if (!q6_ramdump_dev) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	q6_wakeup_intr = ioremap_nocache(Q6SS_SOFT_INTR_WAKEUP, 8);
+
+	if (!q6_wakeup_intr)
+		pr_warn("lpass-8660: Unable to ioremap q6 wakeup address.");
+
+	ret = ssr_register_subsystem(&subsys_8x60_q6);
+out:
+	return ret;
+}
+
+module_init(lpass_fatal_init);
+module_exit(lpass_fatal_exit);
+
diff --git a/arch/arm/mach-msm/lpass-8960.c b/arch/arm/mach-msm/lpass-8960.c
new file mode 100644
index 0000000..c58b0e1
--- /dev/null
+++ b/arch/arm/mach-msm/lpass-8960.c
@@ -0,0 +1,284 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/workqueue.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/err.h>
+
+#include <mach/irqs.h>
+#include <mach/scm.h>
+#include <mach/peripheral-loader.h>
+#include <mach/subsystem_restart.h>
+#include <mach/subsystem_notif.h>
+
+#include "smd_private.h"
+#include "ramdump.h"
+#include "sysmon.h"
+
+#define SCM_Q6_NMI_CMD                  0x1
+#define MODULE_NAME			"lpass_8960"
+#define MAX_BUF_SIZE			0x51
+
+/* Subsystem restart: QDSP6 data, functions */
+static void lpass_fatal_fn(struct work_struct *);
+static DECLARE_WORK(lpass_fatal_work, lpass_fatal_fn);
+struct lpass_ssr {
+	void *lpass_ramdump_dev;
+} lpass_ssr;
+
+static struct lpass_ssr lpass_ssr_8960;
+static int q6_crash_shutdown;
+
+static int riva_notifier_cb(struct notifier_block *this, unsigned long code,
+								void *ss_handle)
+{
+	int ret;
+	switch (code) {
+	case SUBSYS_BEFORE_SHUTDOWN:
+		pr_debug("%s: R-Notify: Shutdown started\n", __func__);
+		ret = sysmon_send_event(SYSMON_SS_LPASS, "wcnss",
+				SUBSYS_BEFORE_SHUTDOWN);
+		if (ret < 0)
+			pr_err("%s: sysmon_send_event error %d", __func__,
+				ret);
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+static void *ssr_notif_hdle;
+static struct notifier_block rnb = {
+	.notifier_call = riva_notifier_cb,
+};
+
+static int modem_notifier_cb(struct notifier_block *this, unsigned long code,
+								void *ss_handle)
+{
+	int ret;
+	switch (code) {
+	case SUBSYS_BEFORE_SHUTDOWN:
+		pr_debug("%s: M-Notify: Shutdown started\n", __func__);
+		ret = sysmon_send_event(SYSMON_SS_LPASS, "modem",
+				SUBSYS_BEFORE_SHUTDOWN);
+		if (ret < 0)
+			pr_err("%s: sysmon_send_event error %d", __func__,
+				ret);
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+static void *ssr_modem_notif_hdle;
+static struct notifier_block mnb = {
+	.notifier_call = modem_notifier_cb,
+};
+
+static void lpass_log_failure_reason(void)
+{
+	char *reason;
+	char buffer[MAX_BUF_SIZE];
+	unsigned size;
+
+	reason = smem_get_entry(SMEM_SSR_REASON_LPASS0, &size);
+
+	if (!reason) {
+		pr_err("%s: subsystem failure reason: (unknown, smem_get_entry failed).",
+			 MODULE_NAME);
+		return;
+	}
+
+	if (reason[0] == '\0') {
+		pr_err("%s: subsystem failure reason: (unknown, init value found)",
+			 MODULE_NAME);
+		return;
+	}
+
+	size = size < MAX_BUF_SIZE ? size : (MAX_BUF_SIZE-1);
+	memcpy(buffer, reason, size);
+	buffer[size] = '\0';
+	pr_err("%s: subsystem failure reason: %s", MODULE_NAME, buffer);
+	memset((void *)reason, 0x0, size);
+	wmb();
+}
+
+static void lpass_fatal_fn(struct work_struct *work)
+{
+	pr_err("%s %s: Watchdog bite received from Q6!\n", MODULE_NAME,
+		__func__);
+	lpass_log_failure_reason();
+	panic(MODULE_NAME ": Resetting the SoC");
+}
+
+static void lpass_smsm_state_cb(void *data, uint32_t old_state,
+				uint32_t new_state)
+{
+	/* Ignore if we're the one that set SMSM_RESET */
+	if (q6_crash_shutdown)
+		return;
+
+	if (new_state & SMSM_RESET) {
+		pr_err("%s: LPASS SMSM state changed to SMSM_RESET,"
+			" new_state = 0x%x, old_state = 0x%x\n", __func__,
+			new_state, old_state);
+		lpass_log_failure_reason();
+		panic(MODULE_NAME ": Resetting the SoC");
+	}
+}
+
+static void send_q6_nmi(void)
+{
+	/* Send NMI to QDSP6 via an SCM call. */
+	uint32_t cmd = 0x1;
+
+	scm_call(SCM_SVC_UTIL, SCM_Q6_NMI_CMD,
+	&cmd, sizeof(cmd), NULL, 0);
+
+	/* Q6 requires worstcase 100ms to dump caches etc.*/
+	mdelay(100);
+	pr_debug("%s: Q6 NMI was sent.\n", __func__);
+}
+
+static int lpass_shutdown(const struct subsys_data *subsys)
+{
+	send_q6_nmi();
+	pil_force_shutdown("q6");
+	disable_irq_nosync(LPASS_Q6SS_WDOG_EXPIRED);
+
+	return 0;
+}
+
+static int lpass_powerup(const struct subsys_data *subsys)
+{
+	int ret = pil_force_boot("q6");
+	enable_irq(LPASS_Q6SS_WDOG_EXPIRED);
+	return ret;
+}
+/* RAM segments - address and size for 8960 */
+static struct ramdump_segment q6_segments[] = { {0x8da00000, 0x8f200000 -
+					0x8da00000}, {0x28400000, 0x20000} };
+static int lpass_ramdump(int enable, const struct subsys_data *subsys)
+{
+	pr_debug("%s: enable[%d]\n", __func__, enable);
+	if (enable)
+		return do_ramdump(lpass_ssr_8960.lpass_ramdump_dev,
+				q6_segments,
+				ARRAY_SIZE(q6_segments));
+	else
+		return 0;
+}
+
+static void lpass_crash_shutdown(const struct subsys_data *subsys)
+{
+	q6_crash_shutdown = 1;
+	send_q6_nmi();
+}
+
+static irqreturn_t lpass_wdog_bite_irq(int irq, void *dev_id)
+{
+	int ret;
+
+	pr_debug("%s: rxed irq[0x%x]", __func__, irq);
+	disable_irq_nosync(LPASS_Q6SS_WDOG_EXPIRED);
+	ret = schedule_work(&lpass_fatal_work);
+
+	return IRQ_HANDLED;
+}
+
+static struct subsys_data lpass_8960 = {
+	.name = "lpass",
+	.shutdown = lpass_shutdown,
+	.powerup = lpass_powerup,
+	.ramdump = lpass_ramdump,
+	.crash_shutdown = lpass_crash_shutdown
+};
+
+static int __init lpass_restart_init(void)
+{
+	return ssr_register_subsystem(&lpass_8960);
+}
+
+static int __init lpass_fatal_init(void)
+{
+	int ret;
+
+	ret = smsm_state_cb_register(SMSM_Q6_STATE, SMSM_RESET,
+		lpass_smsm_state_cb, 0);
+
+	if (ret < 0)
+		pr_err("%s: Unable to register SMSM callback! (%d)\n",
+				__func__, ret);
+
+	ret = request_irq(LPASS_Q6SS_WDOG_EXPIRED, lpass_wdog_bite_irq,
+			IRQF_TRIGGER_RISING, "q6_wdog", NULL);
+
+	if (ret < 0) {
+		pr_err("%s: Unable to request LPASS_Q6SS_WDOG_EXPIRED irq.",
+			__func__);
+		goto out;
+	}
+	ret = lpass_restart_init();
+	if (ret < 0) {
+		pr_err("%s: Unable to reg with lpass ssr. (%d)\n",
+				__func__, ret);
+		goto out;
+	}
+
+	lpass_ssr_8960.lpass_ramdump_dev = create_ramdump_device("lpass");
+
+	if (!lpass_ssr_8960.lpass_ramdump_dev) {
+		pr_err("%s: Unable to create ramdump device.\n",
+				__func__);
+		ret = -ENOMEM;
+		goto out;
+	}
+	ssr_notif_hdle = subsys_notif_register_notifier("riva",
+							&rnb);
+	if (IS_ERR(ssr_notif_hdle) < 0) {
+		ret = PTR_ERR(ssr_notif_hdle);
+		pr_err("%s: subsys_register_notifier for Riva: err = %d\n",
+			__func__, ret);
+		free_irq(LPASS_Q6SS_WDOG_EXPIRED, NULL);
+		goto out;
+	}
+
+	ssr_modem_notif_hdle = subsys_notif_register_notifier("modem",
+							&mnb);
+	if (IS_ERR(ssr_modem_notif_hdle) < 0) {
+		ret = PTR_ERR(ssr_modem_notif_hdle);
+		pr_err("%s: subsys_register_notifier for Modem: err = %d\n",
+			__func__, ret);
+		subsys_notif_unregister_notifier(ssr_notif_hdle, &rnb);
+		free_irq(LPASS_Q6SS_WDOG_EXPIRED, NULL);
+		goto out;
+	}
+
+	pr_info("%s: lpass SSR driver init'ed.\n", __func__);
+out:
+	return ret;
+}
+
+static void __exit lpass_fatal_exit(void)
+{
+	subsys_notif_unregister_notifier(ssr_notif_hdle, &rnb);
+	subsys_notif_unregister_notifier(ssr_modem_notif_hdle, &mnb);
+	free_irq(LPASS_Q6SS_WDOG_EXPIRED, NULL);
+}
+
+module_init(lpass_fatal_init);
+module_exit(lpass_fatal_exit);
+
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
new file mode 100644
index 0000000..80b82cb
--- /dev/null
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -0,0 +1,243 @@
+/* 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <mach/mpm.h>
+#include "rpm_resources.h"
+#include "pm.h"
+
+static struct msm_rpmrs_level *msm_lpm_levels;
+static int msm_lpm_level_count;
+
+static int msm_lpm_enter_sleep(uint32_t sclk_count, void *limits,
+		bool from_idle, bool notify_rpm)
+{
+	/* TODO */
+	return 0;
+}
+
+static void msm_lpm_exit_sleep(void *limits, bool from_idle,
+		bool notify_rpm, bool collapsed)
+{
+	/* TODO */
+	return;
+}
+
+static bool msm_rpmrs_irqs_detectable(struct msm_rpmrs_limits *limits,
+		bool irqs_detect, bool gpio_detect)
+{
+	/* TODO */
+	return true;
+}
+
+void msm_rpmrs_show_resources(void)
+{
+	/* TODO */
+	return;
+}
+
+static void *msm_lpm_lowest_limits(bool from_idle,
+		enum msm_pm_sleep_mode sleep_mode, uint32_t latency_us,
+		uint32_t sleep_us, uint32_t *power)
+{
+	unsigned int cpu = smp_processor_id();
+	struct msm_rpmrs_level *best_level = NULL;
+	bool irqs_detectable = false;
+	bool gpio_detectable = false;
+	uint32_t pwr;
+	int i;
+
+	if (!msm_lpm_levels)
+		return NULL;
+
+	if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) {
+		irqs_detectable = msm_mpm_irqs_detectable(from_idle);
+		gpio_detectable = msm_mpm_gpio_irqs_detectable(from_idle);
+	}
+
+	for (i = 0; i < msm_lpm_level_count; i++) {
+		struct msm_rpmrs_level *level = &msm_lpm_levels[i];
+
+		if (!level->available)
+			continue;
+
+		if (sleep_mode != level->sleep_mode)
+			continue;
+
+		if (latency_us < level->latency_us)
+			continue;
+
+		if (!msm_rpmrs_irqs_detectable(&level->rs_limits,
+					irqs_detectable, gpio_detectable))
+			continue;
+
+		if (sleep_us <= 1) {
+			pwr = level->energy_overhead;
+		} else if (sleep_us <= level->time_overhead_us) {
+			pwr = level->energy_overhead / sleep_us;
+		} else if ((sleep_us >> 10) > level->time_overhead_us) {
+			pwr = level->steady_state_power;
+		} else {
+			pwr = level->steady_state_power;
+			pwr -= (level->time_overhead_us *
+					level->steady_state_power)/sleep_us;
+			pwr += level->energy_overhead / sleep_us;
+		}
+
+		if (!best_level || best_level->rs_limits.power[cpu] >= pwr) {
+
+			level->rs_limits.latency_us[cpu] = level->latency_us;
+			level->rs_limits.power[cpu] = pwr;
+			best_level = level;
+
+			if (power)
+				*power = pwr;
+		}
+	}
+
+	return best_level ? &best_level->rs_limits : NULL;
+}
+static struct msm_pm_sleep_ops msm_lpm_ops = {
+	.lowest_limits = msm_lpm_lowest_limits,
+	.enter_sleep = msm_lpm_enter_sleep,
+	.exit_sleep = msm_lpm_exit_sleep,
+};
+
+static int __devinit msm_lpm_levels_probe(struct platform_device *pdev)
+{
+	struct msm_rpmrs_level *levels = NULL;
+	struct msm_rpmrs_level *level = NULL;
+	struct device_node *node = NULL;
+	char *key = NULL;
+	uint32_t val = 0;
+	int ret = 0;
+	uint32_t num_levels = 0;
+	int idx = 0;
+
+	for_each_child_of_node(pdev->dev.of_node, node)
+		num_levels++;
+
+	levels = kzalloc(num_levels * sizeof(struct msm_rpmrs_level),
+			GFP_KERNEL);
+	if (!levels)
+		return -ENOMEM;
+
+	for_each_child_of_node(pdev->dev.of_node, node) {
+		level = &levels[idx++];
+		level->available = false;
+
+		key = "qcom,mode";
+		ret = of_property_read_u32(node, key, &val);
+		if (ret)
+			goto fail;
+		level->sleep_mode = val;
+
+		key = "qcom,xo";
+		ret = of_property_read_u32(node, key, &val);
+		if (ret)
+			goto fail;
+		level->rs_limits.pxo = val;
+
+		key = "qcom,l2";
+		ret = of_property_read_u32(node, key, &val);
+		if (ret)
+			goto fail;
+		level->rs_limits.l2_cache = val;
+
+		key = "qcom,vdd-dig-upper-bound";
+		ret = of_property_read_u32(node, key, &val);
+		if (ret)
+			goto fail;
+		level->rs_limits.vdd_dig_upper_bound = val;
+
+		key = "qcom,vdd-dig-lower-bound";
+		ret = of_property_read_u32(node, key, &val);
+		if (ret)
+			goto fail;
+		level->rs_limits.vdd_dig = val;
+
+		key = "qcom,vdd-mem-upper-bound";
+		ret = of_property_read_u32(node, key, &val);
+		if (ret)
+			goto fail;
+		level->rs_limits.vdd_mem_upper_bound = val;
+
+		key = "qcom,vdd-mem-lower-bound";
+		ret = of_property_read_u32(node, key, &val);
+		if (ret)
+			goto fail;
+		level->rs_limits.vdd_mem = val;
+
+		key = "qcom,latency-us";
+		ret = of_property_read_u32(node, key, &val);
+		if (ret)
+			goto fail;
+		level->latency_us = val;
+
+		key = "qcom,ss-power";
+		ret = of_property_read_u32(node, key, &val);
+		if (ret)
+			goto fail;
+		level->steady_state_power = val;
+
+		key = "qcom,energy-overhead";
+		ret = of_property_read_u32(node, key, &val);
+		if (ret)
+			goto fail;
+		level->energy_overhead = val;
+
+		key = "qcom,time-overhead";
+		ret = of_property_read_u32(node, key, &val);
+		if (ret)
+			goto fail;
+		level->time_overhead_us = val;
+
+		level->available = true;
+	}
+
+	msm_lpm_levels = levels;
+	msm_lpm_level_count = idx;
+
+	msm_pm_set_sleep_ops(&msm_lpm_ops);
+
+	return 0;
+fail:
+	pr_err("%s: Error in name %s key %s\n", __func__, node->full_name, key);
+	kfree(levels);
+	return -EFAULT;
+}
+
+static struct of_device_id msm_lpm_levels_match_table[] = {
+	{.compatible = "qcom,lpm-levels"},
+	{},
+};
+
+static struct platform_driver msm_lpm_levels_driver = {
+	.probe = msm_lpm_levels_probe,
+	.driver = {
+		.name = "lpm-levels",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_lpm_levels_match_table,
+	},
+};
+
+static int __init msm_lpm_levels_module_init(void)
+{
+	return platform_driver_register(&msm_lpm_levels_driver);
+}
+late_initcall(msm_lpm_levels_module_init);
diff --git a/arch/arm/mach-msm/mdm.c b/arch/arm/mach-msm/mdm.c
new file mode 100644
index 0000000..cbdc92a
--- /dev/null
+++ b/arch/arm/mach-msm/mdm.c
@@ -0,0 +1,483 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/gpio.h>
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+#include <linux/reboot.h>
+#include <linux/debugfs.h>
+#include <linux/completion.h>
+#include <linux/workqueue.h>
+#include <linux/clk.h>
+#include <asm/mach-types.h>
+#include <asm/uaccess.h>
+#include <linux/mfd/pm8xxx/misc.h>
+#include <mach/mdm.h>
+#include <mach/restart.h>
+#include <mach/subsystem_notif.h>
+#include <mach/subsystem_restart.h>
+#include <linux/msm_charm.h>
+#include "msm_watchdog.h"
+#include "devices.h"
+#include "clock.h"
+
+#define CHARM_MODEM_TIMEOUT	6000
+#define CHARM_HOLD_TIME		4000
+#define CHARM_MODEM_DELTA	100
+
+static void (*power_on_charm)(void);
+static void (*power_down_charm)(void);
+
+static int charm_debug_on;
+static int charm_status_irq;
+static int charm_errfatal_irq;
+static int charm_ready;
+static enum charm_boot_type boot_type = CHARM_NORMAL_BOOT;
+static int charm_boot_status;
+static int charm_ram_dump_status;
+static struct workqueue_struct *charm_queue;
+
+#define CHARM_DBG(...)	do { if (charm_debug_on) \
+					pr_info(__VA_ARGS__); \
+			} while (0);
+
+
+DECLARE_COMPLETION(charm_needs_reload);
+DECLARE_COMPLETION(charm_boot);
+DECLARE_COMPLETION(charm_ram_dumps);
+
+static void charm_disable_irqs(void)
+{
+	disable_irq_nosync(charm_errfatal_irq);
+	disable_irq_nosync(charm_status_irq);
+
+}
+
+static int charm_subsys_shutdown(const struct subsys_data *crashed_subsys)
+{
+	charm_ready = 0;
+	power_down_charm();
+	return 0;
+}
+
+static int charm_subsys_powerup(const struct subsys_data *crashed_subsys)
+{
+	power_on_charm();
+	boot_type = CHARM_NORMAL_BOOT;
+	complete(&charm_needs_reload);
+	wait_for_completion(&charm_boot);
+	pr_info("%s: charm modem has been restarted\n", __func__);
+	INIT_COMPLETION(charm_boot);
+	return charm_boot_status;
+}
+
+static int charm_subsys_ramdumps(int want_dumps,
+				const struct subsys_data *crashed_subsys)
+{
+	charm_ram_dump_status = 0;
+	if (want_dumps) {
+		boot_type = CHARM_RAM_DUMPS;
+		complete(&charm_needs_reload);
+		wait_for_completion(&charm_ram_dumps);
+		INIT_COMPLETION(charm_ram_dumps);
+		power_down_charm();
+	}
+	return charm_ram_dump_status;
+}
+
+static struct subsys_data charm_subsystem = {
+	.shutdown = charm_subsys_shutdown,
+	.ramdump = charm_subsys_ramdumps,
+	.powerup = charm_subsys_powerup,
+	.name = "external_modem",
+};
+
+static int charm_panic_prep(struct notifier_block *this,
+				unsigned long event, void *ptr)
+{
+	int i;
+
+	CHARM_DBG("%s: setting AP2MDM_ERRFATAL high for a non graceful reset\n",
+			 __func__);
+	if (get_restart_level() == RESET_SOC)
+		pm8xxx_stay_on();
+
+	charm_disable_irqs();
+	gpio_set_value(AP2MDM_ERRFATAL, 1);
+	gpio_set_value(AP2MDM_WAKEUP, 1);
+	for (i = CHARM_MODEM_TIMEOUT; i > 0; i -= CHARM_MODEM_DELTA) {
+		pet_watchdog();
+		mdelay(CHARM_MODEM_DELTA);
+		if (gpio_get_value(MDM2AP_STATUS) == 0)
+			break;
+	}
+	if (i <= 0)
+		pr_err("%s: MDM2AP_STATUS never went low\n", __func__);
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block charm_panic_blk = {
+	.notifier_call  = charm_panic_prep,
+};
+
+static int first_boot = 1;
+
+static long charm_modem_ioctl(struct file *filp, unsigned int cmd,
+				unsigned long arg)
+{
+
+	int status, ret = 0;
+
+	if (_IOC_TYPE(cmd) != CHARM_CODE) {
+		pr_err("%s: invalid ioctl code\n", __func__);
+		return -EINVAL;
+	}
+
+	CHARM_DBG("%s: Entering ioctl cmd = %d\n", __func__, _IOC_NR(cmd));
+	switch (cmd) {
+	case WAKE_CHARM:
+		CHARM_DBG("%s: Powering on\n", __func__);
+		power_on_charm();
+		break;
+	case CHECK_FOR_BOOT:
+		if (gpio_get_value(MDM2AP_STATUS) == 0)
+			put_user(1, (unsigned long __user *) arg);
+		else
+			put_user(0, (unsigned long __user *) arg);
+		break;
+	case NORMAL_BOOT_DONE:
+		CHARM_DBG("%s: check if charm is booted up\n", __func__);
+		get_user(status, (unsigned long __user *) arg);
+		if (status)
+			charm_boot_status = -EIO;
+		else
+			charm_boot_status = 0;
+		charm_ready = 1;
+
+		gpio_set_value(AP2MDM_KPDPWR_N, 0);
+		if (!first_boot)
+			complete(&charm_boot);
+		else
+			first_boot = 0;
+		break;
+	case RAM_DUMP_DONE:
+		CHARM_DBG("%s: charm done collecting RAM dumps\n", __func__);
+		get_user(status, (unsigned long __user *) arg);
+		if (status)
+			charm_ram_dump_status = -EIO;
+		else
+			charm_ram_dump_status = 0;
+		complete(&charm_ram_dumps);
+		break;
+	case WAIT_FOR_RESTART:
+		CHARM_DBG("%s: wait for charm to need images reloaded\n",
+				__func__);
+		ret = wait_for_completion_interruptible(&charm_needs_reload);
+		if (!ret)
+			put_user(boot_type, (unsigned long __user *) arg);
+		INIT_COMPLETION(charm_needs_reload);
+		break;
+	default:
+		pr_err("%s: invalid ioctl cmd = %d\n", __func__, _IOC_NR(cmd));
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int charm_modem_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static const struct file_operations charm_modem_fops = {
+	.owner		= THIS_MODULE,
+	.open		= charm_modem_open,
+	.unlocked_ioctl	= charm_modem_ioctl,
+};
+
+
+struct miscdevice charm_modem_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "mdm",
+	.fops	= &charm_modem_fops
+};
+
+
+
+static void charm_status_fn(struct work_struct *work)
+{
+	pr_info("Reseting the charm because status changed\n");
+	subsystem_restart("external_modem");
+}
+
+static DECLARE_WORK(charm_status_work, charm_status_fn);
+
+static void charm_fatal_fn(struct work_struct *work)
+{
+	pr_info("Reseting the charm due to an errfatal\n");
+	if (get_restart_level() == RESET_SOC)
+		pm8xxx_stay_on();
+	subsystem_restart("external_modem");
+}
+
+static DECLARE_WORK(charm_fatal_work, charm_fatal_fn);
+
+static irqreturn_t charm_errfatal(int irq, void *dev_id)
+{
+	CHARM_DBG("%s: charm got errfatal interrupt\n", __func__);
+	if (charm_ready && (gpio_get_value(MDM2AP_STATUS) == 1)) {
+		CHARM_DBG("%s: scheduling work now\n", __func__);
+		queue_work(charm_queue, &charm_fatal_work);
+	}
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t charm_status_change(int irq, void *dev_id)
+{
+	CHARM_DBG("%s: charm sent status change interrupt\n", __func__);
+	if ((gpio_get_value(MDM2AP_STATUS) == 0) && charm_ready) {
+		CHARM_DBG("%s: scheduling work now\n", __func__);
+		queue_work(charm_queue, &charm_status_work);
+	} else if (gpio_get_value(MDM2AP_STATUS) == 1) {
+		CHARM_DBG("%s: charm is now ready\n", __func__);
+	}
+	return IRQ_HANDLED;
+}
+
+static int charm_debug_on_set(void *data, u64 val)
+{
+	charm_debug_on = val;
+	return 0;
+}
+
+static int charm_debug_on_get(void *data, u64 *val)
+{
+	*val = charm_debug_on;
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(charm_debug_on_fops,
+			charm_debug_on_get,
+			charm_debug_on_set, "%llu\n");
+
+static int charm_debugfs_init(void)
+{
+	struct dentry *dent;
+
+	dent = debugfs_create_dir("charm_dbg", 0);
+	if (IS_ERR(dent))
+		return PTR_ERR(dent);
+
+	debugfs_create_file("debug_on", 0644, dent, NULL,
+			&charm_debug_on_fops);
+	return 0;
+}
+
+static int gsbi9_uart_notifier_cb(struct notifier_block *this,
+					unsigned long code, void *_cmd)
+{
+	switch (code) {
+	case SUBSYS_AFTER_SHUTDOWN:
+		platform_device_unregister(msm_device_uart_gsbi9);
+		msm_device_uart_gsbi9 = msm_add_gsbi9_uart();
+		if (IS_ERR(msm_device_uart_gsbi9))
+			pr_err("%s(): Failed to create uart gsbi9 device\n",
+								__func__);
+	default:
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block gsbi9_nb = {
+	.notifier_call = gsbi9_uart_notifier_cb,
+};
+
+static int __init charm_modem_probe(struct platform_device *pdev)
+{
+	int ret, irq;
+	struct charm_platform_data *d = pdev->dev.platform_data;
+
+	gpio_request(AP2MDM_STATUS, "AP2MDM_STATUS");
+	gpio_request(AP2MDM_ERRFATAL, "AP2MDM_ERRFATAL");
+	gpio_request(AP2MDM_KPDPWR_N, "AP2MDM_KPDPWR_N");
+	gpio_request(AP2MDM_PMIC_RESET_N, "AP2MDM_PMIC_RESET_N");
+	gpio_request(MDM2AP_STATUS, "MDM2AP_STATUS");
+	gpio_request(MDM2AP_ERRFATAL, "MDM2AP_ERRFATAL");
+	gpio_request(AP2MDM_WAKEUP, "AP2MDM_WAKEUP");
+
+	gpio_direction_output(AP2MDM_STATUS, 1);
+	gpio_direction_output(AP2MDM_ERRFATAL, 0);
+	gpio_direction_output(AP2MDM_WAKEUP, 0);
+	gpio_direction_input(MDM2AP_STATUS);
+	gpio_direction_input(MDM2AP_ERRFATAL);
+
+	power_on_charm = d->charm_modem_on;
+	power_down_charm = d->charm_modem_off;
+
+	charm_queue = create_singlethread_workqueue("charm_queue");
+	if (!charm_queue) {
+		pr_err("%s: could not create workqueue. All charm \
+				functionality will be disabled\n",
+			__func__);
+		ret = -ENOMEM;
+		goto fatal_err;
+	}
+
+	atomic_notifier_chain_register(&panic_notifier_list, &charm_panic_blk);
+	charm_debugfs_init();
+
+	ssr_register_subsystem(&charm_subsystem);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		pr_err("%s: could not get MDM2AP_ERRFATAL IRQ resource. \
+			error=%d No IRQ will be generated on errfatal.",
+			__func__, irq);
+		goto errfatal_err;
+	}
+
+	ret = request_irq(irq, charm_errfatal,
+		IRQF_TRIGGER_RISING , "charm errfatal", NULL);
+
+	if (ret < 0) {
+		pr_err("%s: MDM2AP_ERRFATAL IRQ#%d request failed with error=%d\
+			. No IRQ will be generated on errfatal.",
+			__func__, irq, ret);
+		goto errfatal_err;
+	}
+	charm_errfatal_irq = irq;
+
+errfatal_err:
+
+	irq = platform_get_irq(pdev, 1);
+	if (irq < 0) {
+		pr_err("%s: could not get MDM2AP_STATUS IRQ resource. \
+			error=%d No IRQ will be generated on status change.",
+			__func__, irq);
+		goto status_err;
+	}
+
+	ret = request_threaded_irq(irq, NULL, charm_status_change,
+		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+		"charm status", NULL);
+
+	if (ret < 0) {
+		pr_err("%s: MDM2AP_STATUS IRQ#%d request failed with error=%d\
+			. No IRQ will be generated on status change.",
+			__func__, irq, ret);
+		goto status_err;
+	}
+	charm_status_irq = irq;
+
+status_err:
+	subsys_notif_register_notifier("external_modem", &gsbi9_nb);
+
+	pr_info("%s: Registering charm modem\n", __func__);
+
+	return misc_register(&charm_modem_misc);
+
+fatal_err:
+	gpio_free(AP2MDM_STATUS);
+	gpio_free(AP2MDM_ERRFATAL);
+	gpio_free(AP2MDM_KPDPWR_N);
+	gpio_free(AP2MDM_PMIC_RESET_N);
+	gpio_free(MDM2AP_STATUS);
+	gpio_free(MDM2AP_ERRFATAL);
+	return ret;
+
+}
+
+
+static int __devexit charm_modem_remove(struct platform_device *pdev)
+{
+	gpio_free(AP2MDM_STATUS);
+	gpio_free(AP2MDM_ERRFATAL);
+	gpio_free(AP2MDM_KPDPWR_N);
+	gpio_free(AP2MDM_PMIC_RESET_N);
+	gpio_free(MDM2AP_STATUS);
+	gpio_free(MDM2AP_ERRFATAL);
+
+	return misc_deregister(&charm_modem_misc);
+}
+
+static void charm_modem_shutdown(struct platform_device *pdev)
+{
+	int i;
+
+	CHARM_DBG("%s: setting AP2MDM_STATUS low for a graceful restart\n",
+		__func__);
+
+	charm_disable_irqs();
+
+	gpio_set_value(AP2MDM_STATUS, 0);
+	gpio_set_value(AP2MDM_WAKEUP, 1);
+
+	for (i = CHARM_MODEM_TIMEOUT; i > 0; i -= CHARM_MODEM_DELTA) {
+		pet_watchdog();
+		msleep(CHARM_MODEM_DELTA);
+		if (gpio_get_value(MDM2AP_STATUS) == 0)
+			break;
+	}
+
+	if (i <= 0) {
+		pr_err("%s: MDM2AP_STATUS never went low.\n",
+			 __func__);
+		gpio_direction_output(AP2MDM_PMIC_RESET_N, 1);
+		for (i = CHARM_HOLD_TIME; i > 0; i -= CHARM_MODEM_DELTA) {
+			pet_watchdog();
+			msleep(CHARM_MODEM_DELTA);
+		}
+		gpio_direction_output(AP2MDM_PMIC_RESET_N, 0);
+	}
+	gpio_set_value(AP2MDM_WAKEUP, 0);
+}
+
+static struct platform_driver charm_modem_driver = {
+	.remove         = charm_modem_remove,
+	.shutdown	= charm_modem_shutdown,
+	.driver         = {
+		.name = "charm_modem",
+		.owner = THIS_MODULE
+	},
+};
+
+static int __init charm_modem_init(void)
+{
+	return platform_driver_probe(&charm_modem_driver, charm_modem_probe);
+}
+
+static void __exit charm_modem_exit(void)
+{
+	platform_driver_unregister(&charm_modem_driver);
+}
+
+module_init(charm_modem_init);
+module_exit(charm_modem_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("msm8660 charm modem driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("charm_modem");
diff --git a/arch/arm/mach-msm/mdm2.c b/arch/arm/mach-msm/mdm2.c
new file mode 100644
index 0000000..bd7bd9e
--- /dev/null
+++ b/arch/arm/mach-msm/mdm2.c
@@ -0,0 +1,237 @@
+/* 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
+ * 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/gpio.h>
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+#include <linux/reboot.h>
+#include <linux/debugfs.h>
+#include <linux/completion.h>
+#include <linux/workqueue.h>
+#include <linux/clk.h>
+#include <linux/mfd/pmic8058.h>
+#include <asm/mach-types.h>
+#include <asm/uaccess.h>
+#include <mach/mdm2.h>
+#include <mach/restart.h>
+#include <mach/subsystem_notif.h>
+#include <mach/subsystem_restart.h>
+#include <linux/msm_charm.h>
+#include "msm_watchdog.h"
+#include "devices.h"
+#include "clock.h"
+#include "mdm_private.h"
+
+#define MDM_MODEM_TIMEOUT	6000
+#define MDM_HOLD_TIME		4000
+#define MDM_MODEM_DELTA		100
+
+static int mdm_debug_on;
+static int power_on_count;
+static int hsic_peripheral_status;
+static DEFINE_MUTEX(hsic_status_lock);
+
+static void mdm_peripheral_connect(struct mdm_modem_drv *mdm_drv)
+{
+	if (!mdm_drv->pdata->peripheral_platform_device)
+		return;
+
+	mutex_lock(&hsic_status_lock);
+	if (hsic_peripheral_status)
+		goto out;
+	platform_device_add(mdm_drv->pdata->peripheral_platform_device);
+	hsic_peripheral_status = 1;
+out:
+	mutex_unlock(&hsic_status_lock);
+}
+
+static void mdm_peripheral_disconnect(struct mdm_modem_drv *mdm_drv)
+{
+	if (!mdm_drv->pdata->peripheral_platform_device)
+		return;
+
+	mutex_lock(&hsic_status_lock);
+	if (!hsic_peripheral_status)
+		goto out;
+	platform_device_del(mdm_drv->pdata->peripheral_platform_device);
+	hsic_peripheral_status = 0;
+out:
+	mutex_unlock(&hsic_status_lock);
+}
+
+static void mdm_power_down_common(struct mdm_modem_drv *mdm_drv)
+{
+	int soft_reset_direction =
+		mdm_drv->pdata->soft_reset_inverted ? 1 : 0;
+
+	gpio_direction_output(mdm_drv->ap2mdm_soft_reset_gpio,
+				soft_reset_direction);
+	mdm_peripheral_disconnect(mdm_drv);
+}
+
+static void mdm_do_first_power_on(struct mdm_modem_drv *mdm_drv)
+{
+	int soft_reset_direction =
+		mdm_drv->pdata->soft_reset_inverted ? 0 : 1;
+
+	if (power_on_count != 1) {
+		pr_err("%s: Calling fn when power_on_count != 1\n",
+			   __func__);
+		return;
+	}
+
+	pr_err("%s: Powering on modem for the first time\n", __func__);
+	mdm_peripheral_disconnect(mdm_drv);
+
+	/* If the device has a kpd pwr gpio then toggle it. */
+	if (mdm_drv->ap2mdm_kpdpwr_n_gpio > 0) {
+		/* Pull AP2MDM_KPDPWR gpio high and wait for PS_HOLD to settle,
+		 * then	pull it back low.
+		 */
+		pr_debug("%s: Pulling AP2MDM_KPDPWR gpio high\n", __func__);
+		gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 1);
+		msleep(1000);
+		gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 0);
+	}
+
+	/* De-assert the soft reset line. */
+	pr_debug("%s: De-asserting soft reset gpio\n", __func__);
+	gpio_direction_output(mdm_drv->ap2mdm_soft_reset_gpio,
+						  soft_reset_direction);
+
+	mdm_peripheral_connect(mdm_drv);
+	msleep(200);
+}
+
+static void mdm_do_soft_power_on(struct mdm_modem_drv *mdm_drv)
+{
+	int soft_reset_direction =
+		mdm_drv->pdata->soft_reset_inverted ? 0 : 1;
+
+	/* De-assert the soft reset line. */
+	pr_err("%s: soft resetting mdm modem\n", __func__);
+
+	mdm_peripheral_disconnect(mdm_drv);
+
+	gpio_direction_output(mdm_drv->ap2mdm_soft_reset_gpio,
+		soft_reset_direction == 1 ? 0 : 1);
+	usleep_range(5000, 10000);
+	gpio_direction_output(mdm_drv->ap2mdm_soft_reset_gpio,
+		soft_reset_direction == 1 ? 1 : 0);
+
+	mdm_peripheral_connect(mdm_drv);
+	msleep(200);
+}
+
+static void mdm_power_on_common(struct mdm_modem_drv *mdm_drv)
+{
+	power_on_count++;
+
+	/* this gpio will be used to indicate apq readiness,
+	 * de-assert it now so that it can be asserted later.
+	 * May not be used.
+	 */
+	if (mdm_drv->ap2mdm_wakeup_gpio > 0)
+		gpio_direction_output(mdm_drv->ap2mdm_wakeup_gpio, 0);
+
+	/*
+	 * If we did an "early power on" then ignore the very next
+	 * power-on request because it would the be first request from
+	 * user space but we're already powered on. Ignore it.
+	 */
+	if (mdm_drv->pdata->early_power_on &&
+			(power_on_count == 2))
+		return;
+
+	if (power_on_count == 1)
+		mdm_do_first_power_on(mdm_drv);
+	else
+		mdm_do_soft_power_on(mdm_drv);
+}
+
+static void debug_state_changed(int value)
+{
+	mdm_debug_on = value;
+}
+
+static void mdm_status_changed(struct mdm_modem_drv *mdm_drv, int value)
+{
+	pr_debug("%s: value:%d\n", __func__, value);
+
+	if (value) {
+		mdm_peripheral_disconnect(mdm_drv);
+		mdm_peripheral_connect(mdm_drv);
+		if (mdm_drv->ap2mdm_wakeup_gpio > 0)
+			gpio_direction_output(mdm_drv->ap2mdm_wakeup_gpio, 1);
+	}
+}
+
+static struct mdm_ops mdm_cb = {
+	.power_on_mdm_cb = mdm_power_on_common,
+	.reset_mdm_cb = mdm_power_on_common,
+	.power_down_mdm_cb = mdm_power_down_common,
+	.debug_state_changed_cb = debug_state_changed,
+	.status_cb = mdm_status_changed,
+};
+
+static int __init mdm_modem_probe(struct platform_device *pdev)
+{
+	return mdm_common_create(pdev, &mdm_cb);
+}
+
+static int __devexit mdm_modem_remove(struct platform_device *pdev)
+{
+	return mdm_common_modem_remove(pdev);
+}
+
+static void mdm_modem_shutdown(struct platform_device *pdev)
+{
+	mdm_common_modem_shutdown(pdev);
+}
+
+static struct platform_driver mdm_modem_driver = {
+	.remove         = mdm_modem_remove,
+	.shutdown	= mdm_modem_shutdown,
+	.driver         = {
+		.name = "mdm2_modem",
+		.owner = THIS_MODULE
+	},
+};
+
+static int __init mdm_modem_init(void)
+{
+	return platform_driver_probe(&mdm_modem_driver, mdm_modem_probe);
+}
+
+static void __exit mdm_modem_exit(void)
+{
+	platform_driver_unregister(&mdm_modem_driver);
+}
+
+module_init(mdm_modem_init);
+module_exit(mdm_modem_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("mdm modem driver");
+MODULE_VERSION("2.0");
+MODULE_ALIAS("mdm_modem");
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
new file mode 100644
index 0000000..ffff782
--- /dev/null
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -0,0 +1,607 @@
+/* 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
+ * 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/gpio.h>
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+#include <linux/reboot.h>
+#include <linux/debugfs.h>
+#include <linux/completion.h>
+#include <linux/workqueue.h>
+#include <linux/clk.h>
+#include <linux/mfd/pmic8058.h>
+#include <asm/mach-types.h>
+#include <asm/uaccess.h>
+#include <mach/mdm2.h>
+#include <mach/restart.h>
+#include <mach/subsystem_notif.h>
+#include <mach/subsystem_restart.h>
+#include <linux/msm_charm.h>
+#include "msm_watchdog.h"
+#include "mdm_private.h"
+#include "sysmon.h"
+
+#define MDM_MODEM_TIMEOUT	6000
+#define MDM_MODEM_DELTA	100
+#define MDM_BOOT_TIMEOUT	60000L
+#define MDM_RDUMP_TIMEOUT	60000L
+
+static int mdm_debug_on;
+static struct workqueue_struct *mdm_queue;
+static struct workqueue_struct *mdm_sfr_queue;
+
+#define EXTERNAL_MODEM "external_modem"
+
+static struct mdm_modem_drv *mdm_drv;
+
+DECLARE_COMPLETION(mdm_needs_reload);
+DECLARE_COMPLETION(mdm_boot);
+DECLARE_COMPLETION(mdm_ram_dumps);
+
+static int first_boot = 1;
+
+#define RD_BUF_SIZE			100
+#define SFR_MAX_RETRIES		10
+#define SFR_RETRY_INTERVAL	1000
+
+static void mdm_restart_reason_fn(struct work_struct *work)
+{
+	int ret, ntries = 0;
+	char sfr_buf[RD_BUF_SIZE];
+
+	do {
+		msleep(SFR_RETRY_INTERVAL);
+		ret = sysmon_get_reason(SYSMON_SS_EXT_MODEM,
+					sfr_buf, sizeof(sfr_buf));
+		if (ret) {
+			/*
+			 * The sysmon device may not have been probed as yet
+			 * after the restart.
+			 */
+			pr_err("%s: Error retrieving mdm restart reason, ret = %d, "
+					"%d/%d tries\n", __func__, ret,
+					ntries + 1,	SFR_MAX_RETRIES);
+		} else {
+			pr_err("mdm restart reason: %s\n", sfr_buf);
+			break;
+		}
+	} while (++ntries < SFR_MAX_RETRIES);
+}
+
+static DECLARE_WORK(sfr_reason_work, mdm_restart_reason_fn);
+
+long mdm_modem_ioctl(struct file *filp, unsigned int cmd,
+				unsigned long arg)
+{
+	int status, ret = 0;
+
+	if (_IOC_TYPE(cmd) != CHARM_CODE) {
+		pr_err("%s: invalid ioctl code\n", __func__);
+		return -EINVAL;
+	}
+
+	pr_debug("%s: Entering ioctl cmd = %d\n", __func__, _IOC_NR(cmd));
+	switch (cmd) {
+	case WAKE_CHARM:
+		pr_info("%s: Powering on mdm\n", __func__);
+		mdm_drv->ops->power_on_mdm_cb(mdm_drv);
+		break;
+	case CHECK_FOR_BOOT:
+		if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
+			put_user(1, (unsigned long __user *) arg);
+		else
+			put_user(0, (unsigned long __user *) arg);
+		break;
+	case NORMAL_BOOT_DONE:
+		pr_debug("%s: check if mdm is booted up\n", __func__);
+		get_user(status, (unsigned long __user *) arg);
+		if (status) {
+			pr_debug("%s: normal boot failed\n", __func__);
+			mdm_drv->mdm_boot_status = -EIO;
+		} else {
+			pr_info("%s: normal boot done\n", __func__);
+			mdm_drv->mdm_boot_status = 0;
+		}
+		mdm_drv->mdm_ready = 1;
+
+		if (mdm_drv->ops->normal_boot_done_cb != NULL)
+			mdm_drv->ops->normal_boot_done_cb(mdm_drv);
+
+		if (!first_boot)
+			complete(&mdm_boot);
+		else
+			first_boot = 0;
+		break;
+	case RAM_DUMP_DONE:
+		pr_debug("%s: mdm done collecting RAM dumps\n", __func__);
+		get_user(status, (unsigned long __user *) arg);
+		if (status)
+			mdm_drv->mdm_ram_dump_status = -EIO;
+		else {
+			pr_info("%s: ramdump collection completed\n", __func__);
+			mdm_drv->mdm_ram_dump_status = 0;
+		}
+		complete(&mdm_ram_dumps);
+		break;
+	case WAIT_FOR_RESTART:
+		pr_debug("%s: wait for mdm to need images reloaded\n",
+				__func__);
+		ret = wait_for_completion_interruptible(&mdm_needs_reload);
+		if (!ret)
+			put_user(mdm_drv->boot_type,
+					 (unsigned long __user *) arg);
+		INIT_COMPLETION(mdm_needs_reload);
+		break;
+	case GET_DLOAD_STATUS:
+		pr_debug("getting status of mdm2ap_errfatal_gpio\n");
+		if (gpio_get_value(mdm_drv->mdm2ap_errfatal_gpio) == 1 &&
+			!mdm_drv->mdm_ready)
+			put_user(1, (unsigned long __user *) arg);
+		else
+			put_user(0, (unsigned long __user *) arg);
+		break;
+	default:
+		pr_err("%s: invalid ioctl cmd = %d\n", __func__, _IOC_NR(cmd));
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static void mdm_status_fn(struct work_struct *work)
+{
+	int value = gpio_get_value(mdm_drv->mdm2ap_status_gpio);
+
+	pr_debug("%s: status:%d\n", __func__, value);
+	if (mdm_drv->mdm_ready && mdm_drv->ops->status_cb)
+		mdm_drv->ops->status_cb(mdm_drv, value);
+}
+
+static DECLARE_WORK(mdm_status_work, mdm_status_fn);
+
+static void mdm_disable_irqs(void)
+{
+	disable_irq_nosync(mdm_drv->mdm_errfatal_irq);
+	disable_irq_nosync(mdm_drv->mdm_status_irq);
+}
+
+static irqreturn_t mdm_errfatal(int irq, void *dev_id)
+{
+	pr_debug("%s: mdm got errfatal interrupt\n", __func__);
+	if (mdm_drv->mdm_ready &&
+		(gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 1)) {
+		pr_info("%s: Reseting the mdm due to an errfatal\n", __func__);
+		mdm_drv->mdm_ready = 0;
+		subsystem_restart(EXTERNAL_MODEM);
+	}
+	return IRQ_HANDLED;
+}
+
+static int mdm_modem_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static const struct file_operations mdm_modem_fops = {
+	.owner		= THIS_MODULE,
+	.open		= mdm_modem_open,
+	.unlocked_ioctl	= mdm_modem_ioctl,
+};
+
+
+static struct miscdevice mdm_modem_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "mdm",
+	.fops	= &mdm_modem_fops
+};
+
+static int mdm_panic_prep(struct notifier_block *this,
+				unsigned long event, void *ptr)
+{
+	int i;
+
+	pr_debug("%s: setting AP2MDM_ERRFATAL high for a non graceful reset\n",
+			 __func__);
+	mdm_disable_irqs();
+	gpio_set_value(mdm_drv->ap2mdm_errfatal_gpio, 1);
+
+	for (i = MDM_MODEM_TIMEOUT; i > 0; i -= MDM_MODEM_DELTA) {
+		pet_watchdog();
+		mdelay(MDM_MODEM_DELTA);
+		if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
+			break;
+	}
+	if (i <= 0) {
+		pr_err("%s: MDM2AP_STATUS never went low\n", __func__);
+		/* Reset the modem so that it will go into download mode. */
+		if (mdm_drv && mdm_drv->ops->reset_mdm_cb)
+			mdm_drv->ops->reset_mdm_cb(mdm_drv);
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block mdm_panic_blk = {
+	.notifier_call  = mdm_panic_prep,
+};
+
+static irqreturn_t mdm_status_change(int irq, void *dev_id)
+{
+	int value = gpio_get_value(mdm_drv->mdm2ap_status_gpio);
+
+	pr_debug("%s: mdm sent status change interrupt\n", __func__);
+	if (value == 0 && mdm_drv->mdm_ready == 1) {
+		pr_info("%s: unexpected reset external modem\n", __func__);
+		mdm_drv->mdm_unexpected_reset_occurred = 1;
+		mdm_drv->mdm_ready = 0;
+		subsystem_restart(EXTERNAL_MODEM);
+	} else if (value == 1) {
+		pr_info("%s: status = 1: mdm is now ready\n", __func__);
+		queue_work(mdm_queue, &mdm_status_work);
+	}
+	return IRQ_HANDLED;
+}
+
+static int mdm_subsys_shutdown(const struct subsys_data *crashed_subsys)
+{
+	gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 1);
+	if (mdm_drv->pdata->ramdump_delay_ms > 0) {
+		/* Wait for the external modem to complete
+		 * its preparation for ramdumps.
+		 */
+		msleep(mdm_drv->pdata->ramdump_delay_ms);
+	}
+	if (!mdm_drv->mdm_unexpected_reset_occurred)
+		mdm_drv->ops->reset_mdm_cb(mdm_drv);
+	else
+		mdm_drv->mdm_unexpected_reset_occurred = 0;
+
+	return 0;
+}
+
+static int mdm_subsys_powerup(const struct subsys_data *crashed_subsys)
+{
+	gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 0);
+	gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 1);
+	mdm_drv->ops->power_on_mdm_cb(mdm_drv);
+	mdm_drv->boot_type = CHARM_NORMAL_BOOT;
+	complete(&mdm_needs_reload);
+	if (!wait_for_completion_timeout(&mdm_boot,
+			msecs_to_jiffies(MDM_BOOT_TIMEOUT))) {
+		mdm_drv->mdm_boot_status = -ETIMEDOUT;
+		pr_info("%s: mdm modem restart timed out.\n", __func__);
+	} else {
+		pr_info("%s: mdm modem has been restarted\n", __func__);
+
+		/* Log the reason for the restart */
+		if (mdm_drv->pdata->sfr_query)
+			queue_work(mdm_sfr_queue, &sfr_reason_work);
+	}
+	INIT_COMPLETION(mdm_boot);
+	return mdm_drv->mdm_boot_status;
+}
+
+static int mdm_subsys_ramdumps(int want_dumps,
+				const struct subsys_data *crashed_subsys)
+{
+	mdm_drv->mdm_ram_dump_status = 0;
+	if (want_dumps) {
+		mdm_drv->boot_type = CHARM_RAM_DUMPS;
+		complete(&mdm_needs_reload);
+		if (!wait_for_completion_timeout(&mdm_ram_dumps,
+				msecs_to_jiffies(MDM_RDUMP_TIMEOUT))) {
+			mdm_drv->mdm_ram_dump_status = -ETIMEDOUT;
+			pr_info("%s: mdm modem ramdumps timed out.\n",
+					__func__);
+		} else
+			pr_info("%s: mdm modem ramdumps completed.\n",
+					__func__);
+		INIT_COMPLETION(mdm_ram_dumps);
+		mdm_drv->ops->power_down_mdm_cb(mdm_drv);
+	}
+	return mdm_drv->mdm_ram_dump_status;
+}
+
+static struct subsys_data mdm_subsystem = {
+	.shutdown = mdm_subsys_shutdown,
+	.ramdump = mdm_subsys_ramdumps,
+	.powerup = mdm_subsys_powerup,
+	.name = EXTERNAL_MODEM,
+};
+
+static int mdm_debug_on_set(void *data, u64 val)
+{
+	mdm_debug_on = val;
+	if (mdm_drv->ops->debug_state_changed_cb)
+		mdm_drv->ops->debug_state_changed_cb(mdm_debug_on);
+	return 0;
+}
+
+static int mdm_debug_on_get(void *data, u64 *val)
+{
+	*val = mdm_debug_on;
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(mdm_debug_on_fops,
+			mdm_debug_on_get,
+			mdm_debug_on_set, "%llu\n");
+
+static int mdm_debugfs_init(void)
+{
+	struct dentry *dent;
+
+	dent = debugfs_create_dir("mdm_dbg", 0);
+	if (IS_ERR(dent))
+		return PTR_ERR(dent);
+
+	debugfs_create_file("debug_on", 0644, dent, NULL,
+			&mdm_debug_on_fops);
+	return 0;
+}
+
+static void mdm_modem_initialize_data(struct platform_device  *pdev,
+				struct mdm_ops *mdm_ops)
+{
+	struct resource *pres;
+
+	/* MDM2AP_ERRFATAL */
+	pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
+							"MDM2AP_ERRFATAL");
+	if (pres)
+		mdm_drv->mdm2ap_errfatal_gpio = pres->start;
+
+	/* AP2MDM_ERRFATAL */
+	pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
+							"AP2MDM_ERRFATAL");
+	if (pres)
+		mdm_drv->ap2mdm_errfatal_gpio = pres->start;
+
+	/* MDM2AP_STATUS */
+	pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
+							"MDM2AP_STATUS");
+	if (pres)
+		mdm_drv->mdm2ap_status_gpio = pres->start;
+
+	/* AP2MDM_STATUS */
+	pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
+							"AP2MDM_STATUS");
+	if (pres)
+		mdm_drv->ap2mdm_status_gpio = pres->start;
+
+	/* MDM2AP_WAKEUP */
+	pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
+							"MDM2AP_WAKEUP");
+	if (pres)
+		mdm_drv->mdm2ap_wakeup_gpio = pres->start;
+
+	/* AP2MDM_WAKEUP */
+	pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
+							"AP2MDM_WAKEUP");
+	if (pres)
+		mdm_drv->ap2mdm_wakeup_gpio = pres->start;
+
+	/* AP2MDM_SOFT_RESET */
+	pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
+							"AP2MDM_SOFT_RESET");
+	if (pres)
+		mdm_drv->ap2mdm_soft_reset_gpio = pres->start;
+
+	/* AP2MDM_KPDPWR_N */
+	pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
+							"AP2MDM_KPDPWR_N");
+	if (pres)
+		mdm_drv->ap2mdm_kpdpwr_n_gpio = pres->start;
+
+	/* AP2MDM_PMIC_PWR_EN */
+	pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
+							"AP2MDM_PMIC_PWR_EN");
+	if (pres)
+		mdm_drv->ap2mdm_pmic_pwr_en_gpio = pres->start;
+
+	mdm_drv->boot_type                  = CHARM_NORMAL_BOOT;
+
+	mdm_drv->ops      = mdm_ops;
+	mdm_drv->pdata    = pdev->dev.platform_data;
+}
+
+int mdm_common_create(struct platform_device  *pdev,
+					  struct mdm_ops *p_mdm_cb)
+{
+	int ret = -1, irq;
+
+	mdm_drv = kzalloc(sizeof(struct mdm_modem_drv), GFP_KERNEL);
+	if (mdm_drv == NULL) {
+		pr_err("%s: kzalloc fail.\n", __func__);
+		goto alloc_err;
+	}
+
+	mdm_modem_initialize_data(pdev, p_mdm_cb);
+	if (mdm_drv->ops->debug_state_changed_cb)
+		mdm_drv->ops->debug_state_changed_cb(mdm_debug_on);
+
+	gpio_request(mdm_drv->ap2mdm_status_gpio, "AP2MDM_STATUS");
+	gpio_request(mdm_drv->ap2mdm_errfatal_gpio, "AP2MDM_ERRFATAL");
+	if (mdm_drv->ap2mdm_kpdpwr_n_gpio > 0)
+		gpio_request(mdm_drv->ap2mdm_kpdpwr_n_gpio, "AP2MDM_KPDPWR_N");
+	gpio_request(mdm_drv->mdm2ap_status_gpio, "MDM2AP_STATUS");
+	gpio_request(mdm_drv->mdm2ap_errfatal_gpio, "MDM2AP_ERRFATAL");
+
+	if (mdm_drv->ap2mdm_pmic_pwr_en_gpio > 0)
+		gpio_request(mdm_drv->ap2mdm_pmic_pwr_en_gpio,
+					 "AP2MDM_PMIC_PWR_EN");
+	if (mdm_drv->ap2mdm_soft_reset_gpio > 0)
+		gpio_request(mdm_drv->ap2mdm_soft_reset_gpio,
+					 "AP2MDM_SOFT_RESET");
+
+	if (mdm_drv->ap2mdm_wakeup_gpio > 0)
+		gpio_request(mdm_drv->ap2mdm_wakeup_gpio, "AP2MDM_WAKEUP");
+
+	gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 1);
+	gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 0);
+
+	if (mdm_drv->ap2mdm_wakeup_gpio > 0)
+		gpio_direction_output(mdm_drv->ap2mdm_wakeup_gpio, 0);
+
+	gpio_direction_input(mdm_drv->mdm2ap_status_gpio);
+	gpio_direction_input(mdm_drv->mdm2ap_errfatal_gpio);
+
+	mdm_queue = create_singlethread_workqueue("mdm_queue");
+	if (!mdm_queue) {
+		pr_err("%s: could not create workqueue. All mdm "
+				"functionality will be disabled\n",
+			__func__);
+		ret = -ENOMEM;
+		goto fatal_err;
+	}
+
+	mdm_sfr_queue = alloc_workqueue("mdm_sfr_queue", 0, 0);
+	if (!mdm_sfr_queue) {
+		pr_err("%s: could not create workqueue mdm_sfr_queue."
+			" All mdm functionality will be disabled\n",
+			__func__);
+		ret = -ENOMEM;
+		destroy_workqueue(mdm_queue);
+		goto fatal_err;
+	}
+
+	atomic_notifier_chain_register(&panic_notifier_list, &mdm_panic_blk);
+	mdm_debugfs_init();
+
+	/* Register subsystem handlers */
+	ssr_register_subsystem(&mdm_subsystem);
+
+	/* ERR_FATAL irq. */
+	irq = MSM_GPIO_TO_INT(mdm_drv->mdm2ap_errfatal_gpio);
+	if (irq < 0) {
+		pr_err("%s: could not get MDM2AP_ERRFATAL IRQ resource. "
+			"error=%d No IRQ will be generated on errfatal.",
+			__func__, irq);
+		goto errfatal_err;
+	}
+	ret = request_irq(irq, mdm_errfatal,
+		IRQF_TRIGGER_RISING , "mdm errfatal", NULL);
+
+	if (ret < 0) {
+		pr_err("%s: MDM2AP_ERRFATAL IRQ#%d request failed with error=%d"
+			". No IRQ will be generated on errfatal.",
+			__func__, irq, ret);
+		goto errfatal_err;
+	}
+	mdm_drv->mdm_errfatal_irq = irq;
+
+errfatal_err:
+
+	/* status irq */
+	irq = MSM_GPIO_TO_INT(mdm_drv->mdm2ap_status_gpio);
+	if (irq < 0) {
+		pr_err("%s: could not get MDM2AP_STATUS IRQ resource. "
+			"error=%d No IRQ will be generated on status change.",
+			__func__, irq);
+		goto status_err;
+	}
+
+	ret = request_threaded_irq(irq, NULL, mdm_status_change,
+		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_SHARED,
+		"mdm status", mdm_drv);
+
+	if (ret < 0) {
+		pr_err("%s: MDM2AP_STATUS IRQ#%d request failed with error=%d"
+			". No IRQ will be generated on status change.",
+			__func__, irq, ret);
+		goto status_err;
+	}
+	mdm_drv->mdm_status_irq = irq;
+
+status_err:
+	/*
+	 * If AP2MDM_PMIC_PWR_EN gpio is used, pull it high. It remains
+	 * high until the whole phone is shut down.
+	 */
+	if (mdm_drv->ap2mdm_pmic_pwr_en_gpio > 0)
+		gpio_direction_output(mdm_drv->ap2mdm_pmic_pwr_en_gpio, 1);
+
+	/* Perform early powerup of the external modem in order to
+	 * allow tabla devices to be found.
+	 */
+	if (mdm_drv->pdata->early_power_on)
+		mdm_drv->ops->power_on_mdm_cb(mdm_drv);
+
+	pr_info("%s: Registering mdm modem\n", __func__);
+	return misc_register(&mdm_modem_misc);
+
+fatal_err:
+	gpio_free(mdm_drv->ap2mdm_status_gpio);
+	gpio_free(mdm_drv->ap2mdm_errfatal_gpio);
+	if (mdm_drv->ap2mdm_kpdpwr_n_gpio > 0)
+		gpio_free(mdm_drv->ap2mdm_kpdpwr_n_gpio);
+	if (mdm_drv->ap2mdm_pmic_pwr_en_gpio > 0)
+		gpio_free(mdm_drv->ap2mdm_pmic_pwr_en_gpio);
+	gpio_free(mdm_drv->mdm2ap_status_gpio);
+	gpio_free(mdm_drv->mdm2ap_errfatal_gpio);
+	if (mdm_drv->ap2mdm_soft_reset_gpio > 0)
+		gpio_free(mdm_drv->ap2mdm_soft_reset_gpio);
+
+	if (mdm_drv->ap2mdm_wakeup_gpio > 0)
+		gpio_free(mdm_drv->ap2mdm_wakeup_gpio);
+
+	kfree(mdm_drv);
+	ret = -ENODEV;
+
+alloc_err:
+	return ret;
+}
+
+int mdm_common_modem_remove(struct platform_device *pdev)
+{
+	int ret;
+
+	gpio_free(mdm_drv->ap2mdm_status_gpio);
+	gpio_free(mdm_drv->ap2mdm_errfatal_gpio);
+	if (mdm_drv->ap2mdm_kpdpwr_n_gpio > 0)
+		gpio_free(mdm_drv->ap2mdm_kpdpwr_n_gpio);
+	if (mdm_drv->ap2mdm_pmic_pwr_en_gpio > 0)
+		gpio_free(mdm_drv->ap2mdm_pmic_pwr_en_gpio);
+	gpio_free(mdm_drv->mdm2ap_status_gpio);
+	gpio_free(mdm_drv->mdm2ap_errfatal_gpio);
+	if (mdm_drv->ap2mdm_soft_reset_gpio > 0)
+		gpio_free(mdm_drv->ap2mdm_soft_reset_gpio);
+
+	if (mdm_drv->ap2mdm_wakeup_gpio > 0)
+		gpio_free(mdm_drv->ap2mdm_wakeup_gpio);
+
+	kfree(mdm_drv);
+
+	ret = misc_deregister(&mdm_modem_misc);
+	return ret;
+}
+
+void mdm_common_modem_shutdown(struct platform_device *pdev)
+{
+	mdm_disable_irqs();
+
+	mdm_drv->ops->power_down_mdm_cb(mdm_drv);
+	if (mdm_drv->ap2mdm_pmic_pwr_en_gpio > 0)
+		gpio_direction_output(mdm_drv->ap2mdm_pmic_pwr_en_gpio, 0);
+}
+
diff --git a/arch/arm/mach-msm/mdm_private.h b/arch/arm/mach-msm/mdm_private.h
new file mode 100644
index 0000000..f157d88
--- /dev/null
+++ b/arch/arm/mach-msm/mdm_private.h
@@ -0,0 +1,59 @@
+/* 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
+ * 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 _ARCH_ARM_MACH_MSM_MDM_PRIVATE_H
+#define _ARCH_ARM_MACH_MSM_MDM_PRIVATE_H
+
+struct mdm_modem_drv;
+
+struct mdm_ops {
+	void (*power_on_mdm_cb)(struct mdm_modem_drv *mdm_drv);
+	void (*reset_mdm_cb)(struct mdm_modem_drv *mdm_drv);
+	void (*normal_boot_done_cb)(struct mdm_modem_drv *mdm_drv);
+	void (*power_down_mdm_cb)(struct mdm_modem_drv *mdm_drv);
+	void (*debug_state_changed_cb)(int value);
+	void (*status_cb)(struct mdm_modem_drv *mdm_drv, int value);
+};
+
+/* Private mdm2 data structure */
+struct mdm_modem_drv {
+	unsigned mdm2ap_errfatal_gpio;
+	unsigned ap2mdm_errfatal_gpio;
+	unsigned mdm2ap_status_gpio;
+	unsigned ap2mdm_status_gpio;
+	unsigned mdm2ap_wakeup_gpio;
+	unsigned ap2mdm_wakeup_gpio;
+	unsigned ap2mdm_kpdpwr_n_gpio;
+	unsigned ap2mdm_soft_reset_gpio;
+	unsigned ap2mdm_pmic_pwr_en_gpio;
+
+	int mdm_errfatal_irq;
+	int mdm_status_irq;
+	int mdm_ready;
+	int mdm_boot_status;
+	int mdm_ram_dump_status;
+	enum charm_boot_type boot_type;
+	int mdm_debug_on;
+	int mdm_unexpected_reset_occurred;
+
+	struct mdm_ops *ops;
+	struct mdm_platform_data *pdata;
+};
+
+int mdm_common_create(struct platform_device  *pdev,
+					  struct mdm_ops *mdm_cb);
+int mdm_common_modem_remove(struct platform_device *pdev);
+void mdm_common_modem_shutdown(struct platform_device *pdev);
+void mdm_common_set_debug_state(int value);
+
+#endif
+
diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c
new file mode 100644
index 0000000..40845d7
--- /dev/null
+++ b/arch/arm/mach-msm/memory.c
@@ -0,0 +1,441 @@
+/* arch/arm/mach-msm/memory.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009-2012, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/mm.h>
+#include <linux/mm_types.h>
+#include <linux/bootmem.h>
+#include <linux/module.h>
+#include <linux/memory_alloc.h>
+#include <linux/memblock.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/mach/map.h>
+#include <asm/cacheflush.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <mach/msm_memtypes.h>
+#include <linux/hardirq.h>
+#if defined(CONFIG_MSM_NPA_REMOTE)
+#include "npa_remote.h"
+#include <linux/completion.h>
+#include <linux/err.h>
+#endif
+#include <linux/android_pmem.h>
+#include <mach/msm_iomap.h>
+#include <mach/socinfo.h>
+#include <linux/sched.h>
+
+/* fixme */
+#include <asm/tlbflush.h>
+#include <../../mm/mm.h>
+#include <linux/fmem.h>
+
+void *strongly_ordered_page;
+char strongly_ordered_mem[PAGE_SIZE*2-4];
+
+void map_page_strongly_ordered(void)
+{
+#if defined(CONFIG_ARCH_MSM7X27) && !defined(CONFIG_ARCH_MSM7X27A)
+	long unsigned int phys;
+	struct map_desc map;
+
+	if (strongly_ordered_page)
+		return;
+
+	strongly_ordered_page = (void*)PFN_ALIGN((int)&strongly_ordered_mem);
+	phys = __pa(strongly_ordered_page);
+
+	map.pfn = __phys_to_pfn(phys);
+	map.virtual = MSM_STRONGLY_ORDERED_PAGE;
+	map.length = PAGE_SIZE;
+	map.type = MT_DEVICE_STRONGLY_ORDERED;
+	create_mapping(&map);
+
+	printk(KERN_ALERT "Initialized strongly ordered page successfully\n");
+#endif
+}
+EXPORT_SYMBOL(map_page_strongly_ordered);
+
+void write_to_strongly_ordered_memory(void)
+{
+#if defined(CONFIG_ARCH_MSM7X27) && !defined(CONFIG_ARCH_MSM7X27A)
+	if (!strongly_ordered_page) {
+		if (!in_interrupt())
+			map_page_strongly_ordered();
+		else {
+			printk(KERN_ALERT "Cannot map strongly ordered page in "
+				"Interrupt Context\n");
+			/* capture it here before the allocation fails later */
+			BUG();
+		}
+	}
+	*(int *)MSM_STRONGLY_ORDERED_PAGE = 0;
+#endif
+}
+EXPORT_SYMBOL(write_to_strongly_ordered_memory);
+
+/* These cache related routines make the assumption (if outer cache is
+ * available) that the associated physical memory is contiguous.
+ * They will operate on all (L1 and L2 if present) caches.
+ */
+void clean_and_invalidate_caches(unsigned long vstart,
+	unsigned long length, unsigned long pstart)
+{
+	dmac_flush_range((void *)vstart, (void *) (vstart + length));
+	outer_flush_range(pstart, pstart + length);
+}
+
+void clean_caches(unsigned long vstart,
+	unsigned long length, unsigned long pstart)
+{
+	dmac_clean_range((void *)vstart, (void *) (vstart + length));
+	outer_clean_range(pstart, pstart + length);
+}
+
+void invalidate_caches(unsigned long vstart,
+	unsigned long length, unsigned long pstart)
+{
+	dmac_inv_range((void *)vstart, (void *) (vstart + length));
+	outer_inv_range(pstart, pstart + length);
+}
+
+void * __init alloc_bootmem_aligned(unsigned long size, unsigned long alignment)
+{
+	void *unused_addr = NULL;
+	unsigned long addr, tmp_size, unused_size;
+
+	/* Allocate maximum size needed, see where it ends up.
+	 * Then free it -- in this path there are no other allocators
+	 * so we can depend on getting the same address back
+	 * when we allocate a smaller piece that is aligned
+	 * at the end (if necessary) and the piece we really want,
+	 * then free the unused first piece.
+	 */
+
+	tmp_size = size + alignment - PAGE_SIZE;
+	addr = (unsigned long)alloc_bootmem(tmp_size);
+	free_bootmem(__pa(addr), tmp_size);
+
+	unused_size = alignment - (addr % alignment);
+	if (unused_size)
+		unused_addr = alloc_bootmem(unused_size);
+
+	addr = (unsigned long)alloc_bootmem(size);
+	if (unused_size)
+		free_bootmem(__pa(unused_addr), unused_size);
+
+	return (void *)addr;
+}
+
+int (*change_memory_power)(u64, u64, int);
+
+int platform_physical_remove_pages(u64 start, u64 size)
+{
+	if (!change_memory_power)
+		return 0;
+	return change_memory_power(start, size, MEMORY_DEEP_POWERDOWN);
+}
+
+int platform_physical_active_pages(u64 start, u64 size)
+{
+	if (!change_memory_power)
+		return 0;
+	return change_memory_power(start, size, MEMORY_ACTIVE);
+}
+
+int platform_physical_low_power_pages(u64 start, u64 size)
+{
+	if (!change_memory_power)
+		return 0;
+	return change_memory_power(start, size, MEMORY_SELF_REFRESH);
+}
+
+char *memtype_name[] = {
+	"SMI_KERNEL",
+	"SMI",
+	"EBI0",
+	"EBI1"
+};
+
+struct reserve_info *reserve_info;
+
+static unsigned long stable_size(struct membank *mb,
+	unsigned long unstable_limit)
+{
+	unsigned long upper_limit = mb->start + mb->size;
+
+	if (!unstable_limit)
+		return mb->size;
+
+	/* Check for 32 bit roll-over */
+	if (upper_limit >= mb->start) {
+		/* If we didn't roll over we can safely make the check below */
+		if (upper_limit <= unstable_limit)
+			return mb->size;
+	}
+
+	if (mb->start >= unstable_limit)
+		return 0;
+	return unstable_limit - mb->start;
+}
+
+/* stable size of all memory banks contiguous to and below this one */
+static unsigned long total_stable_size(unsigned long bank)
+{
+	int i;
+	struct membank *mb = &meminfo.bank[bank];
+	int memtype = reserve_info->paddr_to_memtype(mb->start);
+	unsigned long size;
+
+	size = stable_size(mb, reserve_info->low_unstable_address);
+	for (i = bank - 1, mb = &meminfo.bank[bank - 1]; i >= 0; i--, mb--) {
+		if (mb->start + mb->size != (mb + 1)->start)
+			break;
+		if (reserve_info->paddr_to_memtype(mb->start) != memtype)
+			break;
+		size += stable_size(mb, reserve_info->low_unstable_address);
+	}
+	return size;
+}
+
+static void __init calculate_reserve_limits(void)
+{
+	int i;
+	struct membank *mb;
+	int memtype;
+	struct memtype_reserve *mt;
+	unsigned long size;
+
+	for (i = 0, mb = &meminfo.bank[0]; i < meminfo.nr_banks; i++, mb++)  {
+		memtype = reserve_info->paddr_to_memtype(mb->start);
+		if (memtype == MEMTYPE_NONE) {
+			pr_warning("unknown memory type for bank at %lx\n",
+				(long unsigned int)mb->start);
+			continue;
+		}
+		mt = &reserve_info->memtype_reserve_table[memtype];
+		size = total_stable_size(i);
+		mt->limit = max(mt->limit, size);
+	}
+}
+
+static void __init adjust_reserve_sizes(void)
+{
+	int i;
+	struct memtype_reserve *mt;
+
+	mt = &reserve_info->memtype_reserve_table[0];
+	for (i = 0; i < MEMTYPE_MAX; i++, mt++) {
+		if (mt->flags & MEMTYPE_FLAGS_1M_ALIGN)
+			mt->size = (mt->size + SECTION_SIZE - 1) & SECTION_MASK;
+		if (mt->size > mt->limit) {
+			pr_warning("%lx size for %s too large, setting to %lx\n",
+				mt->size, memtype_name[i], mt->limit);
+			mt->size = mt->limit;
+		}
+	}
+}
+
+static void __init reserve_memory_for_mempools(void)
+{
+	int i, memtype, membank_type;
+	struct memtype_reserve *mt;
+	struct membank *mb;
+	int ret;
+	unsigned long size;
+
+	mt = &reserve_info->memtype_reserve_table[0];
+	for (memtype = 0; memtype < MEMTYPE_MAX; memtype++, mt++) {
+		if (mt->flags & MEMTYPE_FLAGS_FIXED || !mt->size)
+			continue;
+
+		/* We know we will find memory bank(s) of the proper size
+		 * as we have limited the size of the memory pool for
+		 * each memory type to the largest total size of the memory
+		 * banks which are contiguous and of the correct memory type.
+		 * Choose the memory bank with the highest physical
+		 * address which is large enough, so that we will not
+		 * take memory from the lowest memory bank which the kernel
+		 * is in (and cause boot problems) and so that we might
+		 * be able to steal memory that would otherwise become
+		 * highmem. However, do not use unstable memory.
+		 */
+		for (i = meminfo.nr_banks - 1; i >= 0; i--) {
+			mb = &meminfo.bank[i];
+			membank_type =
+				reserve_info->paddr_to_memtype(mb->start);
+			if (memtype != membank_type)
+				continue;
+			size = total_stable_size(i);
+			if (size >= mt->size) {
+				size = stable_size(mb,
+					reserve_info->low_unstable_address);
+				if (!size)
+					continue;
+				/* mt->size may be larger than size, all this
+				 * means is that we are carving the memory pool
+				 * out of multiple contiguous memory banks.
+				 */
+				mt->start = mb->start + (size - mt->size);
+				ret = memblock_remove(mt->start, mt->size);
+				BUG_ON(ret);
+				break;
+			}
+		}
+	}
+}
+
+static void __init initialize_mempools(void)
+{
+	struct mem_pool *mpool;
+	int memtype;
+	struct memtype_reserve *mt;
+
+	mt = &reserve_info->memtype_reserve_table[0];
+	for (memtype = 0; memtype < MEMTYPE_MAX; memtype++, mt++) {
+		if (!mt->size)
+			continue;
+		mpool = initialize_memory_pool(mt->start, mt->size, memtype);
+		if (!mpool)
+			pr_warning("failed to create %s mempool\n",
+				memtype_name[memtype]);
+	}
+}
+
+#define  MAX_FIXED_AREA_SIZE 0x11000000
+
+void __init msm_reserve(void)
+{
+	unsigned long msm_fixed_area_size;
+	unsigned long msm_fixed_area_start;
+
+	memory_pool_init();
+	reserve_info->calculate_reserve_sizes();
+
+	msm_fixed_area_size = reserve_info->fixed_area_size;
+	msm_fixed_area_start = reserve_info->fixed_area_start;
+	if (msm_fixed_area_size)
+		if (msm_fixed_area_start > reserve_info->low_unstable_address
+			- MAX_FIXED_AREA_SIZE)
+			reserve_info->low_unstable_address =
+			msm_fixed_area_start;
+
+	calculate_reserve_limits();
+	adjust_reserve_sizes();
+	reserve_memory_for_mempools();
+	initialize_mempools();
+}
+
+static int get_ebi_memtype(void)
+{
+	/* on 7x30 and 8x55 "EBI1 kernel PMEM" is really on EBI0 */
+	if (cpu_is_msm7x30() || cpu_is_msm8x55())
+		return MEMTYPE_EBI0;
+	return MEMTYPE_EBI1;
+}
+
+void *allocate_contiguous_ebi(unsigned long size,
+	unsigned long align, int cached)
+{
+	return allocate_contiguous_memory(size, get_ebi_memtype(),
+		align, cached);
+}
+EXPORT_SYMBOL(allocate_contiguous_ebi);
+
+unsigned long allocate_contiguous_ebi_nomap(unsigned long size,
+	unsigned long align)
+{
+	return _allocate_contiguous_memory_nomap(size, get_ebi_memtype(),
+		align, __builtin_return_address(0));
+}
+EXPORT_SYMBOL(allocate_contiguous_ebi_nomap);
+
+/* emulation of the deprecated pmem_kalloc and pmem_kfree */
+int32_t pmem_kalloc(const size_t size, const uint32_t flags)
+{
+	int pmem_memtype;
+	int memtype = MEMTYPE_NONE;
+	int ebi1_memtype = MEMTYPE_EBI1;
+	unsigned int align;
+	int32_t paddr;
+
+	switch (flags & PMEM_ALIGNMENT_MASK) {
+	case PMEM_ALIGNMENT_4K:
+		align = SZ_4K;
+		break;
+	case PMEM_ALIGNMENT_1M:
+		align = SZ_1M;
+		break;
+	default:
+		pr_alert("Invalid alignment %x\n",
+			(flags & PMEM_ALIGNMENT_MASK));
+		return -EINVAL;
+	}
+
+	/* on 7x30 and 8x55 "EBI1 kernel PMEM" is really on EBI0 */
+	if (cpu_is_msm7x30() || cpu_is_msm8x55())
+			ebi1_memtype = MEMTYPE_EBI0;
+
+	pmem_memtype = flags & PMEM_MEMTYPE_MASK;
+	if (pmem_memtype == PMEM_MEMTYPE_EBI1)
+		memtype = ebi1_memtype;
+	else if (pmem_memtype == PMEM_MEMTYPE_SMI)
+		memtype = MEMTYPE_SMI_KERNEL;
+	else {
+		pr_alert("Invalid memory type %x\n",
+			flags & PMEM_MEMTYPE_MASK);
+		return -EINVAL;
+	}
+
+	paddr = _allocate_contiguous_memory_nomap(size, memtype, align,
+		__builtin_return_address(0));
+
+	if (!paddr && pmem_memtype == PMEM_MEMTYPE_SMI)
+		paddr = _allocate_contiguous_memory_nomap(size,
+			ebi1_memtype, align, __builtin_return_address(0));
+
+	if (!paddr)
+		return -ENOMEM;
+	return paddr;
+}
+EXPORT_SYMBOL(pmem_kalloc);
+
+int pmem_kfree(const int32_t physaddr)
+{
+	free_contiguous_memory_by_paddr(physaddr);
+
+	return 0;
+}
+EXPORT_SYMBOL(pmem_kfree);
+
+unsigned int msm_ttbr0;
+
+void store_ttbr0(void)
+{
+	/* Store TTBR0 for post-mortem debugging purposes. */
+	asm("mrc p15, 0, %0, c2, c0, 0\n"
+		: "=r" (msm_ttbr0));
+}
+
+int request_fmem_c_region(void *unused)
+{
+	return fmem_set_state(FMEM_C_STATE);
+}
+
+int release_fmem_c_region(void *unused)
+{
+	return fmem_set_state(FMEM_T_STATE);
+}
diff --git a/arch/arm/mach-msm/memory_topology.c b/arch/arm/mach-msm/memory_topology.c
new file mode 100644
index 0000000..70aaf4a
--- /dev/null
+++ b/arch/arm/mach-msm/memory_topology.c
@@ -0,0 +1,268 @@
+/* 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
+ * 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 <asm/setup.h>
+#include <asm/errno.h>
+#include <asm/sizes.h>
+#include <asm/pgtable.h>
+#include <linux/mutex.h>
+#include <linux/memory.h>
+#include <mach/msm_memtypes.h>
+#include <mach/socinfo.h>
+#include "smd_private.h"
+
+#if defined(CONFIG_ARCH_MSM8960)
+#include "rpm_resources.h"
+#endif
+
+static struct mem_region_t {
+	u64 start;
+	u64 size;
+	/* reserved for future use */
+	u64 num_partitions;
+	int state;
+} mem_regions[MAX_NR_REGIONS];
+
+static struct mutex mem_regions_mutex;
+static unsigned int nr_mem_regions;
+static int mem_regions_mask;
+
+enum {
+	STATE_POWER_DOWN = 0x0,
+	STATE_ACTIVE = 0x2,
+	STATE_DEFAULT = STATE_ACTIVE
+};
+
+static int default_mask = ~0x0;
+
+/* Return the number of chipselects populated with a memory bank */
+/* This is 7x30 only and will be re-implemented in the future */
+
+#if defined(CONFIG_ARCH_MSM7X30)
+unsigned int get_num_populated_chipselects()
+{
+	/* Currently, Linux cannot determine the memory toplogy of a target */
+	/* This is a kludge until all this info is figured out from smem */
+
+	/* There is atleast one chipselect populated for hosting the 1st bank */
+	unsigned int num_chipselects = 1;
+	int i;
+	for (i = 0; i < meminfo.nr_banks; i++) {
+		struct membank *bank = &meminfo.bank[i];
+		if (bank->start == EBI1_PHYS_OFFSET)
+			num_chipselects++;
+	}
+	return num_chipselects;
+}
+#endif
+
+#if (defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_MSM8930)) \
+	&& defined(CONFIG_ENABLE_DMM)
+static int rpm_change_memory_state(int retention_mask,
+					int active_mask)
+{
+	int ret;
+	struct msm_rpm_iv_pair cmd[2];
+	struct msm_rpm_iv_pair status[2];
+
+	cmd[0].id = MSM_RPM_ID_DDR_DMM_0;
+	cmd[1].id = MSM_RPM_ID_DDR_DMM_1;
+
+	status[0].id = MSM_RPM_STATUS_ID_DDR_DMM_0;
+	status[1].id = MSM_RPM_STATUS_ID_DDR_DMM_1;
+
+	cmd[0].value = retention_mask;
+	cmd[1].value = active_mask;
+
+	ret = msm_rpm_set(MSM_RPM_CTX_SET_0, cmd, 2);
+	if (ret < 0) {
+		pr_err("rpm set failed");
+		return -EINVAL;
+	}
+
+	ret = msm_rpm_get_status(status, 2);
+	if (ret < 0) {
+		pr_err("rpm status failed");
+		return -EINVAL;
+	}
+	if (status[0].value == retention_mask &&
+		status[1].value == active_mask)
+		return 0;
+	else {
+		pr_err("rpm failed to change memory state");
+		return -EINVAL;
+	}
+}
+
+static int switch_memory_state(int mask, int new_state, int start_region,
+				int end_region)
+{
+	int final_mask = 0;
+	int i;
+
+	mutex_lock(&mem_regions_mutex);
+
+	for (i = start_region; i <= end_region; i++) {
+		if (new_state == mem_regions[i].state)
+			goto no_change;
+		/* All region states must be the same to change them */
+		if (mem_regions[i].state != mem_regions[start_region].state)
+			goto no_change;
+	}
+
+	if (new_state == STATE_POWER_DOWN)
+		final_mask = mem_regions_mask & mask;
+	else if (new_state == STATE_ACTIVE)
+		final_mask = mem_regions_mask | ~mask;
+	else
+		goto no_change;
+
+	pr_info("request memory %d to %d state switch (%d->%d)\n",
+		start_region, end_region, mem_regions[start_region].state,
+		new_state);
+	if (rpm_change_memory_state(final_mask, final_mask) == 0) {
+		for (i = start_region; i <= end_region; i++)
+			mem_regions[i].state = new_state;
+		mem_regions_mask = final_mask;
+
+		pr_info("completed memory %d to %d state switch to %d\n",
+			start_region, end_region, new_state);
+		mutex_unlock(&mem_regions_mutex);
+		return 0;
+	}
+
+	pr_err("failed memory %d to %d state switch (%d->%d)\n",
+		start_region, end_region, mem_regions[start_region].state,
+		new_state);
+
+no_change:
+	mutex_unlock(&mem_regions_mutex);
+	return -EINVAL;
+}
+#else
+
+static int switch_memory_state(int mask, int new_state, int start_region,
+				int end_region)
+{
+	return -EINVAL;
+}
+#endif
+
+/* The hotplug code expects the number of bytes that switched state successfully
+ * as the return value, so a return value of zero indicates an error
+*/
+int soc_change_memory_power(u64 start, u64 size, int change)
+{
+	int i = 0;
+	int mask = default_mask;
+	u64 end = start + size;
+	int start_region = 0;
+	int end_region = 0;
+
+	if (change != STATE_ACTIVE && change != STATE_POWER_DOWN) {
+		pr_info("requested state transition invalid\n");
+		return 0;
+	}
+	/* Find the memory regions that fall within the range */
+	for (i = 0; i < nr_mem_regions; i++) {
+		if (mem_regions[i].start <= start &&
+			mem_regions[i].start >=
+			mem_regions[start_region].start) {
+			start_region = i;
+		}
+		if (end <= mem_regions[i].start + mem_regions[i].size) {
+			end_region = i;
+			break;
+		}
+	}
+
+	/* Set the bitmask for each region in the range */
+	for (i = start_region; i <= end_region; i++)
+		mask &= ~(0x1 << i);
+
+	if (!switch_memory_state(mask, change, start_region, end_region))
+		return size;
+	else
+		return 0;
+}
+
+unsigned int get_num_memory_banks(void)
+{
+	return nr_mem_regions;
+}
+
+unsigned int get_memory_bank_size(unsigned int id)
+{
+	BUG_ON(id >= nr_mem_regions);
+	return mem_regions[id].size;
+}
+
+unsigned int get_memory_bank_start(unsigned int id)
+{
+	BUG_ON(id >= nr_mem_regions);
+	return mem_regions[id].start;
+}
+
+int __init meminfo_init(unsigned int type, unsigned int min_bank_size)
+{
+	unsigned int i, j;
+	unsigned long bank_size;
+	unsigned long bank_start;
+	unsigned long region_size;
+	struct smem_ram_ptable *ram_ptable;
+	/* physical memory banks */
+	unsigned int nr_mem_banks = 0;
+	/* logical memory regions for dmm */
+	nr_mem_regions = 0;
+
+	ram_ptable = smem_alloc(SMEM_USABLE_RAM_PARTITION_TABLE,
+				sizeof(struct smem_ram_ptable));
+
+	if (!ram_ptable) {
+		pr_err("Could not read ram partition table\n");
+		return -EINVAL;
+	}
+
+	pr_info("meminfo_init: smem ram ptable found: ver: %d len: %d\n",
+			ram_ptable->version, ram_ptable->len);
+
+	for (i = 0; i < ram_ptable->len; i++) {
+		/* A bank is valid only if is greater than min_bank_size. If
+		 * non-valid memory (e.g. modem memory) became greater than
+		 * min_bank_size, there is currently no way to differentiate.
+		 */
+		if (ram_ptable->parts[i].type == type &&
+			ram_ptable->parts[i].size >= min_bank_size) {
+			bank_start = ram_ptable->parts[i].start;
+			bank_size = ram_ptable->parts[i].size;
+			region_size = bank_size / NR_REGIONS_PER_BANK;
+
+			for (j = 0; j < NR_REGIONS_PER_BANK; j++) {
+				mem_regions[nr_mem_regions].start =
+					bank_start;
+				mem_regions[nr_mem_regions].size =
+					region_size;
+				mem_regions[nr_mem_regions].state =
+							STATE_DEFAULT;
+				bank_start += region_size;
+				nr_mem_regions++;
+			}
+			nr_mem_banks++;
+		}
+	}
+	mutex_init(&mem_regions_mutex);
+	mem_regions_mask = default_mask;
+	pr_info("Found %d memory banks grouped into %d memory regions\n",
+			nr_mem_banks, nr_mem_regions);
+	return 0;
+}
diff --git a/arch/arm/mach-msm/mkrpcsym.pl b/arch/arm/mach-msm/mkrpcsym.pl
new file mode 100644
index 0000000..f4abb5f
--- /dev/null
+++ b/arch/arm/mach-msm/mkrpcsym.pl
@@ -0,0 +1,162 @@
+#!/usr/bin/perl
+#
+# Generate the smd_rpc_sym.c symbol file for ONCRPC SMEM Logging
+#
+# Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Code Aurora Forum, Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+use strict;
+use POSIX;
+
+my $base_fn = "smd_rpc_sym";
+my %prog_table;
+my ($in, $out) = @ARGV;
+my $max_table_size = 1024;
+
+my $header = <<"EOF";
+/* Autogenerated by mkrpcsym.pl.  Do not edit */
+EOF
+
+sub smd_rpc_gen_files() {
+	my $c_fp;
+	my $h_fp;
+	my @table;
+	my $tbl_index;
+	my $num_undefined=0;
+
+	# Process the input hash table into an array
+	# Any duplicate items will be combined, missing items will
+	# become "UNKNOWN"  We end-up with a fully-qualified table
+	# from 0 to n.
+
+	$prog_table{"UNDEFINED"}{'name'}="UNDEFINED";
+	$prog_table{"UNDEFINED"}{'prog'}=-1;
+	my $hex_num = 0xFFFF;
+	foreach my $api_prog (sort {$a cmp $b} keys %prog_table ) {
+		$tbl_index = hex($api_prog) & hex("0000FFFF");
+		if($prog_table{$api_prog}{'prog'} >= 0) {
+			if($tbl_index < $max_table_size) {
+				$table[$tbl_index]=$prog_table{$api_prog};
+			} else {
+				print "Skipping table item $tbl_index, larger ",
+					"than max:$max_table_size \n";
+			}
+		}
+	}
+	for (my $i=0; $i<=$#table; $i++) {
+		if (!exists $table[$i]) {
+			$table[$i]=$prog_table{"UNDEFINED"};
+		$num_undefined++;
+		}
+	}
+
+
+	open($c_fp, ">", $out) or die  $!;
+	print $c_fp $header;
+	print $c_fp "\n\n\n";
+	print $c_fp <<"EOF";
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+
+struct sym {
+	const char *str;
+};
+
+EOF
+
+# Each API is named starts with "CB " to allow both the forward and
+# callback names of the API to be returned from a common database.
+# By convention, program names starting with 0x30 are forward APIS,
+# API names starting with 0x31 are callback apis.
+	print $c_fp "const char *smd_rpc_syms[] = {\n";
+
+	for (my $i=0; $i<= $#table; $i++) {
+		my $l = length($table[$i]{'name'});
+		my $t = floor((45 - $l - 4)/8);
+		print $c_fp "\t\"CB ".uc($table[$i]{'name'})."\",";
+		if($table[$i]{'name'} ne "UNDEFINED") {
+			for (my $i=0;$i<$t;$i++) {
+				print $c_fp "\t";
+			}
+			print $c_fp "/*".$table[$i]{'prog'}."*/\n";
+		} else {
+			print $c_fp "\n";
+		}
+	}
+
+	print $c_fp "};\n";
+	print $c_fp <<"EOF";
+
+static struct sym_tbl {
+	const char **data;
+	int size;
+} tbl = { smd_rpc_syms, ARRAY_SIZE(smd_rpc_syms)};
+
+const char *smd_rpc_get_sym(uint32_t val)
+{
+	int idx = val & 0xFFFF;
+	if (idx < tbl.size) {
+		if (val & 0x01000000)
+			return tbl.data[idx];
+		else
+			return tbl.data[idx] + 3;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(smd_rpc_get_sym);
+
+EOF
+	close $c_fp;
+}
+
+sub read_smd_rpc_table() {
+	my $fp;
+	my $line;
+	open($fp, "<", $in) or die  "$! File:$in";
+	while ($line = <$fp>) {
+		chomp($line);
+		if($line =~ /([^\s]+)\s+([\w]+)$/) {
+			if(defined $prog_table{$1}) {
+				print "Error entry already defined $1,",
+				      " in $prog_table{$1}{name} \n";
+			} else {
+				$prog_table{$1}{'name'}=$2;
+				$prog_table{$1}{'prog'}=$1;
+			}
+		} else {
+			if($line =~ /\w/) {
+				print "Error parsing error >>$line<< \n";
+			}
+		}
+	}
+	close $fp;
+}
+
+read_smd_rpc_table();
+smd_rpc_gen_files();
diff --git a/arch/arm/mach-msm/modem-8660.c b/arch/arm/mach-msm/modem-8660.c
new file mode 100644
index 0000000..0b7b768
--- /dev/null
+++ b/arch/arm/mach-msm/modem-8660.c
@@ -0,0 +1,288 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/workqueue.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/stringify.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+
+#include <mach/irqs.h>
+#include <mach/scm.h>
+#include <mach/peripheral-loader.h>
+#include <mach/subsystem_restart.h>
+#include <mach/subsystem_notif.h>
+
+#include "smd_private.h"
+#include "modem_notifier.h"
+#include "ramdump.h"
+
+#define MODEM_HWIO_MSS_RESET_ADDR       0x00902C48
+#define MODULE_NAME			"modem_8660"
+#define MODEM_WDOG_ENABLE		0x10020008
+#define MODEM_CLEANUP_DELAY_MS		20
+
+#define SUBSYS_FATAL_DEBUG
+
+#if defined(SUBSYS_FATAL_DEBUG)
+static void debug_crash_modem_fn(struct work_struct *);
+static int reset_modem;
+static int ignore_smsm_ack;
+
+static DECLARE_DELAYED_WORK(debug_crash_modem_work,
+				debug_crash_modem_fn);
+
+module_param(reset_modem, int, 0644);
+#endif
+
+/* Subsystem restart: Modem data, functions */
+static void *modem_ramdump_dev;
+static void modem_fatal_fn(struct work_struct *);
+static void modem_unlock_timeout(struct work_struct *work);
+static int modem_notif_handler(struct notifier_block *this,
+				unsigned long code,
+				void *_cmd);
+static DECLARE_WORK(modem_fatal_work, modem_fatal_fn);
+static DECLARE_DELAYED_WORK(modem_unlock_timeout_work,
+				modem_unlock_timeout);
+
+static struct notifier_block modem_notif_nb = {
+	.notifier_call = modem_notif_handler,
+};
+
+static void modem_unlock_timeout(struct work_struct *work)
+{
+	void __iomem *hwio_modem_reset_addr =
+			ioremap_nocache(MODEM_HWIO_MSS_RESET_ADDR, 8);
+	pr_crit("%s: Timeout waiting for modem to unlock.\n", MODULE_NAME);
+
+	/* Set MSS_MODEM_RESET to 0x0 since the unlock didn't work */
+	writel_relaxed(0x0, hwio_modem_reset_addr);
+	/* Write needs to go through before the modem is restarted. */
+	mb();
+	iounmap(hwio_modem_reset_addr);
+
+	subsystem_restart("modem");
+	enable_irq(MARM_WDOG_EXPIRED);
+}
+
+static void modem_fatal_fn(struct work_struct *work)
+{
+	uint32_t modem_state;
+	uint32_t panic_smsm_states = SMSM_RESET | SMSM_SYSTEM_DOWNLOAD;
+	uint32_t reset_smsm_states = SMSM_SYSTEM_REBOOT_USR |
+					SMSM_SYSTEM_PWRDWN_USR;
+
+	pr_err("%s: Watchdog bite received from modem!\n", MODULE_NAME);
+
+	modem_state = smsm_get_state(SMSM_MODEM_STATE);
+	pr_err("%s: Modem SMSM state = 0x%x!", MODULE_NAME, modem_state);
+
+	if (modem_state == 0 || modem_state & panic_smsm_states) {
+
+		subsystem_restart("modem");
+		enable_irq(MARM_WDOG_EXPIRED);
+
+	} else if (modem_state & reset_smsm_states) {
+
+		pr_err("%s: User-invoked system reset/powerdown.",
+			MODULE_NAME);
+		kernel_restart(NULL);
+
+	} else {
+
+		int ret;
+		void *hwio_modem_reset_addr =
+				ioremap_nocache(MODEM_HWIO_MSS_RESET_ADDR, 8);
+
+		pr_err("%s: Modem AHB locked up.\n", MODULE_NAME);
+		pr_err("%s: Trying to free up modem!\n", MODULE_NAME);
+
+		writel_relaxed(0x3, hwio_modem_reset_addr);
+
+		/* If we are still alive after 6 seconds (allowing for
+		 * the 5-second-delayed-panic-reboot), modem is either
+		 * still wedged or SMSM didn't come through. Force panic
+		 * in that case.
+		*/
+		ret = schedule_delayed_work(&modem_unlock_timeout_work,
+					msecs_to_jiffies(6000));
+
+		iounmap(hwio_modem_reset_addr);
+	}
+}
+
+static int modem_notif_handler(struct notifier_block *this,
+				unsigned long code,
+				void *_cmd)
+{
+	if (code == MODEM_NOTIFIER_START_RESET) {
+		if (ignore_smsm_ack) {
+			ignore_smsm_ack = 0;
+			goto out;
+		}
+		pr_err("%s: Modem error fatal'ed.", MODULE_NAME);
+		subsystem_restart("modem");
+	}
+out:
+	return NOTIFY_DONE;
+}
+
+static int modem_shutdown(const struct subsys_data *crashed_subsys)
+{
+	void __iomem *modem_wdog_addr;
+
+	/* If the modem didn't already crash, setting SMSM_RESET
+	 * here will help flush caches etc. The ignore_smsm_ack
+	 * flag is set to ignore the SMSM_RESET notification
+	 * that is generated due to the modem settings its own
+	 * SMSM_RESET bit in response to the apps setting the
+	 * apps SMSM_RESET bit.
+	 */
+	if (!(smsm_get_state(SMSM_MODEM_STATE) & SMSM_RESET)) {
+		ignore_smsm_ack = 1;
+		smsm_reset_modem(SMSM_RESET);
+	}
+
+	/* Disable the modem watchdog to allow clean modem bootup */
+	modem_wdog_addr = ioremap_nocache(MODEM_WDOG_ENABLE, 8);
+	writel_relaxed(0x0, modem_wdog_addr);
+
+	/*
+	 * The write above needs to go through before the modem is
+	 * powered up again (subsystem restart).
+	 */
+	mb();
+	iounmap(modem_wdog_addr);
+
+	/* Wait here to allow the modem to clean up caches etc. */
+	msleep(MODEM_CLEANUP_DELAY_MS);
+	pil_force_shutdown("modem");
+	disable_irq_nosync(MARM_WDOG_EXPIRED);
+
+
+
+	return 0;
+}
+
+static int modem_powerup(const struct subsys_data *crashed_subsys)
+{
+	int ret;
+
+	ret = pil_force_boot("modem");
+	enable_irq(MARM_WDOG_EXPIRED);
+
+	return ret;
+}
+
+/* FIXME: Get address, size from PIL */
+static struct ramdump_segment modem_segments[] = {
+	{0x42F00000, 0x46000000 - 0x42F00000} };
+
+static int modem_ramdump(int enable,
+				const struct subsys_data *crashed_subsys)
+{
+	if (enable)
+		return do_ramdump(modem_ramdump_dev, modem_segments,
+			ARRAY_SIZE(modem_segments));
+	else
+		return 0;
+}
+
+static void modem_crash_shutdown(
+				const struct subsys_data *crashed_subsys)
+{
+	/* If modem hasn't already crashed, send SMSM_RESET. */
+	if (!(smsm_get_state(SMSM_MODEM_STATE) & SMSM_RESET)) {
+		modem_unregister_notifier(&modem_notif_nb);
+		smsm_reset_modem(SMSM_RESET);
+	}
+
+	/* Wait to allow the modem to clean up caches etc. */
+	mdelay(5);
+}
+
+static irqreturn_t modem_wdog_bite_irq(int irq, void *dev_id)
+{
+	int ret;
+
+	ret = schedule_work(&modem_fatal_work);
+	disable_irq_nosync(MARM_WDOG_EXPIRED);
+
+	return IRQ_HANDLED;
+}
+
+static struct subsys_data subsys_8660_modem = {
+	.name = "modem",
+	.shutdown = modem_shutdown,
+	.powerup = modem_powerup,
+	.ramdump = modem_ramdump,
+	.crash_shutdown = modem_crash_shutdown
+};
+
+static int __init modem_8660_init(void)
+{
+	int ret;
+
+	/* Need to listen for SMSM_RESET always */
+	modem_register_notifier(&modem_notif_nb);
+
+#if defined(SUBSYS_FATAL_DEBUG)
+	schedule_delayed_work(&debug_crash_modem_work, msecs_to_jiffies(5000));
+#endif
+
+	ret = request_irq(MARM_WDOG_EXPIRED, modem_wdog_bite_irq,
+			IRQF_TRIGGER_RISING, "modem_wdog", NULL);
+
+	if (ret < 0) {
+		pr_err("%s: Unable to request MARM_WDOG_EXPIRED irq.",
+			__func__);
+		goto out;
+	}
+
+	modem_ramdump_dev = create_ramdump_device("modem");
+
+	if (!modem_ramdump_dev) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = ssr_register_subsystem(&subsys_8660_modem);
+out:
+	return ret;
+}
+
+static void __exit modem_8660_exit(void)
+{
+	free_irq(MARM_WDOG_EXPIRED, NULL);
+}
+
+#ifdef SUBSYS_FATAL_DEBUG
+static void debug_crash_modem_fn(struct work_struct *work)
+{
+	if (reset_modem == 1)
+		smsm_reset_modem(SMSM_RESET);
+	else if (reset_modem == 2)
+		subsystem_restart("lpass");
+
+	reset_modem = 0;
+	schedule_delayed_work(&debug_crash_modem_work, msecs_to_jiffies(1000));
+}
+#endif
+
+module_init(modem_8660_init);
+module_exit(modem_8660_exit);
+
diff --git a/arch/arm/mach-msm/modem-8960.c b/arch/arm/mach-msm/modem-8960.c
new file mode 100644
index 0000000..4922007
--- /dev/null
+++ b/arch/arm/mach-msm/modem-8960.c
@@ -0,0 +1,396 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/workqueue.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/stringify.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/debugfs.h>
+
+#include <mach/irqs.h>
+#include <mach/scm.h>
+#include <mach/peripheral-loader.h>
+#include <mach/subsystem_restart.h>
+#include <mach/subsystem_notif.h>
+#include <mach/socinfo.h>
+#include <mach/msm_smsm.h>
+
+#include "smd_private.h"
+#include "modem_notifier.h"
+#include "ramdump.h"
+
+static int crash_shutdown;
+
+#define MAX_SSR_REASON_LEN 81U
+#define Q6_FW_WDOG_ENABLE		0x08882024
+#define Q6_SW_WDOG_ENABLE		0x08982024
+
+static void log_modem_sfr(void)
+{
+	u32 size;
+	char *smem_reason, reason[MAX_SSR_REASON_LEN];
+
+	smem_reason = smem_get_entry(SMEM_SSR_REASON_MSS0, &size);
+	if (!smem_reason || !size) {
+		pr_err("modem subsystem failure reason: (unknown, smem_get_entry failed).\n");
+		return;
+	}
+	if (!smem_reason[0]) {
+		pr_err("modem subsystem failure reason: (unknown, init string found).\n");
+		return;
+	}
+
+	size = min(size, MAX_SSR_REASON_LEN-1);
+	memcpy(reason, smem_reason, size);
+	reason[size] = '\0';
+	pr_err("modem subsystem failure reason: %s.\n", reason);
+
+	smem_reason[0] = '\0';
+	wmb();
+}
+
+static void modem_wdog_check(struct work_struct *work)
+{
+	void __iomem *q6_sw_wdog_addr;
+	u32 regval;
+
+	q6_sw_wdog_addr = ioremap_nocache(Q6_SW_WDOG_ENABLE, 4);
+	if (!q6_sw_wdog_addr)
+		panic("Unable to check modem watchdog status.\n");
+
+	regval = readl_relaxed(q6_sw_wdog_addr);
+	if (!regval) {
+		pr_err("modem-8960: Modem watchdog wasn't activated!. Restarting the modem now.\n");
+		log_modem_sfr();
+		subsystem_restart("modem");
+	}
+
+	iounmap(q6_sw_wdog_addr);
+}
+
+static DECLARE_DELAYED_WORK(modem_wdog_check_work, modem_wdog_check);
+
+static void modem_sw_fatal_fn(struct work_struct *work)
+{
+	uint32_t panic_smsm_states = SMSM_RESET | SMSM_SYSTEM_DOWNLOAD;
+	uint32_t reset_smsm_states = SMSM_SYSTEM_REBOOT_USR |
+					SMSM_SYSTEM_PWRDWN_USR;
+	uint32_t modem_state;
+
+	pr_err("Watchdog bite received from modem SW!\n");
+
+	modem_state = smsm_get_state(SMSM_MODEM_STATE);
+
+	if (modem_state & panic_smsm_states) {
+
+		pr_err("Modem SMSM state changed to SMSM_RESET.\n"
+			"Probable err_fatal on the modem. "
+			"Calling subsystem restart...\n");
+		log_modem_sfr();
+		subsystem_restart("modem");
+
+	} else if (modem_state & reset_smsm_states) {
+
+		pr_err("%s: User-invoked system reset/powerdown. "
+			"Resetting the SoC now.\n",
+			__func__);
+		kernel_restart(NULL);
+	} else {
+		log_modem_sfr();
+		subsystem_restart("modem");
+	}
+}
+
+static void modem_fw_fatal_fn(struct work_struct *work)
+{
+	pr_err("Watchdog bite received from modem FW!\n");
+	log_modem_sfr();
+	subsystem_restart("modem");
+}
+
+static DECLARE_WORK(modem_sw_fatal_work, modem_sw_fatal_fn);
+static DECLARE_WORK(modem_fw_fatal_work, modem_fw_fatal_fn);
+
+static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
+{
+	/* Ignore if we're the one that set SMSM_RESET */
+	if (crash_shutdown)
+		return;
+
+	if (new_state & SMSM_RESET) {
+		pr_err("Probable fatal error on the modem.\n");
+		log_modem_sfr();
+		subsystem_restart("modem");
+	}
+}
+
+static int modem_shutdown(const struct subsys_data *subsys)
+{
+	void __iomem *q6_fw_wdog_addr;
+	void __iomem *q6_sw_wdog_addr;
+
+	/*
+	 * Cancel any pending wdog_check work items, since we're shutting
+	 * down anyway.
+	 */
+	cancel_delayed_work(&modem_wdog_check_work);
+
+	/*
+	 * Disable the modem watchdog since it keeps running even after the
+	 * modem is shutdown.
+	 */
+	q6_fw_wdog_addr = ioremap_nocache(Q6_FW_WDOG_ENABLE, 4);
+	if (!q6_fw_wdog_addr)
+		return -ENOMEM;
+
+	q6_sw_wdog_addr = ioremap_nocache(Q6_SW_WDOG_ENABLE, 4);
+	if (!q6_sw_wdog_addr) {
+		iounmap(q6_fw_wdog_addr);
+		return -ENOMEM;
+	}
+
+	writel_relaxed(0x0, q6_fw_wdog_addr);
+	writel_relaxed(0x0, q6_sw_wdog_addr);
+	mb();
+	iounmap(q6_sw_wdog_addr);
+	iounmap(q6_fw_wdog_addr);
+
+	pil_force_shutdown("modem");
+	pil_force_shutdown("modem_fw");
+	disable_irq_nosync(Q6FW_WDOG_EXPIRED_IRQ);
+	disable_irq_nosync(Q6SW_WDOG_EXPIRED_IRQ);
+
+	return 0;
+}
+
+#define MODEM_WDOG_CHECK_TIMEOUT_MS 10000
+
+static int modem_powerup(const struct subsys_data *subsys)
+{
+	pil_force_boot("modem_fw");
+	pil_force_boot("modem");
+	enable_irq(Q6FW_WDOG_EXPIRED_IRQ);
+	enable_irq(Q6SW_WDOG_EXPIRED_IRQ);
+	schedule_delayed_work(&modem_wdog_check_work,
+				msecs_to_jiffies(MODEM_WDOG_CHECK_TIMEOUT_MS));
+	return 0;
+}
+
+void modem_crash_shutdown(const struct subsys_data *subsys)
+{
+	crash_shutdown = 1;
+	smsm_reset_modem(SMSM_RESET);
+}
+
+/* FIXME: Get address, size from PIL */
+static struct ramdump_segment modemsw_segments[] = {
+	{0x89000000, 0x8D400000 - 0x89000000},
+};
+
+static struct ramdump_segment modemfw_segments[] = {
+	{0x8D400000, 0x8DA00000 - 0x8D400000},
+};
+
+static struct ramdump_segment smem_segments[] = {
+	{0x80000000, 0x00200000},
+};
+
+static void *modemfw_ramdump_dev;
+static void *modemsw_ramdump_dev;
+static void *smem_ramdump_dev;
+
+static int modem_ramdump(int enable,
+				const struct subsys_data *crashed_subsys)
+{
+	int ret = 0;
+
+	if (enable) {
+		ret = do_ramdump(modemsw_ramdump_dev, modemsw_segments,
+			ARRAY_SIZE(modemsw_segments));
+
+		if (ret < 0) {
+			pr_err("Unable to dump modem sw memory (rc = %d).\n",
+			       ret);
+			goto out;
+		}
+
+		ret = do_ramdump(modemfw_ramdump_dev, modemfw_segments,
+			ARRAY_SIZE(modemfw_segments));
+
+		if (ret < 0) {
+			pr_err("Unable to dump modem fw memory (rc = %d).\n",
+				ret);
+			goto out;
+		}
+
+		ret = do_ramdump(smem_ramdump_dev, smem_segments,
+			ARRAY_SIZE(smem_segments));
+
+		if (ret < 0) {
+			pr_err("Unable to dump smem memory (rc = %d).\n", ret);
+			goto out;
+		}
+	}
+
+out:
+	return ret;
+}
+
+static irqreturn_t modem_wdog_bite_irq(int irq, void *dev_id)
+{
+	int ret;
+
+	switch (irq) {
+
+	case Q6SW_WDOG_EXPIRED_IRQ:
+		ret = schedule_work(&modem_sw_fatal_work);
+		disable_irq_nosync(Q6SW_WDOG_EXPIRED_IRQ);
+		disable_irq_nosync(Q6FW_WDOG_EXPIRED_IRQ);
+		break;
+	case Q6FW_WDOG_EXPIRED_IRQ:
+		ret = schedule_work(&modem_fw_fatal_work);
+		disable_irq_nosync(Q6SW_WDOG_EXPIRED_IRQ);
+		disable_irq_nosync(Q6FW_WDOG_EXPIRED_IRQ);
+		break;
+	break;
+
+	default:
+		pr_err("%s: Unknown IRQ!\n", __func__);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static struct subsys_data modem_8960 = {
+	.name = "modem",
+	.shutdown = modem_shutdown,
+	.powerup = modem_powerup,
+	.ramdump = modem_ramdump,
+	.crash_shutdown = modem_crash_shutdown
+};
+
+static int modem_subsystem_restart_init(void)
+{
+	return ssr_register_subsystem(&modem_8960);
+}
+
+static int modem_debug_set(void *data, u64 val)
+{
+	if (val == 1)
+		subsystem_restart("modem");
+
+	return 0;
+}
+
+static int modem_debug_get(void *data, u64 *val)
+{
+	*val = 0;
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(modem_debug_fops, modem_debug_get, modem_debug_set,
+				"%llu\n");
+
+static int modem_debugfs_init(void)
+{
+	struct dentry *dent;
+	dent = debugfs_create_dir("modem_debug", 0);
+
+	if (IS_ERR(dent))
+		return PTR_ERR(dent);
+
+	debugfs_create_file("reset_modem", 0644, dent, NULL,
+		&modem_debug_fops);
+	return 0;
+}
+
+static int __init modem_8960_init(void)
+{
+	int ret;
+
+	if (!cpu_is_msm8960() && !cpu_is_msm8930() && !cpu_is_msm9615())
+		return -ENODEV;
+
+	ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
+		smsm_state_cb, 0);
+
+	if (ret < 0)
+		pr_err("%s: Unable to register SMSM callback! (%d)\n",
+				__func__, ret);
+
+	ret = request_irq(Q6FW_WDOG_EXPIRED_IRQ, modem_wdog_bite_irq,
+			IRQF_TRIGGER_RISING, "modem_wdog_fw", NULL);
+
+	if (ret < 0) {
+		pr_err("%s: Unable to request q6fw watchdog IRQ. (%d)\n",
+				__func__, ret);
+		goto out;
+	}
+
+	ret = request_irq(Q6SW_WDOG_EXPIRED_IRQ, modem_wdog_bite_irq,
+			IRQF_TRIGGER_RISING, "modem_wdog_sw", NULL);
+
+	if (ret < 0) {
+		pr_err("%s: Unable to request q6sw watchdog IRQ. (%d)\n",
+				__func__, ret);
+		disable_irq_nosync(Q6FW_WDOG_EXPIRED_IRQ);
+		goto out;
+	}
+
+	ret = modem_subsystem_restart_init();
+
+	if (ret < 0) {
+		pr_err("%s: Unable to reg with subsystem restart. (%d)\n",
+				__func__, ret);
+		goto out;
+	}
+
+	modemfw_ramdump_dev = create_ramdump_device("modem_fw");
+
+	if (!modemfw_ramdump_dev) {
+		pr_err("%s: Unable to create modem fw ramdump device. (%d)\n",
+				__func__, -ENOMEM);
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	modemsw_ramdump_dev = create_ramdump_device("modem_sw");
+
+	if (!modemsw_ramdump_dev) {
+		pr_err("%s: Unable to create modem sw ramdump device. (%d)\n",
+				__func__, -ENOMEM);
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	smem_ramdump_dev = create_ramdump_device("smem");
+
+	if (!smem_ramdump_dev) {
+		pr_err("%s: Unable to create smem ramdump device. (%d)\n",
+				__func__, -ENOMEM);
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = modem_debugfs_init();
+
+	pr_info("%s: modem fatal driver init'ed.\n", __func__);
+out:
+	return ret;
+}
+
+module_init(modem_8960_init);
diff --git a/arch/arm/mach-msm/modem_notifier.c b/arch/arm/mach-msm/modem_notifier.c
new file mode 100644
index 0000000..d92098b
--- /dev/null
+++ b/arch/arm/mach-msm/modem_notifier.c
@@ -0,0 +1,213 @@
+/* Copyright (c) 2008-2010, 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.
+ *
+ */
+/*
+ * Modem Restart Notifier -- Provides notification
+ *			     of modem restart events.
+ */
+
+#include <linux/notifier.h>
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <linux/workqueue.h>
+
+#include "modem_notifier.h"
+
+#define DEBUG
+
+static struct srcu_notifier_head modem_notifier_list;
+static struct workqueue_struct *modem_notifier_wq;
+
+static void notify_work_smsm_init(struct work_struct *work)
+{
+	modem_notify(0, MODEM_NOTIFIER_SMSM_INIT);
+}
+static DECLARE_WORK(modem_notifier_smsm_init_work, &notify_work_smsm_init);
+
+void modem_queue_smsm_init_notify(void)
+{
+	int ret;
+
+	ret = queue_work(modem_notifier_wq, &modem_notifier_smsm_init_work);
+
+	if (!ret)
+		printk(KERN_ERR "%s\n", __func__);
+}
+EXPORT_SYMBOL(modem_queue_smsm_init_notify);
+
+static void notify_work_start_reset(struct work_struct *work)
+{
+	modem_notify(0, MODEM_NOTIFIER_START_RESET);
+}
+static DECLARE_WORK(modem_notifier_start_reset_work, &notify_work_start_reset);
+
+void modem_queue_start_reset_notify(void)
+{
+	int ret;
+
+	ret = queue_work(modem_notifier_wq, &modem_notifier_start_reset_work);
+
+	if (!ret)
+		printk(KERN_ERR "%s\n", __func__);
+}
+EXPORT_SYMBOL(modem_queue_start_reset_notify);
+
+static void notify_work_end_reset(struct work_struct *work)
+{
+	modem_notify(0, MODEM_NOTIFIER_END_RESET);
+}
+static DECLARE_WORK(modem_notifier_end_reset_work, &notify_work_end_reset);
+
+void modem_queue_end_reset_notify(void)
+{
+	int ret;
+
+	ret = queue_work(modem_notifier_wq, &modem_notifier_end_reset_work);
+
+	if (!ret)
+		printk(KERN_ERR "%s\n", __func__);
+}
+EXPORT_SYMBOL(modem_queue_end_reset_notify);
+
+int modem_register_notifier(struct notifier_block *nb)
+{
+	int ret;
+
+	ret = srcu_notifier_chain_register(
+		&modem_notifier_list, nb);
+
+	return ret;
+}
+EXPORT_SYMBOL(modem_register_notifier);
+
+int modem_unregister_notifier(struct notifier_block *nb)
+{
+	int ret;
+
+	ret = srcu_notifier_chain_unregister(
+		&modem_notifier_list, nb);
+
+	return ret;
+}
+EXPORT_SYMBOL(modem_unregister_notifier);
+
+void modem_notify(void *data, unsigned int state)
+{
+	srcu_notifier_call_chain(&modem_notifier_list, state, data);
+}
+EXPORT_SYMBOL(modem_notify);
+
+#if defined(CONFIG_DEBUG_FS)
+static int debug_reset_start(const char __user *buf, int count)
+{
+	modem_queue_start_reset_notify();
+	return 0;
+}
+
+static int debug_reset_end(const char __user *buf, int count)
+{
+	modem_queue_end_reset_notify();
+	return 0;
+}
+
+static ssize_t debug_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *ppos)
+{
+	int (*fling)(const char __user *buf, int max) = file->private_data;
+	fling(buf, count);
+	return count;
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static const struct file_operations debug_ops = {
+	.write = debug_write,
+	.open = debug_open,
+};
+
+static void debug_create(const char *name, mode_t mode,
+			 struct dentry *dent,
+			 int (*fling)(const char __user *buf, int max))
+{
+	debugfs_create_file(name, mode, dent, fling, &debug_ops);
+}
+
+static void modem_notifier_debugfs_init(void)
+{
+	struct dentry *dent;
+
+	dent = debugfs_create_dir("modem_notifier", 0);
+	if (IS_ERR(dent))
+		return;
+
+	debug_create("reset_start", 0444, dent, debug_reset_start);
+	debug_create("reset_end", 0444, dent, debug_reset_end);
+}
+#else
+static void modem_notifier_debugfs_init(void) {}
+#endif
+
+#if defined(DEBUG)
+static int modem_notifier_test_call(struct notifier_block *this,
+				  unsigned long code,
+				  void *_cmd)
+{
+	switch (code) {
+	case MODEM_NOTIFIER_START_RESET:
+		printk(KERN_ERR "Notify: start reset\n");
+		break;
+	case MODEM_NOTIFIER_END_RESET:
+		printk(KERN_ERR "Notify: end reset\n");
+		break;
+	case MODEM_NOTIFIER_SMSM_INIT:
+		printk(KERN_ERR "Notify: smsm init\n");
+		break;
+	default:
+		printk(KERN_ERR "Notify: general\n");
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block nb = {
+	.notifier_call = modem_notifier_test_call,
+};
+
+static void register_test_notifier(void)
+{
+	modem_register_notifier(&nb);
+}
+#endif
+
+static int __init init_modem_notifier_list(void)
+{
+	srcu_init_notifier_head(&modem_notifier_list);
+	modem_notifier_debugfs_init();
+#if defined(DEBUG)
+	register_test_notifier();
+#endif
+
+	/* Create the workqueue */
+	modem_notifier_wq = create_singlethread_workqueue("modem_notifier");
+	if (!modem_notifier_wq) {
+		srcu_cleanup_notifier_head(&modem_notifier_list);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+module_init(init_modem_notifier_list);
diff --git a/arch/arm/mach-msm/modem_notifier.h b/arch/arm/mach-msm/modem_notifier.h
new file mode 100644
index 0000000..1bd2d6d
--- /dev/null
+++ b/arch/arm/mach-msm/modem_notifier.h
@@ -0,0 +1,34 @@
+/* Copyright (c) 2008-2010, 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.
+ *
+ */
+/*
+ * Modem Restart Notifier API
+ *
+ */
+
+#ifndef _MODEM_NOTIFIER_H
+#define _MODEM_NOTIFIER_H
+
+#include <linux/notifier.h>
+
+#define MODEM_NOTIFIER_START_RESET 0x1
+#define MODEM_NOTIFIER_END_RESET 0x2
+#define MODEM_NOTIFIER_SMSM_INIT 0x3
+
+extern int modem_register_notifier(struct notifier_block *nb);
+extern int modem_unregister_notifier(struct notifier_block *nb);
+extern void modem_notify(void *data, unsigned int state);
+extern void modem_queue_start_reset_notify(void);
+extern void modem_queue_end_reset_notify(void);
+extern void modem_queue_smsm_init_notify(void);
+
+#endif /* _MODEM_NOTIFIER_H */
diff --git a/arch/arm/mach-msm/mpm-8625.c b/arch/arm/mach-msm/mpm-8625.c
new file mode 100644
index 0000000..fa966d2
--- /dev/null
+++ b/arch/arm/mach-msm/mpm-8625.c
@@ -0,0 +1,304 @@
+/* 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/bitops.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/spinlock.h>
+
+#include <asm/hardware/gic.h>
+#include <mach/msm_smsm.h>
+
+#include "mpm-8625.h"
+
+#define NUM_REGS_ENABLE		2
+/* (NR_MSM_IRQS/32) 96 max irqs supported */
+#define NUM_REGS_DISABLE	3
+#define GIC_IRQ_MASK(irq)	BIT(irq % 32)
+#define GIC_IRQ_INDEX(irq)	(irq / 32)
+
+enum {
+	IRQ_DEBUG_SLEEP_INT_TRIGGER	= BIT(0),
+	IRQ_DEBUG_SLEEP_INT		= BIT(1),
+	IRQ_DEBUG_SLEEP_ABORT		= BIT(2),
+	IRQ_DEBUG_SLEEP			= BIT(3),
+	IRQ_DEBUG_SLEEP_REQUEST		= BIT(4)
+};
+
+static int msm_gic_irq_debug_mask;
+module_param_named(debug_mask, msm_gic_irq_debug_mask, int,
+		S_IRUGO | S_IWUSR | S_IWGRP);
+
+static uint32_t msm_gic_irq_smsm_wake_enable[NUM_REGS_ENABLE];
+static uint32_t msm_gic_irq_idle_disable[NUM_REGS_DISABLE];
+
+ /*
+  * Some of the interrupts which will not be considered as wake capable
+  * should be marked as FAKE.
+  * Interrupts: GPIO, Timers etc..
+  */
+#define SMSM_FAKE_IRQ	(0xff)
+
+ /* msm_gic_irq_to_smsm:  IRQ's those will be monitored by Modem */
+static uint8_t msm_gic_irq_to_smsm[NR_IRQS] = {
+	[MSM8625_INT_USB_OTG]		= 4,
+	[MSM8625_INT_PWB_I2C]		= 5,
+	[MSM8625_INT_SDC1_0]		= 6,
+	[MSM8625_INT_SDC1_1]		= 7,
+	[MSM8625_INT_SDC2_0]		= 8,
+	[MSM8625_INT_SDC2_1]		= 9,
+	[MSM8625_INT_ADSP_A9_A11]	= 10,
+	[MSM8625_INT_UART1]		= 11,
+	[MSM8625_INT_UART2]		= 12,
+	[MSM8625_INT_UART3]		= 13,
+	[MSM8625_INT_UART1_RX]		= 14,
+	[MSM8625_INT_UART2_RX]		= 15,
+	[MSM8625_INT_UART3_RX]		= 16,
+	[MSM8625_INT_UART1DM_IRQ]	= 17,
+	[MSM8625_INT_UART1DM_RX]	= 18,
+	[MSM8625_INT_KEYSENSE]		= 19,
+	[MSM8625_INT_AD_HSSD]		= 20,
+	[MSM8625_INT_NAND_WR_ER_DONE]	= 21,
+	[MSM8625_INT_NAND_OP_DONE]	= 22,
+	[MSM8625_INT_TCHSCRN1]		= 23,
+	[MSM8625_INT_TCHSCRN2]		= 24,
+	[MSM8625_INT_TCHSCRN_SSBI]	= 25,
+	[MSM8625_INT_USB_HS]		= 26,
+	[MSM8625_INT_UART2DM_RX]	= 27,
+	[MSM8625_INT_UART2DM_IRQ]	= 28,
+	[MSM8625_INT_SDC4_1]		= 29,
+	[MSM8625_INT_SDC4_0]		= 30,
+	[MSM8625_INT_SDC3_1]		= 31,
+	[MSM8625_INT_SDC3_0]		= 32,
+
+	/* fake wakeup interrupts */
+	[MSM8625_INT_GPIO_GROUP1]	= SMSM_FAKE_IRQ,
+	[MSM8625_INT_GPIO_GROUP2]	= SMSM_FAKE_IRQ,
+	[MSM8625_INT_A9_M2A_0]		= SMSM_FAKE_IRQ,
+	[MSM8625_INT_A9_M2A_1]		= SMSM_FAKE_IRQ,
+	[MSM8625_INT_A9_M2A_5]		= SMSM_FAKE_IRQ,
+	[MSM8625_INT_GP_TIMER_EXP]	= SMSM_FAKE_IRQ,
+	[MSM8625_INT_DEBUG_TIMER_EXP]	= SMSM_FAKE_IRQ,
+	[MSM8625_INT_ADSP_A11]		= SMSM_FAKE_IRQ,
+};
+
+static void msm_gic_mask_irq(struct irq_data *d)
+{
+	unsigned int index = GIC_IRQ_INDEX(d->irq);
+	uint32_t mask;
+	int smsm_irq = msm_gic_irq_to_smsm[d->irq];
+
+	mask = GIC_IRQ_MASK(d->irq);
+
+	if (smsm_irq == 0) {
+		msm_gic_irq_idle_disable[index] &= ~mask;
+	} else {
+		mask = GIC_IRQ_MASK(smsm_irq - 1);
+		msm_gic_irq_smsm_wake_enable[0] &= ~mask;
+	}
+}
+
+static void msm_gic_unmask_irq(struct irq_data *d)
+{
+	unsigned int index = GIC_IRQ_INDEX(d->irq);
+	uint32_t mask;
+	int smsm_irq = msm_gic_irq_to_smsm[d->irq];
+
+	mask = GIC_IRQ_MASK(d->irq);
+
+	if (smsm_irq == 0) {
+		msm_gic_irq_idle_disable[index] |= mask;
+	} else {
+		mask = GIC_IRQ_MASK(smsm_irq - 1);
+		msm_gic_irq_smsm_wake_enable[0] |= mask;
+	}
+}
+
+static int msm_gic_set_irq_wake(struct irq_data *d, unsigned int on)
+{
+	uint32_t mask;
+	int smsm_irq = msm_gic_irq_to_smsm[d->irq];
+
+	if (smsm_irq == 0) {
+		pr_err("bad wake up irq %d\n", d->irq);
+		return  -EINVAL;
+	}
+
+	if (smsm_irq == SMSM_FAKE_IRQ)
+		return 0;
+
+	mask = GIC_IRQ_MASK(smsm_irq - 1);
+	if (on)
+		msm_gic_irq_smsm_wake_enable[1] |= mask;
+	else
+		msm_gic_irq_smsm_wake_enable[1] &= ~mask;
+
+	return 0;
+}
+
+void __init msm_gic_irq_extn_init(void __iomem *db, void __iomem *cb)
+{
+	gic_arch_extn.irq_mask	= msm_gic_mask_irq;
+	gic_arch_extn.irq_unmask = msm_gic_unmask_irq;
+	gic_arch_extn.irq_disable = msm_gic_mask_irq;
+	gic_arch_extn.irq_set_wake = msm_gic_set_irq_wake;
+}
+
+/* Power APIs */
+
+ /*
+  * Iterate over the disable list
+  */
+
+int msm_gic_irq_idle_sleep_allowed(void)
+{
+	uint32_t i, disable = 0;
+
+	for (i = 0; i < NUM_REGS_DISABLE; i++)
+		disable |= msm_gic_irq_idle_disable[i];
+
+	return !disable;
+}
+
+ /*
+  * Prepare interrupt subsystem for entering sleep -- phase 1
+  * If modem_wake is true, return currently enabled interrupt
+  * mask in  *irq_mask
+  */
+void msm_gic_irq_enter_sleep1(bool modem_wake, int from_idle, uint32_t
+		*irq_mask)
+{
+	if (modem_wake) {
+		*irq_mask = msm_gic_irq_smsm_wake_enable[!from_idle];
+		if (msm_gic_irq_debug_mask & IRQ_DEBUG_SLEEP)
+			pr_info("%s irq_mask %x\n", __func__, *irq_mask);
+	}
+}
+
+ /*
+  * Prepare interrupt susbsytem for entering sleep -- phase 2
+  * Detect any pending interrupts and configure interrupt hardware.
+  * Return value:
+  * -EAGAIN: there are pending interrupt(s); interrupt configuration is not
+  *		changed
+  *	  0: Success
+  */
+int msm_gic_irq_enter_sleep2(bool modem_wake, int from_idle)
+{
+	if (from_idle && !modem_wake)
+		return 0;
+
+	/* edge triggered interrupt may get lost if this mode is used */
+	WARN_ON_ONCE(!modem_wake && !from_idle);
+
+	if (msm_gic_irq_debug_mask & IRQ_DEBUG_SLEEP)
+		pr_info("%s interrupts pending\n", __func__);
+
+	/* check the pending interrupts */
+	if (msm_gic_spi_ppi_pending()) {
+		if (msm_gic_irq_debug_mask & IRQ_DEBUG_SLEEP_ABORT)
+			pr_info("%s aborted....\n", __func__);
+		return -EAGAIN;
+	}
+
+	if (modem_wake) {
+		/* save the contents of GIC CPU interface and Distributor
+		 * Disable all the Interrupts, if we enter from idle pc
+		 */
+		msm_gic_save(modem_wake, from_idle);
+		irq_set_irq_type(MSM8625_INT_A9_M2A_6, IRQF_TRIGGER_RISING);
+		enable_irq(MSM8625_INT_A9_M2A_6);
+		pr_debug("%s going for sleep now\n", __func__);
+	}
+
+	return 0;
+}
+
+ /*
+  * Restore interrupt subsystem from sleep -- phase 1
+  * Configure the interrupt hardware.
+  */
+void msm_gic_irq_exit_sleep1(uint32_t irq_mask, uint32_t wakeup_reason,
+		uint32_t pending_irqs)
+{
+	/* Restore GIC contents, which were saved */
+	msm_gic_restore();
+
+	/* Disable A9_M2A_6 */
+	disable_irq(MSM8625_INT_A9_M2A_6);
+
+	if (msm_gic_irq_debug_mask & IRQ_DEBUG_SLEEP)
+		pr_info("%s %x %x %x now\n", __func__, irq_mask,
+				pending_irqs, wakeup_reason);
+}
+
+ /*
+  * Restore interrupt subsystem from sleep -- phase 2
+  * Poke the specified pending interrupts into interrupt hardware.
+  */
+void msm_gic_irq_exit_sleep2(uint32_t irq_mask, uint32_t wakeup_reason,
+			uint32_t pending)
+{
+	int i, smsm_irq, smsm_mask;
+	struct irq_desc *desc;
+
+	if (msm_gic_irq_debug_mask & IRQ_DEBUG_SLEEP)
+		pr_info("%s %x %x %x now\n", __func__, irq_mask,
+				 pending, wakeup_reason);
+
+	for (i = 0; pending && i < ARRAY_SIZE(msm_gic_irq_to_smsm); i++) {
+		smsm_irq = msm_gic_irq_to_smsm[i];
+
+		if (smsm_irq == 0)
+			continue;
+
+		smsm_mask = BIT(smsm_irq - 1);
+		if (!(pending & smsm_mask))
+			continue;
+
+		pending &= ~smsm_mask;
+
+		if (msm_gic_irq_debug_mask & IRQ_DEBUG_SLEEP_INT)
+			pr_info("%s, irq %d, still pending %x now\n",
+					__func__, i, pending);
+		/* Peding IRQ */
+		desc = i ? irq_to_desc(i) : NULL;
+
+		/* Check if the pending */
+		if (desc && !irqd_is_level_type(&desc->irq_data)) {
+			/* Mark the IRQ as pending, if not Level */
+			irq_set_pending(i);
+			check_irq_resend(desc, i);
+		}
+	}
+}
+
+ /*
+  * Restore interrupt subsystem from sleep -- phase 3
+  * Print debug information
+  */
+void msm_gic_irq_exit_sleep3(uint32_t irq_mask, uint32_t wakeup_reason,
+		uint32_t pending_irqs)
+{
+	if (msm_gic_irq_debug_mask & IRQ_DEBUG_SLEEP)
+		pr_info("%s, irq_mask %x pending_irqs %x, wakeup_reason %x,"
+				"state %x now\n", __func__, irq_mask,
+				pending_irqs, wakeup_reason,
+				smsm_get_state(SMSM_MODEM_STATE));
+}
diff --git a/arch/arm/mach-msm/mpm-8625.h b/arch/arm/mach-msm/mpm-8625.h
new file mode 100644
index 0000000..4ada9e2
--- /dev/null
+++ b/arch/arm/mach-msm/mpm-8625.h
@@ -0,0 +1,30 @@
+/* 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 _ARCH_ARM_MACH_MSM_MPM_8625_H_
+#define _ARCH_ARM_MACH_MSM_MPM_8625_H_
+
+void msm_gic_irq_extn_init(void __iomem *, void __iomem *);
+
+unsigned int msm_gic_spi_ppi_pending(void);
+int msm_gic_irq_idle_sleep_allowed(void);
+void msm_gic_irq_enter_sleep1(bool modem_wake, int from_idle, uint32_t
+		*irq_mask);
+int msm_gic_irq_enter_sleep2(bool modem_wake, int from_idle);
+void msm_gic_irq_exit_sleep1(uint32_t irq_mask, uint32_t wakeup_reason,
+		uint32_t pending_irqs);
+void msm_gic_irq_exit_sleep2(uint32_t irq_mask, uint32_t wakeup_reason,
+		uint32_t pending);
+void msm_gic_irq_exit_sleep3(uint32_t irq_mask, uint32_t wakeup_reason,
+		uint32_t pending_irqs);
+#endif
diff --git a/arch/arm/mach-msm/mpm.c b/arch/arm/mach-msm/mpm.c
new file mode 100644
index 0000000..b395b61
--- /dev/null
+++ b/arch/arm/mach-msm/mpm.c
@@ -0,0 +1,546 @@
+/* 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
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/bitmap.h>
+#include <linux/bitops.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <asm/hardware/gic.h>
+#include <mach/msm_iomap.h>
+#include <mach/gpio.h>
+
+#include <mach/mpm.h>
+
+/******************************************************************************
+ * Debug Definitions
+ *****************************************************************************/
+
+enum {
+	MSM_MPM_DEBUG_NON_DETECTABLE_IRQ = BIT(0),
+	MSM_MPM_DEBUG_PENDING_IRQ = BIT(1),
+	MSM_MPM_DEBUG_WRITE = BIT(2),
+	MSM_MPM_DEBUG_NON_DETECTABLE_IRQ_IDLE = BIT(3),
+};
+
+static int msm_mpm_debug_mask = 1;
+module_param_named(
+	debug_mask, msm_mpm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
+);
+
+/******************************************************************************
+ * Request and Status Definitions
+ *****************************************************************************/
+
+enum {
+	MSM_MPM_REQUEST_REG_ENABLE,
+	MSM_MPM_REQUEST_REG_DETECT_CTL,
+	MSM_MPM_REQUEST_REG_POLARITY,
+	MSM_MPM_REQUEST_REG_CLEAR,
+};
+
+enum {
+	MSM_MPM_STATUS_REG_PENDING,
+};
+
+/******************************************************************************
+ * IRQ Mapping Definitions
+ *****************************************************************************/
+
+#define MSM_MPM_NR_APPS_IRQS  (NR_MSM_IRQS + NR_GPIO_IRQS)
+
+#define MSM_MPM_REG_WIDTH  DIV_ROUND_UP(MSM_MPM_NR_MPM_IRQS, 32)
+#define MSM_MPM_IRQ_INDEX(irq)  (irq / 32)
+#define MSM_MPM_IRQ_MASK(irq)  BIT(irq % 32)
+
+static struct msm_mpm_device_data msm_mpm_dev_data;
+static uint8_t msm_mpm_irqs_a2m[MSM_MPM_NR_APPS_IRQS];
+
+static DEFINE_SPINLOCK(msm_mpm_lock);
+
+/*
+ * Note: the following two bitmaps only mark irqs that are _not_
+ * mappable to MPM.
+ */
+static DECLARE_BITMAP(msm_mpm_enabled_apps_irqs, MSM_MPM_NR_APPS_IRQS);
+static DECLARE_BITMAP(msm_mpm_wake_apps_irqs, MSM_MPM_NR_APPS_IRQS);
+
+static DECLARE_BITMAP(msm_mpm_gpio_irqs_mask, MSM_MPM_NR_APPS_IRQS);
+
+static uint32_t msm_mpm_enabled_irq[MSM_MPM_REG_WIDTH];
+static uint32_t msm_mpm_wake_irq[MSM_MPM_REG_WIDTH];
+static uint32_t msm_mpm_detect_ctl[MSM_MPM_REG_WIDTH];
+static uint32_t msm_mpm_polarity[MSM_MPM_REG_WIDTH];
+
+
+/******************************************************************************
+ * Low Level Functions for Accessing MPM
+ *****************************************************************************/
+
+static inline uint32_t msm_mpm_read(
+	unsigned int reg, unsigned int subreg_index)
+{
+	unsigned int offset = reg * MSM_MPM_REG_WIDTH + subreg_index;
+	return __raw_readl(msm_mpm_dev_data.mpm_status_reg_base + offset * 4);
+}
+
+static inline void msm_mpm_write(
+	unsigned int reg, unsigned int subreg_index, uint32_t value)
+{
+	unsigned int offset = reg * MSM_MPM_REG_WIDTH + subreg_index;
+	__raw_writel(value, msm_mpm_dev_data.mpm_request_reg_base + offset * 4);
+
+	if (MSM_MPM_DEBUG_WRITE & msm_mpm_debug_mask)
+		pr_info("%s: reg %u.%u: 0x%08x\n",
+			__func__, reg, subreg_index, value);
+}
+
+static inline void msm_mpm_send_interrupt(void)
+{
+	__raw_writel(msm_mpm_dev_data.mpm_apps_ipc_val,
+			msm_mpm_dev_data.mpm_apps_ipc_reg);
+	/* Ensure the write is complete before returning. */
+	mb();
+}
+
+static irqreturn_t msm_mpm_irq(int irq, void *dev_id)
+{
+	return IRQ_HANDLED;
+}
+
+/******************************************************************************
+ * MPM Access Functions
+ *****************************************************************************/
+
+static void msm_mpm_set(bool wakeset)
+{
+	uint32_t *irqs;
+	unsigned int reg;
+	int i;
+
+	irqs = wakeset ? msm_mpm_wake_irq : msm_mpm_enabled_irq;
+	for (i = 0; i < MSM_MPM_REG_WIDTH; i++) {
+		reg = MSM_MPM_REQUEST_REG_ENABLE;
+		msm_mpm_write(reg, i, irqs[i]);
+
+		reg = MSM_MPM_REQUEST_REG_DETECT_CTL;
+		msm_mpm_write(reg, i, msm_mpm_detect_ctl[i]);
+
+		reg = MSM_MPM_REQUEST_REG_POLARITY;
+		msm_mpm_write(reg, i, msm_mpm_polarity[i]);
+
+		reg = MSM_MPM_REQUEST_REG_CLEAR;
+		msm_mpm_write(reg, i, 0xffffffff);
+	}
+
+	/* Ensure that the set operation is complete before sending the
+	 * interrupt
+	 */
+	mb();
+	msm_mpm_send_interrupt();
+}
+
+static void msm_mpm_clear(void)
+{
+	int i;
+
+	for (i = 0; i < MSM_MPM_REG_WIDTH; i++) {
+		msm_mpm_write(MSM_MPM_REQUEST_REG_ENABLE, i, 0);
+		msm_mpm_write(MSM_MPM_REQUEST_REG_CLEAR, i, 0xffffffff);
+	}
+
+	/* Ensure the clear is complete before sending the interrupt */
+	mb();
+	msm_mpm_send_interrupt();
+}
+
+/******************************************************************************
+ * Interrupt Mapping Functions
+ *****************************************************************************/
+
+static inline bool msm_mpm_is_valid_apps_irq(unsigned int irq)
+{
+	return irq < ARRAY_SIZE(msm_mpm_irqs_a2m);
+}
+
+static inline uint8_t msm_mpm_get_irq_a2m(unsigned int irq)
+{
+	return msm_mpm_irqs_a2m[irq];
+}
+
+static inline void msm_mpm_set_irq_a2m(unsigned int apps_irq,
+	unsigned int mpm_irq)
+{
+	msm_mpm_irqs_a2m[apps_irq] = (uint8_t) mpm_irq;
+}
+
+static inline bool msm_mpm_is_valid_mpm_irq(unsigned int irq)
+{
+	return irq < msm_mpm_dev_data.irqs_m2a_size;
+}
+
+static inline uint16_t msm_mpm_get_irq_m2a(unsigned int irq)
+{
+	return msm_mpm_dev_data.irqs_m2a[irq];
+}
+
+static bool msm_mpm_bypass_apps_irq(unsigned int irq)
+{
+	int i;
+
+	for (i = 0; i < msm_mpm_dev_data.bypassed_apps_irqs_size; i++)
+		if (irq == msm_mpm_dev_data.bypassed_apps_irqs[i])
+			return true;
+
+	return false;
+}
+
+static int msm_mpm_enable_irq_exclusive(
+	unsigned int irq, bool enable, bool wakeset)
+{
+	uint32_t mpm_irq;
+
+	if (!msm_mpm_is_valid_apps_irq(irq))
+		return -EINVAL;
+
+	if (msm_mpm_bypass_apps_irq(irq))
+		return 0;
+
+	mpm_irq = msm_mpm_get_irq_a2m(irq);
+	if (mpm_irq) {
+		uint32_t *mpm_irq_masks = wakeset ?
+				msm_mpm_wake_irq : msm_mpm_enabled_irq;
+		uint32_t index = MSM_MPM_IRQ_INDEX(mpm_irq);
+		uint32_t mask = MSM_MPM_IRQ_MASK(mpm_irq);
+
+		if (enable)
+			mpm_irq_masks[index] |= mask;
+		else
+			mpm_irq_masks[index] &= ~mask;
+	} else {
+		unsigned long *apps_irq_bitmap = wakeset ?
+			msm_mpm_wake_apps_irqs : msm_mpm_enabled_apps_irqs;
+
+		if (enable)
+			__set_bit(irq, apps_irq_bitmap);
+		else
+			__clear_bit(irq, apps_irq_bitmap);
+	}
+
+	return 0;
+}
+
+static int msm_mpm_set_irq_type_exclusive(
+	unsigned int irq, unsigned int flow_type)
+{
+	uint32_t mpm_irq;
+
+	if (!msm_mpm_is_valid_apps_irq(irq))
+		return -EINVAL;
+
+	if (msm_mpm_bypass_apps_irq(irq))
+		return 0;
+
+	mpm_irq = msm_mpm_get_irq_a2m(irq);
+	if (mpm_irq) {
+		uint32_t index = MSM_MPM_IRQ_INDEX(mpm_irq);
+		uint32_t mask = MSM_MPM_IRQ_MASK(mpm_irq);
+
+		if (index >= MSM_MPM_REG_WIDTH)
+			return -EFAULT;
+
+		if (flow_type & IRQ_TYPE_EDGE_BOTH)
+			msm_mpm_detect_ctl[index] |= mask;
+		else
+			msm_mpm_detect_ctl[index] &= ~mask;
+
+		if (flow_type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH))
+			msm_mpm_polarity[index] |= mask;
+		else
+			msm_mpm_polarity[index] &= ~mask;
+	}
+
+	return 0;
+}
+
+static int __msm_mpm_enable_irq(unsigned int irq, unsigned int enable)
+{
+	unsigned long flags;
+	int rc;
+
+	spin_lock_irqsave(&msm_mpm_lock, flags);
+	rc = msm_mpm_enable_irq_exclusive(irq, (bool)enable, false);
+	spin_unlock_irqrestore(&msm_mpm_lock, flags);
+
+	return rc;
+}
+
+static void msm_mpm_enable_irq(struct irq_data *d)
+{
+	__msm_mpm_enable_irq(d->irq, 1);
+}
+
+static void msm_mpm_disable_irq(struct irq_data *d)
+{
+	__msm_mpm_enable_irq(d->irq, 0);
+}
+
+static int msm_mpm_set_irq_wake(struct irq_data *d, unsigned int on)
+{
+	unsigned long flags;
+	int rc;
+
+	spin_lock_irqsave(&msm_mpm_lock, flags);
+	rc = msm_mpm_enable_irq_exclusive(d->irq, (bool)on, true);
+	spin_unlock_irqrestore(&msm_mpm_lock, flags);
+
+	return rc;
+}
+
+static int msm_mpm_set_irq_type(struct irq_data *d, unsigned int flow_type)
+{
+	unsigned long flags;
+	int rc;
+
+	spin_lock_irqsave(&msm_mpm_lock, flags);
+	rc = msm_mpm_set_irq_type_exclusive(d->irq, flow_type);
+	spin_unlock_irqrestore(&msm_mpm_lock, flags);
+
+	return rc;
+}
+
+/******************************************************************************
+ * Public functions
+ *****************************************************************************/
+int msm_mpm_enable_pin(unsigned int pin, unsigned int enable)
+{
+	uint32_t index = MSM_MPM_IRQ_INDEX(pin);
+	uint32_t mask = MSM_MPM_IRQ_MASK(pin);
+	unsigned long flags;
+
+	spin_lock_irqsave(&msm_mpm_lock, flags);
+
+	if (enable)
+		msm_mpm_enabled_irq[index] |= mask;
+	else
+		msm_mpm_enabled_irq[index] &= ~mask;
+
+	spin_unlock_irqrestore(&msm_mpm_lock, flags);
+	return 0;
+}
+
+int msm_mpm_set_pin_wake(unsigned int pin, unsigned int on)
+{
+	uint32_t index = MSM_MPM_IRQ_INDEX(pin);
+	uint32_t mask = MSM_MPM_IRQ_MASK(pin);
+	unsigned long flags;
+
+	spin_lock_irqsave(&msm_mpm_lock, flags);
+
+	if (on)
+		msm_mpm_wake_irq[index] |= mask;
+	else
+		msm_mpm_wake_irq[index] &= ~mask;
+
+	spin_unlock_irqrestore(&msm_mpm_lock, flags);
+	return 0;
+}
+
+int msm_mpm_set_pin_type(unsigned int pin, unsigned int flow_type)
+{
+	uint32_t index = MSM_MPM_IRQ_INDEX(pin);
+	uint32_t mask = MSM_MPM_IRQ_MASK(pin);
+	unsigned long flags;
+
+	spin_lock_irqsave(&msm_mpm_lock, flags);
+
+	if (flow_type & IRQ_TYPE_EDGE_BOTH)
+		msm_mpm_detect_ctl[index] |= mask;
+	else
+		msm_mpm_detect_ctl[index] &= ~mask;
+
+	if (flow_type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH))
+		msm_mpm_polarity[index] |= mask;
+	else
+		msm_mpm_polarity[index] &= ~mask;
+
+	spin_unlock_irqrestore(&msm_mpm_lock, flags);
+	return 0;
+}
+
+bool msm_mpm_irqs_detectable(bool from_idle)
+{
+	unsigned long *apps_irq_bitmap;
+	int debug_mask;
+
+	if (from_idle) {
+		apps_irq_bitmap = msm_mpm_enabled_apps_irqs;
+		debug_mask = msm_mpm_debug_mask &
+					MSM_MPM_DEBUG_NON_DETECTABLE_IRQ_IDLE;
+	} else {
+		apps_irq_bitmap = msm_mpm_wake_apps_irqs;
+		debug_mask = msm_mpm_debug_mask &
+					MSM_MPM_DEBUG_NON_DETECTABLE_IRQ;
+	}
+
+	if (debug_mask) {
+		static char buf[DIV_ROUND_UP(MSM_MPM_NR_APPS_IRQS, 32)*9+1];
+
+		bitmap_scnprintf(buf, sizeof(buf), apps_irq_bitmap,
+				MSM_MPM_NR_APPS_IRQS);
+		buf[sizeof(buf) - 1] = '\0';
+
+		pr_info("%s: cannot monitor %s", __func__, buf);
+	}
+
+	return (bool)__bitmap_empty(apps_irq_bitmap, MSM_MPM_NR_APPS_IRQS);
+}
+
+bool msm_mpm_gpio_irqs_detectable(bool from_idle)
+{
+	unsigned long *apps_irq_bitmap = from_idle ?
+			msm_mpm_enabled_apps_irqs : msm_mpm_wake_apps_irqs;
+
+	return !__bitmap_intersects(msm_mpm_gpio_irqs_mask, apps_irq_bitmap,
+			MSM_MPM_NR_APPS_IRQS);
+}
+
+void msm_mpm_enter_sleep(bool from_idle)
+{
+	msm_mpm_set(!from_idle);
+}
+
+void msm_mpm_exit_sleep(bool from_idle)
+{
+	unsigned long pending;
+	int i;
+	int k;
+
+	for (i = 0; i < MSM_MPM_REG_WIDTH; i++) {
+		pending = msm_mpm_read(MSM_MPM_STATUS_REG_PENDING, i);
+
+		if (MSM_MPM_DEBUG_PENDING_IRQ & msm_mpm_debug_mask)
+			pr_info("%s: pending.%d: 0x%08lx", __func__,
+					i, pending);
+
+		k = find_first_bit(&pending, 32);
+		while (k < 32) {
+			unsigned int mpm_irq = 32 * i + k;
+			unsigned int apps_irq = msm_mpm_get_irq_m2a(mpm_irq);
+			struct irq_desc *desc = apps_irq ?
+				irq_to_desc(apps_irq) : NULL;
+
+			if (desc && !irqd_is_level_type(&desc->irq_data)) {
+				irq_set_pending(apps_irq);
+				if (from_idle)
+					check_irq_resend(desc, apps_irq);
+			}
+
+			k = find_next_bit(&pending, 32, k + 1);
+		}
+	}
+
+	msm_mpm_clear();
+}
+
+static int __init msm_mpm_early_init(void)
+{
+	uint8_t mpm_irq;
+	uint16_t apps_irq;
+
+	for (mpm_irq = 0; msm_mpm_is_valid_mpm_irq(mpm_irq); mpm_irq++) {
+		apps_irq = msm_mpm_get_irq_m2a(mpm_irq);
+		if (apps_irq && msm_mpm_is_valid_apps_irq(apps_irq))
+			msm_mpm_set_irq_a2m(apps_irq, mpm_irq);
+	}
+
+	return 0;
+}
+core_initcall(msm_mpm_early_init);
+
+void __init msm_mpm_irq_extn_init(struct msm_mpm_device_data *mpm_data)
+{
+	gic_arch_extn.irq_mask = msm_mpm_disable_irq;
+	gic_arch_extn.irq_unmask = msm_mpm_enable_irq;
+	gic_arch_extn.irq_disable = msm_mpm_disable_irq;
+	gic_arch_extn.irq_set_type = msm_mpm_set_irq_type;
+	gic_arch_extn.irq_set_wake = msm_mpm_set_irq_wake;
+
+	msm_gpio_irq_extn.irq_mask = msm_mpm_disable_irq;
+	msm_gpio_irq_extn.irq_unmask = msm_mpm_enable_irq;
+	msm_gpio_irq_extn.irq_disable = msm_mpm_disable_irq;
+	msm_gpio_irq_extn.irq_set_type = msm_mpm_set_irq_type;
+	msm_gpio_irq_extn.irq_set_wake = msm_mpm_set_irq_wake;
+
+	bitmap_set(msm_mpm_gpio_irqs_mask, NR_MSM_IRQS, NR_GPIO_IRQS);
+
+	if (!mpm_data) {
+#ifdef CONFIG_MSM_MPM
+		BUG();
+#endif
+		return;
+	}
+
+	memcpy(&msm_mpm_dev_data, mpm_data, sizeof(struct msm_mpm_device_data));
+
+	msm_mpm_dev_data.irqs_m2a =
+		kzalloc(msm_mpm_dev_data.irqs_m2a_size * sizeof(uint16_t),
+			GFP_KERNEL);
+	BUG_ON(!msm_mpm_dev_data.irqs_m2a);
+	memcpy(msm_mpm_dev_data.irqs_m2a, mpm_data->irqs_m2a,
+		msm_mpm_dev_data.irqs_m2a_size * sizeof(uint16_t));
+	msm_mpm_dev_data.bypassed_apps_irqs =
+		kzalloc(msm_mpm_dev_data.bypassed_apps_irqs_size *
+			sizeof(uint16_t), GFP_KERNEL);
+	BUG_ON(!msm_mpm_dev_data.bypassed_apps_irqs);
+	memcpy(msm_mpm_dev_data.bypassed_apps_irqs,
+		mpm_data->bypassed_apps_irqs,
+		msm_mpm_dev_data.bypassed_apps_irqs_size * sizeof(uint16_t));
+}
+
+static int __init msm_mpm_init(void)
+{
+	unsigned int irq = msm_mpm_dev_data.mpm_ipc_irq;
+	int rc;
+
+	rc = request_irq(irq, msm_mpm_irq,
+			IRQF_TRIGGER_RISING, "mpm_drv", msm_mpm_irq);
+
+	if (rc) {
+		pr_err("%s: failed to request irq %u: %d\n",
+			__func__, irq, rc);
+		goto init_bail;
+	}
+
+	rc = irq_set_irq_wake(irq, 1);
+	if (rc) {
+		pr_err("%s: failed to set wakeup irq %u: %d\n",
+			__func__, irq, rc);
+		goto init_free_bail;
+	}
+
+	return 0;
+
+init_free_bail:
+	free_irq(irq, msm_mpm_irq);
+
+init_bail:
+	return rc;
+}
+device_initcall(msm_mpm_init);
diff --git a/arch/arm/mach-msm/mpp.c b/arch/arm/mach-msm/mpp.c
new file mode 100644
index 0000000..bd70e9a
--- /dev/null
+++ b/arch/arm/mach-msm/mpp.c
@@ -0,0 +1,96 @@
+/* Copyright (c) 2008-2009, 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.
+ *
+ */
+
+/* Qualcomm PMIC Multi-Purpose Pin Configurations */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+
+#include <mach/mpp.h>
+#include <mach/proc_comm.h>
+
+int mpp_config_digital_out(unsigned mpp, unsigned config)
+{
+	int err;
+	err = msm_proc_comm(PCOM_PM_MPP_CONFIG, &mpp, &config);
+	if (err)
+		pr_err("%s: msm_proc_comm(PCOM_PM_MPP_CONFIG) failed\n",
+		       __func__);
+	return err;
+}
+EXPORT_SYMBOL(mpp_config_digital_out);
+
+int mpp_config_digital_in(unsigned mpp, unsigned config)
+{
+	int err;
+	err = msm_proc_comm(PCOM_PM_MPP_CONFIG_DIGITAL_INPUT, &mpp, &config);
+	if (err)
+		pr_err("%s: msm_proc_comm(PCOM_PM_MPP_CONFIG) failed\n",
+		       __func__);
+	return err;
+}
+EXPORT_SYMBOL(mpp_config_digital_in);
+
+#if defined(CONFIG_DEBUG_FS)
+static int test_result;
+
+static int mpp_debug_set(void *data, u64 val)
+{
+	unsigned mpp = (unsigned) data;
+
+	test_result = mpp_config_digital_out(mpp, (unsigned)val);
+	if (test_result) {
+		printk(KERN_ERR
+			   "%s: mpp_config_digital_out \
+			   [mpp(%d) = 0x%x] failed (err=%d)\n",
+			   __func__, mpp, (unsigned)val, test_result);
+	}
+	return 0;
+}
+
+static int mpp_debug_get(void *data, u64 *val)
+{
+	if (!test_result)
+		*val = 0;
+	else
+		*val = 1;
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(mpp_fops, mpp_debug_get, mpp_debug_set, "%llu\n");
+
+static int __init mpp_debug_init(void)
+{
+	struct dentry *dent;
+	int n;
+	char	file_name[16];
+
+	dent = debugfs_create_dir("mpp", 0);
+	if (IS_ERR(dent))
+		return 0;
+
+	for (n = 0; n < MPPS; n++) {
+		snprintf(file_name, sizeof(file_name), "mpp%d", n + 1);
+		debugfs_create_file(file_name, 0644, dent,
+				    (void *)n, &mpp_fops);
+	}
+
+	return 0;
+}
+
+device_initcall(mpp_debug_init);
+#endif
+
diff --git a/arch/arm/mach-msm/msm-buspm-dev.c b/arch/arm/mach-msm/msm-buspm-dev.c
new file mode 100644
index 0000000..296418d
--- /dev/null
+++ b/arch/arm/mach-msm/msm-buspm-dev.c
@@ -0,0 +1,256 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/* #define DEBUG */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/memory_alloc.h>
+#include "msm-buspm-dev.h"
+
+#define MSM_BUSPM_DRV_NAME "msm-buspm-dev"
+
+/*
+ * Allocate kernel buffer.
+ * Currently limited to one buffer per file descriptor.  If alloc() is
+ * called twice for the same descriptor, the original buffer is freed.
+ * There is also no locking protection so the same descriptor can not be shared.
+ */
+
+static inline void *msm_buspm_dev_get_vaddr(struct file *filp)
+{
+	struct msm_buspm_map_dev *dev = filp->private_data;
+
+	return (dev) ? dev->vaddr : NULL;
+}
+
+static inline unsigned long msm_buspm_dev_get_paddr(struct file *filp)
+{
+	struct msm_buspm_map_dev *dev = filp->private_data;
+
+	return (dev) ? dev->paddr : 0L;
+}
+
+static void msm_buspm_dev_free(struct file *filp)
+{
+	struct msm_buspm_map_dev *dev = filp->private_data;
+
+	if (dev) {
+		pr_debug("freeing memory at 0x%p\n", dev->vaddr);
+		free_contiguous_memory(dev->vaddr);
+		dev->paddr = 0L;
+		dev->vaddr = NULL;
+	}
+}
+
+static int msm_buspm_dev_open(struct inode *inode, struct file *filp)
+{
+	struct msm_buspm_map_dev *dev;
+
+	if (capable(CAP_SYS_ADMIN)) {
+		dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+		if (dev)
+			filp->private_data = dev;
+		else
+			return -ENOMEM;
+	} else {
+		return -EPERM;
+	}
+
+	return 0;
+}
+
+static int
+msm_buspm_dev_alloc(struct file *filp, struct buspm_alloc_params data)
+{
+	unsigned long paddr;
+	void *vaddr;
+	struct msm_buspm_map_dev *dev = filp->private_data;
+
+	/* If buffer already allocated, then free it */
+	if (dev->vaddr)
+		msm_buspm_dev_free(filp);
+
+	/* Allocate uncached memory */
+	vaddr = allocate_contiguous_ebi(data.size, PAGE_SIZE, 0);
+	paddr = (vaddr) ? memory_pool_node_paddr(vaddr) : 0L;
+
+	if (vaddr == NULL) {
+		pr_err("allocation of 0x%x bytes failed", data.size);
+		return -ENOMEM;
+	}
+
+	dev->vaddr = vaddr;
+	dev->paddr = paddr;
+	dev->buflen = data.size;
+	filp->f_pos = 0;
+	pr_debug("virt addr = 0x%p\n", dev->vaddr);
+	pr_debug("phys addr = 0x%lx\n", dev->paddr);
+
+	return 0;
+}
+
+static long
+msm_buspm_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	struct buspm_xfer_req xfer;
+	struct buspm_alloc_params alloc_data;
+	unsigned long paddr;
+	int retval = 0;
+	void *buf = msm_buspm_dev_get_vaddr(filp);
+	unsigned char *dbgbuf = buf;
+
+	switch (cmd) {
+	case MSM_BUSPM_IOC_FREE:
+		pr_debug("cmd = 0x%x (FREE)\n", cmd);
+		msm_buspm_dev_free(filp);
+		break;
+
+	case MSM_BUSPM_IOC_ALLOC:
+		pr_debug("cmd = 0x%x (ALLOC)\n", cmd);
+		retval = __get_user(alloc_data.size, (size_t __user *)arg);
+
+		if (retval == 0)
+			retval = msm_buspm_dev_alloc(filp, alloc_data);
+		break;
+
+	case MSM_BUSPM_IOC_RD_PHYS_ADDR:
+		pr_debug("Read Physical Address\n");
+		paddr = msm_buspm_dev_get_paddr(filp);
+		if (paddr == 0L) {
+			retval = -EINVAL;
+		} else {
+			pr_debug("phys addr = 0x%lx\n", paddr);
+			retval = __put_user(paddr,
+				(unsigned long __user *)arg);
+		}
+		break;
+
+	case MSM_BUSPM_IOC_RDBUF:
+		pr_debug("Read Buffer: 0x%x%x%x%x\n",
+				dbgbuf[0], dbgbuf[1], dbgbuf[2], dbgbuf[3]);
+
+		if (!buf) {
+			retval = -EINVAL;
+			break;
+		}
+
+		if (copy_from_user(&xfer, (void __user *)arg, sizeof(xfer))) {
+			retval = -EFAULT;
+			break;
+		}
+
+		if ((xfer.size <= sizeof(buf)) &&
+			(copy_to_user((void __user *)xfer.data, buf,
+					xfer.size))) {
+			retval = -EFAULT;
+			break;
+		}
+		break;
+
+	case MSM_BUSPM_IOC_WRBUF:
+		pr_debug("Write Buffer\n");
+
+		if (!buf) {
+			retval = -EINVAL;
+			break;
+		}
+
+		if (copy_from_user(&xfer, (void __user *)arg, sizeof(xfer))) {
+			retval = -EFAULT;
+			break;
+		}
+
+		if ((sizeof(buf) <= xfer.size) &&
+			(copy_from_user(buf, (void __user *)xfer.data,
+			xfer.size))) {
+			retval = -EFAULT;
+			break;
+		}
+		break;
+
+	default:
+		pr_debug("Unknown command 0x%x\n", cmd);
+		retval = -EINVAL;
+		break;
+	}
+
+	return retval;
+}
+
+static int msm_buspm_dev_release(struct inode *inode, struct file *filp)
+{
+	struct msm_buspm_map_dev *dev = filp->private_data;
+
+	msm_buspm_dev_free(filp);
+	kfree(dev);
+	filp->private_data = NULL;
+
+	return 0;
+}
+
+static int msm_buspm_dev_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	pr_debug("vma = 0x%p\n", vma);
+
+	/* Mappings are uncached */
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+		vma->vm_end - vma->vm_start, vma->vm_page_prot))
+		return -EFAULT;
+
+	return 0;
+}
+
+static const struct file_operations msm_buspm_dev_fops = {
+	.owner		= THIS_MODULE,
+	.mmap		= msm_buspm_dev_mmap,
+	.open		= msm_buspm_dev_open,
+	.unlocked_ioctl	= msm_buspm_dev_ioctl,
+	.llseek		= noop_llseek,
+	.release	= msm_buspm_dev_release,
+};
+
+struct miscdevice msm_buspm_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= MSM_BUSPM_DRV_NAME,
+	.fops	= &msm_buspm_dev_fops,
+};
+
+static int __init msm_buspm_dev_init(void)
+{
+	int ret = 0;
+
+	ret = misc_register(&msm_buspm_misc);
+	if (ret < 0)
+		pr_err("%s: Cannot register misc device\n", __func__);
+
+	return ret;
+}
+
+static void __exit msm_buspm_dev_exit(void)
+{
+	misc_deregister(&msm_buspm_misc);
+}
+module_init(msm_buspm_dev_init);
+module_exit(msm_buspm_dev_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:"MSM_BUSPM_DRV_NAME);
diff --git a/arch/arm/mach-msm/msm-buspm-dev.h b/arch/arm/mach-msm/msm-buspm-dev.h
new file mode 100644
index 0000000..5839087
--- /dev/null
+++ b/arch/arm/mach-msm/msm-buspm-dev.h
@@ -0,0 +1,50 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_BUSPM_DEV_H__
+#define __MSM_BUSPM_DEV_H__
+
+#include <linux/ioctl.h>
+
+struct msm_buspm_map_dev {
+	void            *vaddr;
+	unsigned long   paddr;
+	size_t          buflen;
+};
+
+/* Read/write data into kernel buffer */
+struct buspm_xfer_req {
+	int size;		/* Size of this request, in bytes */
+	void *data;		/* Data buffer to transfer data to/from */
+};
+
+struct buspm_alloc_params {
+	int size;
+};
+
+#define MSM_BUSPM_IOC_MAGIC	'p'
+
+#define MSM_BUSPM_IOC_FREE	\
+	_IOW(MSM_BUSPM_IOC_MAGIC, 0, void *)
+
+#define MSM_BUSPM_IOC_ALLOC	\
+	_IOW(MSM_BUSPM_IOC_MAGIC, 1, size_t)
+
+#define MSM_BUSPM_IOC_RDBUF	\
+	_IOW(MSM_BUSPM_IOC_MAGIC, 2, struct buspm_xfer_req)
+
+#define MSM_BUSPM_IOC_WRBUF	\
+	_IOW(MSM_BUSPM_IOC_MAGIC, 3, struct buspm_xfer_req)
+
+#define MSM_BUSPM_IOC_RD_PHYS_ADDR	\
+	_IOR(MSM_BUSPM_IOC_MAGIC, 4, unsigned long)
+#endif
diff --git a/arch/arm/mach-msm/msm-keypad-devices.h b/arch/arm/mach-msm/msm-keypad-devices.h
new file mode 100644
index 0000000..469564a
--- /dev/null
+++ b/arch/arm/mach-msm/msm-keypad-devices.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2009, Code Aurora Forum. 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 _MSM_KEYPAD_DEVICES_H
+#define _MSM_KEYPAD_DEVICES_H
+
+extern struct platform_device keypad_device_7k_ffa;
+extern struct platform_device keypad_device_8k_ffa;
+extern struct platform_device keypad_device_surf;
+
+#endif
diff --git a/arch/arm/mach-msm/msm-krait-l2-accessors.c b/arch/arm/mach-msm/msm-krait-l2-accessors.c
new file mode 100644
index 0000000..3d341e3
--- /dev/null
+++ b/arch/arm/mach-msm/msm-krait-l2-accessors.c
@@ -0,0 +1,84 @@
+/*
+ * 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
+ * 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/spinlock.h>
+#include <linux/module.h>
+#include <asm/mach-types.h>
+
+DEFINE_RAW_SPINLOCK(l2_access_lock);
+
+u32 set_get_l2_indirect_reg(u32 reg_addr, u32 val)
+{
+	unsigned long flags;
+	u32 ret_val;
+	/* CP15 registers are not emulated on RUMI3. */
+	if (machine_is_msm8960_rumi3())
+		return 0;
+
+	raw_spin_lock_irqsave(&l2_access_lock, flags);
+
+	mb();
+	asm volatile ("mcr     p15, 3, %[l2cpselr], c15, c0, 6\n\t"
+		      "isb\n\t"
+		      "mcr     p15, 3, %[l2cpdr],   c15, c0, 7\n\t"
+		      "isb\n\t"
+		      "mrc p15, 3, %[l2cpdr_read], c15, c0, 7\n\t"
+			: [l2cpdr_read]"=r" (ret_val)
+			: [l2cpselr]"r" (reg_addr), [l2cpdr]"r" (val)
+	);
+	raw_spin_unlock_irqrestore(&l2_access_lock, flags);
+
+	return ret_val;
+}
+EXPORT_SYMBOL(set_get_l2_indirect_reg);
+
+void set_l2_indirect_reg(u32 reg_addr, u32 val)
+{
+	unsigned long flags;
+	/* CP15 registers are not emulated on RUMI3. */
+	if (machine_is_msm8960_rumi3())
+		return;
+
+	raw_spin_lock_irqsave(&l2_access_lock, flags);
+	mb();
+	asm volatile ("mcr     p15, 3, %[l2cpselr], c15, c0, 6\n\t"
+		      "isb\n\t"
+		      "mcr     p15, 3, %[l2cpdr],   c15, c0, 7\n\t"
+		      "isb\n\t"
+			:
+			: [l2cpselr]"r" (reg_addr), [l2cpdr]"r" (val)
+	);
+	raw_spin_unlock_irqrestore(&l2_access_lock, flags);
+}
+EXPORT_SYMBOL(set_l2_indirect_reg);
+
+u32 get_l2_indirect_reg(u32 reg_addr)
+{
+	u32 val;
+	unsigned long flags;
+	/* CP15 registers are not emulated on RUMI3. */
+	if (machine_is_msm8960_rumi3())
+		return 0;
+
+	raw_spin_lock_irqsave(&l2_access_lock, flags);
+	asm volatile ("mcr     p15, 3, %[l2cpselr], c15, c0, 6\n\t"
+		      "isb\n\t"
+		      "mrc     p15, 3, %[l2cpdr],   c15, c0, 7\n\t"
+			: [l2cpdr]"=r" (val)
+			: [l2cpselr]"r" (reg_addr)
+	);
+	raw_spin_unlock_irqrestore(&l2_access_lock, flags);
+
+	return val;
+}
+EXPORT_SYMBOL(get_l2_indirect_reg);
diff --git a/arch/arm/mach-msm/msm_bus/Makefile b/arch/arm/mach-msm/msm_bus/Makefile
new file mode 100644
index 0000000..061998c
--- /dev/null
+++ b/arch/arm/mach-msm/msm_bus/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for msm-bus driver specific files
+#
+obj-y += msm_bus_core.o msm_bus_fabric.o msm_bus_config.o msm_bus_arb.o msm_bus_rpm.o
+obj-$(CONFIG_ARCH_MSM8X60) += msm_bus_board_8660.o
+obj-$(CONFIG_ARCH_MSM8960) += msm_bus_board_8960.o
+obj-$(CONFIG_ARCH_MSM9615) += msm_bus_board_9615.o
+obj-$(CONFIG_ARCH_APQ8064) += msm_bus_board_8064.o
+obj-$(CONFIG_ARCH_MSM8930) += msm_bus_board_8930.o
+obj-$(CONFIG_DEBUG_FS) += msm_bus_dbg.o
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
new file mode 100644
index 0000000..07082b7
--- /dev/null
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
@@ -0,0 +1,719 @@
+/* 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
+ * 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.
+ */
+
+#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/radix-tree.h>
+#include <linux/clk.h>
+#include <mach/msm_bus.h>
+#include "msm_bus_core.h"
+
+#define INDEX_MASK 0x0000FFFF
+#define PNODE_MASK 0xFFFF0000
+#define SHIFT_VAL 16
+#define CREATE_PNODE_ID(n, i) (((n) << SHIFT_VAL) | (i))
+#define GET_INDEX(n) ((n) & INDEX_MASK)
+#define GET_NODE(n) ((n) >> SHIFT_VAL)
+#define IS_NODE(n) ((n) % FABRIC_ID_KEY)
+#define SEL_FAB_CLK 1
+#define SEL_SLAVE_CLK 0
+
+#define BW_TO_CLK_FREQ_HZ(width, bw) ((unsigned long)\
+	DIV_ROUND_UP((bw), (width)))
+#define IS_MASTER_VALID(mas) \
+	(((mas >= MSM_BUS_MASTER_FIRST) && (mas <= MSM_BUS_MASTER_LAST)) \
+	 ? 1 : 0)
+
+#define IS_SLAVE_VALID(slv) \
+	(((slv >= MSM_BUS_SLAVE_FIRST) && (slv <= MSM_BUS_SLAVE_LAST)) ? 1 : 0)
+
+static DEFINE_MUTEX(msm_bus_lock);
+
+/**
+ * add_path_node: Adds the path information to the current node
+ * @info: Internal node info structure
+ * @next: Combination of the id and index of the next node
+ * Function returns: Number of pnodes (path_nodes) on success,
+ * error on failure.
+ *
+ * Every node maintains the list of path nodes. A path node is
+ * reached by finding the node-id and index stored at the current
+ * node. This makes updating the paths with requested bw and clock
+ * values efficient, as it avoids lookup for each update-path request.
+ */
+static int add_path_node(struct msm_bus_inode_info *info, int next)
+{
+	struct path_node *pnode;
+	int i;
+	if (ZERO_OR_NULL_PTR(info)) {
+		MSM_BUS_ERR("Cannot find node info!: id :%d\n",
+				info->node_info->priv_id);
+		return -ENXIO;
+	}
+
+	for (i = 0; i <= info->num_pnodes; i++) {
+		if (info->pnode[i].next == -2) {
+			MSM_BUS_DBG("Reusing pnode for info: %d at index: %d\n",
+				info->node_info->priv_id, i);
+			info->pnode[i].clk[DUAL_CTX] = 0;
+			info->pnode[i].clk[ACTIVE_CTX] = 0;
+			info->pnode[i].bw[DUAL_CTX] = 0;
+			info->pnode[i].bw[ACTIVE_CTX] = 0;
+			info->pnode[i].next = next;
+			MSM_BUS_DBG("%d[%d] : (%d, %d)\n",
+				info->node_info->priv_id, i, GET_NODE(next),
+				GET_INDEX(next));
+			return i;
+		}
+	}
+
+	info->num_pnodes++;
+	pnode = krealloc(info->pnode,
+		((info->num_pnodes + 1) * sizeof(struct path_node))
+		, GFP_KERNEL);
+	if (ZERO_OR_NULL_PTR(pnode)) {
+		MSM_BUS_ERR("Error creating path node!\n");
+		info->num_pnodes--;
+		return -ENOMEM;
+	}
+	info->pnode = pnode;
+	info->pnode[info->num_pnodes].clk[DUAL_CTX] = 0;
+	info->pnode[info->num_pnodes].clk[ACTIVE_CTX] = 0;
+	info->pnode[info->num_pnodes].bw[DUAL_CTX] = 0;
+	info->pnode[info->num_pnodes].bw[ACTIVE_CTX] = 0;
+	info->pnode[info->num_pnodes].next = next;
+	MSM_BUS_DBG("%d[%d] : (%d, %d)\n", info->node_info->priv_id,
+		info->num_pnodes, GET_NODE(next), GET_INDEX(next));
+	return info->num_pnodes;
+}
+
+static int clearvisitedflag(struct device *dev, void *data)
+{
+	struct msm_bus_fabric_device *fabdev = to_msm_bus_fabric_device(dev);
+	fabdev->visited = false;
+	return 0;
+}
+
+/**
+ * getpath() - Finds the path from the topology between src and dest
+ * @src: Source. This is the master from which the request originates
+ * @dest: Destination. This is the slave to which we're trying to reach
+ *
+ * Function returns: next_pnode_id. The higher 16 bits of the next_pnode_id
+ * represent the src id of the  next node on path. The lower 16 bits of the
+ * next_pnode_id represent the "index", which is the next entry in the array
+ * of pnodes for that node to fill in clk and bw values. This is created using
+ * CREATE_PNODE_ID. The return value is stored in ret_pnode, and this is added
+ * to the list of path nodes.
+ *
+ * This function recursively finds the path by updating the src to the
+ * closest possible node to dest.
+ */
+static int getpath(int src, int dest)
+{
+	int pnode_num = -1, i;
+	struct msm_bus_fabnodeinfo *fabnodeinfo;
+	struct msm_bus_fabric_device *fabdev;
+	int next_pnode_id = -1;
+	struct msm_bus_inode_info *info = NULL;
+	int _src = src/FABRIC_ID_KEY;
+	int _dst = dest/FABRIC_ID_KEY;
+	int ret_pnode = -1;
+	int fabid = GET_FABID(src);
+
+	/* Find the location of fabric for the src */
+	MSM_BUS_DBG("%d --> %d\n", src, dest);
+
+	fabdev = msm_bus_get_fabric_device(fabid);
+	if (!fabdev) {
+		MSM_BUS_WARN("Fabric Not yet registered. Try again\n");
+		return -ENXIO;
+	}
+
+	/* Are we there yet? */
+	if (src == dest) {
+		info = fabdev->algo->find_node(fabdev, src);
+		if (ZERO_OR_NULL_PTR(info)) {
+			MSM_BUS_ERR("Node %d not found\n", dest);
+			return -ENXIO;
+		}
+
+		for (i = 0; i <= info->num_pnodes; i++) {
+			if (info->pnode[i].next == -2) {
+				MSM_BUS_DBG("src = dst  Reusing pnode for"
+				" info: %d at index: %d\n",
+				info->node_info->priv_id, i);
+				next_pnode_id = CREATE_PNODE_ID(src, i);
+				info->pnode[i].clk[DUAL_CTX] = 0;
+				info->pnode[i].bw[DUAL_CTX] = 0;
+				info->pnode[i].next = next_pnode_id;
+				MSM_BUS_DBG("returning: %d, %d\n", GET_NODE
+				(next_pnode_id), GET_INDEX(next_pnode_id));
+				return next_pnode_id;
+			}
+		}
+		next_pnode_id = CREATE_PNODE_ID(src, (info->num_pnodes + 1));
+		pnode_num = add_path_node(info, next_pnode_id);
+		if (pnode_num < 0) {
+			MSM_BUS_ERR("Error adding path node\n");
+			return -ENXIO;
+		}
+		MSM_BUS_DBG("returning: %d, %d\n", GET_NODE(next_pnode_id),
+			GET_INDEX(next_pnode_id));
+		return next_pnode_id;
+	} else if (_src == _dst) {
+		/*
+		 * src and dest belong to same fabric, find the destination
+		 * from the radix tree
+		 */
+		info = fabdev->algo->find_node(fabdev, dest);
+		if (ZERO_OR_NULL_PTR(info)) {
+			MSM_BUS_ERR("Node %d not found\n", dest);
+			return -ENXIO;
+		}
+
+		ret_pnode = getpath(info->node_info->priv_id, dest);
+		next_pnode_id = ret_pnode;
+	} else {
+		/* find the dest fabric */
+		int trynextgw = true;
+		struct list_head *gateways = fabdev->algo->get_gw_list(fabdev);
+		list_for_each_entry(fabnodeinfo, gateways, list) {
+		/* see if the destination is at a connected fabric */
+			if (_dst == (fabnodeinfo->info->node_info->priv_id /
+				FABRIC_ID_KEY)) {
+				/* Found the fab on which the device exists */
+				info = fabnodeinfo->info;
+				trynextgw = false;
+				ret_pnode = getpath(info->node_info->priv_id,
+					dest);
+				pnode_num = add_path_node(info, ret_pnode);
+				if (pnode_num < 0) {
+					MSM_BUS_ERR("Error adding path node\n");
+					return -ENXIO;
+				}
+				next_pnode_id = CREATE_PNODE_ID(
+					info->node_info->priv_id, pnode_num);
+				break;
+			}
+		}
+
+		/* find the gateway */
+		if (trynextgw) {
+			gateways = fabdev->algo->get_gw_list(fabdev);
+			list_for_each_entry(fabnodeinfo, gateways, list) {
+				struct msm_bus_fabric_device *gwfab =
+					msm_bus_get_fabric_device(fabnodeinfo->
+						info->node_info->priv_id);
+				if (!gwfab->visited) {
+					MSM_BUS_DBG("VISITED ID: %d\n",
+						gwfab->id);
+					gwfab->visited = true;
+					info = fabnodeinfo->info;
+					ret_pnode = getpath(info->
+						node_info->priv_id, dest);
+					pnode_num = add_path_node(info,
+						ret_pnode);
+					if (pnode_num < 0) {
+						MSM_BUS_ERR("Malloc failure in"
+						" adding path node\n");
+						return -ENXIO;
+					}
+					next_pnode_id = CREATE_PNODE_ID(
+					info->node_info->priv_id, pnode_num);
+					break;
+				}
+			}
+			if (next_pnode_id < 0)
+				return -ENXIO;
+		}
+	}
+
+	if (!IS_NODE(src)) {
+		MSM_BUS_DBG("Returning next_pnode_id:%d[%d]\n", GET_NODE(
+			next_pnode_id), GET_INDEX(next_pnode_id));
+		return next_pnode_id;
+	}
+	info = fabdev->algo->find_node(fabdev, src);
+	if (!info) {
+		MSM_BUS_ERR("Node info not found.\n");
+		return -ENXIO;
+	}
+
+	pnode_num = add_path_node(info, next_pnode_id);
+	MSM_BUS_DBG(" Last: %d[%d] = (%d, %d)\n",
+		src, info->num_pnodes, GET_NODE(next_pnode_id),
+		GET_INDEX(next_pnode_id));
+	MSM_BUS_DBG("returning: %d, %d\n", src, pnode_num);
+	return CREATE_PNODE_ID(src, pnode_num);
+}
+
+/**
+ * update_path() - Update the path with the bandwidth and clock values, as
+ * requested by the client.
+ *
+ * @curr: Current source node, as specified in the client vector (master)
+ * @pnode: The first-hop node on the path, stored in the internal client struct
+ * @req_clk: Requested clock value from the vector
+ * @req_bw: Requested bandwidth value from the vector
+ * @curr_clk: Current clock frequency
+ * @curr_bw: Currently allocated bandwidth
+ *
+ * This function updates the nodes on the path calculated using getpath(), with
+ * clock and bandwidth values. The sum of bandwidths, and the max of clock
+ * frequencies is calculated at each node on the path. Commit data to be sent
+ * to RPM for each master and slave is also calculated here.
+ */
+static int update_path(int curr, int pnode, unsigned long req_clk, unsigned
+	long req_bw, unsigned long curr_clk, unsigned long curr_bw,
+	unsigned int ctx, unsigned int cl_active_flag)
+{
+	int index, ret = 0;
+	struct msm_bus_inode_info *info;
+	int next_pnode;
+	long int add_bw = req_bw - curr_bw;
+	unsigned bwsum = 0;
+	unsigned req_clk_hz, curr_clk_hz, bwsum_hz;
+	int *master_tiers;
+	struct msm_bus_fabric_device *fabdev = msm_bus_get_fabric_device
+		(GET_FABID(curr));
+
+	MSM_BUS_DBG("args: %d %d %d %lu %lu %lu %lu %u\n",
+		curr, GET_NODE(pnode), GET_INDEX(pnode), req_clk, req_bw,
+		curr_clk, curr_bw, ctx);
+	index = GET_INDEX(pnode);
+	MSM_BUS_DBG("Client passed index :%d\n", index);
+	info = fabdev->algo->find_node(fabdev, curr);
+	if (!info) {
+		MSM_BUS_ERR("Cannot find node info!\n");
+		return -ENXIO;
+	}
+
+	info->link_info.sel_bw = &info->link_info.bw[ctx];
+	info->link_info.sel_clk = &info->link_info.clk[ctx];
+	*info->link_info.sel_bw += add_bw;
+
+	info->pnode[index].sel_bw = &info->pnode[index].bw[ctx];
+
+	/**
+	 * To select the right clock, AND the context with
+	 * client active flag.
+	 */
+	info->pnode[index].sel_clk = &info->pnode[index].clk[ctx &
+		cl_active_flag];
+	*info->pnode[index].sel_bw += add_bw;
+
+	info->link_info.num_tiers = info->node_info->num_tiers;
+	info->link_info.tier = info->node_info->tier;
+	master_tiers = info->node_info->tier;
+
+	do {
+		struct msm_bus_inode_info *hop;
+		fabdev = msm_bus_get_fabric_device(GET_FABID(curr));
+		if (!fabdev) {
+			MSM_BUS_ERR("Fabric not found\n");
+			return -ENXIO;
+		}
+		MSM_BUS_DBG("id: %d\n", info->node_info->priv_id);
+
+		/* find next node and index */
+		next_pnode = info->pnode[index].next;
+		curr = GET_NODE(next_pnode);
+		index = GET_INDEX(next_pnode);
+		MSM_BUS_DBG("id:%d, next: %d\n", info->
+		    node_info->priv_id, curr);
+
+		/* Get hop */
+		/* check if we are here as gateway, or does the hop belong to
+		 * this fabric */
+		if (IS_NODE(curr))
+			hop = fabdev->algo->find_node(fabdev, curr);
+		else
+			hop = fabdev->algo->find_gw_node(fabdev, curr);
+		if (!hop) {
+			MSM_BUS_ERR("Null Info found for hop\n");
+			return -ENXIO;
+		}
+
+		hop->link_info.sel_bw = &hop->link_info.bw[ctx];
+		hop->link_info.sel_clk = &hop->link_info.clk[ctx];
+		*hop->link_info.sel_bw += add_bw;
+
+		hop->pnode[index].sel_bw = &hop->pnode[index].bw[ctx];
+		hop->pnode[index].sel_clk = &hop->pnode[index].clk[ctx &
+			cl_active_flag];
+
+		if (!hop->node_info->buswidth) {
+			MSM_BUS_WARN("No bus width found. Using default\n");
+			hop->node_info->buswidth = 8;
+		}
+		*hop->pnode[index].sel_clk = BW_TO_CLK_FREQ_HZ(hop->node_info->
+			buswidth, req_clk);
+		*hop->pnode[index].sel_bw += add_bw;
+		MSM_BUS_DBG("fabric: %d slave: %d, slave-width: %d info: %d\n",
+			fabdev->id, hop->node_info->priv_id, hop->node_info->
+			buswidth, info->node_info->priv_id);
+		/* Update Bandwidth */
+		fabdev->algo->update_bw(fabdev, hop, info, add_bw,
+			master_tiers, ctx);
+		bwsum = (uint16_t)*hop->link_info.sel_bw;
+		/* Update Fabric clocks */
+		curr_clk_hz = BW_TO_CLK_FREQ_HZ(hop->node_info->buswidth,
+			curr_clk);
+		req_clk_hz = BW_TO_CLK_FREQ_HZ(hop->node_info->buswidth,
+			req_clk);
+		bwsum_hz = BW_TO_CLK_FREQ_HZ(hop->node_info->buswidth,
+			bwsum);
+		MSM_BUS_DBG("Calling update-clks: curr_hz: %lu, req_hz: %lu,"
+			" bw_hz %u\n", curr_clk, req_clk, bwsum_hz);
+		ret = fabdev->algo->update_clks(fabdev, hop, index,
+			curr_clk_hz, req_clk_hz, bwsum_hz, SEL_FAB_CLK,
+			ctx, cl_active_flag);
+		if (ret)
+			MSM_BUS_WARN("Failed to update clk\n");
+		info = hop;
+	} while (GET_NODE(info->pnode[index].next) != info->node_info->priv_id);
+
+	/* Update BW, clk after exiting the loop for the last one */
+	if (!info) {
+		MSM_BUS_ERR("Cannot find node info!\n");
+		return -ENXIO;
+	}
+	/* Update slave clocks */
+	ret = fabdev->algo->update_clks(fabdev, info, index, curr_clk_hz,
+	    req_clk_hz, bwsum_hz, SEL_SLAVE_CLK, ctx, cl_active_flag);
+	if (ret)
+		MSM_BUS_ERR("Failed to update clk\n");
+	return ret;
+}
+
+/**
+ * msm_bus_commit_fn() - Commits the data for fabric to rpm
+ * @dev: fabric device
+ * @data: NULL
+ */
+static int msm_bus_commit_fn(struct device *dev, void *data)
+{
+	int ret = 0;
+	struct msm_bus_fabric_device *fabdev = to_msm_bus_fabric_device(dev);
+	MSM_BUS_DBG("Committing: fabid: %d\n", fabdev->id);
+	ret = fabdev->algo->commit(fabdev);
+	return ret;
+}
+
+/**
+ * msm_bus_scale_register_client() - Register the clients with the msm bus
+ * driver
+ * @pdata: Platform data of the client, containing src, dest, ab, ib
+ *
+ * Client data contains the vectors specifying arbitrated bandwidth (ab)
+ * and instantaneous bandwidth (ib) requested between a particular
+ * src and dest.
+ */
+uint32_t msm_bus_scale_register_client(struct msm_bus_scale_pdata *pdata)
+{
+	struct msm_bus_client *client = NULL;
+	int i;
+	int src, dest, nfab;
+	struct msm_bus_fabric_device *deffab;
+
+	deffab = msm_bus_get_fabric_device(MSM_BUS_FAB_DEFAULT);
+	if (!deffab) {
+		MSM_BUS_ERR("Error finding default fabric\n");
+		return -ENXIO;
+	}
+
+	nfab = msm_bus_get_num_fab();
+	if (nfab < deffab->board_algo->board_nfab) {
+		MSM_BUS_ERR("Can't register client!\n"
+				"Num of fabrics up: %d\n",
+				nfab);
+		return 0;
+	}
+
+	if ((!pdata) || (pdata->usecase->num_paths == 0) || IS_ERR(pdata)) {
+		MSM_BUS_ERR("Cannot register client with null data\n");
+		return 0;
+	}
+
+	client = kzalloc(sizeof(struct msm_bus_client), GFP_KERNEL);
+	if (!client) {
+		MSM_BUS_ERR("Error allocating client\n");
+		return 0;
+	}
+
+	mutex_lock(&msm_bus_lock);
+	client->pdata = pdata;
+	client->curr = -1;
+	for (i = 0; i < pdata->usecase->num_paths; i++) {
+		int *pnode;
+		struct msm_bus_fabric_device *srcfab;
+		pnode = krealloc(client->src_pnode, ((i + 1) * sizeof(int)),
+			GFP_KERNEL);
+		if (ZERO_OR_NULL_PTR(pnode)) {
+			MSM_BUS_ERR("Invalid Pnode ptr!\n");
+			continue;
+		} else
+			client->src_pnode = pnode;
+
+		if (!IS_MASTER_VALID(pdata->usecase->vectors[i].src)) {
+			MSM_BUS_ERR("Invalid Master ID %d in request!\n",
+				pdata->usecase->vectors[i].src);
+			goto err;
+		}
+
+		if (!IS_SLAVE_VALID(pdata->usecase->vectors[i].dst)) {
+			MSM_BUS_ERR("Invalid Slave ID %d in request!\n",
+				pdata->usecase->vectors[i].dst);
+			goto err;
+		}
+
+		src = msm_bus_board_get_iid(pdata->usecase->vectors[i].src);
+		if (src == -ENXIO) {
+			MSM_BUS_ERR("Master %d not supported. Client cannot be"
+				" registered\n",
+				pdata->usecase->vectors[i].src);
+			goto err;
+		}
+		dest = msm_bus_board_get_iid(pdata->usecase->vectors[i].dst);
+		if (dest == -ENXIO) {
+			MSM_BUS_ERR("Slave %d not supported. Client cannot be"
+				" registered\n",
+				pdata->usecase->vectors[i].dst);
+			goto err;
+		}
+		srcfab = msm_bus_get_fabric_device(GET_FABID(src));
+		srcfab->visited = true;
+		pnode[i] = getpath(src, dest);
+		bus_for_each_dev(&msm_bus_type, NULL, NULL, clearvisitedflag);
+		if (pnode[i] == -ENXIO) {
+			MSM_BUS_ERR("Cannot register client now! Try again!\n");
+			goto err;
+		}
+	}
+	msm_bus_dbg_client_data(client->pdata, MSM_BUS_DBG_REGISTER,
+		(uint32_t)client);
+	mutex_unlock(&msm_bus_lock);
+	MSM_BUS_DBG("ret: %u num_paths: %d\n", (uint32_t)client,
+		pdata->usecase->num_paths);
+	return (uint32_t)(client);
+err:
+	kfree(client->src_pnode);
+	kfree(client);
+	mutex_unlock(&msm_bus_lock);
+	return 0;
+}
+EXPORT_SYMBOL(msm_bus_scale_register_client);
+
+/**
+ * msm_bus_scale_client_update_request() - Update the request for bandwidth
+ * from a particular client
+ *
+ * cl: Handle to the client
+ * index: Index into the vector, to which the bw and clock values need to be
+ * updated
+ */
+int msm_bus_scale_client_update_request(uint32_t cl, unsigned index)
+{
+	int i, ret = 0;
+	struct msm_bus_scale_pdata *pdata;
+	int pnode, src, curr, ctx;
+	unsigned long req_clk, req_bw, curr_clk, curr_bw;
+	struct msm_bus_client *client = (struct msm_bus_client *)cl;
+	if (IS_ERR(client)) {
+		MSM_BUS_ERR("msm_bus_scale_client update req error %d\n",
+				(uint32_t)client);
+		return -ENXIO;
+	}
+
+	mutex_lock(&msm_bus_lock);
+	if (client->curr == index)
+		goto err;
+
+	curr = client->curr;
+	pdata = client->pdata;
+
+	if (index >= pdata->num_usecases) {
+		MSM_BUS_ERR("Client %u passed invalid index: %d\n",
+			(uint32_t)client, index);
+		ret = -ENXIO;
+		goto err;
+	}
+
+	MSM_BUS_DBG("cl: %u index: %d curr: %d"
+			" num_paths: %d\n", cl, index, client->curr,
+			client->pdata->usecase->num_paths);
+
+	for (i = 0; i < pdata->usecase->num_paths; i++) {
+		src = msm_bus_board_get_iid(client->pdata->usecase[index].
+			vectors[i].src);
+		if (src == -ENXIO) {
+			MSM_BUS_ERR("Master %d not supported. Request cannot"
+				" be updated\n", client->pdata->usecase->
+				vectors[i].src);
+			goto err;
+		}
+
+		if (msm_bus_board_get_iid(client->pdata->usecase[index].
+			vectors[i].dst) == -ENXIO) {
+			MSM_BUS_ERR("Slave %d not supported. Request cannot"
+				" be updated\n", client->pdata->usecase->
+				vectors[i].dst);
+		}
+
+		pnode = client->src_pnode[i];
+		req_clk = client->pdata->usecase[index].vectors[i].ib;
+		req_bw = client->pdata->usecase[index].vectors[i].ab;
+		if (curr < 0) {
+			curr_clk = 0;
+			curr_bw = 0;
+		} else {
+			curr_clk = client->pdata->usecase[curr].vectors[i].ib;
+			curr_bw = client->pdata->usecase[curr].vectors[i].ab;
+			MSM_BUS_DBG("ab: %lu ib: %lu\n", curr_bw, curr_clk);
+		}
+
+		if (!pdata->active_only) {
+			ret = update_path(src, pnode, req_clk, req_bw,
+				curr_clk, curr_bw, 0, pdata->active_only);
+			if (ret) {
+				MSM_BUS_ERR("Update path failed! %d\n", ret);
+				goto err;
+			}
+		}
+
+		ret = update_path(src, pnode, req_clk, req_bw, curr_clk,
+				curr_bw, ACTIVE_CTX, pdata->active_only);
+		if (ret) {
+			MSM_BUS_ERR("Update Path failed! %d\n", ret);
+			goto err;
+		}
+	}
+
+	client->curr = index;
+	ctx = ACTIVE_CTX;
+	msm_bus_dbg_client_data(client->pdata, index, cl);
+	bus_for_each_dev(&msm_bus_type, NULL, NULL, msm_bus_commit_fn);
+
+err:
+	mutex_unlock(&msm_bus_lock);
+	return ret;
+}
+EXPORT_SYMBOL(msm_bus_scale_client_update_request);
+
+int reset_pnodes(int curr, int pnode)
+{
+	struct msm_bus_inode_info *info;
+	struct msm_bus_fabric_device *fabdev;
+	int index, next_pnode;
+	fabdev = msm_bus_get_fabric_device(GET_FABID(curr));
+	index = GET_INDEX(pnode);
+	info = fabdev->algo->find_node(fabdev, curr);
+	if (!info) {
+		MSM_BUS_ERR("Cannot find node info!\n");
+		return -ENXIO;
+	}
+
+	MSM_BUS_DBG("Starting the loop--remove\n");
+	do {
+		struct msm_bus_inode_info *hop;
+		fabdev = msm_bus_get_fabric_device(GET_FABID(curr));
+		if (!fabdev) {
+			MSM_BUS_ERR("Fabric not found\n");
+				return -ENXIO;
+		}
+
+		next_pnode = info->pnode[index].next;
+		info->pnode[index].next = -2;
+		curr = GET_NODE(next_pnode);
+		index = GET_INDEX(next_pnode);
+		if (IS_NODE(curr))
+			hop = fabdev->algo->find_node(fabdev, curr);
+		else
+			hop = fabdev->algo->find_gw_node(fabdev, curr);
+		if (!hop) {
+			MSM_BUS_ERR("Null Info found for hop\n");
+			return -ENXIO;
+		}
+
+		MSM_BUS_DBG("%d[%d] = %d\n", info->node_info->priv_id, index,
+			info->pnode[index].next);
+		MSM_BUS_DBG("num_pnodes: %d: %d\n", info->node_info->priv_id,
+			info->num_pnodes);
+		info = hop;
+	} while (GET_NODE(info->pnode[index].next) != info->node_info->priv_id);
+
+	info->pnode[index].next = -2;
+	MSM_BUS_DBG("%d[%d] = %d\n", info->node_info->priv_id, index,
+		info->pnode[index].next);
+	MSM_BUS_DBG("num_pnodes: %d: %d\n", info->node_info->priv_id,
+		info->num_pnodes);
+	return 0;
+}
+
+int msm_bus_board_get_iid(int id)
+{
+	struct msm_bus_fabric_device *deffab;
+
+	deffab = msm_bus_get_fabric_device(MSM_BUS_FAB_DEFAULT);
+	if (!deffab) {
+		MSM_BUS_ERR("Error finding default fabric\n");
+		return -ENXIO;
+	}
+
+	return deffab->board_algo->get_iid(id);
+}
+
+void msm_bus_scale_client_reset_pnodes(uint32_t cl)
+{
+	int i, src, pnode, index;
+	struct msm_bus_client *client = (struct msm_bus_client *)(cl);
+	if (IS_ERR(client)) {
+		MSM_BUS_ERR("msm_bus_scale_reset_pnodes error\n");
+		return;
+	}
+	index = 0;
+	for (i = 0; i < client->pdata->usecase->num_paths; i++) {
+		src = msm_bus_board_get_iid(
+			client->pdata->usecase[index].vectors[i].src);
+		pnode = client->src_pnode[i];
+		MSM_BUS_DBG("(%d, %d)\n", GET_NODE(pnode), GET_INDEX(pnode));
+		reset_pnodes(src, pnode);
+	}
+}
+
+/**
+ * msm_bus_scale_unregister_client() - Unregister the client from the bus driver
+ * @cl: Handle to the client
+ */
+void msm_bus_scale_unregister_client(uint32_t cl)
+{
+	struct msm_bus_client *client = (struct msm_bus_client *)(cl);
+	if (IS_ERR(client) || (!client))
+		return;
+	if (client->curr != 0)
+		msm_bus_scale_client_update_request(cl, 0);
+	MSM_BUS_DBG("Unregistering client %d\n", cl);
+	mutex_lock(&msm_bus_lock);
+	msm_bus_scale_client_reset_pnodes(cl);
+	msm_bus_dbg_client_data(client->pdata, MSM_BUS_DBG_UNREGISTER, cl);
+	mutex_unlock(&msm_bus_lock);
+	kfree(client->src_pnode);
+	kfree(client);
+}
+EXPORT_SYMBOL(msm_bus_scale_unregister_client);
+
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8064.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8064.c
new file mode 100644
index 0000000..5a3d722
--- /dev/null
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8064.c
@@ -0,0 +1,975 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#include <mach/board.h>
+#include <mach/rpm.h>
+#include "msm_bus_core.h"
+
+#define NMASTERS 54
+#define NSLAVES 75
+#define NFAB_8064 5
+
+enum msm_bus_fabric_tiered_slave_type {
+	MSM_BUS_SYSTEM_TIERED_SLAVE_FAB_APPSS_0 = 1,
+	MSM_BUS_SYSTEM_TIERED_SLAVE_FAB_APPSS_1,
+	MSM_BUS_TIERED_SLAVE_SYSTEM_IMEM,
+
+	MSM_BUS_TIERED_SLAVE_MM_IMEM = 1,
+	MSM_BUS_MMSS_TIERED_SLAVE_FAB_APPS_0,
+	MSM_BUS_MMSS_TIERED_SLAVE_FAB_APPS_1,
+
+	MSM_BUS_TIERED_SLAVE_EBI1_CH0 = 1,
+	MSM_BUS_TIERED_SLAVE_EBI1_CH1,
+	MSM_BUS_TIERED_SLAVE_KMPSS_L2,
+};
+
+enum msm_bus_8064_master_ports_type {
+	MSM_BUS_SYSTEM_MASTER_PORT_APPSS_FAB = 0,
+	MSM_BUS_MASTER_PORT_SPS,
+	MSM_BUS_MASTER_PORT_ADM_PORT0,
+	MSM_BUS_MASTER_PORT_ADM_PORT1,
+	MSM_BUS_MASTER_PORT_LPASS_PROC,
+	MSM_BUS_MASTER_PORT_GSS_NAV,
+	MSM_BUS_MASTER_PORT_PCIE,
+	MSM_BUS_MASTER_PORT_RIVA,
+	MSM_BUS_MASTER_PORT_SATA,
+	MSM_BUS_MASTER_PORT_LPASS,
+	MSM_BUS_SYSTEM_MASTER_PORT_CPSS_FPB,
+	MSM_BUS_SYSTEM_MASTER_PORT_SYSTEM_FPB,
+	MSM_BUS_SYSTEM_MASTER_PORT_MMSS_FPB,
+	MSM_BUS_SYSTEM_MASTER_PORT_ADM_AHB_CI,
+	MSM_BUS_SYSTEM_MASTER_PORT_CRYPTO,
+
+	MSM_BUS_MASTER_PORT_MDP_PORT0 = 0,
+	MSM_BUS_MASTER_PORT_MDP_PORT1,
+	MSM_BUS_MASTER_PORT_GRAPHICS_3D_PORT0,
+	MSM_BUS_MASTER_PORT_ROTATOR,
+	MSM_BUS_MASTER_PORT_GRAPHICS_3D_PORT1,
+	MSM_BUS_MASTER_PORT_JPEG_DEC,
+	MSM_BUS_MASTER_PORT_VIDEO_CAP,
+	MSM_BUS_MASTER_PORT_VFE,
+	MSM_BUS_MASTER_PORT_VPE,
+	MSM_BUS_MASTER_PORT_JPEG_ENC,
+	MSM_BUS_MASTER_PORT_VIDEO_DEC,
+	MSM_BUS_MMSS_MASTER_PORT_APPS_FAB,
+	MSM_BUS_MASTER_PORT_VIDEO_ENC,
+
+	MSM_BUS_MASTER_PORT_KMPSS_M0 = 0,
+	MSM_BUS_MASTER_PORT_KMPSS_M1,
+	MSM_BUS_APPSS_MASTER_PORT_FAB_MMSS_0,
+	MSM_BUS_APPSS_MASTER_PORT_FAB_MMSS_1,
+	MSM_BUS_APPSS_MASTER_PORT_FAB_SYSTEM_0,
+	MSM_BUS_APPSS_MASTER_PORT_FAB_SYSTEM_1,
+
+};
+
+enum msm_bus_8064_slave_ports_type {
+	MSM_BUS_SLAVE_PORT_MM_IMEM = 0,
+	MSM_BUS_MMSS_SLAVE_PORT_APPS_FAB_0,
+	MSM_BUS_MMSS_SLAVE_PORT_APPS_FAB_1,
+
+	MSM_BUS_SLAVE_PORT_EBI1_CH0 = 0,
+	MSM_BUS_SLAVE_PORT_EBI1_CH1,
+	MSM_BUS_SLAVE_PORT_KMPSS_L2,
+	MSM_BUS_APPSS_SLAVE_PORT_MMSS_FAB,
+	MSM_BUS_SLAVE_PORT_SYSTEM_FAB,
+
+	MSM_BUS_SYSTEM_SLAVE_PORT_APPSS_FAB_0 = 0,
+	MSM_BUS_SYSTEM_SLAVE_PORT_APPSS_FAB_1,
+	MSM_BUS_SLAVE_PORT_SPS,
+	MSM_BUS_SLAVE_PORT_SYSTEM_IMEM,
+	MSM_BUS_SLAVE_PORT_CORESIGHT,
+	MSM_BUS_SLAVE_PORT_PCIE,
+	MSM_BUS_SLAVE_PORT_KMPSS,
+	MSM_BUS_SLAVE_PORT_GSS,
+	MSM_BUS_SLAVE_PORT_LPASS,
+	MSM_BUS_SYSTEM_SLAVE_PORT_CPSS_FPB,
+	MSM_BUS_SYSTEM_SLAVE_PORT_SYSTEM_FPB,
+	MSM_BUS_SYSTEM_SLAVE_PORT_MMSS_FPB,
+	MSM_BUS_SLAVE_PORT_RIVA,
+	MSM_BUS_SLAVE_PORT_SATA,
+	MSM_BUS_SLAVE_PORT_CRYPTO,
+};
+
+static int tier2[] = {MSM_BUS_BW_TIER2,};
+static uint32_t master_iids[NMASTERS];
+static uint32_t slave_iids[NSLAVES];
+
+static int mport_kmpss_m0[] = {MSM_BUS_MASTER_PORT_KMPSS_M0,};
+static int mport_kmpss_m1[] = {MSM_BUS_MASTER_PORT_KMPSS_M1,};
+
+static int mmss_mport_apps_fab[] = {MSM_BUS_MMSS_MASTER_PORT_APPS_FAB,};
+static int system_mport_appss_fab[] = {MSM_BUS_SYSTEM_MASTER_PORT_APPSS_FAB,};
+static int sport_ebi1_ch0[] = {
+	MSM_BUS_SLAVE_PORT_EBI1_CH0,
+	MSM_BUS_SLAVE_PORT_EBI1_CH1,
+};
+static int sport_ebi1_ch1[] = {MSM_BUS_SLAVE_PORT_EBI1_CH1,};
+static int sport_kmpss_l2[] = {MSM_BUS_SLAVE_PORT_KMPSS_L2,};
+static int appss_sport_mmss_fab[] = {MSM_BUS_APPSS_SLAVE_PORT_MMSS_FAB,};
+static int sport_system_fab[] = {MSM_BUS_SLAVE_PORT_SYSTEM_FAB,};
+
+static int tiered_slave_ebi1_ch0[] = {
+	MSM_BUS_TIERED_SLAVE_EBI1_CH0,
+	MSM_BUS_TIERED_SLAVE_EBI1_CH1,
+};
+static int tiered_slave_ebi1_ch1[] = {MSM_BUS_TIERED_SLAVE_EBI1_CH1,};
+
+static int tiered_slave_kmpss[] = {MSM_BUS_TIERED_SLAVE_KMPSS_L2,};
+
+static struct msm_bus_node_info apps_fabric_info[] = {
+	{
+		.id = MSM_BUS_MASTER_AMPSS_M0,
+		.masterp = mport_kmpss_m0,
+		.num_mports = ARRAY_SIZE(mport_kmpss_m0),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_AMPSS_M1,
+		.masterp = mport_kmpss_m1,
+		.num_mports = ARRAY_SIZE(mport_kmpss_m1),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI_CH0,
+		.slavep = sport_ebi1_ch0,
+		.num_sports = ARRAY_SIZE(sport_ebi1_ch0),
+		.tier = tiered_slave_ebi1_ch0,
+		.num_tiers = ARRAY_SIZE(tiered_slave_ebi1_ch0),
+		.buswidth = 8,
+		.slaveclk[DUAL_CTX] = "mem_clk",
+		.slaveclk[ACTIVE_CTX] = "mem_a_clk",
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI_CH1,
+		.slavep = sport_ebi1_ch1,
+		.num_sports = ARRAY_SIZE(sport_ebi1_ch1),
+		.tier = tiered_slave_ebi1_ch1,
+		.num_tiers = ARRAY_SIZE(tiered_slave_ebi1_ch1),
+		.buswidth = 8,
+		.slaveclk[DUAL_CTX] = "mem_clk",
+		.slaveclk[ACTIVE_CTX] = "mem_a_clk",
+	},
+	{
+		.id = MSM_BUS_SLAVE_AMPSS_L2,
+		.slavep = sport_kmpss_l2,
+		.num_sports = ARRAY_SIZE(sport_kmpss_l2),
+		.tier = tiered_slave_kmpss,
+		.num_tiers = ARRAY_SIZE(tiered_slave_kmpss),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_FAB_MMSS,
+		.gateway = 1,
+		.slavep = appss_sport_mmss_fab,
+		.num_sports = ARRAY_SIZE(appss_sport_mmss_fab),
+		.masterp = mmss_mport_apps_fab,
+		.num_mports = ARRAY_SIZE(mmss_mport_apps_fab),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_FAB_SYSTEM,
+		.gateway = 1,
+		.slavep = sport_system_fab,
+		.num_sports = ARRAY_SIZE(sport_system_fab),
+		.masterp = system_mport_appss_fab,
+		.num_mports = ARRAY_SIZE(system_mport_appss_fab),
+		.buswidth = 8,
+	},
+};
+
+static int mport_sps[] = {MSM_BUS_MASTER_PORT_SPS,};
+static int mport_adm_port0[] = {MSM_BUS_MASTER_PORT_ADM_PORT0,};
+static int mport_adm_port1[] = {MSM_BUS_MASTER_PORT_ADM_PORT1,};
+static int mport_gss_nav[] = {MSM_BUS_MASTER_PORT_GSS_NAV,};
+static int mport_pcie[] = {MSM_BUS_MASTER_PORT_PCIE,};
+static int mport_lpass_proc[] = {MSM_BUS_MASTER_PORT_LPASS_PROC,};
+static int mport_sata[] = {MSM_BUS_MASTER_PORT_SATA,};
+
+static int mport_riva[] = {MSM_BUS_MASTER_PORT_RIVA,};
+static int mport_crypto[] = {MSM_BUS_SYSTEM_MASTER_PORT_CRYPTO,};
+static int mport_lpass[] = {MSM_BUS_MASTER_PORT_LPASS,};
+static int system_mport_mmss_fpb[] = {MSM_BUS_SYSTEM_MASTER_PORT_MMSS_FPB,};
+static int system_mport_adm_ahb_ci[] = {MSM_BUS_SYSTEM_MASTER_PORT_ADM_AHB_CI,};
+static int appss_mport_fab_system[] = {
+	MSM_BUS_APPSS_MASTER_PORT_FAB_SYSTEM_0,
+	MSM_BUS_APPSS_MASTER_PORT_FAB_SYSTEM_1
+};
+static int mport_system_fpb[] = {MSM_BUS_SYSTEM_MASTER_PORT_SYSTEM_FPB,};
+static int system_mport_cpss_fpb[] = {MSM_BUS_SYSTEM_MASTER_PORT_CPSS_FPB,};
+
+static int system_sport_appss_fab[] = {
+	MSM_BUS_SYSTEM_SLAVE_PORT_APPSS_FAB_0,
+	MSM_BUS_SYSTEM_SLAVE_PORT_APPSS_FAB_1
+};
+static int system_sport_system_fpb[] = {MSM_BUS_SYSTEM_SLAVE_PORT_SYSTEM_FPB,};
+static int system_sport_cpss_fpb[] = {MSM_BUS_SYSTEM_SLAVE_PORT_CPSS_FPB,};
+static int sport_sps[] = {MSM_BUS_SLAVE_PORT_SPS,};
+static int sport_system_imem[] = {MSM_BUS_SLAVE_PORT_SYSTEM_IMEM,};
+static int sport_coresight[] = {MSM_BUS_SLAVE_PORT_CORESIGHT,};
+static int sport_crypto[] = {MSM_BUS_SLAVE_PORT_CRYPTO,};
+static int sport_riva[] = {MSM_BUS_SLAVE_PORT_RIVA,};
+static int sport_sata[] = {MSM_BUS_SLAVE_PORT_SATA,};
+static int sport_kmpss[] = {MSM_BUS_SLAVE_PORT_KMPSS,};
+static int sport_gss[] = {MSM_BUS_SLAVE_PORT_GSS,};
+static int sport_lpass[] = {MSM_BUS_SLAVE_PORT_LPASS,};
+static int sport_mmss_fpb[] = {MSM_BUS_SYSTEM_SLAVE_PORT_MMSS_FPB,};
+
+static int tiered_slave_system_imem[] = {MSM_BUS_TIERED_SLAVE_SYSTEM_IMEM,};
+static int system_tiered_slave_fab_appss[] = {
+	MSM_BUS_SYSTEM_TIERED_SLAVE_FAB_APPSS_0,
+	MSM_BUS_SYSTEM_TIERED_SLAVE_FAB_APPSS_1,
+};
+
+static struct msm_bus_node_info system_fabric_info[]  = {
+	{
+		.id = MSM_BUS_MASTER_SPS,
+		.masterp = mport_sps,
+		.num_mports = ARRAY_SIZE(mport_sps),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_ADM_PORT0,
+		.masterp = mport_adm_port0,
+		.num_mports = ARRAY_SIZE(mport_adm_port0),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_ADM_PORT1,
+		.masterp = mport_adm_port1,
+		.num_mports = ARRAY_SIZE(mport_adm_port1),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_LPASS_PROC,
+		.masterp = mport_lpass_proc,
+		.num_mports = ARRAY_SIZE(mport_lpass_proc),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_GSS_NAV,
+		.masterp = mport_gss_nav,
+		.num_mports = ARRAY_SIZE(mport_gss_nav),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_PCIE,
+		.masterp = mport_pcie,
+		.num_mports = ARRAY_SIZE(mport_pcie),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_RIVA,
+		.masterp = mport_riva,
+		.num_mports = ARRAY_SIZE(mport_riva),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_SATA,
+		.masterp = mport_sata,
+		.num_mports = ARRAY_SIZE(mport_sata),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_CRYPTO,
+		.masterp = mport_crypto,
+		.num_mports = ARRAY_SIZE(mport_crypto),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_LPASS,
+		.masterp = mport_lpass,
+		.num_mports = ARRAY_SIZE(mport_lpass),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_SYSTEM_MASTER_MMSS_FPB,
+		.masterp = system_mport_mmss_fpb,
+		.num_mports = ARRAY_SIZE(system_mport_mmss_fpb),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_ADM0_CI,
+		.masterp = system_mport_adm_ahb_ci,
+		.num_mports = ARRAY_SIZE(system_mport_adm_ahb_ci),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_FAB_APPSS,
+		.gateway = 1,
+		.slavep = system_sport_appss_fab,
+		.num_sports = ARRAY_SIZE(system_sport_appss_fab),
+		.masterp = appss_mport_fab_system,
+		.num_mports = ARRAY_SIZE(appss_mport_fab_system),
+		.tier = system_tiered_slave_fab_appss,
+		.num_tiers = ARRAY_SIZE(system_tiered_slave_fab_appss),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_FAB_SYSTEM_FPB,
+		.gateway = 1,
+		.slavep = system_sport_system_fpb,
+		.num_sports = ARRAY_SIZE(system_sport_system_fpb),
+		.masterp = mport_system_fpb,
+		.num_mports = ARRAY_SIZE(mport_system_fpb),
+		.buswidth = 4,
+	},
+	{
+		.id = MSM_BUS_FAB_CPSS_FPB,
+		.gateway = 1,
+		.slavep = system_sport_cpss_fpb,
+		.num_sports = ARRAY_SIZE(system_sport_cpss_fpb),
+		.masterp = system_mport_cpss_fpb,
+		.num_mports = ARRAY_SIZE(system_mport_cpss_fpb),
+		.buswidth = 4,
+	},
+	{
+		.id = MSM_BUS_SLAVE_SPS,
+		.slavep = sport_sps,
+		.num_sports = ARRAY_SIZE(sport_sps),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slaveclk[DUAL_CTX] = "dfab_clk",
+		.slaveclk[ACTIVE_CTX] = "dfab_a_clk",
+	},
+	{
+		.id = MSM_BUS_SLAVE_SYSTEM_IMEM,
+		.slavep = sport_system_imem,
+		.num_sports = ARRAY_SIZE(sport_system_imem),
+		.tier = tiered_slave_system_imem,
+		.num_tiers = ARRAY_SIZE(tiered_slave_system_imem),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_CORESIGHT,
+		.slavep = sport_coresight,
+		.num_sports = ARRAY_SIZE(sport_coresight),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_CRYPTO,
+		.slavep = sport_crypto,
+		.num_sports = ARRAY_SIZE(sport_crypto),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_RIVA,
+		.slavep = sport_riva,
+		.num_sports = ARRAY_SIZE(sport_riva),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_SATA,
+		.slavep = sport_sata,
+		.num_sports = ARRAY_SIZE(sport_sata),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_AMPSS,
+		.slavep = sport_kmpss,
+		.num_sports = ARRAY_SIZE(sport_kmpss),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSS,
+		.slavep = sport_gss,
+		.num_sports = ARRAY_SIZE(sport_gss),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_LPASS,
+		.slavep = sport_lpass,
+		.num_sports = ARRAY_SIZE(sport_lpass),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SYSTEM_SLAVE_MMSS_FPB,
+		.slavep = sport_mmss_fpb,
+		.num_sports = ARRAY_SIZE(sport_mmss_fpb),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+};
+
+static int mport_mdp[] = {
+	MSM_BUS_MASTER_PORT_MDP_PORT0,
+	MSM_BUS_MASTER_PORT_MDP_PORT1,
+};
+static int mport_mdp1[] = {MSM_BUS_MASTER_PORT_MDP_PORT1,};
+static int mport_rotator[] = {MSM_BUS_MASTER_PORT_ROTATOR,};
+static int mport_graphics_3d_port0[] = {MSM_BUS_MASTER_PORT_GRAPHICS_3D_PORT0,};
+static int mport_graphics_3d_port1[] = {MSM_BUS_MASTER_PORT_GRAPHICS_3D_PORT1,};
+static int mport_jpeg_dec[] = {MSM_BUS_MASTER_PORT_JPEG_DEC,};
+static int mport_video_cap[] = {MSM_BUS_MASTER_PORT_VIDEO_CAP,};
+static int mport_vfe[] = {MSM_BUS_MASTER_PORT_VFE,};
+static int mport_vpe[] = {MSM_BUS_MASTER_PORT_VPE,};
+static int mport_jpeg_enc[] = {MSM_BUS_MASTER_PORT_JPEG_ENC,};
+static int mport_video_enc[] = {MSM_BUS_MASTER_PORT_VIDEO_ENC,};
+static int mport_video_dec[] = {MSM_BUS_MASTER_PORT_VIDEO_DEC,};
+static int appss_mport_fab_mmss[] = {
+	MSM_BUS_APPSS_MASTER_PORT_FAB_MMSS_0,
+	MSM_BUS_APPSS_MASTER_PORT_FAB_MMSS_1
+};
+
+static int mmss_sport_apps_fab[] = {
+	MSM_BUS_MMSS_SLAVE_PORT_APPS_FAB_0,
+	MSM_BUS_MMSS_SLAVE_PORT_APPS_FAB_1
+};
+static int sport_mm_imem[] = {MSM_BUS_SLAVE_PORT_MM_IMEM,};
+
+static int mmss_tiered_slave_fab_apps[] = {
+	MSM_BUS_MMSS_TIERED_SLAVE_FAB_APPS_0,
+	MSM_BUS_MMSS_TIERED_SLAVE_FAB_APPS_1,
+};
+static int tiered_slave_mm_imem[] = {MSM_BUS_TIERED_SLAVE_MM_IMEM,};
+
+
+static struct msm_bus_node_info mmss_fabric_info[]  = {
+	{
+		.id = MSM_BUS_MASTER_MDP_PORT0,
+		.masterp = mport_mdp,
+		.num_mports = ARRAY_SIZE(mport_mdp),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_MDP_PORT1,
+		.masterp = mport_mdp1,
+		.num_mports = ARRAY_SIZE(mport_mdp1),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_ROTATOR,
+		.masterp = mport_rotator,
+		.num_mports = ARRAY_SIZE(mport_rotator),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_GRAPHICS_3D,
+		.masterp = mport_graphics_3d_port0,
+		.num_mports = ARRAY_SIZE(mport_graphics_3d_port0),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_GRAPHICS_3D_PORT1,
+		.masterp = mport_graphics_3d_port1,
+		.num_mports = ARRAY_SIZE(mport_graphics_3d_port1),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_JPEG_DEC,
+		.masterp = mport_jpeg_dec,
+		.num_mports = ARRAY_SIZE(mport_jpeg_dec),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_VIDEO_CAP,
+		.masterp = mport_video_cap,
+		.num_mports = ARRAY_SIZE(mport_video_cap),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_VIDEO_ENC,
+		.masterp = mport_video_enc,
+		.num_mports = ARRAY_SIZE(mport_video_enc),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_VFE,
+		.masterp = mport_vfe,
+		.num_mports = ARRAY_SIZE(mport_vfe),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_VPE,
+		.masterp = mport_vpe,
+		.num_mports = ARRAY_SIZE(mport_vpe),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_JPEG_ENC,
+		.masterp = mport_jpeg_enc,
+		.num_mports = ARRAY_SIZE(mport_jpeg_enc),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	/* This port has been added for V2. It is absent in V1 */
+	{
+		.id = MSM_BUS_MASTER_VIDEO_DEC,
+		.masterp = mport_video_dec,
+		.num_mports = ARRAY_SIZE(mport_video_dec),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_FAB_APPSS,
+		.gateway = 1,
+		.slavep = mmss_sport_apps_fab,
+		.num_sports = ARRAY_SIZE(mmss_sport_apps_fab),
+		.masterp = appss_mport_fab_mmss,
+		.num_mports = ARRAY_SIZE(appss_mport_fab_mmss),
+		.tier = mmss_tiered_slave_fab_apps,
+		.num_tiers = ARRAY_SIZE(mmss_tiered_slave_fab_apps),
+		.buswidth = 16,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MM_IMEM,
+		.slavep = sport_mm_imem,
+		.num_sports = ARRAY_SIZE(sport_mm_imem),
+		.tier = tiered_slave_mm_imem,
+		.num_tiers = ARRAY_SIZE(tiered_slave_mm_imem),
+		.buswidth = 8,
+	},
+};
+
+static struct msm_bus_node_info sys_fpb_fabric_info[]  = {
+	{
+		.id = MSM_BUS_FAB_SYSTEM,
+		.gateway = 1,
+		.slavep = system_sport_system_fpb,
+		.num_sports = ARRAY_SIZE(system_sport_system_fpb),
+		.masterp = mport_system_fpb,
+		.num_mports = ARRAY_SIZE(mport_system_fpb),
+		.buswidth = 4,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_MASTER_SPDM,
+		.ahb = 1,
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_RPM,
+		.ahb = 1,
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_SLAVE_SPDM,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_RPM,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_RPM_MSG_RAM,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MPM,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PMIC1_SSBI1_A,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PMIC1_SSBI1_B,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PMIC1_SSBI1_C,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PMIC2_SSBI2_A,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PMIC2_SSBI2_B,
+		.buswidth = 4,
+		.ahb = 1,
+	},
+};
+
+static struct msm_bus_node_info cpss_fpb_fabric_info[] = {
+	{
+		.id = MSM_BUS_FAB_SYSTEM,
+		.gateway = 1,
+		.slavep = system_sport_cpss_fpb,
+		.num_sports = ARRAY_SIZE(system_sport_cpss_fpb),
+		.masterp = system_mport_cpss_fpb,
+		.num_mports = ARRAY_SIZE(system_mport_cpss_fpb),
+		.buswidth = 4,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI1_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI2_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI3_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI4_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI5_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI6_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI7_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI8_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI9_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI10_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI11_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI12_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI1_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI2_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI3_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI4_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI5_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI6_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI7_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI8_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI9_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI10_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI11_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI12_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_NAND,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_CS0,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_CS1,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_CS2,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_CS3,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_CS4,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_CS5,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_USB_FS1,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_USB_FS2,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_TSIF,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MSM_TSSC,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MSM_PDM,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MSM_DIMEM,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MSM_TCSR,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MSM_PRNG,
+		.buswidth = 4,
+		.ahb = 1,
+	},
+};
+
+static void msm_bus_board_assign_iids(struct msm_bus_fabric_registration
+	*fabreg, int fabid)
+{
+	int i;
+	for (i = 0; i < fabreg->len; i++) {
+		if (!fabreg->info[i].gateway) {
+			fabreg->info[i].priv_id = fabid + fabreg->info[i].id;
+			if (fabreg->info[i].id < SLAVE_ID_KEY) {
+				WARN(fabreg->info[i].id >= NMASTERS,
+					"id %d exceeds array size!\n",
+					fabreg->info[i].id);
+				master_iids[fabreg->info[i].id] =
+					fabreg->info[i].priv_id;
+			} else {
+				WARN((fabreg->info[i].id - SLAVE_ID_KEY) >=
+					NSLAVES, "id %d exceeds array size!\n",
+					fabreg->info[i].id);
+				slave_iids[fabreg->info[i].id - (SLAVE_ID_KEY)]
+					= fabreg->info[i].priv_id;
+			}
+		} else
+			fabreg->info[i].priv_id = fabreg->info[i].id;
+	}
+}
+
+static int msm_bus_board_8064_get_iid(int id)
+{
+	if ((id < SLAVE_ID_KEY && id >= NMASTERS) ||
+		id >= (SLAVE_ID_KEY + NSLAVES)) {
+		MSM_BUS_ERR("Cannot get iid. Invalid id %d passed\n", id);
+		return -EINVAL;
+	}
+
+	return CHECK_ID(((id < SLAVE_ID_KEY) ? master_iids[id] :
+		slave_iids[id - SLAVE_ID_KEY]), id);
+}
+
+static struct msm_bus_board_algorithm msm_bus_board_algo = {
+	.board_nfab = NFAB_8064,
+	.get_iid = msm_bus_board_8064_get_iid,
+	.assign_iids = msm_bus_board_assign_iids,
+};
+
+struct msm_bus_fabric_registration msm_bus_8064_apps_fabric_pdata = {
+	.id = MSM_BUS_FAB_APPSS,
+	.name = "msm_apps_fab",
+	.info = apps_fabric_info,
+	.len = ARRAY_SIZE(apps_fabric_info),
+	.ahb = 0,
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
+	.haltid = MSM_RPM_ID_APPS_FABRIC_CFG_HALT_0,
+	.offset = MSM_RPM_ID_APPS_FABRIC_ARB_0,
+	.nmasters = 6,
+	.nslaves = 5,
+	.ntieredslaves = 3,
+	.board_algo = &msm_bus_board_algo,
+};
+
+struct msm_bus_fabric_registration msm_bus_8064_sys_fabric_pdata = {
+	.id = MSM_BUS_FAB_SYSTEM,
+	.name = "msm_sys_fab",
+	system_fabric_info,
+	ARRAY_SIZE(system_fabric_info),
+	.ahb = 0,
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
+	.haltid = MSM_RPM_ID_SYS_FABRIC_CFG_HALT_0,
+	.offset = MSM_RPM_ID_SYSTEM_FABRIC_ARB_0,
+	.nmasters = 15,
+	.nslaves = 15,
+	.ntieredslaves = 3,
+	.board_algo = &msm_bus_board_algo,
+};
+
+struct msm_bus_fabric_registration msm_bus_8064_mm_fabric_pdata = {
+	.id = MSM_BUS_FAB_MMSS,
+	.name = "msm_mm_fab",
+	mmss_fabric_info,
+	ARRAY_SIZE(mmss_fabric_info),
+	.ahb = 0,
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
+	.haltid = MSM_RPM_ID_MMSS_FABRIC_CFG_HALT_0,
+	.offset = MSM_RPM_ID_MM_FABRIC_ARB_0,
+	.nmasters = 13,
+	.nslaves = 3,
+	.ntieredslaves = 3,
+	.board_algo = &msm_bus_board_algo,
+};
+
+struct msm_bus_fabric_registration msm_bus_8064_sys_fpb_pdata = {
+	.id = MSM_BUS_FAB_SYSTEM_FPB,
+	.name = "msm_sys_fpb",
+	sys_fpb_fabric_info,
+	ARRAY_SIZE(sys_fpb_fabric_info),
+	.ahb = 1,
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
+	.nmasters = 0,
+	.nslaves = 0,
+	.ntieredslaves = 0,
+	.board_algo = &msm_bus_board_algo,
+};
+
+struct msm_bus_fabric_registration msm_bus_8064_cpss_fpb_pdata = {
+	.id = MSM_BUS_FAB_CPSS_FPB,
+	.name = "msm_cpss_fpb",
+	cpss_fpb_fabric_info,
+	ARRAY_SIZE(cpss_fpb_fabric_info),
+	.ahb = 1,
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
+	.nmasters = 0,
+	.nslaves = 0,
+	.ntieredslaves = 0,
+	.board_algo = &msm_bus_board_algo,
+};
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8660.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8660.c
new file mode 100644
index 0000000..296c6dc
--- /dev/null
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8660.c
@@ -0,0 +1,924 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#include <mach/board.h>
+#include <mach/rpm.h>
+#include "msm_bus_core.h"
+
+#define NMASTERS 39
+#define NSLAVES 68
+#define NFAB_8660 5
+
+enum msm_bus_fabric_tiered_slave_type {
+	MSM_BUS_SYSTEM_TIERED_SLAVE_FAB_APPSS = 1,
+	MSM_BUS_TIERED_SLAVE_SYSTEM_IMEM,
+
+	MSM_BUS_TIERED_SLAVE_SMI = 1,
+	MSM_BUS_MMSS_TIERED_SLAVE_FAB_APPS,
+	MSM_BUS_TIERED_SLAVE_MM_IMEM,
+
+	MSM_BUS_TIERED_SLAVE_EBI_CH0 = 1,
+	MSM_BUS_TIERED_SLAVE_SMPSS_L2,
+};
+
+enum msm_bus_8660_master_ports_type {
+	MSM_BUS_SYSTEM_MASTER_PORT_APPSS_FAB = 0,
+	MSM_BUS_MASTER_PORT_SPS,
+	MSM_BUS_MASTER_PORT_ADM0_PORT0,
+	MSM_BUS_MASTER_PORT_ADM0_PORT1,
+	MSM_BUS_MASTER_PORT_ADM1_PORT0,
+	MSM_BUS_MASTER_PORT_ADM1_PORT1,
+	MSM_BUS_MASTER_PORT_LPASS_PROC,
+	MSM_BUS_MASTER_PORT_MSS_PROCI,
+	MSM_BUS_MASTER_PORT_MSM_MSS_PROCD,
+	MSM_BUS_MASTER_PORT_MSM_MDM_PORT0,
+	MSM_BUS_MASTER_PORT_LPASS,
+	MSM_BUS_SYSTEM_MASTER_PORT_CPSS_FPB,
+	MSM_BUS_MASTER_PORT_SYSTEM_FPB,
+	MSM_BUS_MASTER_PORT_MMSS_FPB,
+	MSM_BUS_MASTER_PORT_ADM1_AHB_CI,
+	MSM_BUS_MASTER_PORT_ADM0_AHB_CI,
+	MSM_BUS_MASTER_PORT_MSS_MDM_PORT1,
+
+	MSM_BUS_MASTER_PORT_MDP_PORT0 = 0,
+	MSM_BUS_MASTER_PORT_MDP_PORT1,
+	MSM_BUS_MMSS_MASTER_PORT_ADM1_PORT0,
+	MSM_BUS_MASTER_PORT_ROTATOR,
+	MSM_BUS_MASTER_PORT_GRAPHICS_3D,
+	MSM_BUS_MASTER_PORT_JPEG_DEC,
+	MSM_BUS_MASTER_PORT_GRAPHICS_2D_CORE0,
+	MSM_BUS_MASTER_PORT_VFE,
+	MSM_BUS_MASTER_PORT_VPE,
+	MSM_BUS_MASTER_PORT_JPEG_ENC,
+	MSM_BUS_MASTER_PORT_GRAPHICS_2D_CORE1,
+	MSM_BUS_MMSS_MASTER_PORT_APPS_FAB,
+	MSM_BUS_MASTER_PORT_HD_CODEC_PORT0,
+	MSM_BUS_MASTER_PORT_HD_CODEC_PORT1,
+
+	MSM_BUS_MASTER_PORT_SMPSS_M0 = 0,
+	MSM_BUS_MASTER_PORT_SMPSS_M1,
+	MSM_BUS_APPSS_MASTER_PORT_FAB_MMSS,
+	MSM_BUS_APPSS_MASTER_PORT_FAB_SYSTEM,
+
+};
+
+static int tier2[] = {MSM_BUS_BW_TIER2,};
+
+enum msm_bus_8660_slave_ports_type {
+	MSM_BUS_SLAVE_PORT_SMI = 0,
+	MSM_BUS_MMSS_SLAVE_PORT_APPS_FAB_0,
+	MSM_BUS_MMSS_SLAVE_PORT_APPS_FAB_1,
+	MSM_BUS_SLAVE_PORT_MM_IMEM,
+
+	MSM_BUS_SLAVE_PORT_EBI_CH0 = 0,
+	MSM_BUS_SLAVE_PORT_SMPSS_L2,
+	MSM_BUS_APPSS_SLAVE_PORT_MMSS_FAB,
+	MSM_BUS_SLAVE_PORT_SYSTEM_FAB,
+
+	MSM_BUS_SYSTEM_SLAVE_PORT_APPSS_FAB = 0,
+	MSM_BUS_SLAVE_PORT_SPS,
+	MSM_BUS_SLAVE_PORT_SYSTEM_IMEM,
+	MSM_BUS_SLAVE_PORT_SMPSS,
+	MSM_BUS_SLAVE_PORT_MSS,
+	MSM_BUS_SLAVE_PORT_LPASS,
+	MSM_BUS_SYSTEM_SLAVE_PORT_CPSS_FPB,
+	MSM_BUS_SYSTEM_SLAVE_PORT_SYSTEM_FPB,
+	MSM_BUS_SLAVE_PORT_MMSS_FPB,
+};
+
+static uint32_t master_iids[NMASTERS];
+static uint32_t slave_iids[NSLAVES];
+
+static int ampss_m0_mports[] = {MSM_BUS_MASTER_PORT_SMPSS_M0,};
+static int ampss_m1_mports[] = {MSM_BUS_MASTER_PORT_SMPSS_M1,};
+static int mmss_mport_apps_fab[] = {MSM_BUS_MMSS_MASTER_PORT_APPS_FAB,};
+static int system_mport_appss_fab[] = {MSM_BUS_SYSTEM_MASTER_PORT_APPSS_FAB,};
+
+static int sport_ebi_ch0[] = {MSM_BUS_SLAVE_PORT_EBI_CH0,};
+static int sport_smpss_l2[] = {MSM_BUS_SLAVE_PORT_SMPSS_L2,};
+static int appss_sport_mmss_fab[] = {MSM_BUS_APPSS_SLAVE_PORT_MMSS_FAB,};
+static int sport_system_fab[] = {MSM_BUS_SLAVE_PORT_SYSTEM_FAB,};
+
+static int tiered_slave_ebi[] = {MSM_BUS_TIERED_SLAVE_EBI_CH0,};
+static int tiered_slave_smpss[] = {MSM_BUS_TIERED_SLAVE_SMPSS_L2,};
+
+static struct msm_bus_node_info apps_fabric_info[] = {
+	{
+		.id = MSM_BUS_MASTER_AMPSS_M0,
+		.masterp = ampss_m0_mports,
+		.num_mports = ARRAY_SIZE(ampss_m0_mports),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_AMPSS_M1,
+		.masterp = ampss_m1_mports,
+		.num_mports = ARRAY_SIZE(ampss_m1_mports),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI_CH0,
+		.slavep = sport_ebi_ch0,
+		.num_sports = ARRAY_SIZE(sport_ebi_ch0),
+		.tier = tiered_slave_ebi,
+		.num_tiers = ARRAY_SIZE(tiered_slave_ebi),
+		.buswidth = 8,
+		.slaveclk[DUAL_CTX] = "mem_clk",
+		.slaveclk[ACTIVE_CTX] = "mem_a_clk",
+	},
+	{
+		.id = MSM_BUS_SLAVE_AMPSS_L2,
+		.slavep = sport_smpss_l2,
+		.num_sports = ARRAY_SIZE(sport_smpss_l2),
+		.tier = tiered_slave_smpss,
+		.num_tiers = ARRAY_SIZE(tiered_slave_smpss),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_FAB_MMSS,
+		.gateway = 1,
+		.slavep = appss_sport_mmss_fab,
+		.num_sports = ARRAY_SIZE(appss_sport_mmss_fab),
+		.masterp = mmss_mport_apps_fab,
+		.num_mports = ARRAY_SIZE(mmss_mport_apps_fab),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_FAB_SYSTEM,
+		.gateway = 1,
+		.slavep = sport_system_fab,
+		.num_sports = ARRAY_SIZE(sport_system_fab),
+		.masterp = system_mport_appss_fab,
+		.num_mports = ARRAY_SIZE(system_mport_appss_fab),
+		.buswidth = 8,
+	},
+};
+
+static int mport_sps[] = {MSM_BUS_MASTER_PORT_SPS,};
+static int mport_adm0_port0[] = {MSM_BUS_MASTER_PORT_ADM0_PORT0,};
+static int mport_adm0_port1[] = {MSM_BUS_MASTER_PORT_ADM0_PORT1,};
+static int mport_adm1_port0[] = {MSM_BUS_MASTER_PORT_ADM1_PORT0,};
+static int mport_adm1_port1[] = {MSM_BUS_MASTER_PORT_ADM1_PORT1,};
+static int mport_lpass_proc[] = {MSM_BUS_MASTER_PORT_LPASS_PROC,};
+static int mport_mss_proci[] = {MSM_BUS_MASTER_PORT_MSS_PROCI,};
+static int mport_msm_mss_procd[] = {MSM_BUS_MASTER_PORT_MSM_MSS_PROCD,};
+static int mport_mss_mdm_port0[] = {MSM_BUS_MASTER_PORT_MSM_MDM_PORT0,};
+static int mport_lpass[] = {MSM_BUS_MASTER_PORT_LPASS,};
+static int mport_mmss_fpb[] = {MSM_BUS_MASTER_PORT_MMSS_FPB,};
+static int mport_adm1_ahb_ci[] = {MSM_BUS_MASTER_PORT_ADM1_AHB_CI,};
+static int mport_adm0_ahb_ci[] = {MSM_BUS_MASTER_PORT_ADM0_AHB_CI,};
+static int mport_mss_mdm_port1[] = {MSM_BUS_MASTER_PORT_MSS_MDM_PORT1,};
+static int appss_mport_fab_system[] = {MSM_BUS_APPSS_MASTER_PORT_FAB_SYSTEM,};
+static int mport_system_fpb[] = {MSM_BUS_MASTER_PORT_SYSTEM_FPB,};
+static int system_mport_cpss_fpb[] = {MSM_BUS_SYSTEM_MASTER_PORT_CPSS_FPB,};
+
+static int system_sport_appss_fab[] = {MSM_BUS_SYSTEM_SLAVE_PORT_APPSS_FAB,};
+static int system_sport_system_fpb[] = {MSM_BUS_SYSTEM_SLAVE_PORT_SYSTEM_FPB,};
+static int system_sport_cpss_fpb[] = {MSM_BUS_SYSTEM_SLAVE_PORT_CPSS_FPB,};
+static int sport_sps[] = {MSM_BUS_SLAVE_PORT_SPS,};
+static int sport_system_imem[] = {MSM_BUS_SLAVE_PORT_SYSTEM_IMEM,};
+static int sport_smpss[] = {MSM_BUS_SLAVE_PORT_SMPSS,};
+static int sport_mss[] = {MSM_BUS_SLAVE_PORT_MSS,};
+static int sport_lpass[] = {MSM_BUS_SLAVE_PORT_LPASS,};
+static int sport_mmss_fpb[] = {MSM_BUS_SLAVE_PORT_MMSS_FPB,};
+
+static int tiered_slave_system_imem[] = {MSM_BUS_TIERED_SLAVE_SYSTEM_IMEM,};
+static int system_tiered_slave_fab_appss[] = {
+	MSM_BUS_SYSTEM_TIERED_SLAVE_FAB_APPSS,};
+
+static struct msm_bus_node_info system_fabric_info[]  = {
+	{
+		.id = MSM_BUS_MASTER_SPS,
+		.masterp = mport_sps,
+		.num_mports = ARRAY_SIZE(mport_sps),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_ADM_PORT0,
+		.masterp = mport_adm0_port0,
+		.num_mports = ARRAY_SIZE(mport_adm0_port0),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_ADM_PORT1,
+		.masterp = mport_adm0_port1,
+		.num_mports = ARRAY_SIZE(mport_adm0_port1),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_SYSTEM_MASTER_ADM1_PORT0,
+		.masterp = mport_adm1_port0,
+		.num_mports = ARRAY_SIZE(mport_adm1_port0),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_ADM1_PORT1,
+		.masterp = mport_adm1_port1,
+		.num_mports = ARRAY_SIZE(mport_adm1_port1),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_LPASS_PROC,
+		.masterp = mport_lpass_proc,
+		.num_mports = ARRAY_SIZE(mport_lpass_proc),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_MSS_PROCI,
+		.masterp = mport_mss_proci,
+		.num_mports = ARRAY_SIZE(mport_mss_proci),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_MSS_PROCD,
+		.masterp = mport_msm_mss_procd,
+		.num_mports = ARRAY_SIZE(mport_msm_mss_procd),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_MSS_MDM_PORT0,
+		.masterp = mport_mss_mdm_port0,
+		.num_mports = ARRAY_SIZE(mport_mss_mdm_port0),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_LPASS,
+		.masterp = mport_lpass,
+		.num_mports = ARRAY_SIZE(mport_lpass),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_SYSTEM_MASTER_MMSS_FPB,
+		.masterp = mport_mmss_fpb,
+		.num_mports = ARRAY_SIZE(mport_mmss_fpb),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_ADM1_CI,
+		.masterp = mport_adm1_ahb_ci,
+		.num_mports = ARRAY_SIZE(mport_adm1_ahb_ci),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_ADM0_CI,
+		.masterp = mport_adm0_ahb_ci,
+		.num_mports = ARRAY_SIZE(mport_adm0_ahb_ci),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_MSS_MDM_PORT1,
+		.masterp = mport_mss_mdm_port1,
+		.num_mports = ARRAY_SIZE(mport_mss_mdm_port1),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_FAB_APPSS,
+		.gateway = 1,
+		.slavep = system_sport_appss_fab,
+		.num_sports = ARRAY_SIZE(system_sport_appss_fab),
+		.masterp = appss_mport_fab_system,
+		.num_mports = ARRAY_SIZE(appss_mport_fab_system),
+		.tier = system_tiered_slave_fab_appss,
+		.num_tiers = ARRAY_SIZE(system_tiered_slave_fab_appss),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_FAB_SYSTEM_FPB,
+		.gateway = 1,
+		.slavep = system_sport_system_fpb,
+		.num_sports = ARRAY_SIZE(system_sport_system_fpb),
+		.masterp = mport_system_fpb,
+		.num_mports = ARRAY_SIZE(mport_system_fpb),
+		.buswidth = 4,
+	},
+	{
+		.id = MSM_BUS_FAB_CPSS_FPB,
+		.gateway = 1,
+		.slavep = system_sport_cpss_fpb,
+		.num_sports = ARRAY_SIZE(system_sport_cpss_fpb),
+		.masterp = system_mport_cpss_fpb,
+		.num_mports = ARRAY_SIZE(system_mport_cpss_fpb),
+		.buswidth = 4,
+	},
+	{
+		.id = MSM_BUS_SLAVE_SPS,
+		.slavep = sport_sps,
+		.num_sports = ARRAY_SIZE(sport_sps),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_SYSTEM_IMEM,
+		.slavep = sport_system_imem,
+		.num_sports = ARRAY_SIZE(sport_system_imem),
+		.tier = tiered_slave_system_imem,
+		.num_tiers = ARRAY_SIZE(tiered_slave_system_imem),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_AMPSS,
+		.slavep = sport_smpss,
+		.num_sports = ARRAY_SIZE(sport_smpss),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MSS,
+		.slavep = sport_mss,
+		.num_sports = ARRAY_SIZE(sport_mss),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_LPASS,
+		.slavep = sport_lpass,
+		.num_sports = ARRAY_SIZE(sport_lpass),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SYSTEM_SLAVE_MMSS_FPB,
+		.slavep = sport_mmss_fpb,
+		.num_sports = ARRAY_SIZE(sport_mmss_fpb),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+};
+
+static int mport_mdp_port0[] = {MSM_BUS_MASTER_PORT_MDP_PORT0,};
+static int mport_mdp_port1[] = {MSM_BUS_MASTER_PORT_MDP_PORT1,};
+static int mmss_mport_adm1_port0[] = {MSM_BUS_MMSS_MASTER_PORT_ADM1_PORT0,};
+static int mport_rotator[] = {MSM_BUS_MASTER_PORT_ROTATOR,};
+static int mport_graphics_3d[] = {MSM_BUS_MASTER_PORT_GRAPHICS_3D,};
+static int mport_jpeg_dec[] = {MSM_BUS_MASTER_PORT_JPEG_DEC,};
+static int mport_graphics_2d_core0[] = {MSM_BUS_MASTER_PORT_GRAPHICS_2D_CORE0,};
+static int mport_vfe[] = {MSM_BUS_MASTER_PORT_VFE,};
+static int mport_vpe[] = {MSM_BUS_MASTER_PORT_VPE,};
+static int mport_jpeg_enc[] = {MSM_BUS_MASTER_PORT_JPEG_ENC,};
+static int mport_graphics_2d_core1[] = {MSM_BUS_MASTER_PORT_GRAPHICS_2D_CORE1,};
+static int mport_hd_codec_port0[] = {MSM_BUS_MASTER_PORT_HD_CODEC_PORT0,};
+static int mport_hd_codec_port1[] = {MSM_BUS_MASTER_PORT_HD_CODEC_PORT1,};
+static int appss_mport_fab_mmss[] = {MSM_BUS_APPSS_MASTER_PORT_FAB_MMSS,};
+
+static int sport_smi[] = {MSM_BUS_SLAVE_PORT_SMI,};
+static int mmss_sport_apps_fab_0[] = {MSM_BUS_MMSS_SLAVE_PORT_APPS_FAB_0,};
+static int sport_mm_imem[] = {MSM_BUS_SLAVE_PORT_MM_IMEM,};
+
+static int tiered_slave_smi[] = {MSM_BUS_TIERED_SLAVE_SMI,};
+static int mmss_tiered_slave_fab_apps[] = {MSM_BUS_MMSS_TIERED_SLAVE_FAB_APPS,};
+static int tiered_slave_mm_imem[] = {MSM_BUS_TIERED_SLAVE_MM_IMEM,};
+
+static struct msm_bus_node_info mmss_fabric_info[]  = {
+	{
+		.id = MSM_BUS_MASTER_MDP_PORT0,
+		.masterp = mport_mdp_port0,
+		.num_mports = ARRAY_SIZE(mport_mdp_port0),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_MDP_PORT1,
+		.masterp = mport_mdp_port1,
+		.num_mports = ARRAY_SIZE(mport_mdp_port1),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MMSS_MASTER_ADM1_PORT0,
+		.masterp = mmss_mport_adm1_port0,
+		.num_mports = ARRAY_SIZE(mmss_mport_adm1_port0),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_ROTATOR,
+		.masterp = mport_rotator,
+		.num_mports = ARRAY_SIZE(mport_rotator),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_GRAPHICS_3D,
+		.masterp = mport_graphics_3d,
+		.num_mports = ARRAY_SIZE(mport_graphics_3d),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_JPEG_DEC,
+		.masterp = mport_jpeg_dec,
+		.num_mports = ARRAY_SIZE(mport_jpeg_dec),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_GRAPHICS_2D_CORE0,
+		.masterp = mport_graphics_2d_core0,
+		.num_mports = ARRAY_SIZE(mport_graphics_2d_core0),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_VFE,
+		.masterp = mport_vfe,
+		.num_mports = ARRAY_SIZE(mport_vfe),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_VPE,
+		.masterp = mport_vpe,
+		.num_mports = ARRAY_SIZE(mport_vpe),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_JPEG_ENC,
+		.masterp = mport_jpeg_enc,
+		.num_mports = ARRAY_SIZE(mport_jpeg_enc),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	/* This port has been added for V2. It is absent in V1 */
+	{
+		.id = MSM_BUS_MASTER_GRAPHICS_2D_CORE1,
+		.masterp = mport_graphics_2d_core1,
+		.num_mports = ARRAY_SIZE(mport_graphics_2d_core1),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.masterp = mport_hd_codec_port0,
+		.num_mports = ARRAY_SIZE(mport_hd_codec_port0),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.masterp = mport_hd_codec_port1,
+		.num_mports = ARRAY_SIZE(mport_hd_codec_port1),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_SLAVE_SMI,
+		.slavep = sport_smi,
+		.num_sports = ARRAY_SIZE(sport_smi),
+		.tier = tiered_slave_smi,
+		.num_tiers = ARRAY_SIZE(tiered_slave_smi),
+		.buswidth = 16,
+		.slaveclk[DUAL_CTX] = "smi_clk",
+		.slaveclk[ACTIVE_CTX] = "smi_a_clk",
+	},
+	{
+		.id = MSM_BUS_MMSS_SLAVE_FAB_APPS_1,
+		.slavep = mmss_sport_apps_fab_0,
+		.num_sports = ARRAY_SIZE(mmss_sport_apps_fab_0),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_FAB_APPSS,
+		.gateway = 1,
+		.slavep = mmss_sport_apps_fab_0,
+		.num_sports = ARRAY_SIZE(mmss_sport_apps_fab_0),
+		.masterp = appss_mport_fab_mmss,
+		.num_mports = ARRAY_SIZE(appss_mport_fab_mmss),
+		.tier = mmss_tiered_slave_fab_apps,
+		.num_tiers = ARRAY_SIZE(mmss_tiered_slave_fab_apps),
+		.buswidth = 16,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MM_IMEM,
+		.slavep = sport_mm_imem,
+		.num_sports = ARRAY_SIZE(sport_mm_imem),
+		.tier = tiered_slave_mm_imem,
+		.num_tiers = ARRAY_SIZE(tiered_slave_mm_imem),
+		.buswidth = 8,
+	},
+};
+
+static struct msm_bus_node_info sys_fpb_fabric_info[]  = {
+	{
+		.id = MSM_BUS_FAB_SYSTEM,
+		.gateway = 1,
+		.slavep = system_sport_system_fpb,
+		.num_sports = ARRAY_SIZE(system_sport_system_fpb),
+		.masterp = mport_system_fpb,
+		.num_mports = ARRAY_SIZE(mport_system_fpb),
+		.buswidth = 4,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_MASTER_SPDM,
+		.ahb = 1,
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_RPM,
+		.ahb = 1,
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_SLAVE_SPDM,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_RPM,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_RPM_MSG_RAM,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MPM,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PMIC1_SSBI1_A,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PMIC1_SSBI1_B,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PMIC1_SSBI1_C,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PMIC2_SSBI2_A,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PMIC2_SSBI2_B,
+		.buswidth = 4,
+		.ahb = 1,
+	},
+};
+
+static struct msm_bus_node_info cpss_fpb_fabric_info[] = {
+	{
+		.id = MSM_BUS_FAB_SYSTEM,
+		.gateway = 1,
+		.slavep = system_sport_cpss_fpb,
+		.num_sports = ARRAY_SIZE(system_sport_cpss_fpb),
+		.masterp = system_mport_cpss_fpb,
+		.num_mports = ARRAY_SIZE(system_mport_cpss_fpb),
+		.buswidth = 4,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI1_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI2_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI3_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI4_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI5_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI6_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI7_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI8_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI9_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI10_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI11_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI12_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI1_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI2_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI3_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI4_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI5_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI6_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI7_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI8_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI9_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI10_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI11_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI12_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_NAND,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_CS0,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_CS1,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_CS2,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_CS3,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_CS4,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_CS5,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_USB_FS1,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_USB_FS2,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_TSIF,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MSM_TSSC,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MSM_PDM,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MSM_DIMEM,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MSM_TCSR,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MSM_PRNG,
+		.buswidth = 4,
+		.ahb = 1,
+	},
+};
+
+static void msm_bus_board_assign_iids(struct msm_bus_fabric_registration
+	*fabreg, int fabid)
+{
+	int i;
+	for (i = 0; i < fabreg->len; i++) {
+		if (!fabreg->info[i].gateway) {
+			fabreg->info[i].priv_id = fabid + fabreg->info[i].id;
+			if (fabreg->info[i].id < SLAVE_ID_KEY)
+				master_iids[fabreg->info[i].id] =
+					fabreg->info[i].priv_id;
+			else
+				slave_iids[fabreg->info[i].id - (SLAVE_ID_KEY)]
+					= fabreg->info[i].priv_id;
+		} else
+			fabreg->info[i].priv_id = fabreg->info[i].id;
+	}
+}
+
+static int msm_bus_board_8660_get_iid(int id)
+{
+	if ((id < SLAVE_ID_KEY && id >= NMASTERS) ||
+		id >= (SLAVE_ID_KEY + NSLAVES)) {
+		MSM_BUS_ERR("Cannot get iid. Invalid id %d passed\n", id);
+		return -EINVAL;
+	}
+
+	return CHECK_ID(((id < SLAVE_ID_KEY) ? master_iids[id] :
+		slave_iids[id - SLAVE_ID_KEY]), id);
+}
+
+static struct msm_bus_board_algorithm msm_bus_board_algo = {
+	.board_nfab = NFAB_8660,
+	.get_iid = msm_bus_board_8660_get_iid,
+	.assign_iids = msm_bus_board_assign_iids,
+};
+
+struct msm_bus_fabric_registration msm_bus_apps_fabric_pdata = {
+	.id = MSM_BUS_FAB_APPSS,
+	.name = "msm_apps_fab",
+	.info = apps_fabric_info,
+	.len = ARRAY_SIZE(apps_fabric_info),
+	.ahb = 0,
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
+	.haltid = MSM_RPM_ID_APPS_FABRIC_HALT_0,
+	.offset = MSM_RPM_ID_APPS_FABRIC_ARB_0,
+	.nmasters = 4,
+	.nslaves = 4,
+	.ntieredslaves = 2,
+	.board_algo = &msm_bus_board_algo,
+};
+
+struct msm_bus_fabric_registration msm_bus_sys_fabric_pdata = {
+	.id = MSM_BUS_FAB_SYSTEM,
+	.name = "msm_sys_fab",
+	system_fabric_info,
+	ARRAY_SIZE(system_fabric_info),
+	.ahb = 0,
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
+	.haltid = MSM_RPM_ID_SYSTEM_FABRIC_HALT_0,
+	.offset = MSM_RPM_ID_SYSTEM_FABRIC_ARB_0,
+	.nmasters = 17,
+	.nslaves = 9,
+	.ntieredslaves = 2,
+	.board_algo = &msm_bus_board_algo,
+};
+
+struct msm_bus_fabric_registration msm_bus_mm_fabric_pdata = {
+	.id = MSM_BUS_FAB_MMSS,
+	.name = "msm_mm_fab",
+	mmss_fabric_info,
+	ARRAY_SIZE(mmss_fabric_info),
+	.ahb = 0,
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
+	.haltid = MSM_RPM_ID_MM_FABRIC_HALT_0,
+	.offset = MSM_RPM_ID_MM_FABRIC_ARB_0,
+	.nmasters = 14,
+	.nslaves = 4,
+	.ntieredslaves = 3,
+	.board_algo = &msm_bus_board_algo,
+};
+
+struct msm_bus_fabric_registration msm_bus_sys_fpb_pdata = {
+	.id = MSM_BUS_FAB_SYSTEM_FPB,
+	.name = "msm_sys_fpb",
+	sys_fpb_fabric_info,
+	ARRAY_SIZE(sys_fpb_fabric_info),
+	.ahb = 1,
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
+	.nmasters = 0,
+	.nslaves = 0,
+	.ntieredslaves = 0,
+	.board_algo = &msm_bus_board_algo,
+};
+
+struct msm_bus_fabric_registration msm_bus_cpss_fpb_pdata = {
+	.id = MSM_BUS_FAB_CPSS_FPB,
+	.name = "msm_cpss_fpb",
+	cpss_fpb_fabric_info,
+	ARRAY_SIZE(cpss_fpb_fabric_info),
+	.ahb = 1,
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
+	.nmasters = 0,
+	.nslaves = 0,
+	.ntieredslaves = 0,
+	.board_algo = &msm_bus_board_algo,
+};
+
+int msm_bus_board_rpm_get_il_ids(uint16_t id[])
+{
+	return -ENXIO;
+}
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8930.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8930.c
new file mode 100644
index 0000000..0f37c6d
--- /dev/null
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8930.c
@@ -0,0 +1,880 @@
+/* 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/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#include <mach/board.h>
+#include <mach/rpm.h>
+#include "msm_bus_core.h"
+
+#define NMASTERS 45
+#define NSLAVES 75
+#define NFAB_8930 5
+
+enum msm_bus_fabric_tiered_slave_type {
+	MSM_BUS_SYSTEM_TIERED_SLAVE_FAB_APPSS_0 = 1,
+	MSM_BUS_TIERED_SLAVE_SYSTEM_IMEM,
+
+	MSM_BUS_TIERED_SLAVE_MM_IMEM = 1,
+	MSM_BUS_MMSS_TIERED_SLAVE_FAB_APPS_0,
+
+	MSM_BUS_TIERED_SLAVE_EBI1_CH0 = 1,
+	MSM_BUS_TIERED_SLAVE_KMPSS_L2,
+};
+
+enum msm_bus_8930_master_ports_type {
+	MSM_BUS_SYSTEM_MASTER_PORT_APPSS_FAB = 0,
+	MSM_BUS_MASTER_PORT_SPS,
+	MSM_BUS_MASTER_PORT_ADM_PORT0,
+	MSM_BUS_MASTER_PORT_ADM_PORT1,
+	MSM_BUS_MASTER_PORT_LPASS_PROC,
+	MSM_BUS_MASTER_PORT_MSS,
+	MSM_BUS_MASTER_PORT_RIVA,
+	MSM_BUS_MASTER_PORT_MSS_SW_PROC,
+	MSM_BUS_MASTER_PORT_MSS_FW_PROC,
+	MSM_BUS_MASTER_PORT_LPASS,
+	MSM_BUS_SYSTEM_MASTER_PORT_CPSS_FPB,
+	MSM_BUS_SYSTEM_MASTER_PORT_SYSTEM_FPB,
+	MSM_BUS_SYSTEM_MASTER_PORT_MMSS_FPB,
+	MSM_BUS_SYSTEM_MASTER_PORT_ADM_AHB_CI,
+
+	MSM_BUS_MASTER_PORT_MDP_PORT0 = 0,
+	MSM_BUS_MASTER_PORT_MDP_PORT1,
+	MSM_BUS_MASTER_PORT_GRAPHICS_3D,
+	MSM_BUS_MASTER_PORT_ROTATOR,
+	MSM_BUS_MASTER_PORT_VFE,
+	MSM_BUS_MASTER_PORT_VPE,
+	MSM_BUS_MASTER_PORT_JPEG_ENC,
+	MSM_BUS_MMSS_MASTER_PORT_APPS_FAB,
+	MSM_BUS_MASTER_PORT_HD_CODEC_PORT0,
+	MSM_BUS_MASTER_PORT_HD_CODEC_PORT1,
+
+	MSM_BUS_MASTER_PORT_KMPSS_M0 = 0,
+	MSM_BUS_MASTER_PORT_KMPSS_M1,
+	MSM_BUS_APPSS_MASTER_PORT_FAB_MMSS_0,
+	MSM_BUS_APPSS_MASTER_PORT_FAB_SYSTEM_0,
+};
+
+enum msm_bus_8930_slave_ports_type {
+	MSM_BUS_SLAVE_PORT_MM_IMEM = 0,
+	MSM_BUS_MMSS_SLAVE_PORT_APPS_FAB_0,
+
+	MSM_BUS_SLAVE_PORT_EBI1_CH0 = 0,
+	MSM_BUS_SLAVE_PORT_KMPSS_L2,
+	MSM_BUS_APPSS_SLAVE_PORT_MMSS_FAB,
+	MSM_BUS_SLAVE_PORT_SYSTEM_FAB,
+
+	MSM_BUS_SYSTEM_SLAVE_PORT_APPSS_FAB_0 = 0,
+	MSM_BUS_SLAVE_PORT_SPS,
+	MSM_BUS_SLAVE_PORT_SYSTEM_IMEM,
+	MSM_BUS_SLAVE_PORT_CORESIGHT,
+	MSM_BUS_SLAVE_PORT_KMPSS,
+	MSM_BUS_SLAVE_PORT_MSS,
+	MSM_BUS_SLAVE_PORT_LPASS,
+	MSM_BUS_SYSTEM_SLAVE_PORT_CPSS_FPB,
+	MSM_BUS_SYSTEM_SLAVE_PORT_SYSTEM_FPB,
+	MSM_BUS_SYSTEM_SLAVE_PORT_MMSS_FPB,
+	MSM_BUS_SLAVE_PORT_RIVA,
+};
+
+static int tier2[] = {MSM_BUS_BW_TIER2,};
+static uint32_t master_iids[NMASTERS];
+static uint32_t slave_iids[NSLAVES];
+
+static int mport_kmpss_m0[] = {MSM_BUS_MASTER_PORT_KMPSS_M0,};
+static int mport_kmpss_m1[] = {MSM_BUS_MASTER_PORT_KMPSS_M1,};
+
+static int mmss_mport_apps_fab[] = {MSM_BUS_MMSS_MASTER_PORT_APPS_FAB,};
+static int system_mport_appss_fab[] = {MSM_BUS_SYSTEM_MASTER_PORT_APPSS_FAB,};
+static int sport_ebi1_ch0[] = {
+	MSM_BUS_SLAVE_PORT_EBI1_CH0,
+};
+static int sport_kmpss_l2[] = {MSM_BUS_SLAVE_PORT_KMPSS_L2,};
+static int appss_sport_mmss_fab[] = {MSM_BUS_APPSS_SLAVE_PORT_MMSS_FAB,};
+static int sport_system_fab[] = {MSM_BUS_SLAVE_PORT_SYSTEM_FAB,};
+
+static int tiered_slave_ebi1_ch0[] = {
+	MSM_BUS_TIERED_SLAVE_EBI1_CH0,
+};
+
+static int tiered_slave_kmpss[] = {MSM_BUS_TIERED_SLAVE_KMPSS_L2,};
+
+static struct msm_bus_node_info apps_fabric_info[] = {
+	{
+		.id = MSM_BUS_MASTER_AMPSS_M0,
+		.masterp = mport_kmpss_m0,
+		.num_mports = ARRAY_SIZE(mport_kmpss_m0),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_AMPSS_M1,
+		.masterp = mport_kmpss_m1,
+		.num_mports = ARRAY_SIZE(mport_kmpss_m1),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI_CH0,
+		.slavep = sport_ebi1_ch0,
+		.num_sports = ARRAY_SIZE(sport_ebi1_ch0),
+		.tier = tiered_slave_ebi1_ch0,
+		.num_tiers = ARRAY_SIZE(tiered_slave_ebi1_ch0),
+		.buswidth = 8,
+		.slaveclk[DUAL_CTX] = "mem_clk",
+		.slaveclk[ACTIVE_CTX] = "mem_a_clk",
+	},
+	{
+		.id = MSM_BUS_SLAVE_AMPSS_L2,
+		.slavep = sport_kmpss_l2,
+		.num_sports = ARRAY_SIZE(sport_kmpss_l2),
+		.tier = tiered_slave_kmpss,
+		.num_tiers = ARRAY_SIZE(tiered_slave_kmpss),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_FAB_MMSS,
+		.gateway = 1,
+		.slavep = appss_sport_mmss_fab,
+		.num_sports = ARRAY_SIZE(appss_sport_mmss_fab),
+		.masterp = mmss_mport_apps_fab,
+		.num_mports = ARRAY_SIZE(mmss_mport_apps_fab),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_FAB_SYSTEM,
+		.gateway = 1,
+		.slavep = sport_system_fab,
+		.num_sports = ARRAY_SIZE(sport_system_fab),
+		.masterp = system_mport_appss_fab,
+		.num_mports = ARRAY_SIZE(system_mport_appss_fab),
+		.buswidth = 8,
+	},
+};
+
+static int mport_sps[] = {MSM_BUS_MASTER_PORT_SPS,};
+static int mport_adm_port0[] = {MSM_BUS_MASTER_PORT_ADM_PORT0,};
+static int mport_adm_port1[] = {MSM_BUS_MASTER_PORT_ADM_PORT1,};
+static int mport_mss[] = {MSM_BUS_MASTER_PORT_MSS,};
+static int mport_lpass_proc[] = {MSM_BUS_MASTER_PORT_LPASS_PROC,};
+static int mport_riva[] = {MSM_BUS_MASTER_PORT_RIVA,};
+static int mport_mss_sw_proc[] = {MSM_BUS_MASTER_PORT_MSS_SW_PROC,};
+static int mport_mss_fw_proc[] = {MSM_BUS_MASTER_PORT_MSS_FW_PROC,};
+static int mport_lpass[] = {MSM_BUS_MASTER_PORT_LPASS,};
+static int system_mport_mmss_fpb[] = {MSM_BUS_SYSTEM_MASTER_PORT_MMSS_FPB,};
+static int system_mport_adm_ahb_ci[] = {MSM_BUS_SYSTEM_MASTER_PORT_ADM_AHB_CI,};
+static int appss_mport_fab_system[] = {
+	MSM_BUS_APPSS_MASTER_PORT_FAB_SYSTEM_0,
+};
+static int mport_system_fpb[] = {MSM_BUS_SYSTEM_MASTER_PORT_SYSTEM_FPB,};
+static int system_mport_cpss_fpb[] = {MSM_BUS_SYSTEM_MASTER_PORT_CPSS_FPB,};
+
+static int system_sport_appss_fab[] = {
+	MSM_BUS_SYSTEM_SLAVE_PORT_APPSS_FAB_0,
+};
+static int system_sport_system_fpb[] = {MSM_BUS_SYSTEM_SLAVE_PORT_SYSTEM_FPB,};
+static int system_sport_cpss_fpb[] = {MSM_BUS_SYSTEM_SLAVE_PORT_CPSS_FPB,};
+static int sport_sps[] = {MSM_BUS_SLAVE_PORT_SPS,};
+static int sport_system_imem[] = {MSM_BUS_SLAVE_PORT_SYSTEM_IMEM,};
+static int sport_coresight[] = {MSM_BUS_SLAVE_PORT_CORESIGHT,};
+static int sport_riva[] = {MSM_BUS_SLAVE_PORT_RIVA,};
+static int sport_kmpss[] = {MSM_BUS_SLAVE_PORT_KMPSS,};
+static int sport_mss[] = {MSM_BUS_SLAVE_PORT_MSS,};
+static int sport_lpass[] = {MSM_BUS_SLAVE_PORT_LPASS,};
+static int sport_mmss_fpb[] = {MSM_BUS_SYSTEM_SLAVE_PORT_MMSS_FPB,};
+
+static int tiered_slave_system_imem[] = {MSM_BUS_TIERED_SLAVE_SYSTEM_IMEM,};
+static int system_tiered_slave_fab_appss[] = {
+	MSM_BUS_SYSTEM_TIERED_SLAVE_FAB_APPSS_0,
+};
+
+static struct msm_bus_node_info system_fabric_info[]  = {
+	{
+		.id = MSM_BUS_MASTER_SPS,
+		.masterp = mport_sps,
+		.num_mports = ARRAY_SIZE(mport_sps),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_ADM_PORT0,
+		.masterp = mport_adm_port0,
+		.num_mports = ARRAY_SIZE(mport_adm_port0),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_ADM_PORT1,
+		.masterp = mport_adm_port1,
+		.num_mports = ARRAY_SIZE(mport_adm_port1),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_LPASS_PROC,
+		.masterp = mport_lpass_proc,
+		.num_mports = ARRAY_SIZE(mport_lpass_proc),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_MSS,
+		.masterp = mport_mss,
+		.num_mports = ARRAY_SIZE(mport_mss),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_RIVA,
+		.masterp = mport_riva,
+		.num_mports = ARRAY_SIZE(mport_riva),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_MSS_SW_PROC,
+		.masterp = mport_mss_sw_proc,
+		.num_mports = ARRAY_SIZE(mport_mss_sw_proc),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_MSS_FW_PROC,
+		.masterp = mport_mss_fw_proc,
+		.num_mports = ARRAY_SIZE(mport_mss_fw_proc),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_LPASS,
+		.masterp = mport_lpass,
+		.num_mports = ARRAY_SIZE(mport_lpass),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_SYSTEM_MASTER_MMSS_FPB,
+		.masterp = system_mport_mmss_fpb,
+		.num_mports = ARRAY_SIZE(system_mport_mmss_fpb),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_ADM0_CI,
+		.masterp = system_mport_adm_ahb_ci,
+		.num_mports = ARRAY_SIZE(system_mport_adm_ahb_ci),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_FAB_APPSS,
+		.gateway = 1,
+		.slavep = system_sport_appss_fab,
+		.num_sports = ARRAY_SIZE(system_sport_appss_fab),
+		.masterp = appss_mport_fab_system,
+		.num_mports = ARRAY_SIZE(appss_mport_fab_system),
+		.tier = system_tiered_slave_fab_appss,
+		.num_tiers = ARRAY_SIZE(system_tiered_slave_fab_appss),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_FAB_SYSTEM_FPB,
+		.gateway = 1,
+		.slavep = system_sport_system_fpb,
+		.num_sports = ARRAY_SIZE(system_sport_system_fpb),
+		.masterp = mport_system_fpb,
+		.num_mports = ARRAY_SIZE(mport_system_fpb),
+		.buswidth = 4,
+	},
+	{
+		.id = MSM_BUS_FAB_CPSS_FPB,
+		.gateway = 1,
+		.slavep = system_sport_cpss_fpb,
+		.num_sports = ARRAY_SIZE(system_sport_cpss_fpb),
+		.masterp = system_mport_cpss_fpb,
+		.num_mports = ARRAY_SIZE(system_mport_cpss_fpb),
+		.buswidth = 4,
+	},
+	{
+		.id = MSM_BUS_SLAVE_SPS,
+		.slavep = sport_sps,
+		.num_sports = ARRAY_SIZE(sport_sps),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slaveclk[DUAL_CTX] = "dfab_clk",
+		.slaveclk[ACTIVE_CTX] = "dfab_a_clk",
+	},
+	{
+		.id = MSM_BUS_SLAVE_SYSTEM_IMEM,
+		.slavep = sport_system_imem,
+		.num_sports = ARRAY_SIZE(sport_system_imem),
+		.tier = tiered_slave_system_imem,
+		.num_tiers = ARRAY_SIZE(tiered_slave_system_imem),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_CORESIGHT,
+		.slavep = sport_coresight,
+		.num_sports = ARRAY_SIZE(sport_coresight),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_RIVA,
+		.slavep = sport_riva,
+		.num_sports = ARRAY_SIZE(sport_riva),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_AMPSS,
+		.slavep = sport_kmpss,
+		.num_sports = ARRAY_SIZE(sport_kmpss),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MSS,
+		.slavep = sport_mss,
+		.num_sports = ARRAY_SIZE(sport_mss),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_LPASS,
+		.slavep = sport_lpass,
+		.num_sports = ARRAY_SIZE(sport_lpass),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SYSTEM_SLAVE_MMSS_FPB,
+		.slavep = sport_mmss_fpb,
+		.num_sports = ARRAY_SIZE(sport_mmss_fpb),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+};
+
+static int mport_mdp[] = {
+	MSM_BUS_MASTER_PORT_MDP_PORT0,
+	MSM_BUS_MASTER_PORT_MDP_PORT1,
+};
+static int mport_mdp1[] = {MSM_BUS_MASTER_PORT_MDP_PORT1,};
+static int mport_rotator[] = {MSM_BUS_MASTER_PORT_ROTATOR,};
+static int mport_graphics_3d[] = {MSM_BUS_MASTER_PORT_GRAPHICS_3D,};
+static int mport_vfe[] = {MSM_BUS_MASTER_PORT_VFE,};
+static int mport_vpe[] = {MSM_BUS_MASTER_PORT_VPE,};
+static int mport_jpeg_enc[] = {MSM_BUS_MASTER_PORT_JPEG_ENC,};
+static int mport_hd_codec_port0[] = {MSM_BUS_MASTER_PORT_HD_CODEC_PORT0,};
+static int mport_hd_codec_port1[] = {MSM_BUS_MASTER_PORT_HD_CODEC_PORT1,};
+static int appss_mport_fab_mmss[] = {
+	MSM_BUS_APPSS_MASTER_PORT_FAB_MMSS_0,
+};
+
+static int mmss_sport_apps_fab[] = {
+	MSM_BUS_MMSS_SLAVE_PORT_APPS_FAB_0,
+};
+static int sport_mm_imem[] = {MSM_BUS_SLAVE_PORT_MM_IMEM,};
+
+static int mmss_tiered_slave_fab_apps[] = {
+	MSM_BUS_MMSS_TIERED_SLAVE_FAB_APPS_0,
+};
+static int tiered_slave_mm_imem[] = {MSM_BUS_TIERED_SLAVE_MM_IMEM,};
+
+
+static struct msm_bus_node_info mmss_fabric_info[]  = {
+	{
+		.id = MSM_BUS_MASTER_MDP_PORT0,
+		.masterp = mport_mdp,
+		.num_mports = ARRAY_SIZE(mport_mdp),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_MDP_PORT1,
+		.masterp = mport_mdp1,
+		.num_mports = ARRAY_SIZE(mport_mdp1),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_ROTATOR,
+		.masterp = mport_rotator,
+		.num_mports = ARRAY_SIZE(mport_rotator),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_GRAPHICS_3D,
+		.masterp = mport_graphics_3d,
+		.num_mports = ARRAY_SIZE(mport_graphics_3d),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_VFE,
+		.masterp = mport_vfe,
+		.num_mports = ARRAY_SIZE(mport_vfe),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_VPE,
+		.masterp = mport_vpe,
+		.num_mports = ARRAY_SIZE(mport_vpe),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_JPEG_ENC,
+		.masterp = mport_jpeg_enc,
+		.num_mports = ARRAY_SIZE(mport_jpeg_enc),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.masterp = mport_hd_codec_port0,
+		.num_mports = ARRAY_SIZE(mport_hd_codec_port0),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.masterp = mport_hd_codec_port1,
+		.num_mports = ARRAY_SIZE(mport_hd_codec_port1),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_FAB_APPSS,
+		.gateway = 1,
+		.slavep = mmss_sport_apps_fab,
+		.num_sports = ARRAY_SIZE(mmss_sport_apps_fab),
+		.masterp = appss_mport_fab_mmss,
+		.num_mports = ARRAY_SIZE(appss_mport_fab_mmss),
+		.tier = mmss_tiered_slave_fab_apps,
+		.num_tiers = ARRAY_SIZE(mmss_tiered_slave_fab_apps),
+		.buswidth = 16,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MM_IMEM,
+		.slavep = sport_mm_imem,
+		.num_sports = ARRAY_SIZE(sport_mm_imem),
+		.tier = tiered_slave_mm_imem,
+		.num_tiers = ARRAY_SIZE(tiered_slave_mm_imem),
+		.buswidth = 8,
+	},
+};
+
+static struct msm_bus_node_info sys_fpb_fabric_info[]  = {
+	{
+		.id = MSM_BUS_FAB_SYSTEM,
+		.gateway = 1,
+		.slavep = system_sport_system_fpb,
+		.num_sports = ARRAY_SIZE(system_sport_system_fpb),
+		.masterp = mport_system_fpb,
+		.num_mports = ARRAY_SIZE(mport_system_fpb),
+		.buswidth = 4,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_MASTER_SPDM,
+		.ahb = 1,
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_RPM,
+		.ahb = 1,
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_SLAVE_SPDM,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_RPM,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_RPM_MSG_RAM,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MPM,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PMIC1_SSBI1_A,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PMIC1_SSBI1_B,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PMIC1_SSBI1_C,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PMIC2_SSBI2_A,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PMIC2_SSBI2_B,
+		.buswidth = 4,
+		.ahb = 1,
+	},
+};
+
+static struct msm_bus_node_info cpss_fpb_fabric_info[] = {
+	{
+		.id = MSM_BUS_FAB_SYSTEM,
+		.gateway = 1,
+		.slavep = system_sport_cpss_fpb,
+		.num_sports = ARRAY_SIZE(system_sport_cpss_fpb),
+		.masterp = system_mport_cpss_fpb,
+		.num_mports = ARRAY_SIZE(system_mport_cpss_fpb),
+		.buswidth = 4,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI1_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI2_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI3_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI4_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI5_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI6_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI7_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI8_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI9_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI10_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI11_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI12_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI1_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI2_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI3_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI4_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI5_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI6_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI7_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI8_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI9_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI10_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI11_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI12_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_NAND,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_CS0,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_CS1,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_CS2,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_CS3,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_CS4,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_CS5,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_USB_FS1,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_USB_FS2,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_TSIF,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MSM_TSSC,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MSM_PDM,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MSM_DIMEM,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MSM_TCSR,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MSM_PRNG,
+		.buswidth = 4,
+		.ahb = 1,
+	},
+};
+
+static void msm_bus_board_assign_iids(struct msm_bus_fabric_registration
+	*fabreg, int fabid)
+{
+	int i;
+	for (i = 0; i < fabreg->len; i++) {
+		if (!fabreg->info[i].gateway) {
+			fabreg->info[i].priv_id = fabid + fabreg->info[i].id;
+			if (fabreg->info[i].id < SLAVE_ID_KEY)
+				master_iids[fabreg->info[i].id] =
+					fabreg->info[i].priv_id;
+			else
+				slave_iids[fabreg->info[i].id - (SLAVE_ID_KEY)]
+					= fabreg->info[i].priv_id;
+		} else
+			fabreg->info[i].priv_id = fabreg->info[i].id;
+	}
+}
+
+static int msm_bus_board_8930_get_iid(int id)
+{
+	if ((id < SLAVE_ID_KEY && id >= NMASTERS) ||
+		id >= (SLAVE_ID_KEY + NSLAVES)) {
+		MSM_BUS_ERR("Cannot get iid. Invalid id %d passed\n", id);
+		return -EINVAL;
+	}
+
+	return CHECK_ID(((id < SLAVE_ID_KEY) ? master_iids[id] :
+		slave_iids[id - SLAVE_ID_KEY]), id);
+}
+
+static struct msm_bus_board_algorithm msm_bus_board_algo = {
+	.board_nfab = NFAB_8930,
+	.get_iid = msm_bus_board_8930_get_iid,
+	.assign_iids = msm_bus_board_assign_iids,
+};
+
+struct msm_bus_fabric_registration msm_bus_8930_apps_fabric_pdata = {
+	.id = MSM_BUS_FAB_APPSS,
+	.name = "msm_apps_fab",
+	.info = apps_fabric_info,
+	.len = ARRAY_SIZE(apps_fabric_info),
+	.ahb = 0,
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
+	.haltid = MSM_RPM_ID_APPS_FABRIC_CFG_HALT_0,
+	.offset = MSM_RPM_ID_APPS_FABRIC_ARB_0,
+	.nmasters = 4,
+	.nslaves = 4,
+	.ntieredslaves = 2,
+	.board_algo = &msm_bus_board_algo,
+};
+
+struct msm_bus_fabric_registration msm_bus_8930_sys_fabric_pdata = {
+	.id = MSM_BUS_FAB_SYSTEM,
+	.name = "msm_sys_fab",
+	system_fabric_info,
+	ARRAY_SIZE(system_fabric_info),
+	.ahb = 0,
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
+	.haltid = MSM_RPM_ID_SYS_FABRIC_CFG_HALT_0,
+	.offset = MSM_RPM_ID_SYSTEM_FABRIC_ARB_0,
+	.nmasters = 14,
+	.nslaves = 11,
+	.ntieredslaves = 2,
+	.board_algo = &msm_bus_board_algo,
+};
+
+struct msm_bus_fabric_registration msm_bus_8930_mm_fabric_pdata = {
+	.id = MSM_BUS_FAB_MMSS,
+	.name = "msm_mm_fab",
+	mmss_fabric_info,
+	ARRAY_SIZE(mmss_fabric_info),
+	.ahb = 0,
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
+	.haltid = MSM_RPM_ID_MMSS_FABRIC_CFG_HALT_0,
+	.offset = MSM_RPM_ID_MM_FABRIC_ARB_0,
+	.nmasters = 10,
+	.nslaves = 2,
+	.ntieredslaves = 2,
+	.board_algo = &msm_bus_board_algo,
+};
+
+struct msm_bus_fabric_registration msm_bus_8930_sys_fpb_pdata = {
+	.id = MSM_BUS_FAB_SYSTEM_FPB,
+	.name = "msm_sys_fpb",
+	sys_fpb_fabric_info,
+	ARRAY_SIZE(sys_fpb_fabric_info),
+	.ahb = 1,
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
+	.nmasters = 0,
+	.nslaves = 0,
+	.ntieredslaves = 0,
+	.board_algo = &msm_bus_board_algo,
+};
+
+struct msm_bus_fabric_registration msm_bus_8930_cpss_fpb_pdata = {
+	.id = MSM_BUS_FAB_CPSS_FPB,
+	.name = "msm_cpss_fpb",
+	cpss_fpb_fabric_info,
+	ARRAY_SIZE(cpss_fpb_fabric_info),
+	.ahb = 1,
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
+	.nmasters = 0,
+	.nslaves = 0,
+	.ntieredslaves = 0,
+	.board_algo = &msm_bus_board_algo,
+};
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
new file mode 100644
index 0000000..7ede23d
--- /dev/null
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
@@ -0,0 +1,955 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#include <mach/board.h>
+#include <mach/rpm.h>
+#include "msm_bus_core.h"
+
+#define NMASTERS 45
+#define NSLAVES 75
+#define NFAB_8960 5
+
+enum msm_bus_fabric_tiered_slave_type {
+	MSM_BUS_SYSTEM_TIERED_SLAVE_FAB_APPSS_0 = 1,
+	MSM_BUS_SYSTEM_TIERED_SLAVE_FAB_APPSS_1,
+	MSM_BUS_TIERED_SLAVE_SYSTEM_IMEM,
+
+	MSM_BUS_MMSS_TIERED_SLAVE_FAB_APPS_0 = 1,
+	MSM_BUS_MMSS_TIERED_SLAVE_FAB_APPS_1,
+	MSM_BUS_TIERED_SLAVE_MM_IMEM,
+
+	MSM_BUS_TIERED_SLAVE_EBI1_CH0 = 1,
+	MSM_BUS_TIERED_SLAVE_EBI1_CH1,
+	MSM_BUS_TIERED_SLAVE_KMPSS_L2,
+};
+
+enum msm_bus_8960_master_ports_type {
+	MSM_BUS_SYSTEM_MASTER_PORT_APPSS_FAB = 0,
+	MSM_BUS_MASTER_PORT_SPS,
+	MSM_BUS_MASTER_PORT_ADM_PORT0,
+	MSM_BUS_MASTER_PORT_ADM_PORT1,
+	MSM_BUS_MASTER_PORT_LPASS_PROC,
+	MSM_BUS_MASTER_PORT_MSS,
+	MSM_BUS_SYSTEM_MASTER_PORT_UNUSED_6,
+	MSM_BUS_MASTER_PORT_RIVA,
+	MSM_BUS_MASTER_PORT_MSS_SW_PROC,
+	MSM_BUS_MASTER_PORT_MSS_FW_PROC,
+	MSM_BUS_MASTER_PORT_LPASS,
+	MSM_BUS_SYSTEM_MASTER_PORT_CPSS_FPB,
+	MSM_BUS_SYSTEM_MASTER_PORT_SYSTEM_FPB,
+	MSM_BUS_SYSTEM_MASTER_PORT_MMSS_FPB,
+	MSM_BUS_SYSTEM_MASTER_PORT_ADM_AHB_CI,
+
+	MSM_BUS_MASTER_PORT_MDP_PORT0 = 0,
+	MSM_BUS_MASTER_PORT_MDP_PORT1,
+	MSM_BUS_MMSS_MASTER_PORT_UNUSED_2,
+	MSM_BUS_MASTER_PORT_ROTATOR,
+	MSM_BUS_MASTER_PORT_GRAPHICS_3D,
+	MSM_BUS_MASTER_PORT_JPEG_DEC,
+	MSM_BUS_MASTER_PORT_GRAPHICS_2D_CORE0,
+	MSM_BUS_MASTER_PORT_VFE,
+	MSM_BUS_MASTER_PORT_VPE,
+	MSM_BUS_MASTER_PORT_JPEG_ENC,
+	MSM_BUS_MASTER_PORT_GRAPHICS_2D_CORE1,
+	MSM_BUS_MMSS_MASTER_PORT_APPS_FAB,
+	MSM_BUS_MASTER_PORT_HD_CODEC_PORT0,
+	MSM_BUS_MASTER_PORT_HD_CODEC_PORT1,
+
+	MSM_BUS_MASTER_PORT_KMPSS_M0 = 0,
+	MSM_BUS_MASTER_PORT_KMPSS_M1,
+	MSM_BUS_APPSS_MASTER_PORT_FAB_MMSS_0,
+	MSM_BUS_APPSS_MASTER_PORT_FAB_MMSS_1,
+	MSM_BUS_APPSS_MASTER_PORT_FAB_SYSTEM_0,
+	MSM_BUS_APPSS_MASTER_PORT_FAB_SYSTEM_1,
+
+};
+
+enum msm_bus_8660_slave_ports_type {
+	MSM_BUS_MMSS_SLAVE_PORT_UNUSED_0 = 0,
+	MSM_BUS_MMSS_SLAVE_PORT_APPS_FAB_0,
+	MSM_BUS_MMSS_SLAVE_PORT_APPS_FAB_1,
+	MSM_BUS_SLAVE_PORT_MM_IMEM,
+
+	MSM_BUS_SLAVE_PORT_EBI1_CH0 = 0,
+	MSM_BUS_SLAVE_PORT_EBI1_CH1,
+	MSM_BUS_SLAVE_PORT_KMPSS_L2,
+	MSM_BUS_APPSS_SLAVE_PORT_MMSS_FAB,
+	MSM_BUS_SLAVE_PORT_SYSTEM_FAB,
+
+	MSM_BUS_SYSTEM_SLAVE_PORT_APPSS_FAB_0 = 0,
+	MSM_BUS_SYSTEM_SLAVE_PORT_APPSS_FAB_1,
+	MSM_BUS_SLAVE_PORT_SPS,
+	MSM_BUS_SLAVE_PORT_SYSTEM_IMEM,
+	MSM_BUS_SLAVE_PORT_CORESIGHT,
+	MSM_BUS_SLAVE_PORT_KMPSS,
+	MSM_BUS_SLAVE_PORT_MSS,
+	MSM_BUS_SLAVE_PORT_LPASS,
+	MSM_BUS_SYSTEM_SLAVE_PORT_CPSS_FPB,
+	MSM_BUS_SYSTEM_SLAVE_PORT_SYSTEM_FPB,
+	MSM_BUS_SYSTEM_SLAVE_PORT_MMSS_FPB,
+	MSM_BUS_SLAVE_PORT_RIVA,
+};
+
+static int tier2[] = {MSM_BUS_BW_TIER2,};
+static uint32_t master_iids[NMASTERS];
+static uint32_t slave_iids[NSLAVES];
+
+static int mport_kmpss_m0[] = {MSM_BUS_MASTER_PORT_KMPSS_M0,};
+static int mport_kmpss_m1[] = {MSM_BUS_MASTER_PORT_KMPSS_M1,};
+
+static int mmss_mport_apps_fab[] = {MSM_BUS_MMSS_MASTER_PORT_APPS_FAB,};
+static int system_mport_appss_fab[] = {MSM_BUS_SYSTEM_MASTER_PORT_APPSS_FAB,};
+static int sport_ebi1_ch0[] = {
+	MSM_BUS_SLAVE_PORT_EBI1_CH0,
+	MSM_BUS_SLAVE_PORT_EBI1_CH1,
+};
+static int sport_ebi1_ch1[] = {MSM_BUS_SLAVE_PORT_EBI1_CH1,};
+static int sport_kmpss_l2[] = {MSM_BUS_SLAVE_PORT_KMPSS_L2,};
+static int appss_sport_mmss_fab[] = {MSM_BUS_APPSS_SLAVE_PORT_MMSS_FAB,};
+static int sport_system_fab[] = {MSM_BUS_SLAVE_PORT_SYSTEM_FAB,};
+
+static int tiered_slave_ebi1_ch0[] = {
+	MSM_BUS_TIERED_SLAVE_EBI1_CH0,
+	MSM_BUS_TIERED_SLAVE_EBI1_CH1,
+};
+static int tiered_slave_ebi1_ch1[] = {MSM_BUS_TIERED_SLAVE_EBI1_CH1,};
+
+static int tiered_slave_kmpss[] = {MSM_BUS_TIERED_SLAVE_KMPSS_L2,};
+
+static struct msm_bus_node_info apps_fabric_info[] = {
+	{
+		.id = MSM_BUS_MASTER_AMPSS_M0,
+		.masterp = mport_kmpss_m0,
+		.num_mports = ARRAY_SIZE(mport_kmpss_m0),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_AMPSS_M1,
+		.masterp = mport_kmpss_m1,
+		.num_mports = ARRAY_SIZE(mport_kmpss_m1),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI_CH0,
+		.slavep = sport_ebi1_ch0,
+		.num_sports = ARRAY_SIZE(sport_ebi1_ch0),
+		.tier = tiered_slave_ebi1_ch0,
+		.num_tiers = ARRAY_SIZE(tiered_slave_ebi1_ch0),
+		.buswidth = 8,
+		.slaveclk[DUAL_CTX] = "mem_clk",
+		.slaveclk[ACTIVE_CTX] = "mem_a_clk",
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI_CH1,
+		.slavep = sport_ebi1_ch1,
+		.num_sports = ARRAY_SIZE(sport_ebi1_ch1),
+		.tier = tiered_slave_ebi1_ch1,
+		.num_tiers = ARRAY_SIZE(tiered_slave_ebi1_ch1),
+		.buswidth = 8,
+		.slaveclk[DUAL_CTX] = "mem_clk",
+		.slaveclk[ACTIVE_CTX] = "mem_a_clk",
+	},
+	{
+		.id = MSM_BUS_SLAVE_AMPSS_L2,
+		.slavep = sport_kmpss_l2,
+		.num_sports = ARRAY_SIZE(sport_kmpss_l2),
+		.tier = tiered_slave_kmpss,
+		.num_tiers = ARRAY_SIZE(tiered_slave_kmpss),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_FAB_MMSS,
+		.gateway = 1,
+		.slavep = appss_sport_mmss_fab,
+		.num_sports = ARRAY_SIZE(appss_sport_mmss_fab),
+		.masterp = mmss_mport_apps_fab,
+		.num_mports = ARRAY_SIZE(mmss_mport_apps_fab),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_FAB_SYSTEM,
+		.gateway = 1,
+		.slavep = sport_system_fab,
+		.num_sports = ARRAY_SIZE(sport_system_fab),
+		.masterp = system_mport_appss_fab,
+		.num_mports = ARRAY_SIZE(system_mport_appss_fab),
+		.buswidth = 8,
+	},
+};
+
+static int mport_sps[] = {MSM_BUS_MASTER_PORT_SPS,};
+static int mport_adm_port0[] = {MSM_BUS_MASTER_PORT_ADM_PORT0,};
+static int mport_adm_port1[] = {MSM_BUS_MASTER_PORT_ADM_PORT1,};
+static int mport_mss[] = {MSM_BUS_MASTER_PORT_MSS,};
+static int mport_lpass_proc[] = {MSM_BUS_MASTER_PORT_LPASS_PROC,};
+static int system_mport_unused_6[] = {MSM_BUS_SYSTEM_MASTER_PORT_UNUSED_6,};
+static int mport_riva[] = {MSM_BUS_MASTER_PORT_RIVA,};
+static int mport_mss_sw_proc[] = {MSM_BUS_MASTER_PORT_MSS_SW_PROC,};
+static int mport_mss_fw_proc[] = {MSM_BUS_MASTER_PORT_MSS_FW_PROC,};
+static int mport_lpass[] = {MSM_BUS_MASTER_PORT_LPASS,};
+static int system_mport_mmss_fpb[] = {MSM_BUS_SYSTEM_MASTER_PORT_MMSS_FPB,};
+static int system_mport_adm_ahb_ci[] = {MSM_BUS_SYSTEM_MASTER_PORT_ADM_AHB_CI,};
+static int appss_mport_fab_system[] = {
+	MSM_BUS_APPSS_MASTER_PORT_FAB_SYSTEM_0,
+	MSM_BUS_APPSS_MASTER_PORT_FAB_SYSTEM_1
+};
+static int mport_system_fpb[] = {MSM_BUS_SYSTEM_MASTER_PORT_SYSTEM_FPB,};
+static int system_mport_cpss_fpb[] = {MSM_BUS_SYSTEM_MASTER_PORT_CPSS_FPB,};
+
+static int system_sport_appss_fab[] = {
+	MSM_BUS_SYSTEM_SLAVE_PORT_APPSS_FAB_0,
+	MSM_BUS_SYSTEM_SLAVE_PORT_APPSS_FAB_1
+};
+static int system_sport_system_fpb[] = {MSM_BUS_SYSTEM_SLAVE_PORT_SYSTEM_FPB,};
+static int system_sport_cpss_fpb[] = {MSM_BUS_SYSTEM_SLAVE_PORT_CPSS_FPB,};
+static int sport_sps[] = {MSM_BUS_SLAVE_PORT_SPS,};
+static int sport_system_imem[] = {MSM_BUS_SLAVE_PORT_SYSTEM_IMEM,};
+static int sport_coresight[] = {MSM_BUS_SLAVE_PORT_CORESIGHT,};
+static int sport_riva[] = {MSM_BUS_SLAVE_PORT_RIVA,};
+static int sport_kmpss[] = {MSM_BUS_SLAVE_PORT_KMPSS,};
+static int sport_mss[] = {MSM_BUS_SLAVE_PORT_MSS,};
+static int sport_lpass[] = {MSM_BUS_SLAVE_PORT_LPASS,};
+static int sport_mmss_fpb[] = {MSM_BUS_SYSTEM_SLAVE_PORT_MMSS_FPB,};
+
+static int tiered_slave_system_imem[] = {MSM_BUS_TIERED_SLAVE_SYSTEM_IMEM,};
+static int system_tiered_slave_fab_appss[] = {
+	MSM_BUS_SYSTEM_TIERED_SLAVE_FAB_APPSS_0,
+	MSM_BUS_SYSTEM_TIERED_SLAVE_FAB_APPSS_1,
+};
+
+static struct msm_bus_node_info system_fabric_info[]  = {
+	{
+		.id = MSM_BUS_MASTER_SPS,
+		.masterp = mport_sps,
+		.num_mports = ARRAY_SIZE(mport_sps),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_ADM_PORT0,
+		.masterp = mport_adm_port0,
+		.num_mports = ARRAY_SIZE(mport_adm_port0),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_ADM_PORT1,
+		.masterp = mport_adm_port1,
+		.num_mports = ARRAY_SIZE(mport_adm_port1),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_LPASS_PROC,
+		.masterp = mport_lpass_proc,
+		.num_mports = ARRAY_SIZE(mport_lpass_proc),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_MSS,
+		.masterp = mport_mss,
+		.num_mports = ARRAY_SIZE(mport_mss),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_SYSTEM_MASTER_UNUSED_6,
+		.masterp = system_mport_unused_6,
+		.num_mports = ARRAY_SIZE(system_mport_unused_6),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_RIVA,
+		.masterp = mport_riva,
+		.num_mports = ARRAY_SIZE(mport_riva),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_MSS_SW_PROC,
+		.masterp = mport_mss_sw_proc,
+		.num_mports = ARRAY_SIZE(mport_mss_sw_proc),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_MSS_FW_PROC,
+		.masterp = mport_mss_fw_proc,
+		.num_mports = ARRAY_SIZE(mport_mss_fw_proc),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_LPASS,
+		.masterp = mport_lpass,
+		.num_mports = ARRAY_SIZE(mport_lpass),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_SYSTEM_MASTER_MMSS_FPB,
+		.masterp = system_mport_mmss_fpb,
+		.num_mports = ARRAY_SIZE(system_mport_mmss_fpb),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_ADM0_CI,
+		.masterp = system_mport_adm_ahb_ci,
+		.num_mports = ARRAY_SIZE(system_mport_adm_ahb_ci),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_FAB_APPSS,
+		.gateway = 1,
+		.slavep = system_sport_appss_fab,
+		.num_sports = ARRAY_SIZE(system_sport_appss_fab),
+		.masterp = appss_mport_fab_system,
+		.num_mports = ARRAY_SIZE(appss_mport_fab_system),
+		.tier = system_tiered_slave_fab_appss,
+		.num_tiers = ARRAY_SIZE(system_tiered_slave_fab_appss),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_FAB_SYSTEM_FPB,
+		.gateway = 1,
+		.slavep = system_sport_system_fpb,
+		.num_sports = ARRAY_SIZE(system_sport_system_fpb),
+		.masterp = mport_system_fpb,
+		.num_mports = ARRAY_SIZE(mport_system_fpb),
+		.buswidth = 4,
+	},
+	{
+		.id = MSM_BUS_FAB_CPSS_FPB,
+		.gateway = 1,
+		.slavep = system_sport_cpss_fpb,
+		.num_sports = ARRAY_SIZE(system_sport_cpss_fpb),
+		.masterp = system_mport_cpss_fpb,
+		.num_mports = ARRAY_SIZE(system_mport_cpss_fpb),
+		.buswidth = 4,
+	},
+	{
+		.id = MSM_BUS_SLAVE_SPS,
+		.slavep = sport_sps,
+		.num_sports = ARRAY_SIZE(sport_sps),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slaveclk[DUAL_CTX] = "dfab_clk",
+		.slaveclk[ACTIVE_CTX] = "dfab_a_clk",
+	},
+	{
+		.id = MSM_BUS_SLAVE_SYSTEM_IMEM,
+		.slavep = sport_system_imem,
+		.num_sports = ARRAY_SIZE(sport_system_imem),
+		.tier = tiered_slave_system_imem,
+		.num_tiers = ARRAY_SIZE(tiered_slave_system_imem),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_CORESIGHT,
+		.slavep = sport_coresight,
+		.num_sports = ARRAY_SIZE(sport_coresight),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_RIVA,
+		.slavep = sport_riva,
+		.num_sports = ARRAY_SIZE(sport_riva),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_AMPSS,
+		.slavep = sport_kmpss,
+		.num_sports = ARRAY_SIZE(sport_kmpss),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MSS,
+		.slavep = sport_mss,
+		.num_sports = ARRAY_SIZE(sport_mss),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_LPASS,
+		.slavep = sport_lpass,
+		.num_sports = ARRAY_SIZE(sport_lpass),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SYSTEM_SLAVE_MMSS_FPB,
+		.slavep = sport_mmss_fpb,
+		.num_sports = ARRAY_SIZE(sport_mmss_fpb),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+};
+
+static int mport_mdp[] = {
+	MSM_BUS_MASTER_PORT_MDP_PORT0,
+	MSM_BUS_MASTER_PORT_MDP_PORT1,
+};
+static int mport_mdp1[] = {MSM_BUS_MASTER_PORT_MDP_PORT1,};
+static int mport_rotator[] = {MSM_BUS_MASTER_PORT_ROTATOR,};
+static int mport_graphics_3d[] = {MSM_BUS_MASTER_PORT_GRAPHICS_3D,};
+static int mport_jpeg_dec[] = {MSM_BUS_MASTER_PORT_JPEG_DEC,};
+static int mport_graphics_2d_core0[] = {MSM_BUS_MASTER_PORT_GRAPHICS_2D_CORE0,};
+static int mport_vfe[] = {MSM_BUS_MASTER_PORT_VFE,};
+static int mport_vpe[] = {MSM_BUS_MASTER_PORT_VPE,};
+static int mport_jpeg_enc[] = {MSM_BUS_MASTER_PORT_JPEG_ENC,};
+static int mport_graphics_2d_core1[] = {MSM_BUS_MASTER_PORT_GRAPHICS_2D_CORE1,};
+static int mport_hd_codec_port0[] = {MSM_BUS_MASTER_PORT_HD_CODEC_PORT0,};
+static int mport_hd_codec_port1[] = {MSM_BUS_MASTER_PORT_HD_CODEC_PORT1,};
+static int appss_mport_fab_mmss[] = {
+	MSM_BUS_APPSS_MASTER_PORT_FAB_MMSS_0,
+	MSM_BUS_APPSS_MASTER_PORT_FAB_MMSS_1
+};
+
+static int mmss_sport_apps_fab[] = {
+	MSM_BUS_MMSS_SLAVE_PORT_APPS_FAB_0,
+	MSM_BUS_MMSS_SLAVE_PORT_APPS_FAB_1
+};
+static int sport_mm_imem[] = {MSM_BUS_SLAVE_PORT_MM_IMEM,};
+
+static int mmss_tiered_slave_fab_apps[] = {
+	MSM_BUS_MMSS_TIERED_SLAVE_FAB_APPS_0,
+	MSM_BUS_MMSS_TIERED_SLAVE_FAB_APPS_1,
+};
+static int tiered_slave_mm_imem[] = {MSM_BUS_TIERED_SLAVE_MM_IMEM,};
+
+
+static struct msm_bus_node_info mmss_fabric_info[]  = {
+	{
+		.id = MSM_BUS_MASTER_MDP_PORT0,
+		.masterp = mport_mdp,
+		.num_mports = ARRAY_SIZE(mport_mdp),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_MDP_PORT1,
+		.masterp = mport_mdp1,
+		.num_mports = ARRAY_SIZE(mport_mdp1),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_ROTATOR,
+		.masterp = mport_rotator,
+		.num_mports = ARRAY_SIZE(mport_rotator),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_GRAPHICS_3D,
+		.masterp = mport_graphics_3d,
+		.num_mports = ARRAY_SIZE(mport_graphics_3d),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_JPEG_DEC,
+		.masterp = mport_jpeg_dec,
+		.num_mports = ARRAY_SIZE(mport_jpeg_dec),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_GRAPHICS_2D_CORE0,
+		.masterp = mport_graphics_2d_core0,
+		.num_mports = ARRAY_SIZE(mport_graphics_2d_core0),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_VFE,
+		.masterp = mport_vfe,
+		.num_mports = ARRAY_SIZE(mport_vfe),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_VPE,
+		.masterp = mport_vpe,
+		.num_mports = ARRAY_SIZE(mport_vpe),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_JPEG_ENC,
+		.masterp = mport_jpeg_enc,
+		.num_mports = ARRAY_SIZE(mport_jpeg_enc),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	/* This port has been added for V2. It is absent in V1 */
+	{
+		.id = MSM_BUS_MASTER_GRAPHICS_2D_CORE1,
+		.masterp = mport_graphics_2d_core1,
+		.num_mports = ARRAY_SIZE(mport_graphics_2d_core1),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_HD_CODEC_PORT0,
+		.masterp = mport_hd_codec_port0,
+		.num_mports = ARRAY_SIZE(mport_hd_codec_port0),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_HD_CODEC_PORT1,
+		.masterp = mport_hd_codec_port1,
+		.num_mports = ARRAY_SIZE(mport_hd_codec_port1),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_FAB_APPSS,
+		.gateway = 1,
+		.slavep = mmss_sport_apps_fab,
+		.num_sports = ARRAY_SIZE(mmss_sport_apps_fab),
+		.masterp = appss_mport_fab_mmss,
+		.num_mports = ARRAY_SIZE(appss_mport_fab_mmss),
+		.tier = mmss_tiered_slave_fab_apps,
+		.num_tiers = ARRAY_SIZE(mmss_tiered_slave_fab_apps),
+		.buswidth = 16,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MM_IMEM,
+		.slavep = sport_mm_imem,
+		.num_sports = ARRAY_SIZE(sport_mm_imem),
+		.tier = tiered_slave_mm_imem,
+		.num_tiers = ARRAY_SIZE(tiered_slave_mm_imem),
+		.buswidth = 8,
+	},
+};
+
+static struct msm_bus_node_info sys_fpb_fabric_info[]  = {
+	{
+		.id = MSM_BUS_FAB_SYSTEM,
+		.gateway = 1,
+		.slavep = system_sport_system_fpb,
+		.num_sports = ARRAY_SIZE(system_sport_system_fpb),
+		.masterp = mport_system_fpb,
+		.num_mports = ARRAY_SIZE(mport_system_fpb),
+		.buswidth = 4,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_MASTER_SPDM,
+		.ahb = 1,
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_RPM,
+		.ahb = 1,
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_SLAVE_SPDM,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_RPM,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_RPM_MSG_RAM,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MPM,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PMIC1_SSBI1_A,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PMIC1_SSBI1_B,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PMIC1_SSBI1_C,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PMIC2_SSBI2_A,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PMIC2_SSBI2_B,
+		.buswidth = 4,
+		.ahb = 1,
+	},
+};
+
+static struct msm_bus_node_info cpss_fpb_fabric_info[] = {
+	{
+		.id = MSM_BUS_FAB_SYSTEM,
+		.gateway = 1,
+		.slavep = system_sport_cpss_fpb,
+		.num_sports = ARRAY_SIZE(system_sport_cpss_fpb),
+		.masterp = system_mport_cpss_fpb,
+		.num_mports = ARRAY_SIZE(system_mport_cpss_fpb),
+		.buswidth = 4,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI1_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI2_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI3_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI4_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI5_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI6_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI7_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI8_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI9_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI10_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI11_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI12_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI1_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI2_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI3_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI4_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI5_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI6_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI7_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI8_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI9_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI10_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI11_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI12_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_NAND,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_CS0,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_CS1,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_CS2,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_CS3,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_CS4,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_CS5,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_USB_FS1,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_USB_FS2,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_TSIF,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MSM_TSSC,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MSM_PDM,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MSM_DIMEM,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MSM_TCSR,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MSM_PRNG,
+		.buswidth = 4,
+		.ahb = 1,
+	},
+};
+
+static void msm_bus_board_assign_iids(struct msm_bus_fabric_registration
+	*fabreg, int fabid)
+{
+	int i;
+	for (i = 0; i < fabreg->len; i++) {
+		if (!fabreg->info[i].gateway) {
+			fabreg->info[i].priv_id = fabid + fabreg->info[i].id;
+			if (fabreg->info[i].id < SLAVE_ID_KEY)
+				master_iids[fabreg->info[i].id] =
+					fabreg->info[i].priv_id;
+			else
+				slave_iids[fabreg->info[i].id - (SLAVE_ID_KEY)]
+					= fabreg->info[i].priv_id;
+		} else
+			fabreg->info[i].priv_id = fabreg->info[i].id;
+	}
+}
+
+static int msm_bus_board_8960_get_iid(int id)
+{
+	if ((id < SLAVE_ID_KEY && id >= NMASTERS) ||
+		id >= (SLAVE_ID_KEY + NSLAVES)) {
+		MSM_BUS_ERR("Cannot get iid. Invalid id %d passed\n", id);
+		return -EINVAL;
+	}
+
+	return CHECK_ID(((id < SLAVE_ID_KEY) ? master_iids[id] :
+		slave_iids[id - SLAVE_ID_KEY]), id);
+}
+
+static struct msm_bus_board_algorithm msm_bus_board_algo = {
+	.board_nfab = NFAB_8960,
+	.get_iid = msm_bus_board_8960_get_iid,
+	.assign_iids = msm_bus_board_assign_iids,
+};
+
+struct msm_bus_fabric_registration msm_bus_8960_apps_fabric_pdata = {
+	.id = MSM_BUS_FAB_APPSS,
+	.name = "msm_apps_fab",
+	.info = apps_fabric_info,
+	.len = ARRAY_SIZE(apps_fabric_info),
+	.ahb = 0,
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
+	.haltid = MSM_RPM_ID_APPS_FABRIC_CFG_HALT_0,
+	.offset = MSM_RPM_ID_APPS_FABRIC_ARB_0,
+	.nmasters = 6,
+	.nslaves = 5,
+	.ntieredslaves = 3,
+	.board_algo = &msm_bus_board_algo,
+};
+
+struct msm_bus_fabric_registration msm_bus_8960_sys_fabric_pdata = {
+	.id = MSM_BUS_FAB_SYSTEM,
+	.name = "msm_sys_fab",
+	system_fabric_info,
+	ARRAY_SIZE(system_fabric_info),
+	.ahb = 0,
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
+	.haltid = MSM_RPM_ID_SYS_FABRIC_CFG_HALT_0,
+	.offset = MSM_RPM_ID_SYSTEM_FABRIC_ARB_0,
+	.nmasters = 15,
+	.nslaves = 12,
+	.ntieredslaves = 3,
+	.board_algo = &msm_bus_board_algo,
+};
+
+struct msm_bus_fabric_registration msm_bus_8960_mm_fabric_pdata = {
+	.id = MSM_BUS_FAB_MMSS,
+	.name = "msm_mm_fab",
+	mmss_fabric_info,
+	ARRAY_SIZE(mmss_fabric_info),
+	.ahb = 0,
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
+	.haltid = MSM_RPM_ID_MMSS_FABRIC_CFG_HALT_0,
+	.offset = MSM_RPM_ID_MM_FABRIC_ARB_0,
+	.nmasters = 14,
+	.nslaves = 4,
+	.ntieredslaves = 3,
+	.board_algo = &msm_bus_board_algo,
+};
+
+struct msm_bus_fabric_registration msm_bus_8960_sys_fpb_pdata = {
+	.id = MSM_BUS_FAB_SYSTEM_FPB,
+	.name = "msm_sys_fpb",
+	sys_fpb_fabric_info,
+	ARRAY_SIZE(sys_fpb_fabric_info),
+	.ahb = 1,
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
+	.nmasters = 0,
+	.nslaves = 0,
+	.ntieredslaves = 0,
+	.board_algo = &msm_bus_board_algo,
+};
+
+struct msm_bus_fabric_registration msm_bus_8960_cpss_fpb_pdata = {
+	.id = MSM_BUS_FAB_CPSS_FPB,
+	.name = "msm_cpss_fpb",
+	cpss_fpb_fabric_info,
+	ARRAY_SIZE(cpss_fpb_fabric_info),
+	.ahb = 1,
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
+	.nmasters = 0,
+	.nslaves = 0,
+	.ntieredslaves = 0,
+	.board_algo = &msm_bus_board_algo,
+};
+
+int msm_bus_board_rpm_get_il_ids(uint16_t id[])
+{
+	id[0] = MSM_RPM_STATUS_ID_EBI1_CH0_RANGE;
+	id[1] = MSM_RPM_STATUS_ID_EBI1_CH1_RANGE;
+	return 0;
+}
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_9615.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_9615.c
new file mode 100644
index 0000000..34cb2db
--- /dev/null
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_9615.c
@@ -0,0 +1,313 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#include <mach/board.h>
+#include <mach/rpm.h>
+#include "msm_bus_core.h"
+
+#define NMASTERS 14
+#define NSLAVES 12
+#define NFAB_9615 2
+
+enum msm_bus_fabric_tiered_slave_type {
+	MSM_BUS_TIERED_SLAVE_EBI1_CH0 = 1,
+};
+
+enum msm_bus_9615_master_ports_type {
+	MSM_BUS_MASTER_PORT_SPS = 0,
+	MSM_BUS_MASTER_PORT_APSS_PROC,
+	MSM_BUS_MASTER_PORT_ADM_PORT0,
+	MSM_BUS_MASTER_PORT_ADM_PORT1,
+	MSM_BUS_MASTER_PORT_LPASS_PROC,
+	MSM_BUS_MASTER_PORT_MSS,
+	MSM_BUS_MASTER_PORT_MSS_SW_PROC,
+	MSM_BUS_MASTER_PORT_MSS_FW_PROC,
+	MSM_BUS_MASTER_PORT_LPASS,
+	MSM_BUS_SYSTEM_MASTER_PORT_CPSS_FPB,
+	MSM_BUS_SYSTEM_MASTER_PORT_SYSTEM_FPB,
+	MSM_BUS_SYSTEM_MASTER_PORT_ADM_AHB_CI,
+};
+
+enum msm_bus_9615_slave_ports_type {
+	MSM_BUS_SLAVE_PORT_SPS = 0,
+	MSM_BUS_SLAVE_PORT_EBI1_CH0,
+	MSM_BUS_SLAVE_PORT_APSS_L2,
+	MSM_BUS_SLAVE_PORT_SYSTEM_IMEM,
+	MSM_BUS_SLAVE_PORT_CORESIGHT,
+	MSM_BUS_SLAVE_PORT_APSS,
+	MSM_BUS_SLAVE_PORT_MSS,
+	MSM_BUS_SLAVE_PORT_LPASS,
+	MSM_BUS_SYSTEM_SLAVE_PORT_CPSS_FPB,
+	MSM_BUS_SYSTEM_SLAVE_PORT_SYSTEM_FPB,
+};
+
+static int tier2[] = {MSM_BUS_BW_TIER2,};
+static uint32_t master_iids[NMASTERS];
+static uint32_t slave_iids[NSLAVES];
+
+static int sport_ebi1_ch0[] = {MSM_BUS_SLAVE_PORT_EBI1_CH0,};
+static int sport_apss_l2[] = {MSM_BUS_SLAVE_PORT_APSS_L2,};
+
+static int tiered_slave_ebi1_ch0[] = {MSM_BUS_TIERED_SLAVE_EBI1_CH0,};
+
+static int mport_sps[] = {MSM_BUS_MASTER_PORT_SPS,};
+static int mport_apss_proc[] = {MSM_BUS_MASTER_PORT_APSS_PROC,};
+static int mport_adm_port0[] = {MSM_BUS_MASTER_PORT_ADM_PORT0,};
+static int mport_adm_port1[] = {MSM_BUS_MASTER_PORT_ADM_PORT1,};
+static int mport_mss[] = {MSM_BUS_MASTER_PORT_MSS,};
+static int mport_lpass_proc[] = {MSM_BUS_MASTER_PORT_LPASS_PROC,};
+static int mport_mss_sw_proc[] = {MSM_BUS_MASTER_PORT_MSS_SW_PROC,};
+static int mport_mss_fw_proc[] = {MSM_BUS_MASTER_PORT_MSS_FW_PROC,};
+static int mport_lpass[] = {MSM_BUS_MASTER_PORT_LPASS,};
+static int system_mport_adm_ahb_ci[] = {MSM_BUS_SYSTEM_MASTER_PORT_ADM_AHB_CI,};
+static int mport_system_fpb[] = {MSM_BUS_SYSTEM_MASTER_PORT_SYSTEM_FPB,};
+static int system_mport_cpss_fpb[] = {MSM_BUS_SYSTEM_MASTER_PORT_CPSS_FPB,};
+
+static int system_sport_system_fpb[] = {MSM_BUS_SYSTEM_SLAVE_PORT_SYSTEM_FPB,};
+static int system_sport_cpss_fpb[] = {MSM_BUS_SYSTEM_SLAVE_PORT_CPSS_FPB,};
+static int sport_sps[] = {MSM_BUS_SLAVE_PORT_SPS,};
+static int sport_system_imem[] = {MSM_BUS_SLAVE_PORT_SYSTEM_IMEM,};
+static int sport_coresight[] = {MSM_BUS_SLAVE_PORT_CORESIGHT,};
+static int sport_apss[] = {MSM_BUS_SLAVE_PORT_APSS,};
+static int sport_mss[] = {MSM_BUS_SLAVE_PORT_MSS,};
+static int sport_lpass[] = {MSM_BUS_SLAVE_PORT_LPASS,};
+
+static struct msm_bus_node_info system_fabric_info[]  = {
+	{
+		.id = MSM_BUS_MASTER_SPS,
+		.masterp = mport_sps,
+		.num_mports = ARRAY_SIZE(mport_sps),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_ADM_PORT0,
+		.masterp = mport_adm_port0,
+		.num_mports = ARRAY_SIZE(mport_adm_port0),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_ADM_PORT1,
+		.masterp = mport_adm_port1,
+		.num_mports = ARRAY_SIZE(mport_adm_port1),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_LPASS_PROC,
+		.masterp = mport_lpass_proc,
+		.num_mports = ARRAY_SIZE(mport_lpass_proc),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_MSS,
+		.masterp = mport_mss,
+		.num_mports = ARRAY_SIZE(mport_mss),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_AMPSS_M0,
+		.masterp = mport_apss_proc,
+		.num_mports = ARRAY_SIZE(mport_apss_proc),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_MSS_SW_PROC,
+		.masterp = mport_mss_sw_proc,
+		.num_mports = ARRAY_SIZE(mport_mss_sw_proc),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_MSS_FW_PROC,
+		.masterp = mport_mss_fw_proc,
+		.num_mports = ARRAY_SIZE(mport_mss_fw_proc),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_LPASS,
+		.masterp = mport_lpass,
+		.num_mports = ARRAY_SIZE(mport_lpass),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_ADM0_CI,
+		.masterp = system_mport_adm_ahb_ci,
+		.num_mports = ARRAY_SIZE(system_mport_adm_ahb_ci),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_FAB_SYSTEM_FPB,
+		.gateway = 1,
+		.slavep = system_sport_system_fpb,
+		.num_sports = ARRAY_SIZE(system_sport_system_fpb),
+		.masterp = mport_system_fpb,
+		.num_mports = ARRAY_SIZE(mport_system_fpb),
+		.buswidth = 4,
+	},
+	{
+		.id = MSM_BUS_FAB_CPSS_FPB,
+		.gateway = 1,
+		.slavep = system_sport_cpss_fpb,
+		.num_sports = ARRAY_SIZE(system_sport_cpss_fpb),
+		.masterp = system_mport_cpss_fpb,
+		.num_mports = ARRAY_SIZE(system_mport_cpss_fpb),
+		.buswidth = 4,
+	},
+	{
+		.id = MSM_BUS_SLAVE_SPS,
+		.slavep = sport_sps,
+		.num_sports = ARRAY_SIZE(sport_sps),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+		.slaveclk[DUAL_CTX] = "dfab_clk",
+		.slaveclk[ACTIVE_CTX] = "dfab_a_clk",
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI_CH0,
+		.slavep = sport_ebi1_ch0,
+		.num_sports = ARRAY_SIZE(sport_ebi1_ch0),
+		.tier = tiered_slave_ebi1_ch0,
+		.num_tiers = ARRAY_SIZE(tiered_slave_ebi1_ch0),
+		.buswidth = 8,
+		.slaveclk[DUAL_CTX] = "mem_clk",
+		.slaveclk[ACTIVE_CTX] = "mem_a_clk",
+	},
+	{
+		.id = MSM_BUS_SLAVE_SYSTEM_IMEM,
+		.slavep = sport_system_imem,
+		.num_sports = ARRAY_SIZE(sport_system_imem),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_CORESIGHT,
+		.slavep = sport_coresight,
+		.num_sports = ARRAY_SIZE(sport_coresight),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_AMPSS,
+		.slavep = sport_apss,
+		.num_sports = ARRAY_SIZE(sport_apss),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_AMPSS_L2,
+		.slavep = sport_apss_l2,
+		.num_sports = ARRAY_SIZE(sport_apss_l2),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MSS,
+		.slavep = sport_mss,
+		.num_sports = ARRAY_SIZE(sport_mss),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_LPASS,
+		.slavep = sport_lpass,
+		.num_sports = ARRAY_SIZE(sport_lpass),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+};
+
+static void msm_bus_board_assign_iids(struct msm_bus_fabric_registration
+	*fabreg, int fabid)
+{
+	int i;
+	for (i = 0; i < fabreg->len; i++) {
+		if (!fabreg->info[i].gateway) {
+			fabreg->info[i].priv_id = fabid + fabreg->info[i].id;
+			if (fabreg->info[i].id < SLAVE_ID_KEY)
+				master_iids[fabreg->info[i].id] =
+					fabreg->info[i].priv_id;
+			else
+				slave_iids[fabreg->info[i].id - (SLAVE_ID_KEY)]
+					= fabreg->info[i].priv_id;
+		} else
+			fabreg->info[i].priv_id = fabreg->info[i].id;
+	}
+}
+
+static int msm_bus_board_9615_get_iid(int id)
+{
+	if ((id < SLAVE_ID_KEY && id >= NMASTERS) ||
+		id >= (SLAVE_ID_KEY + NSLAVES)) {
+		MSM_BUS_ERR("Cannot get iid. Invalid id %d passed\n", id);
+		return -EINVAL;
+	}
+
+	return ((id < SLAVE_ID_KEY) ? master_iids[id] : slave_iids[id -
+		SLAVE_ID_KEY]);
+}
+
+static struct msm_bus_board_algorithm msm_bus_board_algo = {
+	.board_nfab = NFAB_9615,
+	.get_iid = msm_bus_board_9615_get_iid,
+	.assign_iids = msm_bus_board_assign_iids,
+};
+
+struct msm_bus_fabric_registration msm_bus_9615_sys_fabric_pdata = {
+	.id = MSM_BUS_FAB_SYSTEM,
+	.name = "msm_sys_fab",
+	system_fabric_info,
+	ARRAY_SIZE(system_fabric_info),
+	.ahb = 0,
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
+	.haltid = MSM_RPM_ID_SYS_FABRIC_CFG_HALT_0,
+	.offset = MSM_RPM_ID_SYSTEM_FABRIC_ARB_0,
+	.nmasters = 12,
+	.nslaves = 10,
+	.ntieredslaves = 1,
+	.board_algo = &msm_bus_board_algo,
+};
+
+struct msm_bus_fabric_registration msm_bus_9615_def_fab_pdata = {
+	.id = MSM_BUS_FAB_DEFAULT,
+	.name = "msm_def_fab",
+	.ahb = 1,
+	.nmasters = 0,
+	.nslaves = 0,
+	.ntieredslaves = 0,
+	.board_algo = &msm_bus_board_algo,
+};
+
+int msm_bus_board_rpm_get_il_ids(uint16_t id[])
+{
+	return -ENXIO;
+}
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_config.c b/arch/arm/mach-msm/msm_bus/msm_bus_config.c
new file mode 100644
index 0000000..28f3073
--- /dev/null
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_config.c
@@ -0,0 +1,78 @@
+/* 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
+ * 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.
+ */
+
+#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/radix-tree.h>
+#include <linux/clk.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_bus.h>
+#include "msm_bus_core.h"
+
+static DEFINE_MUTEX(msm_bus_config_lock);
+
+/**
+ * msm_bus_axi_porthalt() - Halt the given axi master port
+ * @master_port: AXI Master port to be halted
+ */
+int msm_bus_axi_porthalt(int master_port)
+{
+	int ret = 0;
+	int priv_id;
+	struct msm_bus_fabric_device *fabdev;
+
+	priv_id = msm_bus_board_get_iid(master_port);
+	MSM_BUS_DBG("master_port: %d iid: %d fabid%d\n",
+		master_port, priv_id, GET_FABID(priv_id));
+	fabdev = msm_bus_get_fabric_device(GET_FABID(priv_id));
+	if (IS_ERR(fabdev)) {
+		MSM_BUS_ERR("Fabric device not found for mport: %d\n",
+			master_port);
+		return -ENODEV;
+	}
+	mutex_lock(&msm_bus_config_lock);
+	ret = fabdev->algo->port_halt(fabdev, priv_id);
+	mutex_unlock(&msm_bus_config_lock);
+	return ret;
+}
+EXPORT_SYMBOL(msm_bus_axi_porthalt);
+
+/**
+ * msm_bus_axi_portunhalt() - Unhalt the given axi master port
+ * @master_port: AXI Master port to be unhalted
+ */
+int msm_bus_axi_portunhalt(int master_port)
+{
+	int ret = 0;
+	int priv_id;
+	struct msm_bus_fabric_device *fabdev;
+
+	priv_id = msm_bus_board_get_iid(master_port);
+	MSM_BUS_DBG("master_port: %d iid: %d fabid: %d\n",
+		master_port, priv_id, GET_FABID(priv_id));
+	fabdev = msm_bus_get_fabric_device(GET_FABID(priv_id));
+	if (IS_ERR(fabdev)) {
+		MSM_BUS_ERR("Fabric device not found for mport: %d\n",
+			master_port);
+		return -ENODEV;
+	}
+	mutex_lock(&msm_bus_config_lock);
+	ret = fabdev->algo->port_unhalt(fabdev, priv_id);
+	mutex_unlock(&msm_bus_config_lock);
+	return ret;
+}
+EXPORT_SYMBOL(msm_bus_axi_portunhalt);
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_core.c b/arch/arm/mach-msm/msm_bus/msm_bus_core.c
new file mode 100644
index 0000000..4d73b03
--- /dev/null
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_core.c
@@ -0,0 +1,117 @@
+/* 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
+ * 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.
+ */
+
+#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/radix-tree.h>
+#include <linux/clk.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_bus.h>
+#include "msm_bus_core.h"
+
+static atomic_t num_fab = ATOMIC_INIT(0);
+
+int msm_bus_get_num_fab(void)
+{
+	return atomic_read(&num_fab);
+}
+
+int msm_bus_device_match(struct device *dev, void* id)
+{
+	struct msm_bus_fabric_device *fabdev = to_msm_bus_fabric_device(dev);
+
+	if (!fabdev) {
+		MSM_BUS_WARN("Fabric %p returning 0\n", fabdev);
+		return 0;
+	}
+	return (fabdev->id == (int)id);
+}
+
+struct bus_type msm_bus_type = {
+	.name      = "msm-bus-type",
+};
+EXPORT_SYMBOL(msm_bus_type);
+
+/**
+ * msm_bus_get_fabric_device() - This function is used to search for
+ * the fabric device on the bus
+ * @fabid: Fabric id
+ * Function returns: Pointer to the fabric device
+ */
+struct msm_bus_fabric_device *msm_bus_get_fabric_device(int fabid)
+{
+	struct device *dev;
+	struct msm_bus_fabric_device *fabric;
+	dev = bus_find_device(&msm_bus_type, NULL, (void *)fabid,
+		msm_bus_device_match);
+	fabric = to_msm_bus_fabric_device(dev);
+	return fabric;
+}
+
+/**
+ * msm_bus_fabric_device_register() - Registers a fabric on msm bus
+ * @fabdev: Fabric device to be registered
+ */
+int msm_bus_fabric_device_register(struct msm_bus_fabric_device *fabdev)
+{
+	int ret = 0;
+	fabdev->dev.bus = &msm_bus_type;
+	ret = dev_set_name(&fabdev->dev, fabdev->name);
+	if (ret) {
+		MSM_BUS_ERR("error setting dev name\n");
+		goto err;
+	}
+	ret = device_register(&fabdev->dev);
+	if (ret < 0) {
+		MSM_BUS_ERR("error registering device%d %s\n",
+				ret, fabdev->name);
+		goto err;
+	}
+	atomic_inc(&num_fab);
+err:
+	return ret;
+}
+
+/**
+ * msm_bus_fabric_device_unregister() - Unregisters the fabric
+ * devices from the msm bus
+ */
+void msm_bus_fabric_device_unregister(struct msm_bus_fabric_device *fabdev)
+{
+	device_unregister(&fabdev->dev);
+	atomic_dec(&num_fab);
+}
+
+static void __exit msm_bus_exit(void)
+{
+	bus_unregister(&msm_bus_type);
+}
+
+static int __init msm_bus_init(void)
+{
+	int retval = 0;
+	retval = bus_register(&msm_bus_type);
+	if (retval)
+		MSM_BUS_ERR("bus_register error! %d\n",
+			retval);
+	return retval;
+}
+postcore_initcall(msm_bus_init);
+module_exit(msm_bus_exit);
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("0.2");
+MODULE_ALIAS("platform:msm_bus");
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_core.h b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
new file mode 100644
index 0000000..341fda8
--- /dev/null
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
@@ -0,0 +1,217 @@
+/* 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
+ * 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 _ARCH_ARM_MACH_MSM_BUS_CORE_H
+#define _ARCH_ARM_MACH_MSM_BUS_CORE_H
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/radix-tree.h>
+#include <linux/platform_device.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_bus.h>
+
+#define MSM_BUS_DBG(msg, ...) \
+	pr_debug(msg, ## __VA_ARGS__)
+#define MSM_BUS_ERR(msg, ...) \
+	pr_err(msg, ## __VA_ARGS__)
+#define MSM_BUS_WARN(msg, ...) \
+	pr_warn(msg, ## __VA_ARGS__)
+#define MSM_FAB_ERR(msg, ...) \
+	dev_err(&fabric->fabdev.dev, msg, ## __VA_ARGS__)
+
+#define IS_MASTER_VALID(mas) \
+	(((mas >= MSM_BUS_MASTER_FIRST) && (mas <= MSM_BUS_MASTER_LAST)) \
+	 ? 1 : 0)
+#define IS_SLAVE_VALID(slv) \
+	(((slv >= MSM_BUS_SLAVE_FIRST) && (slv <= MSM_BUS_SLAVE_LAST)) ? 1 : 0)
+
+#define INTERLEAVED_BW(fab_pdata, bw, ports) \
+	((fab_pdata->il_flag) ? DIV_ROUND_UP((bw), (ports)) : (bw))
+#define INTERLEAVED_VAL(fab_pdata, n) \
+	((fab_pdata->il_flag) ? (n) : 1)
+
+enum msm_bus_dbg_op_type {
+	MSM_BUS_DBG_UNREGISTER = -2,
+	MSM_BUS_DBG_REGISTER,
+	MSM_BUS_DBG_OP = 1,
+};
+
+extern struct bus_type msm_bus_type;
+
+struct msm_bus_node_info {
+	unsigned int id;
+	unsigned int priv_id;
+	int gateway;
+	int *masterp;
+	int num_mports;
+	int *slavep;
+	int num_sports;
+	int *tier;
+	int num_tiers;
+	int ahb;
+	int hw_sel;
+	const char *slaveclk[NUM_CTX];
+	const char *memclk;
+	unsigned int buswidth;
+	unsigned int ws;
+	unsigned int mode;
+};
+
+struct path_node {
+	unsigned long clk[NUM_CTX];
+	unsigned long bw[NUM_CTX];
+	unsigned long *sel_clk;
+	unsigned long *sel_bw;
+	int next;
+};
+
+struct msm_bus_link_info {
+	unsigned long clk[NUM_CTX];
+	unsigned long *sel_clk;
+	unsigned long memclk;
+	long bw[NUM_CTX];
+	long *sel_bw;
+	int *tier;
+	int num_tiers;
+};
+
+struct nodeclk {
+	struct clk *clk;
+	unsigned long rate;
+	bool dirty;
+	bool enable;
+};
+
+struct msm_bus_inode_info {
+	struct msm_bus_node_info *node_info;
+	unsigned long max_bw;
+	unsigned long max_clk;
+	struct msm_bus_link_info link_info;
+	int num_pnodes;
+	struct path_node *pnode;
+	int commit_index;
+	struct nodeclk nodeclk[NUM_CTX];
+	struct nodeclk memclk;
+	void *hw_data;
+};
+
+struct msm_bus_hw_algorithm {
+	int (*allocate_commit_data)(struct msm_bus_fabric_registration
+		*fab_pdata, void **cdata, int ctx);
+	void *(*allocate_hw_data)(struct platform_device *pdev,
+		struct msm_bus_fabric_registration *fab_pdata);
+	void (*node_init)(void *hw_data, struct msm_bus_inode_info *info);
+	void (*free_commit_data)(void *cdata);
+	void (*update_bw)(struct msm_bus_inode_info *hop,
+		struct msm_bus_inode_info *info,
+		struct msm_bus_fabric_registration *fab_pdata,
+		void *sel_cdata, int *master_tiers,
+		long int add_bw);
+	void (*fill_cdata_buffer)(int *curr, char *buf, const int max_size,
+		void *cdata, int nmasters, int nslaves, int ntslaves);
+	int (*commit)(struct msm_bus_fabric_registration
+		*fab_pdata, void *hw_data, void **cdata);
+	int (*port_unhalt)(uint32_t haltid, uint8_t mport);
+	int (*port_halt)(uint32_t haltid, uint8_t mport);
+};
+
+struct msm_bus_fabric_device {
+	int id;
+	const char *name;
+	struct device dev;
+	const struct msm_bus_fab_algorithm *algo;
+	const struct msm_bus_board_algorithm *board_algo;
+	struct msm_bus_hw_algorithm hw_algo;
+	int visited;
+};
+#define to_msm_bus_fabric_device(d) container_of(d, \
+		struct msm_bus_fabric_device, d)
+
+
+struct msm_bus_fab_algorithm {
+	int (*update_clks)(struct msm_bus_fabric_device *fabdev,
+		struct msm_bus_inode_info *pme, int index,
+		unsigned long curr_clk, unsigned long req_clk,
+		unsigned long bwsum, int flag, int ctx,
+		unsigned int cl_active_flag);
+	int (*port_halt)(struct msm_bus_fabric_device *fabdev, int portid);
+	int (*port_unhalt)(struct msm_bus_fabric_device *fabdev, int portid);
+	int (*commit)(struct msm_bus_fabric_device *fabdev);
+	struct msm_bus_inode_info *(*find_node)(struct msm_bus_fabric_device
+		*fabdev, int id);
+	struct msm_bus_inode_info *(*find_gw_node)(struct msm_bus_fabric_device
+		*fabdev, int id);
+	struct list_head *(*get_gw_list)(struct msm_bus_fabric_device *fabdev);
+	void (*update_bw)(struct msm_bus_fabric_device *fabdev, struct
+		msm_bus_inode_info * hop, struct msm_bus_inode_info *info,
+		long int add_bw, int *master_tiers, int ctx);
+};
+
+struct msm_bus_board_algorithm {
+	const int board_nfab;
+	void (*assign_iids)(struct msm_bus_fabric_registration *fabreg,
+		int fabid);
+	int (*get_iid)(int id);
+};
+
+/**
+ * Used to store the list of fabrics and other info to be
+ * maintained outside the fabric structure.
+ * Used while calculating path, and to find fabric ptrs
+ */
+struct msm_bus_fabnodeinfo {
+	struct list_head list;
+	struct msm_bus_inode_info *info;
+};
+
+struct msm_bus_client {
+	int id;
+	struct msm_bus_scale_pdata *pdata;
+	int *src_pnode;
+	int curr;
+};
+
+int msm_bus_fabric_device_register(struct msm_bus_fabric_device *fabric);
+void msm_bus_fabric_device_unregister(struct msm_bus_fabric_device *fabric);
+struct msm_bus_fabric_device *msm_bus_get_fabric_device(int fabid);
+int msm_bus_get_num_fab(void);
+
+void msm_bus_rpm_fill_cdata_buffer(int *curr, char *buf, const int max_size,
+	void *cdata, int nmasters, int nslaves, int ntslaves);
+
+int msm_bus_hw_fab_init(struct msm_bus_fabric_registration *pdata,
+	struct msm_bus_hw_algorithm *hw_algo);
+int msm_bus_rpm_hw_init(struct msm_bus_fabric_registration *pdata,
+	struct msm_bus_hw_algorithm *hw_algo);
+int msm_bus_noc_hw_init(struct msm_bus_fabric_registration *pdata,
+	struct msm_bus_hw_algorithm *hw_algo);
+int msm_bus_bimc_hw_init(struct msm_bus_fabric_registration *pdata,
+	struct msm_bus_hw_algorithm *hw_algo);
+#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_MSM_BUS_SCALING)
+void msm_bus_dbg_client_data(struct msm_bus_scale_pdata *pdata, int index,
+	uint32_t cl);
+void msm_bus_dbg_commit_data(const char *fabname, void *cdata,
+	int nmasters, int nslaves, int ntslaves, int op);
+#else
+static inline void msm_bus_dbg_client_data(struct msm_bus_scale_pdata *pdata,
+	int index, uint32_t cl)
+{
+}
+static inline void msm_bus_dbg_commit_data(const char *fabname,
+	void *cdata, int nmasters, int nslaves, int ntslaves,
+	int op)
+{
+}
+#endif
+
+#endif /*_ARCH_ARM_MACH_MSM_BUS_CORE_H*/
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_dbg.c b/arch/arm/mach-msm/msm_bus/msm_bus_dbg.c
new file mode 100644
index 0000000..76f85c6
--- /dev/null
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_dbg.c
@@ -0,0 +1,715 @@
+/* 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
+ * 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.
+ *
+ */
+
+#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+#include <linux/hrtimer.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_bus.h>
+#include "msm_bus_core.h"
+
+#define MAX_BUFF_SIZE 4096
+#define FILL_LIMIT 128
+
+static struct dentry *clients;
+static struct dentry *dir;
+static DEFINE_MUTEX(msm_bus_dbg_fablist_lock);
+struct msm_bus_dbg_state {
+	uint32_t cl;
+	uint8_t enable;
+	uint8_t current_index;
+} clstate;
+
+struct msm_bus_cldata {
+	const struct msm_bus_scale_pdata *pdata;
+	int index;
+	uint32_t clid;
+	int size;
+	struct dentry *file;
+	struct list_head list;
+	char buffer[MAX_BUFF_SIZE];
+};
+
+struct msm_bus_fab_list {
+	const char *name;
+	int size;
+	struct dentry *file;
+	struct list_head list;
+	char buffer[MAX_BUFF_SIZE];
+};
+
+LIST_HEAD(fabdata_list);
+LIST_HEAD(cl_list);
+
+/**
+ * The following structures and funtions are used for
+ * the test-client which can be created at run-time.
+ */
+
+static struct msm_bus_vectors init_vectors[1];
+static struct msm_bus_vectors current_vectors[1];
+static struct msm_bus_vectors requested_vectors[1];
+
+static struct msm_bus_paths shell_client_usecases[] = {
+	{
+		.num_paths = ARRAY_SIZE(init_vectors),
+		.vectors = init_vectors,
+	},
+	{
+		.num_paths = ARRAY_SIZE(current_vectors),
+		.vectors = current_vectors,
+	},
+	{
+		.num_paths = ARRAY_SIZE(requested_vectors),
+		.vectors = requested_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata shell_client = {
+	.usecase = shell_client_usecases,
+	.num_usecases = ARRAY_SIZE(shell_client_usecases),
+	.name = "test-client",
+};
+
+static void msm_bus_dbg_init_vectors(void)
+{
+	init_vectors[0].src = -1;
+	init_vectors[0].dst = -1;
+	init_vectors[0].ab = 0;
+	init_vectors[0].ib = 0;
+	current_vectors[0].src = -1;
+	current_vectors[0].dst = -1;
+	current_vectors[0].ab = 0;
+	current_vectors[0].ib = 0;
+	requested_vectors[0].src = -1;
+	requested_vectors[0].dst = -1;
+	requested_vectors[0].ab = 0;
+	requested_vectors[0].ib = 0;
+	clstate.enable = 0;
+	clstate.current_index = 0;
+}
+
+static int msm_bus_dbg_update_cl_request(uint32_t cl)
+{
+	int ret = 0;
+
+	if (clstate.current_index < 2)
+		clstate.current_index = 2;
+	else {
+		clstate.current_index = 1;
+		current_vectors[0].ab = requested_vectors[0].ab;
+		current_vectors[0].ib = requested_vectors[0].ib;
+	}
+
+	if (clstate.enable) {
+		MSM_BUS_DBG("Updating request for shell client, index: %d\n",
+			clstate.current_index);
+		ret = msm_bus_scale_client_update_request(clstate.cl,
+			clstate.current_index);
+	} else
+		MSM_BUS_DBG("Enable bit not set. Skipping update request\n");
+
+	return ret;
+}
+
+static void msm_bus_dbg_unregister_client(uint32_t cl)
+{
+	MSM_BUS_DBG("Unregistering shell client\n");
+	msm_bus_scale_unregister_client(clstate.cl);
+	clstate.cl = 0;
+}
+
+static uint32_t msm_bus_dbg_register_client(void)
+{
+	int ret = 0;
+
+	if (init_vectors[0].src != requested_vectors[0].src) {
+		MSM_BUS_DBG("Shell client master changed. Unregistering\n");
+		msm_bus_dbg_unregister_client(clstate.cl);
+	}
+	if (init_vectors[0].dst != requested_vectors[0].dst) {
+		MSM_BUS_DBG("Shell client slave changed. Unregistering\n");
+		msm_bus_dbg_unregister_client(clstate.cl);
+	}
+
+	if (!clstate.enable) {
+		MSM_BUS_DBG("Enable bit not set, skipping registration: cl "
+			"%d\n",	clstate.cl);
+		return 0;
+	}
+
+	if (clstate.cl) {
+		MSM_BUS_DBG("Client  registered, skipping registration\n");
+		return 0;
+	}
+
+	current_vectors[0].src = init_vectors[0].src;
+	requested_vectors[0].src = init_vectors[0].src;
+	current_vectors[0].dst = init_vectors[0].dst;
+	requested_vectors[0].dst = init_vectors[0].dst;
+	MSM_BUS_DBG("Registering shell client\n");
+	ret = msm_bus_scale_register_client(&shell_client);
+	return ret;
+}
+
+static int msm_bus_dbg_mas_get(void  *data, u64 *val)
+{
+	*val = init_vectors[0].src;
+	MSM_BUS_DBG("Get master: %llu\n", *val);
+	return 0;
+}
+
+static int msm_bus_dbg_mas_set(void  *data, u64 val)
+{
+	init_vectors[0].src = val;
+	MSM_BUS_DBG("Set master: %llu\n", val);
+	clstate.cl = msm_bus_dbg_register_client();
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(shell_client_mas_fops, msm_bus_dbg_mas_get,
+	msm_bus_dbg_mas_set, "%llu\n");
+
+static int msm_bus_dbg_slv_get(void  *data, u64 *val)
+{
+	*val = init_vectors[0].dst;
+	MSM_BUS_DBG("Get slave: %llu\n", *val);
+	return 0;
+}
+
+static int msm_bus_dbg_slv_set(void  *data, u64 val)
+{
+	init_vectors[0].dst = val;
+	MSM_BUS_DBG("Set slave: %llu\n", val);
+	clstate.cl = msm_bus_dbg_register_client();
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(shell_client_slv_fops, msm_bus_dbg_slv_get,
+	msm_bus_dbg_slv_set, "%llu\n");
+
+static int msm_bus_dbg_ab_get(void  *data, u64 *val)
+{
+	*val = requested_vectors[0].ab;
+	MSM_BUS_DBG("Get ab: %llu\n", *val);
+	return 0;
+}
+
+static int msm_bus_dbg_ab_set(void  *data, u64 val)
+{
+	requested_vectors[0].ab = val;
+	MSM_BUS_DBG("Set ab: %llu\n", val);
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(shell_client_ab_fops, msm_bus_dbg_ab_get,
+	msm_bus_dbg_ab_set, "%llu\n");
+
+static int msm_bus_dbg_ib_get(void  *data, u64 *val)
+{
+	*val = requested_vectors[0].ib;
+	MSM_BUS_DBG("Get ib: %llu\n", *val);
+	return 0;
+}
+
+static int msm_bus_dbg_ib_set(void  *data, u64 val)
+{
+	requested_vectors[0].ib = val;
+	MSM_BUS_DBG("Set ib: %llu\n", val);
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(shell_client_ib_fops, msm_bus_dbg_ib_get,
+	msm_bus_dbg_ib_set, "%llu\n");
+
+static int msm_bus_dbg_en_get(void  *data, u64 *val)
+{
+	*val = clstate.enable;
+	MSM_BUS_DBG("Get enable: %llu\n", *val);
+	return 0;
+}
+
+static int msm_bus_dbg_en_set(void  *data, u64 val)
+{
+	int ret = 0;
+
+	clstate.enable = val;
+	if (clstate.enable) {
+		if (!clstate.cl) {
+			MSM_BUS_DBG("client: %u\n", clstate.cl);
+			clstate.cl = msm_bus_dbg_register_client();
+			if (clstate.cl)
+				ret = msm_bus_dbg_update_cl_request(clstate.cl);
+		} else {
+			MSM_BUS_DBG("update request for cl: %u\n", clstate.cl);
+			ret = msm_bus_dbg_update_cl_request(clstate.cl);
+		}
+	}
+
+	MSM_BUS_DBG("Set enable: %llu\n", val);
+	return ret;
+}
+DEFINE_SIMPLE_ATTRIBUTE(shell_client_en_fops, msm_bus_dbg_en_get,
+	msm_bus_dbg_en_set, "%llu\n");
+
+/**
+ * The following funtions are used for viewing the client data
+ * and changing the client request at run-time
+ */
+
+static ssize_t client_data_read(struct file *file, char __user *buf,
+	size_t count, loff_t *ppos)
+{
+	int bsize = 0;
+	uint32_t cl = (uint32_t)file->private_data;
+	struct msm_bus_cldata *cldata = NULL;
+
+	list_for_each_entry(cldata, &cl_list, list) {
+		if (cldata->clid == cl)
+			break;
+	}
+	bsize = cldata->size;
+	return simple_read_from_buffer(buf, count, ppos,
+		cldata->buffer, bsize);
+}
+
+static int client_data_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static const struct file_operations client_data_fops = {
+	.open		= client_data_open,
+	.read		= client_data_read,
+};
+
+struct dentry *msm_bus_dbg_create(const char *name, mode_t mode,
+	struct dentry *dent, uint32_t clid)
+{
+	if (dent == NULL) {
+		MSM_BUS_DBG("debugfs not ready yet\n");
+		return NULL;
+	}
+	return debugfs_create_file(name, mode, dent, (void *)clid,
+		&client_data_fops);
+}
+
+static int msm_bus_dbg_record_client(const struct msm_bus_scale_pdata *pdata,
+	int index, uint32_t clid, struct dentry *file)
+{
+	struct msm_bus_cldata *cldata;
+
+	cldata = kmalloc(sizeof(struct msm_bus_cldata), GFP_KERNEL);
+	if (!cldata) {
+		MSM_BUS_DBG("Failed to allocate memory for client data\n");
+		return -ENOMEM;
+	}
+	cldata->pdata = pdata;
+	cldata->index = index;
+	cldata->clid = clid;
+	cldata->file = file;
+	cldata->size = 0;
+	list_add_tail(&cldata->list, &cl_list);
+	return 0;
+}
+
+static void msm_bus_dbg_free_client(uint32_t clid)
+{
+	struct msm_bus_cldata *cldata = NULL;
+
+	list_for_each_entry(cldata, &cl_list, list) {
+		if (cldata->clid == clid) {
+			debugfs_remove(cldata->file);
+			list_del(&cldata->list);
+			kfree(cldata);
+			break;
+		}
+	}
+}
+
+static int msm_bus_dbg_fill_cl_buffer(const struct msm_bus_scale_pdata *pdata,
+	int index, uint32_t clid)
+{
+	int i = 0, j;
+	char *buf = NULL;
+	struct msm_bus_cldata *cldata = NULL;
+	struct timespec ts;
+
+	list_for_each_entry(cldata, &cl_list, list) {
+		if (cldata->clid == clid)
+			break;
+	}
+	if (cldata->file == NULL) {
+		if (pdata->name == NULL) {
+			MSM_BUS_DBG("Client doesn't have a name\n");
+			return -EINVAL;
+		}
+		cldata->file = msm_bus_dbg_create(pdata->name, S_IRUGO,
+			clients, clid);
+	}
+
+	if (cldata->size < (MAX_BUFF_SIZE - FILL_LIMIT))
+		i = cldata->size;
+	else {
+		i = 0;
+		cldata->size = 0;
+	}
+	buf = cldata->buffer;
+	ts = ktime_to_timespec(ktime_get());
+	i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\n%d.%d\n",
+		(int)ts.tv_sec, (int)ts.tv_nsec);
+	i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "curr   : %d\n", index);
+	i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "masters: ");
+
+	for (j = 0; j < pdata->usecase->num_paths; j++)
+		i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "%d  ",
+			pdata->usecase[index].vectors[j].src);
+	i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\nslaves : ");
+	for (j = 0; j < pdata->usecase->num_paths; j++)
+		i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "%d  ",
+			pdata->usecase[index].vectors[j].dst);
+	i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\nab     : ");
+	for (j = 0; j < pdata->usecase->num_paths; j++)
+		i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "%u  ",
+			pdata->usecase[index].vectors[j].ab);
+	i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\nib     : ");
+	for (j = 0; j < pdata->usecase->num_paths; j++)
+		i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "%u  ",
+			pdata->usecase[index].vectors[j].ib);
+	i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\n");
+
+	cldata->size = i;
+	return i;
+}
+
+static int msm_bus_dbg_update_request(struct msm_bus_cldata *cldata, int index)
+{
+	int ret = 0;
+
+	if ((index < 0) || (index > cldata->pdata->num_usecases)) {
+		MSM_BUS_DBG("Invalid index!\n");
+		return -EINVAL;
+	}
+	ret = msm_bus_scale_client_update_request(cldata->clid, index);
+	return ret;
+}
+
+static ssize_t  msm_bus_dbg_update_request_write(struct file *file,
+	const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	struct msm_bus_cldata *cldata;
+	unsigned long index = 0;
+	int ret = 0;
+	char *chid;
+	char *buf = kmalloc((sizeof(char) * (cnt + 1)), GFP_KERNEL);
+
+	if (!buf || IS_ERR(buf)) {
+		MSM_BUS_ERR("Memory allocation for buffer failed\n");
+		return -ENOMEM;
+	}
+	if (cnt == 0)
+		return 0;
+	if (copy_from_user(buf, ubuf, cnt))
+		return -EFAULT;
+	buf[cnt] = '\0';
+	chid = buf;
+	MSM_BUS_DBG("buffer: %s\n size: %d\n", buf, sizeof(ubuf));
+
+	list_for_each_entry(cldata, &cl_list, list) {
+		if (strstr(chid, cldata->pdata->name)) {
+			cldata = cldata;
+			strsep(&chid, " ");
+			if (chid) {
+				ret = strict_strtoul(chid, 10, &index);
+				if (ret) {
+					MSM_BUS_DBG("Index conversion"
+						" failed\n");
+					return -EFAULT;
+				}
+			} else
+				MSM_BUS_DBG("Error parsing input. Index not"
+					" found\n");
+			break;
+		}
+	}
+
+	msm_bus_dbg_update_request(cldata, index);
+	kfree(buf);
+	return cnt;
+}
+
+/**
+ * The following funtions are used for viewing the commit data
+ * for each fabric
+ */
+static ssize_t fabric_data_read(struct file *file, char __user *buf,
+	size_t count, loff_t *ppos)
+{
+	struct msm_bus_fab_list *fablist = NULL;
+	int bsize = 0;
+	ssize_t ret;
+	const char *name = file->private_data;
+
+	mutex_lock(&msm_bus_dbg_fablist_lock);
+	list_for_each_entry(fablist, &fabdata_list, list) {
+		if (strcmp(fablist->name, name) == 0)
+			break;
+	}
+	bsize = fablist->size;
+	ret = simple_read_from_buffer(buf, count, ppos,
+		fablist->buffer, bsize);
+	mutex_unlock(&msm_bus_dbg_fablist_lock);
+	return ret;
+}
+
+static const struct file_operations fabric_data_fops = {
+	.open		= client_data_open,
+	.read		= fabric_data_read,
+};
+
+static int msm_bus_dbg_record_fabric(const char *fabname, struct dentry *file)
+{
+	struct msm_bus_fab_list *fablist;
+	int ret = 0;
+
+	mutex_lock(&msm_bus_dbg_fablist_lock);
+	fablist = kmalloc(sizeof(struct msm_bus_fab_list), GFP_KERNEL);
+	if (!fablist) {
+		MSM_BUS_DBG("Failed to allocate memory for commit data\n");
+		ret =  -ENOMEM;
+		goto err;
+	}
+
+	fablist->name = fabname;
+	fablist->size = 0;
+	list_add_tail(&fablist->list, &fabdata_list);
+err:
+	mutex_unlock(&msm_bus_dbg_fablist_lock);
+	return ret;
+}
+
+static void msm_bus_dbg_free_fabric(const char *fabname)
+{
+	struct msm_bus_fab_list *fablist = NULL;
+
+	mutex_lock(&msm_bus_dbg_fablist_lock);
+	list_for_each_entry(fablist, &fabdata_list, list) {
+		if (strcmp(fablist->name, fabname) == 0) {
+			debugfs_remove(fablist->file);
+			list_del(&fablist->list);
+			kfree(fablist);
+			break;
+		}
+	}
+	mutex_unlock(&msm_bus_dbg_fablist_lock);
+}
+
+static int msm_bus_dbg_fill_fab_buffer(const char *fabname,
+	void *cdata, int nmasters, int nslaves,
+	int ntslaves)
+{
+	int i;
+	char *buf = NULL;
+	struct msm_bus_fab_list *fablist = NULL;
+	struct timespec ts;
+
+	mutex_lock(&msm_bus_dbg_fablist_lock);
+	list_for_each_entry(fablist, &fabdata_list, list) {
+		if (strcmp(fablist->name, fabname) == 0)
+			break;
+	}
+	if (fablist->file == NULL) {
+		MSM_BUS_DBG("Fabric dbg entry does not exist\n");
+		mutex_unlock(&msm_bus_dbg_fablist_lock);
+		return -EFAULT;
+	}
+
+	if (fablist->size < MAX_BUFF_SIZE - 256)
+		i = fablist->size;
+	else {
+		i = 0;
+		fablist->size = 0;
+	}
+	buf = fablist->buffer;
+	mutex_unlock(&msm_bus_dbg_fablist_lock);
+	ts = ktime_to_timespec(ktime_get());
+	i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\n%d.%d\n",
+		(int)ts.tv_sec, (int)ts.tv_nsec);
+
+	msm_bus_rpm_fill_cdata_buffer(&i, buf, MAX_BUFF_SIZE, cdata,
+		nmasters, nslaves, ntslaves);
+	i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\n");
+	mutex_lock(&msm_bus_dbg_fablist_lock);
+	fablist->size = i;
+	mutex_unlock(&msm_bus_dbg_fablist_lock);
+	return 0;
+}
+
+static const struct file_operations msm_bus_dbg_update_request_fops = {
+	.open = client_data_open,
+	.write = msm_bus_dbg_update_request_write,
+};
+
+/**
+ * msm_bus_dbg_client_data() - Add debug data for clients
+ * @pdata: Platform data of the client
+ * @index: The current index or operation to be performed
+ * @clid: Client handle obtained during registration
+ */
+void msm_bus_dbg_client_data(struct msm_bus_scale_pdata *pdata, int index,
+	uint32_t clid)
+{
+	struct dentry *file = NULL;
+
+	if (index == MSM_BUS_DBG_REGISTER) {
+		msm_bus_dbg_record_client(pdata, index, clid, file);
+		if (!pdata->name) {
+			MSM_BUS_DBG("Cannot create debugfs entry. Null name\n");
+			return;
+		}
+	} else if (index == MSM_BUS_DBG_UNREGISTER) {
+		msm_bus_dbg_free_client(clid);
+		MSM_BUS_DBG("Client %d unregistered\n", clid);
+	} else
+		msm_bus_dbg_fill_cl_buffer(pdata, index, clid);
+}
+EXPORT_SYMBOL(msm_bus_dbg_client_data);
+
+/**
+ * msm_bus_dbg_commit_data() - Add commit data from fabrics
+ * @fabname: Fabric name specified in platform data
+ * @cdata: Commit Data
+ * @nmasters: Number of masters attached to fabric
+ * @nslaves: Number of slaves attached to fabric
+ * @ntslaves: Number of tiered slaves attached to fabric
+ * @op: Operation to be performed
+ */
+void msm_bus_dbg_commit_data(const char *fabname, void *cdata,
+	int nmasters, int nslaves, int ntslaves, int op)
+{
+	struct dentry *file = NULL;
+
+	if (op == MSM_BUS_DBG_REGISTER)
+		msm_bus_dbg_record_fabric(fabname, file);
+	else if (op == MSM_BUS_DBG_UNREGISTER)
+		msm_bus_dbg_free_fabric(fabname);
+	else
+		msm_bus_dbg_fill_fab_buffer(fabname, cdata, nmasters,
+			nslaves, ntslaves);
+}
+EXPORT_SYMBOL(msm_bus_dbg_commit_data);
+
+static int __init msm_bus_debugfs_init(void)
+{
+	struct dentry *commit, *shell_client;
+	struct msm_bus_fab_list *fablist;
+	struct msm_bus_cldata *cldata = NULL;
+	uint64_t val = 0;
+
+	dir = debugfs_create_dir("msm-bus-dbg", NULL);
+	if ((!dir) || IS_ERR(dir)) {
+		MSM_BUS_ERR("Couldn't create msm-bus-dbg\n");
+		goto err;
+	}
+
+	clients = debugfs_create_dir("client-data", dir);
+	if ((!dir) || IS_ERR(dir)) {
+		MSM_BUS_ERR("Couldn't create clients\n");
+		goto err;
+	}
+
+	shell_client = debugfs_create_dir("shell-client", dir);
+	if ((!dir) || IS_ERR(dir)) {
+		MSM_BUS_ERR("Couldn't create clients\n");
+		goto err;
+	}
+
+	commit = debugfs_create_dir("commit-data", dir);
+	if ((!dir) || IS_ERR(dir)) {
+		MSM_BUS_ERR("Couldn't create commit\n");
+		goto err;
+	}
+
+	if (debugfs_create_file("update_request", S_IRUGO | S_IWUSR,
+		shell_client, &val, &shell_client_en_fops) == NULL)
+		goto err;
+	if (debugfs_create_file("ib", S_IRUGO | S_IWUSR, shell_client, &val,
+		&shell_client_ib_fops) == NULL)
+		goto err;
+	if (debugfs_create_file("ab", S_IRUGO | S_IWUSR, shell_client, &val,
+		&shell_client_ab_fops) == NULL)
+		goto err;
+	if (debugfs_create_file("slv", S_IRUGO | S_IWUSR, shell_client,
+		&val, &shell_client_slv_fops) == NULL)
+		goto err;
+	if (debugfs_create_file("mas", S_IRUGO | S_IWUSR, shell_client,
+		&val, &shell_client_mas_fops) == NULL)
+		goto err;
+	if (debugfs_create_file("update-request", S_IRUGO | S_IWUSR,
+		clients, NULL, &msm_bus_dbg_update_request_fops) == NULL)
+		goto err;
+
+	list_for_each_entry(cldata, &cl_list, list) {
+		if (cldata->pdata->name == NULL) {
+			MSM_BUS_DBG("Client name not found\n");
+			continue;
+		}
+		cldata->file = msm_bus_dbg_create(cldata->
+			pdata->name, S_IRUGO, clients, cldata->clid);
+	}
+
+	mutex_lock(&msm_bus_dbg_fablist_lock);
+	list_for_each_entry(fablist, &fabdata_list, list) {
+		fablist->file = debugfs_create_file(fablist->name, S_IRUGO,
+			commit, (void *)fablist->name, &fabric_data_fops);
+		if (fablist->file == NULL) {
+			MSM_BUS_DBG("Cannot create files for commit data\n");
+			goto err;
+		}
+	}
+	mutex_unlock(&msm_bus_dbg_fablist_lock);
+
+	msm_bus_dbg_init_vectors();
+	return 0;
+err:
+	debugfs_remove_recursive(dir);
+	return -ENODEV;
+}
+late_initcall(msm_bus_debugfs_init);
+
+static void __exit msm_bus_dbg_teardown(void)
+{
+	struct msm_bus_fab_list *fablist = NULL, *fablist_temp;
+	struct msm_bus_cldata *cldata = NULL, *cldata_temp;
+
+	debugfs_remove_recursive(dir);
+	list_for_each_entry_safe(cldata, cldata_temp, &cl_list, list) {
+		list_del(&cldata->list);
+		kfree(cldata);
+	}
+	mutex_lock(&msm_bus_dbg_fablist_lock);
+	list_for_each_entry_safe(fablist, fablist_temp, &fabdata_list, list) {
+		list_del(&fablist->list);
+		kfree(fablist);
+	}
+	mutex_unlock(&msm_bus_dbg_fablist_lock);
+}
+module_exit(msm_bus_dbg_teardown);
+MODULE_DESCRIPTION("Debugfs for msm bus scaling client");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Gagan Mac <gmac@codeaurora.org>");
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
new file mode 100644
index 0000000..8c015d1
--- /dev/null
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -0,0 +1,752 @@
+/* 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
+ * 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.
+ */
+
+#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/radix-tree.h>
+#include <mach/board.h>
+#include <mach/socinfo.h>
+#include "msm_bus_core.h"
+
+enum {
+	SLAVE_NODE,
+	MASTER_NODE,
+};
+
+enum {
+	DISABLE,
+	ENABLE,
+};
+
+struct msm_bus_fabric {
+	struct msm_bus_fabric_device fabdev;
+	int ahb;
+	void *cdata[NUM_CTX];
+	bool arb_dirty;
+	bool clk_dirty;
+	struct radix_tree_root fab_tree;
+	int num_nodes;
+	struct list_head gateways;
+	struct msm_bus_inode_info info;
+	struct msm_bus_fabric_registration *pdata;
+	void *hw_data;
+};
+#define to_msm_bus_fabric(d) container_of(d, \
+	struct msm_bus_fabric, d)
+
+/**
+ * msm_bus_fabric_add_node() - Add a node to the fabric structure
+ * @fabric: Fabric device to which the node should be added
+ * @info: The node to be added
+ */
+static int msm_bus_fabric_add_node(struct msm_bus_fabric *fabric,
+	struct msm_bus_inode_info *info)
+{
+	int status = -ENOMEM;
+	MSM_BUS_DBG("msm_bus_fabric_add_node: ID %d Gw: %d\n",
+		info->node_info->priv_id, info->node_info->gateway);
+	status = radix_tree_preload(GFP_ATOMIC);
+	if (status)
+		goto out;
+
+	status = radix_tree_insert(&fabric->fab_tree, info->node_info->priv_id,
+			info);
+	radix_tree_preload_end();
+	if (IS_SLAVE(info->node_info->priv_id))
+		radix_tree_tag_set(&fabric->fab_tree, info->node_info->priv_id,
+			SLAVE_NODE);
+
+	if (info->node_info->slaveclk[DUAL_CTX]) {
+		info->nodeclk[DUAL_CTX].clk = clk_get_sys("msm_bus",
+			info->node_info->slaveclk[DUAL_CTX]);
+		if (IS_ERR(info->nodeclk[DUAL_CTX].clk)) {
+			MSM_BUS_ERR("Could not get clock for %s\n",
+				info->node_info->slaveclk[DUAL_CTX]);
+			status = -EINVAL;
+			goto out;
+		}
+		info->nodeclk[DUAL_CTX].enable = false;
+		info->nodeclk[DUAL_CTX].dirty = false;
+	}
+
+out:
+	return status;
+}
+
+/**
+ * msm_bus_add_fab() - Add a fabric (gateway) to the current fabric
+ * @fabric: Fabric device to which the gateway info should be added
+ * @info: Gateway node to be added to the fabric
+ */
+static int msm_bus_fabric_add_fab(struct msm_bus_fabric *fabric,
+	struct msm_bus_inode_info *info)
+{
+	struct msm_bus_fabnodeinfo *fabnodeinfo;
+	MSM_BUS_DBG("msm_bus_fabric_add_fab: ID %d Gw: %d\n",
+		info->node_info->priv_id, info->node_info->gateway);
+	fabnodeinfo = kzalloc(sizeof(struct msm_bus_fabnodeinfo), GFP_KERNEL);
+	if (fabnodeinfo == NULL) {
+		MSM_FAB_ERR("msm_bus_fabric_add_fab: "
+			"No Node Info\n");
+		MSM_FAB_ERR("axi: Cannot register fabric!\n");
+		return -ENOMEM;
+	}
+
+	fabnodeinfo->info = info;
+	fabnodeinfo->info->num_pnodes = -1;
+	list_add_tail(&fabnodeinfo->list, &fabric->gateways);
+	return 0;
+}
+
+/**
+ * register_fabric_info() - Create the internal fabric structure and
+ * build the topology tree from platform specific data
+ * @pdev: Platform device for getting base addresses
+ * @fabric: Fabric to which the gateways, nodes should be added
+ *
+ * This function is called from probe. Iterates over the platform data,
+ * and builds the topology
+ */
+static int register_fabric_info(struct platform_device *pdev,
+	struct msm_bus_fabric *fabric)
+{
+	int i = 0, ret = 0, err = 0;
+
+	MSM_BUS_DBG("id:%d pdata-id: %d len: %d\n", fabric->fabdev.id,
+		fabric->pdata->id, fabric->pdata->len);
+	fabric->hw_data = fabric->fabdev.hw_algo.allocate_hw_data(pdev,
+		fabric->pdata);
+	if (ZERO_OR_NULL_PTR(fabric->hw_data)) {
+		MSM_BUS_ERR("Couldn't allocate hw_data for fab: %d\n",
+			fabric->fabdev.id);
+		goto error;
+	}
+
+	for (i = 0; i < fabric->pdata->len; i++) {
+		struct msm_bus_inode_info *info;
+		int ctx;
+
+		info = kzalloc(sizeof(struct msm_bus_inode_info), GFP_KERNEL);
+		if (info == NULL) {
+			MSM_BUS_ERR("Error allocating info\n");
+			return -ENOMEM;
+		}
+
+		info->node_info = fabric->pdata->info + i;
+		info->commit_index = -1;
+		info->num_pnodes = -1;
+
+		for (ctx = 0; ctx < NUM_CTX; ctx++) {
+			if (info->node_info->slaveclk[ctx]) {
+				info->nodeclk[ctx].clk = clk_get_sys("msm_bus",
+					info->node_info->slaveclk[ctx]);
+				if (IS_ERR(info->nodeclk[ctx].clk)) {
+					MSM_BUS_ERR("Couldn't get clk %s\n",
+						info->node_info->slaveclk[ctx]);
+					err = -EINVAL;
+				}
+				info->nodeclk[ctx].enable = false;
+				info->nodeclk[ctx].dirty = false;
+			}
+		}
+		if (info->node_info->memclk) {
+			info->memclk.clk = clk_get_sys("msm_bus",
+					info->node_info->memclk);
+			if (IS_ERR(info->memclk.clk)) {
+				MSM_BUS_ERR("Couldn't get clk %s\n",
+					info->node_info->memclk);
+				err = -EINVAL;
+			}
+			info->memclk.enable = false;
+			info->memclk.dirty = false;
+		}
+
+		ret = info->node_info->gateway ?
+			msm_bus_fabric_add_fab(fabric, info) :
+			msm_bus_fabric_add_node(fabric, info);
+		if (ret) {
+			MSM_BUS_ERR("Unable to add node info, ret: %d\n", ret);
+			kfree(info);
+			goto error;
+		}
+
+		if (fabric->fabdev.hw_algo.node_init == NULL)
+			continue;
+
+		fabric->fabdev.hw_algo.node_init(fabric->hw_data, info);
+		if (ret) {
+			MSM_BUS_ERR("Unable to init node info, ret: %d\n", ret);
+			kfree(info);
+		}
+	}
+
+	MSM_BUS_DBG("Fabric: %d nmasters: %d nslaves: %d\n"
+		" ntieredslaves: %d, rpm_enabled: %d\n",
+		fabric->fabdev.id, fabric->pdata->nmasters,
+		fabric->pdata->nslaves, fabric->pdata->ntieredslaves,
+		fabric->pdata->rpm_enabled);
+	MSM_BUS_DBG("msm_bus_register_fabric_info i: %d\n", i);
+	fabric->num_nodes = fabric->pdata->len;
+error:
+	fabric->num_nodes = i;
+	msm_bus_dbg_commit_data(fabric->fabdev.name, NULL, 0, 0, 0,
+		MSM_BUS_DBG_REGISTER);
+	return ret | err;
+}
+
+/**
+ * msm_bus_fabric_update_clks() - Set the clocks for fabrics and slaves
+ * @fabric: Fabric for which the clocks need to be updated
+ * @slave: The node for which the clocks need to be updated
+ * @index: The index for which the current clocks are set
+ * @curr_clk_hz:Current clock value
+ * @req_clk_hz: Requested clock value
+ * @bwsum: Bandwidth Sum
+ * @clk_flag: Flag determining whether fabric clock or the slave clock has to
+ * be set. If clk_flag is set, fabric clock is set, else slave clock is set.
+ */
+static int msm_bus_fabric_update_clks(struct msm_bus_fabric_device *fabdev,
+		struct msm_bus_inode_info *slave, int index,
+		unsigned long curr_clk_hz, unsigned long req_clk_hz,
+		unsigned long bwsum_hz, int clk_flag, int ctx,
+		unsigned int cl_active_flag)
+{
+	int i, status = 0;
+	unsigned long max_pclk = 0, rate;
+	unsigned long *pclk = NULL;
+	struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
+	struct nodeclk *nodeclk;
+
+	/**
+	 * Integration for clock rates is not required if context is not
+	 * same as client's active-only flag
+	 */
+	if (ctx != cl_active_flag)
+		goto skip_set_clks;
+
+	/* Maximum for this gateway */
+	for (i = 0; i <= slave->num_pnodes; i++) {
+		if (i == index && (req_clk_hz < curr_clk_hz))
+			continue;
+		slave->pnode[i].sel_clk = &slave->pnode[i].clk[ctx];
+		max_pclk = max(max_pclk, *slave->pnode[i].sel_clk);
+	}
+
+	*slave->link_info.sel_clk =
+		max(max_pclk, max(bwsum_hz, req_clk_hz));
+	/* Is this gateway or slave? */
+	if (clk_flag && (!fabric->ahb)) {
+		struct msm_bus_fabnodeinfo *fabgw = NULL;
+		struct msm_bus_inode_info *info = NULL;
+		/* Maximum of all gateways set at fabric */
+		list_for_each_entry(fabgw, &fabric->gateways, list) {
+			info = fabgw->info;
+			if (!info)
+				continue;
+			info->link_info.sel_clk = &info->link_info.clk[ctx];
+			max_pclk = max(max_pclk, *info->link_info.sel_clk);
+		}
+		MSM_BUS_DBG("max_pclk from gateways: %lu\n", max_pclk);
+
+		/* Maximum of all slave clocks. */
+
+		for (i = 0; i < fabric->pdata->len; i++) {
+			if (fabric->pdata->info[i].gateway ||
+				(fabric->pdata->info[i].id < SLAVE_ID_KEY))
+				continue;
+			info = radix_tree_lookup(&fabric->fab_tree,
+				fabric->pdata->info[i].priv_id);
+			if (!info)
+				continue;
+			info->link_info.sel_clk = &info->link_info.clk[ctx];
+			max_pclk = max(max_pclk, *info->link_info.sel_clk);
+		}
+
+
+		MSM_BUS_DBG("max_pclk from slaves & gws: %lu\n", max_pclk);
+		fabric->info.link_info.sel_clk =
+			&fabric->info.link_info.clk[ctx];
+		pclk = fabric->info.link_info.sel_clk;
+	} else {
+		slave->link_info.sel_clk = &slave->link_info.clk[ctx];
+		pclk = slave->link_info.sel_clk;
+	}
+
+
+	*pclk = max(max_pclk, max(bwsum_hz, req_clk_hz));
+
+	if (!fabric->pdata->rpm_enabled)
+		goto skip_set_clks;
+
+	if (clk_flag) {
+		nodeclk = &fabric->info.nodeclk[ctx];
+		if (nodeclk->clk) {
+			MSM_BUS_DBG("clks: id: %d set-clk: %lu bwsum_hz:%lu\n",
+			fabric->fabdev.id, *pclk, bwsum_hz);
+			if (nodeclk->rate != *pclk) {
+				nodeclk->dirty = true;
+				nodeclk->rate = *pclk;
+			}
+			fabric->clk_dirty = true;
+		}
+	} else {
+		nodeclk = &slave->nodeclk[ctx];
+		if (nodeclk->clk) {
+			rate = *pclk;
+			MSM_BUS_DBG("AXI_clks: id: %d set-clk: %lu "
+			"bwsum_hz: %lu\n" , slave->node_info->priv_id, rate,
+			bwsum_hz);
+			if (nodeclk->rate != rate) {
+				nodeclk->dirty = true;
+				nodeclk->rate = rate;
+			}
+		}
+		if (!status && slave->memclk.clk) {
+			rate = *slave->link_info.sel_clk;
+			if (slave->memclk.rate != rate) {
+				slave->memclk.rate = rate;
+				slave->memclk.dirty = true;
+			}
+			slave->memclk.rate = rate;
+			fabric->clk_dirty = true;
+		}
+	}
+skip_set_clks:
+	return status;
+}
+
+void msm_bus_fabric_update_bw(struct msm_bus_fabric_device *fabdev,
+	struct msm_bus_inode_info *hop, struct msm_bus_inode_info *info,
+	long int add_bw, int *master_tiers, int ctx)
+{
+	struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
+	void *sel_cdata;
+
+	/* Temporarily stub out arbitration settings for copper */
+	if (machine_is_copper())
+		return;
+
+	sel_cdata = fabric->cdata[ctx];
+
+	/* If it's an ahb fabric, don't calculate arb values */
+	if (fabric->ahb) {
+		MSM_BUS_DBG("AHB fabric, skipping bw calculation\n");
+		return;
+	}
+	if (!add_bw) {
+		MSM_BUS_DBG("No bandwidth delta. Skipping commit\n");
+		return;
+	}
+
+	fabdev->hw_algo.update_bw(hop, info, fabric->pdata, sel_cdata,
+		master_tiers, add_bw);
+	fabric->arb_dirty = true;
+}
+
+static int msm_bus_fabric_clk_set(int enable, struct msm_bus_inode_info *info)
+{
+	int i, status = 0;
+	for (i = 0; i < NUM_CTX; i++)
+		if (info->nodeclk[i].dirty) {
+			status = clk_set_rate(info->nodeclk[i].clk, info->
+				nodeclk[i].rate);
+			if (enable && !(info->nodeclk[i].enable)) {
+				clk_prepare_enable(info->nodeclk[i].clk);
+				info->nodeclk[i].dirty = false;
+				info->nodeclk[i].enable = true;
+			} else if ((info->nodeclk[i].rate == 0) && (!enable)
+				&& (info->nodeclk[i].enable)) {
+				clk_disable_unprepare(info->nodeclk[i].clk);
+				info->nodeclk[i].dirty = false;
+				info->nodeclk[i].enable = false;
+			}
+		}
+
+	if (info->memclk.dirty) {
+		status = clk_set_rate(info->memclk.clk, info->memclk.rate);
+		if (enable && !(info->memclk.enable)) {
+			clk_prepare_enable(info->memclk.clk);
+			info->memclk.dirty = false;
+			info->memclk.enable = true;
+		} else if (info->memclk.rate == 0 && (!enable) &&
+			(info->memclk.enable)) {
+			clk_disable_unprepare(info->memclk.clk);
+			info->memclk.dirty = false;
+			info->memclk.enable = false;
+		}
+	}
+
+	return status;
+}
+
+/**
+ * msm_bus_fabric_clk_commit() - Call clock enable and update clock
+ * values.
+*/
+static int msm_bus_fabric_clk_commit(int enable, struct msm_bus_fabric *fabric)
+{
+	unsigned int i, nfound = 0, status = 0;
+	struct msm_bus_inode_info *info[fabric->pdata->nslaves];
+
+	if (fabric->clk_dirty == false) {
+		MSM_BUS_DBG("No clocks have been touched for fabric: %d\n",
+			fabric->fabdev.id);
+		goto out;
+	} else
+		status = msm_bus_fabric_clk_set(enable, &fabric->info);
+
+	if (status)
+		MSM_BUS_WARN("Error setting clocks on fabric: %d\n",
+			fabric->fabdev.id);
+
+	nfound = radix_tree_gang_lookup_tag(&fabric->fab_tree, (void **)&info,
+		fabric->fabdev.id, fabric->pdata->nslaves, SLAVE_NODE);
+	if (nfound == 0) {
+		MSM_BUS_DBG("No slaves found for fabric: %d\n",
+			fabric->fabdev.id);
+		goto out;
+	}
+
+	for (i = 0; i < nfound; i++) {
+		status = msm_bus_fabric_clk_set(enable, info[i]);
+		if (status)
+			MSM_BUS_WARN("Error setting clocks for node: %d\n",
+				info[i]->node_info->id);
+	}
+
+out:
+	return status;
+}
+
+/**
+ * msm_bus_fabric_hw_commit() - Commit the arbitration data to Hardware.
+ * @fabric: Fabric for which the data should be committed
+ * */
+static int msm_bus_fabric_hw_commit(struct msm_bus_fabric_device *fabdev)
+{
+	int status = 0;
+	struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
+
+	/*
+	 * For a non-zero bandwidth request, clocks should be enabled before
+	 * sending the arbitration data to RPM, but should be disabled only
+	 * after commiting the data.
+	 */
+	status = msm_bus_fabric_clk_commit(ENABLE, fabric);
+	if (status)
+		MSM_BUS_DBG("Error setting clocks on fabric: %d\n",
+			fabric->fabdev.id);
+
+	if (!fabric->arb_dirty) {
+		MSM_BUS_DBG("Not committing as fabric not arb_dirty\n");
+		goto skip_arb;
+	}
+
+	status = fabdev->hw_algo.commit(fabric->pdata, fabric->hw_data,
+		(void **)fabric->cdata);
+	if (status)
+		MSM_BUS_DBG("Error committing arb data for fabric: %d\n",
+			fabric->fabdev.id);
+
+	fabric->arb_dirty = false;
+skip_arb:
+	/*
+	 * If the bandwidth request is 0 for a fabric, the clocks
+	 * should be disabled after arbitration data is committed.
+	 */
+	status = msm_bus_fabric_clk_commit(DISABLE, fabric);
+	if (status)
+		MSM_BUS_DBG("Error disabling clocks on fabric: %d\n",
+			fabric->fabdev.id);
+	fabric->clk_dirty = false;
+	return status;
+}
+
+/**
+ * msm_bus_fabric_port_halt() - Used to halt a master port
+ * @fabric: Fabric on which the current master node is present
+ * @portid: Port id of the master
+ */
+int msm_bus_fabric_port_halt(struct msm_bus_fabric_device *fabdev, int iid)
+{
+	struct msm_bus_inode_info *info = NULL;
+	uint8_t mport;
+	uint32_t haltid = 0;
+	struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
+
+	info = fabdev->algo->find_node(fabdev, iid);
+	if (!info) {
+		MSM_BUS_ERR("Error: Info not found for id: %u", iid);
+		return -EINVAL;
+	}
+
+	haltid = fabric->pdata->haltid;
+	mport = info->node_info->masterp[0];
+
+	return fabdev->hw_algo.port_halt(haltid, mport);
+}
+
+/**
+ * msm_bus_fabric_port_unhalt() - Used to unhalt a master port
+ * @fabric: Fabric on which the current master node is present
+ * @portid: Port id of the master
+ */
+int msm_bus_fabric_port_unhalt(struct msm_bus_fabric_device *fabdev, int iid)
+{
+	struct msm_bus_inode_info *info = NULL;
+	uint8_t mport;
+	uint32_t haltid = 0;
+	struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
+
+	info = fabdev->algo->find_node(fabdev, iid);
+	if (!info) {
+		MSM_BUS_ERR("Error: Info not found for id: %u", iid);
+		return -EINVAL;
+	}
+
+	haltid = fabric->pdata->haltid;
+	mport = info->node_info->masterp[0];
+	return fabdev->hw_algo.port_unhalt(haltid, mport);
+}
+
+/**
+ * msm_bus_fabric_find_gw_node() - This function finds the gateway node
+ * attached on a given fabric
+ * @id:       ID of the gateway node
+ * @fabric:   Fabric to find the gateway node on
+ * Function returns: Pointer to the gateway node
+ */
+static struct msm_bus_inode_info *msm_bus_fabric_find_gw_node(struct
+	msm_bus_fabric_device * fabdev, int id)
+{
+	struct msm_bus_inode_info *info = NULL;
+	struct msm_bus_fabnodeinfo *fab;
+	struct msm_bus_fabric *fabric;
+	if (!fabdev) {
+		MSM_BUS_ERR("No fabric device found!\n");
+		return NULL;
+	}
+
+	fabric = to_msm_bus_fabric(fabdev);
+	if (!fabric || IS_ERR(fabric)) {
+		MSM_BUS_ERR("No fabric type found!\n");
+		return NULL;
+	}
+	list_for_each_entry(fab, &fabric->gateways, list) {
+		if (fab->info->node_info->priv_id == id) {
+			info = fab->info;
+			break;
+		}
+	}
+
+	return info;
+}
+
+static struct msm_bus_inode_info *msm_bus_fabric_find_node(struct
+	msm_bus_fabric_device * fabdev, int id)
+{
+	struct msm_bus_inode_info *info = NULL;
+	struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
+	info = radix_tree_lookup(&fabric->fab_tree, id);
+	if (!info)
+		MSM_BUS_ERR("Null info found for id %d\n", id);
+	return info;
+}
+
+static struct list_head *msm_bus_fabric_get_gw_list(struct msm_bus_fabric_device
+	*fabdev)
+{
+	struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
+	if (!fabric || IS_ERR(fabric)) {
+		MSM_BUS_ERR("No fabric found from fabdev\n");
+		return NULL;
+	}
+	return &fabric->gateways;
+
+}
+static struct msm_bus_fab_algorithm msm_bus_algo = {
+	.update_clks = msm_bus_fabric_update_clks,
+	.update_bw = msm_bus_fabric_update_bw,
+	.port_halt = msm_bus_fabric_port_halt,
+	.port_unhalt = msm_bus_fabric_port_unhalt,
+	.commit = msm_bus_fabric_hw_commit,
+	.find_node = msm_bus_fabric_find_node,
+	.find_gw_node = msm_bus_fabric_find_gw_node,
+	.get_gw_list = msm_bus_fabric_get_gw_list,
+};
+
+static int msm_bus_fabric_hw_init(struct msm_bus_fabric_registration *pdata,
+	struct msm_bus_hw_algorithm *hw_algo)
+{
+	int ret = 0;
+	ret = msm_bus_rpm_hw_init(pdata, hw_algo);
+	if (ret) {
+		MSM_BUS_ERR("RPM initialization failed\n");
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int msm_bus_fabric_probe(struct platform_device *pdev)
+{
+	int ctx, ret = 0;
+	struct msm_bus_fabric *fabric;
+	struct msm_bus_fabric_registration *pdata;
+
+	fabric = kzalloc(sizeof(struct msm_bus_fabric), GFP_KERNEL);
+	if (!fabric) {
+		MSM_BUS_ERR("Fabric alloc failed\n");
+		return -ENOMEM;
+	}
+
+	INIT_LIST_HEAD(&fabric->gateways);
+	INIT_RADIX_TREE(&fabric->fab_tree, GFP_ATOMIC);
+	fabric->num_nodes = 0;
+	fabric->fabdev.id = pdev->id;
+	fabric->fabdev.visited = false;
+
+	fabric->info.node_info = kzalloc(sizeof(struct msm_bus_node_info),
+				GFP_KERNEL);
+	if (ZERO_OR_NULL_PTR(fabric->info.node_info)) {
+		MSM_BUS_ERR("Fabric node info alloc failed\n");
+		kfree(fabric);
+		return -ENOMEM;
+	}
+	fabric->info.node_info->priv_id = fabric->fabdev.id;
+	fabric->info.node_info->id = fabric->fabdev.id;
+	fabric->info.num_pnodes = -1;
+	fabric->info.link_info.clk[DUAL_CTX] = 0;
+	fabric->info.link_info.bw[DUAL_CTX] = 0;
+	fabric->info.link_info.clk[ACTIVE_CTX] = 0;
+	fabric->info.link_info.bw[ACTIVE_CTX] = 0;
+
+	fabric->fabdev.id = pdev->id;
+	pdata = (struct msm_bus_fabric_registration *)pdev->dev.platform_data;
+	fabric->fabdev.name = pdata->name;
+	fabric->fabdev.algo = &msm_bus_algo;
+	ret = msm_bus_fabric_hw_init(pdata, &fabric->fabdev.hw_algo);
+	if (ret) {
+		MSM_BUS_ERR("Error initializing hardware for fabric: %d\n",
+			fabric->fabdev.id);
+		goto err;
+	}
+
+	fabric->ahb = pdata->ahb;
+	fabric->pdata = pdata;
+	fabric->pdata->board_algo->assign_iids(fabric->pdata,
+		fabric->fabdev.id);
+	fabric->fabdev.board_algo = fabric->pdata->board_algo;
+
+	/*
+	 * clk and bw for fabric->info will contain the max bw and clk
+	 * it will allow. This info will come from the boards file.
+	 */
+	ret = msm_bus_fabric_device_register(&fabric->fabdev);
+	if (ret) {
+		MSM_BUS_ERR("Error registering fabric %d ret %d\n",
+			fabric->fabdev.id, ret);
+		goto err;
+	}
+
+	for (ctx = 0; ctx < NUM_CTX; ctx++) {
+		if (pdata->fabclk[ctx]) {
+			fabric->info.nodeclk[ctx].clk = clk_get(
+				&fabric->fabdev.dev, pdata->fabclk[ctx]);
+			if (IS_ERR(fabric->info.nodeclk[ctx].clk)) {
+				MSM_BUS_ERR("Couldn't get clock %s\n",
+					pdata->fabclk[ctx]);
+				ret = -EINVAL;
+				goto err;
+			}
+			fabric->info.nodeclk[ctx].enable = false;
+			fabric->info.nodeclk[ctx].dirty = false;
+		}
+	}
+
+	/* Find num. of slaves, masters, populate gateways, radix tree */
+	ret = register_fabric_info(pdev, fabric);
+	if (ret) {
+		MSM_BUS_ERR("Could not register fabric %d info, ret: %d\n",
+			fabric->fabdev.id, ret);
+		goto err;
+	}
+	if (!fabric->ahb) {
+		/* Allocate memory for commit data */
+		for (ctx = 0; ctx < NUM_CTX; ctx++) {
+			ret = fabric->fabdev.hw_algo.allocate_commit_data(
+				fabric->pdata, &fabric->cdata[ctx], ctx);
+			if (ret) {
+				MSM_BUS_ERR("Failed to alloc commit data for "
+					"fab: %d, ret = %d\n",
+					fabric->fabdev.id, ret);
+				goto err;
+			}
+		}
+	}
+
+	return ret;
+err:
+	kfree(fabric->info.node_info);
+	kfree(fabric);
+	return ret;
+}
+
+static int msm_bus_fabric_remove(struct platform_device *pdev)
+{
+	struct msm_bus_fabric_device *fabdev = NULL;
+	struct msm_bus_fabric *fabric;
+	int i;
+	int ret = 0;
+
+	fabdev = platform_get_drvdata(pdev);
+	msm_bus_fabric_device_unregister(fabdev);
+	fabric = to_msm_bus_fabric(fabdev);
+	msm_bus_dbg_commit_data(fabric->fabdev.name, NULL, 0, 0, 0,
+		MSM_BUS_DBG_UNREGISTER);
+	for (i = 0; i < fabric->pdata->nmasters; i++)
+		radix_tree_delete(&fabric->fab_tree, fabric->fabdev.id + i);
+	for (i = (fabric->fabdev.id + SLAVE_ID_KEY); i <
+		fabric->pdata->nslaves; i++)
+		radix_tree_delete(&fabric->fab_tree, i);
+	if (!fabric->ahb) {
+		fabdev->hw_algo.free_commit_data(fabric->cdata[DUAL_CTX]);
+		fabdev->hw_algo.free_commit_data(fabric->cdata[ACTIVE_CTX]);
+	}
+
+	kfree(fabric->info.node_info);
+	kfree(fabric->hw_data);
+	kfree(fabric);
+	return ret;
+}
+
+static struct platform_driver msm_bus_fabric_driver = {
+	.probe = msm_bus_fabric_probe,
+	.remove = msm_bus_fabric_remove,
+	.driver = {
+		.name = "msm_bus_fabric",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_bus_fabric_init_driver(void)
+{
+	MSM_BUS_ERR("msm_bus_fabric_init_driver\n");
+	return platform_driver_register(&msm_bus_fabric_driver);
+}
+postcore_initcall(msm_bus_fabric_init_driver);
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_rpm.c b/arch/arm/mach-msm/msm_bus/msm_bus_rpm.c
new file mode 100644
index 0000000..4653431
--- /dev/null
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_rpm.c
@@ -0,0 +1,964 @@
+/* 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
+ * 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.
+ *
+ */
+
+#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#include <mach/board.h>
+#include <mach/rpm.h>
+#include "msm_bus_core.h"
+#include "../rpm_resources.h"
+
+void msm_bus_rpm_set_mt_mask()
+{
+#ifdef CONFIG_MSM_BUS_RPM_MULTI_TIER_ENABLED
+	struct msm_rpm_iv_pair mt[1];
+	int mask = MSM_RPMRS_MASK_RPM_CTL_MULTI_TIER;
+	mt[0].id = MSM_RPM_ID_RPM_CTL;
+	mt[0].value = 2;
+	msm_rpmrs_set_bits_noirq(MSM_RPM_CTX_SET_0, mt, 1,
+		&mask);
+#endif
+}
+
+bool msm_bus_rpm_is_mem_interleaved(void)
+{
+	int status = 0;
+	struct msm_rpm_iv_pair il[2];
+	uint16_t id[2];
+
+	il[0].value = 0;
+	il[1].value = 0;
+	status = msm_bus_board_rpm_get_il_ids(id);
+	if (status) {
+		MSM_BUS_DBG("Dynamic check not supported, "
+			"default: Interleaved memory\n");
+		goto inter;
+	}
+
+	il[0].id = id[0];
+	il[1].id = id[1];
+	status = msm_rpm_get_status(il, ARRAY_SIZE(il));
+	if (status) {
+		MSM_BUS_ERR("Status read for interleaving returned: %d\n"
+			"Using interleaved memory by default\n",
+			status);
+		goto inter;
+	}
+
+	/*
+	 * If the start address of EBI1-CH0 is the same as
+	 * the start address of EBI1-CH1, the memory is interleaved.
+	 * The start addresses are stored in the 16 MSBs of the status
+	 * register
+	 */
+	if ((il[0].value & 0xFFFF0000) != (il[1].value & 0xFFFF0000)) {
+		MSM_BUS_DBG("Non-interleaved memory\n");
+		return false;
+	}
+
+inter:
+	MSM_BUS_DBG("Interleaved memory\n");
+	return true;
+}
+
+#ifndef CONFIG_MSM_BUS_RPM_MULTI_TIER_ENABLED
+struct commit_data {
+	uint16_t *bwsum;
+	uint16_t *arb;
+	unsigned long *actarb;
+};
+
+/*
+ * The following macros are used for various operations on commit data.
+ * Commit data is an array of 32 bit integers. The size of arrays is unique
+ * to the fabric. Commit arrays are allocated at run-time based on the number
+ * of masters, slaves and tiered-slaves registered.
+ */
+
+#define MSM_BUS_GET_BW_INFO(val, type, bw) \
+	do { \
+		(type) = MSM_BUS_GET_BW_TYPE(val); \
+		(bw) = MSM_BUS_GET_BW(val);	\
+	} while (0)
+
+
+#define MSM_BUS_GET_BW_INFO_BYTES (val, type, bw) \
+	do { \
+		(type) = MSM_BUS_GET_BW_TYPE(val); \
+		(bw) = msm_bus_get_bw_bytes(val); \
+	} while (0)
+
+#define ROUNDED_BW_VAL_FROM_BYTES(bw) \
+	((((bw) >> 17) + 1) & 0x8000 ? 0x7FFF : (((bw) >> 17) + 1))
+
+#define BW_VAL_FROM_BYTES(bw) \
+	((((bw) >> 17) & 0x8000) ? 0x7FFF : ((bw) >> 17))
+
+static uint32_t msm_bus_set_bw_bytes(unsigned long bw)
+{
+	return ((((bw) & 0x1FFFF) && (((bw) >> 17) == 0)) ?
+		ROUNDED_BW_VAL_FROM_BYTES(bw) : BW_VAL_FROM_BYTES(bw));
+
+}
+
+uint64_t msm_bus_get_bw_bytes(unsigned long val)
+{
+	return ((val) & 0x7FFF) << 17;
+}
+
+uint16_t msm_bus_get_bw(unsigned long val)
+{
+	return (val)&0x7FFF;
+}
+
+static uint16_t msm_bus_create_bw_tier_pair_bytes(uint8_t type,
+	unsigned long bw)
+{
+	return ((((type) == MSM_BUS_BW_TIER1 ? 1 : 0) << 15) |
+	 (msm_bus_set_bw_bytes(bw)));
+};
+
+uint16_t msm_bus_create_bw_tier_pair(uint8_t type, unsigned long bw)
+{
+	return (((type) == MSM_BUS_BW_TIER1 ? 1 : 0) << 15) | ((bw) & 0x7FFF);
+}
+
+void msm_bus_rpm_fill_cdata_buffer(int *curr, char *buf, const int max_size,
+	void *cdata, int nmasters, int nslaves, int ntslaves)
+{
+	int j, c;
+	struct commit_data *cd = (struct commit_data *)cdata;
+
+	*curr += scnprintf(buf + *curr, max_size - *curr, "BWSum:\n");
+	for (c = 0; c < nslaves; c++)
+		*curr += scnprintf(buf + *curr, max_size - *curr,
+			"0x%x\t", cd->bwsum[c]);
+	*curr += scnprintf(buf + *curr, max_size - *curr, "\nArb:");
+	for (c = 0; c < ntslaves; c++) {
+		*curr += scnprintf(buf + *curr, max_size - *curr,
+		"\nTSlave %d:\n", c);
+		for (j = 0; j < nmasters; j++)
+			*curr += scnprintf(buf + *curr, max_size - *curr,
+				" 0x%x\t", cd->arb[(c * nmasters) + j]);
+	}
+}
+
+/**
+ * allocate_commit_data() - Allocate the data for commit array in the
+ * format specified by RPM
+ * @fabric: Fabric device for which commit data is allocated
+ */
+static int msm_bus_rpm_allocate_commit_data(struct msm_bus_fabric_registration
+	*fab_pdata, void **cdata, int ctx)
+{
+	struct commit_data **cd = (struct commit_data **)cdata;
+	*cd = kzalloc(sizeof(struct commit_data), GFP_KERNEL);
+	if (!*cd) {
+		MSM_BUS_DBG("Couldn't alloc mem for cdata\n");
+		return -ENOMEM;
+	}
+	(*cd)->bwsum = kzalloc((sizeof(uint16_t) * fab_pdata->nslaves),
+			GFP_KERNEL);
+	if (!(*cd)->bwsum) {
+		MSM_BUS_DBG("Couldn't alloc mem for slaves\n");
+		kfree(*cd);
+		return -ENOMEM;
+	}
+	(*cd)->arb = kzalloc(((sizeof(uint16_t *)) *
+		(fab_pdata->ntieredslaves * fab_pdata->nmasters) + 1),
+		GFP_KERNEL);
+	if (!(*cd)->arb) {
+		MSM_BUS_DBG("Couldn't alloc memory for"
+				" slaves\n");
+		kfree((*cd)->bwsum);
+		kfree(*cd);
+		return -ENOMEM;
+	}
+	(*cd)->actarb = kzalloc(((sizeof(unsigned long *)) *
+		(fab_pdata->ntieredslaves * fab_pdata->nmasters) + 1),
+		GFP_KERNEL);
+	if (!(*cd)->actarb) {
+		MSM_BUS_DBG("Couldn't alloc memory for"
+				" slaves\n");
+		kfree((*cd)->bwsum);
+		kfree((*cd)->arb);
+		kfree(*cd);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void free_commit_data(void *cdata)
+{
+	struct commit_data *cd = (struct commit_data *)cdata;
+
+	kfree(cd->bwsum);
+	kfree(cd->arb);
+	kfree(cd->actarb);
+	kfree(cd);
+}
+
+/**
+ * allocate_rpm_data() - Allocate the id-value pairs to be
+ * sent to RPM
+ */
+static void *msm_bus_rpm_allocate_rpm_data(struct platform_device *pdev,
+	struct msm_bus_fabric_registration *fab_pdata)
+{
+	struct msm_rpm_iv_pair *rpm_data;
+	uint16_t count = ((fab_pdata->nmasters * fab_pdata->ntieredslaves) +
+		fab_pdata->nslaves + 1)/2;
+
+	rpm_data = kmalloc((sizeof(struct msm_rpm_iv_pair) * count),
+		GFP_KERNEL);
+	return (void *)rpm_data;
+}
+
+#define BWMASK 0x7FFF
+#define TIERMASK 0x8000
+#define GET_TIER(n) (((n) & TIERMASK) >> 15)
+
+static void msm_bus_rpm_update_bw(struct msm_bus_inode_info *hop,
+	struct msm_bus_inode_info *info,
+	struct msm_bus_fabric_registration *fab_pdata,
+	void *sel_cdata, int *master_tiers,
+	long int add_bw)
+{
+	int index, i, j, tiers, ports;
+	struct commit_data *sel_cd = (struct commit_data *)sel_cdata;
+
+	add_bw = INTERLEAVED_BW(fab_pdata, add_bw, info->node_info->num_mports);
+	ports = INTERLEAVED_VAL(fab_pdata, info->node_info->num_mports);
+	tiers = INTERLEAVED_VAL(fab_pdata, hop->node_info->num_tiers);
+	for (i = 0; i < tiers; i++) {
+		for (j = 0; j < ports; j++) {
+			uint16_t hop_tier;
+			/*
+			 * For interleaved gateway ports and slave ports,
+			 * there is one-one mapping between gateway port and
+			 * the slave port
+			 */
+			if (info->node_info->gateway && i != j &&
+				(hop->node_info->num_sports > 1))
+				continue;
+
+			if (!hop->node_info->tier)
+				hop_tier = MSM_BUS_BW_TIER2 - 1;
+			else
+				hop_tier = hop->node_info->tier[i] - 1;
+			index = ((hop_tier * fab_pdata->nmasters) +
+				(info->node_info->masterp[j]));
+			/* If there is tier, calculate arb for commit */
+			if (hop->node_info->tier) {
+				uint16_t tier;
+				unsigned long tieredbw = sel_cd->actarb[index];
+				if (GET_TIER(sel_cd->arb[index]))
+					tier = MSM_BUS_BW_TIER1;
+				else if (master_tiers)
+					/*
+					 * By default master is only in the
+					 * tier specified by default.
+					 * To change the default tier, client
+					 * needs to explicitly request for a
+					 * different supported tier */
+					tier = master_tiers[0];
+				else
+					tier = MSM_BUS_BW_TIER2;
+
+				/*
+				 * Make sure gateway to slave port bandwidth
+				 * is not divided when slave is interleaved
+				 */
+				if (info->node_info->gateway
+					&& hop->node_info->num_sports > 1)
+					tieredbw += add_bw;
+				else
+					tieredbw += INTERLEAVED_BW(fab_pdata,
+						add_bw, hop->node_info->
+						num_sports);
+
+				/* If bw is 0, update tier to default */
+				if (!tieredbw)
+					tier = MSM_BUS_BW_TIER2;
+				/* Update Arb for fab,get HW Mport from enum */
+				sel_cd->arb[index] =
+					msm_bus_create_bw_tier_pair_bytes(tier,
+					tieredbw);
+				sel_cd->actarb[index] = tieredbw;
+				MSM_BUS_DBG("tier:%d mport: %d tiered_bw:%ld "
+				"bwsum: %ld\n", hop_tier, info->node_info->
+				masterp[i], tieredbw, *hop->link_info.sel_bw);
+			}
+		}
+	}
+
+	/* Update bwsum for slaves on fabric */
+	ports = INTERLEAVED_VAL(fab_pdata, hop->node_info->num_sports);
+	for (i = 0; i < ports; i++) {
+		sel_cd->bwsum[hop->node_info->slavep[i]]
+			= (uint16_t)msm_bus_create_bw_tier_pair_bytes(0,
+			(*hop->link_info.sel_bw/hop->node_info->num_sports));
+		MSM_BUS_DBG("slavep:%d, link_bw: %ld\n",
+			hop->node_info->slavep[i], (*hop->link_info.sel_bw/
+			hop->node_info->num_sports));
+	}
+}
+
+#define RPM_SHIFT_VAL 16
+#define RPM_SHIFT(n) ((n) << RPM_SHIFT_VAL)
+static int msm_bus_rpm_compare_cdata(
+	struct msm_bus_fabric_registration *fab_pdata,
+	struct commit_data *cd1, struct commit_data *cd2)
+{
+	size_t n;
+	int ret;
+	n = sizeof(uint16_t) * fab_pdata->nslaves;
+	ret = memcmp(cd1->bwsum, cd2->bwsum, n);
+	if (ret) {
+		MSM_BUS_DBG("Commit Data bwsum not equal\n");
+		return ret;
+	}
+
+	n = sizeof(uint16_t *) * ((fab_pdata->ntieredslaves *
+		fab_pdata->nmasters) + 1);
+	ret = memcmp(cd1->arb, cd2->arb, n);
+	if (ret) {
+		MSM_BUS_DBG("Commit Data arb[%d] not equal\n", n);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int msm_bus_rpm_commit_arb(struct msm_bus_fabric_registration
+	*fab_pdata, int ctx, struct msm_rpm_iv_pair *rpm_data,
+	struct commit_data *cd, bool valid)
+{
+	int i, j, offset = 0, status = 0, count, index = 0;
+	/*
+	 * count is the number of 2-byte words required to commit the
+	 * data to rpm. This is calculated by the following formula.
+	 * Commit data is split into two arrays:
+	 * 1. arb[nmasters * ntieredslaves]
+	 * 2. bwsum[nslaves]
+	 */
+	count = ((fab_pdata->nmasters * fab_pdata->ntieredslaves)
+		+ (fab_pdata->nslaves) + 1)/2;
+
+	offset = fab_pdata->offset;
+
+	/*
+	 * Copy bwsum to rpm data
+	 * Since bwsum is uint16, the values need to be adjusted to
+	 * be copied to value field of rpm-data, which is 32 bits.
+	 */
+	for (i = 0; i < (fab_pdata->nslaves - 1); i += 2) {
+		rpm_data[index].id = offset + index;
+		rpm_data[index].value = RPM_SHIFT(*(cd->bwsum + i + 1)) |
+			*(cd->bwsum + i);
+		index++;
+	}
+	/* Account for odd number of slaves */
+	if (fab_pdata->nslaves & 1) {
+		rpm_data[index].id = offset + index;
+		rpm_data[index].value = *(cd->arb);
+		rpm_data[index].value = RPM_SHIFT(rpm_data[index].value) |
+			*(cd->bwsum + i);
+		index++;
+		i = 1;
+	} else
+		i = 0;
+
+	/* Copy arb values to rpm data */
+	for (; i < (fab_pdata->ntieredslaves * fab_pdata->nmasters);
+		i += 2) {
+		rpm_data[index].id = offset + index;
+		rpm_data[index].value = RPM_SHIFT(*(cd->arb + i + 1)) |
+			*(cd->arb + i);
+		index++;
+	}
+
+	MSM_BUS_DBG("rpm data for fab: %d\n", fab_pdata->id);
+	for (i = 0; i < count; i++)
+		MSM_BUS_DBG("%d %x\n", rpm_data[i].id, rpm_data[i].value);
+
+	MSM_BUS_DBG("Commit Data: Fab: %d BWSum:\n", fab_pdata->id);
+	for (i = 0; i < fab_pdata->nslaves; i++)
+		MSM_BUS_DBG("fab_slaves:0x%x\n", cd->bwsum[i]);
+	MSM_BUS_DBG("Commit Data: Fab: %d Arb:\n", fab_pdata->id);
+	for (i = 0; i < fab_pdata->ntieredslaves; i++) {
+		MSM_BUS_DBG("tiered-slave: %d\n", i);
+		for (j = 0; j < fab_pdata->nmasters; j++)
+			MSM_BUS_DBG(" 0x%x\n",
+			cd->arb[(i * fab_pdata->nmasters) + j]);
+	}
+
+	MSM_BUS_DBG("calling msm_rpm_set:  %d\n", status);
+	msm_bus_dbg_commit_data(fab_pdata->name, cd, fab_pdata->
+		nmasters, fab_pdata->nslaves, fab_pdata->ntieredslaves,
+		MSM_BUS_DBG_OP);
+	if (fab_pdata->rpm_enabled) {
+		if (valid) {
+			if (ctx == ACTIVE_CTX) {
+				status = msm_rpm_set(MSM_RPM_CTX_SET_0,
+					rpm_data, count);
+				MSM_BUS_DBG("msm_rpm_set returned: %d\n",
+					status);
+			} else if (ctx == DUAL_CTX) {
+				status = msm_rpm_set(MSM_RPM_CTX_SET_SLEEP,
+					rpm_data, count);
+				MSM_BUS_DBG("msm_rpm_set returned: %d\n",
+					status);
+			}
+		} else {
+			if (ctx == ACTIVE_CTX) {
+				status = msm_rpm_clear(MSM_RPM_CTX_SET_0,
+					rpm_data, count);
+				MSM_BUS_DBG("msm_rpm_clear returned: %d\n",
+					status);
+			} else if (ctx == DUAL_CTX) {
+				status = msm_rpm_clear(MSM_RPM_CTX_SET_SLEEP,
+					rpm_data, count);
+				MSM_BUS_DBG("msm_rpm_clear returned: %d\n",
+					status);
+			}
+		}
+	}
+
+	return status;
+}
+
+#else
+
+#define NUM_TIERS 2
+#define RPM_SHIFT24(n) ((n) << 24)
+#define RPM_SHIFT16(n) ((n) << 16)
+#define RPM_SHIFT8(n) ((n) << 8)
+struct commit_data {
+	uint16_t *bwsum;
+	uint8_t *arb[NUM_TIERS];
+	unsigned long *actarb[NUM_TIERS];
+};
+
+#define MODE_BIT(val) ((val) & 0x80)
+#define MODE0_IMM(val) ((val) & 0xF)
+#define MODE0_SHIFT(val) (((val) & 0x70) >> 4)
+#define MODE1_STEP	48 /* 48 MB */
+#define MODE1_OFFSET	512 /* 512 MB */
+#define MODE1_IMM(val)	((val) & 0x7F)
+#define __CLZ(x) ((8 * sizeof(uint32_t)) - 1 - __fls(x))
+
+static uint8_t msm_bus_set_bw_bytes(unsigned long val)
+{
+	unsigned int shift;
+	unsigned int intVal;
+	unsigned char result;
+
+	/* Convert to MB */
+	intVal = (unsigned int)((val + ((1 << 20) - 1)) >> 20);
+	/**
+	 * Divide by 2^20 and round up
+	 * A value graeter than 0x1E0 will round up to 512 and overflow
+	 * Mode 0 so it should be made Mode 1
+	 */
+	if (0x1E0 > intVal) {
+		/**
+		 * MODE 0
+		 * Compute the shift value
+		 * Shift value is 32 - the number of leading zeroes -
+		 * 4 to save the most significant 4 bits of the value
+		 */
+		shift = 32 - 4 - min((uint8_t)28, (uint8_t)__CLZ(intVal));
+
+		/* Add min value - 1 to force a round up when shifting right */
+		intVal += (1 << shift) - 1;
+
+		/* Recompute the shift value in case there was an overflow */
+		shift = 32 - 4 - min((uint8_t)28, (uint8_t)__CLZ(intVal));
+
+		/* Clear the mode bit (msb) and fill in the fields */
+		result = ((0x70 & (shift << 4)) |
+			(0x0F & (intVal >> shift)));
+	} else {
+		/* MODE 1 */
+		result = (unsigned char)(0x80 |
+			((intVal - MODE1_OFFSET + MODE1_STEP - 1) /
+			MODE1_STEP));
+	}
+
+	return result;
+}
+
+uint64_t msm_bus_get_bw(unsigned long val)
+{
+	return MODE_BIT(val) ?
+	 /* Mode 1 */
+	 (MODE1_IMM(val) * MODE1_STEP + MODE1_OFFSET) :
+	 /* Mode 0 */
+	 (MODE0_IMM(val) << MODE0_SHIFT(val));
+}
+
+uint64_t msm_bus_get_bw_bytes(unsigned long val)
+{
+	return msm_bus_get_bw(val) << 20;
+}
+
+static uint8_t msm_bus_create_bw_tier_pair_bytes(uint8_t type,
+	unsigned long bw)
+{
+	return msm_bus_set_bw_bytes(bw);
+};
+
+uint8_t msm_bus_create_bw_tier_pair(uint8_t type, unsigned long bw)
+{
+	return msm_bus_create_bw_tier_pair_bytes(type, bw);
+};
+
+static int msm_bus_rpm_allocate_commit_data(struct msm_bus_fabric_registration
+	*fab_pdata, void **cdata, int ctx)
+{
+	struct commit_data **cd = (struct commit_data **)cdata;
+	int i;
+
+	*cd = kzalloc(sizeof(struct commit_data), GFP_KERNEL);
+	if (!*cd) {
+		MSM_BUS_DBG("Couldn't alloc mem for cdata\n");
+		goto cdata_err;
+	}
+
+	(*cd)->bwsum = kzalloc((sizeof(uint16_t) * fab_pdata->nslaves),
+			GFP_KERNEL);
+	if (!(*cd)->bwsum) {
+		MSM_BUS_DBG("Couldn't alloc mem for slaves\n");
+		goto bwsum_err;
+	}
+
+	for (i = 0; i < NUM_TIERS; i++) {
+		(*cd)->arb[i] = kzalloc(((sizeof(uint8_t *)) *
+			(fab_pdata->ntieredslaves * fab_pdata->nmasters) + 1),
+			GFP_KERNEL);
+		if (!(*cd)->arb[i]) {
+			MSM_BUS_DBG("Couldn't alloc memory for"
+				" slaves\n");
+			goto arb_err;
+		}
+
+		(*cd)->actarb[i] = kzalloc(((sizeof(unsigned long *)) *
+			(fab_pdata->ntieredslaves * fab_pdata->nmasters) + 1),
+			GFP_KERNEL);
+		if (!(*cd)->actarb[i]) {
+			MSM_BUS_DBG("Couldn't alloc memory for"
+					" slaves\n");
+			kfree((*cd)->arb[i]);
+			goto arb_err;
+		}
+	}
+
+
+	return 0;
+
+arb_err:
+	for (i = i - 1; i >= 0; i--) {
+		kfree((*cd)->arb[i]);
+		kfree((*cd)->actarb[i]);
+	}
+bwsum_err:
+	kfree((*cd)->bwsum);
+cdata_err:
+	kfree(*cd);
+	return -ENOMEM;
+}
+
+static void free_commit_data(void *cdata)
+{
+	int i;
+	struct commit_data *cd = (struct commit_data *)cdata;
+	kfree(cd->bwsum);
+	for (i = 0; i < NUM_TIERS; i++) {
+		kfree(cd->arb[i]);
+		kfree(cd->actarb[i]);
+	}
+	kfree(cd);
+}
+
+static void *msm_bus_rpm_allocate_rpm_data(struct platform_device *pdev,
+	struct msm_bus_fabric_registration *fab_pdata)
+{
+	struct msm_rpm_iv_pair *rpm_data;
+	uint16_t count = (((fab_pdata->nmasters * fab_pdata->ntieredslaves *
+		NUM_TIERS)/2) + fab_pdata->nslaves + 1)/2;
+
+	rpm_data = kmalloc((sizeof(struct msm_rpm_iv_pair) * count),
+		GFP_KERNEL);
+	return (void *)rpm_data;
+}
+
+static int msm_bus_rpm_compare_cdata(
+	struct msm_bus_fabric_registration *fab_pdata,
+	struct commit_data *cd1, struct commit_data *cd2)
+{
+	size_t n;
+	int i, ret;
+	n = sizeof(uint16_t) * fab_pdata->nslaves;
+	ret = memcmp(cd1->bwsum, cd2->bwsum, n);
+	if (ret) {
+		MSM_BUS_DBG("Commit Data bwsum not equal\n");
+		return ret;
+	}
+
+	n = sizeof(uint8_t *) * ((fab_pdata->ntieredslaves *
+		fab_pdata->nmasters) + 1);
+	for (i = 0; i < NUM_TIERS; i++) {
+		ret = memcmp(cd1->arb[i], cd2->arb[i], n);
+		if (ret) {
+			MSM_BUS_DBG("Commit Data arb[%d] not equal\n", i);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int msm_bus_rpm_commit_arb(struct msm_bus_fabric_registration
+	*fab_pdata, int ctx, struct msm_rpm_iv_pair *rpm_data,
+	struct commit_data *cd, bool valid)
+{
+	int i, j, k, offset = 0, status = 0, count, index = 0;
+	/*
+	 * count is the number of 2-byte words required to commit the
+	 * data to rpm. This is calculated by the following formula.
+	 * Commit data is split into two arrays:
+	 * 1. arb[nmasters * ntieredslaves][num_tiers]
+	 * 2. bwsum[nslaves]
+	 */
+	count = (((fab_pdata->nmasters * fab_pdata->ntieredslaves * NUM_TIERS)
+		/2) + fab_pdata->nslaves + 1)/2;
+
+	offset = fab_pdata->offset;
+
+	/*
+	 * Copy bwsum to rpm data
+	 * Since bwsum is uint16, the values need to be adjusted to
+	 * be copied to value field of rpm-data, which is 32 bits.
+	 */
+	for (i = 0; i < (fab_pdata->nslaves - 1); i += 2) {
+		rpm_data[index].id = offset + index;
+		rpm_data[index].value = RPM_SHIFT16(*(cd->bwsum + i + 1)) |
+			*(cd->bwsum + i);
+		index++;
+	}
+	/* Account for odd number of slaves */
+	if (fab_pdata->nslaves & 1) {
+		rpm_data[index].id = offset + index;
+		rpm_data[index].value = RPM_SHIFT8(*cd->arb[1]) |
+			*(cd->arb[0]);
+		rpm_data[index].value = RPM_SHIFT16(rpm_data[index].value) |
+			*(cd->bwsum + i);
+		index++;
+		i = 1;
+	} else
+		i = 0;
+
+	/* Copy arb values to rpm data */
+	for (; i < (fab_pdata->ntieredslaves * fab_pdata->nmasters);
+		i += 2) {
+		uint16_t tv1, tv0;
+		rpm_data[index].id = offset + index;
+		tv0 = RPM_SHIFT8(*(cd->arb[1] + i)) | (*(cd->arb[0] + i));
+		tv1 = RPM_SHIFT8(*(cd->arb[1] + i + 1)) | (*(cd->arb[0] + i
+			+ 1));
+		rpm_data[index].value = RPM_SHIFT16(tv1) | tv0;
+			index++;
+	}
+
+	MSM_BUS_DBG("rpm data for fab: %d\n", fab_pdata->id);
+	for (i = 0; i < count; i++)
+		MSM_BUS_DBG("%d %x\n", rpm_data[i].id, rpm_data[i].value);
+
+	MSM_BUS_DBG("Commit Data: Fab: %d BWSum:\n", fab_pdata->id);
+	for (i = 0; i < fab_pdata->nslaves; i++)
+		MSM_BUS_DBG("fab_slaves:0x%x\n", cd->bwsum[i]);
+	MSM_BUS_DBG("Commit Data: Fab: %d Arb:\n", fab_pdata->id);
+	for (k = 0; k < NUM_TIERS; k++) {
+		MSM_BUS_DBG("Tier: %d\n", k);
+		for (i = 0; i < fab_pdata->ntieredslaves; i++) {
+			MSM_BUS_DBG("tiered-slave: %d\n", i);
+			for (j = 0; j < fab_pdata->nmasters; j++)
+				MSM_BUS_DBG(" 0x%x\n",
+				cd->arb[k][(i * fab_pdata->nmasters)
+				+ j]);
+		}
+	}
+
+	MSM_BUS_DBG("calling msm_rpm_set:  %d\n", status);
+	msm_bus_dbg_commit_data(fab_pdata->name, (void *)cd, fab_pdata->
+		nmasters, fab_pdata->nslaves, fab_pdata->ntieredslaves,
+		MSM_BUS_DBG_OP);
+	if (fab_pdata->rpm_enabled) {
+		if (valid) {
+			if (ctx == ACTIVE_CTX) {
+				status = msm_rpm_set(MSM_RPM_CTX_SET_0,
+					rpm_data, count);
+				MSM_BUS_DBG("msm_rpm_set returned: %d\n",
+					status);
+			} else if (ctx == DUAL_CTX) {
+				status = msm_rpm_set(MSM_RPM_CTX_SET_SLEEP,
+					rpm_data, count);
+				MSM_BUS_DBG("msm_rpm_set returned: %d\n",
+					status);
+			}
+		} else {
+			if (ctx == ACTIVE_CTX) {
+				status = msm_rpm_clear(MSM_RPM_CTX_SET_0,
+					rpm_data, count);
+				MSM_BUS_DBG("msm_rpm_clear returned: %d\n",
+					status);
+			} else if (ctx == DUAL_CTX) {
+				status = msm_rpm_clear(MSM_RPM_CTX_SET_SLEEP,
+					rpm_data, count);
+				MSM_BUS_DBG("msm_rpm_clear returned: %d\n",
+					status);
+			}
+		}
+	}
+
+	return status;
+}
+
+#define FORMAT_BW(x) \
+	((x < 0) ? \
+	-(msm_bus_get_bw_bytes(msm_bus_create_bw_tier_pair_bytes(0, -(x)))) : \
+	(msm_bus_get_bw_bytes(msm_bus_create_bw_tier_pair_bytes(0, x))))
+
+static uint16_t msm_bus_pack_bwsum_bytes(unsigned long bw)
+{
+	return (bw + ((1 << 20) - 1)) >> 20;
+};
+
+static void msm_bus_rpm_update_bw(struct msm_bus_inode_info *hop,
+	struct msm_bus_inode_info *info,
+	struct msm_bus_fabric_registration *fab_pdata,
+	void *sel_cdata, int *master_tiers,
+	long int add_bw)
+{
+	int index, i, j, tiers, ports;
+	struct commit_data *sel_cd = (struct commit_data *)sel_cdata;
+
+	add_bw = INTERLEAVED_BW(fab_pdata, add_bw, info->node_info->num_mports);
+	ports = INTERLEAVED_VAL(fab_pdata, info->node_info->num_mports);
+	tiers = INTERLEAVED_VAL(fab_pdata, hop->node_info->num_tiers);
+	for (i = 0; i < tiers; i++) {
+		for (j = 0; j < ports; j++) {
+			uint16_t hop_tier;
+			/*
+			 * For interleaved gateway ports and slave ports,
+			 * there is one-one mapping between gateway port and
+			 * the slave port
+			 */
+			if (info->node_info->gateway && i != j
+				&& hop->node_info->num_sports > 1)
+				continue;
+
+			if (!hop->node_info->tier)
+				hop_tier = MSM_BUS_BW_TIER2 - 1;
+			else
+				hop_tier = hop->node_info->tier[i] - 1;
+			index = ((hop_tier * fab_pdata->nmasters) +
+				(info->node_info->masterp[j]));
+			/* If there is tier, calculate arb for commit */
+			if (hop->node_info->tier) {
+				uint16_t tier;
+				unsigned long tieredbw;
+				if (master_tiers)
+					tier = master_tiers[0] - 1;
+				else
+					tier = MSM_BUS_BW_TIER2 - 1;
+
+				tieredbw = sel_cd->actarb[tier][index];
+				/*
+				 * Make sure gateway to slave port bandwidth
+				 * is not divided when slave is interleaved
+				 */
+				if (info->node_info->gateway
+					&& hop->node_info->num_sports > 1)
+					tieredbw += add_bw;
+				else
+					tieredbw += INTERLEAVED_BW(fab_pdata,
+						add_bw, hop->node_info->
+						num_sports);
+
+				/* Update Arb for fab,get HW Mport from enum */
+				sel_cd->arb[tier][index] =
+				msm_bus_create_bw_tier_pair_bytes(0, tieredbw);
+				sel_cd->actarb[tier][index] = tieredbw;
+				MSM_BUS_DBG("tier:%d mport: %d tiered_bw:%lu "
+				"bwsum: %ld\n", hop_tier, info->node_info->
+				masterp[i], tieredbw, *hop->link_info.sel_bw);
+			}
+		}
+	}
+
+	/* Update bwsum for slaves on fabric */
+
+	ports = INTERLEAVED_VAL(fab_pdata, hop->node_info->num_sports);
+	for (i = 0; i < ports; i++) {
+		sel_cd->bwsum[hop->node_info->slavep[i]]
+			= msm_bus_pack_bwsum_bytes((*hop->link_info.
+			sel_bw/hop->node_info->num_sports));
+		MSM_BUS_DBG("slavep:%d, link_bw: %ld\n",
+			hop->node_info->slavep[i], (*hop->link_info.sel_bw/
+			hop->node_info->num_sports));
+	}
+}
+
+
+void msm_bus_rpm_fill_cdata_buffer(int *curr, char *buf, const int max_size,
+	void *cdata, int nmasters, int nslaves, int ntslaves)
+{
+	int j, k, c;
+	struct commit_data *cd = (struct commit_data *)cdata;
+
+	*curr += scnprintf(buf + *curr, max_size - *curr, "BWSum:\n");
+	for (c = 0; c < nslaves; c++)
+		*curr += scnprintf(buf + *curr, max_size - *curr,
+			"0x%x\t", cd->bwsum[c]);
+	*curr += scnprintf(buf + *curr, max_size - *curr, "\nArb:");
+	for (k = 0; k < NUM_TIERS; k++) {
+		*curr += scnprintf(buf + *curr, max_size - *curr,
+			"\nTier %d:\n", k);
+		for (c = 0; c < ntslaves; c++) {
+			*curr += scnprintf(buf + *curr, max_size - *curr,
+			"TSlave %d:\n", c);
+			for (j = 0; j < nmasters; j++)
+				*curr += scnprintf(buf + *curr, max_size -
+				*curr, " 0x%x\t",
+				cd->arb[k][(c * nmasters) + j]);
+		}
+	}
+}
+#endif
+
+/**
+* msm_bus_rpm_commit() - Commit the arbitration data to RPM
+* @fabric: Fabric for which the data should be committed
+**/
+static int msm_bus_rpm_commit(struct msm_bus_fabric_registration
+	*fab_pdata, void *hw_data, void **cdata)
+{
+
+	int ret;
+	bool valid;
+	struct commit_data *dual_cd, *act_cd;
+	struct msm_rpm_iv_pair *rpm_data = (struct msm_rpm_iv_pair *)hw_data;
+	dual_cd = (struct commit_data *)cdata[DUAL_CTX];
+	act_cd = (struct commit_data *)cdata[ACTIVE_CTX];
+
+	/*
+	 * If the arb data for active set and sleep set is
+	 * different, commit both sets.
+	 * If the arb data for active set and sleep set is
+	 * the same, invalidate the sleep set.
+	 */
+	ret = msm_bus_rpm_compare_cdata(fab_pdata, act_cd, dual_cd);
+	if (!ret)
+		/* Invalidate sleep set.*/
+		valid = false;
+	else
+		valid = true;
+
+	ret = msm_bus_rpm_commit_arb(fab_pdata, DUAL_CTX, rpm_data,
+		dual_cd, valid);
+	if (ret)
+		MSM_BUS_ERR("Error comiting fabric:%d in %d ctx\n",
+			fab_pdata->id, DUAL_CTX);
+
+	valid = true;
+	ret = msm_bus_rpm_commit_arb(fab_pdata, ACTIVE_CTX, rpm_data, act_cd,
+		valid);
+	if (ret)
+		MSM_BUS_ERR("Error comiting fabric:%d in %d ctx\n",
+			fab_pdata->id, ACTIVE_CTX);
+
+	return ret;
+}
+
+static int msm_bus_rpm_port_halt(uint32_t haltid, uint8_t mport)
+{
+	int status = 0;
+	struct msm_bus_halt_vector hvector = {0, 0};
+	struct msm_rpm_iv_pair rpm_data[2];
+
+	MSM_BUS_MASTER_HALT(hvector.haltmask, hvector.haltval, mport);
+	rpm_data[0].id = haltid;
+	rpm_data[0].value = hvector.haltval;
+	rpm_data[1].id = haltid + 1;
+	rpm_data[1].value = hvector.haltmask;
+
+	MSM_BUS_DBG("ctx: %d, id: %d, value: %d\n",
+		MSM_RPM_CTX_SET_0, rpm_data[0].id, rpm_data[0].value);
+	MSM_BUS_DBG("ctx: %d, id: %d, value: %d\n",
+		MSM_RPM_CTX_SET_0, rpm_data[1].id, rpm_data[1].value);
+
+	status = msm_rpm_set(MSM_RPM_CTX_SET_0, rpm_data, 2);
+	if (status)
+		MSM_BUS_DBG("msm_rpm_set returned: %d\n", status);
+	return status;
+}
+
+static int msm_bus_rpm_port_unhalt(uint32_t haltid, uint8_t mport)
+{
+	int status = 0;
+	struct msm_bus_halt_vector hvector = {0, 0};
+	struct msm_rpm_iv_pair rpm_data[2];
+
+	MSM_BUS_MASTER_UNHALT(hvector.haltmask, hvector.haltval,
+		mport);
+	rpm_data[0].id = haltid;
+	rpm_data[0].value = hvector.haltval;
+	rpm_data[1].id = haltid + 1;
+	rpm_data[1].value = hvector.haltmask;
+
+	MSM_BUS_DBG("unalt: ctx: %d, id: %d, value: %d\n",
+		MSM_RPM_CTX_SET_SLEEP, rpm_data[0].id, rpm_data[0].value);
+	MSM_BUS_DBG("unhalt: ctx: %d, id: %d, value: %d\n",
+		MSM_RPM_CTX_SET_SLEEP, rpm_data[1].id, rpm_data[1].value);
+
+	status = msm_rpm_set(MSM_RPM_CTX_SET_0, rpm_data, 2);
+	if (status)
+		MSM_BUS_DBG("msm_rpm_set returned: %d\n", status);
+	return status;
+}
+
+int msm_bus_rpm_hw_init(struct msm_bus_fabric_registration *pdata,
+	struct msm_bus_hw_algorithm *hw_algo)
+{
+	pdata->il_flag = msm_bus_rpm_is_mem_interleaved();
+	hw_algo->allocate_commit_data = msm_bus_rpm_allocate_commit_data;
+	hw_algo->allocate_hw_data = msm_bus_rpm_allocate_rpm_data;
+	hw_algo->node_init = NULL;
+	hw_algo->free_commit_data = free_commit_data;
+	hw_algo->update_bw = msm_bus_rpm_update_bw;
+	hw_algo->commit = msm_bus_rpm_commit;
+	hw_algo->port_halt = msm_bus_rpm_port_halt;
+	hw_algo->port_unhalt = msm_bus_rpm_port_unhalt;
+	if (!pdata->ahb)
+		pdata->rpm_enabled = 1;
+	return 0;
+}
diff --git a/arch/arm/mach-msm/msm_cache_dump.c b/arch/arm/mach-msm/msm_cache_dump.c
new file mode 100644
index 0000000..9759d5a
--- /dev/null
+++ b/arch/arm/mach-msm/msm_cache_dump.c
@@ -0,0 +1,148 @@
+/* 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/memory_alloc.h>
+#include <linux/notifier.h>
+#include <mach/scm.h>
+#include <mach/msm_cache_dump.h>
+#include <mach/memory.h>
+#include <mach/msm_iomap.h>
+
+#define L2_DUMP_OFFSET 0x14
+
+static unsigned long msm_cache_dump_addr;
+
+/*
+ * These should not actually be dereferenced. There's no
+ * need for a virtual mapping, but the physical address is
+ * necessary.
+ */
+static struct l1_cache_dump *l1_dump;
+static struct l2_cache_dump *l2_dump;
+
+static int msm_cache_dump_panic(struct notifier_block *this,
+				unsigned long event, void *ptr)
+{
+#ifdef CONFIG_MSM_CACHE_DUMP_ON_PANIC
+	/*
+	 * Clear the bootloader magic so the dumps aren't overwritten
+	 */
+	__raw_writel(0, MSM_IMEM_BASE + L2_DUMP_OFFSET);
+
+	scm_call_atomic1(L1C_SERVICE_ID, CACHE_BUFFER_DUMP_COMMAND_ID, 2);
+	scm_call_atomic1(L1C_SERVICE_ID, CACHE_BUFFER_DUMP_COMMAND_ID, 1);
+#endif
+	return 0;
+}
+
+static struct notifier_block msm_cache_dump_blk = {
+	.notifier_call  = msm_cache_dump_panic,
+	/*
+	 * higher priority to ensure this runs before another panic handler
+	 * flushes the caches.
+	 */
+	.priority = 1,
+};
+
+static int msm_cache_dump_probe(struct platform_device *pdev)
+{
+	struct msm_cache_dump_platform_data *d = pdev->dev.platform_data;
+	int ret;
+	struct {
+		unsigned long buf;
+		unsigned long size;
+	} l1_cache_data;
+	void *temp;
+	unsigned long total_size = d->l1_size + d->l2_size;
+
+	msm_cache_dump_addr = allocate_contiguous_ebi_nomap(total_size, SZ_4K);
+
+	if (!msm_cache_dump_addr) {
+		pr_err("%s: Could not get memory for cache dumping\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	temp = ioremap(msm_cache_dump_addr, total_size);
+	memset(temp, 0xFF, total_size);
+	iounmap(temp);
+
+	l1_cache_data.buf = msm_cache_dump_addr;
+	l1_cache_data.size = d->l1_size;
+
+	ret = scm_call(L1C_SERVICE_ID, L1C_BUFFER_SET_COMMAND_ID,
+			&l1_cache_data, sizeof(l1_cache_data), NULL, 0);
+
+	if (ret)
+		pr_err("%s: could not register L1 buffer ret = %d.\n",
+			__func__, ret);
+
+	l1_dump = (struct l1_cache_dump *)msm_cache_dump_addr;
+
+#if defined(CONFIG_MSM_CACHE_DUMP_ON_PANIC)
+	l1_cache_data.buf = msm_cache_dump_addr + d->l1_size;
+	l1_cache_data.size = d->l2_size;
+
+	ret = scm_call(L1C_SERVICE_ID, L2C_BUFFER_SET_COMMAND_ID,
+			&l1_cache_data, sizeof(l1_cache_data), NULL, 0);
+
+	if (ret)
+		pr_err("%s: could not register L2 buffer ret = %d.\n",
+			__func__, ret);
+#endif
+	__raw_writel(msm_cache_dump_addr + d->l1_size,
+			MSM_IMEM_BASE + L2_DUMP_OFFSET);
+
+
+	l2_dump = (struct l2_cache_dump *)(msm_cache_dump_addr + d->l1_size);
+
+	atomic_notifier_chain_register(&panic_notifier_list,
+						&msm_cache_dump_blk);
+	return 0;
+}
+
+static int msm_cache_dump_remove(struct platform_device *pdev)
+{
+	atomic_notifier_chain_unregister(&panic_notifier_list,
+					&msm_cache_dump_blk);
+	return 0;
+}
+
+static struct platform_driver msm_cache_dump_driver = {
+	.remove		= __devexit_p(msm_cache_dump_remove),
+	.driver         = {
+		.name = "msm_cache_dump",
+		.owner = THIS_MODULE
+	},
+};
+
+static int __init msm_cache_dump_init(void)
+{
+	return platform_driver_probe(&msm_cache_dump_driver,
+					msm_cache_dump_probe);
+}
+
+static void __exit msm_cache_dump_exit(void)
+{
+	platform_driver_unregister(&msm_cache_dump_driver);
+}
+late_initcall(msm_cache_dump_init);
+module_exit(msm_cache_dump_exit)
diff --git a/arch/arm/mach-msm/msm_dcvs.c b/arch/arm/mach-msm/msm_dcvs.c
new file mode 100644
index 0000000..0c158de
--- /dev/null
+++ b/arch/arm/mach-msm/msm_dcvs.c
@@ -0,0 +1,791 @@
+/* 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/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/kthread.h>
+#include <linux/kobject.h>
+#include <linux/ktime.h>
+#include <linux/hrtimer.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/stringify.h>
+#include <linux/debugfs.h>
+#include <asm/atomic.h>
+#include <asm/page.h>
+#include <mach/msm_dcvs.h>
+
+#define CORE_HANDLE_OFFSET (0xA0)
+#define __err(f, ...) pr_err("MSM_DCVS: %s: " f, __func__, __VA_ARGS__)
+#define __info(f, ...) pr_info("MSM_DCVS: %s: " f, __func__, __VA_ARGS__)
+#define MAX_PENDING	(5)
+
+enum {
+	MSM_DCVS_DEBUG_NOTIFIER    = BIT(0),
+	MSM_DCVS_DEBUG_IDLE_PULSE  = BIT(1),
+	MSM_DCVS_DEBUG_FREQ_CHANGE = BIT(2),
+};
+
+struct core_attribs {
+	struct kobj_attribute idle_enabled;
+	struct kobj_attribute freq_change_enabled;
+	struct kobj_attribute actual_freq;
+	struct kobj_attribute freq_change_us;
+
+	struct kobj_attribute max_time_us;
+
+	struct kobj_attribute slack_time_us;
+	struct kobj_attribute scale_slack_time;
+	struct kobj_attribute scale_slack_time_pct;
+	struct kobj_attribute disable_pc_threshold;
+	struct kobj_attribute em_window_size;
+	struct kobj_attribute em_max_util_pct;
+	struct kobj_attribute ss_window_size;
+	struct kobj_attribute ss_util_pct;
+	struct kobj_attribute ss_iobusy_conv;
+
+	struct attribute_group attrib_group;
+};
+
+struct dcvs_core {
+	char core_name[CORE_NAME_MAX];
+	uint32_t new_freq[MAX_PENDING];
+	uint32_t actual_freq;
+	uint32_t freq_change_us;
+
+	uint32_t max_time_us; /* core param */
+
+	struct msm_dcvs_algo_param algo_param;
+	struct msm_dcvs_idle *idle_driver;
+	struct msm_dcvs_freq *freq_driver;
+
+	/* private */
+	int64_t time_start;
+	struct mutex lock;
+	spinlock_t cpu_lock;
+	struct task_struct *task;
+	struct core_attribs attrib;
+	uint32_t handle;
+	uint32_t group_id;
+	uint32_t freq_pending;
+	struct hrtimer timer;
+	int32_t timer_disabled;
+	/* track if kthread for change_freq is active */
+	int32_t change_freq_activated;
+};
+
+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 dcvs_core core_list[CORES_MAX];
+static DEFINE_MUTEX(core_list_lock);
+
+static struct kobject *cores_kobj;
+static struct dcvs_core *core_handles[CORES_MAX];
+
+/* Change core frequency, called with core mutex locked */
+static int __msm_dcvs_change_freq(struct dcvs_core *core)
+{
+	int ret = 0;
+	unsigned long flags = 0;
+	unsigned int requested_freq = 0;
+	unsigned int prev_freq = 0;
+	int64_t time_start = 0;
+	int64_t time_end = 0;
+	uint32_t slack_us = 0;
+	uint32_t ret1 = 0;
+
+	if (!core->freq_driver || !core->freq_driver->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]);
+		}
+	}
+	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
+	 * timers as well.
+	 */
+	hrtimer_cancel(&core->timer);
+	core->timer_disabled = 1;
+	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);
+	if (ret <= 0) {
+		__err("Core %s failed to set freq %u\n",
+				core->core_name, requested_freq);
+		/* continue to call TZ to get updated slack timer */
+	} else {
+		prev_freq = core->actual_freq;
+		core->actual_freq = ret;
+	}
+
+	time_end = ktime_to_ns(ktime_get());
+	if (msm_dcvs_debug & MSM_DCVS_DEBUG_FREQ_CHANGE)
+		__info("Core %s Time end %llu Time start: %llu\n",
+			core->core_name, time_end, time_start);
+	time_end -= time_start;
+	do_div(time_end, NSEC_PER_USEC);
+	core->freq_change_us = (uint32_t)time_end;
+
+	/**
+	 * Disable low power modes if the actual frequency is >
+	 * disable_pc_threshold.
+	 */
+	if (core->actual_freq >
+			core->algo_param.disable_pc_threshold) {
+		core->idle_driver->enable(core->idle_driver,
+				MSM_DCVS_DISABLE_HIGH_LATENCY_MODES);
+		if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
+			__info("Disabling LPM for %s\n", core->core_name);
+	} else if (core->actual_freq <=
+			core->algo_param.disable_pc_threshold) {
+		core->idle_driver->enable(core->idle_driver,
+				MSM_DCVS_ENABLE_HIGH_LATENCY_MODES);
+		if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
+			__info("Enabling LPM for %s\n", core->core_name);
+	}
+
+	/**
+	 * Update algorithm with new freq and time taken to change
+	 * to this frequency and that will get us the new slack
+	 * timer
+	 */
+	ret = msm_dcvs_scm_event(core->handle, MSM_DCVS_SCM_CLOCK_FREQ_UPDATE,
+		core->actual_freq, (uint32_t)time_end, &slack_us, &ret1);
+	if (!ret) {
+		/* Reset the slack timer */
+		if (slack_us) {
+			core->timer_disabled = 0;
+			ret = hrtimer_start(&core->timer,
+				ktime_set(0, slack_us * 1000),
+				HRTIMER_MODE_REL_PINNED);
+			if (ret)
+				__err("Failed to register timer for core %s\n",
+						core->core_name);
+		}
+	} else {
+		__err("Error sending core (%s) freq change (%u)\n",
+				core->core_name, core->actual_freq);
+	}
+
+	if (msm_dcvs_debug & MSM_DCVS_DEBUG_FREQ_CHANGE)
+		__info("Freq %u requested for core %s (actual %u prev %u) "
+			"change time %u us slack time %u us\n",
+			requested_freq, core->core_name,
+			core->actual_freq, prev_freq,
+			core->freq_change_us, slack_us);
+
+	/**
+	 * By the time we are done with freq changes, we could be asked to
+	 * change again. Check before exiting.
+	 */
+	if (core->freq_pending)
+		goto repeat;
+
+	core->change_freq_activated = 0;
+	return ret;
+}
+
+static int msm_dcvs_do_freq(void *data)
+{
+	struct dcvs_core *core = (struct dcvs_core *)data;
+	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();
+
+		if (kthread_should_stop())
+			break;
+
+		set_current_state(TASK_UNINTERRUPTIBLE);
+	}
+
+	__set_current_state(TASK_RUNNING);
+
+	return 0;
+}
+
+static int msm_dcvs_update_freq(struct dcvs_core *core,
+		enum msm_dcvs_scm_event event, uint32_t param0,
+		uint32_t *ret1, int *freq_changed)
+{
+	int ret = 0;
+	unsigned long flags = 0;
+	uint32_t new_freq = 0;
+
+	spin_lock_irqsave(&core->cpu_lock, flags);
+	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",
+				ret, event, core->core_name);
+		goto freq_done;
+	}
+
+	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;
+		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);
+		}
+	} else {
+		if (freq_changed)
+			*freq_changed = 0;
+	}
+freq_done:
+	spin_unlock_irqrestore(&core->cpu_lock, flags);
+
+	return ret;
+}
+
+static enum hrtimer_restart msm_dcvs_core_slack_timer(struct hrtimer *timer)
+{
+	int ret = 0;
+	struct dcvs_core *core = container_of(timer, struct dcvs_core, timer);
+	uint32_t ret1;
+	uint32_t ret2;
+
+	if (msm_dcvs_debug & MSM_DCVS_DEBUG_FREQ_CHANGE)
+		__info("Slack timer fired for core %s\n", core->core_name);
+
+	/**
+	 * Timer expired, notify TZ
+	 * Dont care about the third arg.
+	 */
+	ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_QOS_TIMER_EXPIRED, 0,
+				   &ret1, &ret2);
+	if (ret)
+		__err("Timer expired for core %s but failed to notify.\n",
+				core->core_name);
+
+	return HRTIMER_NORESTART;
+}
+
+/* Helper functions and macros for sysfs nodes for a core */
+#define CORE_FROM_ATTRIBS(attr, name) \
+	container_of(container_of(attr, struct core_attribs, name), \
+		struct dcvs_core, attrib);
+
+#define DCVS_PARAM_SHOW(_name, v) \
+static ssize_t msm_dcvs_attr_##_name##_show(struct kobject *kobj, \
+		struct kobj_attribute *attr, char *buf) \
+{ \
+	struct dcvs_core *core = CORE_FROM_ATTRIBS(attr, _name); \
+	return snprintf(buf, PAGE_SIZE, "%d\n", v); \
+}
+
+#define DCVS_ALGO_PARAM(_name) \
+static ssize_t msm_dcvs_attr_##_name##_show(struct kobject *kobj,\
+		struct kobj_attribute *attr, char *buf) \
+{ \
+	struct dcvs_core *core = CORE_FROM_ATTRIBS(attr, _name); \
+	return snprintf(buf, PAGE_SIZE, "%d\n", core->algo_param._name); \
+} \
+static ssize_t msm_dcvs_attr_##_name##_store(struct kobject *kobj, \
+		struct kobj_attribute *attr, const char *buf, size_t count) \
+{ \
+	int ret = 0; \
+	uint32_t val = 0; \
+	struct dcvs_core *core = CORE_FROM_ATTRIBS(attr, _name); \
+	mutex_lock(&core->lock); \
+	ret = kstrtouint(buf, 10, &val); \
+	if (ret) { \
+		__err("Invalid input %s for %s\n", buf, __stringify(_name));\
+	} else { \
+		uint32_t old_val = core->algo_param._name; \
+		core->algo_param._name = val; \
+		ret = msm_dcvs_scm_set_algo_params(core->handle, \
+				&core->algo_param); \
+		if (ret) { \
+			core->algo_param._name = old_val; \
+			__err("Error(%d) in setting %d for algo param %s\n",\
+					ret, val, __stringify(_name)); \
+		} \
+	} \
+	mutex_unlock(&core->lock); \
+	return count; \
+}
+
+#define DCVS_RO_ATTRIB(i, _name) \
+	core->attrib._name.attr.name = __stringify(_name); \
+	core->attrib._name.attr.mode = S_IRUGO; \
+	core->attrib._name.show = msm_dcvs_attr_##_name##_show; \
+	core->attrib._name.store = NULL; \
+	core->attrib.attrib_group.attrs[i] = &core->attrib._name.attr;
+
+#define DCVS_RW_ATTRIB(i, _name) \
+	core->attrib._name.attr.name = __stringify(_name); \
+	core->attrib._name.attr.mode = S_IRUGO | S_IWUSR; \
+	core->attrib._name.show = msm_dcvs_attr_##_name##_show; \
+	core->attrib._name.store = msm_dcvs_attr_##_name##_store; \
+	core->attrib.attrib_group.attrs[i] = &core->attrib._name.attr;
+
+/**
+ * Function declarations for different attributes.
+ * Gets used when setting the attribute show and store parameters.
+ */
+DCVS_PARAM_SHOW(idle_enabled, (core->idle_driver != NULL))
+DCVS_PARAM_SHOW(freq_change_enabled, (core->freq_driver != NULL))
+DCVS_PARAM_SHOW(actual_freq, (core->actual_freq))
+DCVS_PARAM_SHOW(freq_change_us, (core->freq_change_us))
+DCVS_PARAM_SHOW(max_time_us, (core->max_time_us))
+
+DCVS_ALGO_PARAM(slack_time_us)
+DCVS_ALGO_PARAM(scale_slack_time)
+DCVS_ALGO_PARAM(scale_slack_time_pct)
+DCVS_ALGO_PARAM(disable_pc_threshold)
+DCVS_ALGO_PARAM(em_window_size)
+DCVS_ALGO_PARAM(em_max_util_pct)
+DCVS_ALGO_PARAM(ss_window_size)
+DCVS_ALGO_PARAM(ss_util_pct)
+DCVS_ALGO_PARAM(ss_iobusy_conv)
+
+static int msm_dcvs_setup_core_sysfs(struct dcvs_core *core)
+{
+	int ret = 0;
+	struct kobject *core_kobj = NULL;
+	const int attr_count = 15;
+
+	BUG_ON(!cores_kobj);
+
+	core->attrib.attrib_group.attrs =
+		kzalloc(attr_count * sizeof(struct attribute *), GFP_KERNEL);
+
+	if (!core->attrib.attrib_group.attrs) {
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	DCVS_RO_ATTRIB(0, idle_enabled);
+	DCVS_RO_ATTRIB(1, freq_change_enabled);
+	DCVS_RO_ATTRIB(2, actual_freq);
+	DCVS_RO_ATTRIB(3, freq_change_us);
+	DCVS_RO_ATTRIB(4, max_time_us);
+
+	DCVS_RW_ATTRIB(5, slack_time_us);
+	DCVS_RW_ATTRIB(6, scale_slack_time);
+	DCVS_RW_ATTRIB(7, scale_slack_time_pct);
+	DCVS_RW_ATTRIB(8, disable_pc_threshold);
+	DCVS_RW_ATTRIB(9, em_window_size);
+	DCVS_RW_ATTRIB(10, em_max_util_pct);
+	DCVS_RW_ATTRIB(11, ss_window_size);
+	DCVS_RW_ATTRIB(12, ss_util_pct);
+	DCVS_RW_ATTRIB(13, ss_iobusy_conv);
+
+	core->attrib.attrib_group.attrs[14] = NULL;
+
+	core_kobj = kobject_create_and_add(core->core_name, cores_kobj);
+	if (!core_kobj) {
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	ret = sysfs_create_group(core_kobj, &core->attrib.attrib_group);
+	if (ret)
+		__err("Cannot create core %s attr group\n", core->core_name);
+	else if (msm_dcvs_debug & MSM_DCVS_DEBUG_NOTIFIER)
+		__info("Setting up attributes for core %s\n", core->core_name);
+
+done:
+	if (ret) {
+		kfree(core->attrib.attrib_group.attrs);
+		kobject_del(core_kobj);
+	}
+
+	return ret;
+}
+
+/* Return the core if found or add to list if @add_to_list is true */
+static struct dcvs_core *msm_dcvs_get_core(const char *name, int add_to_list)
+{
+	struct dcvs_core *core = NULL;
+	int i;
+	int empty = -1;
+
+	if (!name[0] ||
+		(strnlen(name, CORE_NAME_MAX - 1) == CORE_NAME_MAX - 1))
+		return core;
+
+	mutex_lock(&core_list_lock);
+	for (i = 0; i < CORES_MAX; i++) {
+		core = &core_list[i];
+		if ((empty < 0) && !core->core_name[0]) {
+			empty = i;
+			continue;
+		}
+		if (!strncmp(name, core->core_name, CORE_NAME_MAX))
+			break;
+	}
+
+	/* Check for core_list full */
+	if ((i == CORES_MAX) && (empty < 0)) {
+		mutex_unlock(&core_list_lock);
+		return NULL;
+	}
+
+	if (i == CORES_MAX && add_to_list) {
+		core = &core_list[empty];
+		strlcpy(core->core_name, name, CORE_NAME_MAX);
+		mutex_init(&core->lock);
+		spin_lock_init(&core->cpu_lock);
+		core->handle = empty + CORE_HANDLE_OFFSET;
+		hrtimer_init(&core->timer,
+				CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
+		core->timer.function = msm_dcvs_core_slack_timer;
+	}
+	mutex_unlock(&core_list_lock);
+
+	return core;
+}
+
+int msm_dcvs_register_core(const char *core_name, uint32_t group_id,
+		struct msm_dcvs_core_info *info)
+{
+	int ret = -EINVAL;
+	struct dcvs_core *core = NULL;
+
+	if (!core_name || !core_name[0])
+		return ret;
+
+	core = msm_dcvs_get_core(core_name, true);
+	if (!core)
+		return ret;
+
+	mutex_lock(&core->lock);
+	if (group_id) {
+		/**
+		 * Create a group for cores, if this core is part of a group
+		 * if the group_id is 0, the core is not part of a group.
+		 * If the group_id already exits, it will through an error
+		 * which we will ignore.
+		 */
+		ret = msm_dcvs_scm_create_group(group_id);
+		if (ret == -ENOMEM)
+			goto bail;
+	}
+	core->group_id = group_id;
+
+	core->max_time_us = info->core_param.max_time_us;
+	memcpy(&core->algo_param, &info->algo_param,
+			sizeof(struct msm_dcvs_algo_param));
+
+	ret = msm_dcvs_scm_register_core(core->handle, group_id,
+			&info->core_param, info->freq_tbl);
+	if (ret)
+		goto bail;
+
+	ret = msm_dcvs_scm_set_algo_params(core->handle, &info->algo_param);
+	if (ret)
+		goto bail;
+
+	ret = msm_dcvs_setup_core_sysfs(core);
+	if (ret) {
+		__err("Unable to setup core %s sysfs\n", core->core_name);
+		core_handles[core->handle - CORE_HANDLE_OFFSET] = NULL;
+		goto bail;
+	}
+
+bail:
+	mutex_unlock(&core->lock);
+	return ret;
+}
+EXPORT_SYMBOL(msm_dcvs_register_core);
+
+int msm_dcvs_freq_sink_register(struct msm_dcvs_freq *drv)
+{
+	int ret = -EINVAL;
+	struct dcvs_core *core = NULL;
+	uint32_t ret1;
+	uint32_t ret2;
+
+	if (!drv || !drv->core_name)
+		return ret;
+
+	core = msm_dcvs_get_core(drv->core_name, true);
+	if (!core)
+		return ret;
+
+	mutex_lock(&core->lock);
+	if (core->freq_driver && (msm_dcvs_debug & MSM_DCVS_DEBUG_NOTIFIER))
+		__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;
+	}
+
+	if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
+		__info("Enabling idle pulse for %s\n", core->core_name);
+
+	if (core->idle_driver) {
+		core->actual_freq = core->freq_driver->get_frequency(drv);
+		/* Notify TZ to start receiving idle info for the core */
+		ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_ENABLE_CORE, 1,
+					   &ret1, &ret2);
+		core->idle_driver->enable(core->idle_driver,
+				MSM_DCVS_ENABLE_IDLE_PULSE);
+	}
+
+	mutex_unlock(&core->lock);
+
+	return core->handle;
+}
+EXPORT_SYMBOL(msm_dcvs_freq_sink_register);
+
+int msm_dcvs_freq_sink_unregister(struct msm_dcvs_freq *drv)
+{
+	int ret = -EINVAL;
+	struct dcvs_core *core = NULL;
+	uint32_t ret1;
+	uint32_t ret2;
+
+	if (!drv || !drv->core_name)
+		return ret;
+
+	core = msm_dcvs_get_core(drv->core_name, false);
+	if (!core)
+		return ret;
+
+	mutex_lock(&core->lock);
+	if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
+		__info("Disabling idle pulse for %s\n", core->core_name);
+	if (core->idle_driver) {
+		core->idle_driver->enable(core->idle_driver,
+				MSM_DCVS_DISABLE_IDLE_PULSE);
+		/* Notify TZ to stop receiving idle info for the core */
+		ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_ENABLE_CORE, 0,
+					   &ret1, &ret2);
+		hrtimer_cancel(&core->timer);
+		core->idle_driver->enable(core->idle_driver,
+				MSM_DCVS_ENABLE_HIGH_LATENCY_MODES);
+		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);
+
+int msm_dcvs_idle_source_register(struct msm_dcvs_idle *drv)
+{
+	int ret = -EINVAL;
+	struct dcvs_core *core = NULL;
+
+	if (!drv || !drv->core_name)
+		return ret;
+
+	core = msm_dcvs_get_core(drv->core_name, true);
+	if (!core)
+		return ret;
+
+	mutex_lock(&core->lock);
+	if (core->idle_driver && (msm_dcvs_debug & MSM_DCVS_DEBUG_NOTIFIER))
+		__info("Idle notifier for %s being replaced\n",
+				core->core_name);
+	core->idle_driver = drv;
+	mutex_unlock(&core->lock);
+
+	return core->handle;
+}
+EXPORT_SYMBOL(msm_dcvs_idle_source_register);
+
+int msm_dcvs_idle_source_unregister(struct msm_dcvs_idle *drv)
+{
+	int ret = -EINVAL;
+	struct dcvs_core *core = NULL;
+
+	if (!drv || !drv->core_name)
+		return ret;
+
+	core = msm_dcvs_get_core(drv->core_name, false);
+	if (!core)
+		return ret;
+
+	mutex_lock(&core->lock);
+	core->idle_driver = NULL;
+	mutex_unlock(&core->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_dcvs_idle_source_unregister);
+
+int msm_dcvs_idle(int handle, enum msm_core_idle_state state, uint32_t iowaited)
+{
+	int ret = 0;
+	struct dcvs_core *core = NULL;
+	uint32_t timer_interval_us = 0;
+	uint32_t r0, r1;
+	uint32_t freq_changed = 0;
+
+	if (handle >= CORE_HANDLE_OFFSET &&
+			(handle - CORE_HANDLE_OFFSET) < CORES_MAX)
+		core = &core_list[handle - CORE_HANDLE_OFFSET];
+
+	BUG_ON(!core);
+
+	if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
+		__info("Core %s idle state %d\n", core->core_name, state);
+
+	switch (state) {
+	case MSM_DCVS_IDLE_ENTER:
+		hrtimer_cancel(&core->timer);
+		ret = msm_dcvs_scm_event(core->handle,
+				MSM_DCVS_SCM_IDLE_ENTER, 0, 0, &r0, &r1);
+		if (ret)
+			__err("Error (%d) sending idle enter for %s\n",
+					ret, core->core_name);
+		break;
+
+	case MSM_DCVS_IDLE_EXIT:
+		hrtimer_cancel(&core->timer);
+		ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_IDLE_EXIT,
+				iowaited, &timer_interval_us, &freq_changed);
+		if (ret)
+			__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)
+			break;
+		if (timer_interval_us && !core->timer_disabled) {
+			ret = hrtimer_start(&core->timer,
+				ktime_set(0, timer_interval_us * 1000),
+				HRTIMER_MODE_REL_PINNED);
+
+			if (ret)
+				__err("Failed to register timer for core %s\n",
+				      core->core_name);
+		}
+		break;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(msm_dcvs_idle);
+
+static int __init msm_dcvs_late_init(void)
+{
+	struct kobject *module_kobj = NULL;
+	int ret = 0;
+
+	module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
+	if (!module_kobj) {
+		pr_err("%s: cannot find kobject for module %s\n",
+				__func__, KBUILD_MODNAME);
+		ret = -ENOENT;
+		goto err;
+	}
+
+	cores_kobj = kobject_create_and_add("cores", module_kobj);
+	if (!cores_kobj) {
+		__err("Cannot create %s kobject\n", "cores");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	debugfs_base = debugfs_create_dir("msm_dcvs", NULL);
+	if (!debugfs_base) {
+		__err("Cannot create debugfs base %s\n", "msm_dcvs");
+		ret = -ENOENT;
+		goto err;
+	}
+
+	if (!debugfs_create_u32("debug_mask", S_IRUGO | S_IWUSR,
+				debugfs_base, &msm_dcvs_debug)) {
+		__err("Cannot create debugfs entry %s\n", "debug_mask");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+err:
+	if (ret) {
+		kobject_del(cores_kobj);
+		cores_kobj = NULL;
+		debugfs_remove(debugfs_base);
+	}
+
+	return ret;
+}
+late_initcall(msm_dcvs_late_init);
+
+static int __init msm_dcvs_early_init(void)
+{
+	int ret = 0;
+
+	if (!msm_dcvs_enabled) {
+		__info("Not enabled (%d)\n", msm_dcvs_enabled);
+		return 0;
+	}
+
+	ret = msm_dcvs_scm_init(10 * 1024);
+	if (ret)
+		__err("Unable to initialize DCVS err=%d\n", ret);
+
+	return ret;
+}
+postcore_initcall(msm_dcvs_early_init);
diff --git a/arch/arm/mach-msm/msm_dcvs_idle.c b/arch/arm/mach-msm/msm_dcvs_idle.c
new file mode 100644
index 0000000..179e170
--- /dev/null
+++ b/arch/arm/mach-msm/msm_dcvs_idle.c
@@ -0,0 +1,170 @@
+/* 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/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/cpu_pm.h>
+#include <linux/platform_device.h>
+#include <linux/pm_qos.h>
+#include <linux/hrtimer.h>
+#include <linux/tick.h>
+#include <mach/msm_dcvs.h>
+
+struct cpu_idle_info {
+	int cpu;
+	int enabled;
+	int handle;
+	struct msm_dcvs_idle dcvs_notifier;
+};
+
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct cpu_idle_info, cpu_idle_info);
+static DEFINE_PER_CPU_SHARED_ALIGNED(u64, iowait_on_cpu);
+static char core_name[NR_CPUS][10];
+static struct pm_qos_request qos_req;
+static uint32_t latency;
+
+static int msm_dcvs_idle_notifier(struct msm_dcvs_idle *self,
+		enum msm_core_control_event event)
+{
+	struct cpu_idle_info *info = container_of(self,
+				struct cpu_idle_info, dcvs_notifier);
+
+	switch (event) {
+	case MSM_DCVS_ENABLE_IDLE_PULSE:
+		info->enabled = true;
+		break;
+
+	case MSM_DCVS_DISABLE_IDLE_PULSE:
+		info->enabled = false;
+		break;
+
+	case MSM_DCVS_ENABLE_HIGH_LATENCY_MODES:
+		pm_qos_update_request(&qos_req, PM_QOS_DEFAULT_VALUE);
+		break;
+
+	case MSM_DCVS_DISABLE_HIGH_LATENCY_MODES:
+		pm_qos_update_request(&qos_req, latency);
+		break;
+	}
+
+	return 0;
+}
+
+static int msm_cpuidle_notifier(struct notifier_block *self, unsigned long cmd,
+		void *v)
+{
+	struct cpu_idle_info *info =
+		&per_cpu(cpu_idle_info, smp_processor_id());
+	u64 io_wait_us = 0;
+	u64 prev_io_wait_us = 0;
+	u64 last_update_time = 0;
+	u64 val = 0;
+	uint32_t iowaited = 0;
+
+	if (!info->enabled)
+		return NOTIFY_OK;
+
+	switch (cmd) {
+	case CPU_PM_ENTER:
+		val = get_cpu_iowait_time_us(smp_processor_id(),
+					&last_update_time);
+		/* val could be -1 when NOHZ is not enabled */
+		if (val == (u64)-1)
+			val = 0;
+		per_cpu(iowait_on_cpu, smp_processor_id()) = val;
+		msm_dcvs_idle(info->handle, MSM_DCVS_IDLE_ENTER, 0);
+		break;
+
+	case CPU_PM_ENTER_FAILED:
+	case CPU_PM_EXIT:
+		prev_io_wait_us = per_cpu(iowait_on_cpu, smp_processor_id());
+		val = get_cpu_iowait_time_us(smp_processor_id(),
+				&last_update_time);
+		if (val == (u64)-1)
+			val = 0;
+		io_wait_us = val;
+		iowaited = (io_wait_us - prev_io_wait_us);
+		msm_dcvs_idle(info->handle, MSM_DCVS_IDLE_EXIT, iowaited);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block idle_nb = {
+	.notifier_call = msm_cpuidle_notifier,
+};
+
+static int msm_dcvs_idle_probe(struct platform_device *pdev)
+{
+	int cpu;
+	struct cpu_idle_info *info = NULL;
+	struct msm_dcvs_idle *inotify = NULL;
+
+	for_each_possible_cpu(cpu) {
+		info = &per_cpu(cpu_idle_info, cpu);
+		info->cpu = cpu;
+		inotify = &info->dcvs_notifier;
+		snprintf(core_name[cpu], 10, "cpu%d", cpu);
+		inotify->core_name = core_name[cpu];
+		inotify->enable = msm_dcvs_idle_notifier;
+		info->handle = msm_dcvs_idle_source_register(inotify);
+		BUG_ON(info->handle < 0);
+	}
+
+	latency = *((uint32_t *)pdev->dev.platform_data);
+	pm_qos_add_request(&qos_req, PM_QOS_CPU_DMA_LATENCY,
+				PM_QOS_DEFAULT_VALUE);
+
+	return cpu_pm_register_notifier(&idle_nb);
+}
+
+static int msm_dcvs_idle_remove(struct platform_device *pdev)
+{
+	int ret = 0;
+	int rc = 0;
+	int cpu = 0;
+	struct msm_dcvs_idle *inotify = NULL;
+	struct cpu_idle_info *info = NULL;
+
+	rc = cpu_pm_unregister_notifier(&idle_nb);
+
+	for_each_possible_cpu(cpu) {
+		info = &per_cpu(cpu_idle_info, cpu);
+		inotify = &info->dcvs_notifier;
+		ret = msm_dcvs_idle_source_unregister(inotify);
+		if (ret) {
+			rc = -EFAULT;
+			pr_err("Error de-registering core %d idle notifier.\n",
+					cpu);
+		}
+	}
+
+	return rc;
+}
+
+static struct platform_driver idle_pdrv = {
+	.probe = msm_dcvs_idle_probe,
+	.remove = __devexit_p(msm_dcvs_idle_remove),
+	.driver = {
+		.name  = "msm_cpu_idle",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int msm_dcvs_idle_init(void)
+{
+	return platform_driver_register(&idle_pdrv);
+}
+late_initcall(msm_dcvs_idle_init);
diff --git a/arch/arm/mach-msm/msm_dcvs_scm.c b/arch/arm/mach-msm/msm_dcvs_scm.c
new file mode 100644
index 0000000..6095e0813
--- /dev/null
+++ b/arch/arm/mach-msm/msm_dcvs_scm.c
@@ -0,0 +1,161 @@
+/* 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/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/memory_alloc.h>
+#include <mach/memory.h>
+#include <mach/scm.h>
+#include <mach/msm_dcvs_scm.h>
+
+#define DCVS_CMD_CREATE_GROUP		1
+#define DCVS_CMD_REGISTER_CORE		2
+#define DCVS_CMD_SET_ALGO_PARAM		3
+#define DCVS_CMD_EVENT			4
+#define DCVS_CMD_INIT			5
+
+struct scm_register_core {
+	uint32_t core_id;
+	uint32_t group_id;
+	phys_addr_t core_param_phy;
+	phys_addr_t freq_phy;
+};
+
+struct scm_algo {
+	uint32_t core_id;
+	phys_addr_t algo_phy;
+};
+
+struct scm_init {
+	uint32_t phy;
+	uint32_t size;
+};
+
+int msm_dcvs_scm_init(size_t size)
+{
+	int ret = 0;
+	struct scm_init init;
+	uint32_t p = 0;
+
+	/* Allocate word aligned non-cacheable memory */
+	p = allocate_contiguous_ebi_nomap(size, 4);
+	if (!p)
+		return -ENOMEM;
+
+	init.phy = p;
+	init.size = size;
+
+	ret = scm_call(SCM_SVC_DCVS, DCVS_CMD_INIT,
+			&init, sizeof(init), NULL, 0);
+
+	/* Not freed if the initialization succeeds */
+	if (ret)
+		free_contiguous_memory_by_paddr(p);
+
+	return ret;
+}
+EXPORT_SYMBOL(msm_dcvs_scm_init);
+
+int msm_dcvs_scm_create_group(uint32_t id)
+{
+	int ret = 0;
+
+	ret = scm_call(SCM_SVC_DCVS, DCVS_CMD_CREATE_GROUP,
+			&id, sizeof(uint32_t), NULL, 0);
+
+	return ret;
+}
+EXPORT_SYMBOL(msm_dcvs_scm_create_group);
+
+int msm_dcvs_scm_register_core(uint32_t core_id, uint32_t group_id,
+		struct msm_dcvs_core_param *param,
+		struct msm_dcvs_freq_entry *freq)
+{
+	int ret = 0;
+	struct scm_register_core reg_data;
+	struct msm_dcvs_core_param *p = NULL;
+	struct msm_dcvs_freq_entry *f = NULL;
+
+	p = kzalloc(PAGE_ALIGN(sizeof(struct msm_dcvs_core_param)), GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+
+	f = kzalloc(PAGE_ALIGN(sizeof(struct msm_dcvs_freq_entry) *
+				param->num_freq), GFP_KERNEL);
+	if (!f) {
+		kfree(p);
+		return -ENOMEM;
+	}
+
+	memcpy(p, param, sizeof(struct msm_dcvs_core_param));
+	memcpy(f, freq, sizeof(struct msm_dcvs_freq_entry) * param->num_freq);
+
+	reg_data.core_id = core_id;
+	reg_data.group_id = group_id;
+	reg_data.core_param_phy = virt_to_phys(p);
+	reg_data.freq_phy = virt_to_phys(f);
+
+	ret = scm_call(SCM_SVC_DCVS, DCVS_CMD_REGISTER_CORE,
+			&reg_data, sizeof(reg_data), NULL, 0);
+
+	kfree(f);
+	kfree(p);
+
+	return ret;
+}
+EXPORT_SYMBOL(msm_dcvs_scm_register_core);
+
+int msm_dcvs_scm_set_algo_params(uint32_t core_id,
+		struct msm_dcvs_algo_param *param)
+{
+	int ret = 0;
+	struct scm_algo algo;
+	struct msm_dcvs_algo_param *p = NULL;
+
+	p = kzalloc(PAGE_ALIGN(sizeof(struct msm_dcvs_algo_param)), GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+
+	memcpy(p, param, sizeof(struct msm_dcvs_algo_param));
+
+	algo.core_id = core_id;
+	algo.algo_phy = virt_to_phys(p);
+
+	ret = scm_call(SCM_SVC_DCVS, DCVS_CMD_SET_ALGO_PARAM,
+			&algo, sizeof(algo), NULL, 0);
+
+	kfree(p);
+
+	return ret;
+}
+EXPORT_SYMBOL(msm_dcvs_scm_set_algo_params);
+
+int msm_dcvs_scm_event(uint32_t core_id,
+		enum msm_dcvs_scm_event event_id,
+		uint32_t param0, uint32_t param1,
+		uint32_t *ret0, uint32_t *ret1)
+{
+	int ret = -EINVAL;
+
+	if (!ret0 || !ret1)
+		return ret;
+
+	ret = scm_call_atomic4_3(SCM_SVC_DCVS, DCVS_CMD_EVENT,
+			core_id, event_id, param0, param1, ret0, ret1);
+
+	return ret;
+}
+EXPORT_SYMBOL(msm_dcvs_scm_event);
diff --git a/arch/arm/mach-msm/msm_dsps.c b/arch/arm/mach-msm/msm_dsps.c
new file mode 100644
index 0000000..057665b
--- /dev/null
+++ b/arch/arm/mach-msm/msm_dsps.c
@@ -0,0 +1,912 @@
+/* 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
+ * 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.
+ */
+
+/*
+ * msm_dsps - control DSPS clocks, gpios and vregs.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/gpio.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/msm_dsps.h>
+
+#include <mach/irqs.h>
+#include <mach/peripheral-loader.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_smsm.h>
+#include <mach/msm_dsps.h>
+#include <mach/subsystem_restart.h>
+#include <mach/subsystem_notif.h>
+
+#include "timer.h"
+
+#define DRV_NAME	"msm_dsps"
+#define DRV_VERSION	"3.02"
+
+#define PPSS_PAUSE_REG	0x1804
+
+#define PPSS_TIMER0_32KHZ_REG	0x1004
+#define PPSS_TIMER0_20MHZ_REG	0x0804
+
+/**
+ *  Driver Context
+ *
+ *  @dev_class - device class.
+ *  @dev_num - device major & minor number.
+ *  @dev - the device.
+ *  @cdev - character device for user interface.
+ *  @pdata - platform data.
+ *  @pil - handle to DSPS Firmware loader.
+ *  @is_on - DSPS is on.
+ *  @ref_count - open/close reference count.
+ *  @ppss_base - ppss registers virtual base address.
+ */
+struct dsps_drv {
+
+	struct class *dev_class;
+	dev_t dev_num;
+	struct device *dev;
+	struct cdev *cdev;
+
+	struct msm_dsps_platform_data *pdata;
+
+	void *pil;
+
+	int is_on;
+	int ref_count;
+
+	void __iomem *ppss_base;
+};
+
+/**
+ * Driver context.
+ */
+static struct dsps_drv *drv;
+
+/**
+ * self-initiated shutdown flag
+ */
+static int dsps_crash_shutdown_g;
+
+
+static void dsps_fatal_handler(struct work_struct *work);
+
+/**
+ *  Load DSPS Firmware.
+ */
+static int dsps_load(const char *name)
+{
+	pr_debug("%s.\n", __func__);
+
+	drv->pil = pil_get(name);
+
+	if (IS_ERR(drv->pil)) {
+		pr_err("%s: fail to load DSPS firmware %s.\n", __func__, name);
+		return -ENODEV;
+	}
+	msleep(20);
+	return 0;
+}
+
+/**
+ *  Unload DSPS Firmware.
+ */
+static void dsps_unload(void)
+{
+	pr_debug("%s.\n", __func__);
+
+	pil_put(drv->pil);
+}
+
+/**
+ *  Suspend DSPS CPU.
+ */
+static void dsps_suspend(void)
+{
+	pr_debug("%s.\n", __func__);
+
+	writel_relaxed(1, drv->ppss_base + PPSS_PAUSE_REG);
+	mb(); /* Make sure write commited before ioctl returns. */
+}
+
+/**
+ *  Resume DSPS CPU.
+ */
+static void dsps_resume(void)
+{
+	pr_debug("%s.\n", __func__);
+
+	writel_relaxed(0, drv->ppss_base + PPSS_PAUSE_REG);
+	mb(); /* Make sure write commited before ioctl returns. */
+}
+
+/**
+ * Read DSPS slow timer.
+ */
+static u32 dsps_read_slow_timer(void)
+{
+	u32 val;
+
+	/* Read the timer value from the MSM sclk. The MSM slow clock & DSPS
+	 * timers are in sync, so these are the same value */
+	val = msm_timer_get_sclk_ticks();
+	pr_debug("%s.count=%d.\n", __func__, val);
+
+	return val;
+}
+
+/**
+ * Read DSPS fast timer.
+ */
+static u32 dsps_read_fast_timer(void)
+{
+	u32 val;
+
+	val = readl_relaxed(drv->ppss_base + PPSS_TIMER0_20MHZ_REG);
+	rmb(); /* order reads from the user output buffer */
+
+	pr_debug("%s.count=%d.\n", __func__, val);
+
+	return val;
+}
+
+/**
+ *  Power on request.
+ *
+ *  Set clocks to ON.
+ *  Set sensors chip-select GPIO to non-reset (on) value.
+ *
+ */
+static int dsps_power_on_handler(void)
+{
+	int ret = 0;
+	int i, ci, gi, ri;
+
+	pr_debug("%s.\n", __func__);
+
+	if (drv->is_on) {
+		pr_debug("%s: already ON.\n",  __func__);
+		return 0;
+	}
+
+	for (ci = 0; ci < drv->pdata->clks_num; ci++) {
+		const char *name = drv->pdata->clks[ci].name;
+		u32 rate = drv->pdata->clks[ci].rate;
+		struct clk *clock = drv->pdata->clks[ci].clock;
+
+		if (clock == NULL)
+			continue;
+
+		if (rate > 0) {
+			ret = clk_set_rate(clock, rate);
+			pr_debug("%s: clk %s set rate %d.",
+				__func__, name, rate);
+			if (ret) {
+				pr_err("%s: clk %s set rate %d. err=%d.",
+					__func__, name, rate, ret);
+				goto clk_err;
+			}
+
+		}
+
+		ret = clk_enable(clock);
+		if (ret) {
+			pr_err("%s: enable clk %s err %d.",
+			       __func__, name, ret);
+			goto clk_err;
+		}
+	}
+
+	for (gi = 0; gi < drv->pdata->gpios_num; gi++) {
+		const char *name = drv->pdata->gpios[gi].name;
+		int num = drv->pdata->gpios[gi].num;
+		int val = drv->pdata->gpios[gi].on_val;
+		int is_owner = drv->pdata->gpios[gi].is_owner;
+
+		if (!is_owner)
+			continue;
+
+		ret = gpio_direction_output(num, val);
+		if (ret) {
+			pr_err("%s: set GPIO %s num %d to %d err %d.",
+			       __func__, name, num, val, ret);
+			goto gpio_err;
+		}
+	}
+
+	for (ri = 0; ri < drv->pdata->regs_num; ri++) {
+		const char *name = drv->pdata->regs[ri].name;
+		struct regulator *reg = drv->pdata->regs[ri].reg;
+		int volt = drv->pdata->regs[ri].volt;
+
+		if (reg == NULL)
+			continue;
+
+		pr_debug("%s: set regulator %s.", __func__, name);
+
+		ret = regulator_set_voltage(reg, volt, volt);
+
+		if (ret) {
+			pr_err("%s: set regulator %s voltage %d err = %d.\n",
+				__func__, name, volt, ret);
+			goto reg_err;
+		}
+
+		ret = regulator_enable(reg);
+		if (ret) {
+			pr_err("%s: enable regulator %s err = %d.\n",
+				__func__, name, ret);
+			goto reg_err;
+		}
+	}
+
+	drv->is_on = true;
+
+	return 0;
+
+	/*
+	 * If failling to set ANY clock/gpio/regulator to ON then we set
+	 * them back to OFF to avoid consuming power for unused
+	 * clocks/gpios/regulators.
+	 */
+reg_err:
+	for (i = 0; i < ri; i++) {
+		struct regulator *reg = drv->pdata->regs[ri].reg;
+
+		if (reg == NULL)
+			continue;
+
+		regulator_disable(reg);
+	}
+
+gpio_err:
+	for (i = 0; i < gi; i++) {
+		int num = drv->pdata->gpios[i].num;
+		int val = drv->pdata->gpios[i].off_val;
+		int is_owner = drv->pdata->gpios[i].is_owner;
+
+		if (!is_owner)
+			continue;
+
+		ret = gpio_direction_output(num, val);
+	}
+
+clk_err:
+	for (i = 0; i < ci; i++) {
+		struct clk *clock = drv->pdata->clks[i].clock;
+
+		if (clock == NULL)
+			continue;
+
+		clk_disable(clock);
+	}
+
+	return -ENODEV;
+}
+
+/**
+ *  Power off request.
+ *
+ *  Set clocks to OFF.
+ *  Set sensors chip-select GPIO to reset (off) value.
+ *
+ */
+static int dsps_power_off_handler(void)
+{
+	int ret;
+	int i;
+
+	pr_debug("%s.\n", __func__);
+
+	if (!drv->is_on) {
+		pr_debug("%s: already OFF.\n", __func__);
+		return 0;
+	}
+
+	for (i = 0; i < drv->pdata->clks_num; i++)
+		if (drv->pdata->clks[i].clock) {
+			const char *name = drv->pdata->clks[i].name;
+
+			pr_debug("%s: set clk %s off.", __func__, name);
+			clk_disable(drv->pdata->clks[i].clock);
+		}
+
+	for (i = 0; i < drv->pdata->regs_num; i++)
+		if (drv->pdata->regs[i].reg) {
+			const char *name = drv->pdata->regs[i].name;
+
+			pr_debug("%s: set regulator %s off.", __func__, name);
+			regulator_disable(drv->pdata->regs[i].reg);
+		}
+
+	/* Clocks on/off has reference count but GPIOs don't. */
+	drv->is_on = false;
+
+	for (i = 0; i < drv->pdata->gpios_num; i++) {
+		const char *name = drv->pdata->gpios[i].name;
+		int num = drv->pdata->gpios[i].num;
+		int val = drv->pdata->gpios[i].off_val;
+
+		pr_debug("%s: set gpio %s off.", __func__, name);
+
+		ret = gpio_direction_output(num, val);
+		if (ret) {
+			pr_err("%s: set GPIO %s err %d.", __func__, name, ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static DECLARE_WORK(dsps_fatal_work, dsps_fatal_handler);
+
+/**
+ *  Watchdog interrupt handler
+ *
+ */
+static irqreturn_t dsps_wdog_bite_irq(int irq, void *dev_id)
+{
+	pr_debug("%s\n", __func__);
+	(void)schedule_work(&dsps_fatal_work);
+	disable_irq_nosync(irq);
+	return IRQ_HANDLED;
+}
+
+/**
+ * IO Control - handle commands from client.
+ *
+ */
+static long dsps_ioctl(struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	int ret = 0;
+	u32 val = 0;
+
+	pr_debug("%s.\n", __func__);
+
+	switch (cmd) {
+	case DSPS_IOCTL_ON:
+		ret = dsps_power_on_handler();
+		dsps_resume();
+		break;
+	case DSPS_IOCTL_OFF:
+		if (!drv->pdata->dsps_pwr_ctl_en) {
+			dsps_suspend();
+			ret = dsps_power_off_handler();
+		}
+		break;
+	case DSPS_IOCTL_READ_SLOW_TIMER:
+		val = dsps_read_slow_timer();
+		ret = put_user(val, (u32 __user *) arg);
+		break;
+	case DSPS_IOCTL_READ_FAST_TIMER:
+		val = dsps_read_fast_timer();
+		ret = put_user(val, (u32 __user *) arg);
+		break;
+	case DSPS_IOCTL_RESET:
+		dsps_fatal_handler(NULL);
+		ret = 0;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/**
+ * allocate resources.
+ * @pdev - pointer to platform device.
+ */
+static int dsps_alloc_resources(struct platform_device *pdev)
+{
+	int ret = -ENODEV;
+	struct resource *ppss_res;
+	struct resource *ppss_wdog;
+	int i;
+
+	pr_debug("%s.\n", __func__);
+
+	if ((drv->pdata->signature != DSPS_SIGNATURE)) {
+		pr_err("%s: invalid signature for pdata.", __func__);
+		return -EINVAL;
+	}
+
+	ppss_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						"ppss_reg");
+	if (!ppss_res) {
+		pr_err("%s: failed to get ppss_reg resource.\n", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < drv->pdata->clks_num; i++) {
+		const char *name = drv->pdata->clks[i].name;
+		struct clk *clock;
+
+		drv->pdata->clks[i].clock = NULL;
+
+		pr_debug("%s: get clk %s.", __func__, name);
+
+		clock = clk_get(drv->dev, name);
+		if (IS_ERR(clock)) {
+			pr_err("%s: can't get clk %s.", __func__, name);
+			goto clk_err;
+		}
+		drv->pdata->clks[i].clock = clock;
+	}
+
+	for (i = 0; i < drv->pdata->gpios_num; i++) {
+		const char *name = drv->pdata->gpios[i].name;
+		int num = drv->pdata->gpios[i].num;
+
+		drv->pdata->gpios[i].is_owner = false;
+
+		pr_debug("%s: get gpio %s.", __func__, name);
+
+		ret = gpio_request(num, name);
+		if (ret) {
+			pr_err("%s: request GPIO %s err %d.",
+			       __func__, name, ret);
+			goto gpio_err;
+		}
+
+		drv->pdata->gpios[i].is_owner = true;
+
+	}
+
+	for (i = 0; i < drv->pdata->regs_num; i++) {
+		const char *name = drv->pdata->regs[i].name;
+
+		drv->pdata->regs[i].reg = NULL;
+
+		pr_debug("%s: get regulator %s.", __func__, name);
+
+		drv->pdata->regs[i].reg = regulator_get(drv->dev, name);
+		if (IS_ERR(drv->pdata->regs[i].reg)) {
+			pr_err("%s: get regulator %s failed.",
+			       __func__, name);
+			goto reg_err;
+		}
+	}
+
+	drv->ppss_base = ioremap(ppss_res->start,
+				 resource_size(ppss_res));
+
+	ppss_wdog = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+						"ppss_wdog");
+	if (ppss_wdog) {
+		ret = request_irq(ppss_wdog->start, dsps_wdog_bite_irq,
+				  IRQF_TRIGGER_RISING, "dsps_wdog", NULL);
+		if (ret) {
+			pr_err("%s: request_irq fail %d\n", __func__, ret);
+			goto request_irq_err;
+		}
+	} else {
+		pr_debug("%s: ppss_wdog not supported.\n", __func__);
+	}
+
+	if (drv->pdata->init)
+		drv->pdata->init(drv->pdata);
+
+	return 0;
+
+request_irq_err:
+	iounmap(drv->ppss_base);
+
+reg_err:
+	for (i = 0; i < drv->pdata->regs_num; i++) {
+		if (drv->pdata->regs[i].reg) {
+			regulator_put(drv->pdata->regs[i].reg);
+			drv->pdata->regs[i].reg = NULL;
+		}
+	}
+
+gpio_err:
+	for (i = 0; i < drv->pdata->gpios_num; i++)
+		if (drv->pdata->gpios[i].is_owner) {
+			gpio_free(drv->pdata->gpios[i].num);
+			drv->pdata->gpios[i].is_owner = false;
+		}
+clk_err:
+	for (i = 0; i < drv->pdata->clks_num; i++)
+		if (drv->pdata->clks[i].clock) {
+			clk_put(drv->pdata->clks[i].clock);
+			drv->pdata->clks[i].clock = NULL;
+		}
+
+	return ret;
+}
+
+/**
+ * Open File.
+ *
+ */
+static int dsps_open(struct inode *ip, struct file *fp)
+{
+	int ret = 0;
+
+	pr_debug("%s.\n", __func__);
+
+	if (drv->ref_count == 0) {
+
+		/* clocks must be ON before loading.*/
+		ret = dsps_power_on_handler();
+		if (ret)
+			return ret;
+
+		ret = dsps_load(drv->pdata->pil_name);
+
+		if (ret) {
+			dsps_power_off_handler();
+			return ret;
+		}
+
+		dsps_resume();
+	}
+	drv->ref_count++;
+
+	return ret;
+}
+
+/**
+ * free resources.
+ *
+ */
+static void dsps_free_resources(void)
+{
+	int i;
+
+	pr_debug("%s.\n", __func__);
+
+	for (i = 0; i < drv->pdata->clks_num; i++)
+		if (drv->pdata->clks[i].clock) {
+			clk_put(drv->pdata->clks[i].clock);
+			drv->pdata->clks[i].clock = NULL;
+		}
+
+	for (i = 0; i < drv->pdata->gpios_num; i++)
+		if (drv->pdata->gpios[i].is_owner) {
+			gpio_free(drv->pdata->gpios[i].num);
+			drv->pdata->gpios[i].is_owner = false;
+		}
+
+	for (i = 0; i < drv->pdata->regs_num; i++) {
+		if (drv->pdata->regs[i].reg) {
+			regulator_put(drv->pdata->regs[i].reg);
+			drv->pdata->regs[i].reg = NULL;
+		}
+	}
+
+	iounmap(drv->ppss_base);
+}
+
+/**
+ * Close File.
+ *
+ * The client shall close and re-open the file for re-loading the DSPS
+ * firmware.
+ * The file system will close the file if the user space app has crashed.
+ *
+ * If the DSPS is running, then we must reset DSPS CPU & HW before
+ * setting the clocks off.
+ * The DSPS reset should be done as part of the pil_put().
+ * The DSPS reset should be used for error recovery if the DSPS firmware
+ * has crashed and re-loading the firmware is required.
+ */
+static int dsps_release(struct inode *inode, struct file *file)
+{
+	pr_debug("%s.\n", __func__);
+
+	drv->ref_count--;
+
+	if (drv->ref_count == 0) {
+		if (!drv->pdata->dsps_pwr_ctl_en) {
+			dsps_suspend();
+
+			dsps_unload();
+
+			dsps_power_off_handler();
+		}
+	}
+
+	return 0;
+}
+
+const struct file_operations dsps_fops = {
+	.owner = THIS_MODULE,
+	.open = dsps_open,
+	.release = dsps_release,
+	.unlocked_ioctl = dsps_ioctl,
+};
+
+/**
+ *  Fatal error handler
+ *  Resets DSPS.
+ */
+static void dsps_fatal_handler(struct work_struct *work)
+{
+	uint32_t dsps_state;
+
+	dsps_state = smsm_get_state(SMSM_DSPS_STATE);
+
+	pr_debug("%s: DSPS state 0x%x\n", __func__, dsps_state);
+
+	if (dsps_state & SMSM_RESET) {
+		pr_err("%s: DSPS fatal error detected. Resetting\n",
+		       __func__);
+		panic("DSPS fatal error detected.");
+	} else {
+		pr_debug("%s: User-initiated DSPS reset. Resetting\n",
+			 __func__);
+		panic("User-initiated DSPS reset.");
+	}
+}
+
+
+/**
+ *  SMSM state change callback
+ *
+ */
+static void dsps_smsm_state_cb(void *data, uint32_t old_state,
+			       uint32_t new_state)
+{
+	pr_debug("%s\n", __func__);
+	if (dsps_crash_shutdown_g == 1) {
+		pr_debug("%s: SMSM_RESET state change ignored\n",
+			 __func__);
+		dsps_crash_shutdown_g = 0;
+		return;
+	}
+
+	if (new_state & SMSM_RESET) {
+		pr_err
+		    ("%s: SMSM_RESET state detected. restarting the DSPS\n",
+		     __func__);
+		panic("SMSM_RESET state detected.");
+	}
+}
+
+/**
+ *  Shutdown function
+ * called by the restart notifier
+ *
+ */
+static int dsps_shutdown(const struct subsys_data *subsys)
+{
+	pr_debug("%s\n", __func__);
+	dsps_unload();
+	return 0;
+}
+
+/**
+ *  Powerup function
+ * called by the restart notifier
+ *
+ */
+static int dsps_powerup(const struct subsys_data *subsys)
+{
+	pr_debug("%s\n", __func__);
+	if (dsps_load(drv->pdata->pil_name) != 0) {
+		pr_err("%s: fail to restart DSPS after reboot\n",
+		       __func__);
+		return 1;
+	}
+	return 0;
+}
+
+/**
+ *  Crash shutdown function
+ * called by the restart notifier
+ *
+ */
+static void dsps_crash_shutdown(const struct subsys_data *subsys)
+{
+	pr_debug("%s\n", __func__);
+	dsps_crash_shutdown_g = 1;
+	smsm_change_state(SMSM_DSPS_STATE, SMSM_RESET, SMSM_RESET);
+}
+
+/**
+ *  Ramdump function
+ * called by the restart notifier
+ *
+ */
+static int dsps_ramdump(int enable, const struct subsys_data *subsys)
+{
+	pr_debug("%s\n", __func__);
+	return 0;
+}
+
+static struct subsys_data dsps_ssrops = {
+	.name = "dsps",
+	.shutdown = dsps_shutdown,
+	.powerup = dsps_powerup,
+	.ramdump = dsps_ramdump,
+	.crash_shutdown = dsps_crash_shutdown
+};
+
+/**
+ * platform driver
+ *
+ */
+static int __devinit dsps_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	pr_debug("%s.\n", __func__);
+
+	if (pdev->dev.platform_data == NULL) {
+		pr_err("%s: platform data is NULL.\n", __func__);
+		return -ENODEV;
+	}
+
+	drv = kzalloc(sizeof(*drv), GFP_KERNEL);
+	if (drv == NULL) {
+		pr_err("%s: kzalloc fail.\n", __func__);
+		goto alloc_err;
+	}
+	drv->pdata = pdev->dev.platform_data;
+
+	drv->dev_class = class_create(THIS_MODULE, DRV_NAME);
+	if (drv->dev_class == NULL) {
+		pr_err("%s: class_create fail.\n", __func__);
+		goto res_err;
+	}
+
+	ret = alloc_chrdev_region(&drv->dev_num, 0, 1, DRV_NAME);
+	if (ret) {
+		pr_err("%s: alloc_chrdev_region fail.\n", __func__);
+		goto alloc_chrdev_region_err;
+	}
+
+	drv->dev = device_create(drv->dev_class, NULL,
+				     drv->dev_num,
+				     drv, DRV_NAME);
+	if (IS_ERR(drv->dev)) {
+		pr_err("%s: device_create fail.\n", __func__);
+		goto device_create_err;
+	}
+
+	drv->cdev = cdev_alloc();
+	if (drv->cdev == NULL) {
+		pr_err("%s: cdev_alloc fail.\n", __func__);
+		goto cdev_alloc_err;
+	}
+	cdev_init(drv->cdev, &dsps_fops);
+	drv->cdev->owner = THIS_MODULE;
+
+	ret = cdev_add(drv->cdev, drv->dev_num, 1);
+	if (ret) {
+		pr_err("%s: cdev_add fail.\n", __func__);
+		goto cdev_add_err;
+	}
+
+	ret = dsps_alloc_resources(pdev);
+	if (ret) {
+		pr_err("%s: failed to allocate dsps resources.\n", __func__);
+		goto cdev_add_err;
+	}
+
+	ret =
+	    smsm_state_cb_register(SMSM_DSPS_STATE, SMSM_RESET,
+				   dsps_smsm_state_cb, 0);
+	if (ret) {
+		pr_err("%s: smsm_state_cb_register fail %d\n", __func__,
+		       ret);
+		goto smsm_register_err;
+	}
+
+	ret = ssr_register_subsystem(&dsps_ssrops);
+	if (ret) {
+		pr_err("%s: ssr_register_subsystem fail %d\n", __func__,
+		       ret);
+		goto ssr_register_err;
+	}
+
+	return 0;
+
+ssr_register_err:
+	smsm_state_cb_deregister(SMSM_DSPS_STATE, SMSM_RESET,
+				 dsps_smsm_state_cb,
+				 0);
+smsm_register_err:
+	cdev_del(drv->cdev);
+cdev_add_err:
+	kfree(drv->cdev);
+cdev_alloc_err:
+	device_destroy(drv->dev_class, drv->dev_num);
+device_create_err:
+	unregister_chrdev_region(drv->dev_num, 1);
+alloc_chrdev_region_err:
+	class_destroy(drv->dev_class);
+res_err:
+	kfree(drv);
+	drv = NULL;
+alloc_err:
+	return -ENODEV;
+}
+
+static int __devexit dsps_remove(struct platform_device *pdev)
+{
+	pr_debug("%s.\n", __func__);
+
+	dsps_power_off_handler();
+	dsps_free_resources();
+
+	cdev_del(drv->cdev);
+	kfree(drv->cdev);
+	drv->cdev = NULL;
+	device_destroy(drv->dev_class, drv->dev_num);
+	unregister_chrdev_region(drv->dev_num, 1);
+	class_destroy(drv->dev_class);
+	kfree(drv);
+	drv = NULL;
+
+	return 0;
+}
+
+static struct platform_driver dsps_driver = {
+	.probe          = dsps_probe,
+	.remove         = __exit_p(dsps_remove),
+	.driver         = {
+		.name   = "msm_dsps",
+	},
+};
+
+/**
+ * Module Init.
+ */
+static int __init dsps_init(void)
+{
+	int ret;
+
+	pr_info("%s driver version %s.\n", DRV_NAME, DRV_VERSION);
+
+	ret = platform_driver_register(&dsps_driver);
+
+	if (ret)
+		pr_err("dsps_init.err=%d.\n", ret);
+
+	return ret;
+}
+
+/**
+ * Module Exit.
+ */
+static void __exit dsps_exit(void)
+{
+	pr_debug("%s.\n", __func__);
+
+	platform_driver_unregister(&dsps_driver);
+}
+
+module_init(dsps_init);
+module_exit(dsps_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Dedicated Sensors Processor Subsystem (DSPS) driver");
+MODULE_AUTHOR("Amir Samuelov <amirs@codeaurora.org>");
+
diff --git a/arch/arm/mach-msm/msm_fault_handlers.c b/arch/arm/mach-msm/msm_fault_handlers.c
new file mode 100644
index 0000000..c975856
--- /dev/null
+++ b/arch/arm/mach-msm/msm_fault_handlers.c
@@ -0,0 +1,84 @@
+/*
+ *  Copyright (C) 1995  Linus Torvalds
+ *  Modifications for ARM processor (c) 1995-2004 Russell King
+ *  Copyright (c) 2010, 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 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/signal.h>
+#include <linux/cpumask.h>
+#include "acpuclock.h"
+
+#define __str(x) #x
+#define MRC(x, v1, v2, v4, v5, v6) do {					\
+	unsigned int __##x;						\
+	asm("mrc " __str(v1) ", " __str(v2) ", %0, " __str(v4) ", "	\
+		__str(v5) ", " __str(v6) "\n" \
+		: "=r" (__##x));					\
+	pr_info("%s: %s = 0x%.8x\n", __func__, #x, __##x);		\
+} while (0)
+
+static int msm_imp_ext_abort(unsigned long addr, unsigned int fsr,
+			     struct pt_regs *regs)
+{
+	int cpu;
+	unsigned int regval;
+	static unsigned char flush_toggle;
+
+	asm("mrc p15, 7, %0, c15, c0, 1\n" /* read EFSR for fault status */
+	    : "=r" (regval));
+	if (regval == 0x2) {
+		/* Fault was caused by icache parity error. Alternate
+		 * simply retrying the access and flushing the icache. */
+		flush_toggle ^= 1;
+		if (flush_toggle)
+			asm("mcr p15, 0, %0, c7, c5, 0\n"
+				:
+				: "r" (regval)); /* input value is ignored */
+		/* Clear fault in EFSR. */
+		asm("mcr p15, 7, %0, c15, c0, 1\n"
+			:
+			: "r" (regval));
+		/* Clear fault in ADFSR. */
+		regval = 0;
+		asm("mcr p15, 0, %0, c5, c1, 0\n"
+			:
+			: "r" (regval));
+		return 0;
+	}
+
+	MRC(ADFSR,    p15, 0,  c5, c1, 0);
+	MRC(DFSR,     p15, 0,  c5, c0, 0);
+	MRC(ACTLR,    p15, 0,  c1, c0, 1);
+	MRC(EFSR,     p15, 7, c15, c0, 1);
+	MRC(L2SR,     p15, 3, c15, c1, 0);
+	MRC(L2CR0,    p15, 3, c15, c0, 1);
+	MRC(L2CPUESR, p15, 3, c15, c1, 1);
+	MRC(L2CPUCR,  p15, 3, c15, c0, 2);
+	MRC(SPESR,    p15, 1,  c9, c7, 0);
+	MRC(SPCR,     p15, 0,  c9, c7, 0);
+	MRC(DMACHSR,  p15, 1, c11, c0, 0);
+	MRC(DMACHESR, p15, 1, c11, c0, 1);
+	MRC(DMACHCR,  p15, 0, c11, c0, 2);
+	for_each_online_cpu(cpu)
+		pr_info("cpu %d, acpuclk rate: %lu kHz\n", cpu,
+			acpuclk_get_rate(cpu));
+
+	return 1;
+}
+
+static int __init msm_register_fault_handlers(void)
+{
+	/* hook in our handler for imprecise abort for when we get
+	   i-cache parity errors */
+	hook_fault_code(22, msm_imp_ext_abort, SIGBUS, 0,
+			"imprecise external abort");
+
+	return 0;
+}
+arch_initcall(msm_register_fault_handlers);
diff --git a/arch/arm/mach-msm/msm_kexec.c b/arch/arm/mach-msm/msm_kexec.c
new file mode 100644
index 0000000..4597cf0
--- /dev/null
+++ b/arch/arm/mach-msm/msm_kexec.c
@@ -0,0 +1,30 @@
+/* Copyright (c) 2010, 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/kexec.h>
+#include <linux/io.h>
+
+#ifdef CONFIG_MSM_WATCHDOG
+#include <mach/msm_iomap.h>
+
+#define WDT0_EN        (MSM_TMR_BASE + 0x40)
+#endif
+
+void arch_kexec(void)
+{
+#ifdef CONFIG_MSM_WATCHDOG
+	/* Prevent watchdog from resetting SoC */
+	writel(0, WDT0_EN);
+	pr_crit("KEXEC: MSM Watchdog Exit - Deactivated\n");
+#endif
+	return;
+}
diff --git a/arch/arm/mach-msm/msm_rq_stats.c b/arch/arm/mach-msm/msm_rq_stats.c
new file mode 100644
index 0000000..738819f
--- /dev/null
+++ b/arch/arm/mach-msm/msm_rq_stats.c
@@ -0,0 +1,220 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+/*
+ * Qualcomm MSM Runqueue Stats Interface for Userspace
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/hrtimer.h>
+#include <linux/cpu.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+#include <linux/notifier.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/rq_stats.h>
+#include <asm/smp_plat.h>
+
+#define MAX_LONG_SIZE 24
+#define DEFAULT_RQ_POLL_JIFFIES 1
+#define DEFAULT_DEF_TIMER_JIFFIES 5
+
+static void def_work_fn(struct work_struct *work)
+{
+	int64_t diff;
+
+	diff = ktime_to_ns(ktime_get()) - rq_info.def_start_time;
+	do_div(diff, 1000 * 1000);
+	rq_info.def_interval = (unsigned int) diff;
+
+	/* Notify polling threads on change of value */
+	sysfs_notify(rq_info.kobj, NULL, "def_timer_ms");
+}
+
+static ssize_t show_run_queue_avg(struct kobject *kobj,
+		struct kobj_attribute *attr, char *buf)
+{
+	unsigned int val = 0;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&rq_lock, flags);
+	/* rq avg currently available only on one core */
+	val = rq_info.rq_avg;
+	rq_info.rq_avg = 0;
+	spin_unlock_irqrestore(&rq_lock, flags);
+
+	return snprintf(buf, PAGE_SIZE, "%d.%d\n", val/10, val%10);
+}
+
+static ssize_t show_run_queue_poll_ms(struct kobject *kobj,
+				      struct kobj_attribute *attr, char *buf)
+{
+	int ret = 0;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&rq_lock, flags);
+	ret = snprintf(buf, MAX_LONG_SIZE, "%u\n",
+		       jiffies_to_msecs(rq_info.rq_poll_jiffies));
+	spin_unlock_irqrestore(&rq_lock, flags);
+
+	return ret;
+}
+
+static ssize_t store_run_queue_poll_ms(struct kobject *kobj,
+				       struct kobj_attribute *attr,
+				       const char *buf, size_t count)
+{
+	unsigned int val = 0;
+	unsigned long flags = 0;
+	static DEFINE_MUTEX(lock_poll_ms);
+
+	mutex_lock(&lock_poll_ms);
+
+	spin_lock_irqsave(&rq_lock, flags);
+	sscanf(buf, "%u", &val);
+	rq_info.rq_poll_jiffies = msecs_to_jiffies(val);
+	spin_unlock_irqrestore(&rq_lock, flags);
+
+	mutex_unlock(&lock_poll_ms);
+
+	return count;
+}
+
+static ssize_t show_def_timer_ms(struct kobject *kobj,
+		struct kobj_attribute *attr, char *buf)
+{
+	return snprintf(buf, MAX_LONG_SIZE, "%u\n", rq_info.def_interval);
+}
+
+static ssize_t store_def_timer_ms(struct kobject *kobj,
+		struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	unsigned int val = 0;
+
+	sscanf(buf, "%u", &val);
+	rq_info.def_timer_jiffies = msecs_to_jiffies(val);
+
+	rq_info.def_start_time = ktime_to_ns(ktime_get());
+	return count;
+}
+
+#define MSM_RQ_STATS_RO_ATTRIB(att) ({ \
+		struct attribute *attrib = NULL; \
+		struct kobj_attribute *ptr = NULL; \
+		ptr = kzalloc(sizeof(struct kobj_attribute), GFP_KERNEL); \
+		if (ptr) { \
+			ptr->attr.name = #att; \
+			ptr->attr.mode = S_IRUGO; \
+			ptr->show = show_##att; \
+			ptr->store = NULL; \
+			attrib = &ptr->attr; \
+		} \
+		attrib; })
+
+#define MSM_RQ_STATS_RW_ATTRIB(att) ({ \
+		struct attribute *attrib = NULL; \
+		struct kobj_attribute *ptr = NULL; \
+		ptr = kzalloc(sizeof(struct kobj_attribute), GFP_KERNEL); \
+		if (ptr) { \
+			ptr->attr.name = #att; \
+			ptr->attr.mode = S_IWUSR|S_IRUSR; \
+			ptr->show = show_##att; \
+			ptr->store = store_##att; \
+			attrib = &ptr->attr; \
+		} \
+		attrib; })
+
+static int init_rq_attribs(void)
+{
+	int i;
+	int err = 0;
+	const int attr_count = 4;
+
+	struct attribute **attribs =
+		kzalloc(sizeof(struct attribute *) * attr_count, GFP_KERNEL);
+
+	if (!attribs)
+		goto rel;
+
+	rq_info.rq_avg = 0;
+
+	attribs[0] = MSM_RQ_STATS_RW_ATTRIB(def_timer_ms);
+	attribs[1] = MSM_RQ_STATS_RO_ATTRIB(run_queue_avg);
+	attribs[2] = MSM_RQ_STATS_RW_ATTRIB(run_queue_poll_ms);
+	attribs[3] = NULL;
+
+	for (i = 0; i < attr_count - 1 ; i++) {
+		if (!attribs[i])
+			goto rel2;
+	}
+
+	rq_info.attr_group = kzalloc(sizeof(struct attribute_group),
+						GFP_KERNEL);
+	if (!rq_info.attr_group)
+		goto rel3;
+	rq_info.attr_group->attrs = attribs;
+
+	/* Create /sys/devices/system/cpu/cpu0/rq-stats/... */
+	rq_info.kobj = kobject_create_and_add("rq-stats",
+	&get_cpu_device(0)->kobj);
+	if (!rq_info.kobj)
+		goto rel3;
+
+	err = sysfs_create_group(rq_info.kobj, rq_info.attr_group);
+	if (err)
+		kobject_put(rq_info.kobj);
+	else
+		kobject_uevent(rq_info.kobj, KOBJ_ADD);
+
+	if (!err)
+		return err;
+
+rel3:
+	kfree(rq_info.attr_group);
+	kfree(rq_info.kobj);
+rel2:
+	for (i = 0; i < attr_count - 1; i++)
+		kfree(attribs[i]);
+rel:
+	kfree(attribs);
+
+	return -ENOMEM;
+}
+
+static int __init msm_rq_stats_init(void)
+{
+	int ret;
+
+	/* Bail out if this is not an SMP Target */
+	if (!is_smp()) {
+		rq_info.init = 0;
+		return -ENOSYS;
+	}
+
+	rq_wq = create_singlethread_workqueue("rq_stats");
+	BUG_ON(!rq_wq);
+	INIT_WORK(&rq_info.def_timer_work, def_work_fn);
+	spin_lock_init(&rq_lock);
+	rq_info.rq_poll_jiffies = DEFAULT_RQ_POLL_JIFFIES;
+	rq_info.def_timer_jiffies = DEFAULT_DEF_TIMER_JIFFIES;
+	rq_info.rq_poll_last_jiffy = 0;
+	rq_info.def_timer_last_jiffy = 0;
+	ret = init_rq_attribs();
+
+	rq_info.init = 1;
+	return ret;
+}
+late_initcall(msm_rq_stats_init);
diff --git a/arch/arm/mach-msm/msm_rtb.c b/arch/arm/mach-msm/msm_rtb.c
new file mode 100644
index 0000000..9dbf9c1
--- /dev/null
+++ b/arch/arm/mach-msm/msm_rtb.c
@@ -0,0 +1,295 @@
+/*
+ * 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/atomic.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/memory_alloc.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/atomic.h>
+#include <asm/io.h>
+#include <asm-generic/sizes.h>
+#include <mach/memory.h>
+#include <mach/msm_rtb.h>
+#include <mach/system.h>
+
+#define SENTINEL_BYTE_1 0xFF
+#define SENTINEL_BYTE_2 0xAA
+#define SENTINEL_BYTE_3 0xFF
+
+/* Write
+ * 1) 3 bytes sentinel
+ * 2) 1 bytes of log type
+ * 3) 4 bytes of where the caller came from
+ * 4) 4 bytes index
+ * 4) 4 bytes extra data from the caller
+ *
+ * Total = 16 bytes.
+ */
+struct msm_rtb_layout {
+	unsigned char sentinel[3];
+	unsigned char log_type;
+	void *caller;
+	unsigned long idx;
+	void *data;
+} __attribute__ ((__packed__));
+
+
+struct msm_rtb_state {
+	struct msm_rtb_layout *rtb;
+	unsigned long phys;
+	int nentries;
+	int size;
+	int enabled;
+	int initialized;
+	uint32_t filter;
+	int step_size;
+};
+
+#if defined(CONFIG_MSM_RTB_SEPARATE_CPUS)
+DEFINE_PER_CPU(atomic_t, msm_rtb_idx_cpu);
+#else
+static atomic_t msm_rtb_idx;
+#endif
+
+struct msm_rtb_state msm_rtb = {
+	.filter = 1 << LOGK_LOGBUF,
+	.enabled = 1,
+};
+
+module_param_named(filter, msm_rtb.filter, uint, 0644);
+module_param_named(enable, msm_rtb.enabled, int, 0644);
+
+static int msm_rtb_panic_notifier(struct notifier_block *this,
+					unsigned long event, void *ptr)
+{
+	msm_rtb.enabled = 0;
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block msm_rtb_panic_blk = {
+	.notifier_call  = msm_rtb_panic_notifier,
+};
+
+int msm_rtb_event_should_log(enum logk_event_type log_type)
+{
+	return msm_rtb.initialized && msm_rtb.enabled &&
+		((1 << (log_type & ~LOGTYPE_NOPC)) & msm_rtb.filter);
+}
+EXPORT_SYMBOL(msm_rtb_event_should_log);
+
+static void msm_rtb_emit_sentinel(struct msm_rtb_layout *start)
+{
+	start->sentinel[0] = SENTINEL_BYTE_1;
+	start->sentinel[1] = SENTINEL_BYTE_2;
+	start->sentinel[2] = SENTINEL_BYTE_3;
+}
+
+static void msm_rtb_write_type(enum logk_event_type log_type,
+			struct msm_rtb_layout *start)
+{
+	start->log_type = (char)log_type;
+}
+
+static void msm_rtb_write_caller(void *caller, struct msm_rtb_layout *start)
+{
+	start->caller = caller;
+}
+
+static void msm_rtb_write_idx(unsigned long idx,
+				struct msm_rtb_layout *start)
+{
+	start->idx = idx;
+}
+
+static void msm_rtb_write_data(void *data, struct msm_rtb_layout *start)
+{
+	start->data = data;
+}
+
+static void uncached_logk_pc_idx(enum logk_event_type log_type, void *caller,
+				 void *data, int idx)
+{
+	struct msm_rtb_layout *start;
+
+	start = &msm_rtb.rtb[idx & (msm_rtb.nentries - 1)];
+
+	msm_rtb_emit_sentinel(start);
+	msm_rtb_write_type(log_type, start);
+	msm_rtb_write_caller(caller, start);
+	msm_rtb_write_idx(idx, start);
+	msm_rtb_write_data(data, start);
+	mb();
+
+	return;
+}
+
+static void uncached_logk_timestamp(int idx)
+{
+	unsigned long long timestamp;
+	void *timestamp_upper, *timestamp_lower;
+	timestamp = sched_clock();
+	timestamp_lower = (void *)lower_32_bits(timestamp);
+	timestamp_upper = (void *)upper_32_bits(timestamp);
+
+	uncached_logk_pc_idx(LOGK_TIMESTAMP|LOGTYPE_NOPC, timestamp_lower,
+			     timestamp_upper, idx);
+}
+
+#if defined(CONFIG_MSM_RTB_SEPARATE_CPUS)
+static int msm_rtb_get_idx(void)
+{
+	int cpu, i, offset;
+	atomic_t *index;
+
+	/*
+	 * ideally we would use get_cpu but this is a close enough
+	 * approximation for our purposes.
+	 */
+	cpu = raw_smp_processor_id();
+
+	index = &per_cpu(msm_rtb_idx_cpu, cpu);
+
+	i = atomic_add_return(msm_rtb.step_size, index);
+	i -= msm_rtb.step_size;
+
+	/* Check if index has wrapped around */
+	offset = (i & (msm_rtb.nentries - 1)) -
+		 ((i - msm_rtb.step_size) & (msm_rtb.nentries - 1));
+	if (offset < 0) {
+		uncached_logk_timestamp(i);
+		i = atomic_add_return(msm_rtb.step_size, index);
+		i -= msm_rtb.step_size;
+	}
+
+	return i;
+}
+#else
+static int msm_rtb_get_idx(void)
+{
+	int i, offset;
+
+	i = atomic_inc_return(&msm_rtb_idx);
+	i--;
+
+	/* Check if index has wrapped around */
+	offset = (i & (msm_rtb.nentries - 1)) -
+		 ((i - 1) & (msm_rtb.nentries - 1));
+	if (offset < 0) {
+		uncached_logk_timestamp(i);
+		i = atomic_inc_return(&msm_rtb_idx);
+		i--;
+	}
+
+	return i;
+}
+#endif
+
+int uncached_logk_pc(enum logk_event_type log_type, void *caller,
+				void *data)
+{
+	int i;
+
+	if (!msm_rtb_event_should_log(log_type))
+		return 0;
+
+	i = msm_rtb_get_idx();
+
+	uncached_logk_pc_idx(log_type, caller, data, i);
+
+	return 1;
+}
+EXPORT_SYMBOL(uncached_logk_pc);
+
+noinline int uncached_logk(enum logk_event_type log_type, void *data)
+{
+	return uncached_logk_pc(log_type, __builtin_return_address(0), data);
+}
+EXPORT_SYMBOL(uncached_logk);
+
+int msm_rtb_probe(struct platform_device *pdev)
+{
+	struct msm_rtb_platform_data *d = pdev->dev.platform_data;
+#if defined(CONFIG_MSM_RTB_SEPARATE_CPUS)
+	unsigned int cpu;
+#endif
+
+	msm_rtb.size = d->size;
+
+	if (msm_rtb.size <= 0 || msm_rtb.size > SZ_1M)
+		return -EINVAL;
+
+	/*
+	 * The ioremap call is made separately to store the physical
+	 * address of the buffer. This is necessary for cases where
+	 * the only way to access the buffer is a physical address.
+	 */
+	msm_rtb.phys = allocate_contiguous_ebi_nomap(msm_rtb.size, SZ_4K);
+
+	if (!msm_rtb.phys)
+		return -ENOMEM;
+
+	msm_rtb.rtb = ioremap(msm_rtb.phys, msm_rtb.size);
+
+	if (!msm_rtb.rtb) {
+		free_contiguous_memory_by_paddr(msm_rtb.phys);
+		return -ENOMEM;
+	}
+
+	msm_rtb.nentries = msm_rtb.size / sizeof(struct msm_rtb_layout);
+
+	/* Round this down to a power of 2 */
+	msm_rtb.nentries = __rounddown_pow_of_two(msm_rtb.nentries);
+
+	memset(msm_rtb.rtb, 0, msm_rtb.size);
+
+
+#if defined(CONFIG_MSM_RTB_SEPARATE_CPUS)
+	for_each_possible_cpu(cpu) {
+		atomic_t *a = &per_cpu(msm_rtb_idx_cpu, cpu);
+		atomic_set(a, cpu);
+	}
+	msm_rtb.step_size = num_possible_cpus();
+#else
+	atomic_set(&msm_rtb_idx, 0);
+	msm_rtb.step_size = 1;
+#endif
+
+	atomic_notifier_chain_register(&panic_notifier_list,
+						&msm_rtb_panic_blk);
+	msm_rtb.initialized = 1;
+	return 0;
+}
+
+static struct platform_driver msm_rtb_driver = {
+	.driver         = {
+		.name = "msm_rtb",
+		.owner = THIS_MODULE
+	},
+};
+
+static int __init msm_rtb_init(void)
+{
+	return platform_driver_probe(&msm_rtb_driver, msm_rtb_probe);
+}
+
+static void __exit msm_rtb_exit(void)
+{
+	platform_driver_unregister(&msm_rtb_driver);
+}
+module_init(msm_rtb_init)
+module_exit(msm_rtb_exit)
diff --git a/arch/arm/mach-msm/msm_show_resume_irq.c b/arch/arm/mach-msm/msm_show_resume_irq.c
new file mode 100644
index 0000000..8209367
--- /dev/null
+++ b/arch/arm/mach-msm/msm_show_resume_irq.c
@@ -0,0 +1,22 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+int msm_show_resume_irq_mask;
+
+module_param_named(
+	debug_mask, msm_show_resume_irq_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
+);
diff --git a/arch/arm/mach-msm/msm_vibrator.c b/arch/arm/mach-msm/msm_vibrator.c
new file mode 100644
index 0000000..5595ba0
--- /dev/null
+++ b/arch/arm/mach-msm/msm_vibrator.c
@@ -0,0 +1,162 @@
+/* include/asm/mach-msm/htc_pwrsink.h
+ *
+ * Copyright (C) 2008 HTC Corporation.
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2011 Code Aurora Forum. 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.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/hrtimer.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include "pmic.h"
+#include "timed_output.h"
+
+#include <mach/msm_rpcrouter.h>
+
+#define PM_LIBPROG      0x30000061
+#if (CONFIG_MSM_AMSS_VERSION == 6220) || (CONFIG_MSM_AMSS_VERSION == 6225)
+#define PM_LIBVERS      0xfb837d0b
+#else
+#define PM_LIBVERS      0x10001
+#endif
+
+#define HTC_PROCEDURE_SET_VIB_ON_OFF	21
+#define PMIC_VIBRATOR_LEVEL	(3000)
+
+static struct work_struct work_vibrator_on;
+static struct work_struct work_vibrator_off;
+static struct hrtimer vibe_timer;
+
+#ifdef CONFIG_PM8XXX_RPC_VIBRATOR
+static void set_pmic_vibrator(int on)
+{
+	int rc;
+
+	rc = pmic_vib_mot_set_mode(PM_VIB_MOT_MODE__MANUAL);
+	if (rc) {
+		pr_err("%s: Vibrator set mode failed", __func__);
+		return;
+	}
+
+	if (on)
+		rc = pmic_vib_mot_set_volt(PMIC_VIBRATOR_LEVEL);
+	else
+		rc = pmic_vib_mot_set_volt(0);
+
+	if (rc)
+		pr_err("%s: Vibrator set voltage level failed", __func__);
+}
+#else
+static void set_pmic_vibrator(int on)
+{
+	static struct msm_rpc_endpoint *vib_endpoint;
+	struct set_vib_on_off_req {
+		struct rpc_request_hdr hdr;
+		uint32_t data;
+	} req;
+
+	if (!vib_endpoint) {
+		vib_endpoint = msm_rpc_connect(PM_LIBPROG, PM_LIBVERS, 0);
+		if (IS_ERR(vib_endpoint)) {
+			printk(KERN_ERR "init vib rpc failed!\n");
+			vib_endpoint = 0;
+			return;
+		}
+	}
+
+
+	if (on)
+		req.data = cpu_to_be32(PMIC_VIBRATOR_LEVEL);
+	else
+		req.data = cpu_to_be32(0);
+
+	msm_rpc_call(vib_endpoint, HTC_PROCEDURE_SET_VIB_ON_OFF, &req,
+		sizeof(req), 5 * HZ);
+}
+#endif
+
+static void pmic_vibrator_on(struct work_struct *work)
+{
+	set_pmic_vibrator(1);
+}
+
+static void pmic_vibrator_off(struct work_struct *work)
+{
+	set_pmic_vibrator(0);
+}
+
+static void timed_vibrator_on(struct timed_output_dev *sdev)
+{
+	schedule_work(&work_vibrator_on);
+}
+
+static void timed_vibrator_off(struct timed_output_dev *sdev)
+{
+	schedule_work(&work_vibrator_off);
+}
+
+static void vibrator_enable(struct timed_output_dev *dev, int value)
+{
+	hrtimer_cancel(&vibe_timer);
+
+	if (value == 0)
+		timed_vibrator_off(dev);
+	else {
+		value = (value > 15000 ? 15000 : value);
+
+		timed_vibrator_on(dev);
+
+		hrtimer_start(&vibe_timer,
+			      ktime_set(value / 1000, (value % 1000) * 1000000),
+			      HRTIMER_MODE_REL);
+	}
+}
+
+static int vibrator_get_time(struct timed_output_dev *dev)
+{
+	if (hrtimer_active(&vibe_timer)) {
+		ktime_t r = hrtimer_get_remaining(&vibe_timer);
+		struct timeval t = ktime_to_timeval(r);
+		return t.tv_sec * 1000 + t.tv_usec / 1000;
+	}
+	return 0;
+}
+
+static enum hrtimer_restart vibrator_timer_func(struct hrtimer *timer)
+{
+	timed_vibrator_off(NULL);
+	return HRTIMER_NORESTART;
+}
+
+static struct timed_output_dev pmic_vibrator = {
+	.name = "vibrator",
+	.get_time = vibrator_get_time,
+	.enable = vibrator_enable,
+};
+
+void __init msm_init_pmic_vibrator(void)
+{
+	INIT_WORK(&work_vibrator_on, pmic_vibrator_on);
+	INIT_WORK(&work_vibrator_off, pmic_vibrator_off);
+
+	hrtimer_init(&vibe_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	vibe_timer.function = vibrator_timer_func;
+
+	timed_output_dev_register(&pmic_vibrator);
+}
+
+MODULE_DESCRIPTION("timed output pmic vibrator device");
+MODULE_LICENSE("GPL");
+
diff --git a/arch/arm/mach-msm/msm_watchdog.c b/arch/arm/mach-msm/msm_watchdog.c
new file mode 100644
index 0000000..2cff7f0
--- /dev/null
+++ b/arch/arm/mach-msm/msm_watchdog.c
@@ -0,0 +1,464 @@
+/* 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
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/pm.h>
+#include <linux/mfd/pmic8058.h>
+#include <linux/jiffies.h>
+#include <linux/suspend.h>
+#include <linux/percpu.h>
+#include <linux/interrupt.h>
+#include <asm/fiq.h>
+#include <asm/hardware/gic.h>
+#include <mach/msm_iomap.h>
+#include <asm/mach-types.h>
+#include <mach/scm.h>
+#include <mach/socinfo.h>
+#include "msm_watchdog.h"
+#include "timer.h"
+
+#define MODULE_NAME "msm_watchdog"
+
+#define TCSR_WDT_CFG	0x30
+
+#define WDT0_RST	0x38
+#define WDT0_EN		0x40
+#define WDT0_STS	0x44
+#define WDT0_BARK_TIME	0x4C
+#define WDT0_BITE_TIME	0x5C
+
+#define WDT_HZ		32768
+
+struct msm_watchdog_dump msm_dump_cpu_ctx;
+
+static void __iomem *msm_tmr0_base;
+
+static unsigned long delay_time;
+static unsigned long bark_time;
+static unsigned long long last_pet;
+static bool has_vic;
+
+/*
+ * On the kernel command line specify
+ * msm_watchdog.enable=1 to enable the watchdog
+ * By default watchdog is turned on
+ */
+static int enable = 1;
+module_param(enable, int, 0);
+
+/*
+ * If the watchdog is enabled at bootup (enable=1),
+ * the runtime_disable sysfs node at
+ * /sys/module/msm_watchdog/runtime_disable
+ * can be used to deactivate the watchdog.
+ * This is a one-time setting. The watchdog
+ * cannot be re-enabled once it is disabled.
+ */
+static int runtime_disable;
+static DEFINE_MUTEX(disable_lock);
+static int wdog_enable_set(const char *val, struct kernel_param *kp);
+module_param_call(runtime_disable, wdog_enable_set, param_get_int,
+			&runtime_disable, 0644);
+
+/*
+ * On the kernel command line specify msm_watchdog.appsbark=1 to handle
+ * watchdog barks in Linux. By default barks are processed by the secure side.
+ */
+static int appsbark;
+module_param(appsbark, int, 0);
+
+static int appsbark_fiq;
+
+/*
+ * Use /sys/module/msm_watchdog/parameters/print_all_stacks
+ * to control whether stacks of all running
+ * processes are printed when a wdog bark is received.
+ */
+static int print_all_stacks = 1;
+module_param(print_all_stacks, int,  S_IRUGO | S_IWUSR);
+
+/* Area for context dump in secure mode */
+static void *scm_regsave;
+
+static struct msm_watchdog_pdata __percpu **percpu_pdata;
+
+static void pet_watchdog_work(struct work_struct *work);
+static void init_watchdog_work(struct work_struct *work);
+static DECLARE_DELAYED_WORK(dogwork_struct, pet_watchdog_work);
+static DECLARE_WORK(init_dogwork_struct, init_watchdog_work);
+
+/* Called from the FIQ bark handler */
+void msm_wdog_bark_fin(void)
+{
+	pr_crit("\nApps Watchdog bark received - Calling Panic\n");
+	panic("Apps Watchdog Bark received\n");
+}
+
+static int msm_watchdog_suspend(struct device *dev)
+{
+	if (!enable)
+		return 0;
+
+	__raw_writel(1, msm_tmr0_base + WDT0_RST);
+	__raw_writel(0, msm_tmr0_base + WDT0_EN);
+	mb();
+	return 0;
+}
+
+static int msm_watchdog_resume(struct device *dev)
+{
+	if (!enable)
+		return 0;
+
+	__raw_writel(1, msm_tmr0_base + WDT0_EN);
+	__raw_writel(1, msm_tmr0_base + WDT0_RST);
+	mb();
+	return 0;
+}
+
+static int panic_wdog_handler(struct notifier_block *this,
+			      unsigned long event, void *ptr)
+{
+	if (panic_timeout == 0) {
+		__raw_writel(0, msm_tmr0_base + WDT0_EN);
+		mb();
+	} else {
+		__raw_writel(WDT_HZ * (panic_timeout + 4),
+				msm_tmr0_base + WDT0_BARK_TIME);
+		__raw_writel(WDT_HZ * (panic_timeout + 4),
+				msm_tmr0_base + WDT0_BITE_TIME);
+		__raw_writel(1, msm_tmr0_base + WDT0_RST);
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block panic_blk = {
+	.notifier_call	= panic_wdog_handler,
+};
+
+struct wdog_disable_work_data {
+	struct work_struct work;
+	struct completion complete;
+};
+
+static void wdog_disable_work(struct work_struct *work)
+{
+	struct wdog_disable_work_data *work_data =
+		container_of(work, struct wdog_disable_work_data, work);
+	__raw_writel(0, msm_tmr0_base + WDT0_EN);
+	mb();
+	if (has_vic) {
+		free_irq(WDT0_ACCSCSSNBARK_INT, 0);
+	} else {
+		disable_percpu_irq(WDT0_ACCSCSSNBARK_INT);
+		if (!appsbark_fiq) {
+			free_percpu_irq(WDT0_ACCSCSSNBARK_INT,
+					percpu_pdata);
+			free_percpu(percpu_pdata);
+		}
+	}
+	enable = 0;
+	atomic_notifier_chain_unregister(&panic_notifier_list, &panic_blk);
+	cancel_delayed_work(&dogwork_struct);
+	/* may be suspended after the first write above */
+	__raw_writel(0, msm_tmr0_base + WDT0_EN);
+	complete(&work_data->complete);
+	pr_info("MSM Watchdog deactivated.\n");
+}
+
+static int wdog_enable_set(const char *val, struct kernel_param *kp)
+{
+	int ret = 0;
+	int old_val = runtime_disable;
+	struct wdog_disable_work_data work_data;
+
+	mutex_lock(&disable_lock);
+	if (!enable) {
+		printk(KERN_INFO "MSM Watchdog is not active.\n");
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ret = param_set_int(val, kp);
+	if (ret)
+		goto done;
+
+	if (runtime_disable == 1) {
+		if (old_val)
+			goto done;
+		init_completion(&work_data.complete);
+		INIT_WORK_ONSTACK(&work_data.work, wdog_disable_work);
+		schedule_work_on(0, &work_data.work);
+		wait_for_completion(&work_data.complete);
+	} else {
+		runtime_disable = old_val;
+		ret = -EINVAL;
+	}
+done:
+	mutex_unlock(&disable_lock);
+	return ret;
+}
+
+unsigned min_slack_ticks = UINT_MAX;
+unsigned long long min_slack_ns = ULLONG_MAX;
+
+void pet_watchdog(void)
+{
+	int slack;
+	unsigned long long time_ns;
+	unsigned long long slack_ns;
+	unsigned long long bark_time_ns = bark_time * 1000000ULL;
+
+	if (!enable)
+		return;
+
+	slack = __raw_readl(msm_tmr0_base + WDT0_STS) >> 3;
+	slack = ((bark_time*WDT_HZ)/1000) - slack;
+	if (slack < min_slack_ticks)
+		min_slack_ticks = slack;
+	__raw_writel(1, msm_tmr0_base + WDT0_RST);
+	time_ns = sched_clock();
+	slack_ns = (last_pet + bark_time_ns) - time_ns;
+	if (slack_ns < min_slack_ns)
+		min_slack_ns = slack_ns;
+	last_pet = time_ns;
+}
+
+static void pet_watchdog_work(struct work_struct *work)
+{
+	pet_watchdog();
+
+	if (enable)
+		schedule_delayed_work_on(0, &dogwork_struct, delay_time);
+}
+
+static int msm_watchdog_remove(struct platform_device *pdev)
+{
+	if (enable) {
+		__raw_writel(0, msm_tmr0_base + WDT0_EN);
+		mb();
+		if (has_vic) {
+			free_irq(WDT0_ACCSCSSNBARK_INT, 0);
+		} else {
+			disable_percpu_irq(WDT0_ACCSCSSNBARK_INT);
+			if (!appsbark_fiq) {
+				free_percpu_irq(WDT0_ACCSCSSNBARK_INT,
+						percpu_pdata);
+				free_percpu(percpu_pdata);
+			}
+		}
+		enable = 0;
+		/* In case we got suspended mid-exit */
+		__raw_writel(0, msm_tmr0_base + WDT0_EN);
+	}
+	printk(KERN_INFO "MSM Watchdog Exit - Deactivated\n");
+	return 0;
+}
+
+static irqreturn_t wdog_bark_handler(int irq, void *dev_id)
+{
+	unsigned long nanosec_rem;
+	unsigned long long t = sched_clock();
+	struct task_struct *tsk;
+
+	nanosec_rem = do_div(t, 1000000000);
+	printk(KERN_INFO "Watchdog bark! Now = %lu.%06lu\n", (unsigned long) t,
+		nanosec_rem / 1000);
+
+	nanosec_rem = do_div(last_pet, 1000000000);
+	printk(KERN_INFO "Watchdog last pet at %lu.%06lu\n", (unsigned long)
+		last_pet, nanosec_rem / 1000);
+
+	if (print_all_stacks) {
+
+		/* Suspend wdog until all stacks are printed */
+		msm_watchdog_suspend(NULL);
+
+		printk(KERN_INFO "Stack trace dump:\n");
+
+		for_each_process(tsk) {
+			printk(KERN_INFO "\nPID: %d, Name: %s\n",
+				tsk->pid, tsk->comm);
+			show_stack(tsk, NULL);
+		}
+
+		msm_watchdog_resume(NULL);
+	}
+
+	panic("Apps watchdog bark received!");
+	return IRQ_HANDLED;
+}
+
+#define SCM_SET_REGSAVE_CMD 0x2
+
+static void configure_bark_dump(void)
+{
+	int ret;
+	struct {
+		unsigned addr;
+		int len;
+	} cmd_buf;
+
+	if (!appsbark) {
+		scm_regsave = (void *)__get_free_page(GFP_KERNEL);
+
+		if (scm_regsave) {
+			cmd_buf.addr = __pa(scm_regsave);
+			cmd_buf.len  = PAGE_SIZE;
+
+			ret = scm_call(SCM_SVC_UTIL, SCM_SET_REGSAVE_CMD,
+				       &cmd_buf, sizeof(cmd_buf), NULL, 0);
+			if (ret)
+				pr_err("Setting register save address failed.\n"
+				       "Registers won't be dumped on a dog "
+				       "bite\n");
+		} else {
+			pr_err("Allocating register save space failed\n"
+			       "Registers won't be dumped on a dog bite\n");
+			/*
+			 * No need to bail if allocation fails. Simply don't
+			 * send the command, and the secure side will reset
+			 * without saving registers.
+			 */
+		}
+	}
+}
+
+struct fiq_handler wdog_fh = {
+	.name = MODULE_NAME,
+};
+
+static void init_watchdog_work(struct work_struct *work)
+{
+	u64 timeout = (bark_time * WDT_HZ)/1000;
+	void *stack;
+	int ret;
+
+	if (has_vic) {
+		ret = request_irq(WDT0_ACCSCSSNBARK_INT, wdog_bark_handler, 0,
+				  "apps_wdog_bark", NULL);
+		if (ret)
+			return;
+	} else if (appsbark_fiq) {
+		claim_fiq(&wdog_fh);
+		set_fiq_handler(&msm_wdog_fiq_start, msm_wdog_fiq_length);
+		stack = (void *)__get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER);
+		if (!stack) {
+			pr_info("No free pages available - %s fails\n",
+					__func__);
+			return;
+		}
+
+		msm_wdog_fiq_setup(stack);
+		gic_set_irq_secure(WDT0_ACCSCSSNBARK_INT);
+	} else {
+		percpu_pdata = alloc_percpu(struct msm_watchdog_pdata *);
+		if (!percpu_pdata) {
+			pr_err("%s: memory allocation failed for percpu data\n",
+					__func__);
+			return;
+		}
+
+		/* Must request irq before sending scm command */
+		ret = request_percpu_irq(WDT0_ACCSCSSNBARK_INT,
+			wdog_bark_handler, "apps_wdog_bark", percpu_pdata);
+		if (ret) {
+			free_percpu(percpu_pdata);
+			return;
+		}
+	}
+
+	configure_bark_dump();
+
+	__raw_writel(timeout, msm_tmr0_base + WDT0_BARK_TIME);
+	__raw_writel(timeout + 3*WDT_HZ, msm_tmr0_base + WDT0_BITE_TIME);
+
+	schedule_delayed_work_on(0, &dogwork_struct, delay_time);
+
+	atomic_notifier_chain_register(&panic_notifier_list,
+				       &panic_blk);
+
+	__raw_writel(1, msm_tmr0_base + WDT0_EN);
+	__raw_writel(1, msm_tmr0_base + WDT0_RST);
+	last_pet = sched_clock();
+
+	if (!has_vic)
+		enable_percpu_irq(WDT0_ACCSCSSNBARK_INT, IRQ_TYPE_EDGE_RISING);
+
+	printk(KERN_INFO "MSM Watchdog Initialized\n");
+
+	return;
+}
+
+static int msm_watchdog_probe(struct platform_device *pdev)
+{
+	struct msm_watchdog_pdata *pdata = pdev->dev.platform_data;
+
+	if (!enable || !pdata || !pdata->pet_time || !pdata->bark_time) {
+		printk(KERN_INFO "MSM Watchdog Not Initialized\n");
+		return -ENODEV;
+	}
+
+	bark_time = pdata->bark_time;
+	has_vic = pdata->has_vic;
+	if (!pdata->has_secure) {
+		appsbark = 1;
+		appsbark_fiq = pdata->use_kernel_fiq;
+	}
+
+	msm_tmr0_base = msm_timer_get_timer0_base();
+
+	/*
+	 * This is only temporary till SBLs turn on the XPUs
+	 * This initialization will be done in SBLs on a later releases
+	 */
+	if (cpu_is_msm9615())
+		__raw_writel(0xF, MSM_TCSR_BASE + TCSR_WDT_CFG);
+
+	if (pdata->needs_expired_enable)
+		__raw_writel(0x1, MSM_CLK_CTL_BASE + 0x3820);
+
+	delay_time = msecs_to_jiffies(pdata->pet_time);
+	schedule_work_on(0, &init_dogwork_struct);
+	return 0;
+}
+
+static const struct dev_pm_ops msm_watchdog_dev_pm_ops = {
+	.suspend_noirq = msm_watchdog_suspend,
+	.resume_noirq = msm_watchdog_resume,
+};
+
+static struct platform_driver msm_watchdog_driver = {
+	.probe = msm_watchdog_probe,
+	.remove = msm_watchdog_remove,
+	.driver = {
+		.name = MODULE_NAME,
+		.owner = THIS_MODULE,
+		.pm = &msm_watchdog_dev_pm_ops,
+	},
+};
+
+static int init_watchdog(void)
+{
+	return platform_driver_register(&msm_watchdog_driver);
+}
+
+late_initcall(init_watchdog);
+MODULE_DESCRIPTION("MSM Watchdog Driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/msm_watchdog.h b/arch/arm/mach-msm/msm_watchdog.h
new file mode 100644
index 0000000..00ff0b6
--- /dev/null
+++ b/arch/arm/mach-msm/msm_watchdog.h
@@ -0,0 +1,77 @@
+/* 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
+ * 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 __ARCH_ARM_MACH_MSM_MSM_WATCHDOG_H
+#define __ARCH_ARM_MACH_MSM_MSM_WATCHDOG_H
+
+struct msm_watchdog_pdata {
+	/* pet interval period in ms */
+	unsigned int pet_time;
+	/* bark timeout in ms */
+	unsigned int bark_time;
+	bool has_secure;
+	bool needs_expired_enable;
+	bool has_vic;
+	/* You have to be running in secure mode to use FIQ */
+	bool use_kernel_fiq;
+};
+
+struct msm_watchdog_dump {
+	uint32_t magic;
+	uint32_t curr_cpsr;
+	uint32_t usr_r0;
+	uint32_t usr_r1;
+	uint32_t usr_r2;
+	uint32_t usr_r3;
+	uint32_t usr_r4;
+	uint32_t usr_r5;
+	uint32_t usr_r6;
+	uint32_t usr_r7;
+	uint32_t usr_r8;
+	uint32_t usr_r9;
+	uint32_t usr_r10;
+	uint32_t usr_r11;
+	uint32_t usr_r12;
+	uint32_t usr_r13;
+	uint32_t usr_r14;
+	uint32_t irq_spsr;
+	uint32_t irq_r13;
+	uint32_t irq_r14;
+	uint32_t svc_spsr;
+	uint32_t svc_r13;
+	uint32_t svc_r14;
+	uint32_t abt_spsr;
+	uint32_t abt_r13;
+	uint32_t abt_r14;
+	uint32_t und_spsr;
+	uint32_t und_r13;
+	uint32_t und_r14;
+	uint32_t fiq_spsr;
+	uint32_t fiq_r8;
+	uint32_t fiq_r9;
+	uint32_t fiq_r10;
+	uint32_t fiq_r11;
+	uint32_t fiq_r12;
+	uint32_t fiq_r13;
+	uint32_t fiq_r14;
+};
+
+void msm_wdog_fiq_setup(void *stack);
+extern unsigned int msm_wdog_fiq_length, msm_wdog_fiq_start;
+
+#ifdef CONFIG_MSM_WATCHDOG
+void pet_watchdog(void);
+#else
+static inline void pet_watchdog(void) { }
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/msm_watchdog_asm.S b/arch/arm/mach-msm/msm_watchdog_asm.S
new file mode 100644
index 0000000..c0377d6
--- /dev/null
+++ b/arch/arm/mach-msm/msm_watchdog_asm.S
@@ -0,0 +1,84 @@
+/* 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/linkage.h>
+#include <asm/assembler.h>
+
+#define VERSION_ID 0x1
+#define MAGIC 0xDEAD0000 | VERSION_ID
+
+	.text
+
+	.align 3
+
+ENTRY(msm_wdog_fiq_start)
+	mov	sp, r8		@get stack
+	ldr	r8, Ldump_cpu_ctx
+	@ store magic to indicate a valid dump
+	ldr	r9, Lmagic
+	str	r9, [r8], #4
+	@ get the current cpsr
+	mrs	r9, cpsr
+	str	r9, [r8],#4
+	@ get the USR r0-r7
+	stmia	r8!, {r0-r7}
+	mov	r4, r8
+	mov	r5, #PSR_I_BIT | PSR_F_BIT | SYSTEM_MODE
+	msr	cpsr_c, r5	@ select SYSTEM mode
+	stmia	r4!, {r8-r14}
+	mov	r5, #PSR_I_BIT | PSR_F_BIT | IRQ_MODE
+	msr	cpsr_c, r5	@ select IRQ mode
+	mrs	r5, spsr
+	str	r5, [r4], #4
+	stmia	r4!, {r13-r14}
+	mov	r5, #PSR_I_BIT | PSR_F_BIT | SVC_MODE
+	msr	cpsr_c, r5	@ select SVC mode
+	mrs	r5, spsr
+	str	r5, [r4], #4
+	stmia	r4!, {r13-r14}
+	mov	r5, #PSR_I_BIT | PSR_F_BIT | ABT_MODE
+	msr	cpsr_c, r5	@ select ABT mode
+	mrs	r5, spsr
+	str	r5, [r4], #4
+	stmia	r4!, {r13-r14}
+	mov	r5, #PSR_I_BIT | PSR_F_BIT | UND_MODE
+	msr	cpsr_c, r5	@ select UND mode
+	mrs	r5, spsr
+	str	r5, [r4], #4
+	stmia	r4!, {r13-r14}
+	mov	r5, #PSR_I_BIT | PSR_F_BIT | FIQ_MODE
+	msr	cpsr_c, r5	@ select FIQ mode
+	mrs	r5, spsr
+	str	r5, [r4], #4
+	stmia	r4!, {r8-r14}
+	dsb
+	mov	r5, #PSR_F_BIT | SVC_MODE
+	msr	cpsr_c, r5	@ select SVC mode
+	ldr	r2, Lwatchdog_bark_fin
+	blx	r2
+Ldump_cpu_ctx:
+	.word	msm_dump_cpu_ctx
+Lmagic:
+	.word	MAGIC
+Lwatchdog_bark_fin:
+	.word	msm_wdog_bark_fin
+ENTRY(msm_wdog_fiq_length)
+	.word	. - msm_wdog_fiq_start
+
+/* setup the stack */
+ENTRY(msm_wdog_fiq_setup)
+	mrs	r3, cpsr
+	msr	cpsr_c, #(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)
+	mov	r8, r0
+	msr	cpsr_c, r3
+	bx	lr
diff --git a/arch/arm/mach-msm/msm_xo.c b/arch/arm/mach-msm/msm_xo.c
new file mode 100644
index 0000000..407231a
--- /dev/null
+++ b/arch/arm/mach-msm/msm_xo.c
@@ -0,0 +1,386 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/debugfs.h>
+#include <linux/list.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
+#include <linux/string.h>
+#include <linux/clk.h>
+
+#include <mach/msm_xo.h>
+#include <mach/rpm.h>
+#include <mach/socinfo.h>
+
+#include "rpm_resources.h"
+
+static DEFINE_MUTEX(msm_xo_lock);
+
+struct msm_xo {
+	unsigned votes[NUM_MSM_XO_MODES];
+	unsigned mode;
+	struct list_head voters;
+};
+
+struct msm_xo_voter {
+	const char *name;
+	unsigned mode;
+	struct msm_xo *xo;
+	struct list_head list;
+};
+
+static struct msm_xo msm_xo_sources[NUM_MSM_XO_IDS];
+
+#ifdef CONFIG_DEBUG_FS
+static const char *msm_xo_to_str[NUM_MSM_XO_IDS] = {
+	[MSM_XO_TCXO_D0] = "D0",
+	[MSM_XO_TCXO_D1] = "D1",
+	[MSM_XO_TCXO_A0] = "A0",
+	[MSM_XO_TCXO_A1] = "A1",
+	[MSM_XO_TCXO_A2] = "A2",
+	[MSM_XO_CORE] = "CORE",
+};
+
+static const char *msm_xo_mode_to_str[NUM_MSM_XO_MODES] = {
+	[MSM_XO_MODE_ON] = "ON",
+	[MSM_XO_MODE_PIN_CTRL] = "PIN",
+	[MSM_XO_MODE_OFF] = "OFF",
+};
+
+static int msm_xo_debugfs_open(struct inode *inode, struct file *filp)
+{
+	filp->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t msm_xo_debugfs_read(struct file *filp, char __user *ubuf,
+		size_t cnt, loff_t *ppos)
+{
+	int r;
+	char buf[10];
+	struct msm_xo_voter *xo = filp->private_data;
+
+	r = snprintf(buf, sizeof(buf), "%s\n", msm_xo_mode_to_str[xo->mode]);
+	return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
+}
+
+static ssize_t msm_xo_debugfs_write(struct file *filp,
+		const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	struct msm_xo_voter *xo = filp->private_data;
+	char buf[10], *b;
+	int i, ret;
+
+	if (cnt > sizeof(buf) - 1)
+		return -EINVAL;
+
+	if (copy_from_user(&buf, ubuf, cnt))
+		return -EFAULT;
+	buf[cnt] = '\0';
+	b = strstrip(buf);
+
+	for (i = 0; i < ARRAY_SIZE(msm_xo_mode_to_str); i++)
+		if (!strncasecmp(b, msm_xo_mode_to_str[i], sizeof(buf))) {
+			ret = msm_xo_mode_vote(xo, i);
+			return ret ? : cnt;
+		}
+
+	return -EINVAL;
+}
+
+static const struct file_operations msm_xo_debugfs_fops = {
+	.open	= msm_xo_debugfs_open,
+	.read	= msm_xo_debugfs_read,
+	.write	= msm_xo_debugfs_write,
+};
+
+static struct dentry *xo_debugfs_root;
+static struct msm_xo_voter *xo_debugfs_voters[NUM_MSM_XO_IDS];
+
+static int __init msm_xo_init_debugfs_voters(void)
+{
+	int i;
+
+	xo_debugfs_root = debugfs_create_dir("msm_xo", NULL);
+	if (!xo_debugfs_root)
+		return -ENOMEM;
+
+	for (i = 0; i < ARRAY_SIZE(msm_xo_sources); i++) {
+		xo_debugfs_voters[i] = msm_xo_get(i, "debugfs");
+		if (IS_ERR(xo_debugfs_voters[i]))
+			goto err;
+		debugfs_create_file(msm_xo_to_str[i], S_IRUGO | S_IWUSR,
+				xo_debugfs_root, xo_debugfs_voters[i],
+				&msm_xo_debugfs_fops);
+	}
+	return 0;
+err:
+	while (--i >= 0)
+		msm_xo_put(xo_debugfs_voters[i]);
+	debugfs_remove_recursive(xo_debugfs_root);
+	return -ENOMEM;
+}
+
+static void msm_xo_dump_xo(struct seq_file *m, struct msm_xo *xo,
+		const char *name)
+{
+	struct msm_xo_voter *voter;
+
+	seq_printf(m, "CXO %-16s%s\n", name, msm_xo_mode_to_str[xo->mode]);
+	list_for_each_entry(voter, &xo->voters, list)
+		seq_printf(m, " %s %-16s %s\n",
+				xo->mode == voter->mode ? "*" : " ",
+				voter->name,
+				msm_xo_mode_to_str[voter->mode]);
+}
+
+static int msm_xo_show_voters(struct seq_file *m, void *v)
+{
+	int i;
+
+	mutex_lock(&msm_xo_lock);
+	for (i = 0; i < ARRAY_SIZE(msm_xo_sources); i++)
+		msm_xo_dump_xo(m, &msm_xo_sources[i], msm_xo_to_str[i]);
+	mutex_unlock(&msm_xo_lock);
+
+	return 0;
+}
+
+static int msm_xo_voters_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, msm_xo_show_voters, inode->i_private);
+}
+
+static const struct file_operations msm_xo_voters_ops = {
+	.open		= msm_xo_voters_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
+
+static int __init msm_xo_debugfs_init(void)
+{
+	msm_xo_init_debugfs_voters();
+	if (!debugfs_create_file("xo_voters", S_IRUGO, NULL, NULL,
+			&msm_xo_voters_ops))
+		return -ENOMEM;
+	return 0;
+}
+#else
+static int __init msm_xo_debugfs_init(void) { return 0; }
+#endif
+
+static int msm_xo_update_vote(struct msm_xo *xo)
+{
+	int ret;
+	unsigned vote, prev_vote = xo->mode;
+	struct msm_rpm_iv_pair cmd;
+
+	if (xo->votes[MSM_XO_MODE_ON])
+		vote = MSM_XO_MODE_ON;
+	else if (xo->votes[MSM_XO_MODE_PIN_CTRL])
+		vote = MSM_XO_MODE_PIN_CTRL;
+	else
+		vote = MSM_XO_MODE_OFF;
+
+	if (vote == prev_vote)
+		return 0;
+
+	/*
+	 * Change the vote here to simplify the TCXO logic. If the RPM
+	 * command fails we'll rollback.
+	 */
+	xo->mode = vote;
+	cmd.id = MSM_RPM_ID_CXO_BUFFERS;
+	cmd.value = (msm_xo_sources[MSM_XO_TCXO_D0].mode << 0)  |
+		    (msm_xo_sources[MSM_XO_TCXO_D1].mode << 8)  |
+		    (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) |
+		    /*
+		     * 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(MSM_RPM_CTX_SET_0, &cmd, 1);
+
+	if (ret)
+		xo->mode = prev_vote;
+
+	return ret;
+}
+
+static int __msm_xo_mode_vote(struct msm_xo_voter *xo_voter, unsigned mode)
+{
+	int ret;
+	struct msm_xo *xo = xo_voter->xo;
+	int is_d0 = xo == &msm_xo_sources[MSM_XO_TCXO_D0];
+	int needs_workaround = cpu_is_msm8960() || cpu_is_apq8064() ||
+			       cpu_is_msm8930() || cpu_is_msm9615();
+
+	if (xo_voter->mode == mode)
+		return 0;
+
+	xo->votes[mode]++;
+	xo->votes[xo_voter->mode]--;
+	ret = msm_xo_update_vote(xo);
+	if (ret) {
+		xo->votes[xo_voter->mode]++;
+		xo->votes[mode]--;
+		goto out;
+	}
+	/* TODO: Remove once RPM separates the concept of D0 and CXO */
+	if (is_d0 && needs_workaround) {
+		static struct clk *xo_clk;
+
+		if (!xo_clk) {
+			xo_clk = clk_get_sys("msm_xo", "xo");
+			BUG_ON(IS_ERR(xo_clk));
+		}
+		/* Ignore transitions from pin to on or vice versa */
+		if (mode && xo_voter->mode == MSM_XO_MODE_OFF)
+			clk_enable(xo_clk);
+		else if (!mode)
+			clk_disable(xo_clk);
+	}
+	xo_voter->mode = mode;
+out:
+	return ret;
+}
+
+/**
+ * msm_xo_mode_vote() - Vote for an XO to be ON, OFF, or under PIN_CTRL
+ * @xo_voter - Valid handle returned from msm_xo_get()
+ * @mode - Mode to vote for (ON, OFF, PIN_CTRL)
+ *
+ * Vote for an XO to be either ON, OFF, or under PIN_CTRL. Votes are
+ * aggregated with ON taking precedence over PIN_CTRL taking precedence
+ * over OFF.
+ *
+ * This function returns 0 on success or a negative error code on failure.
+ */
+int msm_xo_mode_vote(struct msm_xo_voter *xo_voter, enum msm_xo_modes mode)
+{
+	int ret;
+
+	if (!xo_voter)
+		return 0;
+
+	if (mode >= NUM_MSM_XO_MODES || IS_ERR(xo_voter))
+		return -EINVAL;
+
+	mutex_lock(&msm_xo_lock);
+	ret = __msm_xo_mode_vote(xo_voter, mode);
+	mutex_unlock(&msm_xo_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(msm_xo_mode_vote);
+
+/**
+ * msm_xo_get() - Get a voting handle for an XO
+ * @xo_id - XO identifier
+ * @voter - Debug string to identify users
+ *
+ * XO voters vote for OFF by default. This function returns a pointer
+ * indicating success. An ERR_PTR is returned on failure.
+ *
+ * If XO voting is disabled, %NULL is returned.
+ */
+struct msm_xo_voter *msm_xo_get(enum msm_xo_ids xo_id, const char *voter)
+{
+	int ret;
+	struct msm_xo_voter *xo_voter;
+
+	if (xo_id >= NUM_MSM_XO_IDS) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	xo_voter = kzalloc(sizeof(*xo_voter), GFP_KERNEL);
+	if (!xo_voter) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	xo_voter->name = kstrdup(voter, GFP_KERNEL);
+	if (!xo_voter->name) {
+		ret = -ENOMEM;
+		goto err_name;
+	}
+
+	xo_voter->xo = &msm_xo_sources[xo_id];
+
+	/* Voters vote for OFF by default */
+	mutex_lock(&msm_xo_lock);
+	xo_voter->xo->votes[MSM_XO_MODE_OFF]++;
+	list_add(&xo_voter->list, &xo_voter->xo->voters);
+	mutex_unlock(&msm_xo_lock);
+
+	return xo_voter;
+
+err_name:
+	kfree(xo_voter);
+err:
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(msm_xo_get);
+
+/**
+ * msm_xo_put() - Release a voting handle
+ * @xo_voter - Valid handle returned from msm_xo_get()
+ *
+ * Release a reference to an XO voting handle. This also removes the voter's
+ * vote, therefore calling msm_xo_mode_vote(xo_voter, MSM_XO_MODE_OFF)
+ * beforehand is unnecessary.
+ */
+void msm_xo_put(struct msm_xo_voter *xo_voter)
+{
+	if (!xo_voter || IS_ERR(xo_voter))
+		return;
+
+	mutex_lock(&msm_xo_lock);
+	__msm_xo_mode_vote(xo_voter, MSM_XO_MODE_OFF);
+	xo_voter->xo->votes[MSM_XO_MODE_OFF]--;
+	list_del(&xo_voter->list);
+	mutex_unlock(&msm_xo_lock);
+
+	kfree(xo_voter->name);
+	kfree(xo_voter);
+}
+EXPORT_SYMBOL(msm_xo_put);
+
+int __init msm_xo_init(void)
+{
+	int i, ret;
+	struct msm_rpm_iv_pair cmd[1];
+
+	for (i = 0; i < ARRAY_SIZE(msm_xo_sources); i++)
+		INIT_LIST_HEAD(&msm_xo_sources[i].voters);
+
+	cmd[0].id = MSM_RPM_ID_CXO_BUFFERS;
+	cmd[0].value = 0;
+	ret = msm_rpmrs_set(MSM_RPM_CTX_SET_0, cmd, ARRAY_SIZE(cmd));
+	if (ret)
+		return ret;
+	msm_xo_debugfs_init();
+	return 0;
+}
diff --git a/arch/arm/mach-msm/nand_partitions.c b/arch/arm/mach-msm/nand_partitions.c
new file mode 100644
index 0000000..499ad99
--- /dev/null
+++ b/arch/arm/mach-msm/nand_partitions.c
@@ -0,0 +1,202 @@
+/* arch/arm/mach-msm/nand_partitions.c
+ *
+ * Code to extract partition information from ATAG set up by the
+ * bootloader.
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008-2009,2011 Code Aurora Forum. All rights reserved.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach/flash.h>
+#include <linux/io.h>
+
+#include <asm/setup.h>
+
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
+#include <mach/msm_iomap.h>
+
+#include <mach/board.h>
+#ifdef CONFIG_MSM_SMD
+#include "smd_private.h"
+#endif
+
+/* configuration tags specific to msm */
+
+#define ATAG_MSM_PARTITION 0x4d534D70 /* MSMp */
+
+struct msm_ptbl_entry {
+	char name[16];
+	__u32 offset;
+	__u32 size;
+	__u32 flags;
+};
+
+#define MSM_MAX_PARTITIONS 18
+
+static struct mtd_partition msm_nand_partitions[MSM_MAX_PARTITIONS];
+static char msm_nand_names[MSM_MAX_PARTITIONS * 16];
+
+extern struct flash_platform_data msm_nand_data;
+
+static int __init parse_tag_msm_partition(const struct tag *tag)
+{
+	struct mtd_partition *ptn = msm_nand_partitions;
+	char *name = msm_nand_names;
+	struct msm_ptbl_entry *entry = (void *) &tag->u;
+	unsigned count, n;
+
+	count = (tag->hdr.size - 2) /
+		(sizeof(struct msm_ptbl_entry) / sizeof(__u32));
+
+	if (count > MSM_MAX_PARTITIONS)
+		count = MSM_MAX_PARTITIONS;
+
+	for (n = 0; n < count; n++) {
+		memcpy(name, entry->name, 15);
+		name[15] = 0;
+
+		ptn->name = name;
+		ptn->offset = entry->offset;
+		ptn->size = entry->size;
+
+		printk(KERN_INFO "Partition (from atag) %s "
+				"-- Offset:%llx Size:%llx\n",
+				ptn->name, ptn->offset, ptn->size);
+
+		name += 16;
+		entry++;
+		ptn++;
+	}
+
+	msm_nand_data.nr_parts = count;
+	msm_nand_data.parts = msm_nand_partitions;
+
+	return 0;
+}
+
+__tagtable(ATAG_MSM_PARTITION, parse_tag_msm_partition);
+
+#define FLASH_PART_MAGIC1     0x55EE73AA
+#define FLASH_PART_MAGIC2     0xE35EBDDB
+#define FLASH_PARTITION_VERSION   0x3
+
+#define LINUX_FS_PARTITION_NAME  "0:EFS2APPS"
+
+struct flash_partition_entry {
+	char name[16];
+	u32 offset;	/* Offset in blocks from beginning of device */
+	u32 length;	/* Length of the partition in blocks */
+	u8 attrib1;
+	u8 attrib2;
+	u8 attrib3;
+	u8 which_flash;	/* Numeric ID (first = 0, second = 1) */
+};
+struct flash_partition_table {
+	u32 magic1;
+	u32 magic2;
+	u32 version;
+	u32 numparts;
+	struct flash_partition_entry part_entry[16];
+};
+
+#ifdef CONFIG_MSM_SMD
+static int get_nand_partitions(void)
+{
+	struct flash_partition_table *partition_table;
+	struct flash_partition_entry *part_entry;
+	struct mtd_partition *ptn = msm_nand_partitions;
+	char *name = msm_nand_names;
+	int part;
+
+	if (msm_nand_data.nr_parts)
+		return 0;
+
+	partition_table = (struct flash_partition_table *)
+	    smem_alloc(SMEM_AARM_PARTITION_TABLE,
+		       sizeof(struct flash_partition_table));
+
+	if (!partition_table) {
+		printk(KERN_WARNING "%s: no flash partition table in shared "
+		       "memory\n", __func__);
+		return -ENOENT;
+	}
+
+	if ((partition_table->magic1 != (u32) FLASH_PART_MAGIC1) ||
+	    (partition_table->magic2 != (u32) FLASH_PART_MAGIC2) ||
+	    (partition_table->version != (u32) FLASH_PARTITION_VERSION)) {
+		printk(KERN_WARNING "%s: version mismatch -- magic1=%#x, "
+		       "magic2=%#x, version=%#x\n", __func__,
+		       partition_table->magic1,
+		       partition_table->magic2,
+		       partition_table->version);
+		return -EFAULT;
+	}
+
+	msm_nand_data.nr_parts = 0;
+
+	/* Get the LINUX FS partition info */
+	for (part = 0; part < partition_table->numparts; part++) {
+		part_entry = &partition_table->part_entry[part];
+
+		/* Find a match for the Linux file system partition */
+		if (strcmp(part_entry->name, LINUX_FS_PARTITION_NAME) == 0) {
+			strcpy(name, part_entry->name);
+			ptn->name = name;
+
+			/*TODO: Get block count and size info */
+			ptn->offset = part_entry->offset;
+
+			/* For SMEM, -1 indicates remaining space in flash,
+			 * but for MTD it is 0
+			 */
+			if (part_entry->length == (u32)-1)
+				ptn->size = 0;
+			else
+				ptn->size = part_entry->length;
+
+			msm_nand_data.nr_parts = 1;
+			msm_nand_data.parts = msm_nand_partitions;
+
+			printk(KERN_INFO "Partition(from smem) %s "
+					"-- Offset:%llx Size:%llx\n",
+					ptn->name, ptn->offset, ptn->size);
+
+			return 0;
+		}
+	}
+
+	printk(KERN_WARNING "%s: no partition table found!", __func__);
+
+	return -ENODEV;
+}
+#else
+static int get_nand_partitions(void)
+{
+
+	if (msm_nand_data.nr_parts)
+		return 0;
+
+	printk(KERN_WARNING "%s: no partition table found!", __func__);
+
+	return -ENODEV;
+}
+#endif
+
+device_initcall(get_nand_partitions);
diff --git a/arch/arm/mach-msm/no-pm.c b/arch/arm/mach-msm/no-pm.c
new file mode 100644
index 0000000..d38b416
--- /dev/null
+++ b/arch/arm/mach-msm/no-pm.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+
+#include <mach/cpuidle.h>
+#include "idle.h"
+#include "pm.h"
+
+void arch_idle(void)
+{ }
+
+void msm_pm_set_platform_data(struct msm_pm_platform_data *data, int count)
+{ }
+
+void msm_pm_cpu_enter_lowpower(unsigned cpu)
+{
+	asm("wfi"
+		:
+		:
+		: "memory", "cc");
+}
+
+void msm_pm_set_max_sleep_time(int64_t max_sleep_time_ns) { }
+
+void msm_pm_set_irq_extns(struct msm_pm_irq_calls *irq_calls) {}
+
+int msm_pm_idle_prepare(struct cpuidle_device *dev,
+			struct cpuidle_driver *drv, int index)
+{
+	return -ENOSYS;
+}
+
+int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode)
+{
+	return -ENOSYS;
+}
+
diff --git a/arch/arm/mach-msm/nohlt.c b/arch/arm/mach-msm/nohlt.c
new file mode 100644
index 0000000..532d57d
--- /dev/null
+++ b/arch/arm/mach-msm/nohlt.c
@@ -0,0 +1,40 @@
+/* Copyright (c) 2009, 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.
+ *
+ */
+/*
+ * MSM architecture driver to control arm halt behavior
+ */
+
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/fs.h>
+#include <asm/system.h>
+
+static int set_nohalt(void *data, u64 val)
+{
+	if (val)
+		disable_hlt();
+	else
+		enable_hlt();
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(nohalt_ops, NULL, set_nohalt, "%llu\n");
+
+static int __init init_hlt_debug(void)
+{
+	debugfs_create_file("nohlt", 0200, NULL, NULL, &nohalt_ops);
+
+	return 0;
+}
+
+late_initcall(init_hlt_debug);
diff --git a/arch/arm/mach-msm/ocmem.c b/arch/arm/mach-msm/ocmem.c
new file mode 100644
index 0000000..69e39df
--- /dev/null
+++ b/arch/arm/mach-msm/ocmem.c
@@ -0,0 +1,314 @@
+/* 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 <mach/ocmem_priv.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/rbtree.h>
+#include <linux/genalloc.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+struct ocmem_partition {
+	const char *name;
+	int id;
+	unsigned long p_start;
+	unsigned long p_size;
+	unsigned long p_min;
+	unsigned int p_tail;
+};
+
+struct ocmem_plat_data {
+	void __iomem *vbase;
+	unsigned long size;
+	unsigned long base;
+	struct ocmem_partition *parts;
+	unsigned nr_parts;
+};
+
+struct ocmem_zone zones[OCMEM_CLIENT_MAX];
+
+struct ocmem_zone *get_zone(unsigned id)
+{
+	if (id < OCMEM_GRAPHICS || id >= OCMEM_CLIENT_MAX)
+		return NULL;
+	else
+		return &zones[id];
+}
+
+static struct ocmem_plat_data *ocmem_pdata;
+
+#define CLIENT_NAME_MAX 10
+/* Must be in sync with enum ocmem_client */
+static const char *client_names[OCMEM_CLIENT_MAX] = {
+	"graphics",
+	"video",
+	"camera",
+	"hp_audio",
+	"voice",
+	"lp_audio",
+	"sensors",
+	"blast",
+};
+
+struct ocmem_quota_table {
+	const char *name;
+	int id;
+	unsigned long start;
+	unsigned long size;
+	unsigned long min;
+	unsigned int tail;
+};
+
+/* This static table will go away with device tree support */
+static struct ocmem_quota_table qt[OCMEM_CLIENT_MAX] = {
+	/* name,        id,     start,  size,   min, tail */
+	{ "graphics", OCMEM_GRAPHICS, 0x0, 0x100000, 0x80000, 0},
+	{ "video", OCMEM_VIDEO, 0x100000, 0x80000, 0x55000, 1},
+	{ "camera", OCMEM_CAMERA, 0x0, 0x0, 0x0, 0},
+	{ "voice", OCMEM_VOICE,  0x0, 0x0, 0x0, 0 },
+	{ "hp_audio", OCMEM_HP_AUDIO, 0x0, 0x0, 0x0, 0},
+	{ "lp_audio", OCMEM_LP_AUDIO, 0x80000, 0xA0000, 0xA0000, 0},
+	{ "blast", OCMEM_BLAST, 0x120000, 0x20000, 0x20000, 0},
+	{ "sensors", OCMEM_SENSORS, 0x140000, 0x40000, 0x40000, 0},
+};
+
+static inline int get_id(const char *name)
+{
+	int i = 0;
+	for (i = 0 ; i < OCMEM_CLIENT_MAX; i++) {
+		if (strncmp(name, client_names[i], CLIENT_NAME_MAX) == 0)
+			return i;
+	}
+	return -EINVAL;
+}
+
+static struct ocmem_plat_data *parse_static_config(struct platform_device *pdev)
+{
+	struct ocmem_plat_data *pdata = NULL;
+	struct ocmem_partition *parts = NULL;
+	struct device   *dev = &pdev->dev;
+	unsigned nr_parts = 0;
+	int i;
+	int j;
+
+	pdata = devm_kzalloc(dev, sizeof(struct ocmem_plat_data),
+			GFP_KERNEL);
+
+	if (!pdata) {
+		dev_err(dev, "Unable to allocate memory for"
+			" platform data\n");
+		return NULL;
+	}
+
+	for (i = 0 ; i < ARRAY_SIZE(qt); i++)
+		if (qt[i].size != 0x0)
+			nr_parts++;
+
+	if (nr_parts == 0x0) {
+		dev_err(dev, "No valid ocmem partitions\n");
+		return NULL;
+	} else
+		dev_info(dev, "Total partitions = %d\n", nr_parts);
+
+	parts = devm_kzalloc(dev, sizeof(struct ocmem_partition) * nr_parts,
+				 GFP_KERNEL);
+
+	if (!parts) {
+		dev_err(dev, "Unable to allocate memory for"
+			" partition data\n");
+		return NULL;
+	}
+
+	for (i = 0, j = 0; i < ARRAY_SIZE(qt); i++) {
+		if (qt[i].size == 0x0) {
+			dev_dbg(dev, "Skipping creation of pool for %s\n",
+						qt[i].name);
+			continue;
+		}
+		parts[j].id = qt[i].id;
+		parts[j].p_size = qt[i].size;
+		parts[j].p_start = qt[i].start;
+		parts[j].p_min = qt[i].min;
+		parts[j].p_tail = qt[i].tail;
+		j++;
+	}
+	BUG_ON(j != nr_parts);
+	pdata->nr_parts = nr_parts;
+	pdata->parts = parts;
+	pdata->base = OCMEM_PHYS_BASE;
+	pdata->size = OCMEM_PHYS_SIZE;
+	return pdata;
+}
+
+static struct ocmem_plat_data *parse_dt_config(struct platform_device *pdev)
+{
+	return NULL;
+}
+
+static int ocmem_zone_init(struct platform_device *pdev)
+{
+
+	int ret = -1;
+	int i = 0;
+	unsigned active_zones = 0;
+
+	struct ocmem_zone *zone = NULL;
+	struct ocmem_zone_ops *z_ops = NULL;
+	struct device   *dev = &pdev->dev;
+	unsigned long start;
+	struct ocmem_plat_data *pdata = NULL;
+
+	pdata = platform_get_drvdata(pdev);
+
+	for (i = 0; i < pdata->nr_parts; i++) {
+		struct ocmem_partition *part = &pdata->parts[i];
+		zone = get_zone(part->id);
+
+		dev_dbg(dev, "Partition %d, start %lx, size %lx for %s\n",
+				i, part->p_start, part->p_size,
+				client_names[part->id]);
+
+		if (part->p_size > pdata->size) {
+			dev_alert(dev, "Quota > ocmem_size for id:%d\n",
+					part->id);
+			continue;
+		}
+
+		zone->z_pool = gen_pool_create(PAGE_SHIFT, -1);
+
+		if (!zone->z_pool) {
+			dev_alert(dev, "Creating pool failed for id:%d\n",
+					part->id);
+			return -EBUSY;
+		}
+
+		start = pdata->base + part->p_start;
+		ret = gen_pool_add(zone->z_pool, start,
+					part->p_size, -1);
+
+		if (ret < 0) {
+			gen_pool_destroy(zone->z_pool);
+			dev_alert(dev, "Unable to back pool %d with "
+				"buffer:%lx\n", part->id, part->p_size);
+			return -EBUSY;
+		}
+
+		/* Initialize zone allocators */
+		z_ops = devm_kzalloc(dev, sizeof(struct ocmem_zone_ops),
+				GFP_KERNEL);
+		if (!z_ops) {
+			pr_alert("ocmem: Unable to allocate memory for"
+					"zone ops:%d\n", i);
+			return -EBUSY;
+		}
+
+		/* Initialize zone parameters */
+		zone->z_start = start;
+		zone->z_head = zone->z_start;
+		zone->z_end = start + part->p_size;
+		zone->z_tail = zone->z_end;
+		zone->z_free = part->p_size;
+		zone->owner = part->id;
+		zone->active_regions = 0;
+		zone->max_regions = 0;
+		INIT_LIST_HEAD(&zone->region_list);
+		zone->z_ops = z_ops;
+		if (part->p_tail) {
+			z_ops->allocate = allocate_tail;
+			z_ops->free = free_tail;
+		} else {
+			z_ops->allocate = allocate_head;
+			z_ops->free = free_head;
+		}
+		active_zones++;
+
+		if (active_zones == 1)
+			pr_info("Physical OCMEM zone layout:\n");
+
+		pr_info(" zone %s\t: 0x%08lx - 0x%08lx (%4ld KB)\n",
+				client_names[part->id], zone->z_start,
+				zone->z_end, part->p_size/SZ_1K);
+	}
+
+	dev_info(dev, "Total active zones = %d\n", active_zones);
+	return 0;
+}
+
+static int __devinit msm_ocmem_probe(struct platform_device *pdev)
+{
+	struct device   *dev = &pdev->dev;
+
+	if (!pdev->dev.of_node->child) {
+		dev_info(dev, "Missing Configuration in Device Tree\n");
+		ocmem_pdata = parse_static_config(pdev);
+	} else {
+		ocmem_pdata = parse_dt_config(pdev);
+	}
+
+	/* Check if we have some configuration data to start */
+	if (!ocmem_pdata)
+		return -ENODEV;
+
+	/* Sanity Checks */
+	BUG_ON(!IS_ALIGNED(ocmem_pdata->size, PAGE_SIZE));
+	BUG_ON(!IS_ALIGNED(ocmem_pdata->base, PAGE_SIZE));
+
+	platform_set_drvdata(pdev, ocmem_pdata);
+
+	if (ocmem_zone_init(pdev))
+		return -EBUSY;
+
+	dev_info(dev, "initialized successfully\n");
+	return 0;
+}
+
+static int __devexit msm_ocmem_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static struct of_device_id msm_ocmem_dt_match[] = {
+	{       .compatible = "qcom,msm_ocmem",
+	},
+	{}
+};
+
+static struct platform_driver msm_ocmem_driver = {
+	.probe = msm_ocmem_probe,
+	.remove = __devexit_p(msm_ocmem_remove),
+	.driver = {
+		.name = "msm_ocmem",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_ocmem_dt_match,
+	},
+};
+
+static int __init ocmem_init(void)
+{
+	return platform_driver_register(&msm_ocmem_driver);
+}
+subsys_initcall(ocmem_init);
+
+static void __exit ocmem_exit(void)
+{
+	platform_driver_unregister(&msm_ocmem_driver);
+}
+module_exit(ocmem_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Support for On-Chip Memory on MSM");
diff --git a/arch/arm/mach-msm/ocmem_allocator.c b/arch/arm/mach-msm/ocmem_allocator.c
new file mode 100644
index 0000000..71cacda
--- /dev/null
+++ b/arch/arm/mach-msm/ocmem_allocator.c
@@ -0,0 +1,105 @@
+/* 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 <mach/ocmem.h>
+#include <mach/ocmem_priv.h>
+#include <linux/genalloc.h>
+
+/* All allocator operations are serialized by ocmem driver */
+
+/* The allocators work as follows:
+	Constraints:
+	1) There is no IOMMU access to OCMEM hence successive allocations
+		in the zone must be physically contiguous
+	2) Allocations must be freed in reverse order within a zone.
+
+	z->z_start: Fixed pointer to the start of a zone
+	z->z_end:   Fixed pointer to the end of a zone
+
+	z->z_head:  Movable pointer to the next free area when growing at head
+			Fixed on zones that grow from tail
+
+	z->z_tail:  Movable pointer to the next free area when growing at tail
+			Fixed on zones that grow from head
+
+	z->z_free:  Free space in a zone that is updated on an allocation/free
+
+	reserve:    Enable libgenpool to simulate tail allocations
+*/
+
+unsigned long allocate_head(struct ocmem_zone *z, unsigned long size)
+{
+
+	unsigned long offset;
+
+	offset  = gen_pool_alloc(z->z_pool, size);
+
+	if (!offset)
+		return -ENOMEM;
+
+	z->z_head += size;
+	z->z_free -= size;
+	return offset;
+}
+
+unsigned long allocate_tail(struct ocmem_zone *z, unsigned long size)
+{
+	unsigned long offset;
+	unsigned long reserve;
+	unsigned long head;
+
+	if (z->z_tail < (z->z_head + size))
+		return -ENOMEM;
+
+	reserve = z->z_tail - z->z_head - size;
+	if (reserve) {
+		head = gen_pool_alloc(z->z_pool, reserve);
+		offset = gen_pool_alloc(z->z_pool, size);
+		gen_pool_free(z->z_pool, head, reserve);
+	} else
+		offset = gen_pool_alloc(z->z_pool, size);
+
+	if (!offset)
+		return -ENOMEM;
+
+	z->z_tail -= size;
+	z->z_free -= size;
+	return offset;
+}
+
+int free_head(struct ocmem_zone *z, unsigned long offset,
+			unsigned long size)
+{
+	if (offset > z->z_head) {
+		pr_err("ocmem: Detected out of order free "
+				"leading to fragmentation\n");
+		return -EINVAL;
+	}
+	gen_pool_free(z->z_pool, offset, size);
+	z->z_head -= size;
+	z->z_free += size;
+	return 0;
+}
+
+int free_tail(struct ocmem_zone *z, unsigned long offset,
+				unsigned long size)
+{
+	if (offset > z->z_tail) {
+		pr_err("ocmem: Detected out of order free "
+				"leading to fragmentation\n");
+		return -EINVAL;
+	}
+	gen_pool_free(z->z_pool, offset, size);
+	z->z_tail += size;
+	z->z_free += size;
+	return 0;
+}
diff --git a/arch/arm/mach-msm/oem_rapi_client.c b/arch/arm/mach-msm/oem_rapi_client.c
new file mode 100644
index 0000000..bcf6e57
--- /dev/null
+++ b/arch/arm/mach-msm/oem_rapi_client.c
@@ -0,0 +1,357 @@
+/* Copyright (c) 2009-2010, 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.
+ *
+ */
+
+/*
+ * OEM RAPI CLIENT Driver source file
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/oem_rapi_client.h>
+
+#define OEM_RAPI_PROG  0x3000006B
+#define OEM_RAPI_VERS  0x00010001
+
+#define OEM_RAPI_NULL_PROC                        0
+#define OEM_RAPI_RPC_GLUE_CODE_INFO_REMOTE_PROC   1
+#define OEM_RAPI_STREAMING_FUNCTION_PROC          2
+
+#define OEM_RAPI_CLIENT_MAX_OUT_BUFF_SIZE 128
+
+static struct msm_rpc_client *rpc_client;
+static uint32_t open_count;
+static DEFINE_MUTEX(oem_rapi_client_lock);
+
+/* TODO: check where to allocate memory for return */
+static int oem_rapi_client_cb(struct msm_rpc_client *client,
+			      struct rpc_request_hdr *req,
+			      struct msm_rpc_xdr *xdr)
+{
+	uint32_t cb_id, accept_status;
+	int rc;
+	void *cb_func;
+	uint32_t temp;
+
+	struct oem_rapi_client_streaming_func_cb_arg arg;
+	struct oem_rapi_client_streaming_func_cb_ret ret;
+
+	arg.input = NULL;
+	ret.out_len = NULL;
+	ret.output = NULL;
+
+	xdr_recv_uint32(xdr, &cb_id);                    /* cb_id */
+	xdr_recv_uint32(xdr, &arg.event);                /* enum */
+	xdr_recv_uint32(xdr, (uint32_t *)(&arg.handle)); /* handle */
+	xdr_recv_uint32(xdr, &arg.in_len);               /* in_len */
+	xdr_recv_bytes(xdr, (void **)&arg.input, &temp); /* input */
+	xdr_recv_uint32(xdr, &arg.out_len_valid);        /* out_len */
+	if (arg.out_len_valid) {
+		ret.out_len = kmalloc(sizeof(*ret.out_len), GFP_KERNEL);
+		if (!ret.out_len) {
+			accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
+			goto oem_rapi_send_ack;
+		}
+	}
+
+	xdr_recv_uint32(xdr, &arg.output_valid);         /* out */
+	if (arg.output_valid) {
+		xdr_recv_uint32(xdr, &arg.output_size);  /* ouput_size */
+
+		ret.output = kmalloc(arg.output_size, GFP_KERNEL);
+		if (!ret.output) {
+			accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
+			goto oem_rapi_send_ack;
+		}
+	}
+
+	cb_func = msm_rpc_get_cb_func(client, cb_id);
+	if (cb_func) {
+		rc = ((int (*)(struct oem_rapi_client_streaming_func_cb_arg *,
+			       struct oem_rapi_client_streaming_func_cb_ret *))
+		      cb_func)(&arg, &ret);
+		if (rc)
+			accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
+		else
+			accept_status = RPC_ACCEPTSTAT_SUCCESS;
+	} else
+		accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
+
+ oem_rapi_send_ack:
+	xdr_start_accepted_reply(xdr, accept_status);
+
+	if (accept_status == RPC_ACCEPTSTAT_SUCCESS) {
+		uint32_t temp = sizeof(uint32_t);
+		xdr_send_pointer(xdr, (void **)&(ret.out_len), temp,
+				 xdr_send_uint32);
+
+		/* output */
+		if (ret.output && ret.out_len)
+			xdr_send_bytes(xdr, (const void **)&ret.output,
+					     ret.out_len);
+		else {
+			temp = 0;
+			xdr_send_uint32(xdr, &temp);
+		}
+	}
+	rc = xdr_send_msg(xdr);
+	if (rc)
+		pr_err("%s: sending reply failed: %d\n", __func__, rc);
+
+	kfree(arg.input);
+	kfree(ret.out_len);
+	kfree(ret.output);
+
+	return 0;
+}
+
+static int oem_rapi_client_streaming_function_arg(struct msm_rpc_client *client,
+						  struct msm_rpc_xdr *xdr,
+						  void *data)
+{
+	int cb_id;
+	struct oem_rapi_client_streaming_func_arg *arg = data;
+
+	cb_id = msm_rpc_add_cb_func(client, (void *)arg->cb_func);
+	if ((cb_id < 0) && (cb_id != MSM_RPC_CLIENT_NULL_CB_ID))
+		return cb_id;
+
+	xdr_send_uint32(xdr, &arg->event);                /* enum */
+	xdr_send_uint32(xdr, &cb_id);                     /* cb_id */
+	xdr_send_uint32(xdr, (uint32_t *)(&arg->handle)); /* handle */
+	xdr_send_uint32(xdr, &arg->in_len);               /* in_len */
+	xdr_send_bytes(xdr, (const void **)&arg->input,
+			     &arg->in_len);                     /* input */
+	xdr_send_uint32(xdr, &arg->out_len_valid);        /* out_len */
+	xdr_send_uint32(xdr, &arg->output_valid);         /* output */
+
+	/* output_size */
+	if (arg->output_valid)
+		xdr_send_uint32(xdr, &arg->output_size);
+
+	return 0;
+}
+
+static int oem_rapi_client_streaming_function_ret(struct msm_rpc_client *client,
+						  struct msm_rpc_xdr *xdr,
+						  void *data)
+{
+	struct oem_rapi_client_streaming_func_ret *ret = data;
+	uint32_t temp;
+
+	/* out_len */
+	xdr_recv_pointer(xdr, (void **)&(ret->out_len), sizeof(uint32_t),
+			 xdr_recv_uint32);
+
+	/* output */
+	if (ret->out_len && *ret->out_len)
+		xdr_recv_bytes(xdr, (void **)&ret->output, &temp);
+
+	return 0;
+}
+
+int oem_rapi_client_streaming_function(
+	struct msm_rpc_client *client,
+	struct oem_rapi_client_streaming_func_arg *arg,
+	struct oem_rapi_client_streaming_func_ret *ret)
+{
+	return msm_rpc_client_req2(client,
+				   OEM_RAPI_STREAMING_FUNCTION_PROC,
+				   oem_rapi_client_streaming_function_arg, arg,
+				   oem_rapi_client_streaming_function_ret,
+				   ret, -1);
+}
+EXPORT_SYMBOL(oem_rapi_client_streaming_function);
+
+int oem_rapi_client_close(void)
+{
+	mutex_lock(&oem_rapi_client_lock);
+	if (--open_count == 0) {
+		msm_rpc_unregister_client(rpc_client);
+		pr_info("%s: disconnected from remote oem rapi server\n",
+			__func__);
+	}
+	mutex_unlock(&oem_rapi_client_lock);
+	return 0;
+}
+EXPORT_SYMBOL(oem_rapi_client_close);
+
+struct msm_rpc_client *oem_rapi_client_init(void)
+{
+	mutex_lock(&oem_rapi_client_lock);
+	if (open_count == 0) {
+		rpc_client = msm_rpc_register_client2("oemrapiclient",
+						      OEM_RAPI_PROG,
+						      OEM_RAPI_VERS, 0,
+						      oem_rapi_client_cb);
+		if (!IS_ERR(rpc_client))
+			open_count++;
+	}
+	mutex_unlock(&oem_rapi_client_lock);
+	return rpc_client;
+}
+EXPORT_SYMBOL(oem_rapi_client_init);
+
+#if defined(CONFIG_DEBUG_FS)
+
+static struct dentry *dent;
+static int oem_rapi_client_test_res;
+
+static int oem_rapi_client_null(struct msm_rpc_client *client,
+				void *arg, void *ret)
+{
+	return msm_rpc_client_req2(client, OEM_RAPI_NULL_PROC,
+				   NULL, NULL, NULL, NULL, -1);
+}
+
+static int oem_rapi_client_test_streaming_cb_func(
+	struct oem_rapi_client_streaming_func_cb_arg *arg,
+	struct oem_rapi_client_streaming_func_cb_ret *ret)
+{
+	uint32_t size;
+
+	size = (arg->in_len < OEM_RAPI_CLIENT_MAX_OUT_BUFF_SIZE) ?
+		arg->in_len : OEM_RAPI_CLIENT_MAX_OUT_BUFF_SIZE;
+
+	if (ret->out_len != 0)
+		*ret->out_len = size;
+
+	if (ret->output != 0)
+		memcpy(ret->output, arg->input, size);
+
+	return 0;
+}
+
+static ssize_t debug_read(struct file *fp, char __user *buf,
+			  size_t count, loff_t *pos)
+{
+	char _buf[16];
+
+	snprintf(_buf, sizeof(_buf), "%i\n", oem_rapi_client_test_res);
+
+	return simple_read_from_buffer(buf, count, pos, _buf, strlen(_buf));
+}
+
+static ssize_t debug_write(struct file *fp, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	char input[OEM_RAPI_CLIENT_MAX_OUT_BUFF_SIZE];
+	struct oem_rapi_client_streaming_func_arg arg;
+	struct oem_rapi_client_streaming_func_ret ret;
+
+	unsigned char cmd[64];
+	int len;
+
+	if (count < 1)
+		return 0;
+
+	len = count > 63 ? 63 : count;
+
+	if (copy_from_user(cmd, buf, len))
+		return -EFAULT;
+
+	cmd[len] = 0;
+
+	if (cmd[len-1] == '\n') {
+		cmd[len-1] = 0;
+		len--;
+	}
+
+	if (!strncmp(cmd, "null", 64)) {
+		oem_rapi_client_test_res = oem_rapi_client_null(rpc_client,
+								NULL, NULL);
+	} else if (!strncmp(cmd, "streaming_func", 64)) {
+		memset(input, 5, 16);
+		arg.event = 0;
+		arg.cb_func = oem_rapi_client_test_streaming_cb_func;
+		arg.handle = (void *)20;
+		arg.in_len = 16;
+		arg.input = input;
+		arg.out_len_valid = 1;
+		arg.output_valid = 1;
+		arg.output_size = OEM_RAPI_CLIENT_MAX_OUT_BUFF_SIZE;
+		ret.out_len = NULL;
+		ret.output = NULL;
+
+		oem_rapi_client_test_res = oem_rapi_client_streaming_function(
+			rpc_client, &arg, &ret);
+
+		kfree(ret.out_len);
+		kfree(ret.output);
+
+	} else
+		oem_rapi_client_test_res = -EINVAL;
+
+	if (oem_rapi_client_test_res)
+		pr_err("oem rapi client test fail %d\n",
+		       oem_rapi_client_test_res);
+	else
+		pr_info("oem rapi client test passed\n");
+
+	return count;
+}
+
+static int debug_release(struct inode *ip, struct file *fp)
+{
+	return oem_rapi_client_close();
+}
+
+static int debug_open(struct inode *ip, struct file *fp)
+{
+	struct msm_rpc_client *client;
+	client = oem_rapi_client_init();
+	if (IS_ERR(client)) {
+		pr_err("%s: couldn't open oem rapi client\n", __func__);
+		return PTR_ERR(client);
+	} else
+		pr_info("%s: connected to remote oem rapi server\n", __func__);
+
+	return 0;
+}
+
+static const struct file_operations debug_ops = {
+	.owner = THIS_MODULE,
+	.open = debug_open,
+	.release = debug_release,
+	.read = debug_read,
+	.write = debug_write,
+};
+
+static void __exit oem_rapi_client_mod_exit(void)
+{
+	debugfs_remove(dent);
+}
+
+static int __init oem_rapi_client_mod_init(void)
+{
+	dent = debugfs_create_file("oem_rapi", 0444, 0, NULL, &debug_ops);
+	open_count = 0;
+	oem_rapi_client_test_res = -1;
+	return 0;
+}
+
+module_init(oem_rapi_client_mod_init);
+module_exit(oem_rapi_client_mod_exit);
+
+#endif
+
+MODULE_DESCRIPTION("OEM RAPI CLIENT Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pcie.c b/arch/arm/mach-msm/pcie.c
new file mode 100644
index 0000000..f0809d3
--- /dev/null
+++ b/arch/arm/mach-msm/pcie.c
@@ -0,0 +1,671 @@
+/* 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.
+ */
+
+/*
+ * MSM PCIe controller driver.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+#include <asm/mach/pci.h>
+#include <mach/gpiomux.h>
+#include <mach/hardware.h>
+#include <mach/msm_iomap.h>
+
+#include "pcie.h"
+
+/* Root Complex Port vendor/device IDs */
+#define PCIE_VENDOR_ID_RCP             0x17cb
+#define PCIE_DEVICE_ID_RCP             0x0101
+
+#define PCIE20_PARF_PCS_DEEMPH         0x34
+#define PCIE20_PARF_PCS_SWING          0x38
+#define PCIE20_PARF_PHY_CTRL           0x40
+#define PCIE20_PARF_PHY_REFCLK         0x4C
+#define PCIE20_PARF_CONFIG_BITS        0x50
+
+#define PCIE20_ELBI_SYS_CTRL           0x04
+
+#define PCIE20_CAP                     0x70
+#define PCIE20_CAP_LINKCTRLSTATUS      (PCIE20_CAP + 0x10)
+
+#define PCIE20_COMMAND_STATUS          0x04
+#define PCIE20_BUSNUMBERS              0x18
+#define PCIE20_MEMORY_BASE_LIMIT       0x20
+
+#define PCIE20_PLR_IATU_VIEWPORT       0x900
+#define PCIE20_PLR_IATU_CTRL1          0x904
+#define PCIE20_PLR_IATU_CTRL2          0x908
+#define PCIE20_PLR_IATU_LBAR           0x90C
+#define PCIE20_PLR_IATU_UBAR           0x910
+#define PCIE20_PLR_IATU_LAR            0x914
+#define PCIE20_PLR_IATU_LTAR           0x918
+#define PCIE20_PLR_IATU_UTAR           0x91c
+
+#define PCIE_RESET                     (MSM_CLK_CTL_BASE + 0x22dc)
+#define PCIE_SFAB_AXI_S5_FCLK_CTL      (MSM_CLK_CTL_BASE + 0x2154)
+
+#define MSM_PCIE_DEV_BAR_ADDR          PCIBIOS_MIN_MEM
+#define MSM_PCIE_DEV_CFG_ADDR          0x01000000
+
+#define RD 0
+#define WR 1
+
+/* debug mask sys interface */
+static int msm_pcie_debug_mask;
+module_param_named(debug_mask, msm_pcie_debug_mask,
+			    int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+/* resources from device file */
+enum msm_pcie_res {
+	MSM_PCIE_RES_PARF,
+	MSM_PCIE_RES_ELBI,
+	MSM_PCIE_RES_PCIE20,
+	MSM_PCIE_RES_AXI_BAR,
+	MSM_PCIE_RES_AXI_CONF,
+	MSM_PCIE_MAX_RES
+};
+
+/* msm pcie device data */
+static struct msm_pcie_dev_t msm_pcie_dev;
+
+/* regulators */
+static struct msm_pcie_vreg_info_t msm_pcie_vreg_info[MSM_PCIE_MAX_VREG] = {
+	{NULL, "vp_pcie",      1050000, 1050000, 40900},
+	{NULL, "vptx_pcie",    1050000, 1050000, 18200},
+	{NULL, "vdd_pcie_vph",       0,       0,     0},
+	{NULL, "pcie_ext_3p3v",      0,       0,     0}
+};
+
+/* clocks */
+static struct msm_pcie_clk_info_t msm_pcie_clk_info[MSM_PCIE_MAX_CLK] = {
+	{NULL, "bus_clk"},
+	{NULL, "iface_clk"},
+	{NULL, "ref_clk"}
+};
+
+/* resources */
+static struct msm_pcie_res_info_t msm_pcie_res_info[MSM_PCIE_MAX_RES] = {
+	{"parf",     0, 0, 0},
+	{"elbi",     0, 0, 0},
+	{"pcie20",   0, 0, 0},
+	{"axi_bar",  0, 0, 0},
+	{"axi_conf", 0, 0, 0},
+};
+
+int msm_pcie_get_debug_mask(void)
+{
+	return msm_pcie_debug_mask;
+}
+
+static void msm_pcie_write_mask(void __iomem *addr,
+				uint32_t clear_mask, uint32_t set_mask)
+{
+	uint32_t val;
+
+	val = (readl_relaxed(addr) & ~clear_mask) | set_mask;
+	writel_relaxed(val, addr);
+	wmb();  /* ensure data is written to hardware register */
+}
+
+static int msm_pcie_is_link_up(void)
+{
+	return readl_relaxed(msm_pcie_dev.pcie20 + PCIE20_CAP_LINKCTRLSTATUS) &
+				BIT(29);
+}
+
+static inline int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper,
+				     int where, int size, u32 *val)
+{
+	uint32_t word_offset, byte_offset, mask;
+	uint32_t rd_val, wr_val;
+	struct msm_pcie_dev_t *dev = &msm_pcie_dev;
+	void __iomem *config_base;
+
+	/*
+	 * Only buses 0 and 1 are supported. RC port on bus 0 and EP in bus 1.
+	 * For downstream bus (1), make sure link is up
+	 */
+	if ((bus->number > 1) || (devfn != 0)) {
+		PCIE_DBG("invalid %s - bus %d devfn %d\n",
+			 (oper == RD) ? "rd" : "wr", bus->number, devfn);
+		*val = ~0;
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	} else if ((bus->number != 0) && !msm_pcie_is_link_up()) {
+		PCIE_DBG("%s fail, link down - bus %d devfn %d\n",
+			 (oper == RD) ? "rd" : "wr", bus->number, devfn);
+		*val = ~0;
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+
+	word_offset = where & ~0x3;
+	byte_offset = where & 0x3;
+	mask = (~0 >> (8 * (4 - size))) << (8 * byte_offset);
+
+	config_base = (bus->number == 0) ? dev->pcie20 : dev->axi_conf;
+	rd_val = readl_relaxed(config_base + word_offset);
+
+	if (oper == RD) {
+		*val = ((rd_val & mask) >> (8 * byte_offset));
+
+		PCIE_DBG("%d:0x%02x + 0x%04x[%d] -> 0x%08x; rd 0x%08x\n",
+			 bus->number, devfn, where, size, *val, rd_val);
+	} else {
+		wr_val = (rd_val & ~mask) |
+				((*val << (8 * byte_offset)) & mask);
+		writel_relaxed(wr_val, config_base + word_offset);
+		wmb(); /* ensure config data is written to hardware register */
+
+		PCIE_DBG("%d:0x%02x + 0x%04x[%d] <- 0x%08x;"
+			 " rd 0x%08x val 0x%08x\n", bus->number,
+			 devfn, where, size, wr_val, rd_val, *val);
+	}
+
+	return 0;
+}
+
+static int msm_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
+			    int size, u32 *val)
+{
+	return msm_pcie_oper_conf(bus, devfn, RD, where, size, val);
+}
+
+static int msm_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
+			    int where, int size, u32 val)
+{
+	return msm_pcie_oper_conf(bus, devfn, WR, where, size, &val);
+}
+
+static struct pci_ops msm_pcie_ops = {
+	.read = msm_pcie_rd_conf,
+	.write = msm_pcie_wr_conf,
+};
+
+static int __init msm_pcie_gpio_init(void)
+{
+	int rc, i;
+	struct msm_pcie_gpio_info_t *info;
+
+	for (i = 0; i < MSM_PCIE_MAX_GPIO; i++) {
+		info = &msm_pcie_dev.gpio[i];
+
+		rc = gpio_request(info->num, info->name);
+		if (rc) {
+			pr_err("can't get gpio %s; %d\n", info->name, rc);
+			break;
+		}
+
+		rc = gpio_direction_output(info->num, 0);
+		if (rc) {
+			pr_err("can't set gpio direction %s; %d\n",
+			       info->name, rc);
+			gpio_free(info->num);
+			break;
+		}
+	}
+
+	if (rc)
+		while (i--)
+			gpio_free(msm_pcie_dev.gpio[i].num);
+
+	return rc;
+}
+
+static void msm_pcie_gpio_deinit(void)
+{
+	int i;
+
+	for (i = 0; i < MSM_PCIE_MAX_GPIO; i++)
+		gpio_free(msm_pcie_dev.gpio[i].num);
+}
+
+static int __init msm_pcie_vreg_init(struct device *dev)
+{
+	int i, rc = 0;
+	struct regulator *vreg;
+	struct msm_pcie_vreg_info_t *info;
+
+	for (i = 0; i < MSM_PCIE_MAX_VREG; i++) {
+		info = &msm_pcie_dev.vreg[i];
+
+		vreg = regulator_get(dev, info->name);
+		if (!vreg || IS_ERR(vreg)) {
+			rc = (PTR_ERR(vreg)) ? PTR_ERR(vreg) : -ENODEV;
+			pr_err("can't get %s; %d\n", info->name, rc);
+			break;
+		}
+
+		if (info->max_v) {
+			rc = regulator_set_voltage(vreg,
+						   info->min_v, info->max_v);
+			if (rc) {
+				pr_err("can't set voltage %s; %d\n",
+				       info->name, rc);
+				regulator_put(vreg);
+				break;
+			}
+		}
+
+		if (info->opt_mode) {
+			rc = regulator_set_optimum_mode(vreg, info->opt_mode);
+			if (rc < 0) {
+				pr_err("can't set mode %s; %d\n",
+				       info->name, rc);
+				regulator_put(vreg);
+				break;
+			}
+		}
+
+		rc = regulator_enable(vreg);
+		if (rc) {
+			pr_err("can't enable %s, %d\n", info->name, rc);
+			regulator_put(vreg);
+			break;
+		}
+		info->hdl = vreg;
+	}
+
+	if (rc)
+		while (i--) {
+			regulator_disable(msm_pcie_dev.vreg[i].hdl);
+			regulator_put(msm_pcie_dev.vreg[i].hdl);
+			msm_pcie_dev.vreg[i].hdl = NULL;
+		}
+
+	return rc;
+}
+
+static void msm_pcie_vreg_deinit(void)
+{
+	int i;
+
+	for (i = 0; i < MSM_PCIE_MAX_VREG; i++) {
+		regulator_disable(msm_pcie_dev.vreg[i].hdl);
+		regulator_put(msm_pcie_dev.vreg[i].hdl);
+		msm_pcie_dev.vreg[i].hdl = NULL;
+	}
+}
+
+static int __init msm_pcie_clk_init(struct device *dev)
+{
+	int i, rc = 0;
+	struct clk *clk_hdl;
+	struct msm_pcie_clk_info_t *info;
+
+	for (i = 0; i < MSM_PCIE_MAX_CLK; i++) {
+		info = &msm_pcie_dev.clk[i];
+
+		clk_hdl = clk_get(dev, info->name);
+		if (!clk_hdl || IS_ERR(clk_hdl)) {
+			rc = (PTR_ERR(clk_hdl)) ? PTR_ERR(clk_hdl) : -ENODEV;
+			pr_err("can't get clk %s; %d\n", info->name, rc);
+			break;
+		}
+		clk_prepare_enable(clk_hdl);
+		info->hdl = clk_hdl;
+	}
+
+	if (rc)
+		while (i--) {
+			clk_disable_unprepare(msm_pcie_dev.clk[i].hdl);
+			clk_put(msm_pcie_dev.clk[i].hdl);
+			msm_pcie_dev.clk[i].hdl = NULL;
+		}
+
+	return rc;
+}
+
+static void msm_pcie_clk_deinit(void)
+{
+	int i;
+
+	for (i = 0; i < MSM_PCIE_MAX_CLK; i++) {
+		clk_disable_unprepare(msm_pcie_dev.clk[i].hdl);
+		clk_put(msm_pcie_dev.clk[i].hdl);
+		msm_pcie_dev.clk[i].hdl = NULL;
+	}
+}
+
+static void __init msm_pcie_config_controller(void)
+{
+	struct msm_pcie_dev_t *dev = &msm_pcie_dev;
+	struct msm_pcie_res_info_t *axi_bar = &dev->res[MSM_PCIE_RES_AXI_BAR];
+	struct msm_pcie_res_info_t *axi_conf = &dev->res[MSM_PCIE_RES_AXI_CONF];
+
+	/*
+	 * program and enable address translation region 0 (device config
+	 * address space); region type config;
+	 * axi config address range to device config address range
+	 */
+	writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_VIEWPORT);
+	/* ensure that hardware locks the region before programming it */
+	wmb();
+
+	writel_relaxed(4, dev->pcie20 + PCIE20_PLR_IATU_CTRL1);
+	writel_relaxed(BIT(31), dev->pcie20 + PCIE20_PLR_IATU_CTRL2);
+	writel_relaxed(axi_conf->start, dev->pcie20 + PCIE20_PLR_IATU_LBAR);
+	writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_UBAR);
+	writel_relaxed(axi_conf->end, dev->pcie20 + PCIE20_PLR_IATU_LAR);
+	writel_relaxed(MSM_PCIE_DEV_CFG_ADDR,
+		       dev->pcie20 + PCIE20_PLR_IATU_LTAR);
+	writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_UTAR);
+	/* ensure that hardware registers the configuration */
+	wmb();
+
+	/*
+	 * program and enable address translation region 2 (device resource
+	 * address space); region type memory;
+	 * axi device bar address range to device bar address range
+	 */
+	writel_relaxed(2, dev->pcie20 + PCIE20_PLR_IATU_VIEWPORT);
+	/* ensure that hardware locks the region before programming it */
+	wmb();
+
+	writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_CTRL1);
+	writel_relaxed(BIT(31), dev->pcie20 + PCIE20_PLR_IATU_CTRL2);
+	writel_relaxed(axi_bar->start, dev->pcie20 + PCIE20_PLR_IATU_LBAR);
+	writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_UBAR);
+	writel_relaxed(axi_bar->end, dev->pcie20 + PCIE20_PLR_IATU_LAR);
+	writel_relaxed(MSM_PCIE_DEV_BAR_ADDR,
+		       dev->pcie20 + PCIE20_PLR_IATU_LTAR);
+	writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_UTAR);
+	/* ensure that hardware registers the configuration */
+	wmb();
+}
+
+static int __init msm_pcie_get_resources(struct platform_device *pdev)
+{
+	int i, rc = 0;
+	struct resource *res;
+	struct msm_pcie_res_info_t *info;
+	struct msm_pcie_dev_t *dev = &msm_pcie_dev;
+
+	for (i = 0; i < MSM_PCIE_MAX_RES; i++) {
+		info = &dev->res[i];
+
+		res = platform_get_resource_byname(pdev,
+						   IORESOURCE_MEM, info->name);
+		if (!res) {
+			pr_err("can't get %s resource\n", info->name);
+			rc = -ENOMEM;
+			break;
+		}
+
+		info->base = ioremap(res->start, resource_size(res));
+		if (!info->base) {
+			pr_err("can't remap %s\n", info->name);
+			rc = -ENOMEM;
+			break;
+		}
+
+		info->start = res->start;
+		info->end = res->end;
+	}
+
+	if (rc) {
+		while (i--) {
+			iounmap(dev->res[i].base);
+			dev->res[i].base = NULL;
+		}
+	} else {
+		dev->parf = dev->res[MSM_PCIE_RES_PARF].base;
+		dev->elbi = dev->res[MSM_PCIE_RES_ELBI].base;
+		dev->pcie20 = dev->res[MSM_PCIE_RES_PCIE20].base;
+		dev->axi_conf = dev->res[MSM_PCIE_RES_AXI_CONF].base;
+	}
+
+	return rc;
+}
+
+static void msm_pcie_release_resources(void)
+{
+	int i;
+
+	for (i = 0; i < MSM_PCIE_MAX_RES; i++) {
+		iounmap(msm_pcie_dev.res[i].base);
+		msm_pcie_dev.res[i].base = NULL;
+	}
+
+	msm_pcie_dev.parf = NULL;
+	msm_pcie_dev.elbi = NULL;
+	msm_pcie_dev.pcie20 = NULL;
+	msm_pcie_dev.axi_conf = NULL;
+}
+
+static int __init msm_pcie_setup(int nr, struct pci_sys_data *sys)
+{
+	int rc;
+	struct msm_pcie_dev_t *dev = &msm_pcie_dev;
+	uint32_t val;
+
+	PCIE_DBG("bus %d\n", nr);
+	if (nr != 0)
+		return 0;
+
+	/* assert PCIe reset link to keep EP in reset */
+	gpio_set_value_cansleep(dev->gpio[MSM_PCIE_GPIO_RST_N].num,
+				dev->gpio[MSM_PCIE_GPIO_RST_N].on);
+
+	/* enable power */
+	rc = msm_pcie_vreg_init(&dev->pdev->dev);
+	if (rc)
+		goto out;
+
+	/* assert PCIe PARF reset while powering the core */
+	msm_pcie_write_mask(PCIE_RESET, 0, BIT(2));
+
+	/* enable clocks */
+	rc = msm_pcie_clk_init(&dev->pdev->dev);
+	if (rc)
+		goto clk_fail;
+
+	/* enable pcie power; wait 3ms for clock to stabilize */
+	gpio_set_value_cansleep(dev->gpio[MSM_PCIE_GPIO_PWR_EN].num,
+				dev->gpio[MSM_PCIE_GPIO_PWR_EN].on);
+	usleep(3000);
+
+	/*
+	 * de-assert PCIe PARF reset;
+	 * wait 1us before accessing PARF registers
+	 */
+	msm_pcie_write_mask(PCIE_RESET, BIT(2), 0);
+	udelay(1);
+
+	/* enable PCIe clocks and resets */
+	msm_pcie_write_mask(dev->parf + PCIE20_PARF_PHY_CTRL, BIT(0), 0);
+
+	/* PARF programming */
+	writel_relaxed(0x282828, dev->parf + PCIE20_PARF_PCS_DEEMPH);
+	writel_relaxed(0x7F7F, dev->parf + PCIE20_PARF_PCS_SWING);
+	writel_relaxed((4<<24), dev->parf + PCIE20_PARF_CONFIG_BITS);
+	/* ensure that hardware registers the PARF configuration */
+	wmb();
+
+	/* enable reference clock */
+	msm_pcie_write_mask(dev->parf + PCIE20_PARF_PHY_REFCLK, 0, BIT(16));
+
+	/* enable access to PCIe slave port on system fabric */
+	writel_relaxed(BIT(4), PCIE_SFAB_AXI_S5_FCLK_CTL);
+	/* ensure that access is enabled before proceeding */
+	wmb();
+
+	/* de-assert PICe PHY, Core, POR and AXI clk domain resets */
+	msm_pcie_write_mask(PCIE_RESET, BIT(5), 0);
+	msm_pcie_write_mask(PCIE_RESET, BIT(4), 0);
+	msm_pcie_write_mask(PCIE_RESET, BIT(3), 0);
+	msm_pcie_write_mask(PCIE_RESET, BIT(0), 0);
+
+	/* wait 150ms for clock acquisition */
+	udelay(150);
+
+	/* de-assert PCIe reset link to bring EP out of reset */
+	gpio_set_value_cansleep(dev->gpio[MSM_PCIE_GPIO_RST_N].num,
+				!dev->gpio[MSM_PCIE_GPIO_RST_N].on);
+
+	/* enable link training */
+	msm_pcie_write_mask(dev->elbi + PCIE20_ELBI_SYS_CTRL, 0, BIT(0));
+
+	/* poll for link to come up for upto 100ms */
+	rc = readl_poll_timeout(
+			(msm_pcie_dev.pcie20 + PCIE20_CAP_LINKCTRLSTATUS),
+			val, (val & BIT(29)), 10000, 100000);
+	if (rc) {
+		pr_err("link initialization failed\n");
+		goto link_fail;
+	} else
+		pr_info("link initialized\n");
+
+	msm_pcie_config_controller();
+	rc = msm_pcie_irq_init(dev);
+	if (!rc)
+		goto out;
+
+link_fail:
+	msm_pcie_clk_deinit();
+clk_fail:
+	msm_pcie_vreg_deinit();
+out:
+	return (rc) ? 0 : 1;
+}
+
+static struct pci_bus __init *msm_pcie_scan_bus(int nr,
+						struct pci_sys_data *sys)
+{
+	struct pci_bus *bus = NULL;
+
+	PCIE_DBG("bus %d\n", nr);
+	if (nr == 0)
+		bus = pci_scan_bus(sys->busnr, &msm_pcie_ops, sys);
+
+	return bus;
+}
+
+static int __init msm_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+	PCIE_DBG("slot %d pin %d\n", slot, pin);
+	return (pin <= 4) ? (PCIE20_INTA + pin - 1) : 0;
+}
+
+static struct hw_pci msm_pci __initdata = {
+	.nr_controllers = 1,
+	.swizzle = pci_std_swizzle,
+	.setup = msm_pcie_setup,
+	.scan = msm_pcie_scan_bus,
+	.map_irq = msm_pcie_map_irq,
+};
+
+static int __init msm_pcie_probe(struct platform_device *pdev)
+{
+	const struct msm_pcie_platform *pdata;
+	int rc;
+
+	PCIE_DBG("\n");
+
+	msm_pcie_dev.pdev = pdev;
+	pdata = pdev->dev.platform_data;
+	msm_pcie_dev.gpio = pdata->gpio;
+	msm_pcie_dev.vreg = msm_pcie_vreg_info;
+	msm_pcie_dev.clk = msm_pcie_clk_info;
+	msm_pcie_dev.res = msm_pcie_res_info;
+
+	rc = msm_pcie_get_resources(msm_pcie_dev.pdev);
+	if (rc)
+		return rc;
+
+	rc = msm_pcie_gpio_init();
+	if (rc) {
+		msm_pcie_release_resources();
+		return rc;
+	}
+
+	/* kick start ARM PCI configuration framework */
+	pci_common_init(&msm_pci);
+	return 0;
+}
+
+static int __exit msm_pcie_remove(struct platform_device *pdev)
+{
+	PCIE_DBG("\n");
+
+	msm_pcie_irq_deinit(&msm_pcie_dev);
+	msm_pcie_vreg_deinit();
+	msm_pcie_clk_deinit();
+	msm_pcie_gpio_deinit();
+	msm_pcie_release_resources();
+
+	msm_pcie_dev.pdev = NULL;
+	msm_pcie_dev.vreg = NULL;
+	msm_pcie_dev.clk = NULL;
+	msm_pcie_dev.gpio = NULL;
+	return 0;
+}
+
+static struct platform_driver msm_pcie_driver = {
+	.remove = __exit_p(msm_pcie_remove),
+	.driver = {
+		.name = "msm_pcie",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_pcie_init(void)
+{
+	PCIE_DBG("\n");
+	pcibios_min_io = 0x10000000;
+	pcibios_min_mem = 0x10000000;
+	return platform_driver_probe(&msm_pcie_driver, msm_pcie_probe);
+}
+subsys_initcall(msm_pcie_init);
+
+/* RC do not represent the right class; set it to PCI_CLASS_BRIDGE_PCI */
+static void __devinit msm_pcie_fixup_header(struct pci_dev *dev)
+{
+	PCIE_DBG("hdr_type %d\n", dev->hdr_type);
+	if (dev->hdr_type == 1)
+		dev->class = (dev->class & 0xff) | (PCI_CLASS_BRIDGE_PCI << 8);
+}
+DECLARE_PCI_FIXUP_HEADER(PCIE_VENDOR_ID_RCP, PCIE_DEVICE_ID_RCP,
+			 msm_pcie_fixup_header);
+
+/*
+ * actual physical (BAR) address of the device resources starts from 0x10xxxxxx;
+ * the system axi address for the device resources starts from 0x08xxxxxx;
+ * correct the device resource structure here; address translation unit handles
+ * the required translations
+ */
+static void __devinit msm_pcie_fixup_final(struct pci_dev *dev)
+{
+	int i;
+
+	PCIE_DBG("vendor 0x%x 0x%x\n", dev->vendor, dev->device);
+	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+		if (dev->resource[i].start & 0xFF000000) {
+			dev->resource[i].start &= 0x00FFFFFF;
+			dev->resource[i].start |= 0x08000000;
+			dev->resource[i].end &= 0x00FFFFFF;
+			dev->resource[i].end |= 0x08000000;
+		}
+	}
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, msm_pcie_fixup_final);
diff --git a/arch/arm/mach-msm/pcie.h b/arch/arm/mach-msm/pcie.h
new file mode 100644
index 0000000..4866ec5
--- /dev/null
+++ b/arch/arm/mach-msm/pcie.h
@@ -0,0 +1,73 @@
+/* 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 __ARCH_ARM_MACH_MSM_PCIE_H
+#define __ARCH_ARM_MACH_MSM_PCIE_H
+
+#include <linux/clk.h>
+#include <linux/compiler.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+#include <mach/msm_pcie.h>
+
+#define MSM_PCIE_MAX_VREG 4
+#define MSM_PCIE_MAX_CLK  3
+
+#define PCIE_DBG(x...) do {              \
+	if (msm_pcie_get_debug_mask())   \
+		pr_info(x);              \
+	} while (0)
+
+/* voltage regulator info structrue */
+struct msm_pcie_vreg_info_t {
+	struct regulator  *hdl;
+	char              *name;
+	uint32_t           max_v;
+	uint32_t           min_v;
+	uint32_t           opt_mode;
+};
+
+/* clock info structure */
+struct msm_pcie_clk_info_t {
+	struct clk  *hdl;
+	char        *name;
+};
+
+/* resource info structure */
+struct msm_pcie_res_info_t {
+	char          *name;
+	uint32_t       start;
+	uint32_t       end;
+	void __iomem  *base;
+};
+
+/* msm pcie device structure */
+struct msm_pcie_dev_t {
+	struct platform_device       *pdev;
+
+	struct msm_pcie_vreg_info_t  *vreg;
+	struct msm_pcie_gpio_info_t  *gpio;
+	struct msm_pcie_clk_info_t   *clk;
+	struct msm_pcie_res_info_t   *res;
+
+	void __iomem                 *parf;
+	void __iomem                 *elbi;
+	void __iomem                 *pcie20;
+	void __iomem                 *axi_conf;
+};
+
+extern uint32_t msm_pcie_irq_init(struct msm_pcie_dev_t *dev);
+extern void msm_pcie_irq_deinit(struct msm_pcie_dev_t *dev);
+extern int msm_pcie_get_debug_mask(void);
+
+#endif
diff --git a/arch/arm/mach-msm/pcie_irq.c b/arch/arm/mach-msm/pcie_irq.c
new file mode 100644
index 0000000..d915561
--- /dev/null
+++ b/arch/arm/mach-msm/pcie_irq.c
@@ -0,0 +1,170 @@
+/* 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.
+ */
+
+/*
+ * MSM PCIe controller IRQ driver.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/msi.h>
+#include <linux/pci.h>
+#include <mach/irqs.h>
+
+#include "pcie.h"
+
+/* Any address will do here, as it won't be dereferenced */
+#define MSM_PCIE_MSI_PHY 0xa0000000
+
+#define PCIE20_MSI_CTRL_ADDR            (0x820)
+#define PCIE20_MSI_CTRL_UPPER_ADDR      (0x824)
+#define PCIE20_MSI_CTRL_INTR_EN         (0x828)
+#define PCIE20_MSI_CTRL_INTR_MASK       (0x82C)
+#define PCIE20_MSI_CTRL_INTR_STATUS     (0x830)
+
+#define PCIE20_MSI_CTRL_MAX 8
+
+static DECLARE_BITMAP(msi_irq_in_use, NR_PCIE_MSI_IRQS);
+
+irqreturn_t handle_msi_irq(int irq, void *data)
+{
+	int i, j;
+	unsigned long val;
+	struct msm_pcie_dev_t *dev = data;
+	void __iomem *ctrl_status;
+
+	/* check for set bits, clear it by setting that bit
+	   and trigger corresponding irq */
+	for (i = 0; i < PCIE20_MSI_CTRL_MAX; i++) {
+		ctrl_status = dev->pcie20 +
+				PCIE20_MSI_CTRL_INTR_STATUS + (i * 12);
+
+		val = readl_relaxed(ctrl_status);
+		while (val) {
+			j = find_first_bit(&val, 32);
+			writel_relaxed(BIT(j), ctrl_status);
+			/* ensure that interrupt is cleared (acked) */
+			wmb();
+
+			generic_handle_irq(MSM_PCIE_MSI_INT(j + (32 * i)));
+			val = readl_relaxed(ctrl_status);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+uint32_t __init msm_pcie_irq_init(struct msm_pcie_dev_t *dev)
+{
+	int i, rc;
+
+	PCIE_DBG("\n");
+
+	/* program MSI controller and enable all interrupts */
+	writel_relaxed(MSM_PCIE_MSI_PHY, dev->pcie20 + PCIE20_MSI_CTRL_ADDR);
+	writel_relaxed(0, dev->pcie20 + PCIE20_MSI_CTRL_UPPER_ADDR);
+
+	for (i = 0; i < PCIE20_MSI_CTRL_MAX; i++)
+		writel_relaxed(~0, dev->pcie20 +
+			       PCIE20_MSI_CTRL_INTR_EN + (i * 12));
+
+	/* ensure that hardware is configured before proceeding */
+	wmb();
+
+	/* register handler for physical MSI interrupt line */
+	rc = request_irq(PCIE20_INT_MSI, handle_msi_irq, IRQF_TRIGGER_RISING,
+			 "msm_pcie_msi", dev);
+	if (rc)
+		pr_err("Unable to allocate msi interrupt\n");
+
+	return rc;
+}
+
+void __exit msm_pcie_irq_deinit(struct msm_pcie_dev_t *dev)
+{
+	free_irq(PCIE20_INT_MSI, dev);
+}
+
+void msm_pcie_destroy_irq(unsigned int irq)
+{
+	int pos = irq - MSM_PCIE_MSI_INT(0);
+
+	dynamic_irq_cleanup(irq);
+	clear_bit(pos, msi_irq_in_use);
+}
+
+/* hookup to linux pci msi framework */
+void arch_teardown_msi_irq(unsigned int irq)
+{
+	PCIE_DBG("irq %d deallocated\n", irq);
+	msm_pcie_destroy_irq(irq);
+}
+
+static void msm_pcie_msi_nop(struct irq_data *d)
+{
+	return;
+}
+
+static struct irq_chip pcie_msi_chip = {
+	.name = "msm-pcie-msi",
+	.irq_ack = msm_pcie_msi_nop,
+	.irq_enable = unmask_msi_irq,
+	.irq_disable = mask_msi_irq,
+	.irq_mask = mask_msi_irq,
+	.irq_unmask = unmask_msi_irq,
+};
+
+static int msm_pcie_create_irq(void)
+{
+	int irq, pos;
+
+again:
+	pos = find_first_zero_bit(msi_irq_in_use, NR_PCIE_MSI_IRQS);
+	irq = MSM_PCIE_MSI_INT(pos);
+	if (irq >= (MSM_PCIE_MSI_INT(0) + NR_PCIE_MSI_IRQS))
+		return -ENOSPC;
+
+	if (test_and_set_bit(pos, msi_irq_in_use))
+		goto again;
+
+	dynamic_irq_init(irq);
+	return irq;
+}
+
+/* hookup to linux pci msi framework */
+int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
+{
+	int irq;
+	struct msi_msg msg;
+
+	irq = msm_pcie_create_irq();
+	if (irq < 0)
+		return irq;
+
+	PCIE_DBG("irq %d allocated\n", irq);
+
+	irq_set_msi_desc(irq, desc);
+
+	/* write msi vector and data */
+	msg.address_hi = 0;
+	msg.address_lo = MSM_PCIE_MSI_PHY;
+	msg.data = irq - MSM_PCIE_MSI_INT(0);
+	write_msi_msg(irq, &msg);
+
+	irq_set_chip_and_handler(irq, &pcie_msi_chip, handle_simple_irq);
+	set_irq_flags(irq, IRQF_VALID);
+	return 0;
+}
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
new file mode 100644
index 0000000..bfbf4bc
--- /dev/null
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -0,0 +1,687 @@
+/* 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
+ * 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/module.h>
+#include <linux/string.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/io.h>
+#include <linux/debugfs.h>
+#include <linux/elf.h>
+#include <linux/mutex.h>
+#include <linux/memblock.h>
+#include <linux/slab.h>
+#include <linux/atomic.h>
+#include <linux/suspend.h>
+#include <linux/rwsem.h>
+#include <linux/sysfs.h>
+#include <linux/workqueue.h>
+#include <linux/jiffies.h>
+#include <linux/wakelock.h>
+
+#include <asm/uaccess.h>
+#include <asm/setup.h>
+#include <mach/peripheral-loader.h>
+
+#include "peripheral-loader.h"
+
+enum pil_state {
+	PIL_OFFLINE,
+	PIL_ONLINE,
+};
+
+static const char *pil_states[] = {
+	[PIL_OFFLINE] = "OFFLINE",
+	[PIL_ONLINE] = "ONLINE",
+};
+
+struct pil_device {
+	struct pil_desc *desc;
+	int count;
+	enum pil_state state;
+	struct mutex lock;
+	struct device dev;
+	struct module *owner;
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+	struct delayed_work proxy;
+	struct wake_lock wlock;
+	char wake_name[32];
+};
+
+#define to_pil_device(d) container_of(d, struct pil_device, dev)
+
+static ssize_t name_show(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%s\n", to_pil_device(dev)->desc->name);
+}
+
+static ssize_t state_show(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	enum pil_state state = to_pil_device(dev)->state;
+	return snprintf(buf, PAGE_SIZE, "%s\n", pil_states[state]);
+}
+
+static struct device_attribute pil_attrs[] = {
+	__ATTR_RO(name),
+	__ATTR_RO(state),
+	{ },
+};
+
+struct bus_type pil_bus_type = {
+	.name		= "pil",
+	.dev_attrs	= pil_attrs,
+};
+
+static int __find_peripheral(struct device *dev, void *data)
+{
+	struct pil_device *pdev = to_pil_device(dev);
+	return !strncmp(pdev->desc->name, data, INT_MAX);
+}
+
+static struct pil_device *find_peripheral(const char *str)
+{
+	struct device *dev;
+
+	if (!str)
+		return NULL;
+
+	dev = bus_find_device(&pil_bus_type, NULL, (void *)str,
+			__find_peripheral);
+	return dev ? to_pil_device(dev) : NULL;
+}
+
+static void pil_proxy_work(struct work_struct *work)
+{
+	struct pil_device *pil;
+
+	pil = container_of(work, struct pil_device, proxy.work);
+	pil->desc->ops->proxy_unvote(pil->desc);
+	wake_unlock(&pil->wlock);
+}
+
+static int pil_proxy_vote(struct pil_device *pil)
+{
+	if (pil->desc->ops->proxy_vote) {
+		wake_lock(&pil->wlock);
+		return pil->desc->ops->proxy_vote(pil->desc);
+	}
+	return 0;
+}
+
+static void pil_proxy_unvote(struct pil_device *pil, unsigned long timeout)
+{
+	if (pil->desc->ops->proxy_unvote)
+		schedule_delayed_work(&pil->proxy, msecs_to_jiffies(timeout));
+}
+
+#define IOMAP_SIZE SZ_4M
+
+static int load_segment(const struct elf32_phdr *phdr, unsigned num,
+		struct pil_device *pil)
+{
+	int ret = 0, count, paddr;
+	char fw_name[30];
+	const struct firmware *fw = NULL;
+	const u8 *data;
+
+	if (memblock_overlaps_memory(phdr->p_paddr, phdr->p_memsz)) {
+		dev_err(&pil->dev, "%s: kernel memory would be overwritten "
+			"[%#08lx, %#08lx)\n", pil->desc->name,
+			(unsigned long)phdr->p_paddr,
+			(unsigned long)(phdr->p_paddr + phdr->p_memsz));
+		return -EPERM;
+	}
+
+	if (phdr->p_filesz) {
+		snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d",
+				pil->desc->name, num);
+		ret = request_firmware(&fw, fw_name, &pil->dev);
+		if (ret) {
+			dev_err(&pil->dev, "%s: Failed to locate blob %s\n",
+					pil->desc->name, fw_name);
+			return ret;
+		}
+
+		if (fw->size != phdr->p_filesz) {
+			dev_err(&pil->dev, "%s: Blob size %u doesn't match "
+					"%u\n", pil->desc->name, fw->size,
+					phdr->p_filesz);
+			ret = -EPERM;
+			goto release_fw;
+		}
+	}
+
+	/* Load the segment into memory */
+	count = phdr->p_filesz;
+	paddr = phdr->p_paddr;
+	data = fw ? fw->data : NULL;
+	while (count > 0) {
+		int size;
+		u8 __iomem *buf;
+
+		size = min_t(size_t, IOMAP_SIZE, count);
+		buf = ioremap(paddr, size);
+		if (!buf) {
+			dev_err(&pil->dev, "%s: Failed to map memory\n",
+					pil->desc->name);
+			ret = -ENOMEM;
+			goto release_fw;
+		}
+		memcpy(buf, data, size);
+		iounmap(buf);
+
+		count -= size;
+		paddr += size;
+		data += size;
+	}
+
+	/* Zero out trailing memory */
+	count = phdr->p_memsz - phdr->p_filesz;
+	while (count > 0) {
+		int size;
+		u8 __iomem *buf;
+
+		size = min_t(size_t, IOMAP_SIZE, count);
+		buf = ioremap(paddr, size);
+		if (!buf) {
+			dev_err(&pil->dev, "%s: Failed to map memory\n",
+					pil->desc->name);
+			ret = -ENOMEM;
+			goto release_fw;
+		}
+		memset(buf, 0, size);
+		iounmap(buf);
+
+		count -= size;
+		paddr += size;
+	}
+
+	if (pil->desc->ops->verify_blob) {
+		ret = pil->desc->ops->verify_blob(pil->desc, phdr->p_paddr,
+					  phdr->p_memsz);
+		if (ret)
+			dev_err(&pil->dev, "%s: Blob%u failed verification\n",
+				pil->desc->name, num);
+	}
+
+release_fw:
+	release_firmware(fw);
+	return ret;
+}
+
+#define segment_is_hash(flag) (((flag) & (0x7 << 24)) == (0x2 << 24))
+
+static int segment_is_loadable(const struct elf32_phdr *p)
+{
+	return (p->p_type & PT_LOAD) && !segment_is_hash(p->p_flags);
+}
+
+/* Sychronize request_firmware() with suspend */
+static DECLARE_RWSEM(pil_pm_rwsem);
+
+static int load_image(struct pil_device *pil)
+{
+	int i, ret;
+	char fw_name[30];
+	struct elf32_hdr *ehdr;
+	const struct elf32_phdr *phdr;
+	const struct firmware *fw;
+	unsigned long proxy_timeout = pil->desc->proxy_timeout;
+
+	down_read(&pil_pm_rwsem);
+	snprintf(fw_name, sizeof(fw_name), "%s.mdt", pil->desc->name);
+	ret = request_firmware(&fw, fw_name, &pil->dev);
+	if (ret) {
+		dev_err(&pil->dev, "%s: Failed to locate %s\n",
+				pil->desc->name, fw_name);
+		goto out;
+	}
+
+	if (fw->size < sizeof(*ehdr)) {
+		dev_err(&pil->dev, "%s: Not big enough to be an elf header\n",
+				pil->desc->name);
+		ret = -EIO;
+		goto release_fw;
+	}
+
+	ehdr = (struct elf32_hdr *)fw->data;
+	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
+		dev_err(&pil->dev, "%s: Not an elf header\n", pil->desc->name);
+		ret = -EIO;
+		goto release_fw;
+	}
+
+	if (ehdr->e_phnum == 0) {
+		dev_err(&pil->dev, "%s: No loadable segments\n",
+				pil->desc->name);
+		ret = -EIO;
+		goto release_fw;
+	}
+	if (sizeof(struct elf32_phdr) * ehdr->e_phnum +
+	    sizeof(struct elf32_hdr) > fw->size) {
+		dev_err(&pil->dev, "%s: Program headers not within mdt\n",
+				pil->desc->name);
+		ret = -EIO;
+		goto release_fw;
+	}
+
+	ret = pil->desc->ops->init_image(pil->desc, fw->data, fw->size);
+	if (ret) {
+		dev_err(&pil->dev, "%s: Invalid firmware metadata\n",
+				pil->desc->name);
+		goto release_fw;
+	}
+
+	phdr = (const struct elf32_phdr *)(fw->data + sizeof(struct elf32_hdr));
+	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
+		if (!segment_is_loadable(phdr))
+			continue;
+
+		ret = load_segment(phdr, i, pil);
+		if (ret) {
+			dev_err(&pil->dev, "%s: Failed to load segment %d\n",
+					pil->desc->name, i);
+			goto release_fw;
+		}
+	}
+
+	ret = pil_proxy_vote(pil);
+	if (ret) {
+		dev_err(&pil->dev, "%s: Failed to proxy vote\n",
+					pil->desc->name);
+		goto release_fw;
+	}
+
+	ret = pil->desc->ops->auth_and_reset(pil->desc);
+	if (ret) {
+		dev_err(&pil->dev, "%s: Failed to bring out of reset\n",
+				pil->desc->name);
+		proxy_timeout = 0; /* Remove proxy vote immediately on error */
+		goto err_boot;
+	}
+	dev_info(&pil->dev, "%s: Brought out of reset\n", pil->desc->name);
+err_boot:
+	pil_proxy_unvote(pil, proxy_timeout);
+release_fw:
+	release_firmware(fw);
+out:
+	up_read(&pil_pm_rwsem);
+	return ret;
+}
+
+static void pil_set_state(struct pil_device *pil, enum pil_state state)
+{
+	if (pil->state != state) {
+		pil->state = state;
+		sysfs_notify(&pil->dev.kobj, NULL, "state");
+	}
+}
+
+/**
+ * pil_get() - Load a peripheral into memory and take it out of reset
+ * @name: pointer to a string containing the name of the peripheral to load
+ *
+ * This function returns a pointer if it succeeds. If an error occurs an
+ * ERR_PTR is returned.
+ *
+ * If PIL is not enabled in the kernel, the value %NULL will be returned.
+ */
+void *pil_get(const char *name)
+{
+	int ret;
+	struct pil_device *pil;
+	struct pil_device *pil_d;
+	void *retval;
+
+	if (!name)
+		return NULL;
+
+	pil = retval = find_peripheral(name);
+	if (!pil)
+		return ERR_PTR(-ENODEV);
+	if (!try_module_get(pil->owner)) {
+		put_device(&pil->dev);
+		return ERR_PTR(-ENODEV);
+	}
+
+	pil_d = pil_get(pil->desc->depends_on);
+	if (IS_ERR(pil_d)) {
+		retval = pil_d;
+		goto err_depends;
+	}
+
+	mutex_lock(&pil->lock);
+	if (!pil->count) {
+		ret = load_image(pil);
+		if (ret) {
+			retval = ERR_PTR(ret);
+			goto err_load;
+		}
+	}
+	pil->count++;
+	pil_set_state(pil, PIL_ONLINE);
+	mutex_unlock(&pil->lock);
+out:
+	return retval;
+err_load:
+	mutex_unlock(&pil->lock);
+	pil_put(pil_d);
+err_depends:
+	put_device(&pil->dev);
+	module_put(pil->owner);
+	goto out;
+}
+EXPORT_SYMBOL(pil_get);
+
+static void pil_shutdown(struct pil_device *pil)
+{
+	pil->desc->ops->shutdown(pil->desc);
+	flush_delayed_work(&pil->proxy);
+	pil_set_state(pil, PIL_OFFLINE);
+}
+
+/**
+ * pil_put() - Inform PIL the peripheral no longer needs to be active
+ * @peripheral_handle: pointer from a previous call to pil_get()
+ *
+ * This doesn't imply that a peripheral is shutdown or in reset since another
+ * driver could be using the peripheral.
+ */
+void pil_put(void *peripheral_handle)
+{
+	struct pil_device *pil_d, *pil = peripheral_handle;
+
+	if (IS_ERR_OR_NULL(pil))
+		return;
+
+	mutex_lock(&pil->lock);
+	if (WARN(!pil->count, "%s: %s: Reference count mismatch\n",
+			pil->desc->name, __func__))
+		goto err_out;
+	if (!--pil->count)
+		pil_shutdown(pil);
+	mutex_unlock(&pil->lock);
+
+	pil_d = find_peripheral(pil->desc->depends_on);
+	module_put(pil->owner);
+	if (pil_d) {
+		pil_put(pil_d);
+		put_device(&pil_d->dev);
+	}
+	put_device(&pil->dev);
+	return;
+err_out:
+	mutex_unlock(&pil->lock);
+	return;
+}
+EXPORT_SYMBOL(pil_put);
+
+void pil_force_shutdown(const char *name)
+{
+	struct pil_device *pil;
+
+	pil = find_peripheral(name);
+	if (!pil) {
+		pr_err("%s: Couldn't find %s\n", __func__, name);
+		return;
+	}
+
+	mutex_lock(&pil->lock);
+	if (!WARN(!pil->count, "%s: %s: Reference count mismatch\n",
+			pil->desc->name, __func__))
+		pil_shutdown(pil);
+	mutex_unlock(&pil->lock);
+
+	put_device(&pil->dev);
+}
+EXPORT_SYMBOL(pil_force_shutdown);
+
+int pil_force_boot(const char *name)
+{
+	int ret = -EINVAL;
+	struct pil_device *pil;
+
+	pil = find_peripheral(name);
+	if (!pil) {
+		pr_err("%s: Couldn't find %s\n", __func__, name);
+		return -EINVAL;
+	}
+
+	mutex_lock(&pil->lock);
+	if (!WARN(!pil->count, "%s: %s: Reference count mismatch\n",
+			pil->desc->name, __func__))
+		ret = load_image(pil);
+	if (!ret)
+		pil_set_state(pil, PIL_ONLINE);
+	mutex_unlock(&pil->lock);
+	put_device(&pil->dev);
+
+	return ret;
+}
+EXPORT_SYMBOL(pil_force_boot);
+
+#ifdef CONFIG_DEBUG_FS
+static int msm_pil_debugfs_open(struct inode *inode, struct file *filp)
+{
+	filp->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t msm_pil_debugfs_read(struct file *filp, char __user *ubuf,
+		size_t cnt, loff_t *ppos)
+{
+	int r;
+	char buf[40];
+	struct pil_device *pil = filp->private_data;
+
+	mutex_lock(&pil->lock);
+	r = snprintf(buf, sizeof(buf), "%d\n", pil->count);
+	mutex_unlock(&pil->lock);
+	return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
+}
+
+static ssize_t msm_pil_debugfs_write(struct file *filp,
+		const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	struct pil_device *pil = filp->private_data;
+	char buf[4];
+
+	if (cnt > sizeof(buf))
+		return -EINVAL;
+
+	if (copy_from_user(&buf, ubuf, cnt))
+		return -EFAULT;
+
+	if (!strncmp(buf, "get", 3)) {
+		if (IS_ERR(pil_get(pil->desc->name)))
+			return -EIO;
+	} else if (!strncmp(buf, "put", 3))
+		pil_put(pil);
+	else
+		return -EINVAL;
+
+	return cnt;
+}
+
+static const struct file_operations msm_pil_debugfs_fops = {
+	.open	= msm_pil_debugfs_open,
+	.read	= msm_pil_debugfs_read,
+	.write	= msm_pil_debugfs_write,
+};
+
+static struct dentry *pil_base_dir;
+
+static int __init msm_pil_debugfs_init(void)
+{
+	pil_base_dir = debugfs_create_dir("pil", NULL);
+	if (!pil_base_dir) {
+		pil_base_dir = NULL;
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void __exit msm_pil_debugfs_exit(void)
+{
+	debugfs_remove_recursive(pil_base_dir);
+}
+
+static int msm_pil_debugfs_add(struct pil_device *pil)
+{
+	if (!pil_base_dir)
+		return -ENOMEM;
+
+	pil->dentry = debugfs_create_file(pil->desc->name, S_IRUGO | S_IWUSR,
+				pil_base_dir, pil, &msm_pil_debugfs_fops);
+	return !pil->dentry ? -ENOMEM : 0;
+}
+
+static void msm_pil_debugfs_remove(struct pil_device *pil)
+{
+	debugfs_remove(pil->dentry);
+}
+#else
+static int __init msm_pil_debugfs_init(void) { return 0; };
+static void __exit msm_pil_debugfs_exit(void) { return 0; };
+static int msm_pil_debugfs_add(struct pil_device *pil) { return 0; }
+static void msm_pil_debugfs_remove(struct pil_device *pil) { }
+#endif
+
+static int __msm_pil_shutdown(struct device *dev, void *data)
+{
+	pil_shutdown(to_pil_device(dev));
+	return 0;
+}
+
+static int msm_pil_shutdown_at_boot(void)
+{
+	return bus_for_each_dev(&pil_bus_type, NULL, NULL, __msm_pil_shutdown);
+}
+late_initcall(msm_pil_shutdown_at_boot);
+
+static void pil_device_release(struct device *dev)
+{
+	struct pil_device *pil = to_pil_device(dev);
+	wake_lock_destroy(&pil->wlock);
+	mutex_destroy(&pil->lock);
+	kfree(pil);
+}
+
+struct pil_device *msm_pil_register(struct pil_desc *desc)
+{
+	int err;
+	static atomic_t pil_count = ATOMIC_INIT(-1);
+	struct pil_device *pil;
+
+	/* Ignore users who don't make any sense */
+	if (WARN(desc->ops->proxy_unvote && !desc->ops->proxy_vote,
+				"invalid proxy voting. ignoring\n"))
+		((struct pil_reset_ops *)desc->ops)->proxy_unvote = NULL;
+
+	WARN(desc->ops->proxy_unvote && !desc->proxy_timeout,
+		"A proxy timeout of 0 ms was specified for %s. Specify one in "
+		"desc->proxy_timeout.\n", desc->name);
+
+	pil = kzalloc(sizeof(*pil), GFP_KERNEL);
+	if (!pil)
+		return ERR_PTR(-ENOMEM);
+
+	mutex_init(&pil->lock);
+	pil->desc = desc;
+	pil->owner = desc->owner;
+	pil->dev.parent = desc->dev;
+	pil->dev.bus = &pil_bus_type;
+	pil->dev.release = pil_device_release;
+
+	snprintf(pil->wake_name, sizeof(pil->wake_name), "pil-%s", desc->name);
+	wake_lock_init(&pil->wlock, WAKE_LOCK_SUSPEND, pil->wake_name);
+	INIT_DELAYED_WORK(&pil->proxy, pil_proxy_work);
+
+	dev_set_name(&pil->dev, "pil%d", atomic_inc_return(&pil_count));
+	err = device_register(&pil->dev);
+	if (err) {
+		put_device(&pil->dev);
+		wake_lock_destroy(&pil->wlock);
+		mutex_destroy(&pil->lock);
+		kfree(pil);
+		return ERR_PTR(err);
+	}
+
+	err = msm_pil_debugfs_add(pil);
+	if (err) {
+		device_unregister(&pil->dev);
+		return ERR_PTR(err);
+	}
+
+	return pil;
+}
+EXPORT_SYMBOL(msm_pil_register);
+
+void msm_pil_unregister(struct pil_device *pil)
+{
+	if (IS_ERR_OR_NULL(pil))
+		return;
+
+	if (get_device(&pil->dev)) {
+		mutex_lock(&pil->lock);
+		WARN_ON(pil->count);
+		flush_delayed_work_sync(&pil->proxy);
+		msm_pil_debugfs_remove(pil);
+		device_unregister(&pil->dev);
+		mutex_unlock(&pil->lock);
+		put_device(&pil->dev);
+	}
+}
+EXPORT_SYMBOL(msm_pil_unregister);
+
+static int pil_pm_notify(struct notifier_block *b, unsigned long event, void *p)
+{
+	switch (event) {
+	case PM_SUSPEND_PREPARE:
+		down_write(&pil_pm_rwsem);
+		break;
+	case PM_POST_SUSPEND:
+		up_write(&pil_pm_rwsem);
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block pil_pm_notifier = {
+	.notifier_call = pil_pm_notify,
+};
+
+static int __init msm_pil_init(void)
+{
+	int ret = msm_pil_debugfs_init();
+	if (ret)
+		return ret;
+	register_pm_notifier(&pil_pm_notifier);
+	return bus_register(&pil_bus_type);
+}
+subsys_initcall(msm_pil_init);
+
+static void __exit msm_pil_exit(void)
+{
+	bus_unregister(&pil_bus_type);
+	unregister_pm_notifier(&pil_pm_notifier);
+	msm_pil_debugfs_exit();
+}
+module_exit(msm_pil_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Load peripheral images and bring peripherals out of reset");
diff --git a/arch/arm/mach-msm/peripheral-loader.h b/arch/arm/mach-msm/peripheral-loader.h
new file mode 100644
index 0000000..e3b250b
--- /dev/null
+++ b/arch/arm/mach-msm/peripheral-loader.h
@@ -0,0 +1,61 @@
+/* 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
+ * 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 __MSM_PERIPHERAL_LOADER_H
+#define __MSM_PERIPHERAL_LOADER_H
+
+struct device;
+struct module;
+
+/**
+ * struct pil_desc - PIL descriptor
+ * @name: string used for pil_get()
+ * @depends_on: booted before this peripheral
+ * @dev: parent device
+ * @ops: callback functions
+ * @owner: module the descriptor belongs to
+ * @proxy_timeout: delay in ms until proxy vote is removed
+ */
+struct pil_desc {
+	const char *name;
+	const char *depends_on;
+	struct device *dev;
+	const struct pil_reset_ops *ops;
+	struct module *owner;
+	unsigned long proxy_timeout;
+};
+
+/**
+ * struct pil_reset_ops - PIL operations
+ * @init_image: prepare an image for authentication
+ * @verify_blob: authenticate a program segment, called once for each loadable
+ *		 program segment (optional)
+ * @proxy_vote: make proxy votes before auth_and_reset (optional)
+ * @auth_and_reset: boot the processor
+ * @proxy_unvote: remove any proxy votes (optional)
+ * @shutdown: shutdown the processor
+ */
+struct pil_reset_ops {
+	int (*init_image)(struct pil_desc *pil, const u8 *metadata,
+			  size_t size);
+	int (*verify_blob)(struct pil_desc *pil, u32 phy_addr, size_t size);
+	int (*proxy_vote)(struct pil_desc *pil);
+	int (*auth_and_reset)(struct pil_desc *pil);
+	void (*proxy_unvote)(struct pil_desc *pil);
+	int (*shutdown)(struct pil_desc *pil);
+};
+
+struct pil_device;
+
+extern struct pil_device *msm_pil_register(struct pil_desc *desc);
+extern void msm_pil_unregister(struct pil_device *pil);
+
+#endif
diff --git a/arch/arm/mach-msm/pil-dsps.c b/arch/arm/mach-msm/pil-dsps.c
new file mode 100644
index 0000000..81f5330
--- /dev/null
+++ b/arch/arm/mach-msm/pil-dsps.c
@@ -0,0 +1,146 @@
+/* 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/elf.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#include <mach/msm_iomap.h>
+
+#include "peripheral-loader.h"
+#include "scm-pas.h"
+
+#define PPSS_RESET			(MSM_CLK_CTL_BASE + 0x2594)
+#define PPSS_RESET_PROC_RESET		0x2
+#define PPSS_RESET_RESET		0x1
+#define PPSS_PROC_CLK_CTL		(MSM_CLK_CTL_BASE + 0x2588)
+#define CLK_BRANCH_ENA			0x10
+#define PPSS_HCLK_CTL			(MSM_CLK_CTL_BASE + 0x2580)
+#define CLK_HALT_DFAB_STATE		(MSM_CLK_CTL_BASE + 0x2FC8)
+
+static int init_image_dsps(struct pil_desc *pil, const u8 *metadata,
+				     size_t size)
+{
+	/* Bring memory and bus interface out of reset */
+	writel_relaxed(PPSS_RESET_PROC_RESET, PPSS_RESET);
+	writel_relaxed(CLK_BRANCH_ENA, PPSS_HCLK_CTL);
+	mb();
+	return 0;
+}
+
+static int reset_dsps(struct pil_desc *pil)
+{
+	writel_relaxed(CLK_BRANCH_ENA, PPSS_PROC_CLK_CTL);
+	while (readl_relaxed(CLK_HALT_DFAB_STATE) & BIT(18))
+		cpu_relax();
+	/* Bring DSPS out of reset */
+	writel_relaxed(0x0, PPSS_RESET);
+	return 0;
+}
+
+static int shutdown_dsps(struct pil_desc *pil)
+{
+	writel_relaxed(PPSS_RESET_PROC_RESET | PPSS_RESET_RESET, PPSS_RESET);
+	usleep_range(1000, 2000);
+	writel_relaxed(PPSS_RESET_PROC_RESET, PPSS_RESET);
+	writel_relaxed(0x0, PPSS_PROC_CLK_CTL);
+	return 0;
+}
+
+struct pil_reset_ops pil_dsps_ops = {
+	.init_image = init_image_dsps,
+	.auth_and_reset = reset_dsps,
+	.shutdown = shutdown_dsps,
+};
+
+static int init_image_dsps_trusted(struct pil_desc *pil, const u8 *metadata,
+				   size_t size)
+{
+	return pas_init_image(PAS_DSPS, metadata, size);
+}
+
+static int reset_dsps_trusted(struct pil_desc *pil)
+{
+	return pas_auth_and_reset(PAS_DSPS);
+}
+
+static int shutdown_dsps_trusted(struct pil_desc *pil)
+{
+	return pas_shutdown(PAS_DSPS);
+}
+
+struct pil_reset_ops pil_dsps_ops_trusted = {
+	.init_image = init_image_dsps_trusted,
+	.auth_and_reset = reset_dsps_trusted,
+	.shutdown = shutdown_dsps_trusted,
+};
+
+static int __devinit pil_dsps_driver_probe(struct platform_device *pdev)
+{
+	struct pil_desc *desc;
+	struct pil_device *pil;
+
+	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+
+	desc->name = pdev->dev.platform_data;
+	desc->dev = &pdev->dev;
+	desc->owner = THIS_MODULE;
+	if (pas_supported(PAS_DSPS) > 0) {
+		desc->ops = &pil_dsps_ops_trusted;
+		dev_info(&pdev->dev, "using secure boot\n");
+	} else {
+		desc->ops = &pil_dsps_ops;
+		dev_info(&pdev->dev, "using non-secure boot\n");
+	}
+	pil = msm_pil_register(desc);
+	if (IS_ERR(pil))
+		return PTR_ERR(pil);
+	platform_set_drvdata(pdev, pil);
+	return 0;
+}
+
+static int __devexit pil_dsps_driver_exit(struct platform_device *pdev)
+{
+	struct pil_device *pil = platform_get_drvdata(pdev);
+	msm_pil_unregister(pil);
+	return 0;
+}
+
+static struct platform_driver pil_dsps_driver = {
+	.probe = pil_dsps_driver_probe,
+	.remove = __devexit_p(pil_dsps_driver_exit),
+	.driver = {
+		.name = "pil_dsps",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init pil_dsps_init(void)
+{
+	return platform_driver_register(&pil_dsps_driver);
+}
+module_init(pil_dsps_init);
+
+static void __exit pil_dsps_exit(void)
+{
+	platform_driver_unregister(&pil_dsps_driver);
+}
+module_exit(pil_dsps_exit);
+
+MODULE_DESCRIPTION("Support for booting sensors (DSPS) images");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-gss.c b/arch/arm/mach-msm/pil-gss.c
new file mode 100644
index 0000000..dc7baa1
--- /dev/null
+++ b/arch/arm/mach-msm/pil-gss.c
@@ -0,0 +1,396 @@
+/*
+ * 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/kernel.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/elf.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/smp.h>
+
+#include <mach/msm_iomap.h>
+#include <mach/msm_xo.h>
+#include <mach/socinfo.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_bus.h>
+
+#include "peripheral-loader.h"
+#include "scm-pas.h"
+
+#define GSS_CSR_AHB_CLK_SEL	0x0
+#define GSS_CSR_RESET		0x4
+#define GSS_CSR_CLK_BLK_CONFIG	0x8
+#define GSS_CSR_CLK_ENABLE	0xC
+#define GSS_CSR_BOOT_REMAP	0x14
+#define GSS_CSR_POWER_UP_DOWN	0x18
+#define GSS_CSR_CFG_HID		0x2C
+
+#define GSS_SLP_CLK_CTL		(MSM_CLK_CTL_BASE + 0x2C60)
+#define GSS_RESET		(MSM_CLK_CTL_BASE + 0x2C64)
+#define GSS_CLAMP_ENA		(MSM_CLK_CTL_BASE + 0x2C68)
+#define GSS_CXO_SRC_CTL		(MSM_CLK_CTL_BASE + 0x2C74)
+
+#define PLL5_STATUS		(MSM_CLK_CTL_BASE + 0x30F8)
+#define PLL_ENA_GSS		(MSM_CLK_CTL_BASE + 0x3480)
+
+#define PLL5_VOTE		BIT(5)
+#define PLL_STATUS		BIT(16)
+#define REMAP_ENABLE		BIT(16)
+#define A5_POWER_STATUS		BIT(4)
+#define A5_POWER_ENA		BIT(0)
+#define NAV_POWER_ENA		BIT(1)
+#define XO_CLK_BRANCH_ENA	BIT(0)
+#define SLP_CLK_BRANCH_ENA	BIT(4)
+#define A5_RESET		BIT(0)
+
+struct gss_data {
+	void __iomem *base;
+	void __iomem *qgic2_base;
+	unsigned long start_addr;
+	struct clk *xo;
+	struct pil_device *pil;
+};
+
+static int pil_gss_init_image(struct pil_desc *pil, const u8 *metadata,
+		size_t size)
+{
+	const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
+	struct gss_data *drv = dev_get_drvdata(pil->dev);
+	drv->start_addr = ehdr->e_entry;
+	return 0;
+}
+
+static int make_gss_proxy_votes(struct pil_desc *pil)
+{
+	int ret;
+	struct gss_data *drv = dev_get_drvdata(pil->dev);
+
+	ret = clk_prepare_enable(drv->xo);
+	if (ret) {
+		dev_err(pil->dev, "Failed to enable XO\n");
+		return ret;
+	}
+	return 0;
+}
+
+static void remove_gss_proxy_votes(struct pil_desc *pil)
+{
+	struct gss_data *drv = dev_get_drvdata(pil->dev);
+	clk_disable_unprepare(drv->xo);
+}
+
+static void gss_init(struct gss_data *drv)
+{
+	void __iomem *base = drv->base;
+
+	/* Supply clocks to GSS. */
+	writel_relaxed(XO_CLK_BRANCH_ENA, GSS_CXO_SRC_CTL);
+	writel_relaxed(SLP_CLK_BRANCH_ENA, GSS_SLP_CLK_CTL);
+
+	/* Deassert GSS reset and clamps. */
+	writel_relaxed(0x0, GSS_RESET);
+	writel_relaxed(0x0, GSS_CLAMP_ENA);
+	mb();
+
+	/*
+	 * Configure clock source and dividers for 288MHz core, 144MHz AXI and
+	 * 72MHz AHB, all derived from the 288MHz PLL.
+	 */
+	writel_relaxed(0x341, base + GSS_CSR_CLK_BLK_CONFIG);
+	writel_relaxed(0x1, base + GSS_CSR_AHB_CLK_SEL);
+
+	/* Assert all GSS resets. */
+	writel_relaxed(0x7F, base + GSS_CSR_RESET);
+
+	/* Enable all bus clocks and wait for resets to propagate. */
+	writel_relaxed(0x1F, base + GSS_CSR_CLK_ENABLE);
+	mb();
+	udelay(1);
+
+	/* Release subsystem from reset, but leave A5 in reset. */
+	writel_relaxed(A5_RESET, base + GSS_CSR_RESET);
+}
+
+static void cfg_qgic2_bus_access(void *data)
+{
+	struct gss_data *drv = data;
+	int i;
+
+	/*
+	 * Apply a 8064 v1.0 workaround to configure QGIC bus access.
+	 * This must be done from Krait 0 to configure the Master ID
+	 * correctly.
+	 */
+	writel_relaxed(0x2, drv->base + GSS_CSR_CFG_HID);
+	for (i = 0; i <= 3; i++)
+		readl_relaxed(drv->qgic2_base);
+}
+
+static int pil_gss_shutdown(struct pil_desc *pil)
+{
+	struct gss_data *drv = dev_get_drvdata(pil->dev);
+	void __iomem *base = drv->base;
+	u32 regval;
+	int ret;
+
+	ret = clk_prepare_enable(drv->xo);
+	if (ret) {
+		dev_err(pil->dev, "Failed to enable XO\n");
+		return ret;
+	}
+
+	/* Make sure bus port is halted. */
+	msm_bus_axi_porthalt(MSM_BUS_MASTER_GSS_NAV);
+
+	/*
+	 * Vote PLL on in GSS's voting register and wait for it to enable.
+	 * The PLL must be enable to switch the GFMUX to a low-power source.
+	 */
+	writel_relaxed(PLL5_VOTE, PLL_ENA_GSS);
+	while ((readl_relaxed(PLL5_STATUS) & PLL_STATUS) == 0)
+		cpu_relax();
+
+	/* Perform one-time GSS initialization. */
+	gss_init(drv);
+
+	/* Assert A5 reset. */
+	regval = readl_relaxed(base + GSS_CSR_RESET);
+	regval |= A5_RESET;
+	writel_relaxed(regval, base + GSS_CSR_RESET);
+
+	/* Power down A5 and NAV. */
+	regval = readl_relaxed(base + GSS_CSR_POWER_UP_DOWN);
+	regval &= ~(A5_POWER_ENA|NAV_POWER_ENA);
+	writel_relaxed(regval, base + GSS_CSR_POWER_UP_DOWN);
+
+	/* Select XO clock source and increase dividers to save power. */
+	regval = readl_relaxed(base + GSS_CSR_CLK_BLK_CONFIG);
+	regval |= 0x3FF;
+	writel_relaxed(regval, base + GSS_CSR_CLK_BLK_CONFIG);
+
+	/* Disable bus clocks. */
+	writel_relaxed(0x1F, base + GSS_CSR_CLK_ENABLE);
+
+	/* Clear GSS PLL votes. */
+	writel_relaxed(0, PLL_ENA_GSS);
+	mb();
+
+	clk_disable_unprepare(drv->xo);
+
+	return 0;
+}
+
+static int pil_gss_reset(struct pil_desc *pil)
+{
+	struct gss_data *drv = dev_get_drvdata(pil->dev);
+	void __iomem *base = drv->base;
+	unsigned long start_addr = drv->start_addr;
+	int ret;
+
+	/* Unhalt bus port. */
+	ret = msm_bus_axi_portunhalt(MSM_BUS_MASTER_GSS_NAV);
+	if (ret) {
+		dev_err(pil->dev, "Failed to unhalt bus port\n");
+		return ret;
+	}
+
+	/* Vote PLL on in GSS's voting register and wait for it to enable. */
+	writel_relaxed(PLL5_VOTE, PLL_ENA_GSS);
+	while ((readl_relaxed(PLL5_STATUS) & PLL_STATUS) == 0)
+		cpu_relax();
+
+	/* Perform GSS initialization. */
+	gss_init(drv);
+
+	/* Configure boot address and enable remap. */
+	writel_relaxed(REMAP_ENABLE | (start_addr >> 16),
+			base + GSS_CSR_BOOT_REMAP);
+
+	/* Power up A5 core. */
+	writel_relaxed(A5_POWER_ENA, base + GSS_CSR_POWER_UP_DOWN);
+	while (!(readl_relaxed(base + GSS_CSR_POWER_UP_DOWN) & A5_POWER_STATUS))
+		cpu_relax();
+
+	if (cpu_is_apq8064() &&
+	    ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1) &&
+	     (SOCINFO_VERSION_MINOR(socinfo_get_version()) == 0))) {
+		ret = smp_call_function_single(0, cfg_qgic2_bus_access, drv, 1);
+		if (ret) {
+			pr_err("Failed to configure QGIC2 bus access\n");
+			pil_gss_shutdown(pil);
+			return ret;
+		}
+	}
+
+	/* Release A5 from reset. */
+	writel_relaxed(0x0, base + GSS_CSR_RESET);
+
+	return 0;
+}
+
+static struct pil_reset_ops pil_gss_ops = {
+	.init_image = pil_gss_init_image,
+	.auth_and_reset = pil_gss_reset,
+	.shutdown = pil_gss_shutdown,
+	.proxy_vote = make_gss_proxy_votes,
+	.proxy_unvote = remove_gss_proxy_votes,
+};
+
+static int pil_gss_init_image_trusted(struct pil_desc *pil,
+		const u8 *metadata, size_t size)
+{
+	return pas_init_image(PAS_GSS, metadata, size);
+}
+
+static int pil_gss_shutdown_trusted(struct pil_desc *pil)
+{
+	struct gss_data *drv = dev_get_drvdata(pil->dev);
+	int ret;
+
+	/*
+	 * CXO is used in the secure shutdown code to configure the processor
+	 * for low power mode.
+	 */
+	ret = clk_prepare_enable(drv->xo);
+	if (ret) {
+		dev_err(pil->dev, "Failed to enable XO\n");
+		return ret;
+	}
+
+	msm_bus_axi_porthalt(MSM_BUS_MASTER_GSS_NAV);
+	ret = pas_shutdown(PAS_GSS);
+	clk_disable_unprepare(drv->xo);
+
+	return ret;
+}
+
+static int pil_gss_reset_trusted(struct pil_desc *pil)
+{
+	int err;
+
+	err = msm_bus_axi_portunhalt(MSM_BUS_MASTER_GSS_NAV);
+	if (err) {
+		dev_err(pil->dev, "Failed to unhalt bus port\n");
+		goto out;
+	}
+
+	err =  pas_auth_and_reset(PAS_GSS);
+	if (err)
+		goto halt_port;
+
+	return 0;
+
+halt_port:
+	msm_bus_axi_porthalt(MSM_BUS_MASTER_GSS_NAV);
+out:
+	return err;
+}
+
+static struct pil_reset_ops pil_gss_ops_trusted = {
+	.init_image = pil_gss_init_image_trusted,
+	.auth_and_reset = pil_gss_reset_trusted,
+	.shutdown = pil_gss_shutdown_trusted,
+	.proxy_vote = make_gss_proxy_votes,
+	.proxy_unvote = remove_gss_proxy_votes,
+};
+
+static int __devinit pil_gss_probe(struct platform_device *pdev)
+{
+	struct gss_data *drv;
+	struct resource *res;
+	struct pil_desc *desc;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -EINVAL;
+
+	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+	if (!drv)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, drv);
+
+	drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!drv->base)
+		return -ENOMEM;
+
+	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res)
+		return -EINVAL;
+
+	drv->qgic2_base = devm_ioremap(&pdev->dev, res->start,
+					resource_size(res));
+	if (!drv->qgic2_base)
+		return -ENOMEM;
+
+	drv->xo = devm_clk_get(&pdev->dev, "xo");
+	if (IS_ERR(drv->xo))
+		return PTR_ERR(drv->xo);
+
+	desc->name = "gss";
+	desc->dev = &pdev->dev;
+	desc->owner = THIS_MODULE;
+	desc->proxy_timeout = 10000;
+
+	if (pas_supported(PAS_GSS) > 0) {
+		desc->ops = &pil_gss_ops_trusted;
+		dev_info(&pdev->dev, "using secure boot\n");
+	} else {
+		desc->ops = &pil_gss_ops;
+		dev_info(&pdev->dev, "using non-secure boot\n");
+	}
+
+	drv->pil = msm_pil_register(desc);
+	if (IS_ERR(drv->pil)) {
+		return PTR_ERR(drv->pil);
+	}
+	return 0;
+}
+
+static int __devexit pil_gss_remove(struct platform_device *pdev)
+{
+	struct gss_data *drv = platform_get_drvdata(pdev);
+	msm_pil_unregister(drv->pil);
+	return 0;
+}
+
+static struct platform_driver pil_gss_driver = {
+	.probe = pil_gss_probe,
+	.remove = __devexit_p(pil_gss_remove),
+	.driver = {
+		.name = "pil_gss",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init pil_gss_init(void)
+{
+	return platform_driver_register(&pil_gss_driver);
+}
+module_init(pil_gss_init);
+
+static void __exit pil_gss_exit(void)
+{
+	platform_driver_unregister(&pil_gss_driver);
+}
+module_exit(pil_gss_exit);
+
+MODULE_DESCRIPTION("Support for booting the GSS processor");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-modem.c b/arch/arm/mach-msm/pil-modem.c
new file mode 100644
index 0000000..8344496
--- /dev/null
+++ b/arch/arm/mach-msm/pil-modem.c
@@ -0,0 +1,311 @@
+/* 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
+ * 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/elf.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include <mach/msm_iomap.h>
+
+#include "peripheral-loader.h"
+#include "scm-pas.h"
+
+#define MARM_BOOT_CONTROL		0x0010
+#define MARM_RESET			(MSM_CLK_CTL_BASE + 0x2BD4)
+#define MAHB0_SFAB_PORT_RESET		(MSM_CLK_CTL_BASE + 0x2304)
+#define MARM_CLK_BRANCH_ENA_VOTE	(MSM_CLK_CTL_BASE + 0x3000)
+#define MARM_CLK_SRC0_NS		(MSM_CLK_CTL_BASE + 0x2BC0)
+#define MARM_CLK_SRC1_NS		(MSM_CLK_CTL_BASE + 0x2BC4)
+#define MARM_CLK_SRC_CTL		(MSM_CLK_CTL_BASE + 0x2BC8)
+#define MARM_CLK_CTL			(MSM_CLK_CTL_BASE + 0x2BCC)
+#define SFAB_MSS_S_HCLK_CTL		(MSM_CLK_CTL_BASE + 0x2C00)
+#define MSS_MODEM_CXO_CLK_CTL		(MSM_CLK_CTL_BASE + 0x2C44)
+#define MSS_SLP_CLK_CTL			(MSM_CLK_CTL_BASE + 0x2C60)
+#define MSS_MARM_SYS_REF_CLK_CTL	(MSM_CLK_CTL_BASE + 0x2C64)
+#define MAHB0_CLK_CTL			(MSM_CLK_CTL_BASE + 0x2300)
+#define MAHB1_CLK_CTL			(MSM_CLK_CTL_BASE + 0x2BE4)
+#define MAHB2_CLK_CTL			(MSM_CLK_CTL_BASE + 0x2C20)
+#define MAHB1_NS			(MSM_CLK_CTL_BASE + 0x2BE0)
+#define MARM_CLK_FS			(MSM_CLK_CTL_BASE + 0x2BD0)
+#define MAHB2_CLK_FS			(MSM_CLK_CTL_BASE + 0x2C24)
+#define PLL_ENA_MARM			(MSM_CLK_CTL_BASE + 0x3500)
+#define PLL8_STATUS			(MSM_CLK_CTL_BASE + 0x3158)
+#define CLK_HALT_MSS_SMPSS_MISC_STATE	(MSM_CLK_CTL_BASE + 0x2FDC)
+
+struct modem_data {
+	void __iomem *base;
+	unsigned long start_addr;
+	struct pil_device *pil;
+	struct clk *xo;
+};
+
+static int make_modem_proxy_votes(struct pil_desc *pil)
+{
+	int ret;
+	struct modem_data *drv = dev_get_drvdata(pil->dev);
+
+	ret = clk_prepare_enable(drv->xo);
+	if (ret) {
+		dev_err(pil->dev, "Failed to enable XO\n");
+		return ret;
+	}
+	return 0;
+}
+
+static void remove_modem_proxy_votes(struct pil_desc *pil)
+{
+	struct modem_data *drv = dev_get_drvdata(pil->dev);
+	clk_disable_unprepare(drv->xo);
+}
+
+static int modem_init_image(struct pil_desc *pil, const u8 *metadata,
+		size_t size)
+{
+	const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
+	struct modem_data *drv = dev_get_drvdata(pil->dev);
+	drv->start_addr = ehdr->e_entry;
+	return 0;
+}
+
+static int modem_reset(struct pil_desc *pil)
+{
+	u32 reg;
+	const struct modem_data *drv = dev_get_drvdata(pil->dev);
+
+	/* Put modem AHB0,1,2 clocks into reset */
+	writel_relaxed(BIT(0) | BIT(1), MAHB0_SFAB_PORT_RESET);
+	writel_relaxed(BIT(7), MAHB1_CLK_CTL);
+	writel_relaxed(BIT(7), MAHB2_CLK_CTL);
+
+	/* Vote for pll8 on behalf of the modem */
+	reg = readl_relaxed(PLL_ENA_MARM);
+	reg |= BIT(8);
+	writel_relaxed(reg, PLL_ENA_MARM);
+
+	/* Wait for PLL8 to enable */
+	while (!(readl_relaxed(PLL8_STATUS) & BIT(16)))
+		cpu_relax();
+
+	/* Set MAHB1 divider to Div-5 to run MAHB1,2 and sfab at 79.8 Mhz*/
+	writel_relaxed(0x4, MAHB1_NS);
+
+	/* Vote for modem AHB1 and 2 clocks to be on on behalf of the modem */
+	reg = readl_relaxed(MARM_CLK_BRANCH_ENA_VOTE);
+	reg |= BIT(0) | BIT(1);
+	writel_relaxed(reg, MARM_CLK_BRANCH_ENA_VOTE);
+
+	/* Source marm_clk off of PLL8 */
+	reg = readl_relaxed(MARM_CLK_SRC_CTL);
+	if ((reg & 0x1) == 0) {
+		writel_relaxed(0x3, MARM_CLK_SRC1_NS);
+		reg |= 0x1;
+	} else {
+		writel_relaxed(0x3, MARM_CLK_SRC0_NS);
+		reg &= ~0x1;
+	}
+	writel_relaxed(reg | 0x2, MARM_CLK_SRC_CTL);
+
+	/*
+	 * Force core on and periph on signals to remain active during halt
+	 * for marm_clk and mahb2_clk
+	 */
+	writel_relaxed(0x6F, MARM_CLK_FS);
+	writel_relaxed(0x6F, MAHB2_CLK_FS);
+
+	/*
+	 * Enable all of the marm_clk branches, cxo sourced marm branches,
+	 * and sleep clock branches
+	 */
+	writel_relaxed(0x10, MARM_CLK_CTL);
+	writel_relaxed(0x10, MAHB0_CLK_CTL);
+	writel_relaxed(0x10, SFAB_MSS_S_HCLK_CTL);
+	writel_relaxed(0x10, MSS_MODEM_CXO_CLK_CTL);
+	writel_relaxed(0x10, MSS_SLP_CLK_CTL);
+	writel_relaxed(0x10, MSS_MARM_SYS_REF_CLK_CTL);
+
+	/* Wait for above clocks to be turned on */
+	while (readl_relaxed(CLK_HALT_MSS_SMPSS_MISC_STATE) & (BIT(7) | BIT(8) |
+				BIT(9) | BIT(10) | BIT(4) | BIT(6)))
+		cpu_relax();
+
+	/* Take MAHB0,1,2 clocks out of reset */
+	writel_relaxed(0x0, MAHB2_CLK_CTL);
+	writel_relaxed(0x0, MAHB1_CLK_CTL);
+	writel_relaxed(0x0, MAHB0_SFAB_PORT_RESET);
+	mb();
+
+	/* Setup exception vector table base address */
+	writel_relaxed(drv->start_addr | 0x1, drv->base + MARM_BOOT_CONTROL);
+
+	/* Wait for vector table to be setup */
+	mb();
+
+	/* Bring modem out of reset */
+	writel_relaxed(0x0, MARM_RESET);
+
+	return 0;
+}
+
+static int modem_shutdown(struct pil_desc *pil)
+{
+	u32 reg;
+
+	/* Put modem into reset */
+	writel_relaxed(0x1, MARM_RESET);
+	mb();
+
+	/* Put modem AHB0,1,2 clocks into reset */
+	writel_relaxed(BIT(0) | BIT(1), MAHB0_SFAB_PORT_RESET);
+	writel_relaxed(BIT(7), MAHB1_CLK_CTL);
+	writel_relaxed(BIT(7), MAHB2_CLK_CTL);
+	mb();
+
+	/*
+	 * Disable all of the marm_clk branches, cxo sourced marm branches,
+	 * and sleep clock branches
+	 */
+	writel_relaxed(0x0, MARM_CLK_CTL);
+	writel_relaxed(0x0, MAHB0_CLK_CTL);
+	writel_relaxed(0x0, SFAB_MSS_S_HCLK_CTL);
+	writel_relaxed(0x0, MSS_MODEM_CXO_CLK_CTL);
+	writel_relaxed(0x0, MSS_SLP_CLK_CTL);
+	writel_relaxed(0x0, MSS_MARM_SYS_REF_CLK_CTL);
+
+	/* Disable marm_clk */
+	reg = readl_relaxed(MARM_CLK_SRC_CTL);
+	reg &= ~0x2;
+	writel_relaxed(reg, MARM_CLK_SRC_CTL);
+
+	/* Clear modem's votes for ahb clocks */
+	writel_relaxed(0x0, MARM_CLK_BRANCH_ENA_VOTE);
+
+	/* Clear modem's votes for PLLs */
+	writel_relaxed(0x0, PLL_ENA_MARM);
+
+	return 0;
+}
+
+static struct pil_reset_ops pil_modem_ops = {
+	.init_image = modem_init_image,
+	.auth_and_reset = modem_reset,
+	.shutdown = modem_shutdown,
+	.proxy_vote = make_modem_proxy_votes,
+	.proxy_unvote = remove_modem_proxy_votes,
+};
+
+static int modem_init_image_trusted(struct pil_desc *pil, const u8 *metadata,
+		size_t size)
+{
+	return pas_init_image(PAS_MODEM, metadata, size);
+}
+
+static int modem_reset_trusted(struct pil_desc *pil)
+{
+	return pas_auth_and_reset(PAS_MODEM);
+}
+
+static int modem_shutdown_trusted(struct pil_desc *pil)
+{
+	return pas_shutdown(PAS_MODEM);
+}
+
+static struct pil_reset_ops pil_modem_ops_trusted = {
+	.init_image = modem_init_image_trusted,
+	.auth_and_reset = modem_reset_trusted,
+	.shutdown = modem_shutdown_trusted,
+	.proxy_vote = make_modem_proxy_votes,
+	.proxy_unvote = remove_modem_proxy_votes,
+};
+
+static int __devinit pil_modem_driver_probe(struct platform_device *pdev)
+{
+	struct modem_data *drv;
+	struct resource *res;
+	struct pil_desc *desc;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -EINVAL;
+
+	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+	if (!drv)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, drv);
+
+	drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!drv->base)
+		return -ENOMEM;
+
+	drv->xo = devm_clk_get(&pdev->dev, "xo");
+	if (IS_ERR(drv->xo))
+		return PTR_ERR(drv->xo);
+
+	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+
+	desc->name = "modem";
+	desc->depends_on = "q6";
+	desc->dev = &pdev->dev;
+	desc->owner = THIS_MODULE;
+	desc->proxy_timeout = 10000;
+
+	if (pas_supported(PAS_MODEM) > 0) {
+		desc->ops = &pil_modem_ops_trusted;
+		dev_info(&pdev->dev, "using secure boot\n");
+	} else {
+		desc->ops = &pil_modem_ops;
+		dev_info(&pdev->dev, "using non-secure boot\n");
+	}
+	drv->pil = msm_pil_register(desc);
+	if (IS_ERR(drv->pil)) {
+		return PTR_ERR(drv->pil);
+	}
+	return 0;
+}
+
+static int __devexit pil_modem_driver_exit(struct platform_device *pdev)
+{
+	struct modem_data *drv = platform_get_drvdata(pdev);
+	msm_pil_unregister(drv->pil);
+	return 0;
+}
+
+static struct platform_driver pil_modem_driver = {
+	.probe = pil_modem_driver_probe,
+	.remove = __devexit_p(pil_modem_driver_exit),
+	.driver = {
+		.name = "pil_modem",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init pil_modem_init(void)
+{
+	return platform_driver_register(&pil_modem_driver);
+}
+module_init(pil_modem_init);
+
+static void __exit pil_modem_exit(void)
+{
+	platform_driver_unregister(&pil_modem_driver);
+}
+module_exit(pil_modem_exit);
+
+MODULE_DESCRIPTION("Support for booting modem processors");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
new file mode 100644
index 0000000..58d5176
--- /dev/null
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -0,0 +1,349 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/elf.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#include "peripheral-loader.h"
+#include "scm-pas.h"
+
+#define PRONTO_PMU_COMMON_GDSCR				0x24
+#define PRONTO_PMU_COMMON_GDSCR_SW_COLLAPSE		BIT(0)
+#define CLK_DIS_WAIT					12
+#define EN_FEW_WAIT					16
+#define EN_REST_WAIT					20
+
+#define PRONTO_PMU_COMMON_CPU_CBCR			0x30
+#define PRONTO_PMU_COMMON_CPU_CBCR_CLK_EN		BIT(0)
+#define PRONTO_PMU_COMMON_CPU_CLK_OFF			BIT(31)
+
+#define PRONTO_PMU_COMMON_AHB_CBCR			0x34
+#define PRONTO_PMU_COMMON_AHB_CBCR_CLK_EN		BIT(0)
+#define PRONTO_PMU_COMMON_AHB_CLK_OFF			BIT(31)
+
+#define PRONTO_PMU_COMMON_CSR				0x1040
+#define PRONTO_PMU_COMMON_CSR_A2XB_CFG_EN		BIT(0)
+
+#define PRONTO_PMU_SOFT_RESET				0x104C
+#define PRONTO_PMU_SOFT_RESET_CRCM_CCPU_SOFT_RESET	BIT(10)
+
+#define PRONTO_PMU_CCPU_CTL				0x2000
+#define PRONTO_PMU_CCPU_CTL_REMAP_EN			BIT(2)
+#define PRONTO_PMU_CCPU_CTL_HIGH_IVT			BIT(0)
+
+#define PRONTO_PMU_CCPU_BOOT_REMAP_ADDR			0x2004
+
+#define CLK_CTL_WCNSS_RESTART_BIT			BIT(0)
+
+#define AXI_HALTREQ					0x0
+#define AXI_HALTACK					0x4
+#define AXI_IDLE					0x8
+
+#define HALT_ACK_TIMEOUT_US				500000
+#define CLK_UPDATE_TIMEOUT_US				500000
+
+struct pronto_data {
+	void __iomem *base;
+	void __iomem *reset_base;
+	void __iomem *axi_halt_base;
+	unsigned long start_addr;
+	struct pil_device *pil;
+	struct clk *cxo;
+	struct regulator *vreg;
+};
+
+static int pil_pronto_make_proxy_vote(struct pil_desc *pil)
+{
+	struct pronto_data *drv = dev_get_drvdata(pil->dev);
+	int ret;
+
+	ret = regulator_enable(drv->vreg);
+	if (ret) {
+		dev_err(pil->dev, "failed to enable pll supply\n");
+		goto err;
+	}
+	ret = clk_prepare_enable(drv->cxo);
+	if (ret) {
+		dev_err(pil->dev, "failed to enable cxo\n");
+		goto err_clk;
+	}
+	return 0;
+err_clk:
+	regulator_disable(drv->vreg);
+err:
+	return ret;
+}
+
+static void pil_pronto_remove_proxy_vote(struct pil_desc *pil)
+{
+	struct pronto_data *drv = dev_get_drvdata(pil->dev);
+	regulator_disable(drv->vreg);
+	clk_disable_unprepare(drv->cxo);
+}
+
+static int pil_pronto_init_image(struct pil_desc *pil, const u8 *metadata,
+		size_t size)
+{
+	const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
+	struct pronto_data *drv = dev_get_drvdata(pil->dev);
+	drv->start_addr = ehdr->e_entry;
+	return 0;
+}
+
+static int pil_pronto_reset(struct pil_desc *pil)
+{
+	u32 reg;
+	int rc;
+	struct pronto_data *drv = dev_get_drvdata(pil->dev);
+	void __iomem *base = drv->base;
+	unsigned long start_addr = drv->start_addr;
+
+	/* Deassert reset to Pronto */
+	reg = readl_relaxed(drv->reset_base);
+	reg &= ~CLK_CTL_WCNSS_RESTART_BIT;
+	writel_relaxed(reg, drv->reset_base);
+	mb();
+
+	/* Configure boot address */
+	writel_relaxed(start_addr >> 16, base +
+			PRONTO_PMU_CCPU_BOOT_REMAP_ADDR);
+
+	/* Use the high vector table */
+	reg = readl_relaxed(base + PRONTO_PMU_CCPU_CTL);
+	reg |= PRONTO_PMU_CCPU_CTL_REMAP_EN | PRONTO_PMU_CCPU_CTL_HIGH_IVT;
+	writel_relaxed(reg, base + PRONTO_PMU_CCPU_CTL);
+
+	/* Turn on AHB clock of common_ss */
+	reg = readl_relaxed(base + PRONTO_PMU_COMMON_AHB_CBCR);
+	reg |= PRONTO_PMU_COMMON_AHB_CBCR_CLK_EN;
+	writel_relaxed(reg, base + PRONTO_PMU_COMMON_AHB_CBCR);
+
+	/* Turn on CPU clock of common_ss */
+	reg = readl_relaxed(base + PRONTO_PMU_COMMON_CPU_CBCR);
+	reg |= PRONTO_PMU_COMMON_CPU_CBCR_CLK_EN;
+	writel_relaxed(reg, base + PRONTO_PMU_COMMON_CPU_CBCR);
+
+	/* Enable A2XB bridge */
+	reg = readl_relaxed(base + PRONTO_PMU_COMMON_CSR);
+	reg |= PRONTO_PMU_COMMON_CSR_A2XB_CFG_EN;
+	writel_relaxed(reg, base + PRONTO_PMU_COMMON_CSR);
+
+	/* Enable common_ss power */
+	reg = readl_relaxed(base + PRONTO_PMU_COMMON_GDSCR);
+	reg &= ~PRONTO_PMU_COMMON_GDSCR_SW_COLLAPSE;
+	writel_relaxed(reg, base + PRONTO_PMU_COMMON_GDSCR);
+
+	/* Wait for AHB clock to be on */
+	rc = readl_tight_poll_timeout(base + PRONTO_PMU_COMMON_AHB_CBCR,
+				      reg,
+				      !(reg & PRONTO_PMU_COMMON_AHB_CLK_OFF),
+				      CLK_UPDATE_TIMEOUT_US);
+	if (rc) {
+		dev_err(pil->dev, "pronto common ahb clk enable timeout\n");
+		return rc;
+	}
+
+	/* Wait for CPU clock to be on */
+	rc = readl_tight_poll_timeout(base + PRONTO_PMU_COMMON_CPU_CBCR,
+				      reg,
+				      !(reg & PRONTO_PMU_COMMON_CPU_CLK_OFF),
+				      CLK_UPDATE_TIMEOUT_US);
+	if (rc) {
+		dev_err(pil->dev, "pronto common cpu clk enable timeout\n");
+		return rc;
+	}
+
+	/* Deassert ARM9 software reset */
+	reg = readl_relaxed(base + PRONTO_PMU_SOFT_RESET);
+	reg &= ~PRONTO_PMU_SOFT_RESET_CRCM_CCPU_SOFT_RESET;
+	writel_relaxed(reg, base + PRONTO_PMU_SOFT_RESET);
+
+	return 0;
+}
+
+static int pil_pronto_shutdown(struct pil_desc *pil)
+{
+	struct pronto_data *drv = dev_get_drvdata(pil->dev);
+	int ret;
+	u32 reg, status;
+
+	/* Halt A2XB */
+	writel_relaxed(1, drv->axi_halt_base + AXI_HALTREQ);
+	ret = readl_poll_timeout(drv->axi_halt_base + AXI_HALTACK,
+				status, status, 50, HALT_ACK_TIMEOUT_US);
+	if (ret)
+		dev_err(pil->dev, "Port halt timeout\n");
+	else if (!readl_relaxed(drv->axi_halt_base + AXI_IDLE))
+		dev_err(pil->dev, "Port halt failed\n");
+
+	writel_relaxed(0, drv->axi_halt_base + AXI_HALTREQ);
+
+	/* Assert reset to Pronto */
+	reg = readl_relaxed(drv->reset_base);
+	reg |= CLK_CTL_WCNSS_RESTART_BIT;
+	writel_relaxed(reg, drv->reset_base);
+
+	/* Wait for reset to complete */
+	mb();
+	usleep_range(1000, 2000);
+
+	/* Deassert reset to Pronto */
+	reg = readl_relaxed(drv->reset_base);
+	reg &= ~CLK_CTL_WCNSS_RESTART_BIT;
+	writel_relaxed(reg, drv->reset_base);
+	mb();
+
+	return 0;
+}
+
+static struct pil_reset_ops pil_pronto_ops = {
+	.init_image = pil_pronto_init_image,
+	.auth_and_reset = pil_pronto_reset,
+	.shutdown = pil_pronto_shutdown,
+	.proxy_vote = pil_pronto_make_proxy_vote,
+	.proxy_unvote = pil_pronto_remove_proxy_vote,
+};
+
+static int __devinit pil_pronto_probe(struct platform_device *pdev)
+{
+	struct pronto_data *drv;
+	struct resource *res;
+	struct pil_desc *desc;
+	int ret;
+	uint32_t regval;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -EINVAL;
+
+	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+	if (!drv)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, drv);
+
+	drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!drv->base)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res)
+		return -EINVAL;
+
+	drv->reset_base = devm_ioremap(&pdev->dev, res->start,
+					resource_size(res));
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	if (!res)
+		return -EINVAL;
+
+	drv->axi_halt_base = devm_ioremap(&pdev->dev, res->start,
+					  resource_size(res));
+
+	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+
+	ret = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name",
+				      &desc->name);
+	if (ret)
+		return ret;
+
+	desc->dev = &pdev->dev;
+	desc->owner = THIS_MODULE;
+	desc->proxy_timeout = 10000;
+
+	/* TODO: need to add secure boot when the support is available */
+	desc->ops = &pil_pronto_ops;
+	dev_info(&pdev->dev, "using non-secure boot\n");
+
+	drv->vreg = devm_regulator_get(&pdev->dev, "vdd_pronto_pll");
+	if (IS_ERR(drv->vreg)) {
+		dev_err(&pdev->dev, "failed to get pronto pll supply");
+		return PTR_ERR(drv->vreg);
+	}
+
+	ret = regulator_set_voltage(drv->vreg, 1800000, 1800000);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to set pll supply voltage\n");
+		return ret;
+	}
+
+	ret = regulator_set_optimum_mode(drv->vreg, 18000);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to set pll supply mode\n");
+		return ret;
+	}
+
+	drv->cxo = devm_clk_get(&pdev->dev, "xo");
+	if (IS_ERR(drv->cxo))
+		return PTR_ERR(drv->cxo);
+
+	drv->pil = msm_pil_register(desc);
+	if (IS_ERR(drv->pil))
+		return PTR_ERR(drv->pil);
+
+	/* Initialize common_ss GDSCR to wait 4 cycles between states */
+	regval = readl_relaxed(drv->base + PRONTO_PMU_COMMON_GDSCR)
+		& PRONTO_PMU_COMMON_GDSCR_SW_COLLAPSE;
+	regval |= (2 << EN_REST_WAIT) | (2 << EN_FEW_WAIT)
+		  | (2 << CLK_DIS_WAIT);
+	writel_relaxed(regval, drv->base + PRONTO_PMU_COMMON_GDSCR);
+
+	return 0;
+}
+
+static int __devexit pil_pronto_remove(struct platform_device *pdev)
+{
+	struct pronto_data *drv = platform_get_drvdata(pdev);
+	msm_pil_unregister(drv->pil);
+	return 0;
+}
+
+static struct of_device_id msm_pil_pronto_match[] = {
+	{.compatible = "qcom,pil-pronto"},
+	{}
+};
+
+static struct platform_driver pil_pronto_driver = {
+	.probe = pil_pronto_probe,
+	.remove = __devexit_p(pil_pronto_remove),
+	.driver = {
+		.name = "pil_pronto",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_pil_pronto_match,
+	},
+};
+
+static int __init pil_pronto_init(void)
+{
+	return platform_driver_register(&pil_pronto_driver);
+}
+module_init(pil_pronto_init);
+
+static void __exit pil_pronto_exit(void)
+{
+	platform_driver_unregister(&pil_pronto_driver);
+}
+module_exit(pil_pronto_exit);
+
+MODULE_DESCRIPTION("Support for booting PRONTO (WCNSS) processors");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-q6v3.c b/arch/arm/mach-msm/pil-q6v3.c
new file mode 100644
index 0000000..28b9dee
--- /dev/null
+++ b/arch/arm/mach-msm/pil-q6v3.c
@@ -0,0 +1,277 @@
+/* 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
+ * 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/elf.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include <mach/msm_iomap.h>
+
+#include "peripheral-loader.h"
+#include "scm-pas.h"
+
+#define QDSP6SS_RST_EVB		0x0000
+#define QDSP6SS_STRAP_TCM	0x001C
+#define QDSP6SS_STRAP_AHB	0x0020
+
+#define LCC_Q6_FUNC		(MSM_LPASS_CLK_CTL_BASE + 0x001C)
+#define LV_EN			BIT(27)
+#define STOP_CORE		BIT(26)
+#define CLAMP_IO		BIT(25)
+#define Q6SS_PRIV_ARES		BIT(24)
+#define Q6SS_SS_ARES		BIT(23)
+#define Q6SS_ISDB_ARES		BIT(22)
+#define Q6SS_ETM_ARES		BIT(21)
+#define Q6_JTAG_CRC_EN		BIT(20)
+#define Q6_JTAG_INV_EN		BIT(19)
+#define Q6_JTAG_CXC_EN		BIT(18)
+#define Q6_PXO_CRC_EN		BIT(17)
+#define Q6_PXO_INV_EN		BIT(16)
+#define Q6_PXO_CXC_EN		BIT(15)
+#define Q6_PXO_SLEEP_EN		BIT(14)
+#define Q6_SLP_CRC_EN		BIT(13)
+#define Q6_SLP_INV_EN		BIT(12)
+#define Q6_SLP_CXC_EN		BIT(11)
+#define CORE_ARES		BIT(10)
+#define CORE_L1_MEM_CORE_EN	BIT(9)
+#define CORE_TCM_MEM_CORE_EN	BIT(8)
+#define CORE_TCM_MEM_PERPH_EN	BIT(7)
+#define CORE_GFM4_CLK_EN	BIT(2)
+#define CORE_GFM4_RES		BIT(1)
+#define RAMP_PLL_SRC_SEL	BIT(0)
+
+#define Q6_STRAP_AHB_UPPER	(0x290 << 12)
+#define Q6_STRAP_AHB_LOWER	0x280
+#define Q6_STRAP_TCM_BASE	(0x28C << 15)
+#define Q6_STRAP_TCM_CONFIG	0x28B
+
+struct q6v3_data {
+	void __iomem *base;
+	unsigned long start_addr;
+	struct pil_device *pil;
+	struct clk *pll;
+};
+
+static int pil_q6v3_init_image(struct pil_desc *pil, const u8 *metadata,
+		size_t size)
+{
+	const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
+	struct q6v3_data *drv = dev_get_drvdata(pil->dev);
+	drv->start_addr = ehdr->e_entry;
+	return 0;
+}
+
+static void pil_q6v3_remove_proxy_votes(struct pil_desc *pil)
+{
+	struct q6v3_data *drv = dev_get_drvdata(pil->dev);
+	clk_disable_unprepare(drv->pll);
+}
+
+static int pil_q6v3_make_proxy_votes(struct pil_desc *pil)
+{
+	int ret;
+	struct q6v3_data *drv = dev_get_drvdata(pil->dev);
+
+	ret = clk_prepare_enable(drv->pll);
+	if (ret) {
+		dev_err(pil->dev, "Failed to enable PLL\n");
+		return ret;
+	}
+	return 0;
+}
+
+static int pil_q6v3_reset(struct pil_desc *pil)
+{
+	u32 reg;
+	struct q6v3_data *drv = dev_get_drvdata(pil->dev);
+
+	/* Put Q6 into reset */
+	reg = readl_relaxed(LCC_Q6_FUNC);
+	reg |= Q6SS_SS_ARES | Q6SS_ISDB_ARES | Q6SS_ETM_ARES | STOP_CORE |
+		CORE_ARES;
+	reg &= ~CORE_GFM4_CLK_EN;
+	writel_relaxed(reg, LCC_Q6_FUNC);
+
+	/* Wait 8 AHB cycles for Q6 to be fully reset (AHB = 1.5Mhz) */
+	usleep_range(20, 30);
+
+	/* Turn on Q6 memory */
+	reg |= CORE_GFM4_CLK_EN | CORE_L1_MEM_CORE_EN | CORE_TCM_MEM_CORE_EN |
+		CORE_TCM_MEM_PERPH_EN;
+	writel_relaxed(reg, LCC_Q6_FUNC);
+
+	/* Turn on Q6 core clocks and take core out of reset */
+	reg &= ~(CLAMP_IO | Q6SS_SS_ARES | Q6SS_ISDB_ARES | Q6SS_ETM_ARES |
+			CORE_ARES);
+	writel_relaxed(reg, LCC_Q6_FUNC);
+
+	/* Wait for clocks to be enabled */
+	mb();
+	/* Program boot address */
+	writel_relaxed((drv->start_addr >> 12) & 0xFFFFF,
+			drv->base + QDSP6SS_RST_EVB);
+
+	writel_relaxed(Q6_STRAP_TCM_CONFIG | Q6_STRAP_TCM_BASE,
+			drv->base + QDSP6SS_STRAP_TCM);
+	writel_relaxed(Q6_STRAP_AHB_UPPER | Q6_STRAP_AHB_LOWER,
+			drv->base + QDSP6SS_STRAP_AHB);
+
+	/* Wait for addresses to be programmed before starting Q6 */
+	mb();
+
+	/* Start Q6 instruction execution */
+	reg &= ~STOP_CORE;
+	writel_relaxed(reg, LCC_Q6_FUNC);
+
+	return 0;
+}
+
+static int pil_q6v3_shutdown(struct pil_desc *pil)
+{
+	u32 reg;
+
+	/* Put Q6 into reset */
+	reg = readl_relaxed(LCC_Q6_FUNC);
+	reg |= Q6SS_SS_ARES | Q6SS_ISDB_ARES | Q6SS_ETM_ARES | STOP_CORE |
+		CORE_ARES;
+	reg &= ~CORE_GFM4_CLK_EN;
+	writel_relaxed(reg, LCC_Q6_FUNC);
+
+	/* Wait 8 AHB cycles for Q6 to be fully reset (AHB = 1.5Mhz) */
+	usleep_range(20, 30);
+
+	/* Turn off Q6 memory */
+	reg &= ~(CORE_L1_MEM_CORE_EN | CORE_TCM_MEM_CORE_EN |
+		CORE_TCM_MEM_PERPH_EN);
+	writel_relaxed(reg, LCC_Q6_FUNC);
+
+	reg |= CLAMP_IO;
+	writel_relaxed(reg, LCC_Q6_FUNC);
+
+	return 0;
+}
+
+static struct pil_reset_ops pil_q6v3_ops = {
+	.init_image = pil_q6v3_init_image,
+	.auth_and_reset = pil_q6v3_reset,
+	.shutdown = pil_q6v3_shutdown,
+	.proxy_vote = pil_q6v3_make_proxy_votes,
+	.proxy_unvote = pil_q6v3_remove_proxy_votes,
+};
+
+static int pil_q6v3_init_image_trusted(struct pil_desc *pil,
+		const u8 *metadata, size_t size)
+{
+	return pas_init_image(PAS_Q6, metadata, size);
+}
+
+static int pil_q6v3_reset_trusted(struct pil_desc *pil)
+{
+	return pas_auth_and_reset(PAS_Q6);
+}
+
+static int pil_q6v3_shutdown_trusted(struct pil_desc *pil)
+{
+	return pas_shutdown(PAS_Q6);
+}
+
+static struct pil_reset_ops pil_q6v3_ops_trusted = {
+	.init_image = pil_q6v3_init_image_trusted,
+	.auth_and_reset = pil_q6v3_reset_trusted,
+	.shutdown = pil_q6v3_shutdown_trusted,
+	.proxy_vote = pil_q6v3_make_proxy_votes,
+	.proxy_unvote = pil_q6v3_remove_proxy_votes,
+};
+
+static int __devinit pil_q6v3_driver_probe(struct platform_device *pdev)
+{
+	struct q6v3_data *drv;
+	struct resource *res;
+	struct pil_desc *desc;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -EINVAL;
+
+	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+	if (!drv)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, drv);
+
+	drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!drv->base)
+		return -ENOMEM;
+
+	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+	if (!drv)
+		return -ENOMEM;
+
+	drv->pll = devm_clk_get(&pdev->dev, "pll4");
+	if (IS_ERR(drv->pll))
+		return PTR_ERR(drv->pll);
+
+	desc->name = "q6";
+	desc->dev = &pdev->dev;
+	desc->owner = THIS_MODULE;
+	desc->proxy_timeout = 10000;
+
+	if (pas_supported(PAS_Q6) > 0) {
+		desc->ops = &pil_q6v3_ops_trusted;
+		dev_info(&pdev->dev, "using secure boot\n");
+	} else {
+		desc->ops = &pil_q6v3_ops;
+		dev_info(&pdev->dev, "using non-secure boot\n");
+	}
+
+	drv->pil = msm_pil_register(desc);
+	if (IS_ERR(drv->pil)) {
+		return PTR_ERR(drv->pil);
+	}
+	return 0;
+}
+
+static int __devexit pil_q6v3_driver_exit(struct platform_device *pdev)
+{
+	struct q6v3_data *drv = platform_get_drvdata(pdev);
+	msm_pil_unregister(drv->pil);
+	return 0;
+}
+
+static struct platform_driver pil_q6v3_driver = {
+	.probe = pil_q6v3_driver_probe,
+	.remove = __devexit_p(pil_q6v3_driver_exit),
+	.driver = {
+		.name = "pil_qdsp6v3",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init pil_q6v3_init(void)
+{
+	return platform_driver_register(&pil_q6v3_driver);
+}
+module_init(pil_q6v3_init);
+
+static void __exit pil_q6v3_exit(void)
+{
+	platform_driver_unregister(&pil_q6v3_driver);
+}
+module_exit(pil_q6v3_exit);
+
+MODULE_DESCRIPTION("Support for booting QDSP6v3 (Hexagon) processors");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-q6v4.c b/arch/arm/mach-msm/pil-q6v4.c
new file mode 100644
index 0000000..131a74b
--- /dev/null
+++ b/arch/arm/mach-msm/pil-q6v4.c
@@ -0,0 +1,466 @@
+/* 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
+ * 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/regulator/consumer.h>
+#include <linux/elf.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include <mach/msm_bus.h>
+#include <mach/msm_iomap.h>
+
+#include "peripheral-loader.h"
+#include "pil-q6v4.h"
+#include "scm-pas.h"
+
+#define QDSP6SS_RST_EVB		0x0
+#define QDSP6SS_RESET		0x04
+#define QDSP6SS_STRAP_TCM	0x1C
+#define QDSP6SS_STRAP_AHB	0x20
+#define QDSP6SS_GFMUX_CTL	0x30
+#define QDSP6SS_PWR_CTL		0x38
+
+#define MSS_S_HCLK_CTL		(MSM_CLK_CTL_BASE + 0x2C70)
+#define MSS_SLP_CLK_CTL		(MSM_CLK_CTL_BASE + 0x2C60)
+#define SFAB_MSS_M_ACLK_CTL	(MSM_CLK_CTL_BASE + 0x2340)
+#define SFAB_MSS_S_HCLK_CTL	(MSM_CLK_CTL_BASE + 0x2C00)
+#define MSS_RESET		(MSM_CLK_CTL_BASE + 0x2C64)
+
+#define Q6SS_SS_ARES		BIT(0)
+#define Q6SS_CORE_ARES		BIT(1)
+#define Q6SS_ISDB_ARES		BIT(2)
+#define Q6SS_ETM_ARES		BIT(3)
+#define Q6SS_STOP_CORE_ARES	BIT(4)
+#define Q6SS_PRIV_ARES		BIT(5)
+
+#define Q6SS_L2DATA_SLP_NRET_N	BIT(0)
+#define Q6SS_SLP_RET_N		BIT(1)
+#define Q6SS_L1TCM_SLP_NRET_N	BIT(2)
+#define Q6SS_L2TAG_SLP_NRET_N	BIT(3)
+#define Q6SS_ETB_SLEEP_NRET_N	BIT(4)
+#define Q6SS_ARR_STBY_N		BIT(5)
+#define Q6SS_CLAMP_IO		BIT(6)
+
+#define Q6SS_CLK_ENA		BIT(1)
+#define Q6SS_SRC_SWITCH_CLK_OVR	BIT(8)
+
+struct q6v4_data {
+	void __iomem *base;
+	void __iomem *modem_base;
+	unsigned long start_addr;
+	struct regulator *vreg;
+	struct regulator *pll_supply;
+	bool vreg_enabled;
+	struct clk *xo;
+	struct pil_device *pil;
+};
+
+static int pil_q6v4_init_image(struct pil_desc *pil, const u8 *metadata,
+		size_t size)
+{
+	const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
+	struct q6v4_data *drv = dev_get_drvdata(pil->dev);
+	drv->start_addr = ehdr->e_entry;
+	return 0;
+}
+
+static int pil_q6v4_make_proxy_votes(struct pil_desc *pil)
+{
+	const struct q6v4_data *drv = dev_get_drvdata(pil->dev);
+	int ret;
+
+	ret = clk_prepare_enable(drv->xo);
+	if (ret) {
+		dev_err(pil->dev, "Failed to enable XO\n");
+		goto err;
+	}
+	if (drv->pll_supply) {
+		ret = regulator_enable(drv->pll_supply);
+		if (ret) {
+			dev_err(pil->dev, "Failed to enable pll supply\n");
+			goto err_regulator;
+		}
+	}
+	return 0;
+err_regulator:
+	clk_disable_unprepare(drv->xo);
+err:
+	return ret;
+}
+
+static void pil_q6v4_remove_proxy_votes(struct pil_desc *pil)
+{
+	const struct q6v4_data *drv = dev_get_drvdata(pil->dev);
+	if (drv->pll_supply)
+		regulator_disable(drv->pll_supply);
+	clk_disable_unprepare(drv->xo);
+}
+
+static int pil_q6v4_power_up(struct device *dev)
+{
+	int err;
+	struct q6v4_data *drv = dev_get_drvdata(dev);
+
+	err = regulator_set_voltage(drv->vreg, 375000, 375000);
+	if (err) {
+		dev_err(dev, "Failed to set regulator's voltage step.\n");
+		return err;
+	}
+	err = regulator_enable(drv->vreg);
+	if (err) {
+		dev_err(dev, "Failed to enable regulator.\n");
+		return err;
+	}
+
+	/*
+	 * Q6 hardware requires a two step voltage ramp-up.
+	 * Delay between the steps.
+	 */
+	udelay(100);
+
+	err = regulator_set_voltage(drv->vreg, 1050000, 1050000);
+	if (err) {
+		dev_err(dev, "Failed to set regulator's voltage.\n");
+		return err;
+	}
+	drv->vreg_enabled = true;
+	return 0;
+}
+
+static DEFINE_MUTEX(pil_q6v4_modem_lock);
+static unsigned pil_q6v4_modem_count;
+
+/* Bring modem subsystem out of reset */
+static void pil_q6v4_init_modem(void __iomem *base, void __iomem *jtag_clk)
+{
+	mutex_lock(&pil_q6v4_modem_lock);
+	if (!pil_q6v4_modem_count) {
+		/* Enable MSS clocks */
+		writel_relaxed(0x10, SFAB_MSS_M_ACLK_CTL);
+		writel_relaxed(0x10, SFAB_MSS_S_HCLK_CTL);
+		writel_relaxed(0x10, MSS_S_HCLK_CTL);
+		writel_relaxed(0x10, MSS_SLP_CLK_CTL);
+		/* Wait for clocks to enable */
+		mb();
+		udelay(10);
+
+		/* De-assert MSS reset */
+		writel_relaxed(0x0, MSS_RESET);
+		mb();
+		udelay(10);
+		/* Enable MSS */
+		writel_relaxed(0x7, base);
+	}
+
+	/* Enable JTAG clocks */
+	/* TODO: Remove if/when Q6 software enables them? */
+	writel_relaxed(0x10, jtag_clk);
+
+	pil_q6v4_modem_count++;
+	mutex_unlock(&pil_q6v4_modem_lock);
+}
+
+/* Put modem subsystem back into reset */
+static void pil_q6v4_shutdown_modem(void)
+{
+	mutex_lock(&pil_q6v4_modem_lock);
+	if (pil_q6v4_modem_count)
+		pil_q6v4_modem_count--;
+	if (pil_q6v4_modem_count == 0)
+		writel_relaxed(0x1, MSS_RESET);
+	mutex_unlock(&pil_q6v4_modem_lock);
+}
+
+static int pil_q6v4_reset(struct pil_desc *pil)
+{
+	u32 reg, err;
+	const struct q6v4_data *drv = dev_get_drvdata(pil->dev);
+	const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
+
+	err = pil_q6v4_power_up(pil->dev);
+	if (err)
+		return err;
+	/* Enable Q6 ACLK */
+	writel_relaxed(0x10, pdata->aclk_reg);
+
+	if (drv->modem_base)
+		pil_q6v4_init_modem(drv->modem_base, pdata->jtag_clk_reg);
+
+	/* Unhalt bus port */
+	err = msm_bus_axi_portunhalt(pdata->bus_port);
+	if (err)
+		dev_err(pil->dev, "Failed to unhalt bus port\n");
+
+	/* Deassert Q6SS_SS_ARES */
+	reg = readl_relaxed(drv->base + QDSP6SS_RESET);
+	reg &= ~(Q6SS_SS_ARES);
+	writel_relaxed(reg, drv->base + QDSP6SS_RESET);
+
+	/* Program boot address */
+	writel_relaxed((drv->start_addr >> 8) & 0xFFFFFF,
+			drv->base + QDSP6SS_RST_EVB);
+
+	/* Program TCM and AHB address ranges */
+	writel_relaxed(pdata->strap_tcm_base, drv->base + QDSP6SS_STRAP_TCM);
+	writel_relaxed(pdata->strap_ahb_upper | pdata->strap_ahb_lower,
+		       drv->base + QDSP6SS_STRAP_AHB);
+
+	/* Turn off Q6 core clock */
+	writel_relaxed(Q6SS_SRC_SWITCH_CLK_OVR,
+		       drv->base + QDSP6SS_GFMUX_CTL);
+
+	/* Put memories to sleep */
+	writel_relaxed(Q6SS_CLAMP_IO, drv->base + QDSP6SS_PWR_CTL);
+
+	/* Assert resets */
+	reg = readl_relaxed(drv->base + QDSP6SS_RESET);
+	reg |= (Q6SS_CORE_ARES | Q6SS_ISDB_ARES | Q6SS_ETM_ARES
+	    | Q6SS_STOP_CORE_ARES);
+	writel_relaxed(reg, drv->base + QDSP6SS_RESET);
+
+	/* Wait 8 AHB cycles for Q6 to be fully reset (AHB = 1.5Mhz) */
+	mb();
+	usleep_range(20, 30);
+
+	/* Turn on Q6 memories */
+	reg = Q6SS_L2DATA_SLP_NRET_N | Q6SS_SLP_RET_N | Q6SS_L1TCM_SLP_NRET_N
+	    | Q6SS_L2TAG_SLP_NRET_N | Q6SS_ETB_SLEEP_NRET_N | Q6SS_ARR_STBY_N
+	    | Q6SS_CLAMP_IO;
+	writel_relaxed(reg, drv->base + QDSP6SS_PWR_CTL);
+
+	/* Turn on Q6 core clock */
+	reg = Q6SS_CLK_ENA | Q6SS_SRC_SWITCH_CLK_OVR;
+	writel_relaxed(reg, drv->base + QDSP6SS_GFMUX_CTL);
+
+	/* Remove Q6SS_CLAMP_IO */
+	reg = readl_relaxed(drv->base + QDSP6SS_PWR_CTL);
+	reg &= ~Q6SS_CLAMP_IO;
+	writel_relaxed(reg, drv->base + QDSP6SS_PWR_CTL);
+
+	/* Bring Q6 core out of reset and start execution. */
+	writel_relaxed(0x0, drv->base + QDSP6SS_RESET);
+
+	return 0;
+}
+
+static int pil_q6v4_shutdown(struct pil_desc *pil)
+{
+	u32 reg;
+	struct q6v4_data *drv = dev_get_drvdata(pil->dev);
+	const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
+
+	/* Make sure bus port is halted */
+	msm_bus_axi_porthalt(pdata->bus_port);
+
+	/* Turn off Q6 core clock */
+	writel_relaxed(Q6SS_SRC_SWITCH_CLK_OVR,
+		       drv->base + QDSP6SS_GFMUX_CTL);
+
+	/* Assert resets */
+	reg = (Q6SS_SS_ARES | Q6SS_CORE_ARES | Q6SS_ISDB_ARES
+	     | Q6SS_ETM_ARES | Q6SS_STOP_CORE_ARES | Q6SS_PRIV_ARES);
+	writel_relaxed(reg, drv->base + QDSP6SS_RESET);
+
+	/* Turn off Q6 memories */
+	writel_relaxed(Q6SS_CLAMP_IO, drv->base + QDSP6SS_PWR_CTL);
+
+	if (drv->modem_base)
+		pil_q6v4_shutdown_modem();
+
+	if (drv->vreg_enabled) {
+		regulator_disable(drv->vreg);
+		drv->vreg_enabled = false;
+	}
+
+	return 0;
+}
+
+static struct pil_reset_ops pil_q6v4_ops = {
+	.init_image = pil_q6v4_init_image,
+	.auth_and_reset = pil_q6v4_reset,
+	.shutdown = pil_q6v4_shutdown,
+	.proxy_vote = pil_q6v4_make_proxy_votes,
+	.proxy_unvote = pil_q6v4_remove_proxy_votes,
+};
+
+static int pil_q6v4_init_image_trusted(struct pil_desc *pil,
+		const u8 *metadata, size_t size)
+{
+	const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
+	return pas_init_image(pdata->pas_id, metadata, size);
+}
+
+static int pil_q6v4_reset_trusted(struct pil_desc *pil)
+{
+	const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
+	int err;
+
+	err = pil_q6v4_power_up(pil->dev);
+	if (err)
+		return err;
+
+	/* Unhalt bus port */
+	err = msm_bus_axi_portunhalt(pdata->bus_port);
+	if (err)
+		dev_err(pil->dev, "Failed to unhalt bus port\n");
+	return pas_auth_and_reset(pdata->pas_id);
+}
+
+static int pil_q6v4_shutdown_trusted(struct pil_desc *pil)
+{
+	int ret;
+	struct q6v4_data *drv = dev_get_drvdata(pil->dev);
+	struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
+
+	/* Make sure bus port is halted */
+	msm_bus_axi_porthalt(pdata->bus_port);
+
+	ret = pas_shutdown(pdata->pas_id);
+	if (ret)
+		return ret;
+
+	if (drv->vreg_enabled) {
+		regulator_disable(drv->vreg);
+		drv->vreg_enabled = false;
+	}
+
+	return ret;
+}
+
+static struct pil_reset_ops pil_q6v4_ops_trusted = {
+	.init_image = pil_q6v4_init_image_trusted,
+	.auth_and_reset = pil_q6v4_reset_trusted,
+	.shutdown = pil_q6v4_shutdown_trusted,
+	.proxy_vote = pil_q6v4_make_proxy_votes,
+	.proxy_unvote = pil_q6v4_remove_proxy_votes,
+};
+
+static int __devinit pil_q6v4_driver_probe(struct platform_device *pdev)
+{
+	const struct pil_q6v4_pdata *pdata = pdev->dev.platform_data;
+	struct q6v4_data *drv;
+	struct resource *res;
+	struct pil_desc *desc;
+	int ret;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -EINVAL;
+
+	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+	if (!drv)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, drv);
+
+	drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!drv->base)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (res) {
+		drv->modem_base = devm_ioremap(&pdev->dev, res->start,
+				resource_size(res));
+		if (!drv->modem_base)
+			return -ENOMEM;
+	}
+
+	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+
+	drv->pll_supply = devm_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");
+			return ret;
+		}
+
+		ret = regulator_set_optimum_mode(drv->pll_supply, 100000);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "failed to set pll optimum mode\n");
+			return ret;
+		}
+	}
+
+	desc->name = pdata->name;
+	desc->depends_on = pdata->depends;
+	desc->dev = &pdev->dev;
+	desc->owner = THIS_MODULE;
+	desc->proxy_timeout = 10000;
+
+	if (pas_supported(pdata->pas_id) > 0) {
+		desc->ops = &pil_q6v4_ops_trusted;
+		dev_info(&pdev->dev, "using secure boot\n");
+	} else {
+		desc->ops = &pil_q6v4_ops;
+		dev_info(&pdev->dev, "using non-secure boot\n");
+	}
+
+	drv->vreg = devm_regulator_get(&pdev->dev, "core_vdd");
+	if (IS_ERR(drv->vreg))
+		return PTR_ERR(drv->vreg);
+
+	ret = regulator_set_optimum_mode(drv->vreg, 100000);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to set regulator's mode.\n");
+		return ret;
+	}
+
+	drv->xo = devm_clk_get(&pdev->dev, "xo");
+	if (IS_ERR(drv->xo))
+		return PTR_ERR(drv->xo);
+
+	drv->pil = msm_pil_register(desc);
+	if (IS_ERR(drv->pil))
+		return PTR_ERR(drv->pil);
+	return 0;
+}
+
+static int __devexit pil_q6v4_driver_exit(struct platform_device *pdev)
+{
+	struct q6v4_data *drv = platform_get_drvdata(pdev);
+	msm_pil_unregister(drv->pil);
+	return 0;
+}
+
+static struct platform_driver pil_q6v4_driver = {
+	.probe = pil_q6v4_driver_probe,
+	.remove = __devexit_p(pil_q6v4_driver_exit),
+	.driver = {
+		.name = "pil_qdsp6v4",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init pil_q6v4_init(void)
+{
+	return platform_driver_register(&pil_q6v4_driver);
+}
+module_init(pil_q6v4_init);
+
+static void __exit pil_q6v4_exit(void)
+{
+	platform_driver_unregister(&pil_q6v4_driver);
+}
+module_exit(pil_q6v4_exit);
+
+MODULE_DESCRIPTION("Support for booting QDSP6v4 (Hexagon) processors");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-q6v4.h b/arch/arm/mach-msm/pil-q6v4.h
new file mode 100644
index 0000000..b0b97d0
--- /dev/null
+++ b/arch/arm/mach-msm/pil-q6v4.h
@@ -0,0 +1,26 @@
+/* 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
+ * 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 __MSM_PIL_Q6V4_H
+#define __MSM_PIL_Q6V4_H
+
+struct pil_q6v4_pdata {
+	const unsigned long strap_tcm_base;
+	const unsigned long strap_ahb_upper;
+	const unsigned long strap_ahb_lower;
+	void __iomem *aclk_reg;
+	void __iomem *jtag_clk_reg;
+	const char *name;
+	const char *depends;
+	const unsigned pas_id;
+	int bus_port;
+};
+#endif
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
new file mode 100644
index 0000000..311f8a7
--- /dev/null
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -0,0 +1,141 @@
+/*
+ * 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+
+#include "peripheral-loader.h"
+#include "pil-q6v5.h"
+
+#define QDSP6SS_RST_EVB			0x010
+#define PROXY_TIMEOUT_MS		10000
+
+static int pil_lpass_shutdown(struct pil_desc *pil)
+{
+	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+
+	pil_q6v5_halt_axi_port(pil, drv->axi_halt_base);
+
+	/*
+	 * If the shutdown function is called before the reset function, clocks
+	 * will not be enabled yet. Enable them here so that register writes
+	 * performed during the shutdown succeed.
+	 */
+	if (drv->is_booted == false)
+		pil_q6v5_enable_clks(pil);
+
+	pil_q6v5_shutdown(pil);
+	pil_q6v5_disable_clks(pil);
+
+	drv->is_booted = false;
+
+	return 0;
+}
+
+static int pil_lpass_reset(struct pil_desc *pil)
+{
+	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+	int ret;
+
+	ret = pil_q6v5_enable_clks(pil);
+	if (ret)
+		return ret;
+
+	/* Program Image Address */
+	writel_relaxed(((drv->start_addr >> 4) & 0x0FFFFFF0),
+				drv->reg_base + QDSP6SS_RST_EVB);
+
+	ret = pil_q6v5_reset(pil);
+	if (ret) {
+		pil_q6v5_disable_clks(pil);
+		return ret;
+	}
+
+	drv->is_booted = true;
+
+	return 0;
+}
+
+static struct pil_reset_ops pil_lpass_ops = {
+	.init_image = pil_q6v5_init_image,
+	.proxy_vote = pil_q6v5_make_proxy_votes,
+	.proxy_unvote = pil_q6v5_remove_proxy_votes,
+	.auth_and_reset = pil_lpass_reset,
+	.shutdown = pil_lpass_shutdown,
+};
+
+static int __devinit pil_lpass_driver_probe(struct platform_device *pdev)
+{
+	struct q6v5_data *drv;
+	struct pil_desc *desc;
+
+	desc = pil_q6v5_init(pdev);
+	if (IS_ERR(desc))
+		return PTR_ERR(desc);
+
+	drv = platform_get_drvdata(pdev);
+	if (drv == NULL)
+		return -ENODEV;
+
+	desc->ops = &pil_lpass_ops;
+	desc->owner = THIS_MODULE;
+	desc->proxy_timeout = PROXY_TIMEOUT_MS;
+
+	drv->pil = msm_pil_register(desc);
+	if (IS_ERR(drv->pil))
+		return PTR_ERR(drv->pil);
+
+	return 0;
+}
+
+static int __devexit pil_lpass_driver_exit(struct platform_device *pdev)
+{
+	struct q6v5_data *drv = platform_get_drvdata(pdev);
+	msm_pil_unregister(drv->pil);
+	return 0;
+}
+
+static struct of_device_id lpass_match_table[] = {
+	{ .compatible = "qcom,pil-q6v5-lpass" },
+	{}
+};
+
+static struct platform_driver pil_lpass_driver = {
+	.probe = pil_lpass_driver_probe,
+	.remove = __devexit_p(pil_lpass_driver_exit),
+	.driver = {
+		.name = "pil-q6v5-lpass",
+		.of_match_table = lpass_match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init pil_lpass_init(void)
+{
+	return platform_driver_register(&pil_lpass_driver);
+}
+module_init(pil_lpass_init);
+
+static void __exit pil_lpass_exit(void)
+{
+	platform_driver_unregister(&pil_lpass_driver);
+}
+module_exit(pil_lpass_exit);
+
+MODULE_DESCRIPTION("Support for booting low-power audio subsystems with QDSP6v5 (Hexagon) processors");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-q6v5.c b/arch/arm/mach-msm/pil-q6v5.c
new file mode 100644
index 0000000..6a96990
--- /dev/null
+++ b/arch/arm/mach-msm/pil-q6v5.c
@@ -0,0 +1,273 @@
+/*
+ * 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/elf.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+
+#include <mach/clk.h>
+
+#include "peripheral-loader.h"
+#include "pil-q6v5.h"
+
+/* QDSP6SS Register Offsets */
+#define QDSP6SS_RESET			0x014
+#define QDSP6SS_GFMUX_CTL		0x020
+#define QDSP6SS_PWR_CTL			0x030
+
+/* AXI Halt Register Offsets */
+#define AXI_HALTREQ			0x0
+#define AXI_HALTACK			0x4
+#define AXI_IDLE			0x8
+
+#define HALT_ACK_TIMEOUT_US		100000
+
+/* QDSP6SS_RESET */
+#define Q6SS_CORE_ARES			BIT(1)
+#define Q6SS_ETM_ISDB_ARES		BIT(3)
+#define Q6SS_STOP_CORE			BIT(4)
+
+/* QDSP6SS_GFMUX_CTL */
+#define Q6SS_CLK_ENA			BIT(1)
+
+/* QDSP6SS_PWR_CTL */
+#define Q6SS_L2DATA_SLP_NRET_N		BIT(0)
+#define Q6SS_L2TAG_SLP_NRET_N		BIT(16)
+#define Q6SS_ETB_SLP_NRET_N		BIT(17)
+#define Q6SS_L2DATA_STBY_N		BIT(18)
+#define Q6SS_SLP_RET_N			BIT(19)
+#define Q6SS_CLAMP_IO			BIT(20)
+#define QDSS_BHS_ON			BIT(21)
+
+int pil_q6v5_make_proxy_votes(struct pil_desc *pil)
+{
+	int ret;
+	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+
+	ret = clk_prepare_enable(drv->xo);
+	if (ret) {
+		dev_err(pil->dev, "Failed to enable XO\n");
+		return ret;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(pil_q6v5_make_proxy_votes);
+
+void pil_q6v5_remove_proxy_votes(struct pil_desc *pil)
+{
+	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+	clk_disable_unprepare(drv->xo);
+}
+EXPORT_SYMBOL(pil_q6v5_remove_proxy_votes);
+
+void pil_q6v5_halt_axi_port(struct pil_desc *pil, void __iomem *halt_base)
+{
+	int ret;
+	u32 status;
+
+	/* Assert halt request */
+	writel_relaxed(1, halt_base + AXI_HALTREQ);
+
+	/* Wait for halt */
+	ret = readl_poll_timeout(halt_base + AXI_HALTACK,
+		status, status != 0, 50, HALT_ACK_TIMEOUT_US);
+	if (ret)
+		dev_warn(pil->dev, "Port %p halt timeout\n", halt_base);
+	else if (!readl_relaxed(halt_base + AXI_IDLE))
+		dev_warn(pil->dev, "Port %p halt failed\n", halt_base);
+
+	/* Clear halt request (port will remain halted until reset) */
+	writel_relaxed(0, halt_base + AXI_HALTREQ);
+}
+EXPORT_SYMBOL(pil_q6v5_halt_axi_port);
+
+int pil_q6v5_init_image(struct pil_desc *pil, const u8 *metadata,
+			       size_t size)
+{
+	const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
+	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+	drv->start_addr = ehdr->e_entry;
+	return 0;
+}
+EXPORT_SYMBOL(pil_q6v5_init_image);
+
+int pil_q6v5_enable_clks(struct pil_desc *pil)
+{
+	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+	int ret;
+
+	ret = clk_reset(drv->core_clk, CLK_RESET_DEASSERT);
+	if (ret)
+		goto err_reset;
+	ret = clk_prepare_enable(drv->core_clk);
+	if (ret)
+		goto err_core_clk;
+	ret = clk_prepare_enable(drv->bus_clk);
+	if (ret)
+		goto err_bus_clk;
+
+	return 0;
+
+err_bus_clk:
+	clk_disable_unprepare(drv->core_clk);
+err_core_clk:
+	clk_reset(drv->core_clk, CLK_RESET_ASSERT);
+err_reset:
+	return ret;
+}
+EXPORT_SYMBOL(pil_q6v5_enable_clks);
+
+void pil_q6v5_disable_clks(struct pil_desc *pil)
+{
+	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+
+	clk_disable_unprepare(drv->bus_clk);
+	clk_disable_unprepare(drv->core_clk);
+	clk_reset(drv->core_clk, CLK_RESET_ASSERT);
+}
+EXPORT_SYMBOL(pil_q6v5_disable_clks);
+
+void pil_q6v5_shutdown(struct pil_desc *pil)
+{
+	u32 val;
+	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+
+	/* Turn off core clock */
+	val = readl_relaxed(drv->reg_base + QDSP6SS_GFMUX_CTL);
+	val &= ~Q6SS_CLK_ENA;
+	writel_relaxed(val, drv->reg_base + QDSP6SS_GFMUX_CTL);
+
+	/* Clamp IO */
+	val = readl_relaxed(drv->reg_base + QDSP6SS_PWR_CTL);
+	val |= Q6SS_CLAMP_IO;
+	writel_relaxed(val, drv->reg_base + QDSP6SS_PWR_CTL);
+
+	/* Turn off Q6 memories */
+	val &= ~(Q6SS_L2DATA_SLP_NRET_N | Q6SS_SLP_RET_N |
+		 Q6SS_L2TAG_SLP_NRET_N | Q6SS_ETB_SLP_NRET_N |
+		 Q6SS_L2DATA_STBY_N);
+	writel_relaxed(Q6SS_CLAMP_IO, drv->reg_base + QDSP6SS_PWR_CTL);
+
+	/* Assert Q6 resets */
+	val = readl_relaxed(drv->reg_base + QDSP6SS_RESET);
+	val = (Q6SS_CORE_ARES | Q6SS_ETM_ISDB_ARES);
+	writel_relaxed(val, drv->reg_base + QDSP6SS_RESET);
+
+	/* Kill power at block headswitch (affects LPASS only) */
+	val = readl_relaxed(drv->reg_base + QDSP6SS_PWR_CTL);
+	val &= ~QDSS_BHS_ON;
+	writel_relaxed(val, drv->reg_base + QDSP6SS_PWR_CTL);
+}
+EXPORT_SYMBOL(pil_q6v5_shutdown);
+
+int pil_q6v5_reset(struct pil_desc *pil)
+{
+	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+	u32 val;
+
+	/* Assert resets, stop core */
+	val = readl_relaxed(drv->reg_base + QDSP6SS_RESET);
+	val |= (Q6SS_CORE_ARES | Q6SS_ETM_ISDB_ARES | Q6SS_STOP_CORE);
+	writel_relaxed(val, drv->reg_base + QDSP6SS_RESET);
+
+	/* Enable power block headswitch (only affects LPASS) */
+	val = readl_relaxed(drv->reg_base + QDSP6SS_PWR_CTL);
+	val |= QDSS_BHS_ON;
+	writel_relaxed(val, drv->reg_base + QDSP6SS_PWR_CTL);
+
+	/* Turn on memories */
+	val = readl_relaxed(drv->reg_base + QDSP6SS_PWR_CTL);
+	val |= Q6SS_L2DATA_SLP_NRET_N | Q6SS_SLP_RET_N |
+	       Q6SS_L2TAG_SLP_NRET_N | Q6SS_ETB_SLP_NRET_N |
+	       Q6SS_L2DATA_STBY_N;
+	writel_relaxed(val, drv->reg_base + QDSP6SS_PWR_CTL);
+
+	/* Remove IO clamp */
+	val &= ~Q6SS_CLAMP_IO;
+	writel_relaxed(val, drv->reg_base + QDSP6SS_PWR_CTL);
+
+	/* Bring core out of reset */
+	val = Q6SS_STOP_CORE;
+	writel_relaxed(val, drv->reg_base + QDSP6SS_RESET);
+
+	/* Turn on core clock */
+	val = readl_relaxed(drv->reg_base + QDSP6SS_GFMUX_CTL);
+	val |= Q6SS_CLK_ENA;
+	writel_relaxed(val, drv->reg_base + QDSP6SS_GFMUX_CTL);
+
+	/* Start core execution */
+	val = readl_relaxed(drv->reg_base + QDSP6SS_RESET);
+	val &= ~Q6SS_STOP_CORE;
+	writel_relaxed(val, drv->reg_base + QDSP6SS_RESET);
+
+	return 0;
+}
+EXPORT_SYMBOL(pil_q6v5_reset);
+
+struct pil_desc __devinit *pil_q6v5_init(struct platform_device *pdev)
+{
+	struct q6v5_data *drv;
+	struct resource *res;
+	struct pil_desc *desc;
+	int ret;
+
+	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+	if (!drv)
+		return ERR_PTR(-ENOMEM);
+	platform_set_drvdata(pdev, drv);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return ERR_PTR(-EINVAL);
+	drv->reg_base = devm_ioremap(&pdev->dev, res->start,
+				     resource_size(res));
+	if (!drv->reg_base)
+		return ERR_PTR(-ENOMEM);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	drv->axi_halt_base = devm_ioremap(&pdev->dev, res->start,
+					  resource_size(res));
+	if (!drv->axi_halt_base)
+		return ERR_PTR(-ENOMEM);
+
+	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return ERR_PTR(-ENOMEM);
+
+	ret = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name",
+				      &desc->name);
+	if (ret)
+		return ERR_PTR(ret);
+
+	drv->xo = devm_clk_get(&pdev->dev, "xo");
+	if (IS_ERR(drv->xo))
+		return ERR_CAST(drv->xo);
+
+	drv->bus_clk = devm_clk_get(&pdev->dev, "bus_clk");
+	if (IS_ERR(drv->bus_clk))
+		return ERR_CAST(drv->bus_clk);
+
+	drv->core_clk = devm_clk_get(&pdev->dev, "core_clk");
+	if (IS_ERR(drv->core_clk))
+		return ERR_CAST(drv->core_clk);
+
+	desc->dev = &pdev->dev;
+
+	return desc;
+}
+EXPORT_SYMBOL(pil_q6v5_init);
diff --git a/arch/arm/mach-msm/pil-q6v5.h b/arch/arm/mach-msm/pil-q6v5.h
new file mode 100644
index 0000000..a9a8d07
--- /dev/null
+++ b/arch/arm/mach-msm/pil-q6v5.h
@@ -0,0 +1,47 @@
+/*
+ * 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 __MSM_PIL_Q6V5_H
+#define __MSM_PIL_Q6V5_H
+
+struct regulator;
+struct clk;
+struct pil_device;
+struct pil_desc;
+struct platform_device;
+
+struct q6v5_data {
+	void __iomem *reg_base;
+	struct clk *xo;
+	struct clk *bus_clk;
+	struct clk *core_clk;
+	void __iomem *axi_halt_base;
+	void __iomem *rmb_base;
+	unsigned long start_addr;
+	struct regulator *vreg;
+	bool is_booted;
+	int self_auth;
+	struct pil_device *pil;
+};
+
+int pil_q6v5_make_proxy_votes(struct pil_desc *pil);
+void pil_q6v5_remove_proxy_votes(struct pil_desc *pil);
+void pil_q6v5_halt_axi_port(struct pil_desc *pil, void __iomem *halt_base);
+int pil_q6v5_init_image(struct pil_desc *pil, const u8 *metadata,
+			size_t size);
+void pil_q6v5_shutdown(struct pil_desc *pil);
+int pil_q6v5_reset(struct pil_desc *pil);
+int pil_q6v5_enable_clks(struct pil_desc *pil);
+void pil_q6v5_disable_clks(struct pil_desc *pil);
+struct pil_desc *pil_q6v5_init(struct platform_device *pdev);
+
+#endif
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
new file mode 100644
index 0000000..8a16b43
--- /dev/null
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -0,0 +1,384 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/elf.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/clk.h>
+
+#include <mach/msm_iomap.h>
+
+#include "peripheral-loader.h"
+#include "scm-pas.h"
+
+#define RIVA_PMU_A2XB_CFG		0xB8
+#define RIVA_PMU_A2XB_CFG_EN		BIT(0)
+
+#define RIVA_PMU_CFG			0x28
+#define RIVA_PMU_CFG_WARM_BOOT		BIT(0)
+#define RIVA_PMU_CFG_IRIS_XO_MODE	0x6
+#define RIVA_PMU_CFG_IRIS_XO_MODE_48	(3 << 1)
+
+#define RIVA_PMU_OVRD_EN		0x2C
+#define RIVA_PMU_OVRD_EN_CCPU_RESET	BIT(0)
+#define RIVA_PMU_OVRD_EN_CCPU_CLK	BIT(1)
+
+#define RIVA_PMU_OVRD_VAL		0x30
+#define RIVA_PMU_OVRD_VAL_CCPU_RESET	BIT(0)
+#define RIVA_PMU_OVRD_VAL_CCPU_CLK	BIT(1)
+
+#define RIVA_PMU_CCPU_CTL		0x9C
+#define RIVA_PMU_CCPU_CTL_HIGH_IVT	BIT(0)
+#define RIVA_PMU_CCPU_CTL_REMAP_EN	BIT(2)
+
+#define RIVA_PMU_CCPU_BOOT_REMAP_ADDR	0xA0
+
+#define RIVA_PLL_MODE			(MSM_CLK_CTL_BASE + 0x31A0)
+#define PLL_MODE_OUTCTRL		BIT(0)
+#define PLL_MODE_BYPASSNL		BIT(1)
+#define PLL_MODE_RESET_N		BIT(2)
+#define PLL_MODE_REF_XO_SEL		0x30
+#define PLL_MODE_REF_XO_SEL_CXO		(2 << 4)
+#define PLL_MODE_REF_XO_SEL_RF		(3 << 4)
+#define RIVA_PLL_L_VAL			(MSM_CLK_CTL_BASE + 0x31A4)
+#define RIVA_PLL_M_VAL			(MSM_CLK_CTL_BASE + 0x31A8)
+#define RIVA_PLL_N_VAL			(MSM_CLK_CTL_BASE + 0x31Ac)
+#define RIVA_PLL_CONFIG			(MSM_CLK_CTL_BASE + 0x31B4)
+#define RIVA_PLL_STATUS			(MSM_CLK_CTL_BASE + 0x31B8)
+#define RIVA_RESET			(MSM_CLK_CTL_BASE + 0x35E0)
+
+#define RIVA_PMU_ROOT_CLK_SEL		0xC8
+#define RIVA_PMU_ROOT_CLK_SEL_3		BIT(2)
+
+#define RIVA_PMU_CLK_ROOT3			0x78
+#define RIVA_PMU_CLK_ROOT3_ENA			BIT(0)
+#define RIVA_PMU_CLK_ROOT3_SRC0_DIV		0x3C
+#define RIVA_PMU_CLK_ROOT3_SRC0_DIV_2		(1 << 2)
+#define RIVA_PMU_CLK_ROOT3_SRC0_SEL		0x1C0
+#define RIVA_PMU_CLK_ROOT3_SRC0_SEL_RIVA	(1 << 6)
+#define RIVA_PMU_CLK_ROOT3_SRC1_DIV		0x1E00
+#define RIVA_PMU_CLK_ROOT3_SRC1_DIV_2		(1 << 9)
+#define RIVA_PMU_CLK_ROOT3_SRC1_SEL		0xE000
+#define RIVA_PMU_CLK_ROOT3_SRC1_SEL_RIVA	(1 << 13)
+
+struct riva_data {
+	void __iomem *base;
+	unsigned long start_addr;
+	struct clk *xo;
+	struct regulator *pll_supply;
+	struct pil_device *pil;
+};
+
+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_make_proxy_vote(struct pil_desc *pil)
+{
+	struct riva_data *drv = dev_get_drvdata(pil->dev);
+	int ret;
+
+	ret = regulator_enable(drv->pll_supply);
+	if (ret) {
+		dev_err(pil->dev, "failed to enable pll supply\n");
+		goto err;
+	}
+	ret = clk_prepare_enable(drv->xo);
+	if (ret) {
+		dev_err(pil->dev, "failed to enable xo\n");
+		goto err_clk;
+	}
+	return 0;
+err_clk:
+	regulator_disable(drv->pll_supply);
+err:
+	return ret;
+}
+
+static void pil_riva_remove_proxy_vote(struct pil_desc *pil)
+{
+	struct riva_data *drv = dev_get_drvdata(pil->dev);
+	regulator_disable(drv->pll_supply);
+	clk_disable_unprepare(drv->xo);
+}
+
+static int pil_riva_init_image(struct pil_desc *pil, const u8 *metadata,
+		size_t size)
+{
+	const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
+	struct riva_data *drv = dev_get_drvdata(pil->dev);
+	drv->start_addr = ehdr->e_entry;
+	return 0;
+}
+
+static int pil_riva_reset(struct pil_desc *pil)
+{
+	u32 reg, sel;
+	struct riva_data *drv = dev_get_drvdata(pil->dev);
+	void __iomem *base = drv->base;
+	unsigned long start_addr = drv->start_addr;
+	bool use_cxo = cxo_is_needed(drv);
+
+	/* 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);
+
+	/* 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)
+		writel_relaxed(0x40000C00 | 50, RIVA_PLL_L_VAL);
+	else
+		writel_relaxed(0x40000C00 | 40, RIVA_PLL_L_VAL);
+	writel_relaxed(0, RIVA_PLL_M_VAL);
+	writel_relaxed(1, RIVA_PLL_N_VAL);
+	writel_relaxed(0x01495227, RIVA_PLL_CONFIG);
+
+	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;
+	writel_relaxed(reg, RIVA_PLL_MODE);
+
+	/* Enable PLL 13 */
+	reg |= PLL_MODE_BYPASSNL;
+	writel_relaxed(reg, RIVA_PLL_MODE);
+
+	/*
+	 * H/W requires a 5us delay between disabling the bypass and
+	 * de-asserting the reset. Delay 10us just to be safe.
+	 */
+	mb();
+	usleep_range(10, 20);
+
+	reg |= PLL_MODE_RESET_N;
+	writel_relaxed(reg, RIVA_PLL_MODE);
+	reg |= PLL_MODE_OUTCTRL;
+	writel_relaxed(reg, RIVA_PLL_MODE);
+
+	/* Wait for PLL to settle */
+	mb();
+	usleep_range(50, 100);
+
+	/* Configure cCPU for 240 MHz */
+	sel = readl_relaxed(base + RIVA_PMU_ROOT_CLK_SEL);
+	reg = readl_relaxed(base + RIVA_PMU_CLK_ROOT3);
+	if (sel & RIVA_PMU_ROOT_CLK_SEL_3) {
+		reg &= ~(RIVA_PMU_CLK_ROOT3_SRC0_SEL |
+			 RIVA_PMU_CLK_ROOT3_SRC0_DIV);
+		reg |= RIVA_PMU_CLK_ROOT3_SRC0_SEL_RIVA |
+		       RIVA_PMU_CLK_ROOT3_SRC0_DIV_2;
+	} else {
+		reg &= ~(RIVA_PMU_CLK_ROOT3_SRC1_SEL |
+			 RIVA_PMU_CLK_ROOT3_SRC1_DIV);
+		reg |= RIVA_PMU_CLK_ROOT3_SRC1_SEL_RIVA |
+		       RIVA_PMU_CLK_ROOT3_SRC1_DIV_2;
+	}
+	writel_relaxed(reg, base + RIVA_PMU_CLK_ROOT3);
+	reg |= RIVA_PMU_CLK_ROOT3_ENA;
+	writel_relaxed(reg, base + RIVA_PMU_CLK_ROOT3);
+	reg = readl_relaxed(base + RIVA_PMU_ROOT_CLK_SEL);
+	reg ^= RIVA_PMU_ROOT_CLK_SEL_3;
+	writel_relaxed(reg, base + RIVA_PMU_ROOT_CLK_SEL);
+
+	/* Use the high vector table */
+	reg = readl_relaxed(base + RIVA_PMU_CCPU_CTL);
+	reg |= RIVA_PMU_CCPU_CTL_HIGH_IVT | RIVA_PMU_CCPU_CTL_REMAP_EN;
+	writel_relaxed(reg, base + RIVA_PMU_CCPU_CTL);
+
+	/* Set base memory address */
+	writel_relaxed(start_addr >> 16, base + RIVA_PMU_CCPU_BOOT_REMAP_ADDR);
+
+	/* Clear warmboot bit indicating this is a cold boot */
+	reg = readl_relaxed(base + RIVA_PMU_CFG);
+	reg &= ~(RIVA_PMU_CFG_WARM_BOOT);
+	writel_relaxed(reg, base + RIVA_PMU_CFG);
+
+	/* Enable the cCPU clock */
+	reg = readl_relaxed(base + RIVA_PMU_OVRD_VAL);
+	reg |= RIVA_PMU_OVRD_VAL_CCPU_CLK;
+	writel_relaxed(reg, base + RIVA_PMU_OVRD_VAL);
+
+	/* Take cCPU out of reset */
+	reg |= RIVA_PMU_OVRD_VAL_CCPU_RESET;
+	writel_relaxed(reg, base + RIVA_PMU_OVRD_VAL);
+
+	return 0;
+}
+
+static int pil_riva_shutdown(struct pil_desc *pil)
+{
+	struct riva_data *drv = dev_get_drvdata(pil->dev);
+	u32 reg;
+
+	/* 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);
+	writel_relaxed(reg, drv->base + RIVA_PMU_OVRD_VAL);
+	reg = readl_relaxed(drv->base + RIVA_PMU_OVRD_EN);
+	reg |= RIVA_PMU_OVRD_EN_CCPU_RESET | RIVA_PMU_OVRD_EN_CCPU_CLK;
+	writel_relaxed(reg, drv->base + RIVA_PMU_OVRD_EN);
+	mb();
+
+	/* Assert reset to Riva */
+	writel_relaxed(1, RIVA_RESET);
+	mb();
+	usleep_range(1000, 2000);
+
+	/* Deassert reset to Riva */
+	writel_relaxed(0, RIVA_RESET);
+	mb();
+
+	return 0;
+}
+
+static struct pil_reset_ops pil_riva_ops = {
+	.init_image = pil_riva_init_image,
+	.auth_and_reset = pil_riva_reset,
+	.shutdown = pil_riva_shutdown,
+	.proxy_vote = pil_riva_make_proxy_vote,
+	.proxy_unvote = pil_riva_remove_proxy_vote,
+};
+
+static int pil_riva_init_image_trusted(struct pil_desc *pil,
+		const u8 *metadata, size_t size)
+{
+	return pas_init_image(PAS_RIVA, metadata, size);
+}
+
+static int pil_riva_reset_trusted(struct pil_desc *pil)
+{
+	return pas_auth_and_reset(PAS_RIVA);
+}
+
+static int pil_riva_shutdown_trusted(struct pil_desc *pil)
+{
+	return pas_shutdown(PAS_RIVA);
+}
+
+static struct pil_reset_ops pil_riva_ops_trusted = {
+	.init_image = pil_riva_init_image_trusted,
+	.auth_and_reset = pil_riva_reset_trusted,
+	.shutdown = pil_riva_shutdown_trusted,
+	.proxy_vote = pil_riva_make_proxy_vote,
+	.proxy_unvote = pil_riva_remove_proxy_vote,
+};
+
+static int __devinit pil_riva_probe(struct platform_device *pdev)
+{
+	struct riva_data *drv;
+	struct resource *res;
+	struct pil_desc *desc;
+	int ret;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -EINVAL;
+
+	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+	if (!drv)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, drv);
+
+	drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!drv->base)
+		return -ENOMEM;
+
+	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+
+	drv->pll_supply = devm_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);
+	}
+	if (regulator_count_voltages(drv->pll_supply) > 0) {
+		ret = regulator_set_voltage(drv->pll_supply, 1800000, 1800000);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"failed to set pll supply voltage\n");
+			return ret;
+		}
+
+		ret = regulator_set_optimum_mode(drv->pll_supply, 100000);
+		if (ret < 0) {
+			dev_err(&pdev->dev,
+				"failed to set pll supply optimum mode\n");
+			return ret;
+		}
+	}
+
+	desc->name = "wcnss";
+	desc->dev = &pdev->dev;
+	desc->owner = THIS_MODULE;
+	desc->proxy_timeout = 10000;
+
+	if (pas_supported(PAS_RIVA) > 0) {
+		desc->ops = &pil_riva_ops_trusted;
+		dev_info(&pdev->dev, "using secure boot\n");
+	} else {
+		desc->ops = &pil_riva_ops;
+		dev_info(&pdev->dev, "using non-secure boot\n");
+	}
+
+	drv->xo = devm_clk_get(&pdev->dev, "cxo");
+	if (IS_ERR(drv->xo))
+		return PTR_ERR(drv->xo);
+
+	drv->pil = msm_pil_register(desc);
+	if (IS_ERR(drv->pil))
+		return PTR_ERR(drv->pil);
+	return 0;
+}
+
+static int __devexit pil_riva_remove(struct platform_device *pdev)
+{
+	struct riva_data *drv = platform_get_drvdata(pdev);
+	msm_pil_unregister(drv->pil);
+	return 0;
+}
+
+static struct platform_driver pil_riva_driver = {
+	.probe = pil_riva_probe,
+	.remove = __devexit_p(pil_riva_remove),
+	.driver = {
+		.name = "pil_riva",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init pil_riva_init(void)
+{
+	return platform_driver_register(&pil_riva_driver);
+}
+module_init(pil_riva_init);
+
+static void __exit pil_riva_exit(void)
+{
+	platform_driver_unregister(&pil_riva_driver);
+}
+module_exit(pil_riva_exit);
+
+MODULE_DESCRIPTION("Support for booting RIVA (WCNSS) processors");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-tzapps.c b/arch/arm/mach-msm/pil-tzapps.c
new file mode 100644
index 0000000..2345453
--- /dev/null
+++ b/arch/arm/mach-msm/pil-tzapps.c
@@ -0,0 +1,96 @@
+/* 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
+ * 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/elf.h>
+#include <linux/err.h>
+
+#include "peripheral-loader.h"
+#include "scm-pas.h"
+
+static int pil_tzapps_init_image(struct pil_desc *pil, const u8 *metadata,
+		size_t size)
+{
+	return pas_init_image(PAS_TZAPPS, metadata, size);
+}
+
+static int pil_tzapps_reset(struct pil_desc *pil)
+{
+	return pas_auth_and_reset(PAS_TZAPPS);
+}
+
+static int pil_tzapps_shutdown(struct pil_desc *pil)
+{
+	return pas_shutdown(PAS_TZAPPS);
+}
+
+static struct pil_reset_ops pil_tzapps_ops = {
+	.init_image = pil_tzapps_init_image,
+	.auth_and_reset = pil_tzapps_reset,
+	.shutdown = pil_tzapps_shutdown,
+};
+
+static int __devinit pil_tzapps_driver_probe(struct platform_device *pdev)
+{
+	struct pil_desc *desc;
+	struct pil_device *pil;
+
+	if (pas_supported(PAS_TZAPPS) < 0)
+		return -ENOSYS;
+
+	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+
+	desc->name = "tzapps";
+	desc->dev = &pdev->dev;
+	desc->ops = &pil_tzapps_ops;
+	desc->owner = THIS_MODULE;
+	pil = msm_pil_register(desc);
+	if (IS_ERR(pil))
+		return PTR_ERR(pil);
+	platform_set_drvdata(pdev, pil);
+	return 0;
+}
+
+static int __devexit pil_tzapps_driver_exit(struct platform_device *pdev)
+{
+	struct pil_device *pil = platform_get_drvdata(pdev);
+	msm_pil_unregister(pil);
+	return 0;
+}
+
+static struct platform_driver pil_tzapps_driver = {
+	.probe = pil_tzapps_driver_probe,
+	.remove = __devexit_p(pil_tzapps_driver_exit),
+	.driver = {
+		.name = "pil_tzapps",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init pil_tzapps_init(void)
+{
+	return platform_driver_register(&pil_tzapps_driver);
+}
+module_init(pil_tzapps_init);
+
+static void __exit pil_tzapps_exit(void)
+{
+	platform_driver_unregister(&pil_tzapps_driver);
+}
+module_exit(pil_tzapps_exit);
+
+MODULE_DESCRIPTION("Support for booting TZApps images");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-vidc.c b/arch/arm/mach-msm/pil-vidc.c
new file mode 100644
index 0000000..ceb9bcd
--- /dev/null
+++ b/arch/arm/mach-msm/pil-vidc.c
@@ -0,0 +1,146 @@
+/* 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/elf.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include "peripheral-loader.h"
+#include "scm-pas.h"
+
+struct vidc_data {
+	struct clk *smmu_iface;
+	struct clk *core;
+	struct pil_device *pil;
+};
+
+static int pil_vidc_init_image(struct pil_desc *pil, const u8 *metadata,
+		size_t size)
+{
+	return pas_init_image(PAS_VIDC, metadata, size);
+}
+
+static int pil_vidc_reset(struct pil_desc *pil)
+{
+	int ret;
+	struct vidc_data *drv = dev_get_drvdata(pil->dev);
+
+	ret = clk_prepare_enable(drv->smmu_iface);
+	if (ret)
+		goto err_smmu;
+	ret = clk_prepare_enable(drv->core);
+	if (ret)
+		goto err_core;
+	ret = pas_auth_and_reset(PAS_VIDC);
+
+	clk_disable_unprepare(drv->core);
+err_core:
+	clk_disable_unprepare(drv->smmu_iface);
+err_smmu:
+	return ret;
+}
+
+static int pil_vidc_shutdown(struct pil_desc *pil)
+{
+	return pas_shutdown(PAS_VIDC);
+}
+
+static struct pil_reset_ops pil_vidc_ops = {
+	.init_image = pil_vidc_init_image,
+	.auth_and_reset = pil_vidc_reset,
+	.shutdown = pil_vidc_shutdown,
+};
+
+static int __devinit pil_vidc_driver_probe(struct platform_device *pdev)
+{
+	struct pil_desc *desc;
+	struct vidc_data *drv;
+	int ret;
+
+	if (pas_supported(PAS_VIDC) < 0)
+		return -ENOSYS;
+
+	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+
+	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+	if (!drv)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, drv);
+	drv->smmu_iface = clk_get(&pdev->dev, "smmu_iface_clk");
+	if (IS_ERR(drv->smmu_iface)) {
+		dev_err(&pdev->dev, "failed to get smmu interface clock\n");
+		ret = PTR_ERR(drv->smmu_iface);
+		goto err_smmu;
+	}
+	drv->core = clk_get(&pdev->dev, "core_clk");
+	if (IS_ERR(drv->core)) {
+		dev_err(&pdev->dev, "failed to get core clock\n");
+		ret = PTR_ERR(drv->core);
+		goto err_core;
+	}
+
+	desc->name = "vidc";
+	desc->dev = &pdev->dev;
+	desc->ops = &pil_vidc_ops;
+	desc->owner = THIS_MODULE;
+	drv->pil = msm_pil_register(desc);
+	if (IS_ERR(drv->pil)) {
+		ret = PTR_ERR(drv->pil);
+		goto err_register;
+	}
+	return 0;
+
+err_register:
+	clk_put(drv->core);
+err_core:
+	clk_put(drv->smmu_iface);
+err_smmu:
+	return ret;
+}
+
+static int __devexit pil_vidc_driver_exit(struct platform_device *pdev)
+{
+	struct vidc_data *drv = platform_get_drvdata(pdev);
+	msm_pil_unregister(drv->pil);
+	clk_put(drv->smmu_iface);
+	clk_put(drv->core);
+	return 0;
+}
+
+static struct platform_driver pil_vidc_driver = {
+	.probe = pil_vidc_driver_probe,
+	.remove = __devexit_p(pil_vidc_driver_exit),
+	.driver = {
+		.name = "pil_vidc",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init pil_vidc_init(void)
+{
+	return platform_driver_register(&pil_vidc_driver);
+}
+module_init(pil_vidc_init);
+
+static void __exit pil_vidc_exit(void)
+{
+	platform_driver_unregister(&pil_vidc_driver);
+}
+module_exit(pil_vidc_exit);
+
+MODULE_DESCRIPTION("Support for secure booting vidc images");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/ping_apps_server.c b/arch/arm/mach-msm/ping_apps_server.c
new file mode 100644
index 0000000..0a85600
--- /dev/null
+++ b/arch/arm/mach-msm/ping_apps_server.c
@@ -0,0 +1,605 @@
+/* Copyright (c) 2010, 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.
+ *
+ */
+
+/*
+ * PING APPS SERVER Driver
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/kthread.h>
+#include <linux/workqueue.h>
+#include <mach/msm_rpcrouter.h>
+
+/* ping server definitions */
+
+#define PING_APPS_PROG 0x30000082
+#define PING_APPS_VERS 0x00010001
+
+#define PING_APPS_NULL  0
+#define PING_APPS_DATA  4
+#define PING_APPS_REG   2
+#define PING_APPS_UNREG 3
+#define PING_APPS_DATA_CB_REG    6
+#define PING_APPS_DATA_CB_UNREG  5
+
+#define PING_APPS_REG_CB  2
+#define PING_APPS_DATA_CB 1
+
+static LIST_HEAD(cb_entry_list);
+static DEFINE_MUTEX(cb_entry_list_lock);
+
+static struct task_struct *server_thread;
+
+struct ping_apps_register_arg {
+	uint32_t cb_id;
+	int32_t num;
+};
+
+struct ping_apps_unregister_arg {
+	uint32_t cb_id;
+};
+
+struct ping_apps_register_cb_arg {
+	uint32_t cb_id;
+	int32_t num;
+};
+
+struct ping_apps_register_ret {
+	uint32_t result;
+};
+
+struct ping_apps_unregister_ret {
+	uint32_t result;
+};
+
+struct ping_apps_data_cb_reg_arg {
+	uint32_t cb_id;
+	uint32_t num;
+	uint32_t size;
+	uint32_t interval_ms;
+	uint32_t num_tasks;
+};
+
+struct ping_apps_data_cb_unreg_arg {
+	uint32_t cb_id;
+};
+
+struct ping_apps_data_cb_arg {
+	uint32_t cb_id;
+	uint32_t *data;
+	uint32_t size;
+	uint32_t sum;
+};
+
+struct ping_apps_data_cb_reg_ret {
+	uint32_t result;
+};
+
+struct ping_apps_data_cb_unreg_ret {
+	uint32_t result;
+};
+
+struct ping_apps_data_cb_ret {
+	uint32_t result;
+};
+
+struct ping_apps_data_arg {
+	uint32_t *data;
+	uint32_t size;
+};
+
+struct ping_apps_data_ret {
+	uint32_t result;
+};
+
+struct ping_apps_data_cb_info {
+	void *cb_func;
+	uint32_t size;
+	uint32_t num_tasks;
+};
+
+struct ping_apps_cb_entry {
+	struct list_head list;
+
+	struct msm_rpc_client_info clnt_info;
+	void *cb_info;
+	uint32_t cb_id;
+	int32_t num;
+	uint32_t interval_ms;
+	uint32_t time_to_next_cb;
+	void (*cb_func)(struct ping_apps_cb_entry *);
+};
+
+static int handle_rpc_call(struct msm_rpc_server *server,
+			   struct rpc_request_hdr *req,
+			   struct msm_rpc_xdr *xdr);
+
+static int ping_apps_data_cb(struct msm_rpc_server *server,
+			     struct msm_rpc_client_info *clnt_info,
+			     struct ping_apps_data_cb_arg *arg,
+			     struct ping_apps_data_cb_ret *ret);
+
+static int ping_apps_register_cb(struct msm_rpc_server *server,
+				 struct msm_rpc_client_info *clnt_info,
+				 struct ping_apps_register_cb_arg *arg,
+				 void *ret);
+
+static struct msm_rpc_server rpc_server = {
+	.prog = PING_APPS_PROG,
+	.vers = PING_APPS_VERS,
+	.rpc_call2 = handle_rpc_call,
+};
+
+static void handle_ping_apps_data_cb(struct ping_apps_cb_entry *cb_entry)
+{
+	struct ping_apps_data_cb_arg arg;
+	struct ping_apps_data_cb_ret ret;
+	uint32_t my_sum = 0;
+	uint32_t *my_data;
+	int i;
+
+	if (cb_entry->num > 0) {
+		cb_entry->num--;
+		arg.cb_id = cb_entry->cb_id;
+		arg.size = ((struct ping_apps_data_cb_info *)
+			    (cb_entry->cb_info))->size;
+
+		my_data = kmalloc((arg.size * sizeof(uint32_t)), GFP_KERNEL);
+		if (!my_data)
+			return;
+
+		for (i = 0; i < arg.size; i++) {
+			my_data[i] = (42 + i);
+			my_sum ^= (42 + i);
+		}
+		arg.data = my_data;
+		arg.sum = my_sum;
+
+		((int (*)(struct msm_rpc_server *,
+			  struct msm_rpc_client_info *,
+			  struct ping_apps_data_cb_arg *,
+			  struct ping_apps_data_cb_ret *))
+		 ((struct ping_apps_data_cb_info *)
+		  (cb_entry->cb_info))->cb_func)(&rpc_server,
+					     &cb_entry->clnt_info,
+					     &arg, &ret);
+		pr_info("%s: cb_id = %d, ret = %d\n",
+			__func__, arg.cb_id, ret.result);
+		kfree(my_data);
+	}
+}
+
+static void handle_ping_apps_register_cb(struct ping_apps_cb_entry *cb_entry)
+{
+	struct ping_apps_register_cb_arg arg;
+
+	if (cb_entry->num > 0) {
+		cb_entry->num--;
+		arg.cb_id = cb_entry->cb_id;
+		arg.num = cb_entry->num;
+
+		pr_info("%s: cb_id = %d, num = %d\n",
+			__func__, arg.cb_id, arg.num);
+		((int (*)(struct msm_rpc_server *,
+			  struct msm_rpc_client_info *,
+			  struct ping_apps_register_cb_arg *,
+			  void *))cb_entry->cb_info)(&rpc_server,
+						     &cb_entry->clnt_info,
+						     &arg, NULL);
+	}
+
+}
+
+static int ping_apps_cb_process_thread(void *data)
+{
+	struct ping_apps_cb_entry *cb_entry;
+	uint32_t sleep_time;
+	uint32_t time_slept = 0;
+
+	pr_info("%s: thread started\n", __func__);
+	for (;;) {
+		sleep_time = 1000;
+		mutex_lock(&cb_entry_list_lock);
+		list_for_each_entry(cb_entry, &cb_entry_list, list) {
+			if (cb_entry->time_to_next_cb <= time_slept) {
+				cb_entry->cb_func(cb_entry);
+				cb_entry->time_to_next_cb =
+					cb_entry->interval_ms;
+			} else
+				cb_entry->time_to_next_cb -= time_slept;
+
+			if (cb_entry->time_to_next_cb < sleep_time)
+				sleep_time = cb_entry->time_to_next_cb;
+		}
+		mutex_unlock(&cb_entry_list_lock);
+
+		msleep(sleep_time);
+		time_slept = sleep_time;
+	}
+
+	do_exit(0);
+}
+
+static int ping_apps_data_register(struct ping_apps_data_arg *arg,
+				   struct ping_apps_data_ret *ret)
+{
+	int i;
+
+	ret->result = 0;
+	for (i = 0; i < arg->size; i++)
+		ret->result ^= arg->data[i];
+
+	return 0;
+}
+
+static int ping_apps_data_cb_reg(struct ping_apps_data_cb_reg_arg *arg,
+				 struct ping_apps_data_cb_reg_ret *ret)
+{
+	struct ping_apps_cb_entry *cb_entry;
+	struct ping_apps_data_cb_info *cb_info;
+
+	cb_entry = kmalloc(sizeof(*cb_entry), GFP_KERNEL);
+	if (!cb_entry)
+		return -ENOMEM;
+
+	cb_entry->cb_info = kmalloc(sizeof(struct ping_apps_data_cb_info),
+				    GFP_KERNEL);
+	if (!cb_entry->cb_info) {
+		kfree(cb_entry);
+		return -ENOMEM;
+	}
+	cb_info = (struct ping_apps_data_cb_info *)cb_entry->cb_info;
+
+	INIT_LIST_HEAD(&cb_entry->list);
+	cb_entry->cb_func = handle_ping_apps_data_cb;
+	cb_entry->cb_id = arg->cb_id;
+	cb_entry->num = arg->num;
+	cb_entry->interval_ms = arg->interval_ms;
+	cb_entry->time_to_next_cb = arg->interval_ms;
+	cb_info->cb_func = ping_apps_data_cb;
+	cb_info->size = arg->size;
+	cb_info->num_tasks = arg->num_tasks;
+
+	mutex_lock(&cb_entry_list_lock);
+	list_add_tail(&cb_entry->list, &cb_entry_list);
+	mutex_unlock(&cb_entry_list_lock);
+
+	msm_rpc_server_get_requesting_client(&cb_entry->clnt_info);
+
+	if (IS_ERR(server_thread))
+		server_thread = kthread_run(ping_apps_cb_process_thread,
+					    NULL, "kpingrpccbprocessd");
+	if (IS_ERR(server_thread)) {
+		kfree(cb_entry);
+		return PTR_ERR(server_thread);
+	}
+
+	ret->result = 1;
+	return 0;
+}
+
+static int ping_apps_data_cb_unreg(struct ping_apps_data_cb_unreg_arg *arg,
+				   struct ping_apps_data_cb_unreg_ret *ret)
+{
+	struct ping_apps_cb_entry *cb_entry, *tmp_cb_entry;
+
+	mutex_lock(&cb_entry_list_lock);
+	list_for_each_entry_safe(cb_entry, tmp_cb_entry,
+				 &cb_entry_list, list) {
+		if (cb_entry->cb_id == arg->cb_id) {
+			list_del(&cb_entry->list);
+			kfree(cb_entry->cb_info);
+			kfree(cb_entry);
+			break;
+		}
+	}
+	mutex_unlock(&cb_entry_list_lock);
+
+	ret->result = 1;
+	return 0;
+}
+
+static int ping_apps_register(struct ping_apps_register_arg *arg,
+			      struct ping_apps_register_ret *ret)
+{
+	struct ping_apps_cb_entry *cb_entry;
+
+	cb_entry = kmalloc(sizeof(*cb_entry), GFP_KERNEL);
+	if (!cb_entry)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&cb_entry->list);
+	cb_entry->cb_func = handle_ping_apps_register_cb;
+	cb_entry->cb_info = ping_apps_register_cb;
+	cb_entry->cb_id = arg->cb_id;
+	cb_entry->num = arg->num;
+	cb_entry->interval_ms = 100;
+	cb_entry->time_to_next_cb = 100;
+
+	mutex_lock(&cb_entry_list_lock);
+	list_add_tail(&cb_entry->list, &cb_entry_list);
+	mutex_unlock(&cb_entry_list_lock);
+
+	msm_rpc_server_get_requesting_client(&cb_entry->clnt_info);
+
+	if (IS_ERR(server_thread))
+		server_thread = kthread_run(ping_apps_cb_process_thread,
+					    NULL, "kpingrpccbprocessd");
+	if (IS_ERR(server_thread)) {
+		kfree(cb_entry);
+		return PTR_ERR(server_thread);
+	}
+
+	ret->result = 1;
+	return 0;
+}
+
+static int ping_apps_unregister(struct ping_apps_unregister_arg *arg,
+				struct ping_apps_unregister_ret *ret)
+{
+	struct ping_apps_cb_entry *cb_entry, *tmp_cb_entry;
+
+	mutex_lock(&cb_entry_list_lock);
+	list_for_each_entry_safe(cb_entry, tmp_cb_entry,
+				 &cb_entry_list, list) {
+		if (cb_entry->cb_id == arg->cb_id) {
+			list_del(&cb_entry->list);
+			kfree(cb_entry);
+			break;
+		}
+	}
+	mutex_unlock(&cb_entry_list_lock);
+
+	ret->result = 1;
+	return 0;
+}
+
+static int ping_apps_data_cb_arg_func(struct msm_rpc_server *server,
+				      struct msm_rpc_xdr *xdr, void *data)
+{
+	struct ping_apps_data_cb_arg *arg = data;
+
+	xdr_send_uint32(xdr, &arg->cb_id);
+	xdr_send_array(xdr, (void **)&arg->data, &arg->size, 64,
+		       sizeof(uint32_t), (void *)xdr_send_uint32);
+	xdr_send_uint32(xdr, &arg->size);
+	xdr_send_uint32(xdr, &arg->sum);
+
+	return 0;
+}
+
+static int ping_apps_data_cb_ret_func(struct msm_rpc_server *server,
+				      struct msm_rpc_xdr *xdr, void *data)
+{
+	struct ping_apps_data_cb_ret *ret = data;
+
+	xdr_recv_uint32(xdr, &ret->result);
+
+	return 0;
+}
+
+static int ping_apps_data_cb(struct msm_rpc_server *server,
+			     struct msm_rpc_client_info *clnt_info,
+			     struct ping_apps_data_cb_arg *arg,
+			     struct ping_apps_data_cb_ret *ret)
+{
+	return msm_rpc_server_cb_req2(server, clnt_info,
+				      PING_APPS_DATA_CB,
+				      ping_apps_data_cb_arg_func, arg,
+				      ping_apps_data_cb_ret_func, ret, -1);
+}
+
+static int ping_apps_register_cb_arg(struct msm_rpc_server *server,
+				     struct msm_rpc_xdr *xdr, void *data)
+{
+	struct ping_apps_register_cb_arg *arg = data;
+
+	xdr_send_uint32(xdr, &arg->cb_id);
+	xdr_send_int32(xdr, &arg->num);
+
+	return 0;
+}
+
+static int ping_apps_register_cb(struct msm_rpc_server *server,
+				struct msm_rpc_client_info *clnt_info,
+				struct ping_apps_register_cb_arg *arg,
+				void *ret)
+{
+	return msm_rpc_server_cb_req2(server, clnt_info,
+				      PING_APPS_REG_CB,
+				      ping_apps_register_cb_arg,
+				      arg, NULL, NULL, -1);
+}
+
+static int handle_ping_apps_data_register(struct msm_rpc_server *server,
+					  struct rpc_request_hdr *req,
+					  struct msm_rpc_xdr *xdr)
+{
+	uint32_t rc;
+	struct ping_apps_data_arg arg;
+	struct ping_apps_data_ret ret;
+
+	pr_info("%s: request received\n", __func__);
+
+	xdr_recv_array(xdr, (void **)&arg.data, &arg.size, 64,
+		       sizeof(uint32_t), (void *)xdr_recv_uint32);
+	xdr_recv_uint32(xdr, &arg.size);
+
+	rc = ping_apps_data_register(&arg, &ret);
+	if (rc < 0)
+		goto free_and_return;
+
+	xdr_start_accepted_reply(xdr, RPC_ACCEPTSTAT_SUCCESS);
+	xdr_send_uint32(xdr, &ret.result);
+	rc = xdr_send_msg(xdr);
+	if (rc < 0)
+		pr_info("%s: sending reply failed\n", __func__);
+	else
+		rc = 1;
+
+ free_and_return:
+	kfree(arg.data);
+	return rc;
+}
+
+static int handle_ping_apps_data_cb_reg(struct msm_rpc_server *server,
+					struct rpc_request_hdr *req,
+					struct msm_rpc_xdr *xdr)
+{
+	uint32_t rc;
+	struct ping_apps_data_cb_reg_arg arg;
+	struct ping_apps_data_cb_reg_ret ret;
+
+	pr_info("%s: request received\n", __func__);
+
+	xdr_recv_uint32(xdr, &arg.cb_id);
+	xdr_recv_uint32(xdr, &arg.num);
+	xdr_recv_uint32(xdr, &arg.size);
+	xdr_recv_uint32(xdr, &arg.interval_ms);
+	xdr_recv_uint32(xdr, &arg.num_tasks);
+
+	rc = ping_apps_data_cb_reg(&arg, &ret);
+	if (rc < 0)
+		return rc;
+
+	xdr_start_accepted_reply(xdr, RPC_ACCEPTSTAT_SUCCESS);
+	xdr_send_uint32(xdr, &ret.result);
+	rc = xdr_send_msg(xdr);
+	if (rc < 0)
+		pr_info("%s: sending reply failed\n", __func__);
+	else
+		rc = 1;
+
+	return rc;
+}
+
+static int handle_ping_apps_data_cb_unreg(struct msm_rpc_server *server,
+					  struct rpc_request_hdr *req,
+					  struct msm_rpc_xdr *xdr)
+{
+	uint32_t rc;
+	struct ping_apps_data_cb_unreg_arg arg;
+	struct ping_apps_data_cb_unreg_ret ret;
+
+	pr_info("%s: request received\n", __func__);
+
+	xdr_recv_uint32(xdr, &arg.cb_id);
+
+	rc = ping_apps_data_cb_unreg(&arg, &ret);
+	if (rc < 0)
+		return rc;
+
+	xdr_start_accepted_reply(xdr, RPC_ACCEPTSTAT_SUCCESS);
+	xdr_send_uint32(xdr, &ret.result);
+	rc = xdr_send_msg(xdr);
+	if (rc < 0)
+		pr_info("%s: sending reply failed\n", __func__);
+	else
+		rc = 1;
+
+	return rc;
+}
+
+static int handle_ping_apps_register(struct msm_rpc_server *server,
+				     struct rpc_request_hdr *req,
+				     struct msm_rpc_xdr *xdr)
+{
+	uint32_t rc;
+	struct ping_apps_register_arg arg;
+	struct ping_apps_register_ret ret;
+
+	pr_info("%s: request received\n", __func__);
+
+	xdr_recv_uint32(xdr, &arg.cb_id);
+	xdr_recv_int32(xdr, &arg.num);
+
+	rc = ping_apps_register(&arg, &ret);
+	if (rc < 0)
+		return rc;
+
+	xdr_start_accepted_reply(xdr, RPC_ACCEPTSTAT_SUCCESS);
+	xdr_send_uint32(xdr, &ret.result);
+	rc = xdr_send_msg(xdr);
+	if (rc < 0)
+		pr_info("%s: sending reply failed\n", __func__);
+	else
+		rc = 1;
+
+	return rc;
+}
+
+static int handle_ping_apps_unregister(struct msm_rpc_server *server,
+				       struct rpc_request_hdr *req,
+				       struct msm_rpc_xdr *xdr)
+{
+	uint32_t rc;
+	struct ping_apps_unregister_arg arg;
+	struct ping_apps_unregister_ret ret;
+
+	pr_info("%s: request received\n", __func__);
+
+	xdr_recv_uint32(xdr, &arg.cb_id);
+
+	rc = ping_apps_unregister(&arg, &ret);
+	if (rc < 0)
+		return rc;
+
+	xdr_start_accepted_reply(xdr, RPC_ACCEPTSTAT_SUCCESS);
+	xdr_send_uint32(xdr, &ret.result);
+	rc = xdr_send_msg(xdr);
+	if (rc < 0)
+		pr_info("%s: sending reply failed\n", __func__);
+	else
+		rc = 1;
+
+	return rc;
+}
+
+static int handle_rpc_call(struct msm_rpc_server *server,
+			   struct rpc_request_hdr *req,
+			   struct msm_rpc_xdr *xdr)
+{
+	switch (req->procedure) {
+	case PING_APPS_NULL:
+		pr_info("%s: null procedure request received\n", __func__);
+		return 0;
+	case PING_APPS_DATA:
+		return handle_ping_apps_data_register(server, req, xdr);
+	case PING_APPS_REG:
+		return handle_ping_apps_register(server, req, xdr);
+	case PING_APPS_UNREG:
+		return handle_ping_apps_unregister(server, req, xdr);
+	case PING_APPS_DATA_CB_REG:
+		return handle_ping_apps_data_cb_reg(server, req, xdr);
+	case PING_APPS_DATA_CB_UNREG:
+		return handle_ping_apps_data_cb_unreg(server, req, xdr);
+	default:
+		return -ENODEV;
+	}
+}
+
+static int __init ping_apps_server_init(void)
+{
+	INIT_LIST_HEAD(&cb_entry_list);
+	server_thread = ERR_PTR(-1);
+	return msm_rpc_create_server2(&rpc_server);
+}
+
+module_init(ping_apps_server_init);
+
+MODULE_DESCRIPTION("PING APPS SERVER Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/ping_mdm_rpc_client.c b/arch/arm/mach-msm/ping_mdm_rpc_client.c
new file mode 100644
index 0000000..57ac85d
--- /dev/null
+++ b/arch/arm/mach-msm/ping_mdm_rpc_client.c
@@ -0,0 +1,814 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/*
+ * SMD RPC PING MODEM Driver
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/kfifo.h>
+#include <linux/export.h>
+#include <mach/msm_rpcrouter.h>
+
+#define PING_TEST_BASE 0x31
+
+#define PTIOC_NULL_TEST _IO(PING_TEST_BASE, 1)
+#define PTIOC_REG_TEST _IO(PING_TEST_BASE, 2)
+#define PTIOC_DATA_REG_TEST _IO(PING_TEST_BASE, 3)
+#define PTIOC_DATA_CB_REG_TEST _IO(PING_TEST_BASE, 4)
+
+#define PING_MDM_PROG  0x30000081
+#define PING_MDM_VERS  0x00010001
+#define PING_MDM_CB_PROG  0x31000081
+#define PING_MDM_CB_VERS  0x00010001
+
+#define PING_MDM_NULL_PROC                        0
+#define PING_MDM_RPC_GLUE_CODE_INFO_REMOTE_PROC   1
+#define PING_MDM_REGISTER_PROC                    2
+#define PING_MDM_UNREGISTER_PROC                  3
+#define PING_MDM_REGISTER_DATA_PROC               4
+#define PING_MDM_UNREGISTER_DATA_CB_PROC          5
+#define PING_MDM_REGISTER_DATA_CB_PROC            6
+
+#define PING_MDM_DATA_CB_PROC            1
+#define PING_MDM_CB_PROC                 2
+
+#define PING_MAX_RETRY			5
+
+static struct msm_rpc_client *rpc_client;
+static uint32_t open_count;
+static DEFINE_MUTEX(ping_mdm_lock);
+
+struct ping_mdm_register_cb_arg {
+	uint32_t cb_id;
+	int val;
+};
+
+struct ping_mdm_register_data_cb_cb_arg {
+	uint32_t cb_id;
+	uint32_t *data;
+	uint32_t size;
+	uint32_t sum;
+};
+
+struct ping_mdm_register_data_cb_cb_ret {
+	uint32_t result;
+};
+
+static struct dentry *dent;
+static uint32_t test_res;
+static int reg_cb_num, reg_cb_num_req;
+static int data_cb_num, data_cb_num_req;
+static int reg_done_flag, data_cb_done_flag;
+static DECLARE_WAIT_QUEUE_HEAD(reg_test_wait);
+static DECLARE_WAIT_QUEUE_HEAD(data_cb_test_wait);
+
+enum {
+	PING_MODEM_NOT_IN_RESET = 0,
+	PING_MODEM_IN_RESET,
+	PING_LEAVING_RESET,
+	PING_MODEM_REGISTER_CB
+};
+static int fifo_event;
+static DEFINE_MUTEX(event_fifo_lock);
+static DEFINE_KFIFO(event_fifo, int, sizeof(int)*16);
+
+static int ping_mdm_register_cb(struct msm_rpc_client *client,
+				struct msm_rpc_xdr *xdr)
+{
+	int rc;
+	uint32_t accept_status;
+	struct ping_mdm_register_cb_arg arg;
+	void *cb_func;
+
+	xdr_recv_uint32(xdr, &arg.cb_id);             /* cb_id */
+	xdr_recv_int32(xdr, &arg.val);                /* val */
+
+	cb_func = msm_rpc_get_cb_func(client, arg.cb_id);
+	if (cb_func) {
+		rc = ((int (*)(struct ping_mdm_register_cb_arg *, void *))
+		      cb_func)(&arg, NULL);
+		if (rc)
+			accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
+		else
+			accept_status = RPC_ACCEPTSTAT_SUCCESS;
+	} else
+		accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
+
+	xdr_start_accepted_reply(xdr, accept_status);
+	rc = xdr_send_msg(xdr);
+	if (rc)
+		pr_err("%s: send accepted reply failed: %d\n", __func__, rc);
+
+	return rc;
+}
+
+static int ping_mdm_data_cb(struct msm_rpc_client *client,
+			    struct msm_rpc_xdr *xdr)
+{
+	int rc;
+	void *cb_func;
+	uint32_t size, accept_status;
+	struct ping_mdm_register_data_cb_cb_arg arg;
+	struct ping_mdm_register_data_cb_cb_ret ret;
+
+	xdr_recv_uint32(xdr, &arg.cb_id);           /* cb_id */
+
+	/* data */
+	xdr_recv_array(xdr, (void **)(&(arg.data)), &size, 64,
+		       sizeof(uint32_t), (void *)xdr_recv_uint32);
+
+	xdr_recv_uint32(xdr, &arg.size);           /* size */
+	xdr_recv_uint32(xdr, &arg.sum);            /* sum */
+
+	cb_func = msm_rpc_get_cb_func(client, arg.cb_id);
+	if (cb_func) {
+		rc = ((int (*)
+		       (struct ping_mdm_register_data_cb_cb_arg *,
+			struct ping_mdm_register_data_cb_cb_ret *))
+		      cb_func)(&arg, &ret);
+		if (rc)
+			accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
+		else
+			accept_status = RPC_ACCEPTSTAT_SUCCESS;
+	} else
+		accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
+
+	xdr_start_accepted_reply(xdr, accept_status);
+
+	if (accept_status == RPC_ACCEPTSTAT_SUCCESS)
+		xdr_send_uint32(xdr, &ret.result);         /* result */
+
+	rc = xdr_send_msg(xdr);
+	if (rc)
+		pr_err("%s: send accepted reply failed: %d\n", __func__, rc);
+
+	kfree(arg.data);
+	return rc;
+}
+
+static int ping_mdm_cb_func(struct msm_rpc_client *client,
+			    struct rpc_request_hdr *req,
+			    struct msm_rpc_xdr *xdr)
+{
+	int rc = 0;
+
+	switch (req->procedure) {
+	case PING_MDM_CB_PROC:
+		rc = ping_mdm_register_cb(client, xdr);
+		break;
+	case PING_MDM_DATA_CB_PROC:
+		rc = ping_mdm_data_cb(client, xdr);
+		break;
+	default:
+		pr_err("%s: procedure not supported %d\n",
+		       __func__, req->procedure);
+		xdr_start_accepted_reply(xdr, RPC_ACCEPTSTAT_PROC_UNAVAIL);
+		rc = xdr_send_msg(xdr);
+		if (rc)
+			pr_err("%s: sending reply failed: %d\n", __func__, rc);
+		break;
+	}
+	return rc;
+}
+
+struct ping_mdm_unregister_data_cb_arg {
+	int (*cb_func)(
+		struct ping_mdm_register_data_cb_cb_arg *arg,
+		struct ping_mdm_register_data_cb_cb_ret *ret);
+};
+
+struct ping_mdm_register_data_cb_arg {
+	int (*cb_func)(
+		struct ping_mdm_register_data_cb_cb_arg *arg,
+		struct ping_mdm_register_data_cb_cb_ret *ret);
+	uint32_t num;
+	uint32_t size;
+	uint32_t interval_ms;
+	uint32_t num_tasks;
+};
+
+struct ping_mdm_register_data_cb_ret {
+	uint32_t result;
+};
+
+struct ping_mdm_unregister_data_cb_ret {
+	uint32_t result;
+};
+
+static int ping_mdm_data_cb_register_arg(struct msm_rpc_client *client,
+					 struct msm_rpc_xdr *xdr, void *data)
+{
+	struct ping_mdm_register_data_cb_arg *arg = data;
+	int cb_id;
+
+	cb_id = msm_rpc_add_cb_func(client, (void *)arg->cb_func);
+	if ((cb_id < 0) && (cb_id != MSM_RPC_CLIENT_NULL_CB_ID))
+		return cb_id;
+
+	xdr_send_uint32(xdr, &cb_id);                /* cb_id */
+	xdr_send_uint32(xdr, &arg->num);             /* num */
+	xdr_send_uint32(xdr, &arg->size);            /* size */
+	xdr_send_uint32(xdr, &arg->interval_ms);     /* interval_ms */
+	xdr_send_uint32(xdr, &arg->num_tasks);       /* num_tasks */
+
+	return 0;
+}
+
+static int ping_mdm_data_cb_unregister_arg(struct msm_rpc_client *client,
+					   struct msm_rpc_xdr *xdr, void *data)
+{
+	struct ping_mdm_unregister_data_cb_arg *arg = data;
+	int cb_id;
+
+	cb_id = msm_rpc_add_cb_func(client, (void *)arg->cb_func);
+	if ((cb_id < 0) && (cb_id != MSM_RPC_CLIENT_NULL_CB_ID))
+		return cb_id;
+
+	xdr_send_uint32(xdr, &cb_id);                /* cb_id */
+
+	return 0;
+}
+
+static int ping_mdm_data_cb_register_ret(struct msm_rpc_client *client,
+					 struct msm_rpc_xdr *xdr, void *data)
+{
+	struct ping_mdm_register_data_cb_ret *ret = data;
+
+	xdr_recv_uint32(xdr, &ret->result);      /* result */
+
+	return 0;
+}
+
+static int ping_mdm_register_data_cb(
+	struct msm_rpc_client *client,
+	struct ping_mdm_register_data_cb_arg *arg,
+	struct ping_mdm_register_data_cb_ret *ret)
+{
+	return msm_rpc_client_req2(client,
+				   PING_MDM_REGISTER_DATA_CB_PROC,
+				   ping_mdm_data_cb_register_arg, arg,
+				   ping_mdm_data_cb_register_ret, ret, -1);
+}
+
+static int ping_mdm_unregister_data_cb(
+	struct msm_rpc_client *client,
+	struct ping_mdm_unregister_data_cb_arg *arg,
+	struct ping_mdm_unregister_data_cb_ret *ret)
+{
+	return msm_rpc_client_req2(client,
+				   PING_MDM_UNREGISTER_DATA_CB_PROC,
+				   ping_mdm_data_cb_unregister_arg, arg,
+				   ping_mdm_data_cb_register_ret, ret, -1);
+}
+
+struct ping_mdm_data_arg {
+	uint32_t *data;
+	uint32_t size;
+};
+
+struct ping_mdm_data_ret {
+	uint32_t result;
+};
+
+static int ping_mdm_data_register_arg(struct msm_rpc_client *client,
+				      struct msm_rpc_xdr *xdr, void *data)
+{
+	struct ping_mdm_data_arg *arg = data;
+
+	/* data */
+	xdr_send_array(xdr, (void **)&arg->data, &arg->size, 64,
+	       sizeof(uint32_t), (void *)xdr_send_uint32);
+
+	xdr_send_uint32(xdr, &arg->size);             /* size */
+
+	return 0;
+}
+
+static int ping_mdm_data_register_ret(struct msm_rpc_client *client,
+				      struct msm_rpc_xdr *xdr, void *data)
+{
+	struct ping_mdm_data_ret *ret = data;
+
+	xdr_recv_uint32(xdr, &ret->result);      /* result */
+
+	return 0;
+}
+
+static int ping_mdm_data_register(
+	struct msm_rpc_client *client,
+	struct ping_mdm_data_arg *arg,
+	struct ping_mdm_data_ret *ret)
+{
+	return msm_rpc_client_req2(client,
+				   PING_MDM_REGISTER_DATA_PROC,
+				   ping_mdm_data_register_arg, arg,
+				   ping_mdm_data_register_ret, ret, -1);
+}
+
+struct ping_mdm_register_arg {
+	int (*cb_func)(struct ping_mdm_register_cb_arg *, void *);
+	int num;
+};
+
+struct ping_mdm_unregister_arg {
+	int (*cb_func)(struct ping_mdm_register_cb_arg *, void *);
+};
+
+struct ping_mdm_register_ret {
+	uint32_t result;
+};
+
+struct ping_mdm_unregister_ret {
+	uint32_t result;
+};
+
+static int ping_mdm_register_arg(struct msm_rpc_client *client,
+				 struct msm_rpc_xdr *xdr, void *data)
+{
+	struct ping_mdm_register_arg *arg = data;
+	int cb_id;
+
+	cb_id = msm_rpc_add_cb_func(client, (void *)arg->cb_func);
+	if ((cb_id < 0) && (cb_id != MSM_RPC_CLIENT_NULL_CB_ID))
+		return cb_id;
+
+	xdr_send_uint32(xdr, &cb_id);             /* cb_id */
+	xdr_send_uint32(xdr, &arg->num);          /* num */
+
+	return 0;
+}
+
+static int ping_mdm_unregister_arg(struct msm_rpc_client *client,
+				   struct msm_rpc_xdr *xdr, void *data)
+{
+	struct ping_mdm_unregister_arg *arg = data;
+	int cb_id;
+
+	cb_id = msm_rpc_add_cb_func(client, (void *)arg->cb_func);
+	if ((cb_id < 0) && (cb_id != MSM_RPC_CLIENT_NULL_CB_ID))
+		return cb_id;
+
+	xdr_send_uint32(xdr, &cb_id);             /* cb_id */
+
+	return 0;
+}
+
+static int ping_mdm_register_ret(struct msm_rpc_client *client,
+				 struct msm_rpc_xdr *xdr, void *data)
+{
+	struct ping_mdm_register_ret *ret = data;
+
+	xdr_recv_uint32(xdr, &ret->result);      /* result */
+
+	return 0;
+}
+
+static int ping_mdm_register(
+	struct msm_rpc_client *client,
+	struct ping_mdm_register_arg *arg,
+	struct ping_mdm_register_ret *ret)
+{
+	return msm_rpc_client_req2(client,
+				   PING_MDM_REGISTER_PROC,
+				   ping_mdm_register_arg, arg,
+				   ping_mdm_register_ret, ret, -1);
+}
+
+static int ping_mdm_unregister(
+	struct msm_rpc_client *client,
+	struct ping_mdm_unregister_arg *arg,
+	struct ping_mdm_unregister_ret *ret)
+{
+	return msm_rpc_client_req2(client,
+				   PING_MDM_UNREGISTER_PROC,
+				   ping_mdm_unregister_arg, arg,
+				   ping_mdm_register_ret, ret, -1);
+}
+
+static int ping_mdm_null(struct msm_rpc_client *client,
+			 void *arg, void *ret)
+{
+	return msm_rpc_client_req2(client, PING_MDM_NULL_PROC,
+				   NULL, NULL, NULL, NULL, -1);
+}
+
+static int ping_mdm_close(void)
+{
+	mutex_lock(&ping_mdm_lock);
+	if (--open_count == 0) {
+		msm_rpc_unregister_client(rpc_client);
+		pr_info("%s: disconnected from remote ping server\n",
+			__func__);
+	}
+	mutex_unlock(&ping_mdm_lock);
+	return 0;
+}
+
+static void handle_restart_teardown(struct msm_rpc_client *client)
+{
+	int	event = PING_MODEM_IN_RESET;
+
+	pr_info("%s: modem in reset\n", __func__);
+
+	mutex_lock(&event_fifo_lock);
+	kfifo_in(&event_fifo, &event, sizeof(event));
+	fifo_event = 1;
+	mutex_unlock(&event_fifo_lock);
+
+	wake_up(&data_cb_test_wait);
+}
+
+static void handle_restart_setup(struct msm_rpc_client *client)
+{
+	int	event = PING_LEAVING_RESET;
+
+	pr_info("%s: modem leaving reset\n", __func__);
+
+	mutex_lock(&event_fifo_lock);
+	kfifo_in(&event_fifo, &event, sizeof(event));
+	fifo_event = 1;
+	mutex_unlock(&event_fifo_lock);
+
+	wake_up(&data_cb_test_wait);
+}
+
+static struct msm_rpc_client *ping_mdm_init(void)
+{
+	mutex_lock(&ping_mdm_lock);
+	if (open_count == 0) {
+		rpc_client = msm_rpc_register_client2("pingdef",
+						      PING_MDM_PROG,
+						      PING_MDM_VERS, 1,
+						      ping_mdm_cb_func);
+		if (!IS_ERR(rpc_client)) {
+			open_count++;
+			msm_rpc_register_reset_callbacks(rpc_client,
+					handle_restart_teardown,
+					handle_restart_setup);
+		}
+	}
+	mutex_unlock(&ping_mdm_lock);
+	return rpc_client;
+}
+
+static int ping_mdm_data_register_test(void)
+{
+	int i, rc = 0;
+	uint32_t my_data[64];
+	uint32_t my_sum = 0;
+	struct ping_mdm_data_arg data_arg;
+	struct ping_mdm_data_ret data_ret;
+
+	for (i = 0; i < 64; i++) {
+		my_data[i] = (42 + i);
+		my_sum ^= (42 + i);
+	}
+
+	data_arg.data = my_data;
+	data_arg.size = 64;
+
+	rc = ping_mdm_data_register(rpc_client, &data_arg, &data_ret);
+	if (rc)
+		return rc;
+
+	if (my_sum != data_ret.result) {
+		pr_err("%s: sum mismatch %d %d\n",
+		       __func__, my_sum, data_ret.result);
+		rc = -1;
+	}
+
+	return rc;
+}
+
+static int ping_mdm_test_register_data_cb(
+	struct ping_mdm_register_data_cb_cb_arg *arg,
+	struct ping_mdm_register_data_cb_cb_ret *ret)
+{
+	uint32_t i, sum = 0;
+
+	data_cb_num++;
+
+	pr_info("%s: received cb_id %d, size = %d, sum = %u, num = %u of %u\n",
+		__func__, arg->cb_id, arg->size, arg->sum, data_cb_num,
+		data_cb_num_req);
+
+	if (arg->data)
+		for (i = 0; i < arg->size; i++)
+			sum ^= arg->data[i];
+
+	if (sum != arg->sum)
+		pr_err("%s: sum mismatch %u %u\n", __func__, sum, arg->sum);
+
+	if (data_cb_num == data_cb_num_req) {
+		data_cb_done_flag = 1;
+		wake_up(&data_cb_test_wait);
+	}
+
+	ret->result = 1;
+	return 0;
+}
+
+static int ping_mdm_data_cb_register(
+		struct ping_mdm_register_data_cb_ret *reg_ret)
+{
+	int rc;
+	struct ping_mdm_register_data_cb_arg reg_arg;
+
+	reg_arg.cb_func = ping_mdm_test_register_data_cb;
+	reg_arg.num = data_cb_num_req - data_cb_num;
+	reg_arg.size = 64;
+	reg_arg.interval_ms = 10;
+	reg_arg.num_tasks = 1;
+
+	pr_info("%s: registering callback\n", __func__);
+	rc = ping_mdm_register_data_cb(rpc_client, &reg_arg, reg_ret);
+	if (rc)
+		pr_err("%s: failed to register callback %d\n", __func__, rc);
+
+	return rc;
+}
+
+
+static void retry_timer_cb(unsigned long data)
+{
+	int	event = (int)data;
+
+	pr_info("%s: retry timer triggered\n", __func__);
+
+	mutex_lock(&event_fifo_lock);
+	kfifo_in(&event_fifo, &event, sizeof(event));
+	fifo_event = 1;
+	mutex_unlock(&event_fifo_lock);
+
+	wake_up(&data_cb_test_wait);
+}
+
+static int ping_mdm_data_cb_register_test(void)
+{
+	int rc;
+	int event;
+	int retry_count = 0;
+	struct ping_mdm_register_data_cb_ret reg_ret;
+	struct ping_mdm_unregister_data_cb_arg unreg_arg;
+	struct ping_mdm_unregister_data_cb_ret unreg_ret;
+	struct timer_list retry_timer;
+
+	mutex_init(&event_fifo_lock);
+	init_timer(&retry_timer);
+
+	data_cb_done_flag = 0;
+	data_cb_num = 0;
+	if (!data_cb_num_req)
+		data_cb_num_req = 10;
+
+	rc = ping_mdm_data_cb_register(&reg_ret);
+	if (rc)
+		return rc;
+
+	pr_info("%s: data_cb_register result: 0x%x\n",
+		__func__, reg_ret.result);
+
+	while (!data_cb_done_flag) {
+		wait_event(data_cb_test_wait, data_cb_done_flag || fifo_event);
+		fifo_event = 0;
+
+		for (;;) {
+			mutex_lock(&event_fifo_lock);
+
+			if (kfifo_is_empty(&event_fifo)) {
+				mutex_unlock(&event_fifo_lock);
+				break;
+			}
+			rc = kfifo_out(&event_fifo, &event, sizeof(event));
+			mutex_unlock(&event_fifo_lock);
+			BUG_ON(rc != sizeof(event));
+
+			pr_info("%s: processing event data_cb_done_flag=%d,event=%d\n",
+				__func__, data_cb_done_flag, event);
+
+			if (event == PING_MODEM_IN_RESET) {
+				pr_info("%s: modem entering reset\n", __func__);
+				retry_count = 0;
+			} else if (event == PING_LEAVING_RESET) {
+				pr_info("%s: modem exiting reset - "
+					"re-registering cb\n", __func__);
+
+				rc = ping_mdm_data_cb_register(&reg_ret);
+				if (rc) {
+					retry_count++;
+					if (retry_count < PING_MAX_RETRY) {
+						pr_info("%s: retry %d failed\n",
+							__func__, retry_count);
+
+						retry_timer.expires = jiffies +
+							msecs_to_jiffies(1000);
+						retry_timer.data =
+							PING_LEAVING_RESET;
+						retry_timer.function =
+							retry_timer_cb;
+						add_timer(&retry_timer);
+					} else {
+						pr_err("%s: max retries exceeded, aborting\n",
+								__func__);
+						return -ENETRESET;
+					}
+				} else
+					pr_info("%s: data_cb_register result: 0x%x\n",
+						__func__, reg_ret.result);
+			}
+		}
+	}
+
+	while (del_timer(&retry_timer))
+		;
+
+	unreg_arg.cb_func = ping_mdm_test_register_data_cb;
+	rc = ping_mdm_unregister_data_cb(rpc_client, &unreg_arg, &unreg_ret);
+	if (rc)
+		return rc;
+
+	pr_info("%s: data_cb_unregister result: 0x%x\n",
+		__func__, unreg_ret.result);
+
+	pr_info("%s: Test completed\n", __func__);
+
+	return 0;
+}
+
+static int ping_mdm_test_register_cb(
+	struct ping_mdm_register_cb_arg *arg, void *ret)
+{
+	pr_info("%s: received cb_id %d, val = %d\n",
+		__func__, arg->cb_id, arg->val);
+
+	reg_cb_num++;
+	if (reg_cb_num == reg_cb_num_req) {
+		reg_done_flag = 1;
+		wake_up(&reg_test_wait);
+	}
+	return 0;
+}
+
+static int ping_mdm_register_test(void)
+{
+	int rc = 0;
+	struct ping_mdm_register_arg reg_arg;
+	struct ping_mdm_unregister_arg unreg_arg;
+	struct ping_mdm_register_ret reg_ret;
+	struct ping_mdm_unregister_ret unreg_ret;
+
+	reg_cb_num = 0;
+	reg_cb_num_req = 10;
+	reg_done_flag = 0;
+
+	reg_arg.num = 10;
+	reg_arg.cb_func = ping_mdm_test_register_cb;
+
+	rc = ping_mdm_register(rpc_client, &reg_arg, &reg_ret);
+	if (rc)
+		return rc;
+
+	pr_info("%s: register result: 0x%x\n",
+		__func__, reg_ret.result);
+
+	wait_event(reg_test_wait, reg_done_flag);
+
+	unreg_arg.cb_func = ping_mdm_test_register_cb;
+	rc = ping_mdm_unregister(rpc_client, &unreg_arg, &unreg_ret);
+	if (rc)
+		return rc;
+
+	pr_info("%s: unregister result: 0x%x\n",
+		__func__, unreg_ret.result);
+
+	return 0;
+}
+
+static int ping_mdm_null_test(void)
+{
+	return ping_mdm_null(rpc_client, NULL, NULL);
+}
+
+static int ping_test_release(struct inode *ip, struct file *fp)
+{
+	return ping_mdm_close();
+}
+
+static int ping_test_open(struct inode *ip, struct file *fp)
+{
+	struct msm_rpc_client *client;
+
+	client = ping_mdm_init();
+	if (IS_ERR(client)) {
+		pr_err("%s: couldn't open ping client\n", __func__);
+		return PTR_ERR(client);
+	} else
+		pr_info("%s: connected to remote ping server\n",
+			__func__);
+
+	return 0;
+}
+
+static ssize_t ping_test_read(struct file *fp, char __user *buf,
+			size_t count, loff_t *pos)
+{
+	char _buf[16];
+
+	snprintf(_buf, sizeof(_buf), "%i\n", test_res);
+
+	return simple_read_from_buffer(buf, count, pos, _buf, strlen(_buf));
+}
+
+static ssize_t ping_test_write(struct file *fp, const char __user *buf,
+			 size_t count, loff_t *pos)
+{
+	unsigned char cmd[64];
+	int len;
+
+	if (count < 1)
+		return 0;
+
+	len = count > 63 ? 63 : count;
+
+	if (copy_from_user(cmd, buf, len))
+		return -EFAULT;
+
+	cmd[len] = 0;
+
+	/* lazy */
+	if (cmd[len-1] == '\n') {
+		cmd[len-1] = 0;
+		len--;
+	}
+
+	if (!strncmp(cmd, "null_test", 64))
+		test_res = ping_mdm_null_test();
+	else if (!strncmp(cmd, "reg_test", 64))
+		test_res = ping_mdm_register_test();
+	else if (!strncmp(cmd, "data_reg_test", 64))
+		test_res = ping_mdm_data_register_test();
+	else if (!strncmp(cmd, "data_cb_reg_test", 64))
+		test_res = ping_mdm_data_cb_register_test();
+	else if (!strncmp(cmd, "count=", 6)) {
+		long tmp;
+
+		if (strict_strtol(cmd + 6, 0, &tmp) == 0) {
+			data_cb_num_req = tmp;
+			pr_info("Set repetition count to %d\n",
+				data_cb_num_req);
+		} else {
+			data_cb_num_req = 10;
+			pr_err("invalid number %s, defaulting to %d\n",
+				cmd + 6, data_cb_num_req);
+		}
+	}
+	else
+		test_res = -EINVAL;
+
+	return count;
+}
+
+static const struct file_operations debug_ops = {
+	.owner = THIS_MODULE,
+	.open = ping_test_open,
+	.read = ping_test_read,
+	.write = ping_test_write,
+	.release = ping_test_release,
+};
+
+static void __exit ping_test_exit(void)
+{
+	debugfs_remove(dent);
+}
+
+static int __init ping_test_init(void)
+{
+	dent = debugfs_create_file("ping_mdm", 0444, 0, NULL, &debug_ops);
+	test_res = 0;
+	open_count = 0;
+	return 0;
+}
+
+module_init(ping_test_init);
+module_exit(ping_test_exit);
+
+MODULE_DESCRIPTION("PING TEST Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/platsmp-8625.c b/arch/arm/mach-msm/platsmp-8625.c
new file mode 100644
index 0000000..915047a
--- /dev/null
+++ b/arch/arm/mach-msm/platsmp-8625.c
@@ -0,0 +1,295 @@
+/* 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/errno.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/jiffies.h>
+#include <linux/smp.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+
+#include <asm/cacheflush.h>
+#include <asm/hardware/gic.h>
+#include <asm/hardware/cache-l2x0.h>
+#include <asm/smp_scu.h>
+#include <asm/unified.h>
+#include <mach/msm_iomap.h>
+#include "pm.h"
+
+#define MSM_CORE1_RESET		0xA8600590
+#define MSM_CORE1_STATUS_MSK	0x02800000
+
+/*
+ * control for which core is the next to come out of the secondary
+ * boot "holding pen"
+ */
+int pen_release = -1;
+
+static bool cold_boot_done;
+
+static uint32_t *msm8625_boot_vector;
+static void __iomem *reset_core1_base;
+
+/*
+ * Write pen_release in a way that is guaranteed to be visible to all
+ * observers, irrespective of whether they're taking part in coherency
+ * or not.  This is necessary for the hotplug code to work reliably.
+ */
+static void __cpuinit write_pen_release(int val)
+{
+	pen_release = val;
+	smp_wmb();
+	__cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
+	outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
+}
+
+static void __iomem *scu_base_addr(void)
+{
+	return MSM_SCU_BASE;
+}
+
+static DEFINE_SPINLOCK(boot_lock);
+
+/*
+ * MP_CORE_IPC will be used to generate interrupt and can be used by either
+ * of core.
+ * To bring core1 out of GDFS we need to raise the SPI using the MP_CORE_IPC.
+ */
+static void raise_clear_spi(unsigned int cpu, bool set)
+{
+	int value;
+
+	value = __raw_readl(MSM_CSR_BASE + 0x54);
+	if (set)
+		__raw_writel(value | BIT(cpu), MSM_CSR_BASE + 0x54);
+	else
+		__raw_writel(value & ~BIT(cpu), MSM_CSR_BASE + 0x54);
+	mb();
+}
+
+static void clear_pending_spi(unsigned int irq)
+{
+	struct irq_data *d = irq_get_irq_data(irq);
+	struct irq_chip *c = irq_data_get_irq_chip(d);
+
+	c->irq_mask(d);
+	local_irq_disable();
+	/* Clear the IRQ from the ENABLE_SET */
+	gic_clear_spi_pending(irq);
+	local_irq_enable();
+}
+
+void __cpuinit platform_secondary_init(unsigned int cpu)
+{
+	pr_debug("CPU%u: Booted secondary processor\n", cpu);
+
+	WARN_ON(msm_platform_secondary_init(cpu));
+
+	/*
+	 * if any interrupts are already enabled for the primary
+	 * core (e.g. timer irq), then they will not have been enabled
+	 * for us: do so
+	 */
+	gic_secondary_init(0);
+
+	/*
+	 * let the primary processor know we're out of the
+	 * pen, then head off into the C entry point
+	 */
+	write_pen_release(-1);
+
+	/* clear the IPC1(SPI-8) pending SPI */
+	if (power_collapsed) {
+		raise_clear_spi(1, false);
+		clear_pending_spi(MSM8625_INT_ACSR_MP_CORE_IPC1);
+		power_collapsed = 0;
+	}
+
+	/*
+	 * Synchronise with the boot thread.
+	 */
+	spin_lock(&boot_lock);
+	spin_unlock(&boot_lock);
+}
+
+static int  __cpuinit msm8625_release_secondary(void)
+{
+	void __iomem *base_ptr;
+	int value = 0;
+	unsigned long timeout;
+
+	/*
+	 * loop to ensure that the GHS_STATUS_CORE1 bit in the
+	 * MPA5_STATUS_REG(0x3c) is set. The timeout for the while
+	 * loop can be set as 20us as of now
+	 */
+	timeout = jiffies + usecs_to_jiffies(20);
+	while (time_before(jiffies, timeout)) {
+		value = __raw_readl(MSM_CFG_CTL_BASE + 0x3c);
+		if ((value & MSM_CORE1_STATUS_MSK) ==
+				MSM_CORE1_STATUS_MSK)
+			break;
+			udelay(1);
+	}
+
+	if (!value) {
+		pr_err("Core 1 cannot be brought out of Reset!!!\n");
+		return -ENODEV;
+	}
+
+	base_ptr = ioremap_nocache(MSM_CORE1_RESET, SZ_4);
+	if (!base_ptr)
+		return -ENODEV;
+	/* Reset core 1 out of reset */
+	__raw_writel(0x0, base_ptr);
+	mb();
+
+	reset_core1_base = base_ptr;
+
+	return 0;
+}
+
+void __iomem *core1_reset_base(void)
+{
+	return reset_core1_base;
+}
+
+int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+	unsigned long timeout;
+
+	preset_lpj = loops_per_jiffy;
+
+	if (cold_boot_done == false) {
+		if (msm8625_release_secondary()) {
+			pr_err("Failed to release secondary core\n");
+			return -ENODEV;
+		}
+		cold_boot_done = true;
+	}
+
+	/*
+	 * Set synchronisation state between this boot processor
+	 * and the secondary one
+	 */
+	spin_lock(&boot_lock);
+
+	/*
+	 * This is really belt and braces; we hold unintended secondary
+	 * CPUs in the holding pen until we're ready for them.  However,
+	 * since we haven't sent them a soft interrupt, they shouldn't
+	 * be there.
+	 */
+	write_pen_release(cpu);
+
+	/*
+	 * Send the secondary CPU a soft interrupt, thereby causing
+	 * the boot monitor to read the system wide flags register,
+	 * and branch to the address found there.
+	 *
+	 * power_collapsed is the flag which will be updated for Powercollapse.
+	 * Once we are out of PC, as Core1 will be in the state of GDFS which
+	 * needs to be brought out by raising an SPI.
+	 */
+
+	if (power_collapsed) {
+		core1_gic_configure_and_raise();
+		raise_clear_spi(1, true);
+	} else {
+		gic_raise_softirq(cpumask_of(cpu), 1);
+	}
+
+	timeout = jiffies + (1 * HZ);
+	while (time_before(jiffies, timeout)) {
+		smp_rmb();
+		if (pen_release == -1)
+			break;
+
+		udelay(10);
+	}
+
+	/*
+	 * now the secondary core is starting up let it run its
+	 * calibrations, then wait for it to finish
+	 */
+	spin_unlock(&boot_lock);
+
+	return 0;
+}
+
+/*
+ * Initialise the CPU possible map early - this describes the CPUs
+ * which may be present or become present in the system.
+ */
+void __init smp_init_cpus(void)
+{
+	void __iomem *scu_base = scu_base_addr();
+
+	unsigned int i, ncores;
+
+	ncores = scu_base ? scu_get_core_count(scu_base) : 1;
+
+	for (i = 0; i < ncores; i++)
+		set_cpu_possible(i, true);
+
+	set_smp_cross_call(gic_raise_softirq);
+}
+
+static void __init msm8625_boot_vector_init(uint32_t *boot_vector,
+		unsigned long entry)
+{
+	if (!boot_vector)
+		return;
+	msm8625_boot_vector = boot_vector;
+
+	msm8625_boot_vector[0] = 0xE51FF004; /* ldr pc, 4 */
+	msm8625_boot_vector[1] = entry;
+}
+
+void __init platform_smp_prepare_cpus(unsigned int max_cpus)
+{
+	int i, value;
+	void __iomem *second_ptr;
+
+	/*
+	 * Initialise the present map, which describes the set of CPUs
+	 * actually populated at the present time.
+	 */
+	for (i = 0; i < max_cpus; i++)
+		set_cpu_present(i, true);
+
+	scu_enable(scu_base_addr());
+
+	/*
+	 * Write the address of secondary startup into the
+	 * boot remapper register. The secondary CPU branches to this address.
+	 */
+	__raw_writel(MSM8625_SECONDARY_PHYS, (MSM_CFG_CTL_BASE + 0x34));
+	mb();
+
+	second_ptr = ioremap_nocache(MSM8625_SECONDARY_PHYS, SZ_8);
+	if (!second_ptr) {
+		pr_err("failed to ioremap for secondary core\n");
+		return;
+	}
+
+	msm8625_boot_vector_init(second_ptr,
+			virt_to_phys(msm_secondary_startup));
+	iounmap(second_ptr);
+
+	/* Enable boot remapper address: bit 26 for core1 */
+	value = __raw_readl(MSM_CFG_CTL_BASE + 0x30);
+	__raw_writel(value | (0x4 << 24), MSM_CFG_CTL_BASE + 0x30) ;
+	mb();
+}
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index db0117e..b40c0c7 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -1,19 +1,18 @@
 /*
  *  Copyright (C) 2002 ARM Ltd.
  *  All Rights Reserved
- *  Copyright (c) 2010, 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 as
  * published by the Free Software Foundation.
  */
 
+#include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/errno.h>
+#include <linux/cpumask.h>
 #include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/jiffies.h>
-#include <linux/smp.h>
+#include <linux/interrupt.h>
 #include <linux/io.h>
 
 #include <asm/hardware/gic.h>
@@ -22,18 +21,20 @@
 #include <asm/mach-types.h>
 #include <asm/smp_plat.h>
 
+#include <mach/socinfo.h>
+#include <mach/hardware.h>
 #include <mach/msm_iomap.h>
 
+#include "pm.h"
 #include "scm-boot.h"
+#include "spm.h"
 
 #define VDD_SC1_ARRAY_CLAMP_GFS_CTL 0x15A0
 #define SCSS_CPU1CORE_RESET 0xD80
 #define SCSS_DBG_STATUS_CORE_PWRDUP 0xE64
 
-/* Mask for edge trigger PPIs except AVS_SVICINT and AVS_SVICINTSWDONE */
-#define GIC_PPI_EDGE_MASK 0xFFFFD7FF
-
 extern void msm_secondary_startup(void);
+
 /*
  * control for which core is the next to come out of the secondary
  * boot "holding pen".
@@ -42,16 +43,9 @@
 
 static DEFINE_SPINLOCK(boot_lock);
 
-static inline int get_core_count(void)
-{
-	/* 1 + the PART[1:0] field of MIDR */
-	return ((read_cpuid_id() >> 4) & 3) + 1;
-}
-
 void __cpuinit platform_secondary_init(unsigned int cpu)
 {
-	/* Configure edge-triggered PPIs */
-	writel(GIC_PPI_EDGE_MASK, MSM_QGIC_DIST_BASE + GIC_DIST_CONFIG + 4);
+	WARN_ON(msm_platform_secondary_init(cpu));
 
 	/*
 	 * if any interrupts are already enabled for the primary
@@ -61,47 +55,134 @@
 	gic_secondary_init(0);
 
 	/*
-	 * let the primary processor know we're out of the
-	 * pen, then head off into the C entry point
-	 */
-	pen_release = -1;
-	smp_wmb();
-
-	/*
 	 * Synchronise with the boot thread.
 	 */
 	spin_lock(&boot_lock);
 	spin_unlock(&boot_lock);
 }
 
-static __cpuinit void prepare_cold_cpu(unsigned int cpu)
+static int __cpuinit scorpion_release_secondary(void)
 {
-	int ret;
-	ret = scm_set_boot_addr(virt_to_phys(msm_secondary_startup),
-				SCM_FLAG_COLDBOOT_CPU1);
-	if (ret == 0) {
-		void __iomem *sc1_base_ptr;
-		sc1_base_ptr = ioremap_nocache(0x00902000, SZ_4K*2);
-		if (sc1_base_ptr) {
-			writel(0, sc1_base_ptr + VDD_SC1_ARRAY_CLAMP_GFS_CTL);
-			writel(0, sc1_base_ptr + SCSS_CPU1CORE_RESET);
-			writel(3, sc1_base_ptr + SCSS_DBG_STATUS_CORE_PWRDUP);
-			iounmap(sc1_base_ptr);
-		}
-	} else
-		printk(KERN_DEBUG "Failed to set secondary core boot "
-				  "address\n");
+	void *base_ptr = ioremap_nocache(0x00902000, SZ_4K*2);
+	if (!base_ptr)
+		return -EINVAL;
+
+	writel_relaxed(0, base_ptr + VDD_SC1_ARRAY_CLAMP_GFS_CTL);
+	dmb();
+	writel_relaxed(0, base_ptr + SCSS_CPU1CORE_RESET);
+	writel_relaxed(3, base_ptr + SCSS_DBG_STATUS_CORE_PWRDUP);
+	mb();
+	iounmap(base_ptr);
+
+	return 0;
 }
 
+static int __cpuinit krait_release_secondary_sim(unsigned long base, int cpu)
+{
+	void *base_ptr = ioremap_nocache(base + (cpu * 0x10000), SZ_4K);
+	if (!base_ptr)
+		return -ENODEV;
+
+	if (machine_is_msm8960_sim() || machine_is_msm8960_rumi3()) {
+		writel_relaxed(0x10, base_ptr+0x04);
+		writel_relaxed(0x80, base_ptr+0x04);
+	}
+
+	if (machine_is_apq8064_sim())
+		writel_relaxed(0xf0000, base_ptr+0x04);
+
+	if (machine_is_copper_sim()) {
+		writel_relaxed(0x800, base_ptr+0x04);
+		writel_relaxed(0x3FFF, base_ptr+0x14);
+	}
+
+	mb();
+	iounmap(base_ptr);
+	return 0;
+}
+
+static int __cpuinit krait_release_secondary(unsigned long base, int cpu)
+{
+	void *base_ptr = ioremap_nocache(base + (cpu * 0x10000), SZ_4K);
+	if (!base_ptr)
+		return -ENODEV;
+
+	msm_spm_turn_on_cpu_rail(cpu);
+
+	writel_relaxed(0x109, base_ptr+0x04);
+	writel_relaxed(0x101, base_ptr+0x04);
+	ndelay(300);
+
+	writel_relaxed(0x121, base_ptr+0x04);
+	udelay(2);
+
+	writel_relaxed(0x020, base_ptr+0x04);
+	udelay(2);
+
+	writel_relaxed(0x000, base_ptr+0x04);
+	udelay(100);
+
+	writel_relaxed(0x080, base_ptr+0x04);
+	mb();
+	iounmap(base_ptr);
+	return 0;
+}
+
+static int __cpuinit release_secondary(unsigned int cpu)
+{
+	BUG_ON(cpu >= get_core_count());
+
+	if (cpu_is_msm8x60())
+		return scorpion_release_secondary();
+
+	if (machine_is_msm8960_sim() || machine_is_msm8960_rumi3() ||
+	    machine_is_apq8064_sim())
+		return krait_release_secondary_sim(0x02088000, cpu);
+
+	if (machine_is_copper_sim())
+		return krait_release_secondary_sim(0xf9088000, cpu);
+
+	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_apq8064())
+		return krait_release_secondary(0x02088000, cpu);
+
+	WARN(1, "unknown CPU case in release_secondary\n");
+	return -EINVAL;
+}
+
+DEFINE_PER_CPU(int, cold_boot_done);
+static int cold_boot_flags[] = {
+	0,
+	SCM_FLAG_COLDBOOT_CPU1,
+	SCM_FLAG_COLDBOOT_CPU2,
+	SCM_FLAG_COLDBOOT_CPU3,
+};
+
 int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
 {
+	int ret;
+	int flag = 0;
 	unsigned long timeout;
-	static int cold_boot_done;
 
-	/* Only need to bring cpu out of reset this way once */
-	if (cold_boot_done == false) {
-		prepare_cold_cpu(cpu);
-		cold_boot_done = true;
+	pr_debug("Starting secondary CPU %d\n", cpu);
+
+	/* Set preset_lpj to avoid subsequent lpj recalculations */
+	preset_lpj = loops_per_jiffy;
+
+	if (cpu > 0 && cpu < ARRAY_SIZE(cold_boot_flags))
+		flag = cold_boot_flags[cpu];
+	else
+		__WARN();
+
+	if (per_cpu(cold_boot_done, cpu) == false) {
+		ret = scm_set_boot_addr((void *)
+					virt_to_phys(msm_secondary_startup),
+					flag);
+		if (ret == 0)
+			release_secondary(cpu);
+		else
+			printk(KERN_DEBUG "Failed to set secondary core boot "
+					  "address\n");
+		per_cpu(cold_boot_done, cpu) = true;
 	}
 
 	/*
@@ -121,6 +202,8 @@
 	pen_release = cpu_logical_map(cpu);
 	__cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
 	outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
+	__asm__("sev");
+	mb();
 
 	/*
 	 * Send the secondary CPU a soft interrupt, thereby causing
@@ -135,6 +218,8 @@
 		if (pen_release == -1)
 			break;
 
+		dmac_inv_range((void *)&pen_release,
+			       (void *)(&pen_release+sizeof(pen_release)));
 		udelay(10);
 	}
 
@@ -146,12 +231,9 @@
 
 	return pen_release != -1 ? -ENOSYS : 0;
 }
-
 /*
  * Initialise the CPU possible map early - this describes the CPUs
- * which may be present or become present in the system. The msm8x60
- * does not support the ARM SCU, so just set the possible cpu mask to
- * NR_CPUS.
+ * which may be present or become present in the system.
  */
 void __init smp_init_cpus(void)
 {
@@ -166,7 +248,7 @@
 	for (i = 0; i < ncores; i++)
 		set_cpu_possible(i, true);
 
-        set_smp_cross_call(gic_raise_softirq);
+	set_smp_cross_call(gic_raise_softirq);
 }
 
 void __init platform_smp_prepare_cpus(unsigned int max_cpus)
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
new file mode 100644
index 0000000..163caa5
--- /dev/null
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -0,0 +1,1059 @@
+/* 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
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/completion.h>
+#include <linux/cpuidle.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ktime.h>
+#include <linux/pm.h>
+#include <linux/pm_qos.h>
+#include <linux/smp.h>
+#include <linux/suspend.h>
+#include <linux/tick.h>
+#include <linux/wakelock.h>
+#include <linux/delay.h>
+#include <mach/msm_iomap.h>
+#include <mach/socinfo.h>
+#include <mach/system.h>
+#include <asm/cacheflush.h>
+#include <asm/hardware/gic.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/hardware/cache-l2x0.h>
+#ifdef CONFIG_VFP
+#include <asm/vfp.h>
+#endif
+
+#include "acpuclock.h"
+#include "clock.h"
+#include "avs.h"
+#include <mach/cpuidle.h>
+#include "idle.h"
+#include "pm.h"
+#include "scm-boot.h"
+#include "spm.h"
+#include "timer.h"
+#include "pm-boot.h"
+
+/******************************************************************************
+ * Debug Definitions
+ *****************************************************************************/
+
+enum {
+	MSM_PM_DEBUG_SUSPEND = BIT(0),
+	MSM_PM_DEBUG_POWER_COLLAPSE = BIT(1),
+	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),
+};
+
+static int msm_pm_debug_mask = 1;
+module_param_named(
+	debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
+);
+
+
+/******************************************************************************
+ * Sleep Modes and Parameters
+ *****************************************************************************/
+enum {
+	MSM_PM_MODE_ATTR_SUSPEND,
+	MSM_PM_MODE_ATTR_IDLE,
+	MSM_PM_MODE_ATTR_NR,
+};
+
+static char *msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_NR] = {
+	[MSM_PM_MODE_ATTR_SUSPEND] = "suspend_enabled",
+	[MSM_PM_MODE_ATTR_IDLE] = "idle_enabled",
+};
+
+struct msm_pm_kobj_attribute {
+	unsigned int cpu;
+	struct kobj_attribute ka;
+};
+
+#define GET_CPU_OF_ATTR(attr) \
+	(container_of(attr, struct msm_pm_kobj_attribute, ka)->cpu)
+
+struct msm_pm_sysfs_sleep_mode {
+	struct kobject *kobj;
+	struct attribute_group attr_group;
+	struct attribute *attrs[MSM_PM_MODE_ATTR_NR + 1];
+	struct msm_pm_kobj_attribute kas[MSM_PM_MODE_ATTR_NR];
+};
+
+static char *msm_pm_sleep_mode_labels[MSM_PM_SLEEP_MODE_NR] = {
+	[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = "power_collapse",
+	[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT] = "wfi",
+	[MSM_PM_SLEEP_MODE_RETENTION] = "retention",
+	[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE] =
+		"standalone_power_collapse",
+};
+
+static struct msm_pm_sleep_ops pm_sleep_ops;
+/*
+ * Write out the attribute.
+ */
+static ssize_t msm_pm_mode_attr_show(
+	struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	int ret = -EINVAL;
+	int i;
+
+	for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
+		struct kernel_param kp;
+		unsigned int cpu;
+		struct msm_pm_platform_data *mode;
+
+		if (msm_pm_sleep_mode_labels[i] == NULL)
+			continue;
+
+		if (strcmp(kobj->name, msm_pm_sleep_mode_labels[i]))
+			continue;
+
+		cpu = GET_CPU_OF_ATTR(attr);
+		mode = &msm_pm_sleep_modes[MSM_PM_MODE(cpu, i)];
+
+		if (!strcmp(attr->attr.name,
+			msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_SUSPEND])) {
+			u32 arg = mode->suspend_enabled;
+			kp.arg = &arg;
+			ret = param_get_ulong(buf, &kp);
+		} else if (!strcmp(attr->attr.name,
+			msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_IDLE])) {
+			u32 arg = mode->idle_enabled;
+			kp.arg = &arg;
+			ret = param_get_ulong(buf, &kp);
+		}
+
+		break;
+	}
+
+	if (ret > 0) {
+		strlcat(buf, "\n", PAGE_SIZE);
+		ret++;
+	}
+
+	return ret;
+}
+
+/*
+ * Read in the new attribute value.
+ */
+static ssize_t msm_pm_mode_attr_store(struct kobject *kobj,
+	struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	int ret = -EINVAL;
+	int i;
+
+	for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
+		struct kernel_param kp;
+		unsigned int cpu;
+		struct msm_pm_platform_data *mode;
+
+		if (msm_pm_sleep_mode_labels[i] == NULL)
+			continue;
+
+		if (strcmp(kobj->name, msm_pm_sleep_mode_labels[i]))
+			continue;
+
+		cpu = GET_CPU_OF_ATTR(attr);
+		mode = &msm_pm_sleep_modes[MSM_PM_MODE(cpu, i)];
+
+		if (!strcmp(attr->attr.name,
+			msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_SUSPEND])) {
+			kp.arg = &mode->suspend_enabled;
+			ret = param_set_byte(buf, &kp);
+		} else if (!strcmp(attr->attr.name,
+			msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_IDLE])) {
+			kp.arg = &mode->idle_enabled;
+			ret = param_set_byte(buf, &kp);
+		}
+
+		break;
+	}
+
+	return ret ? ret : count;
+}
+
+/*
+ * Add sysfs entries for one cpu.
+ */
+static int __init msm_pm_mode_sysfs_add_cpu(
+	unsigned int cpu, struct kobject *modes_kobj)
+{
+	char cpu_name[8];
+	struct kobject *cpu_kobj;
+	struct msm_pm_sysfs_sleep_mode *mode = NULL;
+	int i, j, k;
+	int ret;
+
+	snprintf(cpu_name, sizeof(cpu_name), "cpu%u", cpu);
+	cpu_kobj = kobject_create_and_add(cpu_name, modes_kobj);
+	if (!cpu_kobj) {
+		pr_err("%s: cannot create %s kobject\n", __func__, cpu_name);
+		ret = -ENOMEM;
+		goto mode_sysfs_add_cpu_exit;
+	}
+
+	for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
+		int idx = MSM_PM_MODE(cpu, i);
+
+		if ((!msm_pm_sleep_modes[idx].suspend_supported)
+			&& (!msm_pm_sleep_modes[idx].idle_supported))
+			continue;
+
+		if (!msm_pm_sleep_mode_labels[i] ||
+				!msm_pm_sleep_mode_labels[i][0])
+			continue;
+
+		mode = kzalloc(sizeof(*mode), GFP_KERNEL);
+		if (!mode) {
+			pr_err("%s: cannot allocate memory for attributes\n",
+				__func__);
+			ret = -ENOMEM;
+			goto mode_sysfs_add_cpu_exit;
+		}
+
+		mode->kobj = kobject_create_and_add(
+				msm_pm_sleep_mode_labels[i], cpu_kobj);
+		if (!mode->kobj) {
+			pr_err("%s: cannot create kobject\n", __func__);
+			ret = -ENOMEM;
+			goto mode_sysfs_add_cpu_exit;
+		}
+
+		for (k = 0, j = 0; k < MSM_PM_MODE_ATTR_NR; k++) {
+			if ((k == MSM_PM_MODE_ATTR_IDLE) &&
+				!msm_pm_sleep_modes[idx].idle_supported)
+				continue;
+			if ((k == MSM_PM_MODE_ATTR_SUSPEND) &&
+			     !msm_pm_sleep_modes[idx].suspend_supported)
+				continue;
+			mode->kas[j].cpu = cpu;
+			mode->kas[j].ka.attr.mode = 0644;
+			mode->kas[j].ka.show = msm_pm_mode_attr_show;
+			mode->kas[j].ka.store = msm_pm_mode_attr_store;
+			mode->kas[j].ka.attr.name = msm_pm_mode_attr_labels[k];
+			mode->attrs[j] = &mode->kas[j].ka.attr;
+			j++;
+		}
+		mode->attrs[j] = NULL;
+
+		mode->attr_group.attrs = mode->attrs;
+		ret = sysfs_create_group(mode->kobj, &mode->attr_group);
+		if (ret) {
+			pr_err("%s: cannot create kobject attribute group\n",
+				__func__);
+			goto mode_sysfs_add_cpu_exit;
+		}
+	}
+
+	ret = 0;
+
+mode_sysfs_add_cpu_exit:
+	if (ret) {
+		if (mode && mode->kobj)
+			kobject_del(mode->kobj);
+		kfree(mode);
+	}
+
+	return ret;
+}
+
+/*
+ * Add sysfs entries for the sleep modes.
+ */
+static int __init msm_pm_mode_sysfs_add(void)
+{
+	struct kobject *module_kobj;
+	struct kobject *modes_kobj;
+	unsigned int cpu;
+	int ret;
+
+	module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
+	if (!module_kobj) {
+		pr_err("%s: cannot find kobject for module %s\n",
+			__func__, KBUILD_MODNAME);
+		ret = -ENOENT;
+		goto mode_sysfs_add_exit;
+	}
+
+	modes_kobj = kobject_create_and_add("modes", module_kobj);
+	if (!modes_kobj) {
+		pr_err("%s: cannot create modes kobject\n", __func__);
+		ret = -ENOMEM;
+		goto mode_sysfs_add_exit;
+	}
+
+	for_each_possible_cpu(cpu) {
+		ret = msm_pm_mode_sysfs_add_cpu(cpu, modes_kobj);
+		if (ret)
+			goto mode_sysfs_add_exit;
+	}
+
+	ret = 0;
+
+mode_sysfs_add_exit:
+	return ret;
+}
+
+/******************************************************************************
+ * Configure Hardware before/after Low Power Mode
+ *****************************************************************************/
+
+/*
+ * Configure hardware registers in preparation for Apps power down.
+ */
+static void msm_pm_config_hw_before_power_down(void)
+{
+	return;
+}
+
+/*
+ * Clear hardware registers after Apps powers up.
+ */
+static void msm_pm_config_hw_after_power_up(void)
+{
+	return;
+}
+
+/*
+ * Configure hardware registers in preparation for SWFI.
+ */
+static void msm_pm_config_hw_before_swfi(void)
+{
+	return;
+}
+
+
+/******************************************************************************
+ * Suspend Max Sleep Time
+ *****************************************************************************/
+
+#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE
+static int msm_pm_sleep_time_override;
+module_param_named(sleep_time_override,
+	msm_pm_sleep_time_override, int, S_IRUGO | S_IWUSR | S_IWGRP);
+#endif
+
+#define SCLK_HZ (32768)
+#define MSM_PM_SLEEP_TICK_LIMIT (0x6DDD000)
+
+static uint32_t msm_pm_max_sleep_time;
+
+/*
+ * Convert time from nanoseconds to slow clock ticks, then cap it to the
+ * specified limit
+ */
+static int64_t msm_pm_convert_and_cap_time(int64_t time_ns, int64_t limit)
+{
+	do_div(time_ns, NSEC_PER_SEC / SCLK_HZ);
+	return (time_ns > limit) ? limit : time_ns;
+}
+
+/*
+ * Set the sleep time for suspend.  0 means infinite sleep time.
+ */
+void msm_pm_set_max_sleep_time(int64_t max_sleep_time_ns)
+{
+	if (max_sleep_time_ns == 0) {
+		msm_pm_max_sleep_time = 0;
+	} else {
+		msm_pm_max_sleep_time = (uint32_t)msm_pm_convert_and_cap_time(
+			max_sleep_time_ns, MSM_PM_SLEEP_TICK_LIMIT);
+
+		if (msm_pm_max_sleep_time == 0)
+			msm_pm_max_sleep_time = 1;
+	}
+
+	if (msm_pm_debug_mask & MSM_PM_DEBUG_SUSPEND)
+		pr_info("%s: Requested %lld ns Giving %u sclk ticks\n",
+			__func__, max_sleep_time_ns, msm_pm_max_sleep_time);
+}
+EXPORT_SYMBOL(msm_pm_set_max_sleep_time);
+
+
+/******************************************************************************
+ *
+ *****************************************************************************/
+
+static void *msm_pm_idle_rs_limits;
+static bool msm_pm_use_qtimer;
+
+static void msm_pm_swfi(void)
+{
+	msm_pm_config_hw_before_swfi();
+	msm_arch_idle();
+}
+
+
+static void msm_pm_retention(void)
+{
+	int ret = 0;
+
+	msm_pm_config_hw_before_swfi();
+	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_RETENTION, false);
+	WARN_ON(ret);
+	msm_arch_idle();
+	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
+	WARN_ON(ret);
+}
+
+#ifdef CONFIG_CACHE_L2X0
+static inline bool msm_pm_l2x0_power_collapse(void)
+{
+	bool collapsed = 0;
+
+	l2cc_suspend();
+	collapsed = msm_pm_collapse();
+	l2cc_resume();
+
+	return collapsed;
+}
+#else
+static inline bool msm_pm_l2x0_power_collapse(void)
+{
+	return msm_pm_collapse();
+}
+#endif
+
+static bool __ref msm_pm_spm_power_collapse(
+	unsigned int cpu, bool from_idle, bool notify_rpm)
+{
+	void *entry;
+	bool collapsed = 0;
+	int ret;
+	unsigned int saved_gic_cpu_ctrl;
+
+	saved_gic_cpu_ctrl = readl_relaxed(MSM_QGIC_CPU_BASE + GIC_CPU_CTRL);
+	mb();
+
+	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
+		pr_info("CPU%u: %s: notify_rpm %d\n",
+			cpu, __func__, (int) notify_rpm);
+
+	ret = msm_spm_set_low_power_mode(
+			MSM_SPM_MODE_POWER_COLLAPSE, notify_rpm);
+	WARN_ON(ret);
+
+	entry = (!cpu || from_idle) ?
+		msm_pm_collapse_exit : msm_secondary_startup;
+	msm_pm_boot_config_before_pc(cpu, virt_to_phys(entry));
+
+	if (MSM_PM_DEBUG_RESET_VECTOR & msm_pm_debug_mask)
+		pr_info("CPU%u: %s: program vector to %p\n",
+			cpu, __func__, entry);
+
+#ifdef CONFIG_VFP
+	vfp_pm_suspend();
+#endif
+
+	collapsed = msm_pm_l2x0_power_collapse();
+
+	msm_pm_boot_config_after_pc(cpu);
+
+	if (collapsed) {
+#ifdef CONFIG_VFP
+		vfp_pm_resume();
+#endif
+		cpu_init();
+		writel(0xF0, MSM_QGIC_CPU_BASE + GIC_CPU_PRIMASK);
+		writel_relaxed(saved_gic_cpu_ctrl,
+				MSM_QGIC_CPU_BASE + GIC_CPU_CTRL);
+		mb();
+		local_fiq_enable();
+	}
+
+	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
+		pr_info("CPU%u: %s: msm_pm_collapse returned, collapsed %d\n",
+			cpu, __func__, collapsed);
+
+	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
+	WARN_ON(ret);
+	return collapsed;
+}
+
+static bool msm_pm_power_collapse_standalone(bool from_idle)
+{
+	unsigned int cpu = smp_processor_id();
+	unsigned int avsdscr_setting;
+	bool collapsed;
+
+	avsdscr_setting = avs_get_avsdscr();
+	avs_disable();
+	collapsed = msm_pm_spm_power_collapse(cpu, from_idle, false);
+	avs_reset_delays(avsdscr_setting);
+	return collapsed;
+}
+
+static bool msm_pm_power_collapse(bool from_idle)
+{
+	unsigned int cpu = smp_processor_id();
+	unsigned long saved_acpuclk_rate;
+	unsigned int avsdscr_setting;
+	bool collapsed;
+
+	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
+		pr_info("CPU%u: %s: idle %d\n",
+			cpu, __func__, (int)from_idle);
+
+	msm_pm_config_hw_before_power_down();
+	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
+		pr_info("CPU%u: %s: pre power down\n", cpu, __func__);
+
+	avsdscr_setting = avs_get_avsdscr();
+	avs_disable();
+
+	if (cpu_online(cpu))
+		saved_acpuclk_rate = acpuclk_power_collapse();
+	else
+		saved_acpuclk_rate = 0;
+
+	if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
+		pr_info("CPU%u: %s: change clock rate (old rate = %lu)\n",
+			cpu, __func__, saved_acpuclk_rate);
+
+	collapsed = msm_pm_spm_power_collapse(cpu, from_idle, true);
+
+	if (cpu_online(cpu)) {
+		if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
+			pr_info("CPU%u: %s: restore clock rate to %lu\n",
+				cpu, __func__, saved_acpuclk_rate);
+		if (acpuclk_set_rate(cpu, saved_acpuclk_rate, SETRATE_PC) < 0)
+			pr_err("CPU%u: %s: failed to restore clock rate(%lu)\n",
+				cpu, __func__, saved_acpuclk_rate);
+	} else {
+		unsigned int gic_dist_enabled;
+		unsigned int gic_dist_pending;
+		gic_dist_enabled = readl_relaxed(
+				MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_CLEAR);
+		gic_dist_pending = readl_relaxed(
+				MSM_QGIC_DIST_BASE + GIC_DIST_PENDING_SET);
+		mb();
+		gic_dist_pending &= gic_dist_enabled;
+
+		if (gic_dist_pending)
+			pr_err("CPU %d interrupted during hotplug.Pending int 0x%x\n",
+					cpu, gic_dist_pending);
+	}
+
+
+	avs_reset_delays(avsdscr_setting);
+	msm_pm_config_hw_after_power_up();
+	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
+		pr_info("CPU%u: %s: post power up\n", cpu, __func__);
+
+	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
+		pr_info("CPU%u: %s: return\n", cpu, __func__);
+	return collapsed;
+}
+
+static void msm_pm_qtimer_available(void)
+{
+	if (machine_is_copper())
+		msm_pm_use_qtimer = true;
+}
+
+static int64_t msm_pm_timer_enter_idle(void)
+{
+	if (msm_pm_use_qtimer)
+		return ktime_to_ns(tick_nohz_get_sleep_length());
+
+	return msm_timer_enter_idle();
+}
+
+static void msm_pm_timer_exit_idle(bool timer_halted)
+{
+	if (msm_pm_use_qtimer)
+		return;
+
+	msm_timer_exit_idle((int) timer_halted);
+}
+
+static int64_t msm_pm_timer_enter_suspend(int64_t *period)
+{
+	int time = 0;
+
+	if (msm_pm_use_qtimer)
+		return sched_clock();
+
+	time = msm_timer_get_sclk_time(period);
+	if (!time)
+		pr_err("%s: Unable to read sclk.\n", __func__);
+
+	return time;
+}
+
+static int64_t msm_pm_timer_exit_suspend(int64_t time, int64_t period)
+{
+	if (msm_pm_use_qtimer)
+		return sched_clock() - time;
+
+	if (time != 0) {
+		int64_t end_time = msm_timer_get_sclk_time(NULL);
+		if (end_time != 0) {
+			time = end_time - time;
+			if (time < 0)
+				time += period;
+		} else
+			time = 0;
+	}
+
+	return time;
+}
+
+/******************************************************************************
+ * External Idle/Suspend Functions
+ *****************************************************************************/
+
+void arch_idle(void)
+{
+	return;
+}
+
+int msm_pm_idle_prepare(struct cpuidle_device *dev,
+		struct cpuidle_driver *drv, int index)
+{
+	uint32_t latency_us;
+	uint32_t sleep_us;
+	int i;
+	unsigned int power_usage = -1;
+	int ret = 0;
+
+	latency_us = (uint32_t) pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
+	sleep_us = (uint32_t) ktime_to_ns(tick_nohz_get_sleep_length());
+	sleep_us = DIV_ROUND_UP(sleep_us, 1000);
+
+	for (i = 0; i < dev->state_count; i++) {
+		struct cpuidle_state *state = &drv->states[i];
+		struct cpuidle_state_usage *st_usage = &dev->states_usage[i];
+		enum msm_pm_sleep_mode mode;
+		bool allow;
+		void *rs_limits = NULL;
+		uint32_t power;
+		int idx;
+
+		mode = (enum msm_pm_sleep_mode) cpuidle_get_statedata(st_usage);
+		idx = MSM_PM_MODE(dev->cpu, mode);
+
+		allow = msm_pm_sleep_modes[idx].idle_enabled &&
+				msm_pm_sleep_modes[idx].idle_supported;
+
+		switch (mode) {
+		case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
+			if (!allow)
+				break;
+
+			if (num_online_cpus() > 1) {
+				allow = false;
+				break;
+			}
+#ifdef CONFIG_HAS_WAKELOCK
+			if (has_wake_lock(WAKE_LOCK_IDLE)) {
+				allow = false;
+				break;
+			}
+#endif
+			/* fall through */
+
+		case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
+			if (!allow)
+				break;
+			/* fall through */
+
+		case MSM_PM_SLEEP_MODE_RETENTION:
+			if (!allow)
+				break;
+			/* fall through */
+
+		case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
+			if (!allow)
+				break;
+
+			if (pm_sleep_ops.lowest_limits)
+				rs_limits = pm_sleep_ops.lowest_limits(true,
+						mode, latency_us, sleep_us,
+						&power);
+
+			if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
+				pr_info("CPU%u: %s: %s, latency %uus, "
+					"sleep %uus, limit %p\n",
+					dev->cpu, __func__, state->desc,
+					latency_us, sleep_us, rs_limits);
+
+			if (!rs_limits)
+				allow = false;
+			break;
+
+		default:
+			allow = false;
+			break;
+		}
+
+		if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
+			pr_info("CPU%u: %s: allow %s: %d\n",
+				dev->cpu, __func__, state->desc, (int)allow);
+
+		if (allow) {
+			if (power < power_usage) {
+				power_usage = power;
+				ret = mode;
+			}
+
+			if (MSM_PM_SLEEP_MODE_POWER_COLLAPSE == mode)
+				msm_pm_idle_rs_limits = rs_limits;
+		}
+	}
+
+	return ret;
+}
+
+int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode)
+{
+	int64_t time;
+	int exit_stat;
+
+	if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
+		pr_info("CPU%u: %s: mode %d\n",
+			smp_processor_id(), __func__, sleep_mode);
+
+	time = ktime_to_ns(ktime_get());
+
+	switch (sleep_mode) {
+	case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
+		msm_pm_swfi();
+		exit_stat = MSM_PM_STAT_IDLE_WFI;
+		break;
+
+	case MSM_PM_SLEEP_MODE_RETENTION:
+		msm_pm_retention();
+		exit_stat = MSM_PM_STAT_RETENTION;
+		break;
+
+	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
+		msm_pm_power_collapse_standalone(true);
+		exit_stat = MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
+		break;
+
+	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE: {
+		int64_t timer_expiration = 0;
+		bool timer_halted = false;
+		uint32_t sleep_delay;
+		int ret = -ENODEV;
+		int notify_rpm =
+			(sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE);
+		int collapsed;
+
+		timer_expiration = msm_pm_timer_enter_idle();
+
+		sleep_delay = (uint32_t) msm_pm_convert_and_cap_time(
+			timer_expiration, MSM_PM_SLEEP_TICK_LIMIT);
+		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();
+
+		if (pm_sleep_ops.enter_sleep)
+			ret = pm_sleep_ops.enter_sleep(sleep_delay,
+					msm_pm_idle_rs_limits,
+					true, notify_rpm);
+		if (!ret) {
+			collapsed = msm_pm_power_collapse(true);
+			timer_halted = true;
+
+			if (pm_sleep_ops.exit_sleep)
+				pm_sleep_ops.exit_sleep(msm_pm_idle_rs_limits,
+						true, notify_rpm, collapsed);
+		}
+		msm_pm_timer_exit_idle(timer_halted);
+		exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
+		break;
+	}
+
+	default:
+		__WARN();
+		goto cpuidle_enter_bail;
+	}
+
+	time = ktime_to_ns(ktime_get()) - time;
+	msm_pm_add_stat(exit_stat, time);
+
+	do_div(time, 1000);
+	return (int) time;
+
+cpuidle_enter_bail:
+	return 0;
+}
+
+static struct msm_pm_sleep_status_data *msm_pm_slp_sts;
+
+static DEFINE_PER_CPU_SHARED_ALIGNED(enum msm_pm_sleep_mode,
+		msm_pm_last_slp_mode);
+
+bool msm_pm_verify_cpu_pc(unsigned int cpu)
+{
+	enum msm_pm_sleep_mode mode = per_cpu(msm_pm_last_slp_mode, cpu);
+
+	if (msm_pm_slp_sts)
+		if ((mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) ||
+			(mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE))
+			return true;
+
+	return false;
+}
+
+void msm_pm_cpu_enter_lowpower(unsigned int cpu)
+{
+	int i;
+	bool allow[MSM_PM_SLEEP_MODE_NR];
+
+	for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
+		struct msm_pm_platform_data *mode;
+
+		mode = &msm_pm_sleep_modes[MSM_PM_MODE(cpu, i)];
+		allow[i] = mode->suspend_supported && mode->suspend_enabled;
+	}
+
+	if (MSM_PM_DEBUG_HOTPLUG & msm_pm_debug_mask)
+		pr_notice("CPU%u: %s: shutting down cpu\n", cpu, __func__);
+
+	if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE]) {
+		per_cpu(msm_pm_last_slp_mode, cpu)
+			= MSM_PM_SLEEP_MODE_POWER_COLLAPSE;
+		msm_pm_power_collapse(false);
+	} else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
+		per_cpu(msm_pm_last_slp_mode, cpu)
+			= MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE;
+		msm_pm_power_collapse_standalone(false);
+	} else if (allow[MSM_PM_SLEEP_MODE_RETENTION]) {
+		per_cpu(msm_pm_last_slp_mode, cpu)
+			= MSM_PM_SLEEP_MODE_RETENTION;
+		msm_pm_retention();
+	} else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
+		per_cpu(msm_pm_last_slp_mode, cpu)
+			= MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT;
+		msm_pm_swfi();
+	} else
+		per_cpu(msm_pm_last_slp_mode, cpu) = MSM_PM_SLEEP_MODE_NR;
+}
+
+int msm_pm_wait_cpu_shutdown(unsigned int cpu)
+{
+
+	int timeout = 10;
+
+	if (!msm_pm_slp_sts)
+		return 0;
+
+	while (timeout--) {
+
+		/*
+		 * Check for the SPM of the core being hotplugged to set
+		 * its sleep state.The SPM sleep state indicates that the
+		 * core has been power collapsed.
+		 */
+
+		int acc_sts = __raw_readl(msm_pm_slp_sts->base_addr
+					+ cpu * msm_pm_slp_sts->cpu_offset);
+		mb();
+
+		if (acc_sts & msm_pm_slp_sts->mask)
+			return 0;
+
+		usleep(100);
+	}
+	pr_warn("%s(): Timed out waiting for CPU %u SPM to enter sleep state",
+			__func__, cpu);
+	return -EBUSY;
+}
+
+static int msm_pm_enter(suspend_state_t state)
+{
+	bool allow[MSM_PM_SLEEP_MODE_NR];
+	int i;
+	int64_t period = 0;
+	int64_t time = msm_pm_timer_enter_suspend(&period);
+
+	if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
+		pr_info("%s\n", __func__);
+
+	if (smp_processor_id()) {
+		__WARN();
+		goto enter_exit;
+	}
+
+
+	for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
+		struct msm_pm_platform_data *mode;
+
+		mode = &msm_pm_sleep_modes[MSM_PM_MODE(0, i)];
+		allow[i] = mode->suspend_supported && mode->suspend_enabled;
+	}
+
+	if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE]) {
+		void *rs_limits = NULL;
+		int ret = -ENODEV;
+		uint32_t power;
+
+		if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
+			pr_info("%s: power collapse\n", __func__);
+
+		clock_debug_print_enabled();
+
+#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE
+		if (msm_pm_sleep_time_override > 0) {
+			int64_t ns = NSEC_PER_SEC *
+				(int64_t) msm_pm_sleep_time_override;
+			msm_pm_set_max_sleep_time(ns);
+			msm_pm_sleep_time_override = 0;
+		}
+#endif /* CONFIG_MSM_SLEEP_TIME_OVERRIDE */
+		if (pm_sleep_ops.lowest_limits)
+			rs_limits = pm_sleep_ops.lowest_limits(false,
+					MSM_PM_SLEEP_MODE_POWER_COLLAPSE, -1,
+					-1, &power);
+
+		if (rs_limits) {
+			if (pm_sleep_ops.enter_sleep)
+				ret = pm_sleep_ops.enter_sleep(
+						msm_pm_max_sleep_time,
+						rs_limits, false, true);
+			if (!ret) {
+				int collapsed = msm_pm_power_collapse(false);
+				if (pm_sleep_ops.exit_sleep) {
+					pm_sleep_ops.exit_sleep(rs_limits,
+						false, true, collapsed);
+				}
+			}
+		} else {
+			pr_err("%s: cannot find the lowest power limit\n",
+				__func__);
+		}
+		time = msm_pm_timer_exit_suspend(time, period);
+		msm_pm_add_stat(MSM_PM_STAT_SUSPEND, time);
+	} else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
+		if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
+			pr_info("%s: standalone power collapse\n", __func__);
+		msm_pm_power_collapse_standalone(false);
+	} else if (allow[MSM_PM_SLEEP_MODE_RETENTION]) {
+		if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
+			pr_info("%s: retention\n", __func__);
+		msm_pm_retention();
+	} else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
+		if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
+			pr_info("%s: swfi\n", __func__);
+		msm_pm_swfi();
+	}
+
+
+enter_exit:
+	if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
+		pr_info("%s: return\n", __func__);
+
+	return 0;
+}
+
+static struct platform_suspend_ops msm_pm_ops = {
+	.enter = msm_pm_enter,
+	.valid = suspend_valid_only_mem,
+};
+
+/******************************************************************************
+ * Initialization routine
+ *****************************************************************************/
+void __init msm_pm_init_sleep_status_data(
+		struct msm_pm_sleep_status_data *data)
+{
+	msm_pm_slp_sts = data;
+}
+
+void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops)
+{
+	if (ops)
+		pm_sleep_ops = *ops;
+}
+
+static int __init msm_pm_init(void)
+{
+	pgd_t *pc_pgd;
+	pmd_t *pmd;
+	unsigned long pmdval;
+	enum msm_pm_time_stats_id enable_stats[] = {
+		MSM_PM_STAT_IDLE_WFI,
+		MSM_PM_STAT_RETENTION,
+		MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
+		MSM_PM_STAT_IDLE_POWER_COLLAPSE,
+		MSM_PM_STAT_SUSPEND,
+	};
+	unsigned long exit_phys;
+
+	/* Page table for cores to come back up safely. */
+	pc_pgd = pgd_alloc(&init_mm);
+	if (!pc_pgd)
+		return -ENOMEM;
+
+	exit_phys = virt_to_phys(msm_pm_collapse_exit);
+
+	pmd = pmd_offset(pud_offset(pc_pgd + pgd_index(exit_phys),exit_phys),
+					exit_phys);
+	pmdval = (exit_phys & PGDIR_MASK) |
+		     PMD_TYPE_SECT | PMD_SECT_AP_WRITE;
+	pmd[0] = __pmd(pmdval);
+	pmd[1] = __pmd(pmdval + (1 << (PGDIR_SHIFT - 1)));
+
+	msm_saved_state_phys =
+		allocate_contiguous_ebi_nomap(CPU_SAVED_STATE_SIZE *
+					      num_possible_cpus(), 4);
+	if (!msm_saved_state_phys)
+		return -ENOMEM;
+	msm_saved_state = ioremap_nocache(msm_saved_state_phys,
+					  CPU_SAVED_STATE_SIZE *
+					  num_possible_cpus());
+	if (!msm_saved_state)
+		return -ENOMEM;
+
+	/* It is remotely possible that the code in msm_pm_collapse_exit()
+	 * which turns on the MMU with this mapping is in the
+	 * next even-numbered megabyte beyond the
+	 * start of msm_pm_collapse_exit().
+	 * Map this megabyte in as well.
+	 */
+	pmd[2] = __pmd(pmdval + (2 << (PGDIR_SHIFT - 1)));
+	flush_pmd_entry(pmd);
+	msm_pm_pc_pgd = virt_to_phys(pc_pgd);
+	clean_caches((unsigned long)&msm_pm_pc_pgd, sizeof(msm_pm_pc_pgd),
+		     virt_to_phys(&msm_pm_pc_pgd));
+
+	msm_pm_mode_sysfs_add();
+	msm_pm_add_stats(enable_stats, ARRAY_SIZE(enable_stats));
+
+	msm_spm_allow_x_cpu_set_vdd(false);
+
+	suspend_set_ops(&msm_pm_ops);
+	msm_pm_qtimer_available();
+	msm_cpuidle_init();
+
+	return 0;
+}
+
+late_initcall(msm_pm_init);
diff --git a/arch/arm/mach-msm/pm-boot.c b/arch/arm/mach-msm/pm-boot.c
new file mode 100644
index 0000000..f6105af1
--- /dev/null
+++ b/arch/arm/mach-msm/pm-boot.c
@@ -0,0 +1,272 @@
+/* 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
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <mach/msm_iomap.h>
+#include <mach/socinfo.h>
+#include <asm/mach-types.h>
+#include <asm/sizes.h>
+#include "scm-boot.h"
+#include "idle.h"
+#include "pm-boot.h"
+
+static uint32_t *msm_pm_reset_vector;
+static uint32_t saved_vector[2];
+static void (*msm_pm_boot_before_pc)(unsigned int cpu, unsigned long entry);
+static void (*msm_pm_boot_after_pc)(unsigned int cpu);
+
+static void msm_pm_write_boot_vector(unsigned int cpu, unsigned long address)
+{
+	msm_pm_boot_vector[cpu] = address;
+	clean_caches((unsigned long)&msm_pm_boot_vector[cpu],
+		     sizeof(msm_pm_boot_vector[cpu]),
+		     virt_to_phys(&msm_pm_boot_vector[cpu]));
+}
+
+#ifdef CONFIG_MSM_SCM
+static int __init msm_pm_tz_boot_init(void)
+{
+	int flag = 0;
+	if (num_possible_cpus() == 1)
+		flag = SCM_FLAG_WARMBOOT_CPU0;
+	else if (num_possible_cpus() == 2)
+		flag = SCM_FLAG_WARMBOOT_CPU0 | SCM_FLAG_WARMBOOT_CPU1;
+	else if (num_possible_cpus() == 4)
+		flag = SCM_FLAG_WARMBOOT_CPU0 | SCM_FLAG_WARMBOOT_CPU1 |
+				SCM_FLAG_WARMBOOT_CPU2 | SCM_FLAG_WARMBOOT_CPU3;
+	else
+		__WARN();
+
+	return scm_set_boot_addr((void *)virt_to_phys(msm_pm_boot_entry), flag);
+}
+
+static void msm_pm_config_tz_before_pc(unsigned int cpu,
+		unsigned long entry)
+{
+	msm_pm_write_boot_vector(cpu, entry);
+}
+#else
+static int __init msm_pm_tz_boot_init(void)
+{
+	return 0;
+};
+
+static inline void msm_pm_config_tz_before_pc(unsigned int cpu,
+		unsigned long entry) {}
+#endif
+
+static int __init msm_pm_boot_reset_vector_init(uint32_t *reset_vector)
+{
+	if (!reset_vector)
+		return -ENODEV;
+	msm_pm_reset_vector = reset_vector;
+	mb();
+
+	return 0;
+}
+
+static void msm_pm_config_rst_vector_before_pc(unsigned int cpu,
+		unsigned long entry)
+{
+	saved_vector[0] = msm_pm_reset_vector[0];
+	saved_vector[1] = msm_pm_reset_vector[1];
+	msm_pm_reset_vector[0] = 0xE51FF004; /* ldr pc, 4 */
+	msm_pm_reset_vector[1] = entry;
+}
+
+static void msm_pm_config_rst_vector_after_pc(unsigned int cpu)
+{
+	msm_pm_reset_vector[0] = saved_vector[0];
+	msm_pm_reset_vector[1] = saved_vector[1];
+}
+
+void msm_pm_boot_config_before_pc(unsigned int cpu, unsigned long entry)
+{
+	if (msm_pm_boot_before_pc)
+		msm_pm_boot_before_pc(cpu, entry);
+}
+
+void msm_pm_boot_config_after_pc(unsigned int cpu)
+{
+	if (msm_pm_boot_after_pc)
+		msm_pm_boot_after_pc(cpu);
+}
+#define BOOT_REMAP_ENABLE  BIT(0)
+
+int __init msm_pm_boot_init(struct msm_pm_boot_platform_data *pdata)
+{
+	int ret = 0;
+	unsigned long entry;
+	void __iomem *warm_boot_ptr;
+
+	switch (pdata->mode) {
+	case MSM_PM_BOOT_CONFIG_TZ:
+		ret = msm_pm_tz_boot_init();
+		msm_pm_boot_before_pc = msm_pm_config_tz_before_pc;
+		msm_pm_boot_after_pc = NULL;
+		break;
+	case MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS:
+		pdata->v_addr = ioremap(pdata->p_addr, PAGE_SIZE);
+		/* Fall through */
+	case MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT:
+
+		if (!pdata->v_addr)
+			return -ENODEV;
+
+		ret = msm_pm_boot_reset_vector_init(pdata->v_addr);
+		msm_pm_boot_before_pc
+			= msm_pm_config_rst_vector_before_pc;
+		msm_pm_boot_after_pc
+			= msm_pm_config_rst_vector_after_pc;
+		break;
+	case MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR:
+		if (!cpu_is_msm8625()) {
+			void *remapped;
+
+			/*
+			 * Set the boot remap address and enable remapping of
+			 * reset vector
+			 */
+			if (!pdata->p_addr || !pdata->v_addr)
+				return -ENODEV;
+
+			remapped = ioremap_nocache(pdata->p_addr, SZ_8);
+			ret = msm_pm_boot_reset_vector_init(remapped);
+
+			__raw_writel((pdata->p_addr | BOOT_REMAP_ENABLE),
+					pdata->v_addr);
+
+			msm_pm_boot_before_pc
+				= msm_pm_config_rst_vector_before_pc;
+			msm_pm_boot_after_pc
+				= msm_pm_config_rst_vector_after_pc;
+		} else {
+			warm_boot_ptr = ioremap_nocache(
+						MSM8625_WARM_BOOT_PHYS, SZ_64);
+			ret = msm_pm_boot_reset_vector_init(warm_boot_ptr);
+
+			entry = virt_to_phys(msm_pm_boot_entry);
+
+			/* Below sequence is a work around for cores
+			 * to come out of GDFS properly on 8625 target.
+			 * On 8625 while cores coming out of GDFS observed
+			 * the memory corruption at very first memory read.
+			 */
+			msm_pm_reset_vector[0] = 0xE59F000C; /* ldr r0, 0x14 */
+			msm_pm_reset_vector[1] = 0xE59F1008; /* ldr r1, 0x14 */
+			msm_pm_reset_vector[2] = 0xE1500001; /* cmp r0, r1 */
+			msm_pm_reset_vector[3] = 0x1AFFFFFB; /* bne 0x0 */
+			msm_pm_reset_vector[4] = 0xE12FFF10; /* bx  r0 */
+			msm_pm_reset_vector[5] = entry; /* 0x14 */
+
+			/* Here upper 16bits[16:31] used by CORE1
+			 * lower 16bits[0:15] used by CORE0
+			 */
+			entry = (MSM8625_WARM_BOOT_PHYS |
+				((MSM8625_WARM_BOOT_PHYS & 0xFFFF0000) >> 16));
+
+			/* write 'entry' to boot remapper register */
+			__raw_writel(entry, (pdata->v_addr +
+						MPA5_BOOT_REMAP_ADDR));
+
+			/* Enable boot remapper for C0 [bit:25th] */
+			__raw_writel(readl_relaxed(pdata->v_addr +
+					MPA5_CFG_CTL_REG) | BIT(25),
+					pdata->v_addr + MPA5_CFG_CTL_REG);
+
+			/* Enable boot remapper for C1 [bit:26th] */
+			__raw_writel(readl_relaxed(pdata->v_addr +
+					MPA5_CFG_CTL_REG) | BIT(26),
+					pdata->v_addr + MPA5_CFG_CTL_REG);
+			msm_pm_boot_before_pc = msm_pm_write_boot_vector;
+		}
+		break;
+	default:
+		__WARN();
+	}
+
+	return ret;
+}
+
+static int __devinit msm_pm_boot_probe(struct platform_device *pdev)
+{
+	struct msm_pm_boot_platform_data pdata;
+	char *key = NULL;
+	uint32_t val = 0;
+	int ret = 0;
+	int flag = 0;
+
+	key = "qcom,mode";
+	ret = of_property_read_u32(pdev->dev.of_node, key, &val);
+	if (ret) {
+		pr_err("Unable to read boot mode Err(%d).\n", ret);
+		return -ENODEV;
+	}
+	pdata.mode = val;
+
+	key = "qcom,phy-addr";
+	ret = of_property_read_u32(pdev->dev.of_node, key, &val);
+	if (ret && pdata.mode == MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS)
+		goto fail;
+	if (!ret) {
+		pdata.p_addr = val;
+		flag++;
+	}
+
+	key = "qcom,virt-addr";
+	ret = of_property_read_u32(pdev->dev.of_node, key, &val);
+	if (ret && pdata.mode == MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT)
+		goto fail;
+	if (!ret) {
+		pdata.v_addr = (void *)val;
+		flag++;
+	}
+
+	if (pdata.mode == MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR && (flag != 2)) {
+		key = "addresses for boot remap";
+		goto fail;
+	}
+
+	return msm_pm_boot_init(&pdata);
+
+fail:
+	pr_err("Error reading %s\n", key);
+	return -EFAULT;
+}
+
+static struct of_device_id msm_pm_match_table[] = {
+	{.compatible = "qcom,pm-boot"},
+	{},
+};
+
+static struct platform_driver msm_pm_boot_driver = {
+	.probe = msm_pm_boot_probe,
+	.driver = {
+		.name = "pm-boot",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_pm_match_table,
+	},
+};
+
+static int __init msm_pm_boot_module_init(void)
+{
+	return platform_driver_register(&msm_pm_boot_driver);
+}
+module_init(msm_pm_boot_module_init);
diff --git a/arch/arm/mach-msm/pm-boot.h b/arch/arm/mach-msm/pm-boot.h
new file mode 100644
index 0000000..30b67c21
--- /dev/null
+++ b/arch/arm/mach-msm/pm-boot.h
@@ -0,0 +1,47 @@
+/* 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
+ * 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 _ARCH_ARM_MACH_MSM_PM_BOOT_H
+#define _ARCH_ARM_MACH_MSM_PM_BOOT_H
+
+/* 8x25 specific macros */
+#define MPA5_CFG_CTL_REG	0x30
+#define MPA5_BOOT_REMAP_ADDR	0x34
+/* end */
+
+enum {
+	MSM_PM_BOOT_CONFIG_TZ		     = 0,
+	MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS = 1,
+	MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT = 2,
+	MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR   = 3,
+};
+
+struct msm_pm_boot_platform_data {
+	int mode;
+	phys_addr_t  p_addr;
+	void __iomem *v_addr;
+};
+
+#ifdef CONFIG_PM
+int __init msm_pm_boot_init(struct msm_pm_boot_platform_data *pdata);
+#else
+static inline int __init msm_pm_boot_init(
+		struct msm_pm_boot_platform_data *pdata)
+{
+	return 0;
+}
+#endif
+
+void msm_pm_boot_config_before_pc(unsigned int cpu, unsigned long entry);
+void msm_pm_boot_config_after_pc(unsigned int cpu);
+
+#endif
diff --git a/arch/arm/mach-msm/pm-data.c b/arch/arm/mach-msm/pm-data.c
new file mode 100644
index 0000000..6f4743f
--- /dev/null
+++ b/arch/arm/mach-msm/pm-data.c
@@ -0,0 +1,128 @@
+/* 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 "pm.h"
+
+struct msm_pm_platform_data msm_pm_sleep_modes[] = {
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = {
+		.idle_supported = 1,
+		.suspend_supported = 1,
+		.idle_enabled = 0,
+		.suspend_enabled = 0,
+	},
+
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = {
+		.idle_supported = 1,
+		.suspend_supported = 1,
+		.idle_enabled = 0,
+		.suspend_enabled = 0,
+	},
+
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_RETENTION)] = {
+		.idle_supported = 1,
+		.suspend_supported = 1,
+		.idle_enabled = 0,
+		.suspend_enabled = 0,
+	},
+
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
+		.idle_supported = 1,
+		.suspend_supported = 1,
+		.idle_enabled = 1,
+		.suspend_enabled = 1,
+	},
+
+	[MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = {
+		.idle_supported = 0,
+		.suspend_supported = 1,
+		.idle_enabled = 0,
+		.suspend_enabled = 0,
+	},
+
+	[MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = {
+		.idle_supported = 1,
+		.suspend_supported = 1,
+		.idle_enabled = 0,
+		.suspend_enabled = 0,
+	},
+
+	[MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_RETENTION)] = {
+		.idle_supported = 1,
+		.suspend_supported = 1,
+		.idle_enabled = 0,
+		.suspend_enabled = 0,
+	},
+
+	[MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
+		.idle_supported = 1,
+		.suspend_supported = 0,
+		.idle_enabled = 1,
+		.suspend_enabled = 0,
+	},
+
+	[MSM_PM_MODE(2, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = {
+		.idle_supported = 0,
+		.suspend_supported = 1,
+		.idle_enabled = 0,
+		.suspend_enabled = 0,
+	},
+
+	[MSM_PM_MODE(2, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = {
+		.idle_supported = 1,
+		.suspend_supported = 1,
+		.idle_enabled = 0,
+		.suspend_enabled = 0,
+	},
+
+	[MSM_PM_MODE(2, MSM_PM_SLEEP_MODE_RETENTION)] = {
+		.idle_supported = 1,
+		.suspend_supported = 1,
+		.idle_enabled = 0,
+		.suspend_enabled = 0,
+	},
+
+	[MSM_PM_MODE(2, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
+		.idle_supported = 1,
+		.suspend_supported = 0,
+		.idle_enabled = 1,
+		.suspend_enabled = 0,
+	},
+
+	[MSM_PM_MODE(3, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = {
+		.idle_supported = 0,
+		.suspend_supported = 1,
+		.idle_enabled = 0,
+		.suspend_enabled = 0,
+	},
+
+	[MSM_PM_MODE(3, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = {
+		.idle_supported = 1,
+		.suspend_supported = 1,
+		.idle_enabled = 0,
+		.suspend_enabled = 0,
+	},
+
+	[MSM_PM_MODE(3, MSM_PM_SLEEP_MODE_RETENTION)] = {
+		.idle_supported = 1,
+		.suspend_supported = 1,
+		.idle_enabled = 0,
+		.suspend_enabled = 0,
+	},
+
+	[MSM_PM_MODE(3, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
+		.idle_supported = 1,
+		.suspend_supported = 0,
+		.idle_enabled = 1,
+		.suspend_enabled = 0,
+	},
+};
diff --git a/arch/arm/mach-msm/pm-stats.c b/arch/arm/mach-msm/pm-stats.c
new file mode 100644
index 0000000..936820a
--- /dev/null
+++ b/arch/arm/mach-msm/pm-stats.c
@@ -0,0 +1,305 @@
+/* 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/proc_fs.h>
+
+#include "pm.h"
+
+struct msm_pm_time_stats {
+	const char *name;
+	int64_t first_bucket_time;
+	int bucket[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
+	int64_t min_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
+	int64_t max_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
+	int count;
+	int64_t total_time;
+	bool enabled;
+};
+
+struct msm_pm_cpu_time_stats {
+	struct msm_pm_time_stats stats[MSM_PM_STAT_COUNT];
+};
+
+static DEFINE_SPINLOCK(msm_pm_stats_lock);
+static DEFINE_PER_CPU_SHARED_ALIGNED(
+	struct msm_pm_cpu_time_stats, msm_pm_stats);
+
+/*
+ * Add the given time data to the statistics collection.
+ */
+void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t)
+{
+	unsigned long flags;
+	struct msm_pm_time_stats *stats;
+	int64_t bt;
+	int i;
+
+	spin_lock_irqsave(&msm_pm_stats_lock, flags);
+	stats = __get_cpu_var(msm_pm_stats).stats;
+
+	if (!stats[id].enabled)
+		goto add_bail;
+
+	stats[id].total_time += t;
+	stats[id].count++;
+
+	bt = t;
+	do_div(bt, stats[id].first_bucket_time);
+
+	if (bt < 1ULL << (CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT *
+				(CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1)))
+		i = DIV_ROUND_UP(fls((uint32_t)bt),
+					CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT);
+	else
+		i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
+
+	if (i >= CONFIG_MSM_IDLE_STATS_BUCKET_COUNT)
+		i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
+
+	stats[id].bucket[i]++;
+
+	if (t < stats[id].min_time[i] || !stats[id].max_time[i])
+		stats[id].min_time[i] = t;
+	if (t > stats[id].max_time[i])
+		stats[id].max_time[i] = t;
+
+add_bail:
+	spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
+}
+
+/*
+ * Helper function of snprintf where buf is auto-incremented, size is auto-
+ * decremented, and there is no return value.
+ *
+ * NOTE: buf and size must be l-values (e.g. variables)
+ */
+#define SNPRINTF(buf, size, format, ...) \
+	do { \
+		if (size > 0) { \
+			int ret; \
+			ret = snprintf(buf, size, format, ## __VA_ARGS__); \
+			if (ret > size) { \
+				buf += size; \
+				size = 0; \
+			} else { \
+				buf += ret; \
+				size -= ret; \
+			} \
+		} \
+	} while (0)
+
+/*
+ * Write out the power management statistics.
+ */
+static int msm_pm_read_proc
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	unsigned int cpu = off / MSM_PM_STAT_COUNT;
+	int id = off % MSM_PM_STAT_COUNT;
+	char *p = page;
+
+	if (count < 1024) {
+		*start = (char *) 0;
+		*eof = 0;
+		return 0;
+	}
+
+	if (cpu < num_possible_cpus()) {
+		unsigned long flags;
+		struct msm_pm_time_stats *stats;
+		int i;
+		int64_t bucket_time;
+		int64_t s;
+		uint32_t ns;
+
+		spin_lock_irqsave(&msm_pm_stats_lock, flags);
+		stats = per_cpu(msm_pm_stats, cpu).stats;
+
+		/* Skip the disabled ones */
+		if (!stats[id].enabled) {
+			*p = '\0';
+			p++;
+			goto again;
+		}
+
+		s = stats[id].total_time;
+		ns = do_div(s, NSEC_PER_SEC);
+		SNPRINTF(p, count,
+			"[cpu %u] %s:\n"
+			"  count: %7d\n"
+			"  total_time: %lld.%09u\n",
+			cpu, stats[id].name,
+			stats[id].count,
+			s, ns);
+
+		bucket_time = stats[id].first_bucket_time;
+		for (i = 0; i < CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1; i++) {
+			s = bucket_time;
+			ns = do_div(s, NSEC_PER_SEC);
+			SNPRINTF(p, count,
+				"   <%6lld.%09u: %7d (%lld-%lld)\n",
+				s, ns, stats[id].bucket[i],
+				stats[id].min_time[i],
+				stats[id].max_time[i]);
+
+			bucket_time <<= CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT;
+		}
+
+		SNPRINTF(p, count, "  >=%6lld.%09u: %7d (%lld-%lld)\n",
+			s, ns, stats[id].bucket[i],
+			stats[id].min_time[i],
+			stats[id].max_time[i]);
+
+again:
+		*start = (char *) 1;
+		*eof = (off + 1 >= MSM_PM_STAT_COUNT * num_possible_cpus());
+
+		spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
+	}
+
+	return p - page;
+}
+#undef SNPRINTF
+
+#define MSM_PM_STATS_RESET "reset"
+
+/*
+ * Reset the power management statistics values.
+ */
+static int msm_pm_write_proc(struct file *file, const char __user *buffer,
+	unsigned long count, void *data)
+{
+	char buf[sizeof(MSM_PM_STATS_RESET)];
+	int ret;
+	unsigned long flags;
+	unsigned int cpu;
+
+	if (count < sizeof(MSM_PM_STATS_RESET)) {
+		ret = -EINVAL;
+		goto write_proc_failed;
+	}
+
+	if (copy_from_user(buf, buffer, sizeof(MSM_PM_STATS_RESET))) {
+		ret = -EFAULT;
+		goto write_proc_failed;
+	}
+
+	if (memcmp(buf, MSM_PM_STATS_RESET, sizeof(MSM_PM_STATS_RESET))) {
+		ret = -EINVAL;
+		goto write_proc_failed;
+	}
+
+	spin_lock_irqsave(&msm_pm_stats_lock, flags);
+	for_each_possible_cpu(cpu) {
+		struct msm_pm_time_stats *stats;
+		int i;
+
+		stats = per_cpu(msm_pm_stats, cpu).stats;
+		for (i = 0; i < MSM_PM_STAT_COUNT; i++) {
+			memset(stats[i].bucket,
+				0, sizeof(stats[i].bucket));
+			memset(stats[i].min_time,
+				0, sizeof(stats[i].min_time));
+			memset(stats[i].max_time,
+				0, sizeof(stats[i].max_time));
+			stats[i].count = 0;
+			stats[i].total_time = 0;
+		}
+	}
+
+	spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
+	return count;
+
+write_proc_failed:
+	return ret;
+}
+#undef MSM_PM_STATS_RESET
+
+void msm_pm_add_stats(enum msm_pm_time_stats_id *enable_stats, int size)
+{
+	unsigned int cpu;
+	struct proc_dir_entry *d_entry;
+	int i = 0;
+
+	for_each_possible_cpu(cpu) {
+		struct msm_pm_time_stats *stats =
+			per_cpu(msm_pm_stats, cpu).stats;
+
+		stats[MSM_PM_STAT_REQUESTED_IDLE].name = "idle-request";
+		stats[MSM_PM_STAT_REQUESTED_IDLE].first_bucket_time =
+			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+		stats[MSM_PM_STAT_IDLE_SPIN].name = "idle-spin";
+		stats[MSM_PM_STAT_IDLE_SPIN].first_bucket_time =
+			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+		stats[MSM_PM_STAT_IDLE_WFI].name = "idle-wfi";
+		stats[MSM_PM_STAT_IDLE_WFI].first_bucket_time =
+			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+		stats[MSM_PM_STAT_RETENTION].name = "retention";
+		stats[MSM_PM_STAT_RETENTION].first_bucket_time =
+			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+		stats[MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].name =
+			"idle-standalone-power-collapse";
+		stats[MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].
+			first_bucket_time = CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+		stats[MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE].name =
+			"idle-failed-standalone-power-collapse";
+		stats[MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE].
+			first_bucket_time =
+			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+		stats[MSM_PM_STAT_IDLE_POWER_COLLAPSE].name =
+			"idle-power-collapse";
+		stats[MSM_PM_STAT_IDLE_POWER_COLLAPSE].first_bucket_time =
+			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+		stats[MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].name =
+			"idle-failed-power-collapse";
+		stats[MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].
+			first_bucket_time =
+			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+		stats[MSM_PM_STAT_SUSPEND].name = "suspend";
+		stats[MSM_PM_STAT_SUSPEND].first_bucket_time =
+			CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET;
+
+		stats[MSM_PM_STAT_FAILED_SUSPEND].name = "failed-suspend";
+		stats[MSM_PM_STAT_FAILED_SUSPEND].first_bucket_time =
+			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+		stats[MSM_PM_STAT_NOT_IDLE].name = "not-idle";
+		stats[MSM_PM_STAT_NOT_IDLE].first_bucket_time =
+			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+		for (i = 0; i < size; i++)
+			stats[enable_stats[i]].enabled = true;
+
+	}
+
+	d_entry = create_proc_entry("msm_pm_stats",
+			S_IRUGO | S_IWUSR | S_IWGRP, NULL);
+	if (d_entry) {
+		d_entry->read_proc = msm_pm_read_proc;
+		d_entry->write_proc = msm_pm_write_proc;
+		d_entry->data = NULL;
+	}
+}
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
new file mode 100644
index 0000000..70d54da
--- /dev/null
+++ b/arch/arm/mach-msm/pm.h
@@ -0,0 +1,141 @@
+/* arch/arm/mach-msm/pm.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+ * Author: San Mehat <san@android.com>
+ *
+ * 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 __ARCH_ARM_MACH_MSM_PM_H
+#define __ARCH_ARM_MACH_MSM_PM_H
+
+#include <linux/types.h>
+#include <linux/cpuidle.h>
+
+#ifdef CONFIG_SMP
+extern void msm_secondary_startup(void);
+#else
+#define msm_secondary_startup NULL
+#endif
+
+extern int power_collapsed;
+
+struct msm_pm_irq_calls {
+	unsigned int (*irq_pending)(void);
+	int (*idle_sleep_allowed)(void);
+	void (*enter_sleep1)(bool modem_wake, int from_idle, uint32_t
+								*irq_mask);
+	int (*enter_sleep2)(bool modem_wake, int from_idle);
+	void (*exit_sleep1)(uint32_t irq_mask, uint32_t wakeup_reason,
+							uint32_t pending_irqs);
+	void (*exit_sleep2)(uint32_t irq_mask, uint32_t wakeup_reason,
+							uint32_t pending_irqs);
+	void (*exit_sleep3)(uint32_t irq_mask, uint32_t wakeup_reason,
+							uint32_t pending_irqs);
+};
+
+enum msm_pm_sleep_mode {
+	MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT = 0,
+	MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT = 1,
+	MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE = 2,
+	MSM_PM_SLEEP_MODE_POWER_COLLAPSE = 3,
+	MSM_PM_SLEEP_MODE_APPS_SLEEP = 4,
+	MSM_PM_SLEEP_MODE_RETENTION = MSM_PM_SLEEP_MODE_APPS_SLEEP,
+	MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND = 5,
+	MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN = 6,
+	MSM_PM_SLEEP_MODE_NR
+};
+
+#define MSM_PM_MODE(cpu, mode_nr)  ((cpu) * MSM_PM_SLEEP_MODE_NR + (mode_nr))
+
+struct msm_pm_platform_data {
+	u8 idle_supported;   /* Allow device to enter mode during idle */
+	u8 suspend_supported; /* Allow device to enter mode during suspend */
+	u8 suspend_enabled;  /* enabled for suspend */
+	u8 idle_enabled;     /* enabled for idle low power */
+	u32 latency;         /* interrupt latency in microseconds when entering
+				and exiting the low power mode */
+	u32 residency;       /* time threshold in microseconds beyond which
+				staying in the low power mode saves power */
+};
+
+extern struct msm_pm_platform_data msm_pm_sleep_modes[];
+
+struct msm_pm_sleep_status_data {
+	void *base_addr;
+	uint32_t cpu_offset;
+	uint32_t mask;
+};
+
+struct msm_pm_sleep_ops {
+	void *(*lowest_limits)(bool from_idle,
+			enum msm_pm_sleep_mode sleep_mode, uint32_t latency_us,
+			uint32_t sleep_us, uint32_t *power);
+	int (*enter_sleep)(uint32_t sclk_count, void *limits,
+			bool from_idle, bool notify_rpm);
+	void (*exit_sleep)(void *limits, bool from_idle,
+			bool notify_rpm, bool collapsed);
+};
+
+void msm_pm_set_platform_data(struct msm_pm_platform_data *data, int count);
+int msm_pm_idle_prepare(struct cpuidle_device *dev,
+			struct cpuidle_driver *drv, int index);
+void msm_pm_set_irq_extns(struct msm_pm_irq_calls *irq_calls);
+int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode);
+void msm_pm_cpu_enter_lowpower(unsigned int cpu);
+
+void __init msm_pm_init_sleep_status_data(
+		struct msm_pm_sleep_status_data *sleep_data);
+
+
+#ifdef CONFIG_MSM_PM8X60
+void msm_pm_set_rpm_wakeup_irq(unsigned int irq);
+int msm_pm_wait_cpu_shutdown(unsigned int cpu);
+bool msm_pm_verify_cpu_pc(unsigned int cpu);
+void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops);
+#else
+static inline void msm_pm_set_rpm_wakeup_irq(unsigned int irq) {}
+static inline int msm_pm_wait_cpu_shutdown(unsigned int cpu) { return 0; }
+static inline bool msm_pm_verify_cpu_pc(unsigned int cpu) { return true; }
+static inline void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops) {}
+#endif
+#ifdef CONFIG_HOTPLUG_CPU
+int msm_platform_secondary_init(unsigned int cpu);
+#else
+static inline int msm_platform_secondary_init(unsigned int cpu) { return 0; }
+#endif
+
+enum msm_pm_time_stats_id {
+	MSM_PM_STAT_REQUESTED_IDLE = 0,
+	MSM_PM_STAT_IDLE_SPIN,
+	MSM_PM_STAT_IDLE_WFI,
+	MSM_PM_STAT_RETENTION,
+	MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
+	MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE,
+	MSM_PM_STAT_IDLE_POWER_COLLAPSE,
+	MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE,
+	MSM_PM_STAT_SUSPEND,
+	MSM_PM_STAT_FAILED_SUSPEND,
+	MSM_PM_STAT_NOT_IDLE,
+	MSM_PM_STAT_COUNT
+};
+
+#ifdef CONFIG_MSM_IDLE_STATS
+void msm_pm_add_stats(enum msm_pm_time_stats_id *enable_stats, int size);
+void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t);
+#else
+static inline void msm_pm_add_stats(enum msm_pm_time_stats_id *enable_stats,
+		int size) {}
+static inline void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t) {}
+#endif
+
+#endif  /* __ARCH_ARM_MACH_MSM_PM_H */
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
new file mode 100644
index 0000000..bac6ef8
--- /dev/null
+++ b/arch/arm/mach-msm/pm2.c
@@ -0,0 +1,1756 @@
+/* arch/arm/mach-msm/pm2.c
+ *
+ * MSM Power Management Routines
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008-2012 Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/pm_qos.h>
+#include <linux/suspend.h>
+#include <linux/reboot.h>
+#include <linux/io.h>
+#include <linux/tick.h>
+#include <linux/memory.h>
+#ifdef CONFIG_HAS_WAKELOCK
+#include <linux/wakelock.h>
+#endif
+#include <mach/msm_iomap.h>
+#include <mach/system.h>
+#ifdef CONFIG_CPU_V7
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#endif
+#include <asm/system_misc.h>
+#ifdef CONFIG_CACHE_L2X0
+#include <asm/hardware/cache-l2x0.h>
+#endif
+#ifdef CONFIG_VFP
+#include <asm/vfp.h>
+#endif
+
+#ifdef CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_DEEP_POWER_DOWN
+#include <mach/msm_migrate_pages.h>
+#endif
+#include <mach/socinfo.h>
+#include <mach/proc_comm.h>
+#include <asm/smp_scu.h>
+
+#include "smd_private.h"
+#include "smd_rpcrouter.h"
+#include "acpuclock.h"
+#include "clock.h"
+#include "idle.h"
+#include "irq.h"
+#include "gpio.h"
+#include "timer.h"
+#include "pm.h"
+#include "spm.h"
+#include "sirc.h"
+#include "pm-boot.h"
+#include "devices-msm7x2xa.h"
+
+/******************************************************************************
+ * Debug Definitions
+ *****************************************************************************/
+
+enum {
+	MSM_PM_DEBUG_SUSPEND = BIT(0),
+	MSM_PM_DEBUG_POWER_COLLAPSE = BIT(1),
+	MSM_PM_DEBUG_STATE = BIT(2),
+	MSM_PM_DEBUG_CLOCK = BIT(3),
+	MSM_PM_DEBUG_RESET_VECTOR = BIT(4),
+	MSM_PM_DEBUG_SMSM_STATE = BIT(5),
+	MSM_PM_DEBUG_IDLE = BIT(6),
+	MSM_PM_DEBUG_HOTPLUG = BIT(7),
+};
+
+static int msm_pm_debug_mask;
+int power_collapsed;
+module_param_named(
+	debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
+);
+
+#define MSM_PM_DPRINTK(mask, level, message, ...) \
+	do { \
+		if ((mask) & msm_pm_debug_mask) \
+			printk(level message, ## __VA_ARGS__); \
+	} while (0)
+
+#define MSM_PM_DEBUG_PRINT_STATE(tag) \
+	do { \
+		MSM_PM_DPRINTK(MSM_PM_DEBUG_STATE, \
+			KERN_INFO, "%s: " \
+			"APPS_CLK_SLEEP_EN %x, APPS_PWRDOWN %x, " \
+			"SMSM_POWER_MASTER_DEM %x, SMSM_MODEM_STATE %x, " \
+			"SMSM_APPS_DEM %x\n", \
+			tag, \
+			__raw_readl(APPS_CLK_SLEEP_EN), \
+			__raw_readl(APPS_PWRDOWN), \
+			smsm_get_state(SMSM_POWER_MASTER_DEM), \
+			smsm_get_state(SMSM_MODEM_STATE), \
+			smsm_get_state(SMSM_APPS_DEM)); \
+	} while (0)
+
+#define MSM_PM_DEBUG_PRINT_SLEEP_INFO() \
+	do { \
+		if (msm_pm_debug_mask & MSM_PM_DEBUG_SMSM_STATE) \
+			smsm_print_sleep_info(msm_pm_smem_data->sleep_time, \
+				msm_pm_smem_data->resources_used, \
+				msm_pm_smem_data->irq_mask, \
+				msm_pm_smem_data->wakeup_reason, \
+				msm_pm_smem_data->pending_irqs); \
+	} while (0)
+
+
+/******************************************************************************
+ * Sleep Modes and Parameters
+ *****************************************************************************/
+
+static int msm_pm_idle_sleep_min_time = CONFIG_MSM7X00A_IDLE_SLEEP_MIN_TIME;
+module_param_named(
+	idle_sleep_min_time, msm_pm_idle_sleep_min_time,
+	int, S_IRUGO | S_IWUSR | S_IWGRP
+);
+
+enum {
+	MSM_PM_MODE_ATTR_SUSPEND,
+	MSM_PM_MODE_ATTR_IDLE,
+	MSM_PM_MODE_ATTR_LATENCY,
+	MSM_PM_MODE_ATTR_RESIDENCY,
+	MSM_PM_MODE_ATTR_NR,
+};
+
+static char *msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_NR] = {
+	[MSM_PM_MODE_ATTR_SUSPEND] = "suspend_enabled",
+	[MSM_PM_MODE_ATTR_IDLE] = "idle_enabled",
+	[MSM_PM_MODE_ATTR_LATENCY] = "latency",
+	[MSM_PM_MODE_ATTR_RESIDENCY] = "residency",
+};
+
+static char *msm_pm_sleep_mode_labels[MSM_PM_SLEEP_MODE_NR] = {
+	[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND] = " ",
+	[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = "power_collapse",
+	[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT] =
+		"ramp_down_and_wfi",
+	[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT] = "wfi",
+	[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN] =
+		"power_collapse_no_xo_shutdown",
+	[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE] =
+		"standalone_power_collapse",
+};
+
+static struct msm_pm_platform_data *msm_pm_modes;
+static struct msm_pm_irq_calls *msm_pm_irq_extns;
+
+struct msm_pm_kobj_attribute {
+	unsigned int cpu;
+	struct kobj_attribute ka;
+};
+
+#define GET_CPU_OF_ATTR(attr) \
+	(container_of(attr, struct msm_pm_kobj_attribute, ka)->cpu)
+
+struct msm_pm_sysfs_sleep_mode {
+	struct kobject *kobj;
+	struct attribute_group attr_group;
+	struct attribute *attrs[MSM_PM_MODE_ATTR_NR + 1];
+	struct msm_pm_kobj_attribute kas[MSM_PM_MODE_ATTR_NR];
+};
+
+/*
+ * Write out the attribute.
+ */
+static ssize_t msm_pm_mode_attr_show(
+	struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	int ret = -EINVAL;
+	int i;
+
+	for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
+		struct kernel_param kp;
+		unsigned int cpu;
+		struct msm_pm_platform_data *mode;
+
+		if (msm_pm_sleep_mode_labels[i] == NULL)
+			continue;
+
+		if (strcmp(kobj->name, msm_pm_sleep_mode_labels[i]))
+			continue;
+
+		cpu = GET_CPU_OF_ATTR(attr);
+		mode = &msm_pm_modes[MSM_PM_MODE(cpu, i)];
+
+		if (!strcmp(attr->attr.name,
+			msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_SUSPEND])) {
+			u32 arg = mode->suspend_enabled;
+			kp.arg = &arg;
+			ret = param_get_ulong(buf, &kp);
+		} else if (!strcmp(attr->attr.name,
+			msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_IDLE])) {
+			u32 arg = mode->idle_enabled;
+			kp.arg = &arg;
+			ret = param_get_ulong(buf, &kp);
+		} else if (!strcmp(attr->attr.name,
+			msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_LATENCY])) {
+			u32 arg = mode->latency;
+			kp.arg = &arg;
+			ret = param_get_ulong(buf, &kp);
+		} else if (!strcmp(attr->attr.name,
+			msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_RESIDENCY])) {
+			u32 arg = mode->residency;
+			kp.arg = &arg;
+			ret = param_get_ulong(buf, &kp);
+		}
+
+		break;
+	}
+
+	if (ret > 0) {
+		strlcat(buf, "\n", PAGE_SIZE);
+		ret++;
+	}
+
+	return ret;
+}
+
+/*
+ * Read in the new attribute value.
+ */
+static ssize_t msm_pm_mode_attr_store(struct kobject *kobj,
+	struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	int ret = -EINVAL;
+	int i;
+
+	for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
+		struct kernel_param kp;
+		unsigned int cpu;
+		struct msm_pm_platform_data *mode;
+
+		if (msm_pm_sleep_mode_labels[i] == NULL)
+			continue;
+
+		if (strcmp(kobj->name, msm_pm_sleep_mode_labels[i]))
+			continue;
+
+		cpu = GET_CPU_OF_ATTR(attr);
+		mode = &msm_pm_modes[MSM_PM_MODE(cpu, i)];
+
+		if (!strcmp(attr->attr.name,
+			msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_SUSPEND])) {
+			kp.arg = &mode->suspend_enabled;
+			ret = param_set_byte(buf, &kp);
+		} else if (!strcmp(attr->attr.name,
+			msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_IDLE])) {
+			kp.arg = &mode->idle_enabled;
+			ret = param_set_byte(buf, &kp);
+		} else if (!strcmp(attr->attr.name,
+			msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_LATENCY])) {
+			kp.arg = &mode->latency;
+			ret = param_set_ulong(buf, &kp);
+		} else if (!strcmp(attr->attr.name,
+			msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_RESIDENCY])) {
+			kp.arg = &mode->residency;
+			ret = param_set_ulong(buf, &kp);
+		}
+
+		break;
+	}
+
+	return ret ? ret : count;
+}
+
+ /* Add sysfs entries for one cpu. */
+static int __init msm_pm_mode_sysfs_add_cpu(
+	unsigned int cpu, struct kobject *modes_kobj)
+{
+	char cpu_name[8];
+	struct kobject *cpu_kobj;
+	struct msm_pm_sysfs_sleep_mode *mode = NULL;
+	int i, j, k;
+	int ret;
+
+	snprintf(cpu_name, sizeof(cpu_name), "cpu%u", cpu);
+	cpu_kobj = kobject_create_and_add(cpu_name, modes_kobj);
+	if (!cpu_kobj) {
+		pr_err("%s: cannot create %s kobject\n", __func__, cpu_name);
+		ret = -ENOMEM;
+		goto mode_sysfs_add_cpu_exit;
+	}
+
+	for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
+		int idx = MSM_PM_MODE(cpu, i);
+
+		if ((!msm_pm_modes[idx].suspend_supported) &&
+				(!msm_pm_modes[idx].idle_supported))
+			continue;
+
+		mode = kzalloc(sizeof(*mode), GFP_KERNEL);
+		if (!mode) {
+			pr_err("%s: cannot allocate memory for attributes\n",
+				__func__);
+			ret = -ENOMEM;
+			goto mode_sysfs_add_cpu_exit;
+		}
+
+		mode->kobj = kobject_create_and_add(
+				msm_pm_sleep_mode_labels[i], cpu_kobj);
+		if (!mode->kobj) {
+			pr_err("%s: cannot create kobject\n", __func__);
+			ret = -ENOMEM;
+			goto mode_sysfs_add_cpu_exit;
+		}
+
+		for (k = 0, j = 0; k < MSM_PM_MODE_ATTR_NR; k++) {
+			if ((k == MSM_PM_MODE_ATTR_IDLE) &&
+				!msm_pm_modes[idx].idle_supported)
+				continue;
+			if ((k == MSM_PM_MODE_ATTR_SUSPEND) &&
+			     !msm_pm_modes[idx].suspend_supported)
+				continue;
+			mode->kas[j].cpu = cpu;
+			mode->kas[j].ka.attr.mode = 0644;
+			mode->kas[j].ka.show = msm_pm_mode_attr_show;
+			mode->kas[j].ka.store = msm_pm_mode_attr_store;
+			mode->kas[j].ka.attr.name = msm_pm_mode_attr_labels[k];
+			mode->attrs[j] = &mode->kas[j].ka.attr;
+			j++;
+		}
+		mode->attrs[j] = NULL;
+
+		mode->attr_group.attrs = mode->attrs;
+		ret = sysfs_create_group(mode->kobj, &mode->attr_group);
+		if (ret) {
+			printk(KERN_ERR
+				"%s: cannot create kobject attribute group\n",
+				__func__);
+			goto mode_sysfs_add_cpu_exit;
+		}
+	}
+
+	ret = 0;
+
+mode_sysfs_add_cpu_exit:
+	if (ret) {
+		if (mode && mode->kobj)
+			kobject_del(mode->kobj);
+		kfree(mode);
+	}
+
+	return ret;
+}
+
+/*
+ * Add sysfs entries for the sleep modes.
+ */
+static int __init msm_pm_mode_sysfs_add(void)
+{
+	struct kobject *module_kobj = NULL;
+	struct kobject *modes_kobj = NULL;
+	unsigned int cpu;
+	int ret;
+
+	module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
+	if (!module_kobj) {
+		printk(KERN_ERR "%s: cannot find kobject for module %s\n",
+			__func__, KBUILD_MODNAME);
+		ret = -ENOENT;
+		goto mode_sysfs_add_exit;
+	}
+
+	modes_kobj = kobject_create_and_add("modes", module_kobj);
+	if (!modes_kobj) {
+		printk(KERN_ERR "%s: cannot create modes kobject\n", __func__);
+		ret = -ENOMEM;
+		goto mode_sysfs_add_exit;
+	}
+
+	for_each_possible_cpu(cpu) {
+		ret = msm_pm_mode_sysfs_add_cpu(cpu, modes_kobj);
+		if (ret)
+			goto mode_sysfs_add_exit;
+	}
+
+	ret = 0;
+
+mode_sysfs_add_exit:
+	return ret;
+}
+
+void __init msm_pm_set_platform_data(
+	struct msm_pm_platform_data *data, int count)
+{
+	BUG_ON(MSM_PM_SLEEP_MODE_NR * num_possible_cpus() > count);
+	msm_pm_modes = data;
+}
+
+void __init msm_pm_set_irq_extns(struct msm_pm_irq_calls *irq_calls)
+{
+	/* sanity check */
+	BUG_ON(irq_calls == NULL || irq_calls->irq_pending == NULL ||
+		irq_calls->idle_sleep_allowed == NULL ||
+		irq_calls->enter_sleep1 == NULL ||
+		irq_calls->enter_sleep2 == NULL ||
+		irq_calls->exit_sleep1 == NULL ||
+		irq_calls->exit_sleep2 == NULL ||
+		irq_calls->exit_sleep3 == NULL);
+
+	msm_pm_irq_extns = irq_calls;
+}
+
+/******************************************************************************
+ * Sleep Limitations
+ *****************************************************************************/
+enum {
+	SLEEP_LIMIT_NONE = 0,
+	SLEEP_LIMIT_NO_TCXO_SHUTDOWN = 2,
+	SLEEP_LIMIT_MASK = 0x03,
+};
+
+static uint32_t msm_pm_sleep_limit = SLEEP_LIMIT_NONE;
+#ifdef CONFIG_MSM_MEMORY_LOW_POWER_MODE
+enum {
+	SLEEP_RESOURCE_MEMORY_BIT0 = 0x0200,
+	SLEEP_RESOURCE_MEMORY_BIT1 = 0x0010,
+};
+#endif
+
+
+/******************************************************************************
+ * Configure Hardware for Power Down/Up
+ *****************************************************************************/
+
+#if defined(CONFIG_ARCH_MSM7X30)
+#define APPS_CLK_SLEEP_EN (MSM_APCS_GCC_BASE + 0x020)
+#define APPS_PWRDOWN      (MSM_ACC0_BASE + 0x01c)
+#define APPS_SECOP        (MSM_TCSR_BASE + 0x038)
+#define APPS_STANDBY_CTL  NULL
+#else
+#define APPS_CLK_SLEEP_EN (MSM_CSR_BASE + 0x11c)
+#define APPS_PWRDOWN      (MSM_CSR_BASE + 0x440)
+#define APPS_STANDBY_CTL  (MSM_CSR_BASE + 0x108)
+#define APPS_SECOP	  NULL
+#endif
+
+/*
+ * Configure hardware registers in preparation for Apps power down.
+ */
+static void msm_pm_config_hw_before_power_down(void)
+{
+	if (cpu_is_msm7x30() || cpu_is_msm8x55()) {
+		__raw_writel(4, APPS_SECOP);
+	} else if (cpu_is_msm7x27()) {
+		__raw_writel(0x1f, APPS_CLK_SLEEP_EN);
+	} else if (cpu_is_msm7x27a() || cpu_is_msm7x27aa() ||
+		   cpu_is_msm7x25a() || cpu_is_msm7x25aa() ||
+		   cpu_is_msm7x25ab()) {
+		__raw_writel(0x7, APPS_CLK_SLEEP_EN);
+	} else if (cpu_is_qsd8x50()) {
+		__raw_writel(0x1f, APPS_CLK_SLEEP_EN);
+		mb();
+		__raw_writel(0, APPS_STANDBY_CTL);
+	}
+	mb();
+	__raw_writel(1, APPS_PWRDOWN);
+	mb();
+}
+
+/*
+ * Program the top csr from core0 context to put the
+ * core1 into GDFS, as core1 is not running yet.
+ */
+static void configure_top_csr(void)
+{
+	void __iomem *base_ptr;
+	unsigned int value = 0;
+
+	base_ptr = core1_reset_base();
+	if (!base_ptr)
+		return;
+
+	/* bring the core1 out of reset */
+	__raw_writel(0x3, base_ptr);
+	mb();
+	/*
+	 * override DBGNOPOWERDN and program the GDFS
+	 * count val
+	 */
+
+	 __raw_writel(0x00030002, (MSM_CFG_CTL_BASE + 0x38));
+	mb();
+
+	/* Initialize the SPM0 and SPM1 registers */
+	msm_spm_reinit();
+
+	/* enable TCSR for core1 */
+	value = __raw_readl((MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG));
+	value |= BIT(22);
+	__raw_writel(value,  MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG);
+	mb();
+
+	/* set reset bit for SPM1 */
+	value = __raw_readl((MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG));
+	value |= BIT(20);
+	__raw_writel(value,  MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG);
+	mb();
+
+	/* set CLK_OFF bit */
+	value = __raw_readl((MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG));
+	value |= BIT(18);
+	__raw_writel(value,  MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG);
+	mb();
+
+	/* set clamps bit */
+	value = __raw_readl((MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG));
+	value |= BIT(21);
+	__raw_writel(value,  MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG);
+	mb();
+
+	/* set power_up bit */
+	value = __raw_readl((MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG));
+	value |= BIT(19);
+	__raw_writel(value,  MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG);
+	mb();
+
+	/* Disable TSCR for core0 */
+	value = __raw_readl((MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG));
+	value &= ~BIT(22);
+	__raw_writel(value,  MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG);
+	mb();
+	__raw_writel(0x0, base_ptr);
+	mb();
+}
+
+/*
+ * Clear hardware registers after Apps powers up.
+ */
+static void msm_pm_config_hw_after_power_up(void)
+{
+
+	if (cpu_is_msm7x30() || cpu_is_msm8x55()) {
+		__raw_writel(0, APPS_SECOP);
+		mb();
+		__raw_writel(0, APPS_PWRDOWN);
+		mb();
+		msm_spm_reinit();
+	} else if (cpu_is_msm8625()) {
+		__raw_writel(0, APPS_PWRDOWN);
+		mb();
+
+		if (power_collapsed) {
+			/*
+			 * enable the SCU while coming out of power
+			 * collapse.
+			 */
+			scu_enable(MSM_SCU_BASE);
+			/*
+			 * Program the top csr to put the core1 into GDFS.
+			 */
+			configure_top_csr();
+		}
+	} else {
+		__raw_writel(0, APPS_PWRDOWN);
+		mb();
+		__raw_writel(0, APPS_CLK_SLEEP_EN);
+		mb();
+	}
+}
+
+/*
+ * Configure hardware registers in preparation for SWFI.
+ */
+static void msm_pm_config_hw_before_swfi(void)
+{
+	if (cpu_is_qsd8x50()) {
+		__raw_writel(0x1f, APPS_CLK_SLEEP_EN);
+		mb();
+	} else if (cpu_is_msm7x27()) {
+		__raw_writel(0x0f, APPS_CLK_SLEEP_EN);
+		mb();
+	} else if (cpu_is_msm7x27a() || cpu_is_msm7x27aa() ||
+		   cpu_is_msm7x25a() || cpu_is_msm7x25aa() ||
+		   cpu_is_msm7x25ab()) {
+		__raw_writel(0x7, APPS_CLK_SLEEP_EN);
+		mb();
+	}
+}
+
+/*
+ * Respond to timing out waiting for Modem
+ *
+ * NOTE: The function never returns.
+ */
+static void msm_pm_timeout(void)
+{
+#if defined(CONFIG_MSM_PM_TIMEOUT_RESET_CHIP)
+	printk(KERN_EMERG "%s(): resetting chip\n", __func__);
+	msm_proc_comm(PCOM_RESET_CHIP_IMM, NULL, NULL);
+#elif defined(CONFIG_MSM_PM_TIMEOUT_RESET_MODEM)
+	printk(KERN_EMERG "%s(): resetting modem\n", __func__);
+	msm_proc_comm_reset_modem_now();
+#elif defined(CONFIG_MSM_PM_TIMEOUT_HALT)
+	printk(KERN_EMERG "%s(): halting\n", __func__);
+#endif
+	for (;;)
+		;
+}
+
+
+/******************************************************************************
+ * State Polling Definitions
+ *****************************************************************************/
+
+struct msm_pm_polled_group {
+	uint32_t group_id;
+
+	uint32_t bits_all_set;
+	uint32_t bits_all_clear;
+	uint32_t bits_any_set;
+	uint32_t bits_any_clear;
+
+	uint32_t value_read;
+};
+
+/*
+ * Return true if all bits indicated by flag are set in source.
+ */
+static inline bool msm_pm_all_set(uint32_t source, uint32_t flag)
+{
+	return (source & flag) == flag;
+}
+
+/*
+ * Return true if any bit indicated by flag are set in source.
+ */
+static inline bool msm_pm_any_set(uint32_t source, uint32_t flag)
+{
+	return !flag || (source & flag);
+}
+
+/*
+ * Return true if all bits indicated by flag are cleared in source.
+ */
+static inline bool msm_pm_all_clear(uint32_t source, uint32_t flag)
+{
+	return (~source & flag) == flag;
+}
+
+/*
+ * Return true if any bit indicated by flag are cleared in source.
+ */
+static inline bool msm_pm_any_clear(uint32_t source, uint32_t flag)
+{
+	return !flag || (~source & flag);
+}
+
+/*
+ * Poll the shared memory states as indicated by the poll groups.
+ *
+ * nr_grps: number of groups in the array
+ * grps: array of groups
+ *
+ * The function returns when conditions specified by any of the poll
+ * groups become true.  The conditions specified by a poll group are
+ * deemed true when 1) at least one bit from bits_any_set is set OR one
+ * bit from bits_any_clear is cleared; and 2) all bits in bits_all_set
+ * are set; and 3) all bits in bits_all_clear are cleared.
+ *
+ * Return value:
+ *      >=0: index of the poll group whose conditions have become true
+ *      -ETIMEDOUT: timed out
+ */
+static int msm_pm_poll_state(int nr_grps, struct msm_pm_polled_group *grps)
+{
+	int i, k;
+
+	for (i = 0; i < 50000; i++) {
+		for (k = 0; k < nr_grps; k++) {
+			bool all_set, all_clear;
+			bool any_set, any_clear;
+
+			grps[k].value_read = smsm_get_state(grps[k].group_id);
+
+			all_set = msm_pm_all_set(grps[k].value_read,
+					grps[k].bits_all_set);
+			all_clear = msm_pm_all_clear(grps[k].value_read,
+					grps[k].bits_all_clear);
+			any_set = msm_pm_any_set(grps[k].value_read,
+					grps[k].bits_any_set);
+			any_clear = msm_pm_any_clear(grps[k].value_read,
+					grps[k].bits_any_clear);
+
+			if (all_set && all_clear && (any_set || any_clear))
+				return k;
+		}
+		udelay(50);
+	}
+
+	printk(KERN_ERR "%s failed:\n", __func__);
+	for (k = 0; k < nr_grps; k++)
+		printk(KERN_ERR "(%x, %x, %x, %x) %x\n",
+			grps[k].bits_all_set, grps[k].bits_all_clear,
+			grps[k].bits_any_set, grps[k].bits_any_clear,
+			grps[k].value_read);
+
+	return -ETIMEDOUT;
+}
+
+
+/******************************************************************************
+ * Suspend Max Sleep Time
+ *****************************************************************************/
+
+#define SCLK_HZ (32768)
+#define MSM_PM_SLEEP_TICK_LIMIT (0x6DDD000)
+
+#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE
+static int msm_pm_sleep_time_override;
+module_param_named(sleep_time_override,
+	msm_pm_sleep_time_override, int, S_IRUGO | S_IWUSR | S_IWGRP);
+#endif
+
+static uint32_t msm_pm_max_sleep_time;
+
+/*
+ * Convert time from nanoseconds to slow clock ticks, then cap it to the
+ * specified limit
+ */
+static int64_t msm_pm_convert_and_cap_time(int64_t time_ns, int64_t limit)
+{
+	do_div(time_ns, NSEC_PER_SEC / SCLK_HZ);
+	return (time_ns > limit) ? limit : time_ns;
+}
+
+/*
+ * Set the sleep time for suspend.  0 means infinite sleep time.
+ */
+void msm_pm_set_max_sleep_time(int64_t max_sleep_time_ns)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (max_sleep_time_ns == 0) {
+		msm_pm_max_sleep_time = 0;
+	} else {
+		msm_pm_max_sleep_time = (uint32_t)msm_pm_convert_and_cap_time(
+			max_sleep_time_ns, MSM_PM_SLEEP_TICK_LIMIT);
+
+		if (msm_pm_max_sleep_time == 0)
+			msm_pm_max_sleep_time = 1;
+	}
+
+	MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND, KERN_INFO,
+		"%s(): Requested %lld ns Giving %u sclk ticks\n", __func__,
+		max_sleep_time_ns, msm_pm_max_sleep_time);
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL(msm_pm_set_max_sleep_time);
+
+
+/******************************************************************************
+ * Shared Memory Bits
+ *****************************************************************************/
+
+#define DEM_MASTER_BITS_PER_CPU             6
+
+/* Power Master State Bits - Per CPU */
+#define DEM_MASTER_SMSM_RUN \
+	(0x01UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
+#define DEM_MASTER_SMSM_RSA \
+	(0x02UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
+#define DEM_MASTER_SMSM_PWRC_EARLY_EXIT \
+	(0x04UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
+#define DEM_MASTER_SMSM_SLEEP_EXIT \
+	(0x08UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
+#define DEM_MASTER_SMSM_READY \
+	(0x10UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
+#define DEM_MASTER_SMSM_SLEEP \
+	(0x20UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
+
+/* Power Slave State Bits */
+#define DEM_SLAVE_SMSM_RUN                  (0x0001)
+#define DEM_SLAVE_SMSM_PWRC                 (0x0002)
+#define DEM_SLAVE_SMSM_PWRC_DELAY           (0x0004)
+#define DEM_SLAVE_SMSM_PWRC_EARLY_EXIT      (0x0008)
+#define DEM_SLAVE_SMSM_WFPI                 (0x0010)
+#define DEM_SLAVE_SMSM_SLEEP                (0x0020)
+#define DEM_SLAVE_SMSM_SLEEP_EXIT           (0x0040)
+#define DEM_SLAVE_SMSM_MSGS_REDUCED         (0x0080)
+#define DEM_SLAVE_SMSM_RESET                (0x0100)
+#define DEM_SLAVE_SMSM_PWRC_SUSPEND         (0x0200)
+
+
+/******************************************************************************
+ * Shared Memory Data
+ *****************************************************************************/
+
+#define DEM_MAX_PORT_NAME_LEN (20)
+
+struct msm_pm_smem_t {
+	uint32_t sleep_time;
+	uint32_t irq_mask;
+	uint32_t resources_used;
+	uint32_t reserved1;
+
+	uint32_t wakeup_reason;
+	uint32_t pending_irqs;
+	uint32_t rpc_prog;
+	uint32_t rpc_proc;
+	char     smd_port_name[DEM_MAX_PORT_NAME_LEN];
+	uint32_t reserved2;
+};
+
+
+/******************************************************************************
+ *
+ *****************************************************************************/
+static struct msm_pm_smem_t *msm_pm_smem_data;
+static atomic_t msm_pm_init_done = ATOMIC_INIT(0);
+
+static int msm_pm_modem_busy(void)
+{
+	if (!(smsm_get_state(SMSM_POWER_MASTER_DEM) & DEM_MASTER_SMSM_READY)) {
+		MSM_PM_DPRINTK(MSM_PM_DEBUG_POWER_COLLAPSE,
+			KERN_INFO, "%s(): master not ready\n", __func__);
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+/*
+ * Power collapse the Apps processor.  This function executes the handshake
+ * protocol with Modem.
+ *
+ * Return value:
+ *      -EAGAIN: modem reset occurred or early exit from power collapse
+ *      -EBUSY: modem not ready for our power collapse -- no power loss
+ *      -ETIMEDOUT: timed out waiting for modem's handshake -- no power loss
+ *      0: success
+ */
+static int msm_pm_power_collapse
+	(bool from_idle, uint32_t sleep_delay, uint32_t sleep_limit)
+{
+	struct msm_pm_polled_group state_grps[2];
+	unsigned long saved_acpuclk_rate;
+	int collapsed = 0;
+	int ret;
+	int val;
+	int modem_early_exit = 0;
+
+	MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
+		KERN_INFO, "%s(): idle %d, delay %u, limit %u\n", __func__,
+		(int)from_idle, sleep_delay, sleep_limit);
+
+	if (!(smsm_get_state(SMSM_POWER_MASTER_DEM) & DEM_MASTER_SMSM_READY)) {
+		MSM_PM_DPRINTK(
+			MSM_PM_DEBUG_SUSPEND | MSM_PM_DEBUG_POWER_COLLAPSE,
+			KERN_INFO, "%s(): master not ready\n", __func__);
+		ret = -EBUSY;
+		goto power_collapse_bail;
+	}
+
+	memset(msm_pm_smem_data, 0, sizeof(*msm_pm_smem_data));
+
+	if (cpu_is_msm8625()) {
+		/* Program the SPM */
+		ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_COLLAPSE,
+									false);
+		WARN_ON(ret);
+	}
+
+	msm_pm_irq_extns->enter_sleep1(true, from_idle,
+						&msm_pm_smem_data->irq_mask);
+	msm_sirc_enter_sleep();
+	msm_gpio_enter_sleep(from_idle);
+
+	msm_pm_smem_data->sleep_time = sleep_delay;
+	msm_pm_smem_data->resources_used = sleep_limit;
+
+	/* Enter PWRC/PWRC_SUSPEND */
+
+	if (from_idle)
+		smsm_change_state(SMSM_APPS_DEM, DEM_SLAVE_SMSM_RUN,
+			DEM_SLAVE_SMSM_PWRC);
+	else
+		smsm_change_state(SMSM_APPS_DEM, DEM_SLAVE_SMSM_RUN,
+			DEM_SLAVE_SMSM_PWRC | DEM_SLAVE_SMSM_PWRC_SUSPEND);
+
+	MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): PWRC");
+	MSM_PM_DEBUG_PRINT_SLEEP_INFO();
+
+	memset(state_grps, 0, sizeof(state_grps));
+	state_grps[0].group_id = SMSM_POWER_MASTER_DEM;
+	state_grps[0].bits_all_set = DEM_MASTER_SMSM_RSA;
+	state_grps[1].group_id = SMSM_MODEM_STATE;
+	state_grps[1].bits_all_set = SMSM_RESET;
+
+	ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps);
+
+	if (ret < 0) {
+		printk(KERN_EMERG "%s(): power collapse entry "
+			"timed out waiting for Modem's response\n", __func__);
+		msm_pm_timeout();
+	}
+
+	if (ret == 1) {
+		MSM_PM_DPRINTK(
+			MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
+			KERN_INFO,
+			"%s(): msm_pm_poll_state detected Modem reset\n",
+			__func__);
+		goto power_collapse_early_exit;
+	}
+
+	/* DEM Master in RSA */
+
+	MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): PWRC RSA");
+
+	ret = msm_pm_irq_extns->enter_sleep2(true, from_idle);
+	if (ret < 0) {
+		MSM_PM_DPRINTK(
+			MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
+			KERN_INFO,
+			"%s(): msm_irq_enter_sleep2 aborted, %d\n", __func__,
+			ret);
+		goto power_collapse_early_exit;
+	}
+
+	msm_pm_config_hw_before_power_down();
+	MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): pre power down");
+
+	saved_acpuclk_rate = acpuclk_power_collapse();
+	MSM_PM_DPRINTK(MSM_PM_DEBUG_CLOCK, KERN_INFO,
+		"%s(): change clock rate (old rate = %lu)\n", __func__,
+		saved_acpuclk_rate);
+
+	if (saved_acpuclk_rate == 0) {
+		msm_pm_config_hw_after_power_up();
+		goto power_collapse_early_exit;
+	}
+
+	msm_pm_boot_config_before_pc(smp_processor_id(),
+			virt_to_phys(msm_pm_collapse_exit));
+
+#ifdef CONFIG_VFP
+	if (from_idle)
+		vfp_pm_suspend();
+#endif
+
+#ifdef CONFIG_CACHE_L2X0
+	if (!cpu_is_msm8625())
+		l2cc_suspend();
+	else
+		apps_power_collapse = 1;
+#endif
+
+	collapsed = msm_pm_collapse();
+
+	/*
+	 * TBD: Currently recognise the MODEM early exit
+	 * path by reading the MPA5_GDFS_CNT_VAL register.
+	 */
+	if (cpu_is_msm8625()) {
+		/*
+		 * on system reset, default value of MPA5_GDFS_CNT_VAL
+		 * is = 0x0, later modem reprogram this value to
+		 * 0x00030004. Once APPS did a power collapse and
+		 * coming out of it expected value of this register
+		 * always be 0x00030004. Incase if APPS sees the value
+		 * as 0x00030002 consider this case as a modem early
+		 * exit.
+		 */
+		val = __raw_readl(MSM_CFG_CTL_BASE + 0x38);
+		if (val != 0x00030002)
+			power_collapsed = 1;
+		else
+			modem_early_exit = 1;
+	}
+
+#ifdef CONFIG_CACHE_L2X0
+	if (!cpu_is_msm8625())
+		l2cc_resume();
+	else
+		apps_power_collapse = 0;
+#endif
+
+	msm_pm_boot_config_after_pc(smp_processor_id());
+
+	if (collapsed) {
+#ifdef CONFIG_VFP
+		if (from_idle)
+			vfp_pm_resume();
+#endif
+		cpu_init();
+		local_fiq_enable();
+	}
+
+	MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND | MSM_PM_DEBUG_POWER_COLLAPSE,
+		KERN_INFO,
+		"%s(): msm_pm_collapse returned %d\n", __func__, collapsed);
+
+	MSM_PM_DPRINTK(MSM_PM_DEBUG_CLOCK, KERN_INFO,
+		"%s(): restore clock rate to %lu\n", __func__,
+		saved_acpuclk_rate);
+	if (acpuclk_set_rate(smp_processor_id(), saved_acpuclk_rate,
+			SETRATE_PC) < 0)
+		printk(KERN_ERR "%s(): failed to restore clock rate(%lu)\n",
+			__func__, saved_acpuclk_rate);
+
+	msm_pm_irq_extns->exit_sleep1(msm_pm_smem_data->irq_mask,
+		msm_pm_smem_data->wakeup_reason,
+		msm_pm_smem_data->pending_irqs);
+
+	msm_pm_config_hw_after_power_up();
+	MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): post power up");
+
+	memset(state_grps, 0, sizeof(state_grps));
+	state_grps[0].group_id = SMSM_POWER_MASTER_DEM;
+	state_grps[0].bits_any_set =
+		DEM_MASTER_SMSM_RSA | DEM_MASTER_SMSM_PWRC_EARLY_EXIT;
+	state_grps[1].group_id = SMSM_MODEM_STATE;
+	state_grps[1].bits_all_set = SMSM_RESET;
+
+	ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps);
+
+	if (ret < 0) {
+		printk(KERN_EMERG "%s(): power collapse exit "
+			"timed out waiting for Modem's response\n", __func__);
+		msm_pm_timeout();
+	}
+
+	if (ret == 1) {
+		MSM_PM_DPRINTK(
+			MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
+			KERN_INFO,
+			"%s(): msm_pm_poll_state detected Modem reset\n",
+			__func__);
+		goto power_collapse_early_exit;
+	}
+
+	/* Sanity check */
+	if (collapsed && !modem_early_exit) {
+		BUG_ON(!(state_grps[0].value_read & DEM_MASTER_SMSM_RSA));
+	} else {
+		BUG_ON(!(state_grps[0].value_read &
+			DEM_MASTER_SMSM_PWRC_EARLY_EXIT));
+		goto power_collapse_early_exit;
+	}
+
+	/* Enter WFPI */
+
+	smsm_change_state(SMSM_APPS_DEM,
+		DEM_SLAVE_SMSM_PWRC | DEM_SLAVE_SMSM_PWRC_SUSPEND,
+		DEM_SLAVE_SMSM_WFPI);
+
+	MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): WFPI");
+
+	memset(state_grps, 0, sizeof(state_grps));
+	state_grps[0].group_id = SMSM_POWER_MASTER_DEM;
+	state_grps[0].bits_all_set = DEM_MASTER_SMSM_RUN;
+	state_grps[1].group_id = SMSM_MODEM_STATE;
+	state_grps[1].bits_all_set = SMSM_RESET;
+
+	ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps);
+
+	if (ret < 0) {
+		printk(KERN_EMERG "%s(): power collapse WFPI "
+			"timed out waiting for Modem's response\n", __func__);
+		msm_pm_timeout();
+	}
+
+	if (ret == 1) {
+		MSM_PM_DPRINTK(
+			MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
+			KERN_INFO,
+			"%s(): msm_pm_poll_state detected Modem reset\n",
+			__func__);
+		ret = -EAGAIN;
+		goto power_collapse_restore_gpio_bail;
+	}
+
+	/* DEM Master == RUN */
+
+	MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): WFPI RUN");
+	MSM_PM_DEBUG_PRINT_SLEEP_INFO();
+
+	msm_pm_irq_extns->exit_sleep2(msm_pm_smem_data->irq_mask,
+		msm_pm_smem_data->wakeup_reason,
+		msm_pm_smem_data->pending_irqs);
+	msm_pm_irq_extns->exit_sleep3(msm_pm_smem_data->irq_mask,
+		msm_pm_smem_data->wakeup_reason,
+		msm_pm_smem_data->pending_irqs);
+	msm_gpio_exit_sleep();
+	msm_sirc_exit_sleep();
+
+	smsm_change_state(SMSM_APPS_DEM,
+		DEM_SLAVE_SMSM_WFPI, DEM_SLAVE_SMSM_RUN);
+
+	MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): RUN");
+
+	smd_sleep_exit();
+
+	if (cpu_is_msm8625()) {
+		ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING,
+									false);
+		WARN_ON(ret);
+	}
+
+	return 0;
+
+power_collapse_early_exit:
+	/* Enter PWRC_EARLY_EXIT */
+
+	smsm_change_state(SMSM_APPS_DEM,
+		DEM_SLAVE_SMSM_PWRC | DEM_SLAVE_SMSM_PWRC_SUSPEND,
+		DEM_SLAVE_SMSM_PWRC_EARLY_EXIT);
+
+	MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): EARLY_EXIT");
+
+	memset(state_grps, 0, sizeof(state_grps));
+	state_grps[0].group_id = SMSM_POWER_MASTER_DEM;
+	state_grps[0].bits_all_set = DEM_MASTER_SMSM_PWRC_EARLY_EXIT;
+	state_grps[1].group_id = SMSM_MODEM_STATE;
+	state_grps[1].bits_all_set = SMSM_RESET;
+
+	ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps);
+	MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): EARLY_EXIT EE");
+
+	if (ret < 0) {
+		printk(KERN_EMERG "%s(): power collapse EARLY_EXIT "
+			"timed out waiting for Modem's response\n", __func__);
+		msm_pm_timeout();
+	}
+
+	if (ret == 1) {
+		MSM_PM_DPRINTK(
+			MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
+			KERN_INFO,
+			"%s(): msm_pm_poll_state detected Modem reset\n",
+			__func__);
+	}
+
+	/* DEM Master == RESET or PWRC_EARLY_EXIT */
+
+	ret = -EAGAIN;
+
+power_collapse_restore_gpio_bail:
+	msm_gpio_exit_sleep();
+	msm_sirc_exit_sleep();
+
+	/* Enter RUN */
+	smsm_change_state(SMSM_APPS_DEM,
+		DEM_SLAVE_SMSM_PWRC | DEM_SLAVE_SMSM_PWRC_SUSPEND |
+		DEM_SLAVE_SMSM_PWRC_EARLY_EXIT, DEM_SLAVE_SMSM_RUN);
+
+	MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): RUN");
+
+	if (collapsed)
+		smd_sleep_exit();
+
+power_collapse_bail:
+	if (cpu_is_msm8625()) {
+		ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING,
+									false);
+		WARN_ON(ret);
+	}
+
+	return ret;
+}
+
+/*
+ * Power collapse the Apps processor without involving Modem.
+ *
+ * Return value:
+ *      0: success
+ */
+static int __ref msm_pm_power_collapse_standalone(bool from_idle)
+{
+	int collapsed = 0;
+	int ret;
+	void *entry;
+
+	MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
+		KERN_INFO, "%s()\n", __func__);
+
+	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_COLLAPSE, false);
+	WARN_ON(ret);
+
+	entry = (!smp_processor_id() || from_idle) ?
+			msm_pm_collapse_exit : msm_secondary_startup;
+
+	msm_pm_boot_config_before_pc(smp_processor_id(),
+						virt_to_phys(entry));
+
+#ifdef CONFIG_VFP
+	vfp_pm_suspend();
+#endif
+
+#ifdef CONFIG_CACHE_L2X0
+	if (!cpu_is_msm8625())
+		l2cc_suspend();
+#endif
+
+	collapsed = msm_pm_collapse();
+
+#ifdef CONFIG_CACHE_L2X0
+	if (!cpu_is_msm8625())
+		l2cc_resume();
+#endif
+
+	msm_pm_boot_config_after_pc(smp_processor_id());
+
+	if (collapsed) {
+#ifdef CONFIG_VFP
+		vfp_pm_resume();
+#endif
+		cpu_init();
+		local_fiq_enable();
+	}
+
+	MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND | MSM_PM_DEBUG_POWER_COLLAPSE,
+		KERN_INFO,
+		"%s(): msm_pm_collapse returned %d\n", __func__, collapsed);
+
+	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
+	WARN_ON(ret);
+
+	return !collapsed;
+}
+
+/*
+ * Bring the Apps processor to SWFI.
+ *
+ * Return value:
+ *      -EIO: could not ramp Apps processor clock
+ *      0: success
+ */
+static int msm_pm_swfi(bool ramp_acpu)
+{
+	unsigned long saved_acpuclk_rate = 0;
+
+	if (ramp_acpu) {
+		saved_acpuclk_rate = acpuclk_wait_for_irq();
+		MSM_PM_DPRINTK(MSM_PM_DEBUG_CLOCK, KERN_INFO,
+			"%s(): change clock rate (old rate = %lu)\n", __func__,
+			saved_acpuclk_rate);
+
+		if (!saved_acpuclk_rate)
+			return -EIO;
+	}
+
+	if (!cpu_is_msm8625())
+		msm_pm_config_hw_before_swfi();
+
+	msm_arch_idle();
+
+	if (ramp_acpu) {
+		MSM_PM_DPRINTK(MSM_PM_DEBUG_CLOCK, KERN_INFO,
+			"%s(): restore clock rate to %lu\n", __func__,
+			saved_acpuclk_rate);
+		if (acpuclk_set_rate(smp_processor_id(), saved_acpuclk_rate,
+				SETRATE_SWFI) < 0)
+			printk(KERN_ERR
+				"%s(): failed to restore clock rate(%lu)\n",
+				__func__, saved_acpuclk_rate);
+	}
+
+	return 0;
+}
+
+static int64_t msm_pm_timer_enter_suspend(int64_t *period)
+{
+	int time = 0;
+
+	time = msm_timer_get_sclk_time(period);
+	if (!time)
+		pr_err("%s: Unable to read sclk.\n", __func__);
+		return time;
+}
+
+static int64_t msm_pm_timer_exit_suspend(int64_t time, int64_t period)
+{
+
+	if (time != 0) {
+		int64_t end_time = msm_timer_get_sclk_time(NULL);
+		if (end_time != 0) {
+			time = end_time - time;
+			if (time < 0)
+				time += period;
+			} else
+				time = 0;
+		}
+	return time;
+}
+
+/******************************************************************************
+ * External Idle/Suspend Functions
+ *****************************************************************************/
+
+/*
+ * Put CPU in low power mode.
+ */
+void arch_idle(void)
+{
+	bool allow[MSM_PM_SLEEP_MODE_NR];
+	uint32_t sleep_limit = SLEEP_LIMIT_NONE;
+
+	int64_t timer_expiration;
+	int latency_qos;
+	int ret;
+	int i;
+	unsigned int cpu;
+	int64_t t1;
+	static DEFINE_PER_CPU(int64_t, t2);
+	int exit_stat;
+
+	if (!atomic_read(&msm_pm_init_done))
+		return;
+
+	cpu = smp_processor_id();
+	latency_qos = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
+	/* get the next timer expiration */
+	timer_expiration = ktime_to_ns(tick_nohz_get_sleep_length());
+
+	t1 = ktime_to_ns(ktime_get());
+	msm_pm_add_stat(MSM_PM_STAT_NOT_IDLE, t1 - __get_cpu_var(t2));
+	msm_pm_add_stat(MSM_PM_STAT_REQUESTED_IDLE, timer_expiration);
+	exit_stat = MSM_PM_STAT_IDLE_SPIN;
+
+	for (i = 0; i < ARRAY_SIZE(allow); i++)
+		allow[i] = true;
+
+	if (num_online_cpus() > 1 ||
+		(timer_expiration < msm_pm_idle_sleep_min_time) ||
+#ifdef CONFIG_HAS_WAKELOCK
+		has_wake_lock(WAKE_LOCK_IDLE) ||
+#endif
+		!msm_pm_irq_extns->idle_sleep_allowed()) {
+		allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = false;
+		allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN] = false;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(allow); i++) {
+		struct msm_pm_platform_data *mode =
+					&msm_pm_modes[MSM_PM_MODE(cpu, i)];
+		if (!mode->idle_supported || !mode->idle_enabled ||
+			mode->latency >= latency_qos ||
+			mode->residency * 1000ULL >= timer_expiration)
+			allow[i] = false;
+	}
+
+	if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] ||
+		allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]) {
+		uint32_t wait_us = CONFIG_MSM_IDLE_WAIT_ON_MODEM;
+		while (msm_pm_modem_busy() && wait_us) {
+			if (wait_us > 100) {
+				udelay(100);
+				wait_us -= 100;
+			} else {
+				udelay(wait_us);
+				wait_us = 0;
+			}
+		}
+
+		if (msm_pm_modem_busy()) {
+			allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = false;
+			allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]
+				= false;
+		}
+	}
+
+	MSM_PM_DPRINTK(MSM_PM_DEBUG_IDLE, KERN_INFO,
+		"%s(): latency qos %d, next timer %lld, sleep limit %u\n",
+		__func__, latency_qos, timer_expiration, sleep_limit);
+
+	for (i = 0; i < ARRAY_SIZE(allow); i++)
+		MSM_PM_DPRINTK(MSM_PM_DEBUG_IDLE, KERN_INFO,
+			"%s(): allow %s: %d\n", __func__,
+			msm_pm_sleep_mode_labels[i], (int)allow[i]);
+
+	if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] ||
+		allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]) {
+		/* Sync the timer with SCLK, it is needed only for modem
+		 * assissted pollapse case.
+		 */
+		int64_t next_timer_exp = msm_timer_enter_idle();
+		uint32_t sleep_delay;
+		bool low_power = false;
+
+		sleep_delay = (uint32_t) msm_pm_convert_and_cap_time(
+			next_timer_exp, MSM_PM_SLEEP_TICK_LIMIT);
+
+		if (sleep_delay == 0) /* 0 would mean infinite time */
+			sleep_delay = 1;
+
+		if (!allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE])
+			sleep_limit = SLEEP_LIMIT_NO_TCXO_SHUTDOWN;
+
+#if defined(CONFIG_MSM_MEMORY_LOW_POWER_MODE_IDLE_ACTIVE)
+		sleep_limit |= SLEEP_RESOURCE_MEMORY_BIT1;
+#elif defined(CONFIG_MSM_MEMORY_LOW_POWER_MODE_IDLE_RETENTION)
+		sleep_limit |= SLEEP_RESOURCE_MEMORY_BIT0;
+#endif
+
+		ret = msm_pm_power_collapse(true, sleep_delay, sleep_limit);
+		low_power = (ret != -EBUSY && ret != -ETIMEDOUT);
+		msm_timer_exit_idle(low_power);
+
+		if (ret)
+			exit_stat = MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE;
+		else {
+			exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
+			msm_pm_sleep_limit = sleep_limit;
+		}
+	} else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
+		ret = msm_pm_power_collapse_standalone(true);
+		exit_stat = ret ?
+			MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE :
+			MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
+	} else if (allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT]) {
+		ret = msm_pm_swfi(true);
+		if (ret)
+			while (!msm_pm_irq_extns->irq_pending())
+				udelay(1);
+		exit_stat = ret ? MSM_PM_STAT_IDLE_SPIN : MSM_PM_STAT_IDLE_WFI;
+	} else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
+		msm_pm_swfi(false);
+		exit_stat = MSM_PM_STAT_IDLE_WFI;
+	} else {
+		while (!msm_pm_irq_extns->irq_pending())
+			udelay(1);
+		exit_stat = MSM_PM_STAT_IDLE_SPIN;
+	}
+
+	__get_cpu_var(t2) = ktime_to_ns(ktime_get());
+	msm_pm_add_stat(exit_stat, __get_cpu_var(t2) - t1);
+}
+
+/*
+ * Suspend the Apps processor.
+ *
+ * Return value:
+ *	-EPERM: Suspend happened by a not permitted core
+ *      -EAGAIN: modem reset occurred or early exit from suspend
+ *      -EBUSY: modem not ready for our suspend
+ *      -EINVAL: invalid sleep mode
+ *      -EIO: could not ramp Apps processor clock
+ *      -ETIMEDOUT: timed out waiting for modem's handshake
+ *      0: success
+ */
+static int msm_pm_enter(suspend_state_t state)
+{
+	bool allow[MSM_PM_SLEEP_MODE_NR];
+	uint32_t sleep_limit = SLEEP_LIMIT_NONE;
+	int ret = -EPERM;
+	int i;
+	int64_t period = 0;
+	int64_t time = 0;
+
+	/* Must executed by CORE0 */
+	if (smp_processor_id()) {
+		__WARN();
+		goto suspend_exit;
+	}
+
+	time = msm_pm_timer_enter_suspend(&period);
+
+	MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND, KERN_INFO,
+		"%s(): sleep limit %u\n", __func__, sleep_limit);
+
+	for (i = 0; i < ARRAY_SIZE(allow); i++)
+		allow[i] = true;
+
+	for (i = 0; i < ARRAY_SIZE(allow); i++) {
+		struct msm_pm_platform_data *mode;
+		mode = &msm_pm_modes[MSM_PM_MODE(0, i)];
+		if (!mode->suspend_supported || !mode->suspend_enabled)
+			allow[i] = false;
+	}
+
+	if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] ||
+		allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]) {
+		enum msm_pm_time_stats_id id;
+
+		clock_debug_print_enabled();
+
+#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE
+		if (msm_pm_sleep_time_override > 0) {
+			int64_t ns;
+			ns = NSEC_PER_SEC * (int64_t)msm_pm_sleep_time_override;
+			msm_pm_set_max_sleep_time(ns);
+			msm_pm_sleep_time_override = 0;
+		}
+#endif
+		if (!allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE])
+			sleep_limit = SLEEP_LIMIT_NO_TCXO_SHUTDOWN;
+
+#if defined(CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_ACTIVE)
+		sleep_limit |= SLEEP_RESOURCE_MEMORY_BIT1;
+#elif defined(CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_RETENTION)
+		sleep_limit |= SLEEP_RESOURCE_MEMORY_BIT0;
+#elif defined(CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_DEEP_POWER_DOWN)
+		if (get_msm_migrate_pages_status() != MEM_OFFLINE)
+			sleep_limit |= SLEEP_RESOURCE_MEMORY_BIT0;
+#endif
+
+		for (i = 0; i < 30 && msm_pm_modem_busy(); i++)
+			udelay(500);
+
+		ret = msm_pm_power_collapse(
+			false, msm_pm_max_sleep_time, sleep_limit);
+
+		if (ret)
+			id = MSM_PM_STAT_FAILED_SUSPEND;
+		else {
+			id = MSM_PM_STAT_SUSPEND;
+			msm_pm_sleep_limit = sleep_limit;
+		}
+
+		time = msm_pm_timer_exit_suspend(time, period);
+		msm_pm_add_stat(id, time);
+	} else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
+		ret = msm_pm_power_collapse_standalone(false);
+	} else if (allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT]) {
+		ret = msm_pm_swfi(true);
+		if (ret)
+			while (!msm_pm_irq_extns->irq_pending())
+				udelay(1);
+	} else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
+		msm_pm_swfi(false);
+	}
+
+suspend_exit:
+	MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND, KERN_INFO,
+		"%s(): return %d\n", __func__, ret);
+
+	return ret;
+}
+
+static struct platform_suspend_ops msm_pm_ops = {
+	.enter = msm_pm_enter,
+	.valid = suspend_valid_only_mem,
+};
+
+/* Hotplug the "non boot" CPU's and put
+ * the cores into low power mode
+ */
+void msm_pm_cpu_enter_lowpower(unsigned int cpu)
+{
+	bool allow[MSM_PM_SLEEP_MODE_NR];
+	int i;
+
+	for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
+		struct msm_pm_platform_data *mode;
+
+		mode = &msm_pm_modes[MSM_PM_MODE(cpu, i)];
+		allow[i] = mode->suspend_supported && mode->suspend_enabled;
+	}
+
+	MSM_PM_DPRINTK(MSM_PM_DEBUG_HOTPLUG, KERN_INFO,
+		"CPU%u: %s: shutting down cpu\n", cpu, __func__);
+
+	if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
+		msm_pm_power_collapse_standalone(false);
+	} else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
+		msm_pm_swfi(false);
+	} else {
+		MSM_PM_DPRINTK(MSM_PM_DEBUG_HOTPLUG, KERN_INFO,
+			"CPU%u: %s: shutting down failed!!!\n", cpu, __func__);
+	}
+}
+
+/******************************************************************************
+ * Restart Definitions
+ *****************************************************************************/
+
+static uint32_t restart_reason = 0x776655AA;
+
+static void msm_pm_power_off(void)
+{
+	msm_rpcrouter_close();
+	msm_proc_comm(PCOM_POWER_DOWN, 0, 0);
+	for (;;)
+		;
+}
+
+static void msm_pm_restart(char str, const char *cmd)
+{
+	msm_rpcrouter_close();
+	msm_proc_comm(PCOM_RESET_CHIP, &restart_reason, 0);
+
+	for (;;)
+		;
+}
+
+static int msm_reboot_call
+	(struct notifier_block *this, unsigned long code, void *_cmd)
+{
+	if ((code == SYS_RESTART) && _cmd) {
+		char *cmd = _cmd;
+		if (!strcmp(cmd, "bootloader")) {
+			restart_reason = 0x77665500;
+		} else if (!strcmp(cmd, "recovery")) {
+			restart_reason = 0x77665502;
+		} else if (!strcmp(cmd, "eraseflash")) {
+			restart_reason = 0x776655EF;
+		} else if (!strncmp(cmd, "oem-", 4)) {
+			unsigned code = simple_strtoul(cmd + 4, 0, 16) & 0xff;
+			restart_reason = 0x6f656d00 | code;
+		} else {
+			restart_reason = 0x77665501;
+		}
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block msm_reboot_notifier = {
+	.notifier_call = msm_reboot_call,
+};
+
+
+/*
+ * Initialize the power management subsystem.
+ *
+ * Return value:
+ *      -ENODEV: initialization failed
+ *      0: success
+ */
+static int __init msm_pm_init(void)
+{
+	int ret;
+	int val;
+	enum msm_pm_time_stats_id enable_stats[] = {
+		MSM_PM_STAT_REQUESTED_IDLE,
+		MSM_PM_STAT_IDLE_SPIN,
+		MSM_PM_STAT_IDLE_WFI,
+		MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
+		MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE,
+		MSM_PM_STAT_IDLE_POWER_COLLAPSE,
+		MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE,
+		MSM_PM_STAT_SUSPEND,
+		MSM_PM_STAT_FAILED_SUSPEND,
+		MSM_PM_STAT_NOT_IDLE,
+	};
+
+#ifdef CONFIG_CPU_V7
+	pgd_t *pc_pgd;
+	pmd_t *pmd;
+	unsigned long pmdval;
+	unsigned long exit_phys;
+
+	exit_phys = virt_to_phys(msm_pm_collapse_exit);
+
+	/* Page table for cores to come back up safely. */
+	pc_pgd = pgd_alloc(&init_mm);
+	if (!pc_pgd)
+		return -ENOMEM;
+	pmd = pmd_offset(pud_offset(pc_pgd + pgd_index(exit_phys), exit_phys),
+			 exit_phys);
+	pmdval = (exit_phys & PGDIR_MASK) |
+		     PMD_TYPE_SECT | PMD_SECT_AP_WRITE;
+	pmd[0] = __pmd(pmdval);
+	pmd[1] = __pmd(pmdval + (1 << (PGDIR_SHIFT - 1)));
+
+	msm_saved_state_phys =
+		allocate_contiguous_ebi_nomap(CPU_SAVED_STATE_SIZE *
+					      num_possible_cpus(), 4);
+	if (!msm_saved_state_phys)
+		return -ENOMEM;
+	msm_saved_state = ioremap_nocache(msm_saved_state_phys,
+					  CPU_SAVED_STATE_SIZE *
+					  num_possible_cpus());
+	if (!msm_saved_state)
+		return -ENOMEM;
+
+	/* It is remotely possible that the code in msm_pm_collapse_exit()
+	 * which turns on the MMU with this mapping is in the
+	 * next even-numbered megabyte beyond the
+	 * start of msm_pm_collapse_exit().
+	 * Map this megabyte in as well.
+	 */
+	pmd[2] = __pmd(pmdval + (2 << (PGDIR_SHIFT - 1)));
+	flush_pmd_entry(pmd);
+	msm_pm_pc_pgd = virt_to_phys(pc_pgd);
+	clean_caches((unsigned long)&msm_pm_pc_pgd, sizeof(msm_pm_pc_pgd),
+		     virt_to_phys(&msm_pm_pc_pgd));
+#endif
+
+	pm_power_off = msm_pm_power_off;
+	arm_pm_restart = msm_pm_restart;
+	register_reboot_notifier(&msm_reboot_notifier);
+
+	msm_pm_smem_data = smem_alloc(SMEM_APPS_DEM_SLAVE_DATA,
+		sizeof(*msm_pm_smem_data));
+	if (msm_pm_smem_data == NULL) {
+		printk(KERN_ERR "%s: failed to get smsm_data\n", __func__);
+		return -ENODEV;
+	}
+
+	ret = msm_timer_init_time_sync(msm_pm_timeout);
+	if (ret)
+		return ret;
+
+	ret = smsm_change_intr_mask(SMSM_POWER_MASTER_DEM, 0xFFFFFFFF, 0);
+	if (ret) {
+		printk(KERN_ERR "%s: failed to clear interrupt mask, %d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	if (cpu_is_msm8625()) {
+		target_type = TARGET_IS_8625;
+		clean_caches((unsigned long)&target_type, sizeof(target_type),
+				virt_to_phys(&target_type));
+
+		/*
+		 * Configure the MPA5_GDFS_CNT_VAL register for
+		 * DBGPWRUPEREQ_OVERRIDE[17:16] = Override the
+		 * DBGNOPOWERDN for each cpu.
+		 * MPA5_GDFS_CNT_VAL[9:0] = Delay counter for
+		 * GDFS control.
+		 */
+		val = 0x00030002;
+		__raw_writel(val, (MSM_CFG_CTL_BASE + 0x38));
+
+		l2x0_base_addr = MSM_L2CC_BASE;
+	}
+
+#ifdef CONFIG_MSM_MEMORY_LOW_POWER_MODE
+	/* The wakeup_reason field is overloaded during initialization time
+	   to signal Modem that Apps will control the low power modes of
+	   the memory.
+	 */
+	msm_pm_smem_data->wakeup_reason = 1;
+	smsm_change_state(SMSM_APPS_DEM, 0, DEM_SLAVE_SMSM_RUN);
+#endif
+
+	BUG_ON(msm_pm_modes == NULL);
+
+	suspend_set_ops(&msm_pm_ops);
+
+	msm_pm_mode_sysfs_add();
+	msm_pm_add_stats(enable_stats, ARRAY_SIZE(enable_stats));
+
+	atomic_set(&msm_pm_init_done, 1);
+	return 0;
+}
+
+late_initcall_sync(msm_pm_init);
diff --git a/arch/arm/mach-msm/pmic.c b/arch/arm/mach-msm/pmic.c
new file mode 100644
index 0000000..1e92710
--- /dev/null
+++ b/arch/arm/mach-msm/pmic.c
@@ -0,0 +1,1286 @@
+/* Copyright (c) 2009, 2011 Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <linux/err.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+
+#include <mach/pmic.h>
+
+#include "smd_rpcrouter.h"
+
+#define TRACE_PMIC 0
+
+#if TRACE_PMIC
+#define PMIC(x...) printk(KERN_INFO "[PMIC] " x)
+#else
+#define PMIC(x...) do {} while (0)
+#endif
+
+
+#define LIB_NULL_PROC 0
+#define LIB_RPC_GLUE_CODE_INFO_REMOTE_PROC 1
+#define LP_MODE_CONTROL_PROC 2
+#define VREG_SET_LEVEL_PROC 3
+#define VREG_PULL_DOWN_SWITCH_PROC 4
+#define SECURE_MPP_CONFIG_DIGITAL_OUTPUT_PROC 5
+#define SECURE_MPP_CONFIG_I_SINK_PROC 6
+#define RTC_START_PROC 7
+#define RTC_STOP_PROC 8
+#define RTC_GET_TIME_PROC 9
+#define RTC_ENABLE_ALARM_PROC 10
+#define RTC_DISABLE_ALARM_PROC 11
+#define RTC_GET_ALARM_TIME_PROC 12
+#define RTC_GET_ALARM_STATUS_PROC 13
+#define RTC_SET_TIME_ADJUST_PROC 14
+#define RTC_GET_TIME_ADJUST_PROC 15
+#define SET_LED_INTENSITY_PROC 16
+#define FLASH_LED_SET_CURRENT_PROC 17
+#define FLASH_LED_SET_MODE_PROC 18
+#define FLASH_LED_SET_POLARITY_PROC 19
+#define SPEAKER_CMD_PROC 20
+#define SET_SPEAKER_GAIN_PROC 21
+#define VIB_MOT_SET_VOLT_PROC 22
+#define VIB_MOT_SET_MODE_PROC 23
+#define VIB_MOT_SET_POLARITY_PROC 24
+#define VID_EN_PROC 25
+#define VID_IS_EN_PROC 26
+#define VID_LOAD_DETECT_EN_PROC 27
+#define MIC_EN_PROC 28
+#define MIC_IS_EN_PROC 29
+#define MIC_SET_VOLT_PROC 30
+#define MIC_GET_VOLT_PROC 31
+#define SPKR_EN_RIGHT_CHAN_PROC 32
+#define SPKR_IS_RIGHT_CHAN_EN_PROC 33
+#define SPKR_EN_LEFT_CHAN_PROC 34
+#define SPKR_IS_LEFT_CHAN_EN_PROC 35
+#define SET_SPKR_CONFIGURATION_PROC 36
+#define GET_SPKR_CONFIGURATION_PROC 37
+#define SPKR_GET_GAIN_PROC 38
+#define SPKR_IS_EN_PROC 39
+#define SPKR_EN_MUTE_PROC 40
+#define SPKR_IS_MUTE_EN_PROC 41
+#define SPKR_SET_DELAY_PROC 42
+#define SPKR_GET_DELAY_PROC 43
+#define SECURE_MPP_CONFIG_DIGITAL_INPUT_PROC 44
+#define SET_SPEAKER_DELAY_PROC 45
+#define SPEAKER_1K6_ZIN_ENABLE_PROC 46
+#define SPKR_SET_MUX_HPF_CORNER_FREQ_PROC 47
+#define SPKR_GET_MUX_HPF_CORNER_FREQ_PROC 48
+#define SPKR_IS_RIGHT_LEFT_CHAN_ADDED_PROC 49
+#define SPKR_EN_STEREO_PROC 50
+#define SPKR_IS_STEREO_EN_PROC 51
+#define SPKR_SELECT_USB_WITH_HPF_20HZ_PROC 52
+#define SPKR_IS_USB_WITH_HPF_20HZ_PROC 53
+#define SPKR_BYPASS_MUX_PROC 54
+#define SPKR_IS_MUX_BYPASSED_PROC 55
+#define SPKR_EN_HPF_PROC 56
+#define SPKR_IS_HPF_EN_PROC 57
+#define SPKR_EN_SINK_CURR_FROM_REF_VOLT_CIR_PROC 58
+#define SPKR_IS_SINK_CURR_FROM_REF_VOLT_CIR_EN_PROC 59
+#define SPKR_ADD_RIGHT_LEFT_CHAN_PROC 60
+#define SPKR_SET_GAIN_PROC 61
+#define SPKR_EN_PROC 62
+#define HSED_SET_PERIOD_PROC 63
+#define HSED_SET_HYSTERESIS_PROC 64
+#define HSED_SET_CURRENT_THRESHOLD_PROC 65
+#define HSED_ENABLE_PROC 66
+#define HIGH_CURRENT_LED_SET_CURRENT_PROC 67
+#define HIGH_CURRENT_LED_SET_POLARITY_PROC 68
+#define HIGH_CURRENT_LED_SET_MODE_PROC 69
+#define LP_FORCE_LPM_CONTROL_PROC 70
+#define LOW_CURRENT_LED_SET_EXT_SIGNAL_PROC 71
+#define LOW_CURRENT_LED_SET_CURRENT_PROC 72
+#define SPKR_SET_VSEL_LDO_PROC 86
+#define HP_SPKR_CTRL_AUX_GAIN_INPUT_PROC 87
+#define HP_SPKR_MSTR_EN_PROC 88
+#define SPKR_SET_BOOST_PROC 89
+#define HP_SPKR_PRM_IN_EN_PROC 90
+#define HP_SPKR_CTRL_PRM_GAIN_INPUT_PROC 91
+#define HP_SPKR_MUTE_EN_PROC 92
+#define SPKR_BYPASS_EN_PROC 93
+#define HP_SPKR_AUX_IN_EN_PROC 94
+#define XO_CORE_FORCE_ENABLE 96
+#define GPIO_SET_CURRENT_SOURCE_PULLS_PROC 97
+#define GPIO_SET_GPIO_DIRECTION_INPUT_PROC 98
+#define GPIO_SET_EXT_PIN_CONFIG_PROC 99
+#define GPIO_SET_GPIO_CONFIG_PROC 100
+#define GPIO_CONFIG_DIGITAL_OUTPUT_PROC 101
+#define GPIO_GET_GPIO_DIRECTION_PROC 102
+#define GPIO_SET_SLEEP_CLK_CONFIG_PROC 103
+#define GPIO_CONFIG_DIGITAL_INPUT_PROC 104
+#define GPIO_SET_OUTPUT_BUFFER_CONFIGURATION_PROC 105
+#define GPIO_SET_PROC 106
+#define GPIO_CONFIG_MODE_SELECTION_PROC 107
+#define GPIO_SET_INVERSION_CONFIGURATION_PROC 108
+#define GPIO_SET_GPIO_DIRECTION_OUTPUT_PROC 109
+#define GPIO_SET_SOURCE_CONFIGURATION_PROC 110
+#define GPIO_GET_PROC 111
+#define GPIO_SET_VOLTAGE_SOURCE_PROC 112
+#define GPIO_SET_OUTPUT_BUFFER_DRIVE_STRENGTH_PROC 113
+
+/* rpc related */
+#define PMIC_RPC_TIMEOUT (5*HZ)
+
+#define PMIC_PDEV_NAME	"rs00010001:00000000"
+#define PMIC_RPC_PROG	0x30000061
+#define PMIC_RPC_VER_1_1	0x00010001
+#define PMIC_RPC_VER_2_1	0x00020001
+#define PMIC_RPC_VER_3_1	0x00030001
+#define PMIC_RPC_VER_5_1	0x00050001
+#define PMIC_RPC_VER_6_1	0x00060001
+
+/* error bit flags defined by modem side */
+#define PM_ERR_FLAG__PAR1_OUT_OF_RANGE		(0x0001)
+#define PM_ERR_FLAG__PAR2_OUT_OF_RANGE		(0x0002)
+#define PM_ERR_FLAG__PAR3_OUT_OF_RANGE		(0x0004)
+#define PM_ERR_FLAG__PAR4_OUT_OF_RANGE		(0x0008)
+#define PM_ERR_FLAG__PAR5_OUT_OF_RANGE		(0x0010)
+
+#define PM_ERR_FLAG__ALL_PARMS_OUT_OF_RANGE   	(0x001F) /* all 5 previous */
+
+#define PM_ERR_FLAG__SBI_OPT_ERR		(0x0080)
+#define PM_ERR_FLAG__FEATURE_NOT_SUPPORTED	(0x0100)
+
+#define	PMIC_BUFF_SIZE		256
+
+struct pmic_buf {
+	char *start;		/* buffer start addr */
+	char *end;		/* buffer end addr */
+	int size;		/* buffer size */
+	char *data;		/* payload begin addr */
+	int len;		/* payload len */
+};
+
+static DEFINE_MUTEX(pmic_mtx);
+
+struct pmic_ctrl {
+	int inited;
+	struct pmic_buf	tbuf;
+	struct pmic_buf	rbuf;
+	struct msm_rpc_endpoint *endpoint;
+};
+
+static struct pmic_ctrl pmic_ctrl = {
+	.inited = -1,
+};
+
+/* Add newer versions at the top of array */
+static const unsigned int rpc_vers[] = {
+	PMIC_RPC_VER_6_1,
+	PMIC_RPC_VER_5_1,
+	PMIC_RPC_VER_3_1,
+	PMIC_RPC_VER_2_1,
+	PMIC_RPC_VER_1_1,
+};
+
+static int pmic_rpc_req_reply(struct pmic_buf *tbuf,
+				struct pmic_buf *rbuf, int proc);
+static int pmic_rpc_set_only(uint data0, uint data1, uint data2,
+				uint data3, int num, int proc);
+static int pmic_rpc_set_struct(int, uint, uint *data, uint size, int proc);
+static int pmic_rpc_set_get(uint setdata, uint *getdata, int size, int proc);
+static int pmic_rpc_get_only(uint *getdata, int size, int proc);
+
+static int pmic_buf_init(void)
+{
+	struct pmic_ctrl *pm = &pmic_ctrl;
+
+	memset(&pmic_ctrl, 0, sizeof(pmic_ctrl));
+
+	pm->tbuf.start = kmalloc(PMIC_BUFF_SIZE, GFP_KERNEL);
+	if (pm->tbuf.start == NULL) {
+		printk(KERN_ERR "%s:%u\n", __func__, __LINE__);
+		return -ENOMEM;
+	}
+
+	pm->tbuf.data = pm->tbuf.start;
+	pm->tbuf.size = PMIC_BUFF_SIZE;
+	pm->tbuf.end = pm->tbuf.start + PMIC_BUFF_SIZE;
+	pm->tbuf.len = 0;
+
+	pm->rbuf.start = kmalloc(PMIC_BUFF_SIZE, GFP_KERNEL);
+	if (pm->rbuf.start == NULL) {
+		kfree(pm->tbuf.start);
+		printk(KERN_ERR "%s:%u\n", __func__, __LINE__);
+		return -ENOMEM;
+	}
+	pm->rbuf.data = pm->rbuf.start;
+	pm->rbuf.size = PMIC_BUFF_SIZE;
+	pm->rbuf.end = pm->rbuf.start + PMIC_BUFF_SIZE;
+	pm->rbuf.len = 0;
+
+	pm->inited = 1;
+
+	return 0;
+}
+
+static inline void pmic_buf_reserve(struct pmic_buf *bp, int len)
+{
+	bp->data += len;
+	bp->len  += len;
+}
+
+static inline void pmic_buf_reset(struct pmic_buf *bp)
+{
+	bp->data = bp->start;
+	bp->len = 0;
+}
+
+static int modem_to_linux_err(uint err)
+{
+	if (err == 0)
+		return 0;
+
+	if (err & PM_ERR_FLAG__ALL_PARMS_OUT_OF_RANGE)
+		return -EINVAL;	/* PM_ERR_FLAG__PAR[1..5]_OUT_OF_RANGE */
+
+	if (err & PM_ERR_FLAG__SBI_OPT_ERR)
+		return -EIO;
+
+	if (err & PM_ERR_FLAG__FEATURE_NOT_SUPPORTED)
+		return -ENOSYS;
+
+	return -EPERM;
+}
+
+static int pmic_put_tx_data(struct pmic_buf *tp, uint datav)
+{
+	uint *lp;
+
+	if ((tp->size - tp->len) < sizeof(datav)) {
+		printk(KERN_ERR "%s: OVERFLOW size=%d len=%d\n",
+					__func__, tp->size, tp->len);
+		return -1;
+	}
+
+	lp = (uint *)tp->data;
+	*lp = cpu_to_be32(datav);
+	tp->data += sizeof(datav);
+	tp->len += sizeof(datav);
+
+	return sizeof(datav);
+}
+
+static int pmic_pull_rx_data(struct pmic_buf *rp, uint *datap)
+{
+	uint *lp;
+
+	if (rp->len < sizeof(*datap)) {
+		printk(KERN_ERR "%s: UNDERRUN len=%d\n", __func__, rp->len);
+		return -1;
+	}
+	lp = (uint *)rp->data;
+	*datap = be32_to_cpu(*lp);
+	rp->data += sizeof(*datap);
+	rp->len -= sizeof(*datap);
+
+	return sizeof(*datap);
+}
+
+
+/*
+ *
+ *   +-------------------+
+ *   |  PROC cmd layer   |
+ *   +-------------------+
+ *   |     RPC layer     |
+ *   +-------------------+
+ *
+ * 1) network byte order
+ * 2) RPC request header(40 bytes) and RPC reply header (24 bytes)
+ * 3) each transaction consists of a request and reply
+ * 3) PROC (comamnd) layer has its own sub-protocol defined
+ * 4) sub-protocol can be grouped to follwoing 7 cases:
+ *  	a) set one argument, no get
+ * 	b) set two argument, no get
+ * 	c) set three argument, no get
+ * 	d) set a struct, no get
+ * 	e) set a argument followed by a struct, no get
+ * 	f) set a argument, get a argument
+ * 	g) no set, get either a argument or a struct
+ */
+
+/**
+ * pmic_rpc_req_reply() - send request and wait for reply
+ * @tbuf:	buffer contains arguments
+ * @rbuf:	buffer to be filled with arguments at reply
+ * @proc:	command/request id
+ *
+ * This function send request to modem and wait until reply received
+ */
+static int pmic_rpc_req_reply(struct pmic_buf *tbuf, struct pmic_buf *rbuf,
+	int	proc)
+{
+	struct pmic_ctrl *pm = &pmic_ctrl;
+	int	ans, len, i;
+
+
+	if ((pm->endpoint == NULL) || IS_ERR(pm->endpoint)) {
+		for (i = 0; i < ARRAY_SIZE(rpc_vers); i++) {
+			pm->endpoint = msm_rpc_connect_compatible(PMIC_RPC_PROG,
+					rpc_vers[i], MSM_RPC_UNINTERRUPTIBLE);
+
+			if (IS_ERR(pm->endpoint)) {
+				ans  = PTR_ERR(pm->endpoint);
+				printk(KERN_ERR "%s: init rpc failed! ans = %d"
+						" for 0x%x version, fallback\n",
+						__func__, ans, rpc_vers[i]);
+			} else {
+				printk(KERN_DEBUG "%s: successfully connected"
+					" to 0x%x rpc version\n",
+					 __func__, rpc_vers[i]);
+				break;
+			}
+		}
+	}
+
+	if (IS_ERR(pm->endpoint)) {
+		ans  = PTR_ERR(pm->endpoint);
+		return ans;
+	}
+
+	/*
+	* data is point to next available space at this moment,
+	* move it back to beginning of request header and increase
+	* the length
+	*/
+	tbuf->data = tbuf->start;
+
+	len = msm_rpc_call_reply(pm->endpoint, proc,
+				tbuf->data, tbuf->len,
+				rbuf->data, rbuf->size,
+				PMIC_RPC_TIMEOUT);
+
+	if (len <= 0) {
+		printk(KERN_ERR "%s: rpc failed! len = %d\n", __func__, len);
+		pm->endpoint = NULL;	/* re-connect later ? */
+		return len;
+	}
+
+	rbuf->len = len;
+	/* strip off rpc_reply_hdr */
+	rbuf->data += sizeof(struct rpc_reply_hdr);
+	rbuf->len -= sizeof(struct rpc_reply_hdr);
+
+	return rbuf->len;
+}
+
+/**
+ * pmic_rpc_set_only() - set arguments and no get
+ * @data0:	first argumrnt
+ * @data1:	second argument
+ * @data2:	third argument
+ * @data3:	fourth argument
+ * @num:	number of argument
+ * @proc:	command/request id
+ *
+ * This function covers case a, b, and c
+ */
+static int pmic_rpc_set_only(uint data0, uint data1, uint data2, uint data3,
+		int num, int proc)
+{
+	struct pmic_ctrl *pm = &pmic_ctrl;
+	struct pmic_buf	*tp;
+	struct pmic_buf	*rp;
+	int	stat;
+
+
+	if (mutex_lock_interruptible(&pmic_mtx))
+		return -ERESTARTSYS;
+
+	if (pm->inited <= 0) {
+		stat = pmic_buf_init();
+		if (stat < 0) {
+			mutex_unlock(&pmic_mtx);
+			return stat;
+		}
+	}
+
+	tp = &pm->tbuf;
+	rp = &pm->rbuf;
+
+	pmic_buf_reset(tp);
+	pmic_buf_reserve(tp, sizeof(struct rpc_request_hdr));
+	pmic_buf_reset(rp);
+
+	if (num > 0)
+		pmic_put_tx_data(tp, data0);
+
+	if (num > 1)
+		pmic_put_tx_data(tp, data1);
+
+	if (num > 2)
+		pmic_put_tx_data(tp, data2);
+
+	if (num > 3)
+		pmic_put_tx_data(tp, data3);
+
+	stat = pmic_rpc_req_reply(tp, rp, proc);
+	if (stat < 0) {
+		mutex_unlock(&pmic_mtx);
+		return stat;
+	}
+
+	pmic_pull_rx_data(rp, &stat);	/* result from server */
+
+	mutex_unlock(&pmic_mtx);
+
+	return modem_to_linux_err(stat);
+}
+
+/**
+ * pmic_rpc_set_struct() - set the whole struct
+ * @xflag:	indicates an extra argument
+ * @xdata:	the extra argument
+ * @*data:	starting address of struct
+ * @size:	size of struct
+ * @proc:	command/request id
+ *
+ * This fucntion covers case d and e
+ */
+static int pmic_rpc_set_struct(int xflag, uint xdata, uint *data, uint size,
+	int proc)
+{
+	struct pmic_ctrl *pm = &pmic_ctrl;
+	struct pmic_buf *tp;
+	struct pmic_buf	*rp;
+	int	i, stat, more_data;
+
+
+	if (mutex_lock_interruptible(&pmic_mtx))
+		return -ERESTARTSYS;
+
+	if (pm->inited <= 0) {
+		stat = pmic_buf_init();
+		if (stat < 0) {
+			mutex_unlock(&pmic_mtx);
+			return stat;
+		}
+	}
+
+	tp = &pm->tbuf;
+	rp = &pm->rbuf;
+
+	pmic_buf_reset(tp);
+	pmic_buf_reserve(tp, sizeof(struct rpc_request_hdr));
+	pmic_buf_reset(rp);
+
+	if (xflag)
+		pmic_put_tx_data(tp, xdata);
+
+	more_data = 1; 		/* tell server there have more data followed */
+	pmic_put_tx_data(tp, more_data);
+
+	size >>= 2;
+	for (i = 0; i < size; i++) {
+		pmic_put_tx_data(tp, *data);
+		data++;
+	}
+
+	stat = pmic_rpc_req_reply(tp, rp, proc);
+	if (stat < 0) {
+		mutex_unlock(&pmic_mtx);
+		return stat;
+	}
+
+	pmic_pull_rx_data(rp, &stat);	/* result from server */
+
+	mutex_unlock(&pmic_mtx);
+
+	return modem_to_linux_err(stat);
+}
+
+/**
+ * pmic_rpc_set_get() - set one argument and get one argument
+ * @setdata:	set argument
+ * @*getdata:	memory to store argumnet
+ * @size:	size of memory
+ * @proc:	command/request id
+ *
+ * This function covers case f
+ */
+static int pmic_rpc_set_get(uint setdata, uint *getdata, int size, int proc)
+{
+	struct pmic_ctrl *pm = &pmic_ctrl;
+	struct pmic_buf	*tp;
+	struct pmic_buf	*rp;
+	unsigned int *lp;
+	int i, stat, more_data;
+
+
+	if (mutex_lock_interruptible(&pmic_mtx))
+		return -ERESTARTSYS;
+
+	if (pm->inited <= 0) {
+		stat = pmic_buf_init();
+		if (stat < 0) {
+			mutex_unlock(&pmic_mtx);
+			return stat;
+		}
+	}
+
+	tp = &pm->tbuf;
+	rp = &pm->rbuf;
+
+	pmic_buf_reset(tp);
+	pmic_buf_reserve(tp, sizeof(struct rpc_request_hdr));
+	pmic_buf_reset(rp);
+
+	pmic_put_tx_data(tp, setdata);
+
+	/*
+	* more_data = TRUE to ask server reply with requested datum
+	* otherwise, server will reply without datum
+	*/
+	more_data = (getdata != NULL);
+	pmic_put_tx_data(tp, more_data);
+
+	stat = pmic_rpc_req_reply(tp, rp, proc);
+	if (stat < 0) {
+		mutex_unlock(&pmic_mtx);
+		return stat;
+	}
+
+	pmic_pull_rx_data(rp, &stat);		/* result from server */
+	pmic_pull_rx_data(rp, &more_data);
+
+	if (more_data) { 				/* more data followed */
+		size >>= 2;
+		lp = getdata;
+		for (i = 0; i < size; i++) {
+			if (pmic_pull_rx_data(rp, lp++) < 0)
+				break;	/* not supposed to happen */
+		}
+	}
+
+	mutex_unlock(&pmic_mtx);
+
+	return modem_to_linux_err(stat);
+}
+
+/**
+ * pmic_rpc_get_only() - get one or more than one arguments
+ * @*getdata:	memory to store arguments
+ * @size:	size of mmory
+ * @proc:	command/request id
+ *
+ * This function covers case g
+ */
+static int pmic_rpc_get_only(uint *getdata, int size, int proc)
+{
+	struct pmic_ctrl *pm = &pmic_ctrl;
+	struct pmic_buf *tp;
+	struct pmic_buf *rp;
+	unsigned int *lp;
+	int	i, stat, more_data;
+
+
+	if (mutex_lock_interruptible(&pmic_mtx))
+		return -ERESTARTSYS;
+
+	if (pm->inited <= 0) {
+		stat = pmic_buf_init();
+		if (stat < 0) {
+			mutex_unlock(&pmic_mtx);
+			return stat;
+		}
+	}
+
+	tp = &pm->tbuf;
+	rp = &pm->rbuf;
+
+	pmic_buf_reset(tp);
+	pmic_buf_reserve(tp, sizeof(struct rpc_request_hdr));
+	pmic_buf_reset(rp);
+
+	/*
+	* more_data = TRUE to ask server reply with requested datum
+	* otherwise, server will reply without datum
+	*/
+	more_data = (getdata != NULL);
+	pmic_put_tx_data(tp, more_data);
+
+	stat = pmic_rpc_req_reply(tp, rp, proc);
+	if (stat < 0) {
+		mutex_unlock(&pmic_mtx);
+		return stat;
+	}
+
+	pmic_pull_rx_data(rp, &stat);		/* result from server */
+	pmic_pull_rx_data(rp, &more_data);
+
+	if (more_data) { 				/* more data followed */
+		size >>= 2;
+		lp = getdata;
+		for (i = 0; i < size; i++) {
+			if (pmic_pull_rx_data(rp, lp++) < 0)
+				break;	/* not supposed to happen */
+		}
+	}
+
+	mutex_unlock(&pmic_mtx);
+
+	return modem_to_linux_err(stat);
+}
+
+
+int pmic_lp_mode_control(enum switch_cmd cmd, enum vreg_lp_id id)
+{
+	return pmic_rpc_set_only(cmd, id, 0, 0, 2, LP_MODE_CONTROL_PROC);
+}
+EXPORT_SYMBOL(pmic_lp_mode_control);
+
+int pmic_vreg_set_level(enum vreg_id vreg, int level)
+{
+	return pmic_rpc_set_only(vreg, level, 0, 0, 2, VREG_SET_LEVEL_PROC);
+}
+EXPORT_SYMBOL(pmic_vreg_set_level);
+
+int pmic_vreg_pull_down_switch(enum switch_cmd cmd, enum vreg_pdown_id id)
+{
+	return pmic_rpc_set_only(cmd, id, 0, 0, 2, VREG_PULL_DOWN_SWITCH_PROC);
+}
+EXPORT_SYMBOL(pmic_vreg_pull_down_switch);
+
+int pmic_secure_mpp_control_digital_output(enum mpp_which which,
+	enum mpp_dlogic_level level,
+	enum mpp_dlogic_out_ctrl out)
+{
+	return pmic_rpc_set_only(which, level, out, 0, 3,
+				SECURE_MPP_CONFIG_DIGITAL_OUTPUT_PROC);
+}
+EXPORT_SYMBOL(pmic_secure_mpp_control_digital_output);
+
+int pmic_secure_mpp_config_i_sink(enum mpp_which which,
+				enum mpp_i_sink_level level,
+				enum mpp_i_sink_switch onoff)
+{
+	return pmic_rpc_set_only(which, level, onoff, 0, 3,
+				SECURE_MPP_CONFIG_I_SINK_PROC);
+}
+EXPORT_SYMBOL(pmic_secure_mpp_config_i_sink);
+
+int pmic_secure_mpp_config_digital_input(enum mpp_which which,
+	enum mpp_dlogic_level level,
+	enum mpp_dlogic_in_dbus dbus)
+{
+	return pmic_rpc_set_only(which, level, dbus, 0, 3,
+				SECURE_MPP_CONFIG_DIGITAL_INPUT_PROC);
+}
+EXPORT_SYMBOL(pmic_secure_mpp_config_digital_input);
+
+int pmic_rtc_start(struct rtc_time *time)
+{
+	return pmic_rpc_set_struct(0, 0, (uint *)time, sizeof(*time),
+				RTC_START_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_start);
+
+int pmic_rtc_stop(void)
+{
+	return pmic_rpc_set_only(0, 0, 0, 0, 0, RTC_STOP_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_stop);
+
+int pmic_rtc_get_time(struct rtc_time *time)
+{
+	return pmic_rpc_get_only((uint *)time, sizeof(*time),
+				RTC_GET_TIME_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_get_time);
+
+int pmic_rtc_enable_alarm(enum rtc_alarm alarm,
+	struct rtc_time *time)
+{
+	return pmic_rpc_set_struct(1, alarm, (uint *)time, sizeof(*time),
+				RTC_ENABLE_ALARM_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_enable_alarm);
+
+int pmic_rtc_disable_alarm(enum rtc_alarm alarm)
+{
+	return pmic_rpc_set_only(alarm, 0, 0, 0, 1, RTC_DISABLE_ALARM_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_disable_alarm);
+
+int pmic_rtc_get_alarm_time(enum rtc_alarm	alarm,
+	struct rtc_time *time)
+{
+	return pmic_rpc_set_get(alarm, (uint *)time, sizeof(*time),
+				RTC_GET_ALARM_TIME_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_get_alarm_time);
+
+int pmic_rtc_get_alarm_status(uint *status)
+{
+	return pmic_rpc_get_only(status, sizeof(*status),
+				RTC_GET_ALARM_STATUS_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_get_alarm_status);
+
+int pmic_rtc_set_time_adjust(uint adjust)
+{
+	return pmic_rpc_set_only(adjust, 0, 0, 0, 1,
+				RTC_SET_TIME_ADJUST_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_set_time_adjust);
+
+int pmic_rtc_get_time_adjust(uint *adjust)
+{
+	return pmic_rpc_get_only(adjust, sizeof(*adjust),
+				RTC_GET_TIME_ADJUST_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_get_time_adjust);
+
+/*
+ * generic speaker
+ */
+int pmic_speaker_cmd(const enum spkr_cmd cmd)
+{
+	return pmic_rpc_set_only(cmd, 0, 0, 0, 1, SPEAKER_CMD_PROC);
+}
+EXPORT_SYMBOL(pmic_speaker_cmd);
+
+int pmic_set_spkr_configuration(struct spkr_config_mode	*cfg)
+{
+	return pmic_rpc_set_struct(0, 0, (uint *)cfg, sizeof(*cfg),
+				SET_SPKR_CONFIGURATION_PROC);
+}
+EXPORT_SYMBOL(pmic_set_spkr_configuration);
+
+int pmic_get_spkr_configuration(struct spkr_config_mode *cfg)
+{
+	return pmic_rpc_get_only((uint *)cfg, sizeof(*cfg),
+				GET_SPKR_CONFIGURATION_PROC);
+}
+EXPORT_SYMBOL(pmic_get_spkr_configuration);
+
+int pmic_spkr_en_right_chan(uint enable)
+{
+	return pmic_rpc_set_only(enable, 0, 0, 0, 1, SPKR_EN_RIGHT_CHAN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_en_right_chan);
+
+int pmic_spkr_is_right_chan_en(uint *enabled)
+{
+	return pmic_rpc_get_only(enabled, sizeof(*enabled),
+				SPKR_IS_RIGHT_CHAN_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_is_right_chan_en);
+
+int pmic_spkr_en_left_chan(uint	enable)
+{
+	return pmic_rpc_set_only(enable, 0, 0, 0, 1, SPKR_EN_LEFT_CHAN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_en_left_chan);
+
+int pmic_spkr_is_left_chan_en(uint *enabled)
+{
+	return pmic_rpc_get_only(enabled, sizeof(*enabled),
+				SPKR_IS_LEFT_CHAN_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_is_left_chan_en);
+
+int pmic_set_speaker_gain(enum spkr_gain gain)
+{
+	return pmic_rpc_set_only(gain, 0, 0, 0, 1, SET_SPEAKER_GAIN_PROC);
+}
+EXPORT_SYMBOL(pmic_set_speaker_gain);
+
+int pmic_set_speaker_delay(enum spkr_dly delay)
+{
+	return pmic_rpc_set_only(delay, 0, 0, 0, 1, SET_SPEAKER_DELAY_PROC);
+}
+EXPORT_SYMBOL(pmic_set_speaker_delay);
+
+int pmic_speaker_1k6_zin_enable(uint enable)
+{
+	return pmic_rpc_set_only(enable, 0, 0, 0, 1,
+				SPEAKER_1K6_ZIN_ENABLE_PROC);
+}
+EXPORT_SYMBOL(pmic_speaker_1k6_zin_enable);
+
+int pmic_spkr_set_mux_hpf_corner_freq(enum spkr_hpf_corner_freq	freq)
+{
+	return pmic_rpc_set_only(freq, 0, 0, 0, 1,
+				SPKR_SET_MUX_HPF_CORNER_FREQ_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_set_mux_hpf_corner_freq);
+
+int pmic_spkr_get_mux_hpf_corner_freq(enum spkr_hpf_corner_freq	*freq)
+{
+	return pmic_rpc_get_only(freq, sizeof(*freq),
+				SPKR_GET_MUX_HPF_CORNER_FREQ_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_get_mux_hpf_corner_freq);
+
+int pmic_spkr_select_usb_with_hpf_20hz(uint	enable)
+{
+	return pmic_rpc_set_only(enable, 0, 0, 0, 1,
+				SPKR_SELECT_USB_WITH_HPF_20HZ_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_select_usb_with_hpf_20hz);
+
+int pmic_spkr_is_usb_with_hpf_20hz(uint *enabled)
+{
+	return pmic_rpc_get_only(enabled, sizeof(*enabled),
+				SPKR_IS_USB_WITH_HPF_20HZ_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_is_usb_with_hpf_20hz);
+
+int pmic_spkr_bypass_mux(uint enable)
+{
+	return pmic_rpc_set_only(enable, 0, 0, 0, 1, SPKR_BYPASS_MUX_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_bypass_mux);
+
+int pmic_spkr_is_mux_bypassed(uint *enabled)
+{
+	return pmic_rpc_get_only(enabled, sizeof(*enabled),
+				SPKR_IS_MUX_BYPASSED_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_is_mux_bypassed);
+
+int pmic_spkr_en_hpf(uint enable)
+{
+	return pmic_rpc_set_only(enable, 0, 0, 0, 1, SPKR_EN_HPF_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_en_hpf);
+
+int pmic_spkr_is_hpf_en(uint *enabled)
+{
+	return pmic_rpc_get_only(enabled, sizeof(*enabled),
+				SPKR_IS_HPF_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_is_hpf_en);
+
+int pmic_spkr_en_sink_curr_from_ref_volt_cir(uint enable)
+{
+	return pmic_rpc_set_only(enable, 0, 0, 0, 1,
+				SPKR_EN_SINK_CURR_FROM_REF_VOLT_CIR_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_en_sink_curr_from_ref_volt_cir);
+
+int pmic_spkr_is_sink_curr_from_ref_volt_cir_en(uint *enabled)
+{
+	return pmic_rpc_get_only(enabled, sizeof(*enabled),
+				SPKR_IS_SINK_CURR_FROM_REF_VOLT_CIR_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_is_sink_curr_from_ref_volt_cir_en);
+
+/*
+ * 	speaker indexed by left_right
+ */
+int pmic_spkr_en(enum spkr_left_right left_right, uint enable)
+{
+	return pmic_rpc_set_only(left_right, enable, 0, 0, 2, SPKR_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_en);
+
+int pmic_spkr_is_en(enum spkr_left_right left_right, uint *enabled)
+{
+	return pmic_rpc_set_get(left_right, enabled, sizeof(*enabled),
+				SPKR_IS_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_is_en);
+
+int pmic_spkr_set_gain(enum spkr_left_right left_right, enum spkr_gain gain)
+{
+	return pmic_rpc_set_only(left_right, gain, 0, 0, 2, SPKR_SET_GAIN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_set_gain);
+
+int pmic_spkr_get_gain(enum spkr_left_right left_right, enum spkr_gain *gain)
+{
+	return pmic_rpc_set_get(left_right, gain, sizeof(*gain),
+				SPKR_GET_GAIN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_get_gain);
+
+int pmic_spkr_set_delay(enum spkr_left_right left_right, enum spkr_dly delay)
+{
+	return pmic_rpc_set_only(left_right, delay, 0, 0, 2,
+				SPKR_SET_DELAY_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_set_delay);
+
+int pmic_spkr_get_delay(enum spkr_left_right left_right, enum spkr_dly *delay)
+{
+	return pmic_rpc_set_get(left_right, delay, sizeof(*delay),
+				SPKR_GET_DELAY_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_get_delay);
+
+int pmic_spkr_en_mute(enum spkr_left_right left_right, uint enabled)
+{
+	return pmic_rpc_set_only(left_right, enabled, 0, 0, 2,
+				SPKR_EN_MUTE_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_en_mute);
+
+int pmic_spkr_is_mute_en(enum spkr_left_right left_right, uint *enabled)
+{
+	return pmic_rpc_set_get(left_right, enabled, sizeof(*enabled),
+				SPKR_IS_MUTE_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_is_mute_en);
+
+int pmic_spkr_set_vsel_ldo(enum spkr_left_right left_right,
+					enum spkr_ldo_v_sel vlt_cntrl)
+{
+	return pmic_rpc_set_only(left_right, vlt_cntrl, 0, 0, 2,
+			SPKR_SET_VSEL_LDO_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_set_vsel_ldo);
+
+int pmic_spkr_set_boost(enum spkr_left_right left_right, uint enable)
+{
+	return pmic_rpc_set_only(left_right, enable, 0, 0, 2,
+			SPKR_SET_BOOST_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_set_boost);
+
+int pmic_spkr_bypass_en(enum spkr_left_right left_right, uint enable)
+{
+	return pmic_rpc_set_only(left_right, enable, 0, 0, 2,
+			SPKR_BYPASS_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_bypass_en);
+
+/*
+ * 	mic
+ */
+int pmic_mic_en(uint enable)
+{
+	return pmic_rpc_set_only(enable, 0, 0, 0, 1, MIC_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_mic_en);
+
+int pmic_mic_is_en(uint	*enabled)
+{
+	return pmic_rpc_get_only(enabled, sizeof(*enabled), MIC_IS_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_mic_is_en);
+
+int pmic_mic_set_volt(enum mic_volt vol)
+{
+	return pmic_rpc_set_only(vol, 0, 0, 0, 1, MIC_SET_VOLT_PROC);
+}
+EXPORT_SYMBOL(pmic_mic_set_volt);
+
+int pmic_mic_get_volt(enum mic_volt *voltage)
+{
+	return pmic_rpc_get_only(voltage, sizeof(*voltage), MIC_GET_VOLT_PROC);
+}
+EXPORT_SYMBOL(pmic_mic_get_volt);
+
+int pmic_vib_mot_set_volt(uint vol)
+{
+	return pmic_rpc_set_only(vol, 0, 0, 0, 1, VIB_MOT_SET_VOLT_PROC);
+}
+EXPORT_SYMBOL(pmic_vib_mot_set_volt);
+
+int pmic_vib_mot_set_mode(enum pm_vib_mot_mode mode)
+{
+	return pmic_rpc_set_only(mode, 0, 0, 0, 1, VIB_MOT_SET_MODE_PROC);
+}
+EXPORT_SYMBOL(pmic_vib_mot_set_mode);
+
+int pmic_vib_mot_set_polarity(enum pm_vib_mot_pol pol)
+{
+	return pmic_rpc_set_only(pol, 0, 0, 0, 1, VIB_MOT_SET_POLARITY_PROC);
+}
+EXPORT_SYMBOL(pmic_vib_mot_set_polarity);
+
+int pmic_vid_en(uint enable)
+{
+	return pmic_rpc_set_only(enable, 0, 0, 0, 1, VID_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_vid_en);
+
+int pmic_vid_is_en(uint *enabled)
+{
+	return pmic_rpc_get_only(enabled, sizeof(*enabled), VID_IS_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_vid_is_en);
+
+int pmic_vid_load_detect_en(uint enable)
+{
+	return pmic_rpc_set_only(enable, 0, 0, 0, 1, VID_LOAD_DETECT_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_vid_load_detect_en);
+
+int pmic_set_led_intensity(enum ledtype type, int level)
+{
+	return pmic_rpc_set_only(type, level, 0, 0, 2, SET_LED_INTENSITY_PROC);
+}
+EXPORT_SYMBOL(pmic_set_led_intensity);
+
+int pmic_flash_led_set_current(const uint16_t milliamps)
+{
+	return pmic_rpc_set_only(milliamps, 0, 0, 0, 1,
+				FLASH_LED_SET_CURRENT_PROC);
+}
+EXPORT_SYMBOL(pmic_flash_led_set_current);
+
+int pmic_flash_led_set_mode(enum flash_led_mode mode)
+{
+	return pmic_rpc_set_only((int)mode, 0, 0, 0, 1,
+				FLASH_LED_SET_MODE_PROC);
+}
+EXPORT_SYMBOL(pmic_flash_led_set_mode);
+
+int pmic_flash_led_set_polarity(enum flash_led_pol pol)
+{
+	return pmic_rpc_set_only((int)pol, 0, 0, 0, 1,
+				FLASH_LED_SET_POLARITY_PROC);
+}
+EXPORT_SYMBOL(pmic_flash_led_set_polarity);
+
+int pmic_spkr_add_right_left_chan(uint enable)
+{
+	return pmic_rpc_set_only(enable, 0, 0, 0, 1,
+				SPKR_ADD_RIGHT_LEFT_CHAN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_add_right_left_chan);
+
+int pmic_spkr_is_right_left_chan_added(uint *enabled)
+{
+	return pmic_rpc_get_only(enabled, sizeof(*enabled),
+				SPKR_IS_RIGHT_LEFT_CHAN_ADDED_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_is_right_left_chan_added);
+
+int pmic_spkr_en_stereo(uint enable)
+{
+	return pmic_rpc_set_only(enable, 0, 0, 0, 1, SPKR_EN_STEREO_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_en_stereo);
+
+int pmic_spkr_is_stereo_en(uint *enabled)
+{
+	return pmic_rpc_get_only(enabled, sizeof(*enabled),
+				SPKR_IS_STEREO_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_is_stereo_en);
+
+int pmic_hsed_set_period(
+	enum hsed_controller controller,
+	enum hsed_period_pre_div period_pre_div,
+	enum hsed_period_time period_time
+)
+{
+	return pmic_rpc_set_only(controller, period_pre_div, period_time, 0,
+				 3,
+				 HSED_SET_PERIOD_PROC);
+}
+EXPORT_SYMBOL(pmic_hsed_set_period);
+
+int pmic_hsed_set_hysteresis(
+	enum hsed_controller controller,
+	enum hsed_hyst_pre_div hyst_pre_div,
+	enum hsed_hyst_time hyst_time
+)
+{
+	return pmic_rpc_set_only(controller, hyst_pre_div, hyst_time, 0,
+				 3,
+				 HSED_SET_HYSTERESIS_PROC);
+}
+EXPORT_SYMBOL(pmic_hsed_set_hysteresis);
+
+int pmic_hsed_set_current_threshold(
+	enum hsed_controller controller,
+	enum hsed_switch switch_hsed,
+	uint32_t current_threshold
+)
+{
+	return pmic_rpc_set_only(controller, switch_hsed, current_threshold, 0,
+				 3,
+				 HSED_SET_CURRENT_THRESHOLD_PROC);
+}
+EXPORT_SYMBOL(pmic_hsed_set_current_threshold);
+
+int pmic_hsed_enable(
+	enum hsed_controller controller,
+	enum hsed_enable enable_hsed
+)
+{
+	return pmic_rpc_set_only(controller, enable_hsed, 0, 0,
+				 2,
+				 HSED_ENABLE_PROC);
+}
+EXPORT_SYMBOL(pmic_hsed_enable);
+
+int pmic_high_current_led_set_current(enum high_current_led led,
+		uint16_t milliamps)
+{
+	return pmic_rpc_set_only(led, milliamps, 0, 0,
+			2,
+			HIGH_CURRENT_LED_SET_CURRENT_PROC);
+}
+EXPORT_SYMBOL(pmic_high_current_led_set_current);
+
+int pmic_high_current_led_set_polarity(enum high_current_led led,
+		enum flash_led_pol polarity)
+{
+	return pmic_rpc_set_only(led, polarity, 0, 0,
+			2,
+			HIGH_CURRENT_LED_SET_POLARITY_PROC);
+}
+EXPORT_SYMBOL(pmic_high_current_led_set_polarity);
+
+int pmic_high_current_led_set_mode(enum high_current_led led,
+		enum flash_led_mode mode)
+{
+	return pmic_rpc_set_only(led, mode, 0, 0,
+			2,
+			HIGH_CURRENT_LED_SET_MODE_PROC);
+}
+EXPORT_SYMBOL(pmic_high_current_led_set_mode);
+
+int pmic_lp_force_lpm_control(enum switch_cmd cmd,
+		enum vreg_lpm_id vreg)
+{
+	return pmic_rpc_set_only(cmd, vreg, 0, 0,
+			2,
+			LP_FORCE_LPM_CONTROL_PROC);
+}
+EXPORT_SYMBOL(pmic_lp_force_lpm_control);
+
+int pmic_low_current_led_set_ext_signal(enum low_current_led led,
+		enum ext_signal sig)
+{
+	return pmic_rpc_set_only(led, sig, 0, 0,
+			2,
+			LOW_CURRENT_LED_SET_EXT_SIGNAL_PROC);
+}
+EXPORT_SYMBOL(pmic_low_current_led_set_ext_signal);
+
+int pmic_low_current_led_set_current(enum low_current_led led,
+		uint16_t milliamps)
+{
+	return pmic_rpc_set_only(led, milliamps, 0, 0,
+			2,
+			LOW_CURRENT_LED_SET_CURRENT_PROC);
+}
+EXPORT_SYMBOL(pmic_low_current_led_set_current);
+
+/*
+ * Head phone speaker
+ */
+int pmic_hp_spkr_mstr_en(enum hp_spkr_left_right left_right, uint enable)
+{
+	return pmic_rpc_set_only(left_right, enable, 0, 0, 2,
+			HP_SPKR_MSTR_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_hp_spkr_mstr_en);
+
+int pmic_hp_spkr_mute_en(enum hp_spkr_left_right left_right, uint enable)
+{
+	return pmic_rpc_set_only(left_right, enable, 0, 0, 2,
+			HP_SPKR_MUTE_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_hp_spkr_mute_en);
+
+int pmic_hp_spkr_prm_in_en(enum hp_spkr_left_right left_right, uint enable)
+{
+	return pmic_rpc_set_only(left_right, enable, 0, 0, 2,
+			HP_SPKR_PRM_IN_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_hp_spkr_prm_in_en);
+
+int pmic_hp_spkr_aux_in_en(enum hp_spkr_left_right left_right, uint enable)
+{
+	return pmic_rpc_set_only(left_right, enable, 0, 0, 2,
+			HP_SPKR_AUX_IN_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_hp_spkr_aux_in_en);
+
+int pmic_hp_spkr_ctrl_prm_gain_input(enum hp_spkr_left_right left_right,
+							uint prm_gain_ctl)
+{
+	return pmic_rpc_set_only(left_right, prm_gain_ctl, 0, 0, 2,
+			HP_SPKR_CTRL_PRM_GAIN_INPUT_PROC);
+}
+EXPORT_SYMBOL(pmic_hp_spkr_ctrl_prm_gain_input);
+
+int pmic_hp_spkr_ctrl_aux_gain_input(enum hp_spkr_left_right left_right,
+							uint aux_gain_ctl)
+{
+	return pmic_rpc_set_only(left_right, aux_gain_ctl, 0, 0, 2,
+			HP_SPKR_CTRL_AUX_GAIN_INPUT_PROC);
+}
+EXPORT_SYMBOL(pmic_hp_spkr_ctrl_aux_gain_input);
+
+int pmic_xo_core_force_enable(uint enable)
+{
+	return pmic_rpc_set_only(enable, 0, 0, 0, 1, XO_CORE_FORCE_ENABLE);
+}
+EXPORT_SYMBOL(pmic_xo_core_force_enable);
+
+int pmic_gpio_direction_input(unsigned gpio)
+{
+	return pmic_rpc_set_only(gpio, 0, 0, 0, 1,
+			GPIO_SET_GPIO_DIRECTION_INPUT_PROC);
+}
+EXPORT_SYMBOL(pmic_gpio_direction_input);
+
+int pmic_gpio_direction_output(unsigned gpio)
+{
+	return pmic_rpc_set_only(gpio, 0, 0, 0, 1,
+			GPIO_SET_GPIO_DIRECTION_OUTPUT_PROC);
+}
+EXPORT_SYMBOL(pmic_gpio_direction_output);
+
+int pmic_gpio_set_value(unsigned gpio, int value)
+{
+	return pmic_rpc_set_only(gpio, value, 0, 0, 2, GPIO_SET_PROC);
+}
+EXPORT_SYMBOL(pmic_gpio_set_value);
+
+int pmic_gpio_get_value(unsigned gpio)
+{
+	uint value;
+	int ret;
+
+	ret = pmic_rpc_set_get(gpio, &value, sizeof(value), GPIO_GET_PROC);
+	if (ret < 0)
+		return ret;
+	return value ? 1 : 0;
+}
+EXPORT_SYMBOL(pmic_gpio_get_value);
+
+int pmic_gpio_get_direction(unsigned gpio)
+{
+	enum pmic_direction_mode dir;
+	int ret;
+
+	ret = pmic_rpc_set_get(gpio, &dir, sizeof(dir),
+			GPIO_GET_GPIO_DIRECTION_PROC);
+	if (ret < 0)
+		return ret;
+	return dir;
+}
+EXPORT_SYMBOL(pmic_gpio_get_direction);
+
+int pmic_gpio_config(struct pm8xxx_gpio_rpc_cfg *param)
+{
+	return pmic_rpc_set_struct(0, 0, (uint *)param, sizeof(*param),
+			GPIO_SET_GPIO_CONFIG_PROC);
+}
+EXPORT_SYMBOL(pmic_gpio_config);
diff --git a/arch/arm/mach-msm/pmic.h b/arch/arm/mach-msm/pmic.h
new file mode 100644
index 0000000..e6ef960
--- /dev/null
+++ b/arch/arm/mach-msm/pmic.h
@@ -0,0 +1,295 @@
+/* Copyright (c) 2009, 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 __ARCH_ARM_MACH_PMIC_H
+#define __ARCH_ARM_MACH_PMIC_H
+
+#include <mach/proc_comm.h>
+
+enum spkr_left_right {
+	LEFT_SPKR,
+	RIGHT_SPKR,
+};
+
+enum spkr_gain {
+	SPKR_GAIN_MINUS16DB,      /* -16 db */
+	SPKR_GAIN_MINUS12DB,      /* -12 db */
+	SPKR_GAIN_MINUS08DB,      /* -08 db */
+	SPKR_GAIN_MINUS04DB,      /* -04 db */
+	SPKR_GAIN_00DB,           /*  00 db */
+	SPKR_GAIN_PLUS04DB,       /* +04 db */
+	SPKR_GAIN_PLUS08DB,       /* +08 db */
+	SPKR_GAIN_PLUS12DB,       /* +12 db */
+};
+
+enum spkr_dly {
+	SPKR_DLY_10MS,            /* ~10  ms delay */
+	SPKR_DLY_100MS,           /* ~100 ms delay */
+};
+
+enum spkr_hpf_corner_freq {
+	SPKR_FREQ_1_39KHZ,         /* 1.39 kHz */
+	SPKR_FREQ_0_64KHZ,         /* 0.64 kHz */
+	SPKR_FREQ_0_86KHZ,         /* 0.86 kHz */
+	SPKR_FREQ_0_51KHZ,         /* 0.51 kHz */
+	SPKR_FREQ_1_06KHZ,         /* 1.06 kHz */
+	SPKR_FREQ_0_57KHZ,         /* 0.57 kHz */
+	SPKR_FREQ_0_73KHZ,         /* 0.73 kHz */
+	SPKR_FREQ_0_47KHZ,         /* 0.47 kHz */
+	SPKR_FREQ_1_20KHZ,         /* 1.20 kHz */
+	SPKR_FREQ_0_60KHZ,         /* 0.60 kHz */
+	SPKR_FREQ_0_76KHZ,         /* 0.76 kHz */
+	SPKR_FREQ_0_49KHZ,         /* 0.49 kHz */
+	SPKR_FREQ_0_95KHZ,         /* 0.95 kHz */
+	SPKR_FREQ_0_54KHZ,         /* 0.54 kHz */
+	SPKR_FREQ_0_68KHZ,         /* 0.68 kHz */
+	SPKR_FREQ_0_45KHZ,         /* 0.45 kHz */
+};
+
+/* Turn the speaker on or off and enables or disables mute.*/
+enum spkr_cmd {
+	SPKR_DISABLE,  /* Enable Speaker */
+	SPKR_ENABLE,   /* Disable Speaker */
+	SPKR_MUTE_OFF, /* turn speaker mute off, SOUND ON */
+	SPKR_MUTE_ON,  /* turn speaker mute on, SOUND OFF */
+	SPKR_OFF,      /* turn speaker OFF (speaker disable and mute on) */
+	SPKR_ON,        /* turn speaker ON (speaker enable and mute off)  */
+	SPKR_SET_FREQ_CMD,    /* set speaker frequency */
+	SPKR_GET_FREQ_CMD,    /* get speaker frequency */
+	SPKR_SET_GAIN_CMD,    /* set speaker gain */
+	SPKR_GET_GAIN_CMD,    /* get speaker gain */
+	SPKR_SET_DELAY_CMD,   /* set speaker delay */
+	SPKR_GET_DELAY_CMD,   /* get speaker delay */
+	SPKR_SET_PDM_MODE,
+	SPKR_SET_PWM_MODE,
+};
+
+struct spkr_config_mode {
+	uint32_t is_right_chan_en;
+	uint32_t is_left_chan_en;
+	uint32_t is_right_left_chan_added;
+	uint32_t is_stereo_en;
+	uint32_t is_usb_with_hpf_20hz;
+	uint32_t is_mux_bypassed;
+	uint32_t is_hpf_en;
+	uint32_t is_sink_curr_from_ref_volt_cir_en;
+};
+
+enum mic_volt {
+	MIC_VOLT_2_00V,            /*  2.00 V  */
+	MIC_VOLT_1_93V,            /*  1.93 V  */
+	MIC_VOLT_1_80V,            /*  1.80 V  */
+	MIC_VOLT_1_73V,            /*  1.73 V  */
+};
+
+enum ledtype {
+	LED_LCD,
+	LED_KEYPAD,
+};
+
+enum flash_led_mode {
+	FLASH_LED_MODE__MANUAL,
+	FLASH_LED_MODE__DBUS1,
+	FLASH_LED_MODE__DBUS2,
+	FLASH_LED_MODE__DBUS3,
+};
+
+enum flash_led_pol {
+	FLASH_LED_POL__ACTIVE_HIGH,
+	FLASH_LED_POL__ACTIVE_LOW,
+};
+
+enum switch_cmd {
+	OFF_CMD,
+	ON_CMD
+};
+
+enum vreg_lp_id {
+	PM_VREG_LP_MSMA_ID,
+	PM_VREG_LP_MSMP_ID,
+	PM_VREG_LP_MSME1_ID,
+	PM_VREG_LP_GP3_ID,
+	PM_VREG_LP_MSMC_ID,
+	PM_VREG_LP_MSME2_ID,
+	PM_VREG_LP_GP4_ID,
+	PM_VREG_LP_GP1_ID,
+	PM_VREG_LP_RFTX_ID,
+	PM_VREG_LP_RFRX1_ID,
+	PM_VREG_LP_RFRX2_ID,
+	PM_VREG_LP_WLAN_ID,
+	PM_VREG_LP_MMC_ID,
+	PM_VREG_LP_RUIM_ID,
+	PM_VREG_LP_MSMC0_ID,
+	PM_VREG_LP_GP2_ID,
+	PM_VREG_LP_GP5_ID,
+	PM_VREG_LP_GP6_ID,
+	PM_VREG_LP_MPLL_ID,
+	PM_VREG_LP_RFUBM_ID,
+	PM_VREG_LP_RFA_ID,
+	PM_VREG_LP_CDC2_ID,
+	PM_VREG_LP_RFTX2_ID,
+	PM_VREG_LP_USIM_ID,
+	PM_VREG_LP_USB2P6_ID,
+	PM_VREG_LP_TCXO_ID,
+	PM_VREG_LP_USB3P3_ID,
+
+	PM_VREG_LP_MSME_ID = PM_VREG_LP_MSME1_ID,
+	/* backward compatible enums only */
+	PM_VREG_LP_CAM_ID = PM_VREG_LP_GP1_ID,
+	PM_VREG_LP_MDDI_ID = PM_VREG_LP_GP2_ID,
+	PM_VREG_LP_RUIM2_ID = PM_VREG_LP_GP3_ID,
+	PM_VREG_LP_AUX_ID = PM_VREG_LP_GP4_ID,
+	PM_VREG_LP_AUX2_ID = PM_VREG_LP_GP5_ID,
+	PM_VREG_LP_BT_ID = PM_VREG_LP_GP6_ID,
+	PM_VREG_LP_MSMC_LDO_ID = PM_VREG_LP_MSMC_ID,
+	PM_VREG_LP_MSME1_LDO_ID = PM_VREG_LP_MSME1_ID,
+	PM_VREG_LP_MSME2_LDO_ID = PM_VREG_LP_MSME2_ID,
+	PM_VREG_LP_RFA1_ID = PM_VREG_LP_RFRX2_ID,
+	PM_VREG_LP_RFA2_ID = PM_VREG_LP_RFTX2_ID,
+	PM_VREG_LP_XO_ID = PM_VREG_LP_TCXO_ID
+};
+
+enum mpp_which {
+	PM_MPP_1,
+	PM_MPP_2,
+	PM_MPP_3,
+	PM_MPP_4,
+	PM_MPP_5,
+	PM_MPP_6,
+	PM_MPP_7,
+	PM_MPP_8,
+	PM_MPP_9,
+	PM_MPP_10,
+	PM_MPP_11,
+	PM_MPP_12,
+	PM_MPP_13,
+	PM_MPP_14,
+	PM_MPP_15,
+	PM_MPP_16,
+	PM_MPP_17,
+	PM_MPP_18,
+	PM_MPP_19,
+	PM_MPP_20,
+	PM_MPP_21,
+	PM_MPP_22,
+
+	PM_NUM_MPP_HAN = PM_MPP_4 + 1,
+	PM_NUM_MPP_KIP = PM_MPP_4 + 1,
+	PM_NUM_MPP_EPIC = PM_MPP_4 + 1,
+	PM_NUM_MPP_PM7500 = PM_MPP_22 + 1,
+	PM_NUM_MPP_PM6650 = PM_MPP_12 + 1,
+	PM_NUM_MPP_PM6658 = PM_MPP_12 + 1,
+	PM_NUM_MPP_PANORAMIX = PM_MPP_2 + 1,
+	PM_NUM_MPP_PM6640 = PM_NUM_MPP_PANORAMIX,
+	PM_NUM_MPP_PM6620 = PM_NUM_MPP_PANORAMIX
+};
+
+enum mpp_dlogic_level {
+	PM_MPP__DLOGIC__LVL_MSME,
+	PM_MPP__DLOGIC__LVL_MSMP,
+	PM_MPP__DLOGIC__LVL_RUIM,
+	PM_MPP__DLOGIC__LVL_MMC,
+	PM_MPP__DLOGIC__LVL_VDD,
+};
+
+enum mpp_dlogic_in_dbus {
+	PM_MPP__DLOGIC_IN__DBUS_NONE,
+	PM_MPP__DLOGIC_IN__DBUS1,
+	PM_MPP__DLOGIC_IN__DBUS2,
+	PM_MPP__DLOGIC_IN__DBUS3,
+};
+
+enum mpp_dlogic_out_ctrl {
+	PM_MPP__DLOGIC_OUT__CTRL_LOW,
+	PM_MPP__DLOGIC_OUT__CTRL_HIGH,
+	PM_MPP__DLOGIC_OUT__CTRL_MPP,
+	PM_MPP__DLOGIC_OUT__CTRL_NOT_MPP,
+};
+
+enum mpp_i_sink_level {
+	PM_MPP__I_SINK__LEVEL_5mA,
+	PM_MPP__I_SINK__LEVEL_10mA,
+	PM_MPP__I_SINK__LEVEL_15mA,
+	PM_MPP__I_SINK__LEVEL_20mA,
+	PM_MPP__I_SINK__LEVEL_25mA,
+	PM_MPP__I_SINK__LEVEL_30mA,
+	PM_MPP__I_SINK__LEVEL_35mA,
+	PM_MPP__I_SINK__LEVEL_40mA,
+};
+
+enum mpp_i_sink_switch {
+	PM_MPP__I_SINK__SWITCH_DIS,
+	PM_MPP__I_SINK__SWITCH_ENA,
+	PM_MPP__I_SINK__SWITCH_ENA_IF_MPP_HIGH,
+	PM_MPP__I_SINK__SWITCH_ENA_IF_MPP_LOW,
+};
+
+enum pm_vib_mot_mode {
+	PM_VIB_MOT_MODE__MANUAL,
+	PM_VIB_MOT_MODE__DBUS1,
+	PM_VIB_MOT_MODE__DBUS2,
+	PM_VIB_MOT_MODE__DBUS3,
+};
+
+enum pm_vib_mot_pol {
+	PM_VIB_MOT_POL__ACTIVE_HIGH,
+	PM_VIB_MOT_POL__ACTIVE_LOW,
+};
+
+struct rtc_time {
+	uint  sec;
+};
+
+enum rtc_alarm {
+	PM_RTC_ALARM_1,
+};
+
+
+int pmic_lp_mode_control(enum switch_cmd cmd, enum vreg_lp_id id);
+int pmic_secure_mpp_control_digital_output(enum mpp_which which,
+		enum mpp_dlogic_level level, enum mpp_dlogic_out_ctrl out);
+int pmic_secure_mpp_config_i_sink(enum mpp_which which,
+		enum mpp_i_sink_level level, enum mpp_i_sink_switch onoff);
+int pmic_secure_mpp_config_digital_input(enum mpp_which	which,
+		enum mpp_dlogic_level level, enum mpp_dlogic_in_dbus dbus);
+int pmic_speaker_cmd(const enum spkr_cmd cmd);
+int pmic_set_spkr_configuration(struct spkr_config_mode	*cfg);
+int pmic_spkr_en_right_chan(uint enable);
+int pmic_spkr_en_left_chan(uint enable);
+int pmic_spkr_en(enum spkr_left_right left_right, uint enabled);
+int pmic_spkr_set_gain(enum spkr_left_right left_right, enum spkr_gain gain);
+int pmic_set_speaker_gain(enum spkr_gain gain);
+int pmic_set_speaker_delay(enum spkr_dly delay);
+int pmic_speaker_1k6_zin_enable(uint enable);
+int pmic_spkr_set_mux_hpf_corner_freq(enum spkr_hpf_corner_freq	freq);
+int pmic_spkr_select_usb_with_hpf_20hz(uint enable);
+int pmic_spkr_bypass_mux(uint enable);
+int pmic_spkr_en_hpf(uint enable);
+int pmic_spkr_en_sink_curr_from_ref_volt_cir(uint enable);
+int pmic_spkr_set_delay(enum spkr_left_right left_right, enum spkr_dly delay);
+int pmic_spkr_en_mute(enum spkr_left_right left_right, uint enabled);
+int pmic_mic_en(uint enable);
+int pmic_mic_set_volt(enum mic_volt vol);
+int pmic_set_led_intensity(enum ledtype type, int level);
+int pmic_flash_led_set_current(uint16_t milliamps);
+int pmic_flash_led_set_mode(enum flash_led_mode mode);
+int pmic_flash_led_set_polarity(enum flash_led_pol pol);
+int pmic_spkr_add_right_left_chan(uint enable);
+int pmic_spkr_en_stereo(uint enable);
+int pmic_vib_mot_set_volt(uint vol);
+int pmic_vib_mot_set_mode(enum pm_vib_mot_mode mode);
+int pmic_vib_mot_set_polarity(enum pm_vib_mot_pol pol);
+int pmic_vid_en(uint enable);
+int pmic_vid_load_detect_en(uint enable);
+
+#endif
diff --git a/arch/arm/mach-msm/pmic_debugfs.c b/arch/arm/mach-msm/pmic_debugfs.c
new file mode 100644
index 0000000..c52cf9b
--- /dev/null
+++ b/arch/arm/mach-msm/pmic_debugfs.c
@@ -0,0 +1,1156 @@
+/* Copyright (c) 2009, 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/module.h>
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <linux/err.h>
+#include <linux/uaccess.h>
+
+#include <mach/pmic.h>
+
+
+static int debug_lp_mode_control(char *buf, int size)
+{
+	enum switch_cmd	cmd;
+	enum vreg_lp_id	id;
+	int	cnt;
+
+
+	cnt = sscanf(buf, "%u %u", &cmd, &id);
+	if (cnt < 2) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d", __func__, cnt);
+		return -EINVAL;
+	}
+
+	if (pmic_lp_mode_control(cmd, id) < 0)
+		return -EFAULT;
+
+	return size;
+}
+
+static int debug_vreg_set_level(char *buf, int size)
+{
+	enum vreg_id vreg;
+	int	level;
+	int	cnt;
+
+	cnt = sscanf(buf, "%u %u", &vreg, &level);
+	if (cnt < 2) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d", __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_vreg_set_level(vreg, level) < 0)
+		return -EFAULT;
+
+	return size;
+}
+
+static int debug_vreg_pull_down_switch(char *buf, int size)
+{
+	enum switch_cmd	cmd;
+	enum vreg_pdown_id id;
+	int	cnt;
+
+	cnt = sscanf(buf, "%u %u", &cmd, &id);
+	if (cnt < 2) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d", __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_vreg_pull_down_switch(cmd, id) < 0)
+		return -EFAULT;
+
+	return size;
+}
+
+static int debug_secure_mpp_control_digital_output(char *buf, int size)
+{
+	enum mpp_which which;
+	enum mpp_dlogic_level level;
+	enum mpp_dlogic_out_ctrl out;
+	int	cnt;
+
+	cnt = sscanf(buf, "%u %u %u", &which, &level, &out);
+	if (cnt < 3) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+
+	if (pmic_secure_mpp_control_digital_output(which, level, out) < 0)
+		return -EFAULT;
+
+	return size;
+}
+
+static int debug_secure_mpp_config_i_sink(char *buf, int size)
+{
+	enum mpp_which which;
+	enum mpp_i_sink_level level;
+	enum mpp_i_sink_switch onoff;
+	int	cnt;
+
+	cnt = sscanf(buf, "%u %u %u", &which, &level, &onoff);
+	if (cnt < 3) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+
+	if (pmic_secure_mpp_config_i_sink(which, level, onoff) < 0)
+		return -EFAULT;
+
+	return size;
+}
+
+static int debug_secure_mpp_config_digital_input(char *buf, int size)
+{
+	enum mpp_which which;
+	enum mpp_dlogic_level level;
+	enum mpp_dlogic_in_dbus dbus;
+	int	cnt;
+
+	cnt = sscanf(buf, "%u %u %u", &which, &level, &dbus);
+	if (cnt < 3) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_secure_mpp_config_digital_input(which, level, dbus) < 0)
+		return -EFAULT;
+
+	return size;
+}
+
+static int debug_rtc_start(char *buf, int size)
+{
+	uint time;
+	struct rtc_time	*hal;
+	int	cnt;
+
+	cnt = sscanf(buf, "%d", &time);
+	if (cnt < 1) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	hal = (struct rtc_time 	*)&time;
+	if (pmic_rtc_start(hal) < 0)
+		return -EFAULT;
+
+	return size;
+}
+
+static int debug_rtc_stop(char *buf, int size)
+{
+	if (pmic_rtc_stop() < 0)
+		return -EFAULT;
+
+	return size;
+}
+
+static int debug_rtc_get_time(char *buf, int size)
+{
+	uint time;
+	struct rtc_time *hal;
+
+	hal = (struct rtc_time 	*)&time;
+	if (pmic_rtc_get_time(hal) < 0)
+		return -EFAULT;
+
+	return snprintf(buf, size, "%d\n", time);
+}
+
+static int	debug_rtc_alarm_ndx;
+
+int debug_rtc_enable_alarm(char *buf, int size)
+{
+	enum rtc_alarm alarm;
+	struct rtc_time	*hal;
+	uint time;
+	int	cnt;
+
+
+	cnt = sscanf(buf, "%u %u", &alarm, &time);
+	if (cnt < 2) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	hal = (struct rtc_time 	*)&time;
+
+	if (pmic_rtc_enable_alarm(alarm, hal) < 0)
+		return -EFAULT;
+
+	debug_rtc_alarm_ndx = alarm;
+	return size;
+}
+
+static int debug_rtc_disable_alarm(char *buf, int size)
+{
+
+	enum rtc_alarm alarm;
+	int	cnt;
+
+	cnt = sscanf(buf, "%u", &alarm);
+	if (cnt < 1) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_rtc_disable_alarm(alarm) < 0)
+		return -EFAULT;
+
+	return size;
+}
+
+static int debug_rtc_get_alarm_time(char *buf, int size)
+{
+	uint time;
+	struct rtc_time	*hal;
+
+	hal = (struct rtc_time 	*)&time;
+	if (pmic_rtc_get_alarm_time(debug_rtc_alarm_ndx, hal) < 0)
+		return -EFAULT;
+
+	return snprintf(buf, size, "%d\n", time);
+}
+static int debug_rtc_get_alarm_status(char *buf, int size)
+{
+	int	status;;
+
+	if (pmic_rtc_get_alarm_status(&status) < 0)
+		return -EFAULT;
+
+	return snprintf(buf, size, "%d\n", status);
+
+}
+
+static int debug_rtc_set_time_adjust(char *buf, int size)
+{
+	uint adjust;
+	int	cnt;
+
+	cnt = sscanf(buf, "%d", &adjust);
+	if (cnt < 1) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_rtc_set_time_adjust(adjust) < 0)
+		return -EFAULT;
+
+	return size;
+}
+
+static int debug_rtc_get_time_adjust(char *buf, int size)
+{
+	int	adjust;;
+
+	if (pmic_rtc_get_time_adjust(&adjust) < 0)
+		return -EFAULT;
+
+	return snprintf(buf, size, "%d\n", adjust);
+}
+
+static int debug_set_led_intensity(char *buf, int size)
+{
+	enum ledtype type;
+	int	level;
+	int	cnt;
+
+	cnt = sscanf(buf, "%u %d", &type, &level);
+	if (cnt < 2) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_set_led_intensity(type, level) < 0)
+		return -EFAULT;
+
+	return size;
+}
+
+static int debug_flash_led_set_current(char *buf, int size)
+{
+	int	milliamps;
+	int	cnt;
+
+	cnt = sscanf(buf, "%d", &milliamps);
+	if (cnt < 1) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_flash_led_set_current(milliamps) < 0)
+		return -EFAULT;
+
+	return size;
+}
+static int debug_flash_led_set_mode(char *buf, int size)
+{
+
+	uint mode;
+	int	cnt;
+
+	cnt = sscanf(buf, "%d", &mode);
+	if (cnt < 1) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_flash_led_set_mode(mode) < 0)
+		return -EFAULT;
+
+	return size;
+}
+
+static int debug_flash_led_set_polarity(char *buf, int size)
+{
+	int	pol;
+	int	cnt;
+
+	cnt = sscanf(buf, "%d", &pol);
+	if (cnt < 1) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_flash_led_set_polarity(pol) < 0)
+		return -EFAULT;
+
+	return size;
+}
+
+static int debug_speaker_cmd(char *buf, int size)
+{
+	int	cmd;
+	int	cnt;
+
+	cnt = sscanf(buf, "%d", &cmd);
+	if (cnt < 1) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_speaker_cmd(cmd) < 0)
+		return -EFAULT;
+
+	return size;
+}
+static int debug_set_speaker_gain(char *buf, int size)
+{
+	int	gain;
+	int	cnt;
+
+	cnt = sscanf(buf, "%d", &gain);
+	if (cnt < 1) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_set_speaker_gain(gain) < 0)
+		return -EFAULT;
+
+	return size;
+}
+
+static int debug_mic_en(char *buf, int size)
+{
+	int	enable;
+	int	cnt;
+
+	cnt = sscanf(buf, "%d", &enable);
+	if (cnt < 1) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_mic_en(enable) < 0)
+		return -EFAULT;
+
+	return size;
+}
+
+static int debug_mic_is_en(char *buf, int size)
+{
+	int	enabled;
+
+	if (pmic_mic_is_en(&enabled) < 0)
+		return -EFAULT;
+
+	return snprintf(buf, size, "%d\n", enabled);
+}
+
+static int debug_mic_set_volt(char *buf, int size)
+{
+	int	vol;
+	int	cnt;
+
+	cnt = sscanf(buf, "%d", &vol);
+	if (cnt < 1) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_mic_set_volt(vol) < 0)
+		return -EFAULT;
+
+	return size;
+}
+
+static int debug_mic_get_volt(char *buf, int size)
+{
+	uint vol;
+
+	if (pmic_mic_get_volt(&vol) < 0)
+		return -EFAULT;
+
+	return snprintf(buf, size, "%d\n", vol);
+}
+
+static int debug_spkr_en_right_chan(char *buf, int size)
+{
+	int	enable;
+	int	cnt;
+
+	cnt = sscanf(buf, "%d", &enable);
+	if (cnt < 1) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_spkr_en_right_chan(enable) < 0)
+		return -EFAULT;
+
+	return size;
+}
+
+static int debug_spkr_is_right_chan_en(char *buf, int size)
+{
+	int	enabled;
+
+	if (pmic_spkr_is_right_chan_en(&enabled) < 0)
+		return -EFAULT;
+
+	return snprintf(buf, size, "%d\n", enabled);
+}
+static int debug_spkr_en_left_chan(char *buf, int size)
+{
+	int	enable;
+	int	cnt;
+
+	cnt = sscanf(buf, "%d", &enable);
+	if (cnt < 1) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_spkr_en_left_chan(enable) < 0)
+		return -EFAULT;
+
+	return size;
+}
+
+static int debug_spkr_is_left_chan_en(char *buf, int size)
+{
+	int	enabled;
+
+	if (pmic_spkr_is_left_chan_en(&enabled) < 0)
+		return -EFAULT;
+
+	return snprintf(buf, size, "%d\n", enabled);
+}
+
+static int debug_set_spkr_configuration(char *buf, int size)
+{
+
+	struct spkr_config_mode	cfg;
+	int	cnt;
+
+	cnt = sscanf(buf, "%d %d %d %d %d %d %d %d",
+		    &cfg.is_right_chan_en,
+		    &cfg.is_left_chan_en,
+		    &cfg.is_right_left_chan_added,
+		    &cfg.is_stereo_en,
+		    &cfg.is_usb_with_hpf_20hz,
+		    &cfg.is_mux_bypassed,
+		    &cfg.is_hpf_en,
+		    &cfg.is_sink_curr_from_ref_volt_cir_en);
+
+	if (cnt < 8) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+
+	if (pmic_set_spkr_configuration(&cfg) < 0)
+		return -EFAULT;
+
+	return size;
+}
+
+static int debug_get_spkr_configuration(char *buf, int size)
+{
+	struct spkr_config_mode cfg;
+
+	if (pmic_get_spkr_configuration(&cfg) < 0)
+		return -EFAULT;
+
+	return snprintf(buf, size, "%d %d %d %d %d %d %d %d\n",
+				cfg.is_right_chan_en,
+				cfg.is_left_chan_en,
+				cfg.is_right_left_chan_added,
+				cfg.is_stereo_en,
+				cfg.is_usb_with_hpf_20hz,
+				cfg.is_mux_bypassed,
+				cfg.is_hpf_en,
+				cfg.is_sink_curr_from_ref_volt_cir_en);
+
+}
+
+static int debug_set_speaker_delay(char *buf, int size)
+{
+	int	delay;
+	int	cnt;
+
+	cnt = sscanf(buf, "%d", &delay);
+	if (cnt < 1) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_set_speaker_delay(delay) < 0)
+		return -EFAULT;
+
+	return size;
+}
+
+static int debug_speaker_1k6_zin_enable(char *buf, int size)
+{
+	uint enable;
+	int	cnt;
+
+	cnt = sscanf(buf, "%u", &enable);
+	if (cnt < 1) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_speaker_1k6_zin_enable(enable) < 0)
+		return -EFAULT;
+
+	return size;
+}
+
+static int debug_spkr_set_mux_hpf_corner_freq(char *buf, int size)
+{
+	int	freq;
+	int	cnt;
+
+	cnt = sscanf(buf, "%d", &freq);
+	if (cnt < 1) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_spkr_set_mux_hpf_corner_freq(freq) < 0)
+		return -EFAULT;
+
+	return size;
+}
+
+static int debug_spkr_get_mux_hpf_corner_freq(char *buf, int size)
+{
+	uint freq;
+
+	if (pmic_spkr_get_mux_hpf_corner_freq(&freq) < 0)
+		return -EFAULT;
+
+	return snprintf(buf, size, "%d\n", freq);
+}
+
+static int debug_spkr_add_right_left_chan(char *buf, int size)
+{
+	int	enable;
+	int	cnt;
+
+	cnt = sscanf(buf, "%d", &enable);
+	if (cnt < 1) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_spkr_add_right_left_chan(enable) < 0)
+		return -EFAULT;
+
+	return size;
+}
+
+static int debug_spkr_is_right_left_chan_added(char *buf, int size)
+{
+	int	enabled;
+
+	if (pmic_spkr_is_right_left_chan_added(&enabled) < 0)
+		return -EFAULT;
+
+	return snprintf(buf, size, "%d\n", enabled);
+}
+
+static int debug_spkr_en_stereo(char *buf, int size)
+{
+	int	enable;
+	int	cnt;
+
+	cnt = sscanf(buf, "%d", &enable);
+	if (cnt < 1) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_spkr_en_stereo(enable) < 0)
+		return -EFAULT;
+
+	return size;
+}
+static int debug_spkr_is_stereo_en(char *buf, int size)
+{
+	int	enabled;
+
+	if (pmic_spkr_is_stereo_en(&enabled) < 0)
+		return -EFAULT;
+
+	return snprintf(buf, size, "%d\n", enabled);
+}
+
+static int debug_spkr_select_usb_with_hpf_20hz(char *buf, int size)
+{
+	int	enable;
+	int	cnt;
+
+	cnt = sscanf(buf, "%d", &enable);
+	if (cnt < 1) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_spkr_select_usb_with_hpf_20hz(enable) < 0)
+		return -EFAULT;
+
+	return size;
+}
+static int debug_spkr_is_usb_with_hpf_20hz(char *buf, int size)
+{
+	int	enabled;
+
+	if (pmic_spkr_is_usb_with_hpf_20hz(&enabled) < 0)
+		return -EFAULT;
+
+	return snprintf(buf, size, "%d\n", enabled);
+}
+
+static int debug_spkr_bypass_mux(char *buf, int size)
+{
+	int	enable;
+	int	cnt;
+
+	cnt = sscanf(buf, "%d", &enable);
+	if (cnt < 1) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_spkr_bypass_mux(enable) < 0)
+		return -EFAULT;
+
+	return size;
+}
+static int debug_spkr_is_mux_bypassed(char *buf, int size)
+{
+	int	enabled;
+
+	if (pmic_spkr_is_mux_bypassed(&enabled) < 0)
+		return -EFAULT;
+
+	return snprintf(buf, size, "%d\n", enabled);
+}
+
+static int debug_spkr_en_hpf(char *buf, int size)
+{
+	int	enable;
+	int	cnt;
+
+	cnt = sscanf(buf, "%d", &enable);
+	if (cnt < 1) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_spkr_en_hpf(enable) < 0)
+		return -EFAULT;
+
+	return size;
+}
+static int debug_spkr_is_hpf_en(char *buf, int size)
+{
+	int	enabled;
+
+	if (pmic_spkr_is_hpf_en(&enabled) < 0)
+		return -EFAULT;
+
+	return snprintf(buf, size, "%d\n", enabled);
+}
+
+static int debug_spkr_en_sink_curr_from_ref_volt_cir(char *buf, int size)
+{
+	int	enable;
+	int	cnt;
+
+	cnt = sscanf(buf, "%d", &enable);
+	if (cnt < 1) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_spkr_en_sink_curr_from_ref_volt_cir(enable) < 0)
+		return -EFAULT;
+
+	return size;
+}
+
+static int debug_spkr_is_sink_curr_from_ref_volt_cir_en(char *buf, int size)
+{
+	int	enabled;
+
+	if (pmic_spkr_is_sink_curr_from_ref_volt_cir_en(&enabled) < 0)
+		return -EFAULT;
+
+	return snprintf(buf, size, "%d\n", enabled);
+}
+
+static int debug_vib_mot_set_volt(char *buf, int size)
+{
+	int vol;
+	int	cnt;
+
+	cnt = sscanf(buf, "%d", &vol);
+	if (cnt < 1) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_vib_mot_set_volt(vol) < 0)
+		return -EFAULT;
+
+	return size;
+}
+static int debug_vib_mot_set_mode(char *buf, int size)
+{
+	int mode;
+	int	cnt;
+
+	cnt = sscanf(buf, "%d", &mode);
+	if (cnt < 1) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_vib_mot_set_mode(mode) < 0)
+		return -EFAULT;
+
+	return size;
+}
+
+static int debug_vib_mot_set_polarity(char *buf, int size)
+{
+	int	pol;
+	int	cnt;
+
+	cnt = sscanf(buf, "%d", &pol);
+	if (cnt < 1) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_vib_mot_set_polarity(pol) < 0)
+		return -EFAULT;
+
+	return size;
+}
+static int debug_vid_en(char *buf, int size)
+{
+	int	enable;
+	int	cnt;
+
+	cnt = sscanf(buf, "%d", &enable);
+	if (cnt < 1) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_vid_en(enable) < 0)
+		return -EFAULT;
+
+	return size;
+}
+static int debug_vid_is_en(char *buf, int size)
+{
+	int	enabled;
+
+	if (pmic_vid_is_en(&enabled) < 0)
+		return -EFAULT;
+
+	return snprintf(buf, size, "%d\n", enabled);
+}
+
+static int debug_vid_load_detect_en(char *buf, int size)
+{
+	int	enable;
+	int	cnt;
+
+	cnt = sscanf(buf, "%d", &enable);
+	if (cnt < 1) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_vid_load_detect_en(enable) < 0)
+		return -EFAULT;
+
+	return size;
+}
+
+/**************************************************
+ * 	speaker indexed by left_right
+**************************************************/
+static enum spkr_left_right debug_spkr_left_right = LEFT_SPKR;
+
+static int debug_spkr_en(char *buf, int size)
+{
+	int	left_right;
+	int	enable;
+	int	cnt;
+
+	cnt = sscanf(buf, "%d %d", &left_right, &enable);
+	if (cnt < 2) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_spkr_en(left_right, enable) >= 0) {
+		debug_spkr_left_right = left_right;
+		return size;
+	}
+	return -EFAULT;
+}
+
+static int debug_spkr_is_en(char *buf, int size)
+{
+	int	enabled;
+
+	if (pmic_spkr_is_en(debug_spkr_left_right, &enabled) < 0)
+		return -EFAULT;
+
+	return snprintf(buf, size, "%d\n", enabled);
+}
+
+static int debug_spkr_set_gain(char *buf, int size)
+{
+	int	left_right;
+	int	enable;
+	int	cnt;
+
+	cnt = sscanf(buf, "%d %d", &left_right, &enable);
+	if (cnt < 2) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_spkr_set_gain(left_right, enable) >= 0) {
+		debug_spkr_left_right = left_right;
+		return size;
+	}
+	return -EFAULT;
+}
+
+static int debug_spkr_get_gain(char *buf, int size)
+{
+	uint gain;
+
+	if (pmic_spkr_get_gain(debug_spkr_left_right, &gain) < 0)
+		return -EFAULT;
+
+	return snprintf(buf, size, "%d\n", gain);
+}
+static int debug_spkr_set_delay(char *buf, int size)
+{
+	int	left_right;
+	int	delay;
+	int	cnt;
+
+	cnt = sscanf(buf, "%d %d", &left_right, &delay);
+	if (cnt < 2) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_spkr_set_delay(left_right, delay) >= 0) {
+		debug_spkr_left_right = left_right;
+		return size;
+	}
+	return -EFAULT;
+}
+
+static int debug_spkr_get_delay(char *buf, int size)
+{
+	uint delay;
+
+	if (pmic_spkr_get_delay(debug_spkr_left_right, &delay) < 0)
+		return -EFAULT;
+
+	return snprintf(buf, size, "%d\n", delay);
+}
+
+static int debug_spkr_en_mute(char *buf, int size)
+{
+	int	left_right;
+	int	enable;
+	int	cnt;
+
+	cnt = sscanf(buf, "%d %d", &left_right, &enable);
+	if (cnt < 2) {
+		printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+		return -EINVAL;
+	}
+	if (pmic_spkr_en_mute(left_right, enable) >= 0) {
+		debug_spkr_left_right = left_right;
+		return size;
+	}
+	return -EFAULT;
+}
+
+static int debug_spkr_is_mute_en(char *buf, int size)
+{
+	int	enabled;
+
+	if (pmic_spkr_is_mute_en(debug_spkr_left_right, &enabled) < 0)
+		return -EFAULT;
+
+	return snprintf(buf, size, "%d\n", enabled);
+}
+
+/*******************************************************************
+ * debug function table
+*******************************************************************/
+
+struct	pmic_debug_desc {
+	int (*get) (char *, int);
+	int (*set) (char *, int);
+};
+
+struct pmic_debug_desc pmic_debug[] = {
+	{NULL, NULL},	/*LIB_NULL_PROC */
+	{NULL, NULL}, /* LIB_RPC_GLUE_CODE_INFO_REMOTE_PROC */
+	{NULL, debug_lp_mode_control}, /* LP_MODE_CONTROL_PROC */
+	{NULL, debug_vreg_set_level}, /*VREG_SET_LEVEL_PROC */
+	{NULL, debug_vreg_pull_down_switch}, /*VREG_PULL_DOWN_SWITCH_PROC */
+	{NULL, debug_secure_mpp_control_digital_output},
+				/* SECURE_MPP_CONFIG_DIGITAL_OUTPUT_PROC */
+	/*SECURE_MPP_CONFIG_I_SINK_PROC */
+	{NULL, debug_secure_mpp_config_i_sink},
+	{NULL, debug_rtc_start}, /*RTC_START_PROC */
+	{NULL, debug_rtc_stop}, /* RTC_STOP_PROC */
+	{debug_rtc_get_time, NULL}, /* RTC_GET_TIME_PROC */
+	{NULL, debug_rtc_enable_alarm}, /* RTC_ENABLE_ALARM_PROC */
+	{NULL , debug_rtc_disable_alarm}, /*RTC_DISABLE_ALARM_PROC */
+	{debug_rtc_get_alarm_time, NULL}, /* RTC_GET_ALARM_TIME_PROC */
+	{debug_rtc_get_alarm_status, NULL}, /* RTC_GET_ALARM_STATUS_PROC */
+	{NULL, debug_rtc_set_time_adjust}, /* RTC_SET_TIME_ADJUST_PROC */
+	{debug_rtc_get_time_adjust, NULL}, /* RTC_GET_TIME_ADJUST_PROC */
+	{NULL, debug_set_led_intensity}, /* SET_LED_INTENSITY_PROC */
+	{NULL, debug_flash_led_set_current}, /* FLASH_LED_SET_CURRENT_PROC */
+	{NULL, debug_flash_led_set_mode}, /* FLASH_LED_SET_MODE_PROC */
+	{NULL, debug_flash_led_set_polarity}, /* FLASH_LED_SET_POLARITY_PROC */
+	{NULL, debug_speaker_cmd}, /* SPEAKER_CMD_PROC */
+	{NULL, debug_set_speaker_gain}, /* SET_SPEAKER_GAIN_PROC */
+	{NULL, debug_vib_mot_set_volt}, /* VIB_MOT_SET_VOLT_PROC */
+	{NULL, debug_vib_mot_set_mode}, /* VIB_MOT_SET_MODE_PROC */
+	{NULL, debug_vib_mot_set_polarity}, /* VIB_MOT_SET_POLARITY_PROC */
+	{NULL, debug_vid_en}, /* VID_EN_PROC */
+	{debug_vid_is_en, NULL}, /* VID_IS_EN_PROC */
+	{NULL, debug_vid_load_detect_en}, /* VID_LOAD_DETECT_EN_PROC */
+	{NULL, debug_mic_en}, /* MIC_EN_PROC */
+	{debug_mic_is_en, NULL}, /* MIC_IS_EN_PROC */
+	{NULL, debug_mic_set_volt}, /* MIC_SET_VOLT_PROC */
+	{debug_mic_get_volt, NULL}, /* MIC_GET_VOLT_PROC */
+	{NULL, debug_spkr_en_right_chan}, /* SPKR_EN_RIGHT_CHAN_PROC */
+	{debug_spkr_is_right_chan_en, NULL}, /* SPKR_IS_RIGHT_CHAN_EN_PROC */
+	{NULL, debug_spkr_en_left_chan}, /* SPKR_EN_LEFT_CHAN_PROC */
+	{debug_spkr_is_left_chan_en, NULL}, /* SPKR_IS_LEFT_CHAN_EN_PROC */
+	{NULL, debug_set_spkr_configuration}, /* SET_SPKR_CONFIGURATION_PROC */
+	{debug_get_spkr_configuration, NULL}, /* GET_SPKR_CONFIGURATION_PROC */
+	{debug_spkr_get_gain, NULL}, /* SPKR_GET_GAIN_PROC */
+	{debug_spkr_is_en, NULL}, /* SPKR_IS_EN_PROC */
+	{NULL, debug_spkr_en_mute}, /* SPKR_EN_MUTE_PROC */
+	{debug_spkr_is_mute_en, NULL}, /* SPKR_IS_MUTE_EN_PROC */
+	{NULL, debug_spkr_set_delay}, /* SPKR_SET_DELAY_PROC */
+	{debug_spkr_get_delay, NULL}, /* SPKR_GET_DELAY_PROC */
+	/* SECURE_MPP_CONFIG_DIGITAL_INPUT_PROC */
+	{NULL, debug_secure_mpp_config_digital_input},
+	{NULL, debug_set_speaker_delay}, /* SET_SPEAKER_DELAY_PROC */
+	{NULL, debug_speaker_1k6_zin_enable}, /* SPEAKER_1K6_ZIN_ENABLE_PROC */
+	/* SPKR_SET_MUX_HPF_CORNER_FREQ_PROC */
+	{NULL, debug_spkr_set_mux_hpf_corner_freq},
+	/* SPKR_GET_MUX_HPF_CORNER_FREQ_PROC */
+	{debug_spkr_get_mux_hpf_corner_freq, NULL},
+	/* SPKR_IS_RIGHT_LEFT_CHAN_ADDED_PROC */
+	{debug_spkr_is_right_left_chan_added, NULL},
+	{NULL, debug_spkr_en_stereo}, /* SPKR_EN_STEREO_PROC */
+	{debug_spkr_is_stereo_en, NULL}, /* SPKR_IS_STEREO_EN_PROC */
+	 /* SPKR_SELECT_USB_WITH_HPF_20HZ_PROC */
+	{NULL, debug_spkr_select_usb_with_hpf_20hz},
+	/* SPKR_IS_USB_WITH_HPF_20HZ_PROC */
+	{debug_spkr_is_usb_with_hpf_20hz, NULL},
+	{NULL, debug_spkr_bypass_mux}, /* SPKR_BYPASS_MUX_PROC */
+	{debug_spkr_is_mux_bypassed, NULL}, /* SPKR_IS_MUX_BYPASSED_PROC */
+	{NULL, debug_spkr_en_hpf}, /* SPKR_EN_HPF_PROC */
+	{ debug_spkr_is_hpf_en, NULL}, /* SPKR_IS_HPF_EN_PROC */
+	/* SPKR_EN_SINK_CURR_FROM_REF_VOLT_CIR_PROC */
+	{NULL, debug_spkr_en_sink_curr_from_ref_volt_cir},
+	/* SPKR_IS_SINK_CURR_FROM_REF_VOLT_CIR_EN_PROC */
+	{debug_spkr_is_sink_curr_from_ref_volt_cir_en, NULL},
+	/* SPKR_ADD_RIGHT_LEFT_CHAN_PROC */
+	{NULL, debug_spkr_add_right_left_chan},
+	{NULL, debug_spkr_set_gain}, /* SPKR_SET_GAIN_PROC */
+	{NULL , debug_spkr_en}, /* SPKR_EN_PROC */
+};
+
+/***********************************************************************/
+
+#define PROC_END (sizeof(pmic_debug)/sizeof(struct pmic_debug_desc))
+
+
+#define PMIC_DEBUG_BUF	512
+
+static int	debug_proc;		/* PROC's index */
+
+static char	debug_buf[PMIC_DEBUG_BUF];
+
+static int proc_index_set(void *data, u64 val)
+{
+	int	ndx;
+
+	ndx = (int)val;
+
+	if (ndx >= 0 && ndx <= PROC_END)
+		debug_proc = ndx;
+
+	return 0;
+}
+
+static int proc_index_get(void *data, u64 *val)
+{
+	*val = (u64)debug_proc;
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(
+			proc_index_fops,
+			proc_index_get,
+			proc_index_set,
+			"%llu\n");
+
+
+static int pmic_debugfs_open(struct inode *inode, struct file *file)
+{
+	/* non-seekable */
+	file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
+	return 0;
+}
+
+static int pmic_debugfs_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static ssize_t pmic_debugfs_write(
+	struct file *file,
+	const char __user *buff,
+	size_t count,
+	loff_t *ppos)
+{
+	struct pmic_debug_desc *pd;
+	int len = 0;
+
+	printk(KERN_INFO "%s: proc=%d count=%d *ppos=%d\n",
+			__func__, debug_proc, count, (uint)*ppos);
+
+	if (count > sizeof(debug_buf))
+		return -EFAULT;
+
+	if (copy_from_user(debug_buf, buff, count))
+		return -EFAULT;
+
+
+	debug_buf[count] = 0;	/* end of string */
+
+	pd = &pmic_debug[debug_proc];
+
+	if (pd->set) {
+		len = pd->set(debug_buf, count);
+		printk(KERN_INFO "%s: len=%d\n", __func__, len);
+		return len;
+	}
+
+	return 0;
+}
+
+static ssize_t pmic_debugfs_read(
+	struct file *file,
+	char __user *buff,
+	size_t count,
+	loff_t *ppos)
+{
+	struct pmic_debug_desc *pd;
+	int len = 0;
+
+	printk(KERN_INFO "%s: proc=%d count=%d *ppos=%d\n",
+			__func__, debug_proc, count, (uint)*ppos);
+
+	pd = &pmic_debug[debug_proc];
+
+	if (*ppos)
+		return 0;	/* the end */
+
+	if (pd->get) {
+		len = pd->get(debug_buf, sizeof(debug_buf));
+		if (len > 0) {
+			if (len > count)
+				len = count;
+			if (copy_to_user(buff, debug_buf, len))
+				return -EFAULT;
+		}
+	}
+
+	printk(KERN_INFO "%s: len=%d\n", __func__, len);
+
+	if (len < 0)
+		return 0;
+
+	*ppos += len;	/* increase offset */
+
+	return len;
+}
+
+static const struct file_operations pmic_debugfs_fops = {
+	.open = pmic_debugfs_open,
+	.release = pmic_debugfs_release,
+	.read = pmic_debugfs_read,
+	.write = pmic_debugfs_write,
+};
+
+static int __init pmic_debugfs_init(void)
+{
+	struct dentry *dent = debugfs_create_dir("pmic", NULL);
+
+	if (IS_ERR(dent)) {
+		printk(KERN_ERR "%s(%d): debugfs_create_dir fail, error %ld\n",
+			__FILE__, __LINE__, PTR_ERR(dent));
+		return -1;
+	}
+
+	if (debugfs_create_file("index", 0644, dent, 0, &proc_index_fops)
+			== NULL) {
+		printk(KERN_ERR "%s(%d): debugfs_create_file: index fail\n",
+			__FILE__, __LINE__);
+		return -1;
+	}
+
+	if (debugfs_create_file("debug", 0644, dent, 0, &pmic_debugfs_fops)
+			== NULL) {
+		printk(KERN_ERR "%s(%d): debugfs_create_file: debug fail\n",
+			__FILE__, __LINE__);
+		return -1;
+	}
+
+	debug_proc = 0;
+	debug_rtc_alarm_ndx = 0;
+
+	return 0;
+}
+
+late_initcall(pmic_debugfs_init);
diff --git a/arch/arm/mach-msm/pmu.c b/arch/arm/mach-msm/pmu.c
new file mode 100644
index 0000000..1f82468
--- /dev/null
+++ b/arch/arm/mach-msm/pmu.c
@@ -0,0 +1,62 @@
+/* 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
+ * 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/platform_device.h>
+#include <asm/pmu.h>
+#include <mach/irqs.h>
+
+static struct resource cpu_pmu_resource[] = {
+	{
+		.start = INT_ARMQC_PERFMON,
+		.end = INT_ARMQC_PERFMON,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+#ifdef CONFIG_CPU_HAS_L2_PMU
+static struct resource l2_pmu_resource[] = {
+	{
+		.start = SC_SICL2PERFMONIRPTREQ,
+		.end = SC_SICL2PERFMONIRPTREQ,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device l2_pmu_device = {
+	.name		= "l2-arm-pmu",
+	.id		= ARM_PMU_DEVICE_L2,
+	.resource	= l2_pmu_resource,
+	.num_resources	= ARRAY_SIZE(l2_pmu_resource),
+};
+
+#endif
+
+static struct platform_device cpu_pmu_device = {
+	.name		= "cpu-arm-pmu",
+	.id		= ARM_PMU_DEVICE_CPU,
+	.resource	= cpu_pmu_resource,
+	.num_resources	= ARRAY_SIZE(cpu_pmu_resource),
+};
+
+static struct platform_device *pmu_devices[] = {
+	&cpu_pmu_device,
+#ifdef CONFIG_CPU_HAS_L2_PMU
+	&l2_pmu_device,
+#endif
+};
+
+static int __init msm_pmu_init(void)
+{
+	return platform_add_devices(pmu_devices, ARRAY_SIZE(pmu_devices));
+}
+
+arch_initcall(msm_pmu_init);
diff --git a/arch/arm/mach-msm/proc_comm.c b/arch/arm/mach-msm/proc_comm.c
index 9980dc7..421e7de 100644
--- a/arch/arm/mach-msm/proc_comm.c
+++ b/arch/arm/mach-msm/proc_comm.c
@@ -1,6 +1,7 @@
 /* arch/arm/mach-msm/proc_comm.c
  *
  * Copyright (C) 2007-2008 Google, Inc.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -18,23 +19,24 @@
 #include <linux/errno.h>
 #include <linux/io.h>
 #include <linux/spinlock.h>
+#include <linux/module.h>
 #include <mach/msm_iomap.h>
 #include <mach/system.h>
+#include <mach/proc_comm.h>
 
-#include "proc_comm.h"
-
-static inline void msm_a2m_int(uint32_t irq)
-{
-#if defined(CONFIG_ARCH_MSM7X30)
-	writel(1 << irq, MSM_GCC_BASE + 0x8);
-#else
-	writel(1, MSM_CSR_BASE + 0x400 + (irq * 4));
-#endif
-}
+#include "smd_private.h"
 
 static inline void notify_other_proc_comm(void)
 {
-	msm_a2m_int(6);
+	/* Make sure the write completes before interrupt */
+	wmb();
+#if defined(CONFIG_ARCH_MSM7X30)
+	__raw_writel(1 << 6, MSM_APCS_GCC_BASE + 0x8);
+#elif defined(CONFIG_ARCH_MSM8X60)
+	__raw_writel(1 << 5, MSM_GCC_BASE + 0x8);
+#else
+	__raw_writel(1, MSM_CSR_BASE + 0x400 + (6) * 4);
+#endif
 }
 
 #define APP_COMMAND 0x00
@@ -48,83 +50,109 @@
 #define MDM_DATA2   0x1C
 
 static DEFINE_SPINLOCK(proc_comm_lock);
-
-/* The higher level SMD support will install this to
- * provide a way to check for and handle modem restart.
- */
-int (*msm_check_for_modem_crash)(void);
+static int msm_proc_comm_disable;
 
 /* Poll for a state change, checking for possible
  * modem crashes along the way (so we don't wait
- * forever while the ARM9 is blowing up).
+ * forever while the ARM9 is blowing up.
  *
  * Return an error in the event of a modem crash and
  * restart so the msm_proc_comm() routine can restart
  * the operation from the beginning.
  */
-static int proc_comm_wait_for(void __iomem *addr, unsigned value)
+static int proc_comm_wait_for(unsigned addr, unsigned value)
 {
-	for (;;) {
-		if (readl(addr) == value)
+	while (1) {
+		/* Barrier here prevents excessive spinning */
+		mb();
+		if (readl_relaxed(addr) == value)
 			return 0;
 
-		if (msm_check_for_modem_crash)
-			if (msm_check_for_modem_crash())
-				return -EAGAIN;
+		if (smsm_check_for_modem_crash())
+			return -EAGAIN;
+
+		udelay(5);
 	}
 }
 
+void msm_proc_comm_reset_modem_now(void)
+{
+	unsigned base = (unsigned)MSM_SHARED_RAM_BASE;
+	unsigned long flags;
+
+	spin_lock_irqsave(&proc_comm_lock, flags);
+
+again:
+	if (proc_comm_wait_for(base + MDM_STATUS, PCOM_READY))
+		goto again;
+
+	writel_relaxed(PCOM_RESET_MODEM, base + APP_COMMAND);
+	writel_relaxed(0, base + APP_DATA1);
+	writel_relaxed(0, base + APP_DATA2);
+
+	spin_unlock_irqrestore(&proc_comm_lock, flags);
+
+	/* Make sure the writes complete before notifying the other side */
+	wmb();
+	notify_other_proc_comm();
+
+	return;
+}
+EXPORT_SYMBOL(msm_proc_comm_reset_modem_now);
+
 int msm_proc_comm(unsigned cmd, unsigned *data1, unsigned *data2)
 {
-	void __iomem *base = MSM_SHARED_RAM_BASE;
+	unsigned base = (unsigned)MSM_SHARED_RAM_BASE;
 	unsigned long flags;
 	int ret;
 
 	spin_lock_irqsave(&proc_comm_lock, flags);
 
-	for (;;) {
-		if (proc_comm_wait_for(base + MDM_STATUS, PCOM_READY))
-			continue;
-
-		writel(cmd, base + APP_COMMAND);
-		writel(data1 ? *data1 : 0, base + APP_DATA1);
-		writel(data2 ? *data2 : 0, base + APP_DATA2);
-
-		notify_other_proc_comm();
-
-		if (proc_comm_wait_for(base + APP_COMMAND, PCOM_CMD_DONE))
-			continue;
-
-		if (readl(base + APP_STATUS) != PCOM_CMD_FAIL) {
-			if (data1)
-				*data1 = readl(base + APP_DATA1);
-			if (data2)
-				*data2 = readl(base + APP_DATA2);
-			ret = 0;
-		} else {
-			ret = -EIO;
-		}
-		break;
+	if (msm_proc_comm_disable) {
+		ret = -EIO;
+		goto end;
 	}
 
-	writel(PCOM_CMD_IDLE, base + APP_COMMAND);
 
+again:
+	if (proc_comm_wait_for(base + MDM_STATUS, PCOM_READY))
+		goto again;
+
+	writel_relaxed(cmd, base + APP_COMMAND);
+	writel_relaxed(data1 ? *data1 : 0, base + APP_DATA1);
+	writel_relaxed(data2 ? *data2 : 0, base + APP_DATA2);
+
+	/* Make sure the writes complete before notifying the other side */
+	wmb();
+	notify_other_proc_comm();
+
+	if (proc_comm_wait_for(base + APP_COMMAND, PCOM_CMD_DONE))
+		goto again;
+
+	if (readl_relaxed(base + APP_STATUS) == PCOM_CMD_SUCCESS) {
+		if (data1)
+			*data1 = readl_relaxed(base + APP_DATA1);
+		if (data2)
+			*data2 = readl_relaxed(base + APP_DATA2);
+		ret = 0;
+	} else {
+		ret = -EIO;
+	}
+
+	writel_relaxed(PCOM_CMD_IDLE, base + APP_COMMAND);
+
+	switch (cmd) {
+	case PCOM_RESET_CHIP:
+	case PCOM_RESET_CHIP_IMM:
+	case PCOM_RESET_APPS:
+		msm_proc_comm_disable = 1;
+		printk(KERN_ERR "msm: proc_comm: proc comm disabled\n");
+		break;
+	}
+end:
+	/* Make sure the writes complete before returning */
+	wmb();
 	spin_unlock_irqrestore(&proc_comm_lock, flags);
-
 	return ret;
 }
-
-/*
- * We need to wait for the ARM9 to at least partially boot
- * up before we can continue. Since the ARM9 does resource
- * allocation, if we dont' wait we could end up crashing or in
- * and unknown state. This function should be called early to
- * wait on the ARM9.
- */
-void __devinit proc_comm_boot_wait(void)
-{
-	void __iomem *base = MSM_SHARED_RAM_BASE;
- 
-	proc_comm_wait_for(base + MDM_STATUS, PCOM_READY);
- 
-}
+EXPORT_SYMBOL(msm_proc_comm);
diff --git a/arch/arm/mach-msm/proc_comm.h b/arch/arm/mach-msm/proc_comm.h
deleted file mode 100644
index 12da4ca..0000000
--- a/arch/arm/mach-msm/proc_comm.h
+++ /dev/null
@@ -1,258 +0,0 @@
-/* arch/arm/mach-msm/proc_comm.h
- *
- * Copyright (c) 2007 QUALCOMM Incorporated
- *
- * 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 _ARCH_ARM_MACH_MSM_PROC_COMM_H_
-#define _ARCH_ARM_MACH_MSM_PROC_COMM_H_
-
-#include <linux/init.h>
-
-enum {
-	PCOM_CMD_IDLE = 0x0,
-	PCOM_CMD_DONE,
-	PCOM_RESET_APPS,
-	PCOM_RESET_CHIP,
-	PCOM_CONFIG_NAND_MPU,
-	PCOM_CONFIG_USB_CLKS,
-	PCOM_GET_POWER_ON_STATUS,
-	PCOM_GET_WAKE_UP_STATUS,
-	PCOM_GET_BATT_LEVEL,
-	PCOM_CHG_IS_CHARGING,
-	PCOM_POWER_DOWN,
-	PCOM_USB_PIN_CONFIG,
-	PCOM_USB_PIN_SEL,
-	PCOM_SET_RTC_ALARM,
-	PCOM_NV_READ,
-	PCOM_NV_WRITE,
-	PCOM_GET_UUID_HIGH,
-	PCOM_GET_UUID_LOW,
-	PCOM_GET_HW_ENTROPY,
-	PCOM_RPC_GPIO_TLMM_CONFIG_REMOTE,
-	PCOM_CLKCTL_RPC_ENABLE,
-	PCOM_CLKCTL_RPC_DISABLE,
-	PCOM_CLKCTL_RPC_RESET,
-	PCOM_CLKCTL_RPC_SET_FLAGS,
-	PCOM_CLKCTL_RPC_SET_RATE,
-	PCOM_CLKCTL_RPC_MIN_RATE,
-	PCOM_CLKCTL_RPC_MAX_RATE,
-	PCOM_CLKCTL_RPC_RATE,
-	PCOM_CLKCTL_RPC_PLL_REQUEST,
-	PCOM_CLKCTL_RPC_ENABLED,
-	PCOM_VREG_SWITCH,
-	PCOM_VREG_SET_LEVEL,
-	PCOM_GPIO_TLMM_CONFIG_GROUP,
-	PCOM_GPIO_TLMM_UNCONFIG_GROUP,
-	PCOM_NV_WRITE_BYTES_4_7,
-	PCOM_CONFIG_DISP,
-	PCOM_GET_FTM_BOOT_COUNT,
-	PCOM_RPC_GPIO_TLMM_CONFIG_EX,
-	PCOM_PM_MPP_CONFIG,
-	PCOM_GPIO_IN,
-	PCOM_GPIO_OUT,
-	PCOM_RESET_MODEM,
-	PCOM_RESET_CHIP_IMM,
-	PCOM_PM_VID_EN,
-	PCOM_VREG_PULLDOWN,
-	PCOM_GET_MODEM_VERSION,
-	PCOM_CLK_REGIME_SEC_RESET,
-	PCOM_CLK_REGIME_SEC_RESET_ASSERT,
-	PCOM_CLK_REGIME_SEC_RESET_DEASSERT,
-	PCOM_CLK_REGIME_SEC_PLL_REQUEST_WRP,
-	PCOM_CLK_REGIME_SEC_ENABLE,
-	PCOM_CLK_REGIME_SEC_DISABLE,
-	PCOM_CLK_REGIME_SEC_IS_ON,
-	PCOM_CLK_REGIME_SEC_SEL_CLK_INV,
-	PCOM_CLK_REGIME_SEC_SEL_CLK_SRC,
-	PCOM_CLK_REGIME_SEC_SEL_CLK_DIV,
-	PCOM_CLK_REGIME_SEC_ICODEC_CLK_ENABLE,
-	PCOM_CLK_REGIME_SEC_ICODEC_CLK_DISABLE,
-	PCOM_CLK_REGIME_SEC_SEL_SPEED,
-	PCOM_CLK_REGIME_SEC_CONFIG_GP_CLK_WRP,
-	PCOM_CLK_REGIME_SEC_CONFIG_MDH_CLK_WRP,
-	PCOM_CLK_REGIME_SEC_USB_XTAL_ON,
-	PCOM_CLK_REGIME_SEC_USB_XTAL_OFF,
-	PCOM_CLK_REGIME_SEC_SET_QDSP_DME_MODE,
-	PCOM_CLK_REGIME_SEC_SWITCH_ADSP_CLK,
-	PCOM_CLK_REGIME_SEC_GET_MAX_ADSP_CLK_KHZ,
-	PCOM_CLK_REGIME_SEC_GET_I2C_CLK_KHZ,
-	PCOM_CLK_REGIME_SEC_MSM_GET_CLK_FREQ_KHZ,
-	PCOM_CLK_REGIME_SEC_SEL_VFE_SRC,
-	PCOM_CLK_REGIME_SEC_MSM_SEL_CAMCLK,
-	PCOM_CLK_REGIME_SEC_MSM_SEL_LCDCLK,
-	PCOM_CLK_REGIME_SEC_VFE_RAIL_OFF,
-	PCOM_CLK_REGIME_SEC_VFE_RAIL_ON,
-	PCOM_CLK_REGIME_SEC_GRP_RAIL_OFF,
-	PCOM_CLK_REGIME_SEC_GRP_RAIL_ON,
-	PCOM_CLK_REGIME_SEC_VDC_RAIL_OFF,
-	PCOM_CLK_REGIME_SEC_VDC_RAIL_ON,
-	PCOM_CLK_REGIME_SEC_LCD_CTRL,
-	PCOM_CLK_REGIME_SEC_REGISTER_FOR_CPU_RESOURCE,
-	PCOM_CLK_REGIME_SEC_DEREGISTER_FOR_CPU_RESOURCE,
-	PCOM_CLK_REGIME_SEC_RESOURCE_REQUEST_WRP,
-	PCOM_CLK_REGIME_MSM_SEC_SEL_CLK_OWNER,
-	PCOM_CLK_REGIME_SEC_DEVMAN_REQUEST_WRP,
-	PCOM_GPIO_CONFIG,
-	PCOM_GPIO_CONFIGURE_GROUP,
-	PCOM_GPIO_TLMM_SET_PORT,
-	PCOM_GPIO_TLMM_CONFIG_EX,
-	PCOM_SET_FTM_BOOT_COUNT,
-	PCOM_RESERVED0,
-	PCOM_RESERVED1,
-	PCOM_CUSTOMER_CMD1,
-	PCOM_CUSTOMER_CMD2,
-	PCOM_CUSTOMER_CMD3,
-	PCOM_CLK_REGIME_ENTER_APPSBL_CHG_MODE,
-	PCOM_CLK_REGIME_EXIT_APPSBL_CHG_MODE,
-	PCOM_CLK_REGIME_SEC_RAIL_DISABLE,
-	PCOM_CLK_REGIME_SEC_RAIL_ENABLE,
-	PCOM_CLK_REGIME_SEC_RAIL_CONTROL,
-	PCOM_SET_SW_WATCHDOG_STATE,
-	PCOM_PM_MPP_CONFIG_DIGITAL_INPUT,
-	PCOM_PM_MPP_CONFIG_I_SINK,
-	PCOM_RESERVED_101,
-	PCOM_MSM_HSUSB_PHY_RESET,
-	PCOM_GET_BATT_MV_LEVEL,
-	PCOM_CHG_USB_IS_PC_CONNECTED,
-	PCOM_CHG_USB_IS_CHARGER_CONNECTED,
-	PCOM_CHG_USB_IS_DISCONNECTED,
-	PCOM_CHG_USB_IS_AVAILABLE,
-	PCOM_CLK_REGIME_SEC_MSM_SEL_FREQ,
-	PCOM_CLK_REGIME_SEC_SET_PCLK_AXI_POLICY,
-	PCOM_CLKCTL_RPC_RESET_ASSERT,
-	PCOM_CLKCTL_RPC_RESET_DEASSERT,
-	PCOM_CLKCTL_RPC_RAIL_ON,
-	PCOM_CLKCTL_RPC_RAIL_OFF,
-	PCOM_CLKCTL_RPC_RAIL_ENABLE,
-	PCOM_CLKCTL_RPC_RAIL_DISABLE,
-	PCOM_CLKCTL_RPC_RAIL_CONTROL,
-	PCOM_CLKCTL_RPC_MIN_MSMC1,
-	PCOM_NUM_CMDS,
-};
-
-enum {
-	PCOM_INVALID_STATUS = 0x0,
-	PCOM_READY,
-	PCOM_CMD_RUNNING,
-	PCOM_CMD_SUCCESS,
-	PCOM_CMD_FAIL,
-	PCOM_CMD_FAIL_FALSE_RETURNED,
-	PCOM_CMD_FAIL_CMD_OUT_OF_BOUNDS_SERVER,
-	PCOM_CMD_FAIL_CMD_OUT_OF_BOUNDS_CLIENT,
-	PCOM_CMD_FAIL_CMD_UNREGISTERED,
-	PCOM_CMD_FAIL_CMD_LOCKED,
-	PCOM_CMD_FAIL_SERVER_NOT_YET_READY,
-	PCOM_CMD_FAIL_BAD_DESTINATION,
-	PCOM_CMD_FAIL_SERVER_RESET,
-	PCOM_CMD_FAIL_SMSM_NOT_INIT,
-	PCOM_CMD_FAIL_PROC_COMM_BUSY,
-	PCOM_CMD_FAIL_PROC_COMM_NOT_INIT,
-
-};
-
-/* List of VREGs that support the Pull Down Resistor setting. */
-enum vreg_pdown_id {
-	PM_VREG_PDOWN_MSMA_ID,
-	PM_VREG_PDOWN_MSMP_ID,
-	PM_VREG_PDOWN_MSME1_ID,	/* Not supported in Panoramix */
-	PM_VREG_PDOWN_MSMC1_ID,	/* Not supported in PM6620 */
-	PM_VREG_PDOWN_MSMC2_ID,	/* Supported in PM7500 only */
-	PM_VREG_PDOWN_GP3_ID,	/* Supported in PM7500 only */
-	PM_VREG_PDOWN_MSME2_ID,	/* Supported in PM7500 and Panoramix only */
-	PM_VREG_PDOWN_GP4_ID,	/* Supported in PM7500 only */
-	PM_VREG_PDOWN_GP1_ID,	/* Supported in PM7500 only */
-	PM_VREG_PDOWN_TCXO_ID,
-	PM_VREG_PDOWN_PA_ID,
-	PM_VREG_PDOWN_RFTX_ID,
-	PM_VREG_PDOWN_RFRX1_ID,
-	PM_VREG_PDOWN_RFRX2_ID,
-	PM_VREG_PDOWN_SYNT_ID,
-	PM_VREG_PDOWN_WLAN_ID,
-	PM_VREG_PDOWN_USB_ID,
-	PM_VREG_PDOWN_MMC_ID,
-	PM_VREG_PDOWN_RUIM_ID,
-	PM_VREG_PDOWN_MSMC0_ID,	/* Supported in PM6610 only */
-	PM_VREG_PDOWN_GP2_ID,	/* Supported in PM7500 only */
-	PM_VREG_PDOWN_GP5_ID,	/* Supported in PM7500 only */
-	PM_VREG_PDOWN_GP6_ID,	/* Supported in PM7500 only */
-	PM_VREG_PDOWN_RF_ID,
-	PM_VREG_PDOWN_RF_VCO_ID,
-	PM_VREG_PDOWN_MPLL_ID,
-	PM_VREG_PDOWN_S2_ID,
-	PM_VREG_PDOWN_S3_ID,
-	PM_VREG_PDOWN_RFUBM_ID,
-
-	/* new for HAN */
-	PM_VREG_PDOWN_RF1_ID,
-	PM_VREG_PDOWN_RF2_ID,
-	PM_VREG_PDOWN_RFA_ID,
-	PM_VREG_PDOWN_CDC2_ID,
-	PM_VREG_PDOWN_RFTX2_ID,
-	PM_VREG_PDOWN_USIM_ID,
-	PM_VREG_PDOWN_USB2P6_ID,
-	PM_VREG_PDOWN_USB3P3_ID,
-	PM_VREG_PDOWN_INVALID_ID,
-
-	/* backward compatible enums only */
-	PM_VREG_PDOWN_CAM_ID = PM_VREG_PDOWN_GP1_ID,
-	PM_VREG_PDOWN_MDDI_ID = PM_VREG_PDOWN_GP2_ID,
-	PM_VREG_PDOWN_RUIM2_ID = PM_VREG_PDOWN_GP3_ID,
-	PM_VREG_PDOWN_AUX_ID = PM_VREG_PDOWN_GP4_ID,
-	PM_VREG_PDOWN_AUX2_ID = PM_VREG_PDOWN_GP5_ID,
-	PM_VREG_PDOWN_BT_ID = PM_VREG_PDOWN_GP6_ID,
-
-	PM_VREG_PDOWN_MSME_ID = PM_VREG_PDOWN_MSME1_ID,
-	PM_VREG_PDOWN_MSMC_ID = PM_VREG_PDOWN_MSMC1_ID,
-	PM_VREG_PDOWN_RFA1_ID = PM_VREG_PDOWN_RFRX2_ID,
-	PM_VREG_PDOWN_RFA2_ID = PM_VREG_PDOWN_RFTX2_ID,
-	PM_VREG_PDOWN_XO_ID = PM_VREG_PDOWN_TCXO_ID
-};
-
-enum {
-	PCOM_CLKRGM_APPS_RESET_USB_PHY	= 34,
-	PCOM_CLKRGM_APPS_RESET_USBH	= 37,
-};
-
-/* gpio info for PCOM_RPC_GPIO_TLMM_CONFIG_EX */
-
-#define GPIO_ENABLE	0
-#define GPIO_DISABLE	1
-
-#define GPIO_INPUT	0
-#define GPIO_OUTPUT	1
-
-#define GPIO_NO_PULL	0
-#define GPIO_PULL_DOWN	1
-#define GPIO_KEEPER	2
-#define GPIO_PULL_UP	3
-
-#define GPIO_2MA	0
-#define GPIO_4MA	1
-#define GPIO_6MA	2
-#define GPIO_8MA	3
-#define GPIO_10MA	4
-#define GPIO_12MA	5
-#define GPIO_14MA	6
-#define GPIO_16MA	7
-
-#define PCOM_GPIO_CFG(gpio, func, dir, pull, drvstr) \
-		((((gpio) & 0x3FF) << 4)	| \
-		((func) & 0xf)			| \
-		(((dir) & 0x1) << 14)		| \
-		(((pull) & 0x3) << 15)		| \
-		(((drvstr) & 0xF) << 17))
-
-int msm_proc_comm(unsigned cmd, unsigned *data1, unsigned *data2);
-void __init proc_comm_boot_wait(void);
-
-#endif
diff --git a/arch/arm/mach-msm/proc_comm_test.c b/arch/arm/mach-msm/proc_comm_test.c
new file mode 100644
index 0000000..e4eca11
--- /dev/null
+++ b/arch/arm/mach-msm/proc_comm_test.c
@@ -0,0 +1,125 @@
+/* Copyright (c) 2009, 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.
+ *
+ */
+
+/*
+ * PROC COMM TEST Driver source file
+ */
+
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <mach/proc_comm.h>
+
+static struct dentry *dent;
+static int proc_comm_test_res;
+
+static int proc_comm_reverse_test(void)
+{
+	uint32_t data1, data2;
+	int rc;
+
+	data1 = 10;
+	data2 = 20;
+
+	rc = msm_proc_comm(PCOM_OEM_TEST_CMD, &data1, &data2);
+	if (rc)
+		return rc;
+
+	if ((data1 != 20) || (data2 != 10))
+		return -1;
+
+	return 0;
+}
+
+static ssize_t debug_read(struct file *fp, char __user *buf,
+			  size_t count, loff_t *pos)
+{
+	char _buf[16];
+
+	snprintf(_buf, sizeof(_buf), "%i\n", proc_comm_test_res);
+
+	return simple_read_from_buffer(buf, count, pos, _buf, strlen(_buf));
+}
+
+static ssize_t debug_write(struct file *fp, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+
+	unsigned char cmd[64];
+	int len;
+
+	if (count < 1)
+		return 0;
+
+	len = count > 63 ? 63 : count;
+
+	if (copy_from_user(cmd, buf, len))
+		return -EFAULT;
+
+	cmd[len] = 0;
+
+	if (cmd[len-1] == '\n') {
+		cmd[len-1] = 0;
+		len--;
+	}
+
+	if (!strncmp(cmd, "reverse_test", 64))
+		proc_comm_test_res = proc_comm_reverse_test();
+	else
+		proc_comm_test_res = -EINVAL;
+
+	if (proc_comm_test_res)
+		pr_err("proc comm test fail %d\n",
+		       proc_comm_test_res);
+	else
+		pr_info("proc comm test passed\n");
+
+	return count;
+}
+
+static int debug_release(struct inode *ip, struct file *fp)
+{
+	return 0;
+}
+
+static int debug_open(struct inode *ip, struct file *fp)
+{
+	return 0;
+}
+
+static const struct file_operations debug_ops = {
+	.owner = THIS_MODULE,
+	.open = debug_open,
+	.release = debug_release,
+	.read = debug_read,
+	.write = debug_write,
+};
+
+static void __exit proc_comm_test_mod_exit(void)
+{
+	debugfs_remove(dent);
+}
+
+static int __init proc_comm_test_mod_init(void)
+{
+	dent = debugfs_create_file("proc_comm", 0444, 0, NULL, &debug_ops);
+	proc_comm_test_res = -1;
+	return 0;
+}
+
+module_init(proc_comm_test_mod_init);
+module_exit(proc_comm_test_mod_exit);
+
+MODULE_DESCRIPTION("PROC COMM TEST Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/proccomm-regulator.c b/arch/arm/mach-msm/proccomm-regulator.c
new file mode 100644
index 0000000..21a4f84
--- /dev/null
+++ b/arch/arm/mach-msm/proccomm-regulator.c
@@ -0,0 +1,389 @@
+/*
+ * 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
+ * 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <mach/proc_comm.h>
+#include "proccomm-regulator.h"
+
+#define MV_TO_UV(mv) ((mv)*1000)
+#define UV_TO_MV(uv) (((uv)+999)/1000)
+
+/*
+ * Wrappers for the msm_proc_comm() calls.
+ * Does basic impedance matching between what the proccomm interface
+ * expects and how the driver sees the world.
+ */
+
+/* Converts a proccomm error to an errno value. */
+static int _pcom_err_to_linux_errno(unsigned error)
+{
+	if (!error)		/* 0 == no error */
+		return 0;
+	else if (error & 0x1F)  /* bits 0..4 => parameter 1..5 out of range */
+		return -EDOM;
+	else if (error & 0x100) /* bit 8 => feature not supported */
+		return -ENOSYS;
+	else			/* anything else non-zero: unknown error */
+		return -EINVAL;
+}
+
+/* vreg_switch: (vreg ID, on/off) => (return code, <null>) */
+static int _vreg_switch(int vreg_id, bool enable)
+{
+	unsigned _id		= (unsigned)vreg_id;
+	unsigned _enable	= !!enable;
+
+	return msm_proc_comm(PCOM_VREG_SWITCH, &_id, &_enable);
+}
+
+/* vreg_set_level: (vreg ID, mV) => (return code, <null>) */
+static int _vreg_set_level(int vreg_id, int level_mV)
+{
+	unsigned _id		= (unsigned)vreg_id;
+	unsigned _level		= (unsigned)level_mV;
+	int	 rc;
+
+	rc = msm_proc_comm(PCOM_VREG_SET_LEVEL, &_id, &_level);
+
+	if (rc)
+		return rc;
+
+	return _pcom_err_to_linux_errno(_id);
+}
+
+/* vreg_pull_down: (pull down, vreg ID) => (<null>, <null>) */
+/* Returns error code from msm_proc_comm. */
+static int _vreg_pull_down(int vreg_id, bool pull_down)
+{
+	unsigned _id		= (unsigned)vreg_id;
+	unsigned _enable	= !!pull_down;
+
+	return msm_proc_comm(PCOM_VREG_PULLDOWN, &_enable, &_id);
+}
+
+struct proccomm_regulator_drvdata {
+	struct regulator_desc	rdesc;
+	int			rise_time;
+	int			last_voltage;
+	bool			enabled;
+	bool			negative;
+};
+
+static int proccomm_vreg_enable(struct regulator_dev *rdev)
+{
+	struct proccomm_regulator_drvdata *ddata;
+	int rc;
+
+	ddata = rdev_get_drvdata(rdev);
+	rc = _vreg_switch(rdev_get_id(rdev), VREG_SWITCH_ENABLE);
+
+	if (rc) {
+		dev_err(rdev_get_dev(rdev),
+			"could not enable regulator %d (%s): %d\n",
+			rdev_get_id(rdev), ddata->rdesc.name, rc);
+	} else {
+		dev_dbg(rdev_get_dev(rdev),
+			"enabled regulator %d (%s)\n",
+			rdev_get_id(rdev), ddata->rdesc.name);
+		ddata->enabled = 1;
+	}
+
+	return rc;
+}
+
+static int proccomm_vreg_disable(struct regulator_dev *rdev)
+{
+	struct proccomm_regulator_drvdata *ddata;
+	int rc;
+
+	ddata = rdev_get_drvdata(rdev);
+	rc = _vreg_switch(rdev_get_id(rdev), VREG_SWITCH_DISABLE);
+
+	if (rc) {
+		dev_err(rdev_get_dev(rdev),
+			"could not disable regulator %d (%s): %d\n",
+			rdev_get_id(rdev), ddata->rdesc.name, rc);
+	} else {
+		dev_dbg(rdev_get_dev(rdev),
+			"disabled regulator %d (%s)\n",
+			rdev_get_id(rdev), ddata->rdesc.name);
+		ddata->enabled = 0;
+	}
+
+	return rc;
+}
+
+static int proccomm_vreg_is_enabled(struct regulator_dev *rdev)
+{
+	struct proccomm_regulator_drvdata *ddata = rdev_get_drvdata(rdev);
+
+	return ddata->enabled;
+}
+
+static int proccomm_vreg_rise_time(struct regulator_dev *rdev)
+{
+	struct proccomm_regulator_drvdata *ddata = rdev_get_drvdata(rdev);
+
+	return ddata->rise_time;
+}
+
+static int proccomm_vreg_get_voltage(struct regulator_dev *rdev)
+{
+
+	struct proccomm_regulator_drvdata *ddata = rdev_get_drvdata(rdev);
+
+	return MV_TO_UV(ddata->last_voltage);
+}
+
+static int proccomm_vreg_set_voltage(struct regulator_dev *rdev,
+					int min_uV, int max_uV, unsigned *sel)
+{
+	struct proccomm_regulator_drvdata *ddata = rdev_get_drvdata(rdev);
+	int level_mV = UV_TO_MV(min_uV);
+	int rc;
+
+	rc = _vreg_set_level(rdev_get_id(rdev),
+			ddata->negative ? -level_mV : level_mV);
+
+	if (rc) {
+		dev_err(rdev_get_dev(rdev),
+			"could not set voltage for regulator %d (%s) "
+			"to %d mV: %d\n",
+			rdev_get_id(rdev), ddata->rdesc.name, level_mV, rc);
+	} else {
+		dev_dbg(rdev_get_dev(rdev),
+			"voltage for regulator %d (%s) set to %d mV\n",
+			rdev_get_id(rdev), ddata->rdesc.name, level_mV);
+		ddata->last_voltage = level_mV;
+	}
+
+	return rc;
+}
+
+static struct regulator_ops proccomm_regulator_ops = {
+	.enable		= proccomm_vreg_enable,
+	.disable	= proccomm_vreg_disable,
+	.is_enabled	= proccomm_vreg_is_enabled,
+	.get_voltage	= proccomm_vreg_get_voltage,
+	.set_voltage	= proccomm_vreg_set_voltage,
+	.enable_time	= proccomm_vreg_rise_time,
+};
+
+/*
+ * Create and register a struct regulator_dev based on the information in
+ * a struct proccomm_regulator_info.
+ * Fills in the rdev field in struct proccomm_regulator_info.
+ */
+static struct regulator_dev *__devinit create_proccomm_rdev(
+	struct proccomm_regulator_info *info, struct device *parent)
+{
+	const char *name;
+	struct proccomm_regulator_drvdata *d;
+	struct regulator_dev *rdev;
+	int rc = 0;
+
+	if (info->id < 0) {
+		dev_err(parent, "invalid regulator id %d\n", info->id);
+		rc = -EINVAL;
+		goto out;
+	}
+
+	name = info->init_data.constraints.name;
+
+	if (!name) {
+		dev_err(parent,
+			"could not register regulator with id %d: "
+			"no name specified\n", info->id);
+		rc = -EINVAL;
+		goto out;
+	}
+
+	if (info->pulldown > 0) {
+		rc = _vreg_pull_down(info->id, info->pulldown);
+		if (rc) {
+			dev_err(parent,
+				"probing for regulator %d (%s) failed\n",
+				info->id, name);
+			goto out;
+		}
+	}
+
+	d = kzalloc(sizeof(*d), GFP_KERNEL);
+
+	if (!d) {
+		dev_err(parent,
+			"could not allocate struct proccomm_regulator_drvdata "
+			"for regulator %d (%s)\n", info->id, name);
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	d->rdesc.name	= name;
+	d->rdesc.id	= info->id;
+	d->rdesc.ops	= &proccomm_regulator_ops;
+	d->rdesc.type	= REGULATOR_VOLTAGE;
+	d->rdesc.owner	= THIS_MODULE;
+	d->rise_time	= info->rise_time;
+	d->enabled	= 0;
+	d->negative	= info->negative;
+	d->rdesc.n_voltages = info->n_voltages;
+
+	rdev = regulator_register(&d->rdesc, parent, &info->init_data, d, NULL);
+
+	if (IS_ERR(rdev)) {
+		rc = PTR_ERR(rdev);
+		dev_err(parent, "error registering regulator %d (%s): %d\n",
+				info->id, name, rc);
+		goto clean;
+	}
+
+	dev_dbg(parent, "registered regulator %d (%s)\n", info->id, name);
+
+	return rdev;
+
+clean:
+	kfree(d);
+out:
+	return ERR_PTR(rc);
+}
+
+/*
+ * Unregister and destroy a struct regulator_dev created by
+ * create_proccomm_rdev.
+ */
+static void destroy_proccomm_rdev(struct regulator_dev *rdev)
+{
+	struct proccomm_regulator_drvdata *d;
+
+	if (!rdev)
+		return;
+
+	d = rdev_get_drvdata(rdev);
+
+	regulator_unregister(rdev);
+
+	dev_dbg(rdev_get_dev(rdev)->parent,
+		"unregistered regulator %d (%s)\n",
+		d->rdesc.id, d->rdesc.name);
+
+	kfree(d);
+}
+
+
+static int __devinit proccomm_vreg_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct proccomm_regulator_platform_data *pdata = dev->platform_data;
+	struct regulator_dev **rdevs;
+	int rc = 0;
+	size_t i = 0;
+
+	if (!pdata) {
+		dev_err(dev, "invalid platform data\n");
+		rc = -EINVAL;
+		goto check_fail;
+	}
+
+	if (pdata->nregs == 0) {
+		dev_err(dev, "registering an empty regulator list; "
+				"this is probably not what you want\n");
+		rc = -EINVAL;
+		goto check_fail;
+	}
+
+	rdevs = kcalloc(pdata->nregs, sizeof(*rdevs), GFP_KERNEL);
+
+	if (!rdevs) {
+		dev_err(dev, "could not allocate storage for "
+				"struct regulator_dev array\n");
+		rc = -ENOMEM;
+		goto check_fail;
+	}
+
+	platform_set_drvdata(pdev, rdevs);
+
+	dev_dbg(dev, "registering %d proccomm regulators\n", pdata->nregs);
+
+	for (i = 0; i < pdata->nregs; i++) {
+		rdevs[i] = create_proccomm_rdev(&pdata->regs[i], dev);
+		if (IS_ERR(rdevs[i])) {
+			rc = PTR_ERR(rdevs[i]);
+			goto backout;
+		}
+	}
+
+	dev_dbg(dev, "%d proccomm regulators registered\n", pdata->nregs);
+
+	return rc;
+
+backout:
+	while (--i >= 0)
+		destroy_proccomm_rdev(rdevs[i]);
+
+	kfree(rdevs);
+
+check_fail:
+	return rc;
+}
+
+static int __devexit proccomm_vreg_remove(struct platform_device *pdev)
+{
+	struct proccomm_regulator_platform_data *pdata;
+	struct regulator_dev **rdevs;
+	size_t i;
+
+	pdata = pdev->dev.platform_data;
+	rdevs = platform_get_drvdata(pdev);
+
+	for (i = 0; i < pdata->nregs; i++)
+		destroy_proccomm_rdev(rdevs[i]);
+
+	kfree(rdevs);
+
+	return 0;
+}
+
+static struct platform_driver proccomm_vreg_driver = {
+	.probe	= proccomm_vreg_probe,
+	.remove = __devexit_p(proccomm_vreg_remove),
+	.driver = {
+		.name	= PROCCOMM_REGULATOR_DEV_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init proccomm_vreg_init(void)
+{
+	return platform_driver_register(&proccomm_vreg_driver);
+}
+postcore_initcall(proccomm_vreg_init);
+
+static void __exit proccomm_vreg_exit(void)
+{
+	platform_driver_unregister(&proccomm_vreg_driver);
+}
+module_exit(proccomm_vreg_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("ProcComm regulator driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:" PROCCOMM_REGULATOR_DEV_NAME);
diff --git a/arch/arm/mach-msm/proccomm-regulator.h b/arch/arm/mach-msm/proccomm-regulator.h
new file mode 100644
index 0000000..46d3b13
--- /dev/null
+++ b/arch/arm/mach-msm/proccomm-regulator.h
@@ -0,0 +1,77 @@
+/*
+ * 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
+ * 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 __ARCH_ARM_MACH_MSM_PROCCOMM_REGULATOR_H__
+#define __ARCH_ARM_MACH_MSM_PROCCOMM_REGULATOR_H__
+
+#include <linux/regulator/machine.h>
+
+#define PROCCOMM_REGULATOR_DEV_NAME "proccomm-regulator"
+
+/**
+ * struct proccomm_regulator_info - A description of one proccomm regulator
+ * @init_data:	Initialization data for the regulator.
+ *		Must contain:
+ *		- A list of struct regulator_consumer_supply indicating
+ *		  supply names for the regulator
+ *		- A filled out struct regulation_constraints containing:
+ *		  - The name of the regulator
+ *		  - The minimum and maximum voltages supported
+ *		  - The supported modes (REGULATOR_MODE_NORMAL)
+ *		  - The supported operations, currently limited to:
+ *		    REGULATOR_CHANGE_STATUS
+ *		    REGULATOR_CHANGE_VOLTAGE
+ *		  - The input voltage, if the regulator is powered by another
+ *		  - Properly set always_on, boot_on, and apply_uV flags
+ *		- The name of the supply regulator, if applicable
+ * @id:		The proccomm ID of this regulator.
+ * @rise_time:  The time that the regulator takes to initialize,
+ *		in microseconds. Set to 0 to disable rise-time checking.
+ * @pulldown:   Whether the regulator should be pulled down when off.
+ *		1 to pull down the regulator.
+ *		0 to leave the regulator floating.
+ *		-1 to indicate no preference.
+ */
+struct proccomm_regulator_info {
+	struct regulator_init_data	init_data;
+	int				id;
+	int				rise_time;
+	int				pulldown;
+	int				negative;
+	int				n_voltages;
+};
+
+/**
+ * struct proccomm_regulator_platform_data - proccomm driver platform data.
+ *
+ * Contains a description of a set of proccomm-controlled regulators.
+ * Pass this in the platform_data field when instantiating the driver.
+ *
+ * @regs:	An array of struct proccomm_regulator_info describing
+ *		the regulators to register.
+ * @nregs:	The number of regulators to register.
+ */
+struct proccomm_regulator_platform_data {
+	struct proccomm_regulator_info	*regs;
+	size_t				nregs;
+};
+
+#if defined(CONFIG_MSM_VREG_SWITCH_INVERTED)
+#define VREG_SWITCH_ENABLE 0
+#define VREG_SWITCH_DISABLE 1
+#else
+#define VREG_SWITCH_ENABLE 1
+#define VREG_SWITCH_DISABLE 0
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp5/Makefile b/arch/arm/mach-msm/qdsp5/Makefile
new file mode 100644
index 0000000..2ce0031
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/Makefile
@@ -0,0 +1,20 @@
+obj-y += adsp.o adsp_driver.o adsp_info.o adsp_rm.o dsp_debug.o adsp_debug.o
+obj-y += adsp_video_verify_cmd.o
+obj-y += adsp_videoenc_verify_cmd.o
+obj-y += adsp_jpeg_verify_cmd.o adsp_jpeg_patch_event.o
+obj-y += adsp_vfe_verify_cmd.o adsp_vfe_patch_event.o
+obj-y += adsp_lpm_verify_cmd.o
+ifdef CONFIG_MSM7X27A_AUDIO
+obj-y += audio_pcm_in.o
+obj-$(CONFIG_DEBUG_FS) += audio_voice_lb.o
+else
+obj-y += audio_in.o snd_pcm_client.o
+endif
+obj-$(CONFIG_MSM7X27A_AUDIO) += audio_aac_in.o audio_evrc_in.o audio_qcelp_in.o
+obj-y += audio_out.o audio_mp3.o audmgr.o audpp.o audrec.o audpreproc.o
+obj-y += audio_evrc.o audio_qcelp.o audio_amrnb.o audio_aac.o audio_amrnb_in.o
+obj-y += audio_wma.o audio_voicememo.o audio_pcm.o audio_amrwb.o audio_wmapro.o
+obj-y += snd.o snd_adie.o
+obj-$(CONFIG_ARCH_MSM7X27A) += audio_fm.o
+obj-$(CONFIG_ARCH_MSM7X27A) += audio_mvs.o
+obj-$(CONFIG_ARCH_MSM7X27A) += audio_lpa.o
diff --git a/arch/arm/mach-msm/qdsp5/adsp.c b/arch/arm/mach-msm/qdsp5/adsp.c
new file mode 100644
index 0000000..6f5ccbf
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/adsp.c
@@ -0,0 +1,1457 @@
+/* arch/arm/mach-msm/qdsp5/adsp.c
+ *
+ * Register/Interrupt access for userspace aDSP library.
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+ * Author: Iliyan Malchev <ibm@android.com>
+ *
+ * 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.
+ *
+ */
+
+/* TODO:
+ * - move shareable rpc code outside of adsp.c
+ * - general solution for virt->phys patchup
+ * - queue IDs should be relative to modules
+ * - disallow access to non-associated queues
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/wakelock.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <mach/debug_mm.h>
+#include <linux/debugfs.h>
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *dentry_adsp;
+static struct dentry *dentry_wdata;
+static struct dentry *dentry_rdata;
+static int wdump, rdump;
+#endif /* CONFIG_DEBUG_FS */
+static struct wake_lock adsp_wake_lock;
+static inline void prevent_suspend(void)
+{
+	wake_lock(&adsp_wake_lock);
+}
+static inline void allow_suspend(void)
+{
+	wake_unlock(&adsp_wake_lock);
+}
+
+#include <linux/io.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_adsp.h>
+#include "adsp.h"
+
+static struct adsp_info adsp_info;
+static struct msm_rpc_endpoint *rpc_cb_server_client;
+static struct msm_adsp_module *adsp_modules;
+static int adsp_open_count;
+
+static uint32_t rpc_adsp_rtos_atom_prog;
+static uint32_t rpc_adsp_rtos_atom_vers;
+static uint32_t rpc_adsp_rtos_atom_vers_comp;
+static uint32_t rpc_adsp_rtos_mtoa_prog;
+static uint32_t rpc_adsp_rtos_mtoa_vers;
+static uint32_t rpc_adsp_rtos_mtoa_vers_comp;
+static DEFINE_MUTEX(adsp_open_lock);
+
+static struct workqueue_struct *msm_adsp_probe_work_queue;
+static void adsp_probe_work(struct work_struct *work);
+static DECLARE_WORK(msm_adsp_probe_work, adsp_probe_work);
+
+/* protect interactions with the ADSP command/message queue */
+static spinlock_t adsp_cmd_lock;
+static spinlock_t adsp_write_lock;
+
+static uint32_t current_image = -1;
+
+void adsp_set_image(struct adsp_info *info, uint32_t image)
+{
+	current_image = image;
+}
+
+/*
+ * Checks whether the module_id is available in the
+ * module_entries table.If module_id is available returns `0`.
+ * If module_id is not available returns `-ENXIO`.
+ */
+static int32_t adsp_validate_module(uint32_t module_id)
+{
+	uint32_t	*ptr;
+	uint32_t	module_index;
+	uint32_t	num_mod_entries;
+
+	ptr = adsp_info.init_info_ptr->module_entries;
+	num_mod_entries = adsp_info.init_info_ptr->module_table_size;
+
+	for (module_index = 0; module_index < num_mod_entries; module_index++)
+		if (module_id == ptr[module_index])
+			return 0;
+
+	return -ENXIO;
+}
+
+static int32_t adsp_validate_queue(uint32_t mod_id, unsigned q_idx,
+							uint32_t size)
+{
+	int32_t i;
+	struct adsp_rtos_mp_mtoa_init_info_type	*sptr;
+
+	sptr = adsp_info.init_info_ptr;
+	for (i = 0; i < sptr->mod_to_q_entries; i++)
+		if (mod_id == sptr->mod_to_q_tbl[i].module)
+			if (q_idx == sptr->mod_to_q_tbl[i].q_type) {
+				if (size <= sptr->mod_to_q_tbl[i].q_max_len)
+					return 0;
+				MM_ERR("q_idx: %d is not a valid queue \
+					for module %x\n", q_idx, mod_id);
+				return -EINVAL;
+			}
+	MM_ERR("cmd_buf size is more than allowed size\n");
+	return -EINVAL;
+}
+
+uint32_t adsp_get_module(struct adsp_info *info, uint32_t task)
+{
+	return info->task_to_module[current_image][task];
+}
+
+uint32_t adsp_get_queue_offset(struct adsp_info *info, uint32_t queue_id)
+{
+	return info->queue_offset[current_image][queue_id];
+}
+
+static int rpc_adsp_rtos_app_to_modem(uint32_t cmd, uint32_t module,
+				      struct msm_adsp_module *adsp_module)
+{
+	int rc;
+	struct rpc_adsp_rtos_app_to_modem_args_t rpc_req;
+	struct rpc_reply_hdr rpc_rsp;
+
+	rpc_req.gotit = cpu_to_be32(1);
+	rpc_req.cmd = cpu_to_be32(cmd);
+	rpc_req.proc_id = cpu_to_be32(RPC_ADSP_RTOS_PROC_APPS);
+	rpc_req.module = cpu_to_be32(module);
+	rc = msm_rpc_call_reply(adsp_module->rpc_client,
+					RPC_ADSP_RTOS_APP_TO_MODEM_PROC,
+					&rpc_req, sizeof(rpc_req),
+					&rpc_rsp, sizeof(rpc_rsp),
+					5 * HZ);
+
+	if (rc < 0) {
+		MM_ERR("error receiving RPC reply: %d (%d)\n",
+				rc, -ERESTARTSYS);
+		return rc;
+	}
+
+	if (be32_to_cpu(rpc_rsp.reply_stat) != RPCMSG_REPLYSTAT_ACCEPTED) {
+		MM_ERR("RPC call was denied!\n");
+		return -EPERM;
+	}
+
+	if (be32_to_cpu(rpc_rsp.data.acc_hdr.accept_stat) !=
+	    RPC_ACCEPTSTAT_SUCCESS) {
+		MM_ERR("RPC call was not successful (%d)\n",
+				be32_to_cpu(rpc_rsp.data.acc_hdr.accept_stat));
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int get_module_index(uint32_t id)
+{
+	int mod_idx;
+	for (mod_idx = 0; mod_idx < adsp_info.module_count; mod_idx++)
+		if (adsp_info.module[mod_idx].id == id)
+			return mod_idx;
+
+	return -ENXIO;
+}
+
+static struct msm_adsp_module *find_adsp_module_by_id(
+	struct adsp_info *info, uint32_t id)
+{
+	int mod_idx;
+
+	if (id > info->max_module_id) {
+		return NULL;
+	} else {
+		mod_idx = get_module_index(id);
+		if (mod_idx < 0)
+			return NULL;
+		return info->id_to_module[mod_idx];
+	}
+}
+
+static struct msm_adsp_module *find_adsp_module_by_name(
+	struct adsp_info *info, const char *name)
+{
+	unsigned n;
+	for (n = 0; n < info->module_count; n++)
+		if (!strcmp(name, adsp_modules[n].name))
+			return adsp_modules + n;
+	return NULL;
+}
+
+static int adsp_rpc_init(struct msm_adsp_module *adsp_module)
+{
+	/* remove the original connect once compatible support is complete */
+	adsp_module->rpc_client = msm_rpc_connect(
+		rpc_adsp_rtos_atom_prog,
+		rpc_adsp_rtos_atom_vers,
+		MSM_RPC_UNINTERRUPTIBLE);
+	if (IS_ERR(adsp_module->rpc_client))
+		adsp_module->rpc_client = msm_rpc_connect_compatible(
+		rpc_adsp_rtos_atom_prog,
+		rpc_adsp_rtos_atom_vers_comp,
+		MSM_RPC_UNINTERRUPTIBLE);
+
+	if (IS_ERR(adsp_module->rpc_client)) {
+		int rc = PTR_ERR(adsp_module->rpc_client);
+		adsp_module->rpc_client = 0;
+		MM_ERR("could not open rpc client: %d\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+/*
+ * Send RPC_ADSP_RTOS_CMD_GET_INIT_INFO cmd to ARM9 and get
+ * queue offsets and module entries (init info) as part of the event.
+ */
+static void  msm_get_init_info(void)
+{
+	int rc;
+	struct rpc_adsp_rtos_app_to_modem_args_t rpc_req;
+	struct rpc_reply_hdr rpc_rsp;
+
+	adsp_info.init_info_rpc_client = msm_rpc_connect(
+		rpc_adsp_rtos_atom_prog,
+		rpc_adsp_rtos_atom_vers,
+		MSM_RPC_UNINTERRUPTIBLE);
+	if (IS_ERR(adsp_info.init_info_rpc_client)) {
+		adsp_info.init_info_rpc_client = msm_rpc_connect_compatible(
+		rpc_adsp_rtos_atom_prog,
+		rpc_adsp_rtos_atom_vers_comp,
+		MSM_RPC_UNINTERRUPTIBLE);
+		if (IS_ERR(adsp_info.init_info_rpc_client)) {
+			rc = PTR_ERR(adsp_info.init_info_rpc_client);
+			adsp_info.init_info_rpc_client = 0;
+			MM_ERR("could not open rpc client: %d\n", rc);
+			return;
+		}
+	}
+
+	rpc_req.gotit = cpu_to_be32(1);
+	rpc_req.cmd = cpu_to_be32(RPC_ADSP_RTOS_CMD_GET_INIT_INFO);
+	rpc_req.proc_id = cpu_to_be32(RPC_ADSP_RTOS_PROC_APPS);
+	rpc_req.module = 0;
+
+	rc = msm_rpc_call_reply(adsp_info.init_info_rpc_client,
+					RPC_ADSP_RTOS_APP_TO_MODEM_PROC,
+					&rpc_req, sizeof(rpc_req),
+					&rpc_rsp, sizeof(rpc_rsp),
+					5 * HZ);
+
+	if (rc < 0)
+		MM_ERR("could not send RPC request: %d\n", rc);
+}
+
+int msm_adsp_get(const char *name, struct msm_adsp_module **out,
+		 struct msm_adsp_ops *ops, void *driver_data)
+{
+	struct msm_adsp_module *module;
+	int rc = 0;
+	static uint32_t init_info_cmd_sent;
+
+	mutex_lock(&adsp_info.lock);
+	if (!init_info_cmd_sent) {
+		init_waitqueue_head(&adsp_info.init_info_wait);
+		msm_get_init_info();
+		rc = wait_event_timeout(adsp_info.init_info_wait,
+			adsp_info.init_info_state == ADSP_STATE_INIT_INFO,
+			5 * HZ);
+		if (!rc) {
+			MM_ERR("INIT_INFO failed\n");
+			mutex_unlock(&adsp_info.lock);
+			return -ETIMEDOUT;
+
+		}
+		init_info_cmd_sent++;
+	}
+	mutex_unlock(&adsp_info.lock);
+
+	module = find_adsp_module_by_name(&adsp_info, name);
+	if (!module)
+		return -ENODEV;
+
+	mutex_lock(&module->lock);
+	MM_INFO("opening module %s\n", module->name);
+
+	if (module->ops) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	rc = adsp_rpc_init(module);
+	if (rc)
+		goto done;
+
+	module->ops = ops;
+	module->driver_data = driver_data;
+	*out = module;
+	rc = rpc_adsp_rtos_app_to_modem(RPC_ADSP_RTOS_CMD_REGISTER_APP,
+					module->id, module);
+	if (rc) {
+		module->ops = NULL;
+		module->driver_data = NULL;
+		*out = NULL;
+		MM_ERR("REGISTER_APP failed\n");
+		goto done;
+	}
+
+	MM_DBG("module %s has been registered\n", module->name);
+
+done:
+	mutex_unlock(&module->lock);
+	return rc;
+}
+EXPORT_SYMBOL(msm_adsp_get);
+
+static int msm_adsp_disable_locked(struct msm_adsp_module *module);
+
+void msm_adsp_put(struct msm_adsp_module *module)
+{
+	unsigned long flags;
+
+	mutex_lock(&module->lock);
+	if (module->ops) {
+		MM_INFO("closing module %s\n", module->name);
+
+		/* lock to ensure a dsp event cannot be delivered
+		 * during or after removal of the ops and driver_data
+		 */
+		spin_lock_irqsave(&adsp_cmd_lock, flags);
+		module->ops = NULL;
+		module->driver_data = NULL;
+		spin_unlock_irqrestore(&adsp_cmd_lock, flags);
+
+		if (module->state != ADSP_STATE_DISABLED) {
+			MM_INFO("disabling module %s\n", module->name);
+			msm_adsp_disable_locked(module);
+		}
+
+		msm_rpc_close(module->rpc_client);
+		module->rpc_client = 0;
+	} else {
+		MM_INFO("module %s is already closed\n", module->name);
+	}
+	mutex_unlock(&module->lock);
+}
+EXPORT_SYMBOL(msm_adsp_put);
+
+/* this should be common code with rpc_servers.c */
+static int rpc_send_accepted_void_reply(struct msm_rpc_endpoint *client,
+					uint32_t xid, uint32_t accept_status)
+{
+	int rc = 0;
+	uint8_t reply_buf[sizeof(struct rpc_reply_hdr)];
+	struct rpc_reply_hdr *reply = (struct rpc_reply_hdr *)reply_buf;
+
+	reply->xid = cpu_to_be32(xid);
+	reply->type = cpu_to_be32(1); /* reply */
+	reply->reply_stat = cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED);
+
+	reply->data.acc_hdr.accept_stat = cpu_to_be32(accept_status);
+	reply->data.acc_hdr.verf_flavor = 0;
+	reply->data.acc_hdr.verf_length = 0;
+
+	rc = msm_rpc_write(rpc_cb_server_client, reply_buf, sizeof(reply_buf));
+	if (rc < 0)
+		MM_ERR("could not write RPC response: %d\n", rc);
+	return rc;
+}
+
+int __msm_adsp_write(struct msm_adsp_module *module, unsigned dsp_queue_addr,
+		   void *cmd_buf, size_t cmd_size)
+{
+	uint32_t ctrl_word;
+	uint32_t dsp_q_addr;
+	uint32_t dsp_addr;
+	uint32_t cmd_id = 0;
+	int cnt = 0;
+	int ret_status = 0;
+	unsigned long flags;
+	struct adsp_info *info;
+
+	if (!module || !cmd_buf) {
+		MM_ERR("Called with NULL parameters\n");
+		return -EINVAL;
+	}
+	info = module->info;
+	spin_lock_irqsave(&adsp_write_lock, flags);
+
+	if (module->state != ADSP_STATE_ENABLED) {
+		spin_unlock_irqrestore(&adsp_write_lock, flags);
+		MM_ERR("module %s not enabled before write\n", module->name);
+		return -ENODEV;
+	}
+	if (adsp_validate_module(module->id)) {
+		spin_unlock_irqrestore(&adsp_write_lock, flags);
+		MM_ERR("module id validation failed %s  %d\n",
+				module->name, module->id);
+		return -ENXIO;
+	}
+	if (dsp_queue_addr >= QDSP_MAX_NUM_QUEUES) {
+		spin_unlock_irqrestore(&adsp_write_lock, flags);
+		MM_ERR("Invalid Queue Index: %d\n", dsp_queue_addr);
+		return -ENXIO;
+	}
+	if (adsp_validate_queue(module->id, dsp_queue_addr, cmd_size)) {
+		spin_unlock_irqrestore(&adsp_write_lock, flags);
+		return -EINVAL;
+	}
+	dsp_q_addr = adsp_get_queue_offset(info, dsp_queue_addr);
+	dsp_q_addr &= ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M;
+
+	/* Poll until the ADSP is ready to accept a command.
+	 * Wait for 100us, return error if it's not responding.
+	 * If this returns an error, we need to disable ALL modules and
+	 * then retry.
+	 */
+	while (((ctrl_word = readl(info->write_ctrl)) &
+		ADSP_RTOS_WRITE_CTRL_WORD_READY_M) !=
+		ADSP_RTOS_WRITE_CTRL_WORD_READY_V) {
+		if (cnt > 50) {
+			MM_ERR("timeout waiting for DSP write ready\n");
+			ret_status = -EIO;
+			goto fail;
+		}
+		MM_DBG("waiting for DSP write ready\n");
+		udelay(2);
+		cnt++;
+	}
+
+	/* Set the mutex bits */
+	ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_M);
+	ctrl_word |=  ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_NAVAIL_V;
+
+	/* Clear the command bits */
+	ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_CMD_M);
+
+	/* Set the queue address bits */
+	ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M);
+	ctrl_word |= dsp_q_addr;
+
+	writel(ctrl_word, info->write_ctrl);
+
+	/* Generate an interrupt to the DSP.  This notifies the DSP that
+	 * we are about to send a command on this particular queue.  The
+	 * DSP will in response change its state.
+	 */
+	writel(1, info->send_irq);
+
+	/* Poll until the adsp responds to the interrupt; this does not
+	 * generate an interrupt from the adsp.  This should happen within
+	 * 5ms.
+	 */
+	cnt = 0;
+	while ((readl(info->write_ctrl) &
+		ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_M) ==
+		ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_NAVAIL_V) {
+		if (cnt > 2500) {
+			MM_ERR("timeout waiting for adsp ack\n");
+			ret_status = -EIO;
+			goto fail;
+		}
+		udelay(2);
+		cnt++;
+	}
+
+	/* Read the ctrl word */
+	ctrl_word = readl(info->write_ctrl);
+
+	if ((ctrl_word & ADSP_RTOS_WRITE_CTRL_WORD_STATUS_M) !=
+	    ADSP_RTOS_WRITE_CTRL_WORD_NO_ERR_V) {
+		ret_status = -EAGAIN;
+		goto fail;
+	} else {
+		/* No error */
+		/* Get the DSP buffer address */
+		dsp_addr = (ctrl_word & ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M) +
+			   (uint32_t)MSM_AD5_BASE;
+
+		if (dsp_addr < (uint32_t)(MSM_AD5_BASE + QDSP_RAMC_OFFSET)) {
+			uint16_t *buf_ptr = (uint16_t *) cmd_buf;
+			uint16_t *dsp_addr16 = (uint16_t *)dsp_addr;
+			cmd_size /= sizeof(uint16_t);
+
+			/* Save the command ID */
+			cmd_id = (uint32_t) buf_ptr[0];
+
+			/* Copy the command to DSP memory */
+			cmd_size++;
+			while (--cmd_size)
+				*dsp_addr16++ = *buf_ptr++;
+		} else {
+			uint32_t *buf_ptr = (uint32_t *) cmd_buf;
+			uint32_t *dsp_addr32 = (uint32_t *)dsp_addr;
+			cmd_size /= sizeof(uint32_t);
+
+			/* Save the command ID */
+			cmd_id = buf_ptr[0];
+
+			cmd_size++;
+			while (--cmd_size)
+				*dsp_addr32++ = *buf_ptr++;
+		}
+
+		/* Set the mutex bits */
+		ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_M);
+		ctrl_word |=  ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_NAVAIL_V;
+
+		/* Set the command bits to write done */
+		ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_CMD_M);
+		ctrl_word |= ADSP_RTOS_WRITE_CTRL_WORD_CMD_WRITE_DONE_V;
+
+		/* Set the queue address bits */
+		ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M);
+		ctrl_word |= dsp_q_addr;
+
+		writel(ctrl_word, info->write_ctrl);
+
+		/* Generate an interrupt to the DSP.  It does not respond with
+		 * an interrupt, and we do not need to wait for it to
+		 * acknowledge, because it will hold the mutex lock until it's
+		 * ready to receive more commands again.
+		 */
+		writel(1, info->send_irq);
+
+		module->num_commands++;
+	} /* Ctrl word status bits were 00, no error in the ctrl word */
+
+fail:
+	spin_unlock_irqrestore(&adsp_write_lock, flags);
+	return ret_status;
+}
+EXPORT_SYMBOL(msm_adsp_write);
+
+int msm_adsp_write(struct msm_adsp_module *module, unsigned dsp_queue_addr,
+			void *cmd_buf, size_t cmd_size)
+{
+	int rc, retries = 0;
+#ifdef CONFIG_DEBUG_FS
+	uint16_t *ptr;
+	int ii;
+
+	if (wdump > 0) {
+		ptr = cmd_buf;
+		pr_info("A->D:%x\n", module->id);
+		pr_info("adsp: %x %d\n", dsp_queue_addr, cmd_size);
+		for (ii = 0; ii < cmd_size/2; ii++)
+			pr_info("%x ", ptr[ii]);
+		pr_info("\n");
+	}
+#endif /* CONFIG_DEBUG_FS */
+	do {
+		rc = __msm_adsp_write(module, dsp_queue_addr, cmd_buf,
+								cmd_size);
+		if (rc == -EAGAIN)
+			udelay(10);
+	} while (rc == -EAGAIN && retries++ < 300);
+	if (retries > 50)
+		MM_ERR("adsp: %s command took %d attempts: rc %d\n",
+			module->name, retries, rc);
+	return rc;
+}
+
+static void *event_addr;
+static void read_event(void *buf, size_t len)
+{
+	uint32_t dptr[3];
+	struct rpc_adsp_rtos_modem_to_app_args_t *sptr;
+	struct adsp_rtos_mp_mtoa_type	*pkt_ptr;
+
+	sptr = event_addr;
+	pkt_ptr = &sptr->mtoa_pkt.adsp_rtos_mp_mtoa_data.mp_mtoa_packet;
+
+	dptr[0] = be32_to_cpu(sptr->mtoa_pkt.mp_mtoa_header.event);
+	dptr[1] = be32_to_cpu(pkt_ptr->module);
+	dptr[2] = be32_to_cpu(pkt_ptr->image);
+
+	if (len > EVENT_LEN)
+		len = EVENT_LEN;
+
+	memcpy(buf, dptr, len);
+}
+
+static void handle_adsp_rtos_mtoa_app(struct rpc_request_hdr *req)
+{
+	struct rpc_adsp_rtos_modem_to_app_args_t *args =
+		(struct rpc_adsp_rtos_modem_to_app_args_t *)req;
+	uint32_t event;
+	uint32_t proc_id;
+	uint32_t module_id;
+	uint32_t image;
+	struct msm_adsp_module *module;
+	struct adsp_rtos_mp_mtoa_type	*pkt_ptr;
+	struct queue_to_offset_type	*qptr;
+	struct queue_to_offset_type	*qtbl;
+	struct mod_to_queue_offsets	*mqptr;
+	struct mod_to_queue_offsets	*mqtbl;
+	uint32_t	*mptr;
+	uint32_t	*mtbl;
+	uint32_t	q_idx;
+	uint32_t	num_entries;
+	uint32_t	entries_per_image;
+	struct adsp_rtos_mp_mtoa_init_info_type *iptr;
+	struct adsp_rtos_mp_mtoa_init_info_type	*sptr;
+	int32_t		i_no, e_idx;
+
+	event = be32_to_cpu(args->mtoa_pkt.mp_mtoa_header.event);
+	proc_id = be32_to_cpu(args->mtoa_pkt.mp_mtoa_header.proc_id);
+
+	if (event == RPC_ADSP_RTOS_INIT_INFO) {
+		MM_INFO("INIT_INFO Event\n");
+		sptr = &args->mtoa_pkt.adsp_rtos_mp_mtoa_data.mp_mtoa_init_packet;
+
+		iptr = adsp_info.init_info_ptr;
+		iptr->image_count = be32_to_cpu(sptr->image_count);
+		if (iptr->image_count > IMG_MAX)
+			iptr->image_count = IMG_MAX;
+		iptr->num_queue_offsets = be32_to_cpu(sptr->num_queue_offsets);
+		num_entries = iptr->num_queue_offsets;
+		if (num_entries > ENTRIES_MAX) {
+			num_entries = ENTRIES_MAX;
+			iptr->num_queue_offsets = ENTRIES_MAX;
+		}
+		qptr = &sptr->queue_offsets_tbl[0][0];
+		for (i_no = 0; i_no < iptr->image_count; i_no++) {
+			qtbl = &iptr->queue_offsets_tbl[i_no][0];
+			for (e_idx = 0; e_idx < num_entries; e_idx++) {
+				qtbl[e_idx].offset = be32_to_cpu(qptr->offset);
+				qtbl[e_idx].queue = be32_to_cpu(qptr->queue);
+				q_idx = be32_to_cpu(qptr->queue);
+				iptr->queue_offsets[i_no][q_idx] = qtbl[e_idx].offset;
+				qptr++;
+			}
+		}
+
+		num_entries = be32_to_cpu(sptr->num_task_module_entries);
+		if (num_entries > ENTRIES_MAX)
+			num_entries = ENTRIES_MAX;
+		iptr->num_task_module_entries = num_entries;
+		entries_per_image = num_entries / iptr->image_count;
+		mptr = &sptr->task_to_module_tbl[0][0];
+		for (i_no = 0; i_no < iptr->image_count; i_no++) {
+			mtbl = &iptr->task_to_module_tbl[i_no][0];
+			for (e_idx = 0; e_idx < entries_per_image; e_idx++) {
+				mtbl[e_idx] = be32_to_cpu(*mptr);
+				mptr++;
+			}
+		}
+
+		iptr->module_table_size = be32_to_cpu(sptr->module_table_size);
+#if CONFIG_ADSP_RPC_VER > 0x30001
+		if (iptr->module_table_size > MODULES_MAX)
+			iptr->module_table_size = MODULES_MAX;
+#else
+		if (iptr->module_table_size > ENTRIES_MAX)
+			iptr->module_table_size = ENTRIES_MAX;
+#endif
+		mptr = &sptr->module_entries[0];
+		for (i_no = 0; i_no < iptr->module_table_size; i_no++)
+			iptr->module_entries[i_no] = be32_to_cpu(mptr[i_no]);
+
+		mqptr = &sptr->mod_to_q_tbl[0];
+		mqtbl = &iptr->mod_to_q_tbl[0];
+		iptr->mod_to_q_entries = be32_to_cpu(sptr->mod_to_q_entries);
+		if (iptr->mod_to_q_entries > ENTRIES_MAX)
+			iptr->mod_to_q_entries = ENTRIES_MAX;
+		for (e_idx = 0; e_idx < iptr->mod_to_q_entries; e_idx++) {
+			mqtbl[e_idx].module = be32_to_cpu(mqptr->module);
+			mqtbl[e_idx].q_type = be32_to_cpu(mqptr->q_type);
+			mqtbl[e_idx].q_max_len = be32_to_cpu(mqptr->q_max_len);
+			mqptr++;
+		}
+
+		adsp_info.init_info_state = ADSP_STATE_INIT_INFO;
+		rpc_send_accepted_void_reply(rpc_cb_server_client, req->xid,
+						RPC_ACCEPTSTAT_SUCCESS);
+		wake_up(&adsp_info.init_info_wait);
+
+		return;
+	}
+
+	pkt_ptr = &args->mtoa_pkt.adsp_rtos_mp_mtoa_data.mp_mtoa_packet;
+	module_id = be32_to_cpu(pkt_ptr->module);
+	image     = be32_to_cpu(pkt_ptr->image);
+
+	MM_DBG("rpc event=%d, proc_id=%d, module=%d, image=%d\n",
+		event, proc_id, module_id, image);
+
+	module = find_adsp_module_by_id(&adsp_info, module_id);
+	if (!module) {
+		MM_ERR("module %d is not supported!\n", module_id);
+		rpc_send_accepted_void_reply(rpc_cb_server_client, req->xid,
+				RPC_ACCEPTSTAT_GARBAGE_ARGS);
+		return;
+	}
+
+	mutex_lock(&module->lock);
+	switch (event) {
+	case RPC_ADSP_RTOS_MOD_READY:
+		MM_INFO("module %s: READY\n", module->name);
+		module->state = ADSP_STATE_ENABLED;
+		wake_up(&module->state_wait);
+		adsp_set_image(module->info, image);
+		break;
+	case RPC_ADSP_RTOS_MOD_DISABLE:
+		MM_INFO("module %s: DISABLED\n", module->name);
+		module->state = ADSP_STATE_DISABLED;
+		wake_up(&module->state_wait);
+		break;
+	case RPC_ADSP_RTOS_SERVICE_RESET:
+		MM_INFO("module %s: SERVICE_RESET\n", module->name);
+		module->state = ADSP_STATE_DISABLED;
+		wake_up(&module->state_wait);
+		break;
+	case RPC_ADSP_RTOS_CMD_SUCCESS:
+		MM_INFO("module %s: CMD_SUCCESS\n", module->name);
+		break;
+	case RPC_ADSP_RTOS_CMD_FAIL:
+		MM_INFO("module %s: CMD_FAIL\n", module->name);
+		break;
+	case RPC_ADSP_RTOS_DISABLE_FAIL:
+		MM_INFO("module %s: DISABLE_FAIL\n", module->name);
+		break;
+	default:
+		MM_ERR("unknown event %d\n", event);
+		rpc_send_accepted_void_reply(rpc_cb_server_client, req->xid,
+					     RPC_ACCEPTSTAT_GARBAGE_ARGS);
+		mutex_unlock(&module->lock);
+		return;
+	}
+	rpc_send_accepted_void_reply(rpc_cb_server_client, req->xid,
+				     RPC_ACCEPTSTAT_SUCCESS);
+#ifdef CONFIG_MSM_ADSP_REPORT_EVENTS
+	event_addr = (uint32_t *)req;
+	module->ops->event(module->driver_data,
+				EVENT_MSG_ID,
+				EVENT_LEN,
+				read_event);
+#endif
+	mutex_unlock(&module->lock);
+}
+
+static int handle_adsp_rtos_mtoa(struct rpc_request_hdr *req)
+{
+	switch (req->procedure) {
+	case RPC_ADSP_RTOS_MTOA_NULL_PROC:
+		rpc_send_accepted_void_reply(rpc_cb_server_client,
+					     req->xid,
+					     RPC_ACCEPTSTAT_SUCCESS);
+		break;
+#if CONFIG_ADSP_RPC_VER > 0x30001
+	case RPC_ADSP_RTOS_MTOA_INIT_INFO_PROC:
+	case RPC_ADSP_RTOS_MTOA_EVENT_INFO_PROC:
+#else
+	case RPC_ADSP_RTOS_MODEM_TO_APP_PROC:
+#endif
+		handle_adsp_rtos_mtoa_app(req);
+		break;
+	default:
+		MM_ERR("unknowned proc %d\n", req->procedure);
+		rpc_send_accepted_void_reply(
+			rpc_cb_server_client, req->xid,
+			RPC_ACCEPTSTAT_PROC_UNAVAIL);
+		break;
+	}
+	return 0;
+}
+
+/* this should be common code with rpc_servers.c */
+static int adsp_rpc_thread(void *data)
+{
+	void *buffer;
+	struct rpc_request_hdr *req;
+	int rc, exit = 0;
+
+	do {
+		rc = msm_rpc_read(rpc_cb_server_client, &buffer, -1, -1);
+		if (rc < 0) {
+			MM_ERR("could not read rpc: %d\n", rc);
+			break;
+		}
+		req = (struct rpc_request_hdr *)buffer;
+
+		req->type = be32_to_cpu(req->type);
+		req->xid = be32_to_cpu(req->xid);
+		req->rpc_vers = be32_to_cpu(req->rpc_vers);
+		req->prog = be32_to_cpu(req->prog);
+		req->vers = be32_to_cpu(req->vers);
+		req->procedure = be32_to_cpu(req->procedure);
+
+		if (req->type != 0)
+			goto bad_rpc;
+		if (req->rpc_vers != 2)
+			goto bad_rpc;
+		if (req->prog != rpc_adsp_rtos_mtoa_prog)
+			goto bad_rpc;
+		if (!msm_rpc_is_compatible_version(rpc_adsp_rtos_mtoa_vers,
+							req->vers))
+			goto bad_rpc;
+
+		handle_adsp_rtos_mtoa(req);
+		kfree(buffer);
+		continue;
+
+bad_rpc:
+		MM_ERR("bogus rpc from modem\n");
+		kfree(buffer);
+	} while (!exit);
+	do_exit(0);
+}
+
+static size_t read_event_size;
+static void *read_event_addr;
+
+static void read_event_16(void *buf, size_t len)
+{
+	uint16_t *dst = buf;
+	uint16_t *src = read_event_addr;
+	len /= 2;
+	if (len > read_event_size)
+		len = read_event_size;
+	while (len--)
+		*dst++ = *src++;
+}
+
+static void read_event_32(void *buf, size_t len)
+{
+	uint32_t *dst = buf;
+	uint32_t *src = read_event_addr;
+	len /= 2;
+	if (len > read_event_size)
+		len = read_event_size;
+	while (len--)
+		*dst++ = *src++;
+}
+
+static int adsp_rtos_read_ctrl_word_cmd_tast_to_h_v(
+	struct adsp_info *info, void *dsp_addr)
+{
+	struct msm_adsp_module *module;
+	unsigned rtos_task_id;
+	unsigned msg_id;
+	unsigned msg_length;
+#ifdef CONFIG_DEBUG_FS
+	uint16_t *ptr;
+	int ii;
+#endif /* CONFIG_DEBUG_FS */
+	void (*func)(void *, size_t);
+
+	if (dsp_addr >= (void *)(MSM_AD5_BASE + QDSP_RAMC_OFFSET)) {
+		uint32_t *dsp_addr32 = dsp_addr;
+		uint32_t tmp = *dsp_addr32++;
+		rtos_task_id = (tmp & ADSP_RTOS_READ_CTRL_WORD_TASK_ID_M) >> 8;
+		msg_id = (tmp & ADSP_RTOS_READ_CTRL_WORD_MSG_ID_M);
+		read_event_size = tmp >> 16;
+		read_event_addr = dsp_addr32;
+		msg_length = read_event_size * sizeof(uint32_t);
+		func = read_event_32;
+	} else {
+		uint16_t *dsp_addr16 = dsp_addr;
+		uint16_t tmp = *dsp_addr16++;
+		rtos_task_id = (tmp & ADSP_RTOS_READ_CTRL_WORD_TASK_ID_M) >> 8;
+		msg_id = tmp & ADSP_RTOS_READ_CTRL_WORD_MSG_ID_M;
+		read_event_size = *dsp_addr16++;
+		read_event_addr = dsp_addr16;
+		msg_length = read_event_size * sizeof(uint16_t);
+		func = read_event_16;
+	}
+
+	if (rtos_task_id > info->max_task_id) {
+		MM_ERR("bogus task id %d\n", rtos_task_id);
+		return 0;
+	}
+	module = find_adsp_module_by_id(info,
+					adsp_get_module(info, rtos_task_id));
+
+	if (!module) {
+		MM_ERR("no module for task id %d\n", rtos_task_id);
+		return 0;
+	}
+
+	module->num_events++;
+
+	if (!module->ops) {
+		MM_ERR("module %s is not open\n", module->name);
+		return 0;
+	}
+#ifdef CONFIG_DEBUG_FS
+	if (rdump > 0) {
+		ptr = read_event_addr;
+		pr_info("D->A\n");
+		pr_info("m_id = %x id = %x\n", module->id, msg_id);
+		for (ii = 0; ii < msg_length/2; ii++)
+			pr_info("%x ", ptr[ii]);
+		pr_info("\n");
+	}
+#endif /* CONFIG_DEBUG_FS */
+
+	module->ops->event(module->driver_data, msg_id, msg_length, func);
+	return 0;
+}
+
+static int adsp_get_event(struct adsp_info *info)
+{
+	uint32_t ctrl_word;
+	uint32_t ready;
+	void *dsp_addr;
+	uint32_t cmd_type;
+	int cnt;
+	unsigned long flags;
+	int rc = 0;
+
+	spin_lock_irqsave(&adsp_cmd_lock, flags);
+
+	/* Whenever the DSP has a message, it updates this control word
+	 * and generates an interrupt.  When we receive the interrupt, we
+	 * read this register to find out what ADSP task the command is
+	 * comming from.
+	 *
+	 * The ADSP should *always* be ready on the first call, but the
+	 * irq handler calls us in a loop (to handle back-to-back command
+	 * processing), so we give the DSP some time to return to the
+	 * ready state.  The DSP will not issue another IRQ for events
+	 * pending between the first IRQ and the event queue being drained,
+	 * unfortunately.
+	 */
+
+	for (cnt = 0; cnt < 50; cnt++) {
+		ctrl_word = readl(info->read_ctrl);
+
+		if ((ctrl_word & ADSP_RTOS_READ_CTRL_WORD_FLAG_M) ==
+		    ADSP_RTOS_READ_CTRL_WORD_FLAG_UP_CONT_V)
+			goto ready;
+
+		udelay(2);
+	}
+	MM_ERR("not ready after 100uS\n");
+	rc = -EBUSY;
+	goto done;
+
+ready:
+	/* Here we check to see if there are pending messages. If there are
+	 * none, we siply return -EAGAIN to indicate that there are no more
+	 * messages pending.
+	 */
+	ready = ctrl_word & ADSP_RTOS_READ_CTRL_WORD_READY_M;
+	if ((ready != ADSP_RTOS_READ_CTRL_WORD_READY_V) &&
+	    (ready != ADSP_RTOS_READ_CTRL_WORD_CONT_V)) {
+		rc = -EAGAIN;
+		goto done;
+	}
+
+	/* DSP says that there are messages waiting for the host to read */
+
+	/* Get the Command Type */
+	cmd_type = ctrl_word & ADSP_RTOS_READ_CTRL_WORD_CMD_TYPE_M;
+
+	/* Get the DSP buffer address */
+	dsp_addr = (void *)((ctrl_word &
+			     ADSP_RTOS_READ_CTRL_WORD_DSP_ADDR_M) +
+			    (uint32_t)MSM_AD5_BASE);
+
+	/* We can only handle Task-to-Host messages */
+	if (cmd_type != ADSP_RTOS_READ_CTRL_WORD_CMD_TASK_TO_H_V) {
+		MM_ERR("unknown dsp cmd_type %d\n", cmd_type);
+		rc = -EIO;
+		goto done;
+	}
+
+	adsp_rtos_read_ctrl_word_cmd_tast_to_h_v(info, dsp_addr);
+
+	ctrl_word = readl(info->read_ctrl);
+	ctrl_word &= ~ADSP_RTOS_READ_CTRL_WORD_READY_M;
+
+	/* Write ctrl word to the DSP */
+	writel(ctrl_word, info->read_ctrl);
+
+	/* Generate an interrupt to the DSP */
+	writel(1, info->send_irq);
+
+done:
+	spin_unlock_irqrestore(&adsp_cmd_lock, flags);
+	return rc;
+}
+
+static irqreturn_t adsp_irq_handler(int irq, void *data)
+{
+	struct adsp_info *info = &adsp_info;
+	int cnt = 0;
+	for (cnt = 0; cnt < 15; cnt++)
+		if (adsp_get_event(info) < 0)
+			break;
+	if (cnt > info->event_backlog_max)
+		info->event_backlog_max = cnt;
+	info->events_received += cnt;
+	if (cnt == 15)
+		MM_ERR("too many (%d) events for single irq!\n", cnt);
+	return IRQ_HANDLED;
+}
+
+int adsp_set_clkrate(struct msm_adsp_module *module, unsigned long clk_rate)
+{
+	if (!module)
+		return -EINVAL;
+
+	if (module->clk && clk_rate)
+		return clk_set_rate(module->clk, clk_rate);
+
+	return -EINVAL;
+}
+
+int msm_adsp_generate_event(void *data,
+			struct msm_adsp_module *mod,
+			unsigned event_id,
+			unsigned event_length,
+			unsigned event_size,
+			void *msg)
+{
+	unsigned long flags;
+	void (*func)(void *, size_t);
+
+	if (!mod)
+		return -EINVAL;
+
+	if (event_size == sizeof(uint32_t))
+		func = read_event_32;
+	else if (event_size == sizeof(uint16_t))
+		func = read_event_16;
+	else
+		return -EINVAL;
+
+	spin_lock_irqsave(&adsp_cmd_lock, flags);
+	read_event_addr = msg;
+	read_event_size = event_length;
+	mod->ops->event(data, event_id, event_length, func);
+	spin_unlock_irqrestore(&adsp_cmd_lock, flags);
+	return 0;
+}
+
+int msm_adsp_enable(struct msm_adsp_module *module)
+{
+	int rc = 0;
+
+	if (!module)
+		return -EINVAL;
+
+	MM_INFO("enable '%s'state[%d] id[%d]\n",
+				module->name, module->state, module->id);
+
+	mutex_lock(&module->lock);
+	switch (module->state) {
+	case ADSP_STATE_DISABLED:
+		rc = rpc_adsp_rtos_app_to_modem(RPC_ADSP_RTOS_CMD_ENABLE,
+						module->id, module);
+		if (rc)
+			break;
+		module->state = ADSP_STATE_ENABLING;
+		mutex_unlock(&module->lock);
+		rc = wait_event_timeout(module->state_wait,
+					module->state != ADSP_STATE_ENABLING,
+					1 * HZ);
+		mutex_lock(&module->lock);
+		if (module->state == ADSP_STATE_ENABLED) {
+			rc = 0;
+		} else {
+			MM_ERR("module '%s' enable timed out\n", module->name);
+			rc = -ETIMEDOUT;
+		}
+		if (module->open_count++ == 0 && module->clk)
+			clk_prepare_enable(module->clk);
+
+		mutex_lock(&adsp_open_lock);
+		if (adsp_open_count++ == 0) {
+			enable_irq(adsp_info.int_adsp);
+			prevent_suspend();
+		}
+		mutex_unlock(&adsp_open_lock);
+		break;
+	case ADSP_STATE_ENABLING:
+		MM_DBG("module '%s' enable in progress\n", module->name);
+		break;
+	case ADSP_STATE_ENABLED:
+		MM_DBG("module '%s' already enabled\n", module->name);
+		break;
+	case ADSP_STATE_DISABLING:
+		MM_ERR("module '%s' disable in progress\n", module->name);
+		rc = -EBUSY;
+		break;
+	}
+	mutex_unlock(&module->lock);
+	return rc;
+}
+EXPORT_SYMBOL(msm_adsp_enable);
+
+int msm_adsp_disable_event_rsp(struct msm_adsp_module *module)
+{
+	int rc = 0;
+
+	if (!module)
+		return -EINVAL;
+
+	mutex_lock(&module->lock);
+
+	rc = rpc_adsp_rtos_app_to_modem(RPC_ADSP_RTOS_CMD_DISABLE_EVENT_RSP,
+							module->id, module);
+	mutex_unlock(&module->lock);
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_adsp_disable_event_rsp);
+
+static int msm_adsp_disable_locked(struct msm_adsp_module *module)
+{
+	int rc = 0;
+
+	if (!module)
+		return -EINVAL;
+
+	switch (module->state) {
+	case ADSP_STATE_DISABLED:
+		MM_DBG("module '%s' already disabled\n", module->name);
+		break;
+	case ADSP_STATE_ENABLING:
+	case ADSP_STATE_ENABLED:
+		rc = rpc_adsp_rtos_app_to_modem(RPC_ADSP_RTOS_CMD_DISABLE,
+						module->id, module);
+		module->state = ADSP_STATE_DISABLED;
+		if (--module->open_count == 0 && module->clk)
+			clk_disable_unprepare(module->clk);
+		mutex_lock(&adsp_open_lock);
+		if (--adsp_open_count == 0) {
+			disable_irq(adsp_info.int_adsp);
+			allow_suspend();
+			MM_DBG("disable interrupt\n");
+		}
+		mutex_unlock(&adsp_open_lock);
+	}
+	return rc;
+}
+
+int msm_adsp_disable(struct msm_adsp_module *module)
+{
+	int rc;
+
+	if (!module)
+		return -EINVAL;
+
+	MM_INFO("disable '%s'\n", module->name);
+	mutex_lock(&module->lock);
+	rc = msm_adsp_disable_locked(module);
+	mutex_unlock(&module->lock);
+	return rc;
+}
+EXPORT_SYMBOL(msm_adsp_disable);
+
+static int msm_adsp_probe(struct platform_device *pdev)
+{
+	unsigned count;
+	int rc, i;
+
+	adsp_info.int_adsp = platform_get_irq(pdev, 0);
+	if (adsp_info.int_adsp < 0) {
+		MM_ERR("no irq resource?\n");
+		return -ENODEV;
+	}
+
+	wake_lock_init(&adsp_wake_lock, WAKE_LOCK_SUSPEND, "adsp");
+	adsp_info.init_info_ptr = kzalloc(
+		(sizeof(struct adsp_rtos_mp_mtoa_init_info_type)), GFP_KERNEL);
+	if (!adsp_info.init_info_ptr)
+		return -ENOMEM;
+
+	rc = adsp_init_info(&adsp_info);
+	if (rc)
+		return rc;
+	adsp_info.send_irq += (uint32_t) MSM_AD5_BASE;
+	adsp_info.read_ctrl += (uint32_t) MSM_AD5_BASE;
+	adsp_info.write_ctrl += (uint32_t) MSM_AD5_BASE;
+	count = adsp_info.module_count;
+
+	adsp_modules = kzalloc(
+		(sizeof(struct msm_adsp_module) + sizeof(void *)) *
+		count, GFP_KERNEL);
+	if (!adsp_modules)
+		return -ENOMEM;
+
+	adsp_info.id_to_module = (void *) (adsp_modules + count);
+
+	spin_lock_init(&adsp_cmd_lock);
+	spin_lock_init(&adsp_write_lock);
+	mutex_init(&adsp_info.lock);
+
+	rc = request_irq(adsp_info.int_adsp, adsp_irq_handler,
+			IRQF_TRIGGER_RISING, "adsp", 0);
+	if (rc < 0)
+		goto fail_request_irq;
+	disable_irq(adsp_info.int_adsp);
+
+	rpc_cb_server_client = msm_rpc_open();
+	if (IS_ERR(rpc_cb_server_client)) {
+		rpc_cb_server_client = NULL;
+		rc = PTR_ERR(rpc_cb_server_client);
+		MM_ERR("could not create rpc server (%d)\n", rc);
+		goto fail_rpc_open;
+	}
+
+	rc = msm_rpc_register_server(rpc_cb_server_client,
+				     rpc_adsp_rtos_mtoa_prog,
+				     rpc_adsp_rtos_mtoa_vers);
+	if (rc) {
+		MM_ERR("could not register callback server (%d)\n", rc);
+		goto fail_rpc_register;
+	}
+
+	/* schedule start of kernel thread later using work queue */
+	queue_work(msm_adsp_probe_work_queue, &msm_adsp_probe_work);
+
+	for (i = 0; i < count; i++) {
+		struct msm_adsp_module *mod = adsp_modules + i;
+		mutex_init(&mod->lock);
+		init_waitqueue_head(&mod->state_wait);
+		mod->info = &adsp_info;
+		mod->name = adsp_info.module[i].name;
+		mod->id = adsp_info.module[i].id;
+		if (adsp_info.module[i].clk_name)
+			mod->clk = clk_get(NULL, adsp_info.module[i].clk_name);
+		else
+			mod->clk = NULL;
+		if (mod->clk && adsp_info.module[i].clk_rate)
+			clk_set_rate(mod->clk, adsp_info.module[i].clk_rate);
+		mod->verify_cmd = adsp_info.module[i].verify_cmd;
+		mod->patch_event = adsp_info.module[i].patch_event;
+		INIT_HLIST_HEAD(&mod->pmem_regions);
+		mod->pdev.name = adsp_info.module[i].pdev_name;
+		mod->pdev.id = -1;
+		adsp_info.id_to_module[i] = mod;
+		platform_device_register(&mod->pdev);
+	}
+
+	msm_adsp_publish_cdevs(adsp_modules, count);
+	rmtask_init();
+
+	return 0;
+
+fail_rpc_register:
+	msm_rpc_close(rpc_cb_server_client);
+	rpc_cb_server_client = NULL;
+fail_rpc_open:
+	enable_irq(adsp_info.int_adsp);
+	free_irq(adsp_info.int_adsp, 0);
+fail_request_irq:
+	kfree(adsp_modules);
+	kfree(adsp_info.init_info_ptr);
+	return rc;
+}
+
+static void adsp_probe_work(struct work_struct *work)
+{
+	/* start the kernel thread to process the callbacks */
+	kthread_run(adsp_rpc_thread, NULL, "kadspd");
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int get_parameters(char *buf, long int *param1, int num_of_par)
+{
+	char *token;
+	int base, cnt;
+
+	token = strsep(&buf, " ");
+
+	for (cnt = 0; cnt < num_of_par; cnt++) {
+		if (token != NULL) {
+			if ((token[1] == 'x') || (token[1] == 'X'))
+				base = 16;
+			else
+				base = 10;
+
+			if (strict_strtoul(token, base, &param1[cnt]) != 0)
+				return -EINVAL;
+
+			token = strsep(&buf, " ");
+			}
+		else
+			return -EINVAL;
+	}
+	return 0;
+}
+
+
+static ssize_t adsp_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	pr_debug("adsp debugfs opened\n");
+	return 0;
+}
+static ssize_t adsp_debug_write(struct file *file, const char __user *buf,
+				size_t cnt, loff_t *ppos)
+{
+	char *access_str = file->private_data;
+	char lbuf[32];
+	int rc;
+	long int param[5];
+
+	if (cnt > sizeof(lbuf) - 1)
+		return -EINVAL;
+	rc = copy_from_user(lbuf, buf, cnt);
+	if (rc) {
+		pr_info("Unable to copy data from user space\n");
+		return -EFAULT;
+	}
+	lbuf[cnt] = '\0';
+
+	if (!strcmp(access_str, "write_log")) {
+		if (get_parameters(lbuf, param, 1) == 0) {
+			switch (param[0]) {
+			case 1:
+				if (wdump <= 0)
+					wdump = 1;
+				pr_debug("write cmd to DSP(A->D) dump \
+					 started:%d\n", wdump);
+				break;
+			case 0:
+				if (wdump > 0)
+					wdump = 0;
+				pr_debug("Stop write cmd to \
+					 DSP(A->D):%d\n", wdump);
+				break;
+			default:
+				rc = -EINVAL;
+				break;
+			}
+		} else
+			rc = -EINVAL;
+	} else if (!strcmp(access_str, "read_log")) {
+		if (get_parameters(lbuf, param, 1) == 0) {
+			switch (param[0]) {
+			case 1:
+				if (rdump <= 0)
+					rdump = 1;
+				pr_debug("write cmd from DSP(D->A) dump \
+					started:%d\n", wdump);
+				break;
+			case 0:
+				if (rdump > 0)
+					rdump = 0;
+				pr_debug("Stop write cmd from \
+					DSP(D->A):%d\n", wdump);
+				break;
+			default:
+				rc = -EINVAL;
+				break;
+			}
+		} else
+			rc = -EINVAL;
+	} else {
+		rc = -EINVAL;
+	}
+	if (rc == 0)
+		rc = cnt;
+	else {
+		pr_err("%s: rc = %d\n", __func__, rc);
+		pr_info("\nWrong command: Use =>\n");
+		pr_info("-------------------------\n");
+		pr_info("To Start A->D:: echo \"1\">/sys/kernel/debug/ \
+			adsp_cmd/write_log\n");
+		pr_info("To Start D->A:: echo \"1\">/sys/kernel/debug/ \
+			adsp_cmd/read_log\n");
+		pr_info("To Stop  A->D:: echo \"0\">/sys/kernel/debug/ \
+			adsp_cmd/write_log\n");
+		pr_info("To Stop  D->A:: echo \"0\">/sys/kernel/debug/ \
+			adsp_cmd/read_log\n");
+		pr_info("------------------------\n");
+	}
+
+	return rc;
+}
+#endif
+
+static struct platform_driver msm_adsp_driver = {
+	.probe = msm_adsp_probe,
+	.driver = {
+		.owner = THIS_MODULE,
+	},
+};
+
+static const char msm_adsp_driver_name[] = "msm_adsp";
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations adsp_debug_fops = {
+	.write = adsp_debug_write,
+	.open = adsp_debug_open,
+};
+#endif
+
+static int __init adsp_init(void)
+{
+	int rc;
+
+#ifdef CONFIG_DEBUG_FS
+	dentry_adsp    = debugfs_create_dir("adsp_cmd", 0);
+	if (!IS_ERR(dentry_adsp)) {
+		dentry_wdata   = debugfs_create_file("write_log", \
+		 S_IFREG | S_IRUGO, dentry_adsp,
+		 (void *) "write_log" , &adsp_debug_fops);
+		dentry_rdata   = debugfs_create_file("read_log", \
+		 S_IFREG | S_IRUGO, dentry_adsp,
+		 (void *) "read_log", &adsp_debug_fops);
+	}
+	rdump = 0;
+	wdump = 0;
+#endif /* CONFIG_DEBUG_FS */
+
+	rpc_adsp_rtos_atom_prog = 0x3000000a;
+	rpc_adsp_rtos_atom_vers = 0x10001;
+	rpc_adsp_rtos_atom_vers_comp = 0x00010001;
+	rpc_adsp_rtos_mtoa_prog = 0x3000000b;
+#if CONFIG_ADSP_RPC_VER > 0x30001
+	rpc_adsp_rtos_mtoa_vers = 0x30002;
+	rpc_adsp_rtos_mtoa_vers_comp = 0x00030002;
+#else
+	rpc_adsp_rtos_mtoa_vers = 0x30001;
+	rpc_adsp_rtos_mtoa_vers_comp = 0x00030001;
+#endif
+
+	msm_adsp_probe_work_queue = create_workqueue("msm_adsp_probe");
+	if (msm_adsp_probe_work_queue == NULL)
+		return -ENOMEM;
+	msm_adsp_driver.driver.name = msm_adsp_driver_name;
+	rc = platform_driver_register(&msm_adsp_driver);
+	MM_INFO("%s -- %d\n", msm_adsp_driver_name, rc);
+	return rc;
+}
+
+device_initcall(adsp_init);
diff --git a/arch/arm/mach-msm/qdsp5/adsp.h b/arch/arm/mach-msm/qdsp5/adsp.h
new file mode 100644
index 0000000..0f16111
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/adsp.h
@@ -0,0 +1,356 @@
+/* arch/arm/mach-msm/qdsp5/adsp.h
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2008-2010, 2012 Code Aurora Forum. All rights reserved.
+ * Author: Iliyan Malchev <ibm@android.com>
+ *
+ * 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 _ARCH_ARM_MACH_MSM_ADSP_H
+#define _ARCH_ARM_MACH_MSM_ADSP_H
+
+#include <linux/types.h>
+#include <linux/msm_adsp.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/msm_adsp.h>
+
+int adsp_pmem_fixup(struct msm_adsp_module *module, void **addr,
+		    unsigned long len);
+int adsp_pmem_fixup_kvaddr(struct msm_adsp_module *module, void **addr,
+			   unsigned long *kvaddr, unsigned long len,
+			   struct file **filp, unsigned long *offset);
+int adsp_pmem_paddr_fixup(struct msm_adsp_module *module, void **addr);
+
+int adsp_vfe_verify_cmd(struct msm_adsp_module *module,
+			unsigned int queue_id, void *cmd_data,
+			size_t cmd_size);
+int adsp_jpeg_verify_cmd(struct msm_adsp_module *module,
+			 unsigned int queue_id, void *cmd_data,
+			 size_t cmd_size);
+int adsp_lpm_verify_cmd(struct msm_adsp_module *module,
+			unsigned int queue_id, void *cmd_data,
+			size_t cmd_size);
+int adsp_video_verify_cmd(struct msm_adsp_module *module,
+			  unsigned int queue_id, void *cmd_data,
+			  size_t cmd_size);
+int adsp_videoenc_verify_cmd(struct msm_adsp_module *module,
+			  unsigned int queue_id, void *cmd_data,
+			  size_t cmd_size);
+void q5audio_dsp_not_responding(void);
+
+struct adsp_event;
+
+int adsp_vfe_patch_event(struct msm_adsp_module *module,
+			struct adsp_event *event);
+
+int adsp_jpeg_patch_event(struct msm_adsp_module *module,
+			struct adsp_event *event);
+
+
+struct adsp_module_info {
+	const char *name;
+	const char *pdev_name;
+	uint32_t id;
+	const char *clk_name;
+	unsigned long clk_rate;
+	int (*verify_cmd) (struct msm_adsp_module*, unsigned int, void *,
+			   size_t);
+	int (*patch_event) (struct msm_adsp_module*, struct adsp_event *);
+};
+
+#define ADSP_EVENT_MAX_SIZE 496
+#define EVENT_LEN       12
+#define EVENT_MSG_ID ((uint16_t)~0)
+
+struct adsp_event {
+	struct list_head list;
+	uint32_t size; /* always in bytes */
+	uint16_t msg_id;
+	uint16_t type; /* 0 for msgs (from aDSP), -1 for events (from ARM9) */
+	int is16; /* always 0 (msg is 32-bit) when the event type is 1(ARM9) */
+	union {
+		uint16_t msg16[ADSP_EVENT_MAX_SIZE / 2];
+		uint32_t msg32[ADSP_EVENT_MAX_SIZE / 4];
+	} data;
+};
+
+struct adsp_info {
+	uint32_t send_irq;
+	uint32_t read_ctrl;
+	uint32_t write_ctrl;
+
+	uint32_t max_msg16_size;
+	uint32_t max_msg32_size;
+
+	uint32_t max_task_id;
+	uint32_t max_module_id;
+	uint32_t max_queue_id;
+	uint32_t max_image_id;
+
+	/* for each image id, a map of queue id to offset */
+	uint32_t **queue_offset;
+
+	/* for each image id, a map of task id to module id */
+	uint32_t **task_to_module;
+
+	/* for each module id, map of module id to module */
+	struct msm_adsp_module **id_to_module;
+
+	uint32_t module_count;
+	struct adsp_module_info *module;
+
+	/* stats */
+	uint32_t events_received;
+	uint32_t event_backlog_max;
+
+	/* rpc_client for init_info */
+	struct msm_rpc_endpoint	*init_info_rpc_client;
+	struct adsp_rtos_mp_mtoa_init_info_type	*init_info_ptr;
+	wait_queue_head_t	init_info_wait;
+	unsigned 		init_info_state;
+	struct mutex lock;
+
+	/* Interrupt value */
+	int int_adsp;
+};
+
+#define RPC_ADSP_RTOS_ATOM_NULL_PROC 0
+#define RPC_ADSP_RTOS_MTOA_NULL_PROC 0
+#define RPC_ADSP_RTOS_APP_TO_MODEM_PROC 2
+#define RPC_ADSP_RTOS_MODEM_TO_APP_PROC 2
+#define RPC_ADSP_RTOS_MTOA_EVENT_INFO_PROC 3
+#define RPC_ADSP_RTOS_MTOA_INIT_INFO_PROC 4
+
+enum rpc_adsp_rtos_proc_type {
+	RPC_ADSP_RTOS_PROC_NONE = 0,
+	RPC_ADSP_RTOS_PROC_MODEM = 1,
+	RPC_ADSP_RTOS_PROC_APPS = 2,
+};
+
+enum {
+	RPC_ADSP_RTOS_CMD_REGISTER_APP,
+	RPC_ADSP_RTOS_CMD_ENABLE,
+	RPC_ADSP_RTOS_CMD_DISABLE,
+	RPC_ADSP_RTOS_CMD_KERNEL_COMMAND,
+	RPC_ADSP_RTOS_CMD_16_COMMAND,
+	RPC_ADSP_RTOS_CMD_32_COMMAND,
+	RPC_ADSP_RTOS_CMD_DISABLE_EVENT_RSP,
+	RPC_ADSP_RTOS_CMD_REMOTE_EVENT,
+	RPC_ADSP_RTOS_CMD_SET_STATE,
+	RPC_ADSP_RTOS_CMD_REMOTE_INIT_INFO_EVENT,
+	RPC_ADSP_RTOS_CMD_GET_INIT_INFO,
+};
+
+enum rpc_adsp_rtos_mod_status_type {
+	RPC_ADSP_RTOS_MOD_READY,
+	RPC_ADSP_RTOS_MOD_DISABLE,
+	RPC_ADSP_RTOS_SERVICE_RESET,
+	RPC_ADSP_RTOS_CMD_FAIL,
+	RPC_ADSP_RTOS_CMD_SUCCESS,
+	RPC_ADSP_RTOS_INIT_INFO,
+	RPC_ADSP_RTOS_DISABLE_FAIL,
+};
+
+struct rpc_adsp_rtos_app_to_modem_args_t {
+	struct rpc_request_hdr hdr;
+	uint32_t gotit; /* if 1, the next elements are present */
+	uint32_t cmd; /* e.g., RPC_ADSP_RTOS_CMD_REGISTER_APP */
+	uint32_t proc_id; /* e.g., RPC_ADSP_RTOS_PROC_APPS */
+	uint32_t module; /* e.g., QDSP_MODULE_AUDPPTASK */
+};
+
+enum qdsp_image_type {
+	QDSP_IMAGE_COMBO,
+	QDSP_IMAGE_GAUDIO,
+	QDSP_IMAGE_QTV_LP,
+	QDSP_IMAGE_MAX,
+	/* DO NOT USE: Force this enum to be a 32bit type to improve speed */
+	QDSP_IMAGE_32BIT_DUMMY = 0x10000
+};
+
+struct adsp_rtos_mp_mtoa_header_type {
+	enum rpc_adsp_rtos_mod_status_type  event;
+	enum rpc_adsp_rtos_proc_type        proc_id;
+};
+
+/* ADSP RTOS MP Communications - Modem to APP's  Event Info*/
+struct adsp_rtos_mp_mtoa_type {
+	uint32_t	module;
+	uint32_t	image;
+	uint32_t	apps_okts;
+};
+
+/* ADSP RTOS MP Communications - Modem to APP's Init Info  */
+#if CONFIG_ADSP_RPC_VER > 0x30001
+#define IMG_MAX         2
+#define ENTRIES_MAX     36
+#define MODULES_MAX     64
+#else
+#define IMG_MAX         6
+#define ENTRIES_MAX     48
+#endif
+#define QUEUES_MAX      64
+
+struct queue_to_offset_type {
+	uint32_t	queue;
+	uint32_t	offset;
+};
+
+struct mod_to_queue_offsets {
+	uint32_t        module;
+	uint32_t        q_type;
+	uint32_t        q_max_len;
+};
+
+struct adsp_rtos_mp_mtoa_init_info_type {
+	uint32_t	image_count;
+	uint32_t	num_queue_offsets;
+	struct queue_to_offset_type	queue_offsets_tbl[IMG_MAX][ENTRIES_MAX];
+	uint32_t	num_task_module_entries;
+	uint32_t	task_to_module_tbl[IMG_MAX][ENTRIES_MAX];
+
+	uint32_t	module_table_size;
+#if CONFIG_ADSP_RPC_VER > 0x30001
+	uint32_t	module_entries[MODULES_MAX];
+#else
+	uint32_t	module_entries[ENTRIES_MAX];
+#endif
+	uint32_t	mod_to_q_entries;
+	struct mod_to_queue_offsets	mod_to_q_tbl[ENTRIES_MAX];
+	/*
+	 * queue_offsets[] is to store only queue_offsets
+	 */
+	uint32_t	queue_offsets[IMG_MAX][QUEUES_MAX];
+};
+
+struct adsp_rtos_mp_mtoa_s_type {
+	struct adsp_rtos_mp_mtoa_header_type mp_mtoa_header;
+#if CONFIG_ADSP_RPC_VER == 0x30001
+	uint32_t desc_field;
+#endif
+	union {
+		struct adsp_rtos_mp_mtoa_init_info_type mp_mtoa_init_packet;
+		struct adsp_rtos_mp_mtoa_type mp_mtoa_packet;
+	} adsp_rtos_mp_mtoa_data;
+};
+
+struct rpc_adsp_rtos_modem_to_app_args_t {
+	struct rpc_request_hdr hdr;
+	uint32_t gotit; /* if 1, the next elements are present */
+	struct adsp_rtos_mp_mtoa_s_type mtoa_pkt;
+};
+
+#define ADSP_STATE_DISABLED   0
+#define ADSP_STATE_ENABLING   1
+#define ADSP_STATE_ENABLED    2
+#define ADSP_STATE_DISABLING  3
+#define ADSP_STATE_INIT_INFO  4
+
+struct msm_adsp_module {
+	struct mutex lock;
+	const char *name;
+	unsigned id;
+	struct adsp_info *info;
+
+	struct msm_rpc_endpoint *rpc_client;
+	struct msm_adsp_ops *ops;
+	void *driver_data;
+
+	/* statistics */
+	unsigned num_commands;
+	unsigned num_events;
+
+	wait_queue_head_t state_wait;
+	unsigned state;
+
+	struct platform_device pdev;
+	struct clk *clk;
+	int open_count;
+
+	struct mutex pmem_regions_lock;
+	struct hlist_head pmem_regions;
+	int (*verify_cmd) (struct msm_adsp_module*, unsigned int, void *,
+			   size_t);
+	int (*patch_event) (struct msm_adsp_module*, struct adsp_event *);
+};
+
+extern void msm_adsp_publish_cdevs(struct msm_adsp_module *, unsigned);
+extern int adsp_init_info(struct adsp_info *info);
+extern void rmtask_init(void);
+
+/* Value to indicate that a queue is not defined for a particular image */
+#define QDSP_RTOS_NO_QUEUE  0xfffffffe
+
+/*
+ * Constants used to communicate with the ADSP RTOS
+ */
+#define ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_M            0x80000000U
+#define ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_NAVAIL_V     0x80000000U
+#define ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_AVAIL_V      0x00000000U
+
+#define ADSP_RTOS_WRITE_CTRL_WORD_CMD_M              0x70000000U
+#define ADSP_RTOS_WRITE_CTRL_WORD_CMD_WRITE_REQ_V    0x00000000U
+#define ADSP_RTOS_WRITE_CTRL_WORD_CMD_WRITE_DONE_V   0x10000000U
+#define ADSP_RTOS_WRITE_CTRL_WORD_CMD_NO_CMD_V       0x70000000U
+
+#define ADSP_RTOS_WRITE_CTRL_WORD_STATUS_M           0x0E000000U
+#define ADSP_RTOS_WRITE_CTRL_WORD_NO_ERR_V           0x00000000U
+#define ADSP_RTOS_WRITE_CTRL_WORD_NO_FREE_BUF_V      0x02000000U
+
+#define ADSP_RTOS_WRITE_CTRL_WORD_KERNEL_FLG_M       0x01000000U
+#define ADSP_RTOS_WRITE_CTRL_WORD_HTOD_MSG_WRITE_V   0x00000000U
+#define ADSP_RTOS_WRITE_CTRL_WORD_HTOD_CMD_V         0x01000000U
+
+#define ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M         0x00FFFFFFU
+#define ADSP_RTOS_WRITE_CTRL_WORD_HTOD_CMD_ID_M      0x00FFFFFFU
+
+/* Combination of MUTEX and CMD bits to check if the DSP is busy */
+#define ADSP_RTOS_WRITE_CTRL_WORD_READY_M            0xF0000000U
+#define ADSP_RTOS_WRITE_CTRL_WORD_READY_V            0x70000000U
+
+/* RTOS to Host processor command mask values */
+#define ADSP_RTOS_READ_CTRL_WORD_FLAG_M              0x80000000U
+#define ADSP_RTOS_READ_CTRL_WORD_FLAG_UP_WAIT_V      0x00000000U
+#define ADSP_RTOS_READ_CTRL_WORD_FLAG_UP_CONT_V      0x80000000U
+
+#define ADSP_RTOS_READ_CTRL_WORD_CMD_M               0x60000000U
+#define ADSP_RTOS_READ_CTRL_WORD_READ_DONE_V         0x00000000U
+#define ADSP_RTOS_READ_CTRL_WORD_READ_REQ_V          0x20000000U
+#define ADSP_RTOS_READ_CTRL_WORD_NO_CMD_V            0x60000000U
+
+/* Combination of FLAG and COMMAND bits to check if MSG ready */
+#define ADSP_RTOS_READ_CTRL_WORD_READY_M             0xE0000000U
+#define ADSP_RTOS_READ_CTRL_WORD_READY_V             0xA0000000U
+#define ADSP_RTOS_READ_CTRL_WORD_CONT_V              0xC0000000U
+#define ADSP_RTOS_READ_CTRL_WORD_DONE_V              0xE0000000U
+
+#define ADSP_RTOS_READ_CTRL_WORD_STATUS_M            0x18000000U
+#define ADSP_RTOS_READ_CTRL_WORD_NO_ERR_V            0x00000000U
+
+#define ADSP_RTOS_READ_CTRL_WORD_IN_PROG_M           0x04000000U
+#define ADSP_RTOS_READ_CTRL_WORD_NO_READ_IN_PROG_V   0x00000000U
+#define ADSP_RTOS_READ_CTRL_WORD_READ_IN_PROG_V      0x04000000U
+
+#define ADSP_RTOS_READ_CTRL_WORD_CMD_TYPE_M          0x03000000U
+#define ADSP_RTOS_READ_CTRL_WORD_CMD_TASK_TO_H_V     0x00000000U
+#define ADSP_RTOS_READ_CTRL_WORD_CMD_KRNL_TO_H_V     0x01000000U
+#define ADSP_RTOS_READ_CTRL_WORD_CMD_H_TO_KRNL_CFM_V 0x02000000U
+
+#define ADSP_RTOS_READ_CTRL_WORD_DSP_ADDR_M          0x00FFFFFFU
+
+#define ADSP_RTOS_READ_CTRL_WORD_MSG_ID_M            0x000000FFU
+#define ADSP_RTOS_READ_CTRL_WORD_TASK_ID_M           0x0000FF00U
+
+/* Base address of DSP and DSP hardware registers */
+#define QDSP_RAMC_OFFSET  0x400000
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp5/adsp_6210.c b/arch/arm/mach-msm/qdsp5/adsp_6210.c
new file mode 100644
index 0000000..322ba68
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/adsp_6210.c
@@ -0,0 +1,283 @@
+/* arch/arm/mach-msm/qdsp5/adsp_6210.h
+ *
+ * Copyright (c) 2008-2009, Code Aurora Forum. 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.
+ *
+ */
+
+#include "adsp.h"
+
+/* Firmware modules */
+typedef enum { 
+	QDSP_MODULE_KERNEL,
+	QDSP_MODULE_AFETASK,
+	QDSP_MODULE_AUDPLAY0TASK,
+	QDSP_MODULE_AUDPLAY1TASK,
+	QDSP_MODULE_AUDPPTASK,
+	QDSP_MODULE_VIDEOTASK,
+	QDSP_MODULE_VIDEO_AAC_VOC,
+	QDSP_MODULE_PCM_DEC,
+	QDSP_MODULE_AUDIO_DEC_MP3,
+	QDSP_MODULE_AUDIO_DEC_AAC,
+	QDSP_MODULE_AUDIO_DEC_WMA,
+	QDSP_MODULE_HOSTPCM,
+	QDSP_MODULE_DTMF,
+	QDSP_MODULE_AUDRECTASK,
+	QDSP_MODULE_AUDPREPROCTASK,
+	QDSP_MODULE_SBC_ENC,
+	QDSP_MODULE_VOC,
+	QDSP_MODULE_VOC_PCM,
+	QDSP_MODULE_VOCENCTASK,
+	QDSP_MODULE_VOCDECTASK,
+	QDSP_MODULE_VOICEPROCTASK,
+	QDSP_MODULE_VIDEOENCTASK,
+	QDSP_MODULE_VFETASK,
+	QDSP_MODULE_WAV_ENC,
+	QDSP_MODULE_AACLC_ENC,
+	QDSP_MODULE_VIDEO_AMR,
+	QDSP_MODULE_VOC_AMR,
+	QDSP_MODULE_VOC_EVRC,
+	QDSP_MODULE_VOC_13K,
+	QDSP_MODULE_VOC_FGV,
+	QDSP_MODULE_DIAGTASK,
+	QDSP_MODULE_JPEGTASK,
+	QDSP_MODULE_LPMTASK,
+	QDSP_MODULE_QCAMTASK,
+	QDSP_MODULE_MODMATHTASK,
+	QDSP_MODULE_AUDPLAY2TASK,
+	QDSP_MODULE_AUDPLAY3TASK,
+	QDSP_MODULE_AUDPLAY4TASK,
+	QDSP_MODULE_GRAPHICSTASK,
+	QDSP_MODULE_MIDI,
+	QDSP_MODULE_GAUDIO,
+	QDSP_MODULE_VDEC_LP_MODE,
+	QDSP_MODULE_MAX,
+} qdsp_module_type;
+
+#define QDSP_RTOS_MAX_TASK_ID  19U
+
+/* Table of modules indexed by task ID for the GAUDIO image */
+static qdsp_module_type qdsp_gaudio_task_to_module_table[] = {
+	QDSP_MODULE_KERNEL,
+	QDSP_MODULE_AFETASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_AUDPPTASK,
+	QDSP_MODULE_AUDPLAY0TASK,
+	QDSP_MODULE_AUDPLAY1TASK,
+	QDSP_MODULE_AUDPLAY2TASK,
+	QDSP_MODULE_AUDPLAY3TASK,
+	QDSP_MODULE_AUDPLAY4TASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_AUDRECTASK,
+	QDSP_MODULE_AUDPREPROCTASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_GRAPHICSTASK,
+	QDSP_MODULE_MAX
+};
+
+/* Queue offset table indexed by queue ID for the GAUDIO image */
+static uint32_t qdsp_gaudio_queue_offset_table[] = {
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_lpmCommandQueue              */
+	0x3be,               /* QDSP_mpuAfeQueue                  */
+	0x3ee,               /* QDSP_mpuGraphicsCmdQueue          */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuModmathCmdQueue           */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuVDecCmdQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuVDecPktQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuVEncCmdQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_rxMpuDecCmdQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_rxMpuDecPktQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_txMpuEncQueue                */
+	0x3c2,               /* QDSP_uPAudPPCmd1Queue             */
+	0x3c6,               /* QDSP_uPAudPPCmd2Queue             */
+	0x3ca,               /* QDSP_uPAudPPCmd3Queue             */
+	0x3da,               /* QDSP_uPAudPlay0BitStreamCtrlQueue */
+	0x3de,               /* QDSP_uPAudPlay1BitStreamCtrlQueue */
+	0x3e2,               /* QDSP_uPAudPlay2BitStreamCtrlQueue */
+	0x3e6,               /* QDSP_uPAudPlay3BitStreamCtrlQueue */
+	0x3ea,               /* QDSP_uPAudPlay4BitStreamCtrlQueue */
+	0x3ce,               /* QDSP_uPAudPreProcCmdQueue         */
+	0x3d6,               /* QDSP_uPAudRecBitStreamQueue       */
+	0x3d2,               /* QDSP_uPAudRecCmdQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPJpegActionCmdQueue         */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPJpegCfgCmdQueue            */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPVocProcQueue               */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_vfeCommandQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_vfeCommandScaleQueue         */
+	QDSP_RTOS_NO_QUEUE   /* QDSP_vfeCommandTableQueue         */
+};
+
+/* Table of modules indexed by task ID for the COMBO image */
+static qdsp_module_type qdsp_combo_task_to_module_table[] = {
+	QDSP_MODULE_KERNEL,
+	QDSP_MODULE_AFETASK,
+	QDSP_MODULE_VOCDECTASK,
+	QDSP_MODULE_VOCENCTASK,
+	QDSP_MODULE_VIDEOTASK,
+	QDSP_MODULE_VIDEOENCTASK,
+	QDSP_MODULE_VOICEPROCTASK,
+	QDSP_MODULE_VFETASK,
+	QDSP_MODULE_JPEGTASK,
+	QDSP_MODULE_AUDPPTASK,
+	QDSP_MODULE_AUDPLAY0TASK,
+	QDSP_MODULE_AUDPLAY1TASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_LPMTASK,
+	QDSP_MODULE_AUDRECTASK,
+	QDSP_MODULE_AUDPREPROCTASK,
+	QDSP_MODULE_MODMATHTASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX
+};
+
+/* Queue offset table indexed by queue ID for the COMBO image */
+static uint32_t qdsp_combo_queue_offset_table[] = {
+	0x585,               /* QDSP_lpmCommandQueue              */
+	0x52d,               /* QDSP_mpuAfeQueue                  */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuGraphicsCmdQueue          */
+	0x541,               /* QDSP_mpuModmathCmdQueue           */
+	0x555,               /* QDSP_mpuVDecCmdQueue              */
+	0x559,               /* QDSP_mpuVDecPktQueue              */
+	0x551,               /* QDSP_mpuVEncCmdQueue              */
+	0x535,               /* QDSP_rxMpuDecCmdQueue             */
+	0x539,               /* QDSP_rxMpuDecPktQueue             */
+	0x53d,               /* QDSP_txMpuEncQueue                */
+	0x55d,               /* QDSP_uPAudPPCmd1Queue             */
+	0x561,               /* QDSP_uPAudPPCmd2Queue             */
+	0x565,               /* QDSP_uPAudPPCmd3Queue             */
+	0x575,               /* QDSP_uPAudPlay0BitStreamCtrlQueue */
+	0x579,               /* QDSP_uPAudPlay1BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay2BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay3BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay4BitStreamCtrlQueue */
+	0x569,               /* QDSP_uPAudPreProcCmdQueue         */
+	0x571,               /* QDSP_uPAudRecBitStreamQueue       */
+	0x56d,               /* QDSP_uPAudRecCmdQueue             */
+	0x581,               /* QDSP_uPJpegActionCmdQueue         */
+	0x57d,               /* QDSP_uPJpegCfgCmdQueue            */
+	0x531,               /* QDSP_uPVocProcQueue               */
+	0x545,               /* QDSP_vfeCommandQueue              */
+	0x54d,               /* QDSP_vfeCommandScaleQueue         */
+	0x549                /* QDSP_vfeCommandTableQueue         */
+};
+
+/* Table of modules indexed by task ID for the QTV_LP image */
+static qdsp_module_type qdsp_qtv_lp_task_to_module_table[] = {
+	QDSP_MODULE_KERNEL,
+	QDSP_MODULE_AFETASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_VIDEOTASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_AUDPPTASK,
+	QDSP_MODULE_AUDPLAY0TASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_AUDRECTASK,
+	QDSP_MODULE_AUDPREPROCTASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX
+};
+
+/* Queue offset table indexed by queue ID for the QTV_LP image */
+static uint32_t qdsp_qtv_lp_queue_offset_table[] = {
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_lpmCommandQueue              */
+	0x40c,               /* QDSP_mpuAfeQueue                  */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuGraphicsCmdQueue          */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuModmathCmdQueue           */
+	0x410,               /* QDSP_mpuVDecCmdQueue              */
+	0x414,               /* QDSP_mpuVDecPktQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuVEncCmdQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_rxMpuDecCmdQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_rxMpuDecPktQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_txMpuEncQueue                */
+	0x41c,               /* QDSP_uPAudPPCmd1Queue             */
+	0x420,               /* QDSP_uPAudPPCmd2Queue             */
+	0x424,               /* QDSP_uPAudPPCmd3Queue             */
+	0x430,               /* QDSP_uPAudPlay0BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay1BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay2BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay3BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay4BitStreamCtrlQueue */
+	0x418,               /* QDSP_uPAudPreProcCmdQueue         */
+	0x42c,               /* QDSP_uPAudRecBitStreamQueue       */
+	0x428,               /* QDSP_uPAudRecCmdQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPJpegActionCmdQueue         */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPJpegCfgCmdQueue            */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPVocProcQueue               */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_vfeCommandQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_vfeCommandScaleQueue         */
+	QDSP_RTOS_NO_QUEUE   /* QDSP_vfeCommandTableQueue         */
+};
+
+/* Tables to convert tasks to modules */
+static uint32_t *qdsp_task_to_module[] = {
+	qdsp_combo_task_to_module_table,
+	qdsp_gaudio_task_to_module_table,
+	qdsp_qtv_lp_task_to_module_table,
+};
+
+/* Tables to retrieve queue offsets */
+static uint32_t *qdsp_queue_offset_table[] = {
+	qdsp_combo_queue_offset_table,
+	qdsp_gaudio_queue_offset_table,
+	qdsp_qtv_lp_queue_offset_table,
+};
+
+#define QDSP_MODULE(n) \
+	{ .name = #n, .pdev_name = "adsp_" #n, .id = QDSP_MODULE_##n }
+
+static struct adsp_module_info module_info[] = {
+	QDSP_MODULE(AUDPPTASK),
+	QDSP_MODULE(AUDRECTASK),
+	QDSP_MODULE(AUDPREPROCTASK),
+	QDSP_MODULE(VFETASK),
+	QDSP_MODULE(QCAMTASK),
+	QDSP_MODULE(LPMTASK),
+	QDSP_MODULE(JPEGTASK),
+	QDSP_MODULE(VIDEOTASK),
+	QDSP_MODULE(VDEC_LP_MODE),
+};
+
+int adsp_init_info(struct adsp_info *info)
+{
+	info->send_irq =   0x00c00200;
+	info->read_ctrl =  0x00400038;
+	info->write_ctrl = 0x00400034;
+
+	info->max_msg16_size = 193;
+	info->max_msg32_size = 8;
+
+	info->max_task_id = 16;
+	info->max_module_id = QDSP_MODULE_MAX - 1;
+	info->max_queue_id = QDSP_QUEUE_MAX;
+	info->max_image_id = 2;
+	info->queue_offset = qdsp_queue_offset_table;
+	info->task_to_module = qdsp_task_to_module;
+
+	info->module_count = ARRAY_SIZE(module_info);
+	info->module = module_info;
+	return 0;
+}
diff --git a/arch/arm/mach-msm/qdsp5/adsp_6220.c b/arch/arm/mach-msm/qdsp5/adsp_6220.c
new file mode 100644
index 0000000..f947cd7
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/adsp_6220.c
@@ -0,0 +1,284 @@
+/* arch/arm/mach-msm/qdsp5/adsp_6220.h
+ *
+ * Copyright (c) 2008-2009, Code Aurora Forum. 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.
+ *
+ */
+
+#include "adsp.h"
+
+/* Firmware modules */
+typedef enum { 
+	QDSP_MODULE_KERNEL,
+	QDSP_MODULE_AFETASK,
+	QDSP_MODULE_AUDPLAY0TASK,
+	QDSP_MODULE_AUDPLAY1TASK,
+	QDSP_MODULE_AUDPPTASK,
+	QDSP_MODULE_VIDEOTASK,
+	QDSP_MODULE_VIDEO_AAC_VOC,
+	QDSP_MODULE_PCM_DEC,
+	QDSP_MODULE_AUDIO_DEC_MP3,
+	QDSP_MODULE_AUDIO_DEC_AAC,
+	QDSP_MODULE_AUDIO_DEC_WMA,
+	QDSP_MODULE_HOSTPCM,
+	QDSP_MODULE_DTMF,
+	QDSP_MODULE_AUDRECTASK,
+	QDSP_MODULE_AUDPREPROCTASK,
+	QDSP_MODULE_SBC_ENC,
+	QDSP_MODULE_VOC,
+	QDSP_MODULE_VOC_PCM,
+	QDSP_MODULE_VOCENCTASK,
+	QDSP_MODULE_VOCDECTASK,
+	QDSP_MODULE_VOICEPROCTASK,
+	QDSP_MODULE_VIDEOENCTASK,
+	QDSP_MODULE_VFETASK,
+	QDSP_MODULE_WAV_ENC,
+	QDSP_MODULE_AACLC_ENC,
+	QDSP_MODULE_VIDEO_AMR,
+	QDSP_MODULE_VOC_AMR,
+	QDSP_MODULE_VOC_EVRC,
+	QDSP_MODULE_VOC_13K,
+	QDSP_MODULE_VOC_FGV,
+	QDSP_MODULE_DIAGTASK,
+	QDSP_MODULE_JPEGTASK,
+	QDSP_MODULE_LPMTASK,
+	QDSP_MODULE_QCAMTASK,
+	QDSP_MODULE_MODMATHTASK,
+	QDSP_MODULE_AUDPLAY2TASK,
+	QDSP_MODULE_AUDPLAY3TASK,
+	QDSP_MODULE_AUDPLAY4TASK,
+	QDSP_MODULE_GRAPHICSTASK,
+	QDSP_MODULE_MIDI,
+	QDSP_MODULE_GAUDIO,
+	QDSP_MODULE_VDEC_LP_MODE,
+	QDSP_MODULE_MAX,
+} qdsp_module_type;
+
+#define QDSP_RTOS_MAX_TASK_ID  19U
+
+/* Table of modules indexed by task ID for the GAUDIO image */
+static qdsp_module_type qdsp_gaudio_task_to_module_table[] = {
+	QDSP_MODULE_KERNEL,
+	QDSP_MODULE_AFETASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_AUDPPTASK,
+	QDSP_MODULE_AUDPLAY0TASK,
+	QDSP_MODULE_AUDPLAY1TASK,
+	QDSP_MODULE_AUDPLAY2TASK,
+	QDSP_MODULE_AUDPLAY3TASK,
+	QDSP_MODULE_AUDPLAY4TASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_AUDRECTASK,
+	QDSP_MODULE_AUDPREPROCTASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_GRAPHICSTASK,
+	QDSP_MODULE_MAX
+};
+
+/* Queue offset table indexed by queue ID for the GAUDIO image */
+static uint32_t qdsp_gaudio_queue_offset_table[] = {
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_lpmCommandQueue              */
+	0x3f0,               /* QDSP_mpuAfeQueue                  */
+	0x420,               /* QDSP_mpuGraphicsCmdQueue          */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuModmathCmdQueue           */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuVDecCmdQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuVDecPktQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuVEncCmdQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_rxMpuDecCmdQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_rxMpuDecPktQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_txMpuEncQueue                */
+	0x3f4,               /* QDSP_uPAudPPCmd1Queue             */
+	0x3f8,               /* QDSP_uPAudPPCmd2Queue             */
+	0x3fc,               /* QDSP_uPAudPPCmd3Queue             */
+	0x40c,               /* QDSP_uPAudPlay0BitStreamCtrlQueue */
+	0x410,               /* QDSP_uPAudPlay1BitStreamCtrlQueue */
+	0x414,               /* QDSP_uPAudPlay2BitStreamCtrlQueue */
+	0x418,               /* QDSP_uPAudPlay3BitStreamCtrlQueue */
+	0x41c,               /* QDSP_uPAudPlay4BitStreamCtrlQueue */
+	0x400,               /* QDSP_uPAudPreProcCmdQueue         */
+	0x408,               /* QDSP_uPAudRecBitStreamQueue       */
+	0x404,               /* QDSP_uPAudRecCmdQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPJpegActionCmdQueue         */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPJpegCfgCmdQueue            */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPVocProcQueue               */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_vfeCommandQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_vfeCommandScaleQueue         */
+	QDSP_RTOS_NO_QUEUE   /* QDSP_vfeCommandTableQueue         */
+};
+
+/* Table of modules indexed by task ID for the COMBO image */
+static qdsp_module_type qdsp_combo_task_to_module_table[] = {
+	QDSP_MODULE_KERNEL,
+	QDSP_MODULE_AFETASK,
+	QDSP_MODULE_VOCDECTASK,
+	QDSP_MODULE_VOCENCTASK,
+	QDSP_MODULE_VIDEOTASK,
+	QDSP_MODULE_VIDEOENCTASK,
+	QDSP_MODULE_VOICEPROCTASK,
+	QDSP_MODULE_VFETASK,
+	QDSP_MODULE_JPEGTASK,
+	QDSP_MODULE_AUDPPTASK,
+	QDSP_MODULE_AUDPLAY0TASK,
+	QDSP_MODULE_AUDPLAY1TASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_LPMTASK,
+	QDSP_MODULE_AUDRECTASK,
+	QDSP_MODULE_AUDPREPROCTASK,
+	QDSP_MODULE_MODMATHTASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX
+};
+
+/* Queue offset table indexed by queue ID for the COMBO image */
+static uint32_t qdsp_combo_queue_offset_table[] = {
+	0x6f2,               /* QDSP_lpmCommandQueue              */
+	0x69e,               /* QDSP_mpuAfeQueue                  */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuGraphicsCmdQueue          */
+	0x6b2,               /* QDSP_mpuModmathCmdQueue           */
+	0x6c6,               /* QDSP_mpuVDecCmdQueue              */
+	0x6ca,               /* QDSP_mpuVDecPktQueue              */
+	0x6c2,               /* QDSP_mpuVEncCmdQueue              */
+	0x6a6,               /* QDSP_rxMpuDecCmdQueue             */
+	0x6aa,               /* QDSP_rxMpuDecPktQueue             */
+	0x6ae,               /* QDSP_txMpuEncQueue                */
+	0x6ce,               /* QDSP_uPAudPPCmd1Queue             */
+	0x6d2,               /* QDSP_uPAudPPCmd2Queue             */
+	0x6d6,               /* QDSP_uPAudPPCmd3Queue             */
+	0x6e6,               /* QDSP_uPAudPlay0BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay1BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay2BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay3BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay4BitStreamCtrlQueue */
+	0x6da,               /* QDSP_uPAudPreProcCmdQueue         */
+	0x6e2,               /* QDSP_uPAudRecBitStreamQueue       */
+	0x6de,               /* QDSP_uPAudRecCmdQueue             */
+	0x6ee,               /* QDSP_uPJpegActionCmdQueue         */
+	0x6ea,               /* QDSP_uPJpegCfgCmdQueue            */
+	0x6a2,               /* QDSP_uPVocProcQueue               */
+	0x6b6,               /* QDSP_vfeCommandQueue              */
+	0x6be,               /* QDSP_vfeCommandScaleQueue         */
+	0x6ba                /* QDSP_vfeCommandTableQueue         */
+};
+
+/* Table of modules indexed by task ID for the QTV_LP image */
+static qdsp_module_type qdsp_qtv_lp_task_to_module_table[] = {
+	QDSP_MODULE_KERNEL,
+	QDSP_MODULE_AFETASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_VIDEOTASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_AUDPPTASK,
+	QDSP_MODULE_AUDPLAY0TASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_AUDRECTASK,
+	QDSP_MODULE_AUDPREPROCTASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX
+};
+
+/* Queue offset table indexed by queue ID for the QTV_LP image */
+static uint32_t qdsp_qtv_lp_queue_offset_table[] = {
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_lpmCommandQueue              */
+	0x430,               /* QDSP_mpuAfeQueue                  */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuGraphicsCmdQueue          */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuModmathCmdQueue           */
+	0x434,               /* QDSP_mpuVDecCmdQueue              */
+	0x438,               /* QDSP_mpuVDecPktQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuVEncCmdQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_rxMpuDecCmdQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_rxMpuDecPktQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_txMpuEncQueue                */
+	0x440,               /* QDSP_uPAudPPCmd1Queue             */
+	0x444,               /* QDSP_uPAudPPCmd2Queue             */
+	0x448,               /* QDSP_uPAudPPCmd3Queue             */
+	0x454,               /* QDSP_uPAudPlay0BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay1BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay2BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay3BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay4BitStreamCtrlQueue */
+	0x43c,               /* QDSP_uPAudPreProcCmdQueue         */
+	0x450,               /* QDSP_uPAudRecBitStreamQueue       */
+	0x44c,               /* QDSP_uPAudRecCmdQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPJpegActionCmdQueue         */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPJpegCfgCmdQueue            */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPVocProcQueue               */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_vfeCommandQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_vfeCommandScaleQueue         */
+	QDSP_RTOS_NO_QUEUE   /* QDSP_vfeCommandTableQueue         */
+};
+
+/* Tables to convert tasks to modules */
+static qdsp_module_type *qdsp_task_to_module[] = {
+	qdsp_combo_task_to_module_table,
+	qdsp_gaudio_task_to_module_table,
+	qdsp_qtv_lp_task_to_module_table,
+};
+
+/* Tables to retrieve queue offsets */
+static uint32_t *qdsp_queue_offset_table[] = {
+	qdsp_combo_queue_offset_table,
+	qdsp_gaudio_queue_offset_table,
+	qdsp_qtv_lp_queue_offset_table,
+};
+
+#define QDSP_MODULE(n) \
+	{ .name = #n, .pdev_name = "adsp_" #n, .id = QDSP_MODULE_##n }
+
+static struct adsp_module_info module_info[] = {
+	QDSP_MODULE(AUDPLAY0TASK),
+	QDSP_MODULE(AUDPPTASK),
+	QDSP_MODULE(AUDPREPROCTASK),
+	QDSP_MODULE(AUDRECTASK),
+	QDSP_MODULE(VFETASK),
+	QDSP_MODULE(QCAMTASK),
+	QDSP_MODULE(LPMTASK),
+	QDSP_MODULE(JPEGTASK),
+	QDSP_MODULE(VIDEOTASK),
+	QDSP_MODULE(VDEC_LP_MODE),
+};
+
+int adsp_init_info(struct adsp_info *info)
+{
+	info->send_irq =   0x00c00200;
+	info->read_ctrl =  0x00400038;
+	info->write_ctrl = 0x00400034;
+
+	info->max_msg16_size = 193;
+	info->max_msg32_size = 8;
+
+	info->max_task_id = 16;
+	info->max_module_id = QDSP_MODULE_MAX - 1;
+	info->max_queue_id = QDSP_QUEUE_MAX;
+	info->max_image_id = 2;
+	info->queue_offset = qdsp_queue_offset_table;
+	info->task_to_module = qdsp_task_to_module;
+
+	info->module_count = ARRAY_SIZE(module_info);
+	info->module = module_info;
+	return 0;
+}
diff --git a/arch/arm/mach-msm/qdsp5/adsp_6225.c b/arch/arm/mach-msm/qdsp5/adsp_6225.c
new file mode 100644
index 0000000..6f8d3f4
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/adsp_6225.c
@@ -0,0 +1,328 @@
+/* arch/arm/mach-msm/qdsp5/adsp_6225.h
+ *
+ * Copyright (c) 2008-2009, Code Aurora Forum. 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.
+ *
+ */
+
+#include "adsp.h"
+
+/* Firmware modules */
+typedef enum {
+	QDSP_MODULE_KERNEL,
+	QDSP_MODULE_AFETASK,
+	QDSP_MODULE_AUDPLAY0TASK,
+	QDSP_MODULE_AUDPLAY1TASK,
+	QDSP_MODULE_AUDPPTASK,
+	QDSP_MODULE_VIDEOTASK,
+	QDSP_MODULE_VIDEO_AAC_VOC,
+	QDSP_MODULE_PCM_DEC,
+	QDSP_MODULE_AUDIO_DEC_MP3,
+	QDSP_MODULE_AUDIO_DEC_AAC,
+	QDSP_MODULE_AUDIO_DEC_WMA,
+	QDSP_MODULE_HOSTPCM,
+	QDSP_MODULE_DTMF,
+	QDSP_MODULE_AUDRECTASK,
+	QDSP_MODULE_AUDPREPROCTASK,
+	QDSP_MODULE_SBC_ENC,
+	QDSP_MODULE_VOC_UMTS,
+	QDSP_MODULE_VOC_CDMA,
+	QDSP_MODULE_VOC_PCM,
+	QDSP_MODULE_VOCENCTASK,
+	QDSP_MODULE_VOCDECTASK,
+	QDSP_MODULE_VOICEPROCTASK,
+	QDSP_MODULE_VIDEOENCTASK,
+	QDSP_MODULE_VFETASK,
+	QDSP_MODULE_WAV_ENC,
+	QDSP_MODULE_AACLC_ENC,
+	QDSP_MODULE_VIDEO_AMR,
+	QDSP_MODULE_VOC_AMR,
+	QDSP_MODULE_VOC_EVRC,
+	QDSP_MODULE_VOC_13K,
+	QDSP_MODULE_VOC_FGV,
+	QDSP_MODULE_DIAGTASK,
+	QDSP_MODULE_JPEGTASK,
+	QDSP_MODULE_LPMTASK,
+	QDSP_MODULE_QCAMTASK,
+	QDSP_MODULE_MODMATHTASK,
+	QDSP_MODULE_AUDPLAY2TASK,
+	QDSP_MODULE_AUDPLAY3TASK,
+	QDSP_MODULE_AUDPLAY4TASK,
+	QDSP_MODULE_GRAPHICSTASK,
+	QDSP_MODULE_MIDI,
+	QDSP_MODULE_GAUDIO,
+	QDSP_MODULE_VDEC_LP_MODE,
+	QDSP_MODULE_MAX,
+} qdsp_module_type;
+
+#define QDSP_RTOS_MAX_TASK_ID  30U
+
+/* Table of modules indexed by task ID for the GAUDIO image */
+static qdsp_module_type qdsp_gaudio_task_to_module_table[] = {
+	QDSP_MODULE_KERNEL,
+	QDSP_MODULE_AFETASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_AUDPPTASK,
+	QDSP_MODULE_AUDPLAY0TASK,
+	QDSP_MODULE_AUDPLAY1TASK,
+	QDSP_MODULE_AUDPLAY2TASK,
+	QDSP_MODULE_AUDPLAY3TASK,
+	QDSP_MODULE_AUDPLAY4TASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_AUDRECTASK,
+	QDSP_MODULE_AUDPREPROCTASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_GRAPHICSTASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+};
+
+/* Queue offset table indexed by queue ID for the GAUDIO image */
+static uint32_t qdsp_gaudio_queue_offset_table[] = {
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_lpmCommandQueue              */
+	0x3f0,               /* QDSP_mpuAfeQueue                  */
+	0x420,               /* QDSP_mpuGraphicsCmdQueue          */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuModmathCmdQueue           */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuVDecCmdQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuVDecPktQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuVEncCmdQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_rxMpuDecCmdQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_rxMpuDecPktQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_txMpuEncQueue                */
+	0x3f4,               /* QDSP_uPAudPPCmd1Queue             */
+	0x3f8,               /* QDSP_uPAudPPCmd2Queue             */
+	0x3fc,               /* QDSP_uPAudPPCmd3Queue             */
+	0x40c,               /* QDSP_uPAudPlay0BitStreamCtrlQueue */
+	0x410,               /* QDSP_uPAudPlay1BitStreamCtrlQueue */
+	0x414,               /* QDSP_uPAudPlay2BitStreamCtrlQueue */
+	0x418,               /* QDSP_uPAudPlay3BitStreamCtrlQueue */
+	0x41c,               /* QDSP_uPAudPlay4BitStreamCtrlQueue */
+	0x400,               /* QDSP_uPAudPreProcCmdQueue         */
+	0x408,               /* QDSP_uPAudRecBitStreamQueue       */
+	0x404,               /* QDSP_uPAudRecCmdQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPJpegActionCmdQueue         */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPJpegCfgCmdQueue            */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPVocProcQueue               */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_vfeCommandQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_vfeCommandScaleQueue         */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_vfeCommandTableQueue         */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPDiagQueue                  */
+};
+
+/* Table of modules indexed by task ID for the COMBO image */
+static qdsp_module_type qdsp_combo_task_to_module_table[] = {
+	QDSP_MODULE_KERNEL,
+	QDSP_MODULE_AFETASK,
+	QDSP_MODULE_VOCDECTASK,
+	QDSP_MODULE_VOCENCTASK,
+	QDSP_MODULE_VIDEOTASK,
+	QDSP_MODULE_VIDEOENCTASK,
+	QDSP_MODULE_VOICEPROCTASK,
+	QDSP_MODULE_VFETASK,
+	QDSP_MODULE_JPEGTASK,
+	QDSP_MODULE_AUDPPTASK,
+	QDSP_MODULE_AUDPLAY0TASK,
+	QDSP_MODULE_AUDPLAY1TASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_LPMTASK,
+	QDSP_MODULE_AUDRECTASK,
+	QDSP_MODULE_AUDPREPROCTASK,
+	QDSP_MODULE_MODMATHTASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_DIAGTASK,
+	QDSP_MODULE_MAX,
+};
+
+/* Queue offset table indexed by queue ID for the COMBO image */
+static uint32_t qdsp_combo_queue_offset_table[] = {
+	0x714,               /* QDSP_lpmCommandQueue              */
+	0x6bc,               /* QDSP_mpuAfeQueue                  */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuGraphicsCmdQueue          */
+	0x6d0,               /* QDSP_mpuModmathCmdQueue           */
+	0x6e8,               /* QDSP_mpuVDecCmdQueue              */
+	0x6ec,               /* QDSP_mpuVDecPktQueue              */
+	0x6e4,               /* QDSP_mpuVEncCmdQueue              */
+	0x6c4,               /* QDSP_rxMpuDecCmdQueue             */
+	0x6c8,               /* QDSP_rxMpuDecPktQueue             */
+	0x6cc,               /* QDSP_txMpuEncQueue                */
+	0x6f0,               /* QDSP_uPAudPPCmd1Queue             */
+	0x6f4,               /* QDSP_uPAudPPCmd2Queue             */
+	0x6f8,               /* QDSP_uPAudPPCmd3Queue             */
+	0x708,               /* QDSP_uPAudPlay0BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay1BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay2BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay3BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay4BitStreamCtrlQueue */
+	0x6fc,               /* QDSP_uPAudPreProcCmdQueue         */
+	0x704,               /* QDSP_uPAudRecBitStreamQueue       */
+	0x700,               /* QDSP_uPAudRecCmdQueue             */
+	0x710,               /* QDSP_uPJpegActionCmdQueue         */
+	0x70c,               /* QDSP_uPJpegCfgCmdQueue            */
+	0x6c0,               /* QDSP_uPVocProcQueue               */
+	0x6d8,               /* QDSP_vfeCommandQueue              */
+	0x6e0,               /* QDSP_vfeCommandScaleQueue         */
+	0x6dc,               /* QDSP_vfeCommandTableQueue         */
+	0x6d4,               /* QDSP_uPDiagQueue                  */
+};
+
+/* Table of modules indexed by task ID for the QTV_LP image */
+static qdsp_module_type qdsp_qtv_lp_task_to_module_table[] = {
+	QDSP_MODULE_KERNEL,
+	QDSP_MODULE_AFETASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_VIDEOTASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_AUDPPTASK,
+	QDSP_MODULE_AUDPLAY0TASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_AUDRECTASK,
+	QDSP_MODULE_AUDPREPROCTASK,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+	QDSP_MODULE_MAX,
+};
+
+/* Queue offset table indexed by queue ID for the QTV_LP image */
+static uint32_t qdsp_qtv_lp_queue_offset_table[] = {
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_lpmCommandQueue              */
+	0x3fe,               /* QDSP_mpuAfeQueue                  */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuGraphicsCmdQueue          */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuModmathCmdQueue           */
+	0x402,               /* QDSP_mpuVDecCmdQueue              */
+	0x406,               /* QDSP_mpuVDecPktQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_mpuVEncCmdQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_rxMpuDecCmdQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_rxMpuDecPktQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_txMpuEncQueue                */
+	0x40e,               /* QDSP_uPAudPPCmd1Queue             */
+	0x412,               /* QDSP_uPAudPPCmd2Queue             */
+	0x416,               /* QDSP_uPAudPPCmd3Queue             */
+	0x422,               /* QDSP_uPAudPlay0BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay1BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay2BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay3BitStreamCtrlQueue */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPAudPlay4BitStreamCtrlQueue */
+	0x40a,               /* QDSP_uPAudPreProcCmdQueue         */
+	0x41e,               /* QDSP_uPAudRecBitStreamQueue       */
+	0x41a,               /* QDSP_uPAudRecCmdQueue             */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPJpegActionCmdQueue         */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPJpegCfgCmdQueue            */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPVocProcQueue               */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_vfeCommandQueue              */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_vfeCommandScaleQueue         */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_vfeCommandTableQueue         */
+	QDSP_RTOS_NO_QUEUE,  /* QDSP_uPDiagQueue                  */
+};
+
+/* Tables to convert tasks to modules */
+static qdsp_module_type *qdsp_task_to_module[] = {
+	qdsp_combo_task_to_module_table,
+	qdsp_gaudio_task_to_module_table,
+	qdsp_qtv_lp_task_to_module_table,
+};
+
+/* Tables to retrieve queue offsets */
+static uint32_t *qdsp_queue_offset_table[] = {
+	qdsp_combo_queue_offset_table,
+	qdsp_gaudio_queue_offset_table,
+	qdsp_qtv_lp_queue_offset_table,
+};
+
+#define QDSP_MODULE(n, clkname, clkrate, verify_cmd_func, patch_event_func) \
+	{ .name = #n, .pdev_name = "adsp_" #n, .id = QDSP_MODULE_##n, \
+	  .clk_name = clkname, .clk_rate = clkrate, \
+	  .verify_cmd = verify_cmd_func, .patch_event = patch_event_func }
+
+static struct adsp_module_info module_info[] = {
+	QDSP_MODULE(AUDPLAY0TASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(AUDPPTASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(AUDRECTASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(AUDPREPROCTASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(VFETASK, "vfe_clk", 0, adsp_vfe_verify_cmd,
+		adsp_vfe_patch_event),
+	QDSP_MODULE(QCAMTASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(LPMTASK, NULL, 0, adsp_lpm_verify_cmd, NULL),
+	QDSP_MODULE(JPEGTASK, "vdc_clk", 0, adsp_jpeg_verify_cmd,
+		adsp_jpeg_patch_event),
+	QDSP_MODULE(VIDEOTASK, "vdc_clk", 96000000,
+		adsp_video_verify_cmd, NULL),
+	QDSP_MODULE(VDEC_LP_MODE, NULL, 0, NULL, NULL),
+	QDSP_MODULE(VIDEOENCTASK, "vdc_clk", 96000000,
+		adsp_videoenc_verify_cmd, NULL),
+};
+
+int adsp_init_info(struct adsp_info *info)
+{
+	info->send_irq =   0x00c00200;
+	info->read_ctrl =  0x00400038;
+	info->write_ctrl = 0x00400034;
+
+	info->max_msg16_size = 193;
+	info->max_msg32_size = 8;
+
+	info->max_task_id = 16;
+	info->max_module_id = QDSP_MODULE_MAX - 1;
+	info->max_queue_id = QDSP_QUEUE_MAX;
+	info->max_image_id = 2;
+	info->queue_offset = qdsp_queue_offset_table;
+	info->task_to_module = qdsp_task_to_module;
+
+	info->module_count = ARRAY_SIZE(module_info);
+	info->module = module_info;
+	return 0;
+}
diff --git a/arch/arm/mach-msm/qdsp5/adsp_debug.c b/arch/arm/mach-msm/qdsp5/adsp_debug.c
new file mode 100644
index 0000000..03deab9
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/adsp_debug.c
@@ -0,0 +1,97 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+
+#include <mach/debug_mm.h>
+#include <mach/msm_smd.h>
+
+#include "adsp.h"
+
+#define MAX_LEN 64
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *adsp_dentry;
+#endif
+static char l_buf[MAX_LEN];
+static unsigned int crash_enable;
+
+static ssize_t q5_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	MM_DBG("q5 debugfs opened\n");
+	return 0;
+}
+
+static ssize_t q5_debug_write(struct file *file, const char __user *buf,
+				size_t count, loff_t *ppos)
+{
+	int len;
+
+	if (count < 0)
+		return 0;
+	len = count > (MAX_LEN - 1) ? (MAX_LEN - 1) : count;
+	if (copy_from_user(l_buf, buf, len)) {
+		MM_INFO("Unable to copy data from user space\n");
+		return -EFAULT;
+	}
+	l_buf[len] = 0;
+	if (l_buf[len - 1] == '\n') {
+		l_buf[len - 1] = 0;
+		len--;
+	}
+	if (!strncmp(l_buf, "boom", MAX_LEN)) {
+		q5audio_dsp_not_responding();
+	} else if (!strncmp(l_buf, "enable", MAX_LEN)) {
+		crash_enable = 1;
+		MM_INFO("Crash enabled : %d\n", crash_enable);
+	} else if (!strncmp(l_buf, "disable", MAX_LEN)) {
+		crash_enable = 0;
+		MM_INFO("Crash disabled : %d\n", crash_enable);
+	} else
+		MM_INFO("Unknown Command\n");
+
+	return count;
+}
+
+static const struct file_operations q5_debug_fops = {
+	.write = q5_debug_write,
+	.open = q5_debug_open,
+};
+
+static int __init q5_debug_init(void)
+{
+#ifdef CONFIG_DEBUG_FS
+	adsp_dentry = debugfs_create_file("q5_debug", S_IFREG | S_IRUGO,
+				NULL, (void *) NULL, &q5_debug_fops);
+#endif /* CONFIG_DEBUG_FS */
+	return 0;
+}
+device_initcall(q5_debug_init);
+
diff --git a/arch/arm/mach-msm/qdsp5/adsp_driver.c b/arch/arm/mach-msm/qdsp5/adsp_driver.c
new file mode 100644
index 0000000..6860d84
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/adsp_driver.c
@@ -0,0 +1,668 @@
+/* arch/arm/mach-msm/qdsp5/adsp_driver.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ * Author: Iliyan Malchev <ibm@android.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+
+#include "adsp.h"
+
+#include <linux/msm_adsp.h>
+#include <linux/android_pmem.h>
+#include <mach/debug_mm.h>
+
+struct adsp_pmem_info {
+	int fd;
+	void *vaddr;
+};
+
+struct adsp_pmem_region {
+	struct hlist_node list;
+	void *vaddr;
+	unsigned long paddr;
+	unsigned long kvaddr;
+	unsigned long len;
+	struct file *file;
+};
+
+struct adsp_device {
+	struct msm_adsp_module *module;
+
+	spinlock_t event_queue_lock;
+	wait_queue_head_t event_wait;
+	struct list_head event_queue;
+	int abort;
+
+	const char *name;
+	struct device *device;
+	struct cdev cdev;
+};
+
+static struct adsp_device *inode_to_device(struct inode *inode);
+
+#define __CONTAINS(r, v, l) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __v = v;					\
+	typeof(v) __e = __v + l;				\
+	int res = __v >= __r->vaddr && 				\
+		__e <= __r->vaddr + __r->len;			\
+	res;							\
+})
+
+#define CONTAINS(r1, r2) ({					\
+	typeof(r2) __r2 = r2;					\
+	__CONTAINS(r1, __r2->vaddr, __r2->len);			\
+})
+
+#define IN_RANGE(r, v) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __vv = v;					\
+	int res = ((__vv >= __r->vaddr) &&			\
+		(__vv < (__r->vaddr + __r->len)));		\
+	res;							\
+})
+
+#define OVERLAPS(r1, r2) ({					\
+	typeof(r1) __r1 = r1;					\
+	typeof(r2) __r2 = r2;					\
+	typeof(__r2->vaddr) __v = __r2->vaddr;			\
+	typeof(__v) __e = __v + __r2->len - 1;			\
+	int res = (IN_RANGE(__r1, __v) || IN_RANGE(__r1, __e));	\
+	res;							\
+})
+
+static int adsp_pmem_check(struct msm_adsp_module *module,
+		void *vaddr, unsigned long len)
+{
+	struct adsp_pmem_region *region_elt;
+	struct hlist_node *node;
+	struct adsp_pmem_region t = { .vaddr = vaddr, .len = len };
+
+	hlist_for_each_entry(region_elt, node, &module->pmem_regions, list) {
+		if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
+		    OVERLAPS(region_elt, &t)) {
+			MM_ERR("module %s:"
+				" region (vaddr %p len %ld)"
+				" clashes with registered region"
+				" (vaddr %p paddr %p len %ld)\n",
+				module->name,
+				vaddr, len,
+				region_elt->vaddr,
+				(void *)region_elt->paddr,
+				region_elt->len);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int adsp_pmem_add(struct msm_adsp_module *module,
+			 struct adsp_pmem_info *info)
+{
+	unsigned long paddr, kvaddr, len;
+	struct file *file;
+	struct adsp_pmem_region *region;
+	int rc = -EINVAL;
+
+	mutex_lock(&module->pmem_regions_lock);
+	region = kmalloc(sizeof(*region), GFP_KERNEL);
+	if (!region) {
+		rc = -ENOMEM;
+		goto end;
+	}
+	INIT_HLIST_NODE(&region->list);
+	if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) {
+		kfree(region);
+		goto end;
+	}
+
+	rc = adsp_pmem_check(module, info->vaddr, len);
+	if (rc < 0) {
+		put_pmem_file(file);
+		kfree(region);
+		goto end;
+	}
+
+	region->vaddr = info->vaddr;
+	region->paddr = paddr;
+	region->kvaddr = kvaddr;
+	region->len = len;
+	region->file = file;
+
+	hlist_add_head(&region->list, &module->pmem_regions);
+end:
+	mutex_unlock(&module->pmem_regions_lock);
+	return rc;
+}
+
+static int adsp_pmem_lookup_vaddr(struct msm_adsp_module *module, void **addr,
+		     unsigned long len, struct adsp_pmem_region **region)
+{
+	struct hlist_node *node;
+	void *vaddr = *addr;
+	struct adsp_pmem_region *region_elt;
+
+	int match_count = 0;
+
+	*region = NULL;
+
+	/* returns physical address or zero */
+	hlist_for_each_entry(region_elt, node, &module->pmem_regions, list) {
+		if (vaddr >= region_elt->vaddr &&
+		    vaddr < region_elt->vaddr + region_elt->len &&
+		    vaddr + len <= region_elt->vaddr + region_elt->len) {
+			/* offset since we could pass vaddr inside a registerd
+			 * pmem buffer
+			 */
+
+			match_count++;
+			if (!*region)
+				*region = region_elt;
+		}
+	}
+
+	if (match_count > 1) {
+		MM_ERR("module %s: "
+			"multiple hits for vaddr %p, len %ld\n",
+			module->name, vaddr, len);
+		hlist_for_each_entry(region_elt, node,
+				&module->pmem_regions, list) {
+			if (vaddr >= region_elt->vaddr &&
+			    vaddr < region_elt->vaddr + region_elt->len &&
+			    vaddr + len <= region_elt->vaddr + region_elt->len)
+				MM_ERR("%p, %ld --> %p\n",
+					region_elt->vaddr,
+					region_elt->len,
+					(void *)region_elt->paddr);
+		}
+	}
+
+	return *region ? 0 : -1;
+}
+
+int adsp_pmem_fixup_kvaddr(struct msm_adsp_module *module, void **addr,
+			   unsigned long *kvaddr, unsigned long len,
+			   struct file **filp, unsigned long *offset)
+{
+	struct adsp_pmem_region *region;
+	void *vaddr = *addr;
+	unsigned long *paddr = (unsigned long *)addr;
+	int ret;
+
+	ret = adsp_pmem_lookup_vaddr(module, addr, len, &region);
+	if (ret) {
+		MM_ERR("not patching %s (paddr & kvaddr),"
+			" lookup (%p, %ld) failed\n",
+			module->name, vaddr, len);
+		return ret;
+	}
+	*paddr = region->paddr + (vaddr - region->vaddr);
+	*kvaddr = region->kvaddr + (vaddr - region->vaddr);
+	if (filp)
+		*filp = region->file;
+	if (offset)
+		*offset = vaddr - region->vaddr;
+	return 0;
+}
+
+int adsp_pmem_fixup(struct msm_adsp_module *module, void **addr,
+		    unsigned long len)
+{
+	struct adsp_pmem_region *region;
+	void *vaddr = *addr;
+	unsigned long *paddr = (unsigned long *)addr;
+	int ret;
+
+	ret = adsp_pmem_lookup_vaddr(module, addr, len, &region);
+	if (ret) {
+		MM_ERR("not patching %s, lookup (%p, %ld) failed\n",
+			module->name, vaddr, len);
+		return ret;
+	}
+
+	*paddr = region->paddr + (vaddr - region->vaddr);
+	return 0;
+}
+
+static int adsp_verify_cmd(struct msm_adsp_module *module,
+			   unsigned int queue_id, void *cmd_data,
+			   size_t cmd_size)
+{
+	/* call the per module verifier */
+	if (module->verify_cmd)
+		return module->verify_cmd(module, queue_id, cmd_data,
+					     cmd_size);
+	else
+		MM_INFO("no packet verifying function "
+				 "for task %s\n", module->name);
+	return 0;
+}
+
+static long adsp_write_cmd(struct adsp_device *adev, void __user *arg)
+{
+	struct adsp_command_t cmd;
+	unsigned char buf[256];
+	void *cmd_data;
+	long rc;
+
+	if (copy_from_user(&cmd, (void __user *)arg, sizeof(cmd)))
+		return -EFAULT;
+
+	if (cmd.len > 256) {
+		cmd_data = kmalloc(cmd.len, GFP_USER);
+		if (!cmd_data)
+			return -ENOMEM;
+	} else {
+		cmd_data = buf;
+	}
+
+	if (copy_from_user(cmd_data, (void __user *)(cmd.data), cmd.len)) {
+		rc = -EFAULT;
+		goto end;
+	}
+
+	mutex_lock(&adev->module->pmem_regions_lock);
+	if (adsp_verify_cmd(adev->module, cmd.queue, cmd_data, cmd.len)) {
+		MM_ERR("module %s: verify failed.\n", adev->module->name);
+		rc = -EINVAL;
+		goto end;
+	}
+	/* complete the writes to the buffer */
+	wmb();
+	rc = msm_adsp_write(adev->module, cmd.queue, cmd_data, cmd.len);
+end:
+	mutex_unlock(&adev->module->pmem_regions_lock);
+
+	if (cmd.len > 256)
+		kfree(cmd_data);
+
+	return rc;
+}
+
+static int adsp_events_pending(struct adsp_device *adev)
+{
+	unsigned long flags;
+	int yes;
+	spin_lock_irqsave(&adev->event_queue_lock, flags);
+	yes = !list_empty(&adev->event_queue);
+	spin_unlock_irqrestore(&adev->event_queue_lock, flags);
+	return yes || adev->abort;
+}
+
+static int adsp_pmem_lookup_paddr(struct msm_adsp_module *module, void **addr,
+		     struct adsp_pmem_region **region)
+{
+	struct hlist_node *node;
+	unsigned long paddr = (unsigned long)(*addr);
+	struct adsp_pmem_region *region_elt;
+
+	hlist_for_each_entry(region_elt, node, &module->pmem_regions, list) {
+		if (paddr >= region_elt->paddr &&
+		    paddr < region_elt->paddr + region_elt->len) {
+			*region = region_elt;
+			return 0;
+		}
+	}
+	return -1;
+}
+
+int adsp_pmem_paddr_fixup(struct msm_adsp_module *module, void **addr)
+{
+	struct adsp_pmem_region *region;
+	unsigned long paddr = (unsigned long)(*addr);
+	unsigned long *vaddr = (unsigned long *)addr;
+	int ret;
+
+	ret = adsp_pmem_lookup_paddr(module, addr, &region);
+	if (ret) {
+		MM_ERR("not patching %s, paddr %p lookup failed\n",
+			module->name, vaddr);
+		return ret;
+	}
+
+	*vaddr = (unsigned long)region->vaddr + (paddr - region->paddr);
+	return 0;
+}
+
+static int adsp_patch_event(struct msm_adsp_module *module,
+				struct adsp_event *event)
+{
+	/* call the per-module msg verifier */
+	if (module->patch_event)
+		return module->patch_event(module, event);
+	return 0;
+}
+
+static long adsp_get_event(struct adsp_device *adev, void __user *arg)
+{
+	unsigned long flags;
+	struct adsp_event *data = NULL;
+	struct adsp_event_t evt;
+	int timeout;
+	long rc = 0;
+
+	if (copy_from_user(&evt, arg, sizeof(struct adsp_event_t)))
+		return -EFAULT;
+
+	timeout = (int)evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(
+			adev->event_wait, adsp_events_pending(adev),
+			msecs_to_jiffies(timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(
+			adev->event_wait, adsp_events_pending(adev));
+	}
+	if (rc < 0)
+		return rc;
+
+	if (adev->abort)
+		return -ENODEV;
+
+	spin_lock_irqsave(&adev->event_queue_lock, flags);
+	if (!list_empty(&adev->event_queue)) {
+		data = list_first_entry(&adev->event_queue,
+					struct adsp_event, list);
+		list_del(&data->list);
+	}
+	spin_unlock_irqrestore(&adev->event_queue_lock, flags);
+
+	if (!data)
+		return -EAGAIN;
+
+	/* DSP messages are type 0; they may contain physical addresses */
+	if (data->type == 0)
+		adsp_patch_event(adev->module, data);
+
+	/* map adsp_event --> adsp_event_t */
+	if (evt.len < data->size) {
+		rc = -ETOOSMALL;
+		goto end;
+	}
+	/* order the reads to the buffer */
+	rmb();
+	if (data->msg_id != EVENT_MSG_ID) {
+		if (copy_to_user((void *)(evt.data), data->data.msg16,
+					data->size)) {
+			rc = -EFAULT;
+			goto end;
+	}
+	} else {
+		if (copy_to_user((void *)(evt.data), data->data.msg32,
+					data->size)) {
+			rc = -EFAULT;
+			goto end;
+		}
+	}
+
+	evt.type = data->type; /* 0 --> from aDSP, 1 --> from ARM9 */
+	evt.msg_id = data->msg_id;
+	evt.flags = data->is16;
+	evt.len = data->size;
+	if (copy_to_user(arg, &evt, sizeof(evt)))
+		rc = -EFAULT;
+end:
+	kfree(data);
+	return rc;
+}
+
+static int adsp_pmem_del(struct msm_adsp_module *module)
+{
+	struct hlist_node *node, *tmp;
+	struct adsp_pmem_region *region;
+
+	mutex_lock(&module->pmem_regions_lock);
+	hlist_for_each_safe(node, tmp, &module->pmem_regions) {
+		region = hlist_entry(node, struct adsp_pmem_region, list);
+		hlist_del(node);
+		put_pmem_file(region->file);
+		kfree(region);
+	}
+	mutex_unlock(&module->pmem_regions_lock);
+	BUG_ON(!hlist_empty(&module->pmem_regions));
+
+	return 0;
+}
+
+static long adsp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	struct adsp_device *adev = filp->private_data;
+
+	switch (cmd) {
+	case ADSP_IOCTL_ENABLE:
+		return msm_adsp_enable(adev->module);
+
+	case ADSP_IOCTL_DISABLE:
+		return msm_adsp_disable(adev->module);
+
+	case ADSP_IOCTL_DISABLE_EVENT_RSP:
+		return msm_adsp_disable_event_rsp(adev->module);
+
+	case ADSP_IOCTL_DISABLE_ACK:
+		MM_ERR("ADSP_IOCTL_DISABLE_ACK is not implemented\n");
+		break;
+
+	case ADSP_IOCTL_WRITE_COMMAND:
+		return adsp_write_cmd(adev, (void __user *) arg);
+
+	case ADSP_IOCTL_GET_EVENT:
+		return adsp_get_event(adev, (void __user *) arg);
+
+	case ADSP_IOCTL_SET_CLKRATE: {
+		unsigned long clk_rate;
+		if (copy_from_user(&clk_rate, (void *) arg, sizeof(clk_rate)))
+			return -EFAULT;
+		return adsp_set_clkrate(adev->module, clk_rate);
+	}
+
+	case ADSP_IOCTL_REGISTER_PMEM: {
+		struct adsp_pmem_info info;
+		if (copy_from_user(&info, (void *) arg, sizeof(info)))
+			return -EFAULT;
+		return adsp_pmem_add(adev->module, &info);
+	}
+
+	case ADSP_IOCTL_ABORT_EVENT_READ:
+		adev->abort = 1;
+		wake_up(&adev->event_wait);
+		break;
+
+	case ADSP_IOCTL_UNREGISTER_PMEM:
+		return adsp_pmem_del(adev->module);
+
+	default:
+		break;
+	}
+	return -EINVAL;
+}
+
+static int adsp_release(struct inode *inode, struct file *filp)
+{
+	struct adsp_device *adev = filp->private_data;
+	struct msm_adsp_module *module = adev->module;
+	int rc = 0;
+
+	MM_INFO("release '%s'\n", adev->name);
+
+	/* clear module before putting it to avoid race with open() */
+	adev->module = NULL;
+
+	rc = adsp_pmem_del(module);
+
+	msm_adsp_put(module);
+	return rc;
+}
+
+static void adsp_event(void *driver_data, unsigned id, size_t len,
+		       void (*getevent)(void *ptr, size_t len))
+{
+	struct adsp_device *adev = driver_data;
+	struct adsp_event *event;
+	unsigned long flags;
+
+	if (len > ADSP_EVENT_MAX_SIZE) {
+		MM_ERR("event too large (%d bytes)\n", len);
+		return;
+	}
+
+	event = kmalloc(sizeof(*event), GFP_ATOMIC);
+	if (!event) {
+		MM_ERR("cannot allocate buffer\n");
+		return;
+	}
+
+	if (id != EVENT_MSG_ID) {
+		event->type = 0;
+		event->is16 = 0;
+		event->msg_id = id;
+		event->size = len;
+
+		getevent(event->data.msg16, len);
+	} else {
+		event->type = 1;
+		event->is16 = 1;
+		event->msg_id = id;
+		event->size = len;
+		getevent(event->data.msg32, len);
+	}
+
+	spin_lock_irqsave(&adev->event_queue_lock, flags);
+	list_add_tail(&event->list, &adev->event_queue);
+	spin_unlock_irqrestore(&adev->event_queue_lock, flags);
+	wake_up(&adev->event_wait);
+}
+
+static struct msm_adsp_ops adsp_ops = {
+	.event = adsp_event,
+};
+
+static int adsp_open(struct inode *inode, struct file *filp)
+{
+	struct adsp_device *adev;
+	int rc;
+
+	rc = nonseekable_open(inode, filp);
+	if (rc < 0)
+		return rc;
+
+	adev = inode_to_device(inode);
+	if (!adev)
+		return -ENODEV;
+
+	MM_INFO("open '%s'\n", adev->name);
+
+	rc = msm_adsp_get(adev->name, &adev->module, &adsp_ops, adev);
+	if (rc)
+		return rc;
+
+	MM_INFO("opened module '%s' adev %p\n", adev->name, adev);
+	filp->private_data = adev;
+	adev->abort = 0;
+	INIT_HLIST_HEAD(&adev->module->pmem_regions);
+	mutex_init(&adev->module->pmem_regions_lock);
+
+	return 0;
+}
+
+static unsigned adsp_device_count;
+static struct adsp_device *adsp_devices;
+
+static struct adsp_device *inode_to_device(struct inode *inode)
+{
+	unsigned n = MINOR(inode->i_rdev);
+	if (n < adsp_device_count) {
+		if (adsp_devices[n].device)
+			return adsp_devices + n;
+	}
+	return NULL;
+}
+
+static dev_t adsp_devno;
+static struct class *adsp_class;
+
+static struct file_operations adsp_fops = {
+	.owner = THIS_MODULE,
+	.open = adsp_open,
+	.unlocked_ioctl = adsp_ioctl,
+	.release = adsp_release,
+};
+
+static void adsp_create(struct adsp_device *adev, const char *name,
+			struct device *parent, dev_t devt)
+{
+	struct device *dev;
+	int rc;
+
+	dev = device_create(adsp_class, parent, devt, "%s", name);
+	if (IS_ERR(dev))
+		return;
+
+	init_waitqueue_head(&adev->event_wait);
+	INIT_LIST_HEAD(&adev->event_queue);
+	spin_lock_init(&adev->event_queue_lock);
+
+	cdev_init(&adev->cdev, &adsp_fops);
+	adev->cdev.owner = THIS_MODULE;
+
+	rc = cdev_add(&adev->cdev, devt, 1);
+	if (rc < 0) {
+		device_destroy(adsp_class, devt);
+	} else {
+		adev->device = dev;
+		adev->name = name;
+	}
+}
+
+void msm_adsp_publish_cdevs(struct msm_adsp_module *modules, unsigned n)
+{
+	int rc;
+
+	adsp_devices = kzalloc(sizeof(struct adsp_device) * n, GFP_KERNEL);
+	if (!adsp_devices)
+		return;
+
+	adsp_class = class_create(THIS_MODULE, "adsp");
+	if (IS_ERR(adsp_class))
+		goto fail_create_class;
+
+	rc = alloc_chrdev_region(&adsp_devno, 0, n, "adsp");
+	if (rc < 0)
+		goto fail_alloc_region;
+
+	adsp_device_count = n;
+	for (n = 0; n < adsp_device_count; n++) {
+		adsp_create(adsp_devices + n,
+			    modules[n].name, &modules[n].pdev.dev,
+			    MKDEV(MAJOR(adsp_devno), n));
+	}
+
+	return;
+
+fail_alloc_region:
+	class_unregister(adsp_class);
+fail_create_class:
+	kfree(adsp_devices);
+}
diff --git a/arch/arm/mach-msm/qdsp5/adsp_info.c b/arch/arm/mach-msm/qdsp5/adsp_info.c
new file mode 100644
index 0000000..dea52bb
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/adsp_info.c
@@ -0,0 +1,144 @@
+/* arch/arm/mach-msm/adsp_info.c
+ *
+ * Copyright (c) 2008-2009, 2011-2012 Code Aurora Forum. 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.
+ *
+ */
+
+#include "adsp.h"
+
+/* Firmware modules */
+#define QDSP_MODULE_KERNEL                  0x0106dd4e
+#define QDSP_MODULE_AFETASK                 0x0106dd6f
+#define QDSP_MODULE_AUDPLAY0TASK            0x0106dd70
+#define QDSP_MODULE_AUDPLAY1TASK            0x0106dd71
+#define QDSP_MODULE_AUDPPTASK               0x0106dd72
+#define QDSP_MODULE_VIDEOTASK               0x0106dd73
+#define QDSP_MODULE_VIDEO_AAC_VOC           0x0106dd74
+#define QDSP_MODULE_PCM_DEC                 0x0106dd75
+#define QDSP_MODULE_AUDIO_DEC_MP3           0x0106dd76
+#define QDSP_MODULE_AUDIO_DEC_AAC           0x0106dd77
+#define QDSP_MODULE_AUDIO_DEC_WMA           0x0106dd78
+#define QDSP_MODULE_HOSTPCM                 0x0106dd79
+#define QDSP_MODULE_DTMF                    0x0106dd7a
+#define QDSP_MODULE_AUDRECTASK              0x0106dd7b
+#define QDSP_MODULE_AUDPREPROCTASK          0x0106dd7c
+#define QDSP_MODULE_SBC_ENC                 0x0106dd7d
+#define QDSP_MODULE_VOC_UMTS                0x0106dd9a
+#define QDSP_MODULE_VOC_CDMA                0x0106dd98
+#define QDSP_MODULE_VOC_PCM                 0x0106dd7f
+#define QDSP_MODULE_VOCENCTASK              0x0106dd80
+#define QDSP_MODULE_VOCDECTASK              0x0106dd81
+#define QDSP_MODULE_VOICEPROCTASK           0x0106dd82
+#define QDSP_MODULE_VIDEOENCTASK            0x0106dd83
+#define QDSP_MODULE_VFETASK                 0x0106dd84
+#define QDSP_MODULE_WAV_ENC                 0x0106dd85
+#define QDSP_MODULE_AACLC_ENC               0x0106dd86
+#define QDSP_MODULE_VIDEO_AMR               0x0106dd87
+#define QDSP_MODULE_VOC_AMR                 0x0106dd88
+#define QDSP_MODULE_VOC_EVRC                0x0106dd89
+#define QDSP_MODULE_VOC_13K                 0x0106dd8a
+#define QDSP_MODULE_VOC_FGV                 0x0106dd8b
+#define QDSP_MODULE_DIAGTASK                0x0106dd8c
+#define QDSP_MODULE_JPEGTASK                0x0106dd8d
+#define QDSP_MODULE_LPMTASK                 0x0106dd8e
+#define QDSP_MODULE_QCAMTASK                0x0106dd8f
+#define QDSP_MODULE_MODMATHTASK             0x0106dd90
+#define QDSP_MODULE_AUDPLAY2TASK            0x0106dd91
+#define QDSP_MODULE_AUDPLAY3TASK            0x0106dd92
+#define QDSP_MODULE_AUDPLAY4TASK            0x0106dd93
+#define QDSP_MODULE_GRAPHICSTASK            0x0106dd94
+#define QDSP_MODULE_MIDI                    0x0106dd95
+#define QDSP_MODULE_GAUDIO                  0x0106dd96
+#define QDSP_MODULE_VDEC_LP_MODE            0x0106dd97
+#define QDSP_MODULE_VIDEO_AAC_VOC_TURBO     0x01089f77
+#define QDSP_MODULE_VIDEO_AMR_TURBO         0x01089f78
+#define QDSP_MODULE_WM_TURBO_MODE           0x01089f79
+#define QDSP_MODULE_VDEC_LP_MODE_TURBO      0x01089f7a
+#define QDSP_MODULE_AUDREC0TASK             0x0109696f
+#define QDSP_MODULE_AUDREC1TASK             0x01096970
+#define QDSP_MODULE_RMTASK                  0x01090f8e
+#define QDSP_MODULE_MAX                     0x7fffffff
+
+   /* DO NOT USE: Force this enum to be a 32bit type to improve speed */
+#define QDSP_MODULE_32BIT_DUMMY 0x10000
+
+static uint32_t *qdsp_task_to_module[IMG_MAX];
+static uint32_t	*qdsp_queue_offset_table[IMG_MAX];
+
+#define QDSP_MODULE(n, clkname, clkrate, verify_cmd_func, patch_event_func) \
+	{ .name = #n, .pdev_name = "adsp_" #n, .id = QDSP_MODULE_##n, \
+	  .clk_name = clkname, .clk_rate = clkrate, \
+	  .verify_cmd = verify_cmd_func, .patch_event = patch_event_func }
+
+static struct adsp_module_info module_info[] = {
+	QDSP_MODULE(AUDPLAY0TASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(AUDPLAY1TASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(AUDPLAY2TASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(AUDPLAY3TASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(AUDPPTASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(AUDPREPROCTASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(RMTASK, NULL, 0, NULL, NULL),
+#if !defined(CONFIG_ARCH_MSM7X30)
+	QDSP_MODULE(AUDRECTASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(VFETASK, NULL, 0, adsp_vfe_verify_cmd,
+		adsp_vfe_patch_event),
+	QDSP_MODULE(QCAMTASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(LPMTASK, NULL, 0, adsp_lpm_verify_cmd, NULL),
+	QDSP_MODULE(JPEGTASK, "vdc_clk", 96000000, adsp_jpeg_verify_cmd,
+		adsp_jpeg_patch_event),
+	QDSP_MODULE(VIDEOTASK, "vdc_clk", 96000000,
+		adsp_video_verify_cmd, NULL),
+	QDSP_MODULE(VDEC_LP_MODE, NULL, 0, NULL, NULL),
+	QDSP_MODULE(VIDEOENCTASK, "vdc_clk", 96000000,
+		adsp_videoenc_verify_cmd, NULL),
+	QDSP_MODULE(VIDEO_AAC_VOC_TURBO, NULL, 0, NULL, NULL),
+	QDSP_MODULE(VIDEO_AMR_TURBO, NULL, 0, NULL, NULL),
+	QDSP_MODULE(WM_TURBO_MODE, NULL, 0, NULL, NULL),
+	QDSP_MODULE(VDEC_LP_MODE_TURBO, NULL, 0, NULL, NULL),
+#if defined(CONFIG_MSM7X27A_AUDIO)
+	QDSP_MODULE(AUDREC1TASK, NULL, 0, NULL, NULL),
+#endif
+#else
+	QDSP_MODULE(AFETASK , NULL, 0, NULL, NULL),
+	QDSP_MODULE(AUDREC0TASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(AUDREC1TASK, NULL, 0, NULL, NULL),
+#endif
+};
+
+int adsp_init_info(struct adsp_info *info)
+{
+	uint32_t img_num;
+
+	info->send_irq =   0x00c00200;
+	info->read_ctrl =  0x00400038;
+	info->write_ctrl = 0x00400034;
+
+	info->max_msg16_size = 193;
+	info->max_msg32_size = 8;
+	for (img_num = 0; img_num < IMG_MAX; img_num++)
+		qdsp_queue_offset_table[img_num] =
+		&info->init_info_ptr->queue_offsets[img_num][0];
+
+	for (img_num = 0; img_num < IMG_MAX; img_num++)
+		qdsp_task_to_module[img_num] =
+		&info->init_info_ptr->task_to_module_tbl[img_num][0];
+	info->max_task_id = 30;
+	info->max_module_id = QDSP_MODULE_MAX - 1;
+	info->max_queue_id = QDSP_MAX_NUM_QUEUES;
+	info->max_image_id = 2;
+	info->queue_offset = qdsp_queue_offset_table;
+	info->task_to_module = qdsp_task_to_module;
+
+	info->module_count = ARRAY_SIZE(module_info);
+	info->module = module_info;
+	return 0;
+}
diff --git a/arch/arm/mach-msm/qdsp5/adsp_jpeg_patch_event.c b/arch/arm/mach-msm/qdsp5/adsp_jpeg_patch_event.c
new file mode 100644
index 0000000..8fb2e06
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/adsp_jpeg_patch_event.c
@@ -0,0 +1,39 @@
+/* arch/arm/mach-msm/qdsp5/adsp_jpeg_patch_event.c
+ *
+ * Verification code for aDSP JPEG events.
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2008-2009, Code Aurora Forum. 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.
+ *
+ */
+
+#include <mach/qdsp5/qdsp5jpegmsg.h>
+#include "adsp.h"
+
+int adsp_jpeg_patch_event(struct msm_adsp_module *module,
+			struct adsp_event *event)
+{
+	if (event->msg_id == JPEG_MSG_ENC_OP_PRODUCED) {
+		jpeg_msg_enc_op_produced *op = (jpeg_msg_enc_op_produced *)event->data.msg16;
+		return adsp_pmem_paddr_fixup(module, (void **)&op->op_buf_addr);
+	}
+	if (event->msg_id == JPEG_MSG_DEC_OP_PRODUCED) {
+		jpeg_msg_dec_op_produced *op = (jpeg_msg_dec_op_produced *)
+			event->data.msg16;
+		return adsp_pmem_paddr_fixup(module,
+				(void **)&op->luma_op_buf_addr) ||
+			adsp_pmem_paddr_fixup(module,
+				(void **)&op->chroma_op_buf_addr);
+	}
+
+	return 0;
+}
diff --git a/arch/arm/mach-msm/qdsp5/adsp_jpeg_verify_cmd.c b/arch/arm/mach-msm/qdsp5/adsp_jpeg_verify_cmd.c
new file mode 100644
index 0000000..87d5dc3
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/adsp_jpeg_verify_cmd.c
@@ -0,0 +1,201 @@
+/* arch/arm/mach-msm/qdsp5/adsp_jpeg_verify_cmd.c
+ *
+ * Verification code for aDSP JPEG packets from userspace.
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2008-2009, Code Aurora Forum. 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.
+ *
+ */
+
+#include <mach/qdsp5/qdsp5jpegcmdi.h>
+#include "adsp.h"
+#include <mach/debug_mm.h>
+
+static uint32_t dec_fmt;
+
+static inline void get_sizes(jpeg_cmd_enc_cfg *cmd, uint32_t *luma_size,
+			     uint32_t *chroma_size)
+{
+	uint32_t fmt, luma_width, luma_height;
+
+	fmt = cmd->process_cfg & JPEG_CMD_ENC_PROCESS_CFG_IP_DATA_FORMAT_M;
+	luma_width = (cmd->ip_size_cfg & JPEG_CMD_IP_SIZE_CFG_LUMA_WIDTH_M)
+		      >> 16;
+	luma_height = cmd->frag_cfg & JPEG_CMD_FRAG_SIZE_LUMA_HEIGHT_M;
+	*luma_size = luma_width * luma_height;
+	if (fmt == JPEG_CMD_ENC_PROCESS_CFG_IP_DATA_FORMAT_H2V2)
+		*chroma_size = *luma_size/2;
+	else
+		*chroma_size = *luma_size;
+}
+
+static inline int verify_jpeg_cmd_enc_cfg(struct msm_adsp_module *module,
+                             		  void *cmd_data, size_t cmd_size)
+{
+	jpeg_cmd_enc_cfg *cmd = (jpeg_cmd_enc_cfg *)cmd_data;
+	uint32_t luma_size, chroma_size;
+	int i, num_frags;
+
+	if (cmd_size != sizeof(jpeg_cmd_enc_cfg)) {
+		MM_ERR("module %s: JPEG ENC CFG invalid \
+			cmd_size %d\n", module->name, cmd_size);
+		return -1;
+	}
+
+	get_sizes(cmd, &luma_size, &chroma_size);
+	num_frags = (cmd->process_cfg >> 10) & 0xf;
+	num_frags = ((num_frags == 1) ? num_frags : num_frags * 2);
+	for (i = 0; i < num_frags; i += 2) {
+		if (adsp_pmem_fixup(module, (void **)(&cmd->frag_cfg_part[i]), luma_size) ||
+		    adsp_pmem_fixup(module, (void **)(&cmd->frag_cfg_part[i+1]), chroma_size))
+			return -1;
+	}
+
+	if (adsp_pmem_fixup(module, (void **)&cmd->op_buf_0_cfg_part1,
+			    cmd->op_buf_0_cfg_part2) ||
+	    adsp_pmem_fixup(module, (void **)&cmd->op_buf_1_cfg_part1,
+			    cmd->op_buf_1_cfg_part2))
+		return -1;
+	return 0;
+}
+
+static inline int verify_jpeg_cmd_dec_cfg(struct msm_adsp_module *module,
+					  void *cmd_data, size_t cmd_size)
+{
+	jpeg_cmd_dec_cfg *cmd = (jpeg_cmd_dec_cfg *)cmd_data;
+	uint32_t div;
+
+	if (cmd_size != sizeof(jpeg_cmd_dec_cfg)) {
+		MM_ERR("module %s: JPEG DEC CFG invalid \
+			cmd_size %d\n", module->name, cmd_size);
+		return -1;
+	}
+
+	if (adsp_pmem_fixup(module, (void **)&cmd->ip_stream_buf_cfg_part1,
+			    cmd->ip_stream_buf_cfg_part2) ||
+	    adsp_pmem_fixup(module, (void **)&cmd->op_stream_buf_0_cfg_part1,
+			    cmd->op_stream_buf_0_cfg_part2) ||
+	    adsp_pmem_fixup(module, (void **)&cmd->op_stream_buf_1_cfg_part1,
+			    cmd->op_stream_buf_1_cfg_part2))
+		return -1;
+	dec_fmt = cmd->op_data_format &
+		JPEG_CMD_DEC_OP_DATA_FORMAT_M;
+	div = (dec_fmt == JPEG_CMD_DEC_OP_DATA_FORMAT_H2V2) ? 2 : 1;
+	if (adsp_pmem_fixup(module, (void **)&cmd->op_stream_buf_0_cfg_part3,
+			    cmd->op_stream_buf_0_cfg_part2 / div) ||
+	    adsp_pmem_fixup(module, (void **)&cmd->op_stream_buf_1_cfg_part3,
+			    cmd->op_stream_buf_1_cfg_part2 / div))
+		return -1;
+	return 0;
+}
+
+static int verify_jpeg_cfg_cmd(struct msm_adsp_module *module,
+			       void *cmd_data, size_t cmd_size)
+{
+	uint32_t cmd_id = ((uint32_t *)cmd_data)[0];
+	switch(cmd_id) {
+	case JPEG_CMD_ENC_CFG:
+		return verify_jpeg_cmd_enc_cfg(module, cmd_data, cmd_size);
+	case JPEG_CMD_DEC_CFG:
+		return verify_jpeg_cmd_dec_cfg(module, cmd_data, cmd_size);
+	default:
+		if (cmd_id > 1) {
+			MM_ERR("module %s: invalid JPEG CFG cmd_id %d\n",
+					module->name, cmd_id);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static int verify_jpeg_action_cmd(struct msm_adsp_module *module,
+				  void *cmd_data, size_t cmd_size)
+{
+	uint32_t cmd_id = ((uint32_t *)cmd_data)[0];
+	switch (cmd_id) {
+	case JPEG_CMD_ENC_OP_CONSUMED:
+	{
+		jpeg_cmd_enc_op_consumed *cmd =
+			(jpeg_cmd_enc_op_consumed *)cmd_data;
+
+		if (cmd_size != sizeof(jpeg_cmd_enc_op_consumed)) {
+			MM_ERR("module %s: JPEG_CMD_ENC_OP_CONSUMED \
+				invalid size %d\n", module->name, cmd_size);
+			return -1;
+		}
+
+		if (adsp_pmem_fixup(module, (void **)&cmd->op_buf_addr,
+				    cmd->op_buf_size))
+			return -1;
+	}
+	break;
+	case JPEG_CMD_DEC_OP_CONSUMED:
+	{
+		uint32_t div;
+		jpeg_cmd_dec_op_consumed *cmd =
+			(jpeg_cmd_dec_op_consumed *)cmd_data;
+
+		if (cmd_size != sizeof(jpeg_cmd_dec_op_consumed)) {
+			MM_ERR("module %s: JPEG_CMD_DEC_OP_CONSUMED \
+				invalid size %d\n", module->name, cmd_size);
+			return -1;
+		}
+
+		div = (dec_fmt == JPEG_CMD_DEC_OP_DATA_FORMAT_H2V2) ?  2 : 1;
+		if (adsp_pmem_fixup(module, (void **)&cmd->luma_op_buf_addr,
+				    cmd->luma_op_buf_size) ||
+		    adsp_pmem_fixup(module, (void **)&cmd->chroma_op_buf_addr,
+				    cmd->luma_op_buf_size / div))
+			return -1;
+	}
+	break;
+
+	case JPEG_CMD_DEC_IP:
+	{
+		jpeg_cmd_dec_ip *cmd =
+			(jpeg_cmd_dec_ip *)cmd_data;
+
+		if (cmd_size != sizeof(jpeg_cmd_dec_ip)) {
+			MM_ERR("module %s: JPEG_CMD_DEC_IP invalid \
+				size %d\n", module->name, cmd_size);
+			return -1;
+		}
+		if (adsp_pmem_fixup(module, (void **)&cmd->ip_buf_addr,
+			cmd->ip_buf_size))
+			return -1;
+	}
+	break;
+
+	default:
+		if (cmd_id > 7) {
+			MM_ERR("module %s: invalid cmd_id %d\n",
+				module->name, cmd_id);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+int adsp_jpeg_verify_cmd(struct msm_adsp_module *module,
+			 unsigned int queue_id, void *cmd_data,
+			 size_t cmd_size)
+{
+	switch(queue_id) {
+	case QDSP_uPJpegCfgCmdQueue:
+		return verify_jpeg_cfg_cmd(module, cmd_data, cmd_size);
+	case QDSP_uPJpegActionCmdQueue:
+		return verify_jpeg_action_cmd(module, cmd_data, cmd_size);
+	default:
+		return -1;
+	}
+}
+
diff --git a/arch/arm/mach-msm/qdsp5/adsp_lpm_verify_cmd.c b/arch/arm/mach-msm/qdsp5/adsp_lpm_verify_cmd.c
new file mode 100644
index 0000000..06b70de
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/adsp_lpm_verify_cmd.c
@@ -0,0 +1,66 @@
+/* arch/arm/mach-msm/qdsp5/adsp_lpm_verify_cmd.c
+ *
+ * Verificion code for aDSP LPM packets from userspace.
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2008-2009, Code Aurora Forum. 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.
+ *
+ */
+
+#include <mach/qdsp5/qdsp5lpmcmdi.h>
+#include "adsp.h"
+#include <mach/debug_mm.h>
+
+int adsp_lpm_verify_cmd(struct msm_adsp_module *module,
+			 unsigned int queue_id, void *cmd_data,
+			 size_t cmd_size)
+{
+	uint32_t cmd_id, col_height, input_row_incr, output_row_incr,
+		input_size, output_size;
+	uint32_t size_mask = 0x0fff;
+	lpm_cmd_start *cmd;
+
+	if (queue_id != QDSP_lpmCommandQueue) {
+		MM_ERR("module %s: wrong queue id %d\n",
+				module->name, queue_id);
+		return -1;
+	}
+
+	cmd = (lpm_cmd_start *)cmd_data;
+	cmd_id = cmd->cmd_id;
+
+	if (cmd_id == LPM_CMD_START) {
+		if (cmd_size != sizeof(lpm_cmd_start)) {
+			MM_ERR("module %s: wrong size %d, \
+				expect %d\n", module->name,
+				cmd_size, sizeof(lpm_cmd_start));
+			return -1;
+		}
+		col_height = cmd->ip_data_cfg_part1 & size_mask;
+		input_row_incr = cmd->ip_data_cfg_part2 & size_mask;
+		output_row_incr = cmd->op_data_cfg_part1 & size_mask;
+		input_size = col_height * input_row_incr;
+		output_size = col_height * output_row_incr;
+		if ((cmd->ip_data_cfg_part4 && adsp_pmem_fixup(module,
+				    (void **)(&cmd->ip_data_cfg_part4),
+				    input_size)) ||
+		   (cmd->op_data_cfg_part3 && adsp_pmem_fixup(module,
+				    (void **)(&cmd->op_data_cfg_part3),
+				    output_size)))
+			return -1;
+	} else if (cmd_id > 1) {
+		MM_ERR("module %s: invalid cmd_id %d\n", module->name, cmd_id);
+		return -1;
+	}
+	return 0;
+}
+
diff --git a/arch/arm/mach-msm/qdsp5/adsp_rm.c b/arch/arm/mach-msm/qdsp5/adsp_rm.c
new file mode 100644
index 0000000..81147f7
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/adsp_rm.c
@@ -0,0 +1,193 @@
+/* Copyright (c) 2010, 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/cdev.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/msm_adsp.h>
+#include <linux/module.h>
+
+#include <mach/qdsp5/qdsp5rmtcmdi.h>
+#include <mach/qdsp5/qdsp5rmtmsg.h>
+#include <mach/debug_mm.h>
+#include "adsp.h"
+
+#define MAX_CLIENTS		5
+#define MAX_AUDIO_CLIENTS	5
+#define MAX_RM_CLIENTS		MAX_AUDIO_CLIENTS
+
+static char *rm_errs[] = {
+			"",
+			"PCM Blocks not Sufficient",
+			"TASK is already occupied",
+			"Concurrency not supported",
+			"MIPS not sufficient"
+			};
+static struct client {
+	wait_queue_head_t		wait;
+	unsigned int			wait_state;
+	struct aud_codec_config_ack	cfg_msg;
+} rmclient[MAX_RM_CLIENTS];
+
+static struct rm {
+	struct msm_adsp_module		*mod;
+	int				cnt;
+	int				state;
+
+	struct aud_codec_config_ack	cfg_msg;
+	struct mutex			lock;
+} rmtask;
+
+static void rm_dsp_event(void *data, unsigned id, size_t len,
+			void (*getevent) (void *ptr, size_t len));
+static struct msm_adsp_ops rm_ops = {
+	.event = rm_dsp_event,
+};
+
+int32_t get_adsp_resource(unsigned short client_id,
+				void *cmd_buf, size_t cmd_size)
+{
+	int rc = 0;
+	int client_idx;
+
+	client_idx = ((client_id >> 8) * MAX_CLIENTS) + (client_id & 0xFF);
+	if (client_idx >= MAX_RM_CLIENTS)
+		return -EINVAL;
+
+	mutex_lock(&rmtask.lock);
+	if (rmtask.state != ADSP_STATE_ENABLED) {
+		rc = msm_adsp_get("RMTASK", &rmtask.mod, &rm_ops, NULL);
+		if (rc) {
+			MM_ERR("Failed to get module RMTASK\n");
+			mutex_unlock(&rmtask.lock);
+			return rc;
+		}
+		rc = msm_adsp_enable(rmtask.mod);
+		if (rc) {
+			MM_ERR("RMTASK enable Failed\n");
+			msm_adsp_put(rmtask.mod);
+			mutex_unlock(&rmtask.lock);
+			return rc;
+		}
+		rmtask.state = ADSP_STATE_ENABLED;
+	}
+	rmclient[client_idx].wait_state = -1;
+	mutex_unlock(&rmtask.lock);
+	msm_adsp_write(rmtask.mod, QDSP_apuRmtQueue, cmd_buf, cmd_size);
+	rc = wait_event_interruptible_timeout(rmclient[client_idx].wait,
+			rmclient[client_idx].wait_state != -1, 5 * HZ);
+	mutex_lock(&rmtask.lock);
+	if (unlikely(rc < 0)) {
+		if (rc == -ERESTARTSYS)
+			MM_ERR("wait_event_interruptible "
+					"returned -ERESTARTSYS\n");
+		else
+			MM_ERR("wait_event_interruptible "
+					"returned error\n");
+		if (!rmtask.cnt)
+			goto disable_rm;
+		goto unlock;
+	} else if (rc == 0) {
+		MM_ERR("RMTASK Msg not received\n");
+		rc = -ETIMEDOUT;
+		if (!rmtask.cnt)
+			goto disable_rm;
+		goto unlock;
+	}
+	if (!(rmclient[client_idx].cfg_msg.enable)) {
+		MM_ERR("Reason for failure: %s\n",
+			rm_errs[rmclient[client_idx].cfg_msg.reason]);
+		rc = -EBUSY;
+		if (!rmtask.cnt)
+			goto disable_rm;
+		goto unlock;
+	}
+	rmtask.cnt++;
+	mutex_unlock(&rmtask.lock);
+	return 0;
+
+disable_rm:
+	msm_adsp_disable(rmtask.mod);
+	msm_adsp_put(rmtask.mod);
+	rmtask.state = ADSP_STATE_DISABLED;
+unlock:
+	mutex_unlock(&rmtask.lock);
+	return rc;
+}
+EXPORT_SYMBOL(get_adsp_resource);
+
+int32_t put_adsp_resource(unsigned short client_id, void *cmd_buf,
+							size_t cmd_size)
+{
+	mutex_lock(&rmtask.lock);
+	if (rmtask.state != ADSP_STATE_ENABLED) {
+		mutex_unlock(&rmtask.lock);
+		return 0;
+	}
+
+	msm_adsp_write(rmtask.mod, QDSP_apuRmtQueue, cmd_buf, cmd_size);
+	rmtask.cnt--;
+	if (!rmtask.cnt) {
+		msm_adsp_disable(rmtask.mod);
+		msm_adsp_put(rmtask.mod);
+		rmtask.state = ADSP_STATE_DISABLED;
+	}
+	mutex_unlock(&rmtask.lock);
+	return 0;
+}
+EXPORT_SYMBOL(put_adsp_resource);
+
+static void rm_dsp_event(void *data, unsigned id, size_t len,
+				void (*getevent) (void *ptr, size_t len))
+{
+	unsigned short client_id;
+	int client_idx;
+
+	MM_DBG("Msg ID = %d\n", id);
+
+	switch (id) {
+	case RMT_CODEC_CONFIG_ACK: {
+		getevent(&rmtask.cfg_msg, sizeof(rmtask.cfg_msg));
+		client_id = ((rmtask.cfg_msg.client_id << 8) |
+						rmtask.cfg_msg.task_id);
+		client_idx = ((client_id >> 8) * MAX_CLIENTS) +
+						(client_id & 0xFF);
+		memcpy(&rmclient[client_idx].cfg_msg, &rmtask.cfg_msg,
+							sizeof(rmtask.cfg_msg));
+		rmclient[client_idx].wait_state = 1;
+		wake_up(&rmclient[client_idx].wait);
+		break;
+	}
+	case RMT_DSP_OUT_OF_MIPS: {
+		struct rmt_dsp_out_of_mips msg;
+		getevent(&msg, sizeof(msg));
+		MM_ERR("RMT_DSP_OUT_OF_MIPS: Not enough resorces in ADSP \
+				to handle all sessions :%hx\n", msg.dec_info);
+		break;
+	}
+	default:
+		MM_DBG("Unknown Msg Id\n");
+		break;
+	}
+}
+
+void rmtask_init(void)
+{
+	int i;
+
+	for (i = 0; i < MAX_RM_CLIENTS; i++)
+		init_waitqueue_head(&rmclient[i].wait);
+	mutex_init(&rmtask.lock);
+}
diff --git a/arch/arm/mach-msm/qdsp5/adsp_vfe_patch_event.c b/arch/arm/mach-msm/qdsp5/adsp_vfe_patch_event.c
new file mode 100644
index 0000000..68ae380
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/adsp_vfe_patch_event.c
@@ -0,0 +1,54 @@
+/* arch/arm/mach-msm/qdsp5/adsp_vfe_patch_event.c
+ *
+ * Verification code for aDSP VFE packets from userspace.
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2008-2009, Code Aurora Forum. 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.
+ *
+ */
+
+#include <mach/qdsp5/qdsp5vfemsg.h>
+#include "adsp.h"
+
+static int patch_op_event(struct msm_adsp_module *module,
+				struct adsp_event *event)
+{
+	vfe_msg_op1 *op = (vfe_msg_op1 *)event->data.msg16;
+	if (adsp_pmem_paddr_fixup(module, (void **)&op->op1_buf_y_addr) ||
+	    adsp_pmem_paddr_fixup(module, (void **)&op->op1_buf_cbcr_addr))
+		return -1;
+	return 0;
+}
+
+static int patch_af_wb_event(struct msm_adsp_module *module,
+				struct adsp_event *event)
+{
+	vfe_msg_stats_wb_exp *af = (vfe_msg_stats_wb_exp *)event->data.msg16;
+	return adsp_pmem_paddr_fixup(module, (void **)&af->wb_exp_stats_op_buf);
+}
+
+int adsp_vfe_patch_event(struct msm_adsp_module *module,
+			struct adsp_event *event)
+{
+	switch(event->msg_id) {
+	case VFE_MSG_OP1:
+	case VFE_MSG_OP2:
+		return patch_op_event(module, event);
+	case VFE_MSG_STATS_AF:
+	case VFE_MSG_STATS_WB_EXP:	
+		return patch_af_wb_event(module, event);
+	default:
+		break;
+	}
+
+	return 0;
+}
diff --git a/arch/arm/mach-msm/qdsp5/adsp_vfe_verify_cmd.c b/arch/arm/mach-msm/qdsp5/adsp_vfe_verify_cmd.c
new file mode 100644
index 0000000..dcd3d96
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/adsp_vfe_verify_cmd.c
@@ -0,0 +1,244 @@
+/* arch/arm/mach-msm/qdsp5/adsp_vfe_verify_cmd.c
+ *
+ * Verification code for aDSP VFE packets from userspace.
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2008-2009, Code Aurora Forum. 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.
+ *
+ */
+
+#include <mach/qdsp5/qdsp5vfecmdi.h>
+#include "adsp.h"
+#include <mach/debug_mm.h>
+
+static uint32_t size1_y, size2_y, size1_cbcr, size2_cbcr;
+static uint32_t af_size = 4228;
+static uint32_t awb_size = 8196;
+
+static inline int verify_cmd_op_ack(struct msm_adsp_module *module,
+				    void *cmd_data, size_t cmd_size)
+{
+	vfe_cmd_op1_ack *cmd = (vfe_cmd_op1_ack *)cmd_data;
+	void **addr_y = (void **)&cmd->op1_buf_y_addr;
+	void **addr_cbcr = (void **)(&cmd->op1_buf_cbcr_addr);
+
+	if (cmd_size != sizeof(vfe_cmd_op1_ack))
+		return -1;
+	if ((*addr_y && adsp_pmem_fixup(module, addr_y, size1_y)) ||
+	    (*addr_cbcr && adsp_pmem_fixup(module, addr_cbcr, size1_cbcr)))
+		return -1;
+	return 0;
+}
+
+static inline int verify_cmd_stats_autofocus_cfg(struct msm_adsp_module *module,
+						 void *cmd_data, size_t cmd_size)
+{
+	int i;
+	vfe_cmd_stats_autofocus_cfg *cmd =
+		(vfe_cmd_stats_autofocus_cfg *)cmd_data;
+
+	if (cmd_size != sizeof(vfe_cmd_stats_autofocus_cfg))
+		return -1;
+
+	for (i = 0; i < 3; i++) {
+		void **addr = (void **)(&cmd->af_stats_op_buf[i]);
+		if (*addr && adsp_pmem_fixup(module, addr, af_size))
+			return -1;
+	}
+	return 0;
+}
+
+static inline int verify_cmd_stats_wb_exp_cfg(struct msm_adsp_module *module,
+					      void *cmd_data, size_t cmd_size)
+{
+	vfe_cmd_stats_wb_exp_cfg *cmd =
+		(vfe_cmd_stats_wb_exp_cfg *)cmd_data;
+	int i;
+
+	if (cmd_size != sizeof(vfe_cmd_stats_wb_exp_cfg))
+		return -1;
+
+	for (i = 0; i < 3; i++) {
+		void **addr = (void **)(&cmd->wb_exp_stats_op_buf[i]);
+		if (*addr && adsp_pmem_fixup(module, addr, awb_size))
+			return -1;
+	}
+	return 0;
+}
+
+static inline int verify_cmd_stats_af_ack(struct msm_adsp_module *module,
+					  void *cmd_data, size_t cmd_size)
+{
+	vfe_cmd_stats_af_ack *cmd = (vfe_cmd_stats_af_ack *)cmd_data;
+	void **addr = (void **)&cmd->af_stats_op_buf;
+
+	if (cmd_size != sizeof(vfe_cmd_stats_af_ack))
+		return -1;
+
+	if (*addr && adsp_pmem_fixup(module, addr, af_size))
+		return -1;
+	return 0;
+}
+
+static inline int verify_cmd_stats_wb_exp_ack(struct msm_adsp_module *module,
+					      void *cmd_data, size_t cmd_size)
+{
+	vfe_cmd_stats_wb_exp_ack *cmd =
+		(vfe_cmd_stats_wb_exp_ack *)cmd_data;
+	void **addr = (void **)&cmd->wb_exp_stats_op_buf;
+
+	if (cmd_size != sizeof(vfe_cmd_stats_wb_exp_ack))
+		return -1;
+
+	if (*addr && adsp_pmem_fixup(module, addr, awb_size))
+		return -1;
+	return 0;
+}
+
+static int verify_vfe_command(struct msm_adsp_module *module,
+			      void *cmd_data, size_t cmd_size)
+{
+	uint32_t cmd_id = ((uint32_t *)cmd_data)[0];
+	switch (cmd_id) {
+	case VFE_CMD_OP1_ACK:
+		return verify_cmd_op_ack(module, cmd_data, cmd_size);
+	case VFE_CMD_OP2_ACK:
+		return verify_cmd_op_ack(module, cmd_data, cmd_size);
+	case VFE_CMD_STATS_AUTOFOCUS_CFG:
+		return verify_cmd_stats_autofocus_cfg(module, cmd_data,
+						      cmd_size);
+	case VFE_CMD_STATS_WB_EXP_CFG:
+		return verify_cmd_stats_wb_exp_cfg(module, cmd_data, cmd_size);
+	case VFE_CMD_STATS_AF_ACK:
+		return verify_cmd_stats_af_ack(module, cmd_data, cmd_size);
+	case VFE_CMD_STATS_WB_EXP_ACK:
+		return verify_cmd_stats_wb_exp_ack(module, cmd_data, cmd_size);
+	default:
+		if (cmd_id > 29) {
+			MM_ERR("module %s: invalid VFE command id %d\n",
+					module->name, cmd_id);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static int verify_vfe_command_scale(struct msm_adsp_module *module,
+				    void *cmd_data, size_t cmd_size)
+{
+	uint32_t cmd_id = ((uint32_t *)cmd_data)[0];
+	// FIXME: check the size
+	if (cmd_id > 1) {
+		MM_ERR("module %s: invalid VFE SCALE command id %d\n",
+				module->name, cmd_id);
+		return -1;
+	}
+	return 0;
+}
+
+
+static uint32_t get_size(uint32_t hw)
+{
+	uint32_t height, width;
+	uint32_t height_mask = 0x3ffc;
+	uint32_t width_mask = 0x3ffc000;
+
+	height = (hw & height_mask) >> 2;
+	width = (hw & width_mask) >> 14 ;
+	return height * width;
+}
+
+static int verify_vfe_command_table(struct msm_adsp_module *module,
+				    void *cmd_data, size_t cmd_size)
+{
+	uint32_t cmd_id = ((uint32_t *)cmd_data)[0];
+	int i;
+
+	switch (cmd_id) {
+	case VFE_CMD_AXI_IP_CFG:
+	{
+		vfe_cmd_axi_ip_cfg *cmd = (vfe_cmd_axi_ip_cfg *)cmd_data;
+		uint32_t size;
+		if (cmd_size != sizeof(vfe_cmd_axi_ip_cfg)) {
+			MM_ERR("module %s: invalid VFE TABLE \
+				(VFE_CMD_AXI_IP_CFG) command size %d\n",
+				module->name, cmd_size);
+			return -1;
+		}
+		size = get_size(cmd->ip_cfg_part2);
+
+		for (i = 0; i < 8; i++) {
+			void **addr = (void **)
+				&cmd->ip_buf_addr[i];
+			if (*addr && adsp_pmem_fixup(module, addr, size))
+				return -1;
+		}
+	}
+	case VFE_CMD_AXI_OP_CFG:
+	{
+		vfe_cmd_axi_op_cfg *cmd = (vfe_cmd_axi_op_cfg *)cmd_data;
+		void **addr1_y, **addr2_y, **addr1_cbcr, **addr2_cbcr;
+
+		if (cmd_size != sizeof(vfe_cmd_axi_op_cfg)) { 
+			MM_ERR("module %s: invalid VFE TABLE \
+				(VFE_CMD_AXI_OP_CFG) command size %d\n",
+				module->name, cmd_size);
+			return -1;
+		}
+		size1_y = get_size(cmd->op1_y_cfg_part2);
+		size1_cbcr = get_size(cmd->op1_cbcr_cfg_part2);
+		size2_y = get_size(cmd->op2_y_cfg_part2);
+		size2_cbcr = get_size(cmd->op2_cbcr_cfg_part2);
+		for (i = 0; i < 8; i++) {
+			addr1_y = (void **)(&cmd->op1_buf1_addr[2*i]);
+			addr1_cbcr = (void **)(&cmd->op1_buf1_addr[2*i+1]);
+			addr2_y = (void **)(&cmd->op2_buf1_addr[2*i]);
+			addr2_cbcr = (void **)(&cmd->op2_buf1_addr[2*i+1]);
+/*
+			printk("module %s: [%d] %p %p %p %p\n",
+				module->name, i,
+				*addr1_y, *addr1_cbcr, *addr2_y, *addr2_cbcr);
+*/
+			if ((*addr1_y && adsp_pmem_fixup(module, addr1_y, size1_y)) ||
+			    (*addr1_cbcr && adsp_pmem_fixup(module, addr1_cbcr, size1_cbcr)) ||
+			    (*addr2_y && adsp_pmem_fixup(module, addr2_y, size2_y)) ||
+			    (*addr2_cbcr && adsp_pmem_fixup(module, addr2_cbcr, size2_cbcr)))
+				return -1;
+		}
+	}
+	default:
+		if (cmd_id > 4) {
+			MM_ERR("module %s: invalid VFE TABLE command \
+				id %d\n", module->name, cmd_id);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+int adsp_vfe_verify_cmd(struct msm_adsp_module *module,
+			unsigned int queue_id, void *cmd_data,
+			size_t cmd_size)
+{
+	switch (queue_id) {
+	case QDSP_vfeCommandQueue:
+		return verify_vfe_command(module, cmd_data, cmd_size);
+	case QDSP_vfeCommandScaleQueue:
+		return verify_vfe_command_scale(module, cmd_data, cmd_size);
+	case QDSP_vfeCommandTableQueue:
+		return verify_vfe_command_table(module, cmd_data, cmd_size);
+	default:
+		MM_ERR("module %s: unknown queue id %d\n",
+			 module->name, queue_id);
+		return -1;
+	}
+}
diff --git a/arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c b/arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c
new file mode 100644
index 0000000..492fa0e
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c
@@ -0,0 +1,272 @@
+/* arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c
+ *
+ * Verificion code for aDSP VDEC packets from userspace.
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2008-2010, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/android_pmem.h>
+
+#include <mach/qdsp5/qdsp5vdeccmdi.h>
+#include "adsp.h"
+#include <mach/debug_mm.h>
+
+#define MAX_FLUSH_SIZE 160
+
+static inline void *high_low_short_to_ptr(unsigned short high,
+					  unsigned short low)
+{
+	return (void *)((((unsigned long)high) << 16) | ((unsigned long)low));
+}
+
+static inline void ptr_to_high_low_short(void *ptr, unsigned short *high,
+					 unsigned short *low)
+{
+	*high = (unsigned short)((((unsigned long)ptr) >> 16) & 0xffff);
+	*low = (unsigned short)((unsigned long)ptr & 0xffff);
+}
+
+static int pmem_fixup_high_low(unsigned short *high,
+				unsigned short *low,
+				unsigned short size_high,
+				unsigned short size_low,
+				struct msm_adsp_module *module,
+				unsigned long *addr, unsigned long *size,
+				struct file **filp, unsigned long *offset)
+{
+	void *phys_addr;
+	unsigned long phys_size;
+	unsigned long kvaddr;
+
+	phys_addr = high_low_short_to_ptr(*high, *low);
+	phys_size = (unsigned long)high_low_short_to_ptr(size_high, size_low);
+	MM_DBG("virt %x %x\n", (unsigned int)phys_addr,
+			(unsigned int)phys_size);
+	if (phys_addr) {
+		if (adsp_pmem_fixup_kvaddr(module, &phys_addr,
+			 &kvaddr, phys_size, filp, offset)) {
+			MM_ERR("ah%x al%x sh%x sl%x addr %x size %x\n",
+					*high, *low, size_high,
+					size_low, (unsigned int)phys_addr,
+					(unsigned int)phys_size);
+			return -EINVAL;
+		}
+	}
+	ptr_to_high_low_short(phys_addr, high, low);
+	MM_DBG("phys %x %x\n", (unsigned int)phys_addr,
+			(unsigned int)phys_size);
+	if (addr)
+		*addr = kvaddr;
+	if (size)
+		*size = phys_size;
+	return 0;
+}
+
+static int verify_vdec_pkt_cmd(struct msm_adsp_module *module,
+			       void *cmd_data, size_t cmd_size)
+{
+	unsigned short cmd_id = ((unsigned short *)cmd_data)[0];
+	viddec_cmd_subframe_pkt *pkt;
+	unsigned long subframe_pkt_addr;
+	unsigned long subframe_pkt_size;
+	unsigned short *frame_header_pkt;
+	int i, num_addr, col_addr = 0, skip;
+	int start_pos = 0, xdim_pos = 1, ydim_pos = 2;
+	unsigned short *frame_buffer_high, *frame_buffer_low;
+	unsigned long frame_buffer_size;
+	unsigned short frame_buffer_size_high, frame_buffer_size_low;
+	struct file *filp = NULL;
+	unsigned long offset = 0;
+	struct pmem_addr pmem_addr;
+	unsigned long Codec_Id = 0;
+
+	MM_DBG("cmd_size %d cmd_id %d cmd_data %x\n", cmd_size, cmd_id,
+					(unsigned int)cmd_data);
+	if (cmd_id != VIDDEC_CMD_SUBFRAME_PKT) {
+		MM_INFO("adsp_video: unknown video packet %u\n", cmd_id);
+		return 0;
+	}
+	if (cmd_size < sizeof(viddec_cmd_subframe_pkt))
+		return -1;
+
+	pkt = (viddec_cmd_subframe_pkt *)cmd_data;
+
+	if (pmem_fixup_high_low(&(pkt->subframe_packet_high),
+				&(pkt->subframe_packet_low),
+				pkt->subframe_packet_size_high,
+				pkt->subframe_packet_size_low,
+				module,
+				&subframe_pkt_addr,
+				&subframe_pkt_size,
+				&filp, &offset))
+		return -1;
+	Codec_Id = pkt->codec_selection_word;
+	/*Invalidate cache before accessing the cached pmem buffer*/
+	if (filp) {
+		pmem_addr.vaddr = subframe_pkt_addr;
+		pmem_addr.length = (((subframe_pkt_size*2) + 31) & (~31)) + 32;
+		pmem_addr.offset = offset;
+		if (pmem_cache_maint (filp, PMEM_INV_CACHES,  &pmem_addr)) {
+			MM_ERR("Cache operation failed for phys addr high %x"
+				" addr low %x\n", pkt->subframe_packet_high,
+				pkt->subframe_packet_low);
+			return -EINVAL;
+		}
+	}
+	/* deref those ptrs and check if they are a frame header packet */
+	frame_header_pkt = (unsigned short *)subframe_pkt_addr;
+	switch (frame_header_pkt[0]) {
+	case 0xB201: /* h.264 vld in dsp */
+	   if (Codec_Id == 0x8) {
+		num_addr = 16;
+		skip = 0;
+		start_pos = 5;
+	   } else {
+	       num_addr = 16;
+	       skip = 0;
+	       start_pos = 6;
+	       col_addr = 17;
+	   }
+		break;
+	case 0x8201: /* h.264 vld in arm */
+		num_addr = 16;
+		skip = 0;
+		start_pos = 6;
+		break;
+	case 0x4D01: /* mpeg-4 and h.263 vld in arm */
+		num_addr = 3;
+		skip = 0;
+		start_pos = 5;
+		break;
+	case 0x9201: /*For Real Decoder*/
+		num_addr = 2;
+		skip = 0;
+		start_pos = 5;
+		break;
+	case 0xBD01: /* mpeg-4 and h.263 vld in dsp */
+		num_addr = 3;
+		skip = 0;
+		start_pos = 6;
+		if (((frame_header_pkt[5] & 0x000c) >> 2) == 0x2) /* B-frame */
+			start_pos = 8;
+		break;
+	case 0x0001: /* wmv */
+		num_addr = 2;
+		skip = 0;
+		start_pos = 5;
+		break;
+	case 0xC201: /*WMV main profile*/
+		 num_addr = 3;
+		 skip = 0;
+		 start_pos = 6;
+		 break;
+	case 0xDD01: /* VP6 */
+		num_addr = 3;
+		skip = 0;
+		start_pos = 10;
+		break;
+	case 0xFD01: /* VP8 */
+		num_addr = 3;
+		skip = 0;
+		start_pos = 24;
+		break;
+	default:
+		return 0;
+	}
+
+	frame_buffer_high = &frame_header_pkt[start_pos];
+	frame_buffer_low = &frame_header_pkt[start_pos + 1];
+	frame_buffer_size = (frame_header_pkt[xdim_pos] *
+			     frame_header_pkt[ydim_pos] * 3) / 2;
+	ptr_to_high_low_short((void *)frame_buffer_size,
+			      &frame_buffer_size_high,
+			      &frame_buffer_size_low);
+	for (i = 0; i < num_addr; i++) {
+		if (frame_buffer_high && frame_buffer_low) {
+			if (pmem_fixup_high_low(frame_buffer_high,
+						frame_buffer_low,
+						frame_buffer_size_high,
+						frame_buffer_size_low,
+						module,
+						NULL, NULL, NULL, NULL))
+				return -EINVAL;
+	   }
+		frame_buffer_high += 2;
+		frame_buffer_low += 2;
+	}
+	/* Patch the output buffer. */
+	frame_buffer_high += 2*skip;
+	frame_buffer_low += 2*skip;
+	if (frame_buffer_high && frame_buffer_low) {
+		if (pmem_fixup_high_low(frame_buffer_high,
+					frame_buffer_low,
+					frame_buffer_size_high,
+					frame_buffer_size_low,
+					module,
+					NULL, NULL, NULL, NULL))
+			return -EINVAL;
+	}
+	if (col_addr) {
+		frame_buffer_high += 2;
+		frame_buffer_low += 2;
+		/* Patch the Co-located buffers.*/
+		frame_buffer_size =  (72 * frame_header_pkt[xdim_pos] *
+					frame_header_pkt[ydim_pos]) >> 16;
+		ptr_to_high_low_short((void *)frame_buffer_size,
+					&frame_buffer_size_high,
+					&frame_buffer_size_low);
+		for (i = 0; i < col_addr; i++) {
+			if (frame_buffer_high && frame_buffer_low) {
+				if (pmem_fixup_high_low(frame_buffer_high,
+						frame_buffer_low,
+						frame_buffer_size_high,
+						frame_buffer_size_low,
+						module,
+						NULL, NULL, NULL, NULL))
+					return -EINVAL;
+			}
+			frame_buffer_high += 2;
+			frame_buffer_low += 2;
+		}
+	}
+	/*Flush the cached pmem subframe packet before sending to DSP*/
+	if (filp) {
+		pmem_addr.vaddr = subframe_pkt_addr;
+		pmem_addr.length = MAX_FLUSH_SIZE;
+		pmem_addr.offset = offset;
+		if (pmem_cache_maint(filp, PMEM_CLEAN_CACHES, &pmem_addr)) {
+			MM_ERR("Cache operation failed for phys addr high %x"
+				" addr low %x\n", pkt->subframe_packet_high,
+				pkt->subframe_packet_low);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+int adsp_video_verify_cmd(struct msm_adsp_module *module,
+			 unsigned int queue_id, void *cmd_data,
+			 size_t cmd_size)
+{
+	switch (queue_id) {
+	case QDSP_mpuVDecPktQueue:
+		return verify_vdec_pkt_cmd(module, cmd_data, cmd_size);
+	default:
+		MM_INFO("unknown video queue %u\n", queue_id);
+		return 0;
+	}
+}
+
diff --git a/arch/arm/mach-msm/qdsp5/adsp_videoenc_verify_cmd.c b/arch/arm/mach-msm/qdsp5/adsp_videoenc_verify_cmd.c
new file mode 100644
index 0000000..936b7af
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/adsp_videoenc_verify_cmd.c
@@ -0,0 +1,235 @@
+/* arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c
+ *
+ * Verificion code for aDSP VENC packets from userspace.
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2008-2009, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/io.h>
+
+#include <mach/qdsp5/qdsp5venccmdi.h>
+#include "adsp.h"
+#include <mach/debug_mm.h>
+
+
+static unsigned short x_dimension, y_dimension;
+
+static inline void *high_low_short_to_ptr(unsigned short high,
+					  unsigned short low)
+{
+	return (void *)((((unsigned long)high) << 16) | ((unsigned long)low));
+}
+
+static inline void ptr_to_high_low_short(void *ptr, unsigned short *high,
+					 unsigned short *low)
+{
+	*high = (unsigned short)((((unsigned long)ptr) >> 16) & 0xffff);
+	*low = (unsigned short)((unsigned long)ptr & 0xffff);
+}
+
+static int pmem_fixup_high_low(unsigned short *high,
+				unsigned short *low,
+				unsigned short size_high,
+				unsigned short size_low,
+				struct msm_adsp_module *module,
+				unsigned long *addr, unsigned long *size)
+{
+	void *phys_addr;
+	unsigned long phys_size;
+	unsigned long kvaddr;
+
+	phys_addr = high_low_short_to_ptr(*high, *low);
+	phys_size = (unsigned long)high_low_short_to_ptr(size_high, size_low);
+	MM_DBG("virt %x %x\n", (unsigned int)phys_addr,
+			(unsigned int)phys_size);
+	if (adsp_pmem_fixup_kvaddr(module, &phys_addr, &kvaddr, phys_size,
+				NULL, NULL)) {
+		MM_ERR("ah%x al%x sh%x sl%x addr %x size %x\n",
+			*high, *low, size_high,
+			size_low, (unsigned int)phys_addr,
+			(unsigned int) phys_size);
+		return -1;
+	}
+	ptr_to_high_low_short(phys_addr, high, low);
+	MM_DBG("phys %x %x\n", (unsigned int)phys_addr,
+			(unsigned int)phys_size);
+	if (addr)
+		*addr = kvaddr;
+	if (size)
+		*size = phys_size;
+	return 0;
+}
+
+static int verify_venc_cmd(struct msm_adsp_module *module,
+			       void *cmd_data, size_t cmd_size)
+{
+	unsigned short cmd_id = ((unsigned short *)cmd_data)[0];
+	unsigned long frame_buf_size, luma_buf_size, chroma_buf_size;
+	unsigned short frame_buf_size_high, frame_buf_size_low;
+	unsigned short luma_buf_size_high, luma_buf_size_low;
+	unsigned short chroma_buf_size_high, chroma_buf_size_low;
+	videnc_cmd_cfg *config_cmd;
+	videnc_cmd_frame_start *frame_cmd;
+	videnc_cmd_dis *dis_cmd;
+
+	MM_DBG("cmd_size %d cmd_id %d cmd_data %x\n",
+		cmd_size, cmd_id, (unsigned int)cmd_data);
+	switch (cmd_id) {
+	case VIDENC_CMD_ACTIVE:
+		if (cmd_size < sizeof(videnc_cmd_active))
+			return -1;
+		break;
+	case VIDENC_CMD_IDLE:
+		if (cmd_size < sizeof(videnc_cmd_idle))
+			return -1;
+		x_dimension = y_dimension = 0;
+		break;
+	case VIDENC_CMD_STATUS_QUERY:
+		if (cmd_size < sizeof(videnc_cmd_status_query))
+			return -1;
+		break;
+	case VIDENC_CMD_RC_CFG:
+		if (cmd_size < sizeof(videnc_cmd_rc_cfg))
+			return -1;
+		break;
+	case VIDENC_CMD_INTRA_REFRESH:
+		if (cmd_size < sizeof(videnc_cmd_intra_refresh))
+			return -1;
+		break;
+	case VIDENC_CMD_DIGITAL_ZOOM:
+		if (cmd_size < sizeof(videnc_cmd_digital_zoom))
+			return -1;
+		break;
+	case VIDENC_CMD_DIS_CFG:
+		if (cmd_size < sizeof(videnc_cmd_dis_cfg))
+			return -1;
+		break;
+	case VIDENC_CMD_VENC_CLOCK:
+		if (cmd_size < sizeof(struct videnc_cmd_venc_clock))
+			return -1;
+		break;
+	case VIDENC_CMD_CFG:
+		if (cmd_size < sizeof(videnc_cmd_cfg))
+			return -1;
+		config_cmd = (videnc_cmd_cfg *)cmd_data;
+		x_dimension = ((config_cmd->venc_frame_dim) & 0xFF00)>>8;
+		x_dimension = x_dimension*16;
+		y_dimension = (config_cmd->venc_frame_dim) & 0xFF;
+		y_dimension = y_dimension * 16;
+		break;
+	case VIDENC_CMD_FRAME_START:
+		if (cmd_size < sizeof(videnc_cmd_frame_start))
+			return -1;
+		frame_cmd = (videnc_cmd_frame_start *)cmd_data;
+		luma_buf_size = x_dimension * y_dimension;
+		chroma_buf_size = luma_buf_size>>1;
+		frame_buf_size = luma_buf_size + chroma_buf_size;
+		ptr_to_high_low_short((void *)luma_buf_size,
+			      &luma_buf_size_high,
+			      &luma_buf_size_low);
+		ptr_to_high_low_short((void *)chroma_buf_size,
+			      &chroma_buf_size_high,
+			      &chroma_buf_size_low);
+		ptr_to_high_low_short((void *)frame_buf_size,
+			      &frame_buf_size_high,
+			      &frame_buf_size_low);
+		/* Address of raw Y data. */
+		if (pmem_fixup_high_low(&frame_cmd->input_luma_addr_high,
+					&frame_cmd->input_luma_addr_low,
+					luma_buf_size_high,
+					luma_buf_size_low,
+					module,
+					NULL, NULL))
+			return -1;
+		/* Address of raw CbCr data */
+		if (pmem_fixup_high_low(&frame_cmd->input_chroma_addr_high,
+					&frame_cmd->input_chroma_addr_low,
+					chroma_buf_size_high,
+					chroma_buf_size_low,
+					module,
+					NULL, NULL))
+			return -1;
+		/* Reference VOP */
+		if (pmem_fixup_high_low(&frame_cmd->ref_vop_buf_ptr_high,
+					&frame_cmd->ref_vop_buf_ptr_low,
+					frame_buf_size_high,
+					frame_buf_size_low,
+					module,
+					NULL, NULL))
+			return -1;
+		/* Encoded Packet Address */
+		if (pmem_fixup_high_low(&frame_cmd->enc_pkt_buf_ptr_high,
+					&frame_cmd->enc_pkt_buf_ptr_low,
+					frame_cmd->enc_pkt_buf_size_high,
+					frame_cmd->enc_pkt_buf_size_low,
+					module,
+					NULL, NULL))
+			return -1;
+		/* Unfiltered VOP Buffer Address */
+		if (pmem_fixup_high_low(
+				&frame_cmd->unfilt_recon_vop_buf_ptr_high,
+				&frame_cmd->unfilt_recon_vop_buf_ptr_low,
+				frame_buf_size_high,
+				frame_buf_size_low,
+				module,
+				NULL, NULL))
+			return -1;
+		/* Filtered VOP Buffer Address */
+		if (pmem_fixup_high_low(&frame_cmd->filt_recon_vop_buf_ptr_high,
+					&frame_cmd->filt_recon_vop_buf_ptr_low,
+					frame_buf_size_high,
+					frame_buf_size_low,
+					module,
+					NULL, NULL))
+			return -1;
+		break;
+	case VIDENC_CMD_DIS:
+		if (cmd_size < sizeof(videnc_cmd_dis))
+			return -1;
+		dis_cmd = (videnc_cmd_dis *)cmd_data;
+		luma_buf_size = x_dimension * y_dimension;
+		ptr_to_high_low_short((void *)luma_buf_size,
+			      &luma_buf_size_high,
+			      &luma_buf_size_low);
+		/* Prev VFE Luma Output Address */
+		if (pmem_fixup_high_low(&dis_cmd->vfe_out_prev_luma_addr_high,
+					&dis_cmd->vfe_out_prev_luma_addr_low,
+					luma_buf_size_high,
+					luma_buf_size_low,
+					module,
+					NULL, NULL))
+			return -1;
+		break;
+	default:
+		MM_INFO("adsp_video:unknown encoder video cmd %u\n", cmd_id);
+		return 0;
+	}
+
+	return 0;
+}
+
+
+int adsp_videoenc_verify_cmd(struct msm_adsp_module *module,
+			 unsigned int queue_id, void *cmd_data,
+			 size_t cmd_size)
+{
+	switch (queue_id) {
+	case QDSP_mpuVEncCmdQueue:
+		return verify_venc_cmd(module, cmd_data, cmd_size);
+	default:
+		MM_INFO("unknown video queue %u\n", queue_id);
+		return 0;
+	}
+}
+
diff --git a/arch/arm/mach-msm/qdsp5/audio_aac.c b/arch/arm/mach-msm/qdsp5/audio_aac.c
new file mode 100644
index 0000000..725819f
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_aac.c
@@ -0,0 +1,1915 @@
+/* arch/arm/mach-msm/qdsp5/audio_aac.c
+ *
+ * aac audio decoder device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2008-2009, 2011-2012 Code Aurora Forum. 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.
+ *
+ */
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/earlysuspend.h>
+#include <linux/android_pmem.h>
+#include <linux/slab.h>
+#include <linux/msm_audio_aac.h>
+#include <linux/memory_alloc.h>
+
+#include <mach/msm_adsp.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audplaycmdi.h>
+#include <mach/qdsp5/qdsp5audplaymsg.h>
+#include <mach/qdsp5/qdsp5rmtcmdi.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_memtypes.h>
+
+#include "audmgr.h"
+
+#define BUFSZ 32768
+#define DMASZ (BUFSZ * 2)
+#define BUFSZ_MIN 4096
+#define DMASZ_MIN (BUFSZ_MIN * 2)
+
+#define AUDPLAY_INVALID_READ_PTR_OFFSET	0xFFFF
+#define AUDDEC_DEC_AAC 5
+
+#define PCM_BUFSZ_MIN 9600	/* Hold one stereo AAC frame */
+#define PCM_BUF_MAX_COUNT 5	/* DSP only accepts 5 buffers at most
+				   but support 2 buffers currently */
+#define ROUTING_MODE_FTRT 1
+#define ROUTING_MODE_RT 2
+/* Decoder status received from AUDPPTASK */
+#define  AUDPP_DEC_STATUS_SLEEP	0
+#define	 AUDPP_DEC_STATUS_INIT  1
+#define  AUDPP_DEC_STATUS_CFG   2
+#define  AUDPP_DEC_STATUS_PLAY  3
+
+#define AUDAAC_METAFIELD_MASK 0xFFFF0000
+#define AUDAAC_EOS_FLG_OFFSET 0x0A /* Offset from beginning of buffer */
+#define AUDAAC_EOS_FLG_MASK 0x01
+#define AUDAAC_EOS_NONE 0x0 /* No EOS detected */
+#define AUDAAC_EOS_SET 0x1 /* EOS set in meta field */
+
+#define AUDAAC_EVENT_NUM 10 /* Default number of pre-allocated event packets */
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+	unsigned short mfield_sz; /*only useful for data has meta field */
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct audaac_suspend_ctl {
+	struct early_suspend node;
+	struct audio *audio;
+};
+#endif
+
+struct audaac_event{
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+
+struct audio {
+	struct buffer out[2];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed;	/* number of buffers the dsp is waiting for */
+	unsigned out_dma_sz;
+
+	atomic_t out_bytes;
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	/* Host PCM section */
+	struct buffer in[PCM_BUF_MAX_COUNT];
+	struct mutex read_lock;
+	wait_queue_head_t read_wait;	/* Wait queue for read */
+	char *read_data;	/* pointer to reader buffer */
+	int32_t read_phys;	/* physical address of reader buffer */
+	uint8_t read_next;	/* index to input buffers to be read next */
+	uint8_t fill_next;	/* index to buffer that DSP should be filling */
+	uint8_t pcm_buf_count;	/* number of pcm buffer allocated */
+	/* ---- End of Host PCM section */
+
+	struct msm_adsp_module *audplay;
+	void *map_v_read;
+	void *map_v_write;
+
+	/* configuration to use on next enable */
+	uint32_t out_sample_rate;
+	uint32_t out_channel_mode;
+	struct msm_audio_aac_config aac_config;
+	struct audmgr audmgr;
+
+	/* data allocated for various buffers */
+	char *data;
+	int32_t phys; /* physical address of write buffer */
+
+	int mfield; /* meta field embedded in data */
+	int rflush; /* Read  flush */
+	int eos_in_progress;
+	int wflush; /* Write flush */
+	int opened;
+	int enabled;
+	int running;
+	int stopped;	/* set when stopped, cleared on flush */
+	int pcm_feedback;
+	int buf_refresh;
+	int rmt_resource_released;
+	int teos; /* valid only if tunnel mode & no data left for decoder */
+	enum msm_aud_decoder_state dec_state;	/* Represents decoder state */
+	int reserved; /* A byte is being reserved */
+	char rsv_byte; /* Handle odd length user data */
+
+	const char *module_name;
+	unsigned queue_id;
+	uint16_t dec_id;
+	uint32_t read_ptr_offset;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct audaac_suspend_ctl suspend_ctl;
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+
+	wait_queue_head_t wait;
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	wait_queue_head_t event_wait;
+	spinlock_t event_queue_lock;
+	struct mutex get_event_lock;
+	int event_abort;
+
+	struct msm_audio_bitstream_info stream_info;
+
+	int eq_enable;
+	int eq_needs_commit;
+	audpp_cmd_cfg_object_params_eqalizer eq;
+	audpp_cmd_cfg_object_params_volume vol_pan;
+};
+
+static int auddec_dsp_config(struct audio *audio, int enable);
+static void audpp_cmd_cfg_adec_params(struct audio *audio);
+static void audpp_cmd_cfg_routing_mode(struct audio *audio);
+static void audplay_send_data(struct audio *audio, unsigned needed);
+static void audplay_config_hostpcm(struct audio *audio);
+static void audplay_buffer_refresh(struct audio *audio);
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
+static void audaac_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload);
+
+static int rmt_put_resource(struct audio *audio)
+{
+	struct aud_codec_config_cmd cmd;
+	unsigned short client_idx;
+
+	cmd.cmd_id = RM_CMD_AUD_CODEC_CFG;
+	cmd.client_id = RM_AUD_CLIENT_ID;
+	cmd.task_id = audio->dec_id;
+	cmd.enable = RMT_DISABLE;
+	cmd.dec_type = AUDDEC_DEC_AAC;
+	client_idx = ((cmd.client_id << 8) | cmd.task_id);
+
+	return put_adsp_resource(client_idx, &cmd, sizeof(cmd));
+}
+
+static int rmt_get_resource(struct audio *audio)
+{
+	struct aud_codec_config_cmd cmd;
+	unsigned short client_idx;
+
+	cmd.cmd_id = RM_CMD_AUD_CODEC_CFG;
+	cmd.client_id = RM_AUD_CLIENT_ID;
+	cmd.task_id = audio->dec_id;
+	cmd.enable = RMT_ENABLE;
+	cmd.dec_type = AUDDEC_DEC_AAC;
+	client_idx = ((cmd.client_id << 8) | cmd.task_id);
+
+	return get_adsp_resource(client_idx, &cmd, sizeof(cmd));
+}
+
+/* must be called with audio->lock held */
+static int audio_enable(struct audio *audio)
+{
+	struct audmgr_config cfg;
+	int rc;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	if (audio->enabled)
+		return 0;
+
+	if (audio->rmt_resource_released == 1) {
+		audio->rmt_resource_released = 0;
+		rc = rmt_get_resource(audio);
+		if (rc) {
+			MM_ERR("ADSP resources are not available for AAC \
+				session 0x%08x on decoder: %d\n Ignoring \
+				error and going ahead with the playback\n",
+				(int)audio, audio->dec_id);
+		}
+	}
+
+	audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
+		cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+		cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;
+		cfg.def_method = RPC_AUD_DEF_METHOD_PLAYBACK;
+		cfg.codec = RPC_AUD_DEF_CODEC_AAC;
+		cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+		rc = audmgr_enable(&audio->audmgr, &cfg);
+		if (rc < 0)
+			return rc;
+	}
+
+	if (msm_adsp_enable(audio->audplay)) {
+		MM_ERR("msm_adsp_enable(audplay) failed\n");
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+
+	if (audpp_enable(audio->dec_id, audio_dsp_event, audio)) {
+		MM_ERR("audpp_enable() failed\n");
+		msm_adsp_disable(audio->audplay);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+	audio->enabled = 1;
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audio_disable(struct audio *audio)
+{
+	int rc = 0;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+		auddec_dsp_config(audio, 0);
+		rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+		else if (audio->dec_state != MSM_AUD_DECODER_STATE_CLOSE)
+			rc = -EFAULT;
+		else
+			rc = 0;
+		audio->stopped = 1;
+		wake_up(&audio->write_wait);
+		wake_up(&audio->read_wait);
+		msm_adsp_disable(audio->audplay);
+		audpp_disable(audio->dec_id, audio);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_disable(&audio->audmgr);
+		audio->out_needed = 0;
+		rmt_put_resource(audio);
+		audio->rmt_resource_released = 1;
+	}
+	return rc;
+}
+
+/* ------------------- dsp --------------------- */
+static void audio_update_pcm_buf_entry(struct audio *audio, uint32_t *payload)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	if (audio->rflush)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < payload[1]; index++) {
+		if (audio->in[audio->fill_next].addr ==
+		    payload[2 + index * 2]) {
+			MM_DBG("in[%d] ready\n", audio->fill_next);
+			audio->in[audio->fill_next].used =
+				payload[3 + index * 2];
+			if ((++audio->fill_next) == audio->pcm_buf_count)
+				audio->fill_next = 0;
+
+		} else {
+			MM_ERR("expected=%x ret=%x\n",
+				audio->in[audio->fill_next].addr,
+				payload[1 + index * 2]);
+			break;
+		}
+	}
+	if (audio->in[audio->fill_next].used == 0) {
+		audplay_buffer_refresh(audio);
+	} else {
+		MM_DBG("read cannot keep up\n");
+		audio->buf_refresh = 1;
+	}
+	wake_up(&audio->read_wait);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+
+}
+static void audaac_update_stream_info(struct audio *audio, uint32_t *payload)
+{
+	unsigned long flags;
+	union msm_audio_event_payload e_payload;
+
+	/* get stream info from DSP msg */
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+
+	audio->stream_info.codec_type = AUDIO_CODEC_TYPE_AAC;
+	audio->stream_info.chan_info = (0x0000FFFF & payload[1]);
+	audio->stream_info.sample_rate = (0x0000FFFF & payload[2]);
+	audio->stream_info.bit_stream_info = (0x0000FFFF & payload[3]);
+	audio->stream_info.bit_rate = payload[4];
+
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	MM_DBG("chan_info=%d, sample_rate=%d, bit_stream_info=%d\n",
+			audio->stream_info.chan_info,
+			audio->stream_info.sample_rate,
+			audio->stream_info.bit_stream_info);
+
+	/* send event to ARM to notify steam info coming */
+	e_payload.stream_info = audio->stream_info;
+	audaac_post_event(audio, AUDIO_EVENT_STREAM_INFO, e_payload);
+}
+static void audplay_dsp_event(void *data, unsigned id, size_t len,
+			      void (*getevent) (void *ptr, size_t len))
+{
+	struct audio *audio = data;
+	uint32_t msg[28];
+	getevent(msg, sizeof(msg));
+
+	MM_DBG("msg_id=%x\n", id);
+
+	switch (id) {
+	case AUDPLAY_MSG_DEC_NEEDS_DATA:
+		audplay_send_data(audio, 1);
+		break;
+
+	case AUDPLAY_MSG_BUFFER_UPDATE:
+		audio_update_pcm_buf_entry(audio, msg);
+		break;
+
+	case AUDPLAY_UP_STREAM_INFO:
+		audaac_update_stream_info(audio, msg);
+		break;
+
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audplaytask)\n");
+		break;
+
+	default:
+		MM_ERR("unexpected message from decoder \n");
+	}
+}
+
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned status = msg[1];
+
+			switch (status) {
+			case AUDPP_DEC_STATUS_SLEEP: {
+				uint16_t reason = msg[2];
+				MM_DBG("decoder status: sleep reason = \
+						0x%04x\n", reason);
+				if ((reason == AUDPP_MSG_REASON_MEM)
+					|| (reason ==
+					AUDPP_MSG_REASON_NODECODER)) {
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_FAILURE;
+					wake_up(&audio->wait);
+				} else if (reason == AUDPP_MSG_REASON_NONE) {
+					/* decoder is in disable state */
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_CLOSE;
+					wake_up(&audio->wait);
+				}
+				break;
+			}
+			case AUDPP_DEC_STATUS_INIT:
+				MM_DBG("decoder status: init \n");
+				if (audio->pcm_feedback)
+					audpp_cmd_cfg_routing_mode(audio);
+				else
+					audpp_cmd_cfg_adec_params(audio);
+				break;
+
+			case AUDPP_DEC_STATUS_CFG:
+				MM_DBG("decoder status: cfg \n");
+				break;
+			case AUDPP_DEC_STATUS_PLAY:
+				MM_DBG("decoder status: play \n");
+				if (audio->pcm_feedback) {
+					audplay_config_hostpcm(audio);
+					audplay_buffer_refresh(audio);
+				}
+				audio->dec_state =
+					MSM_AUD_DECODER_STATE_SUCCESS;
+				wake_up(&audio->wait);
+				break;
+			default:
+				MM_ERR("unknown decoder status \n");
+			}
+			break;
+		}
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			MM_DBG("CFG_MSG ENABLE\n");
+			auddec_dsp_config(audio, 1);
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+			audpp_dsp_set_eq(audio->dec_id, audio->eq_enable,
+								&audio->eq);
+			audpp_avsync(audio->dec_id, 22050);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			MM_DBG("CFG_MSG DISABLE\n");
+			audpp_avsync(audio->dec_id, 0);
+			audio->running = 0;
+		} else {
+			MM_DBG("CFG_MSG %d?\n",	msg[0]);
+		}
+		break;
+	case AUDPP_MSG_ROUTING_ACK:
+		MM_DBG("ROUTING_ACK mode=%d\n",	msg[1]);
+		audpp_cmd_cfg_adec_params(audio);
+		break;
+
+	case AUDPP_MSG_FLUSH_ACK:
+		MM_DBG("FLUSH_ACK\n");
+		audio->wflush = 0;
+		audio->rflush = 0;
+		wake_up(&audio->write_wait);
+		if (audio->pcm_feedback)
+			audplay_buffer_refresh(audio);
+		break;
+
+	case AUDPP_MSG_PCMDMAMISSED:
+		MM_DBG("PCMDMAMISSED\n");
+		audio->teos = 1;
+		wake_up(&audio->write_wait);
+		break;
+
+	default:
+		MM_ERR("UNKNOWN (%d)\n", id);
+	}
+
+}
+
+struct msm_adsp_ops audplay_adsp_ops_aac = {
+	.event = audplay_dsp_event,
+};
+
+#define audplay_send_queue0(audio, cmd, len) \
+	msm_adsp_write(audio->audplay, audio->queue_id,\
+			cmd, len)
+
+static int auddec_dsp_config(struct audio *audio, int enable)
+{
+	u16 cfg_dec_cmd[AUDPP_CMD_CFG_DEC_TYPE_LEN / sizeof(unsigned short)];
+
+	memset(cfg_dec_cmd, 0, sizeof(cfg_dec_cmd));
+	cfg_dec_cmd[0] = AUDPP_CMD_CFG_DEC_TYPE;
+
+	if (enable)
+		cfg_dec_cmd[1 + audio->dec_id] = AUDPP_CMD_UPDATDE_CFG_DEC |
+			AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_AAC;
+	else
+		cfg_dec_cmd[1 + audio->dec_id] = AUDPP_CMD_UPDATDE_CFG_DEC |
+		AUDPP_CMD_DIS_DEC_V;
+
+	return audpp_send_queue1(&cfg_dec_cmd, sizeof(cfg_dec_cmd));
+}
+
+static void audpp_cmd_cfg_adec_params(struct audio *audio)
+{
+	audpp_cmd_cfg_adec_params_aac cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_AAC_LEN;
+	cmd.common.dec_id = audio->dec_id;
+	cmd.common.input_sampling_frequency = audio->out_sample_rate;
+	cmd.format = audio->aac_config.format;
+	cmd.audio_object = audio->aac_config.audio_object;
+	cmd.ep_config = audio->aac_config.ep_config;
+	cmd.aac_section_data_resilience_flag =
+		audio->aac_config.aac_section_data_resilience_flag;
+	cmd.aac_scalefactor_data_resilience_flag =
+		audio->aac_config.aac_scalefactor_data_resilience_flag;
+	cmd.aac_spectral_data_resilience_flag =
+		audio->aac_config.aac_spectral_data_resilience_flag;
+	cmd.sbr_on_flag = audio->aac_config.sbr_on_flag;
+	cmd.sbr_ps_on_flag = audio->aac_config.sbr_ps_on_flag;
+	cmd.channel_configuration = audio->aac_config.channel_configuration;
+
+	audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static void audpp_cmd_cfg_routing_mode(struct audio *audio)
+{
+	struct audpp_cmd_routing_mode cmd;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_ROUTING_MODE;
+	cmd.object_number = audio->dec_id;
+	if (audio->pcm_feedback)
+		cmd.routing_mode = ROUTING_MODE_FTRT;
+	else
+		cmd.routing_mode = ROUTING_MODE_RT;
+
+	audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static int audplay_dsp_send_data_avail(struct audio *audio,
+				       unsigned idx, unsigned len)
+{
+	struct audplay_cmd_bitstream_data_avail_nt2 cmd;
+
+	cmd.cmd_id = AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_NT2;
+	if (audio->mfield)
+		cmd.decoder_id = AUDAAC_METAFIELD_MASK |
+			(audio->out[idx].mfield_sz >> 1);
+	else
+	    cmd.decoder_id = audio->dec_id;
+	cmd.buf_ptr = audio->out[idx].addr;
+	cmd.buf_size = len / 2;
+	cmd.partition_number = 0;
+	/* complete all the writes to the input buffer */
+	wmb();
+	return audplay_send_queue0(audio, &cmd, sizeof(cmd));
+}
+
+static void audplay_buffer_refresh(struct audio *audio)
+{
+	struct audplay_cmd_buffer_refresh refresh_cmd;
+
+	refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH;
+	refresh_cmd.num_buffers = 1;
+	refresh_cmd.buf0_address = audio->in[audio->fill_next].addr;
+	/* AAC frame size */
+	refresh_cmd.buf0_length = audio->in[audio->fill_next].size -
+		(audio->in[audio->fill_next].size % 1024)
+		+ (audio->mfield ? 24 : 0);
+	refresh_cmd.buf_read_count = 0;
+	MM_DBG("buf0_addr=%x buf0_len=%d\n", refresh_cmd.buf0_address,
+			refresh_cmd.buf0_length);
+	(void)audplay_send_queue0(audio, &refresh_cmd, sizeof(refresh_cmd));
+}
+
+static void audplay_config_hostpcm(struct audio *audio)
+{
+	struct audplay_cmd_hpcm_buf_cfg cfg_cmd;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	cfg_cmd.cmd_id = AUDPLAY_CMD_HPCM_BUF_CFG;
+	cfg_cmd.max_buffers = audio->pcm_buf_count;
+	cfg_cmd.byte_swap = 0;
+	cfg_cmd.hostpcm_config = (0x8000) | (0x4000);
+	cfg_cmd.feedback_frequency = 1;
+	cfg_cmd.partition_number = 0;
+	(void)audplay_send_queue0(audio, &cfg_cmd, sizeof(cfg_cmd));
+
+}
+
+static void audplay_send_data(struct audio *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (needed && !audio->wflush) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			MM_DBG("frame %d free\n", audio->out_tail);
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		} else if ((audio->out[0].used == 0) &&
+			 (audio->out[1].used == 0) &&
+			 (audio->eos_in_progress)) {
+			wake_up(&audio->write_wait);
+		}
+
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+			MM_DBG("frame %d busy\n", audio->out_tail);
+			audplay_dsp_send_data_avail(audio, audio->out_tail,
+						    frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+ done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+
+static void audio_flush(struct audio *audio)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->out[0].used = 0;
+	audio->out[1].used = 0;
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->reserved = 0;
+	audio->out_needed = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	atomic_set(&audio->out_bytes, 0);
+}
+
+static void audio_flush_pcm_buf(struct audio *audio)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
+		audio->in[index].used = 0;
+	audio->buf_refresh = 0;
+	audio->read_next = 0;
+	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static int audaac_validate_usr_config(struct msm_audio_aac_config *config)
+{
+	int ret_val = -1;
+
+	if (config->format != AUDIO_AAC_FORMAT_ADTS &&
+		config->format != AUDIO_AAC_FORMAT_RAW &&
+		config->format != AUDIO_AAC_FORMAT_PSUEDO_RAW &&
+		config->format != AUDIO_AAC_FORMAT_LOAS)
+		goto done;
+
+	if (config->audio_object != AUDIO_AAC_OBJECT_LC &&
+		config->audio_object != AUDIO_AAC_OBJECT_LTP &&
+		config->audio_object != AUDIO_AAC_OBJECT_BSAC &&
+		config->audio_object != AUDIO_AAC_OBJECT_ERLC)
+		goto done;
+
+	if (config->audio_object == AUDIO_AAC_OBJECT_ERLC) {
+		if (config->ep_config > 3)
+			goto done;
+		if (config->aac_scalefactor_data_resilience_flag !=
+			AUDIO_AAC_SCA_DATA_RES_OFF &&
+			config->aac_scalefactor_data_resilience_flag !=
+			AUDIO_AAC_SCA_DATA_RES_ON)
+			goto done;
+		if (config->aac_section_data_resilience_flag !=
+			AUDIO_AAC_SEC_DATA_RES_OFF &&
+			config->aac_section_data_resilience_flag !=
+			AUDIO_AAC_SEC_DATA_RES_ON)
+			goto done;
+		if (config->aac_spectral_data_resilience_flag !=
+			AUDIO_AAC_SPEC_DATA_RES_OFF &&
+			config->aac_spectral_data_resilience_flag !=
+			AUDIO_AAC_SPEC_DATA_RES_ON)
+			goto done;
+	} else {
+		config->aac_section_data_resilience_flag =
+			AUDIO_AAC_SEC_DATA_RES_OFF;
+		config->aac_scalefactor_data_resilience_flag =
+			AUDIO_AAC_SCA_DATA_RES_OFF;
+		config->aac_spectral_data_resilience_flag =
+			AUDIO_AAC_SPEC_DATA_RES_OFF;
+	}
+
+#ifndef CONFIG_AUDIO_AAC_PLUS
+	if (AUDIO_AAC_SBR_ON_FLAG_OFF != config->sbr_on_flag)
+		goto done;
+#else
+	if (config->sbr_on_flag != AUDIO_AAC_SBR_ON_FLAG_OFF &&
+		config->sbr_on_flag != AUDIO_AAC_SBR_ON_FLAG_ON)
+		goto done;
+#endif
+
+#ifndef CONFIG_AUDIO_ENHANCED_AAC_PLUS
+	if (AUDIO_AAC_SBR_PS_ON_FLAG_OFF != config->sbr_ps_on_flag)
+		goto done;
+#else
+	if (config->sbr_ps_on_flag != AUDIO_AAC_SBR_PS_ON_FLAG_OFF &&
+		config->sbr_ps_on_flag != AUDIO_AAC_SBR_PS_ON_FLAG_ON)
+		goto done;
+#endif
+
+	if (config->dual_mono_mode > AUDIO_AAC_DUAL_MONO_PL_SR)
+		goto done;
+
+	if (config->channel_configuration > 2)
+		goto done;
+
+	ret_val = 0;
+ done:
+	return ret_val;
+}
+
+static void audio_ioport_reset(struct audio *audio)
+{
+	/* Make sure read/write thread are free from
+	 * sleep and knowing that system is not able
+	 * to process io request at the moment
+	 */
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audio_flush(audio);
+	mutex_unlock(&audio->write_lock);
+	wake_up(&audio->read_wait);
+	mutex_lock(&audio->read_lock);
+	audio_flush_pcm_buf(audio);
+	mutex_unlock(&audio->read_lock);
+}
+
+static int audaac_events_pending(struct audio *audio)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	return empty || audio->event_abort;
+}
+
+static void audaac_reset_event_queue(struct audio *audio)
+{
+	unsigned long flags;
+	struct audaac_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audaac_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+				struct audaac_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	return;
+}
+
+static long audaac_process_event_req(struct audio *audio, void __user *arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audaac_event *drv_evt = NULL;
+	int timeout;
+	unsigned long flags;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int) usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(
+			audio->event_wait, audaac_events_pending(audio),
+			msecs_to_jiffies(timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(
+			audio->event_wait, audaac_events_pending(audio));
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	rc = 0;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audaac_event, list);
+		list_del(&drv_evt->list);
+	}
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else
+		rc = -1;
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	if (!rc && copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audio_enable_eq(struct audio *audio, int enable)
+{
+	if (audio->eq_enable == enable && !audio->eq_needs_commit)
+		return 0;
+
+	audio->eq_enable = enable;
+
+	if (audio->running) {
+		audpp_dsp_set_eq(audio->dec_id, enable, &audio->eq);
+		audio->eq_needs_commit = 0;
+	}
+	return 0;
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = -EINVAL;
+	unsigned long flags = 0;
+	uint16_t enable_mask;
+	int enable;
+	int prev_state;
+
+	MM_DBG("cmd = %d\n", cmd);
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = audpp_avsync_byte_count(audio->dec_id);
+		stats.sample_count = audpp_avsync_sample_count(audio->dec_id);
+		if (copy_to_user((void *)arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	switch (cmd) {
+	case AUDIO_ENABLE_AUDPP:
+		if (copy_from_user(&enable_mask, (void *) arg,
+						sizeof(enable_mask))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		enable = (enable_mask & EQ_ENABLE) ? 1 : 0;
+		audio_enable_eq(audio, enable);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+	case AUDIO_SET_VOLUME:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.volume = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_PAN:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.pan = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_EQ:
+		prev_state = audio->eq_enable;
+		audio->eq_enable = 0;
+		if (copy_from_user(&audio->eq.num_bands, (void *) arg,
+				sizeof(audio->eq) -
+				(AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2))) {
+			rc = -EFAULT;
+			break;
+		}
+		audio->eq_enable = prev_state;
+		audio->eq_needs_commit = 1;
+		rc = 0;
+		break;
+	}
+
+	if (-EINVAL != rc)
+		return rc;
+
+	if (cmd == AUDIO_GET_EVENT) {
+		MM_DBG("AUDIO_GET_EVENT\n");
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audaac_process_event_req(audio,
+					(void __user *) arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		return rc;
+	}
+
+	if (cmd == AUDIO_ABORT_GET_EVENT) {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		MM_DBG("AUDIO_START\n");
+		rc = audio_enable(audio);
+		if (!rc) {
+			rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+			MM_INFO("dec_state %d rc = %d\n", audio->dec_state, rc);
+
+			if (audio->dec_state != MSM_AUD_DECODER_STATE_SUCCESS)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		break;
+	case AUDIO_STOP:
+		MM_DBG("AUDIO_STOP\n");
+		rc = audio_disable(audio);
+		audio_ioport_reset(audio);
+		audio->stopped = 0;
+		break;
+	case AUDIO_FLUSH:
+		MM_DBG("AUDIO_FLUSH running=%d\n", audio->running);
+		audio->rflush = 1;
+		audio->wflush = 1;
+		audio_ioport_reset(audio);
+		if (audio->running) {
+			audpp_flush(audio->dec_id);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		break;
+
+	case AUDIO_SET_CONFIG:{
+			struct msm_audio_config config;
+
+			if (copy_from_user
+			    (&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+
+			if (config.channel_count == 1) {
+				config.channel_count =
+				    AUDPP_CMD_PCM_INTF_MONO_V;
+			} else if (config.channel_count == 2) {
+				config.channel_count =
+				    AUDPP_CMD_PCM_INTF_STEREO_V;
+			} else {
+				rc = -EINVAL;
+				break;
+			}
+
+			audio->out_sample_rate = config.sample_rate;
+			audio->out_channel_mode = config.channel_count;
+			audio->mfield = config.meta_field;
+			rc = 0;
+			break;
+		}
+	case AUDIO_GET_CONFIG:{
+			struct msm_audio_config config;
+			config.buffer_size = (audio->out_dma_sz >> 1);
+			config.buffer_count = 2;
+			config.sample_rate = audio->out_sample_rate;
+			if (audio->out_channel_mode ==
+			    AUDPP_CMD_PCM_INTF_MONO_V) {
+				config.channel_count = 1;
+			} else {
+				config.channel_count = 2;
+			}
+			config.meta_field = 0;
+			config.unused[0] = 0;
+			config.unused[1] = 0;
+			config.unused[2] = 0;
+			if (copy_to_user((void *)arg, &config,
+					 sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+
+			break;
+		}
+	case AUDIO_GET_AAC_CONFIG:{
+			if (copy_to_user((void *)arg, &audio->aac_config,
+				sizeof(audio->aac_config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_SET_AAC_CONFIG:{
+			struct msm_audio_aac_config usr_config;
+
+			if (copy_from_user
+				(&usr_config, (void *)arg,
+					sizeof(usr_config))) {
+				rc = -EFAULT;
+				break;
+			}
+
+			if (audaac_validate_usr_config(&usr_config) == 0) {
+				audio->aac_config = usr_config;
+				rc = 0;
+			} else
+				rc = -EINVAL;
+
+			break;
+		}
+	case AUDIO_GET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			config.pcm_feedback = audio->pcm_feedback;
+			config.buffer_count = PCM_BUF_MAX_COUNT;
+			config.buffer_size = PCM_BUFSZ_MIN;
+			if (copy_to_user((void *)arg, &config,
+					 sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_SET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			if (copy_from_user
+			    (&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+			if (config.pcm_feedback != audio->pcm_feedback) {
+				MM_ERR("Not sufficient permission to"
+					 "change the playback mode\n");
+				rc = -EACCES;
+				break;
+			}
+			if ((config.buffer_count > PCM_BUF_MAX_COUNT) ||
+			    (config.buffer_count == 1))
+				config.buffer_count = PCM_BUF_MAX_COUNT;
+
+			if (config.buffer_size < PCM_BUFSZ_MIN)
+				config.buffer_size = PCM_BUFSZ_MIN;
+
+			/* Check if pcm feedback is required */
+			if (config.pcm_feedback) {
+					audio->buf_refresh = 0;
+					audio->read_next = 0;
+					audio->fill_next = 0;
+			}
+			rc = 0;
+			break;
+		}
+	case AUDIO_PAUSE:
+		MM_DBG("AUDIO_PAUSE %ld\n", arg);
+		rc = audpp_pause(audio->dec_id, (int) arg);
+		break;
+	case AUDIO_GET_STREAM_INFO:{
+		if (audio->stream_info.sample_rate == 0) {
+			/* haven't received DSP stream event,
+			the stream info is not updated */
+			rc = -EPERM;
+			break;
+		}
+		if (copy_to_user((void *)arg, &audio->stream_info,
+			sizeof(struct msm_audio_bitstream_info)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+/* Only useful in tunnel-mode */
+static int audaac_fsync(struct file *file, loff_t a, loff_t b, int datasync)
+{
+	struct audio *audio = file->private_data;
+	struct buffer *frame;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	if (!audio->running || audio->pcm_feedback) {
+		rc = -EINVAL;
+		goto done_nolock;
+	}
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(!audio->out[0].used &&
+		!audio->out[1].used &&
+		audio->out_needed) || audio->wflush);
+
+	if (rc < 0)
+		goto done;
+	else if (audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (audio->reserved) {
+		MM_DBG("send reserved byte\n");
+		frame = audio->out + audio->out_tail;
+		((char *) frame->data)[0] = audio->rsv_byte;
+		((char *) frame->data)[1] = 0;
+		frame->used = 2;
+		audplay_send_data(audio, 0);
+
+		rc = wait_event_interruptible(audio->write_wait,
+			(!audio->out[0].used &&
+			!audio->out[1].used &&
+			audio->out_needed) || audio->wflush);
+
+		if (rc < 0)
+			goto done;
+		else if (audio->wflush) {
+			rc = -EBUSY;
+			goto done;
+		}
+	}
+
+	/* pcm dmamiss message is sent continously
+	 * when decoder is starved so no race
+	 * condition concern
+	 */
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		audio->teos || audio->wflush);
+
+	if (audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+done_nolock:
+	return rc;
+}
+
+static ssize_t audio_read(struct file *file, char __user *buf, size_t count,
+			  loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	int rc = 0;
+
+	if (!audio->pcm_feedback)
+		return 0; /* PCM feedback is not enabled. Nothing to read */
+
+	mutex_lock(&audio->read_lock);
+	MM_DBG("to read %d \n", count);
+	while (count > 0) {
+		rc = wait_event_interruptible(audio->read_wait,
+					      (audio->in[audio->read_next].
+						used > 0) || (audio->stopped)
+						|| (audio->rflush));
+
+		if (rc < 0)
+			break;
+
+		if (audio->stopped || audio->rflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (count < audio->in[audio->read_next].used) {
+			/* Read must happen in frame boundary. Since driver
+			   does not know frame size, read count must be greater
+			   or equal to size of PCM samples */
+			MM_DBG("no partial frame done reading\n");
+			break;
+		} else {
+			MM_DBG("read from in[%d]\n", audio->read_next);
+			/* order reads to the output buffer */
+			rmb();
+			if (copy_to_user
+			    (buf, audio->in[audio->read_next].data,
+			     audio->in[audio->read_next].used)) {
+				MM_ERR("invalid addr %x\n", (unsigned int)buf);
+				rc = -EFAULT;
+				break;
+			}
+			count -= audio->in[audio->read_next].used;
+			buf += audio->in[audio->read_next].used;
+			audio->in[audio->read_next].used = 0;
+			if ((++audio->read_next) == audio->pcm_buf_count)
+				audio->read_next = 0;
+			break;
+				/*
+				* Force to exit while loop
+				* to prevent output thread
+				* sleep too long if data is not
+				* ready at this moment.
+				*/
+		}
+	}
+
+	/* don't feed output buffer to HW decoder during flushing
+	 * buffer refresh command will be sent once flush completes
+	 * send buf refresh command here can confuse HW decoder
+	 */
+	if (audio->buf_refresh && !audio->rflush) {
+		audio->buf_refresh = 0;
+		MM_DBG("kick start pcm feedback again\n");
+		audplay_buffer_refresh(audio);
+	}
+
+	mutex_unlock(&audio->read_lock);
+
+	if (buf > start)
+		rc = buf - start;
+
+	MM_DBG("read %d bytes\n", rc);
+	return rc;
+}
+
+static int audaac_process_eos(struct audio *audio,
+	const char __user *buf_start, unsigned short mfield_size)
+{
+	struct buffer *frame;
+	char *buf_ptr;
+	int rc = 0;
+	unsigned long flags = 0;
+
+	MM_DBG("signal input EOS reserved=%d\n", audio->reserved);
+	if (audio->reserved) {
+		MM_DBG("Pass reserve byte\n");
+		frame = audio->out + audio->out_head;
+		buf_ptr = frame->data;
+		rc = wait_event_interruptible(audio->write_wait,
+					(frame->used == 0)
+					|| (audio->stopped)
+					|| (audio->wflush));
+	if (rc < 0)
+		goto done;
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+	buf_ptr[0] = audio->rsv_byte;
+	buf_ptr[1] = 0;
+	audio->out_head ^= 1;
+	frame->mfield_sz = 0;
+	audio->reserved = 0;
+	frame->used = 2;
+	audplay_send_data(audio, 0);
+	}
+	MM_DBG("Now signal input EOS after reserved bytes %d %d %d\n",
+		audio->out[0].used, audio->out[1].used, audio->out_needed);
+	frame = audio->out + audio->out_head;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->eos_in_progress = 1;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->out_needed &&
+		audio->out[0].used == 0 &&
+		audio->out[1].used == 0)
+		|| (audio->stopped)
+		|| (audio->wflush));
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->eos_in_progress = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+
+	if (rc < 0)
+		goto done;
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (copy_from_user(frame->data, buf_start, mfield_size)) {
+		rc = -EFAULT;
+		goto done;
+	}
+
+	frame->mfield_sz = mfield_size;
+	audio->out_head ^= 1;
+	frame->used = mfield_size;
+	audplay_send_data(audio, 0);
+done:
+	return rc;
+}
+static ssize_t audio_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	char *cpy_ptr;
+	int rc = 0, eos_condition = AUDAAC_EOS_NONE;
+	unsigned dsize;
+
+	unsigned short mfield_size = 0;
+	MM_DBG("cnt=%d\n", count);
+	mutex_lock(&audio->write_lock);
+	while (count > 0) {
+		frame = audio->out + audio->out_head;
+		cpy_ptr = frame->data;
+		dsize = 0;
+		rc = wait_event_interruptible(audio->write_wait,
+					      (frame->used == 0)
+						|| (audio->stopped)
+						|| (audio->wflush));
+		if (rc < 0)
+			break;
+		if (audio->stopped || audio->wflush) {
+			rc = -EBUSY;
+			break;
+		}
+		if (audio->mfield) {
+			if (buf == start) {
+				/* Processing beginning of user buffer */
+				if (__get_user(mfield_size,
+					(unsigned short __user *) buf)) {
+					rc = -EFAULT;
+					break;
+				} else 	if (mfield_size > count) {
+					rc = -EINVAL;
+					break;
+				}
+				MM_DBG("mf offset_val %x\n", mfield_size);
+				if (copy_from_user(cpy_ptr, buf, mfield_size)) {
+					rc = -EFAULT;
+					break;
+				}
+				/* Check if EOS flag is set and buffer has
+				* contains just meta field
+				*/
+				if (cpy_ptr[AUDAAC_EOS_FLG_OFFSET] &
+						AUDAAC_EOS_FLG_MASK) {
+					MM_DBG("eos set\n");
+					eos_condition = AUDAAC_EOS_SET;
+					if (mfield_size == count) {
+						buf += mfield_size;
+						break;
+					} else
+					cpy_ptr[AUDAAC_EOS_FLG_OFFSET] &=
+							~AUDAAC_EOS_FLG_MASK;
+				}
+				/* Check EOS to see if */
+				cpy_ptr += mfield_size;
+				count -= mfield_size;
+				dsize += mfield_size;
+				buf += mfield_size;
+			} else {
+				mfield_size = 0;
+				MM_DBG("continuous buffer\n");
+			}
+			frame->mfield_sz = mfield_size;
+		}
+
+		if (audio->reserved) {
+			MM_DBG("append reserved byte %x\n",
+				audio->rsv_byte);
+			*cpy_ptr = audio->rsv_byte;
+			xfer = (count > ((frame->size - mfield_size) - 1)) ?
+				(frame->size - mfield_size) - 1 : count;
+			cpy_ptr++;
+			dsize += 1;
+			audio->reserved = 0;
+		} else
+			xfer = (count > (frame->size - mfield_size)) ?
+				(frame->size - mfield_size) : count;
+
+		if (copy_from_user(cpy_ptr, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+
+		dsize += xfer;
+		if (dsize & 1) {
+			audio->rsv_byte = ((char *) frame->data)[dsize - 1];
+			MM_DBG("odd length buf reserve last byte %x\n",
+					audio->rsv_byte);
+			audio->reserved = 1;
+			dsize--;
+		}
+		count -= xfer;
+		buf += xfer;
+
+		if (dsize > 0) {
+			audio->out_head ^= 1;
+			frame->used = dsize;
+			audplay_send_data(audio, 0);
+		}
+	}
+	MM_DBG("eos_condition %x buf[0x%x] start[0x%x]\n", eos_condition,
+			(int) buf, (int) start);
+	if (eos_condition == AUDAAC_EOS_SET)
+		rc = audaac_process_eos(audio, start, mfield_size);
+	mutex_unlock(&audio->write_lock);
+	if (!rc) {
+		if (buf > start)
+			return buf - start;
+	}
+	return rc;
+}
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	MM_INFO("audio instance 0x%08x freeing\n", (int)audio);
+	mutex_lock(&audio->lock);
+	audio_disable(audio);
+	if (audio->rmt_resource_released == 0)
+		rmt_put_resource(audio);
+	audio_flush(audio);
+	audio_flush_pcm_buf(audio);
+	msm_adsp_put(audio->audplay);
+	audpp_adec_free(audio->dec_id);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&audio->suspend_ctl.node);
+#endif
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audaac_reset_event_queue(audio);
+	iounmap(audio->map_v_write);
+	free_contiguous_memory_by_paddr(audio->phys);
+	iounmap(audio->map_v_read);
+	free_contiguous_memory_by_paddr(audio->read_phys);
+	mutex_unlock(&audio->lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio);
+	return 0;
+}
+
+static void audaac_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload)
+{
+	struct audaac_event *e_node = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+				struct audaac_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audaac_event), GFP_ATOMIC);
+		if (!e_node) {
+			MM_ERR("No mem to post event %d\n", type);
+			spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	wake_up(&audio->event_wait);
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audaac_suspend(struct early_suspend *h)
+{
+	struct audaac_suspend_ctl *ctl =
+		container_of(h, struct audaac_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audaac_post_event(ctl->audio, AUDIO_EVENT_SUSPEND, payload);
+}
+
+static void audaac_resume(struct early_suspend *h)
+{
+	struct audaac_suspend_ctl *ctl =
+		container_of(h, struct audaac_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audaac_post_event(ctl->audio, AUDIO_EVENT_RESUME, payload);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audaac_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audaac_debug_read(struct file *file, char __user *buf,
+					size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 1024;
+	static char buffer[1024];
+	int n = 0, i;
+	struct audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"enabled %d\n", audio->enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_feedback %d\n", audio->pcm_feedback);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_buf_sz %d\n", audio->out[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_buf_count %d \n", audio->pcm_buf_count);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_buf_sz %d \n", audio->in[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"volume %x \n", audio->vol_pan.volume);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"sample rate %d \n", audio->out_sample_rate);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"channel mode %d \n", audio->out_channel_mode);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"rflush %d\n", audio->rflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"running %d \n", audio->running);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"dec state %d \n", audio->dec_state);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_needed %d \n", audio->out_needed);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_head %d \n", audio->out_head);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_tail %d \n", audio->out_tail);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out[0].used %d \n", audio->out[0].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out[1].used %d \n", audio->out[1].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"buffer_refresh %d \n", audio->buf_refresh);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"read_next %d \n", audio->read_next);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"fill_next %d \n", audio->fill_next);
+	for (i = 0; i < audio->pcm_buf_count; i++)
+		n += scnprintf(buffer + n, debug_bufmax - n,
+				"in[%d].used %d \n", i, audio->in[i].used);
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audaac_debug_fops = {
+	.read = audaac_debug_read,
+	.open = audaac_debug_open,
+};
+#endif
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = NULL;
+	int rc, dec_attrb, decid, index, offset = 0;
+	unsigned pmem_sz = DMASZ;
+	struct audaac_event *e_node = NULL;
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_aac_" + 5];
+#endif
+
+	/* Allocate audio instance, set to zero */
+	audio = kzalloc(sizeof(struct audio), GFP_KERNEL);
+	if (!audio) {
+		MM_ERR("no memory to allocate audio instance \n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	MM_INFO("audio instance 0x%08x created\n", (int)audio);
+
+	/* Allocate the decoder */
+	dec_attrb = AUDDEC_DEC_AAC;
+	if ((file->f_mode & FMODE_WRITE) &&
+			(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_NONTUNNEL;
+		audio->pcm_feedback = NON_TUNNEL_MODE_PLAYBACK;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_TUNNEL;
+		audio->pcm_feedback = TUNNEL_MODE_PLAYBACK;
+	} else {
+		kfree(audio);
+		rc = -EACCES;
+		goto done;
+	}
+	decid = audpp_adec_alloc(dec_attrb, &audio->module_name,
+			&audio->queue_id);
+
+	if (decid < 0) {
+		MM_ERR("No free decoder available, freeing instance 0x%08x\n",
+				(int)audio);
+		rc = -ENODEV;
+		kfree(audio);
+		goto done;
+	}
+	audio->dec_id = decid & MSM_AUD_DECODER_MASK;
+
+	while (pmem_sz >= DMASZ_MIN) {
+		MM_DBG("pmemsz = %d\n", pmem_sz);
+		audio->phys = allocate_contiguous_ebi_nomap(pmem_sz, SZ_4K);
+		if (audio->phys) {
+			audio->map_v_write = ioremap(audio->phys, pmem_sz);
+			if (IS_ERR(audio->map_v_write)) {
+				MM_ERR("could not map write buffers, \
+						freeing instance 0x%08x\n",
+						(int)audio);
+				rc = -ENOMEM;
+				free_contiguous_memory_by_paddr(audio->phys);
+				audpp_adec_free(audio->dec_id);
+				kfree(audio);
+				goto done;
+			}
+			audio->data = audio->map_v_write;
+			MM_DBG("write buf: phy addr 0x%08x kernel addr \
+				0x%08x\n", audio->phys, (int)audio->data);
+			break;
+		} else if (pmem_sz == DMASZ_MIN) {
+			MM_ERR("could not allocate write buffers, freeing \
+					instance 0x%08x\n", (int)audio);
+			rc = -ENOMEM;
+			audpp_adec_free(audio->dec_id);
+			kfree(audio);
+			goto done;
+		} else
+			pmem_sz >>= 1;
+	}
+	audio->out_dma_sz = pmem_sz;
+
+	audio->read_phys = allocate_contiguous_ebi_nomap(PCM_BUFSZ_MIN *
+						PCM_BUF_MAX_COUNT, SZ_4K);
+	if (!audio->read_phys) {
+		MM_ERR("could not allocate read buffers, freeing instance \
+				0x%08x\n", (int)audio);
+		rc = -ENOMEM;
+		iounmap(audio->map_v_write);
+		free_contiguous_memory_by_paddr(audio->phys);
+		audpp_adec_free(audio->dec_id);
+		kfree(audio);
+		goto done;
+	}
+	audio->map_v_read = ioremap(audio->read_phys,
+					PCM_BUFSZ_MIN * PCM_BUF_MAX_COUNT);
+	if (IS_ERR(audio->map_v_read)) {
+		MM_ERR("could not map read buffers, freeing instance \
+				0x%08x\n", (int)audio);
+		rc = -ENOMEM;
+		iounmap(audio->map_v_write);
+		free_contiguous_memory_by_paddr(audio->phys);
+		free_contiguous_memory_by_paddr(audio->read_phys);
+		audpp_adec_free(audio->dec_id);
+		kfree(audio);
+		goto done;
+	}
+	audio->read_data = audio->map_v_read;
+	MM_DBG("read buf: phy addr 0x%08x kernel addr 0x%08x\n",
+				audio->read_phys, (int)audio->read_data);
+
+	if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
+		rc = audmgr_open(&audio->audmgr);
+		if (rc) {
+			MM_ERR("audmgr open failed, freeing instance \
+					0x%08x\n", (int)audio);
+			goto err;
+		}
+	}
+
+	rc = msm_adsp_get(audio->module_name, &audio->audplay,
+			  &audplay_adsp_ops_aac, audio);
+	if (rc) {
+		MM_ERR("failed to get %s module, freeing instance 0x%08x\n",
+				audio->module_name, (int)audio);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_close(&audio->audmgr);
+		goto err;
+	}
+
+	rc = rmt_get_resource(audio);
+	if (rc) {
+		MM_ERR("ADSP resources are not available for AAC session \
+			 0x%08x on decoder: %d\n", (int)audio, audio->dec_id);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_close(&audio->audmgr);
+		msm_adsp_put(audio->audplay);
+		goto err;
+	}
+
+	mutex_init(&audio->lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->get_event_lock);
+	spin_lock_init(&audio->dsp_lock);
+	spin_lock_init(&audio->event_queue_lock);
+	INIT_LIST_HEAD(&audio->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+	init_waitqueue_head(&audio->write_wait);
+	init_waitqueue_head(&audio->read_wait);
+	init_waitqueue_head(&audio->wait);
+	init_waitqueue_head(&audio->event_wait);
+
+	audio->out[0].data = audio->data + 0;
+	audio->out[0].addr = audio->phys + 0;
+	audio->out[0].size = audio->out_dma_sz >> 1;
+
+	audio->out[1].data = audio->data + audio->out[0].size;
+	audio->out[1].addr = audio->phys + audio->out[0].size;
+	audio->out[1].size = audio->out[0].size;
+
+	audio->pcm_buf_count = PCM_BUF_MAX_COUNT;
+	for (index = 0; index < PCM_BUF_MAX_COUNT; index++) {
+		audio->in[index].data = audio->read_data + offset;
+		audio->in[index].addr = audio->read_phys + offset;
+		audio->in[index].size = PCM_BUFSZ_MIN;
+		audio->in[index].used = 0;
+		offset += PCM_BUFSZ_MIN;
+	}
+
+	audio->out_sample_rate = 44100;
+	audio->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V;
+	audio->aac_config.format = AUDIO_AAC_FORMAT_ADTS;
+	audio->aac_config.audio_object = AUDIO_AAC_OBJECT_LC;
+	audio->aac_config.ep_config = 0;
+	audio->aac_config.aac_section_data_resilience_flag =
+		AUDIO_AAC_SEC_DATA_RES_OFF;
+	audio->aac_config.aac_scalefactor_data_resilience_flag =
+		AUDIO_AAC_SCA_DATA_RES_OFF;
+	audio->aac_config.aac_spectral_data_resilience_flag =
+		AUDIO_AAC_SPEC_DATA_RES_OFF;
+#ifdef CONFIG_AUDIO_AAC_PLUS
+	audio->aac_config.sbr_on_flag = AUDIO_AAC_SBR_ON_FLAG_ON;
+#else
+	audio->aac_config.sbr_on_flag = AUDIO_AAC_SBR_ON_FLAG_OFF;
+#endif
+#ifdef CONFIG_AUDIO_ENHANCED_AAC_PLUS
+	audio->aac_config.sbr_ps_on_flag = AUDIO_AAC_SBR_PS_ON_FLAG_ON;
+#else
+	audio->aac_config.sbr_ps_on_flag = AUDIO_AAC_SBR_PS_ON_FLAG_OFF;
+#endif
+	audio->aac_config.dual_mono_mode = AUDIO_AAC_DUAL_MONO_PL_SR;
+	audio->aac_config.channel_configuration = 2;
+	audio->vol_pan.volume = 0x2000;
+
+	audio_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_aac_%04x", audio->dec_id);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+				NULL, (void *) audio,
+				&audaac_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		MM_DBG("debugfs_create_file failed\n");
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	audio->suspend_ctl.node.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+	audio->suspend_ctl.node.resume = audaac_resume;
+	audio->suspend_ctl.node.suspend = audaac_suspend;
+	audio->suspend_ctl.audio = audio;
+	register_early_suspend(&audio->suspend_ctl.node);
+#endif
+	for (index = 0; index < AUDAAC_EVENT_NUM; index++) {
+		e_node = kmalloc(sizeof(struct audaac_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			MM_ERR("event pkt alloc failed\n");
+			break;
+		}
+	}
+	memset(&audio->stream_info, 0, sizeof(struct msm_audio_bitstream_info));
+done:
+	return rc;
+err:
+	iounmap(audio->map_v_write);
+	free_contiguous_memory_by_paddr(audio->phys);
+	iounmap(audio->map_v_read);
+	free_contiguous_memory_by_paddr(audio->read_phys);
+	audpp_adec_free(audio->dec_id);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_aac_fops = {
+	.owner = THIS_MODULE,
+	.open = audio_open,
+	.release = audio_release,
+	.read = audio_read,
+	.write = audio_write,
+	.unlocked_ioctl = audio_ioctl,
+	.fsync = audaac_fsync
+};
+
+struct miscdevice audio_aac_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_aac",
+	.fops = &audio_aac_fops,
+};
+
+static int __init audio_init(void)
+{
+	return misc_register(&audio_aac_misc);
+}
+
+static void __exit audio_exit(void)
+{
+	misc_deregister(&audio_aac_misc);
+}
+
+module_init(audio_init);
+module_exit(audio_exit);
+
+MODULE_DESCRIPTION("MSM AAC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5/audio_aac_in.c b/arch/arm/mach-msm/qdsp5/audio_aac_in.c
new file mode 100644
index 0000000..79a828a
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_aac_in.c
@@ -0,0 +1,1459 @@
+/* arch/arm/mach-msm/qdsp5/audio_aac_in.c
+ *
+ * aac audio input device
+ *
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This code is based in part on arch/arm/mach-msm/qdsp5v2/audio_aac_in.c,
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ *
+ * 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.
+ *
+ */
+
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/msm_audio_aac.h>
+#include <linux/android_pmem.h>
+#include <linux/memory_alloc.h>
+
+#include "audmgr.h"
+
+#include <mach/msm_rpcrouter.h>
+#include <mach/msm_memtypes.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+
+#include <mach/msm_adsp.h>
+#include <mach/qdsp5/qdsp5audpreproc.h>
+#include <mach/qdsp5/qdsp5audpreproccmdi.h>
+#include <mach/qdsp5/qdsp5audpreprocmsg.h>
+#include <mach/qdsp5/qdsp5audreccmdi.h>
+#include <mach/qdsp5/qdsp5audrecmsg.h>
+#include <mach/debug_mm.h>
+
+#define FRAME_HEADER_SIZE	8 /* 8 bytes frame header */
+#define NT_FRAME_HEADER_SIZE	24 /* 24 bytes frame header */
+/* FRAME_NUM must be a power of two */
+#define FRAME_NUM	8
+#define AAC_FRAME_SIZE	1536 /* 36 bytes data */
+/*Tunnel mode : 1536 bytes data + 8 byte header*/
+#define FRAME_SIZE	(AAC_FRAME_SIZE + FRAME_HEADER_SIZE)
+/* 1536 bytes data  + 24 meta field*/
+#define NT_FRAME_SIZE	(AAC_FRAME_SIZE + NT_FRAME_HEADER_SIZE)
+#define DMASZ		(FRAME_SIZE * FRAME_NUM)
+#define NT_DMASZ	(NT_FRAME_SIZE * FRAME_NUM)
+#define OUT_FRAME_NUM	2
+#define OUT_BUFFER_SIZE (32 * 1024 + NT_FRAME_HEADER_SIZE)
+#define BUFFER_SIZE	(OUT_BUFFER_SIZE * OUT_FRAME_NUM)
+
+#define AUDPREPROC_AAC_EOS_FLG_OFFSET 0x0A /* Offset from beginning of buffer*/
+#define AUDPREPROC_AAC_EOS_FLG_MASK 0x01
+#define AUDPREPROC_AAC_EOS_NONE 0x0 /* No EOS detected */
+#define AUDPREPROC_AAC_EOS_SET 0x1 /* EOS set in meta field */
+
+struct buffer {
+	void *data;
+	uint32_t size;
+	uint32_t read;
+	uint32_t addr;
+	uint32_t used;
+	uint32_t mfield_sz;
+};
+
+struct audio_aac_in {
+	struct buffer in[FRAME_NUM];
+
+	spinlock_t dsp_lock;
+
+	atomic_t in_bytes;
+	atomic_t in_samples;
+
+	struct mutex lock;
+	struct mutex read_lock;
+	wait_queue_head_t wait;
+	wait_queue_head_t wait_enable;
+	/*write section*/
+	struct buffer out[OUT_FRAME_NUM];
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed;	/* number of buffers the dsp is waiting for */
+	uint32_t out_count;
+
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+	int32_t out_phys; /* physical address of write buffer */
+	char *out_data;
+	int mfield; /* meta field embedded in data */
+	int wflush; /*write flush */
+	int rflush; /*read flush*/
+	int out_frame_cnt;
+
+	struct msm_adsp_module *audrec;
+	struct msm_adsp_module *audpre;
+
+
+	/* configuration to use on next enable */
+	uint32_t samp_rate;
+	uint32_t channel_mode;
+	uint32_t buffer_size; /* Frame size (1536 bytes) */
+	uint32_t bit_rate; /* bit rate for AAC */
+	uint32_t record_quality; /* record quality (bits/sample/channel) */
+	uint32_t enc_type; /* 1 for AAC */
+	uint32_t mode; /* T or NT Mode*/
+	uint32_t dsp_cnt;
+	uint32_t in_head; /* next buffer dsp will write */
+	uint32_t in_tail; /* next buffer read() will read */
+	uint32_t in_count; /* number of buffers available to read() */
+
+	uint32_t eos_ack;
+	uint32_t flush_ack;
+
+	const char *module_name;
+	unsigned queue_ids;
+	uint16_t enc_id; /* Session Id */
+
+	unsigned short samp_rate_index;
+	uint32_t audrec_obj_idx ;
+
+	struct audmgr audmgr;
+
+	/* data allocated for various buffers */
+	char *data;
+	dma_addr_t phys;
+	void *map_v_read;
+	void *map_v_write;
+
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+};
+
+struct audio_frame {
+	uint16_t frame_count_lsw;
+	uint16_t frame_count_msw;
+	uint16_t frame_length;
+	uint16_t erased_pcm;
+	unsigned char raw_bitstream[];
+} __packed;
+
+struct audio_frame_nt {
+	uint16_t metadata_len;
+	uint16_t frame_count_lsw;
+	uint16_t frame_count_msw;
+	uint16_t frame_length;
+	uint16_t erased_pcm;
+	uint16_t reserved;
+	uint16_t time_stamp_dword_lsw;
+	uint16_t time_stamp_dword_msw;
+	uint16_t time_stamp_lsw;
+	uint16_t time_stamp_msw;
+	uint16_t nflag_lsw;
+	uint16_t nflag_msw;
+	unsigned char raw_bitstream[]; /* samples */
+} __packed;
+
+struct aac_encoded_meta_out {
+	uint16_t metadata_len;
+	uint16_t time_stamp_dword_lsw;
+	uint16_t time_stamp_dword_msw;
+	uint16_t time_stamp_lsw;
+	uint16_t time_stamp_msw;
+	uint16_t nflag_lsw;
+	uint16_t nflag_msw;
+};
+
+/* Audrec Queue command sent macro's */
+#define audio_send_queue_pre(audio, cmd, len) \
+	msm_adsp_write(audio->audpre, QDSP_uPAudPreProcCmdQueue, cmd, len)
+
+#define audio_send_queue_recbs(audio, cmd, len) \
+	msm_adsp_write(audio->audrec, ((audio->queue_ids & 0xFFFF0000) >> 16),\
+			cmd, len)
+#define audio_send_queue_rec(audio, cmd, len) \
+	msm_adsp_write(audio->audrec, (audio->queue_ids & 0x0000FFFF),\
+			cmd, len)
+
+static int audaac_in_dsp_enable(struct audio_aac_in *audio, int enable);
+static int audaac_in_encparam_config(struct audio_aac_in *audio);
+static int audaac_in_encmem_config(struct audio_aac_in *audio);
+static int audaac_in_dsp_read_buffer(struct audio_aac_in *audio,
+				uint32_t read_cnt);
+static void audaac_in_flush(struct audio_aac_in *audio);
+
+static void audaac_in_get_dsp_frames(struct audio_aac_in *audio);
+static int audpcm_config(struct audio_aac_in *audio);
+static void audaac_out_flush(struct audio_aac_in *audio);
+static int audaac_in_routing_mode_config(struct audio_aac_in *audio);
+static void audrec_pcm_send_data(struct audio_aac_in *audio, unsigned needed);
+static void audaac_nt_in_get_dsp_frames(struct audio_aac_in *audio);
+static void audaac_in_flush(struct audio_aac_in *audio);
+
+static unsigned convert_dsp_samp_index(unsigned index)
+{
+	switch (index) {
+	case 48000:	return AUDREC_CMD_SAMP_RATE_INDX_48000;
+	case 44100:	return AUDREC_CMD_SAMP_RATE_INDX_44100;
+	case 32000:	return AUDREC_CMD_SAMP_RATE_INDX_32000;
+	case 24000:	return AUDREC_CMD_SAMP_RATE_INDX_24000;
+	case 22050:	return AUDREC_CMD_SAMP_RATE_INDX_22050;
+	case 16000:	return AUDREC_CMD_SAMP_RATE_INDX_16000;
+	case 12000:	return AUDREC_CMD_SAMP_RATE_INDX_12000;
+	case 11025:	return AUDREC_CMD_SAMP_RATE_INDX_11025;
+	case 8000:	return AUDREC_CMD_SAMP_RATE_INDX_8000;
+	default:	return AUDREC_CMD_SAMP_RATE_INDX_11025;
+	}
+}
+
+static unsigned convert_samp_rate(unsigned hz)
+{
+	switch (hz) {
+	case 48000: return RPC_AUD_DEF_SAMPLE_RATE_48000;
+	case 44100: return RPC_AUD_DEF_SAMPLE_RATE_44100;
+	case 32000: return RPC_AUD_DEF_SAMPLE_RATE_32000;
+	case 24000: return RPC_AUD_DEF_SAMPLE_RATE_24000;
+	case 22050: return RPC_AUD_DEF_SAMPLE_RATE_22050;
+	case 16000: return RPC_AUD_DEF_SAMPLE_RATE_16000;
+	case 12000: return RPC_AUD_DEF_SAMPLE_RATE_12000;
+	case 11025: return RPC_AUD_DEF_SAMPLE_RATE_11025;
+	case 8000:  return RPC_AUD_DEF_SAMPLE_RATE_8000;
+	default:    return RPC_AUD_DEF_SAMPLE_RATE_11025;
+	}
+}
+
+static unsigned convert_samp_index(unsigned index)
+{
+	switch (index) {
+	case RPC_AUD_DEF_SAMPLE_RATE_48000:	return 48000;
+	case RPC_AUD_DEF_SAMPLE_RATE_44100:	return 44100;
+	case RPC_AUD_DEF_SAMPLE_RATE_32000:	return 32000;
+	case RPC_AUD_DEF_SAMPLE_RATE_24000:	return 24000;
+	case RPC_AUD_DEF_SAMPLE_RATE_22050:	return 22050;
+	case RPC_AUD_DEF_SAMPLE_RATE_16000:	return 16000;
+	case RPC_AUD_DEF_SAMPLE_RATE_12000:	return 12000;
+	case RPC_AUD_DEF_SAMPLE_RATE_11025:	return 11025;
+	case RPC_AUD_DEF_SAMPLE_RATE_8000:	return 8000;
+	default:				return 11025;
+	}
+}
+
+/* Convert Bit Rate to Record Quality field of DSP */
+static unsigned int bitrate_to_record_quality(unsigned int sample_rate,
+		unsigned int channel, unsigned int bit_rate) {
+	unsigned int temp;
+
+	temp = sample_rate * channel;
+	MM_DBG(" sample rate *  channel = %d\n", temp);
+	/* To represent in Q12 fixed format */
+	temp = (bit_rate * 4096) / temp;
+	MM_DBG(" Record Quality = 0x%8x\n", temp);
+	return temp;
+}
+
+/* must be called with audio->lock held */
+static int audaac_in_enable(struct audio_aac_in *audio)
+{
+	struct audmgr_config cfg;
+	int rc;
+
+	if (audio->enabled)
+		return 0;
+
+	cfg.tx_rate = audio->samp_rate;
+	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+	cfg.def_method = RPC_AUD_DEF_METHOD_RECORD;
+	cfg.codec = RPC_AUD_DEF_CODEC_AAC;
+	cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+		rc = audmgr_enable(&audio->audmgr, &cfg);
+		if (rc < 0)
+			return rc;
+
+		if (msm_adsp_enable(audio->audpre)) {
+			audmgr_disable(&audio->audmgr);
+			MM_ERR("msm_adsp_enable(audpre) failed\n");
+			return -ENODEV;
+		}
+	}
+	if (msm_adsp_enable(audio->audrec)) {
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+			audmgr_disable(&audio->audmgr);
+			msm_adsp_disable(audio->audpre);
+		}
+		MM_ERR("msm_adsp_enable(audrec) failed\n");
+		return -ENODEV;
+	}
+
+	audio->enabled = 1;
+	audaac_in_dsp_enable(audio, 1);
+
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audaac_in_disable(struct audio_aac_in *audio)
+{
+	if (audio->enabled) {
+		audio->enabled = 0;
+
+		audaac_in_dsp_enable(audio, 0);
+
+		wait_event_interruptible_timeout(audio->wait_enable,
+				audio->running == 0, 1*HZ);
+		audio->stopped = 1;
+		wake_up(&audio->wait);
+		msm_adsp_disable(audio->audrec);
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+			msm_adsp_disable(audio->audpre);
+			audmgr_disable(&audio->audmgr);
+		}
+	}
+	return 0;
+}
+
+/* ------------------- dsp --------------------- */
+static void audpre_dsp_event(void *data, unsigned id, size_t len,
+			    void (*getevent)(void *ptr, size_t len))
+{
+	uint16_t msg[2];
+	getevent(msg, sizeof(msg));
+
+	switch (id) {
+	case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
+		MM_DBG("type %d, status_flag %d\n", msg[0], msg[1]);
+		break;
+	case AUDPREPROC_MSG_ERROR_MSG_ID:
+		MM_ERR("err_index %d\n", msg[0]);
+		break;
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audpreproctask)\n");
+		break;
+	default:
+		MM_ERR("unknown event %d\n", id);
+	}
+}
+
+
+static void audaac_in_get_dsp_frames(struct audio_aac_in *audio)
+{
+	struct audio_frame *frame;
+	uint32_t index;
+	unsigned long flags;
+
+	index = audio->in_head;
+
+	frame = (void *) (((char *)audio->in[index].data) -
+			sizeof(*frame));
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->in[index].size = frame->frame_length;
+
+	/* statistics of read */
+	atomic_add(audio->in[index].size, &audio->in_bytes);
+	atomic_add(1, &audio->in_samples);
+
+	audio->in_head = (audio->in_head + 1) & (FRAME_NUM - 1);
+
+	/* If overflow, move the tail index foward. */
+	if (audio->in_head == audio->in_tail) {
+		MM_ERR("Error! not able to keep up the read\n");
+		audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
+		MM_ERR("in_count = %d\n", audio->in_count);
+	} else
+		audio->in_count++;
+
+	audaac_in_dsp_read_buffer(audio, audio->dsp_cnt++);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+
+	wake_up(&audio->wait);
+}
+
+static void audaac_nt_in_get_dsp_frames(struct audio_aac_in *audio)
+{
+	struct audio_frame_nt *nt_frame;
+	uint32_t index;
+	unsigned long flags;
+
+	index = audio->in_head;
+	nt_frame = (void *) (((char *)audio->in[index].data) - \
+				sizeof(struct audio_frame_nt));
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->in[index].size = nt_frame->frame_length;
+	/* statistics of read */
+	atomic_add(audio->in[index].size, &audio->in_bytes);
+	atomic_add(1, &audio->in_samples);
+
+	audio->in_head = (audio->in_head + 1) & (FRAME_NUM - 1);
+
+	/* If overflow, move the tail index foward. */
+	if (audio->in_head == audio->in_tail)
+		MM_DBG("Error! not able to keep up the read\n");
+	else
+		audio->in_count++;
+
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	wake_up(&audio->wait);
+}
+
+static int audrec_pcm_buffer_ptr_refresh(struct audio_aac_in *audio,
+				       unsigned idx, unsigned len)
+{
+	struct audrec_cmd_pcm_buffer_ptr_refresh_arm_enc cmd;
+
+	if (len ==  NT_FRAME_HEADER_SIZE)
+		len = len / 2;
+	else
+		len = (len + NT_FRAME_HEADER_SIZE) / 2;
+	MM_DBG("len = %d\n", len);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_PCM_BUFFER_PTR_REFRESH_ARM_TO_ENC;
+	cmd.num_buffers = 1;
+	if (cmd.num_buffers == 1) {
+		cmd.buf_address_length[0] = (audio->out[idx].addr &
+							0xffff0000) >> 16;
+		cmd.buf_address_length[1] = (audio->out[idx].addr &
+							0x0000ffff);
+		cmd.buf_address_length[2] = (len & 0xffff0000) >> 16;
+		cmd.buf_address_length[3] = (len & 0x0000ffff);
+	}
+	audio->out_frame_cnt++;
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static int audpcm_config(struct audio_aac_in *audio)
+{
+	struct audrec_cmd_pcm_cfg_arm_to_enc cmd;
+	MM_DBG("\n");
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_PCM_CFG_ARM_TO_ENC;
+	cmd.config_update_flag = AUDREC_PCM_CONFIG_UPDATE_FLAG_ENABLE;
+	cmd.enable_flag = AUDREC_ENABLE_FLAG_VALUE;
+	cmd.sampling_freq = convert_samp_index(audio->samp_rate);
+	if (!audio->channel_mode)
+		cmd.channels = 1;
+	else
+		cmd.channels = 2;
+	cmd.frequency_of_intimation = 1;
+	cmd.max_number_of_buffers = OUT_FRAME_NUM;
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static int audaac_in_routing_mode_config(struct audio_aac_in *audio)
+{
+	struct audrec_cmd_routing_mode cmd;
+
+	MM_DBG("\n");
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_ROUTING_MODE;
+	if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)
+		cmd.routing_mode = 1;
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static void audrec_dsp_event(void *data, unsigned id, size_t len,
+			    void (*getevent)(void *ptr, size_t len))
+{
+	struct audio_aac_in *audio = NULL;
+	if (data)
+		audio = data;
+	else {
+		MM_ERR("invalid data for event %x\n", id);
+		return;
+	}
+
+	switch (id) {
+	case AUDREC_MSG_CMD_CFG_DONE_MSG: {
+		struct audrec_msg_cmd_cfg_done_msg cmd_cfg_done_msg;
+		getevent(&cmd_cfg_done_msg, AUDREC_MSG_CMD_CFG_DONE_MSG_LEN);
+		if (cmd_cfg_done_msg.audrec_enc_type & \
+				AUDREC_MSG_CFG_DONE_ENC_ENA) {
+			audio->audrec_obj_idx = cmd_cfg_done_msg.audrec_obj_idx;
+			MM_DBG("CFG ENABLED\n");
+			if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
+				MM_DBG("routing command\n");
+				audaac_in_routing_mode_config(audio);
+			} else {
+				audaac_in_encmem_config(audio);
+			}
+		} else {
+			MM_DBG("CFG SLEEP\n");
+			audio->running = 0;
+			wake_up(&audio->wait_enable);
+		}
+		break;
+	}
+	case AUDREC_MSG_CMD_ROUTING_MODE_DONE_MSG: {
+		struct audrec_msg_cmd_routing_mode_done_msg \
+			routing_msg;
+		getevent(&routing_msg, AUDREC_MSG_CMD_ROUTING_MODE_DONE_MSG);
+		MM_DBG("AUDREC_MSG_CMD_ROUTING_MODE_DONE_MSG");
+		if (routing_msg.configuration == 0) {
+			MM_ERR("routing configuration failed\n");
+			audio->running = 0;
+			wake_up(&audio->wait_enable);
+		} else
+			audaac_in_encmem_config(audio);
+		break;
+	}
+	case AUDREC_MSG_CMD_AREC_MEM_CFG_DONE_MSG: {
+		MM_DBG("AREC_MEM_CFG_DONE_MSG\n");
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
+			audaac_in_encparam_config(audio);
+		else
+			audpcm_config(audio);
+		break;
+	}
+	case AUDREC_CMD_PCM_CFG_ARM_TO_ENC_DONE_MSG: {
+		MM_DBG("AUDREC_CMD_PCM_CFG_ARM_TO_ENC_DONE_MSG");
+		audaac_in_encparam_config(audio);
+	    break;
+	}
+	case AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG: {
+		MM_DBG("AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG\n");
+		audio->running = 1;
+		wake_up(&audio->wait_enable);
+		if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)
+			audrec_pcm_send_data(audio, 1);
+		break;
+	}
+	case AUDREC_CMD_PCM_BUFFER_PTR_UPDATE_ARM_TO_ENC_MSG: {
+		MM_DBG("ptr_update recieved from DSP\n");
+		audrec_pcm_send_data(audio, 1);
+		break;
+	}
+	case AUDREC_MSG_NO_EXT_PKT_AVAILABLE_MSG: {
+		struct audrec_msg_no_ext_pkt_avail_msg err_msg;
+		getevent(&err_msg, AUDREC_MSG_NO_EXT_PKT_AVAILABLE_MSG_LEN);
+		MM_DBG("NO_EXT_PKT_AVAILABLE_MSG %x\n",\
+			err_msg.audrec_err_id);
+		break;
+	}
+	case AUDREC_MSG_PACKET_READY_MSG: {
+		struct audrec_msg_packet_ready_msg pkt_ready_msg;
+
+		getevent(&pkt_ready_msg, AUDREC_MSG_PACKET_READY_MSG_LEN);
+		MM_DBG("UP_PACKET_READY_MSG: write cnt msw  %d \
+		write cnt lsw %d read cnt msw %d  read cnt lsw %d \n",\
+		pkt_ready_msg.pkt_counter_msw, \
+		pkt_ready_msg.pkt_counter_lsw, \
+		pkt_ready_msg.pkt_read_cnt_msw, \
+		pkt_ready_msg.pkt_read_cnt_lsw);
+
+		audaac_in_get_dsp_frames(audio);
+		break;
+	}
+	case AUDREC_UP_NT_PACKET_READY_MSG: {
+		struct audrec_up_nt_packet_ready_msg pkt_ready_msg;
+
+		getevent(&pkt_ready_msg, AUDREC_UP_NT_PACKET_READY_MSG_LEN);
+		MM_DBG("UP_NT_PACKET_READY_MSG: write cnt lsw  %d \
+		write cnt msw %d read cnt lsw %d  read cnt msw %d \n",\
+		pkt_ready_msg.audrec_packetwrite_cnt_lsw, \
+		pkt_ready_msg.audrec_packetwrite_cnt_msw, \
+		pkt_ready_msg.audrec_upprev_readcount_lsw, \
+		pkt_ready_msg.audrec_upprev_readcount_msw);
+
+		audaac_nt_in_get_dsp_frames(audio);
+		break;
+	}
+	case AUDREC_CMD_FLUSH_DONE_MSG: {
+		audio->wflush = 0;
+		audio->rflush = 0;
+		audio->flush_ack = 1;
+		wake_up(&audio->write_wait);
+		MM_DBG("flush ack recieved\n");
+		break;
+	}
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module \
+				enable/disable(audrectask)\n");
+		break;
+	default:
+		MM_ERR("unknown event %d\n", id);
+	}
+}
+
+struct msm_adsp_ops audpre_aac_adsp_ops = {
+	.event = audpre_dsp_event,
+};
+
+struct msm_adsp_ops audrec_aac_adsp_ops = {
+	.event = audrec_dsp_event,
+};
+
+static int audaac_in_dsp_enable(struct audio_aac_in *audio, int enable)
+{
+	struct audrec_cmd_enc_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_ENC_CFG;
+	cmd.audrec_enc_type = (audio->enc_type & 0xFF) |
+			(enable ? AUDREC_CMD_ENC_ENA : AUDREC_CMD_ENC_DIS);
+	/* Don't care */
+	cmd.audrec_obj_idx = audio->audrec_obj_idx;
+
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static int audaac_in_encmem_config(struct audio_aac_in *audio)
+{
+	struct audrec_cmd_arecmem_cfg cmd;
+	uint16_t *data = (void *) audio->data;
+	int n;
+	int header_len = 0;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	cmd.cmd_id = AUDREC_CMD_ARECMEM_CFG;
+	cmd.audrec_obj_idx = audio->audrec_obj_idx;
+	/* Rate at which packet complete message comes */
+	cmd.audrec_up_pkt_intm_cnt = 1;
+	cmd.audrec_extpkt_buffer_msw = audio->phys >> 16;
+	cmd.audrec_extpkt_buffer_lsw = audio->phys;
+	/* Max Buffer no available for frames */
+	cmd.audrec_extpkt_buffer_num = FRAME_NUM;
+
+	/* prepare buffer pointers:
+	 * T:1536 bytes aac packet + 4 halfword header
+	 * NT:1536 bytes aac packet + 12 halfword header
+	 */
+	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
+		header_len = FRAME_HEADER_SIZE/2;
+	else
+		header_len = NT_FRAME_HEADER_SIZE/2;
+
+	for (n = 0; n < FRAME_NUM; n++) {
+		audio->in[n].data = data + header_len;
+		data += (AAC_FRAME_SIZE/2) + header_len;
+		MM_DBG("0x%8x\n", (int)(audio->in[n].data - header_len*2));
+	}
+
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static int audaac_in_encparam_config(struct audio_aac_in *audio)
+{
+	struct audrec_cmd_arecparam_aac_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDREC_CMD_ARECPARAM_CFG;
+	cmd.common.audrec_obj_idx = audio->audrec_obj_idx;
+	cmd.samp_rate_idx = audio->samp_rate_index;
+	cmd.stereo_mode = audio->channel_mode;
+	cmd.rec_quality = audio->record_quality;
+
+
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static int audaac_flush_command(struct audio_aac_in *audio)
+{
+	struct audrec_cmd_flush cmd;
+	MM_DBG("\n");
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_FLUSH;
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static int audaac_in_dsp_read_buffer(struct audio_aac_in *audio,
+		uint32_t read_cnt)
+{
+	audrec_cmd_packet_ext_ptr cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_PACKET_EXT_PTR;
+	cmd.type = audio->audrec_obj_idx;
+	cmd.curr_rec_count_msw = read_cnt >> 16;
+	cmd.curr_rec_count_lsw = read_cnt;
+
+	return audio_send_queue_recbs(audio, &cmd, sizeof(cmd));
+}
+
+/* ------------------- device --------------------- */
+
+static void audaac_ioport_reset(struct audio_aac_in *audio)
+{
+	/* Make sure read/write thread are free from
+	 * sleep and knowing that system is not able
+	 * to process io request at the moment
+	 */
+	wake_up(&audio->wait);
+	mutex_lock(&audio->read_lock);
+	audaac_in_flush(audio);
+	mutex_unlock(&audio->read_lock);
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audaac_out_flush(audio);
+	mutex_unlock(&audio->write_lock);
+}
+
+static void audaac_in_flush(struct audio_aac_in *audio)
+{
+	int i;
+	unsigned long flags;
+
+	audio->dsp_cnt = 0;
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->in_head = 0;
+	audio->in_tail = 0;
+	audio->in_count = 0;
+	audio->eos_ack = 0;
+	for (i = FRAME_NUM-1; i >= 0; i--) {
+		audio->in[i].size = 0;
+		audio->in[i].read = 0;
+	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	MM_DBG("in_bytes %d\n", atomic_read(&audio->in_bytes));
+	MM_DBG("in_samples %d\n", atomic_read(&audio->in_samples));
+	atomic_set(&audio->in_bytes, 0);
+	atomic_set(&audio->in_samples, 0);
+}
+
+static void audaac_out_flush(struct audio_aac_in *audio)
+{
+	int i;
+	unsigned long flags;
+
+	audio->out_head = 0;
+	audio->out_count = 0;
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->out_tail = 0;
+	for (i = OUT_FRAME_NUM-1; i >= 0; i--) {
+		audio->out[i].size = 0;
+		audio->out[i].read = 0;
+		audio->out[i].used = 0;
+	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+static long audaac_in_ioctl(struct file *file,
+				unsigned int cmd, unsigned long arg)
+{
+	struct audio_aac_in *audio = file->private_data;
+	int rc = 0;
+
+	MM_DBG("\n");
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = atomic_read(&audio->in_bytes);
+		stats.sample_count = atomic_read(&audio->in_samples);
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return rc;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START: {
+		rc = audaac_in_enable(audio);
+		if (!rc) {
+			rc =
+			wait_event_interruptible_timeout(audio->wait_enable,
+				audio->running != 0, 1*HZ);
+			MM_DBG("state %d rc = %d\n", audio->running, rc);
+
+			if (audio->running == 0)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		audio->stopped = 0;
+		break;
+	}
+	case AUDIO_STOP: {
+		rc = audaac_in_disable(audio);
+		break;
+	}
+	case AUDIO_FLUSH: {
+		MM_DBG("AUDIO_FLUSH\n");
+		audio->rflush = 1;
+		audio->wflush = 1;
+		audaac_ioport_reset(audio);
+		if (audio->running) {
+			audaac_flush_command(audio);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config cfg;
+		memset(&cfg, 0, sizeof(cfg));
+		cfg.buffer_size = OUT_BUFFER_SIZE;
+		cfg.buffer_count = OUT_FRAME_NUM;
+		cfg.sample_rate = convert_samp_index(audio->samp_rate);
+		cfg.channel_count = 1;
+		cfg.type = 0;
+		cfg.unused[0] = 0;
+		cfg.unused[1] = 0;
+		cfg.unused[2] = 0;
+		if (copy_to_user((void *) arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	}
+	case AUDIO_GET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		memset(&cfg, 0, sizeof(cfg));
+		cfg.buffer_size = audio->buffer_size;
+		cfg.buffer_count = FRAME_NUM;
+		if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	}
+	case AUDIO_SET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		/* Allow only single frame */
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+			if (cfg.buffer_size != (FRAME_SIZE - 8))
+				rc = -EINVAL;
+				break;
+		} else {
+			if (cfg.buffer_size != (AAC_FRAME_SIZE + 14))
+				rc = -EINVAL;
+				break;
+		}
+		audio->buffer_size = cfg.buffer_size;
+		break;
+	}
+	case AUDIO_GET_AAC_ENC_CONFIG: {
+		struct msm_audio_aac_enc_config cfg;
+		if (audio->channel_mode == AUDREC_CMD_STEREO_MODE_MONO)
+			cfg.channels = 1;
+		else
+			cfg.channels = 2;
+		cfg.sample_rate = convert_samp_index(audio->samp_rate);
+		cfg.bit_rate = audio->bit_rate;
+		cfg.stream_format = AUDIO_AAC_FORMAT_RAW;
+		if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_AAC_ENC_CONFIG: {
+		struct msm_audio_aac_enc_config cfg;
+		unsigned int record_quality;
+		if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (cfg.stream_format != AUDIO_AAC_FORMAT_RAW) {
+			MM_ERR("unsupported AAC format\n");
+			rc = -EINVAL;
+			break;
+		}
+		record_quality = bitrate_to_record_quality(cfg.sample_rate,
+					cfg.channels, cfg.bit_rate);
+		/* Range of Record Quality Supported by DSP, Q12 format */
+		if ((record_quality < 0x800) || (record_quality > 0x4000)) {
+			MM_ERR("Unsupported bit rate\n");
+			rc = -EINVAL;
+			break;
+		}
+		MM_DBG("channels = %d\n", cfg.channels);
+		if (cfg.channels == 1) {
+			cfg.channels = AUDREC_CMD_STEREO_MODE_MONO;
+		} else if (cfg.channels == 2) {
+			cfg.channels = AUDREC_CMD_STEREO_MODE_STEREO;
+		} else {
+			rc = -EINVAL;
+			break;
+		}
+
+		audio->samp_rate = convert_samp_rate(cfg.sample_rate);
+		audio->samp_rate_index =
+		  convert_dsp_samp_index(cfg.sample_rate);
+		audio->channel_mode = cfg.channels;
+		audio->bit_rate = cfg.bit_rate;
+		audio->record_quality = record_quality;
+		MM_DBG(" Record Quality = 0x%8x\n", audio->record_quality);
+		break;
+	}
+
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static ssize_t audaac_in_read(struct file *file,
+				char __user *buf,
+				size_t count, loff_t *pos)
+{
+	struct audio_aac_in *audio = file->private_data;
+	unsigned long flags;
+	const char __user *start = buf;
+	void *data;
+	uint32_t index;
+	uint32_t size;
+	int rc = 0;
+	struct aac_encoded_meta_out meta_field;
+	struct audio_frame_nt *nt_frame;
+	MM_DBG("count = %d\n", count);
+	mutex_lock(&audio->read_lock);
+	while (count > 0) {
+		rc = wait_event_interruptible(
+			audio->wait, (audio->in_count > 0) || audio->stopped ||
+			audio->rflush);
+		if (rc < 0)
+			break;
+
+		if (audio->rflush) {
+			rc = -EBUSY;
+			break;
+		}
+		if (audio->stopped && !audio->in_count) {
+			MM_DBG("Driver in stop state, No more buffer to read");
+			rc = 0;/* End of File */
+			break;
+		}
+
+		index = audio->in_tail;
+		data = (uint8_t *) audio->in[index].data;
+		size = audio->in[index].size;
+
+		if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
+			nt_frame = (struct audio_frame_nt *)(data -
+					sizeof(struct audio_frame_nt));
+			memcpy((char *)&meta_field.time_stamp_dword_lsw,
+				(char *)&nt_frame->time_stamp_dword_lsw,
+				(sizeof(struct aac_encoded_meta_out) - \
+				sizeof(uint16_t)));
+			meta_field.metadata_len =
+					sizeof(struct aac_encoded_meta_out);
+			if (copy_to_user((char *)start, (char *)&meta_field,
+					sizeof(struct aac_encoded_meta_out))) {
+				rc = -EFAULT;
+				break;
+			}
+			if (nt_frame->nflag_lsw & 0x0001) {
+				MM_DBG("recieved EOS in read call\n");
+				audio->eos_ack = 1;
+			}
+			buf += sizeof(struct aac_encoded_meta_out);
+			count -= sizeof(struct aac_encoded_meta_out);
+		}
+		if (count >= size) {
+			/* order the reads on the buffer */
+			dma_coherent_post_ops();
+			if (copy_to_user(buf, data, size)) {
+				rc = -EFAULT;
+				break;
+			}
+			spin_lock_irqsave(&audio->dsp_lock, flags);
+			if (index != audio->in_tail) {
+				/* overrun -- data is
+				 * invalid and we need to retry */
+				spin_unlock_irqrestore(&audio->dsp_lock, flags);
+				continue;
+			}
+			audio->in[index].size = 0;
+			audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
+			audio->in_count--;
+			spin_unlock_irqrestore(&audio->dsp_lock, flags);
+			count -= size;
+			buf += size;
+			if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)) {
+				if (!audio->eos_ack) {
+					MM_DBG("sending read ptr command \
+							%d %d\n",
+							audio->dsp_cnt,
+							audio->in_tail);
+					audaac_in_dsp_read_buffer(audio,
+							audio->dsp_cnt++);
+				}
+			}
+		} else {
+			MM_ERR("short read\n");
+			break;
+		}
+		break;
+	}
+	mutex_unlock(&audio->read_lock);
+
+	if (buf > start)
+		return buf - start;
+
+	return rc;
+}
+
+static void audrec_pcm_send_data(struct audio_aac_in *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+	MM_DBG("\n");
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (needed && !audio->wflush) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			MM_DBG("frame %d free\n", audio->out_tail);
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+			audrec_pcm_buffer_ptr_refresh(audio,
+						 audio->out_tail,
+						    frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+ done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+
+static int audaac_in_fsync(struct file *file, loff_t a, loff_t b, int datasync)
+
+{
+	struct audio_aac_in *audio = file->private_data;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (!audio->running || (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)) {
+		rc = -EINVAL;
+		goto done_nolock;
+	}
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->write_wait,
+			audio->wflush);
+	MM_DBG("waked on by some event audio->wflush = %d\n", audio->wflush);
+
+	if (rc < 0)
+		goto done;
+	else if (audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+done:
+	mutex_unlock(&audio->write_lock);
+done_nolock:
+	return rc;
+
+}
+
+int audrec_aac_process_eos(struct audio_aac_in *audio,
+		const char __user *buf_start, unsigned short mfield_size)
+{
+	struct buffer *frame;
+	int rc = 0;
+
+	frame = audio->out + audio->out_head;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->out_needed &&
+		audio->out[0].used == 0 &&
+		audio->out[1].used == 0)
+		|| (audio->stopped)
+		|| (audio->wflush));
+
+	if (rc < 0)
+		goto done;
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+	if (copy_from_user(frame->data, buf_start, mfield_size)) {
+		rc = -EFAULT;
+		goto done;
+	}
+
+	frame->mfield_sz = mfield_size;
+	audio->out_head ^= 1;
+	frame->used = mfield_size;
+	MM_DBG("copying meta_out frame->used = %d\n", frame->used);
+	audrec_pcm_send_data(audio, 0);
+done:
+	return rc;
+}
+static ssize_t audaac_in_write(struct file *file,
+				const char __user *buf,
+				size_t count, loff_t *pos)
+{
+	struct audio_aac_in *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	char *cpy_ptr;
+	int rc = 0, eos_condition = AUDPREPROC_AAC_EOS_NONE;
+	unsigned short mfield_size = 0;
+	int write_count = 0;
+	MM_DBG("cnt=%d\n", count);
+
+	if (count & 1)
+		return -EINVAL;
+
+	if (audio->mode != MSM_AUD_ENC_MODE_NONTUNNEL)
+		return -EINVAL;
+
+	mutex_lock(&audio->write_lock);
+	frame = audio->out + audio->out_head;
+	/* if supplied count is more than driver buffer size
+	 * then only copy driver buffer size
+	 */
+	if (count > frame->size)
+		count = frame->size;
+
+	write_count = count;
+	cpy_ptr = frame->data;
+	rc = wait_event_interruptible(audio->write_wait,
+				      (frame->used == 0)
+					|| (audio->stopped)
+					|| (audio->wflush));
+	if (rc < 0)
+		goto error;
+
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto error;
+	}
+	if (audio->mfield) {
+		if (buf == start) {
+			/* Processing beginning of user buffer */
+			if (__get_user(mfield_size,
+				(unsigned short __user *) buf)) {
+				rc = -EFAULT;
+				goto error;
+			} else if (mfield_size > count) {
+				rc = -EINVAL;
+				goto error;
+			}
+			MM_DBG("mf offset_val %x\n", mfield_size);
+			if (copy_from_user(cpy_ptr, buf, mfield_size)) {
+				rc = -EFAULT;
+				goto error;
+			}
+			/* Check if EOS flag is set and buffer has
+			 * contains just meta field
+			 */
+			if (cpy_ptr[AUDPREPROC_AAC_EOS_FLG_OFFSET] &
+					AUDPREPROC_AAC_EOS_FLG_MASK) {
+				eos_condition = AUDPREPROC_AAC_EOS_SET;
+				MM_DBG("EOS SET\n");
+				if (mfield_size == count) {
+					buf += mfield_size;
+					eos_condition = 0;
+					goto exit;
+				} else
+				cpy_ptr[AUDPREPROC_AAC_EOS_FLG_OFFSET] &=
+					~AUDPREPROC_AAC_EOS_FLG_MASK;
+			}
+			cpy_ptr += mfield_size;
+			count -= mfield_size;
+			buf += mfield_size;
+		} else {
+			mfield_size = 0;
+			MM_DBG("continuous buffer\n");
+		}
+		frame->mfield_sz = mfield_size;
+	}
+	MM_DBG("copying the stream count = %d\n", count);
+	if (copy_from_user(cpy_ptr, buf, count)) {
+		rc = -EFAULT;
+		goto error;
+	}
+exit:
+	frame->used = count;
+	audio->out_head ^= 1;
+	if (!audio->flush_ack)
+		audrec_pcm_send_data(audio, 0);
+	else {
+		audrec_pcm_send_data(audio, 1);
+		audio->flush_ack = 0;
+	}
+	if (eos_condition == AUDPREPROC_AAC_EOS_SET)
+		rc = audrec_aac_process_eos(audio, start, mfield_size);
+	mutex_unlock(&audio->write_lock);
+	return write_count;
+error:
+	mutex_unlock(&audio->write_lock);
+	return rc;
+}
+
+static int audaac_in_release(struct inode *inode, struct file *file)
+{
+	struct audio_aac_in *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	audaac_in_disable(audio);
+	audaac_in_flush(audio);
+	msm_adsp_put(audio->audrec);
+
+	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
+		msm_adsp_put(audio->audpre);
+
+	audpreproc_aenc_free(audio->enc_id);
+	audio->audrec = NULL;
+	audio->audpre = NULL;
+	audio->opened = 0;
+
+	if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) && \
+	   (audio->out_data)) {
+		iounmap(audio->map_v_write);
+		free_contiguous_memory_by_paddr(audio->out_phys);
+		audio->out_data = NULL;
+	}
+
+	if (audio->data) {
+		iounmap(audio->map_v_read);
+		free_contiguous_memory_by_paddr(audio->phys);
+		audio->data = NULL;
+	}
+	mutex_unlock(&audio->lock);
+	return 0;
+}
+
+struct audio_aac_in the_audio_aac_in;
+
+static int audaac_in_open(struct inode *inode, struct file *file)
+{
+	struct audio_aac_in *audio = &the_audio_aac_in;
+	int rc;
+	int encid;
+	int dma_size = 0;
+
+	mutex_lock(&audio->lock);
+	if (audio->opened) {
+		rc = -EBUSY;
+		goto done;
+	}
+	if ((file->f_mode & FMODE_WRITE) &&
+		(file->f_mode & FMODE_READ)) {
+		audio->mode = MSM_AUD_ENC_MODE_NONTUNNEL;
+		dma_size = NT_DMASZ;
+		MM_DBG("Opened for non tunnel mode encoding\n");
+	} else if (!(file->f_mode & FMODE_WRITE) &&
+				(file->f_mode & FMODE_READ)) {
+		audio->mode = MSM_AUD_ENC_MODE_TUNNEL;
+		dma_size = DMASZ;
+		MM_DBG("Opened for tunnel mode encoding\n");
+	} else {
+		MM_ERR("Invalid mode\n");
+		rc = -EACCES;
+		goto done;
+	}
+
+	/* Settings will be re-config at AUDIO_SET_CONFIG,
+	 * but at least we need to have initial config
+	 */
+	audio->samp_rate = RPC_AUD_DEF_SAMPLE_RATE_11025;
+	audio->samp_rate_index = AUDREC_CMD_SAMP_RATE_INDX_11025;
+
+	/* For AAC, bit rate hard coded, default settings is
+	 * sample rate (11025) x channel count (1) x recording quality (1.75)
+	 * = 19293 bps  */
+	audio->bit_rate = 19293;
+	audio->record_quality = 0x1c00;
+
+	audio->channel_mode = AUDREC_CMD_STEREO_MODE_MONO;
+	if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)
+			audio->buffer_size = (AAC_FRAME_SIZE + 14);
+	else
+			audio->buffer_size = (FRAME_SIZE - 8);
+	audio->enc_type = AUDREC_CMD_TYPE_0_INDEX_AAC | audio->mode;
+
+	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+		rc = audmgr_open(&audio->audmgr);
+		if (rc)
+			goto done;
+	}
+
+	encid = audpreproc_aenc_alloc(audio->enc_type, &audio->module_name,
+			&audio->queue_ids);
+	if (encid < 0) {
+		MM_ERR("No free encoder available\n");
+		rc = -ENODEV;
+		goto done;
+	}
+	audio->enc_id = encid;
+
+	rc = msm_adsp_get(audio->module_name, &audio->audrec,
+			   &audrec_aac_adsp_ops, audio);
+	if (rc) {
+		audpreproc_aenc_free(audio->enc_id);
+		goto done;
+	}
+
+	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+		rc = msm_adsp_get("AUDPREPROCTASK", &audio->audpre,
+				&audpre_aac_adsp_ops, audio);
+		if (rc) {
+			msm_adsp_put(audio->audrec);
+			audpreproc_aenc_free(audio->enc_id);
+			goto done;
+		}
+	}
+
+	audio->dsp_cnt = 0;
+	audio->stopped = 0;
+	audio->wflush = 0;
+	audio->rflush = 0;
+	audio->flush_ack = 0;
+
+	audaac_in_flush(audio);
+	audaac_out_flush(audio);
+
+	audio->phys = allocate_contiguous_ebi_nomap(dma_size, SZ_4K);
+	if (audio->phys) {
+		audio->map_v_read = ioremap(
+					audio->phys, dma_size);
+		if (IS_ERR(audio->map_v_read)) {
+			MM_ERR("could not map DMA buffers\n");
+			rc = -ENOMEM;
+			free_contiguous_memory_by_paddr(audio->phys);
+			goto evt_error;
+		}
+		audio->data = audio->map_v_read;
+	} else {
+		MM_ERR("could not allocate read buffers\n");
+		rc = -ENOMEM;
+		goto evt_error;
+	}
+	MM_DBG("Memory addr = 0x%8x  phy addr = 0x%8x\n",\
+		(int) audio->data, (int) audio->phys);
+
+	audio->out_data = NULL;
+	if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
+		audio->out_phys = allocate_contiguous_ebi_nomap(BUFFER_SIZE,
+								SZ_4K);
+		if (!audio->out_phys) {
+			MM_ERR("could not allocate write buffers\n");
+			rc = -ENOMEM;
+			iounmap(audio->map_v_read);
+			free_contiguous_memory_by_paddr(audio->phys);
+			goto evt_error;
+		} else {
+			audio->map_v_write = ioremap(
+					audio->out_phys, BUFFER_SIZE);
+			if (IS_ERR(audio->map_v_write)) {
+				MM_ERR("could not map write phys address\n");
+				rc = -ENOMEM;
+				iounmap(audio->map_v_read);
+				free_contiguous_memory_by_paddr(audio->phys);
+				free_contiguous_memory_by_paddr(\
+						audio->out_phys);
+				goto evt_error;
+			}
+			audio->out_data = audio->map_v_write;
+			MM_DBG("wr buf: phy addr 0x%08x kernel addr 0x%08x\n",
+					audio->out_phys, (int)audio->out_data);
+		}
+
+		/* Initialize buffer */
+		audio->out[0].data = audio->out_data + 0;
+		audio->out[0].addr = audio->out_phys + 0;
+		audio->out[0].size = OUT_BUFFER_SIZE;
+
+		audio->out[1].data = audio->out_data + OUT_BUFFER_SIZE;
+		audio->out[1].addr = audio->out_phys + OUT_BUFFER_SIZE;
+		audio->out[1].size = OUT_BUFFER_SIZE;
+
+		MM_DBG("audio->out[0].data = %d  audio->out[1].data = %d",
+				(unsigned int)audio->out[0].data,
+				(unsigned int)audio->out[1].data);
+		audio->mfield = NT_FRAME_HEADER_SIZE;
+		audio->out_frame_cnt++;
+	}
+	file->private_data = audio;
+	audio->opened = 1;
+
+done:
+	mutex_unlock(&audio->lock);
+	return rc;
+evt_error:
+	msm_adsp_put(audio->audrec);
+	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
+		msm_adsp_put(audio->audpre);
+
+	audpreproc_aenc_free(audio->enc_id);
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static const struct file_operations audio_aac_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audaac_in_open,
+	.release	= audaac_in_release,
+	.read		= audaac_in_read,
+	.write		= audaac_in_write,
+	.fsync		= audaac_in_fsync,
+	.unlocked_ioctl	= audaac_in_ioctl,
+};
+
+static struct miscdevice audaac_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_aac_in",
+	.fops	= &audio_aac_in_fops,
+};
+
+static int __init audaac_in_init(void)
+{
+	mutex_init(&the_audio_aac_in.lock);
+	mutex_init(&the_audio_aac_in.read_lock);
+	spin_lock_init(&the_audio_aac_in.dsp_lock);
+	init_waitqueue_head(&the_audio_aac_in.wait);
+	init_waitqueue_head(&the_audio_aac_in.wait_enable);
+	mutex_init(&the_audio_aac_in.write_lock);
+	init_waitqueue_head(&the_audio_aac_in.write_wait);
+	return misc_register(&audaac_in_misc);
+}
+device_initcall(audaac_in_init);
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb.c b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
new file mode 100644
index 0000000..1a1002e
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
@@ -0,0 +1,1630 @@
+/* linux/arch/arm/mach-msm/qdsp5/audio_amrnb.c
+ *
+ * amrnb audio decoder device
+ *
+ * Copyright (c) 2008-2009, 2011-2012 Code Aurora Forum. All rights reserved.
+ *
+ * Based on the mp3 native driver in arch/arm/mach-msm/qdsp5/audio_mp3.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/earlysuspend.h>
+#include <linux/android_pmem.h>
+#include <linux/slab.h>
+#include <linux/msm_audio.h>
+#include <linux/memory_alloc.h>
+
+#include <mach/msm_adsp.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audplaycmdi.h>
+#include <mach/qdsp5/qdsp5audplaymsg.h>
+#include <mach/qdsp5/qdsp5rmtcmdi.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_memtypes.h>
+
+#include "audmgr.h"
+
+#define BUFSZ 1024 /* Hold minimum 700ms voice data and 14 bytes of meta in*/
+#define DMASZ (BUFSZ * 2)
+
+#define AUDPLAY_INVALID_READ_PTR_OFFSET	0xFFFF
+#define AUDDEC_DEC_AMRNB 10
+
+#define PCM_BUFSZ_MIN 1624 /* 100ms worth of data and 24 bytes of meta out*/
+#define AMRNB_DECODED_FRSZ 320 /* AMR-NB 20ms 8KHz mono PCM size */
+#define PCM_BUF_MAX_COUNT 5	/* DSP only accepts 5 buffers at most
+				   but support 2 buffers currently */
+#define ROUTING_MODE_FTRT 1
+#define ROUTING_MODE_RT 2
+/* Decoder status received from AUDPPTASK */
+#define  AUDPP_DEC_STATUS_SLEEP	0
+#define	 AUDPP_DEC_STATUS_INIT  1
+#define  AUDPP_DEC_STATUS_CFG   2
+#define  AUDPP_DEC_STATUS_PLAY  3
+
+#define AUDAMRNB_METAFIELD_MASK 0xFFFF0000
+#define AUDAMRNB_EOS_FLG_OFFSET 0x0A /* Offset from beginning of buffer */
+#define AUDAMRNB_EOS_FLG_MASK 0x01
+#define AUDAMRNB_EOS_NONE 0x0 /* No EOS detected */
+#define AUDAMRNB_EOS_SET 0x1 /* EOS set in meta field */
+
+#define AUDAMRNB_EVENT_NUM 10 /* Default number of pre-allocated event pkts */
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+	unsigned short mfield_sz; /*only useful for data has meta field */
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct audamrnb_suspend_ctl {
+	struct early_suspend node;
+	struct audio *audio;
+};
+#endif
+
+struct audamrnb_event{
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+
+struct audio {
+	struct buffer out[2];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed;	/* number of buffers the dsp is waiting for */
+
+	atomic_t out_bytes;
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	/* Host PCM section */
+	struct buffer in[PCM_BUF_MAX_COUNT];
+	struct mutex read_lock;
+	wait_queue_head_t read_wait;	/* Wait queue for read */
+	char *read_data;	/* pointer to reader buffer */
+	int32_t read_phys;	/* physical address of reader buffer */
+	uint8_t read_next;	/* index to input buffers to be read next */
+	uint8_t fill_next;	/* index to buffer that DSP should be filling */
+	uint8_t pcm_buf_count;	/* number of pcm buffer allocated */
+	/* ---- End of Host PCM section */
+
+	struct msm_adsp_module *audplay;
+
+	struct audmgr audmgr;
+
+	/* data allocated for various buffers */
+	char *data;
+	int32_t phys; /* physical address of write buffer */
+	void *map_v_read;
+	void *map_v_write;
+
+
+	int mfield; /* meta field embedded in data */
+	int rflush; /* Read  flush */
+	int wflush; /* Write flush */
+	uint8_t opened:1;
+	uint8_t enabled:1;
+	uint8_t running:1;
+	uint8_t stopped:1;	/* set when stopped, cleared on flush */
+	uint8_t pcm_feedback:1;
+	uint8_t buf_refresh:1;
+	int teos; /* valid only if tunnel mode & no data left for decoder */
+	enum msm_aud_decoder_state dec_state;	/* Represents decoder state */
+	int rmt_resource_released;
+
+	const char *module_name;
+	unsigned queue_id;
+	uint16_t dec_id;
+	uint32_t read_ptr_offset;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct audamrnb_suspend_ctl suspend_ctl;
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+
+	wait_queue_head_t wait;
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	wait_queue_head_t event_wait;
+	spinlock_t event_queue_lock;
+	struct mutex get_event_lock;
+	int event_abort;
+
+	int eq_enable;
+	int eq_needs_commit;
+	audpp_cmd_cfg_object_params_eqalizer eq;
+	audpp_cmd_cfg_object_params_volume vol_pan;
+};
+
+struct audpp_cmd_cfg_adec_params_amrnb {
+   audpp_cmd_cfg_adec_params_common     common;
+   unsigned short                       stereo_cfg;
+} __attribute__((packed)) ;
+
+static int auddec_dsp_config(struct audio *audio, int enable);
+static void audpp_cmd_cfg_adec_params(struct audio *audio);
+static void audpp_cmd_cfg_routing_mode(struct audio *audio);
+static void audamrnb_send_data(struct audio *audio, unsigned needed);
+static void audamrnb_config_hostpcm(struct audio *audio);
+static void audamrnb_buffer_refresh(struct audio *audio);
+static void audamrnb_dsp_event(void *private, unsigned id, uint16_t *msg);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audamrnb_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload);
+#endif
+
+static int rmt_put_resource(struct audio *audio)
+{
+	struct aud_codec_config_cmd cmd;
+	unsigned short client_idx;
+
+	cmd.cmd_id = RM_CMD_AUD_CODEC_CFG;
+	cmd.client_id = RM_AUD_CLIENT_ID;
+	cmd.task_id = audio->dec_id;
+	cmd.enable = RMT_DISABLE;
+	cmd.dec_type = AUDDEC_DEC_AMRNB;
+	client_idx = ((cmd.client_id << 8) | cmd.task_id);
+
+	return put_adsp_resource(client_idx, &cmd, sizeof(cmd));
+}
+
+static int rmt_get_resource(struct audio *audio)
+{
+	struct aud_codec_config_cmd cmd;
+	unsigned short client_idx;
+
+	cmd.cmd_id = RM_CMD_AUD_CODEC_CFG;
+	cmd.client_id = RM_AUD_CLIENT_ID;
+	cmd.task_id = audio->dec_id;
+	cmd.enable = RMT_ENABLE;
+	cmd.dec_type = AUDDEC_DEC_AMRNB;
+	client_idx = ((cmd.client_id << 8) | cmd.task_id);
+
+	return get_adsp_resource(client_idx, &cmd, sizeof(cmd));
+}
+
+/* must be called with audio->lock held */
+static int audamrnb_enable(struct audio *audio)
+{
+	struct audmgr_config cfg;
+	int rc;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled)
+		return 0;
+
+	if (audio->rmt_resource_released == 1) {
+		audio->rmt_resource_released = 0;
+		rc = rmt_get_resource(audio);
+		if (rc) {
+			MM_ERR("ADSP resources are not available for AMRNB \
+				session 0x%08x on decoder: %d\n Ignoring \
+				error and going ahead with the playback\n",
+				(int)audio, audio->dec_id);
+		}
+	}
+
+	audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
+		cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+		cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;
+		cfg.def_method = RPC_AUD_DEF_METHOD_PLAYBACK;
+		cfg.codec = RPC_AUD_DEF_CODEC_AMR_NB;
+		cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+		rc = audmgr_enable(&audio->audmgr, &cfg);
+		if (rc < 0)
+			return rc;
+	}
+
+	if (msm_adsp_enable(audio->audplay)) {
+		MM_ERR("msm_adsp_enable(audplay) failed\n");
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+
+	if (audpp_enable(audio->dec_id, audamrnb_dsp_event, audio)) {
+		MM_ERR("audpp_enable() failed\n");
+		msm_adsp_disable(audio->audplay);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+	audio->enabled = 1;
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audamrnb_disable(struct audio *audio)
+{
+	int rc = 0;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+		auddec_dsp_config(audio, 0);
+		rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+		else if (audio->dec_state != MSM_AUD_DECODER_STATE_CLOSE)
+			rc = -EFAULT;
+		else
+			rc = 0;
+		audio->stopped = 1;
+		wake_up(&audio->write_wait);
+		wake_up(&audio->read_wait);
+		msm_adsp_disable(audio->audplay);
+		audpp_disable(audio->dec_id, audio);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_disable(&audio->audmgr);
+		audio->out_needed = 0;
+		rmt_put_resource(audio);
+		audio->rmt_resource_released = 1;
+	}
+	return rc;
+}
+
+/* ------------------- dsp --------------------- */
+static void audamrnb_update_pcm_buf_entry(struct audio *audio,
+		uint32_t *payload)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	if (audio->rflush)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < payload[1]; index++) {
+		if (audio->in[audio->fill_next].addr ==
+		    payload[2 + index * 2]) {
+			MM_DBG("in[%d] ready\n", audio->fill_next);
+			audio->in[audio->fill_next].used =
+			    payload[3 + index * 2];
+			if ((++audio->fill_next) == audio->pcm_buf_count)
+				audio->fill_next = 0;
+
+		} else {
+			MM_ERR("expected=%x ret=%x\n",
+				audio->in[audio->fill_next].addr,
+				payload[1 + index * 2]);
+			break;
+		}
+	}
+	if (audio->in[audio->fill_next].used == 0) {
+		audamrnb_buffer_refresh(audio);
+	} else {
+		MM_DBG("read cannot keep up\n");
+		audio->buf_refresh = 1;
+	}
+	wake_up(&audio->read_wait);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static void audplay_dsp_event(void *data, unsigned id, size_t len,
+			      void (*getevent) (void *ptr, size_t len))
+{
+	struct audio *audio = data;
+	uint32_t msg[28];
+	getevent(msg, sizeof(msg));
+
+	MM_DBG("msg_id=%x\n", id);
+
+	switch (id) {
+	case AUDPLAY_MSG_DEC_NEEDS_DATA:
+		audamrnb_send_data(audio, 1);
+		break;
+
+	case AUDPLAY_MSG_BUFFER_UPDATE:
+		audamrnb_update_pcm_buf_entry(audio, msg);
+		break;
+
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audplaytask)\n");
+		break;
+
+	default:
+		MM_ERR("unexpected message from decoder\n");
+	}
+}
+
+static void audamrnb_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned status = msg[1];
+
+			switch (status) {
+			case AUDPP_DEC_STATUS_SLEEP: {
+				uint16_t reason = msg[2];
+				MM_DBG("decoder status:sleep reason = \
+						0x%04x\n", reason);
+				if ((reason == AUDPP_MSG_REASON_MEM)
+					|| (reason ==
+					AUDPP_MSG_REASON_NODECODER)) {
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_FAILURE;
+					wake_up(&audio->wait);
+				} else if (reason == AUDPP_MSG_REASON_NONE) {
+					/* decoder is in disable state */
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_CLOSE;
+					wake_up(&audio->wait);
+				}
+				break;
+			}
+			case AUDPP_DEC_STATUS_INIT:
+				MM_DBG("decoder status: init \n");
+				if (audio->pcm_feedback)
+					audpp_cmd_cfg_routing_mode(audio);
+				else
+					audpp_cmd_cfg_adec_params(audio);
+				break;
+
+			case AUDPP_DEC_STATUS_CFG:
+				MM_DBG("decoder status: cfg \n");
+				break;
+			case AUDPP_DEC_STATUS_PLAY:
+				MM_DBG("decoder status: play \n");
+				if (audio->pcm_feedback) {
+					audamrnb_config_hostpcm(audio);
+					audamrnb_buffer_refresh(audio);
+				}
+				audio->dec_state =
+					MSM_AUD_DECODER_STATE_SUCCESS;
+				wake_up(&audio->wait);
+				break;
+			default:
+				MM_ERR("unknown decoder status \n");
+				break;
+			}
+			break;
+		}
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			MM_DBG("CFG_MSG ENABLE\n");
+			auddec_dsp_config(audio, 1);
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+			audpp_dsp_set_eq(audio->dec_id,	audio->eq_enable,
+								&audio->eq);
+			audpp_avsync(audio->dec_id, 22050);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			MM_DBG("CFG_MSG DISABLE\n");
+			audpp_avsync(audio->dec_id, 0);
+			audio->running = 0;
+		} else {
+			MM_DBG("CFG_MSG %d?\n", msg[0]);
+		}
+		break;
+	case AUDPP_MSG_ROUTING_ACK:
+		MM_DBG("ROUTING_ACK mode=%d\n", msg[1]);
+		audpp_cmd_cfg_adec_params(audio);
+		break;
+	case AUDPP_MSG_FLUSH_ACK:
+		MM_DBG("FLUSH_ACK\n");
+		audio->wflush = 0;
+		audio->rflush = 0;
+		wake_up(&audio->write_wait);
+		if (audio->pcm_feedback)
+			audamrnb_buffer_refresh(audio);
+		break;
+	case AUDPP_MSG_PCMDMAMISSED:
+		MM_DBG("PCMDMAMISSED\n");
+		audio->teos = 1;
+		wake_up(&audio->write_wait);
+		break;
+	default:
+		MM_ERR("UNKNOWN (%d)\n", id);
+	}
+
+}
+
+struct msm_adsp_ops audplay_adsp_ops_amrnb = {
+	.event = audplay_dsp_event,
+};
+
+#define audplay_send_queue0(audio, cmd, len) \
+	msm_adsp_write(audio->audplay, audio->queue_id, \
+			cmd, len)
+
+static int auddec_dsp_config(struct audio *audio, int enable)
+{
+	u16 cfg_dec_cmd[AUDPP_CMD_CFG_DEC_TYPE_LEN / sizeof(unsigned short)];
+
+	memset(cfg_dec_cmd, 0, sizeof(cfg_dec_cmd));
+	cfg_dec_cmd[0] = AUDPP_CMD_CFG_DEC_TYPE;
+	if (enable)
+		cfg_dec_cmd[1 + audio->dec_id] = AUDPP_CMD_UPDATDE_CFG_DEC |
+			AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_AMRNB;
+	else
+		cfg_dec_cmd[1 + audio->dec_id] = AUDPP_CMD_UPDATDE_CFG_DEC |
+			AUDPP_CMD_DIS_DEC_V;
+
+	return audpp_send_queue1(&cfg_dec_cmd, sizeof(cfg_dec_cmd));
+}
+
+static void audpp_cmd_cfg_adec_params(struct audio *audio)
+{
+	struct audpp_cmd_cfg_adec_params_amrnb cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_V13K_LEN;
+	cmd.common.dec_id = audio->dec_id;
+	cmd.common.input_sampling_frequency = 8000;
+	cmd.stereo_cfg = AUDPP_CMD_PCM_INTF_MONO_V;
+
+	audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static void audpp_cmd_cfg_routing_mode(struct audio *audio)
+{
+	struct audpp_cmd_routing_mode cmd;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_ROUTING_MODE;
+	cmd.object_number = audio->dec_id;
+	if (audio->pcm_feedback)
+		cmd.routing_mode = ROUTING_MODE_FTRT;
+	else
+		cmd.routing_mode = ROUTING_MODE_RT;
+
+	audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static int audplay_dsp_send_data_avail(struct audio *audio,
+				       unsigned idx, unsigned len)
+{
+	struct audplay_cmd_bitstream_data_avail_nt2 cmd;
+
+	cmd.cmd_id = AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_NT2;
+	if (audio->mfield)
+		cmd.decoder_id = AUDAMRNB_METAFIELD_MASK |
+			(audio->out[idx].mfield_sz >> 1);
+	else
+		cmd.decoder_id = audio->dec_id;
+	cmd.buf_ptr = audio->out[idx].addr;
+	cmd.buf_size = len / 2;
+	cmd.partition_number = 0;
+	/* complete writes to the input buffer */
+	wmb();
+	return audplay_send_queue0(audio, &cmd, sizeof(cmd));
+}
+
+static void audamrnb_buffer_refresh(struct audio *audio)
+{
+	struct audplay_cmd_buffer_refresh refresh_cmd;
+
+	refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH;
+	refresh_cmd.num_buffers = 1;
+	refresh_cmd.buf0_address = audio->in[audio->fill_next].addr;
+	refresh_cmd.buf0_length = audio->in[audio->fill_next].size -
+	  (audio->in[audio->fill_next].size % AMRNB_DECODED_FRSZ) +
+	  (audio->mfield ? 24 : 0);
+	refresh_cmd.buf_read_count = 0;
+	MM_DBG("buf0_addr=%x buf0_len=%d\n", refresh_cmd.buf0_address,
+			refresh_cmd.buf0_length);
+	(void)audplay_send_queue0(audio, &refresh_cmd, sizeof(refresh_cmd));
+}
+
+static void audamrnb_config_hostpcm(struct audio *audio)
+{
+	struct audplay_cmd_hpcm_buf_cfg cfg_cmd;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	cfg_cmd.cmd_id = AUDPLAY_CMD_HPCM_BUF_CFG;
+	cfg_cmd.max_buffers = audio->pcm_buf_count;
+	cfg_cmd.byte_swap = 0;
+	cfg_cmd.hostpcm_config = (0x8000) | (0x4000);
+	cfg_cmd.feedback_frequency = 1;
+	cfg_cmd.partition_number = 0;
+	(void)audplay_send_queue0(audio, &cfg_cmd, sizeof(cfg_cmd));
+
+}
+
+static void audamrnb_send_data(struct audio *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (needed && !audio->wflush) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+			MM_DBG("frame %d busy\n", audio->out_tail);
+			audplay_dsp_send_data_avail(audio, audio->out_tail,
+						    frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+ done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+
+static void audamrnb_flush(struct audio *audio)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->out[0].used = 0;
+	audio->out[1].used = 0;
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	atomic_set(&audio->out_bytes, 0);
+}
+
+static void audamrnb_flush_pcm_buf(struct audio *audio)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
+		audio->in[index].used = 0;
+
+	audio->buf_refresh = 0;
+	audio->read_next = 0;
+	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static void audamrnb_ioport_reset(struct audio *audio)
+{
+	/* Make sure read/write thread are free from
+	 * sleep and knowing that system is not able
+	 * to process io request at the moment
+	 */
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audamrnb_flush(audio);
+	mutex_unlock(&audio->write_lock);
+	wake_up(&audio->read_wait);
+	mutex_lock(&audio->read_lock);
+	audamrnb_flush_pcm_buf(audio);
+	mutex_unlock(&audio->read_lock);
+}
+
+static int audamrnb_events_pending(struct audio *audio)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	return empty || audio->event_abort;
+}
+
+static void audamrnb_reset_event_queue(struct audio *audio)
+{
+	unsigned long flags;
+	struct audamrnb_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audamrnb_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+				struct audamrnb_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	return;
+}
+
+static long audamrnb_process_event_req(struct audio *audio, void __user *arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audamrnb_event *drv_evt = NULL;
+	int timeout;
+	unsigned long flags;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int) usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(
+			audio->event_wait, audamrnb_events_pending(audio),
+			msecs_to_jiffies(timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(
+			audio->event_wait, audamrnb_events_pending(audio));
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	rc = 0;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audamrnb_event, list);
+		list_del(&drv_evt->list);
+	}
+
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else
+		rc = -1;
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	if (!rc && copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audio_enable_eq(struct audio *audio, int enable)
+{
+	if (audio->eq_enable == enable && !audio->eq_needs_commit)
+		return 0;
+
+	audio->eq_enable = enable;
+
+	if (audio->running) {
+		audpp_dsp_set_eq(audio->dec_id, enable, &audio->eq);
+		audio->eq_needs_commit = 0;
+	}
+	return 0;
+}
+
+static long audamrnb_ioctl(struct file *file, unsigned int cmd,
+		unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = -EINVAL;
+	unsigned long flags = 0;
+	uint16_t enable_mask;
+	int enable;
+	int prev_state;
+
+	MM_DBG("cmd = %d\n", cmd);
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = audpp_avsync_byte_count(audio->dec_id);
+		stats.sample_count = audpp_avsync_sample_count(audio->dec_id);
+		if (copy_to_user((void *)arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	switch (cmd) {
+	case AUDIO_ENABLE_AUDPP:
+		if (copy_from_user(&enable_mask, (void *) arg,
+						sizeof(enable_mask))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		enable = (enable_mask & EQ_ENABLE) ? 1 : 0;
+		audio_enable_eq(audio, enable);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+	case AUDIO_SET_VOLUME:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.volume = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_PAN:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.pan = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_EQ:
+		prev_state = audio->eq_enable;
+		audio->eq_enable = 0;
+		if (copy_from_user(&audio->eq.num_bands, (void *) arg,
+				sizeof(audio->eq) -
+				(AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2))) {
+			rc = -EFAULT;
+			break;
+		}
+		audio->eq_enable = prev_state;
+		audio->eq_needs_commit = 1;
+		rc = 0;
+		break;
+	}
+
+	if (-EINVAL != rc)
+		return rc;
+
+	if (cmd == AUDIO_GET_EVENT) {
+		MM_DBG("AUDIO_GET_EVENT\n");
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audamrnb_process_event_req(audio,
+					(void __user *) arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		return rc;
+	}
+
+	if (cmd == AUDIO_ABORT_GET_EVENT) {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		MM_DBG("AUDIO_START\n");
+		rc = audamrnb_enable(audio);
+		if (!rc) {
+			rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+			MM_INFO("dec_state %d rc = %d\n", audio->dec_state, rc);
+
+			if (audio->dec_state != MSM_AUD_DECODER_STATE_SUCCESS)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		break;
+	case AUDIO_STOP:
+		MM_DBG("AUDIO_STOP\n");
+		rc = audamrnb_disable(audio);
+		audamrnb_ioport_reset(audio);
+		audio->stopped = 0;
+		break;
+	case AUDIO_FLUSH:
+		MM_DBG("AUDIO_FLUSH\n");
+		audio->rflush = 1;
+		audio->wflush = 1;
+		audamrnb_ioport_reset(audio);
+		if (audio->running) {
+			audpp_flush(audio->dec_id);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		break;
+	case AUDIO_SET_CONFIG:{
+			struct msm_audio_config config;
+			if (copy_from_user
+			    (&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+			audio->mfield = config.meta_field;
+			rc = 0;
+			break;
+		}
+	case AUDIO_GET_CONFIG:{
+			struct msm_audio_config config;
+			config.buffer_size = BUFSZ;
+			config.buffer_count = 2;
+			config.sample_rate = 8000;
+			config.channel_count = 1;
+			config.meta_field = 0;
+			config.unused[0] = 0;
+			config.unused[1] = 0;
+			config.unused[2] = 0;
+			if (copy_to_user((void *)arg, &config,
+					 sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+
+			break;
+		}
+	case AUDIO_GET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			config.pcm_feedback = audio->pcm_feedback;
+			config.buffer_count = PCM_BUF_MAX_COUNT;
+			config.buffer_size = PCM_BUFSZ_MIN;
+			if (copy_to_user((void *)arg, &config,
+					 sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_SET_PCM_CONFIG:{
+		struct msm_audio_pcm_config config;
+		if (copy_from_user
+		    (&config, (void *)arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (config.pcm_feedback != audio->pcm_feedback) {
+			MM_ERR("Not sufficient permission to"
+				 "change the playback mode\n");
+			rc = -EACCES;
+			break;
+		}
+		if ((config.buffer_count > PCM_BUF_MAX_COUNT) ||
+		    (config.buffer_count == 1))
+			config.buffer_count = PCM_BUF_MAX_COUNT;
+
+		if (config.buffer_size < PCM_BUFSZ_MIN)
+			config.buffer_size = PCM_BUFSZ_MIN;
+
+			/* Check if pcm feedback is required */
+		if ((config.pcm_feedback) && (!audio->read_data)) {
+			MM_DBG("allocate PCM buf %d\n",
+					config.buffer_count *
+					config.buffer_size);
+			audio->read_phys = allocate_contiguous_ebi_nomap(
+						config.buffer_size *
+						config.buffer_count,
+						SZ_4K);
+			if (!audio->read_phys) {
+					rc = -ENOMEM;
+					break;
+			}
+			audio->map_v_read = ioremap(
+						audio->read_phys,
+						config.buffer_size *
+						config.buffer_count);
+			if (IS_ERR(audio->map_v_read)) {
+				MM_ERR("failed to map read buf\n");
+				rc = -ENOMEM;
+				free_contiguous_memory_by_paddr(
+							audio->read_phys);
+			} else {
+				uint8_t index;
+				uint32_t offset = 0;
+				audio->read_data =
+						audio->map_v_read;
+				audio->buf_refresh = 0;
+				audio->pcm_buf_count =
+					config.buffer_count;
+				audio->read_next = 0;
+				audio->fill_next = 0;
+
+				for (index = 0;
+				index < config.buffer_count; index++) {
+					audio->in[index].data =
+						audio->read_data + offset;
+					audio->in[index].addr =
+					    audio->read_phys + offset;
+					audio->in[index].size =
+					    config.buffer_size;
+					audio->in[index].used = 0;
+					offset += config.buffer_size;
+				}
+				MM_DBG("read buf: phy addr 0x%08x kernel \
+					addr 0x%08x\n", audio->read_phys,
+					(int)audio->read_data);
+				rc = 0;
+			}
+		} else {
+			rc = 0;
+		}
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+/* Only useful in tunnel-mode */
+static int audamrnb_fsync(struct file *file, loff_t a, loff_t b, int datasync)
+{
+	struct audio *audio = file->private_data;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	if (!audio->running || audio->pcm_feedback) {
+		rc = -EINVAL;
+		goto done_nolock;
+	}
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(!audio->out[0].used &&
+		!audio->out[1].used &&
+		audio->out_needed) || audio->wflush);
+
+	if (rc < 0)
+		goto done;
+	else if (audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	/* pcm dmamiss message is sent continously
+	 * when decoder is starved so no race
+	 * condition concern
+	 */
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		audio->teos || audio->wflush);
+
+	if (audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+done_nolock:
+	return rc;
+}
+
+static ssize_t audamrnb_read(struct file *file, char __user *buf, size_t count,
+			  loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	int rc = 0;
+
+	if (!audio->pcm_feedback)
+		return 0; /* PCM feedback is not enabled. Nothing to read */
+
+	mutex_lock(&audio->read_lock);
+	MM_DBG("%d \n",	count);
+	while (count > 0) {
+		rc = wait_event_interruptible(audio->read_wait,
+			(audio->in[audio->read_next].used > 0) ||
+			(audio->stopped) || (audio->rflush));
+
+		if (rc < 0)
+			break;
+
+		if (audio->stopped || audio->rflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (count < audio->in[audio->read_next].used) {
+			/* Read must happen in frame boundary. Since driver does
+			 * not know frame size, read count must be greater or
+			 * equal to size of PCM samples
+			 */
+			MM_DBG("read stop - partial frame\n");
+			break;
+		} else {
+			MM_DBG("read from in[%d]\n", audio->read_next);
+			/* order reads from the output buffer */
+			rmb();
+			if (copy_to_user
+			    (buf, audio->in[audio->read_next].data,
+			     audio->in[audio->read_next].used)) {
+				MM_ERR("invalid addr %x \n", (unsigned int)buf);
+				rc = -EFAULT;
+				break;
+			}
+			count -= audio->in[audio->read_next].used;
+			buf += audio->in[audio->read_next].used;
+			audio->in[audio->read_next].used = 0;
+			if ((++audio->read_next) == audio->pcm_buf_count)
+				audio->read_next = 0;
+			break;
+		}
+	}
+
+	/* don't feed output buffer to HW decoder during flushing
+	 * buffer refresh command will be sent once flush completes
+	 * send buf refresh command here can confuse HW decoder
+	 */
+	if (audio->buf_refresh && !audio->rflush) {
+		audio->buf_refresh = 0;
+		MM_DBG("kick start pcm feedback again\n");
+		audamrnb_buffer_refresh(audio);
+	}
+
+	mutex_unlock(&audio->read_lock);
+
+	if (buf > start)
+		rc = buf - start;
+
+	MM_DBG("read %d bytes\n", rc);
+	return rc;
+}
+
+static int audamrnb_process_eos(struct audio *audio,
+		const char __user *buf_start, unsigned short mfield_size)
+{
+	int rc = 0;
+	struct buffer *frame;
+
+	frame = audio->out + audio->out_head;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->out_needed &&
+		audio->out[0].used == 0 &&
+		audio->out[1].used == 0)
+		|| (audio->stopped)
+		|| (audio->wflush));
+
+	if (rc < 0)
+		goto done;
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (copy_from_user(frame->data, buf_start, mfield_size)) {
+		rc = -EFAULT;
+		goto done;
+	}
+
+	frame->mfield_sz = mfield_size;
+	audio->out_head ^= 1;
+	frame->used = mfield_size;
+	audamrnb_send_data(audio, 0);
+
+done:
+	return rc;
+}
+
+static ssize_t audamrnb_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	char *cpy_ptr;
+	int rc = 0, eos_condition = AUDAMRNB_EOS_NONE;
+	unsigned short mfield_size = 0;
+
+	MM_DBG("cnt=%d\n", count);
+
+	if (count & 1)
+		return -EINVAL;
+
+	mutex_lock(&audio->write_lock);
+	while (count > 0) {
+		frame = audio->out + audio->out_head;
+		cpy_ptr = frame->data;
+		rc = wait_event_interruptible(audio->write_wait,
+					      (frame->used == 0)
+						|| (audio->stopped)
+						|| (audio->wflush));
+
+		MM_DBG("buffer available\n");
+		if (rc < 0)
+			break;
+		if (audio->stopped || audio->wflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (audio->mfield) {
+			if (buf == start) {
+				/* Processing beginning of user buffer */
+				if (__get_user(mfield_size,
+					(unsigned short __user *) buf)) {
+					rc = -EFAULT;
+					break;
+				} else 	if (mfield_size > count) {
+					rc = -EINVAL;
+					break;
+				}
+				MM_DBG("mf offset_val %x\n", mfield_size);
+				if (copy_from_user(cpy_ptr, buf, mfield_size)) {
+					rc = -EFAULT;
+					break;
+				}
+				/* Check if EOS flag is set and buffer
+				 * contains just meta field
+				 */
+				if (cpy_ptr[AUDAMRNB_EOS_FLG_OFFSET] &
+						AUDAMRNB_EOS_FLG_MASK) {
+					MM_DBG("eos set\n");
+					eos_condition = AUDAMRNB_EOS_SET;
+					if (mfield_size == count) {
+						buf += mfield_size;
+						break;
+					} else
+					cpy_ptr[AUDAMRNB_EOS_FLG_OFFSET] &=
+							~AUDAMRNB_EOS_FLG_MASK;
+				}
+				cpy_ptr += mfield_size;
+				count -= mfield_size;
+				buf += mfield_size;
+			} else {
+				mfield_size = 0;
+				MM_DBG("continuous buffer\n");
+			}
+			frame->mfield_sz = mfield_size;
+		}
+
+		xfer = (count > (frame->size - mfield_size)) ?
+			(frame->size - mfield_size) : count;
+		if (copy_from_user(cpy_ptr, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+
+		frame->used = (xfer + mfield_size);
+		audio->out_head ^= 1;
+		count -= xfer;
+		buf += xfer;
+
+		audamrnb_send_data(audio, 0);
+
+	}
+	if (eos_condition == AUDAMRNB_EOS_SET)
+		rc = audamrnb_process_eos(audio, start, mfield_size);
+	mutex_unlock(&audio->write_lock);
+	if (!rc) {
+		if (buf > start)
+			return buf - start;
+	}
+	return rc;
+}
+
+static int audamrnb_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	MM_INFO("audio instance 0x%08x freeing\n", (int)audio);
+	mutex_lock(&audio->lock);
+	audamrnb_disable(audio);
+	if (audio->rmt_resource_released == 0)
+		rmt_put_resource(audio);
+	audamrnb_flush(audio);
+	audamrnb_flush_pcm_buf(audio);
+	msm_adsp_put(audio->audplay);
+	audpp_adec_free(audio->dec_id);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&audio->suspend_ctl.node);
+#endif
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audamrnb_reset_event_queue(audio);
+	iounmap(audio->map_v_write);
+	free_contiguous_memory_by_paddr(audio->phys);
+	if (audio->read_data) {
+		iounmap(audio->map_v_read);
+		free_contiguous_memory_by_paddr(audio->read_phys);
+	}
+	mutex_unlock(&audio->lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio);
+	return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audamrnb_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload)
+{
+	struct audamrnb_event *e_node = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+				struct audamrnb_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audamrnb_event), GFP_ATOMIC);
+		if (!e_node) {
+			MM_ERR("No mem to post event %d\n", type);
+			spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	wake_up(&audio->event_wait);
+}
+
+static void audamrnb_suspend(struct early_suspend *h)
+{
+	struct audamrnb_suspend_ctl *ctl =
+		container_of(h, struct audamrnb_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audamrnb_post_event(ctl->audio, AUDIO_EVENT_SUSPEND, payload);
+}
+
+static void audamrnb_resume(struct early_suspend *h)
+{
+	struct audamrnb_suspend_ctl *ctl =
+		container_of(h, struct audamrnb_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audamrnb_post_event(ctl->audio, AUDIO_EVENT_RESUME, payload);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audamrnb_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audamrnb_debug_read(struct file *file, char __user *buf,
+					size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 1024;
+	static char buffer[1024];
+	int n = 0, i;
+	struct audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"enabled %d\n", audio->enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_feedback %d\n", audio->pcm_feedback);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_buf_sz %d\n", audio->out[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_buf_count %d \n", audio->pcm_buf_count);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_buf_sz %d \n", audio->in[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"volume %x \n", audio->vol_pan.volume);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"rflush %d\n", audio->rflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"running %d \n", audio->running);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"dec state %d \n", audio->dec_state);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_needed %d \n", audio->out_needed);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_head %d \n", audio->out_head);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_tail %d \n", audio->out_tail);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out[0].used %d \n", audio->out[0].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out[1].used %d \n", audio->out[1].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"buffer_refresh %d \n", audio->buf_refresh);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"read_next %d \n", audio->read_next);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"fill_next %d \n", audio->fill_next);
+	for (i = 0; i < audio->pcm_buf_count; i++)
+		n += scnprintf(buffer + n, debug_bufmax - n,
+				"in[%d].used %d \n", i, audio->in[i].used);
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audamrnb_debug_fops = {
+	.read = audamrnb_debug_read,
+	.open = audamrnb_debug_open,
+};
+#endif
+
+static int audamrnb_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = NULL;
+	int rc, dec_attrb, decid, i;
+	struct audamrnb_event *e_node = NULL;
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_amrnb_" + 5];
+#endif
+
+	/* Allocate Mem for audio instance */
+	audio = kzalloc(sizeof(struct audio), GFP_KERNEL);
+	if (!audio) {
+		MM_ERR("no memory to allocate audio instance \n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	MM_INFO("audio instance 0x%08x created\n", (int)audio);
+
+	/* Allocate the decoder */
+	dec_attrb = AUDDEC_DEC_AMRNB;
+	if ((file->f_mode & FMODE_WRITE) &&
+			(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_NONTUNNEL;
+		audio->pcm_feedback = NON_TUNNEL_MODE_PLAYBACK;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_TUNNEL;
+		audio->pcm_feedback = TUNNEL_MODE_PLAYBACK;
+	} else {
+		kfree(audio);
+		rc = -EACCES;
+		goto done;
+	}
+
+	decid = audpp_adec_alloc(dec_attrb, &audio->module_name,
+			&audio->queue_id);
+
+	if (decid < 0) {
+		MM_ERR("No free decoder available, freeing instance 0x%08x\n",
+				(int)audio);
+		rc = -ENODEV;
+		kfree(audio);
+		goto done;
+	}
+
+	audio->dec_id = decid & MSM_AUD_DECODER_MASK;
+
+	audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
+	if (!audio->phys) {
+		MM_ERR("could not allocate write buffers, freeing instance \
+				0x%08x\n", (int)audio);
+		rc = -ENOMEM;
+		audpp_adec_free(audio->dec_id);
+		kfree(audio);
+		goto done;
+	} else {
+		audio->map_v_write = ioremap(
+					audio->phys, DMASZ);
+		if (IS_ERR(audio->map_v_write)) {
+			MM_ERR("could not map write buffers, freeing \
+					instance 0x%08x freeing\n", (int)audio);
+			rc = -ENOMEM;
+			free_contiguous_memory_by_paddr(audio->phys);
+			audpp_adec_free(audio->dec_id);
+			kfree(audio);
+			goto done;
+		}
+		audio->data = audio->map_v_write;
+		MM_DBG("write buf: phy addr 0x%08x kernel addr \
+				0x%08x\n", audio->phys, (int)audio->data);
+	}
+
+	if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
+		rc = audmgr_open(&audio->audmgr);
+		if (rc) {
+			MM_ERR("audmgr open failed, freeing instance \
+					0x%08x\n", (int)audio);
+			goto err;
+		}
+	}
+
+	rc = msm_adsp_get(audio->module_name, &audio->audplay,
+		&audplay_adsp_ops_amrnb, audio);
+	if (rc) {
+		MM_ERR("failed to get %s module, freeing instance 0x%08x\n",
+				audio->module_name, (int)audio);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_close(&audio->audmgr);
+		goto err;
+	}
+
+	rc = rmt_get_resource(audio);
+	if (rc) {
+		MM_ERR("ADSP resources are not available for AMRNB session \
+			 0x%08x on decoder: %d\n", (int)audio, audio->dec_id);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_close(&audio->audmgr);
+		msm_adsp_put(audio->audplay);
+		goto err;
+	}
+
+	mutex_init(&audio->lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->get_event_lock);
+	spin_lock_init(&audio->dsp_lock);
+	spin_lock_init(&audio->event_queue_lock);
+	INIT_LIST_HEAD(&audio->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+	init_waitqueue_head(&audio->write_wait);
+	init_waitqueue_head(&audio->read_wait);
+	init_waitqueue_head(&audio->wait);
+	init_waitqueue_head(&audio->event_wait);
+
+	audio->out[0].data = audio->data + 0;
+	audio->out[0].addr = audio->phys + 0;
+	audio->out[0].size = BUFSZ;
+
+	audio->out[1].data = audio->data + BUFSZ;
+	audio->out[1].addr = audio->phys + BUFSZ;
+	audio->out[1].size = BUFSZ;
+
+	audio->vol_pan.volume = 0x2000;
+
+	audamrnb_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_amrnb_%04x", audio->dec_id);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+			NULL, (void *) audio, &audamrnb_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		MM_DBG("debugfs_create_file failed\n");
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	audio->suspend_ctl.node.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+	audio->suspend_ctl.node.resume = audamrnb_resume;
+	audio->suspend_ctl.node.suspend = audamrnb_suspend;
+	audio->suspend_ctl.audio = audio;
+	register_early_suspend(&audio->suspend_ctl.node);
+#endif
+	for (i = 0; i < AUDAMRNB_EVENT_NUM; i++) {
+		e_node = kmalloc(sizeof(struct audamrnb_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			MM_ERR("event pkt alloc failed\n");
+			break;
+		}
+	}
+done:
+	return rc;
+err:
+	iounmap(audio->map_v_write);
+	free_contiguous_memory_by_paddr(audio->phys);
+	audpp_adec_free(audio->dec_id);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_amrnb_fops = {
+	.owner = THIS_MODULE,
+	.open = audamrnb_open,
+	.release = audamrnb_release,
+	.read = audamrnb_read,
+	.write = audamrnb_write,
+	.unlocked_ioctl = audamrnb_ioctl,
+	.fsync = audamrnb_fsync,
+};
+
+struct miscdevice audio_amrnb_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_amrnb",
+	.fops = &audio_amrnb_fops,
+};
+
+static int __init audamrnb_init(void)
+{
+	return misc_register(&audio_amrnb_misc);
+}
+
+static void __exit audamrnb_exit(void)
+{
+	misc_deregister(&audio_amrnb_misc);
+}
+
+module_init(audamrnb_init);
+module_exit(audamrnb_exit);
+
+MODULE_DESCRIPTION("MSM AMR-NB driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c b/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
new file mode 100644
index 0000000..ac2b5ca
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
@@ -0,0 +1,1484 @@
+/* arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
+ *
+ * amrnb encoder device
+ *
+ * Copyright (c) 2009, 2011-2012 Code Aurora Forum. All rights reserved.
+ *
+ * This code is based in part on arch/arm/mach-msm/qdsp5/audio_in.c, which is
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ *
+ * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ *
+ */
+
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/msm_audio_amrnb.h>
+#include <linux/android_pmem.h>
+#include <linux/memory_alloc.h>
+
+#include "audmgr.h"
+
+#include <mach/msm_rpcrouter.h>
+#include <mach/msm_memtypes.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+
+#include <mach/msm_adsp.h>
+#include <mach/qdsp5/qdsp5audpreproc.h>
+#include <mach/qdsp5/qdsp5audpreproccmdi.h>
+#include <mach/qdsp5/qdsp5audpreprocmsg.h>
+#include <mach/qdsp5/qdsp5audreccmdi.h>
+#include <mach/qdsp5/qdsp5audrecmsg.h>
+#include <mach/debug_mm.h>
+
+#define FRAME_HEADER_SIZE	8 /* 8 bytes frame header */
+#define NT_FRAME_HEADER_SIZE	24 /* 24 bytes frame header */
+/* FRAME_NUM must be a power of two */
+#define FRAME_NUM	8
+#define AMRNB_FRAME_SIZE	36 /* 36 bytes data */
+/*Tunnel mode : 1536 bytes data + 8 byte header*/
+#define FRAME_SIZE	(AMRNB_FRAME_SIZE + FRAME_HEADER_SIZE)
+/* 1536 bytes data  + 24 meta field*/
+#define NT_FRAME_SIZE	(AMRNB_FRAME_SIZE + NT_FRAME_HEADER_SIZE)
+#define DMASZ		(FRAME_SIZE * FRAME_NUM)
+#define NT_DMASZ	(NT_FRAME_SIZE * FRAME_NUM)
+#define OUT_FRAME_NUM	2
+#define OUT_BUFFER_SIZE (4 * 1024 + NT_FRAME_HEADER_SIZE)
+#define BUFFER_SIZE	(OUT_BUFFER_SIZE * OUT_FRAME_NUM)
+
+/* Offset from beginning of buffer*/
+#define AUDPREPROC_AMRNB_EOS_FLG_OFFSET 0x0A
+#define AUDPREPROC_AMRNB_EOS_FLG_MASK 0x01
+#define AUDPREPROC_AMRNB_EOS_NONE 0x0 /* No EOS detected */
+#define AUDPREPROC_AMRNB_EOS_SET 0x1 /* EOS set in meta field */
+
+struct buffer {
+	void *data;
+	uint32_t size;
+	uint32_t read;
+	uint32_t addr;
+	uint32_t used;
+	uint32_t mfield_sz;
+};
+
+struct audio_amrnb_in {
+	struct buffer in[FRAME_NUM];
+
+	spinlock_t dsp_lock;
+
+	atomic_t in_bytes;
+	atomic_t in_samples;
+
+	struct mutex lock;
+	struct mutex read_lock;
+	wait_queue_head_t wait;
+	wait_queue_head_t wait_enable;
+	/*write section*/
+	struct buffer out[OUT_FRAME_NUM];
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed;	/* number of buffers the dsp is waiting for */
+	uint32_t out_count;
+
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+	int32_t out_phys; /* physical address of write buffer */
+	char *out_data;
+	uint8_t mfield; /* meta field embedded in data */
+	uint8_t wflush; /*write flush */
+	uint8_t rflush; /*read flush*/
+	uint32_t out_frame_cnt;
+
+	struct msm_adsp_module *audrec;
+	struct msm_adsp_module *audpre;
+
+
+	/* configuration to use on next enable */
+	uint32_t samp_rate;
+	uint32_t channel_mode;
+	uint32_t buffer_size;
+	uint32_t enc_type; /* 0 for WAV ,1 for AAC,10 for AMRNB */
+	uint32_t mode; /* T or NT Mode*/
+	struct msm_audio_amrnb_enc_config amrnb_enc_cfg;
+
+	uint32_t dsp_cnt;
+	uint32_t in_head; /* next buffer dsp will write */
+	uint32_t in_tail; /* next buffer read() will read */
+	uint32_t in_count; /* number of buffers available to read() */
+
+	uint32_t eos_ack;
+	uint32_t flush_ack;
+
+	const char *module_name;
+	unsigned queue_ids;
+	uint16_t enc_id; /* Session Id */
+
+	unsigned short samp_rate_index;
+	uint32_t audrec_obj_idx ;
+
+	struct audmgr audmgr;
+
+	/* data allocated for various buffers */
+	char *data;
+	dma_addr_t phys;
+	void *map_v_write;
+
+	uint8_t opened;
+	uint8_t enabled;
+	uint8_t running;
+	uint8_t stopped; /* set when stopped, cleared on flush */
+};
+
+struct audio_frame {
+	uint16_t frame_count_lsw;
+	uint16_t frame_count_msw;
+	uint16_t frame_length;
+	uint16_t erased_pcm;
+	unsigned char raw_bitstream[];
+} __packed;
+
+struct audio_frame_nt {
+	uint16_t metadata_len;
+	uint16_t frame_count_lsw;
+	uint16_t frame_count_msw;
+	uint16_t frame_length;
+	uint16_t erased_pcm;
+	uint16_t reserved;
+	uint16_t time_stamp_dword_lsw;
+	uint16_t time_stamp_dword_msw;
+	uint16_t time_stamp_lsw;
+	uint16_t time_stamp_msw;
+	uint16_t nflag_lsw;
+	uint16_t nflag_msw;
+	unsigned char raw_bitstream[]; /* samples */
+} __packed;
+
+struct amrnb_encoded_meta_out {
+	uint16_t metadata_len;
+	uint16_t time_stamp_dword_lsw;
+	uint16_t time_stamp_dword_msw;
+	uint16_t time_stamp_lsw;
+	uint16_t time_stamp_msw;
+	uint16_t nflag_lsw;
+	uint16_t nflag_msw;
+};
+
+/* Audrec Queue command sent macro's */
+#define audio_send_queue_pre(audio, cmd, len) \
+	msm_adsp_write(audio->audpre, QDSP_uPAudPreProcCmdQueue, cmd, len)
+
+#define audio_send_queue_recbs(audio, cmd, len) \
+	msm_adsp_write(audio->audrec, ((audio->queue_ids & 0xFFFF0000) >> 16),\
+			cmd, len)
+#define audio_send_queue_rec(audio, cmd, len) \
+	msm_adsp_write(audio->audrec, (audio->queue_ids & 0x0000FFFF),\
+			cmd, len)
+
+static int audamrnb_in_dsp_enable(struct audio_amrnb_in *audio, int enable);
+static int audamrnb_in_encparam_config(struct audio_amrnb_in *audio);
+static int audamrnb_in_encmem_config(struct audio_amrnb_in *audio);
+static int audamrnb_in_dsp_read_buffer(struct audio_amrnb_in *audio,
+				uint32_t read_cnt);
+static void audamrnb_in_flush(struct audio_amrnb_in *audio);
+
+static void audamrnb_in_get_dsp_frames(struct audio_amrnb_in *audio);
+static int audpcm_config(struct audio_amrnb_in *audio);
+static void audamrnb_out_flush(struct audio_amrnb_in *audio);
+static int audamrnb_in_routing_mode_config(struct audio_amrnb_in *audio);
+static void audrec_pcm_send_data(struct audio_amrnb_in *audio, unsigned needed);
+static void audamrnb_nt_in_get_dsp_frames(struct audio_amrnb_in *audio);
+static void audamrnb_in_flush(struct audio_amrnb_in *audio);
+
+static unsigned convert_samp_index(unsigned index)
+{
+	switch (index) {
+	case RPC_AUD_DEF_SAMPLE_RATE_48000:	return 48000;
+	case RPC_AUD_DEF_SAMPLE_RATE_44100:	return 44100;
+	case RPC_AUD_DEF_SAMPLE_RATE_32000:	return 32000;
+	case RPC_AUD_DEF_SAMPLE_RATE_24000:	return 24000;
+	case RPC_AUD_DEF_SAMPLE_RATE_22050:	return 22050;
+	case RPC_AUD_DEF_SAMPLE_RATE_16000:	return 16000;
+	case RPC_AUD_DEF_SAMPLE_RATE_12000:	return 12000;
+	case RPC_AUD_DEF_SAMPLE_RATE_11025:	return 11025;
+	case RPC_AUD_DEF_SAMPLE_RATE_8000:	return 8000;
+	default:				return 11025;
+	}
+}
+
+/* must be called with audio->lock held */
+static int audamrnb_in_enable(struct audio_amrnb_in *audio)
+{
+	struct audmgr_config cfg;
+	int32_t rc;
+
+	if (audio->enabled)
+		return 0;
+
+	cfg.tx_rate = audio->samp_rate;
+	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+	cfg.def_method = RPC_AUD_DEF_METHOD_RECORD;
+	cfg.codec = RPC_AUD_DEF_CODEC_AMR_NB;
+	cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+		rc = audmgr_enable(&audio->audmgr, &cfg);
+		if (rc < 0)
+			return rc;
+
+		if (msm_adsp_enable(audio->audpre)) {
+			audmgr_disable(&audio->audmgr);
+			MM_ERR("msm_adsp_enable(audpre) failed\n");
+			return -ENODEV;
+		}
+	}
+	if (msm_adsp_enable(audio->audrec)) {
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+			audmgr_disable(&audio->audmgr);
+			msm_adsp_disable(audio->audpre);
+		}
+		MM_ERR("msm_adsp_enable(audrec) failed\n");
+		return -ENODEV;
+	}
+
+	audio->enabled = 1;
+	audamrnb_in_dsp_enable(audio, 1);
+
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audamrnb_in_disable(struct audio_amrnb_in *audio)
+{
+	if (audio->enabled) {
+		audio->enabled = 0;
+
+		audamrnb_in_dsp_enable(audio, 0);
+
+		wake_up(&audio->wait);
+		wait_event_interruptible_timeout(audio->wait_enable,
+				audio->running == 0, 1*HZ);
+		msm_adsp_disable(audio->audrec);
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+			msm_adsp_disable(audio->audpre);
+			audmgr_disable(&audio->audmgr);
+		}
+	}
+	return 0;
+}
+
+/* ------------------- dsp --------------------- */
+static void audpre_dsp_event(void *data, unsigned id, size_t len,
+			    void (*getevent)(void *ptr, size_t len))
+{
+	uint16_t msg[2];
+	getevent(msg, sizeof(msg));
+
+	switch (id) {
+	case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
+		MM_DBG("type %d, status_flag %d\n", msg[0], msg[1]);
+		break;
+	case AUDPREPROC_MSG_ERROR_MSG_ID:
+		MM_ERR("err_index %d\n", msg[0]);
+		break;
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audpreproctask)\n");
+		break;
+	default:
+		MM_ERR("unknown event %d\n", id);
+	}
+}
+
+static void audamrnb_in_get_dsp_frames(struct audio_amrnb_in *audio)
+{
+	struct audio_frame *frame;
+	uint32_t index;
+	unsigned long flags;
+	index = audio->in_head;
+
+	frame = (void *) (((char *)audio->in[index].data) -
+		sizeof(*frame));
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+
+	/* Send	Complete Transcoded Data, not actual frame part  */
+	audio->in[index].size = FRAME_SIZE - (sizeof(*frame));
+	/* statistics of read */
+	atomic_add(audio->in[index].size, &audio->in_bytes);
+	atomic_add(1, &audio->in_samples);
+
+	audio->in_head = (audio->in_head + 1) & (FRAME_NUM - 1);
+
+	/* If overflow, move the tail index foward. */
+	if (audio->in_head == audio->in_tail) {
+		MM_ERR("Error! not able to keep up the read\n");
+		audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
+		MM_ERR("in_count = %d\n", audio->in_count);
+	} else
+		audio->in_count++;
+
+	audamrnb_in_dsp_read_buffer(audio, audio->dsp_cnt++);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+
+	wake_up(&audio->wait);
+}
+
+static void audamrnb_nt_in_get_dsp_frames(struct audio_amrnb_in *audio)
+{
+	struct audio_frame_nt *nt_frame;
+	uint32_t index;
+	unsigned long flags;
+
+	index = audio->in_head;
+	nt_frame = (void *) (((char *)audio->in[index].data) - \
+				sizeof(struct audio_frame_nt));
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->in[index].size = nt_frame->frame_length;
+	/* statistics of read */
+	atomic_add(audio->in[index].size, &audio->in_bytes);
+	atomic_add(1, &audio->in_samples);
+
+	audio->in_head = (audio->in_head + 1) & (FRAME_NUM - 1);
+
+	/* If overflow, move the tail index foward. */
+	if (audio->in_head == audio->in_tail)
+		MM_DBG("Error! not able to keep up the read\n");
+	else
+		audio->in_count++;
+
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	wake_up(&audio->wait);
+}
+
+static int audrec_pcm_buffer_ptr_refresh(struct audio_amrnb_in *audio,
+				       unsigned idx, unsigned len)
+{
+	struct audrec_cmd_pcm_buffer_ptr_refresh_arm_enc cmd;
+
+	if (len ==  NT_FRAME_HEADER_SIZE)
+		len = len / 2;
+	else
+		len = (len + NT_FRAME_HEADER_SIZE) / 2;
+	MM_DBG("len = %d\n", len);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_PCM_BUFFER_PTR_REFRESH_ARM_TO_ENC;
+	cmd.num_buffers = 1;
+	if (cmd.num_buffers == 1) {
+		cmd.buf_address_length[0] = (audio->out[idx].addr &
+							0xffff0000) >> 16;
+		cmd.buf_address_length[1] = (audio->out[idx].addr &
+							0x0000ffff);
+		cmd.buf_address_length[2] = (len & 0xffff0000) >> 16;
+		cmd.buf_address_length[3] = (len & 0x0000ffff);
+	}
+	audio->out_frame_cnt++;
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static int audpcm_config(struct audio_amrnb_in *audio)
+{
+	struct audrec_cmd_pcm_cfg_arm_to_enc cmd;
+	MM_DBG("\n");
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_PCM_CFG_ARM_TO_ENC;
+	cmd.config_update_flag = AUDREC_PCM_CONFIG_UPDATE_FLAG_ENABLE;
+	cmd.enable_flag = AUDREC_ENABLE_FLAG_VALUE;
+	cmd.sampling_freq = convert_samp_index(audio->samp_rate);
+	if (!audio->channel_mode)
+		cmd.channels = 1;
+	else
+		cmd.channels = 2;
+	cmd.frequency_of_intimation = 1;
+	cmd.max_number_of_buffers = OUT_FRAME_NUM;
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+
+static int audamrnb_in_routing_mode_config(struct audio_amrnb_in *audio)
+{
+	struct audrec_cmd_routing_mode cmd;
+
+	MM_DBG("\n");
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_ROUTING_MODE;
+	if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)
+		cmd.routing_mode = 1;
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static void audrec_dsp_event(void *data, unsigned id, size_t len,
+			    void (*getevent)(void *ptr, size_t len))
+{
+	struct audio_amrnb_in *audio = data;
+	if (data)
+		audio = data;
+	else {
+		MM_ERR("invalid data for event %x\n", id);
+		return;
+	}
+
+	switch (id) {
+	case AUDREC_MSG_CMD_CFG_DONE_MSG: {
+		struct audrec_msg_cmd_cfg_done_msg cmd_cfg_done_msg;
+		getevent(&cmd_cfg_done_msg, AUDREC_MSG_CMD_CFG_DONE_MSG_LEN);
+		if (cmd_cfg_done_msg.audrec_enc_type & \
+				AUDREC_MSG_CFG_DONE_ENC_ENA) {
+			audio->audrec_obj_idx = cmd_cfg_done_msg.audrec_obj_idx;
+			MM_DBG("CFG ENABLED\n");
+			if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
+				MM_DBG("routing command\n");
+				audamrnb_in_routing_mode_config(audio);
+			} else {
+				audamrnb_in_encmem_config(audio);
+			}
+		} else {
+			MM_DBG("CFG SLEEP\n");
+			audio->running = 0;
+			wake_up(&audio->wait_enable);
+		}
+		break;
+	}
+	case AUDREC_MSG_CMD_ROUTING_MODE_DONE_MSG: {
+		struct audrec_msg_cmd_routing_mode_done_msg \
+			routing_msg;
+		getevent(&routing_msg, AUDREC_MSG_CMD_ROUTING_MODE_DONE_MSG);
+		MM_DBG("AUDREC_MSG_CMD_ROUTING_MODE_DONE_MSG");
+		if (routing_msg.configuration == 0) {
+			MM_ERR("routing configuration failed\n");
+			audio->running = 0;
+			wake_up(&audio->wait_enable);
+		} else
+			audamrnb_in_encmem_config(audio);
+		break;
+	}
+	case AUDREC_MSG_CMD_AREC_MEM_CFG_DONE_MSG: {
+		MM_DBG("AREC_MEM_CFG_DONE_MSG\n");
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
+			audamrnb_in_encparam_config(audio);
+		else
+			audpcm_config(audio);
+		break;
+	}
+
+	case AUDREC_CMD_PCM_CFG_ARM_TO_ENC_DONE_MSG: {
+		MM_DBG("AUDREC_CMD_PCM_CFG_ARM_TO_ENC_DONE_MSG");
+		audamrnb_in_encparam_config(audio);
+	    break;
+	}
+	case AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG: {
+		MM_DBG("AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG\n");
+		audio->running = 1;
+		wake_up(&audio->wait_enable);
+		if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)
+			audrec_pcm_send_data(audio, 1);
+		break;
+	}
+	case AUDREC_CMD_PCM_BUFFER_PTR_UPDATE_ARM_TO_ENC_MSG: {
+		MM_DBG("ptr_update recieved from DSP\n");
+		audrec_pcm_send_data(audio, 1);
+		break;
+	}
+	case AUDREC_MSG_NO_EXT_PKT_AVAILABLE_MSG: {
+		struct audrec_msg_no_ext_pkt_avail_msg err_msg;
+		getevent(&err_msg, AUDREC_MSG_NO_EXT_PKT_AVAILABLE_MSG_LEN);
+		MM_DBG("NO_EXT_PKT_AVAILABLE_MSG %x\n",\
+			err_msg.audrec_err_id);
+		break;
+	}
+	case AUDREC_MSG_PACKET_READY_MSG: {
+		struct audrec_msg_packet_ready_msg pkt_ready_msg;
+
+		getevent(&pkt_ready_msg, AUDREC_MSG_PACKET_READY_MSG_LEN);
+		MM_DBG("UP_PACKET_READY_MSG: write cnt msw  %d \
+		write cnt lsw %d read cnt msw %d  read cnt lsw %d \n",\
+		pkt_ready_msg.pkt_counter_msw, \
+		pkt_ready_msg.pkt_counter_lsw, \
+		pkt_ready_msg.pkt_read_cnt_msw, \
+		pkt_ready_msg.pkt_read_cnt_lsw);
+
+		audamrnb_in_get_dsp_frames(audio);
+		break;
+	}
+	case AUDREC_UP_NT_PACKET_READY_MSG: {
+		struct audrec_up_nt_packet_ready_msg pkt_ready_msg;
+
+		getevent(&pkt_ready_msg, AUDREC_UP_NT_PACKET_READY_MSG_LEN);
+		MM_DBG("UP_NT_PACKET_READY_MSG: write cnt lsw  %d \
+		write cnt msw %d read cnt lsw %d  read cnt msw %d \n",\
+		pkt_ready_msg.audrec_packetwrite_cnt_lsw, \
+		pkt_ready_msg.audrec_packetwrite_cnt_msw, \
+		pkt_ready_msg.audrec_upprev_readcount_lsw, \
+		pkt_ready_msg.audrec_upprev_readcount_msw);
+
+		audamrnb_nt_in_get_dsp_frames(audio);
+		break;
+	}
+	case AUDREC_CMD_FLUSH_DONE_MSG: {
+		audio->wflush = 0;
+		audio->rflush = 0;
+		audio->flush_ack = 1;
+		wake_up(&audio->write_wait);
+		MM_DBG("flush ack recieved\n");
+		break;
+	}
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module \
+				enable/disable(audrectask)\n");
+		break;
+	default:
+		MM_ERR("unknown event %d\n", id);
+	}
+}
+
+struct msm_adsp_ops audpre_amrnb_adsp_ops = {
+	.event = audpre_dsp_event,
+};
+
+struct msm_adsp_ops audrec_amrnb_adsp_ops = {
+	.event = audrec_dsp_event,
+};
+
+static int audamrnb_in_dsp_enable(struct audio_amrnb_in *audio, int enable)
+{
+	struct audrec_cmd_enc_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_ENC_CFG;
+	cmd.audrec_enc_type = (audio->enc_type & 0xFF) |
+	(enable ? AUDREC_CMD_ENC_ENA : AUDREC_CMD_ENC_DIS);
+	/* Don't care on enable, required on disable */
+	cmd.audrec_obj_idx = audio->audrec_obj_idx;
+
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static int audamrnb_in_encmem_config(struct audio_amrnb_in *audio)
+{
+	struct audrec_cmd_arecmem_cfg cmd;
+	uint16_t *data = (void *) audio->data;
+	uint8_t n;
+	uint16_t header_len = 0;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	cmd.cmd_id = AUDREC_CMD_ARECMEM_CFG;
+	cmd.audrec_obj_idx = audio->audrec_obj_idx;
+	/* Rate at which packet complete message comes */
+	cmd.audrec_up_pkt_intm_cnt = 1;
+	cmd.audrec_extpkt_buffer_msw = audio->phys >> 16;
+	cmd.audrec_extpkt_buffer_lsw = audio->phys;
+	/* Max Buffer no available for frames */
+	cmd.audrec_extpkt_buffer_num = FRAME_NUM;
+
+	/* prepare buffer pointers:
+	 * T:36 bytes amrnb packet + 4 halfword header
+	 * NT:36 bytes amrnb packet + 12 halfword header
+	 */
+	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
+		header_len = FRAME_HEADER_SIZE/2;
+	else
+		header_len = NT_FRAME_HEADER_SIZE/2;
+
+	for (n = 0; n < FRAME_NUM; n++) {
+		audio->in[n].data = data + header_len;
+		data += (AMRNB_FRAME_SIZE/2) + header_len;
+		MM_DBG("0x%8x\n", (uint32_t)(audio->in[n].data - header_len*2));
+	}
+
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static int audamrnb_in_encparam_config(struct audio_amrnb_in *audio)
+{
+	struct audrec_cmd_arecparam_amrnb_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	cmd.common.cmd_id = AUDREC_CMD_ARECPARAM_CFG;
+	cmd.common.audrec_obj_idx = audio->audrec_obj_idx;
+	cmd.samp_rate_idx = audio->samp_rate_index; /* 8k Sampling rate */
+	cmd.voicememoencweight1 = audio->amrnb_enc_cfg.voicememoencweight1;
+	cmd.voicememoencweight2 = audio->amrnb_enc_cfg.voicememoencweight2;
+	cmd.voicememoencweight3 = audio->amrnb_enc_cfg.voicememoencweight3;
+	cmd.voicememoencweight4 = audio->amrnb_enc_cfg.voicememoencweight4;
+	cmd.update_mode = 0x8000 | 0x0000;
+	cmd.dtx_mode = audio->amrnb_enc_cfg.dtx_mode_enable;
+	cmd.test_mode = audio->amrnb_enc_cfg.test_mode_enable;
+	cmd.used_mode = audio->amrnb_enc_cfg.enc_mode;
+
+	MM_DBG("cmd.common.cmd_id = 0x%4x\n", cmd.common.cmd_id);
+	MM_DBG("cmd.common.audrec_obj_idx = 0x%4x\n",
+			cmd.common.audrec_obj_idx);
+	MM_DBG("cmd.samp_rate_idx = 0x%4x\n", cmd.samp_rate_idx);
+	MM_DBG("cmd.voicememoencweight1 = 0x%4x\n",
+			cmd.voicememoencweight1);
+	MM_DBG("cmd.voicememoencweight2 = 0x%4x\n",
+			cmd.voicememoencweight2);
+	MM_DBG("cmd.voicememoencweight3 = 0x%4x\n",
+			cmd.voicememoencweight3);
+	MM_DBG("cmd.voicememoencweight4 = 0x%4x\n",
+			cmd.voicememoencweight4);
+	MM_DBG("cmd.update_mode = 0x%4x\n", cmd.update_mode);
+	MM_DBG("cmd.dtx_mode = 0x%4x\n", cmd.dtx_mode);
+	MM_DBG("cmd.test_mode = 0x%4x\n", cmd.test_mode);
+	MM_DBG("cmd.used_mode = 0x%4x\n", cmd.used_mode);
+
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static int audamrnb_flush_command(struct audio_amrnb_in *audio)
+{
+	struct audrec_cmd_flush cmd;
+	MM_DBG("\n");
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_FLUSH;
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+static int audamrnb_in_dsp_read_buffer(struct audio_amrnb_in *audio,
+		uint32_t read_cnt)
+{
+	audrec_cmd_packet_ext_ptr cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_PACKET_EXT_PTR;
+	cmd.type = audio->audrec_obj_idx;
+	cmd.curr_rec_count_msw = read_cnt >> 16;
+	cmd.curr_rec_count_lsw = read_cnt;
+
+	return audio_send_queue_recbs(audio, &cmd, sizeof(cmd));
+}
+
+/* ------------------- device --------------------- */
+
+static void audamrnb_ioport_reset(struct audio_amrnb_in *audio)
+{
+	/* Make sure read/write thread are free from
+	 * sleep and knowing that system is not able
+	 * to process io request at the moment
+	 */
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audamrnb_in_flush(audio);
+	mutex_unlock(&audio->write_lock);
+	wake_up(&audio->wait);
+	mutex_lock(&audio->read_lock);
+	audamrnb_out_flush(audio);
+	mutex_unlock(&audio->read_lock);
+}
+
+static void audamrnb_in_flush(struct audio_amrnb_in *audio)
+{
+	uint8_t i;
+
+	audio->dsp_cnt = 0;
+	audio->in_head = 0;
+	audio->in_tail = 0;
+	audio->in_count = 0;
+	audio->eos_ack = 0;
+	for (i = FRAME_NUM-1; i >= 0; i--) {
+		audio->in[i].size = 0;
+		audio->in[i].read = 0;
+	}
+	MM_DBG("in_bytes %d\n", atomic_read(&audio->in_bytes));
+	MM_DBG("in_samples %d\n", atomic_read(&audio->in_samples));
+	atomic_set(&audio->in_bytes, 0);
+	atomic_set(&audio->in_samples, 0);
+}
+
+static void audamrnb_out_flush(struct audio_amrnb_in *audio)
+{
+	uint8_t i;
+
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->out_count = 0;
+	for (i = OUT_FRAME_NUM-1; i >= 0; i--) {
+		audio->out[i].size = 0;
+		audio->out[i].read = 0;
+		audio->out[i].used = 0;
+	}
+}
+
+/* ------------------- device --------------------- */
+static long audamrnb_in_ioctl(struct file *file,
+				unsigned int cmd, unsigned long arg)
+{
+	struct audio_amrnb_in *audio = file->private_data;
+	int32_t rc = 0;
+
+	MM_DBG("\n");
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = atomic_read(&audio->in_bytes);
+		stats.sample_count = atomic_read(&audio->in_samples);
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return rc;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START: {
+		rc = audamrnb_in_enable(audio);
+		if (!rc) {
+			rc =
+			wait_event_interruptible_timeout(audio->wait_enable,
+				audio->running != 0, 1*HZ);
+			MM_INFO("state %d rc = %d\n", audio->running, rc);
+
+			if (audio->running == 0)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		audio->stopped = 0;
+		break;
+	}
+	case AUDIO_STOP: {
+		rc = audamrnb_in_disable(audio);
+		audio->stopped = 1;
+		break;
+	}
+	case AUDIO_FLUSH: {
+		MM_DBG("AUDIO_FLUSH\n");
+		audio->rflush = 1;
+		audio->wflush = 1;
+		audamrnb_ioport_reset(audio);
+		if (audio->running) {
+			audamrnb_flush_command(audio);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+	struct msm_audio_config cfg;
+		memset(&cfg, 0, sizeof(cfg));
+		if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
+			cfg.buffer_size = OUT_BUFFER_SIZE;
+			cfg.buffer_count = OUT_FRAME_NUM;
+		} else {
+			cfg.buffer_size = audio->buffer_size;
+			cfg.buffer_count = FRAME_NUM;
+		}
+		cfg.sample_rate = convert_samp_index(audio->samp_rate);
+		cfg.channel_count = 1;
+		cfg.type = 0;
+		cfg.unused[0] = 0;
+		cfg.unused[1] = 0;
+		cfg.unused[2] = 0;
+		if (copy_to_user((void *) arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	}
+	case AUDIO_GET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		memset(&cfg, 0, sizeof(cfg));
+		cfg.buffer_size = audio->buffer_size;
+		cfg.buffer_count = FRAME_NUM;
+		if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	}
+	case AUDIO_SET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		/* Allow only single frame */
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+			if (cfg.buffer_size != (FRAME_SIZE - 8)) {
+				rc = -EINVAL;
+				break;
+			}
+		} else {
+			if (cfg.buffer_size != (AMRNB_FRAME_SIZE + 14)) {
+				rc = -EINVAL;
+				break;
+			}
+		}
+		audio->buffer_size = cfg.buffer_size;
+		break;
+	}
+
+	case AUDIO_GET_AMRNB_ENC_CONFIG: {
+		if (copy_to_user((void *)arg, &audio->amrnb_enc_cfg,
+			sizeof(audio->amrnb_enc_cfg)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	}
+	case AUDIO_SET_AMRNB_ENC_CONFIG: {
+		struct msm_audio_amrnb_enc_config cfg;
+		if (copy_from_user
+			(&cfg, (void *)arg, sizeof(cfg))) {
+			rc = -EFAULT;
+		} else
+			rc = 0;
+		audio->amrnb_enc_cfg.voicememoencweight1 =
+					cfg.voicememoencweight1;
+		audio->amrnb_enc_cfg.voicememoencweight2 =
+					cfg.voicememoencweight2;
+		audio->amrnb_enc_cfg.voicememoencweight3 =
+					cfg.voicememoencweight3;
+		audio->amrnb_enc_cfg.voicememoencweight4 =
+					cfg.voicememoencweight4;
+		audio->amrnb_enc_cfg.dtx_mode_enable = cfg.dtx_mode_enable;
+		audio->amrnb_enc_cfg.test_mode_enable = cfg.test_mode_enable;
+		audio->amrnb_enc_cfg.enc_mode = cfg.enc_mode;
+		/* Run time change of Param */
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static ssize_t audamrnb_in_read(struct file *file,
+				char __user *buf,
+				size_t count, loff_t *pos)
+{
+	struct audio_amrnb_in *audio = file->private_data;
+	unsigned long flags;
+	const char __user *start = buf;
+	void *data;
+	uint32_t index;
+	uint32_t size;
+	int32_t rc = 0;
+	struct amrnb_encoded_meta_out meta_field;
+	struct audio_frame_nt *nt_frame;
+	MM_DBG("count = %d\n", count);
+	mutex_lock(&audio->read_lock);
+	while (count > 0) {
+		rc = wait_event_interruptible(
+			audio->wait, (audio->in_count > 0) || audio->stopped ||
+			audio->rflush);
+		if (rc < 0)
+			break;
+
+		if (audio->rflush) {
+			rc = -EBUSY;
+			break;
+		}
+		if (audio->stopped && !audio->in_count) {
+			MM_DBG("Driver in stop state, No more buffer to read");
+			rc = 0;/* End of File */
+			break;
+		}
+
+		index = audio->in_tail;
+		data = (uint8_t *) audio->in[index].data;
+		size = audio->in[index].size;
+
+		if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
+			nt_frame = (struct audio_frame_nt *)(data -
+					sizeof(struct audio_frame_nt));
+			memcpy((char *)&meta_field.time_stamp_dword_lsw,
+				(char *)&nt_frame->time_stamp_dword_lsw,
+				(sizeof(struct amrnb_encoded_meta_out) - \
+				sizeof(uint16_t)));
+			meta_field.metadata_len =
+					sizeof(struct amrnb_encoded_meta_out);
+			if (copy_to_user((char *)start, (char *)&meta_field,
+				sizeof(struct amrnb_encoded_meta_out))) {
+				rc = -EFAULT;
+				break;
+			}
+			if (nt_frame->nflag_lsw & 0x0001) {
+				MM_ERR("recieved EOS in read call\n");
+				audio->eos_ack = 1;
+			}
+			buf += sizeof(struct amrnb_encoded_meta_out);
+			count -= sizeof(struct amrnb_encoded_meta_out);
+		}
+		if (count >= size) {
+			/* order the reads on the buffer */
+			dma_coherent_post_ops();
+			if (copy_to_user(buf, data, size)) {
+				rc = -EFAULT;
+				break;
+			}
+			spin_lock_irqsave(&audio->dsp_lock, flags);
+			if (index != audio->in_tail) {
+				/* overrun -- data is
+				 * invalid and we need to retry */
+				spin_unlock_irqrestore(&audio->dsp_lock, flags);
+				continue;
+			}
+			audio->in[index].size = 0;
+			audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
+			audio->in_count--;
+			spin_unlock_irqrestore(&audio->dsp_lock, flags);
+			count -= size;
+			buf += size;
+			if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)) {
+				if (!audio->eos_ack) {
+					MM_DBG("sending read ptr command \
+							%d %d\n",
+							audio->dsp_cnt,
+							audio->in_tail);
+					audamrnb_in_dsp_read_buffer(audio,
+							audio->dsp_cnt++);
+				}
+			}
+		} else {
+			MM_ERR("short read\n");
+			break;
+		}
+
+	}
+	mutex_unlock(&audio->read_lock);
+
+	if (buf > start)
+		return buf - start;
+
+	return rc;
+}
+
+static void audrec_pcm_send_data(struct audio_amrnb_in *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+	MM_DBG("\n");
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (needed && !audio->wflush) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			MM_DBG("frame %d free\n", audio->out_tail);
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+			audrec_pcm_buffer_ptr_refresh(audio,
+						 audio->out_tail,
+						    frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+ done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static int audamrnb_in_fsync(struct file *file, loff_t a, loff_t b, int datasync)
+
+{
+	struct audio_amrnb_in *audio = file->private_data;
+	int32_t rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (!audio->running || (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)) {
+		rc = -EINVAL;
+		goto done_nolock;
+	}
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->write_wait,
+			audio->wflush);
+	MM_DBG("waked on by some event audio->wflush = %d\n", audio->wflush);
+
+	if (rc < 0)
+		goto done;
+	else if (audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+done:
+	mutex_unlock(&audio->write_lock);
+done_nolock:
+	return rc;
+
+}
+
+int audrec_amrnb_process_eos(struct audio_amrnb_in *audio,
+		const char __user *buf_start, unsigned short mfield_size)
+{
+	struct buffer *frame;
+	int32_t rc = 0;
+
+	frame = audio->out + audio->out_head;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->out_needed &&
+		audio->out[0].used == 0 &&
+		audio->out[1].used == 0)
+		|| (audio->stopped)
+		|| (audio->wflush));
+
+	if (rc < 0)
+		goto done;
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+	if (copy_from_user(frame->data, buf_start, mfield_size)) {
+		rc = -EFAULT;
+		goto done;
+	}
+
+	frame->mfield_sz = mfield_size;
+	audio->out_head ^= 1;
+	frame->used = mfield_size;
+	MM_DBG("copying meta_out frame->used = %d\n", frame->used);
+	audrec_pcm_send_data(audio, 0);
+done:
+	return rc;
+}
+
+static ssize_t audamrnb_in_write(struct file *file,
+				const char __user *buf,
+				size_t count, loff_t *pos)
+{
+	struct audio_amrnb_in *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	char *cpy_ptr;
+	int32_t rc = 0, eos_condition = AUDPREPROC_AMRNB_EOS_NONE;
+	unsigned short mfield_size = 0;
+	int32_t write_count = 0;
+	MM_DBG("cnt=%d\n", count);
+
+	if (count & 1)
+		return -EINVAL;
+
+	if (audio->mode != MSM_AUD_ENC_MODE_NONTUNNEL)
+		return -EINVAL;
+
+	mutex_lock(&audio->write_lock);
+	frame = audio->out + audio->out_head;
+	/* if supplied count is more than driver buffer size
+	 * then only copy driver buffer size
+	 */
+	if (count > frame->size)
+		count = frame->size;
+
+	write_count = count;
+	cpy_ptr = frame->data;
+	rc = wait_event_interruptible(audio->write_wait,
+				      (frame->used == 0)
+					|| (audio->stopped)
+					|| (audio->wflush));
+	if (rc < 0)
+		goto error;
+
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto error;
+	}
+	if (audio->mfield) {
+		if (buf == start) {
+			/* Processing beginning of user buffer */
+			if (__get_user(mfield_size,
+				(unsigned short __user *) buf)) {
+				rc = -EFAULT;
+				goto error;
+			} else if (mfield_size > count) {
+				rc = -EINVAL;
+				goto error;
+			}
+			MM_DBG("mf offset_val %x\n", mfield_size);
+			if (copy_from_user(cpy_ptr, buf, mfield_size)) {
+				rc = -EFAULT;
+				goto error;
+			}
+			/* Check if EOS flag is set and buffer has
+			 * contains just meta field
+			 */
+			if (cpy_ptr[AUDPREPROC_AMRNB_EOS_FLG_OFFSET] &
+					AUDPREPROC_AMRNB_EOS_FLG_MASK) {
+				eos_condition = AUDPREPROC_AMRNB_EOS_SET;
+				MM_DBG("EOS SET\n");
+				if (mfield_size == count) {
+					buf += mfield_size;
+					eos_condition = 0;
+					goto exit;
+				} else
+				cpy_ptr[AUDPREPROC_AMRNB_EOS_FLG_OFFSET] &=
+					~AUDPREPROC_AMRNB_EOS_FLG_MASK;
+			}
+			cpy_ptr += mfield_size;
+			count -= mfield_size;
+			buf += mfield_size;
+		} else {
+			mfield_size = 0;
+			MM_DBG("continuous buffer\n");
+		}
+		frame->mfield_sz = mfield_size;
+	}
+	MM_DBG("copying the stream count = %d\n", count);
+	if (copy_from_user(cpy_ptr, buf, count)) {
+		rc = -EFAULT;
+		goto error;
+	}
+exit:
+	frame->used = count;
+	audio->out_head ^= 1;
+	if (!audio->flush_ack)
+		audrec_pcm_send_data(audio, 0);
+	else {
+		audrec_pcm_send_data(audio, 1);
+		audio->flush_ack = 0;
+	}
+	if (eos_condition == AUDPREPROC_AMRNB_EOS_SET)
+		rc = audrec_amrnb_process_eos(audio, start, mfield_size);
+	mutex_unlock(&audio->write_lock);
+	return write_count;
+error:
+	mutex_unlock(&audio->write_lock);
+	return rc;
+}
+
+static int audamrnb_in_release(struct inode *inode, struct file *file)
+{
+	struct audio_amrnb_in *audio = file->private_data;
+	int32_t dma_size = 0;
+	mutex_lock(&audio->lock);
+	audamrnb_in_disable(audio);
+	audamrnb_in_flush(audio);
+	msm_adsp_put(audio->audrec);
+
+	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
+		msm_adsp_put(audio->audpre);
+
+	audpreproc_aenc_free(audio->enc_id);
+	audio->audrec = NULL;
+	audio->audpre = NULL;
+	audio->opened = 0;
+	if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) && \
+	   (audio->out_data)) {
+		iounmap(audio->map_v_write);
+		free_contiguous_memory_by_paddr(audio->out_phys);
+		audio->out_data = NULL;
+	}
+	if (audio->data) {
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
+			dma_size = DMASZ;
+		else
+			dma_size = NT_DMASZ;
+
+		dma_free_coherent(NULL,
+			dma_size, audio->data, audio->phys);
+		audio->data = NULL;
+	}
+	mutex_unlock(&audio->lock);
+	return 0;
+}
+
+struct audio_amrnb_in the_audio_amrnb_in;
+
+static int audamrnb_in_open(struct inode *inode, struct file *file)
+{
+	struct audio_amrnb_in *audio = &the_audio_amrnb_in;
+	int32_t rc;
+	int encid;
+	int32_t dma_size = 0;
+
+	mutex_lock(&audio->lock);
+	if (audio->opened) {
+		rc = -EBUSY;
+		goto done;
+	}
+	if ((file->f_mode & FMODE_WRITE) &&
+		(file->f_mode & FMODE_READ)) {
+		audio->mode = MSM_AUD_ENC_MODE_NONTUNNEL;
+		dma_size = NT_DMASZ;
+		MM_DBG("Opened for non tunnel mode encoding\n");
+	} else if (!(file->f_mode & FMODE_WRITE) &&
+				(file->f_mode & FMODE_READ)) {
+		audio->mode = MSM_AUD_ENC_MODE_TUNNEL;
+		dma_size = DMASZ;
+		MM_DBG("Opened for tunnel mode encoding\n");
+	} else {
+		MM_ERR("Invalid mode\n");
+		rc = -EACCES;
+		goto done;
+	}
+
+	/* Settings will be re-config at AUDIO_SET_CONFIG,
+	 * but at least we need to have initial config
+	 */
+	audio->samp_rate = RPC_AUD_DEF_SAMPLE_RATE_8000,
+	audio->samp_rate_index = AUDREC_CMD_SAMP_RATE_INDX_8000;
+	audio->channel_mode = AUDREC_CMD_STEREO_MODE_MONO;
+	if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)
+			audio->buffer_size = (AMRNB_FRAME_SIZE + 14);
+	else
+			audio->buffer_size = (FRAME_SIZE - 8);
+	audio->enc_type = AUDREC_CMD_TYPE_0_INDEX_AMRNB | audio->mode;
+
+	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+		rc = audmgr_open(&audio->audmgr);
+		if (rc)
+			goto done;
+	}
+	audio->amrnb_enc_cfg.voicememoencweight1 = 0x0000;
+	audio->amrnb_enc_cfg.voicememoencweight2 = 0x0000;
+	audio->amrnb_enc_cfg.voicememoencweight3 = 0x4000;
+	audio->amrnb_enc_cfg.voicememoencweight4 = 0x0000;
+	audio->amrnb_enc_cfg.dtx_mode_enable = 0;
+	audio->amrnb_enc_cfg.test_mode_enable = 0;
+	audio->amrnb_enc_cfg.enc_mode = 7;
+
+	encid = audpreproc_aenc_alloc(audio->enc_type, &audio->module_name,
+			&audio->queue_ids);
+	if (encid < 0) {
+		MM_ERR("No free encoder available\n");
+		rc = -ENODEV;
+		goto done;
+	}
+	audio->enc_id = encid;
+	rc = msm_adsp_get(audio->module_name, &audio->audrec,
+			   &audrec_amrnb_adsp_ops, audio);
+	if (rc) {
+		audpreproc_aenc_free(audio->enc_id);
+		goto done;
+	}
+
+	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+		rc = msm_adsp_get("AUDPREPROCTASK", &audio->audpre,
+				&audpre_amrnb_adsp_ops, audio);
+		if (rc) {
+			msm_adsp_put(audio->audrec);
+			audpreproc_aenc_free(audio->enc_id);
+			goto done;
+		}
+	}
+	audio->dsp_cnt = 0;
+	audio->stopped = 0;
+	audio->wflush = 0;
+	audio->rflush = 0;
+	audio->flush_ack = 0;
+
+	audamrnb_in_flush(audio);
+	audamrnb_out_flush(audio);
+	/* used dma_allco_coherent for backward compatibility with 7x27 */
+	audio->data = dma_alloc_coherent(NULL, dma_size,
+				       &audio->phys, GFP_KERNEL);
+	if (!audio->data) {
+		MM_ERR("Unable to allocate DMA buffer\n");
+		goto evt_error;
+	}
+
+	audio->out_data = NULL;
+	if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
+		audio->out_phys = allocate_contiguous_ebi_nomap(BUFFER_SIZE,
+								SZ_4K);
+		if (!audio->out_phys) {
+			MM_ERR("could not allocate write buffers\n");
+			rc = -ENOMEM;
+			dma_free_coherent(NULL,
+				dma_size, audio->data, audio->phys);
+			goto evt_error;
+		} else {
+			audio->map_v_write = ioremap(
+					audio->out_phys, BUFFER_SIZE);
+			if (IS_ERR(audio->map_v_write)) {
+				MM_ERR("could not map write phys address\n");
+				rc = -ENOMEM;
+				dma_free_coherent(NULL,
+					dma_size, audio->data, audio->phys);
+				free_contiguous_memory_by_paddr(\
+						audio->out_phys);
+				goto evt_error;
+			}
+			audio->out_data = audio->map_v_write;
+			MM_DBG("wr buf: phy addr 0x%08x kernel addr 0x%08x\n",
+					audio->out_phys,
+					(uint32_t)audio->out_data);
+		}
+
+		/* Initialize buffer */
+		audio->out[0].data = audio->out_data + 0;
+		audio->out[0].addr = audio->out_phys + 0;
+		audio->out[0].size = OUT_BUFFER_SIZE;
+
+		audio->out[1].data = audio->out_data + OUT_BUFFER_SIZE;
+		audio->out[1].addr = audio->out_phys + OUT_BUFFER_SIZE;
+		audio->out[1].size = OUT_BUFFER_SIZE;
+
+		MM_DBG("audio->out[0].data = %d  audio->out[1].data = %d",
+				(uint32_t)audio->out[0].data,
+				(uint32_t)audio->out[1].data);
+		audio->mfield = NT_FRAME_HEADER_SIZE;
+		audio->out_frame_cnt++;
+	}
+	file->private_data = audio;
+	audio->opened = 1;
+
+done:
+	mutex_unlock(&audio->lock);
+	return rc;
+evt_error:
+	msm_adsp_put(audio->audrec);
+	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
+		msm_adsp_put(audio->audpre);
+
+	audpreproc_aenc_free(audio->enc_id);
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static const struct file_operations audio_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audamrnb_in_open,
+	.release	= audamrnb_in_release,
+	.read		= audamrnb_in_read,
+	.write		= audamrnb_in_write,
+	.fsync		= audamrnb_in_fsync,
+	.unlocked_ioctl	= audamrnb_in_ioctl,
+};
+
+struct miscdevice audamrnb_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_amrnb_in",
+	.fops	= &audio_fops,
+};
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audamrnb_in_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audamrnb_in_debug_read(struct file *file, char __user *buf,
+		size_t count, loff_t *ppos)
+{
+	const int32_t debug_bufmax = 1024;
+	static char buffer[1024];
+	int32_t n = 0, i;
+	struct audio_amrnb_in *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"enabled %d\n", audio->enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"audrec_obj_idx %d\n", audio->audrec_obj_idx);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"dsp_cnt %d \n", audio->dsp_cnt);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"in_count %d \n", audio->in_count);
+	for (i = 0; i < FRAME_NUM; i++)
+		n += scnprintf(buffer + n, debug_bufmax - n,
+			"audio->in[%d].size %d \n", i, audio->in[i].size);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when record halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"running %d \n", audio->running);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"buffer_size %d \n", audio->buffer_size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"in_head %d \n", audio->in_head);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"in_tail %d \n", audio->in_tail);
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audamrnb_in_debug_fops = {
+	.read = audamrnb_in_debug_read,
+	.open = audamrnb_in_debug_open,
+};
+#endif
+
+static int __init audamrnb_in_init(void)
+{
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+
+	mutex_init(&the_audio_amrnb_in.lock);
+	mutex_init(&the_audio_amrnb_in.read_lock);
+	spin_lock_init(&the_audio_amrnb_in.dsp_lock);
+	init_waitqueue_head(&the_audio_amrnb_in.wait);
+	init_waitqueue_head(&the_audio_amrnb_in.wait_enable);
+	mutex_init(&the_audio_amrnb_in.write_lock);
+	init_waitqueue_head(&the_audio_amrnb_in.write_wait);
+
+#ifdef CONFIG_DEBUG_FS
+	dentry = debugfs_create_file("msm_amrnb_in", S_IFREG | S_IRUGO, NULL,
+		(void *) &the_audio_amrnb_in, &audamrnb_in_debug_fops);
+
+	if (IS_ERR(dentry))
+		MM_ERR("debugfs_create_file failed\n");
+#endif
+	return misc_register(&audamrnb_in_misc);
+}
+
+static void __exit audamrnb_in_exit(void)
+{
+	misc_deregister(&audamrnb_in_misc);
+}
+
+module_init(audamrnb_in_init);
+module_exit(audamrnb_in_exit);
+
+MODULE_DESCRIPTION("MSM AMRNB Encoder driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrwb.c b/arch/arm/mach-msm/qdsp5/audio_amrwb.c
new file mode 100644
index 0000000..b85b153
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_amrwb.c
@@ -0,0 +1,1698 @@
+/* linux/arch/arm/mach-msm/qdsp5/audio_amrwb.c
+ *
+ * amrwb audio decoder device
+ *
+ * Based on the mp3 native driver in arch/arm/mach-msm/qdsp5/audio_mp3.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2009, 2011-2012 Code Aurora Forum. All rights reserved.
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/earlysuspend.h>
+#include <linux/android_pmem.h>
+#include <linux/slab.h>
+#include <linux/msm_audio.h>
+#include <linux/memory_alloc.h>
+
+#include <mach/msm_adsp.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audplaycmdi.h>
+#include <mach/qdsp5/qdsp5audplaymsg.h>
+#include <mach/qdsp5/qdsp5rmtcmdi.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_memtypes.h>
+
+#include "audmgr.h"
+
+#define BUFSZ 4110 /* Hold minimum 700ms voice data and 14 bytes of meta in*/
+#define DMASZ (BUFSZ * 2)
+
+#define AUDPLAY_INVALID_READ_PTR_OFFSET	0xFFFF
+#define AUDDEC_DEC_AMRWB 11
+
+#define PCM_BUFSZ_MIN 8216 /* 100ms worth of data and 24 bytes of meta out*/
+#define PCM_BUF_MAX_COUNT 5	/* DSP only accepts 5 buffers at most
+				   but support 2 buffers currently */
+#define ROUTING_MODE_FTRT 1
+#define ROUTING_MODE_RT 2
+/* Decoder status received from AUDPPTASK */
+#define  AUDPP_DEC_STATUS_SLEEP	0
+#define	 AUDPP_DEC_STATUS_INIT  1
+#define  AUDPP_DEC_STATUS_CFG   2
+#define  AUDPP_DEC_STATUS_PLAY  3
+
+#define AUDAMRWB_METAFIELD_MASK 0xFFFF0000
+#define AUDAMRWB_EOS_FLG_OFFSET 0x0A /* Offset from beginning of buffer */
+#define AUDAMRWB_EOS_FLG_MASK 0x01
+#define AUDAMRWB_EOS_NONE 0x0 /* No EOS detected */
+#define AUDAMRWB_EOS_SET 0x1 /* EOS set in meta field */
+
+#define AUDAMRWB_EVENT_NUM 10 /* Default number of pre-allocated event pkts */
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+	unsigned short mfield_sz; /*only useful for data has meta field */
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct audamrwb_suspend_ctl {
+	struct early_suspend node;
+	struct audio *audio;
+};
+#endif
+
+struct audamrwb_event{
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+
+struct audio {
+	struct buffer out[2];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed;	/* number of buffers the dsp is waiting for */
+
+	atomic_t out_bytes;
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	/* Host PCM section */
+	struct buffer in[PCM_BUF_MAX_COUNT];
+	struct mutex read_lock;
+	wait_queue_head_t read_wait;	/* Wait queue for read */
+	char *read_data;	/* pointer to reader buffer */
+	int32_t read_phys;	/* physical address of reader buffer */
+	uint8_t read_next;	/* index to input buffers to be read next */
+	uint8_t fill_next;	/* index to buffer that DSP should be filling */
+	uint8_t pcm_buf_count;	/* number of pcm buffer allocated */
+	/* ---- End of Host PCM section */
+
+	struct msm_adsp_module *audplay;
+	struct audmgr audmgr;
+
+	/* configuration to use on next enable */
+	uint32_t out_sample_rate;
+	uint32_t out_channel_mode;
+
+	/* data allocated for various buffers */
+	char *data;
+	int32_t phys; /* physical address of write buffer */
+	void *map_v_read;
+	void *map_v_write;
+	int mfield; /* meta field embedded in data */
+	int rflush; /* Read  flush */
+	int wflush; /* Write flush */
+	int opened;
+	int enabled;
+	int running;
+	int stopped;	/* set when stopped, cleared on flush */
+	int pcm_feedback;
+	int buf_refresh;
+	int rmt_resource_released;
+	int teos; /* valid only if tunnel mode & no data left for decoder */
+	enum msm_aud_decoder_state dec_state;	/* Represents decoder state */
+	int reserved; /* A byte is being reserved */
+	char rsv_byte; /* Handle odd length user data */
+
+	const char *module_name;
+	unsigned queue_id;
+	uint16_t dec_id;
+	uint32_t read_ptr_offset;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct audamrwb_suspend_ctl suspend_ctl;
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+
+	wait_queue_head_t wait;
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	wait_queue_head_t event_wait;
+	spinlock_t event_queue_lock;
+	struct mutex get_event_lock;
+	int event_abort;
+
+	int eq_enable;
+	int eq_needs_commit;
+	audpp_cmd_cfg_object_params_eqalizer eq;
+	audpp_cmd_cfg_object_params_volume vol_pan;
+};
+
+static int auddec_dsp_config(struct audio *audio, int enable);
+static void audpp_cmd_cfg_adec_params(struct audio *audio);
+static void audpp_cmd_cfg_routing_mode(struct audio *audio);
+static void audamrwb_send_data(struct audio *audio, unsigned needed);
+static void audamrwb_config_hostpcm(struct audio *audio);
+static void audamrwb_buffer_refresh(struct audio *audio);
+static void audamrwb_dsp_event(void *private, unsigned id, uint16_t *msg);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audamrwb_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload);
+#endif
+
+static int rmt_put_resource(struct audio *audio)
+{
+	struct aud_codec_config_cmd cmd;
+	unsigned short client_idx;
+
+	cmd.cmd_id = RM_CMD_AUD_CODEC_CFG;
+	cmd.client_id = RM_AUD_CLIENT_ID;
+	cmd.task_id = audio->dec_id;
+	cmd.enable = RMT_DISABLE;
+	cmd.dec_type = AUDDEC_DEC_AMRWB;
+	client_idx = ((cmd.client_id << 8) | cmd.task_id);
+
+	return put_adsp_resource(client_idx, &cmd, sizeof(cmd));
+}
+
+static int rmt_get_resource(struct audio *audio)
+{
+	struct aud_codec_config_cmd cmd;
+	unsigned short client_idx;
+
+	cmd.cmd_id = RM_CMD_AUD_CODEC_CFG;
+	cmd.client_id = RM_AUD_CLIENT_ID;
+	cmd.task_id = audio->dec_id;
+	cmd.enable = RMT_ENABLE;
+	cmd.dec_type = AUDDEC_DEC_AMRWB;
+	client_idx = ((cmd.client_id << 8) | cmd.task_id);
+
+	return get_adsp_resource(client_idx, &cmd, sizeof(cmd));
+}
+
+/* must be called with audio->lock held */
+static int audamrwb_enable(struct audio *audio)
+{
+	struct audmgr_config cfg;
+	int rc;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	if (audio->enabled)
+		return 0;
+
+	if (audio->rmt_resource_released == 1) {
+		audio->rmt_resource_released = 0;
+		rc = rmt_get_resource(audio);
+		if (rc) {
+			MM_ERR("ADSP resources are not available for AMRWB \
+				session 0x%08x on decoder: %d\n Ignoring \
+				error and going ahead with the playback\n",
+				(int)audio, audio->dec_id);
+		}
+	}
+
+	audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
+		cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+		cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;
+		cfg.def_method = RPC_AUD_DEF_METHOD_PLAYBACK;
+		cfg.codec = RPC_AUD_DEF_CODEC_AMR_WB;
+		cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+		rc = audmgr_enable(&audio->audmgr, &cfg);
+		if (rc < 0)
+			return rc;
+	}
+
+	if (msm_adsp_enable(audio->audplay)) {
+		MM_ERR("msm_adsp_enable(audplay) failed\n");
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+
+	if (audpp_enable(audio->dec_id, audamrwb_dsp_event, audio)) {
+		MM_ERR("audpp_enable() failed\n");
+		msm_adsp_disable(audio->audplay);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+	audio->enabled = 1;
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audamrwb_disable(struct audio *audio)
+{
+	int rc = 0;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+		auddec_dsp_config(audio, 0);
+		rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+		else if (audio->dec_state != MSM_AUD_DECODER_STATE_CLOSE)
+			rc = -EFAULT;
+		else
+			rc = 0;
+		audio->stopped = 1;
+		wake_up(&audio->write_wait);
+		wake_up(&audio->read_wait);
+		msm_adsp_disable(audio->audplay);
+		audpp_disable(audio->dec_id, audio);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_disable(&audio->audmgr);
+		audio->out_needed = 0;
+		rmt_put_resource(audio);
+		audio->rmt_resource_released = 1;
+	}
+	return rc;
+}
+
+/* ------------------- dsp --------------------- */
+static void audamrwb_update_pcm_buf_entry(struct audio *audio,
+		uint32_t *payload)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	if (audio->rflush)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < payload[1]; index++) {
+		if (audio->in[audio->fill_next].addr ==
+		    payload[2 + index * 2]) {
+			MM_DBG("in[%d] ready\n", audio->fill_next);
+			audio->in[audio->fill_next].used =
+			    payload[3 + index * 2];
+			if ((++audio->fill_next) == audio->pcm_buf_count)
+				audio->fill_next = 0;
+
+		} else {
+			MM_ERR("expected=%x ret=%x\n",
+					audio->in[audio->fill_next].addr,
+					payload[1 + index * 2]);
+			break;
+		}
+	}
+	if (audio->in[audio->fill_next].used == 0) {
+		audamrwb_buffer_refresh(audio);
+	} else {
+		MM_DBG("read cannot keep up\n");
+		audio->buf_refresh = 1;
+	}
+	wake_up(&audio->read_wait);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static void audplay_dsp_event(void *data, unsigned id, size_t len,
+			      void (*getevent) (void *ptr, size_t len))
+{
+	struct audio *audio = data;
+	uint32_t msg[28];
+	getevent(msg, sizeof(msg));
+
+	MM_DBG("msg_id=%x\n", id);
+
+	switch (id) {
+	case AUDPLAY_MSG_DEC_NEEDS_DATA:
+		audamrwb_send_data(audio, 1);
+		break;
+
+	case AUDPLAY_MSG_BUFFER_UPDATE:
+		audamrwb_update_pcm_buf_entry(audio, msg);
+		break;
+
+	default:
+		MM_ERR("unexpected message from decoder\n");
+	}
+}
+
+static void audamrwb_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned status = msg[1];
+
+			switch (status) {
+			case AUDPP_DEC_STATUS_SLEEP: {
+				uint16_t reason = msg[2];
+				MM_DBG("decoder status:sleep reason=0x%04x\n",
+					reason);
+				if ((reason == AUDPP_MSG_REASON_MEM)
+					|| (reason ==
+					AUDPP_MSG_REASON_NODECODER)) {
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_FAILURE;
+					wake_up(&audio->wait);
+				} else if (reason == AUDPP_MSG_REASON_NONE) {
+					/* decoder is in disable state */
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_CLOSE;
+					wake_up(&audio->wait);
+				}
+				break;
+			}
+			case AUDPP_DEC_STATUS_INIT:
+				MM_DBG("decoder status: init\n");
+				if (audio->pcm_feedback)
+					audpp_cmd_cfg_routing_mode(audio);
+				else
+					audpp_cmd_cfg_adec_params(audio);
+				break;
+
+			case AUDPP_DEC_STATUS_CFG:
+				MM_DBG("decoder status: cfg\n");
+				break;
+			case AUDPP_DEC_STATUS_PLAY:
+				MM_DBG("decoder status: play\n");
+				if (audio->pcm_feedback) {
+					audamrwb_config_hostpcm(audio);
+					audamrwb_buffer_refresh(audio);
+				}
+				audio->dec_state =
+					MSM_AUD_DECODER_STATE_SUCCESS;
+				wake_up(&audio->wait);
+				break;
+			default:
+				MM_DBG("unknown decoder status\n");
+				break;
+			}
+			break;
+		}
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			MM_DBG("CFG_MSG ENABLE\n");
+			auddec_dsp_config(audio, 1);
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+			audpp_dsp_set_eq(audio->dec_id,	audio->eq_enable,
+								&audio->eq);
+			audpp_avsync(audio->dec_id, 22050);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			MM_DBG("CFG_MSG DISABLE\n");
+			audpp_avsync(audio->dec_id, 0);
+			audio->running = 0;
+		} else {
+			MM_DBG("CFG_MSG %d?\n", msg[0]);
+		}
+		break;
+	case AUDPP_MSG_ROUTING_ACK:
+		MM_DBG("ROUTING_ACK mode=%d\n", msg[1]);
+		audpp_cmd_cfg_adec_params(audio);
+		break;
+	case AUDPP_MSG_FLUSH_ACK:
+		MM_DBG("FLUSH_ACK\n");
+		audio->wflush = 0;
+		audio->rflush = 0;
+		wake_up(&audio->write_wait);
+		if (audio->pcm_feedback)
+			audamrwb_buffer_refresh(audio);
+		break;
+	case AUDPP_MSG_PCMDMAMISSED:
+		MM_DBG("PCMDMAMISSED\n");
+		audio->teos = 1;
+		wake_up(&audio->write_wait);
+		break;
+	default:
+		MM_DBG("UNKNOWN (%d)\n", id);
+	}
+
+}
+
+struct msm_adsp_ops audplay_adsp_ops_amrwb = {
+	.event = audplay_dsp_event,
+};
+
+#define audplay_send_queue0(audio, cmd, len) \
+	msm_adsp_write(audio->audplay, audio->queue_id, \
+			cmd, len)
+
+static int auddec_dsp_config(struct audio *audio, int enable)
+{
+	u16 cfg_dec_cmd[AUDPP_CMD_CFG_DEC_TYPE_LEN / sizeof(unsigned short)];
+
+	memset(cfg_dec_cmd, 0, sizeof(cfg_dec_cmd));
+	cfg_dec_cmd[0] = AUDPP_CMD_CFG_DEC_TYPE;
+	if (enable)
+		cfg_dec_cmd[1 + audio->dec_id] = AUDPP_CMD_UPDATDE_CFG_DEC |
+			AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_AMRWB;
+	else
+		cfg_dec_cmd[1 + audio->dec_id] = AUDPP_CMD_UPDATDE_CFG_DEC |
+			AUDPP_CMD_DIS_DEC_V;
+
+	return audpp_send_queue1(&cfg_dec_cmd, sizeof(cfg_dec_cmd));
+}
+
+static void audpp_cmd_cfg_adec_params(struct audio *audio)
+{
+	struct audpp_cmd_cfg_adec_params_amrwb cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_AMRWB_LEN;
+	cmd.common.dec_id = audio->dec_id;
+	cmd.common.input_sampling_frequency = audio->out_sample_rate;
+	cmd.stereo_cfg = audio->out_channel_mode;
+	audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static void audpp_cmd_cfg_routing_mode(struct audio *audio)
+{
+	struct audpp_cmd_routing_mode cmd;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_ROUTING_MODE;
+	cmd.object_number = audio->dec_id;
+	if (audio->pcm_feedback)
+		cmd.routing_mode = ROUTING_MODE_FTRT;
+	else
+		cmd.routing_mode = ROUTING_MODE_RT;
+
+	audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static int audplay_dsp_send_data_avail(struct audio *audio,
+				       unsigned idx, unsigned len)
+{
+	struct audplay_cmd_bitstream_data_avail_nt2 cmd;
+
+	cmd.cmd_id = AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_NT2;
+	if (audio->mfield)
+		cmd.decoder_id = AUDAMRWB_METAFIELD_MASK |
+			(audio->out[idx].mfield_sz >> 1);
+	else
+		cmd.decoder_id = audio->dec_id;
+	cmd.buf_ptr = audio->out[idx].addr;
+	cmd.buf_size = len / 2;
+	cmd.partition_number = 0;
+	return audplay_send_queue0(audio, &cmd, sizeof(cmd));
+}
+
+static void audamrwb_buffer_refresh(struct audio *audio)
+{
+	struct audplay_cmd_buffer_refresh refresh_cmd;
+
+	refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH;
+	refresh_cmd.num_buffers = 1;
+	refresh_cmd.buf0_address = audio->in[audio->fill_next].addr;
+	refresh_cmd.buf0_length = audio->in[audio->fill_next].size;
+	refresh_cmd.buf_read_count = 0;
+	MM_DBG("buf0_addr=%x buf0_len=%d\n", refresh_cmd.buf0_address,
+			refresh_cmd.buf0_length);
+	(void)audplay_send_queue0(audio, &refresh_cmd, sizeof(refresh_cmd));
+}
+
+static void audamrwb_config_hostpcm(struct audio *audio)
+{
+	struct audplay_cmd_hpcm_buf_cfg cfg_cmd;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	cfg_cmd.cmd_id = AUDPLAY_CMD_HPCM_BUF_CFG;
+	cfg_cmd.max_buffers = audio->pcm_buf_count;
+	cfg_cmd.byte_swap = 0;
+	cfg_cmd.hostpcm_config = (0x8000) | (0x4000);
+	cfg_cmd.feedback_frequency = 1;
+	cfg_cmd.partition_number = 0;
+	(void)audplay_send_queue0(audio, &cfg_cmd, sizeof(cfg_cmd));
+
+}
+
+static void audamrwb_send_data(struct audio *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (needed && !audio->wflush) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+			MM_DBG("frame %d busy\n", audio->out_tail);
+			audplay_dsp_send_data_avail(audio, audio->out_tail,
+						    frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+ done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+
+static void audamrwb_flush(struct audio *audio)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->out[0].used = 0;
+	audio->out[1].used = 0;
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->reserved = 0;
+	audio->out_needed = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	atomic_set(&audio->out_bytes, 0);
+}
+
+static void audamrwb_flush_pcm_buf(struct audio *audio)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
+		audio->in[index].used = 0;
+
+	audio->buf_refresh = 0;
+	audio->read_next = 0;
+	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static void audamrwb_ioport_reset(struct audio *audio)
+{
+	/* Make sure read/write thread are free from
+	 * sleep and knowing that system is not able
+	 * to process io request at the moment
+	 */
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audamrwb_flush(audio);
+	mutex_unlock(&audio->write_lock);
+	wake_up(&audio->read_wait);
+	mutex_lock(&audio->read_lock);
+	audamrwb_flush_pcm_buf(audio);
+	mutex_unlock(&audio->read_lock);
+}
+
+static int audamrwb_events_pending(struct audio *audio)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	return empty || audio->event_abort;
+}
+
+static void audamrwb_reset_event_queue(struct audio *audio)
+{
+	unsigned long flags;
+	struct audamrwb_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audamrwb_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+				struct audamrwb_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	return;
+}
+
+static long audamrwb_process_event_req(struct audio *audio, void __user *arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audamrwb_event *drv_evt = NULL;
+	int timeout;
+	unsigned long flags;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int) usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(
+			audio->event_wait, audamrwb_events_pending(audio),
+			msecs_to_jiffies(timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(
+			audio->event_wait, audamrwb_events_pending(audio));
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	rc = 0;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audamrwb_event, list);
+		list_del(&drv_evt->list);
+	}
+
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else
+		rc = -1;
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	if (!rc && copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audio_enable_eq(struct audio *audio, int enable)
+{
+	if (audio->eq_enable == enable && !audio->eq_needs_commit)
+		return 0;
+
+	audio->eq_enable = enable;
+
+	if (audio->running) {
+		audpp_dsp_set_eq(audio->dec_id, enable, &audio->eq);
+		audio->eq_needs_commit = 0;
+	}
+	return 0;
+}
+
+static long audamrwb_ioctl(struct file *file, unsigned int cmd,
+		unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = -EINVAL;
+	unsigned long flags = 0;
+	uint16_t enable_mask;
+	int enable;
+	int prev_state;
+
+	MM_DBG("cmd = %d\n", cmd);
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = audpp_avsync_byte_count(audio->dec_id);
+		stats.sample_count = audpp_avsync_sample_count(audio->dec_id);
+		if (copy_to_user((void *)arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	switch (cmd) {
+	case AUDIO_ENABLE_AUDPP:
+		if (copy_from_user(&enable_mask, (void *) arg,
+						sizeof(enable_mask))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		enable = (enable_mask & EQ_ENABLE) ? 1 : 0;
+		audio_enable_eq(audio, enable);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+	case AUDIO_SET_VOLUME:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.volume = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_PAN:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.pan = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_EQ:
+		prev_state = audio->eq_enable;
+		audio->eq_enable = 0;
+		if (copy_from_user(&audio->eq.num_bands, (void *) arg,
+				sizeof(audio->eq) -
+				(AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2))) {
+			rc = -EFAULT;
+			break;
+		}
+		audio->eq_enable = prev_state;
+		audio->eq_needs_commit = 1;
+		rc = 0;
+		break;
+	}
+
+	if (-EINVAL != rc)
+		return rc;
+
+	if (cmd == AUDIO_GET_EVENT) {
+		MM_DBG("AUDIO_GET_EVENT\n");
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audamrwb_process_event_req(audio,
+					(void __user *) arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		return rc;
+	}
+
+	if (cmd == AUDIO_ABORT_GET_EVENT) {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		MM_DBG("AUDIO_START\n");
+		rc = audamrwb_enable(audio);
+		if (!rc) {
+			rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+			MM_INFO("dec_state %d rc = %d\n", audio->dec_state, rc);
+
+			if (audio->dec_state != MSM_AUD_DECODER_STATE_SUCCESS)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		break;
+	case AUDIO_STOP:
+		MM_DBG("AUDIO_STOP\n");
+		rc = audamrwb_disable(audio);
+		audamrwb_ioport_reset(audio);
+		audio->stopped = 0;
+		break;
+	case AUDIO_FLUSH:
+		MM_DBG(" AUDIO_FLUSH\n");
+		audio->rflush = 1;
+		audio->wflush = 1;
+		audamrwb_ioport_reset(audio);
+		if (audio->running) {
+			audpp_flush(audio->dec_id);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		break;
+	case AUDIO_SET_CONFIG:{
+			struct msm_audio_config config;
+			if (copy_from_user
+			    (&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+			if (config.channel_count == 1)
+				config.channel_count =
+					AUDPP_CMD_PCM_INTF_MONO_V;
+			else if (config.channel_count == 2)
+				config.channel_count =
+					AUDPP_CMD_PCM_INTF_STEREO_V;
+			else
+				rc = -EINVAL;
+			audio->out_channel_mode = config.channel_count;
+			audio->out_sample_rate = config.sample_rate;
+			audio->mfield = config.meta_field;
+			rc = 0;
+			break;
+		}
+	case AUDIO_GET_CONFIG:{
+			struct msm_audio_config config;
+			config.buffer_size = BUFSZ;
+			config.buffer_count = 2;
+			config.sample_rate = audio->out_sample_rate;
+			if (audio->out_channel_mode ==
+					AUDPP_CMD_PCM_INTF_MONO_V)
+				config.channel_count = 1;
+			else
+				config.channel_count = 2;
+			config.meta_field = 0;
+			config.unused[0] = 0;
+			config.unused[1] = 0;
+			config.unused[2] = 0;
+			if (copy_to_user((void *)arg, &config,
+					 sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+
+			break;
+		}
+	case AUDIO_GET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			config.pcm_feedback = 0;
+			config.buffer_count = PCM_BUF_MAX_COUNT;
+			config.buffer_size = PCM_BUFSZ_MIN;
+			if (copy_to_user((void *)arg, &config,
+					 sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_SET_PCM_CONFIG:{
+		struct msm_audio_pcm_config config;
+		if (copy_from_user
+		    (&config, (void *)arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if ((config.buffer_count > PCM_BUF_MAX_COUNT) ||
+		    (config.buffer_count == 1))
+			config.buffer_count = PCM_BUF_MAX_COUNT;
+
+		if (config.buffer_size < PCM_BUFSZ_MIN)
+			config.buffer_size = PCM_BUFSZ_MIN;
+
+			/* Check if pcm feedback is required */
+		if ((config.pcm_feedback) && (!audio->read_data)) {
+			MM_DBG("allocate PCM buf %d\n", config.buffer_count *
+					config.buffer_size);
+			audio->read_phys = allocate_contiguous_ebi_nomap(
+						config.buffer_size *
+						config.buffer_count,
+						SZ_4K);
+			if (!audio->read_phys) {
+					rc = -ENOMEM;
+					break;
+			}
+			audio->map_v_read = ioremap(
+						audio->read_phys,
+						config.buffer_size *
+						config.buffer_count);
+			if (IS_ERR(audio->map_v_read)) {
+				MM_ERR("failed to map mem for read buf\n");
+				rc = -ENOMEM;
+				free_contiguous_memory_by_paddr(
+							audio->read_phys);
+			} else {
+				uint8_t index;
+				uint32_t offset = 0;
+				audio->read_data = audio->map_v_read;
+				audio->pcm_feedback = 1;
+				audio->buf_refresh = 0;
+				audio->pcm_buf_count =
+					config.buffer_count;
+				audio->read_next = 0;
+				audio->fill_next = 0;
+
+				for (index = 0;
+				index < config.buffer_count; index++) {
+					audio->in[index].data =
+						audio->read_data + offset;
+					audio->in[index].addr =
+					    audio->read_phys + offset;
+					audio->in[index].size =
+					    config.buffer_size;
+					audio->in[index].used = 0;
+					offset += config.buffer_size;
+				}
+				MM_DBG("read buf: phy addr 0x%08x \
+						kernel addr 0x%08x\n",
+						audio->read_phys,
+						(int)audio->read_data);
+				rc = 0;
+			}
+		} else {
+			rc = 0;
+		}
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+/* Only useful in tunnel-mode */
+static int audamrwb_fsync(struct file *file, loff_t a, loff_t b, int datasync)
+{
+	struct audio *audio = file->private_data;
+	struct buffer *frame;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	if (!audio->running || audio->pcm_feedback) {
+		rc = -EINVAL;
+		goto done_nolock;
+	}
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(!audio->out[0].used &&
+		!audio->out[1].used &&
+		audio->out_needed) || audio->wflush);
+
+	if (rc < 0)
+		goto done;
+	else if (audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (audio->reserved) {
+		MM_DBG("send reserved byte\n");
+		frame = audio->out + audio->out_tail;
+		((char *) frame->data)[0] = audio->rsv_byte;
+		((char *) frame->data)[1] = 0;
+		frame->used = 2;
+		audamrwb_send_data(audio, 0);
+
+		rc = wait_event_interruptible(audio->write_wait,
+			(!audio->out[0].used &&
+			!audio->out[1].used &&
+			audio->out_needed) || audio->wflush);
+
+		if (rc < 0)
+			goto done;
+		else if (audio->wflush) {
+			rc = -EBUSY;
+			goto done;
+		}
+	}
+
+	/* pcm dmamiss message is sent continously
+	 * when decoder is starved so no race
+	 * condition concern
+	 */
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		audio->teos || audio->wflush);
+
+	if (audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+done_nolock:
+	return rc;
+}
+
+static ssize_t audamrwb_read(struct file *file, char __user *buf, size_t count,
+			  loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	int rc = 0;
+
+	if (!audio->pcm_feedback)
+		return 0; /* PCM feedback is not enabled. Nothing to read */
+
+	mutex_lock(&audio->read_lock);
+	MM_DBG("count %d\n", count);
+	while (count > 0) {
+		rc = wait_event_interruptible(audio->read_wait,
+			(audio->in[audio->read_next].used > 0) ||
+			(audio->stopped) || (audio->rflush));
+
+		if (rc < 0)
+			break;
+
+		if (audio->stopped || audio->rflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (count < audio->in[audio->read_next].used) {
+			/* Read must happen in frame boundary. Since driver does
+			 * not know frame size, read count must be greater or
+			 * equal to size of PCM samples
+			 */
+			MM_DBG("read stop - partial frame\n");
+			break;
+		} else {
+			MM_DBG("read from in[%d]\n",
+				audio->read_next);
+
+			if (copy_to_user
+			    (buf, audio->in[audio->read_next].data,
+			     audio->in[audio->read_next].used)) {
+				MM_ERR("invalid addr %x \n", (unsigned int)buf);
+				rc = -EFAULT;
+				break;
+			}
+			count -= audio->in[audio->read_next].used;
+			buf += audio->in[audio->read_next].used;
+			audio->in[audio->read_next].used = 0;
+			if ((++audio->read_next) == audio->pcm_buf_count)
+				audio->read_next = 0;
+			break;
+		}
+	}
+
+	/* don't feed output buffer to HW decoder during flushing
+	 * buffer refresh command will be sent once flush completes
+	 * send buf refresh command here can confuse HW decoder
+	 */
+	if (audio->buf_refresh && !audio->rflush) {
+		audio->buf_refresh = 0;
+		MM_ERR("kick start pcm feedback again\n");
+		audamrwb_buffer_refresh(audio);
+	}
+
+	mutex_unlock(&audio->read_lock);
+
+	if (buf > start)
+		rc = buf - start;
+
+	MM_DBG("read %d bytes\n", rc);
+	return rc;
+}
+
+static int audamrwb_process_eos(struct audio *audio,
+		const char __user *buf_start, unsigned short mfield_size)
+{
+	struct buffer *frame;
+	char *buf_ptr;
+	int rc = 0;
+
+	MM_DBG("signal input EOS reserved=%d\n", audio->reserved);
+	if (audio->reserved) {
+		MM_DBG("Pass reserve byte\n");
+		frame = audio->out + audio->out_head;
+		buf_ptr = frame->data;
+		rc = wait_event_interruptible(audio->write_wait,
+					(frame->used == 0)
+					|| (audio->stopped)
+					|| (audio->wflush));
+	if (rc < 0)
+		goto done;
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+	buf_ptr[0] = audio->rsv_byte;
+	buf_ptr[1] = 0;
+	audio->out_head ^= 1;
+	frame->mfield_sz = 0;
+	audio->reserved = 0;
+	frame->used = 2;
+	audamrwb_send_data(audio, 0);
+	}
+
+	MM_DBG("Now signal input EOS after reserved bytes %d %d %d\n",
+		audio->out[0].used, audio->out[1].used, audio->out_needed);
+
+	frame = audio->out + audio->out_head;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->out_needed &&
+		audio->out[0].used == 0 &&
+		audio->out[1].used == 0)
+		|| (audio->stopped)
+		|| (audio->wflush));
+
+	if (rc < 0)
+		goto done;
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (copy_from_user(frame->data, buf_start, mfield_size)) {
+		rc = -EFAULT;
+		goto done;
+	}
+
+	frame->mfield_sz = mfield_size;
+	audio->out_head ^= 1;
+	frame->used = mfield_size;
+	audamrwb_send_data(audio, 0);
+
+done:
+	return rc;
+}
+
+static ssize_t audamrwb_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	char *cpy_ptr;
+	int rc = 0, eos_condition = AUDAMRWB_EOS_NONE;
+	unsigned short mfield_size = 0;
+	unsigned dsize;
+
+	MM_DBG("cnt=%d\n", count);
+
+	mutex_lock(&audio->write_lock);
+	while (count > 0) {
+		frame = audio->out + audio->out_head;
+		cpy_ptr = frame->data;
+		dsize = 0;
+		rc = wait_event_interruptible(audio->write_wait,
+					      (frame->used == 0)
+						|| (audio->stopped)
+						|| (audio->wflush));
+
+		MM_DBG("buffer available\n");
+		if (rc < 0)
+			break;
+		if (audio->stopped || audio->wflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (audio->mfield) {
+			if (buf == start) {
+				/* Processing beginning of user buffer */
+				if (__get_user(mfield_size,
+					(unsigned short __user *) buf)) {
+					rc = -EFAULT;
+					break;
+				} else 	if (mfield_size > count) {
+					rc = -EINVAL;
+					break;
+				}
+				MM_DBG("mf offset_val %x\n", mfield_size);
+				if (copy_from_user(cpy_ptr, buf, mfield_size)) {
+					rc = -EFAULT;
+					break;
+				}
+				/* Check if EOS flag is set and buffer
+				 * contains just meta field
+				 */
+				if (cpy_ptr[AUDAMRWB_EOS_FLG_OFFSET] &
+						AUDAMRWB_EOS_FLG_MASK) {
+					MM_DBG("eos set\n");
+					eos_condition = AUDAMRWB_EOS_SET;
+					if (mfield_size == count) {
+						buf += mfield_size;
+						break;
+					} else
+					cpy_ptr[AUDAMRWB_EOS_FLG_OFFSET] &=
+							~AUDAMRWB_EOS_FLG_MASK;
+				}
+				cpy_ptr += mfield_size;
+				count -= mfield_size;
+				dsize += mfield_size;
+				buf += mfield_size;
+			} else {
+				mfield_size = 0;
+				MM_DBG("continuous buffer\n");
+			}
+			frame->mfield_sz = mfield_size;
+		}
+
+		if (audio->reserved) {
+			MM_DBG("append reserved byte %x\n", audio->rsv_byte);
+			*cpy_ptr = audio->rsv_byte;
+			xfer = (count > ((frame->size - mfield_size) - 1)) ?
+				((frame->size - mfield_size) - 1) : count;
+			cpy_ptr++;
+			dsize += 1;
+			audio->reserved = 0;
+		} else
+			xfer = (count > (frame->size - mfield_size)) ?
+				(frame->size - mfield_size) : count;
+
+		if (copy_from_user(cpy_ptr, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+
+		dsize += xfer;
+		if (dsize & 1) {
+			audio->rsv_byte = ((char *) frame->data)[dsize - 1];
+			MM_DBG("odd length buf reserve last byte %x\n",
+					audio->rsv_byte);
+			audio->reserved = 1;
+			dsize--;
+		}
+		count -= xfer;
+		buf += xfer;
+
+		if (dsize > 0) {
+			audio->out_head ^= 1;
+			frame->used = dsize;
+			audamrwb_send_data(audio, 0);
+		}
+	}
+	MM_DBG("eos_condition %x buf[0x%x] start[0x%x]\n", eos_condition,
+			(int) buf, (int) start);
+	if (eos_condition == AUDAMRWB_EOS_SET)
+		rc = audamrwb_process_eos(audio, start, mfield_size);
+	mutex_unlock(&audio->write_lock);
+	if (!rc) {
+		if (buf > start)
+			return buf - start;
+	}
+	return rc;
+}
+
+static int audamrwb_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	MM_INFO("audio instance 0x%08x freeing\n", (int)audio);
+	mutex_lock(&audio->lock);
+	audamrwb_disable(audio);
+	if (audio->rmt_resource_released == 0)
+		rmt_put_resource(audio);
+	audamrwb_flush(audio);
+	audamrwb_flush_pcm_buf(audio);
+	msm_adsp_put(audio->audplay);
+	audpp_adec_free(audio->dec_id);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&audio->suspend_ctl.node);
+#endif
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audamrwb_reset_event_queue(audio);
+	iounmap(audio->map_v_write);
+	free_contiguous_memory_by_paddr(audio->phys);
+	if (audio->read_data) {
+		iounmap(audio->map_v_read);
+		free_contiguous_memory_by_paddr(audio->read_phys);
+	}
+	mutex_unlock(&audio->lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio);
+	return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audamrwb_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload)
+{
+	struct audamrwb_event *e_node = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+				struct audamrwb_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audamrwb_event), GFP_ATOMIC);
+		if (!e_node) {
+			MM_ERR("No mem to post event %d\n", type);
+			spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	wake_up(&audio->event_wait);
+}
+
+static void audamrwb_suspend(struct early_suspend *h)
+{
+	struct audamrwb_suspend_ctl *ctl =
+		container_of(h, struct audamrwb_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audamrwb_post_event(ctl->audio, AUDIO_EVENT_SUSPEND, payload);
+}
+
+static void audamrwb_resume(struct early_suspend *h)
+{
+	struct audamrwb_suspend_ctl *ctl =
+		container_of(h, struct audamrwb_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audamrwb_post_event(ctl->audio, AUDIO_EVENT_RESUME, payload);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audamrwb_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audamrwb_debug_read(struct file *file, char __user *buf,
+					size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 1024;
+	static char buffer[1024];
+	int n = 0, i;
+	struct audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"enabled %d\n", audio->enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_feedback %d\n", audio->pcm_feedback);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_buf_sz %d\n", audio->out[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_buf_count %d \n", audio->pcm_buf_count);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_buf_sz %d \n", audio->in[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"volume %x \n", audio->vol_pan.volume);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"sample rate %d \n", audio->out_sample_rate);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"channel mode %d \n", audio->out_channel_mode);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"rflush %d\n", audio->rflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"running %d \n", audio->running);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"dec state %d \n", audio->dec_state);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_needed %d \n", audio->out_needed);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_head %d \n", audio->out_head);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_tail %d \n", audio->out_tail);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out[0].used %d \n", audio->out[0].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out[1].used %d \n", audio->out[1].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"buffer_refresh %d \n", audio->buf_refresh);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"read_next %d \n", audio->read_next);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"fill_next %d \n", audio->fill_next);
+	for (i = 0; i < audio->pcm_buf_count; i++)
+		n += scnprintf(buffer + n, debug_bufmax - n,
+				"in[%d].used %d \n", i, audio->in[i].used);
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audamrwb_debug_fops = {
+	.read = audamrwb_debug_read,
+	.open = audamrwb_debug_open,
+};
+#endif
+
+static int audamrwb_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = NULL;
+	int rc, dec_attrb, decid, i;
+	struct audamrwb_event *e_node = NULL;
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_amrwb_" + 5];
+#endif
+
+	/* Allocate Mem for audio instance */
+	audio = kzalloc(sizeof(struct audio), GFP_KERNEL);
+	if (!audio) {
+		MM_ERR("No memory to allocate audio instance\n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	MM_INFO("audio instance 0x%08x created\n", (int)audio);
+
+	/* Allocate the decoder */
+	dec_attrb = AUDDEC_DEC_AMRWB;
+	if (file->f_mode & FMODE_READ)
+		dec_attrb |= MSM_AUD_MODE_NONTUNNEL;
+	else
+		dec_attrb |= MSM_AUD_MODE_TUNNEL;
+
+	decid = audpp_adec_alloc(dec_attrb, &audio->module_name,
+			&audio->queue_id);
+
+	if (decid < 0) {
+		MM_ERR("No free decoder available, freeing instance 0x%08x\n",
+				(int)audio);
+		rc = -ENODEV;
+		kfree(audio);
+		goto done;
+	}
+
+	audio->dec_id = decid & MSM_AUD_DECODER_MASK;
+
+	audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
+	if (!audio->phys) {
+		MM_ERR("could not allocate write buffers, freeing instance \
+				0x%08x\n", (int)audio);
+		rc = -ENOMEM;
+		audpp_adec_free(audio->dec_id);
+		kfree(audio);
+		goto done;
+	} else {
+		audio->map_v_write = ioremap(audio->phys, DMASZ);
+
+		if (IS_ERR(audio->map_v_write)) {
+			MM_ERR("could not map write buffers, freeing \
+					instance 0x%08x\n", (int)audio);
+			rc = -ENOMEM;
+			free_contiguous_memory_by_paddr(audio->phys);
+			audpp_adec_free(audio->dec_id);
+			kfree(audio);
+			goto done;
+		}
+		audio->data = audio->map_v_write;
+		MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+				audio->phys, (int)audio->data);
+	}
+
+	if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
+		rc = audmgr_open(&audio->audmgr);
+		if (rc) {
+			MM_ERR("audmgr open failed, freeing instance \
+					0x%08x\n", (int)audio);
+			goto err;
+		}
+	}
+
+	rc = msm_adsp_get(audio->module_name, &audio->audplay,
+		&audplay_adsp_ops_amrwb, audio);
+	if (rc) {
+		MM_ERR("failed to get %s module, freeing instance 0x%08x\n",
+				audio->module_name, (int)audio);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_close(&audio->audmgr);
+		goto err;
+	}
+
+	rc = rmt_get_resource(audio);
+	if (rc) {
+		MM_ERR("ADSP resources are not available for AMRWB session \
+			 0x%08x on decoder: %d\n", (int)audio, audio->dec_id);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_close(&audio->audmgr);
+		msm_adsp_put(audio->audplay);
+		goto err;
+	}
+
+	mutex_init(&audio->lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->get_event_lock);
+	spin_lock_init(&audio->dsp_lock);
+	spin_lock_init(&audio->event_queue_lock);
+	INIT_LIST_HEAD(&audio->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+	init_waitqueue_head(&audio->write_wait);
+	init_waitqueue_head(&audio->read_wait);
+	init_waitqueue_head(&audio->wait);
+	init_waitqueue_head(&audio->event_wait);
+
+	audio->out[0].data = audio->data + 0;
+	audio->out[0].addr = audio->phys + 0;
+	audio->out[0].size = BUFSZ;
+
+	audio->out[1].data = audio->data + BUFSZ;
+	audio->out[1].addr = audio->phys + BUFSZ;
+	audio->out[1].size = BUFSZ;
+
+	audio->vol_pan.volume = 0x2000;
+	audio->vol_pan.pan = 0x0;
+	audio->eq_enable = 0;
+	audio->out_sample_rate = 44100;
+	audio->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V;
+
+	audamrwb_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+	audio->event_abort = 0;
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_amrwb_%04x", audio->dec_id);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+			NULL, (void *) audio, &audamrwb_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		MM_DBG("debugfs_create_file failed\n");
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	audio->suspend_ctl.node.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+	audio->suspend_ctl.node.resume = audamrwb_resume;
+	audio->suspend_ctl.node.suspend = audamrwb_suspend;
+	audio->suspend_ctl.audio = audio;
+	register_early_suspend(&audio->suspend_ctl.node);
+#endif
+	for (i = 0; i < AUDAMRWB_EVENT_NUM; i++) {
+		e_node = kmalloc(sizeof(struct audamrwb_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			MM_ERR("event pkt alloc failed\n");
+			break;
+		}
+	}
+done:
+	return rc;
+err:
+	iounmap(audio->map_v_write);
+	free_contiguous_memory_by_paddr(audio->phys);
+	audpp_adec_free(audio->dec_id);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_amrwb_fops = {
+	.owner = THIS_MODULE,
+	.open = audamrwb_open,
+	.release = audamrwb_release,
+	.read = audamrwb_read,
+	.write = audamrwb_write,
+	.unlocked_ioctl = audamrwb_ioctl,
+	.fsync = audamrwb_fsync,
+};
+
+struct miscdevice audio_amrwb_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_amrwb",
+	.fops = &audio_amrwb_fops,
+};
+
+static int __init audamrwb_init(void)
+{
+	return misc_register(&audio_amrwb_misc);
+}
+
+static void __exit audamrwb_exit(void)
+{
+	misc_deregister(&audio_amrwb_misc);
+}
+
+module_init(audamrwb_init);
+module_exit(audamrwb_exit);
+
+MODULE_DESCRIPTION("MSM AMR-WB driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5/audio_evrc.c b/arch/arm/mach-msm/qdsp5/audio_evrc.c
new file mode 100644
index 0000000..489929b
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_evrc.c
@@ -0,0 +1,1623 @@
+/* arch/arm/mach-msm/audio_evrc.c
+ *
+ * Copyright (c) 2008-2009, 2011-2012 Code Aurora Forum. All rights reserved.
+ *
+ * This code also borrows from audio_aac.c, which is
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ *
+ * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/earlysuspend.h>
+#include <linux/android_pmem.h>
+#include <linux/slab.h>
+#include <linux/msm_audio.h>
+#include <linux/memory_alloc.h>
+
+#include <mach/msm_adsp.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audplaycmdi.h>
+#include <mach/qdsp5/qdsp5audplaymsg.h>
+#include <mach/qdsp5/qdsp5rmtcmdi.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_memtypes.h>
+
+#include "audmgr.h"
+
+/* Hold 30 packets of 24 bytes each and 14 bytes of meta in */
+#define BUFSZ 			734
+#define DMASZ 			(BUFSZ * 2)
+
+#define AUDDEC_DEC_EVRC 	12
+
+#define PCM_BUFSZ_MIN 		1624	/* 100ms worth of data and
+					   and 24 bytes of meta out */
+#define PCM_BUF_MAX_COUNT 	5
+/* DSP only accepts 5 buffers at most
+ * but support 2 buffers currently
+ */
+#define EVRC_DECODED_FRSZ 	320	/* EVRC 20ms 8KHz mono PCM size */
+
+#define ROUTING_MODE_FTRT 	1
+#define ROUTING_MODE_RT 	2
+/* Decoder status received from AUDPPTASK */
+#define  AUDPP_DEC_STATUS_SLEEP	0
+#define	 AUDPP_DEC_STATUS_INIT  1
+#define  AUDPP_DEC_STATUS_CFG   2
+#define  AUDPP_DEC_STATUS_PLAY  3
+
+#define AUDEVRC_METAFIELD_MASK 0xFFFF0000
+#define AUDEVRC_EOS_FLG_OFFSET 0x0A /* Offset from beginning of buffer */
+#define AUDEVRC_EOS_FLG_MASK 0x01
+#define AUDEVRC_EOS_NONE 0x0 /* No EOS detected */
+#define AUDEVRC_EOS_SET 0x1 /* EOS set in meta field */
+
+#define AUDEVRC_EVENT_NUM 10 /* Default number of pre-allocated event packets */
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+	unsigned short mfield_sz; /*only useful for data has meta field */
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct audevrc_suspend_ctl {
+	struct early_suspend node;
+	struct audio *audio;
+};
+#endif
+
+struct audevrc_event{
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+
+struct audio {
+	struct buffer out[2];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed;	/* number of buffers the dsp is waiting for */
+
+	atomic_t out_bytes;
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	/* Host PCM section */
+	struct buffer in[PCM_BUF_MAX_COUNT];
+	struct mutex read_lock;
+	wait_queue_head_t read_wait;	/* Wait queue for read */
+	char *read_data;	/* pointer to reader buffer */
+	int32_t read_phys;	/* physical address of reader buffer */
+	uint8_t read_next;	/* index to input buffers to be read next */
+	uint8_t fill_next;	/* index to buffer that DSP should be filling */
+	uint8_t pcm_buf_count;	/* number of pcm buffer allocated */
+	/* ---- End of Host PCM section */
+
+	struct msm_adsp_module *audplay;
+	struct audmgr audmgr;
+
+	/* data allocated for various buffers */
+	char *data;
+	int32_t phys;  /* physical address of write buffer */
+	void *map_v_read;
+	void *map_v_write;
+
+	int mfield; /* meta field embedded in data */
+	int rflush; /* Read  flush */
+	int wflush; /* Write flush */
+	uint8_t opened:1;
+	uint8_t enabled:1;
+	uint8_t running:1;
+	uint8_t stopped:1;	/* set when stopped, cleared on flush */
+	uint8_t pcm_feedback:1;
+	uint8_t buf_refresh:1;
+	int teos; /* valid only if tunnel mode & no data left for decoder */
+	enum msm_aud_decoder_state dec_state;	/* Represents decoder state */
+	int rmt_resource_released;
+
+	const char *module_name;
+	unsigned queue_id;
+	uint16_t dec_id;
+	uint32_t read_ptr_offset;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct audevrc_suspend_ctl suspend_ctl;
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+
+	wait_queue_head_t wait;
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	wait_queue_head_t event_wait;
+	spinlock_t event_queue_lock;
+	struct mutex get_event_lock;
+	int event_abort;
+
+	int eq_enable;
+	int eq_needs_commit;
+	audpp_cmd_cfg_object_params_eqalizer eq;
+	audpp_cmd_cfg_object_params_volume vol_pan;
+};
+
+static int auddec_dsp_config(struct audio *audio, int enable);
+static void audpp_cmd_cfg_adec_params(struct audio *audio);
+static void audpp_cmd_cfg_routing_mode(struct audio *audio);
+static void audevrc_send_data(struct audio *audio, unsigned needed);
+static void audevrc_dsp_event(void *private, unsigned id, uint16_t *msg);
+static void audevrc_config_hostpcm(struct audio *audio);
+static void audevrc_buffer_refresh(struct audio *audio);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audevrc_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload);
+#endif
+
+static int rmt_put_resource(struct audio *audio)
+{
+	struct aud_codec_config_cmd cmd;
+	unsigned short client_idx;
+
+	cmd.cmd_id = RM_CMD_AUD_CODEC_CFG;
+	cmd.client_id = RM_AUD_CLIENT_ID;
+	cmd.task_id = audio->dec_id;
+	cmd.enable = RMT_DISABLE;
+	cmd.dec_type = AUDDEC_DEC_EVRC;
+	client_idx = ((cmd.client_id << 8) | cmd.task_id);
+
+	return put_adsp_resource(client_idx, &cmd, sizeof(cmd));
+}
+
+static int rmt_get_resource(struct audio *audio)
+{
+	struct aud_codec_config_cmd cmd;
+	unsigned short client_idx;
+
+	cmd.cmd_id = RM_CMD_AUD_CODEC_CFG;
+	cmd.client_id = RM_AUD_CLIENT_ID;
+	cmd.task_id = audio->dec_id;
+	cmd.enable = RMT_ENABLE;
+	cmd.dec_type = AUDDEC_DEC_EVRC;
+	client_idx = ((cmd.client_id << 8) | cmd.task_id);
+
+	return get_adsp_resource(client_idx, &cmd, sizeof(cmd));
+}
+
+/* must be called with audio->lock held */
+static int audevrc_enable(struct audio *audio)
+{
+	struct audmgr_config cfg;
+	int rc;
+
+	if (audio->enabled)
+		return 0;
+
+	if (audio->rmt_resource_released == 1) {
+		audio->rmt_resource_released = 0;
+		rc = rmt_get_resource(audio);
+		if (rc) {
+			MM_ERR("ADSP resources are not available for EVRC \
+				session 0x%08x on decoder: %d\n Ignoring \
+				error and going ahead with the playback\n",
+				(int)audio, audio->dec_id);
+		}
+	}
+
+	audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
+		cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+		cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;
+		cfg.def_method = RPC_AUD_DEF_METHOD_PLAYBACK;
+		cfg.codec = RPC_AUD_DEF_CODEC_EVRC;
+		cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+		rc = audmgr_enable(&audio->audmgr, &cfg);
+		if (rc < 0)
+			return rc;
+	}
+
+	if (msm_adsp_enable(audio->audplay)) {
+		MM_ERR("msm_adsp_enable(audplay) failed\n");
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+
+	if (audpp_enable(audio->dec_id, audevrc_dsp_event, audio)) {
+		MM_ERR("audpp_enable() failed\n");
+		msm_adsp_disable(audio->audplay);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+	audio->enabled = 1;
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audevrc_disable(struct audio *audio)
+{
+	int rc = 0;
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+		auddec_dsp_config(audio, 0);
+		rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+		else if (audio->dec_state != MSM_AUD_DECODER_STATE_CLOSE)
+			rc = -EFAULT;
+		else
+			rc = 0;
+		audio->stopped = 1;
+		wake_up(&audio->write_wait);
+		wake_up(&audio->read_wait);
+		msm_adsp_disable(audio->audplay);
+		audpp_disable(audio->dec_id, audio);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_disable(&audio->audmgr);
+		audio->out_needed = 0;
+		rmt_put_resource(audio);
+		audio->rmt_resource_released = 1;
+	}
+	return rc;
+}
+
+/* ------------------- dsp --------------------- */
+
+static void audevrc_update_pcm_buf_entry(struct audio *audio,
+					 uint32_t *payload)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	if (audio->rflush)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < payload[1]; index++) {
+		if (audio->in[audio->fill_next].addr
+				== payload[2 + index * 2]) {
+			MM_DBG("in[%d] ready\n", audio->fill_next);
+			audio->in[audio->fill_next].used =
+				payload[3 + index * 2];
+			if ((++audio->fill_next) == audio->pcm_buf_count)
+				audio->fill_next = 0;
+
+		} else {
+			MM_ERR("expected=%x ret=%x\n",
+				audio->in[audio->fill_next].addr,
+				payload[1 + index * 2]);
+			break;
+		}
+	}
+	if (audio->in[audio->fill_next].used == 0) {
+		audevrc_buffer_refresh(audio);
+	} else {
+		MM_DBG("read cannot keep up\n");
+		audio->buf_refresh = 1;
+	}
+	wake_up(&audio->read_wait);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static void audplay_dsp_event(void *data, unsigned id, size_t len,
+			      void (*getevent) (void *ptr, size_t len))
+{
+	struct audio *audio = data;
+	uint32_t msg[28];
+	getevent(msg, sizeof(msg));
+
+	MM_DBG("msg_id=%x\n", id);
+	switch (id) {
+	case AUDPLAY_MSG_DEC_NEEDS_DATA:
+		audevrc_send_data(audio, 1);
+		break;
+	case AUDPLAY_MSG_BUFFER_UPDATE:
+		MM_DBG("\n"); /* Macro prints the file name and function */
+		audevrc_update_pcm_buf_entry(audio, msg);
+		break;
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audplaytask)\n");
+		break;
+	default:
+		MM_ERR("unexpected message from decoder \n");
+	}
+}
+
+static void audevrc_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned status = msg[1];
+
+			switch (status) {
+			case AUDPP_DEC_STATUS_SLEEP: {
+				uint16_t reason = msg[2];
+				MM_DBG("decoder status:sleep reason = \
+						0x%04x\n", reason);
+				if ((reason == AUDPP_MSG_REASON_MEM)
+					|| (reason ==
+					AUDPP_MSG_REASON_NODECODER)) {
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_FAILURE;
+					wake_up(&audio->wait);
+				} else if (reason == AUDPP_MSG_REASON_NONE) {
+					/* decoder is in disable state */
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_CLOSE;
+					wake_up(&audio->wait);
+				}
+				break;
+			}
+			case AUDPP_DEC_STATUS_INIT:
+				MM_DBG("decoder status: init \n");
+				if (audio->pcm_feedback)
+					audpp_cmd_cfg_routing_mode(audio);
+				else
+					audpp_cmd_cfg_adec_params(audio);
+				break;
+
+			case AUDPP_DEC_STATUS_CFG:
+				MM_DBG("decoder status: cfg \n");
+				break;
+			case AUDPP_DEC_STATUS_PLAY:
+				MM_DBG("decoder status: play \n");
+				if (audio->pcm_feedback) {
+					audevrc_config_hostpcm(audio);
+					audevrc_buffer_refresh(audio);
+				}
+				audio->dec_state =
+					MSM_AUD_DECODER_STATE_SUCCESS;
+				wake_up(&audio->wait);
+				break;
+			default:
+				MM_ERR("unknown decoder status \n");
+			}
+			break;
+		}
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			MM_DBG("CFG_MSG ENABLE\n");
+			auddec_dsp_config(audio, 1);
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+			audpp_dsp_set_eq(audio->dec_id,	audio->eq_enable,
+								&audio->eq);
+			audpp_avsync(audio->dec_id, 22050);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			MM_DBG("CFG_MSG DISABLE\n");
+			audpp_avsync(audio->dec_id, 0);
+			audio->running = 0;
+		} else {
+			MM_DBG("CFG_MSG %d?\n", msg[0]);
+		}
+		break;
+	case AUDPP_MSG_ROUTING_ACK:
+		MM_DBG("ROUTING_ACK\n");
+		audpp_cmd_cfg_adec_params(audio);
+		break;
+	case AUDPP_MSG_FLUSH_ACK:
+		MM_DBG("FLUSH_ACK\n");
+		audio->wflush = 0;
+		audio->rflush = 0;
+		wake_up(&audio->write_wait);
+		if (audio->pcm_feedback)
+			audevrc_buffer_refresh(audio);
+		break;
+	case AUDPP_MSG_PCMDMAMISSED:
+		MM_DBG("PCMDMAMISSED\n");
+		audio->teos = 1;
+		wake_up(&audio->write_wait);
+		break;
+	default:
+		MM_ERR("UNKNOWN (%d)\n", id);
+	}
+
+}
+
+struct msm_adsp_ops audplay_adsp_ops_evrc = {
+	.event = audplay_dsp_event,
+};
+
+#define audplay_send_queue0(audio, cmd, len) \
+	msm_adsp_write(audio->audplay, audio->queue_id, \
+			cmd, len)
+
+static int auddec_dsp_config(struct audio *audio, int enable)
+{
+	u16 cfg_dec_cmd[AUDPP_CMD_CFG_DEC_TYPE_LEN / sizeof(unsigned short)];
+
+	memset(cfg_dec_cmd, 0, sizeof(cfg_dec_cmd));
+
+	cfg_dec_cmd[0] = AUDPP_CMD_CFG_DEC_TYPE;
+	if (enable)
+		cfg_dec_cmd[1 + audio->dec_id] = AUDPP_CMD_UPDATDE_CFG_DEC |
+			AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_EVRC;
+	else
+		cfg_dec_cmd[1 + audio->dec_id] = AUDPP_CMD_UPDATDE_CFG_DEC |
+			AUDPP_CMD_DIS_DEC_V;
+
+	return audpp_send_queue1(&cfg_dec_cmd, sizeof(cfg_dec_cmd));
+}
+
+static void audpp_cmd_cfg_adec_params(struct audio *audio)
+{
+	struct audpp_cmd_cfg_adec_params_evrc cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	cmd.common.length = sizeof(cmd);
+	cmd.common.dec_id = audio->dec_id;
+	cmd.common.input_sampling_frequency = 8000;
+	cmd.stereo_cfg = AUDPP_CMD_PCM_INTF_MONO_V;
+
+	audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static void audpp_cmd_cfg_routing_mode(struct audio *audio)
+{
+	struct audpp_cmd_routing_mode cmd;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_ROUTING_MODE;
+	cmd.object_number = audio->dec_id;
+	if (audio->pcm_feedback)
+		cmd.routing_mode = ROUTING_MODE_FTRT;
+	else
+		cmd.routing_mode = ROUTING_MODE_RT;
+
+	audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static int audplay_dsp_send_data_avail(struct audio *audio,
+				       unsigned idx, unsigned len)
+{
+	struct audplay_cmd_bitstream_data_avail_nt2 cmd;
+
+	cmd.cmd_id = AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_NT2;
+	if (audio->mfield)
+		cmd.decoder_id = AUDEVRC_METAFIELD_MASK |
+			(audio->out[idx].mfield_sz >> 1);
+	else
+		cmd.decoder_id = audio->dec_id;
+	cmd.buf_ptr = audio->out[idx].addr;
+	cmd.buf_size = len / 2;
+	cmd.partition_number = 0;
+	/* complete writes to the input buffer */
+	wmb();
+	return audplay_send_queue0(audio, &cmd, sizeof(cmd));
+}
+
+static void audevrc_buffer_refresh(struct audio *audio)
+{
+	struct audplay_cmd_buffer_refresh refresh_cmd;
+
+	refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH;
+	refresh_cmd.num_buffers = 1;
+	refresh_cmd.buf0_address = audio->in[audio->fill_next].addr;
+	refresh_cmd.buf0_length = audio->in[audio->fill_next].size;
+
+	refresh_cmd.buf_read_count = 0;
+	MM_DBG("buf0_addr=%x buf0_len=%d\n", refresh_cmd.buf0_address,
+			refresh_cmd.buf0_length);
+	audplay_send_queue0(audio, &refresh_cmd, sizeof(refresh_cmd));
+}
+
+static void audevrc_config_hostpcm(struct audio *audio)
+{
+	struct audplay_cmd_hpcm_buf_cfg cfg_cmd;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	cfg_cmd.cmd_id = AUDPLAY_CMD_HPCM_BUF_CFG;
+	cfg_cmd.max_buffers = 1;
+	cfg_cmd.byte_swap = 0;
+	cfg_cmd.hostpcm_config = (0x8000) | (0x4000);
+	cfg_cmd.feedback_frequency = 1;
+	cfg_cmd.partition_number = 0;
+	audplay_send_queue0(audio, &cfg_cmd, sizeof(cfg_cmd));
+
+}
+
+static void audevrc_send_data(struct audio *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (needed && !audio->wflush) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			MM_DBG("frame %d free\n", audio->out_tail);
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+			MM_DBG("frame %d busy\n", audio->out_tail);
+			audplay_dsp_send_data_avail(audio, audio->out_tail,
+						    frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+
+static void audevrc_flush(struct audio *audio)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->out[0].used = 0;
+	audio->out[1].used = 0;
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	atomic_set(&audio->out_bytes, 0);
+}
+
+static void audevrc_flush_pcm_buf(struct audio *audio)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
+		audio->in[index].used = 0;
+	audio->buf_refresh = 0;
+	audio->read_next = 0;
+	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static void audevrc_ioport_reset(struct audio *audio)
+{
+	/* Make sure read/write thread are free from
+	 * sleep and knowing that system is not able
+	 * to process io request at the moment
+	 */
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audevrc_flush(audio);
+	mutex_unlock(&audio->write_lock);
+	wake_up(&audio->read_wait);
+	mutex_lock(&audio->read_lock);
+	audevrc_flush_pcm_buf(audio);
+	mutex_unlock(&audio->read_lock);
+}
+
+static int audevrc_events_pending(struct audio *audio)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	return empty || audio->event_abort;
+}
+
+static void audevrc_reset_event_queue(struct audio *audio)
+{
+	unsigned long flags;
+	struct audevrc_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audevrc_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+			struct audevrc_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	return;
+}
+
+
+static long audevrc_process_event_req(struct audio *audio, void __user *arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audevrc_event *drv_evt = NULL;
+	int timeout;
+	unsigned long flags;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int) usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(
+			audio->event_wait, audevrc_events_pending(audio),
+			msecs_to_jiffies(timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(
+			audio->event_wait, audevrc_events_pending(audio));
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	rc = 0;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audevrc_event, list);
+		list_del(&drv_evt->list);
+	}
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else
+		rc = -1;
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	if (!rc && copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audio_enable_eq(struct audio *audio, int enable)
+{
+	if (audio->eq_enable == enable && !audio->eq_needs_commit)
+		return 0;
+
+	audio->eq_enable = enable;
+
+	if (audio->running) {
+		audpp_dsp_set_eq(audio->dec_id, enable, &audio->eq);
+		audio->eq_needs_commit = 0;
+	}
+	return 0;
+}
+
+static long audevrc_ioctl(struct file *file, unsigned int cmd,
+			  unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = -EINVAL;
+	unsigned long flags = 0;
+	uint16_t enable_mask;
+	int enable;
+	int prev_state;
+
+	MM_DBG("cmd = %d\n", cmd);
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = audpp_avsync_byte_count(audio->dec_id);
+		stats.sample_count = audpp_avsync_sample_count(audio->dec_id);
+		if (copy_to_user((void *)arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	switch (cmd) {
+	case AUDIO_ENABLE_AUDPP:
+		if (copy_from_user(&enable_mask, (void *) arg,
+						sizeof(enable_mask))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		enable = (enable_mask & EQ_ENABLE) ? 1 : 0;
+		audio_enable_eq(audio, enable);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+	case AUDIO_SET_VOLUME:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.volume = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_PAN:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.pan = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_EQ:
+		prev_state = audio->eq_enable;
+		audio->eq_enable = 0;
+		if (copy_from_user(&audio->eq.num_bands, (void *) arg,
+				sizeof(audio->eq) -
+				(AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2))) {
+			rc = -EFAULT;
+			break;
+		}
+		audio->eq_enable = prev_state;
+		audio->eq_needs_commit = 1;
+		rc = 0;
+		break;
+	}
+
+	if (-EINVAL != rc)
+		return rc;
+
+	if (cmd == AUDIO_GET_EVENT) {
+		MM_DBG("AUDIO_GET_EVENT\n");
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audevrc_process_event_req(audio,
+					(void __user *) arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		return rc;
+	}
+
+	if (cmd == AUDIO_ABORT_GET_EVENT) {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		MM_DBG("AUDIO_START\n");
+		rc = audevrc_enable(audio);
+		if (!rc) {
+			rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+			MM_INFO("dec_state %d rc = %d\n", audio->dec_state, rc);
+
+			if (audio->dec_state != MSM_AUD_DECODER_STATE_SUCCESS)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		break;
+	case AUDIO_STOP:
+		MM_DBG("AUDIO_STOP\n");
+		rc = audevrc_disable(audio);
+		audevrc_ioport_reset(audio);
+		audio->stopped = 0;
+		break;
+	case AUDIO_FLUSH:
+		MM_DBG("AUDIO_FLUSH\n");
+		audio->rflush = 1;
+		audio->wflush = 1;
+		audevrc_ioport_reset(audio);
+		if (audio->running) {
+			audpp_flush(audio->dec_id);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		break;
+	case AUDIO_SET_CONFIG:{
+			struct msm_audio_config config;
+			if (copy_from_user
+				(&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+			audio->mfield = config.meta_field;
+			rc = 0;
+			MM_DBG("AUDIO_SET_CONFIG applicable only \
+				for meta field configuration\n");
+			break;
+		}
+	case AUDIO_GET_CONFIG:{
+			struct msm_audio_config config;
+			config.buffer_size = BUFSZ;
+			config.buffer_count = 2;
+			config.sample_rate = 8000;
+			config.channel_count = 1;
+			config.meta_field = 0;
+			config.unused[0] = 0;
+			config.unused[1] = 0;
+			config.unused[2] = 0;
+			if (copy_to_user((void *)arg, &config, sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_GET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			config.pcm_feedback = audio->pcm_feedback;
+			config.buffer_count = PCM_BUF_MAX_COUNT;
+			config.buffer_size = PCM_BUFSZ_MIN;
+			if (copy_to_user((void *)arg, &config, sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_SET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			if (copy_from_user
+			    (&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+			if (config.pcm_feedback != audio->pcm_feedback) {
+				MM_ERR("Not sufficient permission to"
+					 "change the playback mode\n");
+				rc = -EACCES;
+				break;
+			}
+			if ((config.buffer_count > PCM_BUF_MAX_COUNT) ||
+			    (config.buffer_count == 1))
+				config.buffer_count = PCM_BUF_MAX_COUNT;
+
+			if (config.buffer_size < PCM_BUFSZ_MIN)
+				config.buffer_size = PCM_BUFSZ_MIN;
+
+			/* Check if pcm feedback is required */
+			if ((config.pcm_feedback) && (!audio->read_data)) {
+				MM_DBG("allocate PCM buf %d\n",
+					config.buffer_count *
+					config.buffer_size);
+				audio->read_phys =
+						allocate_contiguous_ebi_nomap(
+							config.buffer_size *
+							config.buffer_count,
+							SZ_4K);
+				if (!audio->read_phys) {
+					rc = -ENOMEM;
+					break;
+				}
+				audio->map_v_read = ioremap(
+							audio->read_phys,
+							config.buffer_size *
+							config.buffer_count);
+				if (IS_ERR(audio->map_v_read)) {
+					MM_ERR("failed to map mem"
+							" for read buf\n");
+					rc = -ENOMEM;
+					free_contiguous_memory_by_paddr(
+							audio->read_phys);
+				} else {
+					uint8_t index;
+					uint32_t offset = 0;
+					audio->read_data =
+						audio->map_v_read;
+					audio->buf_refresh = 0;
+					audio->pcm_buf_count =
+					    config.buffer_count;
+					audio->read_next = 0;
+					audio->fill_next = 0;
+
+					for (index = 0;
+					     index < config.buffer_count;
+					     index++) {
+						audio->in[index].data =
+						    audio->read_data + offset;
+						audio->in[index].addr =
+						    audio->read_phys + offset;
+						audio->in[index].size =
+						    config.buffer_size;
+						audio->in[index].used = 0;
+						offset += config.buffer_size;
+					}
+					MM_DBG("read buf: phy addr \
+						0x%08x kernel addr 0x%08x\n",
+						audio->read_phys,
+						(int)audio->read_data);
+					rc = 0;
+				}
+			} else {
+				rc = 0;
+			}
+			break;
+		}
+	case AUDIO_PAUSE:
+		MM_DBG("AUDIO_PAUSE %ld\n", arg);
+		rc = audpp_pause(audio->dec_id, (int) arg);
+		break;
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+/* Only useful in tunnel-mode */
+static int audevrc_fsync(struct file *file, loff_t a, loff_t b, int datasync)
+{
+	struct audio *audio = file->private_data;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (!audio->running || audio->pcm_feedback) {
+		rc = -EINVAL;
+		goto done_nolock;
+	}
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(!audio->out[0].used &&
+		!audio->out[1].used &&
+		audio->out_needed) || audio->wflush);
+
+	if (rc < 0)
+		goto done;
+	else if (audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	/* pcm dmamiss message is sent continously
+	 * when decoder is starved so no race
+	 * condition concern
+	 */
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		audio->teos || audio->wflush);
+
+	if (audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+done_nolock:
+	return rc;
+}
+
+static ssize_t audevrc_read(struct file *file, char __user *buf, size_t count,
+			    loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	int rc = 0;
+	if (!audio->pcm_feedback) {
+		return 0;
+		/* PCM feedback is not enabled. Nothing to read */
+	}
+	mutex_lock(&audio->read_lock);
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	while (count > 0) {
+		rc = wait_event_interruptible(audio->read_wait,
+				(audio->in[audio->read_next].used > 0) ||
+				(audio->stopped) || (audio->rflush));
+
+		MM_DBG("wait terminated \n");
+		if (rc < 0)
+			break;
+		if (audio->stopped || audio->rflush) {
+			rc = -EBUSY;
+			break;
+		}
+		if (count < audio->in[audio->read_next].used) {
+			/* Read must happen in frame boundary. Since driver does
+			 * not know frame size, read count must be greater or
+			 * equal to size of PCM samples
+			 */
+			MM_DBG("read stop - partial frame\n");
+			break;
+		} else {
+			MM_DBG("read from in[%d]\n", audio->read_next);
+			/* order reads from the output buffer */
+			rmb();
+			if (copy_to_user
+			    (buf, audio->in[audio->read_next].data,
+			     audio->in[audio->read_next].used)) {
+				MM_ERR("invalid addr %x \n",
+				       (unsigned int)buf);
+				rc = -EFAULT;
+				break;
+			}
+			count -= audio->in[audio->read_next].used;
+			buf += audio->in[audio->read_next].used;
+			audio->in[audio->read_next].used = 0;
+			if ((++audio->read_next) == audio->pcm_buf_count)
+				audio->read_next = 0;
+			break;
+				/* Force to exit while loop
+				 * to prevent output thread
+				 * sleep too long if data is
+				 * not ready at this moment
+				 */
+
+		}
+	}
+	/* don't feed output buffer to HW decoder during flushing
+	 * buffer refresh command will be sent once flush completes
+	 * send buf refresh command here can confuse HW decoder
+	 */
+	if (audio->buf_refresh && !audio->rflush) {
+		audio->buf_refresh = 0;
+		MM_DBG("kick start pcm feedback again\n");
+		audevrc_buffer_refresh(audio);
+	}
+	mutex_unlock(&audio->read_lock);
+	if (buf > start)
+		rc = buf - start;
+	MM_DBG("read %d bytes\n", rc);
+	return rc;
+}
+
+static int audevrc_process_eos(struct audio *audio,
+		const char __user *buf_start, unsigned short mfield_size)
+{
+	int rc = 0;
+	struct buffer *frame;
+
+	frame = audio->out + audio->out_head;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->out_needed &&
+		audio->out[0].used == 0 &&
+		audio->out[1].used == 0)
+		|| (audio->stopped)
+		|| (audio->wflush));
+
+	if (rc < 0)
+		goto done;
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (copy_from_user(frame->data, buf_start, mfield_size)) {
+		rc = -EFAULT;
+		goto done;
+	}
+
+	frame->mfield_sz = mfield_size;
+	audio->out_head ^= 1;
+	frame->used = mfield_size;
+	audevrc_send_data(audio, 0);
+
+done:
+	return rc;
+}
+
+static ssize_t audevrc_write(struct file *file, const char __user *buf,
+			     size_t count, loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	char *cpy_ptr;
+	unsigned short mfield_size = 0;
+	int rc = 0, eos_condition = AUDEVRC_EOS_NONE;
+
+	MM_DBG("cnt=%d\n", count);
+
+	if (count & 1)
+		return -EINVAL;
+
+	mutex_lock(&audio->write_lock);
+	while (count > 0) {
+		frame = audio->out + audio->out_head;
+		cpy_ptr = frame->data;
+		rc = wait_event_interruptible(audio->write_wait,
+					      (frame->used == 0)
+						|| (audio->stopped)
+						|| (audio->wflush));
+		if (rc < 0)
+			break;
+		if (audio->stopped || audio->wflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (audio->mfield) {
+			if (buf == start) {
+				/* Processing beginning of user buffer */
+				if (__get_user(mfield_size,
+					(unsigned short __user *) buf)) {
+					rc = -EFAULT;
+					break;
+				} else if (mfield_size > count) {
+					rc = -EINVAL;
+					break;
+				}
+				MM_DBG("mf offset_val %x\n", mfield_size);
+				if (copy_from_user(cpy_ptr, buf,
+							mfield_size)) {
+					rc = -EFAULT;
+					break;
+				}
+				/* Check if EOS flag is set and buffer has
+				 * contains just meta field
+				 */
+				if (cpy_ptr[AUDEVRC_EOS_FLG_OFFSET] &
+						AUDEVRC_EOS_FLG_MASK) {
+					MM_DBG("eos set\n");
+					eos_condition = AUDEVRC_EOS_SET;
+					if (mfield_size == count) {
+						buf += mfield_size;
+						break;
+					} else
+					cpy_ptr[AUDEVRC_EOS_FLG_OFFSET] &=
+						~AUDEVRC_EOS_FLG_MASK;
+				}
+				 /* Check EOS to see if */
+				cpy_ptr += mfield_size;
+				count -= mfield_size;
+				buf += mfield_size;
+			 } else {
+				 mfield_size = 0;
+				 MM_DBG("continuous buffer\n");
+			 }
+			 frame->mfield_sz = mfield_size;
+		}
+
+		xfer = (count > (frame->size - mfield_size)) ?
+			(frame->size - mfield_size) : count;
+		if (copy_from_user(cpy_ptr, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+
+		frame->used = xfer + mfield_size;
+		audio->out_head ^= 1;
+		count -= xfer;
+		buf += xfer;
+		audevrc_send_data(audio, 0);
+	}
+	if (eos_condition == AUDEVRC_EOS_SET)
+		rc = audevrc_process_eos(audio, start, mfield_size);
+	mutex_unlock(&audio->write_lock);
+	if (!rc) {
+		if (buf > start)
+			return buf - start;
+	}
+	return rc;
+}
+
+static int audevrc_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	MM_INFO("audio instance 0x%08x freeing\n", (int)audio);
+	mutex_lock(&audio->lock);
+	audevrc_disable(audio);
+	if (audio->rmt_resource_released == 0)
+		rmt_put_resource(audio);
+	audevrc_flush(audio);
+	audevrc_flush_pcm_buf(audio);
+	msm_adsp_put(audio->audplay);
+	audpp_adec_free(audio->dec_id);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&audio->suspend_ctl.node);
+#endif
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audevrc_reset_event_queue(audio);
+	iounmap(audio->map_v_write);
+	free_contiguous_memory_by_paddr(audio->phys);
+	if (audio->read_data) {
+		iounmap(audio->map_v_read);
+		free_contiguous_memory_by_paddr(audio->read_phys);
+	}
+	mutex_unlock(&audio->lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio);
+	return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audevrc_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload)
+{
+	struct audevrc_event *e_node = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+				struct audevrc_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audevrc_event), GFP_ATOMIC);
+		if (!e_node) {
+			MM_ERR("No mem to post event %d\n", type);
+			spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	wake_up(&audio->event_wait);
+}
+
+static void audevrc_suspend(struct early_suspend *h)
+{
+	struct audevrc_suspend_ctl *ctl =
+		container_of(h, struct audevrc_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audevrc_post_event(ctl->audio, AUDIO_EVENT_SUSPEND, payload);
+}
+
+static void audevrc_resume(struct early_suspend *h)
+{
+	struct audevrc_suspend_ctl *ctl =
+		container_of(h, struct audevrc_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audevrc_post_event(ctl->audio, AUDIO_EVENT_RESUME, payload);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audevrc_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audevrc_debug_read(struct file *file, char __user *buf,
+					size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 1024;
+	static char buffer[1024];
+	int n = 0, i;
+	struct audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"enabled %d\n", audio->enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_feedback %d\n", audio->pcm_feedback);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_buf_sz %d\n", audio->out[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_buf_count %d \n", audio->pcm_buf_count);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_buf_sz %d \n", audio->in[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"volume %x \n", audio->vol_pan.volume);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"rflush %d\n", audio->rflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"running %d \n", audio->running);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"dec state %d \n", audio->dec_state);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_needed %d \n", audio->out_needed);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_head %d \n", audio->out_head);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_tail %d \n", audio->out_tail);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out[0].used %d \n", audio->out[0].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out[1].used %d \n", audio->out[1].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"buffer_refresh %d \n", audio->buf_refresh);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"read_next %d \n", audio->read_next);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"fill_next %d \n", audio->fill_next);
+	for (i = 0; i < audio->pcm_buf_count; i++)
+		n += scnprintf(buffer + n, debug_bufmax - n,
+				"in[%d].size %d \n", i, audio->in[i].used);
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audevrc_debug_fops = {
+	.read = audevrc_debug_read,
+	.open = audevrc_debug_open,
+};
+#endif
+
+static int audevrc_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = NULL;
+	int rc, dec_attrb, decid, i;
+	struct audevrc_event *e_node = NULL;
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_evrc_" + 5];
+#endif
+
+	/* Allocate audio instance, set to zero */
+	audio = kzalloc(sizeof(struct audio), GFP_KERNEL);
+	if (!audio) {
+		MM_ERR("no memory to allocate audio instance\n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	MM_INFO("audio instance 0x%08x created\n", (int)audio);
+
+	/* Allocate the decoder */
+	dec_attrb = AUDDEC_DEC_EVRC;
+	if ((file->f_mode & FMODE_WRITE) &&
+			(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_NONTUNNEL;
+		audio->pcm_feedback = NON_TUNNEL_MODE_PLAYBACK;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_TUNNEL;
+		audio->pcm_feedback = TUNNEL_MODE_PLAYBACK;
+	} else {
+		kfree(audio);
+		rc = -EACCES;
+		goto done;
+	}
+	decid = audpp_adec_alloc(dec_attrb, &audio->module_name,
+			&audio->queue_id);
+
+	if (decid < 0) {
+		MM_ERR("No free decoder available, freeing instance 0x%08x\n",
+				(int)audio);
+		rc = -ENODEV;
+		kfree(audio);
+		goto done;
+	}
+
+	audio->dec_id = decid & MSM_AUD_DECODER_MASK;
+
+	audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
+	if (!audio->phys) {
+		MM_ERR("could not allocate write buffers, freeing instance \
+				0x%08x\n", (int)audio);
+		rc = -ENOMEM;
+		audpp_adec_free(audio->dec_id);
+		kfree(audio);
+		goto done;
+	} else {
+		audio->map_v_write = ioremap(audio->phys, DMASZ);
+		if (IS_ERR(audio->map_v_write)) {
+			MM_ERR("could not map write buffers, freeing \
+					instance 0x%08x\n", (int)audio);
+			rc = -ENOMEM;
+			free_contiguous_memory_by_paddr(audio->phys);
+			audpp_adec_free(audio->dec_id);
+			kfree(audio);
+			goto done;
+		}
+		audio->data = audio->map_v_write;
+		MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+				audio->phys, (int)audio->data);
+	}
+
+	if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
+		rc = audmgr_open(&audio->audmgr);
+		if (rc) {
+			MM_ERR("audmgr open failed, freeing instance \
+					0x%08x\n", (int)audio);
+			goto err;
+		}
+	}
+
+	rc = msm_adsp_get(audio->module_name, &audio->audplay,
+			&audplay_adsp_ops_evrc, audio);
+
+	if (rc) {
+		MM_ERR("failed to get %s module, freeing instance 0x%08x\n",
+				audio->module_name, (int)audio);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_close(&audio->audmgr);
+		goto err;
+	}
+
+	rc = rmt_get_resource(audio);
+	if (rc) {
+		MM_ERR("ADSP resources are not available for EVRC session \
+			 0x%08x on decoder: %d\n", (int)audio, audio->dec_id);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_close(&audio->audmgr);
+		msm_adsp_put(audio->audplay);
+		goto err;
+	}
+
+	/* Initialize all locks of audio instance */
+	mutex_init(&audio->lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->get_event_lock);
+	spin_lock_init(&audio->dsp_lock);
+	init_waitqueue_head(&audio->write_wait);
+	init_waitqueue_head(&audio->read_wait);
+	INIT_LIST_HEAD(&audio->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+	init_waitqueue_head(&audio->wait);
+	init_waitqueue_head(&audio->event_wait);
+	spin_lock_init(&audio->event_queue_lock);
+
+	audio->out[0].data = audio->data + 0;
+	audio->out[0].addr = audio->phys + 0;
+	audio->out[0].size = BUFSZ;
+
+	audio->out[1].data = audio->data + BUFSZ;
+	audio->out[1].addr = audio->phys + BUFSZ;
+	audio->out[1].size = BUFSZ;
+
+	audio->vol_pan.volume = 0x3FFF;
+
+	audevrc_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_evrc_%04x", audio->dec_id);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+			NULL, (void *) audio, &audevrc_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		MM_DBG("debugfs_create_file failed\n");
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	audio->suspend_ctl.node.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+	audio->suspend_ctl.node.resume = audevrc_resume;
+	audio->suspend_ctl.node.suspend = audevrc_suspend;
+	audio->suspend_ctl.audio = audio;
+	register_early_suspend(&audio->suspend_ctl.node);
+#endif
+	for (i = 0; i < AUDEVRC_EVENT_NUM; i++) {
+		e_node = kmalloc(sizeof(struct audevrc_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			MM_ERR("event pkt alloc failed\n");
+			break;
+		}
+	}
+done:
+	return rc;
+err:
+	iounmap(audio->map_v_write);
+	free_contiguous_memory_by_paddr(audio->phys);
+	audpp_adec_free(audio->dec_id);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_evrc_fops = {
+	.owner = THIS_MODULE,
+	.open = audevrc_open,
+	.release = audevrc_release,
+	.read = audevrc_read,
+	.write = audevrc_write,
+	.unlocked_ioctl = audevrc_ioctl,
+	.fsync = audevrc_fsync,
+};
+
+struct miscdevice audio_evrc_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_evrc",
+	.fops = &audio_evrc_fops,
+};
+
+static int __init audevrc_init(void)
+{
+	return misc_register(&audio_evrc_misc);
+
+}
+
+static void __exit audevrc_exit(void)
+{
+	misc_deregister(&audio_evrc_misc);
+}
+
+module_init(audevrc_init);
+module_exit(audevrc_exit);
+
+MODULE_DESCRIPTION("MSM EVRC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5/audio_evrc_in.c b/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
new file mode 100644
index 0000000..e13b072
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
@@ -0,0 +1,1396 @@
+/* arch/arm/mach-msm/qdsp5/audio_evrc_in.c
+ *
+ * evrc audio input device
+ *
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This code is based in part on arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c,
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/delay.h>
+
+#include <linux/msm_audio_qcp.h>
+
+
+#include <linux/memory_alloc.h>
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <mach/msm_memtypes.h>
+#include <mach/msm_adsp.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+
+#include "audmgr.h"
+
+#include <mach/qdsp5/qdsp5audpreproc.h>
+#include <mach/qdsp5/qdsp5audpreproccmdi.h>
+#include <mach/qdsp5/qdsp5audpreprocmsg.h>
+#include <mach/qdsp5/qdsp5audreccmdi.h>
+#include <mach/qdsp5/qdsp5audrecmsg.h>
+#include <mach/debug_mm.h>
+
+#define FRAME_HEADER_SIZE	8 /* 8 bytes frame header */
+#define NT_FRAME_HEADER_SIZE	24 /* 24 bytes frame header */
+/* FRAME_NUM must be a power of two */
+#define FRAME_NUM	8
+#define EVRC_FRAME_SIZE	36 /* 36 bytes data */
+/*Tunnel mode : 36 bytes data + 8 byte header*/
+#define FRAME_SIZE	(EVRC_FRAME_SIZE + FRAME_HEADER_SIZE)
+ /* 36 bytes data  + 24 meta field*/
+#define NT_FRAME_SIZE	(EVRC_FRAME_SIZE + NT_FRAME_HEADER_SIZE)
+#define DMASZ		(FRAME_SIZE * FRAME_NUM)
+#define NT_DMASZ	(NT_FRAME_SIZE * FRAME_NUM)
+#define OUT_FRAME_NUM	2
+#define OUT_BUFFER_SIZE (4 * 1024 + NT_FRAME_HEADER_SIZE)
+#define BUFFER_SIZE	(OUT_BUFFER_SIZE * OUT_FRAME_NUM)
+
+#define AUDPREPROC_EVRC_EOS_FLG_OFFSET 0x0A /* Offset from beginning of buffer*/
+#define AUDPREPROC_EVRC_EOS_FLG_MASK 0x01
+#define AUDPREPROC_EVRC_EOS_NONE 0x0 /* No EOS detected */
+#define AUDPREPROC_EVRC_EOS_SET 0x1 /* EOS set in meta field */
+
+struct buffer {
+	void *data;
+	uint32_t size;
+	uint32_t read;
+	uint32_t addr;
+	uint32_t used;
+	uint32_t mfield_sz;
+};
+
+struct audio_evrc_in {
+	struct buffer in[FRAME_NUM];
+
+	spinlock_t dsp_lock;
+
+	atomic_t in_bytes;
+	atomic_t in_samples;
+
+	struct mutex lock;
+	struct mutex read_lock;
+	wait_queue_head_t wait;
+	wait_queue_head_t wait_enable;
+	/*write section*/
+	struct buffer out[OUT_FRAME_NUM];
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed;	/* number of buffers the dsp is waiting for */
+	uint32_t out_count;
+
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+	int32_t out_phys; /* physical address of write buffer */
+	char *out_data;
+	int mfield; /* meta field embedded in data */
+	int wflush; /*write flush */
+	int rflush; /*read flush*/
+	int out_frame_cnt;
+
+	struct msm_adsp_module *audrec;
+	struct msm_adsp_module *audpre;
+
+
+	/* configuration to use on next enable */
+	uint32_t samp_rate;
+	uint32_t channel_mode;
+	uint32_t buffer_size; /* Frame size (36 bytes) */
+	uint32_t enc_type; /* 11 for EVRC */
+	uint32_t mode; /* T or NT Mode*/
+
+	struct msm_audio_evrc_enc_config cfg;
+
+	uint32_t dsp_cnt;
+	uint32_t in_head; /* next buffer dsp will write */
+	uint32_t in_tail; /* next buffer read() will read */
+	uint32_t in_count; /* number of buffers available to read() */
+
+	uint32_t eos_ack;
+	uint32_t flush_ack;
+
+	const char *module_name;
+	unsigned queue_ids;
+	uint16_t enc_id; /* Session Id */
+
+	unsigned short samp_rate_index;
+	uint32_t audrec_obj_idx ;
+
+	struct audmgr audmgr;
+
+	/* data allocated for various buffers */
+	char *data;
+	dma_addr_t phys;
+
+	void *map_v_read;
+	void *map_v_write;
+
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+};
+
+struct audio_frame {
+	uint16_t frame_count_lsw;
+	uint16_t frame_count_msw;
+	uint16_t frame_length;
+	uint16_t erased_pcm;
+	unsigned char raw_bitstream[];
+} __packed;
+
+struct audio_frame_nt {
+	uint16_t metadata_len;
+	uint16_t frame_count_lsw;
+	uint16_t frame_count_msw;
+	uint16_t frame_length;
+	uint16_t erased_pcm;
+	uint16_t reserved;
+	uint16_t time_stamp_dword_lsw;
+	uint16_t time_stamp_dword_msw;
+	uint16_t time_stamp_lsw;
+	uint16_t time_stamp_msw;
+	uint16_t nflag_lsw;
+	uint16_t nflag_msw;
+	unsigned char raw_bitstream[]; /* samples */
+} __packed;
+
+struct evrc_encoded_meta_out {
+	uint16_t metadata_len;
+	uint16_t time_stamp_dword_lsw;
+	uint16_t time_stamp_dword_msw;
+	uint16_t time_stamp_lsw;
+	uint16_t time_stamp_msw;
+	uint16_t nflag_lsw;
+	uint16_t nflag_msw;
+};
+
+/* Audrec Queue command sent macro's */
+#define audio_send_queue_pre(audio, cmd, len) \
+	msm_adsp_write(audio->audpre, QDSP_uPAudPreProcCmdQueue, cmd, len)
+
+#define audio_send_queue_recbs(audio, cmd, len) \
+	msm_adsp_write(audio->audrec, ((audio->queue_ids & 0xFFFF0000) >> 16),\
+			cmd, len)
+#define audio_send_queue_rec(audio, cmd, len) \
+	msm_adsp_write(audio->audrec, (audio->queue_ids & 0x0000FFFF),\
+			cmd, len)
+
+static int audevrc_in_dsp_enable(struct audio_evrc_in *audio, int enable);
+static int audevrc_in_encparam_config(struct audio_evrc_in *audio);
+static int audevrc_in_encmem_config(struct audio_evrc_in *audio);
+static int audevrc_in_dsp_read_buffer(struct audio_evrc_in *audio,
+				uint32_t read_cnt);
+static void audevrc_in_flush(struct audio_evrc_in *audio);
+
+static void audevrc_in_get_dsp_frames(struct audio_evrc_in *audio);
+static int audpcm_config(struct audio_evrc_in *audio);
+static void audevrc_out_flush(struct audio_evrc_in *audio);
+static int audevrc_in_routing_mode_config(struct audio_evrc_in *audio);
+static void audrec_pcm_send_data(struct audio_evrc_in *audio, unsigned needed);
+static void audevrc_nt_in_get_dsp_frames(struct audio_evrc_in *audio);
+static void audevrc_in_flush(struct audio_evrc_in *audio);
+
+static unsigned convert_samp_index(unsigned index)
+{
+	switch (index) {
+	case RPC_AUD_DEF_SAMPLE_RATE_48000:	return 48000;
+	case RPC_AUD_DEF_SAMPLE_RATE_44100:	return 44100;
+	case RPC_AUD_DEF_SAMPLE_RATE_32000:	return 32000;
+	case RPC_AUD_DEF_SAMPLE_RATE_24000:	return 24000;
+	case RPC_AUD_DEF_SAMPLE_RATE_22050:	return 22050;
+	case RPC_AUD_DEF_SAMPLE_RATE_16000:	return 16000;
+	case RPC_AUD_DEF_SAMPLE_RATE_12000:	return 12000;
+	case RPC_AUD_DEF_SAMPLE_RATE_11025:	return 11025;
+	case RPC_AUD_DEF_SAMPLE_RATE_8000:	return 8000;
+	default:				return 11025;
+	}
+}
+
+/* must be called with audio->lock held */
+static int audevrc_in_enable(struct audio_evrc_in *audio)
+{
+	struct audmgr_config cfg;
+	int rc;
+
+	if (audio->enabled)
+		return 0;
+
+	cfg.tx_rate = audio->samp_rate;
+	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+	cfg.def_method = RPC_AUD_DEF_METHOD_RECORD;
+	cfg.codec = RPC_AUD_DEF_CODEC_EVRC;
+	cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+		rc = audmgr_enable(&audio->audmgr, &cfg);
+		if (rc < 0)
+			return rc;
+
+		if (msm_adsp_enable(audio->audpre)) {
+			audmgr_disable(&audio->audmgr);
+			MM_ERR("msm_adsp_enable(audpre) failed\n");
+			return -ENODEV;
+		}
+	}
+	if (msm_adsp_enable(audio->audrec)) {
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+			audmgr_disable(&audio->audmgr);
+			msm_adsp_disable(audio->audpre);
+		}
+		MM_ERR("msm_adsp_enable(audrec) failed\n");
+		return -ENODEV;
+	}
+
+	audio->enabled = 1;
+	audevrc_in_dsp_enable(audio, 1);
+
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audevrc_in_disable(struct audio_evrc_in *audio)
+{
+	if (audio->enabled) {
+		audio->enabled = 0;
+
+		audevrc_in_dsp_enable(audio, 0);
+
+		wake_up(&audio->wait);
+		wait_event_interruptible_timeout(audio->wait_enable,
+				audio->running == 0, 1*HZ);
+		audio->stopped = 1;
+		wake_up(&audio->wait);
+		msm_adsp_disable(audio->audrec);
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+			msm_adsp_disable(audio->audpre);
+			audmgr_disable(&audio->audmgr);
+		}
+	}
+	return 0;
+}
+
+/* ------------------- dsp --------------------- */
+static void audpre_dsp_event(void *data, unsigned id, size_t len,
+			    void (*getevent)(void *ptr, size_t len))
+{
+	uint16_t msg[2];
+	getevent(msg, sizeof(msg));
+
+	switch (id) {
+	case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
+		MM_DBG("type %d, status_flag %d\n", msg[0], msg[1]);
+		break;
+	case AUDPREPROC_MSG_ERROR_MSG_ID:
+		MM_ERR("err_index %d\n", msg[0]);
+		break;
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audpreproctask)\n");
+		break;
+	default:
+		MM_ERR("unknown event %d\n", id);
+	}
+}
+
+static void audevrc_in_get_dsp_frames(struct audio_evrc_in *audio)
+{
+	struct audio_frame *frame;
+	uint32_t index;
+	unsigned long flags;
+
+	index = audio->in_head;
+
+	frame = (void *) (((char *)audio->in[index].data) -
+			sizeof(*frame));
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->in[index].size = frame->frame_length;
+
+	/* statistics of read */
+	atomic_add(audio->in[index].size, &audio->in_bytes);
+	atomic_add(1, &audio->in_samples);
+
+	audio->in_head = (audio->in_head + 1) & (FRAME_NUM - 1);
+
+	/* If overflow, move the tail index foward. */
+	if (audio->in_head == audio->in_tail) {
+		MM_ERR("Error! not able to keep up the read\n");
+		audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
+		MM_ERR("in_count = %d\n", audio->in_count);
+	} else
+		audio->in_count++;
+
+	audevrc_in_dsp_read_buffer(audio, audio->dsp_cnt++);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+
+	wake_up(&audio->wait);
+}
+
+static void audevrc_nt_in_get_dsp_frames(struct audio_evrc_in *audio)
+{
+	struct audio_frame_nt *nt_frame;
+	uint32_t index;
+	unsigned long flags;
+
+	index = audio->in_head;
+	nt_frame = (void *) (((char *)audio->in[index].data) - \
+				sizeof(struct audio_frame_nt));
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->in[index].size = nt_frame->frame_length;
+	/* statistics of read */
+	atomic_add(audio->in[index].size, &audio->in_bytes);
+	atomic_add(1, &audio->in_samples);
+
+	audio->in_head = (audio->in_head + 1) & (FRAME_NUM - 1);
+
+	/* If overflow, move the tail index foward. */
+	if (audio->in_head == audio->in_tail)
+		MM_DBG("Error! not able to keep up the read\n");
+	else
+		audio->in_count++;
+
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	wake_up(&audio->wait);
+}
+
+static int audrec_pcm_buffer_ptr_refresh(struct audio_evrc_in *audio,
+				       unsigned idx, unsigned len)
+{
+	struct audrec_cmd_pcm_buffer_ptr_refresh_arm_enc cmd;
+
+	if (len ==  NT_FRAME_HEADER_SIZE)
+		len = len / 2;
+	else
+		len = (len + NT_FRAME_HEADER_SIZE) / 2;
+	MM_DBG("len = %d\n", len);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_PCM_BUFFER_PTR_REFRESH_ARM_TO_ENC;
+	cmd.num_buffers = 1;
+	if (cmd.num_buffers == 1) {
+		cmd.buf_address_length[0] = (audio->out[idx].addr &
+							0xffff0000) >> 16;
+		cmd.buf_address_length[1] = (audio->out[idx].addr &
+							0x0000ffff);
+		cmd.buf_address_length[2] = (len & 0xffff0000) >> 16;
+		cmd.buf_address_length[3] = (len & 0x0000ffff);
+	}
+	audio->out_frame_cnt++;
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static int audpcm_config(struct audio_evrc_in *audio)
+{
+	struct audrec_cmd_pcm_cfg_arm_to_enc cmd;
+	MM_DBG("\n");
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_PCM_CFG_ARM_TO_ENC;
+	cmd.config_update_flag = AUDREC_PCM_CONFIG_UPDATE_FLAG_ENABLE;
+	cmd.enable_flag = AUDREC_ENABLE_FLAG_VALUE;
+	cmd.sampling_freq = convert_samp_index(audio->samp_rate);
+	if (!audio->channel_mode)
+		cmd.channels = 1;
+	else
+		cmd.channels = 2;
+	cmd.frequency_of_intimation = 1;
+	cmd.max_number_of_buffers = OUT_FRAME_NUM;
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+
+static int audevrc_in_routing_mode_config(struct audio_evrc_in *audio)
+{
+	struct audrec_cmd_routing_mode cmd;
+
+	MM_DBG("\n");
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_ROUTING_MODE;
+	if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)
+		cmd.routing_mode = 1;
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static void audrec_dsp_event(void *data, unsigned id, size_t len,
+			    void (*getevent)(void *ptr, size_t len))
+{
+	struct audio_evrc_in *audio = NULL;
+
+	if (data)
+		audio = data;
+	else {
+		MM_ERR("invalid data for event %x\n", id);
+		return;
+	}
+
+	switch (id) {
+	case AUDREC_MSG_CMD_CFG_DONE_MSG: {
+		struct audrec_msg_cmd_cfg_done_msg cmd_cfg_done_msg;
+		getevent(&cmd_cfg_done_msg, AUDREC_MSG_CMD_CFG_DONE_MSG_LEN);
+		if (cmd_cfg_done_msg.audrec_enc_type & \
+				AUDREC_MSG_CFG_DONE_ENC_ENA) {
+			audio->audrec_obj_idx = cmd_cfg_done_msg.audrec_obj_idx;
+			MM_DBG("CFG ENABLED\n");
+			if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
+				MM_DBG("routing command\n");
+				audevrc_in_routing_mode_config(audio);
+			} else {
+				audevrc_in_encmem_config(audio);
+			}
+		} else {
+			MM_DBG("CFG SLEEP\n");
+			audio->running = 0;
+			wake_up(&audio->wait_enable);
+		}
+		break;
+	}
+	case AUDREC_MSG_CMD_ROUTING_MODE_DONE_MSG: {
+		struct audrec_msg_cmd_routing_mode_done_msg \
+			routing_msg;
+		getevent(&routing_msg, AUDREC_MSG_CMD_ROUTING_MODE_DONE_MSG);
+		MM_DBG("AUDREC_MSG_CMD_ROUTING_MODE_DONE_MSG");
+		if (routing_msg.configuration == 0) {
+			MM_ERR("routing configuration failed\n");
+			audio->running = 0;
+			wake_up(&audio->wait_enable);
+		} else
+			audevrc_in_encmem_config(audio);
+		break;
+	}
+	case AUDREC_MSG_CMD_AREC_MEM_CFG_DONE_MSG: {
+		MM_DBG("AREC_MEM_CFG_DONE_MSG\n");
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
+			audevrc_in_encparam_config(audio);
+		else
+			audpcm_config(audio);
+		break;
+	}
+	case AUDREC_CMD_PCM_CFG_ARM_TO_ENC_DONE_MSG: {
+		MM_DBG("AUDREC_CMD_PCM_CFG_ARM_TO_ENC_DONE_MSG");
+		audevrc_in_encparam_config(audio);
+	    break;
+	}
+	case AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG: {
+		MM_DBG("AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG\n");
+		audio->running = 1;
+		wake_up(&audio->wait_enable);
+		if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)
+			audrec_pcm_send_data(audio, 1);
+		break;
+	}
+	case AUDREC_CMD_PCM_BUFFER_PTR_UPDATE_ARM_TO_ENC_MSG: {
+		MM_DBG("ptr_update recieved from DSP\n");
+		audrec_pcm_send_data(audio, 1);
+		break;
+	}
+	case AUDREC_MSG_NO_EXT_PKT_AVAILABLE_MSG: {
+		struct audrec_msg_no_ext_pkt_avail_msg err_msg;
+		getevent(&err_msg, AUDREC_MSG_NO_EXT_PKT_AVAILABLE_MSG_LEN);
+		MM_DBG("NO_EXT_PKT_AVAILABLE_MSG %x\n",\
+			err_msg.audrec_err_id);
+		break;
+	}
+	case AUDREC_MSG_PACKET_READY_MSG: {
+		struct audrec_msg_packet_ready_msg pkt_ready_msg;
+
+		getevent(&pkt_ready_msg, AUDREC_MSG_PACKET_READY_MSG_LEN);
+		MM_DBG("UP_PACKET_READY_MSG: write cnt msw  %d \
+		write cnt lsw %d read cnt msw %d  read cnt lsw %d \n",\
+		pkt_ready_msg.pkt_counter_msw, \
+		pkt_ready_msg.pkt_counter_lsw, \
+		pkt_ready_msg.pkt_read_cnt_msw, \
+		pkt_ready_msg.pkt_read_cnt_lsw);
+
+		audevrc_in_get_dsp_frames(audio);
+		break;
+	}
+	case AUDREC_UP_NT_PACKET_READY_MSG: {
+		struct audrec_up_nt_packet_ready_msg pkt_ready_msg;
+
+		getevent(&pkt_ready_msg, AUDREC_UP_NT_PACKET_READY_MSG_LEN);
+		MM_DBG("UP_NT_PACKET_READY_MSG: write cnt lsw  %d \
+		write cnt msw %d read cnt lsw %d  read cnt msw %d \n",\
+		pkt_ready_msg.audrec_packetwrite_cnt_lsw, \
+		pkt_ready_msg.audrec_packetwrite_cnt_msw, \
+		pkt_ready_msg.audrec_upprev_readcount_lsw, \
+		pkt_ready_msg.audrec_upprev_readcount_msw);
+
+		audevrc_nt_in_get_dsp_frames(audio);
+		break;
+	}
+	case AUDREC_CMD_FLUSH_DONE_MSG: {
+		audio->wflush = 0;
+		audio->rflush = 0;
+		audio->flush_ack = 1;
+		wake_up(&audio->write_wait);
+		MM_DBG("flush ack recieved\n");
+		break;
+	}
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module \
+				enable/disable(audrectask)\n");
+		break;
+	default:
+		MM_ERR("unknown event %d\n", id);
+	}
+}
+
+static struct msm_adsp_ops audpre_evrc_adsp_ops = {
+	.event = audpre_dsp_event,
+};
+
+static struct msm_adsp_ops audrec_evrc_adsp_ops = {
+	.event = audrec_dsp_event,
+};
+
+static int audevrc_in_dsp_enable(struct audio_evrc_in *audio, int enable)
+{
+	struct audrec_cmd_enc_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_ENC_CFG;
+	cmd.audrec_enc_type = (audio->enc_type & 0xFF) |
+			(enable ? AUDREC_CMD_ENC_ENA : AUDREC_CMD_ENC_DIS);
+	/* Don't care */
+	cmd.audrec_obj_idx = audio->audrec_obj_idx;
+
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static int audevrc_in_encmem_config(struct audio_evrc_in *audio)
+{
+	struct audrec_cmd_arecmem_cfg cmd;
+	uint16_t *data = (void *) audio->data;
+	int n;
+	int header_len = 0;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	cmd.cmd_id = AUDREC_CMD_ARECMEM_CFG;
+	cmd.audrec_obj_idx = audio->audrec_obj_idx;
+	/* Rate at which packet complete message comes */
+	cmd.audrec_up_pkt_intm_cnt = 1;
+	cmd.audrec_extpkt_buffer_msw = audio->phys >> 16;
+	cmd.audrec_extpkt_buffer_lsw = audio->phys;
+	/* Max Buffer no available for frames */
+	cmd.audrec_extpkt_buffer_num = FRAME_NUM;
+
+	/* prepare buffer pointers:
+	 * T:36 bytes evrc packet + 4 halfword header
+	 * NT:36 bytes evrc packet + 12 halfword header
+	 */
+	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
+		header_len = FRAME_HEADER_SIZE/2;
+	else
+		header_len = NT_FRAME_HEADER_SIZE/2;
+
+	for (n = 0; n < FRAME_NUM; n++) {
+		audio->in[n].data = data + header_len;
+		data += (EVRC_FRAME_SIZE/2) + header_len;
+		MM_DBG("0x%8x\n", (int)(audio->in[n].data - header_len*2));
+	}
+
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static int audevrc_in_encparam_config(struct audio_evrc_in *audio)
+{
+	struct audrec_cmd_arecparam_evrc_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDREC_CMD_ARECPARAM_CFG;
+	cmd.common.audrec_obj_idx = audio->audrec_obj_idx;
+	cmd.enc_min_rate = audio->cfg.min_bit_rate;
+	cmd.enc_max_rate = audio->cfg.max_bit_rate;
+	cmd.rate_modulation_cmd = 0;  /* Default set to 0 */
+
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static int audevrc_flush_command(struct audio_evrc_in *audio)
+{
+	struct audrec_cmd_flush cmd;
+	MM_DBG("\n");
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_FLUSH;
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static int audevrc_in_dsp_read_buffer(struct audio_evrc_in *audio,
+		uint32_t read_cnt)
+{
+	audrec_cmd_packet_ext_ptr cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_PACKET_EXT_PTR;
+	cmd.type = audio->audrec_obj_idx;
+	cmd.curr_rec_count_msw = read_cnt >> 16;
+	cmd.curr_rec_count_lsw = read_cnt;
+
+	return audio_send_queue_recbs(audio, &cmd, sizeof(cmd));
+}
+
+/* ------------------- device --------------------- */
+
+static void audevrc_ioport_reset(struct audio_evrc_in *audio)
+{
+	/* Make sure read/write thread are free from
+	 * sleep and knowing that system is not able
+	 * to process io request at the moment
+	 */
+	wake_up(&audio->wait);
+	mutex_lock(&audio->read_lock);
+	audevrc_in_flush(audio);
+	mutex_unlock(&audio->read_lock);
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audevrc_out_flush(audio);
+	mutex_unlock(&audio->write_lock);
+}
+
+static void audevrc_in_flush(struct audio_evrc_in *audio)
+{
+	int i;
+	unsigned long flags;
+
+	audio->dsp_cnt = 0;
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->in_head = 0;
+	audio->in_tail = 0;
+	audio->in_count = 0;
+	audio->eos_ack = 0;
+	for (i = FRAME_NUM-1; i >= 0; i--) {
+		audio->in[i].size = 0;
+		audio->in[i].read = 0;
+	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	MM_DBG("in_bytes %d\n", atomic_read(&audio->in_bytes));
+	MM_DBG("in_samples %d\n", atomic_read(&audio->in_samples));
+	atomic_set(&audio->in_bytes, 0);
+	atomic_set(&audio->in_samples, 0);
+}
+
+static void audevrc_out_flush(struct audio_evrc_in *audio)
+{
+	int i;
+	unsigned long flags;
+
+	audio->out_head = 0;
+	audio->out_count = 0;
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->out_tail = 0;
+	for (i = OUT_FRAME_NUM-1; i >= 0; i--) {
+		audio->out[i].size = 0;
+		audio->out[i].read = 0;
+		audio->out[i].used = 0;
+	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+static long audevrc_in_ioctl(struct file *file,
+				unsigned int cmd, unsigned long arg)
+{
+	struct audio_evrc_in *audio = file->private_data;
+	int rc = 0;
+
+	MM_DBG("\n");
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = atomic_read(&audio->in_bytes);
+		stats.sample_count = atomic_read(&audio->in_samples);
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return rc;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START: {
+		rc = audevrc_in_enable(audio);
+		if (!rc) {
+			rc =
+			wait_event_interruptible_timeout(audio->wait_enable,
+				audio->running != 0, 1*HZ);
+			MM_DBG("state %d rc = %d\n", audio->running, rc);
+
+			if (audio->running == 0)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		audio->stopped = 0;
+		break;
+	}
+	case AUDIO_STOP: {
+		rc = audevrc_in_disable(audio);
+		break;
+	}
+	case AUDIO_FLUSH: {
+		MM_DBG("AUDIO_FLUSH\n");
+		audio->rflush = 1;
+		audio->wflush = 1;
+		audevrc_ioport_reset(audio);
+		if (audio->running) {
+			audevrc_flush_command(audio);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config cfg;
+		memset(&cfg, 0, sizeof(cfg));
+		cfg.buffer_size = OUT_BUFFER_SIZE;
+		cfg.buffer_count = OUT_FRAME_NUM;
+		cfg.sample_rate = convert_samp_index(audio->samp_rate);
+		cfg.channel_count = 1;
+		cfg.type = 0;
+		cfg.unused[0] = 0;
+		cfg.unused[1] = 0;
+		cfg.unused[2] = 0;
+		if (copy_to_user((void *) arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	}
+	case AUDIO_GET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		memset(&cfg, 0, sizeof(cfg));
+		cfg.buffer_size = audio->buffer_size;
+		cfg.buffer_count = FRAME_NUM;
+		if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	}
+	case AUDIO_SET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		/* Allow only single frame */
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+			if (cfg.buffer_size != (FRAME_SIZE - 8)) {
+				rc = -EINVAL;
+				break;
+			}
+		} else {
+			if (cfg.buffer_size != (EVRC_FRAME_SIZE + 14)) {
+				rc = -EINVAL;
+				break;
+			}
+		}
+		audio->buffer_size = cfg.buffer_size;
+		break;
+	}
+	case AUDIO_GET_EVRC_ENC_CONFIG: {
+		if (copy_to_user((void *) arg, &audio->cfg, sizeof(audio->cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_EVRC_ENC_CONFIG: {
+		struct msm_audio_evrc_enc_config cfg;
+		if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		MM_DBG("0X%8x, 0x%8x, 0x%8x\n", cfg.min_bit_rate,
+				cfg.max_bit_rate, cfg.cdma_rate);
+		if (cfg.min_bit_rate > CDMA_RATE_FULL || \
+				 cfg.min_bit_rate < CDMA_RATE_EIGHTH) {
+			MM_ERR("invalid min bitrate\n");
+			rc = -EFAULT;
+			break;
+		}
+		if (cfg.max_bit_rate > CDMA_RATE_FULL || \
+				cfg.max_bit_rate < CDMA_RATE_EIGHTH) {
+			MM_ERR("invalid max bitrate\n");
+			rc = -EFAULT;
+			break;
+		}
+		/* Recording Does not support Erase and Blank */
+		if (cfg.cdma_rate > CDMA_RATE_FULL ||
+			cfg.cdma_rate < CDMA_RATE_EIGHTH) {
+			MM_ERR("invalid qcelp cdma rate\n");
+			rc = -EFAULT;
+			break;
+		}
+		memcpy(&audio->cfg, &cfg, sizeof(cfg));
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static ssize_t audevrc_in_read(struct file *file,
+				char __user *buf,
+				size_t count, loff_t *pos)
+{
+	struct audio_evrc_in *audio = file->private_data;
+	unsigned long flags;
+	const char __user *start = buf;
+	void *data;
+	uint32_t index;
+	uint32_t size;
+	int rc = 0;
+	struct evrc_encoded_meta_out meta_field;
+	struct audio_frame_nt *nt_frame;
+	MM_DBG("count = %d\n", count);
+	mutex_lock(&audio->read_lock);
+	while (count > 0) {
+		rc = wait_event_interruptible(
+			audio->wait, (audio->in_count > 0) || audio->stopped ||
+			audio->rflush);
+		if (rc < 0)
+			break;
+
+		if (audio->rflush) {
+			rc = -EBUSY;
+			break;
+		}
+		if (audio->stopped && !audio->in_count) {
+			MM_DBG("Driver in stop state, No more buffer to read");
+			rc = 0;/* End of File */
+			break;
+		}
+
+		index = audio->in_tail;
+		data = (uint8_t *) audio->in[index].data;
+		size = audio->in[index].size;
+
+		if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
+			nt_frame = (struct audio_frame_nt *)(data -
+					sizeof(struct audio_frame_nt));
+			memcpy((char *)&meta_field.time_stamp_dword_lsw,
+				(char *)&nt_frame->time_stamp_dword_lsw,
+				(sizeof(struct evrc_encoded_meta_out) - \
+				sizeof(uint16_t)));
+			meta_field.metadata_len =
+					sizeof(struct evrc_encoded_meta_out);
+			if (copy_to_user((char *)start, (char *)&meta_field,
+					sizeof(struct evrc_encoded_meta_out))) {
+				rc = -EFAULT;
+				break;
+			}
+			if (nt_frame->nflag_lsw & 0x0001) {
+				MM_ERR("recieved EOS in read call\n");
+				audio->eos_ack = 1;
+			}
+			buf += sizeof(struct evrc_encoded_meta_out);
+			count -= sizeof(struct evrc_encoded_meta_out);
+		}
+		if (count >= size) {
+			/* order the reads on the buffer */
+			dma_coherent_post_ops();
+			if (copy_to_user(buf, data, size)) {
+				rc = -EFAULT;
+				break;
+			}
+			spin_lock_irqsave(&audio->dsp_lock, flags);
+			if (index != audio->in_tail) {
+				/* overrun -- data is
+				 * invalid and we need to retry */
+				spin_unlock_irqrestore(&audio->dsp_lock, flags);
+				continue;
+			}
+			audio->in[index].size = 0;
+			audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
+			audio->in_count--;
+			spin_unlock_irqrestore(&audio->dsp_lock, flags);
+			count -= size;
+			buf += size;
+			if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)) {
+				if (!audio->eos_ack) {
+					MM_DBG("sending read ptr command \
+							%d %d\n",
+							audio->dsp_cnt,
+							audio->in_tail);
+					audevrc_in_dsp_read_buffer(audio,
+							audio->dsp_cnt++);
+				}
+			}
+		} else {
+			MM_ERR("short read\n");
+			break;
+		}
+		break;
+	}
+	mutex_unlock(&audio->read_lock);
+
+	if (buf > start)
+		return buf - start;
+
+	return rc;
+}
+
+static void audrec_pcm_send_data(struct audio_evrc_in *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+	MM_DBG("\n");
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (needed && !audio->wflush) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			MM_DBG("frame %d free\n", audio->out_tail);
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+			audrec_pcm_buffer_ptr_refresh(audio,
+						 audio->out_tail,
+						    frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+ done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static int audevrc_in_fsync(struct file *file,loff_t a, loff_t b, int datasync)
+
+{
+	struct audio_evrc_in *audio = file->private_data;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (!audio->running || (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)) {
+		rc = -EINVAL;
+		goto done_nolock;
+	}
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->write_wait,
+			audio->wflush);
+	MM_DBG("waked on by some event audio->wflush = %d\n", audio->wflush);
+
+	if (rc < 0)
+		goto done;
+	else if (audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+done:
+	mutex_unlock(&audio->write_lock);
+done_nolock:
+	return rc;
+
+}
+
+int audrec_evrc_process_eos(struct audio_evrc_in *audio,
+		const char __user *buf_start, unsigned short mfield_size)
+{
+	struct buffer *frame;
+	int rc = 0;
+
+	frame = audio->out + audio->out_head;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->out_needed &&
+		audio->out[0].used == 0 &&
+		audio->out[1].used == 0)
+		|| (audio->stopped)
+		|| (audio->wflush));
+
+	if (rc < 0)
+		goto done;
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+	if (copy_from_user(frame->data, buf_start, mfield_size)) {
+		rc = -EFAULT;
+		goto done;
+	}
+
+	frame->mfield_sz = mfield_size;
+	audio->out_head ^= 1;
+	frame->used = mfield_size;
+	MM_DBG("copying meta_out frame->used = %d\n", frame->used);
+	audrec_pcm_send_data(audio, 0);
+done:
+	return rc;
+}
+
+static ssize_t audevrc_in_write(struct file *file,
+				const char __user *buf,
+				size_t count, loff_t *pos)
+{
+	struct audio_evrc_in *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	char *cpy_ptr;
+	int rc = 0, eos_condition = AUDPREPROC_EVRC_EOS_NONE;
+	unsigned short mfield_size = 0;
+	int write_count = 0;
+	MM_DBG("cnt=%d\n", count);
+
+	if (count & 1)
+		return -EINVAL;
+
+	if (audio->mode != MSM_AUD_ENC_MODE_NONTUNNEL)
+		return -EINVAL;
+
+	mutex_lock(&audio->write_lock);
+	frame = audio->out + audio->out_head;
+	/* if supplied count is more than driver buffer size
+	 * then only copy driver buffer size
+	 */
+	if (count > frame->size)
+		count = frame->size;
+
+	write_count = count;
+	cpy_ptr = frame->data;
+	rc = wait_event_interruptible(audio->write_wait,
+				      (frame->used == 0)
+					|| (audio->stopped)
+					|| (audio->wflush));
+	if (rc < 0)
+		goto error;
+
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto error;
+	}
+	if (audio->mfield) {
+		if (buf == start) {
+			/* Processing beginning of user buffer */
+			if (__get_user(mfield_size,
+				(unsigned short __user *) buf)) {
+				rc = -EFAULT;
+				goto error;
+			} else if (mfield_size > count) {
+				rc = -EINVAL;
+				goto error;
+			}
+			MM_DBG("mf offset_val %x\n", mfield_size);
+			if (copy_from_user(cpy_ptr, buf, mfield_size)) {
+				rc = -EFAULT;
+				goto error;
+			}
+			/* Check if EOS flag is set and buffer has
+			 * contains just meta field
+			 */
+			if (cpy_ptr[AUDPREPROC_EVRC_EOS_FLG_OFFSET] &
+					AUDPREPROC_EVRC_EOS_FLG_MASK) {
+				eos_condition = AUDPREPROC_EVRC_EOS_SET;
+				MM_DBG("EOS SET\n");
+				if (mfield_size == count) {
+					buf += mfield_size;
+					eos_condition = 0;
+					goto exit;
+				} else
+				cpy_ptr[AUDPREPROC_EVRC_EOS_FLG_OFFSET] &=
+					~AUDPREPROC_EVRC_EOS_FLG_MASK;
+			}
+			cpy_ptr += mfield_size;
+			count -= mfield_size;
+			buf += mfield_size;
+		} else {
+			mfield_size = 0;
+			MM_DBG("continuous buffer\n");
+		}
+		frame->mfield_sz = mfield_size;
+	}
+	MM_DBG("copying the stream count = %d\n", count);
+	if (copy_from_user(cpy_ptr, buf, count)) {
+		rc = -EFAULT;
+		goto error;
+	}
+exit:
+	frame->used = count;
+	audio->out_head ^= 1;
+	if (!audio->flush_ack)
+		audrec_pcm_send_data(audio, 0);
+	else {
+		audrec_pcm_send_data(audio, 1);
+		audio->flush_ack = 0;
+	}
+	if (eos_condition == AUDPREPROC_EVRC_EOS_SET)
+		rc = audrec_evrc_process_eos(audio, start, mfield_size);
+	mutex_unlock(&audio->write_lock);
+	return write_count;
+error:
+	mutex_unlock(&audio->write_lock);
+	return rc;
+}
+
+static int audevrc_in_release(struct inode *inode, struct file *file)
+{
+	struct audio_evrc_in *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	audevrc_in_disable(audio);
+	audevrc_in_flush(audio);
+	msm_adsp_put(audio->audrec);
+
+	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
+		msm_adsp_put(audio->audpre);
+
+	audpreproc_aenc_free(audio->enc_id);
+	audio->audrec = NULL;
+	audio->audpre = NULL;
+	audio->opened = 0;
+	if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) && \
+	   (audio->out_data)) {
+		iounmap(audio->map_v_write);
+		free_contiguous_memory_by_paddr(audio->out_phys);
+		audio->out_data = NULL;
+	}
+	if (audio->data) {
+		iounmap(audio->map_v_read);
+		free_contiguous_memory_by_paddr(audio->phys);
+		audio->data = NULL;
+	}
+	mutex_unlock(&audio->lock);
+	return 0;
+}
+
+static struct audio_evrc_in the_audio_evrc_in;
+
+static int audevrc_in_open(struct inode *inode, struct file *file)
+{
+	struct audio_evrc_in *audio = &the_audio_evrc_in;
+	int rc;
+	int encid;
+	int dma_size = 0;
+
+	mutex_lock(&audio->lock);
+	if (audio->opened) {
+		rc = -EBUSY;
+		goto done;
+	}
+	if ((file->f_mode & FMODE_WRITE) &&
+		(file->f_mode & FMODE_READ)) {
+		audio->mode = MSM_AUD_ENC_MODE_NONTUNNEL;
+		dma_size = NT_DMASZ;
+		MM_DBG("Opened for non tunnel mode encoding\n");
+	} else if (!(file->f_mode & FMODE_WRITE) &&
+				(file->f_mode & FMODE_READ)) {
+		audio->mode = MSM_AUD_ENC_MODE_TUNNEL;
+		dma_size = DMASZ;
+		MM_DBG("Opened for tunnel mode encoding\n");
+	} else {
+		MM_ERR("Invalid mode\n");
+		rc = -EACCES;
+		goto done;
+	}
+
+	/* Settings will be re-config at AUDIO_SET_CONFIG,
+	 * but at least we need to have initial config
+	 */
+	audio->samp_rate = RPC_AUD_DEF_SAMPLE_RATE_8000,
+	audio->samp_rate_index = AUDREC_CMD_SAMP_RATE_INDX_8000;
+	audio->channel_mode = AUDREC_CMD_STEREO_MODE_MONO;
+	if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)
+		audio->buffer_size = (EVRC_FRAME_SIZE + 14);
+	else
+		audio->buffer_size = EVRC_FRAME_SIZE;
+	audio->enc_type = AUDREC_CMD_TYPE_0_INDEX_EVRC | audio->mode;
+
+	audio->cfg.cdma_rate = CDMA_RATE_FULL;
+	audio->cfg.min_bit_rate = CDMA_RATE_FULL;
+	audio->cfg.max_bit_rate = CDMA_RATE_FULL;
+
+	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+		rc = audmgr_open(&audio->audmgr);
+		if (rc)
+			goto done;
+	}
+
+	encid = audpreproc_aenc_alloc(audio->enc_type, &audio->module_name,
+			&audio->queue_ids);
+	if (encid < 0) {
+		MM_ERR("No free encoder available\n");
+		rc = -ENODEV;
+		goto done;
+	}
+	audio->enc_id = encid;
+
+	rc = msm_adsp_get(audio->module_name, &audio->audrec,
+			   &audrec_evrc_adsp_ops, audio);
+	if (rc) {
+		audpreproc_aenc_free(audio->enc_id);
+		goto done;
+	}
+
+	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+		rc = msm_adsp_get("AUDPREPROCTASK", &audio->audpre,
+				&audpre_evrc_adsp_ops, audio);
+		if (rc) {
+			msm_adsp_put(audio->audrec);
+			audpreproc_aenc_free(audio->enc_id);
+			goto done;
+		}
+	}
+
+	audio->dsp_cnt = 0;
+	audio->stopped = 0;
+	audio->wflush = 0;
+	audio->rflush = 0;
+	audio->flush_ack = 0;
+
+	audevrc_in_flush(audio);
+	audevrc_out_flush(audio);
+
+	audio->phys = allocate_contiguous_ebi_nomap(dma_size, SZ_4K);
+	if (!audio->phys) {
+		MM_ERR("could not allocate physical read buffers\n");
+		rc = -ENOMEM;
+		goto evt_error;
+	} else {
+		audio->map_v_read = ioremap(audio->phys, dma_size);
+		if (IS_ERR(audio->map_v_read)) {
+			MM_ERR("could not map physical address\n");
+			rc = -ENOMEM;
+			free_contiguous_memory_by_paddr(audio->phys);
+			goto evt_error;
+		}
+		audio->data = audio->map_v_read;
+		MM_DBG("read buf: phy addr 0x%08x kernel addr 0x%08x\n",
+				audio->phys, (int)audio->data);
+	}
+	audio->out_data = NULL;
+	if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
+		audio->out_phys = allocate_contiguous_ebi_nomap(BUFFER_SIZE,
+						SZ_4K);
+		if (!audio->out_phys) {
+			MM_ERR("could not allocate physical write buffers\n");
+			rc = -ENOMEM;
+			iounmap(audio->map_v_read);
+			free_contiguous_memory_by_paddr(audio->phys);
+			goto evt_error;
+		} else {
+			audio->map_v_write = ioremap(
+						audio->out_phys, BUFFER_SIZE);
+
+			if (IS_ERR(audio->map_v_write)) {
+				MM_ERR("could not map write phys address\n");
+				rc = -ENOMEM;
+				iounmap(audio->map_v_read);
+				free_contiguous_memory_by_paddr(audio->phys);
+				free_contiguous_memory_by_paddr(\
+							audio->out_phys);
+				goto evt_error;
+			}
+			audio->out_data = audio->map_v_write;
+			MM_DBG("wr buf: phy addr 0x%08x kernel addr 0x%08x\n",
+					audio->out_phys, (int)audio->out_data);
+		}
+
+		/* Initialize buffer */
+		audio->out[0].data = audio->out_data + 0;
+		audio->out[0].addr = audio->out_phys + 0;
+		audio->out[0].size = OUT_BUFFER_SIZE;
+
+		audio->out[1].data = audio->out_data + OUT_BUFFER_SIZE;
+		audio->out[1].addr = audio->out_phys + OUT_BUFFER_SIZE;
+		audio->out[1].size = OUT_BUFFER_SIZE;
+
+		MM_DBG("audio->out[0].data = %d  audio->out[1].data = %d",
+				(unsigned int)audio->out[0].data,
+				(unsigned int)audio->out[1].data);
+		audio->mfield = NT_FRAME_HEADER_SIZE;
+		audio->out_frame_cnt++;
+	}
+	file->private_data = audio;
+	audio->opened = 1;
+
+done:
+	mutex_unlock(&audio->lock);
+	return rc;
+evt_error:
+	msm_adsp_put(audio->audrec);
+	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
+		msm_adsp_put(audio->audpre);
+
+	audpreproc_aenc_free(audio->enc_id);
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static const struct file_operations audio_evrc_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audevrc_in_open,
+	.release	= audevrc_in_release,
+	.read		= audevrc_in_read,
+	.write		= audevrc_in_write,
+	.fsync		= audevrc_in_fsync,
+	.unlocked_ioctl	= audevrc_in_ioctl,
+};
+
+static struct miscdevice audevrc_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_evrc_in",
+	.fops	= &audio_evrc_in_fops,
+};
+
+static int __init audevrc_in_init(void)
+{
+	mutex_init(&the_audio_evrc_in.lock);
+	mutex_init(&the_audio_evrc_in.read_lock);
+	spin_lock_init(&the_audio_evrc_in.dsp_lock);
+	init_waitqueue_head(&the_audio_evrc_in.wait);
+	init_waitqueue_head(&the_audio_evrc_in.wait_enable);
+	mutex_init(&the_audio_evrc_in.write_lock);
+	init_waitqueue_head(&the_audio_evrc_in.write_wait);
+	return misc_register(&audevrc_in_misc);
+}
+device_initcall(audevrc_in_init);
diff --git a/arch/arm/mach-msm/qdsp5/audio_fm.c b/arch/arm/mach-msm/qdsp5/audio_fm.c
new file mode 100644
index 0000000..2ab7cad
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_fm.c
@@ -0,0 +1,169 @@
+/* arch/arm/mach-msm/qdsp5/audio_fm.c
+ *
+ * pcm audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2011, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/msm_audio.h>
+#include <mach/debug_mm.h>
+
+#include "audmgr.h"
+
+struct audio {
+	struct mutex lock;
+	int opened;
+	int enabled;
+	int running;
+	struct audmgr audmgr;
+	uint16_t volume;
+};
+
+static struct audio fm_audio;
+
+/* must be called with audio->lock held */
+static int audio_enable(struct audio *audio)
+{
+	struct audmgr_config cfg;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	if (audio->enabled)
+		return 0;
+
+	cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;
+	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;
+	cfg.def_method = RPC_AUD_DEF_METHOD_HOST_PCM;
+	cfg.codec = RPC_AUD_DEF_CODEC_PCM;
+	cfg.snd_method = RPC_SND_METHOD_VOICE;
+
+	rc = audmgr_enable(&audio->audmgr, &cfg);
+	if (rc < 0)
+		return rc;
+
+	audio->enabled = 1;
+	return rc;
+}
+
+/* must be called with audio->lock held */
+static int audio_disable(struct audio *audio)
+{
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audmgr_disable(&audio->audmgr);
+	}
+	return 0;
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = -EINVAL;
+
+	MM_DBG("cmd %d", cmd);
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		MM_DBG("AUDIO_START\n");
+		rc = audio_enable(audio);
+		break;
+	case AUDIO_STOP:
+		MM_DBG("AUDIO_STOP\n");
+		rc = audio_disable(audio);
+		audio->running = 0;
+		audio->enabled = 0;
+		break;
+
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	MM_DBG("audio instance 0x%08x freeing\n", (int)audio);
+	mutex_lock(&audio->lock);
+	audio_disable(audio);
+	audio->running = 0;
+	audio->enabled = 0;
+	audio->opened = 0;
+	mutex_unlock(&audio->lock);
+	return 0;
+}
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = &fm_audio;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	mutex_lock(&audio->lock);
+
+	if (audio->opened) {
+		MM_ERR("busy\n");
+		rc = -EBUSY;
+		goto done;
+	}
+
+	rc = audmgr_open(&audio->audmgr);
+
+	if (rc) {
+		MM_ERR("%s: failed to register listnet\n", __func__);
+		goto done;
+	}
+
+	file->private_data = audio;
+	audio->opened = 1;
+
+done:
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static const struct file_operations audio_fm_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audio_open,
+	.release	= audio_release,
+	.unlocked_ioctl	= audio_ioctl,
+};
+
+struct miscdevice audio_fm_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_fm",
+	.fops	= &audio_fm_fops,
+};
+
+static int __init audio_init(void)
+{
+	struct audio *audio = &fm_audio;
+
+	mutex_init(&audio->lock);
+	return misc_register(&audio_fm_misc);
+}
+
+device_initcall(audio_init);
+
+MODULE_DESCRIPTION("MSM FM driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5/audio_in.c b/arch/arm/mach-msm/qdsp5/audio_in.c
new file mode 100644
index 0000000..6fc5d6b
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_in.c
@@ -0,0 +1,996 @@
+/* arch/arm/mach-msm/qdsp5/audio_in.c
+ *
+ * pcm audio input device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2009, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/delay.h>
+
+#include <linux/msm_audio_aac.h>
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <mach/msm_adsp.h>
+#include <mach/msm_rpcrouter.h>
+
+#include "audmgr.h"
+
+#include <mach/qdsp5/qdsp5audpreproccmdi.h>
+#include <mach/qdsp5/qdsp5audpreprocmsg.h>
+#include <mach/qdsp5/qdsp5audreccmdi.h>
+#include <mach/qdsp5/qdsp5audrecmsg.h>
+#include <mach/debug_mm.h>
+
+/* FRAME_NUM must be a power of two */
+#define FRAME_NUM		(8)
+#define FRAME_SIZE		(2052 * 2)
+#define MONO_DATA_SIZE		(2048)
+#define STEREO_DATA_SIZE	(MONO_DATA_SIZE * 2)
+#define DMASZ 			(FRAME_SIZE * FRAME_NUM)
+
+struct buffer {
+	void *data;
+	uint32_t size;
+	uint32_t read;
+	uint32_t addr;
+};
+
+struct audio_in {
+	struct buffer in[FRAME_NUM];
+
+	spinlock_t dsp_lock;
+
+	atomic_t in_bytes;
+
+	struct mutex lock;
+	struct mutex read_lock;
+	wait_queue_head_t wait;
+
+	struct msm_adsp_module *audpre;
+	struct msm_adsp_module *audrec;
+
+	/* configuration to use on next enable */
+	uint32_t samp_rate;
+	uint32_t channel_mode;
+	uint32_t buffer_size; /* 2048 for mono, 4096 for stereo */
+	uint32_t type; /* 0 for PCM ,1 for AAC */
+	uint32_t bit_rate; /* bit rate for AAC */
+	uint32_t record_quality; /* record quality (bits/sample/channel)
+				    for AAC*/
+	uint32_t buffer_cfg_ioctl; /* to allow any one of buffer set ioctl */
+	uint32_t dsp_cnt;
+	uint32_t in_head; /* next buffer dsp will write */
+	uint32_t in_tail; /* next buffer read() will read */
+	uint32_t in_count; /* number of buffers available to read() */
+
+	unsigned short samp_rate_index;
+
+	struct audmgr audmgr;
+
+	/* data allocated for various buffers */
+	char *data;
+	dma_addr_t phys;
+
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+
+	/* audpre settings */
+	int tx_agc_enable;
+	audpreproc_cmd_cfg_agc_params tx_agc_cfg;
+	int ns_enable;
+	audpreproc_cmd_cfg_ns_params ns_cfg;
+	/* For different sample rate, the coeff might be different. *
+	 * All the coeff should be passed from user space	    */
+	int iir_enable;
+	audpreproc_cmd_cfg_iir_tuning_filter_params iir_cfg;
+};
+
+static int audio_in_dsp_enable(struct audio_in *audio, int enable);
+static int audio_in_encoder_config(struct audio_in *audio);
+static int audio_dsp_read_buffer(struct audio_in *audio, uint32_t read_cnt);
+static void audio_flush(struct audio_in *audio);
+static int audio_dsp_set_tx_agc(struct audio_in *audio);
+static int audio_dsp_set_ns(struct audio_in *audio);
+static int audio_dsp_set_iir(struct audio_in *audio);
+
+static unsigned convert_dsp_samp_index(unsigned index)
+{
+	switch (index) {
+	case 48000:	return AUDREC_CMD_SAMP_RATE_INDX_48000;
+	case 44100:	return AUDREC_CMD_SAMP_RATE_INDX_44100;
+	case 32000:	return AUDREC_CMD_SAMP_RATE_INDX_32000;
+	case 24000:	return AUDREC_CMD_SAMP_RATE_INDX_24000;
+	case 22050:	return AUDREC_CMD_SAMP_RATE_INDX_22050;
+	case 16000:	return AUDREC_CMD_SAMP_RATE_INDX_16000;
+	case 12000:	return AUDREC_CMD_SAMP_RATE_INDX_12000;
+	case 11025:	return AUDREC_CMD_SAMP_RATE_INDX_11025;
+	case 8000:	return AUDREC_CMD_SAMP_RATE_INDX_8000;
+	default: 	return AUDREC_CMD_SAMP_RATE_INDX_11025;
+	}
+}
+
+static unsigned convert_samp_rate(unsigned hz)
+{
+	switch (hz) {
+	case 48000: return RPC_AUD_DEF_SAMPLE_RATE_48000;
+	case 44100: return RPC_AUD_DEF_SAMPLE_RATE_44100;
+	case 32000: return RPC_AUD_DEF_SAMPLE_RATE_32000;
+	case 24000: return RPC_AUD_DEF_SAMPLE_RATE_24000;
+	case 22050: return RPC_AUD_DEF_SAMPLE_RATE_22050;
+	case 16000: return RPC_AUD_DEF_SAMPLE_RATE_16000;
+	case 12000: return RPC_AUD_DEF_SAMPLE_RATE_12000;
+	case 11025: return RPC_AUD_DEF_SAMPLE_RATE_11025;
+	case 8000:  return RPC_AUD_DEF_SAMPLE_RATE_8000;
+	default:    return RPC_AUD_DEF_SAMPLE_RATE_11025;
+	}
+}
+
+static unsigned convert_samp_index(unsigned index)
+{
+	switch (index) {
+	case RPC_AUD_DEF_SAMPLE_RATE_48000:	return 48000;
+	case RPC_AUD_DEF_SAMPLE_RATE_44100:	return 44100;
+	case RPC_AUD_DEF_SAMPLE_RATE_32000:	return 32000;
+	case RPC_AUD_DEF_SAMPLE_RATE_24000:	return 24000;
+	case RPC_AUD_DEF_SAMPLE_RATE_22050:	return 22050;
+	case RPC_AUD_DEF_SAMPLE_RATE_16000:	return 16000;
+	case RPC_AUD_DEF_SAMPLE_RATE_12000:	return 12000;
+	case RPC_AUD_DEF_SAMPLE_RATE_11025:	return 11025;
+	case RPC_AUD_DEF_SAMPLE_RATE_8000:	return 8000;
+	default: 				return 11025;
+	}
+}
+
+/* must be called with audio->lock held */
+static int audio_in_enable(struct audio_in *audio)
+{
+	struct audmgr_config cfg;
+	int rc;
+
+	if (audio->enabled)
+		return 0;
+
+	cfg.tx_rate = audio->samp_rate;
+	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+	cfg.def_method = RPC_AUD_DEF_METHOD_RECORD;
+	if (audio->type == AUDREC_CMD_TYPE_0_INDEX_WAV)
+		cfg.codec = RPC_AUD_DEF_CODEC_PCM;
+	else
+		cfg.codec = RPC_AUD_DEF_CODEC_AAC;
+	cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+	rc = audmgr_enable(&audio->audmgr, &cfg);
+	if (rc < 0)
+		return rc;
+
+	if (msm_adsp_enable(audio->audpre)) {
+		MM_ERR("msm_adsp_enable(audpre) failed\n");
+		return -ENODEV;
+	}
+	if (msm_adsp_enable(audio->audrec)) {
+		MM_ERR("msm_adsp_enable(audrec) failed\n");
+		return -ENODEV;
+	}
+
+	audio->enabled = 1;
+	audio_in_dsp_enable(audio, 1);
+
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audio_in_disable(struct audio_in *audio)
+{
+	if (audio->enabled) {
+		audio->enabled = 0;
+
+		audio_in_dsp_enable(audio, 0);
+
+		wake_up(&audio->wait);
+
+		msm_adsp_disable(audio->audrec);
+		msm_adsp_disable(audio->audpre);
+		audmgr_disable(&audio->audmgr);
+	}
+	return 0;
+}
+
+/* ------------------- dsp --------------------- */
+static void audpre_dsp_event(void *data, unsigned id, size_t len,
+			    void (*getevent)(void *ptr, size_t len))
+{
+	uint16_t msg[2];
+	getevent(msg, sizeof(msg));
+
+	switch (id) {
+	case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
+		MM_INFO("type %d, status_flag %d\n", msg[0], msg[1]);
+		break;
+	case AUDPREPROC_MSG_ERROR_MSG_ID:
+		MM_INFO("err_index %d\n", msg[0]);
+		break;
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audpreproctask)\n");
+		break;
+	default:
+		MM_ERR("unknown event %d\n", id);
+	}
+}
+
+struct audio_frame {
+	uint16_t count_low;
+	uint16_t count_high;
+	uint16_t bytes;
+	uint16_t unknown;
+	unsigned char samples[];
+} __attribute__((packed));
+
+static void audio_in_get_dsp_frames(struct audio_in *audio)
+{
+	struct audio_frame *frame;
+	uint32_t index;
+	unsigned long flags;
+
+		index = audio->in_head;
+
+		/* XXX check for bogus frame size? */
+
+		frame = (void *) (((char *)audio->in[index].data) -
+				 sizeof(*frame));
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->in[index].size = frame->bytes;
+
+		audio->in_head = (audio->in_head + 1) & (FRAME_NUM - 1);
+
+		/* If overflow, move the tail index foward. */
+		if (audio->in_head == audio->in_tail)
+			audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
+		else
+			audio->in_count++;
+
+		audio_dsp_read_buffer(audio, audio->dsp_cnt++);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+
+		wake_up(&audio->wait);
+}
+
+static void audrec_dsp_event(void *data, unsigned id, size_t len,
+			    void (*getevent)(void *ptr, size_t len))
+{
+	struct audio_in *audio = data;
+	uint16_t msg[3];
+	getevent(msg, sizeof(msg));
+
+	switch (id) {
+	case AUDREC_MSG_CMD_CFG_DONE_MSG:
+		if (msg[0] & AUDREC_MSG_CFG_DONE_TYPE_0_UPDATE) {
+			if (msg[0] & AUDREC_MSG_CFG_DONE_TYPE_0_ENA) {
+				MM_INFO("CFG ENABLED\n");
+				audio_in_encoder_config(audio);
+			} else {
+				MM_INFO("CFG SLEEP\n");
+				audio->running = 0;
+				audio->tx_agc_enable = 0;
+				audio->ns_enable = 0;
+				audio->iir_enable = 0;
+			}
+		} else {
+			MM_INFO("CMD_CFG_DONE %x\n", msg[0]);
+		}
+		break;
+	case AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG: {
+		MM_INFO("PARAM CFG DONE\n");
+		audio->running = 1;
+		audio_dsp_set_tx_agc(audio);
+		audio_dsp_set_ns(audio);
+		audio_dsp_set_iir(audio);
+		break;
+	}
+	case AUDREC_MSG_FATAL_ERR_MSG:
+		MM_ERR("ERROR %x\n", msg[0]);
+		break;
+	case AUDREC_MSG_PACKET_READY_MSG:
+/* REC_DBG("type %x, count %d", msg[0], (msg[1] | (msg[2] << 16))); */
+		audio_in_get_dsp_frames(audio);
+		break;
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module \
+				enable/disable(audrectask)\n");
+		break;
+	default:
+		MM_ERR("unknown event %d\n", id);
+	}
+}
+
+struct msm_adsp_ops audpre_adsp_ops = {
+	.event = audpre_dsp_event,
+};
+
+struct msm_adsp_ops audrec_adsp_ops = {
+	.event = audrec_dsp_event,
+};
+
+
+#define audio_send_queue_pre(audio, cmd, len) \
+	msm_adsp_write(audio->audpre, QDSP_uPAudPreProcCmdQueue, cmd, len)
+#define audio_send_queue_recbs(audio, cmd, len) \
+	msm_adsp_write(audio->audrec, QDSP_uPAudRecBitStreamQueue, cmd, len)
+#define audio_send_queue_rec(audio, cmd, len) \
+	msm_adsp_write(audio->audrec, \
+	QDSP_uPAudRecCmdQueue, cmd, len)
+
+/* Convert Bit Rate to Record Quality field of DSP */
+static unsigned int bitrate_to_record_quality(unsigned int sample_rate,
+    unsigned int channel, unsigned int bit_rate) {
+	unsigned int temp;
+
+	temp = sample_rate * channel;
+	MM_DBG(" sample rate *  channel = %d \n", temp);
+	/* To represent in Q12 fixed format */
+	temp = (bit_rate * 4096) / temp;
+	MM_DBG(" Record Quality = 0x%8x \n", temp);
+	return temp;
+}
+
+static int audio_dsp_set_tx_agc(struct audio_in *audio)
+{
+	audpreproc_cmd_cfg_agc_params cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	audio->tx_agc_cfg.cmd_id = AUDPREPROC_CMD_CFG_AGC_PARAMS;
+	if (audio->tx_agc_enable) {
+		/* cmd.tx_agc_param_mask = 0xFE00 from sample code */
+		audio->tx_agc_cfg.tx_agc_param_mask =
+		(1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_SLOPE) |
+		(1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_TH) |
+		(1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_EXP_SLOPE) |
+		(1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_EXP_TH) |
+		(1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_AIG_FLAG) |
+		(1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_STATIC_GAIN) |
+		(1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_TX_AGC_ENA_FLAG);
+		audio->tx_agc_cfg.tx_agc_enable_flag =
+			AUDPREPROC_CMD_TX_AGC_ENA_FLAG_ENA;
+		/* cmd.param_mask = 0xFFF0 from sample code */
+		audio->tx_agc_cfg.param_mask =
+			(1 << AUDPREPROC_CMD_PARAM_MASK_RMS_TAY) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_RELEASEK) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_DELAY) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_ATTACKK) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_LEAKRATE_SLOW) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_LEAKRATE_FAST) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_AIG_RELEASEK) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_AIG_MIN) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_AIG_MAX) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_LEAK_UP) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_LEAK_DOWN) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_AIG_ATTACKK);
+	} else {
+		audio->tx_agc_cfg.tx_agc_param_mask =
+			(1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_TX_AGC_ENA_FLAG);
+		audio->tx_agc_cfg.tx_agc_enable_flag =
+			AUDPREPROC_CMD_TX_AGC_ENA_FLAG_DIS;
+	}
+	cmd = audio->tx_agc_cfg;
+
+	return audio_send_queue_pre(audio, &cmd, sizeof(cmd));
+}
+
+static int audio_enable_tx_agc(struct audio_in *audio, int enable)
+{
+	if (audio->tx_agc_enable != enable) {
+		audio->tx_agc_enable = enable;
+		if (audio->running)
+			audio_dsp_set_tx_agc(audio);
+	}
+	return 0;
+}
+
+static int audio_dsp_set_ns(struct audio_in *audio)
+{
+	audpreproc_cmd_cfg_ns_params cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	audio->ns_cfg.cmd_id = AUDPREPROC_CMD_CFG_NS_PARAMS;
+
+	if (audio->ns_enable) {
+		/* cmd.ec_mode_new is fixed as 0x0064 when enable
+		 * from sample code */
+		audio->ns_cfg.ec_mode_new =
+			AUDPREPROC_CMD_EC_MODE_NEW_NS_ENA |
+			AUDPREPROC_CMD_EC_MODE_NEW_HB_ENA |
+			AUDPREPROC_CMD_EC_MODE_NEW_VA_ENA;
+	} else {
+		audio->ns_cfg.ec_mode_new =
+			AUDPREPROC_CMD_EC_MODE_NEW_NLMS_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_DES_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_NS_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_CNI_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_NLES_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_HB_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_VA_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_PCD_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_FEHI_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_NEHI_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_NLPP_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_FNE_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_PRENLMS_DIS;
+	}
+	cmd = audio->ns_cfg;
+
+	return audio_send_queue_pre(audio, &cmd, sizeof(cmd));
+}
+
+static int audio_enable_ns(struct audio_in *audio, int enable)
+{
+	if (audio->ns_enable != enable) {
+		audio->ns_enable = enable;
+		if (audio->running)
+			audio_dsp_set_ns(audio);
+	}
+	return 0;
+}
+
+static int audio_dsp_set_iir(struct audio_in *audio)
+{
+	audpreproc_cmd_cfg_iir_tuning_filter_params cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	audio->iir_cfg.cmd_id = AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS;
+
+	if (audio->iir_enable)
+		/* cmd.active_flag is 0xFFFF from sample code but 0x0001 here */
+		audio->iir_cfg.active_flag = AUDPREPROC_CMD_IIR_ACTIVE_FLAG_ENA;
+	else
+		audio->iir_cfg.active_flag = AUDPREPROC_CMD_IIR_ACTIVE_FLAG_DIS;
+
+	cmd = audio->iir_cfg;
+
+	return audio_send_queue_pre(audio, &cmd, sizeof(cmd));
+}
+
+static int audio_enable_iir(struct audio_in *audio, int enable)
+{
+	if (audio->iir_enable != enable) {
+		audio->iir_enable = enable;
+		if (audio->running)
+			audio_dsp_set_iir(audio);
+	}
+	return 0;
+}
+
+static int audio_in_dsp_enable(struct audio_in *audio, int enable)
+{
+	audrec_cmd_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_CFG;
+	cmd.type_0 = enable ? AUDREC_CMD_TYPE_0_ENA : AUDREC_CMD_TYPE_0_DIS;
+	cmd.type_0 |= (AUDREC_CMD_TYPE_0_UPDATE | audio->type);
+	cmd.type_1 = 0;
+
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static int audio_in_encoder_config(struct audio_in *audio)
+{
+	audrec_cmd_arec0param_cfg cmd;
+	uint16_t *data = (void *) audio->data;
+	unsigned n;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_AREC0PARAM_CFG;
+	cmd.ptr_to_extpkt_buffer_msw = audio->phys >> 16;
+	cmd.ptr_to_extpkt_buffer_lsw = audio->phys;
+	cmd.buf_len = FRAME_NUM; /* Both WAV and AAC use 8 frames */
+	cmd.samp_rate_index = audio->samp_rate_index;
+	cmd.stereo_mode = audio->channel_mode; /* 0 for mono, 1 for stereo */
+
+	/* cmd.rec_quality is based on user set bit rate / sample rate /
+	 * channel
+	 */
+	cmd.rec_quality = audio->record_quality;
+
+	/* prepare buffer pointers:
+	 * Mono: 1024 samples + 4 halfword header
+	 * Stereo: 2048 samples + 4 halfword header
+	 * AAC
+	 * Mono/Stere: 768 + 4 halfword header
+	 */
+	for (n = 0; n < FRAME_NUM; n++) {
+		audio->in[n].data = data + 4;
+		if (audio->type == AUDREC_CMD_TYPE_0_INDEX_WAV)
+			data += (4 + (audio->channel_mode ? 2048 : 1024));
+		else if (audio->type == AUDREC_CMD_TYPE_0_INDEX_AAC)
+			data += (4 + 768);
+	}
+
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static int audio_dsp_read_buffer(struct audio_in *audio, uint32_t read_cnt)
+{
+	audrec_cmd_packet_ext_ptr cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_PACKET_EXT_PTR;
+	/* Both WAV and AAC use AUDREC_CMD_TYPE_0 */
+	cmd.type = AUDREC_CMD_TYPE_0;
+	cmd.curr_rec_count_msw = read_cnt >> 16;
+	cmd.curr_rec_count_lsw = read_cnt;
+
+	return audio_send_queue_recbs(audio, &cmd, sizeof(cmd));
+}
+
+/* ------------------- device --------------------- */
+
+static void audio_flush(struct audio_in *audio)
+{
+	int i;
+
+	audio->dsp_cnt = 0;
+	audio->in_head = 0;
+	audio->in_tail = 0;
+	audio->in_count = 0;
+	for (i = 0; i < FRAME_NUM; i++) {
+		audio->in[i].size = 0;
+		audio->in[i].read = 0;
+	}
+}
+
+static long audio_in_ioctl(struct file *file,
+				unsigned int cmd, unsigned long arg)
+{
+	struct audio_in *audio = file->private_data;
+	int rc;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = atomic_read(&audio->in_bytes);
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		rc = audio_in_enable(audio);
+		break;
+	case AUDIO_STOP:
+		rc = audio_in_disable(audio);
+		audio->stopped = 1;
+		break;
+	case AUDIO_FLUSH:
+		if (audio->stopped) {
+			/* Make sure we're stopped and we wake any threads
+			 * that might be blocked holding the read_lock.
+			 * While audio->stopped read threads will always
+			 * exit immediately.
+			 */
+			wake_up(&audio->wait);
+			mutex_lock(&audio->read_lock);
+			audio_flush(audio);
+			mutex_unlock(&audio->read_lock);
+		}
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config cfg;
+		/* The below code is to make mutual exclusive between
+		 * AUDIO_SET_CONFIG and AUDIO_SET_STREAM_CONFIG.
+		 * Allow any one IOCTL.
+		 */
+		if (audio->buffer_cfg_ioctl == AUDIO_SET_STREAM_CONFIG) {
+			rc = -EINVAL;
+			break;
+		}
+		if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (cfg.channel_count == 1) {
+			cfg.channel_count = AUDREC_CMD_STEREO_MODE_MONO;
+		} else if (cfg.channel_count == 2) {
+			cfg.channel_count = AUDREC_CMD_STEREO_MODE_STEREO;
+		} else {
+			rc = -EINVAL;
+			break;
+		}
+
+		if (cfg.type == 0) {
+			cfg.type = AUDREC_CMD_TYPE_0_INDEX_WAV;
+		} else if (cfg.type == 1) {
+			cfg.type = AUDREC_CMD_TYPE_0_INDEX_AAC;
+		} else {
+			rc = -EINVAL;
+			break;
+		}
+		audio->samp_rate = convert_samp_rate(cfg.sample_rate);
+		audio->samp_rate_index =
+		  convert_dsp_samp_index(cfg.sample_rate);
+		audio->channel_mode = cfg.channel_count;
+		audio->buffer_size =
+				audio->channel_mode ? STEREO_DATA_SIZE
+							: MONO_DATA_SIZE;
+		audio->type = cfg.type;
+		audio->buffer_cfg_ioctl = AUDIO_SET_CONFIG;
+		rc = 0;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config cfg;
+		cfg.buffer_size = audio->buffer_size;
+		cfg.buffer_count = FRAME_NUM;
+		cfg.sample_rate = convert_samp_index(audio->samp_rate);
+		if (audio->channel_mode == AUDREC_CMD_STEREO_MODE_MONO)
+			cfg.channel_count = 1;
+		else
+			cfg.channel_count = 2;
+		if (audio->type == AUDREC_CMD_TYPE_0_INDEX_WAV)
+			cfg.type = 0;
+		else
+			cfg.type = 1;
+		cfg.unused[0] = 0;
+		cfg.unused[1] = 0;
+		cfg.unused[2] = 0;
+		if (copy_to_user((void *) arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	}
+	case AUDIO_GET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		cfg.buffer_size = audio->buffer_size;
+		cfg.buffer_count = FRAME_NUM;
+		if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	}
+	case AUDIO_SET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		/* The below code is to make mutual exclusive between
+		 * AUDIO_SET_CONFIG and AUDIO_SET_STREAM_CONFIG.
+		 * Allow any one IOCTL.
+		 */
+		if (audio->buffer_cfg_ioctl == AUDIO_SET_CONFIG) {
+			rc = -EINVAL;
+			break;
+		}
+		if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		} else
+			rc = 0;
+		audio->buffer_size = cfg.buffer_size;
+		/* The IOCTL is only of AAC, set the encoder as AAC */
+		audio->type = 1;
+		audio->buffer_cfg_ioctl = AUDIO_SET_STREAM_CONFIG;
+		break;
+	}
+	case AUDIO_GET_AAC_ENC_CONFIG: {
+		struct msm_audio_aac_enc_config cfg;
+		if (audio->channel_mode == AUDREC_CMD_STEREO_MODE_MONO)
+			cfg.channels = 1;
+		else
+			cfg.channels = 2;
+		cfg.sample_rate = convert_samp_index(audio->samp_rate);
+		cfg.bit_rate = audio->bit_rate;
+		cfg.stream_format = AUDIO_AAC_FORMAT_RAW;
+		if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	}
+	case AUDIO_SET_AAC_ENC_CONFIG: {
+		struct msm_audio_aac_enc_config cfg;
+		unsigned int record_quality;
+		if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (cfg.stream_format != AUDIO_AAC_FORMAT_RAW) {
+			MM_ERR("unsupported AAC format\n");
+			rc = -EINVAL;
+			break;
+		}
+		record_quality = bitrate_to_record_quality(cfg.sample_rate,
+					cfg.channels, cfg.bit_rate);
+		/* Range of Record Quality Supported by DSP, Q12 format */
+		if ((record_quality < 0x800) || (record_quality > 0x4000)) {
+			MM_ERR("Unsupported bit rate \n");
+			rc = -EINVAL;
+			break;
+		}
+		if (cfg.channels == 1) {
+			cfg.channels = AUDREC_CMD_STEREO_MODE_MONO;
+		} else if (cfg.channels == 2) {
+			cfg.channels = AUDREC_CMD_STEREO_MODE_STEREO;
+		} else {
+			rc = -EINVAL;
+			break;
+		}
+		audio->samp_rate = convert_samp_rate(cfg.sample_rate);
+		audio->samp_rate_index =
+		  convert_dsp_samp_index(cfg.sample_rate);
+		audio->channel_mode = cfg.channels;
+		audio->bit_rate = cfg.bit_rate;
+		audio->record_quality = record_quality;
+		MM_DBG(" Record Quality = 0x%8x \n", audio->record_quality);
+		rc = 0;
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static ssize_t audio_in_read(struct file *file,
+				char __user *buf,
+				size_t count, loff_t *pos)
+{
+	struct audio_in *audio = file->private_data;
+	unsigned long flags;
+	const char __user *start = buf;
+	void *data;
+	uint32_t index;
+	uint32_t size;
+	int rc = 0;
+
+	mutex_lock(&audio->read_lock);
+	while (count > 0) {
+		rc = wait_event_interruptible(
+			audio->wait, (audio->in_count > 0) || audio->stopped);
+		if (rc < 0)
+			break;
+
+		if (audio->stopped && !audio->in_count) {
+			rc = 0;/* End of File */
+			break;
+		}
+
+		index = audio->in_tail;
+		data = (uint8_t *) audio->in[index].data;
+		size = audio->in[index].size;
+		if (count >= size) {
+			/* order the reads on the buffer */
+			dma_coherent_post_ops();
+			if (copy_to_user(buf, data, size)) {
+				rc = -EFAULT;
+				break;
+			}
+			spin_lock_irqsave(&audio->dsp_lock, flags);
+			if (index != audio->in_tail) {
+			/* overrun -- data is invalid and we need to retry */
+				spin_unlock_irqrestore(&audio->dsp_lock, flags);
+				continue;
+			}
+			audio->in[index].size = 0;
+			audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
+			audio->in_count--;
+			spin_unlock_irqrestore(&audio->dsp_lock, flags);
+			count -= size;
+			buf += size;
+		} else {
+			MM_ERR("short read\n");
+			break;
+		}
+		if (audio->type == AUDREC_CMD_TYPE_0_INDEX_AAC)
+			break; /* AAC only read one frame */
+	}
+	mutex_unlock(&audio->read_lock);
+
+	if (buf > start)
+		return buf - start;
+
+	return rc;
+}
+
+static ssize_t audio_in_write(struct file *file,
+				const char __user *buf,
+				size_t count, loff_t *pos)
+{
+	return -EINVAL;
+}
+
+static int audio_in_release(struct inode *inode, struct file *file)
+{
+	struct audio_in *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	audio_in_disable(audio);
+	audio_flush(audio);
+	msm_adsp_put(audio->audrec);
+	msm_adsp_put(audio->audpre);
+	audio->audrec = NULL;
+	audio->audpre = NULL;
+	audio->opened = 0;
+	mutex_unlock(&audio->lock);
+	return 0;
+}
+
+struct audio_in the_audio_in;
+
+static int audio_in_open(struct inode *inode, struct file *file)
+{
+	struct audio_in *audio = &the_audio_in;
+	int rc;
+
+	mutex_lock(&audio->lock);
+	if (audio->opened) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	/* Settings will be re-config at AUDIO_SET_CONFIG,
+	 * but at least we need to have initial config
+	 */
+	audio->samp_rate = RPC_AUD_DEF_SAMPLE_RATE_11025;
+	audio->samp_rate_index = AUDREC_CMD_SAMP_RATE_INDX_11025;
+	audio->channel_mode = AUDREC_CMD_STEREO_MODE_MONO;
+	audio->buffer_size = MONO_DATA_SIZE;
+	audio->type = AUDREC_CMD_TYPE_0_INDEX_WAV;
+
+	/* For AAC, bit rate hard coded, default settings is
+	 * sample rate (11025) x channel count (1) x recording quality (1.75)
+	 * = 19293 bps  */
+	audio->bit_rate = 19293;
+	audio->record_quality = 0x1c00;
+
+	rc = audmgr_open(&audio->audmgr);
+	if (rc)
+		goto done;
+	rc = msm_adsp_get("AUDPREPROCTASK", &audio->audpre,
+				&audpre_adsp_ops, audio);
+	if (rc)
+		goto done;
+	rc = msm_adsp_get("AUDRECTASK", &audio->audrec,
+			   &audrec_adsp_ops, audio);
+	if (rc)
+		goto done;
+
+	audio->dsp_cnt = 0;
+	audio->stopped = 0;
+	audio->buffer_cfg_ioctl = 0; /* No valid ioctl set */
+
+	audio_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+	rc = 0;
+done:
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static long audpre_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct audio_in *audio = file->private_data;
+	int rc = 0, enable;
+	uint16_t enable_mask;
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_ENABLE_AUDPRE:
+		if (copy_from_user(&enable_mask, (void *) arg,
+						sizeof(enable_mask))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		enable = (enable_mask & AGC_ENABLE) ? 1 : 0;
+		audio_enable_tx_agc(audio, enable);
+		enable = (enable_mask & NS_ENABLE) ? 1 : 0;
+		audio_enable_ns(audio, enable);
+		enable = (enable_mask & TX_IIR_ENABLE) ? 1 : 0;
+		audio_enable_iir(audio, enable);
+		break;
+
+	case AUDIO_SET_AGC:
+		if (copy_from_user(&audio->tx_agc_cfg, (void *) arg,
+						sizeof(audio->tx_agc_cfg)))
+			rc = -EFAULT;
+		break;
+
+	case AUDIO_SET_NS:
+		if (copy_from_user(&audio->ns_cfg, (void *) arg,
+						sizeof(audio->ns_cfg)))
+			rc = -EFAULT;
+		break;
+
+	case AUDIO_SET_TX_IIR:
+		if (copy_from_user(&audio->iir_cfg, (void *) arg,
+						sizeof(audio->iir_cfg)))
+			rc = -EFAULT;
+		break;
+
+	default:
+		rc = -EINVAL;
+	}
+
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static int audpre_open(struct inode *inode, struct file *file)
+{
+	struct audio_in *audio = &the_audio_in;
+
+	file->private_data = audio;
+
+	return 0;
+}
+
+static struct file_operations audio_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audio_in_open,
+	.release	= audio_in_release,
+	.read		= audio_in_read,
+	.write		= audio_in_write,
+	.unlocked_ioctl	= audio_in_ioctl,
+};
+
+struct miscdevice audio_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_pcm_in",
+	.fops	= &audio_fops,
+};
+
+static const struct file_operations audpre_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audpre_open,
+	.unlocked_ioctl	= audpre_ioctl,
+};
+
+struct miscdevice audpre_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_preproc_ctl",
+	.fops	= &audpre_fops,
+};
+
+static int __init audio_in_init(void)
+{
+	the_audio_in.data = dma_alloc_coherent(NULL, DMASZ,
+					       &the_audio_in.phys, GFP_KERNEL);
+	if (!the_audio_in.data) {
+		MM_ERR("Unable to allocate DMA buffer\n");
+		return -ENOMEM;
+	}
+
+	mutex_init(&the_audio_in.lock);
+	mutex_init(&the_audio_in.read_lock);
+	spin_lock_init(&the_audio_in.dsp_lock);
+	init_waitqueue_head(&the_audio_in.wait);
+	return misc_register(&audio_in_misc) || misc_register(&audpre_misc);
+}
+
+device_initcall(audio_in_init);
diff --git a/arch/arm/mach-msm/qdsp5/audio_lpa.c b/arch/arm/mach-msm/qdsp5/audio_lpa.c
new file mode 100644
index 0000000..8754337
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_lpa.c
@@ -0,0 +1,1487 @@
+
+/* audio_lpa.c - low power audio driver
+ *
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * Based on the PCM decoder driver in arch/arm/mach-msm/qdsp5/audio_pcm.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/earlysuspend.h>
+#include <linux/list.h>
+#include <linux/android_pmem.h>
+#include <linux/slab.h>
+#include <linux/msm_audio.h>
+
+
+#include <mach/msm_adsp.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audplaycmdi.h>
+#include <mach/qdsp5/qdsp5audplaymsg.h>
+#include <mach/qdsp5/qdsp5rmtcmdi.h>
+#include <mach/debug_mm.h>
+#include <linux/memory_alloc.h>
+#include <mach/msm_memtypes.h>
+
+#include "audmgr.h"
+
+/* for queue ids - should be relative to module number*/
+#include "adsp.h"
+
+#define ADRV_STATUS_AIO_INTF 0x00000001
+#define ADRV_STATUS_OBUF_GIVEN 0x00000002
+#define ADRV_STATUS_IBUF_GIVEN 0x00000004
+#define ADRV_STATUS_FSYNC 0x00000008
+
+#define MSM_MAX_VOLUME 0x2000
+/* 17 added to avoid more deviation */
+#define MSM_VOLUME_STEP (MSM_MAX_VOLUME+17)
+#define MSM_VOLUME_FACTOR (10000)
+
+/* Size must be power of 2 */
+#define MAX_BUF 2
+#define BUFSZ (524288)
+
+#define AUDDEC_DEC_PCM 0
+
+/* Decoder status received from AUDPPTASK */
+#define  AUDPP_DEC_STATUS_SLEEP	0
+#define  AUDPP_DEC_STATUS_INIT  1
+#define  AUDPP_DEC_STATUS_CFG   2
+#define  AUDPP_DEC_STATUS_PLAY  3
+
+#define AUDPCM_EVENT_NUM 10 /* Default number of pre-allocated event packets */
+
+#define __CONTAINS(r, v, l) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __v = v;					\
+	typeof(v) __e = __v + l;				\
+	int res = ((__v >= __r->vaddr) &&			\
+		(__e <= __r->vaddr + __r->len));		\
+	res;							\
+})
+
+#define CONTAINS(r1, r2) ({					\
+	typeof(r2) __r2 = r2;					\
+	__CONTAINS(r1, __r2->vaddr, __r2->len);			\
+})
+
+#define IN_RANGE(r, v) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __vv = v;					\
+	int res = ((__vv >= __r->vaddr) &&			\
+		(__vv < (__r->vaddr + __r->len)));		\
+	res;							\
+})
+
+#define OVERLAPS(r1, r2) ({					\
+	typeof(r1) __r1 = r1;					\
+	typeof(r2) __r2 = r2;					\
+	typeof(__r2->vaddr) __v = __r2->vaddr;			\
+	typeof(__v) __e = __v + __r2->len - 1;			\
+	int res = (IN_RANGE(__r1, __v) || IN_RANGE(__r1, __e));	\
+	res;							\
+})
+
+struct audio;
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct audpcm_suspend_ctl {
+struct early_suspend node;
+struct audio *audio;
+};
+#endif
+
+struct audpcm_event {
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+
+struct audlpa_pmem_region {
+	struct list_head list;
+	struct file *file;
+	int fd;
+	void *vaddr;
+	unsigned long paddr;
+	unsigned long kvaddr;
+	unsigned long len;
+	unsigned ref_cnt;
+};
+
+struct audpcm_buffer_node {
+	struct list_head list;
+	struct msm_audio_aio_buf buf;
+	unsigned long paddr;
+};
+
+struct audio {
+	struct buffer out[2];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed; /* number of buffers the dsp is waiting for */
+	struct list_head out_queue; /* queue to retain output buffers */
+	atomic_t out_bytes;
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	struct msm_adsp_module *audplay;
+
+	/* configuration to use on next enable */
+	uint32_t out_sample_rate;
+	uint32_t out_channel_mode;
+	uint32_t out_bits; /* bits per sample */
+
+	struct audmgr audmgr;
+
+	/* data allocated for various buffers */
+	char *data;
+	int32_t phys;
+	struct msm_mapped_buffer *map_v_write;
+
+	uint32_t drv_status;
+	int wflush; /* Write flush */
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+	int teos; /* valid only if tunnel mode & no data left for decoder */
+	int rmt_resource_released;
+	enum msm_aud_decoder_state dec_state; /* Represents decoder state */
+	int reserved; /* A byte is being reserved */
+	char rsv_byte; /* Handle odd length user data */
+
+	const char *module_name;
+	unsigned queue_id;
+
+	unsigned long volume;
+
+	uint16_t dec_id;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct audpcm_suspend_ctl suspend_ctl;
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+	wait_queue_head_t wait;
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	wait_queue_head_t event_wait;
+	spinlock_t event_queue_lock;
+	struct mutex get_event_lock;
+	int event_abort;
+
+	struct list_head pmem_region_queue;
+	int buffer_count;
+	int buffer_size;
+};
+
+static int auddec_dsp_config(struct audio *audio, int enable);
+static void audpp_cmd_cfg_adec_params(struct audio *audio);
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
+static void audpcm_post_event(struct audio *audio, int type,
+	union msm_audio_event_payload payload);
+static unsigned long audlpa_pmem_fixup(struct audio *audio, void *addr,
+	unsigned long len, int ref_up);
+static void audpcm_async_send_data(struct audio *audio,
+	unsigned needed);
+
+
+static int rmt_put_resource(struct audio *audio)
+{
+	struct aud_codec_config_cmd cmd;
+	unsigned short client_idx;
+
+	cmd.cmd_id = RM_CMD_AUD_CODEC_CFG;
+	cmd.client_id = RM_AUD_CLIENT_ID;
+	cmd.task_id = audio->dec_id;
+	cmd.enable = RMT_DISABLE;
+	cmd.dec_type = AUDDEC_DEC_PCM;
+	client_idx = ((cmd.client_id << 8) | cmd.task_id);
+
+	return put_adsp_resource(client_idx, &cmd, sizeof(cmd));
+}
+
+static int rmt_get_resource(struct audio *audio)
+{
+	struct aud_codec_config_cmd cmd;
+	unsigned short client_idx;
+
+	cmd.cmd_id = RM_CMD_AUD_CODEC_CFG;
+	cmd.client_id = RM_AUD_CLIENT_ID;
+	cmd.task_id = audio->dec_id;
+	cmd.enable = RMT_ENABLE;
+	cmd.dec_type = AUDDEC_DEC_PCM;
+	client_idx = ((cmd.client_id << 8) | cmd.task_id);
+
+	return get_adsp_resource(client_idx, &cmd, sizeof(cmd));
+}
+
+/* must be called with audio->lock held */
+static int audio_enable(struct audio *audio)
+{
+	struct audmgr_config cfg;
+	int rc;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled)
+		return 0;
+
+	if (audio->rmt_resource_released == 1) {
+		audio->rmt_resource_released = 0;
+		rc = rmt_get_resource(audio);
+		if (rc)
+			MM_ERR("ADSP resources are not available");
+	}
+
+	audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;
+	cfg.def_method = RPC_AUD_DEF_METHOD_PLAYBACK;
+	cfg.codec = RPC_AUD_DEF_CODEC_PCM;
+	cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+	rc = audmgr_enable(&audio->audmgr, &cfg);
+	if (rc < 0)
+		return rc;
+
+	if (msm_adsp_enable(audio->audplay)) {
+		MM_ERR("msm_adsp_enable(audplay) failed\n");
+		audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+
+	if (audpp_enable(audio->dec_id, audio_dsp_event, audio)) {
+		MM_ERR("audpp_enable() failed\n");
+		msm_adsp_disable(audio->audplay);
+		audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+
+	audio->enabled = 1;
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audio_disable(struct audio *audio)
+{
+	int rc = 0;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+		auddec_dsp_config(audio, 0);
+		rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+		else if (audio->dec_state != MSM_AUD_DECODER_STATE_CLOSE)
+			rc = -EFAULT;
+		else
+			rc = 0;
+		audio->stopped = 1;
+		wake_up(&audio->write_wait);
+		msm_adsp_disable(audio->audplay);
+		audpp_disable(audio->dec_id, audio);
+		audmgr_disable(&audio->audmgr);
+		audio->out_needed = 0;
+		rmt_put_resource(audio);
+		audio->rmt_resource_released = 1;
+	}
+	return rc;
+}
+
+/* ------------------- dsp --------------------- */
+static void audplay_dsp_event(void *data, unsigned id, size_t len,
+			      void (*getevent) (void *ptr, size_t len))
+{
+	struct audio *audio = data;
+	uint32_t msg[28];
+	getevent(msg, sizeof(msg));
+
+	MM_DBG("msg_id=%x\n", id);
+
+	switch (id) {
+	case AUDPLAY_MSG_DEC_NEEDS_DATA:
+		audpcm_async_send_data(audio, 1);
+		break;
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audplaytask)\n");
+		break;
+	default:
+		MM_ERR("unexpected message from decoder\n");
+		break;
+	}
+}
+
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned status = msg[1];
+
+			switch (status) {
+			case AUDPP_DEC_STATUS_SLEEP: {
+				uint16_t reason = msg[2];
+				MM_DBG("decoder status: sleep reason =0x%04x\n",
+						reason);
+				if ((reason == AUDPP_MSG_REASON_MEM)
+						|| (reason ==
+						AUDPP_MSG_REASON_NODECODER)) {
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_FAILURE;
+					wake_up(&audio->wait);
+				} else if (reason == AUDPP_MSG_REASON_NONE) {
+					/* decoder is in disable state */
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_CLOSE;
+					wake_up(&audio->wait);
+				}
+				break;
+			}
+			case AUDPP_DEC_STATUS_INIT:
+				MM_DBG("decoder status: init\n");
+				audpp_cmd_cfg_adec_params(audio);
+				break;
+
+			case AUDPP_DEC_STATUS_CFG:
+				MM_DBG("decoder status: cfg\n");
+				break;
+			case AUDPP_DEC_STATUS_PLAY:
+				MM_DBG("decoder status: play\n");
+				audio->dec_state =
+					MSM_AUD_DECODER_STATE_SUCCESS;
+				wake_up(&audio->wait);
+				break;
+			default:
+				MM_ERR("unknown decoder status\n");
+				break;
+			}
+			break;
+		}
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			MM_DBG("CFG_MSG ENABLE\n");
+			auddec_dsp_config(audio, 1);
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_set_volume_and_pan(audio->dec_id, audio->volume,
+					0);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			MM_DBG("CFG_MSG DISABLE\n");
+			audio->running = 0;
+		} else {
+			MM_ERR("CFG_MSG %d?\n",	msg[0]);
+		}
+		break;
+	case AUDPP_MSG_FLUSH_ACK:
+		MM_DBG("FLUSH_ACK\n");
+		audio->wflush = 0;
+		wake_up(&audio->write_wait);
+		break;
+
+	case AUDPP_MSG_PCMDMAMISSED:
+		MM_DBG("PCMDMAMISSED\n");
+		audio->teos = 1;
+		wake_up(&audio->write_wait);
+		break;
+
+	default:
+		MM_ERR("UNKNOWN (%d)\n", id);
+	}
+
+}
+
+
+struct msm_adsp_ops audlpadec_adsp_ops = {
+	.event = audplay_dsp_event,
+};
+
+
+#define audplay_send_queue0(audio, cmd, len) \
+	msm_adsp_write(audio->audplay, audio->queue_id, \
+			cmd, len)
+
+static int auddec_dsp_config(struct audio *audio, int enable)
+{
+	u16 cfg_dec_cmd[AUDPP_CMD_CFG_DEC_TYPE_LEN / sizeof(unsigned short)];
+
+	memset(cfg_dec_cmd, 0, sizeof(cfg_dec_cmd));
+
+	cfg_dec_cmd[0] = AUDPP_CMD_CFG_DEC_TYPE;
+	if (enable)
+		cfg_dec_cmd[1 + audio->dec_id] = AUDPP_CMD_UPDATDE_CFG_DEC |
+				AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_PCM;
+	else
+		cfg_dec_cmd[1 + audio->dec_id] = AUDPP_CMD_UPDATDE_CFG_DEC |
+				AUDPP_CMD_DIS_DEC_V;
+
+	return audpp_send_queue1(&cfg_dec_cmd, sizeof(cfg_dec_cmd));
+}
+
+static void audpp_cmd_cfg_adec_params(struct audio *audio)
+{
+	audpp_cmd_cfg_adec_params_wav cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_WAV_LEN;
+	cmd.common.dec_id = audio->dec_id;
+	cmd.common.input_sampling_frequency = audio->out_sample_rate;
+	cmd.stereo_cfg = audio->out_channel_mode;
+	cmd.pcm_width = audio->out_bits;
+	cmd.sign = 0;
+	audpp_send_queue2(&cmd, sizeof(cmd));
+}
+static void audpcm_async_send_data(struct audio *audio, unsigned needed)
+{
+	unsigned long flags;
+
+	if (!audio->running)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+
+	if (needed && !audio->wflush) {
+		audio->out_needed = 1;
+		if (audio->drv_status & ADRV_STATUS_OBUF_GIVEN) {
+			/* pop one node out of queue */
+			union msm_audio_event_payload payload;
+			struct audpcm_buffer_node *used_buf;
+
+			MM_DBG("consumed\n");
+
+			BUG_ON(list_empty(&audio->out_queue));
+			used_buf = list_first_entry(&audio->out_queue,
+				struct audpcm_buffer_node, list);
+			list_del(&used_buf->list);
+			payload.aio_buf = used_buf->buf;
+			audpcm_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+				payload);
+			kfree(used_buf);
+			audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
+		}
+	}
+	if (audio->out_needed) {
+		struct audpcm_buffer_node *next_buf;
+		audplay_cmd_bitstream_data_avail cmd;
+		if (!list_empty(&audio->out_queue)) {
+			next_buf = list_first_entry(&audio->out_queue,
+					struct audpcm_buffer_node, list);
+			MM_DBG("next_buf %p\n", next_buf);
+			if (next_buf) {
+				MM_DBG("next buf phy %lx len %d\n",
+				next_buf->paddr, next_buf->buf.data_len);
+
+				cmd.cmd_id = AUDPLAY_CMD_BITSTREAM_DATA_AVAIL;
+				if (next_buf->buf.data_len)
+					cmd.decoder_id = audio->dec_id;
+				else {
+					cmd.decoder_id = -1;
+					MM_DBG("input EOS signaled\n");
+				}
+				cmd.buf_ptr	= (unsigned) next_buf->paddr;
+				cmd.buf_size = next_buf->buf.data_len >> 1;
+				cmd.partition_number	= 0;
+				/* complete writes to the input buffer */
+				wmb();
+				audplay_send_queue0(audio, &cmd, sizeof(cmd));
+				audio->out_needed = 0;
+				audio->drv_status |= ADRV_STATUS_OBUF_GIVEN;
+			}
+		}
+	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+static void audpcm_async_flush(struct audio *audio)
+{
+	struct audpcm_buffer_node *buf_node;
+	struct list_head *ptr, *next;
+	union msm_audio_event_payload payload;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	list_for_each_safe(ptr, next, &audio->out_queue) {
+		buf_node = list_entry(ptr, struct audpcm_buffer_node, list);
+		list_del(&buf_node->list);
+		payload.aio_buf = buf_node->buf;
+		audpcm_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+				payload);
+		kfree(buf_node);
+	}
+	audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
+	audio->out_needed = 0;
+	atomic_set(&audio->out_bytes, 0);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+static void audio_ioport_reset(struct audio *audio)
+{
+	if (audio->drv_status & ADRV_STATUS_AIO_INTF) {
+		/* If fsync is in progress, make sure
+		 * return value of fsync indicates
+		 * abort due to flush
+		 */
+		if (audio->drv_status & ADRV_STATUS_FSYNC) {
+			MM_DBG("fsync in progress\n");
+			wake_up(&audio->write_wait);
+			mutex_lock(&audio->write_lock);
+			audpcm_async_flush(audio);
+			mutex_unlock(&audio->write_lock);
+		} else
+			audpcm_async_flush(audio);
+	} else {
+		/* Make sure read/write thread are free from
+		 * sleep and knowing that system is not able
+		 * to process io request at the moment
+		 */
+		wake_up(&audio->write_wait);
+		mutex_lock(&audio->write_lock);
+		audpcm_async_flush(audio);
+		mutex_unlock(&audio->write_lock);
+	}
+}
+
+static int audpcm_events_pending(struct audio *audio)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	return empty || audio->event_abort;
+}
+
+static void audpcm_reset_event_queue(struct audio *audio)
+{
+	unsigned long flags;
+	struct audpcm_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+			struct audpcm_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+			struct audpcm_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	return;
+}
+
+static long audpcm_process_event_req(struct audio *audio, void __user *arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audpcm_event *drv_evt = NULL;
+	int timeout;
+	unsigned long flags;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int) usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(
+			audio->event_wait, audpcm_events_pending(audio),
+			msecs_to_jiffies(timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(
+			audio->event_wait, audpcm_events_pending(audio));
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+			struct audpcm_event, list);
+		list_del(&drv_evt->list);
+	}
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else
+		rc = -1;
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	if (drv_evt && drv_evt->event_type == AUDIO_EVENT_WRITE_DONE) {
+		mutex_lock(&audio->lock);
+		audlpa_pmem_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+				  drv_evt->payload.aio_buf.buf_len, 0);
+		mutex_unlock(&audio->lock);
+	}
+	if (!rc && copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audlpa_pmem_check(struct audio *audio,
+		void *vaddr, unsigned long len)
+{
+	struct audlpa_pmem_region *region_elt;
+	struct audlpa_pmem_region t = { .vaddr = vaddr, .len = len };
+
+	list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+		if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
+		    OVERLAPS(region_elt, &t)) {
+			MM_ERR("region (vaddr %p len %ld)"
+				" clashes with registered region"
+				" (vaddr %p paddr %p len %ld)\n",
+				vaddr, len,
+				region_elt->vaddr,
+				(void *)region_elt->paddr,
+				region_elt->len);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int audlpa_pmem_add(struct audio *audio,
+	struct msm_audio_pmem_info *info)
+{
+	unsigned long paddr, kvaddr, len;
+	struct file *file;
+	struct audlpa_pmem_region *region;
+	int rc = -EINVAL;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	region = kmalloc(sizeof(*region), GFP_KERNEL);
+
+	if (!region) {
+		rc = -ENOMEM;
+		goto end;
+	}
+
+	if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) {
+		kfree(region);
+		goto end;
+	}
+
+	rc = audlpa_pmem_check(audio, info->vaddr, len);
+	if (rc < 0) {
+		put_pmem_file(file);
+		kfree(region);
+		goto end;
+	}
+
+	region->vaddr = info->vaddr;
+	region->fd = info->fd;
+	region->paddr = paddr;
+	region->kvaddr = kvaddr;
+	region->len = len;
+	region->file = file;
+	region->ref_cnt = 0;
+	MM_DBG("add region paddr %lx vaddr %p, len %lu\n", region->paddr,
+			region->vaddr, region->len);
+	list_add_tail(&region->list, &audio->pmem_region_queue);
+end:
+	return rc;
+}
+
+static int audlpa_pmem_remove(struct audio *audio,
+	struct msm_audio_pmem_info *info)
+{
+	struct audlpa_pmem_region *region;
+	struct list_head *ptr, *next;
+	int rc = -EINVAL;
+
+	MM_DBG("info fd %d vaddr %p\n", info->fd, info->vaddr);
+
+	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
+		region = list_entry(ptr, struct audlpa_pmem_region, list);
+
+		if ((region->fd == info->fd) &&
+		    (region->vaddr == info->vaddr)) {
+			if (region->ref_cnt) {
+				MM_DBG("region %p in use ref_cnt %d\n",
+						region, region->ref_cnt);
+				break;
+			}
+			MM_DBG("remove region fd %d vaddr %p\n",
+				info->fd, info->vaddr);
+			list_del(&region->list);
+			put_pmem_file(region->file);
+			kfree(region);
+			rc = 0;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static int audlpa_pmem_lookup_vaddr(struct audio *audio, void *addr,
+		     unsigned long len, struct audlpa_pmem_region **region)
+{
+	struct audlpa_pmem_region *region_elt;
+
+	int match_count = 0;
+
+	*region = NULL;
+
+	/* returns physical address or zero */
+	list_for_each_entry(region_elt, &audio->pmem_region_queue,
+		list) {
+		if (addr >= region_elt->vaddr &&
+		    addr < region_elt->vaddr + region_elt->len &&
+		    addr + len <= region_elt->vaddr + region_elt->len) {
+			/* offset since we could pass vaddr inside a registerd
+			 * pmem buffer
+			 */
+
+			match_count++;
+			if (!*region)
+				*region = region_elt;
+		}
+	}
+
+	if (match_count > 1) {
+		MM_ERR("multiple hits for vaddr %p, len %ld\n", addr, len);
+		list_for_each_entry(region_elt,
+		  &audio->pmem_region_queue, list) {
+			if (addr >= region_elt->vaddr &&
+			    addr < region_elt->vaddr + region_elt->len &&
+			    addr + len <= region_elt->vaddr + region_elt->len)
+				MM_ERR("\t%p, %ld --> %p\n", region_elt->vaddr,
+						region_elt->len,
+						(void *)region_elt->paddr);
+		}
+	}
+
+	return *region ? 0 : -1;
+}
+
+unsigned long audlpa_pmem_fixup(struct audio *audio, void *addr,
+		    unsigned long len, int ref_up)
+{
+	struct audlpa_pmem_region *region;
+	unsigned long paddr;
+	int ret;
+
+	ret = audlpa_pmem_lookup_vaddr(audio, addr, len, &region);
+	if (ret) {
+		MM_ERR("lookup (%p, %ld) failed\n", addr, len);
+		return 0;
+	}
+	if (ref_up)
+		region->ref_cnt++;
+	else
+		region->ref_cnt--;
+	MM_DBG("found region %p ref_cnt %d\n", region, region->ref_cnt);
+	paddr = region->paddr + (addr - region->vaddr);
+	return paddr;
+}
+
+/* audio -> lock must be held at this point */
+static int audlpa_aio_buf_add(struct audio *audio, unsigned dir,
+	void __user *arg)
+{
+	unsigned long flags;
+	struct audpcm_buffer_node *buf_node;
+
+	buf_node = kmalloc(sizeof(*buf_node), GFP_KERNEL);
+
+	if (!buf_node)
+		return -ENOMEM;
+
+	if (copy_from_user(&buf_node->buf, arg, sizeof(buf_node->buf))) {
+		kfree(buf_node);
+		return -EFAULT;
+	}
+
+	MM_DBG("node %p dir %x buf_addr %p buf_len %d data_len"
+			"%d\n", buf_node, dir,
+			buf_node->buf.buf_addr, buf_node->buf.buf_len,
+			buf_node->buf.data_len);
+
+	buf_node->paddr = audlpa_pmem_fixup(
+		audio, buf_node->buf.buf_addr,
+		buf_node->buf.buf_len, 1);
+
+	if (dir) {
+		/* write */
+		if (!buf_node->paddr ||
+		    (buf_node->paddr & 0x1) ||
+		    (buf_node->buf.data_len & 0x1)) {
+			kfree(buf_node);
+			return -EINVAL;
+		}
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		list_add_tail(&buf_node->list, &audio->out_queue);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		audpcm_async_send_data(audio, 0);
+	}
+	MM_DBG("Add buf_node %p paddr %lx\n", buf_node, buf_node->paddr);
+
+	return 0;
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = 0;
+
+	MM_DBG("cmd = %d\n", cmd);
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = audpp_avsync_byte_count(audio->dec_id);
+		stats.sample_count = audpp_avsync_sample_count(audio->dec_id);
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+	if (cmd == AUDIO_SET_VOLUME) {
+		unsigned long flags;
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+
+		audio->volume = MSM_VOLUME_STEP * arg;
+		audio->volume /= MSM_VOLUME_FACTOR;
+
+		if (audio->volume > MSM_MAX_VOLUME)
+			audio->volume = MSM_MAX_VOLUME;
+
+		if (audio->running)
+			audpp_set_volume_and_pan(audio->dec_id,
+			audio->volume, 0);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		return 0;
+	}
+	if (cmd == AUDIO_GET_EVENT) {
+		MM_DBG("AUDIO_GET_EVENT\n");
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audpcm_process_event_req(audio,
+				(void __user *) arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		return rc;
+	}
+
+	if (cmd == AUDIO_ABORT_GET_EVENT) {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		MM_DBG("AUDIO_START\n");
+		rc = audio_enable(audio);
+		if (!rc) {
+			rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+			MM_INFO("dec_state %d rc = %d\n", audio->dec_state, rc);
+
+			if (audio->dec_state != MSM_AUD_DECODER_STATE_SUCCESS)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		break;
+	case AUDIO_STOP:
+		MM_DBG("AUDIO_STOP\n");
+		rc = audio_disable(audio);
+		audio_ioport_reset(audio);
+		audio->stopped = 0;
+		break;
+	case AUDIO_FLUSH:
+		MM_DBG("AUDIO_FLUSH\n");
+		audio->wflush = 1;
+		audio_ioport_reset(audio);
+		if (audio->running) {
+			audpp_flush(audio->dec_id);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->wflush = 0;
+		}
+		break;
+
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (copy_from_user(&config, (void *) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (config.channel_count == 1) {
+			config.channel_count = AUDPP_CMD_PCM_INTF_MONO_V;
+		} else if (config.channel_count == 2) {
+			config.channel_count = AUDPP_CMD_PCM_INTF_STEREO_V;
+		} else {
+			rc = -EINVAL;
+			break;
+		}
+		if (config.bits == 8)
+			config.bits = AUDPP_CMD_WAV_PCM_WIDTH_8;
+		else if (config.bits == 16)
+			config.bits = AUDPP_CMD_WAV_PCM_WIDTH_16;
+		else {
+			rc = -EINVAL;
+			break;
+		}
+		audio->out_sample_rate = config.sample_rate;
+		audio->out_channel_mode = config.channel_count;
+		audio->out_bits = config.bits;
+		audio->buffer_count = config.buffer_count;
+		audio->buffer_size = config.buffer_size;
+		MM_DBG("AUDIO_SET_CONFIG\n");
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_count = audio->buffer_count;
+		config.buffer_size = audio->buffer_size;
+		config.sample_rate = audio->out_sample_rate;
+		if (audio->out_channel_mode == AUDPP_CMD_PCM_INTF_MONO_V)
+			config.channel_count = 1;
+		else
+			config.channel_count = 2;
+		if (audio->out_bits == AUDPP_CMD_WAV_PCM_WIDTH_8)
+			config.bits = 8;
+		else if (audio->out_bits == AUDPP_CMD_WAV_PCM_WIDTH_16)
+			config.bits = 16;
+		else
+			config.bits = 16;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+
+		if (copy_to_user((void *) arg, &config, sizeof(config)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		MM_DBG("AUDIO_GET_CONFIG\n");
+		break;
+	}
+
+
+	case AUDIO_PAUSE:
+		MM_DBG("AUDIO_PAUSE %ld\n", arg);
+		rc = audpp_pause(audio->dec_id, (int) arg);
+		break;
+
+	case AUDIO_REGISTER_PMEM: {
+			struct msm_audio_pmem_info info;
+			MM_DBG("AUDIO_REGISTER_PMEM\n");
+			if (copy_from_user(&info, (void *) arg, sizeof(info)))
+				rc = -EFAULT;
+			else
+				rc = audlpa_pmem_add(audio, &info);
+			break;
+		}
+
+	case AUDIO_DEREGISTER_PMEM: {
+			struct msm_audio_pmem_info info;
+			MM_DBG("AUDIO_DEREGISTER_PMEM\n");
+			if (copy_from_user(&info, (void *) arg, sizeof(info)))
+				rc = -EFAULT;
+			else
+				rc = audlpa_pmem_remove(audio, &info);
+			break;
+		}
+
+	case AUDIO_ASYNC_WRITE:
+		if (audio->drv_status & ADRV_STATUS_FSYNC)
+			rc = -EBUSY;
+		else
+			rc = audlpa_aio_buf_add(audio, 1, (void __user *) arg);
+		break;
+
+	case AUDIO_ASYNC_READ:
+		MM_ERR("AUDIO_ASYNC_READ not supported\n");
+		rc = -EPERM;
+		break;
+
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+/* Only useful in tunnel-mode */
+int audlpa_async_fsync(struct audio *audio)
+{
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	/* Blocking client sends more data */
+	mutex_lock(&audio->lock);
+	audio->drv_status |= ADRV_STATUS_FSYNC;
+	mutex_unlock(&audio->lock);
+
+	mutex_lock(&audio->write_lock);
+	/* pcm dmamiss message is sent continously
+	 * when decoder is starved so no race
+	 * condition concern
+	 */
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->teos && audio->out_needed &&
+		list_empty(&audio->out_queue))
+		|| audio->wflush || audio->stopped);
+
+	if (audio->stopped || audio->wflush)
+		rc = -EBUSY;
+
+	mutex_unlock(&audio->write_lock);
+	mutex_lock(&audio->lock);
+	audio->drv_status &= ~ADRV_STATUS_FSYNC;
+	mutex_unlock(&audio->lock);
+
+	return rc;
+}
+
+int audlpa_sync_fsync(struct audio *audio)
+{
+	struct buffer *frame;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(!audio->out[0].used &&
+		!audio->out[1].used &&
+		audio->out_needed) || audio->wflush);
+
+	if (rc < 0)
+		goto done;
+	else if (audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (audio->reserved) {
+		MM_DBG("send reserved byte\n");
+		frame = audio->out + audio->out_tail;
+		((char *) frame->data)[0] = audio->rsv_byte;
+		((char *) frame->data)[1] = 0;
+		frame->used = 2;
+		audpcm_async_send_data(audio, 0);
+
+		rc = wait_event_interruptible(audio->write_wait,
+			(!audio->out[0].used &&
+			!audio->out[1].used &&
+			audio->out_needed) || audio->wflush);
+
+		if (rc < 0)
+			goto done;
+		else if (audio->wflush) {
+			rc = -EBUSY;
+			goto done;
+		}
+	}
+
+	/* pcm dmamiss message is sent continously
+	 * when decoder is starved so no race
+	 * condition concern
+	 */
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		audio->teos || audio->wflush);
+
+	if (audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+	return rc;
+}
+
+int audlpa_fsync(struct file *file, loff_t a, loff_t b, int datasync)
+{
+	struct audio *audio = file->private_data;
+
+	if (!audio->running)
+		return -EINVAL;
+
+	return audlpa_async_fsync(audio);
+}
+
+static void audpcm_reset_pmem_region(struct audio *audio)
+{
+	struct audlpa_pmem_region *region;
+	struct list_head *ptr, *next;
+
+	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
+		region = list_entry(ptr, struct audlpa_pmem_region, list);
+		list_del(&region->list);
+		put_pmem_file(region->file);
+		kfree(region);
+	}
+
+	return;
+}
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	MM_DBG("audio instance 0x%08x freeing\n", (int)audio);
+	mutex_lock(&audio->lock);
+	audio_disable(audio);
+	if (audio->rmt_resource_released == 0)
+		rmt_put_resource(audio);
+	audpcm_async_flush(audio);
+	audpcm_reset_pmem_region(audio);
+
+	msm_adsp_put(audio->audplay);
+	audpp_adec_free(audio->dec_id);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&audio->suspend_ctl.node);
+#endif
+	audio->opened = 0;
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audpcm_reset_event_queue(audio);
+	MM_DBG("pmem area = 0x%8x\n", (unsigned int)audio->data);
+	if (audio->data) {
+		iounmap(audio->map_v_write);
+		free_contiguous_memory_by_paddr(audio->phys);
+	}
+	mutex_unlock(&audio->lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio);
+	return 0;
+}
+
+static void audpcm_post_event(struct audio *audio, int type,
+	union msm_audio_event_payload payload)
+{
+	struct audpcm_event *e_node = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+			struct audpcm_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audpcm_event), GFP_ATOMIC);
+		if (!e_node) {
+			MM_ERR("No mem to post event %d\n", type);
+			spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	wake_up(&audio->event_wait);
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audpcm_suspend(struct early_suspend *h)
+{
+	struct audpcm_suspend_ctl *ctl =
+		container_of(h, struct audpcm_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audpcm_post_event(ctl->audio, AUDIO_EVENT_SUSPEND, payload);
+}
+
+static void audpcm_resume(struct early_suspend *h)
+{
+	struct audpcm_suspend_ctl *ctl =
+		container_of(h, struct audpcm_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audpcm_post_event(ctl->audio, AUDIO_EVENT_RESUME, payload);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audpcm_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audpcm_debug_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 4096;
+	static char buffer[4096];
+	int n = 0;
+	struct audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "enabled %d\n", audio->enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_buf_sz %d\n", audio->out[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "volume %lx\n", audio->volume);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "sample rate %d\n", audio->out_sample_rate);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		"channel mode %d\n", audio->out_channel_mode);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "running %d\n", audio->running);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				"dec state %d\n", audio->dec_state);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_needed %d\n", audio->out_needed);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_head %d\n", audio->out_head);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_tail %d\n", audio->out_tail);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out[0].used %d\n", audio->out[0].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out[1].used %d\n", audio->out[1].used);
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audpcm_debug_fops = {
+	.read = audpcm_debug_read,
+	.open = audpcm_debug_open,
+};
+#endif
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = NULL;
+	int rc, i, dec_attrb, decid;
+	struct audpcm_event *e_node = NULL;
+
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_lpa_" + 5];
+#endif
+
+	/* Allocate audio instance, set to zero */
+	audio = kzalloc(sizeof(struct audio), GFP_KERNEL);
+	if (!audio) {
+		MM_ERR("no memory to allocate audio instance\n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	MM_DBG("audio instance 0x%08x created\n", (int)audio);
+
+	/* Allocate the decoder */
+	dec_attrb = AUDDEC_DEC_PCM;
+	if (file->f_mode & FMODE_READ) {
+		MM_ERR("Non-Tunneled mode not supported\n");
+		rc = -EPERM;
+		kfree(audio);
+		goto done;
+	} else
+		dec_attrb |= MSM_AUD_MODE_TUNNEL;
+
+	decid = audpp_adec_alloc(dec_attrb, &audio->module_name,
+			&audio->queue_id);
+	if (decid < 0) {
+		MM_ERR("No free decoder available\n");
+		rc = -ENODEV;
+		MM_DBG("audio instance 0x%08x freeing\n", (int)audio);
+		kfree(audio);
+		goto done;
+	}
+	audio->dec_id = decid & MSM_AUD_DECODER_MASK;
+
+	audio->buffer_size = BUFSZ;
+	audio->buffer_count = MAX_BUF;
+	rc = audmgr_open(&audio->audmgr);
+	if (rc)
+		goto err;
+
+	rc = msm_adsp_get(audio->module_name, &audio->audplay,
+			&audlpadec_adsp_ops, audio);
+	if (rc) {
+		MM_ERR("failed to get %s module\n", audio->module_name);
+		audmgr_close(&audio->audmgr);
+		goto err;
+	}
+
+	rc = rmt_get_resource(audio);
+	if (rc) {
+		MM_ERR("ADSP resources are not available for PCM session");
+		audmgr_close(&audio->audmgr);
+		msm_adsp_put(audio->audplay);
+		goto err;
+	}
+
+	/* Initialize all locks of audio instance */
+	mutex_init(&audio->lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->get_event_lock);
+	spin_lock_init(&audio->dsp_lock);
+	init_waitqueue_head(&audio->write_wait);
+	INIT_LIST_HEAD(&audio->out_queue);
+	INIT_LIST_HEAD(&audio->pmem_region_queue);
+	INIT_LIST_HEAD(&audio->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+	init_waitqueue_head(&audio->wait);
+	init_waitqueue_head(&audio->event_wait);
+	spin_lock_init(&audio->event_queue_lock);
+
+	audio->out_sample_rate = 44100;
+	audio->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V;
+	audio->out_bits = AUDPP_CMD_WAV_PCM_WIDTH_16;
+	audio->volume = 0x2000;
+	audpcm_async_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_pcm_lp_dec_%04x", audio->dec_id);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+		NULL, (void *) audio, &audpcm_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		MM_DBG("debugfs_create_file failed\n");
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	audio->suspend_ctl.node.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+	audio->suspend_ctl.node.resume = audpcm_resume;
+	audio->suspend_ctl.node.suspend = audpcm_suspend;
+	audio->suspend_ctl.audio = audio;
+	register_early_suspend(&audio->suspend_ctl.node);
+#endif
+	for (i = 0; i < AUDPCM_EVENT_NUM; i++) {
+		e_node = kmalloc(sizeof(struct audpcm_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			MM_ERR("event pkt alloc failed\n");
+			break;
+		}
+	}
+done:
+	return rc;
+err:
+	audpp_adec_free(audio->dec_id);
+	MM_DBG("audio instance 0x%08x freeing\n", (int)audio);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_pcm_lp_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audio_open,
+	.release	= audio_release,
+	.unlocked_ioctl	= audio_ioctl,
+	.fsync = audlpa_fsync,
+};
+
+struct miscdevice audio_lpa_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_pcm_lp_dec",
+	.fops	= &audio_pcm_lp_fops,
+};
+
+static int __init audio_init(void)
+{
+	return misc_register(&audio_lpa_misc);
+}
+
+device_initcall(audio_init);
diff --git a/arch/arm/mach-msm/qdsp5/audio_mp3.c b/arch/arm/mach-msm/qdsp5/audio_mp3.c
new file mode 100644
index 0000000..9346107
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_mp3.c
@@ -0,0 +1,2360 @@
+/* arch/arm/mach-msm/qdsp5/audio_mp3.c
+ *
+ * mp3 audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2009-2012, Code Aurora Forum. 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.
+ *
+ */
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/earlysuspend.h>
+#include <linux/list.h>
+#include <linux/android_pmem.h>
+#include <linux/slab.h>
+#include <linux/msm_audio.h>
+#include <linux/memory_alloc.h>
+
+#include <mach/msm_adsp.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/msm_memtypes.h>
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audplaycmdi.h>
+#include <mach/qdsp5/qdsp5audplaymsg.h>
+#include <mach/qdsp5/qdsp5rmtcmdi.h>
+#include <mach/debug_mm.h>
+
+#include "audmgr.h"
+
+#define ADRV_STATUS_AIO_INTF 0x00000001
+#define ADRV_STATUS_OBUF_GIVEN 0x00000002
+#define ADRV_STATUS_IBUF_GIVEN 0x00000004
+#define ADRV_STATUS_FSYNC 0x00000008
+
+/* Size must be power of 2 */
+#define BUFSZ_MAX 32768
+#define BUFSZ_MIN 4096
+#define DMASZ_MAX (BUFSZ_MAX * 2)
+#define DMASZ_MIN (BUFSZ_MIN * 2)
+
+#define AUDPLAY_INVALID_READ_PTR_OFFSET	0xFFFF
+#define AUDDEC_DEC_MP3 2
+
+#define PCM_BUFSZ_MIN 4800	/* Hold one stereo MP3 frame */
+#define PCM_BUF_MAX_COUNT 5	/* DSP only accepts 5 buffers at most
+				   but support 2 buffers currently */
+#define ROUTING_MODE_FTRT 1
+#define ROUTING_MODE_RT 2
+/* Decoder status received from AUDPPTASK */
+#define  AUDPP_DEC_STATUS_SLEEP	0
+#define	 AUDPP_DEC_STATUS_INIT  1
+#define  AUDPP_DEC_STATUS_CFG   2
+#define  AUDPP_DEC_STATUS_PLAY  3
+
+#define AUDMP3_METAFIELD_MASK 0xFFFF0000
+#define AUDMP3_EOS_FLG_OFFSET 0x0A /* Offset from beginning of buffer */
+#define AUDMP3_EOS_FLG_MASK 0x01
+#define AUDMP3_EOS_NONE 0x0 /* No EOS detected */
+#define AUDMP3_EOS_SET 0x1 /* EOS set in meta field */
+
+#define AUDMP3_EVENT_NUM 10 /* Default number of pre-allocated event packets */
+
+#define __CONTAINS(r, v, l) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __v = v;					\
+	typeof(v) __e = __v + l;				\
+	int res = ((__v >= __r->vaddr) && 			\
+		(__e <= __r->vaddr + __r->len));		\
+	res;							\
+})
+
+#define CONTAINS(r1, r2) ({					\
+	typeof(r2) __r2 = r2;					\
+	__CONTAINS(r1, __r2->vaddr, __r2->len);			\
+})
+
+#define IN_RANGE(r, v) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __vv = v;					\
+	int res = ((__vv >= __r->vaddr) &&			\
+		(__vv < (__r->vaddr + __r->len)));		\
+	res;							\
+})
+
+#define OVERLAPS(r1, r2) ({					\
+	typeof(r1) __r1 = r1;					\
+	typeof(r2) __r2 = r2;					\
+	typeof(__r2->vaddr) __v = __r2->vaddr;			\
+	typeof(__v) __e = __v + __r2->len - 1;			\
+	int res = (IN_RANGE(__r1, __v) || IN_RANGE(__r1, __e));	\
+	res;							\
+})
+
+struct audio;
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+	unsigned short mfield_sz; /*only useful for data has meta field */
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct audmp3_suspend_ctl {
+  struct early_suspend node;
+  struct audio *audio;
+};
+#endif
+
+struct audmp3_event {
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+
+struct audmp3_pmem_region {
+	struct list_head list;
+	struct file *file;
+	int fd;
+	void *vaddr;
+	unsigned long paddr;
+	unsigned long kvaddr;
+	unsigned long len;
+	unsigned ref_cnt;
+};
+
+struct audmp3_buffer_node {
+	struct list_head list;
+	struct msm_audio_aio_buf buf;
+	unsigned long paddr;
+};
+
+struct audmp3_drv_operations {
+	void (*pcm_buf_update)(struct audio *, uint32_t *);
+	void (*buffer_refresh)(struct audio *);
+	void (*send_data)(struct audio *, unsigned);
+	void (*out_flush)(struct audio *);
+	void (*in_flush)(struct audio *);
+	int (*fsync)(struct audio *);
+};
+
+struct audio {
+	struct buffer out[2];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed; /* number of buffers the dsp is waiting for */
+	unsigned out_dma_sz;
+	struct list_head out_queue; /* queue to retain output buffers */
+	atomic_t out_bytes;
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	/* Host PCM section */
+	struct buffer in[PCM_BUF_MAX_COUNT];
+	struct mutex read_lock;
+	wait_queue_head_t read_wait;	/* Wait queue for read */
+	char *read_data;	/* pointer to reader buffer */
+	int32_t read_phys;	/* physical address of reader buffer */
+	uint8_t read_next;	/* index to input buffers to be read next */
+	uint8_t fill_next;	/* index to buffer that DSP should be filling */
+	uint8_t pcm_buf_count;	/* number of pcm buffer allocated */
+	struct list_head in_queue; /* queue to retain input buffers */
+	/* ---- End of Host PCM section */
+
+	struct msm_adsp_module *audplay;
+
+	/* configuration to use on next enable */
+	uint32_t out_sample_rate;
+	uint32_t out_channel_mode;
+
+	struct audmgr audmgr;
+
+	/* data allocated for various buffers */
+	char *data;
+	int32_t phys; /* physical address of write buffer */
+	void *map_v_read;
+	void *map_v_write;
+
+	uint32_t drv_status;
+	int mfield; /* meta field embedded in data */
+	int rflush; /* Read  flush */
+	int wflush; /* Write flush */
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+	int pcm_feedback;
+	int buf_refresh;
+	int rmt_resource_released;
+	int teos; /* valid only if tunnel mode & no data left for decoder */
+	enum msm_aud_decoder_state dec_state;	/* Represents decoder state */
+	int reserved; /* A byte is being reserved */
+	char rsv_byte; /* Handle odd length user data */
+
+	const char *module_name;
+	unsigned queue_id;
+	uint16_t dec_id;
+	uint32_t read_ptr_offset;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct audmp3_suspend_ctl suspend_ctl;
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+
+	wait_queue_head_t wait;
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	wait_queue_head_t event_wait;
+	spinlock_t event_queue_lock;
+	struct mutex get_event_lock;
+	int event_abort;
+
+	struct list_head pmem_region_queue; /* protected by lock */
+	struct audmp3_drv_operations drv_ops;
+
+	int eq_enable;
+	int eq_needs_commit;
+	audpp_cmd_cfg_object_params_eqalizer eq;
+	audpp_cmd_cfg_object_params_volume vol_pan;
+};
+
+static int auddec_dsp_config(struct audio *audio, int enable);
+static void audpp_cmd_cfg_adec_params(struct audio *audio);
+static void audpp_cmd_cfg_routing_mode(struct audio *audio);
+static void audplay_send_data(struct audio *audio, unsigned needed);
+static void audplay_config_hostpcm(struct audio *audio);
+static void audplay_buffer_refresh(struct audio *audio);
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
+static void audmp3_post_event(struct audio *audio, int type,
+	union msm_audio_event_payload payload);
+static unsigned long audmp3_pmem_fixup(struct audio *audio, void *addr,
+				unsigned long len, int ref_up);
+
+static int rmt_put_resource(struct audio *audio)
+{
+	struct aud_codec_config_cmd cmd;
+	unsigned short client_idx;
+
+	cmd.cmd_id = RM_CMD_AUD_CODEC_CFG;
+	cmd.client_id = RM_AUD_CLIENT_ID;
+	cmd.task_id = audio->dec_id;
+	cmd.enable = RMT_DISABLE;
+	cmd.dec_type = AUDDEC_DEC_MP3;
+	client_idx = ((cmd.client_id << 8) | cmd.task_id);
+
+	return put_adsp_resource(client_idx, &cmd, sizeof(cmd));
+}
+
+static int rmt_get_resource(struct audio *audio)
+{
+	struct aud_codec_config_cmd cmd;
+	unsigned short client_idx;
+
+	cmd.cmd_id = RM_CMD_AUD_CODEC_CFG;
+	cmd.client_id = RM_AUD_CLIENT_ID;
+	cmd.task_id = audio->dec_id;
+	cmd.enable = RMT_ENABLE;
+	cmd.dec_type = AUDDEC_DEC_MP3;
+	client_idx = ((cmd.client_id << 8) | cmd.task_id);
+
+	return get_adsp_resource(client_idx, &cmd, sizeof(cmd));
+}
+
+/* must be called with audio->lock held */
+static int audio_enable(struct audio *audio)
+{
+	struct audmgr_config cfg;
+	int rc;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	if (audio->enabled)
+		return 0;
+
+	if (audio->rmt_resource_released == 1) {
+		audio->rmt_resource_released = 0;
+		rc = rmt_get_resource(audio);
+		if (rc) {
+			MM_ERR("ADSP resources are not available for MP3 \
+				session 0x%08x on decoder: %d\n Ignoring \
+				error and going ahead with the playback\n",
+				(int)audio, audio->dec_id);
+		}
+	}
+
+	audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
+		cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+		cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;
+		cfg.def_method = RPC_AUD_DEF_METHOD_PLAYBACK;
+		cfg.codec = RPC_AUD_DEF_CODEC_MP3;
+		cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+		rc = audmgr_enable(&audio->audmgr, &cfg);
+		if (rc < 0)
+			return rc;
+	}
+
+	if (msm_adsp_enable(audio->audplay)) {
+		MM_ERR("msm_adsp_enable(audplay) failed\n");
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+
+	if (audpp_enable(audio->dec_id, audio_dsp_event, audio)) {
+		MM_ERR("audpp_enable() failed\n");
+		msm_adsp_disable(audio->audplay);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+
+	audio->enabled = 1;
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audio_disable(struct audio *audio)
+{
+	int rc = 0;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+		auddec_dsp_config(audio, 0);
+		rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+		else if (audio->dec_state != MSM_AUD_DECODER_STATE_CLOSE)
+			rc = -EFAULT;
+		else
+			rc = 0;
+		audio->stopped = 1;
+		wake_up(&audio->write_wait);
+		wake_up(&audio->read_wait);
+		msm_adsp_disable(audio->audplay);
+		audpp_disable(audio->dec_id, audio);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_disable(&audio->audmgr);
+		audio->out_needed = 0;
+		rmt_put_resource(audio);
+		audio->rmt_resource_released = 1;
+	}
+	return rc;
+}
+
+/* ------------------- dsp --------------------- */
+static void audmp3_async_pcm_buf_update(struct audio *audio, uint32_t *payload)
+{
+	unsigned long flags;
+	union msm_audio_event_payload event_payload;
+	struct audmp3_buffer_node *filled_buf;
+	uint8_t index;
+
+	if (audio->rflush)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < payload[1]; index++) {
+		BUG_ON(list_empty(&audio->in_queue));
+		filled_buf = list_first_entry(&audio->in_queue,
+					struct audmp3_buffer_node, list);
+		if (filled_buf->paddr == payload[2 + index * 2]) {
+			list_del(&filled_buf->list);
+			event_payload.aio_buf = filled_buf->buf;
+			event_payload.aio_buf.data_len =
+				payload[3 + index * 2];
+			MM_DBG("pcm buf %p data_len %d\n", filled_buf,
+					event_payload.aio_buf.data_len);
+			audmp3_post_event(audio, AUDIO_EVENT_READ_DONE,
+						event_payload);
+			kfree(filled_buf);
+		} else {
+			MM_ERR("expected=%lx ret=%x\n", filled_buf->paddr,
+					payload[2 + index * 2]);
+			break;
+		}
+	}
+
+	audio->drv_status &= ~ADRV_STATUS_IBUF_GIVEN;
+	audio->drv_ops.buffer_refresh(audio);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+
+}
+
+static void audio_update_pcm_buf_entry(struct audio *audio, uint32_t *payload)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	if (audio->rflush)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < payload[1]; index++) {
+		if (audio->in[audio->fill_next].addr ==
+		    payload[2 + index * 2]) {
+			MM_DBG("in[%d] ready\n", audio->fill_next);
+			audio->in[audio->fill_next].used =
+			  payload[3 + index * 2];
+			if ((++audio->fill_next) == audio->pcm_buf_count)
+				audio->fill_next = 0;
+
+		} else {
+			MM_ERR("expected=%x ret=%x\n",
+					audio->in[audio->fill_next].addr,
+					payload[2 + index * 2]);
+			break;
+		}
+	}
+	if (audio->in[audio->fill_next].used == 0) {
+		audio->drv_ops.buffer_refresh(audio);
+	} else {
+		MM_DBG("read cannot keep up\n");
+		audio->buf_refresh = 1;
+	}
+	wake_up(&audio->read_wait);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+
+}
+
+static void audplay_dsp_event(void *data, unsigned id, size_t len,
+			      void (*getevent) (void *ptr, size_t len))
+{
+	struct audio *audio = data;
+	uint32_t msg[28];
+	getevent(msg, sizeof(msg));
+
+	MM_DBG("msg_id=%x\n", id);
+
+	switch (id) {
+	case AUDPLAY_MSG_DEC_NEEDS_DATA:
+		audio->drv_ops.send_data(audio, 1);
+		break;
+
+	case AUDPLAY_MSG_BUFFER_UPDATE:
+		audio->drv_ops.pcm_buf_update(audio, msg);
+		break;
+
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audplaytask)\n");
+		break;
+
+	default:
+		MM_ERR("unexpected message from decoder \n");
+		break;
+	}
+}
+
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned status = msg[1];
+
+			switch (status) {
+			case AUDPP_DEC_STATUS_SLEEP: {
+				uint16_t reason = msg[2];
+				MM_DBG("decoder status: sleep reason=0x%04x\n",
+						reason);
+				if ((reason == AUDPP_MSG_REASON_MEM)
+					|| (reason ==
+					AUDPP_MSG_REASON_NODECODER)) {
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_FAILURE;
+					wake_up(&audio->wait);
+				} else if (reason == AUDPP_MSG_REASON_NONE) {
+					/* decoder is in disable state */
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_CLOSE;
+					wake_up(&audio->wait);
+				}
+				break;
+			}
+			case AUDPP_DEC_STATUS_INIT:
+				MM_DBG("decoder status: init \n");
+				if (audio->pcm_feedback)
+					audpp_cmd_cfg_routing_mode(audio);
+				else
+					audpp_cmd_cfg_adec_params(audio);
+				break;
+
+			case AUDPP_DEC_STATUS_CFG:
+				MM_DBG("decoder status: cfg \n");
+				break;
+			case AUDPP_DEC_STATUS_PLAY:
+				MM_DBG("decoder status: play \n");
+				if (audio->pcm_feedback) {
+					audplay_config_hostpcm(audio);
+					audio->drv_ops.buffer_refresh(audio);
+				}
+				audio->dec_state =
+					MSM_AUD_DECODER_STATE_SUCCESS;
+				wake_up(&audio->wait);
+				break;
+			default:
+				MM_ERR("unknown decoder status \n");
+				break;
+			}
+			break;
+		}
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			MM_DBG("CFG_MSG ENABLE\n");
+			auddec_dsp_config(audio, 1);
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+			audpp_dsp_set_eq(audio->dec_id, audio->eq_enable,
+								&audio->eq);
+			audpp_avsync(audio->dec_id, 22050);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			MM_DBG("CFG_MSG DISABLE\n");
+			audpp_avsync(audio->dec_id, 0);
+			audio->running = 0;
+		} else {
+			MM_DBG("CFG_MSG %d?\n", msg[0]);
+		}
+		break;
+	case AUDPP_MSG_ROUTING_ACK:
+		MM_DBG("ROUTING_ACK mode=%d\n",	msg[1]);
+		audpp_cmd_cfg_adec_params(audio);
+		break;
+
+	case AUDPP_MSG_FLUSH_ACK:
+		MM_DBG("FLUSH_ACK\n");
+		audio->wflush = 0;
+		audio->rflush = 0;
+		wake_up(&audio->write_wait);
+		if (audio->pcm_feedback)
+			audio->drv_ops.buffer_refresh(audio);
+		break;
+
+	case AUDPP_MSG_PCMDMAMISSED:
+		MM_DBG("PCMDMAMISSED\n");
+		audio->teos = 1;
+		wake_up(&audio->write_wait);
+		break;
+
+	default:
+		MM_ERR("UNKNOWN (%d)\n", id);
+	}
+
+}
+
+
+struct msm_adsp_ops audplay_adsp_ops = {
+	.event = audplay_dsp_event,
+};
+
+
+#define audplay_send_queue0(audio, cmd, len) \
+	msm_adsp_write(audio->audplay, audio->queue_id, \
+			cmd, len)
+
+static int auddec_dsp_config(struct audio *audio, int enable)
+{
+	u16 cfg_dec_cmd[AUDPP_CMD_CFG_DEC_TYPE_LEN / sizeof(unsigned short)];
+
+	memset(cfg_dec_cmd, 0, sizeof(cfg_dec_cmd));
+
+	cfg_dec_cmd[0] = AUDPP_CMD_CFG_DEC_TYPE;
+	if (enable)
+		cfg_dec_cmd[1 + audio->dec_id] = AUDPP_CMD_UPDATDE_CFG_DEC |
+			AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_MP3;
+	else
+		cfg_dec_cmd[1 + audio->dec_id] = AUDPP_CMD_UPDATDE_CFG_DEC |
+			AUDPP_CMD_DIS_DEC_V;
+
+	return audpp_send_queue1(&cfg_dec_cmd, sizeof(cfg_dec_cmd));
+}
+
+static void audpp_cmd_cfg_adec_params(struct audio *audio)
+{
+	audpp_cmd_cfg_adec_params_mp3 cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_MP3_LEN;
+	cmd.common.dec_id = audio->dec_id;
+	cmd.common.input_sampling_frequency = audio->out_sample_rate;
+
+	audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static void audpp_cmd_cfg_routing_mode(struct audio *audio)
+{
+	struct audpp_cmd_routing_mode cmd;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_ROUTING_MODE;
+	cmd.object_number = audio->dec_id;
+	if (audio->pcm_feedback)
+		cmd.routing_mode = ROUTING_MODE_FTRT;
+	else
+		cmd.routing_mode = ROUTING_MODE_RT;
+
+	audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static int audplay_dsp_send_data_avail(struct audio *audio,
+					unsigned idx, unsigned len)
+{
+	struct audplay_cmd_bitstream_data_avail_nt2 cmd;
+
+	cmd.cmd_id		= AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_NT2;
+	if (audio->mfield)
+		cmd.decoder_id = AUDMP3_METAFIELD_MASK |
+			(audio->out[idx].mfield_sz >> 1);
+	else
+		cmd.decoder_id		= audio->dec_id;
+	cmd.buf_ptr		= audio->out[idx].addr;
+	cmd.buf_size		= len/2;
+	cmd.partition_number	= 0;
+	/* complete all the writes to the input buffer */
+	wmb();
+	return audplay_send_queue0(audio, &cmd, sizeof(cmd));
+}
+
+/* Caller holds irq_lock */
+static void audmp3_async_buffer_refresh(struct audio *audio)
+{
+	struct audplay_cmd_buffer_refresh refresh_cmd;
+	struct audmp3_buffer_node *next_buf;
+
+	if (!audio->running ||
+	    audio->drv_status & ADRV_STATUS_IBUF_GIVEN)
+		return;
+
+	if (!list_empty(&audio->in_queue)) {
+		next_buf = list_first_entry(&audio->in_queue,
+		    struct audmp3_buffer_node, list);
+		if (!next_buf)
+			return;
+		MM_DBG("next buf %p phy %lx len %d\n", next_buf,
+				next_buf->paddr, next_buf->buf.buf_len);
+		refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH;
+		refresh_cmd.num_buffers = 1;
+		refresh_cmd.buf0_address = next_buf->paddr;
+		refresh_cmd.buf0_length = next_buf->buf.buf_len -
+			(next_buf->buf.buf_len % 576) +
+			(audio->mfield ? 24 : 0); /* Mp3 frame size */
+		refresh_cmd.buf_read_count = 0;
+		audio->drv_status |= ADRV_STATUS_IBUF_GIVEN;
+		(void) audplay_send_queue0(audio, &refresh_cmd,
+			sizeof(refresh_cmd));
+	}
+
+}
+
+static void audplay_buffer_refresh(struct audio *audio)
+{
+	struct audplay_cmd_buffer_refresh refresh_cmd;
+
+	refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH;
+	refresh_cmd.num_buffers = 1;
+	refresh_cmd.buf0_address = audio->in[audio->fill_next].addr;
+	refresh_cmd.buf0_length = audio->in[audio->fill_next].size -
+		(audio->in[audio->fill_next].size % 576) +
+		(audio->mfield ? 24 : 0); /* Mp3 frame size */
+	refresh_cmd.buf_read_count = 0;
+	MM_DBG("buf0_addr=%x buf0_len=%d\n", refresh_cmd.buf0_address,
+			refresh_cmd.buf0_length);
+	(void)audplay_send_queue0(audio, &refresh_cmd, sizeof(refresh_cmd));
+}
+
+static void audplay_config_hostpcm(struct audio *audio)
+{
+	struct audplay_cmd_hpcm_buf_cfg cfg_cmd;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	cfg_cmd.cmd_id = AUDPLAY_CMD_HPCM_BUF_CFG;
+	cfg_cmd.max_buffers = 1;
+	cfg_cmd.byte_swap = 0;
+	cfg_cmd.hostpcm_config = (0x8000) | (0x4000);
+	cfg_cmd.feedback_frequency = 1;
+	cfg_cmd.partition_number = 0;
+	(void)audplay_send_queue0(audio, &cfg_cmd, sizeof(cfg_cmd));
+
+}
+
+static void audmp3_async_send_data(struct audio *audio, unsigned needed)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (needed && !audio->wflush) {
+		audio->out_needed = 1;
+		if (audio->drv_status & ADRV_STATUS_OBUF_GIVEN) {
+			/* pop one node out of queue */
+			union msm_audio_event_payload payload;
+			struct audmp3_buffer_node *used_buf;
+
+			MM_DBG("consumed\n");
+			BUG_ON(list_empty(&audio->out_queue));
+			used_buf = list_first_entry(&audio->out_queue,
+				struct audmp3_buffer_node, list);
+			list_del(&used_buf->list);
+			payload.aio_buf = used_buf->buf;
+			audmp3_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+				payload);
+			kfree(used_buf);
+			audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
+		}
+
+	}
+
+	if (audio->out_needed) {
+		struct audmp3_buffer_node *next_buf;
+		struct audplay_cmd_bitstream_data_avail_nt2 cmd;
+		if (!list_empty(&audio->out_queue)) {
+			next_buf = list_first_entry(&audio->out_queue,
+					struct audmp3_buffer_node, list);
+			MM_DBG("next_buf %p\n", next_buf);
+			if (next_buf) {
+				MM_DBG("next buf phy %lx len %d\n",
+						next_buf->paddr,
+						next_buf->buf.data_len);
+
+				cmd.cmd_id =
+					AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_NT2;
+				if (audio->mfield)
+					cmd.decoder_id = AUDMP3_METAFIELD_MASK |
+						(next_buf->buf.mfield_sz >> 1);
+				else
+					cmd.decoder_id = audio->dec_id;
+				cmd.buf_ptr	= (unsigned) next_buf->paddr;
+				cmd.buf_size = next_buf->buf.data_len >> 1;
+				cmd.partition_number	= 0;
+				/* complete the writes to the input buffer */
+				wmb();
+				audplay_send_queue0(audio, &cmd, sizeof(cmd));
+				audio->out_needed = 0;
+				audio->drv_status |= ADRV_STATUS_OBUF_GIVEN;
+			}
+		}
+	}
+
+done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static void audplay_send_data(struct audio *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (needed && !audio->wflush) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			MM_DBG("frame %d free\n", audio->out_tail);
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+		  BUG_ON(frame->used == 0xffffffff);
+		  MM_DBG("frame %d busy\n", audio->out_tail);
+		  audplay_dsp_send_data_avail(audio, audio->out_tail,
+					      frame->used);
+		  frame->used = 0xffffffff;
+		  audio->out_needed = 0;
+		}
+	}
+done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+static void audmp3_async_flush(struct audio *audio)
+{
+	struct audmp3_buffer_node *buf_node;
+	struct list_head *ptr, *next;
+	union msm_audio_event_payload payload;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	list_for_each_safe(ptr, next, &audio->out_queue) {
+		buf_node = list_entry(ptr, struct audmp3_buffer_node, list);
+		list_del(&buf_node->list);
+		payload.aio_buf = buf_node->buf;
+		audmp3_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+				payload);
+		kfree(buf_node);
+	}
+	audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
+	audio->out_needed = 0;
+	atomic_set(&audio->out_bytes, 0);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static void audio_flush(struct audio *audio)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->out[0].used = 0;
+	audio->out[1].used = 0;
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->reserved = 0;
+	audio->out_needed = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	atomic_set(&audio->out_bytes, 0);
+}
+
+static void audmp3_async_flush_pcm_buf(struct audio *audio)
+{
+	struct audmp3_buffer_node *buf_node;
+	struct list_head *ptr, *next;
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	list_for_each_safe(ptr, next, &audio->in_queue) {
+		buf_node = list_entry(ptr, struct audmp3_buffer_node, list);
+		list_del(&buf_node->list);
+		payload.aio_buf = buf_node->buf;
+		payload.aio_buf.data_len = 0;
+		audmp3_post_event(audio, AUDIO_EVENT_READ_DONE,
+				payload);
+		kfree(buf_node);
+	}
+	audio->drv_status &= ~ADRV_STATUS_IBUF_GIVEN;
+
+}
+
+static void audio_flush_pcm_buf(struct audio *audio)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
+		audio->in[index].used = 0;
+	audio->buf_refresh = 0;
+	audio->read_next = 0;
+	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static void audio_ioport_reset(struct audio *audio)
+{
+	if (audio->drv_status & ADRV_STATUS_AIO_INTF) {
+		/* If fsync is in progress, make sure
+		 * return value of fsync indicates
+		 * abort due to flush
+		 */
+		if (audio->drv_status & ADRV_STATUS_FSYNC) {
+			MM_DBG("fsync in progress\n");
+			wake_up(&audio->write_wait);
+			mutex_lock(&audio->write_lock);
+			audio->drv_ops.out_flush(audio);
+			mutex_unlock(&audio->write_lock);
+		} else
+			audio->drv_ops.out_flush(audio);
+		audio->drv_ops.in_flush(audio);
+	} else {
+		/* Make sure read/write thread are free from
+		 * sleep and knowing that system is not able
+		 * to process io request at the moment
+		 */
+		wake_up(&audio->write_wait);
+		mutex_lock(&audio->write_lock);
+		audio->drv_ops.out_flush(audio);
+		mutex_unlock(&audio->write_lock);
+		wake_up(&audio->read_wait);
+		mutex_lock(&audio->read_lock);
+		audio->drv_ops.in_flush(audio);
+		mutex_unlock(&audio->read_lock);
+	}
+}
+
+static int audmp3_events_pending(struct audio *audio)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	return empty || audio->event_abort;
+}
+
+static void audmp3_reset_event_queue(struct audio *audio)
+{
+	unsigned long flags;
+	struct audmp3_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+			struct audmp3_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+			struct audmp3_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	return;
+}
+
+static long audmp3_process_event_req(struct audio *audio, void __user *arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audmp3_event *drv_evt = NULL;
+	int timeout;
+	unsigned long flags;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int) usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(
+			audio->event_wait, audmp3_events_pending(audio),
+			msecs_to_jiffies(timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(
+			audio->event_wait, audmp3_events_pending(audio));
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	rc = 0;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+			struct audmp3_event, list);
+		list_del(&drv_evt->list);
+	}
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else
+		rc = -1;
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	if (drv_evt->event_type == AUDIO_EVENT_WRITE_DONE ||
+	    drv_evt->event_type == AUDIO_EVENT_READ_DONE) {
+		mutex_lock(&audio->lock);
+		audmp3_pmem_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+				  drv_evt->payload.aio_buf.buf_len, 0);
+		mutex_unlock(&audio->lock);
+	}
+
+	/* order reads from the output buffer */
+	if (drv_evt->event_type == AUDIO_EVENT_READ_DONE)
+		rmb();
+
+	if (!rc && copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audmp3_pmem_check(struct audio *audio,
+		void *vaddr, unsigned long len)
+{
+	struct audmp3_pmem_region *region_elt;
+	struct audmp3_pmem_region t = { .vaddr = vaddr, .len = len };
+
+	list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+		if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
+		    OVERLAPS(region_elt, &t)) {
+			MM_ERR("region (vaddr %p len %ld)"
+				" clashes with registered region"
+				" (vaddr %p paddr %p len %ld)\n",
+				vaddr, len,
+				region_elt->vaddr,
+				(void *)region_elt->paddr,
+				region_elt->len);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int audmp3_pmem_add(struct audio *audio,
+	struct msm_audio_pmem_info *info)
+{
+	unsigned long paddr, kvaddr, len;
+	struct file *file;
+	struct audmp3_pmem_region *region;
+	int rc = -EINVAL;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	region = kmalloc(sizeof(*region), GFP_KERNEL);
+
+	if (!region) {
+		rc = -ENOMEM;
+		goto end;
+	}
+
+	if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) {
+		kfree(region);
+		goto end;
+	}
+
+	rc = audmp3_pmem_check(audio, info->vaddr, len);
+	if (rc < 0) {
+		put_pmem_file(file);
+		kfree(region);
+		goto end;
+	}
+
+	region->vaddr = info->vaddr;
+	region->fd = info->fd;
+	region->paddr = paddr;
+	region->kvaddr = kvaddr;
+	region->len = len;
+	region->file = file;
+	region->ref_cnt = 0;
+	MM_DBG("add region paddr %lx vaddr %p, len %lu\n", region->paddr,
+			region->vaddr, region->len);
+	list_add_tail(&region->list, &audio->pmem_region_queue);
+end:
+	return rc;
+}
+
+static int audmp3_pmem_remove(struct audio *audio,
+	struct msm_audio_pmem_info *info)
+{
+	struct audmp3_pmem_region *region;
+	struct list_head *ptr, *next;
+	int rc = -EINVAL;
+
+	MM_DBG("info fd %d vaddr %p\n", info->fd, info->vaddr);
+
+	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
+		region = list_entry(ptr, struct audmp3_pmem_region, list);
+
+		if ((region->fd == info->fd) &&
+		    (region->vaddr == info->vaddr)) {
+			if (region->ref_cnt) {
+				MM_DBG("region %p in use ref_cnt %d\n",
+						region, region->ref_cnt);
+				break;
+			}
+			MM_DBG("remove region fd %d vaddr %p \n",
+					info->fd, info->vaddr);
+			list_del(&region->list);
+			put_pmem_file(region->file);
+			kfree(region);
+			rc = 0;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static int audmp3_pmem_lookup_vaddr(struct audio *audio, void *addr,
+		     unsigned long len, struct audmp3_pmem_region **region)
+{
+	struct audmp3_pmem_region *region_elt;
+
+	int match_count = 0;
+
+	*region = NULL;
+
+	/* returns physical address or zero */
+	list_for_each_entry(region_elt, &audio->pmem_region_queue,
+		list) {
+		if (addr >= region_elt->vaddr &&
+		    addr < region_elt->vaddr + region_elt->len &&
+		    addr + len <= region_elt->vaddr + region_elt->len) {
+			/* offset since we could pass vaddr inside a registerd
+			 * pmem buffer
+			 */
+
+			match_count++;
+			if (!*region)
+				*region = region_elt;
+		}
+	}
+
+	if (match_count > 1) {
+		MM_ERR("multiple hits for vaddr %p, len %ld\n", addr, len);
+		list_for_each_entry(region_elt,
+		  &audio->pmem_region_queue, list) {
+			if (addr >= region_elt->vaddr &&
+			    addr < region_elt->vaddr + region_elt->len &&
+			    addr + len <= region_elt->vaddr + region_elt->len)
+				MM_ERR("\t%p, %ld --> %p\n", region_elt->vaddr,
+						region_elt->len,
+						(void *)region_elt->paddr);
+		}
+	}
+
+	return *region ? 0 : -1;
+}
+
+unsigned long audmp3_pmem_fixup(struct audio *audio, void *addr,
+		    unsigned long len, int ref_up)
+{
+	struct audmp3_pmem_region *region;
+	unsigned long paddr;
+	int ret;
+
+	ret = audmp3_pmem_lookup_vaddr(audio, addr, len, &region);
+	if (ret) {
+		MM_ERR("lookup (%p, %ld) failed\n", addr, len);
+		return 0;
+	}
+	if (ref_up)
+		region->ref_cnt++;
+	else
+		region->ref_cnt--;
+	MM_DBG("found region %p ref_cnt %d\n", region, region->ref_cnt);
+	paddr = region->paddr + (addr - region->vaddr);
+	return paddr;
+}
+
+/* audio -> lock must be held at this point */
+static int audmp3_aio_buf_add(struct audio *audio, unsigned dir,
+	void __user *arg)
+{
+	unsigned long flags;
+	struct audmp3_buffer_node *buf_node;
+
+	buf_node = kmalloc(sizeof(*buf_node), GFP_KERNEL);
+
+	if (!buf_node)
+		return -ENOMEM;
+
+	if (copy_from_user(&buf_node->buf, arg, sizeof(buf_node->buf))) {
+		kfree(buf_node);
+		return -EFAULT;
+	}
+
+	MM_DBG("node %p dir %x buf_addr %p buf_len %d data_len \
+			%d\n", buf_node, dir,
+			buf_node->buf.buf_addr, buf_node->buf.buf_len,
+			buf_node->buf.data_len);
+
+	buf_node->paddr = audmp3_pmem_fixup(
+		audio, buf_node->buf.buf_addr,
+		buf_node->buf.buf_len, 1);
+
+	if (dir) {
+		/* write */
+		if (!buf_node->paddr ||
+		    (buf_node->paddr & 0x1) ||
+		    (buf_node->buf.data_len & 0x1) ||
+		    (!audio->pcm_feedback &&
+		    !buf_node->buf.data_len)) {
+			kfree(buf_node);
+			return -EINVAL;
+		}
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		list_add_tail(&buf_node->list, &audio->out_queue);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		audio->drv_ops.send_data(audio, 0);
+	} else {
+		/* read */
+		if (!buf_node->paddr ||
+		    (buf_node->paddr & 0x1) ||
+		    (buf_node->buf.buf_len < PCM_BUFSZ_MIN)) {
+			kfree(buf_node);
+			return -EINVAL;
+		}
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		list_add_tail(&buf_node->list, &audio->in_queue);
+		audio->drv_ops.buffer_refresh(audio);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	}
+
+	MM_DBG("Add buf_node %p paddr %lx\n", buf_node, buf_node->paddr);
+
+	return 0;
+}
+
+static int audio_enable_eq(struct audio *audio, int enable)
+{
+	if (audio->eq_enable == enable && !audio->eq_needs_commit)
+		return 0;
+
+	audio->eq_enable = enable;
+
+	if (audio->running) {
+		audpp_dsp_set_eq(audio->dec_id, enable, &audio->eq);
+		audio->eq_needs_commit = 0;
+	}
+	return 0;
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = -EINVAL;
+	unsigned long flags = 0;
+	uint16_t enable_mask;
+	int enable;
+	int prev_state;
+
+	MM_DBG("cmd = %d\n", cmd);
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = audpp_avsync_byte_count(audio->dec_id);
+		stats.sample_count = audpp_avsync_sample_count(audio->dec_id);
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	switch (cmd) {
+	case AUDIO_ENABLE_AUDPP:
+		if (copy_from_user(&enable_mask, (void *) arg,
+						sizeof(enable_mask))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		enable = (enable_mask & EQ_ENABLE) ? 1 : 0;
+		audio_enable_eq(audio, enable);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+	case AUDIO_SET_VOLUME:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.volume = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_PAN:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.pan = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_EQ:
+		prev_state = audio->eq_enable;
+		audio->eq_enable = 0;
+		if (copy_from_user(&audio->eq.num_bands, (void *) arg,
+				sizeof(audio->eq) -
+				(AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2))) {
+			rc = -EFAULT;
+			break;
+		}
+		audio->eq_enable = prev_state;
+		audio->eq_needs_commit = 1;
+		rc = 0;
+		break;
+	}
+
+	if (-EINVAL != rc)
+		return rc;
+
+	if (cmd == AUDIO_GET_EVENT) {
+		MM_DBG(" AUDIO_GET_EVENT\n");
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audmp3_process_event_req(audio,
+				(void __user *) arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		return rc;
+	}
+
+	if (cmd == AUDIO_ABORT_GET_EVENT) {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		MM_DBG("AUDIO_START\n");
+		rc = audio_enable(audio);
+		if (!rc) {
+			rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+			MM_INFO("dec_state %d rc = %d\n", audio->dec_state, rc);
+
+			if (audio->dec_state != MSM_AUD_DECODER_STATE_SUCCESS)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		break;
+	case AUDIO_STOP:
+		MM_DBG("AUDIO_STOP\n");
+		rc = audio_disable(audio);
+		audio_ioport_reset(audio);
+		audio->stopped = 0;
+		break;
+	case AUDIO_FLUSH:
+		MM_DBG("AUDIO_FLUSH\n");
+		audio->rflush = 1;
+		audio->wflush = 1;
+		audio_ioport_reset(audio);
+		if (audio->running) {
+			audpp_flush(audio->dec_id);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		break;
+
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (copy_from_user(&config, (void *) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (config.channel_count == 1) {
+			config.channel_count = AUDPP_CMD_PCM_INTF_MONO_V;
+		} else if (config.channel_count == 2) {
+			config.channel_count = AUDPP_CMD_PCM_INTF_STEREO_V;
+		} else {
+			rc = -EINVAL;
+			break;
+		}
+		audio->mfield = config.meta_field;
+		audio->out_sample_rate = config.sample_rate;
+		audio->out_channel_mode = config.channel_count;
+		rc = 0;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_size = (audio->out_dma_sz >> 1);
+		config.buffer_count = 2;
+		config.sample_rate = audio->out_sample_rate;
+		if (audio->out_channel_mode == AUDPP_CMD_PCM_INTF_MONO_V) {
+			config.channel_count = 1;
+		} else {
+			config.channel_count = 2;
+		}
+		config.meta_field = 0;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void *) arg, &config, sizeof(config))) {
+			rc = -EFAULT;
+		} else {
+			rc = 0;
+		}
+		break;
+	}
+	case AUDIO_GET_PCM_CONFIG:{
+		struct msm_audio_pcm_config config;
+		config.pcm_feedback = audio->pcm_feedback;
+		config.buffer_count = PCM_BUF_MAX_COUNT;
+		config.buffer_size = PCM_BUFSZ_MIN;
+		if (copy_to_user((void *)arg, &config,
+			 sizeof(config)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	}
+	case AUDIO_SET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			if (copy_from_user
+			    (&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+
+			if (config.pcm_feedback != audio->pcm_feedback) {
+				MM_ERR("Not sufficient permission to"
+					 "change the playback mode\n");
+				rc = -EACCES;
+				break;
+			}
+			if (audio->drv_status & ADRV_STATUS_AIO_INTF) {
+				rc = 0;
+				break;
+			}
+
+			if ((config.buffer_count > PCM_BUF_MAX_COUNT) ||
+			    (config.buffer_count == 1))
+				config.buffer_count = PCM_BUF_MAX_COUNT;
+
+			if (config.buffer_size < PCM_BUFSZ_MIN)
+				config.buffer_size = PCM_BUFSZ_MIN;
+
+			/* Check if pcm feedback is required */
+			if ((config.pcm_feedback) && (!audio->read_data)) {
+				MM_DBG("allocate PCM buffer %d\n",
+					config.buffer_count *
+					config.buffer_size);
+				audio->read_phys =
+						allocate_contiguous_ebi_nomap(
+							config.buffer_size *
+							config.buffer_count,
+							SZ_4K);
+				if (!audio->read_phys) {
+					rc = -ENOMEM;
+					break;
+				}
+				audio->map_v_read = ioremap(
+							audio->read_phys,
+							config.buffer_size *
+							config.buffer_count);
+
+				if (IS_ERR(audio->map_v_read)) {
+					MM_ERR("map of read buf failed\n");
+					rc = -ENOMEM;
+					free_contiguous_memory_by_paddr(
+							audio->read_phys);
+				} else {
+					uint8_t index;
+					uint32_t offset = 0;
+					audio->read_data =
+						audio->map_v_read;
+					audio->buf_refresh = 0;
+					audio->pcm_buf_count =
+					    config.buffer_count;
+					audio->read_next = 0;
+					audio->fill_next = 0;
+
+					for (index = 0;
+					     index < config.buffer_count;
+					     index++) {
+						audio->in[index].data =
+						    audio->read_data + offset;
+						audio->in[index].addr =
+						    audio->read_phys + offset;
+						audio->in[index].size =
+						    config.buffer_size;
+						audio->in[index].used = 0;
+						offset += config.buffer_size;
+					}
+					rc = 0;
+					MM_DBG("read buf: phy addr \
+						0x%08x kernel addr 0x%08x\n",
+						audio->read_phys,
+						(int)audio->read_data);
+				}
+			} else {
+				rc = 0;
+			}
+			break;
+		}
+	case AUDIO_PAUSE:
+		MM_DBG("AUDIO_PAUSE %ld\n", arg);
+		rc = audpp_pause(audio->dec_id, (int) arg);
+		break;
+
+	case AUDIO_REGISTER_PMEM: {
+			struct msm_audio_pmem_info info;
+			MM_DBG("AUDIO_REGISTER_PMEM\n");
+			if (copy_from_user(&info, (void *) arg, sizeof(info)))
+				rc = -EFAULT;
+			else
+				rc = audmp3_pmem_add(audio, &info);
+			break;
+		}
+
+	case AUDIO_DEREGISTER_PMEM: {
+			struct msm_audio_pmem_info info;
+			MM_DBG("AUDIO_DEREGISTER_PMEM\n");
+			if (copy_from_user(&info, (void *) arg, sizeof(info)))
+				rc = -EFAULT;
+			else
+				rc = audmp3_pmem_remove(audio, &info);
+			break;
+		}
+	case AUDIO_ASYNC_WRITE:
+		if (audio->drv_status & ADRV_STATUS_FSYNC)
+			rc = -EBUSY;
+		else
+			rc = audmp3_aio_buf_add(audio, 1, (void __user *) arg);
+		break;
+
+	case AUDIO_ASYNC_READ:
+		if (audio->pcm_feedback)
+			rc = audmp3_aio_buf_add(audio, 0, (void __user *) arg);
+		else
+			rc = -EPERM;
+		break;
+
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+/* Only useful in tunnel-mode */
+int audmp3_async_fsync(struct audio *audio)
+{
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	/* Blocking client sends more data */
+	mutex_lock(&audio->lock);
+	audio->drv_status |= ADRV_STATUS_FSYNC;
+	mutex_unlock(&audio->lock);
+
+	mutex_lock(&audio->write_lock);
+	/* pcm dmamiss message is sent continously
+	 * when decoder is starved so no race
+	 * condition concern
+	 */
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->teos && audio->out_needed &&
+		list_empty(&audio->out_queue))
+		|| audio->wflush || audio->stopped);
+
+	if (audio->stopped || audio->wflush)
+		rc = -EBUSY;
+
+	mutex_unlock(&audio->write_lock);
+	mutex_lock(&audio->lock);
+	audio->drv_status &= ~ADRV_STATUS_FSYNC;
+	mutex_unlock(&audio->lock);
+
+	return rc;
+}
+
+int audmp3_sync_fsync(struct audio *audio)
+{
+	struct buffer *frame;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(!audio->out[0].used &&
+		!audio->out[1].used &&
+		audio->out_needed) || audio->wflush);
+
+	if (rc < 0)
+		goto done;
+	else if (audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (audio->reserved) {
+		MM_DBG("send reserved byte\n");
+		frame = audio->out + audio->out_tail;
+		((char *) frame->data)[0] = audio->rsv_byte;
+		((char *) frame->data)[1] = 0;
+		frame->used = 2;
+		audio->drv_ops.send_data(audio, 0);
+
+		rc = wait_event_interruptible(audio->write_wait,
+			(!audio->out[0].used &&
+			!audio->out[1].used &&
+			audio->out_needed) || audio->wflush);
+
+		if (rc < 0)
+			goto done;
+		else if (audio->wflush) {
+			rc = -EBUSY;
+			goto done;
+		}
+	}
+
+	/* pcm dmamiss message is sent continously
+	 * when decoder is starved so no race
+	 * condition concern
+	 */
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		audio->teos || audio->wflush);
+
+	if (audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+	return rc;
+}
+
+int audmp3_fsync(struct file *file, loff_t a, loff_t b, int datasync)
+{
+	struct audio *audio = file->private_data;
+
+	if (!audio->running || audio->pcm_feedback)
+		return -EINVAL;
+
+	return audio->drv_ops.fsync(audio);
+}
+
+static ssize_t audio_read(struct file *file, char __user *buf, size_t count,
+			  loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	int rc = 0;
+
+	if (audio->drv_status & ADRV_STATUS_AIO_INTF)
+		return -EPERM;
+	else if (!audio->pcm_feedback)
+		return 0; /* PCM feedback disabled. Nothing to read */
+
+	mutex_lock(&audio->read_lock);
+	MM_DBG("%d \n",	count);
+	while (count > 0) {
+		rc = wait_event_interruptible(
+			audio->read_wait,
+			(audio->in[audio->read_next].
+			used > 0) || (audio->stopped)
+			|| (audio->rflush));
+
+		if (rc < 0)
+			break;
+
+		if (audio->stopped || audio->rflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (count < audio->in[audio->read_next].used) {
+			/* Read must happen in frame boundary. Since
+			 * driver does not know frame size, read count
+			 * must be greater or equal
+			 * to size of PCM samples
+			 */
+			MM_DBG("no partial frame done reading\n");
+			break;
+		} else {
+			MM_DBG("read from in[%d]\n", audio->read_next);
+			/* order reads from the output buffer */
+			rmb();
+			if (copy_to_user
+			    (buf, audio->in[audio->read_next].data,
+			     audio->in[audio->read_next].used)) {
+				MM_ERR("invalid addr %x \n", (unsigned int)buf);
+				rc = -EFAULT;
+				break;
+			}
+			count -= audio->in[audio->read_next].used;
+			buf += audio->in[audio->read_next].used;
+			audio->in[audio->read_next].used = 0;
+			if ((++audio->read_next) == audio->pcm_buf_count)
+				audio->read_next = 0;
+			break;	/* Force to exit while loop
+				 * to prevent output thread
+				 * sleep too long if data is
+				 * not ready at this moment.
+				 */
+		}
+	}
+
+	/* don't feed output buffer to HW decoder during flushing
+	 * buffer refresh command will be sent once flush completes
+	 * send buf refresh command here can confuse HW decoder
+	 */
+	if (audio->buf_refresh && !audio->rflush) {
+		audio->buf_refresh = 0;
+		MM_DBG("kick start pcm feedback again\n");
+		audio->drv_ops.buffer_refresh(audio);
+	}
+
+	mutex_unlock(&audio->read_lock);
+
+	if (buf > start)
+		rc = buf - start;
+
+	MM_DBG("read %d bytes\n", rc);
+	return rc;
+}
+
+static int audmp3_process_eos(struct audio *audio,
+		const char __user *buf_start, unsigned short mfield_size)
+{
+	int rc = 0;
+	struct buffer *frame;
+	char *buf_ptr;
+
+	if (audio->reserved) {
+		MM_DBG("flush reserve byte\n");
+		frame = audio->out + audio->out_head;
+		buf_ptr = frame->data;
+		rc = wait_event_interruptible(audio->write_wait,
+			(frame->used == 0)
+			|| (audio->stopped)
+			|| (audio->wflush));
+		if (rc < 0)
+			goto done;
+		if (audio->stopped || audio->wflush) {
+			rc = -EBUSY;
+			goto done;
+		}
+
+		buf_ptr[0] = audio->rsv_byte;
+		buf_ptr[1] = 0;
+		audio->out_head ^= 1;
+		frame->mfield_sz = 0;
+		frame->used = 2;
+		audio->reserved = 0;
+		audio->drv_ops.send_data(audio, 0);
+	}
+
+	frame = audio->out + audio->out_head;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->out_needed &&
+		audio->out[0].used == 0 &&
+		audio->out[1].used == 0)
+		|| (audio->stopped)
+		|| (audio->wflush));
+
+	if (rc < 0)
+		goto done;
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (copy_from_user(frame->data, buf_start, mfield_size)) {
+		rc = -EFAULT;
+		goto done;
+	}
+
+	frame->mfield_sz = mfield_size;
+	audio->out_head ^= 1;
+	frame->used = mfield_size;
+	audio->drv_ops.send_data(audio, 0);
+done:
+	return rc;
+}
+
+static ssize_t audio_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	char *cpy_ptr;
+	int rc = 0, eos_condition = AUDMP3_EOS_NONE;
+	unsigned dsize;
+	unsigned short mfield_size = 0;
+
+	if (audio->drv_status & ADRV_STATUS_AIO_INTF)
+		return -EPERM;
+
+	MM_DBG("cnt=%d\n", count);
+
+	mutex_lock(&audio->write_lock);
+	while (count > 0) {
+		frame = audio->out + audio->out_head;
+		cpy_ptr = frame->data;
+		dsize = 0;
+		rc = wait_event_interruptible(audio->write_wait,
+					      (frame->used == 0)
+					      || (audio->stopped)
+						  || (audio->wflush));
+		if (rc < 0)
+			break;
+		if (audio->stopped || audio->wflush) {
+			rc = -EBUSY;
+			break;
+		}
+		if (audio->mfield) {
+			if (buf == start) {
+				/* Processing beginning of user buffer */
+				if (__get_user(mfield_size,
+					(unsigned short __user *) buf)) {
+					rc = -EFAULT;
+					break;
+				} else  if (mfield_size > count) {
+					rc = -EINVAL;
+					break;
+				}
+				MM_DBG("mf offset_val %x\n", mfield_size);
+				if (copy_from_user(cpy_ptr, buf, mfield_size)) {
+					rc = -EFAULT;
+					break;
+				}
+				/* Check if EOS flag is set and buffer has
+				 * contains just meta field
+				 */
+				if (cpy_ptr[AUDMP3_EOS_FLG_OFFSET] &
+						 AUDMP3_EOS_FLG_MASK) {
+					MM_DBG("EOS SET\n");
+					eos_condition = AUDMP3_EOS_SET;
+					if (mfield_size == count) {
+						buf += mfield_size;
+						break;
+					} else
+						cpy_ptr[AUDMP3_EOS_FLG_OFFSET]
+							&= ~AUDMP3_EOS_FLG_MASK;
+				}
+				cpy_ptr += mfield_size;
+				count -= mfield_size;
+				dsize += mfield_size;
+				buf += mfield_size;
+			} else {
+				mfield_size = 0;
+				MM_DBG("continuous buffer\n");
+			}
+			frame->mfield_sz = mfield_size;
+		}
+
+		if (audio->reserved) {
+			MM_DBG("append reserved byte %x\n", audio->rsv_byte);
+			*cpy_ptr = audio->rsv_byte;
+			xfer = (count > ((frame->size - mfield_size) - 1)) ?
+				(frame->size - mfield_size) - 1 : count;
+			cpy_ptr++;
+			dsize += 1;
+			audio->reserved = 0;
+		} else
+			xfer = (count > (frame->size - mfield_size)) ?
+				(frame->size - mfield_size) : count;
+
+		if (copy_from_user(cpy_ptr, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+
+		dsize += xfer;
+		if (dsize & 1) {
+			audio->rsv_byte = ((char *) frame->data)[dsize - 1];
+			MM_DBG("odd length buf reserve last byte %x\n",
+					audio->rsv_byte);
+			audio->reserved = 1;
+			dsize--;
+		}
+		count -= xfer;
+		buf += xfer;
+
+		if (dsize > 0) {
+			audio->out_head ^= 1;
+			frame->used = dsize;
+			audio->drv_ops.send_data(audio, 0);
+		}
+	}
+	if (eos_condition == AUDMP3_EOS_SET)
+		rc = audmp3_process_eos(audio, start, mfield_size);
+	mutex_unlock(&audio->write_lock);
+	if (!rc) {
+		if (buf > start)
+			return buf - start;
+	}
+	return rc;
+}
+
+static void audmp3_reset_pmem_region(struct audio *audio)
+{
+	struct audmp3_pmem_region *region;
+	struct list_head *ptr, *next;
+
+	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
+		region = list_entry(ptr, struct audmp3_pmem_region, list);
+		list_del(&region->list);
+		put_pmem_file(region->file);
+		kfree(region);
+	}
+
+	return;
+}
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	MM_INFO("audio instance 0x%08x freeing\n", (int)audio);
+	mutex_lock(&audio->lock);
+	audio_disable(audio);
+	if (audio->rmt_resource_released == 0)
+		rmt_put_resource(audio);
+	audio->drv_ops.out_flush(audio);
+	audio->drv_ops.in_flush(audio);
+	audmp3_reset_pmem_region(audio);
+
+	msm_adsp_put(audio->audplay);
+	audpp_adec_free(audio->dec_id);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&audio->suspend_ctl.node);
+#endif
+	audio->opened = 0;
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audmp3_reset_event_queue(audio);
+	MM_DBG("pmem area = 0x%8x\n", (unsigned int)audio->data);
+	if (audio->data) {
+		iounmap(audio->map_v_write);
+		free_contiguous_memory_by_paddr(audio->phys);
+	}
+	if (audio->read_data) {
+		iounmap(audio->map_v_read);
+		free_contiguous_memory_by_paddr(audio->read_phys);
+	}
+	mutex_unlock(&audio->lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio);
+	return 0;
+}
+
+static void audmp3_post_event(struct audio *audio, int type,
+	union msm_audio_event_payload payload)
+{
+	struct audmp3_event *e_node = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+			struct audmp3_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audmp3_event), GFP_ATOMIC);
+		if (!e_node) {
+			MM_ERR("No mem to post event %d\n", type);
+			spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	wake_up(&audio->event_wait);
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audmp3_suspend(struct early_suspend *h)
+{
+	struct audmp3_suspend_ctl *ctl =
+		container_of(h, struct audmp3_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audmp3_post_event(ctl->audio, AUDIO_EVENT_SUSPEND, payload);
+}
+
+static void audmp3_resume(struct early_suspend *h)
+{
+	struct audmp3_suspend_ctl *ctl =
+		container_of(h, struct audmp3_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audmp3_post_event(ctl->audio, AUDIO_EVENT_RESUME, payload);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audmp3_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audmp3_debug_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 4096;
+	static char buffer[4096];
+	int n = 0, i;
+	struct audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "enabled %d\n", audio->enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "pcm_feedback %d\n", audio->pcm_feedback);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_buf_sz %d\n", audio->out[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "pcm_buf_count %d \n", audio->pcm_buf_count);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "pcm_buf_sz %d \n", audio->in[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "volume %x \n", audio->vol_pan.volume);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "sample rate %d \n", audio->out_sample_rate);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		"channel mode %d \n", audio->out_channel_mode);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "rflush %d\n", audio->rflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "running %d \n", audio->running);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				"dec state %d \n", audio->dec_state);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_needed %d \n", audio->out_needed);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_head %d \n", audio->out_head);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_tail %d \n", audio->out_tail);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out[0].used %d \n", audio->out[0].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out[1].used %d \n", audio->out[1].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "buffer_refresh %d \n", audio->buf_refresh);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "read_next %d \n", audio->read_next);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "fill_next %d \n", audio->fill_next);
+	for (i = 0; i < audio->pcm_buf_count; i++)
+		n += scnprintf(buffer + n, debug_bufmax - n,
+			"in[%d].size %d \n", i, audio->in[i].used);
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audmp3_debug_fops = {
+	.read = audmp3_debug_read,
+	.open = audmp3_debug_open,
+};
+#endif
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+
+	struct audio *audio = NULL;
+	int rc, i, dec_attrb, decid;
+	struct audmp3_event *e_node = NULL;
+	unsigned pmem_sz = DMASZ_MAX;
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_mp3_" + 5];
+#endif
+
+	/* Allocate audio instance, set to zero */
+	audio = kzalloc(sizeof(struct audio), GFP_KERNEL);
+	if (!audio) {
+		MM_ERR("no memory to allocate audio instance \n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	MM_INFO("audio instance 0x%08x created\n", (int)audio);
+
+	/* Allocate the decoder */
+	dec_attrb = AUDDEC_DEC_MP3;
+	if ((file->f_mode & FMODE_WRITE) &&
+			(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_NONTUNNEL;
+		audio->pcm_feedback = NON_TUNNEL_MODE_PLAYBACK;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_TUNNEL;
+		audio->pcm_feedback = TUNNEL_MODE_PLAYBACK;
+	} else {
+		kfree(audio);
+		rc = -EACCES;
+		goto done;
+	}
+
+	decid = audpp_adec_alloc(dec_attrb, &audio->module_name,
+			&audio->queue_id);
+	if (decid < 0) {
+		MM_ERR("No free decoder available, freeing instance 0x%08x\n",
+				(int)audio);
+		rc = -ENODEV;
+		kfree(audio);
+		goto done;
+	}
+	audio->dec_id = decid & MSM_AUD_DECODER_MASK;
+
+	/* Non AIO interface */
+	if (!(file->f_flags & O_NONBLOCK)) {
+		while (pmem_sz >= DMASZ_MIN) {
+			MM_DBG("pmemsz = %d\n", pmem_sz);
+			audio->phys = allocate_contiguous_ebi_nomap(pmem_sz,
+								SZ_4K);
+			if (audio->phys) {
+				audio->map_v_write = ioremap(
+							audio->phys, pmem_sz);
+				if (IS_ERR(audio->map_v_write)) {
+					MM_ERR("could not map write \
+						buffers, freeing instance \
+						0x%08x\n", (int)audio);
+					rc = -ENOMEM;
+					free_contiguous_memory_by_paddr(
+								audio->phys);
+					audpp_adec_free(audio->dec_id);
+					kfree(audio);
+					goto done;
+				}
+				audio->data = audio->map_v_write;
+				MM_DBG("write buf: phy addr 0x%08x kernel addr\
+					0x%08x\n", audio->phys,\
+					(int)audio->data);
+				break;
+			} else if (pmem_sz == DMASZ_MIN) {
+				MM_ERR("could not allocate write buffers, \
+						freeing instance 0x%08x\n",
+						(int)audio);
+				rc = -ENOMEM;
+				audpp_adec_free(audio->dec_id);
+				kfree(audio);
+				goto done;
+			} else
+				pmem_sz >>= 1;
+		}
+		audio->out_dma_sz = pmem_sz;
+	}
+
+	if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
+		rc = audmgr_open(&audio->audmgr);
+		if (rc) {
+			MM_ERR("audmgr open failed, freeing instance \
+					0x%08x\n", (int)audio);
+			goto err;
+		}
+	}
+
+	rc = msm_adsp_get(audio->module_name, &audio->audplay,
+		&audplay_adsp_ops, audio);
+
+	if (rc) {
+		MM_ERR("failed to get %s module, freeing instance 0x%08x\n",
+				audio->module_name, (int)audio);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_close(&audio->audmgr);
+		goto err;
+	}
+
+	rc = rmt_get_resource(audio);
+	if (rc) {
+		MM_ERR("ADSP resources are not available for MP3 session \
+			 0x%08x on decoder: %d\n", (int)audio, audio->dec_id);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_close(&audio->audmgr);
+		msm_adsp_put(audio->audplay);
+		goto err;
+	}
+
+	if (file->f_flags & O_NONBLOCK) {
+		MM_DBG("set to aio interface\n");
+		audio->drv_status |= ADRV_STATUS_AIO_INTF;
+		audio->drv_ops.pcm_buf_update = audmp3_async_pcm_buf_update;
+		audio->drv_ops.buffer_refresh = audmp3_async_buffer_refresh;
+		audio->drv_ops.send_data = audmp3_async_send_data;
+		audio->drv_ops.out_flush = audmp3_async_flush;
+		audio->drv_ops.in_flush = audmp3_async_flush_pcm_buf;
+		audio->drv_ops.fsync = audmp3_async_fsync;
+	} else {
+		MM_DBG("set to std io interface\n");
+		audio->drv_ops.pcm_buf_update = audio_update_pcm_buf_entry;
+		audio->drv_ops.buffer_refresh = audplay_buffer_refresh;
+		audio->drv_ops.send_data = audplay_send_data;
+		audio->drv_ops.out_flush = audio_flush;
+		audio->drv_ops.in_flush = audio_flush_pcm_buf;
+		audio->drv_ops.fsync = audmp3_sync_fsync;
+		audio->out[0].data = audio->data + 0;
+		audio->out[0].addr = audio->phys + 0;
+		audio->out[0].size = (audio->out_dma_sz >> 1);
+
+		audio->out[1].data = audio->data + audio->out[0].size;
+		audio->out[1].addr = audio->phys + audio->out[0].size;
+		audio->out[1].size = audio->out[0].size;
+	}
+
+	/* Initialize all locks of audio instance */
+	mutex_init(&audio->lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->get_event_lock);
+	spin_lock_init(&audio->dsp_lock);
+	init_waitqueue_head(&audio->write_wait);
+	init_waitqueue_head(&audio->read_wait);
+	INIT_LIST_HEAD(&audio->out_queue);
+	INIT_LIST_HEAD(&audio->in_queue);
+	INIT_LIST_HEAD(&audio->pmem_region_queue);
+	INIT_LIST_HEAD(&audio->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+	init_waitqueue_head(&audio->wait);
+	init_waitqueue_head(&audio->event_wait);
+	spin_lock_init(&audio->event_queue_lock);
+
+	audio->out_sample_rate = 44100;
+	audio->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V;
+	audio->vol_pan.volume = 0x2000;
+
+	audio->drv_ops.out_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_mp3_%04x", audio->dec_id);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+			NULL, (void *) audio, &audmp3_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		MM_DBG("debugfs_create_file failed\n");
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	audio->suspend_ctl.node.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+	audio->suspend_ctl.node.resume = audmp3_resume;
+	audio->suspend_ctl.node.suspend = audmp3_suspend;
+	audio->suspend_ctl.audio = audio;
+	register_early_suspend(&audio->suspend_ctl.node);
+#endif
+	for (i = 0; i < AUDMP3_EVENT_NUM; i++) {
+		e_node = kmalloc(sizeof(struct audmp3_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			MM_ERR("event pkt alloc failed\n");
+			break;
+		}
+	}
+done:
+	return rc;
+err:
+	if (audio->data) {
+		iounmap(audio->map_v_write);
+		free_contiguous_memory_by_paddr(audio->phys);
+	}
+	audpp_adec_free(audio->dec_id);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_mp3_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audio_open,
+	.release	= audio_release,
+	.read		= audio_read,
+	.write		= audio_write,
+	.unlocked_ioctl	= audio_ioctl,
+	.fsync = audmp3_fsync,
+};
+
+struct miscdevice audio_mp3_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_mp3",
+	.fops	= &audio_mp3_fops,
+};
+
+static int __init audio_init(void)
+{
+	return misc_register(&audio_mp3_misc);
+}
+
+static void __exit audio_exit(void)
+{
+	misc_deregister(&audio_mp3_misc);
+}
+
+module_init(audio_init);
+module_exit(audio_exit);
+
+MODULE_DESCRIPTION("MSM MP3 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5/audio_mvs.c b/arch/arm/mach-msm/qdsp5/audio_mvs.c
new file mode 100644
index 0000000..5ccd18b
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_mvs.c
@@ -0,0 +1,1704 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/fs.h>
+#include <linux/kthread.h>
+#include <linux/list.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/msm_audio_mvs.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/wakelock.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_rpcrouter.h>
+
+#define MVS_PROG 0x30000014
+#define MVS_VERS 0x00030001
+#define MVS_VERS_COMP_VER2 0x00060001
+#define MVS_VERS_COMP_VER3 0x00030001
+
+
+#define MVS_CLIENT_ID_VOIP 0x00000003
+
+#define MVS_ACQUIRE_PROC 4
+#define MVS_ENABLE_PROC 5
+#define MVS_RELEASE_PROC 6
+#define MVS_AMR_SET_AMR_MODE_PROC 7
+#define MVS_AMR_SET_AWB_MODE_PROC 8
+#define MVS_VOC_SET_FRAME_RATE_PROC 10
+#define MVS_GSM_SET_DTX_MODE_PROC 11
+#define MVS_G729A_SET_MODE_PROC 12
+#define MVS_G711_GET_MODE_PROC 14
+#define MVS_G711_SET_MODE_PROC 15
+#define MVS_G711A_GET_MODE_PROC 16
+#define MVS_G711A_SET_MODE_PROC 17
+#define MVS_G722_SET_MODE_PROC 20
+#define MVS_G722_GET_MODE_PROC 21
+#define MVS_SET_DTX_MODE_PROC 22
+
+#define MVS_EVENT_CB_TYPE_PROC 1
+#define MVS_PACKET_UL_FN_TYPE_PROC 2
+#define MVS_PACKET_DL_FN_TYPE_PROC 3
+
+#define MVS_CB_FUNC_ID 0xAAAABBBB
+#define MVS_UL_CB_FUNC_ID 0xBBBBCCCC
+#define MVS_DL_CB_FUNC_ID 0xCCCCDDDD
+
+#define MVS_FRAME_MODE_VOC_TX 1
+#define MVS_FRAME_MODE_VOC_RX 2
+#define MVS_FRAME_MODE_AMR_UL 3
+#define MVS_FRAME_MODE_AMR_DL 4
+#define MVS_FRAME_MODE_GSM_UL 5
+#define MVS_FRAME_MODE_GSM_DL 6
+#define MVS_FRAME_MODE_HR_UL 7
+#define MVS_FRAME_MODE_HR_DL 8
+#define MVS_FRAME_MODE_G711_UL 9
+#define MVS_FRAME_MODE_G711_DL 10
+#define MVS_FRAME_MODE_PCM_UL 13
+#define MVS_FRAME_MODE_PCM_DL 14
+#define MVS_FRAME_MODE_PCM_WB_UL 23
+#define MVS_FRAME_MODE_PCM_WB_DL 24
+#define MVS_FRAME_MODE_G729A_UL 17
+#define MVS_FRAME_MODE_G729A_DL 18
+#define MVS_FRAME_MODE_G711A_UL 19
+#define MVS_FRAME_MODE_G711A_DL 20
+#define MVS_FRAME_MODE_G722_UL 21
+#define MVS_FRAME_MODE_G722_DL 22
+
+
+
+#define MVS_PKT_CONTEXT_ISR 0x00000001
+
+#define RPC_TYPE_REQUEST 0
+#define RPC_TYPE_REPLY 1
+
+#define RPC_STATUS_FAILURE 0
+#define RPC_STATUS_SUCCESS 1
+#define RPC_STATUS_REJECT 1
+
+#define RPC_COMMON_HDR_SZ  (sizeof(uint32_t) * 2)
+#define RPC_REQUEST_HDR_SZ (sizeof(struct rpc_request_hdr))
+#define RPC_REPLY_HDR_SZ   (sizeof(uint32_t) * 3)
+
+enum audio_mvs_state_type {
+	AUDIO_MVS_CLOSED,
+	AUDIO_MVS_OPENED,
+	AUDIO_MVS_STARTED,
+	AUDIO_MVS_STOPPED
+};
+
+enum audio_mvs_event_type {
+	AUDIO_MVS_COMMAND,
+	AUDIO_MVS_MODE,
+	AUDIO_MVS_NOTIFY
+};
+
+enum audio_mvs_cmd_status_type {
+	AUDIO_MVS_CMD_FAILURE,
+	AUDIO_MVS_CMD_BUSY,
+	AUDIO_MVS_CMD_SUCCESS
+};
+
+enum audio_mvs_mode_status_type {
+	AUDIO_MVS_MODE_NOT_AVAIL,
+	AUDIO_MVS_MODE_INIT,
+	AUDIO_MVS_MODE_READY
+};
+
+enum audio_mvs_pkt_status_type {
+	AUDIO_MVS_PKT_NORMAL,
+	AUDIO_MVS_PKT_FAST,
+	AUDIO_MVS_PKT_SLOW
+};
+
+/* Parameters required for MVS acquire. */
+struct rpc_audio_mvs_acquire_args {
+	uint32_t client_id;
+	uint32_t cb_func_id;
+};
+
+struct audio_mvs_acquire_msg {
+	struct rpc_request_hdr rpc_hdr;
+	struct rpc_audio_mvs_acquire_args acquire_args;
+};
+
+/* Parameters required for MVS enable. */
+struct rpc_audio_mvs_enable_args {
+	uint32_t client_id;
+	uint32_t mode;
+	uint32_t ul_cb_func_id;
+	uint32_t dl_cb_func_id;
+	uint32_t context;
+};
+
+struct audio_mvs_enable_msg {
+	struct rpc_request_hdr rpc_hdr;
+	struct rpc_audio_mvs_enable_args enable_args;
+};
+
+/* Parameters required for MVS release. */
+struct audio_mvs_release_msg {
+	struct rpc_request_hdr rpc_hdr;
+	uint32_t client_id;
+};
+
+/* Parameters required for setting AMR mode. */
+struct audio_mvs_set_amr_mode_msg {
+	struct rpc_request_hdr rpc_hdr;
+	uint32_t amr_mode;
+};
+
+/* Parameters required for setting DTX. */
+struct audio_mvs_set_dtx_mode_msg {
+	struct rpc_request_hdr rpc_hdr;
+	uint32_t dtx_mode;
+};
+
+/* Parameters required for setting EVRC mode. */
+struct audio_mvs_set_voc_mode_msg {
+	struct rpc_request_hdr rpc_hdr;
+	uint32_t max_rate;
+	uint32_t min_rate;
+};
+
+/* Parameters for G711 mode */
+struct audio_mvs_set_g711_mode_msg {
+	struct rpc_request_hdr rpc_hdr;
+	uint32_t g711_mode;
+};
+
+/* Parameters for G729 mode */
+struct audio_mvs_set_g729_mode_msg {
+	struct rpc_request_hdr rpc_hdr;
+	uint32_t g729_mode;
+};
+
+/* Parameters for G722 mode */
+struct audio_mvs_set_g722_mode_msg {
+	struct rpc_request_hdr rpc_hdr;
+	uint32_t g722_mode;
+};
+
+
+/* Parameters for G711A mode */
+struct audio_mvs_set_g711A_mode_msg {
+	struct rpc_request_hdr rpc_hdr;
+	uint32_t g711A_mode;
+};
+
+/* Parameters for EFR FR and HR mode */
+struct audio_mvs_set_efr_mode_msg {
+	struct rpc_request_hdr rpc_hdr;
+	uint32_t efr_mode;
+};
+
+union audio_mvs_event_data {
+	struct mvs_ev_command_type {
+		uint32_t event;
+		uint32_t client_id;
+		uint32_t cmd_status;
+	} mvs_ev_command_type;
+
+	struct mvs_ev_mode_type {
+		uint32_t event;
+		uint32_t client_id;
+		uint32_t mode_status;
+		uint32_t mode;
+	} mvs_ev_mode_type;
+
+	struct mvs_ev_notify_type {
+		uint32_t event;
+		uint32_t client_id;
+		uint32_t buf_dir;
+		uint32_t max_frames;
+	} mvs_ev_notify_type;
+};
+
+struct audio_mvs_cb_func_args {
+	uint32_t cb_func_id;
+	uint32_t valid_ptr;
+	uint32_t event;
+	union audio_mvs_event_data event_data;
+};
+
+struct audio_mvs_frame_info_hdr {
+	uint32_t frame_mode;
+	uint32_t mvs_mode;
+	uint16_t buf_free_cnt;
+};
+
+struct audio_mvs_ul_reply {
+	struct rpc_reply_hdr reply_hdr;
+	uint32_t valid_pkt_status_ptr;
+	uint32_t pkt_status;
+};
+
+struct audio_mvs_dl_cb_func_args {
+	uint32_t cb_func_id;
+
+	uint32_t valid_ptr;
+	uint32_t frame_mode;
+	uint32_t frame_mode_ignore;
+
+	struct audio_mvs_frame_info_hdr frame_info_hdr;
+
+	uint32_t amr_frame;
+	uint32_t amr_mode;
+};
+/*general codec parameters includes AMR, G711A, PCM
+G729, VOC and HR vocoders
+*/
+struct gnr_cdc_param {
+	uint32_t param1;
+	uint32_t param2;
+	uint32_t valid_pkt_status_ptr;
+	uint32_t pkt_status;
+};
+/*G711 codec parameter*/
+struct g711_param {
+	uint32_t param1;
+	uint32_t valid_pkt_status_ptr;
+	uint32_t pkt_status;
+};
+
+union codec_param {
+	struct gnr_cdc_param gnr_arg;
+	struct g711_param g711_arg;
+};
+
+struct audio_mvs_dl_reply {
+	struct rpc_reply_hdr reply_hdr;
+
+	uint32_t voc_pkt[MVS_MAX_VOC_PKT_SIZE/4];
+
+	uint32_t valid_frame_info_ptr;
+	uint32_t frame_mode;
+	uint32_t frame_mode_again;
+
+	struct audio_mvs_frame_info_hdr frame_info_hdr;
+	union codec_param cdc_param;
+};
+
+struct audio_mvs_buf_node {
+	struct list_head list;
+	struct msm_audio_mvs_frame frame;
+};
+
+/* Each buffer is 20 ms, queue holds 200 ms of data. */
+#define MVS_MAX_Q_LEN 10
+
+struct audio_mvs_info_type {
+	enum audio_mvs_state_type state;
+	uint32_t frame_mode;
+	uint32_t mvs_mode;
+	uint32_t buf_free_cnt;
+	uint32_t rate_type;
+	uint32_t dtx_mode;
+
+	struct msm_rpc_endpoint *rpc_endpt;
+	uint32_t rpc_prog;
+	uint32_t rpc_ver;
+	uint32_t rpc_status;
+
+	uint8_t *mem_chunk;
+
+	struct list_head in_queue;
+	struct list_head free_in_queue;
+
+	struct list_head out_queue;
+	struct list_head free_out_queue;
+
+	struct task_struct *task;
+
+	wait_queue_head_t wait;
+	wait_queue_head_t mode_wait;
+	wait_queue_head_t out_wait;
+
+	struct mutex lock;
+	struct mutex in_lock;
+	struct mutex out_lock;
+
+	struct wake_lock suspend_lock;
+	struct wake_lock idle_lock;
+};
+
+static struct audio_mvs_info_type audio_mvs_info;
+
+static int audio_mvs_setup_mode(struct audio_mvs_info_type *audio)
+{
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	switch (audio->mvs_mode) {
+	case MVS_MODE_AMR:
+	case MVS_MODE_AMR_WB: {
+		struct audio_mvs_set_amr_mode_msg set_amr_mode_msg;
+		struct audio_mvs_set_dtx_mode_msg set_dtx_mode_msg;
+
+		/* Set AMR mode. */
+		memset(&set_amr_mode_msg, 0, sizeof(set_amr_mode_msg));
+		set_amr_mode_msg.amr_mode = cpu_to_be32(audio->rate_type);
+
+		if (audio->mvs_mode == MVS_MODE_AMR) {
+			msm_rpc_setup_req(&set_amr_mode_msg.rpc_hdr,
+					  audio->rpc_prog,
+					  audio->rpc_ver,
+					  MVS_AMR_SET_AMR_MODE_PROC);
+		} else {
+			msm_rpc_setup_req(&set_amr_mode_msg.rpc_hdr,
+					  audio->rpc_prog,
+					  audio->rpc_ver,
+					  MVS_AMR_SET_AWB_MODE_PROC);
+		}
+
+		audio->rpc_status = RPC_STATUS_FAILURE;
+		rc = msm_rpc_write(audio->rpc_endpt,
+				   &set_amr_mode_msg,
+				   sizeof(set_amr_mode_msg));
+
+		if (rc >= 0) {
+			MM_DBG("RPC write for set amr mode done\n");
+
+			/* Save the MVS configuration information. */
+			audio->frame_mode = MVS_FRAME_MODE_AMR_DL;
+
+			/* Disable DTX. */
+			memset(&set_dtx_mode_msg, 0, sizeof(set_dtx_mode_msg));
+			set_dtx_mode_msg.dtx_mode = cpu_to_be32(0);
+
+			msm_rpc_setup_req(&set_dtx_mode_msg.rpc_hdr,
+					  audio->rpc_prog,
+					  audio->rpc_ver,
+					  MVS_SET_DTX_MODE_PROC);
+
+			audio->rpc_status = RPC_STATUS_FAILURE;
+			rc = msm_rpc_write(audio->rpc_endpt,
+					   &set_dtx_mode_msg,
+					   sizeof(set_dtx_mode_msg));
+
+			if (rc >= 0) {
+				MM_DBG("RPC write for set dtx done\n");
+
+				rc = 0;
+			}
+		} else {
+			MM_ERR("RPC write for set amr mode failed %d\n", rc);
+		}
+		break;
+	}
+	case MVS_MODE_PCM:
+	case MVS_MODE_LINEAR_PCM: {
+		/* PCM does not have any params to be set.
+		Save the MVS configuration information. */
+		audio->rate_type = MVS_AMR_MODE_UNDEF;
+		audio->frame_mode = MVS_FRAME_MODE_PCM_DL;
+		break;
+	}
+	case MVS_MODE_PCM_WB: {
+		audio->rate_type = MVS_AMR_MODE_UNDEF;
+		audio->frame_mode = MVS_FRAME_MODE_PCM_WB_DL;
+		break;
+	}
+	case MVS_MODE_IS127:
+	case MVS_MODE_IS733:
+	case MVS_MODE_4GV_NB:
+	case MVS_MODE_4GV_WB: {
+		struct audio_mvs_set_voc_mode_msg set_voc_mode_msg;
+
+		/* Set EVRC mode. */
+		memset(&set_voc_mode_msg, 0, sizeof(set_voc_mode_msg));
+		set_voc_mode_msg.min_rate = cpu_to_be32(audio->rate_type);
+		set_voc_mode_msg.max_rate = cpu_to_be32(audio->rate_type);
+
+		msm_rpc_setup_req(&set_voc_mode_msg.rpc_hdr,
+				  audio->rpc_prog,
+				  audio->rpc_ver,
+				  MVS_VOC_SET_FRAME_RATE_PROC);
+
+		audio->rpc_status = RPC_STATUS_FAILURE;
+		rc = msm_rpc_write(audio->rpc_endpt,
+				   &set_voc_mode_msg,
+				   sizeof(set_voc_mode_msg));
+
+		if (rc >= 0) {
+			MM_DBG("RPC write for set voc mode done\n");
+
+			/* Save the MVS configuration information. */
+			audio->frame_mode = MVS_FRAME_MODE_VOC_RX;
+
+			rc = 0;
+		} else {
+			MM_ERR("RPC write for set voc mode failed %d\n", rc);
+		}
+		break;
+	}
+	case MVS_MODE_G711: {
+		struct audio_mvs_set_g711_mode_msg set_g711_mode_msg;
+
+		/* Set G711 mode. */
+		memset(&set_g711_mode_msg, 0, sizeof(set_g711_mode_msg));
+		set_g711_mode_msg.g711_mode = cpu_to_be32(audio->rate_type);
+
+		MM_DBG("mode of g711:%d\n", set_g711_mode_msg.g711_mode);
+
+		msm_rpc_setup_req(&set_g711_mode_msg.rpc_hdr,
+				 audio->rpc_prog,
+				 audio->rpc_ver,
+				 MVS_G711_SET_MODE_PROC);
+
+		audio->rpc_status = RPC_STATUS_FAILURE;
+		rc = msm_rpc_write(audio->rpc_endpt,
+				  &set_g711_mode_msg,
+				  sizeof(set_g711_mode_msg));
+
+		if (rc >= 0) {
+			MM_DBG("RPC write for set g711 mode done\n");
+			/* Save the MVS configuration information. */
+			audio->frame_mode = MVS_FRAME_MODE_G711_DL;
+
+			rc = 0;
+		} else {
+		       MM_ERR("RPC write for set g711 mode failed %d\n", rc);
+		}
+		break;
+	}
+	case MVS_MODE_G729A: {
+		struct audio_mvs_set_g729_mode_msg set_g729_mode_msg;
+
+		/* Set G729 mode. */
+		memset(&set_g729_mode_msg, 0, sizeof(set_g729_mode_msg));
+		set_g729_mode_msg.g729_mode = cpu_to_be32(audio->dtx_mode);
+
+		MM_DBG("mode of g729:%d\n",
+			       set_g729_mode_msg.g729_mode);
+
+		msm_rpc_setup_req(&set_g729_mode_msg.rpc_hdr,
+				 audio->rpc_prog,
+				 audio->rpc_ver,
+				 MVS_G729A_SET_MODE_PROC);
+
+		audio->rpc_status = RPC_STATUS_FAILURE;
+		rc = msm_rpc_write(audio->rpc_endpt,
+				  &set_g729_mode_msg,
+				  sizeof(set_g729_mode_msg));
+
+		if (rc >= 0) {
+			MM_DBG("RPC write for set g729 mode done\n");
+
+			/* Save the MVS configuration information. */
+			audio->frame_mode = MVS_FRAME_MODE_G729A_DL;
+
+			rc = 0;
+		} else {
+		       MM_ERR("RPC write for set g729 mode failed %d\n", rc);
+		}
+		break;
+	}
+	case MVS_MODE_G722: {
+		struct audio_mvs_set_g722_mode_msg set_g722_mode_msg;
+
+		/* Set G722 mode. */
+		memset(&set_g722_mode_msg, 0, sizeof(set_g722_mode_msg));
+		set_g722_mode_msg.g722_mode = cpu_to_be32(audio->rate_type);
+
+		MM_DBG("mode of g722:%d\n",
+		      set_g722_mode_msg.g722_mode);
+
+		msm_rpc_setup_req(&set_g722_mode_msg.rpc_hdr,
+			audio->rpc_prog,
+			audio->rpc_ver,
+			MVS_G722_SET_MODE_PROC);
+
+		audio->rpc_status = RPC_STATUS_FAILURE;
+		rc = msm_rpc_write(audio->rpc_endpt,
+			 &set_g722_mode_msg,
+			 sizeof(set_g722_mode_msg));
+
+		if (rc >= 0) {
+			MM_DBG("RPC write for set g722 mode done\n");
+
+			/* Save the MVS configuration information. */
+			audio->frame_mode = MVS_FRAME_MODE_G722_DL;
+
+			rc = 0;
+		}
+		break;
+	}
+	case MVS_MODE_G711A: {
+		struct audio_mvs_set_g711A_mode_msg set_g711A_mode_msg;
+		struct audio_mvs_set_dtx_mode_msg set_dtx_mode_msg;
+
+		/* Set G711A mode. */
+		memset(&set_g711A_mode_msg, 0, sizeof(set_g711A_mode_msg));
+		set_g711A_mode_msg.g711A_mode = cpu_to_be32(audio->rate_type);
+
+		MM_DBG("mode of g711A:%d\n",
+		       set_g711A_mode_msg.g711A_mode);
+
+		msm_rpc_setup_req(&set_g711A_mode_msg.rpc_hdr,
+			 audio->rpc_prog,
+			 audio->rpc_ver,
+			 MVS_G711A_SET_MODE_PROC);
+
+		audio->rpc_status = RPC_STATUS_FAILURE;
+		rc = msm_rpc_write(audio->rpc_endpt,
+			  &set_g711A_mode_msg,
+			  sizeof(set_g711A_mode_msg));
+
+		if (rc >= 0) {
+			MM_DBG("RPC write for set g711A mode done\n");
+
+			/* Save the MVS configuration information. */
+			audio->frame_mode = MVS_FRAME_MODE_G711A_DL;
+			/* Set DTX MODE. */
+			memset(&set_dtx_mode_msg, 0, sizeof(set_dtx_mode_msg));
+			set_dtx_mode_msg.dtx_mode =
+				cpu_to_be32((audio->dtx_mode));
+
+			msm_rpc_setup_req(&set_dtx_mode_msg.rpc_hdr,
+					  audio->rpc_prog,
+					  audio->rpc_ver,
+					  MVS_SET_DTX_MODE_PROC);
+
+			audio->rpc_status = RPC_STATUS_FAILURE;
+			rc = msm_rpc_write(audio->rpc_endpt,
+					   &set_dtx_mode_msg,
+					   sizeof(set_dtx_mode_msg));
+
+			if (rc >= 0) {
+				MM_DBG("RPC write for set dtx done\n");
+
+				rc = 0;
+			}
+			rc = 0;
+		} else {
+		MM_ERR("RPC write for set g711A mode failed %d\n", rc);
+		}
+		break;
+	}
+	case MVS_MODE_EFR:
+	case MVS_MODE_FR:
+	case MVS_MODE_HR: {
+		struct audio_mvs_set_efr_mode_msg set_efr_mode_msg;
+
+		/* Set G729 mode. */
+		memset(&set_efr_mode_msg, 0, sizeof(set_efr_mode_msg));
+		set_efr_mode_msg.efr_mode = cpu_to_be32(audio->dtx_mode);
+
+		MM_DBG("mode of EFR, FR and HR:%d\n",
+			       set_efr_mode_msg.efr_mode);
+
+		msm_rpc_setup_req(&set_efr_mode_msg.rpc_hdr,
+				 audio->rpc_prog,
+				 audio->rpc_ver,
+				 MVS_GSM_SET_DTX_MODE_PROC);
+
+		audio->rpc_status = RPC_STATUS_FAILURE;
+		rc = msm_rpc_write(audio->rpc_endpt,
+				  &set_efr_mode_msg,
+				  sizeof(set_efr_mode_msg));
+
+		if (rc >= 0) {
+			MM_DBG("RPC write for set EFR, FR and HR mode done\n");
+
+			/* Save the MVS configuration information. */
+			if ((audio->mvs_mode == MVS_MODE_EFR) ||
+				(audio->mvs_mode == MVS_MODE_FR))
+				audio->frame_mode = MVS_FRAME_MODE_GSM_DL;
+			if (audio->mvs_mode == MVS_MODE_HR)
+				audio->frame_mode = MVS_FRAME_MODE_HR_DL;
+
+			rc = 0;
+		} else {
+			MM_ERR("RPC write for set EFR, FR"
+				"and HR mode failed %d\n", rc);
+		}
+		break;
+	}
+	default:
+		rc = -EINVAL;
+		MM_ERR("Default case\n");
+	}
+	return rc;
+}
+
+static int audio_mvs_setup(struct audio_mvs_info_type *audio)
+{
+	int rc = 0;
+	struct audio_mvs_enable_msg enable_msg;
+
+	MM_DBG("\n");
+
+	/* Enable MVS. */
+	memset(&enable_msg, 0, sizeof(enable_msg));
+	enable_msg.enable_args.client_id = cpu_to_be32(MVS_CLIENT_ID_VOIP);
+	enable_msg.enable_args.mode = cpu_to_be32(audio->mvs_mode);
+	enable_msg.enable_args.ul_cb_func_id = cpu_to_be32(MVS_UL_CB_FUNC_ID);
+	enable_msg.enable_args.dl_cb_func_id = cpu_to_be32(MVS_DL_CB_FUNC_ID);
+	enable_msg.enable_args.context = cpu_to_be32(MVS_PKT_CONTEXT_ISR);
+
+	msm_rpc_setup_req(&enable_msg.rpc_hdr,
+			  audio->rpc_prog,
+			  audio->rpc_ver,
+			  MVS_ENABLE_PROC);
+
+	audio->rpc_status = RPC_STATUS_FAILURE;
+	rc = msm_rpc_write(audio->rpc_endpt, &enable_msg, sizeof(enable_msg));
+
+	if (rc >= 0) {
+		MM_DBG("RPC write for enable done\n");
+
+		rc = wait_event_timeout(audio->mode_wait,
+				(audio->rpc_status != RPC_STATUS_FAILURE),
+				10 * HZ);
+
+		if (rc > 0) {
+			MM_DBG("Wait event for enable succeeded\n");
+			rc = audio_mvs_setup_mode(audio);
+			if (rc < 0) {
+				MM_ERR("Unknown MVS mode %d\n",
+				       audio->mvs_mode);
+			}
+			MM_ERR("rc value after mode setup: %d\n", rc);
+		} else {
+			MM_ERR("Wait event for enable failed %d\n", rc);
+		}
+	} else {
+		MM_ERR("RPC write for enable failed %d\n", rc);
+	}
+
+	return rc;
+}
+
+static int audio_mvs_start(struct audio_mvs_info_type *audio)
+{
+	int rc = 0;
+	struct audio_mvs_acquire_msg acquire_msg;
+
+	MM_DBG("\n");
+
+	/* Prevent sleep. */
+	wake_lock(&audio->suspend_lock);
+	wake_lock(&audio->idle_lock);
+
+	/* Acquire MVS. */
+	memset(&acquire_msg, 0, sizeof(acquire_msg));
+	acquire_msg.acquire_args.client_id = cpu_to_be32(MVS_CLIENT_ID_VOIP);
+	acquire_msg.acquire_args.cb_func_id = cpu_to_be32(MVS_CB_FUNC_ID);
+
+	msm_rpc_setup_req(&acquire_msg.rpc_hdr,
+			  audio->rpc_prog,
+			  audio->rpc_ver,
+			  MVS_ACQUIRE_PROC);
+
+	audio->rpc_status = RPC_STATUS_FAILURE;
+	rc = msm_rpc_write(audio->rpc_endpt,
+			   &acquire_msg,
+			   sizeof(acquire_msg));
+
+	if (rc >= 0) {
+		MM_DBG("RPC write for acquire done\n");
+
+		rc = wait_event_timeout(audio->wait,
+			(audio->rpc_status != RPC_STATUS_FAILURE),
+			1 * HZ);
+
+		if (rc > 0) {
+
+			rc = audio_mvs_setup(audio);
+
+			if (rc == 0)
+				audio->state = AUDIO_MVS_STARTED;
+
+		} else {
+			MM_ERR("Wait event for acquire failed %d\n", rc);
+
+			rc = -EBUSY;
+		}
+	} else {
+		MM_ERR("RPC write for acquire failed %d\n", rc);
+
+		rc = -EBUSY;
+	}
+
+	return rc;
+}
+
+static int audio_mvs_stop(struct audio_mvs_info_type *audio)
+{
+	int rc = 0;
+	struct audio_mvs_release_msg release_msg;
+
+	MM_DBG("\n");
+
+	/* Release MVS. */
+	memset(&release_msg, 0, sizeof(release_msg));
+	release_msg.client_id = cpu_to_be32(MVS_CLIENT_ID_VOIP);
+
+	msm_rpc_setup_req(&release_msg.rpc_hdr,
+			  audio->rpc_prog,
+			  audio->rpc_ver,
+			  MVS_RELEASE_PROC);
+
+	audio->rpc_status = RPC_STATUS_FAILURE;
+	rc = msm_rpc_write(audio->rpc_endpt, &release_msg, sizeof(release_msg));
+
+	if (rc >= 0) {
+		MM_DBG("RPC write for release done\n");
+
+		rc = wait_event_timeout(audio->mode_wait,
+				(audio->rpc_status != RPC_STATUS_FAILURE),
+				1 * HZ);
+
+		if (rc > 0) {
+			MM_DBG("Wait event for release succeeded\n");
+
+			audio->state = AUDIO_MVS_STOPPED;
+
+			/* Un-block read in case it is waiting for data. */
+			wake_up(&audio->out_wait);
+			rc = 0;
+		} else {
+			MM_ERR("Wait event for release failed %d\n", rc);
+		}
+	} else {
+		MM_ERR("RPC write for release failed %d\n", rc);
+	}
+
+	/* Allow sleep. */
+	wake_unlock(&audio->suspend_lock);
+	wake_unlock(&audio->idle_lock);
+
+	return rc;
+}
+
+static void audio_mvs_process_rpc_request(uint32_t procedure,
+					  uint32_t xid,
+					  void *data,
+					  uint32_t length,
+					  struct audio_mvs_info_type *audio)
+{
+	int rc = 0;
+
+	MM_DBG("\n");
+
+	switch (procedure) {
+	case MVS_EVENT_CB_TYPE_PROC: {
+		struct audio_mvs_cb_func_args *args = data;
+		struct rpc_reply_hdr reply_hdr;
+
+		MM_DBG("MVS CB CB_FUNC_ID 0x%x\n",
+			 be32_to_cpu(args->cb_func_id));
+
+		if (be32_to_cpu(args->valid_ptr)) {
+			uint32_t event_type = be32_to_cpu(args->event);
+
+			MM_DBG("MVS CB event type %d\n",
+				 be32_to_cpu(args->event));
+
+			if (event_type == AUDIO_MVS_COMMAND) {
+				uint32_t cmd_status = be32_to_cpu(
+			args->event_data.mvs_ev_command_type.cmd_status);
+
+				MM_DBG("MVS CB command status %d\n",
+					cmd_status);
+
+				if (cmd_status == AUDIO_MVS_CMD_SUCCESS) {
+					audio->rpc_status = RPC_STATUS_SUCCESS;
+					wake_up(&audio->wait);
+				}
+
+			} else if (event_type == AUDIO_MVS_MODE) {
+				uint32_t mode_status = be32_to_cpu(
+				args->event_data.mvs_ev_mode_type.mode_status);
+
+				MM_DBG("MVS CB mode status %d\n", mode_status);
+
+				if (mode_status == AUDIO_MVS_MODE_READY) {
+					audio->rpc_status = RPC_STATUS_SUCCESS;
+					wake_up(&audio->mode_wait);
+				}
+			} else {
+				MM_ERR("MVS CB unknown event type %d\n",
+					event_type);
+			}
+		} else {
+			MM_ERR("MVS CB event pointer not valid\n");
+		}
+
+		/* Send ack to modem. */
+		memset(&reply_hdr, 0, sizeof(reply_hdr));
+		reply_hdr.xid = cpu_to_be32(xid);
+		reply_hdr.type = cpu_to_be32(RPC_TYPE_REPLY);
+		reply_hdr.reply_stat = cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED);
+
+		reply_hdr.data.acc_hdr.accept_stat = cpu_to_be32(
+			RPC_ACCEPTSTAT_SUCCESS);
+		reply_hdr.data.acc_hdr.verf_flavor = 0;
+		reply_hdr.data.acc_hdr.verf_length = 0;
+
+		rc = msm_rpc_write(audio->rpc_endpt,
+				   &reply_hdr,
+				   sizeof(reply_hdr));
+
+		if (rc < 0)
+			MM_ERR("RPC write for response failed %d\n", rc);
+
+		break;
+	}
+
+	case MVS_PACKET_UL_FN_TYPE_PROC: {
+		uint32_t *args = data;
+		uint32_t pkt_len;
+		uint32_t frame_mode;
+		struct audio_mvs_ul_reply ul_reply;
+		struct audio_mvs_buf_node *buf_node = NULL;
+
+		MM_DBG("MVS UL CB_FUNC_ID 0x%x\n",
+			 be32_to_cpu(*args));
+		args++;
+
+		pkt_len = be32_to_cpu(*args);
+		MM_DBG("UL pkt_len %d\n", pkt_len);
+		args++;
+
+		/* Copy the vocoder packets. */
+		mutex_lock(&audio->out_lock);
+
+		if (!list_empty(&audio->free_out_queue)) {
+			buf_node = list_first_entry(&audio->free_out_queue,
+						    struct audio_mvs_buf_node,
+						    list);
+			list_del(&buf_node->list);
+
+			memcpy(&buf_node->frame.voc_pkt[0], args, pkt_len);
+			buf_node->frame.len = pkt_len;
+			pkt_len = ALIGN(pkt_len, 4);
+			args = args + pkt_len/4;
+
+			MM_DBG("UL valid_ptr 0x%x\n",
+				 be32_to_cpu(*args));
+			args++;
+
+			frame_mode = be32_to_cpu(*args);
+			MM_DBG("UL frame_mode %d\n",
+				 frame_mode);
+			args++;
+
+			MM_DBG("UL frame_mode %d\n",
+				 be32_to_cpu(*args));
+			args++;
+
+			MM_DBG("UL frame_mode %d\n",
+				 be32_to_cpu(*args));
+			args++;
+
+			MM_DBG("UL mvs_mode %d\n",
+				 be32_to_cpu(*args));
+			args++;
+
+			MM_DBG("UL buf_free_cnt %d\n",
+				 be32_to_cpu(*args));
+			args++;
+
+			if (frame_mode == MVS_FRAME_MODE_AMR_UL) {
+				/* Extract AMR frame type. */
+				buf_node->frame.frame_type = be32_to_cpu(*args);
+
+				MM_DBG("UL AMR frame_type %d\n",
+					 be32_to_cpu(*args));
+			} else if ((frame_mode == MVS_FRAME_MODE_PCM_UL) ||
+				   (frame_mode == MVS_FRAME_MODE_VOC_TX)) {
+				/* PCM and EVRC don't have frame_type */
+				buf_node->frame.frame_type = 0;
+			} else if (frame_mode == MVS_FRAME_MODE_G711_UL) {
+				/* Extract G711 frame type. */
+				buf_node->frame.frame_type = be32_to_cpu(*args);
+
+				MM_DBG("UL G711 frame_type %d\n",
+					be32_to_cpu(*args));
+			} else if (frame_mode == MVS_FRAME_MODE_G729A_UL) {
+				/* Extract G729 frame type. */
+				buf_node->frame.frame_type = be32_to_cpu(*args);
+
+				MM_DBG("UL G729 frame_type %d\n",
+					be32_to_cpu(*args));
+			} else if (frame_mode == MVS_FRAME_MODE_G722_UL) {
+				/* Extract G722 frame type. */
+				buf_node->frame.frame_type = be32_to_cpu(*args);
+
+				MM_DBG("UL G722 frame_type %d\n",
+				       be32_to_cpu(*args));
+			} else if (frame_mode == MVS_FRAME_MODE_G711A_UL) {
+				/* Extract G711A frame type. */
+				buf_node->frame.frame_type = be32_to_cpu(*args);
+
+				MM_DBG("UL G711A frame_type %d\n",
+				       be32_to_cpu(*args));
+			} else if ((frame_mode == MVS_FRAME_MODE_GSM_UL) ||
+				   (frame_mode == MVS_FRAME_MODE_HR_UL)) {
+				/* Extract EFR, FR and HR frame type. */
+				buf_node->frame.frame_type = be32_to_cpu(*args);
+
+				MM_DBG("UL EFR,FR,HR frame_type %d\n",
+					be32_to_cpu(*args));
+			} else {
+				MM_DBG("UL Unknown frame mode %d\n",
+				       frame_mode);
+			}
+
+			list_add_tail(&buf_node->list, &audio->out_queue);
+		} else {
+			MM_ERR("UL data dropped, read is slow\n");
+		}
+
+		mutex_unlock(&audio->out_lock);
+
+		wake_up(&audio->out_wait);
+
+		/* Send UL message accept to modem. */
+		memset(&ul_reply, 0, sizeof(ul_reply));
+		ul_reply.reply_hdr.xid = cpu_to_be32(xid);
+		ul_reply.reply_hdr.type = cpu_to_be32(RPC_TYPE_REPLY);
+		ul_reply.reply_hdr.reply_stat = cpu_to_be32(
+			RPCMSG_REPLYSTAT_ACCEPTED);
+
+		ul_reply.reply_hdr.data.acc_hdr.accept_stat = cpu_to_be32(
+			RPC_ACCEPTSTAT_SUCCESS);
+		ul_reply.reply_hdr.data.acc_hdr.verf_flavor = 0;
+		ul_reply.reply_hdr.data.acc_hdr.verf_length = 0;
+
+		ul_reply.valid_pkt_status_ptr = cpu_to_be32(0x00000001);
+		ul_reply.pkt_status = cpu_to_be32(0x00000000);
+
+		rc = msm_rpc_write(audio->rpc_endpt,
+				   &ul_reply,
+				   sizeof(ul_reply));
+
+		if (rc < 0)
+			MM_ERR("RPC write for UL response failed %d\n",
+			       rc);
+
+		break;
+	}
+
+	case MVS_PACKET_DL_FN_TYPE_PROC: {
+		struct audio_mvs_dl_cb_func_args *args = data;
+		struct audio_mvs_dl_reply dl_reply;
+		uint32_t frame_mode;
+		struct audio_mvs_buf_node *buf_node = NULL;
+
+		MM_DBG("MVS DL CB CB_FUNC_ID 0x%x\n",
+			 be32_to_cpu(args->cb_func_id));
+
+		frame_mode = be32_to_cpu(args->frame_mode);
+		MM_DBG("DL frame_mode %d\n", frame_mode);
+
+		/* Prepare and send the DL packets to modem. */
+		memset(&dl_reply, 0, sizeof(dl_reply));
+		dl_reply.reply_hdr.xid = cpu_to_be32(xid);
+		dl_reply.reply_hdr.type = cpu_to_be32(RPC_TYPE_REPLY);
+		dl_reply.reply_hdr.reply_stat = cpu_to_be32(
+			RPCMSG_REPLYSTAT_ACCEPTED);
+
+		dl_reply.reply_hdr.data.acc_hdr.accept_stat = cpu_to_be32(
+			RPC_ACCEPTSTAT_SUCCESS);
+		dl_reply.reply_hdr.data.acc_hdr.verf_flavor = 0;
+		dl_reply.reply_hdr.data.acc_hdr.verf_length = 0;
+
+		mutex_lock(&audio->in_lock);
+
+		if (!list_empty(&audio->in_queue)) {
+			buf_node = list_first_entry(&audio->in_queue,
+						    struct audio_mvs_buf_node,
+						    list);
+			list_del(&buf_node->list);
+
+			memcpy(&dl_reply.voc_pkt,
+			       &buf_node->frame.voc_pkt[0],
+			       buf_node->frame.len);
+
+			MM_DBG("frame mode %d buf_node->frame.len %d\n",
+				 frame_mode, buf_node->frame.len);
+			if (frame_mode == MVS_FRAME_MODE_AMR_DL) {
+				dl_reply.cdc_param.gnr_arg.param1 = cpu_to_be32(
+					buf_node->frame.frame_type);
+				dl_reply.cdc_param.gnr_arg.param2 =
+						cpu_to_be32(audio->rate_type);
+				dl_reply.cdc_param.\
+						gnr_arg.valid_pkt_status_ptr =
+							cpu_to_be32(0x00000001);
+				dl_reply.cdc_param.gnr_arg.pkt_status =
+					cpu_to_be32(AUDIO_MVS_PKT_NORMAL);
+			} else if (frame_mode == MVS_FRAME_MODE_PCM_DL) {
+				dl_reply.cdc_param.gnr_arg.param1 = 0;
+				dl_reply.cdc_param.gnr_arg.param2 = 0;
+				dl_reply.cdc_param.\
+						gnr_arg.valid_pkt_status_ptr =
+							cpu_to_be32(0x00000001);
+				dl_reply.cdc_param.gnr_arg.pkt_status =
+					cpu_to_be32(AUDIO_MVS_PKT_NORMAL);
+			} else if (frame_mode == MVS_FRAME_MODE_VOC_RX) {
+				dl_reply.cdc_param.gnr_arg.param1 =
+						cpu_to_be32(audio->rate_type);
+				dl_reply.cdc_param.gnr_arg.param2 = 0;
+				dl_reply.cdc_param.\
+						gnr_arg.valid_pkt_status_ptr =
+							cpu_to_be32(0x00000001);
+				dl_reply.cdc_param.gnr_arg.pkt_status =
+					cpu_to_be32(AUDIO_MVS_PKT_NORMAL);
+			} else if (frame_mode == MVS_FRAME_MODE_G711_DL) {
+				dl_reply.cdc_param.g711_arg.param1 =
+				cpu_to_be32(buf_node->frame.frame_type);
+				dl_reply.cdc_param.\
+						g711_arg.valid_pkt_status_ptr =
+							cpu_to_be32(0x00000001);
+				dl_reply.cdc_param.g711_arg.pkt_status =
+					cpu_to_be32(AUDIO_MVS_PKT_NORMAL);
+			} else if (frame_mode == MVS_FRAME_MODE_G729A_DL) {
+				dl_reply.cdc_param.gnr_arg.param1 = cpu_to_be32(
+				       buf_node->frame.frame_type);
+				dl_reply.cdc_param.gnr_arg.param2 =
+						cpu_to_be32(audio->rate_type);
+				dl_reply.cdc_param.\
+						gnr_arg.valid_pkt_status_ptr =
+							cpu_to_be32(0x00000001);
+				dl_reply.cdc_param.gnr_arg.pkt_status =
+					cpu_to_be32(AUDIO_MVS_PKT_NORMAL);
+			} else if (frame_mode == MVS_FRAME_MODE_G722_DL) {
+				dl_reply.cdc_param.gnr_arg.param1 = cpu_to_be32(
+				      buf_node->frame.frame_type);
+				dl_reply.cdc_param.gnr_arg.param2 =
+						cpu_to_be32(audio->rate_type);
+				dl_reply.cdc_param.\
+						gnr_arg.valid_pkt_status_ptr =
+							cpu_to_be32(0x00000001);
+				dl_reply.cdc_param.gnr_arg.pkt_status =
+					cpu_to_be32(AUDIO_MVS_PKT_NORMAL);
+			} else if (frame_mode == MVS_FRAME_MODE_G711A_DL) {
+				dl_reply.cdc_param.gnr_arg.param1 = cpu_to_be32(
+				       buf_node->frame.frame_type);
+				dl_reply.cdc_param.gnr_arg.param2 =
+						cpu_to_be32(audio->rate_type);
+				dl_reply.cdc_param.\
+						gnr_arg.valid_pkt_status_ptr =
+							cpu_to_be32(0x00000001);
+				dl_reply.cdc_param.gnr_arg.pkt_status =
+					cpu_to_be32(AUDIO_MVS_PKT_NORMAL);
+			} else if ((frame_mode == MVS_FRAME_MODE_GSM_DL) ||
+				   (frame_mode == MVS_FRAME_MODE_HR_DL)) {
+				dl_reply.cdc_param.gnr_arg.param1 = cpu_to_be32(
+				       buf_node->frame.frame_type);
+				dl_reply.cdc_param.gnr_arg.param2 =
+						cpu_to_be32(audio->rate_type);
+				dl_reply.cdc_param.\
+						gnr_arg.valid_pkt_status_ptr =
+							cpu_to_be32(0x00000001);
+				dl_reply.cdc_param.gnr_arg.pkt_status =
+					cpu_to_be32(AUDIO_MVS_PKT_NORMAL);
+			} else {
+				MM_ERR("DL Unknown frame mode %d\n",
+				       frame_mode);
+			}
+			list_add_tail(&buf_node->list, &audio->free_in_queue);
+		} else {
+			MM_DBG("No DL data available to send to MVS\n");
+			if (frame_mode == MVS_FRAME_MODE_G711_DL) {
+				dl_reply.cdc_param.\
+						g711_arg.valid_pkt_status_ptr =
+							cpu_to_be32(0x00000001);
+				dl_reply.cdc_param.g711_arg.pkt_status =
+						cpu_to_be32(AUDIO_MVS_PKT_SLOW);
+			} else {
+				dl_reply.cdc_param.\
+						gnr_arg.valid_pkt_status_ptr =
+							cpu_to_be32(0x00000001);
+				dl_reply.cdc_param.gnr_arg.pkt_status =
+						cpu_to_be32(AUDIO_MVS_PKT_SLOW);
+			}
+		}
+
+		mutex_unlock(&audio->in_lock);
+
+		dl_reply.valid_frame_info_ptr = cpu_to_be32(0x00000001);
+
+		dl_reply.frame_mode = cpu_to_be32(audio->frame_mode);
+		dl_reply.frame_mode_again = cpu_to_be32(audio->frame_mode);
+
+		dl_reply.frame_info_hdr.frame_mode =
+			cpu_to_be32(audio->frame_mode);
+		dl_reply.frame_info_hdr.mvs_mode = cpu_to_be32(audio->mvs_mode);
+		dl_reply.frame_info_hdr.buf_free_cnt = 0;
+
+		rc = msm_rpc_write(audio->rpc_endpt,
+				   &dl_reply,
+				   sizeof(dl_reply));
+
+		if (rc < 0)
+			MM_ERR("RPC write for DL response failed %d\n",
+			       rc);
+
+		break;
+	}
+
+	default:
+		MM_ERR("Unknown CB type %d\n", procedure);
+	}
+}
+
+static int audio_mvs_thread(void *data)
+{
+	struct audio_mvs_info_type *audio = data;
+	struct rpc_request_hdr *rpc_hdr = NULL;
+
+	MM_DBG("\n");
+
+	while (!kthread_should_stop()) {
+
+		int rpc_hdr_len = msm_rpc_read(audio->rpc_endpt,
+					       (void **) &rpc_hdr,
+					       -1,
+					       -1);
+
+		if (rpc_hdr_len < 0) {
+			MM_ERR("RPC read failed %d\n",
+			       rpc_hdr_len);
+
+			break;
+		} else if (rpc_hdr_len < RPC_COMMON_HDR_SZ) {
+			continue;
+		} else {
+			uint32_t rpc_type = be32_to_cpu(rpc_hdr->type);
+			if (rpc_type == RPC_TYPE_REPLY) {
+				struct rpc_reply_hdr *rpc_reply =
+					(void *) rpc_hdr;
+				uint32_t reply_status;
+
+				if (rpc_hdr_len < RPC_REPLY_HDR_SZ)
+					continue;
+
+				reply_status =
+					be32_to_cpu(rpc_reply->reply_stat);
+
+				if (reply_status != RPCMSG_REPLYSTAT_ACCEPTED) {
+					/* If the command is not accepted, there
+					 * will be no response callback. Wake
+					 * the caller and report error. */
+					audio->rpc_status = RPC_STATUS_REJECT;
+
+					wake_up(&audio->wait);
+
+					MM_ERR("RPC reply status denied\n");
+				}
+			} else if (rpc_type == RPC_TYPE_REQUEST) {
+				if (rpc_hdr_len < RPC_REQUEST_HDR_SZ)
+					continue;
+
+				audio_mvs_process_rpc_request(
+					be32_to_cpu(rpc_hdr->procedure),
+					be32_to_cpu(rpc_hdr->xid),
+					(void *) (rpc_hdr + 1),
+					(rpc_hdr_len - sizeof(*rpc_hdr)),
+					audio);
+			} else {
+				MM_ERR("Unexpected RPC type %d\n", rpc_type);
+			}
+		}
+
+		kfree(rpc_hdr);
+		rpc_hdr = NULL;
+	}
+
+	MM_DBG("MVS thread stopped\n");
+
+	return 0;
+}
+
+static int audio_mvs_alloc_buf(struct audio_mvs_info_type *audio)
+{
+	int i = 0;
+	struct audio_mvs_buf_node *buf_node = NULL;
+	struct list_head *ptr = NULL;
+	struct list_head *next = NULL;
+
+	MM_DBG("\n");
+
+	/* Allocate input buffers. */
+	for (i = 0; i < MVS_MAX_Q_LEN; i++) {
+		buf_node = kmalloc(sizeof(struct audio_mvs_buf_node),
+				   GFP_KERNEL);
+
+		if (buf_node != NULL) {
+			list_add_tail(&buf_node->list,
+				      &audio->free_in_queue);
+		} else {
+			MM_ERR("No memory for IO buffers\n");
+			goto err;
+		}
+		buf_node = NULL;
+	}
+
+	/* Allocate output buffers. */
+	for (i = 0; i < MVS_MAX_Q_LEN; i++) {
+		buf_node = kmalloc(sizeof(struct audio_mvs_buf_node),
+				   GFP_KERNEL);
+
+		if (buf_node != NULL) {
+			list_add_tail(&buf_node->list,
+				      &audio->free_out_queue);
+		} else {
+			MM_ERR("No memory for IO buffers\n");
+			goto err;
+		}
+		buf_node = NULL;
+	}
+
+	return 0;
+
+err:
+	list_for_each_safe(ptr, next, &audio->free_in_queue) {
+		buf_node = list_entry(ptr, struct audio_mvs_buf_node, list);
+		list_del(&buf_node->list);
+		kfree(buf_node);
+		buf_node = NULL;
+	}
+
+	ptr = next = NULL;
+	list_for_each_safe(ptr, next, &audio->free_out_queue) {
+		buf_node = list_entry(ptr, struct audio_mvs_buf_node, list);
+		list_del(&buf_node->list);
+		kfree(buf_node);
+		buf_node = NULL;
+	}
+
+	return -ENOMEM;
+}
+
+static void audio_mvs_free_buf(struct audio_mvs_info_type *audio)
+{
+	struct list_head *ptr = NULL;
+	struct list_head *next = NULL;
+	struct audio_mvs_buf_node *buf_node = NULL;
+
+	MM_DBG("\n");
+
+	mutex_lock(&audio->in_lock);
+	/* Free input buffers. */
+	list_for_each_safe(ptr, next, &audio->in_queue) {
+		buf_node = list_entry(ptr, struct audio_mvs_buf_node, list);
+		list_del(&buf_node->list);
+		kfree(buf_node);
+		buf_node = NULL;
+	}
+
+	ptr = next = NULL;
+	/* Free free_input buffers. */
+	list_for_each_safe(ptr, next, &audio->free_in_queue) {
+		buf_node = list_entry(ptr, struct audio_mvs_buf_node, list);
+		list_del(&buf_node->list);
+		kfree(buf_node);
+		buf_node = NULL;
+	}
+	mutex_unlock(&audio->in_lock);
+
+	mutex_lock(&audio->out_lock);
+	ptr = next = NULL;
+	/* Free output buffers. */
+	list_for_each_safe(ptr, next, &audio->out_queue) {
+		buf_node = list_entry(ptr, struct audio_mvs_buf_node, list);
+		list_del(&buf_node->list);
+		kfree(buf_node);
+		buf_node = NULL;
+	}
+
+	/* Free free_ioutput buffers. */
+	ptr = next = NULL;
+	list_for_each_safe(ptr, next, &audio->free_out_queue) {
+		buf_node = list_entry(ptr, struct audio_mvs_buf_node, list);
+		list_del(&buf_node->list);
+		kfree(buf_node);
+		buf_node = NULL;
+	}
+	mutex_unlock(&audio->out_lock);
+}
+static int audio_mvs_release(struct inode *inode, struct file *file)
+{
+
+	struct audio_mvs_info_type *audio = file->private_data;
+
+	MM_DBG("\n");
+
+	mutex_lock(&audio->lock);
+	if (audio->state == AUDIO_MVS_STARTED)
+		audio_mvs_stop(audio);
+	audio_mvs_free_buf(audio);
+	audio->state = AUDIO_MVS_CLOSED;
+	mutex_unlock(&audio->lock);
+
+	MM_DBG("Release done\n");
+	return 0;
+}
+
+static ssize_t audio_mvs_read(struct file *file,
+			      char __user *buf,
+			      size_t count,
+			      loff_t *pos)
+{
+	int rc = 0;
+	struct audio_mvs_buf_node *buf_node = NULL;
+	struct audio_mvs_info_type *audio = file->private_data;
+
+	MM_DBG("\n");
+
+	rc = wait_event_interruptible_timeout(audio->out_wait,
+			(!list_empty(&audio->out_queue) ||
+			 audio->state == AUDIO_MVS_STOPPED),
+			1 * HZ);
+
+	if (rc > 0) {
+		mutex_lock(&audio->out_lock);
+		if ((audio->state == AUDIO_MVS_STARTED) &&
+		    (!list_empty(&audio->out_queue))) {
+
+			if (count >= sizeof(struct msm_audio_mvs_frame)) {
+				buf_node = list_first_entry(&audio->out_queue,
+						struct audio_mvs_buf_node,
+						list);
+				list_del(&buf_node->list);
+
+				rc = copy_to_user(buf,
+					&buf_node->frame,
+					sizeof(struct msm_audio_mvs_frame));
+
+				if (rc == 0) {
+					rc = buf_node->frame.len +
+					    sizeof(buf_node->frame.frame_type) +
+					    sizeof(buf_node->frame.len);
+				} else {
+					MM_ERR("Copy to user retuned %d", rc);
+
+					rc = -EFAULT;
+				}
+
+				list_add_tail(&buf_node->list,
+					      &audio->free_out_queue);
+			} else {
+				MM_ERR("Read count %d < sizeof(frame) %d",
+				       count,
+				       sizeof(struct msm_audio_mvs_frame));
+
+				rc = -ENOMEM;
+			}
+		} else {
+			MM_ERR("Read performed in state %d\n",
+			       audio->state);
+
+			rc = -EPERM;
+		}
+		mutex_unlock(&audio->out_lock);
+
+	} else if (rc == 0) {
+		MM_ERR("No UL data available\n");
+
+		rc = -ETIMEDOUT;
+	} else {
+		MM_ERR("Read was interrupted\n");
+
+		rc = -ERESTARTSYS;
+	}
+
+	return rc;
+}
+
+static ssize_t audio_mvs_write(struct file *file,
+			       const char __user *buf,
+			       size_t count,
+			       loff_t *pos)
+{
+	int rc = 0;
+	struct audio_mvs_buf_node *buf_node = NULL;
+	struct audio_mvs_info_type *audio = file->private_data;
+
+	MM_DBG("\n");
+
+	mutex_lock(&audio->in_lock);
+	if (audio->state == AUDIO_MVS_STARTED) {
+		if (count <= sizeof(struct msm_audio_mvs_frame)) {
+			if (!list_empty(&audio->free_in_queue)) {
+				buf_node =
+					list_first_entry(&audio->free_in_queue,
+						struct audio_mvs_buf_node,
+						list);
+				list_del(&buf_node->list);
+
+				rc = copy_from_user(&buf_node->frame,
+						    buf,
+						    count);
+
+				list_add_tail(&buf_node->list,
+					      &audio->in_queue);
+			} else {
+				MM_ERR("No free DL buffs\n");
+			}
+		} else {
+			MM_ERR("Write count %d < sizeof(frame) %d",
+			       count,
+			       sizeof(struct msm_audio_mvs_frame));
+
+			rc = -ENOMEM;
+		}
+	} else {
+		MM_ERR("Write performed in invalid state %d\n",
+		       audio->state);
+
+		rc = -EPERM;
+	}
+	mutex_unlock(&audio->in_lock);
+
+	return rc;
+}
+
+static long audio_mvs_ioctl(struct file *file,
+			    unsigned int cmd,
+			    unsigned long arg)
+{
+	int rc = 0;
+
+	struct audio_mvs_info_type *audio = file->private_data;
+
+	MM_DBG("\n");
+
+	switch (cmd) {
+	case AUDIO_GET_MVS_CONFIG: {
+		struct msm_audio_mvs_config config;
+
+		MM_DBG("IOCTL GET_MVS_CONFIG\n");
+
+		mutex_lock(&audio->lock);
+		config.mvs_mode = audio->mvs_mode;
+		config.rate_type = audio->rate_type;
+		mutex_unlock(&audio->lock);
+
+		rc = copy_to_user((void *)arg, &config, sizeof(config));
+		if (rc == 0)
+			rc = sizeof(config);
+		else
+			MM_ERR("Config copy failed %d\n", rc);
+
+		break;
+	}
+
+	case AUDIO_SET_MVS_CONFIG: {
+		struct msm_audio_mvs_config config;
+
+		MM_DBG("IOCTL SET_MVS_CONFIG\n");
+
+		rc = copy_from_user(&config, (void *)arg, sizeof(config));
+		if (rc == 0) {
+			mutex_lock(&audio->lock);
+
+			if (audio->state == AUDIO_MVS_OPENED) {
+				audio->mvs_mode = config.mvs_mode;
+				audio->rate_type = config.rate_type;
+				audio->dtx_mode = config.dtx_mode;
+			} else {
+				MM_ERR("Set confg called in state %d\n",
+				       audio->state);
+
+				rc = -EPERM;
+			}
+
+			mutex_unlock(&audio->lock);
+		} else {
+			MM_ERR("Config copy failed %d\n", rc);
+		}
+
+		break;
+	}
+
+	case AUDIO_START: {
+		MM_DBG("IOCTL START\n");
+
+		mutex_lock(&audio->lock);
+
+		if (audio->state == AUDIO_MVS_OPENED ||
+		    audio->state == AUDIO_MVS_STOPPED) {
+			rc = audio_mvs_start(audio);
+			if (rc != 0)
+				audio_mvs_stop(audio);
+		} else {
+			MM_ERR("Start called in invalid state %d\n",
+			       audio->state);
+
+			rc = -EPERM;
+		}
+
+		mutex_unlock(&audio->lock);
+
+		break;
+	}
+
+	case AUDIO_STOP: {
+		MM_DBG("IOCTL STOP\n");
+
+		mutex_lock(&audio->lock);
+
+		if (audio->state == AUDIO_MVS_STARTED) {
+			rc = audio_mvs_stop(audio);
+		} else {
+			MM_ERR("Stop called in invalid state %d\n",
+			       audio->state);
+
+			rc = -EPERM;
+		}
+
+		mutex_unlock(&audio->lock);
+		break;
+	}
+
+	default: {
+		MM_ERR("Unknown IOCTL %d\n", cmd);
+	}
+	}
+
+	return rc;
+}
+
+static int audio_mvs_open(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+
+	MM_DBG("\n");
+
+	memset(&audio_mvs_info, 0, sizeof(audio_mvs_info));
+	mutex_init(&audio_mvs_info.lock);
+	mutex_init(&audio_mvs_info.in_lock);
+	mutex_init(&audio_mvs_info.out_lock);
+
+	init_waitqueue_head(&audio_mvs_info.wait);
+	init_waitqueue_head(&audio_mvs_info.mode_wait);
+	init_waitqueue_head(&audio_mvs_info.out_wait);
+
+	INIT_LIST_HEAD(&audio_mvs_info.in_queue);
+	INIT_LIST_HEAD(&audio_mvs_info.free_in_queue);
+	INIT_LIST_HEAD(&audio_mvs_info.out_queue);
+	INIT_LIST_HEAD(&audio_mvs_info.free_out_queue);
+
+	wake_lock_init(&audio_mvs_info.suspend_lock,
+		       WAKE_LOCK_SUSPEND,
+		       "audio_mvs_suspend");
+	wake_lock_init(&audio_mvs_info.idle_lock,
+		       WAKE_LOCK_IDLE,
+		       "audio_mvs_idle");
+
+	audio_mvs_info.rpc_endpt = msm_rpc_connect_compatible(MVS_PROG,
+					MVS_VERS_COMP_VER2,
+					MSM_RPC_UNINTERRUPTIBLE);
+
+	if (IS_ERR(audio_mvs_info.rpc_endpt)) {
+		MM_ERR("MVS RPC connect failed ver 0x%x\n",
+				MVS_VERS_COMP_VER2);
+		audio_mvs_info.rpc_endpt = msm_rpc_connect_compatible(MVS_PROG,
+					MVS_VERS_COMP_VER3,
+					MSM_RPC_UNINTERRUPTIBLE);
+		if (IS_ERR(audio_mvs_info.rpc_endpt)) {
+			MM_ERR("MVS RPC connect failed ver 0x%x\n",
+				MVS_VERS_COMP_VER3);
+		} else {
+			MM_DBG("MVS RPC connect succeeded ver 0x%x\n",
+				MVS_VERS_COMP_VER3);
+			audio_mvs_info.rpc_prog = MVS_PROG;
+			audio_mvs_info.rpc_ver = MVS_VERS_COMP_VER3;
+		}
+	} else {
+		MM_DBG("MVS RPC connect succeeded ver 0x%x\n",
+			MVS_VERS_COMP_VER2);
+		audio_mvs_info.rpc_prog = MVS_PROG;
+		audio_mvs_info.rpc_ver = MVS_VERS_COMP_VER2;
+	}
+	audio_mvs_info.task = kthread_run(audio_mvs_thread,
+					  &audio_mvs_info,
+					  "audio_mvs");
+	if (IS_ERR(audio_mvs_info.task)) {
+		MM_ERR("MVS thread create failed\n");
+		rc = PTR_ERR(audio_mvs_info.task);
+		audio_mvs_info.task = NULL;
+		msm_rpc_close(audio_mvs_info.rpc_endpt);
+		audio_mvs_info.rpc_endpt = NULL;
+		goto done;
+	}
+
+	mutex_lock(&audio_mvs_info.lock);
+
+	if (audio_mvs_info.state == AUDIO_MVS_CLOSED) {
+
+		if (audio_mvs_info.task != NULL ||
+			audio_mvs_info.rpc_endpt != NULL) {
+			rc = audio_mvs_alloc_buf(&audio_mvs_info);
+
+			if (rc == 0) {
+				audio_mvs_info.state = AUDIO_MVS_OPENED;
+				file->private_data = &audio_mvs_info;
+			}
+		}  else {
+			MM_ERR("MVS thread and RPC end point do not exist\n");
+
+			rc = -ENODEV;
+		}
+	} else {
+		MM_ERR("MVS driver exists, state %d\n",
+		       audio_mvs_info.state);
+
+		rc = -EBUSY;
+	}
+
+	mutex_unlock(&audio_mvs_info.lock);
+
+done:
+	return rc;
+}
+
+static const struct file_operations audio_mvs_fops = {
+	.owner = THIS_MODULE,
+	.open = audio_mvs_open,
+	.release = audio_mvs_release,
+	.read = audio_mvs_read,
+	.write = audio_mvs_write,
+	.unlocked_ioctl = audio_mvs_ioctl
+};
+
+struct miscdevice audio_mvs_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_mvs",
+	.fops = &audio_mvs_fops
+};
+static int __init audio_mvs_init(void)
+{
+	return misc_register(&audio_mvs_misc);
+}
+
+static void __exit audio_mvs_exit(void)
+{
+	MM_DBG("\n");
+
+	misc_deregister(&audio_mvs_misc);
+}
+
+module_init(audio_mvs_init);
+module_exit(audio_mvs_exit);
+
+MODULE_DESCRIPTION("MSM MVS driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/arch/arm/mach-msm/qdsp5/audio_out.c b/arch/arm/mach-msm/qdsp5/audio_out.c
new file mode 100644
index 0000000..91ce29d
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_out.c
@@ -0,0 +1,1154 @@
+/* arch/arm/mach-msm/qdsp5/audio_out.c
+ *
+ * pcm audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2012 Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/wakelock.h>
+
+#include <linux/msm_audio.h>
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <mach/msm_adsp.h>
+
+#include "audmgr.h"
+
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+#include <mach/qdsp5/qdsp5audppmsg.h>
+
+#include <mach/htc_pwrsink.h>
+#include <mach/debug_mm.h>
+
+#include "evlog.h"
+
+#define LOG_AUDIO_EVENTS 1
+#define LOG_AUDIO_FAULTS 0
+
+#define SRS_ID_GLOBAL			0x00000001
+#define SRS_ID_WOWHD			0x00000002
+#define SRS_ID_CSHP			0x00000003
+#define SRS_ID_HPF			0x00000004
+#define SRS_ID_PEQ			0x00000005
+#define SRS_ID_HL			0x00000006
+
+#define SRS_MASK_G 1
+#define SRS_MASK_W 2
+#define SRS_MASK_C 4
+#define SRS_MASK_HP 8
+#define SRS_MASK_P 16
+#define SRS_MASK_HL 32
+
+
+enum {
+	EV_NULL,
+	EV_OPEN,
+	EV_WRITE,
+	EV_RETURN,
+	EV_IOCTL,
+	EV_WRITE_WAIT,
+	EV_WAIT_EVENT,
+	EV_FILL_BUFFER,
+	EV_SEND_BUFFER,
+	EV_DSP_EVENT,
+	EV_ENABLE,
+};
+
+#if (LOG_AUDIO_EVENTS != 1)
+static inline void LOG(unsigned id, unsigned arg) {}
+#else
+static const char *pcm_log_strings[] = {
+	"NULL",
+	"OPEN",
+	"WRITE",
+	"RETURN",
+	"IOCTL",
+	"WRITE_WAIT",
+	"WAIT_EVENT",
+	"FILL_BUFFER",
+	"SEND_BUFFER",
+	"DSP_EVENT",
+	"ENABLE",
+};
+
+DECLARE_LOG(pcm_log, 64, pcm_log_strings);
+
+static int __init _pcm_log_init(void)
+{
+	return ev_log_init(&pcm_log);
+}
+module_init(_pcm_log_init);
+
+#define LOG(id,arg) ev_log_write(&pcm_log, id, arg)
+#endif
+
+
+
+
+
+#define BUFSZ (960 * 5)
+#define DMASZ (BUFSZ * 2)
+
+#define COMMON_OBJ_ID 6
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;
+	unsigned addr;
+};
+
+struct audio {
+	struct buffer out[2];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed; /* number of buffers the dsp is waiting for */
+
+	atomic_t out_bytes;
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t wait;
+
+	/* configuration to use on next enable */
+	uint32_t out_sample_rate;
+	uint32_t out_channel_mode;
+	uint32_t out_weight;
+	uint32_t out_buffer_size;
+
+	struct audmgr audmgr;
+
+	/* data allocated for various buffers */
+	char *data;
+	dma_addr_t phys;
+
+	int teos; /* valid only if tunnel mode & no data left for decoder */
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+
+	struct wake_lock wakelock;
+	struct wake_lock idlelock;
+
+	audpp_cmd_cfg_object_params_volume vol_pan;
+};
+
+struct audio_copp {
+	int mbadrc_enable;
+	int mbadrc_needs_commit;
+	char *mbadrc_data;
+	dma_addr_t mbadrc_phys;
+
+	audpp_cmd_cfg_object_params_mbadrc mbadrc;
+
+	int eq_enable;
+	int eq_needs_commit;
+	audpp_cmd_cfg_object_params_eqalizer eq;
+
+	int rx_iir_enable;
+	int rx_iir_needs_commit;
+	audpp_cmd_cfg_object_params_pcm iir;
+
+	audpp_cmd_cfg_object_params_volume vol_pan;
+
+	int qconcert_plus_enable;
+	int qconcert_plus_needs_commit;
+
+	int srs_enable;
+	int srs_needs_commit;
+	int srs_feature_mask;
+	audpp_cmd_cfg_object_params_qconcert qconcert_plus;
+
+	int status;
+	int opened;
+	struct mutex lock;
+
+	struct audpp_event_callback ecb;
+
+	struct audpp_cmd_cfg_object_params_srstm_g g;
+	struct audpp_cmd_cfg_object_params_srstm_w w;
+	struct audpp_cmd_cfg_object_params_srstm_c c;
+	struct audpp_cmd_cfg_object_params_srstm_h h;
+	struct audpp_cmd_cfg_object_params_srstm_p p;
+	struct audpp_cmd_cfg_object_params_srstm_l l;
+} the_audio_copp;
+
+static void audio_prevent_sleep(struct audio *audio)
+{
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	wake_lock(&audio->wakelock);
+	wake_lock(&audio->idlelock);
+}
+
+static void audio_allow_sleep(struct audio *audio)
+{
+	wake_unlock(&audio->wakelock);
+	wake_unlock(&audio->idlelock);
+	MM_DBG("\n"); /* Macro prints the file name and function */
+}
+
+static int audio_dsp_out_enable(struct audio *audio, int yes);
+static int audio_dsp_send_buffer(struct audio *audio, unsigned id, unsigned len);
+
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
+static int audio_enable_srs_trumedia(struct audio_copp *audio_copp, int enable);
+/* must be called with audio->lock held */
+static int audio_enable(struct audio *audio)
+{
+	struct audmgr_config cfg;
+	int rc;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	if (audio->enabled)
+		return 0;	
+
+	/* refuse to start if we're not ready */
+	if (!audio->out[0].used || !audio->out[1].used)
+		return -EIO;
+
+	/* we start buffers 0 and 1, so buffer 0 will be the
+	 * next one the dsp will want
+	 */
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;
+	cfg.def_method = RPC_AUD_DEF_METHOD_HOST_PCM;
+	cfg.codec = RPC_AUD_DEF_CODEC_PCM;
+	cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+	audio_prevent_sleep(audio);	
+	rc = audmgr_enable(&audio->audmgr, &cfg);
+	if (rc < 0) {
+		audio_allow_sleep(audio);
+		return rc;
+	}
+
+	if (audpp_enable(-1, audio_dsp_event, audio)) {
+		MM_ERR("audpp_enable() failed\n");
+		audmgr_disable(&audio->audmgr);
+		audio_allow_sleep(audio);
+		return -ENODEV;
+	}
+
+	audio->enabled = 1;
+	htc_pwrsink_set(PWRSINK_AUDIO, 100);
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audio_disable(struct audio *audio)
+{
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audio_dsp_out_enable(audio, 0);
+
+		audpp_disable(-1, audio);
+
+		audio->stopped = 1;
+		wake_up(&audio->wait);
+		audmgr_disable(&audio->audmgr);
+		audio->out_needed = 0;
+		audio_allow_sleep(audio);
+	}
+	return 0;
+}
+
+void audio_commit_pending_pp_params(void *priv, unsigned id, uint16_t *msg)
+{
+	struct audio_copp *audio_copp = priv;
+
+	if (AUDPP_MSG_CFG_MSG == id && msg[0] == AUDPP_MSG_ENA_DIS)
+		return;
+
+	if (!audio_copp->status)
+		return;
+
+	audpp_dsp_set_mbadrc(COMMON_OBJ_ID, audio_copp->mbadrc_enable,
+						&audio_copp->mbadrc);
+
+	audpp_dsp_set_eq(COMMON_OBJ_ID, audio_copp->eq_enable,
+						&audio_copp->eq);
+
+	audpp_dsp_set_rx_iir(COMMON_OBJ_ID, audio_copp->rx_iir_enable,
+							&audio_copp->iir);
+	audpp_dsp_set_vol_pan(COMMON_OBJ_ID, &audio_copp->vol_pan);
+
+	audpp_dsp_set_qconcert_plus(COMMON_OBJ_ID,
+				audio_copp->qconcert_plus_enable,
+				&audio_copp->qconcert_plus);
+	audio_enable_srs_trumedia(audio_copp, true);
+}
+EXPORT_SYMBOL(audio_commit_pending_pp_params);
+
+/* ------------------- dsp --------------------- */
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+	struct buffer *frame;
+	unsigned long flags;
+
+	LOG(EV_DSP_EVENT, id);
+	switch (id) {
+	case AUDPP_MSG_HOST_PCM_INTF_MSG: {
+		unsigned id = msg[2];
+		unsigned idx = msg[3] - 1;
+
+		/* MM_INFO("HOST_PCM id %d idx %d\n", id, idx); */
+		if (id != AUDPP_MSG_HOSTPCM_ID_ARM_RX) {
+			MM_ERR("bogus id\n");
+			break;
+		}
+		if (idx > 1) {
+			MM_ERR("bogus buffer idx\n");
+			break;
+		}
+
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		if (audio->running) {
+			atomic_add(audio->out[idx].used, &audio->out_bytes);
+			audio->out[idx].used = 0;
+
+			frame = audio->out + audio->out_tail;
+			if (frame->used) {
+				audio_dsp_send_buffer(
+					audio, audio->out_tail, frame->used);
+				audio->out_tail ^= 1;
+			} else {
+				audio->out_needed++;
+			}
+			wake_up(&audio->wait);
+		}
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		break;
+	}
+	case AUDPP_MSG_PCMDMAMISSED:
+		MM_INFO("PCMDMAMISSED %d\n", msg[0]);
+		audio->teos = 1;
+		wake_up(&audio->wait);
+		break;
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			LOG(EV_ENABLE, 1);
+			MM_DBG("CFG_MSG ENABLE\n");
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_dsp_set_vol_pan(5, &audio->vol_pan);
+			audio_dsp_out_enable(audio, 1);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			LOG(EV_ENABLE, 0);
+			MM_DBG("CFG_MSG DISABLE\n");
+			audio->running = 0;
+		} else {
+			MM_ERR("CFG_MSG %d?\n", msg[0]);
+		}
+		break;
+	default:
+		MM_ERR("UNKNOWN (%d)\n", id);
+	}
+}
+
+static int audio_dsp_out_enable(struct audio *audio, int yes)
+{
+	audpp_cmd_pcm_intf cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id	= AUDPP_CMD_PCM_INTF_2; 
+	cmd.object_num	= AUDPP_CMD_PCM_INTF_OBJECT_NUM;
+	cmd.config	= AUDPP_CMD_PCM_INTF_CONFIG_CMD_V;
+	cmd.intf_type	= AUDPP_CMD_PCM_INTF_RX_ENA_ARMTODSP_V;
+
+	if (yes) {
+		cmd.write_buf1LSW	= audio->out[0].addr;
+		cmd.write_buf1MSW	= audio->out[0].addr >> 16;
+		if (audio->out[0].used)
+			cmd.write_buf1_len	= audio->out[0].used;
+		else
+			cmd.write_buf1_len	= audio->out[0].size;
+		cmd.write_buf2LSW	= audio->out[1].addr;
+		cmd.write_buf2MSW	= audio->out[1].addr >> 16;
+		if (audio->out[1].used)
+			cmd.write_buf2_len	= audio->out[1].used;
+		else
+			cmd.write_buf2_len	= audio->out[1].size;
+		cmd.arm_to_rx_flag	= AUDPP_CMD_PCM_INTF_ENA_V;
+		cmd.weight_decoder_to_rx = audio->out_weight;
+		cmd.weight_arm_to_rx	= 1;
+		cmd.partition_number_arm_to_dsp = 0;
+		cmd.sample_rate		= audio->out_sample_rate;
+		cmd.channel_mode	= audio->out_channel_mode;
+	}
+	
+	return audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static int audio_dsp_send_buffer(struct audio *audio, unsigned idx, unsigned len)
+{
+	audpp_cmd_pcm_intf_send_buffer cmd;
+	
+	cmd.cmd_id		= AUDPP_CMD_PCM_INTF_2;
+	cmd.host_pcm_object	= AUDPP_CMD_PCM_INTF_OBJECT_NUM;
+	cmd.config		= AUDPP_CMD_PCM_INTF_BUFFER_CMD_V;
+	cmd.intf_type		= AUDPP_CMD_PCM_INTF_RX_ENA_ARMTODSP_V;
+	cmd.dsp_to_arm_buf_id	= 0;
+	cmd.arm_to_dsp_buf_id	= idx + 1;
+	cmd.arm_to_dsp_buf_len	= len;
+
+	LOG(EV_SEND_BUFFER, idx);
+	dma_coherent_pre_ops();
+	return audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+/* ------------------- device --------------------- */
+
+static int audio_enable_mbadrc(struct audio_copp *audio_copp, int enable)
+{
+	if (audio_copp->mbadrc_enable == enable &&
+				!audio_copp->mbadrc_needs_commit)
+		return 0;
+
+	audio_copp->mbadrc_enable = enable;
+	if (is_audpp_enable()) {
+		audpp_dsp_set_mbadrc(COMMON_OBJ_ID, enable,
+						&audio_copp->mbadrc);
+		audio_copp->mbadrc_needs_commit = 0;
+	}
+
+	return 0;
+}
+
+static int audio_enable_eq(struct audio_copp *audio_copp, int enable)
+{
+	if (audio_copp->eq_enable == enable &&
+				!audio_copp->eq_needs_commit)
+		return 0;
+
+	audio_copp->eq_enable = enable;
+
+	if (is_audpp_enable()) {
+		audpp_dsp_set_eq(COMMON_OBJ_ID, enable, &audio_copp->eq);
+		audio_copp->eq_needs_commit = 0;
+	}
+	return 0;
+}
+
+static int audio_enable_rx_iir(struct audio_copp *audio_copp, int enable)
+{
+	if (audio_copp->rx_iir_enable == enable &&
+				!audio_copp->rx_iir_needs_commit)
+		return 0;
+
+	audio_copp->rx_iir_enable = enable;
+
+	if (is_audpp_enable()) {
+		audpp_dsp_set_rx_iir(COMMON_OBJ_ID, enable, &audio_copp->iir);
+		audio_copp->rx_iir_needs_commit = 0;
+	}
+	return 0;
+}
+
+static int audio_enable_srs_trumedia(struct audio_copp *audio_copp, int enable)
+{
+
+	if (!audio_copp->srs_needs_commit)
+		return 0;
+
+	audio_copp->srs_enable = enable;
+
+	MM_DBG("Enable SRS flags 0x%x enable %d\n",
+		audio_copp->srs_feature_mask, enable);
+	if (is_audpp_enable()) {
+		MM_DBG("Updating audpp for srs\n");
+		if (audio_copp->srs_feature_mask & SRS_MASK_W)
+			audpp_dsp_set_rx_srs_trumedia_w(&audio_copp->w);
+		if (audio_copp->srs_feature_mask & SRS_MASK_C)
+			audpp_dsp_set_rx_srs_trumedia_c(&audio_copp->c);
+		if (audio_copp->srs_feature_mask & SRS_MASK_HP)
+			audpp_dsp_set_rx_srs_trumedia_h(&audio_copp->h);
+		if (audio_copp->srs_feature_mask & SRS_MASK_P)
+			audpp_dsp_set_rx_srs_trumedia_p(&audio_copp->p);
+		if (audio_copp->srs_feature_mask & SRS_MASK_HL)
+			audpp_dsp_set_rx_srs_trumedia_l(&audio_copp->l);
+		if (audio_copp->srs_feature_mask & SRS_MASK_G)
+			audpp_dsp_set_rx_srs_trumedia_g(&audio_copp->g);
+
+		audio_copp->srs_needs_commit = 0;
+		audio_copp->srs_feature_mask = 0;
+	}
+	return 0;
+}
+
+static int audio_enable_vol_pan(struct audio_copp *audio_copp)
+{
+	if (is_audpp_enable())
+		audpp_dsp_set_vol_pan(COMMON_OBJ_ID, &audio_copp->vol_pan);
+	return 0;
+}
+
+static int audio_enable_qconcert_plus(struct audio_copp *audio_copp, int enable)
+{
+	if (audio_copp->qconcert_plus_enable == enable &&
+				!audio_copp->qconcert_plus_needs_commit)
+		return 0;
+
+	audio_copp->qconcert_plus_enable = enable;
+
+	if (is_audpp_enable()) {
+		audpp_dsp_set_qconcert_plus(COMMON_OBJ_ID, enable,
+					&audio_copp->qconcert_plus);
+		audio_copp->qconcert_plus_needs_commit = 0;
+	}
+	return 0;
+}
+
+static void audio_flush(struct audio *audio)
+{
+	audio->out[0].used = 0;
+	audio->out[1].used = 0;
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->stopped = 0;
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = -EINVAL;
+	unsigned long flags = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = atomic_read(&audio->out_bytes);
+		if (copy_to_user((void*) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	switch (cmd) {
+	case AUDIO_SET_VOLUME:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.volume = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(5, &audio->vol_pan);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		return 0;
+
+	case AUDIO_SET_PAN:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.pan = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(5, &audio->vol_pan);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		return 0;
+	}
+
+	LOG(EV_IOCTL, cmd);
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		rc = audio_enable(audio);
+		break;
+	case AUDIO_STOP:
+		rc = audio_disable(audio);
+		break;
+	case AUDIO_FLUSH:
+		if (audio->stopped) {
+			/* Make sure we're stopped and we wake any threads
+			 * that might be blocked holding the write_lock.
+			 * While audio->stopped write threads will always
+			 * exit immediately.
+			 */
+			wake_up(&audio->wait);
+			mutex_lock(&audio->write_lock);
+			audio_flush(audio);
+			mutex_unlock(&audio->write_lock);
+		}
+		break;
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (copy_from_user(&config, (void*) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (config.channel_count == 1) {
+			config.channel_count = AUDPP_CMD_PCM_INTF_MONO_V;
+		} else if (config.channel_count == 2) {
+			config.channel_count= AUDPP_CMD_PCM_INTF_STEREO_V;
+		} else {
+			rc = -EINVAL;
+			break;
+		}
+		audio->out_sample_rate = config.sample_rate;
+		audio->out_channel_mode = config.channel_count;
+		rc = 0;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_size = BUFSZ;
+		config.buffer_count = 2;
+		config.sample_rate = audio->out_sample_rate;
+		if (audio->out_channel_mode == AUDPP_CMD_PCM_INTF_MONO_V) {
+			config.channel_count = 1;
+		} else {
+			config.channel_count = 2;
+		}
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void*) arg, &config, sizeof(config))) {
+			rc = -EFAULT;
+		} else {
+			rc = 0;
+		}
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+/* Only useful in tunnel-mode */
+static int audio_fsync(struct file *file, loff_t a, loff_t b, int datasync)
+{
+	struct audio *audio = file->private_data;
+	int rc = 0;
+
+	if (!audio->running)
+		return -EINVAL;
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->wait,
+		(!audio->out[0].used &&
+		!audio->out[1].used));
+
+	if (rc < 0)
+		goto done;
+
+	/* pcm dmamiss message is sent continously when
+	 * decoder is starved so no race condition concern
+	 */
+
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->wait,
+		audio->teos);
+
+done:
+	mutex_unlock(&audio->write_lock);
+	return rc;
+}
+
+static ssize_t audio_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
+{
+	return -EINVAL;
+}
+
+static inline int rt_policy(int policy)
+{
+	if (unlikely(policy == SCHED_FIFO) || unlikely(policy == SCHED_RR))
+		return 1;
+	return 0;
+}
+
+static inline int task_has_rt_policy(struct task_struct *p)
+{
+	return rt_policy(p->policy);
+}
+
+static ssize_t audio_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct sched_param s = { .sched_priority = 1 };
+	struct audio *audio = file->private_data;
+	unsigned long flags;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	int old_prio = current->rt_priority;
+	int old_policy = current->policy;
+	int cap_nice = cap_raised(current_cap(), CAP_SYS_NICE);
+	int rc = 0;
+
+	LOG(EV_WRITE, count | (audio->running << 28) | (audio->stopped << 24));
+
+	/* just for this write, set us real-time */
+	if (!task_has_rt_policy(current)) {
+		struct cred *new = prepare_creds();
+		cap_raise(new->cap_effective, CAP_SYS_NICE);
+		commit_creds(new);
+		if ((sched_setscheduler(current, SCHED_RR, &s)) < 0)
+			MM_ERR("sched_setscheduler failed\n");
+	}
+
+	mutex_lock(&audio->write_lock);
+	while (count > 0) {
+		frame = audio->out + audio->out_head;
+
+		LOG(EV_WAIT_EVENT, 0);
+		rc = wait_event_interruptible(audio->wait,
+					      (frame->used == 0) || (audio->stopped));
+		LOG(EV_WAIT_EVENT, 1);
+
+		if (rc < 0)
+			break;
+		if (audio->stopped) {
+			rc = -EBUSY;
+			break;
+		}
+		xfer = count > frame->size ? frame->size : count;
+		if (copy_from_user(frame->data, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+		frame->used = xfer;
+		audio->out_head ^= 1;
+		count -= xfer;
+		buf += xfer;
+
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		LOG(EV_FILL_BUFFER, audio->out_head ^ 1);
+		frame = audio->out + audio->out_tail;
+		if (frame->used && audio->out_needed) {
+			audio_dsp_send_buffer(audio, audio->out_tail, frame->used);
+			audio->out_tail ^= 1;
+			audio->out_needed--;
+		}
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	}
+
+	mutex_unlock(&audio->write_lock);
+
+	/* restore scheduling policy and priority */
+	if (!rt_policy(old_policy)) {
+		struct sched_param v = { .sched_priority = old_prio };
+		if ((sched_setscheduler(current, old_policy, &v)) < 0)
+			MM_ERR("sched_setscheduler failed\n");
+		if (likely(!cap_nice)) {
+			struct cred *new = prepare_creds();
+			cap_lower(new->cap_effective, CAP_SYS_NICE);
+			commit_creds(new);
+		}
+	}
+
+	LOG(EV_RETURN,(buf > start) ? (buf - start) : rc);
+	if (buf > start)
+		return buf - start;
+	return rc;	
+}
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	LOG(EV_OPEN, 0);
+	mutex_lock(&audio->lock);
+	audio_disable(audio);
+	audio_flush(audio);
+	audio->opened = 0;
+	mutex_unlock(&audio->lock);
+	htc_pwrsink_set(PWRSINK_AUDIO, 0);
+	return 0;
+}
+
+struct audio the_audio;
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = &the_audio;
+	int rc;
+
+	mutex_lock(&audio->lock);
+
+	if (audio->opened) {
+		MM_ERR("busy\n");
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (!audio->data) {
+		audio->data = dma_alloc_coherent(NULL, DMASZ, 
+						 &audio->phys, GFP_KERNEL);
+		if (!audio->data) {
+			MM_ERR("could not allocate DMA buffers\n");
+			rc = -ENOMEM;
+			goto done;
+		}
+	}
+
+	rc = audmgr_open(&audio->audmgr);
+	if (rc)
+		goto done;
+
+	audio->out_buffer_size = BUFSZ;
+	audio->out_sample_rate = 44100;
+	audio->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V;
+	audio->out_weight = 100;
+
+	audio->out[0].data = audio->data + 0;
+	audio->out[0].addr = audio->phys + 0;
+	audio->out[0].size = BUFSZ;
+	
+	audio->out[1].data = audio->data + BUFSZ;
+	audio->out[1].addr = audio->phys + BUFSZ;
+	audio->out[1].size = BUFSZ;
+
+	audio->vol_pan.volume = 0x2000;
+	audio->vol_pan.pan = 0x0;
+
+	audio_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+	rc = 0;
+	LOG(EV_OPEN, 1);
+done:
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static long audpp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct audio_copp *audio_copp = file->private_data;
+	int rc = 0, enable;
+	uint16_t enable_mask;
+	int prev_state;
+	uint32_t to_set, size = 0;
+	void *tmpbuf, *srs_params = NULL;
+
+	mutex_lock(&audio_copp->lock);
+	switch (cmd) {
+	case AUDIO_ENABLE_AUDPP:
+		if (copy_from_user(&enable_mask, (void *) arg,
+						sizeof(enable_mask))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		enable = ((enable_mask & ADRC_ENABLE) ||
+				(enable_mask & MBADRC_ENABLE)) ? 1 : 0;
+		audio_enable_mbadrc(audio_copp, enable);
+		enable = (enable_mask & EQ_ENABLE) ? 1 : 0;
+		audio_enable_eq(audio_copp, enable);
+		enable = (enable_mask & IIR_ENABLE) ? 1 : 0;
+		audio_enable_rx_iir(audio_copp, enable);
+		enable = (enable_mask & QCONCERT_PLUS_ENABLE) ? 1 : 0;
+		audio_enable_qconcert_plus(audio_copp, enable);
+		enable = (enable_mask & SRS_ENABLE) ? 1 : 0;
+		audio_enable_srs_trumedia(audio_copp, enable);
+		break;
+
+	case AUDIO_SET_MBADRC: {
+		uint32_t mbadrc_coeff_buf;
+		prev_state = audio_copp->mbadrc_enable;
+		audio_copp->mbadrc_enable = 0;
+		if (copy_from_user(&audio_copp->mbadrc.num_bands, (void *) arg,
+				sizeof(audio_copp->mbadrc) -
+				(AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2)))
+			rc = -EFAULT;
+		else if (audio_copp->mbadrc.ext_buf_size) {
+			mbadrc_coeff_buf = (uint32_t) ((char *) arg +
+					sizeof(audio_copp->mbadrc) -
+				(AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2));
+			if ((copy_from_user(audio_copp->mbadrc_data,
+					(void *) mbadrc_coeff_buf,
+					AUDPP_MBADRC_EXTERNAL_BUF_SIZE * 2))) {
+				rc = -EFAULT;
+				break;
+			}
+			audio_copp->mbadrc.ext_buf_lsw =
+					audio_copp->mbadrc_phys & 0xFFFF;
+			audio_copp->mbadrc.ext_buf_msw =
+				((audio_copp->mbadrc_phys & 0xFFFF0000) >> 16);
+		}
+		audio_copp->mbadrc_enable = prev_state;
+		if (!rc)
+			audio_copp->mbadrc_needs_commit = 1;
+		break;
+	}
+
+	case AUDIO_SET_ADRC: {
+			struct audpp_cmd_cfg_object_params_adrc adrc;
+			prev_state = audio_copp->mbadrc_enable;
+			audio_copp->mbadrc_enable = 0;
+			if (copy_from_user(&adrc.compression_th, (void *) arg,
+							sizeof(adrc) - 2)) {
+				rc = -EFAULT;
+				audio_copp->mbadrc_enable = prev_state;
+				break;
+			}
+			audio_copp->mbadrc.num_bands = 1;
+			audio_copp->mbadrc.down_samp_level = 8;
+			audio_copp->mbadrc.adrc_delay = adrc.adrc_delay;
+			audio_copp->mbadrc.ext_buf_size = 0;
+			audio_copp->mbadrc.ext_partition = 0;
+			audio_copp->mbadrc.adrc_band[0].subband_enable = 1;
+			audio_copp->mbadrc.adrc_band[0].adrc_sub_mute = 0;
+			audio_copp->mbadrc.adrc_band[0].rms_time =
+								adrc.rms_time;
+			audio_copp->mbadrc.adrc_band[0].compression_th =
+							adrc.compression_th;
+			audio_copp->mbadrc.adrc_band[0].compression_slope =
+							adrc.compression_slope;
+			audio_copp->mbadrc.adrc_band[0].attack_const_lsw =
+							adrc.attack_const_lsw;
+			audio_copp->mbadrc.adrc_band[0].attack_const_msw =
+							adrc.attack_const_msw;
+			audio_copp->mbadrc.adrc_band[0].release_const_lsw =
+							adrc.release_const_lsw;
+			audio_copp->mbadrc.adrc_band[0].release_const_msw =
+							adrc.release_const_msw;
+			audio_copp->mbadrc.adrc_band[0].makeup_gain = 0x2000;
+			audio_copp->mbadrc_enable = prev_state;
+			audio_copp->mbadrc_needs_commit = 1;
+			break;
+		}
+
+	case AUDIO_SET_EQ:
+		prev_state = audio_copp->eq_enable;
+		audio_copp->eq_enable = 0;
+		if (copy_from_user(&audio_copp->eq.num_bands, (void *) arg,
+				sizeof(audio_copp->eq) -
+				(AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2)))
+			rc = -EFAULT;
+		audio_copp->eq_enable = prev_state;
+		audio_copp->eq_needs_commit = 1;
+		break;
+
+	case AUDIO_SET_RX_IIR:
+		prev_state = audio_copp->rx_iir_enable;
+		audio_copp->rx_iir_enable = 0;
+		if (copy_from_user(&audio_copp->iir.num_bands, (void *) arg,
+				sizeof(audio_copp->iir) -
+				(AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2)))
+			rc = -EFAULT;
+		audio_copp->rx_iir_enable = prev_state;
+		audio_copp->rx_iir_needs_commit = 1;
+		break;
+
+	case AUDIO_SET_VOLUME:
+		audio_copp->vol_pan.volume = arg;
+		audio_enable_vol_pan(audio_copp);
+		break;
+
+	case AUDIO_SET_PAN:
+		audio_copp->vol_pan.pan = arg;
+		audio_enable_vol_pan(audio_copp);
+		break;
+
+	case AUDIO_SET_QCONCERT_PLUS:
+		prev_state = audio_copp->qconcert_plus_enable;
+		audio_copp->qconcert_plus_enable = 0;
+		if (copy_from_user(&audio_copp->qconcert_plus.op_mode,
+				(void *) arg,
+				sizeof(audio_copp->qconcert_plus) -
+				(AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2)))
+			rc = -EFAULT;
+		audio_copp->qconcert_plus_enable = prev_state;
+		audio_copp->qconcert_plus_needs_commit = 1;
+		break;
+
+	case AUDIO_SET_SRS_TRUMEDIA_PARAM: {
+		prev_state = audio_copp->srs_enable;
+		audio_copp->srs_enable = 0;
+
+		if (copy_from_user(&to_set, (void *)arg, sizeof(uint32_t))) {
+			rc = -EFAULT;
+			break;
+		}
+		switch (to_set) {
+		case SRS_ID_GLOBAL:
+			srs_params = (void *)audio_copp->g.v;
+			size = sizeof(audio_copp->g.v);
+			audio_copp->srs_feature_mask |= SRS_MASK_G;
+			break;
+		case SRS_ID_WOWHD:
+			srs_params = (void *)audio_copp->w.v;
+			size = sizeof(audio_copp->w.v);
+			audio_copp->srs_feature_mask |= SRS_MASK_W;
+			break;
+		case SRS_ID_CSHP:
+			srs_params = (void *)audio_copp->c.v;
+			size = sizeof(audio_copp->c.v);
+			audio_copp->srs_feature_mask |= SRS_MASK_C;
+			break;
+		case SRS_ID_HPF:
+			srs_params = (void *)audio_copp->h.v;
+			size = sizeof(audio_copp->h.v);
+			audio_copp->srs_feature_mask |= SRS_MASK_HP;
+			break;
+		case SRS_ID_PEQ:
+			srs_params = (void *)audio_copp->p.v;
+			size = sizeof(audio_copp->p.v);
+			audio_copp->srs_feature_mask |= SRS_MASK_P;
+			break;
+		case SRS_ID_HL:
+			srs_params = (void *)audio_copp->l.v;
+			size = sizeof(audio_copp->l.v);
+			audio_copp->srs_feature_mask |= SRS_MASK_HL;
+			break;
+		default:
+			MM_ERR("SRS TruMedia error: invalid ioctl\n");
+			rc = -EINVAL;
+		}
+
+		if (rc >= 0) {
+			tmpbuf = kzalloc(sizeof(uint32_t) + size , GFP_KERNEL);
+			if (!tmpbuf) {
+				MM_ERR("SRS TruMedia error: no kernel mem\n");
+				rc = -ENOMEM;
+			} else {
+				if (copy_from_user(tmpbuf, (void *)arg,
+						sizeof(uint32_t) + size))
+					rc = -EFAULT;
+				memcpy(srs_params,
+					&(((uint32_t *)tmpbuf)[1]), size);
+				kfree(tmpbuf);
+			}
+		}
+
+		MM_DBG("Ioctl SRS flags=0x%x\n", audio_copp->srs_feature_mask);
+		if (rc < 0)
+			MM_ERR("SRS TruMedia error setting params failed.\n");
+		else{
+			audio_copp->srs_needs_commit = 1;
+			audio_copp->srs_enable = prev_state;
+		}
+		break;
+	}
+
+	default:
+		rc = -EINVAL;
+	}
+
+	mutex_unlock(&audio_copp->lock);
+	return rc;
+}
+
+static int audpp_open(struct inode *inode, struct file *file)
+{
+	struct audio_copp *audio_copp = &the_audio_copp;
+	int rc;
+
+	mutex_lock(&audio_copp->lock);
+	if (audio_copp->opened) {
+		mutex_unlock(&audio_copp->lock);
+		return -EBUSY;
+	}
+
+	audio_copp->opened = 1;
+
+	if (!audio_copp->status) {
+		audio_copp->ecb.fn = audio_commit_pending_pp_params;
+		audio_copp->ecb.private = audio_copp;
+		rc = audpp_register_event_callback(&audio_copp->ecb);
+		if (rc) {
+			audio_copp->opened = 0;
+			mutex_unlock(&audio_copp->lock);
+			return rc;
+		}
+		audio_copp->mbadrc_data = dma_alloc_coherent(NULL,
+				AUDPP_MBADRC_EXTERNAL_BUF_SIZE * 2,
+				 &audio_copp->mbadrc_phys, GFP_KERNEL);
+		if (!audio_copp->mbadrc_data) {
+			MM_ERR("could not allocate DMA buffers\n");
+			audio_copp->opened = 0;
+			audpp_unregister_event_callback(&audio_copp->ecb);
+			mutex_unlock(&audio_copp->lock);
+			return -ENOMEM;
+		}
+		audio_copp->vol_pan.volume = 0x2000;
+		audio_copp->vol_pan.pan = 0x0;
+		audio_copp->status = 1;
+	}
+
+	file->private_data = audio_copp;
+	mutex_unlock(&audio_copp->lock);
+
+	return 0;
+}
+
+static int audpp_release(struct inode *inode, struct file *file)
+{
+	struct audio_copp *audio_copp = &the_audio_copp;
+
+	audio_copp->opened = 0;
+
+	return 0;
+}
+
+static struct file_operations audio_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audio_open,
+	.release	= audio_release,
+	.read		= audio_read,
+	.write		= audio_write,
+	.unlocked_ioctl	= audio_ioctl,
+	.fsync		= audio_fsync,
+};
+
+static struct file_operations audpp_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audpp_open,
+	.release	= audpp_release,
+	.unlocked_ioctl	= audpp_ioctl,
+};
+
+struct miscdevice audio_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_pcm_out",
+	.fops	= &audio_fops,
+};
+
+struct miscdevice audpp_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_pcm_ctl",
+	.fops	= &audpp_fops,
+};
+
+static int __init audio_init(void)
+{
+	mutex_init(&the_audio.lock);
+	mutex_init(&the_audio.write_lock);
+	mutex_init(&the_audio_copp.lock);
+	spin_lock_init(&the_audio.dsp_lock);
+	init_waitqueue_head(&the_audio.wait);
+	wake_lock_init(&the_audio.wakelock, WAKE_LOCK_SUSPEND, "audio_pcm");
+	wake_lock_init(&the_audio.idlelock, WAKE_LOCK_IDLE, "audio_pcm_idle");
+	return (misc_register(&audio_misc) || misc_register(&audpp_misc));
+}
+
+device_initcall(audio_init);
diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm.c b/arch/arm/mach-msm/qdsp5/audio_pcm.c
new file mode 100644
index 0000000..49c781f
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_pcm.c
@@ -0,0 +1,1707 @@
+
+/* audio_pcm.c - pcm audio decoder driver
+ *
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+ *
+ * Based on the mp3 decoder driver in arch/arm/mach-msm/qdsp5/audio_mp3.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/earlysuspend.h>
+#include <linux/list.h>
+#include <linux/android_pmem.h>
+#include <linux/slab.h>
+#include <linux/msm_audio.h>
+
+
+#include <mach/msm_adsp.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audplaycmdi.h>
+#include <mach/qdsp5/qdsp5audplaymsg.h>
+#include <mach/qdsp5/qdsp5rmtcmdi.h>
+#include <mach/debug_mm.h>
+#include <linux/memory_alloc.h>
+#include <mach/msm_memtypes.h>
+
+#include "audmgr.h"
+
+/* for queue ids - should be relative to module number*/
+#include "adsp.h"
+
+#define ADRV_STATUS_AIO_INTF 0x00000001
+#define ADRV_STATUS_OBUF_GIVEN 0x00000002
+#define ADRV_STATUS_IBUF_GIVEN 0x00000004
+#define ADRV_STATUS_FSYNC 0x00000008
+
+/* Size must be power of 2 */
+#define BUFSZ_MAX 32768
+#define BUFSZ_MIN 4096
+#define DMASZ_MAX (BUFSZ_MAX * 2)
+#define DMASZ_MIN (BUFSZ_MIN * 2)
+
+#define AUDDEC_DEC_PCM 0
+
+/* Decoder status received from AUDPPTASK */
+#define  AUDPP_DEC_STATUS_SLEEP	0
+#define  AUDPP_DEC_STATUS_INIT  1
+#define  AUDPP_DEC_STATUS_CFG   2
+#define  AUDPP_DEC_STATUS_PLAY  3
+
+#define AUDPCM_EVENT_NUM 10 /* Default number of pre-allocated event packets */
+
+#define __CONTAINS(r, v, l) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __v = v;					\
+	typeof(v) __e = __v + l;				\
+	int res = ((__v >= __r->vaddr) && 			\
+		(__e <= __r->vaddr + __r->len));		\
+	res;							\
+})
+
+#define CONTAINS(r1, r2) ({					\
+	typeof(r2) __r2 = r2;					\
+	__CONTAINS(r1, __r2->vaddr, __r2->len);			\
+})
+
+#define IN_RANGE(r, v) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __vv = v;					\
+	int res = ((__vv >= __r->vaddr) &&			\
+		(__vv < (__r->vaddr + __r->len)));		\
+	res;							\
+})
+
+#define OVERLAPS(r1, r2) ({					\
+	typeof(r1) __r1 = r1;					\
+	typeof(r2) __r2 = r2;					\
+	typeof(__r2->vaddr) __v = __r2->vaddr;			\
+	typeof(__v) __e = __v + __r2->len - 1;			\
+	int res = (IN_RANGE(__r1, __v) || IN_RANGE(__r1, __e));	\
+	res;							\
+})
+
+struct audio;
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct audpcm_suspend_ctl {
+  struct early_suspend node;
+  struct audio *audio;
+};
+#endif
+
+struct audpcm_event {
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+
+struct audpcm_pmem_region {
+	struct list_head list;
+	struct file *file;
+	int fd;
+	void *vaddr_ref;
+	void *vaddr;
+	unsigned long paddr;
+	unsigned long kvaddr;
+	unsigned long len;
+	unsigned ref_cnt;
+};
+
+struct audpcm_buffer_node {
+	struct list_head list;
+	struct msm_audio_aio_buf buf;
+	unsigned long paddr;
+};
+
+struct audpcm_drv_operations {
+	void (*send_data)(struct audio *, unsigned);
+	void (*out_flush)(struct audio *);
+	int (*fsync)(struct audio *);
+};
+
+struct audio {
+	struct buffer out[2];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed; /* number of buffers the dsp is waiting for */
+	unsigned out_dma_sz;
+	struct list_head out_queue; /* queue to retain output buffers */
+	atomic_t out_bytes;
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	struct msm_adsp_module *audplay;
+
+	/* configuration to use on next enable */
+	uint32_t out_sample_rate;
+	uint32_t out_channel_mode;
+	uint32_t out_bits; /* bits per sample */
+
+	struct audmgr audmgr;
+
+	/* data allocated for various buffers */
+	char *data;
+	int32_t phys;
+	void *map_v_write;
+
+	uint32_t drv_status;
+	int wflush; /* Write flush */
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+	int teos; /* valid only if tunnel mode & no data left for decoder */
+	int rmt_resource_released;
+	enum msm_aud_decoder_state dec_state; /* Represents decoder state */
+	int reserved; /* A byte is being reserved */
+	char rsv_byte; /* Handle odd length user data */
+
+	const char *module_name;
+	unsigned queue_id;
+
+	unsigned volume;
+
+	uint16_t dec_id;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct audpcm_suspend_ctl suspend_ctl;
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+	wait_queue_head_t wait;
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	wait_queue_head_t event_wait;
+	spinlock_t event_queue_lock;
+	struct mutex get_event_lock;
+	int event_abort;
+
+	struct list_head pmem_region_queue;
+	struct audpcm_drv_operations drv_ops;
+};
+
+static int auddec_dsp_config(struct audio *audio, int enable);
+static void audpp_cmd_cfg_adec_params(struct audio *audio);
+static void audplay_send_data(struct audio *audio, unsigned needed);
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
+static void audpcm_post_event(struct audio *audio, int type,
+	union msm_audio_event_payload payload);
+static unsigned long audpcm_pmem_fixup(struct audio *audio, void *addr,
+	unsigned long len, int ref_up);
+
+static int rmt_put_resource(struct audio *audio)
+{
+	struct aud_codec_config_cmd cmd;
+	unsigned short client_idx;
+
+	cmd.cmd_id = RM_CMD_AUD_CODEC_CFG;
+	cmd.client_id = RM_AUD_CLIENT_ID;
+	cmd.task_id = audio->dec_id;
+	cmd.enable = RMT_DISABLE;
+	cmd.dec_type = AUDDEC_DEC_PCM;
+	client_idx = ((cmd.client_id << 8) | cmd.task_id);
+
+	return put_adsp_resource(client_idx, &cmd, sizeof(cmd));
+}
+
+static int rmt_get_resource(struct audio *audio)
+{
+	struct aud_codec_config_cmd cmd;
+	unsigned short client_idx;
+
+	cmd.cmd_id = RM_CMD_AUD_CODEC_CFG;
+	cmd.client_id = RM_AUD_CLIENT_ID;
+	cmd.task_id = audio->dec_id;
+	cmd.enable = RMT_ENABLE;
+	cmd.dec_type = AUDDEC_DEC_PCM;
+	client_idx = ((cmd.client_id << 8) | cmd.task_id);
+
+	return get_adsp_resource(client_idx, &cmd, sizeof(cmd));
+}
+
+/* must be called with audio->lock held */
+static int audio_enable(struct audio *audio)
+{
+	struct audmgr_config cfg;
+	int rc;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled)
+		return 0;
+
+	if (audio->rmt_resource_released == 1) {
+		audio->rmt_resource_released = 0;
+		rc = rmt_get_resource(audio);
+		if (rc) {
+			MM_ERR("ADSP resources are not available for PCM \
+				session 0x%08x on decoder: %d\n Ignoring \
+				error and going ahead with the playback\n",
+				(int)audio, audio->dec_id);
+		}
+	}
+
+	audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;
+	cfg.def_method = RPC_AUD_DEF_METHOD_PLAYBACK;
+	cfg.codec = RPC_AUD_DEF_CODEC_PCM;
+	cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+	rc = audmgr_enable(&audio->audmgr, &cfg);
+	if (rc < 0)
+		return rc;
+
+	if (msm_adsp_enable(audio->audplay)) {
+		MM_ERR("msm_adsp_enable(audplay) failed\n");
+		audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+
+	if (audpp_enable(audio->dec_id, audio_dsp_event, audio)) {
+		MM_ERR("audpp_enable() failed\n");
+		msm_adsp_disable(audio->audplay);
+		audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+
+	audio->enabled = 1;
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audio_disable(struct audio *audio)
+{
+	int rc = 0;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+		auddec_dsp_config(audio, 0);
+		rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+		else if (audio->dec_state != MSM_AUD_DECODER_STATE_CLOSE)
+			rc = -EFAULT;
+		else
+			rc = 0;
+		audio->stopped = 1;
+		wake_up(&audio->write_wait);
+		msm_adsp_disable(audio->audplay);
+		audpp_disable(audio->dec_id, audio);
+		audmgr_disable(&audio->audmgr);
+		audio->out_needed = 0;
+		rmt_put_resource(audio);
+		audio->rmt_resource_released = 1;
+	}
+	return rc;
+}
+
+/* ------------------- dsp --------------------- */
+static void audplay_dsp_event(void *data, unsigned id, size_t len,
+			      void (*getevent) (void *ptr, size_t len))
+{
+	struct audio *audio = data;
+	uint32_t msg[28];
+	getevent(msg, sizeof(msg));
+
+	MM_DBG("msg_id=%x\n", id);
+
+	switch (id) {
+	case AUDPLAY_MSG_DEC_NEEDS_DATA:
+		audio->drv_ops.send_data(audio, 1);
+		break;
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audplaytask)\n");
+		break;
+	default:
+		MM_ERR("unexpected message from decoder \n");
+		break;
+	}
+}
+
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned status = msg[1];
+
+			switch (status) {
+			case AUDPP_DEC_STATUS_SLEEP: {
+				uint16_t reason = msg[2];
+				MM_DBG("decoder status: sleep reason = \
+						0x%04x\n", reason);
+				if ((reason == AUDPP_MSG_REASON_MEM)
+						|| (reason ==
+						AUDPP_MSG_REASON_NODECODER)) {
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_FAILURE;
+					wake_up(&audio->wait);
+				} else if (reason == AUDPP_MSG_REASON_NONE) {
+					/* decoder is in disable state */
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_CLOSE;
+					wake_up(&audio->wait);
+				}
+				break;
+			}
+			case AUDPP_DEC_STATUS_INIT:
+				MM_DBG("decoder status: init\n");
+				audpp_cmd_cfg_adec_params(audio);
+				break;
+
+			case AUDPP_DEC_STATUS_CFG:
+				MM_DBG("decoder status: cfg \n");
+				break;
+			case AUDPP_DEC_STATUS_PLAY:
+				MM_DBG("decoder status: play \n");
+				audio->dec_state =
+					MSM_AUD_DECODER_STATE_SUCCESS;
+				wake_up(&audio->wait);
+				break;
+			default:
+				MM_ERR("unknown decoder status \n");
+				break;
+			}
+			break;
+		}
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			MM_DBG("CFG_MSG ENABLE\n");
+			auddec_dsp_config(audio, 1);
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_set_volume_and_pan(audio->dec_id, audio->volume,
+					0);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			MM_DBG("CFG_MSG DISABLE\n");
+			audio->running = 0;
+		} else {
+			MM_ERR("CFG_MSG %d?\n",	msg[0]);
+		}
+		break;
+	case AUDPP_MSG_FLUSH_ACK:
+		MM_DBG("FLUSH_ACK\n");
+		audio->wflush = 0;
+		wake_up(&audio->write_wait);
+		break;
+
+	case AUDPP_MSG_PCMDMAMISSED:
+		MM_DBG("PCMDMAMISSED\n");
+		audio->teos = 1;
+		wake_up(&audio->write_wait);
+		break;
+
+	default:
+		MM_ERR("UNKNOWN (%d)\n", id);
+	}
+
+}
+
+
+struct msm_adsp_ops audpcmdec_adsp_ops = {
+	.event = audplay_dsp_event,
+};
+
+
+#define audplay_send_queue0(audio, cmd, len) \
+	msm_adsp_write(audio->audplay, audio->queue_id, \
+			cmd, len)
+
+static int auddec_dsp_config(struct audio *audio, int enable)
+{
+	u16 cfg_dec_cmd[AUDPP_CMD_CFG_DEC_TYPE_LEN / sizeof(unsigned short)];
+
+	memset(cfg_dec_cmd, 0, sizeof(cfg_dec_cmd));
+
+	cfg_dec_cmd[0] = AUDPP_CMD_CFG_DEC_TYPE;
+	if (enable)
+		cfg_dec_cmd[1 + audio->dec_id] = AUDPP_CMD_UPDATDE_CFG_DEC |
+				AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_PCM;
+	else
+		cfg_dec_cmd[1 + audio->dec_id] = AUDPP_CMD_UPDATDE_CFG_DEC |
+				AUDPP_CMD_DIS_DEC_V;
+
+	return audpp_send_queue1(&cfg_dec_cmd, sizeof(cfg_dec_cmd));
+}
+
+static void audpp_cmd_cfg_adec_params(struct audio *audio)
+{
+	audpp_cmd_cfg_adec_params_wav cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_WAV_LEN;
+	cmd.common.dec_id = audio->dec_id;
+	cmd.common.input_sampling_frequency = audio->out_sample_rate;
+	cmd.stereo_cfg = audio->out_channel_mode;
+	cmd.pcm_width = audio->out_bits;
+	cmd.sign = 0;
+	audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static int audplay_dsp_send_data_avail(struct audio *audio,
+					unsigned idx, unsigned len)
+{
+	audplay_cmd_bitstream_data_avail cmd;
+
+	cmd.cmd_id		= AUDPLAY_CMD_BITSTREAM_DATA_AVAIL;
+	cmd.decoder_id		= audio->dec_id;
+	cmd.buf_ptr		= audio->out[idx].addr;
+	cmd.buf_size		= len/2;
+	cmd.partition_number	= 0;
+	/* complete writes to the input buffer */
+	wmb();
+	return audplay_send_queue0(audio, &cmd, sizeof(cmd));
+}
+
+static void audpcm_async_send_data(struct audio *audio, unsigned needed)
+{
+	unsigned long flags;
+
+	if (!audio->running)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+
+	if (needed && !audio->wflush) {
+		audio->out_needed = 1;
+		if (audio->drv_status & ADRV_STATUS_OBUF_GIVEN) {
+			/* pop one node out of queue */
+			union msm_audio_event_payload payload;
+			struct audpcm_buffer_node *used_buf;
+
+			MM_DBG("consumed\n");
+
+			BUG_ON(list_empty(&audio->out_queue));
+			used_buf = list_first_entry(&audio->out_queue,
+				struct audpcm_buffer_node, list);
+			list_del(&used_buf->list);
+			payload.aio_buf = used_buf->buf;
+			audpcm_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+				payload);
+			kfree(used_buf);
+			audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
+		}
+	}
+	if (audio->out_needed) {
+		struct audpcm_buffer_node *next_buf;
+		audplay_cmd_bitstream_data_avail cmd;
+		if (!list_empty(&audio->out_queue)) {
+			next_buf = list_first_entry(&audio->out_queue,
+					struct audpcm_buffer_node, list);
+			MM_DBG("next_buf %p\n", next_buf);
+			if (next_buf) {
+				MM_DBG("next buf phy %lx len %d\n",
+				next_buf->paddr, next_buf->buf.data_len);
+
+				cmd.cmd_id = AUDPLAY_CMD_BITSTREAM_DATA_AVAIL;
+				if (next_buf->buf.data_len)
+					cmd.decoder_id = audio->dec_id;
+				else {
+					cmd.decoder_id = -1;
+					MM_DBG("input EOS signaled\n");
+				}
+				cmd.buf_ptr	= (unsigned) next_buf->paddr;
+				cmd.buf_size = next_buf->buf.data_len >> 1;
+				cmd.partition_number	= 0;
+				/* complete writes to the input buffer */
+				wmb();
+				audplay_send_queue0(audio, &cmd, sizeof(cmd));
+				audio->out_needed = 0;
+				audio->drv_status |= ADRV_STATUS_OBUF_GIVEN;
+			}
+		}
+	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static void audplay_send_data(struct audio *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+
+	if (!audio->running)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+
+	if (needed && !audio->wflush) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			MM_DBG("frame %d free\n", audio->out_tail);
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+			MM_DBG("frame %d busy\n", audio->out_tail);
+			audplay_dsp_send_data_avail(audio, audio->out_tail,
+					frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+static void audpcm_async_flush(struct audio *audio)
+{
+	struct audpcm_buffer_node *buf_node;
+	struct list_head *ptr, *next;
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	list_for_each_safe(ptr, next, &audio->out_queue) {
+		buf_node = list_entry(ptr, struct audpcm_buffer_node, list);
+		list_del(&buf_node->list);
+		payload.aio_buf = buf_node->buf;
+		audpcm_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+				payload);
+		kfree(buf_node);
+	}
+	audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
+	audio->out_needed = 0;
+	atomic_set(&audio->out_bytes, 0);
+}
+
+static void audio_flush(struct audio *audio)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->out[0].used = 0;
+	audio->out[1].used = 0;
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->reserved = 0;
+	audio->out_needed = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	atomic_set(&audio->out_bytes, 0);
+}
+
+static void audio_ioport_reset(struct audio *audio)
+{
+	if (audio->drv_status & ADRV_STATUS_AIO_INTF) {
+		/* If fsync is in progress, make sure
+		 * return value of fsync indicates
+		 * abort due to flush
+		 */
+		if (audio->drv_status & ADRV_STATUS_FSYNC) {
+			MM_DBG("fsync in progress\n");
+			wake_up(&audio->write_wait);
+			mutex_lock(&audio->write_lock);
+			audio->drv_ops.out_flush(audio);
+			mutex_unlock(&audio->write_lock);
+		} else
+			audio->drv_ops.out_flush(audio);
+	} else {
+		/* Make sure read/write thread are free from
+		 * sleep and knowing that system is not able
+		 * to process io request at the moment
+		 */
+		wake_up(&audio->write_wait);
+		mutex_lock(&audio->write_lock);
+		audio->drv_ops.out_flush(audio);
+		mutex_unlock(&audio->write_lock);
+	}
+}
+
+static int audpcm_events_pending(struct audio *audio)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	return empty || audio->event_abort;
+}
+
+static void audpcm_reset_event_queue(struct audio *audio)
+{
+	unsigned long flags;
+	struct audpcm_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+			struct audpcm_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+			struct audpcm_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	return;
+}
+
+static long audpcm_process_event_req(struct audio *audio, void __user *arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audpcm_event *drv_evt = NULL;
+	int timeout;
+	unsigned long flags;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int) usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(
+			audio->event_wait, audpcm_events_pending(audio),
+			msecs_to_jiffies(timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(
+			audio->event_wait, audpcm_events_pending(audio));
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+			struct audpcm_event, list);
+		list_del(&drv_evt->list);
+	}
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else
+		rc = -1;
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	if (drv_evt && drv_evt->event_type == AUDIO_EVENT_WRITE_DONE) {
+		mutex_lock(&audio->lock);
+		audpcm_pmem_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+				  drv_evt->payload.aio_buf.buf_len, 0);
+		mutex_unlock(&audio->lock);
+	}
+	if (!rc && copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audpcm_pmem_check(struct audio *audio,
+		void *vaddr, unsigned long len)
+{
+	struct audpcm_pmem_region *region_elt;
+	struct audpcm_pmem_region t = { .vaddr = vaddr, .len = len };
+
+	list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+		if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
+		    OVERLAPS(region_elt, &t)) {
+			MM_ERR("region (vaddr %p len %ld)"
+				" clashes with registered region"
+				" (vaddr %p paddr %p len %ld)\n",
+				vaddr, len,
+				region_elt->vaddr,
+				(void *)region_elt->paddr,
+				region_elt->len);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int audpcm_pmem_add(struct audio *audio,
+	struct msm_audio_pmem_info *info)
+{
+	unsigned long paddr, kvaddr, len;
+	struct file *file;
+	struct audpcm_pmem_region *region;
+	struct vm_area_struct *vma;
+	int rc = -EINVAL;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	region = kmalloc(sizeof(*region), GFP_KERNEL);
+	if (!region)
+		return -ENOMEM;
+
+	if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) {
+		kfree(region);
+		return -EINVAL;
+	}
+
+	vma = find_vma_intersection(current->active_mm,
+		(unsigned long) info->vaddr, (unsigned long) info->vaddr+1);
+
+	if (vma && ((vma->vm_end - vma->vm_start) == len)) {
+		rc = audpcm_pmem_check(audio, (void *) vma->vm_start, len);
+		if (rc < 0) {
+			put_pmem_file(file);
+			kfree(region);
+			return rc;
+		}
+		region->vaddr = (void *) vma->vm_start;
+		region->vaddr_ref = info->vaddr;
+		MM_DBG("Valid VMA region vma->vm_start = 0x%8x \
+			vma->vm_end = 0x%8x\n", (int) vma->vm_start,
+			(int) vma->vm_end);
+	} else {
+		MM_ERR("No valid VMA region found\n");
+		put_pmem_file(file);
+		kfree(region);
+		return rc;
+	}
+	region->fd = info->fd;
+	region->paddr = paddr;
+	region->kvaddr = kvaddr;
+	region->len = len;
+	region->file = file;
+	region->ref_cnt = 0;
+	MM_DBG("add region paddr %lx vaddr %p, len %lu\n", region->paddr,
+			region->vaddr, region->len);
+	list_add_tail(&region->list, &audio->pmem_region_queue);
+	return rc;
+}
+
+static int audpcm_pmem_remove(struct audio *audio,
+	struct msm_audio_pmem_info *info)
+{
+	struct audpcm_pmem_region *region;
+	struct list_head *ptr, *next;
+	int rc = -EINVAL;
+
+	MM_DBG("info fd %d vaddr %p\n",	info->fd, info->vaddr);
+
+	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
+		region = list_entry(ptr, struct audpcm_pmem_region, list);
+
+		if ((region->fd == info->fd) &&
+		    (region->vaddr_ref == info->vaddr)) {
+			if (region->ref_cnt) {
+				MM_DBG("region %p in use ref_cnt %d\n",
+						region, region->ref_cnt);
+				break;
+			}
+			MM_DBG("remove region fd %d vaddr %p \n", info->fd,
+					info->vaddr);
+			list_del(&region->list);
+			put_pmem_file(region->file);
+			kfree(region);
+			rc = 0;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static int audpcm_pmem_lookup_vaddr(struct audio *audio, void *addr,
+		     unsigned long len, struct audpcm_pmem_region **region)
+{
+	struct audpcm_pmem_region *region_elt;
+
+	int match_count = 0;
+
+	*region = NULL;
+
+	/* returns physical address or zero */
+	list_for_each_entry(region_elt, &audio->pmem_region_queue,
+		list) {
+		if (addr >= region_elt->vaddr &&
+		    addr < region_elt->vaddr + region_elt->len &&
+		    addr + len <= region_elt->vaddr + region_elt->len) {
+			/* offset since we could pass vaddr inside a registerd
+			 * pmem buffer
+			 */
+			match_count++;
+			if (!*region)
+				*region = region_elt;
+		}
+	}
+
+	if (match_count > 1) {
+		MM_ERR("multiple hits for vaddr %p, len %ld\n", addr, len);
+		list_for_each_entry(region_elt,
+		  &audio->pmem_region_queue, list) {
+			if (addr >= region_elt->vaddr &&
+			    addr < region_elt->vaddr + region_elt->len &&
+			    addr + len <= region_elt->vaddr + region_elt->len)
+				MM_ERR("\t%p, %ld --> %p\n", region_elt->vaddr,
+						region_elt->len,
+						(void *)region_elt->paddr);
+		}
+	}
+
+	return *region ? 0 : -1;
+}
+
+static unsigned long audpcm_pmem_fixup(struct audio *audio, void *addr,
+		    unsigned long len, int ref_up)
+{
+	struct audpcm_pmem_region *region;
+	unsigned long paddr;
+	int ret;
+
+	ret = audpcm_pmem_lookup_vaddr(audio, addr, len, &region);
+	if (ret) {
+		MM_ERR("lookup (%p, %ld) failed\n", addr, len);
+		return 0;
+	}
+	if (ref_up)
+		region->ref_cnt++;
+	else
+		region->ref_cnt--;
+	MM_DBG("found region %p ref_cnt %d\n", region, region->ref_cnt);
+	paddr = region->paddr + (addr - region->vaddr);
+	return paddr;
+}
+
+/* audio -> lock must be held at this point */
+static int audpcm_aio_buf_add(struct audio *audio, unsigned dir,
+	void __user *arg)
+{
+	unsigned long flags;
+	struct audpcm_buffer_node *buf_node;
+
+	buf_node = kmalloc(sizeof(*buf_node), GFP_KERNEL);
+
+	if (!buf_node)
+		return -ENOMEM;
+
+	if (copy_from_user(&buf_node->buf, arg, sizeof(buf_node->buf))) {
+		kfree(buf_node);
+		return -EFAULT;
+	}
+
+	MM_DBG("node %p dir %x buf_addr %p buf_len %d data_len %d\n",
+			buf_node, dir, buf_node->buf.buf_addr,
+			buf_node->buf.buf_len, buf_node->buf.data_len);
+
+	buf_node->paddr = audpcm_pmem_fixup(
+		audio, buf_node->buf.buf_addr,
+		buf_node->buf.buf_len, 1);
+	if (dir) {
+		/* write */
+		if (!buf_node->paddr ||
+		    (buf_node->paddr & 0x1) ||
+		    (buf_node->buf.data_len & 0x1) ||
+		    (!buf_node->buf.data_len)) {
+			kfree(buf_node);
+			return -EINVAL;
+		}
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		list_add_tail(&buf_node->list, &audio->out_queue);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		audio->drv_ops.send_data(audio, 0);
+	}
+
+	MM_DBG("Add buf_node %p paddr %lx\n", buf_node, buf_node->paddr);
+
+	return 0;
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = 0;
+
+	MM_DBG("cmd = %d\n", cmd);
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = audpp_avsync_byte_count(audio->dec_id);
+		stats.sample_count = audpp_avsync_sample_count(audio->dec_id);
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+	if (cmd == AUDIO_SET_VOLUME) {
+		unsigned long flags;
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->volume = arg;
+		if (audio->running)
+			audpp_set_volume_and_pan(audio->dec_id, arg, 0);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		return 0;
+	}
+	if (cmd == AUDIO_GET_EVENT) {
+		MM_DBG("AUDIO_GET_EVENT\n");
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audpcm_process_event_req(audio,
+				(void __user *) arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		return rc;
+	}
+
+	if (cmd == AUDIO_ABORT_GET_EVENT) {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		MM_DBG("AUDIO_START\n");
+		rc = audio_enable(audio);
+		if (!rc) {
+			rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+			MM_INFO("dec_state %d rc = %d\n", audio->dec_state, rc);
+
+			if (audio->dec_state != MSM_AUD_DECODER_STATE_SUCCESS)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		break;
+	case AUDIO_STOP:
+		MM_DBG("AUDIO_STOP\n");
+		rc = audio_disable(audio);
+		audio_ioport_reset(audio);
+		audio->stopped = 0;
+		break;
+	case AUDIO_FLUSH:
+		MM_DBG("AUDIO_FLUSH\n");
+		audio->wflush = 1;
+		audio_ioport_reset(audio);
+		if (audio->running) {
+			audpp_flush(audio->dec_id);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->wflush = 0;
+		}
+		break;
+
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (copy_from_user(&config, (void *) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (config.channel_count == 1) {
+			config.channel_count = AUDPP_CMD_PCM_INTF_MONO_V;
+		} else if (config.channel_count == 2) {
+			config.channel_count = AUDPP_CMD_PCM_INTF_STEREO_V;
+		} else {
+			rc = -EINVAL;
+			break;
+		}
+		if (config.bits == 8)
+			config.bits = AUDPP_CMD_WAV_PCM_WIDTH_8;
+		else if (config.bits == 16)
+			config.bits = AUDPP_CMD_WAV_PCM_WIDTH_16;
+		else if (config.bits == 24)
+			config.bits = AUDPP_CMD_WAV_PCM_WIDTH_24;
+		else {
+			rc = -EINVAL;
+			break;
+		}
+		audio->out_sample_rate = config.sample_rate;
+		audio->out_channel_mode = config.channel_count;
+		audio->out_bits = config.bits;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_size = (audio->out_dma_sz >> 1);
+		config.buffer_count = 2;
+		config.sample_rate = audio->out_sample_rate;
+		if (audio->out_channel_mode == AUDPP_CMD_PCM_INTF_MONO_V)
+			config.channel_count = 1;
+		else
+			config.channel_count = 2;
+		if (audio->out_bits == AUDPP_CMD_WAV_PCM_WIDTH_8)
+			config.bits = 8;
+		else if (audio->out_bits == AUDPP_CMD_WAV_PCM_WIDTH_24)
+			config.bits = 24;
+		else
+			config.bits = 16;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+
+		if (copy_to_user((void *) arg, &config, sizeof(config)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	}
+
+
+	case AUDIO_PAUSE:
+		MM_DBG("AUDIO_PAUSE %ld\n", arg);
+		rc = audpp_pause(audio->dec_id, (int) arg);
+		break;
+
+	case AUDIO_REGISTER_PMEM: {
+			struct msm_audio_pmem_info info;
+			MM_DBG("AUDIO_REGISTER_PMEM\n");
+			if (copy_from_user(&info, (void *) arg, sizeof(info)))
+				rc = -EFAULT;
+			else
+				rc = audpcm_pmem_add(audio, &info);
+			break;
+		}
+
+	case AUDIO_DEREGISTER_PMEM: {
+			struct msm_audio_pmem_info info;
+			MM_DBG("AUDIO_DEREGISTER_PMEM\n");
+			if (copy_from_user(&info, (void *) arg, sizeof(info)))
+				rc = -EFAULT;
+			else
+				rc = audpcm_pmem_remove(audio, &info);
+			break;
+		}
+
+	case AUDIO_ASYNC_WRITE:
+		if (audio->drv_status & ADRV_STATUS_FSYNC)
+			rc = -EBUSY;
+		else
+			rc = audpcm_aio_buf_add(audio, 1, (void __user *) arg);
+		break;
+
+	case AUDIO_ASYNC_READ:
+		MM_ERR("AUDIO_ASYNC_READ not supported\n");
+		rc = -EPERM;
+		break;
+
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+/* Only useful in tunnel-mode */
+int audpcm_async_fsync(struct audio *audio)
+{
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	/* Blocking client sends more data */
+	mutex_lock(&audio->lock);
+	audio->drv_status |= ADRV_STATUS_FSYNC;
+	mutex_unlock(&audio->lock);
+
+	mutex_lock(&audio->write_lock);
+	/* pcm dmamiss message is sent continously
+	 * when decoder is starved so no race
+	 * condition concern
+	 */
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->teos && audio->out_needed &&
+		list_empty(&audio->out_queue))
+		|| audio->wflush || audio->stopped);
+
+	if (audio->stopped || audio->wflush)
+		rc = -EBUSY;
+
+	mutex_unlock(&audio->write_lock);
+	mutex_lock(&audio->lock);
+	audio->drv_status &= ~ADRV_STATUS_FSYNC;
+	mutex_unlock(&audio->lock);
+
+	return rc;
+}
+
+int audpcm_sync_fsync(struct audio *audio)
+{
+	struct buffer *frame;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(!audio->out[0].used &&
+		!audio->out[1].used &&
+		audio->out_needed) || audio->wflush);
+
+	if (rc < 0)
+		goto done;
+	else if (audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (audio->reserved) {
+		MM_DBG("send reserved byte\n");
+		frame = audio->out + audio->out_tail;
+		((char *) frame->data)[0] = audio->rsv_byte;
+		((char *) frame->data)[1] = 0;
+		frame->used = 2;
+		audio->drv_ops.send_data(audio, 0);
+
+		rc = wait_event_interruptible(audio->write_wait,
+			(!audio->out[0].used &&
+			!audio->out[1].used &&
+			audio->out_needed) || audio->wflush);
+
+		if (rc < 0)
+			goto done;
+		else if (audio->wflush) {
+			rc = -EBUSY;
+			goto done;
+		}
+	}
+
+	/* pcm dmamiss message is sent continously
+	 * when decoder is starved so no race
+	 * condition concern
+	 */
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		audio->teos || audio->wflush);
+
+	if (audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+	return rc;
+}
+
+int audpcm_fsync(struct file *file, loff_t a, loff_t b, int datasync)
+{
+	struct audio *audio = file->private_data;
+
+	if (!audio->running)
+		return -EINVAL;
+
+	return audio->drv_ops.fsync(audio);
+}
+
+static ssize_t audio_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	char *cpy_ptr;
+	int rc = 0;
+	unsigned dsize;
+
+	if (audio->drv_status & ADRV_STATUS_AIO_INTF)
+		return -EPERM;
+
+	MM_DBG("cnt=%d\n", count);
+
+	mutex_lock(&audio->write_lock);
+	while (count > 0) {
+		frame = audio->out + audio->out_head;
+		cpy_ptr = frame->data;
+		dsize = 0;
+		rc = wait_event_interruptible(audio->write_wait,
+					      (frame->used == 0)
+					      || (audio->stopped)
+						  || (audio->wflush));
+		if (rc < 0)
+			break;
+		if (audio->stopped || audio->wflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (audio->reserved) {
+			MM_DBG("append reserved byte %x\n", audio->rsv_byte);
+			*cpy_ptr = audio->rsv_byte;
+			xfer = (count > (frame->size - 1)) ?
+				frame->size - 1 : count;
+			cpy_ptr++;
+			dsize = 1;
+			audio->reserved = 0;
+		} else
+			xfer = (count > frame->size) ? frame->size : count;
+
+		if (copy_from_user(cpy_ptr, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+
+		dsize += xfer;
+		if (dsize & 1) {
+			audio->rsv_byte = ((char *) frame->data)[dsize - 1];
+			MM_DBG("odd length buf reserve last byte %x\n",
+					audio->rsv_byte);
+			audio->reserved = 1;
+			dsize--;
+		}
+		count -= xfer;
+		buf += xfer;
+
+		if (dsize > 0) {
+			audio->out_head ^= 1;
+			frame->used = dsize;
+			audio->drv_ops.send_data(audio, 0);
+		}
+	}
+	mutex_unlock(&audio->write_lock);
+	if (buf > start)
+		return buf - start;
+
+	return rc;
+}
+
+static void audpcm_reset_pmem_region(struct audio *audio)
+{
+	struct audpcm_pmem_region *region;
+	struct list_head *ptr, *next;
+
+	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
+		region = list_entry(ptr, struct audpcm_pmem_region, list);
+		list_del(&region->list);
+		put_pmem_file(region->file);
+		kfree(region);
+	}
+
+	return;
+}
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	MM_DBG("audio instance 0x%08x freeing\n", (int)audio);
+	mutex_lock(&audio->lock);
+	audio_disable(audio);
+	if (audio->rmt_resource_released == 0)
+		rmt_put_resource(audio);
+	audio->drv_ops.out_flush(audio);
+	audpcm_reset_pmem_region(audio);
+
+	msm_adsp_put(audio->audplay);
+	audpp_adec_free(audio->dec_id);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&audio->suspend_ctl.node);
+#endif
+	audio->opened = 0;
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audpcm_reset_event_queue(audio);
+	MM_DBG("pmem area = 0x%8x\n", (unsigned int)audio->data);
+	if (audio->data) {
+		iounmap(audio->map_v_write);
+		free_contiguous_memory_by_paddr(audio->phys);
+	}
+	mutex_unlock(&audio->lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio);
+	return 0;
+}
+
+static void audpcm_post_event(struct audio *audio, int type,
+	union msm_audio_event_payload payload)
+{
+	struct audpcm_event *e_node = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+			struct audpcm_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audpcm_event), GFP_ATOMIC);
+		if (!e_node) {
+			MM_ERR("No mem to post event %d\n", type);
+			spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	wake_up(&audio->event_wait);
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audpcm_suspend(struct early_suspend *h)
+{
+	struct audpcm_suspend_ctl *ctl =
+		container_of(h, struct audpcm_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audpcm_post_event(ctl->audio, AUDIO_EVENT_SUSPEND, payload);
+}
+
+static void audpcm_resume(struct early_suspend *h)
+{
+	struct audpcm_suspend_ctl *ctl =
+		container_of(h, struct audpcm_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audpcm_post_event(ctl->audio, AUDIO_EVENT_RESUME, payload);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audpcm_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audpcm_debug_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 4096;
+	static char buffer[4096];
+	int n = 0;
+	struct audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "enabled %d\n", audio->enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_buf_sz %d\n", audio->out[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "volume %x \n", audio->volume);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "sample rate %d \n", audio->out_sample_rate);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		"channel mode %d \n", audio->out_channel_mode);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "running %d \n", audio->running);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				"dec state %d \n", audio->dec_state);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_needed %d \n", audio->out_needed);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_head %d \n", audio->out_head);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_tail %d \n", audio->out_tail);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out[0].used %d \n", audio->out[0].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out[1].used %d \n", audio->out[1].used);
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audpcm_debug_fops = {
+	.read = audpcm_debug_read,
+	.open = audpcm_debug_open,
+};
+#endif
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = NULL;
+	int rc, i, dec_attrb, decid;
+	struct audpcm_event *e_node = NULL;
+	unsigned pmem_sz = DMASZ_MAX;
+
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_pcm_dec_" + 5];
+#endif
+
+	/* Allocate audio instance, set to zero */
+	audio = kzalloc(sizeof(struct audio), GFP_KERNEL);
+	if (!audio) {
+		MM_ERR("no memory to allocate audio instance \n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	MM_DBG("audio instance 0x%08x created\n", (int)audio);
+
+	/* Allocate the decoder */
+	dec_attrb = AUDDEC_DEC_PCM;
+	if (file->f_mode & FMODE_READ) {
+		MM_ERR("Non-Tunneled mode not supported\n");
+		rc = -EPERM;
+		kfree(audio);
+		goto done;
+	} else
+		dec_attrb |= MSM_AUD_MODE_TUNNEL;
+
+	decid = audpp_adec_alloc(dec_attrb, &audio->module_name,
+			&audio->queue_id);
+	if (decid < 0) {
+		MM_ERR("No free decoder available\n");
+		rc = -ENODEV;
+		MM_DBG("audio instance 0x%08x freeing\n", (int)audio);
+		kfree(audio);
+		goto done;
+	}
+	audio->dec_id = decid & MSM_AUD_DECODER_MASK;
+
+	/* Non AIO interface */
+	if (!(file->f_flags & O_NONBLOCK)) {
+		while (pmem_sz >= DMASZ_MIN) {
+			MM_DBG("pmemsz = %d\n", pmem_sz);
+			audio->phys = allocate_contiguous_ebi_nomap(pmem_sz,
+								SZ_4K);
+			if (audio->phys) {
+				audio->map_v_write = ioremap(
+							audio->phys, pmem_sz);
+				if (IS_ERR(audio->map_v_write)) {
+					MM_ERR("could not map write\
+							buffers\n");
+					rc = -ENOMEM;
+					free_contiguous_memory_by_paddr(
+								audio->phys);
+					audpp_adec_free(audio->dec_id);
+					MM_DBG("audio instance 0x%08x\
+						freeing\n", (int)audio);
+					kfree(audio);
+					goto done;
+				}
+				audio->data = audio->map_v_write;
+				MM_DBG("write buf: phy addr 0x%08x kernel addr\
+					0x%08x\n", audio->phys,\
+					(int)audio->data);
+				break;
+			} else if (pmem_sz == DMASZ_MIN) {
+				MM_ERR("could not allocate write buffers\n");
+				rc = -ENOMEM;
+				audpp_adec_free(audio->dec_id);
+				MM_DBG("audio instance 0x%08x freeing\n",\
+					(int)audio);
+				kfree(audio);
+				goto done;
+			} else
+				pmem_sz >>= 1;
+		}
+		audio->out_dma_sz = pmem_sz;
+	}
+
+	rc = audmgr_open(&audio->audmgr);
+	if (rc)
+		goto err;
+
+	rc = msm_adsp_get(audio->module_name, &audio->audplay,
+			&audpcmdec_adsp_ops, audio);
+	if (rc) {
+		MM_ERR("failed to get %s module\n", audio->module_name);
+		audmgr_close(&audio->audmgr);
+		goto err;
+	}
+
+	rc = rmt_get_resource(audio);
+	if (rc) {
+		MM_ERR("ADSP resources are not available for PCM session \
+			 0x%08x on decoder: %d\n", (int)audio, audio->dec_id);
+		audmgr_close(&audio->audmgr);
+		msm_adsp_put(audio->audplay);
+		goto err;
+	}
+
+	if (file->f_flags & O_NONBLOCK) {
+		MM_DBG("set to aio interface\n");
+		audio->drv_status |= ADRV_STATUS_AIO_INTF;
+		audio->drv_ops.send_data = audpcm_async_send_data;
+		audio->drv_ops.out_flush = audpcm_async_flush;
+		audio->drv_ops.fsync = audpcm_async_fsync;
+	} else {
+		MM_DBG("set to std io interface\n");
+		audio->drv_ops.send_data = audplay_send_data;
+		audio->drv_ops.out_flush = audio_flush;
+		audio->drv_ops.fsync = audpcm_sync_fsync;
+		audio->out[0].data = audio->data + 0;
+		audio->out[0].addr = audio->phys + 0;
+		audio->out[0].size = (audio->out_dma_sz >> 1);
+
+		audio->out[1].data = audio->data + audio->out[0].size;
+		audio->out[1].addr = audio->phys + audio->out[0].size;
+		audio->out[1].size = audio->out[0].size;
+	}
+
+	/* Initialize all locks of audio instance */
+	mutex_init(&audio->lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->get_event_lock);
+	spin_lock_init(&audio->dsp_lock);
+	init_waitqueue_head(&audio->write_wait);
+	INIT_LIST_HEAD(&audio->out_queue);
+	INIT_LIST_HEAD(&audio->pmem_region_queue);
+	INIT_LIST_HEAD(&audio->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+	init_waitqueue_head(&audio->wait);
+	init_waitqueue_head(&audio->event_wait);
+	spin_lock_init(&audio->event_queue_lock);
+
+	audio->out_sample_rate = 44100;
+	audio->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V;
+	audio->out_bits = AUDPP_CMD_WAV_PCM_WIDTH_16;
+	audio->volume = 0x2000;
+	audio->drv_ops.out_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_pcm_dec_%04x", audio->dec_id);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+		NULL, (void *) audio, &audpcm_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		MM_DBG("debugfs_create_file failed\n");
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	audio->suspend_ctl.node.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+	audio->suspend_ctl.node.resume = audpcm_resume;
+	audio->suspend_ctl.node.suspend = audpcm_suspend;
+	audio->suspend_ctl.audio = audio;
+	register_early_suspend(&audio->suspend_ctl.node);
+#endif
+	for (i = 0; i < AUDPCM_EVENT_NUM; i++) {
+		e_node = kmalloc(sizeof(struct audpcm_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			MM_ERR("event pkt alloc failed\n");
+			break;
+		}
+	}
+done:
+	return rc;
+err:
+	if (audio->data) {
+		iounmap(audio->map_v_write);
+		free_contiguous_memory_by_paddr(audio->phys);
+	}
+	audpp_adec_free(audio->dec_id);
+	MM_DBG("audio instance 0x%08x freeing\n", (int)audio);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_pcm_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audio_open,
+	.release	= audio_release,
+	.write		= audio_write,
+	.unlocked_ioctl	= audio_ioctl,
+	.fsync = audpcm_fsync,
+};
+
+struct miscdevice audio_pcm_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_pcm_dec",
+	.fops	= &audio_pcm_fops,
+};
+
+static int __init audio_init(void)
+{
+	return misc_register(&audio_pcm_misc);
+}
+
+device_initcall(audio_init);
diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
new file mode 100644
index 0000000..851980d
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
@@ -0,0 +1,956 @@
+/* arch/arm/mach-msm/qdsp5/audio_pcm_in.c
+ *
+ * pcm audio input device
+ *
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This code is based in part on arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c,
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/delay.h>
+
+#include <linux/msm_audio.h>
+
+#include <mach/msm_memtypes.h>
+#include <linux/memory_alloc.h>
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <mach/msm_adsp.h>
+#include <mach/msm_rpcrouter.h>
+
+#include "audmgr.h"
+
+#include <mach/qdsp5/qdsp5audpreproc.h>
+#include <mach/qdsp5/qdsp5audpreproccmdi.h>
+#include <mach/qdsp5/qdsp5audpreprocmsg.h>
+#include <mach/qdsp5/qdsp5audreccmdi.h>
+#include <mach/qdsp5/qdsp5audrecmsg.h>
+#include <mach/debug_mm.h>
+
+/* FRAME_NUM must be a power of two */
+#define FRAME_NUM		(8)
+#define FRAME_SIZE		(2052 * 2)
+#define MONO_DATA_SIZE		(2048)
+#define STEREO_DATA_SIZE	(MONO_DATA_SIZE * 2)
+#define DMASZ			(FRAME_SIZE * FRAME_NUM)
+#define MSM_AUD_BUFFER_UPDATE_WAIT_MS 2000
+
+struct buffer {
+	void *data;
+	uint32_t size;
+	uint32_t read;
+	uint32_t addr;
+};
+
+struct audio_in {
+	struct buffer in[FRAME_NUM];
+
+	spinlock_t dsp_lock;
+
+	atomic_t in_bytes;
+
+	struct mutex lock;
+	struct mutex read_lock;
+	wait_queue_head_t wait;
+
+	struct msm_adsp_module *audpre;
+	struct msm_adsp_module *audrec;
+	const char *module_name;
+	unsigned queue_ids;
+	uint16_t enc_id; /* Session Id */
+
+	/* configuration to use on next enable */
+	uint32_t samp_rate;
+	uint32_t channel_mode;
+	uint32_t buffer_size; /* 2048 for mono, 4096 for stereo */
+	uint32_t enc_type; /* 0 for PCM */
+	uint32_t mode; /* Tunnel for PCM */
+	uint32_t dsp_cnt;
+	uint32_t in_head; /* next buffer dsp will write */
+	uint32_t in_tail; /* next buffer read() will read */
+	uint32_t in_count; /* number of buffers available to read() */
+
+	unsigned short samp_rate_index;
+	uint32_t audrec_obj_idx ;
+
+	struct audmgr audmgr;
+
+	/* data allocated for various buffers */
+	char *data;
+	dma_addr_t phys;
+
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+
+	/* audpre settings */
+	int tx_agc_enable;
+	audpreproc_cmd_cfg_agc_params tx_agc_cfg;
+	int ns_enable;
+	audpreproc_cmd_cfg_ns_params ns_cfg;
+	/* For different sample rate, the coeff might be different. *
+	 * All the coeff should be passed from user space	    */
+	int iir_enable;
+	audpreproc_cmd_cfg_iir_tuning_filter_params iir_cfg;
+};
+
+static int audpcm_in_dsp_enable(struct audio_in *audio, int enable);
+static int audpcm_in_encmem_config(struct audio_in *audio);
+static int audpcm_in_encparam_config(struct audio_in *audio);
+static int audpcm_in_dsp_read_buffer(struct audio_in *audio, uint32_t read_cnt);
+static void audpcm_in_flush(struct audio_in *audio);
+static int audio_dsp_set_tx_agc(struct audio_in *audio);
+static int audio_dsp_set_ns(struct audio_in *audio);
+static int audio_dsp_set_iir(struct audio_in *audio);
+
+static unsigned convert_dsp_samp_index(unsigned index)
+{
+	switch (index) {
+	case 48000:	return AUDREC_CMD_SAMP_RATE_INDX_48000;
+	case 44100:	return AUDREC_CMD_SAMP_RATE_INDX_44100;
+	case 32000:	return AUDREC_CMD_SAMP_RATE_INDX_32000;
+	case 24000:	return AUDREC_CMD_SAMP_RATE_INDX_24000;
+	case 22050:	return AUDREC_CMD_SAMP_RATE_INDX_22050;
+	case 16000:	return AUDREC_CMD_SAMP_RATE_INDX_16000;
+	case 12000:	return AUDREC_CMD_SAMP_RATE_INDX_12000;
+	case 11025:	return AUDREC_CMD_SAMP_RATE_INDX_11025;
+	case 8000:	return AUDREC_CMD_SAMP_RATE_INDX_8000;
+	default:	return AUDREC_CMD_SAMP_RATE_INDX_11025;
+	}
+}
+
+static unsigned convert_samp_rate(unsigned hz)
+{
+	switch (hz) {
+	case 48000: return RPC_AUD_DEF_SAMPLE_RATE_48000;
+	case 44100: return RPC_AUD_DEF_SAMPLE_RATE_44100;
+	case 32000: return RPC_AUD_DEF_SAMPLE_RATE_32000;
+	case 24000: return RPC_AUD_DEF_SAMPLE_RATE_24000;
+	case 22050: return RPC_AUD_DEF_SAMPLE_RATE_22050;
+	case 16000: return RPC_AUD_DEF_SAMPLE_RATE_16000;
+	case 12000: return RPC_AUD_DEF_SAMPLE_RATE_12000;
+	case 11025: return RPC_AUD_DEF_SAMPLE_RATE_11025;
+	case 8000:  return RPC_AUD_DEF_SAMPLE_RATE_8000;
+	default:    return RPC_AUD_DEF_SAMPLE_RATE_11025;
+	}
+}
+
+static unsigned convert_samp_index(unsigned index)
+{
+	switch (index) {
+	case RPC_AUD_DEF_SAMPLE_RATE_48000:	return 48000;
+	case RPC_AUD_DEF_SAMPLE_RATE_44100:	return 44100;
+	case RPC_AUD_DEF_SAMPLE_RATE_32000:	return 32000;
+	case RPC_AUD_DEF_SAMPLE_RATE_24000:	return 24000;
+	case RPC_AUD_DEF_SAMPLE_RATE_22050:	return 22050;
+	case RPC_AUD_DEF_SAMPLE_RATE_16000:	return 16000;
+	case RPC_AUD_DEF_SAMPLE_RATE_12000:	return 12000;
+	case RPC_AUD_DEF_SAMPLE_RATE_11025:	return 11025;
+	case RPC_AUD_DEF_SAMPLE_RATE_8000:	return 8000;
+	default:				return 11025;
+	}
+}
+
+/* must be called with audio->lock held */
+static int audpcm_in_enable(struct audio_in *audio)
+{
+	struct audmgr_config cfg;
+	int rc;
+
+	if (audio->enabled)
+		return 0;
+
+	cfg.tx_rate = audio->samp_rate;
+	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+	cfg.def_method = RPC_AUD_DEF_METHOD_RECORD;
+	cfg.codec = RPC_AUD_DEF_CODEC_PCM;
+	cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+	rc = audmgr_enable(&audio->audmgr, &cfg);
+	if (rc < 0)
+		return rc;
+
+	if (msm_adsp_enable(audio->audpre)) {
+		MM_ERR("msm_adsp_enable(audpre) failed\n");
+		audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+	if (msm_adsp_enable(audio->audrec)) {
+		audmgr_disable(&audio->audmgr);
+		msm_adsp_disable(audio->audpre);
+		MM_ERR("msm_adsp_enable(audrec) failed\n");
+		return -ENODEV;
+	}
+
+	audio->enabled = 1;
+	audpcm_in_dsp_enable(audio, 1);
+
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audpcm_in_disable(struct audio_in *audio)
+{
+	if (audio->enabled) {
+		audio->enabled = 0;
+
+		audpcm_in_dsp_enable(audio, 0);
+
+		audio->stopped = 1;
+		wake_up(&audio->wait);
+
+		msm_adsp_disable(audio->audrec);
+		msm_adsp_disable(audio->audpre);
+		audmgr_disable(&audio->audmgr);
+	}
+	return 0;
+}
+
+/* ------------------- dsp --------------------- */
+static void audpre_dsp_event(void *data, unsigned id, size_t len,
+			    void (*getevent)(void *ptr, size_t len))
+{
+	uint16_t msg[2];
+	getevent(msg, sizeof(msg));
+
+	switch (id) {
+	case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
+		MM_INFO("type %d, status_flag %d\n", msg[0], msg[1]);
+		break;
+	case AUDPREPROC_MSG_ERROR_MSG_ID:
+		MM_ERR("err_index %d\n", msg[0]);
+		break;
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audpreproctask)\n");
+		break;
+	default:
+		MM_ERR("unknown event %d\n", id);
+	}
+}
+
+struct audio_frame {
+	uint16_t count_low;
+	uint16_t count_high;
+	uint16_t bytes;
+	uint16_t unknown;
+	unsigned char samples[];
+} __packed;
+
+static void audpcm_in_get_dsp_frames(struct audio_in *audio)
+{
+	struct audio_frame *frame;
+	uint32_t index;
+	unsigned long flags;
+
+	index = audio->in_head;
+
+	frame = (void *) (((char *)audio->in[index].data) -
+			sizeof(*frame));
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->in[index].size = frame->bytes;
+
+	audio->in_head = (audio->in_head + 1) & (FRAME_NUM - 1);
+
+	/* If overflow, move the tail index foward. */
+	if (audio->in_head == audio->in_tail) {
+		audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
+		MM_ERR("Error! not able to keep up the read\n");
+	} else
+		audio->in_count++;
+
+	audpcm_in_dsp_read_buffer(audio, audio->dsp_cnt++);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+
+	wake_up(&audio->wait);
+}
+
+static void audrec_dsp_event(void *data, unsigned id, size_t len,
+			    void (*getevent)(void *ptr, size_t len))
+{
+	struct audio_in *audio = NULL;
+	uint16_t msg[3];
+
+	if (data)
+		audio = data;
+	else {
+		MM_ERR("invalid data for event %x\n", id);
+		return;
+	}
+
+	getevent(msg, sizeof(msg));
+
+	switch (id) {
+	case AUDREC_MSG_CMD_CFG_DONE_MSG: {
+		if (msg[0] & AUDREC_MSG_CFG_DONE_ENC_ENA) {
+			audio->audrec_obj_idx = msg[1];
+			MM_INFO("CFG ENABLED\n");
+			audpcm_in_encmem_config(audio);
+		} else {
+			MM_INFO("CFG SLEEP\n");
+			audio->running = 0;
+			audio->tx_agc_enable = 0;
+			audio->ns_enable = 0;
+			audio->iir_enable = 0;
+		}
+		break;
+	}
+	case AUDREC_MSG_CMD_AREC_MEM_CFG_DONE_MSG: {
+		MM_DBG("AREC_MEM_CFG_DONE_MSG\n");
+		audpcm_in_encparam_config(audio);
+		break;
+	}
+	case AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG: {
+		MM_INFO("PARAM CFG DONE\n");
+		audio->running = 1;
+		audio_dsp_set_tx_agc(audio);
+		audio_dsp_set_ns(audio);
+		audio_dsp_set_iir(audio);
+		break;
+	}
+	case AUDREC_MSG_NO_EXT_PKT_AVAILABLE_MSG: {
+		MM_DBG("ERROR %x\n", msg[0]);
+		break;
+	}
+	case AUDREC_MSG_PACKET_READY_MSG: {
+		struct audrec_msg_packet_ready_msg pkt_ready_msg;
+
+		getevent(&pkt_ready_msg, AUDREC_MSG_PACKET_READY_MSG_LEN);
+		MM_DBG("UP_PACKET_READY_MSG: write cnt msw  %d \
+		write cnt lsw %d read cnt msw %d  read cnt lsw %d \n",\
+		pkt_ready_msg.pkt_counter_msw, \
+		pkt_ready_msg.pkt_counter_lsw, \
+		pkt_ready_msg.pkt_read_cnt_msw, \
+		pkt_ready_msg.pkt_read_cnt_lsw);
+
+		audpcm_in_get_dsp_frames(audio);
+		break;
+	}
+	case ADSP_MESSAGE_ID: {
+		MM_DBG("Received ADSP event: module \
+				enable/disable(audrectask)\n");
+		break;
+	}
+	default:
+		MM_ERR("unknown event %d\n", id);
+	}
+}
+
+static struct msm_adsp_ops audpre_adsp_ops = {
+	.event = audpre_dsp_event,
+};
+
+static struct msm_adsp_ops audrec_adsp_ops = {
+	.event = audrec_dsp_event,
+};
+
+
+#define audio_send_queue_pre(audio, cmd, len) \
+	msm_adsp_write(audio->audpre, QDSP_uPAudPreProcCmdQueue, cmd, len)
+
+#define audio_send_queue_recbs(audio, cmd, len) \
+	msm_adsp_write(audio->audrec, ((audio->queue_ids & 0xFFFF0000) >> 16),\
+			cmd, len)
+#define audio_send_queue_rec(audio, cmd, len) \
+	msm_adsp_write(audio->audrec, (audio->queue_ids & 0x0000FFFF),\
+			cmd, len)
+
+static int audio_dsp_set_tx_agc(struct audio_in *audio)
+{
+	audpreproc_cmd_cfg_agc_params cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	audio->tx_agc_cfg.cmd_id = AUDPREPROC_CMD_CFG_AGC_PARAMS;
+	if (audio->tx_agc_enable) {
+		/* cmd.tx_agc_param_mask = 0xFE00 from sample code */
+		audio->tx_agc_cfg.tx_agc_param_mask =
+		(1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_SLOPE) |
+		(1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_TH) |
+		(1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_EXP_SLOPE) |
+		(1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_EXP_TH) |
+		(1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_AIG_FLAG) |
+		(1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_COMP_STATIC_GAIN) |
+		(1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_TX_AGC_ENA_FLAG);
+		audio->tx_agc_cfg.tx_agc_enable_flag =
+			AUDPREPROC_CMD_TX_AGC_ENA_FLAG_ENA;
+		/* cmd.param_mask = 0xFFF0 from sample code */
+		audio->tx_agc_cfg.param_mask =
+			(1 << AUDPREPROC_CMD_PARAM_MASK_RMS_TAY) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_RELEASEK) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_DELAY) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_ATTACKK) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_LEAKRATE_SLOW) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_LEAKRATE_FAST) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_AIG_RELEASEK) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_AIG_MIN) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_AIG_MAX) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_LEAK_UP) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_LEAK_DOWN) |
+			(1 << AUDPREPROC_CMD_PARAM_MASK_AIG_ATTACKK);
+	} else {
+		audio->tx_agc_cfg.tx_agc_param_mask =
+			(1 << AUDPREPROC_CMD_TX_AGC_PARAM_MASK_TX_AGC_ENA_FLAG);
+		audio->tx_agc_cfg.tx_agc_enable_flag =
+			AUDPREPROC_CMD_TX_AGC_ENA_FLAG_DIS;
+	}
+	cmd = audio->tx_agc_cfg;
+
+	return audio_send_queue_pre(audio, &cmd, sizeof(cmd));
+}
+
+static int audio_enable_tx_agc(struct audio_in *audio, int enable)
+{
+	if (audio->tx_agc_enable != enable) {
+		audio->tx_agc_enable = enable;
+		if (audio->running)
+			audio_dsp_set_tx_agc(audio);
+	}
+	return 0;
+}
+
+static int audio_dsp_set_ns(struct audio_in *audio)
+{
+	audpreproc_cmd_cfg_ns_params cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	audio->ns_cfg.cmd_id = AUDPREPROC_CMD_CFG_NS_PARAMS;
+
+	if (audio->ns_enable) {
+		/* cmd.ec_mode_new is fixed as 0x0064 when enable
+		 * from sample code */
+		audio->ns_cfg.ec_mode_new =
+			AUDPREPROC_CMD_EC_MODE_NEW_NS_ENA |
+			AUDPREPROC_CMD_EC_MODE_NEW_HB_ENA |
+			AUDPREPROC_CMD_EC_MODE_NEW_VA_ENA;
+	} else {
+		audio->ns_cfg.ec_mode_new =
+			AUDPREPROC_CMD_EC_MODE_NEW_NLMS_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_DES_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_NS_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_CNI_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_NLES_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_HB_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_VA_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_PCD_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_FEHI_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_NEHI_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_NLPP_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_FNE_DIS |
+			AUDPREPROC_CMD_EC_MODE_NEW_PRENLMS_DIS;
+	}
+	cmd = audio->ns_cfg;
+
+	return audio_send_queue_pre(audio, &cmd, sizeof(cmd));
+}
+
+static int audio_enable_ns(struct audio_in *audio, int enable)
+{
+	if (audio->ns_enable != enable) {
+		audio->ns_enable = enable;
+		if (audio->running)
+			audio_dsp_set_ns(audio);
+	}
+	return 0;
+}
+
+static int audio_dsp_set_iir(struct audio_in *audio)
+{
+	audpreproc_cmd_cfg_iir_tuning_filter_params cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	audio->iir_cfg.cmd_id = AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS;
+
+	if (audio->iir_enable)
+		/* cmd.active_flag is 0xFFFF from sample code but 0x0001 here */
+		audio->iir_cfg.active_flag = AUDPREPROC_CMD_IIR_ACTIVE_FLAG_ENA;
+	else
+		audio->iir_cfg.active_flag = AUDPREPROC_CMD_IIR_ACTIVE_FLAG_DIS;
+
+	cmd = audio->iir_cfg;
+
+	return audio_send_queue_pre(audio, &cmd, sizeof(cmd));
+}
+
+static int audio_enable_iir(struct audio_in *audio, int enable)
+{
+	if (audio->iir_enable != enable) {
+		audio->iir_enable = enable;
+		if (audio->running)
+			audio_dsp_set_iir(audio);
+	}
+	return 0;
+}
+
+static int audpcm_in_dsp_enable(struct audio_in *audio, int enable)
+{
+	struct audrec_cmd_enc_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_ENC_CFG;
+
+	cmd.audrec_enc_type = (audio->enc_type & 0xFF) |
+	(enable ? AUDREC_CMD_ENC_ENA : AUDREC_CMD_ENC_DIS);
+	/* Don't care */
+	cmd.audrec_obj_idx = audio->audrec_obj_idx;
+
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static int audpcm_in_encmem_config(struct audio_in *audio)
+{
+	struct audrec_cmd_arecmem_cfg cmd;
+	uint16_t cnt = 0;
+	uint16_t *data = (void *) audio->data;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	cmd.cmd_id = AUDREC_CMD_ARECMEM_CFG;
+	cmd.audrec_obj_idx = audio->audrec_obj_idx;
+	/* Rate at which packet complete message comes */
+	cmd.audrec_up_pkt_intm_cnt = 1;
+	cmd.audrec_extpkt_buffer_msw = audio->phys >> 16;
+	cmd.audrec_extpkt_buffer_lsw = audio->phys;
+	/* Max Buffer no available for frames */
+	cmd.audrec_extpkt_buffer_num = FRAME_NUM;
+
+	/* prepare buffer pointers:
+	 * Mono: 1024 samples + 4 halfword header
+	 * Stereo: 2048 samples + 4 halfword header
+	 */
+	for (cnt = 0; cnt < FRAME_NUM; cnt++) {
+		audio->in[cnt].data = data + 4;
+			data += (4 + (audio->channel_mode ? 2048 : 1024));
+	}
+
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static int audpcm_in_encparam_config(struct audio_in *audio)
+{
+	struct audrec_cmd_arecparam_wav_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDREC_CMD_ARECPARAM_CFG;
+	cmd.common.audrec_obj_idx = audio->audrec_obj_idx;
+	cmd.samp_rate_idx = audio->samp_rate_index;
+	cmd.stereo_mode = audio->channel_mode; /* 0 for mono, 1 for stereo */
+
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static int audpcm_in_dsp_read_buffer(struct audio_in *audio, uint32_t read_cnt)
+{
+	audrec_cmd_packet_ext_ptr cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_PACKET_EXT_PTR;
+	cmd.type = audio->audrec_obj_idx;
+	cmd.curr_rec_count_msw = read_cnt >> 16;
+	cmd.curr_rec_count_lsw = read_cnt;
+
+	return audio_send_queue_recbs(audio, &cmd, sizeof(cmd));
+}
+
+/* ------------------- device --------------------- */
+
+static void audpcm_in_flush(struct audio_in *audio)
+{
+	int i;
+
+	audio->dsp_cnt = 0;
+	audio->in_head = 0;
+	audio->in_tail = 0;
+	audio->in_count = 0;
+	for (i = FRAME_NUM-1; i >= 0; i--) {
+		audio->in[i].size = 0;
+		audio->in[i].read = 0;
+	}
+}
+
+static long audpcm_in_ioctl(struct file *file,
+				unsigned int cmd, unsigned long arg)
+{
+	struct audio_in *audio = file->private_data;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = atomic_read(&audio->in_bytes);
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START: {
+		rc = audpcm_in_enable(audio);
+		audio->stopped = 0;
+		break;
+	}
+	case AUDIO_STOP:
+		rc = audpcm_in_disable(audio);
+		break;
+	case AUDIO_FLUSH:
+		if (audio->stopped) {
+			/* Make sure we're stopped and we wake any threads
+			 * that might be blocked holding the read_lock.
+			 * While audio->stopped read threads will always
+			 * exit immediately.
+			 */
+			wake_up(&audio->wait);
+			mutex_lock(&audio->read_lock);
+			audpcm_in_flush(audio);
+			mutex_unlock(&audio->read_lock);
+		}
+		break;
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config cfg;
+
+		if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (cfg.channel_count == 1) {
+			cfg.channel_count = AUDREC_CMD_STEREO_MODE_MONO;
+		} else if (cfg.channel_count == 2) {
+			cfg.channel_count = AUDREC_CMD_STEREO_MODE_STEREO;
+		} else {
+			rc = -EINVAL;
+			break;
+		}
+
+		audio->samp_rate = convert_samp_rate(cfg.sample_rate);
+		audio->samp_rate_index =
+		  convert_dsp_samp_index(cfg.sample_rate);
+		audio->channel_mode = cfg.channel_count;
+		audio->buffer_size =
+				audio->channel_mode ? STEREO_DATA_SIZE
+							: MONO_DATA_SIZE;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config cfg;
+		cfg.buffer_size = audio->buffer_size;
+		cfg.buffer_count = FRAME_NUM;
+		cfg.sample_rate = convert_samp_index(audio->samp_rate);
+		if (audio->channel_mode == AUDREC_CMD_STEREO_MODE_MONO)
+			cfg.channel_count = 1;
+		else
+			cfg.channel_count = 2;
+		cfg.type = 0;
+		cfg.unused[0] = 0;
+		cfg.unused[1] = 0;
+		cfg.unused[2] = 0;
+		if (copy_to_user((void *) arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static ssize_t audpcm_in_read(struct file *file,
+				char __user *buf,
+				size_t count, loff_t *pos)
+{
+	struct audio_in *audio = file->private_data;
+	unsigned long flags;
+	const char __user *start = buf;
+	void *data;
+	uint32_t index;
+	uint32_t size;
+	int rc = 0;
+
+	mutex_lock(&audio->read_lock);
+	while (count > 0) {
+		rc = wait_event_interruptible_timeout(
+			audio->wait, (audio->in_count > 0) || audio->stopped,
+			msecs_to_jiffies(MSM_AUD_BUFFER_UPDATE_WAIT_MS));
+		if (rc == 0) {
+			rc = -ETIMEDOUT;
+			break;
+		} else if (rc < 0) {
+			break;
+		}
+
+		if (audio->stopped && !audio->in_count) {
+			rc = 0;/* End of File */
+			break;
+		}
+
+		index = audio->in_tail;
+		data = (uint8_t *) audio->in[index].data;
+		size = audio->in[index].size;
+		if (count >= size) {
+			/* order the reads on the buffer */
+			dma_coherent_post_ops();
+			if (copy_to_user(buf, data, size)) {
+				rc = -EFAULT;
+				break;
+			}
+			spin_lock_irqsave(&audio->dsp_lock, flags);
+			if (index != audio->in_tail) {
+				/* overrun -- data is invalid and we need to
+				 * retry
+				 */
+				spin_unlock_irqrestore(&audio->dsp_lock, flags);
+				continue;
+			}
+			audio->in[index].size = 0;
+			audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
+			audio->in_count--;
+			spin_unlock_irqrestore(&audio->dsp_lock, flags);
+			count -= size;
+			buf += size;
+		} else {
+			MM_ERR("short read\n");
+			break;
+		}
+	}
+	mutex_unlock(&audio->read_lock);
+
+	if (buf > start)
+		return buf - start;
+
+	return rc;
+}
+
+static ssize_t audpcm_in_write(struct file *file,
+				const char __user *buf,
+				size_t count, loff_t *pos)
+{
+	return -EINVAL;
+}
+
+static int audpcm_in_release(struct inode *inode, struct file *file)
+{
+	struct audio_in *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	audpcm_in_disable(audio);
+	audpcm_in_flush(audio);
+	audpreproc_aenc_free(audio->enc_id);
+	msm_adsp_put(audio->audrec);
+	msm_adsp_put(audio->audpre);
+	audio->audrec = NULL;
+	audio->audpre = NULL;
+	audio->opened = 0;
+	if (audio->data) {
+		free_contiguous_memory((void *)audio->data);
+		audio->data = NULL;
+	}
+	mutex_unlock(&audio->lock);
+	return 0;
+}
+
+static struct audio_in the_audio_in;
+
+static int audpcm_in_open(struct inode *inode, struct file *file)
+{
+	struct audio_in *audio = &the_audio_in;
+	int rc;
+
+	int encid;
+	mutex_lock(&audio->lock);
+	if (audio->opened) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	/* Settings will be re-config at AUDIO_SET_CONFIG,
+	 * but at least we need to have initial config
+	 */
+	audio->mode = MSM_AUD_ENC_MODE_TUNNEL;
+	audio->samp_rate = RPC_AUD_DEF_SAMPLE_RATE_11025;
+	audio->samp_rate_index = AUDREC_CMD_SAMP_RATE_INDX_11025;
+	audio->channel_mode = AUDREC_CMD_STEREO_MODE_MONO;
+	audio->buffer_size = MONO_DATA_SIZE;
+	audio->enc_type = AUDREC_CMD_TYPE_0_INDEX_WAV | audio->mode;
+
+	rc = audmgr_open(&audio->audmgr);
+	if (rc)
+		goto done;
+	encid = audpreproc_aenc_alloc(audio->enc_type, &audio->module_name,
+			&audio->queue_ids);
+	if (encid < 0) {
+		MM_ERR("No free encoder available\n");
+		rc = -ENODEV;
+		goto done;
+	}
+	audio->enc_id = encid;
+
+	rc = msm_adsp_get(audio->module_name, &audio->audrec,
+			   &audrec_adsp_ops, audio);
+	if (rc) {
+		audpreproc_aenc_free(audio->enc_id);
+		goto done;
+	}
+
+	rc = msm_adsp_get("AUDPREPROCTASK", &audio->audpre,
+				&audpre_adsp_ops, audio);
+	if (rc) {
+		msm_adsp_put(audio->audrec);
+		audpreproc_aenc_free(audio->enc_id);
+		goto done;
+	}
+
+	audio->dsp_cnt = 0;
+	audio->stopped = 0;
+
+	audpcm_in_flush(audio);
+
+	audio->data = allocate_contiguous_memory(DMASZ, MEMTYPE_EBI1,
+				SZ_4K, 0);
+	if (!audio->data) {
+		MM_ERR("could not allocate read buffers\n");
+		rc = -ENOMEM;
+		goto evt_error;
+	} else {
+		audio->phys = memory_pool_node_paddr(audio->data);
+		if (!audio->phys) {
+			MM_ERR("could not get physical address\n");
+			rc = -ENOMEM;
+			free_contiguous_memory(audio->data);
+			goto evt_error;
+		}
+		MM_DBG("read buf: phy addr 0x%08x kernel addr 0x%08x\n",
+				audio->phys, (int)audio->data);
+	}
+
+	file->private_data = audio;
+	audio->opened = 1;
+	rc = 0;
+done:
+	mutex_unlock(&audio->lock);
+	return rc;
+evt_error:
+	msm_adsp_put(audio->audrec);
+	msm_adsp_put(audio->audpre);
+	audpreproc_aenc_free(audio->enc_id);
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static long audpre_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct audio_in *audio = file->private_data;
+	int rc = 0, enable;
+	uint16_t enable_mask;
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_ENABLE_AUDPRE:
+		if (copy_from_user(&enable_mask, (void *) arg,
+						sizeof(enable_mask))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		enable = (enable_mask & AGC_ENABLE) ? 1 : 0;
+		audio_enable_tx_agc(audio, enable);
+		enable = (enable_mask & NS_ENABLE) ? 1 : 0;
+		audio_enable_ns(audio, enable);
+		enable = (enable_mask & TX_IIR_ENABLE) ? 1 : 0;
+		audio_enable_iir(audio, enable);
+		break;
+
+	case AUDIO_SET_AGC:
+		if (copy_from_user(&audio->tx_agc_cfg, (void *) arg,
+						sizeof(audio->tx_agc_cfg)))
+			rc = -EFAULT;
+		break;
+
+	case AUDIO_SET_NS:
+		if (copy_from_user(&audio->ns_cfg, (void *) arg,
+						sizeof(audio->ns_cfg)))
+			rc = -EFAULT;
+		break;
+
+	case AUDIO_SET_TX_IIR:
+		if (copy_from_user(&audio->iir_cfg, (void *) arg,
+						sizeof(audio->iir_cfg)))
+			rc = -EFAULT;
+		break;
+
+	default:
+		rc = -EINVAL;
+	}
+
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static int audpre_open(struct inode *inode, struct file *file)
+{
+	struct audio_in *audio = &the_audio_in;
+
+	file->private_data = audio;
+
+	return 0;
+}
+
+static const struct file_operations audio_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audpcm_in_open,
+	.release	= audpcm_in_release,
+	.read		= audpcm_in_read,
+	.write		= audpcm_in_write,
+	.unlocked_ioctl	= audpcm_in_ioctl,
+};
+
+static struct miscdevice audpcm_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_pcm_in",
+	.fops	= &audio_fops,
+};
+
+static const struct file_operations audpre_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audpre_open,
+	.unlocked_ioctl	= audpre_ioctl,
+};
+
+static struct miscdevice audpre_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_preproc_ctl",
+	.fops	= &audpre_fops,
+};
+
+static int __init audpcm_in_init(void)
+{
+
+	mutex_init(&the_audio_in.lock);
+	mutex_init(&the_audio_in.read_lock);
+	spin_lock_init(&the_audio_in.dsp_lock);
+	init_waitqueue_head(&the_audio_in.wait);
+	return misc_register(&audpcm_in_misc) || misc_register(&audpre_misc);
+}
+device_initcall(audpcm_in_init);
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp.c b/arch/arm/mach-msm/qdsp5/audio_qcelp.c
new file mode 100644
index 0000000..f436759
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp.c
@@ -0,0 +1,1620 @@
+/* arch/arm/mach-msm/qdsp5/audio_qcelp.c
+ *
+ * qcelp 13k audio decoder device
+ *
+ * Copyright (c) 2008-2009, 2011-2012 Code Aurora Forum. All rights reserved.
+ *
+ * This code is based in part on audio_mp3.c, which is
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ *
+ * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ *
+ */
+
+#include <asm/ioctls.h>
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/earlysuspend.h>
+#include <linux/list.h>
+#include <linux/android_pmem.h>
+#include <linux/slab.h>
+#include <linux/msm_audio.h>
+#include <linux/memory_alloc.h>
+
+#include <mach/msm_adsp.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audplaycmdi.h>
+#include <mach/qdsp5/qdsp5audplaymsg.h>
+#include <mach/qdsp5/qdsp5rmtcmdi.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_memtypes.h>
+
+#include "audmgr.h"
+
+#define BUFSZ 1094 /* QCELP 13K Hold 600ms packet data = 36 * 30 and
+		      14 bytes of meta in */
+#define BUF_COUNT 2
+#define DMASZ (BUFSZ * BUF_COUNT)
+
+#define PCM_BUFSZ_MIN 1624 /* 100ms worth of data and
+			      24 bytes of meta out  */
+#define PCM_BUF_MAX_COUNT 5
+
+#define AUDDEC_DEC_QCELP 9
+
+#define	ROUTING_MODE_FTRT	1
+#define	ROUTING_MODE_RT		2
+/* Decoder status received from AUDPPTASK */
+#define	AUDPP_DEC_STATUS_SLEEP	0
+#define	AUDPP_DEC_STATUS_INIT	1
+#define	AUDPP_DEC_STATUS_CFG	2
+#define	AUDPP_DEC_STATUS_PLAY	3
+
+#define AUDQCELP_METAFIELD_MASK 0xFFFF0000
+#define AUDQCELP_EOS_FLG_OFFSET 0x0A /* Offset from beginning of buffer */
+#define AUDQCELP_EOS_FLG_MASK 0x01
+#define AUDQCELP_EOS_NONE 0x0 /* No EOS detected */
+#define AUDQCELP_EOS_SET 0x1 /* EOS set in meta field */
+
+#define AUDQCELP_EVENT_NUM 10 /* Default number of pre-allocated event pkts */
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+	unsigned short mfield_sz; /*only useful for data has meta field */
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct audqcelp_suspend_ctl {
+	struct early_suspend node;
+	struct audio *audio;
+};
+#endif
+
+struct audqcelp_event{
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+
+struct audio {
+	struct buffer out[BUF_COUNT];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed;	/* number of buffers the dsp is waiting for */
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	/* Host PCM section - START */
+	struct buffer in[PCM_BUF_MAX_COUNT];
+	struct mutex read_lock;
+	wait_queue_head_t read_wait;    /* Wait queue for read */
+	char *read_data;        /* pointer to reader buffer */
+	int32_t read_phys;   /* physical address of reader buffer */
+	uint8_t read_next;      /* index to input buffers to be read next */
+	uint8_t fill_next;      /* index to buffer that DSP should be filling */
+	uint8_t pcm_buf_count;  /* number of pcm buffer allocated */
+	/* Host PCM section - END */
+
+	struct msm_adsp_module *audplay;
+
+	struct audmgr audmgr;
+
+	/* data allocated for various buffers */
+	char *data;
+	int32_t phys; /* physical address of write buffer */
+	void *map_v_read;
+	void *map_v_write;
+	int mfield; /* meta field embedded in data */
+	int rflush; /* Read  flush */
+	int wflush; /* Write flush */
+	uint8_t opened:1;
+	uint8_t enabled:1;
+	uint8_t running:1;
+	uint8_t stopped:1;	/* set when stopped, cleared on flush */
+	uint8_t pcm_feedback:1; /* set when non-tunnel mode */
+	uint8_t buf_refresh:1;
+	int teos; /* valid only if tunnel mode & no data left for decoder */
+	enum msm_aud_decoder_state dec_state;	/* Represents decoder state */
+	int rmt_resource_released;
+
+	const char *module_name;
+	unsigned queue_id;
+	uint16_t dec_id;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct audqcelp_suspend_ctl suspend_ctl;
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+
+	wait_queue_head_t wait;
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	wait_queue_head_t event_wait;
+	spinlock_t event_queue_lock;
+	struct mutex get_event_lock;
+	int event_abort;
+
+	int eq_enable;
+	int eq_needs_commit;
+	audpp_cmd_cfg_object_params_eqalizer eq;
+	audpp_cmd_cfg_object_params_volume vol_pan;
+};
+
+static int auddec_dsp_config(struct audio *audio, int enable);
+static void audpp_cmd_cfg_adec_params(struct audio *audio);
+static void audpp_cmd_cfg_routing_mode(struct audio *audio);
+static void audqcelp_send_data(struct audio *audio, unsigned needed);
+static void audqcelp_config_hostpcm(struct audio *audio);
+static void audqcelp_buffer_refresh(struct audio *audio);
+static void audqcelp_dsp_event(void *private, unsigned id, uint16_t *msg);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audqcelp_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload);
+#endif
+
+static int rmt_put_resource(struct audio *audio)
+{
+	struct aud_codec_config_cmd cmd;
+	unsigned short client_idx;
+
+	cmd.cmd_id = RM_CMD_AUD_CODEC_CFG;
+	cmd.client_id = RM_AUD_CLIENT_ID;
+	cmd.task_id = audio->dec_id;
+	cmd.enable = RMT_DISABLE;
+	cmd.dec_type = AUDDEC_DEC_QCELP;
+	client_idx = ((cmd.client_id << 8) | cmd.task_id);
+
+	return put_adsp_resource(client_idx, &cmd, sizeof(cmd));
+}
+
+static int rmt_get_resource(struct audio *audio)
+{
+	struct aud_codec_config_cmd cmd;
+	unsigned short client_idx;
+
+	cmd.cmd_id = RM_CMD_AUD_CODEC_CFG;
+	cmd.client_id = RM_AUD_CLIENT_ID;
+	cmd.task_id = audio->dec_id;
+	cmd.enable = RMT_ENABLE;
+	cmd.dec_type = AUDDEC_DEC_QCELP;
+	client_idx = ((cmd.client_id << 8) | cmd.task_id);
+
+	return get_adsp_resource(client_idx, &cmd, sizeof(cmd));
+}
+
+/* must be called with audio->lock held */
+static int audqcelp_enable(struct audio *audio)
+{
+	struct audmgr_config cfg;
+	int rc;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled)
+		return 0;
+
+	if (audio->rmt_resource_released == 1) {
+		audio->rmt_resource_released = 0;
+		rc = rmt_get_resource(audio);
+		if (rc) {
+			MM_ERR("ADSP resources are not available for QCELP \
+				session 0x%08x on decoder: %d\n Ignoring \
+				error and going ahead with the playback\n",
+				(int)audio, audio->dec_id);
+		}
+	}
+
+	audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
+		cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+		cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;
+		cfg.def_method = RPC_AUD_DEF_METHOD_PLAYBACK;
+		cfg.codec = RPC_AUD_DEF_CODEC_13K;
+		cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+		rc = audmgr_enable(&audio->audmgr, &cfg);
+		if (rc < 0)
+			return rc;
+	}
+
+	if (msm_adsp_enable(audio->audplay)) {
+		MM_ERR("msm_adsp_enable(audplay) failed\n");
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+
+	if (audpp_enable(audio->dec_id, audqcelp_dsp_event, audio)) {
+		MM_ERR("audpp_enable() failed\n");
+		msm_adsp_disable(audio->audplay);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+	audio->enabled = 1;
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audqcelp_disable(struct audio *audio)
+{
+	int rc = 0;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+		auddec_dsp_config(audio, 0);
+		rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+		else if (audio->dec_state != MSM_AUD_DECODER_STATE_CLOSE)
+			rc = -EFAULT;
+		else
+			rc = 0;
+		audio->stopped = 1;
+		wake_up(&audio->write_wait);
+		wake_up(&audio->read_wait);
+		msm_adsp_disable(audio->audplay);
+		audpp_disable(audio->dec_id, audio);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_disable(&audio->audmgr);
+		audio->out_needed = 0;
+		rmt_put_resource(audio);
+		audio->rmt_resource_released = 1;
+	}
+	return rc;
+}
+
+/* ------------------- dsp --------------------- */
+static void audqcelp_update_pcm_buf_entry(struct audio *audio,
+	uint32_t *payload)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	if (audio->rflush)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < payload[1]; index++) {
+		if (audio->in[audio->fill_next].addr ==
+			payload[2 + index * 2]) {
+			MM_DBG("in[%d] ready\n", audio->fill_next);
+			audio->in[audio->fill_next].used =
+			payload[3 + index * 2];
+			if ((++audio->fill_next) == audio->pcm_buf_count)
+				audio->fill_next = 0;
+		} else {
+			MM_ERR("expected=%x ret=%x\n",
+				audio->in[audio->fill_next].addr,
+				payload[1 + index * 2]);
+			break;
+		}
+	}
+	if (audio->in[audio->fill_next].used == 0) {
+		audqcelp_buffer_refresh(audio);
+	} else {
+		MM_DBG("read cannot keep up\n");
+		audio->buf_refresh = 1;
+	}
+	wake_up(&audio->read_wait);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static void audplay_dsp_event(void *data, unsigned id, size_t len,
+			      void (*getevent) (void *ptr, size_t len))
+{
+	struct audio *audio = data;
+	uint32_t msg[28];
+	getevent(msg, sizeof(msg));
+
+	MM_DBG("msg_id=%x\n", id);
+
+	switch (id) {
+	case AUDPLAY_MSG_DEC_NEEDS_DATA:
+		audqcelp_send_data(audio, 1);
+		break;
+
+	case AUDPLAY_MSG_BUFFER_UPDATE:
+		audqcelp_update_pcm_buf_entry(audio, msg);
+		break;
+
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audplaytask)\n");
+		break;
+
+	default:
+		MM_ERR("unexpected message from decoder \n");
+	}
+}
+
+static void audqcelp_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned status = msg[1];
+
+			switch (status) {
+			case AUDPP_DEC_STATUS_SLEEP: {
+				uint16_t reason = msg[2];
+				MM_DBG("decoder status:sleep reason = \
+						0x%04x\n", reason);
+				if ((reason == AUDPP_MSG_REASON_MEM)
+					|| (reason ==
+					AUDPP_MSG_REASON_NODECODER)) {
+					audio->dec_state =
+					MSM_AUD_DECODER_STATE_FAILURE;
+					wake_up(&audio->wait);
+				} else if (reason == AUDPP_MSG_REASON_NONE) {
+					/* decoder is in disable state */
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_CLOSE;
+					wake_up(&audio->wait);
+				}
+				break;
+			}
+			case AUDPP_DEC_STATUS_INIT:
+				MM_DBG("decoder status: init \n");
+				if (audio->pcm_feedback)
+					audpp_cmd_cfg_routing_mode(audio);
+				else
+					audpp_cmd_cfg_adec_params(audio);
+				break;
+
+			case AUDPP_DEC_STATUS_CFG:
+				MM_DBG("decoder status: cfg \n");
+				break;
+			case AUDPP_DEC_STATUS_PLAY:
+				MM_DBG("decoder status: play \n");
+				if (audio->pcm_feedback) {
+					audqcelp_config_hostpcm(audio);
+					audqcelp_buffer_refresh(audio);
+				}
+				audio->dec_state =
+					MSM_AUD_DECODER_STATE_SUCCESS;
+				wake_up(&audio->wait);
+				break;
+			default:
+				MM_ERR("unknown decoder status\n");
+			}
+			break;
+		}
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			MM_DBG("CFG_MSG ENABLE\n");
+			auddec_dsp_config(audio, 1);
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+			audpp_dsp_set_eq(audio->dec_id,	audio->eq_enable,
+								&audio->eq);
+			audpp_avsync(audio->dec_id, 22050);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			MM_DBG("CFG_MSG DISABLE\n");
+			audpp_avsync(audio->dec_id, 0);
+			audio->running = 0;
+		} else {
+			MM_DBG("CFG_MSG %d?\n", msg[0]);
+		}
+		break;
+	case AUDPP_MSG_ROUTING_ACK:
+		MM_DBG("ROUTING_ACK mode=%d\n", msg[1]);
+		audpp_cmd_cfg_adec_params(audio);
+		break;
+	case AUDPP_MSG_FLUSH_ACK:
+		MM_DBG("FLUSH_ACK\n");
+		audio->wflush = 0;
+		audio->rflush = 0;
+		wake_up(&audio->write_wait);
+		if (audio->pcm_feedback)
+			audqcelp_buffer_refresh(audio);
+		break;
+	case AUDPP_MSG_PCMDMAMISSED:
+		MM_DBG("PCMDMAMISSED\n");
+		audio->teos = 1;
+		wake_up(&audio->write_wait);
+		break;
+	default:
+		MM_ERR("UNKNOWN (%d)\n", id);
+	}
+
+}
+
+struct msm_adsp_ops audplay_adsp_ops_qcelp = {
+	.event = audplay_dsp_event,
+};
+
+#define audplay_send_queue0(audio, cmd, len) \
+	msm_adsp_write(audio->audplay, audio->queue_id, \
+		cmd, len)
+
+static int auddec_dsp_config(struct audio *audio, int enable)
+{
+	u16 cfg_dec_cmd[AUDPP_CMD_CFG_DEC_TYPE_LEN / sizeof(unsigned short)];
+
+	memset(cfg_dec_cmd, 0, sizeof(cfg_dec_cmd));
+
+	cfg_dec_cmd[0] = AUDPP_CMD_CFG_DEC_TYPE;
+	if (enable)
+		cfg_dec_cmd[1 + audio->dec_id] = AUDPP_CMD_UPDATDE_CFG_DEC |
+			AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_QCELP;
+	else
+		cfg_dec_cmd[1 + audio->dec_id] = AUDPP_CMD_UPDATDE_CFG_DEC |
+			AUDPP_CMD_DIS_DEC_V;
+
+	return audpp_send_queue1(&cfg_dec_cmd, sizeof(cfg_dec_cmd));
+}
+
+static void audpp_cmd_cfg_adec_params(struct audio *audio)
+{
+	struct audpp_cmd_cfg_adec_params_v13k cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_V13K_LEN;
+	cmd.common.dec_id = audio->dec_id;
+	cmd.common.input_sampling_frequency = 8000;
+	cmd.stereo_cfg = AUDPP_CMD_PCM_INTF_MONO_V;
+
+	audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static void audpp_cmd_cfg_routing_mode(struct audio *audio)
+{
+	struct audpp_cmd_routing_mode cmd;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_ROUTING_MODE;
+	cmd.object_number = audio->dec_id;
+	if (audio->pcm_feedback)
+		cmd.routing_mode = ROUTING_MODE_FTRT;
+	else
+		cmd.routing_mode = ROUTING_MODE_RT;
+	audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static int audplay_dsp_send_data_avail(struct audio *audio,
+				       unsigned idx, unsigned len)
+{
+	struct audplay_cmd_bitstream_data_avail_nt2 cmd;
+
+	cmd.cmd_id = AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_NT2;
+	if (audio->mfield)
+		cmd.decoder_id = AUDQCELP_METAFIELD_MASK |
+			(audio->out[idx].mfield_sz >> 1);
+	else
+		cmd.decoder_id = audio->dec_id;
+	cmd.buf_ptr = audio->out[idx].addr;
+	cmd.buf_size = len / 2;
+	cmd.partition_number = 0;
+	/* complete writes to the input buffer */
+	wmb();
+	return audplay_send_queue0(audio, &cmd, sizeof(cmd));
+}
+
+static void audqcelp_buffer_refresh(struct audio *audio)
+{
+	struct audplay_cmd_buffer_refresh refresh_cmd;
+
+	refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH;
+	refresh_cmd.num_buffers = 1;
+	refresh_cmd.buf0_address = audio->in[audio->fill_next].addr;
+	refresh_cmd.buf0_length = audio->in[audio->fill_next].size;
+	refresh_cmd.buf_read_count = 0;
+	MM_DBG("buf0_addr=%x buf0_len=%d\n", refresh_cmd.buf0_address,
+			refresh_cmd.buf0_length);
+
+	(void)audplay_send_queue0(audio, &refresh_cmd, sizeof(refresh_cmd));
+}
+
+static void audqcelp_config_hostpcm(struct audio *audio)
+{
+	struct audplay_cmd_hpcm_buf_cfg cfg_cmd;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	cfg_cmd.cmd_id = AUDPLAY_CMD_HPCM_BUF_CFG;
+	cfg_cmd.max_buffers = 1;
+	cfg_cmd.byte_swap = 0;
+	cfg_cmd.hostpcm_config = (0x8000) | (0x4000);
+	cfg_cmd.feedback_frequency = 1;
+	cfg_cmd.partition_number = 0;
+
+	(void)audplay_send_queue0(audio, &cfg_cmd, sizeof(cfg_cmd));
+}
+
+static void audqcelp_send_data(struct audio *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (needed && !audio->wflush) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			MM_DBG("frame %d free\n", audio->out_tail);
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+			MM_DBG("frame %d busy\n", audio->out_tail);
+			audplay_dsp_send_data_avail(audio, audio->out_tail,
+						    frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+ done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+
+static void audqcelp_flush(struct audio *audio)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->out[0].used = 0;
+	audio->out[1].used = 0;
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static void audqcelp_flush_pcm_buf(struct audio *audio)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
+		audio->in[index].used = 0;
+
+	audio->buf_refresh = 0;
+	audio->read_next = 0;
+	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static void audqcelp_ioport_reset(struct audio *audio)
+{
+	/* Make sure read/write thread are free from
+	 * sleep and knowing that system is not able
+	 * to process io request at the moment
+	 */
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audqcelp_flush(audio);
+	mutex_unlock(&audio->write_lock);
+	wake_up(&audio->read_wait);
+	mutex_lock(&audio->read_lock);
+	audqcelp_flush_pcm_buf(audio);
+	mutex_unlock(&audio->read_lock);
+}
+
+static int audqcelp_events_pending(struct audio *audio)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	return empty || audio->event_abort;
+}
+
+static void audqcelp_reset_event_queue(struct audio *audio)
+{
+	unsigned long flags;
+	struct audqcelp_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audqcelp_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+				struct audqcelp_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	return;
+}
+
+
+static long audqcelp_process_event_req(struct audio *audio, void __user *arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audqcelp_event *drv_evt = NULL;
+	int timeout;
+	unsigned long flags;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int) usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(
+			audio->event_wait, audqcelp_events_pending(audio),
+			msecs_to_jiffies(timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(
+			audio->event_wait, audqcelp_events_pending(audio));
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	rc = 0;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audqcelp_event, list);
+		list_del(&drv_evt->list);
+	}
+
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else
+		rc = -1;
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	if (!rc && copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audio_enable_eq(struct audio *audio, int enable)
+{
+	if (audio->eq_enable == enable && !audio->eq_needs_commit)
+		return 0;
+
+	audio->eq_enable = enable;
+
+	if (audio->running) {
+		audpp_dsp_set_eq(audio->dec_id, enable, &audio->eq);
+		audio->eq_needs_commit = 0;
+	}
+	return 0;
+}
+
+static long audqcelp_ioctl(struct file *file, unsigned int cmd,
+		unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = -EINVAL;
+	unsigned long flags = 0;
+	uint16_t enable_mask;
+	int enable;
+	int prev_state;
+
+	MM_DBG("cmd = %d\n", cmd);
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = audpp_avsync_byte_count(audio->dec_id);
+		stats.sample_count = audpp_avsync_sample_count(audio->dec_id);
+		if (copy_to_user((void *)arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	switch (cmd) {
+	case AUDIO_ENABLE_AUDPP:
+		if (copy_from_user(&enable_mask, (void *) arg,
+						sizeof(enable_mask))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		enable = (enable_mask & EQ_ENABLE) ? 1 : 0;
+		audio_enable_eq(audio, enable);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+	case AUDIO_SET_VOLUME:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.volume = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_PAN:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.pan = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_EQ:
+		prev_state = audio->eq_enable;
+		audio->eq_enable = 0;
+		if (copy_from_user(&audio->eq.num_bands, (void *) arg,
+				sizeof(audio->eq) -
+				(AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2))) {
+			rc = -EFAULT;
+			break;
+		}
+		audio->eq_enable = prev_state;
+		audio->eq_needs_commit = 1;
+		rc = 0;
+		break;
+	}
+
+	if (-EINVAL != rc)
+		return rc;
+
+	if (cmd == AUDIO_GET_EVENT) {
+		MM_DBG("AUDIO_GET_EVENT\n");
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audqcelp_process_event_req(audio,
+					(void __user *) arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		return rc;
+	}
+
+	if (cmd == AUDIO_ABORT_GET_EVENT) {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		MM_DBG("AUDIO_START\n");
+		rc = audqcelp_enable(audio);
+		if (!rc) {
+			rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+			MM_INFO("dec_state %d rc = %d\n", audio->dec_state, rc);
+
+			if (audio->dec_state != MSM_AUD_DECODER_STATE_SUCCESS)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		break;
+	case AUDIO_STOP:
+		MM_DBG("AUDIO_STOP\n");
+		rc = audqcelp_disable(audio);
+		audqcelp_ioport_reset(audio);
+		audio->stopped = 0;
+		break;
+	case AUDIO_FLUSH:
+		MM_DBG("AUDIO_FLUSH\n");
+		audio->rflush = 1;
+		audio->wflush = 1;
+		audqcelp_ioport_reset(audio);
+		if (audio->running) {
+			audpp_flush(audio->dec_id);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		break;
+	case AUDIO_SET_CONFIG:{
+			struct msm_audio_config config;
+			if (copy_from_user(&config, (void *)arg,
+				sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+			audio->mfield = config.meta_field;
+			MM_DBG("AUDIO_SET_CONFIG applicable \
+				for metafield configuration\n");
+			rc = 0;
+			break;
+		}
+	case AUDIO_GET_CONFIG:{
+			struct msm_audio_config config;
+			config.buffer_size = BUFSZ;
+			config.buffer_count = BUF_COUNT;
+			config.sample_rate = 8000;
+			config.channel_count = 1;
+			config.meta_field = 0;
+			config.unused[0] = 0;
+			config.unused[1] = 0;
+			config.unused[2] = 0;
+			if (copy_to_user((void *)arg, &config,
+					 sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+
+			break;
+		}
+	case AUDIO_GET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+
+			config.pcm_feedback = audio->pcm_feedback;
+			config.buffer_count = PCM_BUF_MAX_COUNT;
+			config.buffer_size = PCM_BUFSZ_MIN;
+			if (copy_to_user((void *)arg, &config,
+				sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_SET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+
+			if (copy_from_user(&config, (void *)arg,
+				sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+			if (config.pcm_feedback != audio->pcm_feedback) {
+				MM_ERR("Not sufficient permission to"
+					 "change the playback mode\n");
+				rc = -EACCES;
+				break;
+			}
+			if ((config.buffer_count > PCM_BUF_MAX_COUNT) ||
+				(config.buffer_count == 1))
+				config.buffer_count = PCM_BUF_MAX_COUNT;
+
+			if (config.buffer_size < PCM_BUFSZ_MIN)
+				config.buffer_size = PCM_BUFSZ_MIN;
+
+			/* Check if pcm feedback is required */
+			if ((config.pcm_feedback) && (!audio->read_data)) {
+				MM_DBG("allocate PCM buf %d\n",
+				config.buffer_count * config.buffer_size);
+				audio->read_phys =
+						allocate_contiguous_ebi_nomap(
+							config.buffer_size *
+							config.buffer_count,
+							SZ_4K);
+				if (!audio->read_phys) {
+					rc = -ENOMEM;
+					break;
+				}
+				audio->map_v_read = ioremap(
+							audio->read_phys,
+							config.buffer_size *
+							config.buffer_count);
+				if (IS_ERR(audio->map_v_read)) {
+					MM_ERR("failed to map read buf\n");
+					rc = -ENOMEM;
+					free_contiguous_memory_by_paddr(
+							audio->read_phys);
+				} else {
+					uint8_t index;
+					uint32_t offset = 0;
+					audio->read_data =
+						audio->map_v_read;
+					audio->buf_refresh = 0;
+					audio->pcm_buf_count =
+						config.buffer_count;
+					audio->read_next = 0;
+					audio->fill_next = 0;
+
+					for (index = 0;
+					index < config.buffer_count; index++) {
+						audio->in[index].data =
+						audio->read_data + offset;
+						audio->in[index].addr =
+						audio->read_phys + offset;
+						audio->in[index].size =
+						config.buffer_size;
+						audio->in[index].used = 0;
+						offset += config.buffer_size;
+					}
+					MM_DBG("read buf: phy addr 0x%08x \
+						kernel addr 0x%08x\n",
+						audio->read_phys,
+						(int)audio->read_data);
+					rc = 0;
+				}
+			} else {
+				rc = 0;
+			}
+			break;
+		}
+	case AUDIO_PAUSE:
+		MM_DBG("AUDIO_PAUSE %ld\n", arg);
+		rc = audpp_pause(audio->dec_id, (int) arg);
+		break;
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+/* Only useful in tunnel-mode */
+static int audqcelp_fsync(struct file *file, loff_t a, loff_t b, int datasync)
+{
+	struct audio *audio = file->private_data;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (!audio->running || audio->pcm_feedback) {
+		rc = -EINVAL;
+		goto done_nolock;
+	}
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(!audio->out[0].used &&
+		!audio->out[1].used &&
+		audio->out_needed) || audio->wflush);
+
+	if (rc < 0)
+		goto done;
+	else if (audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	/* pcm dmamiss message is sent continously
+	 * when decoder is starved so no race
+	 * condition concern
+	 */
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		audio->teos || audio->wflush);
+
+	if (audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+done_nolock:
+	return rc;
+}
+
+static ssize_t audqcelp_read(struct file *file, char __user *buf, size_t count,
+			loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	int rc = 0;
+
+	if (!audio->pcm_feedback)
+		return 0; /* PCM feedback is not enabled. Nothing to read */
+
+	mutex_lock(&audio->read_lock);
+	MM_DBG("%d\n", count);
+	while (count > 0) {
+		rc = wait_event_interruptible(audio->read_wait,
+				(audio->in[audio->read_next].used > 0) ||
+				(audio->stopped) || (audio->rflush));
+		if (rc < 0)
+			break;
+
+		if (audio->stopped || audio->rflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (count < audio->in[audio->read_next].used) {
+			/* Read must happen in frame boundary. Since driver does
+			not know frame size, read count must be greater or equal
+			to size of PCM samples */
+			MM_DBG("read stop - partial frame\n");
+			break;
+		} else {
+			MM_DBG("read from in[%d]\n", audio->read_next);
+			/* order reads from the output buffer */
+			rmb();
+			if (copy_to_user(buf,
+				audio->in[audio->read_next].data,
+				audio->in[audio->read_next].used)) {
+				MM_ERR("invalid addr %x\n", (unsigned int)buf);
+				rc = -EFAULT;
+				break;
+			}
+			count -= audio->in[audio->read_next].used;
+			buf += audio->in[audio->read_next].used;
+			audio->in[audio->read_next].used = 0;
+			if ((++audio->read_next) == audio->pcm_buf_count)
+				audio->read_next = 0;
+			break;
+				/* Force to exit while loop
+				 * to prevent output thread
+				 * sleep too long if data is
+				 * not ready at this moment.
+				 */
+		}
+	}
+
+	/* don't feed output buffer to HW decoder during flushing
+	 * buffer refresh command will be sent once flush completes
+	 * send buf refresh command here can confuse HW decoder
+	 */
+	if (audio->buf_refresh && !audio->rflush) {
+		audio->buf_refresh = 0;
+		MM_DBG("kick start pcm feedback again\n");
+		audqcelp_buffer_refresh(audio);
+	}
+
+	mutex_unlock(&audio->read_lock);
+
+	if (buf > start)
+		rc = buf - start;
+
+	MM_DBG("read %d bytes\n", rc);
+	return rc;
+}
+
+static int audqcelp_process_eos(struct audio *audio,
+		const char __user *buf_start, unsigned short mfield_size)
+{
+	struct buffer *frame;
+	int rc = 0;
+
+	frame = audio->out + audio->out_head;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->out_needed &&
+		audio->out[0].used == 0 &&
+		audio->out[1].used == 0)
+		|| (audio->stopped)
+		|| (audio->wflush));
+
+	if (rc < 0)
+		goto done;
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (copy_from_user(frame->data, buf_start, mfield_size)) {
+		rc = -EFAULT;
+		goto done;
+	}
+
+	frame->mfield_sz = mfield_size;
+	audio->out_head ^= 1;
+	frame->used = mfield_size;
+	audqcelp_send_data(audio, 0);
+
+done:
+	return rc;
+}
+
+static ssize_t audqcelp_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	char *cpy_ptr;
+	int rc = 0, eos_condition = AUDQCELP_EOS_NONE;
+	unsigned short mfield_size = 0;
+
+	MM_DBG("cnt=%d\n", count);
+
+	if (count & 1)
+		return -EINVAL;
+
+	mutex_lock(&audio->write_lock);
+	while (count > 0) {
+		frame = audio->out + audio->out_head;
+		cpy_ptr = frame->data;
+		rc = wait_event_interruptible(audio->write_wait,
+					      (frame->used == 0)
+						|| (audio->stopped)
+						|| (audio->wflush));
+		MM_DBG("buffer available\n");
+		if (rc < 0)
+			break;
+		if (audio->stopped || audio->wflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (audio->mfield) {
+			if (buf == start) {
+				/* Processing beginning of user buffer */
+				if (__get_user(mfield_size,
+					(unsigned short __user *) buf)) {
+					rc = -EFAULT;
+					break;
+				} else 	if (mfield_size > count) {
+					rc = -EINVAL;
+					break;
+				}
+				MM_DBG("mf offset_val %x\n", mfield_size);
+				if (copy_from_user(cpy_ptr, buf, mfield_size)) {
+					rc = -EFAULT;
+					break;
+				}
+				/* Check if EOS flag is set and buffer has
+				 * contains just meta field
+				 */
+				if (cpy_ptr[AUDQCELP_EOS_FLG_OFFSET] &
+						AUDQCELP_EOS_FLG_MASK) {
+					MM_DBG("EOS SET\n");
+					eos_condition = AUDQCELP_EOS_SET;
+					if (mfield_size == count) {
+						buf += mfield_size;
+						break;
+					} else
+					cpy_ptr[AUDQCELP_EOS_FLG_OFFSET] &=
+						~AUDQCELP_EOS_FLG_MASK;
+				}
+				cpy_ptr += mfield_size;
+				count -= mfield_size;
+				buf += mfield_size;
+			} else {
+				mfield_size = 0;
+				MM_DBG("continuous buffer\n");
+			}
+			frame->mfield_sz = mfield_size;
+		}
+
+		xfer = (count > (frame->size - mfield_size)) ?
+			(frame->size - mfield_size) : count;
+		if (copy_from_user(cpy_ptr, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+
+		frame->used = xfer + mfield_size;
+		audio->out_head ^= 1;
+		count -= xfer;
+		buf += xfer;
+		audqcelp_send_data(audio, 0);
+	}
+	if (eos_condition == AUDQCELP_EOS_SET)
+		rc = audqcelp_process_eos(audio, start, mfield_size);
+	mutex_unlock(&audio->write_lock);
+	if (!rc) {
+		if (buf > start)
+			return buf - start;
+	}
+	return rc;
+}
+
+static int audqcelp_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	MM_INFO("audio instance 0x%08x freeing\n", (int) audio);
+	mutex_lock(&audio->lock);
+	audqcelp_disable(audio);
+	if (audio->rmt_resource_released == 0)
+		rmt_put_resource(audio);
+	audqcelp_flush(audio);
+	audqcelp_flush_pcm_buf(audio);
+	msm_adsp_put(audio->audplay);
+	audpp_adec_free(audio->dec_id);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&audio->suspend_ctl.node);
+#endif
+	audio->opened = 0;
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audqcelp_reset_event_queue(audio);
+	iounmap(audio->map_v_write);
+	free_contiguous_memory_by_paddr(audio->phys);
+	if (audio->read_data) {
+		iounmap(audio->map_v_read);
+		free_contiguous_memory_by_paddr(audio->read_phys);
+	}
+	mutex_unlock(&audio->lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio);
+	return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audqcelp_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload)
+{
+	struct audqcelp_event *e_node = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+				struct audqcelp_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audqcelp_event), GFP_ATOMIC);
+		if (!e_node) {
+			MM_ERR("No mem to post event %d\n", type);
+			spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	wake_up(&audio->event_wait);
+}
+
+static void audqcelp_suspend(struct early_suspend *h)
+{
+	struct audqcelp_suspend_ctl *ctl =
+		container_of(h, struct audqcelp_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audqcelp_post_event(ctl->audio, AUDIO_EVENT_SUSPEND, payload);
+}
+
+static void audqcelp_resume(struct early_suspend *h)
+{
+	struct audqcelp_suspend_ctl *ctl =
+		container_of(h, struct audqcelp_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audqcelp_post_event(ctl->audio, AUDIO_EVENT_RESUME, payload);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audqcelp_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audqcelp_debug_read(struct file *file, char __user *buf,
+					size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 1024;
+	static char buffer[1024];
+	int n = 0, i;
+	struct audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"enabled %d\n", audio->enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_feedback %d\n", audio->pcm_feedback);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_buf_sz %d\n", audio->out[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_buf_count %d \n", audio->pcm_buf_count);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_buf_sz %d \n", audio->in[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"volume %x \n", audio->vol_pan.volume);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"rflush %d\n", audio->rflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"running %d \n", audio->running);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"dec state %d \n", audio->dec_state);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_needed %d \n", audio->out_needed);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_head %d \n", audio->out_head);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_tail %d \n", audio->out_tail);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out[0].used %d \n", audio->out[0].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out[1].used %d \n", audio->out[1].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"buffer_refresh %d \n", audio->buf_refresh);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"read_next %d \n", audio->read_next);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"fill_next %d \n", audio->fill_next);
+	for (i = 0; i < audio->pcm_buf_count; i++)
+		n += scnprintf(buffer + n, debug_bufmax - n,
+				"in[%d].size %d \n", i, audio->in[i].used);
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audqcelp_debug_fops = {
+	.read = audqcelp_debug_read,
+	.open = audqcelp_debug_open,
+};
+#endif
+
+static int audqcelp_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = NULL;
+	int rc, dec_attrb, decid, i;
+	struct audqcelp_event *e_node = NULL;
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_qcelp_" + 5];
+#endif
+
+	/* Create audio instance, set to zero */
+	audio = kzalloc(sizeof(struct audio), GFP_KERNEL);
+	if (!audio) {
+		MM_ERR("no memory to allocate audio instance\n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	MM_INFO("audio instance 0x%08x created\n", (int)audio);
+
+	/* Allocate the decoder */
+	dec_attrb = AUDDEC_DEC_QCELP;
+	if ((file->f_mode & FMODE_WRITE) &&
+			(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_NONTUNNEL;
+		audio->pcm_feedback = NON_TUNNEL_MODE_PLAYBACK;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_TUNNEL;
+		audio->pcm_feedback = TUNNEL_MODE_PLAYBACK;
+	} else {
+		kfree(audio);
+		rc = -EACCES;
+		goto done;
+	}
+	decid = audpp_adec_alloc(dec_attrb, &audio->module_name,
+			&audio->queue_id);
+	if (decid < 0) {
+		MM_ERR("No free decoder available, freeing instance 0x%08x\n",
+				(int)audio);
+		rc = -ENODEV;
+		kfree(audio);
+		goto done;
+	}
+	audio->dec_id = decid & MSM_AUD_DECODER_MASK;
+
+	audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
+	if (!audio->phys) {
+		MM_ERR("could not allocate write buffers, freeing instance \
+				0x%08x\n", (int)audio);
+		rc = -ENOMEM;
+		audpp_adec_free(audio->dec_id);
+		kfree(audio);
+		goto done;
+	} else {
+		audio->map_v_write = ioremap(audio->phys, DMASZ);
+		if (IS_ERR(audio->map_v_write)) {
+			MM_ERR("could not map write buffers, freeing \
+					instance 0x%08x\n", (int)audio);
+			rc = -ENOMEM;
+			free_contiguous_memory_by_paddr(audio->phys);
+			audpp_adec_free(audio->dec_id);
+			kfree(audio);
+			goto done;
+		}
+		audio->data = audio->map_v_write;
+		MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+				audio->phys, (int)audio->data);
+	}
+
+	if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
+		rc = audmgr_open(&audio->audmgr);
+		if (rc) {
+			MM_ERR("audmgr open failed, freeing instance \
+					0x%08x\n", (int)audio);
+			goto err;
+		}
+	}
+
+	rc = msm_adsp_get(audio->module_name, &audio->audplay,
+		&audplay_adsp_ops_qcelp, audio);
+	if (rc) {
+		MM_ERR("failed to get %s module, freeing instance 0x%08x\n",
+				audio->module_name, (int)audio);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_close(&audio->audmgr);
+		goto err;
+	}
+
+	rc = rmt_get_resource(audio);
+	if (rc) {
+		MM_ERR("ADSP resources are not available for QCELP session \
+			 0x%08x on decoder: %d\n", (int)audio, audio->dec_id);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_close(&audio->audmgr);
+		msm_adsp_put(audio->audplay);
+		goto err;
+	}
+
+	/* Initialize all locks of audio instance */
+	mutex_init(&audio->lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->get_event_lock);
+	spin_lock_init(&audio->dsp_lock);
+	init_waitqueue_head(&audio->write_wait);
+	init_waitqueue_head(&audio->read_wait);
+	INIT_LIST_HEAD(&audio->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+	init_waitqueue_head(&audio->wait);
+	init_waitqueue_head(&audio->event_wait);
+	spin_lock_init(&audio->event_queue_lock);
+
+	/* Initialize buffer */
+	audio->out[0].data = audio->data + 0;
+	audio->out[0].addr = audio->phys + 0;
+	audio->out[0].size = BUFSZ;
+
+	audio->out[1].data = audio->data + BUFSZ;
+	audio->out[1].addr = audio->phys + BUFSZ;
+	audio->out[1].size = BUFSZ;
+
+	audio->vol_pan.volume = 0x2000;
+
+	audqcelp_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_qcelp_%04x", audio->dec_id);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+			NULL, (void *) audio, &audqcelp_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		MM_DBG("debugfs_create_file failed\n");
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	audio->suspend_ctl.node.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+	audio->suspend_ctl.node.resume = audqcelp_resume;
+	audio->suspend_ctl.node.suspend = audqcelp_suspend;
+	audio->suspend_ctl.audio = audio;
+	register_early_suspend(&audio->suspend_ctl.node);
+#endif
+	for (i = 0; i < AUDQCELP_EVENT_NUM; i++) {
+		e_node = kmalloc(sizeof(struct audqcelp_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			MM_ERR("event pkt alloc failed\n");
+			break;
+		}
+	}
+done:
+	return rc;
+err:
+	iounmap(audio->map_v_write);
+	free_contiguous_memory_by_paddr(audio->phys);
+	audpp_adec_free(audio->dec_id);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_qcelp_fops = {
+	.owner = THIS_MODULE,
+	.open = audqcelp_open,
+	.release = audqcelp_release,
+	.read = audqcelp_read,
+	.write = audqcelp_write,
+	.unlocked_ioctl = audqcelp_ioctl,
+	.fsync = audqcelp_fsync,
+};
+
+struct miscdevice audio_qcelp_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_qcelp",
+	.fops = &audio_qcelp_fops,
+};
+
+static int __init audqcelp_init(void)
+{
+	return misc_register(&audio_qcelp_misc);
+}
+
+static void __exit audqcelp_exit(void)
+{
+	misc_deregister(&audio_qcelp_misc);
+}
+
+module_init(audqcelp_init);
+module_exit(audqcelp_exit);
+
+MODULE_DESCRIPTION("MSM QCELP 13K driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
new file mode 100644
index 0000000..92036e5
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
@@ -0,0 +1,1400 @@
+/* arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
+ *
+ * qcelp audio input device
+ *
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This code is based in part on arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c,
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/delay.h>
+
+#include <linux/msm_audio_qcp.h>
+
+
+#include <linux/memory_alloc.h>
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+
+#include <mach/msm_memtypes.h>
+#include <mach/msm_adsp.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include "audmgr.h"
+
+#include <mach/qdsp5/qdsp5audpreproc.h>
+#include <mach/qdsp5/qdsp5audpreproccmdi.h>
+#include <mach/qdsp5/qdsp5audpreprocmsg.h>
+#include <mach/qdsp5/qdsp5audreccmdi.h>
+#include <mach/qdsp5/qdsp5audrecmsg.h>
+#include <mach/debug_mm.h>
+
+#define FRAME_HEADER_SIZE	8 /* 8 bytes frame header */
+#define NT_FRAME_HEADER_SIZE	24 /* 24 bytes frame header */
+/* FRAME_NUM must be a power of two */
+#define FRAME_NUM	8
+#define QCELP_FRAME_SIZE	36 /* 36 bytes data */
+/*Tunnel mode : 36 bytes data + 8 byte header*/
+#define FRAME_SIZE	(QCELP_FRAME_SIZE + FRAME_HEADER_SIZE)
+ /* 36 bytes data  + 24 meta field*/
+#define NT_FRAME_SIZE	(QCELP_FRAME_SIZE + NT_FRAME_HEADER_SIZE)
+#define DMASZ		(FRAME_SIZE * FRAME_NUM)
+#define NT_DMASZ	(NT_FRAME_SIZE * FRAME_NUM)
+#define OUT_FRAME_NUM	2
+#define OUT_BUFFER_SIZE (4 * 1024 + NT_FRAME_HEADER_SIZE)
+#define BUFFER_SIZE	(OUT_BUFFER_SIZE * OUT_FRAME_NUM)
+
+/* Offset from beginning of buffer*/
+#define AUDPREPROC_QCELP_EOS_FLG_OFFSET 0x0A
+#define AUDPREPROC_QCELP_EOS_FLG_MASK 0x01
+#define AUDPREPROC_QCELP_EOS_NONE 0x0 /* No EOS detected */
+#define AUDPREPROC_QCELP_EOS_SET 0x1 /* EOS set in meta field */
+
+struct buffer {
+	void *data;
+	uint32_t size;
+	uint32_t read;
+	uint32_t addr;
+	uint32_t used;
+	uint32_t mfield_sz;
+};
+
+struct audio_qcelp_in {
+	struct buffer in[FRAME_NUM];
+
+	spinlock_t dsp_lock;
+
+	atomic_t in_bytes;
+	atomic_t in_samples;
+
+	struct mutex lock;
+	struct mutex read_lock;
+	wait_queue_head_t wait;
+	wait_queue_head_t wait_enable;
+	/*write section*/
+	struct buffer out[OUT_FRAME_NUM];
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed;	/* number of buffers the dsp is waiting for */
+	uint32_t out_count;
+
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+	int32_t out_phys; /* physical address of write buffer */
+	char *out_data;
+	int mfield; /* meta field embedded in data */
+	int wflush; /*write flush */
+	int rflush; /*read flush*/
+	int out_frame_cnt;
+
+	struct msm_adsp_module *audrec;
+	struct msm_adsp_module *audpre;
+
+
+	/* configuration to use on next enable */
+	uint32_t samp_rate;
+	uint32_t channel_mode;
+	uint32_t buffer_size; /* Frame size (36 bytes) */
+	uint32_t enc_type; /* 11 for QCELP */
+	uint32_t mode; /* T or NT Mode*/
+
+	struct msm_audio_qcelp_enc_config cfg;
+
+	uint32_t dsp_cnt;
+	uint32_t in_head; /* next buffer dsp will write */
+	uint32_t in_tail; /* next buffer read() will read */
+	uint32_t in_count; /* number of buffers available to read() */
+
+	uint32_t eos_ack;
+	uint32_t flush_ack;
+
+	const char *module_name;
+	unsigned queue_ids;
+	uint16_t enc_id; /* Session Id */
+
+	unsigned short samp_rate_index;
+	uint32_t audrec_obj_idx ;
+
+	struct audmgr audmgr;
+
+	/* data allocated for various buffers */
+	char *data;
+	dma_addr_t phys;
+
+	void *map_v_read;
+	void *map_v_write;
+
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+};
+
+struct audio_frame {
+	uint16_t frame_count_lsw;
+	uint16_t frame_count_msw;
+	uint16_t frame_length;
+	uint16_t erased_pcm;
+	unsigned char raw_bitstream[];
+} __packed;
+
+struct audio_frame_nt {
+	uint16_t metadata_len;
+	uint16_t frame_count_lsw;
+	uint16_t frame_count_msw;
+	uint16_t frame_length;
+	uint16_t erased_pcm;
+	uint16_t reserved;
+	uint16_t time_stamp_dword_lsw;
+	uint16_t time_stamp_dword_msw;
+	uint16_t time_stamp_lsw;
+	uint16_t time_stamp_msw;
+	uint16_t nflag_lsw;
+	uint16_t nflag_msw;
+	unsigned char raw_bitstream[]; /* samples */
+} __packed;
+
+struct qcelp_encoded_meta_out {
+	uint16_t metadata_len;
+	uint16_t time_stamp_dword_lsw;
+	uint16_t time_stamp_dword_msw;
+	uint16_t time_stamp_lsw;
+	uint16_t time_stamp_msw;
+	uint16_t nflag_lsw;
+	uint16_t nflag_msw;
+};
+
+/* Audrec Queue command sent macro's */
+#define audio_send_queue_pre(audio, cmd, len) \
+	msm_adsp_write(audio->audpre, QDSP_uPAudPreProcCmdQueue, cmd, len)
+
+#define audio_send_queue_recbs(audio, cmd, len) \
+	msm_adsp_write(audio->audrec, ((audio->queue_ids & 0xFFFF0000) >> 16),\
+			cmd, len)
+#define audio_send_queue_rec(audio, cmd, len) \
+	msm_adsp_write(audio->audrec, (audio->queue_ids & 0x0000FFFF),\
+			cmd, len)
+
+static int audqcelp_in_dsp_enable(struct audio_qcelp_in *audio, int enable);
+static int audqcelp_in_encparam_config(struct audio_qcelp_in *audio);
+static int audqcelp_in_encmem_config(struct audio_qcelp_in *audio);
+static int audqcelp_in_dsp_read_buffer(struct audio_qcelp_in *audio,
+				uint32_t read_cnt);
+static void audqcelp_in_flush(struct audio_qcelp_in *audio);
+
+static void audqcelp_in_get_dsp_frames(struct audio_qcelp_in *audio);
+static int audpcm_config(struct audio_qcelp_in *audio);
+static void audqcelp_out_flush(struct audio_qcelp_in *audio);
+static int audqcelp_in_routing_mode_config(struct audio_qcelp_in *audio);
+static void audrec_pcm_send_data(struct audio_qcelp_in *audio, unsigned needed);
+static void audqcelp_nt_in_get_dsp_frames(struct audio_qcelp_in *audio);
+static void audqcelp_in_flush(struct audio_qcelp_in *audio);
+
+static unsigned convert_samp_index(unsigned index)
+{
+	switch (index) {
+	case RPC_AUD_DEF_SAMPLE_RATE_48000:	return 48000;
+	case RPC_AUD_DEF_SAMPLE_RATE_44100:	return 44100;
+	case RPC_AUD_DEF_SAMPLE_RATE_32000:	return 32000;
+	case RPC_AUD_DEF_SAMPLE_RATE_24000:	return 24000;
+	case RPC_AUD_DEF_SAMPLE_RATE_22050:	return 22050;
+	case RPC_AUD_DEF_SAMPLE_RATE_16000:	return 16000;
+	case RPC_AUD_DEF_SAMPLE_RATE_12000:	return 12000;
+	case RPC_AUD_DEF_SAMPLE_RATE_11025:	return 11025;
+	case RPC_AUD_DEF_SAMPLE_RATE_8000:	return 8000;
+	default:				return 11025;
+	}
+}
+
+/* must be called with audio->lock held */
+static int audqcelp_in_enable(struct audio_qcelp_in *audio)
+{
+	struct audmgr_config cfg;
+	int rc;
+
+	if (audio->enabled)
+		return 0;
+
+	cfg.tx_rate = audio->samp_rate;
+	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+	cfg.def_method = RPC_AUD_DEF_METHOD_RECORD;
+	cfg.codec = RPC_AUD_DEF_CODEC_13K;
+	cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+		rc = audmgr_enable(&audio->audmgr, &cfg);
+		if (rc < 0)
+			return rc;
+
+		if (msm_adsp_enable(audio->audpre)) {
+			audmgr_disable(&audio->audmgr);
+			MM_ERR("msm_adsp_enable(audpre) failed\n");
+			return -ENODEV;
+		}
+	}
+	if (msm_adsp_enable(audio->audrec)) {
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+			audmgr_disable(&audio->audmgr);
+			msm_adsp_disable(audio->audpre);
+		}
+		MM_ERR("msm_adsp_enable(audrec) failed\n");
+		return -ENODEV;
+	}
+
+	audio->enabled = 1;
+	audqcelp_in_dsp_enable(audio, 1);
+
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audqcelp_in_disable(struct audio_qcelp_in *audio)
+{
+	if (audio->enabled) {
+		audio->enabled = 0;
+
+		audqcelp_in_dsp_enable(audio, 0);
+
+		wait_event_interruptible_timeout(audio->wait_enable,
+				audio->running == 0, 1*HZ);
+		audio->stopped = 1;
+		wake_up(&audio->wait);
+		msm_adsp_disable(audio->audrec);
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+			msm_adsp_disable(audio->audpre);
+			audmgr_disable(&audio->audmgr);
+		}
+	}
+	return 0;
+}
+
+/* ------------------- dsp --------------------- */
+static void audpre_dsp_event(void *data, unsigned id, size_t len,
+			    void (*getevent)(void *ptr, size_t len))
+{
+	uint16_t msg[2];
+	getevent(msg, sizeof(msg));
+
+	switch (id) {
+	case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
+		MM_DBG("type %d, status_flag %d\n", msg[0], msg[1]);
+		break;
+	case AUDPREPROC_MSG_ERROR_MSG_ID:
+		MM_ERR("err_index %d\n", msg[0]);
+		break;
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audpreproctask)\n");
+		break;
+	default:
+		MM_ERR("unknown event %d\n", id);
+	}
+}
+
+static void audqcelp_in_get_dsp_frames(struct audio_qcelp_in *audio)
+{
+	struct audio_frame *frame;
+	uint32_t index;
+	unsigned long flags;
+
+	index = audio->in_head;
+
+	frame = (void *) (((char *)audio->in[index].data) -
+			sizeof(*frame));
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->in[index].size = frame->frame_length;
+
+	/* statistics of read */
+	atomic_add(audio->in[index].size, &audio->in_bytes);
+	atomic_add(1, &audio->in_samples);
+
+	audio->in_head = (audio->in_head + 1) & (FRAME_NUM - 1);
+
+	/* If overflow, move the tail index foward. */
+	if (audio->in_head == audio->in_tail) {
+		MM_ERR("Error! not able to keep up the read\n");
+		audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
+		MM_ERR("in_count = %d\n", audio->in_count);
+	} else
+		audio->in_count++;
+
+	audqcelp_in_dsp_read_buffer(audio, audio->dsp_cnt++);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+
+	wake_up(&audio->wait);
+}
+
+static void audqcelp_nt_in_get_dsp_frames(struct audio_qcelp_in *audio)
+{
+	struct audio_frame_nt *nt_frame;
+	uint32_t index;
+	unsigned long flags;
+
+	index = audio->in_head;
+	nt_frame = (void *) (((char *)audio->in[index].data) - \
+				sizeof(struct audio_frame_nt));
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->in[index].size = nt_frame->frame_length;
+	/* statistics of read */
+	atomic_add(audio->in[index].size, &audio->in_bytes);
+	atomic_add(1, &audio->in_samples);
+
+	audio->in_head = (audio->in_head + 1) & (FRAME_NUM - 1);
+
+	/* If overflow, move the tail index foward. */
+	if (audio->in_head == audio->in_tail)
+		MM_DBG("Error! not able to keep up the read\n");
+	else
+		audio->in_count++;
+
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	wake_up(&audio->wait);
+}
+
+static int audrec_pcm_buffer_ptr_refresh(struct audio_qcelp_in *audio,
+				       unsigned idx, unsigned len)
+{
+	struct audrec_cmd_pcm_buffer_ptr_refresh_arm_enc cmd;
+
+	if (len ==  NT_FRAME_HEADER_SIZE)
+		len = len / 2;
+	else
+		len = (len + NT_FRAME_HEADER_SIZE) / 2;
+	MM_DBG("len = %d\n", len);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_PCM_BUFFER_PTR_REFRESH_ARM_TO_ENC;
+	cmd.num_buffers = 1;
+	if (cmd.num_buffers == 1) {
+		cmd.buf_address_length[0] = (audio->out[idx].addr &
+							0xffff0000) >> 16;
+		cmd.buf_address_length[1] = (audio->out[idx].addr &
+							0x0000ffff);
+		cmd.buf_address_length[2] = (len & 0xffff0000) >> 16;
+		cmd.buf_address_length[3] = (len & 0x0000ffff);
+	}
+	audio->out_frame_cnt++;
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static int audpcm_config(struct audio_qcelp_in *audio)
+{
+	struct audrec_cmd_pcm_cfg_arm_to_enc cmd;
+	MM_DBG("\n");
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_PCM_CFG_ARM_TO_ENC;
+	cmd.config_update_flag = AUDREC_PCM_CONFIG_UPDATE_FLAG_ENABLE;
+	cmd.enable_flag = AUDREC_ENABLE_FLAG_VALUE;
+	cmd.sampling_freq = convert_samp_index(audio->samp_rate);
+	if (!audio->channel_mode)
+		cmd.channels = 1;
+	else
+		cmd.channels = 2;
+	cmd.frequency_of_intimation = 1;
+	cmd.max_number_of_buffers = OUT_FRAME_NUM;
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+
+static int audqcelp_in_routing_mode_config(struct audio_qcelp_in *audio)
+{
+	struct audrec_cmd_routing_mode cmd;
+
+	MM_DBG("\n");
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_ROUTING_MODE;
+	if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)
+		cmd.routing_mode = 1;
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static void audrec_dsp_event(void *data, unsigned id, size_t len,
+			    void (*getevent)(void *ptr, size_t len))
+{
+	struct audio_qcelp_in *audio = NULL;
+
+	if (data)
+		audio = data;
+	else {
+		MM_ERR("invalid data for event %x\n", id);
+		return;
+	}
+
+	switch (id) {
+	case AUDREC_MSG_CMD_CFG_DONE_MSG: {
+		struct audrec_msg_cmd_cfg_done_msg cmd_cfg_done_msg;
+		getevent(&cmd_cfg_done_msg, AUDREC_MSG_CMD_CFG_DONE_MSG_LEN);
+		if (cmd_cfg_done_msg.audrec_enc_type & \
+				AUDREC_MSG_CFG_DONE_ENC_ENA) {
+			audio->audrec_obj_idx = cmd_cfg_done_msg.audrec_obj_idx;
+			MM_DBG("CFG ENABLED\n");
+			if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
+				MM_DBG("routing command\n");
+				audqcelp_in_routing_mode_config(audio);
+			} else {
+				audqcelp_in_encmem_config(audio);
+			}
+		} else {
+			MM_DBG("CFG SLEEP\n");
+			audio->running = 0;
+			wake_up(&audio->wait_enable);
+		}
+		break;
+	}
+	case AUDREC_MSG_CMD_ROUTING_MODE_DONE_MSG: {
+		struct audrec_msg_cmd_routing_mode_done_msg \
+			routing_msg;
+		getevent(&routing_msg, AUDREC_MSG_CMD_ROUTING_MODE_DONE_MSG);
+		MM_DBG("AUDREC_MSG_CMD_ROUTING_MODE_DONE_MSG");
+		if (routing_msg.configuration == 0) {
+			MM_ERR("routing configuration failed\n");
+			audio->running = 0;
+			wake_up(&audio->wait_enable);
+		} else
+			audqcelp_in_encmem_config(audio);
+		break;
+	}
+	case AUDREC_MSG_CMD_AREC_MEM_CFG_DONE_MSG: {
+		MM_DBG("AREC_MEM_CFG_DONE_MSG\n");
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
+			audqcelp_in_encparam_config(audio);
+		else
+			audpcm_config(audio);
+		break;
+	}
+	case AUDREC_CMD_PCM_CFG_ARM_TO_ENC_DONE_MSG: {
+		MM_DBG("AUDREC_CMD_PCM_CFG_ARM_TO_ENC_DONE_MSG");
+		audqcelp_in_encparam_config(audio);
+	    break;
+	}
+	case AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG: {
+		MM_DBG("AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG\n");
+		audio->running = 1;
+		wake_up(&audio->wait_enable);
+		if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)
+			audrec_pcm_send_data(audio, 1);
+		break;
+	}
+	case AUDREC_CMD_PCM_BUFFER_PTR_UPDATE_ARM_TO_ENC_MSG: {
+		MM_DBG("ptr_update recieved from DSP\n");
+		audrec_pcm_send_data(audio, 1);
+		break;
+	}
+	case AUDREC_MSG_NO_EXT_PKT_AVAILABLE_MSG: {
+		struct audrec_msg_no_ext_pkt_avail_msg err_msg;
+		getevent(&err_msg, AUDREC_MSG_NO_EXT_PKT_AVAILABLE_MSG_LEN);
+		MM_DBG("NO_EXT_PKT_AVAILABLE_MSG %x\n",\
+			err_msg.audrec_err_id);
+		break;
+	}
+	case AUDREC_MSG_PACKET_READY_MSG: {
+		struct audrec_msg_packet_ready_msg pkt_ready_msg;
+
+		getevent(&pkt_ready_msg, AUDREC_MSG_PACKET_READY_MSG_LEN);
+		MM_DBG("UP_PACKET_READY_MSG: write cnt msw  %d \
+		write cnt lsw %d read cnt msw %d  read cnt lsw %d \n",\
+		pkt_ready_msg.pkt_counter_msw, \
+		pkt_ready_msg.pkt_counter_lsw, \
+		pkt_ready_msg.pkt_read_cnt_msw, \
+		pkt_ready_msg.pkt_read_cnt_lsw);
+
+		audqcelp_in_get_dsp_frames(audio);
+		break;
+	}
+	case AUDREC_UP_NT_PACKET_READY_MSG: {
+		struct audrec_up_nt_packet_ready_msg pkt_ready_msg;
+
+		getevent(&pkt_ready_msg, AUDREC_UP_NT_PACKET_READY_MSG_LEN);
+		MM_DBG("UP_NT_PACKET_READY_MSG: write cnt lsw  %d \
+		write cnt msw %d read cnt lsw %d  read cnt msw %d \n",\
+		pkt_ready_msg.audrec_packetwrite_cnt_lsw, \
+		pkt_ready_msg.audrec_packetwrite_cnt_msw, \
+		pkt_ready_msg.audrec_upprev_readcount_lsw, \
+		pkt_ready_msg.audrec_upprev_readcount_msw);
+
+		audqcelp_nt_in_get_dsp_frames(audio);
+		break;
+	}
+	case AUDREC_CMD_FLUSH_DONE_MSG: {
+		audio->wflush = 0;
+		audio->rflush = 0;
+		audio->flush_ack = 1;
+		wake_up(&audio->write_wait);
+		MM_DBG("flush ack recieved\n");
+		break;
+	}
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module \
+				enable/disable(audrectask)\n");
+		break;
+	default:
+		MM_ERR("unknown event %d\n", id);
+	}
+}
+
+static struct msm_adsp_ops audpre_qcelp_adsp_ops = {
+	.event = audpre_dsp_event,
+};
+
+static struct msm_adsp_ops audrec_qcelp_adsp_ops = {
+	.event = audrec_dsp_event,
+};
+
+static int audqcelp_in_dsp_enable(struct audio_qcelp_in *audio, int enable)
+{
+	struct audrec_cmd_enc_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_ENC_CFG;
+	cmd.audrec_enc_type = (audio->enc_type & 0xFF) |
+			(enable ? AUDREC_CMD_ENC_ENA : AUDREC_CMD_ENC_DIS);
+	/* Don't care */
+	cmd.audrec_obj_idx = audio->audrec_obj_idx;
+
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static int audqcelp_in_encmem_config(struct audio_qcelp_in *audio)
+{
+	struct audrec_cmd_arecmem_cfg cmd;
+	uint16_t *data = (void *) audio->data;
+	int n;
+	int header_len = 0;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	cmd.cmd_id = AUDREC_CMD_ARECMEM_CFG;
+	cmd.audrec_obj_idx = audio->audrec_obj_idx;
+	/* Rate at which packet complete message comes */
+	cmd.audrec_up_pkt_intm_cnt = 1;
+	cmd.audrec_extpkt_buffer_msw = audio->phys >> 16;
+	cmd.audrec_extpkt_buffer_lsw = audio->phys;
+	/* Max Buffer no available for frames */
+	cmd.audrec_extpkt_buffer_num = FRAME_NUM;
+
+	/* prepare buffer pointers:
+	 * T:36 bytes qcelp packet + 4 halfword header
+	 * NT:36 bytes qcelp packet + 12 halfword header
+	 */
+	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
+		header_len = FRAME_HEADER_SIZE/2;
+	else
+		header_len = NT_FRAME_HEADER_SIZE/2;
+
+	for (n = 0; n < FRAME_NUM; n++) {
+		audio->in[n].data = data + header_len;
+		data += (QCELP_FRAME_SIZE/2) + header_len;
+		MM_DBG("0x%8x\n", (int)(audio->in[n].data - header_len*2));
+	}
+
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static int audqcelp_in_encparam_config(struct audio_qcelp_in *audio)
+{
+	struct audrec_cmd_arecparam_qcelp_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDREC_CMD_ARECPARAM_CFG;
+	cmd.common.audrec_obj_idx = audio->audrec_obj_idx;
+	cmd.enc_min_rate = audio->cfg.min_bit_rate;
+	cmd.enc_max_rate = audio->cfg.max_bit_rate;
+	cmd.rate_modulation_cmd = 0;  /* Default set to 0 */
+	cmd.reduced_rate_level = 0;  /* Default set to 0 */
+
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static int audqcelp_flush_command(struct audio_qcelp_in *audio)
+{
+	struct audrec_cmd_flush cmd;
+	MM_DBG("\n");
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_FLUSH;
+	return audio_send_queue_rec(audio, &cmd, sizeof(cmd));
+}
+
+static int audqcelp_in_dsp_read_buffer(struct audio_qcelp_in *audio,
+		uint32_t read_cnt)
+{
+	audrec_cmd_packet_ext_ptr cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_PACKET_EXT_PTR;
+	cmd.type = audio->audrec_obj_idx;
+	cmd.curr_rec_count_msw = read_cnt >> 16;
+	cmd.curr_rec_count_lsw = read_cnt;
+
+	return audio_send_queue_recbs(audio, &cmd, sizeof(cmd));
+}
+
+/* ------------------- device --------------------- */
+
+static void audqcelp_ioport_reset(struct audio_qcelp_in *audio)
+{
+	/* Make sure read/write thread are free from
+	 * sleep and knowing that system is not able
+	 * to process io request at the moment
+	 */
+	wake_up(&audio->wait);
+	mutex_lock(&audio->read_lock);
+	audqcelp_in_flush(audio);
+	mutex_unlock(&audio->read_lock);
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audqcelp_out_flush(audio);
+	mutex_unlock(&audio->write_lock);
+}
+
+static void audqcelp_in_flush(struct audio_qcelp_in *audio)
+{
+	int i;
+	unsigned long flags;
+
+	audio->eos_ack = 0;
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->dsp_cnt = 0;
+	audio->in_head = 0;
+	audio->in_tail = 0;
+	audio->in_count = 0;
+	for (i = FRAME_NUM-1; i >= 0; i--) {
+		audio->in[i].size = 0;
+		audio->in[i].read = 0;
+	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	MM_DBG("in_bytes %d\n", atomic_read(&audio->in_bytes));
+	MM_DBG("in_samples %d\n", atomic_read(&audio->in_samples));
+	atomic_set(&audio->in_bytes, 0);
+	atomic_set(&audio->in_samples, 0);
+}
+
+static void audqcelp_out_flush(struct audio_qcelp_in *audio)
+{
+	int i;
+	unsigned long flags;
+
+	audio->out_head = 0;
+	audio->out_count = 0;
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->out_tail = 0;
+	for (i = OUT_FRAME_NUM-1; i >= 0; i--) {
+		audio->out[i].size = 0;
+		audio->out[i].read = 0;
+		audio->out[i].used = 0;
+	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+static long audqcelp_in_ioctl(struct file *file,
+				unsigned int cmd, unsigned long arg)
+{
+	struct audio_qcelp_in *audio = file->private_data;
+	int rc = 0;
+
+	MM_DBG("\n");
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = atomic_read(&audio->in_bytes);
+		stats.sample_count = atomic_read(&audio->in_samples);
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return rc;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START: {
+		rc = audqcelp_in_enable(audio);
+		if (!rc) {
+			rc =
+			wait_event_interruptible_timeout(audio->wait_enable,
+				audio->running != 0, 1*HZ);
+			MM_DBG("state %d rc = %d\n", audio->running, rc);
+
+			if (audio->running == 0)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		audio->stopped = 0;
+		break;
+	}
+	case AUDIO_STOP: {
+		rc = audqcelp_in_disable(audio);
+		break;
+	}
+	case AUDIO_FLUSH: {
+		MM_DBG("AUDIO_FLUSH\n");
+		audio->rflush = 1;
+		audio->wflush = 1;
+		audqcelp_ioport_reset(audio);
+		if (audio->running) {
+			audqcelp_flush_command(audio);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config cfg;
+		memset(&cfg, 0, sizeof(cfg));
+		cfg.buffer_size = OUT_BUFFER_SIZE;
+		cfg.buffer_count = OUT_FRAME_NUM;
+		cfg.sample_rate = convert_samp_index(audio->samp_rate);
+		cfg.channel_count = 1;
+		cfg.type = 0;
+		cfg.unused[0] = 0;
+		cfg.unused[1] = 0;
+		cfg.unused[2] = 0;
+		if (copy_to_user((void *) arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	}
+	case AUDIO_GET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		memset(&cfg, 0, sizeof(cfg));
+		cfg.buffer_size = audio->buffer_size;
+		cfg.buffer_count = FRAME_NUM;
+		if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	}
+	case AUDIO_SET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		/* Allow only single frame */
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+			if (cfg.buffer_size != (FRAME_SIZE - 8)) {
+				rc = -EINVAL;
+				break;
+			}
+		} else {
+			if (cfg.buffer_size != (QCELP_FRAME_SIZE + 14)) {
+				rc = -EINVAL;
+				break;
+			}
+		}
+		audio->buffer_size = cfg.buffer_size;
+		break;
+	}
+	case AUDIO_GET_QCELP_ENC_CONFIG: {
+		if (copy_to_user((void *) arg, &audio->cfg, sizeof(audio->cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_QCELP_ENC_CONFIG: {
+		struct msm_audio_qcelp_enc_config cfg;
+		if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		MM_DBG("0X%8x, 0x%8x, 0x%8x\n", cfg.min_bit_rate,
+				cfg.max_bit_rate, cfg.cdma_rate);
+		if (cfg.min_bit_rate > CDMA_RATE_FULL || \
+				 cfg.min_bit_rate < CDMA_RATE_EIGHTH) {
+			MM_ERR("invalid min bitrate\n");
+			rc = -EFAULT;
+			break;
+		}
+		if (cfg.max_bit_rate > CDMA_RATE_FULL || \
+				cfg.max_bit_rate < CDMA_RATE_EIGHTH) {
+			MM_ERR("invalid max bitrate\n");
+			rc = -EFAULT;
+			break;
+		}
+		/* Recording Does not support Erase and Blank */
+		if (cfg.cdma_rate > CDMA_RATE_FULL ||
+			cfg.cdma_rate < CDMA_RATE_EIGHTH) {
+			MM_ERR("invalid qcelp cdma rate\n");
+			rc = -EFAULT;
+			break;
+		}
+		memcpy(&audio->cfg, &cfg, sizeof(cfg));
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static ssize_t audqcelp_in_read(struct file *file,
+				char __user *buf,
+				size_t count, loff_t *pos)
+{
+	struct audio_qcelp_in *audio = file->private_data;
+	unsigned long flags;
+	const char __user *start = buf;
+	void *data;
+	uint32_t index;
+	uint32_t size;
+	int rc = 0;
+	struct qcelp_encoded_meta_out meta_field;
+	struct audio_frame_nt *nt_frame;
+	MM_DBG("count = %d\n", count);
+	mutex_lock(&audio->read_lock);
+	while (count > 0) {
+		rc = wait_event_interruptible(
+			audio->wait, (audio->in_count > 0) || audio->stopped ||
+			audio->rflush);
+		if (rc < 0)
+			break;
+
+		if (audio->rflush) {
+			rc = -EBUSY;
+			break;
+		}
+		if (audio->stopped && !audio->in_count) {
+			MM_DBG("Driver in stop state, No more buffer to read");
+			rc = 0;/* End of File */
+			break;
+		}
+
+		index = audio->in_tail;
+		data = (uint8_t *) audio->in[index].data;
+		size = audio->in[index].size;
+
+		if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
+			nt_frame = (struct audio_frame_nt *)(data -
+					sizeof(struct audio_frame_nt));
+			memcpy((char *)&meta_field.time_stamp_dword_lsw,
+				(char *)&nt_frame->time_stamp_dword_lsw,
+				(sizeof(struct qcelp_encoded_meta_out) - \
+				sizeof(uint16_t)));
+			meta_field.metadata_len =
+					sizeof(struct qcelp_encoded_meta_out);
+			if (copy_to_user((char *)start, (char *)&meta_field,
+				sizeof(struct qcelp_encoded_meta_out))) {
+				rc = -EFAULT;
+				break;
+			}
+			if (nt_frame->nflag_lsw & 0x0001) {
+				MM_ERR("recieved EOS in read call\n");
+				audio->eos_ack = 1;
+			}
+			buf += sizeof(struct qcelp_encoded_meta_out);
+			count -= sizeof(struct qcelp_encoded_meta_out);
+		}
+		if (count >= size) {
+			/* order the reads on the buffer */
+			dma_coherent_post_ops();
+			if (copy_to_user(buf, data, size)) {
+				rc = -EFAULT;
+				break;
+			}
+			spin_lock_irqsave(&audio->dsp_lock, flags);
+			if (index != audio->in_tail) {
+				/* overrun -- data is
+				 * invalid and we need to retry */
+				spin_unlock_irqrestore(&audio->dsp_lock, flags);
+				continue;
+			}
+			audio->in[index].size = 0;
+			audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
+			audio->in_count--;
+			spin_unlock_irqrestore(&audio->dsp_lock, flags);
+			count -= size;
+			buf += size;
+			if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)) {
+				if (!audio->eos_ack) {
+					MM_DBG("sending read ptr command \
+							%d %d\n",
+							audio->dsp_cnt,
+							audio->in_tail);
+					audqcelp_in_dsp_read_buffer(audio,
+							audio->dsp_cnt++);
+				}
+			}
+		} else {
+			MM_ERR("short read\n");
+			break;
+		}
+		break;
+	}
+	mutex_unlock(&audio->read_lock);
+
+	if (buf > start)
+		return buf - start;
+
+	return rc;
+}
+
+static void audrec_pcm_send_data(struct audio_qcelp_in *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+	MM_DBG("\n");
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (needed && !audio->wflush) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			MM_DBG("frame %d free\n", audio->out_tail);
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+			audrec_pcm_buffer_ptr_refresh(audio,
+						 audio->out_tail,
+						    frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+ done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static int audqcelp_in_fsync(struct file *file, loff_t a, loff_t b, int datasync)
+
+{
+	struct audio_qcelp_in *audio = file->private_data;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (!audio->running || (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)) {
+		rc = -EINVAL;
+		goto done_nolock;
+	}
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->write_wait,
+			audio->wflush);
+	MM_DBG("waked on by some event audio->wflush = %d\n", audio->wflush);
+
+	if (rc < 0)
+		goto done;
+	else if (audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+done:
+	mutex_unlock(&audio->write_lock);
+done_nolock:
+	return rc;
+
+}
+
+int audrec_qcelp_process_eos(struct audio_qcelp_in *audio,
+		const char __user *buf_start, unsigned short mfield_size)
+{
+	struct buffer *frame;
+	int rc = 0;
+
+	frame = audio->out + audio->out_head;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->out_needed &&
+		audio->out[0].used == 0 &&
+		audio->out[1].used == 0)
+		|| (audio->stopped)
+		|| (audio->wflush));
+
+	if (rc < 0)
+		goto done;
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+	if (copy_from_user(frame->data, buf_start, mfield_size)) {
+		rc = -EFAULT;
+		goto done;
+	}
+
+	frame->mfield_sz = mfield_size;
+	audio->out_head ^= 1;
+	frame->used = mfield_size;
+	MM_DBG("copying meta_out frame->used = %d\n", frame->used);
+	audrec_pcm_send_data(audio, 0);
+done:
+	return rc;
+}
+
+static ssize_t audqcelp_in_write(struct file *file,
+				const char __user *buf,
+				size_t count, loff_t *pos)
+{
+	struct audio_qcelp_in *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	char *cpy_ptr;
+	int rc = 0, eos_condition = AUDPREPROC_QCELP_EOS_NONE;
+	unsigned short mfield_size = 0;
+	int write_count = 0;
+	MM_DBG("cnt=%d\n", count);
+
+	if (count & 1)
+		return -EINVAL;
+
+	if (audio->mode != MSM_AUD_ENC_MODE_NONTUNNEL)
+		return -EINVAL;
+
+	mutex_lock(&audio->write_lock);
+	frame = audio->out + audio->out_head;
+	/* if supplied count is more than driver buffer size
+	 * then only copy driver buffer size
+	 */
+	if (count > frame->size)
+		count = frame->size;
+
+	write_count = count;
+	cpy_ptr = frame->data;
+	rc = wait_event_interruptible(audio->write_wait,
+				      (frame->used == 0)
+					|| (audio->stopped)
+					|| (audio->wflush));
+	if (rc < 0)
+		goto error;
+
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto error;
+	}
+	if (audio->mfield) {
+		if (buf == start) {
+			/* Processing beginning of user buffer */
+			if (__get_user(mfield_size,
+				(unsigned short __user *) buf)) {
+				rc = -EFAULT;
+				goto error;
+			} else if (mfield_size > count) {
+				rc = -EINVAL;
+				goto error;
+			}
+			MM_DBG("mf offset_val %x\n", mfield_size);
+			if (copy_from_user(cpy_ptr, buf, mfield_size)) {
+				rc = -EFAULT;
+				goto error;
+			}
+			/* Check if EOS flag is set and buffer has
+			 * contains just meta field
+			 */
+			if (cpy_ptr[AUDPREPROC_QCELP_EOS_FLG_OFFSET] &
+					AUDPREPROC_QCELP_EOS_FLG_MASK) {
+				eos_condition = AUDPREPROC_QCELP_EOS_SET;
+				MM_DBG("EOS SET\n");
+				if (mfield_size == count) {
+					buf += mfield_size;
+					eos_condition = 0;
+					goto exit;
+				} else
+				cpy_ptr[AUDPREPROC_QCELP_EOS_FLG_OFFSET] &=
+					~AUDPREPROC_QCELP_EOS_FLG_MASK;
+			}
+			cpy_ptr += mfield_size;
+			count -= mfield_size;
+			buf += mfield_size;
+		} else {
+			mfield_size = 0;
+			MM_DBG("continuous buffer\n");
+		}
+		frame->mfield_sz = mfield_size;
+	}
+	MM_DBG("copying the stream count = %d\n", count);
+	if (copy_from_user(cpy_ptr, buf, count)) {
+		rc = -EFAULT;
+		goto error;
+	}
+exit:
+	frame->used = count;
+	audio->out_head ^= 1;
+	if (!audio->flush_ack)
+		audrec_pcm_send_data(audio, 0);
+	else {
+		audrec_pcm_send_data(audio, 1);
+		audio->flush_ack = 0;
+	}
+	if (eos_condition == AUDPREPROC_QCELP_EOS_SET)
+		rc = audrec_qcelp_process_eos(audio, start, mfield_size);
+	mutex_unlock(&audio->write_lock);
+	return write_count;
+error:
+	mutex_unlock(&audio->write_lock);
+	return rc;
+}
+
+static int audqcelp_in_release(struct inode *inode, struct file *file)
+{
+	struct audio_qcelp_in *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	audqcelp_in_disable(audio);
+	audqcelp_in_flush(audio);
+	msm_adsp_put(audio->audrec);
+
+	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
+		msm_adsp_put(audio->audpre);
+
+	audpreproc_aenc_free(audio->enc_id);
+	audio->audrec = NULL;
+	audio->audpre = NULL;
+	audio->opened = 0;
+
+	if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) && \
+	   (audio->out_data)) {
+		iounmap(audio->map_v_write);
+		free_contiguous_memory_by_paddr(audio->out_phys);
+		audio->out_data = NULL;
+	}
+
+	if (audio->data) {
+		iounmap(audio->map_v_read);
+		free_contiguous_memory_by_paddr(audio->phys);
+		audio->data = NULL;
+	}
+	mutex_unlock(&audio->lock);
+	return 0;
+}
+
+static struct audio_qcelp_in the_audio_qcelp_in;
+
+static int audqcelp_in_open(struct inode *inode, struct file *file)
+{
+	struct audio_qcelp_in *audio = &the_audio_qcelp_in;
+	int rc;
+	int encid;
+	int dma_size = 0;
+
+	mutex_lock(&audio->lock);
+	if (audio->opened) {
+		rc = -EBUSY;
+		goto done;
+	}
+	if ((file->f_mode & FMODE_WRITE) &&
+		(file->f_mode & FMODE_READ)) {
+		audio->mode = MSM_AUD_ENC_MODE_NONTUNNEL;
+		dma_size = NT_DMASZ;
+		MM_DBG("Opened for non tunnel mode encoding\n");
+	} else if (!(file->f_mode & FMODE_WRITE) &&
+				(file->f_mode & FMODE_READ)) {
+		audio->mode = MSM_AUD_ENC_MODE_TUNNEL;
+		dma_size = DMASZ;
+		MM_DBG("Opened for tunnel mode encoding\n");
+	} else {
+		MM_ERR("Invalid mode\n");
+		rc = -EACCES;
+		goto done;
+	}
+
+	/* Settings will be re-config at AUDIO_SET_CONFIG,
+	 * but at least we need to have initial config
+	 */
+	audio->samp_rate = RPC_AUD_DEF_SAMPLE_RATE_8000,
+	audio->samp_rate_index = AUDREC_CMD_SAMP_RATE_INDX_8000;
+	audio->channel_mode = AUDREC_CMD_STEREO_MODE_MONO;
+	if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)
+		audio->buffer_size = (QCELP_FRAME_SIZE + 14);
+	else
+		audio->buffer_size = QCELP_FRAME_SIZE;
+	audio->enc_type = AUDREC_CMD_TYPE_0_INDEX_QCELP | audio->mode;
+
+	audio->cfg.cdma_rate = CDMA_RATE_FULL;
+	audio->cfg.min_bit_rate = CDMA_RATE_FULL;
+	audio->cfg.max_bit_rate = CDMA_RATE_FULL;
+
+	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+		rc = audmgr_open(&audio->audmgr);
+		if (rc)
+			goto done;
+	}
+
+	encid = audpreproc_aenc_alloc(audio->enc_type, &audio->module_name,
+			&audio->queue_ids);
+	if (encid < 0) {
+		MM_ERR("No free encoder available\n");
+		rc = -ENODEV;
+		goto done;
+	}
+	audio->enc_id = encid;
+
+	rc = msm_adsp_get(audio->module_name, &audio->audrec,
+			   &audrec_qcelp_adsp_ops, audio);
+	if (rc) {
+		audpreproc_aenc_free(audio->enc_id);
+		goto done;
+	}
+
+	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+		rc = msm_adsp_get("AUDPREPROCTASK", &audio->audpre,
+				&audpre_qcelp_adsp_ops, audio);
+		if (rc) {
+			msm_adsp_put(audio->audrec);
+			audpreproc_aenc_free(audio->enc_id);
+			goto done;
+		}
+	}
+
+	audio->dsp_cnt = 0;
+	audio->stopped = 0;
+	audio->wflush = 0;
+	audio->rflush = 0;
+	audio->flush_ack = 0;
+
+	audqcelp_in_flush(audio);
+	audqcelp_out_flush(audio);
+
+	audio->phys = allocate_contiguous_ebi_nomap(dma_size, SZ_4K);
+	if (!audio->phys) {
+		MM_ERR("could not allocate physical read buffers\n");
+		rc = -ENOMEM;
+		goto evt_error;
+	} else {
+		audio->map_v_read = ioremap(audio->phys, dma_size);
+		if (IS_ERR(audio->map_v_read)) {
+			MM_ERR("could not map physical address\n");
+			rc = -ENOMEM;
+			free_contiguous_memory_by_paddr(audio->phys);
+			goto evt_error;
+		}
+		audio->data = audio->map_v_read;
+		MM_DBG("read buf: phy addr 0x%08x kernel addr 0x%08x\n",
+				audio->phys, (int)audio->data);
+	}
+
+	audio->out_data = NULL;
+	if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
+		audio->out_phys = allocate_contiguous_ebi_nomap(BUFFER_SIZE,
+						SZ_4K);
+		if (!audio->out_phys) {
+			MM_ERR("could not allocate physical write buffers\n");
+			rc = -ENOMEM;
+			iounmap(audio->map_v_read);
+			free_contiguous_memory_by_paddr(audio->phys);
+			goto evt_error;
+		} else {
+			audio->map_v_write = ioremap(
+						audio->out_phys, BUFFER_SIZE);
+
+			if (IS_ERR(audio->map_v_write)) {
+				MM_ERR("could not map write phys address\n");
+				rc = -ENOMEM;
+				iounmap(audio->map_v_read);
+				free_contiguous_memory_by_paddr(audio->phys);
+				free_contiguous_memory_by_paddr(\
+							audio->out_phys);
+				goto evt_error;
+			}
+			audio->out_data = audio->map_v_write;
+			MM_DBG("wr buf: phy addr 0x%08x kernel addr 0x%08x\n",
+					audio->out_phys, (int)audio->out_data);
+		}
+
+		/* Initialize buffer */
+		audio->out[0].data = audio->out_data + 0;
+		audio->out[0].addr = audio->out_phys + 0;
+		audio->out[0].size = OUT_BUFFER_SIZE;
+
+		audio->out[1].data = audio->out_data + OUT_BUFFER_SIZE;
+		audio->out[1].addr = audio->out_phys + OUT_BUFFER_SIZE;
+		audio->out[1].size = OUT_BUFFER_SIZE;
+
+		MM_DBG("audio->out[0].data = %d  audio->out[1].data = %d",
+				(unsigned int)audio->out[0].data,
+				(unsigned int)audio->out[1].data);
+		audio->mfield = NT_FRAME_HEADER_SIZE;
+		audio->out_frame_cnt++;
+	}
+	file->private_data = audio;
+	audio->opened = 1;
+
+done:
+	mutex_unlock(&audio->lock);
+	return rc;
+evt_error:
+	msm_adsp_put(audio->audrec);
+	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
+		msm_adsp_put(audio->audpre);
+
+	audpreproc_aenc_free(audio->enc_id);
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static const struct file_operations audio_qcelp_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audqcelp_in_open,
+	.release	= audqcelp_in_release,
+	.read		= audqcelp_in_read,
+	.write		= audqcelp_in_write,
+	.fsync		= audqcelp_in_fsync,
+	.unlocked_ioctl	= audqcelp_in_ioctl,
+};
+
+static struct miscdevice audqcelp_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_qcelp_in",
+	.fops	= &audio_qcelp_in_fops,
+};
+
+static int __init audqcelp_in_init(void)
+{
+	mutex_init(&the_audio_qcelp_in.lock);
+	mutex_init(&the_audio_qcelp_in.read_lock);
+	spin_lock_init(&the_audio_qcelp_in.dsp_lock);
+	init_waitqueue_head(&the_audio_qcelp_in.wait);
+	init_waitqueue_head(&the_audio_qcelp_in.wait_enable);
+	mutex_init(&the_audio_qcelp_in.write_lock);
+	init_waitqueue_head(&the_audio_qcelp_in.write_wait);
+	return misc_register(&audqcelp_in_misc);
+}
+device_initcall(audqcelp_in_init);
diff --git a/arch/arm/mach-msm/qdsp5/audio_voice_lb.c b/arch/arm/mach-msm/qdsp5/audio_voice_lb.c
new file mode 100644
index 0000000..08fa487
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_voice_lb.c
@@ -0,0 +1,369 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/kthread.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/wakelock.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include <mach/debug_mm.h>
+#include <mach/msm_rpcrouter.h>
+
+#include "audmgr_new.h"
+
+#define VOICELOOPBACK_PROG	0x300000B8
+#define VOICELOOP_VERS	0x00010001
+
+#define VOICELOOPBACK_START_PROC 2
+#define VOICELOOPBACK_STOP_PROC 3
+
+#define RPC_TYPE_REQUEST 0
+#define RPC_TYPE_REPLY 1
+
+#define RPC_STATUS_FAILURE 0
+#define RPC_STATUS_SUCCESS 1
+#define RPC_STATUS_REJECT 1
+
+#define RPC_COMMON_HDR_SZ  (sizeof(uint32_t) * 2)
+#define RPC_REQUEST_HDR_SZ (sizeof(struct rpc_request_hdr))
+#define RPC_REPLY_HDR_SZ   (sizeof(uint32_t) * 3)
+
+#define MAX_LEN 32
+
+struct audio {
+	struct msm_rpc_endpoint *rpc_endpt;
+	uint32_t rpc_prog;
+	uint32_t rpc_ver;
+	uint32_t rpc_status;
+	struct audmgr audmgr;
+
+	struct dentry *dentry;
+
+	struct mutex lock;
+
+	struct task_struct *task;
+
+	wait_queue_head_t wait;
+	int enabled;
+	int thread_exit;
+};
+
+static struct audio the_audio;
+
+static int audio_voice_loopback_thread(void *data)
+{
+	struct audio *audio = data;
+	struct rpc_request_hdr *rpc_hdr = NULL;
+	int rpc_hdr_len;
+
+	MM_DBG("\n");
+
+	while (!kthread_should_stop()) {
+		if (rpc_hdr != NULL) {
+			kfree(rpc_hdr);
+			rpc_hdr = NULL;
+		}
+
+		if (audio->thread_exit)
+			break;
+
+		rpc_hdr_len = msm_rpc_read(audio->rpc_endpt,
+					       (void **) &rpc_hdr,
+					       -1,
+					       -1);
+		if (rpc_hdr_len < 0) {
+			MM_ERR("RPC read failed %d\n", rpc_hdr_len);
+			break;
+		} else if (rpc_hdr_len < RPC_COMMON_HDR_SZ) {
+			continue;
+		} else {
+			uint32_t rpc_type = be32_to_cpu(rpc_hdr->type);
+			if (rpc_type == RPC_TYPE_REPLY) {
+				struct rpc_reply_hdr *rpc_reply =
+					 (void *) rpc_hdr;
+				uint32_t reply_status;
+
+				reply_status =
+					be32_to_cpu(rpc_reply->reply_stat);
+
+				if (reply_status == RPC_ACCEPTSTAT_SUCCESS)
+					audio->rpc_status = \
+							RPC_STATUS_SUCCESS;
+				else {
+					audio->rpc_status = \
+							RPC_STATUS_REJECT;
+					MM_ERR("RPC reply status denied\n");
+				}
+				wake_up(&audio->wait);
+			} else {
+				MM_ERR("Unexpected RPC type %d\n", rpc_type);
+			}
+		}
+	}
+	kfree(rpc_hdr);
+	rpc_hdr = NULL;
+
+	MM_DBG("Audio Voice Looopback thread stopped\n");
+
+	return 0;
+}
+
+static int audio_voice_loopback_start(struct audio *audio)
+{
+	int rc = 0;
+	struct audmgr_config cfg;
+	struct rpc_request_hdr rpc_hdr;
+
+	MM_DBG("\n");
+
+	cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_8000;
+	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_8000;
+	cfg.def_method = RPC_AUD_DEF_METHOD_VOICE;
+	cfg.codec = RPC_AUD_DEF_CODEC_VOC_CDMA;
+	cfg.snd_method = RPC_SND_METHOD_VOICE;
+	rc = audmgr_enable(&audio->audmgr, &cfg);
+	if (rc < 0) {
+		MM_ERR("audmgr open failed, freeing instance\n");
+		rc = -EINVAL;
+		goto done;
+	}
+
+	memset(&rpc_hdr, 0, sizeof(rpc_hdr));
+
+	msm_rpc_setup_req(&rpc_hdr,
+			audio->rpc_prog,
+			audio->rpc_ver,
+			VOICELOOPBACK_START_PROC);
+
+	audio->rpc_status = RPC_STATUS_FAILURE;
+	rc = msm_rpc_write(audio->rpc_endpt,
+			   &rpc_hdr,
+			   sizeof(rpc_hdr));
+	if (rc >= 0) {
+		rc = wait_event_timeout(audio->wait,
+			(audio->rpc_status != RPC_STATUS_FAILURE),
+			1 * HZ);
+		if (rc > 0) {
+			if (audio->rpc_status != RPC_STATUS_SUCCESS) {
+				MM_ERR("Start loopback failed %d\n", rc);
+				rc = -EBUSY;
+			} else {
+				rc = 0;
+			}
+		} else {
+			MM_ERR("Wait event for acquire failed %d\n", rc);
+			rc = -EBUSY;
+		}
+	} else {
+		audmgr_disable(&audio->audmgr);
+		MM_ERR("RPC write for start loopback failed %d\n", rc);
+		rc = -EBUSY;
+	}
+done:
+	return rc;
+}
+
+static int audio_voice_loopback_stop(struct audio *audio)
+{
+	int rc = 0;
+	struct rpc_request_hdr rpc_hdr;
+
+	MM_DBG("\n");
+
+	memset(&rpc_hdr, 0, sizeof(rpc_hdr));
+
+	msm_rpc_setup_req(&rpc_hdr,
+			  audio->rpc_prog,
+			  audio->rpc_ver,
+			  VOICELOOPBACK_STOP_PROC);
+
+	audio->rpc_status = RPC_STATUS_FAILURE;
+	audio->thread_exit = 1;
+	rc = msm_rpc_write(audio->rpc_endpt,
+			   &rpc_hdr,
+			   sizeof(rpc_hdr));
+	if (rc >= 0) {
+
+		rc = wait_event_timeout(audio->wait,
+				(audio->rpc_status != RPC_STATUS_FAILURE),
+				1 * HZ);
+		if (rc > 0) {
+			MM_DBG("Wait event for release succeeded\n");
+			rc = 0;
+		} else {
+			MM_ERR("Wait event for release failed %d\n", rc);
+		}
+	} else {
+		MM_ERR("RPC write for release failed %d\n", rc);
+	}
+
+	audmgr_disable(&audio->audmgr);
+
+	return rc;
+}
+
+static int audio_voice_loopback_open(struct audio *audio_info)
+{
+	int rc = 0;
+
+	MM_DBG("\n");
+
+	rc = audmgr_open(&audio_info->audmgr);
+	if (rc) {
+		MM_ERR("audmgr open failed, freeing instance\n");
+		rc = -EINVAL;
+		goto done;
+	}
+
+	audio_info->rpc_endpt = msm_rpc_connect_compatible(VOICELOOPBACK_PROG,
+			VOICELOOP_VERS,
+			MSM_RPC_UNINTERRUPTIBLE);
+	if (IS_ERR(audio_info->rpc_endpt)) {
+		MM_ERR("VOICE LOOPBACK RPC connect\
+				failed ver 0x%x\n",
+				VOICELOOP_VERS);
+		rc = PTR_ERR(audio_info->rpc_endpt);
+		audio_info->rpc_endpt = NULL;
+		rc = -EINVAL;
+	} else {
+		MM_DBG("VOICE LOOPBACK connect succeeded ver 0x%x\n",
+				VOICELOOP_VERS);
+		audio_info->thread_exit = 0;
+		audio_info->task = kthread_run(audio_voice_loopback_thread,
+				audio_info,
+				"audio_voice_loopback");
+		if (IS_ERR(audio_info->task)) {
+			MM_ERR("voice loopback thread create failed\n");
+			rc = PTR_ERR(audio_info->task);
+			audio_info->task = NULL;
+			msm_rpc_close(audio_info->rpc_endpt);
+			audio_info->rpc_endpt = NULL;
+			rc = -EINVAL;
+		}
+		audio_info->rpc_prog = VOICELOOPBACK_PROG;
+		audio_info->rpc_ver = VOICELOOP_VERS;
+	}
+done:
+	return rc;
+}
+
+static int audio_voice_loopback_close(struct audio *audio_info)
+{
+	MM_DBG("\n");
+	msm_rpc_close(audio_info->rpc_endpt);
+	audio_info->rpc_endpt = NULL;
+	audmgr_close(&audio_info->audmgr);
+	audio_info->task = NULL;
+	return 0;
+}
+
+static ssize_t audio_voice_loopback_debug_write(struct file *file,
+				const char __user *buf,
+				size_t cnt, loff_t *ppos)
+{
+	char lbuf[MAX_LEN];
+	int rc = 0;
+
+	if (cnt > (MAX_LEN - 1))
+		return -EINVAL;
+
+	memset(&lbuf[0], 0, sizeof(lbuf));
+
+	rc = copy_from_user(lbuf, buf, cnt);
+	if (rc) {
+		MM_ERR("Unable to copy data from user space\n");
+		return -EFAULT;
+	}
+
+	lbuf[cnt] = '\0';
+
+	if (!strncmp(&lbuf[0], "1", cnt-1)) {
+		mutex_lock(&the_audio.lock);
+		if (!the_audio.enabled) {
+			rc = audio_voice_loopback_open(&the_audio);
+			if (!rc) {
+				rc = audio_voice_loopback_start(&the_audio);
+				if (rc < 0) {
+					the_audio.enabled = 0;
+					audio_voice_loopback_close(&the_audio);
+				} else {
+					the_audio.enabled = 1;
+				}
+			}
+		}
+		mutex_unlock(&the_audio.lock);
+	} else if (!strncmp(lbuf, "0", cnt-1)) {
+		mutex_lock(&the_audio.lock);
+		if (the_audio.enabled) {
+			audio_voice_loopback_stop(&the_audio);
+			audio_voice_loopback_close(&the_audio);
+			the_audio.enabled = 0;
+		}
+		mutex_unlock(&the_audio.lock);
+	} else {
+		rc = -EINVAL;
+	}
+
+	if (rc == 0) {
+		rc = cnt;
+	} else {
+		MM_INFO("rc = %d\n", rc);
+		MM_INFO("\nWrong command: Use =>\n");
+		MM_INFO("-------------------------\n");
+		MM_INFO("To Start Loopback:: echo \"1\">/sys/kernel/debug/\
+			voice_loopback\n");
+		MM_INFO("To Stop Loopback:: echo \"0\">/sys/kernel/debug/\
+			voice_loopback\n");
+		MM_INFO("------------------------\n");
+	}
+
+	return rc;
+}
+
+static ssize_t audio_voice_loopback_debug_open(struct inode *inode,
+		struct file *file)
+{
+	file->private_data = inode->i_private;
+	MM_DBG("Audio Voiceloop debugfs opened\n");
+	return 0;
+}
+
+static const struct file_operations voice_loopback_debug_fops = {
+	.write = audio_voice_loopback_debug_write,
+	.open = audio_voice_loopback_debug_open,
+};
+
+static int __init audio_init(void)
+{
+	int rc = 0;
+	memset(&the_audio, 0, sizeof(the_audio));
+
+	mutex_init(&the_audio.lock);
+
+	init_waitqueue_head(&the_audio.wait);
+
+	the_audio.dentry = debugfs_create_file("voice_loopback",
+			S_IFREG | S_IRUGO,
+			NULL,
+			NULL, &voice_loopback_debug_fops);
+	if (IS_ERR(the_audio.dentry))
+		MM_ERR("debugfs_create_file failed\n");
+
+	return rc;
+}
+late_initcall(audio_init);
diff --git a/arch/arm/mach-msm/qdsp5/audio_voicememo.c b/arch/arm/mach-msm/qdsp5/audio_voicememo.c
new file mode 100644
index 0000000..2011c42
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_voicememo.c
@@ -0,0 +1,965 @@
+/* arch/arm/mach-msm/qdsp5/audio_voicememo.c
+ *
+ * Voice Memo device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This code is based in part on arch/arm/mach-msm/qdsp5/audio_mp3.c
+ *
+ * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/msm_audio_voicememo.h>
+#include <linux/slab.h>
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/debug_mm.h>
+
+#include "audmgr.h"
+
+#define SND_PROG_VERS "rs30000002:0x00020001"
+#define SND_PROG 0x30000002
+#define SND_VERS_COMP 0x00020001
+#define SND_VERS2_COMP 0x00030001
+
+#define SND_VOC_REC_START_PROC                  19
+#define SND_VOC_REC_STOP_PROC                   20
+#define SND_VOC_REC_PAUSE_PROC			21
+#define SND_VOC_REC_RESUME_PROC                 22
+#define SND_VOC_REC_PUT_BUF_PROC                23
+
+#define SND_VOC_REC_AV_SYNC_CB_PTR_PROC 	9
+#define SND_VOC_REC_CB_FUNC_TYPE_PROC 		10
+
+#define REC_CLIENT_DATA		0x11223344
+#define DATA_CB_FUNC_ID		0x12345678
+#define AV_SYNC_CB_FUNC_ID	0x87654321
+#define CLIENT_DATA		0xaabbccdd
+
+#define RPC_TYPE_REQUEST 0
+#define RPC_TYPE_REPLY 1
+
+#define RPC_STATUS_FAILURE 0
+#define RPC_STATUS_SUCCESS 1
+
+#define RPC_VERSION 2
+
+#define RPC_COMMON_HDR_SZ  (sizeof(uint32_t) * 2)
+#define RPC_REQUEST_HDR_SZ (sizeof(struct rpc_request_hdr))
+#define RPC_REPLY_HDR_SZ   (sizeof(uint32_t) * 3)
+#define RPC_REPLY_SZ       (sizeof(uint32_t) * 6)
+
+#define MAX_FRAME_SIZE 36 /* QCELP - 36, AMRNB - 32, EVRC - 24 */
+#define MAX_REC_BUF_COUNT 5 /* Maximum supported voc rec buffers */
+#define MAX_REC_BUF_SIZE (MAX_FRAME_SIZE * 10)
+#define MAX_VOICEMEMO_BUF_SIZE  \
+	((MAX_REC_BUF_SIZE)*MAX_REC_BUF_COUNT) /* 5 buffers for 200ms frame */
+#define MSM_AUD_BUFFER_UPDATE_WAIT_MS 2000
+
+enum rpc_voc_rec_status_type {
+	RPC_VOC_REC_STAT_SUCCESS = 1,
+	RPC_VOC_REC_STAT_DONE = 2,
+	RPC_VOC_REC_STAT_AUTO_STOP = 4,
+	RPC_VOC_REC_STAT_PAUSED = 8,
+	RPC_VOC_REC_STAT_RESUMED = 16,
+	RPC_VOC_REC_STAT_ERROR = 32,
+	RPC_VOC_REC_STAT_BUFFER_ERROR = 64,
+	RPC_VOC_REC_STAT_INVALID_PARAM = 128,
+	RPC_VOC_REC_STAT_INT_TIME = 256,
+	RPC_VOC_REC_STAT_DATA = 512,
+	RPC_VOC_REC_STAT_NOT_READY = 1024,
+	RPC_VOC_REC_STAT_INFORM_EVRC = 2048,
+	RPC_VOC_REC_STAT_INFORM_13K = 4096,
+	RPC_VOC_REC_STAT_INFORM_AMR = 8192,
+	RPC_VOC_REC_STAT_INFORM_MAX = 65535
+};
+
+struct rpc_snd_voc_rec_start_args {
+	uint32_t param_status; /* 1 = valid, 0 = not valid */
+	uint32_t rec_type;
+	uint32_t rec_interval_ms;
+	uint32_t auto_stop_ms;
+	uint32_t capability;
+	uint32_t max_rate;
+	uint32_t min_rate;
+	uint32_t frame_format;
+	uint32_t dtx_enable;
+	uint32_t data_req_ms;
+	uint32_t rec_client_data;
+
+	uint32_t cb_func_id;
+	uint32_t sync_cb_func_id;
+	uint32_t client_data;
+};
+
+struct rpc_snd_voc_rec_put_buf_args {
+	uint32_t buf;
+	uint32_t num_bytes;
+};
+
+struct snd_voc_rec_start_msg {
+	struct rpc_request_hdr hdr;
+	struct rpc_snd_voc_rec_start_args args;
+};
+
+struct snd_voc_rec_put_buf_msg {
+	struct rpc_request_hdr hdr;
+	struct rpc_snd_voc_rec_put_buf_args args;
+};
+
+struct snd_voc_rec_av_sync_cb_func_data {
+	uint32_t sync_cb_func_id;
+	uint32_t status;  /* Pointer status (1 = valid, 0  = invalid) */
+	uint32_t num_samples;
+	uint32_t time_stamp[2];
+	uint32_t lost_samples;
+	uint32_t frame_index;
+	uint32_t client_data;
+};
+
+struct snd_voc_rec_cb_func_fw_data {
+	uint32_t fw_ptr_status; /* FW Pointer status (1=valid,0=invalid) */
+	uint32_t rec_buffer_size;
+	uint32_t data[MAX_REC_BUF_SIZE/4];
+	uint32_t rec_buffer_size_copy;
+	uint32_t rec_num_frames; /* Number of voice frames */
+	uint32_t rec_length; /* Valid data in record buffer =
+			      * data_req_ms amount of data */
+	uint32_t client_data; /* A11 rec buffer pointer */
+	uint32_t rw_ptr_status; /* RW Pointer status (1=valid,0=invalid) */
+};
+
+struct snd_voc_rec_cb_func_rw_data {
+	uint32_t fw_ptr_status; /* FW Pointer status (1=valid,0=invalid) */
+	uint32_t rw_ptr_status; /* RW Pointer status (1=valid,0=invalid) */
+	uint32_t rec_buffer_size;
+	uint32_t data[MAX_REC_BUF_SIZE/4];
+	uint32_t rec_buffer_size_copy;
+	uint32_t rec_num_frames; /* Number of voice frames */
+	uint32_t rec_length; /* Valid data in record buffer =
+			      * data_req_ms amount of data */
+	uint32_t client_data; /* A11 rec buffer pointer */
+};
+
+struct snd_voc_rec_data_cb_func_data {
+	uint32_t cb_func_id;
+	uint32_t status; /* Pointer status (1 = valid, 0  = invalid) */
+	uint32_t rec_status;
+
+	union {
+		struct snd_voc_rec_cb_func_fw_data fw_data;
+		struct snd_voc_rec_cb_func_rw_data rw_data;
+	} pkt;
+};
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used; /* Usage actual recorded data */
+	unsigned addr;
+	unsigned numframes;
+};
+
+struct audio_voicememo {
+	uint32_t byte_count; /* Pass statistics to user space for
+			      * time stamping */
+	uint32_t frame_count;
+
+	int opened;
+	int enabled;
+	int running;
+	int stopped;
+	int pause_resume;
+
+	uint32_t rpc_prog;
+	uint32_t rpc_ver;
+	uint32_t rpc_xid;
+	uint32_t rpc_status;
+
+	struct mutex lock;
+	struct mutex read_lock;
+	struct mutex dsp_lock;
+	wait_queue_head_t read_wait;
+	wait_queue_head_t wait;
+
+	struct buffer in[MAX_REC_BUF_COUNT];
+	char *rec_buf_ptr;
+	dma_addr_t phys;
+	uint32_t rec_buf_size;
+	uint8_t read_next;	/* index to input buffers to be read next */
+	uint8_t fill_next;	/* index to buffer that should be filled as
+				 * data comes from A9 */
+
+	struct audmgr audmgr;
+
+	struct msm_audio_voicememo_config voicememo_cfg;
+
+	struct msm_rpc_endpoint *sndept;
+	struct task_struct *task;
+};
+
+static struct audio_voicememo the_audio_voicememo;
+
+static int audvoicememo_validate_usr_config(
+		struct msm_audio_voicememo_config *config)
+{
+	int rc = -1; /* error */
+
+	if (config->rec_type != RPC_VOC_REC_FORWARD &&
+		config->rec_type != RPC_VOC_REC_REVERSE &&
+		config->rec_type != RPC_VOC_REC_BOTH)
+		goto done;
+
+	/* QCELP, EVRC, AMR-NB only */
+	if (config->capability != RPC_VOC_CAP_IS733 &&
+		config->capability != RPC_VOC_CAP_IS127 &&
+		config->capability != RPC_VOC_CAP_AMR)
+		goto done;
+
+	/* QCP, AMR format supported */
+	if ((config->frame_format != RPC_VOC_PB_NATIVE_QCP) &&
+		(config->frame_format != RPC_VOC_PB_AMR))
+		goto done;
+
+	if ((config->frame_format == RPC_VOC_PB_AMR) &&
+		(config->capability != RPC_VOC_CAP_AMR))
+		goto done;
+
+	/* To make sure, max kernel buf size matches
+	 * with max data request time */
+	if (config->data_req_ms > ((MAX_REC_BUF_SIZE/MAX_FRAME_SIZE)*20))
+		goto done;
+
+	rc = 0;
+done:
+	return rc;
+}
+
+static void audvoicememo_flush_buf(struct audio_voicememo *audio)
+{
+	uint8_t index;
+
+	for (index = 0; index < MAX_REC_BUF_COUNT; index++)
+		audio->in[index].used = 0;
+
+	audio->read_next = 0;
+	mutex_lock(&audio->dsp_lock);
+	audio->fill_next = 0;
+	mutex_unlock(&audio->dsp_lock);
+}
+
+static void audvoicememo_ioport_reset(struct audio_voicememo *audio)
+{
+	/* Make sure read/write thread are free from
+	 * sleep and knowing that system is not able
+	 * to process io request at the moment
+	 */
+	wake_up(&audio->read_wait);
+	mutex_lock(&audio->read_lock);
+	audvoicememo_flush_buf(audio);
+	mutex_unlock(&audio->read_lock);
+}
+
+/* must be called with audio->lock held */
+static int audvoicememo_enable(struct audio_voicememo *audio)
+{
+	struct audmgr_config cfg;
+	struct snd_voc_rec_put_buf_msg bmsg;
+	struct snd_voc_rec_start_msg msg;
+	uint8_t index;
+	uint32_t offset = 0;
+	int rc;
+
+	if (audio->enabled)
+		return 0;
+
+	/* Codec / method configure to audmgr client */
+	cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_8000;
+	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+	cfg.def_method = RPC_AUD_DEF_METHOD_RECORD;
+
+	if (audio->voicememo_cfg.capability == RPC_VOC_CAP_IS733)
+		cfg.codec = RPC_AUD_DEF_CODEC_VOC_13K;
+	else if (audio->voicememo_cfg.capability == RPC_VOC_CAP_IS127)
+		cfg.codec = RPC_AUD_DEF_CODEC_VOC_EVRC;
+	else
+		cfg.codec = RPC_AUD_DEF_CODEC_VOC_AMR; /* RPC_VOC_CAP_AMR */
+
+	cfg.snd_method = RPC_SND_METHOD_VOICE;
+	rc = audmgr_enable(&audio->audmgr, &cfg);
+
+	if (rc < 0)
+		return rc;
+
+	/* Configure VOC Rec buffer */
+	for (index = 0; index < MAX_REC_BUF_COUNT; index++) {
+		audio->in[index].data = audio->rec_buf_ptr + offset;
+		audio->in[index].addr = audio->phys + offset;
+		audio->in[index].size = audio->rec_buf_size;
+		audio->in[index].used = 0;
+		audio->in[index].numframes = 0;
+		offset += audio->rec_buf_size;
+		bmsg.args.buf = (uint32_t) audio->in[index].data;
+		bmsg.args.num_bytes = cpu_to_be32(audio->in[index].size);
+		MM_DBG("rec_buf_ptr=0x%8x, rec_buf_size = 0x%8x\n",
+				bmsg.args.buf, bmsg.args.num_bytes);
+
+		msm_rpc_setup_req(&bmsg.hdr, audio->rpc_prog, audio->rpc_ver,
+				SND_VOC_REC_PUT_BUF_PROC);
+		audio->rpc_xid = bmsg.hdr.xid;
+		audio->rpc_status = RPC_STATUS_FAILURE;
+		msm_rpc_write(audio->sndept, &bmsg, sizeof(bmsg));
+		rc = wait_event_timeout(audio->wait,
+			audio->rpc_status != RPC_STATUS_FAILURE, 1 * HZ);
+		if (rc == 0)
+			goto err;
+	}
+
+
+	/* Start Recording */
+	msg.args.param_status = cpu_to_be32(0x00000001);
+	msg.args.rec_type = cpu_to_be32(audio->voicememo_cfg.rec_type);
+	msg.args.rec_interval_ms =
+		cpu_to_be32(audio->voicememo_cfg.rec_interval_ms);
+	msg.args.auto_stop_ms = cpu_to_be32(audio->voicememo_cfg.auto_stop_ms);
+	msg.args.capability = cpu_to_be32(audio->voicememo_cfg.capability);
+	msg.args.max_rate = cpu_to_be32(audio->voicememo_cfg.max_rate);
+	msg.args.min_rate = cpu_to_be32(audio->voicememo_cfg.min_rate);
+	msg.args.frame_format = cpu_to_be32(audio->voicememo_cfg.frame_format);
+	msg.args.dtx_enable = cpu_to_be32(audio->voicememo_cfg.dtx_enable);
+	msg.args.data_req_ms = cpu_to_be32(audio->voicememo_cfg.data_req_ms);
+	msg.args.rec_client_data = cpu_to_be32(REC_CLIENT_DATA);
+	msg.args.cb_func_id = cpu_to_be32(DATA_CB_FUNC_ID);
+	msg.args.sync_cb_func_id = cpu_to_be32(AV_SYNC_CB_FUNC_ID);
+	msg.args.client_data = cpu_to_be32(CLIENT_DATA);
+
+	msm_rpc_setup_req(&msg.hdr, audio->rpc_prog, audio->rpc_ver,
+			SND_VOC_REC_START_PROC);
+
+	audio->rpc_xid = msg.hdr.xid;
+	audio->rpc_status = RPC_STATUS_FAILURE;
+	msm_rpc_write(audio->sndept, &msg, sizeof(msg));
+	rc = wait_event_timeout(audio->wait,
+		audio->rpc_status != RPC_STATUS_FAILURE, 1 * HZ);
+	if (rc == 0)
+		goto err;
+
+	audio->rpc_xid = 0;
+	audio->enabled = 1;
+	return 0;
+
+err:
+	audio->rpc_xid = 0;
+	audmgr_disable(&audio->audmgr);
+	MM_ERR("Fail\n");
+	return -1;
+}
+
+/* must be called with audio->lock held */
+static int audvoicememo_disable(struct audio_voicememo *audio)
+{
+	struct rpc_request_hdr rhdr;
+	int rc = 0;
+	if (audio->enabled) {
+		msm_rpc_setup_req(&rhdr, audio->rpc_prog, audio->rpc_ver,
+				SND_VOC_REC_STOP_PROC);
+		rc = msm_rpc_write(audio->sndept, &rhdr, sizeof(rhdr));
+		wait_event_timeout(audio->wait, audio->stopped == 0,
+				1 * HZ);
+		audio->stopped = 1;
+		wake_up(&audio->read_wait);
+		audmgr_disable(&audio->audmgr);
+		audio->enabled = 0;
+	}
+	return 0;
+}
+
+/* RPC Reply Generator */
+static void rpc_reply(struct msm_rpc_endpoint *ept, uint32_t xid)
+{
+	int rc = 0;
+	uint8_t reply_buf[sizeof(struct rpc_reply_hdr)];
+	struct rpc_reply_hdr *reply = (struct rpc_reply_hdr *)reply_buf;
+
+	MM_DBG("inside\n");
+	reply->xid = cpu_to_be32(xid);
+	reply->type = cpu_to_be32(RPC_TYPE_REPLY); /* reply */
+	reply->reply_stat = cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED);
+
+	reply->data.acc_hdr.accept_stat = cpu_to_be32(RPC_ACCEPTSTAT_SUCCESS);
+	reply->data.acc_hdr.verf_flavor = 0;
+	reply->data.acc_hdr.verf_length = 0;
+
+	rc = msm_rpc_write(ept, reply_buf, sizeof(reply_buf));
+	if (rc < 0)
+		MM_ERR("could not write RPC response: %d\n", rc);
+}
+
+static void process_rpc_request(uint32_t proc, uint32_t xid,
+		void *data, int len, void *private)
+{
+	struct audio_voicememo *audio = private;
+
+	MM_DBG("inside\n");
+	/* Sending Ack before processing the request
+	 * to make sure A9 get response immediate
+	 * However, if there is validation of request planned
+	 * may be move this reply Ack at the end */
+	rpc_reply(audio->sndept, xid);
+	switch (proc) {
+	case SND_VOC_REC_AV_SYNC_CB_PTR_PROC: {
+		MM_DBG("AV Sync CB:func_id=0x%8x,status=0x%x\n",
+			be32_to_cpu(( \
+			(struct snd_voc_rec_av_sync_cb_func_data *)\
+			data)->sync_cb_func_id),\
+			be32_to_cpu(( \
+			(struct snd_voc_rec_av_sync_cb_func_data *)\
+			data)->status));
+		break;
+		}
+	case SND_VOC_REC_CB_FUNC_TYPE_PROC: {
+		struct snd_voc_rec_data_cb_func_data *datacb_data
+			= (void *)(data);
+		struct snd_voc_rec_put_buf_msg bmsg;
+		uint32_t rec_status = be32_to_cpu(datacb_data->rec_status);
+
+		MM_DBG("Data CB:func_id=0x%8x,status=0x%x,\
+			rec_status=0x%x\n",
+			be32_to_cpu(datacb_data->cb_func_id),\
+			be32_to_cpu(datacb_data->status),\
+			be32_to_cpu(datacb_data->rec_status));
+
+		/* Data recorded */
+		if ((rec_status == RPC_VOC_REC_STAT_DATA) ||
+		(rec_status == RPC_VOC_REC_STAT_DONE)) {
+			if (datacb_data->pkt.fw_data.fw_ptr_status &&
+			be32_to_cpu(datacb_data->pkt.fw_data.rec_length)) {
+
+				MM_DBG("Copy FW link:rec_buf_size \
+				= 0x%08x, rec_length=0x%08x\n",
+				be32_to_cpu( \
+				datacb_data->pkt.fw_data. \
+				rec_buffer_size_copy),\
+				be32_to_cpu(datacb_data->pkt.fw_data. \
+				rec_length));
+
+				mutex_lock(&audio->dsp_lock);
+				memcpy(audio->in[audio->fill_next].data, \
+					&(datacb_data->pkt.fw_data.data[0]), \
+				be32_to_cpu(
+				datacb_data->pkt.fw_data.rec_length));
+				audio->in[audio->fill_next].used =
+				be32_to_cpu(
+					datacb_data->pkt.fw_data.rec_length);
+				audio->in[audio->fill_next].numframes =
+				be32_to_cpu(
+				datacb_data->pkt.fw_data.rec_num_frames);
+				mutex_unlock(&audio->dsp_lock);
+			} else if (datacb_data->pkt.rw_data.rw_ptr_status &&
+			be32_to_cpu(datacb_data->pkt.rw_data.rec_length)) {
+				MM_DBG("Copy RW link:rec_buf_size \
+				=0x%08x, rec_length=0x%08x\n",
+				be32_to_cpu( \
+				datacb_data->pkt.rw_data. \
+				rec_buffer_size_copy),\
+				be32_to_cpu(datacb_data->pkt.rw_data. \
+				rec_length));
+
+				mutex_lock(&audio->dsp_lock);
+				memcpy(audio->in[audio->fill_next].data, \
+				&(datacb_data->pkt.rw_data.data[0]), \
+				be32_to_cpu(
+					datacb_data->pkt.rw_data.rec_length));
+				audio->in[audio->fill_next].used =
+				be32_to_cpu(
+					datacb_data->pkt.rw_data.rec_length);
+				audio->in[audio->fill_next].numframes =
+				be32_to_cpu(
+				datacb_data->pkt.rw_data.rec_num_frames);
+				mutex_unlock(&audio->dsp_lock);
+			}
+			if (rec_status != RPC_VOC_REC_STAT_DONE) {
+				/* Not end of record */
+				bmsg.args.buf = \
+				(uint32_t) audio->in[audio->fill_next].data;
+				bmsg.args.num_bytes = \
+				be32_to_cpu(audio->in[audio->fill_next].size);
+
+				if (++audio->fill_next ==  MAX_REC_BUF_COUNT)
+					audio->fill_next = 0;
+
+				msm_rpc_setup_req(&bmsg.hdr, audio->rpc_prog,
+				audio->rpc_ver, SND_VOC_REC_PUT_BUF_PROC);
+
+				msm_rpc_write(audio->sndept, &bmsg,
+				sizeof(bmsg));
+
+				wake_up(&audio->read_wait);
+			} else {
+				/* Indication record stopped gracefully */
+				MM_DBG("End Of Voice Record\n");
+				wake_up(&audio->wait);
+			}
+		} else if (rec_status == RPC_VOC_REC_STAT_PAUSED) {
+			MM_DBG(" Voice Record PAUSED\n");
+			audio->pause_resume = 1;
+		} else if (rec_status == RPC_VOC_REC_STAT_RESUMED) {
+			MM_DBG(" Voice Record RESUMED\n");
+			audio->pause_resume = 0;
+		} else if ((rec_status == RPC_VOC_REC_STAT_ERROR) ||
+		(rec_status == RPC_VOC_REC_STAT_INVALID_PARAM) ||
+		(rec_status == RPC_VOC_REC_STAT_BUFFER_ERROR))
+			MM_ERR("error recording =0x%8x\n",
+				rec_status);
+		else if (rec_status == RPC_VOC_REC_STAT_INT_TIME)
+			MM_DBG("Frames recorded matches interval \
+					callback time\n");
+		else if (rec_status == RPC_VOC_REC_STAT_AUTO_STOP) {
+			MM_DBG(" Voice Record AUTO STOP\n");
+			mutex_lock(&audio->lock);
+			audio->stopped = 1;
+			wake_up(&audio->read_wait);
+			audmgr_disable(&audio->audmgr);
+			audvoicememo_ioport_reset(audio);
+			audio->stopped = 0;
+			audio->enabled = 0;
+			mutex_unlock(&audio->lock);
+		}
+			break;
+		}
+	default:
+		MM_ERR("UNKNOWN PROC , proc = 0x%8x \n", proc);
+	}
+}
+
+static int voicememo_rpc_thread(void *data)
+{
+	struct audio_voicememo *audio = data;
+	struct rpc_request_hdr *hdr = NULL;
+	uint32_t type;
+	int len;
+
+	MM_DBG("start\n");
+
+	while (!kthread_should_stop()) {
+		kfree(hdr);
+		hdr = NULL;
+
+		len = msm_rpc_read(audio->sndept, (void **) &hdr, -1, -1);
+		MM_DBG("rpc_read len = 0x%x\n", len);
+		if (len < 0) {
+			MM_ERR("rpc read failed (%d)\n", len);
+			break;
+		}
+		if (len < RPC_COMMON_HDR_SZ)
+			continue;
+		type = be32_to_cpu(hdr->type);
+		if (type == RPC_TYPE_REPLY) {
+			struct rpc_reply_hdr *rep = (void *) hdr;
+			uint32_t status;
+			if (len < RPC_REPLY_HDR_SZ)
+				continue;
+			status = be32_to_cpu(rep->reply_stat);
+			if (status == RPCMSG_REPLYSTAT_ACCEPTED) {
+				status =
+				be32_to_cpu(rep->data.acc_hdr.accept_stat);
+
+				/* Confirm major RPC success during open*/
+				if ((audio->enabled == 0) &&
+					(status == RPC_ACCEPTSTAT_SUCCESS) &&
+					(audio->rpc_xid == rep->xid)) {
+						audio->rpc_status = \
+							RPC_STATUS_SUCCESS;
+						wake_up(&audio->wait);
+				}
+				MM_DBG("rpc_reply status 0x%8x\n", status);
+			} else {
+				MM_ERR("rpc_reply denied!\n");
+			}
+			/* process reply */
+			continue;
+		} else if (type == RPC_TYPE_REQUEST) {
+			if (len < RPC_REQUEST_HDR_SZ)
+				continue;
+			process_rpc_request(be32_to_cpu(hdr->procedure),
+						be32_to_cpu(hdr->xid),
+						(void *) (hdr + 1),
+						len - sizeof(*hdr),
+						audio);
+		} else
+			MM_ERR("Unexpected type (%d)\n", type);
+	}
+	MM_DBG("stop\n");
+	kfree(hdr);
+	hdr = NULL;
+
+	return 0;
+}
+
+/* ------------------- device --------------------- */
+static long audio_voicememo_ioctl(struct file *file,
+				unsigned int cmd, unsigned long arg)
+{
+	struct audio_voicememo *audio = file->private_data;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		mutex_lock(&audio->dsp_lock);
+		stats.byte_count = audio->byte_count;
+		stats.sample_count = audio->frame_count;
+		mutex_unlock(&audio->dsp_lock);
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START: {
+			MM_DBG("AUDIO_START\n");
+			audio->byte_count = 0;
+			audio->frame_count = 0;
+			if (audio->voicememo_cfg.rec_type != RPC_VOC_REC_NONE)
+				rc = audvoicememo_enable(audio);
+			else
+				rc = -EINVAL;
+			MM_DBG("AUDIO_START rc %d\n", rc);
+			break;
+		}
+	case AUDIO_STOP: {
+			MM_DBG("AUDIO_STOP\n");
+			rc = audvoicememo_disable(audio);
+			audvoicememo_ioport_reset(audio);
+			audio->stopped = 0;
+			MM_DBG("AUDIO_STOP rc %d\n", rc);
+			break;
+		}
+	case AUDIO_GET_CONFIG: {
+			struct msm_audio_config cfg;
+			MM_DBG("AUDIO_GET_CONFIG\n");
+			cfg.buffer_size = audio->rec_buf_size;
+			cfg.buffer_count = MAX_REC_BUF_COUNT;
+			cfg.sample_rate = 8000; /* Voice Encoder works on 8k,
+						 * Mono */
+			cfg.channel_count = 1;
+			cfg.type = 0;
+			cfg.unused[0] = 0;
+			cfg.unused[1] = 0;
+			cfg.unused[2] = 0;
+			if (copy_to_user((void *) arg, &cfg, sizeof(cfg)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			MM_DBG("AUDIO_GET_CONFIG rc %d\n", rc);
+			break;
+		}
+	case AUDIO_GET_VOICEMEMO_CONFIG: {
+			MM_DBG("AUDIO_GET_VOICEMEMO_CONFIG\n");
+			if (copy_to_user((void *)arg, &audio->voicememo_cfg,
+				sizeof(audio->voicememo_cfg)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			MM_DBG("AUDIO_GET_VOICEMEMO_CONFIG rc %d\n", rc);
+			break;
+		}
+	case AUDIO_SET_VOICEMEMO_CONFIG: {
+			struct msm_audio_voicememo_config usr_config;
+			MM_DBG("AUDIO_SET_VOICEMEMO_CONFIG\n");
+			if (copy_from_user
+				(&usr_config, (void *)arg,
+				sizeof(usr_config))) {
+				rc = -EFAULT;
+				break;
+			}
+			if (audvoicememo_validate_usr_config(&usr_config)
+					== 0) {
+				audio->voicememo_cfg = usr_config;
+				rc = 0;
+			} else
+				rc = -EINVAL;
+			MM_DBG("AUDIO_SET_VOICEMEMO_CONFIG rc %d\n", rc);
+			break;
+		}
+	case AUDIO_PAUSE: {
+			struct rpc_request_hdr rhdr;
+			MM_DBG("AUDIO_PAUSE\n");
+			if (arg == 1)
+				msm_rpc_setup_req(&rhdr, audio->rpc_prog,
+				audio->rpc_ver, SND_VOC_REC_PAUSE_PROC);
+			else
+				msm_rpc_setup_req(&rhdr, audio->rpc_prog,
+				audio->rpc_ver, SND_VOC_REC_RESUME_PROC);
+
+			rc = msm_rpc_write(audio->sndept, &rhdr, sizeof(rhdr));
+			MM_DBG("AUDIO_PAUSE exit %d\n",	rc);
+			break;
+		}
+	default:
+		MM_ERR("IOCTL %d not supported\n", cmd);
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static ssize_t audio_voicememo_read(struct file *file,
+				char __user *buf,
+				size_t count, loff_t *pos)
+{
+	struct audio_voicememo *audio = file->private_data;
+	const char __user *start = buf;
+	int rc = 0;
+
+	mutex_lock(&audio->read_lock);
+
+	MM_DBG("buff read =0x%8x \n", count);
+
+	while (count > 0) {
+		rc = wait_event_interruptible_timeout(audio->read_wait,
+			(audio->in[audio->read_next].used > 0) ||
+			(audio->stopped),
+			msecs_to_jiffies(MSM_AUD_BUFFER_UPDATE_WAIT_MS));
+
+		if (rc == 0) {
+			rc = -ETIMEDOUT;
+			break;
+		} else if (rc < 0)
+			break;
+
+		if (audio->stopped) {
+			rc = -EBUSY;
+			break;
+		}
+		if (count < audio->in[audio->read_next].used) {
+			/* Read must happen in frame boundary. Since driver does
+			 * not split frames, read count must be greater or
+			 * equal to size of existing frames to copy
+			 */
+			MM_DBG("read not in frame boundary\n");
+			break;
+		} else {
+			mutex_lock(&audio->dsp_lock);
+			dma_coherent_post_ops();
+			if (copy_to_user
+				(buf, audio->in[audio->read_next].data,
+				audio->in[audio->read_next].used)) {
+				MM_ERR("invalid addr %x \n", (unsigned int)buf);
+				rc = -EFAULT;
+				mutex_unlock(&audio->dsp_lock);
+				break;
+			}
+			count -= audio->in[audio->read_next].used;
+			audio->byte_count += audio->in[audio->read_next].used;
+			audio->frame_count +=
+			audio->in[audio->read_next].numframes;
+			buf += audio->in[audio->read_next].used;
+			audio->in[audio->read_next].used = 0;
+			mutex_unlock(&audio->dsp_lock);
+			if ((++audio->read_next) == MAX_REC_BUF_COUNT)
+				audio->read_next = 0;
+			if (audio->in[audio->read_next].used == 0)
+				break;  /* No data ready at this moment
+					 * Exit while loop to prevent
+					 * output thread sleep too long
+					 */
+		}
+	}
+	mutex_unlock(&audio->read_lock);
+	if (buf > start)
+		rc = buf - start;
+	MM_DBG("exit return =0x%8x\n", rc);
+	return rc;
+}
+
+static ssize_t audio_voicememo_write(struct file *file,
+				const char __user *buf,
+				size_t count, loff_t *pos)
+{
+	return -EINVAL;
+}
+
+static int audio_voicememo_release(struct inode *inode, struct file *file)
+{
+	struct audio_voicememo *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	audvoicememo_disable(audio);
+	audvoicememo_flush_buf(audio);
+	audio->opened = 0;
+	mutex_unlock(&audio->lock);
+	return 0;
+}
+
+static int audio_voicememo_open(struct inode *inode, struct file *file)
+{
+	struct audio_voicememo *audio = &the_audio_voicememo;
+	int rc;
+
+	mutex_lock(&audio->lock);
+	if (audio->opened) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	rc = audmgr_open(&audio->audmgr);
+
+	if (rc)
+		goto done;
+
+	/*Set default param to None*/
+	memset(&audio->voicememo_cfg, 0, sizeof(audio->voicememo_cfg));
+
+	file->private_data = audio;
+	audio->opened = 1;
+	audio->stopped = 0;
+	rc = 0;
+done:
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static const struct file_operations audio_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audio_voicememo_open,
+	.release	= audio_voicememo_release,
+	.read		= audio_voicememo_read,
+	.write		= audio_voicememo_write,
+	.unlocked_ioctl	= audio_voicememo_ioctl,
+};
+
+struct miscdevice audio_voicememo_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_voicememo",
+	.fops	= &audio_fops,
+};
+
+static int audio_voicememo_probe(struct platform_device *pdev)
+{
+	int rc;
+
+	if ((pdev->id != (SND_VERS_COMP & RPC_VERSION_MAJOR_MASK)) &&
+	    (pdev->id != (SND_VERS2_COMP & RPC_VERSION_MAJOR_MASK)))
+		return -EINVAL;
+
+	mutex_init(&the_audio_voicememo.lock);
+	mutex_init(&the_audio_voicememo.read_lock);
+	mutex_init(&the_audio_voicememo.dsp_lock);
+	init_waitqueue_head(&the_audio_voicememo.read_wait);
+	init_waitqueue_head(&the_audio_voicememo.wait);
+
+	the_audio_voicememo.rec_buf_ptr = dma_alloc_coherent(NULL,
+					MAX_VOICEMEMO_BUF_SIZE,
+					&the_audio_voicememo.phys, GFP_KERNEL);
+	if (the_audio_voicememo.rec_buf_ptr == NULL) {
+		MM_ERR("error allocating memory\n");
+		rc = -ENOMEM;
+		return rc;
+	}
+	the_audio_voicememo.rec_buf_size = MAX_REC_BUF_SIZE;
+	MM_DBG("rec_buf_ptr = 0x%8x, phys = 0x%8x \n",
+		(uint32_t) the_audio_voicememo.rec_buf_ptr, \
+		the_audio_voicememo.phys);
+
+	the_audio_voicememo.sndept = msm_rpc_connect_compatible(SND_PROG,
+					SND_VERS_COMP, MSM_RPC_UNINTERRUPTIBLE);
+	if (IS_ERR(the_audio_voicememo.sndept)) {
+		MM_DBG("connect failed with VERS \
+				= %x, trying again with another API\n",
+				SND_VERS_COMP);
+		the_audio_voicememo.sndept = msm_rpc_connect_compatible(
+					SND_PROG, SND_VERS2_COMP,
+					MSM_RPC_UNINTERRUPTIBLE);
+		if (IS_ERR(the_audio_voicememo.sndept)) {
+			rc = PTR_ERR(the_audio_voicememo.sndept);
+			the_audio_voicememo.sndept = NULL;
+			MM_ERR("Failed to connect to snd svc\n");
+			goto err;
+		}
+		the_audio_voicememo.rpc_ver = SND_VERS2_COMP;
+	} else
+		the_audio_voicememo.rpc_ver = SND_VERS_COMP;
+
+	the_audio_voicememo.task = kthread_run(voicememo_rpc_thread,
+					&the_audio_voicememo, "voicememo_rpc");
+	if (IS_ERR(the_audio_voicememo.task)) {
+		rc = PTR_ERR(the_audio_voicememo.task);
+		the_audio_voicememo.task = NULL;
+		msm_rpc_close(the_audio_voicememo.sndept);
+		the_audio_voicememo.sndept = NULL;
+		MM_ERR("Failed to create voicememo_rpc task\n");
+		goto err;
+	}
+	the_audio_voicememo.rpc_prog = SND_PROG;
+
+	return misc_register(&audio_voicememo_misc);
+err:
+	dma_free_coherent(NULL, MAX_VOICEMEMO_BUF_SIZE,
+		the_audio_voicememo.rec_buf_ptr,
+		the_audio_voicememo.phys);
+	the_audio_voicememo.rec_buf_ptr = NULL;
+	return rc;
+}
+
+static void __exit audio_voicememo_exit(void)
+{
+	/* Close the RPC connection to make thread to comeout */
+	msm_rpc_close(the_audio_voicememo.sndept);
+	the_audio_voicememo.sndept = NULL;
+	kthread_stop(the_audio_voicememo.task);
+	the_audio_voicememo.task = NULL;
+	if (the_audio_voicememo.rec_buf_ptr)
+		dma_free_coherent(NULL, MAX_VOICEMEMO_BUF_SIZE,
+			the_audio_voicememo.rec_buf_ptr,
+			the_audio_voicememo.phys);
+	the_audio_voicememo.rec_buf_ptr = NULL;
+	misc_deregister(&audio_voicememo_misc);
+}
+
+static char audio_voicememo_rpc_name[] = "rs00000000";
+
+static struct platform_driver audio_voicememo_driver = {
+	.probe = audio_voicememo_probe,
+	.driver = {
+		.owner = THIS_MODULE,
+	},
+ };
+
+static int __init audio_voicememo_init(void)
+{
+	snprintf(audio_voicememo_rpc_name, sizeof(audio_voicememo_rpc_name),
+			"rs%08x", SND_PROG);
+	audio_voicememo_driver.driver.name = audio_voicememo_rpc_name;
+	return platform_driver_register(&audio_voicememo_driver);
+}
+
+module_init(audio_voicememo_init);
+module_exit(audio_voicememo_exit);
+
+MODULE_DESCRIPTION("MSM Voice Memo driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("QUALCOMM");
diff --git a/arch/arm/mach-msm/qdsp5/audio_wma.c b/arch/arm/mach-msm/qdsp5/audio_wma.c
new file mode 100644
index 0000000..162a6f1
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_wma.c
@@ -0,0 +1,1779 @@
+/* audio_wma.c - wma audio decoder driver
+ *
+ * Copyright (c) 2009, 2011-2012, Code Aurora Forum. All rights reserved.
+ *
+ * Based on the mp3 native driver in arch/arm/mach-msm/qdsp5/audio_mp3.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/earlysuspend.h>
+#include <linux/android_pmem.h>
+#include <linux/slab.h>
+#include <linux/msm_audio.h>
+#include <linux/msm_audio_wma.h>
+#include <linux/memory_alloc.h>
+
+#include <mach/msm_adsp.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audplaycmdi.h>
+#include <mach/qdsp5/qdsp5audplaymsg.h>
+#include <mach/qdsp5/qdsp5rmtcmdi.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_memtypes.h>
+
+#include "audmgr.h"
+
+/* Size must be power of 2 */
+#define BUFSZ_MAX 	2062	/* Includes meta in size */
+#define BUFSZ_MIN 	1038	/* Includes meta in size */
+#define DMASZ_MAX 	(BUFSZ_MAX * 2)
+#define DMASZ_MIN 	(BUFSZ_MIN * 2)
+
+#define AUDPLAY_INVALID_READ_PTR_OFFSET	0xFFFF
+#define AUDDEC_DEC_WMA 4
+
+#define PCM_BUFSZ_MIN 	8216 	/* Hold one stereo WMA frame and meta out*/
+#define PCM_BUF_MAX_COUNT 5	/* DSP only accepts 5 buffers at most
+				   but support 2 buffers currently */
+#define ROUTING_MODE_FTRT 1
+#define ROUTING_MODE_RT 2
+/* Decoder status received from AUDPPTASK */
+#define  AUDPP_DEC_STATUS_SLEEP	0
+#define	 AUDPP_DEC_STATUS_INIT  1
+#define  AUDPP_DEC_STATUS_CFG   2
+#define  AUDPP_DEC_STATUS_PLAY  3
+
+#define AUDWMA_METAFIELD_MASK 0xFFFF0000
+#define AUDWMA_EOS_FLG_OFFSET 0x0A /* Offset from beginning of buffer */
+#define AUDWMA_EOS_FLG_MASK 0x01
+#define AUDWMA_EOS_NONE 0x0 /* No EOS detected */
+#define AUDWMA_EOS_SET 0x1 /* EOS set in meta field */
+
+#define AUDWMA_EVENT_NUM 10 /* Default number of pre-allocated event packets */
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+	unsigned short mfield_sz; /*only useful for data has meta field */
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct audwma_suspend_ctl {
+	struct early_suspend node;
+	struct audio *audio;
+};
+#endif
+
+struct audwma_event{
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+
+struct audio {
+	struct buffer out[2];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed; /* number of buffers the dsp is waiting for */
+	unsigned out_dma_sz;
+
+	atomic_t out_bytes;
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	/* Host PCM section */
+	struct buffer in[PCM_BUF_MAX_COUNT];
+	struct mutex read_lock;
+	wait_queue_head_t read_wait;	/* Wait queue for read */
+	char *read_data;	/* pointer to reader buffer */
+	int32_t read_phys;	/* physical address of reader buffer */
+	uint8_t read_next;	/* index to input buffers to be read next */
+	uint8_t fill_next;	/* index to buffer that DSP should be filling */
+	uint8_t pcm_buf_count;	/* number of pcm buffer allocated */
+	/* ---- End of Host PCM section */
+
+	struct msm_adsp_module *audplay;
+
+	/* configuration to use on next enable */
+	uint32_t out_sample_rate;
+	uint32_t out_channel_mode;
+
+	struct msm_audio_wma_config wma_config;
+	struct audmgr audmgr;
+
+	/* data allocated for various buffers */
+	char *data;
+	int32_t phys; /* physical address of write buffer */
+	void *map_v_read;
+	void *map_v_write;
+
+	int mfield; /* meta field embedded in data */
+	int rflush; /* Read  flush */
+	int wflush; /* Write flush */
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+	int pcm_feedback;
+	int buf_refresh;
+	int rmt_resource_released;
+	int teos; /* valid only if tunnel mode & no data left for decoder */
+	enum msm_aud_decoder_state dec_state;	/* Represents decoder state */
+	int reserved; /* A byte is being reserved */
+	char rsv_byte; /* Handle odd length user data */
+
+	const char *module_name;
+	unsigned queue_id;
+	uint16_t dec_id;
+	uint32_t read_ptr_offset;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct audwma_suspend_ctl suspend_ctl;
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+
+	wait_queue_head_t wait;
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	wait_queue_head_t event_wait;
+	spinlock_t event_queue_lock;
+	struct mutex get_event_lock;
+	int event_abort;
+
+	int eq_enable;
+	int eq_needs_commit;
+	audpp_cmd_cfg_object_params_eqalizer eq;
+	audpp_cmd_cfg_object_params_volume vol_pan;
+};
+
+static int auddec_dsp_config(struct audio *audio, int enable);
+static void audpp_cmd_cfg_adec_params(struct audio *audio);
+static void audpp_cmd_cfg_routing_mode(struct audio *audio);
+static void audplay_send_data(struct audio *audio, unsigned needed);
+static void audplay_config_hostpcm(struct audio *audio);
+static void audplay_buffer_refresh(struct audio *audio);
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audwma_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload);
+#endif
+
+static int rmt_put_resource(struct audio *audio)
+{
+	struct aud_codec_config_cmd cmd;
+	unsigned short client_idx;
+
+	cmd.cmd_id = RM_CMD_AUD_CODEC_CFG;
+	cmd.client_id = RM_AUD_CLIENT_ID;
+	cmd.task_id = audio->dec_id;
+	cmd.enable = RMT_DISABLE;
+	cmd.dec_type = AUDDEC_DEC_WMA;
+	client_idx = ((cmd.client_id << 8) | cmd.task_id);
+
+	return put_adsp_resource(client_idx, &cmd, sizeof(cmd));
+}
+
+static int rmt_get_resource(struct audio *audio)
+{
+	struct aud_codec_config_cmd cmd;
+	unsigned short client_idx;
+
+	cmd.cmd_id = RM_CMD_AUD_CODEC_CFG;
+	cmd.client_id = RM_AUD_CLIENT_ID;
+	cmd.task_id = audio->dec_id;
+	cmd.enable = RMT_ENABLE;
+	cmd.dec_type = AUDDEC_DEC_WMA;
+	client_idx = ((cmd.client_id << 8) | cmd.task_id);
+
+	return get_adsp_resource(client_idx, &cmd, sizeof(cmd));
+}
+
+/* must be called with audio->lock held */
+static int audio_enable(struct audio *audio)
+{
+	struct audmgr_config cfg;
+	int rc;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled)
+		return 0;
+
+	if (audio->rmt_resource_released == 1) {
+		audio->rmt_resource_released = 0;
+		rc = rmt_get_resource(audio);
+		if (rc) {
+			MM_ERR("ADSP resources are not available for WMA \
+				session 0x%08x on decoder: %d\n Ignoring \
+				error and going ahead with the playback\n",
+				(int)audio, audio->dec_id);
+		}
+	}
+
+	audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
+		cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+		cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;
+		cfg.def_method = RPC_AUD_DEF_METHOD_PLAYBACK;
+		cfg.codec = RPC_AUD_DEF_CODEC_WMA;
+		cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+		rc = audmgr_enable(&audio->audmgr, &cfg);
+		if (rc < 0)
+			return rc;
+	}
+
+	if (msm_adsp_enable(audio->audplay)) {
+		MM_ERR("msm_adsp_enable(audplay) failed\n");
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+
+	if (audpp_enable(audio->dec_id, audio_dsp_event, audio)) {
+		MM_ERR("audpp_enable() failed\n");
+		msm_adsp_disable(audio->audplay);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+
+	audio->enabled = 1;
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audio_disable(struct audio *audio)
+{
+	int rc = 0;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+		auddec_dsp_config(audio, 0);
+		rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+		else if (audio->dec_state != MSM_AUD_DECODER_STATE_CLOSE)
+			rc = -EFAULT;
+		else
+			rc = 0;
+		audio->stopped = 1;
+		wake_up(&audio->write_wait);
+		wake_up(&audio->read_wait);
+		msm_adsp_disable(audio->audplay);
+		audpp_disable(audio->dec_id, audio);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_disable(&audio->audmgr);
+		audio->out_needed = 0;
+		rmt_put_resource(audio);
+		audio->rmt_resource_released = 1;
+	}
+	return rc;
+}
+
+/* ------------------- dsp --------------------- */
+static void audio_update_pcm_buf_entry(struct audio *audio,
+	uint32_t *payload)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	if (audio->rflush)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < payload[1]; index++) {
+		if (audio->in[audio->fill_next].addr ==
+			payload[2 + index * 2]) {
+			MM_DBG("audio_update_pcm_buf_entry: \
+				in[%d] ready\n", audio->fill_next);
+			audio->in[audio->fill_next].used =
+			payload[3 + index * 2];
+			if ((++audio->fill_next) == audio->pcm_buf_count)
+				audio->fill_next = 0;
+		} else {
+			MM_ERR("audio_update_pcm_buf_entry: \
+				expected=%x ret=%x\n",
+				audio->in[audio->fill_next].addr,
+				payload[1 + index * 2]);
+			break;
+		}
+	}
+	if (audio->in[audio->fill_next].used == 0) {
+		audplay_buffer_refresh(audio);
+	} else {
+		MM_DBG("read cannot keep up\n");
+		audio->buf_refresh = 1;
+	}
+	wake_up(&audio->read_wait);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static void audplay_dsp_event(void *data, unsigned id, size_t len,
+			      void (*getevent) (void *ptr, size_t len))
+{
+	struct audio *audio = data;
+	uint32_t msg[28];
+
+	getevent(msg, sizeof(msg));
+
+	MM_DBG("msg_id=%x\n", id);
+
+	switch (id) {
+	case AUDPLAY_MSG_DEC_NEEDS_DATA:
+		audplay_send_data(audio, 1);
+		break;
+
+	case AUDPLAY_MSG_BUFFER_UPDATE:
+		audio_update_pcm_buf_entry(audio, msg);
+		break;
+
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audplaytask)\n");
+		break;
+
+	default:
+		MM_ERR("unexpected message from decoder \n");
+		break;
+	}
+}
+
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned status = msg[1];
+
+			switch (status) {
+			case AUDPP_DEC_STATUS_SLEEP: {
+				uint16_t reason = msg[2];
+				MM_DBG("decoder status:sleep reason = \
+						0x%04x\n", reason);
+				if ((reason == AUDPP_MSG_REASON_MEM)
+					|| (reason ==
+					AUDPP_MSG_REASON_NODECODER)) {
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_FAILURE;
+					wake_up(&audio->wait);
+				} else if (reason == AUDPP_MSG_REASON_NONE) {
+					/* decoder is in disable state */
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_CLOSE;
+					wake_up(&audio->wait);
+				}
+				break;
+			}
+			case AUDPP_DEC_STATUS_INIT:
+				MM_DBG("decoder status: init\n");
+				if (audio->pcm_feedback)
+					audpp_cmd_cfg_routing_mode(audio);
+				else
+					audpp_cmd_cfg_adec_params(audio);
+				break;
+
+			case AUDPP_DEC_STATUS_CFG:
+				MM_DBG("decoder status: cfg\n");
+				break;
+			case AUDPP_DEC_STATUS_PLAY:
+				MM_DBG("decoder status: play\n");
+				if (audio->pcm_feedback) {
+					audplay_config_hostpcm(audio);
+					audplay_buffer_refresh(audio);
+				}
+				audio->dec_state =
+					MSM_AUD_DECODER_STATE_SUCCESS;
+				wake_up(&audio->wait);
+				break;
+			default:
+				MM_ERR("unknown decoder status\n");
+			}
+			break;
+		}
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			MM_DBG("CFG_MSG ENABLE\n");
+			auddec_dsp_config(audio, 1);
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+			audpp_dsp_set_eq(audio->dec_id,	audio->eq_enable,
+								&audio->eq);
+			audpp_avsync(audio->dec_id, 22050);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			MM_DBG("CFG_MSG DISABLE\n");
+			audpp_avsync(audio->dec_id, 0);
+			audio->running = 0;
+		} else {
+			MM_DBG("CFG_MSG %d?\n", msg[0]);
+		}
+		break;
+	case AUDPP_MSG_ROUTING_ACK:
+		MM_DBG("ROUTING_ACK mode=%d\n", msg[1]);
+		audpp_cmd_cfg_adec_params(audio);
+		break;
+
+	case AUDPP_MSG_FLUSH_ACK:
+		MM_DBG("FLUSH_ACK\n");
+		audio->wflush = 0;
+		audio->rflush = 0;
+		wake_up(&audio->write_wait);
+		if (audio->pcm_feedback)
+			audplay_buffer_refresh(audio);
+		break;
+	case AUDPP_MSG_PCMDMAMISSED:
+		MM_DBG("PCMDMAMISSED\n");
+		audio->teos = 1;
+		wake_up(&audio->write_wait);
+		break;
+
+	default:
+		MM_ERR("UNKNOWN (%d)\n", id);
+	}
+
+}
+
+static struct msm_adsp_ops audplay_adsp_ops_wma = {
+	.event = audplay_dsp_event,
+};
+
+#define audplay_send_queue0(audio, cmd, len) \
+	msm_adsp_write(audio->audplay, audio->queue_id, \
+			cmd, len)
+
+static int auddec_dsp_config(struct audio *audio, int enable)
+{
+	u16 cfg_dec_cmd[AUDPP_CMD_CFG_DEC_TYPE_LEN / sizeof(unsigned short)];
+
+	memset(cfg_dec_cmd, 0, sizeof(cfg_dec_cmd));
+	cfg_dec_cmd[0] = AUDPP_CMD_CFG_DEC_TYPE;
+	if (enable)
+		cfg_dec_cmd[1 + audio->dec_id] = AUDPP_CMD_UPDATDE_CFG_DEC |
+			AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_WMA;
+	else
+		cfg_dec_cmd[1 + audio->dec_id] = AUDPP_CMD_UPDATDE_CFG_DEC |
+			AUDPP_CMD_DIS_DEC_V;
+
+	return audpp_send_queue1(&cfg_dec_cmd, sizeof(cfg_dec_cmd));
+}
+
+static void audpp_cmd_cfg_adec_params(struct audio *audio)
+{
+	struct audpp_cmd_cfg_adec_params_wma cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_WMA_LEN;
+	cmd.common.dec_id = audio->dec_id;
+	cmd.common.input_sampling_frequency = audio->out_sample_rate;
+
+	/*
+	 * Test done for sample with the following configuration
+	 * armdatareqthr 	= 1262
+	 * channelsdecoded 	= 1(MONO)/2(STEREO)
+	 * wmabytespersec 	= Tested with 6003 Bytes per sec
+	 * wmasamplingfreq	= 44100
+	 * wmaencoderopts	= 31
+	 */
+
+	cmd.armdatareqthr = audio->wma_config.armdatareqthr;
+	cmd.channelsdecoded = audio->wma_config.channelsdecoded;
+	cmd.wmabytespersec = audio->wma_config.wmabytespersec;
+	cmd.wmasamplingfreq = audio->wma_config.wmasamplingfreq;
+	cmd.wmaencoderopts = audio->wma_config.wmaencoderopts;
+
+	audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static void audpp_cmd_cfg_routing_mode(struct audio *audio)
+{
+	struct audpp_cmd_routing_mode cmd;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_ROUTING_MODE;
+	cmd.object_number = audio->dec_id;
+	if (audio->pcm_feedback)
+		cmd.routing_mode = ROUTING_MODE_FTRT;
+	else
+		cmd.routing_mode = ROUTING_MODE_RT;
+
+	audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static void audplay_buffer_refresh(struct audio *audio)
+{
+	struct audplay_cmd_buffer_refresh refresh_cmd;
+
+	refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH;
+	refresh_cmd.num_buffers = 1;
+	refresh_cmd.buf0_address = audio->in[audio->fill_next].addr;
+	refresh_cmd.buf0_length = audio->in[audio->fill_next].size;
+	refresh_cmd.buf_read_count = 0;
+
+	MM_DBG("buf0_addr=%x buf0_len=%d\n",
+			refresh_cmd.buf0_address,
+			refresh_cmd.buf0_length);
+
+	(void)audplay_send_queue0(audio, &refresh_cmd, sizeof(refresh_cmd));
+}
+
+static void audplay_config_hostpcm(struct audio *audio)
+{
+	struct audplay_cmd_hpcm_buf_cfg cfg_cmd;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	cfg_cmd.cmd_id = AUDPLAY_CMD_HPCM_BUF_CFG;
+	cfg_cmd.max_buffers = audio->pcm_buf_count;
+	cfg_cmd.byte_swap = 0;
+	cfg_cmd.hostpcm_config = (0x8000) | (0x4000);
+	cfg_cmd.feedback_frequency = 1;
+	cfg_cmd.partition_number = 0;
+
+	(void)audplay_send_queue0(audio, &cfg_cmd, sizeof(cfg_cmd));
+}
+
+
+static int audplay_dsp_send_data_avail(struct audio *audio,
+					unsigned idx, unsigned len)
+{
+	struct audplay_cmd_bitstream_data_avail_nt2 cmd;
+
+	cmd.cmd_id		= AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_NT2;
+	if (audio->mfield)
+		cmd.decoder_id = AUDWMA_METAFIELD_MASK |
+			(audio->out[idx].mfield_sz >> 1);
+	else
+		cmd.decoder_id		= audio->dec_id;
+	cmd.buf_ptr		= audio->out[idx].addr;
+	cmd.buf_size		= len/2;
+	cmd.partition_number	= 0;
+	/* complete writes to the input buffer */
+	wmb();
+	return audplay_send_queue0(audio, &cmd, sizeof(cmd));
+}
+
+static void audplay_send_data(struct audio *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (audio->wflush) {
+		audio->out_needed = 1;
+		goto done;
+	}
+
+	if (needed && !audio->wflush) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			MM_DBG("frame %d free\n", audio->out_tail);
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		MM_DBG("\n"); /* Macro prints the file name and function */
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+			MM_DBG("frame %d busy\n", audio->out_tail);
+			audplay_dsp_send_data_avail(audio, audio->out_tail,
+								frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+
+static void audio_flush(struct audio *audio)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->out[0].used = 0;
+	audio->out[1].used = 0;
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->reserved = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	atomic_set(&audio->out_bytes, 0);
+}
+
+static void audio_flush_pcm_buf(struct audio *audio)
+{
+	uint8_t index;
+
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
+		audio->in[index].used = 0;
+	audio->buf_refresh = 0;
+	audio->read_next = 0;
+	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static void audio_ioport_reset(struct audio *audio)
+{
+	/* Make sure read/write thread are free from
+	 * sleep and knowing that system is not able
+	 * to process io request at the moment
+	 */
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audio_flush(audio);
+	mutex_unlock(&audio->write_lock);
+	wake_up(&audio->read_wait);
+	mutex_lock(&audio->read_lock);
+	audio_flush_pcm_buf(audio);
+	mutex_unlock(&audio->read_lock);
+}
+
+static int audwma_events_pending(struct audio *audio)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	return empty || audio->event_abort;
+}
+
+static void audwma_reset_event_queue(struct audio *audio)
+{
+	unsigned long flags;
+	struct audwma_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audwma_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+				struct audwma_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	return;
+}
+
+static long audwma_process_event_req(struct audio *audio, void __user *arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audwma_event *drv_evt = NULL;
+	int timeout;
+	unsigned long flags;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int) usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(
+				audio->event_wait, audwma_events_pending(audio),
+				msecs_to_jiffies(timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(
+			audio->event_wait, audwma_events_pending(audio));
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	rc = 0;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audwma_event, list);
+		list_del(&drv_evt->list);
+	}
+
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else
+		rc = -1;
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	if (!rc && copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audio_enable_eq(struct audio *audio, int enable)
+{
+	if (audio->eq_enable == enable && !audio->eq_needs_commit)
+		return 0;
+
+	audio->eq_enable = enable;
+
+	if (audio->running) {
+		audpp_dsp_set_eq(audio->dec_id, enable, &audio->eq);
+		audio->eq_needs_commit = 0;
+	}
+	return 0;
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = -EINVAL;
+	unsigned long flags = 0;
+	uint16_t enable_mask;
+	int enable;
+	int prev_state;
+
+	MM_DBG("cmd = %d\n", cmd);
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = audpp_avsync_byte_count(audio->dec_id);
+		stats.sample_count = audpp_avsync_sample_count(audio->dec_id);
+		if (copy_to_user((void *)arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	switch (cmd) {
+	case AUDIO_ENABLE_AUDPP:
+		if (copy_from_user(&enable_mask, (void *) arg,
+						sizeof(enable_mask))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		enable = (enable_mask & EQ_ENABLE) ? 1 : 0;
+		audio_enable_eq(audio, enable);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+	case AUDIO_SET_VOLUME:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.volume = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_PAN:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.pan = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_EQ:
+		prev_state = audio->eq_enable;
+		audio->eq_enable = 0;
+		if (copy_from_user(&audio->eq.num_bands, (void *) arg,
+				sizeof(audio->eq) -
+				(AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2))) {
+			rc = -EFAULT;
+			break;
+		}
+		audio->eq_enable = prev_state;
+		audio->eq_needs_commit = 1;
+		rc = 0;
+		break;
+	}
+
+	if (-EINVAL != rc)
+		return rc;
+
+	if (cmd == AUDIO_GET_EVENT) {
+		MM_DBG("AUDIO_GET_EVENT\n");
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audwma_process_event_req(audio,
+					(void __user *) arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		return rc;
+	}
+
+	if (cmd == AUDIO_ABORT_GET_EVENT) {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		MM_DBG("AUDIO_START\n");
+		rc = audio_enable(audio);
+		if (!rc) {
+			rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+			MM_INFO("dec_state %d rc = %d\n", audio->dec_state, rc);
+
+			if (audio->dec_state != MSM_AUD_DECODER_STATE_SUCCESS)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		break;
+	case AUDIO_STOP:
+		MM_DBG("AUDIO_STOP\n");
+		rc = audio_disable(audio);
+		audio_ioport_reset(audio);
+		audio->stopped = 0;
+		break;
+	case AUDIO_FLUSH:
+		MM_DBG("AUDIO_FLUSH\n");
+		audio->rflush = 1;
+		audio->wflush = 1;
+		audio_ioport_reset(audio);
+		if (audio->running) {
+			audpp_flush(audio->dec_id);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		break;
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (copy_from_user(&config, (void *) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (config.channel_count == 1) {
+			config.channel_count = AUDPP_CMD_PCM_INTF_MONO_V;
+		} else if (config.channel_count == 2) {
+			config.channel_count = AUDPP_CMD_PCM_INTF_STEREO_V;
+		} else {
+			rc = -EINVAL;
+			break;
+		}
+		audio->mfield = config.meta_field;
+		audio->out_sample_rate = config.sample_rate;
+		audio->out_channel_mode = config.channel_count;
+		rc = 0;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_size = (audio->out_dma_sz >> 1);
+		config.buffer_count = 2;
+		config.sample_rate = audio->out_sample_rate;
+		if (audio->out_channel_mode == AUDPP_CMD_PCM_INTF_MONO_V)
+			config.channel_count = 1;
+		else
+			config.channel_count = 2;
+		config.meta_field = 0;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void *) arg, &config, sizeof(config)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+
+		break;
+	}
+	case AUDIO_GET_WMA_CONFIG:{
+			if (copy_to_user((void *)arg, &audio->wma_config,
+				sizeof(audio->wma_config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_SET_WMA_CONFIG:{
+		struct msm_audio_wma_config usr_config;
+
+		if (copy_from_user
+			(&usr_config, (void *)arg,
+			sizeof(usr_config))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		audio->wma_config = usr_config;
+		rc = 0;
+		break;
+	}
+	case AUDIO_GET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			config.pcm_feedback = audio->pcm_feedback;
+			config.buffer_count = PCM_BUF_MAX_COUNT;
+			config.buffer_size = PCM_BUFSZ_MIN;
+			if (copy_to_user((void *)arg, &config,
+					 sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_SET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			if (copy_from_user
+			    (&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+			if (config.pcm_feedback != audio->pcm_feedback) {
+				MM_ERR("Not sufficient permission to"
+					 "change the playback mode\n");
+				rc = -EACCES;
+				break;
+			}
+			if ((config.buffer_count > PCM_BUF_MAX_COUNT) ||
+			    (config.buffer_count == 1))
+				config.buffer_count = PCM_BUF_MAX_COUNT;
+
+			if (config.buffer_size < PCM_BUFSZ_MIN)
+				config.buffer_size = PCM_BUFSZ_MIN;
+
+			/* Check if pcm feedback is required */
+			if ((config.pcm_feedback) && (!audio->read_data)) {
+				MM_DBG("allocate PCM buffer %d\n",
+						config.buffer_count *
+						config.buffer_size);
+				audio->read_phys =
+						allocate_contiguous_ebi_nomap(
+							config.buffer_size *
+							config.buffer_count,
+							SZ_4K);
+				if (!audio->read_phys) {
+					rc = -ENOMEM;
+					break;
+				}
+				audio->map_v_read = ioremap(
+						audio->read_phys,
+						config.buffer_size *
+						config.buffer_count);
+				if (IS_ERR(audio->map_v_read)) {
+					MM_ERR("map of read buf failed\n");
+					rc = -ENOMEM;
+					free_contiguous_memory_by_paddr(
+							audio->read_phys);
+				} else {
+					uint8_t index;
+					uint32_t offset = 0;
+					audio->read_data =
+						audio->map_v_read;
+					audio->buf_refresh = 0;
+					audio->pcm_buf_count =
+					    config.buffer_count;
+					audio->read_next = 0;
+					audio->fill_next = 0;
+
+					for (index = 0;
+					     index < config.buffer_count;
+					     index++) {
+						audio->in[index].data =
+						    audio->read_data + offset;
+						audio->in[index].addr =
+						    audio->read_phys + offset;
+						audio->in[index].size =
+						    config.buffer_size;
+						audio->in[index].used = 0;
+						offset += config.buffer_size;
+					}
+					MM_DBG("read buf: phy addr \
+						0x%08x kernel addr 0x%08x\n",
+						audio->read_phys,
+						(int)audio->read_data);
+					rc = 0;
+				}
+			} else {
+				rc = 0;
+			}
+			break;
+		}
+	case AUDIO_PAUSE:
+		MM_DBG("AUDIO_PAUSE %ld\n", arg);
+		rc = audpp_pause(audio->dec_id, (int) arg);
+		break;
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+/* Only useful in tunnel-mode */
+static int audio_fsync(struct file *file, loff_t a, loff_t b, int datasync)
+{
+	struct audio *audio = file->private_data;
+	struct buffer *frame;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	if (!audio->running || audio->pcm_feedback) {
+		rc = -EINVAL;
+		goto done_nolock;
+	}
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(!audio->out[0].used &&
+		!audio->out[1].used &&
+		audio->out_needed) || audio->wflush);
+
+	if (rc < 0)
+		goto done;
+	else if (audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (audio->reserved) {
+		MM_DBG("send reserved byte\n");
+		frame = audio->out + audio->out_tail;
+		((char *) frame->data)[0] = audio->rsv_byte;
+		((char *) frame->data)[1] = 0;
+		frame->used = 2;
+		audplay_send_data(audio, 0);
+
+		rc = wait_event_interruptible(audio->write_wait,
+			(!audio->out[0].used &&
+			!audio->out[1].used &&
+			audio->out_needed) || audio->wflush);
+
+		if (rc < 0)
+			goto done;
+		else if (audio->wflush) {
+			rc = -EBUSY;
+			goto done;
+		}
+	}
+
+	/* pcm dmamiss message is sent continously
+	 * when decoder is starved so no race
+	 * condition concern
+	 */
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		audio->teos || audio->wflush);
+
+	if (audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+done_nolock:
+	return rc;
+}
+
+static ssize_t audio_read(struct file *file, char __user *buf, size_t count,
+			  loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	int rc = 0;
+
+	if (!audio->pcm_feedback)
+		return 0; /* PCM feedback is not enabled. Nothing to read */
+
+	mutex_lock(&audio->read_lock);
+	MM_DBG("%d \n", count);
+	while (count > 0) {
+		rc = wait_event_interruptible(audio->read_wait,
+			(audio->in[audio->read_next].used > 0) ||
+			(audio->stopped) || (audio->rflush));
+
+		if (rc < 0)
+			break;
+
+		if (audio->stopped || audio->rflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (count < audio->in[audio->read_next].used) {
+			/* Read must happen in frame boundary. Since driver
+			   does not know frame size, read count must be greater
+			   or equal to size of PCM samples */
+			MM_DBG("audio_read: no partial frame done reading\n");
+			break;
+		} else {
+			MM_DBG("audio_read: read from in[%d]\n",
+					audio->read_next);
+			/* order reads from the output buffer */
+			rmb();
+			if (copy_to_user
+			    (buf, audio->in[audio->read_next].data,
+			     audio->in[audio->read_next].used)) {
+				MM_ERR("invalid addr %x \n", (unsigned int)buf);
+				rc = -EFAULT;
+				break;
+			}
+			count -= audio->in[audio->read_next].used;
+			buf += audio->in[audio->read_next].used;
+			audio->in[audio->read_next].used = 0;
+			if ((++audio->read_next) == audio->pcm_buf_count)
+				audio->read_next = 0;
+			break;	/* Force to exit while loop
+				 * to prevent output thread
+				 * sleep too long if data is
+				 * not ready at this moment.
+				 */
+		}
+	}
+
+	/* don't feed output buffer to HW decoder during flushing
+	 * buffer refresh command will be sent once flush completes
+	 * send buf refresh command here can confuse HW decoder
+	 */
+	if (audio->buf_refresh && !audio->rflush) {
+		audio->buf_refresh = 0;
+		MM_DBG("kick start pcm feedback again\n");
+		audplay_buffer_refresh(audio);
+	}
+
+	mutex_unlock(&audio->read_lock);
+
+	if (buf > start)
+		rc = buf - start;
+
+	MM_DBG("read %d bytes\n", rc);
+	return rc;
+}
+
+static int audwma_process_eos(struct audio *audio,
+		const char __user *buf_start, unsigned short mfield_size)
+{
+	int rc = 0;
+	struct buffer *frame;
+	char *buf_ptr;
+
+	if (audio->reserved) {
+		MM_DBG("flush reserve byte\n");
+		frame = audio->out + audio->out_head;
+		buf_ptr = frame->data;
+		rc = wait_event_interruptible(audio->write_wait,
+				(frame->used == 0)
+				|| (audio->stopped)
+				|| (audio->wflush));
+		if (rc < 0)
+			goto done;
+		if (audio->stopped || audio->wflush) {
+			rc = -EBUSY;
+			goto done;
+		}
+
+		buf_ptr[0] = audio->rsv_byte;
+		buf_ptr[1] = 0;
+		audio->out_head ^= 1;
+		frame->mfield_sz = 0;
+		frame->used = 2;
+		audio->reserved = 0;
+		audplay_send_data(audio, 0);
+	}
+
+	frame = audio->out + audio->out_head;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->out_needed &&
+		audio->out[0].used == 0 &&
+		audio->out[1].used == 0)
+		|| (audio->stopped)
+		|| (audio->wflush));
+
+	if (rc < 0)
+		goto done;
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (copy_from_user(frame->data, buf_start, mfield_size)) {
+		rc = -EFAULT;
+		goto done;
+	}
+
+	frame->mfield_sz = mfield_size;
+	audio->out_head ^= 1;
+	frame->used = mfield_size;
+	audplay_send_data(audio, 0);
+done:
+	return rc;
+}
+
+static ssize_t audio_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	char *cpy_ptr;
+	int rc = 0, eos_condition = AUDWMA_EOS_NONE;
+	unsigned dsize;
+	unsigned short mfield_size = 0;
+
+	MM_DBG("cnt=%d\n", count);
+
+	mutex_lock(&audio->write_lock);
+	while (count > 0) {
+		frame = audio->out + audio->out_head;
+		cpy_ptr = frame->data;
+		dsize = 0;
+		rc = wait_event_interruptible(audio->write_wait,
+					      (frame->used == 0)
+					      || (audio->stopped)
+						  || (audio->wflush));
+		if (rc < 0)
+			break;
+		if (audio->stopped || audio->wflush) {
+			rc = -EBUSY;
+			break;
+		}
+		if (audio->mfield) {
+			if (buf == start) {
+				/* Processing beginning of user buffer */
+				if (__get_user(mfield_size,
+					(unsigned short __user *) buf)) {
+					rc = -EFAULT;
+					break;
+				} else  if (mfield_size > count) {
+					rc = -EINVAL;
+					break;
+				}
+				MM_DBG("audio_write: mf offset_val %x\n",
+						mfield_size);
+				if (copy_from_user(cpy_ptr, buf, mfield_size)) {
+					rc = -EFAULT;
+					break;
+				}
+				/* Check if EOS flag is set and buffer has
+				 * contains just meta field
+				 */
+				if (cpy_ptr[AUDWMA_EOS_FLG_OFFSET] &
+						 AUDWMA_EOS_FLG_MASK) {
+					MM_DBG("audio_write: EOS SET\n");
+					eos_condition = AUDWMA_EOS_SET;
+					if (mfield_size == count) {
+						buf += mfield_size;
+						break;
+					} else
+						cpy_ptr[AUDWMA_EOS_FLG_OFFSET]
+							&= ~AUDWMA_EOS_FLG_MASK;
+				}
+				cpy_ptr += mfield_size;
+				count -= mfield_size;
+				dsize += mfield_size;
+				buf += mfield_size;
+			} else {
+				mfield_size = 0;
+				MM_DBG("audio_write: continuous buffer\n");
+			}
+			frame->mfield_sz = mfield_size;
+		}
+
+		if (audio->reserved) {
+			MM_DBG("append reserved byte %x\n", audio->rsv_byte);
+			*cpy_ptr = audio->rsv_byte;
+			xfer = (count > ((frame->size - mfield_size) - 1)) ?
+				(frame->size - mfield_size) - 1 : count;
+			cpy_ptr++;
+			dsize += 1;
+			audio->reserved = 0;
+		} else
+			xfer = (count > (frame->size - mfield_size)) ?
+				(frame->size - mfield_size) : count;
+
+		if (copy_from_user(cpy_ptr, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+
+		dsize += xfer;
+		if (dsize & 1) {
+			audio->rsv_byte = ((char *) frame->data)[dsize - 1];
+			MM_DBG("odd length buf reserve last byte %x\n",
+					audio->rsv_byte);
+			audio->reserved = 1;
+			dsize--;
+		}
+		count -= xfer;
+		buf += xfer;
+
+		if (dsize > 0) {
+			audio->out_head ^= 1;
+			frame->used = dsize;
+			audplay_send_data(audio, 0);
+		}
+	}
+	if (eos_condition == AUDWMA_EOS_SET)
+		rc = audwma_process_eos(audio, start, mfield_size);
+	mutex_unlock(&audio->write_lock);
+	if (!rc) {
+		if (buf > start)
+			return buf - start;
+	}
+	return rc;
+}
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	MM_INFO("audio instance 0x%08x freeing\n", (int)audio);
+	mutex_lock(&audio->lock);
+	audio_disable(audio);
+	if (audio->rmt_resource_released == 0)
+		rmt_put_resource(audio);
+	audio_flush(audio);
+	audio_flush_pcm_buf(audio);
+	msm_adsp_put(audio->audplay);
+	audpp_adec_free(audio->dec_id);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&audio->suspend_ctl.node);
+#endif
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audwma_reset_event_queue(audio);
+	iounmap(audio->map_v_write);
+	free_contiguous_memory_by_paddr(audio->phys);
+	if (audio->read_data) {
+		iounmap(audio->map_v_read);
+		free_contiguous_memory_by_paddr(audio->read_phys);
+	}
+	mutex_unlock(&audio->lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio);
+	return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audwma_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload)
+{
+	struct audwma_event *e_node = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+				struct audwma_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audwma_event), GFP_ATOMIC);
+		if (!e_node) {
+			MM_ERR("No mem to post event %d\n", type);
+			spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	wake_up(&audio->event_wait);
+}
+
+static void audwma_suspend(struct early_suspend *h)
+{
+	struct audwma_suspend_ctl *ctl =
+		container_of(h, struct audwma_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audwma_post_event(ctl->audio, AUDIO_EVENT_SUSPEND, payload);
+}
+
+static void audwma_resume(struct early_suspend *h)
+{
+	struct audwma_suspend_ctl *ctl =
+		container_of(h, struct audwma_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audwma_post_event(ctl->audio, AUDIO_EVENT_RESUME, payload);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audwma_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audwma_debug_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 4096;
+	static char buffer[4096];
+	int n = 0, i;
+	struct audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "enabled %d\n", audio->enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "pcm_feedback %d\n", audio->pcm_feedback);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_buf_sz %d\n", audio->out[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "pcm_buf_count %d \n", audio->pcm_buf_count);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "pcm_buf_sz %d \n", audio->in[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "volume %x \n", audio->vol_pan.volume);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "sample rate %d \n", audio->out_sample_rate);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		"channel mode %d \n", audio->out_channel_mode);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "rflush %d\n", audio->rflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "running %d \n", audio->running);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"dec state %d \n", audio->dec_state);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_needed %d \n", audio->out_needed);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_head %d \n", audio->out_head);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_tail %d \n", audio->out_tail);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out[0].used %d \n", audio->out[0].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out[1].used %d \n", audio->out[1].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "buffer_refresh %d \n", audio->buf_refresh);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "read_next %d \n", audio->read_next);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "fill_next %d \n", audio->fill_next);
+	for (i = 0; i < audio->pcm_buf_count; i++)
+		n += scnprintf(buffer + n, debug_bufmax - n,
+			"in[%d].size %d \n", i, audio->in[i].used);
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audwma_debug_fops = {
+	.read = audwma_debug_read,
+	.open = audwma_debug_open,
+};
+#endif
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = NULL;
+	int rc, dec_attrb, decid, i;
+	unsigned pmem_sz = DMASZ_MAX;
+	struct audwma_event *e_node = NULL;
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_wma_" + 5];
+#endif
+
+	/* Allocate Mem for audio instance */
+	audio = kzalloc(sizeof(struct audio), GFP_KERNEL);
+	if (!audio) {
+		MM_ERR("no memory to allocate audio instance \n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	MM_INFO("audio instance 0x%08x created\n", (int)audio);
+
+	/* Allocate the decoder */
+	dec_attrb = AUDDEC_DEC_WMA;
+	if ((file->f_mode & FMODE_WRITE) &&
+			(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_NONTUNNEL;
+		audio->pcm_feedback = NON_TUNNEL_MODE_PLAYBACK;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_TUNNEL;
+		audio->pcm_feedback = TUNNEL_MODE_PLAYBACK;
+	} else {
+		kfree(audio);
+		rc = -EACCES;
+		goto done;
+	}
+
+	decid = audpp_adec_alloc(dec_attrb, &audio->module_name,
+			&audio->queue_id);
+
+	if (decid < 0) {
+		MM_ERR("No free decoder available, freeing instance 0x%08x\n",
+				(int)audio);
+		rc = -ENODEV;
+		kfree(audio);
+		goto done;
+	}
+	audio->dec_id = decid & MSM_AUD_DECODER_MASK;
+
+	while (pmem_sz >= DMASZ_MIN) {
+		MM_DBG("pmemsz = %d\n", pmem_sz);
+		audio->phys = allocate_contiguous_ebi_nomap(pmem_sz, SZ_4K);
+		if (audio->phys) {
+			audio->map_v_write = ioremap(audio->phys, pmem_sz);
+			if (IS_ERR(audio->map_v_write)) {
+				MM_ERR("could not map write buffers, \
+						freeing instance 0x%08x\n",
+						(int)audio);
+				rc = -ENOMEM;
+				free_contiguous_memory_by_paddr(audio->phys);
+				audpp_adec_free(audio->dec_id);
+				kfree(audio);
+				goto done;
+			}
+			audio->data = audio->map_v_write;
+			MM_DBG("write buf: phy addr 0x%08x kernel addr \
+				0x%08x\n", audio->phys, (int)audio->data);
+			break;
+		} else if (pmem_sz == DMASZ_MIN) {
+			MM_ERR("could not allocate write buffers, freeing \
+					instance 0x%08x\n", (int)audio);
+			rc = -ENOMEM;
+			audpp_adec_free(audio->dec_id);
+			kfree(audio);
+			goto done;
+		} else
+		pmem_sz >>= 1;
+	}
+	audio->out_dma_sz = pmem_sz;
+
+	if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
+		rc = audmgr_open(&audio->audmgr);
+		if (rc) {
+			MM_ERR("audmgr open failed, freeing instance \
+					0x%08x\n", (int)audio);
+			goto err;
+		}
+	}
+
+	rc = msm_adsp_get(audio->module_name, &audio->audplay,
+			&audplay_adsp_ops_wma, audio);
+	if (rc) {
+		MM_ERR("failed to get %s module, freeing instance 0x%08x\n",
+				audio->module_name, (int)audio);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_close(&audio->audmgr);
+		goto err;
+	}
+
+	rc = rmt_get_resource(audio);
+	if (rc) {
+		MM_ERR("ADSP resources are not available for WMA session \
+			 0x%08x on decoder: %d\n", (int)audio, audio->dec_id);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_close(&audio->audmgr);
+		msm_adsp_put(audio->audplay);
+		goto err;
+	}
+
+	mutex_init(&audio->lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->get_event_lock);
+	spin_lock_init(&audio->dsp_lock);
+	init_waitqueue_head(&audio->write_wait);
+	init_waitqueue_head(&audio->read_wait);
+	INIT_LIST_HEAD(&audio->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+	init_waitqueue_head(&audio->wait);
+	init_waitqueue_head(&audio->event_wait);
+	spin_lock_init(&audio->event_queue_lock);
+
+	audio->out[0].data = audio->data + 0;
+	audio->out[0].addr = audio->phys + 0;
+	audio->out[0].size = audio->out_dma_sz >> 1;
+
+	audio->out[1].data = audio->data + audio->out[0].size;
+	audio->out[1].addr = audio->phys + audio->out[0].size;
+	audio->out[1].size = audio->out[0].size;
+
+	audio->wma_config.armdatareqthr =  1262;
+	audio->wma_config.channelsdecoded = 2;
+	audio->wma_config.wmabytespersec = 6003;
+	audio->wma_config.wmasamplingfreq = 44100;
+	audio->wma_config.wmaencoderopts = 31;
+
+	audio->out_sample_rate = 44100;
+	audio->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V;
+
+	audio->vol_pan.volume = 0x2000;
+
+	audio_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_wma_%04x", audio->dec_id);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+				NULL, (void *) audio,
+				&audwma_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		MM_DBG("debugfs_create_file failed\n");
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	audio->suspend_ctl.node.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+	audio->suspend_ctl.node.resume = audwma_resume;
+	audio->suspend_ctl.node.suspend = audwma_suspend;
+	audio->suspend_ctl.audio = audio;
+	register_early_suspend(&audio->suspend_ctl.node);
+#endif
+	for (i = 0; i < AUDWMA_EVENT_NUM; i++) {
+		e_node = kmalloc(sizeof(struct audwma_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			MM_ERR("event pkt alloc failed\n");
+			break;
+		}
+	}
+done:
+	return rc;
+err:
+	iounmap(audio->map_v_write);
+	free_contiguous_memory_by_paddr(audio->phys);
+	audpp_adec_free(audio->dec_id);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_wma_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audio_open,
+	.release	= audio_release,
+	.read 		= audio_read,
+	.write		= audio_write,
+	.unlocked_ioctl	= audio_ioctl,
+	.fsync 		= audio_fsync,
+};
+
+struct miscdevice audio_wma_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_wma",
+	.fops	= &audio_wma_fops,
+};
+
+static int __init audio_init(void)
+{
+	return misc_register(&audio_wma_misc);
+}
+
+device_initcall(audio_init);
diff --git a/arch/arm/mach-msm/qdsp5/audio_wmapro.c b/arch/arm/mach-msm/qdsp5/audio_wmapro.c
new file mode 100644
index 0000000..641b1c7
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_wmapro.c
@@ -0,0 +1,1766 @@
+/* audio_wmapro.c - wmapro audio decoder driver
+ *
+ * Based on the mp3 native driver in arch/arm/mach-msm/qdsp5/audio_mp3.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/earlysuspend.h>
+#include <linux/android_pmem.h>
+#include <linux/slab.h>
+#include <linux/msm_audio.h>
+#include <linux/memory_alloc.h>
+#include <linux/msm_audio_wmapro.h>
+
+#include <mach/msm_adsp.h>
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audplaycmdi.h>
+#include <mach/qdsp5/qdsp5audplaymsg.h>
+#include <mach/qdsp5/qdsp5rmtcmdi.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_memtypes.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+
+#include "audmgr.h"
+
+/* Size must be power of 2 */
+#define BUFSZ_MAX	8206	/* Includes meta in size */
+#define BUFSZ_MIN 	2062	/* Includes meta in size */
+#define DMASZ_MAX 	(BUFSZ_MAX * 2)
+#define DMASZ_MIN 	(BUFSZ_MIN * 2)
+
+#define AUDPLAY_INVALID_READ_PTR_OFFSET	0xFFFF
+#define AUDDEC_DEC_WMAPRO 13
+
+#define PCM_BUFSZ_MIN 	8216 	/* Hold one stereo WMAPRO frame and meta out*/
+#define PCM_BUF_MAX_COUNT 5	/* DSP only accepts 5 buffers at most
+				   but support 2 buffers currently */
+#define ROUTING_MODE_FTRT 1
+#define ROUTING_MODE_RT 2
+/* Decoder status received from AUDPPTASK */
+#define  AUDPP_DEC_STATUS_SLEEP	0
+#define	 AUDPP_DEC_STATUS_INIT  1
+#define  AUDPP_DEC_STATUS_CFG   2
+#define  AUDPP_DEC_STATUS_PLAY  3
+
+#define AUDWMAPRO_METAFIELD_MASK 0xFFFF0000
+#define AUDWMAPRO_EOS_FLG_OFFSET 0x0A /* Offset from beginning of buffer */
+#define AUDWMAPRO_EOS_FLG_MASK 0x01
+#define AUDWMAPRO_EOS_NONE 0x0 /* No EOS detected */
+#define AUDWMAPRO_EOS_SET 0x1 /* EOS set in meta field */
+
+#define AUDWMAPRO_EVENT_NUM 10 /* Default no. of pre-allocated event packets */
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+	unsigned short mfield_sz; /*only useful for data has meta field */
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct audwmapro_suspend_ctl {
+	struct early_suspend node;
+	struct audio *audio;
+};
+#endif
+
+struct audwmapro_event{
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+
+struct audio {
+	struct buffer out[2];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed; /* number of buffers the dsp is waiting for */
+	unsigned out_dma_sz;
+
+	atomic_t out_bytes;
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	/* Host PCM section */
+	struct buffer in[PCM_BUF_MAX_COUNT];
+	struct mutex read_lock;
+	wait_queue_head_t read_wait;	/* Wait queue for read */
+	char *read_data;	/* pointer to reader buffer */
+	int32_t read_phys;	/* physical address of reader buffer */
+	uint8_t read_next;	/* index to input buffers to be read next */
+	uint8_t fill_next;	/* index to buffer that DSP should be filling */
+	uint8_t pcm_buf_count;	/* number of pcm buffer allocated */
+	/* ---- End of Host PCM section */
+
+	struct msm_adsp_module *audplay;
+
+	/* configuration to use on next enable */
+	uint32_t out_sample_rate;
+	uint32_t out_channel_mode;
+
+	struct msm_audio_wmapro_config wmapro_config;
+	struct audmgr audmgr;
+
+	/* data allocated for various buffers */
+	char *data;
+	int32_t phys; /* physical address of write buffer */
+	void *map_v_read;
+	void *map_v_write;
+
+	int mfield; /* meta field embedded in data */
+	int rflush; /* Read  flush */
+	int wflush; /* Write flush */
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+	int pcm_feedback;
+	int buf_refresh;
+	int rmt_resource_released;
+	int teos; /* valid only if tunnel mode & no data left for decoder */
+	enum msm_aud_decoder_state dec_state;	/* Represents decoder state */
+	int reserved; /* A byte is being reserved */
+	char rsv_byte; /* Handle odd length user data */
+
+	const char *module_name;
+	unsigned queue_id;
+	uint16_t dec_id;
+	uint32_t read_ptr_offset;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct audwmapro_suspend_ctl suspend_ctl;
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+
+	wait_queue_head_t wait;
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	wait_queue_head_t event_wait;
+	spinlock_t event_queue_lock;
+	struct mutex get_event_lock;
+	int event_abort;
+
+	int eq_enable;
+	int eq_needs_commit;
+	audpp_cmd_cfg_object_params_eqalizer eq;
+	audpp_cmd_cfg_object_params_volume vol_pan;
+};
+
+static int auddec_dsp_config(struct audio *audio, int enable);
+static void audpp_cmd_cfg_adec_params(struct audio *audio);
+static void audpp_cmd_cfg_routing_mode(struct audio *audio);
+static void audplay_send_data(struct audio *audio, unsigned needed);
+static void audplay_config_hostpcm(struct audio *audio);
+static void audplay_buffer_refresh(struct audio *audio);
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audwmapro_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload);
+#endif
+
+static int rmt_put_resource(struct audio *audio)
+{
+	struct aud_codec_config_cmd cmd;
+	unsigned short client_idx;
+
+	cmd.cmd_id = RM_CMD_AUD_CODEC_CFG;
+	cmd.client_id = RM_AUD_CLIENT_ID;
+	cmd.task_id = audio->dec_id;
+	cmd.enable = RMT_DISABLE;
+	cmd.dec_type = AUDDEC_DEC_WMAPRO;
+	client_idx = ((cmd.client_id << 8) | cmd.task_id);
+
+	return put_adsp_resource(client_idx, &cmd, sizeof(cmd));
+}
+
+static int rmt_get_resource(struct audio *audio)
+{
+	struct aud_codec_config_cmd cmd;
+	unsigned short client_idx;
+
+	cmd.cmd_id = RM_CMD_AUD_CODEC_CFG;
+	cmd.client_id = RM_AUD_CLIENT_ID;
+	cmd.task_id = audio->dec_id;
+	cmd.enable = RMT_ENABLE;
+	cmd.dec_type = AUDDEC_DEC_WMAPRO;
+	client_idx = ((cmd.client_id << 8) | cmd.task_id);
+
+	return get_adsp_resource(client_idx, &cmd, sizeof(cmd));
+}
+
+/* must be called with audio->lock held */
+static int audio_enable(struct audio *audio)
+{
+	struct audmgr_config cfg;
+	int rc;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled)
+		return 0;
+
+	if (audio->rmt_resource_released == 1) {
+		audio->rmt_resource_released = 0;
+		rc = rmt_get_resource(audio);
+		if (rc) {
+			MM_ERR("ADSP resources are not available for WMAPRO \
+				session 0x%08x on decoder: %d\n Ignoring \
+				error and going ahead with the playback\n",
+				(int)audio, audio->dec_id);
+		}
+	}
+
+	audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;
+	cfg.def_method = RPC_AUD_DEF_METHOD_PLAYBACK;
+	cfg.codec = RPC_AUD_DEF_CODEC_WMA;
+	cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+	rc = audmgr_enable(&audio->audmgr, &cfg);
+	if (rc < 0)
+		return rc;
+
+	if (msm_adsp_enable(audio->audplay)) {
+		MM_ERR("msm_adsp_enable(audplay) failed\n");
+		audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+
+	if (audpp_enable(audio->dec_id, audio_dsp_event, audio)) {
+		MM_ERR("audpp_enable() failed\n");
+		msm_adsp_disable(audio->audplay);
+		audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+
+	audio->enabled = 1;
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audio_disable(struct audio *audio)
+{
+	int rc = 0;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+		auddec_dsp_config(audio, 0);
+		rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+		else if (audio->dec_state != MSM_AUD_DECODER_STATE_CLOSE)
+			rc = -EFAULT;
+		else
+			rc = 0;
+		audio->stopped = 1;
+		wake_up(&audio->write_wait);
+		wake_up(&audio->read_wait);
+		msm_adsp_disable(audio->audplay);
+		audpp_disable(audio->dec_id, audio);
+		audmgr_disable(&audio->audmgr);
+		audio->out_needed = 0;
+		rmt_put_resource(audio);
+		audio->rmt_resource_released = 1;
+	}
+	return rc;
+}
+
+/* ------------------- dsp --------------------- */
+static void audio_update_pcm_buf_entry(struct audio *audio,
+	uint32_t *payload)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	if (audio->rflush)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < payload[1]; index++) {
+		if (audio->in[audio->fill_next].addr ==
+			payload[2 + index * 2]) {
+			MM_DBG("audio_update_pcm_buf_entry: \
+				in[%d] ready\n", audio->fill_next);
+			audio->in[audio->fill_next].used =
+			payload[3 + index * 2];
+			if ((++audio->fill_next) == audio->pcm_buf_count)
+				audio->fill_next = 0;
+		} else {
+			MM_ERR("audio_update_pcm_buf_entry: \
+				expected=%x ret=%x\n",
+				audio->in[audio->fill_next].addr,
+				payload[1 + index * 2]);
+			break;
+		}
+	}
+	if (audio->in[audio->fill_next].used == 0) {
+		audplay_buffer_refresh(audio);
+	} else {
+		MM_DBG("read cannot keep up\n");
+		audio->buf_refresh = 1;
+	}
+	wake_up(&audio->read_wait);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static void audplay_dsp_event(void *data, unsigned id, size_t len,
+			      void (*getevent) (void *ptr, size_t len))
+{
+	struct audio *audio = data;
+	uint32_t msg[28];
+
+	getevent(msg, sizeof(msg));
+
+	MM_DBG("msg_id=%x\n", id);
+
+	switch (id) {
+	case AUDPLAY_MSG_DEC_NEEDS_DATA:
+		audplay_send_data(audio, 1);
+		break;
+
+	case AUDPLAY_MSG_BUFFER_UPDATE:
+		audio_update_pcm_buf_entry(audio, msg);
+		break;
+
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audplaytask)\n");
+		break;
+
+	default:
+		MM_ERR("unexpected message from decoder \n");
+		break;
+	}
+}
+
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned status = msg[1];
+
+			switch (status) {
+			case AUDPP_DEC_STATUS_SLEEP: {
+				uint16_t reason = msg[2];
+				MM_DBG("decoder status:sleep reason = \
+						0x%04x\n", reason);
+				if ((reason == AUDPP_MSG_REASON_MEM)
+					|| (reason ==
+					AUDPP_MSG_REASON_NODECODER)) {
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_FAILURE;
+					wake_up(&audio->wait);
+				} else if (reason == AUDPP_MSG_REASON_NONE) {
+					/* decoder is in disable state */
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_CLOSE;
+					wake_up(&audio->wait);
+				}
+				break;
+			}
+			case AUDPP_DEC_STATUS_INIT:
+				MM_DBG("decoder status: init\n");
+				if (audio->pcm_feedback)
+					audpp_cmd_cfg_routing_mode(audio);
+				else
+					audpp_cmd_cfg_adec_params(audio);
+				break;
+
+			case AUDPP_DEC_STATUS_CFG:
+				MM_DBG("decoder status: cfg\n");
+				break;
+			case AUDPP_DEC_STATUS_PLAY:
+				MM_DBG("decoder status: play\n");
+				if (audio->pcm_feedback) {
+					audplay_config_hostpcm(audio);
+					audplay_buffer_refresh(audio);
+				}
+				audio->dec_state =
+					MSM_AUD_DECODER_STATE_SUCCESS;
+				wake_up(&audio->wait);
+				break;
+			default:
+				MM_ERR("unknown decoder status\n");
+			}
+			break;
+		}
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			MM_DBG("CFG_MSG ENABLE\n");
+			auddec_dsp_config(audio, 1);
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+			audpp_dsp_set_eq(audio->dec_id,	audio->eq_enable,
+								&audio->eq);
+			audpp_avsync(audio->dec_id, 22050);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			MM_DBG("CFG_MSG DISABLE\n");
+			audpp_avsync(audio->dec_id, 0);
+			audio->running = 0;
+		} else {
+			MM_DBG("CFG_MSG %d?\n", msg[0]);
+		}
+		break;
+	case AUDPP_MSG_ROUTING_ACK:
+		MM_DBG("ROUTING_ACK mode=%d\n", msg[1]);
+		audpp_cmd_cfg_adec_params(audio);
+		break;
+
+	case AUDPP_MSG_FLUSH_ACK:
+		MM_DBG("FLUSH_ACK\n");
+		audio->wflush = 0;
+		audio->rflush = 0;
+		wake_up(&audio->write_wait);
+		if (audio->pcm_feedback)
+			audplay_buffer_refresh(audio);
+		break;
+	case AUDPP_MSG_PCMDMAMISSED:
+		MM_DBG("PCMDMAMISSED\n");
+		audio->teos = 1;
+		wake_up(&audio->write_wait);
+		break;
+
+	default:
+		MM_ERR("UNKNOWN (%d)\n", id);
+	}
+
+}
+
+static struct msm_adsp_ops audplay_adsp_ops_wmapro = {
+	.event = audplay_dsp_event,
+};
+
+#define audplay_send_queue0(audio, cmd, len) \
+	msm_adsp_write(audio->audplay, audio->queue_id, \
+			cmd, len)
+
+static int auddec_dsp_config(struct audio *audio, int enable)
+{
+	u16 cfg_dec_cmd[AUDPP_CMD_CFG_DEC_TYPE_LEN / sizeof(unsigned short)];
+
+	memset(cfg_dec_cmd, 0, sizeof(cfg_dec_cmd));
+	cfg_dec_cmd[0] = AUDPP_CMD_CFG_DEC_TYPE;
+	if (enable)
+		cfg_dec_cmd[1 + audio->dec_id] = AUDPP_CMD_UPDATDE_CFG_DEC |
+			AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_WMAPRO;
+	else
+		cfg_dec_cmd[1 + audio->dec_id] = AUDPP_CMD_UPDATDE_CFG_DEC |
+			AUDPP_CMD_DIS_DEC_V;
+
+	return audpp_send_queue1(&cfg_dec_cmd, sizeof(cfg_dec_cmd));
+}
+
+static void audpp_cmd_cfg_adec_params(struct audio *audio)
+{
+	struct audpp_cmd_cfg_adec_params_wmapro cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_WMAPRO_LEN;
+	cmd.common.dec_id = audio->dec_id;
+	cmd.common.input_sampling_frequency = audio->out_sample_rate;
+
+	cmd.armdatareqthr = audio->wmapro_config.armdatareqthr;
+	cmd.numchannels = audio->wmapro_config.numchannels;
+	cmd.validbitspersample = audio->wmapro_config.validbitspersample;
+	cmd.formattag = audio->wmapro_config.formattag;
+	cmd.samplingrate = audio->wmapro_config.samplingrate;
+	cmd.avgbytespersecond = audio->wmapro_config.avgbytespersecond;
+	cmd.asfpacketlength = audio->wmapro_config.asfpacketlength;
+	cmd.channelmask = audio->wmapro_config.channelmask;
+	cmd.encodeopt = audio->wmapro_config.encodeopt;
+	cmd.advancedencodeopt = audio->wmapro_config.advancedencodeopt;
+	cmd.advancedencodeopt2 = audio->wmapro_config.advancedencodeopt2;
+
+	audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static void audpp_cmd_cfg_routing_mode(struct audio *audio)
+{
+	struct audpp_cmd_routing_mode cmd;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_ROUTING_MODE;
+	cmd.object_number = audio->dec_id;
+	if (audio->pcm_feedback)
+		cmd.routing_mode = ROUTING_MODE_FTRT;
+	else
+		cmd.routing_mode = ROUTING_MODE_RT;
+
+	audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static void audplay_buffer_refresh(struct audio *audio)
+{
+	struct audplay_cmd_buffer_refresh refresh_cmd;
+
+	refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH;
+	refresh_cmd.num_buffers = 1;
+	refresh_cmd.buf0_address = audio->in[audio->fill_next].addr;
+	refresh_cmd.buf0_length = audio->in[audio->fill_next].size;
+	refresh_cmd.buf_read_count = 0;
+
+	MM_DBG("buf0_addr=%x buf0_len=%d\n",
+			refresh_cmd.buf0_address,
+			refresh_cmd.buf0_length);
+
+	(void)audplay_send_queue0(audio, &refresh_cmd, sizeof(refresh_cmd));
+}
+
+static void audplay_config_hostpcm(struct audio *audio)
+{
+	struct audplay_cmd_hpcm_buf_cfg cfg_cmd;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	cfg_cmd.cmd_id = AUDPLAY_CMD_HPCM_BUF_CFG;
+	cfg_cmd.max_buffers = audio->pcm_buf_count;
+	cfg_cmd.byte_swap = 0;
+	cfg_cmd.hostpcm_config = (0x8000) | (0x4000);
+	cfg_cmd.feedback_frequency = 1;
+	cfg_cmd.partition_number = 0;
+
+	(void)audplay_send_queue0(audio, &cfg_cmd, sizeof(cfg_cmd));
+}
+
+
+static int audplay_dsp_send_data_avail(struct audio *audio,
+					unsigned idx, unsigned len)
+{
+	struct audplay_cmd_bitstream_data_avail_nt2 cmd;
+
+	cmd.cmd_id		= AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_NT2;
+	if (audio->mfield)
+		cmd.decoder_id = AUDWMAPRO_METAFIELD_MASK |
+			(audio->out[idx].mfield_sz >> 1);
+	else
+		cmd.decoder_id		= audio->dec_id;
+	cmd.buf_ptr		= audio->out[idx].addr;
+	cmd.buf_size		= len/2;
+	cmd.partition_number	= 0;
+	return audplay_send_queue0(audio, &cmd, sizeof(cmd));
+}
+
+static void audplay_send_data(struct audio *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (audio->wflush) {
+		audio->out_needed = 1;
+		goto done;
+	}
+
+	if (needed && !audio->wflush) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			MM_DBG("frame %d free\n", audio->out_tail);
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		MM_DBG("\n"); /* Macro prints the file name and function */
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+			MM_DBG("frame %d busy\n", audio->out_tail);
+			audplay_dsp_send_data_avail(audio, audio->out_tail,
+								frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+
+static void audio_flush(struct audio *audio)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->out[0].used = 0;
+	audio->out[1].used = 0;
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->reserved = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	atomic_set(&audio->out_bytes, 0);
+}
+
+static void audio_flush_pcm_buf(struct audio *audio)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
+		audio->in[index].used = 0;
+	audio->buf_refresh = 0;
+	audio->read_next = 0;
+	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static void audio_ioport_reset(struct audio *audio)
+{
+	/* Make sure read/write thread are free from
+	 * sleep and knowing that system is not able
+	 * to process io request at the moment
+	 */
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audio_flush(audio);
+	mutex_unlock(&audio->write_lock);
+	wake_up(&audio->read_wait);
+	mutex_lock(&audio->read_lock);
+	audio_flush_pcm_buf(audio);
+	mutex_unlock(&audio->read_lock);
+}
+
+static int audwmapro_events_pending(struct audio *audio)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	return empty || audio->event_abort;
+}
+
+static void audwmapro_reset_event_queue(struct audio *audio)
+{
+	unsigned long flags;
+	struct audwmapro_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audwmapro_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+				struct audwmapro_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	return;
+}
+
+static long audwmapro_process_event_req(struct audio *audio, void __user *arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audwmapro_event *drv_evt = NULL;
+	int timeout;
+	unsigned long flags;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int) usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(audio->event_wait,
+				audwmapro_events_pending(audio),
+				msecs_to_jiffies(timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(
+			audio->event_wait, audwmapro_events_pending(audio));
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	rc = 0;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audwmapro_event, list);
+		list_del(&drv_evt->list);
+	}
+
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else
+		rc = -1;
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	if (!rc && copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audio_enable_eq(struct audio *audio, int enable)
+{
+	if (audio->eq_enable == enable && !audio->eq_needs_commit)
+		return 0;
+
+	audio->eq_enable = enable;
+
+	if (audio->running) {
+		audpp_dsp_set_eq(audio->dec_id, enable, &audio->eq);
+		audio->eq_needs_commit = 0;
+	}
+	return 0;
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = -EINVAL;
+	unsigned long flags = 0;
+	uint16_t enable_mask;
+	int enable;
+	int prev_state;
+
+	MM_DBG("cmd = %d\n", cmd);
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = audpp_avsync_byte_count(audio->dec_id);
+		stats.sample_count = audpp_avsync_sample_count(audio->dec_id);
+		if (copy_to_user((void *)arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	switch (cmd) {
+	case AUDIO_ENABLE_AUDPP:
+		if (copy_from_user(&enable_mask, (void *) arg,
+						sizeof(enable_mask))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		enable = (enable_mask & EQ_ENABLE) ? 1 : 0;
+		audio_enable_eq(audio, enable);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+	case AUDIO_SET_VOLUME:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.volume = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_PAN:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.pan = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_EQ:
+		prev_state = audio->eq_enable;
+		audio->eq_enable = 0;
+		if (copy_from_user(&audio->eq.num_bands, (void *) arg,
+				sizeof(audio->eq) -
+				(AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2))) {
+			rc = -EFAULT;
+			break;
+		}
+		audio->eq_enable = prev_state;
+		audio->eq_needs_commit = 1;
+		rc = 0;
+		break;
+	}
+
+	if (-EINVAL != rc)
+		return rc;
+
+	if (cmd == AUDIO_GET_EVENT) {
+		MM_DBG("AUDIO_GET_EVENT\n");
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audwmapro_process_event_req(audio,
+					(void __user *) arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		return rc;
+	}
+
+	if (cmd == AUDIO_ABORT_GET_EVENT) {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		MM_DBG("AUDIO_START\n");
+		rc = audio_enable(audio);
+		if (!rc) {
+			rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+			MM_INFO("dec_state %d rc = %d\n", audio->dec_state, rc);
+
+			if (audio->dec_state != MSM_AUD_DECODER_STATE_SUCCESS)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		break;
+	case AUDIO_STOP:
+		MM_DBG("AUDIO_STOP\n");
+		rc = audio_disable(audio);
+		audio_ioport_reset(audio);
+		audio->stopped = 0;
+		break;
+	case AUDIO_FLUSH:
+		MM_DBG("AUDIO_FLUSH\n");
+		audio->rflush = 1;
+		audio->wflush = 1;
+		audio_ioport_reset(audio);
+		if (audio->running) {
+			audpp_flush(audio->dec_id);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		break;
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (copy_from_user(&config, (void *) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (config.channel_count == 1) {
+			config.channel_count = AUDPP_CMD_PCM_INTF_MONO_V;
+		} else if (config.channel_count == 2) {
+			config.channel_count = AUDPP_CMD_PCM_INTF_STEREO_V;
+		} else {
+			rc = -EINVAL;
+			break;
+		}
+		audio->mfield = config.meta_field;
+		audio->out_sample_rate = config.sample_rate;
+		audio->out_channel_mode = config.channel_count;
+		rc = 0;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_size = (audio->out_dma_sz >> 1);
+		config.buffer_count = 2;
+		config.sample_rate = audio->out_sample_rate;
+		if (audio->out_channel_mode == AUDPP_CMD_PCM_INTF_MONO_V)
+			config.channel_count = 1;
+		else
+			config.channel_count = 2;
+		config.meta_field = 0;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void *) arg, &config, sizeof(config)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+
+		break;
+	}
+	case AUDIO_GET_WMAPRO_CONFIG:{
+			if (copy_to_user((void *)arg, &audio->wmapro_config,
+				sizeof(audio->wmapro_config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_SET_WMAPRO_CONFIG:{
+		struct msm_audio_wmapro_config usr_config;
+
+		if (copy_from_user
+			(&usr_config, (void *)arg,
+			sizeof(usr_config))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		audio->wmapro_config = usr_config;
+
+		/* Need to swap the first and last words of advancedencodeopt2
+		 * as DSP cannot read 32-bit variable at a time. Need to be
+		 * split into two 16-bit and swap them as required by DSP */
+
+		audio->wmapro_config.advancedencodeopt2 =
+			((audio->wmapro_config.advancedencodeopt2 & 0xFFFF0000)
+			 >> 16) | ((audio->wmapro_config.advancedencodeopt2
+			 << 16) & 0xFFFF0000);
+		rc = 0;
+		break;
+	}
+	case AUDIO_GET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			config.pcm_feedback = audio->pcm_feedback;
+			config.buffer_count = PCM_BUF_MAX_COUNT;
+			config.buffer_size = PCM_BUFSZ_MIN;
+			if (copy_to_user((void *)arg, &config,
+					 sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_SET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			if (copy_from_user
+			    (&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+			if (config.pcm_feedback != audio->pcm_feedback) {
+				MM_ERR("Not sufficient permission to"
+						"change the playback mode\n");
+				rc = -EACCES;
+				break;
+			}
+			if ((config.buffer_count > PCM_BUF_MAX_COUNT) ||
+			    (config.buffer_count == 1))
+				config.buffer_count = PCM_BUF_MAX_COUNT;
+
+			if (config.buffer_size < PCM_BUFSZ_MIN)
+				config.buffer_size = PCM_BUFSZ_MIN;
+
+			/* Check if pcm feedback is required */
+			if ((config.pcm_feedback) && (!audio->read_data)) {
+				MM_DBG("allocate PCM buffer %d\n",
+						config.buffer_count *
+						config.buffer_size);
+				audio->read_phys =
+						allocate_contiguous_ebi_nomap(
+							config.buffer_size *
+							config.buffer_count,
+							SZ_4K);
+				if (!audio->read_phys) {
+					rc = -ENOMEM;
+					break;
+				}
+				audio->map_v_read = ioremap(
+						audio->read_phys,
+						config.buffer_size *
+						config.buffer_count);
+
+				if (IS_ERR(audio->map_v_read)) {
+					MM_ERR("map of read buf failed\n");
+					rc = -ENOMEM;
+					free_contiguous_memory_by_paddr(
+							audio->read_phys);
+				} else {
+					uint8_t index;
+					uint32_t offset = 0;
+					audio->read_data = audio->map_v_read;
+					audio->pcm_feedback = 1;
+					audio->buf_refresh = 0;
+					audio->pcm_buf_count =
+					    config.buffer_count;
+					audio->read_next = 0;
+					audio->fill_next = 0;
+
+					for (index = 0;
+					     index < config.buffer_count;
+					     index++) {
+						audio->in[index].data =
+						    audio->read_data + offset;
+						audio->in[index].addr =
+						    audio->read_phys + offset;
+						audio->in[index].size =
+						    config.buffer_size;
+						audio->in[index].used = 0;
+						offset += config.buffer_size;
+					}
+					MM_DBG("read buf: phy addr \
+						0x%08x kernel addr 0x%08x\n",
+						audio->read_phys,
+						(int)audio->read_data);
+					rc = 0;
+				}
+			} else {
+				rc = 0;
+			}
+			break;
+		}
+	case AUDIO_PAUSE:
+		MM_DBG("AUDIO_PAUSE %ld\n", arg);
+		rc = audpp_pause(audio->dec_id, (int) arg);
+		break;
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+/* Only useful in tunnel-mode */
+static int audio_fsync(struct file *file, loff_t a, loff_t b, int datasync)
+{
+	struct audio *audio = file->private_data;
+	struct buffer *frame;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	if (!audio->running || audio->pcm_feedback) {
+		rc = -EINVAL;
+		goto done_nolock;
+	}
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(!audio->out[0].used &&
+		!audio->out[1].used &&
+		audio->out_needed) || audio->wflush);
+
+	if (rc < 0)
+		goto done;
+	else if (audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (audio->reserved) {
+		MM_DBG("send reserved byte\n");
+		frame = audio->out + audio->out_tail;
+		((char *) frame->data)[0] = audio->rsv_byte;
+		((char *) frame->data)[1] = 0;
+		frame->used = 2;
+		audplay_send_data(audio, 0);
+
+		rc = wait_event_interruptible(audio->write_wait,
+			(!audio->out[0].used &&
+			!audio->out[1].used &&
+			audio->out_needed) || audio->wflush);
+
+		if (rc < 0)
+			goto done;
+		else if (audio->wflush) {
+			rc = -EBUSY;
+			goto done;
+		}
+	}
+
+	/* pcm dmamiss message is sent continously
+	 * when decoder is starved so no race
+	 * condition concern
+	 */
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		audio->teos || audio->wflush);
+
+	if (audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+done_nolock:
+	return rc;
+}
+
+static ssize_t audio_read(struct file *file, char __user *buf, size_t count,
+			  loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	int rc = 0;
+
+	if (!audio->pcm_feedback)
+		return 0; /* PCM feedback is not enabled. Nothing to read */
+
+	mutex_lock(&audio->read_lock);
+	MM_DBG("%d \n", count);
+	while (count > 0) {
+		rc = wait_event_interruptible(audio->read_wait,
+			(audio->in[audio->read_next].used > 0) ||
+			(audio->stopped) || (audio->rflush));
+
+		if (rc < 0)
+			break;
+
+		if (audio->stopped || audio->rflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (count < audio->in[audio->read_next].used) {
+			/* Read must happen in frame boundary. Since driver
+			   does not know frame size, read count must be greater
+			   or equal to size of PCM samples */
+			MM_DBG("audio_read: no partial frame done reading\n");
+			break;
+		} else {
+			MM_DBG("audio_read: read from in[%d]\n",
+					audio->read_next);
+			if (copy_to_user
+			    (buf, audio->in[audio->read_next].data,
+			     audio->in[audio->read_next].used)) {
+				MM_ERR("invalid addr %x \n", (unsigned int)buf);
+				rc = -EFAULT;
+				break;
+			}
+			count -= audio->in[audio->read_next].used;
+			buf += audio->in[audio->read_next].used;
+			audio->in[audio->read_next].used = 0;
+			if ((++audio->read_next) == audio->pcm_buf_count)
+				audio->read_next = 0;
+			break;	/* Force to exit while loop
+				 * to prevent output thread
+				 * sleep too long if data is
+				 * not ready at this moment.
+				 */
+		}
+	}
+
+	/* don't feed output buffer to HW decoder during flushing
+	 * buffer refresh command will be sent once flush completes
+	 * send buf refresh command here can confuse HW decoder
+	 */
+	if (audio->buf_refresh && !audio->rflush) {
+		audio->buf_refresh = 0;
+		MM_DBG("kick start pcm feedback again\n");
+		audplay_buffer_refresh(audio);
+	}
+
+	mutex_unlock(&audio->read_lock);
+
+	if (buf > start)
+		rc = buf - start;
+
+	MM_DBG("read %d bytes\n", rc);
+	return rc;
+}
+
+static int audwmapro_process_eos(struct audio *audio,
+		const char __user *buf_start, unsigned short mfield_size)
+{
+	int rc = 0;
+	struct buffer *frame;
+	char *buf_ptr;
+
+	if (audio->reserved) {
+		MM_DBG("flush reserve byte\n");
+		frame = audio->out + audio->out_head;
+		buf_ptr = frame->data;
+		rc = wait_event_interruptible(audio->write_wait,
+				(frame->used == 0)
+				|| (audio->stopped)
+				|| (audio->wflush));
+		if (rc < 0)
+			goto done;
+		if (audio->stopped || audio->wflush) {
+			rc = -EBUSY;
+			goto done;
+		}
+
+		buf_ptr[0] = audio->rsv_byte;
+		buf_ptr[1] = 0;
+		audio->out_head ^= 1;
+		frame->mfield_sz = 0;
+		frame->used = 2;
+		audio->reserved = 0;
+		audplay_send_data(audio, 0);
+	}
+
+	frame = audio->out + audio->out_head;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->out_needed &&
+		audio->out[0].used == 0 &&
+		audio->out[1].used == 0)
+		|| (audio->stopped)
+		|| (audio->wflush));
+
+	if (rc < 0)
+		goto done;
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (copy_from_user(frame->data, buf_start, mfield_size)) {
+		rc = -EFAULT;
+		goto done;
+	}
+
+	frame->mfield_sz = mfield_size;
+	audio->out_head ^= 1;
+	frame->used = mfield_size;
+	audplay_send_data(audio, 0);
+done:
+	return rc;
+}
+
+static ssize_t audio_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	char *cpy_ptr;
+	int rc = 0, eos_condition = AUDWMAPRO_EOS_NONE;
+	unsigned dsize;
+	unsigned short mfield_size = 0;
+
+	MM_DBG("cnt=%d\n", count);
+
+	mutex_lock(&audio->write_lock);
+	while (count > 0) {
+		frame = audio->out + audio->out_head;
+		cpy_ptr = frame->data;
+		dsize = 0;
+		rc = wait_event_interruptible(audio->write_wait,
+					      (frame->used == 0)
+					      || (audio->stopped)
+						  || (audio->wflush));
+		if (rc < 0)
+			break;
+		if (audio->stopped || audio->wflush) {
+			rc = -EBUSY;
+			break;
+		}
+		if (audio->mfield) {
+			if (buf == start) {
+				/* Processing beginning of user buffer */
+				if (__get_user(mfield_size,
+					(unsigned short __user *) buf)) {
+					rc = -EFAULT;
+					break;
+				} else  if (mfield_size > count) {
+					rc = -EINVAL;
+					break;
+				}
+				MM_DBG("audio_write: mf offset_val %x\n",
+						mfield_size);
+				if (copy_from_user(cpy_ptr, buf, mfield_size)) {
+					rc = -EFAULT;
+					break;
+				}
+				/* Check if EOS flag is set and buffer has
+				 * contains just meta field
+				 */
+				if (cpy_ptr[AUDWMAPRO_EOS_FLG_OFFSET] &
+						 AUDWMAPRO_EOS_FLG_MASK) {
+					MM_DBG("audio_write: EOS SET\n");
+					eos_condition = AUDWMAPRO_EOS_SET;
+					if (mfield_size == count) {
+						buf += mfield_size;
+						break;
+					} else
+					cpy_ptr[AUDWMAPRO_EOS_FLG_OFFSET]
+						&= ~AUDWMAPRO_EOS_FLG_MASK;
+				}
+				cpy_ptr += mfield_size;
+				count -= mfield_size;
+				dsize += mfield_size;
+				buf += mfield_size;
+			} else {
+				mfield_size = 0;
+				MM_DBG("audio_write: continuous buffer\n");
+			}
+			frame->mfield_sz = mfield_size;
+		}
+
+		if (audio->reserved) {
+			MM_DBG("append reserved byte %x\n", audio->rsv_byte);
+			*cpy_ptr = audio->rsv_byte;
+			xfer = (count > ((frame->size - mfield_size) - 1)) ?
+				(frame->size - mfield_size) - 1 : count;
+			cpy_ptr++;
+			dsize += 1;
+			audio->reserved = 0;
+		} else
+			xfer = (count > (frame->size - mfield_size)) ?
+				(frame->size - mfield_size) : count;
+
+		if (copy_from_user(cpy_ptr, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+
+		dsize += xfer;
+		if (dsize & 1) {
+			audio->rsv_byte = ((char *) frame->data)[dsize - 1];
+			MM_DBG("odd length buf reserve last byte %x\n",
+					audio->rsv_byte);
+			audio->reserved = 1;
+			dsize--;
+		}
+		count -= xfer;
+		buf += xfer;
+
+		if (dsize > 0) {
+			audio->out_head ^= 1;
+			frame->used = dsize;
+			audplay_send_data(audio, 0);
+		}
+	}
+	if (eos_condition == AUDWMAPRO_EOS_SET)
+		rc = audwmapro_process_eos(audio, start, mfield_size);
+	mutex_unlock(&audio->write_lock);
+	if (!rc) {
+		if (buf > start)
+			return buf - start;
+	}
+	return rc;
+}
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	MM_INFO("audio instance 0x%08x freeing\n", (int)audio);
+	mutex_lock(&audio->lock);
+	audio_disable(audio);
+	if (audio->rmt_resource_released == 0)
+		rmt_put_resource(audio);
+	audio_flush(audio);
+	audio_flush_pcm_buf(audio);
+	msm_adsp_put(audio->audplay);
+	audpp_adec_free(audio->dec_id);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&audio->suspend_ctl.node);
+#endif
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audwmapro_reset_event_queue(audio);
+	iounmap(audio->map_v_write);
+	free_contiguous_memory_by_paddr(audio->phys);
+	if (audio->read_data) {
+		iounmap(audio->map_v_read);
+		free_contiguous_memory_by_paddr(audio->read_phys);
+	}
+	mutex_unlock(&audio->lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio);
+	return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audwmapro_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload)
+{
+	struct audwmapro_event *e_node = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+				struct audwmapro_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audwmapro_event), GFP_ATOMIC);
+		if (!e_node) {
+			MM_ERR("No mem to post event %d\n", type);
+			spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	wake_up(&audio->event_wait);
+}
+
+static void audwmapro_suspend(struct early_suspend *h)
+{
+	struct audwmapro_suspend_ctl *ctl =
+		container_of(h, struct audwmapro_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audwmapro_post_event(ctl->audio, AUDIO_EVENT_SUSPEND, payload);
+}
+
+static void audwmapro_resume(struct early_suspend *h)
+{
+	struct audwmapro_suspend_ctl *ctl =
+		container_of(h, struct audwmapro_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audwmapro_post_event(ctl->audio, AUDIO_EVENT_RESUME, payload);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audwmapro_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audwmapro_debug_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 4096;
+	static char buffer[4096];
+	int n = 0, i;
+	struct audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "enabled %d\n", audio->enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "pcm_feedback %d\n", audio->pcm_feedback);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_buf_sz %d\n", audio->out[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "pcm_buf_count %d \n", audio->pcm_buf_count);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "pcm_buf_sz %d \n", audio->in[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "volume %x \n", audio->vol_pan.volume);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "sample rate %d \n", audio->out_sample_rate);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		"channel mode %d \n", audio->out_channel_mode);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "rflush %d\n", audio->rflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "running %d \n", audio->running);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"dec state %d \n", audio->dec_state);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_needed %d \n", audio->out_needed);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_head %d \n", audio->out_head);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_tail %d \n", audio->out_tail);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out[0].used %d \n", audio->out[0].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out[1].used %d \n", audio->out[1].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "buffer_refresh %d \n", audio->buf_refresh);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "read_next %d \n", audio->read_next);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "fill_next %d \n", audio->fill_next);
+	for (i = 0; i < audio->pcm_buf_count; i++)
+		n += scnprintf(buffer + n, debug_bufmax - n,
+			"in[%d].size %d \n", i, audio->in[i].used);
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audwmapro_debug_fops = {
+	.read = audwmapro_debug_read,
+	.open = audwmapro_debug_open,
+};
+#endif
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = NULL;
+	int rc, dec_attrb, decid, i;
+	unsigned pmem_sz = DMASZ_MAX;
+	struct audwmapro_event *e_node = NULL;
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_wmapro_" + 5];
+#endif
+
+	/* Allocate Mem for audio instance */
+	audio = kzalloc(sizeof(struct audio), GFP_KERNEL);
+	if (!audio) {
+		MM_ERR("no memory to allocate audio instance \n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	MM_INFO("audio instance 0x%08x created\n", (int)audio);
+
+	/* Allocate the decoder */
+	dec_attrb = AUDDEC_DEC_WMAPRO;
+	if ((file->f_mode & FMODE_WRITE) &&
+			(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_NONTUNNEL;
+		audio->pcm_feedback = NON_TUNNEL_MODE_PLAYBACK;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_TUNNEL;
+		audio->pcm_feedback = TUNNEL_MODE_PLAYBACK;
+	} else {
+		kfree(audio);
+		rc = -EACCES;
+		goto done;
+	}
+
+	decid = audpp_adec_alloc(dec_attrb, &audio->module_name,
+			&audio->queue_id);
+
+	if (decid < 0) {
+		MM_ERR("No free decoder available, freeing instance 0x%08x\n",
+				(int)audio);
+		rc = -ENODEV;
+		kfree(audio);
+		goto done;
+	}
+	audio->dec_id = decid & MSM_AUD_DECODER_MASK;
+
+	while (pmem_sz >= DMASZ_MIN) {
+		MM_DBG("pmemsz = %d\n", pmem_sz);
+		audio->phys = allocate_contiguous_ebi_nomap(pmem_sz, SZ_4K);
+		if (audio->phys) {
+			audio->map_v_write = ioremap(audio->phys, pmem_sz);
+			if (IS_ERR(audio->map_v_write)) {
+				MM_ERR("could not map write buffers, \
+						freeing instance 0x%08x\n",
+						(int)audio);
+				rc = -ENOMEM;
+				free_contiguous_memory_by_paddr(audio->phys);
+				audpp_adec_free(audio->dec_id);
+				kfree(audio);
+				goto done;
+			}
+			audio->data = audio->map_v_write;
+			MM_DBG("write buf: phy addr 0x%08x kernel addr \
+				0x%08x\n", audio->phys, (int)audio->data);
+			break;
+		} else if (pmem_sz == DMASZ_MIN) {
+			MM_ERR("could not allocate write buffers, freeing \
+					instance 0x%08x\n", (int)audio);
+			rc = -ENOMEM;
+			audpp_adec_free(audio->dec_id);
+			kfree(audio);
+			goto done;
+		} else
+		pmem_sz >>= 1;
+	}
+	audio->out_dma_sz = pmem_sz;
+
+	rc = audmgr_open(&audio->audmgr);
+	if (rc) {
+		MM_ERR("audmgr open failed, freeing instance 0x%08x\n",
+				(int)audio);
+		goto err;
+	}
+
+	rc = msm_adsp_get(audio->module_name, &audio->audplay,
+			&audplay_adsp_ops_wmapro, audio);
+	if (rc) {
+		MM_ERR("failed to get %s module, freeing instance 0x%08x\n",
+				audio->module_name, (int)audio);
+		audmgr_close(&audio->audmgr);
+		goto err;
+	}
+
+	rc = rmt_get_resource(audio);
+	if (rc) {
+		MM_ERR("ADSP resources are not available for WMAPRO session \
+			 0x%08x on decoder: %d\n", (int)audio, audio->dec_id);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_close(&audio->audmgr);
+		msm_adsp_put(audio->audplay);
+		goto err;
+	}
+
+	mutex_init(&audio->lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->get_event_lock);
+	spin_lock_init(&audio->dsp_lock);
+	init_waitqueue_head(&audio->write_wait);
+	init_waitqueue_head(&audio->read_wait);
+	INIT_LIST_HEAD(&audio->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+	init_waitqueue_head(&audio->wait);
+	init_waitqueue_head(&audio->event_wait);
+	spin_lock_init(&audio->event_queue_lock);
+
+	audio->out[0].data = audio->data + 0;
+	audio->out[0].addr = audio->phys + 0;
+	audio->out[0].size = audio->out_dma_sz >> 1;
+
+	audio->out[1].data = audio->data + audio->out[0].size;
+	audio->out[1].addr = audio->phys + audio->out[0].size;
+	audio->out[1].size = audio->out[0].size;
+
+	audio->out_sample_rate = 44100;
+	audio->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V;
+
+	audio->vol_pan.volume = 0x2000;
+
+	audio_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_wmapro_%04x", audio->dec_id);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+				NULL, (void *) audio,
+				&audwmapro_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		MM_DBG("debugfs_create_file failed\n");
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	audio->suspend_ctl.node.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+	audio->suspend_ctl.node.resume = audwmapro_resume;
+	audio->suspend_ctl.node.suspend = audwmapro_suspend;
+	audio->suspend_ctl.audio = audio;
+	register_early_suspend(&audio->suspend_ctl.node);
+#endif
+	for (i = 0; i < AUDWMAPRO_EVENT_NUM; i++) {
+		e_node = kmalloc(sizeof(struct audwmapro_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			MM_ERR("event pkt alloc failed\n");
+			break;
+		}
+	}
+done:
+	return rc;
+err:
+	iounmap(audio->map_v_write);
+	free_contiguous_memory_by_paddr(audio->phys);
+	audpp_adec_free(audio->dec_id);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_wmapro_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audio_open,
+	.release	= audio_release,
+	.read 		= audio_read,
+	.write		= audio_write,
+	.unlocked_ioctl	= audio_ioctl,
+	.fsync 		= audio_fsync,
+};
+
+struct miscdevice audio_wmapro_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_wmapro",
+	.fops	= &audio_wmapro_fops,
+};
+
+static int __init audio_init(void)
+{
+	return misc_register(&audio_wmapro_misc);
+}
+
+device_initcall(audio_init);
diff --git a/arch/arm/mach-msm/qdsp5/audmgr.c b/arch/arm/mach-msm/qdsp5/audmgr.c
new file mode 100644
index 0000000..231a28c
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audmgr.c
@@ -0,0 +1,365 @@
+/* arch/arm/mach-msm/qdsp5/audmgr.c
+ *
+ * interface to "audmgr" service on the baseband cpu
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2009, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/slab.h>
+
+#include <asm/atomic.h>
+#include <mach/msm_rpcrouter.h>
+
+#include "audmgr.h"
+#include <mach/debug_mm.h>
+
+#define STATE_CLOSED    0
+#define STATE_DISABLED  1
+#define STATE_ENABLING  2
+#define STATE_ENABLED   3
+#define STATE_DISABLING 4
+#define STATE_ERROR	5
+
+/* store information used across complete audmgr sessions */
+struct audmgr_global {
+	struct mutex *lock;
+	struct msm_rpc_endpoint *ept;
+	struct task_struct *task;
+	uint32_t rpc_version;
+};
+static DEFINE_MUTEX(audmgr_lock);
+
+static struct audmgr_global the_audmgr_state = {
+	.lock = &audmgr_lock,
+};
+
+static void rpc_ack(struct msm_rpc_endpoint *ept, uint32_t xid)
+{
+	uint32_t rep[6];
+
+	rep[0] = cpu_to_be32(xid);
+	rep[1] = cpu_to_be32(1);
+	rep[2] = cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED);
+	rep[3] = cpu_to_be32(RPC_ACCEPTSTAT_SUCCESS);
+	rep[4] = 0;
+	rep[5] = 0;
+
+	msm_rpc_write(ept, rep, sizeof(rep));
+}
+
+static void process_audmgr_callback(struct audmgr_global *amg,
+				   struct rpc_audmgr_cb_func_ptr *args,
+				   int len)
+{
+	struct audmgr *am;
+
+	/* Allow only if complete arguments recevied */
+	if (len < (sizeof(struct rpc_audmgr_cb_func_ptr)))
+		return;
+
+	/* Allow only if valid argument */
+	if (be32_to_cpu(args->set_to_one) != 1)
+		return;
+
+	am = (struct audmgr *) be32_to_cpu(args->client_data);
+
+	if (!am)
+		return;
+
+	switch (be32_to_cpu(args->status)) {
+	case RPC_AUDMGR_STATUS_READY:
+		am->handle = be32_to_cpu(args->u.handle);
+		MM_INFO("rpc READY handle=0x%08x\n", am->handle);
+		break;
+	case RPC_AUDMGR_STATUS_CODEC_CONFIG: {
+		uint32_t volume;
+		volume = be32_to_cpu(args->u.volume);
+		MM_INFO("rpc CODEC_CONFIG volume=0x%08x\n", volume);
+		am->state = STATE_ENABLED;
+		wake_up(&am->wait);
+		break;
+	}
+	case RPC_AUDMGR_STATUS_PENDING:
+		MM_ERR("PENDING?\n");
+		break;
+	case RPC_AUDMGR_STATUS_SUSPEND:
+		MM_ERR("SUSPEND?\n");
+		break;
+	case RPC_AUDMGR_STATUS_FAILURE:
+		MM_ERR("FAILURE\n");
+		break;
+	case RPC_AUDMGR_STATUS_VOLUME_CHANGE:
+		MM_ERR("VOLUME_CHANGE?\n");
+		break;
+	case RPC_AUDMGR_STATUS_DISABLED:
+		MM_ERR("DISABLED\n");
+		am->state = STATE_DISABLED;
+		wake_up(&am->wait);
+		break;
+	case RPC_AUDMGR_STATUS_ERROR:
+		MM_ERR("ERROR?\n");
+		am->state = STATE_ERROR;
+		wake_up(&am->wait);
+		break;
+	default:
+		break;
+	}
+}
+
+static void process_rpc_request(uint32_t proc, uint32_t xid,
+				void *data, int len, void *private)
+{
+	struct audmgr_global *amg = private;
+
+	if (proc == AUDMGR_CB_FUNC_PTR)
+		process_audmgr_callback(amg, data, len);
+	else
+		MM_ERR("unknown rpc proc %d\n", proc);
+	rpc_ack(amg->ept, xid);
+}
+
+#define RPC_TYPE_REQUEST 0
+#define RPC_TYPE_REPLY 1
+
+#define RPC_VERSION 2
+
+#define RPC_COMMON_HDR_SZ  (sizeof(uint32_t) * 2)
+#define RPC_REQUEST_HDR_SZ (sizeof(struct rpc_request_hdr))
+#define RPC_REPLY_HDR_SZ   (sizeof(uint32_t) * 3)
+#define RPC_REPLY_SZ       (sizeof(uint32_t) * 6)
+
+static int audmgr_rpc_thread(void *data)
+{
+	struct audmgr_global *amg = data;
+	struct rpc_request_hdr *hdr = NULL;
+	uint32_t type;
+	int len;
+
+	MM_INFO("start\n");
+
+	while (!kthread_should_stop()) {
+		if (hdr) {
+			kfree(hdr);
+			hdr = NULL;
+		}
+		len = msm_rpc_read(amg->ept, (void **) &hdr, -1, -1);
+		if (len < 0) {
+			MM_ERR("rpc read failed (%d)\n", len);
+			break;
+		}
+		if (len < RPC_COMMON_HDR_SZ)
+			continue;
+
+		type = be32_to_cpu(hdr->type);
+		if (type == RPC_TYPE_REPLY) {
+			struct rpc_reply_hdr *rep = (void *) hdr;
+			uint32_t status;
+			if (len < RPC_REPLY_HDR_SZ)
+				continue;
+			status = be32_to_cpu(rep->reply_stat);
+			if (status == RPCMSG_REPLYSTAT_ACCEPTED) {
+				status = be32_to_cpu(rep->data.acc_hdr.accept_stat);
+				MM_INFO("rpc_reply status %d\n", status);
+			} else {
+				MM_INFO("rpc_reply denied!\n");
+			}
+			/* process reply */
+			continue;
+		}
+
+		if (len < RPC_REQUEST_HDR_SZ)
+			continue;
+
+		process_rpc_request(be32_to_cpu(hdr->procedure),
+				    be32_to_cpu(hdr->xid),
+				    (void *) (hdr + 1),
+				    len - sizeof(*hdr),
+				    data);
+	}
+	MM_INFO("exit\n");
+	if (hdr) {
+		kfree(hdr);
+		hdr = NULL;
+	}
+	amg->task = NULL;
+	return 0;
+}
+
+struct audmgr_enable_msg {
+	struct rpc_request_hdr hdr;
+	struct rpc_audmgr_enable_client_args args;
+};
+
+struct audmgr_disable_msg {
+	struct rpc_request_hdr hdr;
+	uint32_t handle;
+};
+
+int audmgr_open(struct audmgr *am)
+{
+	struct audmgr_global *amg = &the_audmgr_state;
+	int rc;
+
+	if (am->state != STATE_CLOSED)
+		return 0;
+
+	mutex_lock(amg->lock);
+
+	/* connect to audmgr end point and polling thread only once */
+	if (amg->ept == NULL) {
+		amg->ept = msm_rpc_connect_compatible(AUDMGR_PROG,
+				AUDMGR_VERS_COMP_VER3,
+				MSM_RPC_UNINTERRUPTIBLE);
+		if (IS_ERR(amg->ept)) {
+			MM_ERR("connect failed with current VERS \
+				= %x, trying again with another API\n",
+				AUDMGR_VERS_COMP_VER3);
+			amg->ept = msm_rpc_connect_compatible(AUDMGR_PROG,
+					AUDMGR_VERS_COMP_VER2,
+					MSM_RPC_UNINTERRUPTIBLE);
+			if (IS_ERR(amg->ept)) {
+				MM_ERR("connect failed with current VERS \
+					= %x, trying again with another API\n",
+					AUDMGR_VERS_COMP_VER2);
+				amg->ept = msm_rpc_connect_compatible(
+						AUDMGR_PROG,
+						AUDMGR_VERS_COMP,
+						MSM_RPC_UNINTERRUPTIBLE);
+				if (IS_ERR(amg->ept)) {
+					MM_ERR("connect failed with current \
+					VERS=%x, trying again with another \
+					API\n", AUDMGR_VERS_COMP);
+					amg->ept = msm_rpc_connect(AUDMGR_PROG,
+						AUDMGR_VERS,
+						MSM_RPC_UNINTERRUPTIBLE);
+					amg->rpc_version = AUDMGR_VERS;
+				} else
+					amg->rpc_version = AUDMGR_VERS_COMP;
+			} else
+				amg->rpc_version = AUDMGR_VERS_COMP_VER2;
+		} else
+			amg->rpc_version = AUDMGR_VERS_COMP_VER3;
+
+		if (IS_ERR(amg->ept)) {
+			rc = PTR_ERR(amg->ept);
+			amg->ept = NULL;
+			MM_ERR("failed to connect to audmgr svc\n");
+			goto done;
+		}
+
+		amg->task = kthread_run(audmgr_rpc_thread, amg, "audmgr_rpc");
+		if (IS_ERR(amg->task)) {
+			rc = PTR_ERR(amg->task);
+			amg->task = NULL;
+			msm_rpc_close(amg->ept);
+			amg->ept = NULL;
+			goto done;
+		}
+	}
+
+	/* Initialize session parameters */
+	init_waitqueue_head(&am->wait);
+	am->state = STATE_DISABLED;
+	rc = 0;
+done:
+	mutex_unlock(amg->lock);
+	return rc;
+}
+EXPORT_SYMBOL(audmgr_open);
+
+int audmgr_close(struct audmgr *am)
+{
+	return -EBUSY;
+}
+EXPORT_SYMBOL(audmgr_close);
+
+int audmgr_enable(struct audmgr *am, struct audmgr_config *cfg)
+{
+	struct audmgr_global *amg = &the_audmgr_state;
+	struct audmgr_enable_msg msg;
+	int rc;
+
+	if (am->state == STATE_ENABLED)
+		return 0;
+
+	if (am->state == STATE_DISABLING)
+		MM_ERR("state is DISABLING in enable?\n");
+	am->state = STATE_ENABLING;
+
+	MM_INFO("session 0x%08x\n", (int) am);
+	msg.args.set_to_one = cpu_to_be32(1);
+	msg.args.tx_sample_rate = cpu_to_be32(cfg->tx_rate);
+	msg.args.rx_sample_rate = cpu_to_be32(cfg->rx_rate);
+	msg.args.def_method = cpu_to_be32(cfg->def_method);
+	msg.args.codec_type = cpu_to_be32(cfg->codec);
+	msg.args.snd_method = cpu_to_be32(cfg->snd_method);
+	msg.args.cb_func = cpu_to_be32(0x11111111);
+	msg.args.client_data = cpu_to_be32((int)am);
+
+	msm_rpc_setup_req(&msg.hdr, AUDMGR_PROG, amg->rpc_version,
+			  AUDMGR_ENABLE_CLIENT);
+
+	rc = msm_rpc_write(amg->ept, &msg, sizeof(msg));
+	if (rc < 0)
+		return rc;
+
+	rc = wait_event_timeout(am->wait, am->state != STATE_ENABLING, 15 * HZ);
+	if (rc == 0) {
+		MM_ERR("ARM9 did not reply to RPC am->state = %d\n", am->state);
+	}
+	if (am->state == STATE_ENABLED)
+		return 0;
+
+	MM_ERR("unexpected state %d while enabling?!\n", am->state);
+	return -ENODEV;
+}
+EXPORT_SYMBOL(audmgr_enable);
+
+int audmgr_disable(struct audmgr *am)
+{
+	struct audmgr_global *amg = &the_audmgr_state;
+	struct audmgr_disable_msg msg;
+	int rc;
+
+	if (am->state == STATE_DISABLED)
+		return 0;
+
+	MM_INFO("session 0x%08x\n", (int) am);
+	msg.handle = cpu_to_be32(am->handle);
+	msm_rpc_setup_req(&msg.hdr, AUDMGR_PROG, amg->rpc_version,
+			  AUDMGR_DISABLE_CLIENT);
+
+	am->state = STATE_DISABLING;
+
+	rc = msm_rpc_write(amg->ept, &msg, sizeof(msg));
+	if (rc < 0)
+		return rc;
+
+	rc = wait_event_timeout(am->wait, am->state != STATE_DISABLING, 15 * HZ);
+	if (rc == 0) {
+		MM_ERR("ARM9 did not reply to RPC am->state = %d\n", am->state);
+	}
+
+	if (am->state == STATE_DISABLED)
+		return 0;
+
+	MM_ERR("unexpected state %d while disabling?!\n", am->state);
+	return -ENODEV;
+}
+EXPORT_SYMBOL(audmgr_disable);
diff --git a/arch/arm/mach-msm/qdsp5/audmgr.h b/arch/arm/mach-msm/qdsp5/audmgr.h
new file mode 100644
index 0000000..34c8488
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audmgr.h
@@ -0,0 +1,280 @@
+/* arch/arm/mach-msm/qdsp5/audmgr.h
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2008-2009, 2012 Code Aurora Forum. 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 _AUDIO_RPC_H_
+#define _AUDIO_RPC_H_
+
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+
+enum rpc_aud_def_sample_rate_type {
+	RPC_AUD_DEF_SAMPLE_RATE_NONE,
+	RPC_AUD_DEF_SAMPLE_RATE_8000,
+	RPC_AUD_DEF_SAMPLE_RATE_11025,
+	RPC_AUD_DEF_SAMPLE_RATE_12000,
+	RPC_AUD_DEF_SAMPLE_RATE_16000,
+	RPC_AUD_DEF_SAMPLE_RATE_22050,
+	RPC_AUD_DEF_SAMPLE_RATE_24000,
+	RPC_AUD_DEF_SAMPLE_RATE_32000,
+	RPC_AUD_DEF_SAMPLE_RATE_44100,
+	RPC_AUD_DEF_SAMPLE_RATE_48000,
+	RPC_AUD_DEF_SAMPLE_RATE_MAX,
+};
+
+enum rpc_aud_def_method_type {
+	RPC_AUD_DEF_METHOD_NONE,
+	RPC_AUD_DEF_METHOD_KEY_BEEP,
+	RPC_AUD_DEF_METHOD_PLAYBACK,
+	RPC_AUD_DEF_METHOD_VOICE,
+	RPC_AUD_DEF_METHOD_RECORD,
+	RPC_AUD_DEF_METHOD_HOST_PCM,
+	RPC_AUD_DEF_METHOD_MIDI_OUT,
+	RPC_AUD_DEF_METHOD_RECORD_SBC,
+	RPC_AUD_DEF_METHOD_DTMF_RINGER,
+	RPC_AUD_DEF_METHOD_MAX,
+};
+
+enum rpc_aud_def_codec_type {
+	RPC_AUD_DEF_CODEC_NONE,
+	RPC_AUD_DEF_CODEC_DTMF,
+	RPC_AUD_DEF_CODEC_MIDI,
+	RPC_AUD_DEF_CODEC_MP3,
+	RPC_AUD_DEF_CODEC_PCM,
+	RPC_AUD_DEF_CODEC_AAC,
+	RPC_AUD_DEF_CODEC_WMA,
+	RPC_AUD_DEF_CODEC_RA,
+	RPC_AUD_DEF_CODEC_ADPCM,
+	RPC_AUD_DEF_CODEC_GAUDIO,
+	RPC_AUD_DEF_CODEC_VOC_EVRC,
+	RPC_AUD_DEF_CODEC_VOC_13K,
+	RPC_AUD_DEF_CODEC_VOC_4GV_NB,
+	RPC_AUD_DEF_CODEC_VOC_AMR,
+	RPC_AUD_DEF_CODEC_VOC_EFR,
+	RPC_AUD_DEF_CODEC_VOC_FR,
+	RPC_AUD_DEF_CODEC_VOC_HR,
+	RPC_AUD_DEF_CODEC_VOC_CDMA,
+	RPC_AUD_DEF_CODEC_VOC_CDMA_WB,
+	RPC_AUD_DEF_CODEC_VOC_UMTS,
+	RPC_AUD_DEF_CODEC_VOC_UMTS_WB,
+	RPC_AUD_DEF_CODEC_SBC,
+	RPC_AUD_DEF_CODEC_VOC_PCM,
+	RPC_AUD_DEF_CODEC_AMR_WB,
+	RPC_AUD_DEF_CODEC_AMR_WB_PLUS,
+	RPC_AUD_DEF_CODEC_AAC_BSAC,
+	RPC_AUD_DEF_CODEC_MAX,
+	RPC_AUD_DEF_CODEC_AMR_NB,
+	RPC_AUD_DEF_CODEC_13K,
+	RPC_AUD_DEF_CODEC_EVRC,
+	RPC_AUD_DEF_CODEC_MAX_002,
+};
+
+enum rpc_snd_method_type {
+	RPC_SND_METHOD_VOICE = 0,
+	RPC_SND_METHOD_KEY_BEEP,
+	RPC_SND_METHOD_MESSAGE,
+	RPC_SND_METHOD_RING,
+	RPC_SND_METHOD_MIDI,
+	RPC_SND_METHOD_AUX,
+	RPC_SND_METHOD_MAX,
+};
+
+enum rpc_voc_codec_type {
+	RPC_VOC_CODEC_DEFAULT,
+	RPC_VOC_CODEC_ON_CHIP_0 = RPC_VOC_CODEC_DEFAULT,
+	RPC_VOC_CODEC_ON_CHIP_1,
+	RPC_VOC_CODEC_STEREO_HEADSET,
+	RPC_VOC_CODEC_ON_CHIP_AUX,
+	RPC_VOC_CODEC_BT_OFF_BOARD,
+	RPC_VOC_CODEC_BT_A2DP,
+	RPC_VOC_CODEC_OFF_BOARD,
+	RPC_VOC_CODEC_SDAC,
+	RPC_VOC_CODEC_RX_EXT_SDAC_TX_INTERNAL,
+	RPC_VOC_CODEC_IN_STEREO_SADC_OUT_MONO_HANDSET,
+	RPC_VOC_CODEC_IN_STEREO_SADC_OUT_STEREO_HEADSET,
+	RPC_VOC_CODEC_TX_INT_SADC_RX_EXT_AUXPCM,
+	RPC_VOC_CODEC_EXT_STEREO_SADC_OUT_MONO_HANDSET,
+	RPC_VOC_CODEC_EXT_STEREO_SADC_OUT_STEREO_HEADSET,
+	RPC_VOC_CODEC_TTY_ON_CHIP_1,
+	RPC_VOC_CODEC_TTY_OFF_BOARD,
+	RPC_VOC_CODEC_TTY_VCO,
+	RPC_VOC_CODEC_TTY_HCO,
+	RPC_VOC_CODEC_ON_CHIP_0_DUAL_MIC,
+	RPC_VOC_CODEC_MAX,
+	RPC_VOC_CODEC_NONE,
+};
+
+enum rpc_audmgr_status_type {
+	RPC_AUDMGR_STATUS_READY,
+	RPC_AUDMGR_STATUS_CODEC_CONFIG,
+	RPC_AUDMGR_STATUS_PENDING,
+	RPC_AUDMGR_STATUS_SUSPEND,
+	RPC_AUDMGR_STATUS_FAILURE,
+	RPC_AUDMGR_STATUS_VOLUME_CHANGE,
+	RPC_AUDMGR_STATUS_DISABLED,
+	RPC_AUDMGR_STATUS_ERROR,
+};
+
+struct rpc_audmgr_enable_client_args {
+	uint32_t set_to_one;
+	uint32_t tx_sample_rate;
+	uint32_t rx_sample_rate;
+	uint32_t def_method;
+	uint32_t codec_type;
+	uint32_t snd_method;
+
+	uint32_t cb_func;
+	uint32_t client_data;
+};
+	
+#define AUDMGR_ENABLE_CLIENT			2
+#define AUDMGR_DISABLE_CLIENT			3
+#define AUDMGR_SUSPEND_EVENT_RSP		4
+#define AUDMGR_REGISTER_OPERATION_LISTENER	5
+#define AUDMGR_UNREGISTER_OPERATION_LISTENER	6
+#define AUDMGR_REGISTER_CODEC_LISTENER		7
+#define AUDMGR_GET_RX_SAMPLE_RATE		8
+#define AUDMGR_GET_TX_SAMPLE_RATE		9
+#define AUDMGR_SET_DEVICE_MODE			10
+
+#define AUDMGR_PROG_VERS "rs30000013:0x7feccbff"
+#define AUDMGR_PROG 0x30000013
+#define AUDMGR_VERS 0x7feccbff
+#define AUDMGR_VERS_COMP 0x00010001
+#define AUDMGR_VERS_COMP_VER2 0x00020001
+#define AUDMGR_VERS_COMP_VER3 0x00030001
+
+struct rpc_audmgr_cb_func_ptr {
+	uint32_t cb_id; /* cb_func */
+	uint32_t status; /* Audmgr status */
+	uint32_t set_to_one;  /* Pointer status (1 = valid, 0  = invalid) */
+	uint32_t disc;
+	/* disc = AUDMGR_STATUS_READY => data=handle
+	   disc = AUDMGR_STATUS_CODEC_CONFIG => data = volume
+	   disc = AUDMGR_STATUS_DISABLED => data =status_disabled
+	   disc = AUDMGR_STATUS_VOLUME_CHANGE => data = volume_change */
+	union {
+		uint32_t handle;
+		uint32_t volume;
+		uint32_t status_disabled;
+		uint32_t volume_change;
+	} u;
+	uint32_t client_data;
+};
+
+#define AUDMGR_CB_FUNC_PTR			1
+#define AUDMGR_OPR_LSTNR_CB_FUNC_PTR		2
+#define AUDMGR_CODEC_LSTR_FUNC_PTR		3
+
+#define AUDMGR_CB_PROG_VERS "rs31000013:0xf8e3e2d9"
+#define AUDMGR_CB_PROG 0x31000013
+#define AUDMGR_CB_VERS 0xf8e3e2d9
+
+struct audmgr {
+	wait_queue_head_t wait;
+	uint32_t handle;
+	int state;
+};
+
+struct audmgr_config {
+	uint32_t tx_rate;
+	uint32_t rx_rate;
+	uint32_t def_method;
+	uint32_t codec;
+	uint32_t snd_method;
+};
+
+int audmgr_open(struct audmgr *am);
+int audmgr_close(struct audmgr *am);
+int audmgr_enable(struct audmgr *am, struct audmgr_config *cfg);
+int audmgr_disable(struct audmgr *am);
+
+typedef void (*audpp_event_func)(void *private, unsigned id, uint16_t *msg);
+typedef void (*audrec_event_func)(void *private, unsigned id, uint16_t *msg);
+
+/* worst case delay of 1sec for response */
+#define MSM_AUD_DECODER_WAIT_MS 1000
+#define MSM_AUD_MODE_TUNNEL  0x00000100
+#define MSM_AUD_MODE_NONTUNNEL  0x00000200
+#define MSM_AUD_DECODER_MASK  0x0000FFFF
+#define MSM_AUD_OP_MASK  0xFFFF0000
+
+/*Playback mode*/
+#define NON_TUNNEL_MODE_PLAYBACK 1
+#define TUNNEL_MODE_PLAYBACK 0
+
+enum msm_aud_decoder_state {
+	MSM_AUD_DECODER_STATE_NONE = 0,
+	MSM_AUD_DECODER_STATE_FAILURE = 1,
+	MSM_AUD_DECODER_STATE_SUCCESS = 2,
+	MSM_AUD_DECODER_STATE_CLOSE = 3,
+};
+
+int audpp_adec_alloc(unsigned dec_attrb, const char **module_name,
+			unsigned *queueid);
+void audpp_adec_free(int decid);
+
+struct audpp_event_callback {
+	audpp_event_func fn;
+	void *private;
+};
+
+int audpp_register_event_callback(struct audpp_event_callback *eh);
+int audpp_unregister_event_callback(struct audpp_event_callback *eh);
+int is_audpp_enable(void);
+
+int audpp_enable(int id, audpp_event_func func, void *private);
+void audpp_disable(int id, void *private);
+
+int audpp_send_queue1(void *cmd, unsigned len);
+int audpp_send_queue2(void *cmd, unsigned len);
+int audpp_send_queue3(void *cmd, unsigned len);
+
+int audpp_set_volume_and_pan(unsigned id, unsigned volume, int pan);
+int audpp_pause(unsigned id, int pause);
+int audpp_flush(unsigned id);
+void audpp_avsync(int id, unsigned rate);
+unsigned audpp_avsync_sample_count(int id);
+unsigned audpp_avsync_byte_count(int id);
+int audpp_dsp_set_mbadrc(unsigned id, unsigned enable,
+			audpp_cmd_cfg_object_params_mbadrc *mbadrc);
+int audpp_dsp_set_eq(unsigned id, unsigned enable,
+			audpp_cmd_cfg_object_params_eqalizer *eq);
+int audpp_dsp_set_rx_iir(unsigned id, unsigned enable,
+				audpp_cmd_cfg_object_params_pcm *iir);
+
+int audpp_dsp_set_rx_srs_trumedia_g
+	(struct audpp_cmd_cfg_object_params_srstm_g *srstm);
+int audpp_dsp_set_rx_srs_trumedia_w
+	(struct audpp_cmd_cfg_object_params_srstm_w *srstm);
+int audpp_dsp_set_rx_srs_trumedia_c
+	(struct audpp_cmd_cfg_object_params_srstm_c *srstm);
+int audpp_dsp_set_rx_srs_trumedia_h
+	(struct audpp_cmd_cfg_object_params_srstm_h *srstm);
+int audpp_dsp_set_rx_srs_trumedia_p
+	(struct audpp_cmd_cfg_object_params_srstm_p *srstm);
+int audpp_dsp_set_rx_srs_trumedia_l
+	(struct audpp_cmd_cfg_object_params_srstm_l *srstm);
+
+int audpp_dsp_set_vol_pan(unsigned id,
+				audpp_cmd_cfg_object_params_volume *vol_pan);
+int audpp_dsp_set_qconcert_plus(unsigned id, unsigned enable,
+			audpp_cmd_cfg_object_params_qconcert *qconcert_plus);
+int audrectask_enable(unsigned enc_type, audrec_event_func func, void *private);
+void audrectask_disable(unsigned enc_type, void *private);
+
+int audrectask_send_cmdqueue(void *cmd, unsigned len);
+int audrectask_send_bitstreamqueue(void *cmd, unsigned len);
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp5/audmgr_new.h b/arch/arm/mach-msm/qdsp5/audmgr_new.h
new file mode 100644
index 0000000..3604405
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audmgr_new.h
@@ -0,0 +1,213 @@
+/* arch/arm/mach-msm/qdsp5/audmgr.h
+ *
+ * Copyright 2008 (c) Code Aurora Forum. All rights reserved.
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * 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 _ARCH_ARM_MACH_MSM_AUDMGR_NEW_H
+#define _ARCH_ARM_MACH_MSM_AUDMGR_NEW_H
+
+enum rpc_aud_def_sample_rate_type {
+	RPC_AUD_DEF_SAMPLE_RATE_NONE,
+	RPC_AUD_DEF_SAMPLE_RATE_8000,
+	RPC_AUD_DEF_SAMPLE_RATE_11025,
+	RPC_AUD_DEF_SAMPLE_RATE_12000,
+	RPC_AUD_DEF_SAMPLE_RATE_16000,
+	RPC_AUD_DEF_SAMPLE_RATE_22050,
+	RPC_AUD_DEF_SAMPLE_RATE_24000,
+	RPC_AUD_DEF_SAMPLE_RATE_32000,
+	RPC_AUD_DEF_SAMPLE_RATE_44100,
+	RPC_AUD_DEF_SAMPLE_RATE_48000,
+	RPC_AUD_DEF_SAMPLE_RATE_MAX,
+};
+
+enum rpc_aud_def_method_type {
+	RPC_AUD_DEF_METHOD_NONE,
+	RPC_AUD_DEF_METHOD_KEY_BEEP,
+	RPC_AUD_DEF_METHOD_PLAYBACK,
+	RPC_AUD_DEF_METHOD_VOICE,
+	RPC_AUD_DEF_METHOD_RECORD,
+	RPC_AUD_DEF_METHOD_HOST_PCM,
+	RPC_AUD_DEF_METHOD_MIDI_OUT,
+	RPC_AUD_DEF_METHOD_RECORD_SBC,
+	RPC_AUD_DEF_METHOD_DTMF_RINGER,
+	RPC_AUD_DEF_METHOD_MAX,
+};
+
+enum rpc_aud_def_codec_type {
+	RPC_AUD_DEF_CODEC_NONE,
+	RPC_AUD_DEF_CODEC_DTMF,
+	RPC_AUD_DEF_CODEC_MIDI,
+	RPC_AUD_DEF_CODEC_MP3,
+	RPC_AUD_DEF_CODEC_PCM,
+	RPC_AUD_DEF_CODEC_AAC,
+	RPC_AUD_DEF_CODEC_WMA,
+	RPC_AUD_DEF_CODEC_RA,
+	RPC_AUD_DEF_CODEC_ADPCM,
+	RPC_AUD_DEF_CODEC_GAUDIO,
+	RPC_AUD_DEF_CODEC_VOC_EVRC,
+	RPC_AUD_DEF_CODEC_VOC_13K,
+	RPC_AUD_DEF_CODEC_VOC_4GV_NB,
+	RPC_AUD_DEF_CODEC_VOC_AMR,
+	RPC_AUD_DEF_CODEC_VOC_EFR,
+	RPC_AUD_DEF_CODEC_VOC_FR,
+	RPC_AUD_DEF_CODEC_VOC_HR,
+	RPC_AUD_DEF_CODEC_VOC_CDMA,
+	RPC_AUD_DEF_CODEC_VOC_CDMA_WB,
+	RPC_AUD_DEF_CODEC_VOC_UMTS,
+	RPC_AUD_DEF_CODEC_VOC_UMTS_WB,
+	RPC_AUD_DEF_CODEC_SBC,
+	RPC_AUD_DEF_CODEC_VOC_PCM,
+	RPC_AUD_DEF_CODEC_AMR_WB,
+	RPC_AUD_DEF_CODEC_AMR_WB_PLUS,
+	RPC_AUD_DEF_CODEC_AAC_BSAC,
+	RPC_AUD_DEF_CODEC_MAX,
+	RPC_AUD_DEF_CODEC_AMR_NB,
+	RPC_AUD_DEF_CODEC_13K,
+	RPC_AUD_DEF_CODEC_EVRC,
+	RPC_AUD_DEF_CODEC_MAX_002,
+};
+
+enum rpc_snd_method_type {
+	RPC_SND_METHOD_VOICE = 0,
+	RPC_SND_METHOD_KEY_BEEP,
+	RPC_SND_METHOD_MESSAGE,
+	RPC_SND_METHOD_RING,
+	RPC_SND_METHOD_MIDI,
+	RPC_SND_METHOD_AUX,
+	RPC_SND_METHOD_MAX,
+};
+
+enum rpc_voc_codec_type {
+	RPC_VOC_CODEC_DEFAULT,
+	RPC_VOC_CODEC_ON_CHIP_0 = RPC_VOC_CODEC_DEFAULT,
+	RPC_VOC_CODEC_ON_CHIP_1,
+	RPC_VOC_CODEC_STEREO_HEADSET,
+	RPC_VOC_CODEC_ON_CHIP_AUX,
+	RPC_VOC_CODEC_BT_OFF_BOARD,
+	RPC_VOC_CODEC_BT_A2DP,
+	RPC_VOC_CODEC_OFF_BOARD,
+	RPC_VOC_CODEC_SDAC,
+	RPC_VOC_CODEC_RX_EXT_SDAC_TX_INTERNAL,
+	RPC_VOC_CODEC_IN_STEREO_SADC_OUT_MONO_HANDSET,
+	RPC_VOC_CODEC_IN_STEREO_SADC_OUT_STEREO_HEADSET,
+	RPC_VOC_CODEC_TX_INT_SADC_RX_EXT_AUXPCM,
+	RPC_VOC_CODEC_EXT_STEREO_SADC_OUT_MONO_HANDSET,
+	RPC_VOC_CODEC_EXT_STEREO_SADC_OUT_STEREO_HEADSET,
+	RPC_VOC_CODEC_TTY_ON_CHIP_1,
+	RPC_VOC_CODEC_TTY_OFF_BOARD,
+	RPC_VOC_CODEC_TTY_VCO,
+	RPC_VOC_CODEC_TTY_HCO,
+	RPC_VOC_CODEC_ON_CHIP_0_DUAL_MIC,
+	RPC_VOC_CODEC_MAX,
+	RPC_VOC_CODEC_NONE,
+};
+
+enum rpc_audmgr_status_type {
+	RPC_AUDMGR_STATUS_READY,
+	RPC_AUDMGR_STATUS_CODEC_CONFIG,
+	RPC_AUDMGR_STATUS_PENDING,
+	RPC_AUDMGR_STATUS_SUSPEND,
+	RPC_AUDMGR_STATUS_FAILURE,
+	RPC_AUDMGR_STATUS_VOLUME_CHANGE,
+	RPC_AUDMGR_STATUS_DISABLED,
+	RPC_AUDMGR_STATUS_ERROR,
+};
+
+struct rpc_audmgr_enable_client_args {
+	uint32_t set_to_one;
+	uint32_t tx_sample_rate;
+	uint32_t rx_sample_rate;
+	uint32_t def_method;
+	uint32_t codec_type;
+	uint32_t snd_method;
+
+	uint32_t cb_func;
+	uint32_t client_data;
+};
+	
+#define AUDMGR_ENABLE_CLIENT			2
+#define AUDMGR_DISABLE_CLIENT			3
+#define AUDMGR_SUSPEND_EVENT_RSP		4
+#define AUDMGR_REGISTER_OPERATION_LISTENER	5
+#define AUDMGR_UNREGISTER_OPERATION_LISTENER	6
+#define AUDMGR_REGISTER_CODEC_LISTENER		7
+#define AUDMGR_GET_RX_SAMPLE_RATE		8
+#define AUDMGR_GET_TX_SAMPLE_RATE		9
+#define AUDMGR_SET_DEVICE_MODE			10
+
+#define AUDMGR_PROG 0x30000013
+#define AUDMGR_VERS MSM_RPC_VERS(1,0)
+
+struct rpc_audmgr_cb_func_ptr {
+	uint32_t cb_id;
+	uint32_t status; /* Audmgr status */
+	uint32_t set_to_one;  /* Pointer status (1 = valid, 0  = invalid) */
+	uint32_t disc;
+	/* disc = AUDMGR_STATUS_READY => data=handle
+	   disc = AUDMGR_STATUS_CODEC_CONFIG => data = handle
+	   disc = AUDMGR_STATUS_DISABLED => data =status_disabled
+	   disc = AUDMGR_STATUS_VOLUME_CHANGE => data = volume-change */
+	union {
+		uint32_t handle;
+		uint32_t volume;
+		uint32_t status_disabled;
+		uint32_t volume_change;
+	} u;
+};
+
+#define AUDMGR_CB_FUNC_PTR			1
+#define AUDMGR_OPR_LSTNR_CB_FUNC_PTR		2
+#define AUDMGR_CODEC_LSTR_FUNC_PTR		3
+
+#define AUDMGR_CB_PROG 0x31000013
+#define AUDMGR_CB_VERS 0xf8e3e2d9
+
+struct audmgr {
+	wait_queue_head_t wait;
+	uint32_t handle;
+	struct msm_rpc_endpoint *ept;
+	struct task_struct *task;
+	int state;
+};
+
+struct audmgr_config {
+	uint32_t tx_rate;
+	uint32_t rx_rate;
+	uint32_t def_method;
+	uint32_t codec;
+	uint32_t snd_method;
+};
+
+int audmgr_open(struct audmgr *am);
+int audmgr_close(struct audmgr *am);
+int audmgr_enable(struct audmgr *am, struct audmgr_config *cfg);
+int audmgr_disable(struct audmgr *am);
+
+typedef void (*audpp_event_func)(void *private, unsigned id, uint16_t *msg);
+
+int audpp_enable(int id, audpp_event_func func, void *private);
+void audpp_disable(int id, void *private);
+
+int audpp_send_queue1(void *cmd, unsigned len);
+int audpp_send_queue2(void *cmd, unsigned len);
+int audpp_send_queue3(void *cmd, unsigned len);
+
+int audpp_set_volume_and_pan(unsigned id, unsigned volume, int pan);
+int audpp_pause(unsigned id, int pause);
+int audpp_flush(unsigned id);
+void audpp_avsync(int id, unsigned rate);
+unsigned audpp_avsync_sample_count(int id);
+unsigned audpp_avsync_byte_count(int id);
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp5/audpp.c b/arch/arm/mach-msm/qdsp5/audpp.c
new file mode 100644
index 0000000..1616ad0
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audpp.c
@@ -0,0 +1,1014 @@
+
+/* arch/arm/mach-msm/qdsp5/audpp.c
+ *
+ * common code to deal with the AUDPP dsp task (audio postproc)
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2009-2010, 2012 Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <mach/board.h>
+#include <mach/msm_adsp.h>
+
+#include "audmgr.h"
+
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/debug_mm.h>
+
+#include "evlog.h"
+
+enum {
+	EV_NULL,
+	EV_ENABLE,
+	EV_DISABLE,
+	EV_EVENT,
+	EV_DATA,
+};
+
+static const char *dsp_log_strings[] = {
+	"NULL",
+	"ENABLE",
+	"DISABLE",
+	"EVENT",
+	"DATA",
+};
+
+DECLARE_LOG(dsp_log, 64, dsp_log_strings);
+
+static int __init _dsp_log_init(void)
+{
+	return ev_log_init(&dsp_log);
+}
+
+module_init(_dsp_log_init);
+#define LOG(id,arg) ev_log_write(&dsp_log, id, arg)
+
+static DEFINE_MUTEX(audpp_lock);
+static DEFINE_MUTEX(audpp_dec_lock);
+
+#define CH_COUNT 5
+#define AUDPP_CLNT_MAX_COUNT 6
+#define AUDPP_AVSYNC_INFO_SIZE 7
+
+#define AUDPP_SRS_PARAMS 2
+#define AUDPP_SRS_PARAMS_G 0
+#define AUDPP_SRS_PARAMS_W 1
+#define AUDPP_SRS_PARAMS_C 2
+#define AUDPP_SRS_PARAMS_H 3
+#define AUDPP_SRS_PARAMS_P 4
+#define AUDPP_SRS_PARAMS_L 5
+
+#define AUDPP_CMD_CFG_OBJ_UPDATE 0x8000
+#define AUDPP_CMD_EQ_FLAG_DIS	0x0000
+#define AUDPP_CMD_EQ_FLAG_ENA	-1
+#define AUDPP_CMD_IIR_FLAG_DIS	  0x0000
+#define AUDPP_CMD_IIR_FLAG_ENA	  -1
+
+#define AUDPP_CMD_VOLUME_PAN		0
+#define AUDPP_CMD_IIR_TUNING_FILTER	1
+#define AUDPP_CMD_EQUALIZER		2
+#define AUDPP_CMD_ADRC			3
+#define AUDPP_CMD_SPECTROGRAM		4
+#define AUDPP_CMD_QCONCERT		5
+#define AUDPP_CMD_SIDECHAIN_TUNING_FILTER	6
+#define AUDPP_CMD_SAMPLING_FREQUENCY	7
+#define AUDPP_CMD_QAFX			8
+#define AUDPP_CMD_QRUMBLE		9
+#define AUDPP_CMD_MBADRC		10
+
+#define MAX_EVENT_CALLBACK_CLIENTS 	1
+
+#define AUDPP_CONCURRENCY_DEFAULT 6	/* All non tunnel mode */
+#define AUDPP_MAX_DECODER_CNT 5
+#define AUDPP_CODEC_MASK 0x000000FF
+#define AUDPP_MODE_MASK 0x00000F00
+#define AUDPP_OP_MASK 0xF0000000
+
+struct audpp_decoder_info {
+	unsigned int codec;
+	pid_t pid;
+};
+
+struct audpp_state {
+	struct msm_adsp_module *mod;
+	audpp_event_func func[AUDPP_CLNT_MAX_COUNT];
+	void *private[AUDPP_CLNT_MAX_COUNT];
+	struct mutex *lock;
+	unsigned open_count;
+	unsigned enabled;
+
+	/* Related to decoder allocation */
+	struct mutex *lock_dec;
+	struct msm_adspdec_database *dec_database;
+	struct audpp_decoder_info dec_info_table[AUDPP_MAX_DECODER_CNT];
+	unsigned dec_inuse;
+	unsigned long concurrency;
+
+	/* which channels are actually enabled */
+	unsigned avsync_mask;
+
+	/* flags, 48 bits sample/bytes counter per channel */
+	uint16_t avsync[CH_COUNT * AUDPP_CLNT_MAX_COUNT + 1];
+	struct audpp_event_callback *cb_tbl[MAX_EVENT_CALLBACK_CLIENTS];
+
+	spinlock_t avsync_lock;
+
+	wait_queue_head_t event_wait;
+};
+
+struct audpp_state the_audpp_state = {
+	.lock = &audpp_lock,
+	.lock_dec = &audpp_dec_lock,
+};
+
+int audpp_send_queue1(void *cmd, unsigned len)
+{
+	return msm_adsp_write(the_audpp_state.mod,
+			      QDSP_uPAudPPCmd1Queue, cmd, len);
+}
+EXPORT_SYMBOL(audpp_send_queue1);
+
+int audpp_send_queue2(void *cmd, unsigned len)
+{
+	return msm_adsp_write(the_audpp_state.mod,
+			      QDSP_uPAudPPCmd2Queue, cmd, len);
+}
+EXPORT_SYMBOL(audpp_send_queue2);
+
+int audpp_send_queue3(void *cmd, unsigned len)
+{
+	return msm_adsp_write(the_audpp_state.mod,
+			      QDSP_uPAudPPCmd3Queue, cmd, len);
+}
+EXPORT_SYMBOL(audpp_send_queue3);
+
+static int audpp_dsp_config(int enable)
+{
+	audpp_cmd_cfg cmd;
+
+	cmd.cmd_id = AUDPP_CMD_CFG;
+	cmd.cfg = enable ? AUDPP_CMD_CFG_ENABLE : AUDPP_CMD_CFG_SLEEP;
+
+	return audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+int is_audpp_enable(void)
+{
+	struct audpp_state *audpp = &the_audpp_state;
+
+	return audpp->enabled;
+}
+EXPORT_SYMBOL(is_audpp_enable);
+
+int audpp_register_event_callback(struct audpp_event_callback *ecb)
+{
+	struct audpp_state *audpp = &the_audpp_state;
+	int i;
+
+	for (i = 0; i < MAX_EVENT_CALLBACK_CLIENTS; ++i) {
+		if (NULL == audpp->cb_tbl[i]) {
+			audpp->cb_tbl[i] = ecb;
+			return 0;
+		}
+	}
+	return -1;
+}
+EXPORT_SYMBOL(audpp_register_event_callback);
+
+int audpp_unregister_event_callback(struct audpp_event_callback *ecb)
+{
+	struct audpp_state *audpp = &the_audpp_state;
+	int i;
+
+	for (i = 0; i < MAX_EVENT_CALLBACK_CLIENTS; ++i) {
+		if (ecb == audpp->cb_tbl[i]) {
+			audpp->cb_tbl[i] = NULL;
+			return 0;
+		}
+	}
+	return -1;
+}
+EXPORT_SYMBOL(audpp_unregister_event_callback);
+
+static void audpp_broadcast(struct audpp_state *audpp, unsigned id,
+			    uint16_t *msg)
+{
+	unsigned n;
+	for (n = 0; n < AUDPP_CLNT_MAX_COUNT; n++) {
+		if (audpp->func[n])
+			audpp->func[n] (audpp->private[n], id, msg);
+	}
+
+	for (n = 0; n < MAX_EVENT_CALLBACK_CLIENTS; ++n)
+		if (audpp->cb_tbl[n] && audpp->cb_tbl[n]->fn)
+			audpp->cb_tbl[n]->fn(audpp->cb_tbl[n]->private, id,
+					     msg);
+}
+
+static void audpp_notify_clnt(struct audpp_state *audpp, unsigned clnt_id,
+			      unsigned id, uint16_t *msg)
+{
+	if (clnt_id < AUDPP_CLNT_MAX_COUNT && audpp->func[clnt_id])
+		audpp->func[clnt_id] (audpp->private[clnt_id], id, msg);
+}
+
+static void audpp_handle_pcmdmamiss(struct audpp_state *audpp,
+				    uint16_t bit_mask)
+{
+	uint8_t b_index;
+
+	for (b_index = 0; b_index < AUDPP_CLNT_MAX_COUNT; b_index++) {
+		if (bit_mask & (0x1 << b_index))
+			if (audpp->func[b_index])
+				audpp->func[b_index] (audpp->private[b_index],
+						      AUDPP_MSG_PCMDMAMISSED,
+						      &bit_mask);
+	}
+}
+
+static void audpp_fake_event(struct audpp_state *audpp, int id,
+			     unsigned event, unsigned arg)
+{
+	uint16_t msg[1];
+	msg[0] = arg;
+	audpp->func[id] (audpp->private[id], event, msg);
+}
+
+static void audpp_dsp_event(void *data, unsigned id, size_t len,
+			    void (*getevent) (void *ptr, size_t len))
+{
+	struct audpp_state *audpp = data;
+	unsigned long flags;
+	uint16_t msg[8];
+	int cid = 0;
+
+	if (id == AUDPP_MSG_AVSYNC_MSG) {
+		spin_lock_irqsave(&audpp->avsync_lock, flags);
+		getevent(audpp->avsync, sizeof(audpp->avsync));
+
+		/* mask off any channels we're not watching to avoid
+		 * cases where we might get one last update after
+		 * disabling avsync and end up in an odd state when
+		 * we next read...
+		 */
+		audpp->avsync[0] &= audpp->avsync_mask;
+		spin_unlock_irqrestore(&audpp->avsync_lock, flags);
+		return;
+	}
+
+	getevent(msg, sizeof(msg));
+
+	LOG(EV_EVENT, (id << 16) | msg[0]);
+	LOG(EV_DATA, (msg[1] << 16) | msg[2]);
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned cid = msg[0];
+			MM_DBG("status %d %d %d\n", cid, msg[1], msg[2]);
+			if ((cid < 5) && audpp->func[cid])
+				audpp->func[cid] (audpp->private[cid], id, msg);
+			break;
+		}
+	case AUDPP_MSG_HOST_PCM_INTF_MSG:
+		if (audpp->func[5])
+			audpp->func[5] (audpp->private[5], id, msg);
+		break;
+	case AUDPP_MSG_PCMDMAMISSED:
+		audpp_handle_pcmdmamiss(audpp, msg[0]);
+		break;
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			MM_INFO("ENABLE\n");
+			if (!audpp->enabled) {
+				audpp->enabled = 1;
+				audpp_broadcast(audpp, id, msg);
+			} else {
+				cid = msg[1];
+				audpp_fake_event(audpp, cid,
+					id, AUDPP_MSG_ENA_ENA);
+			}
+
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			if (audpp->open_count == 0) {
+				MM_INFO("DISABLE\n");
+				audpp->enabled = 0;
+				wake_up(&audpp->event_wait);
+				audpp_broadcast(audpp, id, msg);
+			} else {
+				cid = msg[1];
+				audpp_fake_event(audpp, cid,
+					id, AUDPP_MSG_ENA_DIS);
+				audpp->func[cid] = NULL;
+				audpp->private[cid] = NULL;
+			}
+		} else {
+			MM_ERR("invalid config msg %d\n", msg[0]);
+		}
+		break;
+	case AUDPP_MSG_ROUTING_ACK:
+		audpp_notify_clnt(audpp, msg[0], id, msg);
+		break;
+	case AUDPP_MSG_FLUSH_ACK:
+		audpp_notify_clnt(audpp, msg[0], id, msg);
+		break;
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable/disable(audpptask)");
+		break;
+	default:
+		MM_ERR("unhandled msg id %x\n", id);
+	}
+}
+
+static struct msm_adsp_ops adsp_ops = {
+	.event = audpp_dsp_event,
+};
+
+int audpp_enable(int id, audpp_event_func func, void *private)
+{
+	struct audpp_state *audpp = &the_audpp_state;
+	uint16_t msg[8];
+	int res = 0;
+
+	if (id < -1 || id > 4)
+		return -EINVAL;
+
+	if (id == -1)
+		id = 5;
+
+	mutex_lock(audpp->lock);
+	if (audpp->func[id]) {
+		res = -EBUSY;
+		goto out;
+	}
+
+	audpp->func[id] = func;
+	audpp->private[id] = private;
+
+	LOG(EV_ENABLE, 1);
+	if (audpp->open_count++ == 0) {
+		MM_DBG("enable\n");
+		res = msm_adsp_get("AUDPPTASK", &audpp->mod, &adsp_ops, audpp);
+		if (res < 0) {
+			MM_ERR("cannot open AUDPPTASK\n");
+			audpp->open_count = 0;
+			audpp->func[id] = NULL;
+			audpp->private[id] = NULL;
+			goto out;
+		}
+		LOG(EV_ENABLE, 2);
+		msm_adsp_enable(audpp->mod);
+		audpp_dsp_config(1);
+	} else {
+		if (audpp->enabled) {
+			msg[0] = AUDPP_MSG_ENA_ENA;
+			msg[1] = id;
+			res = msm_adsp_generate_event(audpp, audpp->mod,
+					 AUDPP_MSG_CFG_MSG, sizeof(msg),
+					 sizeof(uint16_t), (void *)msg);
+			if (res < 0)
+				goto out;
+		}
+	}
+
+	res = 0;
+out:
+	mutex_unlock(audpp->lock);
+	return res;
+}
+EXPORT_SYMBOL(audpp_enable);
+
+void audpp_disable(int id, void *private)
+{
+	struct audpp_state *audpp = &the_audpp_state;
+	uint16_t msg[8];
+	int rc;
+
+	if (id < -1 || id > 4)
+		return;
+
+	if (id == -1)
+		id = 5;
+
+	mutex_lock(audpp->lock);
+	LOG(EV_DISABLE, 1);
+	if (!audpp->func[id])
+		goto out;
+	if (audpp->private[id] != private)
+		goto out;
+
+	msg[0] = AUDPP_MSG_ENA_DIS;
+	msg[1] = id;
+	rc = msm_adsp_generate_event(audpp, audpp->mod,
+				 AUDPP_MSG_CFG_MSG, sizeof(msg),
+				 sizeof(uint16_t), (void *)msg);
+	if (rc < 0)
+		goto out;
+
+	if (--audpp->open_count == 0) {
+		MM_DBG("disable\n");
+		LOG(EV_DISABLE, 2);
+		audpp_dsp_config(0);
+		rc = wait_event_interruptible(audpp->event_wait,
+				(audpp->enabled == 0));
+		if (audpp->enabled == 0)
+			MM_INFO("Received CFG_MSG_DISABLE from ADSP\n");
+		else
+			MM_ERR("Didn't receive CFG_MSG DISABLE \
+					message from ADSP\n");
+		msm_adsp_disable(audpp->mod);
+		msm_adsp_put(audpp->mod);
+		audpp->mod = NULL;
+	}
+out:
+	mutex_unlock(audpp->lock);
+}
+EXPORT_SYMBOL(audpp_disable);
+
+#define BAD_ID(id) ((id < 0) || (id >= CH_COUNT))
+
+void audpp_avsync(int id, unsigned rate)
+{
+	unsigned long flags;
+	audpp_cmd_avsync cmd;
+
+	if (BAD_ID(id))
+		return;
+
+	spin_lock_irqsave(&the_audpp_state.avsync_lock, flags);
+	if (rate)
+		the_audpp_state.avsync_mask |= (1 << id);
+	else
+		the_audpp_state.avsync_mask &= (~(1 << id));
+	the_audpp_state.avsync[0] &= the_audpp_state.avsync_mask;
+	spin_unlock_irqrestore(&the_audpp_state.avsync_lock, flags);
+
+	cmd.cmd_id = AUDPP_CMD_AVSYNC;
+	cmd.object_number = id;
+	cmd.interrupt_interval_lsw = rate;
+	cmd.interrupt_interval_msw = rate >> 16;
+	audpp_send_queue1(&cmd, sizeof(cmd));
+}
+EXPORT_SYMBOL(audpp_avsync);
+
+unsigned audpp_avsync_sample_count(int id)
+{
+	struct audpp_state *audpp = &the_audpp_state;
+	uint16_t *avsync = audpp->avsync;
+	unsigned val;
+	unsigned long flags;
+	unsigned mask;
+
+	if (BAD_ID(id))
+		return 0;
+
+	mask = 1 << id;
+	id = id * AUDPP_AVSYNC_INFO_SIZE + 2;
+	spin_lock_irqsave(&audpp->avsync_lock, flags);
+	if (avsync[0] & mask)
+		val = (avsync[id] << 16) | avsync[id + 1];
+	else
+		val = 0;
+	spin_unlock_irqrestore(&audpp->avsync_lock, flags);
+
+	return val;
+}
+EXPORT_SYMBOL(audpp_avsync_sample_count);
+
+unsigned audpp_avsync_byte_count(int id)
+{
+	struct audpp_state *audpp = &the_audpp_state;
+	uint16_t *avsync = audpp->avsync;
+	unsigned val;
+	unsigned long flags;
+	unsigned mask;
+
+	if (BAD_ID(id))
+		return 0;
+
+	mask = 1 << id;
+	id = id * AUDPP_AVSYNC_INFO_SIZE + 5;
+	spin_lock_irqsave(&audpp->avsync_lock, flags);
+	if (avsync[0] & mask)
+		val = (avsync[id] << 16) | avsync[id + 1];
+	else
+		val = 0;
+	spin_unlock_irqrestore(&audpp->avsync_lock, flags);
+
+	return val;
+}
+EXPORT_SYMBOL(audpp_avsync_byte_count);
+
+int audpp_set_volume_and_pan(unsigned id, unsigned volume, int pan)
+{
+	/* cmd, obj_cfg[7], cmd_type, volume, pan */
+	uint16_t cmd[11];
+
+	if (id > 6)
+		return -EINVAL;
+
+	memset(cmd, 0, sizeof(cmd));
+	cmd[0] = AUDPP_CMD_CFG_OBJECT_PARAMS;
+	cmd[1 + id] = AUDPP_CMD_CFG_OBJ_UPDATE;
+	cmd[8] = AUDPP_CMD_VOLUME_PAN;
+	cmd[9] = volume;
+	cmd[10] = pan;
+
+	return audpp_send_queue3(cmd, sizeof(cmd));
+}
+EXPORT_SYMBOL(audpp_set_volume_and_pan);
+
+/* Implementation of COPP features */
+int audpp_dsp_set_mbadrc(unsigned id, unsigned enable,
+			 audpp_cmd_cfg_object_params_mbadrc *mbadrc)
+{
+	audpp_cmd_cfg_object_params_mbadrc cmd;
+
+	if (id != 6)
+		return -EINVAL;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
+	cmd.common.command_type = AUDPP_CMD_MBADRC;
+
+	if (enable) {
+		memcpy(&cmd.num_bands, &mbadrc->num_bands,
+		       sizeof(*mbadrc) -
+		       (AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2));
+		cmd.enable = AUDPP_CMD_ADRC_FLAG_ENA;
+	} else
+		cmd.enable = AUDPP_CMD_ADRC_FLAG_DIS;
+
+	/*order the writes to mbadrc */
+	dma_coherent_pre_ops();
+	return audpp_send_queue3(&cmd, sizeof(cmd));
+}
+EXPORT_SYMBOL(audpp_dsp_set_mbadrc);
+
+int audpp_dsp_set_qconcert_plus(unsigned id, unsigned enable,
+				audpp_cmd_cfg_object_params_qconcert *
+				qconcert_plus)
+{
+	audpp_cmd_cfg_object_params_qconcert cmd;
+	if (id != 6)
+		return -EINVAL;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
+	cmd.common.command_type = AUDPP_CMD_QCONCERT;
+
+	if (enable) {
+		memcpy(&cmd.op_mode, &qconcert_plus->op_mode,
+		       sizeof(audpp_cmd_cfg_object_params_qconcert) -
+		       (AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2));
+		cmd.enable_flag = AUDPP_CMD_ADRC_FLAG_ENA;
+	} else
+		cmd.enable_flag = AUDPP_CMD_ADRC_FLAG_DIS;
+
+	return audpp_send_queue3(&cmd, sizeof(cmd));
+}
+
+int audpp_dsp_set_rx_iir(unsigned id, unsigned enable,
+			 audpp_cmd_cfg_object_params_pcm *iir)
+{
+	audpp_cmd_cfg_object_params_pcm cmd;
+
+	if (id != 6)
+		return -EINVAL;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
+	cmd.common.command_type = AUDPP_CMD_IIR_TUNING_FILTER;
+
+	if (enable) {
+		cmd.active_flag = AUDPP_CMD_IIR_FLAG_ENA;
+		cmd.num_bands = iir->num_bands;
+		memcpy(&cmd.params_filter, &iir->params_filter,
+		       sizeof(iir->params_filter));
+	} else
+		cmd.active_flag = AUDPP_CMD_IIR_FLAG_DIS;
+
+	return audpp_send_queue3(&cmd, sizeof(cmd));
+}
+EXPORT_SYMBOL(audpp_dsp_set_rx_iir);
+
+int audpp_dsp_set_rx_srs_trumedia_g(
+	struct audpp_cmd_cfg_object_params_srstm_g *srstm)
+{
+	struct audpp_cmd_cfg_object_params_srstm_g cmd;
+
+	MM_DBG("%s\n", __func__);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_SRS_PARAMS;
+	cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
+	cmd.common.command_type = AUDPP_SRS_PARAMS_G;
+
+	memcpy(cmd.v, srstm->v, sizeof(srstm->v));
+
+	return audpp_send_queue3(&cmd, sizeof(cmd));
+}
+EXPORT_SYMBOL(audpp_dsp_set_rx_srs_trumedia_g);
+
+int audpp_dsp_set_rx_srs_trumedia_w(
+	struct audpp_cmd_cfg_object_params_srstm_w *srstm)
+{
+	struct audpp_cmd_cfg_object_params_srstm_w cmd;
+
+	MM_DBG("%s\n", __func__);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_SRS_PARAMS;
+	cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
+	cmd.common.command_type = AUDPP_SRS_PARAMS_W;
+
+	memcpy(cmd.v, srstm->v, sizeof(srstm->v));
+
+	return audpp_send_queue3(&cmd, sizeof(cmd));
+}
+EXPORT_SYMBOL(audpp_dsp_set_rx_srs_trumedia_w);
+
+int audpp_dsp_set_rx_srs_trumedia_c(
+	struct audpp_cmd_cfg_object_params_srstm_c *srstm)
+{
+	struct audpp_cmd_cfg_object_params_srstm_c cmd;
+
+	MM_DBG("%s\n", __func__);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_SRS_PARAMS;
+	cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
+	cmd.common.command_type = AUDPP_SRS_PARAMS_C;
+
+	memcpy(cmd.v, srstm->v, sizeof(srstm->v));
+
+	return audpp_send_queue3(&cmd, sizeof(cmd));
+}
+EXPORT_SYMBOL(audpp_dsp_set_rx_srs_trumedia_c);
+
+int audpp_dsp_set_rx_srs_trumedia_h(
+	struct audpp_cmd_cfg_object_params_srstm_h *srstm)
+{
+	struct audpp_cmd_cfg_object_params_srstm_h cmd;
+
+	MM_DBG("%s\n", __func__);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_SRS_PARAMS;
+	cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
+	cmd.common.command_type = AUDPP_SRS_PARAMS_H;
+
+	memcpy(cmd.v, srstm->v, sizeof(srstm->v));
+
+	return audpp_send_queue3(&cmd, sizeof(cmd));
+}
+EXPORT_SYMBOL(audpp_dsp_set_rx_srs_trumedia_h);
+
+int audpp_dsp_set_rx_srs_trumedia_p(
+	struct audpp_cmd_cfg_object_params_srstm_p *srstm)
+{
+	struct audpp_cmd_cfg_object_params_srstm_p cmd;
+
+	MM_DBG("%s\n", __func__);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_SRS_PARAMS;
+	cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
+	cmd.common.command_type = AUDPP_SRS_PARAMS_P;
+
+	memcpy(cmd.v, srstm->v, sizeof(srstm->v));
+
+	return audpp_send_queue3(&cmd, sizeof(cmd));
+}
+EXPORT_SYMBOL(audpp_dsp_set_rx_srs_trumedia_p);
+
+int audpp_dsp_set_rx_srs_trumedia_l(
+	struct audpp_cmd_cfg_object_params_srstm_l *srstm)
+{
+	struct audpp_cmd_cfg_object_params_srstm_l cmd;
+
+	MM_DBG("%s\n", __func__);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_SRS_PARAMS;
+	cmd.common.comman_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
+	cmd.common.command_type = AUDPP_SRS_PARAMS_L;
+
+	memcpy(cmd.v, srstm->v, sizeof(srstm->v));
+
+	return audpp_send_queue3(&cmd, sizeof(cmd));
+}
+EXPORT_SYMBOL(audpp_dsp_set_rx_srs_trumedia_l);
+
+/* Implementation Of COPP + POPP */
+int audpp_dsp_set_eq(unsigned id, unsigned enable,
+		     audpp_cmd_cfg_object_params_eqalizer *eq)
+{
+	audpp_cmd_cfg_object_params_eqalizer cmd;
+	unsigned short *id_ptr = (unsigned short *)&cmd;
+
+	if (id > 6 || id == 5)
+		return -EINVAL;
+
+	memset(&cmd, 0, sizeof(cmd));
+	id_ptr[1 + id] = AUDPP_CMD_CFG_OBJ_UPDATE;
+	cmd.common.command_type = AUDPP_CMD_EQUALIZER;
+
+	if (enable) {
+		cmd.eq_flag = AUDPP_CMD_EQ_FLAG_ENA;
+		cmd.num_bands = eq->num_bands;
+		memcpy(&cmd.eq_coeff, &eq->eq_coeff, sizeof(eq->eq_coeff));
+	} else
+		cmd.eq_flag = AUDPP_CMD_EQ_FLAG_DIS;
+
+	return audpp_send_queue3(&cmd, sizeof(cmd));
+}
+EXPORT_SYMBOL(audpp_dsp_set_eq);
+
+int audpp_dsp_set_vol_pan(unsigned id,
+			  audpp_cmd_cfg_object_params_volume *vol_pan)
+{
+	audpp_cmd_cfg_object_params_volume cmd;
+	unsigned short *id_ptr = (unsigned short *)&cmd;
+
+	if (id > 6)
+		return -EINVAL;
+
+	memset(&cmd, 0, sizeof(cmd));
+	id_ptr[1 + id] = AUDPP_CMD_CFG_OBJ_UPDATE;
+	cmd.common.command_type = AUDPP_CMD_VOLUME_PAN;
+
+	cmd.volume = vol_pan->volume;
+	cmd.pan = vol_pan->pan;
+
+	return audpp_send_queue3(&cmd, sizeof(cmd));
+}
+EXPORT_SYMBOL(audpp_dsp_set_vol_pan);
+
+int audpp_pause(unsigned id, int pause)
+{
+	/* pause 1 = pause 0 = resume */
+	u16 pause_cmd[AUDPP_CMD_DEC_CTRL_LEN / sizeof(unsigned short)];
+
+	if (id >= CH_COUNT)
+		return -EINVAL;
+
+	memset(pause_cmd, 0, sizeof(pause_cmd));
+
+	pause_cmd[0] = AUDPP_CMD_DEC_CTRL;
+	if (pause == 1)
+		pause_cmd[1 + id] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_PAUSE_V;
+	else if (pause == 0)
+		pause_cmd[1 + id] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_RESUME_V;
+	else
+		return -EINVAL;
+
+	return audpp_send_queue1(pause_cmd, sizeof(pause_cmd));
+}
+EXPORT_SYMBOL(audpp_pause);
+
+int audpp_flush(unsigned id)
+{
+	u16 flush_cmd[AUDPP_CMD_DEC_CTRL_LEN / sizeof(unsigned short)];
+
+	if (id >= CH_COUNT)
+		return -EINVAL;
+
+	memset(flush_cmd, 0, sizeof(flush_cmd));
+
+	flush_cmd[0] = AUDPP_CMD_DEC_CTRL;
+	flush_cmd[1 + id] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_FLUSH_V;
+
+	return audpp_send_queue1(flush_cmd, sizeof(flush_cmd));
+}
+EXPORT_SYMBOL(audpp_flush);
+
+/* dec_attrb = 7:0, 0 - No Decoder, else supported decoder *
+ * like mp3, aac, wma etc ... *
+ *           =  15:8, bit[8] = 1 - Tunnel, bit[9] = 1 - NonTunnel *
+ *           =  31:16, reserved */
+int audpp_adec_alloc(unsigned dec_attrb, const char **module_name,
+		     unsigned *queueid)
+{
+	struct audpp_state *audpp = &the_audpp_state;
+	int decid = -1, idx, lidx, mode, codec;
+	int codecs_supported, min_codecs_supported;
+	unsigned int *concurrency_entry;
+	mutex_lock(audpp->lock_dec);
+	/* Represents in bit mask */
+	mode = ((dec_attrb & AUDPP_MODE_MASK) << 16);
+	codec = (1 << (dec_attrb & AUDPP_CODEC_MASK));
+	/* Point to Last entry of the row */
+	concurrency_entry = ((audpp->dec_database->dec_concurrency_table +
+			      ((audpp->concurrency + 1) *
+			       (audpp->dec_database->num_dec))) - 1);
+
+	lidx = audpp->dec_database->num_dec;
+	min_codecs_supported = sizeof(unsigned int) * 8;
+
+	MM_DBG("mode = 0x%08x codec = 0x%08x\n", mode, codec);
+
+	for (idx = lidx; idx > 0; idx--, concurrency_entry--) {
+		if (!(audpp->dec_inuse & (1 << (idx - 1)))) {
+			if ((mode & *concurrency_entry) &&
+			    (codec & *concurrency_entry)) {
+				/* Check supports minimum number codecs */
+				codecs_supported =
+				    audpp->dec_database->dec_info_list[idx -
+								       1].
+				    nr_codec_support;
+				if (codecs_supported < min_codecs_supported) {
+					lidx = idx - 1;
+					min_codecs_supported = codecs_supported;
+				}
+			}
+		}
+	}
+
+	if (lidx < audpp->dec_database->num_dec) {
+		audpp->dec_inuse |= (1 << lidx);
+		*module_name =
+		    audpp->dec_database->dec_info_list[lidx].module_name;
+		*queueid =
+		    audpp->dec_database->dec_info_list[lidx].module_queueid;
+		decid = audpp->dec_database->dec_info_list[lidx].module_decid;
+		audpp->dec_info_table[lidx].codec =
+		    (dec_attrb & AUDPP_CODEC_MASK);
+		audpp->dec_info_table[lidx].pid = current->pid;
+		/* point to row to get supported operation */
+		concurrency_entry =
+		    ((audpp->dec_database->dec_concurrency_table +
+		      ((audpp->concurrency) * (audpp->dec_database->num_dec))) +
+		     lidx);
+		decid |= ((*concurrency_entry & AUDPP_OP_MASK) >> 12);
+		MM_INFO("decid =0x%08x module_name=%s, queueid=%d \n",
+			decid, *module_name, *queueid);
+	}
+	mutex_unlock(audpp->lock_dec);
+	return decid;
+
+}
+EXPORT_SYMBOL(audpp_adec_alloc);
+
+void audpp_adec_free(int decid)
+{
+	struct audpp_state *audpp = &the_audpp_state;
+	int idx;
+	mutex_lock(audpp->lock_dec);
+	for (idx = audpp->dec_database->num_dec; idx > 0; idx--) {
+		if (audpp->dec_database->dec_info_list[idx - 1].module_decid ==
+		    decid) {
+			audpp->dec_inuse &= ~(1 << (idx - 1));
+			audpp->dec_info_table[idx - 1].codec = -1;
+			audpp->dec_info_table[idx - 1].pid = 0;
+			MM_INFO("free decid =%d \n", decid);
+			break;
+		}
+	}
+	mutex_unlock(audpp->lock_dec);
+	return;
+
+}
+EXPORT_SYMBOL(audpp_adec_free);
+
+static ssize_t concurrency_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct audpp_state *audpp = &the_audpp_state;
+	int rc;
+	mutex_lock(audpp->lock_dec);
+	rc = sprintf(buf, "%ld\n", audpp->concurrency);
+	mutex_unlock(audpp->lock_dec);
+	return rc;
+}
+
+static ssize_t concurrency_store(struct device *dev,
+				 struct device_attribute *attr,
+				 const char *buf, size_t count)
+{
+	struct audpp_state *audpp = &the_audpp_state;
+	unsigned long concurrency;
+	int rc = -1;
+	mutex_lock(audpp->lock_dec);
+	if (audpp->dec_inuse) {
+		MM_ERR("Can not change profile, while playback in progress\n");
+		goto done;
+	}
+	rc = strict_strtoul(buf, 10, &concurrency);
+	if (!rc &&
+		(concurrency < audpp->dec_database->num_concurrency_support)) {
+		audpp->concurrency = concurrency;
+		MM_DBG("Concurrency case %ld\n", audpp->concurrency);
+		rc = count;
+	} else {
+		MM_ERR("Not a valid Concurrency case\n");
+		rc = -EINVAL;
+	}
+done:
+	mutex_unlock(audpp->lock_dec);
+	return rc;
+}
+
+static ssize_t decoder_info_show(struct device *dev,
+				 struct device_attribute *attr, char *buf);
+static struct device_attribute dev_attr_decoder[AUDPP_MAX_DECODER_CNT] = {
+	__ATTR(decoder0, S_IRUGO, decoder_info_show, NULL),
+	__ATTR(decoder1, S_IRUGO, decoder_info_show, NULL),
+	__ATTR(decoder2, S_IRUGO, decoder_info_show, NULL),
+	__ATTR(decoder3, S_IRUGO, decoder_info_show, NULL),
+	__ATTR(decoder4, S_IRUGO, decoder_info_show, NULL),
+};
+
+static ssize_t decoder_info_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	int cpy_sz = 0;
+	struct audpp_state *audpp = &the_audpp_state;
+	const ptrdiff_t off = attr - dev_attr_decoder;	/* decoder number */
+	mutex_lock(audpp->lock_dec);
+	cpy_sz += scnprintf(buf + cpy_sz, PAGE_SIZE - cpy_sz, "%d:",
+			    audpp->dec_info_table[off].codec);
+	cpy_sz += scnprintf(buf + cpy_sz, PAGE_SIZE - cpy_sz, "%d\n",
+			    audpp->dec_info_table[off].pid);
+	mutex_unlock(audpp->lock_dec);
+	return cpy_sz;
+}
+
+static DEVICE_ATTR(concurrency, S_IWUSR | S_IRUGO, concurrency_show,
+	    concurrency_store);
+static int audpp_probe(struct platform_device *pdev)
+{
+	int rc, idx;
+	struct audpp_state *audpp = &the_audpp_state;
+	audpp->concurrency = AUDPP_CONCURRENCY_DEFAULT;
+	audpp->dec_database =
+	    (struct msm_adspdec_database *)pdev->dev.platform_data;
+
+	MM_INFO("Number of decoder supported %d\n",
+			audpp->dec_database->num_dec);
+	MM_INFO("Number of concurrency supported %d\n",
+			audpp->dec_database->num_concurrency_support);
+
+	init_waitqueue_head(&audpp->event_wait);
+
+	spin_lock_init(&audpp->avsync_lock);
+
+	for (idx = 0; idx < audpp->dec_database->num_dec; idx++) {
+		audpp->dec_info_table[idx].codec = -1;
+		audpp->dec_info_table[idx].pid = 0;
+		MM_INFO("module_name:%s\n",
+			audpp->dec_database->dec_info_list[idx].module_name);
+		MM_INFO("queueid:%d\n",
+			audpp->dec_database->dec_info_list[idx].module_queueid);
+		MM_INFO("decid:%d\n",
+			audpp->dec_database->dec_info_list[idx].module_decid);
+		MM_INFO("nr_codec_support:%d\n",
+			audpp->dec_database->dec_info_list[idx].
+			nr_codec_support);
+	}
+
+	for (idx = 0; idx < audpp->dec_database->num_dec; idx++) {
+		rc = device_create_file(&pdev->dev, &dev_attr_decoder[idx]);
+		if (rc)
+			goto err;
+	}
+	rc = device_create_file(&pdev->dev, &dev_attr_concurrency);
+	if (rc)
+		goto err;
+	else
+		goto done;
+err:
+	while (idx--)
+		device_remove_file(&pdev->dev, &dev_attr_decoder[idx]);
+done:
+	return rc;
+}
+
+static struct platform_driver audpp_plat_driver = {
+	.probe = audpp_probe,
+	.driver = {
+		   .name = "msm_adspdec",
+		   .owner = THIS_MODULE,
+		   },
+};
+
+static int __init audpp_init(void)
+{
+	return platform_driver_register(&audpp_plat_driver);
+}
+
+device_initcall(audpp_init);
diff --git a/arch/arm/mach-msm/qdsp5/audpreproc.c b/arch/arm/mach-msm/qdsp5/audpreproc.c
new file mode 100644
index 0000000..230429f
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audpreproc.c
@@ -0,0 +1,169 @@
+/*
+ * Common code to deal with the AUDPREPROC dsp task (audio preprocessing)
+ *
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * Based on the audpp layer in arch/arm/mach-msm/qdsp5/audpp.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <mach/msm_adsp.h>
+#include <mach/debug_mm.h>
+#include <mach/qdsp5/qdsp5audpreproc.h>
+#include <mach/qdsp5/qdsp5audreccmdi.h>
+
+static DEFINE_MUTEX(audpreproc_lock);
+
+struct msm_adspenc_info {
+	const char *module_name;
+	unsigned module_queueids;
+	int module_encid; /* streamid */
+	int enc_formats; /* supported formats */
+	int nr_codec_support; /* number of codec suported */
+};
+
+#define ENC_MODULE_INFO(name, queueids, encid, formats, nr_codec) \
+	{.module_name = name, .module_queueids = queueids, \
+	 .module_encid = encid, .enc_formats = formats, \
+	 .nr_codec_support = nr_codec }
+
+#ifdef CONFIG_MSM7X27A_AUDIO
+#define ENC0_FORMAT ((1<<AUDREC_CMD_TYPE_1_INDEX_SBC)| \
+		(1<<AUDREC_CMD_TYPE_0_INDEX_AAC)| \
+		(1<<AUDREC_CMD_TYPE_0_INDEX_AMRNB)| \
+		(1<<AUDREC_CMD_TYPE_0_INDEX_EVRC)| \
+		(1<<AUDREC_CMD_TYPE_0_INDEX_QCELP))
+
+#define ENC1_FORMAT (1<<AUDREC_CMD_TYPE_0_INDEX_WAV)
+#else
+#define ENC0_FORMAT ((1<<AUDREC_CMD_TYPE_0_INDEX_WAV)| \
+		(1<<AUDREC_CMD_TYPE_1_INDEX_SBC)| \
+		(1<<AUDREC_CMD_TYPE_0_INDEX_AAC)| \
+		(1<<AUDREC_CMD_TYPE_0_INDEX_AMRNB)| \
+		(1<<AUDREC_CMD_TYPE_0_INDEX_EVRC)| \
+		(1<<AUDREC_CMD_TYPE_0_INDEX_QCELP))
+#endif
+
+struct msm_adspenc_database {
+	unsigned num_enc;
+	struct msm_adspenc_info *enc_info_list;
+};
+
+#ifdef CONFIG_MSM7X27A_AUDIO
+static struct msm_adspenc_info enc_info_list[] = {
+	ENC_MODULE_INFO("AUDRECTASK", \
+			((QDSP_uPAudRecBitStreamQueue << 16)| \
+			  QDSP_uPAudRecCmdQueue), 0, \
+			(ENC0_FORMAT | (1 << MSM_ADSP_ENC_MODE_TUNNEL) | \
+			(1 << MSM_ADSP_ENC_MODE_NON_TUNNEL)), 5),
+
+	ENC_MODULE_INFO("AUDREC1TASK", \
+			((QDSP_uPAudRec1BitStreamQueue << 16)| \
+			  QDSP_uPAudRec1CmdQueue), 1, \
+			(ENC1_FORMAT | (1 << MSM_ADSP_ENC_MODE_TUNNEL)), 1),
+};
+#else
+static struct msm_adspenc_info enc_info_list[] = {
+	ENC_MODULE_INFO("AUDRECTASK",
+			((QDSP_uPAudRecBitStreamQueue << 16)| \
+			  QDSP_uPAudRecCmdQueue), 0, \
+			(ENC0_FORMAT | (1 << MSM_ADSP_ENC_MODE_TUNNEL)), 6),
+};
+#endif
+
+static struct msm_adspenc_database msm_enc_database = {
+	.num_enc = ARRAY_SIZE(enc_info_list),
+	.enc_info_list = enc_info_list,
+};
+
+struct audpreproc_state {
+	struct msm_adsp_module *mod;
+	struct mutex *lock;
+	unsigned open_count;
+	unsigned enc_inuse;
+};
+
+static struct audpreproc_state the_audpreproc_state = {
+	.lock = &audpreproc_lock,
+};
+
+/* enc_type = supported encode format *
+ * like pcm, aac, sbc, evrc, qcelp, amrnb etc ... *
+ */
+int audpreproc_aenc_alloc(unsigned enc_type, const char **module_name,
+		     unsigned *queue_ids)
+{
+	struct audpreproc_state *audpreproc = &the_audpreproc_state;
+	int encid = -1, idx, lidx, mode, codec;
+	int codecs_supported, min_codecs_supported;
+
+	mutex_lock(audpreproc->lock);
+	/* Represents in bit mask */
+	mode = ((enc_type & AUDPREPROC_MODE_MASK) << 16);
+	codec = (1 << (enc_type & AUDPREPROC_CODEC_MASK));
+
+	lidx = msm_enc_database.num_enc;
+	min_codecs_supported = sizeof(unsigned int) * 8;
+	MM_DBG("mode = 0x%08x codec = 0x%08x\n", mode, codec);
+
+	for (idx = lidx-1; idx >= 0; idx--) {
+		/* encoder free and supports the format */
+		if (!(audpreproc->enc_inuse & (1 << (idx))) &&
+		((mode & msm_enc_database.enc_info_list[idx].enc_formats)
+		== mode) && ((codec &
+		msm_enc_database.enc_info_list[idx].enc_formats)
+		== codec)){
+			/* Check supports minimum number codecs */
+			codecs_supported =
+			msm_enc_database.enc_info_list[idx].nr_codec_support;
+			if (codecs_supported < min_codecs_supported) {
+				lidx = idx;
+				min_codecs_supported = codecs_supported;
+			}
+		}
+	}
+
+	if (lidx < msm_enc_database.num_enc) {
+		audpreproc->enc_inuse |= (1 << lidx);
+		*module_name =
+		    msm_enc_database.enc_info_list[lidx].module_name;
+		*queue_ids =
+		    msm_enc_database.enc_info_list[lidx].module_queueids;
+		encid = msm_enc_database.enc_info_list[lidx].module_encid;
+	}
+
+	mutex_unlock(audpreproc->lock);
+	return encid;
+}
+EXPORT_SYMBOL(audpreproc_aenc_alloc);
+
+void audpreproc_aenc_free(int enc_id)
+{
+	struct audpreproc_state *audpreproc = &the_audpreproc_state;
+	int idx;
+
+	mutex_lock(audpreproc->lock);
+	for (idx = 0; idx < msm_enc_database.num_enc; idx++) {
+		if (msm_enc_database.enc_info_list[idx].module_encid ==
+		    enc_id) {
+			audpreproc->enc_inuse &= ~(1 << idx);
+			break;
+		}
+	}
+	mutex_unlock(audpreproc->lock);
+	return;
+
+}
+EXPORT_SYMBOL(audpreproc_aenc_free);
diff --git a/arch/arm/mach-msm/qdsp5/audrec.c b/arch/arm/mach-msm/qdsp5/audrec.c
new file mode 100644
index 0000000..d5cb168
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audrec.c
@@ -0,0 +1,272 @@
+/* arch/arm/mach-msm/qdsp5/audrec.c
+ *
+ * common code to deal with the AUDREC dsp task (audio recording)
+ *
+ * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * Based on the audpp layer in arch/arm/mach-msm/qdsp5/audpp.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ *
+ * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <mach/msm_adsp.h>
+
+#include <mach/qdsp5/qdsp5audreccmdi.h>
+#include <mach/qdsp5/qdsp5audrecmsg.h>
+
+#include "audmgr.h"
+#include <mach/debug_mm.h>
+
+static DEFINE_MUTEX(audrec_lock);
+
+#define MAX_ENC_COUNT 8 /* Max encoder supported */
+
+#define ENC_SESSION_FREE 0
+#define ENC_SESSION_ACTIVE 1
+
+struct enc_session {
+	unsigned enc_type;  /* Param to identify type of encoder */
+	unsigned audrec_obj_idx;  /* Param to identify REC_OBJ or Session ID */
+	audrec_event_func event_func; /* Event Call back
+					routine for the encoder */
+	void *private;	/* private data element passed as
+				part of Event Call back  routine */
+	unsigned state; /* Current state of the encoder session ,
+				free, active*/
+};
+
+struct audrec_state {
+	struct msm_adsp_module *audrec_mod;
+	struct enc_session enc_session[MAX_ENC_COUNT];
+	struct mutex *lock;
+	unsigned enc_count;
+};
+
+struct audrec_state the_audrec_state = {
+	.lock = &audrec_lock,
+};
+
+int audrectask_send_cmdqueue(void *cmd, unsigned len)
+{
+	return msm_adsp_write(the_audrec_state.audrec_mod,
+				QDSP_uPAudRecCmdQueue, cmd, len);
+}
+EXPORT_SYMBOL(audrectask_send_cmdqueue);
+
+int audrectask_send_bitstreamqueue(void *cmd, unsigned len)
+{
+	return msm_adsp_write(the_audrec_state.audrec_mod,
+				QDSP_uPAudRecBitStreamQueue, cmd, len);
+}
+EXPORT_SYMBOL(audrectask_send_bitstreamqueue);
+
+static void audrectask_dsp_event(void *data, unsigned id, size_t len,
+			    void (*getevent)(void *ptr, size_t len))
+{
+	struct audrec_state *audrec = data;
+	int cnt;
+	uint16_t msg[5]; /* Max size of message */
+	getevent(msg, len);
+
+	switch (id) {
+	case AUDREC_MSG_CMD_CFG_DONE_MSG: {
+		MM_DBG("CMD CFG DONE %x\n", msg[1]);
+		if (msg[0] & AUDREC_MSG_CFG_DONE_ENC_ENA) {
+			for (cnt = 0; cnt < MAX_ENC_COUNT ; cnt++) {
+				if (audrec->enc_session[cnt].enc_type ==
+					(msg[0] & AUDREC_CMD_ENC_TYPE_MASK)) {
+					audrec->enc_session[cnt].audrec_obj_idx
+					 = msg[1];
+					audrec->enc_session[cnt].event_func(
+					audrec->enc_session[cnt].private, id,
+					msg);
+					break;
+				}
+			}
+		} else {
+			for (cnt = 0; cnt < MAX_ENC_COUNT ; cnt++) {
+				if (audrec->enc_session[cnt].enc_type ==
+					(msg[0] & AUDREC_CMD_ENC_TYPE_MASK)) {
+					audrec->enc_session[cnt].event_func(
+					audrec->enc_session[cnt].private, id,
+					msg);
+					audrec->enc_session[cnt].audrec_obj_idx
+					= 0xFFFFFFFF;
+					audrec->enc_session[cnt].state
+					= ENC_SESSION_FREE;
+					audrec->enc_session[cnt].enc_type
+					= 0xFFFFFFFF;
+					audrec->enc_session[cnt].event_func
+					= NULL;
+					audrec->enc_session[cnt].private
+					= NULL;
+					break;
+				}
+			}
+		}
+		break;
+	}
+	case AUDREC_MSG_CMD_AREC_MEM_CFG_DONE_MSG: {
+		MM_DBG("CMD AREC MEM CFG DONE %x\n", msg[0]);
+		for (cnt = 0; cnt < MAX_ENC_COUNT ; cnt++) {
+			if (audrec->enc_session[cnt].audrec_obj_idx ==
+				msg[0]) {
+				audrec->enc_session[cnt].event_func(
+				audrec->enc_session[cnt].private, id, msg);
+				break;
+			}
+		}
+		break;
+	}
+	case AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG: {
+		MM_DBG("CMD AREC PARAM CFG DONE %x\n", msg[0]);
+		for (cnt = 0; cnt < MAX_ENC_COUNT ; cnt++) {
+			if (audrec->enc_session[cnt].audrec_obj_idx ==
+				msg[0]) {
+				audrec->enc_session[cnt].event_func(
+				audrec->enc_session[cnt].private, id, msg);
+				break;
+			}
+		}
+		break;
+	}
+	case AUDREC_MSG_PACKET_READY_MSG: {
+		MM_DBG("PCK READY %x\n", msg[0]);
+		for (cnt = 0; cnt < MAX_ENC_COUNT ; cnt++) {
+			if (audrec->enc_session[cnt].audrec_obj_idx ==
+				msg[0]) {
+				audrec->enc_session[cnt].event_func(
+				audrec->enc_session[cnt].private, id, msg);
+				break;
+			}
+		}
+		break;
+	}
+	case AUDREC_MSG_FATAL_ERR_MSG: {
+		MM_ERR("ERROR %x\n", msg[0]);
+		if (msg[1] & AUDREC_MSG_FATAL_ERR_TYPE_0) {
+			for (cnt = 0; cnt < MAX_ENC_COUNT ; cnt++) {
+				if (audrec->enc_session[cnt].audrec_obj_idx ==
+					msg[0]) {
+					audrec->enc_session[cnt].event_func(
+					audrec->enc_session[cnt].private, id,
+					msg);
+				break;
+				}
+			}
+		} else if (msg[1] & AUDREC_MSG_FATAL_ERR_TYPE_1) {
+			cnt = audrec->enc_count-1;
+			if (audrec->enc_session[cnt].event_func)
+				audrec->enc_session[cnt].event_func(
+				audrec->enc_session[cnt].private, id,
+				msg);
+		}
+		break;
+	}
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module \
+				enable/disable(audrectask)\n");
+		break;
+	default:
+		MM_ERR("unknown event %d\n", id);
+	}
+}
+
+static struct msm_adsp_ops adsp_ops = {
+	.event = audrectask_dsp_event,
+};
+
+int audrectask_enable(unsigned enc_type, audrec_event_func func, void *private)
+{
+	struct audrec_state *audrec = &the_audrec_state;
+	int cnt, rc = 0;
+
+	mutex_lock(audrec->lock);
+
+	if (audrec->enc_count++ == 0) {
+		MM_DBG("enable\n");
+		for (cnt = 0; cnt < MAX_ENC_COUNT ; cnt++) {
+			if (audrec->enc_session[cnt].state ==
+				ENC_SESSION_FREE) {
+				audrec->enc_session[cnt].state =
+				ENC_SESSION_ACTIVE;
+				audrec->enc_session[cnt].enc_type = enc_type;
+				audrec->enc_session[cnt].event_func = func;
+				audrec->enc_session[cnt].private = private;
+				break;
+			}
+		}
+		rc = msm_adsp_get("AUDRECTASK", &audrec->audrec_mod, &adsp_ops,
+					audrec);
+		if (rc < 0) {
+			MM_ERR("cannot open AUDRECTASK\n");
+			audrec->enc_count = 0;
+			audrec->enc_session[cnt].state = ENC_SESSION_FREE;
+			audrec->enc_session[cnt].enc_type = 0xFFFFFFFF;
+			audrec->enc_session[cnt].event_func = NULL;
+			audrec->enc_session[cnt].private = NULL;
+			goto out;
+		}
+		msm_adsp_enable(audrec->audrec_mod);
+	} else {
+		for (cnt = 0; cnt < MAX_ENC_COUNT ; cnt++) {
+			if (audrec->enc_session[cnt].state ==
+				ENC_SESSION_FREE) {
+				audrec->enc_session[cnt].state =
+				ENC_SESSION_ACTIVE;
+				audrec->enc_session[cnt].enc_type = enc_type;
+				audrec->enc_session[cnt].event_func = func;
+				audrec->enc_session[cnt].private = private;
+				break;
+			}
+		}
+	}
+	if (cnt == MAX_ENC_COUNT)
+		rc = -EBUSY;
+	else
+		rc = 0;
+
+out:
+	mutex_unlock(audrec->lock);
+	return rc;
+}
+EXPORT_SYMBOL(audrectask_enable);
+
+void audrectask_disable(unsigned enc_type, void *private)
+{
+	struct audrec_state *audrec = &the_audrec_state;
+
+	mutex_lock(audrec->lock);
+
+	if (--audrec->enc_count == 0) {
+		MM_DBG("\n"); /* Macro prints the file name and function */
+		msm_adsp_disable(audrec->audrec_mod);
+		msm_adsp_put(audrec->audrec_mod);
+		audrec->audrec_mod = NULL;
+	}
+
+	mutex_unlock(audrec->lock);
+}
+EXPORT_SYMBOL(audrectask_disable);
+
diff --git a/arch/arm/mach-msm/qdsp5/dsp_debug.c b/arch/arm/mach-msm/qdsp5/dsp_debug.c
new file mode 100644
index 0000000..331ba00
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/dsp_debug.c
@@ -0,0 +1,235 @@
+/* Copyright (c) 2011, Code Aurora Forum. 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.
+ *
+ */
+
+#include <asm/atomic.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/io.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+
+#include <mach/debug_mm.h>
+#include <mach/msm_iomap.h>
+
+#include "dsp_debug.h"
+
+static wait_queue_head_t dsp_wait;
+static int dsp_has_crashed;
+static int dsp_wait_count;
+
+static atomic_t dsp_crash_count = ATOMIC_INIT(0);
+static dsp_state_cb cb_ptr;
+
+#define MAX_LEN 64
+#define HDR_LEN 20
+#define NUM_DSP_RAM_BANKS 3
+
+static char l_buf[MAX_LEN];
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *dsp_dentry;
+#endif
+
+void q5audio_dsp_not_responding(void)
+{
+	if (cb_ptr)
+		cb_ptr(DSP_STATE_CRASHED);
+
+	MM_DBG("entered q5audio_dsp_not_responding\n");
+	if (atomic_add_return(1, &dsp_crash_count) != 1) {
+		MM_ERR("q5audio_dsp_not_responding() \
+			- parking additional crasher...\n");
+		for (;;)
+			msleep(1000);
+	}
+	if (dsp_wait_count) {
+		dsp_has_crashed = 1;
+		wake_up(&dsp_wait);
+
+		while (dsp_has_crashed != 2)
+			wait_event(dsp_wait, dsp_has_crashed == 2);
+	} else {
+		MM_ERR("q5audio_dsp_not_responding() - no waiter?\n");
+	}
+
+	if (cb_ptr)
+		cb_ptr(DSP_STATE_CRASH_DUMP_DONE);
+}
+
+static int dsp_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static ssize_t dsp_write(struct file *file, const char __user *buf,
+			 size_t count, loff_t *pos)
+{
+	char cmd[32];
+
+	if (count >= sizeof(cmd))
+		return -EINVAL;
+	if (copy_from_user(cmd, buf, count))
+		return -EFAULT;
+	cmd[count] = 0;
+
+	if ((count > 1) && (cmd[count-1] == '\n'))
+		cmd[count-1] = 0;
+
+	if (!strncmp(cmd, "wait-for-crash", sizeof("wait-for-crash"))) {
+		while (!dsp_has_crashed) {
+			int res;
+			dsp_wait_count++;
+			res = wait_event_interruptible(dsp_wait,
+							dsp_has_crashed);
+			if (res < 0) {
+				dsp_wait_count--;
+				return res;
+			}
+		}
+	} else if (!strncmp(cmd, "boom", sizeof("boom"))) {
+		q5audio_dsp_not_responding();
+	} else if (!strncmp(cmd, "continue-crash", sizeof("continue-crash"))) {
+		dsp_has_crashed = 2;
+		wake_up(&dsp_wait);
+	} else {
+		MM_ERR("[%s:%s] unknown dsp_debug command: %s\n", __MM_FILE__,
+				__func__, cmd);
+	}
+
+	return count;
+}
+
+static ssize_t dsp_read(struct file *file, char __user *buf,
+			size_t count, loff_t *pos)
+{
+	size_t actual = 0;
+	static void *dsp_addr;
+	static unsigned copy_ok_count;
+
+	MM_INFO("pos = %lld\n", *pos);
+	if (*pos >= DSP_RAM_SIZE * NUM_DSP_RAM_BANKS)
+		return 0;
+
+	if (*pos == 0)
+		dsp_addr = (*pos + RAMA_BASE);
+	else if (*pos == DSP_RAM_SIZE)
+		dsp_addr = RAMB_BASE;
+	else if (*pos >= DSP_RAM_SIZE * 2)
+		dsp_addr = RAMC_BASE;
+
+	MM_INFO("dsp_addr = %p\n", dsp_addr);
+	while (count >= PAGE_SIZE) {
+		if (copy_to_user(buf, dsp_addr, PAGE_SIZE)) {
+			MM_ERR("[%s:%s] copy error @ %p\n", __MM_FILE__,
+					__func__, buf);
+			return -EFAULT;
+		}
+		copy_ok_count += PAGE_SIZE;
+		dsp_addr = (char *)dsp_addr + PAGE_SIZE;
+		buf += PAGE_SIZE;
+		actual += PAGE_SIZE;
+		count -= PAGE_SIZE;
+	}
+
+	*pos += actual;
+	return actual;
+}
+
+static int dsp_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+int dsp_debug_register(dsp_state_cb ptr)
+{
+	if (ptr == NULL)
+		return -EINVAL;
+
+	cb_ptr = ptr;
+
+	return 0;
+}
+
+static const struct file_operations dsp_fops = {
+	.owner		= THIS_MODULE,
+	.open		= dsp_open,
+	.read		= dsp_read,
+	.write		= dsp_write,
+	.release	= dsp_release,
+};
+
+#ifdef CONFIG_DEBUG_FS
+static struct miscdevice dsp_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "dsp_debug",
+	.fops	= &dsp_fops,
+};
+#endif
+
+static ssize_t dsp_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	MM_DBG("adsp debugfs opened\n");
+	return 0;
+}
+
+static ssize_t dsp_debug_write(struct file *file, const char __user *buf,
+					size_t count, loff_t *ppos)
+{
+	int len;
+
+	if (count < 0)
+		return 0;
+	len = count > (MAX_LEN - 1) ? (MAX_LEN - 1) : count;
+	if (copy_from_user(l_buf + HDR_LEN, buf, len)) {
+		MM_ERR("Unable to copy data from user space\n");
+		return -EFAULT;
+	}
+	l_buf[len + HDR_LEN] = 0;
+	if (l_buf[len + HDR_LEN - 1] == '\n') {
+		l_buf[len + HDR_LEN - 1] = 0;
+		len--;
+	}
+	if (!strncmp(l_buf + HDR_LEN, "boom", 64)) {
+		q5audio_dsp_not_responding();
+	} else if (!strncmp(l_buf + HDR_LEN, "continue-crash",
+				sizeof("continue-crash"))) {
+		dsp_has_crashed = 2;
+		wake_up(&dsp_wait);
+	} else
+		MM_ERR("Unknown command\n");
+
+	return count;
+}
+static const struct file_operations dsp_debug_fops = {
+	.write = dsp_debug_write,
+	.open = dsp_debug_open,
+};
+
+static int __init dsp_init(void)
+{
+	init_waitqueue_head(&dsp_wait);
+#ifdef CONFIG_DEBUG_FS
+	dsp_dentry = debugfs_create_file("dsp_debug", S_IFREG | S_IRUGO,
+			NULL, (void *) NULL, &dsp_debug_fops);
+
+	return misc_register(&dsp_misc);
+#else
+	return 0;
+#endif /* CONFIG_DEBUG_FS */
+}
+
+device_initcall(dsp_init);
diff --git a/arch/arm/mach-msm/qdsp5/dsp_debug.h b/arch/arm/mach-msm/qdsp5/dsp_debug.h
new file mode 100644
index 0000000..bd40682
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/dsp_debug.h
@@ -0,0 +1,28 @@
+/* Copyright (c) 2011, Code Aurora Forum. 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 __DSP_DEBUG_H_
+#define __DSP_DEBUG_H_
+
+typedef int (*dsp_state_cb)(int state);
+int dsp_debug_register(dsp_state_cb ptr);
+
+#define DSP_STATE_CRASHED         0x0
+#define DSP_STATE_CRASH_DUMP_DONE 0x1
+
+#define RAMA_BASE MSM_AD5_BASE
+#define RAMB_BASE ((RAMA_BASE) + (0x200000))
+#define RAMC_BASE ((RAMB_BASE) + (0x200000))
+#define DSP_RAM_SIZE 0x40000
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp5/evlog.h b/arch/arm/mach-msm/qdsp5/evlog.h
new file mode 100644
index 0000000..1f0f16b
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/evlog.h
@@ -0,0 +1,125 @@
+/* arch/arm/mach-msm/qdsp5/evlog.h
+ *
+ * simple event log debugging facility
+ *
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/hrtimer.h>
+#include <linux/debugfs.h>
+
+#define EV_LOG_ENTRY_NAME(n) n##_entry
+
+#define DECLARE_LOG(_name, _size, _str) \
+static struct ev_entry EV_LOG_ENTRY_NAME(_name)[_size]; \
+static struct ev_log _name = { \
+	.name = #_name, \
+	.strings = _str, \
+	.num_strings = ARRAY_SIZE(_str), \
+	.entry = EV_LOG_ENTRY_NAME(_name), \
+	.max = ARRAY_SIZE(EV_LOG_ENTRY_NAME(_name)), \
+}
+
+struct ev_entry {
+	struct timespec when;
+	uint32_t id;
+	uint32_t arg;
+};
+	
+struct ev_log {
+	struct ev_entry *entry;
+	unsigned max;
+	unsigned next;
+	unsigned fault;
+	const char **strings;
+	unsigned num_strings;
+	const char *name;
+};
+
+static char ev_buf[4096];
+
+static ssize_t ev_log_read(struct file *file, char __user *buf,
+			   size_t count, loff_t *ppos)
+{
+	struct ev_log *log = file->private_data;
+	struct ev_entry *entry;
+	unsigned long flags;
+	int size = 0;
+	unsigned n, id, max;
+	struct timespec now, t;
+	
+	max = log->max;
+	getnstimeofday(&now);
+	local_irq_save(flags);
+	n = (log->next - 1) & (max - 1);
+	entry = log->entry;
+	while (n != log->next) {
+		t = timespec_sub(now, entry[n].when);
+		id = entry[n].id;
+		if (id) {
+			const char *str;
+			if (id < log->num_strings)
+				str = log->strings[id];
+			else
+				str = "UNKNOWN";
+			size += scnprintf(ev_buf + size, 4096 - size,
+					  "%lu.%03lu %08x %s\n",
+					  t.tv_sec, t.tv_nsec / 1000000,
+					  entry[n].arg, str);
+		}
+		n = (n - 1) & (max - 1);
+	}
+	log->fault = 0;
+	local_irq_restore(flags);
+	return simple_read_from_buffer(buf, count, ppos, ev_buf, size);
+}
+
+static void ev_log_write(struct ev_log *log, unsigned id, unsigned arg)
+{
+	struct ev_entry *entry;
+	unsigned long flags;
+	local_irq_save(flags);
+
+	if (log->fault) {
+		if (log->fault == 1)
+			goto done;
+		log->fault--;
+	}
+
+	entry = log->entry + log->next;
+	getnstimeofday(&entry->when);
+	entry->id = id;
+	entry->arg = arg;
+	log->next = (log->next + 1) & (log->max - 1);
+done:
+	local_irq_restore(flags);
+}
+
+static int ev_log_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static const struct file_operations ev_log_ops = {
+	.read = ev_log_read,
+	.open = ev_log_open,
+};
+
+static int ev_log_init(struct ev_log *log)
+{
+	debugfs_create_file(log->name, 0444, 0, log, &ev_log_ops);
+	return 0;
+}
+
diff --git a/arch/arm/mach-msm/qdsp5/snd.c b/arch/arm/mach-msm/qdsp5/snd.c
new file mode 100644
index 0000000..f1db012
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/snd.c
@@ -0,0 +1,675 @@
+/* arch/arm/mach-msm/qdsp5/snd.c
+ *
+ * interface to "snd" service on the baseband cpu
+ *
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2009, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <linux/msm_audio.h>
+#include <linux/seq_file.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <mach/board.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/debug_mm.h>
+
+struct snd_ctxt {
+	struct mutex lock;
+	int opened;
+	struct msm_rpc_endpoint *ept;
+	struct msm_snd_endpoints *snd_epts;
+};
+
+struct snd_sys_ctxt {
+	struct mutex lock;
+	struct msm_rpc_endpoint *ept;
+};
+
+static struct snd_sys_ctxt the_snd_sys;
+
+static struct snd_ctxt the_snd;
+
+#define RPC_SND_PROG	0x30000002
+#define RPC_SND_CB_PROG	0x31000002
+
+#define RPC_SND_VERS                    0x00020001
+#define RPC_SND_VERS2                    0x00030001
+
+#define SND_SET_DEVICE_PROC 2
+#define SND_SET_VOLUME_PROC 3
+#define SND_AVC_CTL_PROC 29
+#define SND_AGC_CTL_PROC 30
+
+struct rpc_snd_set_device_args {
+	uint32_t device;
+	uint32_t ear_mute;
+	uint32_t mic_mute;
+
+	uint32_t cb_func;
+	uint32_t client_data;
+};
+
+struct rpc_snd_set_volume_args {
+	uint32_t device;
+	uint32_t method;
+	uint32_t volume;
+
+	uint32_t cb_func;
+	uint32_t client_data;
+};
+
+struct rpc_snd_avc_ctl_args {
+	uint32_t avc_ctl;
+	uint32_t cb_func;
+	uint32_t client_data;
+};
+
+struct rpc_snd_agc_ctl_args {
+	uint32_t agc_ctl;
+	uint32_t cb_func;
+	uint32_t client_data;
+};
+
+struct snd_set_device_msg {
+	struct rpc_request_hdr hdr;
+	struct rpc_snd_set_device_args args;
+};
+
+struct snd_set_volume_msg {
+	struct rpc_request_hdr hdr;
+	struct rpc_snd_set_volume_args args;
+};
+
+struct snd_avc_ctl_msg {
+	struct rpc_request_hdr hdr;
+	struct rpc_snd_avc_ctl_args args;
+};
+
+struct snd_agc_ctl_msg {
+	struct rpc_request_hdr hdr;
+	struct rpc_snd_agc_ctl_args args;
+};
+
+struct snd_endpoint *get_snd_endpoints(int *size);
+
+static inline int check_mute(int mute)
+{
+	return (mute == SND_MUTE_MUTED ||
+		mute == SND_MUTE_UNMUTED) ? 0 : -EINVAL;
+}
+
+static int get_endpoint(struct snd_ctxt *snd, unsigned long arg)
+{
+	int rc = 0, index;
+	struct msm_snd_endpoint ept;
+
+	if (copy_from_user(&ept, (void __user *)arg, sizeof(ept))) {
+		MM_ERR("snd_ioctl get endpoint: invalid read pointer\n");
+		return -EFAULT;
+	}
+
+	index = ept.id;
+	if (index < 0 || index >= snd->snd_epts->num) {
+		MM_ERR("snd_ioctl get endpoint: invalid index!\n");
+		return -EINVAL;
+	}
+
+	ept.id = snd->snd_epts->endpoints[index].id;
+	strncpy(ept.name,
+		snd->snd_epts->endpoints[index].name,
+		sizeof(ept.name));
+
+	if (copy_to_user((void __user *)arg, &ept, sizeof(ept))) {
+		MM_ERR("snd_ioctl get endpoint: invalid write pointer\n");
+		rc = -EFAULT;
+	}
+
+	return rc;
+}
+
+static long snd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct snd_set_device_msg dmsg;
+	struct snd_set_volume_msg vmsg;
+	struct snd_avc_ctl_msg avc_msg;
+	struct snd_agc_ctl_msg agc_msg;
+
+	struct msm_snd_device_config dev;
+	struct msm_snd_volume_config vol;
+	struct snd_ctxt *snd = file->private_data;
+	int rc = 0;
+
+	uint32_t avc, agc;
+
+	mutex_lock(&snd->lock);
+	switch (cmd) {
+	case SND_SET_DEVICE:
+		if (copy_from_user(&dev, (void __user *) arg, sizeof(dev))) {
+			MM_ERR("set device: invalid pointer\n");
+			rc = -EFAULT;
+			break;
+		}
+
+		dmsg.args.device = cpu_to_be32(dev.device);
+		dmsg.args.ear_mute = cpu_to_be32(dev.ear_mute);
+		dmsg.args.mic_mute = cpu_to_be32(dev.mic_mute);
+		if (check_mute(dev.ear_mute) < 0 ||
+				check_mute(dev.mic_mute) < 0) {
+			MM_ERR("set device: invalid mute status\n");
+			rc = -EINVAL;
+			break;
+		}
+		dmsg.args.cb_func = -1;
+		dmsg.args.client_data = 0;
+
+		MM_INFO("snd_set_device %d %d %d\n", dev.device,
+				dev.ear_mute, dev.mic_mute);
+
+		rc = msm_rpc_call(snd->ept,
+			SND_SET_DEVICE_PROC,
+			&dmsg, sizeof(dmsg), 5 * HZ);
+		break;
+
+	case SND_SET_VOLUME:
+		if (copy_from_user(&vol, (void __user *) arg, sizeof(vol))) {
+			MM_ERR("set volume: invalid pointer\n");
+			rc = -EFAULT;
+			break;
+		}
+
+		vmsg.args.device = cpu_to_be32(vol.device);
+		vmsg.args.method = cpu_to_be32(vol.method);
+		if (vol.method != SND_METHOD_VOICE) {
+			MM_ERR("set volume: invalid method\n");
+			rc = -EINVAL;
+			break;
+		}
+
+		vmsg.args.volume = cpu_to_be32(vol.volume);
+		vmsg.args.cb_func = -1;
+		vmsg.args.client_data = 0;
+
+		MM_INFO("snd_set_volume %d %d %d\n", vol.device,
+				vol.method, vol.volume);
+
+		rc = msm_rpc_call(snd->ept,
+			SND_SET_VOLUME_PROC,
+			&vmsg, sizeof(vmsg), 5 * HZ);
+		break;
+
+	case SND_AVC_CTL:
+		if (get_user(avc, (uint32_t __user *) arg)) {
+			rc = -EFAULT;
+			break;
+		} else if ((avc != 1) && (avc != 0)) {
+			rc = -EINVAL;
+			break;
+		}
+
+		avc_msg.args.avc_ctl = cpu_to_be32(avc);
+		avc_msg.args.cb_func = -1;
+		avc_msg.args.client_data = 0;
+
+		MM_INFO("snd_avc_ctl %d\n", avc);
+
+		rc = msm_rpc_call(snd->ept,
+			SND_AVC_CTL_PROC,
+			&avc_msg, sizeof(avc_msg), 5 * HZ);
+		break;
+
+	case SND_AGC_CTL:
+		if (get_user(agc, (uint32_t __user *) arg)) {
+			rc = -EFAULT;
+			break;
+		} else if ((agc != 1) && (agc != 0)) {
+			rc = -EINVAL;
+			break;
+		}
+		agc_msg.args.agc_ctl = cpu_to_be32(agc);
+		agc_msg.args.cb_func = -1;
+		agc_msg.args.client_data = 0;
+
+		MM_INFO("snd_agc_ctl %d\n", agc);
+
+		rc = msm_rpc_call(snd->ept,
+			SND_AGC_CTL_PROC,
+			&agc_msg, sizeof(agc_msg), 5 * HZ);
+		break;
+
+	case SND_GET_NUM_ENDPOINTS:
+		if (copy_to_user((void __user *)arg,
+				&snd->snd_epts->num, sizeof(unsigned))) {
+			MM_ERR("get endpoint: invalid pointer\n");
+			rc = -EFAULT;
+		}
+		break;
+
+	case SND_GET_ENDPOINT:
+		rc = get_endpoint(snd, arg);
+		break;
+
+	default:
+		MM_ERR("unknown command\n");
+		rc = -EINVAL;
+		break;
+	}
+	mutex_unlock(&snd->lock);
+
+	return rc;
+}
+
+static int snd_release(struct inode *inode, struct file *file)
+{
+	struct snd_ctxt *snd = file->private_data;
+	int rc;
+
+	mutex_lock(&snd->lock);
+	rc = msm_rpc_close(snd->ept);
+	if (rc < 0)
+		MM_ERR("msm_rpc_close failed\n");
+	snd->ept = NULL;
+	snd->opened = 0;
+	mutex_unlock(&snd->lock);
+	return 0;
+}
+static int snd_sys_release(void)
+{
+	struct snd_sys_ctxt *snd_sys = &the_snd_sys;
+	int rc = 0;
+
+	mutex_lock(&snd_sys->lock);
+	rc = msm_rpc_close(snd_sys->ept);
+	if (rc < 0)
+		MM_ERR("msm_rpc_close failed\n");
+	snd_sys->ept = NULL;
+	mutex_unlock(&snd_sys->lock);
+	return rc;
+}
+static int snd_open(struct inode *inode, struct file *file)
+{
+	struct snd_ctxt *snd = &the_snd;
+	int rc = 0;
+
+	mutex_lock(&snd->lock);
+	if (snd->opened == 0) {
+		if (snd->ept == NULL) {
+			snd->ept = msm_rpc_connect_compatible(RPC_SND_PROG,
+					RPC_SND_VERS, 0);
+			if (IS_ERR(snd->ept)) {
+				MM_DBG("connect failed with current VERS \
+					= %x, trying again with another API\n",
+					RPC_SND_VERS2);
+				snd->ept =
+					msm_rpc_connect_compatible(RPC_SND_PROG,
+							RPC_SND_VERS2, 0);
+			}
+			if (IS_ERR(snd->ept)) {
+				rc = PTR_ERR(snd->ept);
+				snd->ept = NULL;
+				MM_ERR("failed to connect snd svc\n");
+				goto err;
+			}
+		}
+		file->private_data = snd;
+		snd->opened = 1;
+	} else {
+		MM_ERR("snd already opened\n");
+		rc = -EBUSY;
+	}
+
+err:
+	mutex_unlock(&snd->lock);
+	return rc;
+}
+static int snd_sys_open(void)
+{
+	struct snd_sys_ctxt *snd_sys = &the_snd_sys;
+	int rc = 0;
+
+	mutex_lock(&snd_sys->lock);
+	if (snd_sys->ept == NULL) {
+		snd_sys->ept = msm_rpc_connect_compatible(RPC_SND_PROG,
+			RPC_SND_VERS, 0);
+		if (IS_ERR(snd_sys->ept)) {
+			MM_DBG("connect failed with current VERS \
+				= %x, trying again with another API\n",
+				RPC_SND_VERS2);
+			snd_sys->ept = msm_rpc_connect_compatible(RPC_SND_PROG,
+					RPC_SND_VERS2, 0);
+		}
+		if (IS_ERR(snd_sys->ept)) {
+			rc = PTR_ERR(snd_sys->ept);
+			snd_sys->ept = NULL;
+			MM_ERR("failed to connect snd svc\n");
+			goto err;
+		}
+	} else
+		MM_DBG("snd already opened\n");
+
+err:
+	mutex_unlock(&snd_sys->lock);
+	return rc;
+}
+
+static struct file_operations snd_fops = {
+	.owner		= THIS_MODULE,
+	.open		= snd_open,
+	.release	= snd_release,
+	.unlocked_ioctl	= snd_ioctl,
+};
+
+struct miscdevice snd_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_snd",
+	.fops	= &snd_fops,
+};
+
+static long snd_agc_enable(unsigned long arg)
+{
+	struct snd_sys_ctxt *snd_sys = &the_snd_sys;
+	struct snd_agc_ctl_msg agc_msg;
+	int rc = 0;
+
+	if ((arg != 1) && (arg != 0))
+		return -EINVAL;
+
+	agc_msg.args.agc_ctl = cpu_to_be32(arg);
+	agc_msg.args.cb_func = -1;
+	agc_msg.args.client_data = 0;
+
+	MM_DBG("snd_agc_ctl %ld,%d\n", arg, agc_msg.args.agc_ctl);
+
+	rc = msm_rpc_call(snd_sys->ept,
+		SND_AGC_CTL_PROC,
+		&agc_msg, sizeof(agc_msg), 5 * HZ);
+	return rc;
+}
+
+static long snd_avc_enable(unsigned long arg)
+{
+	struct snd_sys_ctxt *snd_sys = &the_snd_sys;
+	struct snd_avc_ctl_msg avc_msg;
+	int rc = 0;
+
+	if ((arg != 1) && (arg != 0))
+		return -EINVAL;
+
+	avc_msg.args.avc_ctl = cpu_to_be32(arg);
+
+	avc_msg.args.cb_func = -1;
+	avc_msg.args.client_data = 0;
+
+	MM_DBG("snd_avc_ctl %ld,%d\n", arg, avc_msg.args.avc_ctl);
+
+	rc = msm_rpc_call(snd_sys->ept,
+		SND_AVC_CTL_PROC,
+		&avc_msg, sizeof(avc_msg), 5 * HZ);
+	return rc;
+}
+
+static ssize_t snd_agc_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	ssize_t status;
+	struct snd_sys_ctxt *snd_sys = &the_snd_sys;
+	int rc = 0;
+
+	rc = snd_sys_open();
+	if (rc)
+		return rc;
+
+	mutex_lock(&snd_sys->lock);
+
+	if (sysfs_streq(buf, "enable"))
+		status = snd_agc_enable(1);
+	else if (sysfs_streq(buf, "disable"))
+		status = snd_agc_enable(0);
+	else
+		status = -EINVAL;
+
+	mutex_unlock(&snd_sys->lock);
+	rc = snd_sys_release();
+	if (rc)
+		return rc;
+
+	return status ? : size;
+}
+
+static ssize_t snd_avc_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	ssize_t status;
+	struct snd_sys_ctxt *snd_sys = &the_snd_sys;
+	int rc = 0;
+
+	rc = snd_sys_open();
+	if (rc)
+		return rc;
+
+	mutex_lock(&snd_sys->lock);
+
+	if (sysfs_streq(buf, "enable"))
+		status = snd_avc_enable(1);
+	else if (sysfs_streq(buf, "disable"))
+		status = snd_avc_enable(0);
+	else
+		status = -EINVAL;
+
+	mutex_unlock(&snd_sys->lock);
+	rc = snd_sys_release();
+	if (rc)
+		return rc;
+
+	return status ? : size;
+}
+
+static long snd_vol_enable(const char *arg)
+{
+	struct snd_sys_ctxt *snd_sys = &the_snd_sys;
+	struct snd_set_volume_msg vmsg;
+	struct msm_snd_volume_config vol;
+	int rc = 0;
+
+	rc = sscanf(arg, "%d %d %d", &vol.device, &vol.method, &vol.volume);
+	if (rc != 3) {
+		MM_ERR("Invalid arguments. Usage: <device> <method> \
+				<volume>\n");
+		rc = -EINVAL;
+		return rc;
+	}
+
+	vmsg.args.device = cpu_to_be32(vol.device);
+	vmsg.args.method = cpu_to_be32(vol.method);
+	if (vol.method != SND_METHOD_VOICE) {
+		MM_ERR("snd_ioctl set volume: invalid method\n");
+		rc = -EINVAL;
+		return rc;
+	}
+
+	vmsg.args.volume = cpu_to_be32(vol.volume);
+	vmsg.args.cb_func = -1;
+	vmsg.args.client_data = 0;
+
+	MM_DBG("snd_set_volume %d %d %d\n", vol.device, vol.method,
+			vol.volume);
+
+	rc = msm_rpc_call(snd_sys->ept,
+		SND_SET_VOLUME_PROC,
+		&vmsg, sizeof(vmsg), 5 * HZ);
+	return rc;
+}
+
+static long snd_dev_enable(const char *arg)
+{
+	struct snd_sys_ctxt *snd_sys = &the_snd_sys;
+	struct snd_set_device_msg dmsg;
+	struct msm_snd_device_config dev;
+	int rc = 0;
+
+	rc = sscanf(arg, "%d %d %d", &dev.device, &dev.ear_mute, &dev.mic_mute);
+	if (rc != 3) {
+		MM_ERR("Invalid arguments. Usage: <device> <ear_mute> \
+				<mic_mute>\n");
+		rc = -EINVAL;
+		return rc;
+	}
+	dmsg.args.device = cpu_to_be32(dev.device);
+	dmsg.args.ear_mute = cpu_to_be32(dev.ear_mute);
+	dmsg.args.mic_mute = cpu_to_be32(dev.mic_mute);
+	if (check_mute(dev.ear_mute) < 0 ||
+			check_mute(dev.mic_mute) < 0) {
+		MM_ERR("snd_ioctl set device: invalid mute status\n");
+		rc = -EINVAL;
+		return rc;
+	}
+	dmsg.args.cb_func = -1;
+	dmsg.args.client_data = 0;
+
+	MM_INFO("snd_set_device %d %d %d\n", dev.device, dev.ear_mute,
+			dev.mic_mute);
+
+	rc = msm_rpc_call(snd_sys->ept,
+		SND_SET_DEVICE_PROC,
+		&dmsg, sizeof(dmsg), 5 * HZ);
+	return rc;
+}
+
+static ssize_t snd_dev_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	ssize_t status;
+	struct snd_sys_ctxt *snd_sys = &the_snd_sys;
+	int rc = 0;
+
+	rc = snd_sys_open();
+	if (rc)
+		return rc;
+
+	mutex_lock(&snd_sys->lock);
+	status = snd_dev_enable(buf);
+	mutex_unlock(&snd_sys->lock);
+
+	rc = snd_sys_release();
+	if (rc)
+		return rc;
+
+	return status ? : size;
+}
+
+static ssize_t snd_vol_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	ssize_t status;
+	struct snd_sys_ctxt *snd_sys = &the_snd_sys;
+	int rc = 0;
+
+	rc = snd_sys_open();
+	if (rc)
+		return rc;
+
+	mutex_lock(&snd_sys->lock);
+	status = snd_vol_enable(buf);
+	mutex_unlock(&snd_sys->lock);
+
+	rc = snd_sys_release();
+	if (rc)
+		return rc;
+
+	return status ? : size;
+}
+
+static DEVICE_ATTR(agc, S_IWUSR | S_IRUGO,
+		NULL, snd_agc_store);
+
+static DEVICE_ATTR(avc, S_IWUSR | S_IRUGO,
+		NULL, snd_avc_store);
+
+static DEVICE_ATTR(device, S_IWUSR | S_IRUGO,
+		NULL, snd_dev_store);
+
+static DEVICE_ATTR(volume, S_IWUSR | S_IRUGO,
+		NULL, snd_vol_store);
+
+static int snd_probe(struct platform_device *pdev)
+{
+	struct snd_ctxt *snd = &the_snd;
+	struct snd_sys_ctxt *snd_sys = &the_snd_sys;
+	int rc = 0;
+
+	mutex_init(&snd->lock);
+	mutex_init(&snd_sys->lock);
+	snd_sys->ept = NULL;
+	snd->snd_epts = (struct msm_snd_endpoints *)pdev->dev.platform_data;
+	rc = misc_register(&snd_misc);
+	if (rc)
+		return rc;
+
+	rc = device_create_file(snd_misc.this_device, &dev_attr_agc);
+	if (rc) {
+		misc_deregister(&snd_misc);
+		return rc;
+	}
+
+	rc = device_create_file(snd_misc.this_device, &dev_attr_avc);
+	if (rc) {
+		device_remove_file(snd_misc.this_device,
+						&dev_attr_agc);
+		misc_deregister(&snd_misc);
+		return rc;
+	}
+
+	rc = device_create_file(snd_misc.this_device, &dev_attr_device);
+	if (rc) {
+		device_remove_file(snd_misc.this_device,
+						&dev_attr_agc);
+		device_remove_file(snd_misc.this_device,
+						&dev_attr_avc);
+		misc_deregister(&snd_misc);
+		return rc;
+	}
+
+	rc = device_create_file(snd_misc.this_device, &dev_attr_volume);
+	if (rc) {
+		device_remove_file(snd_misc.this_device,
+						&dev_attr_agc);
+		device_remove_file(snd_misc.this_device,
+						&dev_attr_avc);
+		device_remove_file(snd_misc.this_device,
+						&dev_attr_device);
+		misc_deregister(&snd_misc);
+	}
+
+	return rc;
+}
+
+static struct platform_driver snd_plat_driver = {
+	.probe = snd_probe,
+	.driver = {
+		.name = "msm_snd",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init snd_init(void)
+{
+	return platform_driver_register(&snd_plat_driver);
+}
+
+module_init(snd_init);
diff --git a/arch/arm/mach-msm/qdsp5/snd_adie.c b/arch/arm/mach-msm/qdsp5/snd_adie.c
new file mode 100644
index 0000000..ba7efc3
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/snd_adie.c
@@ -0,0 +1,480 @@
+/* Copyright (c) 2009, 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/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <mach/msm_rpcrouter.h>
+#include <linux/debugfs.h>
+#include <mach/qdsp5/snd_adie.h>
+#include <mach/debug_mm.h>
+
+static struct adie_svc_client adie_client[ADIE_SVC_MAX_CLIENTS];
+static DEFINE_MUTEX(adie_client_lock);
+
+static int adie_svc_process_cb(struct msm_rpc_client *client,
+				 void *buffer, int in_size)
+{
+	int rc, id;
+	uint32_t accept_status;
+	struct rpc_request_hdr *req;
+	struct adie_svc_client_register_cb_cb_args arg, *buf_ptr;
+
+	req = (struct rpc_request_hdr *)buffer;
+	for (id = 0; id < ADIE_SVC_MAX_CLIENTS; id++) {
+		if (adie_client[id].rpc_client == client)
+			break;
+	}
+	if (id == ADIE_SVC_MAX_CLIENTS) {
+		MM_ERR("RPC reply with invalid rpc client\n");
+		accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
+		goto err;
+	}
+
+	buf_ptr = (struct adie_svc_client_register_cb_cb_args *)(req + 1);
+	arg.cb_id		= be32_to_cpu(buf_ptr->cb_id);
+	arg.size		= be32_to_cpu(buf_ptr->size);
+	arg.client_id		= be32_to_cpu(buf_ptr->client_id);
+	arg.adie_block		= be32_to_cpu(buf_ptr->adie_block);
+	arg.status		= be32_to_cpu(buf_ptr->status);
+	arg.client_operation	= be32_to_cpu(buf_ptr->client_operation);
+
+	if (arg.cb_id != adie_client[id].cb_id) {
+		MM_ERR("RPC reply with invalid invalid cb_id\n");
+		accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
+		goto err;
+	}
+
+	mutex_lock(&adie_client[id].lock);
+	switch (arg.client_operation) {
+	case ADIE_SVC_REGISTER_CLIENT:
+		MM_DBG("ADIE_SVC_REGISTER_CLIENT callback\n");
+		adie_client[id].client_id = arg.client_id;
+		break;
+	case ADIE_SVC_DEREGISTER_CLIENT:
+		MM_DBG("ADIE_SVC_DEREGISTER_CLIENT callback\n");
+		break;
+	case ADIE_SVC_CONFIG_ADIE_BLOCK:
+		MM_DBG("ADIE_SVC_CONFIG_ADIE_BLOCK callback\n");
+		if (adie_client[id].client_id != arg.client_id) {
+			mutex_unlock(&adie_client[id].lock);
+			accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
+			goto err;
+		}
+		break;
+	default:
+		accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
+		goto err;
+	}
+
+	adie_client[id].status = arg.status;
+	adie_client[id].adie_svc_cb_done = 1;
+	mutex_unlock(&adie_client[id].lock);
+	wake_up(&adie_client[id].wq);
+	accept_status = RPC_ACCEPTSTAT_SUCCESS;
+
+err:
+	msm_rpc_start_accepted_reply(client, be32_to_cpu(req->xid),
+				     accept_status);
+	rc = msm_rpc_send_accepted_reply(client, 0);
+	if (rc)
+		MM_ERR("%s: send accepted reply failed: %d\n", __func__, rc);
+
+	return rc;
+}
+
+static int adie_svc_rpc_cb_func(struct msm_rpc_client *client,
+			    void *buffer, int in_size)
+{
+	int rc = 0;
+	struct rpc_request_hdr *req;
+
+	req = (struct rpc_request_hdr *)buffer;
+
+	MM_DBG("procedure received to rpc cb %d\n",
+			be32_to_cpu(req->procedure));
+	switch (be32_to_cpu(req->procedure)) {
+	case ADIE_SVC_CLIENT_STATUS_FUNC_PTR_TYPE_PROC:
+		rc = adie_svc_process_cb(client, buffer, in_size);
+		break;
+	default:
+		MM_ERR("%s: procedure not supported %d\n", __func__,
+		       be32_to_cpu(req->procedure));
+		msm_rpc_start_accepted_reply(client, be32_to_cpu(req->xid),
+					     RPC_ACCEPTSTAT_PROC_UNAVAIL);
+		rc = msm_rpc_send_accepted_reply(client, 0);
+		if (rc)
+			MM_ERR("%s: sending reply failed: %d\n", __func__, rc);
+		break;
+	}
+	return rc;
+}
+
+static int adie_svc_client_register_arg(struct msm_rpc_client *client,
+		void *buf, void *data)
+{
+	struct adie_svc_client_register_cb_args *arg;
+
+	arg = (struct adie_svc_client_register_cb_args *)data;
+
+	*((int *)buf) = cpu_to_be32((int)arg->cb_id);
+	return sizeof(int);
+}
+
+static int adie_svc_client_deregister_arg(struct msm_rpc_client *client,
+		void *buf, void *data)
+{
+	struct adie_svc_client_deregister_cb_args *arg;
+
+	arg = (struct adie_svc_client_deregister_cb_args *)data;
+
+	*((int *)buf) = cpu_to_be32(arg->client_id);
+	return sizeof(int);
+}
+
+static int adie_svc_config_adie_block_arg(struct msm_rpc_client *client,
+		void *buf, void *data)
+{
+	struct adie_svc_config_adie_block_cb_args *arg;
+	int size = 0;
+
+	arg = (struct adie_svc_config_adie_block_cb_args *)data;
+
+	*((int *)buf) = cpu_to_be32(arg->client_id);
+	size += sizeof(int);
+	buf += sizeof(int);
+
+	*((int *)buf) = cpu_to_be32(arg->adie_block);
+	size += sizeof(int);
+	buf += sizeof(int);
+
+	*((int *)buf) = cpu_to_be32(arg->config);
+	size += sizeof(int);
+
+	return size;
+}
+
+/* Returns : client id on success
+ *           and -1 on failure
+ */
+int adie_svc_get(void)
+{
+	int id, rc = 0;
+	struct adie_svc_client_register_cb_args arg;
+
+	mutex_lock(&adie_client_lock);
+	for (id = 0; id < ADIE_SVC_MAX_CLIENTS; id++) {
+		if (adie_client[id].client_id == -1 &&
+				adie_client[id].rpc_client == NULL)
+			break;
+	}
+	if (id == ADIE_SVC_MAX_CLIENTS) {
+		mutex_unlock(&adie_client_lock);
+		return -1;
+	}
+
+	mutex_lock(&adie_client[id].lock);
+	adie_client[id].rpc_client = msm_rpc_register_client("adie_client",
+							ADIE_SVC_PROG,
+							ADIE_SVC_VERS, 1,
+							adie_svc_rpc_cb_func);
+	if (IS_ERR(adie_client[id].rpc_client)) {
+		MM_ERR("Failed to register RPC client\n");
+		adie_client[id].rpc_client = NULL;
+		mutex_unlock(&adie_client[id].lock);
+		mutex_unlock(&adie_client_lock);
+		return -1;
+	}
+	mutex_unlock(&adie_client_lock);
+
+	adie_client[id].adie_svc_cb_done = 0;
+	arg.cb_id = id;
+	adie_client[id].cb_id = arg.cb_id;
+	mutex_unlock(&adie_client[id].lock);
+	rc = msm_rpc_client_req(adie_client[id].rpc_client,
+				SND_ADIE_SVC_CLIENT_REGISTER_PROC,
+				adie_svc_client_register_arg, &arg,
+					NULL, NULL, -1);
+	if (!rc) {
+		rc = wait_event_interruptible(adie_client[id].wq,
+				adie_client[id].adie_svc_cb_done);
+		mutex_lock(&adie_client[id].lock);
+		if (unlikely(rc < 0)) {
+			if (rc == -ERESTARTSYS)
+				MM_ERR("wait_event_interruptible "
+						"returned -ERESTARTSYS\n");
+			else
+				MM_ERR("wait_event_interruptible "
+						"returned error\n");
+			rc = -1;
+			goto err;
+		}
+		MM_DBG("Status %d received from CB function, id %d rc %d\n",
+		       adie_client[id].status, adie_client[id].client_id, rc);
+		rc = id;
+		if (adie_client[id].status == ADIE_SVC_STATUS_FAILURE) {
+			MM_ERR("Received failed status for register request\n");
+			rc = -1;
+		} else
+			goto done;
+	} else {
+		MM_ERR("Failed to send register client request\n");
+		rc = -1;
+		mutex_lock(&adie_client[id].lock);
+	}
+err:
+	msm_rpc_unregister_client(adie_client[id].rpc_client);
+	adie_client[id].rpc_client = NULL;
+	adie_client[id].client_id = -1;
+	adie_client[id].cb_id = MSM_RPC_CLIENT_NULL_CB_ID;
+	adie_client[id].adie_svc_cb_done = 0;
+done:
+	mutex_unlock(&adie_client[id].lock);
+	return rc;
+}
+EXPORT_SYMBOL(adie_svc_get);
+
+/* Returns: 0 on succes and
+ *         -1 on failure
+ */
+int adie_svc_put(int id)
+{
+	int rc = 0;
+	struct adie_svc_client_deregister_cb_args arg;
+
+	if (id < 0 || id >= ADIE_SVC_MAX_CLIENTS)
+		return -1;
+
+	mutex_lock(&adie_client[id].lock);
+	if (adie_client[id].client_id == -1 ||
+			adie_client[id].rpc_client == NULL) {
+		mutex_unlock(&adie_client[id].lock);
+		return -1;
+	}
+	arg.client_id = adie_client[id].client_id;
+	adie_client[id].adie_svc_cb_done = 0;
+	mutex_unlock(&adie_client[id].lock);
+	rc = msm_rpc_client_req(adie_client[id].rpc_client,
+					SND_ADIE_SVC_CLIENT_DEREGISTER_PROC,
+					adie_svc_client_deregister_arg, &arg,
+					NULL, NULL, -1);
+	if (!rc) {
+		rc = wait_event_interruptible(adie_client[id].wq,
+				adie_client[id].adie_svc_cb_done);
+		if (unlikely(rc < 0)) {
+			if (rc == -ERESTARTSYS)
+				MM_ERR("wait_event_interruptible "
+						"returned -ERESTARTSYS\n");
+			else
+				MM_ERR("wait_event_interruptible "
+						"returned error\n");
+			rc = -1;
+			goto err;
+		}
+		MM_DBG("Status received from CB function\n");
+		mutex_lock(&adie_client[id].lock);
+		if (adie_client[id].status == ADIE_SVC_STATUS_FAILURE) {
+			rc = -1;
+		} else {
+			msm_rpc_unregister_client(adie_client[id].rpc_client);
+			adie_client[id].rpc_client = NULL;
+			adie_client[id].client_id = -1;
+			adie_client[id].cb_id = MSM_RPC_CLIENT_NULL_CB_ID;
+			adie_client[id].adie_svc_cb_done = 0;
+		}
+		mutex_unlock(&adie_client[id].lock);
+	} else {
+		MM_ERR("Failed to send deregister client request\n");
+		rc = -1;
+	}
+err:
+	return rc;
+}
+EXPORT_SYMBOL(adie_svc_put);
+
+/* Returns: 0 on success
+ *          2 already in use
+ *         -1 on failure
+ */
+int adie_svc_config_adie_block(int id,
+		enum adie_block_enum_type adie_block_type, bool enable)
+{
+	int rc = 0;
+	struct adie_svc_config_adie_block_cb_args arg;
+
+	if (id < 0 || id >= ADIE_SVC_MAX_CLIENTS)
+		return -1;
+
+	mutex_lock(&adie_client[id].lock);
+	if (adie_client[id].client_id == -1 ||
+			adie_client[id].rpc_client == NULL) {
+		mutex_unlock(&adie_client[id].lock);
+		return -1;
+	}
+	arg.client_id 	= adie_client[id].client_id;
+	arg.adie_block	= adie_block_type;
+	arg.config	= (enum adie_config_enum_type)enable;
+	adie_client[id].adie_svc_cb_done = 0;
+	mutex_unlock(&adie_client[id].lock);
+	rc = msm_rpc_client_req(adie_client[id].rpc_client,
+					SND_ADIE_SVC_CONFIG_ADIE_BLOCK_PROC,
+					adie_svc_config_adie_block_arg, &arg,
+					NULL, NULL, -1);
+	if (!rc) {
+		rc = wait_event_interruptible(adie_client[id].wq,
+				adie_client[id].adie_svc_cb_done);
+		if (unlikely(rc < 0)) {
+			if (rc == -ERESTARTSYS)
+				MM_ERR("wait_event_interruptible "
+						"returned -ERESTARTSYS\n");
+			else
+				MM_ERR("wait_event_interruptible "
+						"returned error\n");
+			rc = -1;
+			goto err;
+		}
+		MM_DBG("Status received from CB function\n");
+		mutex_lock(&adie_client[id].lock);
+		if (adie_client[id].status == ADIE_SVC_STATUS_FAILURE)
+			rc = -1;
+		else
+			rc = adie_client[id].status;
+		mutex_unlock(&adie_client[id].lock);
+	} else {
+		MM_ERR("Failed to send adie block config request\n");
+		rc = -1;
+	}
+err:
+	return rc;
+}
+EXPORT_SYMBOL(adie_svc_config_adie_block);
+
+#ifdef CONFIG_DEBUG_FS
+
+struct dentry *dentry;
+
+static ssize_t snd_adie_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t snd_adie_debug_write(struct file *file, const char __user *buf,
+	       size_t count, loff_t *ppos)
+{
+	int rc = 0, op = 0;
+	int id = 0, adie_block = 0, config = 1;
+
+	sscanf(buf, "%d %d %d %d", &op, &id, &adie_block, &config);
+	MM_INFO("\nUser input: op %d id %d block %d config %d\n", op, id,
+			adie_block, config);
+	switch (op) {
+	case ADIE_SVC_REGISTER_CLIENT:
+		MM_INFO("ADIE_SVC_REGISTER_CLIENT\n");
+		rc = adie_svc_get();
+		if (rc >= 0)
+			MM_INFO("Client registered: %d\n", rc);
+		else
+			MM_ERR("Failed registering client\n");
+		break;
+	case ADIE_SVC_DEREGISTER_CLIENT:
+		MM_INFO("ADIE_SVC_DEREGISTER_CLIENT: %d\n", id);
+		rc = adie_svc_put(id);
+		if (!rc)
+			MM_INFO("Client %d deregistered\n", id);
+		else
+			MM_ERR("Failed unregistering the client: %d\n",	id);
+		break;
+	case ADIE_SVC_CONFIG_ADIE_BLOCK:
+		MM_INFO("ADIE_SVC_CONFIG_ADIE_BLOCK: id %d adie_block %d \
+				config %d\n", id, adie_block, config);
+		rc =  adie_svc_config_adie_block(id,
+			(enum adie_block_enum_type)adie_block, (bool)config);
+		if (!rc)
+			MM_INFO("ADIE block %d %s", adie_block,
+					config ? "enabled\n" : "disabled\n");
+		else if (rc == 2)
+			MM_INFO("ADIE block %d already in use\n", adie_block);
+		else
+			MM_ERR("ERROR configuring the ADIE block\n");
+		break;
+	default:
+		MM_INFO("Invalid operation\n");
+	}
+	return count;
+}
+
+static ssize_t snd_adie_debug_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *ppos)
+{
+	static char buffer[1024];
+	const int debug_bufmax = sizeof(buffer);
+	int id, n = 0;
+
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"LIST OF CLIENTS\n");
+	for (id = 0; id < ADIE_SVC_MAX_CLIENTS ; id++) {
+		if (adie_client[id].client_id != -1 &&
+				adie_client[id].rpc_client != NULL) {
+			n += scnprintf(buffer + n, debug_bufmax - n,
+				"id %d rpc client 0x%08x\n", id,
+				(uint32_t)adie_client[id].rpc_client);
+		}
+	}
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations snd_adie_debug_fops = {
+	.read = snd_adie_debug_read,
+	.open = snd_adie_debug_open,
+	.write = snd_adie_debug_write,
+};
+#endif
+
+static void __exit snd_adie_exit(void)
+{
+#ifdef CONFIG_DEBUG_FS
+	if (dentry)
+		debugfs_remove(dentry);
+#endif
+}
+
+static int __init snd_adie_init(void)
+{
+	int id;
+#ifdef CONFIG_DEBUG_FS
+	char name[sizeof "msm_snd_adie"];
+
+	snprintf(name, sizeof name, "msm_snd_adie");
+	dentry = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUGO,
+			NULL, NULL, &snd_adie_debug_fops);
+	if (IS_ERR(dentry))
+		MM_DBG("debugfs_create_file failed\n");
+#endif
+	for (id = 0; id < ADIE_SVC_MAX_CLIENTS; id++) {
+		adie_client[id].client_id = -1;
+		adie_client[id].cb_id = MSM_RPC_CLIENT_NULL_CB_ID;
+		adie_client[id].status = 0;
+		adie_client[id].adie_svc_cb_done = 0;
+		mutex_init(&adie_client[id].lock);
+		init_waitqueue_head(&adie_client[id].wq);
+		adie_client[id].rpc_client = NULL;
+	}
+	return 0;
+}
+
+module_init(snd_adie_init);
+module_exit(snd_adie_exit);
diff --git a/arch/arm/mach-msm/qdsp5/snd_pcm_client.c b/arch/arm/mach-msm/qdsp5/snd_pcm_client.c
new file mode 100644
index 0000000..b58d3a2
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/snd_pcm_client.c
@@ -0,0 +1,522 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/kthread.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/msm_audio.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_rpcrouter.h>
+
+#define SND_VOC_PCM_INTERFACE_PROG	0x30000002
+#define SND_VOC_PCM_INTERFACE_VERS	0x00020004
+
+/* Supply always 160 words of PCM samples (20ms data) */
+#define MAX_VOC_FRAME_SIZE 160
+#define VOC_FRAME_DURATION 20
+/* Buffering for Maximum 8 frames between userspace and driver */
+#define MAX_VOC_FRAMES 8
+#define BUFSZ ((MAX_VOC_FRAME_SIZE*2)*MAX_VOC_FRAMES)
+#define SND_VOC_PCM_CLIENT_INPUT_FN_TYPE_PROC 3
+#define SND_VOC_REGISTER_PCM_INPUT_CLIENT_PROC 24
+
+#define START_CALLBACK_ID 0x12345678
+#define STOP_CALLBACK_ID 0xffffffff
+
+#define MAX_WAIT_CONSUME (MAX_VOC_FRAMES * VOC_FRAME_DURATION)
+/* PCM Interfaces */
+enum voice_pcm_interface_type {
+	VOICE_PCM_INTERFACE_TX_INPUT = 3, /* PCM Inject input to PreProc */
+};
+
+enum voice_pcm_interface_reg_status_type {
+	SUCCESS = 0, /* Success 0, else failure */
+};
+
+/* status used by PCM input callbacks to indicate availability of PCM Data */
+enum voice_pcm_data_status_type {
+	VOICE_PCM_DATA_STATUS_AVAILABLE,    /* Data available for PCM input */
+	VOICE_PCM_DATA_STATUS_UNAVAILABLE,  /* Data not available           */
+	VOICE_PCM_DATA_STATUS_MAX
+};
+
+/* Argument needed to register PCM input  client */
+struct snd_voice_pcm_interface_ipclnt_reg_args {
+	/* Interface number specifies the PCM inject point */
+	enum voice_pcm_interface_type interface;
+	/* Non-NULL indicates start,NULL indicates stop */
+	uint32_t callback_id;
+};
+
+struct snd_voice_pcm_interface_ipclnt_reg_status {
+	enum voice_pcm_interface_reg_status_type status;
+};
+
+struct snd_voice_pcm_interface_ipclnt_fn_type_args {
+	uint32_t callback_id;
+	uint32_t pcm_data_ptr_not_null;
+	uint32_t pcm_data_max_length;
+};
+
+struct snd_voice_pcm_interface_ipclnt_fn_type_reply {
+	enum voice_pcm_data_status_type status;
+	struct {
+		uint32_t pcm_data_len;
+		struct {
+			uint16_t pcm_data_ignore;
+			uint16_t pcm_data_valid;
+		} pcm_data_val[MAX_VOC_FRAME_SIZE];
+	} pcm_data;
+};
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;
+};
+
+struct audio {
+	struct buffer out[MAX_VOC_FRAMES];
+
+	uint8_t out_head;
+	uint8_t out_tail;
+
+	atomic_t out_bytes;
+	/* data allocated for various buffers */
+	char *data;
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t wait;
+	wait_queue_head_t stop_wait;
+
+	int buffer_finished;
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped */
+
+	struct msm_rpc_client *client;
+};
+
+static struct audio the_audio;
+
+static int snd_voice_pcm_interface_ipclnt_reg_args(
+	struct msm_rpc_client *client, void *buf, void *data)
+{
+	struct snd_voice_pcm_interface_ipclnt_reg_args *arg;
+	int size = 0;
+
+	arg = (struct snd_voice_pcm_interface_ipclnt_reg_args *)data;
+	*((int *)buf) = cpu_to_be32(arg->interface);
+	size += sizeof(int);
+	buf += sizeof(int);
+	*((int *)buf) = cpu_to_be32(arg->callback_id);
+	size += sizeof(int);
+
+	return size;
+}
+
+static int snd_voice_pcm_interface_ipclnt_reg_status(
+	struct msm_rpc_client *client, void *buf, void *data)
+{
+	struct snd_voice_pcm_interface_ipclnt_reg_status *result =
+	(struct snd_voice_pcm_interface_ipclnt_reg_status *)buf;
+
+	*((int *)data) =  be32_to_cpu(result->status);
+	return 0;
+}
+
+static void process_callback(struct audio *audio,
+	void *buffer, int in_size)
+{
+	uint32_t accept_status = RPC_ACCEPTSTAT_SUCCESS;
+	struct rpc_request_hdr *req;
+	struct snd_voice_pcm_interface_ipclnt_fn_type_args arg, *buf_ptr;
+	struct snd_voice_pcm_interface_ipclnt_fn_type_reply *reply;
+	struct buffer *frame;
+	uint32_t status;
+	uint32_t pcm_data_len;
+
+	req = (struct rpc_request_hdr *)buffer;
+	buf_ptr = (struct snd_voice_pcm_interface_ipclnt_fn_type_args *)\
+				(req + 1);
+	arg.callback_id = be32_to_cpu(buf_ptr->callback_id);
+	arg.pcm_data_ptr_not_null = be32_to_cpu(buf_ptr->pcm_data_ptr_not_null);
+	arg.pcm_data_max_length = be32_to_cpu(buf_ptr->pcm_data_max_length);
+
+	MM_DBG("callback_id = 0x%8x pcm_data_ptr_not_null = 0x%8x"\
+		"pcm_data_max_length = 0x%8x\n", arg.callback_id,\
+		arg.pcm_data_ptr_not_null, arg.pcm_data_max_length);
+	/* Flag interface as running */
+	if (!audio->running)
+		audio->running = 1;
+	if (!arg.pcm_data_ptr_not_null) {
+		accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
+		msm_rpc_start_accepted_reply(audio->client,
+			be32_to_cpu(req->xid), accept_status);
+		msm_rpc_send_accepted_reply(audio->client, 0);
+		return;
+	}
+	reply = (struct snd_voice_pcm_interface_ipclnt_fn_type_reply *)
+		msm_rpc_start_accepted_reply(audio->client,
+			be32_to_cpu(req->xid), accept_status);
+	frame = audio->out + audio->out_tail;
+	/* If Data available, send data */
+	if (frame->used) {
+		int i;
+		unsigned short *src = frame->data;
+		atomic_add(frame->used, &audio->out_bytes);
+		status = VOICE_PCM_DATA_STATUS_AVAILABLE;
+		pcm_data_len = MAX_VOC_FRAME_SIZE;
+		xdr_send_int32(&audio->client->cb_xdr, &status);
+		xdr_send_int32(&audio->client->cb_xdr, &pcm_data_len);
+		/* Expected cb_xdr buffer size is more than PCM buffer size */
+		for (i = 0; i < MAX_VOC_FRAME_SIZE; i++, ++src)
+			xdr_send_int16(&audio->client->cb_xdr, src);
+		frame->used = 0;
+		audio->out_tail = ((++audio->out_tail) % MAX_VOC_FRAMES);
+		wake_up(&audio->wait);
+	} else {
+		status = VOICE_PCM_DATA_STATUS_UNAVAILABLE;
+		pcm_data_len = 0;
+		xdr_send_int32(&audio->client->cb_xdr, &status);
+		xdr_send_int32(&audio->client->cb_xdr, &pcm_data_len);
+		wake_up(&audio->wait);
+		/* Flag all buffer completed */
+		if (audio->stopped) {
+			audio->buffer_finished = 1;
+			wake_up(&audio->stop_wait);
+		}
+	}
+	MM_DBG("Provided PCM data = 0x%8x\n", reply->status);
+	msm_rpc_send_accepted_reply(audio->client, 0);
+	return;
+}
+
+static int pcm_interface_process_callback_routine(struct msm_rpc_client *client,
+	void *buffer, int in_size)
+{
+	struct rpc_request_hdr *req;
+	struct audio *audio = &the_audio;
+	int rc = 0;
+
+	req = (struct rpc_request_hdr *)buffer;
+
+	MM_DBG("proc id = 0x%8x xid = 0x%8x size = 0x%8x\n",
+		be32_to_cpu(req->procedure), be32_to_cpu(req->xid), in_size);
+	switch (be32_to_cpu(req->procedure)) {
+	/* Procedure which called every 20ms for PCM samples request*/
+	case SND_VOC_PCM_CLIENT_INPUT_FN_TYPE_PROC:
+		process_callback(audio, buffer, in_size);
+		break;
+	default:
+		MM_ERR("Not supported proceudure 0x%8x\n",
+			be32_to_cpu(req->procedure));
+		/* Not supported RPC Procedure, send nagative code */
+		msm_rpc_start_accepted_reply(client, be32_to_cpu(req->xid),
+				RPC_ACCEPTSTAT_PROC_UNAVAIL);
+		msm_rpc_send_accepted_reply(client, 0);
+	}
+	return rc;
+}
+
+static void audio_flush(struct audio *audio)
+{
+	int cnt;
+	for (cnt = 0; cnt < MAX_VOC_FRAMES; cnt++)
+		audio->out[cnt].used = 0;
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->stopped = 0;
+	audio->running = 0;
+	audio->buffer_finished = 0;
+}
+
+/* must be called with audio->lock held */
+static int audio_enable(struct audio *audio)
+{
+	int rc;
+	struct snd_voice_pcm_interface_ipclnt_reg_args arg;
+	struct snd_voice_pcm_interface_ipclnt_reg_status result;
+
+	/* voice_pcm_interface_type */
+	arg.interface = VOICE_PCM_INTERFACE_TX_INPUT;
+	/* Should be non-zero, unique */
+	arg.callback_id = START_CALLBACK_ID;
+	/* Start Voice PCM interface */
+	rc = msm_rpc_client_req(audio->client,
+				SND_VOC_REGISTER_PCM_INPUT_CLIENT_PROC,
+				snd_voice_pcm_interface_ipclnt_reg_args, &arg,
+				snd_voice_pcm_interface_ipclnt_reg_status,
+				&result, -1);
+	MM_DBG("input client registration status rc 0x%8x result 0x%8x\n",
+		rc, result.status);
+	/* If error in server side */
+	if (rc == 0)
+		if (result.status != SUCCESS)
+			rc = -ENODEV;
+	return rc;
+}
+static int audio_disable(struct audio *audio)
+{
+	int rc;
+	struct snd_voice_pcm_interface_ipclnt_reg_args arg;
+	struct snd_voice_pcm_interface_ipclnt_reg_status result;
+
+	/* Wait till all buffers consumed to prevent data loss
+	   Also ensure if client stops due to vocoder disable
+	   do not loop forever */
+	rc = wait_event_interruptible_timeout(audio->stop_wait,
+		!(audio->running) || (audio->buffer_finished == 1),
+		msecs_to_jiffies(MAX_WAIT_CONSUME));
+	if (rc < 0)
+		return 0;
+	/* voice_pcm_interface_type */
+	arg.interface = VOICE_PCM_INTERFACE_TX_INPUT;
+	arg.callback_id = STOP_CALLBACK_ID; /* Should be zero */
+	/* Stop Voice PCM interface */
+	rc = msm_rpc_client_req(audio->client,
+				SND_VOC_REGISTER_PCM_INPUT_CLIENT_PROC,
+				snd_voice_pcm_interface_ipclnt_reg_args, &arg,
+				snd_voice_pcm_interface_ipclnt_reg_status,
+				&result, -1);
+	MM_DBG("input client de-registration status rc 0x%8x result 0x%8x\n",
+		rc, result.status);
+	/* If error in server side */
+	if (rc == 0)
+		if (result.status != SUCCESS)
+			rc = -ENODEV;
+	return rc;
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = -EINVAL;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = atomic_read(&audio->out_bytes);
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		rc = audio_enable(audio);
+		if (rc == 0)
+			audio->enabled = 1;
+		break;
+	case AUDIO_STOP:
+		if (audio->enabled) {
+			audio->stopped = 1;
+			rc = audio_disable(audio);
+			if (rc == 0) {
+				audio->enabled = 0;
+				audio->running = 0;
+				wake_up(&audio->wait);
+			} else
+				audio->stopped = 0;
+		}
+		break;
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (copy_from_user(&config, (void *) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (config.type == 0) {
+			/* Selection for different PCM intect point */
+		} else {
+			rc = -EINVAL;
+			break;
+		}
+		rc = 0;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_size = MAX_VOC_FRAME_SIZE * 2;
+		config.buffer_count = MAX_VOC_FRAMES;
+		config.sample_rate = 8000;
+		config.channel_count = 1;
+		config.type = 0;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void *) arg, &config, sizeof(config)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	}
+	default: {
+		rc = -EINVAL;
+		MM_ERR(" Unsupported ioctl 0x%8x\n", cmd);
+	}
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+static ssize_t audio_read(struct file *file, char __user *buf,
+		size_t count, loff_t *pos)
+{
+	return -EINVAL;
+}
+
+static ssize_t audio_write(struct file *file, const char __user *buf,
+		size_t count, loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	int rc = 0;
+
+	mutex_lock(&audio->write_lock);
+	/* Ensure to copy only till frame boundary */
+	while (count >= (MAX_VOC_FRAME_SIZE*2)) {
+		frame = audio->out + audio->out_head;
+		rc = wait_event_interruptible_timeout(audio->wait,\
+				(frame->used == 0) || (audio->stopped),
+				msecs_to_jiffies(MAX_WAIT_CONSUME));
+
+		if (rc < 0)
+			break;
+		if (audio->stopped) {
+			rc = -EBUSY;
+			break;
+		}
+		if (rc == 0) {
+			rc = -ETIMEDOUT;
+			break;
+		}
+
+		xfer = count > frame->size ? frame->size : count;
+		if (copy_from_user(frame->data, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+		frame->used = xfer;
+		audio->out_head = ((++audio->out_head) % MAX_VOC_FRAMES);
+		count -= xfer;
+		buf += xfer;
+	}
+	mutex_unlock(&audio->write_lock);
+	MM_DBG("write done 0x%8x\n", (unsigned int)(buf - start));
+	if (rc < 0)
+		return rc;
+	return buf - start;
+}
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = &the_audio;
+	int rc, cnt;
+
+	mutex_lock(&audio->lock);
+
+	if (audio->opened) {
+		MM_ERR("busy as driver already in open state\n");
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (!audio->data) {
+		audio->data = kmalloc(BUFSZ, GFP_KERNEL);
+		if (!audio->data) {
+			MM_ERR("could not allocate buffers\n");
+			rc = -ENOMEM;
+			goto done;
+		}
+	}
+
+	audio->client = msm_rpc_register_client("voice_pcm_interface_client",
+				SND_VOC_PCM_INTERFACE_PROG,
+				SND_VOC_PCM_INTERFACE_VERS, 1,
+				pcm_interface_process_callback_routine);
+	if (IS_ERR(audio->client)) {
+		MM_ERR("Failed to register voice pcm interface client"\
+			"to 0x%8x\n", SND_VOC_PCM_INTERFACE_PROG);
+		kfree(audio->data);
+		audio->data = NULL;
+		rc = -ENODEV;
+		goto done;
+	}
+	MM_INFO("voice pcm client registred %p\n", audio->client);
+	for (cnt = 0; cnt < MAX_VOC_FRAMES; cnt++) {
+		audio->out[cnt].data = (audio->data +\
+					((MAX_VOC_FRAME_SIZE * 2) * cnt));
+		audio->out[cnt].size = MAX_VOC_FRAME_SIZE * 2;
+		MM_DBG("data ptr = %p\n", audio->out[cnt].data);
+	}
+	file->private_data = audio;
+	audio_flush(audio);
+	audio->opened = 1;
+	rc = 0;
+done:
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	if (audio->enabled) {
+		audio->stopped = 1;
+		audio_disable(audio);
+		audio->running = 0;
+		audio->enabled = 0;
+		wake_up(&audio->wait);
+	}
+	msm_rpc_unregister_client(audio->client);
+	kfree(audio->data);
+	audio->data = NULL;
+	audio->opened = 0;
+	mutex_unlock(&audio->lock);
+	return 0;
+}
+
+static const struct file_operations audio_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audio_open,
+	.release	= audio_release,
+	.read		= audio_read,
+	.write		= audio_write,
+	.unlocked_ioctl	= audio_ioctl,
+};
+
+static struct miscdevice audio_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "snd_pcm_client",
+	.fops	= &audio_fops,
+};
+
+static int __init audio_init(void)
+{
+	mutex_init(&the_audio.lock);
+	mutex_init(&the_audio.write_lock);
+	init_waitqueue_head(&the_audio.wait);
+	init_waitqueue_head(&the_audio.stop_wait);
+	return misc_register(&audio_misc);
+}
+device_initcall(audio_init);
diff --git a/arch/arm/mach-msm/qdsp5v2/Makefile b/arch/arm/mach-msm/qdsp5v2/Makefile
new file mode 100644
index 0000000..3ae3c1b
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/Makefile
@@ -0,0 +1,22 @@
+obj-y += afe.o audio_interct.o mi2s.o audio_dev_ctl.o voice.o
+
+ifeq ($(CONFIG_TIMPANI_CODEC), y)
+obj-y += snddev_icodec.o
+else ifeq ($(CONFIG_MARIMBA_CODEC), y)
+obj-y += snddev_icodec.o
+endif
+
+obj-$(CONFIG_MARIMBA_CODEC) += snddev_data_marimba.o
+obj-$(CONFIG_TIMPANI_CODEC) += snddev_data_timpani.o
+
+obj-y += audio_pcm.o audpp.o audio_mp3.o audio_wma.o audio_aac.o audio_amrnb.o
+obj-y += audio_amrwb.o audio_wmapro.o audio_adpcm.o audio_evrc.o audio_qcelp.o
+obj-y += aux_pcm.o snddev_ecodec.o audio_out.o
+obj-y += audio_lpa.o mp3_funcs.o pcm_funcs.o
+obj-y += audpreproc.o audio_pcm_in.o audio_aac_in.o audio_amrnb_in.o audio_a2dp_in.o
+obj-y += audio_evrc_in.o audio_qcelp_in.o
+obj-y += adsp.o adsp_driver.o adsp_info.o
+obj-y += audio_acdb.o snddev_virtual.o
+obj-y += audio_fm.o
+obj-y += lpa.o snddev_mi2s.o
+obj-y += audio_mvs.o
\ No newline at end of file
diff --git a/arch/arm/mach-msm/qdsp5v2/adsp.c b/arch/arm/mach-msm/qdsp5v2/adsp.c
new file mode 100644
index 0000000..acd9c4c
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/adsp.c
@@ -0,0 +1,1225 @@
+/*
+ * Register/Interrupt access for userspace aDSP library.
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2008-2009,2011-2012 Code Aurora Forum. All rights reserved.
+ * Author: Iliyan Malchev <ibm@android.com>
+ *
+ * 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.
+ *
+ */
+
+/* TODO:
+ * - move shareable rpc code outside of adsp.c
+ * - general solution for virt->phys patchup
+ * - queue IDs should be relative to modules
+ * - disallow access to non-associated queues
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_adsp.h>
+#include "adsp.h"
+#include <mach/debug_mm.h>
+#include <linux/debugfs.h>
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *dentry_adsp;
+static struct dentry *dentry_wdata;
+static struct dentry *dentry_rdata;
+static int wdump, rdump;
+#endif /* CONFIG_DEBUG_FS */
+
+static struct adsp_info adsp_info;
+static struct msm_adsp_module *adsp_modules;
+static int adsp_open_count;
+
+static DEFINE_MUTEX(adsp_open_lock);
+
+/* protect interactions with the ADSP command/message queue */
+static spinlock_t adsp_cmd_lock;
+static spinlock_t adsp_write_lock;
+
+static uint32_t current_image = -1;
+
+void adsp_set_image(struct adsp_info *info, uint32_t image)
+{
+	current_image = image;
+}
+
+/*
+ * Checks whether the module_id is available in the
+ * module_entries table.If module_id is available returns `0`.
+ * If module_id is not available returns `-ENXIO`.
+ */
+static int32_t adsp_validate_module(uint32_t module_id)
+{
+	uint32_t	*ptr;
+	uint32_t	module_index;
+	uint32_t	num_mod_entries;
+
+	ptr = adsp_info.init_info_ptr->module_entries;
+	num_mod_entries = adsp_info.init_info_ptr->module_table_size;
+
+	for (module_index = 0; module_index < num_mod_entries; module_index++)
+		if (module_id == ptr[module_index])
+			return 0;
+
+	return -ENXIO;
+}
+
+static int32_t adsp_validate_queue(uint32_t mod_id, unsigned q_idx,
+							uint32_t size)
+{
+	int32_t i;
+	struct adsp_rtos_mp_mtoa_init_info_type	*sptr;
+
+	sptr = adsp_info.init_info_ptr;
+	for (i = 0; i < sptr->mod_to_q_entries; i++)
+		if (mod_id == sptr->mod_to_q_tbl[i].module)
+			if (q_idx == sptr->mod_to_q_tbl[i].q_type) {
+				if (size <= sptr->mod_to_q_tbl[i].q_max_len)
+					return 0;
+				MM_ERR("q_idx: %d is not a valid queue \
+					for module %x\n", q_idx, mod_id);
+				return -EINVAL;
+			}
+	MM_ERR("cmd_buf size is more than allowed size\n");
+	return -EINVAL;
+}
+
+uint32_t adsp_get_module(struct adsp_info *info, uint32_t task)
+{
+	return info->task_to_module[current_image][task];
+}
+
+uint32_t adsp_get_queue_offset(struct adsp_info *info, uint32_t queue_id)
+{
+	return info->queue_offset[current_image][queue_id];
+}
+
+static int rpc_adsp_rtos_app_to_modem(uint32_t cmd, uint32_t module,
+				      struct msm_adsp_module *adsp_module)
+{
+	struct adsp_rtos_atom_cmd adspsvc_cmd;
+	int err;
+
+	adspsvc_cmd.cmd = cmd;
+	adspsvc_cmd.proc_id = RPC_ADSP_RTOS_PROC_APPS;
+	adspsvc_cmd.module = module;
+	adspsvc_cmd.cb_handle = adsp_info.cb_handle;
+
+	err = dalrpc_fcn_5(DALDEVICE_ADSP_CMD_IDX | 0x80000000,
+					adsp_info.handle,
+					&adspsvc_cmd, sizeof(adspsvc_cmd));
+	if (err < 0)
+		MM_ERR("ADSP command send Failed\n");
+
+	return 0;
+}
+
+static int get_module_index(uint32_t id)
+{
+	int mod_idx;
+	for (mod_idx = 0; mod_idx < adsp_info.module_count; mod_idx++)
+		if (adsp_info.module[mod_idx].id == id)
+			return mod_idx;
+
+	return -ENXIO;
+}
+
+static struct msm_adsp_module *find_adsp_module_by_id(
+	struct adsp_info *info, uint32_t id)
+{
+	int mod_idx;
+
+	if (id > info->max_module_id) {
+		return NULL;
+	} else {
+		mod_idx = get_module_index(id);
+		if (mod_idx < 0)
+			return NULL;
+		return info->id_to_module[mod_idx];
+	}
+}
+
+static struct msm_adsp_module *find_adsp_module_by_name(
+	struct adsp_info *info, const char *name)
+{
+	unsigned n;
+	for (n = 0; n < info->module_count; n++)
+		if (!strcmp(name, adsp_modules[n].name))
+			return adsp_modules + n;
+	return NULL;
+}
+
+/*
+ * Send RPC_ADSP_RTOS_CMD_GET_INIT_INFO cmd to ARM9 and get
+ * queue offsets and module entries (init info) as part of the event.
+ */
+static void  msm_get_init_info(void)
+{
+	struct adsp_rtos_atom_cmd cmd;
+	int err;
+
+	cmd.cmd = RPC_ADSP_RTOS_CMD_GET_INIT_INFO;
+	cmd.proc_id = RPC_ADSP_RTOS_PROC_APPS;
+	cmd.module = 0;
+	cmd.cb_handle = adsp_info.cb_handle;
+
+	err = dalrpc_fcn_5(DALDEVICE_ADSP_CMD_IDX | 0x80000000,
+							adsp_info.handle,
+							&cmd, sizeof(cmd));
+	if (err < 0)
+		MM_ERR("INIT_INFO command send Failed\n");
+}
+
+int msm_adsp_get(const char *name, struct msm_adsp_module **out,
+		 struct msm_adsp_ops *ops, void *driver_data)
+{
+	struct msm_adsp_module *module;
+	int rc = 0;
+
+	module = find_adsp_module_by_name(&adsp_info, name);
+	if (!module)
+		return -ENODEV;
+
+	mutex_lock(&module->lock);
+	MM_DBG("opening module %s\n", module->name);
+
+	if (module->ops) {
+		rc = -EBUSY;
+		mutex_unlock(&module->lock);
+		goto done;
+	}
+
+	module->ops = ops;
+	module->driver_data = driver_data;
+	*out = module;
+	mutex_unlock(&module->lock);
+	rc = rpc_adsp_rtos_app_to_modem(RPC_ADSP_RTOS_CMD_REGISTER_APP,
+					module->id, module);
+	if (rc) {
+		mutex_lock(&module->lock);
+		module->ops = NULL;
+		module->driver_data = NULL;
+		*out = NULL;
+		MM_ERR("REGISTER_APP failed\n");
+		mutex_unlock(&module->lock);
+		goto done;
+	}
+
+	MM_INFO("module %s has been registered\n", module->name);
+
+done:
+	return rc;
+}
+EXPORT_SYMBOL(msm_adsp_get);
+
+void msm_adsp_put(struct msm_adsp_module *module)
+{
+	unsigned long flags;
+
+	mutex_lock(&module->lock);
+	if (module->ops) {
+		MM_INFO("closing module %s\n", module->name);
+
+		/* lock to ensure a dsp event cannot be delivered
+		 * during or after removal of the ops and driver_data
+		 */
+		spin_lock_irqsave(&adsp_cmd_lock, flags);
+		module->ops = NULL;
+		module->driver_data = NULL;
+		spin_unlock_irqrestore(&adsp_cmd_lock, flags);
+
+		if (module->state != ADSP_STATE_DISABLED) {
+			MM_INFO("disabling module %s\n", module->name);
+			mutex_unlock(&module->lock);
+			msm_adsp_disable(module);
+			return;
+		}
+	} else {
+		MM_INFO("module %s is already closed\n", module->name);
+	}
+	mutex_unlock(&module->lock);
+}
+EXPORT_SYMBOL(msm_adsp_put);
+
+int __msm_adsp_write(struct msm_adsp_module *module, unsigned dsp_queue_addr,
+		   void *cmd_buf, size_t cmd_size)
+{
+	uint32_t ctrl_word;
+	uint32_t dsp_q_addr;
+	uint32_t dsp_addr;
+	uint32_t cmd_id = 0;
+	int cnt = 0;
+	int ret_status = 0;
+	unsigned long flags;
+	struct adsp_info *info;
+
+	if (!module || !cmd_buf) {
+		MM_ERR("Called with NULL parameters\n");
+		return -EINVAL;
+	}
+	info = module->info;
+	spin_lock_irqsave(&adsp_write_lock, flags);
+
+	if (module->state != ADSP_STATE_ENABLED) {
+		spin_unlock_irqrestore(&adsp_write_lock, flags);
+		MM_ERR("module %s not enabled before write\n", module->name);
+		return -ENODEV;
+	}
+	if (adsp_validate_module(module->id)) {
+		spin_unlock_irqrestore(&adsp_write_lock, flags);
+		MM_ERR("module id validation failed %s  %d\n",
+				module->name, module->id);
+		return -ENXIO;
+	}
+	if (dsp_queue_addr >= QDSP_MAX_NUM_QUEUES) {
+		spin_unlock_irqrestore(&adsp_write_lock, flags);
+		MM_ERR("Invalid Queue Index: %d\n", dsp_queue_addr);
+		return -ENXIO;
+	}
+	if (adsp_validate_queue(module->id, dsp_queue_addr, cmd_size)) {
+		spin_unlock_irqrestore(&adsp_write_lock, flags);
+		return -EINVAL;
+	}
+	dsp_q_addr = adsp_get_queue_offset(info, dsp_queue_addr);
+	dsp_q_addr &= ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M;
+
+	/* Poll until the ADSP is ready to accept a command.
+	 * Wait for 100us, return error if it's not responding.
+	 * If this returns an error, we need to disable ALL modules and
+	 * then retry.
+	 */
+	while (((ctrl_word = readl(info->write_ctrl)) &
+		ADSP_RTOS_WRITE_CTRL_WORD_READY_M) !=
+		ADSP_RTOS_WRITE_CTRL_WORD_READY_V) {
+		if (cnt > 50) {
+			MM_ERR("timeout waiting for DSP write ready\n");
+			ret_status = -EIO;
+			goto fail;
+		}
+		MM_DBG("waiting for DSP write ready\n");
+		udelay(2);
+		cnt++;
+	}
+
+	/* Set the mutex bits */
+	ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_M);
+	ctrl_word |=  ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_NAVAIL_V;
+
+	/* Clear the command bits */
+	ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_CMD_M);
+
+	/* Set the queue address bits */
+	ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M);
+	ctrl_word |= dsp_q_addr;
+
+	writel(ctrl_word, info->write_ctrl);
+
+	/* Generate an interrupt to the DSP.  This notifies the DSP that
+	 * we are about to send a command on this particular queue.  The
+	 * DSP will in response change its state.
+	 */
+	writel(1, info->send_irq);
+
+	/* Poll until the adsp responds to the interrupt; this does not
+	 * generate an interrupt from the adsp.  This should happen within
+	 * 5ms.
+	 */
+	cnt = 0;
+	while ((readl(info->write_ctrl) &
+		ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_M) ==
+		ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_NAVAIL_V) {
+		if (cnt > 2500) {
+			MM_ERR("timeout waiting for adsp ack\n");
+			ret_status = -EIO;
+			goto fail;
+		}
+		udelay(2);
+		cnt++;
+	}
+
+	/* Read the ctrl word */
+	ctrl_word = readl(info->write_ctrl);
+
+	if ((ctrl_word & ADSP_RTOS_WRITE_CTRL_WORD_STATUS_M) !=
+	    ADSP_RTOS_WRITE_CTRL_WORD_NO_ERR_V) {
+		ret_status = -EAGAIN;
+		goto fail;
+	} else {
+		/* No error */
+		/* Get the DSP buffer address */
+		dsp_addr = (ctrl_word & ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M) +
+			   (uint32_t)MSM_AD5_BASE;
+
+		if (dsp_addr < (uint32_t)(MSM_AD5_BASE + QDSP_RAMC_OFFSET)) {
+			uint16_t *buf_ptr = (uint16_t *) cmd_buf;
+			uint16_t *dsp_addr16 = (uint16_t *)dsp_addr;
+			cmd_size /= sizeof(uint16_t);
+
+			/* Save the command ID */
+			cmd_id = (uint32_t) buf_ptr[0];
+
+			/* Copy the command to DSP memory */
+			cmd_size++;
+			while (--cmd_size)
+				*dsp_addr16++ = *buf_ptr++;
+		} else {
+			uint32_t *buf_ptr = (uint32_t *) cmd_buf;
+			uint32_t *dsp_addr32 = (uint32_t *)dsp_addr;
+			cmd_size /= sizeof(uint32_t);
+
+			/* Save the command ID */
+			cmd_id = buf_ptr[0];
+
+			cmd_size++;
+			while (--cmd_size)
+				*dsp_addr32++ = *buf_ptr++;
+		}
+
+		/* Set the mutex bits */
+		ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_M);
+		ctrl_word |=  ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_NAVAIL_V;
+
+		/* Set the command bits to write done */
+		ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_CMD_M);
+		ctrl_word |= ADSP_RTOS_WRITE_CTRL_WORD_CMD_WRITE_DONE_V;
+
+		/* Set the queue address bits */
+		ctrl_word &= ~(ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M);
+		ctrl_word |= dsp_q_addr;
+
+		writel(ctrl_word, info->write_ctrl);
+
+		/* Generate an interrupt to the DSP.  It does not respond with
+		 * an interrupt, and we do not need to wait for it to
+		 * acknowledge, because it will hold the mutex lock until it's
+		 * ready to receive more commands again.
+		 */
+		writel(1, info->send_irq);
+
+		module->num_commands++;
+	} /* Ctrl word status bits were 00, no error in the ctrl word */
+
+fail:
+	spin_unlock_irqrestore(&adsp_write_lock, flags);
+	return ret_status;
+}
+EXPORT_SYMBOL(msm_adsp_write);
+
+int msm_adsp_write(struct msm_adsp_module *module, unsigned dsp_queue_addr,
+			void *cmd_buf, size_t cmd_size)
+{
+	int rc, retries = 0;
+#ifdef CONFIG_DEBUG_FS
+	uint16_t *ptr;
+	int ii;
+
+	if (wdump > 0) {
+		ptr = cmd_buf;
+		pr_info("A->D:%x\n", module->id);
+		pr_info("adsp: %x %d\n", dsp_queue_addr, cmd_size);
+		for (ii = 0; ii < cmd_size/2; ii++)
+			pr_info("%x ", ptr[ii]);
+		pr_info("\n");
+	}
+#endif /* CONFIG_DEBUG_FS */
+	do {
+		rc = __msm_adsp_write(module, dsp_queue_addr, cmd_buf,
+								cmd_size);
+		if (rc == -EAGAIN)
+			udelay(50);
+	} while (rc == -EAGAIN && retries++ < 300);
+	if (retries > 20)
+		MM_INFO("%s command took %d attempts: rc %d\n",
+			module->name, retries, rc);
+	return rc;
+}
+
+#ifdef CONFIG_MSM_ADSP_REPORT_EVENTS
+static void *event_addr;
+static void read_event(void *buf, size_t len)
+{
+	uint32_t dptr[3];
+	struct adsp_rtos_mp_mtoa_s_type *sptr;
+	struct adsp_rtos_mp_mtoa_type	*pkt_ptr;
+
+	sptr = event_addr;
+	pkt_ptr = &sptr->adsp_rtos_mp_mtoa_data.mp_mtoa_packet;
+
+	dptr[0] = sptr->mp_mtoa_header.event;
+	dptr[1] = pkt_ptr->module;
+	dptr[2] = pkt_ptr->image;
+
+	if (len > EVENT_LEN)
+		len = EVENT_LEN;
+
+	memcpy(buf, dptr, len);
+}
+#endif
+
+static void adsp_rtos_mtoa_cb(void *context, uint32_t param,
+					void *evt_buf, uint32_t len)
+{
+	struct adsp_rtos_mp_mtoa_s_type *args = NULL;
+	uint32_t event = 0;
+	uint32_t proc_id = 0;
+	uint32_t module_id;
+	uint32_t image;
+	struct msm_adsp_module *module;
+	struct adsp_rtos_mp_mtoa_type	*pkt_ptr;
+	struct queue_to_offset_type	*qptr;
+	struct queue_to_offset_type	*qtbl;
+	struct mod_to_queue_offsets	*mqptr;
+	struct mod_to_queue_offsets	*mqtbl;
+	uint32_t	*mptr;
+	uint32_t	*mtbl;
+	uint32_t	q_idx;
+	uint32_t	num_entries;
+	uint32_t	entries_per_image;
+	struct adsp_rtos_mp_mtoa_init_info_type *iptr;
+	struct adsp_rtos_mp_mtoa_init_info_type	*sptr;
+	int32_t		i_no, e_idx;
+	static uint32_t	init_info_completed;
+	static uint32_t init_info_len =
+				sizeof(struct adsp_rtos_mp_mtoa_header_type);
+	static uint32_t	next_init_info_byte;
+	static uint32_t expected_byte = 1;
+	uint32_t hdr_len = sizeof(struct adsp_rtos_mp_mtoa_header_type);
+
+	if (len) {
+		args = (struct adsp_rtos_mp_mtoa_s_type *) evt_buf;
+		event = args->mp_mtoa_header.event;
+		proc_id = args->mp_mtoa_header.proc_id;
+	}
+
+	if (!init_info_completed && event == RPC_ADSP_RTOS_INIT_INFO) {
+		memcpy(((char *)adsp_info.raw_event) + init_info_len,
+						(char *)evt_buf + hdr_len + 4,
+							len - ((hdr_len + 4)));
+		init_info_len += (len - (hdr_len + 4));
+		evt_buf += hdr_len;
+		next_init_info_byte = *(uint32_t *) evt_buf;
+		expected_byte += len;
+		if (next_init_info_byte &&
+				(expected_byte != next_init_info_byte)) {
+			MM_ERR("INIT_INFO - expecting next byte to be %d\n"
+				"\tbut ADSPSVC indicated next byte to be %d\n",
+				expected_byte, next_init_info_byte);
+			return;
+		}
+		if (!next_init_info_byte) {
+			args = adsp_info.raw_event;
+			args->mp_mtoa_header.event = event;
+			args->mp_mtoa_header.proc_id = proc_id;
+			init_info_completed = 1;
+		} else
+			return;
+	}
+
+	if (event == RPC_ADSP_RTOS_INIT_INFO) {
+		MM_INFO("INIT_INFO Event\n");
+		sptr = &args->adsp_rtos_mp_mtoa_data.mp_mtoa_init_packet;
+
+		iptr = adsp_info.init_info_ptr;
+		iptr->image_count = sptr->image_count;
+		if (iptr->image_count > IMG_MAX)
+			iptr->image_count = IMG_MAX;
+		iptr->num_queue_offsets = sptr->num_queue_offsets;
+		num_entries = iptr->num_queue_offsets;
+		if (num_entries > ENTRIES_MAX) {
+			num_entries = ENTRIES_MAX;
+			iptr->num_queue_offsets = ENTRIES_MAX;
+		}
+		qptr = &sptr->queue_offsets_tbl[0][0];
+		for (i_no = 0; i_no < iptr->image_count; i_no++) {
+			qtbl = &iptr->queue_offsets_tbl[i_no][0];
+			for (e_idx = 0; e_idx < num_entries; e_idx++) {
+				qtbl[e_idx].offset = qptr->offset;
+				qtbl[e_idx].queue = qptr->queue;
+				q_idx = qptr->queue;
+				iptr->queue_offsets[i_no][q_idx] =
+							qtbl[e_idx].offset;
+				qptr++;
+			}
+		}
+
+		num_entries = sptr->num_task_module_entries;
+		if (num_entries > ENTRIES_MAX)
+			num_entries = ENTRIES_MAX;
+		iptr->num_task_module_entries = num_entries;
+		entries_per_image = num_entries / iptr->image_count;
+		mptr = &sptr->task_to_module_tbl[0][0];
+		for (i_no = 0; i_no < iptr->image_count; i_no++) {
+			mtbl = &iptr->task_to_module_tbl[i_no][0];
+			for (e_idx = 0; e_idx < entries_per_image; e_idx++) {
+				mtbl[e_idx] = *mptr;
+				mptr++;
+			}
+		}
+
+		iptr->module_table_size = sptr->module_table_size;
+		if (iptr->module_table_size > MODULES_MAX)
+			iptr->module_table_size = MODULES_MAX;
+		mptr = &sptr->module_entries[0];
+		for (i_no = 0; i_no < iptr->module_table_size; i_no++)
+			iptr->module_entries[i_no] = mptr[i_no];
+
+		mqptr = &sptr->mod_to_q_tbl[0];
+		mqtbl = &iptr->mod_to_q_tbl[0];
+		iptr->mod_to_q_entries = sptr->mod_to_q_entries;
+		if (iptr->mod_to_q_entries > ENTRIES_MAX)
+			iptr->mod_to_q_entries = ENTRIES_MAX;
+		for (e_idx = 0; e_idx < iptr->mod_to_q_entries; e_idx++) {
+			mqtbl[e_idx].module = mqptr->module;
+			mqtbl[e_idx].q_type = mqptr->q_type;
+			mqtbl[e_idx].q_max_len = mqptr->q_max_len;
+			mqptr++;
+		}
+
+		adsp_info.init_info_state = ADSP_STATE_INIT_INFO;
+		kfree(adsp_info.raw_event);
+		wake_up(&adsp_info.init_info_wait);
+		return;
+	}
+	pkt_ptr = &args->adsp_rtos_mp_mtoa_data.mp_mtoa_packet;
+	module_id = pkt_ptr->module;
+	image     = pkt_ptr->image;
+
+	MM_INFO("rpc event=%d, proc_id=%d, module=%d, image=%d\n",
+		event, proc_id, module_id, image);
+
+	module = find_adsp_module_by_id(&adsp_info, module_id);
+	if (!module) {
+		MM_ERR("module %d is not supported!\n", module_id);
+		return;
+	}
+
+	mutex_lock(&module->lock);
+	switch (event) {
+	case RPC_ADSP_RTOS_MOD_READY:
+		MM_INFO("module %s: READY\n", module->name);
+		module->state = ADSP_STATE_ENABLED;
+		wake_up(&module->state_wait);
+		adsp_set_image(module->info, image);
+		break;
+	case RPC_ADSP_RTOS_MOD_DISABLE:
+		MM_INFO("module %s: DISABLED\n", module->name);
+		module->state = ADSP_STATE_DISABLED;
+		wake_up(&module->state_wait);
+		break;
+	case RPC_ADSP_RTOS_SERVICE_RESET:
+		MM_INFO("module %s: SERVICE_RESET\n", module->name);
+		module->state = ADSP_STATE_DISABLED;
+		wake_up(&module->state_wait);
+		break;
+	case RPC_ADSP_RTOS_CMD_SUCCESS:
+		MM_INFO("module %s: CMD_SUCCESS\n", module->name);
+		break;
+	case RPC_ADSP_RTOS_CMD_FAIL:
+		MM_INFO("module %s: CMD_FAIL\n", module->name);
+		break;
+	case RPC_ADSP_RTOS_DISABLE_FAIL:
+		MM_INFO("module %s: DISABLE_FAIL\n", module->name);
+		break;
+	default:
+		MM_ERR("unknown event %d\n", event);
+		mutex_unlock(&module->lock);
+		return;
+	}
+#ifdef CONFIG_MSM_ADSP_REPORT_EVENTS
+	event_addr = (uint32_t *)evt_buf;
+	if (module->ops)
+		module->ops->event(module->driver_data,
+					EVENT_MSG_ID,
+					EVENT_LEN,
+					read_event);
+#endif
+	mutex_unlock(&module->lock);
+}
+
+static size_t read_event_size;
+static void *read_event_addr;
+
+static void read_event_16(void *buf, size_t len)
+{
+	uint16_t *dst = buf;
+	uint16_t *src = read_event_addr;
+	len /= 2;
+	if (len > read_event_size)
+		len = read_event_size;
+	while (len--)
+		*dst++ = *src++;
+}
+
+static void read_event_32(void *buf, size_t len)
+{
+	uint32_t *dst = buf;
+	uint32_t *src = read_event_addr;
+	len /= 2;
+	if (len > read_event_size)
+		len = read_event_size;
+	while (len--)
+		*dst++ = *src++;
+}
+
+static int adsp_rtos_read_ctrl_word_cmd_tast_to_h_v(
+	struct adsp_info *info, void *dsp_addr)
+{
+	struct msm_adsp_module *module;
+	unsigned rtos_task_id;
+	unsigned msg_id;
+	unsigned msg_length;
+#ifdef CONFIG_DEBUG_FS
+	uint16_t *ptr;
+	int ii;
+#endif /* CONFIG_DEBUG_FS */
+	void (*func)(void *, size_t);
+
+	if (dsp_addr >= (void *)(MSM_AD5_BASE + QDSP_RAMC_OFFSET)) {
+		uint32_t *dsp_addr32 = dsp_addr;
+		uint32_t tmp = *dsp_addr32++;
+		rtos_task_id = (tmp & ADSP_RTOS_READ_CTRL_WORD_TASK_ID_M) >> 8;
+		msg_id = (tmp & ADSP_RTOS_READ_CTRL_WORD_MSG_ID_M);
+		read_event_size = tmp >> 16;
+		read_event_addr = dsp_addr32;
+		msg_length = read_event_size * sizeof(uint32_t);
+		func = read_event_32;
+	} else {
+		uint16_t *dsp_addr16 = dsp_addr;
+		uint16_t tmp = *dsp_addr16++;
+		rtos_task_id = (tmp & ADSP_RTOS_READ_CTRL_WORD_TASK_ID_M) >> 8;
+		msg_id = tmp & ADSP_RTOS_READ_CTRL_WORD_MSG_ID_M;
+		read_event_size = *dsp_addr16++;
+		read_event_addr = dsp_addr16;
+		msg_length = read_event_size * sizeof(uint16_t);
+		func = read_event_16;
+	}
+
+	if (rtos_task_id > info->max_task_id) {
+		MM_ERR("bogus task id %d\n", rtos_task_id);
+		return 0;
+	}
+	module = find_adsp_module_by_id(info,
+					adsp_get_module(info, rtos_task_id));
+
+	if (!module) {
+		MM_ERR("no module for task id %d\n", rtos_task_id);
+		return 0;
+	}
+
+	module->num_events++;
+
+	if (!module->ops) {
+		MM_ERR("module %s is not open\n", module->name);
+		return 0;
+	}
+#ifdef CONFIG_DEBUG_FS
+	if (rdump > 0) {
+		ptr = read_event_addr;
+		pr_info("D->A\n");
+		pr_info("m_id = %x id = %x\n", module->id, msg_id);
+		for (ii = 0; ii < msg_length/2; ii++)
+			pr_info("%x ", ptr[ii]);
+		pr_info("\n");
+	}
+#endif /* CONFIG_DEBUG_FS */
+
+	module->ops->event(module->driver_data, msg_id, msg_length, func);
+	return 0;
+}
+
+static int adsp_get_event(struct adsp_info *info)
+{
+	uint32_t ctrl_word;
+	uint32_t ready;
+	void *dsp_addr;
+	uint32_t cmd_type;
+	int cnt;
+	unsigned long flags;
+	int rc = 0;
+
+	spin_lock_irqsave(&adsp_cmd_lock, flags);
+
+	/* Whenever the DSP has a message, it updates this control word
+	 * and generates an interrupt.  When we receive the interrupt, we
+	 * read this register to find out what ADSP task the command is
+	 * comming from.
+	 *
+	 * The ADSP should *always* be ready on the first call, but the
+	 * irq handler calls us in a loop (to handle back-to-back command
+	 * processing), so we give the DSP some time to return to the
+	 * ready state.  The DSP will not issue another IRQ for events
+	 * pending between the first IRQ and the event queue being drained,
+	 * unfortunately.
+	 */
+
+	for (cnt = 0; cnt < 50; cnt++) {
+		ctrl_word = readl(info->read_ctrl);
+
+		if ((ctrl_word & ADSP_RTOS_READ_CTRL_WORD_FLAG_M) ==
+		    ADSP_RTOS_READ_CTRL_WORD_FLAG_UP_CONT_V)
+			goto ready;
+
+		udelay(2);
+	}
+	MM_ERR("not ready after 100uS\n");
+	rc = -EBUSY;
+	goto done;
+
+ready:
+	/* Here we check to see if there are pending messages. If there are
+	 * none, we siply return -EAGAIN to indicate that there are no more
+	 * messages pending.
+	 */
+	ready = ctrl_word & ADSP_RTOS_READ_CTRL_WORD_READY_M;
+	if ((ready != ADSP_RTOS_READ_CTRL_WORD_READY_V) &&
+	    (ready != ADSP_RTOS_READ_CTRL_WORD_CONT_V)) {
+		rc = -EAGAIN;
+		goto done;
+	}
+
+	/* DSP says that there are messages waiting for the host to read */
+
+	/* Get the Command Type */
+	cmd_type = ctrl_word & ADSP_RTOS_READ_CTRL_WORD_CMD_TYPE_M;
+
+	/* Get the DSP buffer address */
+	dsp_addr = (void *)((ctrl_word &
+			     ADSP_RTOS_READ_CTRL_WORD_DSP_ADDR_M) +
+			    (uint32_t)MSM_AD5_BASE);
+
+	/* We can only handle Task-to-Host messages */
+	if (cmd_type != ADSP_RTOS_READ_CTRL_WORD_CMD_TASK_TO_H_V) {
+		MM_ERR("unknown dsp cmd_type %d\n", cmd_type);
+		rc = -EIO;
+		goto done;
+	}
+
+	adsp_rtos_read_ctrl_word_cmd_tast_to_h_v(info, dsp_addr);
+
+	ctrl_word = readl(info->read_ctrl);
+	ctrl_word &= ~ADSP_RTOS_READ_CTRL_WORD_READY_M;
+
+	/* Write ctrl word to the DSP */
+	writel(ctrl_word, info->read_ctrl);
+
+	/* Generate an interrupt to the DSP */
+	writel(1, info->send_irq);
+
+done:
+	spin_unlock_irqrestore(&adsp_cmd_lock, flags);
+	return rc;
+}
+
+static irqreturn_t adsp_irq_handler(int irq, void *data)
+{
+	struct adsp_info *info = &adsp_info;
+	int cnt = 0;
+	for (cnt = 0; cnt < 15; cnt++)
+		if (adsp_get_event(info) < 0)
+			break;
+	if (cnt > info->event_backlog_max)
+		info->event_backlog_max = cnt;
+	info->events_received += cnt;
+	if (cnt == 15)
+		MM_ERR("too many (%d) events for single irq!\n", cnt);
+	return IRQ_HANDLED;
+}
+
+int adsp_set_clkrate(struct msm_adsp_module *module, unsigned long clk_rate)
+{
+	if (module->clk && clk_rate)
+		return clk_set_rate(module->clk, clk_rate);
+
+	return -EINVAL;
+}
+
+int msm_adsp_enable(struct msm_adsp_module *module)
+{
+	int rc = 0;
+
+	MM_INFO("enable '%s'state[%d] id[%d]\n",
+				module->name, module->state, module->id);
+
+	mutex_lock(&module->lock);
+	switch (module->state) {
+	case ADSP_STATE_DISABLED:
+		module->state = ADSP_STATE_ENABLING;
+		mutex_unlock(&module->lock);
+		rc = rpc_adsp_rtos_app_to_modem(RPC_ADSP_RTOS_CMD_ENABLE,
+						module->id, module);
+		if (rc) {
+			mutex_lock(&module->lock);
+			module->state = ADSP_STATE_DISABLED;
+			break;
+		}
+		rc = wait_event_timeout(module->state_wait,
+					module->state != ADSP_STATE_ENABLING,
+					1 * HZ);
+		mutex_lock(&module->lock);
+		if (module->state == ADSP_STATE_ENABLED) {
+			rc = 0;
+		} else {
+			MM_ERR("module '%s' enable timed out\n", module->name);
+			rc = -ETIMEDOUT;
+		}
+		if (module->open_count++ == 0 && module->clk)
+			clk_enable(module->clk);
+
+		mutex_lock(&adsp_open_lock);
+		if (adsp_open_count++ == 0)
+			enable_irq(adsp_info.int_adsp);
+		mutex_unlock(&adsp_open_lock);
+		break;
+	case ADSP_STATE_ENABLING:
+		MM_DBG("module '%s' enable in progress\n", module->name);
+		break;
+	case ADSP_STATE_ENABLED:
+		MM_DBG("module '%s' already enabled\n", module->name);
+		break;
+	case ADSP_STATE_DISABLING:
+		MM_ERR("module '%s' disable in progress\n", module->name);
+		rc = -EBUSY;
+		break;
+	}
+	mutex_unlock(&module->lock);
+	return rc;
+}
+EXPORT_SYMBOL(msm_adsp_enable);
+
+int msm_adsp_disable_event_rsp(struct msm_adsp_module *module)
+{
+	int rc = 0;
+
+	mutex_lock(&module->lock);
+
+	rc = rpc_adsp_rtos_app_to_modem(RPC_ADSP_RTOS_CMD_DISABLE_EVENT_RSP,
+							module->id, module);
+	mutex_unlock(&module->lock);
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_adsp_disable_event_rsp);
+
+int msm_adsp_disable(struct msm_adsp_module *module)
+{
+	int rc = 0;
+
+	mutex_lock(&module->lock);
+	switch (module->state) {
+	case ADSP_STATE_DISABLED:
+		MM_DBG("module '%s' already disabled\n", module->name);
+		mutex_unlock(&module->lock);
+		break;
+	case ADSP_STATE_ENABLING:
+	case ADSP_STATE_ENABLED:
+		mutex_unlock(&module->lock);
+		rc = rpc_adsp_rtos_app_to_modem(RPC_ADSP_RTOS_CMD_DISABLE,
+						module->id, module);
+		mutex_lock(&module->lock);
+		module->state = ADSP_STATE_DISABLED;
+		if (--module->open_count == 0 && module->clk)
+			clk_disable(module->clk);
+		mutex_unlock(&module->lock);
+		mutex_lock(&adsp_open_lock);
+		if (--adsp_open_count == 0) {
+			disable_irq(adsp_info.int_adsp);
+			MM_INFO("disable interrupt\n");
+		}
+		mutex_unlock(&adsp_open_lock);
+		break;
+	}
+	return rc;
+}
+EXPORT_SYMBOL(msm_adsp_disable);
+
+static int msm_adsp_probe(struct platform_device *pdev)
+{
+	unsigned count;
+	int rc, i;
+
+	adsp_info.int_adsp = platform_get_irq(pdev, 0);
+	if (adsp_info.int_adsp < 0) {
+		MM_ERR("no irq resource?\n");
+		return -ENODEV;
+	}
+
+	adsp_info.init_info_ptr = kzalloc(
+		(sizeof(struct adsp_rtos_mp_mtoa_init_info_type)), GFP_KERNEL);
+	if (!adsp_info.init_info_ptr)
+		return -ENOMEM;
+
+	adsp_info.raw_event = kzalloc(
+		(sizeof(struct adsp_rtos_mp_mtoa_s_type)), GFP_KERNEL);
+	if (!adsp_info.raw_event) {
+		kfree(adsp_info.init_info_ptr);
+		return -ENOMEM;
+	}
+
+	rc = adsp_init_info(&adsp_info);
+	if (rc) {
+		kfree(adsp_info.init_info_ptr);
+		kfree(adsp_info.raw_event);
+		return rc;
+	}
+	adsp_info.send_irq += (uint32_t) MSM_AD5_BASE;
+	adsp_info.read_ctrl += (uint32_t) MSM_AD5_BASE;
+	adsp_info.write_ctrl += (uint32_t) MSM_AD5_BASE;
+	count = adsp_info.module_count;
+
+	adsp_modules = kzalloc(
+		(sizeof(struct msm_adsp_module) + sizeof(void *)) *
+		count, GFP_KERNEL);
+	if (!adsp_modules) {
+		kfree(adsp_info.init_info_ptr);
+		kfree(adsp_info.raw_event);
+		return -ENOMEM;
+	}
+
+	adsp_info.id_to_module = (void *) (adsp_modules + count);
+
+	spin_lock_init(&adsp_cmd_lock);
+	spin_lock_init(&adsp_write_lock);
+
+	rc = request_irq(adsp_info.int_adsp, adsp_irq_handler,
+			IRQF_TRIGGER_RISING, "adsp", 0);
+	if (rc < 0)
+		goto fail_request_irq;
+	disable_irq(adsp_info.int_adsp);
+
+	for (i = 0; i < count; i++) {
+		struct msm_adsp_module *mod = adsp_modules + i;
+		mutex_init(&mod->lock);
+		init_waitqueue_head(&mod->state_wait);
+		mod->info = &adsp_info;
+		mod->name = adsp_info.module[i].name;
+		mod->id = adsp_info.module[i].id;
+		if (adsp_info.module[i].clk_name)
+			mod->clk = clk_get(NULL, adsp_info.module[i].clk_name);
+		else
+			mod->clk = NULL;
+		if (mod->clk && adsp_info.module[i].clk_rate)
+			clk_set_rate(mod->clk, adsp_info.module[i].clk_rate);
+		mod->verify_cmd = adsp_info.module[i].verify_cmd;
+		mod->patch_event = adsp_info.module[i].patch_event;
+		INIT_HLIST_HEAD(&mod->pmem_regions);
+		mod->pdev.name = adsp_info.module[i].pdev_name;
+		mod->pdev.id = -1;
+		adsp_info.id_to_module[i] = mod;
+		platform_device_register(&mod->pdev);
+	}
+
+	msm_adsp_publish_cdevs(adsp_modules, count);
+
+	rc = daldevice_attach(DALRPC_ADSPSVC_DEVICEID, DALRPC_ADSPSVC_PORT,
+					DALRPC_ADSPSVC_DEST, &adsp_info.handle);
+	if (rc) {
+		MM_ERR("adsp attach failed : %d\n", rc);
+		goto fail_dal_attach;
+	}
+
+	adsp_info.cb_handle = dalrpc_alloc_cb(adsp_info.handle,
+						adsp_rtos_mtoa_cb, NULL);
+	if (adsp_info.cb_handle == NULL) {
+		MM_ERR("Callback registration failed\n");
+		goto fail_allocate_cb;
+	}
+
+	/* Get INIT_INFO */
+	init_waitqueue_head(&adsp_info.init_info_wait);
+	msm_get_init_info();
+	rc = wait_event_timeout(adsp_info.init_info_wait,
+		adsp_info.init_info_state == ADSP_STATE_INIT_INFO,
+		10 * HZ);
+	if (!rc) {
+		MM_ERR("INIT_INFO failed\n");
+		rc = -ETIMEDOUT;
+	} else
+		return 0;
+
+fail_allocate_cb:
+	daldevice_detach(adsp_info.handle);
+	adsp_info.handle = NULL;
+fail_dal_attach:
+	enable_irq(adsp_info.int_adsp);
+	free_irq(adsp_info.int_adsp, 0);
+fail_request_irq:
+	kfree(adsp_modules);
+	kfree(adsp_info.init_info_ptr);
+	kfree(adsp_info.raw_event);
+	return rc;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int get_parameters(char *buf, long int *param1, int num_of_par)
+{
+	char *token;
+	int base, cnt;
+
+	token = strsep(&buf, " ");
+
+	for (cnt = 0; cnt < num_of_par; cnt++) {
+		if (token != NULL) {
+			if ((token[1] == 'x') || (token[1] == 'X'))
+				base = 16;
+			else
+				base = 10;
+
+			if (strict_strtoul(token, base, &param1[cnt]) != 0)
+				return -EINVAL;
+
+			token = strsep(&buf, " ");
+			}
+		else
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static ssize_t adsp_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	pr_debug("adsp debugfs opened\n");
+	return 0;
+}
+static ssize_t adsp_debug_write(struct file *file, const char __user *buf,
+				size_t cnt, loff_t *ppos)
+{
+	char *access_str = file->private_data;
+	char lbuf[32];
+	int rc;
+	long int param[5];
+
+	if (cnt > sizeof(lbuf) - 1)
+		return -EINVAL;
+	rc = copy_from_user(lbuf, buf, cnt);
+	if (rc) {
+		pr_info("Unable to copy data from user space\n");
+		return -EFAULT;
+	}
+	lbuf[cnt] = '\0';
+
+	if (!strncmp(access_str, "write_log", 9)) {
+		if (get_parameters(lbuf, param, 1) == 0) {
+			switch (param[0]) {
+			case 1:
+				if (wdump <= 0)
+					wdump = 1;
+				pr_debug("write cmd to DSP(A->D) dump \
+					 started:%d\n", wdump);
+				break;
+			case 0:
+				if (wdump > 0)
+					wdump = 0;
+				pr_debug("Stop write cmd to \
+					 DSP(A->D):%d\n", wdump);
+				break;
+			default:
+				rc = -EINVAL;
+				break;
+			}
+		} else
+			rc = -EINVAL;
+	} else if (!strncmp(access_str, "read_log", 8)) {
+		if (get_parameters(lbuf, param, 1) == 0) {
+			switch (param[0]) {
+			case 1:
+				if (rdump <= 0)
+					rdump = 1;
+				pr_debug("write cmd from DSP(D->A) dump \
+					started:%d\n", wdump);
+				break;
+			case 0:
+				if (rdump > 0)
+					rdump = 0;
+				pr_debug("Stop write cmd from \
+					DSP(D->A):%d\n", wdump);
+				break;
+			default:
+				rc = -EINVAL;
+				break;
+			}
+		} else
+			rc = -EINVAL;
+	} else {
+		rc = -EINVAL;
+	}
+	if (rc == 0)
+		rc = cnt;
+	else {
+		pr_err("%s: rc = %d\n", __func__, rc);
+		pr_info("\nWrong command: Use =>\n");
+		pr_info("-------------------------\n");
+		pr_info("To Start A->D:: echo \"1\">/sys/kernel/debug/ \
+			adsp_cmd/write_log\n");
+		pr_info("To Start D->A:: echo \"1\">/sys/kernel/debug/ \
+			adsp_cmd/read_log\n");
+		pr_info("To Stop  A->D:: echo \"0\">/sys/kernel/debug/ \
+			adsp_cmd/write_log\n");
+		pr_info("To Stop  D->A:: echo \"0\">/sys/kernel/debug/ \
+			adsp_cmd/read_log\n");
+		pr_info("------------------------\n");
+	}
+
+	return rc;
+}
+#endif
+
+static struct platform_driver msm_adsp_driver = {
+	.probe = msm_adsp_probe,
+	.driver = {
+		.owner = THIS_MODULE,
+	},
+};
+
+static char msm_adsp_driver_name[] = "msm_adsp";
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations adsp_debug_fops = {
+	.write = adsp_debug_write,
+	.open = adsp_debug_open,
+};
+#endif
+
+static int __init adsp_init(void)
+{
+	int rc;
+
+#ifdef CONFIG_DEBUG_FS
+	dentry_adsp    = debugfs_create_dir("adsp_cmd", 0);
+	if (!IS_ERR(dentry_adsp)) {
+		dentry_wdata   = debugfs_create_file("write_log", \
+		 S_IFREG | S_IRUGO, dentry_adsp,
+		 (void *) "write_log" , &adsp_debug_fops);
+		dentry_rdata   = debugfs_create_file("read_log", \
+		 S_IFREG | S_IRUGO, dentry_adsp,
+		 (void *) "read_log", &adsp_debug_fops);
+	}
+#endif /* CONFIG_DEBUG_FS */
+
+	msm_adsp_driver.driver.name = msm_adsp_driver_name;
+	rc = platform_driver_register(&msm_adsp_driver);
+	MM_INFO("%s -- %d\n", msm_adsp_driver_name, rc);
+	return rc;
+}
+
+device_initcall(adsp_init);
diff --git a/arch/arm/mach-msm/qdsp5v2/adsp.h b/arch/arm/mach-msm/qdsp5v2/adsp.h
new file mode 100644
index 0000000..5aceff9
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/adsp.h
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ * Author: Iliyan Malchev <ibm@android.com>
+ *
+ * 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 _ARCH_ARM_MACH_MSM_ADSP_H
+#define _ARCH_ARM_MACH_MSM_ADSP_H
+
+#include <linux/types.h>
+#include <linux/msm_adsp.h>
+#include <linux/platform_device.h>
+#include <mach/msm_adsp.h>
+#include <mach/dal.h>
+
+int adsp_pmem_fixup(struct msm_adsp_module *module, void **addr,
+		    unsigned long len);
+int adsp_pmem_fixup_kvaddr(struct msm_adsp_module *module, void **addr,
+			   unsigned long *kvaddr, unsigned long len);
+int adsp_pmem_paddr_fixup(struct msm_adsp_module *module, void **addr);
+
+int adsp_vfe_verify_cmd(struct msm_adsp_module *module,
+			unsigned int queue_id, void *cmd_data,
+			size_t cmd_size);
+int adsp_jpeg_verify_cmd(struct msm_adsp_module *module,
+			 unsigned int queue_id, void *cmd_data,
+			 size_t cmd_size);
+int adsp_lpm_verify_cmd(struct msm_adsp_module *module,
+			unsigned int queue_id, void *cmd_data,
+			size_t cmd_size);
+int adsp_video_verify_cmd(struct msm_adsp_module *module,
+			  unsigned int queue_id, void *cmd_data,
+			  size_t cmd_size);
+int adsp_videoenc_verify_cmd(struct msm_adsp_module *module,
+			  unsigned int queue_id, void *cmd_data,
+			  size_t cmd_size);
+
+
+struct adsp_event;
+
+int adsp_vfe_patch_event(struct msm_adsp_module *module,
+			struct adsp_event *event);
+
+int adsp_jpeg_patch_event(struct msm_adsp_module *module,
+			struct adsp_event *event);
+
+
+struct adsp_module_info {
+	const char *name;
+	const char *pdev_name;
+	uint32_t id;
+	const char *clk_name;
+	unsigned long clk_rate;
+	int (*verify_cmd) (struct msm_adsp_module*, unsigned int, void *,
+			   size_t);
+	int (*patch_event) (struct msm_adsp_module*, struct adsp_event *);
+};
+
+#define ADSP_EVENT_MAX_SIZE 496
+#define EVENT_LEN       12
+#define EVENT_MSG_ID ((uint16_t)~0)
+
+struct adsp_event {
+	struct list_head list;
+	uint32_t size; /* always in bytes */
+	uint16_t msg_id;
+	uint16_t type; /* 0 for msgs (from aDSP), -1 for events (from ARM9) */
+	int is16; /* always 0 (msg is 32-bit) when the event type is 1(ARM9) */
+	union {
+		uint16_t msg16[ADSP_EVENT_MAX_SIZE / 2];
+		uint32_t msg32[ADSP_EVENT_MAX_SIZE / 4];
+	} data;
+};
+
+#define DALRPC_ADSPSVC_DEVICEID 0x0200009A
+#define DALRPC_ADSPSVC_DEST SMD_APPS_MODEM
+#define DALRPC_ADSPSVC_PORT "DAL00"
+
+enum {
+	DALDEVICE_ADSP_CMD_IDX = DALDEVICE_FIRST_DEVICE_API_IDX,
+};
+
+struct adsp_rtos_atom_cmd {
+	uint32_t cmd;
+	uint32_t proc_id;
+	uint32_t module;
+	void *cb_handle;
+};
+
+enum rpc_adsp_rtos_proc_type {
+	RPC_ADSP_RTOS_PROC_NONE = 0,
+	RPC_ADSP_RTOS_PROC_MODEM = 1,
+	RPC_ADSP_RTOS_PROC_APPS = 2,
+};
+
+enum {
+	RPC_ADSP_RTOS_CMD_REGISTER_APP,
+	RPC_ADSP_RTOS_CMD_ENABLE,
+	RPC_ADSP_RTOS_CMD_DISABLE,
+	RPC_ADSP_RTOS_CMD_KERNEL_COMMAND,
+	RPC_ADSP_RTOS_CMD_16_COMMAND,
+	RPC_ADSP_RTOS_CMD_32_COMMAND,
+	RPC_ADSP_RTOS_CMD_DISABLE_EVENT_RSP,
+	RPC_ADSP_RTOS_CMD_REMOTE_EVENT,
+	RPC_ADSP_RTOS_CMD_SET_STATE,
+	RPC_ADSP_RTOS_CMD_REMOTE_INIT_INFO_EVENT,
+	RPC_ADSP_RTOS_CMD_GET_INIT_INFO,
+};
+
+enum rpc_adsp_rtos_mod_status_type {
+	RPC_ADSP_RTOS_MOD_READY,
+	RPC_ADSP_RTOS_MOD_DISABLE,
+	RPC_ADSP_RTOS_SERVICE_RESET,
+	RPC_ADSP_RTOS_CMD_FAIL,
+	RPC_ADSP_RTOS_CMD_SUCCESS,
+	RPC_ADSP_RTOS_INIT_INFO,
+	RPC_ADSP_RTOS_DISABLE_FAIL,
+};
+
+enum qdsp_image_type {
+	QDSP_IMAGE_COMBO,
+	QDSP_IMAGE_GAUDIO,
+	QDSP_IMAGE_QTV_LP,
+	QDSP_IMAGE_MAX,
+	/* DO NOT USE: Force this enum to be a 32bit type to improve speed */
+	QDSP_IMAGE_32BIT_DUMMY = 0x10000
+};
+
+struct adsp_rtos_mp_mtoa_header_type {
+	enum rpc_adsp_rtos_mod_status_type  event;
+	uint32_t		            version;
+	enum rpc_adsp_rtos_proc_type        proc_id;
+};
+
+/* ADSP RTOS MP Communications - Modem to APP's  Event Info*/
+struct adsp_rtos_mp_mtoa_type {
+	uint32_t	module;
+	uint32_t	image;
+	uint32_t	apps_okts;
+};
+
+/* ADSP RTOS MP Communications - Modem to APP's Init Info  */
+#define IMG_MAX         2
+#define ENTRIES_MAX     36
+#define MODULES_MAX     64
+#define QUEUES_MAX	64
+
+struct queue_to_offset_type {
+	uint32_t	queue;
+	uint32_t	offset;
+};
+
+struct mod_to_queue_offsets {
+	uint32_t        module;
+	uint32_t        q_type;
+	uint32_t        q_max_len;
+};
+
+struct adsp_rtos_mp_mtoa_init_info_type {
+	uint32_t	image_count;
+	uint32_t	num_queue_offsets;
+	struct queue_to_offset_type	queue_offsets_tbl[IMG_MAX][ENTRIES_MAX];
+	uint32_t	num_task_module_entries;
+	uint32_t	task_to_module_tbl[IMG_MAX][ENTRIES_MAX];
+
+	uint32_t	module_table_size;
+	uint32_t	module_entries[MODULES_MAX];
+	uint32_t	mod_to_q_entries;
+	struct mod_to_queue_offsets	mod_to_q_tbl[ENTRIES_MAX];
+	/*
+	 * queue_offsets[] is to store only queue_offsets
+	 */
+	uint32_t	queue_offsets[IMG_MAX][QUEUES_MAX];
+};
+
+struct adsp_rtos_mp_mtoa_s_type {
+	struct adsp_rtos_mp_mtoa_header_type mp_mtoa_header;
+
+	union {
+		struct adsp_rtos_mp_mtoa_init_info_type mp_mtoa_init_packet;
+		struct adsp_rtos_mp_mtoa_type mp_mtoa_packet;
+	} adsp_rtos_mp_mtoa_data;
+};
+
+struct adsp_info {
+	uint32_t send_irq;
+	uint32_t read_ctrl;
+	uint32_t write_ctrl;
+
+	uint32_t max_msg16_size;
+	uint32_t max_msg32_size;
+
+	uint32_t max_task_id;
+	uint32_t max_module_id;
+	uint32_t max_queue_id;
+	uint32_t max_image_id;
+
+	/* for each image id, a map of queue id to offset */
+	uint32_t **queue_offset;
+
+	/* for each image id, a map of task id to module id */
+	uint32_t **task_to_module;
+
+	/* for each module id, map of module id to module */
+	struct msm_adsp_module **id_to_module;
+
+	uint32_t module_count;
+	struct adsp_module_info *module;
+
+	/* stats */
+	uint32_t events_received;
+	uint32_t event_backlog_max;
+
+	/* rpc_client for init_info */
+	struct adsp_rtos_mp_mtoa_init_info_type	*init_info_ptr;
+	struct adsp_rtos_mp_mtoa_s_type *raw_event;
+	wait_queue_head_t	init_info_wait;
+	unsigned 		init_info_state;
+
+	void *handle;
+	void *cb_handle;
+
+	/* Interrupt value */
+	int int_adsp;
+};
+
+#define ADSP_STATE_DISABLED   0
+#define ADSP_STATE_ENABLING   1
+#define ADSP_STATE_ENABLED    2
+#define ADSP_STATE_DISABLING  3
+#define ADSP_STATE_INIT_INFO  4
+
+struct msm_adsp_module {
+	struct mutex lock;
+	const char *name;
+	unsigned id;
+	struct adsp_info *info;
+
+	struct msm_adsp_ops *ops;
+	void *driver_data;
+
+	/* statistics */
+	unsigned num_commands;
+	unsigned num_events;
+
+	wait_queue_head_t state_wait;
+	unsigned state;
+
+	struct platform_device pdev;
+	struct clk *clk;
+	int open_count;
+
+	struct mutex pmem_regions_lock;
+	struct hlist_head pmem_regions;
+	int (*verify_cmd) (struct msm_adsp_module*, unsigned int, void *,
+			   size_t);
+	int (*patch_event) (struct msm_adsp_module*, struct adsp_event *);
+};
+
+extern void msm_adsp_publish_cdevs(struct msm_adsp_module *, unsigned);
+extern int adsp_init_info(struct adsp_info *info);
+
+/* Value to indicate that a queue is not defined for a particular image */
+#define QDSP_RTOS_NO_QUEUE  0xfffffffe
+
+/*
+ * Constants used to communicate with the ADSP RTOS
+ */
+#define ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_M            0x80000000U
+#define ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_NAVAIL_V     0x80000000U
+#define ADSP_RTOS_WRITE_CTRL_WORD_MUTEX_AVAIL_V      0x00000000U
+
+#define ADSP_RTOS_WRITE_CTRL_WORD_CMD_M              0x70000000U
+#define ADSP_RTOS_WRITE_CTRL_WORD_CMD_WRITE_REQ_V    0x00000000U
+#define ADSP_RTOS_WRITE_CTRL_WORD_CMD_WRITE_DONE_V   0x10000000U
+#define ADSP_RTOS_WRITE_CTRL_WORD_CMD_NO_CMD_V       0x70000000U
+
+#define ADSP_RTOS_WRITE_CTRL_WORD_STATUS_M           0x0E000000U
+#define ADSP_RTOS_WRITE_CTRL_WORD_NO_ERR_V           0x00000000U
+#define ADSP_RTOS_WRITE_CTRL_WORD_NO_FREE_BUF_V      0x02000000U
+
+#define ADSP_RTOS_WRITE_CTRL_WORD_KERNEL_FLG_M       0x01000000U
+#define ADSP_RTOS_WRITE_CTRL_WORD_HTOD_MSG_WRITE_V   0x00000000U
+#define ADSP_RTOS_WRITE_CTRL_WORD_HTOD_CMD_V         0x01000000U
+
+#define ADSP_RTOS_WRITE_CTRL_WORD_DSP_ADDR_M         0x00FFFFFFU
+#define ADSP_RTOS_WRITE_CTRL_WORD_HTOD_CMD_ID_M      0x00FFFFFFU
+
+/* Combination of MUTEX and CMD bits to check if the DSP is busy */
+#define ADSP_RTOS_WRITE_CTRL_WORD_READY_M            0xF0000000U
+#define ADSP_RTOS_WRITE_CTRL_WORD_READY_V            0x70000000U
+
+/* RTOS to Host processor command mask values */
+#define ADSP_RTOS_READ_CTRL_WORD_FLAG_M              0x80000000U
+#define ADSP_RTOS_READ_CTRL_WORD_FLAG_UP_WAIT_V      0x00000000U
+#define ADSP_RTOS_READ_CTRL_WORD_FLAG_UP_CONT_V      0x80000000U
+
+#define ADSP_RTOS_READ_CTRL_WORD_CMD_M               0x60000000U
+#define ADSP_RTOS_READ_CTRL_WORD_READ_DONE_V         0x00000000U
+#define ADSP_RTOS_READ_CTRL_WORD_READ_REQ_V          0x20000000U
+#define ADSP_RTOS_READ_CTRL_WORD_NO_CMD_V            0x60000000U
+
+/* Combination of FLAG and COMMAND bits to check if MSG ready */
+#define ADSP_RTOS_READ_CTRL_WORD_READY_M             0xE0000000U
+#define ADSP_RTOS_READ_CTRL_WORD_READY_V             0xA0000000U
+#define ADSP_RTOS_READ_CTRL_WORD_CONT_V              0xC0000000U
+#define ADSP_RTOS_READ_CTRL_WORD_DONE_V              0xE0000000U
+
+#define ADSP_RTOS_READ_CTRL_WORD_STATUS_M            0x18000000U
+#define ADSP_RTOS_READ_CTRL_WORD_NO_ERR_V            0x00000000U
+
+#define ADSP_RTOS_READ_CTRL_WORD_IN_PROG_M           0x04000000U
+#define ADSP_RTOS_READ_CTRL_WORD_NO_READ_IN_PROG_V   0x00000000U
+#define ADSP_RTOS_READ_CTRL_WORD_READ_IN_PROG_V      0x04000000U
+
+#define ADSP_RTOS_READ_CTRL_WORD_CMD_TYPE_M          0x03000000U
+#define ADSP_RTOS_READ_CTRL_WORD_CMD_TASK_TO_H_V     0x00000000U
+#define ADSP_RTOS_READ_CTRL_WORD_CMD_KRNL_TO_H_V     0x01000000U
+#define ADSP_RTOS_READ_CTRL_WORD_CMD_H_TO_KRNL_CFM_V 0x02000000U
+
+#define ADSP_RTOS_READ_CTRL_WORD_DSP_ADDR_M          0x00FFFFFFU
+
+#define ADSP_RTOS_READ_CTRL_WORD_MSG_ID_M            0x000000FFU
+#define ADSP_RTOS_READ_CTRL_WORD_TASK_ID_M           0x0000FF00U
+
+/* Base address of DSP and DSP hardware registers */
+#define QDSP_RAMC_OFFSET  0x400000
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp5v2/adsp_driver.c b/arch/arm/mach-msm/qdsp5v2/adsp_driver.c
new file mode 100644
index 0000000..2a4e4ec
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/adsp_driver.c
@@ -0,0 +1,656 @@
+/*
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ * Author: Iliyan Malchev <ibm@android.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/msm_adsp.h>
+#include <linux/android_pmem.h>
+#include <linux/export.h>
+#include "adsp.h"
+#include <mach/debug_mm.h>
+#include <linux/slab.h>
+
+struct adsp_pmem_info {
+	int fd;
+	void *vaddr;
+};
+
+struct adsp_pmem_region {
+	struct hlist_node list;
+	void *vaddr;
+	unsigned long paddr;
+	unsigned long kvaddr;
+	unsigned long len;
+	struct file *file;
+};
+
+struct adsp_device {
+	struct msm_adsp_module *module;
+
+	spinlock_t event_queue_lock;
+	wait_queue_head_t event_wait;
+	struct list_head event_queue;
+	int abort;
+
+	const char *name;
+	struct device *device;
+	struct cdev cdev;
+};
+
+static struct adsp_device *inode_to_device(struct inode *inode);
+
+#define __CONTAINS(r, v, l) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __v = v;					\
+	typeof(v) __e = __v + l;				\
+	int res = __v >= __r->vaddr && 				\
+		__e <= __r->vaddr + __r->len;			\
+	res;							\
+})
+
+#define CONTAINS(r1, r2) ({					\
+	typeof(r2) __r2 = r2;					\
+	__CONTAINS(r1, __r2->vaddr, __r2->len);			\
+})
+
+#define IN_RANGE(r, v) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __vv = v;					\
+	int res = ((__vv >= __r->vaddr) &&			\
+		(__vv < (__r->vaddr + __r->len)));		\
+	res;							\
+})
+
+#define OVERLAPS(r1, r2) ({					\
+	typeof(r1) __r1 = r1;					\
+	typeof(r2) __r2 = r2;					\
+	typeof(__r2->vaddr) __v = __r2->vaddr;			\
+	typeof(__v) __e = __v + __r2->len - 1;			\
+	int res = (IN_RANGE(__r1, __v) || IN_RANGE(__r1, __e));	\
+	res;							\
+})
+
+static int adsp_pmem_check(struct msm_adsp_module *module,
+		void *vaddr, unsigned long len)
+{
+	struct adsp_pmem_region *region_elt;
+	struct hlist_node *node;
+	struct adsp_pmem_region t = { .vaddr = vaddr, .len = len };
+
+	hlist_for_each_entry(region_elt, node, &module->pmem_regions, list) {
+		if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
+		    OVERLAPS(region_elt, &t)) {
+			MM_ERR("module %s:"
+				" region (vaddr %p len %ld)"
+				" clashes with registered region"
+				" (vaddr %p paddr %p len %ld)\n",
+				module->name,
+				vaddr, len,
+				region_elt->vaddr,
+				(void *)region_elt->paddr,
+				region_elt->len);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int adsp_pmem_add(struct msm_adsp_module *module,
+			 struct adsp_pmem_info *info)
+{
+	unsigned long paddr, kvaddr, len;
+	struct file *file;
+	struct adsp_pmem_region *region;
+	int rc = -EINVAL;
+
+	mutex_lock(&module->pmem_regions_lock);
+	region = kmalloc(sizeof(*region), GFP_KERNEL);
+	if (!region) {
+		rc = -ENOMEM;
+		goto end;
+	}
+	INIT_HLIST_NODE(&region->list);
+	if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) {
+		kfree(region);
+		goto end;
+	}
+
+	rc = adsp_pmem_check(module, info->vaddr, len);
+	if (rc < 0) {
+		put_pmem_file(file);
+		kfree(region);
+		goto end;
+	}
+
+	region->vaddr = info->vaddr;
+	region->paddr = paddr;
+	region->kvaddr = kvaddr;
+	region->len = len;
+	region->file = file;
+
+	hlist_add_head(&region->list, &module->pmem_regions);
+end:
+	mutex_unlock(&module->pmem_regions_lock);
+	return rc;
+}
+
+static int adsp_pmem_lookup_vaddr(struct msm_adsp_module *module, void **addr,
+		     unsigned long len, struct adsp_pmem_region **region)
+{
+	struct hlist_node *node;
+	void *vaddr = *addr;
+	struct adsp_pmem_region *region_elt;
+
+	int match_count = 0;
+
+	*region = NULL;
+
+	/* returns physical address or zero */
+	hlist_for_each_entry(region_elt, node, &module->pmem_regions, list) {
+		if (vaddr >= region_elt->vaddr &&
+		    vaddr < region_elt->vaddr + region_elt->len &&
+		    vaddr + len <= region_elt->vaddr + region_elt->len) {
+			/* offset since we could pass vaddr inside a registerd
+			 * pmem buffer
+			 */
+
+			match_count++;
+			if (!*region)
+				*region = region_elt;
+		}
+	}
+
+	if (match_count > 1) {
+		MM_ERR("module %s: "
+			"multiple hits for vaddr %p, len %ld\n",
+			module->name, vaddr, len);
+		hlist_for_each_entry(region_elt, node,
+				&module->pmem_regions, list) {
+			if (vaddr >= region_elt->vaddr &&
+			    vaddr < region_elt->vaddr + region_elt->len &&
+			    vaddr + len <= region_elt->vaddr + region_elt->len)
+				MM_ERR("%p, %ld --> %p\n",
+					region_elt->vaddr,
+					region_elt->len,
+					(void *)region_elt->paddr);
+		}
+	}
+
+	return *region ? 0 : -1;
+}
+
+int adsp_pmem_fixup_kvaddr(struct msm_adsp_module *module, void **addr,
+			   unsigned long *kvaddr, unsigned long len)
+{
+	struct adsp_pmem_region *region;
+	void *vaddr = *addr;
+	unsigned long *paddr = (unsigned long *)addr;
+	int ret;
+
+	ret = adsp_pmem_lookup_vaddr(module, addr, len, &region);
+	if (ret) {
+		MM_ERR("not patching %s (paddr & kvaddr),"
+			" lookup (%p, %ld) failed\n",
+			module->name, vaddr, len);
+		return ret;
+	}
+	*paddr = region->paddr + (vaddr - region->vaddr);
+	*kvaddr = region->kvaddr + (vaddr - region->vaddr);
+	return 0;
+}
+
+int adsp_pmem_fixup(struct msm_adsp_module *module, void **addr,
+		    unsigned long len)
+{
+	struct adsp_pmem_region *region;
+	void *vaddr = *addr;
+	unsigned long *paddr = (unsigned long *)addr;
+	int ret;
+
+	ret = adsp_pmem_lookup_vaddr(module, addr, len, &region);
+	if (ret) {
+		MM_ERR("not patching %s, lookup (%p, %ld) failed\n",
+			module->name, vaddr, len);
+		return ret;
+	}
+
+	*paddr = region->paddr + (vaddr - region->vaddr);
+	return 0;
+}
+
+static int adsp_verify_cmd(struct msm_adsp_module *module,
+			   unsigned int queue_id, void *cmd_data,
+			   size_t cmd_size)
+{
+	/* call the per module verifier */
+	if (module->verify_cmd)
+		return module->verify_cmd(module, queue_id, cmd_data,
+					     cmd_size);
+	else
+		MM_INFO("no packet verifying function "
+				 "for task %s\n", module->name);
+	return 0;
+}
+
+static long adsp_write_cmd(struct adsp_device *adev, void __user *arg)
+{
+	struct adsp_command_t cmd;
+	unsigned char buf[256];
+	void *cmd_data;
+	long rc;
+
+	if (copy_from_user(&cmd, (void __user *)arg, sizeof(cmd)))
+		return -EFAULT;
+
+	if (cmd.len > 256) {
+		cmd_data = kmalloc(cmd.len, GFP_USER);
+		if (!cmd_data)
+			return -ENOMEM;
+	} else {
+		cmd_data = buf;
+	}
+
+	if (copy_from_user(cmd_data, (void __user *)(cmd.data), cmd.len)) {
+		rc = -EFAULT;
+		goto end;
+	}
+
+	mutex_lock(&adev->module->pmem_regions_lock);
+	if (adsp_verify_cmd(adev->module, cmd.queue, cmd_data, cmd.len)) {
+		MM_ERR("module %s: verify failed.\n", adev->module->name);
+		rc = -EINVAL;
+		goto end;
+	}
+	rc = msm_adsp_write(adev->module, cmd.queue, cmd_data, cmd.len);
+end:
+	mutex_unlock(&adev->module->pmem_regions_lock);
+
+	if (cmd.len > 256)
+		kfree(cmd_data);
+
+	return rc;
+}
+
+static int adsp_events_pending(struct adsp_device *adev)
+{
+	unsigned long flags;
+	int yes;
+	spin_lock_irqsave(&adev->event_queue_lock, flags);
+	yes = !list_empty(&adev->event_queue);
+	spin_unlock_irqrestore(&adev->event_queue_lock, flags);
+	return yes || adev->abort;
+}
+
+static int adsp_pmem_lookup_paddr(struct msm_adsp_module *module, void **addr,
+		     struct adsp_pmem_region **region)
+{
+	struct hlist_node *node;
+	unsigned long paddr = (unsigned long)(*addr);
+	struct adsp_pmem_region *region_elt;
+
+	hlist_for_each_entry(region_elt, node, &module->pmem_regions, list) {
+		if (paddr >= region_elt->paddr &&
+		    paddr < region_elt->paddr + region_elt->len) {
+			*region = region_elt;
+			return 0;
+		}
+	}
+	return -1;
+}
+
+int adsp_pmem_paddr_fixup(struct msm_adsp_module *module, void **addr)
+{
+	struct adsp_pmem_region *region;
+	unsigned long paddr = (unsigned long)(*addr);
+	unsigned long *vaddr = (unsigned long *)addr;
+	int ret;
+
+	ret = adsp_pmem_lookup_paddr(module, addr, &region);
+	if (ret) {
+		MM_ERR("not patching %s, paddr %p lookup failed\n",
+			module->name, vaddr);
+		return ret;
+	}
+
+	*vaddr = (unsigned long)region->vaddr + (paddr - region->paddr);
+	return 0;
+}
+
+static int adsp_patch_event(struct msm_adsp_module *module,
+				struct adsp_event *event)
+{
+	/* call the per-module msg verifier */
+	if (module->patch_event)
+		return module->patch_event(module, event);
+	return 0;
+}
+
+static long adsp_get_event(struct adsp_device *adev, void __user *arg)
+{
+	unsigned long flags;
+	struct adsp_event *data = NULL;
+	struct adsp_event_t evt;
+	int timeout;
+	long rc = 0;
+
+	if (copy_from_user(&evt, arg, sizeof(struct adsp_event_t)))
+		return -EFAULT;
+
+	timeout = (int)evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(
+			adev->event_wait, adsp_events_pending(adev),
+			msecs_to_jiffies(timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(
+			adev->event_wait, adsp_events_pending(adev));
+	}
+	if (rc < 0)
+		return rc;
+
+	if (adev->abort)
+		return -ENODEV;
+
+	spin_lock_irqsave(&adev->event_queue_lock, flags);
+	if (!list_empty(&adev->event_queue)) {
+		data = list_first_entry(&adev->event_queue,
+					struct adsp_event, list);
+		list_del(&data->list);
+	}
+	spin_unlock_irqrestore(&adev->event_queue_lock, flags);
+
+	if (!data)
+		return -EAGAIN;
+
+	/* DSP messages are type 0; they may contain physical addresses */
+	if (data->type == 0)
+		adsp_patch_event(adev->module, data);
+
+	/* map adsp_event --> adsp_event_t */
+	if (evt.len < data->size) {
+		rc = -ETOOSMALL;
+		goto end;
+	}
+	if (data->msg_id != EVENT_MSG_ID) {
+		if (copy_to_user((void *)(evt.data), data->data.msg16,
+					data->size)) {
+			rc = -EFAULT;
+			goto end;
+	}
+	} else {
+		if (copy_to_user((void *)(evt.data), data->data.msg32,
+					data->size)) {
+			rc = -EFAULT;
+			goto end;
+		}
+	}
+
+	evt.type = data->type; /* 0 --> from aDSP, 1 --> from ARM9 */
+	evt.msg_id = data->msg_id;
+	evt.flags = data->is16;
+	evt.len = data->size;
+	if (copy_to_user(arg, &evt, sizeof(evt)))
+		rc = -EFAULT;
+end:
+	kfree(data);
+	return rc;
+}
+
+static int adsp_pmem_del(struct msm_adsp_module *module)
+{
+	struct hlist_node *node, *tmp;
+	struct adsp_pmem_region *region;
+
+	mutex_lock(&module->pmem_regions_lock);
+	hlist_for_each_safe(node, tmp, &module->pmem_regions) {
+		region = hlist_entry(node, struct adsp_pmem_region, list);
+		hlist_del(node);
+		put_pmem_file(region->file);
+		kfree(region);
+	}
+	mutex_unlock(&module->pmem_regions_lock);
+	BUG_ON(!hlist_empty(&module->pmem_regions));
+
+	return 0;
+}
+
+static long adsp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	struct adsp_device *adev = filp->private_data;
+
+	switch (cmd) {
+	case ADSP_IOCTL_ENABLE:
+		return msm_adsp_enable(adev->module);
+
+	case ADSP_IOCTL_DISABLE:
+		return msm_adsp_disable(adev->module);
+
+	case ADSP_IOCTL_DISABLE_EVENT_RSP:
+		return msm_adsp_disable_event_rsp(adev->module);
+
+	case ADSP_IOCTL_DISABLE_ACK:
+		MM_ERR("ADSP_IOCTL_DISABLE_ACK is not implemented\n");
+		break;
+
+	case ADSP_IOCTL_WRITE_COMMAND:
+		return adsp_write_cmd(adev, (void __user *) arg);
+
+	case ADSP_IOCTL_GET_EVENT:
+		return adsp_get_event(adev, (void __user *) arg);
+
+	case ADSP_IOCTL_SET_CLKRATE: {
+		unsigned long clk_rate;
+		if (copy_from_user(&clk_rate, (void *) arg, sizeof(clk_rate)))
+			return -EFAULT;
+		return adsp_set_clkrate(adev->module, clk_rate);
+	}
+
+	case ADSP_IOCTL_REGISTER_PMEM: {
+		struct adsp_pmem_info info;
+		if (copy_from_user(&info, (void *) arg, sizeof(info)))
+			return -EFAULT;
+		return adsp_pmem_add(adev->module, &info);
+	}
+
+	case ADSP_IOCTL_ABORT_EVENT_READ:
+		adev->abort = 1;
+		wake_up(&adev->event_wait);
+		break;
+
+	case ADSP_IOCTL_UNREGISTER_PMEM:
+		return adsp_pmem_del(adev->module);
+
+	default:
+		break;
+	}
+	return -EINVAL;
+}
+
+static int adsp_release(struct inode *inode, struct file *filp)
+{
+	struct adsp_device *adev = filp->private_data;
+	struct msm_adsp_module *module = adev->module;
+	int rc = 0;
+
+	MM_INFO("release '%s'\n", adev->name);
+
+	/* clear module before putting it to avoid race with open() */
+	adev->module = NULL;
+
+	rc = adsp_pmem_del(module);
+
+	msm_adsp_put(module);
+	return rc;
+}
+
+static void adsp_event(void *driver_data, unsigned id, size_t len,
+		       void (*getevent)(void *ptr, size_t len))
+{
+	struct adsp_device *adev = driver_data;
+	struct adsp_event *event;
+	unsigned long flags;
+
+	if (len > ADSP_EVENT_MAX_SIZE) {
+		MM_ERR("event too large (%d bytes)\n", len);
+		return;
+	}
+
+	event = kmalloc(sizeof(*event), GFP_ATOMIC);
+	if (!event) {
+		MM_ERR("cannot allocate buffer\n");
+		return;
+	}
+
+	if (id != EVENT_MSG_ID) {
+		event->type = 0;
+		event->is16 = 0;
+		event->msg_id = id;
+		event->size = len;
+
+		getevent(event->data.msg16, len);
+	} else {
+		event->type = 1;
+		event->is16 = 1;
+		event->msg_id = id;
+		event->size = len;
+		getevent(event->data.msg32, len);
+	}
+
+	spin_lock_irqsave(&adev->event_queue_lock, flags);
+	list_add_tail(&event->list, &adev->event_queue);
+	spin_unlock_irqrestore(&adev->event_queue_lock, flags);
+	wake_up(&adev->event_wait);
+}
+
+static struct msm_adsp_ops adsp_ops = {
+	.event = adsp_event,
+};
+
+static int adsp_open(struct inode *inode, struct file *filp)
+{
+	struct adsp_device *adev;
+	int rc;
+
+	rc = nonseekable_open(inode, filp);
+	if (rc < 0)
+		return rc;
+
+	adev = inode_to_device(inode);
+	if (!adev)
+		return -ENODEV;
+
+	MM_INFO("open '%s'\n", adev->name);
+
+	rc = msm_adsp_get(adev->name, &adev->module, &adsp_ops, adev);
+	if (rc)
+		return rc;
+
+	MM_INFO("opened module '%s' adev %p\n", adev->name, adev);
+	filp->private_data = adev;
+	adev->abort = 0;
+	INIT_HLIST_HEAD(&adev->module->pmem_regions);
+	mutex_init(&adev->module->pmem_regions_lock);
+
+	return 0;
+}
+
+static unsigned adsp_device_count;
+static struct adsp_device *adsp_devices;
+
+static struct adsp_device *inode_to_device(struct inode *inode)
+{
+	unsigned n = MINOR(inode->i_rdev);
+	if (n < adsp_device_count) {
+		if (adsp_devices[n].device)
+			return adsp_devices + n;
+	}
+	return NULL;
+}
+
+static dev_t adsp_devno;
+static struct class *adsp_class;
+
+static const struct file_operations adsp_fops = {
+	.owner = THIS_MODULE,
+	.open = adsp_open,
+	.unlocked_ioctl = adsp_ioctl,
+	.release = adsp_release,
+};
+
+static void adsp_create(struct adsp_device *adev, const char *name,
+			struct device *parent, dev_t devt)
+{
+	struct device *dev;
+	int rc;
+
+	dev = device_create(adsp_class, parent, devt, "%s", name);
+	if (IS_ERR(dev))
+		return;
+
+	init_waitqueue_head(&adev->event_wait);
+	INIT_LIST_HEAD(&adev->event_queue);
+	spin_lock_init(&adev->event_queue_lock);
+
+	cdev_init(&adev->cdev, &adsp_fops);
+	adev->cdev.owner = THIS_MODULE;
+
+	rc = cdev_add(&adev->cdev, devt, 1);
+	if (rc < 0) {
+		device_destroy(adsp_class, devt);
+	} else {
+		adev->device = dev;
+		adev->name = name;
+	}
+}
+
+void msm_adsp_publish_cdevs(struct msm_adsp_module *modules, unsigned n)
+{
+	int rc;
+
+	adsp_devices = kzalloc(sizeof(struct adsp_device) * n, GFP_KERNEL);
+	if (!adsp_devices)
+		return;
+
+	adsp_class = class_create(THIS_MODULE, "adsp");
+	if (IS_ERR(adsp_class))
+		goto fail_create_class;
+
+	rc = alloc_chrdev_region(&adsp_devno, 0, n, "adsp");
+	if (rc < 0)
+		goto fail_alloc_region;
+
+	adsp_device_count = n;
+	for (n = 0; n < adsp_device_count; n++) {
+		adsp_create(adsp_devices + n,
+			    modules[n].name, &modules[n].pdev.dev,
+			    MKDEV(MAJOR(adsp_devno), n));
+	}
+
+	return;
+
+fail_alloc_region:
+	class_unregister(adsp_class);
+fail_create_class:
+	kfree(adsp_devices);
+}
diff --git a/arch/arm/mach-msm/qdsp5v2/adsp_info.c b/arch/arm/mach-msm/qdsp5v2/adsp_info.c
new file mode 100644
index 0000000..4026367
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/adsp_info.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2008-2010, Code Aurora Forum. 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.
+ *
+ */
+
+#include "adsp.h"
+
+/* Firmware modules */
+#define QDSP_MODULE_KERNEL                  0x0106dd4e
+#define QDSP_MODULE_AFETASK                 0x0106dd6f
+#define QDSP_MODULE_AUDPLAY0TASK            0x0106dd70
+#define QDSP_MODULE_AUDPLAY1TASK            0x0106dd71
+#define QDSP_MODULE_AUDPPTASK               0x0106dd72
+#define QDSP_MODULE_VIDEOTASK               0x0106dd73
+#define QDSP_MODULE_VIDEO_AAC_VOC           0x0106dd74
+#define QDSP_MODULE_PCM_DEC                 0x0106dd75
+#define QDSP_MODULE_AUDIO_DEC_MP3           0x0106dd76
+#define QDSP_MODULE_AUDIO_DEC_AAC           0x0106dd77
+#define QDSP_MODULE_AUDIO_DEC_WMA           0x0106dd78
+#define QDSP_MODULE_HOSTPCM                 0x0106dd79
+#define QDSP_MODULE_DTMF                    0x0106dd7a
+#define QDSP_MODULE_AUDRECTASK              0x0106dd7b
+#define QDSP_MODULE_AUDPREPROCTASK          0x0106dd7c
+#define QDSP_MODULE_SBC_ENC                 0x0106dd7d
+#define QDSP_MODULE_VOC_UMTS                0x0106dd9a
+#define QDSP_MODULE_VOC_CDMA                0x0106dd98
+#define QDSP_MODULE_VOC_PCM                 0x0106dd7f
+#define QDSP_MODULE_VOCENCTASK              0x0106dd80
+#define QDSP_MODULE_VOCDECTASK              0x0106dd81
+#define QDSP_MODULE_VOICEPROCTASK           0x0106dd82
+#define QDSP_MODULE_VIDEOENCTASK            0x0106dd83
+#define QDSP_MODULE_VFETASK                 0x0106dd84
+#define QDSP_MODULE_WAV_ENC                 0x0106dd85
+#define QDSP_MODULE_AACLC_ENC               0x0106dd86
+#define QDSP_MODULE_VIDEO_AMR               0x0106dd87
+#define QDSP_MODULE_VOC_AMR                 0x0106dd88
+#define QDSP_MODULE_VOC_EVRC                0x0106dd89
+#define QDSP_MODULE_VOC_13K                 0x0106dd8a
+#define QDSP_MODULE_VOC_FGV                 0x0106dd8b
+#define QDSP_MODULE_DIAGTASK                0x0106dd8c
+#define QDSP_MODULE_JPEGTASK                0x0106dd8d
+#define QDSP_MODULE_LPMTASK                 0x0106dd8e
+#define QDSP_MODULE_QCAMTASK                0x0106dd8f
+#define QDSP_MODULE_MODMATHTASK             0x0106dd90
+#define QDSP_MODULE_AUDPLAY2TASK            0x0106dd91
+#define QDSP_MODULE_AUDPLAY3TASK            0x0106dd92
+#define QDSP_MODULE_AUDPLAY4TASK            0x0106dd93
+#define QDSP_MODULE_GRAPHICSTASK            0x0106dd94
+#define QDSP_MODULE_MIDI                    0x0106dd95
+#define QDSP_MODULE_GAUDIO                  0x0106dd96
+#define QDSP_MODULE_VDEC_LP_MODE            0x0106dd97
+#define QDSP_MODULE_VIDEO_AAC_VOC_TURBO     0x01089f77
+#define QDSP_MODULE_VIDEO_AMR_TURBO         0x01089f78
+#define QDSP_MODULE_WM_TURBO_MODE           0x01089f79
+#define QDSP_MODULE_VDEC_LP_MODE_TURBO      0x01089f7a
+#define QDSP_MODULE_AUDREC0TASK             0x0109696f
+#define QDSP_MODULE_AUDREC1TASK             0x01096970
+#define QDSP_MODULE_AUDREC2TASK             0x010a2f59
+#define QDSP_MODULE_MAX                     0x7fffffff
+
+   /* DO NOT USE: Force this enum to be a 32bit type to improve speed */
+#define QDSP_MODULE_32BIT_DUMMY 0x10000
+
+static uint32_t *qdsp_task_to_module[IMG_MAX];
+static uint32_t	*qdsp_queue_offset_table[IMG_MAX];
+
+#define QDSP_MODULE(n, clkname, clkrate, verify_cmd_func, patch_event_func) \
+	{ .name = #n, .pdev_name = "adsp_" #n, .id = QDSP_MODULE_##n, \
+	  .clk_name = clkname, .clk_rate = clkrate, \
+	  .verify_cmd = verify_cmd_func, .patch_event = patch_event_func }
+
+static struct adsp_module_info module_info[] = {
+	QDSP_MODULE(AUDPLAY0TASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(AUDPLAY1TASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(AUDPLAY2TASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(AUDPLAY3TASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(AUDPPTASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(AUDPREPROCTASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(AFETASK , NULL, 0, NULL, NULL),
+	QDSP_MODULE(AUDREC0TASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(AUDREC1TASK, NULL, 0, NULL, NULL),
+	QDSP_MODULE(AUDREC2TASK, NULL, 0, NULL, NULL),
+};
+
+int adsp_init_info(struct adsp_info *info)
+{
+	uint32_t img_num;
+
+	info->send_irq =   0x00c00200;
+	info->read_ctrl =  0x00400038;
+	info->write_ctrl = 0x00400034;
+
+	info->max_msg16_size = 193;
+	info->max_msg32_size = 8;
+	for (img_num = 0; img_num < IMG_MAX; img_num++)
+		qdsp_queue_offset_table[img_num] =
+		&info->init_info_ptr->queue_offsets[img_num][0];
+
+	for (img_num = 0; img_num < IMG_MAX; img_num++)
+		qdsp_task_to_module[img_num] =
+		&info->init_info_ptr->task_to_module_tbl[img_num][0];
+	info->max_task_id = ENTRIES_MAX;
+	info->max_module_id = QDSP_MODULE_MAX - 1;
+	info->max_queue_id = QDSP_MAX_NUM_QUEUES;
+	info->max_image_id = 0;
+	info->queue_offset = qdsp_queue_offset_table;
+	info->task_to_module = qdsp_task_to_module;
+
+	info->module_count = ARRAY_SIZE(module_info);
+	info->module = module_info;
+	return 0;
+}
diff --git a/arch/arm/mach-msm/qdsp5v2/afe.c b/arch/arm/mach-msm/qdsp5v2/afe.c
new file mode 100644
index 0000000..20c9898
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/afe.c
@@ -0,0 +1,534 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/jiffies.h>
+#include <linux/debugfs.h>
+#include <asm/uaccess.h>
+#include <mach/qdsp5v2/qdsp5afecmdi.h>
+#include <mach/qdsp5v2/qdsp5afemsg.h>
+#include <mach/qdsp5v2/afe.h>
+#include <mach/msm_adsp.h>
+#include <mach/debug_mm.h>
+
+#define AFE_MAX_TIMEOUT 500 /* 500 ms */
+#define AFE_MAX_CLNT 6 /* 6 HW path defined so far */
+#define GETDEVICEID(x) ((x) - 1)
+
+struct msm_afe_state {
+	struct msm_adsp_module *mod;
+	struct msm_adsp_ops    adsp_ops;
+	struct mutex           lock;
+	u8                     in_use;
+	u8                     codec_config[AFE_MAX_CLNT];
+	wait_queue_head_t      wait;
+	u8			aux_conf_flag;
+};
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *debugfs_afelb;
+#endif
+
+
+static struct msm_afe_state the_afe_state;
+
+#define afe_send_queue(afe, cmd, len) \
+  msm_adsp_write(afe->mod, QDSP_apuAfeQueue, \
+	cmd, len)
+
+static void afe_dsp_event(void *data, unsigned id, size_t len,
+			    void (*getevent)(void *ptr, size_t len))
+{
+	struct msm_afe_state *afe = data;
+
+	MM_DBG("msg_id %d \n", id);
+
+	switch (id) {
+	case AFE_APU_MSG_CODEC_CONFIG_ACK: {
+		struct afe_msg_codec_config_ack afe_ack;
+		getevent(&afe_ack, AFE_APU_MSG_CODEC_CONFIG_ACK_LEN);
+		MM_DBG("%s: device_id: %d device activity: %d\n", __func__,
+		afe_ack.device_id, afe_ack.device_activity);
+		if (afe_ack.device_activity == AFE_MSG_CODEC_CONFIG_DISABLED)
+			afe->codec_config[GETDEVICEID(afe_ack.device_id)] = 0;
+		else
+			afe->codec_config[GETDEVICEID(afe_ack.device_id)] =
+			afe_ack.device_activity;
+
+		wake_up(&afe->wait);
+		break;
+	}
+	case AFE_APU_MSG_VOC_TIMING_SUCCESS:
+		MM_INFO("Received VOC_TIMING_SUCCESS message from AFETASK\n");
+		break;
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable/disable(audpptask)");
+		break;
+	default:
+		MM_ERR("unexpected message from afe \n");
+	}
+
+	return;
+}
+
+static void afe_dsp_codec_config(struct msm_afe_state *afe,
+	u8 path_id, u8 enable, struct msm_afe_config *config)
+{
+	struct afe_cmd_codec_config cmd;
+
+	MM_DBG("%s() %p\n", __func__, config);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AFE_CMD_CODEC_CONFIG_CMD;
+	cmd.device_id = path_id;
+	cmd.activity = enable;
+	if (config) {
+		MM_DBG("%s: sample_rate %x ch mode %x vol %x\n",
+			__func__, config->sample_rate,
+			config->channel_mode, config->volume);
+		cmd.sample_rate = config->sample_rate;
+		cmd.channel_mode = config->channel_mode;
+		cmd.volume = config->volume;
+	}
+	afe_send_queue(afe, &cmd, sizeof(cmd));
+}
+/* Function is called after afe module been enabled */
+void afe_loopback(int enable)
+{
+	struct afe_cmd_loopback cmd;
+	struct msm_afe_state *afe;
+
+	afe = &the_afe_state;
+	MM_DBG("enable %d\n", enable);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AFE_CMD_LOOPBACK;
+	if (enable)
+		cmd.enable_flag = AFE_LOOPBACK_ENABLE_COMMAND;
+
+	afe_send_queue(afe, &cmd, sizeof(cmd));
+}
+EXPORT_SYMBOL(afe_loopback);
+
+void afe_ext_loopback(int enable, int rx_copp_id, int tx_copp_id)
+{
+	struct afe_cmd_ext_loopback cmd;
+	struct msm_afe_state *afe;
+
+	afe = &the_afe_state;
+	MM_DBG("enable %d\n", enable);
+	if ((rx_copp_id == 0) && (tx_copp_id == 0)) {
+		afe_loopback(enable);
+	} else {
+		memset(&cmd, 0, sizeof(cmd));
+		cmd.cmd_id = AFE_CMD_EXT_LOOPBACK;
+		cmd.source_id = tx_copp_id;
+		cmd.dst_id = rx_copp_id;
+		if (enable)
+			cmd.enable_flag = AFE_LOOPBACK_ENABLE_COMMAND;
+
+		afe_send_queue(afe, &cmd, sizeof(cmd));
+	}
+}
+EXPORT_SYMBOL(afe_ext_loopback);
+
+void afe_device_volume_ctrl(u16 device_id, u16 device_volume)
+{
+	struct afe_cmd_device_volume_ctrl cmd;
+	struct msm_afe_state *afe;
+
+	afe = &the_afe_state;
+	MM_DBG("device 0x%4x volume 0x%4x\n", device_id, device_volume);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AFE_CMD_DEVICE_VOLUME_CTRL;
+	cmd.device_id = device_id;
+	cmd.device_volume = device_volume;
+	afe_send_queue(afe, &cmd, sizeof(cmd));
+}
+EXPORT_SYMBOL(afe_device_volume_ctrl);
+
+int afe_enable(u8 path_id, struct msm_afe_config *config)
+{
+	struct msm_afe_state *afe = &the_afe_state;
+	int rc;
+
+	MM_DBG("%s: path %d\n", __func__, path_id);
+	if ((GETDEVICEID(path_id) < 0) || (GETDEVICEID(path_id) > 5)) {
+		MM_ERR("Invalid path_id: %d\n", path_id);
+		return -EINVAL;
+	}
+	mutex_lock(&afe->lock);
+	if (!afe->in_use && !afe->aux_conf_flag) {
+		/* enable afe */
+		rc = msm_adsp_get("AFETASK", &afe->mod, &afe->adsp_ops, afe);
+		if (rc < 0) {
+			MM_ERR("%s: failed to get AFETASK module\n", __func__);
+			goto error_adsp_get;
+		}
+		rc = msm_adsp_enable(afe->mod);
+		if (rc < 0)
+			goto error_adsp_enable;
+	}
+	/* Issue codec config command */
+	afe_dsp_codec_config(afe, path_id, 1, config);
+	rc = wait_event_timeout(afe->wait,
+		afe->codec_config[GETDEVICEID(path_id)],
+		msecs_to_jiffies(AFE_MAX_TIMEOUT));
+	if (!rc) {
+		MM_ERR("AFE failed to respond within %d ms\n", AFE_MAX_TIMEOUT);
+		rc = -ENODEV;
+		if (!afe->in_use) {
+			if (!afe->aux_conf_flag ||
+			(afe->aux_conf_flag &&
+			(path_id == AFE_HW_PATH_AUXPCM_RX ||
+			path_id == AFE_HW_PATH_AUXPCM_TX))) {
+				/* clean up if there is no client */
+				msm_adsp_disable(afe->mod);
+				msm_adsp_put(afe->mod);
+				afe->aux_conf_flag = 0;
+				afe->mod = NULL;
+			}
+		}
+
+	} else {
+		rc = 0;
+		afe->in_use++;
+	}
+
+	mutex_unlock(&afe->lock);
+	return rc;
+
+error_adsp_enable:
+	msm_adsp_put(afe->mod);
+	afe->mod = NULL;
+error_adsp_get:
+	mutex_unlock(&afe->lock);
+	return rc;
+}
+EXPORT_SYMBOL(afe_enable);
+
+int afe_config_fm_codec(int fm_enable, uint16_t source)
+{
+	struct afe_cmd_fm_codec_config cmd;
+	struct msm_afe_state *afe = &the_afe_state;
+	int rc = 0;
+	int i = 0;
+	unsigned short *ptrmem = (unsigned short *)&cmd;
+
+	MM_INFO(" configure fm codec\n");
+	mutex_lock(&afe->lock);
+	if (!afe->in_use) {
+		/* enable afe */
+		rc = msm_adsp_get("AFETASK", &afe->mod, &afe->adsp_ops, afe);
+		if (rc < 0) {
+			MM_ERR("%s: failed to get AFETASK module\n", __func__);
+			goto error_adsp_get;
+		}
+		rc = msm_adsp_enable(afe->mod);
+		if (rc < 0)
+			goto error_adsp_enable;
+	}
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AFE_CMD_FM_RX_ROUTING_CMD;
+	cmd.enable = fm_enable;
+	cmd.device_id = source;
+
+	for (i = 0; i < sizeof(cmd)/2; i++, ++ptrmem)
+		MM_DBG("cmd[%d]=0x%04x\n", i, *ptrmem);
+	afe_send_queue(afe, &cmd, sizeof(cmd));
+
+	mutex_unlock(&afe->lock);
+	return rc;
+error_adsp_enable:
+	msm_adsp_put(afe->mod);
+	afe->mod = NULL;
+error_adsp_get:
+	mutex_unlock(&afe->lock);
+	return rc;
+}
+EXPORT_SYMBOL(afe_config_fm_codec);
+
+int afe_config_fm_volume(uint16_t volume)
+{
+	struct afe_cmd_fm_volume_config cmd;
+	struct msm_afe_state *afe = &the_afe_state;
+	int rc = 0;
+
+	MM_INFO(" configure fm volume\n");
+	mutex_lock(&afe->lock);
+	if (!afe->in_use) {
+		/* enable afe */
+		rc = msm_adsp_get("AFETASK", &afe->mod, &afe->adsp_ops, afe);
+		if (rc < 0) {
+			MM_ERR("%s: failed to get AFETASK module\n", __func__);
+			goto error_adsp_get;
+		}
+		rc = msm_adsp_enable(afe->mod);
+		if (rc < 0)
+			goto error_adsp_enable;
+	}
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AFE_CMD_FM_PLAYBACK_VOLUME_CMD;
+	cmd.volume = volume;
+
+	afe_send_queue(afe, &cmd, sizeof(cmd));
+
+	mutex_unlock(&afe->lock);
+	return rc;
+error_adsp_enable:
+	msm_adsp_put(afe->mod);
+	afe->mod = NULL;
+error_adsp_get:
+	mutex_unlock(&afe->lock);
+	return rc;
+}
+EXPORT_SYMBOL(afe_config_fm_volume);
+
+int afe_config_fm_calibration_gain(uint16_t device_id,
+			uint16_t calibration_gain)
+{
+	struct afe_cmd_fm_calibgain_config cmd;
+	struct msm_afe_state *afe = &the_afe_state;
+	int rc = 0;
+
+	MM_INFO("Configure for rx device = 0x%4x, gain = 0x%4x\n", device_id,
+			calibration_gain);
+	mutex_lock(&afe->lock);
+	if (!afe->in_use) {
+		/* enable afe */
+		rc = msm_adsp_get("AFETASK", &afe->mod, &afe->adsp_ops, afe);
+		if (rc < 0) {
+			MM_ERR("%s: failed to get AFETASK module\n", __func__);
+			goto error_adsp_get;
+		}
+		rc = msm_adsp_enable(afe->mod);
+		if (rc < 0)
+			goto error_adsp_enable;
+	}
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AFE_CMD_FM_CALIBRATION_GAIN_CMD;
+	cmd.device_id = device_id;
+	cmd.calibration_gain = calibration_gain;
+
+	afe_send_queue(afe, &cmd, sizeof(cmd));
+
+	mutex_unlock(&afe->lock);
+	return rc;
+error_adsp_enable:
+	msm_adsp_put(afe->mod);
+	afe->mod = NULL;
+error_adsp_get:
+	mutex_unlock(&afe->lock);
+	return rc;
+}
+EXPORT_SYMBOL(afe_config_fm_calibration_gain);
+
+int afe_config_aux_codec(int pcm_ctl_value, int aux_codec_intf_value,
+				int data_format_pad)
+{
+	struct afe_cmd_aux_codec_config cmd;
+	struct msm_afe_state *afe = &the_afe_state;
+	int rc = 0;
+
+	MM_DBG(" configure aux codec \n");
+	mutex_lock(&afe->lock);
+	if (!afe->in_use && !afe->aux_conf_flag) {
+		/* enable afe */
+		rc = msm_adsp_get("AFETASK", &afe->mod, &afe->adsp_ops, afe);
+		if (rc < 0) {
+			MM_ERR("%s: failed to get AFETASK module\n", __func__);
+			goto error_adsp_get;
+		}
+		rc = msm_adsp_enable(afe->mod);
+		if (rc < 0)
+			goto error_adsp_enable;
+	}
+	afe->aux_conf_flag = 1;
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AFE_CMD_AUX_CODEC_CONFIG_CMD;
+	cmd.dma_path_ctl = 0;
+	cmd.pcm_ctl = pcm_ctl_value;
+	cmd.eight_khz_int_mode = 0;
+	cmd.aux_codec_intf_ctl = aux_codec_intf_value;
+	cmd.data_format_padding_info = data_format_pad;
+
+	afe_send_queue(afe, &cmd, sizeof(cmd));
+
+	mutex_unlock(&afe->lock);
+	return rc;
+error_adsp_enable:
+	msm_adsp_put(afe->mod);
+	afe->mod = NULL;
+error_adsp_get:
+	mutex_unlock(&afe->lock);
+	return rc;
+}
+EXPORT_SYMBOL(afe_config_aux_codec);
+
+int afe_config_rmc_block(struct acdb_rmc_block *acdb_rmc)
+{
+	struct afe_cmd_cfg_rmc cmd;
+	struct msm_afe_state *afe = &the_afe_state;
+	int rc = 0;
+	int i = 0;
+	unsigned short *ptrmem = (unsigned short *)&cmd;
+
+	MM_DBG(" configure rmc block\n");
+	mutex_lock(&afe->lock);
+	if (!afe->in_use && !afe->mod) {
+		/* enable afe */
+		rc = msm_adsp_get("AFETASK", &afe->mod, &afe->adsp_ops, afe);
+		if (rc < 0) {
+			MM_DBG("%s: failed to get AFETASK module\n", __func__);
+			goto error_adsp_get;
+		}
+		rc = msm_adsp_enable(afe->mod);
+		if (rc < 0)
+			goto error_adsp_enable;
+	}
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AFE_CMD_CFG_RMC_PARAMS;
+
+	cmd.rmc_mode = acdb_rmc->rmc_enable;
+	cmd.rmc_ipw_length_ms =	acdb_rmc->rmc_ipw_length_ms;
+	cmd.rmc_peak_length_ms = acdb_rmc->rmc_peak_length_ms;
+	cmd.rmc_init_pulse_length_ms = acdb_rmc->rmc_init_pulse_length_ms;
+	cmd.rmc_total_int_length_ms = acdb_rmc->rmc_total_int_length_ms;
+	cmd.rmc_rampupdn_length_ms = acdb_rmc->rmc_rampupdn_length_ms;
+	cmd.rmc_delay_length_ms = acdb_rmc->rmc_delay_length_ms;
+	cmd.rmc_detect_start_threshdb = acdb_rmc->rmc_detect_start_threshdb;
+	cmd.rmc_init_pulse_threshdb = acdb_rmc->rmc_init_pulse_threshdb;
+
+	for (i = 0; i < sizeof(cmd)/2; i++, ++ptrmem)
+		MM_DBG("cmd[%d]=0x%04x\n", i, *ptrmem);
+	afe_send_queue(afe, &cmd, sizeof(cmd));
+
+	mutex_unlock(&afe->lock);
+	return rc;
+error_adsp_enable:
+	msm_adsp_put(afe->mod);
+	afe->mod = NULL;
+error_adsp_get:
+	mutex_unlock(&afe->lock);
+	return rc;
+}
+EXPORT_SYMBOL(afe_config_rmc_block);
+
+int afe_disable(u8 path_id)
+{
+	struct msm_afe_state *afe = &the_afe_state;
+	int rc;
+
+	mutex_lock(&afe->lock);
+
+	BUG_ON(!afe->in_use);
+	MM_DBG("%s() path_id:%d codec state:%d\n", __func__, path_id,
+	afe->codec_config[GETDEVICEID(path_id)]);
+	afe_dsp_codec_config(afe, path_id, 0, NULL);
+	rc = wait_event_timeout(afe->wait,
+		!afe->codec_config[GETDEVICEID(path_id)],
+		msecs_to_jiffies(AFE_MAX_TIMEOUT));
+	if (!rc) {
+		MM_ERR("AFE failed to respond within %d ms\n", AFE_MAX_TIMEOUT);
+		rc = -1;
+	} else
+		rc = 0;
+	afe->in_use--;
+	MM_DBG("%s() in_use:%d \n", __func__, afe->in_use);
+	if (!afe->in_use) {
+		msm_adsp_disable(afe->mod);
+		msm_adsp_put(afe->mod);
+		afe->aux_conf_flag = 0;
+		afe->mod = NULL;
+	}
+	mutex_unlock(&afe->lock);
+	return rc;
+}
+EXPORT_SYMBOL(afe_disable);
+
+
+#ifdef CONFIG_DEBUG_FS
+static int afe_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	MM_INFO("debug intf %s\n", (char *) file->private_data);
+	return 0;
+}
+
+static ssize_t afe_debug_write(struct file *filp,
+	const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	char *lb_str = filp->private_data;
+	char cmd;
+
+	if (get_user(cmd, ubuf))
+		return -EFAULT;
+
+	MM_INFO("%s %c\n", lb_str, cmd);
+
+	if (!strcmp(lb_str, "afe_loopback")) {
+		switch (cmd) {
+		case '1':
+			afe_loopback(1);
+			break;
+		case '0':
+			afe_loopback(0);
+			break;
+		}
+	}
+
+	return cnt;
+}
+
+static const struct file_operations afe_debug_fops = {
+	.open = afe_debug_open,
+	.write = afe_debug_write
+};
+#endif
+
+static int __init afe_init(void)
+{
+	struct msm_afe_state *afe = &the_afe_state;
+
+	MM_INFO("AFE driver init\n");
+
+	memset(afe, 0, sizeof(struct msm_afe_state));
+	afe->adsp_ops.event = afe_dsp_event;
+	mutex_init(&afe->lock);
+	init_waitqueue_head(&afe->wait);
+
+#ifdef CONFIG_DEBUG_FS
+	debugfs_afelb = debugfs_create_file("afe_loopback",
+	S_IFREG | S_IWUGO, NULL, (void *) "afe_loopback",
+	&afe_debug_fops);
+#endif
+
+	return 0;
+}
+
+static void __exit afe_exit(void)
+{
+	MM_INFO("AFE driver exit\n");
+#ifdef CONFIG_DEBUG_FS
+	if (debugfs_afelb)
+		debugfs_remove(debugfs_afelb);
+#endif
+	if (the_afe_state.mod)
+		msm_adsp_put(the_afe_state.mod);
+	return;
+}
+
+module_init(afe_init);
+module_exit(afe_exit);
+
+MODULE_DESCRIPTION("MSM AFE driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.c b/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.c
new file mode 100644
index 0000000..733b7a1
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.c
@@ -0,0 +1,991 @@
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+ *
+ * sbc/pcm audio input driver
+ * Based on the pcm input driver in arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c
+ *
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/msm_audio.h>
+#include <linux/msm_audio_sbc.h>
+#include <linux/android_pmem.h>
+#include <linux/memory_alloc.h>
+
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/msm_adsp.h>
+#include <mach/msm_memtypes.h>
+#include <mach/socinfo.h>
+#include <mach/qdsp5v2/qdsp5audreccmdi.h>
+#include <mach/qdsp5v2/qdsp5audrecmsg.h>
+#include <mach/qdsp5v2/audpreproc.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/debug_mm.h>
+
+/* FRAME_NUM must be a power of two */
+#define FRAME_NUM		(8)
+#define FRAME_SIZE		(2052 * 2)
+#define FRAME_SIZE_SBC		(768 * 2)
+#define MONO_DATA_SIZE		(2048)
+#define STEREO_DATA_SIZE	(MONO_DATA_SIZE * 2)
+#define DMASZ 			(FRAME_SIZE * FRAME_NUM)
+
+struct buffer {
+	void *data;
+	uint32_t size;
+	uint32_t read;
+	uint32_t addr;
+	uint32_t frame_num;
+	uint32_t frame_len;
+};
+
+struct audio_a2dp_in {
+	struct buffer in[FRAME_NUM];
+
+	spinlock_t dsp_lock;
+
+	atomic_t in_bytes;
+	atomic_t in_samples;
+
+	struct mutex lock;
+	struct mutex read_lock;
+	wait_queue_head_t wait;
+	wait_queue_head_t wait_enable;
+
+	struct msm_adsp_module *audrec;
+
+	struct audrec_session_info session_info; /*audrec session info*/
+
+	/* configuration to use on next enable */
+	uint32_t samp_rate;
+	uint32_t channel_mode;
+	uint32_t buffer_size; /* 2048 for mono, 4096 for stereo */
+	uint32_t enc_type;
+	struct msm_audio_sbc_enc_config cfg;
+
+	uint32_t dsp_cnt;
+	uint32_t in_head; /* next buffer dsp will write */
+	uint32_t in_tail; /* next buffer read() will read */
+	uint32_t in_count; /* number of buffers available to read() */
+	uint32_t mode;
+
+	const char *module_name;
+	unsigned queue_ids;
+	uint16_t enc_id; /* Session Id */
+
+	uint16_t source; /* Encoding source bit mask */
+	uint32_t device_events; /* device events interested in */
+	uint32_t dev_cnt;
+	spinlock_t dev_lock;
+
+	/* data allocated for various buffers */
+	char *data;
+	dma_addr_t phys;
+	void *msm_map;
+
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+	int abort; /* set when error, like sample rate mismatch */
+	char *build_id;
+};
+
+static struct audio_a2dp_in the_audio_a2dp_in;
+
+struct wav_frame {
+	uint16_t frame_count_lsw;
+	uint16_t frame_count_msw;
+	uint16_t frame_length;
+	uint16_t erased_a2dp;
+	unsigned char raw_bitstream[]; /* samples */
+};
+
+struct sbc_frame {
+	uint16_t bit_rate_msw;
+	uint16_t bit_rate_lsw;
+	uint16_t frame_length;
+	uint16_t frame_num;
+	unsigned char raw_bitstream[]; /* samples */
+};
+
+struct audio_frame {
+	union {
+		struct wav_frame wav;
+		struct sbc_frame sbc;
+	} a2dp;
+} __attribute__((packed));
+
+/* Audrec Queue command sent macro's */
+#define audrec_send_bitstreamqueue(audio, cmd, len) \
+	msm_adsp_write(audio->audrec, ((audio->queue_ids & 0xFFFF0000) >> 16),\
+			cmd, len)
+
+#define audrec_send_audrecqueue(audio, cmd, len) \
+	msm_adsp_write(audio->audrec, (audio->queue_ids & 0x0000FFFF),\
+			cmd, len)
+
+/* DSP command send functions */
+static int auda2dp_in_enc_config(struct audio_a2dp_in *audio, int enable);
+static int auda2dp_in_param_config(struct audio_a2dp_in *audio);
+static int auda2dp_in_mem_config(struct audio_a2dp_in *audio);
+static int auda2dp_in_record_config(struct audio_a2dp_in *audio, int enable);
+static int auda2dp_dsp_read_buffer(struct audio_a2dp_in *audio,
+							uint32_t read_cnt);
+
+static void auda2dp_in_get_dsp_frames(struct audio_a2dp_in *audio);
+
+static void auda2dp_in_flush(struct audio_a2dp_in *audio);
+
+static void a2dp_in_listener(u32 evt_id, union auddev_evt_data *evt_payload,
+				void *private_data)
+{
+	struct audio_a2dp_in *audio = (struct audio_a2dp_in *) private_data;
+	unsigned long flags;
+
+	MM_DBG("evt_id = 0x%8x\n", evt_id);
+	switch (evt_id) {
+	case AUDDEV_EVT_DEV_RDY: {
+		MM_DBG("AUDDEV_EVT_DEV_RDY\n");
+		spin_lock_irqsave(&audio->dev_lock, flags);
+		audio->dev_cnt++;
+		audio->source |= (0x1 << evt_payload->routing_id);
+		spin_unlock_irqrestore(&audio->dev_lock, flags);
+
+		if ((audio->running == 1) && (audio->enabled == 1))
+			auda2dp_in_record_config(audio, 1);
+
+		break;
+	}
+	case AUDDEV_EVT_DEV_RLS: {
+		MM_DBG("AUDDEV_EVT_DEV_RLS\n");
+		spin_lock_irqsave(&audio->dev_lock, flags);
+		audio->dev_cnt--;
+		audio->source &= ~(0x1 << evt_payload->routing_id);
+		spin_unlock_irqrestore(&audio->dev_lock, flags);
+
+		if (!audio->running || !audio->enabled)
+			break;
+
+		/* Turn of as per source */
+		if (audio->source)
+			auda2dp_in_record_config(audio, 1);
+		else
+			/* Turn off all */
+			auda2dp_in_record_config(audio, 0);
+
+		break;
+	}
+	case AUDDEV_EVT_FREQ_CHG: {
+		MM_DBG("Encoder Driver got sample rate change event\n");
+		MM_DBG("sample rate %d\n", evt_payload->freq_info.sample_rate);
+		MM_DBG("dev_type %d\n", evt_payload->freq_info.dev_type);
+		MM_DBG("acdb_dev_id %d\n", evt_payload->freq_info.acdb_dev_id);
+		if (audio->running == 1) {
+			/* Stop Recording sample rate does not match
+			   with device sample rate */
+			if (evt_payload->freq_info.sample_rate !=
+				audio->samp_rate) {
+				auda2dp_in_record_config(audio, 0);
+				audio->abort = 1;
+				wake_up(&audio->wait);
+			}
+		}
+		break;
+	}
+	default:
+		MM_ERR("wrong event %d\n", evt_id);
+		break;
+	}
+}
+
+/* ------------------- dsp preproc event handler--------------------- */
+static void audpreproc_dsp_event(void *data, unsigned id,  void *msg)
+{
+	struct audio_a2dp_in *audio = data;
+
+	switch (id) {
+	case AUDPREPROC_ERROR_MSG: {
+		struct audpreproc_err_msg *err_msg = msg;
+
+		MM_ERR("ERROR_MSG: stream id %d err idx %d\n",
+		err_msg->stream_id, err_msg->aud_preproc_err_idx);
+		/* Error case */
+		wake_up(&audio->wait_enable);
+		break;
+	}
+	case AUDPREPROC_CMD_CFG_DONE_MSG: {
+		MM_DBG("CMD_CFG_DONE_MSG \n");
+		break;
+	}
+	case AUDPREPROC_CMD_ENC_CFG_DONE_MSG: {
+		struct audpreproc_cmd_enc_cfg_done_msg *enc_cfg_msg = msg;
+
+		MM_DBG("CMD_ENC_CFG_DONE_MSG: stream id %d enc type \
+			0x%8x\n", enc_cfg_msg->stream_id,
+			enc_cfg_msg->rec_enc_type);
+		/* Encoder enable success */
+		if (enc_cfg_msg->rec_enc_type & ENCODE_ENABLE)
+			auda2dp_in_param_config(audio);
+		else { /* Encoder disable success */
+			audio->running = 0;
+			auda2dp_in_record_config(audio, 0);
+		}
+		break;
+	}
+	case AUDPREPROC_CMD_ENC_PARAM_CFG_DONE_MSG: {
+		MM_DBG("CMD_ENC_PARAM_CFG_DONE_MSG \n");
+		auda2dp_in_mem_config(audio);
+		break;
+	}
+	case AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG: {
+		MM_DBG("AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG \n");
+		wake_up(&audio->wait_enable);
+		break;
+	}
+	default:
+		MM_ERR("Unknown Event id %d\n", id);
+	}
+}
+
+/* ------------------- dsp audrec event handler--------------------- */
+static void audrec_dsp_event(void *data, unsigned id, size_t len,
+			    void (*getevent)(void *ptr, size_t len))
+{
+	struct audio_a2dp_in *audio = data;
+
+	switch (id) {
+	case AUDREC_CMD_MEM_CFG_DONE_MSG: {
+		MM_DBG("CMD_MEM_CFG_DONE MSG DONE\n");
+		audio->running = 1;
+		if (audio->dev_cnt > 0)
+			auda2dp_in_record_config(audio, 1);
+		break;
+	}
+	case AUDREC_FATAL_ERR_MSG: {
+		struct audrec_fatal_err_msg fatal_err_msg;
+
+		getevent(&fatal_err_msg, AUDREC_FATAL_ERR_MSG_LEN);
+		MM_ERR("FATAL_ERR_MSG: err id %d\n",
+				fatal_err_msg.audrec_err_id);
+		/* Error stop the encoder */
+		audio->stopped = 1;
+		wake_up(&audio->wait);
+		break;
+	}
+	case AUDREC_UP_PACKET_READY_MSG: {
+		struct audrec_up_pkt_ready_msg pkt_ready_msg;
+
+		getevent(&pkt_ready_msg, AUDREC_UP_PACKET_READY_MSG_LEN);
+		MM_DBG("UP_PACKET_READY_MSG: write cnt lsw  %d \
+		write cnt msw %d read cnt lsw %d  read cnt msw %d \n",\
+		pkt_ready_msg.audrec_packet_write_cnt_lsw, \
+		pkt_ready_msg.audrec_packet_write_cnt_msw, \
+		pkt_ready_msg.audrec_up_prev_read_cnt_lsw, \
+		pkt_ready_msg.audrec_up_prev_read_cnt_msw);
+
+		auda2dp_in_get_dsp_frames(audio);
+		break;
+	}
+	case ADSP_MESSAGE_ID: {
+		MM_DBG("Received ADSP event: module audrectask\n");
+		break;
+	}
+	default:
+		MM_ERR("Unknown Event id %d\n", id);
+	}
+}
+
+static void auda2dp_in_get_dsp_frames(struct audio_a2dp_in *audio)
+{
+	struct audio_frame *frame;
+	uint32_t index;
+	unsigned long flags;
+
+	index = audio->in_head;
+
+	frame = (void *) (((char *)audio->in[index].data) - \
+			 sizeof(*frame));
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (audio->enc_type == ENC_TYPE_WAV)
+		audio->in[index].size = frame->a2dp.wav.frame_length;
+	else if (audio->enc_type == ENC_TYPE_SBC) {
+		audio->in[index].size = frame->a2dp.sbc.frame_length *
+						frame->a2dp.sbc.frame_num;
+		audio->in[index].frame_num = frame->a2dp.sbc.frame_num;
+		audio->in[index].frame_len = frame->a2dp.sbc.frame_length;
+	}
+
+	/* statistics of read */
+	atomic_add(audio->in[index].size, &audio->in_bytes);
+	atomic_add(1, &audio->in_samples);
+
+	audio->in_head = (audio->in_head + 1) & (FRAME_NUM - 1);
+
+	/* If overflow, move the tail index foward. */
+	if (audio->in_head == audio->in_tail)
+		audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
+	else
+		audio->in_count++;
+
+	auda2dp_dsp_read_buffer(audio, audio->dsp_cnt++);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	wake_up(&audio->wait);
+}
+
+static struct msm_adsp_ops audrec_adsp_ops = {
+	.event = audrec_dsp_event,
+};
+
+static int auda2dp_in_enc_config(struct audio_a2dp_in *audio, int enable)
+{
+	struct audpreproc_audrec_cmd_enc_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	if (audio->build_id[17] == '1') {
+		cmd.cmd_id = AUDPREPROC_AUDREC_CMD_ENC_CFG_2;
+	} else {
+		cmd.cmd_id = AUDPREPROC_AUDREC_CMD_ENC_CFG;
+	}
+	cmd.stream_id = audio->enc_id;
+
+	if (enable)
+		cmd.audrec_enc_type = audio->enc_type | ENCODE_ENABLE;
+	else
+		cmd.audrec_enc_type &= ~(ENCODE_ENABLE);
+
+	return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
+}
+
+static int auda2dp_in_param_config(struct audio_a2dp_in *audio)
+{
+	if (audio->enc_type == ENC_TYPE_WAV) {
+		struct audpreproc_audrec_cmd_parm_cfg_wav cmd;
+
+		memset(&cmd, 0, sizeof(cmd));
+		cmd.common.cmd_id = AUDPREPROC_AUDREC_CMD_PARAM_CFG;
+		cmd.common.stream_id = audio->enc_id;
+
+		cmd.aud_rec_samplerate_idx = audio->samp_rate;
+		cmd.aud_rec_stereo_mode = audio->channel_mode;
+		return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
+	} else if (audio->enc_type == ENC_TYPE_SBC) {
+		struct audpreproc_audrec_cmd_parm_cfg_sbc cmd;
+
+		memset(&cmd, 0, sizeof(cmd));
+		cmd.common.cmd_id = AUDPREPROC_AUDREC_CMD_PARAM_CFG;
+		cmd.common.stream_id = audio->enc_id;
+		cmd.aud_rec_sbc_enc_param =
+			(audio->cfg.number_of_blocks <<
+			AUDREC_SBC_ENC_PARAM_NUM_SUB_BLOCKS_MASK) |
+			(audio->cfg.number_of_subbands <<
+			AUDREC_SBC_ENC_PARAM_NUM_SUB_BANDS_MASK) |
+			(audio->cfg.mode <<
+			AUDREC_SBC_ENC_PARAM_MODE_MASK) |
+			(audio->cfg.bit_allocation <<
+			AUDREC_SBC_ENC_PARAM_BIT_ALLOC_MASK);
+		cmd.aud_rec_sbc_bit_rate_msw =
+			(audio->cfg.bit_rate & 0xFFFF0000) >> 16;
+		cmd.aud_rec_sbc_bit_rate_lsw =
+			(audio->cfg.bit_rate & 0xFFFF);
+		return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
+	}
+	return 0;
+}
+
+/* To Do: msm_snddev_route_enc(audio->enc_id); */
+static int auda2dp_in_record_config(struct audio_a2dp_in *audio, int enable)
+{
+	struct audpreproc_afe_cmd_audio_record_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG;
+	cmd.stream_id = audio->enc_id;
+	if (enable)
+		cmd.destination_activity = AUDIO_RECORDING_TURN_ON;
+	else
+		cmd.destination_activity = AUDIO_RECORDING_TURN_OFF;
+
+	cmd.source_mix_mask = audio->source;
+	if (audio->enc_id == 2) {
+		if ((cmd.source_mix_mask &
+				INTERNAL_CODEC_TX_SOURCE_MIX_MASK) ||
+			(cmd.source_mix_mask & AUX_CODEC_TX_SOURCE_MIX_MASK) ||
+			(cmd.source_mix_mask & VOICE_UL_SOURCE_MIX_MASK) ||
+			(cmd.source_mix_mask & VOICE_DL_SOURCE_MIX_MASK)) {
+			cmd.pipe_id = SOURCE_PIPE_1;
+		}
+		if (cmd.source_mix_mask &
+				AUDPP_A2DP_PIPE_SOURCE_MIX_MASK)
+			cmd.pipe_id |= SOURCE_PIPE_0;
+	}
+	return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
+}
+
+static int auda2dp_in_mem_config(struct audio_a2dp_in *audio)
+{
+	struct audrec_cmd_arecmem_cfg cmd;
+	uint16_t *data = (void *) audio->data;
+	int n;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_MEM_CFG_CMD;
+	cmd.audrec_up_pkt_intm_count = 1;
+	cmd.audrec_ext_pkt_start_addr_msw = audio->phys >> 16;
+	cmd.audrec_ext_pkt_start_addr_lsw = audio->phys;
+	cmd.audrec_ext_pkt_buf_number = FRAME_NUM;
+
+	/* prepare buffer pointers:
+	 * Wav:
+	 * Mono: 1024 samples + 4 halfword header
+	 * Stereo: 2048 samples + 4 halfword header
+	 * SBC:
+	 * 768 + 4 halfword header
+	 */
+	if (audio->enc_type == ENC_TYPE_SBC) {
+		for (n = 0; n < FRAME_NUM; n++) {
+			audio->in[n].data = data + 4;
+			data += (4 + (FRAME_SIZE_SBC/2));
+			MM_DBG("0x%8x\n", (int)(audio->in[n].data - 8));
+		}
+	} else if (audio->enc_type == ENC_TYPE_WAV) {
+		for (n = 0; n < FRAME_NUM; n++) {
+			audio->in[n].data = data + 4;
+			data += (4 + (audio->channel_mode ? 2048 : 1024));
+			MM_DBG("0x%8x\n", (int)(audio->in[n].data - 8));
+		}
+	}
+
+	return audrec_send_audrecqueue(audio, &cmd, sizeof(cmd));
+}
+
+static int auda2dp_dsp_read_buffer(struct audio_a2dp_in *audio,
+							uint32_t read_cnt)
+{
+	struct up_audrec_packet_ext_ptr cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = UP_AUDREC_PACKET_EXT_PTR;
+	cmd.audrec_up_curr_read_count_msw = read_cnt >> 16;
+	cmd.audrec_up_curr_read_count_lsw = read_cnt;
+
+	return audrec_send_bitstreamqueue(audio, &cmd, sizeof(cmd));
+}
+
+/* must be called with audio->lock held */
+static int auda2dp_in_enable(struct audio_a2dp_in *audio)
+{
+	if (audio->enabled)
+		return 0;
+
+	if (audpreproc_enable(audio->enc_id, &audpreproc_dsp_event, audio)) {
+		MM_ERR("msm_adsp_enable(audpreproc) failed\n");
+		return -ENODEV;
+	}
+
+	if (msm_adsp_enable(audio->audrec)) {
+		MM_ERR("msm_adsp_enable(audrec) failed\n");
+		audpreproc_disable(audio->enc_id, audio);
+		return -ENODEV;
+	}
+	audio->enabled = 1;
+	auda2dp_in_enc_config(audio, 1);
+
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int auda2dp_in_disable(struct audio_a2dp_in *audio)
+{
+	if (audio->enabled) {
+		audio->enabled = 0;
+		auda2dp_in_enc_config(audio, 0);
+		wake_up(&audio->wait);
+		wait_event_interruptible_timeout(audio->wait_enable,
+				audio->running == 0, 1*HZ);
+		msm_adsp_disable(audio->audrec);
+		audpreproc_disable(audio->enc_id, audio);
+	}
+	return 0;
+}
+
+static void auda2dp_in_flush(struct audio_a2dp_in *audio)
+{
+	int i;
+
+	audio->dsp_cnt = 0;
+	audio->in_head = 0;
+	audio->in_tail = 0;
+	audio->in_count = 0;
+	for (i = 0; i < FRAME_NUM; i++) {
+		audio->in[i].size = 0;
+		audio->in[i].read = 0;
+	}
+	MM_DBG("in_bytes %d\n", atomic_read(&audio->in_bytes));
+	MM_DBG("in_samples %d\n", atomic_read(&audio->in_samples));
+	atomic_set(&audio->in_bytes, 0);
+	atomic_set(&audio->in_samples, 0);
+}
+
+/* ------------------- device --------------------- */
+static long auda2dp_in_ioctl(struct file *file,
+				unsigned int cmd, unsigned long arg)
+{
+	struct audio_a2dp_in *audio = file->private_data;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = atomic_read(&audio->in_bytes);
+		stats.sample_count = atomic_read(&audio->in_samples);
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return rc;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START: {
+		uint32_t freq;
+		/* Poll at 48KHz always */
+		freq = 48000;
+		MM_DBG("AUDIO_START\n");
+		rc = msm_snddev_request_freq(&freq, audio->enc_id,
+					SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
+		MM_DBG("sample rate configured %d sample rate requested %d\n",
+				freq, audio->samp_rate);
+		if (rc < 0) {
+			MM_DBG("sample rate can not be set, return code %d\n",\
+							rc);
+			msm_snddev_withdraw_freq(audio->enc_id,
+						SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
+			MM_DBG("msm_snddev_withdraw_freq\n");
+			break;
+		}
+		/*update aurec session info in audpreproc layer*/
+		audio->session_info.session_id = audio->enc_id;
+		audio->session_info.sampling_freq = audio->samp_rate;
+		audpreproc_update_audrec_info(&audio->session_info);
+		rc = auda2dp_in_enable(audio);
+		if (!rc) {
+			rc =
+			wait_event_interruptible_timeout(audio->wait_enable,
+				audio->running != 0, 1*HZ);
+			MM_DBG("state %d rc = %d\n", audio->running, rc);
+
+			if (audio->running == 0) {
+				rc = -ENODEV;
+				msm_snddev_withdraw_freq(audio->enc_id,
+					SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
+				MM_DBG("msm_snddev_withdraw_freq\n");
+			} else
+				rc = 0;
+		}
+		audio->stopped = 0;
+		break;
+	}
+	case AUDIO_STOP: {
+		/*reset the sampling frequency information at audpreproc layer*/
+		audio->session_info.sampling_freq = 0;
+		audpreproc_update_audrec_info(&audio->session_info);
+		rc = auda2dp_in_disable(audio);
+		rc = msm_snddev_withdraw_freq(audio->enc_id,
+					SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
+		MM_DBG("msm_snddev_withdraw_freq\n");
+		audio->stopped = 1;
+		audio->abort = 0;
+		break;
+	}
+	case AUDIO_FLUSH: {
+		if (audio->stopped) {
+			/* Make sure we're stopped and we wake any threads
+			 * that might be blocked holding the read_lock.
+			 * While audio->stopped read threads will always
+			 * exit immediately.
+			 */
+			wake_up(&audio->wait);
+			mutex_lock(&audio->read_lock);
+			auda2dp_in_flush(audio);
+			mutex_unlock(&audio->read_lock);
+		}
+		break;
+	}
+	case AUDIO_SET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		/* Allow only single frame */
+		if ((audio->enc_type == ENC_TYPE_SBC) &&
+				(cfg.buffer_size != FRAME_SIZE_SBC))
+			rc = -EINVAL;
+		else
+			audio->buffer_size = cfg.buffer_size;
+		break;
+	}
+	case AUDIO_GET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		memset(&cfg, 0, sizeof(cfg));
+		if (audio->enc_type == ENC_TYPE_SBC)
+			cfg.buffer_size = FRAME_SIZE_SBC;
+		else
+			cfg.buffer_size = MONO_DATA_SIZE;
+		cfg.buffer_count = FRAME_NUM;
+		if (copy_to_user((void *) arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_SBC_ENC_CONFIG: {
+		if (copy_from_user(&audio->cfg, (void *) arg,
+						sizeof(audio->cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		audio->samp_rate = audio->cfg.sample_rate;
+		audio->channel_mode = audio->cfg.channels;
+		audio->enc_type = ENC_TYPE_SBC;
+		break;
+	}
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config cfg;
+		if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (cfg.channel_count == 1) {
+			cfg.channel_count = AUDREC_CMD_MODE_MONO;
+			audio->buffer_size = MONO_DATA_SIZE;
+		} else if (cfg.channel_count == 2) {
+			cfg.channel_count = AUDREC_CMD_MODE_STEREO;
+			audio->buffer_size = STEREO_DATA_SIZE;
+		} else {
+			rc = -EINVAL;
+			break;
+		}
+		audio->samp_rate = cfg.sample_rate;
+		audio->channel_mode = cfg.channel_count;
+		audio->enc_type = ENC_TYPE_WAV;
+		break;
+	}
+	case AUDIO_GET_SBC_ENC_CONFIG: {
+		struct msm_audio_sbc_enc_config cfg;
+		memset(&cfg, 0, sizeof(cfg));
+		cfg.bit_allocation = audio->cfg.bit_allocation;
+		cfg.mode =  audio->cfg.mode;
+		cfg.number_of_subbands = audio->cfg.number_of_subbands;
+		cfg.number_of_blocks = audio->cfg.number_of_blocks;
+		cfg.sample_rate = audio->samp_rate;
+		cfg.channels = audio->channel_mode;
+		cfg.bit_rate = audio->cfg.bit_rate;
+		if (copy_to_user((void *) arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config cfg;
+		memset(&cfg, 0, sizeof(cfg));
+		cfg.buffer_count = FRAME_NUM;
+		cfg.sample_rate = audio->samp_rate;
+		if (audio->channel_mode == AUDREC_CMD_MODE_MONO) {
+			cfg.channel_count = 1;
+			cfg.buffer_size = MONO_DATA_SIZE;
+		} else {
+			cfg.channel_count = 2;
+			cfg.buffer_size = STEREO_DATA_SIZE;
+		}
+		cfg.type = ENC_TYPE_WAV;
+		if (copy_to_user((void *) arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_GET_SESSION_ID: {
+		if (copy_to_user((void *) arg, &audio->enc_id,
+			sizeof(unsigned short))) {
+			rc = -EFAULT;
+		}
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static ssize_t auda2dp_in_read(struct file *file,
+				char __user *buf,
+				size_t count, loff_t *pos)
+{
+	struct audio_a2dp_in *audio = file->private_data;
+	unsigned long flags;
+	const char __user *start = buf;
+	void *data;
+	uint32_t index;
+	uint32_t size;
+	int rc = 0;
+	uint32_t f_len = 0, f_num = 0;
+	int i = 0;
+
+	mutex_lock(&audio->read_lock);
+	while (count > 0) {
+		rc = wait_event_interruptible(
+			audio->wait, (audio->in_count > 0) || audio->stopped ||
+			audio->abort);
+
+		if (rc < 0)
+			break;
+
+		if (audio->stopped && !audio->in_count) {
+			MM_DBG("Driver in stop state, No more buffer to read");
+			rc = 0;/* End of File */
+			break;
+		}
+
+		if (audio->abort) {
+			rc = -EPERM; /* Not permitted due to abort */
+			break;
+		}
+
+		index = audio->in_tail;
+		data = (uint8_t *) audio->in[index].data;
+		size = audio->in[index].size;
+		if (count >= size) {
+			if (audio->enc_type == ENC_TYPE_SBC &&
+				(audio->in[index].frame_len % 2)) {
+				f_len = audio->in[index].frame_len;
+				f_num = audio->in[index].frame_num;
+				for (i = 0; i < f_num; i++) {
+					if (copy_to_user(&buf[i * f_len],
+					(uint8_t *) (data + (i * (f_len + 1))),
+					f_len)) {
+						rc = -EFAULT;
+						break;
+					}
+				}
+			} else {
+				if (copy_to_user(buf, data, size)) {
+					rc = -EFAULT;
+					break;
+				}
+			}
+			spin_lock_irqsave(&audio->dsp_lock, flags);
+			if (index != audio->in_tail) {
+				/* overrun -- data is
+				 * invalid and we need to retry */
+				spin_unlock_irqrestore(&audio->dsp_lock, flags);
+				continue;
+			}
+			audio->in[index].size = 0;
+			audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
+			audio->in_count--;
+			spin_unlock_irqrestore(&audio->dsp_lock, flags);
+			count -= size;
+			buf += size;
+		} else {
+			MM_ERR("short read\n");
+			break;
+		}
+	}
+	mutex_unlock(&audio->read_lock);
+	if (buf > start)
+		return buf - start;
+
+	return rc;
+}
+
+static ssize_t auda2dp_in_write(struct file *file,
+				const char __user *buf,
+				size_t count, loff_t *pos)
+{
+	return -EINVAL;
+}
+
+static int auda2dp_in_release(struct inode *inode, struct file *file)
+{
+	struct audio_a2dp_in *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	/* with draw frequency for session
+	   incase not stopped the driver */
+	msm_snddev_withdraw_freq(audio->enc_id, SNDDEV_CAP_TX,
+					AUDDEV_CLNT_ENC);
+	auddev_unregister_evt_listner(AUDDEV_CLNT_ENC, audio->enc_id);
+	/*reset the sampling frequency information at audpreproc layer*/
+	audio->session_info.sampling_freq = 0;
+	audpreproc_update_audrec_info(&audio->session_info);
+	auda2dp_in_disable(audio);
+	auda2dp_in_flush(audio);
+	msm_adsp_put(audio->audrec);
+	audpreproc_aenc_free(audio->enc_id);
+	audio->audrec = NULL;
+	audio->opened = 0;
+	if (audio->data) {
+		iounmap(audio->msm_map);
+		free_contiguous_memory_by_paddr(audio->phys);
+		audio->data = NULL;
+	}
+	mutex_unlock(&audio->lock);
+	return 0;
+}
+
+static int auda2dp_in_open(struct inode *inode, struct file *file)
+{
+	struct audio_a2dp_in *audio = &the_audio_a2dp_in;
+	int rc;
+	int encid;
+
+	mutex_lock(&audio->lock);
+	if (audio->opened) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
+	if (audio->phys) {
+		audio->msm_map = ioremap(audio->phys, DMASZ);
+		if (IS_ERR(audio->msm_map)) {
+			MM_ERR("could not map the phys address to kernel"
+							"space\n");
+			rc = -ENOMEM;
+			free_contiguous_memory_by_paddr(audio->phys);
+			goto done;
+		}
+		audio->data = (u8 *)audio->msm_map;
+	} else {
+		MM_ERR("could not allocate DMA buffers\n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	MM_DBG("Memory addr = 0x%8x  phy addr = 0x%8x\n",\
+		(int) audio->data, (int) audio->phys);
+
+	if ((file->f_mode & FMODE_WRITE) &&
+				(file->f_mode & FMODE_READ)) {
+		rc = -EACCES;
+		MM_ERR("Non tunnel encoding is not supported\n");
+		goto done;
+	} else if (!(file->f_mode & FMODE_WRITE) &&
+					(file->f_mode & FMODE_READ)) {
+		audio->mode = MSM_AUD_ENC_MODE_TUNNEL;
+		MM_DBG("Opened for Tunnel mode encoding\n");
+	} else {
+		rc = -EACCES;
+		goto done;
+	}
+	/* Settings will be re-config at AUDIO_SET_CONFIG/SBC_ENC_CONFIG,
+	 * but at least we need to have initial config
+	 */
+	audio->channel_mode = AUDREC_CMD_MODE_MONO;
+	audio->buffer_size = FRAME_SIZE_SBC;
+	audio->samp_rate = 48000;
+	audio->enc_type = ENC_TYPE_SBC | audio->mode;
+	audio->cfg.bit_allocation = AUDIO_SBC_BA_SNR;
+	audio->cfg.mode = AUDIO_SBC_MODE_JSTEREO;
+	audio->cfg.number_of_subbands = AUDIO_SBC_BANDS_8;
+	audio->cfg.number_of_blocks = AUDIO_SBC_BLOCKS_16;
+	audio->cfg.bit_rate = 320000; /* max 512kbps(mono), 320kbs(others) */
+
+	encid = audpreproc_aenc_alloc(audio->enc_type, &audio->module_name,
+			&audio->queue_ids);
+	if (encid < 0) {
+		MM_ERR("No free encoder available\n");
+		rc = -ENODEV;
+		goto done;
+	}
+	audio->enc_id = encid;
+
+	rc = msm_adsp_get(audio->module_name, &audio->audrec,
+			   &audrec_adsp_ops, audio);
+
+	if (rc) {
+		audpreproc_aenc_free(audio->enc_id);
+		goto done;
+	}
+
+	audio->stopped = 0;
+	audio->source = 0;
+	audio->abort = 0;
+	auda2dp_in_flush(audio);
+	audio->device_events = AUDDEV_EVT_DEV_RDY | AUDDEV_EVT_DEV_RLS |
+				AUDDEV_EVT_FREQ_CHG;
+
+	rc = auddev_register_evt_listner(audio->device_events,
+					AUDDEV_CLNT_ENC, audio->enc_id,
+					a2dp_in_listener, (void *) audio);
+	if (rc) {
+		MM_ERR("failed to register device event listener\n");
+		goto evt_error;
+	}
+	audio->build_id = socinfo_get_build_id();
+	MM_DBG("Modem build id = %s\n", audio->build_id);
+	file->private_data = audio;
+	audio->opened = 1;
+	rc = 0;
+done:
+	mutex_unlock(&audio->lock);
+	return rc;
+evt_error:
+	msm_adsp_put(audio->audrec);
+	audpreproc_aenc_free(audio->enc_id);
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static const struct file_operations audio_a2dp_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= auda2dp_in_open,
+	.release	= auda2dp_in_release,
+	.read		= auda2dp_in_read,
+	.write		= auda2dp_in_write,
+	.unlocked_ioctl	= auda2dp_in_ioctl,
+};
+
+struct miscdevice audio_a2dp_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_a2dp_in",
+	.fops	= &audio_a2dp_in_fops,
+};
+
+static int __init auda2dp_in_init(void)
+{
+	mutex_init(&the_audio_a2dp_in.lock);
+	mutex_init(&the_audio_a2dp_in.read_lock);
+	spin_lock_init(&the_audio_a2dp_in.dsp_lock);
+	spin_lock_init(&the_audio_a2dp_in.dev_lock);
+	init_waitqueue_head(&the_audio_a2dp_in.wait);
+	init_waitqueue_head(&the_audio_a2dp_in.wait_enable);
+	return misc_register(&audio_a2dp_in_misc);
+}
+
+device_initcall(auda2dp_in_init);
+
+MODULE_DESCRIPTION("MSM SBC encode driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_aac.c b/arch/arm/mach-msm/qdsp5v2/audio_aac.c
new file mode 100644
index 0000000..05bca03
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/audio_aac.c
@@ -0,0 +1,2037 @@
+/*
+ * aac audio decoder device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2008-2012, Code Aurora Forum. 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.
+ *
+ */
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/earlysuspend.h>
+#include <linux/android_pmem.h>
+#include <linux/slab.h>
+#include <linux/msm_audio_aac.h>
+#include <linux/memory_alloc.h>
+
+#include <mach/msm_adsp.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/qdsp5v2/qdsp5audppmsg.h>
+#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
+#include <mach/qdsp5v2/qdsp5audplaymsg.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/qdsp5v2/audpp.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_memtypes.h>
+
+
+#define BUFSZ 32768
+#define DMASZ (BUFSZ * 2)
+#define BUFSZ_MIN 4096
+#define DMASZ_MIN (BUFSZ_MIN * 2)
+
+#define AUDPLAY_INVALID_READ_PTR_OFFSET	0xFFFF
+#define AUDDEC_DEC_AAC 5
+
+#define PCM_BUFSZ_MIN 9600	/* Hold one stereo AAC frame */
+#define PCM_BUF_MAX_COUNT 5	/* DSP only accepts 5 buffers at most
+				   but support 2 buffers currently */
+#define ROUTING_MODE_FTRT 1
+#define ROUTING_MODE_RT 2
+/* Decoder status received from AUDPPTASK */
+#define  AUDPP_DEC_STATUS_SLEEP	0
+#define	 AUDPP_DEC_STATUS_INIT  1
+#define  AUDPP_DEC_STATUS_CFG   2
+#define  AUDPP_DEC_STATUS_PLAY  3
+
+#define AUDAAC_METAFIELD_MASK 0xFFFF0000
+#define AUDAAC_EOS_FLG_OFFSET 0x0A /* Offset from beginning of buffer */
+#define AUDAAC_EOS_FLG_MASK 0x01
+#define AUDAAC_EOS_NONE 0x0 /* No EOS detected */
+#define AUDAAC_EOS_SET 0x1 /* EOS set in meta field */
+
+#define AUDAAC_EVENT_NUM 10 /* Default number of pre-allocated event packets */
+
+#define BITSTREAM_ERROR_THRESHOLD_VALUE 0x1 /* DEFAULT THRESHOLD VALUE */
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+	unsigned short mfield_sz; /*only useful for data has meta field */
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct audaac_suspend_ctl {
+	struct early_suspend node;
+	struct audio *audio;
+};
+#endif
+
+struct audaac_event{
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+
+struct audio {
+	struct buffer out[2];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed;	/* number of buffers the dsp is waiting for */
+	unsigned out_dma_sz;
+
+	atomic_t out_bytes;
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	/* Host PCM section */
+	struct buffer in[PCM_BUF_MAX_COUNT];
+	struct mutex read_lock;
+	wait_queue_head_t read_wait;	/* Wait queue for read */
+	char *read_data;	/* pointer to reader buffer */
+	int32_t read_phys;	/* physical address of reader buffer */
+	uint8_t read_next;	/* index to input buffers to be read next */
+	uint8_t fill_next;	/* index to buffer that DSP should be filling */
+	uint8_t pcm_buf_count;	/* number of pcm buffer allocated */
+	/* ---- End of Host PCM section */
+
+	struct msm_adsp_module *audplay;
+
+	/* configuration to use on next enable */
+	uint32_t out_sample_rate;
+	uint32_t out_channel_mode;
+	struct msm_audio_aac_config aac_config;
+
+	/* AV sync Info */
+	int avsync_flag;              /* Flag to indicate feedback from DSP */
+	wait_queue_head_t avsync_wait;/* Wait queue for AV Sync Message     */
+	/* 48 bits sample/bytes counter per channel */
+	uint16_t avsync[AUDPP_AVSYNC_CH_COUNT * AUDPP_AVSYNC_NUM_WORDS + 1];
+
+	/* data allocated for various buffers */
+	char *data;
+	int32_t phys; /* physical address of write buffer */
+	void *map_v_read;
+	void *map_v_write;
+
+	int mfield; /* meta field embedded in data */
+	int rflush; /* Read  flush */
+	int wflush; /* Write flush */
+	int opened;
+	int enabled;
+	int running;
+	int stopped;	/* set when stopped, cleared on flush */
+	int pcm_feedback;
+	int buf_refresh;
+	int teos; /* valid only if tunnel mode & no data left for decoder */
+	enum msm_aud_decoder_state dec_state;	/* Represents decoder state */
+	int reserved; /* A byte is being reserved */
+	char rsv_byte; /* Handle odd length user data */
+
+	const char *module_name;
+	unsigned queue_id;
+	uint16_t dec_id;
+	uint32_t read_ptr_offset;
+	int16_t source;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct audaac_suspend_ctl suspend_ctl;
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+
+	wait_queue_head_t wait;
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	wait_queue_head_t event_wait;
+	spinlock_t event_queue_lock;
+	struct mutex get_event_lock;
+	int event_abort;
+	uint32_t device_events;
+
+	struct msm_audio_bitstream_info stream_info;
+	struct msm_audio_bitstream_error_info bitstream_error_info;
+	uint32_t bitstream_error_threshold_value;
+
+	int eq_enable;
+	int eq_needs_commit;
+	struct audpp_cmd_cfg_object_params_eqalizer eq;
+	struct audpp_cmd_cfg_object_params_volume vol_pan;
+};
+
+static int auddec_dsp_config(struct audio *audio, int enable);
+static void audpp_cmd_cfg_adec_params(struct audio *audio);
+static void audpp_cmd_cfg_routing_mode(struct audio *audio);
+static void audplay_send_data(struct audio *audio, unsigned needed);
+static void audplay_error_threshold_config(struct audio *audio);
+static void audplay_config_hostpcm(struct audio *audio);
+static void audplay_buffer_refresh(struct audio *audio);
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
+static void audaac_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload);
+
+/* must be called with audio->lock held */
+static int audio_enable(struct audio *audio)
+{
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	if (audio->enabled)
+		return 0;
+
+	audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	if (msm_adsp_enable(audio->audplay)) {
+		MM_ERR("msm_adsp_enable(audplay) failed\n");
+		return -ENODEV;
+	}
+
+	if (audpp_enable(audio->dec_id, audio_dsp_event, audio)) {
+		MM_ERR("audpp_enable() failed\n");
+		msm_adsp_disable(audio->audplay);
+		return -ENODEV;
+	}
+	audio->enabled = 1;
+	return 0;
+}
+
+static void aac_listner(u32 evt_id, union auddev_evt_data *evt_payload,
+			void *private_data)
+{
+	struct audio *audio = (struct audio *) private_data;
+	switch (evt_id) {
+	case AUDDEV_EVT_DEV_RDY:
+		MM_DBG(":AUDDEV_EVT_DEV_RDY\n");
+		audio->source |= (0x1 << evt_payload->routing_id);
+		if (audio->running == 1 && audio->enabled == 1)
+			audpp_route_stream(audio->dec_id, audio->source);
+		break;
+	case AUDDEV_EVT_DEV_RLS:
+		MM_DBG(":AUDDEV_EVT_DEV_RLS\n");
+		audio->source &= ~(0x1 << evt_payload->routing_id);
+		if (audio->running == 1 && audio->enabled == 1)
+			audpp_route_stream(audio->dec_id, audio->source);
+		break;
+	case AUDDEV_EVT_STREAM_VOL_CHG:
+		audio->vol_pan.volume = evt_payload->session_vol;
+		MM_DBG(":AUDDEV_EVT_STREAM_VOL_CHG, stream vol %d\n",
+				audio->vol_pan.volume);
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+		break;
+	default:
+		MM_ERR(":ERROR:wrong event\n");
+		break;
+	}
+}
+/* must be called with audio->lock held */
+static int audio_disable(struct audio *audio)
+{
+	int rc = 0;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+		auddec_dsp_config(audio, 0);
+		rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+		else if (audio->dec_state != MSM_AUD_DECODER_STATE_CLOSE)
+			rc = -EFAULT;
+		else
+			rc = 0;
+		wake_up(&audio->write_wait);
+		wake_up(&audio->read_wait);
+		msm_adsp_disable(audio->audplay);
+		audpp_disable(audio->dec_id, audio);
+		audio->out_needed = 0;
+	}
+	return rc;
+}
+
+/* ------------------- dsp --------------------- */
+static void audio_update_pcm_buf_entry(struct audio *audio, uint32_t *payload)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	if (audio->rflush)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < payload[1]; index++) {
+		if (audio->in[audio->fill_next].addr ==
+		    payload[2 + index * 2]) {
+			MM_DBG("in[%d] ready\n", audio->fill_next);
+			audio->in[audio->fill_next].used =
+				payload[3 + index * 2];
+			if ((++audio->fill_next) == audio->pcm_buf_count)
+				audio->fill_next = 0;
+
+		} else {
+			MM_ERR("expected=%x ret=%x\n",
+				audio->in[audio->fill_next].addr,
+				payload[1 + index * 2]);
+			break;
+		}
+	}
+	if (audio->in[audio->fill_next].used == 0) {
+		audplay_buffer_refresh(audio);
+	} else {
+		MM_DBG("read cannot keep up\n");
+		audio->buf_refresh = 1;
+	}
+	wake_up(&audio->read_wait);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+
+}
+
+static void audaac_bitstream_error_info(struct audio *audio, uint32_t *payload)
+{
+	unsigned long flags;
+	union msm_audio_event_payload e_payload;
+
+	if (payload[0] != AUDDEC_DEC_AAC) {
+		MM_ERR("Unexpected bitstream error info from DSP:\
+				Invalid decoder\n");
+		return;
+	}
+
+	/* get stream info from DSP msg */
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+
+	audio->bitstream_error_info.dec_id = payload[0];
+	audio->bitstream_error_info.err_msg_indicator = payload[1];
+	audio->bitstream_error_info.err_type = payload[2];
+
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	MM_ERR("bit_stream_error_type=%d error_count=%d\n",
+			audio->bitstream_error_info.err_type, (0x0000FFFF &
+			audio->bitstream_error_info.err_msg_indicator));
+
+	/* send event to ARM to notify error info coming */
+	e_payload.error_info = audio->bitstream_error_info;
+	audaac_post_event(audio, AUDIO_EVENT_BITSTREAM_ERROR_INFO, e_payload);
+}
+
+static void audaac_update_stream_info(struct audio *audio, uint32_t *payload)
+{
+	unsigned long flags;
+	union msm_audio_event_payload e_payload;
+
+	/* get stream info from DSP msg */
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+
+	audio->stream_info.codec_type = AUDIO_CODEC_TYPE_AAC;
+	audio->stream_info.chan_info = (0x0000FFFF & payload[1]);
+	audio->stream_info.sample_rate = (0x0000FFFF & payload[2]);
+	audio->stream_info.bit_stream_info = (0x0000FFFF & payload[3]);
+	audio->stream_info.bit_rate = payload[4];
+
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	MM_DBG("chan_info=%d, sample_rate=%d, bit_stream_info=%d\n",
+			audio->stream_info.chan_info,
+			audio->stream_info.sample_rate,
+			audio->stream_info.bit_stream_info);
+
+	/* send event to ARM to notify steam info coming */
+	e_payload.stream_info = audio->stream_info;
+	audaac_post_event(audio, AUDIO_EVENT_STREAM_INFO, e_payload);
+}
+static void audplay_dsp_event(void *data, unsigned id, size_t len,
+			      void (*getevent) (void *ptr, size_t len))
+{
+	struct audio *audio = data;
+	uint32_t msg[28];
+	getevent(msg, sizeof(msg));
+
+	MM_DBG("msg_id=%x\n", id);
+
+	switch (id) {
+	case AUDPLAY_MSG_DEC_NEEDS_DATA:
+		audplay_send_data(audio, 1);
+		break;
+
+	case AUDPLAY_MSG_BUFFER_UPDATE:
+		audio_update_pcm_buf_entry(audio, msg);
+		break;
+
+	case AUDPLAY_UP_STREAM_INFO:
+		if ((msg[1] & AUDPLAY_STREAM_INFO_MSG_MASK) ==
+				AUDPLAY_STREAM_INFO_MSG_MASK) {
+			audaac_bitstream_error_info(audio, msg);
+		} else {
+			audaac_update_stream_info(audio, msg);
+		}
+		break;
+
+	case AUDPLAY_UP_OUTPORT_FLUSH_ACK:
+		MM_DBG("OUTPORT_FLUSH_ACK\n");
+		audio->rflush = 0;
+		wake_up(&audio->read_wait);
+		if (audio->pcm_feedback)
+			audplay_buffer_refresh(audio);
+		break;
+
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audplaytask)\n");
+		break;
+
+	default:
+		MM_ERR("unexpected message from decoder \n");
+	}
+}
+
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned status = msg[1];
+
+			switch (status) {
+			case AUDPP_DEC_STATUS_SLEEP: {
+				uint16_t reason = msg[2];
+				MM_DBG("decoder status: sleep reason = \
+						0x%04x\n", reason);
+				if ((reason == AUDPP_MSG_REASON_MEM)
+					|| (reason ==
+					AUDPP_MSG_REASON_NODECODER)) {
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_FAILURE;
+					wake_up(&audio->wait);
+				} else if (reason == AUDPP_MSG_REASON_NONE) {
+					/* decoder is in disable state */
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_CLOSE;
+					wake_up(&audio->wait);
+				}
+				break;
+			}
+			case AUDPP_DEC_STATUS_INIT:
+				MM_DBG("decoder status: init \n");
+				if (audio->pcm_feedback)
+					audpp_cmd_cfg_routing_mode(audio);
+				else
+					audpp_cmd_cfg_adec_params(audio);
+				break;
+
+			case AUDPP_DEC_STATUS_CFG:
+				MM_DBG("decoder status: cfg \n");
+				break;
+			case AUDPP_DEC_STATUS_PLAY:
+				MM_DBG("decoder status: play \n");
+				/* send  mixer command */
+				audpp_route_stream(audio->dec_id,
+						audio->source);
+				if (audio->pcm_feedback) {
+					audplay_error_threshold_config(audio);
+					audplay_config_hostpcm(audio);
+					audplay_buffer_refresh(audio);
+				}
+				audio->dec_state =
+					MSM_AUD_DECODER_STATE_SUCCESS;
+				wake_up(&audio->wait);
+				break;
+			default:
+				MM_ERR("unknown decoder status \n");
+			}
+			break;
+		}
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			MM_DBG("CFG_MSG ENABLE\n");
+			auddec_dsp_config(audio, 1);
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+			audpp_dsp_set_eq(audio->dec_id, audio->eq_enable,
+					&audio->eq, POPP);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			MM_DBG("CFG_MSG DISABLE\n");
+			audio->running = 0;
+		} else {
+			MM_DBG("CFG_MSG %d?\n",	msg[0]);
+		}
+		break;
+	case AUDPP_MSG_ROUTING_ACK:
+		MM_DBG("ROUTING_ACK mode=%d\n",	msg[1]);
+		audpp_cmd_cfg_adec_params(audio);
+		break;
+
+	case AUDPP_MSG_FLUSH_ACK:
+		MM_DBG("FLUSH_ACK\n");
+		audio->wflush = 0;
+		audio->rflush = 0;
+		wake_up(&audio->write_wait);
+		if (audio->pcm_feedback)
+			audplay_buffer_refresh(audio);
+		break;
+
+	case AUDPP_MSG_PCMDMAMISSED:
+		MM_DBG("PCMDMAMISSED\n");
+		audio->teos = 1;
+		wake_up(&audio->write_wait);
+		break;
+
+	case AUDPP_MSG_AVSYNC_MSG:
+		MM_DBG("AUDPP_MSG_AVSYNC_MSG\n");
+		memcpy(&audio->avsync[0], msg, sizeof(audio->avsync));
+		audio->avsync_flag = 1;
+		wake_up(&audio->avsync_wait);
+		break;
+
+	default:
+		MM_ERR("UNKNOWN (%d)\n", id);
+	}
+
+}
+
+struct msm_adsp_ops audplay_adsp_ops_aac = {
+	.event = audplay_dsp_event,
+};
+
+#define audplay_send_queue0(audio, cmd, len) \
+	msm_adsp_write(audio->audplay, audio->queue_id,\
+			cmd, len)
+
+static int auddec_dsp_config(struct audio *audio, int enable)
+{
+	struct audpp_cmd_cfg_dec_type cfg_dec_cmd;
+
+	memset(&cfg_dec_cmd, 0, sizeof(cfg_dec_cmd));
+
+	cfg_dec_cmd.cmd_id = AUDPP_CMD_CFG_DEC_TYPE;
+	if (enable)
+		cfg_dec_cmd.dec_cfg = AUDPP_CMD_UPDATDE_CFG_DEC |
+				AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_AAC;
+	else
+		cfg_dec_cmd.dec_cfg = AUDPP_CMD_UPDATDE_CFG_DEC |
+				AUDPP_CMD_DIS_DEC_V;
+	cfg_dec_cmd.dm_mode = 0x0;
+	cfg_dec_cmd.stream_id = audio->dec_id;
+
+	return audpp_send_queue1(&cfg_dec_cmd, sizeof(cfg_dec_cmd));
+}
+
+static void audpp_cmd_cfg_adec_params(struct audio *audio)
+{
+	struct audpp_cmd_cfg_adec_params_aac cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_AAC_LEN;
+	cmd.common.dec_id = audio->dec_id;
+	cmd.common.input_sampling_frequency = audio->out_sample_rate;
+	cmd.format = audio->aac_config.format;
+	cmd.audio_object = audio->aac_config.audio_object;
+	cmd.ep_config = audio->aac_config.ep_config;
+	cmd.aac_section_data_resilience_flag =
+		audio->aac_config.aac_section_data_resilience_flag;
+	cmd.aac_scalefactor_data_resilience_flag =
+		audio->aac_config.aac_scalefactor_data_resilience_flag;
+	cmd.aac_spectral_data_resilience_flag =
+		audio->aac_config.aac_spectral_data_resilience_flag;
+	cmd.sbr_on_flag = audio->aac_config.sbr_on_flag;
+	cmd.sbr_ps_on_flag = audio->aac_config.sbr_ps_on_flag;
+	cmd.channel_configuration = audio->aac_config.channel_configuration;
+
+	audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static void audpp_cmd_cfg_routing_mode(struct audio *audio)
+{
+	struct audpp_cmd_routing_mode cmd;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_ROUTING_MODE;
+	cmd.object_number = audio->dec_id;
+	if (audio->pcm_feedback)
+		cmd.routing_mode = ROUTING_MODE_FTRT;
+	else
+		cmd.routing_mode = ROUTING_MODE_RT;
+
+	audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static int audplay_dsp_send_data_avail(struct audio *audio,
+				       unsigned idx, unsigned len)
+{
+	struct audplay_cmd_bitstream_data_avail_nt2 cmd;
+
+	cmd.cmd_id = AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_NT2;
+	if (audio->mfield)
+		cmd.decoder_id = AUDAAC_METAFIELD_MASK |
+			(audio->out[idx].mfield_sz >> 1);
+	else
+	    cmd.decoder_id = audio->dec_id;
+	cmd.buf_ptr = audio->out[idx].addr;
+	cmd.buf_size = len / 2;
+	cmd.partition_number = 0;
+	return audplay_send_queue0(audio, &cmd, sizeof(cmd));
+}
+
+static void audplay_buffer_refresh(struct audio *audio)
+{
+	struct audplay_cmd_buffer_refresh refresh_cmd;
+
+	refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH;
+	refresh_cmd.num_buffers = 1;
+	refresh_cmd.buf0_address = audio->in[audio->fill_next].addr;
+	/* AAC frame size */
+	refresh_cmd.buf0_length = audio->in[audio->fill_next].size -
+		(audio->in[audio->fill_next].size % 1024)
+		+ (audio->mfield ? 24 : 0);
+	refresh_cmd.buf_read_count = 0;
+	MM_DBG("buf0_addr=%x buf0_len=%d\n", refresh_cmd.buf0_address,
+			refresh_cmd.buf0_length);
+	(void)audplay_send_queue0(audio, &refresh_cmd, sizeof(refresh_cmd));
+}
+
+static void audplay_outport_flush(struct audio *audio)
+{
+	struct audplay_cmd_outport_flush op_flush_cmd;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	op_flush_cmd.cmd_id = AUDPLAY_CMD_OUTPORT_FLUSH;
+	(void)audplay_send_queue0(audio, &op_flush_cmd, sizeof(op_flush_cmd));
+}
+
+static void audplay_error_threshold_config(struct audio *audio)
+{
+	union audplay_cmd_channel_info ch_cfg_cmd;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	ch_cfg_cmd.thr_update.cmd_id = AUDPLAY_CMD_CHANNEL_INFO;
+	ch_cfg_cmd.thr_update.threshold_update = AUDPLAY_ERROR_THRESHOLD_ENABLE;
+	ch_cfg_cmd.thr_update.threshold_value =
+		audio->bitstream_error_threshold_value;
+	(void)audplay_send_queue0(audio, &ch_cfg_cmd, sizeof(ch_cfg_cmd));
+}
+
+static void audplay_config_hostpcm(struct audio *audio)
+{
+	struct audplay_cmd_hpcm_buf_cfg cfg_cmd;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	cfg_cmd.cmd_id = AUDPLAY_CMD_HPCM_BUF_CFG;
+	cfg_cmd.max_buffers = audio->pcm_buf_count;
+	cfg_cmd.byte_swap = 0;
+	cfg_cmd.hostpcm_config = (0x8000) | (0x4000);
+	cfg_cmd.feedback_frequency = 1;
+	cfg_cmd.partition_number = 0;
+	(void)audplay_send_queue0(audio, &cfg_cmd, sizeof(cfg_cmd));
+
+}
+
+static void audplay_send_data(struct audio *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (needed && !audio->wflush) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			MM_DBG("frame %d free\n", audio->out_tail);
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+			MM_DBG("frame %d busy\n", audio->out_tail);
+			audplay_dsp_send_data_avail(audio, audio->out_tail,
+						    frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+ done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+
+static void audio_flush(struct audio *audio)
+{
+	audio->out[0].used = 0;
+	audio->out[1].used = 0;
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->reserved = 0;
+	audio->out_needed = 0;
+	atomic_set(&audio->out_bytes, 0);
+}
+
+static void audio_flush_pcm_buf(struct audio *audio)
+{
+	uint8_t index;
+
+	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
+		audio->in[index].used = 0;
+	audio->buf_refresh = 0;
+	audio->read_next = 0;
+	audio->fill_next = 0;
+}
+
+static int audaac_validate_usr_config(struct msm_audio_aac_config *config)
+{
+	int ret_val = -1;
+
+	if (config->format != AUDIO_AAC_FORMAT_ADTS &&
+		config->format != AUDIO_AAC_FORMAT_RAW &&
+		config->format != AUDIO_AAC_FORMAT_PSUEDO_RAW &&
+		config->format != AUDIO_AAC_FORMAT_LOAS)
+		goto done;
+
+	if (config->audio_object != AUDIO_AAC_OBJECT_LC &&
+		config->audio_object != AUDIO_AAC_OBJECT_LTP &&
+		config->audio_object != AUDIO_AAC_OBJECT_BSAC &&
+		config->audio_object != AUDIO_AAC_OBJECT_ERLC)
+		goto done;
+
+	if (config->audio_object == AUDIO_AAC_OBJECT_ERLC) {
+		if (config->ep_config > 3)
+			goto done;
+		if (config->aac_scalefactor_data_resilience_flag !=
+			AUDIO_AAC_SCA_DATA_RES_OFF &&
+			config->aac_scalefactor_data_resilience_flag !=
+			AUDIO_AAC_SCA_DATA_RES_ON)
+			goto done;
+		if (config->aac_section_data_resilience_flag !=
+			AUDIO_AAC_SEC_DATA_RES_OFF &&
+			config->aac_section_data_resilience_flag !=
+			AUDIO_AAC_SEC_DATA_RES_ON)
+			goto done;
+		if (config->aac_spectral_data_resilience_flag !=
+			AUDIO_AAC_SPEC_DATA_RES_OFF &&
+			config->aac_spectral_data_resilience_flag !=
+			AUDIO_AAC_SPEC_DATA_RES_ON)
+			goto done;
+	} else {
+		config->aac_section_data_resilience_flag =
+			AUDIO_AAC_SEC_DATA_RES_OFF;
+		config->aac_scalefactor_data_resilience_flag =
+			AUDIO_AAC_SCA_DATA_RES_OFF;
+		config->aac_spectral_data_resilience_flag =
+			AUDIO_AAC_SPEC_DATA_RES_OFF;
+	}
+
+#ifndef CONFIG_AUDIO_AAC_PLUS
+	if (AUDIO_AAC_SBR_ON_FLAG_OFF != config->sbr_on_flag)
+		goto done;
+#else
+	if (config->sbr_on_flag != AUDIO_AAC_SBR_ON_FLAG_OFF &&
+		config->sbr_on_flag != AUDIO_AAC_SBR_ON_FLAG_ON)
+		goto done;
+#endif
+
+#ifndef CONFIG_AUDIO_ENHANCED_AAC_PLUS
+	if (AUDIO_AAC_SBR_PS_ON_FLAG_OFF != config->sbr_ps_on_flag)
+		goto done;
+#else
+	if (config->sbr_ps_on_flag != AUDIO_AAC_SBR_PS_ON_FLAG_OFF &&
+		config->sbr_ps_on_flag != AUDIO_AAC_SBR_PS_ON_FLAG_ON)
+		goto done;
+#endif
+
+	if (config->dual_mono_mode > AUDIO_AAC_DUAL_MONO_PL_SR)
+		goto done;
+
+	if (config->channel_configuration > 2)
+		goto done;
+
+	ret_val = 0;
+ done:
+	return ret_val;
+}
+
+static void audio_ioport_reset(struct audio *audio)
+{
+	/* Make sure read/write thread are free from
+	 * sleep and knowing that system is not able
+	 * to process io request at the moment
+	 */
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audio_flush(audio);
+	mutex_unlock(&audio->write_lock);
+	wake_up(&audio->read_wait);
+	mutex_lock(&audio->read_lock);
+	audio_flush_pcm_buf(audio);
+	mutex_unlock(&audio->read_lock);
+	audio->avsync_flag = 1;
+	wake_up(&audio->avsync_wait);
+
+}
+
+static int audaac_events_pending(struct audio *audio)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	return empty || audio->event_abort;
+}
+
+static void audaac_reset_event_queue(struct audio *audio)
+{
+	unsigned long flags;
+	struct audaac_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audaac_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+				struct audaac_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	return;
+}
+
+static long audaac_process_event_req(struct audio *audio, void __user *arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audaac_event *drv_evt = NULL;
+	int timeout;
+	unsigned long flags;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int) usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(
+			audio->event_wait, audaac_events_pending(audio),
+			msecs_to_jiffies(timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(
+			audio->event_wait, audaac_events_pending(audio));
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	rc = 0;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audaac_event, list);
+		list_del(&drv_evt->list);
+	}
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else
+		rc = -1;
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	if (!rc && copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audio_enable_eq(struct audio *audio, int enable)
+{
+	if (audio->eq_enable == enable && !audio->eq_needs_commit)
+		return 0;
+
+	audio->eq_enable = enable;
+
+	if (audio->running) {
+		audpp_dsp_set_eq(audio->dec_id, enable, &audio->eq, POPP);
+		audio->eq_needs_commit = 0;
+	}
+	return 0;
+}
+
+static int audio_get_avsync_data(struct audio *audio,
+						struct msm_audio_stats *stats)
+{
+	int rc = -EINVAL;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (audio->dec_id == audio->avsync[0] && audio->avsync_flag) {
+		/* av_sync sample count */
+		stats->sample_count = (audio->avsync[2] << 16) |
+							(audio->avsync[3]);
+
+		/* av_sync byte_count */
+		stats->byte_count = (audio->avsync[5] << 16) |
+							(audio->avsync[6]);
+
+		audio->avsync_flag = 0;
+		rc = 0;
+	}
+	local_irq_restore(flags);
+	return rc;
+
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = -EINVAL;
+	unsigned long flags = 0;
+	uint16_t enable_mask;
+	int enable;
+	int prev_state;
+
+	MM_DBG("cmd = %d\n", cmd);
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+
+		audio->avsync_flag = 0;
+		memset(&stats, 0, sizeof(stats));
+		if (audpp_query_avsync(audio->dec_id) < 0)
+			return rc;
+
+		rc = wait_event_interruptible_timeout(audio->avsync_wait,
+				(audio->avsync_flag == 1),
+				msecs_to_jiffies(AUDPP_AVSYNC_EVENT_TIMEOUT));
+
+		if (rc < 0)
+			return rc;
+		else if ((rc > 0) || ((rc == 0) && (audio->avsync_flag == 1))) {
+			if (audio_get_avsync_data(audio, &stats) < 0)
+				return rc;
+
+			if (copy_to_user((void *)arg, &stats, sizeof(stats)))
+				return -EFAULT;
+			return 0;
+		} else
+			return -EAGAIN;
+	}
+
+	switch (cmd) {
+	case AUDIO_ENABLE_AUDPP:
+		if (copy_from_user(&enable_mask, (void *) arg,
+						sizeof(enable_mask))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		enable = (enable_mask & EQ_ENABLE) ? 1 : 0;
+		audio_enable_eq(audio, enable);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+	case AUDIO_SET_VOLUME:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.volume = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_PAN:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.pan = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_EQ:
+		prev_state = audio->eq_enable;
+		audio->eq_enable = 0;
+		if (copy_from_user(&audio->eq.num_bands, (void *) arg,
+				sizeof(audio->eq) -
+				(AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2))) {
+			rc = -EFAULT;
+			break;
+		}
+		audio->eq_enable = prev_state;
+		audio->eq_needs_commit = 1;
+		rc = 0;
+		break;
+	}
+
+	if (-EINVAL != rc)
+		return rc;
+
+	if (cmd == AUDIO_GET_EVENT) {
+		MM_DBG("AUDIO_GET_EVENT\n");
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audaac_process_event_req(audio,
+					(void __user *) arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		return rc;
+	}
+
+	if (cmd == AUDIO_ABORT_GET_EVENT) {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		MM_DBG("AUDIO_START\n");
+		rc = audio_enable(audio);
+		if (!rc) {
+			rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+			MM_INFO("dec_state %d rc = %d\n", audio->dec_state, rc);
+
+			if (audio->dec_state != MSM_AUD_DECODER_STATE_SUCCESS)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		break;
+	case AUDIO_STOP:
+		MM_DBG("AUDIO_STOP\n");
+		rc = audio_disable(audio);
+		audio->stopped = 1;
+		audio_ioport_reset(audio);
+		audio->stopped = 0;
+		break;
+	case AUDIO_FLUSH:
+		MM_DBG("AUDIO_FLUSH running=%d\n", audio->running);
+		audio->rflush = 1;
+		audio->wflush = 1;
+		audio_ioport_reset(audio);
+		if (audio->running) {
+			audpp_flush(audio->dec_id);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		break;
+
+	case AUDIO_OUTPORT_FLUSH:
+		MM_DBG("AUDIO_OUTPORT_FLUSH\n");
+		audio->rflush = 1;
+		wake_up(&audio->read_wait);
+		mutex_lock(&audio->read_lock);
+		audio_flush_pcm_buf(audio);
+		mutex_unlock(&audio->read_lock);
+		audplay_outport_flush(audio);
+		rc = wait_event_interruptible(audio->read_wait,
+				!audio->rflush);
+		if (rc < 0) {
+			MM_ERR("AUDPLAY_OUTPORT_FLUSH interrupted\n");
+			rc = -EINTR;
+		}
+		break;
+
+	case AUDIO_SET_CONFIG:{
+			struct msm_audio_config config;
+
+			if (copy_from_user
+			    (&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+
+			if (config.channel_count == 1) {
+				config.channel_count =
+				    AUDPP_CMD_PCM_INTF_MONO_V;
+			} else if (config.channel_count == 2) {
+				config.channel_count =
+				    AUDPP_CMD_PCM_INTF_STEREO_V;
+			} else {
+				rc = -EINVAL;
+				break;
+			}
+
+			audio->out_sample_rate = config.sample_rate;
+			audio->out_channel_mode = config.channel_count;
+			audio->mfield = config.meta_field;
+			rc = 0;
+			break;
+		}
+	case AUDIO_GET_CONFIG:{
+			struct msm_audio_config config;
+			config.buffer_size = (audio->out_dma_sz >> 1);
+			config.buffer_count = 2;
+			config.sample_rate = audio->out_sample_rate;
+			if (audio->out_channel_mode ==
+			    AUDPP_CMD_PCM_INTF_MONO_V) {
+				config.channel_count = 1;
+			} else {
+				config.channel_count = 2;
+			}
+			config.meta_field = 0;
+			config.unused[0] = 0;
+			config.unused[1] = 0;
+			config.unused[2] = 0;
+			if (copy_to_user((void *)arg, &config,
+					 sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+
+			break;
+		}
+	case AUDIO_GET_AAC_CONFIG:{
+			if (copy_to_user((void *)arg, &audio->aac_config,
+				sizeof(audio->aac_config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_SET_AAC_CONFIG:{
+			struct msm_audio_aac_config usr_config;
+
+			if (copy_from_user
+				(&usr_config, (void *)arg,
+					sizeof(usr_config))) {
+				rc = -EFAULT;
+				break;
+			}
+
+			if (audaac_validate_usr_config(&usr_config) == 0) {
+				audio->aac_config = usr_config;
+				rc = 0;
+			} else
+				rc = -EINVAL;
+
+			break;
+		}
+	case AUDIO_GET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			config.pcm_feedback = audio->pcm_feedback;
+			config.buffer_count = PCM_BUF_MAX_COUNT;
+			config.buffer_size = PCM_BUFSZ_MIN;
+			if (copy_to_user((void *)arg, &config,
+					 sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_SET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			if (copy_from_user
+			    (&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+			if (config.pcm_feedback != audio->pcm_feedback) {
+				MM_ERR("Not sufficient permission to"
+					 "change the playback mode\n");
+				rc = -EACCES;
+				break;
+			}
+			if ((config.buffer_count > PCM_BUF_MAX_COUNT) ||
+			    (config.buffer_count == 1))
+				config.buffer_count = PCM_BUF_MAX_COUNT;
+
+			if (config.buffer_size < PCM_BUFSZ_MIN)
+				config.buffer_size = PCM_BUFSZ_MIN;
+
+			/* Check if pcm feedback is required */
+			if (config.pcm_feedback) {
+					audio->buf_refresh = 0;
+					audio->read_next = 0;
+					audio->fill_next = 0;
+			}
+			rc = 0;
+			break;
+		}
+	case AUDIO_PAUSE:
+		MM_DBG("AUDIO_PAUSE %ld\n", arg);
+		rc = audpp_pause(audio->dec_id, (int) arg);
+		break;
+	case AUDIO_GET_STREAM_INFO:{
+		if (audio->stream_info.sample_rate == 0) {
+			/* haven't received DSP stream event,
+			the stream info is not updated */
+			rc = -EPERM;
+			break;
+		}
+		if (copy_to_user((void *)arg, &audio->stream_info,
+			sizeof(struct msm_audio_bitstream_info)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	}
+	case AUDIO_GET_BITSTREAM_ERROR_INFO:{
+		if ((audio->bitstream_error_info.err_msg_indicator &
+				AUDPLAY_STREAM_INFO_MSG_MASK) ==
+				AUDPLAY_STREAM_INFO_MSG_MASK) {
+			/* haven't received bitstream error info event,
+			the bitstream error info is not updated */
+			rc = -EPERM;
+			break;
+		}
+		if (copy_to_user((void *)arg, &audio->bitstream_error_info,
+			sizeof(struct msm_audio_bitstream_error_info)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	}
+	case AUDIO_GET_SESSION_ID:
+		if (copy_to_user((void *) arg, &audio->dec_id,
+				sizeof(unsigned short)))
+			rc =  -EFAULT;
+		else
+			rc = 0;
+		break;
+	case AUDIO_SET_ERR_THRESHOLD_VALUE:
+		if (copy_from_user(&audio->bitstream_error_threshold_value,
+					(void *)arg, sizeof(uint32_t)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+/* Only useful in tunnel-mode */
+static int audaac_fsync(struct file *file, loff_t ppos1, loff_t ppos2, int datasync)
+{
+	struct audio *audio = file->private_data;
+	struct buffer *frame;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	if (!audio->running || audio->pcm_feedback) {
+		rc = -EINVAL;
+		goto done_nolock;
+	}
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(!audio->out[0].used &&
+		!audio->out[1].used &&
+		audio->out_needed) || audio->wflush);
+
+	if (rc < 0)
+		goto done;
+	else if (audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (audio->reserved) {
+		MM_DBG("send reserved byte\n");
+		frame = audio->out + audio->out_tail;
+		((char *) frame->data)[0] = audio->rsv_byte;
+		((char *) frame->data)[1] = 0;
+		frame->used = 2;
+		audplay_send_data(audio, 0);
+
+		rc = wait_event_interruptible(audio->write_wait,
+			(!audio->out[0].used &&
+			!audio->out[1].used &&
+			audio->out_needed) || audio->wflush);
+
+		if (rc < 0)
+			goto done;
+		else if (audio->wflush) {
+			rc = -EBUSY;
+			goto done;
+		}
+	}
+
+	/* pcm dmamiss message is sent continously
+	 * when decoder is starved so no race
+	 * condition concern
+	 */
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		audio->teos || audio->wflush);
+
+	if (audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+done_nolock:
+	return rc;
+}
+
+static ssize_t audio_read(struct file *file, char __user *buf, size_t count,
+			  loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	int rc = 0;
+
+	if (!audio->pcm_feedback)
+		return 0; /* PCM feedback is not enabled. Nothing to read */
+
+	mutex_lock(&audio->read_lock);
+	MM_DBG("to read %d \n", count);
+	while (count > 0) {
+		rc = wait_event_interruptible_timeout(audio->read_wait,
+					      (audio->in[audio->read_next].
+						used > 0) || (audio->stopped)
+						|| (audio->rflush),
+			msecs_to_jiffies(MSM_AUD_BUFFER_UPDATE_WAIT_MS));
+
+		if (rc == 0) {
+			rc = -ETIMEDOUT;
+			break;
+		} else if (rc < 0)
+			break;
+
+		if (audio->stopped || audio->rflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (count < audio->in[audio->read_next].used) {
+			/* Read must happen in frame boundary. Since driver
+			   does not know frame size, read count must be greater
+			   or equal to size of PCM samples */
+			MM_DBG("no partial frame done reading\n");
+			break;
+		} else {
+			MM_DBG("read from in[%d]\n", audio->read_next);
+			if (copy_to_user
+			    (buf, audio->in[audio->read_next].data,
+			     audio->in[audio->read_next].used)) {
+				MM_ERR("invalid addr %x\n", (unsigned int)buf);
+				rc = -EFAULT;
+				break;
+			}
+			count -= audio->in[audio->read_next].used;
+			buf += audio->in[audio->read_next].used;
+			audio->in[audio->read_next].used = 0;
+			if ((++audio->read_next) == audio->pcm_buf_count)
+				audio->read_next = 0;
+			break;
+				/*
+				* Force to exit while loop
+				* to prevent output thread
+				* sleep too long if data is not
+				* ready at this moment.
+				*/
+		}
+	}
+
+	/* don't feed output buffer to HW decoder during flushing
+	 * buffer refresh command will be sent once flush completes
+	 * send buf refresh command here can confuse HW decoder
+	 */
+	if (audio->buf_refresh && !audio->rflush) {
+		audio->buf_refresh = 0;
+		MM_DBG("kick start pcm feedback again\n");
+		audplay_buffer_refresh(audio);
+	}
+
+	mutex_unlock(&audio->read_lock);
+
+	if (buf > start)
+		rc = buf - start;
+
+	MM_DBG("read %d bytes\n", rc);
+	return rc;
+}
+
+static int audaac_process_eos(struct audio *audio,
+	const char __user *buf_start, unsigned short mfield_size)
+{
+	struct buffer *frame;
+	char *buf_ptr;
+	int rc = 0;
+
+	MM_DBG("signal input EOS reserved=%d\n", audio->reserved);
+	if (audio->reserved) {
+		MM_DBG("Pass reserve byte\n");
+		frame = audio->out + audio->out_head;
+		buf_ptr = frame->data;
+		rc = wait_event_interruptible(audio->write_wait,
+					(frame->used == 0)
+					|| (audio->stopped)
+					|| (audio->wflush));
+	if (rc < 0)
+		goto done;
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+	buf_ptr[0] = audio->rsv_byte;
+	buf_ptr[1] = 0;
+	audio->out_head ^= 1;
+	frame->mfield_sz = 0;
+	audio->reserved = 0;
+	frame->used = 2;
+	audplay_send_data(audio, 0);
+	}
+	MM_DBG("Now signal input EOS after reserved bytes %d %d %d\n",
+		audio->out[0].used, audio->out[1].used, audio->out_needed);
+	frame = audio->out + audio->out_head;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->out_needed &&
+		audio->out[0].used == 0 &&
+		audio->out[1].used == 0)
+		|| (audio->stopped)
+		|| (audio->wflush));
+
+	if (rc < 0)
+		goto done;
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (copy_from_user(frame->data, buf_start, mfield_size)) {
+		rc = -EFAULT;
+		goto done;
+	}
+
+	frame->mfield_sz = mfield_size;
+	audio->out_head ^= 1;
+	frame->used = mfield_size;
+	audplay_send_data(audio, 0);
+done:
+	return rc;
+}
+static ssize_t audio_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	char *cpy_ptr;
+	int rc = 0, eos_condition = AUDAAC_EOS_NONE;
+	unsigned dsize;
+
+	unsigned short mfield_size = 0;
+	MM_DBG("cnt=%d\n", count);
+	mutex_lock(&audio->write_lock);
+	while (count > 0) {
+		frame = audio->out + audio->out_head;
+		cpy_ptr = frame->data;
+		dsize = 0;
+		rc = wait_event_interruptible(audio->write_wait,
+					      (frame->used == 0)
+						|| (audio->stopped)
+						|| (audio->wflush));
+		if (rc < 0)
+			break;
+		if (audio->stopped || audio->wflush) {
+			rc = -EBUSY;
+			break;
+		}
+		if (audio->mfield) {
+			if (buf == start) {
+				/* Processing beginning of user buffer */
+				if (__get_user(mfield_size,
+					(unsigned short __user *) buf)) {
+					rc = -EFAULT;
+					break;
+				} else 	if (mfield_size > count) {
+					rc = -EINVAL;
+					break;
+				}
+				MM_DBG("mf offset_val %x\n", mfield_size);
+				if (copy_from_user(cpy_ptr, buf, mfield_size)) {
+					rc = -EFAULT;
+					break;
+				}
+				/* Check if EOS flag is set and buffer has
+				* contains just meta field
+				*/
+				if (cpy_ptr[AUDAAC_EOS_FLG_OFFSET] &
+						AUDAAC_EOS_FLG_MASK) {
+					MM_DBG("eos set\n");
+					eos_condition = AUDAAC_EOS_SET;
+					if (mfield_size == count) {
+						buf += mfield_size;
+						break;
+					} else
+					cpy_ptr[AUDAAC_EOS_FLG_OFFSET] &=
+							~AUDAAC_EOS_FLG_MASK;
+				}
+				/* Check EOS to see if */
+				cpy_ptr += mfield_size;
+				count -= mfield_size;
+				dsize += mfield_size;
+				buf += mfield_size;
+			} else {
+				mfield_size = 0;
+				MM_DBG("continuous buffer\n");
+			}
+			frame->mfield_sz = mfield_size;
+		}
+
+		if (audio->reserved) {
+			MM_DBG("append reserved byte %x\n",
+				audio->rsv_byte);
+			*cpy_ptr = audio->rsv_byte;
+			xfer = (count > ((frame->size - mfield_size) - 1)) ?
+				(frame->size - mfield_size) - 1 : count;
+			cpy_ptr++;
+			dsize += 1;
+			audio->reserved = 0;
+		} else
+			xfer = (count > (frame->size - mfield_size)) ?
+				(frame->size - mfield_size) : count;
+
+		if (copy_from_user(cpy_ptr, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+
+		dsize += xfer;
+		if (dsize & 1) {
+			audio->rsv_byte = ((char *) frame->data)[dsize - 1];
+			MM_DBG("odd length buf reserve last byte %x\n",
+					audio->rsv_byte);
+			audio->reserved = 1;
+			dsize--;
+		}
+		count -= xfer;
+		buf += xfer;
+
+		if (dsize > 0) {
+			audio->out_head ^= 1;
+			frame->used = dsize;
+			audplay_send_data(audio, 0);
+		}
+	}
+	MM_DBG("eos_condition %x buf[0x%x] start[0x%x]\n", eos_condition,
+			(int) buf, (int) start);
+	if (eos_condition == AUDAAC_EOS_SET)
+		rc = audaac_process_eos(audio, start, mfield_size);
+	mutex_unlock(&audio->write_lock);
+	if (!rc) {
+		if (buf > start)
+			return buf - start;
+	}
+	return rc;
+}
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	MM_INFO("audio instance 0x%08x freeing\n", (int)audio);
+
+	mutex_lock(&audio->lock);
+	auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->dec_id);
+	audio_disable(audio);
+	audio_flush(audio);
+	audio_flush_pcm_buf(audio);
+	msm_adsp_put(audio->audplay);
+	audpp_adec_free(audio->dec_id);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&audio->suspend_ctl.node);
+#endif
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audaac_reset_event_queue(audio);
+	iounmap(audio->map_v_write);
+	free_contiguous_memory_by_paddr(audio->phys);
+	iounmap(audio->map_v_read);
+	free_contiguous_memory_by_paddr(audio->read_phys);
+	mutex_unlock(&audio->lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio);
+	return 0;
+}
+
+static void audaac_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload)
+{
+	struct audaac_event *e_node = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+				struct audaac_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audaac_event), GFP_ATOMIC);
+		if (!e_node) {
+			MM_ERR("No mem to post event %d\n", type);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	wake_up(&audio->event_wait);
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audaac_suspend(struct early_suspend *h)
+{
+	struct audaac_suspend_ctl *ctl =
+		container_of(h, struct audaac_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audaac_post_event(ctl->audio, AUDIO_EVENT_SUSPEND, payload);
+}
+
+static void audaac_resume(struct early_suspend *h)
+{
+	struct audaac_suspend_ctl *ctl =
+		container_of(h, struct audaac_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audaac_post_event(ctl->audio, AUDIO_EVENT_RESUME, payload);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audaac_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audaac_debug_read(struct file *file, char __user *buf,
+					size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 1024;
+	static char buffer[1024];
+	int n = 0, i;
+	struct audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"enabled %d\n", audio->enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_feedback %d\n", audio->pcm_feedback);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_buf_sz %d\n", audio->out[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_buf_count %d \n", audio->pcm_buf_count);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_buf_sz %d \n", audio->in[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"volume %x \n", audio->vol_pan.volume);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"sample rate %d \n", audio->out_sample_rate);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"channel mode %d \n", audio->out_channel_mode);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"rflush %d\n", audio->rflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"running %d \n", audio->running);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"dec state %d \n", audio->dec_state);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_needed %d \n", audio->out_needed);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_head %d \n", audio->out_head);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_tail %d \n", audio->out_tail);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out[0].used %d \n", audio->out[0].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out[1].used %d \n", audio->out[1].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"buffer_refresh %d \n", audio->buf_refresh);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"read_next %d \n", audio->read_next);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"fill_next %d \n", audio->fill_next);
+	for (i = 0; i < audio->pcm_buf_count; i++)
+		n += scnprintf(buffer + n, debug_bufmax - n,
+				"in[%d].used %d \n", i, audio->in[i].used);
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audaac_debug_fops = {
+	.read = audaac_debug_read,
+	.open = audaac_debug_open,
+};
+#endif
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = NULL;
+	int rc, dec_attrb, decid, index, offset = 0;
+	unsigned pmem_sz = DMASZ;
+	struct audaac_event *e_node = NULL;
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_aac_" + 5];
+#endif
+
+	/* Allocate audio instance, set to zero */
+	audio = kzalloc(sizeof(struct audio), GFP_KERNEL);
+	if (!audio) {
+		MM_ERR("no memory to allocate audio instance \n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	MM_INFO("audio instance 0x%08x created\n", (int)audio);
+
+	/* Allocate the decoder */
+	dec_attrb = AUDDEC_DEC_AAC;
+	if ((file->f_mode & FMODE_WRITE) &&
+			(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_NONTUNNEL;
+		audio->pcm_feedback = NON_TUNNEL_MODE_PLAYBACK;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_TUNNEL;
+		audio->pcm_feedback = TUNNEL_MODE_PLAYBACK;
+	} else {
+		kfree(audio);
+		rc = -EACCES;
+		goto done;
+	}
+	decid = audpp_adec_alloc(dec_attrb, &audio->module_name,
+			&audio->queue_id);
+
+	if (decid < 0) {
+		MM_ERR("No free decoder available, freeing instance 0x%08x\n",
+				(int)audio);
+		rc = -ENODEV;
+		kfree(audio);
+		goto done;
+	}
+	audio->dec_id = decid & MSM_AUD_DECODER_MASK;
+
+	while (pmem_sz >= DMASZ_MIN) {
+		MM_DBG("pmemsz = %d\n", pmem_sz);
+		audio->phys = allocate_contiguous_ebi_nomap(pmem_sz, SZ_4K);
+		if (audio->phys) {
+			audio->map_v_write =
+					ioremap(audio->phys,
+						pmem_sz);
+			if (IS_ERR(audio->map_v_write)) {
+				MM_ERR("could not map write phys address, \
+						freeing instance 0x%08x\n",
+						(int)audio);
+				rc = -ENOMEM;
+				free_contiguous_memory_by_paddr(audio->phys);
+				audpp_adec_free(audio->dec_id);
+				kfree(audio);
+				goto done;
+			}
+			audio->data = (u8 *)audio->map_v_write;
+			MM_DBG("write buf: phy addr 0x%08x kernel addr \
+				0x%08x\n", audio->phys, (int)audio->data);
+			break;
+		} else if (pmem_sz == DMASZ_MIN) {
+			MM_ERR("could not allocate write buffers, freeing \
+					instance 0x%08x\n", (int)audio);
+			rc = -ENOMEM;
+			audpp_adec_free(audio->dec_id);
+			kfree(audio);
+			goto done;
+		} else
+			pmem_sz >>= 1;
+	}
+	audio->out_dma_sz = pmem_sz;
+
+	audio->read_phys = allocate_contiguous_ebi_nomap(PCM_BUFSZ_MIN
+					* PCM_BUF_MAX_COUNT, SZ_4K);
+	if (!audio->read_phys) {
+		MM_ERR("could not allocate read buffers, freeing instance \
+				0x%08x\n", (int)audio);
+		rc = -ENOMEM;
+		iounmap(audio->map_v_write);
+		free_contiguous_memory_by_paddr(audio->phys);
+		audpp_adec_free(audio->dec_id);
+		kfree(audio);
+		goto done;
+	}
+	audio->map_v_read = ioremap(audio->read_phys,
+				PCM_BUFSZ_MIN * PCM_BUF_MAX_COUNT);
+	if (IS_ERR(audio->map_v_read)) {
+		MM_ERR("could not map read phys address, freeing instance \
+				0x%08x\n", (int)audio);
+		rc = -ENOMEM;
+		iounmap(audio->map_v_write);
+		free_contiguous_memory_by_paddr(audio->phys);
+		free_contiguous_memory_by_paddr(audio->read_phys);
+		audpp_adec_free(audio->dec_id);
+		kfree(audio);
+		goto done;
+	}
+	audio->read_data = audio->map_v_read;
+	MM_DBG("read buf: phy addr 0x%08x kernel addr 0x%08x\n",
+				audio->read_phys, (int)audio->read_data);
+
+	rc = msm_adsp_get(audio->module_name, &audio->audplay,
+			  &audplay_adsp_ops_aac, audio);
+	if (rc) {
+		MM_ERR("failed to get %s module, freeing instance 0x%08x\n",
+				audio->module_name, (int)audio);
+		goto err;
+	}
+
+	mutex_init(&audio->lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->get_event_lock);
+	spin_lock_init(&audio->dsp_lock);
+	spin_lock_init(&audio->event_queue_lock);
+	INIT_LIST_HEAD(&audio->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+	init_waitqueue_head(&audio->write_wait);
+	init_waitqueue_head(&audio->read_wait);
+	init_waitqueue_head(&audio->wait);
+	init_waitqueue_head(&audio->event_wait);
+	init_waitqueue_head(&audio->avsync_wait);
+
+	audio->out[0].data = audio->data + 0;
+	audio->out[0].addr = audio->phys + 0;
+	audio->out[0].size = audio->out_dma_sz >> 1;
+
+	audio->out[1].data = audio->data + audio->out[0].size;
+	audio->out[1].addr = audio->phys + audio->out[0].size;
+	audio->out[1].size = audio->out[0].size;
+
+	audio->pcm_buf_count = PCM_BUF_MAX_COUNT;
+	for (index = 0; index < PCM_BUF_MAX_COUNT; index++) {
+		audio->in[index].data = audio->read_data + offset;
+		audio->in[index].addr = audio->read_phys + offset;
+		audio->in[index].size = PCM_BUFSZ_MIN;
+		audio->in[index].used = 0;
+		offset += PCM_BUFSZ_MIN;
+	}
+
+	audio->out_sample_rate = 44100;
+	audio->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V;
+	audio->aac_config.format = AUDIO_AAC_FORMAT_ADTS;
+	audio->aac_config.audio_object = AUDIO_AAC_OBJECT_LC;
+	audio->aac_config.ep_config = 0;
+	audio->aac_config.aac_section_data_resilience_flag =
+		AUDIO_AAC_SEC_DATA_RES_OFF;
+	audio->aac_config.aac_scalefactor_data_resilience_flag =
+		AUDIO_AAC_SCA_DATA_RES_OFF;
+	audio->aac_config.aac_spectral_data_resilience_flag =
+		AUDIO_AAC_SPEC_DATA_RES_OFF;
+#ifdef CONFIG_AUDIO_AAC_PLUS
+	audio->aac_config.sbr_on_flag = AUDIO_AAC_SBR_ON_FLAG_ON;
+#else
+	audio->aac_config.sbr_on_flag = AUDIO_AAC_SBR_ON_FLAG_OFF;
+#endif
+#ifdef CONFIG_AUDIO_ENHANCED_AAC_PLUS
+	audio->aac_config.sbr_ps_on_flag = AUDIO_AAC_SBR_PS_ON_FLAG_ON;
+#else
+	audio->aac_config.sbr_ps_on_flag = AUDIO_AAC_SBR_PS_ON_FLAG_OFF;
+#endif
+	audio->aac_config.dual_mono_mode = AUDIO_AAC_DUAL_MONO_PL_SR;
+	audio->aac_config.channel_configuration = 2;
+	audio->vol_pan.volume = 0x2000;
+	audio->bitstream_error_threshold_value =
+		BITSTREAM_ERROR_THRESHOLD_VALUE;
+
+	audio_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+
+	audio->device_events = AUDDEV_EVT_DEV_RDY
+				|AUDDEV_EVT_DEV_RLS|
+				AUDDEV_EVT_STREAM_VOL_CHG;
+
+	rc = auddev_register_evt_listner(audio->device_events,
+					AUDDEV_CLNT_DEC,
+					audio->dec_id,
+					aac_listner,
+					(void *)audio);
+	if (rc) {
+		MM_ERR("%s: failed to register listner\n", __func__);
+		goto event_err;
+	}
+
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_aac_%04x", audio->dec_id);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+				NULL, (void *) audio,
+				&audaac_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		MM_DBG("debugfs_create_file failed\n");
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	audio->suspend_ctl.node.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+	audio->suspend_ctl.node.resume = audaac_resume;
+	audio->suspend_ctl.node.suspend = audaac_suspend;
+	audio->suspend_ctl.audio = audio;
+	register_early_suspend(&audio->suspend_ctl.node);
+#endif
+	for (index = 0; index < AUDAAC_EVENT_NUM; index++) {
+		e_node = kmalloc(sizeof(struct audaac_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			MM_ERR("event pkt alloc failed\n");
+			break;
+		}
+	}
+	memset(&audio->stream_info, 0, sizeof(struct msm_audio_bitstream_info));
+	memset(&audio->bitstream_error_info, 0,
+			sizeof(struct msm_audio_bitstream_info));
+done:
+	return rc;
+event_err:
+	msm_adsp_put(audio->audplay);
+err:
+	iounmap(audio->map_v_write);
+	free_contiguous_memory_by_paddr(audio->phys);
+	iounmap(audio->map_v_read);
+	free_contiguous_memory_by_paddr(audio->read_phys);
+	audpp_adec_free(audio->dec_id);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_aac_fops = {
+	.owner = THIS_MODULE,
+	.open = audio_open,
+	.release = audio_release,
+	.read = audio_read,
+	.write = audio_write,
+	.unlocked_ioctl = audio_ioctl,
+	.fsync = audaac_fsync
+};
+
+struct miscdevice audio_aac_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_aac",
+	.fops = &audio_aac_fops,
+};
+
+static int __init audio_init(void)
+{
+	return misc_register(&audio_aac_misc);
+}
+
+static void __exit audio_exit(void)
+{
+	misc_deregister(&audio_aac_misc);
+}
+
+module_init(audio_init);
+module_exit(audio_exit);
+
+MODULE_DESCRIPTION("MSM AAC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_aac_in.c b/arch/arm/mach-msm/qdsp5v2/audio_aac_in.c
new file mode 100644
index 0000000..8aee946
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/audio_aac_in.c
@@ -0,0 +1,1482 @@
+/*
+ * aac audio input device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2009-2012, Code Aurora Forum. 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.
+ *
+ */
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/msm_audio_aac.h>
+#include <linux/android_pmem.h>
+#include <linux/memory_alloc.h>
+#include <mach/msm_memtypes.h>
+
+#include <mach/msm_adsp.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/qdsp5v2/qdsp5audreccmdi.h>
+#include <mach/qdsp5v2/qdsp5audrecmsg.h>
+#include <mach/qdsp5v2/audpreproc.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/debug_mm.h>
+#include <mach/socinfo.h>
+
+/* FRAME_NUM must be a power of two */
+#define FRAME_NUM		(8)
+#define FRAME_SIZE		(772 * 2) /* 1536 bytes data */
+#define NT_FRAME_SIZE	(780 * 2) /* 1536 bytes data  + 24 meta field*/
+#define AAC_FRAME_SIZE	1536
+#define DMASZ 			(FRAME_SIZE * FRAME_NUM)
+#define OUT_FRAME_NUM	(2)
+#define META_OUT_SIZE	(24)
+#define META_IN_SIZE	(14)
+#define OUT_BUFFER_SIZE (32 * 1024 + META_OUT_SIZE)
+#define BUFFER_SIZE		(OUT_BUFFER_SIZE * OUT_FRAME_NUM)
+
+#define AUDPREPROC_AAC_EOS_FLG_OFFSET 0x0A /* Offset from beginning of buffer */
+#define AUDPREPROC_AAC_EOS_FLG_MASK 0x01
+#define AUDPREPROC_AAC_EOS_NONE 0x0 /* No EOS detected */
+#define AUDPREPROC_AAC_EOS_SET 0x1 /* EOS set in meta field */
+
+#define PCM_CONFIG_UPDATE_FLAG_ENABLE -1
+#define PCM_CONFIG_UPDATE_FLAG_DISABLE	0
+
+#define ENABLE_FLAG_VALUE	-1
+#define DISABLE_FLAG_VALUE	0
+
+struct buffer {
+	void *data;
+	uint32_t size;
+	uint32_t read;
+	uint32_t addr;
+	uint32_t used;
+	uint32_t mfield_sz;
+};
+
+struct audio_in {
+	struct buffer in[FRAME_NUM];
+
+	spinlock_t dsp_lock;
+
+	atomic_t in_bytes;
+	atomic_t in_samples;
+
+	struct mutex lock;
+	struct mutex read_lock;
+	wait_queue_head_t wait;
+	wait_queue_head_t wait_enable;
+	/*write section*/
+	struct buffer out[OUT_FRAME_NUM];
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed;	/* number of buffers the dsp is waiting for */
+	uint32_t out_count;
+
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+	int32_t out_phys; /* physical address of write buffer */
+	char *out_data;
+	void *map_v_read;
+	void *map_v_write;
+
+	int mfield; /* meta field embedded in data */
+	int wflush; /*write flush */
+	int rflush; /*read flush*/
+	int out_frame_cnt;
+
+	struct msm_adsp_module *audrec;
+
+	/* configuration to use on next enable */
+	uint32_t buffer_size; /* Frame size (36 bytes) */
+	uint32_t samp_rate;
+	uint32_t channel_mode;
+	uint32_t bit_rate; /* bit rate for AAC */
+	uint32_t record_quality; /* record quality (bits/sample/channel) */
+	uint32_t enc_type;
+
+	uint32_t dsp_cnt;
+	uint32_t in_head; /* next buffer dsp will write */
+	uint32_t in_tail; /* next buffer read() will read */
+	uint32_t in_count; /* number of buffers available to read() */
+	uint32_t mode;
+	uint32_t eos_ack;
+	uint32_t flush_ack;
+
+	const char *module_name;
+	unsigned queue_ids;
+	uint16_t enc_id;
+
+	struct audrec_session_info session_info; /*audrec session info*/
+	uint16_t source; /* Encoding source bit mask */
+	uint32_t device_events; /* device events interested in */
+	uint32_t dev_cnt;
+	spinlock_t dev_lock;
+
+	/* data allocated for various buffers */
+	char *data;
+	dma_addr_t phys;
+
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+	int abort; /* set when error, like sample rate mismatch */
+	char *build_id;
+};
+
+struct audio_frame {
+	uint16_t frame_count_lsw;
+	uint16_t frame_count_msw;
+	uint16_t frame_length;
+	uint16_t erased_pcm;
+	unsigned char raw_bitstream[]; /* samples */
+} __attribute__((packed));
+
+struct audio_frame_nt {
+	uint16_t metadata_len;
+	uint16_t frame_count_lsw;
+	uint16_t frame_count_msw;
+	uint16_t frame_length;
+	uint16_t erased_pcm;
+	uint16_t reserved;
+	uint16_t time_stamp_dword_lsw;
+	uint16_t time_stamp_dword_msw;
+	uint16_t time_stamp_lsw;
+	uint16_t time_stamp_msw;
+	uint16_t nflag_lsw;
+	uint16_t nflag_msw;
+	unsigned char raw_bitstream[]; /* samples */
+} __attribute__((packed));
+
+struct aac_encoded_meta_in {
+	uint16_t metadata_len;
+	uint16_t time_stamp_dword_lsw;
+	uint16_t time_stamp_dword_msw;
+	uint16_t time_stamp_lsw;
+	uint16_t time_stamp_msw;
+	uint16_t nflag_lsw;
+	uint16_t nflag_msw;
+};
+
+/* Audrec Queue command sent macro's */
+#define audrec_send_bitstreamqueue(audio, cmd, len) \
+	msm_adsp_write(audio->audrec, ((audio->queue_ids & 0xFFFF0000) >> 16),\
+			cmd, len)
+
+#define audrec_send_audrecqueue(audio, cmd, len) \
+	msm_adsp_write(audio->audrec, (audio->queue_ids & 0x0000FFFF),\
+			cmd, len)
+
+/* DSP command send functions */
+static int audaac_in_enc_config(struct audio_in *audio, int enable);
+static int audaac_in_param_config(struct audio_in *audio);
+static int audaac_in_mem_config(struct audio_in *audio);
+static int audaac_in_record_config(struct audio_in *audio, int enable);
+static int audaac_dsp_read_buffer(struct audio_in *audio, uint32_t read_cnt);
+
+static void audaac_in_get_dsp_frames(struct audio_in *audio);
+static int audpcm_config(struct audio_in *audio);
+static void audaac_out_flush(struct audio_in *audio);
+static int audpreproc_cmd_cfg_routing_mode(struct audio_in *audio);
+static void audpreproc_pcm_send_data(struct audio_in *audio, unsigned needed);
+static void audaac_nt_in_get_dsp_frames(struct audio_in *audio);
+
+static void audaac_in_flush(struct audio_in *audio);
+
+static void aac_in_listener(u32 evt_id, union auddev_evt_data *evt_payload,
+				void *private_data)
+{
+	struct audio_in *audio = (struct audio_in *) private_data;
+	unsigned long flags;
+
+	MM_DBG("evt_id = 0x%8x\n", evt_id);
+	switch (evt_id) {
+	case AUDDEV_EVT_DEV_RDY: {
+		MM_DBG("AUDDEV_EVT_DEV_RDY\n");
+		spin_lock_irqsave(&audio->dev_lock, flags);
+		audio->dev_cnt++;
+		audio->source |= (0x1 << evt_payload->routing_id);
+		spin_unlock_irqrestore(&audio->dev_lock, flags);
+
+		if ((audio->running == 1) && (audio->enabled == 1) &&
+			(audio->mode == MSM_AUD_ENC_MODE_TUNNEL))
+			audaac_in_record_config(audio, 1);
+
+		break;
+	}
+	case AUDDEV_EVT_DEV_RLS: {
+		MM_DBG("AUDDEV_EVT_DEV_RLS\n");
+		spin_lock_irqsave(&audio->dev_lock, flags);
+		audio->dev_cnt--;
+		audio->source &= ~(0x1 << evt_payload->routing_id);
+		spin_unlock_irqrestore(&audio->dev_lock, flags);
+
+		if ((!audio->running) || (!audio->enabled))
+			break;
+
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+			/* Turn of as per source */
+			if (audio->source)
+				audaac_in_record_config(audio, 1);
+			else
+			/* Turn off all */
+				audaac_in_record_config(audio, 0);
+		}
+		break;
+	}
+	case AUDDEV_EVT_FREQ_CHG: {
+		MM_DBG("Encoder Driver got sample rate change event\n");
+		MM_DBG("sample rate %d\n", evt_payload->freq_info.sample_rate);
+		MM_DBG("dev_type %d\n", evt_payload->freq_info.dev_type);
+		MM_DBG("acdb_dev_id %d\n", evt_payload->freq_info.acdb_dev_id);
+		if ((audio->running == 1) && (audio->enabled == 1)) {
+			/* Stop Recording sample rate does not match
+			   with device sample rate */
+			if (evt_payload->freq_info.sample_rate !=
+				audio->samp_rate) {
+				if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
+					audaac_in_record_config(audio, 0);
+				audio->abort = 1;
+				wake_up(&audio->wait);
+			}
+		}
+		break;
+	}
+	default:
+		MM_ERR("wrong event %d\n", evt_id);
+		break;
+	}
+}
+
+/* Convert Bit Rate to Record Quality field of DSP */
+static unsigned int bitrate_to_record_quality(unsigned int sample_rate,
+		unsigned int channel, unsigned int bit_rate) {
+	unsigned int temp;
+
+	temp = sample_rate * channel;
+	MM_DBG(" sample rate *  channel = %d \n", temp);
+	/* To represent in Q12 fixed format */
+	temp = (bit_rate * 4096) / temp;
+	MM_DBG(" Record Quality = 0x%8x \n", temp);
+	return temp;
+}
+
+/* ------------------- dsp preproc event handler--------------------- */
+static void audpreproc_dsp_event(void *data, unsigned id,  void *msg)
+{
+	struct audio_in *audio = data;
+
+	switch (id) {
+	case AUDPREPROC_ERROR_MSG: {
+		struct audpreproc_err_msg *err_msg = msg;
+
+		MM_ERR("ERROR_MSG: stream id %d err idx %d\n",
+		err_msg->stream_id, err_msg->aud_preproc_err_idx);
+		/* Error case */
+		wake_up(&audio->wait_enable);
+		break;
+	}
+	case AUDPREPROC_CMD_CFG_DONE_MSG: {
+		MM_DBG("CMD_CFG_DONE_MSG \n");
+		break;
+	}
+	case AUDPREPROC_CMD_ENC_CFG_DONE_MSG: {
+		struct audpreproc_cmd_enc_cfg_done_msg *enc_cfg_msg = msg;
+
+		MM_DBG("CMD_ENC_CFG_DONE_MSG: stream id %d enc type \
+			0x%8x\n", enc_cfg_msg->stream_id,
+			enc_cfg_msg->rec_enc_type);
+		/* Encoder enable success */
+		if (enc_cfg_msg->rec_enc_type & ENCODE_ENABLE) {
+			if(audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
+				MM_DBG("routing command\n");
+				audpreproc_cmd_cfg_routing_mode(audio);
+			} else {
+				audaac_in_param_config(audio);
+			}
+		} else { /* Encoder disable success */
+			audio->running = 0;
+			if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
+				audaac_in_record_config(audio, 0);
+			else
+				wake_up(&audio->wait_enable);
+		}
+		break;
+	}
+	case AUDPREPROC_CMD_ENC_PARAM_CFG_DONE_MSG: {
+		MM_DBG("CMD_ENC_PARAM_CFG_DONE_MSG\n");
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
+			audaac_in_mem_config(audio);
+		else
+			audpcm_config(audio);
+		break;
+	}
+	case AUDPREPROC_CMD_ROUTING_MODE_DONE_MSG: {
+		struct audpreproc_cmd_routing_mode_done\
+				*routing_cfg_done_msg = msg;
+		if (routing_cfg_done_msg->configuration == 0) {
+			MM_INFO("routing configuration failed\n");
+			audio->running = 0;
+		} else
+			audaac_in_param_config(audio);
+		break;
+	}
+	case AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG: {
+		MM_DBG("AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG\n");
+		wake_up(&audio->wait_enable);
+		break;
+	}
+	default:
+		MM_ERR("Unknown Event id %d\n", id);
+	}
+}
+
+/* ------------------- dsp audrec event handler--------------------- */
+static void audrec_dsp_event(void *data, unsigned id, size_t len,
+			    void (*getevent)(void *ptr, size_t len))
+{
+	struct audio_in *audio = data;
+
+	switch (id) {
+	case AUDREC_CMD_MEM_CFG_DONE_MSG: {
+		MM_DBG("CMD_MEM_CFG_DONE MSG DONE\n");
+		audio->running = 1;
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+			if (audio->dev_cnt > 0)
+				audaac_in_record_config(audio, 1);
+		} else {
+			audpreproc_pcm_send_data(audio, 1);
+			wake_up(&audio->wait_enable);
+		}
+		break;
+	}
+	case AUDREC_FATAL_ERR_MSG: {
+		struct audrec_fatal_err_msg fatal_err_msg;
+
+		getevent(&fatal_err_msg, AUDREC_FATAL_ERR_MSG_LEN);
+		MM_ERR("FATAL_ERR_MSG: err id %d\n",
+				fatal_err_msg.audrec_err_id);
+		/* Error stop the encoder */
+		audio->stopped = 1;
+		wake_up(&audio->wait);
+		if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)
+			wake_up(&audio->write_wait);
+		break;
+	}
+	case AUDREC_UP_PACKET_READY_MSG: {
+		struct audrec_up_pkt_ready_msg pkt_ready_msg;
+
+		getevent(&pkt_ready_msg, AUDREC_UP_PACKET_READY_MSG_LEN);
+		MM_DBG("UP_PACKET_READY_MSG: write cnt lsw  %d \
+		write cnt msw %d read cnt lsw %d  read cnt msw %d \n",\
+		pkt_ready_msg.audrec_packet_write_cnt_lsw, \
+		pkt_ready_msg.audrec_packet_write_cnt_msw, \
+		pkt_ready_msg.audrec_up_prev_read_cnt_lsw, \
+		pkt_ready_msg.audrec_up_prev_read_cnt_msw);
+
+		audaac_in_get_dsp_frames(audio);
+		break;
+	}
+	case AUDREC_CMD_PCM_BUFFER_PTR_UPDATE_ARM_TO_ENC_MSG: {
+		MM_DBG("ptr_update recieved from DSP\n");
+		audpreproc_pcm_send_data(audio, 1);
+		break;
+	}
+	case AUDREC_CMD_PCM_CFG_ARM_TO_ENC_DONE_MSG: {
+		MM_ERR("AUDREC_CMD_PCM_CFG_ARM_TO_ENC_DONE_MSG");
+		audaac_in_mem_config(audio);
+		break;
+	}
+	case AUDREC_UP_NT_PACKET_READY_MSG: {
+		struct audrec_up_nt_packet_ready_msg pkt_ready_msg;
+
+		getevent(&pkt_ready_msg, AUDREC_UP_NT_PACKET_READY_MSG_LEN);
+		MM_DBG("UP_NT_PACKET_READY_MSG: write cnt lsw  %d \
+		write cnt msw %d read cnt lsw %d  read cnt msw %d \n",\
+		pkt_ready_msg.audrec_packetwrite_cnt_lsw, \
+		pkt_ready_msg.audrec_packetwrite_cnt_msw, \
+		pkt_ready_msg.audrec_upprev_readcount_lsw, \
+		pkt_ready_msg.audrec_upprev_readcount_msw);
+
+		audaac_nt_in_get_dsp_frames(audio);
+		break;
+	}
+	case AUDREC_CMD_EOS_ACK_MSG: {
+		MM_DBG("eos ack recieved\n");
+		break;
+	}
+	case AUDREC_CMD_FLUSH_DONE_MSG: {
+		audio->wflush = 0;
+		audio->rflush = 0;
+		audio->flush_ack = 1;
+		wake_up(&audio->write_wait);
+		MM_DBG("flush ack recieved\n");
+		break;
+	}
+	case ADSP_MESSAGE_ID: {
+		MM_DBG("Received ADSP event:module audrectask\n");
+		break;
+	}
+	default:
+		MM_ERR("Unknown Event id %d\n", id);
+	}
+}
+
+static void audaac_in_get_dsp_frames(struct audio_in *audio)
+{
+	struct audio_frame *frame;
+	uint32_t index;
+	unsigned long flags;
+
+	MM_DBG("head = %d\n", audio->in_head);
+	index = audio->in_head;
+
+	frame = (void *) (((char *)audio->in[index].data) - \
+			 sizeof(*frame));
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->in[index].size = frame->frame_length;
+
+	/* statistics of read */
+	atomic_add(audio->in[index].size, &audio->in_bytes);
+	atomic_add(1, &audio->in_samples);
+
+	audio->in_head = (audio->in_head + 1) & (FRAME_NUM - 1);
+
+	/* If overflow, move the tail index foward. */
+	if (audio->in_head == audio->in_tail) {
+		MM_ERR("Error! not able to keep up the read\n");
+		audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
+	} else
+		audio->in_count++;
+
+	audaac_dsp_read_buffer(audio, audio->dsp_cnt++);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+
+	wake_up(&audio->wait);
+}
+
+static void audaac_nt_in_get_dsp_frames(struct audio_in *audio)
+{
+	struct audio_frame_nt *nt_frame;
+	uint32_t index;
+	unsigned long flags;
+	MM_DBG("head = %d\n", audio->in_head);
+	index = audio->in_head;
+	nt_frame = (void *) (((char *)audio->in[index].data) - \
+				sizeof(struct audio_frame_nt));
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->in[index].size = nt_frame->frame_length;
+	/* statistics of read */
+	atomic_add(audio->in[index].size, &audio->in_bytes);
+	atomic_add(1, &audio->in_samples);
+
+	audio->in_head = (audio->in_head + 1) & (FRAME_NUM - 1);
+
+	/* If overflow, move the tail index foward. */
+	if (audio->in_head == audio->in_tail)
+		MM_DBG("Error! not able to keep up the read\n");
+	else
+		audio->in_count++;
+
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	wake_up(&audio->wait);
+}
+
+
+struct msm_adsp_ops audrec_aac_adsp_ops = {
+	.event = audrec_dsp_event,
+};
+
+static int audpreproc_pcm_buffer_ptr_refresh(struct audio_in *audio,
+				       unsigned idx, unsigned len)
+{
+	struct audrec_cmd_pcm_buffer_ptr_refresh_arm_enc cmd;
+
+	if (len ==  META_OUT_SIZE)
+		len = len / 2;
+	else
+		len = (len + META_OUT_SIZE) / 2;
+	MM_DBG("len = %d\n", len);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_PCM_BUFFER_PTR_REFRESH_ARM_TO_ENC;
+	cmd.num_buffers = 1;
+	if (cmd.num_buffers == 1) {
+		cmd.buf_address_length[0] = (audio->out[idx].addr &
+							0xffff0000) >> 16;
+		cmd.buf_address_length[1] = (audio->out[idx].addr &
+							0x0000ffff);
+		cmd.buf_address_length[2] = (len & 0xffff0000) >> 16;
+		cmd.buf_address_length[3] = (len & 0x0000ffff);
+	}
+	audio->out_frame_cnt++;
+	return audrec_send_audrecqueue(audio, (void *)&cmd,
+					(unsigned int)sizeof(cmd));
+}
+
+
+static int audpcm_config(struct audio_in *audio)
+{
+	struct audrec_cmd_pcm_cfg_arm_to_enc cmd;
+	MM_DBG("\n");
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_PCM_CFG_ARM_TO_ENC;
+	cmd.config_update_flag = PCM_CONFIG_UPDATE_FLAG_ENABLE;
+	cmd.enable_flag = ENABLE_FLAG_VALUE;
+	cmd.sampling_freq = audio->samp_rate;
+	if (!audio->channel_mode)
+		cmd.channels = 1;
+	else
+		cmd.channels = 2;
+	cmd.frequency_of_intimation = 1;
+	cmd.max_number_of_buffers = OUT_FRAME_NUM;
+	return audrec_send_audrecqueue(audio, (void *)&cmd,
+					(unsigned int)sizeof(cmd));
+}
+
+
+static int audpreproc_cmd_cfg_routing_mode(struct audio_in *audio)
+{
+	struct audpreproc_audrec_cmd_routing_mode cmd;
+
+	MM_DBG("\n");
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPREPROC_AUDREC_CMD_ROUTING_MODE;
+	cmd.stream_id = audio->enc_id;
+	if (audio->mode == MSM_ADSP_ENC_MODE_NON_TUNNEL)
+		cmd.routing_mode = 1;
+	return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
+}
+
+
+
+static int audaac_in_enc_config(struct audio_in *audio, int enable)
+{
+	struct audpreproc_audrec_cmd_enc_cfg cmd;
+	memset(&cmd, 0, sizeof(cmd));
+	if (audio->build_id[17] == '1') {
+		cmd.cmd_id = AUDPREPROC_AUDREC_CMD_ENC_CFG_2;
+		MM_ERR("sending AUDPREPROC_AUDREC_CMD_ENC_CFG_2 command");
+	} else {
+		cmd.cmd_id = AUDPREPROC_AUDREC_CMD_ENC_CFG;
+		MM_ERR("sending AUDPREPROC_AUDREC_CMD_ENC_CFG command");
+	}
+	cmd.stream_id = audio->enc_id;
+
+	if (enable)
+		cmd.audrec_enc_type = audio->enc_type | ENCODE_ENABLE;
+	else
+		cmd.audrec_enc_type &= ~(ENCODE_ENABLE);
+
+	return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
+}
+
+static int audaac_in_param_config(struct audio_in *audio)
+{
+	struct audpreproc_audrec_cmd_parm_cfg_aac cmd;
+
+	MM_DBG("\n");
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPREPROC_AUDREC_CMD_PARAM_CFG;
+	cmd.common.stream_id = audio->enc_id;
+
+	cmd.aud_rec_samplerate_idx = audio->samp_rate;
+	cmd.aud_rec_stereo_mode = audio->channel_mode;
+	cmd.recording_quality = audio->record_quality;
+
+	return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
+}
+
+/* To Do: msm_snddev_route_enc(audio->enc_id); */
+static int audaac_in_record_config(struct audio_in *audio, int enable)
+{
+	struct audpreproc_afe_cmd_audio_record_cfg cmd;
+	MM_DBG("\n");
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG;
+	cmd.stream_id = audio->enc_id;
+	if (enable)
+		cmd.destination_activity = AUDIO_RECORDING_TURN_ON;
+	else
+		cmd.destination_activity = AUDIO_RECORDING_TURN_OFF;
+
+	cmd.source_mix_mask = audio->source;
+	if (audio->enc_id == 2) {
+		if ((cmd.source_mix_mask & INTERNAL_CODEC_TX_SOURCE_MIX_MASK) ||
+			(cmd.source_mix_mask & AUX_CODEC_TX_SOURCE_MIX_MASK) ||
+			(cmd.source_mix_mask & VOICE_UL_SOURCE_MIX_MASK) ||
+			(cmd.source_mix_mask & VOICE_DL_SOURCE_MIX_MASK)) {
+			cmd.pipe_id = SOURCE_PIPE_1;
+		}
+		if (cmd.source_mix_mask &
+				AUDPP_A2DP_PIPE_SOURCE_MIX_MASK)
+			cmd.pipe_id |= SOURCE_PIPE_0;
+	}
+	return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
+}
+
+static int audaac_in_mem_config(struct audio_in *audio)
+{
+	struct audrec_cmd_arecmem_cfg cmd;
+	uint16_t *data = (void *) audio->data;
+	int n;
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_MEM_CFG_CMD;
+	cmd.audrec_up_pkt_intm_count = 1;
+	cmd.audrec_ext_pkt_start_addr_msw = audio->phys >> 16;
+	cmd.audrec_ext_pkt_start_addr_lsw = audio->phys;
+	cmd.audrec_ext_pkt_buf_number = FRAME_NUM;
+	MM_DBG("audio->phys = %x\n", audio->phys);
+	/* prepare buffer pointers:
+	 * 1536 bytes aac packet + 4 halfword header
+	 */
+	for (n = 0; n < FRAME_NUM; n++) {
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+			audio->in[n].data = data + 4;
+			data += (FRAME_SIZE/2);
+			MM_DBG("0x%8x\n", (int)(audio->in[n].data - 8));
+		} else  {
+			audio->in[n].data = data + 12;
+			data += ((AAC_FRAME_SIZE) / 2) + 12;
+			MM_DBG("0x%8x\n", (int)(audio->in[n].data - 24));
+		}
+	}
+	return audrec_send_audrecqueue(audio, &cmd, sizeof(cmd));
+}
+
+static int audaac_dsp_read_buffer(struct audio_in *audio, uint32_t read_cnt)
+{
+	struct up_audrec_packet_ext_ptr cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = UP_AUDREC_PACKET_EXT_PTR;
+	cmd.audrec_up_curr_read_count_msw = read_cnt >> 16;
+	cmd.audrec_up_curr_read_count_lsw = read_cnt;
+
+	return audrec_send_bitstreamqueue(audio, &cmd, sizeof(cmd));
+}
+static int audaac_flush_command(struct audio_in *audio)
+{
+	struct audrec_cmd_flush cmd;
+	MM_DBG("\n");
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_FLUSH;
+	return audrec_send_audrecqueue(audio, &cmd, sizeof(cmd));
+}
+
+/* must be called with audio->lock held */
+static int audaac_in_enable(struct audio_in *audio)
+{
+	if (audio->enabled)
+		return 0;
+
+	if (audpreproc_enable(audio->enc_id, &audpreproc_dsp_event, audio)) {
+		MM_ERR("msm_adsp_enable(audpreproc) failed\n");
+		return -ENODEV;
+	}
+
+	if (msm_adsp_enable(audio->audrec)) {
+		MM_ERR("msm_adsp_enable(audrec) failed\n");
+		audpreproc_disable(audio->enc_id, audio);
+		return -ENODEV;
+	}
+	audio->enabled = 1;
+	audaac_in_enc_config(audio, 1);
+
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audaac_in_disable(struct audio_in *audio)
+{
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audaac_in_enc_config(audio, 0);
+		wake_up(&audio->wait);
+		wait_event_interruptible_timeout(audio->wait_enable,
+				audio->running == 0, 1*HZ);
+		msm_adsp_disable(audio->audrec);
+		audpreproc_disable(audio->enc_id, audio);
+	}
+	return 0;
+}
+
+static void audaac_ioport_reset(struct audio_in *audio)
+{
+	/* Make sure read/write thread are free from
+	 * sleep and knowing that system is not able
+	 * to process io request at the moment
+	 */
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audaac_in_flush(audio);
+	mutex_unlock(&audio->write_lock);
+	wake_up(&audio->wait);
+	mutex_lock(&audio->read_lock);
+	audaac_out_flush(audio);
+	mutex_unlock(&audio->read_lock);
+}
+
+static void audaac_in_flush(struct audio_in *audio)
+{
+	int i;
+
+	audio->dsp_cnt = 0;
+	audio->in_head = 0;
+	audio->in_tail = 0;
+	audio->in_count = 0;
+	audio->eos_ack = 0;
+	for (i = 0; i < FRAME_NUM; i++) {
+		audio->in[i].size = 0;
+		audio->in[i].read = 0;
+	}
+	MM_DBG("in_bytes %d\n", atomic_read(&audio->in_bytes));
+	MM_DBG("in_samples %d\n", atomic_read(&audio->in_samples));
+	atomic_set(&audio->in_bytes, 0);
+	atomic_set(&audio->in_samples, 0);
+}
+
+static void audaac_out_flush(struct audio_in *audio)
+{
+	int i;
+
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->out_count = 0;
+	for (i = 0; i < OUT_FRAME_NUM; i++) {
+		audio->out[i].size = 0;
+		audio->out[i].read = 0;
+		audio->out[i].used = 0;
+	}
+}
+
+/* ------------------- device --------------------- */
+static long audaac_in_ioctl(struct file *file,
+				unsigned int cmd, unsigned long arg)
+{
+	struct audio_in *audio = file->private_data;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = atomic_read(&audio->in_bytes);
+		stats.sample_count = atomic_read(&audio->in_samples);
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return rc;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START: {
+		uint32_t freq;
+		/* Poll at 48KHz always */
+		freq = 48000;
+		MM_DBG("AUDIO_START\n");
+		rc = msm_snddev_request_freq(&freq, audio->enc_id,
+					SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
+		MM_DBG("sample rate configured %d sample rate requested %d\n",
+				freq, audio->samp_rate);
+		if (rc < 0) {
+			MM_DBG(" Sample rate can not be set, return code %d\n",
+								 rc);
+			msm_snddev_withdraw_freq(audio->enc_id,
+					SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
+			MM_DBG("msm_snddev_withdraw_freq\n");
+			break;
+		}
+		/*update aurec session info in audpreproc layer*/
+		audio->session_info.session_id = audio->enc_id;
+		audio->session_info.sampling_freq = audio->samp_rate;
+		audpreproc_update_audrec_info(&audio->session_info);
+		rc = audaac_in_enable(audio);
+		if (!rc) {
+			rc =
+			wait_event_interruptible_timeout(audio->wait_enable,
+				audio->running != 0, 1*HZ);
+			MM_DBG("state %d rc = %d\n", audio->running, rc);
+
+			if (audio->running == 0)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		audio->stopped = 0;
+		break;
+	}
+	case AUDIO_STOP: {
+		audio->session_info.sampling_freq = 0;
+		audpreproc_update_audrec_info(&audio->session_info);
+		rc = audaac_in_disable(audio);
+		rc = msm_snddev_withdraw_freq(audio->enc_id,
+					SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
+		MM_DBG("msm_snddev_withdraw_freq\n");
+		audio->stopped = 1;
+		audio->abort = 0;
+		break;
+	}
+	case AUDIO_FLUSH:
+		MM_DBG("AUDIO_FLUSH\n");
+		audio->rflush = 1;
+		audio->wflush = 1;
+		audaac_ioport_reset(audio);
+		if (audio->running) {
+			audaac_flush_command(audio);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		break;
+	case AUDIO_GET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		memset(&cfg, 0, sizeof(cfg));
+		cfg.buffer_size = audio->buffer_size;
+		cfg.buffer_count = FRAME_NUM;
+		if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		/* Allow only single frame */
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+			if (cfg.buffer_size != (FRAME_SIZE - 8)) {
+				rc = -EINVAL;
+				break;
+			}
+		} else {
+			if (cfg.buffer_size != (NT_FRAME_SIZE - 24)) {
+				rc = -EINVAL;
+				break;
+			}
+		}
+		audio->buffer_size = cfg.buffer_size;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_pcm_config cfg;
+		memset(&cfg, 0, sizeof(cfg));
+		cfg.buffer_size = OUT_BUFFER_SIZE;
+		cfg.buffer_count = OUT_FRAME_NUM;
+		if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_GET_AAC_ENC_CONFIG: {
+		struct msm_audio_aac_enc_config cfg;
+		if (audio->channel_mode == AUDREC_CMD_MODE_MONO)
+			cfg.channels = 1;
+		else
+			cfg.channels = 2;
+		cfg.sample_rate = audio->samp_rate;
+		cfg.bit_rate = audio->bit_rate;
+		cfg.stream_format = AUDIO_AAC_FORMAT_RAW;
+		if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_AAC_ENC_CONFIG: {
+		struct msm_audio_aac_enc_config cfg;
+		unsigned int record_quality;
+		if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (cfg.stream_format != AUDIO_AAC_FORMAT_RAW) {
+			MM_ERR("unsupported AAC format\n");
+			rc = -EINVAL;
+			break;
+		}
+		record_quality = bitrate_to_record_quality(cfg.sample_rate,
+					cfg.channels, cfg.bit_rate);
+		/* Range of Record Quality Supported by DSP, Q12 format */
+		if ((record_quality < 0x800) || (record_quality > 0x4000)) {
+			MM_ERR("Unsupported bit rate \n");
+			rc = -EINVAL;
+			break;
+		}
+		MM_DBG("channels = %d\n", cfg.channels);
+		if (cfg.channels == 1) {
+			cfg.channels = AUDREC_CMD_MODE_MONO;
+		} else if (cfg.channels == 2) {
+			cfg.channels = AUDREC_CMD_MODE_STEREO;
+		} else {
+			rc = -EINVAL;
+			break;
+		}
+		MM_DBG("channels = %d\n", cfg.channels);
+		audio->samp_rate = cfg.sample_rate;
+		audio->channel_mode = cfg.channels;
+		audio->bit_rate = cfg.bit_rate;
+		audio->record_quality = record_quality;
+		MM_DBG(" Record Quality = 0x%8x \n", audio->record_quality);
+		break;
+	}
+	case AUDIO_GET_SESSION_ID: {
+		if (copy_to_user((void *) arg, &audio->enc_id,
+			sizeof(unsigned short))) {
+			rc = -EFAULT;
+		}
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static ssize_t audaac_in_read(struct file *file,
+				char __user *buf,
+				size_t count, loff_t *pos)
+{
+	struct audio_in *audio = file->private_data;
+	unsigned long flags;
+	const char __user *start = buf;
+	void *data;
+	uint32_t index;
+	uint32_t size;
+	int rc = 0;
+	struct aac_encoded_meta_in meta_field;
+	struct audio_frame_nt *nt_frame;
+	MM_DBG(" count = %d\n", count);
+	mutex_lock(&audio->read_lock);
+	while (count > 0) {
+		rc = wait_event_interruptible(
+			audio->wait, (audio->in_count > 0) || audio->stopped ||
+				audio->abort || audio->rflush);
+
+		if (rc < 0)
+			break;
+
+		if (audio->rflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (audio->stopped && !audio->in_count) {
+			MM_DBG("Driver in stop state, No more buffer to read");
+			rc = 0;/* End of File */
+			break;
+		}
+
+		if (audio->abort) {
+			rc = -EPERM; /* Not permitted due to abort */
+			break;
+		}
+
+		index = audio->in_tail;
+		data = (uint8_t *) audio->in[index].data;
+		size = audio->in[index].size;
+
+		if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
+			nt_frame = (struct audio_frame_nt *)(data -
+					sizeof(struct audio_frame_nt));
+			memcpy((char *)&meta_field.time_stamp_dword_lsw,
+				(char *)&nt_frame->time_stamp_dword_lsw, 12);
+			meta_field.metadata_len =
+					sizeof(struct aac_encoded_meta_in);
+			if (copy_to_user((char *)start, (char *)&meta_field,
+					sizeof(struct aac_encoded_meta_in))) {
+				rc = -EFAULT;
+				break;
+			}
+			if (nt_frame->nflag_lsw & 0x0001) {
+				MM_ERR("recieved EOS in read call\n");
+				audio->eos_ack = 1;
+			}
+			buf += sizeof(struct aac_encoded_meta_in);
+			count -= sizeof(struct aac_encoded_meta_in);
+		}
+		if (count >= size) {
+			if (copy_to_user(buf, data, size)) {
+				rc = -EFAULT;
+				break;
+			}
+			spin_lock_irqsave(&audio->dsp_lock, flags);
+			if (index != audio->in_tail) {
+				/* overrun -- data is
+				 * invalid and we need to retry */
+				spin_unlock_irqrestore(&audio->dsp_lock, flags);
+				continue;
+			}
+			audio->in[index].size = 0;
+			audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
+			audio->in_count--;
+			spin_unlock_irqrestore(&audio->dsp_lock, flags);
+			count -= size;
+			buf += size;
+			if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) &&
+						(!audio->eos_ack)) {
+				MM_DBG("sending read ptr command %d %d\n",
+							audio->dsp_cnt,
+							audio->in_tail);
+				audaac_dsp_read_buffer(audio,
+							audio->dsp_cnt++);
+				break;
+			}
+		} else {
+			MM_ERR("short read\n");
+			break;
+		}
+		break;
+	}
+	mutex_unlock(&audio->read_lock);
+	if (buf > start)
+		return buf - start;
+
+	return rc;
+}
+
+static void audpreproc_pcm_send_data(struct audio_in *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+	MM_DBG("\n");
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (needed && !audio->wflush) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			MM_DBG("frame %d free\n", audio->out_tail);
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+			MM_DBG("frame %d busy\n", audio->out_tail);
+			audpreproc_pcm_buffer_ptr_refresh(audio,
+						 audio->out_tail,
+						    frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+ done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+
+static int audaac_in_fsync(struct file *file, loff_t ppos1, loff_t ppos2, int datasync)
+
+{
+	struct audio_in *audio = file->private_data;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (!audio->running || (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)) {
+		rc = -EINVAL;
+		goto done_nolock;
+	}
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->write_wait,
+			audio->wflush);
+	MM_DBG("waked on by some event audio->wflush = %d\n", audio->wflush);
+
+	if (rc < 0)
+		goto done;
+	else if (audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+done:
+	mutex_unlock(&audio->write_lock);
+done_nolock:
+	return rc;
+
+}
+
+ int audpreproc_aac_process_eos(struct audio_in *audio,
+		const char __user *buf_start, unsigned short mfield_size)
+{
+	struct buffer *frame;
+	int rc = 0;
+
+	frame = audio->out + audio->out_head;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->out_needed &&
+		audio->out[0].used == 0 &&
+		audio->out[1].used == 0)
+		|| (audio->stopped)
+		|| (audio->wflush));
+
+	if (rc < 0)
+		goto done;
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+	if (copy_from_user(frame->data, buf_start, mfield_size)) {
+		rc = -EFAULT;
+		goto done;
+	}
+
+	frame->mfield_sz = mfield_size;
+	audio->out_head ^= 1;
+	frame->used = mfield_size;
+	MM_DBG("copying meta_out frame->used = %d\n", frame->used);
+	audpreproc_pcm_send_data(audio, 0);
+done:
+	return rc;
+}
+
+static ssize_t audaac_in_write(struct file *file,
+				const char __user *buf,
+				size_t count, loff_t *pos)
+{
+	struct audio_in *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	char *cpy_ptr;
+	int rc = 0, eos_condition = AUDPREPROC_AAC_EOS_NONE;
+	unsigned short mfield_size = 0;
+	int write_count = count;
+	MM_DBG("cnt=%d\n", count);
+
+	if (count & 1)
+		return -EINVAL;
+
+	mutex_lock(&audio->write_lock);
+	frame = audio->out + audio->out_head;
+	cpy_ptr = frame->data;
+	rc = wait_event_interruptible(audio->write_wait,
+				      (frame->used == 0)
+					|| (audio->stopped)
+					|| (audio->wflush));
+	if (rc < 0)
+		goto error;
+
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto error;
+	}
+	if (audio->mfield) {
+		if (buf == start) {
+			/* Processing beginning of user buffer */
+			if (__get_user(mfield_size,
+				(unsigned short __user *) buf)) {
+				rc = -EFAULT;
+				goto error;
+			} else if (mfield_size > count) {
+				rc = -EINVAL;
+				goto error;
+			}
+			MM_DBG("mf offset_val %x\n", mfield_size);
+			if (copy_from_user(cpy_ptr, buf, mfield_size)) {
+				rc = -EFAULT;
+				goto error;
+			}
+			/* Check if EOS flag is set and buffer has
+			 * contains just meta field
+			 */
+			if (cpy_ptr[AUDPREPROC_AAC_EOS_FLG_OFFSET] &
+					AUDPREPROC_AAC_EOS_FLG_MASK) {
+				MM_DBG("EOS SET\n");
+				eos_condition = AUDPREPROC_AAC_EOS_SET;
+				if (mfield_size == count) {
+					buf += mfield_size;
+					if (audio->mode ==
+						MSM_AUD_ENC_MODE_NONTUNNEL) {
+						eos_condition = 0;
+						goto exit;
+					}
+					goto error;
+				} else
+				cpy_ptr[AUDPREPROC_AAC_EOS_FLG_OFFSET] &=
+					~AUDPREPROC_AAC_EOS_FLG_MASK;
+			}
+			cpy_ptr += mfield_size;
+			count -= mfield_size;
+			buf += mfield_size;
+		} else {
+			mfield_size = 0;
+			MM_DBG("continuous buffer\n");
+		}
+		frame->mfield_sz = mfield_size;
+	}
+	MM_DBG("copying the stream count = %d\n", count);
+	if (copy_from_user(cpy_ptr, buf, count)) {
+		rc = -EFAULT;
+		goto error;
+	}
+exit:
+	frame->used = count;
+	audio->out_head ^= 1;
+	if (!audio->flush_ack)
+		audpreproc_pcm_send_data(audio, 0);
+	else {
+		audpreproc_pcm_send_data(audio, 1);
+		audio->flush_ack = 0;
+	}
+	if (eos_condition == AUDPREPROC_AAC_EOS_SET)
+		rc = audpreproc_aac_process_eos(audio, start, mfield_size);
+	mutex_unlock(&audio->write_lock);
+	return write_count;
+error:
+	mutex_unlock(&audio->write_lock);
+	return rc;
+}
+
+static int audaac_in_release(struct inode *inode, struct file *file)
+{
+	struct audio_in *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	/* with draw frequency for session
+	   incase not stopped the driver */
+	msm_snddev_withdraw_freq(audio->enc_id, SNDDEV_CAP_TX,
+					AUDDEV_CLNT_ENC);
+	auddev_unregister_evt_listner(AUDDEV_CLNT_ENC, audio->enc_id);
+	/*reset the sampling frequency information at audpreproc layer*/
+	audio->session_info.sampling_freq = 0;
+	audpreproc_update_audrec_info(&audio->session_info);
+	audaac_in_disable(audio);
+	audaac_in_flush(audio);
+	msm_adsp_put(audio->audrec);
+	audpreproc_aenc_free(audio->enc_id);
+	audio->audrec = NULL;
+	audio->opened = 0;
+	if (audio->data) {
+		iounmap(audio->map_v_read);
+		free_contiguous_memory_by_paddr(audio->phys);
+		audio->data = NULL;
+	}
+	if (audio->out_data) {
+		iounmap(audio->map_v_write);
+		free_contiguous_memory_by_paddr(audio->out_phys);
+		audio->out_data = NULL;
+	}
+	mutex_unlock(&audio->lock);
+	return 0;
+}
+
+struct audio_in the_audio_aac_in;
+
+static int audaac_in_open(struct inode *inode, struct file *file)
+{
+	struct audio_in *audio = &the_audio_aac_in;
+	int rc;
+	int encid;
+
+	mutex_lock(&audio->lock);
+	if (audio->opened) {
+		rc = -EBUSY;
+		goto done;
+	}
+	audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
+	if (audio->phys) {
+		audio->map_v_read = ioremap(audio->phys, DMASZ);
+		if (IS_ERR(audio->map_v_read)) {
+			MM_ERR("could not map DMA buffers\n");
+			rc = -ENOMEM;
+			free_contiguous_memory_by_paddr(audio->phys);
+			goto done;
+		}
+		audio->data = audio->map_v_read;
+	} else {
+		MM_ERR("could not allocate DMA buffers\n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	MM_DBG("Memory addr = 0x%8x  phy addr = 0x%8x\n",\
+		(int) audio->data, (int) audio->phys);
+	if ((file->f_mode & FMODE_WRITE) &&
+				(file->f_mode & FMODE_READ)) {
+		audio->mode = MSM_AUD_ENC_MODE_NONTUNNEL;
+	} else if (!(file->f_mode & FMODE_WRITE) &&
+					(file->f_mode & FMODE_READ)) {
+		audio->mode = MSM_AUD_ENC_MODE_TUNNEL;
+		MM_DBG("Opened for tunnel mode encoding\n");
+	} else {
+		rc = -EACCES;
+		goto done;
+	}
+
+	/* Settings will be re-config at AUDIO_SET_CONFIG,
+	 * but at least we need to have initial config
+	 */
+	 if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)
+			audio->buffer_size = (NT_FRAME_SIZE - 24);
+	else
+			audio->buffer_size = (FRAME_SIZE - 8);
+	audio->enc_type = ENC_TYPE_AAC | audio->mode;
+	audio->samp_rate = 8000;
+	audio->channel_mode = AUDREC_CMD_MODE_MONO;
+	/* For AAC, bit rate hard coded, default settings is
+	 * sample rate (8000) x channel count (1) x recording quality (1.75)
+	 * = 14000 bps  */
+	audio->bit_rate = 14000;
+	audio->record_quality = 0x1c00;
+	MM_DBG("enc_type = %x\n", audio->enc_type);
+	encid = audpreproc_aenc_alloc(audio->enc_type, &audio->module_name,
+			&audio->queue_ids);
+	if (encid < 0) {
+		MM_ERR("No free encoder available\n");
+		rc = -ENODEV;
+		goto done;
+	}
+	audio->enc_id = encid;
+
+	rc = msm_adsp_get(audio->module_name, &audio->audrec,
+			   &audrec_aac_adsp_ops, audio);
+
+	if (rc) {
+		audpreproc_aenc_free(audio->enc_id);
+		goto done;
+	}
+
+	audio->stopped = 0;
+	audio->source = 0;
+	audio->abort = 0;
+	audio->wflush = 0;
+	audio->rflush = 0;
+	audio->flush_ack = 0;
+
+	audaac_in_flush(audio);
+	audaac_out_flush(audio);
+
+	audio->out_phys = allocate_contiguous_ebi_nomap(BUFFER_SIZE, SZ_4K);
+	if (!audio->out_phys) {
+		MM_ERR("could not allocate write buffers\n");
+		rc = -ENOMEM;
+		goto evt_error;
+	} else {
+		audio->map_v_write = ioremap(
+					audio->out_phys, BUFFER_SIZE);
+		if (IS_ERR(audio->map_v_write)) {
+			MM_ERR("could not map write phys address\n");
+			rc = -ENOMEM;
+			free_contiguous_memory_by_paddr(audio->out_phys);
+			goto evt_error;
+		}
+		audio->out_data = audio->map_v_write;
+		MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+				audio->out_phys, (int)audio->out_data);
+	}
+	audio->build_id = socinfo_get_build_id();
+	MM_DBG("Modem build id = %s\n", audio->build_id);
+
+		/* Initialize buffer */
+	audio->out[0].data = audio->out_data + 0;
+	audio->out[0].addr = audio->out_phys + 0;
+	audio->out[0].size = OUT_BUFFER_SIZE;
+
+	audio->out[1].data = audio->out_data + OUT_BUFFER_SIZE;
+	audio->out[1].addr = audio->out_phys + OUT_BUFFER_SIZE;
+	audio->out[1].size = OUT_BUFFER_SIZE;
+
+	MM_DBG("audio->out[0].data = %d  audio->out[1].data = %d",
+					(unsigned int)audio->out[0].data,
+					(unsigned int)audio->out[1].data);
+	audio->device_events = AUDDEV_EVT_DEV_RDY | AUDDEV_EVT_DEV_RLS |
+				AUDDEV_EVT_FREQ_CHG;
+
+	rc = auddev_register_evt_listner(audio->device_events,
+					AUDDEV_CLNT_ENC, audio->enc_id,
+					aac_in_listener, (void *) audio);
+	if (rc) {
+		MM_ERR("failed to register device event listener\n");
+		iounmap(audio->map_v_write);
+		free_contiguous_memory_by_paddr(audio->out_phys);
+		goto evt_error;
+	}
+	audio->mfield = META_OUT_SIZE;
+	file->private_data = audio;
+	audio->opened = 1;
+	audio->out_frame_cnt++;
+	rc = 0;
+done:
+	mutex_unlock(&audio->lock);
+	return rc;
+evt_error:
+	msm_adsp_put(audio->audrec);
+	audpreproc_aenc_free(audio->enc_id);
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static const struct file_operations audio_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audaac_in_open,
+	.release	= audaac_in_release,
+	.read		= audaac_in_read,
+	.write		= audaac_in_write,
+	.fsync		= audaac_in_fsync,
+	.unlocked_ioctl	= audaac_in_ioctl,
+};
+
+struct miscdevice audio_aac_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_aac_in",
+	.fops	= &audio_in_fops,
+};
+
+static int __init audaac_in_init(void)
+{
+	mutex_init(&the_audio_aac_in.lock);
+	mutex_init(&the_audio_aac_in.read_lock);
+	spin_lock_init(&the_audio_aac_in.dsp_lock);
+	spin_lock_init(&the_audio_aac_in.dev_lock);
+	init_waitqueue_head(&the_audio_aac_in.wait);
+	init_waitqueue_head(&the_audio_aac_in.wait_enable);
+	mutex_init(&the_audio_aac_in.write_lock);
+	init_waitqueue_head(&the_audio_aac_in.write_wait);
+
+	return misc_register(&audio_aac_in_misc);
+}
+
+device_initcall(audaac_in_init);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_acdb.c b/arch/arm/mach-msm/qdsp5v2/audio_acdb.c
new file mode 100644
index 0000000..89957a4
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/audio_acdb.c
@@ -0,0 +1,3448 @@
+/* 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
+ * 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/module.h>
+#include <linux/miscdevice.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/android_pmem.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/uaccess.h>
+#include <linux/msm_audio.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/memory_alloc.h>
+#include <linux/mfd/marimba.h>
+#include <mach/dal.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/qdsp5v2/audpp.h>
+#include <mach/socinfo.h>
+#include <mach/qdsp5v2/audpreproc.h>
+#include <mach/qdsp5v2/qdsp5audppcmdi.h>
+#include <mach/qdsp5v2/qdsp5audpreproccmdi.h>
+#include <mach/qdsp5v2/qdsp5audpreprocmsg.h>
+#include <mach/qdsp5v2/qdsp5audppmsg.h>
+#include <mach/qdsp5v2/afe.h>
+#include <mach/qdsp5v2/audio_acdbi.h>
+#include <mach/qdsp5v2/acdb_commands.h>
+#include <mach/qdsp5v2/audio_acdb_def.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_memtypes.h>
+
+/* this is the ACDB device ID */
+#define DALDEVICEID_ACDB		0x02000069
+#define ACDB_PORT_NAME			"DAL00"
+#define ACDB_CPU			SMD_APPS_MODEM
+#define ACDB_BUF_SIZE			4096
+#define PBE_BUF_SIZE                    (33*1024)
+#define FLUENCE_BUF_SIZE	498
+
+#define ACDB_VALUES_NOT_FILLED		0
+#define ACDB_VALUES_FILLED		1
+#define MAX_RETRY			10
+
+/*below macro is used to align the session info received from
+Devctl driver with the state mentioned as not to alter the
+Existing code*/
+#define AUDREC_OFFSET	2
+/* rpc table index */
+enum {
+	ACDB_DalACDB_ioctl = DALDEVICE_FIRST_DEVICE_API_IDX
+};
+
+enum {
+	CAL_DATA_READY	= 0x1,
+	AUDPP_READY	= 0x2,
+	AUDREC0_READY	= 0x4,
+	AUDREC1_READY	= 0x8,
+	AUDREC2_READY	= 0x10,
+};
+
+
+struct acdb_data {
+	void *handle;
+
+	u32 phys_addr;
+	u8 *virt_addr;
+
+	struct task_struct *cb_thread_task;
+	struct auddev_evt_audcal_info *device_info;
+
+	u32 acdb_state;
+	struct audpp_event_callback audpp_cb;
+	struct audpreproc_event_callback audpreproc_cb;
+
+	struct audpp_cmd_cfg_object_params_pcm *pp_iir;
+	struct audpp_cmd_cfg_cal_gain *calib_gain_rx;
+	struct audpp_cmd_cfg_pbe *pbe_block;
+	struct audpp_cmd_cfg_object_params_mbadrc *pp_mbadrc;
+	struct audpreproc_cmd_cfg_agc_params *preproc_agc;
+	struct audpreproc_cmd_cfg_iir_tuning_filter_params *preproc_iir;
+	struct audpreproc_cmd_cfg_cal_gain *calib_gain_tx;
+	struct acdb_mbadrc_block mbadrc_block;
+	struct audpreproc_cmd_cfg_lvnv_param preproc_lvnv;
+
+	wait_queue_head_t wait;
+	struct mutex acdb_mutex;
+	u32 device_cb_compl;
+	u32 audpp_cb_compl;
+	u32 preproc_cb_compl;
+	u8 preproc_stream_id;
+	u8 audrec_applied;
+	u32 multiple_sessions;
+	u32 cur_tx_session;
+	struct acdb_result acdb_result;
+	u16 *pbe_extbuff;
+	u16 *pbe_enable_flag;
+	u32 fluence_extbuff;
+	u8 *fluence_extbuff_virt;
+	void *map_v_fluence;
+
+	struct acdb_pbe_block *pbe_blk;
+
+	spinlock_t dsp_lock;
+	int dec_id;
+	struct audpp_cmd_cfg_object_params_eqalizer eq;
+	 /*status to enable or disable the fluence*/
+	int fleuce_feature_status[MAX_AUDREC_SESSIONS];
+	struct audrec_session_info session_info;
+	/*pmem info*/
+	int pmem_fd;
+	unsigned long paddr;
+	unsigned long kvaddr;
+	unsigned long pmem_len;
+	struct file *file;
+	/* pmem for get acdb blk */
+	unsigned long	get_blk_paddr;
+	u8		*get_blk_kvaddr;
+	void *map_v_get_blk;
+	char *build_id;
+};
+
+static struct acdb_data		acdb_data;
+
+struct acdb_cache_node {
+	u32 node_status;
+	s32 stream_id;
+	u32 phys_addr_acdb_values;
+	void *map_v_addr;
+	u8 *virt_addr_acdb_values;
+	struct auddev_evt_audcal_info device_info;
+};
+
+/*for RX devices  acdb values are applied based on copp ID so
+the depth of tx cache is MAX number of COPP supported in the system*/
+struct acdb_cache_node acdb_cache_rx[MAX_COPP_NODE_SUPPORTED];
+
+/*for TX devices acdb values are applied based on AUDREC session and
+the depth of the tx cache is define by number of AUDREC sessions supported*/
+struct acdb_cache_node acdb_cache_tx[MAX_AUDREC_SESSIONS];
+
+/*Audrec session info includes Attributes Sampling frequency and enc_id */
+struct audrec_session_info session_info[MAX_AUDREC_SESSIONS];
+#ifdef CONFIG_DEBUG_FS
+
+#define RTC_MAX_TIMEOUT 500 /* 500 ms */
+#define PMEM_RTC_ACDB_QUERY_MEM 4096
+#define EXTRACT_HIGH_WORD(x) ((x & 0xFFFF0000)>>16)
+#define EXTRACT_LOW_WORD(x) (0x0000FFFF & x)
+#define	ACDB_RTC_TX 0xF1
+#define	ACDB_RTC_RX 0x1F
+
+
+static u32 acdb_audpp_entry[][4] = {
+
+  { ABID_AUDIO_RTC_VOLUME_PAN_RX,\
+    IID_AUDIO_RTC_VOLUME_PAN_PARAMETERS,\
+    AUDPP_CMD_VOLUME_PAN,\
+    ACDB_RTC_RX
+   },
+  { ABID_AUDIO_IIR_RX,\
+     IID_AUDIO_IIR_COEFF,\
+     AUDPP_CMD_IIR_TUNING_FILTER,
+     ACDB_RTC_RX
+   },
+  { ABID_AUDIO_RTC_EQUALIZER_PARAMETERS,\
+     IID_AUDIO_RTC_EQUALIZER_PARAMETERS,\
+     AUDPP_CMD_EQUALIZER,\
+     ACDB_RTC_RX
+   },
+  { ABID_AUDIO_RTC_SPA,\
+     IID_AUDIO_RTC_SPA_PARAMETERS,\
+     AUDPP_CMD_SPECTROGRAM,
+     ACDB_RTC_RX
+   },
+  { ABID_AUDIO_STF_RX,\
+     IID_AUDIO_IIR_COEFF,\
+     AUDPP_CMD_SIDECHAIN_TUNING_FILTER,\
+     ACDB_RTC_RX
+  },
+  {
+     ABID_AUDIO_MBADRC_RX,\
+     IID_AUDIO_RTC_MBADRC_PARAMETERS,\
+     AUDPP_CMD_MBADRC,\
+     ACDB_RTC_RX
+  },
+  {
+    ABID_AUDIO_AGC_TX,\
+    IID_AUDIO_AGC_PARAMETERS,\
+    AUDPREPROC_CMD_CFG_AGC_PARAMS,\
+    ACDB_RTC_TX
+  },
+  {
+    ABID_AUDIO_AGC_TX,\
+    IID_AUDIO_RTC_AGC_PARAMETERS,\
+    AUDPREPROC_CMD_CFG_AGC_PARAMS,\
+    ACDB_RTC_TX
+  },
+  {
+    ABID_AUDIO_NS_TX,\
+    IID_NS_PARAMETERS,\
+    AUDPREPROC_CMD_CFG_NS_PARAMS,\
+    ACDB_RTC_TX
+  },
+  {
+     ABID_AUDIO_IIR_TX,\
+     IID_AUDIO_RTC_TX_IIR_COEFF,\
+     AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS,\
+     ACDB_RTC_TX
+  },
+  {
+     ABID_AUDIO_IIR_TX,\
+     IID_AUDIO_IIR_COEFF,\
+     AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS,\
+     ACDB_RTC_TX
+  }
+ /*Any new entries should be added here*/
+};
+
+static struct dentry *get_set_abid_dentry;
+static struct dentry *get_set_abid_data_dentry;
+
+struct rtc_acdb_pmem {
+	u8 *viraddr;
+	int32_t phys;
+	void *map_v_rtc;
+};
+
+struct rtc_acdb_data {
+	u32 acdb_id;
+	u32 cmd_id;
+	u32 set_abid;
+	u32 set_iid;
+	u32 abid;
+	u32 err;
+	bool valid_abid;
+	u32 tx_rx_ctl;
+	struct rtc_acdb_pmem rtc_read;
+	struct rtc_acdb_pmem rtc_write;
+	wait_queue_head_t  wait;
+};
+
+struct get_abid {
+	u32	cmd_id;
+	u32	acdb_id;
+	u32	set_abid;
+	u32	set_iid;
+};
+
+struct acdb_block_mbadrc_rtc {
+	u16 enable;
+	u16 num_bands;
+	u16 down_samp_level;
+	u16 adrc_delay;
+	u16 ext_buf_size;
+	u16 ext_partition;
+	u16 ext_buf_msw;
+	u16 ext_buf_lsw;
+	struct adrc_config adrc_band[AUDPP_MAX_MBADRC_BANDS];
+	signed int ExtBuff[196];
+} __attribute__((packed));
+
+enum {
+	ACDB_RTC_SUCCESS,
+	ACDB_RTC_ERR_INVALID_DEVICE,
+	ACDB_RTC_ERR_DEVICE_INACTIVE,
+	ACDB_RTC_ERR_INVALID_ABID,
+	ACDB_RTC_DSP_FAILURE,
+	ACDB_RTC_DSP_FEATURE_NOT_AVAILABLE,
+	ACDB_RTC_ERR_INVALID_LEN,
+	ACDB_RTC_ERR_UNKNOWN_FAILURE,
+	ACDB_RTC_PENDING_RESPONSE,
+	ACDB_RTC_INIT_FAILURE,
+};
+
+static  struct rtc_acdb_data rtc_acdb;
+
+static int rtc_getsetabid_dbg_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	MM_INFO("GET-SET ABID Open debug intf %s\n",
+			(char *) file->private_data);
+	return 0;
+}
+
+static bool get_feature_id(u32 set_abid, u32 iid, unsigned short *feature_id)
+{
+	bool ret_value = false;
+	int i = 0;
+
+	for (; i < (sizeof(acdb_audpp_entry) / sizeof(acdb_audpp_entry[0]));\
+		i++) {
+		if (acdb_audpp_entry[i][0] == set_abid &&
+			acdb_audpp_entry[i][1] == iid) {
+			*feature_id =  acdb_audpp_entry[i][2];
+			rtc_acdb.tx_rx_ctl = acdb_audpp_entry[i][3];
+			ret_value = true;
+			break;
+		}
+	}
+	return ret_value;
+}
+static ssize_t rtc_getsetabid_dbg_write(struct file *filp,
+					const char __user *ubuf,
+					size_t cnt, loff_t *ppos)
+{
+	struct  get_abid write_abid;
+	unsigned short feat_id = 0;
+	rtc_acdb.valid_abid = false;
+
+	if (copy_from_user(&write_abid, \
+		(void *)ubuf, sizeof(struct get_abid))) {
+		MM_ERR("ACDB DATA WRITE - INVALID READ LEN\n");
+		rtc_acdb.err = ACDB_RTC_ERR_INVALID_LEN;
+		return cnt;
+	}
+	MM_INFO("SET ABID : Cmd ID: %d Device:%d ABID:%d IID : %d cnt: %d\n",\
+		write_abid.cmd_id, write_abid.acdb_id,
+		write_abid.set_abid, write_abid.set_iid, cnt);
+	if (write_abid.acdb_id > ACDB_ID_MAX ||
+		write_abid.acdb_id < ACDB_ID_HANDSET_SPKR){
+		rtc_acdb.err = ACDB_RTC_ERR_INVALID_DEVICE;
+		return cnt;
+	}
+	if (!is_dev_opened(write_abid.acdb_id))	{
+		rtc_acdb.err = ACDB_RTC_ERR_DEVICE_INACTIVE;
+		return cnt;
+	}
+	rtc_acdb.err = ACDB_RTC_ERR_INVALID_ABID;
+	rtc_acdb.abid = write_abid.set_abid;
+	if (get_feature_id(write_abid.set_abid, \
+		write_abid.set_iid, &feat_id)) {
+		rtc_acdb.err = ACDB_RTC_SUCCESS;
+		rtc_acdb.cmd_id = write_abid.cmd_id;
+		rtc_acdb.acdb_id = write_abid.acdb_id;
+		rtc_acdb.set_abid = feat_id;
+		rtc_acdb.valid_abid = true;
+		rtc_acdb.set_iid = write_abid.set_iid;
+	}
+	return cnt;
+}
+static ssize_t	rtc_getsetabid_dbg_read(struct file *file, char __user *buf,
+					size_t count, loff_t *ppos)
+{
+	static char buffer[1024];
+	int n = 0;
+	u32 msg = rtc_acdb.err;
+	memcpy(buffer, &rtc_acdb.cmd_id, sizeof(struct get_abid));
+	memcpy(buffer+16, &msg, 4);
+	n = 20;
+	MM_INFO("SET ABID : Cmd ID: %x Device:%x ABID:%x IID : %x Err: %d\n",\
+		rtc_acdb.cmd_id, rtc_acdb.acdb_id, rtc_acdb.set_abid,\
+		rtc_acdb.set_iid, rtc_acdb.err);
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static int rtc_getsetabid_data_dbg_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	MM_INFO("GET-SET ABID DATA Open debug intf %s\n",
+		(char *) file->private_data);
+	return 0;
+}
+
+void acdb_rtc_set_err(u32 ErrCode)
+{
+	if (rtc_acdb.err == ACDB_RTC_PENDING_RESPONSE) {
+		if (ErrCode == 0xFFFF) {
+			rtc_acdb.err = ACDB_RTC_SUCCESS;
+			MM_INFO("RTC READ SUCCESS---\n");
+		} else if (ErrCode == 0) {
+			rtc_acdb.err = ACDB_RTC_DSP_FAILURE;
+			MM_INFO("RTC READ FAIL---\n");
+		} else if (ErrCode == 1) {
+			rtc_acdb.err = ACDB_RTC_DSP_FEATURE_NOT_AVAILABLE;
+			MM_INFO("RTC READ FEAT UNAVAILABLE---\n");
+		} else {
+			rtc_acdb.err = ACDB_RTC_DSP_FAILURE;
+			MM_ERR("RTC Err CODE---\n");
+		}
+	} else {
+		rtc_acdb.err = ACDB_RTC_DSP_FAILURE;
+		MM_ERR("RTC Err code Invalid State\n");
+	}
+	wake_up(&rtc_acdb.wait);
+}
+static ssize_t	rtc_getsetabid_data_dbg_read(struct file *file,
+					char __user *buf, size_t count,
+					loff_t *ppos)
+{
+	static char buffer[PMEM_RTC_ACDB_QUERY_MEM];
+	int rc, n = 0;
+	int counter = 0;
+	struct rtc_acdb_pmem *rtc_read = &rtc_acdb.rtc_read;
+	memset(&buffer, 0, PMEM_RTC_ACDB_QUERY_MEM);
+
+	if (rtc_acdb.valid_abid != true) {
+		MM_ERR("ACDB DATA READ ---INVALID ABID\n");
+		n = 0;
+		rtc_acdb.err = ACDB_RTC_ERR_INVALID_ABID;
+	} else {
+		if (PMEM_RTC_ACDB_QUERY_MEM < count) {
+			MM_ERR("ACDB DATA READ ---\
+				INVALID READ LEN %x\n", count);
+			n = 0;
+			rtc_acdb.err = ACDB_RTC_ERR_INVALID_LEN;
+		} else {
+			rtc_acdb.err = ACDB_RTC_PENDING_RESPONSE;
+			if (rtc_read->viraddr != NULL) {
+				memset(rtc_read->viraddr,
+					0, PMEM_RTC_ACDB_QUERY_MEM);
+			}
+			if (rtc_acdb.tx_rx_ctl == ACDB_RTC_RX) {
+				struct rtc_audpp_read_data rtc_read_cmd;
+				rtc_read_cmd.cmd_id =
+					AUDPP_CMD_PP_FEAT_QUERY_PARAMS;
+				rtc_read_cmd.obj_id =
+					AUDPP_CMD_COPP_STREAM;
+				rtc_read_cmd.route_id =
+					acdb_data.device_info->dev_id;
+				rtc_read_cmd.feature_id = rtc_acdb.set_abid;
+				rtc_read_cmd.extbufsizemsw =
+					EXTRACT_HIGH_WORD(\
+						PMEM_RTC_ACDB_QUERY_MEM);
+				rtc_read_cmd.extbufsizelsw =
+					EXTRACT_LOW_WORD(\
+						PMEM_RTC_ACDB_QUERY_MEM);
+				rtc_read_cmd.extpart = 0x0000;
+				rtc_read_cmd.extbufstartmsw =
+					EXTRACT_HIGH_WORD(rtc_read->phys);
+				rtc_read_cmd.extbufstartlsw =
+					EXTRACT_LOW_WORD(rtc_read->phys);
+				rc = audpp_send_queue2(&rtc_read_cmd,
+						sizeof(rtc_read_cmd));
+				MM_INFO("ACDB READ Command RC --->%x\
+					Route ID=%x\n", rc,\
+					acdb_data.device_info->dev_id);
+			} else if (rtc_acdb.tx_rx_ctl == ACDB_RTC_TX) {
+				struct rtc_audpreproc_read_data rtc_audpreproc;
+				rtc_audpreproc.cmd_id =
+					AUDPREPROC_CMD_FEAT_QUERY_PARAMS;
+				rtc_audpreproc.stream_id =
+					acdb_data.preproc_stream_id;
+				rtc_audpreproc.feature_id = rtc_acdb.set_abid;
+				rtc_audpreproc.extbufsizemsw =
+					EXTRACT_HIGH_WORD(\
+						PMEM_RTC_ACDB_QUERY_MEM);
+				rtc_audpreproc.extbufsizelsw =
+					EXTRACT_LOW_WORD(\
+						PMEM_RTC_ACDB_QUERY_MEM);
+				rtc_audpreproc.extpart = 0x0000;
+				rtc_audpreproc.extbufstartmsw =
+					EXTRACT_HIGH_WORD(rtc_read->phys);
+				rtc_audpreproc.extbufstartlsw =
+					EXTRACT_LOW_WORD(rtc_read->phys);
+				rc =  audpreproc_send_preproccmdqueue(
+						&rtc_audpreproc,\
+						sizeof(rtc_audpreproc));
+				MM_INFO("ACDB READ Command RC --->%x,\
+					stream_id %x\n", rc,\
+					acdb_data.preproc_stream_id);
+			}
+		rc = wait_event_timeout(rtc_acdb.wait,
+					(rtc_acdb.err !=
+					ACDB_RTC_PENDING_RESPONSE),
+					msecs_to_jiffies(RTC_MAX_TIMEOUT));
+		MM_INFO("ACDB READ ACK Count = %x Err = %x\n",
+			count, rtc_acdb.err);
+		{
+			if (rtc_acdb.err == ACDB_RTC_SUCCESS
+				&& rtc_read->viraddr != NULL) {
+				memcpy(buffer, rtc_read->viraddr, count);
+				n = count;
+				while (counter < count) {
+					MM_DBG("%x", \
+						rtc_read->viraddr[counter]);
+					counter++;
+					}
+				}
+		}
+	}
+	}
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static bool acdb_set_tx_rtc(const char *ubuf, size_t writecount)
+{
+	struct audpreproc_cmd_cfg_iir_tuning_filter_params *preproc_iir;
+	struct audpreproc_cmd_cfg_agc_params *preproc_agc;
+	struct audpreproc_cmd_cfg_ns_params *preproc_ns;
+	s32	result = 0;
+	bool retval = false;
+	unsigned short iircmdsize =
+		sizeof(struct audpreproc_cmd_cfg_iir_tuning_filter_params);
+	unsigned short iircmdid = AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS;
+
+	rtc_acdb.err = ACDB_RTC_ERR_UNKNOWN_FAILURE;
+
+	switch (rtc_acdb.set_abid) {
+
+	case AUDPREPROC_CMD_CFG_AGC_PARAMS:
+	case AUDPREPROC_CMD_CFG_AGC_PARAMS_2:
+	{
+		preproc_agc = kmalloc(sizeof(\
+					struct audpreproc_cmd_cfg_agc_params),\
+					GFP_KERNEL);
+		if ((sizeof(struct audpreproc_cmd_cfg_agc_params) -\
+			(2*sizeof(unsigned short)))
+			< writecount) {
+				MM_ERR("ACDB DATA WRITE --\
+					AGC TX writecount > DSP struct\n");
+		} else {
+			if (preproc_agc != NULL) {
+				char *base; unsigned short offset;
+				unsigned short *offset_addr;
+				base = (char *)preproc_agc;
+				offset = offsetof(struct \
+						audpreproc_cmd_cfg_agc_params,\
+						tx_agc_param_mask);
+				offset_addr = (unsigned short *)(base + offset);
+				if ((copy_from_user(offset_addr,\
+					(void *)ubuf, writecount)) == 0x00) {
+					preproc_agc->cmd_id =
+						AUDPREPROC_CMD_CFG_AGC_PARAMS;
+					preproc_agc->stream_id =
+						acdb_data.preproc_stream_id;
+					result = audpreproc_dsp_set_agc(
+						preproc_agc,
+						sizeof(struct \
+						audpreproc_cmd_cfg_agc_params));
+					if (result) {
+						MM_ERR("ACDB=> Failed to \
+							send AGC data to \
+							preproc)\n");
+					} else {
+						retval = true;
+					       }
+				} else {
+					MM_ERR("ACDB DATA WRITE ---\
+						GC Tx copy_from_user Fail\n");
+				}
+			} else {
+				MM_ERR("ACDB DATA WRITE --\
+					AGC TX kalloc Failed LEN\n");
+			}
+		}
+		if (preproc_agc != NULL)
+			kfree(preproc_agc);
+		break;
+	}
+	case AUDPREPROC_CMD_CFG_NS_PARAMS:
+	{
+
+		preproc_ns = kmalloc(sizeof(struct \
+					audpreproc_cmd_cfg_ns_params),\
+					GFP_KERNEL);
+		if ((sizeof(struct audpreproc_cmd_cfg_ns_params) -\
+				(2 * sizeof(unsigned short)))
+				< writecount) {
+				MM_ERR("ACDB DATA WRITE --\
+					NS TX writecount > DSP struct\n");
+		} else {
+			if (preproc_ns != NULL) {
+				char *base; unsigned short offset;
+				unsigned short *offset_addr;
+				base = (char *)preproc_ns;
+				offset = offsetof(struct \
+						audpreproc_cmd_cfg_ns_params,\
+						ec_mode_new);
+				offset_addr = (unsigned short *)(base + offset);
+				if ((copy_from_user(offset_addr,\
+					(void *)ubuf, writecount)) == 0x00) {
+					preproc_ns->cmd_id =
+						AUDPREPROC_CMD_CFG_NS_PARAMS;
+					preproc_ns->stream_id =
+						acdb_data.preproc_stream_id;
+					result = audpreproc_dsp_set_ns(
+						preproc_ns,
+						sizeof(struct \
+						audpreproc_cmd_cfg_ns_params));
+					if (result) {
+						MM_ERR("ACDB=> Failed to send \
+							NS data to preproc\n");
+					} else {
+						retval = true;
+					}
+				} else {
+					MM_ERR("ACDB DATA WRITE ---NS Tx \
+						copy_from_user Fail\n");
+					}
+			} else {
+				MM_ERR("ACDB DATA WRITE --NS TX\
+					kalloc Failed LEN\n");
+			}
+		}
+		if (preproc_ns != NULL)
+			kfree(preproc_ns);
+		break;
+	}
+	case AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS:
+	{
+
+		preproc_iir = kmalloc(sizeof(struct \
+				audpreproc_cmd_cfg_iir_tuning_filter_params),\
+				GFP_KERNEL);
+		if ((sizeof(struct \
+			audpreproc_cmd_cfg_iir_tuning_filter_params)-\
+			(2 * sizeof(unsigned short)))
+			< writecount) {
+			MM_ERR("ACDB DATA WRITE --IIR TX writecount\
+						> DSP struct\n");
+		} else {
+			if (preproc_iir != NULL) {
+				char *base; unsigned short offset;
+				unsigned short *offset_addr;
+				base = (char *)preproc_iir;
+				offset = offsetof(struct \
+				audpreproc_cmd_cfg_iir_tuning_filter_params,\
+				active_flag);
+				offset_addr = (unsigned short *)(base + \
+						offset);
+				if ((copy_from_user(offset_addr,\
+					(void *)ubuf, writecount)) == 0x00) {
+					preproc_iir->cmd_id = iircmdid;
+					preproc_iir->stream_id =
+						acdb_data.preproc_stream_id;
+					result = audpreproc_dsp_set_iir(\
+							preproc_iir,
+							iircmdsize);
+					if (result) {
+						MM_ERR("ACDB=> Failed to send\
+						IIR data to preproc\n");
+					} else {
+						retval = true;
+					}
+				} else {
+					MM_ERR("ACDB DATA WRITE ---IIR Tx \
+						copy_from_user Fail\n");
+				}
+			} else {
+				MM_ERR("ACDB DATA WRITE --IIR TX kalloc \
+					Failed LEN\n");
+		     }
+		}
+		if (preproc_iir != NULL)
+			kfree(preproc_iir);
+		break;
+	}
+	}
+	return retval;
+}
+
+static bool acdb_set_rx_rtc(const char *ubuf, size_t writecount)
+{
+
+	struct audpp_cmd_cfg_object_params_volpan *volpan_config;
+	struct audpp_cmd_cfg_object_params_mbadrc *mbadrc_config;
+	struct acdb_block_mbadrc_rtc *acdb_mbadrc_rtc;
+	struct audpp_cmd_cfg_object_params_sidechain *stf_config;
+	struct audpp_cmd_cfg_object_params_spectram *spa_config;
+	struct audpp_cmd_cfg_object_params_eqalizer *eq_config;
+	struct audpp_cmd_cfg_object_params_pcm *iir_config;
+	unsigned short temp_spa[34];
+	struct rtc_acdb_pmem *rtc_write = &rtc_acdb.rtc_write;
+	s32	result = 0;
+	bool retval = false;
+
+	switch (rtc_acdb.set_abid) {
+	case AUDPP_CMD_VOLUME_PAN:
+	{
+		volpan_config =  kmalloc(sizeof(struct \
+					 audpp_cmd_cfg_object_params_volpan),\
+					 GFP_KERNEL);
+		if ((sizeof(struct audpp_cmd_cfg_object_params_volpan) -\
+			sizeof(struct audpp_cmd_cfg_object_params_common))
+			< writecount) {
+			MM_ERR("ACDB DATA WRITE --\
+				VolPan writecount > DSP struct\n");
+		} else {
+			if (volpan_config != NULL) {
+				char *base; unsigned short offset;
+				unsigned short *offset_addr;
+				base = (char *)volpan_config;
+				offset = offsetof(struct \
+					audpp_cmd_cfg_object_params_volpan,\
+					volume);
+				offset_addr = (unsigned short *)(base+offset);
+				if ((copy_from_user(offset_addr,\
+					(void *)ubuf, writecount)) == 0x00) {
+					MM_ERR("ACDB RX WRITE DATA:\
+						AUDPP_CMD_VOLUME_PAN\n");
+					result = audpp_set_volume_and_pan(
+						acdb_data.device_info->dev_id,\
+						volpan_config->volume,
+						volpan_config->pan,
+						COPP);
+					if (result) {
+						MM_ERR("ACDB=> Failed to \
+							send VOLPAN data to"
+							" postproc\n");
+					} else {
+						retval = true;
+					}
+				} else {
+					MM_ERR("ACDB DATA WRITE ---\
+						copy_from_user Fail\n");
+				}
+			} else {
+				MM_ERR("ACDB DATA WRITE --\
+					Vol Pan kalloc Failed LEN\n");
+			}
+		}
+	if (volpan_config != NULL)
+		kfree(volpan_config);
+	break;
+	}
+
+	case AUDPP_CMD_IIR_TUNING_FILTER:
+	{
+		iir_config =  kmalloc(sizeof(struct \
+				audpp_cmd_cfg_object_params_pcm),\
+				GFP_KERNEL);
+		if ((sizeof(struct audpp_cmd_cfg_object_params_pcm) -\
+			sizeof(struct audpp_cmd_cfg_object_params_common))
+			< writecount) {
+			MM_ERR("ACDB DATA WRITE --\
+					IIR RX writecount > DSP struct\n");
+		} else {
+			if (iir_config != NULL) {
+				char *base; unsigned short offset;
+				unsigned short *offset_addr;
+				base = (char *)iir_config;
+				offset = offsetof(struct \
+					audpp_cmd_cfg_object_params_pcm,\
+					active_flag);
+				offset_addr = (unsigned short *)(base+offset);
+				if ((copy_from_user(offset_addr,\
+					(void *)ubuf, writecount)) == 0x00) {
+
+					iir_config->common.cmd_id =
+						AUDPP_CMD_CFG_OBJECT_PARAMS;
+					iir_config->common.stream =
+						AUDPP_CMD_COPP_STREAM;
+					iir_config->common.stream_id = 0;
+					iir_config->common.obj_cfg =
+						AUDPP_CMD_OBJ0_UPDATE;
+					iir_config->common.command_type = 0;
+					MM_ERR("ACDB RX WRITE DATA:\
+					AUDPP_CMD_IIR_TUNING_FILTER\n");
+					result = audpp_dsp_set_rx_iir(
+						acdb_data.device_info->dev_id,
+						iir_config->active_flag,\
+						iir_config, COPP);
+					if (result) {
+						MM_ERR("ACDB=> Failed to send\
+							IIR data to\
+							postproc\n");
+					} else {
+						retval = true;
+					}
+				} else {
+					MM_ERR("ACDB DATA WRITE ---\
+						IIR Rx copy_from_user Fail\n");
+				      }
+			 } else {
+				MM_ERR("ACDB DATA WRITE --\
+					acdb_iir_block kalloc Failed LEN\n");
+			}
+		}
+		if (iir_config != NULL)
+			kfree(iir_config);
+		break;
+	}
+	case AUDPP_CMD_EQUALIZER:
+	{
+		eq_config =  kmalloc(sizeof(struct \
+				audpp_cmd_cfg_object_params_eqalizer),\
+				GFP_KERNEL);
+	if ((sizeof(struct audpp_cmd_cfg_object_params_eqalizer) -\
+			sizeof(struct audpp_cmd_cfg_object_params_common))
+			< writecount) {
+			MM_ERR("ACDB DATA WRITE --\
+			EQ RX writecount > DSP struct\n");
+		} else {
+			if (eq_config != NULL) {
+				char *base; unsigned short offset;
+				unsigned short *offset_addr;
+				base = (char *)eq_config;
+				offset = offsetof(struct \
+					audpp_cmd_cfg_object_params_eqalizer,\
+					eq_flag);
+				offset_addr = (unsigned short *)(base+offset);
+				if ((copy_from_user(offset_addr,\
+					(void *)ubuf, writecount)) == 0x00) {
+					eq_config->common.cmd_id =
+						AUDPP_CMD_CFG_OBJECT_PARAMS;
+					eq_config->common.stream =
+						AUDPP_CMD_COPP_STREAM;
+					eq_config->common.stream_id = 0;
+					eq_config->common.obj_cfg =
+						AUDPP_CMD_OBJ0_UPDATE;
+					eq_config->common.command_type = 0;
+					MM_ERR("ACDB RX WRITE\
+					DATA:AUDPP_CMD_EQUALIZER\n");
+					result = audpp_dsp_set_eq(
+						acdb_data.device_info->dev_id,
+						eq_config->eq_flag,\
+						eq_config,
+						COPP);
+					if (result) {
+						MM_ERR("ACDB=> Failed to \
+						send EQ data to postproc\n");
+					} else {
+						retval = true;
+					}
+				} else {
+					MM_ERR("ACDB DATA WRITE ---\
+					EQ Rx copy_from_user Fail\n");
+				}
+			} else {
+				MM_ERR("ACDB DATA WRITE --\
+					EQ kalloc Failed LEN\n");
+			}
+		}
+		if (eq_config != NULL)
+			kfree(eq_config);
+		break;
+	}
+
+	case AUDPP_CMD_SPECTROGRAM:
+	{
+		spa_config =  kmalloc(sizeof(struct \
+				audpp_cmd_cfg_object_params_spectram),\
+				GFP_KERNEL);
+		if ((sizeof(struct audpp_cmd_cfg_object_params_spectram)-\
+				sizeof(struct \
+				audpp_cmd_cfg_object_params_common))
+				< (2 * sizeof(unsigned short))) {
+					MM_ERR("ACDB DATA WRITE --SPA \
+					RX writecount > DSP struct\n");
+		} else {
+			if (spa_config != NULL) {
+				if ((copy_from_user(&temp_spa[0],\
+					(void *)ubuf,
+					(34 * sizeof(unsigned short))))
+					== 0x00) {
+					spa_config->common.cmd_id =
+						AUDPP_CMD_CFG_OBJECT_PARAMS;
+					spa_config->common.stream =
+						AUDPP_CMD_COPP_STREAM;
+					spa_config->common.stream_id = 0;
+					spa_config->common.obj_cfg =
+						AUDPP_CMD_OBJ0_UPDATE;
+					spa_config->common.command_type = 0;
+					spa_config->sample_interval =
+						temp_spa[0];
+					spa_config->num_coeff = temp_spa[1];
+					MM_ERR("ACDB RX WRITE DATA:\
+						AUDPP_CMD_SPECTROGRAM\n");
+					result = audpp_dsp_set_spa(
+						acdb_data.device_info->dev_id,\
+						spa_config, COPP);
+					if (result) {
+						MM_ERR("ACDB=> Failed to \
+							send SPA data \
+							to postproc\n");
+					} else {
+						retval = true;
+					      }
+				} else {
+					MM_ERR("ACDB DATA WRITE \
+					---SPA Rx copy_from_user\
+					Fail\n");
+				}
+			} else {
+				MM_ERR("ACDB DATA WRITE --\
+				SPA kalloc Failed LEN\n");
+			       }
+			}
+		if (spa_config != NULL)
+			kfree(spa_config);
+	break;
+	}
+	case AUDPP_CMD_MBADRC:
+	{
+		acdb_mbadrc_rtc =  kmalloc(sizeof(struct \
+					acdb_block_mbadrc_rtc),\
+					GFP_KERNEL);
+		mbadrc_config =  kmalloc(sizeof(struct \
+					audpp_cmd_cfg_object_params_mbadrc),\
+					GFP_KERNEL);
+		if (mbadrc_config != NULL && acdb_mbadrc_rtc != NULL) {
+			if ((copy_from_user(acdb_mbadrc_rtc,\
+				(void *)ubuf,
+				sizeof(struct acdb_block_mbadrc_rtc)))
+				== 0x00) {
+				mbadrc_config->common.cmd_id =
+					AUDPP_CMD_CFG_OBJECT_PARAMS;
+				mbadrc_config->common.stream =
+					AUDPP_CMD_COPP_STREAM;
+				mbadrc_config->common.stream_id = 0;
+				mbadrc_config->common.obj_cfg =
+					AUDPP_CMD_OBJ0_UPDATE;
+				mbadrc_config->common.command_type = 0;
+				mbadrc_config->enable =
+						acdb_mbadrc_rtc->enable;
+				mbadrc_config->num_bands =
+						acdb_mbadrc_rtc->num_bands;
+				mbadrc_config->down_samp_level =
+				acdb_mbadrc_rtc->down_samp_level;
+				mbadrc_config->adrc_delay =
+					acdb_mbadrc_rtc->adrc_delay;
+				memcpy(mbadrc_config->adrc_band,\
+					acdb_mbadrc_rtc->adrc_band,\
+					AUDPP_MAX_MBADRC_BANDS *\
+					sizeof(struct adrc_config));
+				if (mbadrc_config->num_bands > 1) {
+					mbadrc_config->ext_buf_size =
+						(97 * 2) + (33 * 2 * \
+					(mbadrc_config->num_bands - 2));
+				}
+				mbadrc_config->ext_partition = 0;
+				mbadrc_config->ext_buf_lsw =
+					(u16) EXTRACT_LOW_WORD(\
+						rtc_write->phys);
+				mbadrc_config->ext_buf_msw =
+					(u16) EXTRACT_HIGH_WORD(\
+						rtc_write->phys);
+				memcpy(rtc_write->viraddr,
+					acdb_mbadrc_rtc->ExtBuff,
+					(196*sizeof(signed int)));
+				result = audpp_dsp_set_mbadrc(
+						acdb_data.device_info->dev_id,
+						mbadrc_config->enable,
+						mbadrc_config, COPP);
+				if (result) {
+					MM_ERR("ACDB=> Failed to \
+						Send MBADRC data \
+						to postproc\n");
+				} else {
+					retval = true;
+				}
+			} else {
+				MM_ERR("ACDB DATA WRITE ---\
+					MBADRC Rx copy_from_user Fail\n");
+			}
+		} else {
+			MM_ERR("ACDB DATA WRITE --MBADRC kalloc Failed LEN\n");
+		}
+		if (mbadrc_config != NULL)
+			kfree(mbadrc_config);
+		if (acdb_mbadrc_rtc != NULL)
+			kfree(acdb_mbadrc_rtc);
+	break;
+	}
+	case AUDPP_CMD_SIDECHAIN_TUNING_FILTER:
+	{
+		stf_config =  kmalloc(sizeof(struct \
+				audpp_cmd_cfg_object_params_sidechain),\
+				GFP_KERNEL);
+		if ((sizeof(struct audpp_cmd_cfg_object_params_sidechain) -\
+			sizeof(struct audpp_cmd_cfg_object_params_common))
+			< writecount) {
+				MM_ERR("ACDB DATA WRITE --\
+					STF RX writecount > DSP struct\n");
+		} else {
+			if (stf_config != NULL) {
+				char *base; unsigned short offset;
+				unsigned short *offset_addr;
+				base = (char *)stf_config;
+				offset = offsetof(struct \
+					audpp_cmd_cfg_object_params_sidechain,\
+					active_flag);
+				offset_addr = (unsigned short *)(base+offset);
+				if ((copy_from_user(offset_addr,\
+					(void *)ubuf, writecount)) == 0x00) {
+					stf_config->common.cmd_id =
+						AUDPP_CMD_CFG_OBJECT_PARAMS;
+					stf_config->common.stream =
+						AUDPP_CMD_COPP_STREAM;
+					stf_config->common.stream_id = 0;
+					stf_config->common.obj_cfg =
+						AUDPP_CMD_OBJ0_UPDATE;
+					stf_config->common.command_type = 0;
+					MM_ERR("ACDB RX WRITE DATA:\
+					AUDPP_CMD_SIDECHAIN_TUNING_FILTER\n");
+				result = audpp_dsp_set_stf(
+						acdb_data.device_info->dev_id,\
+						stf_config->active_flag,\
+						stf_config, COPP);
+					if (result) {
+						MM_ERR("ACDB=> Failed to send \
+						STF data to postproc\n");
+					} else {
+						retval = true;
+					}
+				} else {
+					MM_ERR("ACDB DATA WRITE ---\
+					STF Rx copy_from_user Fail\n");
+				}
+			} else {
+				MM_ERR("ACDB DATA WRITE \
+					STF kalloc Failed LEN\n");
+		}
+	}
+	if (stf_config != NULL)
+		kfree(stf_config);
+	break;
+	}
+	}
+	return retval;
+}
+static ssize_t rtc_getsetabid_data_dbg_write(struct file *filp,
+						const char __user *ubuf,
+						size_t cnt, loff_t *ppos)
+{
+	if (rtc_acdb.valid_abid != true) {
+		MM_INFO("ACDB DATA READ ---INVALID ABID\n");
+		rtc_acdb.err = ACDB_RTC_ERR_INVALID_ABID;
+	} else {
+		if (rtc_acdb.tx_rx_ctl == ACDB_RTC_RX) {
+			if (acdb_set_rx_rtc(ubuf, cnt)) {
+				rtc_acdb.err = ACDB_RTC_SUCCESS;
+			} else {
+			rtc_acdb.err = ACDB_RTC_ERR_UNKNOWN_FAILURE;
+			cnt = 0;
+		}
+	} else if (rtc_acdb.tx_rx_ctl == ACDB_RTC_TX) {
+		if (acdb_set_tx_rtc(ubuf, cnt)) {
+			rtc_acdb.err = ACDB_RTC_SUCCESS;
+		} else {
+			rtc_acdb.err = ACDB_RTC_ERR_UNKNOWN_FAILURE;
+			cnt = 0;
+		}
+	}
+  }
+	return cnt;
+}
+
+
+static const	struct file_operations rtc_acdb_data_debug_fops = {
+	.open = rtc_getsetabid_data_dbg_open,
+	.write = rtc_getsetabid_data_dbg_write,
+	.read = rtc_getsetabid_data_dbg_read
+};
+
+static const	struct file_operations rtc_acdb_debug_fops = {
+	.open = rtc_getsetabid_dbg_open,
+	.write = rtc_getsetabid_dbg_write,
+	.read = rtc_getsetabid_dbg_read
+};
+
+static void rtc_acdb_deinit(void)
+{
+	struct rtc_acdb_pmem *rtc_read = &rtc_acdb.rtc_read;
+	struct rtc_acdb_pmem *rtc_write = &rtc_acdb.rtc_write;
+	if (get_set_abid_dentry) {
+		MM_DBG("GetSet ABID remove debugfs\n");
+		debugfs_remove(get_set_abid_dentry);
+	}
+
+	if (get_set_abid_data_dentry) {
+		MM_DBG("GetSet ABID remove debugfs\n");
+		debugfs_remove(get_set_abid_data_dentry);
+	}
+	rtc_acdb.abid = 0;
+	rtc_acdb.acdb_id = 0;
+	rtc_acdb.cmd_id = 0;
+	rtc_acdb.err = 1;
+	rtc_acdb.set_abid = 0;
+	rtc_acdb.set_iid = 0;
+	rtc_acdb.tx_rx_ctl = 0;
+	rtc_acdb.valid_abid = false;
+
+	if (rtc_read->viraddr != NULL || ((void *)rtc_read->phys) != NULL) {
+		iounmap(rtc_read->map_v_rtc);
+		free_contiguous_memory_by_paddr(rtc_read->phys);
+	}
+	if (rtc_write->viraddr != NULL || ((void *)rtc_write->phys) != NULL) {
+		iounmap(rtc_write->map_v_rtc);
+		free_contiguous_memory_by_paddr(rtc_write->phys);
+	}
+}
+
+static bool rtc_acdb_init(void)
+{
+	struct rtc_acdb_pmem *rtc_read = &rtc_acdb.rtc_read;
+	struct rtc_acdb_pmem *rtc_write = &rtc_acdb.rtc_write;
+	s32 result = 0;
+	char name[sizeof "get_set_abid"+1];
+	char name1[sizeof "get_set_abid_data"+1];
+	rtc_acdb.abid = 0;
+	rtc_acdb.acdb_id = 0;
+	rtc_acdb.cmd_id = 0;
+	rtc_acdb.err = 1;
+	rtc_acdb.set_abid = 0;
+	rtc_acdb.set_iid = 0;
+	rtc_acdb.valid_abid = false;
+	rtc_acdb.tx_rx_ctl = 0;
+	if (acdb_data.build_id[17] == '1') {
+		snprintf(name, sizeof name, "get_set_abid");
+		get_set_abid_dentry = debugfs_create_file(name,
+					S_IFREG | S_IRUGO | S_IWUGO,
+					NULL, NULL, &rtc_acdb_debug_fops);
+		if (IS_ERR(get_set_abid_dentry)) {
+			MM_ERR("SET GET ABID debugfs_create_file failed\n");
+			return false;
+		}
+
+		snprintf(name1, sizeof name1, "get_set_abid_data");
+		get_set_abid_data_dentry = debugfs_create_file(name1,
+						S_IFREG | S_IRUGO | S_IWUGO,
+						NULL, NULL,
+						&rtc_acdb_data_debug_fops);
+		if (IS_ERR(get_set_abid_data_dentry)) {
+			MM_ERR("SET GET ABID DATA"
+					" debugfs_create_file failed\n");
+			return false;
+		}
+	}
+
+	rtc_read->phys = allocate_contiguous_ebi_nomap(PMEM_RTC_ACDB_QUERY_MEM,
+								 SZ_4K);
+
+	if (!rtc_read->phys) {
+		MM_ERR("ACDB Cannot allocate physical memory\n");
+		result = -ENOMEM;
+		goto error;
+	}
+	rtc_read->map_v_rtc = ioremap(rtc_read->phys,
+				PMEM_RTC_ACDB_QUERY_MEM);
+
+	if (IS_ERR(rtc_read->map_v_rtc)) {
+		MM_ERR("ACDB Could not map physical address\n");
+		result = -ENOMEM;
+		goto error;
+	}
+	rtc_read->viraddr = rtc_read->map_v_rtc;
+	memset(rtc_read->viraddr, 0, PMEM_RTC_ACDB_QUERY_MEM);
+
+	rtc_write->phys = allocate_contiguous_ebi_nomap(PMEM_RTC_ACDB_QUERY_MEM,
+								SZ_4K);
+
+	if (!rtc_write->phys) {
+		MM_ERR("ACDB Cannot allocate physical memory\n");
+		result = -ENOMEM;
+		goto error;
+	}
+	rtc_write->map_v_rtc = ioremap(rtc_write->phys,
+				PMEM_RTC_ACDB_QUERY_MEM);
+
+	if (IS_ERR(rtc_write->map_v_rtc)) {
+		MM_ERR("ACDB Could not map physical address\n");
+		result = -ENOMEM;
+		goto error;
+	}
+	rtc_write->viraddr = rtc_write->map_v_rtc;
+	memset(rtc_write->viraddr, 0, PMEM_RTC_ACDB_QUERY_MEM);
+	init_waitqueue_head(&rtc_acdb.wait);
+	return true;
+error:
+	MM_DBG("INIT RTC FAILED REMOVING RTC DEBUG FS\n");
+	if (get_set_abid_dentry) {
+		MM_DBG("GetSet ABID remove debugfs\n");
+		debugfs_remove(get_set_abid_dentry);
+	}
+
+	if (get_set_abid_data_dentry) {
+		MM_DBG("GetSet ABID remove debugfs\n");
+		debugfs_remove(get_set_abid_data_dentry);
+	}
+	if (rtc_read->viraddr != NULL || ((void *)rtc_read->phys) != NULL) {
+		iounmap(rtc_read->map_v_rtc);
+		free_contiguous_memory_by_paddr(rtc_read->phys);
+	}
+	if (rtc_write->viraddr != NULL || ((void *)rtc_write->phys) != NULL) {
+		iounmap(rtc_write->map_v_rtc);
+		free_contiguous_memory_by_paddr(rtc_write->phys);
+	}
+	return false;
+}
+#endif /*CONFIG_DEBUG_FS*/
+static s32 acdb_set_calibration_blk(unsigned long arg)
+{
+	struct acdb_cmd_device acdb_cmd;
+	s32 result = 0;
+
+	MM_DBG("acdb_set_calibration_blk\n");
+	if (copy_from_user(&acdb_cmd, (struct acdb_cmd_device *)arg,
+			sizeof(acdb_cmd))) {
+		MM_ERR("Failed copy command struct from user in"
+			"acdb_set_calibration_blk\n");
+		return -EFAULT;
+	}
+	acdb_cmd.phys_buf = (u32 *)acdb_data.paddr;
+
+	MM_DBG("acdb_cmd.phys_buf %x\n", (u32)acdb_cmd.phys_buf);
+
+	result = dalrpc_fcn_8(ACDB_DalACDB_ioctl, acdb_data.handle,
+			(const void *)&acdb_cmd, sizeof(acdb_cmd),
+			&acdb_data.acdb_result,
+			sizeof(acdb_data.acdb_result));
+
+	if (result < 0) {
+		MM_ERR("ACDB=> Device Set RPC failure"
+			" result = %d\n", result);
+		return -EINVAL;
+	} else {
+		MM_ERR("ACDB=> Device Set RPC success\n");
+		if (acdb_data.acdb_result.result == ACDB_RES_SUCCESS)
+			MM_DBG("ACDB_SET_DEVICE Success\n");
+		else if (acdb_data.acdb_result.result == ACDB_RES_FAILURE)
+			MM_ERR("ACDB_SET_DEVICE Failure\n");
+		else if (acdb_data.acdb_result.result == ACDB_RES_BADPARM)
+			MM_ERR("ACDB_SET_DEVICE BadParams\n");
+		else
+			MM_ERR("Unknown error\n");
+	}
+	return result;
+}
+
+static s32 acdb_get_calibration_blk(unsigned long arg)
+{
+	s32 result = 0;
+	struct acdb_cmd_device acdb_cmd;
+
+	MM_DBG("acdb_get_calibration_blk\n");
+
+	if (copy_from_user(&acdb_cmd, (struct acdb_cmd_device *)arg,
+			sizeof(acdb_cmd))) {
+		MM_ERR("Failed copy command struct from user in"
+			"acdb_get_calibration_blk\n");
+		return -EFAULT;
+	}
+	acdb_cmd.phys_buf = (u32 *)acdb_data.paddr;
+	MM_ERR("acdb_cmd.phys_buf %x\n", (u32)acdb_cmd.phys_buf);
+
+	result = dalrpc_fcn_8(ACDB_DalACDB_ioctl, acdb_data.handle,
+			(const void *)&acdb_cmd, sizeof(acdb_cmd),
+			&acdb_data.acdb_result,
+			sizeof(acdb_data.acdb_result));
+
+	if (result < 0) {
+		MM_ERR("ACDB=> Device Get RPC failure"
+			" result = %d\n", result);
+		return -EINVAL;
+	} else {
+		MM_ERR("ACDB=> Device Get RPC Success\n");
+		if (acdb_data.acdb_result.result == ACDB_RES_SUCCESS)
+			MM_DBG("ACDB_GET_DEVICE Success\n");
+		else if (acdb_data.acdb_result.result == ACDB_RES_FAILURE)
+			MM_ERR("ACDB_GET_DEVICE Failure\n");
+		else if (acdb_data.acdb_result.result == ACDB_RES_BADPARM)
+			MM_ERR("ACDB_GET_DEVICE BadParams\n");
+		else
+			MM_ERR("Unknown error\n");
+	}
+	return result;
+}
+
+static int audio_acdb_open(struct inode *inode, struct file *file)
+{
+	MM_DBG("%s\n", __func__);
+	return 0;
+}
+static int audio_acdb_release(struct inode *inode, struct file *file)
+{
+	MM_DBG("%s\n", __func__);
+	return 0;
+}
+
+static long audio_acdb_ioctl(struct file *file, unsigned int cmd,
+					unsigned long arg)
+{
+	int rc = 0;
+	unsigned long flags = 0;
+	struct msm_audio_pmem_info info;
+
+	MM_DBG("%s\n", __func__);
+
+	switch (cmd) {
+	case AUDIO_SET_EQ:
+		MM_DBG("IOCTL SET_EQ_CONFIG\n");
+		if (copy_from_user(&acdb_data.eq.num_bands, (void *) arg,
+				sizeof(acdb_data.eq) -
+				(AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2))) {
+			rc = -EFAULT;
+			break;
+		}
+		spin_lock_irqsave(&acdb_data.dsp_lock, flags);
+		acdb_data.dec_id    = 0;
+		rc = audpp_dsp_set_eq(acdb_data.dec_id, 1,
+			&acdb_data.eq, COPP);
+		if (rc < 0)
+			MM_ERR("AUDPP returned err =%d\n", rc);
+		spin_unlock_irqrestore(&acdb_data.dsp_lock, flags);
+		break;
+	case AUDIO_REGISTER_PMEM:
+		MM_DBG("AUDIO_REGISTER_PMEM\n");
+		if (copy_from_user(&info, (void *) arg, sizeof(info))) {
+			MM_ERR("Cannot copy from user\n");
+			return -EFAULT;
+		}
+		rc = get_pmem_file(info.fd, &acdb_data.paddr,
+					&acdb_data.kvaddr,
+					&acdb_data.pmem_len,
+					&acdb_data.file);
+		if (rc == 0)
+			acdb_data.pmem_fd = info.fd;
+		break;
+	case AUDIO_DEREGISTER_PMEM:
+		if (acdb_data.pmem_fd)
+			put_pmem_file(acdb_data.file);
+		break;
+	case AUDIO_SET_ACDB_BLK:
+		MM_DBG("IOCTL AUDIO_SET_ACDB_BLK\n");
+		rc = acdb_set_calibration_blk(arg);
+		break;
+	case AUDIO_GET_ACDB_BLK:
+		MM_DBG("IOiCTL AUDIO_GET_ACDB_BLK\n");
+		rc = acdb_get_calibration_blk(arg);
+		break;
+	default:
+		MM_DBG("Unknown IOCTL%d\n", cmd);
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+static const struct file_operations acdb_fops = {
+	.owner = THIS_MODULE,
+	.open = audio_acdb_open,
+	.release = audio_acdb_release,
+	.llseek = no_llseek,
+	.unlocked_ioctl = audio_acdb_ioctl
+};
+
+struct miscdevice acdb_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_acdb",
+	.fops	= &acdb_fops,
+};
+
+static s32 acdb_get_calibration(void)
+{
+	struct acdb_cmd_get_device_table	acdb_cmd;
+	s32					result = 0;
+	u32 iterations = 0;
+
+	MM_DBG("acdb state = %d\n", acdb_data.acdb_state);
+
+	acdb_cmd.command_id = ACDB_GET_DEVICE_TABLE;
+	acdb_cmd.device_id = acdb_data.device_info->acdb_id;
+	acdb_cmd.network_id = 0x0108B153;
+	acdb_cmd.sample_rate_id = acdb_data.device_info->sample_rate;
+	acdb_cmd.total_bytes = ACDB_BUF_SIZE;
+	acdb_cmd.phys_buf = (u32 *)acdb_data.phys_addr;
+	MM_DBG("device_id = %d, sampling_freq = %d\n",
+				acdb_cmd.device_id, acdb_cmd.sample_rate_id);
+
+	do {
+		result = dalrpc_fcn_8(ACDB_DalACDB_ioctl, acdb_data.handle,
+				(const void *)&acdb_cmd, sizeof(acdb_cmd),
+				&acdb_data.acdb_result,
+				sizeof(acdb_data.acdb_result));
+
+		if (result < 0) {
+			MM_ERR("ACDB=> Device table RPC failure"
+				" result = %d\n", result);
+			goto error;
+		}
+		/*following check is introduced to handle boot up race
+		condition between AUDCAL SW peers running on apps
+		and modem (ACDB_RES_BADSTATE indicates modem AUDCAL SW is
+		not in initialized sate) we need to retry to get ACDB
+		values*/
+		if (acdb_data.acdb_result.result == ACDB_RES_BADSTATE) {
+			msleep(500);
+			iterations++;
+		} else if (acdb_data.acdb_result.result == ACDB_RES_SUCCESS) {
+			MM_DBG("Modem query for acdb values is successful"
+					" (iterations = %d)\n", iterations);
+			acdb_data.acdb_state |= CAL_DATA_READY;
+			return result;
+		} else {
+			MM_ERR("ACDB=> modem failed to fill acdb values,"
+					" reuslt = %d, (iterations = %d)\n",
+					acdb_data.acdb_result.result,
+					iterations);
+			goto error;
+		}
+	} while (iterations < MAX_RETRY);
+	MM_ERR("ACDB=> AUDCAL SW on modem is not in intiailized state (%d)\n",
+			acdb_data.acdb_result.result);
+error:
+	result = -EINVAL;
+	return result;
+}
+
+s32 acdb_get_calibration_data(struct acdb_get_block *get_block)
+{
+	s32 result = -EINVAL;
+	struct acdb_cmd_device acdb_cmd;
+	struct acdb_result acdb_result;
+
+	MM_DBG("acdb_get_calibration_data\n");
+
+	acdb_cmd.command_id = ACDB_GET_DEVICE;
+	acdb_cmd.network_id = 0x0108B153;
+	acdb_cmd.device_id = get_block->acdb_id;
+	acdb_cmd.sample_rate_id = get_block->sample_rate_id;
+	acdb_cmd.interface_id = get_block->interface_id;
+	acdb_cmd.algorithm_block_id = get_block->algorithm_block_id;
+	acdb_cmd.total_bytes = get_block->total_bytes;
+	acdb_cmd.phys_buf = (u32 *)acdb_data.get_blk_paddr;
+
+	result = dalrpc_fcn_8(ACDB_DalACDB_ioctl, acdb_data.handle,
+			(const void *)&acdb_cmd, sizeof(acdb_cmd),
+			&acdb_result,
+			sizeof(acdb_result));
+
+	if (result < 0) {
+		MM_ERR("ACDB=> Device Get RPC failure"
+			" result = %d\n", result);
+		goto err_state;
+	} else {
+		MM_DBG("ACDB=> Device Get RPC Success\n");
+		if (acdb_result.result == ACDB_RES_SUCCESS) {
+			MM_DBG("ACDB_GET_DEVICE Success\n");
+			result = 0;
+			memcpy(get_block->buf_ptr, acdb_data.get_blk_kvaddr,
+					get_block->total_bytes);
+		} else if (acdb_result.result == ACDB_RES_FAILURE)
+			MM_ERR("ACDB_GET_DEVICE Failure\n");
+		else if (acdb_result.result == ACDB_RES_BADPARM)
+			MM_ERR("ACDB_GET_DEVICE BadParams\n");
+		else
+			MM_ERR("Unknown error\n");
+	}
+err_state:
+	return result;
+}
+EXPORT_SYMBOL(acdb_get_calibration_data);
+
+static u8 check_device_info_already_present(
+		struct auddev_evt_audcal_info   audcal_info,
+			struct acdb_cache_node *acdb_cache_free_node)
+{
+	if ((audcal_info.dev_id ==
+				acdb_cache_free_node->device_info.dev_id) &&
+		(audcal_info.sample_rate ==
+				acdb_cache_free_node->device_info.\
+				sample_rate) &&
+			(audcal_info.acdb_id ==
+				acdb_cache_free_node->device_info.acdb_id)) {
+		MM_DBG("acdb values are already present\n");
+		/*if acdb state is not set for CAL_DATA_READY and node status
+		is filled, acdb state should be updated with CAL_DATA_READY
+		state*/
+		acdb_data.acdb_state |= CAL_DATA_READY;
+		/*checking for cache node status if it is not filled then the
+		acdb values are not cleaned from node so update node status
+		with acdb value filled*/
+		if ((acdb_cache_free_node->node_status != ACDB_VALUES_FILLED) &&
+			((audcal_info.dev_type & RX_DEVICE) == 1)) {
+			MM_DBG("device was released earlier\n");
+			acdb_cache_free_node->node_status = ACDB_VALUES_FILLED;
+			return 2; /*node is presnet but status as not filled*/
+		}
+		return 1; /*node is present but status as filled*/
+	}
+	MM_DBG("copying device info into node\n");
+	/*as device information is not present in cache copy
+	the current device information into the node*/
+	memcpy(&acdb_cache_free_node->device_info,
+				 &audcal_info, sizeof(audcal_info));
+	return 0; /*cant find the node*/
+}
+
+static struct acdb_iir_block *get_audpp_irr_block(void)
+{
+	struct header *prs_hdr;
+	u32 index = 0;
+
+	while (index < acdb_data.acdb_result.used_bytes) {
+		prs_hdr = (struct header *)(acdb_data.virt_addr + index);
+		if (prs_hdr->dbor_signature == DBOR_SIGNATURE) {
+			if (prs_hdr->abid == ABID_AUDIO_IIR_RX) {
+				if (prs_hdr->iid == IID_AUDIO_IIR_COEFF)
+					return (struct acdb_iir_block *)
+						(acdb_data.virt_addr + index
+						 + sizeof(struct header));
+			} else {
+				index += prs_hdr->data_len +
+						sizeof(struct header);
+			}
+		} else {
+			break;
+		}
+	}
+	return NULL;
+}
+
+
+static s32 acdb_fill_audpp_iir(void)
+{
+	struct acdb_iir_block *acdb_iir;
+	s32 i = 0;
+
+	acdb_iir = get_audpp_irr_block();
+	if (acdb_iir == NULL) {
+		MM_ERR("unable to find  audpp iir block returning\n");
+		return -1;
+	}
+	memset(acdb_data.pp_iir, 0, sizeof(*acdb_data.pp_iir));
+
+	acdb_data.pp_iir->common.cmd_id = AUDPP_CMD_CFG_OBJECT_PARAMS;
+	acdb_data.pp_iir->common.stream = AUDPP_CMD_COPP_STREAM;
+	acdb_data.pp_iir->common.stream_id = 0;
+	acdb_data.pp_iir->common.obj_cfg = AUDPP_CMD_OBJ0_UPDATE;
+	acdb_data.pp_iir->common.command_type = 0;
+
+	acdb_data.pp_iir->active_flag = acdb_iir->enable_flag;
+	acdb_data.pp_iir->num_bands = acdb_iir->stage_count;
+	for (; i < acdb_iir->stage_count; i++) {
+		acdb_data.pp_iir->params_filter.filter_4_params.
+			numerator_filter[i].numerator_b0_filter_lsw =
+			acdb_iir->stages[i].b0_lo;
+		acdb_data.pp_iir->params_filter.filter_4_params.
+			numerator_filter[i].numerator_b0_filter_msw =
+			acdb_iir->stages[i].b0_hi;
+		acdb_data.pp_iir->params_filter.filter_4_params.
+			numerator_filter[i].numerator_b1_filter_lsw =
+			acdb_iir->stages[i].b1_lo;
+		acdb_data.pp_iir->params_filter.filter_4_params.
+			numerator_filter[i].numerator_b1_filter_msw =
+			acdb_iir->stages[i].b1_hi;
+		acdb_data.pp_iir->params_filter.filter_4_params.
+			numerator_filter[i].numerator_b2_filter_lsw =
+			acdb_iir->stages[i].b2_lo;
+		acdb_data.pp_iir->params_filter.filter_4_params.
+			numerator_filter[i].numerator_b2_filter_msw =
+			acdb_iir->stages[i].b2_hi;
+		acdb_data.pp_iir->params_filter.filter_4_params.
+			denominator_filter[i].denominator_a0_filter_lsw =
+			acdb_iir->stages_a[i].a1_lo;
+		acdb_data.pp_iir->params_filter.filter_4_params.
+			denominator_filter[i].denominator_a0_filter_msw =
+			acdb_iir->stages_a[i].a1_hi;
+		acdb_data.pp_iir->params_filter.filter_4_params.
+			denominator_filter[i].denominator_a1_filter_lsw =
+			acdb_iir->stages_a[i].a2_lo;
+		acdb_data.pp_iir->params_filter.filter_4_params.
+			denominator_filter[i].denominator_a1_filter_msw =
+			acdb_iir->stages_a[i].a2_hi;
+		acdb_data.pp_iir->params_filter.filter_4_params.
+			shift_factor_filter[i].shift_factor_0 =
+			acdb_iir->shift_factor[i];
+		acdb_data.pp_iir->params_filter.filter_4_params.pan_filter[i].
+			pan_filter_0 = acdb_iir->pan[i];
+	}
+	return 0;
+}
+
+static void extract_mbadrc(u32 *phy_addr, struct header *prs_hdr, u32 *index)
+{
+	if (prs_hdr->iid == IID_MBADRC_EXT_BUFF) {
+		MM_DBG("Got IID = IID_MBADRC_EXT_BUFF\n");
+		*phy_addr = acdb_data.phys_addr	+ *index +
+					sizeof(struct header);
+		memcpy(acdb_data.mbadrc_block.ext_buf,
+				(acdb_data.virt_addr + *index +
+					sizeof(struct header)), 196*2);
+		MM_DBG("phy_addr = %x\n", *phy_addr);
+		*index += prs_hdr->data_len + sizeof(struct header);
+	} else if (prs_hdr->iid == IID_MBADRC_BAND_CONFIG) {
+		MM_DBG("Got IID == IID_MBADRC_BAND_CONFIG\n");
+		memcpy(acdb_data.mbadrc_block.band_config, (acdb_data.virt_addr
+					+ *index + sizeof(struct header)),
+				sizeof(struct mbadrc_band_config_type) *
+					 acdb_data.mbadrc_block.parameters.\
+						mbadrc_num_bands);
+		*index += prs_hdr->data_len + sizeof(struct header);
+	} else if (prs_hdr->iid == IID_MBADRC_PARAMETERS) {
+		struct mbadrc_parameter *tmp;
+		tmp = (struct mbadrc_parameter *)(acdb_data.virt_addr + *index
+						+ sizeof(struct header));
+		MM_DBG("Got IID == IID_MBADRC_PARAMETERS\n");
+		acdb_data.mbadrc_block.parameters.mbadrc_enable =
+							tmp->mbadrc_enable;
+		acdb_data.mbadrc_block.parameters.mbadrc_num_bands =
+							tmp->mbadrc_num_bands;
+		acdb_data.mbadrc_block.parameters.mbadrc_down_sample_level =
+						tmp->mbadrc_down_sample_level;
+		acdb_data.mbadrc_block.parameters.mbadrc_delay =
+							tmp->mbadrc_delay;
+		*index += prs_hdr->data_len + sizeof(struct header);
+	}
+}
+
+static void get_audpp_mbadrc_block(u32 *phy_addr)
+{
+	struct header *prs_hdr;
+	u32 index = 0;
+
+	while (index < acdb_data.acdb_result.used_bytes) {
+		prs_hdr = (struct header *)(acdb_data.virt_addr + index);
+
+		if (prs_hdr->dbor_signature == DBOR_SIGNATURE) {
+			if (prs_hdr->abid == ABID_AUDIO_MBADRC_RX) {
+				if ((prs_hdr->iid == IID_MBADRC_EXT_BUFF)
+					|| (prs_hdr->iid ==
+						IID_MBADRC_BAND_CONFIG)
+					|| (prs_hdr->iid ==
+						IID_MBADRC_PARAMETERS)) {
+					extract_mbadrc(phy_addr, prs_hdr,
+								&index);
+				}
+			} else {
+				index += prs_hdr->data_len +
+						sizeof(struct header);
+			}
+		} else {
+			break;
+		}
+	}
+}
+
+static s32 acdb_fill_audpp_mbadrc(void)
+{
+	u32 mbadrc_phys_addr = -1;
+	get_audpp_mbadrc_block(&mbadrc_phys_addr);
+	if (IS_ERR_VALUE(mbadrc_phys_addr)) {
+		MM_ERR("failed to get mbadrc block\n");
+		return -1;
+	}
+
+	memset(acdb_data.pp_mbadrc, 0, sizeof(*acdb_data.pp_mbadrc));
+
+	acdb_data.pp_mbadrc->common.cmd_id = AUDPP_CMD_CFG_OBJECT_PARAMS;
+	acdb_data.pp_mbadrc->common.stream = AUDPP_CMD_COPP_STREAM;
+	acdb_data.pp_mbadrc->common.stream_id = 0;
+	acdb_data.pp_mbadrc->common.obj_cfg = AUDPP_CMD_OBJ0_UPDATE;
+	acdb_data.pp_mbadrc->common.command_type = 0;
+
+	acdb_data.pp_mbadrc->enable = acdb_data.mbadrc_block.\
+					parameters.mbadrc_enable;
+	acdb_data.pp_mbadrc->num_bands =
+				acdb_data.mbadrc_block.\
+					parameters.mbadrc_num_bands;
+	acdb_data.pp_mbadrc->down_samp_level =
+				acdb_data.mbadrc_block.parameters.\
+					mbadrc_down_sample_level;
+	acdb_data.pp_mbadrc->adrc_delay =
+				acdb_data.mbadrc_block.parameters.\
+					mbadrc_delay;
+
+	if (acdb_data.mbadrc_block.parameters.mbadrc_num_bands > 1)
+		acdb_data.pp_mbadrc->ext_buf_size = (97 * 2) +
+			(33 * 2 * (acdb_data.mbadrc_block.parameters.\
+					mbadrc_num_bands - 2));
+
+	acdb_data.pp_mbadrc->ext_partition = 0;
+	acdb_data.pp_mbadrc->ext_buf_lsw = (u16)(mbadrc_phys_addr\
+						 & 0xFFFF);
+	acdb_data.pp_mbadrc->ext_buf_msw = (u16)((mbadrc_phys_addr\
+						 & 0xFFFF0000) >> 16);
+	memcpy(acdb_data.pp_mbadrc->adrc_band, acdb_data.mbadrc_block.\
+					band_config,
+		sizeof(struct mbadrc_band_config_type) *
+		acdb_data.mbadrc_block.parameters.mbadrc_num_bands);
+	return 0;
+}
+
+static struct acdb_calib_gain_rx *get_audpp_cal_gain(void)
+{
+	struct header *prs_hdr;
+	u32 index = 0;
+
+	while (index < acdb_data.acdb_result.used_bytes) {
+		prs_hdr = (struct header *)(acdb_data.virt_addr + index);
+		if (prs_hdr->dbor_signature == DBOR_SIGNATURE) {
+			if (prs_hdr->abid == ABID_AUDIO_CALIBRATION_GAIN_RX) {
+				if (prs_hdr->iid ==
+					IID_AUDIO_CALIBRATION_GAIN_RX) {
+					MM_DBG("Got audpp_calib_gain_rx"
+					" block\n");
+					return (struct acdb_calib_gain_rx *)
+						(acdb_data.virt_addr + index
+						+ sizeof(struct header));
+				}
+			} else {
+				index += prs_hdr->data_len +
+					sizeof(struct header);
+			}
+		} else {
+			break;
+		}
+	}
+	return NULL;
+}
+
+static s32 acdb_fill_audpp_cal_gain(void)
+{
+	struct acdb_calib_gain_rx *acdb_calib_gain_rx = NULL;
+
+	acdb_calib_gain_rx = get_audpp_cal_gain();
+	if (acdb_calib_gain_rx == NULL) {
+		MM_ERR("unable to find  audpp"
+			" calibration gain block returning\n");
+		return -1;
+	}
+	MM_DBG("Calibration value"
+		" for calib_gain_rx %d\n", acdb_calib_gain_rx->audppcalgain);
+	memset(acdb_data.calib_gain_rx, 0, sizeof(*acdb_data.calib_gain_rx));
+
+	acdb_data.calib_gain_rx->common.cmd_id = AUDPP_CMD_CFG_OBJECT_PARAMS;
+	acdb_data.calib_gain_rx->common.stream = AUDPP_CMD_COPP_STREAM;
+	acdb_data.calib_gain_rx->common.stream_id = 0;
+	acdb_data.calib_gain_rx->common.obj_cfg = AUDPP_CMD_OBJ0_UPDATE;
+	acdb_data.calib_gain_rx->common.command_type = 0;
+
+	acdb_data.calib_gain_rx->audppcalgain =
+				acdb_calib_gain_rx->audppcalgain;
+	return 0;
+}
+
+static void extract_pbe_block(struct header *prs_hdr, u32 *index)
+{
+	if (prs_hdr->iid == IID_AUDIO_PBE_RX_ENABLE_FLAG) {
+		MM_DBG("Got IID = IID_AUDIO_PBE_RX_ENABLE\n");
+		acdb_data.pbe_enable_flag = (u16 *)(acdb_data.virt_addr +
+							*index +
+							sizeof(struct header));
+		*index += prs_hdr->data_len + sizeof(struct header);
+	} else if (prs_hdr->iid == IID_PBE_CONFIG_PARAMETERS) {
+		MM_DBG("Got IID == IID_PBE_CONFIG_PARAMETERS\n");
+		acdb_data.pbe_blk = (struct acdb_pbe_block *)
+					(acdb_data.virt_addr + *index
+					+ sizeof(struct header));
+		*index += prs_hdr->data_len + sizeof(struct header);
+	}
+}
+
+static s32 get_audpp_pbe_block(void)
+{
+	struct header *prs_hdr;
+	u32 index = 0;
+	s32 result = -1;
+
+	while (index < acdb_data.acdb_result.used_bytes) {
+		prs_hdr = (struct header *)(acdb_data.virt_addr + index);
+
+		if (prs_hdr->dbor_signature == DBOR_SIGNATURE) {
+			if (prs_hdr->abid == ABID_AUDIO_PBE_RX) {
+				if ((prs_hdr->iid == IID_PBE_CONFIG_PARAMETERS)
+					|| (prs_hdr->iid ==
+						IID_AUDIO_PBE_RX_ENABLE_FLAG)) {
+					extract_pbe_block(prs_hdr, &index);
+					result = 0;
+				}
+			} else {
+				index += prs_hdr->data_len +
+					sizeof(struct header);
+			}
+		} else {
+			break;
+		}
+	}
+	return result;
+}
+
+static s32 acdb_fill_audpp_pbe(void)
+{
+	s32 result = -1;
+
+	result = get_audpp_pbe_block();
+	if (IS_ERR_VALUE(result))
+		return result;
+	memset(acdb_data.pbe_block, 0, sizeof(*acdb_data.pbe_block));
+
+	acdb_data.pbe_block->common.cmd_id = AUDPP_CMD_CFG_OBJECT_PARAMS;
+	acdb_data.pbe_block->common.stream = AUDPP_CMD_COPP_STREAM;
+	acdb_data.pbe_block->common.stream_id = 0;
+	acdb_data.pbe_block->common.obj_cfg = AUDPP_CMD_OBJ0_UPDATE;
+	acdb_data.pbe_block->common.command_type = 0;
+	acdb_data.pbe_block->pbe_enable = *acdb_data.pbe_enable_flag;
+
+	acdb_data.pbe_block->realbassmix = acdb_data.pbe_blk->realbassmix;
+	acdb_data.pbe_block->basscolorcontrol =
+					acdb_data.pbe_blk->basscolorcontrol;
+	acdb_data.pbe_block->mainchaindelay = acdb_data.pbe_blk->mainchaindelay;
+	acdb_data.pbe_block->xoverfltorder = acdb_data.pbe_blk->xoverfltorder;
+	acdb_data.pbe_block->bandpassfltorder =
+					acdb_data.pbe_blk->bandpassfltorder;
+	acdb_data.pbe_block->adrcdelay = acdb_data.pbe_blk->adrcdelay;
+	acdb_data.pbe_block->downsamplelevel =
+					acdb_data.pbe_blk->downsamplelevel;
+	acdb_data.pbe_block->comprmstav = acdb_data.pbe_blk->comprmstav;
+	acdb_data.pbe_block->expthreshold = acdb_data.pbe_blk->expthreshold;
+	acdb_data.pbe_block->expslope = acdb_data.pbe_blk->expslope;
+	acdb_data.pbe_block->compthreshold = acdb_data.pbe_blk->compthreshold;
+	acdb_data.pbe_block->compslope = acdb_data.pbe_blk->compslope;
+	acdb_data.pbe_block->cpmpattack_lsw = acdb_data.pbe_blk->cpmpattack_lsw;
+	acdb_data.pbe_block->compattack_msw = acdb_data.pbe_blk->compattack_msw;
+	acdb_data.pbe_block->comprelease_lsw =
+					acdb_data.pbe_blk->comprelease_lsw;
+	acdb_data.pbe_block->comprelease_msw =
+					acdb_data.pbe_blk->comprelease_msw;
+	acdb_data.pbe_block->compmakeupgain = acdb_data.pbe_blk->compmakeupgain;
+	acdb_data.pbe_block->baselimthreshold =
+					acdb_data.pbe_blk->baselimthreshold;
+	acdb_data.pbe_block->highlimthreshold =
+					acdb_data.pbe_blk->highlimthreshold;
+	acdb_data.pbe_block->basslimmakeupgain =
+					acdb_data.pbe_blk->basslimmakeupgain;
+	acdb_data.pbe_block->highlimmakeupgain =
+					acdb_data.pbe_blk->highlimmakeupgain;
+	acdb_data.pbe_block->limbassgrc = acdb_data.pbe_blk->limbassgrc;
+	acdb_data.pbe_block->limhighgrc = acdb_data.pbe_blk->limhighgrc;
+	acdb_data.pbe_block->limdelay = acdb_data.pbe_blk->limdelay;
+	memcpy(acdb_data.pbe_block->filter_coeffs,
+		acdb_data.pbe_blk->filter_coeffs, sizeof(u16)*90);
+	acdb_data.pbe_block->extpartition = 0;
+	acdb_data.pbe_block->extbuffsize_lsw = PBE_BUF_SIZE;
+	acdb_data.pbe_block->extbuffsize_msw = 0;
+	acdb_data.pbe_block->extbuffstart_lsw = ((u32)acdb_data.pbe_extbuff
+							& 0xFFFF);
+	acdb_data.pbe_block->extbuffstart_msw = (((u32)acdb_data.pbe_extbuff
+							& 0xFFFF0000) >> 16);
+	return 0;
+}
+
+
+static s32 acdb_calibrate_audpp(void)
+{
+	s32	result = 0;
+
+	result = acdb_fill_audpp_iir();
+	if (!IS_ERR_VALUE(result)) {
+		result = audpp_dsp_set_rx_iir(acdb_data.device_info->dev_id,
+				acdb_data.pp_iir->active_flag,
+					acdb_data.pp_iir, COPP);
+		if (result) {
+			MM_ERR("ACDB=> Failed to send IIR data to postproc\n");
+			result = -EINVAL;
+			goto done;
+		} else
+			MM_DBG("AUDPP is calibrated with IIR parameters"
+					" for COPP ID %d\n",
+						acdb_data.device_info->dev_id);
+	}
+	result = acdb_fill_audpp_mbadrc();
+	if (!IS_ERR_VALUE(result)) {
+		result = audpp_dsp_set_mbadrc(acdb_data.device_info->dev_id,
+					acdb_data.pp_mbadrc->enable,
+					acdb_data.pp_mbadrc, COPP);
+		if (result) {
+			MM_ERR("ACDB=> Failed to send MBADRC data to"
+					" postproc\n");
+			result = -EINVAL;
+			goto done;
+		} else
+			MM_DBG("AUDPP is calibrated with MBADRC parameters"
+					" for COPP ID %d\n",
+					acdb_data.device_info->dev_id);
+	}
+	result = acdb_fill_audpp_cal_gain();
+	if (!(IS_ERR_VALUE(result))) {
+		result = audpp_dsp_set_gain_rx(acdb_data.device_info->dev_id,
+					acdb_data.calib_gain_rx, COPP);
+		if (result) {
+			MM_ERR("ACDB=> Failed to send gain_rx"
+				" data to postproc\n");
+			result = -EINVAL;
+			goto done;
+		} else
+			MM_DBG("AUDPP is calibrated with calib_gain_rx\n");
+	}
+	result = acdb_fill_audpp_pbe();
+	if (!(IS_ERR_VALUE(result))) {
+		result = audpp_dsp_set_pbe(acdb_data.device_info->dev_id,
+					acdb_data.pbe_block->pbe_enable,
+					acdb_data.pbe_block, COPP);
+		if (result) {
+			MM_ERR("ACDB=> Failed to send pbe block"
+				"data to postproc\n");
+			result = -EINVAL;
+			goto done;
+		}
+		MM_DBG("AUDPP is calibarted with PBE\n");
+	}
+done:
+	return result;
+}
+
+static struct acdb_agc_block *get_audpreproc_agc_block(void)
+{
+	struct header *prs_hdr;
+	u32 index = 0;
+
+	while (index < acdb_data.acdb_result.used_bytes) {
+		prs_hdr = (struct header *)(acdb_data.virt_addr + index);
+		if (prs_hdr->dbor_signature == DBOR_SIGNATURE) {
+			if (prs_hdr->abid == ABID_AUDIO_AGC_TX) {
+				if (prs_hdr->iid == IID_AUDIO_AGC_PARAMETERS) {
+					MM_DBG("GOT ABID_AUDIO_AGC_TX\n");
+					return (struct acdb_agc_block *)
+						(acdb_data.virt_addr + index
+						 + sizeof(struct header));
+				}
+			} else {
+				index += prs_hdr->data_len +
+						sizeof(struct header);
+			}
+		} else {
+			break;
+		}
+	}
+	return NULL;
+}
+
+static s32 acdb_fill_audpreproc_agc(void)
+{
+	struct acdb_agc_block	*acdb_agc;
+
+	acdb_agc = get_audpreproc_agc_block();
+	if (!acdb_agc) {
+		MM_DBG("unable to find preproc agc parameters winding up\n");
+		return -1;
+	}
+	memset(acdb_data.preproc_agc, 0, sizeof(*acdb_data.preproc_agc));
+	acdb_data.preproc_agc->cmd_id = AUDPREPROC_CMD_CFG_AGC_PARAMS;
+	acdb_data.preproc_agc->stream_id = acdb_data.preproc_stream_id;
+	/* 0xFE00 to configure all parameters */
+	acdb_data.preproc_agc->tx_agc_param_mask = 0xFFFF;
+
+	if (acdb_agc->enable_status)
+		acdb_data.preproc_agc->tx_agc_enable_flag =
+			AUDPREPROC_CMD_TX_AGC_ENA_FLAG_ENA;
+	else
+		acdb_data.preproc_agc->tx_agc_enable_flag =
+			AUDPREPROC_CMD_TX_AGC_ENA_FLAG_DIS;
+
+	acdb_data.preproc_agc->comp_rlink_static_gain =
+		acdb_agc->comp_rlink_static_gain;
+	acdb_data.preproc_agc->comp_rlink_aig_flag =
+		acdb_agc->comp_rlink_aig_flag;
+	acdb_data.preproc_agc->expander_rlink_th =
+		acdb_agc->exp_rlink_threshold;
+	acdb_data.preproc_agc->expander_rlink_slope =
+		acdb_agc->exp_rlink_slope;
+	acdb_data.preproc_agc->compressor_rlink_th =
+		acdb_agc->comp_rlink_threshold;
+	acdb_data.preproc_agc->compressor_rlink_slope =
+		acdb_agc->comp_rlink_slope;
+
+	/* 0xFFF0 to configure all parameters */
+	acdb_data.preproc_agc->tx_adc_agc_param_mask = 0xFFFF;
+
+	acdb_data.preproc_agc->comp_rlink_aig_attackk =
+		acdb_agc->comp_rlink_aig_attack_k;
+	acdb_data.preproc_agc->comp_rlink_aig_leak_down =
+		acdb_agc->comp_rlink_aig_leak_down;
+	acdb_data.preproc_agc->comp_rlink_aig_leak_up =
+		acdb_agc->comp_rlink_aig_leak_up;
+	acdb_data.preproc_agc->comp_rlink_aig_max =
+		acdb_agc->comp_rlink_aig_max;
+	acdb_data.preproc_agc->comp_rlink_aig_min =
+		acdb_agc->comp_rlink_aig_min;
+	acdb_data.preproc_agc->comp_rlink_aig_releasek =
+		acdb_agc->comp_rlink_aig_release_k;
+	acdb_data.preproc_agc->comp_rlink_aig_leakrate_fast =
+		acdb_agc->comp_rlink_aig_sm_leak_rate_fast;
+	acdb_data.preproc_agc->comp_rlink_aig_leakrate_slow =
+		acdb_agc->comp_rlink_aig_sm_leak_rate_slow;
+	acdb_data.preproc_agc->comp_rlink_attackk_msw =
+		acdb_agc->comp_rlink_attack_k_msw;
+	acdb_data.preproc_agc->comp_rlink_attackk_lsw =
+		acdb_agc->comp_rlink_attack_k_lsw;
+	acdb_data.preproc_agc->comp_rlink_delay =
+		acdb_agc->comp_rlink_delay;
+	acdb_data.preproc_agc->comp_rlink_releasek_msw =
+		acdb_agc->comp_rlink_release_k_msw;
+	acdb_data.preproc_agc->comp_rlink_releasek_lsw =
+		acdb_agc->comp_rlink_release_k_lsw;
+	acdb_data.preproc_agc->comp_rlink_rms_tav =
+		acdb_agc->comp_rlink_rms_trav;
+	return 0;
+}
+
+static struct acdb_iir_block *get_audpreproc_irr_block(void)
+{
+
+	struct header *prs_hdr;
+	u32 index = 0;
+
+	while (index < acdb_data.acdb_result.used_bytes) {
+		prs_hdr = (struct header *)(acdb_data.virt_addr + index);
+
+		if (prs_hdr->dbor_signature == DBOR_SIGNATURE) {
+			if (prs_hdr->abid == ABID_AUDIO_IIR_TX) {
+				if (prs_hdr->iid == IID_AUDIO_IIR_COEFF)
+					return (struct acdb_iir_block *)
+						(acdb_data.virt_addr + index
+						 + sizeof(struct header));
+			} else {
+				index += prs_hdr->data_len +
+						sizeof(struct header);
+			}
+		} else {
+			break;
+		}
+	}
+	return NULL;
+}
+
+
+static s32 acdb_fill_audpreproc_iir(void)
+{
+	struct acdb_iir_block	*acdb_iir;
+
+
+	acdb_iir =  get_audpreproc_irr_block();
+	if (!acdb_iir) {
+		MM_DBG("unable to find preproc iir parameters winding up\n");
+		return -1;
+	}
+	memset(acdb_data.preproc_iir, 0, sizeof(*acdb_data.preproc_iir));
+
+	acdb_data.preproc_iir->cmd_id =
+		AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS;
+	acdb_data.preproc_iir->stream_id = acdb_data.preproc_stream_id;
+	acdb_data.preproc_iir->active_flag = acdb_iir->enable_flag;
+	acdb_data.preproc_iir->num_bands = acdb_iir->stage_count;
+
+	acdb_data.preproc_iir->numerator_coeff_b0_filter0_lsw =
+		acdb_iir->stages[0].b0_lo;
+	acdb_data.preproc_iir->numerator_coeff_b0_filter0_msw =
+		acdb_iir->stages[0].b0_hi;
+	acdb_data.preproc_iir->numerator_coeff_b1_filter0_lsw =
+		acdb_iir->stages[0].b1_lo;
+	acdb_data.preproc_iir->numerator_coeff_b1_filter0_msw =
+		acdb_iir->stages[0].b1_hi;
+	acdb_data.preproc_iir->numerator_coeff_b2_filter0_lsw =
+		acdb_iir->stages[0].b2_lo;
+	acdb_data.preproc_iir->numerator_coeff_b2_filter0_msw =
+		acdb_iir->stages[0].b2_hi;
+
+	acdb_data.preproc_iir->numerator_coeff_b0_filter1_lsw =
+		acdb_iir->stages[1].b0_lo;
+	acdb_data.preproc_iir->numerator_coeff_b0_filter1_msw =
+		acdb_iir->stages[1].b0_hi;
+	acdb_data.preproc_iir->numerator_coeff_b1_filter1_lsw =
+		acdb_iir->stages[1].b1_lo;
+	acdb_data.preproc_iir->numerator_coeff_b1_filter1_msw =
+		acdb_iir->stages[1].b1_hi;
+	acdb_data.preproc_iir->numerator_coeff_b2_filter1_lsw =
+		acdb_iir->stages[1].b2_lo;
+	acdb_data.preproc_iir->numerator_coeff_b2_filter1_msw =
+		acdb_iir->stages[1].b2_hi;
+
+	acdb_data.preproc_iir->numerator_coeff_b0_filter2_lsw =
+		acdb_iir->stages[2].b0_lo;
+	acdb_data.preproc_iir->numerator_coeff_b0_filter2_msw =
+		acdb_iir->stages[2].b0_hi;
+	acdb_data.preproc_iir->numerator_coeff_b1_filter2_lsw =
+		acdb_iir->stages[2].b1_lo;
+	acdb_data.preproc_iir->numerator_coeff_b1_filter2_msw =
+		acdb_iir->stages[2].b1_hi;
+	acdb_data.preproc_iir->numerator_coeff_b2_filter2_lsw =
+		acdb_iir->stages[2].b2_lo;
+	acdb_data.preproc_iir->numerator_coeff_b2_filter2_msw =
+		acdb_iir->stages[2].b2_hi;
+
+	acdb_data.preproc_iir->numerator_coeff_b0_filter3_lsw =
+		acdb_iir->stages[3].b0_lo;
+	acdb_data.preproc_iir->numerator_coeff_b0_filter3_msw =
+		acdb_iir->stages[3].b0_hi;
+	acdb_data.preproc_iir->numerator_coeff_b1_filter3_lsw =
+		acdb_iir->stages[3].b1_lo;
+	acdb_data.preproc_iir->numerator_coeff_b1_filter3_msw =
+		acdb_iir->stages[3].b1_hi;
+	acdb_data.preproc_iir->numerator_coeff_b2_filter3_lsw =
+		acdb_iir->stages[3].b2_lo;
+	acdb_data.preproc_iir->numerator_coeff_b2_filter3_msw =
+		acdb_iir->stages[3].b2_hi;
+
+	acdb_data.preproc_iir->denominator_coeff_a0_filter0_lsw =
+		acdb_iir->stages_a[0].a1_lo;
+	acdb_data.preproc_iir->denominator_coeff_a0_filter0_msw =
+		acdb_iir->stages_a[0].a1_hi;
+	acdb_data.preproc_iir->denominator_coeff_a1_filter0_lsw =
+		acdb_iir->stages_a[0].a2_lo;
+	acdb_data.preproc_iir->denominator_coeff_a1_filter0_msw =
+		acdb_iir->stages_a[0].a2_hi;
+
+	acdb_data.preproc_iir->denominator_coeff_a0_filter1_lsw =
+		acdb_iir->stages_a[1].a1_lo;
+	acdb_data.preproc_iir->denominator_coeff_a0_filter1_msw =
+		acdb_iir->stages_a[1].a1_hi;
+	acdb_data.preproc_iir->denominator_coeff_a1_filter1_lsw =
+		acdb_iir->stages_a[1].a2_lo;
+	acdb_data.preproc_iir->denominator_coeff_a1_filter1_msw =
+		acdb_iir->stages_a[1].a2_hi;
+
+	acdb_data.preproc_iir->denominator_coeff_a0_filter2_lsw =
+		acdb_iir->stages_a[2].a1_lo;
+	acdb_data.preproc_iir->denominator_coeff_a0_filter2_msw =
+		acdb_iir->stages_a[2].a1_hi;
+	acdb_data.preproc_iir->denominator_coeff_a1_filter2_lsw =
+		acdb_iir->stages_a[2].a2_lo;
+	acdb_data.preproc_iir->denominator_coeff_a1_filter2_msw =
+		acdb_iir->stages_a[2].a2_hi;
+
+	acdb_data.preproc_iir->denominator_coeff_a0_filter3_lsw =
+		acdb_iir->stages_a[3].a1_lo;
+	acdb_data.preproc_iir->denominator_coeff_a0_filter3_msw =
+		acdb_iir->stages_a[3].a1_hi;
+	acdb_data.preproc_iir->denominator_coeff_a1_filter3_lsw =
+		acdb_iir->stages_a[3].a2_lo;
+	acdb_data.preproc_iir->denominator_coeff_a1_filter3_msw =
+		acdb_iir->stages_a[3].a2_hi;
+
+	acdb_data.preproc_iir->shift_factor_filter0 =
+		acdb_iir->shift_factor[0];
+	acdb_data.preproc_iir->shift_factor_filter1 =
+		acdb_iir->shift_factor[1];
+	acdb_data.preproc_iir->shift_factor_filter2 =
+		acdb_iir->shift_factor[2];
+	acdb_data.preproc_iir->shift_factor_filter3 =
+		acdb_iir->shift_factor[3];
+
+	acdb_data.preproc_iir->pan_of_filter0 =
+		acdb_iir->pan[0];
+	acdb_data.preproc_iir->pan_of_filter1 =
+		acdb_iir->pan[1];
+	acdb_data.preproc_iir->pan_of_filter2 =
+		acdb_iir->pan[2];
+	acdb_data.preproc_iir->pan_of_filter3 =
+		acdb_iir->pan[3];
+	return 0;
+}
+
+static struct acdb_calib_gain_tx *get_audpreproc_cal_gain(void)
+{
+	struct header *prs_hdr;
+	u32 index = 0;
+
+	while (index < acdb_data.acdb_result.used_bytes) {
+		prs_hdr = (struct header *)(acdb_data.virt_addr + index);
+		if (prs_hdr->dbor_signature == DBOR_SIGNATURE) {
+			if (prs_hdr->abid == ABID_AUDIO_CALIBRATION_GAIN_TX) {
+				if (prs_hdr->iid ==
+					IID_AUDIO_CALIBRATION_GAIN_TX) {
+					MM_DBG("Got audpreproc_calib_gain_tx"
+					" block\n");
+					return (struct acdb_calib_gain_tx *)
+						(acdb_data.virt_addr + index
+						+ sizeof(struct header));
+				}
+			} else {
+				index += prs_hdr->data_len +
+					sizeof(struct header);
+			}
+		} else {
+			break;
+		}
+	}
+	return NULL;
+}
+
+static s32 acdb_fill_audpreproc_cal_gain(void)
+{
+	struct acdb_calib_gain_tx *acdb_calib_gain_tx = NULL;
+
+	acdb_calib_gain_tx = get_audpreproc_cal_gain();
+	if (acdb_calib_gain_tx == NULL) {
+		MM_ERR("unable to find  audpreproc"
+			" calibration block returning\n");
+		return -1;
+	}
+	MM_DBG("Calibration value"
+		" for calib_gain_tx %d\n", acdb_calib_gain_tx->audprecalgain);
+	memset(acdb_data.calib_gain_tx, 0, sizeof(*acdb_data.calib_gain_tx));
+
+	acdb_data.calib_gain_tx->cmd_id =
+					AUDPREPROC_CMD_CFG_CAL_GAIN_PARAMS;
+	acdb_data.calib_gain_tx->stream_id = acdb_data.preproc_stream_id;
+	acdb_data.calib_gain_tx->audprecalgain =
+					acdb_calib_gain_tx->audprecalgain;
+	return 0;
+}
+
+static struct acdb_rmc_block *get_rmc_blk(void)
+{
+	struct header *prs_hdr;
+	u32 index = 0;
+
+	while (index < acdb_data.acdb_result.used_bytes) {
+		prs_hdr = (struct header *)(acdb_data.virt_addr + index);
+		if (prs_hdr->dbor_signature == DBOR_SIGNATURE) {
+			if (prs_hdr->abid == ABID_AUDIO_RMC_TX) {
+				if (prs_hdr->iid ==
+					IID_AUDIO_RMC_PARAM) {
+					MM_DBG("Got afe_rmc block\n");
+					return (struct acdb_rmc_block *)
+						(acdb_data.virt_addr + index
+						+ sizeof(struct header));
+				}
+			} else {
+				index += prs_hdr->data_len +
+					sizeof(struct header);
+			}
+		} else {
+			break;
+		}
+	}
+	return NULL;
+}
+
+struct acdb_fluence_block *get_audpp_fluence_block(void)
+{
+	struct header *prs_hdr;
+	u32 index = 0;
+
+	while (index < acdb_data.acdb_result.used_bytes) {
+		prs_hdr = (struct header *)(acdb_data.virt_addr + index);
+
+		if (prs_hdr->dbor_signature == DBOR_SIGNATURE) {
+			if (prs_hdr->abid == ABID_AUDIO_FLUENCE_TX) {
+				if (prs_hdr->iid == IID_AUDIO_FLUENCE_TX) {
+					MM_DBG("got fluence block\n");
+					return (struct acdb_fluence_block *)
+						(acdb_data.virt_addr + index
+						+ sizeof(struct header));
+				}
+			} else {
+				index += prs_hdr->data_len +
+					sizeof(struct header);
+			}
+		} else {
+			break;
+		}
+	}
+	return NULL;
+}
+
+static s32 acdb_fill_audpreproc_fluence(void)
+{
+	struct acdb_fluence_block *fluence_block = NULL;
+	fluence_block = get_audpp_fluence_block();
+	if (!fluence_block) {
+		MM_ERR("error in finding fluence block\n");
+		return -EPERM;
+	}
+	memset(&acdb_data.preproc_lvnv, 0, sizeof(
+				struct audpreproc_cmd_cfg_lvnv_param));
+	memcpy(acdb_data.fluence_extbuff_virt,
+			&fluence_block->cs_tuningMode,
+			(sizeof(struct acdb_fluence_block) -
+					sizeof(fluence_block->csmode)));
+	acdb_data.preproc_lvnv.cmd_id = AUDPREPROC_CMD_CFG_LVNV_PARMS;
+	acdb_data.preproc_lvnv.stream_id = acdb_data.preproc_stream_id;
+	acdb_data.preproc_lvnv.cs_mode = fluence_block->csmode;
+	acdb_data.preproc_lvnv.lvnv_ext_buf_size = FLUENCE_BUF_SIZE;
+	acdb_data.preproc_lvnv.lvnv_ext_buf_start_lsw =\
+				((u32)(acdb_data.fluence_extbuff)\
+						& 0x0000FFFF);
+	acdb_data.preproc_lvnv.lvnv_ext_buf_start_msw =\
+				(((u32)acdb_data.fluence_extbuff\
+					& 0xFFFF0000) >> 16);
+	return 0;
+}
+
+s32 acdb_calibrate_audpreproc(void)
+{
+	s32	result = 0;
+	struct acdb_rmc_block *acdb_rmc = NULL;
+
+	result = acdb_fill_audpreproc_agc();
+	if (!IS_ERR_VALUE(result)) {
+		result = audpreproc_dsp_set_agc(acdb_data.preproc_agc, sizeof(
+					struct audpreproc_cmd_cfg_agc_params));
+		if (result) {
+			MM_ERR("ACDB=> Failed to send AGC data to preproc)\n");
+			result = -EINVAL;
+			goto done;
+		} else
+			MM_DBG("AUDPREC is calibrated with AGC parameters"
+				" for COPP ID %d and AUDREC session %d\n",
+					acdb_data.device_info->dev_id,
+					acdb_data.preproc_stream_id);
+	}
+	result = acdb_fill_audpreproc_iir();
+	if (!IS_ERR_VALUE(result)) {
+		result = audpreproc_dsp_set_iir(acdb_data.preproc_iir,
+				sizeof(struct\
+				audpreproc_cmd_cfg_iir_tuning_filter_params));
+		if (result) {
+			MM_ERR("ACDB=> Failed to send IIR data to preproc\n");
+			result = -EINVAL;
+			goto done;
+		} else
+			MM_DBG("audpreproc is calibrated with iir parameters"
+			" for COPP ID %d and AUREC session %d\n",
+					acdb_data.device_info->dev_id,
+					acdb_data.preproc_stream_id);
+	}
+	result = acdb_fill_audpreproc_cal_gain();
+	if (!(IS_ERR_VALUE(result))) {
+		result = audpreproc_dsp_set_gain_tx(acdb_data.calib_gain_tx,
+				sizeof(struct audpreproc_cmd_cfg_cal_gain));
+		if (result) {
+			MM_ERR("ACDB=> Failed to send calib_gain_tx"
+				" data to preproc\n");
+			result = -EINVAL;
+			goto done;
+		} else
+			MM_DBG("AUDPREPROC is calibrated"
+				" with calib_gain_tx\n");
+	}
+	if (acdb_data.build_id[17] != '0') {
+		acdb_rmc = get_rmc_blk();
+		if (acdb_rmc != NULL) {
+			result = afe_config_rmc_block(acdb_rmc);
+			if (result) {
+				MM_ERR("ACDB=> Failed to send rmc"
+					" data to afe\n");
+				result = -EINVAL;
+				goto done;
+			} else
+				MM_DBG("AFE is calibrated with rmc params\n");
+		} else
+			MM_DBG("RMC block was not found\n");
+	}
+	if (!acdb_data.fleuce_feature_status[acdb_data.preproc_stream_id]) {
+		result = acdb_fill_audpreproc_fluence();
+		if (!(IS_ERR_VALUE(result))) {
+			result = audpreproc_dsp_set_lvnv(
+					&acdb_data.preproc_lvnv,
+					sizeof(struct\
+					audpreproc_cmd_cfg_lvnv_param));
+			if (result) {
+				MM_ERR("ACDB=> Failed to send lvnv "
+						"data to preproc\n");
+				result = -EINVAL;
+				goto done;
+			} else
+				MM_DBG("AUDPREPROC is calibrated"
+						" with lvnv parameters\n");
+		} else
+			MM_ERR("fluence block is not found\n");
+	} else
+		MM_DBG("fluence block override\n");
+done:
+	return result;
+}
+
+static s32 acdb_send_calibration(void)
+{
+	s32 result = 0;
+
+	if ((acdb_data.device_info->dev_type & RX_DEVICE) == 1) {
+		result = acdb_calibrate_audpp();
+		if (result)
+			goto done;
+	} else if ((acdb_data.device_info->dev_type & TX_DEVICE) == 2) {
+		result = acdb_calibrate_audpreproc();
+		if (result)
+			goto done;
+		if (acdb_data.preproc_stream_id == 0)
+			acdb_data.audrec_applied |= AUDREC0_READY;
+		else if (acdb_data.preproc_stream_id == 1)
+			acdb_data.audrec_applied |= AUDREC1_READY;
+		else if (acdb_data.preproc_stream_id == 2)
+			acdb_data.audrec_applied |= AUDREC2_READY;
+		MM_DBG("acdb_data.audrec_applied = %x\n",
+					acdb_data.audrec_applied);
+	}
+done:
+	return result;
+}
+
+static u8 check_tx_acdb_values_cached(void)
+{
+	u8 stream_id  = acdb_data.preproc_stream_id;
+
+	if ((acdb_data.device_info->dev_id ==
+		acdb_cache_tx[stream_id].device_info.dev_id) &&
+		(acdb_data.device_info->sample_rate ==
+		acdb_cache_tx[stream_id].device_info.sample_rate) &&
+		(acdb_data.device_info->acdb_id ==
+		acdb_cache_tx[stream_id].device_info.acdb_id) &&
+		(acdb_cache_tx[stream_id].node_status ==
+						ACDB_VALUES_FILLED))
+		return 0;
+	else
+		return 1;
+}
+
+static void handle_tx_device_ready_callback(void)
+{
+	u8 i = 0;
+	u8 ret = 0;
+	u8 acdb_value_apply = 0;
+	u8 result = 0;
+	u8 stream_id = acdb_data.preproc_stream_id;
+
+	if (acdb_data.multiple_sessions) {
+		for (i = 0; i < MAX_AUDREC_SESSIONS; i++) {
+			/*check is to exclude copying acdb values in the
+			current node pointed by acdb_data structure*/
+			if (acdb_cache_tx[i].phys_addr_acdb_values !=
+							acdb_data.phys_addr) {
+				ret = check_device_info_already_present(\
+							*acdb_data.device_info,
+							&acdb_cache_tx[i]);
+				if (ret) {
+					memcpy((char *)acdb_cache_tx[i].\
+						virt_addr_acdb_values,
+						(char *)acdb_data.virt_addr,
+								ACDB_BUF_SIZE);
+					acdb_cache_tx[i].node_status =
+							ACDB_VALUES_FILLED;
+				}
+			}
+		}
+		acdb_data.multiple_sessions = 0;
+	}
+	/*check wheather AUDREC enabled before device call backs*/
+	if ((acdb_data.acdb_state & AUDREC0_READY) &&
+			!(acdb_data.audrec_applied & AUDREC0_READY)) {
+		MM_DBG("AUDREC0 already enabled apply acdb values\n");
+		acdb_value_apply |= AUDREC0_READY;
+	} else if ((acdb_data.acdb_state & AUDREC1_READY) &&
+			!(acdb_data.audrec_applied & AUDREC1_READY)) {
+		MM_DBG("AUDREC1 already enabled apply acdb values\n");
+		acdb_value_apply |= AUDREC1_READY;
+	} else if ((acdb_data.acdb_state & AUDREC2_READY) &&
+			!(acdb_data.audrec_applied & AUDREC2_READY)) {
+		MM_DBG("AUDREC2 already enabled apply acdb values\n");
+		acdb_value_apply |= AUDREC2_READY;
+	}
+	if (acdb_value_apply) {
+		if (session_info[stream_id].sampling_freq)
+			acdb_data.device_info->sample_rate =
+					session_info[stream_id].sampling_freq;
+		result = check_tx_acdb_values_cached();
+		if (result) {
+			result = acdb_get_calibration();
+			if (result < 0) {
+				MM_ERR("Not able to get calibration"
+						" data continue\n");
+				return;
+			}
+		}
+		acdb_cache_tx[stream_id].node_status = ACDB_VALUES_FILLED;
+		acdb_send_calibration();
+	}
+}
+
+static struct acdb_cache_node *get_acdb_values_from_cache_tx(u32 stream_id)
+{
+	MM_DBG("searching node with stream_id %d\n", stream_id);
+	if ((acdb_cache_tx[stream_id].stream_id == stream_id) &&
+			(acdb_cache_tx[stream_id].node_status ==
+					ACDB_VALUES_NOT_FILLED)) {
+			return &acdb_cache_tx[stream_id];
+	}
+	MM_DBG("Error! in finding node\n");
+	return NULL;
+}
+
+static void update_acdb_data_struct(struct acdb_cache_node *cur_node)
+{
+	if (cur_node) {
+		acdb_data.device_info = &cur_node->device_info;
+		acdb_data.virt_addr = cur_node->virt_addr_acdb_values;
+		acdb_data.phys_addr = cur_node->phys_addr_acdb_values;
+	} else
+		MM_ERR("error in curent node\n");
+}
+
+static void send_acdb_values_for_active_devices(void)
+{
+	u32 i = 0;
+	for (i = 0; i < MAX_COPP_NODE_SUPPORTED; i++) {
+		if (acdb_cache_rx[i].node_status ==
+					ACDB_VALUES_FILLED) {
+			update_acdb_data_struct(&acdb_cache_rx[i]);
+			if (acdb_data.acdb_state & CAL_DATA_READY)
+				acdb_send_calibration();
+		}
+	}
+}
+
+static s32 initialize_rpc(void)
+{
+	s32 result = 0;
+
+	result = daldevice_attach(DALDEVICEID_ACDB, ACDB_PORT_NAME,
+			ACDB_CPU, &acdb_data.handle);
+
+	if (result) {
+		MM_ERR("ACDB=> Device Attach failed\n");
+		result = -ENODEV;
+		goto done;
+	}
+done:
+	return result;
+}
+
+static u32 allocate_memory_acdb_cache_tx(void)
+{
+	u32 result = 0;
+	u32 i = 0;
+	u32 err = 0;
+	/*initialize local cache */
+	for (i = 0; i < MAX_AUDREC_SESSIONS; i++) {
+		acdb_cache_tx[i].phys_addr_acdb_values =
+				allocate_contiguous_ebi_nomap(ACDB_BUF_SIZE,
+								SZ_4K);
+
+		if (!acdb_cache_tx[i].phys_addr_acdb_values) {
+			MM_ERR("ACDB=> Cannot allocate physical memory\n");
+			result = -ENOMEM;
+			goto error;
+		}
+		acdb_cache_tx[i].map_v_addr = ioremap(
+					acdb_cache_tx[i].phys_addr_acdb_values,
+						ACDB_BUF_SIZE);
+		if (IS_ERR(acdb_cache_tx[i].map_v_addr)) {
+			MM_ERR("ACDB=> Could not map physical address\n");
+			result = -ENOMEM;
+			free_contiguous_memory_by_paddr(
+					acdb_cache_tx[i].phys_addr_acdb_values);
+			goto error;
+		}
+		acdb_cache_tx[i].virt_addr_acdb_values =
+					acdb_cache_tx[i].map_v_addr;
+		memset(acdb_cache_tx[i].virt_addr_acdb_values, 0,
+						ACDB_BUF_SIZE);
+	}
+	return result;
+error:
+	for (err = 0; err < i; err++) {
+		iounmap(acdb_cache_tx[err].map_v_addr);
+		free_contiguous_memory_by_paddr(
+				acdb_cache_tx[err].phys_addr_acdb_values);
+	}
+	return result;
+}
+
+static u32 allocate_memory_acdb_cache_rx(void)
+{
+	u32 result = 0;
+	u32 i = 0;
+	u32 err = 0;
+
+	/*initialize local cache */
+	for (i = 0; i < MAX_COPP_NODE_SUPPORTED; i++) {
+		acdb_cache_rx[i].phys_addr_acdb_values =
+					allocate_contiguous_ebi_nomap(
+						ACDB_BUF_SIZE, SZ_4K);
+
+		if (!acdb_cache_rx[i].phys_addr_acdb_values) {
+			MM_ERR("ACDB=> Can not allocate physical memory\n");
+			result = -ENOMEM;
+			goto error;
+		}
+		acdb_cache_rx[i].map_v_addr =
+				ioremap(acdb_cache_rx[i].phys_addr_acdb_values,
+					ACDB_BUF_SIZE);
+		if (IS_ERR(acdb_cache_rx[i].map_v_addr)) {
+			MM_ERR("ACDB=> Could not map physical address\n");
+			result = -ENOMEM;
+			free_contiguous_memory_by_paddr(
+					acdb_cache_rx[i].phys_addr_acdb_values);
+			goto error;
+		}
+		acdb_cache_rx[i].virt_addr_acdb_values =
+					acdb_cache_rx[i].map_v_addr;
+		memset(acdb_cache_rx[i].virt_addr_acdb_values, 0,
+						ACDB_BUF_SIZE);
+	}
+	return result;
+error:
+	for (err = 0; err < i; err++) {
+		iounmap(acdb_cache_rx[err].map_v_addr);
+		free_contiguous_memory_by_paddr(
+				acdb_cache_rx[err].phys_addr_acdb_values);
+	}
+	return result;
+}
+
+static u32 allocate_memory_acdb_get_blk(void)
+{
+	u32 result = 0;
+	acdb_data.get_blk_paddr = allocate_contiguous_ebi_nomap(
+						ACDB_BUF_SIZE, SZ_4K);
+	if (!acdb_data.get_blk_paddr) {
+		MM_ERR("ACDB=> Cannot allocate physical memory\n");
+		result = -ENOMEM;
+		goto error;
+	}
+	acdb_data.map_v_get_blk = ioremap(acdb_data.get_blk_paddr,
+					ACDB_BUF_SIZE);
+	if (IS_ERR(acdb_data.map_v_get_blk)) {
+		MM_ERR("ACDB=> Could not map physical address\n");
+		result = -ENOMEM;
+		free_contiguous_memory_by_paddr(
+					acdb_data.get_blk_paddr);
+		goto error;
+	}
+	acdb_data.get_blk_kvaddr = acdb_data.map_v_get_blk;
+	memset(acdb_data.get_blk_kvaddr, 0, ACDB_BUF_SIZE);
+error:
+	return result;
+}
+
+static void free_memory_acdb_cache_rx(void)
+{
+	u32 i = 0;
+
+	for (i = 0; i < MAX_COPP_NODE_SUPPORTED; i++) {
+		iounmap(acdb_cache_rx[i].map_v_addr);
+		free_contiguous_memory_by_paddr(
+				acdb_cache_rx[i].phys_addr_acdb_values);
+	}
+}
+
+static void free_memory_acdb_cache_tx(void)
+{
+	u32 i = 0;
+
+	for (i = 0; i < MAX_AUDREC_SESSIONS; i++) {
+		iounmap(acdb_cache_tx[i].map_v_addr);
+		free_contiguous_memory_by_paddr(
+				acdb_cache_tx[i].phys_addr_acdb_values);
+	}
+}
+
+static void free_memory_acdb_get_blk(void)
+{
+	iounmap(acdb_data.map_v_get_blk);
+	free_contiguous_memory_by_paddr(acdb_data.get_blk_paddr);
+}
+
+static s32 initialize_memory(void)
+{
+	s32 result = 0;
+
+	result = allocate_memory_acdb_get_blk();
+	if (result < 0) {
+		MM_ERR("memory allocation for get blk failed\n");
+		goto done;
+	}
+
+	result = allocate_memory_acdb_cache_rx();
+	if (result < 0) {
+		MM_ERR("memory allocation for rx cache is failed\n");
+		free_memory_acdb_get_blk();
+		goto done;
+	}
+	result = allocate_memory_acdb_cache_tx();
+	if (result < 0) {
+		MM_ERR("memory allocation for tx cache is failed\n");
+		free_memory_acdb_get_blk();
+		free_memory_acdb_cache_rx();
+		goto done;
+	}
+	acdb_data.pp_iir = kmalloc(sizeof(*acdb_data.pp_iir),
+		GFP_KERNEL);
+	if (acdb_data.pp_iir == NULL) {
+		MM_ERR("ACDB=> Could not allocate postproc iir memory\n");
+		free_memory_acdb_get_blk();
+		free_memory_acdb_cache_rx();
+		free_memory_acdb_cache_tx();
+		result = -ENOMEM;
+		goto done;
+	}
+
+	acdb_data.pp_mbadrc = kmalloc(sizeof(*acdb_data.pp_mbadrc), GFP_KERNEL);
+	if (acdb_data.pp_mbadrc == NULL) {
+		MM_ERR("ACDB=> Could not allocate postproc mbadrc memory\n");
+		free_memory_acdb_get_blk();
+		free_memory_acdb_cache_rx();
+		free_memory_acdb_cache_tx();
+		kfree(acdb_data.pp_iir);
+		result = -ENOMEM;
+		goto done;
+	}
+	acdb_data.calib_gain_rx = kmalloc(sizeof(*acdb_data.calib_gain_rx),
+							GFP_KERNEL);
+	if (acdb_data.calib_gain_rx == NULL) {
+		MM_ERR("ACDB=> Could not allocate"
+			" postproc calib_gain_rx memory\n");
+		free_memory_acdb_get_blk();
+		free_memory_acdb_cache_rx();
+		free_memory_acdb_cache_tx();
+		kfree(acdb_data.pp_iir);
+		kfree(acdb_data.pp_mbadrc);
+		result = -ENOMEM;
+		goto done;
+	}
+
+	acdb_data.preproc_agc = kmalloc(sizeof(*acdb_data.preproc_agc),
+							GFP_KERNEL);
+	if (acdb_data.preproc_agc == NULL) {
+		MM_ERR("ACDB=> Could not allocate preproc agc memory\n");
+		free_memory_acdb_get_blk();
+		free_memory_acdb_cache_rx();
+		free_memory_acdb_cache_tx();
+		kfree(acdb_data.pp_iir);
+		kfree(acdb_data.pp_mbadrc);
+		kfree(acdb_data.calib_gain_rx);
+		result = -ENOMEM;
+		goto done;
+	}
+
+	acdb_data.preproc_iir = kmalloc(sizeof(*acdb_data.preproc_iir),
+							GFP_KERNEL);
+	if (acdb_data.preproc_iir == NULL) {
+		MM_ERR("ACDB=> Could not allocate preproc iir memory\n");
+		free_memory_acdb_get_blk();
+		free_memory_acdb_cache_rx();
+		free_memory_acdb_cache_tx();
+		kfree(acdb_data.pp_iir);
+		kfree(acdb_data.pp_mbadrc);
+		kfree(acdb_data.calib_gain_rx);
+		kfree(acdb_data.preproc_agc);
+		result = -ENOMEM;
+		goto done;
+	}
+	acdb_data.calib_gain_tx = kmalloc(sizeof(*acdb_data.calib_gain_tx),
+							GFP_KERNEL);
+	if (acdb_data.calib_gain_tx == NULL) {
+		MM_ERR("ACDB=> Could not allocate"
+			" preproc calib_gain_tx memory\n");
+		free_memory_acdb_get_blk();
+		free_memory_acdb_cache_rx();
+		free_memory_acdb_cache_tx();
+		kfree(acdb_data.pp_iir);
+		kfree(acdb_data.pp_mbadrc);
+		kfree(acdb_data.calib_gain_rx);
+		kfree(acdb_data.preproc_agc);
+		kfree(acdb_data.preproc_iir);
+		result = -ENOMEM;
+		goto done;
+	}
+	acdb_data.pbe_block = kmalloc(sizeof(*acdb_data.pbe_block),
+						GFP_KERNEL);
+	if (acdb_data.pbe_block == NULL) {
+		MM_ERR("ACDB=> Could not allocate pbe_block memory\n");
+		free_memory_acdb_get_blk();
+		free_memory_acdb_cache_rx();
+		free_memory_acdb_cache_tx();
+		kfree(acdb_data.pp_iir);
+		kfree(acdb_data.pp_mbadrc);
+		kfree(acdb_data.calib_gain_rx);
+		kfree(acdb_data.preproc_agc);
+		kfree(acdb_data.preproc_iir);
+		kfree(acdb_data.calib_gain_tx);
+		result = -ENOMEM;
+		goto done;
+	}
+	acdb_data.pbe_extbuff = (u16 *) allocate_contiguous_ebi_nomap(
+						PBE_BUF_SIZE, SZ_4K);
+	if (!acdb_data.pbe_extbuff) {
+		MM_ERR("ACDB=> Cannot allocate physical memory\n");
+		free_memory_acdb_get_blk();
+		free_memory_acdb_cache_rx();
+		free_memory_acdb_cache_tx();
+		kfree(acdb_data.pp_iir);
+		kfree(acdb_data.pp_mbadrc);
+		kfree(acdb_data.calib_gain_rx);
+		kfree(acdb_data.preproc_agc);
+		kfree(acdb_data.preproc_iir);
+		kfree(acdb_data.calib_gain_tx);
+		kfree(acdb_data.pbe_block);
+		result = -ENOMEM;
+		goto done;
+	}
+	acdb_data.fluence_extbuff = allocate_contiguous_ebi_nomap(
+					FLUENCE_BUF_SIZE, SZ_4K);
+	if (!acdb_data.fluence_extbuff) {
+		MM_ERR("ACDB=> cannot allocate physical memory for "
+					"fluence block\n");
+		free_memory_acdb_get_blk();
+		free_memory_acdb_cache_rx();
+		free_memory_acdb_cache_tx();
+		kfree(acdb_data.pp_iir);
+		kfree(acdb_data.pp_mbadrc);
+		kfree(acdb_data.calib_gain_rx);
+		kfree(acdb_data.preproc_agc);
+		kfree(acdb_data.preproc_iir);
+		kfree(acdb_data.calib_gain_tx);
+		kfree(acdb_data.pbe_block);
+		free_contiguous_memory_by_paddr((int32_t)acdb_data.pbe_extbuff);
+		result = -ENOMEM;
+		goto done;
+	}
+	acdb_data.map_v_fluence = ioremap(
+				acdb_data.fluence_extbuff,
+				FLUENCE_BUF_SIZE);
+	if (IS_ERR(acdb_data.map_v_fluence)) {
+		MM_ERR("ACDB=> Could not map physical address\n");
+		free_memory_acdb_get_blk();
+		free_memory_acdb_cache_rx();
+		free_memory_acdb_cache_tx();
+		kfree(acdb_data.pp_iir);
+		kfree(acdb_data.pp_mbadrc);
+		kfree(acdb_data.calib_gain_rx);
+		kfree(acdb_data.preproc_agc);
+		kfree(acdb_data.preproc_iir);
+		kfree(acdb_data.calib_gain_tx);
+		kfree(acdb_data.pbe_block);
+		free_contiguous_memory_by_paddr(
+				(int32_t)acdb_data.pbe_extbuff);
+		free_contiguous_memory_by_paddr(
+				(int32_t)acdb_data.fluence_extbuff);
+		result = -ENOMEM;
+		goto done;
+	} else
+		acdb_data.fluence_extbuff_virt =
+					acdb_data.map_v_fluence;
+done:
+	return result;
+}
+
+static u32 free_acdb_cache_node(union auddev_evt_data *evt)
+{
+	u32 session_id;
+	if ((evt->audcal_info.dev_type & TX_DEVICE) == 2) {
+		/*Second argument to find_first_bit should be maximum number
+		of bits interested
+		*/
+		session_id = find_first_bit(
+				(unsigned long *)&(evt->audcal_info.sessions),
+				sizeof(evt->audcal_info.sessions) * 8);
+		MM_DBG("freeing node %d for tx device", session_id);
+		acdb_cache_tx[session_id].
+			node_status = ACDB_VALUES_NOT_FILLED;
+	} else {
+			MM_DBG("freeing rx cache node %d\n",
+						evt->audcal_info.dev_id);
+			acdb_cache_rx[evt->audcal_info.dev_id].
+				node_status = ACDB_VALUES_NOT_FILLED;
+	}
+	return 0;
+}
+
+static u8 check_device_change(struct auddev_evt_audcal_info audcal_info)
+{
+	if (!acdb_data.device_info) {
+		MM_ERR("not pointing to previous valid device detail\n");
+		return 1; /*device info will not be pointing to*/
+			/* valid device when acdb driver comes up*/
+	}
+	if ((audcal_info.dev_id == acdb_data.device_info->dev_id) &&
+		(audcal_info.sample_rate ==
+				acdb_data.device_info->sample_rate) &&
+		(audcal_info.acdb_id == acdb_data.device_info->acdb_id)) {
+		return 0;
+	}
+	return 1;
+}
+
+static void device_cb(u32 evt_id, union auddev_evt_data *evt, void *private)
+{
+	struct auddev_evt_audcal_info	audcal_info;
+	struct acdb_cache_node *acdb_cache_free_node =  NULL;
+	u32 stream_id = 0;
+	u8 ret = 0;
+	u8 count = 0;
+	u8 i = 0;
+	u8 device_change = 0;
+
+	if (!((evt_id == AUDDEV_EVT_DEV_RDY) ||
+		(evt_id == AUDDEV_EVT_DEV_RLS))) {
+		goto done;
+	}
+	/*if session value is zero it indicates that device call back is for
+	voice call we will drop the request as acdb values for voice call is
+	not applied from acdb driver*/
+	if (!evt->audcal_info.sessions) {
+		MM_DBG("no active sessions and call back is for"
+				" voice call\n");
+		goto done;
+	}
+	if (evt_id == AUDDEV_EVT_DEV_RLS) {
+		MM_DBG("got release command for dev %d\n",
+					evt->audcal_info.dev_id);
+		acdb_data.acdb_state &= ~CAL_DATA_READY;
+		free_acdb_cache_node(evt);
+		/*reset the applied flag for the session routed to the device*/
+		acdb_data.audrec_applied &= ~(evt->audcal_info.sessions
+							<< AUDREC_OFFSET);
+		goto done;
+	}
+	if (((evt->audcal_info.dev_type & RX_DEVICE) == 1) &&
+			(evt->audcal_info.acdb_id == PSEUDO_ACDB_ID)) {
+		MM_INFO("device cb is for rx device with pseudo acdb id\n");
+		goto done;
+	}
+	audcal_info = evt->audcal_info;
+	MM_DBG("dev_id = %d\n", audcal_info.dev_id);
+	MM_DBG("sample_rate = %d\n", audcal_info.sample_rate);
+	MM_DBG("acdb_id = %d\n", audcal_info.acdb_id);
+	MM_DBG("sessions = %d\n", audcal_info.sessions);
+	MM_DBG("acdb_state = %x\n", acdb_data.acdb_state);
+	mutex_lock(&acdb_data.acdb_mutex);
+	device_change = check_device_change(audcal_info);
+	if (!device_change) {
+		if ((audcal_info.dev_type & TX_DEVICE) == 2) {
+			if (!(acdb_data.acdb_state & AUDREC0_READY))
+				acdb_data.audrec_applied &= ~AUDREC0_READY;
+			if (!(acdb_data.acdb_state & AUDREC1_READY))
+				acdb_data.audrec_applied &= ~AUDREC1_READY;
+			if (!(acdb_data.acdb_state & AUDREC2_READY))
+				acdb_data.audrec_applied &= ~AUDREC2_READY;
+				acdb_data.acdb_state &= ~CAL_DATA_READY;
+				goto update_cache;
+		}
+	} else
+		/* state is updated to querry the modem for values */
+		acdb_data.acdb_state &= ~CAL_DATA_READY;
+
+update_cache:
+	if ((audcal_info.dev_type & TX_DEVICE) == 2) {
+		/*loop is to take care of use case:- multiple Audrec
+		sessions are routed before enabling the device in this use
+		case we will get the sessions value as bits set for all the
+		sessions routed before device enable, so we should take care
+		of copying device info to all the sessions*/
+		for (i = 0; i < MAX_AUDREC_SESSIONS; i++) {
+			stream_id = ((audcal_info.sessions >> i) & 0x01);
+			if (stream_id) {
+				acdb_cache_free_node =	&acdb_cache_tx[i];
+				ret  = check_device_info_already_present(
+							audcal_info,
+							acdb_cache_free_node);
+				acdb_cache_free_node->stream_id = i;
+				acdb_data.cur_tx_session = i;
+				count++;
+			}
+		}
+		if (count > 1)
+			acdb_data.multiple_sessions = 1;
+	} else {
+		acdb_cache_free_node = &acdb_cache_rx[audcal_info.dev_id];
+		ret = check_device_info_already_present(audcal_info,
+						acdb_cache_free_node);
+		if (ret == 1) {
+			MM_DBG("got device ready call back for another "
+					"audplay task sessions on same COPP\n");
+			/*stream_id is used to keep track of number of active*/
+			/*sessions active on this device*/
+			acdb_cache_free_node->stream_id++;
+			mutex_unlock(&acdb_data.acdb_mutex);
+			goto done;
+		}
+		acdb_cache_free_node->stream_id++;
+	}
+	update_acdb_data_struct(acdb_cache_free_node);
+	acdb_data.device_cb_compl = 1;
+	mutex_unlock(&acdb_data.acdb_mutex);
+	wake_up(&acdb_data.wait);
+done:
+	return;
+}
+
+
+static s32 register_device_cb(void)
+{
+	s32 result = 0;
+
+	result = auddev_register_evt_listner((AUDDEV_EVT_DEV_RDY
+						| AUDDEV_EVT_DEV_RLS),
+		AUDDEV_CLNT_AUDIOCAL, 0, device_cb, (void *)&acdb_data);
+
+	if (result) {
+		MM_ERR("ACDB=> Could not register device callback\n");
+		result = -ENODEV;
+		goto done;
+	}
+done:
+	return result;
+}
+
+static void audpp_cb(void *private, u32 id, u16 *msg)
+{
+	MM_DBG("\n");
+	if (id != AUDPP_MSG_CFG_MSG)
+		goto done;
+
+	if (msg[0] == AUDPP_MSG_ENA_DIS) {
+		if (--acdb_cache_rx[acdb_data.\
+				device_info->dev_id].stream_id <= 0) {
+			acdb_data.acdb_state &= ~AUDPP_READY;
+			acdb_cache_rx[acdb_data.device_info->dev_id]\
+					.stream_id = 0;
+			MM_DBG("AUDPP_MSG_ENA_DIS\n");
+		}
+		goto done;
+	}
+
+	acdb_data.acdb_state |= AUDPP_READY;
+	acdb_data.audpp_cb_compl = 1;
+	wake_up(&acdb_data.wait);
+done:
+	return;
+}
+
+static s8 handle_audpreproc_cb(void)
+{
+	struct acdb_cache_node *acdb_cached_values;
+	s8 result = 0;
+	u8 stream_id = acdb_data.preproc_stream_id;
+	acdb_data.preproc_cb_compl = 0;
+	acdb_cached_values = get_acdb_values_from_cache_tx(stream_id);
+	if (acdb_cached_values == NULL) {
+		MM_DBG("ERROR: to get chached acdb values\n");
+		return -EPERM;
+	}
+	update_acdb_data_struct(acdb_cached_values);
+	if (acdb_data.device_info->dev_id == PSEUDO_ACDB_ID) {
+		MM_INFO("audpreproc is routed to pseudo device\n");
+		return result;
+	}
+	if (acdb_data.build_id[17] == '1') {
+		if (session_info[stream_id].sampling_freq)
+			acdb_data.device_info->sample_rate =
+					session_info[stream_id].sampling_freq;
+	}
+	if (!(acdb_data.acdb_state & CAL_DATA_READY)) {
+		result = check_tx_acdb_values_cached();
+		if (result) {
+			result = acdb_get_calibration();
+			if (result < 0) {
+				MM_ERR("failed to get calibration data\n");
+				return result;
+			}
+		}
+		acdb_cached_values->node_status = ACDB_VALUES_FILLED;
+	}
+	return result;
+}
+
+void fluence_feature_update(int enable, int stream_id)
+{
+	MM_INFO("Fluence feature over ride with = %d\n", enable);
+	acdb_data.fleuce_feature_status[stream_id] = enable;
+}
+EXPORT_SYMBOL(fluence_feature_update);
+
+static void audpreproc_cb(void *private, u32 id, void *msg)
+{
+	struct audpreproc_cmd_enc_cfg_done_msg *tmp;
+	u8 result = 0;
+	int stream_id = 0;
+	if (id != AUDPREPROC_CMD_ENC_CFG_DONE_MSG)
+		goto done;
+
+	tmp = (struct audpreproc_cmd_enc_cfg_done_msg *)msg;
+	acdb_data.preproc_stream_id = tmp->stream_id;
+	stream_id = acdb_data.preproc_stream_id;
+	get_audrec_session_info(stream_id, &session_info[stream_id]);
+	MM_DBG("rec_enc_type = %x\n", tmp->rec_enc_type);
+	if ((tmp->rec_enc_type & 0x8000) ==
+				AUD_PREPROC_CONFIG_DISABLED) {
+		if (acdb_data.preproc_stream_id == 0) {
+			acdb_data.acdb_state &= ~AUDREC0_READY;
+			acdb_data.audrec_applied &= ~AUDREC0_READY;
+		} else if (acdb_data.preproc_stream_id == 1) {
+			acdb_data.acdb_state &= ~AUDREC1_READY;
+			acdb_data.audrec_applied &= ~AUDREC1_READY;
+		} else if (acdb_data.preproc_stream_id == 2) {
+			acdb_data.acdb_state &= ~AUDREC2_READY;
+			acdb_data.audrec_applied &= ~AUDREC2_READY;
+		}
+		acdb_data.fleuce_feature_status[stream_id] = 0;
+		acdb_cache_tx[tmp->stream_id].node_status =\
+						ACDB_VALUES_NOT_FILLED;
+		acdb_data.acdb_state &= ~CAL_DATA_READY;
+		goto done;
+	}
+	/*Following check is added to make sure that device info
+	  is updated. audpre proc layer enabled without device
+	  callback at this scenario we should not access
+	  device information
+	 */
+	if (acdb_data.build_id[17] != '0') {
+		if (acdb_data.device_info &&
+			session_info[stream_id].sampling_freq) {
+			acdb_data.device_info->sample_rate =
+					session_info[stream_id].sampling_freq;
+			result = check_tx_acdb_values_cached();
+			if (!result) {
+				MM_INFO("acdb values for the stream is" \
+							" querried from modem");
+				acdb_data.acdb_state |= CAL_DATA_READY;
+			} else {
+				acdb_data.acdb_state &= ~CAL_DATA_READY;
+			}
+		}
+	}
+	if (acdb_data.preproc_stream_id == 0)
+		acdb_data.acdb_state |= AUDREC0_READY;
+	else if (acdb_data.preproc_stream_id == 1)
+		acdb_data.acdb_state |= AUDREC1_READY;
+	else if (acdb_data.preproc_stream_id == 2)
+		acdb_data.acdb_state |= AUDREC2_READY;
+	acdb_data.preproc_cb_compl = 1;
+	MM_DBG("acdb_data.acdb_state = %x\n", acdb_data.acdb_state);
+	wake_up(&acdb_data.wait);
+done:
+	return;
+}
+
+static s32 register_audpp_cb(void)
+{
+	s32 result = 0;
+
+	acdb_data.audpp_cb.fn = audpp_cb;
+	acdb_data.audpp_cb.private = NULL;
+	result = audpp_register_event_callback(&acdb_data.audpp_cb);
+	if (result) {
+		MM_ERR("ACDB=> Could not register audpp callback\n");
+		result = -ENODEV;
+		goto done;
+	}
+done:
+	return result;
+}
+
+static s32 register_audpreproc_cb(void)
+{
+	s32 result = 0;
+
+	acdb_data.audpreproc_cb.fn = audpreproc_cb;
+	acdb_data.audpreproc_cb.private = NULL;
+	result = audpreproc_register_event_callback(&acdb_data.audpreproc_cb);
+	if (result) {
+		MM_ERR("ACDB=> Could not register audpreproc callback\n");
+		result = -ENODEV;
+		goto done;
+	}
+
+done:
+	return result;
+}
+
+static s32 acdb_initialize_data(void)
+{
+	s32	result = 0;
+
+	mutex_init(&acdb_data.acdb_mutex);
+
+	result = initialize_rpc();
+	if (result)
+		goto err;
+
+	result = initialize_memory();
+	if (result)
+		goto err1;
+
+	result = register_device_cb();
+	if (result)
+		goto err2;
+
+	result = register_audpp_cb();
+	if (result)
+		goto err3;
+
+	result = register_audpreproc_cb();
+	if (result)
+		goto err4;
+
+
+	return result;
+
+err4:
+	result = audpreproc_unregister_event_callback(&acdb_data.audpreproc_cb);
+	if (result)
+		MM_ERR("ACDB=> Could not unregister audpreproc callback\n");
+err3:
+	result = audpp_unregister_event_callback(&acdb_data.audpp_cb);
+	if (result)
+		MM_ERR("ACDB=> Could not unregister audpp callback\n");
+err2:
+	result = auddev_unregister_evt_listner(AUDDEV_CLNT_AUDIOCAL, 0);
+	if (result)
+		MM_ERR("ACDB=> Could not unregister device callback\n");
+err1:
+	daldevice_detach(acdb_data.handle);
+	acdb_data.handle = NULL;
+err:
+	return result;
+}
+
+static s32 initialize_modem_acdb(void)
+{
+	struct acdb_cmd_init_adie acdb_cmd;
+	u8 codec_type = -1;
+	s32 result = 0;
+	u8 iterations = 0;
+
+	codec_type = adie_get_detected_codec_type();
+	if (codec_type == MARIMBA_ID)
+		acdb_cmd.adie_type = ACDB_CURRENT_ADIE_MODE_MARIMBA;
+	else if (codec_type == TIMPANI_ID)
+		acdb_cmd.adie_type = ACDB_CURRENT_ADIE_MODE_TIMPANI;
+	else
+		acdb_cmd.adie_type = ACDB_CURRENT_ADIE_MODE_UNKNOWN;
+	acdb_cmd.command_id = ACDB_CMD_INITIALIZE_FOR_ADIE;
+	do {
+		/*Initialize ACDB software on modem based on codec type*/
+		result = dalrpc_fcn_8(ACDB_DalACDB_ioctl, acdb_data.handle,
+				(const void *)&acdb_cmd, sizeof(acdb_cmd),
+				&acdb_data.acdb_result,
+				sizeof(acdb_data.acdb_result));
+		if (result < 0) {
+			MM_ERR("ACDB=> RPC failure result = %d\n", result);
+			goto error;
+		}
+		/*following check is introduced to handle boot up race
+		condition between AUDCAL SW peers running on apps
+		and modem (ACDB_RES_BADSTATE indicates modem AUDCAL SW is
+		not in initialized sate) we need to retry to get ACDB
+		initialized*/
+		if (acdb_data.acdb_result.result == ACDB_RES_BADSTATE) {
+			msleep(500);
+			iterations++;
+		} else if (acdb_data.acdb_result.result == ACDB_RES_SUCCESS) {
+			MM_DBG("Modem ACDB SW initialized ((iterations = %d)\n",
+							iterations);
+			return result;
+		} else {
+			MM_ERR("ACDB=> Modem ACDB SW failed to initialize"
+					" reuslt = %d, (iterations = %d)\n",
+					acdb_data.acdb_result.result,
+					iterations);
+			goto error;
+		}
+	} while (iterations < MAX_RETRY);
+	MM_ERR("ACDB=> AUDCAL SW on modem is not in intiailized state (%d)\n",
+			acdb_data.acdb_result.result);
+error:
+	result = -EINVAL;
+	return result;
+}
+
+static s32 acdb_calibrate_device(void *data)
+{
+	s32 result = 0;
+
+	/* initialize driver */
+	result = acdb_initialize_data();
+	if (result)
+		goto done;
+	if (acdb_data.build_id[17] != '0') {
+		result = initialize_modem_acdb();
+		if (result < 0)
+			MM_ERR("failed to initialize modem ACDB\n");
+	}
+
+	while (!kthread_should_stop()) {
+		MM_DBG("Waiting for call back events\n");
+		wait_event_interruptible(acdb_data.wait,
+					(acdb_data.device_cb_compl
+					| acdb_data.audpp_cb_compl
+					| acdb_data.preproc_cb_compl));
+		mutex_lock(&acdb_data.acdb_mutex);
+		if (acdb_data.device_cb_compl) {
+			acdb_data.device_cb_compl = 0;
+			if (!(acdb_data.acdb_state & CAL_DATA_READY)) {
+				if ((acdb_data.device_info->dev_type
+							& RX_DEVICE) == 1) {
+					/*we need to get calibration values
+					only for RX device as resampler
+					moved to start of the pre - proc chain
+					tx calibration value will be based on
+					sampling frequency what audrec is
+					configured, calibration values for tx
+					device are fetch in audpreproc
+					callback*/
+					result = acdb_get_calibration();
+					if (result < 0) {
+						mutex_unlock(
+							&acdb_data.acdb_mutex);
+						MM_ERR("Not able to get "
+							"calibration "
+							"data continue\n");
+						continue;
+					}
+				}
+			}
+			MM_DBG("acdb state = %d\n",
+					 acdb_data.acdb_state);
+			if ((acdb_data.device_info->dev_type & TX_DEVICE) == 2)
+				handle_tx_device_ready_callback();
+			else {
+				acdb_cache_rx[acdb_data.device_info->dev_id]\
+						.node_status =
+						ACDB_VALUES_FILLED;
+				if (acdb_data.acdb_state &
+						AUDPP_READY) {
+					MM_DBG("AUDPP already enabled "
+							"apply acdb values\n");
+					goto apply;
+				}
+			}
+		}
+
+		if (!(acdb_data.audpp_cb_compl ||
+				acdb_data.preproc_cb_compl)) {
+			MM_DBG("need to wait for either AUDPP / AUDPREPROC "
+					"Event\n");
+			mutex_unlock(&acdb_data.acdb_mutex);
+			continue;
+		} else {
+			MM_DBG("got audpp / preproc call back\n");
+			if (acdb_data.audpp_cb_compl) {
+				send_acdb_values_for_active_devices();
+				acdb_data.audpp_cb_compl = 0;
+				mutex_unlock(&acdb_data.acdb_mutex);
+				continue;
+			} else {
+				result = handle_audpreproc_cb();
+				if (result < 0) {
+					mutex_unlock(&acdb_data.acdb_mutex);
+					continue;
+				}
+			}
+		}
+apply:
+		if (acdb_data.acdb_state & CAL_DATA_READY)
+			result = acdb_send_calibration();
+
+		mutex_unlock(&acdb_data.acdb_mutex);
+	}
+done:
+	return 0;
+}
+
+static int __init acdb_init(void)
+{
+
+	s32 result = 0;
+
+	memset(&acdb_data, 0, sizeof(acdb_data));
+	spin_lock_init(&acdb_data.dsp_lock);
+	acdb_data.cb_thread_task = kthread_run(acdb_calibrate_device,
+		NULL, "acdb_cb_thread");
+
+	if (IS_ERR(acdb_data.cb_thread_task)) {
+		MM_ERR("ACDB=> Could not register cb thread\n");
+		result = -ENODEV;
+		goto err;
+	}
+
+	acdb_data.build_id = socinfo_get_build_id();
+	MM_INFO("build id used is = %s\n", acdb_data.build_id);
+
+#ifdef CONFIG_DEBUG_FS
+	/*This is RTC specific INIT used only with debugfs*/
+	if (!rtc_acdb_init())
+		MM_ERR("RTC ACDB=>INIT Failure\n");
+
+#endif
+	init_waitqueue_head(&acdb_data.wait);
+
+	return misc_register(&acdb_misc);
+err:
+	return result;
+}
+
+static void __exit acdb_exit(void)
+{
+	s32	result = 0;
+	u32 i = 0;
+
+	result = auddev_unregister_evt_listner(AUDDEV_CLNT_AUDIOCAL, 0);
+	if (result)
+		MM_ERR("ACDB=> Could not unregister device callback\n");
+
+	result = audpp_unregister_event_callback(&acdb_data.audpp_cb);
+	if (result)
+		MM_ERR("ACDB=> Could not unregister audpp callback\n");
+
+	result = audpreproc_unregister_event_callback(&acdb_data.\
+				audpreproc_cb);
+	if (result)
+		MM_ERR("ACDB=> Could not unregister audpreproc callback\n");
+
+	result = kthread_stop(acdb_data.cb_thread_task);
+	if (result)
+		MM_ERR("ACDB=> Could not stop kthread\n");
+
+	free_memory_acdb_get_blk();
+
+	for (i = 0; i < MAX_COPP_NODE_SUPPORTED; i++) {
+		if (i < MAX_AUDREC_SESSIONS) {
+			iounmap(acdb_cache_tx[i].map_v_addr);
+			free_contiguous_memory_by_paddr(
+					acdb_cache_tx[i].phys_addr_acdb_values);
+		}
+		iounmap(acdb_cache_rx[i].map_v_addr);
+		free_contiguous_memory_by_paddr(
+					acdb_cache_rx[i].phys_addr_acdb_values);
+	}
+	kfree(acdb_data.device_info);
+	kfree(acdb_data.pp_iir);
+	kfree(acdb_data.pp_mbadrc);
+	kfree(acdb_data.preproc_agc);
+	kfree(acdb_data.preproc_iir);
+	free_contiguous_memory_by_paddr(
+				(int32_t)acdb_data.pbe_extbuff);
+	iounmap(acdb_data.map_v_fluence);
+	free_contiguous_memory_by_paddr(
+			(int32_t)acdb_data.fluence_extbuff);
+	mutex_destroy(&acdb_data.acdb_mutex);
+	memset(&acdb_data, 0, sizeof(acdb_data));
+	#ifdef CONFIG_DEBUG_FS
+	rtc_acdb_deinit();
+	#endif
+}
+
+late_initcall(acdb_init);
+module_exit(acdb_exit);
+
+MODULE_DESCRIPTION("MSM 7x30 Audio ACDB driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_adpcm.c b/arch/arm/mach-msm/qdsp5v2/audio_adpcm.c
new file mode 100644
index 0000000..95f0547
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/audio_adpcm.c
@@ -0,0 +1,1754 @@
+/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+ *
+ * Based on the mp3 native driver in arch/arm/mach-msm/qdsp5v2/audio_mp3.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/earlysuspend.h>
+#include <linux/android_pmem.h>
+#include <linux/slab.h>
+#include <linux/msm_audio.h>
+#include <linux/memory_alloc.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+
+#include <mach/msm_adsp.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/qdsp5v2/qdsp5audppmsg.h>
+#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
+#include <mach/qdsp5v2/qdsp5audplaymsg.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/qdsp5v2/audpp.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_memtypes.h>
+
+
+/* Size must be power of 2 */
+#define BUFSZ_MAX 	32768	/* Includes meta in size */
+#define BUFSZ_MIN 	4096	/* Includes meta in size */
+#define DMASZ_MAX 	(BUFSZ_MAX * 2)
+#define DMASZ_MIN 	(BUFSZ_MIN * 2)
+
+#define AUDPLAY_INVALID_READ_PTR_OFFSET	0xFFFF
+#define AUDDEC_DEC_ADPCM 1
+
+#define PCM_BUFSZ_MIN 	8216 	/* Hold one stereo ADPCM frame and meta out*/
+#define PCM_BUF_MAX_COUNT 5	/* DSP only accepts 5 buffers at most
+				   but support 2 buffers currently */
+#define ROUTING_MODE_FTRT 1
+#define ROUTING_MODE_RT 2
+/* Decoder status received from AUDPPTASK */
+#define  AUDPP_DEC_STATUS_SLEEP	0
+#define	 AUDPP_DEC_STATUS_INIT  1
+#define  AUDPP_DEC_STATUS_CFG   2
+#define  AUDPP_DEC_STATUS_PLAY  3
+
+#define AUDADPCM_METAFIELD_MASK 0xFFFF0000
+#define AUDADPCM_EOS_FLG_OFFSET 0x0A /* Offset from beginning of buffer */
+#define AUDADPCM_EOS_FLG_MASK 0x01
+#define AUDADPCM_EOS_NONE 0x0 /* No EOS detected */
+#define AUDADPCM_EOS_SET 0x1 /* EOS set in meta field */
+
+#define AUDADPCM_EVENT_NUM 10 /* Default no. of pre-allocated event packets */
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+	unsigned short mfield_sz; /*only useful for data has meta field */
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct audadpcm_suspend_ctl {
+	struct early_suspend node;
+	struct audio *audio;
+};
+#endif
+
+struct audadpcm_event{
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+
+struct audio {
+	struct buffer out[2];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed; /* number of buffers the dsp is waiting for */
+	unsigned out_dma_sz;
+
+	atomic_t out_bytes;
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	/* Host PCM section */
+	struct buffer in[PCM_BUF_MAX_COUNT];
+	struct mutex read_lock;
+	wait_queue_head_t read_wait;	/* Wait queue for read */
+	char *read_data;	/* pointer to reader buffer */
+	int32_t read_phys;	/* physical address of reader buffer */
+	uint8_t read_next;	/* index to input buffers to be read next */
+	uint8_t fill_next;	/* index to buffer that DSP should be filling */
+	uint8_t pcm_buf_count;	/* number of pcm buffer allocated */
+	/* ---- End of Host PCM section */
+
+	struct msm_adsp_module *audplay;
+
+	/* configuration to use on next enable */
+	uint32_t out_sample_rate;
+	uint32_t out_channel_mode;
+	uint32_t out_block_size;
+
+	/* data allocated for various buffers */
+	char *data;
+	int32_t phys; /* physical address of write buffer */
+	void *map_v_read;
+	void *map_v_write;
+	int mfield; /* meta field embedded in data */
+	int rflush; /* Read  flush */
+	int wflush; /* Write flush */
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+	int pcm_feedback;
+	int buf_refresh;
+	int teos; /* valid only if tunnel mode & no data left for decoder */
+	enum msm_aud_decoder_state dec_state;	/* Represents decoder state */
+	int reserved; /* A byte is being reserved */
+	char rsv_byte; /* Handle odd length user data */
+
+	const char *module_name;
+	unsigned queue_id;
+	uint16_t dec_id;
+	uint32_t read_ptr_offset;
+	int16_t source;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct audadpcm_suspend_ctl suspend_ctl;
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+
+	wait_queue_head_t wait;
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	wait_queue_head_t event_wait;
+	spinlock_t event_queue_lock;
+	struct mutex get_event_lock;
+	int event_abort;
+	/* AV sync Info */
+	int avsync_flag;              /* Flag to indicate feedback from DSP */
+	wait_queue_head_t avsync_wait;/* Wait queue for AV Sync Message     */
+	/* flags, 48 bits sample/bytes counter per channel */
+	uint16_t avsync[AUDPP_AVSYNC_CH_COUNT * AUDPP_AVSYNC_NUM_WORDS + 1];
+	uint32_t device_events;
+
+	int eq_enable;
+	int eq_needs_commit;
+	struct audpp_cmd_cfg_object_params_eqalizer eq;
+	struct audpp_cmd_cfg_object_params_volume vol_pan;
+};
+
+static int auddec_dsp_config(struct audio *audio, int enable);
+static void audpp_cmd_cfg_adec_params(struct audio *audio);
+static void audpp_cmd_cfg_routing_mode(struct audio *audio);
+static void audplay_send_data(struct audio *audio, unsigned needed);
+static void audplay_config_hostpcm(struct audio *audio);
+static void audplay_buffer_refresh(struct audio *audio);
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audadpcm_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload);
+#endif
+
+/* must be called with audio->lock held */
+static int audio_enable(struct audio *audio)
+{
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled)
+		return 0;
+
+	audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	if (msm_adsp_enable(audio->audplay)) {
+		MM_ERR("msm_adsp_enable(audplay) failed\n");
+		return -ENODEV;
+	}
+
+	if (audpp_enable(audio->dec_id, audio_dsp_event, audio)) {
+		MM_ERR("audpp_enable() failed\n");
+		msm_adsp_disable(audio->audplay);
+		return -ENODEV;
+	}
+
+	audio->enabled = 1;
+	return 0;
+}
+
+static void adpcm_listner(u32 evt_id, union auddev_evt_data *evt_payload,
+			void *private_data)
+{
+	struct audio *audio = (struct audio *) private_data;
+	switch (evt_id) {
+	case AUDDEV_EVT_DEV_RDY:
+		MM_DBG(":AUDDEV_EVT_DEV_RDY\n");
+		audio->source |= (0x1 << evt_payload->routing_id);
+		if (audio->running == 1 && audio->enabled == 1)
+			audpp_route_stream(audio->dec_id, audio->source);
+		break;
+	case AUDDEV_EVT_DEV_RLS:
+		MM_DBG(":AUDDEV_EVT_DEV_RLS\n");
+		if (audio->dec_state == MSM_AUD_DECODER_STATE_SUCCESS &&
+							audio->enabled == 1)
+			audpp_route_stream(audio->dec_id,
+				msm_snddev_route_dec(audio->dec_id));
+		break;
+	case AUDDEV_EVT_STREAM_VOL_CHG:
+		audio->vol_pan.volume = evt_payload->session_vol;
+		MM_DBG(":AUDDEV_EVT_STREAM_VOL_CHG, stream vol %d\n",
+				audio->vol_pan.volume);
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+		break;
+	default:
+		MM_ERR(":ERROR:wrong event\n");
+		break;
+	}
+}
+/* must be called with audio->lock held */
+static int audio_disable(struct audio *audio)
+{
+	int rc = 0;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+		auddec_dsp_config(audio, 0);
+		rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+		else if (audio->dec_state != MSM_AUD_DECODER_STATE_CLOSE)
+			rc = -EFAULT;
+		else
+			rc = 0;
+		wake_up(&audio->write_wait);
+		wake_up(&audio->read_wait);
+		msm_adsp_disable(audio->audplay);
+		audpp_disable(audio->dec_id, audio);
+		audio->out_needed = 0;
+	}
+	return rc;
+}
+
+/* ------------------- dsp --------------------- */
+static void audio_update_pcm_buf_entry(struct audio *audio,
+	uint32_t *payload)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	if (audio->rflush)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < payload[1]; index++) {
+		if (audio->in[audio->fill_next].addr ==
+			payload[2 + index * 2]) {
+			MM_DBG("audio_update_pcm_buf_entry: \
+				in[%d] ready\n", audio->fill_next);
+			audio->in[audio->fill_next].used =
+			payload[3 + index * 2];
+			if ((++audio->fill_next) == audio->pcm_buf_count)
+				audio->fill_next = 0;
+		} else {
+			MM_ERR("audio_update_pcm_buf_entry: \
+				expected=%x ret=%x\n",
+				audio->in[audio->fill_next].addr,
+				payload[1 + index * 2]);
+			break;
+		}
+	}
+	if (audio->in[audio->fill_next].used == 0) {
+		audplay_buffer_refresh(audio);
+	} else {
+		MM_DBG("read cannot keep up\n");
+		audio->buf_refresh = 1;
+	}
+	wake_up(&audio->read_wait);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static void audplay_dsp_event(void *data, unsigned id, size_t len,
+			      void (*getevent) (void *ptr, size_t len))
+{
+	struct audio *audio = data;
+	uint32_t msg[28];
+
+	getevent(msg, sizeof(msg));
+
+	MM_DBG("msg_id=%x\n", id);
+
+	switch (id) {
+	case AUDPLAY_MSG_DEC_NEEDS_DATA:
+		audplay_send_data(audio, 1);
+		break;
+
+	case AUDPLAY_MSG_BUFFER_UPDATE:
+		audio_update_pcm_buf_entry(audio, msg);
+		break;
+
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audplaytask)\n");
+		break;
+
+	default:
+		MM_ERR("unexpected message from decoder \n");
+		break;
+	}
+}
+
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned status = msg[1];
+
+			switch (status) {
+			case AUDPP_DEC_STATUS_SLEEP: {
+				uint16_t reason = msg[2];
+				MM_DBG("decoder status:sleep reason = \
+						0x%04x\n", reason);
+				if ((reason == AUDPP_MSG_REASON_MEM)
+					|| (reason ==
+					AUDPP_MSG_REASON_NODECODER)) {
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_FAILURE;
+					wake_up(&audio->wait);
+				} else if (reason == AUDPP_MSG_REASON_NONE) {
+					/* decoder is in disable state */
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_CLOSE;
+					wake_up(&audio->wait);
+				}
+				break;
+			}
+			case AUDPP_DEC_STATUS_INIT:
+				MM_DBG("decoder status: init\n");
+				if (audio->pcm_feedback)
+					audpp_cmd_cfg_routing_mode(audio);
+				else
+					audpp_cmd_cfg_adec_params(audio);
+				break;
+
+			case AUDPP_DEC_STATUS_CFG:
+				MM_DBG("decoder status: cfg\n");
+				break;
+			case AUDPP_DEC_STATUS_PLAY:
+				MM_DBG("decoder status: play \n");
+				/* send  mixer command */
+				audpp_route_stream(audio->dec_id,
+						audio->source);
+				if (audio->pcm_feedback) {
+					audplay_config_hostpcm(audio);
+					audplay_buffer_refresh(audio);
+				}
+				audio->dec_state =
+					MSM_AUD_DECODER_STATE_SUCCESS;
+				wake_up(&audio->wait);
+				break;
+			default:
+				MM_ERR("unknown decoder status\n");
+			}
+			break;
+		}
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			MM_DBG("CFG_MSG ENABLE\n");
+			auddec_dsp_config(audio, 1);
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+			audpp_dsp_set_eq(audio->dec_id,	audio->eq_enable,
+					&audio->eq, POPP);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			MM_DBG("CFG_MSG DISABLE\n");
+			audio->running = 0;
+		} else {
+			MM_DBG("CFG_MSG %d?\n", msg[0]);
+		}
+		break;
+	case AUDPP_MSG_ROUTING_ACK:
+		MM_DBG("ROUTING_ACK mode=%d\n", msg[1]);
+		audpp_cmd_cfg_adec_params(audio);
+		break;
+
+	case AUDPP_MSG_FLUSH_ACK:
+		MM_DBG("FLUSH_ACK\n");
+		audio->wflush = 0;
+		audio->rflush = 0;
+		wake_up(&audio->write_wait);
+		if (audio->pcm_feedback)
+			audplay_buffer_refresh(audio);
+		break;
+
+	case AUDPP_MSG_PCMDMAMISSED:
+		MM_DBG("PCMDMAMISSED\n");
+		audio->teos = 1;
+		wake_up(&audio->write_wait);
+		break;
+
+	case AUDPP_MSG_AVSYNC_MSG:
+		MM_DBG("AUDPP_MSG_AVSYNC_MSG\n");
+		memcpy(&audio->avsync[0], msg, sizeof(audio->avsync));
+		audio->avsync_flag = 1;
+		wake_up(&audio->avsync_wait);
+		break;
+
+	default:
+		MM_ERR("UNKNOWN (%d)\n", id);
+	}
+
+}
+
+static struct msm_adsp_ops audplay_adsp_ops_adpcm = {
+	.event = audplay_dsp_event,
+};
+
+#define audplay_send_queue0(audio, cmd, len) \
+	msm_adsp_write(audio->audplay, audio->queue_id, \
+			cmd, len)
+
+static int auddec_dsp_config(struct audio *audio, int enable)
+{
+	struct audpp_cmd_cfg_dec_type cfg_dec_cmd;
+
+	memset(&cfg_dec_cmd, 0, sizeof(cfg_dec_cmd));
+
+	cfg_dec_cmd.cmd_id = AUDPP_CMD_CFG_DEC_TYPE;
+	if (enable)
+		cfg_dec_cmd.dec_cfg = AUDPP_CMD_UPDATDE_CFG_DEC |
+				AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_ADPCM;
+	else
+		cfg_dec_cmd.dec_cfg = AUDPP_CMD_UPDATDE_CFG_DEC |
+				AUDPP_CMD_DIS_DEC_V;
+	cfg_dec_cmd.dm_mode = 0x0;
+	cfg_dec_cmd.stream_id = audio->dec_id;
+	return audpp_send_queue1(&cfg_dec_cmd, sizeof(cfg_dec_cmd));
+}
+
+static void audpp_cmd_cfg_adec_params(struct audio *audio)
+{
+	struct audpp_cmd_cfg_adec_params_adpcm cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_ADPCM_LEN;
+	cmd.common.dec_id = audio->dec_id;
+	cmd.common.input_sampling_frequency = audio->out_sample_rate;
+
+	cmd.stereo_cfg =  audio->out_channel_mode;
+	cmd.block_size =  audio->out_block_size;
+
+	audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static void audpp_cmd_cfg_routing_mode(struct audio *audio)
+{
+	struct audpp_cmd_routing_mode cmd;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_ROUTING_MODE;
+	cmd.object_number = audio->dec_id;
+	if (audio->pcm_feedback)
+		cmd.routing_mode = ROUTING_MODE_FTRT;
+	else
+		cmd.routing_mode = ROUTING_MODE_RT;
+
+	audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static void audplay_buffer_refresh(struct audio *audio)
+{
+	struct audplay_cmd_buffer_refresh refresh_cmd;
+
+	refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH;
+	refresh_cmd.num_buffers = 1;
+	refresh_cmd.buf0_address = audio->in[audio->fill_next].addr;
+	refresh_cmd.buf0_length = audio->in[audio->fill_next].size;
+	refresh_cmd.buf_read_count = 0;
+
+	MM_DBG("buf0_addr=%x buf0_len=%d\n",
+			refresh_cmd.buf0_address,
+			refresh_cmd.buf0_length);
+
+	(void)audplay_send_queue0(audio, &refresh_cmd, sizeof(refresh_cmd));
+}
+
+static void audplay_config_hostpcm(struct audio *audio)
+{
+	struct audplay_cmd_hpcm_buf_cfg cfg_cmd;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	cfg_cmd.cmd_id = AUDPLAY_CMD_HPCM_BUF_CFG;
+	cfg_cmd.max_buffers = audio->pcm_buf_count;
+	cfg_cmd.byte_swap = 0;
+	cfg_cmd.hostpcm_config = (0x8000) | (0x4000);
+	cfg_cmd.feedback_frequency = 1;
+	cfg_cmd.partition_number = 0;
+
+	(void)audplay_send_queue0(audio, &cfg_cmd, sizeof(cfg_cmd));
+}
+
+
+static int audplay_dsp_send_data_avail(struct audio *audio,
+					unsigned idx, unsigned len)
+{
+	struct audplay_cmd_bitstream_data_avail_nt2 cmd;
+
+	cmd.cmd_id		= AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_NT2;
+	if (audio->mfield)
+		cmd.decoder_id = AUDADPCM_METAFIELD_MASK |
+		(audio->out[idx].mfield_sz >> 1);
+	else
+		cmd.decoder_id		= audio->dec_id;
+	cmd.buf_ptr		= audio->out[idx].addr;
+	cmd.buf_size		= len/2;
+	cmd.partition_number	= 0;
+	return audplay_send_queue0(audio, &cmd, sizeof(cmd));
+}
+
+static void audplay_send_data(struct audio *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (audio->wflush) {
+		audio->out_needed = 1;
+		goto done;
+	}
+
+	if (needed && !audio->wflush) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			MM_DBG("frame %d free\n", audio->out_tail);
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		MM_DBG("\n"); /* Macro prints the file name and function */
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+			MM_DBG("frame %d busy\n", audio->out_tail);
+			audplay_dsp_send_data_avail(audio, audio->out_tail,
+								frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+
+static void audio_flush(struct audio *audio)
+{
+	audio->out[0].used = 0;
+	audio->out[1].used = 0;
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->reserved = 0;
+	atomic_set(&audio->out_bytes, 0);
+}
+
+static void audio_flush_pcm_buf(struct audio *audio)
+{
+	uint8_t index;
+
+	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
+		audio->in[index].used = 0;
+	audio->buf_refresh = 0;
+	audio->read_next = 0;
+	audio->fill_next = 0;
+}
+
+static void audio_ioport_reset(struct audio *audio)
+{
+	/* Make sure read/write thread are free from
+	 * sleep and knowing that system is not able
+	 * to process io request at the moment
+	 */
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audio_flush(audio);
+	mutex_unlock(&audio->write_lock);
+	wake_up(&audio->read_wait);
+	mutex_lock(&audio->read_lock);
+	audio_flush_pcm_buf(audio);
+	mutex_unlock(&audio->read_lock);
+	audio->avsync_flag = 1;
+	wake_up(&audio->avsync_wait);
+}
+
+static int audadpcm_events_pending(struct audio *audio)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	return empty || audio->event_abort;
+}
+
+static void audadpcm_reset_event_queue(struct audio *audio)
+{
+	unsigned long flags;
+	struct audadpcm_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audadpcm_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+				struct audadpcm_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	return;
+}
+
+static long audadpcm_process_event_req(struct audio *audio, void __user *arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audadpcm_event *drv_evt = NULL;
+	int timeout;
+	unsigned long flags;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int) usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(
+			audio->event_wait, audadpcm_events_pending(audio),
+			msecs_to_jiffies(timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(
+			audio->event_wait, audadpcm_events_pending(audio));
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	rc = 0;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audadpcm_event, list);
+		list_del(&drv_evt->list);
+	}
+
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else
+		rc = -1;
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	if (!rc && copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audio_enable_eq(struct audio *audio, int enable)
+{
+	if (audio->eq_enable == enable && !audio->eq_needs_commit)
+		return 0;
+
+	audio->eq_enable = enable;
+
+	if (audio->running) {
+		audpp_dsp_set_eq(audio->dec_id,	enable, &audio->eq, POPP);
+		audio->eq_needs_commit = 0;
+	}
+	return 0;
+}
+
+static int audio_get_avsync_data(struct audio *audio,
+						struct msm_audio_stats *stats)
+{
+	int rc = -EINVAL;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (audio->dec_id == audio->avsync[0] && audio->avsync_flag) {
+		/* av_sync sample count */
+		stats->sample_count = (audio->avsync[2] << 16) |
+						(audio->avsync[3]);
+
+		/* av_sync byte_count */
+		stats->byte_count = (audio->avsync[5] << 16) |
+						(audio->avsync[6]);
+
+		audio->avsync_flag = 0;
+		rc = 0;
+	}
+	local_irq_restore(flags);
+	return rc;
+
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = -EINVAL;
+	unsigned long flags = 0;
+	uint16_t enable_mask;
+	int enable;
+	int prev_state;
+
+	MM_DBG("cmd = %d\n", cmd);
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+
+		audio->avsync_flag = 0;
+		memset(&stats, 0, sizeof(stats));
+		if (audpp_query_avsync(audio->dec_id) < 0)
+			return rc;
+
+		rc = wait_event_interruptible_timeout(audio->avsync_wait,
+				(audio->avsync_flag == 1),
+				msecs_to_jiffies(AUDPP_AVSYNC_EVENT_TIMEOUT));
+
+		if (rc < 0)
+			return rc;
+		else if ((rc > 0) || ((rc == 0) && (audio->avsync_flag == 1))) {
+			if (audio_get_avsync_data(audio, &stats) < 0)
+				return rc;
+
+			if (copy_to_user((void *)arg, &stats, sizeof(stats)))
+				return -EFAULT;
+			return 0;
+		} else
+			return -EAGAIN;
+	}
+
+	switch (cmd) {
+	case AUDIO_ENABLE_AUDPP:
+		if (copy_from_user(&enable_mask, (void *) arg,
+						sizeof(enable_mask))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		enable = (enable_mask & EQ_ENABLE) ? 1 : 0;
+		audio_enable_eq(audio, enable);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+	case AUDIO_SET_VOLUME:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.volume = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_PAN:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.pan = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_EQ:
+		prev_state = audio->eq_enable;
+		audio->eq_enable = 0;
+		if (copy_from_user(&audio->eq.num_bands, (void *) arg,
+				sizeof(audio->eq) -
+				(AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2))) {
+			rc = -EFAULT;
+			break;
+		}
+		audio->eq_enable = prev_state;
+		audio->eq_needs_commit = 1;
+		rc = 0;
+		break;
+	}
+
+	if (-EINVAL != rc)
+		return rc;
+
+	if (cmd == AUDIO_GET_EVENT) {
+		MM_DBG("AUDIO_GET_EVENT\n");
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audadpcm_process_event_req(audio,
+					(void __user *) arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		return rc;
+	}
+
+	if (cmd == AUDIO_ABORT_GET_EVENT) {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		MM_DBG("AUDIO_START\n");
+		rc = audio_enable(audio);
+		if (!rc) {
+			rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+			MM_INFO("dec_state %d rc = %d\n", audio->dec_state, rc);
+
+			if (audio->dec_state != MSM_AUD_DECODER_STATE_SUCCESS)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		break;
+	case AUDIO_STOP:
+		MM_DBG("AUDIO_STOP\n");
+		rc = audio_disable(audio);
+		audio->stopped = 1;
+		audio_ioport_reset(audio);
+		audio->stopped = 0;
+		break;
+	case AUDIO_FLUSH:
+		MM_DBG("AUDIO_FLUSH\n");
+		audio->rflush = 1;
+		audio->wflush = 1;
+		audio_ioport_reset(audio);
+		if (audio->running) {
+			audpp_flush(audio->dec_id);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		break;
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (copy_from_user(&config, (void *) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (config.channel_count == 1) {
+			config.channel_count = AUDPP_CMD_PCM_INTF_MONO_V;
+		} else if (config.channel_count == 2) {
+			config.channel_count = AUDPP_CMD_PCM_INTF_STEREO_V;
+		} else {
+			rc = -EINVAL;
+			break;
+		}
+		audio->mfield = config.meta_field;
+		audio->out_sample_rate = config.sample_rate;
+		audio->out_channel_mode = config.channel_count;
+		audio->out_block_size = config.bits;
+		rc = 0;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_size = (audio->out_dma_sz >> 1);
+		config.buffer_count = 2;
+		config.sample_rate = audio->out_sample_rate;
+		if (audio->out_channel_mode == AUDPP_CMD_PCM_INTF_MONO_V)
+			config.channel_count = 1;
+		else
+			config.channel_count = 2;
+		config.meta_field = 0;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void *) arg, &config, sizeof(config)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+
+		break;
+	}
+	case AUDIO_GET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			config.pcm_feedback = audio->pcm_feedback;
+			config.buffer_count = PCM_BUF_MAX_COUNT;
+			config.buffer_size = PCM_BUFSZ_MIN;
+			if (copy_to_user((void *)arg, &config,
+					 sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_SET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			if (copy_from_user
+			    (&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+			if (config.pcm_feedback != audio->pcm_feedback) {
+				MM_ERR("Not sufficient permission to"
+					 "change the playback mode\n");
+				rc = -EACCES;
+				break;
+			}
+			if ((config.buffer_count > PCM_BUF_MAX_COUNT) ||
+			    (config.buffer_count == 1))
+				config.buffer_count = PCM_BUF_MAX_COUNT;
+
+			if (config.buffer_size < PCM_BUFSZ_MIN)
+				config.buffer_size = PCM_BUFSZ_MIN;
+
+			/* Check if pcm feedback is required */
+			if ((config.pcm_feedback) && (!audio->read_data)) {
+				MM_DBG("allocate PCM buffer %d\n",
+						config.buffer_count *
+						config.buffer_size);
+				audio->read_phys =
+					allocate_contiguous_ebi_nomap(
+							config.buffer_size *
+							config.buffer_count,
+							SZ_4K);
+				if (!audio->read_phys) {
+					rc = -ENOMEM;
+					break;
+				}
+				audio->map_v_read = ioremap(
+							audio->read_phys,
+							config.buffer_size *
+							config.buffer_count);
+				if (IS_ERR(audio->map_v_read)) {
+					MM_ERR("read buf map fail\n");
+					rc = -ENOMEM;
+					free_contiguous_memory_by_paddr(
+							audio->read_phys);
+				} else {
+					uint8_t index;
+					uint32_t offset = 0;
+					audio->read_data =
+						audio->map_v_read;
+					audio->buf_refresh = 0;
+					audio->pcm_buf_count =
+					    config.buffer_count;
+					audio->read_next = 0;
+					audio->fill_next = 0;
+
+					for (index = 0;
+					     index < config.buffer_count;
+					     index++) {
+						audio->in[index].data =
+						    audio->read_data + offset;
+						audio->in[index].addr =
+						    audio->read_phys + offset;
+						audio->in[index].size =
+						    config.buffer_size;
+						audio->in[index].used = 0;
+						offset += config.buffer_size;
+					}
+					MM_DBG("read buf: phy addr \
+						0x%08x kernel addr 0x%08x\n",
+						audio->read_phys,
+						(int)audio->read_data);
+					rc = 0;
+				}
+			} else {
+				rc = 0;
+			}
+			break;
+		}
+	case AUDIO_PAUSE:
+		MM_DBG("AUDIO_PAUSE %ld\n", arg);
+		rc = audpp_pause(audio->dec_id, (int) arg);
+		break;
+	case AUDIO_GET_SESSION_ID:
+		if (copy_to_user((void *) arg, &audio->dec_id,
+					sizeof(unsigned short)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+/* Only useful in tunnel-mode */
+static int audio_fsync(struct file *file, loff_t ppos1, loff_t ppos2, int datasync)
+{
+	struct audio *audio = file->private_data;
+	struct buffer *frame;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	if (!audio->running || audio->pcm_feedback) {
+		rc = -EINVAL;
+		goto done_nolock;
+	}
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(!audio->out[0].used &&
+		!audio->out[1].used &&
+		audio->out_needed) || audio->wflush);
+
+	if (rc < 0)
+		goto done;
+	else if (audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (audio->reserved) {
+		MM_DBG("send reserved byte\n");
+		frame = audio->out + audio->out_tail;
+		((char *) frame->data)[0] = audio->rsv_byte;
+		((char *) frame->data)[1] = 0;
+		frame->used = 2;
+		audplay_send_data(audio, 0);
+
+		rc = wait_event_interruptible(audio->write_wait,
+			(!audio->out[0].used &&
+			!audio->out[1].used &&
+			audio->out_needed) || audio->wflush);
+
+		if (rc < 0)
+			goto done;
+		else if (audio->wflush) {
+			rc = -EBUSY;
+			goto done;
+		}
+	}
+
+	/* pcm dmamiss message is sent continously
+	 * when decoder is starved so no race
+	 * condition concern
+	 */
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		audio->teos || audio->wflush);
+
+	if (audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+done_nolock:
+	return rc;
+}
+
+static ssize_t audio_read(struct file *file, char __user *buf, size_t count,
+			  loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	int rc = 0;
+
+	if (!audio->pcm_feedback)
+		return 0; /* PCM feedback is not enabled. Nothing to read */
+
+	mutex_lock(&audio->read_lock);
+	MM_DBG("%d \n", count);
+	while (count > 0) {
+		rc = wait_event_interruptible(audio->read_wait,
+			(audio->in[audio->read_next].used > 0) ||
+			(audio->stopped) || (audio->rflush));
+
+		if (rc < 0)
+			break;
+
+		if (audio->stopped || audio->rflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (count < audio->in[audio->read_next].used) {
+			/* Read must happen in frame boundary. Since driver
+			   does not know frame size, read count must be greater
+			   or equal to size of PCM samples */
+			MM_DBG("audio_read: no partial frame done reading\n");
+			break;
+		} else {
+			MM_DBG("audio_read: read from in[%d]\n",
+					audio->read_next);
+			if (copy_to_user
+			    (buf, audio->in[audio->read_next].data,
+			     audio->in[audio->read_next].used)) {
+				MM_ERR("invalid addr %x \n", (unsigned int)buf);
+				rc = -EFAULT;
+				break;
+			}
+			count -= audio->in[audio->read_next].used;
+			buf += audio->in[audio->read_next].used;
+			audio->in[audio->read_next].used = 0;
+			if ((++audio->read_next) == audio->pcm_buf_count)
+				audio->read_next = 0;
+			break;	/* Force to exit while loop
+				 * to prevent output thread
+				 * sleep too long if data is
+				 * not ready at this moment.
+				 */
+		}
+	}
+
+	/* don't feed output buffer to HW decoder during flushing
+	 * buffer refresh command will be sent once flush completes
+	 * send buf refresh command here can confuse HW decoder
+	 */
+	if (audio->buf_refresh && !audio->rflush) {
+		audio->buf_refresh = 0;
+		MM_DBG("kick start pcm feedback again\n");
+		audplay_buffer_refresh(audio);
+	}
+
+	mutex_unlock(&audio->read_lock);
+
+	if (buf > start)
+		rc = buf - start;
+
+	MM_DBG("read %d bytes\n", rc);
+	return rc;
+}
+
+static int audadpcm_process_eos(struct audio *audio,
+		const char __user *buf_start, unsigned short mfield_size)
+{
+	int rc = 0;
+	struct buffer *frame;
+	char *buf_ptr;
+
+	if (audio->reserved) {
+		MM_DBG("flush reserve byte\n");
+		frame = audio->out + audio->out_head;
+		buf_ptr = frame->data;
+		rc = wait_event_interruptible(audio->write_wait,
+				(frame->used == 0)
+				|| (audio->stopped)
+				|| (audio->wflush));
+		if (rc < 0)
+			goto done;
+		if (audio->stopped || audio->wflush) {
+			rc = -EBUSY;
+			goto done;
+		}
+
+		buf_ptr[0] = audio->rsv_byte;
+		buf_ptr[1] = 0;
+		audio->out_head ^= 1;
+		frame->mfield_sz = 0;
+		frame->used = 2;
+		audio->reserved = 0;
+		audplay_send_data(audio, 0);
+	}
+
+	frame = audio->out + audio->out_head;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->out_needed &&
+		audio->out[0].used == 0 &&
+		audio->out[1].used == 0)
+		|| (audio->stopped)
+		|| (audio->wflush));
+
+	if (rc < 0)
+		goto done;
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (copy_from_user(frame->data, buf_start, mfield_size)) {
+		rc = -EFAULT;
+		goto done;
+	}
+
+	frame->mfield_sz = mfield_size;
+	audio->out_head ^= 1;
+	frame->used = mfield_size;
+	audplay_send_data(audio, 0);
+done:
+	return rc;
+}
+
+static ssize_t audio_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	char *cpy_ptr;
+	int rc = 0, eos_condition = AUDADPCM_EOS_NONE;
+	unsigned dsize;
+	unsigned short mfield_size = 0;
+
+	MM_DBG("cnt=%d\n", count);
+
+	mutex_lock(&audio->write_lock);
+	while (count > 0) {
+		frame = audio->out + audio->out_head;
+		cpy_ptr = frame->data;
+		dsize = 0;
+		rc = wait_event_interruptible(audio->write_wait,
+					      (frame->used == 0)
+					      || (audio->stopped)
+						  || (audio->wflush));
+		if (rc < 0)
+			break;
+		if (audio->stopped || audio->wflush) {
+			rc = -EBUSY;
+			break;
+		}
+		if (audio->mfield) {
+			if (buf == start) {
+				/* Processing beginning of user buffer */
+				if (__get_user(mfield_size,
+					(unsigned short __user *) buf)) {
+					rc = -EFAULT;
+					break;
+				} else  if (mfield_size > count) {
+					rc = -EINVAL;
+					break;
+				}
+				MM_DBG("audio_write: mf offset_val %x\n",
+						mfield_size);
+				if (copy_from_user(cpy_ptr, buf, mfield_size)) {
+					rc = -EFAULT;
+					break;
+				}
+				/* Check if EOS flag is set and buffer has
+				 * contains just meta field
+				 */
+				if (cpy_ptr[AUDADPCM_EOS_FLG_OFFSET] &
+						 AUDADPCM_EOS_FLG_MASK) {
+					MM_DBG("audio_write: EOS SET\n");
+					eos_condition = AUDADPCM_EOS_SET;
+					if (mfield_size == count) {
+						buf += mfield_size;
+						break;
+					} else
+					cpy_ptr[AUDADPCM_EOS_FLG_OFFSET]
+						&= ~AUDADPCM_EOS_FLG_MASK;
+				}
+				cpy_ptr += mfield_size;
+				count -= mfield_size;
+				dsize += mfield_size;
+				buf += mfield_size;
+			} else {
+				mfield_size = 0;
+				MM_DBG("audio_write: continuous buffer\n");
+			}
+			frame->mfield_sz = mfield_size;
+		}
+
+		if (audio->reserved) {
+			MM_DBG("append reserved byte %x\n", audio->rsv_byte);
+			*cpy_ptr = audio->rsv_byte;
+			xfer = (count > ((frame->size - mfield_size) - 1)) ?
+				(frame->size - mfield_size) - 1 : count;
+			cpy_ptr++;
+			dsize += 1;
+			audio->reserved = 0;
+		} else
+			xfer = (count > (frame->size - mfield_size)) ?
+				(frame->size - mfield_size) : count;
+
+		if (copy_from_user(cpy_ptr, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+
+		dsize += xfer;
+		if (dsize & 1) {
+			audio->rsv_byte = ((char *) frame->data)[dsize - 1];
+			MM_DBG("odd length buf reserve last byte %x\n",
+					audio->rsv_byte);
+			audio->reserved = 1;
+			dsize--;
+		}
+		count -= xfer;
+		buf += xfer;
+
+		if (dsize > 0) {
+			audio->out_head ^= 1;
+			frame->used = dsize;
+			audplay_send_data(audio, 0);
+		}
+	}
+	if (eos_condition == AUDADPCM_EOS_SET)
+		rc = audadpcm_process_eos(audio, start, mfield_size);
+	mutex_unlock(&audio->write_lock);
+	if (!rc) {
+		if (buf > start)
+			return buf - start;
+	}
+	return rc;
+}
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	MM_INFO("audio instance 0x%08x freeing\n", (int)audio);
+
+	mutex_lock(&audio->lock);
+	auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->dec_id);
+	audio_disable(audio);
+	audio_flush(audio);
+	audio_flush_pcm_buf(audio);
+	msm_adsp_put(audio->audplay);
+	audpp_adec_free(audio->dec_id);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&audio->suspend_ctl.node);
+#endif
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audadpcm_reset_event_queue(audio);
+	iounmap(audio->map_v_write);
+	free_contiguous_memory_by_paddr(audio->phys);
+	if (audio->read_data) {
+		iounmap(audio->map_v_read);
+		free_contiguous_memory_by_paddr(audio->read_phys);
+	}
+	mutex_unlock(&audio->lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio);
+	return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audadpcm_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload)
+{
+	struct audadpcm_event *e_node = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+				struct audadpcm_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audadpcm_event), GFP_ATOMIC);
+		if (!e_node) {
+			MM_ERR("No mem to post event %d\n", type);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	wake_up(&audio->event_wait);
+}
+
+static void audadpcm_suspend(struct early_suspend *h)
+{
+	struct audadpcm_suspend_ctl *ctl =
+		container_of(h, struct audadpcm_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audadpcm_post_event(ctl->audio, AUDIO_EVENT_SUSPEND, payload);
+}
+
+static void audadpcm_resume(struct early_suspend *h)
+{
+	struct audadpcm_suspend_ctl *ctl =
+		container_of(h, struct audadpcm_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audadpcm_post_event(ctl->audio, AUDIO_EVENT_RESUME, payload);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audadpcm_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audadpcm_debug_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 4096;
+	static char buffer[4096];
+	int n = 0, i;
+	struct audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "enabled %d\n", audio->enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "pcm_feedback %d\n", audio->pcm_feedback);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_buf_sz %d\n", audio->out[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "pcm_buf_count %d \n", audio->pcm_buf_count);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "pcm_buf_sz %d \n", audio->in[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "volume %x \n", audio->vol_pan.volume);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "sample rate %d \n", audio->out_sample_rate);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		"channel mode %d \n", audio->out_channel_mode);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "rflush %d\n", audio->rflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "running %d \n", audio->running);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"dec state %d \n", audio->dec_state);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_needed %d \n", audio->out_needed);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_head %d \n", audio->out_head);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_tail %d \n", audio->out_tail);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out[0].used %d \n", audio->out[0].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out[1].used %d \n", audio->out[1].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "buffer_refresh %d \n", audio->buf_refresh);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "read_next %d \n", audio->read_next);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "fill_next %d \n", audio->fill_next);
+	for (i = 0; i < audio->pcm_buf_count; i++)
+		n += scnprintf(buffer + n, debug_bufmax - n,
+			"in[%d].size %d \n", i, audio->in[i].used);
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audadpcm_debug_fops = {
+	.read = audadpcm_debug_read,
+	.open = audadpcm_debug_open,
+};
+#endif
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = NULL;
+	int rc, dec_attrb, decid, i;
+	unsigned pmem_sz = DMASZ_MAX;
+	struct audadpcm_event *e_node = NULL;
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_adpcm_" + 5];
+#endif
+
+	/* Allocate Mem for audio instance */
+	audio = kzalloc(sizeof(struct audio), GFP_KERNEL);
+	if (!audio) {
+		MM_ERR("no memory to allocate audio instance \n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	MM_INFO("audio instance 0x%08x created\n", (int)audio);
+
+	/* Allocate the decoder */
+	dec_attrb = AUDDEC_DEC_ADPCM;
+	if ((file->f_mode & FMODE_WRITE) &&
+			(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_NONTUNNEL;
+		audio->pcm_feedback = NON_TUNNEL_MODE_PLAYBACK;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_TUNNEL;
+		audio->pcm_feedback = TUNNEL_MODE_PLAYBACK;
+	} else {
+		kfree(audio);
+		rc = -EACCES;
+		goto done;
+	}
+
+	decid = audpp_adec_alloc(dec_attrb, &audio->module_name,
+			&audio->queue_id);
+
+	if (decid < 0) {
+		MM_ERR("No free decoder available, freeing instance 0x%08x\n",
+				(int)audio);
+		rc = -ENODEV;
+		kfree(audio);
+		goto done;
+	}
+	audio->dec_id = decid & MSM_AUD_DECODER_MASK;
+
+	while (pmem_sz >= DMASZ_MIN) {
+		MM_DBG("pmemsz = %d\n", pmem_sz);
+		audio->phys = allocate_contiguous_ebi_nomap(pmem_sz,
+									SZ_4K);
+		if (audio->phys) {
+			audio->map_v_write = ioremap(audio->phys, pmem_sz);
+			if (IS_ERR(audio->map_v_write)) {
+				MM_ERR("could not map write phys address, \
+						freeing instance 0x%08x\n",
+						(int)audio);
+				rc = -ENOMEM;
+				free_contiguous_memory_by_paddr(audio->phys);
+				audpp_adec_free(audio->dec_id);
+				kfree(audio);
+				goto done;
+			}
+			audio->data = audio->map_v_write;
+			MM_DBG("write buf: phy addr 0x%08x kernel addr \
+				0x%08x\n", audio->phys, (int)audio->data);
+			break;
+		} else if (pmem_sz == DMASZ_MIN) {
+			MM_ERR("could not allocate write buffers, freeing \
+					instance 0x%08x\n", (int)audio);
+			rc = -ENOMEM;
+			audpp_adec_free(audio->dec_id);
+			kfree(audio);
+			goto done;
+		} else
+		pmem_sz >>= 1;
+	}
+	audio->out_dma_sz = pmem_sz;
+
+	rc = msm_adsp_get(audio->module_name, &audio->audplay,
+			&audplay_adsp_ops_adpcm, audio);
+	if (rc) {
+		MM_ERR("failed to get %s module, freeing instance 0x%08x\n",
+				audio->module_name, (int)audio);
+		goto err;
+	}
+
+	mutex_init(&audio->lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->get_event_lock);
+	spin_lock_init(&audio->dsp_lock);
+	init_waitqueue_head(&audio->write_wait);
+	init_waitqueue_head(&audio->read_wait);
+	INIT_LIST_HEAD(&audio->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+	init_waitqueue_head(&audio->wait);
+	init_waitqueue_head(&audio->event_wait);
+	spin_lock_init(&audio->event_queue_lock);
+	init_waitqueue_head(&audio->avsync_wait);
+
+	audio->out[0].data = audio->data + 0;
+	audio->out[0].addr = audio->phys + 0;
+	audio->out[0].size = audio->out_dma_sz >> 1;
+
+	audio->out[1].data = audio->data + audio->out[0].size;
+	audio->out[1].addr = audio->phys + audio->out[0].size;
+	audio->out[1].size = audio->out[0].size;
+
+	audio->out_sample_rate = 44100;
+	audio->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V;
+
+	audio->vol_pan.volume = 0x2000;
+
+	audio_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+
+	audio->device_events = AUDDEV_EVT_DEV_RDY
+				|AUDDEV_EVT_DEV_RLS|
+				AUDDEV_EVT_STREAM_VOL_CHG;
+
+	rc = auddev_register_evt_listner(audio->device_events,
+					AUDDEV_CLNT_DEC,
+					audio->dec_id,
+					adpcm_listner,
+					(void *)audio);
+	if (rc) {
+		MM_ERR("%s: failed to register listner\n", __func__);
+		goto event_err;
+	}
+
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_adpcm_%04x", audio->dec_id);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+				NULL, (void *) audio,
+				&audadpcm_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		MM_DBG("debugfs_create_file failed\n");
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	audio->suspend_ctl.node.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+	audio->suspend_ctl.node.resume = audadpcm_resume;
+	audio->suspend_ctl.node.suspend = audadpcm_suspend;
+	audio->suspend_ctl.audio = audio;
+	register_early_suspend(&audio->suspend_ctl.node);
+#endif
+	for (i = 0; i < AUDADPCM_EVENT_NUM; i++) {
+		e_node = kmalloc(sizeof(struct audadpcm_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			MM_ERR("event pkt alloc failed\n");
+			break;
+		}
+	}
+done:
+	return rc;
+event_err:
+	msm_adsp_put(audio->audplay);
+err:
+	iounmap(audio->map_v_write);
+	free_contiguous_memory_by_paddr(audio->phys);
+	audpp_adec_free(audio->dec_id);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_adpcm_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audio_open,
+	.release	= audio_release,
+	.read 		= audio_read,
+	.write		= audio_write,
+	.unlocked_ioctl	= audio_ioctl,
+	.fsync 		= audio_fsync,
+};
+
+struct miscdevice audio_adpcm_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_adpcm",
+	.fops	= &audio_adpcm_fops,
+};
+
+static int __init audio_init(void)
+{
+	return misc_register(&audio_adpcm_misc);
+}
+
+device_initcall(audio_init);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_amrnb.c b/arch/arm/mach-msm/qdsp5v2/audio_amrnb.c
new file mode 100644
index 0000000..55c49b3
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/audio_amrnb.c
@@ -0,0 +1,1645 @@
+/*
+ * amrnb audio decoder device
+ *
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+ *
+ * Based on the mp3 native driver in arch/arm/mach-msm/qdsp5/audio_mp3.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/earlysuspend.h>
+#include <linux/android_pmem.h>
+#include <linux/memory_alloc.h>
+#include <linux/msm_audio.h>
+#include <linux/slab.h>
+#include <mach/msm_adsp.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/qdsp5v2/qdsp5audppmsg.h>
+#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
+#include <mach/qdsp5v2/qdsp5audplaymsg.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/qdsp5v2/audpp.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_memtypes.h>
+
+#define BUFSZ 1024 /* Hold minimum 700ms voice data and 14 bytes of meta in*/
+#define DMASZ (BUFSZ * 2)
+
+#define AUDPLAY_INVALID_READ_PTR_OFFSET	0xFFFF
+#define AUDDEC_DEC_AMRNB 10
+
+#define PCM_BUFSZ_MIN 1624 /* 100ms worth of data and 24 bytes of meta out*/
+#define AMRNB_DECODED_FRSZ 320 /* AMR-NB 20ms 8KHz mono PCM size */
+#define PCM_BUF_MAX_COUNT 5	/* DSP only accepts 5 buffers at most
+				   but support 2 buffers currently */
+#define ROUTING_MODE_FTRT 1
+#define ROUTING_MODE_RT 2
+/* Decoder status received from AUDPPTASK */
+#define  AUDPP_DEC_STATUS_SLEEP	0
+#define	 AUDPP_DEC_STATUS_INIT  1
+#define  AUDPP_DEC_STATUS_CFG   2
+#define  AUDPP_DEC_STATUS_PLAY  3
+
+#define AUDAMRNB_METAFIELD_MASK 0xFFFF0000
+#define AUDAMRNB_EOS_FLG_OFFSET 0x0A /* Offset from beginning of buffer */
+#define AUDAMRNB_EOS_FLG_MASK 0x01
+#define AUDAMRNB_EOS_NONE 0x0 /* No EOS detected */
+#define AUDAMRNB_EOS_SET 0x1 /* EOS set in meta field */
+
+#define AUDAMRNB_EVENT_NUM 10 /* Default number of pre-allocated event pkts */
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+	unsigned short mfield_sz; /*only useful for data has meta field */
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct audamrnb_suspend_ctl {
+	struct early_suspend node;
+	struct audio *audio;
+};
+#endif
+
+struct audamrnb_event{
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+
+struct audio {
+	struct buffer out[2];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed;	/* number of buffers the dsp is waiting for */
+
+	atomic_t out_bytes;
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	/* Host PCM section */
+	struct buffer in[PCM_BUF_MAX_COUNT];
+	struct mutex read_lock;
+	wait_queue_head_t read_wait;	/* Wait queue for read */
+	char *read_data;	/* pointer to reader buffer */
+	int32_t read_phys;	/* physical address of reader buffer */
+	uint8_t read_next;	/* index to input buffers to be read next */
+	uint8_t fill_next;	/* index to buffer that DSP should be filling */
+	uint8_t pcm_buf_count;	/* number of pcm buffer allocated */
+	/* ---- End of Host PCM section */
+
+	struct msm_adsp_module *audplay;
+
+	/* data allocated for various buffers */
+	char *data;
+	int32_t phys; /* physical address of write buffer */
+	void *map_v_read;
+	void *map_v_write;
+
+	int mfield; /* meta field embedded in data */
+	int rflush; /* Read  flush */
+	int wflush; /* Write flush */
+	uint8_t opened:1;
+	uint8_t enabled:1;
+	uint8_t running:1;
+	uint8_t stopped:1;	/* set when stopped, cleared on flush */
+	uint8_t pcm_feedback:1;
+	uint8_t buf_refresh:1;
+	int teos; /* valid only if tunnel mode & no data left for decoder */
+	enum msm_aud_decoder_state dec_state;	/* Represents decoder state */
+
+	const char *module_name;
+	unsigned queue_id;
+	uint16_t dec_id;
+	uint32_t read_ptr_offset;
+	int16_t source;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct audamrnb_suspend_ctl suspend_ctl;
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+
+	wait_queue_head_t wait;
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	wait_queue_head_t event_wait;
+	spinlock_t event_queue_lock;
+	struct mutex get_event_lock;
+	int event_abort;
+	/* AV sync Info */
+	int avsync_flag;              /* Flag to indicate feedback from DSP */
+	wait_queue_head_t avsync_wait;/* Wait queue for AV Sync Message     */
+	/* flags, 48 bits sample/bytes counter per channel */
+	uint16_t avsync[AUDPP_AVSYNC_CH_COUNT * AUDPP_AVSYNC_NUM_WORDS + 1];
+
+	uint32_t device_events;
+
+	int eq_enable;
+	int eq_needs_commit;
+	struct audpp_cmd_cfg_object_params_eqalizer eq;
+	struct audpp_cmd_cfg_object_params_volume vol_pan;
+};
+
+struct audpp_cmd_cfg_adec_params_amrnb {
+   struct audpp_cmd_cfg_adec_params_common  common;
+   unsigned short                       stereo_cfg;
+} __attribute__((packed)) ;
+
+static int auddec_dsp_config(struct audio *audio, int enable);
+static void audpp_cmd_cfg_adec_params(struct audio *audio);
+static void audpp_cmd_cfg_routing_mode(struct audio *audio);
+static void audamrnb_send_data(struct audio *audio, unsigned needed);
+static void audamrnb_config_hostpcm(struct audio *audio);
+static void audamrnb_buffer_refresh(struct audio *audio);
+static void audamrnb_dsp_event(void *private, unsigned id, uint16_t *msg);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audamrnb_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload);
+#endif
+
+/* must be called with audio->lock held */
+static int audamrnb_enable(struct audio *audio)
+{
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled)
+		return 0;
+
+	audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	if (msm_adsp_enable(audio->audplay)) {
+		MM_ERR("msm_adsp_enable(audplay) failed\n");
+		return -ENODEV;
+	}
+
+	if (audpp_enable(audio->dec_id, audamrnb_dsp_event, audio)) {
+		MM_ERR("audpp_enable() failed\n");
+		msm_adsp_disable(audio->audplay);
+		return -ENODEV;
+	}
+	audio->enabled = 1;
+	return 0;
+}
+
+static void amrnb_listner(u32 evt_id, union auddev_evt_data *evt_payload,
+			void *private_data)
+{
+	struct audio *audio = (struct audio *) private_data;
+	switch (evt_id) {
+	case AUDDEV_EVT_DEV_RDY:
+		MM_DBG(":AUDDEV_EVT_DEV_RDY\n");
+		audio->source |= (0x1 << evt_payload->routing_id);
+		if (audio->running == 1 && audio->enabled == 1)
+			audpp_route_stream(audio->dec_id, audio->source);
+		break;
+	case AUDDEV_EVT_DEV_RLS:
+		MM_DBG(":AUDDEV_EVT_DEV_RLS\n");
+		audio->source &= ~(0x1 << evt_payload->routing_id);
+		if (audio->running == 1 && audio->enabled == 1)
+			audpp_route_stream(audio->dec_id, audio->source);
+		break;
+	case AUDDEV_EVT_STREAM_VOL_CHG:
+		audio->vol_pan.volume = evt_payload->session_vol;
+		MM_DBG(":AUDDEV_EVT_STREAM_VOL_CHG, stream vol %d\n",
+				audio->vol_pan.volume);
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+		break;
+	default:
+		MM_ERR(":ERROR:wrong event\n");
+		break;
+	}
+}
+/* must be called with audio->lock held */
+static int audamrnb_disable(struct audio *audio)
+{
+	int rc = 0;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+		auddec_dsp_config(audio, 0);
+		rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+		else if (audio->dec_state != MSM_AUD_DECODER_STATE_CLOSE)
+			rc = -EFAULT;
+		else
+			rc = 0;
+		wake_up(&audio->write_wait);
+		wake_up(&audio->read_wait);
+		msm_adsp_disable(audio->audplay);
+		audpp_disable(audio->dec_id, audio);
+		audio->out_needed = 0;
+	}
+	return rc;
+}
+
+/* ------------------- dsp --------------------- */
+static void audamrnb_update_pcm_buf_entry(struct audio *audio,
+		uint32_t *payload)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	if (audio->rflush)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < payload[1]; index++) {
+		if (audio->in[audio->fill_next].addr ==
+		    payload[2 + index * 2]) {
+			MM_DBG("in[%d] ready\n", audio->fill_next);
+			audio->in[audio->fill_next].used =
+			    payload[3 + index * 2];
+			if ((++audio->fill_next) == audio->pcm_buf_count)
+				audio->fill_next = 0;
+
+		} else {
+			MM_ERR("expected=%x ret=%x\n",
+				audio->in[audio->fill_next].addr,
+				payload[1 + index * 2]);
+			break;
+		}
+	}
+	if (audio->in[audio->fill_next].used == 0) {
+		audamrnb_buffer_refresh(audio);
+	} else {
+		MM_DBG("read cannot keep up\n");
+		audio->buf_refresh = 1;
+	}
+	wake_up(&audio->read_wait);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static void audplay_dsp_event(void *data, unsigned id, size_t len,
+			      void (*getevent) (void *ptr, size_t len))
+{
+	struct audio *audio = data;
+	uint32_t msg[28];
+	getevent(msg, sizeof(msg));
+
+	MM_DBG("msg_id=%x\n", id);
+
+	switch (id) {
+	case AUDPLAY_MSG_DEC_NEEDS_DATA:
+		audamrnb_send_data(audio, 1);
+		break;
+
+	case AUDPLAY_MSG_BUFFER_UPDATE:
+		audamrnb_update_pcm_buf_entry(audio, msg);
+		break;
+
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audplaytask)\n");
+		break;
+
+	default:
+		MM_ERR("unexpected message from decoder\n");
+	}
+}
+
+static void audamrnb_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned status = msg[1];
+
+			switch (status) {
+			case AUDPP_DEC_STATUS_SLEEP: {
+				uint16_t reason = msg[2];
+				MM_DBG("decoder status:sleep reason = \
+						0x%04x\n", reason);
+				if ((reason == AUDPP_MSG_REASON_MEM)
+					|| (reason ==
+					AUDPP_MSG_REASON_NODECODER)) {
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_FAILURE;
+					wake_up(&audio->wait);
+				} else if (reason == AUDPP_MSG_REASON_NONE) {
+					/* decoder is in disable state */
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_CLOSE;
+					wake_up(&audio->wait);
+				}
+				break;
+			}
+			case AUDPP_DEC_STATUS_INIT:
+				MM_DBG("decoder status: init \n");
+				if (audio->pcm_feedback)
+					audpp_cmd_cfg_routing_mode(audio);
+				else
+					audpp_cmd_cfg_adec_params(audio);
+				break;
+
+			case AUDPP_DEC_STATUS_CFG:
+				MM_DBG("decoder status: cfg \n");
+				break;
+			case AUDPP_DEC_STATUS_PLAY:
+				MM_DBG("decoder status: play \n");
+				/* send  mixer command */
+				audpp_route_stream(audio->dec_id,
+						audio->source);
+				if (audio->pcm_feedback) {
+					audamrnb_config_hostpcm(audio);
+					audamrnb_buffer_refresh(audio);
+				}
+				audio->dec_state =
+					MSM_AUD_DECODER_STATE_SUCCESS;
+				wake_up(&audio->wait);
+				break;
+			default:
+				MM_ERR("unknown decoder status \n");
+				break;
+			}
+			break;
+		}
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			MM_DBG("CFG_MSG ENABLE\n");
+			auddec_dsp_config(audio, 1);
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+			audpp_dsp_set_eq(audio->dec_id, audio->eq_enable,
+					&audio->eq, POPP);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			MM_DBG("CFG_MSG DISABLE\n");
+			audio->running = 0;
+		} else {
+			MM_DBG("CFG_MSG %d?\n", msg[0]);
+		}
+		break;
+	case AUDPP_MSG_ROUTING_ACK:
+		MM_DBG("ROUTING_ACK mode=%d\n", msg[1]);
+		audpp_cmd_cfg_adec_params(audio);
+		break;
+	case AUDPP_MSG_FLUSH_ACK:
+		MM_DBG("FLUSH_ACK\n");
+		audio->wflush = 0;
+		audio->rflush = 0;
+		wake_up(&audio->write_wait);
+		if (audio->pcm_feedback)
+			audamrnb_buffer_refresh(audio);
+		break;
+	case AUDPP_MSG_PCMDMAMISSED:
+		MM_DBG("PCMDMAMISSED\n");
+		audio->teos = 1;
+		wake_up(&audio->write_wait);
+		break;
+
+	case AUDPP_MSG_AVSYNC_MSG:
+		MM_DBG("AUDPP_MSG_AVSYNC_MSG\n");
+		memcpy(&audio->avsync[0], msg, sizeof(audio->avsync));
+		audio->avsync_flag = 1;
+		wake_up(&audio->avsync_wait);
+		break;
+
+	default:
+		MM_ERR("UNKNOWN (%d)\n", id);
+	}
+
+}
+
+struct msm_adsp_ops audplay_adsp_ops_amrnb = {
+	.event = audplay_dsp_event,
+};
+
+#define audplay_send_queue0(audio, cmd, len) \
+	msm_adsp_write(audio->audplay, audio->queue_id, \
+			cmd, len)
+
+static int auddec_dsp_config(struct audio *audio, int enable)
+{
+	struct audpp_cmd_cfg_dec_type cfg_dec_cmd;
+
+	memset(&cfg_dec_cmd, 0, sizeof(cfg_dec_cmd));
+
+	cfg_dec_cmd.cmd_id = AUDPP_CMD_CFG_DEC_TYPE;
+	if (enable)
+		cfg_dec_cmd.dec_cfg = AUDPP_CMD_UPDATDE_CFG_DEC |
+				AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_AMRNB;
+	else
+		cfg_dec_cmd.dec_cfg = AUDPP_CMD_UPDATDE_CFG_DEC |
+				AUDPP_CMD_DIS_DEC_V;
+	cfg_dec_cmd.dm_mode = 0x0;
+	cfg_dec_cmd.stream_id = audio->dec_id;
+
+	return audpp_send_queue1(&cfg_dec_cmd, sizeof(cfg_dec_cmd));
+}
+
+static void audpp_cmd_cfg_adec_params(struct audio *audio)
+{
+	struct audpp_cmd_cfg_adec_params_amrnb cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_V13K_LEN;
+	cmd.common.dec_id = audio->dec_id;
+	cmd.common.input_sampling_frequency = 8000;
+	cmd.stereo_cfg = AUDPP_CMD_PCM_INTF_MONO_V;
+
+	audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static void audpp_cmd_cfg_routing_mode(struct audio *audio)
+{
+	struct audpp_cmd_routing_mode cmd;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_ROUTING_MODE;
+	cmd.object_number = audio->dec_id;
+	if (audio->pcm_feedback)
+		cmd.routing_mode = ROUTING_MODE_FTRT;
+	else
+		cmd.routing_mode = ROUTING_MODE_RT;
+
+	audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static int audplay_dsp_send_data_avail(struct audio *audio,
+				       unsigned idx, unsigned len)
+{
+	struct audplay_cmd_bitstream_data_avail_nt2 cmd;
+
+	cmd.cmd_id = AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_NT2;
+	if (audio->mfield)
+		cmd.decoder_id = AUDAMRNB_METAFIELD_MASK |
+			(audio->out[idx].mfield_sz >> 1);
+	else
+		cmd.decoder_id = audio->dec_id;
+	cmd.buf_ptr = audio->out[idx].addr;
+	cmd.buf_size = len / 2;
+	cmd.partition_number = 0;
+	return audplay_send_queue0(audio, &cmd, sizeof(cmd));
+}
+
+static void audamrnb_buffer_refresh(struct audio *audio)
+{
+	struct audplay_cmd_buffer_refresh refresh_cmd;
+
+	refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH;
+	refresh_cmd.num_buffers = 1;
+	refresh_cmd.buf0_address = audio->in[audio->fill_next].addr;
+	refresh_cmd.buf0_length = audio->in[audio->fill_next].size -
+	  (audio->in[audio->fill_next].size % AMRNB_DECODED_FRSZ) +
+	  (audio->mfield ? 24 : 0);
+	refresh_cmd.buf_read_count = 0;
+	MM_DBG("buf0_addr=%x buf0_len=%d\n", refresh_cmd.buf0_address,
+			refresh_cmd.buf0_length);
+	(void)audplay_send_queue0(audio, &refresh_cmd, sizeof(refresh_cmd));
+}
+
+static void audamrnb_config_hostpcm(struct audio *audio)
+{
+	struct audplay_cmd_hpcm_buf_cfg cfg_cmd;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	cfg_cmd.cmd_id = AUDPLAY_CMD_HPCM_BUF_CFG;
+	cfg_cmd.max_buffers = audio->pcm_buf_count;
+	cfg_cmd.byte_swap = 0;
+	cfg_cmd.hostpcm_config = (0x8000) | (0x4000);
+	cfg_cmd.feedback_frequency = 1;
+	cfg_cmd.partition_number = 0;
+	(void)audplay_send_queue0(audio, &cfg_cmd, sizeof(cfg_cmd));
+
+}
+
+static void audamrnb_send_data(struct audio *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (needed && !audio->wflush) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+			MM_DBG("frame %d busy\n", audio->out_tail);
+			audplay_dsp_send_data_avail(audio, audio->out_tail,
+						    frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+ done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+
+static void audamrnb_flush(struct audio *audio)
+{
+	audio->out[0].used = 0;
+	audio->out[1].used = 0;
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+	atomic_set(&audio->out_bytes, 0);
+}
+
+static void audamrnb_flush_pcm_buf(struct audio *audio)
+{
+	uint8_t index;
+
+	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
+		audio->in[index].used = 0;
+
+	audio->buf_refresh = 0;
+	audio->read_next = 0;
+	audio->fill_next = 0;
+}
+
+static void audamrnb_ioport_reset(struct audio *audio)
+{
+	/* Make sure read/write thread are free from
+	 * sleep and knowing that system is not able
+	 * to process io request at the moment
+	 */
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audamrnb_flush(audio);
+	mutex_unlock(&audio->write_lock);
+	wake_up(&audio->read_wait);
+	mutex_lock(&audio->read_lock);
+	audamrnb_flush_pcm_buf(audio);
+	mutex_unlock(&audio->read_lock);
+	audio->avsync_flag = 1;
+	wake_up(&audio->avsync_wait);
+}
+
+static int audamrnb_events_pending(struct audio *audio)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	return empty || audio->event_abort;
+}
+
+static void audamrnb_reset_event_queue(struct audio *audio)
+{
+	unsigned long flags;
+	struct audamrnb_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audamrnb_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+				struct audamrnb_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	return;
+}
+
+static long audamrnb_process_event_req(struct audio *audio, void __user *arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audamrnb_event *drv_evt = NULL;
+	int timeout;
+	unsigned long flags;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int) usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(
+			audio->event_wait, audamrnb_events_pending(audio),
+			msecs_to_jiffies(timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(
+			audio->event_wait, audamrnb_events_pending(audio));
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	rc = 0;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audamrnb_event, list);
+		list_del(&drv_evt->list);
+	}
+
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else
+		rc = -1;
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	if (!rc && copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audio_enable_eq(struct audio *audio, int enable)
+{
+	if (audio->eq_enable == enable && !audio->eq_needs_commit)
+		return 0;
+
+	audio->eq_enable = enable;
+
+	if (audio->running) {
+		audpp_dsp_set_eq(audio->dec_id,	enable, &audio->eq, POPP);
+		audio->eq_needs_commit = 0;
+	}
+	return 0;
+}
+
+static int audio_get_avsync_data(struct audio *audio,
+						struct msm_audio_stats *stats)
+{
+	int rc = -EINVAL;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (audio->dec_id == audio->avsync[0] && audio->avsync_flag) {
+		/* av_sync sample count */
+		stats->sample_count = (audio->avsync[2] << 16) |
+						(audio->avsync[3]);
+
+		/* av_sync byte_count */
+		stats->byte_count = (audio->avsync[5] << 16) |
+						(audio->avsync[6]);
+
+		audio->avsync_flag = 0;
+		rc = 0;
+	}
+	local_irq_restore(flags);
+	return rc;
+
+}
+
+static long audamrnb_ioctl(struct file *file, unsigned int cmd,
+		unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = -EINVAL;
+	unsigned long flags = 0;
+	uint16_t enable_mask;
+	int enable;
+	int prev_state;
+
+	MM_DBG("cmd = %d\n", cmd);
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+
+		audio->avsync_flag = 0;
+		memset(&stats, 0, sizeof(stats));
+		if (audpp_query_avsync(audio->dec_id) < 0)
+			return rc;
+
+		rc = wait_event_interruptible_timeout(audio->avsync_wait,
+				(audio->avsync_flag == 1),
+				msecs_to_jiffies(AUDPP_AVSYNC_EVENT_TIMEOUT));
+
+		if (rc < 0)
+			return rc;
+		else if ((rc > 0) || ((rc == 0) && (audio->avsync_flag == 1))) {
+			if (audio_get_avsync_data(audio, &stats) < 0)
+				return rc;
+
+			if (copy_to_user((void *)arg, &stats, sizeof(stats)))
+				return -EFAULT;
+			return 0;
+		} else
+			return -EAGAIN;
+	}
+
+	switch (cmd) {
+	case AUDIO_ENABLE_AUDPP:
+		if (copy_from_user(&enable_mask, (void *) arg,
+						sizeof(enable_mask))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		enable = (enable_mask & EQ_ENABLE) ? 1 : 0;
+		audio_enable_eq(audio, enable);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+	case AUDIO_SET_VOLUME:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.volume = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_PAN:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.pan = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_EQ:
+		prev_state = audio->eq_enable;
+		audio->eq_enable = 0;
+		if (copy_from_user(&audio->eq.num_bands, (void *) arg,
+				sizeof(audio->eq) -
+				(AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2))) {
+			rc = -EFAULT;
+			break;
+		}
+		audio->eq_enable = prev_state;
+		audio->eq_needs_commit = 1;
+		rc = 0;
+		break;
+	}
+
+	if (-EINVAL != rc)
+		return rc;
+
+	if (cmd == AUDIO_GET_EVENT) {
+		MM_DBG("AUDIO_GET_EVENT\n");
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audamrnb_process_event_req(audio,
+					(void __user *) arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		return rc;
+	}
+
+	if (cmd == AUDIO_ABORT_GET_EVENT) {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		MM_DBG("AUDIO_START\n");
+		rc = audamrnb_enable(audio);
+		if (!rc) {
+			rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+			MM_INFO("dec_state %d rc = %d\n", audio->dec_state, rc);
+
+			if (audio->dec_state != MSM_AUD_DECODER_STATE_SUCCESS)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		break;
+	case AUDIO_STOP:
+		MM_DBG("AUDIO_STOP\n");
+		rc = audamrnb_disable(audio);
+		audio->stopped = 1;
+		audamrnb_ioport_reset(audio);
+		audio->stopped = 0;
+		break;
+	case AUDIO_FLUSH:
+		MM_DBG("AUDIO_FLUSH\n");
+		audio->rflush = 1;
+		audio->wflush = 1;
+		audamrnb_ioport_reset(audio);
+		if (audio->running) {
+			audpp_flush(audio->dec_id);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		break;
+	case AUDIO_SET_CONFIG:{
+			struct msm_audio_config config;
+			if (copy_from_user
+			    (&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+			audio->mfield = config.meta_field;
+			rc = 0;
+			break;
+		}
+	case AUDIO_GET_CONFIG:{
+			struct msm_audio_config config;
+			config.buffer_size = BUFSZ;
+			config.buffer_count = 2;
+			config.sample_rate = 8000;
+			config.channel_count = 1;
+			config.meta_field = 0;
+			config.unused[0] = 0;
+			config.unused[1] = 0;
+			config.unused[2] = 0;
+			if (copy_to_user((void *)arg, &config,
+					 sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+
+			break;
+		}
+	case AUDIO_GET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			config.pcm_feedback = audio->pcm_feedback;
+			config.buffer_count = PCM_BUF_MAX_COUNT;
+			config.buffer_size = PCM_BUFSZ_MIN;
+			if (copy_to_user((void *)arg, &config,
+					 sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_SET_PCM_CONFIG:{
+		struct msm_audio_pcm_config config;
+		if (copy_from_user
+		    (&config, (void *)arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (config.pcm_feedback != audio->pcm_feedback) {
+			MM_ERR("Not sufficient permission to"
+				 "change the playback mode\n");
+			rc = -EACCES;
+			break;
+		}
+		if ((config.buffer_count > PCM_BUF_MAX_COUNT) ||
+		    (config.buffer_count == 1))
+			config.buffer_count = PCM_BUF_MAX_COUNT;
+
+		if (config.buffer_size < PCM_BUFSZ_MIN)
+			config.buffer_size = PCM_BUFSZ_MIN;
+
+			/* Check if pcm feedback is required */
+		if ((config.pcm_feedback) && (!audio->read_data)) {
+			MM_DBG("allocate PCM buf %d\n",
+					config.buffer_count *
+					config.buffer_size);
+			audio->read_phys = allocate_contiguous_ebi_nomap(
+						config.buffer_size *
+						config.buffer_count,
+						SZ_4K);
+			if (!audio->read_phys) {
+					rc = -ENOMEM;
+					break;
+			}
+			audio->map_v_read = ioremap(
+						audio->read_phys,
+						config.buffer_size *
+						config.buffer_count);
+			if (IS_ERR(audio->map_v_read)) {
+				MM_ERR("failed to map read phys address\n");
+				rc = -ENOMEM;
+				free_contiguous_memory_by_paddr(
+							audio->read_phys);
+			} else {
+				uint8_t index;
+				uint32_t offset = 0;
+				audio->read_data = audio->map_v_read;
+				audio->buf_refresh = 0;
+				audio->pcm_buf_count =
+					config.buffer_count;
+				audio->read_next = 0;
+				audio->fill_next = 0;
+
+				for (index = 0;
+				index < config.buffer_count; index++) {
+					audio->in[index].data =
+						audio->read_data + offset;
+					audio->in[index].addr =
+					    audio->read_phys + offset;
+					audio->in[index].size =
+					    config.buffer_size;
+					audio->in[index].used = 0;
+					offset += config.buffer_size;
+				}
+				MM_DBG("read buf: phy addr 0x%08x kernel \
+					addr 0x%08x\n", audio->read_phys,
+					(int)audio->read_data);
+				rc = 0;
+			}
+		} else {
+			rc = 0;
+		}
+		break;
+	}
+	case AUDIO_GET_SESSION_ID:
+		if (copy_to_user((void *) arg, &audio->dec_id,
+			sizeof(unsigned short)))
+			rc =  -EFAULT;
+		else
+			rc = 0;
+		break;
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+/* Only useful in tunnel-mode */
+static int audamrnb_fsync(struct file *file, loff_t ppos1, loff_t ppos2, int datasync)
+{
+	struct audio *audio = file->private_data;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	if (!audio->running || audio->pcm_feedback) {
+		rc = -EINVAL;
+		goto done_nolock;
+	}
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(!audio->out[0].used &&
+		!audio->out[1].used &&
+		audio->out_needed) || audio->wflush);
+
+	if (rc < 0)
+		goto done;
+	else if (audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	/* pcm dmamiss message is sent continously
+	 * when decoder is starved so no race
+	 * condition concern
+	 */
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		audio->teos || audio->wflush);
+
+	if (audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+done_nolock:
+	return rc;
+}
+
+static ssize_t audamrnb_read(struct file *file, char __user *buf, size_t count,
+			  loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	int rc = 0;
+
+	if (!audio->pcm_feedback)
+		return 0; /* PCM feedback is not enabled. Nothing to read */
+
+	mutex_lock(&audio->read_lock);
+	MM_DBG("%d \n",	count);
+	while (count > 0) {
+		rc = wait_event_interruptible(audio->read_wait,
+			(audio->in[audio->read_next].used > 0) ||
+			(audio->stopped) || (audio->rflush));
+
+		if (rc < 0)
+			break;
+
+		if (audio->stopped || audio->rflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (count < audio->in[audio->read_next].used) {
+			/* Read must happen in frame boundary. Since driver does
+			 * not know frame size, read count must be greater or
+			 * equal to size of PCM samples
+			 */
+			MM_DBG("read stop - partial frame\n");
+			break;
+		} else {
+			MM_DBG("read from in[%d]\n", audio->read_next);
+
+			if (copy_to_user
+			    (buf, audio->in[audio->read_next].data,
+			     audio->in[audio->read_next].used)) {
+				MM_ERR("invalid addr %x \n", (unsigned int)buf);
+				rc = -EFAULT;
+				break;
+			}
+			count -= audio->in[audio->read_next].used;
+			buf += audio->in[audio->read_next].used;
+			audio->in[audio->read_next].used = 0;
+			if ((++audio->read_next) == audio->pcm_buf_count)
+				audio->read_next = 0;
+			break;
+		}
+	}
+
+	/* don't feed output buffer to HW decoder during flushing
+	 * buffer refresh command will be sent once flush completes
+	 * send buf refresh command here can confuse HW decoder
+	 */
+	if (audio->buf_refresh && !audio->rflush) {
+		audio->buf_refresh = 0;
+		MM_DBG("kick start pcm feedback again\n");
+		audamrnb_buffer_refresh(audio);
+	}
+
+	mutex_unlock(&audio->read_lock);
+
+	if (buf > start)
+		rc = buf - start;
+
+	MM_DBG("read %d bytes\n", rc);
+	return rc;
+}
+
+static int audamrnb_process_eos(struct audio *audio,
+		const char __user *buf_start, unsigned short mfield_size)
+{
+	int rc = 0;
+	struct buffer *frame;
+
+	frame = audio->out + audio->out_head;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->out_needed &&
+		audio->out[0].used == 0 &&
+		audio->out[1].used == 0)
+		|| (audio->stopped)
+		|| (audio->wflush));
+
+	if (rc < 0)
+		goto done;
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (copy_from_user(frame->data, buf_start, mfield_size)) {
+		rc = -EFAULT;
+		goto done;
+	}
+
+	frame->mfield_sz = mfield_size;
+	audio->out_head ^= 1;
+	frame->used = mfield_size;
+	audamrnb_send_data(audio, 0);
+
+done:
+	return rc;
+}
+
+static ssize_t audamrnb_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	char *cpy_ptr;
+	int rc = 0, eos_condition = AUDAMRNB_EOS_NONE;
+	unsigned short mfield_size = 0;
+
+	MM_DBG("cnt=%d\n", count);
+
+	if (count & 1)
+		return -EINVAL;
+
+	mutex_lock(&audio->write_lock);
+	while (count > 0) {
+		frame = audio->out + audio->out_head;
+		cpy_ptr = frame->data;
+		rc = wait_event_interruptible(audio->write_wait,
+					      (frame->used == 0)
+						|| (audio->stopped)
+						|| (audio->wflush));
+
+		MM_DBG("buffer available\n");
+		if (rc < 0)
+			break;
+		if (audio->stopped || audio->wflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (audio->mfield) {
+			if (buf == start) {
+				/* Processing beginning of user buffer */
+				if (__get_user(mfield_size,
+					(unsigned short __user *) buf)) {
+					rc = -EFAULT;
+					break;
+				} else 	if (mfield_size > count) {
+					rc = -EINVAL;
+					break;
+				}
+				MM_DBG("mf offset_val %x\n", mfield_size);
+				if (copy_from_user(cpy_ptr, buf, mfield_size)) {
+					rc = -EFAULT;
+					break;
+				}
+				/* Check if EOS flag is set and buffer
+				 * contains just meta field
+				 */
+				if (cpy_ptr[AUDAMRNB_EOS_FLG_OFFSET] &
+						AUDAMRNB_EOS_FLG_MASK) {
+					MM_DBG("eos set\n");
+					eos_condition = AUDAMRNB_EOS_SET;
+					if (mfield_size == count) {
+						buf += mfield_size;
+						break;
+					} else
+					cpy_ptr[AUDAMRNB_EOS_FLG_OFFSET] &=
+							~AUDAMRNB_EOS_FLG_MASK;
+				}
+				cpy_ptr += mfield_size;
+				count -= mfield_size;
+				buf += mfield_size;
+			} else {
+				mfield_size = 0;
+				MM_DBG("continuous buffer\n");
+			}
+			frame->mfield_sz = mfield_size;
+		}
+
+		xfer = (count > (frame->size - mfield_size)) ?
+			(frame->size - mfield_size) : count;
+		if (copy_from_user(cpy_ptr, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+
+		frame->used = (xfer + mfield_size);
+		audio->out_head ^= 1;
+		count -= xfer;
+		buf += xfer;
+
+		audamrnb_send_data(audio, 0);
+
+	}
+	if (eos_condition == AUDAMRNB_EOS_SET)
+		rc = audamrnb_process_eos(audio, start, mfield_size);
+	mutex_unlock(&audio->write_lock);
+	if (!rc) {
+		if (buf > start)
+			return buf - start;
+	}
+	return rc;
+}
+
+static int audamrnb_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	MM_INFO("audio instance 0x%08x freeing\n", (int)audio);
+
+	mutex_lock(&audio->lock);
+	auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->dec_id);
+	audamrnb_disable(audio);
+	audamrnb_flush(audio);
+	audamrnb_flush_pcm_buf(audio);
+	msm_adsp_put(audio->audplay);
+	audpp_adec_free(audio->dec_id);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&audio->suspend_ctl.node);
+#endif
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audamrnb_reset_event_queue(audio);
+	iounmap(audio->map_v_write);
+	free_contiguous_memory_by_paddr(audio->phys);
+	if (audio->read_data) {
+		iounmap(audio->map_v_read);
+		free_contiguous_memory_by_paddr(audio->read_phys);
+	}
+	mutex_unlock(&audio->lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio);
+	return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audamrnb_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload)
+{
+	struct audamrnb_event *e_node = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+				struct audamrnb_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audamrnb_event), GFP_ATOMIC);
+		if (!e_node) {
+			MM_ERR("No mem to post event %d\n", type);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	wake_up(&audio->event_wait);
+}
+
+static void audamrnb_suspend(struct early_suspend *h)
+{
+	struct audamrnb_suspend_ctl *ctl =
+		container_of(h, struct audamrnb_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audamrnb_post_event(ctl->audio, AUDIO_EVENT_SUSPEND, payload);
+}
+
+static void audamrnb_resume(struct early_suspend *h)
+{
+	struct audamrnb_suspend_ctl *ctl =
+		container_of(h, struct audamrnb_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audamrnb_post_event(ctl->audio, AUDIO_EVENT_RESUME, payload);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audamrnb_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audamrnb_debug_read(struct file *file, char __user *buf,
+					size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 1024;
+	static char buffer[1024];
+	int n = 0, i;
+	struct audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"enabled %d\n", audio->enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_feedback %d\n", audio->pcm_feedback);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_buf_sz %d\n", audio->out[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_buf_count %d \n", audio->pcm_buf_count);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_buf_sz %d \n", audio->in[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"volume %x \n", audio->vol_pan.volume);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"rflush %d\n", audio->rflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"running %d \n", audio->running);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"dec state %d \n", audio->dec_state);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_needed %d \n", audio->out_needed);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_head %d \n", audio->out_head);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_tail %d \n", audio->out_tail);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out[0].used %d \n", audio->out[0].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out[1].used %d \n", audio->out[1].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"buffer_refresh %d \n", audio->buf_refresh);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"read_next %d \n", audio->read_next);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"fill_next %d \n", audio->fill_next);
+	for (i = 0; i < audio->pcm_buf_count; i++)
+		n += scnprintf(buffer + n, debug_bufmax - n,
+				"in[%d].used %d \n", i, audio->in[i].used);
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audamrnb_debug_fops = {
+	.read = audamrnb_debug_read,
+	.open = audamrnb_debug_open,
+};
+#endif
+
+static int audamrnb_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = NULL;
+	int rc, dec_attrb, decid, i;
+	struct audamrnb_event *e_node = NULL;
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_amrnb_" + 5];
+#endif
+
+	/* Allocate Mem for audio instance */
+	audio = kzalloc(sizeof(struct audio), GFP_KERNEL);
+	if (!audio) {
+		MM_ERR("no memory to allocate audio instance \n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	MM_INFO("audio instance 0x%08x created\n", (int)audio);
+
+	/* Allocate the decoder */
+	dec_attrb = AUDDEC_DEC_AMRNB;
+	if ((file->f_mode & FMODE_WRITE) &&
+			(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_NONTUNNEL;
+		audio->pcm_feedback = NON_TUNNEL_MODE_PLAYBACK;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_TUNNEL;
+		audio->pcm_feedback = TUNNEL_MODE_PLAYBACK;
+	} else {
+		kfree(audio);
+		rc = -EACCES;
+		goto done;
+	}
+
+	decid = audpp_adec_alloc(dec_attrb, &audio->module_name,
+			&audio->queue_id);
+
+	if (decid < 0) {
+		MM_ERR("No free decoder available, freeing instance 0x%08x\n",
+				(int)audio);
+		rc = -ENODEV;
+		kfree(audio);
+		goto done;
+	}
+
+	audio->dec_id = decid & MSM_AUD_DECODER_MASK;
+
+	audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
+	if (!audio->phys) {
+		MM_ERR("could not allocate write buffers, freeing instance \
+				0x%08x\n", (int)audio);
+		rc = -ENOMEM;
+		audpp_adec_free(audio->dec_id);
+		kfree(audio);
+		goto done;
+	} else {
+		audio->map_v_write = ioremap(audio->phys, DMASZ);
+		if (IS_ERR(audio->map_v_write)) {
+			MM_ERR("could not map write phys address, freeing \
+					instance 0x%08x\n", (int)audio);
+			rc = -ENOMEM;
+			free_contiguous_memory_by_paddr(audio->phys);
+			audpp_adec_free(audio->dec_id);
+			free_contiguous_memory_by_paddr(audio->phys);
+			kfree(audio);
+			goto done;
+		}
+		audio->data = audio->map_v_write;
+		MM_DBG("write buf: phy addr 0x%08x kernel addr \
+				0x%08x\n", audio->phys, (int)audio->data);
+	}
+
+	rc = msm_adsp_get(audio->module_name, &audio->audplay,
+		&audplay_adsp_ops_amrnb, audio);
+	if (rc) {
+		MM_ERR("failed to get %s module freeing instance 0x%08x\n",
+				audio->module_name, (int)audio);
+		goto err;
+	}
+
+	mutex_init(&audio->lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->get_event_lock);
+	spin_lock_init(&audio->dsp_lock);
+	spin_lock_init(&audio->event_queue_lock);
+	INIT_LIST_HEAD(&audio->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+	init_waitqueue_head(&audio->write_wait);
+	init_waitqueue_head(&audio->read_wait);
+	init_waitqueue_head(&audio->wait);
+	init_waitqueue_head(&audio->event_wait);
+	init_waitqueue_head(&audio->avsync_wait);
+
+	audio->out[0].data = audio->data + 0;
+	audio->out[0].addr = audio->phys + 0;
+	audio->out[0].size = BUFSZ;
+
+	audio->out[1].data = audio->data + BUFSZ;
+	audio->out[1].addr = audio->phys + BUFSZ;
+	audio->out[1].size = BUFSZ;
+
+	audio->vol_pan.volume = 0x2000;
+
+	audamrnb_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+
+	audio->device_events = AUDDEV_EVT_DEV_RDY
+				|AUDDEV_EVT_DEV_RLS|
+				AUDDEV_EVT_STREAM_VOL_CHG;
+
+	rc = auddev_register_evt_listner(audio->device_events,
+					AUDDEV_CLNT_DEC,
+					audio->dec_id,
+					amrnb_listner,
+					(void *)audio);
+	if (rc) {
+		MM_ERR("%s: failed to register listner\n", __func__);
+		goto event_err;
+	}
+
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_amrnb_%04x", audio->dec_id);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+			NULL, (void *) audio, &audamrnb_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		MM_DBG("debugfs_create_file failed\n");
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	audio->suspend_ctl.node.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+	audio->suspend_ctl.node.resume = audamrnb_resume;
+	audio->suspend_ctl.node.suspend = audamrnb_suspend;
+	audio->suspend_ctl.audio = audio;
+	register_early_suspend(&audio->suspend_ctl.node);
+#endif
+	for (i = 0; i < AUDAMRNB_EVENT_NUM; i++) {
+		e_node = kmalloc(sizeof(struct audamrnb_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			MM_ERR("event pkt alloc failed\n");
+			break;
+		}
+	}
+done:
+	return rc;
+event_err:
+	msm_adsp_put(audio->audplay);
+err:
+	iounmap(audio->map_v_write);
+	free_contiguous_memory_by_paddr(audio->phys);
+	audpp_adec_free(audio->dec_id);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_amrnb_fops = {
+	.owner = THIS_MODULE,
+	.open = audamrnb_open,
+	.release = audamrnb_release,
+	.read = audamrnb_read,
+	.write = audamrnb_write,
+	.unlocked_ioctl = audamrnb_ioctl,
+	.fsync = audamrnb_fsync,
+};
+
+struct miscdevice audio_amrnb_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_amrnb",
+	.fops = &audio_amrnb_fops,
+};
+
+static int __init audamrnb_init(void)
+{
+	return misc_register(&audio_amrnb_misc);
+}
+
+static void __exit audamrnb_exit(void)
+{
+	misc_deregister(&audio_amrnb_misc);
+}
+
+module_init(audamrnb_init);
+module_exit(audamrnb_exit);
+
+MODULE_DESCRIPTION("MSM AMR-NB driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c b/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
new file mode 100644
index 0000000..790c510
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
@@ -0,0 +1,903 @@
+/*
+ * amrnb audio input device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2009-2012, Code Aurora Forum. 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.
+ *
+ */
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/msm_audio_amrnb.h>
+#include <linux/android_pmem.h>
+#include <linux/memory_alloc.h>
+
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/msm_adsp.h>
+#include <mach/socinfo.h>
+#include <mach/qdsp5v2/qdsp5audreccmdi.h>
+#include <mach/qdsp5v2/qdsp5audrecmsg.h>
+#include <mach/qdsp5v2/audpreproc.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_memtypes.h>
+
+/* FRAME_NUM must be a power of two */
+#define FRAME_NUM		(8)
+#define FRAME_SIZE		(22 * 2) /* 36 bytes data */
+#define DMASZ 			(FRAME_SIZE * FRAME_NUM)
+
+struct buffer {
+	void *data;
+	uint32_t size;
+	uint32_t read;
+	uint32_t addr;
+};
+
+struct audio_in {
+	struct buffer in[FRAME_NUM];
+
+	spinlock_t dsp_lock;
+
+	atomic_t in_bytes;
+	atomic_t in_samples;
+
+	struct mutex lock;
+	struct mutex read_lock;
+	wait_queue_head_t wait;
+	wait_queue_head_t wait_enable;
+
+	struct msm_adsp_module *audrec;
+	struct audrec_session_info session_info; /*audrec session info*/
+
+	/* configuration to use on next enable */
+	uint32_t buffer_size; /* Frame size (36 bytes) */
+	uint32_t enc_type;
+
+	int dtx_mode;
+	uint32_t frame_format;
+	uint32_t used_mode;
+	uint32_t rec_mode;
+
+	uint32_t dsp_cnt;
+	uint32_t in_head; /* next buffer dsp will write */
+	uint32_t in_tail; /* next buffer read() will read */
+	uint32_t in_count; /* number of buffers available to read() */
+	uint32_t mode;
+
+	const char *module_name;
+	unsigned queue_ids;
+	uint16_t enc_id;
+
+	uint16_t source; /* Encoding source bit mask */
+	uint32_t device_events;
+	uint32_t in_call;
+	uint32_t dev_cnt;
+	int voice_state;
+	spinlock_t dev_lock;
+
+	/* data allocated for various buffers */
+	char *data;
+	dma_addr_t phys;
+	void *map_v_read;
+
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+	char *build_id;
+};
+
+struct audio_frame {
+	uint16_t frame_count_lsw;
+	uint16_t frame_count_msw;
+	uint16_t frame_length;
+	uint16_t erased_pcm;
+	unsigned char raw_bitstream[]; /* samples */
+} __attribute__((packed));
+
+/* Audrec Queue command sent macro's */
+#define audrec_send_bitstreamqueue(audio, cmd, len) \
+	msm_adsp_write(audio->audrec, ((audio->queue_ids & 0xFFFF0000) >> 16),\
+			cmd, len)
+
+#define audrec_send_audrecqueue(audio, cmd, len) \
+	msm_adsp_write(audio->audrec, (audio->queue_ids & 0x0000FFFF),\
+			cmd, len)
+
+struct audio_in the_audio_amrnb_in;
+
+/* DSP command send functions */
+static int audamrnb_in_enc_config(struct audio_in *audio, int enable);
+static int audamrnb_in_param_config(struct audio_in *audio);
+static int audamrnb_in_mem_config(struct audio_in *audio);
+static int audamrnb_in_record_config(struct audio_in *audio, int enable);
+static int audamrnb_dsp_read_buffer(struct audio_in *audio, uint32_t read_cnt);
+
+static void audamrnb_in_get_dsp_frames(struct audio_in *audio);
+
+static void audamrnb_in_flush(struct audio_in *audio);
+
+static void amrnb_in_listener(u32 evt_id, union auddev_evt_data *evt_payload,
+				void *private_data)
+{
+	struct audio_in *audio = (struct audio_in *) private_data;
+	unsigned long flags;
+
+	MM_DBG("evt_id = 0x%8x\n", evt_id);
+	switch (evt_id) {
+	case AUDDEV_EVT_DEV_RDY: {
+		MM_DBG("AUDDEV_EVT_DEV_RDY\n");
+		spin_lock_irqsave(&audio->dev_lock, flags);
+		audio->dev_cnt++;
+		if (!audio->in_call)
+			audio->source |= (0x1 << evt_payload->routing_id);
+		spin_unlock_irqrestore(&audio->dev_lock, flags);
+
+		if ((audio->running == 1) && (audio->enabled == 1))
+			audamrnb_in_record_config(audio, 1);
+
+		break;
+	}
+	case AUDDEV_EVT_DEV_RLS: {
+		MM_DBG("AUDDEV_EVT_DEV_RLS\n");
+		spin_lock_irqsave(&audio->dev_lock, flags);
+		audio->dev_cnt--;
+		if (!audio->in_call)
+			audio->source &= ~(0x1 << evt_payload->routing_id);
+		spin_unlock_irqrestore(&audio->dev_lock, flags);
+
+		if ((!audio->running) || (!audio->enabled))
+			break;
+
+		/* Turn of as per source */
+		if (audio->source)
+			audamrnb_in_record_config(audio, 1);
+		else
+			/* Turn off all */
+			audamrnb_in_record_config(audio, 0);
+
+		break;
+	}
+	case AUDDEV_EVT_VOICE_STATE_CHG: {
+		MM_DBG("AUDDEV_EVT_VOICE_STATE_CHG, state = %d\n",
+				evt_payload->voice_state);
+		audio->voice_state = evt_payload->voice_state;
+		if (audio->in_call && audio->running) {
+			if (audio->voice_state == VOICE_STATE_INCALL)
+				audamrnb_in_record_config(audio, 1);
+			else if (audio->voice_state == VOICE_STATE_OFFCALL) {
+				audamrnb_in_record_config(audio, 0);
+				wake_up(&audio->wait);
+			}
+		}
+
+		break;
+	}
+	default:
+		MM_ERR("wrong event %d\n", evt_id);
+		break;
+	}
+}
+
+/* ------------------- dsp preproc event handler--------------------- */
+static void audpreproc_dsp_event(void *data, unsigned id,  void *msg)
+{
+	struct audio_in *audio = data;
+
+	switch (id) {
+	case AUDPREPROC_ERROR_MSG: {
+		struct audpreproc_err_msg *err_msg = msg;
+
+		MM_ERR("ERROR_MSG: stream id %d err idx %d\n",
+		err_msg->stream_id, err_msg->aud_preproc_err_idx);
+		/* Error case */
+		wake_up(&audio->wait_enable);
+		break;
+	}
+	case AUDPREPROC_CMD_CFG_DONE_MSG: {
+		MM_DBG("CMD_CFG_DONE_MSG \n");
+		break;
+	}
+	case AUDPREPROC_CMD_ENC_CFG_DONE_MSG: {
+		struct audpreproc_cmd_enc_cfg_done_msg *enc_cfg_msg = msg;
+
+		MM_DBG("CMD_ENC_CFG_DONE_MSG: stream id %d enc type \
+			0x%8x\n", enc_cfg_msg->stream_id,
+			enc_cfg_msg->rec_enc_type);
+		/* Encoder enable success */
+		if (enc_cfg_msg->rec_enc_type & ENCODE_ENABLE)
+			audamrnb_in_param_config(audio);
+		else { /* Encoder disable success */
+			audio->running = 0;
+			audamrnb_in_record_config(audio, 0);
+		}
+		break;
+	}
+	case AUDPREPROC_CMD_ENC_PARAM_CFG_DONE_MSG: {
+		MM_DBG("CMD_ENC_PARAM_CFG_DONE_MSG \n");
+		audamrnb_in_mem_config(audio);
+		break;
+	}
+	case AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG: {
+		MM_DBG("AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG \n");
+		wake_up(&audio->wait_enable);
+		break;
+	}
+	default:
+		MM_ERR("Unknown Event id %d\n", id);
+	}
+}
+
+/* ------------------- dsp audrec event handler--------------------- */
+static void audrec_dsp_event(void *data, unsigned id, size_t len,
+			    void (*getevent)(void *ptr, size_t len))
+{
+	struct audio_in *audio = data;
+
+	switch (id) {
+	case AUDREC_CMD_MEM_CFG_DONE_MSG: {
+		MM_DBG("CMD_MEM_CFG_DONE MSG DONE\n");
+		audio->running = 1;
+		if ((!audio->in_call && (audio->dev_cnt > 0)) ||
+			(audio->in_call &&
+				(audio->voice_state == VOICE_STATE_INCALL)))
+			audamrnb_in_record_config(audio, 1);
+		break;
+	}
+	case AUDREC_FATAL_ERR_MSG: {
+		struct audrec_fatal_err_msg fatal_err_msg;
+
+		getevent(&fatal_err_msg, AUDREC_FATAL_ERR_MSG_LEN);
+		MM_ERR("FATAL_ERR_MSG: err id %d\n",
+				fatal_err_msg.audrec_err_id);
+		/* Error stop the encoder */
+		audio->stopped = 1;
+		wake_up(&audio->wait);
+		break;
+	}
+	case AUDREC_UP_PACKET_READY_MSG: {
+		struct audrec_up_pkt_ready_msg pkt_ready_msg;
+
+		getevent(&pkt_ready_msg, AUDREC_UP_PACKET_READY_MSG_LEN);
+		MM_DBG("UP_PACKET_READY_MSG: write cnt lsw  %d \
+		write cnt msw %d read cnt lsw %d  read cnt msw %d \n",\
+		pkt_ready_msg.audrec_packet_write_cnt_lsw, \
+		pkt_ready_msg.audrec_packet_write_cnt_msw, \
+		pkt_ready_msg.audrec_up_prev_read_cnt_lsw, \
+		pkt_ready_msg.audrec_up_prev_read_cnt_msw);
+
+		audamrnb_in_get_dsp_frames(audio);
+		break;
+	}
+	case ADSP_MESSAGE_ID: {
+		MM_DBG("Received ADSP event:module audrectask\n");
+		break;
+	}
+	default:
+		MM_ERR("Unknown Event id %d\n", id);
+	}
+}
+
+static void audamrnb_in_get_dsp_frames(struct audio_in *audio)
+{
+	struct audio_frame *frame;
+	uint32_t index;
+	unsigned long flags;
+
+	index = audio->in_head;
+
+	frame = (void *) (((char *)audio->in[index].data) - \
+			 sizeof(*frame));
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->in[index].size = frame->frame_length;
+
+	/* statistics of read */
+	atomic_add(audio->in[index].size, &audio->in_bytes);
+	atomic_add(1, &audio->in_samples);
+
+	audio->in_head = (audio->in_head + 1) & (FRAME_NUM - 1);
+
+	/* If overflow, move the tail index foward. */
+	if (audio->in_head == audio->in_tail)
+		audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
+	else
+		audio->in_count++;
+
+	audamrnb_dsp_read_buffer(audio, audio->dsp_cnt++);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+
+	wake_up(&audio->wait);
+}
+struct msm_adsp_ops audrec_amrnb_adsp_ops = {
+	.event = audrec_dsp_event,
+};
+
+static int audamrnb_in_enc_config(struct audio_in *audio, int enable)
+{
+	struct audpreproc_audrec_cmd_enc_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	if (audio->build_id[17] == '1') {
+		cmd.cmd_id = AUDPREPROC_AUDREC_CMD_ENC_CFG_2;
+		MM_ERR("sending AUDPREPROC_AUDREC_CMD_ENC_CFG_2 command");
+	} else {
+		cmd.cmd_id = AUDPREPROC_AUDREC_CMD_ENC_CFG;
+		MM_ERR("sending AUDPREPROC_AUDREC_CMD_ENC_CFG command");
+	}
+	cmd.stream_id = audio->enc_id;
+
+	if (enable)
+		cmd.audrec_enc_type = audio->enc_type | ENCODE_ENABLE;
+	else
+		cmd.audrec_enc_type &= ~(ENCODE_ENABLE);
+
+	return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
+}
+
+static int audamrnb_in_param_config(struct audio_in *audio)
+{
+	struct audpreproc_audrec_cmd_parm_cfg_amrnb cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPREPROC_AUDREC_CMD_PARAM_CFG;
+	cmd.common.stream_id = audio->enc_id;
+
+	cmd.dtx_mode = audio->dtx_mode;
+	cmd.test_mode = -1; /* Default set to -1 */
+	cmd.used_mode = audio->used_mode;
+
+	return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
+}
+
+/* To Do: msm_snddev_route_enc(audio->enc_id); */
+static int audamrnb_in_record_config(struct audio_in *audio, int enable)
+{
+	struct audpreproc_afe_cmd_audio_record_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG;
+	cmd.stream_id = audio->enc_id;
+	if (enable)
+		cmd.destination_activity = AUDIO_RECORDING_TURN_ON;
+	else
+		cmd.destination_activity = AUDIO_RECORDING_TURN_OFF;
+
+	cmd.source_mix_mask = audio->source;
+	if (audio->enc_id == 2) {
+		if ((cmd.source_mix_mask &
+				INTERNAL_CODEC_TX_SOURCE_MIX_MASK) ||
+			(cmd.source_mix_mask & AUX_CODEC_TX_SOURCE_MIX_MASK) ||
+			(cmd.source_mix_mask & VOICE_UL_SOURCE_MIX_MASK) ||
+			(cmd.source_mix_mask & VOICE_DL_SOURCE_MIX_MASK)) {
+			cmd.pipe_id = SOURCE_PIPE_1;
+		}
+		if (cmd.source_mix_mask &
+				AUDPP_A2DP_PIPE_SOURCE_MIX_MASK)
+			cmd.pipe_id |= SOURCE_PIPE_0;
+	}
+
+	return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
+}
+
+static int audamrnb_in_mem_config(struct audio_in *audio)
+{
+	struct audrec_cmd_arecmem_cfg cmd;
+	uint16_t *data = (void *) audio->data;
+	int n;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_MEM_CFG_CMD;
+	cmd.audrec_up_pkt_intm_count = 1;
+	cmd.audrec_ext_pkt_start_addr_msw = audio->phys >> 16;
+	cmd.audrec_ext_pkt_start_addr_lsw = audio->phys;
+	cmd.audrec_ext_pkt_buf_number = FRAME_NUM;
+
+	/* prepare buffer pointers:
+	 * 36 bytes amrnb packet + 4 halfword header
+	 */
+	for (n = 0; n < FRAME_NUM; n++) {
+		audio->in[n].data = data + 4;
+		data += (FRAME_SIZE/2); /* word increment */
+		MM_DBG("0x%8x\n", (int)(audio->in[n].data - 8));
+	}
+
+	return audrec_send_audrecqueue(audio, &cmd, sizeof(cmd));
+}
+
+static int audamrnb_dsp_read_buffer(struct audio_in *audio, uint32_t read_cnt)
+{
+	struct up_audrec_packet_ext_ptr cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = UP_AUDREC_PACKET_EXT_PTR;
+	cmd.audrec_up_curr_read_count_msw = read_cnt >> 16;
+	cmd.audrec_up_curr_read_count_lsw = read_cnt;
+
+	return audrec_send_bitstreamqueue(audio, &cmd, sizeof(cmd));
+}
+
+/* must be called with audio->lock held */
+static int audamrnb_in_enable(struct audio_in *audio)
+{
+	if (audio->enabled)
+		return 0;
+
+	if (audpreproc_enable(audio->enc_id, &audpreproc_dsp_event, audio)) {
+		MM_ERR("msm_adsp_enable(audpreproc) failed\n");
+		return -ENODEV;
+	}
+
+	if (msm_adsp_enable(audio->audrec)) {
+		MM_ERR("msm_adsp_enable(audrec) failed\n");
+		audpreproc_disable(audio->enc_id, audio);
+		return -ENODEV;
+	}
+	audio->enabled = 1;
+	audamrnb_in_enc_config(audio, 1);
+
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audamrnb_in_disable(struct audio_in *audio)
+{
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audamrnb_in_enc_config(audio, 0);
+		wake_up(&audio->wait);
+		wait_event_interruptible_timeout(audio->wait_enable,
+				audio->running == 0, 1*HZ);
+		msm_adsp_disable(audio->audrec);
+		audpreproc_disable(audio->enc_id, audio);
+	}
+	return 0;
+}
+
+static void audamrnb_in_flush(struct audio_in *audio)
+{
+	int i;
+
+	audio->dsp_cnt = 0;
+	audio->in_head = 0;
+	audio->in_tail = 0;
+	audio->in_count = 0;
+	for (i = 0; i < FRAME_NUM; i++) {
+		audio->in[i].size = 0;
+		audio->in[i].read = 0;
+	}
+	MM_DBG("in_bytes %d\n", atomic_read(&audio->in_bytes));
+	MM_DBG("in_samples %d\n", atomic_read(&audio->in_samples));
+	atomic_set(&audio->in_bytes, 0);
+	atomic_set(&audio->in_samples, 0);
+}
+
+/* ------------------- device --------------------- */
+static long audamrnb_in_ioctl(struct file *file,
+				unsigned int cmd, unsigned long arg)
+{
+	struct audio_in *audio = file->private_data;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = atomic_read(&audio->in_bytes);
+		stats.sample_count = atomic_read(&audio->in_samples);
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return rc;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START: {
+		uint32_t freq;
+		freq = 48000;
+		MM_DBG("AUDIO_START\n");
+		if (audio->in_call && (audio->voice_state !=
+				VOICE_STATE_INCALL)) {
+			rc = -EPERM;
+			break;
+		}
+		rc = msm_snddev_request_freq(&freq, audio->enc_id,
+					SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
+		MM_DBG("sample rate configured %d\n", freq);
+		if (rc < 0) {
+			MM_DBG(" Sample rate can not be set, return code %d\n",
+								 rc);
+			msm_snddev_withdraw_freq(audio->enc_id,
+					SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
+			MM_DBG("msm_snddev_withdraw_freq\n");
+			break;
+		}
+		/*update aurec session info in audpreproc layer*/
+		audio->session_info.session_id = audio->enc_id;
+		/*amrnb works only on 8KHz*/
+		audio->session_info.sampling_freq = 8000;
+		audpreproc_update_audrec_info(&audio->session_info);
+		rc = audamrnb_in_enable(audio);
+		if (!rc) {
+			rc =
+			wait_event_interruptible_timeout(audio->wait_enable,
+				audio->running != 0, 1*HZ);
+			MM_DBG("state %d rc = %d\n", audio->running, rc);
+
+			if (audio->running == 0)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		audio->stopped = 0;
+		break;
+	}
+	case AUDIO_STOP: {
+		/*reset the sampling frequency information at audpreproc layer*/
+		audio->session_info.sampling_freq = 0;
+		audpreproc_update_audrec_info(&audio->session_info);
+		rc = audamrnb_in_disable(audio);
+		rc = msm_snddev_withdraw_freq(audio->enc_id,
+					SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
+		MM_DBG("msm_snddev_withdraw_freq\n");
+		audio->stopped = 1;
+		break;
+	}
+	case AUDIO_FLUSH: {
+		if (audio->stopped) {
+			/* Make sure we're stopped and we wake any threads
+			 * that might be blocked holding the read_lock.
+			 * While audio->stopped read threads will always
+			 * exit immediately.
+			 */
+			wake_up(&audio->wait);
+			mutex_lock(&audio->read_lock);
+			audamrnb_in_flush(audio);
+			mutex_unlock(&audio->read_lock);
+		}
+		break;
+	}
+	case AUDIO_SET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		/* Allow only single frame */
+		if (cfg.buffer_size != (FRAME_SIZE - 8))
+			rc = -EINVAL;
+		else
+			audio->buffer_size = cfg.buffer_size;
+		break;
+	}
+	case AUDIO_GET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		memset(&cfg, 0, sizeof(cfg));
+		cfg.buffer_size = audio->buffer_size;
+		cfg.buffer_count = FRAME_NUM;
+		if (copy_to_user((void *) arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_GET_AMRNB_ENC_CONFIG_V2: {
+		struct msm_audio_amrnb_enc_config_v2 cfg;
+		memset(&cfg, 0, sizeof(cfg));
+		cfg.dtx_enable = ((audio->dtx_mode == -1) ? 1 : 0);
+		cfg.band_mode = audio->used_mode;
+		cfg.frame_format = audio->frame_format;
+		if (copy_to_user((void *) arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_AMRNB_ENC_CONFIG_V2: {
+		struct msm_audio_amrnb_enc_config_v2 cfg;
+		if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		/* DSP does not support any other than default format */
+		if (audio->frame_format != cfg.frame_format) {
+			rc = -EINVAL;
+			break;
+		}
+		if (cfg.dtx_enable == 0)
+			audio->dtx_mode = 0;
+		else if (cfg.dtx_enable == 1)
+			audio->dtx_mode = -1;
+		else {
+			rc = -EINVAL;
+			break;
+		}
+		audio->used_mode = cfg.band_mode;
+		break;
+	}
+	case AUDIO_SET_INCALL: {
+		struct msm_voicerec_mode cfg;
+		unsigned long flags;
+		if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (cfg.rec_mode != VOC_REC_BOTH &&
+			cfg.rec_mode != VOC_REC_UPLINK &&
+			cfg.rec_mode != VOC_REC_DOWNLINK) {
+			MM_ERR("invalid rec_mode\n");
+			rc = -EINVAL;
+			break;
+		} else {
+			spin_lock_irqsave(&audio->dev_lock, flags);
+			if (cfg.rec_mode == VOC_REC_UPLINK)
+				audio->source = VOICE_UL_SOURCE_MIX_MASK;
+			else if (cfg.rec_mode == VOC_REC_DOWNLINK)
+				audio->source = VOICE_DL_SOURCE_MIX_MASK;
+			else
+				audio->source = VOICE_DL_SOURCE_MIX_MASK |
+						VOICE_UL_SOURCE_MIX_MASK ;
+			audio->in_call = 1;
+			spin_unlock_irqrestore(&audio->dev_lock, flags);
+		}
+		break;
+	}
+	case AUDIO_GET_SESSION_ID: {
+		if (copy_to_user((void *) arg, &audio->enc_id,
+			sizeof(unsigned short))) {
+			rc = -EFAULT;
+		}
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static ssize_t audamrnb_in_read(struct file *file,
+				char __user *buf,
+				size_t count, loff_t *pos)
+{
+	struct audio_in *audio = file->private_data;
+	unsigned long flags;
+	const char __user *start = buf;
+	void *data;
+	uint32_t index;
+	uint32_t size;
+	int rc = 0;
+
+	mutex_lock(&audio->read_lock);
+	while (count > 0) {
+		rc = wait_event_interruptible(
+			audio->wait, (audio->in_count > 0) || audio->stopped
+			|| (audio->in_call && audio->running &&
+				(audio->voice_state == VOICE_STATE_OFFCALL)));
+		if (rc < 0)
+			break;
+
+		if (!audio->in_count) {
+			if (audio->stopped)  {
+				rc = 0;/* End of File */
+				break;
+			} else if (audio->in_call && audio->running &&
+				(audio->voice_state == VOICE_STATE_OFFCALL)) {
+				MM_DBG("Not Permitted Voice Terminated\n");
+				rc = -EPERM; /* Voice Call stopped */
+				break;
+			}
+		}
+
+		index = audio->in_tail;
+		data = (uint8_t *) audio->in[index].data;
+		size = audio->in[index].size;
+		if (count >= size) {
+			if (copy_to_user(buf, data, size)) {
+				rc = -EFAULT;
+				break;
+			}
+			spin_lock_irqsave(&audio->dsp_lock, flags);
+			if (index != audio->in_tail) {
+				/* overrun -- data is
+				 * invalid and we need to retry */
+				spin_unlock_irqrestore(&audio->dsp_lock, flags);
+				continue;
+			}
+			audio->in[index].size = 0;
+			audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
+			audio->in_count--;
+			spin_unlock_irqrestore(&audio->dsp_lock, flags);
+			count -= size;
+			buf += size;
+		} else {
+			MM_ERR("short read\n");
+			break;
+		}
+	}
+	mutex_unlock(&audio->read_lock);
+
+	if (buf > start)
+		return buf - start;
+
+	return rc;
+}
+
+static ssize_t audamrnb_in_write(struct file *file,
+				const char __user *buf,
+				size_t count, loff_t *pos)
+{
+	return -EINVAL;
+}
+
+static int audamrnb_in_release(struct inode *inode, struct file *file)
+{
+	struct audio_in *audio = file->private_data;
+
+	MM_DBG("\n");
+	mutex_lock(&audio->lock);
+	audio->in_call = 0;
+	/* with draw frequency for session
+	   incase not stopped the driver */
+	msm_snddev_withdraw_freq(audio->enc_id, SNDDEV_CAP_TX,
+					AUDDEV_CLNT_ENC);
+	auddev_unregister_evt_listner(AUDDEV_CLNT_ENC, audio->enc_id);
+	/*reset the sampling frequency information at audpreproc layer*/
+	audio->session_info.sampling_freq = 0;
+	audpreproc_update_audrec_info(&audio->session_info);
+	audamrnb_in_disable(audio);
+	audamrnb_in_flush(audio);
+	msm_adsp_put(audio->audrec);
+	audpreproc_aenc_free(audio->enc_id);
+	audio->audrec = NULL;
+	audio->opened = 0;
+	if (audio->data) {
+		iounmap(audio->map_v_read);
+		free_contiguous_memory_by_paddr(audio->phys);
+		audio->data = NULL;
+	}
+	mutex_unlock(&audio->lock);
+	return 0;
+}
+
+static int audamrnb_in_open(struct inode *inode, struct file *file)
+{
+	struct audio_in *audio = &the_audio_amrnb_in;
+	int rc;
+	int encid;
+
+	mutex_lock(&audio->lock);
+	if (audio->opened) {
+		rc = -EBUSY;
+		goto done;
+	}
+	audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
+	if (audio->phys) {
+		audio->map_v_read = ioremap(audio->phys, DMASZ);
+		if (IS_ERR(audio->map_v_read)) {
+			MM_ERR("could not map DMA buffers\n");
+			rc = -ENOMEM;
+			free_contiguous_memory_by_paddr(audio->phys);
+			goto done;
+		}
+		audio->data = audio->map_v_read;
+	} else {
+		MM_ERR("could not allocate DMA buffers\n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	MM_DBG("Memory addr = 0x%8x  phy addr = 0x%8x\n",\
+		(int) audio->data, (int) audio->phys);
+	if ((file->f_mode & FMODE_WRITE) &&
+			(file->f_mode & FMODE_READ)) {
+		rc = -EACCES;
+		MM_ERR("Non tunnel encoding is not supported\n");
+		goto done;
+	} else if (!(file->f_mode & FMODE_WRITE) &&
+					(file->f_mode & FMODE_READ)) {
+		audio->mode = MSM_AUD_ENC_MODE_TUNNEL;
+		MM_DBG("Opened for tunnel mode encoding\n");
+	} else {
+		rc = -EACCES;
+		goto done;
+	}
+
+
+	/* Settings will be re-config at AUDIO_SET_CONFIG,
+	 * but at least we need to have initial config
+	 */
+	audio->buffer_size = (FRAME_SIZE - 8);
+	audio->enc_type = ENC_TYPE_AMRNB | audio->mode;
+	audio->dtx_mode = -1;
+	audio->frame_format = 0;
+	audio->used_mode = 7; /* Bit Rate 12.2 kbps MR122 */
+
+	encid = audpreproc_aenc_alloc(audio->enc_type, &audio->module_name,
+			&audio->queue_ids);
+	if (encid < 0) {
+		MM_ERR("No free encoder available\n");
+		rc = -ENODEV;
+		goto done;
+	}
+	audio->enc_id = encid;
+
+	rc = msm_adsp_get(audio->module_name, &audio->audrec,
+			   &audrec_amrnb_adsp_ops, audio);
+
+	if (rc) {
+		audpreproc_aenc_free(audio->enc_id);
+		goto done;
+	}
+
+	audio->stopped = 0;
+	audio->source = 0;
+
+	audamrnb_in_flush(audio);
+
+	audio->device_events = AUDDEV_EVT_DEV_RDY | AUDDEV_EVT_DEV_RLS |
+				AUDDEV_EVT_VOICE_STATE_CHG;
+
+	audio->voice_state = msm_get_voice_state();
+	rc = auddev_register_evt_listner(audio->device_events,
+					AUDDEV_CLNT_ENC, audio->enc_id,
+					amrnb_in_listener, (void *) audio);
+	if (rc) {
+		MM_ERR("failed to register device event listener\n");
+		goto evt_error;
+	}
+	audio->build_id = socinfo_get_build_id();
+	MM_DBG("Modem build id = %s\n", audio->build_id);
+
+	file->private_data = audio;
+	audio->opened = 1;
+done:
+	mutex_unlock(&audio->lock);
+	return rc;
+evt_error:
+	msm_adsp_put(audio->audrec);
+	audpreproc_aenc_free(audio->enc_id);
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static const struct file_operations audio_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audamrnb_in_open,
+	.release	= audamrnb_in_release,
+	.read		= audamrnb_in_read,
+	.write		= audamrnb_in_write,
+	.unlocked_ioctl	= audamrnb_in_ioctl,
+};
+
+struct miscdevice audio_amrnb_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_amrnb_in",
+	.fops	= &audio_in_fops,
+};
+
+static int __init audamrnb_in_init(void)
+{
+	mutex_init(&the_audio_amrnb_in.lock);
+	mutex_init(&the_audio_amrnb_in.read_lock);
+	spin_lock_init(&the_audio_amrnb_in.dsp_lock);
+	spin_lock_init(&the_audio_amrnb_in.dev_lock);
+	init_waitqueue_head(&the_audio_amrnb_in.wait);
+	init_waitqueue_head(&the_audio_amrnb_in.wait_enable);
+	return misc_register(&audio_amrnb_in_misc);
+}
+
+device_initcall(audamrnb_in_init);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_amrwb.c b/arch/arm/mach-msm/qdsp5v2/audio_amrwb.c
new file mode 100644
index 0000000..a653d5b
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/audio_amrwb.c
@@ -0,0 +1,1727 @@
+/* amrwb audio decoder device
+ *
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+ *
+ * Based on the mp3 native driver in arch/arm/mach-msm/qdsp5v2/audio_mp3.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/earlysuspend.h>
+#include <linux/android_pmem.h>
+#include <linux/memory_alloc.h>
+#include <linux/msm_audio.h>
+#include <linux/slab.h>
+
+#include <mach/msm_adsp.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/qdsp5v2/qdsp5audppmsg.h>
+#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
+#include <mach/qdsp5v2/qdsp5audplaymsg.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/qdsp5v2/audpp.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_memtypes.h>
+
+#define BUFSZ 4110 /* Hold minimum 700ms voice data and 14 bytes of meta in*/
+#define DMASZ (BUFSZ * 2)
+
+#define AUDPLAY_INVALID_READ_PTR_OFFSET	0xFFFF
+#define AUDDEC_DEC_AMRWB 11
+
+#define PCM_BUFSZ_MIN 8216 /* 100ms worth of data and 24 bytes of meta out*/
+#define PCM_BUF_MAX_COUNT 5	/* DSP only accepts 5 buffers at most
+				   but support 2 buffers currently */
+#define ROUTING_MODE_FTRT 1
+#define ROUTING_MODE_RT 2
+/* Decoder status received from AUDPPTASK */
+#define  AUDPP_DEC_STATUS_SLEEP	0
+#define	 AUDPP_DEC_STATUS_INIT  1
+#define  AUDPP_DEC_STATUS_CFG   2
+#define  AUDPP_DEC_STATUS_PLAY  3
+
+#define AUDAMRWB_METAFIELD_MASK 0xFFFF0000
+#define AUDAMRWB_EOS_FLG_OFFSET 0x0A /* Offset from beginning of buffer */
+#define AUDAMRWB_EOS_FLG_MASK 0x01
+#define AUDAMRWB_EOS_NONE 0x0 /* No EOS detected */
+#define AUDAMRWB_EOS_SET 0x1 /* EOS set in meta field */
+
+#define AUDAMRWB_EVENT_NUM 10 /* Default number of pre-allocated event pkts */
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+	unsigned short mfield_sz; /*only useful for data has meta field */
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct audamrwb_suspend_ctl {
+	struct early_suspend node;
+	struct audio *audio;
+};
+#endif
+
+struct audamrwb_event{
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+
+struct audio {
+	struct buffer out[2];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed;	/* number of buffers the dsp is waiting for */
+
+	atomic_t out_bytes;
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	/* Host PCM section */
+	struct buffer in[PCM_BUF_MAX_COUNT];
+	struct mutex read_lock;
+	wait_queue_head_t read_wait;	/* Wait queue for read */
+	char *read_data;	/* pointer to reader buffer */
+	int32_t read_phys;	/* physical address of reader buffer */
+	uint8_t read_next;	/* index to input buffers to be read next */
+	uint8_t fill_next;	/* index to buffer that DSP should be filling */
+	uint8_t pcm_buf_count;	/* number of pcm buffer allocated */
+	/* ---- End of Host PCM section */
+
+	struct msm_adsp_module *audplay;
+
+	/* configuration to use on next enable */
+	uint32_t out_sample_rate;
+	uint32_t out_channel_mode;
+
+	/* data allocated for various buffers */
+	char *data;
+	int32_t phys; /* physical address of write buffer */
+
+	void *map_v_read;
+	void *map_v_write;
+
+	int mfield; /* meta field embedded in data */
+	int rflush; /* Read  flush */
+	int wflush; /* Write flush */
+	int opened;
+	int enabled;
+	int running;
+	int stopped;	/* set when stopped, cleared on flush */
+	int pcm_feedback;
+	int buf_refresh;
+	int teos; /* valid only if tunnel mode & no data left for decoder */
+	enum msm_aud_decoder_state dec_state;	/* Represents decoder state */
+	int reserved; /* A byte is being reserved */
+	char rsv_byte; /* Handle odd length user data */
+
+	const char *module_name;
+	unsigned queue_id;
+	uint16_t dec_id;
+	uint32_t read_ptr_offset;
+	int16_t source;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct audamrwb_suspend_ctl suspend_ctl;
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+
+	wait_queue_head_t wait;
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	wait_queue_head_t event_wait;
+	spinlock_t event_queue_lock;
+	struct mutex get_event_lock;
+	int event_abort;
+	/* AV sync Info */
+	int avsync_flag;              /* Flag to indicate feedback from DSP */
+	wait_queue_head_t avsync_wait;/* Wait queue for AV Sync Message     */
+	/* flags, 48 bits sample/bytes counter per channel */
+	uint16_t avsync[AUDPP_AVSYNC_CH_COUNT * AUDPP_AVSYNC_NUM_WORDS + 1];
+
+	uint32_t device_events;
+
+	int eq_enable;
+	int eq_needs_commit;
+	struct audpp_cmd_cfg_object_params_eqalizer eq;
+	struct audpp_cmd_cfg_object_params_volume vol_pan;
+};
+
+static int auddec_dsp_config(struct audio *audio, int enable);
+static void audpp_cmd_cfg_adec_params(struct audio *audio);
+static void audpp_cmd_cfg_routing_mode(struct audio *audio);
+static void audamrwb_send_data(struct audio *audio, unsigned needed);
+static void audamrwb_config_hostpcm(struct audio *audio);
+static void audamrwb_buffer_refresh(struct audio *audio);
+static void audamrwb_dsp_event(void *private, unsigned id, uint16_t *msg);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audamrwb_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload);
+#endif
+
+/* must be called with audio->lock held */
+static int audamrwb_enable(struct audio *audio)
+{
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	if (audio->enabled)
+		return 0;
+
+	audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	if (msm_adsp_enable(audio->audplay)) {
+		MM_ERR("msm_adsp_enable(audplay) failed\n");
+		return -ENODEV;
+	}
+
+	if (audpp_enable(audio->dec_id, audamrwb_dsp_event, audio)) {
+		MM_ERR("audpp_enable() failed\n");
+		msm_adsp_disable(audio->audplay);
+		return -ENODEV;
+	}
+	audio->enabled = 1;
+	return 0;
+}
+
+static void amrwb_listner(u32 evt_id, union auddev_evt_data *evt_payload,
+			void *private_data)
+{
+	struct audio *audio = (struct audio *) private_data;
+	switch (evt_id) {
+	case AUDDEV_EVT_DEV_RDY:
+		MM_DBG("AUDDEV_EVT_DEV_RDY\n");
+		audio->source |= (0x1 << evt_payload->routing_id);
+		if (audio->running == 1 && audio->enabled == 1)
+			audpp_route_stream(audio->dec_id, audio->source);
+		break;
+	case AUDDEV_EVT_DEV_RLS:
+		MM_DBG("AUDDEV_EVT_DEV_RLS\n");
+		audio->source &= ~(0x1 << evt_payload->routing_id);
+		if (audio->running == 1 && audio->enabled == 1)
+			audpp_route_stream(audio->dec_id, audio->source);
+		break;
+	case AUDDEV_EVT_STREAM_VOL_CHG:
+		audio->vol_pan.volume = evt_payload->session_vol;
+		MM_DBG("AUDDEV_EVT_STREAM_VOL_CHG, stream vol %d\n",
+				audio->vol_pan.volume);
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+		break;
+	default:
+		MM_ERR("ERROR:wrong event\n");
+		break;
+	}
+}
+
+/* must be called with audio->lock held */
+static int audamrwb_disable(struct audio *audio)
+{
+	int rc = 0;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+		auddec_dsp_config(audio, 0);
+		rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+		else if (audio->dec_state != MSM_AUD_DECODER_STATE_CLOSE)
+			rc = -EFAULT;
+		else
+			rc = 0;
+		wake_up(&audio->write_wait);
+		wake_up(&audio->read_wait);
+		msm_adsp_disable(audio->audplay);
+		audpp_disable(audio->dec_id, audio);
+		audio->out_needed = 0;
+	}
+	return rc;
+}
+
+/* ------------------- dsp --------------------- */
+static void audamrwb_update_pcm_buf_entry(struct audio *audio,
+		uint32_t *payload)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	if (audio->rflush)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < payload[1]; index++) {
+		if (audio->in[audio->fill_next].addr ==
+		    payload[2 + index * 2]) {
+			MM_DBG("audamrwb_update_pcm_buf_entry: \
+				in[%d] ready\n", audio->fill_next);
+			audio->in[audio->fill_next].used =
+			    payload[3 + index * 2];
+			if ((++audio->fill_next) == audio->pcm_buf_count)
+				audio->fill_next = 0;
+
+		} else {
+			MM_ERR("expected=%x ret=%x\n",
+				audio->in[audio->fill_next].addr,
+				payload[1 + index * 2]);
+			break;
+		}
+	}
+	if (audio->in[audio->fill_next].used == 0) {
+		audamrwb_buffer_refresh(audio);
+	} else {
+		MM_DBG("audamrwb_update_pcm_buf_entry: \
+				read cannot keep up\n");
+		audio->buf_refresh = 1;
+	}
+	wake_up(&audio->read_wait);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static void audplay_dsp_event(void *data, unsigned id, size_t len,
+			      void (*getevent) (void *ptr, size_t len))
+{
+	struct audio *audio = data;
+	uint32_t msg[28];
+	getevent(msg, sizeof(msg));
+
+	MM_DBG("audplay_dsp_event: msg_id=%x\n", id);
+
+	switch (id) {
+	case AUDPLAY_MSG_DEC_NEEDS_DATA:
+		audamrwb_send_data(audio, 1);
+		break;
+
+	case AUDPLAY_MSG_BUFFER_UPDATE:
+		audamrwb_update_pcm_buf_entry(audio, msg);
+		break;
+
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event:module audplaytask\n");
+		break;
+
+	default:
+		MM_DBG("unexpected message from decoder\n");
+	}
+}
+
+static void audamrwb_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned status = msg[1];
+
+			switch (status) {
+			case AUDPP_DEC_STATUS_SLEEP: {
+				uint16_t reason = msg[2];
+				MM_DBG("decoder status:sleep reason=0x%04x\n",
+					reason);
+				if ((reason == AUDPP_MSG_REASON_MEM)
+					|| (reason ==
+					AUDPP_MSG_REASON_NODECODER)) {
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_FAILURE;
+					wake_up(&audio->wait);
+				} else if (reason == AUDPP_MSG_REASON_NONE) {
+					/* decoder is in disable state */
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_CLOSE;
+					wake_up(&audio->wait);
+				}
+				break;
+			}
+			case AUDPP_DEC_STATUS_INIT:
+				MM_DBG("decoder status: init\n");
+				if (audio->pcm_feedback)
+					audpp_cmd_cfg_routing_mode(audio);
+				else
+					audpp_cmd_cfg_adec_params(audio);
+				break;
+
+			case AUDPP_DEC_STATUS_CFG:
+				MM_DBG("decoder status: cfg\n");
+				break;
+			case AUDPP_DEC_STATUS_PLAY:
+				MM_DBG("decoder status: play\n");
+				/* send  mixer command */
+				audpp_route_stream(audio->dec_id,
+						audio->source);
+				if (audio->pcm_feedback) {
+					audamrwb_config_hostpcm(audio);
+					audamrwb_buffer_refresh(audio);
+				}
+				audio->dec_state =
+					MSM_AUD_DECODER_STATE_SUCCESS;
+				wake_up(&audio->wait);
+				break;
+			default:
+				MM_DBG("unknown decoder status\n");
+				break;
+			}
+			break;
+		}
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			MM_DBG("CFG_MSG ENABLE\n");
+			auddec_dsp_config(audio, 1);
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+			audpp_dsp_set_eq(audio->dec_id,	audio->eq_enable,
+					&audio->eq, POPP);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			MM_DBG("CFG_MSG DISABLE\n");
+			audio->running = 0;
+		} else {
+			MM_DBG("CFG_MSG %d?\n", msg[0]);
+		}
+		break;
+	case AUDPP_MSG_ROUTING_ACK:
+		MM_DBG("ROUTING_ACK mode=%d\n", msg[1]);
+		audpp_cmd_cfg_adec_params(audio);
+		break;
+	case AUDPP_MSG_FLUSH_ACK:
+		MM_DBG("FLUSH_ACK\n");
+		audio->wflush = 0;
+		audio->rflush = 0;
+		wake_up(&audio->write_wait);
+		if (audio->pcm_feedback)
+			audamrwb_buffer_refresh(audio);
+		break;
+	case AUDPP_MSG_PCMDMAMISSED:
+		MM_DBG("PCMDMAMISSED\n");
+		audio->teos = 1;
+		wake_up(&audio->write_wait);
+		break;
+
+	case AUDPP_MSG_AVSYNC_MSG:
+		MM_DBG("AUDPP_MSG_AVSYNC_MSG\n");
+		memcpy(&audio->avsync[0], msg, sizeof(audio->avsync));
+		audio->avsync_flag = 1;
+		wake_up(&audio->avsync_wait);
+		break;
+
+	default:
+		MM_DBG("UNKNOWN (%d)\n", id);
+	}
+
+}
+
+struct msm_adsp_ops audplay_adsp_ops_amrwb = {
+	.event = audplay_dsp_event,
+};
+
+#define audplay_send_queue0(audio, cmd, len) \
+	msm_adsp_write(audio->audplay, audio->queue_id, \
+			cmd, len)
+
+static int auddec_dsp_config(struct audio *audio, int enable)
+{
+	struct audpp_cmd_cfg_dec_type cfg_dec_cmd;
+
+	memset(&cfg_dec_cmd, 0, sizeof(cfg_dec_cmd));
+
+	cfg_dec_cmd.cmd_id = AUDPP_CMD_CFG_DEC_TYPE;
+	if (enable)
+		cfg_dec_cmd.dec_cfg = AUDPP_CMD_UPDATDE_CFG_DEC |
+				AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_AMRWB;
+	else
+		cfg_dec_cmd.dec_cfg = AUDPP_CMD_UPDATDE_CFG_DEC |
+				AUDPP_CMD_DIS_DEC_V;
+	cfg_dec_cmd.dm_mode = 0x0;
+	cfg_dec_cmd.stream_id = audio->dec_id;
+	return audpp_send_queue1(&cfg_dec_cmd, sizeof(cfg_dec_cmd));
+}
+
+static void audpp_cmd_cfg_adec_params(struct audio *audio)
+{
+	struct audpp_cmd_cfg_adec_params_amrwb cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_AMRWB_LEN;
+	cmd.common.dec_id = audio->dec_id;
+	cmd.common.input_sampling_frequency = audio->out_sample_rate;
+	cmd.stereo_cfg = audio->out_channel_mode;
+	audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static void audpp_cmd_cfg_routing_mode(struct audio *audio)
+{
+	struct audpp_cmd_routing_mode cmd;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_ROUTING_MODE;
+	cmd.object_number = audio->dec_id;
+	if (audio->pcm_feedback)
+		cmd.routing_mode = ROUTING_MODE_FTRT;
+	else
+		cmd.routing_mode = ROUTING_MODE_RT;
+
+	audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static int audplay_dsp_send_data_avail(struct audio *audio,
+				       unsigned idx, unsigned len)
+{
+	struct audplay_cmd_bitstream_data_avail_nt2 cmd;
+
+	cmd.cmd_id = AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_NT2;
+	if (audio->mfield)
+		cmd.decoder_id = AUDAMRWB_METAFIELD_MASK |
+			(audio->out[idx].mfield_sz >> 1);
+	else
+		cmd.decoder_id = audio->dec_id;
+	cmd.buf_ptr = audio->out[idx].addr;
+	cmd.buf_size = len / 2;
+	cmd.partition_number = 0;
+	return audplay_send_queue0(audio, &cmd, sizeof(cmd));
+}
+
+static void audamrwb_buffer_refresh(struct audio *audio)
+{
+	struct audplay_cmd_buffer_refresh refresh_cmd;
+
+	refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH;
+	refresh_cmd.num_buffers = 1;
+	refresh_cmd.buf0_address = audio->in[audio->fill_next].addr;
+	refresh_cmd.buf0_length = audio->in[audio->fill_next].size;
+	refresh_cmd.buf_read_count = 0;
+	MM_DBG("buf0_addr=%x buf0_len=%d\n", refresh_cmd.buf0_address,
+			refresh_cmd.buf0_length);
+	(void)audplay_send_queue0(audio, &refresh_cmd, sizeof(refresh_cmd));
+}
+
+static void audamrwb_config_hostpcm(struct audio *audio)
+{
+	struct audplay_cmd_hpcm_buf_cfg cfg_cmd;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	cfg_cmd.cmd_id = AUDPLAY_CMD_HPCM_BUF_CFG;
+	cfg_cmd.max_buffers = audio->pcm_buf_count;
+	cfg_cmd.byte_swap = 0;
+	cfg_cmd.hostpcm_config = (0x8000) | (0x4000);
+	cfg_cmd.feedback_frequency = 1;
+	cfg_cmd.partition_number = 0;
+	(void)audplay_send_queue0(audio, &cfg_cmd, sizeof(cfg_cmd));
+
+}
+
+static void audamrwb_send_data(struct audio *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (needed && !audio->wflush) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+			MM_DBG("frame %d busy\n", audio->out_tail);
+			audplay_dsp_send_data_avail(audio, audio->out_tail,
+						    frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+ done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+
+static void audamrwb_flush(struct audio *audio)
+{
+	audio->out[0].used = 0;
+	audio->out[1].used = 0;
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->reserved = 0;
+	audio->out_needed = 0;
+	atomic_set(&audio->out_bytes, 0);
+}
+
+static void audamrwb_flush_pcm_buf(struct audio *audio)
+{
+	uint8_t index;
+
+	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
+		audio->in[index].used = 0;
+
+	audio->buf_refresh = 0;
+	audio->read_next = 0;
+	audio->fill_next = 0;
+}
+
+static void audamrwb_ioport_reset(struct audio *audio)
+{
+	/* Make sure read/write thread are free from
+	 * sleep and knowing that system is not able
+	 * to process io request at the moment
+	 */
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audamrwb_flush(audio);
+	mutex_unlock(&audio->write_lock);
+	wake_up(&audio->read_wait);
+	mutex_lock(&audio->read_lock);
+	audamrwb_flush_pcm_buf(audio);
+	mutex_unlock(&audio->read_lock);
+	audio->avsync_flag = 1;
+	wake_up(&audio->avsync_wait);
+}
+
+static int audamrwb_events_pending(struct audio *audio)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	return empty || audio->event_abort;
+}
+
+static void audamrwb_reset_event_queue(struct audio *audio)
+{
+	unsigned long flags;
+	struct audamrwb_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audamrwb_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+				struct audamrwb_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	return;
+}
+
+static long audamrwb_process_event_req(struct audio *audio, void __user *arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audamrwb_event *drv_evt = NULL;
+	int timeout;
+	unsigned long flags;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int) usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(
+			audio->event_wait, audamrwb_events_pending(audio),
+			msecs_to_jiffies(timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(
+			audio->event_wait, audamrwb_events_pending(audio));
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	rc = 0;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audamrwb_event, list);
+		list_del(&drv_evt->list);
+	}
+
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else
+		rc = -1;
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	if (!rc && copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audio_enable_eq(struct audio *audio, int enable)
+{
+	if (audio->eq_enable == enable && !audio->eq_needs_commit)
+		return 0;
+
+	audio->eq_enable = enable;
+
+	if (audio->running) {
+		audpp_dsp_set_eq(audio->dec_id, enable, &audio->eq, POPP);
+		audio->eq_needs_commit = 0;
+	}
+	return 0;
+}
+
+static int audio_get_avsync_data(struct audio *audio,
+						struct msm_audio_stats *stats)
+{
+	int rc = -EINVAL;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (audio->dec_id == audio->avsync[0] && audio->avsync_flag) {
+		/* av_sync sample count */
+		stats->sample_count = (audio->avsync[2] << 16) |
+						(audio->avsync[3]);
+
+		/* av_sync byte_count */
+		stats->byte_count = (audio->avsync[5] << 16) |
+						(audio->avsync[6]);
+
+		audio->avsync_flag = 0;
+		rc = 0;
+	}
+	local_irq_restore(flags);
+	return rc;
+
+}
+
+static long audamrwb_ioctl(struct file *file, unsigned int cmd,
+		unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = -EINVAL;
+	unsigned long flags = 0;
+	uint16_t enable_mask;
+	int enable;
+	int prev_state;
+
+	MM_DBG("cmd = %d\n", cmd);
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+
+		audio->avsync_flag = 0;
+		memset(&stats, 0, sizeof(stats));
+		if (audpp_query_avsync(audio->dec_id) < 0)
+			return rc;
+
+		rc = wait_event_interruptible_timeout(audio->avsync_wait,
+				(audio->avsync_flag == 1),
+				msecs_to_jiffies(AUDPP_AVSYNC_EVENT_TIMEOUT));
+
+		if (rc < 0)
+			return rc;
+		else if ((rc > 0) || ((rc == 0) && (audio->avsync_flag == 1))) {
+			if (audio_get_avsync_data(audio, &stats) < 0)
+				return rc;
+
+			if (copy_to_user((void *)arg, &stats, sizeof(stats)))
+				return -EFAULT;
+			return 0;
+		} else
+			return -EAGAIN;
+	}
+
+	switch (cmd) {
+	case AUDIO_ENABLE_AUDPP:
+		if (copy_from_user(&enable_mask, (void *) arg,
+						sizeof(enable_mask))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		enable = (enable_mask & EQ_ENABLE) ? 1 : 0;
+		audio_enable_eq(audio, enable);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+	case AUDIO_SET_VOLUME:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.volume = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_PAN:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.pan = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_EQ:
+		prev_state = audio->eq_enable;
+		audio->eq_enable = 0;
+		if (copy_from_user(&audio->eq.num_bands, (void *) arg,
+				sizeof(audio->eq) -
+				(AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2))) {
+			rc = -EFAULT;
+			break;
+		}
+		audio->eq_enable = prev_state;
+		audio->eq_needs_commit = 1;
+		rc = 0;
+		break;
+	}
+
+	if (-EINVAL != rc)
+		return rc;
+
+	if (cmd == AUDIO_GET_EVENT) {
+		MM_DBG("AUDIO_GET_EVENT\n");
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audamrwb_process_event_req(audio,
+					(void __user *) arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		return rc;
+	}
+
+	if (cmd == AUDIO_ABORT_GET_EVENT) {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		MM_DBG("AUDIO_START\n");
+		rc = audamrwb_enable(audio);
+		if (!rc) {
+			rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+			MM_INFO("dec_state %d rc = %d\n", audio->dec_state, rc);
+
+			if (audio->dec_state != MSM_AUD_DECODER_STATE_SUCCESS)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		break;
+	case AUDIO_STOP:
+		MM_DBG("AUDIO_STOP\n");
+		rc = audamrwb_disable(audio);
+		audio->stopped = 1;
+		audamrwb_ioport_reset(audio);
+		audio->stopped = 0;
+		break;
+	case AUDIO_FLUSH:
+		MM_DBG("AUDIO_FLUSH\n");
+		audio->rflush = 1;
+		audio->wflush = 1;
+		audamrwb_ioport_reset(audio);
+		if (audio->running) {
+			audpp_flush(audio->dec_id);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		break;
+	case AUDIO_SET_CONFIG:{
+			struct msm_audio_config config;
+			if (copy_from_user
+			    (&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+			if (config.channel_count == 1)
+				config.channel_count =
+					AUDPP_CMD_PCM_INTF_MONO_V;
+			else if (config.channel_count == 2)
+				config.channel_count =
+					AUDPP_CMD_PCM_INTF_STEREO_V;
+			else
+				rc = -EINVAL;
+			audio->out_channel_mode = config.channel_count;
+			audio->out_sample_rate = config.sample_rate;
+			audio->mfield = config.meta_field;
+			rc = 0;
+			break;
+		}
+	case AUDIO_GET_CONFIG:{
+			struct msm_audio_config config;
+			config.buffer_size = BUFSZ;
+			config.buffer_count = 2;
+			config.sample_rate = audio->out_sample_rate;
+			if (audio->out_channel_mode ==
+					AUDPP_CMD_PCM_INTF_MONO_V)
+				config.channel_count = 1;
+			else
+				config.channel_count = 2;
+			config.meta_field = 0;
+			config.unused[0] = 0;
+			config.unused[1] = 0;
+			config.unused[2] = 0;
+			if (copy_to_user((void *)arg, &config,
+					 sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+
+			break;
+		}
+	case AUDIO_GET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			config.pcm_feedback = 0;
+			config.buffer_count = PCM_BUF_MAX_COUNT;
+			config.buffer_size = PCM_BUFSZ_MIN;
+			if (copy_to_user((void *)arg, &config,
+					 sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_SET_PCM_CONFIG:{
+		struct msm_audio_pcm_config config;
+		if (copy_from_user
+		    (&config, (void *)arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if ((config.buffer_count > PCM_BUF_MAX_COUNT) ||
+		    (config.buffer_count == 1))
+			config.buffer_count = PCM_BUF_MAX_COUNT;
+
+		if (config.buffer_size < PCM_BUFSZ_MIN)
+			config.buffer_size = PCM_BUFSZ_MIN;
+
+			/* Check if pcm feedback is required */
+		if ((config.pcm_feedback) && (!audio->read_data)) {
+			MM_DBG("allocate PCM buf %d\n", config.buffer_count *
+					config.buffer_size);
+			audio->read_phys = allocate_contiguous_ebi_nomap(
+						config.buffer_size *
+						config.buffer_count,
+						SZ_4K);
+			if (!audio->read_phys) {
+					rc = -ENOMEM;
+					break;
+			}
+			audio->map_v_read = ioremap(
+						audio->read_phys,
+						config.buffer_size *
+						config.buffer_count);
+			if (IS_ERR(audio->map_v_read)) {
+				MM_ERR("Error could not map read"
+							" phys address\n");
+				rc = -ENOMEM;
+				free_contiguous_memory_by_paddr(
+							audio->read_phys);
+			} else {
+				uint8_t index;
+				uint32_t offset = 0;
+				audio->read_data = audio->map_v_read;
+				audio->pcm_feedback = 1;
+				audio->buf_refresh = 0;
+				audio->pcm_buf_count =
+					config.buffer_count;
+				audio->read_next = 0;
+				audio->fill_next = 0;
+
+				for (index = 0;
+				index < config.buffer_count; index++) {
+					audio->in[index].data =
+						audio->read_data + offset;
+					audio->in[index].addr =
+					    audio->read_phys + offset;
+					audio->in[index].size =
+					    config.buffer_size;
+					audio->in[index].used = 0;
+					offset += config.buffer_size;
+				}
+				MM_DBG("read buf: phy addr 0x%08x \
+						kernel addr 0x%08x\n",
+						audio->read_phys,
+						(int)audio->read_data);
+				rc = 0;
+			}
+		} else {
+			rc = 0;
+		}
+		break;
+	}
+	case AUDIO_GET_SESSION_ID:
+		if (copy_to_user((void *) arg, &audio->dec_id,
+					sizeof(unsigned short)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+/* Only useful in tunnel-mode */
+static int audamrwb_fsync(struct file *file, loff_t ppos1, loff_t ppos2, int datasync)
+{
+	struct audio *audio = file->private_data;
+	struct buffer *frame;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	if (!audio->running || audio->pcm_feedback) {
+		rc = -EINVAL;
+		goto done_nolock;
+	}
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(!audio->out[0].used &&
+		!audio->out[1].used &&
+		audio->out_needed) || audio->wflush);
+
+	if (rc < 0)
+		goto done;
+	else if (audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (audio->reserved) {
+		MM_DBG("send reserved byte\n");
+		frame = audio->out + audio->out_tail;
+		((char *) frame->data)[0] = audio->rsv_byte;
+		((char *) frame->data)[1] = 0;
+		frame->used = 2;
+		audamrwb_send_data(audio, 0);
+
+		rc = wait_event_interruptible(audio->write_wait,
+			(!audio->out[0].used &&
+			!audio->out[1].used &&
+			audio->out_needed) || audio->wflush);
+
+		if (rc < 0)
+			goto done;
+		else if (audio->wflush) {
+			rc = -EBUSY;
+			goto done;
+		}
+	}
+
+	/* pcm dmamiss message is sent continously
+	 * when decoder is starved so no race
+	 * condition concern
+	 */
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		audio->teos || audio->wflush);
+
+	if (audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+done_nolock:
+	return rc;
+}
+
+static ssize_t audamrwb_read(struct file *file, char __user *buf, size_t count,
+			  loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	int rc = 0;
+
+	if (!audio->pcm_feedback)
+		return 0; /* PCM feedback is not enabled. Nothing to read */
+
+	mutex_lock(&audio->read_lock);
+	MM_DBG("count %d\n", count);
+	while (count > 0) {
+		rc = wait_event_interruptible(audio->read_wait,
+			(audio->in[audio->read_next].used > 0) ||
+			(audio->stopped) || (audio->rflush));
+
+		if (rc < 0)
+			break;
+
+		if (audio->stopped || audio->rflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (count < audio->in[audio->read_next].used) {
+			/* Read must happen in frame boundary. Since driver does
+			 * not know frame size, read count must be greater or
+			 * equal to size of PCM samples
+			 */
+			MM_DBG("read stop - partial frame\n");
+			break;
+		} else {
+			MM_DBG("read from in[%d]\n", audio->read_next);
+
+			if (copy_to_user
+			    (buf, audio->in[audio->read_next].data,
+			     audio->in[audio->read_next].used)) {
+				MM_ERR("invalid addr %x\n", (unsigned int)buf);
+				rc = -EFAULT;
+				break;
+			}
+			count -= audio->in[audio->read_next].used;
+			buf += audio->in[audio->read_next].used;
+			audio->in[audio->read_next].used = 0;
+			if ((++audio->read_next) == audio->pcm_buf_count)
+				audio->read_next = 0;
+			break;
+		}
+	}
+
+	/* don't feed output buffer to HW decoder during flushing
+	 * buffer refresh command will be sent once flush completes
+	 * send buf refresh command here can confuse HW decoder
+	 */
+	if (audio->buf_refresh && !audio->rflush) {
+		audio->buf_refresh = 0;
+		MM_DBG("kick start pcm feedback again\n");
+		audamrwb_buffer_refresh(audio);
+	}
+
+	mutex_unlock(&audio->read_lock);
+
+	if (buf > start)
+		rc = buf - start;
+
+	MM_DBG("read %d bytes\n", rc);
+	return rc;
+}
+
+static int audamrwb_process_eos(struct audio *audio,
+		const char __user *buf_start, unsigned short mfield_size)
+{
+	struct buffer *frame;
+	char *buf_ptr;
+	int rc = 0;
+
+	MM_DBG("signal input EOS reserved=%d\n", audio->reserved);
+	if (audio->reserved) {
+		MM_DBG("Pass reserve byte\n");
+		frame = audio->out + audio->out_head;
+		buf_ptr = frame->data;
+		rc = wait_event_interruptible(audio->write_wait,
+					(frame->used == 0)
+					|| (audio->stopped)
+					|| (audio->wflush));
+	if (rc < 0)
+		goto done;
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+	buf_ptr[0] = audio->rsv_byte;
+	buf_ptr[1] = 0;
+	audio->out_head ^= 1;
+	frame->mfield_sz = 0;
+	audio->reserved = 0;
+	frame->used = 2;
+	audamrwb_send_data(audio, 0);
+	}
+
+	MM_DBG("Now signal input EOS after reserved bytes %d %d %d\n",
+		audio->out[0].used, audio->out[1].used, audio->out_needed);
+
+	frame = audio->out + audio->out_head;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->out_needed &&
+		audio->out[0].used == 0 &&
+		audio->out[1].used == 0)
+		|| (audio->stopped)
+		|| (audio->wflush));
+
+	if (rc < 0)
+		goto done;
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (copy_from_user(frame->data, buf_start, mfield_size)) {
+		rc = -EFAULT;
+		goto done;
+	}
+
+	frame->mfield_sz = mfield_size;
+	audio->out_head ^= 1;
+	frame->used = mfield_size;
+	audamrwb_send_data(audio, 0);
+
+done:
+	return rc;
+}
+
+static ssize_t audamrwb_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	char *cpy_ptr;
+	int rc = 0, eos_condition = AUDAMRWB_EOS_NONE;
+	unsigned short mfield_size = 0;
+	unsigned dsize;
+
+	MM_DBG("cnt=%d\n", count);
+
+	mutex_lock(&audio->write_lock);
+	while (count > 0) {
+		frame = audio->out + audio->out_head;
+		cpy_ptr = frame->data;
+		dsize = 0;
+		rc = wait_event_interruptible(audio->write_wait,
+					      (frame->used == 0)
+						|| (audio->stopped)
+						|| (audio->wflush));
+
+		MM_DBG("buffer available\n");
+		if (rc < 0)
+			break;
+		if (audio->stopped || audio->wflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (audio->mfield) {
+			if (buf == start) {
+				/* Processing beginning of user buffer */
+				if (__get_user(mfield_size,
+					(unsigned short __user *) buf)) {
+					rc = -EFAULT;
+					break;
+				} else 	if (mfield_size > count) {
+					rc = -EINVAL;
+					break;
+				}
+				MM_DBG("mf offset_val %x\n", mfield_size);
+				if (copy_from_user(cpy_ptr, buf, mfield_size)) {
+					rc = -EFAULT;
+					break;
+				}
+				/* Check if EOS flag is set and buffer
+				 * contains just meta field
+				 */
+				if (cpy_ptr[AUDAMRWB_EOS_FLG_OFFSET] &
+						AUDAMRWB_EOS_FLG_MASK) {
+					MM_DBG("eos set\n");
+					eos_condition = AUDAMRWB_EOS_SET;
+					if (mfield_size == count) {
+						buf += mfield_size;
+						break;
+					} else
+					cpy_ptr[AUDAMRWB_EOS_FLG_OFFSET] &=
+							~AUDAMRWB_EOS_FLG_MASK;
+				}
+				cpy_ptr += mfield_size;
+				count -= mfield_size;
+				dsize += mfield_size;
+				buf += mfield_size;
+			} else {
+				mfield_size = 0;
+				MM_DBG("continuous buffer\n");
+			}
+			frame->mfield_sz = mfield_size;
+		}
+
+		if (audio->reserved) {
+			MM_DBG("append reserved byte %x\n", audio->rsv_byte);
+			*cpy_ptr = audio->rsv_byte;
+			xfer = (count > ((frame->size - mfield_size) - 1)) ?
+				((frame->size - mfield_size) - 1) : count;
+			cpy_ptr++;
+			dsize += 1;
+			audio->reserved = 0;
+		} else
+			xfer = (count > (frame->size - mfield_size)) ?
+				(frame->size - mfield_size) : count;
+
+		if (copy_from_user(cpy_ptr, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+
+		dsize += xfer;
+		if (dsize & 1) {
+			audio->rsv_byte = ((char *) frame->data)[dsize - 1];
+			MM_DBG("odd length buf reserve last byte %x\n",
+					audio->rsv_byte);
+			audio->reserved = 1;
+			dsize--;
+		}
+		count -= xfer;
+		buf += xfer;
+
+		if (dsize > 0) {
+			audio->out_head ^= 1;
+			frame->used = dsize;
+			audamrwb_send_data(audio, 0);
+		}
+	}
+	MM_DBG("eos_condition %x buf[0x%x] start[0x%x]\n", eos_condition,
+			(int) buf, (int) start);
+	if (eos_condition == AUDAMRWB_EOS_SET)
+		rc = audamrwb_process_eos(audio, start, mfield_size);
+	mutex_unlock(&audio->write_lock);
+	if (!rc) {
+		if (buf > start)
+			return buf - start;
+	}
+	return rc;
+}
+
+static int audamrwb_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	MM_INFO("audio instance 0x%08x freeing\n", (int)audio);
+
+	mutex_lock(&audio->lock);
+	auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->dec_id);
+	audamrwb_disable(audio);
+	audamrwb_flush(audio);
+	audamrwb_flush_pcm_buf(audio);
+	msm_adsp_put(audio->audplay);
+	audpp_adec_free(audio->dec_id);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&audio->suspend_ctl.node);
+#endif
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audamrwb_reset_event_queue(audio);
+	iounmap(audio->map_v_write);
+	free_contiguous_memory_by_paddr(audio->phys);
+	if (audio->read_data) {
+		iounmap(audio->map_v_read);
+		free_contiguous_memory_by_paddr(audio->read_phys);
+	}
+	mutex_unlock(&audio->lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio);
+	return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audamrwb_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload)
+{
+	struct audamrwb_event *e_node = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+				struct audamrwb_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audamrwb_event), GFP_ATOMIC);
+		if (!e_node) {
+			MM_ERR("No mem to post event %d\n", type);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	wake_up(&audio->event_wait);
+}
+
+static void audamrwb_suspend(struct early_suspend *h)
+{
+	struct audamrwb_suspend_ctl *ctl =
+		container_of(h, struct audamrwb_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audamrwb_post_event(ctl->audio, AUDIO_EVENT_SUSPEND, payload);
+}
+
+static void audamrwb_resume(struct early_suspend *h)
+{
+	struct audamrwb_suspend_ctl *ctl =
+		container_of(h, struct audamrwb_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audamrwb_post_event(ctl->audio, AUDIO_EVENT_RESUME, payload);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audamrwb_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audamrwb_debug_read(struct file *file, char __user *buf,
+					size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 1024;
+	static char buffer[1024];
+	int n = 0, i;
+	struct audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"enabled %d\n", audio->enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_feedback %d\n", audio->pcm_feedback);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_buf_sz %d\n", audio->out[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_buf_count %d \n", audio->pcm_buf_count);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_buf_sz %d \n", audio->in[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"volume %x \n", audio->vol_pan.volume);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"sample rate %d \n", audio->out_sample_rate);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"channel mode %d \n", audio->out_channel_mode);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"rflush %d\n", audio->rflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"running %d \n", audio->running);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"dec state %d \n", audio->dec_state);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_needed %d \n", audio->out_needed);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_head %d \n", audio->out_head);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_tail %d \n", audio->out_tail);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out[0].used %d \n", audio->out[0].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out[1].used %d \n", audio->out[1].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"buffer_refresh %d \n", audio->buf_refresh);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"read_next %d \n", audio->read_next);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"fill_next %d \n", audio->fill_next);
+	for (i = 0; i < audio->pcm_buf_count; i++)
+		n += scnprintf(buffer + n, debug_bufmax - n,
+				"in[%d].used %d \n", i, audio->in[i].used);
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audamrwb_debug_fops = {
+	.read = audamrwb_debug_read,
+	.open = audamrwb_debug_open,
+};
+#endif
+
+static int audamrwb_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = NULL;
+	int rc, dec_attrb, decid, i;
+	struct audamrwb_event *e_node = NULL;
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_amrwb_" + 5];
+#endif
+
+	/* Allocate Mem for audio instance */
+	audio = kzalloc(sizeof(struct audio), GFP_KERNEL);
+	if (!audio) {
+		MM_ERR("no memory to allocate audio instance\n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	MM_INFO("audio instance 0x%08x created\n", (int)audio);
+
+	/* Allocate the decoder */
+	dec_attrb = AUDDEC_DEC_AMRWB;
+	if (file->f_mode & FMODE_READ)
+		dec_attrb |= MSM_AUD_MODE_NONTUNNEL;
+	else
+		dec_attrb |= MSM_AUD_MODE_TUNNEL;
+
+	decid = audpp_adec_alloc(dec_attrb, &audio->module_name,
+			&audio->queue_id);
+
+	if (decid < 0) {
+		MM_ERR("No free decoder available, freeing instance 0x%08x\n",
+				(int)audio);
+		rc = -ENODEV;
+		kfree(audio);
+		goto done;
+	}
+
+	audio->dec_id = decid & MSM_AUD_DECODER_MASK;
+
+	audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
+	if (!audio->phys) {
+		MM_ERR("could not allocate write buffers, freeing instance \
+				0x%08x\n", (int)audio);
+		rc = -ENOMEM;
+		audpp_adec_free(audio->dec_id);
+		kfree(audio);
+		goto done;
+	} else {
+		audio->map_v_write = ioremap(audio->phys, DMASZ);
+		if (IS_ERR(audio->map_v_write)) {
+			MM_ERR("could not map write phys buffers, freeing \
+					instance 0x%08x\n", (int)audio);
+			rc = -ENOMEM;
+			free_contiguous_memory_by_paddr(audio->phys);
+			audpp_adec_free(audio->dec_id);
+			kfree(audio);
+			goto done;
+		}
+		audio->data = audio->map_v_write;
+		MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+				audio->phys, (int)audio->data);
+	}
+
+	rc = msm_adsp_get(audio->module_name, &audio->audplay,
+		&audplay_adsp_ops_amrwb, audio);
+	if (rc) {
+		MM_ERR("failed to get %s module freeing instance 0x%08x\n",
+				audio->module_name, (int)audio);
+		goto err;
+	}
+
+	mutex_init(&audio->lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->get_event_lock);
+	spin_lock_init(&audio->dsp_lock);
+	spin_lock_init(&audio->event_queue_lock);
+	INIT_LIST_HEAD(&audio->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+	init_waitqueue_head(&audio->write_wait);
+	init_waitqueue_head(&audio->read_wait);
+	init_waitqueue_head(&audio->wait);
+	init_waitqueue_head(&audio->event_wait);
+	init_waitqueue_head(&audio->avsync_wait);
+
+	audio->out[0].data = audio->data + 0;
+	audio->out[0].addr = audio->phys + 0;
+	audio->out[0].size = BUFSZ;
+
+	audio->out[1].data = audio->data + BUFSZ;
+	audio->out[1].addr = audio->phys + BUFSZ;
+	audio->out[1].size = BUFSZ;
+
+	audio->vol_pan.volume = 0x2000;
+	audio->vol_pan.pan = 0x0;
+	audio->eq_enable = 0;
+	audio->out_sample_rate = 44100;
+	audio->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V;
+
+	audamrwb_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+	audio->event_abort = 0;
+	audio->device_events = AUDDEV_EVT_DEV_RDY
+				|AUDDEV_EVT_DEV_RLS|
+				AUDDEV_EVT_STREAM_VOL_CHG;
+
+	rc = auddev_register_evt_listner(audio->device_events,
+					AUDDEV_CLNT_DEC,
+					audio->dec_id,
+					amrwb_listner,
+					(void *)audio);
+	if (rc) {
+		MM_ERR("failed to register listner\n");
+		goto event_err;
+	}
+
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_amrwb_%04x", audio->dec_id);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+			NULL, (void *) audio, &audamrwb_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		MM_DBG("debugfs_create_file failed\n");
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	audio->suspend_ctl.node.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+	audio->suspend_ctl.node.resume = audamrwb_resume;
+	audio->suspend_ctl.node.suspend = audamrwb_suspend;
+	audio->suspend_ctl.audio = audio;
+	register_early_suspend(&audio->suspend_ctl.node);
+#endif
+	for (i = 0; i < AUDAMRWB_EVENT_NUM; i++) {
+		e_node = kmalloc(sizeof(struct audamrwb_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			MM_ERR("event pkt alloc failed\n");
+			break;
+		}
+	}
+done:
+	return rc;
+event_err:
+	msm_adsp_put(audio->audplay);
+err:
+	iounmap(audio->map_v_write);
+	free_contiguous_memory_by_paddr(audio->phys);
+	audpp_adec_free(audio->dec_id);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_amrwb_fops = {
+	.owner = THIS_MODULE,
+	.open = audamrwb_open,
+	.release = audamrwb_release,
+	.read = audamrwb_read,
+	.write = audamrwb_write,
+	.unlocked_ioctl = audamrwb_ioctl,
+	.fsync = audamrwb_fsync,
+};
+
+struct miscdevice audio_amrwb_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_amrwb",
+	.fops = &audio_amrwb_fops,
+};
+
+static int __init audamrwb_init(void)
+{
+	return misc_register(&audio_amrwb_misc);
+}
+
+static void __exit audamrwb_exit(void)
+{
+	misc_deregister(&audio_amrwb_misc);
+}
+
+module_init(audamrwb_init);
+module_exit(audamrwb_exit);
+
+MODULE_DESCRIPTION("MSM AMR-WB driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_dev_ctl.c b/arch/arm/mach-msm/qdsp5v2/audio_dev_ctl.c
new file mode 100644
index 0000000..b6d6e5e
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/audio_dev_ctl.c
@@ -0,0 +1,1328 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/msm_audio.h>
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <mach/debug_mm.h>
+#include <mach/qdsp5v2/qdsp5audppmsg.h>
+#include <mach/qdsp5v2/audpp.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+
+#ifndef MAX
+#define  MAX(x, y) (((x) > (y)) ? (x) : (y))
+#endif
+
+
+static DEFINE_MUTEX(session_lock);
+
+struct audio_dev_ctrl_state {
+	struct msm_snddev_info *devs[AUDIO_DEV_CTL_MAX_DEV];
+	u32 num_dev;
+	atomic_t opened;
+	struct msm_snddev_info *voice_rx_dev;
+	struct msm_snddev_info *voice_tx_dev;
+	wait_queue_head_t      wait;
+};
+
+static struct audio_dev_ctrl_state audio_dev_ctrl;
+struct event_listner event;
+#define MAX_DEC_SESSIONS	7
+#define MAX_ENC_SESSIONS	3
+
+struct session_freq {
+	int freq;
+	int evt;
+};
+
+
+struct audio_routing_info {
+	unsigned short mixer_mask[MAX_DEC_SESSIONS];
+	unsigned short audrec_mixer_mask[MAX_ENC_SESSIONS];
+	struct session_freq dec_freq[MAX_DEC_SESSIONS];
+	struct session_freq enc_freq[MAX_ENC_SESSIONS];
+	int dual_mic_setting[MAX_ENC_SESSIONS];
+	int voice_tx_dev_id;
+	int voice_rx_dev_id;
+	int voice_tx_sample_rate;
+	int voice_rx_sample_rate;
+	signed int voice_tx_vol;
+	signed int voice_rx_vol;
+	int tx_mute;
+	int rx_mute;
+	int voice_state;
+};
+
+static struct audio_routing_info routing_info;
+
+#ifdef CONFIG_DEBUG_FS
+
+static struct dentry *dentry;
+static int rtc_getdevice_dbg_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	MM_INFO("debug intf %s\n", (char *) file->private_data);
+	return 0;
+}
+bool is_dev_opened(u32 adb_id)
+{
+
+	int dev_id = 0;
+	struct msm_snddev_info *dev_info = NULL;
+
+	for (dev_id = 0; dev_id < audio_dev_ctrl.num_dev; dev_id++) {
+		dev_info = audio_dev_ctrl_find_dev(dev_id);
+	      if (IS_ERR(dev_info)) {
+		MM_ERR("pass invalid dev_id %d\n", dev_id);
+			  return false;
+		}
+		if (dev_info->opened && (dev_info->acdb_id == adb_id))
+			return true;
+	}
+
+  return false;
+}
+static ssize_t rtc_getdevice_dbg_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *ppos)
+{
+	static char buffer[1024];
+	static char swap_buf[1024];
+	const int debug_bufmax = sizeof(buffer);
+	int n = 0;
+	int swap_count = 0;
+	int rc = 0;
+    int dev_count = 0;
+	int dev_id = 0;
+	struct msm_snddev_info *dev_info = NULL;
+
+
+	if (audio_dev_ctrl.num_dev <= 0) {
+		MM_ERR("Invalid no Device present\n");
+		dev_count = 0;
+		n = scnprintf(buffer, debug_bufmax, "DEV_NO:0x%x\n", dev_count);
+	} else {
+	for (dev_id = 0; dev_id < audio_dev_ctrl.num_dev; dev_id++) {
+		dev_info = audio_dev_ctrl_find_dev(dev_id);
+		if (IS_ERR(dev_info)) {
+			MM_ERR("pass invalid dev_id %d\n", dev_id);
+			rc = PTR_ERR(dev_info);
+			return rc;
+		}
+		if (dev_info->opened) {
+			n += scnprintf(swap_buf + n, debug_bufmax - n,
+					"ACDB_ID:0x%x;CAPB:0x%x\n",
+					dev_info->acdb_id,
+					dev_info->capability);
+		      dev_count++;
+		      MM_DBG("RTC Get Device %x COPP %x Session Mask \
+			      %x Capb %x Dev Count %x\n",
+			     dev_id , dev_info->copp_id, dev_info->sessions,
+			     dev_info->capability, dev_count);
+
+		}
+	}
+
+	swap_count = scnprintf(buffer, debug_bufmax, \
+			"DEV_NO:0x%x\n", dev_count);
+
+	memcpy(buffer+swap_count, swap_buf, n*sizeof(char));
+	n = n+swap_count;
+
+	buffer[n] = 0;
+    }
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations rtc_acdb_debug_fops = {
+	.open = rtc_getdevice_dbg_open,
+	.read = rtc_getdevice_dbg_read
+};
+#endif
+int msm_reset_all_device(void)
+{
+	int rc = 0;
+	int dev_id = 0;
+	struct msm_snddev_info *dev_info = NULL;
+
+	for (dev_id = 0; dev_id < audio_dev_ctrl.num_dev; dev_id++) {
+		dev_info = audio_dev_ctrl_find_dev(dev_id);
+		if (IS_ERR(dev_info)) {
+			MM_ERR("pass invalid dev_id %d\n", dev_id);
+			rc = PTR_ERR(dev_info);
+			return rc;
+		}
+		if (!dev_info->opened)
+			continue;
+		MM_DBG("Resetting device %d active on COPP %d"
+			"with  0x%08x as routing\n",
+				dev_id, dev_info->copp_id, dev_info->sessions);
+		broadcast_event(AUDDEV_EVT_REL_PENDING,
+					dev_id,
+					SESSION_IGNORE);
+		rc = dev_info->dev_ops.close(dev_info);
+		if (rc < 0) {
+			MM_ERR("Snd device %d failed close!\n", dev_id);
+			return rc;
+		} else {
+			dev_info->opened = 0;
+			broadcast_event(AUDDEV_EVT_DEV_RLS,
+				dev_id,
+				SESSION_IGNORE);
+		}
+		dev_info->sessions = 0;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(msm_reset_all_device);
+
+int msm_set_dual_mic_config(int enc_session_id, int config)
+{
+	int i;
+	if (enc_session_id >= MAX_ENC_SESSIONS)
+		return -EINVAL;
+	/*config is set(1) dual mic recording is selected */
+	/*config is reset (0) dual mic recording is not selected*/
+	routing_info.dual_mic_setting[enc_session_id] = config;
+	for (i = 0; i < MAX_ENC_SESSIONS; i++)
+		MM_DBG("dual_mic_setting[%d] = %d\n",
+			i, routing_info.dual_mic_setting[i]);
+	return 0;
+}
+EXPORT_SYMBOL(msm_set_dual_mic_config);
+
+int msm_get_dual_mic_config(int enc_session_id)
+{
+	if (enc_session_id >= MAX_ENC_SESSIONS)
+		return -EINVAL;
+	return routing_info.dual_mic_setting[enc_session_id];
+}
+EXPORT_SYMBOL(msm_get_dual_mic_config);
+
+int msm_get_voice_state(void)
+{
+	MM_DBG("voice state %d\n", routing_info.voice_state);
+	return routing_info.voice_state;
+}
+EXPORT_SYMBOL(msm_get_voice_state);
+
+int msm_set_voice_mute(int dir, int mute)
+{
+	MM_DBG("dir %x mute %x\n", dir, mute);
+	if (!audio_dev_ctrl.voice_rx_dev
+		|| !audio_dev_ctrl.voice_tx_dev)
+		return -EPERM;
+	if (dir == DIR_TX) {
+		routing_info.tx_mute = mute;
+		broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG,
+			routing_info.voice_tx_dev_id, SESSION_IGNORE);
+	} else
+		return -EPERM;
+	return 0;
+}
+EXPORT_SYMBOL(msm_set_voice_mute);
+
+int msm_set_voice_vol(int dir, s32 volume)
+{
+	if (!audio_dev_ctrl.voice_rx_dev
+		|| !audio_dev_ctrl.voice_tx_dev)
+		return -EPERM;
+	if (dir == DIR_TX) {
+		routing_info.voice_tx_vol = volume;
+		broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG,
+					routing_info.voice_tx_dev_id,
+					SESSION_IGNORE);
+	} else if (dir == DIR_RX) {
+		routing_info.voice_rx_vol = volume;
+		broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG,
+					routing_info.voice_rx_dev_id,
+					SESSION_IGNORE);
+	} else
+		return -EINVAL;
+	return 0;
+}
+EXPORT_SYMBOL(msm_set_voice_vol);
+
+void msm_snddev_register(struct msm_snddev_info *dev_info)
+{
+	mutex_lock(&session_lock);
+	if (audio_dev_ctrl.num_dev < AUDIO_DEV_CTL_MAX_DEV) {
+		audio_dev_ctrl.devs[audio_dev_ctrl.num_dev] = dev_info;
+		dev_info->dev_volume = 50; /* 50%  */
+		dev_info->sessions = 0x0;
+		dev_info->usage_count = 0;
+		dev_info->set_sample_rate = 0;
+		audio_dev_ctrl.num_dev++;
+	} else
+		MM_ERR("%s: device registry max out\n", __func__);
+	mutex_unlock(&session_lock);
+}
+EXPORT_SYMBOL(msm_snddev_register);
+
+int msm_snddev_devcount(void)
+{
+	return audio_dev_ctrl.num_dev;
+}
+EXPORT_SYMBOL(msm_snddev_devcount);
+
+int msm_snddev_query(int dev_id)
+{
+	if (dev_id <= audio_dev_ctrl.num_dev)
+			return 0;
+	return -ENODEV;
+}
+EXPORT_SYMBOL(msm_snddev_query);
+
+int msm_snddev_is_set(int popp_id, int copp_id)
+{
+	return routing_info.mixer_mask[popp_id] & (0x1 << copp_id);
+}
+EXPORT_SYMBOL(msm_snddev_is_set);
+
+unsigned short msm_snddev_route_enc(int enc_id)
+{
+	if (enc_id >= MAX_ENC_SESSIONS)
+		return -EINVAL;
+	return routing_info.audrec_mixer_mask[enc_id];
+}
+EXPORT_SYMBOL(msm_snddev_route_enc);
+
+unsigned short msm_snddev_route_dec(int popp_id)
+{
+	if (popp_id >= MAX_DEC_SESSIONS)
+		return -EINVAL;
+	return routing_info.mixer_mask[popp_id];
+}
+EXPORT_SYMBOL(msm_snddev_route_dec);
+
+int msm_snddev_set_dec(int popp_id, int copp_id, int set)
+{
+	if (set)
+		routing_info.mixer_mask[popp_id] |= (0x1 << copp_id);
+	else
+		routing_info.mixer_mask[popp_id] &= ~(0x1 << copp_id);
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_snddev_set_dec);
+
+int msm_snddev_set_enc(int popp_id, int copp_id, int set)
+{
+	if (set)
+		routing_info.audrec_mixer_mask[popp_id] |= (0x1 << copp_id);
+	else
+		routing_info.audrec_mixer_mask[popp_id] &= ~(0x1 << copp_id);
+	return 0;
+}
+EXPORT_SYMBOL(msm_snddev_set_enc);
+
+int msm_device_is_voice(int dev_id)
+{
+	if ((dev_id == routing_info.voice_rx_dev_id)
+		|| (dev_id == routing_info.voice_tx_dev_id))
+		return 0;
+	else
+		return -EINVAL;
+}
+EXPORT_SYMBOL(msm_device_is_voice);
+
+int msm_set_voc_route(struct msm_snddev_info *dev_info,
+			int stream_type, int dev_id)
+{
+	int rc = 0;
+	u32 session_mask = 0;
+
+	mutex_lock(&session_lock);
+	switch (stream_type) {
+	case AUDIO_ROUTE_STREAM_VOICE_RX:
+		if (audio_dev_ctrl.voice_rx_dev)
+			audio_dev_ctrl.voice_rx_dev->sessions &= ~0xFF;
+
+		if (!(dev_info->capability & SNDDEV_CAP_RX) |
+		    !(dev_info->capability & SNDDEV_CAP_VOICE)) {
+			rc = -EINVAL;
+			break;
+		}
+		audio_dev_ctrl.voice_rx_dev = dev_info;
+		if (audio_dev_ctrl.voice_rx_dev) {
+			session_mask =
+				0x1 << (8 * ((int)AUDDEV_CLNT_VOC-1));
+			audio_dev_ctrl.voice_rx_dev->sessions |=
+				session_mask;
+		}
+		routing_info.voice_rx_dev_id = dev_id;
+		break;
+	case AUDIO_ROUTE_STREAM_VOICE_TX:
+		if (audio_dev_ctrl.voice_tx_dev)
+			audio_dev_ctrl.voice_tx_dev->sessions &= ~0xFF;
+
+		if (!(dev_info->capability & SNDDEV_CAP_TX) |
+		    !(dev_info->capability & SNDDEV_CAP_VOICE)) {
+			rc = -EINVAL;
+			break;
+		}
+
+		audio_dev_ctrl.voice_tx_dev = dev_info;
+		if (audio_dev_ctrl.voice_rx_dev) {
+			session_mask =
+				0x1 << (8 * ((int)AUDDEV_CLNT_VOC-1));
+			audio_dev_ctrl.voice_tx_dev->sessions |=
+				session_mask;
+		}
+		routing_info.voice_tx_dev_id = dev_id;
+		break;
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&session_lock);
+	return rc;
+}
+EXPORT_SYMBOL(msm_set_voc_route);
+
+void msm_release_voc_thread(void)
+{
+	wake_up(&audio_dev_ctrl.wait);
+}
+EXPORT_SYMBOL(msm_release_voc_thread);
+
+int msm_snddev_get_enc_freq(session_id)
+{
+	return routing_info.enc_freq[session_id].freq;
+}
+EXPORT_SYMBOL(msm_snddev_get_enc_freq);
+
+int msm_get_voc_freq(int *tx_freq, int *rx_freq)
+{
+	*tx_freq = routing_info.voice_tx_sample_rate;
+	*rx_freq = routing_info.voice_rx_sample_rate;
+	return 0;
+}
+EXPORT_SYMBOL(msm_get_voc_freq);
+
+int msm_get_voc_route(u32 *rx_id, u32 *tx_id)
+{
+	int rc = 0;
+
+	if (!rx_id || !tx_id)
+		return -EINVAL;
+
+	mutex_lock(&session_lock);
+	if (!audio_dev_ctrl.voice_rx_dev || !audio_dev_ctrl.voice_tx_dev) {
+		rc = -ENODEV;
+		mutex_unlock(&session_lock);
+		return rc;
+	}
+
+	*rx_id = audio_dev_ctrl.voice_rx_dev->acdb_id;
+	*tx_id = audio_dev_ctrl.voice_tx_dev->acdb_id;
+
+	mutex_unlock(&session_lock);
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_get_voc_route);
+
+struct msm_snddev_info *audio_dev_ctrl_find_dev(u32 dev_id)
+{
+	struct msm_snddev_info *info;
+
+	if ((audio_dev_ctrl.num_dev - 1) < dev_id) {
+		info = ERR_PTR(-ENODEV);
+		goto error;
+	}
+
+	info = audio_dev_ctrl.devs[dev_id];
+error:
+	return info;
+
+}
+EXPORT_SYMBOL(audio_dev_ctrl_find_dev);
+
+int snddev_voice_set_volume(int vol, int path)
+{
+	if (audio_dev_ctrl.voice_rx_dev
+		&& audio_dev_ctrl.voice_tx_dev) {
+		if (path)
+			audio_dev_ctrl.voice_tx_dev->dev_volume = vol;
+		else
+			audio_dev_ctrl.voice_rx_dev->dev_volume = vol;
+	} else
+		return -ENODEV;
+	return 0;
+}
+EXPORT_SYMBOL(snddev_voice_set_volume);
+
+static int audio_dev_ctrl_get_devices(struct audio_dev_ctrl_state *dev_ctrl,
+				      void __user *arg)
+{
+	int rc = 0;
+	u32 index;
+	struct msm_snd_device_list work_list;
+	struct msm_snd_device_info *work_tbl;
+
+	if (copy_from_user(&work_list, arg, sizeof(work_list))) {
+		rc = -EFAULT;
+		goto error;
+	}
+
+	if (work_list.num_dev > dev_ctrl->num_dev) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	work_tbl = kmalloc(work_list.num_dev *
+		sizeof(struct msm_snd_device_info), GFP_KERNEL);
+	if (!work_tbl) {
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	for (index = 0; index < dev_ctrl->num_dev; index++) {
+		work_tbl[index].dev_id = index;
+		work_tbl[index].dev_cap = dev_ctrl->devs[index]->capability;
+		strlcpy(work_tbl[index].dev_name, dev_ctrl->devs[index]->name,
+		64);
+	}
+
+	if (copy_to_user((void *) (work_list.list), work_tbl,
+		 work_list.num_dev * sizeof(struct msm_snd_device_info)))
+		rc = -EFAULT;
+	kfree(work_tbl);
+error:
+	return rc;
+}
+
+
+int auddev_register_evt_listner(u32 evt_id, u32 clnt_type, u32 clnt_id,
+		void (*listner)(u32 evt_id,
+			union auddev_evt_data *evt_payload,
+			void *private_data),
+		void *private_data)
+{
+	int rc;
+	struct msm_snd_evt_listner *callback = NULL;
+	struct msm_snd_evt_listner *new_cb;
+
+	new_cb = kzalloc(sizeof(struct msm_snd_evt_listner), GFP_KERNEL);
+	if (!new_cb) {
+		MM_ERR("No memory to add new listener node\n");
+		return -ENOMEM;
+	}
+
+	mutex_lock(&session_lock);
+	new_cb->cb_next = NULL;
+	new_cb->auddev_evt_listener = listner;
+	new_cb->evt_id = evt_id;
+	new_cb->clnt_type = clnt_type;
+	new_cb->clnt_id = clnt_id;
+	new_cb->private_data = private_data;
+	if (event.cb == NULL) {
+		event.cb = new_cb;
+		new_cb->cb_prev = NULL;
+	} else {
+		callback = event.cb;
+		for (; ;) {
+			if (callback->cb_next == NULL)
+				break;
+			else {
+				callback = callback->cb_next;
+				continue;
+			}
+		}
+		callback->cb_next = new_cb;
+		new_cb->cb_prev = callback;
+	}
+	event.num_listner++;
+	mutex_unlock(&session_lock);
+	rc = 0;
+	return rc;
+}
+EXPORT_SYMBOL(auddev_register_evt_listner);
+
+int auddev_unregister_evt_listner(u32 clnt_type, u32 clnt_id)
+{
+	struct msm_snd_evt_listner *callback = event.cb;
+	struct msm_snddev_info *info;
+	u32 session_mask = 0;
+	int i = 0;
+
+	mutex_lock(&session_lock);
+	while (callback != NULL) {
+		if ((callback->clnt_type == clnt_type)
+			&& (callback->clnt_id == clnt_id))
+			break;
+		 callback = callback->cb_next;
+	}
+	if (callback == NULL) {
+		mutex_unlock(&session_lock);
+		return -EINVAL;
+	}
+
+	if ((callback->cb_next == NULL) && (callback->cb_prev == NULL))
+		event.cb = NULL;
+	else if (callback->cb_next == NULL)
+		callback->cb_prev->cb_next = NULL;
+	else if (callback->cb_prev == NULL) {
+		callback->cb_next->cb_prev = NULL;
+		event.cb = callback->cb_next;
+	} else {
+		callback->cb_prev->cb_next = callback->cb_next;
+		callback->cb_next->cb_prev = callback->cb_prev;
+	}
+	kfree(callback);
+
+	session_mask = (0x1 << (clnt_id)) << (8 * ((int)clnt_type-1));
+	for (i = 0; i < audio_dev_ctrl.num_dev; i++) {
+		info = audio_dev_ctrl.devs[i];
+		info->sessions &= ~session_mask;
+	}
+	if (clnt_type == AUDDEV_CLNT_ENC)
+		msm_set_dual_mic_config(clnt_id, 0);
+	mutex_unlock(&session_lock);
+	return 0;
+}
+EXPORT_SYMBOL(auddev_unregister_evt_listner);
+
+int msm_snddev_withdraw_freq(u32 session_id, u32 capability, u32 clnt_type)
+{
+	int i = 0;
+	struct msm_snddev_info *info;
+	u32 session_mask = 0;
+
+	if ((clnt_type == AUDDEV_CLNT_VOC) && (session_id != 0))
+		return -EINVAL;
+	if ((clnt_type == AUDDEV_CLNT_DEC)
+			&& (session_id >= MAX_DEC_SESSIONS))
+		return -EINVAL;
+	if ((clnt_type == AUDDEV_CLNT_ENC)
+			&& (session_id >= MAX_ENC_SESSIONS))
+		return -EINVAL;
+
+	session_mask = (0x1 << (session_id)) << (8 * ((int)clnt_type-1));
+
+	for (i = 0; i < audio_dev_ctrl.num_dev; i++) {
+		info = audio_dev_ctrl.devs[i];
+		if ((info->sessions & session_mask)
+			&& (info->capability & capability)) {
+			if (!(info->sessions & ~(session_mask)))
+				info->set_sample_rate = 0;
+		}
+	}
+	if (clnt_type == AUDDEV_CLNT_DEC)
+		routing_info.dec_freq[session_id].freq
+					= 0;
+	else if (clnt_type == AUDDEV_CLNT_ENC)
+		routing_info.enc_freq[session_id].freq
+					= 0;
+	else if (capability == SNDDEV_CAP_TX)
+		routing_info.voice_tx_sample_rate = 0;
+	else
+		routing_info.voice_rx_sample_rate = 48000;
+	return 0;
+}
+
+int msm_snddev_request_freq(int *freq, u32 session_id,
+			u32 capability, u32 clnt_type)
+{
+	int i = 0;
+	int rc = 0;
+	struct msm_snddev_info *info;
+	u32 set_freq;
+	u32 session_mask = 0;
+	u32 clnt_type_mask = 0;
+
+	MM_DBG(": clnt_type 0x%08x\n", clnt_type);
+
+	if ((clnt_type == AUDDEV_CLNT_VOC) && (session_id != 0))
+		return -EINVAL;
+	if ((clnt_type == AUDDEV_CLNT_DEC)
+			&& (session_id >= MAX_DEC_SESSIONS))
+		return -EINVAL;
+	if ((clnt_type == AUDDEV_CLNT_ENC)
+			&& (session_id >= MAX_ENC_SESSIONS))
+		return -EINVAL;
+	session_mask = ((0x1 << session_id)) << (8 * (clnt_type-1));
+	clnt_type_mask = (0xFF << (8 * (clnt_type-1)));
+	if (!(*freq == 8000) && !(*freq == 11025) &&
+		!(*freq == 12000) && !(*freq == 16000) &&
+		!(*freq == 22050) && !(*freq == 24000) &&
+		!(*freq == 32000) && !(*freq == 44100) &&
+		!(*freq == 48000))
+		return -EINVAL;
+
+	for (i = 0; i < audio_dev_ctrl.num_dev; i++) {
+		info = audio_dev_ctrl.devs[i];
+		if ((info->sessions & session_mask)
+			&& (info->capability & capability)) {
+			rc = 0;
+			if ((info->sessions & ~clnt_type_mask)
+				&& ((*freq != 8000) && (*freq != 16000)
+					&& (*freq != 48000))) {
+				if (clnt_type == AUDDEV_CLNT_ENC) {
+					routing_info.enc_freq[session_id].freq
+							= 0;
+					return -EPERM;
+				} else if (clnt_type == AUDDEV_CLNT_DEC) {
+					routing_info.dec_freq[session_id].freq
+							= 0;
+					return -EPERM;
+				}
+			}
+			if (*freq == info->set_sample_rate) {
+				rc = info->set_sample_rate;
+				continue;
+			}
+			set_freq = MAX(*freq, info->set_sample_rate);
+
+
+			if (clnt_type == AUDDEV_CLNT_DEC)
+				routing_info.dec_freq[session_id].freq
+						= set_freq;
+			else if (clnt_type == AUDDEV_CLNT_ENC)
+				routing_info.enc_freq[session_id].freq
+						= set_freq;
+			else if (capability == SNDDEV_CAP_TX)
+				routing_info.voice_tx_sample_rate = set_freq;
+
+			rc = set_freq;
+			*freq = set_freq;
+			/* There is difference in device sample rate to
+			 * requested sample rate. So update device sample rate
+			 * and propagate sample rate change event to active
+			 * sessions of the device.
+			 */
+			if (info->set_sample_rate != set_freq) {
+				info->set_sample_rate = set_freq;
+				if (info->opened) {
+					/* Ignore propagating sample rate
+					 * change event to requested client
+					 * session
+					 */
+					if (clnt_type == AUDDEV_CLNT_DEC)
+						routing_info.\
+						dec_freq[session_id].evt = 1;
+					else if (clnt_type == AUDDEV_CLNT_ENC)
+						routing_info.\
+						enc_freq[session_id].evt = 1;
+					broadcast_event(AUDDEV_EVT_FREQ_CHG, i,
+								SESSION_IGNORE);
+					set_freq = info->dev_ops.set_freq(info,
+								set_freq);
+					broadcast_event(AUDDEV_EVT_DEV_RDY, i,
+								SESSION_IGNORE);
+				}
+			}
+		}
+		MM_DBG("info->set_sample_rate = %d\n", info->set_sample_rate);
+		MM_DBG("routing_info.enc_freq.freq = %d\n",
+					routing_info.enc_freq[session_id].freq);
+	}
+	return rc;
+}
+EXPORT_SYMBOL(msm_snddev_request_freq);
+
+int msm_snddev_enable_sidetone(u32 dev_id, u32 enable)
+{
+	int rc;
+	struct msm_snddev_info *dev_info;
+
+	MM_DBG("dev_id %d enable %d\n", dev_id, enable);
+
+	dev_info = audio_dev_ctrl_find_dev(dev_id);
+
+	if (IS_ERR(dev_info)) {
+		MM_ERR("bad dev_id %d\n", dev_id);
+		rc = -EINVAL;
+	} else if (!dev_info->dev_ops.enable_sidetone) {
+		MM_DBG("dev %d no sidetone support\n", dev_id);
+		rc = -EPERM;
+	} else
+		rc = dev_info->dev_ops.enable_sidetone(dev_info, enable);
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_snddev_enable_sidetone);
+
+static long audio_dev_ctrl_ioctl(struct file *file,
+				 unsigned int cmd, unsigned long arg)
+{
+	int rc = 0;
+	struct audio_dev_ctrl_state *dev_ctrl = file->private_data;
+
+	mutex_lock(&session_lock);
+	switch (cmd) {
+	case AUDIO_GET_NUM_SND_DEVICE:
+		rc = put_user(dev_ctrl->num_dev, (uint32_t __user *) arg);
+		break;
+	case AUDIO_GET_SND_DEVICES:
+		rc = audio_dev_ctrl_get_devices(dev_ctrl, (void __user *) arg);
+		break;
+	case AUDIO_ENABLE_SND_DEVICE: {
+		struct msm_snddev_info *dev_info;
+		u32 dev_id;
+
+		if (get_user(dev_id, (u32 __user *) arg)) {
+			rc = -EFAULT;
+			break;
+		}
+		dev_info = audio_dev_ctrl_find_dev(dev_id);
+		if (IS_ERR(dev_info))
+			rc = PTR_ERR(dev_info);
+		else {
+			rc = dev_info->dev_ops.open(dev_info);
+			if (!rc)
+				dev_info->opened = 1;
+			wake_up(&audio_dev_ctrl.wait);
+		}
+		break;
+
+	}
+
+	case AUDIO_DISABLE_SND_DEVICE: {
+		struct msm_snddev_info *dev_info;
+		u32 dev_id;
+
+		if (get_user(dev_id, (u32 __user *) arg)) {
+			rc = -EFAULT;
+			break;
+		}
+		dev_info = audio_dev_ctrl_find_dev(dev_id);
+		if (IS_ERR(dev_info))
+			rc = PTR_ERR(dev_info);
+		else {
+			rc = dev_info->dev_ops.close(dev_info);
+			dev_info->opened = 0;
+		}
+		break;
+	}
+
+	case AUDIO_ROUTE_STREAM: {
+		struct msm_audio_route_config route_cfg;
+		struct msm_snddev_info *dev_info;
+
+		if (copy_from_user(&route_cfg, (void __user *) arg,
+			sizeof(struct msm_audio_route_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		MM_DBG("%s: route cfg %d %d type\n", __func__,
+		route_cfg.dev_id, route_cfg.stream_type);
+		dev_info = audio_dev_ctrl_find_dev(route_cfg.dev_id);
+		if (IS_ERR(dev_info)) {
+			MM_ERR("%s: pass invalid dev_id\n", __func__);
+			rc = PTR_ERR(dev_info);
+			break;
+		}
+
+		switch (route_cfg.stream_type) {
+
+		case AUDIO_ROUTE_STREAM_VOICE_RX:
+			if (!(dev_info->capability & SNDDEV_CAP_RX) |
+			    !(dev_info->capability & SNDDEV_CAP_VOICE)) {
+				rc = -EINVAL;
+				break;
+			}
+			dev_ctrl->voice_rx_dev = dev_info;
+			break;
+		case AUDIO_ROUTE_STREAM_VOICE_TX:
+			if (!(dev_info->capability & SNDDEV_CAP_TX) |
+			    !(dev_info->capability & SNDDEV_CAP_VOICE)) {
+				rc = -EINVAL;
+				break;
+			}
+			dev_ctrl->voice_tx_dev = dev_info;
+			break;
+		}
+		break;
+	}
+
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&session_lock);
+	return rc;
+}
+
+static int audio_dev_ctrl_open(struct inode *inode, struct file *file)
+{
+	MM_DBG("open audio_dev_ctrl\n");
+	atomic_inc(&audio_dev_ctrl.opened);
+	file->private_data = &audio_dev_ctrl;
+	return 0;
+}
+
+static int audio_dev_ctrl_release(struct inode *inode, struct file *file)
+{
+	MM_DBG("release audio_dev_ctrl\n");
+	atomic_dec(&audio_dev_ctrl.opened);
+	return 0;
+}
+
+static const struct file_operations audio_dev_ctrl_fops = {
+	.owner = THIS_MODULE,
+	.open = audio_dev_ctrl_open,
+	.release = audio_dev_ctrl_release,
+	.unlocked_ioctl = audio_dev_ctrl_ioctl,
+};
+
+
+struct miscdevice audio_dev_ctrl_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_audio_dev_ctrl",
+	.fops	= &audio_dev_ctrl_fops,
+};
+
+/* session id is 32 bit routing mask per device
+ * 0-7 for voice clients
+ * 8-15 for Decoder clients
+ * 16-23 for Encoder clients
+ * 24-31 Do not care
+ */
+void broadcast_event(u32 evt_id, u32 dev_id, u32 session_id)
+{
+	int clnt_id = 0, i;
+	union auddev_evt_data *evt_payload;
+	struct msm_snd_evt_listner *callback;
+	struct msm_snddev_info *dev_info = NULL;
+	u32 session_mask = 0;
+	static int pending_sent;
+
+	MM_DBG(": evt_id = %d\n", evt_id);
+
+	if ((evt_id != AUDDEV_EVT_START_VOICE)
+		&& (evt_id != AUDDEV_EVT_END_VOICE)
+		&& (evt_id != AUDDEV_EVT_STREAM_VOL_CHG)
+		&& (evt_id != AUDDEV_EVT_VOICE_STATE_CHG)) {
+		dev_info = audio_dev_ctrl_find_dev(dev_id);
+		if (IS_ERR(dev_info)) {
+			MM_ERR("pass invalid dev_id\n");
+			return;
+		}
+	}
+
+	if (event.cb != NULL)
+		callback = event.cb;
+	else
+		return;
+
+	evt_payload = kzalloc(sizeof(union auddev_evt_data),
+			GFP_KERNEL);
+	if (evt_payload == NULL) {
+		MM_ERR("Memory allocation for event payload failed\n");
+		return;
+	}
+
+	mutex_lock(&session_lock);
+
+	if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
+		routing_info.voice_state = dev_id;
+
+	for (; ;) {
+		if (!(evt_id & callback->evt_id)) {
+			if (callback->cb_next == NULL)
+				break;
+			else {
+				callback = callback->cb_next;
+				continue;
+			}
+		}
+		clnt_id = callback->clnt_id;
+		memset(evt_payload, 0, sizeof(union auddev_evt_data));
+
+		if ((evt_id == AUDDEV_EVT_START_VOICE)
+			|| (evt_id == AUDDEV_EVT_END_VOICE))
+			goto skip_check;
+		if (callback->clnt_type == AUDDEV_CLNT_AUDIOCAL)
+			goto aud_cal;
+
+		session_mask = (0x1 << (clnt_id))
+				<< (8 * ((int)callback->clnt_type-1));
+
+		if ((evt_id == AUDDEV_EVT_STREAM_VOL_CHG) || \
+			(evt_id == AUDDEV_EVT_VOICE_STATE_CHG)) {
+			MM_DBG("AUDDEV_EVT_STREAM_VOL_CHG or\
+				AUDDEV_EVT_VOICE_STATE_CHG\n");
+			goto volume_strm;
+		}
+
+		MM_DBG("dev_info->sessions = %08x\n", dev_info->sessions);
+
+		if ((!session_id && !(dev_info->sessions & session_mask)) ||
+			(session_id && ((dev_info->sessions & session_mask) !=
+						session_id))) {
+			if (callback->cb_next == NULL)
+				break;
+			else {
+				callback = callback->cb_next;
+				continue;
+			}
+		}
+		if (evt_id == AUDDEV_EVT_DEV_CHG_VOICE)
+			goto voc_events;
+
+volume_strm:
+		if (callback->clnt_type == AUDDEV_CLNT_DEC) {
+			MM_DBG("AUDDEV_CLNT_DEC\n");
+			if (evt_id == AUDDEV_EVT_STREAM_VOL_CHG) {
+				MM_DBG("clnt_id = %d, session_id = 0x%8x\n",
+					clnt_id, session_id);
+				if (session_mask != session_id)
+					goto sent_dec;
+				else
+					evt_payload->session_vol =
+						msm_vol_ctl.volume;
+			} else if (evt_id == AUDDEV_EVT_FREQ_CHG) {
+				if (routing_info.dec_freq[clnt_id].evt) {
+					routing_info.dec_freq[clnt_id].evt
+							= 0;
+					goto sent_dec;
+				} else if (routing_info.dec_freq[clnt_id].freq
+					== dev_info->set_sample_rate)
+					goto sent_dec;
+				else {
+					evt_payload->freq_info.sample_rate
+						= dev_info->set_sample_rate;
+					evt_payload->freq_info.dev_type
+						= dev_info->capability;
+					evt_payload->freq_info.acdb_dev_id
+						= dev_info->acdb_id;
+				}
+			/* Propogate device information to client */
+			} else if (evt_id == AUDDEV_EVT_DEVICE_INFO) {
+				evt_payload->devinfo.dev_id
+					= dev_info->copp_id;
+				evt_payload->devinfo.acdb_id
+					= dev_info->acdb_id;
+				evt_payload->devinfo.dev_type =
+					(dev_info->capability & SNDDEV_CAP_TX) ?
+					SNDDEV_CAP_TX : SNDDEV_CAP_RX;
+				evt_payload->devinfo.sample_rate
+					= dev_info->sample_rate;
+				if (session_id == SESSION_IGNORE)
+					evt_payload->devinfo.sessions
+					= dev_info->sessions;
+				else
+					evt_payload->devinfo.sessions
+					= session_id;
+				evt_payload->devinfo.sessions =
+					(evt_payload->devinfo.sessions >>
+						((AUDDEV_CLNT_DEC-1) * 8));
+			} else if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
+				evt_payload->voice_state =
+					routing_info.voice_state;
+			else
+				evt_payload->routing_id = dev_info->copp_id;
+			callback->auddev_evt_listener(
+					evt_id,
+					evt_payload,
+					callback->private_data);
+sent_dec:
+			if ((evt_id != AUDDEV_EVT_STREAM_VOL_CHG) &&
+				(evt_id != AUDDEV_EVT_VOICE_STATE_CHG))
+				routing_info.dec_freq[clnt_id].freq
+						= dev_info->set_sample_rate;
+
+			if (callback->cb_next == NULL)
+				break;
+			else {
+				callback = callback->cb_next;
+				continue;
+			}
+		}
+		if (callback->clnt_type == AUDDEV_CLNT_ENC) {
+
+			MM_DBG("AUDDEV_CLNT_ENC\n");
+			if (evt_id == AUDDEV_EVT_FREQ_CHG) {
+				if (routing_info.enc_freq[clnt_id].evt) {
+					routing_info.enc_freq[clnt_id].evt
+							= 0;
+					goto sent_enc;
+				 } else {
+					evt_payload->freq_info.sample_rate
+						= dev_info->set_sample_rate;
+					evt_payload->freq_info.dev_type
+						= dev_info->capability;
+					evt_payload->freq_info.acdb_dev_id
+						= dev_info->acdb_id;
+				}
+			/* Propogate device information to client */
+			} else if (evt_id == AUDDEV_EVT_DEVICE_INFO) {
+				evt_payload->devinfo.dev_id
+					= dev_info->copp_id;
+				evt_payload->devinfo.acdb_id
+					= dev_info->acdb_id;
+				evt_payload->devinfo.dev_type =
+					(dev_info->capability & SNDDEV_CAP_TX) ?
+					SNDDEV_CAP_TX : SNDDEV_CAP_RX;
+				evt_payload->devinfo.sample_rate
+					= dev_info->sample_rate;
+				if (session_id == SESSION_IGNORE)
+					evt_payload->devinfo.sessions
+					= dev_info->sessions;
+				else
+					evt_payload->devinfo.sessions
+					= session_id;
+				evt_payload->devinfo.sessions =
+					(evt_payload->devinfo.sessions >>
+						((AUDDEV_CLNT_ENC-1) * 8));
+			} else if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
+				evt_payload->voice_state =
+					routing_info.voice_state;
+			else
+				evt_payload->routing_id = dev_info->copp_id;
+			callback->auddev_evt_listener(
+					evt_id,
+					evt_payload,
+					callback->private_data);
+sent_enc:
+			if (callback->cb_next == NULL)
+					break;
+			else {
+				callback = callback->cb_next;
+				continue;
+			}
+		}
+aud_cal:
+		if (callback->clnt_type == AUDDEV_CLNT_AUDIOCAL) {
+			int temp_sessions;
+			MM_DBG("AUDDEV_CLNT_AUDIOCAL\n");
+			if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
+				evt_payload->voice_state =
+					routing_info.voice_state;
+			else if (!dev_info->sessions)
+				goto sent_aud_cal;
+			else {
+				evt_payload->audcal_info.dev_id =
+						dev_info->copp_id;
+				evt_payload->audcal_info.acdb_id =
+						dev_info->acdb_id;
+				evt_payload->audcal_info.dev_type =
+					(dev_info->capability & SNDDEV_CAP_TX) ?
+					SNDDEV_CAP_TX : SNDDEV_CAP_RX;
+				evt_payload->audcal_info.sample_rate =
+					dev_info->set_sample_rate ?
+					dev_info->set_sample_rate :
+					dev_info->sample_rate;
+			}
+			if (evt_payload->audcal_info.dev_type ==
+						SNDDEV_CAP_TX) {
+				if (session_id == SESSION_IGNORE)
+					temp_sessions = dev_info->sessions;
+				else
+					temp_sessions = session_id;
+				evt_payload->audcal_info.sessions =
+					(temp_sessions >>
+						((AUDDEV_CLNT_ENC-1) * 8));
+			} else {
+				if (session_id == SESSION_IGNORE)
+					temp_sessions = dev_info->sessions;
+				else
+					temp_sessions = session_id;
+				evt_payload->audcal_info.sessions =
+					(temp_sessions >>
+						((AUDDEV_CLNT_DEC-1) * 8));
+			}
+			callback->auddev_evt_listener(
+				evt_id,
+				evt_payload,
+				callback->private_data);
+
+sent_aud_cal:
+			if (callback->cb_next == NULL)
+				break;
+			else {
+				callback = callback->cb_next;
+				continue;
+			}
+		}
+skip_check:
+voc_events:
+		if (callback->clnt_type == AUDDEV_CLNT_VOC) {
+			MM_DBG("AUDDEV_CLNT_VOC\n");
+			if (evt_id == AUDDEV_EVT_DEV_RLS) {
+				if (!pending_sent)
+					goto sent_voc;
+				else
+					pending_sent = 0;
+			}
+			if (evt_id == AUDDEV_EVT_REL_PENDING)
+				pending_sent = 1;
+
+			if (evt_id == AUDDEV_EVT_DEVICE_VOL_MUTE_CHG) {
+				if (dev_info->capability & SNDDEV_CAP_TX) {
+					evt_payload->voc_vm_info.dev_type =
+						SNDDEV_CAP_TX;
+					evt_payload->voc_vm_info.acdb_dev_id =
+						dev_info->acdb_id;
+					evt_payload->
+					voc_vm_info.dev_vm_val.mute =
+						routing_info.tx_mute;
+				} else {
+					evt_payload->voc_vm_info.dev_type =
+						SNDDEV_CAP_RX;
+					evt_payload->voc_vm_info.acdb_dev_id =
+						dev_info->acdb_id;
+					evt_payload->
+					voc_vm_info.dev_vm_val.vol =
+						routing_info.voice_rx_vol;
+				}
+			} else if ((evt_id == AUDDEV_EVT_START_VOICE)
+					|| (evt_id == AUDDEV_EVT_END_VOICE))
+				memset(evt_payload, 0,
+					sizeof(union auddev_evt_data));
+			else if (evt_id == AUDDEV_EVT_FREQ_CHG) {
+				if (routing_info.voice_tx_sample_rate
+						!= dev_info->set_sample_rate) {
+					routing_info.voice_tx_sample_rate
+						= dev_info->set_sample_rate;
+					evt_payload->freq_info.sample_rate
+						= dev_info->set_sample_rate;
+					evt_payload->freq_info.dev_type
+						= dev_info->capability;
+					evt_payload->freq_info.acdb_dev_id
+						= dev_info->acdb_id;
+				} else
+					goto sent_voc;
+			} else if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
+				evt_payload->voice_state =
+						routing_info.voice_state;
+			else {
+				evt_payload->voc_devinfo.dev_type =
+					(dev_info->capability & SNDDEV_CAP_TX) ?
+					SNDDEV_CAP_TX : SNDDEV_CAP_RX;
+				evt_payload->voc_devinfo.acdb_dev_id =
+					dev_info->acdb_id;
+				evt_payload->voc_devinfo.dev_sample =
+					dev_info->set_sample_rate ?
+					dev_info->set_sample_rate :
+					dev_info->sample_rate;
+				evt_payload->voc_devinfo.dev_id = dev_id;
+				if (dev_info->capability & SNDDEV_CAP_RX) {
+					for (i = 0; i < VOC_RX_VOL_ARRAY_NUM;
+						i++) {
+						evt_payload->
+						voc_devinfo.max_rx_vol[i] =
+						dev_info->max_voc_rx_vol[i];
+						evt_payload
+						->voc_devinfo.min_rx_vol[i] =
+						dev_info->min_voc_rx_vol[i];
+					}
+				}
+			}
+			callback->auddev_evt_listener(
+				evt_id,
+				evt_payload,
+				callback->private_data);
+			if (evt_id == AUDDEV_EVT_DEV_RLS)
+				dev_info->sessions &= ~(0xFF);
+sent_voc:
+			if (callback->cb_next == NULL)
+				break;
+			else {
+				callback = callback->cb_next;
+				continue;
+			}
+		}
+	}
+	kfree(evt_payload);
+	mutex_unlock(&session_lock);
+}
+EXPORT_SYMBOL(broadcast_event);
+
+
+void mixer_post_event(u32 evt_id, u32 id)
+{
+
+	MM_DBG("evt_id = %d\n", evt_id);
+	switch (evt_id) {
+	case AUDDEV_EVT_DEV_CHG_VOICE: /* Called from Voice_route */
+		broadcast_event(AUDDEV_EVT_DEV_CHG_VOICE, id, SESSION_IGNORE);
+		break;
+	case AUDDEV_EVT_DEV_RDY:
+		broadcast_event(AUDDEV_EVT_DEV_RDY, id, SESSION_IGNORE);
+		break;
+	case AUDDEV_EVT_DEV_RLS:
+		broadcast_event(AUDDEV_EVT_DEV_RLS, id, SESSION_IGNORE);
+		break;
+	case AUDDEV_EVT_REL_PENDING:
+		broadcast_event(AUDDEV_EVT_REL_PENDING, id, SESSION_IGNORE);
+		break;
+	case AUDDEV_EVT_DEVICE_VOL_MUTE_CHG:
+		broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG, id,
+							SESSION_IGNORE);
+		break;
+	case AUDDEV_EVT_STREAM_VOL_CHG:
+		broadcast_event(AUDDEV_EVT_STREAM_VOL_CHG, id,
+							SESSION_IGNORE);
+		break;
+	case AUDDEV_EVT_START_VOICE:
+		broadcast_event(AUDDEV_EVT_START_VOICE,
+				id, SESSION_IGNORE);
+		break;
+	case AUDDEV_EVT_END_VOICE:
+		broadcast_event(AUDDEV_EVT_END_VOICE,
+				id, SESSION_IGNORE);
+		break;
+	case AUDDEV_EVT_FREQ_CHG:
+		broadcast_event(AUDDEV_EVT_FREQ_CHG, id, SESSION_IGNORE);
+		break;
+	default:
+		break;
+	}
+}
+EXPORT_SYMBOL(mixer_post_event);
+
+static int __init audio_dev_ctrl_init(void)
+{
+#ifdef CONFIG_DEBUG_FS
+	char name[sizeof "rtc_get_device"+1];
+#endif
+
+	init_waitqueue_head(&audio_dev_ctrl.wait);
+
+	event.cb = NULL;
+
+	atomic_set(&audio_dev_ctrl.opened, 0);
+	audio_dev_ctrl.num_dev = 0;
+	audio_dev_ctrl.voice_tx_dev = NULL;
+	audio_dev_ctrl.voice_rx_dev = NULL;
+	routing_info.voice_state = VOICE_STATE_INVALID;
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "rtc_get_device");
+	dentry = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUGO,
+			NULL, NULL, &rtc_acdb_debug_fops);
+	if (IS_ERR(dentry))
+		MM_DBG("debugfs_create_file failed\n");
+#endif
+
+	return misc_register(&audio_dev_ctrl_misc);
+}
+
+static void __exit audio_dev_ctrl_exit(void)
+{
+#ifdef CONFIG_DEBUG_FS
+	if (dentry)
+		debugfs_remove(dentry);
+#endif
+
+}
+module_init(audio_dev_ctrl_init);
+module_exit(audio_dev_ctrl_exit);
+
+MODULE_DESCRIPTION("MSM 7K Audio Device Control driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_evrc.c b/arch/arm/mach-msm/qdsp5v2/audio_evrc.c
new file mode 100644
index 0000000..7306e98
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/audio_evrc.c
@@ -0,0 +1,1640 @@
+/*
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This code also borrows from audio_aac.c, which is
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ *
+ * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/earlysuspend.h>
+#include <linux/android_pmem.h>
+#include <linux/memory_alloc.h>
+#include <linux/msm_audio.h>
+#include <linux/slab.h>
+
+#include <mach/msm_adsp.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/qdsp5v2/qdsp5audppmsg.h>
+#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
+#include <mach/qdsp5v2/qdsp5audplaymsg.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/qdsp5v2/audpp.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_memtypes.h>
+
+/* Hold 30 packets of 24 bytes each and 14 bytes of meta in */
+#define BUFSZ 			734
+#define DMASZ 			(BUFSZ * 2)
+
+#define AUDDEC_DEC_EVRC 	12
+
+#define PCM_BUFSZ_MIN 		1624	/* 100ms worth of data and
+					   and 24 bytes of meta out */
+#define PCM_BUF_MAX_COUNT 	5
+/* DSP only accepts 5 buffers at most
+ * but support 2 buffers currently
+ */
+#define EVRC_DECODED_FRSZ 	320	/* EVRC 20ms 8KHz mono PCM size */
+
+#define ROUTING_MODE_FTRT 	1
+#define ROUTING_MODE_RT 	2
+/* Decoder status received from AUDPPTASK */
+#define  AUDPP_DEC_STATUS_SLEEP	0
+#define	 AUDPP_DEC_STATUS_INIT  1
+#define  AUDPP_DEC_STATUS_CFG   2
+#define  AUDPP_DEC_STATUS_PLAY  3
+
+#define AUDEVRC_METAFIELD_MASK 0xFFFF0000
+#define AUDEVRC_EOS_FLG_OFFSET 0x0A /* Offset from beginning of buffer */
+#define AUDEVRC_EOS_FLG_MASK 0x01
+#define AUDEVRC_EOS_NONE 0x0 /* No EOS detected */
+#define AUDEVRC_EOS_SET 0x1 /* EOS set in meta field */
+
+#define AUDEVRC_EVENT_NUM 10 /* Default number of pre-allocated event packets */
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+	unsigned short mfield_sz; /*only useful for data has meta field */
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct audevrc_suspend_ctl {
+	struct early_suspend node;
+	struct audio *audio;
+};
+#endif
+
+struct audevrc_event{
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+
+struct audio {
+	struct buffer out[2];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed;	/* number of buffers the dsp is waiting for */
+
+	atomic_t out_bytes;
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	/* Host PCM section */
+	struct buffer in[PCM_BUF_MAX_COUNT];
+	struct mutex read_lock;
+	wait_queue_head_t read_wait;	/* Wait queue for read */
+	char *read_data;	/* pointer to reader buffer */
+	int32_t read_phys;	/* physical address of reader buffer */
+	uint8_t read_next;	/* index to input buffers to be read next */
+	uint8_t fill_next;	/* index to buffer that DSP should be filling */
+	uint8_t pcm_buf_count;	/* number of pcm buffer allocated */
+	/* ---- End of Host PCM section */
+
+	struct msm_adsp_module *audplay;
+
+	/* data allocated for various buffers */
+	char *data;
+	int32_t phys;  /* physical address of write buffer */
+	void *map_v_read;
+	void *map_v_write;
+
+	int mfield; /* meta field embedded in data */
+	int rflush; /* Read  flush */
+	int wflush; /* Write flush */
+	uint8_t opened:1;
+	uint8_t enabled:1;
+	uint8_t running:1;
+	uint8_t stopped:1;	/* set when stopped, cleared on flush */
+	uint8_t pcm_feedback:1;
+	uint8_t buf_refresh:1;
+	int teos; /* valid only if tunnel mode & no data left for decoder */
+	enum msm_aud_decoder_state dec_state;	/* Represents decoder state */
+
+	const char *module_name;
+	unsigned queue_id;
+	uint16_t dec_id;
+	uint32_t read_ptr_offset;
+	int16_t source;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct audevrc_suspend_ctl suspend_ctl;
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+
+	wait_queue_head_t wait;
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	wait_queue_head_t event_wait;
+	spinlock_t event_queue_lock;
+	struct mutex get_event_lock;
+	int event_abort;
+	/* AV sync Info */
+	int avsync_flag;              /* Flag to indicate feedback from DSP */
+	wait_queue_head_t avsync_wait;/* Wait queue for AV Sync Message     */
+	/* flags, 48 bits sample/bytes counter per channel */
+	uint16_t avsync[AUDPP_AVSYNC_CH_COUNT * AUDPP_AVSYNC_NUM_WORDS + 1];
+
+	uint32_t device_events;
+
+	int eq_enable;
+	int eq_needs_commit;
+	struct audpp_cmd_cfg_object_params_eqalizer eq;
+	struct audpp_cmd_cfg_object_params_volume vol_pan;
+};
+
+static int auddec_dsp_config(struct audio *audio, int enable);
+static void audpp_cmd_cfg_adec_params(struct audio *audio);
+static void audpp_cmd_cfg_routing_mode(struct audio *audio);
+static void audevrc_send_data(struct audio *audio, unsigned needed);
+static void audevrc_dsp_event(void *private, unsigned id, uint16_t *msg);
+static void audevrc_config_hostpcm(struct audio *audio);
+static void audevrc_buffer_refresh(struct audio *audio);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audevrc_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload);
+#endif
+
+/* must be called with audio->lock held */
+static int audevrc_enable(struct audio *audio)
+{
+	if (audio->enabled)
+		return 0;
+
+	audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	if (msm_adsp_enable(audio->audplay)) {
+		MM_ERR("msm_adsp_enable(audplay) failed\n");
+		return -ENODEV;
+	}
+
+	if (audpp_enable(audio->dec_id, audevrc_dsp_event, audio)) {
+		MM_ERR("audpp_enable() failed\n");
+		msm_adsp_disable(audio->audplay);
+		return -ENODEV;
+	}
+	audio->enabled = 1;
+	return 0;
+}
+
+static void evrc_listner(u32 evt_id, union auddev_evt_data *evt_payload,
+			void *private_data)
+{
+	struct audio *audio = (struct audio *) private_data;
+	switch (evt_id) {
+	case AUDDEV_EVT_DEV_RDY:
+		MM_DBG(":AUDDEV_EVT_DEV_RDY\n");
+		audio->source |= (0x1 << evt_payload->routing_id);
+		if (audio->running == 1 && audio->enabled == 1)
+			audpp_route_stream(audio->dec_id, audio->source);
+		break;
+	case AUDDEV_EVT_DEV_RLS:
+		MM_DBG(":AUDDEV_EVT_DEV_RLS\n");
+		audio->source &= ~(0x1 << evt_payload->routing_id);
+		if (audio->running == 1 && audio->enabled == 1)
+			audpp_route_stream(audio->dec_id, audio->source);
+		break;
+	case AUDDEV_EVT_STREAM_VOL_CHG:
+		audio->vol_pan.volume = evt_payload->session_vol;
+		MM_DBG(":AUDDEV_EVT_STREAM_VOL_CHG, stream vol %d\n",
+				audio->vol_pan.volume);
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+		break;
+	default:
+		MM_ERR(":ERROR:wrong event\n");
+		break;
+	}
+}
+/* must be called with audio->lock held */
+static int audevrc_disable(struct audio *audio)
+{
+	int rc = 0;
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+		auddec_dsp_config(audio, 0);
+		rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+		else if (audio->dec_state != MSM_AUD_DECODER_STATE_CLOSE)
+			rc = -EFAULT;
+		else
+			rc = 0;
+		wake_up(&audio->write_wait);
+		wake_up(&audio->read_wait);
+		msm_adsp_disable(audio->audplay);
+		audpp_disable(audio->dec_id, audio);
+		audio->out_needed = 0;
+	}
+	return rc;
+}
+
+/* ------------------- dsp --------------------- */
+
+static void audevrc_update_pcm_buf_entry(struct audio *audio,
+					 uint32_t *payload)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	if (audio->rflush)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < payload[1]; index++) {
+		if (audio->in[audio->fill_next].addr
+				== payload[2 + index * 2]) {
+			MM_DBG("in[%d] ready\n", audio->fill_next);
+			audio->in[audio->fill_next].used =
+				payload[3 + index * 2];
+			if ((++audio->fill_next) == audio->pcm_buf_count)
+				audio->fill_next = 0;
+
+		} else {
+			MM_ERR("expected=%x ret=%x\n",
+				audio->in[audio->fill_next].addr,
+				payload[1 + index * 2]);
+			break;
+		}
+	}
+	if (audio->in[audio->fill_next].used == 0) {
+		audevrc_buffer_refresh(audio);
+	} else {
+		MM_DBG("read cannot keep up\n");
+		audio->buf_refresh = 1;
+	}
+	wake_up(&audio->read_wait);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static void audplay_dsp_event(void *data, unsigned id, size_t len,
+			      void (*getevent) (void *ptr, size_t len))
+{
+	struct audio *audio = data;
+	uint32_t msg[28];
+	getevent(msg, sizeof(msg));
+
+	MM_DBG("msg_id=%x\n", id);
+	switch (id) {
+	case AUDPLAY_MSG_DEC_NEEDS_DATA:
+		audevrc_send_data(audio, 1);
+		break;
+	case AUDPLAY_MSG_BUFFER_UPDATE:
+		MM_DBG("\n"); /* Macro prints the file name and function */
+		audevrc_update_pcm_buf_entry(audio, msg);
+		break;
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audplaytask)\n");
+		break;
+	default:
+		MM_ERR("unexpected message from decoder \n");
+	}
+}
+
+static void audevrc_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned status = msg[1];
+
+			switch (status) {
+			case AUDPP_DEC_STATUS_SLEEP: {
+				uint16_t reason = msg[2];
+				MM_DBG("decoder status:sleep reason = \
+						0x%04x\n", reason);
+				if ((reason == AUDPP_MSG_REASON_MEM)
+					|| (reason ==
+					AUDPP_MSG_REASON_NODECODER)) {
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_FAILURE;
+					wake_up(&audio->wait);
+				} else if (reason == AUDPP_MSG_REASON_NONE) {
+					/* decoder is in disable state */
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_CLOSE;
+					wake_up(&audio->wait);
+				}
+				break;
+			}
+			case AUDPP_DEC_STATUS_INIT:
+				MM_DBG("decoder status: init \n");
+				if (audio->pcm_feedback)
+					audpp_cmd_cfg_routing_mode(audio);
+				else
+					audpp_cmd_cfg_adec_params(audio);
+				break;
+
+			case AUDPP_DEC_STATUS_CFG:
+				MM_DBG("decoder status: cfg \n");
+				break;
+			case AUDPP_DEC_STATUS_PLAY:
+				MM_DBG("decoder status: play \n");
+				audpp_route_stream(audio->dec_id,
+						audio->source);
+				if (audio->pcm_feedback) {
+					audevrc_config_hostpcm(audio);
+					audevrc_buffer_refresh(audio);
+				}
+				audio->dec_state =
+					MSM_AUD_DECODER_STATE_SUCCESS;
+				wake_up(&audio->wait);
+				break;
+			default:
+				MM_ERR("unknown decoder status \n");
+			}
+			break;
+		}
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			MM_DBG("CFG_MSG ENABLE\n");
+			auddec_dsp_config(audio, 1);
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+			audpp_dsp_set_eq(audio->dec_id,	audio->eq_enable,
+					&audio->eq, POPP);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			MM_DBG("CFG_MSG DISABLE\n");
+			audio->running = 0;
+		} else {
+			MM_DBG("CFG_MSG %d?\n", msg[0]);
+		}
+		break;
+	case AUDPP_MSG_ROUTING_ACK:
+		MM_DBG("ROUTING_ACK\n");
+		audpp_cmd_cfg_adec_params(audio);
+		break;
+	case AUDPP_MSG_FLUSH_ACK:
+		MM_DBG("FLUSH_ACK\n");
+		audio->wflush = 0;
+		audio->rflush = 0;
+		wake_up(&audio->write_wait);
+		if (audio->pcm_feedback)
+			audevrc_buffer_refresh(audio);
+		break;
+	case AUDPP_MSG_PCMDMAMISSED:
+		MM_DBG("PCMDMAMISSED\n");
+		audio->teos = 1;
+		wake_up(&audio->write_wait);
+		break;
+
+	case AUDPP_MSG_AVSYNC_MSG:
+		MM_DBG("AUDPP_MSG_AVSYNC_MSG\n");
+		memcpy(&audio->avsync[0], msg, sizeof(audio->avsync));
+		audio->avsync_flag = 1;
+		wake_up(&audio->avsync_wait);
+		break;
+
+	default:
+		MM_ERR("UNKNOWN (%d)\n", id);
+	}
+
+}
+
+struct msm_adsp_ops audplay_adsp_ops_evrc = {
+	.event = audplay_dsp_event,
+};
+
+#define audplay_send_queue0(audio, cmd, len) \
+	msm_adsp_write(audio->audplay, audio->queue_id, \
+			cmd, len)
+
+static int auddec_dsp_config(struct audio *audio, int enable)
+{
+	struct audpp_cmd_cfg_dec_type cfg_dec_cmd;
+
+	memset(&cfg_dec_cmd, 0, sizeof(cfg_dec_cmd));
+
+	cfg_dec_cmd.cmd_id = AUDPP_CMD_CFG_DEC_TYPE;
+	if (enable)
+		cfg_dec_cmd.dec_cfg = AUDPP_CMD_UPDATDE_CFG_DEC |
+				AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_EVRC;
+	else
+		cfg_dec_cmd.dec_cfg = AUDPP_CMD_UPDATDE_CFG_DEC |
+				AUDPP_CMD_DIS_DEC_V;
+	cfg_dec_cmd.dm_mode = 0x0;
+	cfg_dec_cmd.stream_id = audio->dec_id;
+
+	return audpp_send_queue1(&cfg_dec_cmd, sizeof(cfg_dec_cmd));
+}
+
+static void audpp_cmd_cfg_adec_params(struct audio *audio)
+{
+	struct audpp_cmd_cfg_adec_params_evrc cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	cmd.common.length = sizeof(cmd);
+	cmd.common.dec_id = audio->dec_id;
+	cmd.common.input_sampling_frequency = 8000;
+	cmd.stereo_cfg = AUDPP_CMD_PCM_INTF_MONO_V;
+
+	audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static void audpp_cmd_cfg_routing_mode(struct audio *audio)
+{
+	struct audpp_cmd_routing_mode cmd;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_ROUTING_MODE;
+	cmd.object_number = audio->dec_id;
+	if (audio->pcm_feedback)
+		cmd.routing_mode = ROUTING_MODE_FTRT;
+	else
+		cmd.routing_mode = ROUTING_MODE_RT;
+
+	audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static int audplay_dsp_send_data_avail(struct audio *audio,
+				       unsigned idx, unsigned len)
+{
+	struct audplay_cmd_bitstream_data_avail_nt2 cmd;
+
+	cmd.cmd_id = AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_NT2;
+	if (audio->mfield)
+		cmd.decoder_id = AUDEVRC_METAFIELD_MASK |
+			(audio->out[idx].mfield_sz >> 1);
+	else
+		cmd.decoder_id = audio->dec_id;
+	cmd.buf_ptr = audio->out[idx].addr;
+	cmd.buf_size = len / 2;
+	cmd.partition_number = 0;
+	return audplay_send_queue0(audio, &cmd, sizeof(cmd));
+}
+
+static void audevrc_buffer_refresh(struct audio *audio)
+{
+	struct audplay_cmd_buffer_refresh refresh_cmd;
+
+	refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH;
+	refresh_cmd.num_buffers = 1;
+	refresh_cmd.buf0_address = audio->in[audio->fill_next].addr;
+	refresh_cmd.buf0_length = audio->in[audio->fill_next].size;
+
+	refresh_cmd.buf_read_count = 0;
+	MM_DBG("buf0_addr=%x buf0_len=%d\n", refresh_cmd.buf0_address,
+			refresh_cmd.buf0_length);
+	audplay_send_queue0(audio, &refresh_cmd, sizeof(refresh_cmd));
+}
+
+static void audevrc_config_hostpcm(struct audio *audio)
+{
+	struct audplay_cmd_hpcm_buf_cfg cfg_cmd;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	cfg_cmd.cmd_id = AUDPLAY_CMD_HPCM_BUF_CFG;
+	cfg_cmd.max_buffers = 1;
+	cfg_cmd.byte_swap = 0;
+	cfg_cmd.hostpcm_config = (0x8000) | (0x4000);
+	cfg_cmd.feedback_frequency = 1;
+	cfg_cmd.partition_number = 0;
+	audplay_send_queue0(audio, &cfg_cmd, sizeof(cfg_cmd));
+
+}
+
+static void audevrc_send_data(struct audio *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (needed && !audio->wflush) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			MM_DBG("frame %d free\n", audio->out_tail);
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+			MM_DBG("frame %d busy\n", audio->out_tail);
+			audplay_dsp_send_data_avail(audio, audio->out_tail,
+						    frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+
+static void audevrc_flush(struct audio *audio)
+{
+	audio->out[0].used = 0;
+	audio->out[1].used = 0;
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+	atomic_set(&audio->out_bytes, 0);
+}
+
+static void audevrc_flush_pcm_buf(struct audio *audio)
+{
+	uint8_t index;
+
+	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
+		audio->in[index].used = 0;
+
+	audio->buf_refresh = 0;
+	audio->read_next = 0;
+	audio->fill_next = 0;
+}
+
+static void audevrc_ioport_reset(struct audio *audio)
+{
+	/* Make sure read/write thread are free from
+	 * sleep and knowing that system is not able
+	 * to process io request at the moment
+	 */
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audevrc_flush(audio);
+	mutex_unlock(&audio->write_lock);
+	wake_up(&audio->read_wait);
+	mutex_lock(&audio->read_lock);
+	audevrc_flush_pcm_buf(audio);
+	mutex_unlock(&audio->read_lock);
+	audio->avsync_flag = 1;
+	wake_up(&audio->avsync_wait);
+}
+
+static int audevrc_events_pending(struct audio *audio)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	return empty || audio->event_abort;
+}
+
+static void audevrc_reset_event_queue(struct audio *audio)
+{
+	unsigned long flags;
+	struct audevrc_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audevrc_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+			struct audevrc_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	return;
+}
+
+
+static long audevrc_process_event_req(struct audio *audio, void __user *arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audevrc_event *drv_evt = NULL;
+	int timeout;
+	unsigned long flags;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int) usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(
+			audio->event_wait, audevrc_events_pending(audio),
+			msecs_to_jiffies(timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(
+			audio->event_wait, audevrc_events_pending(audio));
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	rc = 0;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audevrc_event, list);
+		list_del(&drv_evt->list);
+	}
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else
+		rc = -1;
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	if (!rc && copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audio_enable_eq(struct audio *audio, int enable)
+{
+	if (audio->eq_enable == enable && !audio->eq_needs_commit)
+		return 0;
+
+	audio->eq_enable = enable;
+
+	if (audio->running) {
+		audpp_dsp_set_eq(audio->dec_id, enable, &audio->eq, POPP);
+		audio->eq_needs_commit = 0;
+	}
+	return 0;
+}
+
+static int audio_get_avsync_data(struct audio *audio,
+						struct msm_audio_stats *stats)
+{
+	int rc = -EINVAL;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (audio->dec_id == audio->avsync[0] && audio->avsync_flag) {
+		/* av_sync sample count */
+		stats->sample_count = (audio->avsync[2] << 16) |
+						(audio->avsync[3]);
+
+		/* av_sync byte_count */
+		stats->byte_count = (audio->avsync[5] << 16) |
+						(audio->avsync[6]);
+
+		audio->avsync_flag = 0;
+		rc = 0;
+	}
+	local_irq_restore(flags);
+	return rc;
+
+}
+
+static long audevrc_ioctl(struct file *file, unsigned int cmd,
+			  unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = -EINVAL;
+	unsigned long flags = 0;
+	uint16_t enable_mask;
+	int enable;
+	int prev_state;
+
+	MM_DBG("cmd = %d\n", cmd);
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+
+		audio->avsync_flag = 0;
+		memset(&stats, 0, sizeof(stats));
+		if (audpp_query_avsync(audio->dec_id) < 0)
+			return rc;
+
+		rc = wait_event_interruptible_timeout(audio->avsync_wait,
+				(audio->avsync_flag == 1),
+				msecs_to_jiffies(AUDPP_AVSYNC_EVENT_TIMEOUT));
+
+		if (rc < 0)
+			return rc;
+		else if ((rc > 0) || ((rc == 0) && (audio->avsync_flag == 1))) {
+			if (audio_get_avsync_data(audio, &stats) < 0)
+				return rc;
+
+			if (copy_to_user((void *)arg, &stats, sizeof(stats)))
+				return -EFAULT;
+			return 0;
+		} else
+			return -EAGAIN;
+	}
+
+	switch (cmd) {
+	case AUDIO_ENABLE_AUDPP:
+		if (copy_from_user(&enable_mask, (void *) arg,
+						sizeof(enable_mask))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		enable = (enable_mask & EQ_ENABLE) ? 1 : 0;
+		audio_enable_eq(audio, enable);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+	case AUDIO_SET_VOLUME:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.volume = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_PAN:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.pan = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_EQ:
+		prev_state = audio->eq_enable;
+		audio->eq_enable = 0;
+		if (copy_from_user(&audio->eq.num_bands, (void *) arg,
+				sizeof(audio->eq) -
+				(AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2))) {
+			rc = -EFAULT;
+			break;
+		}
+		audio->eq_enable = prev_state;
+		audio->eq_needs_commit = 1;
+		rc = 0;
+		break;
+	}
+
+	if (-EINVAL != rc)
+		return rc;
+
+	if (cmd == AUDIO_GET_EVENT) {
+		MM_DBG("AUDIO_GET_EVENT\n");
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audevrc_process_event_req(audio,
+					(void __user *) arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		return rc;
+	}
+
+	if (cmd == AUDIO_ABORT_GET_EVENT) {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		MM_DBG("AUDIO_START\n");
+		rc = audevrc_enable(audio);
+		if (!rc) {
+			rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+			MM_INFO("dec_state %d rc = %d\n", audio->dec_state, rc);
+
+			if (audio->dec_state != MSM_AUD_DECODER_STATE_SUCCESS)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		break;
+	case AUDIO_STOP:
+		MM_DBG("AUDIO_STOP\n");
+		rc = audevrc_disable(audio);
+		audio->stopped = 1;
+		audevrc_ioport_reset(audio);
+		audio->stopped = 0;
+		break;
+	case AUDIO_FLUSH:
+		MM_DBG("AUDIO_FLUSH\n");
+		audio->rflush = 1;
+		audio->wflush = 1;
+		audevrc_ioport_reset(audio);
+		if (audio->running) {
+			audpp_flush(audio->dec_id);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		break;
+	case AUDIO_SET_CONFIG:{
+			struct msm_audio_config config;
+			if (copy_from_user
+				(&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+			audio->mfield = config.meta_field;
+			rc = 0;
+			MM_DBG("AUDIO_SET_CONFIG applicable only \
+				for meta field configuration\n");
+			break;
+		}
+	case AUDIO_GET_CONFIG:{
+			struct msm_audio_config config;
+			config.buffer_size = BUFSZ;
+			config.buffer_count = 2;
+			config.sample_rate = 8000;
+			config.channel_count = 1;
+			config.meta_field = 0;
+			config.unused[0] = 0;
+			config.unused[1] = 0;
+			config.unused[2] = 0;
+			if (copy_to_user((void *)arg, &config, sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_GET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			config.pcm_feedback = audio->pcm_feedback;
+			config.buffer_count = PCM_BUF_MAX_COUNT;
+			config.buffer_size = PCM_BUFSZ_MIN;
+			if (copy_to_user((void *)arg, &config, sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_SET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			if (copy_from_user
+			    (&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+			if (config.pcm_feedback != audio->pcm_feedback) {
+				MM_ERR("Not sufficient permission to"
+					 "change the playback mode\n");
+				rc = -EACCES;
+				break;
+			}
+			if ((config.buffer_count > PCM_BUF_MAX_COUNT) ||
+			    (config.buffer_count == 1))
+				config.buffer_count = PCM_BUF_MAX_COUNT;
+
+			if (config.buffer_size < PCM_BUFSZ_MIN)
+				config.buffer_size = PCM_BUFSZ_MIN;
+
+			/* Check if pcm feedback is required */
+			if ((config.pcm_feedback) && (!audio->read_data)) {
+				MM_DBG("allocate PCM buf %d\n",
+					config.buffer_count *
+					config.buffer_size);
+				audio->read_phys =
+						 allocate_contiguous_ebi_nomap(
+							config.buffer_size *
+							config.buffer_count,
+							SZ_4K);
+				if (!audio->read_phys) {
+					rc = -ENOMEM;
+					break;
+				}
+				audio->map_v_read = ioremap(
+							audio->read_phys,
+							config.buffer_size *
+							config.buffer_count);
+				if (IS_ERR(audio->map_v_read)) {
+					MM_ERR("failed to map read"
+							" phy address\n");
+					rc = -ENOMEM;
+					free_contiguous_memory_by_paddr(
+							audio->read_phys);
+				} else {
+					uint8_t index;
+					uint32_t offset = 0;
+					audio->read_data =
+						audio->map_v_read;
+					audio->buf_refresh = 0;
+					audio->pcm_buf_count =
+					    config.buffer_count;
+					audio->read_next = 0;
+					audio->fill_next = 0;
+
+					for (index = 0;
+					     index < config.buffer_count;
+					     index++) {
+						audio->in[index].data =
+						    audio->read_data + offset;
+						audio->in[index].addr =
+						    audio->read_phys + offset;
+						audio->in[index].size =
+						    config.buffer_size;
+						audio->in[index].used = 0;
+						offset += config.buffer_size;
+					}
+					MM_DBG("read buf: phy addr \
+						0x%08x kernel addr 0x%08x\n",
+						audio->read_phys,
+						(int)audio->read_data);
+					rc = 0;
+				}
+			} else {
+				rc = 0;
+			}
+			break;
+		}
+	case AUDIO_PAUSE:
+		MM_DBG("AUDIO_PAUSE %ld\n", arg);
+		rc = audpp_pause(audio->dec_id, (int) arg);
+		break;
+	case AUDIO_GET_SESSION_ID:
+		if (copy_to_user((void *) arg, &audio->dec_id,
+				sizeof(unsigned short)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+/* Only useful in tunnel-mode */
+static int audevrc_fsync(struct file *file, loff_t ppos1, loff_t ppos2, int datasync)
+{
+	struct audio *audio = file->private_data;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (!audio->running || audio->pcm_feedback) {
+		rc = -EINVAL;
+		goto done_nolock;
+	}
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(!audio->out[0].used &&
+		!audio->out[1].used &&
+		audio->out_needed) || audio->wflush);
+
+	if (rc < 0)
+		goto done;
+	else if (audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	/* pcm dmamiss message is sent continously
+	 * when decoder is starved so no race
+	 * condition concern
+	 */
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		audio->teos || audio->wflush);
+
+	if (audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+done_nolock:
+	return rc;
+}
+
+static ssize_t audevrc_read(struct file *file, char __user *buf, size_t count,
+			    loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	int rc = 0;
+	if (!audio->pcm_feedback) {
+		return 0;
+		/* PCM feedback is not enabled. Nothing to read */
+	}
+	mutex_lock(&audio->read_lock);
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	while (count > 0) {
+		rc = wait_event_interruptible(audio->read_wait,
+				(audio->in[audio->read_next].used > 0) ||
+				(audio->stopped) || (audio->rflush));
+
+		MM_DBG("wait terminated \n");
+		if (rc < 0)
+			break;
+		if (audio->stopped || audio->rflush) {
+			rc = -EBUSY;
+			break;
+		}
+		if (count < audio->in[audio->read_next].used) {
+			/* Read must happen in frame boundary. Since driver does
+			 * not know frame size, read count must be greater or
+			 * equal to size of PCM samples
+			 */
+			MM_DBG("read stop - partial frame\n");
+			break;
+		} else {
+			MM_DBG("read from in[%d]\n", audio->read_next);
+			if (copy_to_user
+			    (buf, audio->in[audio->read_next].data,
+			     audio->in[audio->read_next].used)) {
+				MM_ERR("invalid addr %x \n",
+				       (unsigned int)buf);
+				rc = -EFAULT;
+				break;
+			}
+			count -= audio->in[audio->read_next].used;
+			buf += audio->in[audio->read_next].used;
+			audio->in[audio->read_next].used = 0;
+			if ((++audio->read_next) == audio->pcm_buf_count)
+				audio->read_next = 0;
+			break;
+				/* Force to exit while loop
+				 * to prevent output thread
+				 * sleep too long if data is
+				 * not ready at this moment
+				 */
+
+		}
+	}
+	/* don't feed output buffer to HW decoder during flushing
+	 * buffer refresh command will be sent once flush completes
+	 * send buf refresh command here can confuse HW decoder
+	 */
+	if (audio->buf_refresh && !audio->rflush) {
+		audio->buf_refresh = 0;
+		MM_DBG("kick start pcm feedback again\n");
+		audevrc_buffer_refresh(audio);
+	}
+	mutex_unlock(&audio->read_lock);
+	if (buf > start)
+		rc = buf - start;
+	MM_DBG("read %d bytes\n", rc);
+	return rc;
+}
+
+static int audevrc_process_eos(struct audio *audio,
+		const char __user *buf_start, unsigned short mfield_size)
+{
+	int rc = 0;
+	struct buffer *frame;
+
+	frame = audio->out + audio->out_head;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->out_needed &&
+		audio->out[0].used == 0 &&
+		audio->out[1].used == 0)
+		|| (audio->stopped)
+		|| (audio->wflush));
+
+	if (rc < 0)
+		goto done;
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (copy_from_user(frame->data, buf_start, mfield_size)) {
+		rc = -EFAULT;
+		goto done;
+	}
+
+	frame->mfield_sz = mfield_size;
+	audio->out_head ^= 1;
+	frame->used = mfield_size;
+	audevrc_send_data(audio, 0);
+
+done:
+	return rc;
+}
+
+static ssize_t audevrc_write(struct file *file, const char __user *buf,
+			     size_t count, loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	char *cpy_ptr;
+	unsigned short mfield_size = 0;
+	int rc = 0, eos_condition = AUDEVRC_EOS_NONE;
+
+	MM_DBG("cnt=%d\n", count);
+
+	if (count & 1)
+		return -EINVAL;
+
+	mutex_lock(&audio->write_lock);
+	while (count > 0) {
+		frame = audio->out + audio->out_head;
+		cpy_ptr = frame->data;
+		rc = wait_event_interruptible(audio->write_wait,
+					      (frame->used == 0)
+						|| (audio->stopped)
+						|| (audio->wflush));
+		if (rc < 0)
+			break;
+		if (audio->stopped || audio->wflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (audio->mfield) {
+			if (buf == start) {
+				/* Processing beginning of user buffer */
+				if (__get_user(mfield_size,
+					(unsigned short __user *) buf)) {
+					rc = -EFAULT;
+					break;
+				} else if (mfield_size > count) {
+					rc = -EINVAL;
+					break;
+				}
+				MM_DBG("mf offset_val %x\n", mfield_size);
+				if (copy_from_user(cpy_ptr, buf,
+							mfield_size)) {
+					rc = -EFAULT;
+					break;
+				}
+				/* Check if EOS flag is set and buffer has
+				 * contains just meta field
+				 */
+				if (cpy_ptr[AUDEVRC_EOS_FLG_OFFSET] &
+						AUDEVRC_EOS_FLG_MASK) {
+					MM_DBG("eos set\n");
+					eos_condition = AUDEVRC_EOS_SET;
+					if (mfield_size == count) {
+						buf += mfield_size;
+						break;
+					} else
+					cpy_ptr[AUDEVRC_EOS_FLG_OFFSET] &=
+						~AUDEVRC_EOS_FLG_MASK;
+				}
+				 /* Check EOS to see if */
+				cpy_ptr += mfield_size;
+				count -= mfield_size;
+				buf += mfield_size;
+			 } else {
+				 mfield_size = 0;
+				 MM_DBG("continuous buffer\n");
+			 }
+			 frame->mfield_sz = mfield_size;
+		}
+
+		xfer = (count > (frame->size - mfield_size)) ?
+			(frame->size - mfield_size) : count;
+		if (copy_from_user(cpy_ptr, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+
+		frame->used = xfer + mfield_size;
+		audio->out_head ^= 1;
+		count -= xfer;
+		buf += xfer;
+		audevrc_send_data(audio, 0);
+	}
+	if (eos_condition == AUDEVRC_EOS_SET)
+		rc = audevrc_process_eos(audio, start, mfield_size);
+	mutex_unlock(&audio->write_lock);
+	if (!rc) {
+		if (buf > start)
+			return buf - start;
+	}
+	return rc;
+}
+
+static int audevrc_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	MM_INFO("audio instance 0x%08x freeing\n", (int)audio);
+	mutex_lock(&audio->lock);
+	auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->dec_id);
+	audevrc_disable(audio);
+	audevrc_flush(audio);
+	audevrc_flush_pcm_buf(audio);
+	msm_adsp_put(audio->audplay);
+	audpp_adec_free(audio->dec_id);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&audio->suspend_ctl.node);
+#endif
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audevrc_reset_event_queue(audio);
+	iounmap(audio->map_v_write);
+	free_contiguous_memory_by_paddr(audio->phys);
+	if (audio->read_data) {
+		iounmap(audio->map_v_read);
+		free_contiguous_memory_by_paddr(audio->read_phys);
+	}
+	mutex_unlock(&audio->lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio);
+	return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audevrc_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload)
+{
+	struct audevrc_event *e_node = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+				struct audevrc_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audevrc_event), GFP_ATOMIC);
+		if (!e_node) {
+			MM_ERR("No mem to post event %d\n", type);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	wake_up(&audio->event_wait);
+}
+
+static void audevrc_suspend(struct early_suspend *h)
+{
+	struct audevrc_suspend_ctl *ctl =
+		container_of(h, struct audevrc_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audevrc_post_event(ctl->audio, AUDIO_EVENT_SUSPEND, payload);
+}
+
+static void audevrc_resume(struct early_suspend *h)
+{
+	struct audevrc_suspend_ctl *ctl =
+		container_of(h, struct audevrc_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audevrc_post_event(ctl->audio, AUDIO_EVENT_RESUME, payload);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audevrc_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audevrc_debug_read(struct file *file, char __user *buf,
+					size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 1024;
+	static char buffer[1024];
+	int n = 0, i;
+	struct audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"enabled %d\n", audio->enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_feedback %d\n", audio->pcm_feedback);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_buf_sz %d\n", audio->out[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_buf_count %d \n", audio->pcm_buf_count);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_buf_sz %d \n", audio->in[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"volume %x \n", audio->vol_pan.volume);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"rflush %d\n", audio->rflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"running %d \n", audio->running);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"dec state %d \n", audio->dec_state);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_needed %d \n", audio->out_needed);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_head %d \n", audio->out_head);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_tail %d \n", audio->out_tail);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out[0].used %d \n", audio->out[0].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out[1].used %d \n", audio->out[1].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"buffer_refresh %d \n", audio->buf_refresh);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"read_next %d \n", audio->read_next);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"fill_next %d \n", audio->fill_next);
+	for (i = 0; i < audio->pcm_buf_count; i++)
+		n += scnprintf(buffer + n, debug_bufmax - n,
+				"in[%d].size %d \n", i, audio->in[i].used);
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audevrc_debug_fops = {
+	.read = audevrc_debug_read,
+	.open = audevrc_debug_open,
+};
+#endif
+
+static int audevrc_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = NULL;
+	int rc, dec_attrb, decid, i;
+	struct audevrc_event *e_node = NULL;
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_evrc_" + 5];
+#endif
+
+	/* Allocate audio instance, set to zero */
+	audio = kzalloc(sizeof(struct audio), GFP_KERNEL);
+	if (!audio) {
+		MM_ERR("no memory to allocate audio instance\n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	MM_INFO("audio instance 0x%08x created\n", (int)audio);
+
+	/* Allocate the decoder */
+	dec_attrb = AUDDEC_DEC_EVRC;
+	if ((file->f_mode & FMODE_WRITE) &&
+			(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_NONTUNNEL;
+		audio->pcm_feedback = NON_TUNNEL_MODE_PLAYBACK;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_TUNNEL;
+		audio->pcm_feedback = TUNNEL_MODE_PLAYBACK;
+	} else {
+		kfree(audio);
+		rc = -EACCES;
+		goto done;
+	}
+	decid = audpp_adec_alloc(dec_attrb, &audio->module_name,
+			&audio->queue_id);
+
+	if (decid < 0) {
+		MM_ERR("No free decoder available, freeing instance 0x%08x\n",
+				(int)audio);
+		rc = -ENODEV;
+		kfree(audio);
+		goto done;
+	}
+
+	audio->dec_id = decid & MSM_AUD_DECODER_MASK;
+
+	audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
+	if (!audio->phys) {
+		MM_ERR("could not allocate write buffers, freeing instance \
+				0x%08x\n", (int)audio);
+		rc = -ENOMEM;
+		audpp_adec_free(audio->dec_id);
+		kfree(audio);
+		goto done;
+	} else {
+		audio->map_v_write = ioremap(audio->phys, DMASZ);
+		if (IS_ERR(audio->map_v_write)) {
+			MM_ERR("failed to map write physical address, freeing \
+					instance 0x%08x\n", (int)audio);
+			rc = -ENOMEM;
+			free_contiguous_memory_by_paddr(audio->phys);
+			audpp_adec_free(audio->dec_id);
+			kfree(audio);
+			goto done;
+		}
+		audio->data = audio->map_v_write;
+		MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+				audio->phys, (int)audio->data);
+	}
+
+	rc = msm_adsp_get(audio->module_name, &audio->audplay,
+			&audplay_adsp_ops_evrc, audio);
+
+	if (rc) {
+		MM_ERR("failed to get %s module, freeing instance 0x%08x\n",
+				audio->module_name, (int)audio);
+		goto err;
+	}
+
+	/* Initialize all locks of audio instance */
+	mutex_init(&audio->lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->get_event_lock);
+	spin_lock_init(&audio->dsp_lock);
+	init_waitqueue_head(&audio->write_wait);
+	init_waitqueue_head(&audio->read_wait);
+	INIT_LIST_HEAD(&audio->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+	init_waitqueue_head(&audio->wait);
+	init_waitqueue_head(&audio->event_wait);
+	spin_lock_init(&audio->event_queue_lock);
+	init_waitqueue_head(&audio->avsync_wait);
+
+	audio->out[0].data = audio->data + 0;
+	audio->out[0].addr = audio->phys + 0;
+	audio->out[0].size = BUFSZ;
+
+	audio->out[1].data = audio->data + BUFSZ;
+	audio->out[1].addr = audio->phys + BUFSZ;
+	audio->out[1].size = BUFSZ;
+
+	audio->vol_pan.volume = 0x3FFF;
+
+	audevrc_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+
+	audio->device_events = AUDDEV_EVT_DEV_RDY
+				|AUDDEV_EVT_DEV_RLS|
+				AUDDEV_EVT_STREAM_VOL_CHG;
+
+	rc = auddev_register_evt_listner(audio->device_events,
+					AUDDEV_CLNT_DEC,
+					audio->dec_id,
+					evrc_listner,
+					(void *)audio);
+	if (rc) {
+		MM_ERR("%s: failed to register listner\n", __func__);
+		goto event_err;
+	}
+
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_evrc_%04x", audio->dec_id);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+			NULL, (void *) audio, &audevrc_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		MM_DBG("debugfs_create_file failed\n");
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	audio->suspend_ctl.node.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+	audio->suspend_ctl.node.resume = audevrc_resume;
+	audio->suspend_ctl.node.suspend = audevrc_suspend;
+	audio->suspend_ctl.audio = audio;
+	register_early_suspend(&audio->suspend_ctl.node);
+#endif
+	for (i = 0; i < AUDEVRC_EVENT_NUM; i++) {
+		e_node = kmalloc(sizeof(struct audevrc_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			MM_ERR("event pkt alloc failed\n");
+			break;
+		}
+	}
+done:
+	return rc;
+event_err:
+	msm_adsp_put(audio->audplay);
+err:
+	iounmap(audio->map_v_write);
+	free_contiguous_memory_by_paddr(audio->phys);
+	audpp_adec_free(audio->dec_id);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_evrc_fops = {
+	.owner = THIS_MODULE,
+	.open = audevrc_open,
+	.release = audevrc_release,
+	.read = audevrc_read,
+	.write = audevrc_write,
+	.unlocked_ioctl = audevrc_ioctl,
+	.fsync = audevrc_fsync,
+};
+
+struct miscdevice audio_evrc_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_evrc",
+	.fops = &audio_evrc_fops,
+};
+
+static int __init audevrc_init(void)
+{
+	return misc_register(&audio_evrc_misc);
+
+}
+
+static void __exit audevrc_exit(void)
+{
+	misc_deregister(&audio_evrc_misc);
+}
+
+module_init(audevrc_init);
+module_exit(audevrc_exit);
+
+MODULE_DESCRIPTION("MSM EVRC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c b/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c
new file mode 100644
index 0000000..1ee5029
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c
@@ -0,0 +1,1507 @@
+/*
+ * evrc audio input device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2009-2012, Code Aurora Forum. 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.
+ *
+ */
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/msm_audio_qcp.h>
+#include <linux/android_pmem.h>
+#include <linux/memory_alloc.h>
+
+#include <mach/msm_adsp.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/socinfo.h>
+#include <mach/qdsp5v2/qdsp5audreccmdi.h>
+#include <mach/qdsp5v2/qdsp5audrecmsg.h>
+#include <mach/qdsp5v2/audpreproc.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_memtypes.h>
+
+#define META_OUT_SIZE	24
+/* FRAME_NUM must be a power of two */
+#define FRAME_NUM	8
+#define EVRC_FRAME_SIZE	36 /* 36 bytes data */
+#define FRAME_SIZE	(22 * 2) /* 36 bytes data */
+ /* 36 bytes data  + 24 meta field*/
+#define NT_FRAME_SIZE	(EVRC_FRAME_SIZE + META_OUT_SIZE)
+#define DMASZ		(NT_FRAME_SIZE * FRAME_NUM)
+#define OUT_FRAME_NUM	2
+#define OUT_BUFFER_SIZE (4 * 1024 + META_OUT_SIZE)
+#define BUFFER_SIZE	(OUT_BUFFER_SIZE * OUT_FRAME_NUM)
+
+#define AUDPREPROC_EVRC_EOS_FLG_OFFSET 0x0A /* Offset from beginning of buffer*/
+#define AUDPREPROC_EVRC_EOS_FLG_MASK 0x01
+#define AUDPREPROC_EVRC_EOS_NONE 0x0 /* No EOS detected */
+#define AUDPREPROC_EVRC_EOS_SET 0x1 /* EOS set in meta field */
+
+struct buffer {
+	void *data;
+	uint32_t size;
+	uint32_t read;
+	uint32_t addr;
+	uint32_t used;
+	uint32_t mfield_sz;
+};
+
+struct audio_in {
+	struct buffer in[FRAME_NUM];
+
+	spinlock_t dsp_lock;
+
+	atomic_t in_bytes;
+	atomic_t in_samples;
+
+	struct mutex lock;
+	struct mutex read_lock;
+	wait_queue_head_t wait;
+	wait_queue_head_t wait_enable;
+	/*write section*/
+	struct buffer out[OUT_FRAME_NUM];
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed;	/* number of buffers the dsp is waiting for */
+	uint32_t out_count;
+
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+	int32_t out_phys; /* physical address of write buffer */
+	char *out_data;
+	int mfield; /* meta field embedded in data */
+	int wflush; /*write flush */
+	int rflush; /*read flush*/
+	int out_frame_cnt;
+
+	struct msm_adsp_module *audrec;
+
+	struct audrec_session_info session_info; /*audrec session info*/
+
+	/* configuration to use on next enable */
+	uint32_t buffer_size; /* Frame size (36 bytes) */
+	uint32_t samp_rate;
+	uint32_t channel_mode;
+	uint32_t enc_type;
+
+	struct msm_audio_evrc_enc_config cfg;
+
+	uint32_t dsp_cnt;
+	uint32_t in_head; /* next buffer dsp will write */
+	uint32_t in_tail; /* next buffer read() will read */
+	uint32_t in_count; /* number of buffers available to read() */
+	uint32_t mode;
+	uint32_t eos_ack;
+	uint32_t flush_ack;
+
+	const char *module_name;
+	unsigned queue_ids;
+	uint16_t enc_id;
+
+	uint16_t source; /* Encoding source bit mask */
+	uint32_t device_events;
+	uint32_t in_call;
+	uint32_t dev_cnt;
+	int voice_state;
+	spinlock_t dev_lock;
+
+	/* data allocated for various buffers */
+	char *data;
+	dma_addr_t phys;
+	void *map_v_read;
+	void *map_v_write;
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+	char *build_id;
+};
+
+struct audio_frame {
+	uint16_t frame_count_lsw;
+	uint16_t frame_count_msw;
+	uint16_t frame_length;
+	uint16_t erased_pcm;
+	unsigned char raw_bitstream[]; /* samples */
+} __attribute__((packed));
+
+struct audio_frame_nt {
+	uint16_t metadata_len;
+	uint16_t frame_count_lsw;
+	uint16_t frame_count_msw;
+	uint16_t frame_length;
+	uint16_t erased_pcm;
+	uint16_t reserved;
+	uint16_t time_stamp_dword_lsw;
+	uint16_t time_stamp_dword_msw;
+	uint16_t time_stamp_lsw;
+	uint16_t time_stamp_msw;
+	uint16_t nflag_lsw;
+	uint16_t nflag_msw;
+	unsigned char raw_bitstream[]; /* samples */
+} __attribute__((packed));
+
+struct evrc_encoded_meta_out {
+	uint16_t metadata_len;
+	uint16_t time_stamp_dword_lsw;
+	uint16_t time_stamp_dword_msw;
+	uint16_t time_stamp_lsw;
+	uint16_t time_stamp_msw;
+	uint16_t nflag_lsw;
+	uint16_t nflag_msw;
+};
+
+/* Audrec Queue command sent macro's */
+#define audrec_send_bitstreamqueue(audio, cmd, len) \
+	msm_adsp_write(audio->audrec, ((audio->queue_ids & 0xFFFF0000) >> 16),\
+			cmd, len)
+
+#define audrec_send_audrecqueue(audio, cmd, len) \
+	msm_adsp_write(audio->audrec, (audio->queue_ids & 0x0000FFFF),\
+			cmd, len)
+
+/* DSP command send functions */
+static int audevrc_in_enc_config(struct audio_in *audio, int enable);
+static int audevrc_in_param_config(struct audio_in *audio);
+static int audevrc_in_mem_config(struct audio_in *audio);
+static int audevrc_in_record_config(struct audio_in *audio, int enable);
+static int audevrc_dsp_read_buffer(struct audio_in *audio, uint32_t read_cnt);
+
+static void audevrc_in_get_dsp_frames(struct audio_in *audio);
+static int audpcm_config(struct audio_in *audio);
+static void audevrc_out_flush(struct audio_in *audio);
+static int audpreproc_cmd_cfg_routing_mode(struct audio_in *audio);
+static void audpreproc_pcm_send_data(struct audio_in *audio, unsigned needed);
+static void audevrc_nt_in_get_dsp_frames(struct audio_in *audio);
+
+static void audevrc_in_flush(struct audio_in *audio);
+
+static void evrc_in_listener(u32 evt_id, union auddev_evt_data *evt_payload,
+				void *private_data)
+{
+	struct audio_in *audio = (struct audio_in *) private_data;
+	unsigned long flags;
+
+	MM_DBG("evt_id = 0x%8x\n", evt_id);
+	switch (evt_id) {
+	case AUDDEV_EVT_DEV_RDY: {
+		MM_DBG("AUDDEV_EVT_DEV_RDY\n");
+		spin_lock_irqsave(&audio->dev_lock, flags);
+		audio->dev_cnt++;
+		if (!audio->in_call)
+			audio->source |= (0x1 << evt_payload->routing_id);
+		spin_unlock_irqrestore(&audio->dev_lock, flags);
+
+		if ((audio->running == 1) && (audio->enabled == 1) &&
+			(audio->mode == MSM_AUD_ENC_MODE_TUNNEL))
+			audevrc_in_record_config(audio, 1);
+	}
+		break;
+	case AUDDEV_EVT_DEV_RLS: {
+		MM_DBG("AUDDEV_EVT_DEV_RLS\n");
+		spin_lock_irqsave(&audio->dev_lock, flags);
+		audio->dev_cnt--;
+		if (!audio->in_call)
+			audio->source &= ~(0x1 << evt_payload->routing_id);
+		spin_unlock_irqrestore(&audio->dev_lock, flags);
+
+		if ((!audio->running) || (!audio->enabled))
+			break;
+
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+			/* Turn of as per source */
+			if (audio->source)
+				audevrc_in_record_config(audio, 1);
+			else
+				/* Turn off all */
+				audevrc_in_record_config(audio, 0);
+		}
+	}
+		break;
+	case AUDDEV_EVT_VOICE_STATE_CHG: {
+		MM_DBG("AUDDEV_EVT_VOICE_STATE_CHG, state = %d\n",
+				evt_payload->voice_state);
+		audio->voice_state = evt_payload->voice_state;
+		if (audio->in_call && audio->running &&
+		   (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)) {
+			if (audio->voice_state == VOICE_STATE_INCALL)
+				audevrc_in_record_config(audio, 1);
+			else if (audio->voice_state == VOICE_STATE_OFFCALL) {
+				audevrc_in_record_config(audio, 0);
+				wake_up(&audio->wait);
+			}
+		}
+
+		break;
+	}
+	default:
+		MM_ERR("wrong event %d\n", evt_id);
+		break;
+	}
+}
+
+/* ------------------- dsp preproc event handler--------------------- */
+static void audpreproc_dsp_event(void *data, unsigned id,  void *msg)
+{
+	struct audio_in *audio = data;
+
+	switch (id) {
+	case AUDPREPROC_ERROR_MSG: {
+		struct audpreproc_err_msg *err_msg = msg;
+
+		MM_ERR("ERROR_MSG: stream id %d err idx %d\n",
+		err_msg->stream_id, err_msg->aud_preproc_err_idx);
+		/* Error case */
+		wake_up(&audio->wait_enable);
+		break;
+	}
+	case AUDPREPROC_CMD_CFG_DONE_MSG: {
+		MM_DBG("CMD_CFG_DONE_MSG \n");
+		break;
+	}
+	case AUDPREPROC_CMD_ENC_CFG_DONE_MSG: {
+		struct audpreproc_cmd_enc_cfg_done_msg *enc_cfg_msg = msg;
+
+		MM_DBG("CMD_ENC_CFG_DONE_MSG: stream id %d enc type \
+			0x%8x\n", enc_cfg_msg->stream_id,
+			enc_cfg_msg->rec_enc_type);
+		/* Encoder enable success */
+		if (enc_cfg_msg->rec_enc_type & ENCODE_ENABLE) {
+			if(audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
+				MM_DBG("routing command\n");
+				audpreproc_cmd_cfg_routing_mode(audio);
+			} else {
+				audevrc_in_param_config(audio);
+			}
+		} else { /* Encoder disable success */
+			audio->running = 0;
+			if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
+				audevrc_in_record_config(audio, 0);
+			else
+				wake_up(&audio->wait_enable);
+		}
+		break;
+	}
+	case AUDPREPROC_CMD_ENC_PARAM_CFG_DONE_MSG: {
+		MM_DBG("CMD_ENC_PARAM_CFG_DONE_MSG\n");
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
+			audevrc_in_mem_config(audio);
+		else
+			audpcm_config(audio);
+		break;
+	}
+	case AUDPREPROC_CMD_ROUTING_MODE_DONE_MSG: {
+		struct audpreproc_cmd_routing_mode_done\
+				*routing_cfg_done_msg = msg;
+		if (routing_cfg_done_msg->configuration == 0) {
+			MM_INFO("routing configuration failed\n");
+			audio->running = 0;
+		} else
+			audevrc_in_param_config(audio);
+		break;
+	}
+	case AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG: {
+		MM_DBG("AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG \n");
+		wake_up(&audio->wait_enable);
+		break;
+	}
+	default:
+		MM_ERR("Unknown Event id %d\n", id);
+	}
+}
+
+/* ------------------- dsp audrec event handler--------------------- */
+static void audrec_dsp_event(void *data, unsigned id, size_t len,
+			    void (*getevent)(void *ptr, size_t len))
+{
+	struct audio_in *audio = data;
+
+	switch (id) {
+	case AUDREC_CMD_MEM_CFG_DONE_MSG: {
+		MM_DBG("CMD_MEM_CFG_DONE MSG DONE\n");
+		audio->running = 1;
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+			if ((!audio->in_call && (audio->dev_cnt > 0)) ||
+				(audio->in_call &&
+					(audio->voice_state \
+						== VOICE_STATE_INCALL)))
+				audevrc_in_record_config(audio, 1);
+		} else {
+			audpreproc_pcm_send_data(audio, 1);
+			wake_up(&audio->wait_enable);
+		}
+		break;
+	}
+	case AUDREC_FATAL_ERR_MSG: {
+		struct audrec_fatal_err_msg fatal_err_msg;
+
+		getevent(&fatal_err_msg, AUDREC_FATAL_ERR_MSG_LEN);
+		MM_ERR("FATAL_ERR_MSG: err id %d\n",
+				fatal_err_msg.audrec_err_id);
+		/* Error stop the encoder */
+		audio->stopped = 1;
+		wake_up(&audio->wait);
+		if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)
+			wake_up(&audio->write_wait);
+		break;
+	}
+	case AUDREC_UP_PACKET_READY_MSG: {
+		struct audrec_up_pkt_ready_msg pkt_ready_msg;
+
+		getevent(&pkt_ready_msg, AUDREC_UP_PACKET_READY_MSG_LEN);
+		MM_DBG("UP_PACKET_READY_MSG: write cnt lsw  %d \
+		write cnt msw %d read cnt lsw %d  read cnt msw %d \n",\
+		pkt_ready_msg.audrec_packet_write_cnt_lsw, \
+		pkt_ready_msg.audrec_packet_write_cnt_msw, \
+		pkt_ready_msg.audrec_up_prev_read_cnt_lsw, \
+		pkt_ready_msg.audrec_up_prev_read_cnt_msw);
+
+		audevrc_in_get_dsp_frames(audio);
+		break;
+	}
+	case AUDREC_CMD_PCM_BUFFER_PTR_UPDATE_ARM_TO_ENC_MSG: {
+		MM_DBG("ptr_update recieved from DSP\n");
+		audpreproc_pcm_send_data(audio, 1);
+		break;
+	}
+	case AUDREC_CMD_PCM_CFG_ARM_TO_ENC_DONE_MSG: {
+		MM_ERR("AUDREC_CMD_PCM_CFG_ARM_TO_ENC_DONE_MSG");
+		audevrc_in_mem_config(audio);
+		break;
+	}
+	case AUDREC_UP_NT_PACKET_READY_MSG: {
+		struct audrec_up_nt_packet_ready_msg pkt_ready_msg;
+
+		getevent(&pkt_ready_msg, AUDREC_UP_NT_PACKET_READY_MSG_LEN);
+		MM_DBG("UP_NT_PACKET_READY_MSG: write cnt lsw  %d \
+		write cnt msw %d read cnt lsw %d  read cnt msw %d \n",\
+		pkt_ready_msg.audrec_packetwrite_cnt_lsw, \
+		pkt_ready_msg.audrec_packetwrite_cnt_msw, \
+		pkt_ready_msg.audrec_upprev_readcount_lsw, \
+		pkt_ready_msg.audrec_upprev_readcount_msw);
+
+		audevrc_nt_in_get_dsp_frames(audio);
+		break;
+	}
+	case AUDREC_CMD_EOS_ACK_MSG: {
+		MM_DBG("eos ack recieved\n");
+		break;
+	}
+	case AUDREC_CMD_FLUSH_DONE_MSG: {
+		audio->wflush = 0;
+		audio->rflush = 0;
+		audio->flush_ack = 1;
+		wake_up(&audio->write_wait);
+		MM_DBG("flush ack recieved\n");
+		break;
+	}
+	case ADSP_MESSAGE_ID: {
+		MM_DBG("Received ADSP event:module audrectask\n");
+		break;
+	}
+	default:
+		MM_ERR("Unknown Event id %d\n", id);
+	}
+}
+
+static void audevrc_in_get_dsp_frames(struct audio_in *audio)
+{
+	struct audio_frame *frame;
+	uint32_t index;
+	unsigned long flags;
+
+	index = audio->in_head;
+
+	frame = (void *) (((char *)audio->in[index].data) - \
+			 sizeof(*frame));
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->in[index].size = frame->frame_length;
+
+	/* statistics of read */
+	atomic_add(audio->in[index].size, &audio->in_bytes);
+	atomic_add(1, &audio->in_samples);
+
+	audio->in_head = (audio->in_head + 1) & (FRAME_NUM - 1);
+
+	/* If overflow, move the tail index foward. */
+	if (audio->in_head == audio->in_tail) {
+		MM_ERR("Error! not able to keep up the read\n");
+		audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
+		MM_ERR("in_count = %d\n", audio->in_count);
+	} else
+		audio->in_count++;
+
+	audevrc_dsp_read_buffer(audio, audio->dsp_cnt++);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+
+	wake_up(&audio->wait);
+}
+
+static void audevrc_nt_in_get_dsp_frames(struct audio_in *audio)
+{
+	struct audio_frame_nt *nt_frame;
+	uint32_t index;
+	unsigned long flags;
+
+	index = audio->in_head;
+	nt_frame = (void *) (((char *)audio->in[index].data) - \
+				sizeof(struct audio_frame_nt));
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->in[index].size = nt_frame->frame_length;
+	/* statistics of read */
+	atomic_add(audio->in[index].size, &audio->in_bytes);
+	atomic_add(1, &audio->in_samples);
+
+	audio->in_head = (audio->in_head + 1) & (FRAME_NUM - 1);
+
+	/* If overflow, move the tail index foward. */
+	if (audio->in_head == audio->in_tail)
+		MM_DBG("Error! not able to keep up the read\n");
+	else
+		audio->in_count++;
+
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	wake_up(&audio->wait);
+}
+
+
+struct msm_adsp_ops audrec_evrc_adsp_ops = {
+	.event = audrec_dsp_event,
+};
+
+static int audpreproc_pcm_buffer_ptr_refresh(struct audio_in *audio,
+				       unsigned idx, unsigned len)
+{
+	struct audrec_cmd_pcm_buffer_ptr_refresh_arm_enc cmd;
+
+	if (len ==  META_OUT_SIZE)
+		len = len / 2;
+	else
+		len = (len + META_OUT_SIZE) / 2;
+	MM_DBG("len = %d\n", len);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_PCM_BUFFER_PTR_REFRESH_ARM_TO_ENC;
+	cmd.num_buffers = 1;
+	if (cmd.num_buffers == 1) {
+		cmd.buf_address_length[0] = (audio->out[idx].addr &
+							0xffff0000) >> 16;
+		cmd.buf_address_length[1] = (audio->out[idx].addr &
+							0x0000ffff);
+		cmd.buf_address_length[2] = (len & 0xffff0000) >> 16;
+		cmd.buf_address_length[3] = (len & 0x0000ffff);
+	}
+	audio->out_frame_cnt++;
+	return audrec_send_audrecqueue(audio, (void *)&cmd,
+					(unsigned int)sizeof(cmd));
+}
+
+
+static int audpcm_config(struct audio_in *audio)
+{
+	struct audrec_cmd_pcm_cfg_arm_to_enc cmd;
+	MM_DBG("\n");
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_PCM_CFG_ARM_TO_ENC;
+	cmd.config_update_flag = AUDREC_PCM_CONFIG_UPDATE_FLAG_ENABLE;
+	cmd.enable_flag = AUDREC_ENABLE_FLAG_VALUE;
+	cmd.sampling_freq = audio->samp_rate;
+	if (!audio->channel_mode)
+		cmd.channels = 1;
+	else
+		cmd.channels = 2;
+	cmd.frequency_of_intimation = 1;
+	cmd.max_number_of_buffers = OUT_FRAME_NUM;
+	return audrec_send_audrecqueue(audio, (void *)&cmd,
+					(unsigned int)sizeof(cmd));
+}
+
+
+static int audpreproc_cmd_cfg_routing_mode(struct audio_in *audio)
+{
+	struct audpreproc_audrec_cmd_routing_mode cmd;
+
+	MM_DBG("\n");
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPREPROC_AUDREC_CMD_ROUTING_MODE;
+	cmd.stream_id = audio->enc_id;
+	if (audio->mode == MSM_ADSP_ENC_MODE_NON_TUNNEL)
+		cmd.routing_mode = 1;
+	return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
+}
+
+
+
+static int audevrc_in_enc_config(struct audio_in *audio, int enable)
+{
+	struct audpreproc_audrec_cmd_enc_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	if (audio->build_id[17] == '1') {
+		cmd.cmd_id = AUDPREPROC_AUDREC_CMD_ENC_CFG_2;
+		MM_ERR("sending AUDPREPROC_AUDREC_CMD_ENC_CFG_2 command");
+	} else {
+		cmd.cmd_id = AUDPREPROC_AUDREC_CMD_ENC_CFG;
+		MM_ERR("sending AUDPREPROC_AUDREC_CMD_ENC_CFG command");
+	}
+	cmd.stream_id = audio->enc_id;
+
+	if (enable)
+		cmd.audrec_enc_type = audio->enc_type | ENCODE_ENABLE;
+	else
+		cmd.audrec_enc_type &= ~(ENCODE_ENABLE);
+
+	return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
+}
+
+static int audevrc_in_param_config(struct audio_in *audio)
+{
+	struct audpreproc_audrec_cmd_parm_cfg_evrc cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPREPROC_AUDREC_CMD_PARAM_CFG;
+	cmd.common.stream_id = audio->enc_id;
+
+	cmd.enc_min_rate = audio->cfg.min_bit_rate;
+	cmd.enc_max_rate = audio->cfg.max_bit_rate;
+	cmd.rate_modulation_cmd = 0;  /* Default set to 0 */
+
+	return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
+}
+
+/* To Do: msm_snddev_route_enc(audio->enc_id); */
+static int audevrc_in_record_config(struct audio_in *audio, int enable)
+{
+	struct audpreproc_afe_cmd_audio_record_cfg cmd;
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG;
+	cmd.stream_id = audio->enc_id;
+	if (enable)
+		cmd.destination_activity = AUDIO_RECORDING_TURN_ON;
+	else
+		cmd.destination_activity = AUDIO_RECORDING_TURN_OFF;
+
+	cmd.source_mix_mask = audio->source;
+	if (audio->enc_id == 2) {
+		if ((cmd.source_mix_mask &
+				INTERNAL_CODEC_TX_SOURCE_MIX_MASK) ||
+			(cmd.source_mix_mask & AUX_CODEC_TX_SOURCE_MIX_MASK) ||
+			(cmd.source_mix_mask & VOICE_UL_SOURCE_MIX_MASK) ||
+			(cmd.source_mix_mask & VOICE_DL_SOURCE_MIX_MASK)) {
+			cmd.pipe_id = SOURCE_PIPE_1;
+		}
+		if (cmd.source_mix_mask &
+				AUDPP_A2DP_PIPE_SOURCE_MIX_MASK)
+			cmd.pipe_id |= SOURCE_PIPE_0;
+	}
+	MM_DBG("stream_id %x destination_activity %x \
+	source_mix_mask %x pipe_id %x",\
+	cmd.stream_id, cmd.destination_activity,
+	cmd.source_mix_mask, cmd.pipe_id);
+	return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
+}
+
+static int audevrc_in_mem_config(struct audio_in *audio)
+{
+	struct audrec_cmd_arecmem_cfg cmd;
+	uint16_t *data = (void *) audio->data;
+	int n;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_MEM_CFG_CMD;
+	cmd.audrec_up_pkt_intm_count = 1;
+	cmd.audrec_ext_pkt_start_addr_msw = audio->phys >> 16;
+	cmd.audrec_ext_pkt_start_addr_lsw = audio->phys;
+	cmd.audrec_ext_pkt_buf_number = FRAME_NUM;
+	MM_DBG("audio->phys = %x\n", audio->phys);
+	/* prepare buffer pointers:
+	 * T:36 bytes evrc packet + 4 halfword header
+	 * NT:36 bytes evrc packet + 12 halfword header
+	 */
+	for (n = 0; n < FRAME_NUM; n++) {
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+			audio->in[n].data = data + 4;
+			data += (FRAME_SIZE/2);
+			MM_DBG("0x%8x\n", (int)(audio->in[n].data - 8));
+		} else  {
+			audio->in[n].data = data + 12;
+			data += ((EVRC_FRAME_SIZE) / 2) + 12;
+			MM_DBG("0x%8x\n", (int)(audio->in[n].data - 24));
+		}
+	}
+	return audrec_send_audrecqueue(audio, &cmd, sizeof(cmd));
+}
+
+static int audevrc_dsp_read_buffer(struct audio_in *audio, uint32_t read_cnt)
+{
+	struct up_audrec_packet_ext_ptr cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = UP_AUDREC_PACKET_EXT_PTR;
+	cmd.audrec_up_curr_read_count_msw = read_cnt >> 16;
+	cmd.audrec_up_curr_read_count_lsw = read_cnt;
+
+	return audrec_send_bitstreamqueue(audio, &cmd, sizeof(cmd));
+}
+static int audevrc_flush_command(struct audio_in *audio)
+{
+	struct audrec_cmd_flush cmd;
+	MM_DBG("\n");
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_FLUSH;
+	return audrec_send_audrecqueue(audio, &cmd, sizeof(cmd));
+}
+
+/* must be called with audio->lock held */
+static int audevrc_in_enable(struct audio_in *audio)
+{
+	if (audio->enabled)
+		return 0;
+
+	if (audpreproc_enable(audio->enc_id, &audpreproc_dsp_event, audio)) {
+		MM_ERR("msm_adsp_enable(audpreproc) failed\n");
+		return -ENODEV;
+	}
+
+	if (msm_adsp_enable(audio->audrec)) {
+		MM_ERR("msm_adsp_enable(audrec) failed\n");
+		audpreproc_disable(audio->enc_id, audio);
+		return -ENODEV;
+	}
+	audio->enabled = 1;
+	audevrc_in_enc_config(audio, 1);
+
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audevrc_in_disable(struct audio_in *audio)
+{
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audevrc_in_enc_config(audio, 0);
+		wake_up(&audio->wait);
+		wait_event_interruptible_timeout(audio->wait_enable,
+				audio->running == 0, 1*HZ);
+		msm_adsp_disable(audio->audrec);
+		audpreproc_disable(audio->enc_id, audio);
+	}
+	return 0;
+}
+
+static void audevrc_ioport_reset(struct audio_in *audio)
+{
+	/* Make sure read/write thread are free from
+	 * sleep and knowing that system is not able
+	 * to process io request at the moment
+	 */
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audevrc_in_flush(audio);
+	mutex_unlock(&audio->write_lock);
+	wake_up(&audio->wait);
+	mutex_lock(&audio->read_lock);
+	audevrc_out_flush(audio);
+	mutex_unlock(&audio->read_lock);
+}
+
+static void audevrc_in_flush(struct audio_in *audio)
+{
+	int i;
+
+	audio->dsp_cnt = 0;
+	audio->in_head = 0;
+	audio->in_tail = 0;
+	audio->in_count = 0;
+	audio->eos_ack = 0;
+	for (i = 0; i < FRAME_NUM; i++) {
+		audio->in[i].size = 0;
+		audio->in[i].read = 0;
+	}
+	MM_DBG("in_bytes %d\n", atomic_read(&audio->in_bytes));
+	MM_DBG("in_samples %d\n", atomic_read(&audio->in_samples));
+	atomic_set(&audio->in_bytes, 0);
+	atomic_set(&audio->in_samples, 0);
+}
+
+static void audevrc_out_flush(struct audio_in *audio)
+{
+	int i;
+
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->out_count = 0;
+	for (i = 0; i < OUT_FRAME_NUM; i++) {
+		audio->out[i].size = 0;
+		audio->out[i].read = 0;
+		audio->out[i].used = 0;
+	}
+}
+
+/* ------------------- device --------------------- */
+static long audevrc_in_ioctl(struct file *file,
+				unsigned int cmd, unsigned long arg)
+{
+	struct audio_in *audio = file->private_data;
+	int rc = 0;
+
+	MM_DBG("\n");
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = atomic_read(&audio->in_bytes);
+		stats.sample_count = atomic_read(&audio->in_samples);
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return rc;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START: {
+		uint32_t freq;
+		freq = 48000;
+		MM_DBG("AUDIO_START\n");
+		if (audio->in_call && (audio->voice_state !=
+				VOICE_STATE_INCALL)) {
+			rc = -EPERM;
+			break;
+		}
+		rc = msm_snddev_request_freq(&freq, audio->enc_id,
+					SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
+		MM_DBG("sample rate configured %d\n", freq);
+		if (rc < 0) {
+			MM_DBG(" Sample rate can not be set, return code %d\n",
+								 rc);
+			msm_snddev_withdraw_freq(audio->enc_id,
+					SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
+			MM_DBG("msm_snddev_withdraw_freq\n");
+			break;
+		}
+		/*update aurec session info in audpreproc layer*/
+		audio->session_info.session_id = audio->enc_id;
+		audio->session_info.sampling_freq = audio->samp_rate;
+		audpreproc_update_audrec_info(&audio->session_info);
+		rc = audevrc_in_enable(audio);
+		if (!rc) {
+			rc =
+			wait_event_interruptible_timeout(audio->wait_enable,
+				audio->running != 0, 1*HZ);
+			MM_DBG("state %d rc = %d\n", audio->running, rc);
+
+			if (audio->running == 0)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		audio->stopped = 0;
+		break;
+	}
+	case AUDIO_STOP: {
+		/*reset the sampling frequency information at audpreproc layer*/
+		audio->session_info.sampling_freq = 0;
+		audpreproc_update_audrec_info(&audio->session_info);
+		rc = audevrc_in_disable(audio);
+		rc = msm_snddev_withdraw_freq(audio->enc_id,
+					SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
+		MM_DBG("msm_snddev_withdraw_freq\n");
+		audio->stopped = 1;
+		break;
+	}
+	case AUDIO_FLUSH: {
+		MM_DBG("AUDIO_FLUSH\n");
+		audio->rflush = 1;
+		audio->wflush = 1;
+		audevrc_ioport_reset(audio);
+		if (audio->running) {
+			audevrc_flush_command(audio);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		break;
+	}
+	case AUDIO_SET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		/* Allow only single frame */
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+			if (cfg.buffer_size != (FRAME_SIZE - 8)) {
+				rc = -EINVAL;
+				break;
+			}
+		} else {
+			if (cfg.buffer_size != (EVRC_FRAME_SIZE + 14)) {
+				rc = -EINVAL;
+				break;
+			}
+		}
+		audio->buffer_size = cfg.buffer_size;
+		break;
+	}
+	case AUDIO_GET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		memset(&cfg, 0, sizeof(cfg));
+		cfg.buffer_size = audio->buffer_size;
+		cfg.buffer_count = FRAME_NUM;
+		if (copy_to_user((void *) arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_GET_EVRC_ENC_CONFIG: {
+		if (copy_to_user((void *) arg, &audio->cfg, sizeof(audio->cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_EVRC_ENC_CONFIG: {
+		struct msm_audio_evrc_enc_config cfg;
+		if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		MM_DBG("0X%8x, 0x%8x, 0x%8x\n", cfg.min_bit_rate,
+				cfg.max_bit_rate, cfg.cdma_rate);
+		if (cfg.min_bit_rate > CDMA_RATE_FULL || \
+				 cfg.min_bit_rate < CDMA_RATE_EIGHTH) {
+			MM_ERR("invalid min bitrate\n");
+			rc = -EFAULT;
+			break;
+		}
+		if (cfg.max_bit_rate > CDMA_RATE_FULL || \
+				cfg.max_bit_rate < CDMA_RATE_EIGHTH) {
+			MM_ERR("invalid max bitrate\n");
+			rc = -EFAULT;
+			break;
+		}
+		/* Recording Does not support Erase and Blank */
+		if (cfg.cdma_rate > CDMA_RATE_FULL ||
+			cfg.cdma_rate < CDMA_RATE_EIGHTH) {
+			MM_ERR("invalid qcelp cdma rate\n");
+			rc = -EFAULT;
+			break;
+		}
+		memcpy(&audio->cfg, &cfg, sizeof(cfg));
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config cfg;
+		memset(&cfg, 0, sizeof(cfg));
+		cfg.buffer_size = OUT_BUFFER_SIZE;
+		cfg.buffer_count = OUT_FRAME_NUM;
+		cfg.sample_rate = audio->samp_rate;
+		cfg.channel_count = audio->channel_mode;
+		if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_INCALL: {
+		struct msm_voicerec_mode cfg;
+		unsigned long flags;
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+			if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
+				rc = -EFAULT;
+				break;
+			}
+			if (cfg.rec_mode != VOC_REC_BOTH &&
+				cfg.rec_mode != VOC_REC_UPLINK &&
+				cfg.rec_mode != VOC_REC_DOWNLINK) {
+				MM_ERR("invalid rec_mode\n");
+				rc = -EINVAL;
+				break;
+			} else {
+				spin_lock_irqsave(&audio->dev_lock, flags);
+				if (cfg.rec_mode == VOC_REC_UPLINK)
+					audio->source = \
+						VOICE_UL_SOURCE_MIX_MASK;
+				else if (cfg.rec_mode == VOC_REC_DOWNLINK)
+					audio->source = \
+						VOICE_DL_SOURCE_MIX_MASK;
+				else
+					audio->source = \
+						VOICE_DL_SOURCE_MIX_MASK |
+						VOICE_UL_SOURCE_MIX_MASK ;
+				audio->in_call = 1;
+				spin_unlock_irqrestore(&audio->dev_lock, flags);
+			}
+		}
+		break;
+	}
+	case AUDIO_GET_SESSION_ID: {
+		if (copy_to_user((void *) arg, &audio->enc_id,
+			sizeof(unsigned short))) {
+			rc = -EFAULT;
+		}
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static ssize_t audevrc_in_read(struct file *file,
+				char __user *buf,
+				size_t count, loff_t *pos)
+{
+	struct audio_in *audio = file->private_data;
+	unsigned long flags;
+	const char __user *start = buf;
+	void *data;
+	uint32_t index;
+	uint32_t size;
+	int rc = 0;
+	struct evrc_encoded_meta_out meta_field;
+	struct audio_frame_nt *nt_frame;
+	MM_DBG("count = %d\n", count);
+	mutex_lock(&audio->read_lock);
+	while (count > 0) {
+		rc = wait_event_interruptible(
+			audio->wait, (audio->in_count > 0) || audio->stopped ||
+			audio->rflush ||
+			((audio->mode == MSM_AUD_ENC_MODE_TUNNEL) &&
+			 audio->in_call && audio->running &&
+			(audio->voice_state == VOICE_STATE_OFFCALL)));
+		if (rc < 0)
+			break;
+
+		if (audio->rflush) {
+			rc = -EBUSY;
+			break;
+		}
+		if (audio->stopped && !audio->in_count) {
+			MM_DBG("Driver in stop state, No more buffer to read");
+			rc = 0;/* End of File */
+			break;
+			} else if ((audio->mode == MSM_AUD_ENC_MODE_TUNNEL) &&
+					audio->in_call && audio->running &&
+					(audio->voice_state \
+						== VOICE_STATE_OFFCALL)) {
+				MM_DBG("Not Permitted Voice Terminated\n");
+				rc = -EPERM; /* Voice Call stopped */
+				break;
+		}
+
+		index = audio->in_tail;
+		data = (uint8_t *) audio->in[index].data;
+		size = audio->in[index].size;
+
+		if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
+			nt_frame = (struct audio_frame_nt *)(data -
+					sizeof(struct audio_frame_nt));
+			memcpy((char *)&meta_field.time_stamp_dword_lsw,
+				(char *)&nt_frame->time_stamp_dword_lsw,
+				(sizeof(struct evrc_encoded_meta_out) - \
+				sizeof(uint16_t)));
+			meta_field.metadata_len =
+					sizeof(struct evrc_encoded_meta_out);
+			if (copy_to_user((char *)start, (char *)&meta_field,
+					sizeof(struct evrc_encoded_meta_out))) {
+				rc = -EFAULT;
+				break;
+			}
+			if (nt_frame->nflag_lsw & 0x0001) {
+				MM_ERR("recieved EOS in read call\n");
+				audio->eos_ack = 1;
+			}
+			buf += sizeof(struct evrc_encoded_meta_out);
+			count -= sizeof(struct evrc_encoded_meta_out);
+		}
+		if (count >= size) {
+			if (copy_to_user(buf, data, size)) {
+				rc = -EFAULT;
+				break;
+			}
+			spin_lock_irqsave(&audio->dsp_lock, flags);
+			if (index != audio->in_tail) {
+				/* overrun -- data is
+				 * invalid and we need to retry */
+				spin_unlock_irqrestore(&audio->dsp_lock, flags);
+				continue;
+			}
+			audio->in[index].size = 0;
+			audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
+			audio->in_count--;
+			spin_unlock_irqrestore(&audio->dsp_lock, flags);
+			count -= size;
+			buf += size;
+			if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)) {
+				if (!audio->eos_ack) {
+					MM_DBG("sending read ptr command \
+							%d %d\n",
+							audio->dsp_cnt,
+							audio->in_tail);
+					audevrc_dsp_read_buffer(audio,
+							audio->dsp_cnt++);
+				}
+			}
+		} else {
+			MM_ERR("short read\n");
+			break;
+		}
+		break;
+	}
+	mutex_unlock(&audio->read_lock);
+
+	if (buf > start)
+		return buf - start;
+
+	return rc;
+}
+
+static void audpreproc_pcm_send_data(struct audio_in *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+	MM_DBG("\n");
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (needed && !audio->wflush) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			MM_DBG("frame %d free\n", audio->out_tail);
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+			audpreproc_pcm_buffer_ptr_refresh(audio,
+						 audio->out_tail,
+						    frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+ done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+
+static int audevrc_in_fsync(struct file *file, loff_t ppos1, loff_t ppos2, int datasync)
+
+{
+	struct audio_in *audio = file->private_data;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (!audio->running || (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)) {
+		rc = -EINVAL;
+		goto done_nolock;
+	}
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->write_wait,
+			audio->wflush);
+	MM_DBG("waked on by some event audio->wflush = %d\n", audio->wflush);
+
+	if (rc < 0)
+		goto done;
+	else if (audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+done:
+	mutex_unlock(&audio->write_lock);
+done_nolock:
+	return rc;
+
+}
+
+ int audpreproc_evrc_process_eos(struct audio_in *audio,
+		const char __user *buf_start, unsigned short mfield_size)
+{
+	struct buffer *frame;
+	int rc = 0;
+
+	frame = audio->out + audio->out_head;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->out_needed &&
+		audio->out[0].used == 0 &&
+		audio->out[1].used == 0)
+		|| (audio->stopped)
+		|| (audio->wflush));
+
+	if (rc < 0)
+		goto done;
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+	if (copy_from_user(frame->data, buf_start, mfield_size)) {
+		rc = -EFAULT;
+		goto done;
+	}
+
+	frame->mfield_sz = mfield_size;
+	audio->out_head ^= 1;
+	frame->used = mfield_size;
+	MM_DBG("copying meta_out frame->used = %d\n", frame->used);
+	audpreproc_pcm_send_data(audio, 0);
+done:
+	return rc;
+}
+
+static ssize_t audevrc_in_write(struct file *file,
+				const char __user *buf,
+				size_t count, loff_t *pos)
+{
+	struct audio_in *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	char *cpy_ptr;
+	int rc = 0, eos_condition = AUDPREPROC_EVRC_EOS_NONE;
+	unsigned short mfield_size = 0;
+	int write_count = 0;
+	MM_DBG("cnt=%d\n", count);
+
+	if (count & 1)
+		return -EINVAL;
+
+	if (audio->mode != MSM_AUD_ENC_MODE_NONTUNNEL)
+		return -EINVAL;
+
+	mutex_lock(&audio->write_lock);
+	frame = audio->out + audio->out_head;
+	/* if supplied count is more than driver buffer size
+	 * then only copy driver buffer size
+	 */
+	if (count > frame->size)
+		count = frame->size;
+
+	write_count = count;
+	cpy_ptr = frame->data;
+	rc = wait_event_interruptible(audio->write_wait,
+				      (frame->used == 0)
+					|| (audio->stopped)
+					|| (audio->wflush));
+	if (rc < 0)
+		goto error;
+
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto error;
+	}
+	if (audio->mfield) {
+		if (buf == start) {
+			/* Processing beginning of user buffer */
+			if (__get_user(mfield_size,
+				(unsigned short __user *) buf)) {
+				rc = -EFAULT;
+				goto error;
+			} else if (mfield_size > count) {
+				rc = -EINVAL;
+				goto error;
+			}
+			MM_DBG("mf offset_val %x\n", mfield_size);
+			if (copy_from_user(cpy_ptr, buf, mfield_size)) {
+				rc = -EFAULT;
+				goto error;
+			}
+			/* Check if EOS flag is set and buffer has
+			 * contains just meta field
+			 */
+			if (cpy_ptr[AUDPREPROC_EVRC_EOS_FLG_OFFSET] &
+					AUDPREPROC_EVRC_EOS_FLG_MASK) {
+				eos_condition = AUDPREPROC_EVRC_EOS_SET;
+				MM_DBG("EOS SET\n");
+				if (mfield_size == count) {
+					buf += mfield_size;
+					eos_condition = 0;
+					goto exit;
+				} else
+				cpy_ptr[AUDPREPROC_EVRC_EOS_FLG_OFFSET] &=
+					~AUDPREPROC_EVRC_EOS_FLG_MASK;
+			}
+			cpy_ptr += mfield_size;
+			count -= mfield_size;
+			buf += mfield_size;
+		} else {
+			mfield_size = 0;
+			MM_DBG("continuous buffer\n");
+		}
+		frame->mfield_sz = mfield_size;
+	}
+	MM_DBG("copying the stream count = %d\n", count);
+	if (copy_from_user(cpy_ptr, buf, count)) {
+		rc = -EFAULT;
+		goto error;
+	}
+exit:
+	frame->used = count;
+	audio->out_head ^= 1;
+	if (!audio->flush_ack)
+		audpreproc_pcm_send_data(audio, 0);
+	else {
+		audpreproc_pcm_send_data(audio, 1);
+		audio->flush_ack = 0;
+	}
+	if (eos_condition == AUDPREPROC_EVRC_EOS_SET)
+		rc = audpreproc_evrc_process_eos(audio, start, mfield_size);
+	mutex_unlock(&audio->write_lock);
+	return write_count;
+error:
+	mutex_unlock(&audio->write_lock);
+	return rc;
+}
+
+static int audevrc_in_release(struct inode *inode, struct file *file)
+{
+	struct audio_in *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	audio->in_call = 0;
+	/* with draw frequency for session
+	   incase not stopped the driver */
+	msm_snddev_withdraw_freq(audio->enc_id, SNDDEV_CAP_TX,
+					AUDDEV_CLNT_ENC);
+	auddev_unregister_evt_listner(AUDDEV_CLNT_ENC, audio->enc_id);
+	/*reset the sampling frequency information at audpreproc layer*/
+	audio->session_info.sampling_freq = 0;
+	audpreproc_update_audrec_info(&audio->session_info);
+	audevrc_in_disable(audio);
+	audevrc_in_flush(audio);
+	msm_adsp_put(audio->audrec);
+	audpreproc_aenc_free(audio->enc_id);
+	audio->audrec = NULL;
+	audio->opened = 0;
+	if (audio->data) {
+		iounmap(audio->map_v_read);
+		free_contiguous_memory_by_paddr(audio->phys);
+		audio->data = NULL;
+	}
+	if (audio->out_data) {
+		iounmap(audio->map_v_write);
+		free_contiguous_memory_by_paddr(audio->out_phys);
+		audio->out_data = NULL;
+	}
+	mutex_unlock(&audio->lock);
+	return 0;
+}
+
+struct audio_in the_audio_evrc_in;
+static int audevrc_in_open(struct inode *inode, struct file *file)
+{
+	struct audio_in *audio = &the_audio_evrc_in;
+	int rc;
+	int encid;
+
+	mutex_lock(&audio->lock);
+	if (audio->opened) {
+		rc = -EBUSY;
+		goto done;
+	}
+	audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
+	if (audio->phys) {
+		audio->map_v_read = ioremap(audio->phys, DMASZ);
+		if (IS_ERR(audio->map_v_read)) {
+			MM_ERR("failed to map read physical address\n");
+			rc = -ENOMEM;
+			free_contiguous_memory_by_paddr(audio->phys);
+			goto done;
+		}
+		audio->data = audio->map_v_read;
+	} else {
+		MM_ERR("could not allocate DMA buffers\n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	MM_DBG("Memory addr = 0x%8x  phy addr = 0x%8x\n",\
+		(int) audio->data, (int) audio->phys);
+	if ((file->f_mode & FMODE_WRITE) &&
+		(file->f_mode & FMODE_READ)) {
+		audio->mode = MSM_AUD_ENC_MODE_NONTUNNEL;
+		MM_DBG("Opened for non tunnel mode encoding\n");
+	} else if (!(file->f_mode & FMODE_WRITE) &&
+					(file->f_mode & FMODE_READ)) {
+		audio->mode = MSM_AUD_ENC_MODE_TUNNEL;
+		MM_DBG("Opened for tunnel mode encoding\n");
+	} else {
+		MM_ERR("Invalid mode\n");
+		rc = -EACCES;
+		goto done;
+	}
+
+	/* Settings will be re-config at AUDIO_SET_CONFIG,
+	 * but at least we need to have initial config
+	 */
+	if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)
+			audio->buffer_size = (EVRC_FRAME_SIZE + 14);
+	else
+			audio->buffer_size = (FRAME_SIZE - 8);
+	audio->enc_type = ENC_TYPE_EVRC | audio->mode;
+	audio->samp_rate = 8000;
+	audio->channel_mode = AUDREC_CMD_MODE_MONO;
+	audio->cfg.cdma_rate = CDMA_RATE_FULL;
+	audio->cfg.min_bit_rate = CDMA_RATE_FULL;
+	audio->cfg.max_bit_rate = CDMA_RATE_FULL;
+
+	encid = audpreproc_aenc_alloc(audio->enc_type, &audio->module_name,
+			&audio->queue_ids);
+	if (encid < 0) {
+		MM_ERR("No free encoder available\n");
+		rc = -ENODEV;
+		goto done;
+	}
+	audio->enc_id = encid;
+
+	rc = msm_adsp_get(audio->module_name, &audio->audrec,
+			   &audrec_evrc_adsp_ops, audio);
+
+	if (rc) {
+		audpreproc_aenc_free(audio->enc_id);
+		goto done;
+	}
+
+	audio->stopped = 0;
+	audio->source = 0;
+	audio->wflush = 0;
+	audio->rflush = 0;
+	audio->flush_ack = 0;
+
+	audevrc_in_flush(audio);
+	audevrc_out_flush(audio);
+
+	audio->out_phys = allocate_contiguous_ebi_nomap(BUFFER_SIZE,
+								SZ_4K);
+	if (!audio->out_phys) {
+		MM_ERR("could not allocate write buffers\n");
+		rc = -ENOMEM;
+		goto evt_error;
+	} else {
+		audio->map_v_write = ioremap(audio->out_phys, BUFFER_SIZE);
+		if (IS_ERR(audio->map_v_write)) {
+			MM_ERR("could map write buffers\n");
+			rc = -ENOMEM;
+			free_contiguous_memory_by_paddr(audio->out_phys);
+			goto evt_error;
+		}
+		audio->out_data = audio->map_v_write;
+		MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+				audio->out_phys, (int)audio->out_data);
+	}
+
+		/* Initialize buffer */
+	audio->out[0].data = audio->out_data + 0;
+	audio->out[0].addr = audio->out_phys + 0;
+	audio->out[0].size = OUT_BUFFER_SIZE;
+
+	audio->out[1].data = audio->out_data + OUT_BUFFER_SIZE;
+	audio->out[1].addr = audio->out_phys + OUT_BUFFER_SIZE;
+	audio->out[1].size = OUT_BUFFER_SIZE;
+
+	MM_DBG("audio->out[0].data = %d  audio->out[1].data = %d",
+					(unsigned int)audio->out[0].data,
+					(unsigned int)audio->out[1].data);
+	audio->device_events = AUDDEV_EVT_DEV_RDY | AUDDEV_EVT_DEV_RLS |
+				AUDDEV_EVT_VOICE_STATE_CHG;
+
+	audio->voice_state = msm_get_voice_state();
+	rc = auddev_register_evt_listner(audio->device_events,
+					AUDDEV_CLNT_ENC, audio->enc_id,
+					evrc_in_listener, (void *) audio);
+	if (rc) {
+		MM_ERR("failed to register device event listener\n");
+		iounmap(audio->map_v_write);
+		free_contiguous_memory_by_paddr(audio->out_phys);
+		goto evt_error;
+	}
+	audio->mfield = META_OUT_SIZE;
+	file->private_data = audio;
+	audio->opened = 1;
+	audio->out_frame_cnt++;
+	audio->build_id = socinfo_get_build_id();
+	MM_DBG("Modem build id = %s\n", audio->build_id);
+
+done:
+	mutex_unlock(&audio->lock);
+	return rc;
+evt_error:
+	msm_adsp_put(audio->audrec);
+	audpreproc_aenc_free(audio->enc_id);
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static const struct file_operations audio_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audevrc_in_open,
+	.release	= audevrc_in_release,
+	.read		= audevrc_in_read,
+	.write		= audevrc_in_write,
+	.fsync		= audevrc_in_fsync,
+	.unlocked_ioctl	= audevrc_in_ioctl,
+};
+
+struct miscdevice audio_evrc_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_evrc_in",
+	.fops	= &audio_in_fops,
+};
+
+static int __init audevrc_in_init(void)
+{
+	mutex_init(&the_audio_evrc_in.lock);
+	mutex_init(&the_audio_evrc_in.read_lock);
+	spin_lock_init(&the_audio_evrc_in.dsp_lock);
+	spin_lock_init(&the_audio_evrc_in.dev_lock);
+	init_waitqueue_head(&the_audio_evrc_in.wait);
+	init_waitqueue_head(&the_audio_evrc_in.wait_enable);
+	mutex_init(&the_audio_evrc_in.write_lock);
+	init_waitqueue_head(&the_audio_evrc_in.write_wait);
+	return misc_register(&audio_evrc_in_misc);
+}
+
+device_initcall(audevrc_in_init);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_fm.c b/arch/arm/mach-msm/qdsp5v2/audio_fm.c
new file mode 100644
index 0000000..af65c80
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/audio_fm.c
@@ -0,0 +1,358 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * Based on the mp3 native driver in arch/arm/mach-msm/qdsp5v2/audio_mp3.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/android_pmem.h>
+#include <linux/msm_audio.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <mach/msm_adsp.h>
+#include <mach/debug_mm.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/qdsp5v2/afe.h>
+#include <mach/qdsp5v2/acdb_commands.h>
+#include <mach/qdsp5v2/audio_acdbi.h>
+#include <mach/qdsp5v2/audio_acdb_def.h>
+
+#define SESSION_ID_FM 6
+#define FM_ENABLE	0xFFFF
+#define FM_DISABLE	0x0
+#define FM_COPP		0x2
+/* Macro specifies maximum FM routing
+	possible */
+#define FM_MAX_RX_ROUTE	0x2
+
+struct fm_rx_calib_gain {
+	uint16_t device_id;
+	struct auddev_evt_devinfo dev_details;
+	struct  acdb_calib_gain_rx  calib_rx;
+};
+
+struct audio {
+	struct mutex lock;
+
+	int opened;
+	int enabled;
+	int running;
+
+	uint16_t dec_id;
+	uint16_t source;
+	uint16_t fm_source;
+	uint16_t fm_mask;
+	uint32_t device_events;
+	uint16_t volume;
+	struct fm_rx_calib_gain fm_calibration_rx[FM_MAX_RX_ROUTE];
+};
+
+static struct audio fm_audio;
+
+/* must be called with audio->lock held */
+static int audio_enable(struct audio *audio)
+{
+	int rc = 0;
+	if (audio->enabled)
+		return 0;
+
+	MM_DBG("fm mask= %08x fm_source = %08x\n",
+			audio->fm_mask, audio->fm_source);
+	if (audio->fm_mask && audio->fm_source) {
+		rc = afe_config_fm_codec(FM_ENABLE, audio->fm_mask);
+		if (!rc)
+			audio->running = 1;
+		/* Routed to icodec rx path */
+		if ((audio->fm_mask & AFE_HW_PATH_CODEC_RX) ==
+				AFE_HW_PATH_CODEC_RX) {
+			afe_config_fm_calibration_gain(
+			audio->fm_calibration_rx[0].device_id,
+			audio->fm_calibration_rx[0].calib_rx.audppcalgain);
+		}
+		/* Routed to aux codec rx path */
+		if ((audio->fm_mask & AFE_HW_PATH_AUXPCM_RX) ==
+				AFE_HW_PATH_AUXPCM_RX){
+			afe_config_fm_calibration_gain(
+			audio->fm_calibration_rx[1].device_id,
+			audio->fm_calibration_rx[1].calib_rx.audppcalgain);
+		}
+	}
+
+	audio->enabled = 1;
+	return rc;
+}
+
+static void fm_listner(u32 evt_id, union auddev_evt_data *evt_payload,
+			void *private_data)
+{
+	struct audio *audio = (struct audio *) private_data;
+	struct auddev_evt_devinfo *devinfo =
+			(struct auddev_evt_devinfo *)evt_payload;
+	switch (evt_id) {
+	case AUDDEV_EVT_DEV_RDY:
+		MM_DBG(":AUDDEV_EVT_DEV_RDY\n");
+		if (evt_payload->routing_id == FM_COPP)
+			audio->fm_source = 1;
+		else
+			audio->source = (0x1 << evt_payload->routing_id);
+
+		if (audio->source & 0x1)
+			audio->fm_mask = 0x1;
+		else if (audio->source & 0x2)
+			audio->fm_mask = 0x3;
+		else
+			audio->fm_mask = 0x0;
+
+		if (!audio->enabled
+			|| !audio->fm_mask
+			|| !audio->fm_source)
+			break;
+		else {
+			afe_config_fm_codec(FM_ENABLE, audio->fm_mask);
+			audio->running = 1;
+		}
+		break;
+	case AUDDEV_EVT_DEV_RLS:
+		MM_DBG(":AUDDEV_EVT_DEV_RLS\n");
+		if (evt_payload->routing_id == FM_COPP)
+			audio->fm_source = 0;
+		else
+			audio->source &= ~(0x1 << evt_payload->routing_id);
+
+		if (audio->source & 0x1)
+			audio->fm_mask = 0x1;
+		else if (audio->source & 0x2)
+			audio->fm_mask = 0x3;
+		else
+			audio->fm_mask = 0x0;
+
+		if (audio->running
+			&& (!audio->fm_mask || !audio->fm_source)) {
+			afe_config_fm_codec(FM_DISABLE, audio->fm_mask);
+			audio->running = 0;
+		}
+		break;
+	case AUDDEV_EVT_STREAM_VOL_CHG:
+		MM_DBG(":AUDDEV_EVT_STREAM_VOL_CHG, stream vol \n");
+		audio->volume = evt_payload->session_vol;
+		afe_config_fm_volume(audio->volume);
+		break;
+	case AUDDEV_EVT_DEVICE_INFO:{
+		struct acdb_get_block get_block;
+		int rc = 0;
+		MM_DBG(":AUDDEV_EVT_DEVICE_INFO\n");
+		MM_DBG("sample_rate = %d\n", devinfo->sample_rate);
+		MM_DBG("acdb_id = %d\n", devinfo->acdb_id);
+		/* Applucable only for icodec rx and aux codec rx path
+			and fm stream routed to it */
+		if (((devinfo->dev_id == 0x00) || (devinfo->dev_id == 0x01)) &&
+			(devinfo->sessions && (1 << audio->dec_id))) {
+			/* Query ACDB driver for calib gain, only if difference
+				in device */
+			if ((audio->fm_calibration_rx[devinfo->dev_id].
+				dev_details.acdb_id != devinfo->acdb_id) ||
+				(audio->fm_calibration_rx[devinfo->dev_id].
+				dev_details.sample_rate !=
+					devinfo->sample_rate)) {
+				audio->fm_calibration_rx[devinfo->dev_id].
+					dev_details.dev_id = devinfo->dev_id;
+				audio->fm_calibration_rx[devinfo->dev_id].
+					dev_details.sample_rate =
+						devinfo->sample_rate;
+				audio->fm_calibration_rx[devinfo->dev_id].
+					dev_details.dev_type =
+						devinfo->dev_type;
+				audio->fm_calibration_rx[devinfo->dev_id].
+					dev_details.sessions =
+						devinfo->sessions;
+				/* Query ACDB driver for calibration gain */
+				get_block.acdb_id = devinfo->acdb_id;
+				get_block.sample_rate_id = devinfo->sample_rate;
+				get_block.interface_id =
+					IID_AUDIO_CALIBRATION_GAIN_RX;
+				get_block.algorithm_block_id =
+					ABID_AUDIO_CALIBRATION_GAIN_RX;
+				get_block.total_bytes =
+					sizeof(struct  acdb_calib_gain_rx);
+				get_block.buf_ptr = (u32 *)
+				&audio->fm_calibration_rx[devinfo->dev_id].
+				calib_rx;
+
+				rc = acdb_get_calibration_data(&get_block);
+				if (rc < 0) {
+					MM_ERR("Unable to get calibration"\
+						"gain\n");
+					/* Set to unity incase of error */
+					audio->\
+					fm_calibration_rx[devinfo->dev_id].
+					calib_rx.audppcalgain = 0x2000;
+				} else
+					MM_DBG("calibration gain = 0x%8x\n",
+						*(get_block.buf_ptr));
+			}
+			if (audio->running) {
+				afe_config_fm_calibration_gain(
+				audio->fm_calibration_rx[devinfo->dev_id].
+					device_id,
+				audio->fm_calibration_rx[devinfo->dev_id].
+					calib_rx.audppcalgain);
+				}
+			}
+		break;
+	}
+	default:
+		MM_DBG(":ERROR:wrong event\n");
+		break;
+	}
+}
+/* must be called with audio->lock held */
+static int audio_disable(struct audio *audio)
+{
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	return afe_config_fm_codec(FM_DISABLE, audio->source);
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = -EINVAL;
+
+	MM_DBG("cmd = %d\n", cmd);
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		MM_DBG("AUDIO_START\n");
+		rc = audio_enable(audio);
+		break;
+	case AUDIO_STOP:
+		MM_DBG("AUDIO_STOP\n");
+		rc = audio_disable(audio);
+		audio->running = 0;
+		audio->enabled = 0;
+		break;
+	case AUDIO_GET_SESSION_ID:
+		if (copy_to_user((void *) arg, &audio->dec_id,
+					sizeof(unsigned short)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	MM_DBG("audio instance 0x%08x freeing\n", (int)audio);
+	mutex_lock(&audio->lock);
+	auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->dec_id);
+	audio_disable(audio);
+	audio->running = 0;
+	audio->enabled = 0;
+	audio->opened = 0;
+	mutex_unlock(&audio->lock);
+	return 0;
+}
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = &fm_audio;
+	int rc = 0;
+
+
+	if (audio->opened)
+		return -EPERM;
+
+	/* Allocate the decoder */
+	audio->dec_id = SESSION_ID_FM;
+
+	audio->running = 0;
+	audio->fm_source = 0;
+	audio->fm_mask = 0;
+
+	/* Initialize the calibration gain structure */
+	audio->fm_calibration_rx[0].device_id = AFE_HW_PATH_CODEC_RX;
+	audio->fm_calibration_rx[1].device_id = AFE_HW_PATH_AUXPCM_RX;
+	audio->fm_calibration_rx[0].calib_rx.audppcalgain = 0x2000;
+	audio->fm_calibration_rx[1].calib_rx.audppcalgain = 0x2000;
+	audio->fm_calibration_rx[0].dev_details.acdb_id = PSEUDO_ACDB_ID;
+	audio->fm_calibration_rx[1].dev_details.acdb_id = PSEUDO_ACDB_ID;
+
+	audio->device_events = AUDDEV_EVT_DEV_RDY
+				|AUDDEV_EVT_DEV_RLS|
+				AUDDEV_EVT_STREAM_VOL_CHG|
+				AUDDEV_EVT_DEVICE_INFO;
+
+	rc = auddev_register_evt_listner(audio->device_events,
+					AUDDEV_CLNT_DEC,
+					audio->dec_id,
+					fm_listner,
+					(void *)audio);
+
+	if (rc) {
+		MM_ERR("%s: failed to register listnet\n", __func__);
+		goto event_err;
+	}
+
+	audio->opened = 1;
+	file->private_data = audio;
+
+event_err:
+	return rc;
+}
+
+static const struct file_operations audio_fm_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audio_open,
+	.release	= audio_release,
+	.unlocked_ioctl	= audio_ioctl,
+};
+
+struct miscdevice audio_fm_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_fm",
+	.fops	= &audio_fm_fops,
+};
+
+static int __init audio_init(void)
+{
+	struct audio *audio = &fm_audio;
+
+	mutex_init(&audio->lock);
+	return misc_register(&audio_fm_misc);
+}
+
+device_initcall(audio_init);
+
+MODULE_DESCRIPTION("MSM FM driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_interct.c b/arch/arm/mach-msm/qdsp5v2/audio_interct.c
new file mode 100644
index 0000000..785ed8e
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/audio_interct.c
@@ -0,0 +1,124 @@
+/* Copyright (c) 2009, 2011 Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <asm/io.h>
+#include <mach/qdsp5v2/audio_interct.h>
+
+#define AUDIO_INTERCT_ADSPLPA_WBRX_SEL_BMSK 0x4
+#define AUDIO_INTERCT_ADSPLPA_WBRX_SEL_SHFT 0x2
+#define AUDIO_INTERCT_ADSPAV_RPCMI2SRX_SEL_BMSK 0x10
+#define AUDIO_INTERCT_ADSPAV_RPCMI2SRX_SEL_SHFT 0x4
+#define AUDIO_INTERCT_ADSPAV_TPCMI2STX_SEL_BMSK 0x40
+#define AUDIO_INTERCT_ADSPAV_TPCMI2STX_SEL_SHFT 0x6
+#define AUDIO_INTERCT_ADSPAV_AUX_REGSEL_BMSK 0x100
+#define AUDIO_INTERCT_ADSPAV_AUX_REGSEL_SHFT 0x8
+
+/* Should look to protect this register */
+void __iomem *aictl_reg;
+
+void audio_interct_codec(u32 source)
+{
+	u32 reg_val;
+
+	reg_val = readl(aictl_reg);
+	reg_val = (reg_val & ~AUDIO_INTERCT_ADSPLPA_WBRX_SEL_BMSK) |
+		(source << AUDIO_INTERCT_ADSPLPA_WBRX_SEL_SHFT);
+	writel(reg_val, aictl_reg);
+	mb();
+}
+EXPORT_SYMBOL(audio_interct_codec);
+
+void audio_interct_aux_regsel(u32 source)
+{
+	u32 reg_val;
+
+	reg_val = readl(aictl_reg);
+	reg_val = (reg_val & ~AUDIO_INTERCT_ADSPAV_AUX_REGSEL_BMSK) |
+		(source << AUDIO_INTERCT_ADSPAV_AUX_REGSEL_SHFT);
+	writel(reg_val, aictl_reg);
+	mb();
+}
+EXPORT_SYMBOL(audio_interct_aux_regsel);
+
+void audio_interct_tpcm_source(u32 source)
+{
+	u32 reg_val;
+
+	reg_val = readl(aictl_reg);
+	reg_val = (reg_val & ~AUDIO_INTERCT_ADSPAV_TPCMI2STX_SEL_BMSK) |
+		(source << AUDIO_INTERCT_ADSPAV_TPCMI2STX_SEL_SHFT);
+	writel(reg_val, aictl_reg);
+	mb();
+}
+EXPORT_SYMBOL(audio_interct_tpcm_source);
+
+void audio_interct_rpcm_source(u32 source)
+{
+	u32 reg_val;
+
+	reg_val = readl(aictl_reg);
+	reg_val = (reg_val & ~AUDIO_INTERCT_ADSPAV_RPCMI2SRX_SEL_BMSK) |
+		(source << AUDIO_INTERCT_ADSPAV_RPCMI2SRX_SEL_SHFT);
+	writel(reg_val, aictl_reg);
+	mb();
+}
+EXPORT_SYMBOL(audio_interct_rpcm_source);
+
+static int audio_interct_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct resource *aictl_mem;
+
+	aictl_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!aictl_mem) {
+		rc = -ENODEV;
+		goto error;
+	}
+	aictl_reg = ioremap(aictl_mem->start,
+			(aictl_mem->end - aictl_mem->start) + 1);
+error:
+	return rc;
+}
+
+
+static int audio_interct_remove(struct platform_device *pdev)
+{
+	iounmap(aictl_reg);
+	return 0;
+}
+
+static struct platform_driver audio_interct_driver = {
+	.probe = audio_interct_probe,
+	.remove = audio_interct_remove,
+	.driver = {
+		.name = "audio_interct",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init audio_interct_init(void)
+{
+	return platform_driver_register(&audio_interct_driver);
+}
+
+static void __exit audio_interct_exit(void)
+{
+	platform_driver_unregister(&audio_interct_driver);
+}
+
+module_init(audio_interct_init);
+module_exit(audio_interct_exit);
+
+MODULE_DESCRIPTION("MSM Audio Interconnect driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_lpa.c b/arch/arm/mach-msm/qdsp5v2/audio_lpa.c
new file mode 100644
index 0000000..d5fb2e9
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/audio_lpa.c
@@ -0,0 +1,1748 @@
+/* low power audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2011-2012, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/earlysuspend.h>
+#include <linux/list.h>
+#include <linux/android_pmem.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <mach/msm_adsp.h>
+#include <linux/slab.h>
+#include <linux/msm_audio.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+
+#include <mach/qdsp5v2/qdsp5audppmsg.h>
+#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
+#include <mach/qdsp5v2/qdsp5audplaymsg.h>
+#include <mach/qdsp5v2/audpp.h>
+#include <mach/qdsp5v2/codec_utils.h>
+#include <mach/qdsp5v2/mp3_funcs.h>
+#include <mach/qdsp5v2/pcm_funcs.h>
+#include <mach/debug_mm.h>
+
+#define ADRV_STATUS_AIO_INTF 0x00000001
+#define ADRV_STATUS_OBUF_GIVEN 0x00000002
+#define ADRV_STATUS_IBUF_GIVEN 0x00000004
+#define ADRV_STATUS_FSYNC 0x00000008
+#define ADRV_STATUS_PAUSE 0x00000010
+
+#define DEVICE_SWITCH_STATE_NONE     0
+#define DEVICE_SWITCH_STATE_PENDING  1
+#define DEVICE_SWITCH_STATE_READY    2
+#define DEVICE_SWITCH_STATE_COMPLETE 3
+
+#define AUDDEC_DEC_PCM 0
+#define AUDDEC_DEC_MP3 2
+
+#define PCM_BUFSZ_MIN 4800	/* Hold one stereo MP3 frame */
+
+/* Decoder status received from AUDPPTASK */
+#define  AUDPP_DEC_STATUS_SLEEP	0
+#define	 AUDPP_DEC_STATUS_INIT  1
+#define  AUDPP_DEC_STATUS_CFG   2
+#define  AUDPP_DEC_STATUS_PLAY  3
+
+#define AUDMP3_METAFIELD_MASK 0xFFFF0000
+#define AUDMP3_EOS_FLG_OFFSET 0x0A /* Offset from beginning of buffer */
+#define AUDMP3_EOS_FLG_MASK 0x01
+#define AUDMP3_EOS_NONE 0x0 /* No EOS detected */
+#define AUDMP3_EOS_SET 0x1 /* EOS set in meta field */
+
+#define AUDLPA_EVENT_NUM 10 /* Default number of pre-allocated event packets */
+
+#define MASK_32BITS     0xFFFFFFFF
+
+#define MAX_BUF 4
+#define BUFSZ (524288)
+
+#define __CONTAINS(r, v, l) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __v = v;					\
+	typeof(v) __e = __v + l;				\
+	int res = ((__v >= __r->vaddr) && 			\
+		(__e <= __r->vaddr + __r->len));		\
+	res;							\
+})
+
+#define CONTAINS(r1, r2) ({					\
+	typeof(r2) __r2 = r2;					\
+	__CONTAINS(r1, __r2->vaddr, __r2->len);			\
+})
+
+#define IN_RANGE(r, v) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __vv = v;					\
+	int res = ((__vv >= __r->vaddr) &&			\
+		(__vv < (__r->vaddr + __r->len)));		\
+	res;							\
+})
+
+#define OVERLAPS(r1, r2) ({					\
+	typeof(r1) __r1 = r1;					\
+	typeof(r2) __r2 = r2;					\
+	typeof(__r2->vaddr) __v = __r2->vaddr;			\
+	typeof(__v) __e = __v + __r2->len - 1;			\
+	int res = (IN_RANGE(__r1, __v) || IN_RANGE(__r1, __e));	\
+	res;							\
+})
+
+/* payload[7]; -1 indicates error, 0 indicates no error */
+#define CHECK_ERROR(v) (!v[7])
+
+/* calculates avsync_info from payload */
+#define CALCULATE_AVSYNC_FROM_PAYLOAD(v) ((uint64_t)((((uint64_t)v[10]) \
+					<< 32) | (v[11] & MASK_32BITS)))
+
+/* calculates avsync_info from avsync_info stored in audio */
+#define CALCULATE_AVSYNC(v)					   \
+			((uint64_t)((((uint64_t)v[4]) << 32) | 	   \
+			 (v[5] << 16) | (v[6])))
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct audlpa_suspend_ctl {
+	struct early_suspend node;
+	struct audio *audio;
+};
+#endif
+
+struct audlpa_event {
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+
+struct audlpa_pmem_region {
+	struct list_head list;
+	struct file *file;
+	int fd;
+	void *vaddr;
+	unsigned long paddr;
+	unsigned long kvaddr;
+	unsigned long len;
+	unsigned ref_cnt;
+};
+
+struct audlpa_buffer_node {
+	struct list_head list;
+	struct msm_audio_aio_buf buf;
+	unsigned long paddr;
+};
+
+struct audlpa_dec {
+	char *name;
+	int dec_attrb;
+	long (*ioctl)(struct file *, unsigned int, unsigned long);
+	void (*adec_params)(struct audio *);
+};
+
+struct audlpa_dec audlpa_decs[] = {
+	{"msm_mp3_lp", AUDDEC_DEC_MP3, &mp3_ioctl, &audpp_cmd_cfg_mp3_params},
+	{"msm_pcm_lp_dec", AUDDEC_DEC_PCM, &pcm_ioctl,
+		&audpp_cmd_cfg_pcm_params},
+};
+
+static int auddec_dsp_config(struct audio *audio, int enable);
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
+static void audlpa_post_event(struct audio *audio, int type,
+	union msm_audio_event_payload payload);
+static unsigned long audlpa_pmem_fixup(struct audio *audio, void *addr,
+				unsigned long len, int ref_up);
+static void audlpa_async_send_data(struct audio *audio, unsigned needed,
+				uint32_t *payload);
+
+static void lpa_listner(u32 evt_id, union auddev_evt_data *evt_payload,
+			void *private_data)
+{
+	struct audio *audio = (struct audio *) private_data;
+	switch (evt_id) {
+	case AUDDEV_EVT_DEV_RDY:
+		MM_DBG(":AUDDEV_EVT_DEV_RDY routing id = %d\n",
+		evt_payload->routing_id);
+		/* Do not select HLB path for icodec, if there is already COPP3
+		 * routing exists. DSP can not support concurrency of HLB path
+		 * and COPP3 routing as it involves different buffer Path */
+		if (((0x1 << evt_payload->routing_id) == AUDPP_MIXER_ICODEC) &&
+			!(audio->source & AUDPP_MIXER_3)) {
+			audio->source |= AUDPP_MIXER_HLB;
+			MM_DBG("mixer_mask modified for low-power audio\n");
+		} else
+			audio->source |= (0x1 << evt_payload->routing_id);
+
+		MM_DBG("running = %d, enabled = %d, source = 0x%x\n",
+			audio->running, audio->enabled, audio->source);
+		if (audio->running == 1 && audio->enabled == 1) {
+			audpp_route_stream(audio->dec_id, audio->source);
+			if (audio->source & AUDPP_MIXER_HLB) {
+				audpp_dsp_set_vol_pan(
+					AUDPP_CMD_CFG_DEV_MIXER_ID_4,
+					&audio->vol_pan,
+					COPP);
+					/*restore the POPP gain to 0x2000
+					this is needed to avoid use cases
+					where POPP volume is lowered during
+					NON HLB playback, when device moved
+					from NON HLB to HLB POPP is not
+					disabled but POPP gain will be retained
+					as the old one which result
+					in lower volume*/
+					audio->vol_pan.volume = 0x2000;
+					audpp_dsp_set_vol_pan(
+						audio->dec_id,
+						&audio->vol_pan, POPP);
+			} else if (audio->source & AUDPP_MIXER_NONHLB)
+				audpp_dsp_set_vol_pan(
+					audio->dec_id, &audio->vol_pan, POPP);
+			if (audio->device_switch == DEVICE_SWITCH_STATE_READY) {
+				audio->wflush = 1;
+				audio->device_switch =
+					DEVICE_SWITCH_STATE_COMPLETE;
+				audpp_flush(audio->dec_id);
+				if (wait_event_interruptible(audio->write_wait,
+							 !audio->wflush) < 0)
+					MM_DBG("AUDIO_FLUSH interrupted\n");
+
+				if (audio->wflush == 0) {
+					if (audio->drv_status &
+						ADRV_STATUS_PAUSE) {
+						if (audpp_pause(audio->dec_id,
+							1))
+							MM_DBG("audpp_pause"
+								"failed\n");
+					}
+				}
+			}
+		}
+		break;
+	case AUDDEV_EVT_REL_PENDING:
+		MM_DBG(":AUDDEV_EVT_REL_PENDING\n");
+		/* If route to multiple devices like COPP3, not need to
+		 * handle device switch */
+		if ((audio->running == 1) && (audio->enabled == 1) &&
+			!(audio->source & AUDPP_MIXER_3)) {
+			if (audio->device_switch == DEVICE_SWITCH_STATE_NONE) {
+				if (!(audio->drv_status & ADRV_STATUS_PAUSE)) {
+					if (audpp_pause(audio->dec_id, 1))
+						MM_DBG("audpp pause failed\n");
+				}
+				audio->device_switch =
+					DEVICE_SWITCH_STATE_PENDING;
+				audio->avsync_flag = 0;
+				if (audpp_query_avsync(audio->dec_id) < 0)
+					MM_DBG("query avsync failed\n");
+
+				if (wait_event_interruptible_timeout
+					(audio->avsync_wait, audio->avsync_flag,
+				 msecs_to_jiffies(AVSYNC_EVENT_TIMEOUT)) < 0)
+					MM_DBG("AV sync timeout failed\n");
+				if (audio->avsync_flag == 1) {
+					if (audio->device_switch ==
+						DEVICE_SWITCH_STATE_PENDING)
+						audio->device_switch =
+						DEVICE_SWITCH_STATE_READY;
+				}
+			}
+		}
+		break;
+	case AUDDEV_EVT_DEV_RLS:
+		/* If there is already COPP3 routing exists. icodec route
+		 * was not having HLB path. */
+		MM_DBG(":AUDDEV_EVT_DEV_RLS routing id = %d\n",
+			evt_payload->routing_id);
+		if (((0x1 << evt_payload->routing_id) == AUDPP_MIXER_ICODEC) &&
+			!(audio->source & AUDPP_MIXER_3))
+			audio->source &= ~AUDPP_MIXER_HLB;
+		else
+			audio->source &= ~(0x1 << evt_payload->routing_id);
+		MM_DBG("running = %d, enabled = %d, source = 0x%x\n",
+			audio->running, audio->enabled, audio->source);
+
+		if (audio->running == 1 && audio->enabled == 1)
+			audpp_route_stream(audio->dec_id, audio->source);
+		break;
+	case AUDDEV_EVT_STREAM_VOL_CHG:
+		audio->vol_pan.volume = evt_payload->session_vol;
+		MM_DBG("\n:AUDDEV_EVT_STREAM_VOL_CHG, stream vol %d\n"
+			"running = %d, enabled = %d, source = 0x%x",
+			audio->vol_pan.volume, audio->running,
+			audio->enabled, audio->source);
+		if (audio->running == 1 && audio->enabled == 1) {
+			if (audio->source & AUDPP_MIXER_HLB)
+				audpp_dsp_set_vol_pan(
+					AUDPP_CMD_CFG_DEV_MIXER_ID_4,
+					&audio->vol_pan, COPP);
+			else if (audio->source & AUDPP_MIXER_NONHLB)
+				audpp_dsp_set_vol_pan(
+					audio->dec_id, &audio->vol_pan, POPP);
+		}
+		break;
+	default:
+		MM_ERR(":ERROR:wrong event\n");
+		break;
+	}
+}
+
+/* must be called with audio->lock held */
+static int audio_enable(struct audio *audio)
+{
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	if (audio->enabled)
+		return 0;
+
+	audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+	audio->out_needed = 0;
+
+	if (msm_adsp_enable(audio->audplay)) {
+		MM_ERR("msm_adsp_enable(audplay) failed\n");
+		return -ENODEV;
+	}
+
+	if (audpp_enable(audio->dec_id, audio_dsp_event, audio)) {
+		MM_ERR("audpp_enable() failed\n");
+		msm_adsp_disable(audio->audplay);
+		return -ENODEV;
+	}
+
+	audio->enabled = 1;
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audio_disable(struct audio *audio)
+{
+	int rc = 0;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+		auddec_dsp_config(audio, 0);
+		rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+		else if (audio->dec_state != MSM_AUD_DECODER_STATE_CLOSE)
+			rc = -EFAULT;
+		else
+			rc = 0;
+		wake_up(&audio->write_wait);
+		msm_adsp_disable(audio->audplay);
+		audpp_disable(audio->dec_id, audio);
+		audio->out_needed = 0;
+	}
+	return rc;
+}
+
+/* ------------------- dsp --------------------- */
+static void audplay_dsp_event(void *data, unsigned id, size_t len,
+			      void (*getevent) (void *ptr, size_t len))
+{
+	struct audio *audio = data;
+	uint32_t msg[28];
+	getevent(msg, sizeof(msg));
+
+	MM_DBG("msg_id=%x\n", id);
+
+	switch (id) {
+	case AUDPLAY_MSG_DEC_NEEDS_DATA:
+		audlpa_async_send_data(audio, 1, msg);
+		break;
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audplaytask)\n");
+		break;
+	default:
+		MM_ERR("unexpected message from decoder\n");
+		break;
+	}
+}
+
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned status = msg[1];
+
+			switch (status) {
+			case AUDPP_DEC_STATUS_SLEEP: {
+				uint16_t reason = msg[2];
+				MM_DBG("decoder status: sleep reason=0x%04x\n",
+						reason);
+				if ((reason == AUDPP_MSG_REASON_MEM)
+					|| (reason ==
+					AUDPP_MSG_REASON_NODECODER)) {
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_FAILURE;
+					wake_up(&audio->wait);
+				} else if (reason == AUDPP_MSG_REASON_NONE) {
+					/* decoder is in disable state */
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_CLOSE;
+					wake_up(&audio->wait);
+				}
+				break;
+			}
+			case AUDPP_DEC_STATUS_INIT:
+				MM_DBG("decoder status: init\n");
+				audio->codec_ops.adec_params(audio);
+				break;
+			case AUDPP_DEC_STATUS_CFG:
+				MM_DBG("decoder status: cfg\n");
+				break;
+			case AUDPP_DEC_STATUS_PLAY:
+				MM_DBG("decoder status: play\n");
+				/* send  mixer command */
+				audpp_route_stream(audio->dec_id,
+						audio->source);
+				audio->dec_state =
+					MSM_AUD_DECODER_STATE_SUCCESS;
+				wake_up(&audio->wait);
+				break;
+			case AUDPP_DEC_STATUS_EOS:
+				MM_DBG("decoder status: EOS\n");
+				audio->teos = 1;
+				wake_up(&audio->write_wait);
+				break;
+			default:
+				MM_ERR("unknown decoder status\n");
+				break;
+			}
+			break;
+		}
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			MM_DBG("CFG_MSG ENABLE\n");
+			auddec_dsp_config(audio, 1);
+			audio->out_needed = 0;
+			audio->running = 1;
+			MM_DBG("source = 0x%x\n", audio->source);
+			if (audio->source & AUDPP_MIXER_HLB)
+				audpp_dsp_set_vol_pan(
+					AUDPP_CMD_CFG_DEV_MIXER_ID_4,
+					&audio->vol_pan,
+					COPP);
+			else if (audio->source & AUDPP_MIXER_NONHLB)
+				audpp_dsp_set_vol_pan(
+					audio->dec_id, &audio->vol_pan,
+					POPP);
+			audpp_dsp_set_eq(audio->dec_id, audio->eq_enable,
+					&audio->eq, POPP);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			MM_DBG("CFG_MSG DISABLE\n");
+			audio->running = 0;
+		} else {
+			MM_DBG("CFG_MSG %d?\n", msg[0]);
+		}
+		break;
+	case AUDPP_MSG_ROUTING_ACK:
+		MM_DBG("ROUTING_ACK mode=%d\n",	msg[1]);
+		audio->codec_ops.adec_params(audio);
+		break;
+
+	case AUDPP_MSG_FLUSH_ACK:
+		MM_DBG("FLUSH_ACK\n");
+		audio->wflush = 0;
+		wake_up(&audio->write_wait);
+		break;
+
+	case AUDPP_MSG_PCMDMAMISSED:
+		MM_DBG("PCMDMAMISSED\n");
+		wake_up(&audio->write_wait);
+		break;
+
+	case AUDPP_MSG_AVSYNC_MSG:
+		MM_DBG("AVSYNC_MSG\n");
+		memcpy(&audio->avsync[0], msg, sizeof(audio->avsync));
+		audio->avsync_flag = 1;
+		wake_up(&audio->avsync_wait);
+		break;
+
+	default:
+		MM_ERR("UNKNOWN (%d)\n", id);
+	}
+
+}
+
+struct msm_adsp_ops audplay_adsp_ops_lpa = {
+	.event = audplay_dsp_event,
+};
+
+#define audplay_send_queue0(audio, cmd, len) \
+	msm_adsp_write(audio->audplay, audio->queue_id, \
+			cmd, len)
+
+static int auddec_dsp_config(struct audio *audio, int enable)
+{
+	struct audpp_cmd_cfg_dec_type cfg_dec_cmd;
+
+	memset(&cfg_dec_cmd, 0, sizeof(cfg_dec_cmd));
+
+	cfg_dec_cmd.cmd_id = AUDPP_CMD_CFG_DEC_TYPE;
+	if (enable)
+		cfg_dec_cmd.dec_cfg = AUDPP_CMD_UPDATDE_CFG_DEC |
+			AUDPP_CMD_ENA_DEC_V |
+			audlpa_decs[audio->minor_no].dec_attrb;
+	else
+		cfg_dec_cmd.dec_cfg = AUDPP_CMD_UPDATDE_CFG_DEC |
+				AUDPP_CMD_DIS_DEC_V;
+	cfg_dec_cmd.dm_mode = 0x0;
+	cfg_dec_cmd.stream_id = audio->dec_id;
+	return audpp_send_queue1(&cfg_dec_cmd, sizeof(cfg_dec_cmd));
+}
+
+static void audlpa_async_send_buffer(struct audio *audio)
+{
+	int	found = 0;
+	uint64_t temp = 0;
+	struct audplay_cmd_bitstream_data_avail cmd;
+	struct audlpa_buffer_node *next_buf = NULL;
+
+	temp = audio->bytecount_head;
+	if (audio->device_switch == DEVICE_SWITCH_STATE_NONE) {
+		list_for_each_entry(next_buf, &audio->out_queue, list) {
+			if (temp == audio->bytecount_given) {
+				found = 1;
+				break;
+			} else
+				temp += next_buf->buf.data_len;
+		}
+		if (next_buf && found) {
+			cmd.cmd_id = AUDPLAY_CMD_BITSTREAM_DATA_AVAIL;
+			cmd.decoder_id = audio->dec_id;
+			cmd.buf_ptr	= (unsigned) next_buf->paddr;
+			cmd.buf_size = next_buf->buf.data_len >> 1;
+			cmd.partition_number	= 0;
+			audio->bytecount_given += next_buf->buf.data_len;
+			wmb();
+			audplay_send_queue0(audio, &cmd, sizeof(cmd));
+			audio->out_needed = 0;
+			audio->drv_status |= ADRV_STATUS_OBUF_GIVEN;
+		}
+	} else if (audio->device_switch == DEVICE_SWITCH_STATE_COMPLETE) {
+		audio->device_switch = DEVICE_SWITCH_STATE_NONE;
+		next_buf = list_first_entry(&audio->out_queue,
+					struct audlpa_buffer_node, list);
+		if (next_buf) {
+			cmd.cmd_id = AUDPLAY_CMD_BITSTREAM_DATA_AVAIL;
+			cmd.decoder_id = audio->dec_id;
+			temp = audio->bytecount_head +
+				next_buf->buf.data_len -
+				audio->bytecount_consumed;
+			if (audpp_restore_avsync(audio->dec_id,
+						&audio->avsync[0]))
+				MM_DBG("audpp_restore_avsync failed\n");
+
+			if ((signed)(temp >= 0) &&
+			((signed)(next_buf->buf.data_len - temp) >= 0)) {
+				MM_DBG("audlpa_async_send_buffer - sending the"
+					"rest of the buffer bassedon AV sync");
+				cmd.buf_ptr	= (unsigned) (next_buf->paddr +
+						  (next_buf->buf.data_len -
+						   temp));
+				cmd.buf_size = temp >> 1;
+				cmd.partition_number	= 0;
+				audio->bytecount_given =
+					audio->bytecount_consumed + temp;
+				wmb();
+				audplay_send_queue0(audio, &cmd, sizeof(cmd));
+				audio->out_needed = 0;
+				audio->drv_status |= ADRV_STATUS_OBUF_GIVEN;
+			} else if ((signed)(temp >= 0) &&
+				((signed)(next_buf->buf.data_len -
+							temp) < 0)) {
+				MM_DBG("audlpa_async_send_buffer - else case:"
+					"sending the rest of the buffer bassedon"
+					"AV sync");
+				cmd.buf_ptr	= (unsigned) next_buf->paddr;
+				cmd.buf_size = next_buf->buf.data_len >> 1;
+				cmd.partition_number	= 0;
+				audio->bytecount_given = audio->bytecount_head +
+					next_buf->buf.data_len;
+				wmb();
+				audplay_send_queue0(audio, &cmd, sizeof(cmd));
+				audio->out_needed = 0;
+				audio->drv_status |= ADRV_STATUS_OBUF_GIVEN;
+			}
+		}
+	}
+}
+
+static void audlpa_async_send_data(struct audio *audio, unsigned needed,
+				uint32_t *payload)
+{
+	unsigned long flags;
+	uint64_t temp = 0;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (needed && !audio->wflush) {
+		audio->out_needed = 1;
+		if (audio->drv_status & ADRV_STATUS_OBUF_GIVEN) {
+			union msm_audio_event_payload evt_payload;
+			struct audlpa_buffer_node *used_buf = NULL;
+
+			if (CHECK_ERROR(payload))
+				audio->bytecount_consumed =
+					CALCULATE_AVSYNC_FROM_PAYLOAD(payload);
+
+			if ((audio->device_switch ==
+				DEVICE_SWITCH_STATE_COMPLETE) &&
+				(audio->avsync_flag == 1)) {
+				audio->avsync_flag = 0;
+				audio->bytecount_consumed =
+					CALCULATE_AVSYNC(audio->avsync);
+			}
+			BUG_ON(list_empty(&audio->out_queue));
+			temp = audio->bytecount_head;
+			used_buf = list_first_entry(&audio->out_queue,
+					struct audlpa_buffer_node, list);
+			if (audio->device_switch !=
+				DEVICE_SWITCH_STATE_COMPLETE) {
+				audio->bytecount_head +=
+						used_buf->buf.data_len;
+				temp = audio->bytecount_head;
+				list_del(&used_buf->list);
+				evt_payload.aio_buf = used_buf->buf;
+				audlpa_post_event(audio,
+						AUDIO_EVENT_WRITE_DONE,
+						  evt_payload);
+				kfree(used_buf);
+				audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
+			}
+		}
+	}
+	if (audio->out_needed) {
+		if (!list_empty(&audio->out_queue))
+			audlpa_async_send_buffer(audio);
+	}
+done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+static void audlpa_async_flush(struct audio *audio)
+{
+	struct audlpa_buffer_node *buf_node;
+	struct list_head *ptr, *next;
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	list_for_each_safe(ptr, next, &audio->out_queue) {
+		buf_node = list_entry(ptr, struct audlpa_buffer_node, list);
+		list_del(&buf_node->list);
+		payload.aio_buf = buf_node->buf;
+		if ((buf_node->paddr != 0xFFFFFFFF) &&
+			(buf_node->buf.data_len != 0))
+			audlpa_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+							  payload);
+		kfree(buf_node);
+	}
+	audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
+	audio->out_needed = 0;
+	audio->bytecount_consumed = 0;
+	audio->bytecount_head = 0;
+	audio->bytecount_given = 0;
+	audio->device_switch = DEVICE_SWITCH_STATE_NONE;
+	atomic_set(&audio->out_bytes, 0);
+}
+
+static void audio_ioport_reset(struct audio *audio)
+{
+	/* If fsync is in progress, make sure
+	 * return value of fsync indicates
+	 * abort due to flush
+	 */
+	if (audio->drv_status & ADRV_STATUS_FSYNC) {
+		MM_DBG("fsync in progress\n");
+		wake_up(&audio->write_wait);
+		mutex_lock(&audio->write_lock);
+		audlpa_async_flush(audio);
+		mutex_unlock(&audio->write_lock);
+		audio->avsync_flag = 1;
+		wake_up(&audio->avsync_wait);
+	} else
+		audlpa_async_flush(audio);
+}
+
+static int audlpa_events_pending(struct audio *audio)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	return empty || audio->event_abort;
+}
+
+static void audlpa_reset_event_queue(struct audio *audio)
+{
+	unsigned long flags;
+	struct audlpa_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+			struct audlpa_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+			struct audlpa_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	return;
+}
+
+static long audlpa_process_event_req(struct audio *audio, void __user *arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audlpa_event *drv_evt = NULL;
+	int timeout;
+	unsigned long flags;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int) usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(
+			audio->event_wait, audlpa_events_pending(audio),
+			msecs_to_jiffies(timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(
+			audio->event_wait, audlpa_events_pending(audio));
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	rc = 0;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+			struct audlpa_event, list);
+		list_del(&drv_evt->list);
+	}
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else
+		rc = -1;
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	if (drv_evt->event_type == AUDIO_EVENT_WRITE_DONE ||
+	    drv_evt->event_type == AUDIO_EVENT_READ_DONE) {
+		mutex_lock(&audio->lock);
+		audlpa_pmem_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+				  drv_evt->payload.aio_buf.buf_len, 0);
+		mutex_unlock(&audio->lock);
+	}
+	if (!rc && copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audlpa_pmem_check(struct audio *audio,
+		void *vaddr, unsigned long len)
+{
+	struct audlpa_pmem_region *region_elt;
+	struct audlpa_pmem_region t = { .vaddr = vaddr, .len = len };
+
+	list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+		if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
+		    OVERLAPS(region_elt, &t)) {
+			MM_ERR("region (vaddr %p len %ld)"
+				" clashes with registered region"
+				" (vaddr %p paddr %p len %ld)\n",
+				vaddr, len,
+				region_elt->vaddr,
+				(void *)region_elt->paddr,
+				region_elt->len);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int audlpa_pmem_add(struct audio *audio,
+	struct msm_audio_pmem_info *info)
+{
+	unsigned long paddr, kvaddr, len;
+	struct file *file;
+	struct audlpa_pmem_region *region;
+	int rc = -EINVAL;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	region = kmalloc(sizeof(*region), GFP_KERNEL);
+
+	if (!region) {
+		rc = -ENOMEM;
+		goto end;
+	}
+
+	if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) {
+		kfree(region);
+		goto end;
+	}
+
+	rc = audlpa_pmem_check(audio, info->vaddr, len);
+	if (rc < 0) {
+		put_pmem_file(file);
+		kfree(region);
+		goto end;
+	}
+
+	region->vaddr = info->vaddr;
+	region->fd = info->fd;
+	region->paddr = paddr;
+	region->kvaddr = kvaddr;
+	region->len = len;
+	region->file = file;
+	region->ref_cnt = 0;
+	MM_DBG("add region paddr %lx vaddr %p, len %lu\n", region->paddr,
+			region->vaddr, region->len);
+	list_add_tail(&region->list, &audio->pmem_region_queue);
+end:
+	return rc;
+}
+
+static int audlpa_pmem_remove(struct audio *audio,
+	struct msm_audio_pmem_info *info)
+{
+	struct audlpa_pmem_region *region;
+	struct list_head *ptr, *next;
+	int rc = -EINVAL;
+
+	MM_DBG("info fd %d vaddr %p\n", info->fd, info->vaddr);
+
+	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
+		region = list_entry(ptr, struct audlpa_pmem_region, list);
+
+		if ((region->fd == info->fd) &&
+		    (region->vaddr == info->vaddr)) {
+			if (region->ref_cnt) {
+				MM_DBG("region %p in use ref_cnt %d\n",
+						region, region->ref_cnt);
+				break;
+			}
+			MM_DBG("remove region fd %d vaddr %p\n",
+				info->fd, info->vaddr);
+			list_del(&region->list);
+			put_pmem_file(region->file);
+			kfree(region);
+			rc = 0;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static int audlpa_pmem_lookup_vaddr(struct audio *audio, void *addr,
+		     unsigned long len, struct audlpa_pmem_region **region)
+{
+	struct audlpa_pmem_region *region_elt;
+
+	int match_count = 0;
+
+	*region = NULL;
+
+	/* returns physical address or zero */
+	list_for_each_entry(region_elt, &audio->pmem_region_queue,
+		list) {
+		if (addr >= region_elt->vaddr &&
+		    addr < region_elt->vaddr + region_elt->len &&
+		    addr + len <= region_elt->vaddr + region_elt->len) {
+			/* offset since we could pass vaddr inside a registerd
+			 * pmem buffer
+			 */
+
+			match_count++;
+			if (!*region)
+				*region = region_elt;
+		}
+	}
+
+	if (match_count > 1) {
+		MM_ERR("multiple hits for vaddr %p, len %ld\n", addr, len);
+		list_for_each_entry(region_elt,
+		  &audio->pmem_region_queue, list) {
+			if (addr >= region_elt->vaddr &&
+			    addr < region_elt->vaddr + region_elt->len &&
+			    addr + len <= region_elt->vaddr + region_elt->len)
+				MM_ERR("\t%p, %ld --> %p\n", region_elt->vaddr,
+						region_elt->len,
+						(void *)region_elt->paddr);
+		}
+	}
+
+	return *region ? 0 : -1;
+}
+
+unsigned long audlpa_pmem_fixup(struct audio *audio, void *addr,
+		    unsigned long len, int ref_up)
+{
+	struct audlpa_pmem_region *region;
+	unsigned long paddr;
+	int ret;
+
+	ret = audlpa_pmem_lookup_vaddr(audio, addr, len, &region);
+	if (ret) {
+		MM_ERR("lookup (%p, %ld) failed\n", addr, len);
+		return 0;
+	}
+	if (ref_up)
+		region->ref_cnt++;
+	else
+		region->ref_cnt--;
+	MM_DBG("found region %p ref_cnt %d\n", region, region->ref_cnt);
+	paddr = region->paddr + (addr - region->vaddr);
+	return paddr;
+}
+
+/* audio -> lock must be held at this point */
+static int audlpa_aio_buf_add(struct audio *audio, unsigned dir,
+	void __user *arg)
+{
+	unsigned long flags;
+	struct audlpa_buffer_node *buf_node;
+
+	buf_node = kmalloc(sizeof(*buf_node), GFP_KERNEL);
+
+	if (!buf_node)
+		return -ENOMEM;
+
+	if (copy_from_user(&buf_node->buf, arg, sizeof(buf_node->buf))) {
+		kfree(buf_node);
+		return -EFAULT;
+	}
+
+	MM_DBG("node %p dir %x buf_addr %p buf_len %d data_len"
+			"%d\n", buf_node, dir,
+			buf_node->buf.buf_addr, buf_node->buf.buf_len,
+			buf_node->buf.data_len);
+
+	buf_node->paddr = audlpa_pmem_fixup(
+		audio, buf_node->buf.buf_addr,
+		buf_node->buf.buf_len, 1);
+
+	if (dir) {
+		/* write */
+		if (!buf_node->paddr ||
+		    (buf_node->paddr & 0x1) ||
+		    (buf_node->buf.data_len & 0x1)) {
+			kfree(buf_node);
+			return -EINVAL;
+		}
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		list_add_tail(&buf_node->list, &audio->out_queue);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		audlpa_async_send_data(audio, 0, 0);
+	} else {
+		/* read */
+	}
+
+	MM_DBG("Add buf_node %p paddr %lx\n", buf_node, buf_node->paddr);
+
+	return 0;
+}
+
+static int audio_enable_eq(struct audio *audio, int enable)
+{
+	if (audio->eq_enable == enable && !audio->eq_needs_commit)
+		return 0;
+
+	audio->eq_enable = enable;
+
+	if (audio->running) {
+		audpp_dsp_set_eq(audio->dec_id, enable, &audio->eq, POPP);
+		audio->eq_needs_commit = 0;
+	}
+	return 0;
+}
+
+static int audio_get_avsync_data(struct audio *audio,
+						struct msm_audio_stats *stats)
+{
+	int rc = -EINVAL;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (audio->dec_id == audio->avsync[0] && audio->avsync_flag) {
+		/* av_sync sample count */
+		stats->sample_count = (audio->avsync[2] << 16) |
+						(audio->avsync[3]);
+
+		/* av_sync byte_count */
+		stats->byte_count = (audio->avsync[5] << 16) |
+						(audio->avsync[6]);
+
+		audio->avsync_flag = 0;
+		rc = 0;
+	}
+	local_irq_restore(flags);
+	return rc;
+
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = -EINVAL;
+	unsigned long flags = 0;
+	uint16_t enable_mask;
+	int enable;
+	int prev_state;
+
+	MM_DBG("audio_ioctl() cmd = %d\n", cmd);
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+
+		audio->avsync_flag = 0;
+		memset(&stats, 0, sizeof(stats));
+		if (audpp_query_avsync(audio->dec_id) < 0)
+			return rc;
+
+		rc = wait_event_interruptible_timeout(audio->avsync_wait,
+				(audio->avsync_flag == 1),
+				msecs_to_jiffies(AVSYNC_EVENT_TIMEOUT));
+
+		if (rc < 0)
+			return rc;
+		else if ((rc > 0) || ((rc == 0) && (audio->avsync_flag == 1))) {
+			if (audio_get_avsync_data(audio, &stats) < 0)
+				return rc;
+
+			if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+				return -EFAULT;
+			return 0;
+		} else
+			return -EAGAIN;
+	}
+
+	switch (cmd) {
+	case AUDIO_ENABLE_AUDPP:
+		if (copy_from_user(&enable_mask, (void *) arg,
+						sizeof(enable_mask))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		enable = (enable_mask & EQ_ENABLE) ? 1 : 0;
+		audio_enable_eq(audio, enable);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_VOLUME:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.volume = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(AUDPP_CMD_CFG_DEV_MIXER_ID_4,
+						&audio->vol_pan,
+						COPP);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_PAN:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.pan = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(AUDPP_CMD_CFG_DEV_MIXER_ID_4,
+						&audio->vol_pan,
+						COPP);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_EQ:
+		prev_state = audio->eq_enable;
+		audio->eq_enable = 0;
+		if (copy_from_user(&audio->eq.num_bands, (void *) arg,
+				sizeof(audio->eq) -
+				(AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2))) {
+			rc = -EFAULT;
+			break;
+		}
+		audio->eq_enable = prev_state;
+		audio->eq_needs_commit = 1;
+		rc = 0;
+		break;
+	}
+
+	if (-EINVAL != rc)
+		return rc;
+
+	if (cmd == AUDIO_GET_EVENT) {
+		MM_DBG(" AUDIO_GET_EVENT\n");
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audlpa_process_event_req(audio,
+				(void __user *) arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		return rc;
+	}
+
+	if (cmd == AUDIO_ABORT_GET_EVENT) {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		MM_DBG("AUDIO_START\n");
+		rc = audio_enable(audio);
+		if (!rc) {
+			rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+			MM_DBG("dec_state %d rc = %d\n", audio->dec_state, rc);
+
+			if (audio->dec_state != MSM_AUD_DECODER_STATE_SUCCESS)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		break;
+
+	case AUDIO_STOP:
+		MM_DBG("AUDIO_STOP\n");
+		rc = audio_disable(audio);
+		audio->stopped = 1;
+		audio_ioport_reset(audio);
+		audio->stopped = 0;
+		audio->drv_status &= ~ADRV_STATUS_PAUSE;
+		break;
+
+	case AUDIO_FLUSH:
+		MM_DBG("AUDIO_FLUSH\n");
+		audio->wflush = 1;
+		audio_ioport_reset(audio);
+		if (audio->running) {
+			if (!(audio->drv_status & ADRV_STATUS_PAUSE)) {
+				rc = audpp_pause(audio->dec_id, (int) arg);
+				if (rc < 0) {
+					MM_ERR("%s: pause cmd failed rc=%d\n",
+						__func__, rc);
+					rc = -EINTR;
+					break;
+				}
+			}
+			audpp_flush(audio->dec_id);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->wflush = 0;
+		}
+		break;
+
+	case AUDIO_SET_CONFIG:{
+		struct msm_audio_config config;
+		MM_INFO("AUDIO_SET_CONFIG\n");
+		if (copy_from_user(&config, (void *) arg, sizeof(config))) {
+			rc = -EFAULT;
+			MM_INFO("ERROR: copy from user\n");
+			break;
+		}
+		if (config.channel_count == 1) {
+			config.channel_count = AUDPP_CMD_PCM_INTF_MONO_V;
+		} else if (config.channel_count == 2) {
+			config.channel_count = AUDPP_CMD_PCM_INTF_STEREO_V;
+		} else {
+			rc = -EINVAL;
+			MM_INFO("ERROR: config.channel_count == %d\n",
+					config.channel_count);
+			break;
+		}
+
+		if (config.bits == 8)
+			config.bits = AUDPP_CMD_WAV_PCM_WIDTH_8;
+		else if (config.bits == 16)
+			config.bits = AUDPP_CMD_WAV_PCM_WIDTH_16;
+		else if (config.bits == 24)
+			config.bits = AUDPP_CMD_WAV_PCM_WIDTH_24;
+		else {
+			rc = -EINVAL;
+			MM_INFO("ERROR: config.bits == %d\n", config.bits);
+			break;
+		}
+		audio->out_sample_rate = config.sample_rate;
+		audio->out_channel_mode = config.channel_count;
+		audio->out_bits = config.bits;
+		audio->buffer_count = config.buffer_count;
+		audio->buffer_size = config.buffer_size;
+		MM_DBG("AUDIO_SET_CONFIG: config.bits = %d\n", config.bits);
+		rc = 0;
+		break;
+	}
+
+	case AUDIO_GET_CONFIG:{
+		struct msm_audio_config config;
+		config.buffer_count = audio->buffer_count;
+		config.buffer_size = audio->buffer_size;
+		config.sample_rate = audio->out_sample_rate;
+		if (audio->out_channel_mode == AUDPP_CMD_PCM_INTF_MONO_V)
+			config.channel_count = 1;
+		else
+			config.channel_count = 2;
+		if (audio->out_bits == AUDPP_CMD_WAV_PCM_WIDTH_8)
+			config.bits = 8;
+		else if (audio->out_bits == AUDPP_CMD_WAV_PCM_WIDTH_24)
+			config.bits = 24;
+		else
+			config.bits = 16;
+		config.meta_field = 0;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		MM_DBG("AUDIO_GET_CONFIG: config.bits = %d\n", config.bits);
+		if (copy_to_user((void *) arg, &config, sizeof(config)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	}
+
+	case AUDIO_PAUSE:
+		MM_DBG("AUDIO_PAUSE %ld\n", arg);
+		rc = audpp_pause(audio->dec_id, (int) arg);
+		if (arg == 1)
+			audio->drv_status |= ADRV_STATUS_PAUSE;
+		else if (arg == 0)
+			audio->drv_status &= ~ADRV_STATUS_PAUSE;
+		break;
+
+	case AUDIO_REGISTER_PMEM: {
+			struct msm_audio_pmem_info info;
+			MM_DBG("AUDIO_REGISTER_PMEM\n");
+			if (copy_from_user(&info, (void *) arg, sizeof(info)))
+				rc = -EFAULT;
+			else
+				rc = audlpa_pmem_add(audio, &info);
+			break;
+		}
+
+	case AUDIO_DEREGISTER_PMEM: {
+			struct msm_audio_pmem_info info;
+			MM_DBG("AUDIO_DEREGISTER_PMEM\n");
+			if (copy_from_user(&info, (void *) arg, sizeof(info)))
+				rc = -EFAULT;
+			else
+				rc = audlpa_pmem_remove(audio, &info);
+			break;
+		}
+	case AUDIO_ASYNC_WRITE:
+		if (audio->drv_status & ADRV_STATUS_FSYNC)
+			rc = -EBUSY;
+		else
+			rc = audlpa_aio_buf_add(audio, 1, (void __user *) arg);
+		break;
+
+	case AUDIO_GET_SESSION_ID:
+		if (copy_to_user((void *) arg, &audio->dec_id,
+					sizeof(unsigned short)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	default:
+		rc = audio->codec_ops.ioctl(file, cmd, arg);
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+/* Only useful in tunnel-mode */
+int audlpa_async_fsync(struct audio *audio)
+{
+	int rc = 0, empty = 0;
+	struct audlpa_buffer_node *buf_node;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	/* Blocking client sends more data */
+	mutex_lock(&audio->lock);
+	audio->drv_status |= ADRV_STATUS_FSYNC;
+	mutex_unlock(&audio->lock);
+
+	mutex_lock(&audio->write_lock);
+	audio->teos = 0;
+	empty = list_empty(&audio->out_queue);
+	buf_node = kmalloc(sizeof(*buf_node), GFP_KERNEL);
+	if (!buf_node)
+		goto done;
+
+	buf_node->paddr = 0xFFFFFFFF;
+	buf_node->buf.data_len = 0;
+	buf_node->buf.buf_addr = NULL;
+	buf_node->buf.buf_len = 0;
+	buf_node->buf.private_data = NULL;
+	list_add_tail(&buf_node->list, &audio->out_queue);
+	if ((empty != 0) && (audio->out_needed == 1))
+		audlpa_async_send_data(audio, 0, 0);
+
+	rc = wait_event_interruptible(audio->write_wait,
+				  audio->teos || audio->wflush ||
+				  audio->stopped);
+
+	if (rc < 0)
+		goto done;
+
+	if (audio->teos == 1) {
+		/* Releasing all the pending buffers to user */
+		audio->teos = 0;
+		audlpa_async_flush(audio);
+	}
+
+	if (audio->stopped || audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+	mutex_lock(&audio->lock);
+	audio->drv_status &= ~ADRV_STATUS_FSYNC;
+	mutex_unlock(&audio->lock);
+
+	return rc;
+}
+
+int audlpa_fsync(struct file *file, loff_t ppos1, loff_t ppos2, int datasync)
+{
+	struct audio *audio = file->private_data;
+
+	if (!audio->running)
+		return -EINVAL;
+
+	return audlpa_async_fsync(audio);
+}
+
+static void audlpa_reset_pmem_region(struct audio *audio)
+{
+	struct audlpa_pmem_region *region;
+	struct list_head *ptr, *next;
+
+	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
+		region = list_entry(ptr, struct audlpa_pmem_region, list);
+		list_del(&region->list);
+		put_pmem_file(region->file);
+		kfree(region);
+	}
+
+	return;
+}
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	MM_INFO("audio instance 0x%08x freeing\n", (int)audio);
+	mutex_lock(&audio->lock);
+	auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->dec_id);
+	audio_disable(audio);
+	audlpa_async_flush(audio);
+	audlpa_reset_pmem_region(audio);
+
+	msm_adsp_put(audio->audplay);
+	audpp_adec_free(audio->dec_id);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&audio->suspend_ctl.node);
+#endif
+	audio->opened = 0;
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audlpa_reset_event_queue(audio);
+	iounmap(audio->data);
+	pmem_kfree(audio->phys);
+	mutex_unlock(&audio->lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio);
+	return 0;
+}
+
+static void audlpa_post_event(struct audio *audio, int type,
+	union msm_audio_event_payload payload)
+{
+	struct audlpa_event *e_node = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+			struct audlpa_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audlpa_event), GFP_ATOMIC);
+		if (!e_node) {
+			MM_ERR("No mem to post event %d\n", type);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	wake_up(&audio->event_wait);
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audlpa_suspend(struct early_suspend *h)
+{
+	struct audlpa_suspend_ctl *ctl =
+		container_of(h, struct audlpa_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audlpa_post_event(ctl->audio, AUDIO_EVENT_SUSPEND, payload);
+}
+
+static void audlpa_resume(struct early_suspend *h)
+{
+	struct audlpa_suspend_ctl *ctl =
+		container_of(h, struct audlpa_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audlpa_post_event(ctl->audio, AUDIO_EVENT_RESUME, payload);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audlpa_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audlpa_debug_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 4096;
+	static char buffer[4096];
+	int n = 0;
+	struct audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+					"enabled %d\n", audio->enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+					"stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+					"volume %x\n", audio->vol_pan.volume);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+					"sample rate %d\n",
+					audio->out_sample_rate);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+					"channel mode %d\n",
+					audio->out_channel_mode);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+					"wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+					"running %d\n", audio->running);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+					"dec state %d\n", audio->dec_state);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+					"out_needed %d\n", audio->out_needed);
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audlpa_debug_fops = {
+	.read = audlpa_debug_read,
+	.open = audlpa_debug_open,
+};
+#endif
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = NULL;
+	int rc, i, dec_attrb = 0, decid;
+	struct audlpa_event *e_node = NULL;
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_lpa_" + 5];
+#endif
+
+	/* Allocate audio instance, set to zero */
+	audio = kzalloc(sizeof(struct audio), GFP_KERNEL);
+	if (!audio) {
+		MM_ERR("no memory to allocate audio instance\n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	MM_INFO("audio instance 0x%08x created\n", (int)audio);
+
+	if ((file->f_mode & FMODE_WRITE) && !(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_TUNNEL;
+	} else {
+		kfree(audio);
+		rc = -EACCES;
+		goto done;
+	}
+
+	/* Allocate the decoder based on inode minor number*/
+	audio->minor_no = iminor(inode);
+	dec_attrb |= audlpa_decs[audio->minor_no].dec_attrb;
+	audio->codec_ops.ioctl = audlpa_decs[audio->minor_no].ioctl;
+	audio->codec_ops.adec_params = audlpa_decs[audio->minor_no].adec_params;
+	audio->buffer_size = BUFSZ;
+	audio->buffer_count = MAX_BUF;
+
+	dec_attrb |= MSM_AUD_MODE_LP;
+
+	decid = audpp_adec_alloc(dec_attrb, &audio->module_name,
+			&audio->queue_id);
+	if (decid < 0) {
+		MM_ERR("No free decoder available\n");
+		rc = -ENODEV;
+		MM_INFO("audio instance 0x%08x freeing\n", (int)audio);
+		kfree(audio);
+		goto done;
+	}
+	audio->dec_id = decid & MSM_AUD_DECODER_MASK;
+
+	MM_DBG("set to aio interface\n");
+	audio->drv_status |= ADRV_STATUS_AIO_INTF;
+
+	rc = msm_adsp_get(audio->module_name, &audio->audplay,
+		&audplay_adsp_ops_lpa, audio);
+
+	if (rc) {
+		MM_ERR("failed to get %s module\n", audio->module_name);
+		goto err;
+	}
+
+	/* Initialize all locks of audio instance */
+	mutex_init(&audio->lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->get_event_lock);
+	spin_lock_init(&audio->dsp_lock);
+	init_waitqueue_head(&audio->write_wait);
+	INIT_LIST_HEAD(&audio->out_queue);
+	INIT_LIST_HEAD(&audio->pmem_region_queue);
+	INIT_LIST_HEAD(&audio->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+	init_waitqueue_head(&audio->wait);
+	init_waitqueue_head(&audio->event_wait);
+	spin_lock_init(&audio->event_queue_lock);
+	init_waitqueue_head(&audio->avsync_wait);
+
+	audio->out_sample_rate = 44100;
+	audio->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V;
+	audio->out_bits = AUDPP_CMD_WAV_PCM_WIDTH_16;
+	audio->vol_pan.volume = 0x2000;
+
+	audlpa_async_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+
+	audio->device_events = AUDDEV_EVT_DEV_RDY
+				|AUDDEV_EVT_DEV_RLS | AUDDEV_EVT_REL_PENDING
+				|AUDDEV_EVT_STREAM_VOL_CHG;
+	audio->device_switch = DEVICE_SWITCH_STATE_NONE;
+	audio->drv_status &= ~ADRV_STATUS_PAUSE;
+	audio->bytecount_consumed = 0;
+	audio->bytecount_head = 0;
+	audio->bytecount_given = 0;
+
+	rc = auddev_register_evt_listner(audio->device_events,
+					AUDDEV_CLNT_DEC,
+					audio->dec_id,
+					lpa_listner,
+					(void *)audio);
+	if (rc) {
+		MM_ERR("%s: failed to register listnet\n", __func__);
+		goto event_err;
+	}
+
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_lpa_%04x", audio->dec_id);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+			NULL, (void *) audio, &audlpa_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		MM_DBG("debugfs_create_file failed\n");
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	audio->suspend_ctl.node.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+	audio->suspend_ctl.node.resume = audlpa_resume;
+	audio->suspend_ctl.node.suspend = audlpa_suspend;
+	audio->suspend_ctl.audio = audio;
+	register_early_suspend(&audio->suspend_ctl.node);
+#endif
+	for (i = 0; i < AUDLPA_EVENT_NUM; i++) {
+		e_node = kmalloc(sizeof(struct audlpa_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			MM_ERR("event pkt alloc failed\n");
+			break;
+		}
+	}
+done:
+	return rc;
+event_err:
+	msm_adsp_put(audio->audplay);
+err:
+	iounmap(audio->data);
+	pmem_kfree(audio->phys);
+	audpp_adec_free(audio->dec_id);
+	MM_INFO("audio instance 0x%08x freeing\n", (int)audio);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_lpa_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audio_open,
+	.release	= audio_release,
+	.unlocked_ioctl	= audio_ioctl,
+	.fsync		= audlpa_fsync,
+};
+
+static dev_t audlpa_devno;
+static struct class *audlpa_class;
+struct audlpa_device {
+	const char *name;
+	struct device *device;
+	struct cdev cdev;
+};
+
+static struct audlpa_device *audlpa_devices;
+
+static void audlpa_create(struct audlpa_device *adev, const char *name,
+			struct device *parent, dev_t devt)
+{
+	struct device *dev;
+	int rc;
+
+	dev = device_create(audlpa_class, parent, devt, "%s", name);
+	if (IS_ERR(dev))
+		return;
+
+	cdev_init(&adev->cdev, &audio_lpa_fops);
+	adev->cdev.owner = THIS_MODULE;
+
+	rc = cdev_add(&adev->cdev, devt, 1);
+	if (rc < 0) {
+		device_destroy(audlpa_class, devt);
+	} else {
+		adev->device = dev;
+		adev->name = name;
+	}
+}
+
+static int __init audio_init(void)
+{
+	int rc;
+	int n = ARRAY_SIZE(audlpa_decs);
+
+	audlpa_devices = kzalloc(sizeof(struct audlpa_device) * n, GFP_KERNEL);
+	if (!audlpa_devices)
+		return -ENOMEM;
+
+	audlpa_class = class_create(THIS_MODULE, "audlpa");
+	if (IS_ERR(audlpa_class))
+		goto fail_create_class;
+
+	rc = alloc_chrdev_region(&audlpa_devno, 0, n, "msm_audio_lpa");
+	if (rc < 0)
+		goto fail_alloc_region;
+
+	for (n = 0; n < ARRAY_SIZE(audlpa_decs); n++) {
+		audlpa_create(audlpa_devices + n,
+				audlpa_decs[n].name, NULL,
+				MKDEV(MAJOR(audlpa_devno), n));
+	}
+
+	return 0;
+
+fail_alloc_region:
+	class_unregister(audlpa_class);
+	return rc;
+fail_create_class:
+	kfree(audlpa_devices);
+	return -ENOMEM;
+}
+
+static void __exit audio_exit(void)
+{
+	class_unregister(audlpa_class);
+	kfree(audlpa_devices);
+}
+
+module_init(audio_init);
+module_exit(audio_exit);
+
+MODULE_DESCRIPTION("MSM LPA driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_mp3.c b/arch/arm/mach-msm/qdsp5v2/audio_mp3.c
new file mode 100644
index 0000000..53ae0a4
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/audio_mp3.c
@@ -0,0 +1,2521 @@
+/* mp3 audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2009-2012, Code Aurora Forum. 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.
+ *
+ */
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/earlysuspend.h>
+#include <linux/list.h>
+#include <linux/android_pmem.h>
+#include <linux/slab.h>
+#include <linux/memory_alloc.h>
+#include <linux/msm_audio.h>
+#include <mach/msm_adsp.h>
+
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/qdsp5v2/qdsp5audppmsg.h>
+#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
+#include <mach/qdsp5v2/qdsp5audplaymsg.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/qdsp5v2/audpp.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_memtypes.h>
+
+#define ADRV_STATUS_AIO_INTF 0x00000001
+#define ADRV_STATUS_OBUF_GIVEN 0x00000002
+#define ADRV_STATUS_IBUF_GIVEN 0x00000004
+#define ADRV_STATUS_FSYNC 0x00000008
+
+/* Size must be power of 2 */
+#define BUFSZ_MAX 32768
+#define BUFSZ_MIN 4096
+#define DMASZ_MAX (BUFSZ_MAX * 2)
+#define DMASZ_MIN (BUFSZ_MIN * 2)
+
+#define AUDPLAY_INVALID_READ_PTR_OFFSET	0xFFFF
+#define AUDDEC_DEC_MP3 2
+
+#define PCM_BUFSZ_MIN 4800	/* Hold one stereo MP3 frame */
+#define PCM_BUF_MAX_COUNT 5	/* DSP only accepts 5 buffers at most
+				   but support 2 buffers currently */
+#define ROUTING_MODE_FTRT 1
+#define ROUTING_MODE_RT 2
+/* Decoder status received from AUDPPTASK */
+#define  AUDPP_DEC_STATUS_SLEEP	0
+#define	 AUDPP_DEC_STATUS_INIT  1
+#define  AUDPP_DEC_STATUS_CFG   2
+#define  AUDPP_DEC_STATUS_PLAY  3
+
+#define AUDMP3_METAFIELD_MASK 0xFFFF0000
+#define AUDMP3_EOS_FLG_OFFSET 0x0A /* Offset from beginning of buffer */
+#define AUDMP3_EOS_FLG_MASK 0x01
+#define AUDMP3_EOS_NONE 0x0 /* No EOS detected */
+#define AUDMP3_EOS_SET 0x1 /* EOS set in meta field */
+
+#define AUDMP3_EVENT_NUM 10 /* Default number of pre-allocated event packets */
+
+#define BITSTREAM_ERROR_THRESHOLD_VALUE 0x1 /* DEFAULT THRESHOLD VALUE */
+
+#define __CONTAINS(r, v, l) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __v = v;					\
+	typeof(v) __e = __v + l;				\
+	int res = ((__v >= __r->vaddr) && 			\
+		(__e <= __r->vaddr + __r->len));		\
+	res;							\
+})
+
+#define CONTAINS(r1, r2) ({					\
+	typeof(r2) __r2 = r2;					\
+	__CONTAINS(r1, __r2->vaddr, __r2->len);			\
+})
+
+#define IN_RANGE(r, v) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __vv = v;					\
+	int res = ((__vv >= __r->vaddr) &&			\
+		(__vv < (__r->vaddr + __r->len)));		\
+	res;							\
+})
+
+#define OVERLAPS(r1, r2) ({					\
+	typeof(r1) __r1 = r1;					\
+	typeof(r2) __r2 = r2;					\
+	typeof(__r2->vaddr) __v = __r2->vaddr;			\
+	typeof(__v) __e = __v + __r2->len - 1;			\
+	int res = (IN_RANGE(__r1, __v) || IN_RANGE(__r1, __e));	\
+	res;							\
+})
+struct audio;
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+	unsigned short mfield_sz; /*only useful for data has meta field */
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct audmp3_suspend_ctl {
+  struct early_suspend node;
+  struct audio *audio;
+};
+#endif
+
+struct audmp3_event {
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+
+struct audmp3_pmem_region {
+	struct list_head list;
+	struct file *file;
+	int fd;
+	void *vaddr;
+	unsigned long paddr;
+	unsigned long kvaddr;
+	unsigned long len;
+	unsigned ref_cnt;
+};
+
+struct audmp3_buffer_node {
+	struct list_head list;
+	struct msm_audio_aio_buf buf;
+	unsigned long paddr;
+};
+
+struct audmp3_drv_operations {
+	void (*pcm_buf_update)(struct audio *, uint32_t *);
+	void (*buffer_refresh)(struct audio *);
+	void (*send_data)(struct audio *, unsigned);
+	void (*out_flush)(struct audio *);
+	void (*in_flush)(struct audio *);
+	int (*fsync)(struct audio *);
+};
+
+struct audio {
+	struct buffer out[2];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed; /* number of buffers the dsp is waiting for */
+	unsigned out_dma_sz;
+	struct list_head out_queue; /* queue to retain output buffers */
+	atomic_t out_bytes;
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	/* Host PCM section */
+	struct buffer in[PCM_BUF_MAX_COUNT];
+	struct mutex read_lock;
+	wait_queue_head_t read_wait;	/* Wait queue for read */
+	char *read_data;	/* pointer to reader buffer */
+	int32_t read_phys;	/* physical address of reader buffer */
+	uint8_t read_next;	/* index to input buffers to be read next */
+	uint8_t fill_next;	/* index to buffer that DSP should be filling */
+	uint8_t pcm_buf_count;	/* number of pcm buffer allocated */
+	struct list_head in_queue; /* queue to retain input buffers */
+	/* ---- End of Host PCM section */
+
+	struct msm_adsp_module *audplay;
+
+	/* configuration to use on next enable */
+	uint32_t out_sample_rate;
+	uint32_t out_channel_mode;
+
+	/* data allocated for various buffers */
+	char *data;
+	int32_t phys; /* physical address of write buffer */
+	void *map_v_read;
+	void *map_v_write;
+
+	uint32_t drv_status;
+	int mfield; /* meta field embedded in data */
+	int rflush; /* Read  flush */
+	int wflush; /* Write flush */
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+	int pcm_feedback;
+	int buf_refresh;
+	int teos; /* valid only if tunnel mode & no data left for decoder */
+	enum msm_aud_decoder_state dec_state;	/* Represents decoder state */
+	int reserved; /* A byte is being reserved */
+	char rsv_byte; /* Handle odd length user data */
+
+	const char *module_name;
+	unsigned queue_id;
+	uint16_t dec_id;
+	uint32_t read_ptr_offset;
+	int16_t source;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct audmp3_suspend_ctl suspend_ctl;
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+
+	wait_queue_head_t wait;
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	wait_queue_head_t event_wait;
+	spinlock_t event_queue_lock;
+	struct mutex get_event_lock;
+	int event_abort;
+	/* AV sync Info */
+	int avsync_flag;              /* Flag to indicate feedback from DSP */
+	wait_queue_head_t avsync_wait;/* Wait queue for AV Sync Message     */
+	/* flags, 48 bits sample/bytes counter per channel */
+	uint16_t avsync[AUDPP_AVSYNC_CH_COUNT * AUDPP_AVSYNC_NUM_WORDS + 1];
+
+	uint32_t device_events;
+
+	struct list_head pmem_region_queue; /* protected by lock */
+	struct audmp3_drv_operations drv_ops;
+
+	struct msm_audio_bitstream_info stream_info;
+	struct msm_audio_bitstream_error_info bitstream_error_info;
+	uint32_t bitstream_error_threshold_value;
+
+	int eq_enable;
+	int eq_needs_commit;
+	struct audpp_cmd_cfg_object_params_eqalizer eq;
+	struct audpp_cmd_cfg_object_params_volume vol_pan;
+};
+
+static int auddec_dsp_config(struct audio *audio, int enable);
+static void audpp_cmd_cfg_adec_params(struct audio *audio);
+static void audpp_cmd_cfg_routing_mode(struct audio *audio);
+static void audplay_send_data(struct audio *audio, unsigned needed);
+static void audplay_error_threshold_config(struct audio *audio);
+static void audplay_config_hostpcm(struct audio *audio);
+static void audplay_buffer_refresh(struct audio *audio);
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
+static void audmp3_post_event(struct audio *audio, int type,
+	union msm_audio_event_payload payload);
+static unsigned long audmp3_pmem_fixup(struct audio *audio, void *addr,
+				unsigned long len, int ref_up);
+
+static void mp3_listner(u32 evt_id, union auddev_evt_data *evt_payload,
+			void *private_data)
+{
+	struct audio *audio = (struct audio *) private_data;
+	switch (evt_id) {
+	case AUDDEV_EVT_DEV_RDY:
+		MM_DBG(":AUDDEV_EVT_DEV_RDY\n");
+		audio->source |= (0x1 << evt_payload->routing_id);
+		if (audio->running == 1 && audio->enabled == 1)
+			audpp_route_stream(audio->dec_id, audio->source);
+
+		break;
+	case AUDDEV_EVT_DEV_RLS:
+		MM_DBG(":AUDDEV_EVT_DEV_RLS\n");
+		audio->source &= ~(0x1 << evt_payload->routing_id);
+		if (audio->running == 1 && audio->enabled == 1)
+			audpp_route_stream(audio->dec_id, audio->source);
+		break;
+	case AUDDEV_EVT_STREAM_VOL_CHG:
+		audio->vol_pan.volume = evt_payload->session_vol;
+		MM_DBG(":AUDDEV_EVT_STREAM_VOL_CHG, stream vol %d\n",
+				audio->vol_pan.volume);
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+		break;
+	default:
+		MM_ERR(":ERROR:wrong event\n");
+		break;
+	}
+}
+/* must be called with audio->lock held */
+static int audio_enable(struct audio *audio)
+{
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	if (audio->enabled)
+		return 0;
+
+	audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	if (msm_adsp_enable(audio->audplay)) {
+		MM_ERR("msm_adsp_enable(audplay) failed\n");
+		return -ENODEV;
+	}
+
+	if (audpp_enable(audio->dec_id, audio_dsp_event, audio)) {
+		MM_ERR("audpp_enable() failed\n");
+		msm_adsp_disable(audio->audplay);
+		return -ENODEV;
+	}
+
+	audio->enabled = 1;
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audio_disable(struct audio *audio)
+{
+	int rc = 0;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+		auddec_dsp_config(audio, 0);
+		rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+		else if (audio->dec_state != MSM_AUD_DECODER_STATE_CLOSE)
+			rc = -EFAULT;
+		else
+			rc = 0;
+		wake_up(&audio->write_wait);
+		wake_up(&audio->read_wait);
+		msm_adsp_disable(audio->audplay);
+		audpp_disable(audio->dec_id, audio);
+		audio->out_needed = 0;
+	}
+	return rc;
+}
+
+/* ------------------- dsp --------------------- */
+static void audmp3_async_pcm_buf_update(struct audio *audio, uint32_t *payload)
+{
+	unsigned long flags;
+	union msm_audio_event_payload event_payload;
+	struct audmp3_buffer_node *filled_buf;
+	uint8_t index;
+
+	if (audio->rflush)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < payload[1]; index++) {
+		BUG_ON(list_empty(&audio->in_queue));
+		filled_buf = list_first_entry(&audio->in_queue,
+					struct audmp3_buffer_node, list);
+		if (filled_buf->paddr == payload[2 + index * 2]) {
+			list_del(&filled_buf->list);
+			event_payload.aio_buf = filled_buf->buf;
+			event_payload.aio_buf.data_len =
+				payload[3 + index * 2];
+			MM_DBG("pcm buf %p data_len %d\n", filled_buf,
+					event_payload.aio_buf.data_len);
+			audmp3_post_event(audio, AUDIO_EVENT_READ_DONE,
+						event_payload);
+			kfree(filled_buf);
+		} else {
+			MM_ERR("expected=%lx ret=%x\n", filled_buf->paddr,
+					payload[2 + index * 2]);
+			break;
+		}
+	}
+
+	audio->drv_status &= ~ADRV_STATUS_IBUF_GIVEN;
+	audio->drv_ops.buffer_refresh(audio);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+
+}
+
+static void audio_update_pcm_buf_entry(struct audio *audio, uint32_t *payload)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	if (audio->rflush)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < payload[1]; index++) {
+		if (audio->in[audio->fill_next].addr ==
+		    payload[2 + index * 2]) {
+			MM_DBG("in[%d] ready\n", audio->fill_next);
+			audio->in[audio->fill_next].used =
+			  payload[3 + index * 2];
+			if ((++audio->fill_next) == audio->pcm_buf_count)
+				audio->fill_next = 0;
+
+		} else {
+			MM_ERR("expected=%x ret=%x\n",
+					audio->in[audio->fill_next].addr,
+					payload[2 + index * 2]);
+			break;
+		}
+	}
+	if (audio->in[audio->fill_next].used == 0) {
+		audio->drv_ops.buffer_refresh(audio);
+	} else {
+		MM_DBG("read cannot keep up\n");
+		audio->buf_refresh = 1;
+	}
+	wake_up(&audio->read_wait);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+
+}
+
+static void audmp3_bitstream_error_info(struct audio *audio, uint32_t *payload)
+{
+	unsigned long flags;
+	union msm_audio_event_payload e_payload;
+
+	if (payload[0] != AUDDEC_DEC_MP3) {
+		MM_ERR("Unexpected bitstream error info from DSP:\
+				Invalid decoder\n");
+		return;
+	}
+
+	/* get stream info from DSP msg */
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+
+	audio->bitstream_error_info.dec_id = payload[0];
+	audio->bitstream_error_info.err_msg_indicator = payload[1];
+	audio->bitstream_error_info.err_type = payload[2];
+
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	MM_ERR("bit_stream_error_type=%d error_count=%d\n",
+			audio->bitstream_error_info.err_type, (0x0000FFFF &
+			audio->bitstream_error_info.err_msg_indicator));
+
+	/* send event to ARM to notify error info coming */
+	e_payload.error_info = audio->bitstream_error_info;
+	audmp3_post_event(audio, AUDIO_EVENT_BITSTREAM_ERROR_INFO, e_payload);
+}
+
+static void audmp3_update_stream_info(struct audio *audio, uint32_t *payload)
+{
+	unsigned long flags;
+	union msm_audio_event_payload e_payload;
+
+	/* get stream info from DSP msg */
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+
+	audio->stream_info.codec_type = AUDIO_CODEC_TYPE_MP3;
+	audio->stream_info.chan_info = (0x0000FFFF & payload[1]);
+	audio->stream_info.sample_rate = (0x0000FFFF & payload[2]);
+	audio->stream_info.bit_stream_info = (0x0000FFFF & payload[3]);
+	audio->stream_info.bit_rate = payload[4];
+
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	MM_DBG("chan_info=%d, sample_rate=%d, bit_stream_info=%d\n",
+			audio->stream_info.chan_info,
+			audio->stream_info.sample_rate,
+			audio->stream_info.bit_stream_info);
+
+	/* send event to ARM to notify steam info coming */
+	e_payload.stream_info = audio->stream_info;
+	audmp3_post_event(audio, AUDIO_EVENT_STREAM_INFO, e_payload);
+}
+
+static void audplay_dsp_event(void *data, unsigned id, size_t len,
+			      void (*getevent) (void *ptr, size_t len))
+{
+	struct audio *audio = data;
+	uint32_t msg[28];
+	getevent(msg, sizeof(msg));
+
+	MM_DBG("msg_id=%x\n", id);
+
+	switch (id) {
+	case AUDPLAY_MSG_DEC_NEEDS_DATA:
+		audio->drv_ops.send_data(audio, 1);
+		break;
+
+	case AUDPLAY_MSG_BUFFER_UPDATE:
+		audio->drv_ops.pcm_buf_update(audio, msg);
+		break;
+
+	case AUDPLAY_UP_STREAM_INFO:
+		if ((msg[1] & AUDPLAY_STREAM_INFO_MSG_MASK) ==
+				AUDPLAY_STREAM_INFO_MSG_MASK) {
+			audmp3_bitstream_error_info(audio, msg);
+		} else {
+			audmp3_update_stream_info(audio, msg);
+		}
+		break;
+
+	case AUDPLAY_UP_OUTPORT_FLUSH_ACK:
+		MM_DBG("OUTPORT_FLUSH_ACK\n");
+		audio->rflush = 0;
+		wake_up(&audio->read_wait);
+		if (audio->pcm_feedback)
+			audio->drv_ops.buffer_refresh(audio);
+		break;
+
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audplaytask)\n");
+		break;
+
+	default:
+		MM_ERR("unexpected message from decoder \n");
+		break;
+	}
+}
+
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned status = msg[1];
+
+			switch (status) {
+			case AUDPP_DEC_STATUS_SLEEP: {
+				uint16_t reason = msg[2];
+				MM_DBG("decoder status: sleep reason=0x%04x\n",
+						reason);
+				if ((reason == AUDPP_MSG_REASON_MEM)
+					|| (reason ==
+					AUDPP_MSG_REASON_NODECODER)) {
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_FAILURE;
+					wake_up(&audio->wait);
+				} else if (reason == AUDPP_MSG_REASON_NONE) {
+					/* decoder is in disable state */
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_CLOSE;
+					wake_up(&audio->wait);
+				}
+				break;
+			}
+			case AUDPP_DEC_STATUS_INIT:
+				MM_DBG("decoder status: init \n");
+				if (audio->pcm_feedback)
+					audpp_cmd_cfg_routing_mode(audio);
+				else
+					audpp_cmd_cfg_adec_params(audio);
+				break;
+
+			case AUDPP_DEC_STATUS_CFG:
+				MM_DBG("decoder status: cfg \n");
+				break;
+			case AUDPP_DEC_STATUS_PLAY:
+				MM_DBG("decoder status: play \n");
+				/* send  mixer command */
+				audpp_route_stream(audio->dec_id,
+						audio->source);
+				if (audio->pcm_feedback) {
+					audplay_error_threshold_config(audio);
+					audplay_config_hostpcm(audio);
+					audio->drv_ops.buffer_refresh(audio);
+				}
+				audio->dec_state =
+					MSM_AUD_DECODER_STATE_SUCCESS;
+				wake_up(&audio->wait);
+				break;
+			default:
+				MM_ERR("unknown decoder status \n");
+				break;
+			}
+			break;
+		}
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			MM_DBG("CFG_MSG ENABLE\n");
+			auddec_dsp_config(audio, 1);
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+			audpp_dsp_set_eq(audio->dec_id, audio->eq_enable,
+					&audio->eq, POPP);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			MM_DBG("CFG_MSG DISABLE\n");
+			audio->running = 0;
+		} else {
+			MM_DBG("CFG_MSG %d?\n", msg[0]);
+		}
+		break;
+	case AUDPP_MSG_ROUTING_ACK:
+		MM_DBG("ROUTING_ACK mode=%d\n",	msg[1]);
+		audpp_cmd_cfg_adec_params(audio);
+		break;
+
+	case AUDPP_MSG_FLUSH_ACK:
+		MM_DBG("FLUSH_ACK\n");
+		audio->wflush = 0;
+		audio->rflush = 0;
+		wake_up(&audio->write_wait);
+		if (audio->pcm_feedback)
+			audio->drv_ops.buffer_refresh(audio);
+		break;
+
+	case AUDPP_MSG_PCMDMAMISSED:
+		MM_DBG("PCMDMAMISSED\n");
+		audio->teos = 1;
+		wake_up(&audio->write_wait);
+		break;
+
+	case AUDPP_MSG_AVSYNC_MSG:
+		MM_DBG("AUDPP_MSG_AVSYNC_MSG\n");
+		memcpy(&audio->avsync[0], msg, sizeof(audio->avsync));
+		audio->avsync_flag = 1;
+		wake_up(&audio->avsync_wait);
+		break;
+
+	default:
+		MM_ERR("UNKNOWN (%d)\n", id);
+	}
+
+}
+
+
+struct msm_adsp_ops audplay_adsp_ops = {
+	.event = audplay_dsp_event,
+};
+
+
+#define audplay_send_queue0(audio, cmd, len) \
+	msm_adsp_write(audio->audplay, audio->queue_id, \
+			cmd, len)
+
+static int auddec_dsp_config(struct audio *audio, int enable)
+{
+	struct audpp_cmd_cfg_dec_type cfg_dec_cmd;
+
+	memset(&cfg_dec_cmd, 0, sizeof(cfg_dec_cmd));
+
+	cfg_dec_cmd.cmd_id = AUDPP_CMD_CFG_DEC_TYPE;
+	if (enable)
+		cfg_dec_cmd.dec_cfg = AUDPP_CMD_UPDATDE_CFG_DEC |
+				AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_MP3;
+	else
+		cfg_dec_cmd.dec_cfg = AUDPP_CMD_UPDATDE_CFG_DEC |
+				AUDPP_CMD_DIS_DEC_V;
+	cfg_dec_cmd.dm_mode = 0x0;
+	cfg_dec_cmd.stream_id = audio->dec_id;
+	return audpp_send_queue1(&cfg_dec_cmd, sizeof(cfg_dec_cmd));
+}
+
+static void audpp_cmd_cfg_adec_params(struct audio *audio)
+{
+	struct audpp_cmd_cfg_adec_params_mp3 cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_MP3_LEN;
+	cmd.common.dec_id = audio->dec_id;
+	cmd.common.input_sampling_frequency = audio->out_sample_rate;
+
+	audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static void audpp_cmd_cfg_routing_mode(struct audio *audio)
+{
+	struct audpp_cmd_routing_mode cmd;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_ROUTING_MODE;
+	cmd.object_number = audio->dec_id;
+	if (audio->pcm_feedback)
+		cmd.routing_mode = ROUTING_MODE_FTRT;
+	else
+		cmd.routing_mode = ROUTING_MODE_RT;
+
+	audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static int audplay_dsp_send_data_avail(struct audio *audio,
+					unsigned idx, unsigned len)
+{
+	struct audplay_cmd_bitstream_data_avail_nt2 cmd;
+
+	cmd.cmd_id		= AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_NT2;
+	if (audio->mfield)
+		cmd.decoder_id = AUDMP3_METAFIELD_MASK |
+			(audio->out[idx].mfield_sz >> 1);
+	else
+		cmd.decoder_id		= audio->dec_id;
+	cmd.buf_ptr		= audio->out[idx].addr;
+	cmd.buf_size		= len/2;
+	cmd.partition_number	= 0;
+	return audplay_send_queue0(audio, &cmd, sizeof(cmd));
+}
+/* Caller holds irq_lock */
+static void audmp3_async_buffer_refresh(struct audio *audio)
+{
+	struct audplay_cmd_buffer_refresh refresh_cmd;
+	struct audmp3_buffer_node *next_buf;
+
+	if (!audio->running ||
+	    audio->drv_status & ADRV_STATUS_IBUF_GIVEN)
+		return;
+
+	if (!list_empty(&audio->in_queue)) {
+		next_buf = list_first_entry(&audio->in_queue,
+		    struct audmp3_buffer_node, list);
+		if (!next_buf)
+			return;
+		MM_DBG("next buf %p phy %lx len %d\n", next_buf,
+				next_buf->paddr, next_buf->buf.buf_len);
+		refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH;
+		refresh_cmd.num_buffers = 1;
+		refresh_cmd.buf0_address = next_buf->paddr;
+		refresh_cmd.buf0_length = next_buf->buf.buf_len -
+			(next_buf->buf.buf_len % 576) +
+			(audio->mfield ? 24 : 0); /* Mp3 frame size */
+		refresh_cmd.buf_read_count = 0;
+		audio->drv_status |= ADRV_STATUS_IBUF_GIVEN;
+		(void) audplay_send_queue0(audio, &refresh_cmd,
+			sizeof(refresh_cmd));
+	}
+
+}
+
+static void audplay_buffer_refresh(struct audio *audio)
+{
+	struct audplay_cmd_buffer_refresh refresh_cmd;
+
+	refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH;
+	refresh_cmd.num_buffers = 1;
+	refresh_cmd.buf0_address = audio->in[audio->fill_next].addr;
+	refresh_cmd.buf0_length = audio->in[audio->fill_next].size -
+		(audio->in[audio->fill_next].size % 576) +
+		(audio->mfield ? 24 : 0); /* Mp3 frame size */
+	refresh_cmd.buf_read_count = 0;
+	MM_DBG("buf0_addr=%x buf0_len=%d\n", refresh_cmd.buf0_address,
+			refresh_cmd.buf0_length);
+	(void)audplay_send_queue0(audio, &refresh_cmd, sizeof(refresh_cmd));
+}
+
+static void audplay_error_threshold_config(struct audio *audio)
+{
+	union audplay_cmd_channel_info ch_cfg_cmd;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	ch_cfg_cmd.thr_update.cmd_id = AUDPLAY_CMD_CHANNEL_INFO;
+	ch_cfg_cmd.thr_update.threshold_update = AUDPLAY_ERROR_THRESHOLD_ENABLE;
+	ch_cfg_cmd.thr_update.threshold_value =
+		audio->bitstream_error_threshold_value;
+	(void)audplay_send_queue0(audio, &ch_cfg_cmd, sizeof(ch_cfg_cmd));
+}
+
+static void audplay_config_hostpcm(struct audio *audio)
+{
+	struct audplay_cmd_hpcm_buf_cfg cfg_cmd;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	cfg_cmd.cmd_id = AUDPLAY_CMD_HPCM_BUF_CFG;
+	cfg_cmd.max_buffers = 1;
+	cfg_cmd.byte_swap = 0;
+	cfg_cmd.hostpcm_config = (0x8000) | (0x4000);
+	cfg_cmd.feedback_frequency = 1;
+	cfg_cmd.partition_number = 0;
+	(void)audplay_send_queue0(audio, &cfg_cmd, sizeof(cfg_cmd));
+
+}
+
+static void audplay_outport_flush(struct audio *audio)
+{
+	struct audplay_cmd_outport_flush op_flush_cmd;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	op_flush_cmd.cmd_id = AUDPLAY_CMD_OUTPORT_FLUSH;
+	(void)audplay_send_queue0(audio, &op_flush_cmd, sizeof(op_flush_cmd));
+}
+
+static void audmp3_async_send_data(struct audio *audio, unsigned needed)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (needed && !audio->wflush) {
+		audio->out_needed = 1;
+		if (audio->drv_status & ADRV_STATUS_OBUF_GIVEN) {
+			/* pop one node out of queue */
+			union msm_audio_event_payload payload;
+			struct audmp3_buffer_node *used_buf;
+
+			MM_DBG("consumed\n");
+			BUG_ON(list_empty(&audio->out_queue));
+			used_buf = list_first_entry(&audio->out_queue,
+				struct audmp3_buffer_node, list);
+			list_del(&used_buf->list);
+			payload.aio_buf = used_buf->buf;
+			audmp3_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+				payload);
+			kfree(used_buf);
+			audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
+		}
+
+	}
+
+	if (audio->out_needed) {
+		struct audmp3_buffer_node *next_buf;
+		struct audplay_cmd_bitstream_data_avail_nt2 cmd;
+		if (!list_empty(&audio->out_queue)) {
+			next_buf = list_first_entry(&audio->out_queue,
+					struct audmp3_buffer_node, list);
+			MM_DBG("next_buf %p\n", next_buf);
+			if (next_buf) {
+				MM_DBG("next buf phy %lx len %d\n",
+						next_buf->paddr,
+						next_buf->buf.data_len);
+
+				cmd.cmd_id =
+					AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_NT2;
+				if (audio->mfield)
+					cmd.decoder_id = AUDMP3_METAFIELD_MASK |
+						(next_buf->buf.mfield_sz >> 1);
+				else
+					cmd.decoder_id = audio->dec_id;
+				cmd.buf_ptr	= (unsigned) next_buf->paddr;
+				cmd.buf_size = next_buf->buf.data_len >> 1;
+				cmd.partition_number	= 0;
+				audplay_send_queue0(audio, &cmd, sizeof(cmd));
+				audio->out_needed = 0;
+				audio->drv_status |= ADRV_STATUS_OBUF_GIVEN;
+			}
+		}
+	}
+
+done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static void audplay_send_data(struct audio *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (needed && !audio->wflush) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			MM_DBG("frame %d free\n", audio->out_tail);
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+			MM_DBG("frame %d busy\n", audio->out_tail);
+			audplay_dsp_send_data_avail(audio, audio->out_tail,
+					frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+static void audmp3_async_flush(struct audio *audio)
+{
+	struct audmp3_buffer_node *buf_node;
+	struct list_head *ptr, *next;
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	list_for_each_safe(ptr, next, &audio->out_queue) {
+		buf_node = list_entry(ptr, struct audmp3_buffer_node, list);
+		list_del(&buf_node->list);
+		payload.aio_buf = buf_node->buf;
+		audmp3_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+				payload);
+		kfree(buf_node);
+	}
+	audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
+	audio->out_needed = 0;
+	atomic_set(&audio->out_bytes, 0);
+}
+
+static void audio_flush(struct audio *audio)
+{
+	audio->out[0].used = 0;
+	audio->out[1].used = 0;
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->reserved = 0;
+	audio->out_needed = 0;
+	atomic_set(&audio->out_bytes, 0);
+}
+
+static void audmp3_async_flush_pcm_buf(struct audio *audio)
+{
+	struct audmp3_buffer_node *buf_node;
+	struct list_head *ptr, *next;
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	list_for_each_safe(ptr, next, &audio->in_queue) {
+		buf_node = list_entry(ptr, struct audmp3_buffer_node, list);
+		list_del(&buf_node->list);
+		payload.aio_buf = buf_node->buf;
+		payload.aio_buf.data_len = 0;
+		audmp3_post_event(audio, AUDIO_EVENT_READ_DONE,
+				payload);
+		kfree(buf_node);
+	}
+	audio->drv_status &= ~ADRV_STATUS_IBUF_GIVEN;
+
+}
+
+static void audio_flush_pcm_buf(struct audio *audio)
+{
+	uint8_t index;
+
+	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
+		audio->in[index].used = 0;
+
+	audio->buf_refresh = 0;
+	audio->read_next = 0;
+	audio->fill_next = 0;
+}
+
+static void audio_ioport_reset(struct audio *audio)
+{
+	if (audio->drv_status & ADRV_STATUS_AIO_INTF) {
+		/* If fsync is in progress, make sure
+		 * return value of fsync indicates
+		 * abort due to flush
+		 */
+		if (audio->drv_status & ADRV_STATUS_FSYNC) {
+			MM_DBG("fsync in progress\n");
+			wake_up(&audio->write_wait);
+			mutex_lock(&audio->write_lock);
+			audio->drv_ops.out_flush(audio);
+			mutex_unlock(&audio->write_lock);
+		} else
+			audio->drv_ops.out_flush(audio);
+		audio->drv_ops.in_flush(audio);
+	} else {
+		/* Make sure read/write thread are free from
+		 * sleep and knowing that system is not able
+		 * to process io request at the moment
+		 */
+		wake_up(&audio->write_wait);
+		mutex_lock(&audio->write_lock);
+		audio->drv_ops.out_flush(audio);
+		mutex_unlock(&audio->write_lock);
+		wake_up(&audio->read_wait);
+		mutex_lock(&audio->read_lock);
+		audio->drv_ops.in_flush(audio);
+		mutex_unlock(&audio->read_lock);
+	}
+	audio->avsync_flag = 1;
+	wake_up(&audio->avsync_wait);
+}
+
+static int audmp3_events_pending(struct audio *audio)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	return empty || audio->event_abort;
+}
+
+static void audmp3_reset_event_queue(struct audio *audio)
+{
+	unsigned long flags;
+	struct audmp3_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+			struct audmp3_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+			struct audmp3_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	return;
+}
+
+static long audmp3_process_event_req(struct audio *audio, void __user *arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audmp3_event *drv_evt = NULL;
+	int timeout;
+	unsigned long flags;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int) usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(
+			audio->event_wait, audmp3_events_pending(audio),
+			msecs_to_jiffies(timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(
+			audio->event_wait, audmp3_events_pending(audio));
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	rc = 0;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+			struct audmp3_event, list);
+		list_del(&drv_evt->list);
+	}
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else
+		rc = -1;
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	if (drv_evt->event_type == AUDIO_EVENT_WRITE_DONE ||
+	    drv_evt->event_type == AUDIO_EVENT_READ_DONE) {
+		mutex_lock(&audio->lock);
+		audmp3_pmem_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+				  drv_evt->payload.aio_buf.buf_len, 0);
+		mutex_unlock(&audio->lock);
+	}
+	if (!rc && copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audmp3_pmem_check(struct audio *audio,
+		void *vaddr, unsigned long len)
+{
+	struct audmp3_pmem_region *region_elt;
+	struct audmp3_pmem_region t = { .vaddr = vaddr, .len = len };
+
+	list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+		if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
+		    OVERLAPS(region_elt, &t)) {
+			MM_ERR("region (vaddr %p len %ld)"
+				" clashes with registered region"
+				" (vaddr %p paddr %p len %ld)\n",
+				vaddr, len,
+				region_elt->vaddr,
+				(void *)region_elt->paddr,
+				region_elt->len);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int audmp3_pmem_add(struct audio *audio,
+	struct msm_audio_pmem_info *info)
+{
+	unsigned long paddr, kvaddr, len;
+	struct file *file;
+	struct audmp3_pmem_region *region;
+	int rc = -EINVAL;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	region = kmalloc(sizeof(*region), GFP_KERNEL);
+
+	if (!region) {
+		rc = -ENOMEM;
+		goto end;
+	}
+
+	if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) {
+		kfree(region);
+		goto end;
+	}
+
+	rc = audmp3_pmem_check(audio, info->vaddr, len);
+	if (rc < 0) {
+		put_pmem_file(file);
+		kfree(region);
+		goto end;
+	}
+
+	region->vaddr = info->vaddr;
+	region->fd = info->fd;
+	region->paddr = paddr;
+	region->kvaddr = kvaddr;
+	region->len = len;
+	region->file = file;
+	region->ref_cnt = 0;
+	MM_DBG("add region paddr %lx vaddr %p, len %lu\n", region->paddr,
+			region->vaddr, region->len);
+	list_add_tail(&region->list, &audio->pmem_region_queue);
+end:
+	return rc;
+}
+
+static int audmp3_pmem_remove(struct audio *audio,
+	struct msm_audio_pmem_info *info)
+{
+	struct audmp3_pmem_region *region;
+	struct list_head *ptr, *next;
+	int rc = -EINVAL;
+
+	MM_DBG("info fd %d vaddr %p\n", info->fd, info->vaddr);
+
+	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
+		region = list_entry(ptr, struct audmp3_pmem_region, list);
+
+		if ((region->fd == info->fd) &&
+		    (region->vaddr == info->vaddr)) {
+			if (region->ref_cnt) {
+				MM_DBG("region %p in use ref_cnt %d\n",
+						region, region->ref_cnt);
+				break;
+			}
+			MM_DBG("remove region fd %d vaddr %p \n",
+					info->fd, info->vaddr);
+			list_del(&region->list);
+			put_pmem_file(region->file);
+			kfree(region);
+			rc = 0;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static int audmp3_pmem_lookup_vaddr(struct audio *audio, void *addr,
+		     unsigned long len, struct audmp3_pmem_region **region)
+{
+	struct audmp3_pmem_region *region_elt;
+
+	int match_count = 0;
+
+	*region = NULL;
+
+	/* returns physical address or zero */
+	list_for_each_entry(region_elt, &audio->pmem_region_queue,
+		list) {
+		if (addr >= region_elt->vaddr &&
+		    addr < region_elt->vaddr + region_elt->len &&
+		    addr + len <= region_elt->vaddr + region_elt->len) {
+			/* offset since we could pass vaddr inside a registerd
+			 * pmem buffer
+			 */
+
+			match_count++;
+			if (!*region)
+				*region = region_elt;
+		}
+	}
+
+	if (match_count > 1) {
+		MM_ERR("multiple hits for vaddr %p, len %ld\n", addr, len);
+		list_for_each_entry(region_elt,
+		  &audio->pmem_region_queue, list) {
+			if (addr >= region_elt->vaddr &&
+			    addr < region_elt->vaddr + region_elt->len &&
+			    addr + len <= region_elt->vaddr + region_elt->len)
+				MM_ERR("\t%p, %ld --> %p\n", region_elt->vaddr,
+						region_elt->len,
+						(void *)region_elt->paddr);
+		}
+	}
+
+	return *region ? 0 : -1;
+}
+
+unsigned long audmp3_pmem_fixup(struct audio *audio, void *addr,
+		    unsigned long len, int ref_up)
+{
+	struct audmp3_pmem_region *region;
+	unsigned long paddr;
+	int ret;
+
+	ret = audmp3_pmem_lookup_vaddr(audio, addr, len, &region);
+	if (ret) {
+		MM_ERR("lookup (%p, %ld) failed\n", addr, len);
+		return 0;
+	}
+	if (ref_up)
+		region->ref_cnt++;
+	else
+		region->ref_cnt--;
+	MM_DBG("found region %p ref_cnt %d\n", region, region->ref_cnt);
+	paddr = region->paddr + (addr - region->vaddr);
+	return paddr;
+}
+
+/* audio -> lock must be held at this point */
+static int audmp3_aio_buf_add(struct audio *audio, unsigned dir,
+	void __user *arg)
+{
+	unsigned long flags;
+	struct audmp3_buffer_node *buf_node;
+
+	buf_node = kmalloc(sizeof(*buf_node), GFP_KERNEL);
+
+	if (!buf_node)
+		return -ENOMEM;
+
+	if (copy_from_user(&buf_node->buf, arg, sizeof(buf_node->buf))) {
+		kfree(buf_node);
+		return -EFAULT;
+	}
+
+	MM_DBG("node %p dir %x buf_addr %p buf_len %d data_len \
+			%d\n", buf_node, dir,
+			buf_node->buf.buf_addr, buf_node->buf.buf_len,
+			buf_node->buf.data_len);
+
+	buf_node->paddr = audmp3_pmem_fixup(
+		audio, buf_node->buf.buf_addr,
+		buf_node->buf.buf_len, 1);
+
+	if (dir) {
+		/* write */
+		if (!buf_node->paddr ||
+		    (buf_node->paddr & 0x1) ||
+		    (buf_node->buf.data_len & 0x1) ||
+		    (!audio->pcm_feedback &&
+		    !buf_node->buf.data_len)) {
+			kfree(buf_node);
+			return -EINVAL;
+		}
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		list_add_tail(&buf_node->list, &audio->out_queue);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		audio->drv_ops.send_data(audio, 0);
+	} else {
+		/* read */
+		if (!buf_node->paddr ||
+		    (buf_node->paddr & 0x1) ||
+		    (buf_node->buf.buf_len < PCM_BUFSZ_MIN)) {
+			kfree(buf_node);
+			return -EINVAL;
+		}
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		list_add_tail(&buf_node->list, &audio->in_queue);
+		audio->drv_ops.buffer_refresh(audio);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	}
+
+	MM_DBG("Add buf_node %p paddr %lx\n", buf_node, buf_node->paddr);
+
+	return 0;
+}
+
+static int audio_enable_eq(struct audio *audio, int enable)
+{
+	if (audio->eq_enable == enable && !audio->eq_needs_commit)
+		return 0;
+
+	audio->eq_enable = enable;
+
+	if (audio->running) {
+		audpp_dsp_set_eq(audio->dec_id, enable, &audio->eq, POPP);
+		audio->eq_needs_commit = 0;
+	}
+	return 0;
+}
+
+static int audio_get_avsync_data(struct audio *audio,
+						struct msm_audio_stats *stats)
+{
+	int rc = -EINVAL;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (audio->dec_id == audio->avsync[0] && audio->avsync_flag) {
+		/* av_sync sample count */
+		stats->sample_count = (audio->avsync[2] << 16) |
+						(audio->avsync[3]);
+
+		/* av_sync byte_count */
+		stats->byte_count = (audio->avsync[5] << 16) |
+						(audio->avsync[6]);
+
+		audio->avsync_flag = 0;
+		rc = 0;
+	}
+	local_irq_restore(flags);
+	return rc;
+
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = -EINVAL;
+	unsigned long flags = 0;
+	uint16_t enable_mask;
+	int enable;
+	int prev_state;
+
+	MM_DBG("cmd = %d\n", cmd);
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+
+		audio->avsync_flag = 0;
+		memset(&stats, 0, sizeof(stats));
+		if (audpp_query_avsync(audio->dec_id) < 0)
+			return rc;
+
+		rc = wait_event_interruptible_timeout(audio->avsync_wait,
+				(audio->avsync_flag == 1),
+				msecs_to_jiffies(AUDPP_AVSYNC_EVENT_TIMEOUT));
+
+		if (rc < 0)
+			return rc;
+		else if ((rc > 0) || ((rc == 0) && (audio->avsync_flag == 1))) {
+			if (audio_get_avsync_data(audio, &stats) < 0)
+				return rc;
+
+			if (copy_to_user((void *)arg, &stats, sizeof(stats)))
+				return -EFAULT;
+			return 0;
+		} else
+			return -EAGAIN;
+	}
+
+	switch (cmd) {
+	case AUDIO_ENABLE_AUDPP:
+		if (copy_from_user(&enable_mask, (void *) arg,
+						sizeof(enable_mask))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		enable = (enable_mask & EQ_ENABLE) ? 1 : 0;
+		audio_enable_eq(audio, enable);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+	case AUDIO_SET_VOLUME:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.volume = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_PAN:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.pan = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_EQ:
+		prev_state = audio->eq_enable;
+		audio->eq_enable = 0;
+		if (copy_from_user(&audio->eq.num_bands, (void *) arg,
+				sizeof(audio->eq) -
+				(AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2))) {
+			rc = -EFAULT;
+			break;
+		}
+		audio->eq_enable = prev_state;
+		audio->eq_needs_commit = 1;
+		rc = 0;
+		break;
+	}
+
+	if (-EINVAL != rc)
+		return rc;
+
+	if (cmd == AUDIO_GET_EVENT) {
+		MM_DBG(" AUDIO_GET_EVENT\n");
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audmp3_process_event_req(audio,
+				(void __user *) arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		return rc;
+	}
+
+	if (cmd == AUDIO_ABORT_GET_EVENT) {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		MM_DBG("AUDIO_START\n");
+		rc = audio_enable(audio);
+		if (!rc) {
+			rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+			MM_INFO("dec_state %d rc = %d\n", audio->dec_state, rc);
+
+			if (audio->dec_state != MSM_AUD_DECODER_STATE_SUCCESS)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		break;
+	case AUDIO_STOP:
+		MM_DBG("AUDIO_STOP\n");
+		rc = audio_disable(audio);
+		audio->stopped = 1;
+		audio_ioport_reset(audio);
+		audio->stopped = 0;
+		break;
+	case AUDIO_FLUSH:
+		MM_DBG("AUDIO_FLUSH\n");
+		audio->rflush = 1;
+		audio->wflush = 1;
+		audio_ioport_reset(audio);
+		if (audio->running) {
+			audpp_flush(audio->dec_id);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		break;
+	case AUDIO_OUTPORT_FLUSH:
+		MM_DBG("AUDIO_OUTPORT_FLUSH\n");
+		audio->rflush = 1;
+		if (audio->drv_status & ADRV_STATUS_AIO_INTF) {
+			audio->drv_ops.in_flush(audio);
+		} else {
+			wake_up(&audio->read_wait);
+			mutex_lock(&audio->read_lock);
+			audio->drv_ops.in_flush(audio);
+			mutex_unlock(&audio->read_lock);
+		}
+		audplay_outport_flush(audio);
+		rc = wait_event_interruptible(audio->read_wait,
+				!audio->rflush);
+		if (rc < 0) {
+			MM_ERR("AUDPLAY_OUTPORT_FLUSH interrupted\n");
+			rc = -EINTR;
+		}
+		break;
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (copy_from_user(&config, (void *) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (config.channel_count == 1) {
+			config.channel_count = AUDPP_CMD_PCM_INTF_MONO_V;
+		} else if (config.channel_count == 2) {
+			config.channel_count = AUDPP_CMD_PCM_INTF_STEREO_V;
+		} else {
+			rc = -EINVAL;
+			break;
+		}
+		audio->mfield = config.meta_field;
+		audio->out_sample_rate = config.sample_rate;
+		audio->out_channel_mode = config.channel_count;
+		rc = 0;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_size = (audio->out_dma_sz >> 1);
+		config.buffer_count = 2;
+		config.sample_rate = audio->out_sample_rate;
+		if (audio->out_channel_mode == AUDPP_CMD_PCM_INTF_MONO_V)
+			config.channel_count = 1;
+		else
+			config.channel_count = 2;
+		config.meta_field = 0;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void *) arg, &config, sizeof(config)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	}
+	case AUDIO_GET_PCM_CONFIG:{
+		struct msm_audio_pcm_config config;
+		config.pcm_feedback = audio->pcm_feedback;
+		config.buffer_count = PCM_BUF_MAX_COUNT;
+		config.buffer_size = PCM_BUFSZ_MIN;
+		if (copy_to_user((void *)arg, &config,
+			 sizeof(config)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	}
+	case AUDIO_SET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			if (copy_from_user
+			    (&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+
+			if (config.pcm_feedback != audio->pcm_feedback) {
+				MM_ERR("Not sufficient permission to"
+					 "change the playback mode\n");
+				rc = -EACCES;
+				break;
+			}
+			if (audio->drv_status & ADRV_STATUS_AIO_INTF) {
+				rc = 0;
+				break;
+			}
+
+			if ((config.buffer_count > PCM_BUF_MAX_COUNT) ||
+			    (config.buffer_count == 1))
+				config.buffer_count = PCM_BUF_MAX_COUNT;
+
+			if (config.buffer_size < PCM_BUFSZ_MIN)
+				config.buffer_size = PCM_BUFSZ_MIN;
+
+			/* Check if pcm feedback is required */
+			if ((config.pcm_feedback) && (!audio->read_data)) {
+				MM_DBG("allocate PCM buffer %d\n",
+					config.buffer_count *
+					config.buffer_size);
+				audio->read_phys =
+					allocate_contiguous_ebi_nomap(
+							config.buffer_size *
+							config.buffer_count,
+							SZ_4K);
+				if (!audio->read_phys) {
+					rc = -ENOMEM;
+					break;
+				}
+				audio->map_v_read = ioremap(
+							audio->read_phys,
+							config.buffer_size *
+							config.buffer_count);
+				if (IS_ERR(audio->map_v_read)) {
+					MM_ERR("failed to map read buffer"
+							" physical address\n");
+					rc = -ENOMEM;
+					free_contiguous_memory_by_paddr(
+							audio->read_phys);
+				} else {
+					uint8_t index;
+					uint32_t offset = 0;
+					audio->read_data =
+						audio->map_v_read;
+					audio->buf_refresh = 0;
+					audio->pcm_buf_count =
+					    config.buffer_count;
+					audio->read_next = 0;
+					audio->fill_next = 0;
+
+					for (index = 0;
+					     index < config.buffer_count;
+					     index++) {
+						audio->in[index].data =
+						    audio->read_data + offset;
+						audio->in[index].addr =
+						    audio->read_phys + offset;
+						audio->in[index].size =
+						    config.buffer_size;
+						audio->in[index].used = 0;
+						offset += config.buffer_size;
+					}
+					rc = 0;
+					MM_DBG("read buf: phy addr \
+						0x%08x kernel addr 0x%08x\n",
+						audio->read_phys,
+						(int)audio->read_data);
+				}
+			} else {
+				rc = 0;
+			}
+			break;
+		}
+	case AUDIO_PAUSE:
+		MM_DBG("AUDIO_PAUSE %ld\n", arg);
+		rc = audpp_pause(audio->dec_id, (int) arg);
+		break;
+
+	case AUDIO_GET_STREAM_INFO:{
+		if (audio->stream_info.sample_rate == 0) {
+			/* haven't received DSP stream event,
+			the stream info is not updated */
+			rc = -EPERM;
+			break;
+		}
+		if (copy_to_user((void *)arg, &audio->stream_info,
+			sizeof(struct msm_audio_bitstream_info)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	}
+	case AUDIO_GET_BITSTREAM_ERROR_INFO:{
+		if ((audio->bitstream_error_info.err_msg_indicator &
+				AUDPLAY_STREAM_INFO_MSG_MASK) ==
+				AUDPLAY_STREAM_INFO_MSG_MASK) {
+			/* haven't received bitstream error info event,
+			the bitstream error info is not updated */
+			rc = -EPERM;
+			break;
+		}
+		if (copy_to_user((void *)arg, &audio->bitstream_error_info,
+			sizeof(struct msm_audio_bitstream_error_info)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	}
+
+	case AUDIO_REGISTER_PMEM: {
+			struct msm_audio_pmem_info info;
+			MM_DBG("AUDIO_REGISTER_PMEM\n");
+			if (copy_from_user(&info, (void *) arg, sizeof(info)))
+				rc = -EFAULT;
+			else
+				rc = audmp3_pmem_add(audio, &info);
+			break;
+		}
+
+	case AUDIO_DEREGISTER_PMEM: {
+			struct msm_audio_pmem_info info;
+			MM_DBG("AUDIO_DEREGISTER_PMEM\n");
+			if (copy_from_user(&info, (void *) arg, sizeof(info)))
+				rc = -EFAULT;
+			else
+				rc = audmp3_pmem_remove(audio, &info);
+			break;
+		}
+	case AUDIO_ASYNC_WRITE:
+		if (audio->drv_status & ADRV_STATUS_FSYNC)
+			rc = -EBUSY;
+		else
+			rc = audmp3_aio_buf_add(audio, 1, (void __user *) arg);
+		break;
+
+	case AUDIO_ASYNC_READ:
+		if (audio->pcm_feedback)
+			rc = audmp3_aio_buf_add(audio, 0, (void __user *) arg);
+		else
+			rc = -EPERM;
+		break;
+	case AUDIO_GET_SESSION_ID:
+		if (copy_to_user((void *) arg, &audio->dec_id,
+					sizeof(unsigned short)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	case AUDIO_SET_ERR_THRESHOLD_VALUE:
+		if (copy_from_user(&audio->bitstream_error_threshold_value,
+					(void *)arg, sizeof(uint32_t)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+/* Only useful in tunnel-mode */
+int audmp3_async_fsync(struct audio *audio)
+{
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	/* Blocking client sends more data */
+	mutex_lock(&audio->lock);
+	audio->drv_status |= ADRV_STATUS_FSYNC;
+	mutex_unlock(&audio->lock);
+
+	mutex_lock(&audio->write_lock);
+	/* pcm dmamiss message is sent continously
+	 * when decoder is starved so no race
+	 * condition concern
+	 */
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->teos && audio->out_needed &&
+		list_empty(&audio->out_queue))
+		|| audio->wflush || audio->stopped);
+
+	if (audio->stopped || audio->wflush)
+		rc = -EBUSY;
+
+	mutex_unlock(&audio->write_lock);
+	mutex_lock(&audio->lock);
+	audio->drv_status &= ~ADRV_STATUS_FSYNC;
+	mutex_unlock(&audio->lock);
+
+	return rc;
+}
+
+int audmp3_sync_fsync(struct audio *audio)
+{
+	struct buffer *frame;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(!audio->out[0].used &&
+		!audio->out[1].used &&
+		audio->out_needed) || audio->wflush);
+
+	if (rc < 0)
+		goto done;
+	else if (audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (audio->reserved) {
+		MM_DBG("send reserved byte\n");
+		frame = audio->out + audio->out_tail;
+		((char *) frame->data)[0] = audio->rsv_byte;
+		((char *) frame->data)[1] = 0;
+		frame->used = 2;
+		audio->drv_ops.send_data(audio, 0);
+
+		rc = wait_event_interruptible(audio->write_wait,
+			(!audio->out[0].used &&
+			!audio->out[1].used &&
+			audio->out_needed) || audio->wflush);
+
+		if (rc < 0)
+			goto done;
+		else if (audio->wflush) {
+			rc = -EBUSY;
+			goto done;
+		}
+	}
+
+	/* pcm dmamiss message is sent continously
+	 * when decoder is starved so no race
+	 * condition concern
+	 */
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		audio->teos || audio->wflush);
+
+	if (audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+	return rc;
+}
+
+int audmp3_fsync(struct file *file, loff_t ppos1, loff_t ppos2, int datasync)
+{
+	struct audio *audio = file->private_data;
+
+	if (!audio->running || audio->pcm_feedback)
+		return -EINVAL;
+
+	return audio->drv_ops.fsync(audio);
+}
+
+static ssize_t audio_read(struct file *file, char __user *buf, size_t count,
+			  loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	int rc = 0;
+
+	if (audio->drv_status & ADRV_STATUS_AIO_INTF)
+		return -EPERM;
+	else if (!audio->pcm_feedback)
+		return 0; /* PCM feedback disabled. Nothing to read */
+
+	mutex_lock(&audio->read_lock);
+	MM_DBG("%d \n",	count);
+	while (count > 0) {
+		rc = wait_event_interruptible_timeout(
+			audio->read_wait,
+			(audio->in[audio->read_next].
+			used > 0) || (audio->stopped)
+			|| (audio->rflush),
+			msecs_to_jiffies(MSM_AUD_BUFFER_UPDATE_WAIT_MS));
+
+		if (rc == 0) {
+			rc = -ETIMEDOUT;
+			break;
+		} else if (rc < 0)
+			break;
+
+		if (audio->stopped || audio->rflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (count < audio->in[audio->read_next].used) {
+			/* Read must happen in frame boundary. Since
+			 * driver does not know frame size, read count
+			 * must be greater or equal
+			 * to size of PCM samples
+			 */
+			MM_DBG("no partial frame done reading\n");
+			break;
+		} else {
+			MM_DBG("read from in[%d]\n", audio->read_next);
+
+			if (copy_to_user
+			    (buf, audio->in[audio->read_next].data,
+			     audio->in[audio->read_next].used)) {
+				MM_ERR("invalid addr %x \n", (unsigned int)buf);
+				rc = -EFAULT;
+				break;
+			}
+			count -= audio->in[audio->read_next].used;
+			buf += audio->in[audio->read_next].used;
+			audio->in[audio->read_next].used = 0;
+			if ((++audio->read_next) == audio->pcm_buf_count)
+				audio->read_next = 0;
+			break;	/* Force to exit while loop
+				 * to prevent output thread
+				 * sleep too long if data is
+				 * not ready at this moment.
+				 */
+		}
+	}
+
+	/* don't feed output buffer to HW decoder during flushing
+	 * buffer refresh command will be sent once flush completes
+	 * send buf refresh command here can confuse HW decoder
+	 */
+	if (audio->buf_refresh && !audio->rflush) {
+		audio->buf_refresh = 0;
+		MM_DBG("kick start pcm feedback again\n");
+		audio->drv_ops.buffer_refresh(audio);
+	}
+
+	mutex_unlock(&audio->read_lock);
+
+	if (buf > start)
+		rc = buf - start;
+
+	MM_DBG("read %d bytes\n", rc);
+	return rc;
+}
+
+static int audmp3_process_eos(struct audio *audio,
+		const char __user *buf_start, unsigned short mfield_size)
+{
+	int rc = 0;
+	struct buffer *frame;
+	char *buf_ptr;
+
+	if (audio->reserved) {
+		MM_DBG("flush reserve byte\n");
+		frame = audio->out + audio->out_head;
+		buf_ptr = frame->data;
+		rc = wait_event_interruptible(audio->write_wait,
+			(frame->used == 0)
+			|| (audio->stopped)
+			|| (audio->wflush));
+		if (rc < 0)
+			goto done;
+		if (audio->stopped || audio->wflush) {
+			rc = -EBUSY;
+			goto done;
+		}
+
+		buf_ptr[0] = audio->rsv_byte;
+		buf_ptr[1] = 0;
+		audio->out_head ^= 1;
+		frame->mfield_sz = 0;
+		frame->used = 2;
+		audio->reserved = 0;
+		audio->drv_ops.send_data(audio, 0);
+	}
+
+	frame = audio->out + audio->out_head;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->out_needed &&
+		audio->out[0].used == 0 &&
+		audio->out[1].used == 0)
+		|| (audio->stopped)
+		|| (audio->wflush));
+
+	if (rc < 0)
+		goto done;
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (copy_from_user(frame->data, buf_start, mfield_size)) {
+		rc = -EFAULT;
+		goto done;
+	}
+
+	frame->mfield_sz = mfield_size;
+	audio->out_head ^= 1;
+	frame->used = mfield_size;
+	audio->drv_ops.send_data(audio, 0);
+done:
+	return rc;
+}
+
+static ssize_t audio_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	char *cpy_ptr;
+	int rc = 0, eos_condition = AUDMP3_EOS_NONE;
+	unsigned dsize;
+	unsigned short mfield_size = 0;
+
+	if (audio->drv_status & ADRV_STATUS_AIO_INTF)
+		return -EPERM;
+
+	MM_DBG("cnt=%d\n", count);
+
+	mutex_lock(&audio->write_lock);
+	while (count > 0) {
+		frame = audio->out + audio->out_head;
+		cpy_ptr = frame->data;
+		dsize = 0;
+		rc = wait_event_interruptible(audio->write_wait,
+					      (frame->used == 0)
+					      || (audio->stopped)
+						  || (audio->wflush));
+		if (rc < 0)
+			break;
+		if (audio->stopped || audio->wflush) {
+			rc = -EBUSY;
+			break;
+		}
+		if (audio->mfield) {
+			if (buf == start) {
+				/* Processing beginning of user buffer */
+				if (__get_user(mfield_size,
+					(unsigned short __user *) buf)) {
+					rc = -EFAULT;
+					break;
+				} else  if (mfield_size > count) {
+					rc = -EINVAL;
+					break;
+				}
+				MM_DBG("mf offset_val %x\n", mfield_size);
+				if (copy_from_user(cpy_ptr, buf, mfield_size)) {
+					rc = -EFAULT;
+					break;
+				}
+				/* Check if EOS flag is set and buffer has
+				 * contains just meta field
+				 */
+				if (cpy_ptr[AUDMP3_EOS_FLG_OFFSET] &
+						 AUDMP3_EOS_FLG_MASK) {
+					MM_DBG("EOS SET\n");
+					eos_condition = AUDMP3_EOS_SET;
+					if (mfield_size == count) {
+						buf += mfield_size;
+						break;
+					} else
+						cpy_ptr[AUDMP3_EOS_FLG_OFFSET]
+							&= ~AUDMP3_EOS_FLG_MASK;
+				}
+				cpy_ptr += mfield_size;
+				count -= mfield_size;
+				dsize += mfield_size;
+				buf += mfield_size;
+			} else {
+				mfield_size = 0;
+				MM_DBG("continuous buffer\n");
+			}
+			frame->mfield_sz = mfield_size;
+		}
+
+		if (audio->reserved) {
+			MM_DBG("append reserved byte %x\n", audio->rsv_byte);
+			*cpy_ptr = audio->rsv_byte;
+			xfer = (count > ((frame->size - mfield_size) - 1)) ?
+				(frame->size - mfield_size) - 1 : count;
+			cpy_ptr++;
+			dsize += 1;
+			audio->reserved = 0;
+		} else
+			xfer = (count > (frame->size - mfield_size)) ?
+				(frame->size - mfield_size) : count;
+
+		if (copy_from_user(cpy_ptr, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+
+		dsize += xfer;
+		if (dsize & 1) {
+			audio->rsv_byte = ((char *) frame->data)[dsize - 1];
+			MM_DBG("odd length buf reserve last byte %x\n",
+					audio->rsv_byte);
+			audio->reserved = 1;
+			dsize--;
+		}
+		count -= xfer;
+		buf += xfer;
+
+		if (dsize > 0) {
+			audio->out_head ^= 1;
+			frame->used = dsize;
+			audio->drv_ops.send_data(audio, 0);
+		}
+	}
+	if (eos_condition == AUDMP3_EOS_SET)
+		rc = audmp3_process_eos(audio, start, mfield_size);
+	mutex_unlock(&audio->write_lock);
+	if (!rc) {
+		if (buf > start)
+			return buf - start;
+	}
+	return rc;
+}
+
+static void audmp3_reset_pmem_region(struct audio *audio)
+{
+	struct audmp3_pmem_region *region;
+	struct list_head *ptr, *next;
+
+	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
+		region = list_entry(ptr, struct audmp3_pmem_region, list);
+		list_del(&region->list);
+		put_pmem_file(region->file);
+		kfree(region);
+	}
+
+	return;
+}
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	MM_INFO("audio instance 0x%08x freeing\n", (int)audio);
+	mutex_lock(&audio->lock);
+	auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->dec_id);
+	audio_disable(audio);
+	audio->drv_ops.out_flush(audio);
+	audio->drv_ops.in_flush(audio);
+	audmp3_reset_pmem_region(audio);
+
+	msm_adsp_put(audio->audplay);
+	audpp_adec_free(audio->dec_id);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&audio->suspend_ctl.node);
+#endif
+	audio->opened = 0;
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audmp3_reset_event_queue(audio);
+	if (audio->data) {
+		iounmap(audio->map_v_write);
+		free_contiguous_memory_by_paddr(audio->phys);
+	}
+	if (audio->read_data) {
+		iounmap(audio->map_v_read);
+		free_contiguous_memory_by_paddr(audio->read_phys);
+	}
+	mutex_unlock(&audio->lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio);
+	return 0;
+}
+
+static void audmp3_post_event(struct audio *audio, int type,
+	union msm_audio_event_payload payload)
+{
+	struct audmp3_event *e_node = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+			struct audmp3_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audmp3_event), GFP_ATOMIC);
+		if (!e_node) {
+			MM_ERR("No mem to post event %d\n", type);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	wake_up(&audio->event_wait);
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audmp3_suspend(struct early_suspend *h)
+{
+	struct audmp3_suspend_ctl *ctl =
+		container_of(h, struct audmp3_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audmp3_post_event(ctl->audio, AUDIO_EVENT_SUSPEND, payload);
+}
+
+static void audmp3_resume(struct early_suspend *h)
+{
+	struct audmp3_suspend_ctl *ctl =
+		container_of(h, struct audmp3_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audmp3_post_event(ctl->audio, AUDIO_EVENT_RESUME, payload);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audmp3_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audmp3_debug_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 4096;
+	static char buffer[4096];
+	int n = 0, i;
+	struct audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "enabled %d\n", audio->enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "pcm_feedback %d\n", audio->pcm_feedback);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_buf_sz %d\n", audio->out[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "pcm_buf_count %d \n", audio->pcm_buf_count);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "pcm_buf_sz %d \n", audio->in[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "volume %x \n", audio->vol_pan.volume);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "sample rate %d \n", audio->out_sample_rate);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		"channel mode %d \n", audio->out_channel_mode);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "rflush %d\n", audio->rflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "running %d \n", audio->running);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				"dec state %d \n", audio->dec_state);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_needed %d \n", audio->out_needed);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_head %d \n", audio->out_head);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_tail %d \n", audio->out_tail);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out[0].used %d \n", audio->out[0].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out[1].used %d \n", audio->out[1].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "buffer_refresh %d \n", audio->buf_refresh);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "read_next %d \n", audio->read_next);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "fill_next %d \n", audio->fill_next);
+	for (i = 0; i < audio->pcm_buf_count; i++)
+		n += scnprintf(buffer + n, debug_bufmax - n,
+			"in[%d].size %d \n", i, audio->in[i].used);
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audmp3_debug_fops = {
+	.read = audmp3_debug_read,
+	.open = audmp3_debug_open,
+};
+#endif
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+
+	struct audio *audio = NULL;
+	int rc, i, dec_attrb, decid;
+	struct audmp3_event *e_node = NULL;
+	unsigned pmem_sz = DMASZ_MAX;
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_mp3_" + 5];
+#endif
+
+	/* Allocate audio instance, set to zero */
+	audio = kzalloc(sizeof(struct audio), GFP_KERNEL);
+	if (!audio) {
+		MM_ERR("no memory to allocate audio instance \n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	MM_INFO("audio instance 0x%08x created\n", (int)audio);
+
+	/* Allocate the decoder */
+	dec_attrb = AUDDEC_DEC_MP3;
+	if ((file->f_mode & FMODE_WRITE) &&
+			(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_NONTUNNEL;
+		audio->pcm_feedback = NON_TUNNEL_MODE_PLAYBACK;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_TUNNEL;
+		audio->pcm_feedback = TUNNEL_MODE_PLAYBACK;
+	} else {
+		kfree(audio);
+		rc = -EACCES;
+		goto done;
+	}
+
+	decid = audpp_adec_alloc(dec_attrb, &audio->module_name,
+			&audio->queue_id);
+	if (decid < 0) {
+		MM_ERR("No free decoder available, freeing instance 0x%08x\n",
+				(int)audio);
+		rc = -ENODEV;
+		kfree(audio);
+		goto done;
+	}
+	audio->dec_id = decid & MSM_AUD_DECODER_MASK;
+
+	/* AIO interface */
+	if (file->f_flags & O_NONBLOCK) {
+		MM_DBG("set to aio interface\n");
+		audio->drv_status |= ADRV_STATUS_AIO_INTF;
+		audio->drv_ops.pcm_buf_update = audmp3_async_pcm_buf_update;
+		audio->drv_ops.buffer_refresh = audmp3_async_buffer_refresh;
+		audio->drv_ops.send_data = audmp3_async_send_data;
+		audio->drv_ops.out_flush = audmp3_async_flush;
+		audio->drv_ops.in_flush = audmp3_async_flush_pcm_buf;
+		audio->drv_ops.fsync = audmp3_async_fsync;
+	} else {
+		MM_DBG("set to std io interface\n");
+		while (pmem_sz >= DMASZ_MIN) {
+			MM_DBG("pmemsz = %d\n", pmem_sz);
+			audio->phys = allocate_contiguous_ebi_nomap(pmem_sz,
+									SZ_4K);
+			if (audio->phys) {
+				audio->map_v_write = ioremap(
+							audio->phys, pmem_sz);
+				if (IS_ERR(audio->map_v_write)) {
+					MM_ERR("failed to map write physical"
+						" address , freeing instance"
+						"0x%08x\n", (int)audio);
+					rc = -ENOMEM;
+					free_contiguous_memory_by_paddr(
+								audio->phys);
+					audpp_adec_free(audio->dec_id);
+					kfree(audio);
+					goto done;
+				}
+				audio->data = audio->map_v_write;
+				MM_DBG("write buf: phy addr 0x%08x kernel addr\
+					0x%08x\n", audio->phys,\
+					(int)audio->data);
+				break;
+			} else if (pmem_sz == DMASZ_MIN) {
+				MM_ERR("could not allocate write buffers, \
+						freeing instance 0x%08x\n",
+						(int)audio);
+				rc = -ENOMEM;
+				audpp_adec_free(audio->dec_id);
+				kfree(audio);
+				goto done;
+			} else
+				pmem_sz >>= 1;
+		}
+		audio->out_dma_sz = pmem_sz;
+		audio->drv_ops.pcm_buf_update = audio_update_pcm_buf_entry;
+		audio->drv_ops.buffer_refresh = audplay_buffer_refresh;
+		audio->drv_ops.send_data = audplay_send_data;
+		audio->drv_ops.out_flush = audio_flush;
+		audio->drv_ops.in_flush = audio_flush_pcm_buf;
+		audio->drv_ops.fsync = audmp3_sync_fsync;
+		audio->out[0].data = audio->data + 0;
+		audio->out[0].addr = audio->phys + 0;
+		audio->out[0].size = (audio->out_dma_sz >> 1);
+
+		audio->out[1].data = audio->data + audio->out[0].size;
+		audio->out[1].addr = audio->phys + audio->out[0].size;
+		audio->out[1].size = audio->out[0].size;
+	}
+
+	rc = msm_adsp_get(audio->module_name, &audio->audplay,
+		&audplay_adsp_ops, audio);
+
+	if (rc) {
+		MM_ERR("failed to get %s module freeing instance 0x%08x\n",
+				audio->module_name, (int)audio);
+		goto err;
+	}
+
+	/* Initialize all locks of audio instance */
+	mutex_init(&audio->lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->get_event_lock);
+	spin_lock_init(&audio->dsp_lock);
+	init_waitqueue_head(&audio->write_wait);
+	init_waitqueue_head(&audio->read_wait);
+	INIT_LIST_HEAD(&audio->out_queue);
+	INIT_LIST_HEAD(&audio->in_queue);
+	INIT_LIST_HEAD(&audio->pmem_region_queue);
+	INIT_LIST_HEAD(&audio->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+	init_waitqueue_head(&audio->wait);
+	init_waitqueue_head(&audio->event_wait);
+	spin_lock_init(&audio->event_queue_lock);
+	init_waitqueue_head(&audio->avsync_wait);
+
+	audio->out_sample_rate = 44100;
+	audio->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V;
+	audio->vol_pan.volume = 0x2000;
+	audio->bitstream_error_threshold_value =
+		BITSTREAM_ERROR_THRESHOLD_VALUE;
+
+	audio->drv_ops.out_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+
+	audio->device_events = AUDDEV_EVT_DEV_RDY
+				|AUDDEV_EVT_DEV_RLS |
+				AUDDEV_EVT_STREAM_VOL_CHG;
+
+	rc = auddev_register_evt_listner(audio->device_events,
+					AUDDEV_CLNT_DEC,
+					audio->dec_id,
+					mp3_listner,
+					(void *)audio);
+	if (rc) {
+		MM_ERR("%s: failed to register listner\n", __func__);
+		goto event_err;
+	}
+
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_mp3_%04x", audio->dec_id);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+			NULL, (void *) audio, &audmp3_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		MM_DBG("debugfs_create_file failed\n");
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	audio->suspend_ctl.node.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+	audio->suspend_ctl.node.resume = audmp3_resume;
+	audio->suspend_ctl.node.suspend = audmp3_suspend;
+	audio->suspend_ctl.audio = audio;
+	register_early_suspend(&audio->suspend_ctl.node);
+#endif
+	for (i = 0; i < AUDMP3_EVENT_NUM; i++) {
+		e_node = kmalloc(sizeof(struct audmp3_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			MM_ERR("event pkt alloc failed\n");
+			break;
+		}
+	}
+	memset(&audio->stream_info, 0, sizeof(struct msm_audio_bitstream_info));
+	memset(&audio->bitstream_error_info, 0,
+			sizeof(struct msm_audio_bitstream_info));
+done:
+	return rc;
+event_err:
+	msm_adsp_put(audio->audplay);
+err:
+	if (audio->data) {
+		iounmap(audio->map_v_write);
+		free_contiguous_memory_by_paddr(audio->phys);
+	}
+	audpp_adec_free(audio->dec_id);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_mp3_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audio_open,
+	.release	= audio_release,
+	.read		= audio_read,
+	.write		= audio_write,
+	.unlocked_ioctl	= audio_ioctl,
+	.fsync = audmp3_fsync,
+};
+
+struct miscdevice audio_mp3_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_mp3",
+	.fops	= &audio_mp3_fops,
+};
+
+static int __init audio_init(void)
+{
+	return misc_register(&audio_mp3_misc);
+}
+
+static void __exit audio_exit(void)
+{
+	misc_deregister(&audio_mp3_misc);
+}
+
+module_init(audio_init);
+module_exit(audio_exit);
+
+MODULE_DESCRIPTION("MSM MP3 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_mvs.c b/arch/arm/mach-msm/qdsp5v2/audio_mvs.c
new file mode 100644
index 0000000..fae2401
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/audio_mvs.c
@@ -0,0 +1,1754 @@
+/* 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
+ * 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/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/kthread.h>
+#include <linux/list.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+#include <linux/wakelock.h>
+#include <linux/msm_audio_mvs.h>
+#include <linux/slab.h>
+#include <mach/msm_rpcrouter.h>
+
+#define MVS_PROG 0x30000014
+#define MVS_VERS 0x00030001
+#define MVS_VERS_COMP_VER4 0x00040001
+#define MVS_VERS_COMP_VER5 0x00050001
+
+#define MVS_CLIENT_ID_VOIP 0x00000003
+
+#define MVS_ACQUIRE_PROC 4
+#define MVS_ENABLE_PROC 5
+#define MVS_RELEASE_PROC 6
+#define MVS_AMR_SET_AMR_MODE_PROC 7
+#define MVS_AMR_SET_AWB_MODE_PROC 8
+#define MVS_VOC_SET_FRAME_RATE_PROC 10
+#define MVS_GSM_SET_DTX_MODE_PROC 11
+#define MVS_G729A_SET_MODE_PROC 12
+#define MVS_G711_GET_MODE_PROC 14
+#define MVS_G711_SET_MODE_PROC 15
+#define MVS_G711A_GET_MODE_PROC 16
+#define MVS_G711A_SET_MODE_PROC 17
+#define MVS_G722_SET_MODE_PROC 20
+#define MVS_G722_GET_MODE_PROC 21
+#define MVS_SET_DTX_MODE_PROC 22
+
+#define MVS_EVENT_CB_TYPE_PROC 1
+#define MVS_PACKET_UL_FN_TYPE_PROC 2
+#define MVS_PACKET_DL_FN_TYPE_PROC 3
+
+#define MVS_CB_FUNC_ID 0xAAAABBBB
+#define MVS_UL_CB_FUNC_ID 0xBBBBCCCC
+#define MVS_DL_CB_FUNC_ID 0xCCCCDDDD
+
+#define MVS_FRAME_MODE_VOC_TX 1
+#define MVS_FRAME_MODE_VOC_RX 2
+#define MVS_FRAME_MODE_AMR_UL 3
+#define MVS_FRAME_MODE_AMR_DL 4
+#define MVS_FRAME_MODE_GSM_UL 5
+#define MVS_FRAME_MODE_GSM_DL 6
+#define MVS_FRAME_MODE_HR_UL 7
+#define MVS_FRAME_MODE_HR_DL 8
+#define MVS_FRAME_MODE_G711_UL 9
+#define MVS_FRAME_MODE_G711_DL 10
+#define MVS_FRAME_MODE_PCM_UL 13
+#define MVS_FRAME_MODE_PCM_DL 14
+#define MVS_FRAME_MODE_G729A_UL 17
+#define MVS_FRAME_MODE_G729A_DL 18
+#define MVS_FRAME_MODE_G711A_UL 19
+#define MVS_FRAME_MODE_G711A_DL 20
+#define MVS_FRAME_MODE_G722_UL 21
+#define MVS_FRAME_MODE_G722_DL 22
+
+
+
+#define MVS_PKT_CONTEXT_ISR 0x00000001
+
+#define RPC_TYPE_REQUEST 0
+#define RPC_TYPE_REPLY 1
+
+#define RPC_STATUS_FAILURE 0
+#define RPC_STATUS_SUCCESS 1
+#define RPC_STATUS_REJECT 1
+
+#define RPC_COMMON_HDR_SZ  (sizeof(uint32_t) * 2)
+#define RPC_REQUEST_HDR_SZ (sizeof(struct rpc_request_hdr))
+#define RPC_REPLY_HDR_SZ   (sizeof(uint32_t) * 3)
+
+enum audio_mvs_state_type {
+	AUDIO_MVS_CLOSED,
+	AUDIO_MVS_OPENED,
+	AUDIO_MVS_STARTED,
+	AUDIO_MVS_STOPPED
+};
+
+enum audio_mvs_event_type {
+	AUDIO_MVS_COMMAND,
+	AUDIO_MVS_MODE,
+	AUDIO_MVS_NOTIFY
+};
+
+enum audio_mvs_cmd_status_type {
+	AUDIO_MVS_CMD_FAILURE,
+	AUDIO_MVS_CMD_BUSY,
+	AUDIO_MVS_CMD_SUCCESS
+};
+
+enum audio_mvs_mode_status_type {
+	AUDIO_MVS_MODE_NOT_AVAIL,
+	AUDIO_MVS_MODE_INIT,
+	AUDIO_MVS_MODE_READY
+};
+
+enum audio_mvs_pkt_status_type {
+	AUDIO_MVS_PKT_NORMAL,
+	AUDIO_MVS_PKT_FAST,
+	AUDIO_MVS_PKT_SLOW
+};
+
+/* Parameters required for MVS acquire. */
+struct rpc_audio_mvs_acquire_args {
+	uint32_t client_id;
+	uint32_t cb_func_id;
+};
+
+struct audio_mvs_acquire_msg {
+	struct rpc_request_hdr rpc_hdr;
+	struct rpc_audio_mvs_acquire_args acquire_args;
+};
+
+/* Parameters required for MVS enable. */
+struct rpc_audio_mvs_enable_args {
+	uint32_t client_id;
+	uint32_t mode;
+	uint32_t ul_cb_func_id;
+	uint32_t dl_cb_func_id;
+	uint32_t context;
+};
+
+struct audio_mvs_enable_msg {
+	struct rpc_request_hdr rpc_hdr;
+	struct rpc_audio_mvs_enable_args enable_args;
+};
+
+/* Parameters required for MVS release. */
+struct audio_mvs_release_msg {
+	struct rpc_request_hdr rpc_hdr;
+	uint32_t client_id;
+};
+
+/* Parameters required for setting AMR mode. */
+struct audio_mvs_set_amr_mode_msg {
+	struct rpc_request_hdr rpc_hdr;
+	uint32_t amr_mode;
+};
+
+/* Parameters required for setting DTX. */
+struct audio_mvs_set_dtx_mode_msg {
+	struct rpc_request_hdr rpc_hdr;
+	uint32_t dtx_mode;
+};
+
+/* Parameters required for setting EVRC mode. */
+struct audio_mvs_set_voc_mode_msg {
+	struct rpc_request_hdr rpc_hdr;
+	uint32_t max_rate;
+	uint32_t min_rate;
+};
+
+/* Parameters for G711 mode */
+struct audio_mvs_set_g711_mode_msg {
+	struct rpc_request_hdr rpc_hdr;
+	uint32_t g711_mode;
+};
+
+/* Parameters for G729 mode */
+struct audio_mvs_set_g729_mode_msg {
+	struct rpc_request_hdr rpc_hdr;
+	uint32_t g729_mode;
+};
+
+/* Parameters for G722 mode */
+struct audio_mvs_set_g722_mode_msg {
+	struct rpc_request_hdr rpc_hdr;
+	uint32_t g722_mode;
+};
+
+
+/* Parameters for G711A mode */
+struct audio_mvs_set_g711A_mode_msg {
+	struct rpc_request_hdr rpc_hdr;
+	uint32_t g711A_mode;
+};
+
+/* Parameters for EFR FR and HR mode */
+struct audio_mvs_set_efr_mode_msg {
+	struct rpc_request_hdr rpc_hdr;
+	uint32_t efr_mode;
+};
+
+union audio_mvs_event_data {
+	struct mvs_ev_command_type {
+		uint32_t event;
+		uint32_t client_id;
+		uint32_t cmd_status;
+	} mvs_ev_command_type;
+
+	struct mvs_ev_mode_type {
+		uint32_t event;
+		uint32_t client_id;
+		uint32_t mode_status;
+		uint32_t mode;
+	} mvs_ev_mode_type;
+
+	struct mvs_ev_notify_type {
+		uint32_t event;
+		uint32_t client_id;
+		uint32_t buf_dir;
+		uint32_t max_frames;
+	} mvs_ev_notify_type;
+};
+
+struct audio_mvs_cb_func_args {
+	uint32_t cb_func_id;
+	uint32_t valid_ptr;
+	uint32_t event;
+	union audio_mvs_event_data event_data;
+};
+
+struct audio_mvs_frame_info_hdr {
+	uint32_t frame_mode;
+	uint32_t mvs_mode;
+	uint16_t buf_free_cnt;
+};
+
+struct audio_mvs_ul_reply {
+	struct rpc_reply_hdr reply_hdr;
+	uint32_t valid_pkt_status_ptr;
+	uint32_t pkt_status;
+};
+
+struct audio_mvs_dl_cb_func_args {
+	uint32_t cb_func_id;
+
+	uint32_t valid_ptr;
+	uint32_t frame_mode;
+	uint32_t frame_mode_ignore;
+
+	struct audio_mvs_frame_info_hdr frame_info_hdr;
+
+	uint32_t amr_frame;
+	uint32_t amr_mode;
+};
+/*general codec parameters includes AMR, G711A, PCM
+G729, VOC and HR vocoders
+*/
+struct gnr_cdc_param {
+	uint32_t param1;
+	uint32_t param2;
+	uint32_t valid_pkt_status_ptr;
+	uint32_t pkt_status;
+};
+/*G711 codec parameter*/
+struct g711_param {
+	uint32_t param1;
+	uint32_t valid_pkt_status_ptr;
+	uint32_t pkt_status;
+};
+
+union codec_param {
+	struct gnr_cdc_param gnr_arg;
+	struct g711_param g711_arg;
+};
+
+struct audio_mvs_dl_reply {
+	struct rpc_reply_hdr reply_hdr;
+
+	uint32_t voc_pkt[Q5V2_MVS_MAX_VOC_PKT_SIZE/4];
+
+	uint32_t valid_frame_info_ptr;
+	uint32_t frame_mode;
+	uint32_t frame_mode_again;
+
+	struct audio_mvs_frame_info_hdr frame_info_hdr;
+	union codec_param cdc_param;
+};
+
+struct audio_mvs_buf_node {
+	struct list_head list;
+	struct q5v2_msm_audio_mvs_frame frame;
+};
+
+/* Each buffer is 20 ms, queue holds 200 ms of data. */
+#define MVS_MAX_Q_LEN 10
+
+struct audio_mvs_info_type {
+	enum audio_mvs_state_type state;
+	uint32_t frame_mode;
+	uint32_t mvs_mode;
+	uint32_t buf_free_cnt;
+	uint32_t rate_type;
+	uint32_t dtx_mode;
+
+	struct msm_rpc_endpoint *rpc_endpt;
+	uint32_t rpc_prog;
+	uint32_t rpc_ver;
+	uint32_t rpc_status;
+
+	uint8_t *mem_chunk;
+
+	struct list_head in_queue;
+	struct list_head free_in_queue;
+
+	struct list_head out_queue;
+	struct list_head free_out_queue;
+
+	struct task_struct *task;
+
+	wait_queue_head_t wait;
+	wait_queue_head_t mode_wait;
+	wait_queue_head_t out_wait;
+
+	struct mutex lock;
+	struct mutex in_lock;
+	struct mutex out_lock;
+
+	struct wake_lock suspend_lock;
+	struct wake_lock idle_lock;
+};
+
+static struct audio_mvs_info_type audio_mvs_info;
+
+static int audio_mvs_setup_mode(struct audio_mvs_info_type *audio)
+{
+	int rc = 0;
+
+	pr_debug("%s:\n", __func__);
+
+	switch (audio->mvs_mode) {
+	case MVS_MODE_AMR:
+	case MVS_MODE_AMR_WB: {
+		struct audio_mvs_set_amr_mode_msg set_amr_mode_msg;
+		struct audio_mvs_set_dtx_mode_msg set_dtx_mode_msg;
+
+		/* Set AMR mode. */
+		memset(&set_amr_mode_msg, 0, sizeof(set_amr_mode_msg));
+		set_amr_mode_msg.amr_mode = cpu_to_be32(audio->rate_type);
+
+		if (audio->mvs_mode == MVS_MODE_AMR) {
+			msm_rpc_setup_req(&set_amr_mode_msg.rpc_hdr,
+					  audio->rpc_prog,
+					  audio->rpc_ver,
+					  MVS_AMR_SET_AMR_MODE_PROC);
+		} else {
+			msm_rpc_setup_req(&set_amr_mode_msg.rpc_hdr,
+					  audio->rpc_prog,
+					  audio->rpc_ver,
+					  MVS_AMR_SET_AWB_MODE_PROC);
+		}
+
+		audio->rpc_status = RPC_STATUS_FAILURE;
+		rc = msm_rpc_write(audio->rpc_endpt,
+				   &set_amr_mode_msg,
+				   sizeof(set_amr_mode_msg));
+
+		if (rc >= 0) {
+			pr_debug("%s: RPC write for set amr mode done\n",
+					__func__);
+
+			/* Save the MVS configuration information. */
+			audio->frame_mode = MVS_FRAME_MODE_AMR_DL;
+
+			/* Disable DTX. */
+			memset(&set_dtx_mode_msg, 0, sizeof(set_dtx_mode_msg));
+			set_dtx_mode_msg.dtx_mode = cpu_to_be32(0);
+
+			msm_rpc_setup_req(&set_dtx_mode_msg.rpc_hdr,
+					  audio->rpc_prog,
+					  audio->rpc_ver,
+					  MVS_SET_DTX_MODE_PROC);
+
+			audio->rpc_status = RPC_STATUS_FAILURE;
+			rc = msm_rpc_write(audio->rpc_endpt,
+					   &set_dtx_mode_msg,
+					   sizeof(set_dtx_mode_msg));
+
+			if (rc >= 0) {
+				pr_debug("%s: RPC write for set dtx done\n",
+						 __func__);
+
+				rc = 0;
+			}
+		} else {
+			pr_err("%s: RPC write for set amr mode failed %d\n",
+			       __func__, rc);
+		}
+		break;
+	}
+	case MVS_MODE_PCM:
+	case MVS_MODE_LINEAR_PCM: {
+		/* PCM does not have any params to be set.
+		Save the MVS configuration information. */
+		audio->rate_type = MVS_AMR_MODE_UNDEF;
+		audio->frame_mode = MVS_FRAME_MODE_PCM_DL;
+		break;
+	}
+	case MVS_MODE_IS127:
+	case MVS_MODE_IS733:
+	case MVS_MODE_4GV_NB:
+	case MVS_MODE_4GV_WB: {
+		struct audio_mvs_set_voc_mode_msg set_voc_mode_msg;
+
+		/* Set EVRC mode. */
+		memset(&set_voc_mode_msg, 0, sizeof(set_voc_mode_msg));
+		set_voc_mode_msg.min_rate = cpu_to_be32(audio->rate_type);
+		set_voc_mode_msg.max_rate = cpu_to_be32(audio->rate_type);
+
+		msm_rpc_setup_req(&set_voc_mode_msg.rpc_hdr,
+				  audio->rpc_prog,
+				  audio->rpc_ver,
+				  MVS_VOC_SET_FRAME_RATE_PROC);
+
+		audio->rpc_status = RPC_STATUS_FAILURE;
+		rc = msm_rpc_write(audio->rpc_endpt,
+				   &set_voc_mode_msg,
+				   sizeof(set_voc_mode_msg));
+
+		if (rc >= 0) {
+			pr_debug("%s: RPC write for set voc mode done\n",
+					__func__);
+
+			/* Save the MVS configuration information. */
+			audio->frame_mode = MVS_FRAME_MODE_VOC_RX;
+
+			rc = 0;
+		} else {
+			pr_err("%s: RPC write for set voc mode failed %d\n",
+			       __func__, rc);
+		}
+		break;
+	}
+	case MVS_MODE_G711: {
+		struct audio_mvs_set_g711_mode_msg set_g711_mode_msg;
+
+		/* Set G711 mode. */
+		memset(&set_g711_mode_msg, 0, sizeof(set_g711_mode_msg));
+		set_g711_mode_msg.g711_mode = cpu_to_be32(audio->rate_type);
+
+		pr_debug("%s: mode of g711:%d\n",
+			       __func__, set_g711_mode_msg.g711_mode);
+
+		msm_rpc_setup_req(&set_g711_mode_msg.rpc_hdr,
+				 audio->rpc_prog,
+				 audio->rpc_ver,
+				 MVS_G711_SET_MODE_PROC);
+
+		audio->rpc_status = RPC_STATUS_FAILURE;
+		rc = msm_rpc_write(audio->rpc_endpt,
+				  &set_g711_mode_msg,
+				  sizeof(set_g711_mode_msg));
+
+		if (rc >= 0) {
+			pr_debug("%s: RPC write for set g711 mode done\n",
+					__func__);
+			/* Save the MVS configuration information. */
+			audio->frame_mode = MVS_FRAME_MODE_G711_DL;
+
+			rc = 0;
+		} else {
+		       pr_err("%s: RPC write for set g711 mode failed %d\n",
+			      __func__, rc);
+		}
+		break;
+	}
+	case MVS_MODE_G729A: {
+		struct audio_mvs_set_g729_mode_msg set_g729_mode_msg;
+
+		/* Set G729 mode. */
+		memset(&set_g729_mode_msg, 0, sizeof(set_g729_mode_msg));
+		set_g729_mode_msg.g729_mode = cpu_to_be32(audio->dtx_mode);
+
+		pr_debug("%s: mode of g729:%d\n",
+			       __func__, set_g729_mode_msg.g729_mode);
+
+		msm_rpc_setup_req(&set_g729_mode_msg.rpc_hdr,
+				 audio->rpc_prog,
+				 audio->rpc_ver,
+				 MVS_G729A_SET_MODE_PROC);
+
+		audio->rpc_status = RPC_STATUS_FAILURE;
+		rc = msm_rpc_write(audio->rpc_endpt,
+				  &set_g729_mode_msg,
+				  sizeof(set_g729_mode_msg));
+
+		if (rc >= 0) {
+			pr_debug("%s: RPC write for set g729 mode done\n",
+			       __func__);
+
+			/* Save the MVS configuration information. */
+			audio->frame_mode = MVS_FRAME_MODE_G729A_DL;
+
+			rc = 0;
+		} else {
+		       pr_err("%s: RPC write for set g729 mode failed %d\n",
+			      __func__, rc);
+		}
+		break;
+	}
+	case MVS_MODE_G722: {
+		struct audio_mvs_set_g722_mode_msg set_g722_mode_msg;
+
+		/* Set G722 mode. */
+		memset(&set_g722_mode_msg, 0, sizeof(set_g722_mode_msg));
+		set_g722_mode_msg.g722_mode = cpu_to_be32(audio->rate_type);
+
+		pr_debug("%s: mode of g722:%d\n",
+		      __func__, set_g722_mode_msg.g722_mode);
+
+		msm_rpc_setup_req(&set_g722_mode_msg.rpc_hdr,
+			audio->rpc_prog,
+			audio->rpc_ver,
+			MVS_G722_SET_MODE_PROC);
+
+		audio->rpc_status = RPC_STATUS_FAILURE;
+		rc = msm_rpc_write(audio->rpc_endpt,
+			 &set_g722_mode_msg,
+			 sizeof(set_g722_mode_msg));
+
+		if (rc >= 0) {
+			pr_debug("%s: RPC write for set g722 mode done\n",
+			__func__);
+
+			/* Save the MVS configuration information. */
+			audio->frame_mode = MVS_FRAME_MODE_G722_DL;
+
+			rc = 0;
+		}
+		break;
+	}
+	case MVS_MODE_G711A: {
+		struct audio_mvs_set_g711A_mode_msg set_g711A_mode_msg;
+		struct audio_mvs_set_dtx_mode_msg set_dtx_mode_msg;
+
+		/* Set G711A mode. */
+		memset(&set_g711A_mode_msg, 0, sizeof(set_g711A_mode_msg));
+		set_g711A_mode_msg.g711A_mode = cpu_to_be32(audio->rate_type);
+
+		pr_debug("%s: mode of g711A:%d\n",
+		       __func__, set_g711A_mode_msg.g711A_mode);
+
+		msm_rpc_setup_req(&set_g711A_mode_msg.rpc_hdr,
+			 audio->rpc_prog,
+			 audio->rpc_ver,
+			 MVS_G711A_SET_MODE_PROC);
+
+		audio->rpc_status = RPC_STATUS_FAILURE;
+		rc = msm_rpc_write(audio->rpc_endpt,
+			  &set_g711A_mode_msg,
+			  sizeof(set_g711A_mode_msg));
+
+		if (rc >= 0) {
+			pr_debug("%s: RPC write for set g711A mode done\n",
+				       __func__);
+
+			/* Save the MVS configuration information. */
+			audio->frame_mode = MVS_FRAME_MODE_G711A_DL;
+			/* Set DTX MODE. */
+			memset(&set_dtx_mode_msg, 0, sizeof(set_dtx_mode_msg));
+			set_dtx_mode_msg.dtx_mode =
+				cpu_to_be32((audio->dtx_mode));
+
+			msm_rpc_setup_req(&set_dtx_mode_msg.rpc_hdr,
+					  audio->rpc_prog,
+					  audio->rpc_ver,
+					  MVS_SET_DTX_MODE_PROC);
+
+			audio->rpc_status = RPC_STATUS_FAILURE;
+			rc = msm_rpc_write(audio->rpc_endpt,
+					   &set_dtx_mode_msg,
+					   sizeof(set_dtx_mode_msg));
+
+			if (rc >= 0) {
+				pr_debug("%s: RPC write for set dtx done\n",
+						 __func__);
+
+				rc = 0;
+			}
+			rc = 0;
+		} else {
+		pr_err("%s: RPC write for set g711A mode failed %d\n",
+		      __func__, rc);
+		}
+		break;
+	}
+	case MVS_MODE_EFR:
+	case MVS_MODE_FR:
+	case MVS_MODE_HR: {
+		struct audio_mvs_set_efr_mode_msg set_efr_mode_msg;
+
+		/* Set G729 mode. */
+		memset(&set_efr_mode_msg, 0, sizeof(set_efr_mode_msg));
+		set_efr_mode_msg.efr_mode = cpu_to_be32(audio->dtx_mode);
+
+		pr_debug("%s: mode of EFR, FR and HR:%d\n",
+			       __func__, set_efr_mode_msg.efr_mode);
+
+		msm_rpc_setup_req(&set_efr_mode_msg.rpc_hdr,
+				 audio->rpc_prog,
+				 audio->rpc_ver,
+				 MVS_GSM_SET_DTX_MODE_PROC);
+
+		audio->rpc_status = RPC_STATUS_FAILURE;
+		rc = msm_rpc_write(audio->rpc_endpt,
+				  &set_efr_mode_msg,
+				  sizeof(set_efr_mode_msg));
+
+		if (rc >= 0) {
+			pr_debug("%s: RPC write for set EFR, FR and HR mode done\n",
+			       __func__);
+
+			/* Save the MVS configuration information. */
+			if ((audio->mvs_mode == MVS_MODE_EFR) ||
+				(audio->mvs_mode == MVS_MODE_FR))
+				audio->frame_mode = MVS_FRAME_MODE_GSM_DL;
+			if (audio->mvs_mode == MVS_MODE_HR)
+				audio->frame_mode = MVS_FRAME_MODE_HR_DL;
+
+			rc = 0;
+		} else {
+		       pr_err("%s: RPC write for set EFR, FR and HR mode failed %d\n",
+			      __func__, rc);
+		}
+		break;
+	}
+	default:
+		rc = -EINVAL;
+		pr_err("Default case\n");
+	}
+	return rc;
+}
+
+static int audio_mvs_setup(struct audio_mvs_info_type *audio)
+{
+	int rc = 0;
+	struct audio_mvs_enable_msg enable_msg;
+
+	pr_debug("%s:\n", __func__);
+
+	/* Enable MVS. */
+	memset(&enable_msg, 0, sizeof(enable_msg));
+	enable_msg.enable_args.client_id = cpu_to_be32(MVS_CLIENT_ID_VOIP);
+	enable_msg.enable_args.mode = cpu_to_be32(audio->mvs_mode);
+	enable_msg.enable_args.ul_cb_func_id = cpu_to_be32(MVS_UL_CB_FUNC_ID);
+	enable_msg.enable_args.dl_cb_func_id = cpu_to_be32(MVS_DL_CB_FUNC_ID);
+	enable_msg.enable_args.context = cpu_to_be32(MVS_PKT_CONTEXT_ISR);
+
+	msm_rpc_setup_req(&enable_msg.rpc_hdr,
+			  audio->rpc_prog,
+			  audio->rpc_ver,
+			  MVS_ENABLE_PROC);
+
+	audio->rpc_status = RPC_STATUS_FAILURE;
+	rc = msm_rpc_write(audio->rpc_endpt, &enable_msg, sizeof(enable_msg));
+
+	if (rc >= 0) {
+		pr_debug("%s: RPC write for enable done\n", __func__);
+
+		rc = wait_event_timeout(audio->mode_wait,
+				(audio->rpc_status != RPC_STATUS_FAILURE),
+				10 * HZ);
+
+		if (rc > 0) {
+			pr_debug("%s: Wait event for enable succeeded\n",
+				 __func__);
+			rc = audio_mvs_setup_mode(audio);
+			if (rc < 0) {
+				pr_err("%s: Unknown MVS mode %d\n",
+				       __func__, audio->mvs_mode);
+			}
+			pr_err("rc value after mode setup: %d\n", rc);
+		} else {
+			pr_err("%s: Wait event for enable failed %d\n",
+			       __func__, rc);
+		}
+	} else {
+		pr_err("%s: RPC write for enable failed %d\n", __func__, rc);
+	}
+
+	return rc;
+}
+
+static int audio_mvs_start(struct audio_mvs_info_type *audio)
+{
+	int rc = 0;
+	struct audio_mvs_acquire_msg acquire_msg;
+
+	pr_info("%s:\n", __func__);
+
+	/* Prevent sleep. */
+	wake_lock(&audio->suspend_lock);
+	wake_lock(&audio->idle_lock);
+
+	/* Acquire MVS. */
+	memset(&acquire_msg, 0, sizeof(acquire_msg));
+	acquire_msg.acquire_args.client_id = cpu_to_be32(MVS_CLIENT_ID_VOIP);
+	acquire_msg.acquire_args.cb_func_id = cpu_to_be32(MVS_CB_FUNC_ID);
+
+	msm_rpc_setup_req(&acquire_msg.rpc_hdr,
+			  audio->rpc_prog,
+			  audio->rpc_ver,
+			  MVS_ACQUIRE_PROC);
+
+	audio->rpc_status = RPC_STATUS_FAILURE;
+	rc = msm_rpc_write(audio->rpc_endpt,
+			   &acquire_msg,
+			   sizeof(acquire_msg));
+
+	if (rc >= 0) {
+		pr_debug("%s: RPC write for acquire done\n", __func__);
+
+		rc = wait_event_timeout(audio->wait,
+			(audio->rpc_status != RPC_STATUS_FAILURE),
+			1 * HZ);
+
+		if (rc > 0) {
+
+			rc = audio_mvs_setup(audio);
+
+			if (rc == 0)
+				audio->state = AUDIO_MVS_STARTED;
+
+		} else {
+			pr_err("%s: Wait event for acquire failed %d\n",
+			       __func__, rc);
+
+			rc = -EBUSY;
+		}
+	} else {
+		pr_err("%s: RPC write for acquire failed %d\n", __func__, rc);
+
+		rc = -EBUSY;
+	}
+
+	return rc;
+}
+
+static int audio_mvs_stop(struct audio_mvs_info_type *audio)
+{
+	int rc = 0;
+	struct audio_mvs_release_msg release_msg;
+
+	pr_info("%s:\n", __func__);
+
+	/* Release MVS. */
+	memset(&release_msg, 0, sizeof(release_msg));
+	release_msg.client_id = cpu_to_be32(MVS_CLIENT_ID_VOIP);
+
+	msm_rpc_setup_req(&release_msg.rpc_hdr,
+			  audio->rpc_prog,
+			  audio->rpc_ver,
+			  MVS_RELEASE_PROC);
+
+	audio->rpc_status = RPC_STATUS_FAILURE;
+	rc = msm_rpc_write(audio->rpc_endpt, &release_msg, sizeof(release_msg));
+
+	if (rc >= 0) {
+		pr_debug("%s: RPC write for release done\n", __func__);
+
+		rc = wait_event_timeout(audio->mode_wait,
+				(audio->rpc_status != RPC_STATUS_FAILURE),
+				1 * HZ);
+
+		if (rc > 0) {
+			pr_debug("%s: Wait event for release succeeded\n",
+				 __func__);
+
+			audio->state = AUDIO_MVS_STOPPED;
+
+			/* Un-block read in case it is waiting for data. */
+			wake_up(&audio->out_wait);
+			rc = 0;
+		} else {
+			pr_err("%s: Wait event for release failed %d\n",
+			       __func__, rc);
+		}
+	} else {
+		pr_err("%s: RPC write for release failed %d\n", __func__, rc);
+	}
+
+	/* Allow sleep. */
+	wake_unlock(&audio->suspend_lock);
+	wake_unlock(&audio->idle_lock);
+
+	return rc;
+}
+
+static void audio_mvs_process_rpc_request(uint32_t procedure,
+					  uint32_t xid,
+					  void *data,
+					  uint32_t length,
+					  struct audio_mvs_info_type *audio)
+{
+	int rc = 0;
+
+	pr_debug("%s:\n", __func__);
+
+	switch (procedure) {
+	case MVS_EVENT_CB_TYPE_PROC: {
+		struct audio_mvs_cb_func_args *args = data;
+		struct rpc_reply_hdr reply_hdr;
+
+		pr_debug("%s: MVS CB CB_FUNC_ID 0x%x\n",
+			 __func__, be32_to_cpu(args->cb_func_id));
+
+		if (be32_to_cpu(args->valid_ptr)) {
+			uint32_t event_type = be32_to_cpu(args->event);
+
+			pr_debug("%s: MVS CB event type %d\n",
+				 __func__, be32_to_cpu(args->event));
+
+			if (event_type == AUDIO_MVS_COMMAND) {
+				uint32_t cmd_status = be32_to_cpu(
+			args->event_data.mvs_ev_command_type.cmd_status);
+
+				pr_debug("%s: MVS CB command status %d\n",
+					 __func__, cmd_status);
+
+				if (cmd_status == AUDIO_MVS_CMD_SUCCESS) {
+					audio->rpc_status = RPC_STATUS_SUCCESS;
+					wake_up(&audio->wait);
+				}
+
+			} else if (event_type == AUDIO_MVS_MODE) {
+				uint32_t mode_status = be32_to_cpu(
+				args->event_data.mvs_ev_mode_type.mode_status);
+
+				pr_debug("%s: MVS CB mode status %d\n",
+					 __func__, mode_status);
+
+				if (mode_status == AUDIO_MVS_MODE_READY) {
+					audio->rpc_status = RPC_STATUS_SUCCESS;
+					wake_up(&audio->mode_wait);
+				}
+			} else {
+				pr_err("%s: MVS CB unknown event type %d\n",
+				       __func__, event_type);
+			}
+		} else {
+			pr_err("%s: MVS CB event pointer not valid\n",
+			       __func__);
+		}
+
+		/* Send ack to modem. */
+		memset(&reply_hdr, 0, sizeof(reply_hdr));
+		reply_hdr.xid = cpu_to_be32(xid);
+		reply_hdr.type = cpu_to_be32(RPC_TYPE_REPLY);
+		reply_hdr.reply_stat = cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED);
+
+		reply_hdr.data.acc_hdr.accept_stat = cpu_to_be32(
+			RPC_ACCEPTSTAT_SUCCESS);
+		reply_hdr.data.acc_hdr.verf_flavor = 0;
+		reply_hdr.data.acc_hdr.verf_length = 0;
+
+		rc = msm_rpc_write(audio->rpc_endpt,
+				   &reply_hdr,
+				   sizeof(reply_hdr));
+
+		if (rc < 0)
+			pr_err("%s: RPC write for response failed %d\n",
+			       __func__, rc);
+
+		break;
+	}
+
+	case MVS_PACKET_UL_FN_TYPE_PROC: {
+		uint32_t *args = data;
+		uint32_t pkt_len;
+		uint32_t frame_mode;
+		struct audio_mvs_ul_reply ul_reply;
+		struct audio_mvs_buf_node *buf_node = NULL;
+
+		pr_debug("%s: MVS UL CB_FUNC_ID 0x%x\n",
+			 __func__, be32_to_cpu(*args));
+		args++;
+
+		pkt_len = be32_to_cpu(*args);
+		pr_debug("%s: UL pkt_len %d\n", __func__, pkt_len);
+		args++;
+
+		/* Copy the vocoder packets. */
+		mutex_lock(&audio->out_lock);
+
+		if (!list_empty(&audio->free_out_queue)) {
+			buf_node = list_first_entry(&audio->free_out_queue,
+						    struct audio_mvs_buf_node,
+						    list);
+			list_del(&buf_node->list);
+
+			memcpy(&buf_node->frame.voc_pkt[0], args, pkt_len);
+			buf_node->frame.len = pkt_len;
+			pkt_len = ALIGN(pkt_len, 4);
+			args = args + pkt_len/4;
+
+			pr_debug("%s: UL valid_ptr 0x%x\n",
+				 __func__, be32_to_cpu(*args));
+			args++;
+
+			frame_mode = be32_to_cpu(*args);
+			pr_debug("%s: UL frame_mode %d\n",
+				 __func__, frame_mode);
+			args++;
+
+			pr_debug("%s: UL frame_mode %d\n",
+				 __func__, be32_to_cpu(*args));
+			args++;
+
+			pr_debug("%s: UL frame_mode %d\n",
+				 __func__, be32_to_cpu(*args));
+			args++;
+
+			pr_debug("%s: UL mvs_mode %d\n",
+				 __func__, be32_to_cpu(*args));
+			args++;
+
+			pr_debug("%s: UL buf_free_cnt %d\n",
+				 __func__, be32_to_cpu(*args));
+			args++;
+
+			if (frame_mode == MVS_FRAME_MODE_AMR_UL) {
+				/* Extract AMR frame type. */
+				buf_node->frame.frame_type = be32_to_cpu(*args);
+
+				pr_debug("%s: UL AMR frame_type %d\n",
+					 __func__, be32_to_cpu(*args));
+			} else if (frame_mode == MVS_FRAME_MODE_PCM_UL) {
+				/* PCM don't have frame_type */
+				buf_node->frame.frame_type = 0;
+			} else if (frame_mode == MVS_FRAME_MODE_VOC_TX) {
+				/* Extracting EVRC current buffer frame rate*/
+				buf_node->frame.frame_type = be32_to_cpu(*args);
+
+				pr_debug("%s: UL EVRC frame_type %d\n",
+					__func__, be32_to_cpu(*args));
+			} else if (frame_mode == MVS_FRAME_MODE_G711_UL) {
+				/* Extract G711 frame type. */
+				buf_node->frame.frame_type = be32_to_cpu(*args);
+
+				pr_debug("%s: UL G711 frame_type %d\n",
+					__func__, be32_to_cpu(*args));
+			} else if (frame_mode == MVS_FRAME_MODE_G729A_UL) {
+				/* Extract G729 frame type. */
+				buf_node->frame.frame_type = be32_to_cpu(*args);
+
+				pr_debug("%s: UL G729 frame_type %d\n",
+					__func__, be32_to_cpu(*args));
+			} else if (frame_mode == MVS_FRAME_MODE_G722_UL) {
+				/* Extract G722 frame type. */
+				buf_node->frame.frame_type = be32_to_cpu(*args);
+
+				pr_debug("%s: UL G722 frame_type %d\n",
+				       __func__, be32_to_cpu(*args));
+			} else if (frame_mode == MVS_FRAME_MODE_G711A_UL) {
+				/* Extract G711A frame type. */
+				buf_node->frame.frame_type = be32_to_cpu(*args);
+
+				pr_debug("%s: UL G711A frame_type %d\n",
+				       __func__, be32_to_cpu(*args));
+			} else if ((frame_mode == MVS_FRAME_MODE_GSM_UL) ||
+				   (frame_mode == MVS_FRAME_MODE_HR_UL)) {
+				/* Extract EFR, FR and HR frame type. */
+				buf_node->frame.frame_type = be32_to_cpu(*args);
+
+				pr_debug("%s: UL EFR,FR,HR frame_type %d\n",
+					__func__, be32_to_cpu(*args));
+			} else {
+				pr_debug("%s: UL Unknown frame mode %d\n",
+				       __func__, frame_mode);
+			}
+
+			list_add_tail(&buf_node->list, &audio->out_queue);
+		} else {
+			pr_err("%s: UL data dropped, read is slow\n", __func__);
+		}
+
+		mutex_unlock(&audio->out_lock);
+
+		wake_up(&audio->out_wait);
+
+		/* Send UL message accept to modem. */
+		memset(&ul_reply, 0, sizeof(ul_reply));
+		ul_reply.reply_hdr.xid = cpu_to_be32(xid);
+		ul_reply.reply_hdr.type = cpu_to_be32(RPC_TYPE_REPLY);
+		ul_reply.reply_hdr.reply_stat = cpu_to_be32(
+			RPCMSG_REPLYSTAT_ACCEPTED);
+
+		ul_reply.reply_hdr.data.acc_hdr.accept_stat = cpu_to_be32(
+			RPC_ACCEPTSTAT_SUCCESS);
+		ul_reply.reply_hdr.data.acc_hdr.verf_flavor = 0;
+		ul_reply.reply_hdr.data.acc_hdr.verf_length = 0;
+
+		ul_reply.valid_pkt_status_ptr = cpu_to_be32(0x00000001);
+		ul_reply.pkt_status = cpu_to_be32(0x00000000);
+
+		rc = msm_rpc_write(audio->rpc_endpt,
+				   &ul_reply,
+				   sizeof(ul_reply));
+
+		if (rc < 0)
+			pr_err("%s: RPC write for UL response failed %d\n",
+			       __func__, rc);
+
+		break;
+	}
+
+	case MVS_PACKET_DL_FN_TYPE_PROC: {
+		struct audio_mvs_dl_cb_func_args *args = data;
+		struct audio_mvs_dl_reply dl_reply;
+		uint32_t frame_mode;
+		struct audio_mvs_buf_node *buf_node = NULL;
+
+		pr_debug("%s: MVS DL CB CB_FUNC_ID 0x%x\n",
+			 __func__, be32_to_cpu(args->cb_func_id));
+
+		frame_mode = be32_to_cpu(args->frame_mode);
+		pr_debug("%s: DL frame_mode %d\n", __func__, frame_mode);
+
+		/* Prepare and send the DL packets to modem. */
+		memset(&dl_reply, 0, sizeof(dl_reply));
+		dl_reply.reply_hdr.xid = cpu_to_be32(xid);
+		dl_reply.reply_hdr.type = cpu_to_be32(RPC_TYPE_REPLY);
+		dl_reply.reply_hdr.reply_stat = cpu_to_be32(
+			RPCMSG_REPLYSTAT_ACCEPTED);
+
+		dl_reply.reply_hdr.data.acc_hdr.accept_stat = cpu_to_be32(
+			RPC_ACCEPTSTAT_SUCCESS);
+		dl_reply.reply_hdr.data.acc_hdr.verf_flavor = 0;
+		dl_reply.reply_hdr.data.acc_hdr.verf_length = 0;
+
+		mutex_lock(&audio->in_lock);
+
+		if (!list_empty(&audio->in_queue)) {
+			buf_node = list_first_entry(&audio->in_queue,
+						    struct audio_mvs_buf_node,
+						    list);
+			list_del(&buf_node->list);
+
+			memcpy(&dl_reply.voc_pkt,
+			       &buf_node->frame.voc_pkt[0],
+			       buf_node->frame.len);
+
+			pr_debug("%s:frame mode %d\n", __func__, frame_mode);
+			if (frame_mode == MVS_FRAME_MODE_AMR_DL) {
+				dl_reply.cdc_param.gnr_arg.param1 = cpu_to_be32(
+					buf_node->frame.frame_type);
+				dl_reply.cdc_param.gnr_arg.param2 =
+						cpu_to_be32(audio->rate_type);
+				dl_reply.cdc_param.\
+						gnr_arg.valid_pkt_status_ptr =
+							cpu_to_be32(0x00000001);
+				dl_reply.cdc_param.gnr_arg.pkt_status =
+					cpu_to_be32(AUDIO_MVS_PKT_NORMAL);
+			} else if (frame_mode == MVS_FRAME_MODE_PCM_DL) {
+				dl_reply.cdc_param.gnr_arg.param1 = 0;
+				dl_reply.cdc_param.gnr_arg.param2 = 0;
+				dl_reply.cdc_param.\
+						gnr_arg.valid_pkt_status_ptr =
+							cpu_to_be32(0x00000001);
+				dl_reply.cdc_param.gnr_arg.pkt_status =
+					cpu_to_be32(AUDIO_MVS_PKT_NORMAL);
+			} else if (frame_mode == MVS_FRAME_MODE_VOC_RX) {
+				dl_reply.cdc_param.gnr_arg.param1 =
+				cpu_to_be32(buf_node->frame.frame_type);
+				dl_reply.cdc_param.gnr_arg.param2 = 0;
+				dl_reply.cdc_param.\
+						gnr_arg.valid_pkt_status_ptr =
+							cpu_to_be32(0x00000001);
+				dl_reply.cdc_param.gnr_arg.pkt_status =
+					cpu_to_be32(AUDIO_MVS_PKT_NORMAL);
+			} else if (frame_mode == MVS_FRAME_MODE_G711_DL) {
+				dl_reply.cdc_param.g711_arg.param1 =
+				cpu_to_be32(buf_node->frame.frame_type);
+				dl_reply.cdc_param.\
+						g711_arg.valid_pkt_status_ptr =
+							cpu_to_be32(0x00000001);
+				dl_reply.cdc_param.g711_arg.pkt_status =
+					cpu_to_be32(AUDIO_MVS_PKT_NORMAL);
+			} else if (frame_mode == MVS_FRAME_MODE_G729A_DL) {
+				dl_reply.cdc_param.gnr_arg.param1 = cpu_to_be32(
+				       buf_node->frame.frame_type);
+				dl_reply.cdc_param.gnr_arg.param2 =
+						cpu_to_be32(audio->rate_type);
+				dl_reply.cdc_param.\
+						gnr_arg.valid_pkt_status_ptr =
+							cpu_to_be32(0x00000001);
+				dl_reply.cdc_param.gnr_arg.pkt_status =
+					cpu_to_be32(AUDIO_MVS_PKT_NORMAL);
+			} else if (frame_mode == MVS_FRAME_MODE_G722_DL) {
+				dl_reply.cdc_param.gnr_arg.param1 = cpu_to_be32(
+				      buf_node->frame.frame_type);
+				dl_reply.cdc_param.gnr_arg.param2 =
+						cpu_to_be32(audio->rate_type);
+				dl_reply.cdc_param.\
+						gnr_arg.valid_pkt_status_ptr =
+							cpu_to_be32(0x00000001);
+				dl_reply.cdc_param.gnr_arg.pkt_status =
+					cpu_to_be32(AUDIO_MVS_PKT_NORMAL);
+			} else if (frame_mode == MVS_FRAME_MODE_G711A_DL) {
+				dl_reply.cdc_param.gnr_arg.param1 = cpu_to_be32(
+				       buf_node->frame.frame_type);
+				dl_reply.cdc_param.gnr_arg.param2 =
+						cpu_to_be32(audio->rate_type);
+				dl_reply.cdc_param.\
+						gnr_arg.valid_pkt_status_ptr =
+							cpu_to_be32(0x00000001);
+				dl_reply.cdc_param.gnr_arg.pkt_status =
+					cpu_to_be32(AUDIO_MVS_PKT_NORMAL);
+			} else if ((frame_mode == MVS_FRAME_MODE_GSM_DL) ||
+				   (frame_mode == MVS_FRAME_MODE_HR_DL)) {
+				dl_reply.cdc_param.gnr_arg.param1 = cpu_to_be32(
+				       buf_node->frame.frame_type);
+				dl_reply.cdc_param.gnr_arg.param2 =
+						cpu_to_be32(audio->rate_type);
+				dl_reply.cdc_param.\
+						gnr_arg.valid_pkt_status_ptr =
+							cpu_to_be32(0x00000001);
+				dl_reply.cdc_param.gnr_arg.pkt_status =
+					cpu_to_be32(AUDIO_MVS_PKT_NORMAL);
+			} else {
+				pr_err("%s: DL Unknown frame mode %d\n",
+				       __func__, frame_mode);
+			}
+			list_add_tail(&buf_node->list, &audio->free_in_queue);
+		} else {
+			pr_debug("%s: No DL data available to send to MVS\n",
+				 __func__);
+			if (frame_mode == MVS_FRAME_MODE_G711_DL) {
+				dl_reply.cdc_param.\
+						g711_arg.valid_pkt_status_ptr =
+							cpu_to_be32(0x00000001);
+				dl_reply.cdc_param.g711_arg.pkt_status =
+						cpu_to_be32(AUDIO_MVS_PKT_SLOW);
+			} else {
+				dl_reply.cdc_param.\
+						gnr_arg.valid_pkt_status_ptr =
+							cpu_to_be32(0x00000001);
+				dl_reply.cdc_param.gnr_arg.pkt_status =
+						cpu_to_be32(AUDIO_MVS_PKT_SLOW);
+			}
+		}
+
+		mutex_unlock(&audio->in_lock);
+
+		dl_reply.valid_frame_info_ptr = cpu_to_be32(0x00000001);
+
+		dl_reply.frame_mode = cpu_to_be32(audio->frame_mode);
+		dl_reply.frame_mode_again = cpu_to_be32(audio->frame_mode);
+
+		dl_reply.frame_info_hdr.frame_mode =
+			cpu_to_be32(audio->frame_mode);
+		dl_reply.frame_info_hdr.mvs_mode = cpu_to_be32(audio->mvs_mode);
+		dl_reply.frame_info_hdr.buf_free_cnt = 0;
+
+		rc = msm_rpc_write(audio->rpc_endpt,
+				   &dl_reply,
+				   sizeof(dl_reply));
+
+		if (rc < 0)
+			pr_err("%s: RPC write for DL response failed %d\n",
+			       __func__, rc);
+
+		break;
+	}
+
+	default:
+		pr_err("%s: Unknown CB type %d\n", __func__, procedure);
+	}
+}
+
+static int audio_mvs_thread(void *data)
+{
+	struct audio_mvs_info_type *audio = data;
+	struct rpc_request_hdr *rpc_hdr = NULL;
+
+	pr_info("%s:\n", __func__);
+
+	while (!kthread_should_stop()) {
+
+		int rpc_hdr_len = msm_rpc_read(audio->rpc_endpt,
+					       (void **) &rpc_hdr,
+					       -1,
+					       -1);
+
+		if (rpc_hdr_len < 0) {
+			pr_err("%s: RPC read failed %d\n",
+			       __func__, rpc_hdr_len);
+
+			break;
+		} else if (rpc_hdr_len < RPC_COMMON_HDR_SZ) {
+			continue;
+		} else {
+			uint32_t rpc_type = be32_to_cpu(rpc_hdr->type);
+			if (rpc_type == RPC_TYPE_REPLY) {
+				struct rpc_reply_hdr *rpc_reply =
+					(void *) rpc_hdr;
+				uint32_t reply_status;
+
+				if (rpc_hdr_len < RPC_REPLY_HDR_SZ)
+					continue;
+
+				reply_status =
+					be32_to_cpu(rpc_reply->reply_stat);
+
+				if (reply_status != RPCMSG_REPLYSTAT_ACCEPTED) {
+					/* If the command is not accepted, there
+					 * will be no response callback. Wake
+					 * the caller and report error. */
+					audio->rpc_status = RPC_STATUS_REJECT;
+
+					wake_up(&audio->wait);
+
+					pr_err("%s: RPC reply status denied\n",
+					       __func__);
+				}
+			} else if (rpc_type == RPC_TYPE_REQUEST) {
+				if (rpc_hdr_len < RPC_REQUEST_HDR_SZ)
+					continue;
+
+				audio_mvs_process_rpc_request(
+					be32_to_cpu(rpc_hdr->procedure),
+					be32_to_cpu(rpc_hdr->xid),
+					(void *) (rpc_hdr + 1),
+					(rpc_hdr_len - sizeof(*rpc_hdr)),
+					audio);
+			} else {
+				pr_err("%s: Unexpected RPC type %d\n",
+				       __func__, rpc_type);
+			}
+		}
+
+		kfree(rpc_hdr);
+		rpc_hdr = NULL;
+	}
+
+	pr_info("%s: MVS thread stopped\n", __func__);
+
+	return 0;
+}
+
+static int audio_mvs_alloc_buf(struct audio_mvs_info_type *audio)
+{
+	int i = 0;
+	struct audio_mvs_buf_node *buf_node = NULL;
+	struct list_head *ptr = NULL;
+	struct list_head *next = NULL;
+
+	pr_debug("%s:\n", __func__);
+
+	/* Allocate input buffers. */
+	for (i = 0; i < MVS_MAX_Q_LEN; i++) {
+			buf_node = kmalloc(sizeof(struct audio_mvs_buf_node),
+					   GFP_KERNEL);
+
+			if (buf_node != NULL) {
+				list_add_tail(&buf_node->list,
+					      &audio->free_in_queue);
+			} else {
+				pr_err("%s: No memory for IO buffers\n",
+				       __func__);
+				goto err;
+			}
+			buf_node = NULL;
+	}
+
+	/* Allocate output buffers. */
+	for (i = 0; i < MVS_MAX_Q_LEN; i++) {
+			buf_node = kmalloc(sizeof(struct audio_mvs_buf_node),
+					   GFP_KERNEL);
+
+			if (buf_node != NULL) {
+				list_add_tail(&buf_node->list,
+					      &audio->free_out_queue);
+			} else {
+				pr_err("%s: No memory for IO buffers\n",
+				       __func__);
+				goto err;
+			}
+			buf_node = NULL;
+	}
+
+	return 0;
+
+err:
+	list_for_each_safe(ptr, next, &audio->free_in_queue) {
+		buf_node = list_entry(ptr, struct audio_mvs_buf_node, list);
+		list_del(&buf_node->list);
+		kfree(buf_node);
+		buf_node = NULL;
+	}
+
+	ptr = next = NULL;
+	list_for_each_safe(ptr, next, &audio->free_out_queue) {
+		buf_node = list_entry(ptr, struct audio_mvs_buf_node, list);
+		list_del(&buf_node->list);
+		kfree(buf_node);
+		buf_node = NULL;
+	}
+
+	return -ENOMEM;
+}
+
+static void audio_mvs_free_buf(struct audio_mvs_info_type *audio)
+{
+	struct list_head *ptr = NULL;
+	struct list_head *next = NULL;
+	struct audio_mvs_buf_node *buf_node = NULL;
+
+	pr_debug("%s:\n", __func__);
+
+	mutex_lock(&audio->in_lock);
+	/* Free input buffers. */
+	list_for_each_safe(ptr, next, &audio->in_queue) {
+		buf_node = list_entry(ptr, struct audio_mvs_buf_node, list);
+		list_del(&buf_node->list);
+		kfree(buf_node);
+		buf_node = NULL;
+	}
+
+	ptr = next = NULL;
+	/* Free free_input buffers. */
+	list_for_each_safe(ptr, next, &audio->free_in_queue) {
+		buf_node = list_entry(ptr, struct audio_mvs_buf_node, list);
+		list_del(&buf_node->list);
+		kfree(buf_node);
+		buf_node = NULL;
+	}
+	mutex_unlock(&audio->in_lock);
+
+	mutex_lock(&audio->out_lock);
+	ptr = next = NULL;
+	/* Free output buffers. */
+	list_for_each_safe(ptr, next, &audio->out_queue) {
+		buf_node = list_entry(ptr, struct audio_mvs_buf_node, list);
+		list_del(&buf_node->list);
+		kfree(buf_node);
+		buf_node = NULL;
+	}
+
+	/* Free free_ioutput buffers. */
+	ptr = next = NULL;
+	list_for_each_safe(ptr, next, &audio->free_out_queue) {
+		buf_node = list_entry(ptr, struct audio_mvs_buf_node, list);
+		list_del(&buf_node->list);
+		kfree(buf_node);
+		buf_node = NULL;
+	}
+	mutex_unlock(&audio->out_lock);
+}
+
+static int audio_mvs_open(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+
+	pr_info("%s:\n", __func__);
+
+	mutex_lock(&audio_mvs_info.lock);
+
+	if (audio_mvs_info.state == AUDIO_MVS_CLOSED) {
+
+		if (audio_mvs_info.task != NULL ||
+			audio_mvs_info.rpc_endpt != NULL) {
+			rc = audio_mvs_alloc_buf(&audio_mvs_info);
+
+			if (rc == 0) {
+				audio_mvs_info.state = AUDIO_MVS_OPENED;
+				file->private_data = &audio_mvs_info;
+			}
+		}  else {
+			pr_err("%s: MVS thread and RPC end point do not exist\n",
+				   __func__);
+
+			rc = -ENODEV;
+		}
+	} else {
+		pr_err("%s: MVS driver exists, state %d\n",
+		       __func__, audio_mvs_info.state);
+
+		rc = -EBUSY;
+	}
+
+	mutex_unlock(&audio_mvs_info.lock);
+
+	return rc;
+}
+
+static int audio_mvs_release(struct inode *inode, struct file *file)
+{
+
+	struct audio_mvs_info_type *audio = file->private_data;
+
+	pr_info("%s:\n", __func__);
+
+	mutex_lock(&audio->lock);
+	if (audio->state == AUDIO_MVS_STARTED)
+		audio_mvs_stop(audio);
+	audio_mvs_free_buf(audio);
+	audio->state = AUDIO_MVS_CLOSED;
+	mutex_unlock(&audio->lock);
+
+	pr_debug("%s: Release done\n", __func__);
+	return 0;
+}
+
+static ssize_t audio_mvs_read(struct file *file,
+			      char __user *buf,
+			      size_t count,
+			      loff_t *pos)
+{
+	int rc = 0;
+	struct audio_mvs_buf_node *buf_node = NULL;
+	struct audio_mvs_info_type *audio = file->private_data;
+
+	pr_debug("%s:\n", __func__);
+
+	rc = wait_event_interruptible_timeout(audio->out_wait,
+			(!list_empty(&audio->out_queue) ||
+			 audio->state == AUDIO_MVS_STOPPED),
+			1 * HZ);
+
+	if (rc > 0) {
+		mutex_lock(&audio->out_lock);
+		if ((audio->state == AUDIO_MVS_STARTED) &&
+		    (!list_empty(&audio->out_queue))) {
+
+			if (count >= sizeof(struct q5v2_msm_audio_mvs_frame)) {
+				buf_node = list_first_entry(&audio->out_queue,
+						struct audio_mvs_buf_node,
+						list);
+				list_del(&buf_node->list);
+
+				rc = copy_to_user(buf,
+					&buf_node->frame,
+					sizeof(struct q5v2_msm_audio_mvs_frame)
+					);
+
+				if (rc == 0) {
+					rc = buf_node->frame.len +
+					    sizeof(buf_node->frame.frame_type) +
+					    sizeof(buf_node->frame.len);
+				} else {
+					pr_err("%s: Copy to user retuned %d",
+					       __func__, rc);
+
+					rc = -EFAULT;
+				}
+
+				list_add_tail(&buf_node->list,
+					      &audio->free_out_queue);
+			} else {
+				pr_err("%s: Read count %d < sizeof(frame) %d",
+				       __func__, count,
+				       sizeof(struct q5v2_msm_audio_mvs_frame));
+
+				rc = -ENOMEM;
+			}
+		} else {
+			pr_err("%s: Read performed in state %d\n",
+			       __func__, audio->state);
+
+			rc = -EPERM;
+		}
+		mutex_unlock(&audio->out_lock);
+
+	} else if (rc == 0) {
+		pr_err("%s: No UL data available\n", __func__);
+
+		rc = -ETIMEDOUT;
+	} else {
+		pr_err("%s: Read was interrupted\n", __func__);
+
+		rc = -ERESTARTSYS;
+	}
+
+	return rc;
+}
+
+static ssize_t audio_mvs_write(struct file *file,
+			       const char __user *buf,
+			       size_t count,
+			       loff_t *pos)
+{
+	int rc = 0;
+	struct audio_mvs_buf_node *buf_node = NULL;
+	struct audio_mvs_info_type *audio = file->private_data;
+
+	pr_debug("%s:\n", __func__);
+
+	mutex_lock(&audio->in_lock);
+	if (audio->state == AUDIO_MVS_STARTED) {
+		if (count <= sizeof(struct q5v2_msm_audio_mvs_frame)) {
+			if (!list_empty(&audio->free_in_queue)) {
+				buf_node =
+					list_first_entry(&audio->free_in_queue,
+						struct audio_mvs_buf_node,
+						list);
+				list_del(&buf_node->list);
+
+				rc = copy_from_user(&buf_node->frame,
+						    buf,
+						    count);
+
+				list_add_tail(&buf_node->list,
+					      &audio->in_queue);
+			} else {
+				pr_err("%s: No free DL buffs\n", __func__);
+			}
+		} else {
+			pr_err("%s: Write count %d < sizeof(frame) %d",
+			       __func__, count,
+			       sizeof(struct q5v2_msm_audio_mvs_frame));
+
+			rc = -ENOMEM;
+		}
+	} else {
+		pr_err("%s: Write performed in invalid state %d\n",
+		       __func__, audio->state);
+
+		rc = -EPERM;
+	}
+	mutex_unlock(&audio->in_lock);
+
+	return rc;
+}
+
+static long audio_mvs_ioctl(struct file *file,
+			    unsigned int cmd,
+			    unsigned long arg)
+{
+	int rc = 0;
+
+	struct audio_mvs_info_type *audio = file->private_data;
+
+	pr_info("%s:\n", __func__);
+
+	switch (cmd) {
+	case AUDIO_GET_MVS_CONFIG: {
+		struct msm_audio_mvs_config config;
+
+		pr_debug("%s: IOCTL GET_MVS_CONFIG\n", __func__);
+
+		mutex_lock(&audio->lock);
+		config.mvs_mode = audio->mvs_mode;
+		config.rate_type = audio->rate_type;
+		mutex_unlock(&audio->lock);
+
+		rc = copy_to_user((void *)arg, &config, sizeof(config));
+		if (rc == 0)
+			rc = sizeof(config);
+		else
+			pr_err("%s: Config copy failed %d\n", __func__, rc);
+
+		break;
+	}
+
+	case AUDIO_SET_MVS_CONFIG: {
+		struct msm_audio_mvs_config config;
+
+		pr_debug("%s: IOCTL SET_MVS_CONFIG\n", __func__);
+
+		rc = copy_from_user(&config, (void *)arg, sizeof(config));
+		if (rc == 0) {
+			mutex_lock(&audio->lock);
+
+			if (audio->state == AUDIO_MVS_OPENED) {
+				audio->mvs_mode = config.mvs_mode;
+				audio->rate_type = config.rate_type;
+				audio->dtx_mode = config.dtx_mode;
+			} else {
+				pr_err("%s: Set confg called in state %d\n",
+				       __func__, audio->state);
+
+				rc = -EPERM;
+			}
+
+			mutex_unlock(&audio->lock);
+		} else {
+			pr_err("%s: Config copy failed %d\n", __func__, rc);
+		}
+
+		break;
+	}
+
+	case AUDIO_START: {
+		pr_debug("%s: IOCTL START\n", __func__);
+
+		mutex_lock(&audio->lock);
+
+		if (audio->state == AUDIO_MVS_OPENED ||
+		    audio->state == AUDIO_MVS_STOPPED) {
+			rc = audio_mvs_start(audio);
+
+			if (rc != 0)
+				audio_mvs_stop(audio);
+		} else {
+			pr_err("%s: Start called in invalid state %d\n",
+			       __func__, audio->state);
+
+			rc = -EPERM;
+		}
+
+		mutex_unlock(&audio->lock);
+
+		break;
+	}
+
+	case AUDIO_STOP: {
+		pr_debug("%s: IOCTL STOP\n", __func__);
+
+		mutex_lock(&audio->lock);
+
+		if (audio->state == AUDIO_MVS_STARTED) {
+			rc = audio_mvs_stop(audio);
+		} else {
+			pr_err("%s: Stop called in invalid state %d\n",
+			       __func__, audio->state);
+
+			rc = -EPERM;
+		}
+
+		mutex_unlock(&audio->lock);
+		break;
+	}
+
+	default: {
+		pr_err("%s: Unknown IOCTL %d\n", __func__, cmd);
+	}
+	}
+
+	return rc;
+}
+
+static const struct file_operations audio_mvs_fops = {
+	.owner = THIS_MODULE,
+	.open = audio_mvs_open,
+	.release = audio_mvs_release,
+	.read = audio_mvs_read,
+	.write = audio_mvs_write,
+	.unlocked_ioctl = audio_mvs_ioctl
+};
+
+struct miscdevice audio_mvs_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_mvs",
+	.fops = &audio_mvs_fops
+};
+
+static int __init audio_mvs_init(void)
+{
+	int rc;
+
+	pr_info("%s:\n", __func__);
+
+	memset(&audio_mvs_info, 0, sizeof(audio_mvs_info));
+	mutex_init(&audio_mvs_info.lock);
+	mutex_init(&audio_mvs_info.in_lock);
+	mutex_init(&audio_mvs_info.out_lock);
+
+	init_waitqueue_head(&audio_mvs_info.wait);
+	init_waitqueue_head(&audio_mvs_info.mode_wait);
+	init_waitqueue_head(&audio_mvs_info.out_wait);
+
+	INIT_LIST_HEAD(&audio_mvs_info.in_queue);
+	INIT_LIST_HEAD(&audio_mvs_info.free_in_queue);
+	INIT_LIST_HEAD(&audio_mvs_info.out_queue);
+	INIT_LIST_HEAD(&audio_mvs_info.free_out_queue);
+
+	wake_lock_init(&audio_mvs_info.suspend_lock,
+		       WAKE_LOCK_SUSPEND,
+		       "audio_mvs_suspend");
+	wake_lock_init(&audio_mvs_info.idle_lock,
+		       WAKE_LOCK_IDLE,
+		       "audio_mvs_idle");
+
+	audio_mvs_info.rpc_endpt = msm_rpc_connect_compatible(MVS_PROG,
+					MVS_VERS_COMP_VER5,
+					MSM_RPC_UNINTERRUPTIBLE);
+
+	if (IS_ERR(audio_mvs_info.rpc_endpt)) {
+		pr_err("%s: MVS RPC connect failed ver 0x%x\n", __func__,
+				MVS_VERS_COMP_VER5);
+		audio_mvs_info.rpc_endpt = msm_rpc_connect_compatible(MVS_PROG,
+					MVS_VERS_COMP_VER4,
+					MSM_RPC_UNINTERRUPTIBLE);
+		if (IS_ERR(audio_mvs_info.rpc_endpt)) {
+			pr_err("%s: MVS RPC connect failed ver 0x%x\n",
+				__func__, MVS_VERS_COMP_VER4);
+			audio_mvs_info.rpc_endpt =
+				msm_rpc_connect_compatible(MVS_PROG,
+				MVS_VERS,
+				MSM_RPC_UNINTERRUPTIBLE);
+			if (IS_ERR(audio_mvs_info.rpc_endpt)) {
+				pr_err("%s: MVS RPC connect failed ver 0x%x\n",
+				   __func__, MVS_VERS);
+				rc = PTR_ERR(audio_mvs_info.rpc_endpt);
+				audio_mvs_info.rpc_endpt = NULL;
+				goto done;
+			} else {
+				pr_debug("%s: MVS RPC connect succeeded ver\
+					0x%x\n", __func__, MVS_VERS);
+				audio_mvs_info.rpc_prog = MVS_PROG;
+				audio_mvs_info.rpc_ver = MVS_VERS;
+			}
+		} else {
+			pr_debug("%s: MVS RPC connect succeeded ver 0x%x\n",
+				__func__, MVS_VERS_COMP_VER4);
+			audio_mvs_info.rpc_prog = MVS_PROG;
+			audio_mvs_info.rpc_ver = MVS_VERS_COMP_VER4;
+		}
+	} else {
+		pr_debug("%s: MVS RPC connect succeeded ver 0x%x\n", __func__,
+			MVS_VERS_COMP_VER5);
+		audio_mvs_info.rpc_prog = MVS_PROG;
+		audio_mvs_info.rpc_ver = MVS_VERS_COMP_VER5;
+	}
+	audio_mvs_info.task = kthread_run(audio_mvs_thread,
+					  &audio_mvs_info,
+					  "audio_mvs");
+	if (IS_ERR(audio_mvs_info.task)) {
+		pr_err("%s: MVS thread create failed\n",  __func__);
+		rc = PTR_ERR(audio_mvs_info.task);
+		audio_mvs_info.task = NULL;
+		msm_rpc_close(audio_mvs_info.rpc_endpt);
+		audio_mvs_info.rpc_endpt = NULL;
+		goto done;
+	}
+
+	rc = misc_register(&audio_mvs_misc);
+done:
+	return rc;
+}
+
+static void __exit audio_mvs_exit(void)
+{
+	pr_info("%s:\n", __func__);
+
+	misc_deregister(&audio_mvs_misc);
+}
+
+module_init(audio_mvs_init);
+module_exit(audio_mvs_exit);
+
+MODULE_DESCRIPTION("MSM MVS driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_out.c b/arch/arm/mach-msm/qdsp5v2/audio_out.c
new file mode 100644
index 0000000..288a717
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/audio_out.c
@@ -0,0 +1,728 @@
+/*
+ * pcm audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2009-2012, Code Aurora Forum. 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.
+ *
+ */
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/wakelock.h>
+#include <linux/memory_alloc.h>
+
+#include <linux/msm_audio.h>
+#include <linux/android_pmem.h>
+
+#include <mach/msm_adsp.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/qdsp5v2/qdsp5audppcmdi.h>
+#include <mach/qdsp5v2/qdsp5audppmsg.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/qdsp5v2/audpp.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/msm_memtypes.h>
+
+
+#include <mach/htc_pwrsink.h>
+#include <mach/debug_mm.h>
+
+#define BUFSZ (960 * 5)
+#define DMASZ (BUFSZ * 2)
+
+#define HOSTPCM_STREAM_ID 5
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;
+	unsigned addr;
+};
+
+struct audio {
+	struct buffer out[2];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed; /* number of buffers the dsp is waiting for */
+
+	atomic_t out_bytes;
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t wait;
+
+	/* configuration to use on next enable */
+	uint32_t out_sample_rate;
+	uint32_t out_channel_mode;
+	uint32_t out_weight;
+	uint32_t out_buffer_size;
+	uint32_t device_events;
+	int16_t source;
+
+	/* data allocated for various buffers */
+	char *data;
+	dma_addr_t phys;
+	void *map_v_write;
+	int teos; /* valid only if tunnel mode & no data left for decoder */
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+	uint16_t dec_id;
+	int voice_state;
+
+	struct wake_lock wakelock;
+	struct wake_lock idlelock;
+
+	struct audpp_cmd_cfg_object_params_volume vol_pan;
+};
+
+static void audio_out_listener(u32 evt_id, union auddev_evt_data *evt_payload,
+				void *private_data)
+{
+	struct audio *audio = private_data;
+	switch (evt_id) {
+	case AUDDEV_EVT_DEV_RDY:
+		MM_DBG(":AUDDEV_EVT_DEV_RDY\n");
+		audio->source |= (0x1 << evt_payload->routing_id);
+		if (audio->running == 1 && audio->enabled == 1)
+			audpp_route_stream(audio->dec_id, audio->source);
+		break;
+	case AUDDEV_EVT_DEV_RLS:
+		MM_DBG(":AUDDEV_EVT_DEV_RLS\n");
+		audio->source &= ~(0x1 << evt_payload->routing_id);
+		if (audio->running == 1 && audio->enabled == 1)
+			audpp_route_stream(audio->dec_id, audio->source);
+		break;
+	case AUDDEV_EVT_STREAM_VOL_CHG:
+		audio->vol_pan.volume = evt_payload->session_vol;
+		MM_DBG(":AUDDEV_EVT_STREAM_VOL_CHG, stream vol %d\n",
+				audio->vol_pan.volume);
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+		break;
+	case AUDDEV_EVT_VOICE_STATE_CHG:
+		MM_DBG("AUDDEV_EVT_VOICE_STATE_CHG, state = %d\n",
+						evt_payload->voice_state);
+		audio->voice_state = evt_payload->voice_state;
+		/* Voice uplink Rx case */
+		if (audio->running &&
+			(audio->source & AUDPP_MIXER_UPLINK_RX) &&
+			(audio->voice_state == VOICE_STATE_OFFCALL)) {
+			MM_DBG("Voice is terminated, Wake up write: %x %x\n",
+					audio->voice_state, audio->source);
+			wake_up(&audio->wait);
+		}
+		break;
+	default:
+		MM_ERR("ERROR:wrong event\n");
+		break;
+       }
+}
+
+static void audio_prevent_sleep(struct audio *audio)
+{
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	wake_lock(&audio->wakelock);
+	wake_lock(&audio->idlelock);
+}
+
+static void audio_allow_sleep(struct audio *audio)
+{
+	wake_unlock(&audio->wakelock);
+	wake_unlock(&audio->idlelock);
+	MM_DBG("\n"); /* Macro prints the file name and function */
+}
+
+static int audio_dsp_out_enable(struct audio *audio, int yes);
+static int audio_dsp_send_buffer(struct audio *audio, unsigned id,
+	unsigned len);
+
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
+
+/* must be called with audio->lock held */
+static int audio_enable(struct audio *audio)
+{
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	if (audio->enabled)
+		return 0;
+
+	/* refuse to start if we're not ready */
+	if (!audio->out[0].used || !audio->out[1].used)
+		return -EIO;
+
+	/* we start buffers 0 and 1, so buffer 0 will be the
+	 * next one the dsp will want
+	 */
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	audio_prevent_sleep(audio);
+
+	if (audpp_enable(-1, audio_dsp_event, audio)) {
+		MM_ERR("audpp_enable() failed\n");
+		audio_allow_sleep(audio);
+		return -ENODEV;
+	}
+
+	audio->enabled = 1;
+	htc_pwrsink_set(PWRSINK_AUDIO, 100);
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audio_disable(struct audio *audio)
+{
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audio_dsp_out_enable(audio, 0);
+
+		audpp_disable(-1, audio);
+
+		wake_up(&audio->wait);
+		audio->out_needed = 0;
+		audio_allow_sleep(audio);
+	}
+	return 0;
+}
+
+/* ------------------- dsp --------------------- */
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+	struct buffer *frame;
+	unsigned long flags;
+	static unsigned long pcmdmamsd_time;
+
+	switch (id) {
+	case AUDPP_MSG_HOST_PCM_INTF_MSG: {
+		unsigned id = msg[3];
+		unsigned idx = msg[4] - 1;
+
+		MM_DBG("HOST_PCM id %d idx %d\n", id, idx);
+		if (id != AUDPP_MSG_HOSTPCM_ID_ARM_RX) {
+			MM_ERR("bogus id\n");
+			break;
+		}
+		if (idx > 1) {
+			MM_ERR("bogus buffer idx\n");
+			break;
+		}
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		if (audio->running) {
+			atomic_add(audio->out[idx].used, &audio->out_bytes);
+			audio->out[idx].used = 0;
+			frame = audio->out + audio->out_tail;
+			if (frame->used) {
+				/* Reset teos flag to avoid stale
+				 * PCMDMAMISS been considered
+				 */
+				audio->teos = 0;
+				audio_dsp_send_buffer(
+					audio, audio->out_tail, frame->used);
+				audio->out_tail ^= 1;
+			} else {
+				audio->out_needed++;
+			}
+			wake_up(&audio->wait);
+		}
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		break;
+	}
+	case AUDPP_MSG_PCMDMAMISSED:
+		/* prints only if 1 second is elapsed since the last time
+		 * this message has been printed */
+		if (printk_timed_ratelimit(&pcmdmamsd_time, 1000))
+			printk(KERN_INFO "[%s:%s] PCMDMAMISSED %d\n",
+					__MM_FILE__, __func__, msg[0]);
+		audio->teos++;
+		MM_DBG("PCMDMAMISSED Count per Buffer %d\n", audio->teos);
+		wake_up(&audio->wait);
+		break;
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			MM_DBG("CFG_MSG ENABLE\n");
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+			audpp_route_stream(audio->dec_id, audio->source);
+			audio_dsp_out_enable(audio, 1);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			MM_DBG("CFG_MSG DISABLE\n");
+			audio->running = 0;
+		} else {
+			MM_ERR("CFG_MSG %d?\n", msg[0]);
+		}
+		break;
+	default:
+		MM_ERR("UNKNOWN (%d)\n", id);
+	}
+}
+
+static int audio_dsp_out_enable(struct audio *audio, int yes)
+{
+	struct audpp_cmd_pcm_intf cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id	= AUDPP_CMD_PCM_INTF;
+	cmd.stream	= AUDPP_CMD_POPP_STREAM;
+	cmd.stream_id	= audio->dec_id;
+	cmd.config	= AUDPP_CMD_PCM_INTF_CONFIG_CMD_V;
+	cmd.intf_type	= AUDPP_CMD_PCM_INTF_RX_ENA_ARMTODSP_V;
+
+	if (yes) {
+		cmd.write_buf1LSW	= audio->out[0].addr;
+		cmd.write_buf1MSW	= audio->out[0].addr >> 16;
+		if (audio->out[0].used)
+			cmd.write_buf1_len	= audio->out[0].used;
+		else
+			cmd.write_buf1_len	= audio->out[0].size;
+		cmd.write_buf2LSW	= audio->out[1].addr;
+		cmd.write_buf2MSW	= audio->out[1].addr >> 16;
+		if (audio->out[1].used)
+			cmd.write_buf2_len	= audio->out[1].used;
+		else
+			cmd.write_buf2_len	= audio->out[1].size;
+		cmd.arm_to_rx_flag	= AUDPP_CMD_PCM_INTF_ENA_V;
+		cmd.weight_decoder_to_rx = audio->out_weight;
+		cmd.weight_arm_to_rx	= 1;
+		cmd.partition_number_arm_to_dsp = 0;
+		cmd.sample_rate		= audio->out_sample_rate;
+		cmd.channel_mode	= audio->out_channel_mode;
+	}
+
+	return audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static int audio_dsp_send_buffer(struct audio *audio, unsigned idx,
+	unsigned len)
+{
+	struct audpp_cmd_pcm_intf_send_buffer cmd;
+
+	cmd.cmd_id	= AUDPP_CMD_PCM_INTF;
+	cmd.stream	= AUDPP_CMD_POPP_STREAM;
+	cmd.stream_id	= audio->dec_id;
+	cmd.config	= AUDPP_CMD_PCM_INTF_BUFFER_CMD_V;
+	cmd.intf_type	= AUDPP_CMD_PCM_INTF_RX_ENA_ARMTODSP_V;
+	cmd.dsp_to_arm_buf_id	= 0;
+	cmd.arm_to_dsp_buf_id	= idx + 1;
+	cmd.arm_to_dsp_buf_len	= len;
+
+	return audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+/* ------------------- device --------------------- */
+static void audio_flush(struct audio *audio)
+{
+	audio->out[0].used = 0;
+	audio->out[1].used = 0;
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->stopped = 0;
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = -EINVAL;
+	unsigned long flags = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = atomic_read(&audio->out_bytes);
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	switch (cmd) {
+	case AUDIO_SET_VOLUME:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.volume = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		return 0;
+
+	case AUDIO_SET_PAN:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.pan = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		if ((audio->voice_state != VOICE_STATE_INCALL)
+			&& (audio->source & AUDPP_MIXER_UPLINK_RX)) {
+			MM_ERR("Unable to Start : state %d source %d\n",
+					audio->voice_state, audio->source);
+			rc = -EPERM;
+			break;
+		}
+		rc = audio_enable(audio);
+		break;
+	case AUDIO_STOP:
+		rc = audio_disable(audio);
+		audio->stopped = 1;
+		break;
+	case AUDIO_FLUSH:
+		if (audio->stopped) {
+			/* Make sure we're stopped and we wake any threads
+			 * that might be blocked holding the write_lock.
+			 * While audio->stopped write threads will always
+			 * exit immediately.
+			 */
+			wake_up(&audio->wait);
+			mutex_lock(&audio->write_lock);
+			audio_flush(audio);
+			mutex_unlock(&audio->write_lock);
+		}
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (copy_from_user(&config, (void *) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (config.channel_count == 1)
+			config.channel_count = AUDPP_CMD_PCM_INTF_MONO_V;
+		else if (config.channel_count == 2)
+			config.channel_count = AUDPP_CMD_PCM_INTF_STEREO_V;
+		else {
+			rc = -EINVAL;
+			break;
+		}
+		audio->out_sample_rate = config.sample_rate;
+		audio->out_channel_mode = config.channel_count;
+		rc = 0;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_size = BUFSZ;
+		config.buffer_count = 2;
+		config.sample_rate = audio->out_sample_rate;
+		if (audio->out_channel_mode == AUDPP_CMD_PCM_INTF_MONO_V)
+			config.channel_count = 1;
+		else
+			config.channel_count = 2;
+
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void *) arg, &config, sizeof(config)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	}
+	case AUDIO_GET_SESSION_ID: {
+		if (copy_to_user((void *) arg, &audio->dec_id,
+					sizeof(unsigned short)))
+			return -EFAULT;
+		rc = 0;
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+/* Only useful in tunnel-mode */
+static int audio_fsync(struct file *file, loff_t ppos1, loff_t ppos2, int datasync)
+{
+	struct audio *audio = file->private_data;
+	int rc = 0;
+
+	if (!audio->running)
+		return -EINVAL;
+
+	mutex_lock(&audio->write_lock);
+
+	/* PCM DMAMISS message is sent only once in
+	 * hpcm interface. So, wait for buffer complete
+	 * and teos flag.
+	 */
+	rc = wait_event_interruptible(audio->wait,
+		(!audio->out[0].used &&
+		!audio->out[1].used));
+
+	if (rc < 0)
+		goto done;
+
+	rc = wait_event_interruptible(audio->wait,
+		audio->teos);
+done:
+	mutex_unlock(&audio->write_lock);
+	return rc;
+}
+
+static ssize_t audio_read(struct file *file, char __user *buf,
+		size_t count, loff_t *pos)
+{
+	return -EINVAL;
+}
+
+static inline int rt_policy(int policy)
+{
+	if (unlikely(policy == SCHED_FIFO) || unlikely(policy == SCHED_RR))
+		return 1;
+	return 0;
+}
+
+static inline int task_has_rt_policy(struct task_struct *p)
+{
+	return rt_policy(p->policy);
+}
+
+static ssize_t audio_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct sched_param s = { .sched_priority = 1 };
+	struct audio *audio = file->private_data;
+	unsigned long flags;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	int old_prio = current->rt_priority;
+	int old_policy = current->policy;
+	int cap_nice = cap_raised(current_cap(), CAP_SYS_NICE);
+	int rc = 0;
+
+
+	if ((audio->voice_state == VOICE_STATE_OFFCALL)
+		&& (audio->source & AUDPP_MIXER_UPLINK_RX) &&
+							audio->running) {
+		MM_ERR("Not Permitted Voice Terminated: state %d source %x \
+			running %d\n",
+			audio->voice_state, audio->source, audio->running);
+		return -EPERM;
+	}
+	/* just for this write, set us real-time */
+	if (!task_has_rt_policy(current)) {
+		struct cred *new = prepare_creds();
+		cap_raise(new->cap_effective, CAP_SYS_NICE);
+		commit_creds(new);
+		if ((sched_setscheduler(current, SCHED_RR, &s)) < 0)
+			MM_ERR("sched_setscheduler failed\n");
+	}
+
+	mutex_lock(&audio->write_lock);
+	while (count > 0) {
+		frame = audio->out + audio->out_head;
+
+		rc = wait_event_interruptible(audio->wait,
+		      (frame->used == 0) || (audio->stopped) ||
+			((audio->voice_state == VOICE_STATE_OFFCALL) &&
+			(audio->source & AUDPP_MIXER_UPLINK_RX)));
+
+		if (rc < 0)
+			break;
+		if (audio->stopped) {
+			rc = -EBUSY;
+			break;
+		} else if ((audio->voice_state == VOICE_STATE_OFFCALL) &&
+			(audio->source & AUDPP_MIXER_UPLINK_RX)) {
+			MM_ERR("Not Permitted Voice Terminated: %d\n",
+							audio->voice_state);
+			rc = -EPERM;
+			break;
+		}
+
+		xfer = count > frame->size ? frame->size : count;
+		if (copy_from_user(frame->data, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+		frame->used = xfer;
+		audio->out_head ^= 1;
+		count -= xfer;
+		buf += xfer;
+
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		frame = audio->out + audio->out_tail;
+		if (frame->used && audio->out_needed) {
+			/* Reset teos flag to avoid stale
+			 * PCMDMAMISS been considered
+			 */
+			audio->teos = 0;
+			audio_dsp_send_buffer(audio, audio->out_tail,
+					frame->used);
+			audio->out_tail ^= 1;
+			audio->out_needed--;
+		}
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	}
+
+	mutex_unlock(&audio->write_lock);
+
+	/* restore scheduling policy and priority */
+	if (!rt_policy(old_policy)) {
+		struct sched_param v = { .sched_priority = old_prio };
+		if ((sched_setscheduler(current, old_policy, &v)) < 0)
+			MM_ERR("sched_setscheduler failed\n");
+		if (likely(!cap_nice)) {
+			struct cred *new = prepare_creds();
+			cap_lower(new->cap_effective, CAP_SYS_NICE);
+			commit_creds(new);
+		}
+	}
+
+	if (buf > start)
+		return buf - start;
+	return rc;
+}
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->dec_id);
+	audio_disable(audio);
+	audio_flush(audio);
+	audio->opened = 0;
+	mutex_unlock(&audio->lock);
+	htc_pwrsink_set(PWRSINK_AUDIO, 0);
+	return 0;
+}
+
+static struct audio the_audio;
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = &the_audio;
+	int rc;
+
+	mutex_lock(&audio->lock);
+
+	if (audio->opened) {
+		MM_ERR("busy\n");
+		rc = -EBUSY;
+		goto done;
+	}
+
+
+	audio->dec_id = HOSTPCM_STREAM_ID;
+
+	audio->out_buffer_size = BUFSZ;
+	audio->out_sample_rate = 44100;
+	audio->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V;
+	audio->out_weight = 100;
+
+	audio->out[0].data = audio->data + 0;
+	audio->out[0].addr = audio->phys + 0;
+	audio->out[0].size = BUFSZ;
+
+	audio->out[1].data = audio->data + BUFSZ;
+	audio->out[1].addr = audio->phys + BUFSZ;
+	audio->out[1].size = BUFSZ;
+
+	audio->vol_pan.volume = 0x2000;
+	audio->vol_pan.pan = 0x0;
+	audio->source = 0x0;
+
+	audio_flush(audio);
+	audio->voice_state = msm_get_voice_state();
+	MM_DBG("voice_state = %x\n", audio->voice_state);
+	audio->device_events = AUDDEV_EVT_DEV_RDY
+				|AUDDEV_EVT_DEV_RLS|
+				AUDDEV_EVT_STREAM_VOL_CHG|
+				AUDDEV_EVT_VOICE_STATE_CHG;
+
+	MM_DBG("register for event callback pdata %p\n", audio);
+	rc = auddev_register_evt_listner(audio->device_events,
+					AUDDEV_CLNT_DEC,
+					audio->dec_id,
+					audio_out_listener,
+					(void *)audio);
+	if (rc) {
+		MM_ERR("%s: failed to register listener\n", __func__);
+		goto done;
+	}
+
+	file->private_data = audio;
+	audio->opened = 1;
+	rc = 0;
+done:
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static const struct file_operations audio_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audio_open,
+	.release	= audio_release,
+	.read		= audio_read,
+	.write		= audio_write,
+	.unlocked_ioctl	= audio_ioctl,
+	.fsync		= audio_fsync,
+};
+
+struct miscdevice audio_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_pcm_out",
+	.fops	= &audio_fops,
+};
+
+static int __init audio_init(void)
+{
+	the_audio.phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
+	if (the_audio.phys) {
+		the_audio.map_v_write = ioremap(the_audio.phys, DMASZ);
+		if (IS_ERR(the_audio.map_v_write)) {
+			MM_ERR("could not map physical buffers\n");
+			free_contiguous_memory_by_paddr(the_audio.phys);
+			return -ENOMEM;
+		}
+		the_audio.data = the_audio.map_v_write;
+	} else {
+			MM_ERR("could not allocate physical buffers\n");
+			return -ENOMEM;
+	}
+	MM_DBG("Memory addr = 0x%8x  phy addr = 0x%8x\n",\
+		(int) the_audio.data, (int) the_audio.phys);
+	mutex_init(&the_audio.lock);
+	mutex_init(&the_audio.write_lock);
+	spin_lock_init(&the_audio.dsp_lock);
+	init_waitqueue_head(&the_audio.wait);
+	wake_lock_init(&the_audio.wakelock, WAKE_LOCK_SUSPEND, "audio_pcm");
+	wake_lock_init(&the_audio.idlelock, WAKE_LOCK_IDLE, "audio_pcm_idle");
+	return misc_register(&audio_misc);
+}
+
+late_initcall(audio_init);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_pcm.c b/arch/arm/mach-msm/qdsp5v2/audio_pcm.c
new file mode 100644
index 0000000..4b308b0
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/audio_pcm.c
@@ -0,0 +1,1707 @@
+/* arch/arm/mach-msm/qdsp5v2/audio_pcm.c
+ *
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2009-2012, Code Aurora Forum. 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.
+ *
+ */
+
+#include <asm/ioctls.h>
+#include <asm/atomic.h>
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/earlysuspend.h>
+#include <linux/list.h>
+#include <linux/android_pmem.h>
+#include <linux/memory_alloc.h>
+#include <linux/slab.h>
+#include <linux/msm_audio.h>
+#include <mach/msm_adsp.h>
+
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/qdsp5v2/qdsp5audppcmdi.h>
+#include <mach/qdsp5v2/qdsp5audppmsg.h>
+#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
+#include <mach/qdsp5v2/qdsp5audplaymsg.h>
+#include <mach/qdsp5v2/audpp.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_memtypes.h>
+
+#define ADRV_STATUS_AIO_INTF 0x00000001
+#define ADRV_STATUS_OBUF_GIVEN 0x00000002
+#define ADRV_STATUS_IBUF_GIVEN 0x00000004
+#define ADRV_STATUS_FSYNC 0x00000008
+
+/* Size must be power of 2 */
+#define BUFSZ_MAX 32768
+#define BUFSZ_MIN 4096
+#define DMASZ_MAX (BUFSZ_MAX * 2)
+#define DMASZ_MIN (BUFSZ_MIN * 2)
+
+#define AUDDEC_DEC_PCM 0
+
+/* Decoder status received from AUDPPTASK */
+#define  AUDPP_DEC_STATUS_SLEEP	0
+#define  AUDPP_DEC_STATUS_INIT  1
+#define  AUDPP_DEC_STATUS_CFG   2
+#define  AUDPP_DEC_STATUS_PLAY  3
+
+#define AUDPCM_EVENT_NUM 10 /* Default number of pre-allocated event packets */
+
+#define __CONTAINS(r, v, l) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __v = v;					\
+	typeof(v) __e = __v + l;				\
+	int res = ((__v >= __r->vaddr) && 			\
+		(__e <= __r->vaddr + __r->len));		\
+	res;							\
+})
+
+#define CONTAINS(r1, r2) ({					\
+	typeof(r2) __r2 = r2;					\
+	__CONTAINS(r1, __r2->vaddr, __r2->len);			\
+})
+
+#define IN_RANGE(r, v) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __vv = v;					\
+	int res = ((__vv >= __r->vaddr) &&			\
+		(__vv < (__r->vaddr + __r->len)));		\
+	res;							\
+})
+
+#define OVERLAPS(r1, r2) ({					\
+	typeof(r1) __r1 = r1;					\
+	typeof(r2) __r2 = r2;					\
+	typeof(__r2->vaddr) __v = __r2->vaddr;			\
+	typeof(__v) __e = __v + __r2->len - 1;			\
+	int res = (IN_RANGE(__r1, __v) || IN_RANGE(__r1, __e));	\
+	res;							\
+})
+
+struct audio;
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct audpcm_suspend_ctl {
+  struct early_suspend node;
+  struct audio *audio;
+};
+#endif
+
+struct audpcm_event {
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+
+struct audpcm_pmem_region {
+	struct list_head list;
+	struct file *file;
+	int fd;
+	void *vaddr;
+	unsigned long paddr;
+	unsigned long kvaddr;
+	unsigned long len;
+	unsigned ref_cnt;
+};
+
+struct audpcm_buffer_node {
+	struct list_head list;
+	struct msm_audio_aio_buf buf;
+	unsigned long paddr;
+};
+
+struct audpcm_drv_operations {
+	void (*send_data)(struct audio *, unsigned);
+	void (*out_flush)(struct audio *);
+	int (*fsync)(struct audio *);
+};
+
+struct audio {
+	struct buffer out[2];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed; /* number of buffers the dsp is waiting for */
+	unsigned out_dma_sz;
+	struct list_head out_queue; /* queue to retain output buffers */
+	atomic_t out_bytes;
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	struct msm_adsp_module *audplay;
+
+	/* configuration to use on next enable */
+	uint32_t out_sample_rate;
+	uint32_t out_channel_mode;
+	uint32_t out_bits; /* bits per sample */
+
+	/* data allocated for various buffers */
+	char *data;
+	int32_t phys;
+	void *map_v_write;
+	uint32_t drv_status;
+	int wflush; /* Write flush */
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+	int teos; /* valid only if tunnel mode & no data left for decoder */
+	enum msm_aud_decoder_state dec_state; /* Represents decoder state */
+	int reserved; /* A byte is being reserved */
+	char rsv_byte; /* Handle odd length user data */
+
+	const char *module_name;
+	unsigned queue_id;
+	uint32_t device_events;
+
+	unsigned volume;
+
+	uint16_t dec_id;
+	int16_t source;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct audpcm_suspend_ctl suspend_ctl;
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+	wait_queue_head_t wait;
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	wait_queue_head_t event_wait;
+	spinlock_t event_queue_lock;
+	struct mutex get_event_lock;
+	int event_abort;
+	/* AV sync Info */
+	int avsync_flag;              /* Flag to indicate feedback from DSP */
+	wait_queue_head_t avsync_wait;/* Wait queue for AV Sync Message     */
+	/* flags, 48 bits sample/bytes counter per channel */
+	uint16_t avsync[AUDPP_AVSYNC_CH_COUNT * AUDPP_AVSYNC_NUM_WORDS + 1];
+
+	struct list_head pmem_region_queue;
+	struct audpcm_drv_operations drv_ops;
+};
+
+static int auddec_dsp_config(struct audio *audio, int enable);
+static void audpp_cmd_cfg_adec_params(struct audio *audio);
+static void audplay_send_data(struct audio *audio, unsigned needed);
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
+static void audpcm_post_event(struct audio *audio, int type,
+	union msm_audio_event_payload payload);
+static unsigned long audpcm_pmem_fixup(struct audio *audio, void *addr,
+	unsigned long len, int ref_up);
+
+static void pcm_listner(u32 evt_id, union auddev_evt_data *evt_payload,
+			void *private_data)
+{
+	struct audio *audio = (struct audio *) private_data;
+	switch (evt_id) {
+	case AUDDEV_EVT_DEV_RDY:
+		MM_DBG("AUDDEV_EVT_DEV_RDY\n");
+		audio->source |= (0x1 << evt_payload->routing_id);
+		if (audio->running == 1 && audio->enabled == 1)
+			audpp_route_stream(audio->dec_id, audio->source);
+		break;
+	case AUDDEV_EVT_DEV_RLS:
+		MM_DBG("AUDDEV_EVT_DEV_RLS\n");
+		audio->source &= ~(0x1 << evt_payload->routing_id);
+		if (audio->running == 1 && audio->enabled == 1)
+			audpp_route_stream(audio->dec_id, audio->source);
+		break;
+	case AUDDEV_EVT_STREAM_VOL_CHG:
+		audio->volume = evt_payload->session_vol;
+		MM_DBG("AUDDEV_EVT_STREAM_VOL_CHG, stream vol %d\n",
+				audio->volume);
+		if (audio->running)
+			audpp_set_volume_and_pan(audio->dec_id, audio->volume,
+					0, POPP);
+		break;
+	default:
+		MM_ERR("ERROR:wrong event\n");
+		break;
+	}
+}
+/* must be called with audio->lock held */
+static int audio_enable(struct audio *audio)
+{
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	if (audio->enabled)
+		return 0;
+
+	audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	if (msm_adsp_enable(audio->audplay)) {
+		MM_ERR("msm_adsp_enable(audplay) failed\n");
+		return -ENODEV;
+	}
+
+	if (audpp_enable(audio->dec_id, audio_dsp_event, audio)) {
+		MM_ERR("audpp_enable() failed\n");
+		msm_adsp_disable(audio->audplay);
+		return -ENODEV;
+	}
+
+	audio->enabled = 1;
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audio_disable(struct audio *audio)
+{
+	int rc = 0;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+		auddec_dsp_config(audio, 0);
+		rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+		else if (audio->dec_state != MSM_AUD_DECODER_STATE_CLOSE)
+			rc = -EFAULT;
+		else
+			rc = 0;
+		wake_up(&audio->write_wait);
+		msm_adsp_disable(audio->audplay);
+		audpp_disable(audio->dec_id, audio);
+		audio->out_needed = 0;
+	}
+	return rc;
+}
+
+/* ------------------- dsp --------------------- */
+static void audplay_dsp_event(void *data, unsigned id, size_t len,
+			      void (*getevent) (void *ptr, size_t len))
+{
+	struct audio *audio = data;
+	uint32_t msg[28];
+	getevent(msg, sizeof(msg));
+
+	MM_DBG("msg_id=%x\n", id);
+
+	switch (id) {
+	case AUDPLAY_MSG_DEC_NEEDS_DATA:
+		audio->drv_ops.send_data(audio, 1);
+		break;
+
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event:module audplaytask\n");
+		break;
+
+	default:
+		MM_ERR("unexpected message from decoder\n");
+		break;
+	}
+}
+
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned status = msg[1];
+
+			switch (status) {
+			case AUDPP_DEC_STATUS_SLEEP: {
+				uint16_t reason = msg[2];
+				MM_DBG("decoder status:sleep reason=0x%04x\n",
+						reason);
+				if ((reason == AUDPP_MSG_REASON_MEM)
+						|| (reason ==
+						AUDPP_MSG_REASON_NODECODER)) {
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_FAILURE;
+					wake_up(&audio->wait);
+				} else if (reason == AUDPP_MSG_REASON_NONE) {
+					/* decoder is in disable state */
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_CLOSE;
+					wake_up(&audio->wait);
+				}
+				break;
+			}
+			case AUDPP_DEC_STATUS_INIT:
+				MM_DBG("decoder status: init \n");
+				audpp_cmd_cfg_adec_params(audio);
+				break;
+
+			case AUDPP_DEC_STATUS_CFG:
+				MM_DBG("decoder status: cfg \n");
+				break;
+			case AUDPP_DEC_STATUS_PLAY:
+				MM_DBG("decoder status: play \n");
+				audpp_route_stream(audio->dec_id,
+						audio->source);
+				audio->dec_state =
+					MSM_AUD_DECODER_STATE_SUCCESS;
+				wake_up(&audio->wait);
+				break;
+			default:
+				MM_ERR("unknown decoder status\n");
+				break;
+			}
+			break;
+		}
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			MM_DBG("CFG_MSG ENABLE\n");
+			auddec_dsp_config(audio, 1);
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_set_volume_and_pan(audio->dec_id, audio->volume,
+					0, POPP);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			MM_DBG("CFG_MSG DISABLE\n");
+			audio->running = 0;
+		} else {
+			MM_ERR("audio_dsp_event: CFG_MSG %d?\n", msg[0]);
+		}
+		break;
+	case AUDPP_MSG_FLUSH_ACK:
+		MM_DBG("FLUSH_ACK\n");
+		audio->wflush = 0;
+		wake_up(&audio->write_wait);
+		break;
+
+	case AUDPP_MSG_PCMDMAMISSED:
+		MM_DBG("PCMDMAMISSED\n");
+		audio->teos = 1;
+		wake_up(&audio->write_wait);
+		break;
+
+	case AUDPP_MSG_AVSYNC_MSG:
+		pr_info("%s: AVSYNC_MSG\n", __func__);
+		memcpy(&audio->avsync[0], msg, sizeof(audio->avsync));
+		audio->avsync_flag = 1;
+		wake_up(&audio->avsync_wait);
+		break;
+
+	default:
+		MM_DBG("audio_dsp_event: UNKNOWN (%d)\n", id);
+	}
+
+}
+
+
+struct msm_adsp_ops audpcmdec_adsp_ops = {
+	.event = audplay_dsp_event,
+};
+
+
+#define audplay_send_queue0(audio, cmd, len) \
+	msm_adsp_write(audio->audplay, audio->queue_id, \
+			cmd, len)
+
+static int auddec_dsp_config(struct audio *audio, int enable)
+{
+	struct audpp_cmd_cfg_dec_type cfg_dec_cmd;
+
+	memset(&cfg_dec_cmd, 0, sizeof(cfg_dec_cmd));
+
+	cfg_dec_cmd.cmd_id = AUDPP_CMD_CFG_DEC_TYPE;
+	if (enable)
+		cfg_dec_cmd.dec_cfg = AUDPP_CMD_UPDATDE_CFG_DEC |
+				AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_PCM;
+	else
+		cfg_dec_cmd.dec_cfg = AUDPP_CMD_UPDATDE_CFG_DEC |
+				AUDPP_CMD_DIS_DEC_V;
+	cfg_dec_cmd.dm_mode = 0x0;
+	cfg_dec_cmd.stream_id = audio->dec_id;
+	return audpp_send_queue1(&cfg_dec_cmd, sizeof(cfg_dec_cmd));
+}
+
+static void audpp_cmd_cfg_adec_params(struct audio *audio)
+{
+	struct audpp_cmd_cfg_adec_params_wav cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_WAV_LEN >> 1;
+	cmd.common.dec_id = audio->dec_id;
+	cmd.common.input_sampling_frequency = audio->out_sample_rate;
+	cmd.stereo_cfg = audio->out_channel_mode;
+	cmd.pcm_width = audio->out_bits;
+	cmd.sign = 0;
+	audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static int audplay_dsp_send_data_avail(struct audio *audio,
+					unsigned idx, unsigned len)
+{
+	struct audplay_cmd_bitstream_data_avail cmd;
+
+	cmd.cmd_id		= AUDPLAY_CMD_BITSTREAM_DATA_AVAIL;
+	cmd.decoder_id		= audio->dec_id;
+	cmd.buf_ptr		= audio->out[idx].addr;
+	cmd.buf_size		= len/2;
+	cmd.partition_number	= 0;
+	/* complete writes to the input buffer */
+	wmb();
+	return audplay_send_queue0(audio, &cmd, sizeof(cmd));
+}
+
+static void audpcm_async_send_data(struct audio *audio, unsigned needed)
+{
+	unsigned long flags;
+
+	if (!audio->running)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+
+	if (needed && !audio->wflush) {
+		audio->out_needed = 1;
+		if (audio->drv_status & ADRV_STATUS_OBUF_GIVEN) {
+			/* pop one node out of queue */
+			union msm_audio_event_payload payload;
+			struct audpcm_buffer_node *used_buf;
+
+			MM_DBG("consumed\n");
+
+			BUG_ON(list_empty(&audio->out_queue));
+			used_buf = list_first_entry(&audio->out_queue,
+				struct audpcm_buffer_node, list);
+			list_del(&used_buf->list);
+			payload.aio_buf = used_buf->buf;
+			audpcm_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+				payload);
+			kfree(used_buf);
+			audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
+		}
+	}
+	if (audio->out_needed) {
+		struct audpcm_buffer_node *next_buf;
+		struct audplay_cmd_bitstream_data_avail cmd;
+		if (!list_empty(&audio->out_queue)) {
+			next_buf = list_first_entry(&audio->out_queue,
+					struct audpcm_buffer_node, list);
+			MM_DBG("next_buf %p\n", next_buf);
+			if (next_buf) {
+				MM_DBG("next buf phy %lx len %d\n",
+				next_buf->paddr, next_buf->buf.data_len);
+
+				cmd.cmd_id = AUDPLAY_CMD_BITSTREAM_DATA_AVAIL;
+				if (next_buf->buf.data_len)
+					cmd.decoder_id = audio->dec_id;
+				else {
+					cmd.decoder_id = -1;
+					MM_DBG("input EOS signaled\n");
+				}
+				cmd.buf_ptr	= (unsigned) next_buf->paddr;
+				cmd.buf_size = next_buf->buf.data_len >> 1;
+				cmd.partition_number	= 0;
+				/* complete writes to the input buffer */
+				wmb();
+				audplay_send_queue0(audio, &cmd, sizeof(cmd));
+				audio->out_needed = 0;
+				audio->drv_status |= ADRV_STATUS_OBUF_GIVEN;
+			}
+		}
+	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static void audplay_send_data(struct audio *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+
+	if (!audio->running)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+
+	if (needed && !audio->wflush) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			MM_DBG("frame %d free\n", audio->out_tail);
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+			MM_DBG("frame %d busy\n", audio->out_tail);
+			audplay_dsp_send_data_avail(audio, audio->out_tail,
+					frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+static void audpcm_async_flush(struct audio *audio)
+{
+	struct audpcm_buffer_node *buf_node;
+	struct list_head *ptr, *next;
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	list_for_each_safe(ptr, next, &audio->out_queue) {
+		buf_node = list_entry(ptr, struct audpcm_buffer_node, list);
+		list_del(&buf_node->list);
+		payload.aio_buf = buf_node->buf;
+		audpcm_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+				payload);
+		kfree(buf_node);
+	}
+	audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
+	audio->out_needed = 0;
+	atomic_set(&audio->out_bytes, 0);
+}
+
+static void audio_flush(struct audio *audio)
+{
+	audio->out[0].used = 0;
+	audio->out[1].used = 0;
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->reserved = 0;
+	audio->out_needed = 0;
+	atomic_set(&audio->out_bytes, 0);
+}
+
+static void audio_ioport_reset(struct audio *audio)
+{
+	if (audio->drv_status & ADRV_STATUS_AIO_INTF) {
+		/* If fsync is in progress, make sure
+		 * return value of fsync indicates
+		 * abort due to flush
+		 */
+		if (audio->drv_status & ADRV_STATUS_FSYNC) {
+			MM_DBG("fsync in progress\n");
+			wake_up(&audio->write_wait);
+			mutex_lock(&audio->write_lock);
+			audio->drv_ops.out_flush(audio);
+			mutex_unlock(&audio->write_lock);
+		} else
+			audio->drv_ops.out_flush(audio);
+	} else {
+		/* Make sure read/write thread are free from
+		 * sleep and knowing that system is not able
+		 * to process io request at the moment
+		 */
+		wake_up(&audio->write_wait);
+		mutex_lock(&audio->write_lock);
+		audio->drv_ops.out_flush(audio);
+		mutex_unlock(&audio->write_lock);
+	}
+	audio->avsync_flag = 1;
+	wake_up(&audio->avsync_wait);
+}
+
+static int audpcm_events_pending(struct audio *audio)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	return empty || audio->event_abort;
+}
+
+static void audpcm_reset_event_queue(struct audio *audio)
+{
+	unsigned long flags;
+	struct audpcm_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+			struct audpcm_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+			struct audpcm_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	return;
+}
+
+static long audpcm_process_event_req(struct audio *audio, void __user *arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audpcm_event *drv_evt = NULL;
+	int timeout;
+	unsigned long flags;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int) usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(
+			audio->event_wait, audpcm_events_pending(audio),
+			msecs_to_jiffies(timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(
+			audio->event_wait, audpcm_events_pending(audio));
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+			struct audpcm_event, list);
+		list_del(&drv_evt->list);
+	}
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else
+		rc = -1;
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	if (drv_evt && drv_evt->event_type == AUDIO_EVENT_WRITE_DONE) {
+		mutex_lock(&audio->lock);
+		audpcm_pmem_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+				  drv_evt->payload.aio_buf.buf_len, 0);
+		mutex_unlock(&audio->lock);
+	}
+	if (!rc && copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audpcm_pmem_check(struct audio *audio,
+		void *vaddr, unsigned long len)
+{
+	struct audpcm_pmem_region *region_elt;
+	struct audpcm_pmem_region t = { .vaddr = vaddr, .len = len };
+
+	list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+		if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
+		    OVERLAPS(region_elt, &t)) {
+			MM_ERR("region (vaddr %p len %ld)"
+				" clashes with registered region"
+				" (vaddr %p paddr %p len %ld)\n",
+				vaddr, len,
+				region_elt->vaddr,
+				(void *)region_elt->paddr,
+				region_elt->len);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int audpcm_pmem_add(struct audio *audio,
+	struct msm_audio_pmem_info *info)
+{
+	unsigned long paddr, kvaddr, len;
+	struct file *file;
+	struct audpcm_pmem_region *region;
+	int rc = -EINVAL;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	region = kmalloc(sizeof(*region), GFP_KERNEL);
+	if (!region)
+		return -ENOMEM;
+
+	if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) {
+		kfree(region);
+		return -EINVAL;
+	}
+
+	rc = audpcm_pmem_check(audio, info->vaddr, len);
+	if (rc < 0) {
+		put_pmem_file(file);
+		kfree(region);
+		return rc;
+	}
+
+	region->vaddr = info->vaddr;
+	region->fd = info->fd;
+	region->paddr = paddr;
+	region->kvaddr = kvaddr;
+	region->len = len;
+	region->file = file;
+	region->ref_cnt = 0;
+	MM_DBG("add region paddr %lx vaddr %p, len %lu\n", region->paddr,
+			region->vaddr, region->len);
+	list_add_tail(&region->list, &audio->pmem_region_queue);
+	return rc;
+}
+
+static int audpcm_pmem_remove(struct audio *audio,
+	struct msm_audio_pmem_info *info)
+{
+	struct audpcm_pmem_region *region;
+	struct list_head *ptr, *next;
+	int rc = -EINVAL;
+
+	MM_DBG("info fd %d vaddr %p\n", info->fd, info->vaddr);
+
+	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
+		region = list_entry(ptr, struct audpcm_pmem_region, list);
+
+		if ((region->fd == info->fd) &&
+		    (region->vaddr == info->vaddr)) {
+			if (region->ref_cnt) {
+				MM_DBG("region %p in use ref_cnt %d\n", region,
+						region->ref_cnt);
+				break;
+			}
+			MM_DBG("remove region fd %d vaddr %p \n", info->fd,
+					info->vaddr);
+			list_del(&region->list);
+			put_pmem_file(region->file);
+			kfree(region);
+			rc = 0;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static int audpcm_pmem_lookup_vaddr(struct audio *audio, void *addr,
+		     unsigned long len, struct audpcm_pmem_region **region)
+{
+	struct audpcm_pmem_region *region_elt;
+
+	int match_count = 0;
+
+	*region = NULL;
+
+	/* returns physical address or zero */
+	list_for_each_entry(region_elt, &audio->pmem_region_queue,
+		list) {
+		if (addr >= region_elt->vaddr &&
+		    addr < region_elt->vaddr + region_elt->len &&
+		    addr + len <= region_elt->vaddr + region_elt->len) {
+			/* offset since we could pass vaddr inside a registerd
+			 * pmem buffer
+			 */
+			match_count++;
+			if (!*region)
+				*region = region_elt;
+		}
+	}
+
+	if (match_count > 1) {
+		MM_ERR("multiple hits for vaddr %p, len %ld\n", addr, len);
+		list_for_each_entry(region_elt,
+		  &audio->pmem_region_queue, list) {
+			if (addr >= region_elt->vaddr &&
+			    addr < region_elt->vaddr + region_elt->len &&
+			    addr + len <= region_elt->vaddr + region_elt->len)
+				MM_ERR("\t%p, %ld --> %p\n",
+					region_elt->vaddr,
+					region_elt->len,
+					(void *)region_elt->paddr);
+		}
+	}
+
+	return *region ? 0 : -1;
+}
+
+static unsigned long audpcm_pmem_fixup(struct audio *audio, void *addr,
+		    unsigned long len, int ref_up)
+{
+	struct audpcm_pmem_region *region;
+	unsigned long paddr;
+	int ret;
+
+	ret = audpcm_pmem_lookup_vaddr(audio, addr, len, &region);
+	if (ret) {
+		MM_ERR("lookup (%p, %ld) failed\n", addr, len);
+		return 0;
+	}
+	if (ref_up)
+		region->ref_cnt++;
+	else
+		region->ref_cnt--;
+	MM_DBG("found region %p ref_cnt %d\n", region, region->ref_cnt);
+	paddr = region->paddr + (addr - region->vaddr);
+	return paddr;
+}
+
+/* audio -> lock must be held at this point */
+static int audpcm_aio_buf_add(struct audio *audio, unsigned dir,
+	void __user *arg)
+{
+	unsigned long flags;
+	struct audpcm_buffer_node *buf_node;
+
+	buf_node = kmalloc(sizeof(*buf_node), GFP_KERNEL);
+
+	if (!buf_node)
+		return -ENOMEM;
+
+	if (copy_from_user(&buf_node->buf, arg, sizeof(buf_node->buf))) {
+		kfree(buf_node);
+		return -EFAULT;
+	}
+
+	MM_DBG("node %p dir %x buf_addr %p buf_len %d data_len %d\n",
+			buf_node, dir, buf_node->buf.buf_addr,
+			buf_node->buf.buf_len, buf_node->buf.data_len);
+
+	buf_node->paddr = audpcm_pmem_fixup(
+		audio, buf_node->buf.buf_addr,
+		buf_node->buf.buf_len, 1);
+	if (dir) {
+		/* write */
+		if (!buf_node->paddr ||
+		    (buf_node->paddr & 0x1) ||
+		    (buf_node->buf.data_len & 0x1) ||
+		    (!buf_node->buf.data_len)) {
+			kfree(buf_node);
+			return -EINVAL;
+		}
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		list_add_tail(&buf_node->list, &audio->out_queue);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		audio->drv_ops.send_data(audio, 0);
+	}
+
+	MM_DBG("Add buf_node %p paddr %lx\n", buf_node, buf_node->paddr);
+
+	return 0;
+}
+
+static int audio_get_avsync_data(struct audio *audio,
+						struct msm_audio_stats *stats)
+{
+	int rc = -EINVAL;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (audio->dec_id == audio->avsync[0] && audio->avsync_flag) {
+		/* av_sync sample count */
+		stats->sample_count = (audio->avsync[2] << 16) |
+						(audio->avsync[3]);
+
+		/* av_sync byte_count */
+		stats->byte_count = (audio->avsync[5] << 16) |
+						(audio->avsync[6]);
+
+		audio->avsync_flag = 0;
+		rc = 0;
+	}
+	local_irq_restore(flags);
+	return rc;
+
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = 0;
+
+	MM_DBG("cmd = %d\n", cmd);
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+
+		audio->avsync_flag = 0;
+		memset(&stats, 0, sizeof(stats));
+		if (audpp_query_avsync(audio->dec_id) < 0)
+			return rc;
+
+		rc = wait_event_interruptible_timeout(audio->avsync_wait,
+				(audio->avsync_flag == 1),
+				msecs_to_jiffies(AUDPP_AVSYNC_EVENT_TIMEOUT));
+
+		if (rc < 0)
+			return rc;
+		else if ((rc > 0) || ((rc == 0) && (audio->avsync_flag == 1))) {
+			if (audio_get_avsync_data(audio, &stats) < 0)
+				return rc;
+
+			if (copy_to_user((void *)arg, &stats, sizeof(stats)))
+				return -EFAULT;
+			return 0;
+		} else
+			return -EAGAIN;
+	}
+	if (cmd == AUDIO_SET_VOLUME) {
+		unsigned long flags;
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->volume = arg;
+		if (audio->running)
+			audpp_set_volume_and_pan(audio->dec_id, arg, 0,
+					POPP);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		return 0;
+	}
+	if (cmd == AUDIO_GET_EVENT) {
+		MM_DBG("AUDIO_GET_EVENT\n");
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audpcm_process_event_req(audio,
+				(void __user *) arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		return rc;
+	}
+
+	if (cmd == AUDIO_ABORT_GET_EVENT) {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		MM_DBG("AUDIO_START\n");
+		rc = audio_enable(audio);
+		if (!rc) {
+			rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+			MM_INFO("dec_state %d rc = %d\n", audio->dec_state, rc);
+
+			if (audio->dec_state != MSM_AUD_DECODER_STATE_SUCCESS)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		break;
+	case AUDIO_STOP:
+		MM_DBG("AUDIO_STOP\n");
+		rc = audio_disable(audio);
+		audio->stopped = 1;
+		audio_ioport_reset(audio);
+		audio->stopped = 0;
+		break;
+	case AUDIO_FLUSH:
+		MM_DBG("AUDIO_FLUSH\n");
+		audio->wflush = 1;
+		audio_ioport_reset(audio);
+		if (audio->running) {
+			audpp_flush(audio->dec_id);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->wflush = 0;
+		}
+		break;
+
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (copy_from_user(&config, (void *) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (config.channel_count == 1) {
+			config.channel_count = AUDPP_CMD_PCM_INTF_MONO_V;
+		} else if (config.channel_count == 2) {
+			config.channel_count = AUDPP_CMD_PCM_INTF_STEREO_V;
+		} else {
+			rc = -EINVAL;
+			break;
+		}
+		if (config.bits == 8)
+			config.bits = AUDPP_CMD_WAV_PCM_WIDTH_8;
+		else if (config.bits == 16)
+			config.bits = AUDPP_CMD_WAV_PCM_WIDTH_16;
+		else if (config.bits == 24)
+			config.bits = AUDPP_CMD_WAV_PCM_WIDTH_24;
+		else {
+			rc = -EINVAL;
+			break;
+		}
+		audio->out_sample_rate = config.sample_rate;
+		audio->out_channel_mode = config.channel_count;
+		audio->out_bits = config.bits;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_size = (audio->out_dma_sz >> 1);
+		config.buffer_count = 2;
+		config.sample_rate = audio->out_sample_rate;
+		if (audio->out_channel_mode == AUDPP_CMD_PCM_INTF_MONO_V)
+			config.channel_count = 1;
+		else
+			config.channel_count = 2;
+		if (audio->out_bits == AUDPP_CMD_WAV_PCM_WIDTH_8)
+			config.bits = 8;
+		else if (audio->out_bits == AUDPP_CMD_WAV_PCM_WIDTH_24)
+			config.bits = 24;
+		else
+			config.bits = 16;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+
+		if (copy_to_user((void *) arg, &config, sizeof(config)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	}
+
+	case AUDIO_PAUSE:
+		MM_DBG("AUDIO_PAUSE %ld\n", arg);
+		rc = audpp_pause(audio->dec_id, (int) arg);
+		break;
+
+	case AUDIO_REGISTER_PMEM: {
+			struct msm_audio_pmem_info info;
+			MM_DBG("AUDIO_REGISTER_PMEM\n");
+			if (copy_from_user(&info, (void *) arg, sizeof(info)))
+				rc = -EFAULT;
+			else
+				rc = audpcm_pmem_add(audio, &info);
+			break;
+		}
+
+	case AUDIO_DEREGISTER_PMEM: {
+			struct msm_audio_pmem_info info;
+			MM_DBG("AUDIO_DEREGISTER_PMEM\n");
+			if (copy_from_user(&info, (void *) arg, sizeof(info)))
+				rc = -EFAULT;
+			else
+				rc = audpcm_pmem_remove(audio, &info);
+			break;
+		}
+
+	case AUDIO_ASYNC_WRITE:
+		if (audio->drv_status & ADRV_STATUS_FSYNC)
+			rc = -EBUSY;
+		else
+			rc = audpcm_aio_buf_add(audio, 1, (void __user *) arg);
+		break;
+
+	case AUDIO_ASYNC_READ:
+		MM_ERR("AUDIO_ASYNC_READ not supported\n");
+		rc = -EPERM;
+		break;
+
+	case AUDIO_GET_SESSION_ID:
+		if (copy_to_user((void *) arg, &audio->dec_id,
+					sizeof(unsigned short)))
+			return -EFAULT;
+		break;
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+/* Only useful in tunnel-mode */
+int audpcm_async_fsync(struct audio *audio)
+{
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	/* Blocking client sends more data */
+	mutex_lock(&audio->lock);
+	audio->drv_status |= ADRV_STATUS_FSYNC;
+	mutex_unlock(&audio->lock);
+
+	mutex_lock(&audio->write_lock);
+	/* pcm dmamiss message is sent continously
+	 * when decoder is starved so no race
+	 * condition concern
+	 */
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->teos && audio->out_needed &&
+		list_empty(&audio->out_queue))
+		|| audio->wflush || audio->stopped);
+
+	if (audio->stopped || audio->wflush)
+		rc = -EBUSY;
+
+	mutex_unlock(&audio->write_lock);
+	mutex_lock(&audio->lock);
+	audio->drv_status &= ~ADRV_STATUS_FSYNC;
+	mutex_unlock(&audio->lock);
+
+	return rc;
+}
+
+int audpcm_sync_fsync(struct audio *audio)
+{
+	struct buffer *frame;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(!audio->out[0].used &&
+		!audio->out[1].used &&
+		audio->out_needed) || audio->wflush);
+
+	if (rc < 0)
+		goto done;
+	else if (audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (audio->reserved) {
+		MM_DBG("send reserved byte\n");
+		frame = audio->out + audio->out_tail;
+		((char *) frame->data)[0] = audio->rsv_byte;
+		((char *) frame->data)[1] = 0;
+		frame->used = 2;
+		audio->drv_ops.send_data(audio, 0);
+
+		rc = wait_event_interruptible(audio->write_wait,
+			(!audio->out[0].used &&
+			!audio->out[1].used &&
+			audio->out_needed) || audio->wflush);
+
+		if (rc < 0)
+			goto done;
+		else if (audio->wflush) {
+			rc = -EBUSY;
+			goto done;
+		}
+	}
+
+	/* pcm dmamiss message is sent continously
+	 * when decoder is starved so no race
+	 * condition concern
+	 */
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		audio->teos || audio->wflush);
+
+	if (audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+	return rc;
+}
+
+int audpcm_fsync(struct file *file, loff_t ppos1, loff_t ppos2, int datasync)
+{
+	struct audio *audio = file->private_data;
+
+	if (!audio->running)
+		return -EINVAL;
+
+	return audio->drv_ops.fsync(audio);
+}
+
+static ssize_t audio_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	char *cpy_ptr;
+	int rc = 0;
+	unsigned dsize;
+
+	if (audio->drv_status & ADRV_STATUS_AIO_INTF)
+		return -EPERM;
+
+	MM_DBG("cnt=%d\n", count);
+
+	mutex_lock(&audio->write_lock);
+	while (count > 0) {
+		frame = audio->out + audio->out_head;
+		cpy_ptr = frame->data;
+		dsize = 0;
+		rc = wait_event_interruptible(audio->write_wait,
+					      (frame->used == 0)
+					      || (audio->stopped)
+						  || (audio->wflush));
+		if (rc < 0)
+			break;
+		if (audio->stopped || audio->wflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (audio->reserved) {
+			MM_DBG("append reserved byte %x\n", audio->rsv_byte);
+			*cpy_ptr = audio->rsv_byte;
+			xfer = (count > (frame->size - 1)) ?
+				frame->size - 1 : count;
+			cpy_ptr++;
+			dsize = 1;
+			audio->reserved = 0;
+		} else
+			xfer = (count > frame->size) ? frame->size : count;
+
+		if (copy_from_user(cpy_ptr, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+
+		dsize += xfer;
+		if (dsize & 1) {
+			audio->rsv_byte = ((char *) frame->data)[dsize - 1];
+			MM_DBG("odd length buf reserve last byte %x\n",
+					audio->rsv_byte);
+			audio->reserved = 1;
+			dsize--;
+		}
+		count -= xfer;
+		buf += xfer;
+
+		if (dsize > 0) {
+			audio->out_head ^= 1;
+			frame->used = dsize;
+			audio->drv_ops.send_data(audio, 0);
+		}
+	}
+	mutex_unlock(&audio->write_lock);
+	if (buf > start)
+		return buf - start;
+
+	return rc;
+}
+
+static void audpcm_reset_pmem_region(struct audio *audio)
+{
+	struct audpcm_pmem_region *region;
+	struct list_head *ptr, *next;
+
+	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
+		region = list_entry(ptr, struct audpcm_pmem_region, list);
+		list_del(&region->list);
+		put_pmem_file(region->file);
+		kfree(region);
+	}
+
+	return;
+}
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	MM_INFO("audio instance 0x%08x freeing\n", (int)audio);
+
+	mutex_lock(&audio->lock);
+	auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->dec_id);
+	audio_disable(audio);
+	audio->drv_ops.out_flush(audio);
+	audpcm_reset_pmem_region(audio);
+
+	msm_adsp_put(audio->audplay);
+	audpp_adec_free(audio->dec_id);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&audio->suspend_ctl.node);
+#endif
+	audio->opened = 0;
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audpcm_reset_event_queue(audio);
+	if (audio->data) {
+		iounmap(audio->map_v_write);
+		free_contiguous_memory_by_paddr(audio->phys);
+	}
+	mutex_unlock(&audio->lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio);
+	return 0;
+}
+
+static void audpcm_post_event(struct audio *audio, int type,
+	union msm_audio_event_payload payload)
+{
+	struct audpcm_event *e_node = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+			struct audpcm_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audpcm_event), GFP_ATOMIC);
+		if (!e_node) {
+			MM_ERR("No mem to post event %d\n", type);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	wake_up(&audio->event_wait);
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audpcm_suspend(struct early_suspend *h)
+{
+	struct audpcm_suspend_ctl *ctl =
+		container_of(h, struct audpcm_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audpcm_post_event(ctl->audio, AUDIO_EVENT_SUSPEND, payload);
+}
+
+static void audpcm_resume(struct early_suspend *h)
+{
+	struct audpcm_suspend_ctl *ctl =
+		container_of(h, struct audpcm_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audpcm_post_event(ctl->audio, AUDIO_EVENT_RESUME, payload);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audpcm_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audpcm_debug_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 4096;
+	static char buffer[4096];
+	int n = 0;
+	struct audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "enabled %d\n", audio->enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_buf_sz %d\n", audio->out[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "volume %x \n", audio->volume);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "sample rate %d \n", audio->out_sample_rate);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		"channel mode %d \n", audio->out_channel_mode);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "running %d \n", audio->running);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				"dec state %d \n", audio->dec_state);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_needed %d \n", audio->out_needed);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_head %d \n", audio->out_head);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_tail %d \n", audio->out_tail);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out[0].used %d \n", audio->out[0].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out[1].used %d \n", audio->out[1].used);
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audpcm_debug_fops = {
+	.read = audpcm_debug_read,
+	.open = audpcm_debug_open,
+};
+#endif
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = NULL;
+	int rc, i, dec_attrb, decid;
+	struct audpcm_event *e_node = NULL;
+	unsigned pmem_sz = DMASZ_MAX;
+
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_pcm_dec_" + 5];
+#endif
+
+	/* Allocate audio instance, set to zero */
+	audio = kzalloc(sizeof(struct audio), GFP_KERNEL);
+	if (!audio) {
+		MM_ERR("no memory to allocate audio instance \n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	MM_INFO("audio instance 0x%08x created\n", (int)audio);
+
+	/* Allocate the decoder */
+	dec_attrb = AUDDEC_DEC_PCM;
+	if (file->f_mode & FMODE_READ) {
+		MM_ERR("Non-Tunneled mode not supported\n");
+		rc = -EPERM;
+		kfree(audio);
+		goto done;
+	} else
+		dec_attrb |= MSM_AUD_MODE_TUNNEL;
+
+	decid = audpp_adec_alloc(dec_attrb, &audio->module_name,
+			&audio->queue_id);
+	if (decid < 0) {
+		MM_ERR("No free decoder available, freeing instance 0x%08x\n",
+				(int)audio);
+		rc = -ENODEV;
+		kfree(audio);
+		goto done;
+	}
+	audio->dec_id = decid & MSM_AUD_DECODER_MASK;
+
+	/* AIO interface */
+	if (file->f_flags & O_NONBLOCK) {
+		MM_DBG("set to aio interface\n");
+		audio->drv_status |= ADRV_STATUS_AIO_INTF;
+		audio->drv_ops.send_data = audpcm_async_send_data;
+		audio->drv_ops.out_flush = audpcm_async_flush;
+		audio->drv_ops.fsync = audpcm_async_fsync;
+	} else {
+		MM_DBG("set to std io interface\n");
+		while (pmem_sz >= DMASZ_MIN) {
+			MM_DBG("pmemsz = %d\n", pmem_sz);
+			audio->phys = allocate_contiguous_ebi_nomap(pmem_sz,
+								SZ_4K);
+			if (audio->phys) {
+				audio->map_v_write = ioremap(
+							audio->phys, pmem_sz);
+				if (IS_ERR(audio->map_v_write)) {
+					MM_ERR("could not map write phys\
+						address freeing instance \
+						0x%08x\n", (int)audio);
+					rc = -ENOMEM;
+					free_contiguous_memory_by_paddr(
+								audio->phys);
+					audpp_adec_free(audio->dec_id);
+					kfree(audio);
+					goto done;
+				}
+				audio->data = audio->map_v_write;
+				MM_DBG("write buf: phy addr 0x%08x \
+						kernel addr 0x%08x\n",
+						audio->phys, (int)audio->data);
+				break;
+			} else if (pmem_sz == DMASZ_MIN) {
+				MM_ERR("could not allocate write buffers \
+					freeing instance 0x%08x\n", (int)audio);
+				rc = -ENOMEM;
+				audpp_adec_free(audio->dec_id);
+				kfree(audio);
+				goto done;
+			} else
+				pmem_sz >>= 1;
+		}
+		audio->out_dma_sz = pmem_sz;
+		audio->drv_ops.send_data = audplay_send_data;
+		audio->drv_ops.out_flush = audio_flush;
+		audio->drv_ops.fsync = audpcm_sync_fsync;
+		audio->out[0].data = audio->data + 0;
+		audio->out[0].addr = audio->phys + 0;
+		audio->out[0].size = (audio->out_dma_sz >> 1);
+
+		audio->out[1].data = audio->data + audio->out[0].size;
+		audio->out[1].addr = audio->phys + audio->out[0].size;
+		audio->out[1].size = audio->out[0].size;
+	}
+
+	rc = msm_adsp_get(audio->module_name, &audio->audplay,
+			&audpcmdec_adsp_ops, audio);
+	if (rc) {
+		MM_ERR("failed to get %s module, freeing instance 0x%08x\n",
+				audio->module_name, (int)audio);
+		goto err;
+	}
+
+	/* Initialize all locks of audio instance */
+	mutex_init(&audio->lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->get_event_lock);
+	spin_lock_init(&audio->dsp_lock);
+	init_waitqueue_head(&audio->write_wait);
+	INIT_LIST_HEAD(&audio->out_queue);
+	INIT_LIST_HEAD(&audio->pmem_region_queue);
+	INIT_LIST_HEAD(&audio->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+	init_waitqueue_head(&audio->wait);
+	init_waitqueue_head(&audio->event_wait);
+	spin_lock_init(&audio->event_queue_lock);
+	init_waitqueue_head(&audio->avsync_wait);
+
+	audio->out_sample_rate = 44100;
+	audio->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V;
+	audio->out_bits = AUDPP_CMD_WAV_PCM_WIDTH_16;
+	audio->volume = 0x7FFF;
+	audio->drv_ops.out_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+
+	audio->device_events = AUDDEV_EVT_DEV_RDY
+				|AUDDEV_EVT_DEV_RLS|
+				AUDDEV_EVT_STREAM_VOL_CHG;
+
+	rc = auddev_register_evt_listner(audio->device_events,
+					AUDDEV_CLNT_DEC,
+					audio->dec_id,
+					pcm_listner,
+					(void *)audio);
+	if (rc) {
+		MM_ERR("failed to register listnet\n");
+		goto event_err;
+	}
+
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_pcm_dec_%04x", audio->dec_id);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+		NULL, (void *) audio, &audpcm_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		MM_ERR("debugfs_create_file failed\n");
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	audio->suspend_ctl.node.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+	audio->suspend_ctl.node.resume = audpcm_resume;
+	audio->suspend_ctl.node.suspend = audpcm_suspend;
+	audio->suspend_ctl.audio = audio;
+	register_early_suspend(&audio->suspend_ctl.node);
+#endif
+	for (i = 0; i < AUDPCM_EVENT_NUM; i++) {
+		e_node = kmalloc(sizeof(struct audpcm_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			MM_ERR("event pkt alloc failed\n");
+			break;
+		}
+	}
+done:
+	return rc;
+event_err:
+	msm_adsp_put(audio->audplay);
+err:
+	if (audio->data) {
+		iounmap(audio->map_v_write);
+		free_contiguous_memory_by_paddr(audio->phys);
+	}
+	audpp_adec_free(audio->dec_id);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_pcm_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audio_open,
+	.release	= audio_release,
+	.write		= audio_write,
+	.unlocked_ioctl	= audio_ioctl,
+	.fsync = audpcm_fsync,
+};
+
+struct miscdevice audio_pcm_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_pcm_dec",
+	.fops	= &audio_pcm_fops,
+};
+
+static int __init audio_init(void)
+{
+	return misc_register(&audio_pcm_misc);
+}
+
+device_initcall(audio_init);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c b/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c
new file mode 100644
index 0000000..ce67ebb
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c
@@ -0,0 +1,976 @@
+/*
+ * pcm audio input device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2009-2012, Code Aurora Forum. 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.
+ *
+ */
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/msm_audio.h>
+#include <linux/android_pmem.h>
+#include <linux/memory_alloc.h>
+#include <mach/msm_memtypes.h>
+
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+
+#include <mach/msm_adsp.h>
+#include <mach/socinfo.h>
+#include <mach/qdsp5v2/qdsp5audreccmdi.h>
+#include <mach/qdsp5v2/qdsp5audrecmsg.h>
+#include <mach/qdsp5v2/audpreproc.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/debug_mm.h>
+#include <mach/qdsp5v2/audio_acdbi.h>
+
+/* FRAME_NUM must be a power of two */
+#define FRAME_NUM		(8)
+#define FRAME_HEADER_SIZE       (8) /*4 half words*/
+/* size of a mono frame with 256 samples */
+#define MONO_DATA_SIZE_256	(512) /* in bytes*/
+/*size of a mono frame with 512 samples */
+#define MONO_DATA_SIZE_512	(1024) /* in bytes*/
+/*size of a mono frame with 1024 samples */
+#define MONO_DATA_SIZE_1024	(2048) /* in bytes */
+
+/*size of a stereo frame with 256 samples per channel */
+#define STEREO_DATA_SIZE_256	(1024) /* in bytes*/
+/*size of a stereo frame with 512 samples per channel */
+#define STEREO_DATA_SIZE_512	(2048) /* in bytes*/
+/*size of a stereo frame with 1024 samples per channel */
+#define STEREO_DATA_SIZE_1024	(4096) /* in bytes */
+
+#define MAX_FRAME_SIZE		((STEREO_DATA_SIZE_1024) + FRAME_HEADER_SIZE)
+#define DMASZ			(MAX_FRAME_SIZE * FRAME_NUM)
+
+struct buffer {
+	void *data;
+	uint32_t size;
+	uint32_t read;
+	uint32_t addr;
+};
+
+struct audio_in {
+	struct buffer in[FRAME_NUM];
+
+	spinlock_t dsp_lock;
+
+	atomic_t in_bytes;
+	atomic_t in_samples;
+
+	struct mutex lock;
+	struct mutex read_lock;
+	wait_queue_head_t wait;
+	wait_queue_head_t wait_enable;
+
+	struct msm_adsp_module *audrec;
+
+	/* configuration to use on next enable */
+	uint32_t samp_rate;
+	uint32_t channel_mode;
+	uint32_t buffer_size; /* 2048 for mono, 4096 for stereo */
+	uint32_t enc_type;
+
+	uint32_t dsp_cnt;
+	uint32_t in_head; /* next buffer dsp will write */
+	uint32_t in_tail; /* next buffer read() will read */
+	uint32_t in_count; /* number of buffers available to read() */
+	uint32_t mode;
+
+	const char *module_name;
+	unsigned queue_ids;
+	uint16_t enc_id; /* Session Id */
+
+	uint16_t source; /* Encoding source bit mask */
+	uint32_t device_events; /* device events interested in */
+	uint32_t in_call;
+	uint32_t dev_cnt;
+	int voice_state;
+	spinlock_t dev_lock;
+
+	struct audrec_session_info session_info; /*audrec session info*/
+	/* data allocated for various buffers */
+	char *data;
+	dma_addr_t phys;
+	void *map_v_read;
+
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+	int abort; /* set when error, like sample rate mismatch */
+	int dual_mic_config;
+	char *build_id;
+};
+
+static struct audio_in the_audio_in;
+
+struct audio_frame {
+	uint16_t frame_count_lsw;
+	uint16_t frame_count_msw;
+	uint16_t frame_length;
+	uint16_t erased_pcm;
+	unsigned char raw_bitstream[]; /* samples */
+} __attribute__((packed));
+
+/* Audrec Queue command sent macro's */
+#define audrec_send_bitstreamqueue(audio, cmd, len) \
+	msm_adsp_write(audio->audrec, ((audio->queue_ids & 0xFFFF0000) >> 16),\
+			cmd, len)
+
+#define audrec_send_audrecqueue(audio, cmd, len) \
+	msm_adsp_write(audio->audrec, (audio->queue_ids & 0x0000FFFF),\
+			cmd, len)
+
+/* DSP command send functions */
+static int audpcm_in_enc_config(struct audio_in *audio, int enable);
+static int audpcm_in_param_config(struct audio_in *audio);
+static int audpcm_in_mem_config(struct audio_in *audio);
+static int audpcm_in_record_config(struct audio_in *audio, int enable);
+static int audpcm_dsp_read_buffer(struct audio_in *audio, uint32_t read_cnt);
+
+static void audpcm_in_get_dsp_frames(struct audio_in *audio);
+
+static void audpcm_in_flush(struct audio_in *audio);
+
+static void pcm_in_listener(u32 evt_id, union auddev_evt_data *evt_payload,
+				void *private_data)
+{
+	struct audio_in *audio = (struct audio_in *) private_data;
+	unsigned long flags;
+
+	MM_DBG("evt_id = 0x%8x\n", evt_id);
+	switch (evt_id) {
+	case AUDDEV_EVT_DEV_RDY: {
+		MM_DBG("AUDDEV_EVT_DEV_RDY\n");
+		spin_lock_irqsave(&audio->dev_lock, flags);
+		audio->dev_cnt++;
+		if (!audio->in_call)
+			audio->source |= (0x1 << evt_payload->routing_id);
+		spin_unlock_irqrestore(&audio->dev_lock, flags);
+
+		if ((audio->running == 1) && (audio->enabled == 1))
+			audpcm_in_record_config(audio, 1);
+
+		break;
+	}
+	case AUDDEV_EVT_DEV_RLS: {
+		MM_DBG("AUDDEV_EVT_DEV_RLS\n");
+		spin_lock_irqsave(&audio->dev_lock, flags);
+		audio->dev_cnt--;
+		if (!audio->in_call)
+			audio->source &= ~(0x1 << evt_payload->routing_id);
+		spin_unlock_irqrestore(&audio->dev_lock, flags);
+
+		if (!audio->running || !audio->enabled)
+			break;
+
+		/* Turn of as per source */
+		if (audio->source)
+			audpcm_in_record_config(audio, 1);
+		else
+			/* Turn off all */
+			audpcm_in_record_config(audio, 0);
+
+		break;
+	}
+	case AUDDEV_EVT_VOICE_STATE_CHG: {
+		MM_DBG("AUDDEV_EVT_VOICE_STATE_CHG, state = %d\n",
+				evt_payload->voice_state);
+		audio->voice_state = evt_payload->voice_state;
+		if (audio->in_call && audio->running) {
+			if (audio->voice_state == VOICE_STATE_INCALL)
+				audpcm_in_record_config(audio, 1);
+			else if (audio->voice_state == VOICE_STATE_OFFCALL) {
+				audpcm_in_record_config(audio, 0);
+				wake_up(&audio->wait);
+			}
+		}
+		break;
+	}
+	case AUDDEV_EVT_FREQ_CHG: {
+		MM_DBG("Encoder Driver got sample rate change event\n");
+		MM_DBG("sample rate %d\n", evt_payload->freq_info.sample_rate);
+		MM_DBG("dev_type %d\n", evt_payload->freq_info.dev_type);
+		MM_DBG("acdb_dev_id %d\n", evt_payload->freq_info.acdb_dev_id);
+		if (audio->running == 1) {
+			/* Stop Recording sample rate does not match
+			   with device sample rate */
+			if (evt_payload->freq_info.sample_rate !=
+				audio->samp_rate) {
+				audpcm_in_record_config(audio, 0);
+				audio->abort = 1;
+				wake_up(&audio->wait);
+			}
+		}
+		break;
+	}
+	default:
+		MM_ERR("wrong event %d\n", evt_id);
+		break;
+	}
+}
+
+/* ------------------- dsp preproc event handler--------------------- */
+static void audpreproc_dsp_event(void *data, unsigned id,  void *msg)
+{
+	struct audio_in *audio = data;
+
+	switch (id) {
+	case AUDPREPROC_ERROR_MSG: {
+		struct audpreproc_err_msg *err_msg = msg;
+
+		MM_ERR("ERROR_MSG: stream id %d err idx %d\n",
+		err_msg->stream_id, err_msg->aud_preproc_err_idx);
+		/* Error case */
+		wake_up(&audio->wait_enable);
+		break;
+	}
+	case AUDPREPROC_CMD_CFG_DONE_MSG: {
+		MM_DBG("CMD_CFG_DONE_MSG \n");
+		break;
+	}
+	case AUDPREPROC_CMD_ENC_CFG_DONE_MSG: {
+		struct audpreproc_cmd_enc_cfg_done_msg *enc_cfg_msg = msg;
+
+		MM_DBG("CMD_ENC_CFG_DONE_MSG: stream id %d enc type \
+			0x%8x\n", enc_cfg_msg->stream_id,
+			enc_cfg_msg->rec_enc_type);
+		/* Encoder enable success */
+		if (enc_cfg_msg->rec_enc_type & ENCODE_ENABLE)
+			audpcm_in_param_config(audio);
+		else { /* Encoder disable success */
+			audio->running = 0;
+			audpcm_in_record_config(audio, 0);
+		}
+		break;
+	}
+	case AUDPREPROC_CMD_ENC_PARAM_CFG_DONE_MSG: {
+		MM_DBG("CMD_ENC_PARAM_CFG_DONE_MSG \n");
+		audpcm_in_mem_config(audio);
+		break;
+	}
+	case AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG: {
+		MM_DBG("AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG \n");
+		wake_up(&audio->wait_enable);
+		break;
+	}
+	default:
+		MM_ERR("Unknown Event id %d\n", id);
+	}
+}
+
+/* ------------------- dsp audrec event handler--------------------- */
+static void audrec_dsp_event(void *data, unsigned id, size_t len,
+			    void (*getevent)(void *ptr, size_t len))
+{
+	struct audio_in *audio = data;
+
+	switch (id) {
+	case AUDREC_CMD_MEM_CFG_DONE_MSG: {
+		MM_DBG("CMD_MEM_CFG_DONE MSG DONE\n");
+		audio->running = 1;
+		if ((!audio->in_call && (audio->dev_cnt > 0)) ||
+			(audio->in_call &&
+				(audio->voice_state == VOICE_STATE_INCALL)))
+			audpcm_in_record_config(audio, 1);
+		break;
+	}
+	case AUDREC_FATAL_ERR_MSG: {
+		struct audrec_fatal_err_msg fatal_err_msg;
+
+		getevent(&fatal_err_msg, AUDREC_FATAL_ERR_MSG_LEN);
+		MM_ERR("FATAL_ERR_MSG: err id %d\n",
+				fatal_err_msg.audrec_err_id);
+		/* Error stop the encoder */
+		audio->stopped = 1;
+		wake_up(&audio->wait);
+		break;
+	}
+	case AUDREC_UP_PACKET_READY_MSG: {
+		struct audrec_up_pkt_ready_msg pkt_ready_msg;
+
+		getevent(&pkt_ready_msg, AUDREC_UP_PACKET_READY_MSG_LEN);
+		MM_DBG("UP_PACKET_READY_MSG: write cnt lsw  %d \
+		write cnt msw %d read cnt lsw %d  read cnt msw %d \n",\
+		pkt_ready_msg.audrec_packet_write_cnt_lsw, \
+		pkt_ready_msg.audrec_packet_write_cnt_msw, \
+		pkt_ready_msg.audrec_up_prev_read_cnt_lsw, \
+		pkt_ready_msg.audrec_up_prev_read_cnt_msw);
+
+		audpcm_in_get_dsp_frames(audio);
+		break;
+	}
+	case ADSP_MESSAGE_ID: {
+		MM_DBG("Received ADSP event :module audrectask\n");
+		break;
+	}
+	default:
+		MM_ERR("Unknown Event id %d\n", id);
+	}
+}
+
+static void audpcm_in_get_dsp_frames(struct audio_in *audio)
+{
+	struct audio_frame *frame;
+	uint32_t index;
+	unsigned long flags;
+
+	index = audio->in_head;
+
+	frame = (void *) (((char *)audio->in[index].data) - \
+			 sizeof(*frame));
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->in[index].size = frame->frame_length;
+
+	/* statistics of read */
+	atomic_add(audio->in[index].size, &audio->in_bytes);
+	atomic_add(1, &audio->in_samples);
+
+	audio->in_head = (audio->in_head + 1) & (FRAME_NUM - 1);
+
+	/* If overflow, move the tail index foward. */
+	if (audio->in_head == audio->in_tail)
+		audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
+	else
+		audio->in_count++;
+
+	audpcm_dsp_read_buffer(audio, audio->dsp_cnt++);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+
+	wake_up(&audio->wait);
+}
+
+struct msm_adsp_ops audrec_adsp_ops = {
+	.event = audrec_dsp_event,
+};
+
+static int audpcm_in_enc_config(struct audio_in *audio, int enable)
+{
+	struct audpreproc_audrec_cmd_enc_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	if (audio->build_id[17] == '1') {
+		cmd.cmd_id = AUDPREPROC_AUDREC_CMD_ENC_CFG_2;
+		MM_ERR("sending AUDPREPROC_AUDREC_CMD_ENC_CFG_2 command");
+	} else {
+		cmd.cmd_id = AUDPREPROC_AUDREC_CMD_ENC_CFG;
+		MM_ERR("sending AUDPREPROC_AUDREC_CMD_ENC_CFG command");
+	}
+	cmd.stream_id = audio->enc_id;
+
+	if (enable)
+		cmd.audrec_enc_type = audio->enc_type | ENCODE_ENABLE;
+	else
+		cmd.audrec_enc_type &= ~(ENCODE_ENABLE);
+
+	return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
+}
+
+static int audpcm_in_param_config(struct audio_in *audio)
+{
+	struct audpreproc_audrec_cmd_parm_cfg_wav cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPREPROC_AUDREC_CMD_PARAM_CFG;
+	cmd.common.stream_id = audio->enc_id;
+
+	cmd.aud_rec_samplerate_idx = audio->samp_rate;
+	if (audio->dual_mic_config)
+		cmd.aud_rec_stereo_mode = DUAL_MIC_STEREO_RECORDING;
+	else
+		cmd.aud_rec_stereo_mode = audio->channel_mode;
+
+	if (audio->channel_mode == AUDREC_CMD_MODE_MONO)
+		cmd.aud_rec_frame_size = audio->buffer_size/2;
+	else
+		cmd.aud_rec_frame_size = audio->buffer_size/4;
+	return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
+}
+
+/* To Do: msm_snddev_route_enc(audio->enc_id); */
+static int audpcm_in_record_config(struct audio_in *audio, int enable)
+{
+	struct audpreproc_afe_cmd_audio_record_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG;
+	cmd.stream_id = audio->enc_id;
+	if (enable)
+		cmd.destination_activity = AUDIO_RECORDING_TURN_ON;
+	else
+		cmd.destination_activity = AUDIO_RECORDING_TURN_OFF;
+
+	cmd.source_mix_mask = audio->source;
+	if (audio->enc_id == 2) {
+		if ((cmd.source_mix_mask &
+				INTERNAL_CODEC_TX_SOURCE_MIX_MASK) ||
+			(cmd.source_mix_mask & AUX_CODEC_TX_SOURCE_MIX_MASK) ||
+			(cmd.source_mix_mask & VOICE_UL_SOURCE_MIX_MASK) ||
+			(cmd.source_mix_mask & VOICE_DL_SOURCE_MIX_MASK)) {
+			cmd.pipe_id = SOURCE_PIPE_1;
+		}
+		if (cmd.source_mix_mask &
+				AUDPP_A2DP_PIPE_SOURCE_MIX_MASK)
+			cmd.pipe_id |= SOURCE_PIPE_0;
+	}
+
+	return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
+}
+
+static int audpcm_in_mem_config(struct audio_in *audio)
+{
+	struct audrec_cmd_arecmem_cfg cmd;
+	uint16_t *data = (void *) audio->data;
+	int n;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_MEM_CFG_CMD;
+	cmd.audrec_up_pkt_intm_count = 1;
+	cmd.audrec_ext_pkt_start_addr_msw = audio->phys >> 16;
+	cmd.audrec_ext_pkt_start_addr_lsw = audio->phys;
+	cmd.audrec_ext_pkt_buf_number = FRAME_NUM;
+
+	/* prepare buffer pointers:
+	 * Mono: 1024 samples + 4 halfword header
+	 * Stereo: 2048 samples + 4 halfword header
+	 */
+	for (n = 0; n < FRAME_NUM; n++) {
+		/* word increment*/
+		audio->in[n].data = data + (FRAME_HEADER_SIZE/2);
+		data += ((FRAME_HEADER_SIZE/2) + (audio->buffer_size/2));
+		MM_DBG("0x%8x\n", (int)(audio->in[n].data - FRAME_HEADER_SIZE));
+	}
+
+	return audrec_send_audrecqueue(audio, &cmd, sizeof(cmd));
+}
+
+static int audpcm_dsp_read_buffer(struct audio_in *audio, uint32_t read_cnt)
+{
+	struct up_audrec_packet_ext_ptr cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = UP_AUDREC_PACKET_EXT_PTR;
+	cmd.audrec_up_curr_read_count_msw = read_cnt >> 16;
+	cmd.audrec_up_curr_read_count_lsw = read_cnt;
+
+	return audrec_send_bitstreamqueue(audio, &cmd, sizeof(cmd));
+}
+
+/* must be called with audio->lock held */
+static int audpcm_in_enable(struct audio_in *audio)
+{
+	if (audio->enabled)
+		return 0;
+
+	if (audpreproc_enable(audio->enc_id, &audpreproc_dsp_event, audio)) {
+		MM_ERR("msm_adsp_enable(audpreproc) failed\n");
+		return -ENODEV;
+	}
+
+	if (msm_adsp_enable(audio->audrec)) {
+		MM_ERR("msm_adsp_enable(audrec) failed\n");
+		audpreproc_disable(audio->enc_id, audio);
+		return -ENODEV;
+	}
+	audio->enabled = 1;
+	audpcm_in_enc_config(audio, 1);
+
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audpcm_in_disable(struct audio_in *audio)
+{
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audpcm_in_enc_config(audio, 0);
+		wake_up(&audio->wait);
+		wait_event_interruptible_timeout(audio->wait_enable,
+				audio->running == 0, 1*HZ);
+		msm_adsp_disable(audio->audrec);
+		audpreproc_disable(audio->enc_id, audio);
+	}
+	return 0;
+}
+
+static void audpcm_in_flush(struct audio_in *audio)
+{
+	int i;
+
+	audio->dsp_cnt = 0;
+	audio->in_head = 0;
+	audio->in_tail = 0;
+	audio->in_count = 0;
+	for (i = 0; i < FRAME_NUM; i++) {
+		audio->in[i].size = 0;
+		audio->in[i].read = 0;
+	}
+	MM_DBG("in_bytes %d\n", atomic_read(&audio->in_bytes));
+	MM_DBG("in_samples %d\n", atomic_read(&audio->in_samples));
+	atomic_set(&audio->in_bytes, 0);
+	atomic_set(&audio->in_samples, 0);
+}
+
+/* ------------------- device --------------------- */
+static long audpcm_in_ioctl(struct file *file,
+				unsigned int cmd, unsigned long arg)
+{
+	struct audio_in *audio = file->private_data;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = atomic_read(&audio->in_bytes);
+		stats.sample_count = atomic_read(&audio->in_samples);
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return rc;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START: {
+		uint32_t freq;
+		/* Poll at 48KHz always */
+		freq = 48000;
+		MM_DBG("AUDIO_START\n");
+		if (audio->in_call && (audio->voice_state !=
+				VOICE_STATE_INCALL)) {
+			rc = -EPERM;
+			break;
+		}
+		rc = msm_snddev_request_freq(&freq, audio->enc_id,
+					SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
+		MM_DBG("sample rate configured %d sample rate requested %d\n",
+				freq, audio->samp_rate);
+		if (rc < 0) {
+			MM_DBG("sample rate can not be set, return code %d\n",\
+							rc);
+			msm_snddev_withdraw_freq(audio->enc_id,
+						SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
+			MM_DBG("msm_snddev_withdraw_freq\n");
+			break;
+		}
+		audio->dual_mic_config = msm_get_dual_mic_config(audio->enc_id);
+		/*DSP supports fluence block and by default ACDB layer will
+		applies the fluence pre-processing feature, if dual MIC config
+		is enabled implies client want to record pure dual MIC sample
+		for this we need to over ride the fluence pre processing
+		feature at ACDB layer to not to apply if fluence preprocessing
+		feature supported*/
+		if (audio->dual_mic_config) {
+			MM_INFO("dual MIC config = %d, over ride the fluence "
+			"feature\n", audio->dual_mic_config);
+			fluence_feature_update(audio->dual_mic_config,
+							audio->enc_id);
+		}
+		/*update aurec session info in audpreproc layer*/
+		audio->session_info.session_id = audio->enc_id;
+		audio->session_info.sampling_freq = audio->samp_rate;
+		audpreproc_update_audrec_info(&audio->session_info);
+		rc = audpcm_in_enable(audio);
+		if (!rc) {
+			rc =
+			wait_event_interruptible_timeout(audio->wait_enable,
+				audio->running != 0, 1*HZ);
+			MM_DBG("state %d rc = %d\n", audio->running, rc);
+
+			if (audio->running == 0)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		audio->stopped = 0;
+		break;
+	}
+	case AUDIO_STOP: {
+		/*reset the sampling frequency information at audpreproc layer*/
+		audio->session_info.sampling_freq = 0;
+		audpreproc_update_audrec_info(&audio->session_info);
+		rc = audpcm_in_disable(audio);
+		rc = msm_snddev_withdraw_freq(audio->enc_id,
+					SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
+		MM_DBG("msm_snddev_withdraw_freq\n");
+		audio->stopped = 1;
+		audio->abort = 0;
+		break;
+	}
+	case AUDIO_FLUSH: {
+		if (audio->stopped) {
+			/* Make sure we're stopped and we wake any threads
+			 * that might be blocked holding the read_lock.
+			 * While audio->stopped read threads will always
+			 * exit immediately.
+			 */
+			wake_up(&audio->wait);
+			mutex_lock(&audio->read_lock);
+			audpcm_in_flush(audio);
+			mutex_unlock(&audio->read_lock);
+		}
+		break;
+	}
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config cfg;
+		if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (audio->build_id[17] == '1') {
+			audio->enc_type = ENC_TYPE_EXT_WAV | audio->mode;
+			if (cfg.channel_count == 1) {
+				cfg.channel_count = AUDREC_CMD_MODE_MONO;
+				if ((cfg.buffer_size == MONO_DATA_SIZE_256) ||
+					(cfg.buffer_size ==
+						MONO_DATA_SIZE_512) ||
+					(cfg.buffer_size ==
+						MONO_DATA_SIZE_1024)) {
+					audio->buffer_size = cfg.buffer_size;
+				} else {
+					rc = -EINVAL;
+					break;
+				}
+			} else if (cfg.channel_count == 2) {
+				cfg.channel_count = AUDREC_CMD_MODE_STEREO;
+				if ((cfg.buffer_size ==
+						STEREO_DATA_SIZE_256) ||
+					(cfg.buffer_size ==
+						STEREO_DATA_SIZE_512) ||
+					(cfg.buffer_size ==
+						STEREO_DATA_SIZE_1024)) {
+					audio->buffer_size = cfg.buffer_size;
+				} else {
+					rc = -EINVAL;
+					break;
+				}
+			} else {
+				rc = -EINVAL;
+				break;
+			}
+		} else if (audio->build_id[17] == '0') {
+			audio->enc_type = ENC_TYPE_WAV | audio->mode;
+			if (cfg.channel_count == 1) {
+				cfg.channel_count = AUDREC_CMD_MODE_MONO;
+				audio->buffer_size = MONO_DATA_SIZE_1024;
+			} else if (cfg.channel_count == 2) {
+				cfg.channel_count = AUDREC_CMD_MODE_STEREO;
+				audio->buffer_size = STEREO_DATA_SIZE_1024;
+			}
+		} else {
+			MM_ERR("wrong build_id = %s\n", audio->build_id);
+			return -ENODEV;
+		}
+		audio->samp_rate = cfg.sample_rate;
+		audio->channel_mode = cfg.channel_count;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config cfg;
+		memset(&cfg, 0, sizeof(cfg));
+		cfg.buffer_size = audio->buffer_size;
+		cfg.buffer_count = FRAME_NUM;
+		cfg.sample_rate = audio->samp_rate;
+		if (audio->channel_mode == AUDREC_CMD_MODE_MONO)
+			cfg.channel_count = 1;
+		else
+			cfg.channel_count = 2;
+		if (copy_to_user((void *) arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_INCALL: {
+		struct msm_voicerec_mode cfg;
+		unsigned long flags;
+		if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (cfg.rec_mode != VOC_REC_BOTH &&
+			cfg.rec_mode != VOC_REC_UPLINK &&
+			cfg.rec_mode != VOC_REC_DOWNLINK) {
+			MM_ERR("invalid rec_mode\n");
+			rc = -EINVAL;
+			break;
+		} else {
+			spin_lock_irqsave(&audio->dev_lock, flags);
+			if (cfg.rec_mode == VOC_REC_UPLINK)
+				audio->source = VOICE_UL_SOURCE_MIX_MASK;
+			else if (cfg.rec_mode == VOC_REC_DOWNLINK)
+				audio->source = VOICE_DL_SOURCE_MIX_MASK;
+			else
+				audio->source = VOICE_DL_SOURCE_MIX_MASK |
+						VOICE_UL_SOURCE_MIX_MASK ;
+			audio->in_call = 1;
+			spin_unlock_irqrestore(&audio->dev_lock, flags);
+		}
+		break;
+	}
+	case AUDIO_GET_SESSION_ID: {
+		if (copy_to_user((void *) arg, &audio->enc_id,
+			sizeof(unsigned short))) {
+			rc = -EFAULT;
+		}
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static ssize_t audpcm_in_read(struct file *file,
+				char __user *buf,
+				size_t count, loff_t *pos)
+{
+	struct audio_in *audio = file->private_data;
+	unsigned long flags;
+	const char __user *start = buf;
+	void *data;
+	uint32_t index;
+	uint32_t size;
+	int rc = 0;
+
+	mutex_lock(&audio->read_lock);
+	while (count > 0) {
+		rc = wait_event_interruptible(
+			audio->wait, (audio->in_count > 0) || audio->stopped ||
+			audio->abort || (audio->in_call && audio->running &&
+				(audio->voice_state == VOICE_STATE_OFFCALL)));
+		if (rc < 0)
+			break;
+
+		if (!audio->in_count) {
+			if (audio->stopped) {
+				MM_DBG("Driver in stop state, No more \
+						buffer to read");
+				rc = 0;/* End of File */
+				break;
+			} else if (audio->in_call && audio->running &&
+				(audio->voice_state == VOICE_STATE_OFFCALL)) {
+				MM_DBG("Not Permitted Voice Terminated\n");
+				rc = -EPERM; /* Voice Call stopped */
+				break;
+			}
+		}
+
+		if (audio->abort) {
+			rc = -EPERM; /* Not permitted due to abort */
+			break;
+		}
+
+		index = audio->in_tail;
+		data = (uint8_t *) audio->in[index].data;
+		size = audio->in[index].size;
+		if (count >= size) {
+			if (copy_to_user(buf, data, size)) {
+				rc = -EFAULT;
+				break;
+			}
+			spin_lock_irqsave(&audio->dsp_lock, flags);
+			if (index != audio->in_tail) {
+				/* overrun -- data is
+				 * invalid and we need to retry */
+				spin_unlock_irqrestore(&audio->dsp_lock, flags);
+				continue;
+			}
+			audio->in[index].size = 0;
+			audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
+			audio->in_count--;
+			spin_unlock_irqrestore(&audio->dsp_lock, flags);
+			count -= size;
+			buf += size;
+		} else {
+			MM_ERR("short read count %d\n", count);
+			break;
+		}
+	}
+	mutex_unlock(&audio->read_lock);
+
+	if (buf > start)
+		return buf - start;
+
+	return rc;
+}
+
+static ssize_t audpcm_in_write(struct file *file,
+				const char __user *buf,
+				size_t count, loff_t *pos)
+{
+	return -EINVAL;
+}
+
+static int audpcm_in_release(struct inode *inode, struct file *file)
+{
+	struct audio_in *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	audio->in_call = 0;
+	/* with draw frequency for session
+	   incase not stopped the driver */
+	msm_snddev_withdraw_freq(audio->enc_id, SNDDEV_CAP_TX,
+					AUDDEV_CLNT_ENC);
+	auddev_unregister_evt_listner(AUDDEV_CLNT_ENC, audio->enc_id);
+	/*reset the sampling frequency information at audpreproc layer*/
+	audio->session_info.sampling_freq = 0;
+	audpreproc_update_audrec_info(&audio->session_info);
+	audpcm_in_disable(audio);
+	audpcm_in_flush(audio);
+	msm_adsp_put(audio->audrec);
+	audpreproc_aenc_free(audio->enc_id);
+	audio->audrec = NULL;
+	audio->opened = 0;
+	if (audio->data) {
+		iounmap(audio->map_v_read);
+		free_contiguous_memory_by_paddr(audio->phys);
+		audio->data = NULL;
+	}
+	mutex_unlock(&audio->lock);
+	return 0;
+}
+
+static int audpcm_in_open(struct inode *inode, struct file *file)
+{
+	struct audio_in *audio = &the_audio_in;
+	int rc;
+	int encid;
+
+	mutex_lock(&audio->lock);
+	if (audio->opened) {
+		rc = -EBUSY;
+		goto done;
+	}
+	audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
+	if (audio->phys) {
+		audio->map_v_read = ioremap(audio->phys, DMASZ);
+		if (IS_ERR(audio->map_v_read)) {
+			MM_ERR("could not map read phys buffers\n");
+			rc = -ENOMEM;
+			free_contiguous_memory_by_paddr(audio->phys);
+			goto done;
+		}
+		audio->data = audio->map_v_read;
+	} else {
+		MM_ERR("could not allocate read buffers\n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	MM_DBG("Memory addr = 0x%8x  phy addr = 0x%8x\n",\
+		(int) audio->data, (int) audio->phys);
+	if ((file->f_mode & FMODE_WRITE) &&
+			(file->f_mode & FMODE_READ)) {
+		rc = -EACCES;
+		MM_ERR("Non tunnel encoding is not supported\n");
+		goto done;
+	} else if (!(file->f_mode & FMODE_WRITE) &&
+					(file->f_mode & FMODE_READ)) {
+		audio->mode = MSM_AUD_ENC_MODE_TUNNEL;
+		MM_DBG("Opened for tunnel mode encoding\n");
+	} else {
+		rc = -EACCES;
+		goto done;
+	}
+	/* Settings will be re-config at AUDIO_SET_CONFIG,
+	 * but at least we need to have initial config
+	 */
+	audio->channel_mode = AUDREC_CMD_MODE_MONO;
+	audio->buffer_size = MONO_DATA_SIZE_1024;
+	audio->samp_rate = 8000;
+	audio->enc_type = ENC_TYPE_EXT_WAV | audio->mode;
+
+	encid = audpreproc_aenc_alloc(audio->enc_type, &audio->module_name,
+			&audio->queue_ids);
+	if (encid < 0) {
+		MM_ERR("No free encoder available\n");
+		rc = -ENODEV;
+		goto done;
+	}
+	audio->enc_id = encid;
+
+	rc = msm_adsp_get(audio->module_name, &audio->audrec,
+			   &audrec_adsp_ops, audio);
+
+	if (rc) {
+		audpreproc_aenc_free(audio->enc_id);
+		goto done;
+	}
+
+	audio->stopped = 0;
+	audio->source = 0;
+	audio->abort = 0;
+	audpcm_in_flush(audio);
+	audio->device_events = AUDDEV_EVT_DEV_RDY | AUDDEV_EVT_DEV_RLS |
+				AUDDEV_EVT_FREQ_CHG |
+				AUDDEV_EVT_VOICE_STATE_CHG;
+
+	audio->voice_state = msm_get_voice_state();
+	rc = auddev_register_evt_listner(audio->device_events,
+					AUDDEV_CLNT_ENC, audio->enc_id,
+					pcm_in_listener, (void *) audio);
+	if (rc) {
+		MM_ERR("failed to register device event listener\n");
+		goto evt_error;
+	}
+	file->private_data = audio;
+	audio->opened = 1;
+	rc = 0;
+	audio->build_id = socinfo_get_build_id();
+	MM_DBG("Modem build id = %s\n", audio->build_id);
+done:
+	mutex_unlock(&audio->lock);
+	return rc;
+evt_error:
+	msm_adsp_put(audio->audrec);
+	audpreproc_aenc_free(audio->enc_id);
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static const struct file_operations audio_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audpcm_in_open,
+	.release	= audpcm_in_release,
+	.read		= audpcm_in_read,
+	.write		= audpcm_in_write,
+	.unlocked_ioctl	= audpcm_in_ioctl,
+};
+
+struct miscdevice audio_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_pcm_in",
+	.fops	= &audio_in_fops,
+};
+
+static int __init audpcm_in_init(void)
+{
+	mutex_init(&the_audio_in.lock);
+	mutex_init(&the_audio_in.read_lock);
+	spin_lock_init(&the_audio_in.dsp_lock);
+	spin_lock_init(&the_audio_in.dev_lock);
+	init_waitqueue_head(&the_audio_in.wait);
+	init_waitqueue_head(&the_audio_in.wait_enable);
+	return misc_register(&audio_in_misc);
+}
+
+device_initcall(audpcm_in_init);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_qcelp.c b/arch/arm/mach-msm/qdsp5v2/audio_qcelp.c
new file mode 100644
index 0000000..c53922b
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/audio_qcelp.c
@@ -0,0 +1,1639 @@
+/*
+ * qcelp 13k audio decoder device
+ *
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This code is based in part on audio_mp3.c, which is
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ *
+ * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ *
+ */
+
+#include <asm/ioctls.h>
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/earlysuspend.h>
+#include <linux/list.h>
+#include <linux/android_pmem.h>
+#include <linux/slab.h>
+#include <linux/msm_audio.h>
+#include <linux/memory_alloc.h>
+
+#include <mach/msm_adsp.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/qdsp5v2/qdsp5audppmsg.h>
+#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
+#include <mach/qdsp5v2/qdsp5audplaymsg.h>
+#include <mach/qdsp5v2/audpp.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_memtypes.h>
+
+#define BUFSZ 1094 /* QCELP 13K Hold 600ms packet data = 36 * 30 and
+		      14 bytes of meta in */
+#define BUF_COUNT 2
+#define DMASZ (BUFSZ * BUF_COUNT)
+
+#define PCM_BUFSZ_MIN 1624 /* 100ms worth of data and
+			      24 bytes of meta out  */
+#define PCM_BUF_MAX_COUNT 5
+
+#define AUDDEC_DEC_QCELP 9
+
+#define	ROUTING_MODE_FTRT	1
+#define	ROUTING_MODE_RT		2
+/* Decoder status received from AUDPPTASK */
+#define	AUDPP_DEC_STATUS_SLEEP	0
+#define	AUDPP_DEC_STATUS_INIT	1
+#define	AUDPP_DEC_STATUS_CFG	2
+#define	AUDPP_DEC_STATUS_PLAY	3
+
+#define AUDQCELP_METAFIELD_MASK 0xFFFF0000
+#define AUDQCELP_EOS_FLG_OFFSET 0x0A /* Offset from beginning of buffer */
+#define AUDQCELP_EOS_FLG_MASK 0x01
+#define AUDQCELP_EOS_NONE 0x0 /* No EOS detected */
+#define AUDQCELP_EOS_SET 0x1 /* EOS set in meta field */
+
+#define AUDQCELP_EVENT_NUM 10 /* Default number of pre-allocated event pkts */
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+	unsigned short mfield_sz; /*only useful for data has meta field */
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct audqcelp_suspend_ctl {
+	struct early_suspend node;
+	struct audio *audio;
+};
+#endif
+
+struct audqcelp_event{
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+
+struct audio {
+	struct buffer out[BUF_COUNT];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed;	/* number of buffers the dsp is waiting for */
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	/* Host PCM section - START */
+	struct buffer in[PCM_BUF_MAX_COUNT];
+	struct mutex read_lock;
+	wait_queue_head_t read_wait;    /* Wait queue for read */
+	char *read_data;        /* pointer to reader buffer */
+	int32_t read_phys;   /* physical address of reader buffer */
+	uint8_t read_next;      /* index to input buffers to be read next */
+	uint8_t fill_next;      /* index to buffer that DSP should be filling */
+	uint8_t pcm_buf_count;  /* number of pcm buffer allocated */
+	/* Host PCM section - END */
+
+	struct msm_adsp_module *audplay;
+
+	/* data allocated for various buffers */
+	char *data;
+	int32_t phys; /* physical address of write buffer */
+	void *map_v_read;
+	void *map_v_write;
+
+	int mfield; /* meta field embedded in data */
+	int rflush; /* Read  flush */
+	int wflush; /* Write flush */
+	uint8_t opened:1;
+	uint8_t enabled:1;
+	uint8_t running:1;
+	uint8_t stopped:1;	/* set when stopped, cleared on flush */
+	uint8_t pcm_feedback:1; /* set when non-tunnel mode */
+	uint8_t buf_refresh:1;
+	int teos; /* valid only if tunnel mode & no data left for decoder */
+	enum msm_aud_decoder_state dec_state;	/* Represents decoder state */
+
+	const char *module_name;
+	unsigned queue_id;
+	uint16_t dec_id;
+	int16_t source;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct audqcelp_suspend_ctl suspend_ctl;
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+
+	wait_queue_head_t wait;
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	wait_queue_head_t event_wait;
+	spinlock_t event_queue_lock;
+	struct mutex get_event_lock;
+	int event_abort;
+	/* AV sync Info */
+	int avsync_flag;              /* Flag to indicate feedback from DSP */
+	wait_queue_head_t avsync_wait;/* Wait queue for AV Sync Message     */
+	/* flags, 48 bits sample/bytes counter per channel */
+	uint16_t avsync[AUDPP_AVSYNC_CH_COUNT * AUDPP_AVSYNC_NUM_WORDS + 1];
+
+	uint32_t device_events;
+
+	int eq_enable;
+	int eq_needs_commit;
+	struct audpp_cmd_cfg_object_params_eqalizer eq;
+	struct audpp_cmd_cfg_object_params_volume vol_pan;
+};
+
+static int auddec_dsp_config(struct audio *audio, int enable);
+static void audpp_cmd_cfg_adec_params(struct audio *audio);
+static void audpp_cmd_cfg_routing_mode(struct audio *audio);
+static void audqcelp_send_data(struct audio *audio, unsigned needed);
+static void audqcelp_config_hostpcm(struct audio *audio);
+static void audqcelp_buffer_refresh(struct audio *audio);
+static void audqcelp_dsp_event(void *private, unsigned id, uint16_t *msg);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audqcelp_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload);
+#endif
+
+/* must be called with audio->lock held */
+static int audqcelp_enable(struct audio *audio)
+{
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled)
+		return 0;
+
+	audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	if (msm_adsp_enable(audio->audplay)) {
+		MM_ERR("msm_adsp_enable(audplay) failed\n");
+		return -ENODEV;
+	}
+
+	if (audpp_enable(audio->dec_id, audqcelp_dsp_event, audio)) {
+		MM_ERR("audpp_enable() failed\n");
+		msm_adsp_disable(audio->audplay);
+		return -ENODEV;
+	}
+	audio->enabled = 1;
+	return 0;
+}
+
+static void qcelp_listner(u32 evt_id, union auddev_evt_data *evt_payload,
+			void *private_data)
+{
+	struct audio *audio = (struct audio *) private_data;
+	switch (evt_id) {
+	case AUDDEV_EVT_DEV_RDY:
+		MM_DBG(":AUDDEV_EVT_DEV_RDY\n");
+		audio->source |= (0x1 << evt_payload->routing_id);
+		if (audio->running == 1 && audio->enabled == 1)
+			audpp_route_stream(audio->dec_id, audio->source);
+		break;
+	case AUDDEV_EVT_DEV_RLS:
+		MM_DBG(":AUDDEV_EVT_DEV_RLS\n");
+		audio->source &= ~(0x1 << evt_payload->routing_id);
+		if (audio->running == 1 && audio->enabled == 1)
+			audpp_route_stream(audio->dec_id, audio->source);
+		break;
+	case AUDDEV_EVT_STREAM_VOL_CHG:
+		audio->vol_pan.volume = evt_payload->session_vol;
+		MM_DBG(":AUDDEV_EVT_STREAM_VOL_CHG, stream vol %d\n",
+				audio->vol_pan.volume);
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+		break;
+	default:
+		MM_ERR(":ERROR:wrong event\n");
+		break;
+	}
+}
+/* must be called with audio->lock held */
+static int audqcelp_disable(struct audio *audio)
+{
+	int rc = 0;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+		auddec_dsp_config(audio, 0);
+		rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+		else if (audio->dec_state != MSM_AUD_DECODER_STATE_CLOSE)
+			rc = -EFAULT;
+		else
+			rc = 0;
+		wake_up(&audio->write_wait);
+		wake_up(&audio->read_wait);
+		msm_adsp_disable(audio->audplay);
+		audpp_disable(audio->dec_id, audio);
+		audio->out_needed = 0;
+	}
+	return rc;
+}
+
+/* ------------------- dsp --------------------- */
+static void audqcelp_update_pcm_buf_entry(struct audio *audio,
+	uint32_t *payload)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	if (audio->rflush)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < payload[1]; index++) {
+		if (audio->in[audio->fill_next].addr ==
+			payload[2 + index * 2]) {
+			MM_DBG("in[%d] ready\n", audio->fill_next);
+			audio->in[audio->fill_next].used =
+			payload[3 + index * 2];
+			if ((++audio->fill_next) == audio->pcm_buf_count)
+				audio->fill_next = 0;
+		} else {
+			MM_ERR("expected=%x ret=%x\n",
+				audio->in[audio->fill_next].addr,
+				payload[1 + index * 2]);
+			break;
+		}
+	}
+	if (audio->in[audio->fill_next].used == 0) {
+		audqcelp_buffer_refresh(audio);
+	} else {
+		MM_DBG("read cannot keep up\n");
+		audio->buf_refresh = 1;
+	}
+	wake_up(&audio->read_wait);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static void audplay_dsp_event(void *data, unsigned id, size_t len,
+			      void (*getevent) (void *ptr, size_t len))
+{
+	struct audio *audio = data;
+	uint32_t msg[28];
+	getevent(msg, sizeof(msg));
+
+	MM_DBG("msg_id=%x\n", id);
+
+	switch (id) {
+	case AUDPLAY_MSG_DEC_NEEDS_DATA:
+		audqcelp_send_data(audio, 1);
+		break;
+
+	case AUDPLAY_MSG_BUFFER_UPDATE:
+		audqcelp_update_pcm_buf_entry(audio, msg);
+		break;
+
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audplaytask)\n");
+		break;
+
+	default:
+		MM_ERR("unexpected message from decoder \n");
+	}
+}
+
+static void audqcelp_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned status = msg[1];
+
+			switch (status) {
+			case AUDPP_DEC_STATUS_SLEEP: {
+				uint16_t reason = msg[2];
+				MM_DBG("decoder status:sleep reason = \
+						0x%04x\n", reason);
+				if ((reason == AUDPP_MSG_REASON_MEM)
+					|| (reason ==
+					AUDPP_MSG_REASON_NODECODER)) {
+					audio->dec_state =
+					MSM_AUD_DECODER_STATE_FAILURE;
+					wake_up(&audio->wait);
+				} else if (reason == AUDPP_MSG_REASON_NONE) {
+					/* decoder is in disable state */
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_CLOSE;
+					wake_up(&audio->wait);
+				}
+				break;
+			}
+			case AUDPP_DEC_STATUS_INIT:
+				MM_DBG("decoder status: init \n");
+				if (audio->pcm_feedback)
+					audpp_cmd_cfg_routing_mode(audio);
+				else
+					audpp_cmd_cfg_adec_params(audio);
+				break;
+
+			case AUDPP_DEC_STATUS_CFG:
+				MM_DBG("decoder status: cfg \n");
+				break;
+			case AUDPP_DEC_STATUS_PLAY:
+				MM_DBG("decoder status: play \n");
+				/* send  mixer command */
+				audpp_route_stream(audio->dec_id,
+						audio->source);
+				if (audio->pcm_feedback) {
+					audqcelp_config_hostpcm(audio);
+					audqcelp_buffer_refresh(audio);
+				}
+				audio->dec_state =
+					MSM_AUD_DECODER_STATE_SUCCESS;
+				wake_up(&audio->wait);
+				break;
+			default:
+				MM_ERR("unknown decoder status\n");
+			}
+			break;
+		}
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			MM_DBG("CFG_MSG ENABLE\n");
+			auddec_dsp_config(audio, 1);
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+			audpp_dsp_set_eq(audio->dec_id,	audio->eq_enable,
+					&audio->eq, POPP);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			MM_DBG("CFG_MSG DISABLE\n");
+			audio->running = 0;
+		} else {
+			MM_DBG("CFG_MSG %d?\n", msg[0]);
+		}
+		break;
+	case AUDPP_MSG_ROUTING_ACK:
+		MM_DBG("ROUTING_ACK mode=%d\n", msg[1]);
+		audpp_cmd_cfg_adec_params(audio);
+		break;
+	case AUDPP_MSG_FLUSH_ACK:
+		MM_DBG("FLUSH_ACK\n");
+		audio->wflush = 0;
+		audio->rflush = 0;
+		wake_up(&audio->write_wait);
+		if (audio->pcm_feedback)
+			audqcelp_buffer_refresh(audio);
+		break;
+	case AUDPP_MSG_PCMDMAMISSED:
+		MM_DBG("PCMDMAMISSED\n");
+		audio->teos = 1;
+		wake_up(&audio->write_wait);
+		break;
+
+	case AUDPP_MSG_AVSYNC_MSG:
+		MM_DBG("AUDPP_MSG_AVSYNC_MSG\n");
+		memcpy(&audio->avsync[0], msg, sizeof(audio->avsync));
+		audio->avsync_flag = 1;
+		wake_up(&audio->avsync_wait);
+		break;
+
+	default:
+		MM_ERR("UNKNOWN (%d)\n", id);
+	}
+
+}
+
+struct msm_adsp_ops audplay_adsp_ops_qcelp = {
+	.event = audplay_dsp_event,
+};
+
+#define audplay_send_queue0(audio, cmd, len) \
+	msm_adsp_write(audio->audplay, audio->queue_id, \
+		cmd, len)
+
+static int auddec_dsp_config(struct audio *audio, int enable)
+{
+	struct audpp_cmd_cfg_dec_type cfg_dec_cmd;
+
+	memset(&cfg_dec_cmd, 0, sizeof(cfg_dec_cmd));
+
+	cfg_dec_cmd.cmd_id = AUDPP_CMD_CFG_DEC_TYPE;
+	if (enable)
+		cfg_dec_cmd.dec_cfg = AUDPP_CMD_UPDATDE_CFG_DEC |
+				AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_QCELP;
+	else
+		cfg_dec_cmd.dec_cfg = AUDPP_CMD_UPDATDE_CFG_DEC |
+				AUDPP_CMD_DIS_DEC_V;
+	cfg_dec_cmd.dm_mode = 0x0;
+	cfg_dec_cmd.stream_id = audio->dec_id;
+
+	return audpp_send_queue1(&cfg_dec_cmd, sizeof(cfg_dec_cmd));
+}
+
+static void audpp_cmd_cfg_adec_params(struct audio *audio)
+{
+	struct audpp_cmd_cfg_adec_params_v13k cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_V13K_LEN;
+	cmd.common.dec_id = audio->dec_id;
+	cmd.common.input_sampling_frequency = 8000;
+	cmd.stereo_cfg = AUDPP_CMD_PCM_INTF_MONO_V;
+
+	audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static void audpp_cmd_cfg_routing_mode(struct audio *audio)
+{
+	struct audpp_cmd_routing_mode cmd;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_ROUTING_MODE;
+	cmd.object_number = audio->dec_id;
+	if (audio->pcm_feedback)
+		cmd.routing_mode = ROUTING_MODE_FTRT;
+	else
+		cmd.routing_mode = ROUTING_MODE_RT;
+	audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static int audplay_dsp_send_data_avail(struct audio *audio,
+				       unsigned idx, unsigned len)
+{
+	struct audplay_cmd_bitstream_data_avail_nt2 cmd;
+
+	cmd.cmd_id = AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_NT2;
+	if (audio->mfield)
+		cmd.decoder_id = AUDQCELP_METAFIELD_MASK |
+			(audio->out[idx].mfield_sz >> 1);
+	else
+		cmd.decoder_id = audio->dec_id;
+	cmd.buf_ptr = audio->out[idx].addr;
+	cmd.buf_size = len / 2;
+	cmd.partition_number = 0;
+	return audplay_send_queue0(audio, &cmd, sizeof(cmd));
+}
+
+static void audqcelp_buffer_refresh(struct audio *audio)
+{
+	struct audplay_cmd_buffer_refresh refresh_cmd;
+
+	refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH;
+	refresh_cmd.num_buffers = 1;
+	refresh_cmd.buf0_address = audio->in[audio->fill_next].addr;
+	refresh_cmd.buf0_length = audio->in[audio->fill_next].size;
+	refresh_cmd.buf_read_count = 0;
+	MM_DBG("buf0_addr=%x buf0_len=%d\n", refresh_cmd.buf0_address,
+			refresh_cmd.buf0_length);
+
+	(void)audplay_send_queue0(audio, &refresh_cmd, sizeof(refresh_cmd));
+}
+
+static void audqcelp_config_hostpcm(struct audio *audio)
+{
+	struct audplay_cmd_hpcm_buf_cfg cfg_cmd;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	cfg_cmd.cmd_id = AUDPLAY_CMD_HPCM_BUF_CFG;
+	cfg_cmd.max_buffers = 1;
+	cfg_cmd.byte_swap = 0;
+	cfg_cmd.hostpcm_config = (0x8000) | (0x4000);
+	cfg_cmd.feedback_frequency = 1;
+	cfg_cmd.partition_number = 0;
+
+	(void)audplay_send_queue0(audio, &cfg_cmd, sizeof(cfg_cmd));
+}
+
+static void audqcelp_send_data(struct audio *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (needed && !audio->wflush) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			MM_DBG("frame %d free\n", audio->out_tail);
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+			MM_DBG("frame %d busy\n", audio->out_tail);
+			audplay_dsp_send_data_avail(audio, audio->out_tail,
+						    frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+ done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+
+static void audqcelp_flush(struct audio *audio)
+{
+	audio->out[0].used = 0;
+	audio->out[1].used = 0;
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+}
+
+static void audqcelp_flush_pcm_buf(struct audio *audio)
+{
+	uint8_t index;
+
+	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
+		audio->in[index].used = 0;
+
+	audio->buf_refresh = 0;
+	audio->read_next = 0;
+	audio->fill_next = 0;
+}
+
+static void audqcelp_ioport_reset(struct audio *audio)
+{
+	/* Make sure read/write thread are free from
+	 * sleep and knowing that system is not able
+	 * to process io request at the moment
+	 */
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audqcelp_flush(audio);
+	mutex_unlock(&audio->write_lock);
+	wake_up(&audio->read_wait);
+	mutex_lock(&audio->read_lock);
+	audqcelp_flush_pcm_buf(audio);
+	mutex_unlock(&audio->read_lock);
+	audio->avsync_flag = 1;
+	wake_up(&audio->avsync_wait);
+}
+
+static int audqcelp_events_pending(struct audio *audio)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	return empty || audio->event_abort;
+}
+
+static void audqcelp_reset_event_queue(struct audio *audio)
+{
+	unsigned long flags;
+	struct audqcelp_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audqcelp_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+				struct audqcelp_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	return;
+}
+
+
+static long audqcelp_process_event_req(struct audio *audio, void __user *arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audqcelp_event *drv_evt = NULL;
+	int timeout;
+	unsigned long flags;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int) usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(
+			audio->event_wait, audqcelp_events_pending(audio),
+			msecs_to_jiffies(timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(
+			audio->event_wait, audqcelp_events_pending(audio));
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	rc = 0;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audqcelp_event, list);
+		list_del(&drv_evt->list);
+	}
+
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else
+		rc = -1;
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	if (!rc && copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audio_enable_eq(struct audio *audio, int enable)
+{
+	if (audio->eq_enable == enable && !audio->eq_needs_commit)
+		return 0;
+
+	audio->eq_enable = enable;
+
+	if (audio->running) {
+		audpp_dsp_set_eq(audio->dec_id, enable, &audio->eq, POPP);
+		audio->eq_needs_commit = 0;
+	}
+	return 0;
+}
+
+static int audio_get_avsync_data(struct audio *audio,
+						struct msm_audio_stats *stats)
+{
+	int rc = -EINVAL;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (audio->dec_id == audio->avsync[0] && audio->avsync_flag) {
+		/* av_sync sample count */
+		stats->sample_count = (audio->avsync[2] << 16) |
+						(audio->avsync[3]);
+
+		/* av_sync byte_count */
+		stats->byte_count = (audio->avsync[5] << 16) |
+						(audio->avsync[6]);
+
+		audio->avsync_flag = 0;
+		rc = 0;
+	}
+	local_irq_restore(flags);
+	return rc;
+
+}
+
+static long audqcelp_ioctl(struct file *file, unsigned int cmd,
+		unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = -EINVAL;
+	unsigned long flags = 0;
+	uint16_t enable_mask;
+	int enable;
+	int prev_state;
+
+	MM_DBG("cmd = %d\n", cmd);
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+
+		audio->avsync_flag = 0;
+		memset(&stats, 0, sizeof(stats));
+		if (audpp_query_avsync(audio->dec_id) < 0)
+			return rc;
+
+		rc = wait_event_interruptible_timeout(audio->avsync_wait,
+				(audio->avsync_flag == 1),
+				msecs_to_jiffies(AUDPP_AVSYNC_EVENT_TIMEOUT));
+
+		if (rc < 0)
+			return rc;
+		else if ((rc > 0) || ((rc == 0) && (audio->avsync_flag == 1))) {
+			if (audio_get_avsync_data(audio, &stats) < 0)
+				return rc;
+
+			if (copy_to_user((void *)arg, &stats, sizeof(stats)))
+				return -EFAULT;
+			return 0;
+		} else
+			return -EAGAIN;
+	}
+
+	switch (cmd) {
+	case AUDIO_ENABLE_AUDPP:
+		if (copy_from_user(&enable_mask, (void *) arg,
+						sizeof(enable_mask))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		enable = (enable_mask & EQ_ENABLE) ? 1 : 0;
+		audio_enable_eq(audio, enable);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+	case AUDIO_SET_VOLUME:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.volume = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_PAN:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.pan = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_EQ:
+		prev_state = audio->eq_enable;
+		audio->eq_enable = 0;
+		if (copy_from_user(&audio->eq.num_bands, (void *) arg,
+				sizeof(audio->eq) -
+				(AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2))) {
+			rc = -EFAULT;
+			break;
+		}
+		audio->eq_enable = prev_state;
+		audio->eq_needs_commit = 1;
+		rc = 0;
+		break;
+	}
+
+	if (-EINVAL != rc)
+		return rc;
+
+	if (cmd == AUDIO_GET_EVENT) {
+		MM_DBG("AUDIO_GET_EVENT\n");
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audqcelp_process_event_req(audio,
+					(void __user *) arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		return rc;
+	}
+
+	if (cmd == AUDIO_ABORT_GET_EVENT) {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		MM_DBG("AUDIO_START\n");
+		rc = audqcelp_enable(audio);
+		if (!rc) {
+			rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+			MM_INFO("dec_state %d rc = %d\n", audio->dec_state, rc);
+
+			if (audio->dec_state != MSM_AUD_DECODER_STATE_SUCCESS)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		break;
+	case AUDIO_STOP:
+		MM_DBG("AUDIO_STOP\n");
+		rc = audqcelp_disable(audio);
+		audio->stopped = 1;
+		audqcelp_ioport_reset(audio);
+		audio->stopped = 0;
+		break;
+	case AUDIO_FLUSH:
+		MM_DBG("AUDIO_FLUSH\n");
+		audio->rflush = 1;
+		audio->wflush = 1;
+		audqcelp_ioport_reset(audio);
+		if (audio->running) {
+			audpp_flush(audio->dec_id);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		break;
+	case AUDIO_SET_CONFIG:{
+			struct msm_audio_config config;
+			if (copy_from_user(&config, (void *)arg,
+				sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+			audio->mfield = config.meta_field;
+			MM_DBG("AUDIO_SET_CONFIG applicable \
+				for metafield configuration\n");
+			rc = 0;
+			break;
+		}
+	case AUDIO_GET_CONFIG:{
+			struct msm_audio_config config;
+			config.buffer_size = BUFSZ;
+			config.buffer_count = BUF_COUNT;
+			config.sample_rate = 8000;
+			config.channel_count = 1;
+			config.meta_field = 0;
+			config.unused[0] = 0;
+			config.unused[1] = 0;
+			config.unused[2] = 0;
+			if (copy_to_user((void *)arg, &config,
+					 sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+
+			break;
+		}
+	case AUDIO_GET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+
+			config.pcm_feedback = audio->pcm_feedback;
+			config.buffer_count = PCM_BUF_MAX_COUNT;
+			config.buffer_size = PCM_BUFSZ_MIN;
+			if (copy_to_user((void *)arg, &config,
+				sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_SET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+
+			if (copy_from_user(&config, (void *)arg,
+				sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+			if (config.pcm_feedback != audio->pcm_feedback) {
+				MM_ERR("Not sufficient permission to"
+					 "change the playback mode\n");
+				rc = -EACCES;
+				break;
+			}
+			if ((config.buffer_count > PCM_BUF_MAX_COUNT) ||
+				(config.buffer_count == 1))
+				config.buffer_count = PCM_BUF_MAX_COUNT;
+
+			if (config.buffer_size < PCM_BUFSZ_MIN)
+				config.buffer_size = PCM_BUFSZ_MIN;
+
+			/* Check if pcm feedback is required */
+			if ((config.pcm_feedback) && (!audio->read_data)) {
+				MM_DBG("allocate PCM buf %d\n",
+				config.buffer_count * config.buffer_size);
+				audio->read_phys =
+						allocate_contiguous_ebi_nomap(
+							config.buffer_size *
+							config.buffer_count,
+							SZ_4K);
+				if (!audio->read_phys) {
+					rc = -ENOMEM;
+					break;
+				}
+				audio->map_v_read = ioremap(
+							audio->read_phys,
+							config.buffer_size *
+							config.buffer_count);
+				if (IS_ERR(audio->map_v_read)) {
+					MM_ERR("failed to map read buf\n");
+					rc = -ENOMEM;
+					free_contiguous_memory_by_paddr(
+							audio->read_phys);
+				} else {
+					uint8_t index;
+					uint32_t offset = 0;
+					audio->read_data =
+						audio->map_v_read;
+					audio->buf_refresh = 0;
+					audio->pcm_buf_count =
+						config.buffer_count;
+					audio->read_next = 0;
+					audio->fill_next = 0;
+
+					for (index = 0;
+					index < config.buffer_count; index++) {
+						audio->in[index].data =
+						audio->read_data + offset;
+						audio->in[index].addr =
+						audio->read_phys + offset;
+						audio->in[index].size =
+						config.buffer_size;
+						audio->in[index].used = 0;
+						offset += config.buffer_size;
+					}
+					MM_DBG("read buf: phy addr 0x%08x \
+						kernel addr 0x%08x\n",
+						audio->read_phys,
+						(int)audio->read_data);
+					rc = 0;
+				}
+			} else {
+				rc = 0;
+			}
+			break;
+		}
+	case AUDIO_PAUSE:
+		MM_DBG("AUDIO_PAUSE %ld\n", arg);
+		rc = audpp_pause(audio->dec_id, (int) arg);
+		break;
+	case AUDIO_GET_SESSION_ID:
+		if (copy_to_user((void *) arg, &audio->dec_id,
+				sizeof(unsigned short)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+/* Only useful in tunnel-mode */
+static int audqcelp_fsync(struct file *file, loff_t ppos1, loff_t ppos2, int datasync)
+{
+	struct audio *audio = file->private_data;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (!audio->running || audio->pcm_feedback) {
+		rc = -EINVAL;
+		goto done_nolock;
+	}
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(!audio->out[0].used &&
+		!audio->out[1].used &&
+		audio->out_needed) || audio->wflush);
+
+	if (rc < 0)
+		goto done;
+	else if (audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	/* pcm dmamiss message is sent continously
+	 * when decoder is starved so no race
+	 * condition concern
+	 */
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		audio->teos || audio->wflush);
+
+	if (audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+done_nolock:
+	return rc;
+}
+
+static ssize_t audqcelp_read(struct file *file, char __user *buf, size_t count,
+			loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	int rc = 0;
+
+	if (!audio->pcm_feedback)
+		return 0; /* PCM feedback is not enabled. Nothing to read */
+
+	mutex_lock(&audio->read_lock);
+	MM_DBG("%d\n", count);
+	while (count > 0) {
+		rc = wait_event_interruptible(audio->read_wait,
+				(audio->in[audio->read_next].used > 0) ||
+				(audio->stopped) || (audio->rflush));
+		if (rc < 0)
+			break;
+
+		if (audio->stopped || audio->rflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (count < audio->in[audio->read_next].used) {
+			/* Read must happen in frame boundary. Since driver does
+			not know frame size, read count must be greater or equal
+			to size of PCM samples */
+			MM_DBG("read stop - partial frame\n");
+			break;
+		} else {
+			MM_DBG("read from in[%d]\n", audio->read_next);
+
+			if (copy_to_user(buf,
+				audio->in[audio->read_next].data,
+				audio->in[audio->read_next].used)) {
+				MM_ERR("invalid addr %x\n", (unsigned int)buf);
+				rc = -EFAULT;
+				break;
+			}
+			count -= audio->in[audio->read_next].used;
+			buf += audio->in[audio->read_next].used;
+			audio->in[audio->read_next].used = 0;
+			if ((++audio->read_next) == audio->pcm_buf_count)
+				audio->read_next = 0;
+			break;
+				/* Force to exit while loop
+				 * to prevent output thread
+				 * sleep too long if data is
+				 * not ready at this moment.
+				 */
+		}
+	}
+
+	/* don't feed output buffer to HW decoder during flushing
+	 * buffer refresh command will be sent once flush completes
+	 * send buf refresh command here can confuse HW decoder
+	 */
+	if (audio->buf_refresh && !audio->rflush) {
+		audio->buf_refresh = 0;
+		MM_DBG("kick start pcm feedback again\n");
+		audqcelp_buffer_refresh(audio);
+	}
+
+	mutex_unlock(&audio->read_lock);
+
+	if (buf > start)
+		rc = buf - start;
+
+	MM_DBG("read %d bytes\n", rc);
+	return rc;
+}
+
+static int audqcelp_process_eos(struct audio *audio,
+		const char __user *buf_start, unsigned short mfield_size)
+{
+	struct buffer *frame;
+	int rc = 0;
+
+	frame = audio->out + audio->out_head;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->out_needed &&
+		audio->out[0].used == 0 &&
+		audio->out[1].used == 0)
+		|| (audio->stopped)
+		|| (audio->wflush));
+
+	if (rc < 0)
+		goto done;
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (copy_from_user(frame->data, buf_start, mfield_size)) {
+		rc = -EFAULT;
+		goto done;
+	}
+
+	frame->mfield_sz = mfield_size;
+	audio->out_head ^= 1;
+	frame->used = mfield_size;
+	audqcelp_send_data(audio, 0);
+
+done:
+	return rc;
+}
+
+static ssize_t audqcelp_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	char *cpy_ptr;
+	int rc = 0, eos_condition = AUDQCELP_EOS_NONE;
+	unsigned short mfield_size = 0;
+
+	MM_DBG("cnt=%d\n", count);
+
+	if (count & 1)
+		return -EINVAL;
+
+	mutex_lock(&audio->write_lock);
+	while (count > 0) {
+		frame = audio->out + audio->out_head;
+		cpy_ptr = frame->data;
+		rc = wait_event_interruptible(audio->write_wait,
+					      (frame->used == 0)
+						|| (audio->stopped)
+						|| (audio->wflush));
+		MM_DBG("buffer available\n");
+		if (rc < 0)
+			break;
+		if (audio->stopped || audio->wflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (audio->mfield) {
+			if (buf == start) {
+				/* Processing beginning of user buffer */
+				if (__get_user(mfield_size,
+					(unsigned short __user *) buf)) {
+					rc = -EFAULT;
+					break;
+				} else 	if (mfield_size > count) {
+					rc = -EINVAL;
+					break;
+				}
+				MM_DBG("mf offset_val %x\n", mfield_size);
+				if (copy_from_user(cpy_ptr, buf, mfield_size)) {
+					rc = -EFAULT;
+					break;
+				}
+				/* Check if EOS flag is set and buffer has
+				 * contains just meta field
+				 */
+				if (cpy_ptr[AUDQCELP_EOS_FLG_OFFSET] &
+						AUDQCELP_EOS_FLG_MASK) {
+					MM_DBG("EOS SET\n");
+					eos_condition = AUDQCELP_EOS_SET;
+					if (mfield_size == count) {
+						buf += mfield_size;
+						break;
+					} else
+					cpy_ptr[AUDQCELP_EOS_FLG_OFFSET] &=
+						~AUDQCELP_EOS_FLG_MASK;
+				}
+				cpy_ptr += mfield_size;
+				count -= mfield_size;
+				buf += mfield_size;
+			} else {
+				mfield_size = 0;
+				MM_DBG("continuous buffer\n");
+			}
+			frame->mfield_sz = mfield_size;
+		}
+
+		xfer = (count > (frame->size - mfield_size)) ?
+			(frame->size - mfield_size) : count;
+		if (copy_from_user(cpy_ptr, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+
+		frame->used = xfer + mfield_size;
+		audio->out_head ^= 1;
+		count -= xfer;
+		buf += xfer;
+		audqcelp_send_data(audio, 0);
+	}
+	if (eos_condition == AUDQCELP_EOS_SET)
+		rc = audqcelp_process_eos(audio, start, mfield_size);
+	mutex_unlock(&audio->write_lock);
+	if (!rc) {
+		if (buf > start)
+			return buf - start;
+	}
+	return rc;
+}
+
+static int audqcelp_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	MM_INFO("audio instance 0x%08x freeing\n", (int) audio);
+	mutex_lock(&audio->lock);
+	auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->dec_id);
+	audqcelp_disable(audio);
+	audqcelp_flush(audio);
+	audqcelp_flush_pcm_buf(audio);
+	msm_adsp_put(audio->audplay);
+	audpp_adec_free(audio->dec_id);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&audio->suspend_ctl.node);
+#endif
+	audio->opened = 0;
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audqcelp_reset_event_queue(audio);
+	iounmap(audio->map_v_write);
+	free_contiguous_memory_by_paddr(audio->phys);
+	if (audio->read_data) {
+		iounmap(audio->map_v_read);
+		free_contiguous_memory_by_paddr(audio->read_phys);
+	}
+	mutex_unlock(&audio->lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio);
+	return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audqcelp_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload)
+{
+	struct audqcelp_event *e_node = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+				struct audqcelp_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audqcelp_event), GFP_ATOMIC);
+		if (!e_node) {
+			MM_ERR("No mem to post event %d\n", type);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	wake_up(&audio->event_wait);
+}
+
+static void audqcelp_suspend(struct early_suspend *h)
+{
+	struct audqcelp_suspend_ctl *ctl =
+		container_of(h, struct audqcelp_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audqcelp_post_event(ctl->audio, AUDIO_EVENT_SUSPEND, payload);
+}
+
+static void audqcelp_resume(struct early_suspend *h)
+{
+	struct audqcelp_suspend_ctl *ctl =
+		container_of(h, struct audqcelp_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audqcelp_post_event(ctl->audio, AUDIO_EVENT_RESUME, payload);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audqcelp_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audqcelp_debug_read(struct file *file, char __user *buf,
+					size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 1024;
+	static char buffer[1024];
+	int n = 0, i;
+	struct audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"enabled %d\n", audio->enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_feedback %d\n", audio->pcm_feedback);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_buf_sz %d\n", audio->out[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_buf_count %d \n", audio->pcm_buf_count);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_buf_sz %d \n", audio->in[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"volume %x \n", audio->vol_pan.volume);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"rflush %d\n", audio->rflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"running %d \n", audio->running);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"dec state %d \n", audio->dec_state);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_needed %d \n", audio->out_needed);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_head %d \n", audio->out_head);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_tail %d \n", audio->out_tail);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out[0].used %d \n", audio->out[0].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out[1].used %d \n", audio->out[1].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"buffer_refresh %d \n", audio->buf_refresh);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"read_next %d \n", audio->read_next);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"fill_next %d \n", audio->fill_next);
+	for (i = 0; i < audio->pcm_buf_count; i++)
+		n += scnprintf(buffer + n, debug_bufmax - n,
+				"in[%d].size %d \n", i, audio->in[i].used);
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audqcelp_debug_fops = {
+	.read = audqcelp_debug_read,
+	.open = audqcelp_debug_open,
+};
+#endif
+
+static int audqcelp_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = NULL;
+	int rc, dec_attrb, decid, i;
+	struct audqcelp_event *e_node = NULL;
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_qcelp_" + 5];
+#endif
+
+	/* Create audio instance, set to zero */
+	audio = kzalloc(sizeof(struct audio), GFP_KERNEL);
+	if (!audio) {
+		MM_ERR("no memory to allocate audio instance\n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	MM_INFO("audio instance 0x%08x created\n", (int)audio);
+
+	/* Allocate the decoder */
+	dec_attrb = AUDDEC_DEC_QCELP;
+	if ((file->f_mode & FMODE_WRITE) &&
+			(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_NONTUNNEL;
+		audio->pcm_feedback = NON_TUNNEL_MODE_PLAYBACK;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_TUNNEL;
+		audio->pcm_feedback = TUNNEL_MODE_PLAYBACK;
+	} else {
+		kfree(audio);
+		rc = -EACCES;
+		goto done;
+	}
+	decid = audpp_adec_alloc(dec_attrb, &audio->module_name,
+			&audio->queue_id);
+	if (decid < 0) {
+		MM_ERR("No free decoder available, freeing instance 0x%08x\n",
+				(int)audio);
+		rc = -ENODEV;
+		kfree(audio);
+		goto done;
+	}
+	audio->dec_id = decid & MSM_AUD_DECODER_MASK;
+
+	audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
+	if (!audio->phys) {
+		MM_ERR("could not allocate write buffers, freeing instance \
+				0x%08x\n", (int)audio);
+		rc = -ENOMEM;
+		audpp_adec_free(audio->dec_id);
+		kfree(audio);
+		goto done;
+	} else {
+		audio->map_v_write = ioremap(audio->phys, DMASZ);
+		if (IS_ERR(audio->map_v_write)) {
+			MM_ERR("could not map write phys address, freeing \
+					instance 0x%08x\n", (int)audio);
+			rc = -ENOMEM;
+			free_contiguous_memory_by_paddr(audio->phys);
+			audpp_adec_free(audio->dec_id);
+			kfree(audio);
+			goto done;
+		}
+		audio->data = audio->map_v_write;
+		MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+				audio->phys, (int)audio->data);
+	}
+
+	rc = msm_adsp_get(audio->module_name, &audio->audplay,
+		&audplay_adsp_ops_qcelp, audio);
+	if (rc) {
+		MM_ERR("failed to get %s module, freeing instance  0x%08x\n",
+				audio->module_name, (int)audio);
+		goto err;
+	}
+
+	/* Initialize all locks of audio instance */
+	mutex_init(&audio->lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->get_event_lock);
+	spin_lock_init(&audio->dsp_lock);
+	init_waitqueue_head(&audio->write_wait);
+	init_waitqueue_head(&audio->read_wait);
+	INIT_LIST_HEAD(&audio->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+	init_waitqueue_head(&audio->wait);
+	init_waitqueue_head(&audio->event_wait);
+	spin_lock_init(&audio->event_queue_lock);
+	init_waitqueue_head(&audio->avsync_wait);
+
+	/* Initialize buffer */
+	audio->out[0].data = audio->data + 0;
+	audio->out[0].addr = audio->phys + 0;
+	audio->out[0].size = BUFSZ;
+
+	audio->out[1].data = audio->data + BUFSZ;
+	audio->out[1].addr = audio->phys + BUFSZ;
+	audio->out[1].size = BUFSZ;
+
+	audio->vol_pan.volume = 0x2000;
+
+	audqcelp_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+
+	audio->device_events = AUDDEV_EVT_DEV_RDY
+				|AUDDEV_EVT_DEV_RLS|
+				AUDDEV_EVT_STREAM_VOL_CHG;
+
+	rc = auddev_register_evt_listner(audio->device_events,
+					AUDDEV_CLNT_DEC,
+					audio->dec_id,
+					qcelp_listner,
+					(void *)audio);
+	if (rc) {
+		MM_ERR("%s: failed to register listnet\n", __func__);
+		goto event_err;
+	}
+
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_qcelp_%04x", audio->dec_id);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+			NULL, (void *) audio, &audqcelp_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		MM_DBG("debugfs_create_file failed\n");
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	audio->suspend_ctl.node.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+	audio->suspend_ctl.node.resume = audqcelp_resume;
+	audio->suspend_ctl.node.suspend = audqcelp_suspend;
+	audio->suspend_ctl.audio = audio;
+	register_early_suspend(&audio->suspend_ctl.node);
+#endif
+	for (i = 0; i < AUDQCELP_EVENT_NUM; i++) {
+		e_node = kmalloc(sizeof(struct audqcelp_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			MM_ERR("event pkt alloc failed\n");
+			break;
+		}
+	}
+done:
+	return rc;
+event_err:
+	msm_adsp_put(audio->audplay);
+err:
+	iounmap(audio->map_v_write);
+	free_contiguous_memory_by_paddr(audio->phys);
+	audpp_adec_free(audio->dec_id);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_qcelp_fops = {
+	.owner = THIS_MODULE,
+	.open = audqcelp_open,
+	.release = audqcelp_release,
+	.read = audqcelp_read,
+	.write = audqcelp_write,
+	.unlocked_ioctl = audqcelp_ioctl,
+	.fsync = audqcelp_fsync,
+};
+
+struct miscdevice audio_qcelp_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_qcelp",
+	.fops = &audio_qcelp_fops,
+};
+
+static int __init audqcelp_init(void)
+{
+	return misc_register(&audio_qcelp_misc);
+}
+
+static void __exit audqcelp_exit(void)
+{
+	misc_deregister(&audio_qcelp_misc);
+}
+
+module_init(audqcelp_init);
+module_exit(audqcelp_exit);
+
+MODULE_DESCRIPTION("MSM QCELP 13K driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c b/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
new file mode 100644
index 0000000..e1af2ad
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
@@ -0,0 +1,1513 @@
+/*
+ * qcelp audio input device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2009-2012, Code Aurora Forum. 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.
+ *
+ */
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/msm_audio_qcp.h>
+#include <linux/android_pmem.h>
+#include <linux/memory_alloc.h>
+
+#include <mach/msm_adsp.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/socinfo.h>
+#include <mach/qdsp5v2/qdsp5audreccmdi.h>
+#include <mach/qdsp5v2/qdsp5audrecmsg.h>
+#include <mach/qdsp5v2/audpreproc.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_memtypes.h>
+
+#define META_OUT_SIZE	24
+/* FRAME_NUM must be a power of two */
+#define FRAME_NUM	8
+#define QCELP_FRAME_SIZE	36 /* 36 bytes data */
+#define FRAME_SIZE	(22 * 2) /* 36 bytes data */
+ /* 36 bytes data  + 24 meta field*/
+#define NT_FRAME_SIZE	(QCELP_FRAME_SIZE + META_OUT_SIZE)
+#define DMASZ		(NT_FRAME_SIZE * FRAME_NUM)
+#define OUT_FRAME_NUM	(2)
+#define OUT_BUFFER_SIZE (4 * 1024 + META_OUT_SIZE)
+#define BUFFER_SIZE	(OUT_BUFFER_SIZE * OUT_FRAME_NUM)
+
+
+#define AUDPREPROC_QCELP_EOS_FLG_OFFSET 0x0A
+#define AUDPREPROC_QCELP_EOS_FLG_MASK 0x01
+#define AUDPREPROC_QCELP_EOS_NONE 0x0 /* No EOS detected */
+#define AUDPREPROC_QCELP_EOS_SET 0x1 /* EOS set in meta field */
+
+struct buffer {
+	void *data;
+	uint32_t size;
+	uint32_t read;
+	uint32_t addr;
+	uint32_t used;
+	uint32_t mfield_sz;
+};
+
+struct audio_in {
+	struct buffer in[FRAME_NUM];
+
+	spinlock_t dsp_lock;
+
+	atomic_t in_bytes;
+	atomic_t in_samples;
+
+	struct mutex lock;
+	struct mutex read_lock;
+	wait_queue_head_t wait;
+	wait_queue_head_t wait_enable;
+	/*write section*/
+	struct buffer out[OUT_FRAME_NUM];
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed;	/* number of buffers the dsp is waiting for */
+	uint32_t out_count;
+
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+	int32_t out_phys; /* physical address of write buffer */
+	char *out_data;
+	int mfield; /* meta field embedded in data */
+	int wflush; /*write flush */
+	int rflush; /*read flush*/
+	int out_frame_cnt;
+
+	struct msm_adsp_module *audrec;
+
+	struct audrec_session_info session_info; /*audrec session info*/
+
+	/* configuration to use on next enable */
+	uint32_t buffer_size; /* Frame size (36 bytes) */
+	uint32_t samp_rate;
+	uint32_t channel_mode;
+	uint32_t enc_type;
+
+	struct msm_audio_qcelp_enc_config cfg;
+	uint32_t rec_mode;
+
+	uint32_t dsp_cnt;
+	uint32_t in_head; /* next buffer dsp will write */
+	uint32_t in_tail; /* next buffer read() will read */
+	uint32_t in_count; /* number of buffers available to read() */
+	uint32_t mode;
+	uint32_t eos_ack;
+	uint32_t flush_ack;
+
+	const char *module_name;
+	unsigned queue_ids;
+	uint16_t enc_id;
+
+	uint16_t source; /* Encoding source bit mask */
+	uint32_t device_events;
+	uint32_t in_call;
+	uint32_t dev_cnt;
+	int voice_state;
+	spinlock_t dev_lock;
+
+	/* data allocated for various buffers */
+	char *data;
+	dma_addr_t phys;
+	void *map_v_read;
+	void *map_v_write;
+
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+	char *build_id;
+};
+
+struct audio_frame {
+	uint16_t frame_count_lsw;
+	uint16_t frame_count_msw;
+	uint16_t frame_length;
+	uint16_t erased_pcm;
+	unsigned char raw_bitstream[]; /* samples */
+} __attribute__((packed));
+
+struct audio_frame_nt {
+	uint16_t metadata_len;
+	uint16_t frame_count_lsw;
+	uint16_t frame_count_msw;
+	uint16_t frame_length;
+	uint16_t erased_pcm;
+	uint16_t reserved;
+	uint16_t time_stamp_dword_lsw;
+	uint16_t time_stamp_dword_msw;
+	uint16_t time_stamp_lsw;
+	uint16_t time_stamp_msw;
+	uint16_t nflag_lsw;
+	uint16_t nflag_msw;
+	unsigned char raw_bitstream[]; /* samples */
+} __attribute__((packed));
+
+struct qcelp_encoded_meta_out {
+	uint16_t metadata_len;
+	uint16_t time_stamp_dword_lsw;
+	uint16_t time_stamp_dword_msw;
+	uint16_t time_stamp_lsw;
+	uint16_t time_stamp_msw;
+	uint16_t nflag_lsw;
+	uint16_t nflag_msw;
+};
+
+/* Audrec Queue command sent macro's */
+#define audrec_send_bitstreamqueue(audio, cmd, len) \
+	msm_adsp_write(audio->audrec, ((audio->queue_ids & 0xFFFF0000) >> 16),\
+			cmd, len)
+
+#define audrec_send_audrecqueue(audio, cmd, len) \
+	msm_adsp_write(audio->audrec, (audio->queue_ids & 0x0000FFFF),\
+			cmd, len)
+
+/* DSP command send functions */
+static int audqcelp_in_enc_config(struct audio_in *audio, int enable);
+static int audqcelp_in_param_config(struct audio_in *audio);
+static int audqcelp_in_mem_config(struct audio_in *audio);
+static int audqcelp_in_record_config(struct audio_in *audio, int enable);
+static int audqcelp_dsp_read_buffer(struct audio_in *audio, uint32_t read_cnt);
+
+static void audqcelp_in_get_dsp_frames(struct audio_in *audio);
+static int audpcm_config(struct audio_in *audio);
+static void audqcelp_out_flush(struct audio_in *audio);
+static int audpreproc_cmd_cfg_routing_mode(struct audio_in *audio);
+static void audpreproc_pcm_send_data(struct audio_in *audio, unsigned needed);
+static void audqcelp_nt_in_get_dsp_frames(struct audio_in *audio);
+
+static void audqcelp_in_flush(struct audio_in *audio);
+
+static void qcelp_in_listener(u32 evt_id, union auddev_evt_data *evt_payload,
+				void *private_data)
+{
+	struct audio_in *audio = (struct audio_in *) private_data;
+	unsigned long flags;
+
+	MM_DBG("evt_id = 0x%8x\n", evt_id);
+	switch (evt_id) {
+	case AUDDEV_EVT_DEV_RDY: {
+		MM_DBG("AUDDEV_EVT_DEV_RDY\n");
+		spin_lock_irqsave(&audio->dev_lock, flags);
+		audio->dev_cnt++;
+		if (!audio->in_call)
+			audio->source |= (0x1 << evt_payload->routing_id);
+		spin_unlock_irqrestore(&audio->dev_lock, flags);
+
+		if ((audio->running == 1) && (audio->enabled == 1) &&
+			(audio->mode == MSM_AUD_ENC_MODE_TUNNEL))
+			audqcelp_in_record_config(audio, 1);
+	}
+		break;
+	case AUDDEV_EVT_DEV_RLS: {
+		MM_DBG("AUDDEV_EVT_DEV_RLS\n");
+		spin_lock_irqsave(&audio->dev_lock, flags);
+		audio->dev_cnt--;
+		if (!audio->in_call)
+			audio->source &= ~(0x1 << evt_payload->routing_id);
+		spin_unlock_irqrestore(&audio->dev_lock, flags);
+
+		if ((!audio->running) || (!audio->enabled))
+			break;
+
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+			/* Turn of as per source */
+			if (audio->source)
+				audqcelp_in_record_config(audio, 1);
+			else
+				/* Turn off all */
+				audqcelp_in_record_config(audio, 0);
+		}
+	}
+		break;
+	case AUDDEV_EVT_VOICE_STATE_CHG: {
+		MM_DBG("AUDDEV_EVT_VOICE_STATE_CHG, state = %d\n",
+				evt_payload->voice_state);
+		audio->voice_state = evt_payload->voice_state;
+		if (audio->in_call && audio->running &&
+		   (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)) {
+			if (audio->voice_state == VOICE_STATE_INCALL)
+				audqcelp_in_record_config(audio, 1);
+			else if (audio->voice_state == VOICE_STATE_OFFCALL) {
+				audqcelp_in_record_config(audio, 0);
+				wake_up(&audio->wait);
+			}
+		}
+
+		break;
+	}
+	default:
+		MM_ERR("wrong event %d\n", evt_id);
+		break;
+	}
+}
+
+/* ------------------- dsp preproc event handler--------------------- */
+static void audpreproc_dsp_event(void *data, unsigned id,  void *msg)
+{
+	struct audio_in *audio = data;
+
+	switch (id) {
+	case AUDPREPROC_ERROR_MSG: {
+		struct audpreproc_err_msg *err_msg = msg;
+
+		MM_ERR("ERROR_MSG: stream id %d err idx %d\n",
+		err_msg->stream_id, err_msg->aud_preproc_err_idx);
+		/* Error case */
+		wake_up(&audio->wait_enable);
+		break;
+	}
+	case AUDPREPROC_CMD_CFG_DONE_MSG: {
+		MM_DBG("CMD_CFG_DONE_MSG \n");
+		break;
+	}
+	case AUDPREPROC_CMD_ENC_CFG_DONE_MSG: {
+		struct audpreproc_cmd_enc_cfg_done_msg *enc_cfg_msg = msg;
+
+		MM_DBG("CMD_ENC_CFG_DONE_MSG: stream id %d enc type \
+			0x%8x\n", enc_cfg_msg->stream_id,
+			enc_cfg_msg->rec_enc_type);
+		/* Encoder enable success */
+		if (enc_cfg_msg->rec_enc_type & ENCODE_ENABLE) {
+			if(audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
+				MM_DBG("routing command\n");
+				audpreproc_cmd_cfg_routing_mode(audio);
+			} else {
+				audqcelp_in_param_config(audio);
+			}
+		} else { /* Encoder disable success */
+			audio->running = 0;
+			if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
+				audqcelp_in_record_config(audio, 0);
+			else
+				wake_up(&audio->wait_enable);
+		}
+		break;
+	}
+	case AUDPREPROC_CMD_ENC_PARAM_CFG_DONE_MSG: {
+		MM_DBG("CMD_ENC_PARAM_CFG_DONE_MSG\n");
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
+			audqcelp_in_mem_config(audio);
+		else
+			audpcm_config(audio);
+		break;
+	}
+	case AUDPREPROC_CMD_ROUTING_MODE_DONE_MSG: {
+		struct audpreproc_cmd_routing_mode_done\
+				*routing_cfg_done_msg = msg;
+		if (routing_cfg_done_msg->configuration == 0) {
+			MM_INFO("routing configuration failed\n");
+			audio->running = 0;
+		} else
+			audqcelp_in_param_config(audio);
+		break;
+	}
+	case AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG: {
+		MM_DBG("AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG \n");
+		wake_up(&audio->wait_enable);
+		break;
+	}
+	default:
+		MM_ERR("Unknown Event id %d\n", id);
+	}
+}
+
+/* ------------------- dsp audrec event handler--------------------- */
+static void audrec_dsp_event(void *data, unsigned id, size_t len,
+			    void (*getevent)(void *ptr, size_t len))
+{
+	struct audio_in *audio = data;
+
+	switch (id) {
+	case AUDREC_CMD_MEM_CFG_DONE_MSG: {
+		MM_DBG("CMD_MEM_CFG_DONE MSG DONE\n");
+		audio->running = 1;
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+			if ((!audio->in_call && (audio->dev_cnt > 0)) ||
+				(audio->in_call &&
+					(audio->voice_state \
+						== VOICE_STATE_INCALL)))
+				audqcelp_in_record_config(audio, 1);
+		} else {
+			audpreproc_pcm_send_data(audio, 1);
+			wake_up(&audio->wait_enable);
+		}
+		break;
+	}
+	case AUDREC_FATAL_ERR_MSG: {
+		struct audrec_fatal_err_msg fatal_err_msg;
+
+		getevent(&fatal_err_msg, AUDREC_FATAL_ERR_MSG_LEN);
+		MM_ERR("FATAL_ERR_MSG: err id %d\n",
+				fatal_err_msg.audrec_err_id);
+		/* Error stop the encoder */
+		audio->stopped = 1;
+		wake_up(&audio->wait);
+		if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)
+			wake_up(&audio->write_wait);
+		break;
+	}
+	case AUDREC_UP_PACKET_READY_MSG: {
+		struct audrec_up_pkt_ready_msg pkt_ready_msg;
+
+		getevent(&pkt_ready_msg, AUDREC_UP_PACKET_READY_MSG_LEN);
+		MM_DBG("UP_PACKET_READY_MSG: write cnt lsw  %d \
+		write cnt msw %d read cnt lsw %d  read cnt msw %d \n",\
+		pkt_ready_msg.audrec_packet_write_cnt_lsw, \
+		pkt_ready_msg.audrec_packet_write_cnt_msw, \
+		pkt_ready_msg.audrec_up_prev_read_cnt_lsw, \
+		pkt_ready_msg.audrec_up_prev_read_cnt_msw);
+
+		audqcelp_in_get_dsp_frames(audio);
+		break;
+	}
+	case AUDREC_CMD_PCM_BUFFER_PTR_UPDATE_ARM_TO_ENC_MSG: {
+		MM_DBG("ptr_update recieved from DSP\n");
+		audpreproc_pcm_send_data(audio, 1);
+		break;
+	}
+	case AUDREC_CMD_PCM_CFG_ARM_TO_ENC_DONE_MSG: {
+		MM_ERR("AUDREC_CMD_PCM_CFG_ARM_TO_ENC_DONE_MSG");
+		audqcelp_in_mem_config(audio);
+		break;
+	}
+	case AUDREC_UP_NT_PACKET_READY_MSG: {
+		struct audrec_up_nt_packet_ready_msg pkt_ready_msg;
+
+		getevent(&pkt_ready_msg, AUDREC_UP_NT_PACKET_READY_MSG_LEN);
+		MM_DBG("UP_NT_PACKET_READY_MSG: write cnt lsw  %d \
+		write cnt msw %d read cnt lsw %d  read cnt msw %d \n",\
+		pkt_ready_msg.audrec_packetwrite_cnt_lsw, \
+		pkt_ready_msg.audrec_packetwrite_cnt_msw, \
+		pkt_ready_msg.audrec_upprev_readcount_lsw, \
+		pkt_ready_msg.audrec_upprev_readcount_msw);
+
+		audqcelp_nt_in_get_dsp_frames(audio);
+		break;
+	}
+	case AUDREC_CMD_EOS_ACK_MSG: {
+		MM_DBG("eos ack recieved\n");
+		break;
+	}
+	case AUDREC_CMD_FLUSH_DONE_MSG: {
+		audio->wflush = 0;
+		audio->rflush = 0;
+		audio->flush_ack = 1;
+		wake_up(&audio->write_wait);
+		MM_DBG("flush ack recieved\n");
+		break;
+	}
+	case ADSP_MESSAGE_ID: {
+		MM_DBG("Received ADSP event:module audrectask\n");
+		break;
+	}
+	default:
+		MM_ERR("Unknown Event id %d\n", id);
+	}
+}
+
+static void audqcelp_in_get_dsp_frames(struct audio_in *audio)
+{
+	struct audio_frame *frame;
+	uint32_t index;
+	unsigned long flags;
+
+	MM_DBG("head = %d\n", audio->in_head);
+	index = audio->in_head;
+
+	frame = (void *) (((char *)audio->in[index].data) - \
+			 sizeof(*frame));
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->in[index].size = frame->frame_length;
+
+	/* statistics of read */
+	atomic_add(audio->in[index].size, &audio->in_bytes);
+	atomic_add(1, &audio->in_samples);
+
+	audio->in_head = (audio->in_head + 1) & (FRAME_NUM - 1);
+
+	/* If overflow, move the tail index foward. */
+	if (audio->in_head == audio->in_tail) {
+		MM_ERR("Error! not able to keep up the read\n");
+		audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
+		MM_ERR("in_count = %d\n", audio->in_count);
+	} else
+		audio->in_count++;
+
+	audqcelp_dsp_read_buffer(audio, audio->dsp_cnt++);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+
+	wake_up(&audio->wait);
+}
+
+static void audqcelp_nt_in_get_dsp_frames(struct audio_in *audio)
+{
+	struct audio_frame_nt *nt_frame;
+	uint32_t index;
+	unsigned long flags;
+	MM_DBG("head = %d\n", audio->in_head);
+	index = audio->in_head;
+	nt_frame = (void *) (((char *)audio->in[index].data) - \
+				sizeof(struct audio_frame_nt));
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->in[index].size = nt_frame->frame_length;
+	/* statistics of read */
+	atomic_add(audio->in[index].size, &audio->in_bytes);
+	atomic_add(1, &audio->in_samples);
+
+	audio->in_head = (audio->in_head + 1) & (FRAME_NUM - 1);
+
+	/* If overflow, move the tail index foward. */
+	if (audio->in_head == audio->in_tail)
+		MM_DBG("Error! not able to keep up the read\n");
+	else
+		audio->in_count++;
+
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	wake_up(&audio->wait);
+}
+
+
+struct msm_adsp_ops audrec_qcelp_adsp_ops = {
+	.event = audrec_dsp_event,
+};
+
+static int audpreproc_pcm_buffer_ptr_refresh(struct audio_in *audio,
+				       unsigned idx, unsigned len)
+{
+	struct audrec_cmd_pcm_buffer_ptr_refresh_arm_enc cmd;
+
+	if (len ==  META_OUT_SIZE)
+		len = len / 2;
+	else
+		len = (len + META_OUT_SIZE) / 2;
+	MM_DBG("len = %d\n", len);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_PCM_BUFFER_PTR_REFRESH_ARM_TO_ENC;
+	cmd.num_buffers = 1;
+	if (cmd.num_buffers == 1) {
+		cmd.buf_address_length[0] = (audio->out[idx].addr &
+							0xffff0000) >> 16;
+		cmd.buf_address_length[1] = (audio->out[idx].addr &
+							0x0000ffff);
+		cmd.buf_address_length[2] = (len & 0xffff0000) >> 16;
+		cmd.buf_address_length[3] = (len & 0x0000ffff);
+	}
+	audio->out_frame_cnt++;
+	return audrec_send_audrecqueue(audio, (void *)&cmd,
+					(unsigned int)sizeof(cmd));
+}
+
+
+static int audpcm_config(struct audio_in *audio)
+{
+	struct audrec_cmd_pcm_cfg_arm_to_enc cmd;
+	MM_DBG("\n");
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_PCM_CFG_ARM_TO_ENC;
+	cmd.config_update_flag = AUDREC_PCM_CONFIG_UPDATE_FLAG_ENABLE;
+	cmd.enable_flag = AUDREC_ENABLE_FLAG_VALUE;
+	cmd.sampling_freq = audio->samp_rate;
+	if (!audio->channel_mode)
+		cmd.channels = 1;
+	else
+		cmd.channels = 2;
+	cmd.frequency_of_intimation = 1;
+	cmd.max_number_of_buffers = OUT_FRAME_NUM;
+	return audrec_send_audrecqueue(audio, (void *)&cmd,
+					(unsigned int)sizeof(cmd));
+}
+
+
+static int audpreproc_cmd_cfg_routing_mode(struct audio_in *audio)
+{
+	struct audpreproc_audrec_cmd_routing_mode cmd;
+
+	MM_DBG("\n");
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPREPROC_AUDREC_CMD_ROUTING_MODE;
+	cmd.stream_id = audio->enc_id;
+	if (audio->mode == MSM_ADSP_ENC_MODE_NON_TUNNEL)
+		cmd.routing_mode = 1;
+	return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
+}
+
+
+
+static int audqcelp_in_enc_config(struct audio_in *audio, int enable)
+{
+	struct audpreproc_audrec_cmd_enc_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	if (audio->build_id[17] == '1') {
+		cmd.cmd_id = AUDPREPROC_AUDREC_CMD_ENC_CFG_2;
+		MM_ERR("sending AUDPREPROC_AUDREC_CMD_ENC_CFG_2 command");
+	} else {
+		cmd.cmd_id = AUDPREPROC_AUDREC_CMD_ENC_CFG;
+		MM_ERR("sending AUDPREPROC_AUDREC_CMD_ENC_CFG command");
+	}
+	cmd.stream_id = audio->enc_id;
+
+	if (enable)
+		cmd.audrec_enc_type = audio->enc_type | ENCODE_ENABLE;
+	else
+		cmd.audrec_enc_type &= ~(ENCODE_ENABLE);
+
+	return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
+}
+
+static int audqcelp_in_param_config(struct audio_in *audio)
+{
+	struct audpreproc_audrec_cmd_parm_cfg_qcelp13k cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPREPROC_AUDREC_CMD_PARAM_CFG;
+	cmd.common.stream_id = audio->enc_id;
+
+	cmd.enc_min_rate = audio->cfg.min_bit_rate;
+	cmd.enc_max_rate = audio->cfg.max_bit_rate;
+	cmd.rate_modulation_cmd = 0;  /* Default set to 0 */
+	cmd.reduced_rate_level = 0;  /* Default set to 0 */
+
+	return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
+}
+
+/* To Do: msm_snddev_route_enc(audio->enc_id); */
+static int audqcelp_in_record_config(struct audio_in *audio, int enable)
+{
+	struct audpreproc_afe_cmd_audio_record_cfg cmd;
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG;
+	cmd.stream_id = audio->enc_id;
+	if (enable)
+		cmd.destination_activity = AUDIO_RECORDING_TURN_ON;
+	else
+		cmd.destination_activity = AUDIO_RECORDING_TURN_OFF;
+
+	cmd.source_mix_mask = audio->source;
+	if (audio->enc_id == 2) {
+		if ((cmd.source_mix_mask &
+				INTERNAL_CODEC_TX_SOURCE_MIX_MASK) ||
+			(cmd.source_mix_mask & AUX_CODEC_TX_SOURCE_MIX_MASK) ||
+			(cmd.source_mix_mask & VOICE_UL_SOURCE_MIX_MASK) ||
+			(cmd.source_mix_mask & VOICE_DL_SOURCE_MIX_MASK)) {
+			cmd.pipe_id = SOURCE_PIPE_1;
+		}
+		if (cmd.source_mix_mask &
+				AUDPP_A2DP_PIPE_SOURCE_MIX_MASK)
+			cmd.pipe_id |= SOURCE_PIPE_0;
+	}
+	MM_DBG("stream_id %x destination_activity %x \
+	source_mix_mask %x pipe_id %x",\
+	cmd.stream_id, cmd.destination_activity,
+	cmd.source_mix_mask, cmd.pipe_id);
+	return audpreproc_send_audreccmdqueue(&cmd, sizeof(cmd));
+}
+
+static int audqcelp_in_mem_config(struct audio_in *audio)
+{
+	struct audrec_cmd_arecmem_cfg cmd;
+	uint16_t *data = (void *) audio->data;
+	int n;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_MEM_CFG_CMD;
+	cmd.audrec_up_pkt_intm_count = 1;
+	cmd.audrec_ext_pkt_start_addr_msw = audio->phys >> 16;
+	cmd.audrec_ext_pkt_start_addr_lsw = audio->phys;
+	cmd.audrec_ext_pkt_buf_number = FRAME_NUM;
+	MM_DBG("audio->phys = %x\n", audio->phys);
+	/* prepare buffer pointers:
+	 * T:36 bytes qcelp ppacket + 4 halfword header
+	 * NT:36 bytes qcelp packet + 12 halfword header
+	 */
+	for (n = 0; n < FRAME_NUM; n++) {
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+			audio->in[n].data = data + 4;
+			data += (FRAME_SIZE/2);
+			MM_DBG("0x%8x\n", (int)(audio->in[n].data - 8));
+		} else  {
+			audio->in[n].data = data + 12;
+			data += ((QCELP_FRAME_SIZE) / 2) + 12;
+			MM_DBG("0x%8x\n", (int)(audio->in[n].data - 24));
+		}
+	}
+	return audrec_send_audrecqueue(audio, &cmd, sizeof(cmd));
+}
+
+static int audqcelp_dsp_read_buffer(struct audio_in *audio, uint32_t read_cnt)
+{
+	struct up_audrec_packet_ext_ptr cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = UP_AUDREC_PACKET_EXT_PTR;
+	cmd.audrec_up_curr_read_count_msw = read_cnt >> 16;
+	cmd.audrec_up_curr_read_count_lsw = read_cnt;
+
+	return audrec_send_bitstreamqueue(audio, &cmd, sizeof(cmd));
+}
+static int audqcelp_flush_command(struct audio_in *audio)
+{
+	struct audrec_cmd_flush cmd;
+	MM_DBG("\n");
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_FLUSH;
+	return audrec_send_audrecqueue(audio, &cmd, sizeof(cmd));
+}
+
+/* must be called with audio->lock held */
+static int audqcelp_in_enable(struct audio_in *audio)
+{
+	if (audio->enabled)
+		return 0;
+
+	if (audpreproc_enable(audio->enc_id, &audpreproc_dsp_event, audio)) {
+		MM_ERR("msm_adsp_enable(audpreproc) failed\n");
+		return -ENODEV;
+	}
+
+	if (msm_adsp_enable(audio->audrec)) {
+		MM_ERR("msm_adsp_enable(audrec) failed\n");
+		audpreproc_disable(audio->enc_id, audio);
+		return -ENODEV;
+	}
+	audio->enabled = 1;
+	audqcelp_in_enc_config(audio, 1);
+
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audqcelp_in_disable(struct audio_in *audio)
+{
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audqcelp_in_enc_config(audio, 0);
+		wake_up(&audio->wait);
+		wait_event_interruptible_timeout(audio->wait_enable,
+				audio->running == 0, 1*HZ);
+		msm_adsp_disable(audio->audrec);
+		audpreproc_disable(audio->enc_id, audio);
+	}
+	return 0;
+}
+
+static void audqcelp_ioport_reset(struct audio_in *audio)
+{
+	/* Make sure read/write thread are free from
+	 * sleep and knowing that system is not able
+	 * to process io request at the moment
+	 */
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audqcelp_in_flush(audio);
+	mutex_unlock(&audio->write_lock);
+	wake_up(&audio->wait);
+	mutex_lock(&audio->read_lock);
+	audqcelp_out_flush(audio);
+	mutex_unlock(&audio->read_lock);
+}
+
+static void audqcelp_in_flush(struct audio_in *audio)
+{
+	int i;
+
+	audio->dsp_cnt = 0;
+	audio->in_head = 0;
+	audio->in_tail = 0;
+	audio->in_count = 0;
+	audio->eos_ack = 0;
+	for (i = 0; i < FRAME_NUM; i++) {
+		audio->in[i].size = 0;
+		audio->in[i].read = 0;
+	}
+	MM_DBG("in_bytes %d\n", atomic_read(&audio->in_bytes));
+	MM_DBG("in_samples %d\n", atomic_read(&audio->in_samples));
+	atomic_set(&audio->in_bytes, 0);
+	atomic_set(&audio->in_samples, 0);
+}
+
+static void audqcelp_out_flush(struct audio_in *audio)
+{
+	int i;
+
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->out_count = 0;
+	for (i = 0; i < OUT_FRAME_NUM; i++) {
+		audio->out[i].size = 0;
+		audio->out[i].read = 0;
+		audio->out[i].used = 0;
+	}
+}
+
+/* ------------------- device --------------------- */
+static long audqcelp_in_ioctl(struct file *file,
+				unsigned int cmd, unsigned long arg)
+{
+	struct audio_in *audio = file->private_data;
+	int rc = 0;
+
+	MM_DBG("\n");
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = atomic_read(&audio->in_bytes);
+		stats.sample_count = atomic_read(&audio->in_samples);
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return rc;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START: {
+		uint32_t freq;
+		freq = 48000;
+		MM_DBG("AUDIO_START\n");
+		if (audio->in_call && (audio->voice_state !=
+				VOICE_STATE_INCALL)) {
+			rc = -EPERM;
+			break;
+		}
+		rc = msm_snddev_request_freq(&freq, audio->enc_id,
+					SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
+		MM_DBG("sample rate configured %d\n", freq);
+		if (rc < 0) {
+			MM_DBG(" Sample rate can not be set, return code %d\n",
+								 rc);
+			msm_snddev_withdraw_freq(audio->enc_id,
+					SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
+			MM_DBG("msm_snddev_withdraw_freq\n");
+			break;
+		}
+		/*update aurec session info in audpreproc layer*/
+		audio->session_info.session_id = audio->enc_id;
+		audio->session_info.sampling_freq = audio->samp_rate;
+		audpreproc_update_audrec_info(&audio->session_info);
+		rc = audqcelp_in_enable(audio);
+		if (!rc) {
+			rc =
+			wait_event_interruptible_timeout(audio->wait_enable,
+				audio->running != 0, 1*HZ);
+			MM_DBG("state %d rc = %d\n", audio->running, rc);
+
+			if (audio->running == 0)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		audio->stopped = 0;
+		break;
+	}
+	case AUDIO_STOP: {
+		/*reset the sampling frequency information at audpreproc layer*/
+		audio->session_info.sampling_freq = 0;
+		audpreproc_update_audrec_info(&audio->session_info);
+		rc = audqcelp_in_disable(audio);
+		rc = msm_snddev_withdraw_freq(audio->enc_id,
+					SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
+		MM_DBG("msm_snddev_withdraw_freq\n");
+		audio->stopped = 1;
+		break;
+	}
+	case AUDIO_FLUSH: {
+		MM_DBG("AUDIO_FLUSH\n");
+		audio->rflush = 1;
+		audio->wflush = 1;
+		audqcelp_ioport_reset(audio);
+		if (audio->running) {
+			audqcelp_flush_command(audio);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		break;
+	}
+	case AUDIO_SET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		/* Allow only single frame */
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+			if (cfg.buffer_size != (FRAME_SIZE - 8)) {
+				rc = -EINVAL;
+				break;
+			}
+		} else {
+			if (cfg.buffer_size != (QCELP_FRAME_SIZE + 14)) {
+				rc = -EINVAL;
+				break;
+			}
+		}
+		audio->buffer_size = cfg.buffer_size;
+		break;
+	}
+	case AUDIO_GET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		memset(&cfg, 0, sizeof(cfg));
+		cfg.buffer_size = audio->buffer_size;
+		cfg.buffer_count = FRAME_NUM;
+		if (copy_to_user((void *) arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_GET_QCELP_ENC_CONFIG: {
+		if (copy_to_user((void *) arg, &audio->cfg, sizeof(audio->cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_QCELP_ENC_CONFIG: {
+		struct msm_audio_qcelp_enc_config cfg;
+		if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		MM_DBG("0X%8x, 0x%8x, 0x%8x\n", cfg.min_bit_rate, \
+				cfg.max_bit_rate, cfg.cdma_rate);
+		if (cfg.min_bit_rate > CDMA_RATE_FULL || \
+				 cfg.min_bit_rate < CDMA_RATE_EIGHTH) {
+			MM_ERR("invalid min bitrate\n");
+			rc = -EFAULT;
+			break;
+		}
+		if (cfg.max_bit_rate > CDMA_RATE_FULL || \
+				cfg.max_bit_rate < CDMA_RATE_EIGHTH) {
+			MM_ERR("invalid max bitrate\n");
+			rc = -EFAULT;
+			break;
+		}
+		/* Recording Does not support Erase and Blank */
+		if (cfg.cdma_rate > CDMA_RATE_FULL ||
+			cfg.cdma_rate < CDMA_RATE_EIGHTH) {
+			MM_ERR("invalid qcelp cdma rate\n");
+			rc = -EFAULT;
+			break;
+		}
+		memcpy(&audio->cfg, &cfg, sizeof(cfg));
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config cfg;
+		memset(&cfg, 0, sizeof(cfg));
+		cfg.buffer_size = OUT_BUFFER_SIZE;
+		cfg.buffer_count = OUT_FRAME_NUM;
+		cfg.sample_rate = audio->samp_rate;
+		cfg.channel_count = audio->channel_mode;
+		if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_INCALL: {
+		struct msm_voicerec_mode cfg;
+		unsigned long flags;
+		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+			if (copy_from_user(&cfg, (void *) arg, sizeof(cfg))) {
+				rc = -EFAULT;
+				break;
+			}
+			if (cfg.rec_mode != VOC_REC_BOTH &&
+				cfg.rec_mode != VOC_REC_UPLINK &&
+				cfg.rec_mode != VOC_REC_DOWNLINK) {
+				MM_ERR("invalid rec_mode\n");
+				rc = -EINVAL;
+				break;
+			} else {
+				spin_lock_irqsave(&audio->dev_lock, flags);
+				if (cfg.rec_mode == VOC_REC_UPLINK)
+					audio->source = \
+						VOICE_UL_SOURCE_MIX_MASK;
+				else if (cfg.rec_mode == VOC_REC_DOWNLINK)
+					audio->source = \
+						VOICE_DL_SOURCE_MIX_MASK;
+				else
+					audio->source = \
+						VOICE_DL_SOURCE_MIX_MASK |
+						VOICE_UL_SOURCE_MIX_MASK ;
+				audio->in_call = 1;
+				spin_unlock_irqrestore(&audio->dev_lock, flags);
+			}
+		}
+		break;
+	}
+	case AUDIO_GET_SESSION_ID: {
+		if (copy_to_user((void *) arg, &audio->enc_id,
+			sizeof(unsigned short))) {
+			rc = -EFAULT;
+		}
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static ssize_t audqcelp_in_read(struct file *file,
+				char __user *buf,
+				size_t count, loff_t *pos)
+{
+	struct audio_in *audio = file->private_data;
+	unsigned long flags;
+	const char __user *start = buf;
+	void *data;
+	uint32_t index;
+	uint32_t size;
+	int rc = 0;
+	struct qcelp_encoded_meta_out meta_field;
+	struct audio_frame_nt *nt_frame;
+	MM_DBG(" count = %d\n", count);
+	mutex_lock(&audio->read_lock);
+	while (count > 0) {
+		rc = wait_event_interruptible(
+			audio->wait, (audio->in_count > 0) || audio->stopped ||
+			audio->rflush ||
+			((audio->mode == MSM_AUD_ENC_MODE_TUNNEL) &&
+			 audio->in_call && audio->running &&
+			(audio->voice_state == VOICE_STATE_OFFCALL)));
+		if (rc < 0)
+			break;
+
+		if (audio->rflush) {
+			rc = -EBUSY;
+			break;
+		}
+		if (audio->stopped && !audio->in_count) {
+			MM_DBG("Driver in stop state, No more buffer to read");
+			rc = 0;/* End of File */
+			break;
+			} else if ((audio->mode == MSM_AUD_ENC_MODE_TUNNEL) &&
+					audio->in_call && audio->running &&
+					(audio->voice_state \
+						== VOICE_STATE_OFFCALL)) {
+				MM_DBG("Not Permitted Voice Terminated\n");
+				rc = -EPERM; /* Voice Call stopped */
+				break;
+		}
+
+		index = audio->in_tail;
+		data = (uint8_t *) audio->in[index].data;
+		size = audio->in[index].size;
+
+		if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
+			nt_frame = (struct audio_frame_nt *)(data -
+					sizeof(struct audio_frame_nt));
+			memcpy((char *)&meta_field.time_stamp_dword_lsw,
+				(char *)&nt_frame->time_stamp_dword_lsw,
+				(sizeof(struct qcelp_encoded_meta_out) - \
+				sizeof(uint16_t)));
+			meta_field.metadata_len =
+					sizeof(struct qcelp_encoded_meta_out);
+			if (copy_to_user((char *)start,
+				(char *)&meta_field,
+				sizeof(struct qcelp_encoded_meta_out))) {
+				rc = -EFAULT;
+				break;
+			}
+			if (nt_frame->nflag_lsw & 0x0001) {
+				MM_ERR("recieved EOS in read call\n");
+				audio->eos_ack = 1;
+			}
+			buf += sizeof(struct qcelp_encoded_meta_out);
+			count -= sizeof(struct qcelp_encoded_meta_out);
+		}
+		if (count >= size) {
+			if (copy_to_user(buf, data, size)) {
+				rc = -EFAULT;
+				break;
+			}
+			spin_lock_irqsave(&audio->dsp_lock, flags);
+			if (index != audio->in_tail) {
+				/* overrun -- data is
+				 * invalid and we need to retry */
+				spin_unlock_irqrestore(&audio->dsp_lock, flags);
+				continue;
+			}
+			audio->in[index].size = 0;
+			audio->in_tail = (audio->in_tail + 1) & (FRAME_NUM - 1);
+			audio->in_count--;
+			spin_unlock_irqrestore(&audio->dsp_lock, flags);
+			count -= size;
+			buf += size;
+			if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)) {
+				if (!audio->eos_ack) {
+					MM_DBG("sending read ptr command\
+							%d %d\n",
+							audio->dsp_cnt,
+							audio->in_tail);
+					audqcelp_dsp_read_buffer(audio,
+							audio->dsp_cnt++);
+				}
+			}
+		} else {
+			MM_ERR("short read\n");
+			break;
+		}
+		break;
+	}
+	mutex_unlock(&audio->read_lock);
+
+	if (buf > start)
+		return buf - start;
+
+	return rc;
+}
+
+static void audpreproc_pcm_send_data(struct audio_in *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+	MM_DBG("\n");
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (needed && !audio->wflush) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			MM_DBG("frame %d free\n", audio->out_tail);
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+			audpreproc_pcm_buffer_ptr_refresh(audio,
+						 audio->out_tail,
+						    frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+ done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+
+static int audqcelp_in_fsync(struct file *file, loff_t ppos1, loff_t ppos2, int datasync)
+
+{
+	struct audio_in *audio = file->private_data;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (!audio->running || (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)) {
+		rc = -EINVAL;
+		goto done_nolock;
+	}
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->write_wait,
+			audio->wflush);
+	MM_DBG("waked on by some event audio->wflush = %d\n", audio->wflush);
+
+	if (rc < 0)
+		goto done;
+	else if (audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+done:
+	mutex_unlock(&audio->write_lock);
+done_nolock:
+	return rc;
+
+}
+
+ int audpreproc_qcelp_process_eos(struct audio_in *audio,
+		const char __user *buf_start, unsigned short mfield_size)
+{
+	struct buffer *frame;
+	int rc = 0;
+
+	frame = audio->out + audio->out_head;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->out_needed &&
+		audio->out[0].used == 0 &&
+		audio->out[1].used == 0)
+		|| (audio->stopped)
+		|| (audio->wflush));
+
+	if (rc < 0)
+		goto done;
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+	if (copy_from_user(frame->data, buf_start, mfield_size)) {
+		rc = -EFAULT;
+		goto done;
+	}
+
+	frame->mfield_sz = mfield_size;
+	audio->out_head ^= 1;
+	frame->used = mfield_size;
+	MM_DBG("copying meta_out frame->used = %d\n", frame->used);
+	audpreproc_pcm_send_data(audio, 0);
+done:
+	return rc;
+}
+
+static ssize_t audqcelp_in_write(struct file *file,
+				const char __user *buf,
+				size_t count, loff_t *pos)
+{
+	struct audio_in *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	char *cpy_ptr;
+	int rc = 0, eos_condition = AUDPREPROC_QCELP_EOS_NONE;
+	unsigned short mfield_size = 0;
+	int write_count = 0;
+
+	MM_DBG("cnt=%d\n", count);
+	if (count & 1)
+		return -EINVAL;
+
+	if (audio->mode != MSM_AUD_ENC_MODE_NONTUNNEL)
+		return -EINVAL;
+
+	mutex_lock(&audio->write_lock);
+	frame = audio->out + audio->out_head;
+	/* if supplied count is more than driver buffer size
+	 * then only copy driver buffer size
+	 */
+	if (count > frame->size)
+		count = frame->size;
+
+	write_count = count;
+	cpy_ptr = frame->data;
+	rc = wait_event_interruptible(audio->write_wait,
+				      (frame->used == 0)
+					|| (audio->stopped)
+					|| (audio->wflush));
+	if (rc < 0)
+		goto error;
+
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto error;
+	}
+	if (audio->mfield) {
+		if (buf == start) {
+			/* Processing beginning of user buffer */
+			if (__get_user(mfield_size,
+				(unsigned short __user *) buf)) {
+				rc = -EFAULT;
+				goto error;
+			} else if (mfield_size > count) {
+				rc = -EINVAL;
+				goto error;
+			}
+			MM_DBG("mf offset_val %x\n", mfield_size);
+			if (copy_from_user(cpy_ptr, buf, mfield_size)) {
+				rc = -EFAULT;
+				goto error;
+			}
+			/* Check if EOS flag is set and buffer has
+			 * contains just meta field
+			 */
+			if (cpy_ptr[AUDPREPROC_QCELP_EOS_FLG_OFFSET] &
+					AUDPREPROC_QCELP_EOS_FLG_MASK) {
+				eos_condition = AUDPREPROC_QCELP_EOS_SET;
+				MM_DBG("EOS SET\n");
+				if (mfield_size == count) {
+					buf += mfield_size;
+					eos_condition = 0;
+					goto exit;
+				} else
+				cpy_ptr[AUDPREPROC_QCELP_EOS_FLG_OFFSET] &=
+					~AUDPREPROC_QCELP_EOS_FLG_MASK;
+			}
+			cpy_ptr += mfield_size;
+			count -= mfield_size;
+			buf += mfield_size;
+		} else {
+			mfield_size = 0;
+			MM_DBG("continuous buffer\n");
+		}
+		frame->mfield_sz = mfield_size;
+	}
+	MM_DBG("copying the stream count = %d\n", count);
+	if (copy_from_user(cpy_ptr, buf, count)) {
+		rc = -EFAULT;
+		goto error;
+	}
+exit:
+	frame->used = count;
+	audio->out_head ^= 1;
+	if (!audio->flush_ack)
+		audpreproc_pcm_send_data(audio, 0);
+	else {
+		audpreproc_pcm_send_data(audio, 1);
+		audio->flush_ack = 0;
+	}
+	if (eos_condition == AUDPREPROC_QCELP_EOS_SET)
+		rc = audpreproc_qcelp_process_eos(audio, start, mfield_size);
+	mutex_unlock(&audio->write_lock);
+	return write_count;
+error:
+	mutex_unlock(&audio->write_lock);
+	return rc;
+}
+
+static int audqcelp_in_release(struct inode *inode, struct file *file)
+{
+	struct audio_in *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	audio->in_call = 0;
+	/* with draw frequency for session
+	   incase not stopped the driver */
+	msm_snddev_withdraw_freq(audio->enc_id, SNDDEV_CAP_TX,
+					AUDDEV_CLNT_ENC);
+	auddev_unregister_evt_listner(AUDDEV_CLNT_ENC, audio->enc_id);
+	/*reset the sampling frequency information at audpreproc layer*/
+	audio->session_info.sampling_freq = 0;
+	audpreproc_update_audrec_info(&audio->session_info);
+	audqcelp_in_disable(audio);
+	audqcelp_in_flush(audio);
+	msm_adsp_put(audio->audrec);
+	audpreproc_aenc_free(audio->enc_id);
+	audio->audrec = NULL;
+	audio->opened = 0;
+	if (audio->data) {
+		iounmap(audio->map_v_read);
+		free_contiguous_memory_by_paddr(audio->phys);
+		audio->data = NULL;
+	}
+	if (audio->out_data) {
+		iounmap(audio->map_v_write);
+		free_contiguous_memory_by_paddr(audio->out_phys);
+		audio->out_data = NULL;
+	}
+	mutex_unlock(&audio->lock);
+	return 0;
+}
+
+struct audio_in the_audio_qcelp_in;
+static int audqcelp_in_open(struct inode *inode, struct file *file)
+{
+	struct audio_in *audio = &the_audio_qcelp_in;
+	int rc;
+	int encid;
+
+	mutex_lock(&audio->lock);
+	if (audio->opened) {
+		rc = -EBUSY;
+		goto done;
+	}
+	audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
+	if (audio->phys) {
+		audio->map_v_read = ioremap(audio->phys, DMASZ);
+		if (IS_ERR(audio->map_v_read)) {
+			MM_ERR("could not map DMA buffers\n");
+			rc = -ENOMEM;
+			free_contiguous_memory_by_paddr(audio->phys);
+			goto done;
+		}
+		audio->data = audio->map_v_read;
+	} else {
+		MM_ERR("could not allocate DMA buffers\n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	MM_DBG("Memory addr = 0x%8x  phy addr = 0x%8x\n",\
+		(int) audio->data, (int) audio->phys);
+	if ((file->f_mode & FMODE_WRITE) &&
+		(file->f_mode & FMODE_READ)) {
+		audio->mode = MSM_AUD_ENC_MODE_NONTUNNEL;
+		MM_DBG("Opened for non tunnel mode encoding\n");
+	} else if (!(file->f_mode & FMODE_WRITE) &&
+					(file->f_mode & FMODE_READ)) {
+		audio->mode = MSM_AUD_ENC_MODE_TUNNEL;
+		MM_DBG("Opened for tunnel mode encoding\n");
+	} else {
+		MM_ERR("Invalid mode\n");
+		rc = -EACCES;
+		goto done;
+	}
+
+	/* Settings will be re-config at AUDIO_SET_CONFIG,
+	 * but at least we need to have initial config
+	 */
+	if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL)
+			audio->buffer_size = (QCELP_FRAME_SIZE + 14);
+	else
+			audio->buffer_size = (FRAME_SIZE - 8);
+	audio->enc_type = ENC_TYPE_V13K | audio->mode;
+	audio->samp_rate = 8000;
+	audio->channel_mode = AUDREC_CMD_MODE_MONO;
+	audio->cfg.cdma_rate = CDMA_RATE_FULL;
+	audio->cfg.min_bit_rate = CDMA_RATE_FULL;
+	audio->cfg.max_bit_rate = CDMA_RATE_FULL;
+	audio->source = INTERNAL_CODEC_TX_SOURCE_MIX_MASK;
+	audio->rec_mode = VOC_REC_UPLINK;
+
+	encid = audpreproc_aenc_alloc(audio->enc_type, &audio->module_name,
+			&audio->queue_ids);
+	if (encid < 0) {
+		MM_ERR("No free encoder available\n");
+		rc = -ENODEV;
+		goto done;
+	}
+	audio->enc_id = encid;
+
+	rc = msm_adsp_get(audio->module_name, &audio->audrec,
+			   &audrec_qcelp_adsp_ops, audio);
+
+	if (rc) {
+		audpreproc_aenc_free(audio->enc_id);
+		goto done;
+	}
+
+	audio->stopped = 0;
+	audio->source = 0;
+	audio->wflush = 0;
+	audio->rflush = 0;
+	audio->flush_ack = 0;
+
+	audqcelp_in_flush(audio);
+	audqcelp_out_flush(audio);
+
+	audio->out_phys = allocate_contiguous_ebi_nomap(BUFFER_SIZE, SZ_4K);
+	if (!audio->out_phys) {
+		MM_ERR("could not allocate write buffers\n");
+		rc = -ENOMEM;
+		goto evt_error;
+	} else {
+		audio->map_v_write = ioremap(audio->out_phys, BUFFER_SIZE);
+		if (IS_ERR(audio->map_v_write)) {
+			MM_ERR("could not map write buffers\n");
+			rc = -ENOMEM;
+			free_contiguous_memory_by_paddr(audio->out_phys);
+			goto evt_error;
+		}
+		audio->out_data = audio->map_v_write;
+		MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+				audio->out_phys, (int)audio->out_data);
+	}
+
+		/* Initialize buffer */
+	audio->out[0].data = audio->out_data + 0;
+	audio->out[0].addr = audio->out_phys + 0;
+	audio->out[0].size = OUT_BUFFER_SIZE;
+
+	audio->out[1].data = audio->out_data + OUT_BUFFER_SIZE;
+	audio->out[1].addr = audio->out_phys + OUT_BUFFER_SIZE;
+	audio->out[1].size = OUT_BUFFER_SIZE;
+
+	MM_DBG("audio->out[0].data = %d  audio->out[1].data = %d",
+					(unsigned int)audio->out[0].data,
+					(unsigned int)audio->out[1].data);
+	audio->device_events = AUDDEV_EVT_DEV_RDY | AUDDEV_EVT_DEV_RLS |
+				AUDDEV_EVT_VOICE_STATE_CHG;
+
+	audio->voice_state = msm_get_voice_state();
+	rc = auddev_register_evt_listner(audio->device_events,
+					AUDDEV_CLNT_ENC, audio->enc_id,
+					qcelp_in_listener, (void *) audio);
+	if (rc) {
+		MM_ERR("failed to register device event listener\n");
+		iounmap(audio->map_v_write);
+		free_contiguous_memory_by_paddr(audio->out_phys);
+		goto evt_error;
+	}
+	audio->mfield = META_OUT_SIZE;
+	file->private_data = audio;
+	audio->opened = 1;
+	audio->out_frame_cnt++;
+	audio->build_id = socinfo_get_build_id();
+	MM_DBG("Modem build id = %s\n", audio->build_id);
+done:
+	mutex_unlock(&audio->lock);
+	return rc;
+evt_error:
+	msm_adsp_put(audio->audrec);
+	audpreproc_aenc_free(audio->enc_id);
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static const struct file_operations audio_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audqcelp_in_open,
+	.release	= audqcelp_in_release,
+	.read		= audqcelp_in_read,
+	.write		= audqcelp_in_write,
+	.fsync		= audqcelp_in_fsync,
+	.unlocked_ioctl	= audqcelp_in_ioctl,
+};
+
+struct miscdevice audio_qcelp_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_qcelp_in",
+	.fops	= &audio_in_fops,
+};
+
+static int __init audqcelp_in_init(void)
+{
+	mutex_init(&the_audio_qcelp_in.lock);
+	mutex_init(&the_audio_qcelp_in.read_lock);
+	spin_lock_init(&the_audio_qcelp_in.dsp_lock);
+	spin_lock_init(&the_audio_qcelp_in.dev_lock);
+	init_waitqueue_head(&the_audio_qcelp_in.wait);
+	init_waitqueue_head(&the_audio_qcelp_in.wait_enable);
+	mutex_init(&the_audio_qcelp_in.write_lock);
+	init_waitqueue_head(&the_audio_qcelp_in.write_wait);
+	return misc_register(&audio_qcelp_in_misc);
+}
+
+device_initcall(audqcelp_in_init);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_wma.c b/arch/arm/mach-msm/qdsp5v2/audio_wma.c
new file mode 100644
index 0000000..80adebd
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/audio_wma.c
@@ -0,0 +1,1797 @@
+/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+ *
+ * Based on the mp3 native driver in arch/arm/mach-msm/qdsp5v2/audio_mp3.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/earlysuspend.h>
+#include <linux/android_pmem.h>
+#include <linux/slab.h>
+#include <linux/msm_audio.h>
+#include <linux/msm_audio_wma.h>
+#include <linux/memory_alloc.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+
+#include <mach/msm_adsp.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/qdsp5v2/qdsp5audppmsg.h>
+#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
+#include <mach/qdsp5v2/qdsp5audplaymsg.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/qdsp5v2/audpp.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_memtypes.h>
+
+/* Size must be power of 2 */
+#define BUFSZ_MAX 	4110	/* Includes meta in size */
+#define BUFSZ_MIN 	1038	/* Includes meta in size */
+#define DMASZ_MAX 	(BUFSZ_MAX * 2)
+#define DMASZ_MIN 	(BUFSZ_MIN * 2)
+
+#define AUDPLAY_INVALID_READ_PTR_OFFSET	0xFFFF
+#define AUDDEC_DEC_WMA 4
+
+#define PCM_BUFSZ_MIN 	8216 	/* Hold one stereo WMA frame and meta out*/
+#define PCM_BUF_MAX_COUNT 5	/* DSP only accepts 5 buffers at most
+				   but support 2 buffers currently */
+#define ROUTING_MODE_FTRT 1
+#define ROUTING_MODE_RT 2
+/* Decoder status received from AUDPPTASK */
+#define  AUDPP_DEC_STATUS_SLEEP	0
+#define	 AUDPP_DEC_STATUS_INIT  1
+#define  AUDPP_DEC_STATUS_CFG   2
+#define  AUDPP_DEC_STATUS_PLAY  3
+
+#define AUDWMA_METAFIELD_MASK 0xFFFF0000
+#define AUDWMA_EOS_FLG_OFFSET 0x0A /* Offset from beginning of buffer */
+#define AUDWMA_EOS_FLG_MASK 0x01
+#define AUDWMA_EOS_NONE 0x0 /* No EOS detected */
+#define AUDWMA_EOS_SET 0x1 /* EOS set in meta field */
+
+#define AUDWMA_EVENT_NUM 10 /* Default number of pre-allocated event packets */
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+	unsigned short mfield_sz; /*only useful for data has meta field */
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct audwma_suspend_ctl {
+	struct early_suspend node;
+	struct audio *audio;
+};
+#endif
+
+struct audwma_event{
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+
+struct audio {
+	struct buffer out[2];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed; /* number of buffers the dsp is waiting for */
+	unsigned out_dma_sz;
+
+	atomic_t out_bytes;
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	/* Host PCM section */
+	struct buffer in[PCM_BUF_MAX_COUNT];
+	struct mutex read_lock;
+	wait_queue_head_t read_wait;	/* Wait queue for read */
+	char *read_data;	/* pointer to reader buffer */
+	int32_t read_phys;	/* physical address of reader buffer */
+	uint8_t read_next;	/* index to input buffers to be read next */
+	uint8_t fill_next;	/* index to buffer that DSP should be filling */
+	uint8_t pcm_buf_count;	/* number of pcm buffer allocated */
+	/* ---- End of Host PCM section */
+
+	struct msm_adsp_module *audplay;
+
+	/* configuration to use on next enable */
+	uint32_t out_sample_rate;
+	uint32_t out_channel_mode;
+
+	struct msm_audio_wma_config wma_config;
+
+	/* data allocated for various buffers */
+	char *data;
+	int32_t phys; /* physical address of write buffer */
+	void *map_v_read;
+	void *map_v_write;
+
+	int mfield; /* meta field embedded in data */
+	int rflush; /* Read  flush */
+	int wflush; /* Write flush */
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+	int pcm_feedback;
+	int buf_refresh;
+	int teos; /* valid only if tunnel mode & no data left for decoder */
+	enum msm_aud_decoder_state dec_state;	/* Represents decoder state */
+	int reserved; /* A byte is being reserved */
+	char rsv_byte; /* Handle odd length user data */
+
+	const char *module_name;
+	unsigned queue_id;
+	uint16_t dec_id;
+	uint32_t read_ptr_offset;
+	int16_t source;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct audwma_suspend_ctl suspend_ctl;
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+
+	wait_queue_head_t wait;
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	wait_queue_head_t event_wait;
+	spinlock_t event_queue_lock;
+	struct mutex get_event_lock;
+	int event_abort;
+	/* AV sync Info */
+	int avsync_flag;              /* Flag to indicate feedback from DSP */
+	wait_queue_head_t avsync_wait;/* Wait queue for AV Sync Message     */
+	/* flags, 48 bits sample/bytes counter per channel */
+	uint16_t avsync[AUDPP_AVSYNC_CH_COUNT * AUDPP_AVSYNC_NUM_WORDS + 1];
+
+	uint32_t device_events;
+
+	int eq_enable;
+	int eq_needs_commit;
+	struct audpp_cmd_cfg_object_params_eqalizer eq;
+	struct audpp_cmd_cfg_object_params_volume vol_pan;
+};
+
+static int auddec_dsp_config(struct audio *audio, int enable);
+static void audpp_cmd_cfg_adec_params(struct audio *audio);
+static void audpp_cmd_cfg_routing_mode(struct audio *audio);
+static void audplay_send_data(struct audio *audio, unsigned needed);
+static void audplay_config_hostpcm(struct audio *audio);
+static void audplay_buffer_refresh(struct audio *audio);
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audwma_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload);
+#endif
+/* must be called with audio->lock held */
+static int audio_enable(struct audio *audio)
+{
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled)
+		return 0;
+
+	audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	if (msm_adsp_enable(audio->audplay)) {
+		MM_ERR("msm_adsp_enable(audplay) failed\n");
+		return -ENODEV;
+	}
+
+	if (audpp_enable(audio->dec_id, audio_dsp_event, audio)) {
+		MM_ERR("audpp_enable() failed\n");
+		msm_adsp_disable(audio->audplay);
+		return -ENODEV;
+	}
+
+	audio->enabled = 1;
+	return 0;
+}
+
+static void wma_listner(u32 evt_id, union auddev_evt_data *evt_payload,
+			void *private_data)
+{
+	struct audio *audio = (struct audio *) private_data;
+	switch (evt_id) {
+	case AUDDEV_EVT_DEV_RDY:
+		MM_DBG(":AUDDEV_EVT_DEV_RDY\n");
+		audio->source |= (0x1 << evt_payload->routing_id);
+		if (audio->running == 1 && audio->enabled == 1)
+			audpp_route_stream(audio->dec_id, audio->source);
+		break;
+	case AUDDEV_EVT_DEV_RLS:
+		MM_DBG(":AUDDEV_EVT_DEV_RLS\n");
+		audio->source &= ~(0x1 << evt_payload->routing_id);
+		if (audio->running == 1 && audio->enabled == 1)
+			audpp_route_stream(audio->dec_id, audio->source);
+		break;
+	case AUDDEV_EVT_STREAM_VOL_CHG:
+		audio->vol_pan.volume = evt_payload->session_vol;
+		MM_DBG(":AUDDEV_EVT_STREAM_VOL_CHG, stream vol %d\n",
+				audio->vol_pan.volume);
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+		break;
+	default:
+		MM_ERR(":ERROR:wrong event\n");
+		break;
+	}
+}
+/* must be called with audio->lock held */
+static int audio_disable(struct audio *audio)
+{
+	int rc = 0;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+		auddec_dsp_config(audio, 0);
+		rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+		else if (audio->dec_state != MSM_AUD_DECODER_STATE_CLOSE)
+			rc = -EFAULT;
+		else
+			rc = 0;
+		wake_up(&audio->write_wait);
+		wake_up(&audio->read_wait);
+		msm_adsp_disable(audio->audplay);
+		audpp_disable(audio->dec_id, audio);
+		audio->out_needed = 0;
+	}
+	return rc;
+}
+
+/* ------------------- dsp --------------------- */
+static void audio_update_pcm_buf_entry(struct audio *audio,
+	uint32_t *payload)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	if (audio->rflush)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < payload[1]; index++) {
+		if (audio->in[audio->fill_next].addr ==
+			payload[2 + index * 2]) {
+			MM_DBG("audio_update_pcm_buf_entry: \
+				in[%d] ready\n", audio->fill_next);
+			audio->in[audio->fill_next].used =
+			payload[3 + index * 2];
+			if ((++audio->fill_next) == audio->pcm_buf_count)
+				audio->fill_next = 0;
+		} else {
+			MM_ERR("audio_update_pcm_buf_entry: \
+				expected=%x ret=%x\n",
+				audio->in[audio->fill_next].addr,
+				payload[1 + index * 2]);
+			break;
+		}
+	}
+	if (audio->in[audio->fill_next].used == 0) {
+		audplay_buffer_refresh(audio);
+	} else {
+		MM_DBG("read cannot keep up\n");
+		audio->buf_refresh = 1;
+	}
+	wake_up(&audio->read_wait);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static void audplay_dsp_event(void *data, unsigned id, size_t len,
+			      void (*getevent) (void *ptr, size_t len))
+{
+	struct audio *audio = data;
+	uint32_t msg[28];
+
+	getevent(msg, sizeof(msg));
+
+	MM_DBG("msg_id=%x\n", id);
+
+	switch (id) {
+	case AUDPLAY_MSG_DEC_NEEDS_DATA:
+		audplay_send_data(audio, 1);
+		break;
+
+	case AUDPLAY_MSG_BUFFER_UPDATE:
+		audio_update_pcm_buf_entry(audio, msg);
+		break;
+
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audplaytask)\n");
+		break;
+
+	default:
+		MM_ERR("unexpected message from decoder \n");
+		break;
+	}
+}
+
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned status = msg[1];
+
+			switch (status) {
+			case AUDPP_DEC_STATUS_SLEEP: {
+				uint16_t reason = msg[2];
+				MM_DBG("decoder status:sleep reason = \
+						0x%04x\n", reason);
+				if ((reason == AUDPP_MSG_REASON_MEM)
+					|| (reason ==
+					AUDPP_MSG_REASON_NODECODER)) {
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_FAILURE;
+					wake_up(&audio->wait);
+				} else if (reason == AUDPP_MSG_REASON_NONE) {
+					/* decoder is in disable state */
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_CLOSE;
+					wake_up(&audio->wait);
+				}
+				break;
+			}
+			case AUDPP_DEC_STATUS_INIT:
+				MM_DBG("decoder status: init\n");
+				if (audio->pcm_feedback)
+					audpp_cmd_cfg_routing_mode(audio);
+				else
+					audpp_cmd_cfg_adec_params(audio);
+				break;
+
+			case AUDPP_DEC_STATUS_CFG:
+				MM_DBG("decoder status: cfg\n");
+				break;
+			case AUDPP_DEC_STATUS_PLAY:
+				MM_DBG("decoder status: play \n");
+				/* send  mixer command */
+				audpp_route_stream(audio->dec_id,
+						audio->source);
+				if (audio->pcm_feedback) {
+					audplay_config_hostpcm(audio);
+					audplay_buffer_refresh(audio);
+				}
+				audio->dec_state =
+					MSM_AUD_DECODER_STATE_SUCCESS;
+				wake_up(&audio->wait);
+				break;
+			default:
+				MM_ERR("unknown decoder status\n");
+			}
+			break;
+		}
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			MM_DBG("CFG_MSG ENABLE\n");
+			auddec_dsp_config(audio, 1);
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+			audpp_dsp_set_eq(audio->dec_id, audio->eq_enable,
+					&audio->eq, POPP);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			MM_DBG("CFG_MSG DISABLE\n");
+			audio->running = 0;
+		} else {
+			MM_DBG("CFG_MSG %d?\n", msg[0]);
+		}
+		break;
+	case AUDPP_MSG_ROUTING_ACK:
+		MM_DBG("ROUTING_ACK mode=%d\n", msg[1]);
+		audpp_cmd_cfg_adec_params(audio);
+		break;
+
+	case AUDPP_MSG_FLUSH_ACK:
+		MM_DBG("FLUSH_ACK\n");
+		audio->wflush = 0;
+		audio->rflush = 0;
+		wake_up(&audio->write_wait);
+		if (audio->pcm_feedback)
+			audplay_buffer_refresh(audio);
+		break;
+
+	case AUDPP_MSG_PCMDMAMISSED:
+		MM_DBG("PCMDMAMISSED\n");
+		audio->teos = 1;
+		wake_up(&audio->write_wait);
+		break;
+
+	case AUDPP_MSG_AVSYNC_MSG:
+		MM_DBG("AUDPP_MSG_AVSYNC_MSG\n");
+		memcpy(&audio->avsync[0], msg, sizeof(audio->avsync));
+		audio->avsync_flag = 1;
+		wake_up(&audio->avsync_wait);
+		break;
+
+	default:
+		MM_ERR("UNKNOWN (%d)\n", id);
+	}
+
+}
+
+static struct msm_adsp_ops audplay_adsp_ops_wma = {
+	.event = audplay_dsp_event,
+};
+
+#define audplay_send_queue0(audio, cmd, len) \
+	msm_adsp_write(audio->audplay, audio->queue_id, \
+			cmd, len)
+
+static int auddec_dsp_config(struct audio *audio, int enable)
+{
+	struct audpp_cmd_cfg_dec_type cfg_dec_cmd;
+
+	memset(&cfg_dec_cmd, 0, sizeof(cfg_dec_cmd));
+
+	cfg_dec_cmd.cmd_id = AUDPP_CMD_CFG_DEC_TYPE;
+	if (enable)
+		cfg_dec_cmd.dec_cfg = AUDPP_CMD_UPDATDE_CFG_DEC |
+				AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_WMA;
+	else
+		cfg_dec_cmd.dec_cfg = AUDPP_CMD_UPDATDE_CFG_DEC |
+				AUDPP_CMD_DIS_DEC_V;
+	cfg_dec_cmd.dm_mode = 0x0;
+	cfg_dec_cmd.stream_id = audio->dec_id;
+	return audpp_send_queue1(&cfg_dec_cmd, sizeof(cfg_dec_cmd));
+}
+
+static void audpp_cmd_cfg_adec_params(struct audio *audio)
+{
+	struct audpp_cmd_cfg_adec_params_wma cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_WMA_LEN;
+	cmd.common.dec_id = audio->dec_id;
+	cmd.common.input_sampling_frequency = audio->out_sample_rate;
+
+	/*
+	 * Test done for sample with the following configuration
+	 * armdatareqthr 	= 1262
+	 * channelsdecoded 	= 1(MONO)/2(STEREO)
+	 * wmabytespersec 	= Tested with 6003 Bytes per sec
+	 * wmasamplingfreq	= 44100
+	 * wmaencoderopts	= 31
+	 */
+
+	cmd.armdatareqthr = audio->wma_config.armdatareqthr;
+	cmd.channelsdecoded = audio->wma_config.channelsdecoded;
+	cmd.wmabytespersec = audio->wma_config.wmabytespersec;
+	cmd.wmasamplingfreq = audio->wma_config.wmasamplingfreq;
+	cmd.wmaencoderopts = audio->wma_config.wmaencoderopts;
+
+	audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static void audpp_cmd_cfg_routing_mode(struct audio *audio)
+{
+	struct audpp_cmd_routing_mode cmd;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_ROUTING_MODE;
+	cmd.object_number = audio->dec_id;
+	if (audio->pcm_feedback)
+		cmd.routing_mode = ROUTING_MODE_FTRT;
+	else
+		cmd.routing_mode = ROUTING_MODE_RT;
+
+	audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static void audplay_buffer_refresh(struct audio *audio)
+{
+	struct audplay_cmd_buffer_refresh refresh_cmd;
+
+	refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH;
+	refresh_cmd.num_buffers = 1;
+	refresh_cmd.buf0_address = audio->in[audio->fill_next].addr;
+	refresh_cmd.buf0_length = audio->in[audio->fill_next].size;
+	refresh_cmd.buf_read_count = 0;
+
+	MM_DBG("buf0_addr=%x buf0_len=%d\n",
+			refresh_cmd.buf0_address,
+			refresh_cmd.buf0_length);
+
+	(void)audplay_send_queue0(audio, &refresh_cmd, sizeof(refresh_cmd));
+}
+
+static void audplay_config_hostpcm(struct audio *audio)
+{
+	struct audplay_cmd_hpcm_buf_cfg cfg_cmd;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	cfg_cmd.cmd_id = AUDPLAY_CMD_HPCM_BUF_CFG;
+	cfg_cmd.max_buffers = audio->pcm_buf_count;
+	cfg_cmd.byte_swap = 0;
+	cfg_cmd.hostpcm_config = (0x8000) | (0x4000);
+	cfg_cmd.feedback_frequency = 1;
+	cfg_cmd.partition_number = 0;
+
+	(void)audplay_send_queue0(audio, &cfg_cmd, sizeof(cfg_cmd));
+}
+
+
+static int audplay_dsp_send_data_avail(struct audio *audio,
+					unsigned idx, unsigned len)
+{
+	struct audplay_cmd_bitstream_data_avail_nt2 cmd;
+
+	cmd.cmd_id		= AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_NT2;
+	if (!audio->pcm_feedback)
+		cmd.decoder_id = 0;
+	else {
+		if (audio->mfield)
+			cmd.decoder_id = AUDWMA_METAFIELD_MASK |
+			(audio->out[idx].mfield_sz >> 1);
+		else
+			cmd.decoder_id		= audio->dec_id;
+	}
+	cmd.buf_ptr		= audio->out[idx].addr;
+	cmd.buf_size		= len/2;
+	cmd.partition_number	= 0;
+	return audplay_send_queue0(audio, &cmd, sizeof(cmd));
+}
+
+static void audplay_send_data(struct audio *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (audio->wflush) {
+		audio->out_needed = 1;
+		goto done;
+	}
+
+	if (needed && !audio->wflush) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			MM_DBG("frame %d free\n", audio->out_tail);
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		MM_DBG("\n"); /* Macro prints the file name and function */
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+			MM_DBG("frame %d busy\n", audio->out_tail);
+			audplay_dsp_send_data_avail(audio, audio->out_tail,
+								frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+
+static void audio_flush(struct audio *audio)
+{
+	audio->out[0].used = 0;
+	audio->out[1].used = 0;
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->reserved = 0;
+	atomic_set(&audio->out_bytes, 0);
+}
+
+static void audio_flush_pcm_buf(struct audio *audio)
+{
+	uint8_t index;
+
+	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
+		audio->in[index].used = 0;
+	audio->buf_refresh = 0;
+	audio->read_next = 0;
+	audio->fill_next = 0;
+}
+
+static void audio_ioport_reset(struct audio *audio)
+{
+	/* Make sure read/write thread are free from
+	 * sleep and knowing that system is not able
+	 * to process io request at the moment
+	 */
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audio_flush(audio);
+	mutex_unlock(&audio->write_lock);
+	wake_up(&audio->read_wait);
+	mutex_lock(&audio->read_lock);
+	audio_flush_pcm_buf(audio);
+	mutex_unlock(&audio->read_lock);
+	audio->avsync_flag = 1;
+	wake_up(&audio->avsync_wait);
+}
+
+static int audwma_events_pending(struct audio *audio)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	return empty || audio->event_abort;
+}
+
+static void audwma_reset_event_queue(struct audio *audio)
+{
+	unsigned long flags;
+	struct audwma_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audwma_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+				struct audwma_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	return;
+}
+
+static long audwma_process_event_req(struct audio *audio, void __user *arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audwma_event *drv_evt = NULL;
+	int timeout;
+	unsigned long flags;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int) usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(
+				audio->event_wait, audwma_events_pending(audio),
+				msecs_to_jiffies(timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(
+			audio->event_wait, audwma_events_pending(audio));
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	rc = 0;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audwma_event, list);
+		list_del(&drv_evt->list);
+	}
+
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else
+		rc = -1;
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	if (!rc && copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audio_enable_eq(struct audio *audio, int enable)
+{
+	if (audio->eq_enable == enable && !audio->eq_needs_commit)
+		return 0;
+
+	audio->eq_enable = enable;
+
+	if (audio->running) {
+		audpp_dsp_set_eq(audio->dec_id, enable, &audio->eq, POPP);
+		audio->eq_needs_commit = 0;
+	}
+	return 0;
+}
+
+static int audio_get_avsync_data(struct audio *audio,
+						struct msm_audio_stats *stats)
+{
+	int rc = -EINVAL;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (audio->dec_id == audio->avsync[0] && audio->avsync_flag) {
+		/* av_sync sample count */
+		stats->sample_count = (audio->avsync[2] << 16) |
+						(audio->avsync[3]);
+
+		/* av_sync byte_count */
+		stats->byte_count = (audio->avsync[5] << 16) |
+						(audio->avsync[6]);
+
+		audio->avsync_flag = 0;
+		rc = 0;
+	}
+	local_irq_restore(flags);
+	return rc;
+
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = -EINVAL;
+	unsigned long flags = 0;
+	uint16_t enable_mask;
+	int enable;
+	int prev_state;
+
+	MM_DBG("cmd = %d\n", cmd);
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+
+		audio->avsync_flag = 0;
+		memset(&stats, 0, sizeof(stats));
+		if (audpp_query_avsync(audio->dec_id) < 0)
+			return rc;
+
+		rc = wait_event_interruptible_timeout(audio->avsync_wait,
+				(audio->avsync_flag == 1),
+				msecs_to_jiffies(AUDPP_AVSYNC_EVENT_TIMEOUT));
+
+		if (rc < 0)
+			return rc;
+		else if ((rc > 0) || ((rc == 0) && (audio->avsync_flag == 1))) {
+			if (audio_get_avsync_data(audio, &stats) < 0)
+				return rc;
+
+			if (copy_to_user((void *)arg, &stats, sizeof(stats)))
+				return -EFAULT;
+			return 0;
+		} else
+			return -EAGAIN;
+	}
+
+	switch (cmd) {
+	case AUDIO_ENABLE_AUDPP:
+		if (copy_from_user(&enable_mask, (void *) arg,
+						sizeof(enable_mask))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		enable = (enable_mask & EQ_ENABLE) ? 1 : 0;
+		audio_enable_eq(audio, enable);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+	case AUDIO_SET_VOLUME:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.volume = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_PAN:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.pan = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_EQ:
+		prev_state = audio->eq_enable;
+		audio->eq_enable = 0;
+		if (copy_from_user(&audio->eq.num_bands, (void *) arg,
+				sizeof(audio->eq) -
+				(AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2))) {
+			rc = -EFAULT;
+			break;
+		}
+		audio->eq_enable = prev_state;
+		audio->eq_needs_commit = 1;
+		rc = 0;
+		break;
+	}
+
+	if (-EINVAL != rc)
+		return rc;
+
+	if (cmd == AUDIO_GET_EVENT) {
+		MM_DBG("AUDIO_GET_EVENT\n");
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audwma_process_event_req(audio,
+					(void __user *) arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		return rc;
+	}
+
+	if (cmd == AUDIO_ABORT_GET_EVENT) {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		MM_DBG("AUDIO_START\n");
+		rc = audio_enable(audio);
+		if (!rc) {
+			rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+			MM_INFO("dec_state %d rc = %d\n", audio->dec_state, rc);
+
+			if (audio->dec_state != MSM_AUD_DECODER_STATE_SUCCESS)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		break;
+	case AUDIO_STOP:
+		MM_DBG("AUDIO_STOP\n");
+		rc = audio_disable(audio);
+		audio->stopped = 1;
+		audio_ioport_reset(audio);
+		audio->stopped = 0;
+		break;
+	case AUDIO_FLUSH:
+		MM_DBG("AUDIO_FLUSH\n");
+		audio->rflush = 1;
+		audio->wflush = 1;
+		audio_ioport_reset(audio);
+		if (audio->running) {
+			audpp_flush(audio->dec_id);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		break;
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (copy_from_user(&config, (void *) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (config.channel_count == 1) {
+			config.channel_count = AUDPP_CMD_PCM_INTF_MONO_V;
+		} else if (config.channel_count == 2) {
+			config.channel_count = AUDPP_CMD_PCM_INTF_STEREO_V;
+		} else {
+			rc = -EINVAL;
+			break;
+		}
+		audio->mfield = config.meta_field;
+		audio->out_sample_rate = config.sample_rate;
+		audio->out_channel_mode = config.channel_count;
+		rc = 0;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_size = (audio->out_dma_sz >> 1);
+		config.buffer_count = 2;
+		config.sample_rate = audio->out_sample_rate;
+		if (audio->out_channel_mode == AUDPP_CMD_PCM_INTF_MONO_V)
+			config.channel_count = 1;
+		else
+			config.channel_count = 2;
+		config.meta_field = 0;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void *) arg, &config, sizeof(config)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+
+		break;
+	}
+	case AUDIO_GET_WMA_CONFIG:{
+			if (copy_to_user((void *)arg, &audio->wma_config,
+				sizeof(audio->wma_config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_SET_WMA_CONFIG:{
+		struct msm_audio_wma_config usr_config;
+
+		if (copy_from_user
+			(&usr_config, (void *)arg,
+			sizeof(usr_config))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		audio->wma_config = usr_config;
+		rc = 0;
+		break;
+	}
+	case AUDIO_GET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			config.pcm_feedback = audio->pcm_feedback;
+			config.buffer_count = PCM_BUF_MAX_COUNT;
+			config.buffer_size = PCM_BUFSZ_MIN;
+			if (copy_to_user((void *)arg, &config,
+					 sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_SET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			if (copy_from_user
+			    (&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+			if (config.pcm_feedback != audio->pcm_feedback) {
+				MM_ERR("Not sufficient permission to"
+					 "change the playback mode\n");
+				rc = -EACCES;
+				break;
+			}
+			if ((config.buffer_count > PCM_BUF_MAX_COUNT) ||
+			    (config.buffer_count == 1))
+				config.buffer_count = PCM_BUF_MAX_COUNT;
+
+			if (config.buffer_size < PCM_BUFSZ_MIN)
+				config.buffer_size = PCM_BUFSZ_MIN;
+
+			/* Check if pcm feedback is required */
+			if ((config.pcm_feedback) && (!audio->read_data)) {
+				MM_DBG("allocate PCM buffer %d\n",
+						config.buffer_count *
+						config.buffer_size);
+				audio->read_phys =
+						allocate_contiguous_ebi_nomap(
+							config.buffer_size *
+							config.buffer_count,
+							SZ_4K);
+				if (!audio->read_phys) {
+					rc = -ENOMEM;
+					break;
+				}
+				audio->map_v_read = ioremap(
+							audio->read_phys,
+							config.buffer_size *
+							config.buffer_count);
+				if (IS_ERR(audio->map_v_read)) {
+					MM_ERR("read buf alloc fail\n");
+					rc = -ENOMEM;
+					free_contiguous_memory_by_paddr(
+							audio->read_phys);
+				} else {
+					uint8_t index;
+					uint32_t offset = 0;
+					audio->read_data =
+						audio->map_v_read;
+					audio->buf_refresh = 0;
+					audio->pcm_buf_count =
+					    config.buffer_count;
+					audio->read_next = 0;
+					audio->fill_next = 0;
+
+					for (index = 0;
+					     index < config.buffer_count;
+					     index++) {
+						audio->in[index].data =
+						    audio->read_data + offset;
+						audio->in[index].addr =
+						    audio->read_phys + offset;
+						audio->in[index].size =
+						    config.buffer_size;
+						audio->in[index].used = 0;
+						offset += config.buffer_size;
+					}
+					MM_DBG("read buf: phy addr \
+						0x%08x kernel addr 0x%08x\n",
+						audio->read_phys,
+						(int)audio->read_data);
+					rc = 0;
+				}
+			} else {
+				rc = 0;
+			}
+			break;
+		}
+	case AUDIO_PAUSE:
+		MM_DBG("AUDIO_PAUSE %ld\n", arg);
+		rc = audpp_pause(audio->dec_id, (int) arg);
+		break;
+	case AUDIO_GET_SESSION_ID:
+		if (copy_to_user((void *) arg, &audio->dec_id,
+					sizeof(unsigned short)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+/* Only useful in tunnel-mode */
+static int audio_fsync(struct file *file, loff_t ppos1, loff_t ppos2, int datasync)
+{
+	struct audio *audio = file->private_data;
+	struct buffer *frame;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	if (!audio->running || audio->pcm_feedback) {
+		rc = -EINVAL;
+		goto done_nolock;
+	}
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(!audio->out[0].used &&
+		!audio->out[1].used &&
+		audio->out_needed) || audio->wflush);
+
+	if (rc < 0)
+		goto done;
+	else if (audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (audio->reserved) {
+		MM_DBG("send reserved byte\n");
+		frame = audio->out + audio->out_tail;
+		((char *) frame->data)[0] = audio->rsv_byte;
+		((char *) frame->data)[1] = 0;
+		frame->used = 2;
+		audplay_send_data(audio, 0);
+
+		rc = wait_event_interruptible(audio->write_wait,
+			(!audio->out[0].used &&
+			!audio->out[1].used &&
+			audio->out_needed) || audio->wflush);
+
+		if (rc < 0)
+			goto done;
+		else if (audio->wflush) {
+			rc = -EBUSY;
+			goto done;
+		}
+	}
+
+	/* pcm dmamiss message is sent continously
+	 * when decoder is starved so no race
+	 * condition concern
+	 */
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		audio->teos || audio->wflush);
+
+	if (audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+done_nolock:
+	return rc;
+}
+
+static ssize_t audio_read(struct file *file, char __user *buf, size_t count,
+			  loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	int rc = 0;
+
+	if (!audio->pcm_feedback)
+		return 0; /* PCM feedback is not enabled. Nothing to read */
+
+	mutex_lock(&audio->read_lock);
+	MM_DBG("%d \n", count);
+	while (count > 0) {
+		rc = wait_event_interruptible(audio->read_wait,
+			(audio->in[audio->read_next].used > 0) ||
+			(audio->stopped) || (audio->rflush));
+
+		if (rc < 0)
+			break;
+
+		if (audio->stopped || audio->rflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (count < audio->in[audio->read_next].used) {
+			/* Read must happen in frame boundary. Since driver
+			   does not know frame size, read count must be greater
+			   or equal to size of PCM samples */
+			MM_DBG("audio_read: no partial frame done reading\n");
+			break;
+		} else {
+			MM_DBG("audio_read: read from in[%d]\n",
+					audio->read_next);
+			if (copy_to_user
+			    (buf, audio->in[audio->read_next].data,
+			     audio->in[audio->read_next].used)) {
+				MM_ERR("invalid addr %x \n", (unsigned int)buf);
+				rc = -EFAULT;
+				break;
+			}
+			count -= audio->in[audio->read_next].used;
+			buf += audio->in[audio->read_next].used;
+			audio->in[audio->read_next].used = 0;
+			if ((++audio->read_next) == audio->pcm_buf_count)
+				audio->read_next = 0;
+			break;	/* Force to exit while loop
+				 * to prevent output thread
+				 * sleep too long if data is
+				 * not ready at this moment.
+				 */
+		}
+	}
+
+	/* don't feed output buffer to HW decoder during flushing
+	 * buffer refresh command will be sent once flush completes
+	 * send buf refresh command here can confuse HW decoder
+	 */
+	if (audio->buf_refresh && !audio->rflush) {
+		audio->buf_refresh = 0;
+		MM_DBG("kick start pcm feedback again\n");
+		audplay_buffer_refresh(audio);
+	}
+
+	mutex_unlock(&audio->read_lock);
+
+	if (buf > start)
+		rc = buf - start;
+
+	MM_DBG("read %d bytes\n", rc);
+	return rc;
+}
+
+static int audwma_process_eos(struct audio *audio,
+		const char __user *buf_start, unsigned short mfield_size)
+{
+	int rc = 0;
+	struct buffer *frame;
+	char *buf_ptr;
+
+	if (audio->reserved) {
+		MM_DBG("flush reserve byte\n");
+		frame = audio->out + audio->out_head;
+		buf_ptr = frame->data;
+		rc = wait_event_interruptible(audio->write_wait,
+				(frame->used == 0)
+				|| (audio->stopped)
+				|| (audio->wflush));
+		if (rc < 0)
+			goto done;
+		if (audio->stopped || audio->wflush) {
+			rc = -EBUSY;
+			goto done;
+		}
+
+		buf_ptr[0] = audio->rsv_byte;
+		buf_ptr[1] = 0;
+		audio->out_head ^= 1;
+		frame->mfield_sz = 0;
+		frame->used = 2;
+		audio->reserved = 0;
+		audplay_send_data(audio, 0);
+	}
+
+	frame = audio->out + audio->out_head;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->out_needed &&
+		audio->out[0].used == 0 &&
+		audio->out[1].used == 0)
+		|| (audio->stopped)
+		|| (audio->wflush));
+
+	if (rc < 0)
+		goto done;
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (copy_from_user(frame->data, buf_start, mfield_size)) {
+		rc = -EFAULT;
+		goto done;
+	}
+
+	frame->mfield_sz = mfield_size;
+	audio->out_head ^= 1;
+	frame->used = mfield_size;
+	audplay_send_data(audio, 0);
+done:
+	return rc;
+}
+
+static ssize_t audio_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	char *cpy_ptr;
+	int rc = 0, eos_condition = AUDWMA_EOS_NONE;
+	unsigned dsize;
+	unsigned short mfield_size = 0;
+
+	MM_DBG("cnt=%d\n", count);
+
+	mutex_lock(&audio->write_lock);
+	while (count > 0) {
+		frame = audio->out + audio->out_head;
+		cpy_ptr = frame->data;
+		dsize = 0;
+		rc = wait_event_interruptible(audio->write_wait,
+					      (frame->used == 0)
+					      || (audio->stopped)
+						  || (audio->wflush));
+		if (rc < 0)
+			break;
+		if (audio->stopped || audio->wflush) {
+			rc = -EBUSY;
+			break;
+		}
+		if (audio->mfield) {
+			if (buf == start) {
+				/* Processing beginning of user buffer */
+				if (__get_user(mfield_size,
+					(unsigned short __user *) buf)) {
+					rc = -EFAULT;
+					break;
+				} else  if (mfield_size > count) {
+					rc = -EINVAL;
+					break;
+				}
+				MM_DBG("audio_write: mf offset_val %x\n",
+						mfield_size);
+				if (copy_from_user(cpy_ptr, buf, mfield_size)) {
+					rc = -EFAULT;
+					break;
+				}
+				/* Check if EOS flag is set and buffer has
+				 * contains just meta field
+				 */
+				if (cpy_ptr[AUDWMA_EOS_FLG_OFFSET] &
+						 AUDWMA_EOS_FLG_MASK) {
+					MM_DBG("audio_write: EOS SET\n");
+					eos_condition = AUDWMA_EOS_SET;
+					if (mfield_size == count) {
+						buf += mfield_size;
+						break;
+					} else
+						cpy_ptr[AUDWMA_EOS_FLG_OFFSET]
+							&= ~AUDWMA_EOS_FLG_MASK;
+				}
+				cpy_ptr += mfield_size;
+				count -= mfield_size;
+				dsize += mfield_size;
+				buf += mfield_size;
+			} else {
+				mfield_size = 0;
+				MM_DBG("audio_write: continuous buffer\n");
+			}
+			frame->mfield_sz = mfield_size;
+		}
+
+		if (audio->reserved) {
+			MM_DBG("append reserved byte %x\n", audio->rsv_byte);
+			*cpy_ptr = audio->rsv_byte;
+			xfer = (count > ((frame->size - mfield_size) - 1)) ?
+				(frame->size - mfield_size) - 1 : count;
+			cpy_ptr++;
+			dsize += 1;
+			audio->reserved = 0;
+		} else
+			xfer = (count > (frame->size - mfield_size)) ?
+				(frame->size - mfield_size) : count;
+
+		if (copy_from_user(cpy_ptr, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+
+		dsize += xfer;
+		if (dsize & 1) {
+			audio->rsv_byte = ((char *) frame->data)[dsize - 1];
+			MM_DBG("odd length buf reserve last byte %x\n",
+					audio->rsv_byte);
+			audio->reserved = 1;
+			dsize--;
+		}
+		count -= xfer;
+		buf += xfer;
+
+		if (dsize > 0) {
+			audio->out_head ^= 1;
+			frame->used = dsize;
+			audplay_send_data(audio, 0);
+		}
+	}
+	if (eos_condition == AUDWMA_EOS_SET)
+		rc = audwma_process_eos(audio, start, mfield_size);
+	mutex_unlock(&audio->write_lock);
+	if (!rc) {
+		if (buf > start)
+			return buf - start;
+	}
+	return rc;
+}
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	MM_INFO("audio instance 0x%08x freeing\n", (int)audio);
+	mutex_lock(&audio->lock);
+	auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->dec_id);
+	audio_disable(audio);
+	audio_flush(audio);
+	audio_flush_pcm_buf(audio);
+	msm_adsp_put(audio->audplay);
+	audpp_adec_free(audio->dec_id);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&audio->suspend_ctl.node);
+#endif
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audwma_reset_event_queue(audio);
+	iounmap(audio->map_v_write);
+	free_contiguous_memory_by_paddr(audio->phys);
+	if (audio->read_data) {
+		iounmap(audio->map_v_read);
+		free_contiguous_memory_by_paddr(audio->read_phys);
+	}
+	mutex_unlock(&audio->lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio);
+	return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audwma_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload)
+{
+	struct audwma_event *e_node = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+				struct audwma_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audwma_event), GFP_ATOMIC);
+		if (!e_node) {
+			MM_ERR("No mem to post event %d\n", type);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	wake_up(&audio->event_wait);
+}
+
+static void audwma_suspend(struct early_suspend *h)
+{
+	struct audwma_suspend_ctl *ctl =
+		container_of(h, struct audwma_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audwma_post_event(ctl->audio, AUDIO_EVENT_SUSPEND, payload);
+}
+
+static void audwma_resume(struct early_suspend *h)
+{
+	struct audwma_suspend_ctl *ctl =
+		container_of(h, struct audwma_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audwma_post_event(ctl->audio, AUDIO_EVENT_RESUME, payload);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audwma_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audwma_debug_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 4096;
+	static char buffer[4096];
+	int n = 0, i;
+	struct audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "enabled %d\n", audio->enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "pcm_feedback %d\n", audio->pcm_feedback);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_buf_sz %d\n", audio->out[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "pcm_buf_count %d \n", audio->pcm_buf_count);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "pcm_buf_sz %d \n", audio->in[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "volume %x \n", audio->vol_pan.volume);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "sample rate %d \n", audio->out_sample_rate);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		"channel mode %d \n", audio->out_channel_mode);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "rflush %d\n", audio->rflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "running %d \n", audio->running);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"dec state %d \n", audio->dec_state);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_needed %d \n", audio->out_needed);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_head %d \n", audio->out_head);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_tail %d \n", audio->out_tail);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out[0].used %d \n", audio->out[0].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out[1].used %d \n", audio->out[1].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "buffer_refresh %d \n", audio->buf_refresh);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "read_next %d \n", audio->read_next);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "fill_next %d \n", audio->fill_next);
+	for (i = 0; i < audio->pcm_buf_count; i++)
+		n += scnprintf(buffer + n, debug_bufmax - n,
+			"in[%d].size %d \n", i, audio->in[i].used);
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audwma_debug_fops = {
+	.read = audwma_debug_read,
+	.open = audwma_debug_open,
+};
+#endif
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = NULL;
+	int rc, dec_attrb, decid, i;
+	unsigned pmem_sz = DMASZ_MAX;
+	struct audwma_event *e_node = NULL;
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_wma_" + 5];
+#endif
+
+	/* Allocate Mem for audio instance */
+	audio = kzalloc(sizeof(struct audio), GFP_KERNEL);
+	if (!audio) {
+		MM_ERR("no memory to allocate audio instance \n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	MM_INFO("audio instance 0x%08x created\n", (int)audio);
+
+	/* Allocate the decoder */
+	dec_attrb = AUDDEC_DEC_WMA;
+	if ((file->f_mode & FMODE_WRITE) &&
+			(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_NONTUNNEL;
+		audio->pcm_feedback = NON_TUNNEL_MODE_PLAYBACK;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_TUNNEL;
+		audio->pcm_feedback = TUNNEL_MODE_PLAYBACK;
+	} else {
+		kfree(audio);
+		rc = -EACCES;
+		goto done;
+	}
+
+	decid = audpp_adec_alloc(dec_attrb, &audio->module_name,
+			&audio->queue_id);
+
+	if (decid < 0) {
+		MM_ERR("No free decoder available, freeing instance 0x%08x\n",
+				(int)audio);
+		rc = -ENODEV;
+		kfree(audio);
+		goto done;
+	}
+	audio->dec_id = decid & MSM_AUD_DECODER_MASK;
+
+	while (pmem_sz >= DMASZ_MIN) {
+		MM_DBG("pmemsz = %d\n", pmem_sz);
+		audio->phys = allocate_contiguous_ebi_nomap(pmem_sz, SZ_4K);
+		if (audio->phys) {
+			audio->map_v_write = ioremap(audio->phys, pmem_sz);
+			if (IS_ERR(audio->map_v_write)) {
+				MM_ERR("could not allocate write buffers, \
+						freeing instance 0x%08x\n",
+						(int)audio);
+				rc = -ENOMEM;
+				free_contiguous_memory_by_paddr(audio->phys);
+				audpp_adec_free(audio->dec_id);
+				kfree(audio);
+				goto done;
+			}
+			audio->data = audio->map_v_write;
+			MM_DBG("write buf: phy addr 0x%08x kernel addr \
+				0x%08x\n", audio->phys, (int)audio->data);
+			break;
+		} else if (pmem_sz == DMASZ_MIN) {
+			MM_ERR("could not allocate write buffers, freeing \
+					instance 0x%08x\n", (int)audio);
+			rc = -ENOMEM;
+			audpp_adec_free(audio->dec_id);
+			kfree(audio);
+			goto done;
+		} else
+		pmem_sz >>= 1;
+	}
+	audio->out_dma_sz = pmem_sz;
+
+	rc = msm_adsp_get(audio->module_name, &audio->audplay,
+			&audplay_adsp_ops_wma, audio);
+	if (rc) {
+		MM_ERR("failed to get %s module, freeing instance 0x%08x\n",
+				audio->module_name, (int)audio);
+		goto err;
+	}
+
+	mutex_init(&audio->lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->get_event_lock);
+	spin_lock_init(&audio->dsp_lock);
+	init_waitqueue_head(&audio->write_wait);
+	init_waitqueue_head(&audio->read_wait);
+	INIT_LIST_HEAD(&audio->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+	init_waitqueue_head(&audio->wait);
+	init_waitqueue_head(&audio->event_wait);
+	spin_lock_init(&audio->event_queue_lock);
+	init_waitqueue_head(&audio->avsync_wait);
+
+	audio->out[0].data = audio->data + 0;
+	audio->out[0].addr = audio->phys + 0;
+	audio->out[0].size = audio->out_dma_sz >> 1;
+
+	audio->out[1].data = audio->data + audio->out[0].size;
+	audio->out[1].addr = audio->phys + audio->out[0].size;
+	audio->out[1].size = audio->out[0].size;
+
+	audio->wma_config.armdatareqthr =  1262;
+	audio->wma_config.channelsdecoded = 2;
+	audio->wma_config.wmabytespersec = 6003;
+	audio->wma_config.wmasamplingfreq = 44100;
+	audio->wma_config.wmaencoderopts = 31;
+
+	audio->out_sample_rate = 44100;
+	audio->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V;
+
+	audio->vol_pan.volume = 0x2000;
+
+	audio_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+
+	audio->device_events = AUDDEV_EVT_DEV_RDY
+				|AUDDEV_EVT_DEV_RLS|
+				AUDDEV_EVT_STREAM_VOL_CHG;
+
+	rc = auddev_register_evt_listner(audio->device_events,
+					AUDDEV_CLNT_DEC,
+					audio->dec_id,
+					wma_listner,
+					(void *)audio);
+	if (rc) {
+		MM_ERR("%s: failed to register listner\n", __func__);
+		goto event_err;
+	}
+
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_wma_%04x", audio->dec_id);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+				NULL, (void *) audio,
+				&audwma_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		MM_DBG("debugfs_create_file failed\n");
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	audio->suspend_ctl.node.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+	audio->suspend_ctl.node.resume = audwma_resume;
+	audio->suspend_ctl.node.suspend = audwma_suspend;
+	audio->suspend_ctl.audio = audio;
+	register_early_suspend(&audio->suspend_ctl.node);
+#endif
+	for (i = 0; i < AUDWMA_EVENT_NUM; i++) {
+		e_node = kmalloc(sizeof(struct audwma_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			MM_ERR("event pkt alloc failed\n");
+			break;
+		}
+	}
+done:
+	return rc;
+event_err:
+	msm_adsp_put(audio->audplay);
+err:
+	iounmap(audio->map_v_write);
+	free_contiguous_memory_by_paddr(audio->phys);
+	audpp_adec_free(audio->dec_id);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_wma_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audio_open,
+	.release	= audio_release,
+	.read 		= audio_read,
+	.write		= audio_write,
+	.unlocked_ioctl	= audio_ioctl,
+	.fsync 		= audio_fsync,
+};
+
+struct miscdevice audio_wma_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_wma",
+	.fops	= &audio_wma_fops,
+};
+
+static int __init audio_init(void)
+{
+	return misc_register(&audio_wma_misc);
+}
+
+device_initcall(audio_init);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_wmapro.c b/arch/arm/mach-msm/qdsp5v2/audio_wmapro.c
new file mode 100644
index 0000000..ca072b3
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/audio_wmapro.c
@@ -0,0 +1,1815 @@
+/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+ *
+ * Based on the mp3 native driver in arch/arm/mach-msm/qdsp5v2/audio_mp3.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/earlysuspend.h>
+#include <linux/android_pmem.h>
+#include <linux/msm_audio.h>
+#include <linux/slab.h>
+#include <linux/msm_audio_wmapro.h>
+#include <linux/memory_alloc.h>
+
+#include <mach/msm_adsp.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/qdsp5v2/qdsp5audppmsg.h>
+#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
+#include <mach/qdsp5v2/qdsp5audplaymsg.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/qdsp5v2/audpp.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_memtypes.h>
+
+
+/* Size must be power of 2 */
+#define BUFSZ_MAX 	4110	/* Includes meta in size */
+#define BUFSZ_MIN 	2062	/* Includes meta in size */
+#define DMASZ_MAX 	(BUFSZ_MAX * 2)
+#define DMASZ_MIN 	(BUFSZ_MIN * 2)
+
+#define AUDPLAY_INVALID_READ_PTR_OFFSET	0xFFFF
+#define AUDDEC_DEC_WMAPRO 13
+
+#define PCM_BUFSZ_MIN 	8216 	/* Hold one stereo WMAPRO frame and meta out*/
+#define PCM_BUF_MAX_COUNT 5	/* DSP only accepts 5 buffers at most
+				   but support 2 buffers currently */
+#define ROUTING_MODE_FTRT 1
+#define ROUTING_MODE_RT 2
+/* Decoder status received from AUDPPTASK */
+#define  AUDPP_DEC_STATUS_SLEEP	0
+#define	 AUDPP_DEC_STATUS_INIT  1
+#define  AUDPP_DEC_STATUS_CFG   2
+#define  AUDPP_DEC_STATUS_PLAY  3
+
+#define AUDWMAPRO_METAFIELD_MASK 0xFFFF0000
+#define AUDWMAPRO_EOS_FLG_OFFSET 0x0A /* Offset from beginning of buffer */
+#define AUDWMAPRO_EOS_FLG_MASK 0x01
+#define AUDWMAPRO_EOS_NONE 0x0 /* No EOS detected */
+#define AUDWMAPRO_EOS_SET 0x1 /* EOS set in meta field */
+
+#define AUDWMAPRO_EVENT_NUM 10 /* Default no. of pre-allocated event packets */
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+	unsigned short mfield_sz; /*only useful for data has meta field */
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct audwmapro_suspend_ctl {
+	struct early_suspend node;
+	struct audio *audio;
+};
+#endif
+
+struct audwmapro_event{
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+
+struct audio {
+	struct buffer out[2];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed; /* number of buffers the dsp is waiting for */
+	unsigned out_dma_sz;
+
+	atomic_t out_bytes;
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	/* Host PCM section */
+	struct buffer in[PCM_BUF_MAX_COUNT];
+	struct mutex read_lock;
+	wait_queue_head_t read_wait;	/* Wait queue for read */
+	char *read_data;	/* pointer to reader buffer */
+	int32_t read_phys;	/* physical address of reader buffer */
+	uint8_t read_next;	/* index to input buffers to be read next */
+	uint8_t fill_next;	/* index to buffer that DSP should be filling */
+	uint8_t pcm_buf_count;	/* number of pcm buffer allocated */
+	/* ---- End of Host PCM section */
+
+	struct msm_adsp_module *audplay;
+
+	/* configuration to use on next enable */
+	uint32_t out_sample_rate;
+	uint32_t out_channel_mode;
+
+	struct msm_audio_wmapro_config wmapro_config;
+
+	/* data allocated for various buffers */
+	char *data;
+	int32_t phys; /* physical address of write buffer */
+	void *map_v_read;
+	void *map_v_write;
+
+	int mfield; /* meta field embedded in data */
+	int rflush; /* Read  flush */
+	int wflush; /* Write flush */
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+	int pcm_feedback;
+	int buf_refresh;
+	int teos; /* valid only if tunnel mode & no data left for decoder */
+	enum msm_aud_decoder_state dec_state;	/* Represents decoder state */
+	int reserved; /* A byte is being reserved */
+	char rsv_byte; /* Handle odd length user data */
+
+	const char *module_name;
+	unsigned queue_id;
+	uint16_t dec_id;
+	uint32_t read_ptr_offset;
+	int16_t source;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct audwmapro_suspend_ctl suspend_ctl;
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+
+	wait_queue_head_t wait;
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	wait_queue_head_t event_wait;
+	spinlock_t event_queue_lock;
+	struct mutex get_event_lock;
+	int event_abort;
+	/* AV sync Info */
+	int avsync_flag;              /* Flag to indicate feedback from DSP */
+	wait_queue_head_t avsync_wait;/* Wait queue for AV Sync Message     */
+	/* flags, 48 bits sample/bytes counter per channel */
+	uint16_t avsync[AUDPP_AVSYNC_CH_COUNT * AUDPP_AVSYNC_NUM_WORDS + 1];
+
+	uint32_t device_events;
+
+	int eq_enable;
+	int eq_needs_commit;
+	struct audpp_cmd_cfg_object_params_eqalizer eq;
+	struct audpp_cmd_cfg_object_params_volume vol_pan;
+};
+
+static int auddec_dsp_config(struct audio *audio, int enable);
+static void audpp_cmd_cfg_adec_params(struct audio *audio);
+static void audpp_cmd_cfg_routing_mode(struct audio *audio);
+static void audplay_send_data(struct audio *audio, unsigned needed);
+static void audplay_config_hostpcm(struct audio *audio);
+static void audplay_buffer_refresh(struct audio *audio);
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audwmapro_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload);
+#endif
+
+/* must be called with audio->lock held */
+static int audio_enable(struct audio *audio)
+{
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled)
+		return 0;
+
+	audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	if (msm_adsp_enable(audio->audplay)) {
+		MM_ERR("msm_adsp_enable(audplay) failed\n");
+		return -ENODEV;
+	}
+
+	if (audpp_enable(audio->dec_id, audio_dsp_event, audio)) {
+		MM_ERR("audpp_enable() failed\n");
+		msm_adsp_disable(audio->audplay);
+		return -ENODEV;
+	}
+
+	audio->enabled = 1;
+	return 0;
+}
+
+static void wmapro_listner(u32 evt_id, union auddev_evt_data *evt_payload,
+			void *private_data)
+{
+	struct audio *audio = (struct audio *) private_data;
+	switch (evt_id) {
+	case AUDDEV_EVT_DEV_RDY:
+		MM_DBG(":AUDDEV_EVT_DEV_RDY\n");
+		audio->source |= (0x1 << evt_payload->routing_id);
+		if (audio->running == 1 && audio->enabled == 1)
+			audpp_route_stream(audio->dec_id, audio->source);
+		break;
+	case AUDDEV_EVT_DEV_RLS:
+		MM_DBG(":AUDDEV_EVT_DEV_RLS\n");
+		audio->source &= ~(0x1 << evt_payload->routing_id);
+		if (audio->running == 1 && audio->enabled == 1)
+			audpp_route_stream(audio->dec_id, audio->source);
+		break;
+	case AUDDEV_EVT_STREAM_VOL_CHG:
+		audio->vol_pan.volume = evt_payload->session_vol;
+		MM_DBG(":AUDDEV_EVT_STREAM_VOL_CHG, stream vol %d\n",
+				audio->vol_pan.volume);
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+		break;
+	default:
+		MM_ERR(":ERROR:wrong event\n");
+		break;
+	}
+}
+
+/* must be called with audio->lock held */
+static int audio_disable(struct audio *audio)
+{
+	int rc = 0;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+		auddec_dsp_config(audio, 0);
+		rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+		else if (audio->dec_state != MSM_AUD_DECODER_STATE_CLOSE)
+			rc = -EFAULT;
+		else
+			rc = 0;
+		wake_up(&audio->write_wait);
+		wake_up(&audio->read_wait);
+		msm_adsp_disable(audio->audplay);
+		audpp_disable(audio->dec_id, audio);
+		audio->out_needed = 0;
+	}
+	return rc;
+}
+
+/* ------------------- dsp --------------------- */
+static void audio_update_pcm_buf_entry(struct audio *audio,
+	uint32_t *payload)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	if (audio->rflush)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < payload[1]; index++) {
+		if (audio->in[audio->fill_next].addr ==
+			payload[2 + index * 2]) {
+			MM_DBG("audio_update_pcm_buf_entry: \
+				in[%d] ready\n", audio->fill_next);
+			audio->in[audio->fill_next].used =
+			payload[3 + index * 2];
+			if ((++audio->fill_next) == audio->pcm_buf_count)
+				audio->fill_next = 0;
+		} else {
+			MM_ERR("audio_update_pcm_buf_entry: \
+				expected=%x ret=%x\n",
+				audio->in[audio->fill_next].addr,
+				payload[1 + index * 2]);
+			break;
+		}
+	}
+	if (audio->in[audio->fill_next].used == 0) {
+		audplay_buffer_refresh(audio);
+	} else {
+		MM_DBG("read cannot keep up\n");
+		audio->buf_refresh = 1;
+	}
+	wake_up(&audio->read_wait);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static void audplay_dsp_event(void *data, unsigned id, size_t len,
+			      void (*getevent) (void *ptr, size_t len))
+{
+	struct audio *audio = data;
+	uint32_t msg[28];
+
+	getevent(msg, sizeof(msg));
+
+	MM_DBG("msg_id=%x\n", id);
+
+	switch (id) {
+	case AUDPLAY_MSG_DEC_NEEDS_DATA:
+		audplay_send_data(audio, 1);
+		break;
+
+	case AUDPLAY_MSG_BUFFER_UPDATE:
+		audio_update_pcm_buf_entry(audio, msg);
+		break;
+
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audplaytask)\n");
+		break;
+
+	default:
+		MM_ERR("unexpected message from decoder \n");
+		break;
+	}
+}
+
+static void audio_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned status = msg[1];
+
+			switch (status) {
+			case AUDPP_DEC_STATUS_SLEEP: {
+				uint16_t reason = msg[2];
+				MM_DBG("decoder status:sleep reason = \
+						0x%04x\n", reason);
+				if ((reason == AUDPP_MSG_REASON_MEM)
+					|| (reason ==
+					AUDPP_MSG_REASON_NODECODER)) {
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_FAILURE;
+					wake_up(&audio->wait);
+				} else if (reason == AUDPP_MSG_REASON_NONE) {
+					/* decoder is in disable state */
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_CLOSE;
+					wake_up(&audio->wait);
+				}
+				break;
+			}
+			case AUDPP_DEC_STATUS_INIT:
+				MM_DBG("decoder status: init\n");
+				if (audio->pcm_feedback)
+					audpp_cmd_cfg_routing_mode(audio);
+				else
+					audpp_cmd_cfg_adec_params(audio);
+				break;
+
+			case AUDPP_DEC_STATUS_CFG:
+				MM_DBG("decoder status: cfg\n");
+				break;
+			case AUDPP_DEC_STATUS_PLAY:
+				MM_DBG("decoder status: play \n");
+				audpp_route_stream(audio->dec_id,
+						audio->source);
+				if (audio->pcm_feedback) {
+					audplay_config_hostpcm(audio);
+					audplay_buffer_refresh(audio);
+				}
+				audio->dec_state =
+					MSM_AUD_DECODER_STATE_SUCCESS;
+				wake_up(&audio->wait);
+				break;
+			default:
+				MM_ERR("unknown decoder status\n");
+			}
+			break;
+		}
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			MM_DBG("CFG_MSG ENABLE\n");
+			auddec_dsp_config(audio, 1);
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+			audpp_dsp_set_eq(audio->dec_id, audio->eq_enable,
+					&audio->eq, POPP);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			MM_DBG("CFG_MSG DISABLE\n");
+			audio->running = 0;
+		} else {
+			MM_DBG("CFG_MSG %d?\n", msg[0]);
+		}
+		break;
+	case AUDPP_MSG_ROUTING_ACK:
+		MM_DBG("ROUTING_ACK mode=%d\n", msg[1]);
+		audpp_cmd_cfg_adec_params(audio);
+		break;
+
+	case AUDPP_MSG_FLUSH_ACK:
+		MM_DBG("FLUSH_ACK\n");
+		audio->wflush = 0;
+		audio->rflush = 0;
+		wake_up(&audio->write_wait);
+		if (audio->pcm_feedback)
+			audplay_buffer_refresh(audio);
+		break;
+
+	case AUDPP_MSG_PCMDMAMISSED:
+		MM_DBG("PCMDMAMISSED\n");
+		audio->teos = 1;
+		wake_up(&audio->write_wait);
+		break;
+
+	case AUDPP_MSG_AVSYNC_MSG:
+		MM_DBG("AUDPP_MSG_AVSYNC_MSG\n");
+		memcpy(&audio->avsync[0], msg, sizeof(audio->avsync));
+		audio->avsync_flag = 1;
+		wake_up(&audio->avsync_wait);
+		break;
+
+	default:
+		MM_ERR("UNKNOWN (%d)\n", id);
+	}
+
+}
+
+static struct msm_adsp_ops audplay_adsp_ops_wmapro = {
+	.event = audplay_dsp_event,
+};
+
+#define audplay_send_queue0(audio, cmd, len) \
+	msm_adsp_write(audio->audplay, audio->queue_id, \
+			cmd, len)
+
+static int auddec_dsp_config(struct audio *audio, int enable)
+{
+	struct audpp_cmd_cfg_dec_type cfg_dec_cmd;
+
+	memset(&cfg_dec_cmd, 0, sizeof(cfg_dec_cmd));
+
+	cfg_dec_cmd.cmd_id = AUDPP_CMD_CFG_DEC_TYPE;
+	if (enable)
+		cfg_dec_cmd.dec_cfg = AUDPP_CMD_UPDATDE_CFG_DEC |
+				AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_WMAPRO;
+	else
+		cfg_dec_cmd.dec_cfg = AUDPP_CMD_UPDATDE_CFG_DEC |
+				AUDPP_CMD_DIS_DEC_V;
+	cfg_dec_cmd.dm_mode = 0x0;
+	cfg_dec_cmd.stream_id = audio->dec_id;
+	return audpp_send_queue1(&cfg_dec_cmd, sizeof(cfg_dec_cmd));
+}
+
+static void audpp_cmd_cfg_adec_params(struct audio *audio)
+{
+	struct audpp_cmd_cfg_adec_params_wmapro cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_WMAPRO_LEN;
+	cmd.common.dec_id = audio->dec_id;
+	cmd.common.input_sampling_frequency = audio->out_sample_rate;
+
+	/*
+	 * Test done for sample with the following configuration
+	 * armdatareqthr 	= 1262
+	 * channelsdecoded 	= 1(MONO)/2(STEREO)
+	 * wmaprobytespersec 	= Tested with 6003 Bytes per sec
+	 * wmaprosamplingfreq	= 44100
+	 * wmaproencoderopts	= 31
+	 */
+
+	cmd.armdatareqthr = audio->wmapro_config.armdatareqthr;
+	cmd.numchannels = audio->wmapro_config.numchannels;
+	cmd.validbitspersample = audio->wmapro_config.validbitspersample;
+	cmd.formattag = audio->wmapro_config.formattag;
+	cmd.samplingrate = audio->wmapro_config.samplingrate;
+	cmd.avgbytespersecond = audio->wmapro_config.avgbytespersecond;
+	cmd.asfpacketlength = audio->wmapro_config.asfpacketlength;
+	cmd.channelmask = audio->wmapro_config.channelmask;
+	cmd.encodeopt = audio->wmapro_config.encodeopt;
+	cmd.advancedencodeopt = audio->wmapro_config.advancedencodeopt;
+	cmd.advancedencodeopt2 = audio->wmapro_config.advancedencodeopt2;
+
+	audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static void audpp_cmd_cfg_routing_mode(struct audio *audio)
+{
+	struct audpp_cmd_routing_mode cmd;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_ROUTING_MODE;
+	cmd.object_number = audio->dec_id;
+	if (audio->pcm_feedback)
+		cmd.routing_mode = ROUTING_MODE_FTRT;
+	else
+		cmd.routing_mode = ROUTING_MODE_RT;
+
+	audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static void audplay_buffer_refresh(struct audio *audio)
+{
+	struct audplay_cmd_buffer_refresh refresh_cmd;
+
+	refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH;
+	refresh_cmd.num_buffers = 1;
+	refresh_cmd.buf0_address = audio->in[audio->fill_next].addr;
+	refresh_cmd.buf0_length = audio->in[audio->fill_next].size;
+	refresh_cmd.buf_read_count = 0;
+
+	MM_DBG("buf0_addr=%x buf0_len=%d\n",
+			refresh_cmd.buf0_address,
+			refresh_cmd.buf0_length);
+
+	(void)audplay_send_queue0(audio, &refresh_cmd, sizeof(refresh_cmd));
+}
+
+static void audplay_config_hostpcm(struct audio *audio)
+{
+	struct audplay_cmd_hpcm_buf_cfg cfg_cmd;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	cfg_cmd.cmd_id = AUDPLAY_CMD_HPCM_BUF_CFG;
+	cfg_cmd.max_buffers = audio->pcm_buf_count;
+	cfg_cmd.byte_swap = 0;
+	cfg_cmd.hostpcm_config = (0x8000) | (0x4000);
+	cfg_cmd.feedback_frequency = 1;
+	cfg_cmd.partition_number = 0;
+
+	(void)audplay_send_queue0(audio, &cfg_cmd, sizeof(cfg_cmd));
+}
+
+
+static int audplay_dsp_send_data_avail(struct audio *audio,
+					unsigned idx, unsigned len)
+{
+	struct audplay_cmd_bitstream_data_avail_nt2 cmd;
+
+	cmd.cmd_id		= AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_NT2;
+	if (audio->mfield)
+		cmd.decoder_id = AUDWMAPRO_METAFIELD_MASK |
+			(audio->out[idx].mfield_sz >> 1);
+	else
+		cmd.decoder_id		= audio->dec_id;
+	cmd.buf_ptr		= audio->out[idx].addr;
+	cmd.buf_size		= len/2;
+	cmd.partition_number	= 0;
+	return audplay_send_queue0(audio, &cmd, sizeof(cmd));
+}
+
+static void audplay_send_data(struct audio *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (audio->wflush) {
+		audio->out_needed = 1;
+		goto done;
+	}
+
+	if (needed && !audio->wflush) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			MM_DBG("frame %d free\n", audio->out_tail);
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		MM_DBG("\n"); /* Macro prints the file name and function */
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+			MM_DBG("frame %d busy\n", audio->out_tail);
+			audplay_dsp_send_data_avail(audio, audio->out_tail,
+								frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+
+static void audio_flush(struct audio *audio)
+{
+	audio->out[0].used = 0;
+	audio->out[1].used = 0;
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->reserved = 0;
+	atomic_set(&audio->out_bytes, 0);
+}
+
+static void audio_flush_pcm_buf(struct audio *audio)
+{
+	uint8_t index;
+
+	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
+		audio->in[index].used = 0;
+	audio->buf_refresh = 0;
+	audio->read_next = 0;
+	audio->fill_next = 0;
+}
+
+static void audio_ioport_reset(struct audio *audio)
+{
+	/* Make sure read/write thread are free from
+	 * sleep and knowing that system is not able
+	 * to process io request at the moment
+	 */
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audio_flush(audio);
+	mutex_unlock(&audio->write_lock);
+	wake_up(&audio->read_wait);
+	mutex_lock(&audio->read_lock);
+	audio_flush_pcm_buf(audio);
+	mutex_unlock(&audio->read_lock);
+	audio->avsync_flag = 1;
+	wake_up(&audio->avsync_wait);
+}
+
+static int audwmapro_events_pending(struct audio *audio)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	return empty || audio->event_abort;
+}
+
+static void audwmapro_reset_event_queue(struct audio *audio)
+{
+	unsigned long flags;
+	struct audwmapro_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audwmapro_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+				struct audwmapro_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	return;
+}
+
+static long audwmapro_process_event_req(struct audio *audio, void __user *arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audwmapro_event *drv_evt = NULL;
+	int timeout;
+	unsigned long flags;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int) usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(audio->event_wait,
+				audwmapro_events_pending(audio),
+				msecs_to_jiffies(timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(
+			audio->event_wait, audwmapro_events_pending(audio));
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	rc = 0;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audwmapro_event, list);
+		list_del(&drv_evt->list);
+	}
+
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else
+		rc = -1;
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	if (!rc && copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audio_enable_eq(struct audio *audio, int enable)
+{
+	if (audio->eq_enable == enable && !audio->eq_needs_commit)
+		return 0;
+
+	audio->eq_enable = enable;
+
+	if (audio->running) {
+		audpp_dsp_set_eq(audio->dec_id, enable, &audio->eq, POPP);
+		audio->eq_needs_commit = 0;
+	}
+	return 0;
+}
+
+static int audio_get_avsync_data(struct audio *audio,
+						struct msm_audio_stats *stats)
+{
+	int rc = -EINVAL;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (audio->dec_id == audio->avsync[0] && audio->avsync_flag) {
+		/* av_sync sample count */
+		stats->sample_count = (audio->avsync[2] << 16) |
+						(audio->avsync[3]);
+
+		/* av_sync byte_count */
+		stats->byte_count = (audio->avsync[5] << 16) |
+						(audio->avsync[6]);
+
+		audio->avsync_flag = 0;
+		rc = 0;
+	}
+	local_irq_restore(flags);
+	return rc;
+
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = -EINVAL;
+	unsigned long flags = 0;
+	uint16_t enable_mask;
+	int enable;
+	int prev_state;
+
+	MM_DBG("cmd = %d\n", cmd);
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+
+		audio->avsync_flag = 0;
+		memset(&stats, 0, sizeof(stats));
+		if (audpp_query_avsync(audio->dec_id) < 0)
+			return rc;
+
+		rc = wait_event_interruptible_timeout(audio->avsync_wait,
+				(audio->avsync_flag == 1),
+				msecs_to_jiffies(AUDPP_AVSYNC_EVENT_TIMEOUT));
+
+		if (rc < 0)
+			return rc;
+		else if ((rc > 0) || ((rc == 0) && (audio->avsync_flag == 1))) {
+			if (audio_get_avsync_data(audio, &stats) < 0)
+				return rc;
+
+			if (copy_to_user((void *)arg, &stats, sizeof(stats)))
+				return -EFAULT;
+			return 0;
+		} else
+			return -EAGAIN;
+	}
+
+	switch (cmd) {
+	case AUDIO_ENABLE_AUDPP:
+		if (copy_from_user(&enable_mask, (void *) arg,
+						sizeof(enable_mask))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		enable = (enable_mask & EQ_ENABLE) ? 1 : 0;
+		audio_enable_eq(audio, enable);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+	case AUDIO_SET_VOLUME:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.volume = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_PAN:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.pan = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan,
+					POPP);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_EQ:
+		prev_state = audio->eq_enable;
+		audio->eq_enable = 0;
+		if (copy_from_user(&audio->eq.num_bands, (void *) arg,
+				sizeof(audio->eq) -
+				(AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2))) {
+			rc = -EFAULT;
+			break;
+		}
+		audio->eq_enable = prev_state;
+		audio->eq_needs_commit = 1;
+		rc = 0;
+		break;
+	}
+
+	if (-EINVAL != rc)
+		return rc;
+
+	if (cmd == AUDIO_GET_EVENT) {
+		MM_DBG("AUDIO_GET_EVENT\n");
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audwmapro_process_event_req(audio,
+					(void __user *) arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		return rc;
+	}
+
+	if (cmd == AUDIO_ABORT_GET_EVENT) {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		MM_DBG("AUDIO_START\n");
+		rc = audio_enable(audio);
+		if (!rc) {
+			rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+			MM_INFO("dec_state %d rc = %d\n", audio->dec_state, rc);
+
+			if (audio->dec_state != MSM_AUD_DECODER_STATE_SUCCESS)
+				rc = -ENODEV;
+			else
+				rc = 0;
+		}
+		break;
+	case AUDIO_STOP:
+		MM_DBG("AUDIO_STOP\n");
+		rc = audio_disable(audio);
+		audio->stopped = 1;
+		audio_ioport_reset(audio);
+		audio->stopped = 0;
+		break;
+	case AUDIO_FLUSH:
+		MM_DBG("AUDIO_FLUSH\n");
+		audio->rflush = 1;
+		audio->wflush = 1;
+		audio_ioport_reset(audio);
+		if (audio->running) {
+			audpp_flush(audio->dec_id);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		break;
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (copy_from_user(&config, (void *) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (config.channel_count == 1) {
+			config.channel_count = AUDPP_CMD_PCM_INTF_MONO_V;
+		} else if (config.channel_count == 2) {
+			config.channel_count = AUDPP_CMD_PCM_INTF_STEREO_V;
+		} else {
+			rc = -EINVAL;
+			break;
+		}
+		audio->mfield = config.meta_field;
+		audio->out_sample_rate = config.sample_rate;
+		audio->out_channel_mode = config.channel_count;
+		rc = 0;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_size = (audio->out_dma_sz >> 1);
+		config.buffer_count = 2;
+		config.sample_rate = audio->out_sample_rate;
+		if (audio->out_channel_mode == AUDPP_CMD_PCM_INTF_MONO_V)
+			config.channel_count = 1;
+		else
+			config.channel_count = 2;
+		config.meta_field = 0;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void *) arg, &config, sizeof(config)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+
+		break;
+	}
+	case AUDIO_GET_WMAPRO_CONFIG:{
+			if (copy_to_user((void *)arg, &audio->wmapro_config,
+				sizeof(audio->wmapro_config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_SET_WMAPRO_CONFIG:{
+		struct msm_audio_wmapro_config usr_config;
+
+		if (copy_from_user
+			(&usr_config, (void *)arg,
+			sizeof(usr_config))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		audio->wmapro_config = usr_config;
+
+		/* Need to swap the first and last words of advancedencodeopt2
+		 * as DSP cannot read 32-bit variable at a time. Need to be
+		 * split into two 16-bit and swap them as required by DSP */
+
+		audio->wmapro_config.advancedencodeopt2 =
+			((audio->wmapro_config.advancedencodeopt2 & 0xFFFF0000)
+			 >> 16) | ((audio->wmapro_config.advancedencodeopt2
+			 << 16) & 0xFFFF0000);
+		rc = 0;
+		break;
+	}
+	case AUDIO_GET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			config.pcm_feedback = audio->pcm_feedback;
+			config.buffer_count = PCM_BUF_MAX_COUNT;
+			config.buffer_size = PCM_BUFSZ_MIN;
+			if (copy_to_user((void *)arg, &config,
+					 sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_SET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			if (copy_from_user
+			    (&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+			if (config.pcm_feedback != audio->pcm_feedback) {
+				MM_ERR("Not sufficient permission to"
+						"change the playback mode\n");
+				rc = -EACCES;
+				break;
+			}
+			if ((config.buffer_count > PCM_BUF_MAX_COUNT) ||
+			    (config.buffer_count == 1))
+				config.buffer_count = PCM_BUF_MAX_COUNT;
+
+			if (config.buffer_size < PCM_BUFSZ_MIN)
+				config.buffer_size = PCM_BUFSZ_MIN;
+
+			/* Check if pcm feedback is required */
+			if ((config.pcm_feedback) && (!audio->read_data)) {
+				MM_DBG("allocate PCM buffer %d\n",
+						config.buffer_count *
+						config.buffer_size);
+				audio->read_phys =
+						allocate_contiguous_ebi_nomap(
+							config.buffer_size *
+							config.buffer_count,
+							SZ_4K);
+				if (!audio->read_phys) {
+					rc = -ENOMEM;
+					break;
+				}
+				audio->map_v_read = ioremap(
+							audio->read_phys,
+							config.buffer_size *
+							config.buffer_count);
+				if (IS_ERR(audio->map_v_read)) {
+					MM_ERR("read buf map fail\n");
+					rc = -ENOMEM;
+					free_contiguous_memory_by_paddr(
+							audio->read_phys);
+				} else {
+					uint8_t index;
+					uint32_t offset = 0;
+					audio->read_data =
+						audio->map_v_read;
+					audio->pcm_feedback = 1;
+					audio->buf_refresh = 0;
+					audio->pcm_buf_count =
+					    config.buffer_count;
+					audio->read_next = 0;
+					audio->fill_next = 0;
+
+					for (index = 0;
+					     index < config.buffer_count;
+					     index++) {
+						audio->in[index].data =
+						    audio->read_data + offset;
+						audio->in[index].addr =
+						    audio->read_phys + offset;
+						audio->in[index].size =
+						    config.buffer_size;
+						audio->in[index].used = 0;
+						offset += config.buffer_size;
+					}
+					MM_DBG("read buf: phy addr \
+						0x%08x kernel addr 0x%08x\n",
+						audio->read_phys,
+						(int)audio->read_data);
+					rc = 0;
+				}
+			} else {
+				rc = 0;
+			}
+			break;
+		}
+	case AUDIO_PAUSE:
+		MM_DBG("AUDIO_PAUSE %ld\n", arg);
+		rc = audpp_pause(audio->dec_id, (int) arg);
+		break;
+	case AUDIO_GET_SESSION_ID:
+		if (copy_to_user((void *) arg, &audio->dec_id,
+					sizeof(unsigned short)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+/* Only useful in tunnel-mode */
+static int audio_fsync(struct file *file, loff_t ppos1, loff_t ppos2, int datasync)
+{
+	struct audio *audio = file->private_data;
+	struct buffer *frame;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	if (!audio->running || audio->pcm_feedback) {
+		rc = -EINVAL;
+		goto done_nolock;
+	}
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(!audio->out[0].used &&
+		!audio->out[1].used &&
+		audio->out_needed) || audio->wflush);
+
+	if (rc < 0)
+		goto done;
+	else if (audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (audio->reserved) {
+		MM_DBG("send reserved byte\n");
+		frame = audio->out + audio->out_tail;
+		((char *) frame->data)[0] = audio->rsv_byte;
+		((char *) frame->data)[1] = 0;
+		frame->used = 2;
+		audplay_send_data(audio, 0);
+
+		rc = wait_event_interruptible(audio->write_wait,
+			(!audio->out[0].used &&
+			!audio->out[1].used &&
+			audio->out_needed) || audio->wflush);
+
+		if (rc < 0)
+			goto done;
+		else if (audio->wflush) {
+			rc = -EBUSY;
+			goto done;
+		}
+	}
+
+	/* pcm dmamiss message is sent continously
+	 * when decoder is starved so no race
+	 * condition concern
+	 */
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		audio->teos || audio->wflush);
+
+	if (audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+done_nolock:
+	return rc;
+}
+
+static ssize_t audio_read(struct file *file, char __user *buf, size_t count,
+			  loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	int rc = 0;
+
+	if (!audio->pcm_feedback)
+		return 0; /* PCM feedback is not enabled. Nothing to read */
+
+	mutex_lock(&audio->read_lock);
+	MM_DBG("%d \n", count);
+	while (count > 0) {
+		rc = wait_event_interruptible(audio->read_wait,
+			(audio->in[audio->read_next].used > 0) ||
+			(audio->stopped) || (audio->rflush));
+
+		if (rc < 0)
+			break;
+
+		if (audio->stopped || audio->rflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (count < audio->in[audio->read_next].used) {
+			/* Read must happen in frame boundary. Since driver
+			   does not know frame size, read count must be greater
+			   or equal to size of PCM samples */
+			MM_DBG("audio_read: no partial frame done reading\n");
+			break;
+		} else {
+			MM_DBG("audio_read: read from in[%d]\n",
+					audio->read_next);
+			if (copy_to_user
+			    (buf, audio->in[audio->read_next].data,
+			     audio->in[audio->read_next].used)) {
+				MM_ERR("invalid addr %x \n", (unsigned int)buf);
+				rc = -EFAULT;
+				break;
+			}
+			count -= audio->in[audio->read_next].used;
+			buf += audio->in[audio->read_next].used;
+			audio->in[audio->read_next].used = 0;
+			if ((++audio->read_next) == audio->pcm_buf_count)
+				audio->read_next = 0;
+			break;	/* Force to exit while loop
+				 * to prevent output thread
+				 * sleep too long if data is
+				 * not ready at this moment.
+				 */
+		}
+	}
+
+	/* don't feed output buffer to HW decoder during flushing
+	 * buffer refresh command will be sent once flush completes
+	 * send buf refresh command here can confuse HW decoder
+	 */
+	if (audio->buf_refresh && !audio->rflush) {
+		audio->buf_refresh = 0;
+		MM_DBG("kick start pcm feedback again\n");
+		audplay_buffer_refresh(audio);
+	}
+
+	mutex_unlock(&audio->read_lock);
+
+	if (buf > start)
+		rc = buf - start;
+
+	MM_DBG("read %d bytes\n", rc);
+	return rc;
+}
+
+static int audwmapro_process_eos(struct audio *audio,
+		const char __user *buf_start, unsigned short mfield_size)
+{
+	int rc = 0;
+	struct buffer *frame;
+	char *buf_ptr;
+
+	if (audio->reserved) {
+		MM_DBG("flush reserve byte\n");
+		frame = audio->out + audio->out_head;
+		buf_ptr = frame->data;
+		rc = wait_event_interruptible(audio->write_wait,
+				(frame->used == 0)
+				|| (audio->stopped)
+				|| (audio->wflush));
+		if (rc < 0)
+			goto done;
+		if (audio->stopped || audio->wflush) {
+			rc = -EBUSY;
+			goto done;
+		}
+
+		buf_ptr[0] = audio->rsv_byte;
+		buf_ptr[1] = 0;
+		audio->out_head ^= 1;
+		frame->mfield_sz = 0;
+		frame->used = 2;
+		audio->reserved = 0;
+		audplay_send_data(audio, 0);
+	}
+
+	frame = audio->out + audio->out_head;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->out_needed &&
+		audio->out[0].used == 0 &&
+		audio->out[1].used == 0)
+		|| (audio->stopped)
+		|| (audio->wflush));
+
+	if (rc < 0)
+		goto done;
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (copy_from_user(frame->data, buf_start, mfield_size)) {
+		rc = -EFAULT;
+		goto done;
+	}
+
+	frame->mfield_sz = mfield_size;
+	audio->out_head ^= 1;
+	frame->used = mfield_size;
+	audplay_send_data(audio, 0);
+done:
+	return rc;
+}
+
+static ssize_t audio_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	char *cpy_ptr;
+	int rc = 0, eos_condition = AUDWMAPRO_EOS_NONE;
+	unsigned dsize;
+	unsigned short mfield_size = 0;
+
+	MM_DBG("cnt=%d\n", count);
+
+	mutex_lock(&audio->write_lock);
+	while (count > 0) {
+		frame = audio->out + audio->out_head;
+		cpy_ptr = frame->data;
+		dsize = 0;
+		rc = wait_event_interruptible(audio->write_wait,
+					      (frame->used == 0)
+					      || (audio->stopped)
+						  || (audio->wflush));
+		if (rc < 0)
+			break;
+		if (audio->stopped || audio->wflush) {
+			rc = -EBUSY;
+			break;
+		}
+		if (audio->mfield) {
+			if (buf == start) {
+				/* Processing beginning of user buffer */
+				if (__get_user(mfield_size,
+					(unsigned short __user *) buf)) {
+					rc = -EFAULT;
+					break;
+				} else  if (mfield_size > count) {
+					rc = -EINVAL;
+					break;
+				}
+				MM_DBG("audio_write: mf offset_val %x\n",
+						mfield_size);
+				if (copy_from_user(cpy_ptr, buf, mfield_size)) {
+					rc = -EFAULT;
+					break;
+				}
+				/* Check if EOS flag is set and buffer has
+				 * contains just meta field
+				 */
+				if (cpy_ptr[AUDWMAPRO_EOS_FLG_OFFSET] &
+						 AUDWMAPRO_EOS_FLG_MASK) {
+					MM_DBG("audio_write: EOS SET\n");
+					eos_condition = AUDWMAPRO_EOS_SET;
+					if (mfield_size == count) {
+						buf += mfield_size;
+						break;
+					} else
+					cpy_ptr[AUDWMAPRO_EOS_FLG_OFFSET]
+						&= ~AUDWMAPRO_EOS_FLG_MASK;
+				}
+				cpy_ptr += mfield_size;
+				count -= mfield_size;
+				dsize += mfield_size;
+				buf += mfield_size;
+			} else {
+				mfield_size = 0;
+				MM_DBG("audio_write: continuous buffer\n");
+			}
+			frame->mfield_sz = mfield_size;
+		}
+
+		if (audio->reserved) {
+			MM_DBG("append reserved byte %x\n", audio->rsv_byte);
+			*cpy_ptr = audio->rsv_byte;
+			xfer = (count > ((frame->size - mfield_size) - 1)) ?
+				(frame->size - mfield_size) - 1 : count;
+			cpy_ptr++;
+			dsize += 1;
+			audio->reserved = 0;
+		} else
+			xfer = (count > (frame->size - mfield_size)) ?
+				(frame->size - mfield_size) : count;
+
+		if (copy_from_user(cpy_ptr, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+
+		dsize += xfer;
+		if (dsize & 1) {
+			audio->rsv_byte = ((char *) frame->data)[dsize - 1];
+			MM_DBG("odd length buf reserve last byte %x\n",
+					audio->rsv_byte);
+			audio->reserved = 1;
+			dsize--;
+		}
+		count -= xfer;
+		buf += xfer;
+
+		if (dsize > 0) {
+			audio->out_head ^= 1;
+			frame->used = dsize;
+			audplay_send_data(audio, 0);
+		}
+	}
+	if (eos_condition == AUDWMAPRO_EOS_SET)
+		rc = audwmapro_process_eos(audio, start, mfield_size);
+	mutex_unlock(&audio->write_lock);
+	if (!rc) {
+		if (buf > start)
+			return buf - start;
+	}
+	return rc;
+}
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	MM_INFO("audio instance 0x%08x freeing\n", (int)audio);
+	mutex_lock(&audio->lock);
+	auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->dec_id);
+	audio_disable(audio);
+	audio_flush(audio);
+	audio_flush_pcm_buf(audio);
+	msm_adsp_put(audio->audplay);
+	audpp_adec_free(audio->dec_id);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&audio->suspend_ctl.node);
+#endif
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audwmapro_reset_event_queue(audio);
+	iounmap(audio->map_v_write);
+	free_contiguous_memory_by_paddr(audio->phys);
+	if (audio->read_data) {
+		iounmap(audio->map_v_read);
+		free_contiguous_memory_by_paddr(audio->read_phys);
+	}
+	mutex_unlock(&audio->lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio);
+	return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audwmapro_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload)
+{
+	struct audwmapro_event *e_node = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+				struct audwmapro_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audwmapro_event), GFP_ATOMIC);
+		if (!e_node) {
+			MM_ERR("No mem to post event %d\n", type);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	wake_up(&audio->event_wait);
+}
+
+static void audwmapro_suspend(struct early_suspend *h)
+{
+	struct audwmapro_suspend_ctl *ctl =
+		container_of(h, struct audwmapro_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audwmapro_post_event(ctl->audio, AUDIO_EVENT_SUSPEND, payload);
+}
+
+static void audwmapro_resume(struct early_suspend *h)
+{
+	struct audwmapro_suspend_ctl *ctl =
+		container_of(h, struct audwmapro_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audwmapro_post_event(ctl->audio, AUDIO_EVENT_RESUME, payload);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audwmapro_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audwmapro_debug_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 4096;
+	static char buffer[4096];
+	int n = 0, i;
+	struct audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "enabled %d\n", audio->enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "pcm_feedback %d\n", audio->pcm_feedback);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_buf_sz %d\n", audio->out[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "pcm_buf_count %d \n", audio->pcm_buf_count);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "pcm_buf_sz %d \n", audio->in[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "volume %x \n", audio->vol_pan.volume);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "sample rate %d \n", audio->out_sample_rate);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		"channel mode %d \n", audio->out_channel_mode);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "rflush %d\n", audio->rflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "running %d \n", audio->running);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"dec state %d \n", audio->dec_state);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_needed %d \n", audio->out_needed);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_head %d \n", audio->out_head);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out_tail %d \n", audio->out_tail);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out[0].used %d \n", audio->out[0].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "out[1].used %d \n", audio->out[1].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "buffer_refresh %d \n", audio->buf_refresh);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "read_next %d \n", audio->read_next);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+				   "fill_next %d \n", audio->fill_next);
+	for (i = 0; i < audio->pcm_buf_count; i++)
+		n += scnprintf(buffer + n, debug_bufmax - n,
+			"in[%d].size %d \n", i, audio->in[i].used);
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audwmapro_debug_fops = {
+	.read = audwmapro_debug_read,
+	.open = audwmapro_debug_open,
+};
+#endif
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = NULL;
+	int rc, dec_attrb, decid, i;
+	unsigned pmem_sz = DMASZ_MAX;
+	struct audwmapro_event *e_node = NULL;
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_wmapro_" + 5];
+#endif
+
+	/* Allocate Mem for audio instance */
+	audio = kzalloc(sizeof(struct audio), GFP_KERNEL);
+	if (!audio) {
+		MM_ERR("no memory to allocate audio instance \n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	MM_INFO("audio instance 0x%08x created\n", (int)audio);
+
+	/* Allocate the decoder */
+	dec_attrb = AUDDEC_DEC_WMAPRO;
+	if ((file->f_mode & FMODE_WRITE) &&
+			(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_NONTUNNEL;
+		audio->pcm_feedback = NON_TUNNEL_MODE_PLAYBACK;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_TUNNEL;
+		audio->pcm_feedback = TUNNEL_MODE_PLAYBACK;
+	} else {
+		kfree(audio);
+		rc = -EACCES;
+		goto done;
+	}
+
+	decid = audpp_adec_alloc(dec_attrb, &audio->module_name,
+			&audio->queue_id);
+
+	if (decid < 0) {
+		MM_ERR("No free decoder available, freeing instance 0x%08x\n",
+				(int)audio);
+		rc = -ENODEV;
+		kfree(audio);
+		goto done;
+	}
+	audio->dec_id = decid & MSM_AUD_DECODER_MASK;
+
+	while (pmem_sz >= DMASZ_MIN) {
+		MM_DBG("pmemsz = %d\n", pmem_sz);
+		audio->phys = allocate_contiguous_ebi_nomap(pmem_sz, SZ_4K);
+		if (audio->phys) {
+			audio->map_v_write = ioremap(audio->phys, pmem_sz);
+			if (IS_ERR(audio->map_v_write)) {
+				MM_ERR("could not map write buffers, \
+						freeing instance 0x%08x\n",
+						(int)audio);
+				rc = -ENOMEM;
+				free_contiguous_memory_by_paddr(audio->phys);
+				audpp_adec_free(audio->dec_id);
+				kfree(audio);
+				goto done;
+			}
+			audio->data = audio->map_v_write;
+			MM_DBG("write buf: phy addr 0x%08x kernel addr \
+				0x%08x\n", audio->phys, (int)audio->data);
+			break;
+		} else if (pmem_sz == DMASZ_MIN) {
+			MM_ERR("could not allocate write buffers, freeing \
+					instance 0x%08x\n", (int)audio);
+			rc = -ENOMEM;
+			audpp_adec_free(audio->dec_id);
+			kfree(audio);
+			goto done;
+		} else
+		pmem_sz >>= 1;
+	}
+	audio->out_dma_sz = pmem_sz;
+
+	rc = msm_adsp_get(audio->module_name, &audio->audplay,
+			&audplay_adsp_ops_wmapro, audio);
+	if (rc) {
+		MM_ERR("failed to get %s module, freeing instance 0x%08x\n",
+				audio->module_name, (int)audio);
+		goto err;
+	}
+
+	mutex_init(&audio->lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->get_event_lock);
+	spin_lock_init(&audio->dsp_lock);
+	init_waitqueue_head(&audio->write_wait);
+	init_waitqueue_head(&audio->read_wait);
+	INIT_LIST_HEAD(&audio->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+	init_waitqueue_head(&audio->wait);
+	init_waitqueue_head(&audio->event_wait);
+	spin_lock_init(&audio->event_queue_lock);
+	init_waitqueue_head(&audio->avsync_wait);
+
+	audio->out[0].data = audio->data + 0;
+	audio->out[0].addr = audio->phys + 0;
+	audio->out[0].size = audio->out_dma_sz >> 1;
+
+	audio->out[1].data = audio->data + audio->out[0].size;
+	audio->out[1].addr = audio->phys + audio->out[0].size;
+	audio->out[1].size = audio->out[0].size;
+
+	/*audio->wmapro_config.armdatareqthr =  1268;
+	audio->wmapro_config.numchannels = 2;
+	audio->wmapro_config.avgbytespersecond = 6003;
+	audio->wmapro_config.samplingrate = 44100;
+	audio->wmapro_config.encodeopt = 224;
+	audio->wmapro_config.validbitspersample = 16;
+	audio->wmapro_config.formattag = 354;
+	audio->wmapro_config.asfpacketlength = 2230;
+	audio->wmapro_config.channelmask = 3;
+	audio->wmapro_config.advancedencodeopt = 32834;
+	audio->wmapro_config.advancedencodeopt2 = 0;*/
+
+	audio->out_sample_rate = 44100;
+	audio->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V;
+
+	audio->vol_pan.volume = 0x2000;
+
+	audio_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+	audio->device_events = AUDDEV_EVT_DEV_RDY
+				|AUDDEV_EVT_DEV_RLS|
+				AUDDEV_EVT_STREAM_VOL_CHG;
+
+	rc = auddev_register_evt_listner(audio->device_events,
+					AUDDEV_CLNT_DEC,
+					audio->dec_id,
+					wmapro_listner,
+					(void *)audio);
+	if (rc) {
+		MM_ERR("%s: failed to register listner\n", __func__);
+		goto event_err;
+	}
+
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_wmapro_%04x", audio->dec_id);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+				NULL, (void *) audio,
+				&audwmapro_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		MM_DBG("debugfs_create_file failed\n");
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	audio->suspend_ctl.node.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+	audio->suspend_ctl.node.resume = audwmapro_resume;
+	audio->suspend_ctl.node.suspend = audwmapro_suspend;
+	audio->suspend_ctl.audio = audio;
+	register_early_suspend(&audio->suspend_ctl.node);
+#endif
+	for (i = 0; i < AUDWMAPRO_EVENT_NUM; i++) {
+		e_node = kmalloc(sizeof(struct audwmapro_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			MM_ERR("event pkt alloc failed\n");
+			break;
+		}
+	}
+done:
+	return rc;
+event_err:
+	msm_adsp_put(audio->audplay);
+err:
+	iounmap(audio->map_v_write);
+	free_contiguous_memory_by_paddr(audio->phys);
+	audpp_adec_free(audio->dec_id);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_wmapro_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audio_open,
+	.release	= audio_release,
+	.read 		= audio_read,
+	.write		= audio_write,
+	.unlocked_ioctl	= audio_ioctl,
+	.fsync 		= audio_fsync,
+};
+
+struct miscdevice audio_wmapro_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_wmapro",
+	.fops	= &audio_wmapro_fops,
+};
+
+static int __init audio_init(void)
+{
+	return misc_register(&audio_wmapro_misc);
+}
+
+device_initcall(audio_init);
diff --git a/arch/arm/mach-msm/qdsp5v2/audpp.c b/arch/arm/mach-msm/qdsp5v2/audpp.c
new file mode 100644
index 0000000..31ce643
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/audpp.c
@@ -0,0 +1,1140 @@
+/* arch/arm/mach-msm/qdsp5/audpp.c
+ *
+ * common code to deal with the AUDPP dsp task (audio postproc)
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2009-2011, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/platform_device.h>
+#include <linux/wakelock.h>
+
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <mach/board.h>
+#include <mach/msm_adsp.h>
+#include <mach/qdsp5v2/audio_acdbi.h>
+#include <mach/qdsp5v2/qdsp5audppcmdi.h>
+#include <mach/qdsp5v2/qdsp5audppmsg.h>
+#include <mach/qdsp5v2/audpp.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+
+#include "../qdsp5/evlog.h"
+#include <mach/debug_mm.h>
+
+enum {
+	EV_NULL,
+	EV_ENABLE,
+	EV_DISABLE,
+	EV_EVENT,
+	EV_DATA,
+};
+
+static const char *dsp_log_strings[] = {
+	"NULL",
+	"ENABLE",
+	"DISABLE",
+	"EVENT",
+	"DATA",
+};
+
+DECLARE_LOG(dsp_log, 64, dsp_log_strings);
+
+static int __init _dsp_log_init(void)
+{
+	return ev_log_init(&dsp_log);
+}
+
+module_init(_dsp_log_init);
+#define LOG(id, arg) ev_log_write(&dsp_log, id, arg)
+
+static DEFINE_MUTEX(audpp_lock);
+static DEFINE_MUTEX(audpp_dec_lock);
+static struct wake_lock audpp_wake_lock;
+
+#define CH_COUNT 5
+#define AUDPP_CLNT_MAX_COUNT 6
+
+#define AUDPP_CMD_CFG_OBJ_UPDATE 0x8000
+#define AUDPP_CMD_EQ_FLAG_DIS	0x0000
+#define AUDPP_CMD_EQ_FLAG_ENA	-1
+#define AUDPP_CMD_IIR_FLAG_DIS	  0x0000
+#define AUDPP_CMD_IIR_FLAG_ENA	  -1
+#define AUDPP_CMD_STF_FLAG_ENA -1
+#define AUDPP_CMD_STF_FLAG_DIS 0x0000
+
+#define MAX_EVENT_CALLBACK_CLIENTS 	1
+
+#define AUDPP_CONCURRENCY_DEFAULT 0	/* Set default to LPA mode */
+#define AUDPP_MAX_DECODER_CNT 5
+#define AUDPP_CODEC_MASK 0x000000FF
+#define AUDPP_MODE_MASK 0x00000F00
+#define AUDPP_OP_MASK 0xF0000000
+
+struct audpp_decoder_info {
+	unsigned int codec;
+	pid_t pid;
+};
+
+struct audpp_state {
+	struct msm_adsp_module *mod;
+	audpp_event_func func[AUDPP_CLNT_MAX_COUNT];
+	void *private[AUDPP_CLNT_MAX_COUNT];
+	struct mutex *lock;
+	unsigned open_count;
+	unsigned enabled;
+
+	/* Related to decoder allocation */
+	struct mutex *lock_dec;
+	struct msm_adspdec_database *dec_database;
+	struct audpp_decoder_info dec_info_table[AUDPP_MAX_DECODER_CNT];
+	unsigned dec_inuse;
+	unsigned long concurrency;
+
+	struct audpp_event_callback *cb_tbl[MAX_EVENT_CALLBACK_CLIENTS];
+
+	/* Related to decoder instances */
+	uint8_t op_mode; /* Specifies Turbo/Non Turbo mode */
+	uint8_t decoder_count; /* No. of decoders active running */
+	uint8_t codec_max_instances; /* Max codecs allowed currently */
+	uint8_t codec_cnt[MSM_MAX_DEC_CNT]; /* Nr of each codec
+						 type enabled */
+
+	wait_queue_head_t event_wait;
+};
+
+struct audpp_state the_audpp_state = {
+	.lock = &audpp_lock,
+	.lock_dec = &audpp_dec_lock,
+};
+
+static inline void prevent_suspend(void)
+{
+	wake_lock(&audpp_wake_lock);
+}
+static inline void allow_suspend(void)
+{
+	wake_unlock(&audpp_wake_lock);
+}
+
+int audpp_send_queue1(void *cmd, unsigned len)
+{
+	return msm_adsp_write(the_audpp_state.mod,
+			      QDSP_uPAudPPCmd1Queue, cmd, len);
+}
+EXPORT_SYMBOL(audpp_send_queue1);
+
+int audpp_send_queue2(void *cmd, unsigned len)
+{
+	return msm_adsp_write(the_audpp_state.mod,
+			      QDSP_uPAudPPCmd2Queue, cmd, len);
+}
+EXPORT_SYMBOL(audpp_send_queue2);
+
+int audpp_send_queue3(void *cmd, unsigned len)
+{
+	return msm_adsp_write(the_audpp_state.mod,
+			      QDSP_uPAudPPCmd3Queue, cmd, len);
+}
+EXPORT_SYMBOL(audpp_send_queue3);
+
+static int audpp_dsp_config(int enable)
+{
+	struct audpp_cmd_cfg cmd;
+
+	cmd.cmd_id = AUDPP_CMD_CFG;
+	cmd.cfg = enable ? AUDPP_CMD_CFG_ENABLE : AUDPP_CMD_CFG_SLEEP;
+
+	return audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+void audpp_route_stream(unsigned short dec_id, unsigned short mixer_mask)
+{
+	struct audpp_cmd_cfg_dev_mixer_params mixer_params_cmd;
+
+	memset(&mixer_params_cmd, 0, sizeof(mixer_params_cmd));
+
+	mixer_params_cmd.cmd_id = AUDPP_CMD_CFG_DEV_MIXER;
+	mixer_params_cmd.stream_id = dec_id;
+	mixer_params_cmd.mixer_cmd = mixer_mask;
+	audpp_send_queue1(&mixer_params_cmd, sizeof(mixer_params_cmd));
+
+}
+EXPORT_SYMBOL(audpp_route_stream);
+
+int is_audpp_enable(void)
+{
+	struct audpp_state *audpp = &the_audpp_state;
+
+	return audpp->enabled;
+}
+EXPORT_SYMBOL(is_audpp_enable);
+
+int audpp_register_event_callback(struct audpp_event_callback *ecb)
+{
+	struct audpp_state *audpp = &the_audpp_state;
+	int i;
+
+	for (i = 0; i < MAX_EVENT_CALLBACK_CLIENTS; ++i) {
+		if (NULL == audpp->cb_tbl[i]) {
+			audpp->cb_tbl[i] = ecb;
+			return 0;
+		}
+	}
+	return -1;
+}
+EXPORT_SYMBOL(audpp_register_event_callback);
+
+
+int audpp_unregister_event_callback(struct audpp_event_callback *ecb)
+{
+	struct audpp_state *audpp = &the_audpp_state;
+	int i;
+
+	for (i = 0; i < MAX_EVENT_CALLBACK_CLIENTS; ++i) {
+		if (ecb == audpp->cb_tbl[i]) {
+			audpp->cb_tbl[i] = NULL;
+			return 0;
+		}
+	}
+	return -1;
+}
+EXPORT_SYMBOL(audpp_unregister_event_callback);
+
+static void audpp_broadcast(struct audpp_state *audpp, unsigned id,
+			    uint16_t *msg)
+{
+	unsigned n;
+	for (n = 0; n < AUDPP_CLNT_MAX_COUNT; n++) {
+		if (audpp->func[n])
+			audpp->func[n] (audpp->private[n], id, msg);
+	}
+
+	for (n = 0; n < MAX_EVENT_CALLBACK_CLIENTS; ++n)
+		if (audpp->cb_tbl[n] && audpp->cb_tbl[n]->fn)
+			audpp->cb_tbl[n]->fn(audpp->cb_tbl[n]->private, id,
+					     msg);
+}
+
+static void audpp_notify_clnt(struct audpp_state *audpp, unsigned clnt_id,
+			      unsigned id, uint16_t *msg)
+{
+	if (clnt_id < AUDPP_CLNT_MAX_COUNT && audpp->func[clnt_id])
+		audpp->func[clnt_id] (audpp->private[clnt_id], id, msg);
+}
+
+static void audpp_handle_pcmdmamiss(struct audpp_state *audpp,
+				    uint16_t bit_mask)
+{
+	uint8_t b_index;
+
+	for (b_index = 0; b_index < AUDPP_CLNT_MAX_COUNT; b_index++) {
+		if (bit_mask & (0x1 << b_index))
+			if (audpp->func[b_index])
+				audpp->func[b_index] (audpp->private[b_index],
+						      AUDPP_MSG_PCMDMAMISSED,
+						      &bit_mask);
+	}
+}
+
+static void audpp_dsp_event(void *data, unsigned id, size_t len,
+			    void (*getevent) (void *ptr, size_t len))
+{
+	struct audpp_state *audpp = data;
+	uint16_t msg[8];
+
+	getevent(msg, sizeof(msg));
+
+	LOG(EV_EVENT, (id << 16) | msg[0]);
+	LOG(EV_DATA, (msg[1] << 16) | msg[2]);
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned cid = msg[0];
+			MM_DBG("status %d %d %d\n", cid, msg[1], msg[2]);
+
+			if ((cid < 5) && audpp->func[cid])
+				audpp->func[cid] (audpp->private[cid], id, msg);
+			break;
+		}
+	case AUDPP_MSG_HOST_PCM_INTF_MSG:
+		if (audpp->func[5])
+			audpp->func[5] (audpp->private[5], id, msg);
+		break;
+	case AUDPP_MSG_PCMDMAMISSED:
+		audpp_handle_pcmdmamiss(audpp, msg[0]);
+		break;
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			MM_INFO("ENABLE\n");
+			audpp->enabled = 1;
+			audpp_broadcast(audpp, id, msg);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			MM_INFO("DISABLE\n");
+			audpp->enabled = 0;
+			wake_up(&audpp->event_wait);
+			audpp_broadcast(audpp, id, msg);
+		} else {
+			MM_ERR("invalid config msg %d\n", msg[0]);
+		}
+		break;
+	case AUDPP_MSG_ROUTING_ACK:
+		audpp_notify_clnt(audpp, msg[0], id, msg);
+		break;
+	case AUDPP_MSG_FLUSH_ACK:
+		audpp_notify_clnt(audpp, msg[0], id, msg);
+		break;
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable/disable \
+				(audpptask)");
+		break;
+	case AUDPP_MSG_AVSYNC_MSG:
+		audpp_notify_clnt(audpp, msg[0], id, msg);
+		break;
+#ifdef CONFIG_DEBUG_FS
+	case AUDPP_MSG_FEAT_QUERY_DM_DONE:
+		MM_INFO(" RTC ACK --> %x %x %x %x %x %x %x %x\n", msg[0],\
+			msg[1], msg[2], msg[3], msg[4], \
+			msg[5], msg[6], msg[7]);
+		acdb_rtc_set_err(msg[3]);
+		break;
+#endif
+	default:
+		MM_INFO("unhandled msg id %x\n", id);
+	}
+}
+
+static struct msm_adsp_ops adsp_ops = {
+	.event = audpp_dsp_event,
+};
+
+static void audpp_fake_event(struct audpp_state *audpp, int id,
+			     unsigned event, unsigned arg)
+{
+	uint16_t msg[1];
+	uint16_t n = 0;
+	msg[0] = arg;
+	audpp->func[id] (audpp->private[id], event, msg);
+	if (audpp->enabled == 1) {
+		for (n = 0; n < MAX_EVENT_CALLBACK_CLIENTS; ++n)
+			if (audpp->cb_tbl[n] && audpp->cb_tbl[n]->fn)
+				audpp->cb_tbl[n]->fn(audpp->cb_tbl[n]->private,
+					 AUDPP_MSG_CFG_MSG, msg);
+	}
+}
+
+int audpp_enable(int id, audpp_event_func func, void *private)
+{
+	struct audpp_state *audpp = &the_audpp_state;
+	int res = 0;
+
+	if (id < -1 || id > 4)
+		return -EINVAL;
+
+	if (id == -1)
+		id = 5;
+
+	mutex_lock(audpp->lock);
+	if (audpp->func[id]) {
+		res = -EBUSY;
+		goto out;
+	}
+
+	audpp->func[id] = func;
+	audpp->private[id] = private;
+
+	LOG(EV_ENABLE, 1);
+	if (audpp->open_count++ == 0) {
+		MM_DBG("enable\n");
+		res = msm_adsp_get("AUDPPTASK", &audpp->mod, &adsp_ops, audpp);
+		if (res < 0) {
+			MM_ERR("audpp: cannot open AUDPPTASK\n");
+			audpp->open_count = 0;
+			audpp->func[id] = NULL;
+			audpp->private[id] = NULL;
+			goto out;
+		}
+		LOG(EV_ENABLE, 2);
+		prevent_suspend();
+		msm_adsp_enable(audpp->mod);
+		audpp_dsp_config(1);
+	} else {
+		unsigned long flags;
+		local_irq_save(flags);
+		if (audpp->enabled)
+			audpp_fake_event(audpp, id,
+					 AUDPP_MSG_CFG_MSG, AUDPP_MSG_ENA_ENA);
+		local_irq_restore(flags);
+	}
+
+	res = 0;
+out:
+	mutex_unlock(audpp->lock);
+	return res;
+}
+EXPORT_SYMBOL(audpp_enable);
+
+void audpp_disable(int id, void *private)
+{
+	struct audpp_state *audpp = &the_audpp_state;
+	unsigned long flags;
+	int rc;
+
+	if (id < -1 || id > 4)
+		return;
+
+	if (id == -1)
+		id = 5;
+
+	mutex_lock(audpp->lock);
+	LOG(EV_DISABLE, 1);
+	if (!audpp->func[id])
+		goto out;
+	if (audpp->private[id] != private)
+		goto out;
+
+	local_irq_save(flags);
+	audpp_fake_event(audpp, id, AUDPP_MSG_CFG_MSG, AUDPP_MSG_ENA_DIS);
+	audpp->func[id] = NULL;
+	audpp->private[id] = NULL;
+	local_irq_restore(flags);
+
+	if (--audpp->open_count == 0) {
+		MM_DBG("disable\n");
+		LOG(EV_DISABLE, 2);
+		audpp_dsp_config(0);
+		rc = wait_event_interruptible(audpp->event_wait,
+				(audpp->enabled == 0));
+		if (audpp->enabled == 0)
+			MM_INFO("Received CFG_MSG_DISABLE from ADSP\n");
+		else
+			MM_ERR("Didn't receive CFG_MSG DISABLE \
+					message from ADSP\n");
+		msm_adsp_disable(audpp->mod);
+		msm_adsp_put(audpp->mod);
+		audpp->mod = NULL;
+		allow_suspend();
+	}
+out:
+	mutex_unlock(audpp->lock);
+}
+EXPORT_SYMBOL(audpp_disable);
+
+#define BAD_ID(id) ((id < 0) || (id >= CH_COUNT))
+
+int audpp_restore_avsync(int id, uint16_t *avsync)
+{
+	struct audpp_cmd_avsync cmd;
+
+	if (BAD_ID(id))
+		return -1;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_AVSYNC;
+	cmd.stream_id = id;
+	cmd.interrupt_interval = 0; /* Setting it to Zero as there won't be
+					periodic update */
+	cmd.sample_counter_dlsw = avsync[3];
+	cmd.sample_counter_dmsw = avsync[2];
+	cmd.sample_counter_msw = avsync[1];
+	cmd.byte_counter_dlsw = avsync[6];
+	cmd.byte_counter_dmsw = avsync[5];
+	cmd.byte_counter_msw = avsync[4];
+
+	return audpp_send_queue1(&cmd, sizeof(cmd));
+}
+EXPORT_SYMBOL(audpp_restore_avsync);
+
+int audpp_query_avsync(int id)
+{
+	struct audpp_cmd_query_avsync cmd;
+
+	if (BAD_ID(id))
+		return -EINVAL;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_QUERY_AVSYNC;
+	cmd.stream_id = id;
+	return audpp_send_queue1(&cmd, sizeof(cmd));
+
+}
+EXPORT_SYMBOL(audpp_query_avsync);
+
+int audpp_set_volume_and_pan(unsigned id, unsigned volume, int pan,
+			enum obj_type objtype)
+{
+	/* cmd, obj_cfg[7], cmd_type, volume, pan */
+	uint16_t cmd[7];
+
+	if (objtype) {
+		if (id > 5) {
+			MM_ERR("Wrong POPP decoder id: %d\n", id);
+			return -EINVAL;
+		}
+	} else {
+		if (id > 3) {
+			MM_ERR("Wrong COPP decoder id: %d\n", id);
+			return -EINVAL;
+		}
+	}
+
+	memset(cmd, 0, sizeof(cmd));
+	cmd[0] = AUDPP_CMD_CFG_OBJECT_PARAMS;
+	if (objtype)
+		cmd[1] = AUDPP_CMD_POPP_STREAM;
+	else
+		cmd[1] = AUDPP_CMD_COPP_STREAM;
+	cmd[2] = id;
+	cmd[3] = AUDPP_CMD_CFG_OBJ_UPDATE;
+	cmd[4] = AUDPP_CMD_VOLUME_PAN;
+	cmd[5] = volume;
+	cmd[6] = pan;
+
+	return audpp_send_queue3(cmd, sizeof(cmd));
+}
+EXPORT_SYMBOL(audpp_set_volume_and_pan);
+
+/* Implementation of COPP features */
+int audpp_dsp_set_mbadrc(unsigned id, unsigned enable,
+	struct audpp_cmd_cfg_object_params_mbadrc *mbadrc,
+	enum obj_type objtype)
+{
+	if (objtype) {
+		if (id > 5) {
+			MM_ERR("Wrong POPP decoder id: %d\n", id);
+			return -EINVAL;
+		}
+	} else {
+		if (id > 3) {
+			MM_ERR("Wrong COPP decoder id: %d\n", id);
+			return -EINVAL;
+		}
+	}
+
+	mbadrc->common.cmd_id = AUDPP_CMD_CFG_OBJECT_PARAMS;
+	if (objtype)
+		mbadrc->common.stream = AUDPP_CMD_POPP_STREAM;
+	else
+		mbadrc->common.stream = AUDPP_CMD_COPP_STREAM;
+
+	mbadrc->common.stream_id = id;
+	mbadrc->common.obj_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
+	mbadrc->common.command_type = AUDPP_CMD_MBADRC;
+
+	if (enable)
+		mbadrc->enable = AUDPP_CMD_ADRC_FLAG_ENA;
+	else
+		mbadrc->enable = AUDPP_CMD_ADRC_FLAG_DIS;
+
+	return audpp_send_queue3(mbadrc,
+			sizeof(struct audpp_cmd_cfg_object_params_mbadrc));
+}
+EXPORT_SYMBOL(audpp_dsp_set_mbadrc);
+
+int audpp_dsp_set_qconcert_plus(unsigned id, unsigned enable,
+	struct audpp_cmd_cfg_object_params_qconcert *qconcert_plus,
+	enum obj_type objtype)
+{
+	if (objtype) {
+		if (id > 5) {
+			MM_ERR("Wrong POPP decoder id: %d\n", id);
+			return -EINVAL;
+		}
+	} else {
+		if (id > 3) {
+			MM_ERR("Wrong COPP decoder id: %d\n", id);
+			return -EINVAL;
+		}
+	}
+
+	qconcert_plus->common.cmd_id = AUDPP_CMD_CFG_OBJECT_PARAMS;
+	if (objtype)
+		qconcert_plus->common.stream = AUDPP_CMD_POPP_STREAM;
+	else
+		qconcert_plus->common.stream = AUDPP_CMD_COPP_STREAM;
+
+	qconcert_plus->common.stream_id = id;
+	qconcert_plus->common.obj_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
+	qconcert_plus->common.command_type = AUDPP_CMD_QCONCERT;
+
+	if (enable)
+		qconcert_plus->enable_flag = AUDPP_CMD_ADRC_FLAG_ENA;
+	else
+		qconcert_plus->enable_flag = AUDPP_CMD_ADRC_FLAG_DIS;
+
+	return audpp_send_queue3(qconcert_plus,
+		sizeof(struct audpp_cmd_cfg_object_params_qconcert));
+}
+EXPORT_SYMBOL(audpp_dsp_set_qconcert_plus);
+
+int audpp_dsp_set_rx_iir(unsigned id, unsigned enable,
+	struct audpp_cmd_cfg_object_params_pcm *iir,
+	enum obj_type objtype)
+{
+
+	if (objtype) {
+		if (id > 5) {
+			MM_ERR("Wrong POPP decoder id: %d\n", id);
+			return -EINVAL;
+		}
+	} else {
+		if (id > 3) {
+			MM_ERR("Wrong COPP decoder id: %d\n", id);
+			return -EINVAL;
+		}
+	}
+
+	iir->common.cmd_id = AUDPP_CMD_CFG_OBJECT_PARAMS;
+	if (objtype)
+		iir->common.stream = AUDPP_CMD_POPP_STREAM;
+	else
+		iir->common.stream = AUDPP_CMD_COPP_STREAM;
+
+	iir->common.stream_id = id;
+	iir->common.obj_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
+	iir->common.command_type = AUDPP_CMD_IIR_TUNING_FILTER;
+
+	if (enable)
+		iir->active_flag = AUDPP_CMD_IIR_FLAG_ENA;
+	else
+		iir->active_flag = AUDPP_CMD_IIR_FLAG_DIS;
+
+	return audpp_send_queue3(iir,
+		sizeof(struct audpp_cmd_cfg_object_params_pcm));
+}
+EXPORT_SYMBOL(audpp_dsp_set_rx_iir);
+
+int audpp_dsp_set_gain_rx(unsigned id,
+			struct audpp_cmd_cfg_cal_gain *calib_gain_rx,
+			enum obj_type objtype)
+{
+	if (objtype) {
+		return -EINVAL;
+	} else {
+		if (id > 3) {
+			MM_ERR("Wrong COPP decoder id: %d\n", id);
+			return -EINVAL;
+		}
+	}
+	calib_gain_rx->common.cmd_id = AUDPP_CMD_CFG_OBJECT_PARAMS;
+	calib_gain_rx->common.stream = AUDPP_CMD_COPP_STREAM;
+
+	calib_gain_rx->common.stream_id = id;
+	calib_gain_rx->common.obj_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
+	calib_gain_rx->common.command_type = AUDPP_CMD_CALIB_GAIN_RX;
+
+	return audpp_send_queue3(calib_gain_rx,
+			sizeof(struct audpp_cmd_cfg_cal_gain));
+}
+EXPORT_SYMBOL(audpp_dsp_set_gain_rx);
+
+int audpp_dsp_set_pbe(unsigned id, unsigned enable,
+			struct audpp_cmd_cfg_pbe *pbe_block,
+			enum obj_type objtype)
+{
+	if (objtype) {
+		if (id > 5) {
+			MM_ERR("Wrong POPP decoder id: %d\n", id);
+			return -EINVAL;
+		}
+	} else {
+		if (id > 3) {
+			MM_ERR("Wrong COPP decoder id: %d\n", id);
+			return -EINVAL;
+		}
+	}
+
+	pbe_block->common.cmd_id = AUDPP_CMD_CFG_OBJECT_PARAMS;
+	if (objtype)
+		pbe_block->common.stream = AUDPP_CMD_POPP_STREAM;
+	else
+		pbe_block->common.stream = AUDPP_CMD_COPP_STREAM;
+
+	pbe_block->common.stream_id = id;
+	pbe_block->common.obj_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
+	pbe_block->common.command_type = AUDPP_CMD_PBE;
+
+	if (enable)
+		pbe_block->pbe_enable = AUDPP_CMD_PBE_FLAG_ENA;
+	else
+		pbe_block->pbe_enable = AUDPP_CMD_PBE_FLAG_DIS;
+
+	return audpp_send_queue3(pbe_block,
+			sizeof(struct audpp_cmd_cfg_pbe));
+}
+EXPORT_SYMBOL(audpp_dsp_set_pbe);
+
+int audpp_dsp_set_spa(unsigned id,
+     struct audpp_cmd_cfg_object_params_spectram *spa,
+			enum obj_type objtype){
+	struct audpp_cmd_cfg_object_params_spectram cmd;
+
+	if (objtype) {
+		if (id > 5) {
+			MM_ERR("Wrong POPP decoder id: %d\n", id);
+			return -EINVAL;
+		}
+	} else {
+		if (id > 3) {
+			MM_ERR("Wrong COPP decoder id: %d\n", id);
+			return -EINVAL;
+		}
+	}
+
+	memset(&cmd, 0, sizeof(cmd));
+	if (objtype)
+		cmd.common.stream = AUDPP_CMD_POPP_STREAM;
+	else
+		cmd.common.stream = AUDPP_CMD_COPP_STREAM;
+
+	cmd.common.stream_id = id;
+	cmd.common.obj_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
+	cmd.common.command_type = AUDPP_CMD_SPECTROGRAM;
+       cmd.sample_interval = spa->sample_interval;
+	cmd.num_coeff = spa->num_coeff;
+	return audpp_send_queue3(&cmd, sizeof(cmd));
+
+}
+EXPORT_SYMBOL(audpp_dsp_set_spa);
+
+int audpp_dsp_set_stf(unsigned id, unsigned enable,
+     struct audpp_cmd_cfg_object_params_sidechain *stf,
+			enum obj_type objtype){
+	if (objtype) {
+		if (id > 5) {
+			MM_ERR("Wrong POPP decoder id: %d\n", id);
+			return -EINVAL;
+		}
+	} else {
+		if (id > 3) {
+			MM_ERR("Wrong COPP decoder id: %d\n", id);
+			return -EINVAL;
+		}
+	}
+
+	stf->common.cmd_id = AUDPP_CMD_CFG_OBJECT_PARAMS;
+	if (objtype)
+		stf->common.stream = AUDPP_CMD_POPP_STREAM;
+	else
+		stf->common.stream = AUDPP_CMD_COPP_STREAM;
+
+	stf->common.stream_id = id;
+	stf->common.obj_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
+	stf->common.command_type = AUDPP_CMD_SIDECHAIN_TUNING_FILTER;
+
+	if (enable)
+		stf->active_flag = AUDPP_CMD_STF_FLAG_ENA;
+	else
+		stf->active_flag = AUDPP_CMD_STF_FLAG_DIS;
+	return audpp_send_queue3(stf,
+		sizeof(struct audpp_cmd_cfg_object_params_sidechain));
+}
+EXPORT_SYMBOL(audpp_dsp_set_stf);
+
+/* Implementation Of COPP + POPP */
+int audpp_dsp_set_eq(unsigned id, unsigned enable,
+		     struct audpp_cmd_cfg_object_params_eqalizer *eq,
+				enum obj_type objtype)
+{
+	struct audpp_cmd_cfg_object_params_eqalizer cmd;
+
+	if (objtype) {
+		if (id > 5) {
+			MM_ERR("Wrong POPP decoder id: %d\n", id);
+			return -EINVAL;
+		}
+	} else {
+		if (id > 3) {
+			MM_ERR("Wrong COPP decoder id: %d\n", id);
+			return -EINVAL;
+		}
+	}
+
+	memset(&cmd, 0, sizeof(cmd));
+	if (objtype)
+		cmd.common.stream = AUDPP_CMD_POPP_STREAM;
+	else
+		cmd.common.stream = AUDPP_CMD_COPP_STREAM;
+
+	cmd.common.stream_id = id;
+	cmd.common.obj_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
+	cmd.common.command_type = AUDPP_CMD_EQUALIZER;
+	if (enable) {
+		cmd.eq_flag = AUDPP_CMD_EQ_FLAG_ENA;
+		cmd.num_bands = eq->num_bands;
+		memcpy(&cmd.eq_coeff, &eq->eq_coeff, sizeof(eq->eq_coeff));
+	} else
+		cmd.eq_flag = AUDPP_CMD_EQ_FLAG_DIS;
+
+	return audpp_send_queue3(&cmd, sizeof(cmd));
+}
+EXPORT_SYMBOL(audpp_dsp_set_eq);
+
+int audpp_dsp_set_vol_pan(unsigned id,
+			  struct audpp_cmd_cfg_object_params_volume *vol_pan,
+					enum obj_type objtype)
+{
+	struct audpp_cmd_cfg_object_params_volume cmd;
+
+	if (objtype) {
+		if (id > 5) {
+			MM_ERR("Wrong POPP decoder id: %d\n", id);
+			return -EINVAL;
+		}
+	} else {
+		if (id > AUDPP_MAX_COPP_DEVICES) {
+			MM_ERR("Wrong COPP decoder id: %d\n", id);
+			return -EINVAL;
+		}
+	}
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_OBJECT_PARAMS;
+	if (objtype)
+		cmd.common.stream = AUDPP_CMD_POPP_STREAM;
+	else
+		cmd.common.stream = AUDPP_CMD_COPP_STREAM;
+
+	cmd.common.stream_id = id;
+	cmd.common.obj_cfg = AUDPP_CMD_CFG_OBJ_UPDATE;
+	cmd.common.command_type = AUDPP_CMD_VOLUME_PAN;
+
+	cmd.volume = vol_pan->volume;
+	cmd.pan = vol_pan->pan;
+
+	return audpp_send_queue3(&cmd, sizeof(cmd));
+}
+EXPORT_SYMBOL(audpp_dsp_set_vol_pan);
+
+int audpp_pause(unsigned id, int pause)
+{
+	/* pause 1 = pause 0 = resume */
+	u16 pause_cmd[AUDPP_CMD_DEC_CTRL_LEN / sizeof(unsigned short)];
+
+	if (id >= CH_COUNT)
+		return -EINVAL;
+
+	memset(pause_cmd, 0, sizeof(pause_cmd));
+
+	pause_cmd[0] = AUDPP_CMD_DEC_CTRL;
+	pause_cmd[1] = id;
+	if (pause == 1)
+		pause_cmd[2] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_PAUSE_V;
+	else if (pause == 0)
+		pause_cmd[2] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_RESUME_V;
+	else
+		return -EINVAL;
+
+	return audpp_send_queue1(pause_cmd, sizeof(pause_cmd));
+}
+EXPORT_SYMBOL(audpp_pause);
+
+int audpp_flush(unsigned id)
+{
+	u16 flush_cmd[AUDPP_CMD_DEC_CTRL_LEN / sizeof(unsigned short)];
+
+	if (id >= CH_COUNT)
+		return -EINVAL;
+
+	memset(flush_cmd, 0, sizeof(flush_cmd));
+
+	flush_cmd[0] = AUDPP_CMD_DEC_CTRL;
+	flush_cmd[1] = id;
+	flush_cmd[2] = AUDPP_CMD_UPDATE_V | AUDPP_CMD_FLUSH_V;
+
+	return audpp_send_queue1(flush_cmd, sizeof(flush_cmd));
+}
+EXPORT_SYMBOL(audpp_flush);
+
+/* dec_attrb = 7:0, 0 - No Decoder, else supported decoder *
+ * like mp3, aac, wma etc ... *
+ *           =  15:8, bit[8] = 1 - Tunnel, bit[9] = 1 - NonTunnel *
+ *           =  31:16, reserved */
+int audpp_adec_alloc(unsigned dec_attrb, const char **module_name,
+		     unsigned *queueid)
+{
+	struct audpp_state *audpp = &the_audpp_state;
+	int decid = -1, idx, lidx, mode, codec;
+	int codecs_supported, min_codecs_supported;
+	unsigned int *concurrency_entry;
+	u8 max_instance, codec_type;
+
+	struct dec_instance_table *dec_instance_list;
+	dec_instance_list = (struct dec_instance_table *)
+				(audpp->dec_database->dec_instance_list);
+
+	mutex_lock(audpp->lock_dec);
+	/* Represents in bit mask */
+	mode = ((dec_attrb & AUDPP_MODE_MASK) << 16);
+	codec = (1 << (dec_attrb & AUDPP_CODEC_MASK));
+	codec_type = (dec_attrb & AUDPP_CODEC_MASK);
+
+	/* Find  whether same/different codec instances are running */
+	audpp->decoder_count++;
+	audpp->codec_cnt[codec_type]++;
+	max_instance = 0;
+
+	/*if different instance of codec*/
+	if (audpp->codec_cnt[codec_type] < audpp->decoder_count) {
+		max_instance = audpp->codec_max_instances;
+		/* Get the maximum no. of instances that can be supported */
+		for (idx = 0; idx < MSM_MAX_DEC_CNT; idx++) {
+			if (audpp->codec_cnt[idx]) {
+				if ((dec_instance_list +
+					audpp->op_mode * MSM_MAX_DEC_CNT +
+						idx)->
+						max_instances_diff_dec <
+						max_instance) {
+						max_instance =
+						(dec_instance_list +
+							 audpp->op_mode *
+								MSM_MAX_DEC_CNT
+								+ idx)->
+							max_instances_diff_dec;
+				}
+			}
+		}
+		/* if different codec type, should not cross maximum other
+		   supported */
+		if (audpp->decoder_count > (max_instance + 1)) {
+			MM_ERR("Can not support, already reached max\n");
+			audpp->decoder_count--;
+			audpp->codec_cnt[codec_type]--;
+			goto done;
+		}
+		audpp->codec_max_instances = max_instance;
+		MM_DBG("different codec running\n");
+	} else {
+		max_instance = (dec_instance_list + audpp->op_mode *
+						MSM_MAX_DEC_CNT +
+						 codec_type)->
+							max_instances_same_dec;
+		/* if same codec type, should not cross maximum supported */
+		if (audpp->decoder_count > max_instance) {
+			MM_ERR("Can not support, already reached max\n");
+			audpp->decoder_count--;
+			audpp->codec_cnt[codec_type]--;
+			goto done;
+		}
+		audpp->codec_max_instances = max_instance;
+		MM_DBG("same codec running\n");
+	}
+
+	/* Point to Last entry of the row */
+	concurrency_entry = ((audpp->dec_database->dec_concurrency_table +
+			      ((audpp->concurrency + 1) *
+			       (audpp->dec_database->num_dec))) - 1);
+
+	lidx = audpp->dec_database->num_dec;
+	min_codecs_supported = sizeof(unsigned int) * 8;
+
+	MM_DBG("mode = 0x%08x codec = 0x%08x\n", mode, codec);
+
+	for (idx = lidx; idx > 0; idx--, concurrency_entry--) {
+		if (!(audpp->dec_inuse & (1 << (idx - 1)))) {
+			if (((mode & *concurrency_entry) == mode) &&
+			    (codec & *concurrency_entry)) {
+				/* Check supports minimum number codecs */
+				codecs_supported =
+				    audpp->dec_database->dec_info_list[idx -
+								       1].
+				    nr_codec_support;
+				if (codecs_supported < min_codecs_supported) {
+					lidx = idx - 1;
+					min_codecs_supported = codecs_supported;
+				}
+			}
+		}
+	}
+
+	if (lidx < audpp->dec_database->num_dec) {
+		audpp->dec_inuse |= (1 << lidx);
+		*module_name =
+		    audpp->dec_database->dec_info_list[lidx].module_name;
+		*queueid =
+		    audpp->dec_database->dec_info_list[lidx].module_queueid;
+		decid = audpp->dec_database->dec_info_list[lidx].module_decid;
+		audpp->dec_info_table[lidx].codec =
+		    (dec_attrb & AUDPP_CODEC_MASK);
+		audpp->dec_info_table[lidx].pid = current->pid;
+		/* point to row to get supported operation */
+		concurrency_entry =
+		    ((audpp->dec_database->dec_concurrency_table +
+		      ((audpp->concurrency) * (audpp->dec_database->num_dec))) +
+		     lidx);
+		decid |= ((*concurrency_entry & AUDPP_OP_MASK) >> 12);
+		MM_INFO("decid =0x%08x module_name=%s, queueid=%d \n", decid,
+				*module_name, *queueid);
+	}
+done:
+	mutex_unlock(audpp->lock_dec);
+	return decid;
+
+}
+EXPORT_SYMBOL(audpp_adec_alloc);
+
+void audpp_adec_free(int decid)
+{
+	struct audpp_state *audpp = &the_audpp_state;
+	int idx;
+	mutex_lock(audpp->lock_dec);
+	for (idx = audpp->dec_database->num_dec; idx > 0; idx--) {
+		if (audpp->dec_database->dec_info_list[idx - 1].module_decid ==
+		    decid) {
+			audpp->decoder_count--;
+			audpp->\
+			codec_cnt[audpp->dec_info_table[idx - 1].codec]--;
+			audpp->dec_inuse &= ~(1 << (idx - 1));
+			audpp->dec_info_table[idx - 1].codec = -1;
+			audpp->dec_info_table[idx - 1].pid = 0;
+			MM_INFO("free decid =%d \n", decid);
+			break;
+		}
+	}
+	mutex_unlock(audpp->lock_dec);
+	return;
+
+}
+EXPORT_SYMBOL(audpp_adec_free);
+
+static ssize_t concurrency_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct audpp_state *audpp = &the_audpp_state;
+	int rc;
+	mutex_lock(audpp->lock_dec);
+	rc = sprintf(buf, "%ld\n", audpp->concurrency);
+	mutex_unlock(audpp->lock_dec);
+	return rc;
+}
+
+static ssize_t concurrency_store(struct device *dev,
+				 struct device_attribute *attr,
+				 const char *buf, size_t count)
+{
+	struct audpp_state *audpp = &the_audpp_state;
+	unsigned long concurrency;
+	int rc = -1;
+	mutex_lock(audpp->lock_dec);
+	if (audpp->dec_inuse) {
+		MM_ERR("Can not change profile, while playback in progress\n");
+		goto done;
+	}
+	rc = strict_strtoul(buf, 10, &concurrency);
+	if (!rc &&
+		(concurrency < audpp->dec_database->num_concurrency_support)) {
+		audpp->concurrency = concurrency;
+		MM_DBG("Concurrency case %ld\n", audpp->concurrency);
+		rc = count;
+	} else {
+		MM_ERR("Not a valid Concurrency case\n");
+		rc = -EINVAL;
+	}
+done:
+	mutex_unlock(audpp->lock_dec);
+	return rc;
+}
+
+static ssize_t decoder_info_show(struct device *dev,
+				 struct device_attribute *attr, char *buf);
+static struct device_attribute dev_attr_decoder[AUDPP_MAX_DECODER_CNT] = {
+	__ATTR(decoder0, S_IRUGO, decoder_info_show, NULL),
+	__ATTR(decoder1, S_IRUGO, decoder_info_show, NULL),
+	__ATTR(decoder2, S_IRUGO, decoder_info_show, NULL),
+	__ATTR(decoder3, S_IRUGO, decoder_info_show, NULL),
+	__ATTR(decoder4, S_IRUGO, decoder_info_show, NULL),
+};
+
+static ssize_t decoder_info_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	int cpy_sz = 0;
+	struct audpp_state *audpp = &the_audpp_state;
+	const ptrdiff_t off = attr - dev_attr_decoder;	/* decoder number */
+	mutex_lock(audpp->lock_dec);
+	cpy_sz += scnprintf(buf + cpy_sz, PAGE_SIZE - cpy_sz, "%d:",
+			    audpp->dec_info_table[off].codec);
+	cpy_sz += scnprintf(buf + cpy_sz, PAGE_SIZE - cpy_sz, "%d\n",
+			    audpp->dec_info_table[off].pid);
+	mutex_unlock(audpp->lock_dec);
+	return cpy_sz;
+}
+
+static DEVICE_ATTR(concurrency, S_IWUSR | S_IRUGO, concurrency_show,
+	    concurrency_store);
+static int audpp_probe(struct platform_device *pdev)
+{
+	int rc, idx;
+	struct audpp_state *audpp = &the_audpp_state;
+	audpp->concurrency = AUDPP_CONCURRENCY_DEFAULT;
+	audpp->dec_database =
+	    (struct msm_adspdec_database *)pdev->dev.platform_data;
+
+	MM_INFO("Number of decoder supported  %d\n",
+		audpp->dec_database->num_dec);
+	MM_INFO("Number of concurrency supported  %d\n",
+		audpp->dec_database->num_concurrency_support);
+	init_waitqueue_head(&audpp->event_wait);
+	for (idx = 0; idx < audpp->dec_database->num_dec; idx++) {
+		audpp->dec_info_table[idx].codec = -1;
+		audpp->dec_info_table[idx].pid = 0;
+		MM_INFO("module_name:%s\n",
+			audpp->dec_database->dec_info_list[idx].module_name);
+		MM_INFO("queueid:%d\n",
+			audpp->dec_database->dec_info_list[idx].module_queueid);
+		MM_INFO("decid:%d\n",
+			audpp->dec_database->dec_info_list[idx].module_decid);
+		MM_INFO("nr_codec_support:%d\n",
+			audpp->dec_database->dec_info_list[idx].
+			nr_codec_support);
+	}
+
+	wake_lock_init(&audpp_wake_lock, WAKE_LOCK_SUSPEND, "audpp");
+	for (idx = 0; idx < audpp->dec_database->num_dec; idx++) {
+		rc = device_create_file(&pdev->dev, &dev_attr_decoder[idx]);
+		if (rc)
+			goto err;
+	}
+	rc = device_create_file(&pdev->dev, &dev_attr_concurrency);
+	audpp->op_mode = 0; /* Consider as non turbo mode */
+	if (rc)
+		goto err;
+	else
+		goto done;
+err:
+	while (idx--)
+		device_remove_file(&pdev->dev, &dev_attr_decoder[idx]);
+done:
+	return rc;
+}
+
+static struct platform_driver audpp_plat_driver = {
+	.probe = audpp_probe,
+	.driver = {
+		   .name = "msm_adspdec",
+		   .owner = THIS_MODULE,
+		   },
+};
+
+static int __init audpp_init(void)
+{
+	return platform_driver_register(&audpp_plat_driver);
+}
+
+device_initcall(audpp_init);
diff --git a/arch/arm/mach-msm/qdsp5v2/audpreproc.c b/arch/arm/mach-msm/qdsp5v2/audpreproc.c
new file mode 100644
index 0000000..09611a5
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/audpreproc.c
@@ -0,0 +1,523 @@
+/*
+ * Common code to deal with the AUDPREPROC dsp task (audio preprocessing)
+ *
+ * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * Based on the audpp layer in arch/arm/mach-msm/qdsp5/audpp.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/wakelock.h>
+#include <mach/msm_adsp.h>
+#include <mach/qdsp5v2/audio_acdbi.h>
+#include <mach/qdsp5v2/audpreproc.h>
+#include <mach/debug_mm.h>
+#include <mach/qdsp5v2/qdsp5audpreprocmsg.h>
+
+static DEFINE_MUTEX(audpreproc_lock);
+static struct wake_lock audpre_wake_lock;
+static struct wake_lock audpre_idle_wake_lock;
+
+struct msm_adspenc_info {
+	const char *module_name;
+	unsigned module_queueids;
+	int module_encid; /* streamid */
+	int enc_formats; /* supported formats */
+	int nr_codec_support; /* number of codec suported */
+};
+
+#define ENC_MODULE_INFO(name, queueids, encid, formats, nr_codec) \
+	{.module_name = name, .module_queueids = queueids, \
+	 .module_encid = encid, .enc_formats = formats, \
+	 .nr_codec_support = nr_codec }
+
+#define MAX_EVENT_CALLBACK_CLIENTS 1
+
+#define ENC0_FORMAT ((1<<MSM_ADSP_ENC_CODEC_WAV)| \
+	(1<<MSM_ADSP_ENC_CODEC_SBC) | (1<<MSM_ADSP_ENC_CODEC_EXT_WAV))
+
+#define ENC1_FORMAT ((1<<MSM_ADSP_ENC_CODEC_WAV)| \
+	(1<<MSM_ADSP_ENC_CODEC_AAC) | (1<<MSM_ADSP_ENC_CODEC_AMRNB) | \
+	(1<<MSM_ADSP_ENC_CODEC_EVRC) | (1<<MSM_ADSP_ENC_CODEC_QCELP) | \
+	(1<<MSM_ADSP_ENC_CODEC_EXT_WAV))
+
+#define ENC2_FORMAT ((1<<MSM_ADSP_ENC_CODEC_WAV) | \
+	(1<<MSM_ADSP_ENC_CODEC_EXT_WAV))
+
+struct msm_adspenc_database {
+	unsigned num_enc;
+	struct msm_adspenc_info *enc_info_list;
+};
+
+static struct msm_adspenc_info enc_info_list[] = {
+	ENC_MODULE_INFO("AUDREC0TASK", \
+			((QDSP_uPAudRec0BitStreamQueue << 16)| \
+			   QDSP_uPAudRec0CmdQueue), 0, \
+			 (ENC0_FORMAT  | (1 << MSM_ADSP_ENC_MODE_TUNNEL)), 3),
+
+	ENC_MODULE_INFO("AUDREC1TASK", \
+			 ((QDSP_uPAudRec1BitStreamQueue << 16)| \
+			   QDSP_uPAudRec1CmdQueue), 1, \
+			 (ENC1_FORMAT | (1 << MSM_ADSP_ENC_MODE_TUNNEL) | \
+			  (1 << MSM_ADSP_ENC_MODE_NON_TUNNEL)), 6),
+
+	ENC_MODULE_INFO("AUDREC2TASK", \
+			 ((QDSP_uPAudRec2BitStreamQueue << 16)| \
+			   QDSP_uPAudRec2CmdQueue), 2, \
+			 (ENC2_FORMAT  | (1 << MSM_ADSP_ENC_MODE_TUNNEL)), 2),
+
+};
+
+static struct msm_adspenc_database msm_enc_database = {
+	.num_enc = ARRAY_SIZE(enc_info_list),
+	.enc_info_list = enc_info_list,
+};
+
+
+static struct audrec_session_info
+		session_info[MAX_ENC_COUNT] = { {0, 0}, {0, 0}, {0, 0} };
+
+struct audpreproc_state {
+	struct msm_adsp_module *mod;
+	audpreproc_event_func func[MAX_ENC_COUNT];
+	void *private[MAX_ENC_COUNT];
+	struct mutex *lock;
+	unsigned open_count;
+	unsigned enc_inuse;
+	struct audpreproc_event_callback *cb_tbl[MAX_EVENT_CALLBACK_CLIENTS];
+};
+
+static struct audpreproc_state the_audpreproc_state = {
+	.lock = &audpreproc_lock,
+};
+
+static inline void prevent_suspend(void)
+{
+	wake_lock(&audpre_wake_lock);
+	wake_lock(&audpre_idle_wake_lock);
+}
+static inline void allow_suspend(void)
+{
+	wake_unlock(&audpre_wake_lock);
+	wake_unlock(&audpre_idle_wake_lock);
+}
+
+/* DSP preproc event handler */
+static void audpreproc_dsp_event(void *data, unsigned id, size_t len,
+			    void (*getevent)(void *ptr, size_t len))
+{
+	struct audpreproc_state *audpreproc = data;
+	int n = 0;
+
+	switch (id) {
+	case AUDPREPROC_CMD_CFG_DONE_MSG: {
+		struct audpreproc_cmd_cfg_done_msg cfg_done_msg;
+
+		getevent(&cfg_done_msg, AUDPREPROC_CMD_CFG_DONE_MSG_LEN);
+		MM_DBG("AUDPREPROC_CMD_CFG_DONE_MSG: stream id %d preproc \
+			type %x\n", cfg_done_msg.stream_id, \
+			cfg_done_msg.aud_preproc_type);
+		if ((cfg_done_msg.stream_id < MAX_ENC_COUNT) &&
+				audpreproc->func[cfg_done_msg.stream_id])
+			audpreproc->func[cfg_done_msg.stream_id](
+			audpreproc->private[cfg_done_msg.stream_id], id,
+			&cfg_done_msg);
+		break;
+	}
+	case AUDPREPROC_ERROR_MSG: {
+		struct audpreproc_err_msg err_msg;
+
+		getevent(&err_msg, AUDPREPROC_ERROR_MSG_LEN);
+		MM_DBG("AUDPREPROC_ERROR_MSG: stream id %d err idx %d\n",
+		err_msg.stream_id, err_msg.aud_preproc_err_idx);
+		if ((err_msg.stream_id < MAX_ENC_COUNT) &&
+				audpreproc->func[err_msg.stream_id])
+			audpreproc->func[err_msg.stream_id](
+			audpreproc->private[err_msg.stream_id], id,
+			&err_msg);
+		break;
+	}
+	case AUDPREPROC_CMD_ENC_CFG_DONE_MSG: {
+		struct audpreproc_cmd_enc_cfg_done_msg enc_cfg_msg;
+
+		getevent(&enc_cfg_msg, AUDPREPROC_CMD_ENC_CFG_DONE_MSG_LEN);
+		MM_DBG("AUDPREPROC_CMD_ENC_CFG_DONE_MSG: stream id %d enc type \
+			%d\n", enc_cfg_msg.stream_id, enc_cfg_msg.rec_enc_type);
+		if ((enc_cfg_msg.stream_id < MAX_ENC_COUNT) &&
+				audpreproc->func[enc_cfg_msg.stream_id])
+			audpreproc->func[enc_cfg_msg.stream_id](
+			audpreproc->private[enc_cfg_msg.stream_id], id,
+			&enc_cfg_msg);
+		for (n = 0; n < MAX_EVENT_CALLBACK_CLIENTS; ++n) {
+			if (audpreproc->cb_tbl[n] &&
+					audpreproc->cb_tbl[n]->fn) {
+				audpreproc->cb_tbl[n]->fn( \
+					audpreproc->cb_tbl[n]->private, \
+					id, (void *) &enc_cfg_msg);
+			}
+		}
+		break;
+	}
+	case AUDPREPROC_CMD_ENC_PARAM_CFG_DONE_MSG: {
+		struct audpreproc_cmd_enc_param_cfg_done_msg enc_param_msg;
+
+		getevent(&enc_param_msg,
+				AUDPREPROC_CMD_ENC_PARAM_CFG_DONE_MSG_LEN);
+		MM_DBG("AUDPREPROC_CMD_ENC_PARAM_CFG_DONE_MSG: stream id %d\n",
+				 enc_param_msg.stream_id);
+		if ((enc_param_msg.stream_id < MAX_ENC_COUNT) &&
+				audpreproc->func[enc_param_msg.stream_id])
+			audpreproc->func[enc_param_msg.stream_id](
+			audpreproc->private[enc_param_msg.stream_id], id,
+			&enc_param_msg);
+		break;
+	}
+	case AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG: {
+		struct audpreproc_afe_cmd_audio_record_cfg_done
+						record_cfg_done;
+		getevent(&record_cfg_done,
+			AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG_LEN);
+		MM_DBG("AUDPREPROC_AFE_CMD_AUDIO_RECORD_CFG_DONE_MSG: \
+			stream id %d\n", record_cfg_done.stream_id);
+		if ((record_cfg_done.stream_id < MAX_ENC_COUNT) &&
+				audpreproc->func[record_cfg_done.stream_id])
+			audpreproc->func[record_cfg_done.stream_id](
+			audpreproc->private[record_cfg_done.stream_id], id,
+			&record_cfg_done);
+		break;
+	}
+	case AUDPREPROC_CMD_ROUTING_MODE_DONE_MSG: {
+		struct audpreproc_cmd_routing_mode_done  routing_mode_done;
+
+		getevent(&routing_mode_done,
+			AUDPREPROC_CMD_ROUTING_MODE_DONE_MSG_LEN);
+		MM_DBG("AUDPREPROC_CMD_ROUTING_MODE_DONE_MSG: \
+			stream id %d\n", routing_mode_done.stream_id);
+		if ((routing_mode_done.stream_id < MAX_ENC_COUNT) &&
+				audpreproc->func[routing_mode_done.stream_id])
+			audpreproc->func[routing_mode_done.stream_id](
+			audpreproc->private[routing_mode_done.stream_id], id,
+			&routing_mode_done);
+		break;
+	}
+#ifdef CONFIG_DEBUG_FS
+	case AUDPREPROC_MSG_FEAT_QUERY_DM_DONE:
+	   {
+	    uint16_t msg[3];
+	    getevent(msg, sizeof(msg));
+	    MM_INFO("RTC ACK --> %x %x %x\n", msg[0], msg[1], msg[2]);
+	    acdb_rtc_set_err(msg[2]);
+	   }
+	break;
+#endif
+	case ADSP_MESSAGE_ID: {
+		MM_DBG("Received ADSP event:module audpreproctask\n");
+		break;
+	}
+	default:
+		MM_ERR("Unknown Event %d\n", id);
+	}
+	return;
+}
+
+static struct msm_adsp_ops adsp_ops = {
+	.event = audpreproc_dsp_event,
+};
+
+/* EXPORTED API's */
+int audpreproc_enable(int enc_id, audpreproc_event_func func, void *private)
+{
+	struct audpreproc_state *audpreproc = &the_audpreproc_state;
+	int res = 0;
+
+	if (enc_id < 0 || enc_id > (MAX_ENC_COUNT - 1))
+		return -EINVAL;
+
+	mutex_lock(audpreproc->lock);
+	if (audpreproc->func[enc_id]) {
+		res = -EBUSY;
+		goto out;
+	}
+
+	audpreproc->func[enc_id] = func;
+	audpreproc->private[enc_id] = private;
+
+	/* First client to enable preproc task */
+	if (audpreproc->open_count++ == 0) {
+		MM_DBG("Get AUDPREPROCTASK\n");
+		res = msm_adsp_get("AUDPREPROCTASK", &audpreproc->mod,
+				&adsp_ops, audpreproc);
+		if (res < 0) {
+			MM_ERR("Can not get AUDPREPROCTASK\n");
+			audpreproc->open_count = 0;
+			audpreproc->func[enc_id] = NULL;
+			audpreproc->private[enc_id] = NULL;
+			goto out;
+		}
+		prevent_suspend();
+		if (msm_adsp_enable(audpreproc->mod)) {
+			MM_ERR("Can not enable AUDPREPROCTASK\n");
+			audpreproc->open_count = 0;
+			audpreproc->func[enc_id] = NULL;
+			audpreproc->private[enc_id] = NULL;
+			msm_adsp_put(audpreproc->mod);
+			audpreproc->mod = NULL;
+			res = -ENODEV;
+			allow_suspend();
+			goto out;
+		}
+	}
+	res = 0;
+out:
+	mutex_unlock(audpreproc->lock);
+	return res;
+}
+EXPORT_SYMBOL(audpreproc_enable);
+
+int audpreproc_update_audrec_info(
+			struct audrec_session_info *audrec_session_info)
+{
+	if (!audrec_session_info) {
+		MM_ERR("error in audrec session info address\n");
+		return -EINVAL;
+	}
+	if (audrec_session_info->session_id < MAX_ENC_COUNT) {
+		memcpy(&session_info[audrec_session_info->session_id],
+				audrec_session_info,
+				sizeof(struct audrec_session_info));
+		return 0;
+	}
+	return -EINVAL;
+}
+EXPORT_SYMBOL(audpreproc_update_audrec_info);
+
+void audpreproc_disable(int enc_id, void *private)
+{
+	struct audpreproc_state *audpreproc = &the_audpreproc_state;
+
+	if (enc_id < 0 || enc_id > (MAX_ENC_COUNT - 1))
+		return;
+
+	mutex_lock(audpreproc->lock);
+	if (!audpreproc->func[enc_id])
+		goto out;
+	if (audpreproc->private[enc_id] != private)
+		goto out;
+
+	audpreproc->func[enc_id] = NULL;
+	audpreproc->private[enc_id] = NULL;
+
+	/* Last client then disable preproc task */
+	if (--audpreproc->open_count == 0) {
+		msm_adsp_disable(audpreproc->mod);
+		MM_DBG("Put AUDPREPROCTASK\n");
+		msm_adsp_put(audpreproc->mod);
+		audpreproc->mod = NULL;
+		allow_suspend();
+	}
+out:
+	mutex_unlock(audpreproc->lock);
+	return;
+}
+EXPORT_SYMBOL(audpreproc_disable);
+
+
+int audpreproc_register_event_callback(struct audpreproc_event_callback *ecb)
+{
+	struct audpreproc_state *audpreproc = &the_audpreproc_state;
+	int i;
+
+	for (i = 0; i < MAX_EVENT_CALLBACK_CLIENTS; ++i) {
+		if (NULL == audpreproc->cb_tbl[i]) {
+			audpreproc->cb_tbl[i] = ecb;
+			return 0;
+		}
+	}
+	return -1;
+}
+EXPORT_SYMBOL(audpreproc_register_event_callback);
+
+int audpreproc_unregister_event_callback(struct audpreproc_event_callback *ecb)
+{
+	struct audpreproc_state *audpreproc = &the_audpreproc_state;
+	int i;
+
+	for (i = 0; i < MAX_EVENT_CALLBACK_CLIENTS; ++i) {
+		if (ecb == audpreproc->cb_tbl[i]) {
+			audpreproc->cb_tbl[i] = NULL;
+			return 0;
+		}
+	}
+	return -1;
+}
+EXPORT_SYMBOL(audpreproc_unregister_event_callback);
+
+
+/* enc_type = supported encode format *
+ * like pcm, aac, sbc, evrc, qcelp, amrnb etc ... *
+ */
+int audpreproc_aenc_alloc(unsigned enc_type, const char **module_name,
+		     unsigned *queue_ids)
+{
+	struct audpreproc_state *audpreproc = &the_audpreproc_state;
+	int encid = -1, idx, lidx, mode, codec;
+	int codecs_supported, min_codecs_supported;
+	static int wakelock_init;
+
+	mutex_lock(audpreproc->lock);
+	/* Represents in bit mask */
+	mode = ((enc_type & AUDPREPROC_MODE_MASK) << 16);
+	codec = (1 << (enc_type & AUDPREPROC_CODEC_MASK));
+
+	lidx = msm_enc_database.num_enc;
+	min_codecs_supported = sizeof(unsigned int) * 8;
+	MM_DBG("mode = 0x%08x codec = 0x%08x\n", mode, codec);
+
+	for (idx = lidx-1; idx >= 0; idx--) {
+		/* encoder free and supports the format */
+		if (!(audpreproc->enc_inuse & (1 << (idx))) &&
+		((mode & msm_enc_database.enc_info_list[idx].enc_formats)
+		== mode) && ((codec &
+		msm_enc_database.enc_info_list[idx].enc_formats)
+		== codec)){
+			/* Check supports minimum number codecs */
+			codecs_supported =
+			msm_enc_database.enc_info_list[idx].nr_codec_support;
+			if (codecs_supported < min_codecs_supported) {
+				lidx = idx;
+				min_codecs_supported = codecs_supported;
+			}
+		}
+	}
+
+	if (lidx < msm_enc_database.num_enc) {
+		audpreproc->enc_inuse |= (1 << lidx);
+		*module_name =
+		    msm_enc_database.enc_info_list[lidx].module_name;
+		*queue_ids =
+		    msm_enc_database.enc_info_list[lidx].module_queueids;
+		encid = msm_enc_database.enc_info_list[lidx].module_encid;
+	}
+
+	if (!wakelock_init) {
+		wake_lock_init(&audpre_wake_lock, WAKE_LOCK_SUSPEND, "audpre");
+		wake_lock_init(&audpre_idle_wake_lock, WAKE_LOCK_IDLE,
+				"audpre_idle");
+		wakelock_init = 1;
+	}
+
+	mutex_unlock(audpreproc->lock);
+	return encid;
+}
+EXPORT_SYMBOL(audpreproc_aenc_alloc);
+
+void audpreproc_aenc_free(int enc_id)
+{
+	struct audpreproc_state *audpreproc = &the_audpreproc_state;
+	int idx;
+
+	mutex_lock(audpreproc->lock);
+	for (idx = 0; idx < msm_enc_database.num_enc; idx++) {
+		if (msm_enc_database.enc_info_list[idx].module_encid ==
+		    enc_id) {
+			audpreproc->enc_inuse &= ~(1 << idx);
+			break;
+		}
+	}
+	mutex_unlock(audpreproc->lock);
+	return;
+
+}
+EXPORT_SYMBOL(audpreproc_aenc_free);
+
+int audpreproc_send_preproccmdqueue(void *cmd, unsigned len)
+{
+	return msm_adsp_write(the_audpreproc_state.mod,
+				QDSP_uPAudPreProcCmdQueue, cmd, len);
+}
+EXPORT_SYMBOL(audpreproc_send_preproccmdqueue);
+
+int audpreproc_send_audreccmdqueue(void *cmd, unsigned len)
+{
+	return msm_adsp_write(the_audpreproc_state.mod,
+			      QDSP_uPAudPreProcAudRecCmdQueue, cmd, len);
+}
+EXPORT_SYMBOL(audpreproc_send_audreccmdqueue);
+
+int audpreproc_send_audrec2cmdqueue(void *cmd, unsigned len)
+{
+	return msm_adsp_write(the_audpreproc_state.mod,
+			      QDSP_uPAudRec2CmdQueue, cmd, len);
+}
+EXPORT_SYMBOL(audpreproc_send_audrec2cmdqueue);
+
+int audpreproc_dsp_set_agc(struct audpreproc_cmd_cfg_agc_params *agc,
+				unsigned len)
+{
+	return msm_adsp_write(the_audpreproc_state.mod,
+				QDSP_uPAudPreProcCmdQueue, agc, len);
+}
+EXPORT_SYMBOL(audpreproc_dsp_set_agc);
+
+int audpreproc_dsp_set_agc2(struct audpreproc_cmd_cfg_agc_params_2 *agc2,
+				unsigned len)
+{
+	return msm_adsp_write(the_audpreproc_state.mod,
+				QDSP_uPAudPreProcCmdQueue, agc2, len);
+}
+EXPORT_SYMBOL(audpreproc_dsp_set_agc2);
+
+int audpreproc_dsp_set_ns(struct audpreproc_cmd_cfg_ns_params *ns,
+				unsigned len)
+{
+	return msm_adsp_write(the_audpreproc_state.mod,
+				QDSP_uPAudPreProcCmdQueue, ns, len);
+}
+EXPORT_SYMBOL(audpreproc_dsp_set_ns);
+
+int audpreproc_dsp_set_iir(
+struct audpreproc_cmd_cfg_iir_tuning_filter_params *iir, unsigned len)
+{
+	return msm_adsp_write(the_audpreproc_state.mod,
+				QDSP_uPAudPreProcCmdQueue, iir, len);
+}
+EXPORT_SYMBOL(audpreproc_dsp_set_iir);
+
+int audpreproc_dsp_set_gain_tx(
+		struct audpreproc_cmd_cfg_cal_gain *calib_gain_tx, unsigned len)
+{
+	return msm_adsp_write(the_audpreproc_state.mod,
+			QDSP_uPAudPreProcCmdQueue, calib_gain_tx, len);
+}
+EXPORT_SYMBOL(audpreproc_dsp_set_gain_tx);
+
+void get_audrec_session_info(int id, struct audrec_session_info *info)
+{
+	if (id >= MAX_ENC_COUNT) {
+		MM_ERR("invalid session id = %d\n", id);
+		return;
+	}
+	memcpy(info, &session_info[id], sizeof(struct audrec_session_info));
+}
+EXPORT_SYMBOL(get_audrec_session_info);
+
+int audpreproc_dsp_set_lvnv(
+	struct audpreproc_cmd_cfg_lvnv_param *preproc_lvnv, unsigned len)
+{
+	return msm_adsp_write(the_audpreproc_state.mod,
+		QDSP_uPAudPreProcCmdQueue, preproc_lvnv, len);
+}
+EXPORT_SYMBOL(audpreproc_dsp_set_lvnv);
+
diff --git a/arch/arm/mach-msm/qdsp5v2/aux_pcm.c b/arch/arm/mach-msm/qdsp5v2/aux_pcm.c
new file mode 100644
index 0000000..4cc834d
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/aux_pcm.c
@@ -0,0 +1,280 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <mach/qdsp5v2/aux_pcm.h>
+#include <linux/delay.h>
+#include <mach/debug_mm.h>
+
+/*----------------------------------------------------------------------------
+ * Preprocessor Definitions and Constants
+ * -------------------------------------------------------------------------*/
+
+/* define offset of registers here, may put them into platform data */
+#define AUX_CODEC_CTL_OFFSET 0x00
+#define PCM_PATH_CTL_OFFSET 0x04
+#define AUX_CODEC_CTL_OUT_OFFSET 0x08
+
+/* define some bit values in PCM_PATH_CTL register */
+#define PCM_PATH_CTL__ADSP_CTL_EN_BMSK 0x8
+
+/* mask and shift */
+#define AUX_CODEC_CTL_ADSP_CODEC_CTL_EN_BMSK 0x800
+#define AUX_CODEC_CTL_PCM_SYNC_LONG_BMSK 0x400
+#define AUX_CODEC_CTL_PCM_SYNC_SHORT_BMSK 0x200
+#define AUX_CODEC_CTL_I2S_SAMPLE_CLK_SRC_BMSK 0x80
+#define AUX_CODEC_CTL_I2S_SAMPLE_CLK_MODE_BMSK 0x40
+#define AUX_CODEC_CTL_I2S_RX_MODE_BMSK 0x20
+#define AUX_CODEC_CTL_I2S_CLK_MODE_BMSK 0x10
+#define AUX_CODEC_CTL_AUX_PCM_MODE_BMSK 0x0b
+#define AUX_CODEC_CTL_AUX_CODEC_MODE_BMSK 0x02
+
+/* AUX PCM MODE */
+#define MASTER_PRIM_PCM_SHORT 0
+#define MASTER_AUX_PCM_LONG 1
+#define SLAVE_PRIM_PCM_SHORT 2
+
+struct aux_pcm_state {
+	void __iomem *aux_pcm_base;  /* configure aux pcm through Scorpion */
+	int     dout;
+	int     din;
+	int     syncout;
+	int     clkin_a;
+};
+
+static struct aux_pcm_state the_aux_pcm_state;
+
+static void __iomem *get_base_addr(struct aux_pcm_state *aux_pcm)
+{
+	return aux_pcm->aux_pcm_base;
+}
+
+/* Set who control aux pcm : adsp or MSM */
+void aux_codec_adsp_codec_ctl_en(bool msm_adsp_en)
+{
+	void __iomem *baddr = get_base_addr(&the_aux_pcm_state);
+	uint32_t val;
+
+	if (!IS_ERR(baddr)) {
+		val = readl(baddr + AUX_CODEC_CTL_OFFSET);
+		if (msm_adsp_en) { /* adsp */
+			writel(
+			((val & ~AUX_CODEC_CTL_ADSP_CODEC_CTL_EN_BMSK) |
+			AUX_CODEC_CTL__ADSP_CODEC_CTL_EN__ADSP_V),
+			baddr + AUX_CODEC_CTL_OFFSET);
+		} else { /* MSM */
+			writel(
+			((val & ~AUX_CODEC_CTL_ADSP_CODEC_CTL_EN_BMSK) |
+			AUX_CODEC_CTL__ADSP_CODEC_CTL_EN__MSM_V),
+			baddr + AUX_CODEC_CTL_OFFSET);
+		}
+	}
+	mb();
+}
+
+/* Set who control aux pcm path: adsp or MSM */
+void aux_codec_pcm_path_ctl_en(bool msm_adsp_en)
+{
+	void __iomem *baddr = get_base_addr(&the_aux_pcm_state);
+	uint32_t val;
+
+	 if (!IS_ERR(baddr)) {
+		val = readl(baddr + PCM_PATH_CTL_OFFSET);
+		if (msm_adsp_en) { /* adsp */
+			writel(
+			((val & ~PCM_PATH_CTL__ADSP_CTL_EN_BMSK) |
+			PCM_PATH_CTL__ADSP_CTL_EN__ADSP_V),
+			baddr + PCM_PATH_CTL_OFFSET);
+		} else { /* MSM */
+			writel(
+			((val & ~PCM_PATH_CTL__ADSP_CTL_EN_BMSK) |
+			PCM_PATH_CTL__ADSP_CTL_EN__MSM_V),
+			baddr + PCM_PATH_CTL_OFFSET);
+		}
+	}
+	mb();
+	return;
+}
+EXPORT_SYMBOL(aux_codec_pcm_path_ctl_en);
+
+int aux_pcm_gpios_request(void)
+{
+	int rc = 0;
+
+	MM_DBG("aux_pcm_gpios_request\n");
+	rc = gpio_request(the_aux_pcm_state.dout, "AUX PCM DOUT");
+	if (rc) {
+		MM_ERR("GPIO request for AUX PCM DOUT failed\n");
+		return rc;
+	}
+
+	rc = gpio_request(the_aux_pcm_state.din, "AUX PCM DIN");
+	if (rc) {
+		MM_ERR("GPIO request for AUX PCM DIN failed\n");
+		gpio_free(the_aux_pcm_state.dout);
+		return rc;
+	}
+
+	rc = gpio_request(the_aux_pcm_state.syncout, "AUX PCM SYNC OUT");
+	if (rc) {
+		MM_ERR("GPIO request for AUX PCM SYNC OUT failed\n");
+		gpio_free(the_aux_pcm_state.dout);
+		gpio_free(the_aux_pcm_state.din);
+		return rc;
+	}
+
+	rc = gpio_request(the_aux_pcm_state.clkin_a, "AUX PCM CLKIN A");
+	if (rc) {
+		MM_ERR("GPIO request for AUX PCM CLKIN A failed\n");
+		gpio_free(the_aux_pcm_state.dout);
+		gpio_free(the_aux_pcm_state.din);
+		gpio_free(the_aux_pcm_state.syncout);
+		return rc;
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL(aux_pcm_gpios_request);
+
+
+void aux_pcm_gpios_free(void)
+{
+	MM_DBG(" aux_pcm_gpios_free \n");
+
+	/*
+	 * Feed silence frames before close to prevent buzzing sound in BT at
+	 * call end. This fix is applicable only to Marimba BT.
+	 */
+	gpio_tlmm_config(GPIO_CFG(the_aux_pcm_state.dout, 0, GPIO_CFG_OUTPUT,
+		GPIO_CFG_NO_PULL, GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+	gpio_set_value(the_aux_pcm_state.dout, 0);
+	msleep(20);
+	gpio_tlmm_config(GPIO_CFG(the_aux_pcm_state.dout, 1, GPIO_CFG_OUTPUT,
+		GPIO_CFG_NO_PULL, GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+
+	gpio_free(the_aux_pcm_state.dout);
+	gpio_free(the_aux_pcm_state.din);
+	gpio_free(the_aux_pcm_state.syncout);
+	gpio_free(the_aux_pcm_state.clkin_a);
+}
+EXPORT_SYMBOL(aux_pcm_gpios_free);
+
+
+static int get_aux_pcm_gpios(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct resource         *res;
+
+	/* Claim all of the GPIOs. */
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO,
+					"aux_pcm_dout");
+	if  (!res) {
+		MM_ERR("%s: failed to get gpio AUX PCM DOUT\n", __func__);
+		return -ENODEV;
+	}
+
+	the_aux_pcm_state.dout = res->start;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO,
+					"aux_pcm_din");
+	if  (!res) {
+		MM_ERR("%s: failed to get gpio AUX PCM DIN\n", __func__);
+		return -ENODEV;
+	}
+
+	the_aux_pcm_state.din = res->start;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO,
+					"aux_pcm_syncout");
+	if  (!res) {
+		MM_ERR("%s: failed to get gpio AUX PCM SYNC OUT\n", __func__);
+		return -ENODEV;
+	}
+
+	the_aux_pcm_state.syncout = res->start;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO,
+					"aux_pcm_clkin_a");
+	if  (!res) {
+		MM_ERR("%s: failed to get gpio AUX PCM CLKIN A\n", __func__);
+		return -ENODEV;
+	}
+
+	the_aux_pcm_state.clkin_a = res->start;
+
+	return rc;
+}
+static int aux_pcm_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct resource *mem_src;
+
+	MM_DBG("aux_pcm_probe \n");
+	mem_src = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						"aux_codec_reg_addr");
+	if (!mem_src) {
+		rc = -ENODEV;
+		goto done;
+	}
+
+	the_aux_pcm_state.aux_pcm_base = ioremap(mem_src->start,
+		(mem_src->end - mem_src->start) + 1);
+	if (!the_aux_pcm_state.aux_pcm_base) {
+		rc = -ENOMEM;
+		goto done;
+	}
+	rc = get_aux_pcm_gpios(pdev);
+	if (rc) {
+		MM_ERR("GPIO configuration failed\n");
+		rc = -ENODEV;
+	}
+
+done:	return rc;
+
+}
+
+static int aux_pcm_remove(struct platform_device *pdev)
+{
+	iounmap(the_aux_pcm_state.aux_pcm_base);
+	return 0;
+}
+
+static struct platform_driver aux_pcm_driver = {
+	.probe = aux_pcm_probe,
+	.remove = aux_pcm_remove,
+	.driver = {
+		.name = "msm_aux_pcm",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init aux_pcm_init(void)
+{
+
+	return platform_driver_register(&aux_pcm_driver);
+}
+
+static void __exit aux_pcm_exit(void)
+{
+	platform_driver_unregister(&aux_pcm_driver);
+}
+
+module_init(aux_pcm_init);
+module_exit(aux_pcm_exit);
+
+MODULE_DESCRIPTION("MSM AUX PCM driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5v2/lpa.c b/arch/arm/mach-msm/qdsp5v2/lpa.c
new file mode 100644
index 0000000..c4e0fee
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/lpa.c
@@ -0,0 +1,608 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <mach/qdsp5v2/lpa.h>
+#include <mach/qdsp5v2/lpa_hw.h>
+#include <mach/qdsp5v2/msm_lpa.h>
+#include <mach/debug_mm.h>
+
+#define LPA_REG_WRITEL(drv, val, reg)  writel(val, drv->baseaddr + reg)
+#define LPA_REG_READL(drv, reg)  readl(drv->baseaddr + reg)
+
+/* bit 2:0 is reserved because watermarks have to be 64-bit aligned */
+#define LLB_WATERMARK_VAL_MASK 0x00000003
+
+#define LPA_STATUS_SBUF_EN 0x01
+
+struct lpa_drv {
+	void __iomem *baseaddr;
+	u32 obuf_hlb_size;
+	u32 dsp_proc_id;
+	u32 app_proc_id;
+	struct lpa_mem_config nosb_config;
+	struct lpa_mem_config sb_config;
+	u32 status;
+	u32 watermark_bytes;
+	u32 watermark_aheadtime;
+	u32 sample_boundary;
+};
+
+struct lpa_state {
+	struct lpa_drv lpa_drv; /* One instance for now */
+	u32 assigned;
+	struct mutex lpa_lock;
+};
+
+struct lpa_state the_lpa_state;
+
+static void lpa_enable_codec(struct lpa_drv *lpa, bool enable)
+{
+	u32 val;
+
+	val = LPA_REG_READL(lpa, LPA_OBUF_CODEC);
+	val = enable ? (val | LPA_OBUF_CODEC_CODEC_INTF_EN_BMSK) :
+		(val & ~LPA_OBUF_CODEC_CODEC_INTF_EN_BMSK);
+	val |= LPA_OBUF_CODEC_LOAD_BMSK;
+	LPA_REG_WRITEL(lpa, val, LPA_OBUF_CODEC);
+	mb();
+}
+
+static void lpa_reset(struct lpa_drv *lpa)
+{
+	u32 status;
+	struct clk *adsp_clk;
+	/* Need to make sure not disable clock while other device is enabled */
+	adsp_clk = clk_get(NULL, "adsp_clk");
+	if (!adsp_clk) {
+		MM_ERR("failed to get adsp clk\n");
+		goto error;
+	}
+	clk_enable(adsp_clk);
+	lpa_enable_codec(lpa, 0);
+	LPA_REG_WRITEL(lpa, (LPA_OBUF_RESETS_MISR_RESET |
+		LPA_OBUF_RESETS_OVERALL_RESET), LPA_OBUF_RESETS);
+	do {
+		status = LPA_REG_READL(lpa, LPA_OBUF_STATUS);
+	} while (!(status & LPA_OBUF_STATUS_RESET_DONE));
+
+	LPA_REG_WRITEL(lpa, LPA_OBUF_ACK_RESET_DONE_BMSK, LPA_OBUF_ACK);
+	mb();
+	clk_disable(adsp_clk);
+	clk_put(adsp_clk);
+error:
+	return;
+}
+
+static void lpa_config_hlb_addr(struct lpa_drv *lpa)
+{
+	u32 val, min_addr = 0, max_addr = min_addr + lpa->obuf_hlb_size;
+
+	val = (min_addr & LPA_OBUF_HLB_MIN_ADDR_SEG_BMSK) |
+	LPA_OBUF_HLB_MIN_ADDR_LOAD_BMSK;
+	LPA_REG_WRITEL(lpa, val, LPA_OBUF_HLB_MIN_ADDR);
+	val = max_addr & LPA_OBUF_HLB_MAX_ADDR_SEG_BMSK;
+	LPA_REG_WRITEL(lpa, val, LPA_OBUF_HLB_MAX_ADDR);
+}
+
+static void lpa_powerup_mem_bank(struct lpa_drv *lpa,
+	struct lpa_mem_bank_select *bank)
+{
+	u32 status, val;
+
+	status = LPA_REG_READL(lpa, LPA_OBUF_MEMORY_CONTROL);
+	val = ((*((u32 *) bank)) << LPA_OBUF_MEM_CTL_PWRUP_SHFT) &
+	LPA_OBUF_MEM_CTL_PWRUP_BMSK;
+	val |= status;
+	LPA_REG_WRITEL(lpa, val, LPA_OBUF_MEMORY_CONTROL);
+}
+
+static void lpa_enable_interrupt(struct lpa_drv *lpa, u32 proc_id)
+{
+	u32 val;
+
+	proc_id &= LPA_OBUF_INTR_EN_BMSK;
+	val = 0x1 << proc_id;
+	LPA_REG_WRITEL(lpa, val, LPA_OBUF_INTR_ENABLE);
+}
+
+static void lpa_config_llb_addr(struct lpa_drv *lpa, u32 min_addr, u32 max_addr)
+{
+	u32 val;
+
+	val = (min_addr & LPA_OBUF_LLB_MIN_ADDR_SEG_BMSK) |
+	LPA_OBUF_LLB_MIN_ADDR_LOAD_BMSK;
+	LPA_REG_WRITEL(lpa, val, LPA_OBUF_LLB_MIN_ADDR);
+	val = max_addr & LPA_OBUF_LLB_MAX_ADDR_SEG_BMSK;
+	LPA_REG_WRITEL(lpa, val, LPA_OBUF_LLB_MAX_ADDR);
+}
+
+static void lpa_config_sb_addr(struct lpa_drv *lpa, u32 min_addr, u32 max_addr)
+{
+	u32 val;
+
+	val = (min_addr & LPA_OBUF_SB_MIN_ADDR_SEG_BMSK) |
+	LPA_OBUF_SB_MIN_ADDR_LOAD_BMSK;
+	LPA_REG_WRITEL(lpa, val, LPA_OBUF_SB_MIN_ADDR);
+	val = max_addr & LPA_OBUF_SB_MAX_ADDR_SEG_BMSK;
+	LPA_REG_WRITEL(lpa, val, LPA_OBUF_SB_MAX_ADDR);
+}
+
+static void lpa_switch_sb(struct lpa_drv *lpa)
+{
+	if (lpa->status & LPA_STATUS_SBUF_EN) {
+		lpa_config_llb_addr(lpa, lpa->sb_config.llb_min_addr,
+		lpa->sb_config.llb_max_addr);
+		lpa_config_sb_addr(lpa, lpa->sb_config.sb_min_addr,
+		lpa->sb_config.sb_max_addr);
+	} else {
+		lpa_config_llb_addr(lpa, lpa->nosb_config.llb_min_addr,
+		lpa->nosb_config.llb_max_addr);
+		lpa_config_sb_addr(lpa, lpa->nosb_config.sb_min_addr,
+		lpa->nosb_config.sb_max_addr);
+	}
+}
+
+static u8 lpa_req_wmark_id(struct lpa_drv *lpa)
+{
+  return (u8) (LPA_REG_READL(lpa, LPA_OBUF_WMARK_ASSIGN) &
+	LPA_OBUF_WMARK_ASSIGN_BMSK);
+}
+
+static void lpa_enable_llb_wmark(struct lpa_drv *lpa, u32 wmark_ctrl,
+	u32 wmark_id, u32 cpu_id)
+{
+	u32 val;
+
+	wmark_id = (wmark_id > 3) ? 0 : wmark_id;
+	val = LPA_REG_READL(lpa, LPA_OBUF_WMARK_n_LLB_ADDR(wmark_id));
+	val &= ~LPA_OBUF_LLB_WMARK_CTRL_BMSK;
+	val &= ~LPA_OBUF_LLB_WMARK_MAP_BMSK;
+	val |= (wmark_ctrl << LPA_OBUF_LLB_WMARK_CTRL_SHFT) &
+	LPA_OBUF_LLB_WMARK_CTRL_BMSK;
+	val |= (cpu_id << LPA_OBUF_LLB_WMARK_MAP_SHFT) &
+	LPA_OBUF_LLB_WMARK_MAP_BMSK;
+	LPA_REG_WRITEL(lpa, val, LPA_OBUF_WMARK_n_LLB_ADDR(wmark_id));
+}
+
+static void lpa_enable_sb_wmark(struct lpa_drv *lpa, u32 wmark_ctrl,
+	u32 cpu_id)
+{
+	u32 val;
+
+	val = LPA_REG_READL(lpa, LPA_OBUF_WMARK_SB);
+	val &= ~LPA_OBUF_SB_WMARK_CTRL_BMSK;
+	val &= ~LPA_OBUF_SB_WMARK_MAP_BMSK;
+	val |= (wmark_ctrl << LPA_OBUF_SB_WMARK_CTRL_SHFT) &
+	LPA_OBUF_SB_WMARK_CTRL_BMSK;
+	val |= (cpu_id << LPA_OBUF_SB_WMARK_MAP_SHFT) &
+	LPA_OBUF_SB_WMARK_MAP_BMSK;
+	LPA_REG_WRITEL(lpa, val, LPA_OBUF_WMARK_SB);
+}
+static void lpa_enable_hlb_wmark(struct lpa_drv *lpa, u32 wmark_ctrl,
+	u32 cpu_id)
+{
+	u32 val;
+
+	val = LPA_REG_READL(lpa, LPA_OBUF_WMARK_HLB);
+	val &= ~LPA_OBUF_HLB_WMARK_CTRL_BMSK;
+	val &= ~LPA_OBUF_HLB_WMARK_MAP_BMSK;
+	val |= (wmark_ctrl << LPA_OBUF_HLB_WMARK_CTRL_SHFT) &
+	LPA_OBUF_HLB_WMARK_CTRL_BMSK;
+	val |= (cpu_id << LPA_OBUF_HLB_WMARK_MAP_SHFT) &
+	LPA_OBUF_HLB_WMARK_MAP_BMSK;
+	LPA_REG_WRITEL(lpa, val, LPA_OBUF_WMARK_HLB);
+}
+
+static void lpa_enable_utc(struct lpa_drv *lpa, bool enable, u32 cpu_id)
+{
+	u32 val;
+
+	val = (cpu_id << LPA_OBUF_UTC_CONFIG_MAP_SHFT) &
+	LPA_OBUF_UTC_CONFIG_MAP_BMSK;
+	enable = (enable ? 1 : 0);
+	val = (enable << LPA_OBUF_UTC_CONFIG_EN_SHFT) &
+	LPA_OBUF_UTC_CONFIG_EN_BMSK;
+	LPA_REG_WRITEL(lpa, val, LPA_OBUF_UTC_CONFIG);
+}
+
+static void lpa_enable_mixing(struct lpa_drv *lpa, bool enable)
+{
+	u32 val;
+
+	val = LPA_REG_READL(lpa, LPA_OBUF_CONTROL);
+	val = (enable ? val | LPA_OBUF_CONTROL_LLB_EN_BMSK :
+		val & ~LPA_OBUF_CONTROL_LLB_EN_BMSK);
+	LPA_REG_WRITEL(lpa, val, LPA_OBUF_CONTROL);
+}
+
+static void lpa_enable_mixer_saturation(struct lpa_drv *lpa, u32 buf_id,
+	bool enable)
+{
+	u32 val;
+
+	val = LPA_REG_READL(lpa, LPA_OBUF_CONTROL);
+
+	switch (buf_id) {
+	case LPA_BUF_ID_LLB:
+		val = enable ? (val | LPA_OBUF_CONTROL_LLB_SAT_EN_BMSK) :
+		(val & ~LPA_OBUF_CONTROL_LLB_SAT_EN_BMSK);
+		break;
+
+	case LPA_BUF_ID_SB:
+		val = enable ? (val | LPA_OBUF_CONTROL_SB_SAT_EN_BMSK) :
+		(val & ~LPA_OBUF_CONTROL_SB_SAT_EN_BMSK);
+		break;
+	}
+
+	LPA_REG_WRITEL(lpa, val, LPA_OBUF_CONTROL);
+}
+
+static void lpa_enable_obuf(struct lpa_drv *lpa, u32 buf_id, bool enable)
+{
+	u32 val;
+
+	val = LPA_REG_READL(lpa, LPA_OBUF_CONTROL);
+
+	switch (buf_id) {
+	case LPA_BUF_ID_HLB:
+		val = enable ? (val | LPA_OBUF_CONTROL_HLB_EN_BMSK) :
+			(val & ~LPA_OBUF_CONTROL_HLB_EN_BMSK);
+		break;
+
+	case LPA_BUF_ID_LLB:
+		val = enable ? (val | LPA_OBUF_CONTROL_LLB_EN_BMSK) :
+		(val & ~LPA_OBUF_CONTROL_LLB_EN_BMSK);
+		break;
+
+	case LPA_BUF_ID_SB:
+		val = enable ? (val | LPA_OBUF_CONTROL_SB_EN_BMSK) :
+			(val & ~LPA_OBUF_CONTROL_SB_EN_BMSK);
+		break;
+	}
+	LPA_REG_WRITEL(lpa, val, LPA_OBUF_CONTROL);
+}
+
+struct lpa_drv *lpa_get(void)
+{
+	struct lpa_mem_bank_select mem_bank;
+	struct lpa_drv *ret_lpa = &the_lpa_state.lpa_drv;
+
+	mutex_lock(&the_lpa_state.lpa_lock);
+	if (the_lpa_state.assigned) {
+		MM_ERR("LPA HW accupied\n");
+		ret_lpa = ERR_PTR(-EBUSY);
+		goto error;
+	}
+	/* perform initialization */
+	lpa_reset(ret_lpa);
+	/* Config adec param */
+	/* Initialize LLB/SB min/max address */
+	lpa_switch_sb(ret_lpa);
+	/* Config HLB minx/max address */
+	lpa_config_hlb_addr(ret_lpa);
+
+	/* Power up all memory bank for now */
+	mem_bank.b0 = 1;
+	mem_bank.b1 = 1;
+	mem_bank.b2 = 1;
+	mem_bank.b3 = 1;
+	mem_bank.b4 = 1;
+	mem_bank.b5 = 1;
+	mem_bank.b6 = 1;
+	mem_bank.b7 = 1;
+	mem_bank.b8 = 1;
+	mem_bank.b9 = 1;
+	mem_bank.b10 = 1;
+	mem_bank.llb = 1;
+	lpa_powerup_mem_bank(ret_lpa, &mem_bank);
+
+	while
+	(lpa_req_wmark_id(ret_lpa) != LPA_OBUF_WMARK_ASSIGN_DONE);
+
+	lpa_enable_llb_wmark(ret_lpa, LPA_WMARK_CTL_DISABLED, 0,
+	ret_lpa->dsp_proc_id);
+	lpa_enable_llb_wmark(ret_lpa, LPA_WMARK_CTL_DISABLED, 1,
+	ret_lpa->dsp_proc_id);
+	lpa_enable_llb_wmark(ret_lpa, LPA_WMARK_CTL_DISABLED, 2,
+	ret_lpa->app_proc_id);
+	lpa_enable_llb_wmark(ret_lpa, LPA_WMARK_CTL_DISABLED, 3,
+	ret_lpa->app_proc_id);
+	lpa_enable_hlb_wmark(ret_lpa, LPA_WMARK_CTL_DISABLED,
+	ret_lpa->dsp_proc_id);
+	lpa_enable_sb_wmark(ret_lpa, LPA_WMARK_CTL_DISABLED,
+	ret_lpa->dsp_proc_id);
+	lpa_enable_utc(ret_lpa, 0, LPA_OBUF_UTC_CONFIG_NO_INTR);
+
+	lpa_enable_mixing(ret_lpa, 1);
+	lpa_enable_mixer_saturation(ret_lpa, LPA_BUF_ID_LLB, 1);
+
+	lpa_enable_obuf(ret_lpa, LPA_BUF_ID_HLB, 0);
+	lpa_enable_obuf(ret_lpa, LPA_BUF_ID_LLB, 1);
+	if (ret_lpa->status & LPA_STATUS_SBUF_EN) {
+		lpa_enable_mixer_saturation(ret_lpa, LPA_BUF_ID_SB, 1);
+		lpa_enable_obuf(ret_lpa, LPA_BUF_ID_SB, 1);
+	}
+
+	lpa_enable_interrupt(ret_lpa, ret_lpa->dsp_proc_id);
+	mb();
+	the_lpa_state.assigned++;
+error:
+	mutex_unlock(&the_lpa_state.lpa_lock);
+	return ret_lpa;
+}
+EXPORT_SYMBOL(lpa_get);
+
+void lpa_put(struct lpa_drv *lpa)
+{
+
+	mutex_lock(&the_lpa_state.lpa_lock);
+	if (!lpa || &the_lpa_state.lpa_drv != lpa) {
+		MM_ERR("invalid arg\n");
+		goto error;
+	}
+	/* Deinitialize */
+	the_lpa_state.assigned--;
+error:
+	mutex_unlock(&the_lpa_state.lpa_lock);
+}
+EXPORT_SYMBOL(lpa_put);
+
+int lpa_cmd_codec_config(struct lpa_drv *lpa,
+	struct lpa_codec_config *config_ptr)
+{
+	u32 sample_rate;
+	u32 num_channels;
+	u32 width;
+	u32 val = 0;
+
+	if (!lpa || !config_ptr) {
+		MM_ERR("invalid parameters\n");
+		return -EINVAL;
+	}
+
+	switch (config_ptr->num_channels) {
+	case 8:
+		num_channels = LPA_NUM_CHAN_7P1;
+		break;
+	case 6:
+		num_channels = LPA_NUM_CHAN_5P1;
+		break;
+	case 4:
+		num_channels = LPA_NUM_CHAN_4_CHANNEL;
+		break;
+	case 2:
+		num_channels = LPA_NUM_CHAN_STEREO;
+		break;
+	case 1:
+		num_channels = LPA_NUM_CHAN_MONO;
+		break;
+	default:
+		MM_ERR("unsupported number of channel\n");
+		goto error;
+	}
+	val |= (num_channels << LPA_OBUF_CODEC_NUM_CHAN_SHFT) &
+	LPA_OBUF_CODEC_NUM_CHAN_BMSK;
+
+	switch (config_ptr->sample_rate) {
+	case 96000:
+		sample_rate = LPA_SAMPLE_RATE_96KHZ;
+		break;
+	case 64000:
+		sample_rate = LPA_SAMPLE_RATE_64KHZ;
+		break;
+	case 48000:
+		sample_rate = LPA_SAMPLE_RATE_48KHZ;
+		break;
+	case 44100:
+		sample_rate = LPA_SAMPLE_RATE_44P1KHZ;
+		break;
+	case 32000:
+		sample_rate = LPA_SAMPLE_RATE_32KHZ;
+		break;
+	case 22050:
+		sample_rate = LPA_SAMPLE_RATE_22P05KHZ;
+		break;
+	case 16000:
+		sample_rate = LPA_SAMPLE_RATE_16KHZ;
+		break;
+	case 11025:
+		sample_rate = LPA_SAMPLE_RATE_11P025KHZ;
+		break;
+	case 8000:
+		sample_rate = LPA_SAMPLE_RATE_8KHZ;
+		break;
+	default:
+		MM_ERR("unsupported sample rate \n");
+		goto error;
+	}
+	val |= (sample_rate << LPA_OBUF_CODEC_SAMP_SHFT) &
+		LPA_OBUF_CODEC_SAMP_BMSK;
+	switch (config_ptr->sample_width) {
+	case 32:
+		width = LPA_BITS_PER_CHAN_32BITS;
+		break;
+	case 24:
+		width = LPA_BITS_PER_CHAN_24BITS;
+		break;
+	case 16:
+		width = LPA_BITS_PER_CHAN_16BITS;
+		break;
+	default:
+		MM_ERR("unsupported sample width \n");
+		goto error;
+	}
+	val |= (width << LPA_OBUF_CODEC_BITS_PER_CHAN_SHFT) &
+		LPA_OBUF_CODEC_BITS_PER_CHAN_BMSK;
+
+	val |= LPA_OBUF_CODEC_LOAD_BMSK;
+	val |= (config_ptr->output_interface << LPA_OBUF_CODEC_INTF_SHFT) &
+	LPA_OBUF_CODEC_INTF_BMSK;
+
+	LPA_REG_WRITEL(lpa, val, LPA_OBUF_CODEC);
+	mb();
+
+	return 0;
+error:
+	return -EINVAL;
+}
+EXPORT_SYMBOL(lpa_cmd_codec_config);
+
+static int lpa_check_llb_clear(struct lpa_drv *lpa)
+{
+	u32 val;
+	val = LPA_REG_READL(lpa, LPA_OBUF_STATUS);
+
+	return !(val & LPA_OBUF_STATUS_LLB_CLR_BMSK);
+}
+
+static void lpa_clear_llb(struct lpa_drv *lpa)
+{
+	u32 val;
+
+	val = LPA_REG_READL(lpa, LPA_OBUF_CONTROL);
+	LPA_REG_WRITEL(lpa, (val | LPA_OBUF_CONTROL_LLB_CLR_CMD_BMSK),
+	LPA_OBUF_CONTROL);
+	lpa_enable_obuf(lpa, LPA_BUF_ID_LLB, 0);
+
+	while (!lpa_check_llb_clear(lpa))
+		udelay(100);
+	LPA_REG_WRITEL(lpa, val, LPA_OBUF_CONTROL);
+}
+
+int lpa_cmd_enable_codec(struct lpa_drv *lpa, bool enable)
+{
+	u32 val;
+	struct lpa_mem_bank_select mem_bank;
+
+	MM_DBG(" %s\n", (enable ? "enable" : "disable"));
+
+	if (!lpa)
+		return -EINVAL;
+
+	val = LPA_REG_READL(lpa, LPA_OBUF_CODEC);
+
+	if (enable) {
+		if (val & LPA_OBUF_CODEC_CODEC_INTF_EN_BMSK)
+			return -EBUSY;
+		/* Power up all memory bank for now */
+		mem_bank.b0 = 1;
+		mem_bank.b1 = 1;
+		mem_bank.b2 = 1;
+		mem_bank.b3 = 1;
+		mem_bank.b4 = 1;
+		mem_bank.b5 = 1;
+		mem_bank.b6 = 1;
+		mem_bank.b7 = 1;
+		mem_bank.b8 = 1;
+		mem_bank.b9 = 1;
+		mem_bank.b10 = 1;
+		mem_bank.llb = 1;
+		lpa_powerup_mem_bank(lpa, &mem_bank);
+
+		/*clear LLB*/
+		lpa_clear_llb(lpa);
+
+		lpa_enable_codec(lpa, 1);
+		MM_DBG("LPA codec is enabled\n");
+	} else {
+		if (val & LPA_OBUF_CODEC_CODEC_INTF_EN_BMSK) {
+			lpa_enable_codec(lpa, 0);
+			MM_DBG("LPA codec is disabled\n");
+		} else
+			MM_ERR("LPA codec is already disable\n");
+	}
+	mb();
+	return 0;
+}
+EXPORT_SYMBOL(lpa_cmd_enable_codec);
+
+static int lpa_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct resource *mem_src;
+	struct msm_lpa_platform_data *pdata;
+
+	MM_INFO("lpa probe\n");
+
+	if (!pdev || !pdev->dev.platform_data) {
+		MM_ERR("no plaform data\n");
+		rc = -ENODEV;
+		goto error;
+	}
+
+	mem_src = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpa");
+	if (!mem_src) {
+		MM_ERR("LPA base address undefined\n");
+		rc = -ENODEV;
+		goto error;
+	}
+
+	pdata = pdev->dev.platform_data;
+	the_lpa_state.lpa_drv.baseaddr = ioremap(mem_src->start,
+	(mem_src->end - mem_src->start) + 1);
+	if (!the_lpa_state.lpa_drv.baseaddr) {
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	the_lpa_state.lpa_drv.obuf_hlb_size = pdata->obuf_hlb_size;
+	the_lpa_state.lpa_drv.dsp_proc_id = pdata->dsp_proc_id;
+	the_lpa_state.lpa_drv.app_proc_id = pdata->app_proc_id;
+	the_lpa_state.lpa_drv.nosb_config = pdata->nosb_config;
+	the_lpa_state.lpa_drv.sb_config = pdata->sb_config;
+	/* default to enable summing buffer */
+	the_lpa_state.lpa_drv.status = LPA_STATUS_SBUF_EN;
+
+error:
+	return rc;
+
+}
+
+static int lpa_remove(struct platform_device *pdev)
+{
+	iounmap(the_lpa_state.lpa_drv.baseaddr);
+	return 0;
+}
+
+static struct platform_driver lpa_driver = {
+	.probe = lpa_probe,
+	.remove = lpa_remove,
+	.driver = {
+		.name = "lpa",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init lpa_init(void)
+{
+	the_lpa_state.assigned = 0;
+	mutex_init(&the_lpa_state.lpa_lock);
+	return platform_driver_register(&lpa_driver);
+}
+
+static void __exit lpa_exit(void)
+{
+	platform_driver_unregister(&lpa_driver);
+}
+
+module_init(lpa_init);
+module_exit(lpa_exit);
+
+MODULE_DESCRIPTION("MSM LPA driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5v2/mi2s.c b/arch/arm/mach-msm/qdsp5v2/mi2s.c
new file mode 100644
index 0000000..e38f164
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/mi2s.c
@@ -0,0 +1,885 @@
+/* Copyright (c) 2009,2011 Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+
+#include <mach/qdsp5v2/mi2s.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+
+#define DEBUG
+#ifdef DEBUG
+#define dprintk(format, arg...) \
+printk(KERN_DEBUG format, ## arg)
+#else
+#define dprintk(format, arg...) do {} while (0)
+#endif
+
+/*----------------------------------------------------------------------------
+ * Preprocessor Definitions and Constants
+ * -------------------------------------------------------------------------*/
+
+/* Device Types */
+#define HDMI 0
+#define CODEC_RX 1
+#define CODEC_TX 2
+
+/* Static offset for now. If different target have different
+ * offset, update to platform data model
+ */
+#define MI2S_RESET_OFFSET   0x0
+#define MI2S_MODE_OFFSET    0x4
+#define MI2S_TX_MODE_OFFSET 0x8
+#define MI2S_RX_MODE_OFFSET 0xc
+
+#define MI2S_SD_N_EN_MASK 0xF0
+#define MI2S_TX_RX_N_MASK 0x0F
+
+#define MI2S_RESET__MI2S_RESET__RESET  0x1
+#define MI2S_RESET__MI2S_RESET__ACTIVE 0x0
+#define MI2S_MODE__MI2S_MASTER__MASTER 0x1
+#define MI2S_MODE__MI2S_MASTER__SLAVE  0x0
+#define MI2S_MODE__MI2S_TX_RX_WORD_TYPE__16_BIT 0x1
+#define MI2S_MODE__MI2S_TX_RX_WORD_TYPE__24_BIT 0x2
+#define MI2S_MODE__MI2S_TX_RX_WORD_TYPE__32_BIT 0x3
+#define MI2S_TX_MODE__MI2S_TX_CODEC_16_MONO_MODE__RAW 0x0
+#define MI2S_TX_MODE__MI2S_TX_CODEC_16_MONO_MODE__PACKED 0x1
+#define MI2S_TX_MODE__MI2S_TX_STEREO_MODE__MONO_SAMPLE   0x0
+#define MI2S_TX_MODE__MI2S_TX_STEREO_MODE__STEREO_SAMPLE 0x1
+#define MI2S_TX_MODE__MI2S_TX_CH_TYPE__2_CHANNEL 0x0
+#define MI2S_TX_MODE__MI2S_TX_CH_TYPE__4_CHANNEL 0x1
+#define MI2S_TX_MODE__MI2S_TX_CH_TYPE__6_CHANNEL 0x2
+#define MI2S_TX_MODE__MI2S_TX_CH_TYPE__8_CHANNEL 0x3
+#define MI2S_TX_MODE__MI2S_TX_DMA_ACK_SYNCH_EN__SYNC_ENABLE 0x1
+#define MI2S_RX_MODE__MI2S_RX_CODEC_16_MONO_MODE__RAW 0x0
+#define MI2S_RX_MODE__MI2S_RX_CODEC_16_MONO_MODE__PACKED 0x1
+#define MI2S_RX_MODE__MI2S_RX_STEREO_MODE__MONO_SAMPLE   0x0
+#define MI2S_RX_MODE__MI2S_RX_STEREO_MODE__STEREO_SAMPLE 0x1
+#define MI2S_RX_MODE__MI2S_RX_CH_TYPE__2_CH 0x0
+#define MI2S_RX_MODE__MI2S_RX_DMA_ACK_SYNCH_EN__SYNC_ENABLE 0x1
+
+#define HWIO_AUDIO1_MI2S_MODE_MI2S_MASTER_BMSK				0x1000
+#define HWIO_AUDIO1_MI2S_MODE_MI2S_MASTER_SHFT				0xC
+#define HWIO_AUDIO1_MI2S_MODE_MI2S_TX_RX_WORD_TYPE_BMSK  		0x300
+#define HWIO_AUDIO1_MI2S_MODE_MI2S_TX_RX_WORD_TYPE_SHFT  		0x8
+#define HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_STEREO_MODE_BMSK		0x4
+#define HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_STEREO_MODE_SHFT		0x2
+#define HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_P_MONO_BMSK                    0x2
+#define HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_P_MONO_SHFT                    0x1
+#define HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_CH_TYPE_BMSK			0x18
+#define HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_CH_TYPE_SHFT			0x3
+#define HWIO_AUDIO1_MI2S_TX_MODE_MI2S_4_0_CH_MAP_BMSK			0x80
+#define HWIO_AUDIO1_MI2S_TX_MODE_MI2S_4_0_CH_MAP_SHFT			0x7
+#define HWIO_AUDIO1_MI2S_TX_MODE_MI2S_2_0_CH_MAP_BMSK			0x60
+#define HWIO_AUDIO1_MI2S_TX_MODE_MI2S_2_0_CH_MAP_SHFT			0x5
+#define HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_DMA_ACK_SYNCH_EN_BMSK		0x1
+#define HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_I2S_LINE_BMSK			0x60
+#define HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_I2S_LINE_SHFT			0x5
+#define HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_STEREO_MODE_BMSK		0x4
+#define HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_STEREO_MODE_SHFT		0x2
+#define HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_CODEC_P_MONO_BMSK              0x2
+#define HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_CODEC_P_MONO_SHFT              0x1
+#define HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_CH_TYPE_BMSK			0x18
+#define HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_CH_TYPE_SHFT			0x3
+#define HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_DMA_ACK_SYNCH_EN_BMSK		0x1
+
+/* Max number of channels */
+#define MAX_NUM_CHANNELS_OUT 8
+#define MAX_NUM_CHANNELS_IN  2
+
+/* Num of SD Lines */
+#define MAX_SD_LINES 4
+
+#define MI2S_SD_0_EN_MAP  0x10
+#define MI2S_SD_1_EN_MAP  0x20
+#define MI2S_SD_2_EN_MAP  0x40
+#define MI2S_SD_3_EN_MAP  0x80
+#define MI2S_SD_0_TX_MAP  0x01
+#define MI2S_SD_1_TX_MAP  0x02
+#define MI2S_SD_2_TX_MAP  0x04
+#define MI2S_SD_3_TX_MAP  0x08
+
+struct mi2s_state {
+	void __iomem *mi2s_hdmi_base;
+	void __iomem *mi2s_rx_base;
+	void __iomem *mi2s_tx_base;
+	struct mutex mutex_lock;
+
+};
+
+static struct mi2s_state the_mi2s_state;
+
+static void __iomem *get_base_addr(struct mi2s_state *mi2s, uint8_t dev_id)
+{
+	switch (dev_id) {
+	case HDMI:
+		return mi2s->mi2s_hdmi_base;
+	case CODEC_RX:
+		return mi2s->mi2s_rx_base;
+	case CODEC_TX:
+		return mi2s->mi2s_tx_base;
+	default:
+		break;
+	}
+	return ERR_PTR(-ENODEV);
+}
+
+static void mi2s_reset(struct mi2s_state *mi2s, uint8_t dev_id)
+{
+	void __iomem *baddr = get_base_addr(mi2s, dev_id);
+	if (!IS_ERR(baddr))
+		writel(MI2S_RESET__MI2S_RESET__RESET,
+		baddr + MI2S_RESET_OFFSET);
+}
+
+static void mi2s_release(struct mi2s_state *mi2s, uint8_t dev_id)
+{
+	void __iomem *baddr = get_base_addr(mi2s, dev_id);
+	if (!IS_ERR(baddr))
+		writel(MI2S_RESET__MI2S_RESET__ACTIVE,
+		baddr + MI2S_RESET_OFFSET);
+}
+
+static void mi2s_master(struct mi2s_state *mi2s, uint8_t dev_id, bool master)
+{
+	void __iomem *baddr = get_base_addr(mi2s, dev_id);
+	uint32_t val;
+	if (!IS_ERR(baddr)) {
+		val = readl(baddr + MI2S_MODE_OFFSET);
+		if (master) {
+			writel(
+			((val & ~HWIO_AUDIO1_MI2S_MODE_MI2S_MASTER_BMSK) |
+			 (MI2S_MODE__MI2S_MASTER__MASTER <<
+			  HWIO_AUDIO1_MI2S_MODE_MI2S_MASTER_SHFT)),
+			baddr + MI2S_MODE_OFFSET);
+		} else {
+			writel(
+			((val & ~HWIO_AUDIO1_MI2S_MODE_MI2S_MASTER_BMSK) |
+			 (MI2S_MODE__MI2S_MASTER__SLAVE <<
+			  HWIO_AUDIO1_MI2S_MODE_MI2S_MASTER_SHFT)),
+			baddr + MI2S_MODE_OFFSET);
+		}
+	}
+}
+
+static void mi2s_set_word_type(struct mi2s_state *mi2s, uint8_t dev_id,
+	uint8_t size)
+{
+	void __iomem *baddr = get_base_addr(mi2s, dev_id);
+	uint32_t val;
+	if (!IS_ERR(baddr)) {
+		val = readl(baddr + MI2S_MODE_OFFSET);
+		switch (size) {
+		case WT_16_BIT:
+			writel(
+			((val &
+			~HWIO_AUDIO1_MI2S_MODE_MI2S_TX_RX_WORD_TYPE_BMSK) |
+			(MI2S_MODE__MI2S_TX_RX_WORD_TYPE__16_BIT <<
+			HWIO_AUDIO1_MI2S_MODE_MI2S_TX_RX_WORD_TYPE_SHFT)),
+			baddr + MI2S_MODE_OFFSET);
+			break;
+		case WT_24_BIT:
+			writel(
+			((val &
+			~HWIO_AUDIO1_MI2S_MODE_MI2S_TX_RX_WORD_TYPE_BMSK) |
+			(MI2S_MODE__MI2S_TX_RX_WORD_TYPE__24_BIT <<
+			HWIO_AUDIO1_MI2S_MODE_MI2S_TX_RX_WORD_TYPE_SHFT)),
+			baddr + MI2S_MODE_OFFSET);
+			break;
+		case WT_32_BIT:
+			writel(
+			((val &
+			~HWIO_AUDIO1_MI2S_MODE_MI2S_TX_RX_WORD_TYPE_BMSK) |
+			(MI2S_MODE__MI2S_TX_RX_WORD_TYPE__32_BIT <<
+			HWIO_AUDIO1_MI2S_MODE_MI2S_TX_RX_WORD_TYPE_SHFT)),
+			baddr + MI2S_MODE_OFFSET);
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+static void mi2s_set_sd(struct mi2s_state *mi2s, uint8_t dev_id, uint8_t sd_map)
+{
+	void __iomem *baddr = get_base_addr(mi2s, dev_id);
+	uint32_t val;
+	if (!IS_ERR(baddr)) {
+		val = readl(baddr + MI2S_MODE_OFFSET) &
+			~(MI2S_SD_N_EN_MASK | MI2S_TX_RX_N_MASK);
+		writel(val | sd_map, baddr + MI2S_MODE_OFFSET);
+	}
+}
+
+static void mi2s_set_output_num_channels(struct mi2s_state *mi2s,
+	uint8_t dev_id, uint8_t channels)
+{
+	void __iomem *baddr = get_base_addr(mi2s, dev_id);
+	uint32_t val;
+	if (!IS_ERR(baddr)) {
+		val = readl(baddr + MI2S_TX_MODE_OFFSET);
+		if (channels == MI2S_CHAN_MONO_RAW) {
+			val = (val &
+			~(HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_STEREO_MODE_BMSK |
+			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_P_MONO_BMSK)) |
+			((MI2S_TX_MODE__MI2S_TX_STEREO_MODE__MONO_SAMPLE <<
+			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_STEREO_MODE_SHFT) |
+			(MI2S_TX_MODE__MI2S_TX_CODEC_16_MONO_MODE__RAW <<
+			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_P_MONO_SHFT));
+		} else if (channels == MI2S_CHAN_MONO_PACKED) {
+			val = (val &
+			~(HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_STEREO_MODE_BMSK |
+			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_P_MONO_BMSK)) |
+			((MI2S_TX_MODE__MI2S_TX_STEREO_MODE__MONO_SAMPLE <<
+			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_STEREO_MODE_SHFT) |
+			(MI2S_TX_MODE__MI2S_TX_CODEC_16_MONO_MODE__PACKED <<
+			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_P_MONO_SHFT));
+		} else if (channels == MI2S_CHAN_STEREO) {
+			val = (val &
+			~(HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_STEREO_MODE_BMSK |
+			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_CH_TYPE_BMSK)) |
+			((MI2S_TX_MODE__MI2S_TX_STEREO_MODE__STEREO_SAMPLE <<
+			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_STEREO_MODE_SHFT) |
+			(MI2S_TX_MODE__MI2S_TX_CH_TYPE__2_CHANNEL <<
+			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_CH_TYPE_SHFT));
+		} else if (channels == MI2S_CHAN_4CHANNELS) {
+			val = (val &
+			~(HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_STEREO_MODE_BMSK |
+			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_CH_TYPE_BMSK)) |
+			((MI2S_TX_MODE__MI2S_TX_STEREO_MODE__STEREO_SAMPLE <<
+			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_STEREO_MODE_SHFT) |
+			(MI2S_TX_MODE__MI2S_TX_CH_TYPE__4_CHANNEL <<
+			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_CH_TYPE_SHFT));
+		} else if (channels == MI2S_CHAN_6CHANNELS) {
+			val = (val &
+			~(HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_STEREO_MODE_BMSK |
+			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_CH_TYPE_BMSK)) |
+			((MI2S_TX_MODE__MI2S_TX_STEREO_MODE__STEREO_SAMPLE <<
+			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_STEREO_MODE_SHFT) |
+			(MI2S_TX_MODE__MI2S_TX_CH_TYPE__6_CHANNEL <<
+			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_CH_TYPE_SHFT));
+		} else if (channels == MI2S_CHAN_8CHANNELS) {
+			val = (val &
+			~(HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_STEREO_MODE_BMSK |
+			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_CH_TYPE_BMSK)) |
+			((MI2S_TX_MODE__MI2S_TX_STEREO_MODE__STEREO_SAMPLE <<
+			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_STEREO_MODE_SHFT) |
+			(MI2S_TX_MODE__MI2S_TX_CH_TYPE__8_CHANNEL <<
+			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_CH_TYPE_SHFT));
+		}
+		writel(val, baddr + MI2S_TX_MODE_OFFSET);
+	}
+}
+
+static void mi2s_set_output_4ch_map(struct mi2s_state *mi2s, uint8_t dev_id,
+	bool high_low)
+{
+	void __iomem *baddr = get_base_addr(mi2s, dev_id);
+	uint32_t val;
+	if (!IS_ERR(baddr)) {
+		val = readl(baddr + MI2S_TX_MODE_OFFSET);
+		val = (val & ~HWIO_AUDIO1_MI2S_TX_MODE_MI2S_4_0_CH_MAP_BMSK) |
+			(high_low <<
+			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_4_0_CH_MAP_SHFT);
+		writel(val, baddr + MI2S_TX_MODE_OFFSET);
+	}
+}
+
+static void mi2s_set_output_2ch_map(struct mi2s_state *mi2s, uint8_t dev_id,
+	uint8_t sd_line)
+{
+	void __iomem *baddr = get_base_addr(mi2s, dev_id);
+	uint32_t val;
+
+	if (!IS_ERR(baddr)) {
+		val = readl(baddr + MI2S_TX_MODE_OFFSET);
+		if (sd_line < 4) {
+			val = (val &
+			~HWIO_AUDIO1_MI2S_TX_MODE_MI2S_2_0_CH_MAP_BMSK) |
+			(sd_line <<
+			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_2_0_CH_MAP_SHFT);
+			writel(val, baddr + MI2S_TX_MODE_OFFSET);
+		}
+	}
+}
+
+static void mi2s_set_output_clk_synch(struct mi2s_state *mi2s, uint8_t dev_id)
+{
+	void __iomem *baddr = get_base_addr(mi2s, dev_id);
+	uint32_t val;
+
+	if (!IS_ERR(baddr)) {
+		val = readl(baddr + MI2S_TX_MODE_OFFSET);
+		writel(((val &
+		~HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_DMA_ACK_SYNCH_EN_BMSK) |
+		MI2S_TX_MODE__MI2S_TX_DMA_ACK_SYNCH_EN__SYNC_ENABLE),
+		baddr + MI2S_TX_MODE_OFFSET);
+	}
+}
+
+static void mi2s_set_input_sd_line(struct mi2s_state *mi2s, uint8_t dev_id,
+	uint8_t sd_line)
+{
+	void __iomem *baddr = get_base_addr(mi2s, dev_id);
+	uint32_t val;
+
+	if (!IS_ERR(baddr)) {
+		val = readl(baddr + MI2S_RX_MODE_OFFSET);
+		if (sd_line < 4) {
+			val = (val &
+			~HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_I2S_LINE_BMSK) |
+			(sd_line <<
+			HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_I2S_LINE_SHFT);
+			writel(val, baddr + MI2S_RX_MODE_OFFSET);
+		}
+	}
+}
+
+static void mi2s_set_input_num_channels(struct mi2s_state *mi2s, uint8_t dev_id,
+	uint8_t channels)
+{
+	void __iomem *baddr = get_base_addr(mi2s, dev_id);
+	uint32_t val;
+
+	if (!IS_ERR(baddr)) {
+		val = readl(baddr + MI2S_RX_MODE_OFFSET);
+		if (channels == MI2S_CHAN_MONO_RAW) {
+			val = (val &
+			~(HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_STEREO_MODE_BMSK |
+			HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_CODEC_P_MONO_BMSK)) |
+			((MI2S_RX_MODE__MI2S_RX_STEREO_MODE__MONO_SAMPLE <<
+			HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_STEREO_MODE_SHFT) |
+			(MI2S_RX_MODE__MI2S_RX_CODEC_16_MONO_MODE__RAW <<
+			HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_CODEC_P_MONO_SHFT));
+		} else if (channels == MI2S_CHAN_MONO_PACKED) {
+			val = (val &
+			~(HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_STEREO_MODE_BMSK |
+			HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_CODEC_P_MONO_BMSK)) |
+			((MI2S_RX_MODE__MI2S_RX_STEREO_MODE__MONO_SAMPLE <<
+			HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_STEREO_MODE_SHFT) |
+			(MI2S_RX_MODE__MI2S_RX_CODEC_16_MONO_MODE__PACKED <<
+			HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_CODEC_P_MONO_SHFT));
+		} else if (channels == MI2S_CHAN_STEREO) {
+
+			if (dev_id == HDMI)
+				val = (val &
+			~(HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_STEREO_MODE_BMSK |
+			HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_CH_TYPE_BMSK)) |
+			((MI2S_RX_MODE__MI2S_RX_STEREO_MODE__STEREO_SAMPLE <<
+			HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_STEREO_MODE_SHFT) |
+			(MI2S_RX_MODE__MI2S_RX_CH_TYPE__2_CH <<
+			HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_CH_TYPE_SHFT));
+
+			else
+				val = (val &
+			~(HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_STEREO_MODE_BMSK |
+			HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_CH_TYPE_BMSK)) |
+			((MI2S_RX_MODE__MI2S_RX_STEREO_MODE__STEREO_SAMPLE <<
+			HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_STEREO_MODE_SHFT) |
+			(MI2S_RX_MODE__MI2S_RX_CODEC_16_MONO_MODE__PACKED <<
+			HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_CODEC_P_MONO_SHFT) |
+			(MI2S_RX_MODE__MI2S_RX_CH_TYPE__2_CH <<
+			HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_CH_TYPE_SHFT));
+
+
+		}
+		writel(val, baddr + MI2S_RX_MODE_OFFSET);
+	}
+}
+
+static void mi2s_set_input_clk_synch(struct mi2s_state *mi2s, uint8_t dev_id)
+{
+	void __iomem *baddr = get_base_addr(mi2s, dev_id);
+	uint32_t val;
+
+	if (!IS_ERR(baddr)) {
+		val = readl(baddr + MI2S_RX_MODE_OFFSET);
+		writel(
+		((val &
+		~HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_DMA_ACK_SYNCH_EN_BMSK) |
+		MI2S_RX_MODE__MI2S_RX_DMA_ACK_SYNCH_EN__SYNC_ENABLE),
+		baddr + MI2S_RX_MODE_OFFSET);
+	}
+}
+
+
+static u8 num_of_bits_set(u8 sd_line_mask)
+{
+	u8 num_bits_set = 0;
+
+	while (sd_line_mask) {
+
+		if (sd_line_mask & 1)
+			num_bits_set++;
+		sd_line_mask = sd_line_mask >> 1;
+	}
+	return num_bits_set;
+}
+
+
+bool mi2s_set_hdmi_output_path(uint8_t channels, uint8_t size,
+		uint8_t sd_line_mask)
+{
+	bool ret_val = MI2S_TRUE;
+	struct mi2s_state *mi2s = &the_mi2s_state;
+	u8 sd_line, num_of_sd_lines = 0;
+	void __iomem *baddr;
+	uint32_t val;
+
+	pr_debug("%s: channels = %u size = %u sd_line_mask = 0x%x\n", __func__,
+		channels, size, sd_line_mask);
+
+	if ((channels == 0) ||  (channels > MAX_NUM_CHANNELS_OUT) ||
+		((channels != 1) && (channels % 2 != 0))) {
+
+		pr_err("%s: invalid number of channels. channels = %u\n",
+				__func__, channels);
+		return  MI2S_FALSE;
+	}
+
+	sd_line_mask &=  MI2S_SD_LINE_MASK;
+
+	if (!sd_line_mask) {
+		pr_err("%s: Did not set any data lines to use "
+			" sd_line_mask =0x%x\n", __func__, sd_line_mask);
+		return  MI2S_FALSE;
+	}
+
+	mutex_lock(&mi2s->mutex_lock);
+	/* Put device in reset */
+	mi2s_reset(mi2s, HDMI);
+
+	mi2s_master(mi2s, HDMI, 1);
+
+	/* Set word type */
+	if (size <= WT_MAX)
+		mi2s_set_word_type(mi2s, HDMI, size);
+	else
+		ret_val = MI2S_FALSE;
+
+	/* Enable clock crossing synchronization of RD DMA ACK */
+	mi2s_set_output_clk_synch(mi2s, HDMI);
+
+	mi2s_set_output_num_channels(mi2s, HDMI, channels);
+
+	num_of_sd_lines = num_of_bits_set(sd_line_mask);
+	/*Second argument to find_first_bit should be maximum number of
+	bit*/
+
+	sd_line = find_first_bit((unsigned long *)&sd_line_mask,
+			sizeof(sd_line_mask) * 8);
+	pr_debug("sd_line = %d\n", sd_line);
+
+	if (channels == 1) {
+
+		if (num_of_sd_lines != 1) {
+			pr_err("%s: for one channel only one SD lines is"
+				" needed. num_of_sd_lines = %u\n",
+				__func__, num_of_sd_lines);
+
+			ret_val = MI2S_FALSE;
+			goto error;
+		}
+
+		if (sd_line != 0) {
+			pr_err("%s: for one channel tx, need to use SD_0 "
+					"sd_line = %u\n", __func__, sd_line);
+
+			ret_val = MI2S_FALSE;
+			goto error;
+		}
+
+		/* Enable SD line 0 for Tx (only option for
+			 * mono audio)
+		 */
+		mi2s_set_sd(mi2s, HDMI, MI2S_SD_0_EN_MAP | MI2S_SD_0_TX_MAP);
+
+	} else if (channels == 2) {
+
+		if (num_of_sd_lines != 1) {
+			pr_err("%s: for two channel only one SD lines is"
+				" needed. num_of_sd_lines = %u\n",
+				__func__, num_of_sd_lines);
+			ret_val = MI2S_FALSE;
+			goto error;
+		}
+
+		/* Enable single SD line for Tx */
+		mi2s_set_sd(mi2s, HDMI, (MI2S_SD_0_EN_MAP << sd_line) |
+				(MI2S_SD_0_TX_MAP << sd_line));
+
+		/* Set 2-channel mapping */
+		mi2s_set_output_2ch_map(mi2s, HDMI, sd_line);
+
+	} else if (channels == 4) {
+
+		if (num_of_sd_lines != 2) {
+			pr_err("%s: for 4 channels two SD lines are"
+				" needed. num_of_sd_lines = %u\\n",
+				__func__, num_of_sd_lines);
+			ret_val = MI2S_FALSE;
+			goto error;
+		}
+
+		if ((sd_line_mask && MI2S_SD_0) &&
+				(sd_line_mask && MI2S_SD_1)) {
+
+			mi2s_set_sd(mi2s, HDMI, (MI2S_SD_0_EN_MAP |
+				MI2S_SD_1_EN_MAP) | (MI2S_SD_0_TX_MAP |
+				MI2S_SD_1_TX_MAP));
+			mi2s_set_output_4ch_map(mi2s, HDMI, MI2S_FALSE);
+
+		} else if ((sd_line_mask && MI2S_SD_2) &&
+				(sd_line_mask && MI2S_SD_3)) {
+
+			mi2s_set_sd(mi2s, HDMI, (MI2S_SD_2_EN_MAP |
+				MI2S_SD_3_EN_MAP) | (MI2S_SD_2_TX_MAP |
+				MI2S_SD_3_TX_MAP));
+
+			mi2s_set_output_4ch_map(mi2s, HDMI, MI2S_TRUE);
+		} else {
+
+			pr_err("%s: for 4 channels invalid SD lines usage"
+				" sd_line_mask = 0x%x\n",
+				__func__, sd_line_mask);
+			ret_val = MI2S_FALSE;
+			goto error;
+		}
+	} else if (channels == 6) {
+
+		if (num_of_sd_lines != 3) {
+			pr_err("%s: for 6 channels three SD lines are"
+				" needed. num_of_sd_lines = %u\n",
+				__func__, num_of_sd_lines);
+			ret_val = MI2S_FALSE;
+			goto error;
+		}
+
+		if ((sd_line_mask && MI2S_SD_0) &&
+			(sd_line_mask && MI2S_SD_1) &&
+			(sd_line_mask && MI2S_SD_2)) {
+
+			mi2s_set_sd(mi2s, HDMI, (MI2S_SD_0_EN_MAP |
+				MI2S_SD_1_EN_MAP | MI2S_SD_2_EN_MAP) |
+				(MI2S_SD_0_TX_MAP | MI2S_SD_1_TX_MAP |
+				MI2S_SD_2_TX_MAP));
+
+		} else if ((sd_line_mask && MI2S_SD_1) &&
+				(sd_line_mask && MI2S_SD_2) &&
+				(sd_line_mask && MI2S_SD_3)) {
+
+			mi2s_set_sd(mi2s, HDMI, (MI2S_SD_1_EN_MAP |
+				MI2S_SD_2_EN_MAP | MI2S_SD_3_EN_MAP) |
+				(MI2S_SD_1_TX_MAP | MI2S_SD_2_TX_MAP |
+				MI2S_SD_3_TX_MAP));
+
+		} else {
+
+			pr_err("%s: for 6 channels invalid SD lines usage"
+				" sd_line_mask = 0x%x\n",
+				__func__, sd_line_mask);
+			ret_val = MI2S_FALSE;
+			goto error;
+		}
+	} else if (channels == 8) {
+
+		if (num_of_sd_lines != 4) {
+			pr_err("%s: for 8 channels four SD lines are"
+				" needed. num_of_sd_lines = %u\n",
+				__func__, num_of_sd_lines);
+			ret_val = MI2S_FALSE;
+			goto error;
+		}
+
+		mi2s_set_sd(mi2s, HDMI, (MI2S_SD_0_EN_MAP |
+			MI2S_SD_1_EN_MAP | MI2S_SD_2_EN_MAP |
+			MI2S_SD_3_EN_MAP) | (MI2S_SD_0_TX_MAP |
+			MI2S_SD_1_TX_MAP | MI2S_SD_2_TX_MAP |
+			MI2S_SD_3_TX_MAP));
+	} else {
+		pr_err("%s: invalid number channels = %u\n",
+				__func__, channels);
+			ret_val = MI2S_FALSE;
+			goto error;
+	}
+
+	baddr = get_base_addr(mi2s, HDMI);
+
+	val = readl(baddr + MI2S_MODE_OFFSET);
+	pr_debug("%s(): MI2S_MODE = 0x%x\n", __func__, val);
+
+	val = readl(baddr + MI2S_TX_MODE_OFFSET);
+	pr_debug("%s(): MI2S_TX_MODE = 0x%x\n", __func__, val);
+
+
+error:
+	/* Release device from reset */
+	mi2s_release(mi2s, HDMI);
+
+	mutex_unlock(&mi2s->mutex_lock);
+	mb();
+	return ret_val;
+}
+EXPORT_SYMBOL(mi2s_set_hdmi_output_path);
+
+bool mi2s_set_hdmi_input_path(uint8_t channels, uint8_t size,
+		uint8_t sd_line_mask)
+{
+	bool ret_val = MI2S_TRUE;
+	struct mi2s_state *mi2s = &the_mi2s_state;
+	u8 sd_line, num_of_sd_lines = 0;
+	void __iomem *baddr;
+	uint32_t val;
+
+	pr_debug("%s: channels = %u size = %u sd_line_mask = 0x%x\n", __func__,
+		channels, size, sd_line_mask);
+
+	if ((channels != 1) && (channels != MAX_NUM_CHANNELS_IN)) {
+
+		pr_err("%s: invalid number of channels. channels = %u\n",
+				__func__, channels);
+		return  MI2S_FALSE;
+	}
+
+	if (size > WT_MAX) {
+
+		pr_err("%s: mi2s word size can not be greater than 32 bits\n",
+				__func__);
+		return MI2S_FALSE;
+	}
+
+	sd_line_mask &=  MI2S_SD_LINE_MASK;
+
+	if (!sd_line_mask) {
+		pr_err("%s: Did not set any data lines to use "
+			" sd_line_mask =0x%x\n", __func__, sd_line_mask);
+		return  MI2S_FALSE;
+	}
+
+	num_of_sd_lines = num_of_bits_set(sd_line_mask);
+
+	if (num_of_sd_lines != 1) {
+		pr_err("%s: for two channel input only one SD lines is"
+			" needed. num_of_sd_lines = %u sd_line_mask = 0x%x\n",
+			__func__, num_of_sd_lines, sd_line_mask);
+		return MI2S_FALSE;
+	}
+
+	/*Second argument to find_first_bit should be maximum number of
+	bits interested*/
+	sd_line = find_first_bit((unsigned long *)&sd_line_mask,
+			sizeof(sd_line_mask) * 8);
+	pr_debug("sd_line = %d\n", sd_line);
+
+	/* Ensure sd_line parameter is valid (0-max) */
+	if (sd_line > MAX_SD_LINES) {
+		pr_err("%s: Line number can not be greater than = %u\n",
+			__func__, MAX_SD_LINES);
+		return MI2S_FALSE;
+	}
+
+	mutex_lock(&mi2s->mutex_lock);
+	/* Put device in reset */
+	mi2s_reset(mi2s, HDMI);
+
+	mi2s_master(mi2s, HDMI, 1);
+
+	/* Set word type */
+	mi2s_set_word_type(mi2s, HDMI, size);
+
+	/* Enable clock crossing synchronization of WR DMA ACK */
+	mi2s_set_input_clk_synch(mi2s, HDMI);
+
+	/* Ensure channels parameter is valid (non-zero, less than max,
+	 * and even or mono)
+	 */
+	mi2s_set_input_num_channels(mi2s, HDMI, channels);
+
+	mi2s_set_input_sd_line(mi2s, HDMI, sd_line);
+
+	mi2s_set_sd(mi2s, HDMI, (MI2S_SD_0_EN_MAP << sd_line));
+
+	baddr = get_base_addr(mi2s, HDMI);
+
+	val = readl(baddr + MI2S_MODE_OFFSET);
+	pr_debug("%s(): MI2S_MODE = 0x%x\n", __func__, val);
+
+	val = readl(baddr + MI2S_RX_MODE_OFFSET);
+	pr_debug("%s(): MI2S_RX_MODE = 0x%x\n", __func__, val);
+
+	/* Release device from reset */
+	mi2s_release(mi2s, HDMI);
+
+	mutex_unlock(&mi2s->mutex_lock);
+	mb();
+	return ret_val;
+}
+EXPORT_SYMBOL(mi2s_set_hdmi_input_path);
+
+bool mi2s_set_codec_output_path(uint8_t channels, uint8_t size)
+{
+	bool ret_val = MI2S_TRUE;
+	struct mi2s_state *mi2s = &the_mi2s_state;
+
+	mutex_lock(&mi2s->mutex_lock);
+	/* Put device in reset */
+	mi2s_reset(mi2s, CODEC_TX);
+
+	mi2s_master(mi2s, CODEC_TX, 1);
+
+	/* Enable clock crossing synchronization of RD DMA ACK */
+	mi2s_set_output_clk_synch(mi2s, CODEC_TX);
+
+	/* Set word type */
+	if (size <= WT_MAX)
+		mi2s_set_word_type(mi2s, CODEC_TX, size);
+	else
+		ret_val = MI2S_FALSE;
+
+	mi2s_set_output_num_channels(mi2s, CODEC_TX, channels);
+
+	/* Enable SD line */
+	mi2s_set_sd(mi2s, CODEC_TX, MI2S_SD_0_EN_MAP | MI2S_SD_0_TX_MAP);
+
+	/* Release device from reset */
+	mi2s_release(mi2s, CODEC_TX);
+
+	mutex_unlock(&mi2s->mutex_lock);
+	mb();
+	return ret_val;
+}
+EXPORT_SYMBOL(mi2s_set_codec_output_path);
+
+bool mi2s_set_codec_input_path(uint8_t channels, uint8_t size)
+{
+	bool ret_val = MI2S_TRUE;
+	struct mi2s_state *mi2s = &the_mi2s_state;
+
+	mutex_lock(&the_mi2s_state.mutex_lock);
+	/* Put device in reset */
+	mi2s_reset(mi2s, CODEC_RX);
+
+	mi2s_master(mi2s, CODEC_RX, 1);
+
+	/* Enable clock crossing synchronization of WR DMA ACK */
+	mi2s_set_input_clk_synch(mi2s, CODEC_RX);
+
+	/* Set word type */
+	if (size <= WT_MAX)
+		mi2s_set_word_type(mi2s, CODEC_RX, size);
+	else
+		ret_val = MI2S_FALSE;
+
+	mi2s_set_input_num_channels(mi2s, CODEC_RX, channels);
+
+	/* Enable SD line */
+	mi2s_set_sd(mi2s, CODEC_RX, MI2S_SD_0_EN_MAP);
+
+	/* Release device from reset */
+	mi2s_release(mi2s, CODEC_RX);
+
+	mutex_unlock(&mi2s->mutex_lock);
+	mb();
+	return ret_val;
+}
+EXPORT_SYMBOL(mi2s_set_codec_input_path);
+
+
+static int mi2s_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct resource *mem_src;
+
+	mem_src = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hdmi");
+	if (!mem_src) {
+		rc = -ENODEV;
+		goto error_hdmi;
+	}
+	the_mi2s_state.mi2s_hdmi_base = ioremap(mem_src->start,
+		(mem_src->end - mem_src->start) + 1);
+	if (!the_mi2s_state.mi2s_hdmi_base) {
+		rc = -ENOMEM;
+		goto error_hdmi;
+	}
+	mem_src = platform_get_resource_byname(pdev,
+		IORESOURCE_MEM, "codec_rx");
+	if (!mem_src) {
+		rc = -ENODEV;
+		goto error_codec_rx;
+	}
+	the_mi2s_state.mi2s_rx_base = ioremap(mem_src->start,
+		(mem_src->end - mem_src->start) + 1);
+	if (!the_mi2s_state.mi2s_rx_base) {
+		rc = -ENOMEM;
+		goto error_codec_rx;
+	}
+	mem_src = platform_get_resource_byname(pdev,
+		IORESOURCE_MEM, "codec_tx");
+	if (!mem_src) {
+		rc = -ENODEV;
+		goto error_codec_tx;
+	}
+	the_mi2s_state.mi2s_tx_base = ioremap(mem_src->start,
+		(mem_src->end - mem_src->start) + 1);
+	if (!the_mi2s_state.mi2s_tx_base) {
+		rc = -ENOMEM;
+		goto error_codec_tx;
+	}
+	mutex_init(&the_mi2s_state.mutex_lock);
+
+	return rc;
+
+error_codec_tx:
+	iounmap(the_mi2s_state.mi2s_rx_base);
+error_codec_rx:
+	iounmap(the_mi2s_state.mi2s_hdmi_base);
+error_hdmi:
+	return rc;
+
+}
+
+static int mi2s_remove(struct platform_device *pdev)
+{
+	iounmap(the_mi2s_state.mi2s_tx_base);
+	iounmap(the_mi2s_state.mi2s_rx_base);
+	iounmap(the_mi2s_state.mi2s_hdmi_base);
+	return 0;
+}
+
+static struct platform_driver mi2s_driver = {
+	.probe = mi2s_probe,
+	.remove = mi2s_remove,
+	.driver = {
+		.name = "mi2s",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init mi2s_init(void)
+{
+	return platform_driver_register(&mi2s_driver);
+}
+
+static void __exit mi2s_exit(void)
+{
+	platform_driver_unregister(&mi2s_driver);
+}
+
+module_init(mi2s_init);
+module_exit(mi2s_exit);
+
+MODULE_DESCRIPTION("MSM MI2S driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5v2/mp3_funcs.c b/arch/arm/mach-msm/qdsp5v2/mp3_funcs.c
new file mode 100644
index 0000000..0b20be0
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/mp3_funcs.c
@@ -0,0 +1,45 @@
+/* Copyright (c) 2010, 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/fs.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+
+#include <linux/msm_audio.h>
+
+#include <mach/qdsp5v2/qdsp5audppmsg.h>
+#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
+#include <mach/qdsp5v2/qdsp5audplaymsg.h>
+#include <mach/qdsp5v2/audpp.h>
+#include <mach/qdsp5v2/codec_utils.h>
+#include <mach/qdsp5v2/mp3_funcs.h>
+#include <mach/debug_mm.h>
+
+long mp3_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	MM_DBG("mp3_ioctl() cmd = %d\b", cmd);
+
+	return -EINVAL;
+}
+
+void audpp_cmd_cfg_mp3_params(struct audio *audio)
+{
+	struct audpp_cmd_cfg_adec_params_mp3 cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_MP3_LEN;
+	cmd.common.dec_id = audio->dec_id;
+	cmd.common.input_sampling_frequency = audio->out_sample_rate;
+
+	audpp_send_queue2(&cmd, sizeof(cmd));
+}
diff --git a/arch/arm/mach-msm/qdsp5v2/pcm_funcs.c b/arch/arm/mach-msm/qdsp5v2/pcm_funcs.c
new file mode 100644
index 0000000..d7935a7
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/pcm_funcs.c
@@ -0,0 +1,47 @@
+/* Copyright (c) 2010, 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/fs.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+
+#include <linux/msm_audio.h>
+
+#include <mach/qdsp5v2/qdsp5audppmsg.h>
+#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
+#include <mach/qdsp5v2/qdsp5audplaymsg.h>
+#include <mach/qdsp5v2/audpp.h>
+#include <mach/qdsp5v2/codec_utils.h>
+#include <mach/qdsp5v2/pcm_funcs.h>
+#include <mach/debug_mm.h>
+
+long pcm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	MM_DBG("pcm_ioctl() cmd = %d\n", cmd);
+
+	return -EINVAL;
+}
+
+void audpp_cmd_cfg_pcm_params(struct audio *audio)
+{
+	struct audpp_cmd_cfg_adec_params_wav cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_WAV_LEN >> 1;
+	cmd.common.dec_id = audio->dec_id;
+	cmd.common.input_sampling_frequency = audio->out_sample_rate;
+	cmd.stereo_cfg = audio->out_channel_mode;
+	cmd.pcm_width = audio->out_bits;
+	cmd.sign = 0;
+	audpp_send_queue2(&cmd, sizeof(cmd));
+}
diff --git a/arch/arm/mach-msm/qdsp5v2/snddev_data_marimba.c b/arch/arm/mach-msm/qdsp5v2/snddev_data_marimba.c
new file mode 100644
index 0000000..b15d4c4
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/snddev_data_marimba.c
@@ -0,0 +1,1537 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/mfd/msm-adie-codec.h>
+#include <linux/uaccess.h>
+#include <mach/qdsp5v2/snddev_icodec.h>
+#include <mach/qdsp5v2/marimba_profile.h>
+#include <mach/qdsp5v2/aux_pcm.h>
+#include <mach/qdsp5v2/snddev_ecodec.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/qdsp5v2/snddev_virtual.h>
+#include <mach/board.h>
+#include <asm/mach-types.h>
+#include <mach/gpio.h>
+#include <mach/qdsp5v2/snddev_mi2s.h>
+#include <mach/qdsp5v2/mi2s.h>
+#include <mach/qdsp5v2/audio_acdb_def.h>
+
+/* define the value for BT_SCO */
+#define BT_SCO_PCM_CTL_VAL (PCM_CTL__RPCM_WIDTH__LINEAR_V |\
+				PCM_CTL__TPCM_WIDTH__LINEAR_V)
+#define BT_SCO_DATA_FORMAT_PADDING (DATA_FORMAT_PADDING_INFO__RPCM_FORMAT_V |\
+				DATA_FORMAT_PADDING_INFO__TPCM_FORMAT_V)
+#define BT_SCO_AUX_CODEC_INTF   AUX_CODEC_INTF_CTL__PCMINTF_DATA_EN_V
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *debugfs_hsed_config;
+static void snddev_hsed_config_modify_setting(int type);
+static void snddev_hsed_config_restore_setting(void);
+#endif
+
+static struct adie_codec_action_unit iearpiece_48KHz_osr256_actions[] =
+	HANDSET_RX_48000_OSR_256;
+
+static struct adie_codec_hwsetting_entry iearpiece_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = iearpiece_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(iearpiece_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile iearpiece_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = iearpiece_settings,
+	.setting_sz = ARRAY_SIZE(iearpiece_settings),
+};
+
+static struct snddev_icodec_data snddev_iearpiece_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE),
+	.name = "handset_rx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_HANDSET_SPKR,
+	.profile = &iearpiece_profile,
+	.channel_mode = 1,
+	.pmctl_id = NULL,
+	.pmctl_id_sz = 0,
+	.default_sample_rate = 48000,
+	.pamp_on = NULL,
+	.pamp_off = NULL,
+	.property = SIDE_TONE_MASK,
+	.max_voice_rx_vol[VOC_NB_INDEX] = -200,
+	.min_voice_rx_vol[VOC_NB_INDEX] = -1700,
+	.max_voice_rx_vol[VOC_WB_INDEX] = -200,
+	.min_voice_rx_vol[VOC_WB_INDEX] = -1700
+};
+
+static struct platform_device msm_iearpiece_device = {
+	.name = "snddev_icodec",
+	.id = 0,
+	.dev = { .platform_data = &snddev_iearpiece_data },
+};
+
+static struct adie_codec_action_unit imic_8KHz_osr256_actions[] =
+	HANDSET_TX_8000_OSR_256;
+
+static struct adie_codec_action_unit imic_16KHz_osr256_actions[] =
+	HANDSET_TX_16000_OSR_256;
+
+static struct adie_codec_action_unit imic_48KHz_osr256_actions[] =
+	HANDSET_TX_48000_OSR_256;
+
+static struct adie_codec_hwsetting_entry imic_settings[] = {
+	{
+		.freq_plan = 8000,
+		.osr = 256,
+		.actions = imic_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(imic_8KHz_osr256_actions),
+	},
+	{
+		.freq_plan = 16000,
+		.osr = 256,
+		.actions = imic_16KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(imic_16KHz_osr256_actions),
+	},
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = imic_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(imic_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile imic_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = imic_settings,
+	.setting_sz = ARRAY_SIZE(imic_settings),
+};
+
+static enum hsed_controller imic_pmctl_id[] = {PM_HSED_CONTROLLER_0};
+
+static struct snddev_icodec_data snddev_imic_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "handset_tx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_HANDSET_MIC,
+	.profile = &imic_profile,
+	.channel_mode = 1,
+	.pmctl_id = imic_pmctl_id,
+	.pmctl_id_sz = ARRAY_SIZE(imic_pmctl_id),
+	.default_sample_rate = 48000,
+	.pamp_on = NULL,
+	.pamp_off = NULL,
+};
+
+static struct platform_device msm_imic_device = {
+	.name = "snddev_icodec",
+	.id = 1,
+	.dev = { .platform_data = &snddev_imic_data },
+};
+
+static struct adie_codec_action_unit ihs_stereo_rx_48KHz_osr256_actions[] =
+	HEADSET_STEREO_RX_LEGACY_48000_OSR_256;
+
+static struct adie_codec_hwsetting_entry ihs_stereo_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ihs_stereo_rx_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(ihs_stereo_rx_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile ihs_stereo_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ihs_stereo_rx_settings,
+	.setting_sz = ARRAY_SIZE(ihs_stereo_rx_settings),
+};
+
+static struct snddev_icodec_data snddev_ihs_stereo_rx_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE),
+	.name = "headset_stereo_rx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_HEADSET_SPKR_STEREO,
+	.profile = &ihs_stereo_rx_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pamp_on = NULL,
+	.pamp_off = NULL,
+	.property = SIDE_TONE_MASK,
+	.max_voice_rx_vol[VOC_NB_INDEX] = -700,
+	.min_voice_rx_vol[VOC_NB_INDEX] = -2200,
+	.max_voice_rx_vol[VOC_WB_INDEX] = -900,
+	.min_voice_rx_vol[VOC_WB_INDEX] = -2400
+};
+
+static struct platform_device msm_ihs_stereo_rx_device = {
+	.name = "snddev_icodec",
+	.id = 2,
+	.dev = { .platform_data = &snddev_ihs_stereo_rx_data },
+};
+
+static struct adie_codec_action_unit ihs_mono_rx_48KHz_osr256_actions[] =
+	HEADSET_RX_LEGACY_48000_OSR_256;
+
+static struct adie_codec_hwsetting_entry ihs_mono_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ihs_mono_rx_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(ihs_mono_rx_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile ihs_mono_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ihs_mono_rx_settings,
+	.setting_sz = ARRAY_SIZE(ihs_mono_rx_settings),
+};
+
+static struct snddev_icodec_data snddev_ihs_mono_rx_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE),
+	.name = "headset_mono_rx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_HEADSET_SPKR_MONO,
+	.profile = &ihs_mono_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = NULL,
+	.pamp_off = NULL,
+	.property = SIDE_TONE_MASK,
+	.max_voice_rx_vol[VOC_NB_INDEX] = -700,
+	.min_voice_rx_vol[VOC_NB_INDEX] = -2200,
+	.max_voice_rx_vol[VOC_WB_INDEX] = -900,
+	.min_voice_rx_vol[VOC_WB_INDEX] = -2400,
+
+};
+
+static struct platform_device msm_ihs_mono_rx_device = {
+	.name = "snddev_icodec",
+	.id = 3,
+	.dev = { .platform_data = &snddev_ihs_mono_rx_data },
+};
+
+static struct adie_codec_action_unit ihs_ffa_stereo_rx_48KHz_osr256_actions[] =
+	HEADSET_STEREO_RX_CAPLESS_48000_OSR_256;
+
+static struct adie_codec_hwsetting_entry ihs_ffa_stereo_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ihs_ffa_stereo_rx_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(ihs_ffa_stereo_rx_48KHz_osr256_actions),
+	}
+};
+
+#ifdef CONFIG_DEBUG_FS
+static struct adie_codec_action_unit
+	ihs_ffa_stereo_rx_class_d_legacy_48KHz_osr256_actions[] =
+	HEADSET_STEREO_RX_CLASS_D_LEGACY_48000_OSR_256;
+
+static struct adie_codec_hwsetting_entry
+	ihs_ffa_stereo_rx_class_d_legacy_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions =
+		ihs_ffa_stereo_rx_class_d_legacy_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE
+		(ihs_ffa_stereo_rx_class_d_legacy_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_action_unit
+	ihs_ffa_stereo_rx_class_ab_legacy_48KHz_osr256_actions[] =
+	HEADSET_STEREO_RX_LEGACY_48000_OSR_256;
+
+static struct adie_codec_hwsetting_entry
+	ihs_ffa_stereo_rx_class_ab_legacy_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions =
+		ihs_ffa_stereo_rx_class_ab_legacy_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE
+		(ihs_ffa_stereo_rx_class_ab_legacy_48KHz_osr256_actions),
+	}
+};
+#endif
+
+static struct adie_codec_dev_profile ihs_ffa_stereo_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ihs_ffa_stereo_rx_settings,
+	.setting_sz = ARRAY_SIZE(ihs_ffa_stereo_rx_settings),
+};
+
+static struct snddev_icodec_data snddev_ihs_ffa_stereo_rx_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE),
+	.name = "headset_stereo_rx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_HEADSET_SPKR_STEREO,
+	.profile = &ihs_ffa_stereo_rx_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.voltage_on = msm_snddev_hsed_voltage_on,
+	.voltage_off = msm_snddev_hsed_voltage_off,
+	.max_voice_rx_vol[VOC_NB_INDEX] = -700,
+	.min_voice_rx_vol[VOC_NB_INDEX] = -2200,
+	.max_voice_rx_vol[VOC_WB_INDEX] = -900,
+	.min_voice_rx_vol[VOC_WB_INDEX] = -2400,
+};
+
+static struct platform_device msm_ihs_ffa_stereo_rx_device = {
+	.name = "snddev_icodec",
+	.id = 4,
+	.dev = { .platform_data = &snddev_ihs_ffa_stereo_rx_data },
+};
+
+static struct adie_codec_action_unit ihs_ffa_mono_rx_48KHz_osr256_actions[] =
+	HEADSET_RX_CAPLESS_48000_OSR_256;
+
+static struct adie_codec_hwsetting_entry ihs_ffa_mono_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ihs_ffa_mono_rx_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(ihs_ffa_mono_rx_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile ihs_ffa_mono_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ihs_ffa_mono_rx_settings,
+	.setting_sz = ARRAY_SIZE(ihs_ffa_mono_rx_settings),
+};
+
+static struct snddev_icodec_data snddev_ihs_ffa_mono_rx_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE),
+	.name = "headset_mono_rx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_HEADSET_SPKR_MONO,
+	.profile = &ihs_ffa_mono_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_hsed_voltage_on,
+	.pamp_off = msm_snddev_hsed_voltage_off,
+	.max_voice_rx_vol[VOC_NB_INDEX] = -700,
+	.min_voice_rx_vol[VOC_NB_INDEX] = -2200,
+	.max_voice_rx_vol[VOC_WB_INDEX] = -900,
+	.min_voice_rx_vol[VOC_WB_INDEX] = -2400,
+};
+
+static struct platform_device msm_ihs_ffa_mono_rx_device = {
+	.name = "snddev_icodec",
+	.id = 5,
+	.dev = { .platform_data = &snddev_ihs_ffa_mono_rx_data },
+};
+
+static struct adie_codec_action_unit ihs_mono_tx_8KHz_osr256_actions[] =
+	HEADSET_MONO_TX_8000_OSR_256;
+
+static struct adie_codec_action_unit ihs_mono_tx_16KHz_osr256_actions[] =
+	HEADSET_MONO_TX_16000_OSR_256;
+
+static struct adie_codec_action_unit ihs_mono_tx_48KHz_osr256_actions[] =
+	HEADSET_MONO_TX_48000_OSR_256;
+
+static struct adie_codec_hwsetting_entry ihs_mono_tx_settings[] = {
+	{
+		.freq_plan = 8000,
+		.osr = 256,
+		.actions = ihs_mono_tx_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(ihs_mono_tx_8KHz_osr256_actions),
+	},
+	{
+		.freq_plan = 16000,
+		.osr = 256,
+		.actions = ihs_mono_tx_16KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(ihs_mono_tx_16KHz_osr256_actions),
+	},
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ihs_mono_tx_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(ihs_mono_tx_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile ihs_mono_tx_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = ihs_mono_tx_settings,
+	.setting_sz = ARRAY_SIZE(ihs_mono_tx_settings),
+};
+
+static struct snddev_icodec_data snddev_ihs_mono_tx_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "headset_mono_tx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_HEADSET_MIC,
+	.profile = &ihs_mono_tx_profile,
+	.channel_mode = 1,
+	.pmctl_id = NULL,
+	.pmctl_id_sz = 0,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_tx_route_config,
+	.pamp_off = msm_snddev_tx_route_deconfig,
+};
+
+static struct platform_device msm_ihs_mono_tx_device = {
+	.name = "snddev_icodec",
+	.id = 6,
+	.dev = { .platform_data = &snddev_ihs_mono_tx_data },
+};
+
+static struct adie_codec_action_unit ifmradio_handset_osr64_actions[] =
+	FM_HANDSET_OSR_64;
+
+static struct adie_codec_hwsetting_entry ifmradio_handset_settings[] = {
+	{
+		.freq_plan = 8000,
+		.osr = 256,
+		.actions = ifmradio_handset_osr64_actions,
+		.action_sz = ARRAY_SIZE(ifmradio_handset_osr64_actions),
+	}
+};
+
+static struct adie_codec_dev_profile ifmradio_handset_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ifmradio_handset_settings,
+	.setting_sz = ARRAY_SIZE(ifmradio_handset_settings),
+};
+
+static struct snddev_icodec_data snddev_ifmradio_handset_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_FM),
+	.name = "fmradio_handset_rx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_LP_FM_SPKR_PHONE_STEREO_RX,
+	.profile = &ifmradio_handset_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 8000,
+	.pamp_on = NULL,
+	.pamp_off = NULL,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device msm_ifmradio_handset_device = {
+	.name = "snddev_icodec",
+	.id = 7,
+	.dev = { .platform_data = &snddev_ifmradio_handset_data },
+};
+
+
+static struct adie_codec_action_unit ispeaker_rx_48KHz_osr256_actions[] =
+   SPEAKER_STEREO_RX_48000_OSR_256;
+
+static struct adie_codec_hwsetting_entry ispeaker_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ispeaker_rx_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(ispeaker_rx_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile ispeaker_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ispeaker_rx_settings,
+	.setting_sz = ARRAY_SIZE(ispeaker_rx_settings),
+};
+
+static struct snddev_icodec_data snddev_ispeaker_rx_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE),
+	.name = "speaker_stereo_rx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_SPKR_PHONE_STEREO,
+	.profile = &ispeaker_rx_profile,
+	.channel_mode = 2,
+	.pmctl_id = NULL,
+	.pmctl_id_sz = 0,
+	.default_sample_rate = 48000,
+	.pamp_on = &msm_snddev_poweramp_on,
+	.pamp_off = &msm_snddev_poweramp_off,
+	.max_voice_rx_vol[VOC_NB_INDEX] = 1000,
+	.min_voice_rx_vol[VOC_NB_INDEX] = -500,
+	.max_voice_rx_vol[VOC_WB_INDEX] = 1000,
+	.min_voice_rx_vol[VOC_WB_INDEX] = -500,
+};
+
+static struct platform_device msm_ispeaker_rx_device = {
+	.name = "snddev_icodec",
+	.id = 8,
+	.dev = { .platform_data = &snddev_ispeaker_rx_data },
+
+};
+
+static struct adie_codec_action_unit ifmradio_speaker_osr64_actions[] =
+	FM_SPEAKER_OSR_64;
+
+static struct adie_codec_hwsetting_entry ifmradio_speaker_settings[] = {
+	{
+		.freq_plan = 8000,
+		.osr = 256,
+		.actions = ifmradio_speaker_osr64_actions,
+		.action_sz = ARRAY_SIZE(ifmradio_speaker_osr64_actions),
+	}
+};
+
+static struct adie_codec_dev_profile ifmradio_speaker_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ifmradio_speaker_settings,
+	.setting_sz = ARRAY_SIZE(ifmradio_speaker_settings),
+};
+
+static struct snddev_icodec_data snddev_ifmradio_speaker_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_FM),
+	.name = "fmradio_speaker_rx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_LP_FM_SPKR_PHONE_STEREO_RX,
+	.profile = &ifmradio_speaker_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 8000,
+	.pamp_on = &msm_snddev_poweramp_on,
+	.pamp_off = &msm_snddev_poweramp_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device msm_ifmradio_speaker_device = {
+	.name = "snddev_icodec",
+	.id = 9,
+	.dev = { .platform_data = &snddev_ifmradio_speaker_data },
+};
+
+static struct adie_codec_action_unit ifmradio_headset_osr64_actions[] =
+	FM_HEADSET_STEREO_CLASS_D_LEGACY_OSR_64;
+
+static struct adie_codec_hwsetting_entry ifmradio_headset_settings[] = {
+	{
+		.freq_plan = 8000,
+		.osr = 256,
+		.actions = ifmradio_headset_osr64_actions,
+		.action_sz = ARRAY_SIZE(ifmradio_headset_osr64_actions),
+	}
+};
+
+static struct adie_codec_dev_profile ifmradio_headset_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ifmradio_headset_settings,
+	.setting_sz = ARRAY_SIZE(ifmradio_headset_settings),
+};
+
+static struct snddev_icodec_data snddev_ifmradio_headset_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_FM),
+	.name = "fmradio_headset_rx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_LP_FM_HEADSET_SPKR_STEREO_RX,
+	.profile = &ifmradio_headset_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 8000,
+	.pamp_on = NULL,
+	.pamp_off = NULL,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device msm_ifmradio_headset_device = {
+	.name = "snddev_icodec",
+	.id = 10,
+	.dev = { .platform_data = &snddev_ifmradio_headset_data },
+};
+
+
+static struct adie_codec_action_unit ifmradio_ffa_headset_osr64_actions[] =
+	FM_HEADSET_CLASS_AB_STEREO_CAPLESS_OSR_64;
+
+static struct adie_codec_hwsetting_entry ifmradio_ffa_headset_settings[] = {
+	{
+		.freq_plan = 8000,
+		.osr = 256,
+		.actions = ifmradio_ffa_headset_osr64_actions,
+		.action_sz = ARRAY_SIZE(ifmradio_ffa_headset_osr64_actions),
+	}
+};
+
+static struct adie_codec_dev_profile ifmradio_ffa_headset_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ifmradio_ffa_headset_settings,
+	.setting_sz = ARRAY_SIZE(ifmradio_ffa_headset_settings),
+};
+
+static struct snddev_icodec_data snddev_ifmradio_ffa_headset_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_FM),
+	.name = "fmradio_headset_rx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_LP_FM_HEADSET_SPKR_STEREO_RX,
+	.profile = &ifmradio_ffa_headset_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 8000,
+	.pamp_on = msm_snddev_hsed_voltage_on,
+	.pamp_off = msm_snddev_hsed_voltage_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device msm_ifmradio_ffa_headset_device = {
+	.name = "snddev_icodec",
+	.id = 11,
+	.dev = { .platform_data = &snddev_ifmradio_ffa_headset_data },
+};
+
+static struct snddev_ecodec_data snddev_bt_sco_earpiece_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE),
+	.name = "bt_sco_rx",
+	.copp_id = 1,
+	.acdb_id = ACDB_ID_BT_SCO_SPKR,
+	.channel_mode = 1,
+	.conf_pcm_ctl_val = BT_SCO_PCM_CTL_VAL,
+	.conf_aux_codec_intf = BT_SCO_AUX_CODEC_INTF,
+	.conf_data_format_padding_val = BT_SCO_DATA_FORMAT_PADDING,
+	.max_voice_rx_vol[VOC_NB_INDEX] = 400,
+	.min_voice_rx_vol[VOC_NB_INDEX] = -1100,
+	.max_voice_rx_vol[VOC_WB_INDEX] = 400,
+	.min_voice_rx_vol[VOC_WB_INDEX] = -1100,
+};
+
+static struct snddev_ecodec_data snddev_bt_sco_mic_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "bt_sco_tx",
+	.copp_id = 1,
+	.acdb_id = ACDB_ID_BT_SCO_MIC,
+	.channel_mode = 1,
+	.conf_pcm_ctl_val = BT_SCO_PCM_CTL_VAL,
+	.conf_aux_codec_intf = BT_SCO_AUX_CODEC_INTF,
+	.conf_data_format_padding_val = BT_SCO_DATA_FORMAT_PADDING,
+};
+
+struct platform_device msm_bt_sco_earpiece_device = {
+	.name = "msm_snddev_ecodec",
+	.id = 0,
+	.dev = { .platform_data = &snddev_bt_sco_earpiece_data },
+};
+
+struct platform_device msm_bt_sco_mic_device = {
+	.name = "msm_snddev_ecodec",
+	.id = 1,
+	.dev = { .platform_data = &snddev_bt_sco_mic_data },
+};
+
+static struct adie_codec_action_unit idual_mic_endfire_8KHz_osr256_actions[] =
+	MIC1_LEFT_LINE_IN_RIGHT_8000_OSR_256;
+
+static struct adie_codec_hwsetting_entry idual_mic_endfire_settings[] = {
+	{
+		.freq_plan = 8000,
+		.osr = 256,
+		.actions = idual_mic_endfire_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(idual_mic_endfire_8KHz_osr256_actions),
+	}, /* 8KHz profile can be used for 16KHz */
+	{
+		.freq_plan = 16000,
+		.osr = 256,
+		.actions = idual_mic_endfire_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(idual_mic_endfire_8KHz_osr256_actions),
+	}, /* 8KHz profile can be used for 48KHz */
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = idual_mic_endfire_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(idual_mic_endfire_8KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile idual_mic_endfire_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = idual_mic_endfire_settings,
+	.setting_sz = ARRAY_SIZE(idual_mic_endfire_settings),
+};
+
+static enum hsed_controller idual_mic_endfire_pmctl_id[] = {
+	PM_HSED_CONTROLLER_0, PM_HSED_CONTROLLER_2
+};
+
+static struct snddev_icodec_data snddev_idual_mic_endfire_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "handset_dual_mic_endfire_tx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_HANDSET_MIC_ENDFIRE,
+	.profile = &idual_mic_endfire_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pmctl_id = idual_mic_endfire_pmctl_id,
+	.pmctl_id_sz = ARRAY_SIZE(idual_mic_endfire_pmctl_id),
+	.pamp_on = NULL,
+	.pamp_off = NULL,
+};
+
+static struct platform_device msm_idual_mic_endfire_device = {
+	.name = "snddev_icodec",
+	.id = 12,
+	.dev = { .platform_data = &snddev_idual_mic_endfire_data },
+};
+
+
+static struct snddev_icodec_data\
+		snddev_idual_mic_endfire_real_stereo_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "handset_dual_mic_endfire_tx_real_stereo",
+	.copp_id = 0,
+	.acdb_id = PSEUDO_ACDB_ID,
+	.profile = &idual_mic_endfire_profile,
+	.channel_mode = REAL_STEREO_CHANNEL_MODE,
+	.default_sample_rate = 48000,
+	.pmctl_id = idual_mic_endfire_pmctl_id,
+	.pmctl_id_sz = ARRAY_SIZE(idual_mic_endfire_pmctl_id),
+	.pamp_on = NULL,
+	.pamp_off = NULL,
+};
+
+static struct platform_device msm_real_stereo_tx_device = {
+	.name = "snddev_icodec",
+	.id = 26,
+	.dev = { .platform_data =
+			&snddev_idual_mic_endfire_real_stereo_data },
+};
+
+static struct adie_codec_action_unit idual_mic_bs_8KHz_osr256_actions[] =
+	MIC1_LEFT_AUX_IN_RIGHT_8000_OSR_256;
+
+static struct adie_codec_hwsetting_entry idual_mic_broadside_settings[] = {
+	{
+		.freq_plan = 8000,
+		.osr = 256,
+		.actions = idual_mic_bs_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(idual_mic_bs_8KHz_osr256_actions),
+	}, /* 8KHz profile can be used for 16KHz */
+	{
+		.freq_plan = 16000,
+		.osr = 256,
+		.actions = idual_mic_bs_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(idual_mic_bs_8KHz_osr256_actions),
+	}, /* 8KHz profile can be used for 16KHz */
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = idual_mic_bs_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(idual_mic_bs_8KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile idual_mic_broadside_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = idual_mic_broadside_settings,
+	.setting_sz = ARRAY_SIZE(idual_mic_broadside_settings),
+};
+
+static enum hsed_controller idual_mic_broadside_pmctl_id[] = {
+	PM_HSED_CONTROLLER_0, PM_HSED_CONTROLLER_2
+};
+
+static struct snddev_icodec_data snddev_idual_mic_broadside_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "handset_dual_mic_broadside_tx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_HANDSET_MIC_BROADSIDE,
+	.profile = &idual_mic_broadside_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pmctl_id = idual_mic_broadside_pmctl_id,
+	.pmctl_id_sz = ARRAY_SIZE(idual_mic_broadside_pmctl_id),
+	.pamp_on = NULL,
+	.pamp_off = NULL,
+};
+
+static struct platform_device msm_idual_mic_broadside_device = {
+	.name = "snddev_icodec",
+	.id = 13,
+	.dev = { .platform_data = &snddev_idual_mic_broadside_data },
+};
+
+static struct adie_codec_action_unit ispk_dual_mic_ef_8KHz_osr256_actions[] =
+	SPEAKER_MIC1_LEFT_LINE_IN_RIGHT_8000_OSR_256;
+
+static struct adie_codec_hwsetting_entry ispk_dual_mic_ef_settings[] = {
+	{
+		.freq_plan = 8000,
+		.osr = 256,
+		.actions = ispk_dual_mic_ef_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(ispk_dual_mic_ef_8KHz_osr256_actions),
+	}, /* 8KHz profile can be used for 16Khz */
+	{
+		.freq_plan = 16000,
+		.osr = 256,
+		.actions = ispk_dual_mic_ef_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(ispk_dual_mic_ef_8KHz_osr256_actions),
+	}, /* 8KHz profile can be used for 48KHz */
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ispk_dual_mic_ef_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(ispk_dual_mic_ef_8KHz_osr256_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ispk_dual_mic_ef_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = ispk_dual_mic_ef_settings,
+	.setting_sz = ARRAY_SIZE(ispk_dual_mic_ef_settings),
+};
+
+static struct snddev_icodec_data snddev_spk_idual_mic_endfire_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "speaker_dual_mic_endfire_tx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_SPKR_PHONE_MIC_ENDFIRE,
+	.profile = &ispk_dual_mic_ef_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pmctl_id = idual_mic_endfire_pmctl_id,
+	.pmctl_id_sz = ARRAY_SIZE(idual_mic_endfire_pmctl_id),
+	.pamp_on = NULL,
+	.pamp_off = NULL,
+};
+
+static struct platform_device msm_spk_idual_mic_endfire_device = {
+	.name = "snddev_icodec",
+	.id = 14,
+	.dev = { .platform_data = &snddev_spk_idual_mic_endfire_data },
+};
+
+static struct adie_codec_action_unit ispk_dual_mic_bs_8KHz_osr256_actions[] =
+	SPEAKER_MIC1_LEFT_AUX_IN_RIGHT_8000_OSR_256;
+
+static struct adie_codec_hwsetting_entry ispk_dual_mic_bs_settings[] = {
+	{
+		.freq_plan = 8000,
+		.osr = 256,
+		.actions = ispk_dual_mic_bs_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(ispk_dual_mic_bs_8KHz_osr256_actions),
+	}, /* 8KHz profile can be used for 16Khz */
+	{
+		.freq_plan = 16000,
+		.osr = 256,
+		.actions = ispk_dual_mic_bs_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(ispk_dual_mic_bs_8KHz_osr256_actions),
+	}, /* 8KHz profile can be used for 48KHz */
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ispk_dual_mic_bs_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(ispk_dual_mic_bs_8KHz_osr256_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ispk_dual_mic_bs_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = ispk_dual_mic_bs_settings,
+	.setting_sz = ARRAY_SIZE(ispk_dual_mic_bs_settings),
+};
+static struct snddev_icodec_data snddev_spk_idual_mic_broadside_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "speaker_dual_mic_broadside_tx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_SPKR_PHONE_MIC_BROADSIDE,
+	.profile = &ispk_dual_mic_bs_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pmctl_id = idual_mic_broadside_pmctl_id,
+	.pmctl_id_sz = ARRAY_SIZE(idual_mic_broadside_pmctl_id),
+	.pamp_on = NULL,
+	.pamp_off = NULL,
+};
+
+static struct platform_device msm_spk_idual_mic_broadside_device = {
+	.name = "snddev_icodec",
+	.id = 15,
+	.dev = { .platform_data = &snddev_spk_idual_mic_broadside_data },
+};
+
+static struct adie_codec_action_unit itty_hs_mono_tx_8KHz_osr256_actions[] =
+	TTY_HEADSET_MONO_TX_8000_OSR_256;
+
+static struct adie_codec_hwsetting_entry itty_hs_mono_tx_settings[] = {
+	/* 8KHz, 16KHz, 48KHz TTY Tx devices can shared same set of actions */
+	{
+		.freq_plan = 8000,
+		.osr = 256,
+		.actions = itty_hs_mono_tx_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(itty_hs_mono_tx_8KHz_osr256_actions),
+	},
+	{
+		.freq_plan = 16000,
+		.osr = 256,
+		.actions = itty_hs_mono_tx_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(itty_hs_mono_tx_8KHz_osr256_actions),
+	},
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = itty_hs_mono_tx_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(itty_hs_mono_tx_8KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile itty_hs_mono_tx_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = itty_hs_mono_tx_settings,
+	.setting_sz = ARRAY_SIZE(itty_hs_mono_tx_settings),
+};
+
+static struct snddev_icodec_data snddev_itty_hs_mono_tx_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE | SNDDEV_CAP_TTY),
+	.name = "tty_headset_mono_tx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_TTY_HEADSET_MIC,
+	.profile = &itty_hs_mono_tx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pmctl_id = NULL,
+	.pmctl_id_sz = 0,
+	.pamp_on = NULL,
+	.pamp_off = NULL,
+};
+
+static struct platform_device msm_itty_hs_mono_tx_device = {
+	.name = "snddev_icodec",
+	.id = 16,
+	.dev = { .platform_data = &snddev_itty_hs_mono_tx_data },
+};
+
+static struct adie_codec_action_unit itty_hs_mono_rx_8KHz_osr256_actions[] =
+	TTY_HEADSET_MONO_RX_CLASS_D_8000_OSR_256;
+
+static struct adie_codec_action_unit itty_hs_mono_rx_16KHz_osr256_actions[] =
+	TTY_HEADSET_MONO_RX_CLASS_D_16000_OSR_256;
+
+static struct adie_codec_action_unit itty_hs_mono_rx_48KHz_osr256_actions[] =
+	TTY_HEADSET_MONO_RX_CLASS_D_48000_OSR_256;
+
+static struct adie_codec_hwsetting_entry itty_hs_mono_rx_settings[] = {
+	{
+		.freq_plan = 8000,
+		.osr = 256,
+		.actions = itty_hs_mono_rx_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(itty_hs_mono_rx_8KHz_osr256_actions),
+	},
+	{
+		.freq_plan = 16000,
+		.osr = 256,
+		.actions = itty_hs_mono_rx_16KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(itty_hs_mono_rx_16KHz_osr256_actions),
+	},
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = itty_hs_mono_rx_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(itty_hs_mono_rx_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile itty_hs_mono_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = itty_hs_mono_rx_settings,
+	.setting_sz = ARRAY_SIZE(itty_hs_mono_rx_settings),
+};
+
+static struct snddev_icodec_data snddev_itty_hs_mono_rx_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE | SNDDEV_CAP_TTY),
+	.name = "tty_headset_mono_rx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_TTY_HEADSET_SPKR,
+	.profile = &itty_hs_mono_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = NULL,
+	.pamp_off = NULL,
+	.max_voice_rx_vol[VOC_NB_INDEX] = 0,
+	.min_voice_rx_vol[VOC_NB_INDEX] = 0,
+	.max_voice_rx_vol[VOC_WB_INDEX] = 0,
+	.min_voice_rx_vol[VOC_WB_INDEX] = 0,
+};
+
+static struct platform_device msm_itty_hs_mono_rx_device = {
+	.name = "snddev_icodec",
+	.id = 17,
+	.dev = { .platform_data = &snddev_itty_hs_mono_rx_data },
+};
+
+static struct adie_codec_action_unit ispeaker_tx_8KHz_osr256_actions[] =
+	SPEAKER_TX_8000_OSR_256;
+
+static struct adie_codec_action_unit ispeaker_tx_48KHz_osr256_actions[] =
+	SPEAKER_TX_48000_OSR_256;
+
+static struct adie_codec_hwsetting_entry ispeaker_tx_settings[] = {
+	{
+		.freq_plan = 8000,
+		.osr = 256,
+		.actions = ispeaker_tx_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(ispeaker_tx_8KHz_osr256_actions),
+	},
+	{ /* 8KHz profile is good for 16KHz */
+		.freq_plan = 16000,
+		.osr = 256,
+		.actions = ispeaker_tx_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(ispeaker_tx_8KHz_osr256_actions),
+	},
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ispeaker_tx_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(ispeaker_tx_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile ispeaker_tx_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = ispeaker_tx_settings,
+	.setting_sz = ARRAY_SIZE(ispeaker_tx_settings),
+};
+
+static enum hsed_controller ispk_pmctl_id[] = {PM_HSED_CONTROLLER_0};
+
+static struct snddev_icodec_data snddev_ispeaker_tx_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "speaker_mono_tx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_SPKR_PHONE_MIC,
+	.profile = &ispeaker_tx_profile,
+	.channel_mode = 1,
+	.pmctl_id = ispk_pmctl_id,
+	.pmctl_id_sz = ARRAY_SIZE(ispk_pmctl_id),
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_tx_route_config,
+	.pamp_off = msm_snddev_tx_route_deconfig,
+};
+
+static struct platform_device msm_ispeaker_tx_device = {
+	.name = "snddev_icodec",
+	.id = 18,
+	.dev = { .platform_data = &snddev_ispeaker_tx_data },
+};
+
+static struct adie_codec_action_unit iearpiece_ffa_48KHz_osr256_actions[] =
+	HANDSET_RX_48000_OSR_256_FFA;
+
+static struct adie_codec_hwsetting_entry iearpiece_ffa_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = iearpiece_ffa_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(iearpiece_ffa_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile iearpiece_ffa_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = iearpiece_ffa_settings,
+	.setting_sz = ARRAY_SIZE(iearpiece_ffa_settings),
+};
+
+static struct snddev_icodec_data snddev_iearpiece_ffa_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE),
+	.name = "handset_rx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_HANDSET_SPKR,
+	.profile = &iearpiece_ffa_profile,
+	.channel_mode = 1,
+	.pmctl_id = NULL,
+	.pmctl_id_sz = 0,
+	.default_sample_rate = 48000,
+	.pamp_on = NULL,
+	.pamp_off = NULL,
+	.max_voice_rx_vol[VOC_NB_INDEX] = -700,
+	.min_voice_rx_vol[VOC_NB_INDEX] = -2200,
+	.max_voice_rx_vol[VOC_WB_INDEX] = -1400,
+	.min_voice_rx_vol[VOC_WB_INDEX] = -2900,
+};
+
+static struct platform_device msm_iearpiece_ffa_device = {
+	.name = "snddev_icodec",
+	.id = 19,
+	.dev = { .platform_data = &snddev_iearpiece_ffa_data },
+};
+
+static struct adie_codec_action_unit imic_ffa_8KHz_osr256_actions[] =
+	HANDSET_TX_8000_OSR_256_FFA;
+
+static struct adie_codec_action_unit imic_ffa_16KHz_osr256_actions[] =
+	HANDSET_TX_16000_OSR_256_FFA;
+
+static struct adie_codec_action_unit imic_ffa_48KHz_osr256_actions[] =
+	HANDSET_TX_48000_OSR_256_FFA;
+
+static struct adie_codec_hwsetting_entry imic_ffa_settings[] = {
+	{
+		.freq_plan = 8000,
+		.osr = 256,
+		.actions = imic_ffa_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(imic_ffa_8KHz_osr256_actions),
+	},
+	{
+		.freq_plan = 16000,
+		.osr = 256,
+		.actions = imic_ffa_16KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(imic_ffa_16KHz_osr256_actions),
+	},
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = imic_ffa_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(imic_ffa_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile imic_ffa_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = imic_ffa_settings,
+	.setting_sz = ARRAY_SIZE(imic_ffa_settings),
+};
+
+static struct snddev_icodec_data snddev_imic_ffa_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "handset_tx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_HANDSET_MIC,
+	.profile = &imic_ffa_profile,
+	.channel_mode = 1,
+	.pmctl_id = imic_pmctl_id,
+	.pmctl_id_sz = ARRAY_SIZE(imic_pmctl_id),
+	.default_sample_rate = 48000,
+	.pamp_on = NULL,
+	.pamp_off = NULL,
+};
+
+static struct platform_device msm_imic_ffa_device = {
+	.name = "snddev_icodec",
+	.id = 20,
+	.dev = { .platform_data = &snddev_imic_ffa_data },
+};
+
+
+static struct adie_codec_action_unit
+	ihs_stereo_speaker_stereo_rx_48KHz_osr256_actions[] =
+	HEADSET_STEREO_SPEAKER_STEREO_RX_CAPLESS_48000_OSR_256;
+
+
+static struct adie_codec_hwsetting_entry
+	ihs_stereo_speaker_stereo_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ihs_stereo_speaker_stereo_rx_48KHz_osr256_actions,
+		.action_sz =
+		ARRAY_SIZE(ihs_stereo_speaker_stereo_rx_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile ihs_stereo_speaker_stereo_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ihs_stereo_speaker_stereo_rx_settings,
+	.setting_sz = ARRAY_SIZE(ihs_stereo_speaker_stereo_rx_settings),
+};
+
+static struct snddev_icodec_data snddev_ihs_stereo_speaker_stereo_rx_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE),
+	.name = "headset_stereo_speaker_stereo_rx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_HEADSET_STEREO_PLUS_SPKR_STEREO_RX,
+	.profile = &ihs_stereo_speaker_stereo_rx_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_poweramp_on,
+	.pamp_off = msm_snddev_poweramp_off,
+	.voltage_on = msm_snddev_hsed_voltage_on,
+	.voltage_off = msm_snddev_hsed_voltage_off,
+	.max_voice_rx_vol[VOC_NB_INDEX] = -500,
+	.min_voice_rx_vol[VOC_NB_INDEX] = -2000,
+	.max_voice_rx_vol[VOC_WB_INDEX] = -500,
+	.min_voice_rx_vol[VOC_WB_INDEX] = -2000,
+};
+
+static struct platform_device msm_ihs_stereo_speaker_stereo_rx_device = {
+	.name = "snddev_icodec",
+	.id = 21,
+	.dev = { .platform_data = &snddev_ihs_stereo_speaker_stereo_rx_data },
+};
+
+static struct snddev_mi2s_data snddev_mi2s_stereo_rx_data = {
+	.capability = SNDDEV_CAP_RX ,
+	.name = "hdmi_stereo_rx",
+	.copp_id = 3,
+	.acdb_id = ACDB_ID_HDMI,
+	.channel_mode = 2,
+	.sd_lines = MI2S_SD_0,
+	.route = msm_snddev_tx_route_config,
+	.deroute = msm_snddev_tx_route_deconfig,
+	.default_sample_rate = 48000,
+};
+
+static struct platform_device msm_snddev_mi2s_stereo_rx_device = {
+	.name = "snddev_mi2s",
+	.id = 0,
+	.dev = { .platform_data = &snddev_mi2s_stereo_rx_data },
+};
+
+
+static struct snddev_mi2s_data snddev_mi2s_fm_tx_data = {
+	.capability = SNDDEV_CAP_TX ,
+	.name = "fmradio_stereo_tx",
+	.copp_id = 2,
+	.acdb_id = ACDB_ID_FM_TX,
+	.channel_mode = 2,
+	.sd_lines = MI2S_SD_3,
+	.route = NULL,
+	.deroute = NULL,
+	.default_sample_rate = 48000,
+};
+
+static struct platform_device  msm_snddev_mi2s_fm_tx_device = {
+	.name = "snddev_mi2s",
+	.id = 1,
+	.dev = { .platform_data = &snddev_mi2s_fm_tx_data},
+};
+
+static struct snddev_icodec_data snddev_fluid_imic_tx_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "handset_tx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_SPKR_PHONE_MIC,
+	.profile = &ispeaker_tx_profile,
+	.channel_mode = 1,
+	.pmctl_id = ispk_pmctl_id,
+	.pmctl_id_sz = ARRAY_SIZE(ispk_pmctl_id),
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_tx_route_config,
+	.pamp_off = msm_snddev_tx_route_deconfig,
+};
+
+static struct platform_device msm_fluid_imic_tx_device = {
+	.name = "snddev_icodec",
+	.id = 22,
+	.dev = { .platform_data = &snddev_fluid_imic_tx_data },
+};
+
+static struct snddev_icodec_data snddev_fluid_iearpiece_rx_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE),
+	.name = "handset_rx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_SPKR_PHONE_STEREO,
+	.profile = &ispeaker_rx_profile,
+	.channel_mode = 2,
+	.pmctl_id = NULL,
+	.pmctl_id_sz = 0,
+	.default_sample_rate = 48000,
+	.pamp_on = &msm_snddev_poweramp_on,
+	.pamp_off = &msm_snddev_poweramp_off,
+	.max_voice_rx_vol[VOC_NB_INDEX] = -500,
+	.min_voice_rx_vol[VOC_NB_INDEX] = -1000,
+	.max_voice_rx_vol[VOC_WB_INDEX] = -500,
+	.min_voice_rx_vol[VOC_WB_INDEX] = -1000,
+};
+
+static struct platform_device msm_fluid_iearpeice_rx_device = {
+	.name = "snddev_icodec",
+	.id = 23,
+	.dev = { .platform_data = &snddev_fluid_iearpiece_rx_data },
+};
+
+static struct adie_codec_action_unit fluid_idual_mic_ef_8KHz_osr256_actions[] =
+	MIC1_LEFT_AUX_IN_RIGHT_8000_OSR_256;
+
+static struct adie_codec_hwsetting_entry fluid_idual_mic_endfire_settings[] = {
+	{
+		.freq_plan = 8000,
+		.osr = 256,
+		.actions = fluid_idual_mic_ef_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(fluid_idual_mic_ef_8KHz_osr256_actions),
+	}, /* 8KHz profile can be used for 16KHz */
+	{
+		.freq_plan = 16000,
+		.osr = 256,
+		.actions = fluid_idual_mic_ef_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(fluid_idual_mic_ef_8KHz_osr256_actions),
+	}, /* 8KHz profile can also be used for 48KHz */
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = fluid_idual_mic_ef_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(fluid_idual_mic_ef_8KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile fluid_idual_mic_endfire_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = fluid_idual_mic_endfire_settings,
+	.setting_sz = ARRAY_SIZE(fluid_idual_mic_endfire_settings),
+};
+
+static enum hsed_controller fluid_idual_mic_endfire_pmctl_id[] = {
+	PM_HSED_CONTROLLER_0, PM_HSED_CONTROLLER_2
+};
+
+static struct snddev_icodec_data snddev_fluid_idual_mic_endfire_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "handset_dual_mic_endfire_tx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_SPKR_PHONE_MIC_ENDFIRE,
+	.profile = &fluid_idual_mic_endfire_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pmctl_id = fluid_idual_mic_endfire_pmctl_id,
+	.pmctl_id_sz = ARRAY_SIZE(fluid_idual_mic_endfire_pmctl_id),
+	.pamp_on = msm_snddev_tx_route_config,
+	.pamp_off = msm_snddev_tx_route_deconfig,
+};
+
+static struct platform_device msm_fluid_idual_mic_endfire_device = {
+	.name = "snddev_icodec",
+	.id = 24,
+	.dev = { .platform_data = &snddev_fluid_idual_mic_endfire_data },
+};
+
+static struct snddev_icodec_data snddev_fluid_spk_idual_mic_endfire_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "speaker_dual_mic_endfire_tx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_SPKR_PHONE_MIC_ENDFIRE,
+	.profile = &fluid_idual_mic_endfire_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pmctl_id = fluid_idual_mic_endfire_pmctl_id,
+	.pmctl_id_sz = ARRAY_SIZE(fluid_idual_mic_endfire_pmctl_id),
+	.pamp_on = msm_snddev_tx_route_config,
+	.pamp_off = msm_snddev_tx_route_deconfig,
+};
+
+static struct platform_device msm_fluid_spk_idual_mic_endfire_device = {
+	.name = "snddev_icodec",
+	.id = 25,
+	.dev = { .platform_data = &snddev_fluid_spk_idual_mic_endfire_data },
+};
+
+static struct snddev_virtual_data snddev_a2dp_tx_data = {
+	.capability = SNDDEV_CAP_TX,
+	.name = "a2dp_tx",
+	.copp_id = 5,
+	.acdb_id = PSEUDO_ACDB_ID,
+};
+
+static struct snddev_virtual_data snddev_a2dp_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "a2dp_rx",
+	.copp_id = 2,
+	.acdb_id = PSEUDO_ACDB_ID,
+};
+
+static struct platform_device msm_a2dp_rx_device = {
+	.name = "snddev_virtual",
+	.id = 0,
+	.dev = { .platform_data = &snddev_a2dp_rx_data },
+};
+
+static struct platform_device msm_a2dp_tx_device = {
+	.name = "snddev_virtual",
+	.id = 1,
+	.dev = { .platform_data = &snddev_a2dp_tx_data },
+};
+
+static struct snddev_virtual_data snddev_uplink_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "uplink_rx",
+	.copp_id = 5,
+	.acdb_id = PSEUDO_ACDB_ID,
+};
+
+static struct platform_device msm_uplink_rx_device = {
+	.name = "snddev_virtual",
+	.id = 2,
+	.dev = { .platform_data = &snddev_uplink_rx_data },
+};
+
+static struct platform_device *snd_devices_ffa[] __initdata = {
+	&msm_iearpiece_ffa_device,
+	&msm_imic_ffa_device,
+	&msm_ifmradio_handset_device,
+	&msm_ihs_ffa_stereo_rx_device,
+	&msm_ihs_ffa_mono_rx_device,
+	&msm_ihs_mono_tx_device,
+	&msm_bt_sco_earpiece_device,
+	&msm_bt_sco_mic_device,
+	&msm_ispeaker_rx_device,
+	&msm_ifmradio_speaker_device,
+	&msm_ifmradio_ffa_headset_device,
+	&msm_idual_mic_endfire_device,
+	&msm_idual_mic_broadside_device,
+	&msm_spk_idual_mic_endfire_device,
+	&msm_spk_idual_mic_broadside_device,
+	&msm_itty_hs_mono_tx_device,
+	&msm_itty_hs_mono_rx_device,
+	&msm_ispeaker_tx_device,
+	&msm_ihs_stereo_speaker_stereo_rx_device,
+	&msm_a2dp_rx_device,
+	&msm_a2dp_tx_device,
+	&msm_snddev_mi2s_stereo_rx_device,
+	&msm_snddev_mi2s_fm_tx_device,
+	&msm_uplink_rx_device,
+	&msm_real_stereo_tx_device,
+};
+
+static struct platform_device *snd_devices_surf[] __initdata = {
+	&msm_iearpiece_device,
+	&msm_imic_device,
+	&msm_ihs_stereo_rx_device,
+	&msm_ihs_mono_rx_device,
+	&msm_ihs_mono_tx_device,
+	&msm_bt_sco_earpiece_device,
+	&msm_bt_sco_mic_device,
+	&msm_ifmradio_handset_device,
+	&msm_ispeaker_rx_device,
+	&msm_ifmradio_speaker_device,
+	&msm_ifmradio_headset_device,
+	&msm_itty_hs_mono_tx_device,
+	&msm_itty_hs_mono_rx_device,
+	&msm_ispeaker_tx_device,
+	&msm_ihs_stereo_speaker_stereo_rx_device,
+	&msm_a2dp_rx_device,
+	&msm_a2dp_tx_device,
+	&msm_snddev_mi2s_stereo_rx_device,
+	&msm_snddev_mi2s_fm_tx_device,
+	&msm_uplink_rx_device,
+};
+
+static struct platform_device *snd_devices_fluid[] __initdata = {
+	&msm_ihs_stereo_rx_device,
+	&msm_ihs_mono_rx_device,
+	&msm_ihs_mono_tx_device,
+	&msm_ispeaker_rx_device,
+	&msm_ispeaker_tx_device,
+	&msm_fluid_imic_tx_device,
+	&msm_fluid_iearpeice_rx_device,
+	&msm_fluid_idual_mic_endfire_device,
+	&msm_fluid_spk_idual_mic_endfire_device,
+	&msm_a2dp_rx_device,
+	&msm_a2dp_tx_device,
+	&msm_snddev_mi2s_stereo_rx_device,
+	&msm_uplink_rx_device,
+	&msm_ifmradio_speaker_device,
+	&msm_ifmradio_headset_device,
+};
+
+#ifdef CONFIG_DEBUG_FS
+static void snddev_hsed_config_modify_setting(int type)
+{
+	struct platform_device *device;
+	struct snddev_icodec_data *icodec_data;
+
+	device = &msm_ihs_ffa_stereo_rx_device;
+	icodec_data = (struct snddev_icodec_data *)device->dev.platform_data;
+
+	if (icodec_data) {
+		if (type == 1) {
+			icodec_data->voltage_on = NULL;
+			icodec_data->voltage_off = NULL;
+			icodec_data->profile->settings =
+				ihs_ffa_stereo_rx_class_d_legacy_settings;
+			icodec_data->profile->setting_sz =
+			ARRAY_SIZE(ihs_ffa_stereo_rx_class_d_legacy_settings);
+		} else if (type == 2) {
+			icodec_data->voltage_on = NULL;
+			icodec_data->voltage_off = NULL;
+			icodec_data->profile->settings =
+				ihs_ffa_stereo_rx_class_ab_legacy_settings;
+			icodec_data->profile->setting_sz =
+			ARRAY_SIZE(ihs_ffa_stereo_rx_class_ab_legacy_settings);
+		}
+	}
+}
+
+static void snddev_hsed_config_restore_setting(void)
+{
+	struct platform_device *device;
+	struct snddev_icodec_data *icodec_data;
+
+	device = &msm_ihs_ffa_stereo_rx_device;
+	icodec_data = (struct snddev_icodec_data *)device->dev.platform_data;
+
+	if (icodec_data) {
+		icodec_data->voltage_on = msm_snddev_hsed_voltage_on;
+		icodec_data->voltage_off = msm_snddev_hsed_voltage_off;
+		icodec_data->profile->settings = ihs_ffa_stereo_rx_settings;
+		icodec_data->profile->setting_sz =
+			ARRAY_SIZE(ihs_ffa_stereo_rx_settings);
+	}
+}
+
+static ssize_t snddev_hsed_config_debug_write(struct file *filp,
+	const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	char *lb_str = filp->private_data;
+	char cmd;
+
+	if (get_user(cmd, ubuf))
+		return -EFAULT;
+
+	if (!strcmp(lb_str, "msm_hsed_config")) {
+		switch (cmd) {
+		case '0':
+			snddev_hsed_config_restore_setting();
+			break;
+
+		case '1':
+			snddev_hsed_config_modify_setting(1);
+			break;
+
+		case '2':
+			snddev_hsed_config_modify_setting(2);
+			break;
+
+		default:
+			break;
+		}
+	}
+	return cnt;
+}
+
+static int snddev_hsed_config_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static const struct file_operations snddev_hsed_config_debug_fops = {
+	.open = snddev_hsed_config_debug_open,
+	.write = snddev_hsed_config_debug_write
+};
+#endif
+
+void __ref msm_snddev_init(void)
+{
+	if (machine_is_msm7x30_ffa() || machine_is_msm8x55_ffa() ||
+		machine_is_msm8x55_svlte_ffa()) {
+		platform_add_devices(snd_devices_ffa,
+		ARRAY_SIZE(snd_devices_ffa));
+#ifdef CONFIG_DEBUG_FS
+		debugfs_hsed_config = debugfs_create_file("msm_hsed_config",
+					S_IFREG | S_IRUGO, NULL,
+		(void *) "msm_hsed_config", &snddev_hsed_config_debug_fops);
+#endif
+	} else if (machine_is_msm7x30_surf() || machine_is_msm8x55_surf() ||
+		machine_is_msm8x55_svlte_surf())
+		platform_add_devices(snd_devices_surf,
+		ARRAY_SIZE(snd_devices_surf));
+	else if (machine_is_msm7x30_fluid())
+		platform_add_devices(snd_devices_fluid,
+		ARRAY_SIZE(snd_devices_fluid));
+	else
+		pr_err("%s: Unknown machine type\n", __func__);
+}
diff --git a/arch/arm/mach-msm/qdsp5v2/snddev_data_timpani.c b/arch/arm/mach-msm/qdsp5v2/snddev_data_timpani.c
new file mode 100644
index 0000000..c0a48c8
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/snddev_data_timpani.c
@@ -0,0 +1,1006 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/mfd/msm-adie-codec.h>
+#include <linux/uaccess.h>
+#include <asm/mach-types.h>
+#include <mach/qdsp5v2/aux_pcm.h>
+#include <mach/qdsp5v2/snddev_ecodec.h>
+#include <mach/board.h>
+#include <mach/qdsp5v2/snddev_icodec.h>
+#include <mach/qdsp5v2/snddev_mi2s.h>
+#include <mach/qdsp5v2/mi2s.h>
+#include <mach/qdsp5v2/audio_acdb_def.h>
+#include <mach/qdsp5v2/snddev_virtual.h>
+#include "timpani_profile_7x30.h"
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+
+/* define the value for BT_SCO */
+#define BT_SCO_PCM_CTL_VAL (PCM_CTL__RPCM_WIDTH__LINEAR_V |\
+		PCM_CTL__TPCM_WIDTH__LINEAR_V)
+#define BT_SCO_DATA_FORMAT_PADDING (DATA_FORMAT_PADDING_INFO__RPCM_FORMAT_V |\
+		DATA_FORMAT_PADDING_INFO__TPCM_FORMAT_V)
+#define BT_SCO_AUX_CODEC_INTF   AUX_CODEC_INTF_CTL__PCMINTF_DATA_EN_V
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *debugfs_hsed_config;
+static void snddev_hsed_config_modify_setting(int type);
+static void snddev_hsed_config_restore_setting(void);
+#endif
+
+static struct adie_codec_action_unit iearpiece_ffa_48KHz_osr256_actions[] =
+	EAR_PRI_MONO_8000_OSR_256; /* 8000 profile also works for 48k */
+
+static struct adie_codec_hwsetting_entry iearpiece_ffa_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = iearpiece_ffa_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(iearpiece_ffa_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile iearpiece_ffa_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = iearpiece_ffa_settings,
+	.setting_sz = ARRAY_SIZE(iearpiece_ffa_settings),
+};
+
+static struct snddev_icodec_data snddev_iearpiece_ffa_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE),
+	.name = "handset_rx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_HANDSET_SPKR,
+	.profile = &iearpiece_ffa_profile,
+	.channel_mode = 1,
+	.pmctl_id = NULL,
+	.pmctl_id_sz = 0,
+	.default_sample_rate = 48000,
+	.pamp_on = NULL,
+	.pamp_off = NULL,
+	.property = SIDE_TONE_MASK,
+	.max_voice_rx_vol[VOC_NB_INDEX] = -700,
+	.min_voice_rx_vol[VOC_NB_INDEX] = -2200,
+	.max_voice_rx_vol[VOC_WB_INDEX] = -1400,
+	.min_voice_rx_vol[VOC_WB_INDEX] = -2900,
+};
+
+static struct platform_device msm_iearpiece_ffa_device = {
+	.name = "snddev_icodec",
+	.id = 19,
+	.dev = { .platform_data = &snddev_iearpiece_ffa_data },
+};
+
+static struct adie_codec_action_unit imic_ffa_48KHz_osr256_actions[] =
+	AMIC_PRI_MONO_8000_OSR_256; /* 8000 profile also works for 48k */
+
+static struct adie_codec_hwsetting_entry imic_ffa_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = imic_ffa_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(imic_ffa_48KHz_osr256_actions),
+	}
+};
+
+static enum hsed_controller imic_pmctl_id[] = {PM_HSED_CONTROLLER_0};
+
+static struct adie_codec_dev_profile imic_ffa_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = imic_ffa_settings,
+	.setting_sz = ARRAY_SIZE(imic_ffa_settings),
+};
+
+static struct snddev_icodec_data snddev_imic_ffa_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "handset_tx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_HANDSET_MIC,
+	.profile = &imic_ffa_profile,
+	.channel_mode = 1,
+	.pmctl_id = imic_pmctl_id,
+	.pmctl_id_sz = ARRAY_SIZE(imic_pmctl_id),
+	.default_sample_rate = 48000,
+	.pamp_on = NULL,
+	.pamp_off = NULL,
+};
+
+static struct platform_device msm_imic_ffa_device = {
+	.name = "snddev_icodec",
+	.id = 20,
+	.dev = { .platform_data = &snddev_imic_ffa_data },
+};
+
+static struct adie_codec_action_unit ispkr_stereo_48KHz_osr256_actions[] =
+	SPEAKER_PRI_STEREO_48000_OSR_256;
+
+static struct adie_codec_hwsetting_entry ispkr_stereo_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ispkr_stereo_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(ispkr_stereo_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile ispkr_stereo_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ispkr_stereo_settings,
+	.setting_sz = ARRAY_SIZE(ispkr_stereo_settings),
+};
+
+static struct snddev_icodec_data snddev_ispkr_stereo_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE),
+	.name = "speaker_stereo_rx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_SPKR_PHONE_STEREO,
+	.profile = &ispkr_stereo_profile,
+	.channel_mode = 2,
+	.pmctl_id = NULL,
+	.pmctl_id_sz = 0,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_poweramp_on,
+	.pamp_off = msm_snddev_poweramp_off,
+	.max_voice_rx_vol[VOC_NB_INDEX] = 1000,
+	.min_voice_rx_vol[VOC_NB_INDEX] = -500,
+	.max_voice_rx_vol[VOC_WB_INDEX] = 1000,
+	.min_voice_rx_vol[VOC_WB_INDEX] = -500
+};
+
+static struct platform_device msm_ispkr_stereo_device = {
+	.name = "snddev_icodec",
+	.id = 8,
+	.dev = { .platform_data = &snddev_ispkr_stereo_data },
+};
+
+static struct adie_codec_action_unit iheadset_mic_tx_osr256_actions[] =
+	AMIC1_HEADSET_TX_MONO_PRIMARY_OSR256;
+
+static struct adie_codec_hwsetting_entry iheadset_mic_tx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = iheadset_mic_tx_osr256_actions,
+		.action_sz = ARRAY_SIZE(iheadset_mic_tx_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile iheadset_mic_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = iheadset_mic_tx_settings,
+	.setting_sz = ARRAY_SIZE(iheadset_mic_tx_settings),
+};
+
+static struct snddev_icodec_data snddev_headset_mic_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "headset_mono_tx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_HEADSET_MIC,
+	.profile = &iheadset_mic_profile,
+	.channel_mode = 1,
+	.pmctl_id = NULL,
+	.pmctl_id_sz = 0,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_tx_route_config,
+	.pamp_off = msm_snddev_tx_route_deconfig,
+};
+
+static struct platform_device msm_headset_mic_device = {
+	.name = "snddev_icodec",
+	.id = 6,
+	.dev = { .platform_data = &snddev_headset_mic_data },
+};
+
+static struct snddev_mi2s_data snddev_mi2s_fm_tx_data = {
+	.capability = SNDDEV_CAP_TX ,
+	.name = "fmradio_stereo_tx",
+	.copp_id = 2,
+	.acdb_id = ACDB_ID_FM_TX,
+	.channel_mode = 2,
+	.sd_lines = MI2S_SD_3,
+	.route = NULL,
+	.deroute = NULL,
+	.default_sample_rate = 48000,
+};
+
+static struct platform_device  msm_snddev_mi2s_fm_tx_device = {
+	.name = "snddev_mi2s",
+	.id = 1,
+	.dev = { .platform_data = &snddev_mi2s_fm_tx_data},
+};
+
+static struct snddev_mi2s_data snddev_mi2s_fm_rx_data = {
+	.capability = SNDDEV_CAP_RX ,
+	.name = "fmradio_stereo_rx",
+	.copp_id = 3,
+	.acdb_id = ACDB_ID_FM_RX,
+	.channel_mode = 2,
+	.sd_lines = MI2S_SD_3,
+	.route = NULL,
+	.deroute = NULL,
+	.default_sample_rate = 48000,
+};
+
+static struct platform_device  msm_snddev_mi2s_fm_rx_device = {
+	.name = "snddev_mi2s",
+	.id = 2,
+	.dev = { .platform_data = &snddev_mi2s_fm_rx_data},
+};
+
+static struct snddev_ecodec_data snddev_bt_sco_earpiece_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE),
+	.name = "bt_sco_rx",
+	.copp_id = 1,
+	.acdb_id = ACDB_ID_BT_SCO_SPKR,
+	.channel_mode = 1,
+	.conf_pcm_ctl_val = BT_SCO_PCM_CTL_VAL,
+	.conf_aux_codec_intf = BT_SCO_AUX_CODEC_INTF,
+	.conf_data_format_padding_val = BT_SCO_DATA_FORMAT_PADDING,
+	.max_voice_rx_vol[VOC_NB_INDEX] = 400,
+	.min_voice_rx_vol[VOC_NB_INDEX] = -1100,
+	.max_voice_rx_vol[VOC_WB_INDEX] = 400,
+	.min_voice_rx_vol[VOC_WB_INDEX] = -1100,
+};
+
+static struct snddev_ecodec_data snddev_bt_sco_mic_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "bt_sco_tx",
+	.copp_id = 1,
+	.acdb_id = ACDB_ID_BT_SCO_MIC,
+	.channel_mode = 1,
+	.conf_pcm_ctl_val = BT_SCO_PCM_CTL_VAL,
+	.conf_aux_codec_intf = BT_SCO_AUX_CODEC_INTF,
+	.conf_data_format_padding_val = BT_SCO_DATA_FORMAT_PADDING,
+};
+
+static struct platform_device msm_bt_sco_earpiece_device = {
+	.name = "msm_snddev_ecodec",
+	.id = 0,
+	.dev = { .platform_data = &snddev_bt_sco_earpiece_data },
+};
+
+static struct platform_device msm_bt_sco_mic_device = {
+	.name = "msm_snddev_ecodec",
+	.id = 1,
+	.dev = { .platform_data = &snddev_bt_sco_mic_data },
+};
+
+static struct adie_codec_action_unit headset_ab_cpls_48KHz_osr256_actions[] =
+	HEADSET_AB_CPLS_48000_OSR_256;
+
+static struct adie_codec_hwsetting_entry headset_ab_cpls_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = headset_ab_cpls_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(headset_ab_cpls_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile headset_ab_cpls_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = headset_ab_cpls_settings,
+	.setting_sz = ARRAY_SIZE(headset_ab_cpls_settings),
+};
+
+static struct snddev_icodec_data snddev_ihs_stereo_rx_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE),
+	.name = "headset_stereo_rx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_HEADSET_SPKR_STEREO,
+	.profile = &headset_ab_cpls_profile,
+	.channel_mode = 2,
+	.pmctl_id = NULL,
+	.pmctl_id_sz = 0,
+	.default_sample_rate = 48000,
+	.pamp_on = NULL,
+	.pamp_off = NULL,
+	.property = SIDE_TONE_MASK,
+	.voltage_on = msm_snddev_hsed_voltage_on,
+	.voltage_off = msm_snddev_hsed_voltage_off,
+	.max_voice_rx_vol[VOC_NB_INDEX] = -700,
+	.min_voice_rx_vol[VOC_NB_INDEX] = -2200,
+	.max_voice_rx_vol[VOC_WB_INDEX] = -900,
+	.min_voice_rx_vol[VOC_WB_INDEX] = -2400,
+};
+
+static struct platform_device msm_headset_stereo_device = {
+	.name = "snddev_icodec",
+	.id = 2,
+	.dev = { .platform_data = &snddev_ihs_stereo_rx_data },
+};
+
+/*debug FS interface is exposed to test Class D and class AB mode
+ * amplifers for headset device folloowing options are supported
+ * 0 -> settings will be restored
+ * 1 -> Cladd D mode is selected
+ * 2 -> Class AB mode is selected
+*/
+#ifdef CONFIG_DEBUG_FS
+static struct adie_codec_action_unit
+	ihs_stereo_rx_class_d_legacy_48KHz_osr256_actions[] =
+	HPH_PRI_D_LEG_STEREO;
+
+static struct adie_codec_hwsetting_entry
+	ihs_stereo_rx_class_d_legacy_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions =
+		ihs_stereo_rx_class_d_legacy_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE
+		(ihs_stereo_rx_class_d_legacy_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_action_unit
+	ihs_stereo_rx_class_ab_legacy_48KHz_osr256_actions[] =
+	HPH_PRI_AB_LEG_STEREO;
+
+static struct adie_codec_hwsetting_entry
+	ihs_stereo_rx_class_ab_legacy_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions =
+		ihs_stereo_rx_class_ab_legacy_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE
+		(ihs_stereo_rx_class_ab_legacy_48KHz_osr256_actions),
+	}
+};
+
+static void snddev_hsed_config_modify_setting(int type)
+{
+	struct platform_device *device;
+	struct snddev_icodec_data *icodec_data;
+
+	device = &msm_headset_stereo_device;
+	icodec_data = (struct snddev_icodec_data *)device->dev.platform_data;
+
+	if (icodec_data) {
+		if (type == 1) {
+			icodec_data->voltage_on = NULL;
+			icodec_data->voltage_off = NULL;
+			icodec_data->profile->settings =
+				ihs_stereo_rx_class_d_legacy_settings;
+			icodec_data->profile->setting_sz =
+			ARRAY_SIZE(ihs_stereo_rx_class_d_legacy_settings);
+		} else if (type == 2) {
+			icodec_data->voltage_on = NULL;
+			icodec_data->voltage_off = NULL;
+			icodec_data->profile->settings =
+				ihs_stereo_rx_class_ab_legacy_settings;
+			icodec_data->profile->setting_sz =
+			ARRAY_SIZE(ihs_stereo_rx_class_ab_legacy_settings);
+		}
+	}
+}
+
+static void snddev_hsed_config_restore_setting(void)
+{
+	struct platform_device *device;
+	struct snddev_icodec_data *icodec_data;
+
+	device = &msm_headset_stereo_device;
+	icodec_data = device->dev.platform_data;
+
+	if (icodec_data) {
+		icodec_data->voltage_on = msm_snddev_hsed_voltage_on;
+		icodec_data->voltage_off = msm_snddev_hsed_voltage_off;
+		icodec_data->profile->settings = headset_ab_cpls_settings;
+		icodec_data->profile->setting_sz =
+			ARRAY_SIZE(headset_ab_cpls_settings);
+	}
+}
+
+static ssize_t snddev_hsed_config_debug_write(struct file *filp,
+	const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	char *lb_str = filp->private_data;
+	char cmd;
+
+	if (get_user(cmd, ubuf))
+		return -EFAULT;
+
+	if (!strcmp(lb_str, "msm_hsed_config")) {
+		switch (cmd) {
+		case '0':
+			snddev_hsed_config_restore_setting();
+			break;
+
+		case '1':
+			snddev_hsed_config_modify_setting(1);
+			break;
+
+		case '2':
+			snddev_hsed_config_modify_setting(2);
+			break;
+
+		default:
+			break;
+		}
+	}
+	return cnt;
+}
+
+static int snddev_hsed_config_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static const struct file_operations snddev_hsed_config_debug_fops = {
+	.open = snddev_hsed_config_debug_open,
+	.write = snddev_hsed_config_debug_write
+};
+#endif
+
+static enum hsed_controller ispk_pmctl_id[] = {PM_HSED_CONTROLLER_0};
+
+static struct snddev_icodec_data snddev_ispkr_mic_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "speaker_mono_tx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_SPKR_PHONE_MIC,
+	.profile = &imic_ffa_profile,
+	.channel_mode = 1,
+	.pmctl_id = ispk_pmctl_id,
+	.pmctl_id_sz = ARRAY_SIZE(ispk_pmctl_id),
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_tx_route_config,
+	.pamp_off = msm_snddev_tx_route_deconfig,
+};
+
+static struct platform_device msm_ispkr_mic_device = {
+	.name = "snddev_icodec",
+	.id = 18,
+	.dev = { .platform_data = &snddev_ispkr_mic_data },
+};
+
+static struct adie_codec_action_unit idual_mic_endfire_8KHz_osr256_actions[] =
+	AMIC_DUAL_8000_OSR_256;
+
+static struct adie_codec_hwsetting_entry idual_mic_endfire_settings[] = {
+	{
+		.freq_plan = 8000,
+		.osr = 256,
+		.actions = idual_mic_endfire_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(idual_mic_endfire_8KHz_osr256_actions),
+	}, /* 8KHz profile can be used for 16KHz */
+	{
+		.freq_plan = 16000,
+		.osr = 256,
+		.actions = idual_mic_endfire_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(idual_mic_endfire_8KHz_osr256_actions),
+	}, /* 8KHz profile can be used for 48KHz */
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = idual_mic_endfire_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(idual_mic_endfire_8KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile idual_mic_endfire_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = idual_mic_endfire_settings,
+	.setting_sz = ARRAY_SIZE(idual_mic_endfire_settings),
+};
+
+static enum hsed_controller idual_mic_endfire_pmctl_id[] = {
+	PM_HSED_CONTROLLER_0, PM_HSED_CONTROLLER_2
+};
+
+static struct snddev_icodec_data snddev_idual_mic_endfire_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "handset_dual_mic_endfire_tx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_HANDSET_MIC_ENDFIRE,
+	.profile = &idual_mic_endfire_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pmctl_id = idual_mic_endfire_pmctl_id,
+	.pmctl_id_sz = ARRAY_SIZE(idual_mic_endfire_pmctl_id),
+	.pamp_on = NULL,
+	.pamp_off = NULL,
+};
+
+static struct platform_device msm_idual_mic_endfire_device = {
+	.name = "snddev_icodec",
+	.id = 12,
+	.dev = { .platform_data = &snddev_idual_mic_endfire_data },
+};
+
+static struct snddev_icodec_data snddev_spk_idual_mic_endfire_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "speaker_dual_mic_endfire_tx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_SPKR_PHONE_MIC_ENDFIRE,
+	.profile = &idual_mic_endfire_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pmctl_id = idual_mic_endfire_pmctl_id,
+	.pmctl_id_sz = ARRAY_SIZE(idual_mic_endfire_pmctl_id),
+	.pamp_on = NULL,
+	.pamp_off = NULL,
+};
+
+static struct platform_device msm_spk_idual_mic_endfire_device = {
+	.name = "snddev_icodec",
+	.id = 14,
+	.dev = { .platform_data = &snddev_spk_idual_mic_endfire_data },
+};
+
+static struct adie_codec_action_unit itty_mono_tx_actions[] =
+	TTY_HEADSET_MONO_TX_8000_OSR_256;
+
+static struct adie_codec_hwsetting_entry itty_mono_tx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = itty_mono_tx_actions,
+		.action_sz = ARRAY_SIZE(itty_mono_tx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile itty_mono_tx_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = itty_mono_tx_settings,
+	.setting_sz = ARRAY_SIZE(itty_mono_tx_settings),
+};
+
+static struct snddev_icodec_data snddev_itty_mono_tx_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE | SNDDEV_CAP_TTY),
+	.name = "tty_headset_mono_tx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_TTY_HEADSET_MIC,
+	.profile = &itty_mono_tx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pmctl_id = NULL,
+	.pmctl_id_sz = 0,
+	.pamp_on = NULL,
+	.pamp_off = NULL,
+};
+
+static struct platform_device msm_itty_mono_tx_device = {
+	.name = "snddev_icodec",
+	.id = 16,
+	.dev = { .platform_data = &snddev_itty_mono_tx_data },
+};
+
+static struct adie_codec_action_unit itty_mono_rx_actions[] =
+	TTY_HEADSET_MONO_RX_8000_OSR_256;
+
+static struct adie_codec_hwsetting_entry itty_mono_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = itty_mono_rx_actions,
+		.action_sz = ARRAY_SIZE(itty_mono_rx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile itty_mono_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = itty_mono_rx_settings,
+	.setting_sz = ARRAY_SIZE(itty_mono_rx_settings),
+};
+
+static struct snddev_icodec_data snddev_itty_mono_rx_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE | SNDDEV_CAP_TTY),
+	.name = "tty_headset_mono_rx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_TTY_HEADSET_SPKR,
+	.profile = &itty_mono_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = NULL,
+	.pamp_off = NULL,
+	.max_voice_rx_vol[VOC_NB_INDEX] = 0,
+	.min_voice_rx_vol[VOC_NB_INDEX] = 0,
+	.max_voice_rx_vol[VOC_WB_INDEX] = 0,
+	.min_voice_rx_vol[VOC_WB_INDEX] = 0,
+};
+
+static struct platform_device msm_itty_mono_rx_device = {
+	.name = "snddev_icodec",
+	.id = 17,
+	.dev = { .platform_data = &snddev_itty_mono_rx_data },
+};
+
+static struct snddev_virtual_data snddev_a2dp_tx_data = {
+	.capability = SNDDEV_CAP_TX,
+	.name = "a2dp_tx",
+	.copp_id = 5,
+	.acdb_id = PSEUDO_ACDB_ID,
+};
+
+static struct snddev_virtual_data snddev_a2dp_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "a2dp_rx",
+	.copp_id = 2,
+	.acdb_id = PSEUDO_ACDB_ID,
+};
+
+static struct platform_device msm_a2dp_rx_device = {
+	.name = "snddev_virtual",
+	.id = 0,
+	.dev = { .platform_data = &snddev_a2dp_rx_data },
+};
+
+static struct platform_device msm_a2dp_tx_device = {
+	.name = "snddev_virtual",
+	.id = 1,
+	.dev = { .platform_data = &snddev_a2dp_tx_data },
+};
+
+static struct snddev_virtual_data snddev_uplink_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "uplink_rx",
+	.copp_id = 5,
+	.acdb_id = PSEUDO_ACDB_ID,
+};
+
+static struct platform_device msm_uplink_rx_device = {
+	.name = "snddev_virtual",
+	.id = 2,
+	.dev = { .platform_data = &snddev_uplink_rx_data },
+};
+
+static struct snddev_icodec_data\
+		snddev_idual_mic_endfire_real_stereo_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "handset_dual_mic_endfire_tx_real_stereo",
+	.copp_id = 0,
+	.acdb_id = PSEUDO_ACDB_ID,
+	.profile = &idual_mic_endfire_profile,
+	.channel_mode = REAL_STEREO_CHANNEL_MODE,
+	.default_sample_rate = 48000,
+	.pmctl_id = idual_mic_endfire_pmctl_id,
+	.pmctl_id_sz = ARRAY_SIZE(idual_mic_endfire_pmctl_id),
+	.pamp_on = NULL,
+	.pamp_off = NULL,
+};
+
+static struct platform_device msm_real_stereo_tx_device = {
+	.name = "snddev_icodec",
+	.id = 26,
+	.dev = { .platform_data =
+			&snddev_idual_mic_endfire_real_stereo_data },
+};
+
+static struct adie_codec_action_unit ihs_ffa_mono_rx_48KHz_osr256_actions[] =
+	HEADSET_RX_CAPLESS_48000_OSR_256;
+
+static struct adie_codec_hwsetting_entry ihs_ffa_mono_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ihs_ffa_mono_rx_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(ihs_ffa_mono_rx_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile ihs_ffa_mono_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ihs_ffa_mono_rx_settings,
+	.setting_sz = ARRAY_SIZE(ihs_ffa_mono_rx_settings),
+};
+
+static struct snddev_icodec_data snddev_ihs_ffa_mono_rx_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE),
+	.name = "headset_mono_rx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_HEADSET_SPKR_MONO,
+	.profile = &ihs_ffa_mono_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_hsed_voltage_on,
+	.pamp_off = msm_snddev_hsed_voltage_off,
+	.max_voice_rx_vol[VOC_NB_INDEX] = -700,
+	.min_voice_rx_vol[VOC_NB_INDEX] = -2200,
+	.max_voice_rx_vol[VOC_WB_INDEX] = -900,
+	.min_voice_rx_vol[VOC_WB_INDEX] = -2400,
+	.property = SIDE_TONE_MASK,
+};
+
+static struct platform_device msm_ihs_ffa_mono_rx_device = {
+	.name = "snddev_icodec",
+	.id = 5,
+	.dev = { .platform_data = &snddev_ihs_ffa_mono_rx_data },
+};
+
+static struct adie_codec_action_unit
+	ihs_stereo_speaker_stereo_rx_48KHz_osr256_actions[] =
+	HEADSET_STEREO_SPEAKER_STEREO_RX_CAPLESS_48000_OSR_256;
+
+
+static struct adie_codec_hwsetting_entry
+	ihs_stereo_speaker_stereo_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ihs_stereo_speaker_stereo_rx_48KHz_osr256_actions,
+		.action_sz =
+		ARRAY_SIZE(ihs_stereo_speaker_stereo_rx_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile ihs_stereo_speaker_stereo_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ihs_stereo_speaker_stereo_rx_settings,
+	.setting_sz = ARRAY_SIZE(ihs_stereo_speaker_stereo_rx_settings),
+};
+
+static struct snddev_icodec_data snddev_ihs_stereo_speaker_stereo_rx_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE),
+	.name = "headset_stereo_speaker_stereo_rx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_HEADSET_STEREO_PLUS_SPKR_STEREO_RX,
+	.profile = &ihs_stereo_speaker_stereo_rx_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_poweramp_on,
+	.pamp_off = msm_snddev_poweramp_off,
+	.voltage_on = msm_snddev_hsed_voltage_on,
+	.voltage_off = msm_snddev_hsed_voltage_off,
+	.max_voice_rx_vol[VOC_NB_INDEX] = -500,
+	.min_voice_rx_vol[VOC_NB_INDEX] = -2000,
+	.max_voice_rx_vol[VOC_WB_INDEX] = -900,
+	.min_voice_rx_vol[VOC_WB_INDEX] = -2400,
+};
+
+static struct platform_device msm_ihs_stereo_speaker_stereo_rx_device = {
+	.name = "snddev_icodec",
+	.id = 21,
+	.dev = { .platform_data = &snddev_ihs_stereo_speaker_stereo_rx_data },
+};
+
+static struct adie_codec_action_unit ispk_dual_mic_bs_8KHz_osr256_actions[] =
+	HS_DMIC2_STEREO_8000_OSR_256;
+
+static struct adie_codec_hwsetting_entry ispk_dual_mic_bs_settings[] = {
+	{
+		.freq_plan = 8000,
+		.osr = 256,
+		.actions = ispk_dual_mic_bs_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(ispk_dual_mic_bs_8KHz_osr256_actions),
+	}, /* 8KHz profile can be used for 16Khz */
+	{
+		.freq_plan = 16000,
+		.osr = 256,
+		.actions = ispk_dual_mic_bs_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(ispk_dual_mic_bs_8KHz_osr256_actions),
+	}, /* 8KHz profile can be used for 48KHz */
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ispk_dual_mic_bs_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(ispk_dual_mic_bs_8KHz_osr256_actions),
+	},
+};
+
+static enum hsed_controller idual_mic_broadside_pmctl_id[] = {
+	PM_HSED_CONTROLLER_0, PM_HSED_CONTROLLER_2
+};
+
+static struct adie_codec_dev_profile ispk_dual_mic_bs_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = ispk_dual_mic_bs_settings,
+	.setting_sz = ARRAY_SIZE(ispk_dual_mic_bs_settings),
+};
+static struct snddev_icodec_data snddev_spk_idual_mic_broadside_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "speaker_dual_mic_broadside_tx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_SPKR_PHONE_MIC_BROADSIDE,
+	.profile = &ispk_dual_mic_bs_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pmctl_id = idual_mic_broadside_pmctl_id,
+	.pmctl_id_sz = ARRAY_SIZE(idual_mic_broadside_pmctl_id),
+	.pamp_on = NULL,
+	.pamp_off = NULL,
+};
+
+static struct platform_device msm_spk_idual_mic_broadside_device = {
+	.name = "snddev_icodec",
+	.id = 15,
+	.dev = { .platform_data = &snddev_spk_idual_mic_broadside_data },
+};
+
+static struct adie_codec_action_unit idual_mic_bs_8KHz_osr256_actions[] =
+	HS_DMIC2_STEREO_8000_OSR_256;
+
+static struct adie_codec_hwsetting_entry idual_mic_broadside_settings[] = {
+	{
+		.freq_plan = 8000,
+		.osr = 256,
+		.actions = idual_mic_bs_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(idual_mic_bs_8KHz_osr256_actions),
+	}, /* 8KHz profile can be used for 16KHz */
+	{
+		.freq_plan = 16000,
+		.osr = 256,
+		.actions = idual_mic_bs_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(idual_mic_bs_8KHz_osr256_actions),
+	}, /* 8KHz profile can be used for 16KHz */
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = idual_mic_bs_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(idual_mic_bs_8KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile idual_mic_broadside_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = idual_mic_broadside_settings,
+	.setting_sz = ARRAY_SIZE(idual_mic_broadside_settings),
+};
+
+static struct snddev_icodec_data snddev_idual_mic_broadside_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "handset_dual_mic_broadside_tx",
+	.copp_id = 0,
+	.acdb_id = ACDB_ID_HANDSET_MIC_BROADSIDE,
+	.profile = &idual_mic_broadside_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pmctl_id = idual_mic_broadside_pmctl_id,
+	.pmctl_id_sz = ARRAY_SIZE(idual_mic_broadside_pmctl_id),
+	.pamp_on = NULL,
+	.pamp_off = NULL,
+};
+
+static struct platform_device msm_idual_mic_broadside_device = {
+	.name = "snddev_icodec",
+	.id = 13,
+	.dev = { .platform_data = &snddev_idual_mic_broadside_data },
+};
+
+static struct snddev_mi2s_data snddev_mi2s_stereo_rx_data = {
+	.capability = SNDDEV_CAP_RX ,
+	.name = "hdmi_stereo_rx",
+	.copp_id = 3,
+	.acdb_id = ACDB_ID_HDMI,
+	.channel_mode = 2,
+	.sd_lines = MI2S_SD_0,
+	.route = msm_snddev_tx_route_config,
+	.deroute = msm_snddev_tx_route_deconfig,
+	.default_sample_rate = 48000,
+};
+
+static struct platform_device msm_snddev_mi2s_stereo_rx_device = {
+	.name = "snddev_mi2s",
+	.id = 0,
+	.dev = { .platform_data = &snddev_mi2s_stereo_rx_data },
+};
+
+static struct adie_codec_action_unit auxpga_lb_lo_actions[] =
+	LB_AUXPGA_LO_STEREO;
+
+static struct adie_codec_hwsetting_entry auxpga_lb_lo_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = auxpga_lb_lo_actions,
+		.action_sz = ARRAY_SIZE(auxpga_lb_lo_actions),
+	},
+};
+
+static struct adie_codec_dev_profile auxpga_lb_lo_profile = {
+	.path_type = ADIE_CODEC_LB,
+	.settings = auxpga_lb_lo_settings,
+	.setting_sz = ARRAY_SIZE(auxpga_lb_lo_settings),
+};
+
+static struct snddev_icodec_data snddev_auxpga_lb_lo_data = {
+	.capability = SNDDEV_CAP_LB,
+	.name = "auxpga_loopback_lo",
+	.copp_id = 0,
+	.acdb_id = PSEUDO_ACDB_ID,
+	.profile = &auxpga_lb_lo_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_poweramp_on,
+	.pamp_off = msm_snddev_poweramp_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_ANALOG,
+};
+
+static struct platform_device msm_auxpga_lb_lo_device = {
+	.name = "snddev_icodec",
+	.id = 27,
+	.dev = { .platform_data = &snddev_auxpga_lb_lo_data },
+};
+
+static struct adie_codec_action_unit auxpga_lb_hs_actions[] =
+	LB_AUXPGA_HPH_AB_CPLS_STEREO;
+
+static struct adie_codec_hwsetting_entry auxpga_lb_hs_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = auxpga_lb_hs_actions,
+		.action_sz = ARRAY_SIZE(auxpga_lb_hs_actions),
+	},
+};
+
+static struct adie_codec_dev_profile auxpga_lb_hs_profile = {
+	.path_type = ADIE_CODEC_LB,
+	.settings = auxpga_lb_hs_settings,
+	.setting_sz = ARRAY_SIZE(auxpga_lb_hs_settings),
+};
+
+static struct snddev_icodec_data snddev_auxpga_lb_hs_data = {
+	.capability = SNDDEV_CAP_LB,
+	.name = "auxpga_loopback_hs",
+	.copp_id = 0,
+	.acdb_id = PSEUDO_ACDB_ID,
+	.profile = &auxpga_lb_hs_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.voltage_on = msm_snddev_hsed_voltage_on,
+	.voltage_off = msm_snddev_hsed_voltage_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_ANALOG,
+};
+
+static struct platform_device msm_auxpga_lb_hs_device = {
+	.name = "snddev_icodec",
+	.id = 25,
+	.dev = { .platform_data = &snddev_auxpga_lb_hs_data },
+};
+
+static struct platform_device *snd_devices_ffa[] __initdata = {
+	&msm_iearpiece_ffa_device,
+	&msm_imic_ffa_device,
+	&msm_ispkr_stereo_device,
+	&msm_headset_mic_device,
+	&msm_ihs_ffa_mono_rx_device,
+	&msm_snddev_mi2s_fm_rx_device,
+	&msm_snddev_mi2s_fm_tx_device,
+	&msm_bt_sco_earpiece_device,
+	&msm_bt_sco_mic_device,
+	&msm_ispkr_mic_device,
+	&msm_headset_stereo_device,
+	&msm_idual_mic_endfire_device,
+	&msm_spk_idual_mic_endfire_device,
+	&msm_itty_mono_tx_device,
+	&msm_itty_mono_rx_device,
+	&msm_a2dp_rx_device,
+	&msm_a2dp_tx_device,
+	&msm_uplink_rx_device,
+	&msm_real_stereo_tx_device,
+	&msm_ihs_stereo_speaker_stereo_rx_device,
+	&msm_spk_idual_mic_broadside_device,
+	&msm_idual_mic_broadside_device,
+	&msm_snddev_mi2s_stereo_rx_device,
+	&msm_auxpga_lb_hs_device,
+	&msm_auxpga_lb_lo_device,
+};
+
+void __ref msm_snddev_init_timpani(void)
+{
+	platform_add_devices(snd_devices_ffa,
+			ARRAY_SIZE(snd_devices_ffa));
+#ifdef CONFIG_DEBUG_FS
+	debugfs_hsed_config = debugfs_create_file("msm_hsed_config",
+				S_IFREG | S_IWUGO, NULL,
+		(void *) "msm_hsed_config", &snddev_hsed_config_debug_fops);
+	if (!debugfs_hsed_config)
+		pr_err("failed to create msm_head_config debug fs entry\n");
+#endif
+
+}
diff --git a/arch/arm/mach-msm/qdsp5v2/snddev_ecodec.c b/arch/arm/mach-msm/qdsp5v2/snddev_ecodec.c
new file mode 100644
index 0000000..a5da912
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/snddev_ecodec.c
@@ -0,0 +1,484 @@
+/* Copyright (c) 2009,2011 Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <asm/uaccess.h>
+#include <mach/qdsp5v2/snddev_ecodec.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/qdsp5v2/audio_interct.h>
+#include <mach/qdsp5v2/aux_pcm.h>
+#include <mach/qdsp5v2/afe.h>
+#include <mach/debug_mm.h>
+#include <linux/slab.h>
+
+/* Context for each external codec device */
+struct snddev_ecodec_state {
+	struct snddev_ecodec_data *data;
+	u32 sample_rate;
+	bool enabled;
+};
+
+/* Global state for the driver */
+struct snddev_ecodec_drv_state {
+	struct mutex dev_lock;
+	u32 rx_active; /* ensure one rx device at a time */
+	u32 tx_active; /* ensure one tx device at a time */
+	struct clk *lpa_core_clk;
+	struct clk *ecodec_clk;
+};
+
+#define ADSP_CTL 1
+
+static struct snddev_ecodec_drv_state snddev_ecodec_drv;
+
+static int snddev_ecodec_open_rx(struct snddev_ecodec_state *ecodec)
+{
+	int rc = 0;
+	struct snddev_ecodec_drv_state *drv = &snddev_ecodec_drv;
+	struct msm_afe_config afe_config;
+	int ret = 0;
+
+	MM_DBG("snddev_ecodec_open_rx\n");
+
+	if (!drv->tx_active) {
+		/* request GPIO */
+		rc = aux_pcm_gpios_request();
+		if (rc) {
+			MM_ERR("GPIO enable failed\n");
+			goto done;
+		}
+		/* config clocks */
+		clk_enable(drv->lpa_core_clk);
+
+		/*if long sync is selected in aux PCM interface
+		ecodec clock is updated to work with 128KHz,
+		if short sync is selected ecodec clock is updated to
+		work with 2.048MHz frequency, actual clock output is
+		different than the SW configuration by factor of two*/
+		if (!(ecodec->data->conf_aux_codec_intf &
+			AUX_CODEC_CTL__AUX_CODEC_MODE__I2S_V)) {
+			if (ecodec->data->conf_aux_codec_intf &
+				AUX_CODEC_CTL__AUX_PCM_MODE__AUX_MASTER_V) {
+				MM_DBG("Update ecodec clock to 128 KHz, long "
+					"sync in master mode is selected\n");
+				ret = clk_set_rate(drv->ecodec_clk, 256000);
+				if (ret < 0)
+					MM_ERR("Error updating ecodec clock"
+							" to 128KHz\n");
+			} else if (ecodec->data->conf_aux_codec_intf &
+				AUX_CODEC_CTL__AUX_PCM_MODE__PRIM_SLAVE_V) {
+				MM_DBG("Update ecodec clock to 2 MHz, short"
+					" sync in slave mode is selected\n");
+				ret = clk_set_rate(drv->ecodec_clk, 4096000);
+				if (ret < 0)
+					MM_ERR("Error updating ecodec clock"
+							" to 2.048MHz\n");
+			} else {
+				MM_DBG("Update ecodec clock to 2 MHz, short"
+					" sync in master mode is selected\n");
+				ret = clk_set_rate(drv->ecodec_clk, 4096000);
+				if (ret < 0)
+					MM_ERR("Error updating ecodec clock"
+							" to 2.048MHz\n");
+			}
+		}
+
+		/* enable ecodec clk */
+		clk_enable(drv->ecodec_clk);
+
+		/* let ADSP confiure AUX PCM regs */
+		aux_codec_adsp_codec_ctl_en(ADSP_CTL);
+
+		/* let adsp configure pcm path */
+		aux_codec_pcm_path_ctl_en(ADSP_CTL);
+
+		/* choose ADSP_A */
+		audio_interct_aux_regsel(AUDIO_ADSP_A);
+		audio_interct_tpcm_source(AUDIO_ADSP_A);
+		audio_interct_rpcm_source(AUDIO_ADSP_A);
+
+		clk_disable(drv->lpa_core_clk);
+
+		/* send AUX_CODEC_CONFIG to AFE */
+		rc = afe_config_aux_codec(ecodec->data->conf_pcm_ctl_val,
+				ecodec->data->conf_aux_codec_intf,
+				ecodec->data->conf_data_format_padding_val);
+		if (IS_ERR_VALUE(rc))
+			goto error;
+	}
+	/* send CODEC CONFIG to AFE */
+	afe_config.sample_rate = ecodec->sample_rate / 1000;
+	afe_config.channel_mode = ecodec->data->channel_mode;
+	afe_config.volume = AFE_VOLUME_UNITY;
+	rc = afe_enable(AFE_HW_PATH_AUXPCM_RX, &afe_config);
+	if (IS_ERR_VALUE(rc)) {
+		if (!drv->tx_active) {
+			aux_pcm_gpios_free();
+			clk_disable(drv->ecodec_clk);
+		}
+		goto done;
+	}
+
+	ecodec->enabled = 1;
+	return 0;
+
+error:
+	aux_pcm_gpios_free();
+	clk_disable(drv->ecodec_clk);
+done:
+	return rc;
+}
+
+static int snddev_ecodec_close_rx(struct snddev_ecodec_state *ecodec)
+{
+	struct snddev_ecodec_drv_state *drv = &snddev_ecodec_drv;
+
+	/* free GPIO */
+	if (!drv->tx_active) {
+		aux_pcm_gpios_free();
+		clk_disable(drv->ecodec_clk);
+	}
+
+	/* disable AFE */
+	afe_disable(AFE_HW_PATH_AUXPCM_RX);
+
+	ecodec->enabled = 0;
+
+	return 0;
+}
+
+static int snddev_ecodec_open_tx(struct snddev_ecodec_state *ecodec)
+{
+	int rc = 0;
+	struct snddev_ecodec_drv_state *drv = &snddev_ecodec_drv;
+	struct msm_afe_config afe_config;
+	int ret = 0;
+
+	MM_DBG("snddev_ecodec_open_tx\n");
+
+	/* request GPIO */
+	if (!drv->rx_active) {
+		rc = aux_pcm_gpios_request();
+		if (rc) {
+			MM_ERR("GPIO enable failed\n");
+			goto done;
+		}
+		/* config clocks */
+		clk_enable(drv->lpa_core_clk);
+
+		/*if long sync is selected in aux PCM interface
+		ecodec clock is updated to work with 128KHz,
+		if short sync is selected ecodec clock is updated to
+		work with 2.048MHz frequency, actual clock output is
+		different than the SW configuration by factor of two*/
+		if (!(ecodec->data->conf_aux_codec_intf &
+			AUX_CODEC_CTL__AUX_CODEC_MODE__I2S_V)) {
+			if (ecodec->data->conf_aux_codec_intf &
+				AUX_CODEC_CTL__AUX_PCM_MODE__AUX_MASTER_V) {
+				MM_DBG("Update ecodec clock to 128 KHz, long "
+					"sync in master mode is selected\n");
+				ret = clk_set_rate(drv->ecodec_clk, 256000);
+				if (ret < 0)
+					MM_ERR("Error updating ecodec clock"
+							" to 128KHz\n");
+			} else if (ecodec->data->conf_aux_codec_intf &
+				AUX_CODEC_CTL__AUX_PCM_MODE__PRIM_SLAVE_V) {
+				MM_DBG("Update ecodec clock to 2 MHz, short"
+					" sync in slave mode is selected\n");
+				ret = clk_set_rate(drv->ecodec_clk, 4096000);
+				if (ret < 0)
+					MM_ERR("Error updating ecodec clock"
+							" to 2.048MHz\n");
+			} else {
+				MM_DBG("Update ecodec clock to 2 MHz, short"
+					" sync in master mode is selected\n");
+				ret = clk_set_rate(drv->ecodec_clk, 4096000);
+				if (ret < 0)
+					MM_ERR("Error updating ecodec clock"
+							" to 2.048MHz\n");
+			}
+		}
+
+		/* enable ecodec clk */
+		clk_enable(drv->ecodec_clk);
+
+		/* let ADSP confiure AUX PCM regs */
+		aux_codec_adsp_codec_ctl_en(ADSP_CTL);
+
+		/* let adsp configure pcm path */
+		aux_codec_pcm_path_ctl_en(ADSP_CTL);
+
+		/* choose ADSP_A */
+		audio_interct_aux_regsel(AUDIO_ADSP_A);
+		audio_interct_tpcm_source(AUDIO_ADSP_A);
+		audio_interct_rpcm_source(AUDIO_ADSP_A);
+
+		clk_disable(drv->lpa_core_clk);
+
+		/* send AUX_CODEC_CONFIG to AFE */
+		rc = afe_config_aux_codec(ecodec->data->conf_pcm_ctl_val,
+			ecodec->data->conf_aux_codec_intf,
+			ecodec->data->conf_data_format_padding_val);
+		if (IS_ERR_VALUE(rc))
+			goto error;
+	}
+	/* send CODEC CONFIG to AFE */
+	afe_config.sample_rate = ecodec->sample_rate / 1000;
+	afe_config.channel_mode = ecodec->data->channel_mode;
+	afe_config.volume = AFE_VOLUME_UNITY;
+	rc = afe_enable(AFE_HW_PATH_AUXPCM_TX, &afe_config);
+	if (IS_ERR_VALUE(rc)) {
+		if (!drv->rx_active) {
+			aux_pcm_gpios_free();
+			clk_disable(drv->ecodec_clk);
+		}
+		goto done;
+	}
+
+	ecodec->enabled = 1;
+	return 0;
+
+error:
+	clk_disable(drv->ecodec_clk);
+	aux_pcm_gpios_free();
+done:
+	return rc;
+}
+
+static int snddev_ecodec_close_tx(struct snddev_ecodec_state *ecodec)
+{
+	struct snddev_ecodec_drv_state *drv = &snddev_ecodec_drv;
+
+	/* free GPIO */
+	if (!drv->rx_active) {
+		aux_pcm_gpios_free();
+		clk_disable(drv->ecodec_clk);
+	}
+
+	/* disable AFE */
+	afe_disable(AFE_HW_PATH_AUXPCM_TX);
+
+	ecodec->enabled = 0;
+
+	return 0;
+}
+
+
+static int snddev_ecodec_open(struct msm_snddev_info *dev_info)
+{
+	int rc = 0;
+	struct snddev_ecodec_state *ecodec;
+	struct snddev_ecodec_drv_state *drv = &snddev_ecodec_drv;
+
+	if (!dev_info) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	ecodec = dev_info->private_data;
+
+	if (ecodec->data->capability & SNDDEV_CAP_RX) {
+		mutex_lock(&drv->dev_lock);
+		if (drv->rx_active) {
+			mutex_unlock(&drv->dev_lock);
+			rc = -EBUSY;
+			goto error;
+		}
+		rc = snddev_ecodec_open_rx(ecodec);
+		if (!IS_ERR_VALUE(rc))
+			drv->rx_active = 1;
+		mutex_unlock(&drv->dev_lock);
+	} else {
+		mutex_lock(&drv->dev_lock);
+		if (drv->tx_active) {
+			mutex_unlock(&drv->dev_lock);
+			rc = -EBUSY;
+			goto error;
+		}
+		rc = snddev_ecodec_open_tx(ecodec);
+		if (!IS_ERR_VALUE(rc))
+			drv->tx_active = 1;
+		mutex_unlock(&drv->dev_lock);
+	}
+error:
+	return rc;
+}
+
+static int snddev_ecodec_close(struct msm_snddev_info *dev_info)
+{
+	int rc = 0;
+	struct snddev_ecodec_state *ecodec;
+	struct snddev_ecodec_drv_state *drv = &snddev_ecodec_drv;
+	if (!dev_info) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	ecodec = dev_info->private_data;
+
+	if (ecodec->data->capability & SNDDEV_CAP_RX) {
+		mutex_lock(&drv->dev_lock);
+		if (!drv->rx_active) {
+			mutex_unlock(&drv->dev_lock);
+			rc = -EPERM;
+			goto error;
+		}
+		rc = snddev_ecodec_close_rx(ecodec);
+		if (!IS_ERR_VALUE(rc))
+			drv->rx_active = 0;
+		mutex_unlock(&drv->dev_lock);
+	} else {
+		mutex_lock(&drv->dev_lock);
+		if (!drv->tx_active) {
+			mutex_unlock(&drv->dev_lock);
+			rc = -EPERM;
+			goto error;
+		}
+		rc = snddev_ecodec_close_tx(ecodec);
+		if (!IS_ERR_VALUE(rc))
+			drv->tx_active = 0;
+		mutex_unlock(&drv->dev_lock);
+	}
+
+error:
+	return rc;
+}
+
+static int snddev_ecodec_set_freq(struct msm_snddev_info *dev_info, u32 rate)
+{
+	int rc = 0;
+
+	if (!dev_info) {
+		rc = -EINVAL;
+		goto error;
+	}
+	return 8000;
+
+error:
+	return rc;
+}
+
+static int snddev_ecodec_probe(struct platform_device *pdev)
+{
+	int rc = 0, i;
+	struct snddev_ecodec_data *pdata;
+	struct msm_snddev_info *dev_info;
+	struct snddev_ecodec_state *ecodec;
+
+	if (!pdev || !pdev->dev.platform_data) {
+		printk(KERN_ALERT "Invalid caller \n");
+		rc = -1;
+		goto error;
+	}
+	pdata = pdev->dev.platform_data;
+
+	ecodec = kzalloc(sizeof(struct snddev_ecodec_state), GFP_KERNEL);
+	if (!ecodec) {
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	dev_info = kzalloc(sizeof(struct msm_snddev_info), GFP_KERNEL);
+	if (!dev_info) {
+		kfree(ecodec);
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	dev_info->name = pdata->name;
+	dev_info->copp_id = pdata->copp_id;
+	dev_info->acdb_id = pdata->acdb_id;
+	dev_info->private_data = (void *) ecodec;
+	dev_info->dev_ops.open = snddev_ecodec_open;
+	dev_info->dev_ops.close = snddev_ecodec_close;
+	dev_info->dev_ops.set_freq = snddev_ecodec_set_freq;
+	dev_info->dev_ops.enable_sidetone = NULL;
+	dev_info->capability = pdata->capability;
+	dev_info->opened = 0;
+
+	msm_snddev_register(dev_info);
+	ecodec->data = pdata;
+	ecodec->sample_rate = 8000; /* Default to 8KHz */
+	 if (pdata->capability & SNDDEV_CAP_RX) {
+		for (i = 0; i < VOC_RX_VOL_ARRAY_NUM; i++) {
+			dev_info->max_voc_rx_vol[i] =
+				pdata->max_voice_rx_vol[i];
+			dev_info->min_voc_rx_vol[i] =
+				pdata->min_voice_rx_vol[i];
+		}
+	}
+error:
+	return rc;
+}
+
+static int snddev_ecodec_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static struct platform_driver snddev_ecodec_driver = {
+	.probe = snddev_ecodec_probe,
+	.remove = snddev_ecodec_remove,
+	.driver = { .name = "msm_snddev_ecodec" }
+};
+
+static int __init snddev_ecodec_init(void)
+{
+	int rc = 0;
+	struct snddev_ecodec_drv_state *ecodec_drv = &snddev_ecodec_drv;
+
+	MM_INFO("snddev_ecodec_init\n");
+	rc = platform_driver_register(&snddev_ecodec_driver);
+	if (IS_ERR_VALUE(rc))
+		goto error_platform_driver;
+	ecodec_drv->ecodec_clk = clk_get(NULL, "ecodec_clk");
+	if (IS_ERR(ecodec_drv->ecodec_clk))
+		goto error_ecodec_clk;
+	ecodec_drv->lpa_core_clk = clk_get(NULL, "lpa_core_clk");
+	if (IS_ERR(ecodec_drv->lpa_core_clk))
+		goto error_lpa_core_clk;
+
+
+	mutex_init(&ecodec_drv->dev_lock);
+	ecodec_drv->rx_active = 0;
+	ecodec_drv->tx_active = 0;
+	return 0;
+
+error_lpa_core_clk:
+	clk_put(ecodec_drv->ecodec_clk);
+error_ecodec_clk:
+	platform_driver_unregister(&snddev_ecodec_driver);
+error_platform_driver:
+
+	MM_ERR("encounter error\n");
+	return -ENODEV;
+}
+
+static void __exit snddev_ecodec_exit(void)
+{
+	struct snddev_ecodec_drv_state *ecodec_drv = &snddev_ecodec_drv;
+
+	platform_driver_unregister(&snddev_ecodec_driver);
+	clk_put(ecodec_drv->ecodec_clk);
+
+	return;
+}
+
+module_init(snddev_ecodec_init);
+module_exit(snddev_ecodec_exit);
+
+MODULE_DESCRIPTION("ECodec Sound Device driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5v2/snddev_icodec.c b/arch/arm/mach-msm/qdsp5v2/snddev_icodec.c
new file mode 100644
index 0000000..dbeda82
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/snddev_icodec.c
@@ -0,0 +1,1211 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/msm-adie-codec.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/debugfs.h>
+#include <asm/uaccess.h>
+#include <mach/qdsp5v2/snddev_icodec.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/qdsp5v2/audio_interct.h>
+#include <mach/qdsp5v2/mi2s.h>
+#include <mach/qdsp5v2/afe.h>
+#include <mach/qdsp5v2/lpa.h>
+#include <mach/qdsp5v2/marimba_profile.h>
+#include <mach/vreg.h>
+#include <mach/pmic.h>
+#include <linux/wakelock.h>
+#include <mach/debug_mm.h>
+#include <mach/rpc_pmapp.h>
+#include <mach/qdsp5v2/audio_acdb_def.h>
+#include <linux/slab.h>
+
+#define SMPS_AUDIO_PLAYBACK_ID	"AUPB"
+#define SMPS_AUDIO_RECORD_ID	"AURC"
+
+#define SNDDEV_ICODEC_PCM_SZ 32 /* 16 bit / sample stereo mode */
+#define SNDDEV_ICODEC_MUL_FACTOR 3 /* Multi by 8 Shift by 3  */
+#define SNDDEV_ICODEC_CLK_RATE(freq) \
+	(((freq) * (SNDDEV_ICODEC_PCM_SZ)) << (SNDDEV_ICODEC_MUL_FACTOR))
+
+#ifdef CONFIG_DEBUG_FS
+static struct adie_codec_action_unit debug_rx_actions[] =
+		HANDSET_RX_8000_OSR_256;
+
+static struct adie_codec_action_unit debug_tx_lb_actions[] = {
+	{ ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF },
+	{ ADIE_CODEC_ACTION_ENTRY,
+	ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x01)},
+	{ ADIE_CODEC_ACTION_ENTRY,
+	ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x00) },
+	{ ADIE_CODEC_ACTION_ENTRY,
+	ADIE_CODEC_PACK_ENTRY(0x8A, 0x30, 0x30)},
+	{ ADIE_CODEC_ACTION_ENTRY,
+	ADIE_CODEC_PACK_ENTRY(0x11, 0xfc, 0xfc)},
+	{ ADIE_CODEC_ACTION_ENTRY,
+	ADIE_CODEC_PACK_ENTRY(0x13, 0xfc, 0x58)},
+	{ ADIE_CODEC_ACTION_ENTRY,
+	ADIE_CODEC_PACK_ENTRY(0x14, 0xff, 0x65)},
+	{ ADIE_CODEC_ACTION_ENTRY,
+	ADIE_CODEC_PACK_ENTRY(0x15, 0xff, 0x64)},
+	{ ADIE_CODEC_ACTION_ENTRY,
+	ADIE_CODEC_PACK_ENTRY(0x82, 0xff, 0x5C)},
+	{ ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY },
+	{ ADIE_CODEC_ACTION_ENTRY,
+	ADIE_CODEC_PACK_ENTRY(0x0D, 0xF0, 0xd0)},
+	{ ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8},
+	{ ADIE_CODEC_ACTION_ENTRY,
+	ADIE_CODEC_PACK_ENTRY(0x83, 0x14, 0x14)},
+	{ ADIE_CODEC_ACTION_ENTRY,
+	ADIE_CODEC_PACK_ENTRY(0x86, 0xff, 0x00)},
+	{ ADIE_CODEC_ACTION_ENTRY,
+	ADIE_CODEC_PACK_ENTRY(0x8A, 0x50, 0x40)},
+	{ ADIE_CODEC_ACTION_ENTRY,
+	ADIE_CODEC_PACK_ENTRY(0x91, 0xFF, 0x01)}, /* Start loop back */
+	{ ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY},
+	{ ADIE_CODEC_ACTION_ENTRY,
+	ADIE_CODEC_PACK_ENTRY(0x8A, 0x10, 0x30)},
+	{ ADIE_CODEC_ACTION_ENTRY,
+	ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)},
+	{ ADIE_CODEC_ACTION_ENTRY,
+	ADIE_CODEC_PACK_ENTRY(0x83, 0x14, 0x00)},
+	{ ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF},
+	{ ADIE_CODEC_ACTION_ENTRY,
+	ADIE_CODEC_PACK_ENTRY(0x11, 0xff, 0x00)}
+};
+
+static struct adie_codec_action_unit debug_tx_actions[] =
+		HANDSET_TX_8000_OSR_256;
+
+static struct adie_codec_hwsetting_entry debug_rx_settings[] = {
+	{
+		.freq_plan = 8000,
+		.osr = 256,
+		.actions = debug_rx_actions,
+		.action_sz = ARRAY_SIZE(debug_rx_actions),
+	}
+};
+
+static struct adie_codec_hwsetting_entry debug_tx_settings[] = {
+	{
+		.freq_plan = 8000,
+		.osr = 256,
+		.actions = debug_tx_actions,
+		.action_sz = ARRAY_SIZE(debug_tx_actions),
+	}
+};
+
+static struct adie_codec_hwsetting_entry debug_tx_lb_settings[] = {
+	{
+		.freq_plan = 8000,
+		.osr = 256,
+		.actions = debug_tx_lb_actions,
+		.action_sz = ARRAY_SIZE(debug_tx_lb_actions),
+	}
+};
+
+static struct adie_codec_dev_profile debug_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = debug_rx_settings,
+	.setting_sz = ARRAY_SIZE(debug_rx_settings),
+};
+
+static struct adie_codec_dev_profile debug_tx_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = debug_tx_settings,
+	.setting_sz = ARRAY_SIZE(debug_tx_settings),
+};
+
+static struct adie_codec_dev_profile debug_tx_lb_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = debug_tx_lb_settings,
+	.setting_sz = ARRAY_SIZE(debug_tx_lb_settings),
+};
+#endif /* CONFIG_DEBUG_FS */
+
+/* Context for each internal codec sound device */
+struct snddev_icodec_state {
+	struct snddev_icodec_data *data;
+	struct adie_codec_path *adie_path;
+	u32 sample_rate;
+	u32 enabled;
+};
+
+/* Global state for the driver */
+struct snddev_icodec_drv_state {
+	struct mutex rx_lock;
+	struct mutex lb_lock;
+	struct mutex tx_lock;
+	u32 rx_active; /* ensure one rx device at a time */
+	u32 tx_active; /* ensure one tx device at a time */
+	struct clk *rx_mclk;
+	struct clk *rx_sclk;
+	struct clk *tx_mclk;
+	struct clk *tx_sclk;
+	struct clk *lpa_codec_clk;
+	struct clk *lpa_core_clk;
+	struct clk *lpa_p_clk;
+	struct lpa_drv *lpa;
+
+	struct wake_lock rx_idlelock;
+	struct wake_lock tx_idlelock;
+};
+
+static struct snddev_icodec_drv_state snddev_icodec_drv;
+
+static int snddev_icodec_open_rx(struct snddev_icodec_state *icodec)
+{
+	int trc, err;
+	int smps_mode = PMAPP_SMPS_MODE_VOTE_PWM;
+	struct msm_afe_config afe_config;
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
+	struct lpa_codec_config lpa_config;
+
+	wake_lock(&drv->rx_idlelock);
+
+	if ((icodec->data->acdb_id == ACDB_ID_HEADSET_SPKR_MONO) ||
+		(icodec->data->acdb_id == ACDB_ID_HEADSET_SPKR_STEREO)) {
+		/* Vote PMAPP_SMPS_MODE_VOTE_PFM for headset */
+		smps_mode = PMAPP_SMPS_MODE_VOTE_PFM;
+		MM_DBG("snddev_icodec_open_rx: PMAPP_SMPS_MODE_VOTE_PFM \n");
+	} else
+		MM_DBG("snddev_icodec_open_rx: PMAPP_SMPS_MODE_VOTE_PWM \n");
+
+	/* Vote for SMPS mode*/
+	err = pmapp_smps_mode_vote(SMPS_AUDIO_PLAYBACK_ID,
+				PMAPP_VREG_S4, smps_mode);
+	if (err != 0)
+		MM_ERR("pmapp_smps_mode_vote error %d\n", err);
+
+	/* enable MI2S RX master block */
+	/* enable MI2S RX bit clock */
+	trc = clk_set_rate(drv->rx_mclk,
+		SNDDEV_ICODEC_CLK_RATE(icodec->sample_rate));
+	if (IS_ERR_VALUE(trc))
+		goto error_invalid_freq;
+	clk_enable(drv->rx_mclk);
+	clk_enable(drv->rx_sclk);
+	/* clk_set_rate(drv->lpa_codec_clk, 1); */ /* Remove if use pcom */
+	clk_enable(drv->lpa_p_clk);
+	clk_enable(drv->lpa_codec_clk);
+	clk_enable(drv->lpa_core_clk);
+
+	/* Enable LPA sub system
+	 */
+	drv->lpa = lpa_get();
+	if (!drv->lpa)
+		goto error_lpa;
+	lpa_config.sample_rate = icodec->sample_rate;
+	lpa_config.sample_width = 16;
+	lpa_config.output_interface = LPA_OUTPUT_INTF_WB_CODEC;
+	lpa_config.num_channels = icodec->data->channel_mode;
+	lpa_cmd_codec_config(drv->lpa, &lpa_config);
+
+	/* Set audio interconnect reg to LPA */
+	audio_interct_codec(AUDIO_INTERCT_LPA);
+
+	/* Set MI2S */
+	mi2s_set_codec_output_path((icodec->data->channel_mode == 2 ?
+	MI2S_CHAN_STEREO : MI2S_CHAN_MONO_PACKED), WT_16_BIT);
+
+	if (icodec->data->voltage_on)
+		icodec->data->voltage_on();
+
+	/* Configure ADIE */
+	trc = adie_codec_open(icodec->data->profile, &icodec->adie_path);
+	if (IS_ERR_VALUE(trc))
+		goto error_adie;
+	/* OSR default to 256, can be changed for power optimization
+	 * If OSR is to be changed, need clock API for setting the divider
+	 */
+	adie_codec_setpath(icodec->adie_path, icodec->sample_rate, 256);
+	/* Start AFE */
+	afe_config.sample_rate = icodec->sample_rate / 1000;
+	afe_config.channel_mode = icodec->data->channel_mode;
+	afe_config.volume = AFE_VOLUME_UNITY;
+	trc = afe_enable(AFE_HW_PATH_CODEC_RX, &afe_config);
+	if (IS_ERR_VALUE(trc))
+		goto error_afe;
+	lpa_cmd_enable_codec(drv->lpa, 1);
+	/* Enable ADIE */
+	adie_codec_proceed_stage(icodec->adie_path, ADIE_CODEC_DIGITAL_READY);
+	adie_codec_proceed_stage(icodec->adie_path,
+					ADIE_CODEC_DIGITAL_ANALOG_READY);
+
+	/* Enable power amplifier */
+	if (icodec->data->pamp_on)
+		icodec->data->pamp_on();
+
+	icodec->enabled = 1;
+
+	wake_unlock(&drv->rx_idlelock);
+	return 0;
+
+error_afe:
+	adie_codec_close(icodec->adie_path);
+	icodec->adie_path = NULL;
+error_adie:
+	lpa_put(drv->lpa);
+error_lpa:
+	clk_disable(drv->lpa_p_clk);
+	clk_disable(drv->lpa_codec_clk);
+	clk_disable(drv->lpa_core_clk);
+	clk_disable(drv->rx_sclk);
+	clk_disable(drv->rx_mclk);
+error_invalid_freq:
+
+	MM_ERR("encounter error\n");
+
+	wake_unlock(&drv->rx_idlelock);
+	return -ENODEV;
+}
+
+static int snddev_icodec_open_tx(struct snddev_icodec_state *icodec)
+{
+	int trc;
+	int i, err;
+	struct msm_afe_config afe_config;
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;;
+
+	wake_lock(&drv->tx_idlelock);
+
+	/* Vote for PWM mode*/
+	err = pmapp_smps_mode_vote(SMPS_AUDIO_RECORD_ID,
+			PMAPP_VREG_S4, PMAPP_SMPS_MODE_VOTE_PWM);
+	if (err != 0)
+		MM_ERR("pmapp_smps_mode_vote error %d\n", err);
+
+	/* Reuse pamp_on for TX platform-specific setup  */
+	if (icodec->data->pamp_on)
+		icodec->data->pamp_on();
+
+	for (i = 0; i < icodec->data->pmctl_id_sz; i++) {
+		pmic_hsed_enable(icodec->data->pmctl_id[i],
+			 PM_HSED_ENABLE_PWM_TCXO);
+	}
+
+	/* enable MI2S TX master block */
+	/* enable MI2S TX bit clock */
+	trc = clk_set_rate(drv->tx_mclk,
+		SNDDEV_ICODEC_CLK_RATE(icodec->sample_rate));
+	if (IS_ERR_VALUE(trc))
+		goto error_invalid_freq;
+	clk_enable(drv->tx_mclk);
+	clk_enable(drv->tx_sclk);
+
+	/* Set MI2S */
+	mi2s_set_codec_input_path((icodec->data->channel_mode ==
+				REAL_STEREO_CHANNEL_MODE ? MI2S_CHAN_STEREO :
+				(icodec->data->channel_mode == 2 ?
+				 MI2S_CHAN_STEREO : MI2S_CHAN_MONO_RAW)),
+				WT_16_BIT);
+	/* Configure ADIE */
+	trc = adie_codec_open(icodec->data->profile, &icodec->adie_path);
+	if (IS_ERR_VALUE(trc))
+		goto error_adie;
+	/* Enable ADIE */
+	adie_codec_setpath(icodec->adie_path, icodec->sample_rate, 256);
+	adie_codec_proceed_stage(icodec->adie_path, ADIE_CODEC_DIGITAL_READY);
+	adie_codec_proceed_stage(icodec->adie_path,
+	ADIE_CODEC_DIGITAL_ANALOG_READY);
+
+	/* Start AFE */
+	afe_config.sample_rate = icodec->sample_rate / 1000;
+	afe_config.channel_mode = icodec->data->channel_mode;
+	afe_config.volume = AFE_VOLUME_UNITY;
+	trc = afe_enable(AFE_HW_PATH_CODEC_TX, &afe_config);
+	if (IS_ERR_VALUE(trc))
+		goto error_afe;
+
+
+	icodec->enabled = 1;
+
+	wake_unlock(&drv->tx_idlelock);
+	return 0;
+
+error_afe:
+	adie_codec_close(icodec->adie_path);
+	icodec->adie_path = NULL;
+error_adie:
+	clk_disable(drv->tx_sclk);
+	clk_disable(drv->tx_mclk);
+error_invalid_freq:
+
+	/* Disable mic bias */
+	for (i = 0; i < icodec->data->pmctl_id_sz; i++) {
+		pmic_hsed_enable(icodec->data->pmctl_id[i],
+			 PM_HSED_ENABLE_OFF);
+	}
+
+	if (icodec->data->pamp_off)
+		icodec->data->pamp_off();
+
+	MM_ERR("encounter error\n");
+
+	wake_unlock(&drv->tx_idlelock);
+	return -ENODEV;
+}
+
+static int snddev_icodec_close_lb(struct snddev_icodec_state *icodec)
+{
+	/* Disable power amplifier */
+	if (icodec->data->pamp_off)
+		icodec->data->pamp_off();
+
+	if (icodec->adie_path) {
+		adie_codec_proceed_stage(icodec->adie_path,
+						ADIE_CODEC_DIGITAL_OFF);
+		adie_codec_close(icodec->adie_path);
+		icodec->adie_path = NULL;
+	}
+	if (icodec->data->voltage_off)
+		icodec->data->voltage_off();
+
+	return 0;
+}
+
+static int snddev_icodec_close_rx(struct snddev_icodec_state *icodec)
+{
+	int err;
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
+
+	wake_lock(&drv->rx_idlelock);
+
+	/* Remove the vote for SMPS mode*/
+	err = pmapp_smps_mode_vote(SMPS_AUDIO_PLAYBACK_ID,
+			PMAPP_VREG_S4, PMAPP_SMPS_MODE_VOTE_DONTCARE);
+	if (err != 0)
+		MM_ERR("pmapp_smps_mode_vote error %d\n", err);
+
+	/* Disable power amplifier */
+	if (icodec->data->pamp_off)
+		icodec->data->pamp_off();
+
+	/* Disable ADIE */
+	adie_codec_proceed_stage(icodec->adie_path, ADIE_CODEC_DIGITAL_OFF);
+	adie_codec_close(icodec->adie_path);
+	icodec->adie_path = NULL;
+
+	afe_disable(AFE_HW_PATH_CODEC_RX);
+
+	if (icodec->data->voltage_off)
+		icodec->data->voltage_off();
+
+	/* Disable LPA Sub system */
+	lpa_cmd_enable_codec(drv->lpa, 0);
+	lpa_put(drv->lpa);
+
+	/* Disable LPA clocks */
+	clk_disable(drv->lpa_p_clk);
+	clk_disable(drv->lpa_codec_clk);
+	clk_disable(drv->lpa_core_clk);
+
+	/* Disable MI2S RX master block */
+	/* Disable MI2S RX bit clock */
+	clk_disable(drv->rx_sclk);
+	clk_disable(drv->rx_mclk);
+
+	icodec->enabled = 0;
+
+	wake_unlock(&drv->rx_idlelock);
+	return 0;
+}
+
+static int snddev_icodec_close_tx(struct snddev_icodec_state *icodec)
+{
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
+	int i, err;
+
+	wake_lock(&drv->tx_idlelock);
+
+	/* Remove the vote for SMPS mode*/
+	err = pmapp_smps_mode_vote(SMPS_AUDIO_RECORD_ID,
+			PMAPP_VREG_S4, PMAPP_SMPS_MODE_VOTE_DONTCARE);
+	if (err != 0)
+		MM_ERR("pmapp_smps_mode_vote error %d\n", err);
+
+	afe_disable(AFE_HW_PATH_CODEC_TX);
+
+	/* Disable ADIE */
+	adie_codec_proceed_stage(icodec->adie_path, ADIE_CODEC_DIGITAL_OFF);
+	adie_codec_close(icodec->adie_path);
+	icodec->adie_path = NULL;
+
+	/* Disable MI2S TX master block */
+	/* Disable MI2S TX bit clock */
+	clk_disable(drv->tx_sclk);
+	clk_disable(drv->tx_mclk);
+
+	/* Disable mic bias */
+	for (i = 0; i < icodec->data->pmctl_id_sz; i++) {
+		pmic_hsed_enable(icodec->data->pmctl_id[i],
+			 PM_HSED_ENABLE_OFF);
+	}
+
+	/* Reuse pamp_off for TX platform-specific setup  */
+	if (icodec->data->pamp_off)
+		icodec->data->pamp_off();
+
+	icodec->enabled = 0;
+
+	wake_unlock(&drv->tx_idlelock);
+	return 0;
+}
+
+static int snddev_icodec_open_lb(struct snddev_icodec_state *icodec)
+{
+	int trc;
+	trc = adie_codec_open(icodec->data->profile, &icodec->adie_path);
+	if (IS_ERR_VALUE(trc))
+		pr_err("%s: adie codec open failed\n", __func__);
+	else
+		adie_codec_setpath(icodec->adie_path,
+						icodec->sample_rate, 256);
+
+	if (icodec->adie_path)
+		adie_codec_proceed_stage(icodec->adie_path,
+					ADIE_CODEC_DIGITAL_ANALOG_READY);
+	if (icodec->data->pamp_on)
+		icodec->data->pamp_on();
+
+	icodec->enabled = 1;
+	return 0;
+}
+
+static int snddev_icodec_set_device_volume_impl(
+		struct msm_snddev_info *dev_info, u32 volume)
+{
+	struct snddev_icodec_state *icodec;
+	u8 afe_path_id;
+
+	int rc = 0;
+
+	icodec = dev_info->private_data;
+
+	if (icodec->data->capability & SNDDEV_CAP_RX)
+		afe_path_id = AFE_HW_PATH_CODEC_RX;
+	else
+		afe_path_id = AFE_HW_PATH_CODEC_TX;
+
+	if (icodec->data->dev_vol_type & SNDDEV_DEV_VOL_DIGITAL) {
+
+		rc = adie_codec_set_device_digital_volume(icodec->adie_path,
+				icodec->data->channel_mode ==
+						REAL_STEREO_CHANNEL_MODE ?
+					2 : icodec->data->channel_mode, volume);
+		if (rc < 0) {
+			MM_ERR("unable to set_device_digital_volume for"
+				"%s volume in percentage = %u\n",
+				dev_info->name, volume);
+			return rc;
+		}
+
+	} else if (icodec->data->dev_vol_type & SNDDEV_DEV_VOL_ANALOG) {
+		rc = adie_codec_set_device_analog_volume(icodec->adie_path,
+				icodec->data->channel_mode ==
+						REAL_STEREO_CHANNEL_MODE ?
+					2 : icodec->data->channel_mode, volume);
+		if (rc < 0) {
+			MM_ERR("unable to set_device_analog_volume for"
+				"%s volume in percentage = %u\n",
+				dev_info->name, volume);
+			return rc;
+		}
+	}
+	else {
+		MM_ERR("Invalid device volume control\n");
+		return -EPERM;
+	}
+	return rc;
+}
+
+static int snddev_icodec_close(struct msm_snddev_info *dev_info)
+{
+	int rc = 0;
+	struct snddev_icodec_state *icodec;
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
+	if (!dev_info) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	icodec = dev_info->private_data;
+
+	if (icodec->data->capability & SNDDEV_CAP_RX) {
+		mutex_lock(&drv->rx_lock);
+		if (!drv->rx_active) {
+			mutex_unlock(&drv->rx_lock);
+			rc = -EPERM;
+			goto error;
+		}
+		rc = snddev_icodec_close_rx(icodec);
+		if (!IS_ERR_VALUE(rc))
+			drv->rx_active = 0;
+		mutex_unlock(&drv->rx_lock);
+	} else if (icodec->data->capability & SNDDEV_CAP_LB) {
+		mutex_lock(&drv->lb_lock);
+		rc = snddev_icodec_close_lb(icodec);
+		mutex_unlock(&drv->lb_lock);
+	} else {
+		mutex_lock(&drv->tx_lock);
+		if (!drv->tx_active) {
+			mutex_unlock(&drv->tx_lock);
+			rc = -EPERM;
+			goto error;
+		}
+		rc = snddev_icodec_close_tx(icodec);
+		if (!IS_ERR_VALUE(rc))
+			drv->tx_active = 0;
+		mutex_unlock(&drv->tx_lock);
+	}
+
+error:
+	return rc;
+}
+
+static int snddev_icodec_open(struct msm_snddev_info *dev_info)
+{
+	int rc = 0;
+	struct snddev_icodec_state *icodec;
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
+
+	if (!dev_info) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	icodec = dev_info->private_data;
+
+	if (icodec->data->capability & SNDDEV_CAP_RX) {
+		mutex_lock(&drv->rx_lock);
+		if (drv->rx_active) {
+			mutex_unlock(&drv->rx_lock);
+			rc = -EBUSY;
+			goto error;
+		}
+		rc = snddev_icodec_open_rx(icodec);
+
+		if (!IS_ERR_VALUE(rc)) {
+			drv->rx_active = 1;
+			if ((icodec->data->dev_vol_type & (
+				SNDDEV_DEV_VOL_DIGITAL |
+				SNDDEV_DEV_VOL_ANALOG)))
+				rc = snddev_icodec_set_device_volume_impl(
+						dev_info, dev_info->dev_volume);
+				if (IS_ERR_VALUE(rc)) {
+					MM_ERR("Failed to set device volume"
+						" impl for rx device\n");
+					snddev_icodec_close(dev_info);
+					mutex_unlock(&drv->rx_lock);
+					goto error;
+				}
+		}
+		mutex_unlock(&drv->rx_lock);
+	} else if (icodec->data->capability & SNDDEV_CAP_LB) {
+		mutex_lock(&drv->lb_lock);
+		rc = snddev_icodec_open_lb(icodec);
+		if (!IS_ERR_VALUE(rc)) {
+			if ((icodec->data->dev_vol_type & (
+							SNDDEV_DEV_VOL_DIGITAL |
+							SNDDEV_DEV_VOL_ANALOG)))
+				rc = snddev_icodec_set_device_volume_impl(
+							dev_info,
+							 dev_info->dev_volume);
+				if (rc < 0)
+					MM_ERR("failed to set device volume\n");
+		}
+		mutex_unlock(&drv->lb_lock);
+	} else {
+		mutex_lock(&drv->tx_lock);
+		if (drv->tx_active) {
+			mutex_unlock(&drv->tx_lock);
+			rc = -EBUSY;
+			goto error;
+		}
+		rc = snddev_icodec_open_tx(icodec);
+
+		if (!IS_ERR_VALUE(rc)) {
+			drv->tx_active = 1;
+			if ((icodec->data->dev_vol_type & (
+				SNDDEV_DEV_VOL_DIGITAL |
+				SNDDEV_DEV_VOL_ANALOG)))
+				rc = snddev_icodec_set_device_volume_impl(
+						dev_info, dev_info->dev_volume);
+				if (IS_ERR_VALUE(rc)) {
+					MM_ERR("Failed to set device volume"
+						" impl for tx device\n");
+					snddev_icodec_close(dev_info);
+					mutex_unlock(&drv->tx_lock);
+					goto error;
+				}
+		}
+		mutex_unlock(&drv->tx_lock);
+	}
+error:
+	return rc;
+}
+
+static int snddev_icodec_check_freq(u32 req_freq)
+{
+	int rc = -EINVAL;
+
+	if ((req_freq != 0) && (req_freq >= 8000) && (req_freq <= 48000)) {
+		if ((req_freq == 8000) || (req_freq == 11025) ||
+			(req_freq == 12000) || (req_freq == 16000) ||
+			(req_freq == 22050) || (req_freq == 24000) ||
+			(req_freq == 32000) || (req_freq == 44100) ||
+			(req_freq == 48000)) {
+				rc = 0;
+		} else
+			MM_INFO("Unsupported Frequency:%d\n", req_freq);
+		}
+		return rc;
+}
+
+static int snddev_icodec_set_freq(struct msm_snddev_info *dev_info, u32 rate)
+{
+	int rc;
+	struct snddev_icodec_state *icodec;
+
+	if (!dev_info) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	icodec = dev_info->private_data;
+	if (adie_codec_freq_supported(icodec->data->profile, rate) != 0) {
+		rc = -EINVAL;
+		goto error;
+	} else {
+		if (snddev_icodec_check_freq(rate) != 0) {
+			rc = -EINVAL;
+			goto error;
+		} else
+			icodec->sample_rate = rate;
+	}
+
+	if (icodec->enabled) {
+		snddev_icodec_close(dev_info);
+		snddev_icodec_open(dev_info);
+	}
+
+	return icodec->sample_rate;
+
+error:
+	return rc;
+}
+
+static int snddev_icodec_enable_sidetone(struct msm_snddev_info *dev_info,
+	u32 enable)
+{
+	int rc = 0;
+	struct snddev_icodec_state *icodec;
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
+
+	if (!dev_info) {
+		MM_ERR("invalid dev_info\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	icodec = dev_info->private_data;
+
+	if (icodec->data->capability & SNDDEV_CAP_RX) {
+		mutex_lock(&drv->rx_lock);
+		if (!drv->rx_active || !dev_info->opened) {
+			MM_ERR("dev not active\n");
+			rc = -EPERM;
+			mutex_unlock(&drv->rx_lock);
+			goto error;
+		}
+		rc = adie_codec_enable_sidetone(icodec->adie_path, enable);
+		mutex_unlock(&drv->rx_lock);
+	} else {
+		rc = -EINVAL;
+		MM_ERR("rx device only\n");
+	}
+
+error:
+	return rc;
+
+}
+
+int snddev_icodec_set_device_volume(struct msm_snddev_info *dev_info,
+		u32 volume)
+{
+	struct snddev_icodec_state *icodec;
+	struct mutex *lock;
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
+	int rc = -EPERM;
+
+	if (!dev_info) {
+		MM_INFO("device not intilized.\n");
+		return  -EINVAL;
+	}
+
+	icodec = dev_info->private_data;
+
+	if (!(icodec->data->dev_vol_type & (SNDDEV_DEV_VOL_DIGITAL
+				| SNDDEV_DEV_VOL_ANALOG))) {
+
+		MM_INFO("device %s does not support device volume "
+				"control.", dev_info->name);
+		return -EPERM;
+	}
+	dev_info->dev_volume =  volume;
+
+	if (icodec->data->capability & SNDDEV_CAP_RX)
+		lock = &drv->rx_lock;
+	else if (icodec->data->capability & SNDDEV_CAP_LB)
+		lock = &drv->lb_lock;
+	else
+		lock = &drv->tx_lock;
+
+	mutex_lock(lock);
+
+	rc = snddev_icodec_set_device_volume_impl(dev_info,
+			dev_info->dev_volume);
+	mutex_unlock(lock);
+	return rc;
+}
+
+static int snddev_icodec_probe(struct platform_device *pdev)
+{
+	int rc = 0, i;
+	struct snddev_icodec_data *pdata;
+	struct msm_snddev_info *dev_info;
+	struct snddev_icodec_state *icodec;
+
+	if (!pdev || !pdev->dev.platform_data) {
+		printk(KERN_ALERT "Invalid caller \n");
+		rc = -1;
+		goto error;
+	}
+	pdata = pdev->dev.platform_data;
+	if ((pdata->capability & SNDDEV_CAP_RX) &&
+	   (pdata->capability & SNDDEV_CAP_TX)) {
+		MM_ERR("invalid device data either RX or TX\n");
+		goto error;
+	}
+	icodec = kzalloc(sizeof(struct snddev_icodec_state), GFP_KERNEL);
+	if (!icodec) {
+		rc = -ENOMEM;
+		goto error;
+	}
+	dev_info = kmalloc(sizeof(struct msm_snddev_info), GFP_KERNEL);
+	if (!dev_info) {
+		kfree(icodec);
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	dev_info->name = pdata->name;
+	dev_info->copp_id = pdata->copp_id;
+	dev_info->acdb_id = pdata->acdb_id;
+	dev_info->private_data = (void *) icodec;
+	dev_info->dev_ops.open = snddev_icodec_open;
+	dev_info->dev_ops.close = snddev_icodec_close;
+	dev_info->dev_ops.set_freq = snddev_icodec_set_freq;
+	dev_info->dev_ops.set_device_volume = snddev_icodec_set_device_volume;
+	dev_info->capability = pdata->capability;
+	dev_info->opened = 0;
+	msm_snddev_register(dev_info);
+	icodec->data = pdata;
+	icodec->sample_rate = pdata->default_sample_rate;
+	dev_info->sample_rate = pdata->default_sample_rate;
+	if (pdata->capability & SNDDEV_CAP_RX) {
+		for (i = 0; i < VOC_RX_VOL_ARRAY_NUM; i++) {
+			dev_info->max_voc_rx_vol[i] =
+				pdata->max_voice_rx_vol[i];
+			dev_info->min_voc_rx_vol[i] =
+				pdata->min_voice_rx_vol[i];
+		}
+		/*sidetone is enabled only for  the device which
+		property set for side tone*/
+		if (pdata->property & SIDE_TONE_MASK)
+			dev_info->dev_ops.enable_sidetone =
+				snddev_icodec_enable_sidetone;
+		else
+			dev_info->dev_ops.enable_sidetone = NULL;
+	} else {
+		dev_info->dev_ops.enable_sidetone = NULL;
+	}
+
+error:
+	return rc;
+}
+
+static int snddev_icodec_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static struct platform_driver snddev_icodec_driver = {
+  .probe = snddev_icodec_probe,
+  .remove = snddev_icodec_remove,
+  .driver = { .name = "snddev_icodec" }
+};
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *debugfs_sdev_dent;
+static struct dentry *debugfs_afelb;
+static struct dentry *debugfs_adielb;
+static struct adie_codec_path *debugfs_rx_adie;
+static struct adie_codec_path *debugfs_tx_adie;
+
+static int snddev_icodec_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	MM_INFO("snddev_icodec: debug intf %s\n", (char *) file->private_data);
+	return 0;
+}
+
+static void debugfs_adie_loopback(u32 loop)
+{
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
+
+	if (loop) {
+
+		/* enable MI2S RX master block */
+		/* enable MI2S RX bit clock */
+		clk_set_rate(drv->rx_mclk,
+			SNDDEV_ICODEC_CLK_RATE(8000));
+		clk_enable(drv->rx_mclk);
+		clk_enable(drv->rx_sclk);
+
+		MM_INFO("configure ADIE RX path\n");
+		/* Configure ADIE */
+		adie_codec_open(&debug_rx_profile, &debugfs_rx_adie);
+		adie_codec_setpath(debugfs_rx_adie, 8000, 256);
+		adie_codec_proceed_stage(debugfs_rx_adie,
+		ADIE_CODEC_DIGITAL_ANALOG_READY);
+
+		MM_INFO("Enable Handset Mic bias\n");
+		pmic_hsed_enable(PM_HSED_CONTROLLER_0, PM_HSED_ENABLE_PWM_TCXO);
+		/* enable MI2S TX master block */
+		/* enable MI2S TX bit clock */
+		clk_set_rate(drv->tx_mclk,
+			SNDDEV_ICODEC_CLK_RATE(8000));
+		clk_enable(drv->tx_mclk);
+		clk_enable(drv->tx_sclk);
+
+		MM_INFO("configure ADIE TX path\n");
+		/* Configure ADIE */
+		adie_codec_open(&debug_tx_lb_profile, &debugfs_tx_adie);
+		adie_codec_setpath(debugfs_tx_adie, 8000, 256);
+		adie_codec_proceed_stage(debugfs_tx_adie,
+		ADIE_CODEC_DIGITAL_ANALOG_READY);
+	} else {
+		/* Disable ADIE */
+		adie_codec_proceed_stage(debugfs_rx_adie,
+		ADIE_CODEC_DIGITAL_OFF);
+		adie_codec_close(debugfs_rx_adie);
+		adie_codec_proceed_stage(debugfs_tx_adie,
+		ADIE_CODEC_DIGITAL_OFF);
+		adie_codec_close(debugfs_tx_adie);
+
+		pmic_hsed_enable(PM_HSED_CONTROLLER_0, PM_HSED_ENABLE_OFF);
+
+		/* Disable MI2S RX master block */
+		/* Disable MI2S RX bit clock */
+		clk_disable(drv->rx_sclk);
+		clk_disable(drv->rx_mclk);
+
+		/* Disable MI2S TX master block */
+		/* Disable MI2S TX bit clock */
+		clk_disable(drv->tx_sclk);
+		clk_disable(drv->tx_mclk);
+	}
+}
+
+static void debugfs_afe_loopback(u32 loop)
+{
+	int trc;
+	struct msm_afe_config afe_config;
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
+	struct lpa_codec_config lpa_config;
+
+	if (loop) {
+		/* Vote for SMPS mode*/
+		pmapp_smps_mode_vote(SMPS_AUDIO_PLAYBACK_ID,
+				PMAPP_VREG_S4, PMAPP_SMPS_MODE_VOTE_PWM);
+
+		/* enable MI2S RX master block */
+		/* enable MI2S RX bit clock */
+		trc = clk_set_rate(drv->rx_mclk,
+		SNDDEV_ICODEC_CLK_RATE(8000));
+		if (IS_ERR_VALUE(trc))
+			MM_ERR("failed to set clk rate\n");
+		clk_enable(drv->rx_mclk);
+		clk_enable(drv->rx_sclk);
+		clk_enable(drv->lpa_p_clk);
+		clk_enable(drv->lpa_codec_clk);
+		clk_enable(drv->lpa_core_clk);
+		/* Enable LPA sub system
+		 */
+		drv->lpa = lpa_get();
+		if (!drv->lpa)
+			MM_ERR("failed to enable lpa\n");
+		lpa_config.sample_rate = 8000;
+		lpa_config.sample_width = 16;
+		lpa_config.output_interface = LPA_OUTPUT_INTF_WB_CODEC;
+		lpa_config.num_channels = 1;
+		lpa_cmd_codec_config(drv->lpa, &lpa_config);
+		/* Set audio interconnect reg to LPA */
+		audio_interct_codec(AUDIO_INTERCT_LPA);
+		mi2s_set_codec_output_path(MI2S_CHAN_MONO_PACKED, WT_16_BIT);
+		MM_INFO("configure ADIE RX path\n");
+		/* Configure ADIE */
+		adie_codec_open(&debug_rx_profile, &debugfs_rx_adie);
+		adie_codec_setpath(debugfs_rx_adie, 8000, 256);
+		lpa_cmd_enable_codec(drv->lpa, 1);
+
+		/* Start AFE for RX */
+		afe_config.sample_rate = 0x8;
+		afe_config.channel_mode = 1;
+		afe_config.volume = AFE_VOLUME_UNITY;
+		MM_INFO("enable afe\n");
+		trc = afe_enable(AFE_HW_PATH_CODEC_RX, &afe_config);
+		if (IS_ERR_VALUE(trc))
+			MM_ERR("fail to enable afe RX\n");
+		adie_codec_proceed_stage(debugfs_rx_adie,
+		ADIE_CODEC_DIGITAL_READY);
+		adie_codec_proceed_stage(debugfs_rx_adie,
+		ADIE_CODEC_DIGITAL_ANALOG_READY);
+
+		/* Vote for PWM mode*/
+		pmapp_smps_mode_vote(SMPS_AUDIO_RECORD_ID,
+			PMAPP_VREG_S4, PMAPP_SMPS_MODE_VOTE_PWM);
+
+		MM_INFO("Enable Handset Mic bias\n");
+		pmic_hsed_enable(PM_HSED_CONTROLLER_0, PM_HSED_ENABLE_PWM_TCXO);
+
+		/* enable MI2S TX master block */
+		/* enable MI2S TX bit clock */
+		clk_set_rate(drv->tx_mclk,
+			SNDDEV_ICODEC_CLK_RATE(8000));
+		clk_enable(drv->tx_mclk);
+		clk_enable(drv->tx_sclk);
+		/* Set MI2S */
+		mi2s_set_codec_input_path(MI2S_CHAN_MONO_PACKED, WT_16_BIT);
+		MM_INFO("configure ADIE TX path\n");
+		/* Configure ADIE */
+		adie_codec_open(&debug_tx_profile, &debugfs_tx_adie);
+		adie_codec_setpath(debugfs_tx_adie, 8000, 256);
+		adie_codec_proceed_stage(debugfs_tx_adie,
+		ADIE_CODEC_DIGITAL_READY);
+		adie_codec_proceed_stage(debugfs_tx_adie,
+		ADIE_CODEC_DIGITAL_ANALOG_READY);
+		/* Start AFE for TX */
+		afe_config.sample_rate = 0x8;
+		afe_config.channel_mode = 1;
+		afe_config.volume = AFE_VOLUME_UNITY;
+		trc = afe_enable(AFE_HW_PATH_CODEC_TX, &afe_config);
+		if (IS_ERR_VALUE(trc))
+			MM_ERR("failed to enable AFE TX\n");
+		/* Set the volume level to non unity, to avoid
+		   loopback effect */
+		afe_device_volume_ctrl(AFE_HW_PATH_CODEC_RX, 0x0500);
+
+		/* enable afe loopback */
+		afe_loopback(1);
+		MM_INFO("AFE loopback enabled\n");
+	} else {
+		/* disable afe loopback */
+		afe_loopback(0);
+		/* Remove the vote for SMPS mode*/
+		pmapp_smps_mode_vote(SMPS_AUDIO_PLAYBACK_ID,
+			PMAPP_VREG_S4, PMAPP_SMPS_MODE_VOTE_DONTCARE);
+
+		/* Disable ADIE */
+		adie_codec_proceed_stage(debugfs_rx_adie,
+		ADIE_CODEC_DIGITAL_OFF);
+		adie_codec_close(debugfs_rx_adie);
+		/* Disable AFE for RX */
+		afe_disable(AFE_HW_PATH_CODEC_RX);
+
+		/* Disable LPA Sub system */
+		lpa_cmd_enable_codec(drv->lpa, 0);
+		lpa_put(drv->lpa);
+
+		/* Disable LPA clocks */
+		clk_disable(drv->lpa_p_clk);
+		clk_disable(drv->lpa_codec_clk);
+		clk_disable(drv->lpa_core_clk);
+
+		/* Disable MI2S RX master block */
+		/* Disable MI2S RX bit clock */
+		clk_disable(drv->rx_sclk);
+		clk_disable(drv->rx_mclk);
+
+		pmapp_smps_mode_vote(SMPS_AUDIO_RECORD_ID,
+			PMAPP_VREG_S4, PMAPP_SMPS_MODE_VOTE_DONTCARE);
+
+		/* Disable AFE for TX */
+		afe_disable(AFE_HW_PATH_CODEC_TX);
+
+		/* Disable ADIE */
+		adie_codec_proceed_stage(debugfs_tx_adie,
+		ADIE_CODEC_DIGITAL_OFF);
+		adie_codec_close(debugfs_tx_adie);
+		/* Disable MI2S TX master block */
+		/* Disable MI2S TX bit clock */
+		clk_disable(drv->tx_sclk);
+		clk_disable(drv->tx_mclk);
+		pmic_hsed_enable(PM_HSED_CONTROLLER_0, PM_HSED_ENABLE_OFF);
+		MM_INFO("AFE loopback disabled\n");
+	}
+}
+
+static ssize_t snddev_icodec_debug_write(struct file *filp,
+	const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	char *lb_str = filp->private_data;
+	char cmd;
+
+	if (get_user(cmd, ubuf))
+		return -EFAULT;
+
+	MM_INFO("%s %c\n", lb_str, cmd);
+
+	if (!strcmp(lb_str, "adie_loopback")) {
+		switch (cmd) {
+		case '1':
+			debugfs_adie_loopback(1);
+			break;
+		case '0':
+			debugfs_adie_loopback(0);
+			break;
+		}
+	} else if (!strcmp(lb_str, "afe_loopback")) {
+		switch (cmd) {
+		case '1':
+			debugfs_afe_loopback(1);
+			break;
+		case '0':
+			debugfs_afe_loopback(0);
+			break;
+		}
+	}
+
+	return cnt;
+}
+
+static const struct file_operations snddev_icodec_debug_fops = {
+	.open = snddev_icodec_debug_open,
+	.write = snddev_icodec_debug_write
+};
+#endif
+
+static int __init snddev_icodec_init(void)
+{
+	s32 rc;
+	struct snddev_icodec_drv_state *icodec_drv = &snddev_icodec_drv;
+
+	rc = platform_driver_register(&snddev_icodec_driver);
+	if (IS_ERR_VALUE(rc))
+		goto error_platform_driver;
+	icodec_drv->rx_mclk = clk_get(NULL, "mi2s_codec_rx_m_clk");
+	if (IS_ERR(icodec_drv->rx_mclk))
+		goto error_rx_mclk;
+	icodec_drv->rx_sclk = clk_get(NULL, "mi2s_codec_rx_s_clk");
+	if (IS_ERR(icodec_drv->rx_sclk))
+		goto error_rx_sclk;
+	icodec_drv->tx_mclk = clk_get(NULL, "mi2s_codec_tx_m_clk");
+	if (IS_ERR(icodec_drv->tx_mclk))
+		goto error_tx_mclk;
+	icodec_drv->tx_sclk = clk_get(NULL, "mi2s_codec_tx_s_clk");
+	if (IS_ERR(icodec_drv->tx_sclk))
+		goto error_tx_sclk;
+	icodec_drv->lpa_codec_clk = clk_get(NULL, "lpa_codec_clk");
+	if (IS_ERR(icodec_drv->lpa_codec_clk))
+		goto error_lpa_codec_clk;
+	icodec_drv->lpa_core_clk = clk_get(NULL, "lpa_core_clk");
+	if (IS_ERR(icodec_drv->lpa_core_clk))
+		goto error_lpa_core_clk;
+	icodec_drv->lpa_p_clk = clk_get(NULL, "lpa_pclk");
+	if (IS_ERR(icodec_drv->lpa_p_clk))
+		goto error_lpa_p_clk;
+
+#ifdef CONFIG_DEBUG_FS
+	debugfs_sdev_dent = debugfs_create_dir("snddev_icodec", 0);
+	if (debugfs_sdev_dent) {
+		debugfs_afelb = debugfs_create_file("afe_loopback",
+		S_IFREG | S_IWUGO, debugfs_sdev_dent,
+		(void *) "afe_loopback", &snddev_icodec_debug_fops);
+		debugfs_adielb = debugfs_create_file("adie_loopback",
+		S_IFREG | S_IWUGO, debugfs_sdev_dent,
+		(void *) "adie_loopback", &snddev_icodec_debug_fops);
+	}
+#endif
+	mutex_init(&icodec_drv->rx_lock);
+	mutex_init(&icodec_drv->lb_lock);
+	mutex_init(&icodec_drv->tx_lock);
+	icodec_drv->rx_active = 0;
+	icodec_drv->tx_active = 0;
+	icodec_drv->lpa = NULL;
+	wake_lock_init(&icodec_drv->tx_idlelock, WAKE_LOCK_IDLE,
+			"snddev_tx_idle");
+	wake_lock_init(&icodec_drv->rx_idlelock, WAKE_LOCK_IDLE,
+			"snddev_rx_idle");
+	return 0;
+
+error_lpa_p_clk:
+	clk_put(icodec_drv->lpa_core_clk);
+error_lpa_core_clk:
+	clk_put(icodec_drv->lpa_codec_clk);
+error_lpa_codec_clk:
+	clk_put(icodec_drv->tx_sclk);
+error_tx_sclk:
+	clk_put(icodec_drv->tx_mclk);
+error_tx_mclk:
+	clk_put(icodec_drv->rx_sclk);
+error_rx_sclk:
+	clk_put(icodec_drv->rx_mclk);
+error_rx_mclk:
+	platform_driver_unregister(&snddev_icodec_driver);
+error_platform_driver:
+
+	MM_ERR("encounter error\n");
+	return -ENODEV;
+}
+
+static void __exit snddev_icodec_exit(void)
+{
+	struct snddev_icodec_drv_state *icodec_drv = &snddev_icodec_drv;
+
+#ifdef CONFIG_DEBUG_FS
+	if (debugfs_afelb)
+		debugfs_remove(debugfs_afelb);
+	if (debugfs_adielb)
+		debugfs_remove(debugfs_adielb);
+	if (debugfs_sdev_dent)
+		debugfs_remove(debugfs_sdev_dent);
+#endif
+	platform_driver_unregister(&snddev_icodec_driver);
+
+	clk_put(icodec_drv->rx_sclk);
+	clk_put(icodec_drv->rx_mclk);
+	clk_put(icodec_drv->tx_sclk);
+	clk_put(icodec_drv->tx_mclk);
+	return;
+}
+
+module_init(snddev_icodec_init);
+module_exit(snddev_icodec_exit);
+
+MODULE_DESCRIPTION("ICodec Sound Device driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5v2/snddev_mi2s.c b/arch/arm/mach-msm/qdsp5v2/snddev_mi2s.c
new file mode 100644
index 0000000..939cc8b
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/snddev_mi2s.c
@@ -0,0 +1,405 @@
+/* Copyright (c) 2010, 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/qdsp5v2/audio_interct.h>
+#include <mach/qdsp5v2/mi2s.h>
+#include <mach/qdsp5v2/afe.h>
+#include <mach/debug_mm.h>
+#include <mach/qdsp5v2/snddev_mi2s.h>
+
+/* Global state for the driver */
+struct snddev_mi2s_drv_state {
+	struct clk *mclk;
+	struct clk *sclk;
+	struct mutex lock;
+	u8 sd_lines_used;
+	u8 clocks_enabled;
+};
+
+static struct snddev_mi2s_drv_state snddev_mi2s_drv;
+
+static int snddev_mi2s_open_tx(struct msm_snddev_info *dev_info)
+{
+	u8 channels;
+	struct msm_afe_config afe_config;
+	int rc;
+	struct snddev_mi2s_data *snddev_mi2s_data = dev_info->private_data;
+
+	MM_DBG("%s: channel_mode = %u sd_line_mask = 0x%x "
+		"default_sample_rate = %u\n", __func__,
+		snddev_mi2s_data->channel_mode, snddev_mi2s_data->sd_lines,
+		snddev_mi2s_data->default_sample_rate);
+
+	if (snddev_mi2s_data->channel_mode == 2) {
+		channels = MI2S_CHAN_STEREO;
+	} else {
+		MM_ERR("%s: Invalid number of channels = %u\n", __func__,
+			snddev_mi2s_data->channel_mode);
+		return -EINVAL;
+	}
+
+	/* Set MI2S */
+	mi2s_set_hdmi_input_path(channels, WT_16_BIT,
+				 snddev_mi2s_data->sd_lines);
+
+	afe_config.sample_rate = snddev_mi2s_data->default_sample_rate / 1000;
+	afe_config.channel_mode = snddev_mi2s_data->channel_mode;
+	afe_config.volume = AFE_VOLUME_UNITY;
+	rc = afe_enable(AFE_HW_PATH_MI2S_TX, &afe_config);
+
+	if (IS_ERR_VALUE(rc)) {
+		MM_ERR("%s: afe_enable failed for AFE_HW_PATH_MI2S_TX "
+		       "rc = %d\n", __func__, rc);
+		return -ENODEV;
+	}
+
+	/* Enable audio path */
+	if (snddev_mi2s_data->route)
+		snddev_mi2s_data->route();
+
+	return 0;
+}
+
+static int snddev_mi2s_open_rx(struct msm_snddev_info *dev_info)
+{
+	int rc;
+	struct msm_afe_config afe_config;
+	u8 channels;
+	struct snddev_mi2s_data *snddev_mi2s_data = dev_info->private_data;
+
+	MM_DBG("%s: channel_mode = %u sd_line_mask = 0x%x "
+		"default_sample_rate = %u\n", __func__,
+		snddev_mi2s_data->channel_mode, snddev_mi2s_data->sd_lines,
+		snddev_mi2s_data->default_sample_rate);
+
+	if (snddev_mi2s_data->channel_mode == 2)
+		channels = MI2S_CHAN_STEREO;
+	else if (snddev_mi2s_data->channel_mode == 4)
+		channels = MI2S_CHAN_4CHANNELS;
+	else if (snddev_mi2s_data->channel_mode == 6)
+		channels = MI2S_CHAN_6CHANNELS;
+	else if (snddev_mi2s_data->channel_mode == 8)
+		channels = MI2S_CHAN_8CHANNELS;
+	else
+		channels = MI2S_CHAN_MONO_RAW;
+
+	/* Set MI2S */
+	mi2s_set_hdmi_output_path(channels, WT_16_BIT,
+				  snddev_mi2s_data->sd_lines);
+
+	/* Start AFE */
+	afe_config.sample_rate = snddev_mi2s_data->default_sample_rate / 1000;
+	afe_config.channel_mode = snddev_mi2s_data->channel_mode;
+	afe_config.volume = AFE_VOLUME_UNITY;
+	rc = afe_enable(AFE_HW_PATH_MI2S_RX, &afe_config);
+
+	if (IS_ERR_VALUE(rc)) {
+		MM_ERR("%s: encounter error\n", __func__);
+		return -ENODEV;
+	}
+
+	/* Enable audio path */
+	if (snddev_mi2s_data->route)
+		snddev_mi2s_data->route();
+
+	MM_DBG("%s: enabled %s \n", __func__, snddev_mi2s_data->name);
+
+	return 0;
+}
+
+static int snddev_mi2s_open(struct msm_snddev_info *dev_info)
+{
+	int rc = 0;
+	struct snddev_mi2s_drv_state *drv = &snddev_mi2s_drv;
+	u32 dir;
+	struct snddev_mi2s_data *snddev_mi2s_data = dev_info->private_data;
+
+	if (!dev_info) {
+		MM_ERR("%s:  msm_snddev_info is null \n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&drv->lock);
+
+	if (drv->sd_lines_used & snddev_mi2s_data->sd_lines) {
+		MM_ERR("%s: conflict in SD data line. can not use the device\n",
+		       __func__);
+		mutex_unlock(&drv->lock);
+		return -EBUSY;
+	}
+
+	if (!drv->clocks_enabled) {
+
+		rc = mi2s_config_clk_gpio();
+		if (rc) {
+			MM_ERR("%s: mi2s GPIO config failed for %s\n",
+			       __func__, snddev_mi2s_data->name);
+			mutex_unlock(&drv->lock);
+			return -EIO;
+		}
+		clk_enable(drv->mclk);
+		clk_enable(drv->sclk);
+		drv->clocks_enabled = 1;
+		MM_DBG("%s: clks enabled \n", __func__);
+	} else
+		MM_DBG("%s: clks already enabled \n", __func__);
+
+	if (snddev_mi2s_data->capability & SNDDEV_CAP_RX) {
+
+		dir = DIR_RX;
+		rc = mi2s_config_data_gpio(dir, snddev_mi2s_data->sd_lines);
+
+		if (rc) {
+			rc = -EIO;
+			MM_ERR("%s: mi2s GPIO config failed for %s\n",
+			       __func__, snddev_mi2s_data->name);
+			goto mi2s_data_gpio_failure;
+		}
+
+		MM_DBG("%s: done gpio config rx SD lines\n", __func__);
+
+		rc = snddev_mi2s_open_rx(dev_info);
+
+		if (IS_ERR_VALUE(rc)) {
+			MM_ERR(" snddev_mi2s_open_rx failed \n");
+			goto mi2s_cleanup_open;
+		}
+
+		drv->sd_lines_used |= snddev_mi2s_data->sd_lines;
+
+		MM_DBG("%s: sd_lines_used = 0x%x\n", __func__,
+			drv->sd_lines_used);
+		mutex_unlock(&drv->lock);
+
+	} else {
+		dir = DIR_TX;
+		rc = mi2s_config_data_gpio(dir, snddev_mi2s_data->sd_lines);
+
+		if (rc) {
+			rc = -EIO;
+			MM_ERR("%s: mi2s GPIO config failed for %s\n",
+			       __func__, snddev_mi2s_data->name);
+			goto mi2s_data_gpio_failure;
+		}
+		MM_DBG("%s: done data line gpio config for %s\n",
+			__func__, snddev_mi2s_data->name);
+
+		rc = snddev_mi2s_open_tx(dev_info);
+
+		if (IS_ERR_VALUE(rc)) {
+			MM_ERR(" snddev_mi2s_open_tx failed \n");
+			goto mi2s_cleanup_open;
+		}
+
+		drv->sd_lines_used |= snddev_mi2s_data->sd_lines;
+		MM_DBG("%s: sd_lines_used = 0x%x\n", __func__,
+			drv->sd_lines_used);
+		mutex_unlock(&drv->lock);
+	}
+
+	return 0;
+
+mi2s_cleanup_open:
+	mi2s_unconfig_data_gpio(dir, snddev_mi2s_data->sd_lines);
+
+	/* Disable audio path */
+	if (snddev_mi2s_data->deroute)
+		snddev_mi2s_data->deroute();
+
+mi2s_data_gpio_failure:
+	if (!drv->sd_lines_used) {
+		clk_disable(drv->sclk);
+		clk_disable(drv->mclk);
+		drv->clocks_enabled = 0;
+		mi2s_unconfig_clk_gpio();
+	}
+	mutex_unlock(&drv->lock);
+	return rc;
+}
+
+static int snddev_mi2s_close(struct msm_snddev_info *dev_info)
+{
+	struct snddev_mi2s_drv_state *drv = &snddev_mi2s_drv;
+	int dir;
+	struct snddev_mi2s_data *snddev_mi2s_data = dev_info->private_data;
+
+	if (!dev_info) {
+		MM_ERR("%s:  msm_snddev_info is null \n", __func__);
+		return -EINVAL;
+	}
+
+	if (!dev_info->opened) {
+		MM_ERR(" %s: calling close device with out opening the"
+		       " device \n", __func__);
+		return -EIO;
+	}
+
+	mutex_lock(&drv->lock);
+
+	drv->sd_lines_used &= ~snddev_mi2s_data->sd_lines;
+
+	MM_DBG("%s: sd_lines in use = 0x%x\n", __func__, drv->sd_lines_used);
+
+	if (snddev_mi2s_data->capability & SNDDEV_CAP_RX) {
+		dir = DIR_RX;
+		afe_disable(AFE_HW_PATH_MI2S_RX);
+	} else {
+		dir = DIR_TX;
+		afe_disable(AFE_HW_PATH_MI2S_TX);
+	}
+
+	mi2s_unconfig_data_gpio(dir, snddev_mi2s_data->sd_lines);
+
+	if (!drv->sd_lines_used) {
+		clk_disable(drv->sclk);
+		clk_disable(drv->mclk);
+		drv->clocks_enabled = 0;
+		mi2s_unconfig_clk_gpio();
+	}
+
+	/* Disable audio path */
+	if (snddev_mi2s_data->deroute)
+		snddev_mi2s_data->deroute();
+
+	mutex_unlock(&drv->lock);
+
+	return 0;
+}
+
+static int snddev_mi2s_set_freq(struct msm_snddev_info *dev_info, u32 req_freq)
+{
+	if (req_freq != 48000) {
+		MM_DBG("%s: Unsupported Frequency:%d\n", __func__, req_freq);
+		return -EINVAL;
+	}
+	return 48000;
+}
+
+static int snddev_mi2s_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct snddev_mi2s_data *pdata;
+	struct msm_snddev_info *dev_info;
+
+	if (!pdev || !pdev->dev.platform_data) {
+		printk(KERN_ALERT "Invalid caller \n");
+		return -ENODEV;
+	}
+
+	pdata = pdev->dev.platform_data;
+	if ((pdata->capability & SNDDEV_CAP_RX) &&
+	    (pdata->capability & SNDDEV_CAP_TX)) {
+		MM_ERR("%s: invalid device data either RX or TX\n", __func__);
+		return -ENODEV;
+	}
+
+	dev_info = kzalloc(sizeof(struct msm_snddev_info), GFP_KERNEL);
+	if (!dev_info) {
+		MM_ERR("%s: uneable to allocate memeory for msm_snddev_info \n",
+		       __func__);
+
+		return -ENOMEM;
+	}
+
+	dev_info->name = pdata->name;
+	dev_info->copp_id = pdata->copp_id;
+	dev_info->acdb_id = pdata->acdb_id;
+	dev_info->private_data = (void *)pdata;
+	dev_info->dev_ops.open = snddev_mi2s_open;
+	dev_info->dev_ops.close = snddev_mi2s_close;
+	dev_info->dev_ops.set_freq = snddev_mi2s_set_freq;
+	dev_info->capability = pdata->capability;
+	dev_info->opened = 0;
+	msm_snddev_register(dev_info);
+	dev_info->sample_rate = pdata->default_sample_rate;
+
+	MM_DBG("%s: probe done for %s\n", __func__, pdata->name);
+	return rc;
+}
+
+static int snddev_mi2s_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static struct platform_driver snddev_mi2s_driver = {
+	.probe = snddev_mi2s_probe,
+	.remove = snddev_mi2s_remove,
+	.driver = {.name = "snddev_mi2s"}
+};
+
+static int __init snddev_mi2s_init(void)
+{
+	s32 rc;
+	struct snddev_mi2s_drv_state *drv = &snddev_mi2s_drv;
+
+	rc = platform_driver_register(&snddev_mi2s_driver);
+	if (IS_ERR_VALUE(rc)) {
+
+		MM_ERR("%s: platform_driver_register failed  \n", __func__);
+		goto error_platform_driver;
+	}
+
+	drv->mclk = clk_get(NULL, "mi2s_m_clk");
+	if (IS_ERR(drv->mclk)) {
+		MM_ERR("%s:  clk_get mi2s_mclk failed  \n", __func__);
+		goto error_mclk;
+	}
+
+	drv->sclk = clk_get(NULL, "mi2s_s_clk");
+	if (IS_ERR(drv->sclk)) {
+		MM_ERR("%s:  clk_get mi2s_sclk failed  \n", __func__);
+
+		goto error_sclk;
+	}
+
+	mutex_init(&drv->lock);
+
+	MM_DBG("snddev_mi2s_init : done \n");
+
+	return 0;
+
+error_sclk:
+	clk_put(drv->mclk);
+error_mclk:
+	platform_driver_unregister(&snddev_mi2s_driver);
+error_platform_driver:
+
+	MM_ERR("%s: encounter error\n", __func__);
+	return -ENODEV;
+}
+
+static void __exit snddev_mi2s_exit(void)
+{
+	struct snddev_mi2s_drv_state *drv = &snddev_mi2s_drv;
+
+	platform_driver_unregister(&snddev_mi2s_driver);
+
+	clk_put(drv->sclk);
+	clk_put(drv->mclk);
+	return;
+}
+
+module_init(snddev_mi2s_init);
+module_exit(snddev_mi2s_exit);
+
+MODULE_DESCRIPTION("mi2s Sound Device driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5v2/snddev_virtual.c b/arch/arm/mach-msm/qdsp5v2/snddev_virtual.c
new file mode 100644
index 0000000..cd93345
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/snddev_virtual.c
@@ -0,0 +1,122 @@
+/* Copyright (c) 2010, 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <asm/uaccess.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/qdsp5v2/snddev_virtual.h>
+#include <mach/debug_mm.h>
+#include <linux/slab.h>
+
+static int snddev_virtual_open(struct msm_snddev_info *dev_info)
+{
+	int rc = 0;
+
+	if (!dev_info)
+		rc = -EINVAL;
+	return rc;
+}
+
+static int snddev_virtual_close(struct msm_snddev_info *dev_info)
+{
+	int rc = 0;
+
+	if (!dev_info)
+		rc = -EINVAL;
+	return rc;
+}
+
+static int snddev_virtual_set_freq(struct msm_snddev_info *dev_info, u32 rate)
+{
+	int rc = 0;
+
+	if (!dev_info)
+		rc = -EINVAL;
+	return rate;
+}
+
+static int snddev_virtual_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct snddev_virtual_data *pdata;
+	struct msm_snddev_info *dev_info;
+
+	if (!pdev || !pdev->dev.platform_data) {
+		MM_ERR("Invalid caller\n");
+		rc = -EPERM;
+		goto error;
+	}
+	pdata = pdev->dev.platform_data;
+
+	dev_info = kmalloc(sizeof(struct msm_snddev_info), GFP_KERNEL);
+	if (!dev_info) {
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	dev_info->name = pdata->name;
+	dev_info->copp_id = pdata->copp_id;
+	dev_info->acdb_id = pdata->acdb_id;
+	dev_info->private_data = (void *) NULL;
+	dev_info->dev_ops.open = snddev_virtual_open;
+	dev_info->dev_ops.close = snddev_virtual_close;
+	dev_info->dev_ops.set_freq = snddev_virtual_set_freq;
+	dev_info->capability = pdata->capability;
+	dev_info->sample_rate = 8000;
+	dev_info->opened = 0;
+	dev_info->sessions = 0;
+
+	msm_snddev_register(dev_info);
+
+error:
+	return rc;
+}
+
+static int snddev_virtual_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static struct platform_driver snddev_virtual_driver = {
+	.probe = snddev_virtual_probe,
+	.remove = snddev_virtual_remove,
+	.driver = { .name = "snddev_virtual" }
+};
+
+static int __init snddev_virtual_init(void)
+{
+	int rc = 0;
+
+	MM_DBG(" snddev_virtual_init \n");
+	rc = platform_driver_register(&snddev_virtual_driver);
+	if (IS_ERR_VALUE(rc)) {
+		MM_ERR("platform driver register failure\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static void __exit snddev_virtual_exit(void)
+{
+	platform_driver_unregister(&snddev_virtual_driver);
+
+	return;
+}
+
+module_init(snddev_virtual_init);
+module_exit(snddev_virtual_exit);
+
+MODULE_DESCRIPTION("Virtual Sound Device driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5v2/timpani_profile_7x30.h b/arch/arm/mach-msm/qdsp5v2/timpani_profile_7x30.h
new file mode 100644
index 0000000..d9003cd
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/timpani_profile_7x30.h
@@ -0,0 +1,623 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MACH_QDSP5_V2_TIMPANI_PROFILE_H__
+#define __MACH_QDSP5_V2_MTIMPANI_PROFILE_H__
+
+/*
+ * TX Device Profiles
+ */
+
+/* Analog MIC */
+/* AMIC Primary mono */
+#define AMIC_PRI_MONO_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xD0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8b, 0xff, 0xE6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8c, 0x03, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x09, 0x09)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* Headset MIC */
+#define AMIC1_HEADSET_TX_MONO_PRIMARY_OSR256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xC8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8 }, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8b, 0xff, 0xE7)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8c, 0x03, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0x00)} }
+
+/*
+ * RX Device Profiles
+ */
+
+/* RX EAR */
+#define EAR_PRI_MONO_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x97, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0xFF, 0x4C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x01, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* RX SPEAKER */
+#define SPEAKER_PRI_STEREO_48000_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF},       \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} };
+
+/*
+ * RX HPH PRIMARY
+ */
+
+/* RX HPH CLASS AB CAPLESS */
+
+#define HEADSET_AB_CPLS_48000_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0xFF, 0x29)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0xFE, 0xC8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x27, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* AMIC dual */
+#define AMIC_DUAL_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xD0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8 }, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8b, 0xff, 0xCE)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB4, 0xFF, 0xCE)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8c, 0xFF, 0x5A)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* TTY RX */
+#define TTY_HEADSET_MONO_RX_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x97, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x06)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x4C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x45)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0xFF, 0x29)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0xC5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0xFE, 0xC8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x27, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* TTY TX */
+#define TTY_HEADSET_MONO_TX_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xA8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HEADSET_RX_CAPLESS_48000_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x4e)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x04, 0xff, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x25, 0x0F, 0x0B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xfc, 0xfc)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xff, 0xa2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0xFF, 0xab)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0xf0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x23, 0xff, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xff, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0f, 0x0c)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8a, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3b, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3c, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x34, 0xf0, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HEADSET_STEREO_SPEAKER_STEREO_RX_CAPLESS_48000_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0xFF, 0x29)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x27, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF},	\
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HS_DMIC2_STEREO_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8 }, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0x1F, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0x3F, 0x19)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0x3F, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x39, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA8, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x3F, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0xC0, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HPH_PRI_AB_LEG_STEREO \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x09)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x59)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0xF9)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x27, 0x27)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HPH_PRI_D_LEG_STEREO \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x21, 0xFF, 0x60)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x22, 0xFF, 0xE1)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xFF, 0xD0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2D, 0xFF, 0x6F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2E, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3F, 0xFF, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x40, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x41, 0x08, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x42, 0xFF, 0xBB)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x43, 0xFF, 0xF2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x44, 0xF7, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x45, 0xFF, 0xFF)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x46, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x47, 0xFF, 0xF2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x48, 0xF7, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x49, 0xFF, 0xFF)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4A, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0xFF, 0x8C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x0F, 0x0A)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 300000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LB_AUXPGA_HPH_AB_CPLS_STEREO \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2F, 0xFF, 0x44)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x30, 0xFF, 0x92)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xAA)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0xFF, 0x29)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x90, 0x90)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LB_AUXPGA_LO_STEREO \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY},	\
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2F, 0xFF, 0x44)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x30, 0xFF, 0x92)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xAA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x90, 0x90)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0xF0, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x90, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp5v2/voice.c b/arch/arm/mach-msm/qdsp5v2/voice.c
new file mode 100644
index 0000000..026acb3
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5v2/voice.c
@@ -0,0 +1,752 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/msm_audio.h>
+#include <mach/qdsp5v2/audio_dev_ctl.h>
+#include <mach/dal.h>
+#include <linux/kthread.h>
+#include <linux/completion.h>
+#include <linux/wait.h>
+#include <mach/qdsp5v2/voice.h>
+#include <mach/debug_mm.h>
+
+struct voice_data {
+	void *handle; /* DALRPC handle */
+	void *cb_handle; /* DALRPC callback handle */
+	int network; /* Network information */
+	int dev_state;/*READY, CHANGE, REL_DONE,INIT*/
+	int voc_state;/*INIT, CHANGE, RELEASE, ACQUIRE */
+	struct mutex voc_lock;
+	struct mutex vol_lock;
+	int voc_event;
+	int dev_event;
+	atomic_t rel_start_flag;
+	atomic_t acq_start_flag;
+	atomic_t chg_start_flag;
+	struct task_struct *task;
+	struct completion complete;
+	wait_queue_head_t dev_wait;
+	wait_queue_head_t voc_wait;
+	uint32_t device_events;
+	/* cache the values related to Rx and Tx */
+	struct device_data dev_rx;
+	struct device_data dev_tx;
+	/* these default values are for all devices */
+	uint32_t default_mute_val;
+	uint32_t default_vol_val;
+	uint32_t default_sample_val;
+	/* call status */
+	int v_call_status; /* Start or End */
+	s32 max_rx_vol[VOC_RX_VOL_ARRAY_NUM]; /* [0] is for NB, [1] for WB */
+	s32 min_rx_vol[VOC_RX_VOL_ARRAY_NUM];
+};
+
+static struct voice_data voice;
+
+static int voice_cmd_device_info(struct voice_data *);
+static int voice_cmd_acquire_done(struct voice_data *);
+static void voice_auddev_cb_function(u32 evt_id,
+			union auddev_evt_data *evt_payload,
+			void *private_data);
+
+static int voice_cmd_change(void)
+{
+
+	struct voice_header hdr;
+	struct voice_data *v = &voice;
+	int err;
+
+	hdr.id = CMD_DEVICE_CHANGE;
+	hdr.data_len = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	err = dalrpc_fcn_5(VOICE_DALRPC_CMD, v->handle, &hdr,
+			sizeof(struct voice_header));
+
+	if (err)
+		MM_ERR("Voice change command failed\n");
+	return err;
+}
+
+static void voice_auddev_cb_function(u32 evt_id,
+			union auddev_evt_data *evt_payload,
+			void *private_data)
+{
+	struct voice_data *v = &voice;
+	int rc = 0, i;
+
+	MM_INFO("auddev_cb_function, evt_id=%d, dev_state=%d, voc_state=%d\n",
+		evt_id, v->dev_state, v->voc_state);
+	if ((evt_id != AUDDEV_EVT_START_VOICE) ||
+			(evt_id != AUDDEV_EVT_END_VOICE)) {
+		if (evt_payload == NULL) {
+			MM_ERR(" evt_payload is NULL pointer\n");
+			return;
+		}
+	}
+	switch (evt_id) {
+	case AUDDEV_EVT_START_VOICE:
+		if ((v->dev_state == DEV_INIT) ||
+				(v->dev_state == DEV_REL_DONE)) {
+			v->v_call_status = VOICE_CALL_START;
+			if ((v->dev_rx.enabled == VOICE_DEV_ENABLED)
+				&& (v->dev_tx.enabled == VOICE_DEV_ENABLED)) {
+				v->dev_state = DEV_READY;
+				MM_DBG("dev_state into ready\n");
+				wake_up(&v->dev_wait);
+			}
+			if (v->voc_state == VOICE_CHANGE) {
+				MM_DBG("voc_state is in VOICE_CHANGE\n");
+				v->voc_state = VOICE_ACQUIRE;
+			}
+		}
+		break;
+	case AUDDEV_EVT_DEV_CHG_VOICE:
+		if (v->dev_state == DEV_READY) {
+			v->dev_rx.enabled = VOICE_DEV_DISABLED;
+			v->dev_tx.enabled = VOICE_DEV_DISABLED;
+			v->dev_state = DEV_CHANGE;
+			mutex_lock(&voice.voc_lock);
+			if (v->voc_state == VOICE_ACQUIRE) {
+				/* send device change to modem */
+				voice_cmd_change();
+				mutex_unlock(&voice.voc_lock);
+				msm_snddev_enable_sidetone(v->dev_rx.dev_id,
+				0);
+				/* block to wait for CHANGE_START */
+				rc = wait_event_interruptible(
+				v->voc_wait, (v->voc_state == VOICE_CHANGE)
+				|| (atomic_read(&v->chg_start_flag) == 1)
+				|| (atomic_read(&v->rel_start_flag) == 1));
+			} else {
+				mutex_unlock(&voice.voc_lock);
+				MM_ERR(" Voice is not at ACQUIRE state\n");
+			}
+		} else if ((v->dev_state == DEV_INIT) ||
+				(v->dev_state == DEV_REL_DONE)) {
+				v->dev_rx.enabled = VOICE_DEV_DISABLED;
+				v->dev_tx.enabled = VOICE_DEV_DISABLED;
+		} else
+			MM_ERR(" device is not at proper state\n");
+		break;
+	case AUDDEV_EVT_DEV_RDY:
+		/* update the dev info */
+		if (evt_payload->voc_devinfo.dev_type == DIR_RX) {
+			for (i = 0; i < VOC_RX_VOL_ARRAY_NUM; i++) {
+				v->max_rx_vol[i] =
+					evt_payload->voc_devinfo.max_rx_vol[i];
+				v->min_rx_vol[i] =
+					evt_payload->voc_devinfo.min_rx_vol[i];
+			}
+		}
+		if (v->dev_state == DEV_CHANGE) {
+			if (evt_payload->voc_devinfo.dev_type == DIR_RX) {
+				v->dev_rx.dev_acdb_id =
+					evt_payload->voc_devinfo.acdb_dev_id;
+				v->dev_rx.sample =
+					evt_payload->voc_devinfo.dev_sample;
+				v->dev_rx.dev_id =
+				evt_payload->voc_devinfo.dev_id;
+				v->dev_rx.enabled = VOICE_DEV_ENABLED;
+			} else {
+				v->dev_tx.dev_acdb_id =
+					evt_payload->voc_devinfo.acdb_dev_id;
+				v->dev_tx.sample =
+					evt_payload->voc_devinfo.dev_sample;
+				v->dev_tx.enabled = VOICE_DEV_ENABLED;
+				v->dev_tx.dev_id =
+				evt_payload->voc_devinfo.dev_id;
+			}
+			if ((v->dev_rx.enabled == VOICE_DEV_ENABLED) &&
+				(v->dev_tx.enabled == VOICE_DEV_ENABLED)) {
+				v->dev_state = DEV_READY;
+				MM_DBG("dev state into ready\n");
+				voice_cmd_device_info(v);
+				wake_up(&v->dev_wait);
+				mutex_lock(&voice.voc_lock);
+				if (v->voc_state == VOICE_CHANGE) {
+					v->dev_event = DEV_CHANGE_READY;
+					complete(&v->complete);
+				}
+				mutex_unlock(&voice.voc_lock);
+			}
+		} else if ((v->dev_state == DEV_INIT) ||
+			(v->dev_state == DEV_REL_DONE)) {
+			if (evt_payload->voc_devinfo.dev_type == DIR_RX) {
+				v->dev_rx.dev_acdb_id =
+					evt_payload->voc_devinfo.acdb_dev_id;
+				v->dev_rx.sample =
+					evt_payload->voc_devinfo.dev_sample;
+				v->dev_rx.dev_id =
+				evt_payload->voc_devinfo.dev_id;
+				v->dev_rx.enabled = VOICE_DEV_ENABLED;
+			} else {
+				v->dev_tx.dev_acdb_id =
+					evt_payload->voc_devinfo.acdb_dev_id;
+				v->dev_tx.sample =
+					evt_payload->voc_devinfo.dev_sample;
+				v->dev_tx.dev_id =
+				evt_payload->voc_devinfo.dev_id;
+				v->dev_tx.enabled = VOICE_DEV_ENABLED;
+			}
+			if ((v->dev_rx.enabled == VOICE_DEV_ENABLED) &&
+				(v->dev_tx.enabled == VOICE_DEV_ENABLED) &&
+				(v->v_call_status == VOICE_CALL_START)) {
+				v->dev_state = DEV_READY;
+				MM_DBG("dev state into ready\n");
+				voice_cmd_device_info(v);
+				wake_up(&v->dev_wait);
+				mutex_lock(&voice.voc_lock);
+				if (v->voc_state == VOICE_CHANGE) {
+					v->dev_event = DEV_CHANGE_READY;
+					complete(&v->complete);
+				}
+				mutex_unlock(&voice.voc_lock);
+			}
+		} else
+			MM_ERR("Receive READY not at the proper state =%d\n",
+				v->dev_state);
+		break;
+	case AUDDEV_EVT_DEVICE_VOL_MUTE_CHG:
+		if (evt_payload->voc_devinfo.dev_type == DIR_TX)
+			v->dev_tx.mute =
+				evt_payload->voc_vm_info.dev_vm_val.mute;
+		else
+			v->dev_rx.volume = evt_payload->
+						voc_vm_info.dev_vm_val.vol;
+		/* send device info */
+		voice_cmd_device_info(v);
+		break;
+	case AUDDEV_EVT_REL_PENDING:
+		/* recover the tx mute and rx volume to the default values */
+		if (v->dev_state == DEV_READY) {
+			if (atomic_read(&v->rel_start_flag)) {
+				atomic_dec(&v->rel_start_flag);
+				if (evt_payload->voc_devinfo.dev_type == DIR_RX)
+					v->dev_rx.enabled = VOICE_DEV_DISABLED;
+				else
+					v->dev_tx.enabled = VOICE_DEV_DISABLED;
+				v->dev_state = DEV_REL_DONE;
+				wake_up(&v->dev_wait);
+				break;
+			}
+			mutex_lock(&voice.voc_lock);
+			if ((v->voc_state == VOICE_RELEASE) ||
+					(v->voc_state == VOICE_INIT)) {
+				if (evt_payload->voc_devinfo.dev_type
+							== DIR_RX) {
+					v->dev_rx.enabled = VOICE_DEV_DISABLED;
+				} else {
+					v->dev_tx.enabled = VOICE_DEV_DISABLED;
+				}
+				v->dev_state = DEV_REL_DONE;
+				mutex_unlock(&voice.voc_lock);
+				wake_up(&v->dev_wait);
+			} else {
+				/* send device change to modem */
+				voice_cmd_change();
+				mutex_unlock(&voice.voc_lock);
+				rc = wait_event_interruptible(
+				v->voc_wait, (v->voc_state == VOICE_CHANGE)
+				|| (atomic_read(&v->chg_start_flag) == 1)
+				|| (atomic_read(&v->rel_start_flag) == 1));
+				if (atomic_read(&v->rel_start_flag) == 1)
+					atomic_dec(&v->rel_start_flag);
+				/* clear Rx/Tx to Disable */
+				if (evt_payload->voc_devinfo.dev_type == DIR_RX)
+					v->dev_rx.enabled = VOICE_DEV_DISABLED;
+				else
+					v->dev_tx.enabled = VOICE_DEV_DISABLED;
+				v->dev_state = DEV_REL_DONE;
+				wake_up(&v->dev_wait);
+			}
+		} else if ((v->dev_state == DEV_INIT) ||
+				(v->dev_state == DEV_REL_DONE)) {
+			if (evt_payload->voc_devinfo.dev_type == DIR_RX)
+				v->dev_rx.enabled = VOICE_DEV_DISABLED;
+			else
+				v->dev_tx.enabled = VOICE_DEV_DISABLED;
+		}
+		break;
+	case AUDDEV_EVT_END_VOICE:
+		/* recover the tx mute and rx volume to the default values */
+		v->dev_tx.mute = v->default_mute_val;
+		v->dev_rx.volume = v->default_vol_val;
+
+		if (v->dev_rx.enabled == VOICE_DEV_ENABLED)
+			msm_snddev_enable_sidetone(v->dev_rx.dev_id, 0);
+
+		if ((v->dev_state == DEV_READY) ||
+			(v->dev_state == DEV_CHANGE)) {
+			if (atomic_read(&v->rel_start_flag)) {
+				atomic_dec(&v->rel_start_flag);
+				v->v_call_status = VOICE_CALL_END;
+				v->dev_state = DEV_REL_DONE;
+				wake_up(&v->dev_wait);
+				break;
+			}
+			mutex_lock(&voice.voc_lock);
+			if ((v->voc_state == VOICE_RELEASE) ||
+					(v->voc_state == VOICE_INIT)) {
+				v->v_call_status = VOICE_CALL_END;
+				v->dev_state = DEV_REL_DONE;
+				mutex_unlock(&voice.voc_lock);
+				wake_up(&v->dev_wait);
+			} else {
+				/* send mute and default volume value to MCAD */
+				voice_cmd_device_info(v);
+				/* send device change to modem */
+				voice_cmd_change();
+				mutex_unlock(&voice.voc_lock);
+				/* block to wait for RELEASE_START
+						or CHANGE_START */
+				rc = wait_event_interruptible(
+				v->voc_wait, (v->voc_state == VOICE_CHANGE)
+				|| (atomic_read(&v->chg_start_flag) == 1)
+				|| (atomic_read(&v->rel_start_flag) == 1));
+				if (atomic_read(&v->rel_start_flag) == 1)
+					atomic_dec(&v->rel_start_flag);
+				/* set voice call to END state */
+				v->v_call_status = VOICE_CALL_END;
+				v->dev_state = DEV_REL_DONE;
+				wake_up(&v->dev_wait);
+			}
+		} else
+			v->v_call_status = VOICE_CALL_END;
+		break;
+	case AUDDEV_EVT_FREQ_CHG:
+		MM_DBG("Voice Driver got sample rate change Event\n");
+		MM_DBG("sample rate %d\n", evt_payload->freq_info.sample_rate);
+		MM_DBG("dev_type %d\n", evt_payload->freq_info.dev_type);
+		MM_DBG("acdb_dev_id %d\n", evt_payload->freq_info.acdb_dev_id);
+		if (v->dev_state == DEV_READY) {
+			v->dev_tx.enabled = VOICE_DEV_DISABLED;
+			v->dev_state = DEV_CHANGE;
+			mutex_lock(&voice.voc_lock);
+			if (v->voc_state == VOICE_ACQUIRE) {
+				msm_snddev_enable_sidetone(v->dev_rx.dev_id,
+				0);
+				/* send device change to modem */
+				voice_cmd_change();
+				mutex_unlock(&voice.voc_lock);
+				/* block to wait for CHANGE_START */
+				rc = wait_event_interruptible(
+				v->voc_wait, (v->voc_state == VOICE_CHANGE)
+				|| (atomic_read(&v->chg_start_flag) == 1)
+				|| (atomic_read(&v->rel_start_flag) == 1));
+			} else {
+				mutex_unlock(&voice.voc_lock);
+				MM_ERR(" Voice is not at ACQUIRE state\n");
+			}
+		} else if ((v->dev_state == DEV_INIT) ||
+				(v->dev_state == DEV_REL_DONE)) {
+				v->dev_tx.enabled = VOICE_DEV_DISABLED;
+		} else
+			MM_ERR("Event not at the proper state =%d\n",
+				v->dev_state);
+		break;
+	default:
+		MM_ERR("UNKNOWN EVENT\n");
+	}
+	return;
+}
+EXPORT_SYMBOL(voice_auddev_cb_function);
+
+static void remote_cb_function(void *context, u32 param,
+				void *evt_buf, u32 len)
+{
+	struct voice_header *hdr;
+	struct voice_data *v = context;
+
+	hdr = (struct voice_header *)evt_buf;
+
+	MM_INFO("len=%d id=%d\n", len, hdr->id);
+
+	if (len <= 0) {
+		MM_ERR("unexpected event with length %d \n", len);
+		return;
+	}
+
+	switch (hdr->id) {
+	case EVENT_ACQUIRE_START:
+		atomic_inc(&v->acq_start_flag);
+		wake_up(&v->dev_wait);
+		v->voc_event = VOICE_ACQUIRE_START;
+		v->network = ((struct voice_network *)evt_buf)->network_info;
+		complete(&v->complete);
+		break;
+	case EVENT_RELEASE_START:
+		/* If ACQUIRED come in before the RELEASE,
+		* will only services the RELEASE */
+		atomic_inc(&v->rel_start_flag);
+		wake_up(&v->voc_wait);
+		wake_up(&v->dev_wait);
+		v->voc_event = VOICE_RELEASE_START;
+		complete(&v->complete);
+		break;
+	case EVENT_CHANGE_START:
+		atomic_inc(&v->chg_start_flag);
+		wake_up(&v->voc_wait);
+		v->voc_event = VOICE_CHANGE_START;
+		complete(&v->complete);
+		break;
+	case EVENT_NETWORK_RECONFIG:
+		/* send network change to audio_dev,
+		if sample rate is less than 16k,
+		otherwise, send acquire done */
+		v->voc_event = VOICE_NETWORK_RECONFIG;
+		v->network = ((struct voice_network *)evt_buf)->network_info;
+		complete(&v->complete);
+		break;
+	default:
+		MM_ERR("Undefined event %d \n", hdr->id);
+	}
+
+}
+
+static int voice_cmd_init(struct voice_data *v)
+{
+
+	struct voice_init cmd;
+	int err;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	cmd.hdr.id = CMD_VOICE_INIT;
+	cmd.hdr.data_len = sizeof(struct voice_init) -
+				sizeof(struct voice_header);
+	cmd.cb_handle = v->cb_handle;
+
+	err = dalrpc_fcn_5(VOICE_DALRPC_CMD, v->handle, &cmd,
+			 sizeof(struct voice_init));
+
+	if (err)
+		MM_ERR("Voice init command failed\n");
+	return err;
+}
+
+static int voice_cmd_acquire_done(struct voice_data *v)
+{
+	struct voice_header hdr;
+	int err;
+
+	hdr.id = CMD_ACQUIRE_DONE;
+	hdr.data_len = 0;
+
+	MM_INFO("\n"); /* Macro prints the file name and function */
+
+	/* Enable HW sidetone if device supports it  */
+	msm_snddev_enable_sidetone(v->dev_rx.dev_id, 1);
+
+	err = dalrpc_fcn_5(VOICE_DALRPC_CMD, v->handle, &hdr,
+			 sizeof(struct voice_header));
+
+	if (err)
+		MM_ERR("Voice acquire done command failed\n");
+	return err;
+}
+
+static int voice_cmd_device_info(struct voice_data *v)
+{
+	struct voice_device cmd;
+	int err, vol;
+
+	MM_INFO("tx_dev=%d, rx_dev=%d, tx_sample=%d, tx_mute=%d\n",
+			v->dev_tx.dev_acdb_id, v->dev_rx.dev_acdb_id,
+			v->dev_tx.sample, v->dev_tx.mute);
+
+	mutex_lock(&voice.vol_lock);
+
+	cmd.hdr.id = CMD_DEVICE_INFO;
+	cmd.hdr.data_len = sizeof(struct voice_device) -
+			sizeof(struct voice_header);
+	cmd.tx_device = v->dev_tx.dev_acdb_id;
+	cmd.rx_device = v->dev_rx.dev_acdb_id;
+	if (v->network == NETWORK_WCDMA_WB)
+		vol = v->min_rx_vol[VOC_WB_INDEX] +
+			((v->max_rx_vol[VOC_WB_INDEX] -
+			v->min_rx_vol[VOC_WB_INDEX]) * v->dev_rx.volume)/100;
+	else
+		vol = v->min_rx_vol[VOC_NB_INDEX] +
+			((v->max_rx_vol[VOC_NB_INDEX] -
+			v->min_rx_vol[VOC_NB_INDEX]) * v->dev_rx.volume)/100;
+	cmd.rx_volume = (u32)vol; /* in mb */
+	cmd.rx_mute = 0;
+	cmd.tx_mute = v->dev_tx.mute;
+	cmd.rx_sample = v->dev_rx.sample/1000;
+	cmd.tx_sample = v->dev_tx.sample/1000;
+
+	MM_DBG("rx_vol=%d, rx_sample=%d\n", cmd.rx_volume, v->dev_rx.sample);
+
+	err = dalrpc_fcn_5(VOICE_DALRPC_CMD, v->handle, &cmd,
+			 sizeof(struct voice_device));
+
+	mutex_unlock(&voice.vol_lock);
+
+	if (err)
+		MM_ERR("Voice device command failed\n");
+	return err;
+}
+EXPORT_SYMBOL(voice_cmd_device_info);
+
+void voice_change_sample_rate(struct voice_data *v)
+{
+	int freq = 48000;
+	int rc = 0;
+
+	MM_DBG("network =%d, vote freq=%d\n", v->network, freq);
+	if (freq != v->dev_tx.sample) {
+		rc = msm_snddev_request_freq(&freq, 0,
+				SNDDEV_CAP_TX, AUDDEV_CLNT_VOC);
+		if (rc >= 0) {
+			v->dev_tx.sample = freq;
+			MM_DBG(" vote for freq=%d successfully \n", freq);
+		} else
+			MM_ERR(" voting for freq=%d failed.\n", freq);
+	}
+}
+
+static int voice_thread(void *data)
+{
+	struct voice_data *v = (struct voice_data *)data;
+	int rc = 0;
+
+	MM_INFO("voice_thread() start\n");
+
+	while (!kthread_should_stop()) {
+		wait_for_completion(&v->complete);
+		init_completion(&v->complete);
+
+		MM_DBG(" voc_event=%d, voice state =%d, dev_event=%d\n",
+				v->voc_event, v->voc_state, v->dev_event);
+		switch (v->voc_event) {
+		case VOICE_ACQUIRE_START:
+			/* check if dev_state = READY */
+			/* if ready, send device_info and acquire_done */
+			/* if not ready, block to wait the dev_state = READY */
+			if ((v->voc_state == VOICE_INIT) ||
+				(v->voc_state == VOICE_RELEASE)) {
+				if (v->dev_state == DEV_READY) {
+					mutex_lock(&voice.voc_lock);
+					voice_change_sample_rate(v);
+					rc = voice_cmd_device_info(v);
+					rc = voice_cmd_acquire_done(v);
+					v->voc_state = VOICE_ACQUIRE;
+					mutex_unlock(&voice.voc_lock);
+					broadcast_event(
+					AUDDEV_EVT_VOICE_STATE_CHG,
+					VOICE_STATE_INCALL, SESSION_IGNORE);
+				} else {
+					rc = wait_event_interruptible(
+					v->dev_wait,
+					(v->dev_state == DEV_READY)
+					|| (atomic_read(&v->rel_start_flag)
+						== 1));
+					if (atomic_read(&v->rel_start_flag)
+						== 1) {
+						v->voc_state = VOICE_RELEASE;
+						atomic_dec(&v->rel_start_flag);
+						msm_snddev_withdraw_freq(0,
+						SNDDEV_CAP_TX, AUDDEV_CLNT_VOC);
+						broadcast_event(
+						AUDDEV_EVT_VOICE_STATE_CHG,
+						VOICE_STATE_OFFCALL,
+						SESSION_IGNORE);
+					} else {
+						mutex_lock(&voice.voc_lock);
+						voice_change_sample_rate(v);
+						rc = voice_cmd_device_info(v);
+						rc = voice_cmd_acquire_done(v);
+						v->voc_state = VOICE_ACQUIRE;
+						mutex_unlock(&voice.voc_lock);
+						broadcast_event(
+						AUDDEV_EVT_VOICE_STATE_CHG,
+						VOICE_STATE_INCALL,
+						SESSION_IGNORE);
+					}
+				}
+			} else
+				MM_ERR("Get this event at the wrong state\n");
+			if (atomic_read(&v->acq_start_flag))
+				atomic_dec(&v->acq_start_flag);
+			break;
+		case VOICE_RELEASE_START:
+			MM_DBG("broadcast voice call end\n");
+			broadcast_event(AUDDEV_EVT_VOICE_STATE_CHG,
+					VOICE_STATE_OFFCALL, SESSION_IGNORE);
+			if ((v->dev_state == DEV_REL_DONE) ||
+					(v->dev_state == DEV_INIT)) {
+				v->voc_state = VOICE_RELEASE;
+				msm_snddev_withdraw_freq(0, SNDDEV_CAP_TX,
+					AUDDEV_CLNT_VOC);
+			} else {
+				/* wait for the dev_state = RELEASE */
+				rc = wait_event_interruptible(v->dev_wait,
+					(v->dev_state == DEV_REL_DONE)
+				|| (atomic_read(&v->acq_start_flag) == 1));
+				if (atomic_read(&v->acq_start_flag) == 1)
+					atomic_dec(&v->acq_start_flag);
+				v->voc_state = VOICE_RELEASE;
+				msm_snddev_withdraw_freq(0, SNDDEV_CAP_TX,
+					AUDDEV_CLNT_VOC);
+			}
+			if (atomic_read(&v->rel_start_flag))
+				atomic_dec(&v->rel_start_flag);
+			break;
+		case VOICE_CHANGE_START:
+			if (v->voc_state == VOICE_ACQUIRE)
+				v->voc_state = VOICE_CHANGE;
+			else
+				MM_ERR("Get this event at the wrong state\n");
+			wake_up(&v->voc_wait);
+			if (atomic_read(&v->chg_start_flag))
+				atomic_dec(&v->chg_start_flag);
+			break;
+		case VOICE_NETWORK_RECONFIG:
+			if ((v->voc_state == VOICE_ACQUIRE)
+				|| (v->voc_state == VOICE_CHANGE)) {
+				voice_change_sample_rate(v);
+				rc = voice_cmd_device_info(v);
+				rc = voice_cmd_acquire_done(v);
+			}
+			break;
+		default:
+			break;
+		}
+
+		switch (v->dev_event) {
+		case DEV_CHANGE_READY:
+			if (v->voc_state == VOICE_CHANGE) {
+				mutex_lock(&voice.voc_lock);
+				msm_snddev_enable_sidetone(v->dev_rx.dev_id,
+				1);
+				/* update voice state */
+				v->voc_state = VOICE_ACQUIRE;
+				v->dev_event = 0;
+				mutex_unlock(&voice.voc_lock);
+				broadcast_event(AUDDEV_EVT_VOICE_STATE_CHG,
+					VOICE_STATE_INCALL, SESSION_IGNORE);
+			} else {
+				mutex_lock(&voice.voc_lock);
+				v->dev_event = 0;
+				mutex_unlock(&voice.voc_lock);
+				MM_ERR("Get this event at the wrong state\n");
+			}
+			break;
+		default:
+			mutex_lock(&voice.voc_lock);
+			v->dev_event = 0;
+			mutex_unlock(&voice.voc_lock);
+			break;
+		}
+	}
+	return 0;
+}
+
+static int __init voice_init(void)
+{
+	int rc, i;
+	struct voice_data *v = &voice;
+	MM_INFO("\n"); /* Macro prints the file name and function */
+
+	mutex_init(&voice.voc_lock);
+	mutex_init(&voice.vol_lock);
+	v->handle = NULL;
+	v->cb_handle = NULL;
+
+	/* set default value */
+	v->default_mute_val = 1;  /* default is mute */
+	v->default_vol_val = 0;
+	v->default_sample_val = 8000;
+	for (i = 0; i < VOC_RX_VOL_ARRAY_NUM; i++) {
+		v->max_rx_vol[i] = 0;
+		v->min_rx_vol[i] = 0;
+	}
+	v->network = NETWORK_GSM;
+
+	/* initialize dev_rx and dev_tx */
+	memset(&v->dev_tx, 0, sizeof(struct device_data));
+	memset(&v->dev_rx, 0, sizeof(struct device_data));
+	v->dev_rx.volume = v->default_vol_val;
+	v->dev_tx.mute = v->default_mute_val;
+
+	v->dev_state = DEV_INIT;
+	v->voc_state = VOICE_INIT;
+	atomic_set(&v->rel_start_flag, 0);
+	atomic_set(&v->acq_start_flag, 0);
+	v->dev_event = 0;
+	v->voc_event = 0;
+	init_completion(&voice.complete);
+	init_waitqueue_head(&v->dev_wait);
+	init_waitqueue_head(&v->voc_wait);
+
+	 /* get device handle */
+	rc = daldevice_attach(VOICE_DALRPC_DEVICEID,
+				VOICE_DALRPC_PORT_NAME,
+				VOICE_DALRPC_CPU,
+				&v->handle);
+	if (rc) {
+		MM_ERR("Voc DALRPC call to Modem attach failed\n");
+		goto done;
+	}
+
+	/* Allocate the callback handle */
+	v->cb_handle = dalrpc_alloc_cb(v->handle, remote_cb_function, v);
+	if (v->cb_handle == NULL) {
+		MM_ERR("Allocate Callback failure\n");
+		goto err;
+	}
+
+	/* setup the callback */
+	rc = voice_cmd_init(v);
+	if (rc)
+		goto err1;
+
+	v->device_events = AUDDEV_EVT_DEV_CHG_VOICE |
+			AUDDEV_EVT_DEV_RDY |
+			AUDDEV_EVT_REL_PENDING |
+			AUDDEV_EVT_START_VOICE |
+			AUDDEV_EVT_END_VOICE |
+			AUDDEV_EVT_DEVICE_VOL_MUTE_CHG |
+			AUDDEV_EVT_FREQ_CHG;
+
+	MM_DBG(" to register call back \n");
+	/* register callback to auddev */
+	auddev_register_evt_listner(v->device_events, AUDDEV_CLNT_VOC,
+				0, voice_auddev_cb_function, v);
+
+	/* create and start thread */
+	v->task = kthread_run(voice_thread, v, "voice");
+	if (IS_ERR(v->task)) {
+		rc = PTR_ERR(v->task);
+		v->task = NULL;
+	} else
+		goto done;
+
+err1:   dalrpc_dealloc_cb(v->handle, v->cb_handle);
+err:
+	daldevice_detach(v->handle);
+	v->handle = NULL;
+done:
+	return rc;
+}
+
+late_initcall(voice_init);
diff --git a/arch/arm/mach-msm/qdsp6/Makefile b/arch/arm/mach-msm/qdsp6/Makefile
new file mode 100644
index 0000000..9a55612
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/Makefile
@@ -0,0 +1,19 @@
+obj-y += dal.o
+obj-y += q6audio.o
+obj-y += analog_audio.o
+obj-y += pcm_out.o
+obj-y += pcm_in.o
+obj-y += auxpcm_lb_out.o
+obj-y += auxpcm_lb_in.o
+obj-y += aac_in.o
+obj-y += qcelp_in.o
+obj-y += evrc_in.o
+obj-y += amrnb_in.o
+obj-y += mp3.o
+obj-y += dtmf.o
+obj-y += routing.o
+obj-y += audio_ctl.o
+obj-y += msm_q6vdec.o
+obj-y += msm_q6venc.o
+obj-y += dsp_debug.o
+obj-$(CONFIG_QSD_AUDIO) += audiov2/
diff --git a/arch/arm/mach-msm/qdsp6/aac_in.c b/arch/arm/mach-msm/qdsp6/aac_in.c
new file mode 100644
index 0000000..9e1d5b6
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/aac_in.c
@@ -0,0 +1,470 @@
+/*
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ * Copyright (c) 2010, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+
+#include <linux/msm_audio.h>
+#include <linux/msm_audio_aac.h>
+#include <mach/msm_qdsp6_audio.h>
+#include <mach/debug_mm.h>
+
+#define AAC_FC_BUFF_CNT 10
+#define AAC_READ_TIMEOUT 2000
+struct aac_fc_buff {
+	struct mutex lock;
+	int empty;
+	void *data;
+	int size;
+	int actual_size;
+};
+
+struct aac_fc {
+	struct task_struct *task;
+	wait_queue_head_t fc_wq;
+	struct aac_fc_buff fc_buff[AAC_FC_BUFF_CNT];
+	int buff_index;
+};
+struct aac {
+	struct mutex lock;
+	struct msm_audio_aac_enc_config cfg;
+	struct msm_audio_stream_config str_cfg;
+	struct audio_client *audio_client;
+	struct msm_voicerec_mode voicerec_mode;
+	struct aac_fc *aac_fc;
+};
+
+static int q6_aac_flowcontrol(void *data)
+{
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	struct aac *aac = data;
+	int buff_index = 0;
+	int xfer = 0;
+	struct aac_fc *fc;
+
+
+	ac = aac->audio_client;
+	fc = aac->aac_fc;
+	if (!ac) {
+		pr_err("[%s:%s] audio_client is NULL\n", __MM_FILE__, __func__);
+		return 0;
+	}
+
+	while (!kthread_should_stop()) {
+		ab = ac->buf + ac->cpu_buf;
+		if (ab->used)
+			wait_event(ac->wait, (ab->used == 0));
+		pr_debug("[%s:%s] ab->data = %p, cpu_buf = %d\n", __MM_FILE__,
+			 __func__, ab->data, ac->cpu_buf);
+		xfer = ab->actual_size;
+
+		mutex_lock(&(fc->fc_buff[buff_index].lock));
+		if (!fc->fc_buff[buff_index].empty) {
+			pr_err("[%s:%s] flow control buffer[%d] not read!\n",
+					__MM_FILE__, __func__, buff_index);
+		}
+
+		if (fc->fc_buff[buff_index].size < xfer) {
+			pr_err("[%s:%s] buffer %d too small\n", __MM_FILE__,
+					__func__, buff_index);
+			memcpy(fc->fc_buff[buff_index].data,
+				ab->data, fc->fc_buff[buff_index].size);
+			fc->fc_buff[buff_index].empty = 0;
+			fc->fc_buff[buff_index].actual_size =
+				fc->fc_buff[buff_index].size;
+		} else {
+			memcpy(fc->fc_buff[buff_index].data, ab->data, xfer);
+			fc->fc_buff[buff_index].empty = 0;
+			fc->fc_buff[buff_index].actual_size = xfer;
+		}
+		mutex_unlock(&(fc->fc_buff[buff_index].lock));
+		/*wake up client, if any*/
+		wake_up(&fc->fc_wq);
+
+		buff_index++;
+		if (buff_index >= AAC_FC_BUFF_CNT)
+			buff_index = 0;
+
+		ab->used = 1;
+
+		q6audio_read(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+
+	return 0;
+}
+static long q6_aac_in_ioctl(struct file *file,
+				 unsigned int cmd, unsigned long arg)
+{
+	struct aac *aac = file->private_data;
+	int rc = 0;
+	int i = 0;
+	struct aac_fc *fc;
+	int size = 0;
+
+	mutex_lock(&aac->lock);
+	switch (cmd) {
+	case AUDIO_SET_VOLUME:
+		break;
+	case AUDIO_GET_STATS:
+	{
+		struct msm_audio_stats stats;
+		pr_debug("[%s:%s] GET_STATS\n", __MM_FILE__, __func__);
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+	case AUDIO_START:
+	{
+		uint32_t acdb_id;
+		pr_debug("[%s:%s] AUDIO_START\n", __MM_FILE__, __func__);
+		if (arg == 0) {
+			acdb_id = 0;
+		} else {
+			if (copy_from_user(&acdb_id, (void *) arg,
+					sizeof(acdb_id))) {
+				rc = -EFAULT;
+				break;
+			}
+		}
+		if (aac->audio_client) {
+			rc = -EBUSY;
+			pr_err("[%s:%s] active session already existing\n",
+				__MM_FILE__, __func__);
+			break;
+		} else {
+			aac->audio_client = q6audio_open_aac(
+					aac->str_cfg.buffer_size,
+					aac->cfg.sample_rate,
+					aac->cfg.channels,
+					aac->cfg.bit_rate,
+					aac->cfg.stream_format,
+					aac->voicerec_mode.rec_mode, acdb_id);
+
+			if (aac->audio_client < 0) {
+				pr_err("[%s:%s] aac open session failed\n",
+					__MM_FILE__, __func__);
+				rc = -ENOMEM;
+				break;
+			}
+		}
+
+		/*allocate flow control buffers*/
+		fc = aac->aac_fc;
+		size = ((aac->str_cfg.buffer_size < 1543) ? 1543 :
+				aac->str_cfg.buffer_size);
+		for (i = 0; i < AAC_FC_BUFF_CNT; ++i) {
+			mutex_init(&(fc->fc_buff[i].lock));
+			fc->fc_buff[i].empty = 1;
+			fc->fc_buff[i].data = kmalloc(size, GFP_KERNEL);
+			if (fc->fc_buff[i].data == NULL) {
+				pr_err("[%s:%s] No memory for FC buffers\n",
+						__MM_FILE__, __func__);
+				rc = -ENOMEM;
+				goto fc_fail;
+			}
+			fc->fc_buff[i].size = size;
+			fc->fc_buff[i].actual_size = 0;
+		}
+
+		/*create flow control thread*/
+		fc->task = kthread_run(q6_aac_flowcontrol,
+				aac, "aac_flowcontrol");
+		if (IS_ERR(fc->task)) {
+			rc = PTR_ERR(fc->task);
+			pr_err("[%s:%s] error creating flow control thread\n",
+					__MM_FILE__, __func__);
+			goto fc_fail;
+		}
+		break;
+fc_fail:
+		/*free flow control buffers*/
+		--i;
+		for (; i >=  0; i--) {
+			kfree(fc->fc_buff[i].data);
+			fc->fc_buff[i].data = NULL;
+		}
+		break;
+	}
+	case AUDIO_STOP:
+		pr_debug("[%s:%s] AUDIO_STOP\n", __MM_FILE__, __func__);
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_INCALL: {
+		pr_debug("[%s:%s] SET_INCALL\n", __MM_FILE__, __func__);
+		if (copy_from_user(&aac->voicerec_mode,
+			(void *)arg, sizeof(struct msm_voicerec_mode)))
+			rc = -EFAULT;
+
+		if (aac->voicerec_mode.rec_mode != AUDIO_FLAG_READ
+			&& aac->voicerec_mode.rec_mode !=
+			AUDIO_FLAG_INCALL_MIXED) {
+			aac->voicerec_mode.rec_mode = AUDIO_FLAG_READ;
+			pr_err("[%s:%s] Invalid rec_mode\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+		}
+		break;
+	}
+	case AUDIO_GET_STREAM_CONFIG:
+		if (copy_to_user((void *)arg, &aac->str_cfg,
+			sizeof(struct msm_audio_stream_config)))
+			rc = -EFAULT;
+		pr_debug("[%s:%s] GET_STREAM_CONFIG: buffsz=%d, buffcnt=%d\n",
+			 __MM_FILE__, __func__, aac->str_cfg.buffer_size,
+			aac->str_cfg.buffer_count);
+		break;
+	case AUDIO_SET_STREAM_CONFIG:
+		if (copy_from_user(&aac->str_cfg, (void *)arg,
+			sizeof(struct msm_audio_stream_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("[%s:%s] SET_STREAM_CONFIG: buffsz=%d, buffcnt=%d\n",
+			 __MM_FILE__, __func__, aac->str_cfg.buffer_size,
+			aac->str_cfg.buffer_count);
+		if (aac->str_cfg.buffer_size < 1543) {
+			pr_err("[%s:%s] Buffer size too small\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+			break;
+		}
+		if (aac->str_cfg.buffer_count != 2)
+			pr_info("[%s:%s] Buffer count set to 2\n", __MM_FILE__,
+					__func__);
+
+		break;
+	case AUDIO_SET_AAC_ENC_CONFIG:
+		if (copy_from_user(&aac->cfg, (void *) arg,
+				 sizeof(struct msm_audio_aac_enc_config))) {
+			rc = -EFAULT;
+		}
+		pr_debug("[%s:%s] SET_AAC_ENC_CONFIG: channels=%d, rate=%d\n",
+			__MM_FILE__, __func__, aac->cfg.channels,
+			aac->cfg.sample_rate);
+		if (aac->cfg.channels < 1 || aac->cfg.channels > 2) {
+			pr_err("[%s:%s]invalid number of channels\n",
+				 __MM_FILE__, __func__);
+			rc = -EINVAL;
+		}
+		if (aac->cfg.sample_rate != 48000) {
+			pr_err("[%s:%s] only 48KHz is supported\n",
+					__MM_FILE__, __func__);
+			rc = -EINVAL;
+		}
+		if (aac->cfg.stream_format != AUDIO_AAC_FORMAT_RAW &&
+			aac->cfg.stream_format != AUDIO_AAC_FORMAT_ADTS) {
+			pr_err("[%s:%s] unsupported AAC format\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+		}
+		break;
+	case AUDIO_GET_AAC_ENC_CONFIG:
+		if (copy_to_user((void *) arg, &aac->cfg,
+				 sizeof(struct msm_audio_aac_enc_config))) {
+			rc = -EFAULT;
+		}
+		pr_debug("[%s:%s] GET_AAC_ENC_CONFIG: channels=%d, rate=%d\n",
+			__MM_FILE__, __func__, aac->cfg.channels,
+			aac->cfg.sample_rate);
+		break;
+	default:
+		rc = -EINVAL;
+	}
+
+	mutex_unlock(&aac->lock);
+	pr_debug("[%s:%s] rc = %d\n", __MM_FILE__, __func__, rc);
+	return rc;
+}
+
+static int q6_aac_in_open(struct inode *inode, struct file *file)
+{
+
+	struct aac *aac;
+	struct aac_fc *fc;
+	int i;
+	pr_info("[%s:%s] open\n", __MM_FILE__, __func__);
+	aac = kmalloc(sizeof(struct aac), GFP_KERNEL);
+	if (aac == NULL) {
+		pr_err("[%s:%s] Could not allocate memory for aac driver\n",
+				__MM_FILE__, __func__);
+		return -ENOMEM;
+	}
+
+	mutex_init(&aac->lock);
+	file->private_data = aac;
+	aac->audio_client = NULL;
+	aac->str_cfg.buffer_size = 1543;
+	aac->str_cfg.buffer_count = 2;
+	aac->cfg.channels = 1;
+	aac->cfg.bit_rate = 192000;
+	aac->cfg.stream_format = AUDIO_AAC_FORMAT_ADTS;
+	aac->cfg.sample_rate = 48000;
+	aac->voicerec_mode.rec_mode = AUDIO_FLAG_READ;
+
+	aac->aac_fc = kmalloc(sizeof(struct aac_fc), GFP_KERNEL);
+	if (aac->aac_fc == NULL) {
+		pr_err("[%s:%s] Could not allocate memory for aac_fc\n",
+				__MM_FILE__, __func__);
+		kfree(aac);
+		return -ENOMEM;
+	}
+	fc = aac->aac_fc;
+	fc->task = NULL;
+	fc->buff_index = 0;
+	for (i = 0; i < AAC_FC_BUFF_CNT; ++i) {
+		fc->fc_buff[i].data = NULL;
+		fc->fc_buff[i].size = 0;
+		fc->fc_buff[i].actual_size = 0;
+	}
+	/*initialize wait queue head*/
+	init_waitqueue_head(&fc->fc_wq);
+	return 0;
+}
+
+static ssize_t q6_aac_in_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *pos)
+{
+	struct audio_client *ac;
+	const char __user *start = buf;
+	struct aac *aac = file->private_data;
+	struct aac_fc *fc;
+	int xfer = 0;
+	int res = 0;
+
+	pr_debug("[%s:%s] count = %d\n", __MM_FILE__, __func__, count);
+	mutex_lock(&aac->lock);
+	ac = aac->audio_client;
+
+	if (!ac) {
+		res = -ENODEV;
+		goto fail;
+	}
+	fc = aac->aac_fc;
+
+	/*wait for buffer to full*/
+	if (fc->fc_buff[fc->buff_index].empty != 0) {
+		res = wait_event_interruptible_timeout(fc->fc_wq,
+			(fc->fc_buff[fc->buff_index].empty == 0),
+				msecs_to_jiffies(AAC_READ_TIMEOUT));
+
+		pr_debug("[%s:%s] buff_index = %d\n", __MM_FILE__,
+			__func__, fc->buff_index);
+		if (res == 0) {
+			pr_err("[%s:%s] Timeout!\n", __MM_FILE__, __func__);
+			res = -ETIMEDOUT;
+			goto fail;
+		} else if (res < 0) {
+			pr_err("[%s:%s] Returning on Interrupt\n", __MM_FILE__,
+				__func__);
+			goto fail;
+		}
+	}
+	/*lock the buffer*/
+	mutex_lock(&(fc->fc_buff[fc->buff_index].lock));
+	xfer = fc->fc_buff[fc->buff_index].actual_size;
+
+	if (xfer > count) {
+		mutex_unlock(&(fc->fc_buff[fc->buff_index].lock));
+		pr_err("[%s:%s] read failed! byte count too small\n",
+				__MM_FILE__, __func__);
+		res = -EINVAL;
+		goto fail;
+	}
+
+	if (copy_to_user(buf, fc->fc_buff[fc->buff_index].data,	xfer)) {
+		mutex_unlock(&(fc->fc_buff[fc->buff_index].lock));
+		pr_err("[%s:%s] copy_to_user failed at index %d\n",
+				__MM_FILE__, __func__, fc->buff_index);
+		res = -EFAULT;
+		goto fail;
+	}
+
+	buf += xfer;
+
+	fc->fc_buff[fc->buff_index].empty = 1;
+	fc->fc_buff[fc->buff_index].actual_size = 0;
+
+	mutex_unlock(&(fc->fc_buff[fc->buff_index].lock));
+	++(fc->buff_index);
+	if (fc->buff_index >= AAC_FC_BUFF_CNT)
+		fc->buff_index = 0;
+
+	res = buf - start;
+fail:
+	mutex_unlock(&aac->lock);
+
+	return res;
+}
+
+static int q6_aac_in_release(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	struct aac *aac = file->private_data;
+	int i = 0;
+	struct aac_fc *fc;
+
+	mutex_lock(&aac->lock);
+	fc = aac->aac_fc;
+	kthread_stop(fc->task);
+	fc->task = NULL;
+
+	/*free flow control buffers*/
+	for (i = 0; i < AAC_FC_BUFF_CNT; ++i) {
+		kfree(fc->fc_buff[i].data);
+		fc->fc_buff[i].data = NULL;
+	}
+	kfree(fc);
+	if (aac->audio_client)
+		rc = q6audio_close(aac->audio_client);
+	mutex_unlock(&aac->lock);
+	kfree(aac);
+	pr_info("[%s:%s] release\n", __MM_FILE__, __func__);
+	return rc;
+}
+
+static const struct file_operations q6_aac_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_aac_in_open,
+	.read		= q6_aac_in_read,
+	.release	= q6_aac_in_release,
+	.unlocked_ioctl	= q6_aac_in_ioctl,
+};
+
+struct miscdevice q6_aac_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_aac_in",
+	.fops	= &q6_aac_in_fops,
+};
+
+static int __init q6_aac_in_init(void)
+{
+	return misc_register(&q6_aac_in_misc);
+}
+
+device_initcall(q6_aac_in_init);
diff --git a/arch/arm/mach-msm/qdsp6/amrnb_in.c b/arch/arm/mach-msm/qdsp6/amrnb_in.c
new file mode 100644
index 0000000..e7756e1
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/amrnb_in.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ * Copyright (c) 2010, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio.h>
+#include <linux/msm_audio_amrnb.h>
+#include <mach/msm_qdsp6_audio.h>
+#include "dal_audio_format.h"
+#include <mach/debug_mm.h>
+
+struct amrnb {
+	struct mutex lock;
+	struct msm_audio_amrnb_enc_config_v2 cfg;
+	struct msm_audio_stream_config str_cfg;
+	struct audio_client *audio_client;
+	struct msm_voicerec_mode voicerec_mode;
+};
+
+
+static long q6_amrnb_in_ioctl(struct file *file, unsigned int cmd,
+				unsigned long arg)
+{
+	struct amrnb *amrnb = file->private_data;
+	int rc = 0;
+
+	mutex_lock(&amrnb->lock);
+	switch (cmd) {
+	case AUDIO_SET_VOLUME:
+		pr_debug("[%s:%s] SET_VOLUME\n", __MM_FILE__, __func__);
+		break;
+	case AUDIO_GET_STATS:
+	{
+		struct msm_audio_stats stats;
+		pr_debug("[%s:%s] GET_STATS\n", __MM_FILE__, __func__);
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+	case AUDIO_START:
+	{
+		uint32_t acdb_id;
+		pr_debug("[%s:%s] AUDIO_START\n", __MM_FILE__, __func__);
+		if (arg == 0) {
+			acdb_id = 0;
+		} else {
+			if (copy_from_user(&acdb_id, (void *) arg,
+						sizeof(acdb_id))) {
+				rc = -EFAULT;
+				break;
+			}
+		}
+		if (amrnb->audio_client) {
+			rc = -EBUSY;
+			pr_err("[%s:%s] active session already existing\n",
+				__MM_FILE__, __func__);
+			break;
+		} else {
+			amrnb->audio_client = q6audio_open_amrnb(
+					amrnb->str_cfg.buffer_size,
+					amrnb->cfg.band_mode,
+					amrnb->cfg.dtx_enable,
+					amrnb->voicerec_mode.rec_mode,
+					acdb_id);
+			if (!amrnb->audio_client) {
+				pr_err("[%s:%s] amrnb open session failed\n",
+					__MM_FILE__, __func__);
+				kfree(amrnb);
+				rc = -ENOMEM;
+				break;
+			}
+		}
+		break;
+	}
+	case AUDIO_STOP:
+		pr_debug("[%s:%s] AUDIO_STOP\n", __MM_FILE__, __func__);
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_INCALL: {
+		pr_debug("[%s:%s] SET_INCALL\n", __MM_FILE__, __func__);
+		if (copy_from_user(&amrnb->voicerec_mode,
+			(void *)arg, sizeof(struct msm_voicerec_mode)))
+			rc = -EFAULT;
+
+		if (amrnb->voicerec_mode.rec_mode != AUDIO_FLAG_READ
+				&& amrnb->voicerec_mode.rec_mode !=
+				AUDIO_FLAG_INCALL_MIXED) {
+			amrnb->voicerec_mode.rec_mode = AUDIO_FLAG_READ;
+			pr_err("[%s:%s] Invalid rec_mode\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+		}
+		break;
+	}
+	case AUDIO_GET_STREAM_CONFIG:
+		if (copy_to_user((void *)arg, &amrnb->str_cfg,
+			sizeof(struct msm_audio_stream_config)))
+			rc = -EFAULT;
+		pr_debug("[%s:%s] GET_STREAM_CONFIG: buffsz=%d, buffcnt = %d\n",
+			 __MM_FILE__, __func__, amrnb->str_cfg.buffer_size,
+			amrnb->str_cfg.buffer_count);
+		break;
+	case AUDIO_SET_STREAM_CONFIG:
+		if (copy_from_user(&amrnb->str_cfg, (void *)arg,
+			sizeof(struct msm_audio_stream_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("[%s:%s] SET_STREAM_CONFIG: buffsz=%d, buffcnt = %d\n",
+			 __MM_FILE__, __func__, amrnb->str_cfg.buffer_size,
+			amrnb->str_cfg.buffer_count);
+
+		if (amrnb->str_cfg.buffer_size < 768) {
+			pr_err("[%s:%s] Buffer size too small\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+			break;
+		}
+
+		if (amrnb->str_cfg.buffer_count != 2)
+			pr_info("[%s:%s] Buffer count set to 2\n", __MM_FILE__,
+					__func__);
+		break;
+	case AUDIO_SET_AMRNB_ENC_CONFIG:
+		if (copy_from_user(&amrnb->cfg, (void *) arg,
+			sizeof(struct msm_audio_amrnb_enc_config_v2)))
+			rc = -EFAULT;
+		pr_debug("[%s:%s] SET_AMRNB_ENC_CONFIG\n", __MM_FILE__,
+			__func__);
+		break;
+	case AUDIO_GET_AMRNB_ENC_CONFIG:
+		if (copy_to_user((void *) arg, &amrnb->cfg,
+				 sizeof(struct msm_audio_amrnb_enc_config_v2)))
+			rc = -EFAULT;
+		pr_debug("[%s:%s] GET_AMRNB_ENC_CONFIG\n", __MM_FILE__,
+			__func__);
+		break;
+
+	default:
+		rc = -EINVAL;
+	}
+
+	mutex_unlock(&amrnb->lock);
+	pr_debug("[%s:%s] rc= %d\n", __MM_FILE__, __func__, rc);
+	return rc;
+}
+
+static int q6_amrnb_in_open(struct inode *inode, struct file *file)
+{
+	struct amrnb *amrnb;
+
+	pr_info("[%s:%s] open\n", __MM_FILE__, __func__);
+	amrnb = kmalloc(sizeof(struct amrnb), GFP_KERNEL);
+	if (amrnb == NULL) {
+		pr_err("[%s:%s] Could not allocate memory for amrnb driver\n",
+				__MM_FILE__, __func__);
+		return -ENOMEM;
+	}
+
+	mutex_init(&amrnb->lock);
+	file->private_data = amrnb;
+	amrnb->audio_client = NULL;
+	amrnb->str_cfg.buffer_size = 768;
+	amrnb->str_cfg.buffer_count = 2;
+	amrnb->cfg.band_mode = 7;
+	amrnb->cfg.dtx_enable  = 3;
+	amrnb->cfg.frame_format = ADSP_AUDIO_FORMAT_AMRNB_FS;
+	amrnb->voicerec_mode.rec_mode = AUDIO_FLAG_READ;
+
+	return 0;
+}
+
+static ssize_t q6_amrnb_in_read(struct file *file, char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	const char __user *start = buf;
+	struct amrnb *amrnb = file->private_data;
+	int xfer = 0;
+	int res;
+
+	pr_debug("[%s:%s] count = %d\n", __MM_FILE__, __func__, count);
+	mutex_lock(&amrnb->lock);
+	ac = amrnb->audio_client;
+	if (!ac) {
+		res = -ENODEV;
+		goto fail;
+	}
+	while (count > xfer) {
+		ab = ac->buf + ac->cpu_buf;
+
+		if (ab->used)
+			wait_event(ac->wait, (ab->used == 0));
+
+		pr_debug("[%s:%s] ab->data = %p, cpu_buf = %d\n", __MM_FILE__,
+			__func__, ab->data, ac->cpu_buf);
+		xfer = ab->actual_size;
+
+		if (copy_to_user(buf, ab->data, xfer)) {
+			pr_err("[%s:%s] copy_to_user failed\n",
+				__MM_FILE__, __func__);
+			res = -EFAULT;
+			goto fail;
+		}
+
+		buf += xfer;
+		count -= xfer;
+
+		ab->used = 1;
+		q6audio_read(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+
+	res = buf - start;
+fail:
+	mutex_unlock(&amrnb->lock);
+
+	return res;
+}
+
+static int q6_amrnb_in_release(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	struct amrnb *amrnb = file->private_data;
+
+	mutex_lock(&amrnb->lock);
+	if (amrnb->audio_client)
+		rc = q6audio_close(amrnb->audio_client);
+	mutex_unlock(&amrnb->lock);
+	kfree(amrnb);
+	pr_info("[%s:%s] release\n", __MM_FILE__, __func__);
+	return rc;
+}
+
+static const struct file_operations q6_amrnb_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_amrnb_in_open,
+	.read		= q6_amrnb_in_read,
+	.release	= q6_amrnb_in_release,
+	.unlocked_ioctl	= q6_amrnb_in_ioctl,
+};
+
+struct miscdevice q6_amrnb_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_amr_in",
+	.fops	= &q6_amrnb_in_fops,
+};
+
+static int __init q6_amrnb_in_init(void)
+{
+	return misc_register(&q6_amrnb_in_misc);
+}
+
+device_initcall(q6_amrnb_in_init);
diff --git a/arch/arm/mach-msm/qdsp6/analog_audio.c b/arch/arm/mach-msm/qdsp6/analog_audio.c
new file mode 100644
index 0000000..688f57e
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/analog_audio.c
@@ -0,0 +1,94 @@
+/* Copyright (c) 2010, 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/wait.h>
+#include <linux/gpio.h>
+#include <mach/pmic.h>
+#include <mach/msm_qdsp6_audio.h>
+#include <asm/string.h>
+#include <asm/mach-types.h>
+#include <mach/debug_mm.h>
+
+#define GPIO_HEADSET_AMP 157
+#define GPIO_SPEAKER_AMP 39
+#define GPIO_HEADSET_SHDN_N 48
+
+void analog_init(void)
+{
+	/* stereo pmic init */
+	pmic_spkr_set_gain(LEFT_SPKR, SPKR_GAIN_PLUS12DB);
+	pmic_spkr_set_gain(RIGHT_SPKR, SPKR_GAIN_PLUS12DB);
+	pmic_mic_set_volt(MIC_VOLT_1_80V);
+	gpio_direction_output(GPIO_HEADSET_AMP, 1);
+	gpio_set_value(GPIO_HEADSET_AMP, 0);
+}
+
+void analog_headset_enable(int en)
+{
+	pr_debug("[%s:%s] en = %d\n", __MM_FILE__, __func__, en);
+	/* enable audio amp */
+	gpio_set_value(GPIO_HEADSET_AMP, !!en);
+}
+
+void analog_speaker_enable(int en)
+{
+	struct spkr_config_mode scm;
+	memset(&scm, 0, sizeof(scm));
+
+	pr_debug("[%s:%s] en = %d\n", __MM_FILE__, __func__, en);
+	if (en) {
+		scm.is_right_chan_en = 1;
+		scm.is_left_chan_en = 1;
+		scm.is_stereo_en = 1;
+		scm.is_hpf_en = 1;
+		pmic_spkr_en_mute(LEFT_SPKR, 0);
+		pmic_spkr_en_mute(RIGHT_SPKR, 0);
+		pmic_set_spkr_configuration(&scm);
+		pmic_spkr_en(LEFT_SPKR, 1);
+		pmic_spkr_en(RIGHT_SPKR, 1);
+		
+		/* unmute */
+		pmic_spkr_en_mute(LEFT_SPKR, 1);
+		pmic_spkr_en_mute(RIGHT_SPKR, 1);
+	} else {
+		pmic_spkr_en_mute(LEFT_SPKR, 0);
+		pmic_spkr_en_mute(RIGHT_SPKR, 0);
+
+		pmic_spkr_en(LEFT_SPKR, 0);
+		pmic_spkr_en(RIGHT_SPKR, 0);
+
+		pmic_set_spkr_configuration(&scm);
+	}
+}
+
+void analog_mic_enable(int en)
+{
+	pr_debug("[%s:%s] en = %d\n", __MM_FILE__, __func__, en);
+	pmic_mic_en(en);
+}
+
+static struct q6audio_analog_ops ops = {
+	.init = analog_init,
+	.speaker_enable = analog_speaker_enable,
+	.headset_enable = analog_headset_enable,
+	.int_mic_enable = analog_mic_enable,
+	.ext_mic_enable = analog_mic_enable,
+};
+
+static int __init init(void)
+{
+	q6audio_register_analog_ops(&ops);
+	return 0;
+}
+
+device_initcall(init);
diff --git a/arch/arm/mach-msm/qdsp6/audio_ctl.c b/arch/arm/mach-msm/qdsp6/audio_ctl.c
new file mode 100644
index 0000000..ab1df39
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audio_ctl.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ *
+ * 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.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/msm_audio.h>
+
+#include <mach/msm_qdsp6_audio.h>
+#include <mach/debug_mm.h>
+
+#define BUFSZ (0)
+
+static DEFINE_MUTEX(voice_lock);
+static int voice_started;
+
+static struct audio_client *voc_tx_clnt;
+static struct audio_client *voc_rx_clnt;
+
+static int q6_voice_start(void)
+{
+	int rc = 0;
+
+	mutex_lock(&voice_lock);
+
+	if (voice_started) {
+		pr_err("[%s:%s] busy\n", __MM_FILE__, __func__);
+		rc = -EBUSY;
+		goto done;
+	}
+
+	voc_tx_clnt = q6voice_open(AUDIO_FLAG_WRITE);
+	if (!voc_tx_clnt) {
+		pr_err("[%s:%s] open voice tx failed.\n", __MM_FILE__,
+				__func__);
+		rc = -ENOMEM;
+		goto done;
+	}
+
+	voc_rx_clnt = q6voice_open(AUDIO_FLAG_READ);
+	if (!voc_rx_clnt) {
+		pr_err("[%s:%s] open voice rx failed.\n", __MM_FILE__,
+				__func__);
+		q6voice_close(voc_tx_clnt);
+		rc = -ENOMEM;
+	}
+
+	voice_started = 1;
+done:
+	mutex_unlock(&voice_lock);
+	return rc;
+}
+
+static int q6_voice_stop(void)
+{
+	mutex_lock(&voice_lock);
+	if (voice_started) {
+		q6voice_close(voc_tx_clnt);
+		q6voice_close(voc_rx_clnt);
+		voice_started = 0;
+	}
+	mutex_unlock(&voice_lock);
+	return 0;
+}
+
+static int q6_open(struct inode *inode, struct file *file)
+{
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	return 0;
+}
+
+static long q6_ioctl(struct file *file,
+		    unsigned int cmd, unsigned long arg)
+{
+	int rc;
+	uint32_t n;
+	uint32_t id[2];
+	uint32_t mute_status;
+
+	switch (cmd) {
+	case AUDIO_SWITCH_DEVICE:
+		rc = copy_from_user(&id, (void *)arg, sizeof(id));
+		pr_info("[%s:%s] SWITCH_DEV: id[0] = 0x%x, id[1] = 0x%x",
+			__MM_FILE__, __func__, id[0], id[1]);
+		if (!rc)
+			rc = q6audio_do_routing(id[0], id[1]);
+		break;
+	case AUDIO_SET_VOLUME:
+		rc = copy_from_user(&n, (void *)arg, sizeof(n));
+		pr_debug("[%s:%s] SET_VOLUME: vol = %d\n", __MM_FILE__,
+				__func__, n);
+		if (!rc)
+			rc = q6audio_set_rx_volume(n);
+		break;
+	case AUDIO_SET_MUTE:
+		rc = copy_from_user(&n, (void *)arg, sizeof(n));
+		if (!rc) {
+			if (voice_started) {
+				if (n == 1)
+					mute_status = STREAM_MUTE;
+				else
+					mute_status = STREAM_UNMUTE;
+			} else {
+				if (n == 1)
+					mute_status = DEVICE_MUTE;
+				else
+					mute_status = DEVICE_UNMUTE;
+			}
+
+			pr_debug("[%s:%s] SET_MUTE: mute_status = %d\n",
+				__MM_FILE__, __func__, mute_status);
+			rc = q6audio_set_tx_mute(mute_status);
+		}
+		break;
+	case AUDIO_UPDATE_ACDB:
+		rc = copy_from_user(&id, (void *)arg, sizeof(id));
+		pr_debug("[%s:%s] UPDATE_ACDB: id[0] = 0x%x, id[1] = 0x%x\n",
+				__MM_FILE__, __func__, id[0], id[1]);
+		if (!rc)
+			rc = q6audio_update_acdb(id[0], 0);
+		break;
+	case AUDIO_START_VOICE:
+		pr_debug("[%s:%s] START_VOICE\n", __MM_FILE__, __func__);
+		rc = q6_voice_start();
+		break;
+	case AUDIO_STOP_VOICE:
+		pr_debug("[%s:%s] STOP_VOICE\n", __MM_FILE__, __func__);
+		rc = q6_voice_stop();
+		break;
+	case AUDIO_REINIT_ACDB:
+		pr_debug("[%s:%s] REINIT_ACDB\n", __MM_FILE__, __func__);
+		rc = 0;
+		break;
+	default:
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+
+static int q6_release(struct inode *inode, struct file *file)
+{
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	return 0;
+}
+
+static struct file_operations q6_dev_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_open,
+	.unlocked_ioctl	= q6_ioctl,
+	.release	= q6_release,
+};
+
+struct miscdevice q6_control_device = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_audio_ctl",
+	.fops	= &q6_dev_fops,
+};
+
+
+static int __init q6_audio_ctl_init(void) {
+	return misc_register(&q6_control_device);
+}
+
+device_initcall(q6_audio_ctl_init);
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/Makefile b/arch/arm/mach-msm/qdsp6/audiov2/Makefile
new file mode 100644
index 0000000..86ab9ae
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/Makefile
@@ -0,0 +1,12 @@
+obj-y += q6audio.o
+obj-y += aac_in.o
+obj-y += voice.o
+obj-y += pcm_out.o
+obj-y += pcm_in.o
+obj-y += mp3.o
+obj-y += audio_ctl.o
+obj-y += analog_audio.o
+obj-y += routing.o
+obj-y += evrc_in.o
+obj-y += qcelp_in.o
+obj-y += amrnb_in.o
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/aac_in.c b/arch/arm/mach-msm/qdsp6/audiov2/aac_in.c
new file mode 100644
index 0000000..fe6c049
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/aac_in.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ * Copyright (c) 2009, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio_aac.h>
+
+#include <mach/msm_qdsp6_audiov2.h>
+#include "dal_audio.h"
+#include "dal_audio_format.h"
+
+struct aac {
+	struct mutex lock;
+	struct msm_audio_aac_enc_config cfg;
+	struct msm_audio_stream_config str_cfg;
+	struct audio_client *audio_client;
+};
+
+static long q6_aac_in_ioctl(struct file *file,
+				 unsigned int cmd, unsigned long arg)
+{
+	struct aac *aac = file->private_data;
+	struct adsp_open_command rpc;
+
+	int sample_rate;
+	int audio_object_type;
+	int index = sizeof(u32);
+	int rc = 0;
+	u32 *aac_type = NULL;
+
+
+	mutex_lock(&aac->lock);
+	switch (cmd) {
+
+	case AUDIO_START:
+		if (aac->audio_client) {
+			rc = -EBUSY;
+			break;
+		} else {
+			tx_clk_freq = 48000;
+			aac->audio_client = q6audio_open(AUDIO_FLAG_READ,
+						aac->str_cfg.buffer_size);
+
+			if (aac->audio_client < 0) {
+
+				tx_clk_freq = 8000;
+				rc = -ENOMEM;
+				break;
+			}
+		}
+		memset(&rpc, 0, sizeof(rpc));
+
+		rpc.format_block.binary.format = ADSP_AUDIO_FORMAT_MPEG4_AAC;
+		/* only 48k sample rate is supported */
+		sample_rate = 3;
+
+		/* AAC OBJECT LC */
+		audio_object_type = 2;
+
+		aac_type = (u32 *)rpc.format_block.binary.data;
+		switch (aac->cfg.stream_format) {
+
+		case AUDIO_AAC_FORMAT_ADTS:
+			/* AAC Encoder expect MPEG4_ADTS media type */
+			*aac_type = ADSP_AUDIO_AAC_MPEG4_ADTS;
+			break;
+		case AUDIO_AAC_FORMAT_RAW:
+			/* for ADIF recording */
+			*aac_type = ADSP_AUDIO_AAC_RAW;
+			break;
+		}
+
+		rpc.format_block.binary.data[index++] = (u8)(
+			((audio_object_type & 0x1F) << 3) |
+			((sample_rate >> 1) & 0x7));
+		rpc.format_block.binary.data[index] = (u8)(
+			((sample_rate & 0x1) << 7) |
+			((aac->cfg.channels & 0x7) << 3));
+
+		rpc.format_block.binary.num_bytes = index + 1;
+		rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_READ;
+		rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+		rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD;
+		rpc.buf_max_size = aac->str_cfg.buffer_size;
+		rpc.config.aac.bit_rate = aac->cfg.bit_rate;
+		rpc.config.aac.encoder_mode = ADSP_AUDIO_ENC_AAC_LC_ONLY_MODE;
+		q6audio_start(aac->audio_client, &rpc, sizeof(rpc));
+		break;
+	case AUDIO_STOP:
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_VOLUME:
+		break;
+	case AUDIO_GET_STREAM_CONFIG:
+		if (copy_to_user((void *)arg, &aac->str_cfg,
+			sizeof(struct msm_audio_stream_config)))
+			rc = -EFAULT;
+		break;
+	case AUDIO_SET_STREAM_CONFIG:
+		if (copy_from_user(&aac->str_cfg, (void *)arg,
+			sizeof(struct msm_audio_stream_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (aac->str_cfg.buffer_size < 519) {
+			pr_err("Buffer size too small\n");
+			rc = -EINVAL;
+			break;
+		}
+		if (aac->str_cfg.buffer_count != 2)
+			pr_info("Buffer count set to 2\n");
+
+		break;
+	case AUDIO_SET_AAC_ENC_CONFIG:
+		if (copy_from_user(&aac->cfg, (void *) arg,
+				 sizeof(struct msm_audio_aac_enc_config))) {
+			rc = -EFAULT;
+		}
+		if (aac->cfg.channels != 1) {
+			pr_err("only mono is supported\n");
+			rc = -EINVAL;
+		}
+		if (aac->cfg.sample_rate != 48000) {
+			pr_err("only 48KHz is supported\n");
+			rc = -EINVAL;
+		}
+		if (aac->cfg.stream_format != AUDIO_AAC_FORMAT_RAW &&
+			aac->cfg.stream_format != AUDIO_AAC_FORMAT_ADTS) {
+			pr_err("unsupported AAC format\n");
+			rc = -EINVAL;
+		}
+		break;
+	case AUDIO_GET_AAC_ENC_CONFIG:
+		if (copy_to_user((void *) arg, &aac->cfg,
+				 sizeof(struct msm_audio_aac_enc_config))) {
+			rc = -EFAULT;
+		}
+		break;
+	default:
+		rc = -EINVAL;
+	}
+
+	mutex_unlock(&aac->lock);
+	return rc;
+}
+
+static int q6_aac_in_open(struct inode *inode, struct file *file)
+{
+
+	struct aac *aac;
+	aac = kmalloc(sizeof(struct aac), GFP_KERNEL);
+	if (aac == NULL) {
+		pr_err("Could not allocate memory for aac driver\n");
+		return -ENOMEM;
+	}
+
+	mutex_init(&aac->lock);
+	file->private_data = aac;
+	aac->audio_client = NULL;
+	aac->str_cfg.buffer_size = 519;
+	aac->str_cfg.buffer_count = 2;
+	aac->cfg.channels = 1;
+	aac->cfg.bit_rate = 192000;
+	aac->cfg.stream_format = AUDIO_AAC_FORMAT_ADTS;
+	aac->cfg.sample_rate = 48000;
+
+	return 0;
+}
+
+static ssize_t q6_aac_in_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *pos)
+{
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	const char __user *start = buf;
+	struct aac *aac = file->private_data;
+	int xfer = 0;
+	int res;
+
+	mutex_lock(&aac->lock);
+	ac = aac->audio_client;
+	if (!ac) {
+		res = -ENODEV;
+		goto fail;
+	}
+	while (count > xfer) {
+		ab = ac->buf + ac->cpu_buf;
+
+		if (ab->used)
+			wait_event(ac->wait, (ab->used == 0));
+
+		xfer = ab->actual_size;
+
+		if (copy_to_user(buf, ab->data, xfer)) {
+			res = -EFAULT;
+			goto fail;
+		}
+
+		buf += xfer;
+		count -= xfer;
+
+		ab->used = 1;
+		q6audio_read(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+	res = buf - start;
+fail:
+	mutex_unlock(&aac->lock);
+
+	return res;
+}
+
+static int q6_aac_in_release(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	struct aac *aac = file->private_data;
+
+	mutex_lock(&aac->lock);
+	if (aac->audio_client)
+		rc = q6audio_close(aac->audio_client);
+	mutex_unlock(&aac->lock);
+	kfree(aac);
+	tx_clk_freq = 8000;
+	return rc;
+}
+
+static const struct file_operations q6_aac_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_aac_in_open,
+	.read		= q6_aac_in_read,
+	.release	= q6_aac_in_release,
+	.unlocked_ioctl	= q6_aac_in_ioctl,
+};
+
+struct miscdevice q6_aac_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_aac_in",
+	.fops	= &q6_aac_in_fops,
+};
+
+static int __init q6_aac_in_init(void)
+{
+	return misc_register(&q6_aac_in_misc);
+}
+
+device_initcall(q6_aac_in_init);
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/amrnb_in.c b/arch/arm/mach-msm/qdsp6/audiov2/amrnb_in.c
new file mode 100644
index 0000000..b877977
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/amrnb_in.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ * Copyright (c) 2010, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio_amrnb.h>
+#include <mach/msm_qdsp6_audiov2.h>
+#include "dal_audio.h"
+#include "dal_audio_format.h"
+#include <mach/debug_mm.h>
+
+
+struct amrnb {
+	struct mutex lock;
+	struct msm_audio_amrnb_enc_config_v2 cfg;
+	struct msm_audio_stream_config str_cfg;
+	struct audio_client *audio_client;
+};
+
+
+static long q6_amrnb_in_ioctl(struct file *file, unsigned int cmd,
+				unsigned long arg)
+{
+	struct amrnb *amrnb = file->private_data;
+	struct adsp_open_command rpc;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	mutex_lock(&amrnb->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		if (amrnb->audio_client) {
+			rc = -EBUSY;
+			break;
+		} else {
+			amrnb->audio_client = q6audio_open(AUDIO_FLAG_READ,
+						amrnb->str_cfg.buffer_size);
+
+			if (!amrnb->audio_client) {
+				kfree(amrnb);
+				rc = -ENOMEM;
+				break;
+			}
+		}
+
+		tx_clk_freq = 8000;
+
+		memset(&rpc, 0, sizeof(rpc));
+
+		rpc.format_block.standard.format = ADSP_AUDIO_FORMAT_AMRNB_FS;
+		rpc.format_block.standard.channels = 1;
+		rpc.format_block.standard.bits_per_sample = 16;
+		rpc.format_block.standard.sampling_rate = 8000;
+		rpc.format_block.standard.is_signed = 1;
+		rpc.format_block.standard.is_interleaved = 0;
+
+		rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_READ;
+		rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+		rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD;
+		rpc.buf_max_size = amrnb->str_cfg.buffer_size;
+		rpc.config.amr.mode = amrnb->cfg.band_mode;
+		rpc.config.amr.dtx_mode = amrnb->cfg.dtx_enable;
+		rpc.config.amr.enable = 1;
+		q6audio_start(amrnb->audio_client, &rpc, sizeof(rpc));
+		break;
+	case AUDIO_STOP:
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_VOLUME:
+		break;
+	case AUDIO_GET_STREAM_CONFIG:
+		if (copy_to_user((void *)arg, &amrnb->str_cfg,
+			sizeof(struct msm_audio_stream_config)))
+			rc = -EFAULT;
+		break;
+	case AUDIO_SET_STREAM_CONFIG:
+		if (copy_from_user(&amrnb->str_cfg, (void *)arg,
+			sizeof(struct msm_audio_stream_config))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		if (amrnb->str_cfg.buffer_size < 768) {
+			pr_err("[%s:%s] Buffer size too small\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+			break;
+		}
+
+		if (amrnb->str_cfg.buffer_count != 2)
+			pr_info("[%s:%s] Buffer count set to 2\n", __MM_FILE__,
+					__func__);
+		break;
+	case AUDIO_SET_AMRNB_ENC_CONFIG:
+		if (copy_from_user(&amrnb->cfg, (void *) arg,
+			sizeof(struct msm_audio_amrnb_enc_config_v2)))
+			rc = -EFAULT;
+		break;
+	case AUDIO_GET_AMRNB_ENC_CONFIG:
+		if (copy_to_user((void *) arg, &amrnb->cfg,
+				 sizeof(struct msm_audio_amrnb_enc_config_v2)))
+			rc = -EFAULT;
+		break;
+
+	default:
+		rc = -EINVAL;
+	}
+
+	mutex_unlock(&amrnb->lock);
+	return rc;
+}
+
+static int q6_amrnb_in_open(struct inode *inode, struct file *file)
+{
+	struct amrnb *amrnb;
+	amrnb = kmalloc(sizeof(struct amrnb), GFP_KERNEL);
+	if (amrnb == NULL) {
+		pr_err("[%s:%s] Could not allocate memory for amrnb driver\n",
+				__MM_FILE__, __func__);
+		return -ENOMEM;
+	}
+
+	mutex_init(&amrnb->lock);
+	file->private_data = amrnb;
+	amrnb->audio_client = NULL;
+	amrnb->str_cfg.buffer_size = 768;
+	amrnb->str_cfg.buffer_count = 2;
+	amrnb->cfg.band_mode = ADSP_AUDIO_AMR_MR475;
+	amrnb->cfg.dtx_enable  = ADSP_AUDIO_AMR_DTX_MODE_ON_AUTO;
+	amrnb->cfg.frame_format  = ADSP_AUDIO_FORMAT_AMRNB_FS;
+	return 0;
+}
+
+static ssize_t q6_amrnb_in_read(struct file *file, char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	const char __user *start = buf;
+	struct amrnb *amrnb = file->private_data;
+	int xfer = 0;
+	int res;
+
+	mutex_lock(&amrnb->lock);
+	ac = amrnb->audio_client;
+	if (!ac) {
+		res = -ENODEV;
+		goto fail;
+	}
+	while (count > xfer) {
+		ab = ac->buf + ac->cpu_buf;
+
+		if (ab->used)
+			wait_event(ac->wait, (ab->used == 0));
+
+		xfer = ab->actual_size;
+
+		if (copy_to_user(buf, ab->data, xfer)) {
+			res = -EFAULT;
+			goto fail;
+		}
+
+		buf += xfer;
+		count -= xfer;
+
+		ab->used = 1;
+		q6audio_read(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+
+	res = buf - start;
+fail:
+	mutex_unlock(&amrnb->lock);
+
+	return res;
+}
+
+static int q6_amrnb_in_release(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	struct amrnb *amrnb = file->private_data;
+
+	mutex_lock(&amrnb->lock);
+	if (amrnb->audio_client)
+		rc = q6audio_close(amrnb->audio_client);
+	mutex_unlock(&amrnb->lock);
+	kfree(amrnb);
+	return rc;
+}
+
+static const struct file_operations q6_amrnb_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_amrnb_in_open,
+	.read		= q6_amrnb_in_read,
+	.release	= q6_amrnb_in_release,
+	.unlocked_ioctl	= q6_amrnb_in_ioctl,
+};
+
+struct miscdevice q6_amrnb_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_amr_in",
+	.fops	= &q6_amrnb_in_fops,
+};
+
+static int __init q6_amrnb_in_init(void)
+{
+	return misc_register(&q6_amrnb_in_misc);
+}
+
+device_initcall(q6_amrnb_in_init);
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/analog_audio.c b/arch/arm/mach-msm/qdsp6/audiov2/analog_audio.c
new file mode 100644
index 0000000..1df4f5d
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/analog_audio.c
@@ -0,0 +1,85 @@
+/* Copyright (c) 2009, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/gpio.h>
+#include <mach/pmic.h>
+#include <mach/msm_qdsp6_audiov2.h>
+
+#define GPIO_HEADSET_AMP 157
+
+void analog_init(void)
+{
+	/* stereo pmic init */
+	pmic_spkr_set_gain(LEFT_SPKR, SPKR_GAIN_PLUS12DB);
+	pmic_spkr_set_gain(RIGHT_SPKR, SPKR_GAIN_PLUS12DB);
+	pmic_mic_set_volt(MIC_VOLT_1_80V);
+
+	gpio_direction_output(GPIO_HEADSET_AMP, 1);
+	gpio_set_value(GPIO_HEADSET_AMP, 0);
+}
+
+void analog_headset_enable(int en)
+{
+	/* enable audio amp */
+	gpio_set_value(GPIO_HEADSET_AMP, !!en);
+}
+
+void analog_speaker_enable(int en)
+{
+	struct spkr_config_mode scm;
+	memset(&scm, 0, sizeof(scm));
+
+	if (en) {
+		scm.is_right_chan_en = 1;
+		scm.is_left_chan_en = 1;
+		scm.is_stereo_en = 1;
+		scm.is_hpf_en = 1;
+		pmic_spkr_en_mute(LEFT_SPKR, 0);
+		pmic_spkr_en_mute(RIGHT_SPKR, 0);
+		pmic_set_spkr_configuration(&scm);
+		pmic_spkr_en(LEFT_SPKR, 1);
+		pmic_spkr_en(RIGHT_SPKR, 1);
+
+		/* unmute */
+		pmic_spkr_en_mute(LEFT_SPKR, 1);
+		pmic_spkr_en_mute(RIGHT_SPKR, 1);
+	} else {
+		pmic_spkr_en_mute(LEFT_SPKR, 0);
+		pmic_spkr_en_mute(RIGHT_SPKR, 0);
+
+		pmic_spkr_en(LEFT_SPKR, 0);
+		pmic_spkr_en(RIGHT_SPKR, 0);
+
+		pmic_set_spkr_configuration(&scm);
+	}
+}
+
+void analog_mic_enable(int en)
+{
+	pmic_mic_en(en);
+}
+
+static struct q6audio_analog_ops ops = {
+	.init = analog_init,
+	.speaker_enable = analog_speaker_enable,
+	.headset_enable = analog_headset_enable,
+	.int_mic_enable = analog_mic_enable,
+};
+
+static int __init init(void)
+{
+	q6audio_register_analog_ops(&ops);
+	return 0;
+}
+
+device_initcall(init);
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/audio_ctl.c b/arch/arm/mach-msm/qdsp6/audiov2/audio_ctl.c
new file mode 100644
index 0000000..286d85d
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/audio_ctl.c
@@ -0,0 +1,140 @@
+/* arch/arm/mach-msm/qdsp6/audiov2/audio_ctrl.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ * Copyright (c) 2009, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/msm_audio.h>
+
+#include <mach/msm_qdsp6_audiov2.h>
+
+#define BUFSZ (0)
+
+static DEFINE_MUTEX(voice_lock);
+static int voice_started;
+
+static struct audio_client *voc_clnt;
+
+static int q6_voice_start(void)
+{
+	int rc = 0;
+
+	mutex_lock(&voice_lock);
+
+	if (voice_started) {
+		pr_err("voice: busy\n");
+		rc = -EBUSY;
+		goto done;
+	}
+
+	voc_clnt = q6voice_open();
+	if (!voc_clnt) {
+		pr_err("voice: open voice failed.\n");
+		rc = -ENOMEM;
+		goto done;
+	}
+
+	voice_started = 1;
+done:
+	mutex_unlock(&voice_lock);
+	return rc;
+}
+
+static int q6_voice_stop(void)
+{
+	mutex_lock(&voice_lock);
+	if (voice_started) {
+		q6voice_close(voc_clnt);
+		voice_started = 0;
+	}
+	mutex_unlock(&voice_lock);
+	return 0;
+}
+
+static int q6_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static int q6_ioctl(struct inode *inode, struct file *file,
+		    unsigned int cmd, unsigned long arg)
+{
+	int rc;
+	uint32_t n;
+	uint32_t id[2];
+
+	switch (cmd) {
+	case AUDIO_SWITCH_DEVICE:
+		rc = copy_from_user(&n, (void *)arg, sizeof(n));
+		if (!rc)
+			rc = q6audio_do_routing(n);
+		break;
+	case AUDIO_SET_VOLUME:
+		rc = copy_from_user(&n, (void *)arg, sizeof(n));
+		if (!rc)
+			rc = q6audio_set_rx_volume(n);
+		break;
+	case AUDIO_SET_MUTE:
+		rc = copy_from_user(&n, (void *)arg, sizeof(n));
+		if (!rc)
+			rc = q6audio_set_tx_mute(n);
+		break;
+	case AUDIO_UPDATE_ACDB:
+		rc = copy_from_user(&id, (void *)arg, sizeof(id));
+		if (!rc)
+			rc = q6audio_update_acdb(id[0], id[1]);
+		break;
+	case AUDIO_START_VOICE:
+		rc = q6_voice_start();
+		break;
+	case AUDIO_STOP_VOICE:
+		rc = q6_voice_stop();
+		break;
+	default:
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+
+static int q6_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static const struct file_operations q6_dev_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_open,
+	.ioctl		= q6_ioctl,
+	.release	= q6_release,
+};
+
+struct miscdevice q6_control_device = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_audio_ctl",
+	.fops	= &q6_dev_fops,
+};
+
+
+static int __init q6_audio_ctl_init(void)
+{
+	return misc_register(&q6_control_device);
+}
+
+device_initcall(q6_audio_ctl_init);
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/dal_acdb.h b/arch/arm/mach-msm/qdsp6/audiov2/dal_acdb.h
new file mode 100644
index 0000000..d88b7ad
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/dal_acdb.h
@@ -0,0 +1,71 @@
+/* Copyright (c) 2009, 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.
+ *
+ */
+
+#define ACDB_DAL_DEVICE		0x02000069
+#define ACDB_DAL_PORT		"DAL_AM_AUD"
+#define ACDB_DAL_VERSION	0x00010000
+
+#define ACDB_OP_IOCTL		DAL_OP_FIRST_DEVICE_API
+
+/* ioctls */
+#define ACDB_GET_DEVICE		0x0108bb92
+#define ACDB_SET_DEVICE		0x0108bb93
+#define ACDB_GET_STREAM		0x0108bb95
+#define ACDB_SET_STREAM		0x0108bb96
+#define ACDB_GET_DEVICE_TABLE	0x0108bb97
+#define ACDB_GET_STREAM_TABLE	0x0108bb98
+
+#define ACDB_RES_SUCCESS	0
+#define ACDB_RES_FAILURE	-1
+#define ACDB_RES_BADPARM	-2
+#define ACDB_RES_BADSTATE	-3
+
+struct acdb_cmd_device {
+	uint32_t size;
+
+	uint32_t command_id;
+	uint32_t device_id;
+	uint32_t network_id;
+	uint32_t sample_rate_id;
+	uint32_t interface_id;
+	uint32_t algorithm_block_id;
+
+	/* physical page aligned buffer */
+	uint32_t total_bytes;
+	uint32_t unmapped_buf;
+} __attribute__((packed));
+
+struct acdb_cmd_device_table {
+	uint32_t size;
+
+	uint32_t command_id;
+	uint32_t device_id;
+	uint32_t network_id;
+	uint32_t sample_rate_id;
+
+	/* physical page aligned buffer */
+	uint32_t total_bytes;
+	uint32_t unmapped_buf;
+
+	uint32_t res_size;
+} __attribute__((packed));
+
+struct acdb_result {
+	uint32_t dal_status;
+	uint32_t size;
+
+	uint32_t total_devices;
+	uint32_t unmapped_buf;
+	uint32_t used_bytes;
+	uint32_t result;
+} __attribute__((packed));
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/dal_adie.h b/arch/arm/mach-msm/qdsp6/audiov2/dal_adie.h
new file mode 100644
index 0000000..e828e9c
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/dal_adie.h
@@ -0,0 +1,89 @@
+/* Copyright (c) 2009, 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 _MACH_MSM_QDSP6_ADIE_
+#define _MACH_MSM_QDSP6_ADIE_
+
+#include "../dal.h"
+
+#define ADIE_DAL_DEVICE		0x02000029
+#define ADIE_DAL_PORT		"DAL_AM_AUD"
+#define ADIE_DAL_VERSION	0x00010000
+
+enum {
+	ADIE_OP_SET_PATH =  DAL_OP_FIRST_DEVICE_API,
+	ADIE_OP_PROCEED_TO_STAGE,
+	ADIE_OP_IOCTL
+};
+
+/* Path IDs for normal operation. */
+#define ADIE_PATH_HANDSET_TX			0x010740f6
+#define ADIE_PATH_HANDSET_RX			0x010740f7
+#define ADIE_PATH_HEADSET_MONO_TX		0x010740f8
+#define ADIE_PATH_HEADSET_STEREO_TX		0x010740f9
+#define ADIE_PATH_HEADSET_MONO_RX		0x010740fa
+#define ADIE_PATH_HEADSET_STEREO_RX		0x010740fb
+#define ADIE_PATH_SPEAKER_TX			0x010740fc
+#define ADIE_PATH_SPEAKER_RX			0x010740fd
+#define ADIE_PATH_SPEAKER_STEREO_RX		0x01074101
+
+/* Path IDs used for TTY */
+#define ADIE_PATH_TTY_HEADSET_TX		0x010740fe
+#define ADIE_PATH_TTY_HEADSET_RX		0x010740ff
+
+/* Path IDs used by Factory Test Mode. */
+#define ADIE_PATH_FTM_MIC1_TX			0x01074108
+#define ADIE_PATH_FTM_MIC2_TX			0x01074107
+#define ADIE_PATH_FTM_HPH_L_RX			0x01074106
+#define ADIE_PATH_FTM_HPH_R_RX			0x01074104
+#define ADIE_PATH_FTM_EAR_RX			0x01074103
+#define ADIE_PATH_FTM_SPKR_RX			0x01074102
+
+/* Path IDs for Loopback */
+/* Path IDs used for Line in -> AuxPGA -> Line Out Stereo Mode*/
+#define ADIE_PATH_AUXPGA_LINEOUT_STEREO_LB	0x01074100
+/* Line in -> AuxPGA -> LineOut Mono */
+#define ADIE_PATH_AUXPGA_LINEOUT_MONO_LB	0x01073d82
+/* Line in -> AuxPGA -> Stereo Headphone */
+#define ADIE_PATH_AUXPGA_HDPH_STEREO_LB		0x01074109
+/* Line in -> AuxPGA -> Mono Headphone */
+#define ADIE_PATH_AUXPGA_HDPH_MONO_LB		0x01073d85
+/* Line in -> AuxPGA -> Earpiece */
+#define ADIE_PATH_AUXPGA_EAP_LB			0x01073d81
+/* Line in -> AuxPGA -> AuxOut */
+#define ADIE_PATH_AUXPGA_AUXOUT_LB		0x01073d86
+
+/* Concurrency Profiles */
+#define ADIE_PATH_SPKR_STEREO_HDPH_MONO_RX	0x01073d83
+#define ADIE_PATH_SPKR_MONO_HDPH_MONO_RX	0x01073d84
+#define ADIE_PATH_SPKR_MONO_HDPH_STEREO_RX	0x01073d88
+#define ADIE_PATH_SPKR_STEREO_HDPH_STEREO_RX	0x01073d89
+
+/* stages */
+#define ADIE_STAGE_PATH_OFF			0x0050
+#define ADIE_STAGE_DIGITAL_READY		0x0100
+#define ADIE_STAGE_DIGITAL_ANALOG_READY		0x1000
+#define ADIE_STAGE_ANALOG_OFF			0x0750
+#define ADIE_STAGE_DIGITAL_OFF			0x0600
+
+/* path types */
+#define ADIE_PATH_RX		0
+#define ADIE_PATH_TX		1
+#define ADIE_PATH_LOOPBACK	2
+
+/* mute states */
+#define ADIE_MUTE_OFF		0
+#define ADIE_MUTE_ON		1
+
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/dal_audio.h b/arch/arm/mach-msm/qdsp6/audiov2/dal_audio.h
new file mode 100644
index 0000000..52de785
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/dal_audio.h
@@ -0,0 +1,546 @@
+/* Copyright (c) 2009, 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 __DAL_AUDIO_H__
+#define __DAL_AUDIO_H__
+
+#include "../dal.h"
+#include "dal_audio_format.h"
+
+#define AUDIO_DAL_DEVICE 0x02000028
+#define AUDIO_DAL_PORT "DAL_AQ_AUD"
+#define AUDIO_DAL_VERSION	0x00030001
+
+enum {
+	AUDIO_OP_CONTROL = DAL_OP_FIRST_DEVICE_API,
+	AUDIO_OP_DATA,
+	AUDIO_OP_INIT,
+};
+
+/* ---- common audio structures ---- */
+
+/* This flag, if set, indicates that the beginning of the data in the*/
+/* buffer is a synchronization point or key frame, meaning no data */
+/* before it in the stream is required in order to render the stream */
+/* from this point onward. */
+#define ADSP_AUDIO_BUFFER_FLAG_SYNC_POINT        0x01
+
+/* This flag, if set, indicates that the buffer object is using valid */
+/* physical address used to store the media data */
+#define ADSP_AUDIO_BUFFER_FLAG_PHYS_ADDR         0x04
+
+/* This flag, if set, indicates that a media start timestamp has been */
+/* set for a buffer. */
+#define ADSP_AUDIO_BUFFER_FLAG_START_SET         0x08
+
+/* This flag, if set, indicates that a media stop timestamp has been set */
+/* for a buffer. */
+#define ADSP_AUDIO_BUFFER_FLAG_STOP_SET          0x10
+
+/* This flag, if set, indicates that a preroll timestamp has been set */
+/* for a buffer. */
+#define ADSP_AUDIO_BUFFER_FLAG_PREROLL_SET       0x20
+
+/* This flag, if set, indicates that the data in the buffer is a fragment of */
+/* a larger block of data, and will be continued by the data in the next */
+/* buffer to be delivered. */
+#define ADSP_AUDIO_BUFFER_FLAG_CONTINUATION      0x40
+
+struct adsp_audio_buffer {
+	u32 addr;		/* Physical Address of buffer */
+	u32 max_size;		/* Maximum size of buffer */
+	u32 actual_size;	/* Actual size of valid data in the buffer */
+	u32 offset;		/* Offset to the first valid byte */
+	u32 flags;		/* ADSP_AUDIO_BUFFER_FLAGs that has been set */
+	s64 start;		/* Start timestamp, if any */
+	s64 stop;		/* Stop timestamp, if any */
+	s64 preroll;		/* Preroll timestamp, if any */
+} __attribute__ ((packed));
+
+
+
+/* ---- audio commands ---- */
+
+/* Command/event response types */
+#define ADSP_AUDIO_RESPONSE_COMMAND   0
+#define ADSP_AUDIO_RESPONSE_ASYNC     1
+
+struct adsp_command_hdr {
+	u32 size;		/* sizeof(cmd) - sizeof(u32) */
+
+	u32 dest;
+	u32 src;
+	u32 opcode;
+	u32 response_type;
+	u32 seq_number;
+
+	u32 context;		/* opaque to DSP */
+	u32 data;
+	u32 padding;
+} __attribute__ ((packed));
+
+
+#define DOMAIN_APP	0
+#define DOMAIN_MODEM	1
+#define DOMAIN_DSP	2
+
+
+/* adsp audio addresses are (byte order) major, minor, domain */
+#define AUDIO_ADDR(dmn, maj, min) (((maj & 0xff) << 16) \
+		| ((min & 0xff) << 24) | (dmn & 0xff))
+
+/* AAC Encoder modes */
+#define ADSP_AUDIO_ENC_AAC_LC_ONLY_MODE		0
+#define ADSP_AUDIO_ENC_AAC_PLUS_MODE		1
+#define ADSP_AUDIO_ENC_ENHANCED_AAC_PLUS_MODE	2
+
+struct adsp_audio_aac_enc_cfg {
+	u32 bit_rate;		/* bits per second */
+	u32 encoder_mode;	/* ADSP_AUDIO_ENC_* */
+} __attribute__ ((packed));
+
+#define ADSP_AUDIO_ENC_SBC_ALLOCATION_METHOD_LOUNDNESS     0
+#define ADSP_AUDIO_ENC_SBC_ALLOCATION_METHOD_SNR           1
+
+#define ADSP_AUDIO_ENC_SBC_CHANNEL_MODE_MONO                1
+#define ADSP_AUDIO_ENC_SBC_CHANNEL_MODE_STEREO              2
+#define ADSP_AUDIO_ENC_SBC_CHANNEL_MODE_DUAL                8
+#define ADSP_AUDIO_ENC_SBC_CHANNEL_MODE_JOINT_STEREO        9
+
+struct adsp_audio_sbc_encoder_cfg {
+	u32 num_subbands;
+	u32 block_len;
+	u32 channel_mode;
+	u32 allocation_method;
+	u32 bit_rate;
+} __attribute__ ((packed));
+
+/* AMR NB encoder modes */
+#define ADSP_AUDIO_AMR_MR475	0
+#define ADSP_AUDIO_AMR_MR515	1
+#define ADSP_AUDIO_AMR_MMR59	2
+#define ADSP_AUDIO_AMR_MMR67	3
+#define ADSP_AUDIO_AMR_MMR74	4
+#define ADSP_AUDIO_AMR_MMR795	5
+#define ADSP_AUDIO_AMR_MMR102	6
+#define ADSP_AUDIO_AMR_MMR122	7
+
+/* The following are valid AMR NB DTX modes */
+#define ADSP_AUDIO_AMR_DTX_MODE_OFF		0
+#define ADSP_AUDIO_AMR_DTX_MODE_ON_VAD1		1
+#define ADSP_AUDIO_AMR_DTX_MODE_ON_VAD2		2
+#define ADSP_AUDIO_AMR_DTX_MODE_ON_AUTO		3
+
+/* AMR Encoder configuration */
+struct adsp_audio_amr_enc_cfg {
+	u32	mode;		/* ADSP_AUDIO_AMR_MR* */
+	u32	dtx_mode;	/* ADSP_AUDIO_AMR_DTX_MODE* */
+	u32	enable;		/* 1 = enable, 0 = disable */
+} __attribute__ ((packed));
+
+struct adsp_audio_qcelp13k_enc_cfg {
+	u16	min_rate;
+	u16	max_rate;
+} __attribute__ ((packed));
+
+struct adsp_audio_evrc_enc_cfg {
+	u16	min_rate;
+	u16	max_rate;
+} __attribute__ ((packed));
+
+union adsp_audio_codec_config {
+	struct adsp_audio_amr_enc_cfg amr;
+	struct adsp_audio_aac_enc_cfg aac;
+	struct adsp_audio_qcelp13k_enc_cfg qcelp13k;
+	struct adsp_audio_evrc_enc_cfg evrc;
+	struct adsp_audio_sbc_encoder_cfg sbc;
+} __attribute__ ((packed));
+
+
+/* This is the default value. */
+#define ADSP_AUDIO_OPEN_STREAM_MODE_NONE		0x0000
+
+/* This bit, if set, indicates that the AVSync mode is activated. */
+#define ADSP_AUDIO_OPEN_STREAM_MODE_AVSYNC		0x0001
+
+/* This bit, if set, indicates that the Sample Rate/Channel Mode */
+/* Change Notification mode is activated. */
+#define ADSP_AUDIO_OPEN_STREAM_MODE_SR_CM_NOTIFY	0x0002
+
+#define  ADSP_AUDIO_OPEN_STREAM_MODE_ENABLE_SYNC_CLOCK	0x0004
+
+#define ADSP_AUDIO_MAX_DEVICES 1
+
+struct adsp_open_command {
+	struct adsp_command_hdr hdr;
+	u32 device;
+	u32 end_point;
+	u32 stream_context;
+	u32 mode;
+	u32 buf_max_size;
+	union adsp_audio_format format_block;
+	union adsp_audio_codec_config config;
+
+} __attribute__ ((packed));
+
+
+/* --- audio control and stream session ioctls ---- */
+
+/* Opcode to open a device stream session to capture audio */
+#define ADSP_AUDIO_IOCTL_CMD_OPEN_READ			0x0108dd79
+
+/* Opcode to open a device stream session to render audio */
+#define ADSP_AUDIO_IOCTL_CMD_OPEN_WRITE			0x0108dd7a
+
+/* Opcode to open a device session, must open a device */
+#define ADSP_AUDIO_IOCTL_CMD_OPEN_DEVICE		0x0108dd7b
+
+/* Close an existing stream or device */
+#define ADSP_AUDIO_IOCTL_CMD_CLOSE			0x0108d8bc
+
+
+
+/* A device switch requires three IOCTL */
+/* commands in the following sequence: PREPARE, STANDBY, COMMIT */
+
+/* adsp_audio_device_switch_command structure is needed for */
+/* DEVICE_SWITCH_PREPARE */
+
+/* Device switch protocol step #1. Pause old device and */
+/* generate silence for the old device. */
+#define ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_PREPARE	0x010815c4
+
+/* Device switch protocol step #2. Release old device, */
+/* create new device and generate silence for the new device. */
+
+/* When client receives ack for this IOCTL, the client can */
+/* start sending IOCTL commands to configure, calibrate and */
+/* change filter settings on the new device. */
+#define ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_STANDBY	0x010815c5
+
+/* Device switch protocol step #3. Start normal operations on new device */
+#define ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_COMMIT	0x01075ee7
+
+struct adsp_device_switch_command {
+	struct adsp_command_hdr hdr;
+	u32 old_device;
+	u32 new_device;
+	u8 device_class; /* 0 = i.rx, 1 = i.tx, 2 = e.rx, 3 = e.tx */
+	u8 device_type; /* 0 = rx, 1 = tx, 2 = both */
+} __attribute__ ((packed));
+
+
+
+/* --- audio control session ioctls ---- */
+
+#define ADSP_PATH_RX	0
+#define ADSP_PATH_TX	1
+#define ADSP_PATH_BOTH	2
+
+/* These commands will affect a logical device and all its associated */
+/* streams. */
+
+
+/* Set device volume. */
+#define ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_VOL		0x0107605c
+
+struct adsp_set_dev_volume_command {
+	struct adsp_command_hdr hdr;
+	u32 device_id;
+	u32 path; /* 0 = rx, 1 = tx, 2 = both */
+	s32 volume;
+} __attribute__ ((packed));
+
+/* Set Device stereo volume. This command has data payload, */
+/* struct adsp_audio_set_dev_stereo_volume_command. */
+#define ADSP_AUDIO_IOCTL_SET_DEVICE_STEREO_VOL		0x0108df3e
+
+/* Set L, R cross channel gain for a Device. This command has */
+/* data payload, struct adsp_audio_set_dev_x_chan_gain_command. */
+#define ADSP_AUDIO_IOCTL_SET_DEVICE_XCHAN_GAIN		0x0108df40
+
+/* Set device mute state. */
+#define ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_MUTE		0x0107605f
+
+struct adsp_set_dev_mute_command {
+	struct adsp_command_hdr hdr;
+	u32 device_id;
+	u32 path; /* 0 = rx, 1 = tx, 2 = both */
+	u32 mute; /* 1 = mute */
+} __attribute__ ((packed));
+
+/* Configure Equalizer for a device. */
+/* This command has payload struct adsp_audio_set_dev_equalizer_command. */
+#define ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_EQ_CONFIG	0x0108b10e
+
+/* Set configuration data for an algorithm aspect of a device. */
+/* This command has payload struct adsp_audio_set_dev_cfg_command. */
+#define ADSP_AUDIO_IOCTL_SET_DEVICE_CONFIG		0x0108b6cb
+
+struct adsp_set_dev_cfg_command {
+	struct adsp_command_hdr hdr;
+	u32 device_id;
+	u32 block_id;
+	u32 interface_id;
+	u32 phys_addr;
+	u32 phys_size;
+	u32 phys_used;
+} __attribute__ ((packed));
+
+/* Set configuration data for all interfaces of a device. */
+#define ADSP_AUDIO_IOCTL_SET_DEVICE_CONFIG_TABLE	0x0108b6bf
+
+struct adsp_set_dev_cfg_table_command {
+	struct adsp_command_hdr hdr;
+	u32 device_id;
+	u32 phys_addr;
+	u32 phys_size;
+	u32 phys_used;
+} __attribute__ ((packed));
+
+/* ---- audio stream data commands ---- */
+
+#define ADSP_AUDIO_IOCTL_CMD_DATA_TX			0x0108dd7f
+#define ADSP_AUDIO_IOCTL_CMD_DATA_RX			0x0108dd80
+
+struct adsp_buffer_command {
+	struct adsp_command_hdr hdr;
+	struct adsp_audio_buffer buffer;
+} __attribute__ ((packed));
+
+
+
+/* ---- audio stream ioctls (only affect a single stream in a session) ---- */
+
+/* Stop stream for audio device. */
+#define ADSP_AUDIO_IOCTL_CMD_STREAM_STOP		0x01075c54
+
+/* End of stream reached. Client will not send any more data. */
+#define ADSP_AUDIO_IOCTL_CMD_STREAM_EOS			0x0108b150
+
+/* Do sample slipping/stuffing on AAC outputs. The payload of */
+/* this command is struct adsp_audio_slip_sample_command. */
+#define ADSP_AUDIO_IOCTL_CMD_STREAM_SLIPSAMPLE		0x0108d40e
+
+/* Set stream volume. */
+/* This command has data payload, struct adsp_audio_set_volume_command. */
+#define ADSP_AUDIO_IOCTL_CMD_SET_STREAM_VOL		0x0108c0de
+
+/* Set stream stereo volume. This command has data payload, */
+/* struct adsp_audio_set_stereo_volume_command. */
+#define ADSP_AUDIO_IOCTL_SET_STREAM_STEREO_VOL		0x0108dd7c
+
+/* Set L, R cross channel gain for a Stream. This command has */
+/* data payload, struct adsp_audio_set_x_chan_gain_command. */
+#define ADSP_AUDIO_IOCTL_SET_STREAM_XCHAN_GAIN		0x0108dd7d
+
+/* Set stream mute state. */
+/* This command has data payload, struct adsp_audio_set_stream_mute. */
+#define ADSP_AUDIO_IOCTL_CMD_SET_STREAM_MUTE		0x0108c0df
+
+/* Reconfigure bit rate information. This command has data */
+/* payload, struct adsp_audio_set_bit_rate_command */
+#define ADSP_AUDIO_IOCTL_SET_STREAM_BITRATE		0x0108ccf1
+
+/* Set Channel Mapping. This command has data payload, struct */
+/* This command has data payload struct adsp_audio_set_channel_map_command. */
+#define ADSP_AUDIO_IOCTL_SET_STREAM_CHANNELMAP		0x0108d32a
+
+/* Enable/disable AACPlus SBR. */
+/* This command has data payload struct adsp_audio_set_sbr_command */
+#define ADSP_AUDIO_IOCTL_SET_STREAM_SBR			0x0108d416
+
+/* Enable/disable WMA Pro Chex and Fex. This command has data payload */
+/* struct adsp_audio_stream_set_wma_command. */
+#define ADSP_AUDIO_IOCTL_SET_STREAM_WMAPRO		0x0108d417
+
+
+/* ---- audio session ioctls (affect all streams in a session) --- */
+
+/* Start stream for audio device. */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_START		0x010815c6
+
+/* Stop all stream(s) for audio session as indicated by major id. */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_STOP		0x0108dd7e
+
+/* Pause the data flow for a session as indicated by major id. */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_PAUSE		0x01075ee8
+
+/* Resume the data flow for a session as indicated by major id. */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_RESUME		0x01075ee9
+
+/* Drop any unprocessed data buffers for a session as indicated by major id. */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_FLUSH		0x01075eea
+
+/* Start Stream DTMF tone */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_DTMF_START		0x0108c0dd
+
+/* Stop Stream DTMF tone */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_DTMF_STOP		0x01087554
+
+/* Set Session volume. */
+/* This command has data payload, struct adsp_audio_set_volume_command. */
+#define ADSP_AUDIO_IOCTL_SET_SESSION_VOL		0x0108d8bd
+
+/* Set session stereo volume. This command has data payload, */
+/* struct adsp_audio_set_stereo_volume_command. */
+#define ADSP_AUDIO_IOCTL_SET_SESSION_STEREO_VOL		0x0108df3d
+
+/* Set L, R cross channel gain for a session. This command has */
+/* data payload, struct adsp_audio_set_x_chan_gain_command. */
+#define ADSP_AUDIO_IOCTL_SET_SESSION_XCHAN_GAIN		0x0108df3f
+
+/* Set Session mute state. */
+/* This command has data payload, struct adsp_audio_set_mute_command. */
+#define ADSP_AUDIO_IOCTL_SET_SESSION_MUTE		0x0108d8be
+
+/* Configure Equalizer for a stream. */
+/* This command has payload struct adsp_audio_set_equalizer_command. */
+#define ADSP_AUDIO_IOCTL_SET_SESSION_EQ_CONFIG		0x0108c0e0
+
+/* Set Audio Video sync information. */
+/* This command has data payload, struct adsp_audio_set_av_sync_command. */
+#define ADSP_AUDIO_IOCTL_SET_SESSION_AVSYNC		0x0108d1e2
+
+/* Get Audio Media Session time. */
+/* This command returns the audioTime in adsp_audio_unsigned64_event */
+#define ADSP_AUDIO_IOCTL_CMD_GET_AUDIO_TIME		0x0108c26c
+
+
+/* these command structures are used for both STREAM and SESSION ioctls */
+
+struct adsp_set_volume_command {
+	struct adsp_command_hdr hdr;
+	s32 volume;
+} __attribute__ ((packed));
+
+struct adsp_set_mute_command {
+	struct adsp_command_hdr hdr;
+	u32 mute; /* 1 == mute */
+} __attribute__ ((packed));
+
+
+
+/* ---- audio events ---- */
+
+/* All IOCTL commands generate an event with the IOCTL opcode as the */
+/* event id after the IOCTL command has been executed. */
+
+/* This event is generated after a media stream session is opened. */
+#define ADSP_AUDIO_EVT_STATUS_OPEN				0x0108c0d6
+
+/* This event is generated after a media stream  session is closed. */
+#define ADSP_AUDIO_EVT_STATUS_CLOSE				0x0108c0d7
+
+/* Asyncronous buffer consumption. This event is generated after a */
+/* recived  buffer is consumed during rendering or filled during */
+/* capture opeartion. */
+#define ADSP_AUDIO_EVT_STATUS_BUF_DONE				0x0108c0d8
+
+/* This event is generated when rendering operation is starving for */
+/* data. In order to avoid audio loss at the end of a plauback, the */
+/* client should wait for this event before issuing the close command. */
+#define ADSP_AUDIO_EVT_STATUS_BUF_UNDERRUN			0x0108c0d9
+
+/* This event is generated during capture operation when there are no */
+/* buffers available to copy the captured audio data */
+#define ADSP_AUDIO_EVT_STATUS_BUF_OVERFLOW			0x0108c0da
+
+/* This asynchronous event is generated as a result of an input */
+/* sample rate change and/or channel mode change detected by the */
+/* decoder. The event payload data is an array of 2 uint32 */
+/* values containing the sample rate in Hz and channel mode. */
+#define ADSP_AUDIO_EVT_SR_CM_CHANGE				0x0108d329
+
+struct adsp_event_hdr {
+	u32 evt_handle;		/* DAL common header */
+	u32 evt_cookie;
+	u32 evt_length;
+
+	u32 dest;
+	u32 src;
+
+	u32 event_id;
+	u32 response_type;
+	u32 seq_number;
+
+	u32 context;		/* opaque to DSP */
+	u32 data;
+
+	u32 status;
+} __attribute__ ((packed));
+
+struct adsp_buffer_event {
+	struct adsp_event_hdr hdr;
+	struct adsp_audio_buffer buffer;
+} __attribute__ ((packed));
+
+
+/* ---- audio device IDs ---- */
+
+/* Device direction Rx/Tx flag */
+#define ADSP_AUDIO_RX_DEVICE		0x00
+#define ADSP_AUDIO_TX_DEVICE		0x01
+
+#define ADSP_AUDIO_DEVICE_ID_DEFAULT		0x1081679
+
+/* Default RX or TX device */
+
+#define ADSP_AUDIO_DEVICE_ID_HANDSET_MIC	0x107ac8d
+#define ADSP_AUDIO_DEVICE_ID_HANDSET_DUAL_MIC		0x108f9c3
+#define ADSP_AUDIO_DEVICE_ID_HEADSET_MIC	0x1081510
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MIC	0x1081512
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_DUAL_MIC	0x108f9c5
+#define ADSP_AUDIO_DEVICE_ID_BT_SCO_MIC		0x1081518
+#define ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_MIC	0x108151b
+#define ADSP_AUDIO_DEVICE_ID_I2S_MIC		0x1089bf3
+
+/* Special loopback pseudo device to be paired with an RX device */
+/* with usage ADSP_AUDIO_DEVICE_USAGE_MIXED_PCM_LOOPBACK */
+#define ADSP_AUDIO_DEVICE_ID_MIXED_PCM_LOOPBACK_TX	0x1089bf2
+
+/* Sink (RX) devices */
+#define ADSP_AUDIO_DEVICE_ID_HANDSET_SPKR			0x107ac88
+#define ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_MONO			0x1081511
+#define ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_STEREO		0x107ac8a
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO			0x1081513
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_MONO_HEADSET     0x108c508
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_STEREO_HEADSET   0x108c894
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO			0x1081514
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_MONO_HEADSET   0x108c895
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_STEREO_HEADSET	0x108c509
+#define ADSP_AUDIO_DEVICE_ID_BT_SCO_SPKR			0x1081519
+#define ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_SPKR			0x108151c
+#define ADSP_AUDIO_DEVICE_ID_I2S_SPKR				0x1089bf4
+#define ADSP_AUDIO_DEVICE_ID_NULL_SINK				0x108e512
+
+/* BT A2DP playback device. */
+/* This device must be paired with */
+/* ADSP_AUDIO_DEVICE_ID_MIXED_PCM_LOOPBACK_TX using  */
+/* ADSP_AUDIO_DEVICE_USAGE_MIXED_PCM_LOOPBACK mode */
+#define ADSP_AUDIO_DEVICE_ID_BT_A2DP_SPKR	0x108151a
+
+/* Voice Destination identifier - specifically used for */
+/* controlling Voice module from the Device Control Session */
+#define ADSP_AUDIO_DEVICE_ID_VOICE		0x0108df3c
+
+/*  Audio device usage types. */
+/*  This is a bit mask to determine which topology to use in the */
+/* device session */
+#define ADSP_AUDIO_DEVICE_CONTEXT_VOICE			0x01
+#define ADSP_AUDIO_DEVICE_CONTEXT_PLAYBACK		0x02
+#define ADSP_AUDIO_DEVICE_CONTEXT_MIXED_RECORD		0x10
+#define ADSP_AUDIO_DEVICE_CONTEXT_RECORD		0x20
+#define ADSP_AUDIO_DEVICE_CONTEXT_PCM_LOOPBACK		0x40
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/dal_audio_format.h b/arch/arm/mach-msm/qdsp6/audiov2/dal_audio_format.h
new file mode 100644
index 0000000..348aad1
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/dal_audio_format.h
@@ -0,0 +1,284 @@
+/* Copyright (c) 2009, 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 __ADSP_AUDIO_MEDIA_FORMAT_H
+#define __ADSP_AUDIO_MEDIA_FORMAT_H
+
+/* Supported audio media formats */
+
+/* format block in shmem */
+#define ADSP_AUDIO_FORMAT_SHAREDMEMORY	0x01091a78
+
+/* adsp_audio_format_raw_pcm type */
+#define ADSP_AUDIO_FORMAT_PCM		0x0103d2fd
+
+/* adsp_audio_format_raw_pcm type */
+#define ADSP_AUDIO_FORMAT_DTMF		0x01087725
+
+/* adsp_audio_format_adpcm type */
+#define ADSP_AUDIO_FORMAT_ADPCM		0x0103d2ff
+
+/* Yamaha PCM format */
+#define ADSP_AUDIO_FORMAT_YADPCM	0x0108dc07
+
+/* ISO/IEC 11172 */
+#define ADSP_AUDIO_FORMAT_MP3		0x0103d308
+
+/* ISO/IEC 14496 */
+#define ADSP_AUDIO_FORMAT_MPEG4_AAC	0x010422f1
+
+/* AMR-NB audio in FS format */
+#define ADSP_AUDIO_FORMAT_AMRNB_FS	0x0105c16c
+
+/* AMR-WB audio in FS format */
+#define ADSP_AUDIO_FORMAT_AMRWB_FS	0x0105c16e
+
+/* QCELP 13k, IS733 */
+#define ADSP_AUDIO_FORMAT_V13K_FS	0x01080b8a
+
+/* EVRC   8k, IS127 */
+#define ADSP_AUDIO_FORMAT_EVRC_FS	0x01080b89
+
+/* EVRC-B   8k, 4GV */
+#define ADSP_AUDIO_FORMAT_EVRCB_FS	0x0108f2a3
+
+/* MIDI command stream */
+#define ADSP_AUDIO_FORMAT_MIDI		0x0103d300
+
+/* A2DP SBC stream */
+#define ADSP_AUDIO_FORMAT_SBC		0x0108c4d8
+
+/* Version 10 Professional */
+#define ADSP_AUDIO_FORMAT_WMA_V10PRO	0x0108aa92
+
+/* Version 9 Starndard */
+#define ADSP_AUDIO_FORMAT_WMA_V9	0x0108d430
+
+/* AMR WideBand Plus */
+#define ADSP_AUDIO_FORMAT_AMR_WB_PLUS   0x0108f3da
+
+/* AC3 Decoder */
+#define ADSP_AUDIO_FORMAT_AC3_DECODER   0x0108d5f9
+
+/* Not yet supported audio media formats */
+
+/* ISO/IEC 13818 */
+#define ADSP_AUDIO_FORMAT_MPEG2_AAC	0x0103d309
+
+/* 3GPP TS 26.101 Sec 4.0 */
+#define ADSP_AUDIO_FORMAT_AMRNB_IF1	0x0103d305
+
+/* 3GPP TS 26.101 Annex A */
+#define ADSP_AUDIO_FORMAT_AMRNB_IF2	0x01057b31
+
+/* 3GPP TS 26.201 */
+#define ADSP_AUDIO_FORMAT_AMRWB_IF1	0x0103d306
+
+/* 3GPP TS 26.201 */
+#define ADSP_AUDIO_FORMAT_AMRWB_IF2	0x0105c16d
+
+/* G.711 */
+#define ADSP_AUDIO_FORMAT_G711		0x0106201d
+
+/* QCELP  8k, IS96A */
+#define ADSP_AUDIO_FORMAT_V8K_FS	0x01081d29
+
+/* Version 1 codec */
+#define ADSP_AUDIO_FORMAT_WMA_V1	0x01055b2b
+
+/* Version 2, 7 & 8 codec */
+#define ADSP_AUDIO_FORMAT_WMA_V8	0x01055b2c
+
+/* Version 9 Professional codec */
+#define ADSP_AUDIO_FORMAT_WMA_V9PRO	0x01055b2d
+
+/* Version 9 Voice codec */
+#define ADSP_AUDIO_FORMAT_WMA_SP1	0x01055b2e
+
+/* Version 9 Lossless codec */
+#define ADSP_AUDIO_FORMAT_WMA_LOSSLESS	0x01055b2f
+
+/* Real Media content, low-bitrate */
+#define ADSP_AUDIO_FORMAT_RA_SIPR	0x01042a0f
+
+/* Real Media content */
+#define ADSP_AUDIO_FORMAT_RA_COOK	0x01042a0e
+
+
+/* For all of the audio formats, unless specified otherwise, */
+/* the following apply: */
+/* Format block bits are arranged in bytes and words in little-endian */
+/* order, i.e., least-significant bit first and least-significant */
+/* byte first. */
+
+
+/* AAC Format Block. */
+
+/* AAC format block consist of a format identifier followed by */
+/* AudioSpecificConfig formatted according to ISO/IEC 14496-3 */
+
+/* The following AAC format identifiers are supported */
+#define ADSP_AUDIO_AAC_ADTS		0x010619cf
+#define ADSP_AUDIO_AAC_MPEG4_ADTS	0x010619d0
+#define ADSP_AUDIO_AAC_LOAS		0x010619d1
+#define ADSP_AUDIO_AAC_ADIF		0x010619d2
+#define ADSP_AUDIO_AAC_RAW		0x010619d3
+#define ADSP_AUDIO_AAC_FRAMED_RAW	0x0108c1fb
+
+struct adsp_audio_no_payload_format {
+	/* Media Format Code (must always be first element) */
+	u32 format;
+	/* no payload for this format type */
+} __attribute__ ((packed));
+
+/* Maxmum number of bytes allowed in a format block */
+#define ADSP_AUDIO_FORMAT_DATA_MAX 16
+
+/* For convenience, to be used as a standard format block */
+/* for various media types that don't need a unique format block */
+/* ie. PCM, DTMF, etc. */
+struct adsp_audio_standard_format {
+	/* Media Format Code (must always be first element) */
+	u32 format;
+
+	/* payload */
+	u16 channels;
+	u16 bits_per_sample;
+	u32 sampling_rate;
+	u8 is_signed;
+	u8 is_interleaved;
+} __attribute__ ((packed));
+
+/* ADPCM format block */
+struct adsp_audio_adpcm_format {
+	/* Media Format Code (must always be first element) */
+	u32 format;
+
+	/* payload */
+	u16 channels;
+	u16 bits_per_sample;
+	u32 sampling_rate;
+	u8 is_signed;
+	u8 is_interleaved;
+	u32 block_size;
+} __attribute__ ((packed));
+
+/* MIDI format block */
+struct adsp_audio_midi_format {
+	/* Media Format Code (must always be first element) */
+	u32 format;
+
+	/* payload */
+	u32 sampling_rate;
+	u16 channels;
+	u16 mode;
+} __attribute__ ((packed));
+
+#define ADSP_AUDIO_COMPANDING_ALAW	0x10619cd
+#define ADSP_AUDIO_COMPANDING_MLAW	0x10619ce
+
+/* G711 format block */
+struct adsp_audio_g711_format {
+	/* Media Format Code (must always be first element) */
+	u32 format;
+
+	/* payload */
+	u32 companding;
+} __attribute__ ((packed));
+
+
+struct adsp_audio_wma_pro_format {
+	/* Media Format Code (must always be first element) */
+	u32 format;
+
+	/* payload */
+	u16 format_tag;
+	u16 channels;
+	u32 samples_per_sec;
+	u32 avg_bytes_per_sec;
+	u16 block_align;
+	u16 valid_bits_per_sample;
+	u32 channel_mask;
+	u16 encode_opt;
+	u16 advanced_encode_opt;
+	u32 advanced_encode_opt2;
+	u32 drc_peak_reference;
+	u32 drc_peak_target;
+	u32 drc_average_reference;
+	u32 drc_average_target;
+} __attribute__ ((packed));
+
+struct adsp_audio_amrwb_plus_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* payload */
+	u32		size;
+	u32		version;
+	u32		channels;
+	u32		amr_band_mode;
+	u32		amr_dtx_mode;
+	u32		amr_frame_format;
+	u32		amr_isf_index;
+} __attribute__ ((packed));
+
+/* Binary Byte Stream Format */
+/* Binary format type that defines a byte stream, */
+/* can be used to specify any format (ie. AAC) */
+struct adsp_audio_binary_format {
+	/* Media Format Code (must always be first element) */
+	u32 format;
+
+	/* payload */
+	/* number of bytes set in byte stream */
+	u32 num_bytes;
+	/* Byte stream binary data */
+	u8 data[ADSP_AUDIO_FORMAT_DATA_MAX];
+} __attribute__ ((packed));
+
+struct adsp_audio_shared_memory_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* Number of bytes in shared memory */
+	u32		len;
+	/* Phyisical address to data in shared memory */
+	u32		address;
+} __attribute__ ((packed));
+
+
+/* Union of all format types */
+union adsp_audio_format {
+	/* Basic format block with no payload */
+	struct adsp_audio_no_payload_format	no_payload;
+	/* Generic format block PCM, DTMF */
+	struct adsp_audio_standard_format	standard;
+	/* ADPCM format block */
+	struct adsp_audio_adpcm_format		adpcm;
+	/* MIDI format block */
+	struct adsp_audio_midi_format		midi;
+	/* G711 format block */
+	struct adsp_audio_g711_format		g711;
+	/* WmaPro format block */
+	struct adsp_audio_wma_pro_format	wma_pro;
+	/* WmaPro format block */
+	struct adsp_audio_amrwb_plus_format	amrwb_plus;
+	/* binary (byte stream) format block, used for AAC */
+	struct adsp_audio_binary_format		binary;
+	/* format block in shared memory */
+	struct adsp_audio_shared_memory_format	shared_mem;
+};
+
+#endif
+
+
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/dal_voice.h b/arch/arm/mach-msm/qdsp6/audiov2/dal_voice.h
new file mode 100644
index 0000000..62c1122
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/dal_voice.h
@@ -0,0 +1,69 @@
+/* Copyright (c) 2009, 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 __DAL_VOICE_H__
+#define __DAL_VOICE_H__
+
+#define VOICE_DAL_DEVICE 0x02000075
+#define VOICE_DAL_PORT "DAL_AM_AUD"
+#define VOICE_DAL_VERSION 0x00010000
+
+#define APR_PKTV1_TYPE_EVENT_V 0
+#define APR_UNDEFINED -1
+#define APR_PKTV1_TYPE_MASK 0x00000010
+#define APR_PKTV1_TYPE_SHFT 4
+
+#define APR_SET_BITMASK(mask, shift, value) \
+	(((value) << (shift)) & (mask))
+
+#define APR_SET_FIELD(field, value) \
+	APR_SET_BITMASK((field##_MASK), (field##_SHFT), (value))
+
+
+enum {
+	VOICE_OP_INIT = DAL_OP_FIRST_DEVICE_API,
+	VOICE_OP_CONTROL,
+};
+
+struct apr_command_pkt {
+	uint32_t size;
+	uint32_t header;
+	uint16_t reserved1;
+	uint16_t src_addr;
+	uint16_t dst_addr;
+	uint16_t ret_addr;
+	uint32_t src_token;
+	uint32_t dst_token;
+	uint32_t ret_token;
+	uint32_t context;
+	uint32_t opcode;
+} __attribute__ ((packed));
+
+
+#define APR_IBASIC_RSP_RESULT 0x00010000
+
+#define APR_OP_CMD_CREATE 0x0001001B
+
+#define APR_OP_CMD_DESTROY 0x0001001C
+
+#define VOICE_OP_CMD_BRINGUP 0x0001001E
+
+#define VOICE_OP_CMD_TEARDOWN 0x0001001F
+
+#define VOICE_OP_CMD_SET_NETWORK 0x0001001D
+
+#define VOICE_OP_CMD_STREAM_SETUP 0x00010027
+
+#define VOICE_OP_CMD_STREAM_TEARDOWN 0x00010028
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/evrc_in.c b/arch/arm/mach-msm/qdsp6/audiov2/evrc_in.c
new file mode 100644
index 0000000..88f19b7
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/evrc_in.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ * Copyright (c) 2009, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio_qcp.h>
+#include <mach/msm_qdsp6_audiov2.h>
+#include "dal_audio.h"
+#include "dal_audio_format.h"
+#include <mach/debug_mm.h>
+
+
+struct evrc {
+	struct mutex lock;
+	struct msm_audio_evrc_enc_config cfg;
+	struct msm_audio_stream_config str_cfg;
+	struct audio_client *audio_client;
+};
+
+
+static long q6_evrc_in_ioctl(struct file *file, unsigned int cmd,
+				unsigned long arg)
+{
+	struct evrc *evrc = file->private_data;
+	struct adsp_open_command rpc;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	mutex_lock(&evrc->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		if (evrc->audio_client) {
+			rc = -EBUSY;
+			break;
+		} else {
+			evrc->audio_client = q6audio_open(AUDIO_FLAG_READ,
+						evrc->str_cfg.buffer_size);
+
+			if (!evrc->audio_client) {
+				kfree(evrc);
+				rc = -ENOMEM;
+				break;
+			}
+		}
+
+		tx_clk_freq = 8000;
+
+		memset(&rpc, 0, sizeof(rpc));
+
+		rpc.format_block.standard.format = ADSP_AUDIO_FORMAT_EVRC_FS;
+		rpc.format_block.standard.channels = 1;
+		rpc.format_block.standard.bits_per_sample = 16;
+		rpc.format_block.standard.sampling_rate = 8000;
+		rpc.format_block.standard.is_signed = 1;
+		rpc.format_block.standard.is_interleaved = 0;
+
+		rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_READ;
+		rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+		rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD;
+		rpc.buf_max_size = evrc->str_cfg.buffer_size;
+		rpc.config.evrc.min_rate = evrc->cfg.min_bit_rate;
+		rpc.config.evrc.max_rate = evrc->cfg.max_bit_rate;
+
+		q6audio_start(evrc->audio_client, &rpc, sizeof(rpc));
+		break;
+	case AUDIO_STOP:
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_VOLUME:
+		break;
+	case AUDIO_GET_STREAM_CONFIG:
+		if (copy_to_user((void *)arg, &evrc->str_cfg,
+				sizeof(struct msm_audio_stream_config)))
+			rc = -EFAULT;
+		break;
+	case AUDIO_SET_STREAM_CONFIG:
+		if (copy_from_user(&evrc->str_cfg, (void *)arg,
+			sizeof(struct msm_audio_stream_config))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		if (evrc->str_cfg.buffer_size < 23) {
+			pr_err("[%s:%s] Buffer size too small\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+			break;
+		}
+
+		if (evrc->str_cfg.buffer_count != 2)
+			pr_info("[%s:%s] Buffer count set to 2\n", __MM_FILE__,
+					__func__);
+		break;
+	case AUDIO_SET_EVRC_ENC_CONFIG:
+		if (copy_from_user(&evrc->cfg, (void *) arg,
+				 sizeof(struct msm_audio_evrc_enc_config)))
+			rc = -EFAULT;
+
+		if (evrc->cfg.min_bit_rate > 4 || evrc->cfg.min_bit_rate < 1) {
+			pr_err("[%s:%s] invalid min bitrate\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+		}
+		if (evrc->cfg.max_bit_rate > 4 || evrc->cfg.max_bit_rate < 1) {
+			pr_err("[%s:%s] invalid max bitrate\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+		}
+		break;
+	case AUDIO_GET_EVRC_ENC_CONFIG:
+		if (copy_to_user((void *) arg, &evrc->cfg,
+				 sizeof(struct msm_audio_evrc_enc_config)))
+			rc = -EFAULT;
+		break;
+
+	default:
+		rc = -EINVAL;
+	}
+
+	mutex_unlock(&evrc->lock);
+	return rc;
+}
+
+static int q6_evrc_in_open(struct inode *inode, struct file *file)
+{
+	struct evrc *evrc;
+	evrc = kmalloc(sizeof(struct evrc), GFP_KERNEL);
+	if (evrc == NULL) {
+		pr_err("[%s:%s] Could not allocate memory for evrc driver\n",
+				__MM_FILE__, __func__);
+		return -ENOMEM;
+	}
+
+	mutex_init(&evrc->lock);
+	file->private_data = evrc;
+	evrc->audio_client = NULL;
+	evrc->str_cfg.buffer_size = 23;
+	evrc->str_cfg.buffer_count = 2;
+	evrc->cfg.cdma_rate = CDMA_RATE_FULL;
+	evrc->cfg.min_bit_rate = 1;
+	evrc->cfg.max_bit_rate = 4;
+
+	return 0;
+}
+
+static ssize_t q6_evrc_in_read(struct file *file, char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	const char __user *start = buf;
+	struct evrc *evrc = file->private_data;
+	int xfer = 0;
+	int res;
+
+	mutex_lock(&evrc->lock);
+	ac = evrc->audio_client;
+	if (!ac) {
+		res = -ENODEV;
+		goto fail;
+	}
+	while (count > xfer) {
+		ab = ac->buf + ac->cpu_buf;
+
+		if (ab->used)
+			wait_event(ac->wait, (ab->used == 0));
+
+		xfer = ab->actual_size;
+
+		if (copy_to_user(buf, ab->data, xfer)) {
+			res = -EFAULT;
+			goto fail;
+		}
+
+		buf += xfer;
+		count -= xfer;
+
+		ab->used = 1;
+		q6audio_read(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+
+	res = buf - start;
+
+fail:
+	mutex_unlock(&evrc->lock);
+
+	return res;
+}
+
+static int q6_evrc_in_release(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	struct evrc *evrc = file->private_data;
+
+	mutex_lock(&evrc->lock);
+	if (evrc->audio_client)
+		rc = q6audio_close(evrc->audio_client);
+	mutex_unlock(&evrc->lock);
+	kfree(evrc);
+	return rc;
+}
+
+static const struct file_operations q6_evrc_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_evrc_in_open,
+	.read		= q6_evrc_in_read,
+	.release	= q6_evrc_in_release,
+	.unlocked_ioctl	= q6_evrc_in_ioctl,
+};
+
+struct miscdevice q6_evrc_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_evrc_in",
+	.fops	= &q6_evrc_in_fops,
+};
+
+static int __init q6_evrc_in_init(void)
+{
+	return misc_register(&q6_evrc_in_misc);
+}
+
+device_initcall(q6_evrc_in_init);
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/mp3.c b/arch/arm/mach-msm/qdsp6/audiov2/mp3.c
new file mode 100644
index 0000000..0781eda
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/mp3.c
@@ -0,0 +1,205 @@
+/* arch/arm/mach-msm/qdsp6/audiov2/mp3.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ * Copyright (c) 2009, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio.h>
+
+#include <mach/msm_qdsp6_audiov2.h>
+#include "dal_audio.h"
+#include "dal_audio_format.h"
+
+#define BUFSZ (8192)
+#define DMASZ (BUFSZ * 2)
+
+struct mp3 {
+	struct mutex lock;
+	struct audio_client *ac;
+	struct msm_audio_config cfg;
+};
+
+static long mp3_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct mp3 *mp3 = file->private_data;
+	struct adsp_open_command rpc;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	mutex_lock(&mp3->lock);
+	switch (cmd) {
+	case AUDIO_SET_VOLUME:
+		break;
+	case AUDIO_START:
+		memset(&rpc, 0, sizeof(rpc));
+		rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_WRITE;
+		rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_PLAYBACK;
+		rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+		rpc.format_block.standard.format = ADSP_AUDIO_FORMAT_MP3;
+		rpc.format_block.standard.channels = mp3->cfg.channel_count;
+		rpc.format_block.standard.bits_per_sample = 16;
+		rpc.format_block.standard.sampling_rate = mp3->cfg.sample_rate;
+		rpc.format_block.standard.is_signed = 1;
+		rpc.format_block.standard.is_interleaved = 0;
+		rpc.buf_max_size = BUFSZ;
+		q6audio_start(mp3->ac, (void *) &rpc, sizeof(rpc));
+		break;
+	case AUDIO_STOP:
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_CONFIG:
+		if (copy_from_user(&mp3->cfg, (void *) arg,
+			sizeof(struct msm_audio_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (mp3->cfg.channel_count < 1 || mp3->cfg.channel_count > 2) {
+			rc = -EINVAL;
+			break;
+		}
+		break;
+	case AUDIO_GET_CONFIG:
+		if (copy_to_user((void *) arg, &mp3->cfg,
+			sizeof(struct msm_audio_config))) {
+			rc = -EFAULT;
+		}
+		break;
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&mp3->lock);
+	return rc;
+}
+
+static int mp3_open(struct inode *inode, struct file *file)
+{
+
+	struct mp3 *mp3;
+	mp3 = kzalloc(sizeof(struct mp3), GFP_KERNEL);
+
+	if (!mp3)
+		return -ENOMEM;
+
+	mutex_init(&mp3->lock);
+	file->private_data = mp3;
+	mp3->ac = q6audio_open(AUDIO_FLAG_WRITE, BUFSZ);
+	if (!mp3->ac) {
+		kfree(mp3);
+		return -ENOMEM;
+	}
+	mp3->cfg.channel_count = 2;
+	mp3->cfg.buffer_count = 2;
+	mp3->cfg.buffer_size = BUFSZ;
+	mp3->cfg.unused[0] = 0;
+	mp3->cfg.unused[1] = 0;
+	mp3->cfg.unused[2] = 0;
+	mp3->cfg.sample_rate = 48000;
+
+	return 0;
+}
+
+static ssize_t mp3_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct mp3 *mp3 = file->private_data;
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	const char __user *start = buf;
+	int xfer;
+
+	if (!mp3->ac)
+		mp3_ioctl(file, AUDIO_START, 0);
+
+	ac = mp3->ac;
+	if (!ac)
+		return -ENODEV;
+
+	while (count > 0) {
+		ab = ac->buf + ac->cpu_buf;
+
+		if (ab->used)
+			wait_event(ac->wait, (ab->used == 0));
+
+		xfer = count;
+		if (xfer > ab->size)
+			xfer = ab->size;
+
+		if (copy_from_user(ab->data, buf, xfer))
+			return -EFAULT;
+
+		buf += xfer;
+		count -= xfer;
+
+		ab->used = xfer;
+		q6audio_write(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+
+	return buf - start;
+}
+
+static int mp3_fsync(struct file *f, int datasync)
+{
+	struct mp3 *mp3 = f->private_data;
+	if (mp3->ac)
+		return q6audio_async(mp3->ac);
+	return -ENODEV;
+}
+
+static int mp3_release(struct inode *inode, struct file *file)
+{
+	struct mp3 *mp3 = file->private_data;
+	if (mp3->ac)
+		q6audio_close(mp3->ac);
+	kfree(mp3);
+	return 0;
+}
+
+static const struct file_operations mp3_fops = {
+	.owner		= THIS_MODULE,
+	.open		= mp3_open,
+	.write		= mp3_write,
+	.fsync		= mp3_fsync,
+	.release	= mp3_release,
+	.unlocked_ioctl	= mp3_ioctl,
+};
+
+struct miscdevice mp3_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_mp3",
+	.fops	= &mp3_fops,
+};
+
+static int __init mp3_init(void)
+{
+	return misc_register(&mp3_misc);
+}
+
+device_initcall(mp3_init);
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/pcm_in.c b/arch/arm/mach-msm/qdsp6/audiov2/pcm_in.c
new file mode 100644
index 0000000..6ef2195
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/pcm_in.c
@@ -0,0 +1,208 @@
+/* arch/arm/mach-msm/qdsp6/audiov2/pcm_in.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ * Copyright (c) 2009, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio.h>
+
+#include <mach/msm_qdsp6_audiov2.h>
+#include "dal_audio.h"
+#include "dal_audio_format.h"
+
+#define BUFSZ (4096)
+#define DMASZ (BUFSZ * 2)
+
+
+struct pcm {
+	struct mutex lock;
+	struct msm_audio_config cfg;
+	struct audio_client *audio_client;
+};
+
+static long q6_in_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct pcm *pcm = file->private_data;
+	struct adsp_open_command rpc;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	mutex_lock(&pcm->lock);
+	switch (cmd) {
+
+	case AUDIO_START:
+		tx_clk_freq = pcm->cfg.sample_rate;
+
+		memset(&rpc, 0, sizeof(rpc));
+
+		rpc.format_block.standard.format = ADSP_AUDIO_FORMAT_PCM;
+		rpc.format_block.standard.channels = pcm->cfg.channel_count;
+		rpc.format_block.standard.bits_per_sample = 16;
+		rpc.format_block.standard.sampling_rate = pcm->cfg.sample_rate;
+		rpc.format_block.standard.is_signed = 1;
+		rpc.format_block.standard.is_interleaved = 1;
+
+		rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_READ;
+		rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+		rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD;
+		rpc.buf_max_size = BUFSZ;
+		q6audio_start(pcm->audio_client, &rpc, sizeof(rpc));
+		break;
+	case AUDIO_STOP:
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_VOLUME:
+		break;
+	case AUDIO_SET_CONFIG:
+		if (copy_from_user(&pcm->cfg, (void *) arg,
+				 sizeof(struct msm_audio_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		break;
+	case AUDIO_GET_CONFIG:
+		if (copy_to_user((void *) arg, &pcm->cfg,
+				 sizeof(struct msm_audio_config))) {
+			rc = -EFAULT;
+		}
+		break;
+	default:
+		rc = -EINVAL;
+	}
+
+	mutex_unlock(&pcm->lock);
+	return rc;
+}
+
+static int q6_in_open(struct inode *inode, struct file *file)
+{
+
+	struct pcm *pcm;
+	pcm = kmalloc(sizeof(struct pcm), GFP_KERNEL);
+	if (pcm == NULL) {
+		pr_err("Could not allocate memory for pcm driver\n");
+		return -ENOMEM;
+	}
+	mutex_init(&pcm->lock);
+	file->private_data = pcm;
+	pcm->audio_client = q6audio_open(AUDIO_FLAG_READ, BUFSZ);
+	if (!pcm->audio_client) {
+		kfree(pcm);
+		return -ENOMEM;
+	}
+	pcm->cfg.channel_count = 1;
+	pcm->cfg.buffer_count = 2;
+	pcm->cfg.buffer_size = BUFSZ;
+	pcm->cfg.unused[0] = 0;
+	pcm->cfg.unused[1] = 0;
+	pcm->cfg.unused[2] = 0;
+	pcm->cfg.sample_rate = 8000;
+
+	return 0;
+}
+
+static ssize_t q6_in_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *pos)
+{
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	const char __user *start = buf;
+	struct pcm *pcm = file->private_data;
+	int xfer;
+	int res;
+
+	mutex_lock(&pcm->lock);
+	ac = pcm->audio_client;
+	if (!ac) {
+		res = -ENODEV;
+		goto fail;
+	}
+	while (count > 0) {
+		ab = ac->buf + ac->cpu_buf;
+
+		if (ab->used)
+			wait_event(ac->wait, (ab->used == 0));
+
+		xfer = count;
+		if (xfer > ab->size)
+			xfer = ab->size;
+
+		if (copy_to_user(buf, ab->data, xfer)) {
+			res = -EFAULT;
+			goto fail;
+		}
+
+		buf += xfer;
+		count -= xfer;
+
+		ab->used = 1;
+		q6audio_read(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+fail:
+	res = buf - start;
+	mutex_unlock(&pcm->lock);
+
+	return res;
+}
+
+static int q6_in_release(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	struct pcm *pcm = file->private_data;
+
+	mutex_lock(&pcm->lock);
+	if (pcm->audio_client)
+		rc = q6audio_close(pcm->audio_client);
+	mutex_unlock(&pcm->lock);
+	kfree(pcm);
+	return rc;
+}
+
+static const struct file_operations q6_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_in_open,
+	.read		= q6_in_read,
+	.release	= q6_in_release,
+	.unlocked_ioctl	= q6_in_ioctl,
+};
+
+struct miscdevice q6_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_pcm_in",
+	.fops	= &q6_in_fops,
+};
+
+static int __init q6_in_init(void)
+{
+	return misc_register(&q6_in_misc);
+}
+
+device_initcall(q6_in_init);
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/pcm_out.c b/arch/arm/mach-msm/qdsp6/audiov2/pcm_out.c
new file mode 100644
index 0000000..6743c6c
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/pcm_out.c
@@ -0,0 +1,196 @@
+/* arch/arm/mach-msm/qdsp6/audiov2/pcm_out.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio.h>
+
+#include <mach/msm_qdsp6_audiov2.h>
+#include "dal_audio.h"
+#include "dal_audio_format.h"
+
+#define BUFSZ (8192)
+#define DMASZ (BUFSZ * 2)
+
+struct pcm {
+	struct mutex lock;
+	struct audio_client *ac;
+	struct msm_audio_config cfg;
+
+};
+
+static long pcm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct pcm *pcm = file->private_data;
+	struct adsp_open_command rpc;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	mutex_lock(&pcm->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		memset(&rpc, 0, sizeof(rpc));
+		rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_WRITE;
+		rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_PLAYBACK;
+		rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+		rpc.format_block.standard.format = ADSP_AUDIO_FORMAT_PCM;
+		rpc.format_block.standard.channels = pcm->cfg.channel_count;
+		rpc.format_block.standard.bits_per_sample = 16;
+		rpc.format_block.standard.sampling_rate = pcm->cfg.sample_rate;
+		rpc.format_block.standard.is_signed = 1;
+		rpc.format_block.standard.is_interleaved = 1;
+		rpc.buf_max_size = BUFSZ;
+		q6audio_start(pcm->ac, (void *) &rpc, sizeof(rpc));
+		break;
+	case AUDIO_STOP:
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_CONFIG:
+		if (copy_from_user(&pcm->cfg, (void *) arg,
+				 sizeof(struct msm_audio_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (pcm->cfg.channel_count < 1 || pcm->cfg.channel_count > 2) {
+			rc = -EINVAL;
+			break;
+		}
+
+		break;
+	case AUDIO_GET_CONFIG:
+		if (copy_to_user((void *) arg, &pcm->cfg,
+				 sizeof(struct msm_audio_config))) {
+			rc = -EFAULT;
+		}
+		break;
+
+	default:
+		rc = -EINVAL;
+	}
+
+	mutex_unlock(&pcm->lock);
+	return rc;
+}
+
+static int pcm_open(struct inode *inode, struct file *file)
+{
+	struct pcm *pcm;
+	pcm = kzalloc(sizeof(struct pcm), GFP_KERNEL);
+
+	if (!pcm)
+		return -ENOMEM;
+
+	mutex_init(&pcm->lock);
+	file->private_data = pcm;
+	pcm->ac = q6audio_open(AUDIO_FLAG_WRITE, BUFSZ);
+	if (!pcm->ac) {
+		kfree(pcm);
+		return -ENOMEM;
+	}
+	pcm->cfg.channel_count = 2;
+	pcm->cfg.buffer_count = 2;
+	pcm->cfg.buffer_size = BUFSZ;
+	pcm->cfg.unused[0] = 0;
+	pcm->cfg.unused[1] = 0;
+	pcm->cfg.unused[2] = 0;
+	pcm->cfg.sample_rate = 48000;
+
+	return 0;
+}
+
+static ssize_t pcm_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct pcm *pcm = file->private_data;
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	const char __user *start = buf;
+	int xfer;
+
+	ac = pcm->ac;
+	if (!ac)
+		return -ENODEV;
+
+	while (count > 0) {
+		ab = ac->buf + ac->cpu_buf;
+
+		if (ab->used)
+			wait_event(ac->wait, (ab->used == 0));
+
+		xfer = count;
+		if (xfer > ab->size)
+			xfer = ab->size;
+
+		if (copy_from_user(ab->data, buf, xfer))
+			return -EFAULT;
+
+		buf += xfer;
+		count -= xfer;
+
+		ab->used = 1;
+		ab->actual_size = xfer;
+		q6audio_write(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+
+	return buf - start;
+}
+
+static int pcm_release(struct inode *inode, struct file *file)
+{
+	struct pcm *pcm = file->private_data;
+	if (pcm->ac)
+		q6audio_close(pcm->ac);
+	kfree(pcm);
+	return 0;
+}
+
+static const struct file_operations pcm_fops = {
+	.owner		= THIS_MODULE,
+	.open		= pcm_open,
+	.write		= pcm_write,
+	.release	= pcm_release,
+	.unlocked_ioctl	= pcm_ioctl,
+};
+
+struct miscdevice pcm_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_pcm_out",
+	.fops	= &pcm_fops,
+};
+
+static int __init pcm_init(void)
+{
+	return misc_register(&pcm_misc);
+}
+
+device_initcall(pcm_init);
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/q6audio.c b/arch/arm/mach-msm/qdsp6/audiov2/q6audio.c
new file mode 100644
index 0000000..f713e3d
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/q6audio.c
@@ -0,0 +1,1312 @@
+/* arch/arm/mach-msm/qdsp6/audiov2/q6audio.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+
+#include <linux/delay.h>
+#include <linux/wakelock.h>
+#include <linux/android_pmem.h>
+#include <linux/gpio.h>
+#include <mach/msm_qdsp6_audiov2.h>
+
+#include "../dal.h"
+#include "dal_audio.h"
+#include "dal_audio_format.h"
+#include "dal_acdb.h"
+#include "dal_adie.h"
+#include "q6audio_devices.h"
+
+struct q6_hw_info {
+	int min_gain;
+	int max_gain;
+};
+
+/* TODO: provide mechanism to configure from board file */
+
+static struct q6_hw_info q6_audio_hw[Q6_HW_COUNT] = {
+	[Q6_HW_HANDSET] = {
+		.min_gain = -2000,
+		.max_gain = 0,
+	},
+	[Q6_HW_HEADSET] = {
+		.min_gain = -2000,
+		.max_gain = 0,
+	},
+	[Q6_HW_SPEAKER] = {
+		.min_gain = -1500,
+		.max_gain = 0,
+	},
+	[Q6_HW_TTY] = {
+		.min_gain = -2000,
+		.max_gain = 0,
+	},
+	[Q6_HW_BT_SCO] = {
+		.min_gain = -2000,
+		.max_gain = 0,
+	},
+	[Q6_HW_BT_A2DP] = {
+		.min_gain = -2000,
+		.max_gain = 0,
+	},
+};
+
+static struct wake_lock idlelock;
+static int idlecount;
+static DEFINE_MUTEX(idlecount_lock);
+
+void audio_prevent_sleep(void)
+{
+	mutex_lock(&idlecount_lock);
+	if (++idlecount == 1)
+		wake_lock(&idlelock);
+	mutex_unlock(&idlecount_lock);
+}
+
+void audio_allow_sleep(void)
+{
+	mutex_lock(&idlecount_lock);
+	if (--idlecount == 0)
+		wake_unlock(&idlelock);
+	mutex_unlock(&idlecount_lock);
+}
+
+static struct clk *icodec_rx_clk;
+static struct clk *icodec_tx_clk;
+static struct clk *ecodec_clk;
+static struct clk *sdac_clk;
+
+static struct q6audio_analog_ops default_analog_ops;
+static struct q6audio_analog_ops *analog_ops = &default_analog_ops;
+uint32_t tx_clk_freq = 8000;
+static int tx_mute_status;
+
+void q6audio_register_analog_ops(struct q6audio_analog_ops *ops)
+{
+	analog_ops = ops;
+}
+
+static struct q6_device_info *q6_lookup_device(uint32_t device_id)
+{
+	struct q6_device_info *di = q6_audio_devices;
+	for (;;) {
+		if (di->id == device_id)
+			return di;
+		if (di->id == 0) {
+			pr_err("q6_lookup_device: bogus id 0x%08x\n",
+			       device_id);
+			return di;
+		}
+		di++;
+	}
+}
+
+static uint32_t q6_device_to_codec(uint32_t device_id)
+{
+	struct q6_device_info *di = q6_lookup_device(device_id);
+	return di->codec;
+}
+
+static uint32_t q6_device_to_dir(uint32_t device_id)
+{
+	struct q6_device_info *di = q6_lookup_device(device_id);
+	return di->dir;
+}
+
+static uint32_t q6_device_to_cad_id(uint32_t device_id)
+{
+	struct q6_device_info *di = q6_lookup_device(device_id);
+	return di->cad_id;
+}
+
+static uint32_t q6_device_to_path(uint32_t device_id)
+{
+	struct q6_device_info *di = q6_lookup_device(device_id);
+	return di->path;
+}
+
+static uint32_t q6_device_to_rate(uint32_t device_id)
+{
+	struct q6_device_info *di = q6_lookup_device(device_id);
+	return di->rate;
+}
+
+int q6_device_volume(uint32_t device_id, int level)
+{
+	struct q6_device_info *di = q6_lookup_device(device_id);
+	struct q6_hw_info *hw;
+
+	hw = &q6_audio_hw[di->hw];
+
+	return hw->min_gain + ((hw->max_gain - hw->min_gain) * level) / 100;
+}
+
+static inline int adie_open(struct dal_client *client)
+{
+	return dal_call_f0(client, DAL_OP_OPEN, 0);
+}
+
+static inline int adie_close(struct dal_client *client)
+{
+	return dal_call_f0(client, DAL_OP_CLOSE, 0);
+}
+
+static inline int adie_set_path(struct dal_client *client,
+				uint32_t *adie_params, uint32_t size)
+{
+	uint32_t tmp;
+	return dal_call(client, ADIE_OP_SET_PATH, 5, adie_params, size,
+		(void *)&tmp, sizeof(uint32_t));
+
+}
+
+static inline int adie_proceed_to_stage(struct dal_client *client,
+					uint32_t path_type, uint32_t stage)
+{
+	return dal_call_f1(client, ADIE_OP_PROCEED_TO_STAGE,
+			   path_type, stage);
+}
+
+static int adie_refcount;
+
+static struct dal_client *adie;
+static struct dal_client *adsp;
+static struct dal_client *acdb;
+
+static int adie_enable(void)
+{
+	adie_refcount++;
+	if (adie_refcount == 1)
+		adie_open(adie);
+	return 0;
+}
+
+static int adie_disable(void)
+{
+	adie_refcount--;
+	if (adie_refcount == 0)
+		adie_close(adie);
+	return 0;
+}
+
+/* 4k DMA scratch page used for exchanging acdb device config tables
+ * and stream format descriptions with the DSP.
+ */
+char *audio_data;
+int32_t audio_phys;
+
+#define SESSION_MIN 0
+#define SESSION_MAX 64
+
+static DEFINE_MUTEX(session_lock);
+static DEFINE_MUTEX(audio_lock);
+
+static struct audio_client *session[SESSION_MAX];
+
+static int session_alloc(struct audio_client *ac)
+{
+	int n;
+
+	mutex_lock(&session_lock);
+	for (n = SESSION_MIN; n < SESSION_MAX; n++) {
+		if (!session[n]) {
+			session[n] = ac;
+			mutex_unlock(&session_lock);
+			return n;
+		}
+	}
+	mutex_unlock(&session_lock);
+	return -ENOMEM;
+}
+
+static void session_free(int n, struct audio_client *ac)
+{
+	mutex_lock(&session_lock);
+	if (session[n] == ac)
+		session[n] = 0;
+	mutex_unlock(&session_lock);
+}
+
+static void audio_client_free(struct audio_client *ac)
+{
+	session_free(ac->session, ac);
+
+	if (ac->buf[0].data)
+		pmem_kfree(ac->buf[0].phys);
+	if (ac->buf[1].data)
+		pmem_kfree(ac->buf[1].phys);
+	kfree(ac);
+}
+
+static struct audio_client *audio_client_alloc(unsigned bufsz)
+{
+	struct audio_client *ac;
+	int n;
+
+	ac = kzalloc(sizeof(*ac), GFP_KERNEL);
+	if (!ac)
+		return 0;
+
+	n = session_alloc(ac);
+	if (n < 0)
+		goto fail_session;
+	ac->session = n;
+
+	if (bufsz > 0) {
+		ac->buf[0].phys = pmem_kalloc(bufsz,
+					PMEM_MEMTYPE_EBI1|PMEM_ALIGNMENT_4K);
+		ac->buf[0].data = ioremap(ac->buf[0].phys, bufsz);
+		if (!ac->buf[0].data)
+			goto fail;
+
+		ac->buf[1].phys = pmem_kalloc(bufsz,
+					PMEM_MEMTYPE_EBI1|PMEM_ALIGNMENT_4K);
+		ac->buf[1].data = ioremap(ac->buf[1].phys, bufsz);
+		if (!ac->buf[1].data)
+			goto fail;
+
+		ac->buf[0].size = bufsz;
+		ac->buf[1].size = bufsz;
+	}
+
+	init_waitqueue_head(&ac->wait);
+	ac->client = adsp;
+
+	return ac;
+
+fail:
+	pr_err("pmem_kalloc failed\n");
+	session_free(n, ac);
+fail_session:
+	audio_client_free(ac);
+	return 0;
+}
+
+static int audio_ioctl(struct audio_client *ac, void *ptr, uint32_t len)
+{
+	struct adsp_command_hdr *hdr = ptr;
+	uint32_t tmp;
+	int r;
+
+	hdr->size = len - sizeof(u32);
+	hdr->dest = AUDIO_ADDR(DOMAIN_DSP, ac->session, 0);
+	hdr->src = AUDIO_ADDR(DOMAIN_APP, ac->session, 0);
+	hdr->context = ac->session;
+	ac->cb_status = -EBUSY;
+	r = dal_call(ac->client, AUDIO_OP_CONTROL, 5, ptr, len,
+						&tmp, sizeof(tmp));
+	if (r != 4)
+		return -EIO;
+	wait_event(ac->wait, (ac->cb_status != -EBUSY));
+	return tmp;
+}
+
+static int audio_command(struct audio_client *ac, uint32_t cmd)
+{
+	struct adsp_command_hdr rpc;
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.opcode = cmd;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_open_control(struct audio_client *ac)
+{
+	struct adsp_open_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_DEVICE;
+	rpc.hdr.dest = AUDIO_ADDR(DOMAIN_DSP, ac->session, 0);
+	rpc.hdr.src = AUDIO_ADDR(DOMAIN_APP, ac->session, 0);
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+
+static int audio_close(struct audio_client *ac)
+{
+	audio_command(ac, ADSP_AUDIO_IOCTL_CMD_STREAM_STOP);
+	audio_command(ac, ADSP_AUDIO_IOCTL_CMD_CLOSE);
+	return 0;
+}
+
+static int audio_set_table(struct audio_client *ac,
+			   uint32_t device_id, int size)
+{
+	struct adsp_set_dev_cfg_table_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_SET_DEVICE_CONFIG_TABLE;
+	rpc.hdr.dest = AUDIO_ADDR(DOMAIN_DSP, ac->session, 0);
+	rpc.hdr.src = AUDIO_ADDR(DOMAIN_APP, ac->session, 0);
+	rpc.device_id = device_id;
+	rpc.phys_addr = audio_phys;
+	rpc.phys_size = size;
+	rpc.phys_used = size;
+
+	if (q6_device_to_dir(device_id) == Q6_TX)
+		rpc.hdr.data = tx_clk_freq;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+int q6audio_read(struct audio_client *ac, struct audio_buffer *ab)
+{
+	struct adsp_buffer_command rpc;
+	uint32_t res;
+	int r;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.size = sizeof(rpc) - sizeof(u32);
+	rpc.hdr.dest = AUDIO_ADDR(DOMAIN_DSP, ac->session, 0);
+	rpc.hdr.src = AUDIO_ADDR(DOMAIN_APP, ac->session, 0);
+	rpc.hdr.context = ac->session;
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_DATA_TX;
+	rpc.buffer.addr = ab->phys;
+	rpc.buffer.max_size = ab->size;
+	rpc.buffer.actual_size = ab->actual_size;
+
+	r = dal_call(ac->client, AUDIO_OP_DATA, 5, &rpc, sizeof(rpc),
+		     &res, sizeof(res));
+
+	if ((r == sizeof(res)))
+		return 0;
+
+	return -EIO;
+
+}
+
+int q6audio_write(struct audio_client *ac, struct audio_buffer *ab)
+{
+	struct adsp_buffer_command rpc;
+	uint32_t res;
+	int r;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.size = sizeof(rpc) - sizeof(u32);
+	rpc.hdr.src = AUDIO_ADDR(DOMAIN_APP, ac->session, 0);
+	rpc.hdr.dest = AUDIO_ADDR(DOMAIN_DSP, ac->session, 0);
+	rpc.hdr.context = ac->session;
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_DATA_RX;
+	rpc.buffer.addr = ab->phys;
+	rpc.buffer.max_size = ab->size;
+	rpc.buffer.actual_size = ab->actual_size;
+
+	r = dal_call(ac->client, AUDIO_OP_DATA, 5, &rpc, sizeof(rpc),
+		     &res, sizeof(res));
+	return 0;
+}
+
+static int audio_rx_volume(struct audio_client *ac, uint32_t dev_id,
+				 int32_t volume)
+{
+	struct adsp_set_dev_volume_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_VOL;
+	rpc.hdr.dest = AUDIO_ADDR(DOMAIN_DSP, ac->session, 0);
+	rpc.hdr.src = AUDIO_ADDR(DOMAIN_APP, ac->session, 0);
+	rpc.device_id = dev_id;
+	rpc.path = ADSP_PATH_RX;
+	rpc.volume = volume;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_rx_mute(struct audio_client *ac, uint32_t dev_id, int mute)
+{
+	struct adsp_set_dev_mute_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_MUTE;
+	rpc.hdr.dest = AUDIO_ADDR(DOMAIN_DSP, ac->session, 0);
+	rpc.hdr.src = AUDIO_ADDR(DOMAIN_APP, ac->session, 0);
+	rpc.device_id = dev_id;
+	rpc.path = ADSP_PATH_RX;
+	rpc.mute = !!mute;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_tx_volume(struct audio_client *ac, uint32_t dev_id,
+				 int32_t volume)
+{
+	struct adsp_set_dev_volume_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_VOL;
+	rpc.hdr.dest = AUDIO_ADDR(DOMAIN_DSP, ac->session, 0);
+	rpc.hdr.src = AUDIO_ADDR(DOMAIN_APP, ac->session, 0);
+	rpc.device_id = dev_id;
+	rpc.path = ADSP_PATH_TX;
+	rpc.volume = volume;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_tx_mute(struct audio_client *ac, uint32_t dev_id, int mute)
+{
+	struct adsp_set_dev_mute_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_MUTE;
+	rpc.hdr.dest = AUDIO_ADDR(DOMAIN_DSP, ac->session, 0);
+	rpc.hdr.src = AUDIO_ADDR(DOMAIN_APP, ac->session, 0);
+	rpc.device_id = dev_id;
+	rpc.path = ADSP_PATH_TX;
+	rpc.mute = !!mute;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static void callback(void *data, int len, void *cookie)
+{
+	struct adsp_event_hdr *e = data;
+	struct audio_client *ac;
+	struct adsp_buffer_event *abe = data;
+
+	if (e->context >= SESSION_MAX) {
+		pr_err("audio callback: bogus session %d\n",
+		       e->context);
+		return;
+	}
+	ac = session[e->context];
+	if (!ac) {
+		pr_err("audio callback: unknown session %d\n",
+		       e->context);
+		return;
+	}
+
+	if (e->event_id == ADSP_AUDIO_IOCTL_CMD_STREAM_EOS) {
+		pr_info("playback done\n");
+		if (e->status)
+			pr_err("playback status %d\n", e->status);
+		if (ac->cb_status == -EBUSY) {
+			ac->cb_status = e->status;
+			wake_up(&ac->wait);
+		}
+		return;
+	}
+
+	if (e->event_id == ADSP_AUDIO_EVT_STATUS_BUF_DONE) {
+		if (e->status)
+			pr_err("buffer status %d\n", e->status);
+
+		ac->buf[ac->dsp_buf].actual_size = abe->buffer.actual_size;
+		ac->buf[ac->dsp_buf].used = 0;
+		ac->dsp_buf ^= 1;
+		wake_up(&ac->wait);
+		return;
+	}
+
+	if (e->status)
+		pr_warning("audio_cb: s=%d e=%08x status=%d\n",
+			   e->context, e->event_id, e->status);
+
+	if (ac->cb_status == -EBUSY) {
+		ac->cb_status = e->status;
+		wake_up(&ac->wait);
+	}
+}
+
+static void audio_init(struct dal_client *client)
+{
+	u32 tmp[3];
+
+	tmp[0] = 2 * sizeof(u32);
+	tmp[1] = 0;
+	tmp[2] = 0;
+	dal_call(client, AUDIO_OP_INIT, 5, tmp, sizeof(tmp),
+		 tmp, sizeof(u32));
+}
+
+static struct audio_client *ac_control;
+
+static int q6audio_init(void)
+{
+	struct audio_client *ac = 0;
+	int res = -ENODEV;
+
+	mutex_lock(&audio_lock);
+	if (ac_control) {
+		res = 0;
+		goto done;
+	}
+
+	icodec_rx_clk = clk_get(0, "icodec_rx_clk");
+	icodec_tx_clk = clk_get(0, "icodec_tx_clk");
+	ecodec_clk = clk_get(0, "ecodec_clk");
+	sdac_clk = clk_get(0, "sdac_clk");
+
+	tx_mute_status = 0;
+	audio_phys = pmem_kalloc(4096, PMEM_MEMTYPE_EBI1|PMEM_ALIGNMENT_4K);
+	audio_data = ioremap(audio_phys, 4096);
+	if (!audio_data) {
+		pr_err("pmem kalloc failed\n");
+		res = -ENOMEM;
+		goto done;
+	}
+
+	adsp = dal_attach(AUDIO_DAL_DEVICE, AUDIO_DAL_PORT, 1,
+			  callback, 0);
+	if (!adsp) {
+		pr_err("audio_init: cannot attach to adsp\n");
+		res = -ENODEV;
+		goto done;
+	}
+	if (check_version(adsp, AUDIO_DAL_VERSION) != 0) {
+		pr_err("Incompatible adsp version\n");
+		res = -ENODEV;
+		goto done;
+	}
+
+	audio_init(adsp);
+
+	ac = audio_client_alloc(0);
+	if (!ac) {
+		pr_err("audio_init: cannot allocate client\n");
+		res = -ENOMEM;
+		goto done;
+	}
+
+	if (audio_open_control(ac)) {
+		pr_err("audio_init: cannot open control channel\n");
+		res = -ENODEV;
+		goto done;
+	}
+
+	acdb = dal_attach(ACDB_DAL_DEVICE, ACDB_DAL_PORT, 0, 0, 0);
+	if (!acdb) {
+		pr_err("audio_init: cannot attach to acdb channel\n");
+		res = -ENODEV;
+		goto done;
+	}
+	if (check_version(acdb, ACDB_DAL_VERSION) != 0) {
+		pr_err("Incompatablie acdb version\n");
+		res = -ENODEV;
+		goto done;
+	}
+
+
+	adie = dal_attach(ADIE_DAL_DEVICE, ADIE_DAL_PORT, 0, 0, 0);
+	if (!adie) {
+		pr_err("audio_init: cannot attach to adie\n");
+		res = -ENODEV;
+		goto done;
+	}
+	if (check_version(adie, ADIE_DAL_VERSION) != 0) {
+		pr_err("Incompatablie adie version\n");
+		res = -ENODEV;
+		goto done;
+	}
+	if (analog_ops->init)
+		analog_ops->init();
+
+	res = 0;
+	ac_control = ac;
+
+	wake_lock_init(&idlelock, WAKE_LOCK_IDLE, "audio_pcm_idle");
+done:
+	if ((res < 0) && ac)
+		audio_client_free(ac);
+	mutex_unlock(&audio_lock);
+
+	return res;
+}
+
+static int acdb_get_config_table(uint32_t device_id, uint32_t sample_rate)
+{
+	struct acdb_cmd_device_table rpc;
+	struct acdb_result res;
+	int r;
+
+	if (q6audio_init())
+		return 0;
+
+	memset(audio_data, 0, 4096);
+	memset(&rpc, 0, sizeof(rpc));
+
+	rpc.size = sizeof(rpc) - (2 * sizeof(uint32_t));
+	rpc.command_id = ACDB_GET_DEVICE_TABLE;
+	rpc.device_id = q6_device_to_cad_id(device_id);
+	rpc.network_id = 0x00010023;
+	rpc.sample_rate_id = sample_rate;
+	rpc.total_bytes = 4096;
+	rpc.unmapped_buf = audio_phys;
+	rpc.res_size = sizeof(res) - (2 * sizeof(uint32_t));
+
+	r = dal_call(acdb, ACDB_OP_IOCTL, 8, &rpc, sizeof(rpc),
+		     &res, sizeof(res));
+
+	if ((r == sizeof(res)) && (res.dal_status == 0))
+		return res.used_bytes;
+
+	return -EIO;
+}
+
+static uint32_t audio_rx_path_id = ADIE_PATH_HANDSET_RX;
+static uint32_t audio_rx_device_id = ADSP_AUDIO_DEVICE_ID_HANDSET_SPKR;
+static uint32_t audio_rx_device_group = -1;
+static uint32_t audio_tx_path_id = ADIE_PATH_HANDSET_TX;
+static uint32_t audio_tx_device_id = ADSP_AUDIO_DEVICE_ID_HANDSET_MIC;
+static uint32_t audio_tx_device_group = -1;
+
+static int qdsp6_devchg_notify(struct audio_client *ac,
+			       uint32_t dev_type, uint32_t dev_id)
+{
+	struct adsp_device_switch_command rpc;
+
+	if (dev_type != ADSP_AUDIO_RX_DEVICE &&
+	    dev_type != ADSP_AUDIO_TX_DEVICE)
+		return -EINVAL;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_PREPARE;
+	rpc.hdr.dest = AUDIO_ADDR(DOMAIN_DSP, ac->session, 0);
+	rpc.hdr.src = AUDIO_ADDR(DOMAIN_APP, ac->session, 0);
+
+	if (dev_type == ADSP_AUDIO_RX_DEVICE) {
+		rpc.old_device = audio_rx_device_id;
+		rpc.new_device = dev_id;
+	} else {
+		rpc.old_device = audio_tx_device_id;
+		rpc.new_device = dev_id;
+	}
+	rpc.device_class = 0;
+	rpc.device_type = dev_type;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int qdsp6_standby(struct audio_client *ac)
+{
+	return audio_command(ac, ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_STANDBY);
+}
+
+static int qdsp6_start(struct audio_client *ac)
+{
+	return audio_command(ac, ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_COMMIT);
+}
+
+static void audio_rx_analog_enable(int en)
+{
+	switch (audio_rx_device_id) {
+	case ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_MONO:
+	case ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_STEREO:
+	case ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_SPKR:
+		if (analog_ops->headset_enable)
+			analog_ops->headset_enable(en);
+		break;
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_MONO_HEADSET:
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_STEREO_HEADSET:
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_MONO_HEADSET:
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_STEREO_HEADSET:
+		if (analog_ops->headset_enable)
+			analog_ops->headset_enable(en);
+		if (analog_ops->speaker_enable)
+			analog_ops->speaker_enable(en);
+		break;
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO:
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO:
+		if (analog_ops->speaker_enable)
+			analog_ops->speaker_enable(en);
+		break;
+	case ADSP_AUDIO_DEVICE_ID_BT_SCO_SPKR:
+		if (analog_ops->bt_sco_enable)
+			analog_ops->bt_sco_enable(en);
+		break;
+	}
+}
+
+static void audio_tx_analog_enable(int en)
+{
+	switch (audio_tx_device_id) {
+	case ADSP_AUDIO_DEVICE_ID_HANDSET_MIC:
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MIC:
+		if (analog_ops->int_mic_enable)
+			analog_ops->int_mic_enable(en);
+		break;
+	case ADSP_AUDIO_DEVICE_ID_HEADSET_MIC:
+	case ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_MIC:
+		if (analog_ops->ext_mic_enable)
+			analog_ops->ext_mic_enable(en);
+		break;
+	case ADSP_AUDIO_DEVICE_ID_BT_SCO_MIC:
+		if (analog_ops->bt_sco_enable)
+			analog_ops->bt_sco_enable(en);
+		break;
+	}
+}
+
+static void _audio_rx_path_enable(void)
+{
+	uint32_t adev, sample_rate;
+	int sz;
+	uint32_t adie_params[5];
+
+	adev = audio_rx_device_id;
+	sample_rate = q6_device_to_rate(adev);
+
+	sz = acdb_get_config_table(adev, sample_rate);
+	audio_set_table(ac_control, adev, sz);
+
+	adie_params[0] = 4*sizeof(uint32_t);
+	adie_params[1] = audio_rx_path_id;
+	adie_params[2] = ADIE_PATH_RX;
+	adie_params[3] = 48000;
+	adie_params[4] = 256;
+	/*check for errors here*/
+	if (!adie_set_path(adie, adie_params, sizeof(adie_params)))
+		pr_err("adie set rx path failed\n");
+
+	adie_proceed_to_stage(adie, ADIE_PATH_RX,
+				ADIE_STAGE_DIGITAL_READY);
+	adie_proceed_to_stage(adie, ADIE_PATH_RX,
+				ADIE_STAGE_DIGITAL_ANALOG_READY);
+
+	audio_rx_analog_enable(1);
+
+	audio_rx_mute(ac_control, adev, 0);
+
+	audio_rx_volume(ac_control, adev, q6_device_volume(adev, 100));
+}
+
+static void _audio_tx_path_enable(void)
+{
+	uint32_t adev;
+	int sz;
+	uint32_t adie_params[5];
+
+	adev = audio_tx_device_id;
+
+	pr_info("audiolib: load %08x cfg table\n", adev);
+
+	if (tx_clk_freq > 16000) {
+		adie_params[3] = 48000;
+		sz = acdb_get_config_table(adev, 48000);
+
+	} else if (tx_clk_freq > 8000) {
+		adie_params[3] = 16000;
+		sz = acdb_get_config_table(adev, 16000);
+	} else {
+
+		adie_params[3] = 8000;
+		sz = acdb_get_config_table(adev, 8000);
+	}
+
+	pr_info("cfg table is %d bytes\n", sz);
+	audio_set_table(ac_control, adev, sz);
+
+	pr_info("audiolib: set adie tx path\n");
+
+	adie_params[0] = 4*sizeof(uint32_t);
+	adie_params[1] = audio_tx_path_id;
+	adie_params[2] = ADIE_PATH_TX;
+	adie_params[4] = 256;
+
+	if (!adie_set_path(adie, adie_params, sizeof(adie_params)))
+		pr_err("adie set tx path failed\n");
+
+	adie_proceed_to_stage(adie, ADIE_PATH_TX,
+					 ADIE_STAGE_DIGITAL_READY);
+	adie_proceed_to_stage(adie, ADIE_PATH_TX,
+					 ADIE_STAGE_DIGITAL_ANALOG_READY);
+
+	audio_tx_analog_enable(1);
+	audio_tx_mute(ac_control, adev, tx_mute_status);
+
+	if (!tx_mute_status)
+		audio_tx_volume(ac_control, adev, q6_device_volume(adev, 100));
+}
+
+static void _audio_rx_path_disable(void)
+{
+	audio_rx_analog_enable(0);
+
+	adie_proceed_to_stage(adie, ADIE_PATH_RX, ADIE_STAGE_ANALOG_OFF);
+	adie_proceed_to_stage(adie, ADIE_PATH_RX, ADIE_STAGE_DIGITAL_OFF);
+}
+
+static void _audio_tx_path_disable(void)
+{
+	audio_tx_analog_enable(0);
+
+	adie_proceed_to_stage(adie, ADIE_PATH_TX, ADIE_STAGE_ANALOG_OFF);
+	adie_proceed_to_stage(adie, ADIE_PATH_TX, ADIE_STAGE_DIGITAL_OFF);
+}
+
+static int icodec_rx_clk_refcount;
+static int icodec_tx_clk_refcount;
+static int ecodec_clk_refcount;
+static int sdac_clk_refcount;
+
+static void _audio_rx_clk_enable(void)
+{
+	uint32_t device_group = q6_device_to_codec(audio_rx_device_id);
+
+	switch (device_group) {
+	case Q6_ICODEC_RX:
+		icodec_rx_clk_refcount++;
+		if (icodec_rx_clk_refcount == 1) {
+			clk_set_rate(icodec_rx_clk, 12288000);
+			clk_enable(icodec_rx_clk);
+		}
+		break;
+	case Q6_ECODEC_RX:
+		ecodec_clk_refcount++;
+		if (ecodec_clk_refcount == 1) {
+			clk_set_rate(ecodec_clk, 2048000);
+			clk_enable(ecodec_clk);
+		}
+		break;
+	case Q6_SDAC_RX:
+		sdac_clk_refcount++;
+		if (sdac_clk_refcount == 1) {
+			clk_set_rate(sdac_clk, 12288000);
+			clk_enable(sdac_clk);
+		}
+		break;
+	default:
+		return;
+	}
+	audio_rx_device_group = device_group;
+}
+
+static void _audio_tx_clk_enable(void)
+{
+	uint32_t device_group = q6_device_to_codec(audio_tx_device_id);
+
+	switch (device_group) {
+	case Q6_ICODEC_TX:
+		icodec_tx_clk_refcount++;
+		if (icodec_tx_clk_refcount == 1) {
+			clk_set_rate(icodec_tx_clk, tx_clk_freq * 256);
+			clk_enable(icodec_tx_clk);
+		}
+		break;
+	case Q6_ECODEC_TX:
+		ecodec_clk_refcount++;
+		if (ecodec_clk_refcount == 1) {
+			clk_set_rate(ecodec_clk, 2048000);
+			clk_enable(ecodec_clk);
+		}
+		break;
+	case Q6_SDAC_TX:
+		/* TODO: In QCT BSP, clk rate was set to 20480000 */
+		sdac_clk_refcount++;
+		if (sdac_clk_refcount == 1) {
+			clk_set_rate(sdac_clk, 12288000);
+			clk_enable(sdac_clk);
+		}
+		break;
+	default:
+		return;
+	}
+	audio_tx_device_group = device_group;
+}
+
+static void _audio_rx_clk_disable(void)
+{
+	switch (audio_rx_device_group) {
+	case Q6_ICODEC_RX:
+		icodec_rx_clk_refcount--;
+		if (icodec_rx_clk_refcount == 0) {
+			clk_disable(icodec_rx_clk);
+			audio_rx_device_group = -1;
+		}
+		break;
+	case Q6_ECODEC_RX:
+		ecodec_clk_refcount--;
+		if (ecodec_clk_refcount == 0) {
+			clk_disable(ecodec_clk);
+			audio_rx_device_group = -1;
+		}
+		break;
+	case Q6_SDAC_RX:
+		sdac_clk_refcount--;
+		if (sdac_clk_refcount == 0) {
+			clk_disable(sdac_clk);
+			audio_rx_device_group = -1;
+		}
+		break;
+	default:
+		pr_err("audiolib: invalid rx device group %d\n",
+			audio_rx_device_group);
+		break;
+	}
+}
+
+static void _audio_tx_clk_disable(void)
+{
+	switch (audio_tx_device_group) {
+	case Q6_ICODEC_TX:
+		icodec_tx_clk_refcount--;
+		if (icodec_tx_clk_refcount == 0) {
+			clk_disable(icodec_tx_clk);
+			audio_tx_device_group = -1;
+		}
+		break;
+	case Q6_ECODEC_TX:
+		ecodec_clk_refcount--;
+		if (ecodec_clk_refcount == 0) {
+			clk_disable(ecodec_clk);
+			audio_tx_device_group = -1;
+		}
+		break;
+	case Q6_SDAC_TX:
+		sdac_clk_refcount--;
+		if (sdac_clk_refcount == 0) {
+			clk_disable(sdac_clk);
+			audio_tx_device_group = -1;
+		}
+		break;
+	default:
+		pr_err("audiolib: invalid tx device group %d\n",
+			audio_tx_device_group);
+		break;
+	}
+}
+
+static void _audio_rx_clk_reinit(uint32_t rx_device)
+{
+	uint32_t device_group = q6_device_to_codec(rx_device);
+
+	if (device_group != audio_rx_device_group)
+		_audio_rx_clk_disable();
+
+	audio_rx_device_id = rx_device;
+	audio_rx_path_id = q6_device_to_path(rx_device);
+
+	if (device_group != audio_rx_device_group)
+		_audio_rx_clk_enable();
+
+}
+
+static void _audio_tx_clk_reinit(uint32_t tx_device)
+{
+	uint32_t device_group = q6_device_to_codec(tx_device);
+
+	if (device_group != audio_tx_device_group)
+		_audio_tx_clk_disable();
+
+	audio_tx_device_id = tx_device;
+	audio_tx_path_id = q6_device_to_path(tx_device);
+
+	if (device_group != audio_tx_device_group)
+		_audio_tx_clk_enable();
+}
+
+static DEFINE_MUTEX(audio_path_lock);
+static int audio_rx_path_refcount;
+static int audio_tx_path_refcount;
+
+static int audio_rx_path_enable(int en)
+{
+	mutex_lock(&audio_path_lock);
+	if (en) {
+		audio_rx_path_refcount++;
+		if (audio_rx_path_refcount == 1) {
+			adie_enable();
+			_audio_rx_clk_enable();
+			_audio_rx_path_enable();
+		}
+	} else {
+		audio_rx_path_refcount--;
+		if (audio_rx_path_refcount == 0) {
+			_audio_rx_path_disable();
+			_audio_rx_clk_disable();
+			adie_disable();
+		}
+	}
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+static int audio_tx_path_enable(int en)
+{
+	mutex_lock(&audio_path_lock);
+	if (en) {
+		audio_tx_path_refcount++;
+		if (audio_tx_path_refcount == 1) {
+			adie_enable();
+			_audio_tx_clk_enable();
+			_audio_tx_path_enable();
+		}
+	} else {
+		audio_tx_path_refcount--;
+		if (audio_tx_path_refcount == 0) {
+			_audio_tx_path_disable();
+			_audio_tx_clk_disable();
+			adie_disable();
+		}
+	}
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+int q6audio_update_acdb(uint32_t id_src, uint32_t id_dst)
+{
+	mutex_lock(&audio_path_lock);
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+int q6audio_set_tx_mute(int mute)
+{
+	uint32_t adev;
+	int rc;
+
+	if (q6audio_init())
+		return 0;
+
+	mutex_lock(&audio_path_lock);
+
+	if (mute == tx_mute_status) {
+		mutex_unlock(&audio_path_lock);
+		return 0;
+	}
+
+	adev = audio_tx_device_id;
+	rc = audio_tx_mute(ac_control, adev, mute);
+	if (!rc)
+		tx_mute_status = mute;
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+int q6audio_set_rx_volume(int level)
+{
+	uint32_t adev;
+	int vol;
+
+	if (q6audio_init())
+		return 0;
+
+	if (level < 0 || level > 100)
+		return -EINVAL;
+
+	mutex_lock(&audio_path_lock);
+	adev = audio_rx_device_id;
+	vol = q6_device_volume(adev, level);
+	audio_rx_mute(ac_control, adev, 0);
+	audio_rx_volume(ac_control, adev, vol);
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+static void do_rx_routing(uint32_t device_id)
+{
+	int sz;
+	uint32_t sample_rate;
+
+	if (device_id == audio_rx_device_id)
+		return;
+
+	if (audio_rx_path_refcount > 0) {
+		qdsp6_devchg_notify(ac_control, ADSP_AUDIO_RX_DEVICE,
+					 device_id);
+		_audio_rx_path_disable();
+		_audio_rx_clk_reinit(device_id);
+		_audio_rx_path_enable();
+	} else {
+		sample_rate = q6_device_to_rate(device_id);
+		sz = acdb_get_config_table(device_id, sample_rate);
+		if (sz < 0)
+			pr_err("could not get ACDB config table\n");
+
+		audio_set_table(ac_control, device_id, sz);
+		qdsp6_devchg_notify(ac_control, ADSP_AUDIO_RX_DEVICE,
+					 device_id);
+		qdsp6_standby(ac_control);
+		qdsp6_start(ac_control);
+		audio_rx_device_id = device_id;
+		audio_rx_path_id = q6_device_to_path(device_id);
+	}
+}
+
+static void do_tx_routing(uint32_t device_id)
+{
+	int sz;
+	uint32_t sample_rate;
+
+	if (device_id == audio_tx_device_id)
+		return;
+
+	if (audio_tx_path_refcount > 0) {
+		qdsp6_devchg_notify(ac_control, ADSP_AUDIO_TX_DEVICE,
+					 device_id);
+		_audio_tx_path_disable();
+		_audio_tx_clk_reinit(device_id);
+		_audio_tx_path_enable();
+	} else {
+		sample_rate = q6_device_to_rate(device_id);
+		sz = acdb_get_config_table(device_id, sample_rate);
+		audio_set_table(ac_control, device_id, sz);
+		qdsp6_devchg_notify(ac_control, ADSP_AUDIO_TX_DEVICE,
+					 device_id);
+		qdsp6_standby(ac_control);
+		qdsp6_start(ac_control);
+		audio_tx_device_id = device_id;
+		audio_tx_path_id = q6_device_to_path(device_id);
+	}
+}
+
+int q6audio_do_routing(uint32_t device_id)
+{
+	if (q6audio_init())
+		return 0;
+
+	mutex_lock(&audio_path_lock);
+
+	switch (q6_device_to_dir(device_id)) {
+	case Q6_RX:
+		do_rx_routing(device_id);
+		break;
+	case Q6_TX:
+		do_tx_routing(device_id);
+		break;
+	}
+
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+int q6audio_set_route(const char *name)
+{
+	uint32_t route;
+	if (!strcmp(name, "speaker"))
+		route = ADIE_PATH_SPEAKER_STEREO_RX;
+	else if (!strcmp(name, "headphones"))
+		route = ADIE_PATH_HEADSET_STEREO_RX;
+	else if (!strcmp(name, "handset"))
+		route = ADIE_PATH_HANDSET_RX;
+	else
+		return -EINVAL;
+
+	mutex_lock(&audio_path_lock);
+	if (route == audio_rx_path_id)
+		goto done;
+
+	audio_rx_path_id = route;
+
+	if (audio_rx_path_refcount > 0) {
+		_audio_rx_path_disable();
+		_audio_rx_path_enable();
+	}
+	if (audio_tx_path_refcount > 0) {
+		_audio_tx_path_disable();
+		_audio_tx_path_enable();
+	}
+done:
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+struct audio_client *q6audio_open(uint32_t flags, uint32_t bufsz)
+{
+	struct audio_client *ac;
+
+	if (q6audio_init())
+		return 0;
+
+	ac = audio_client_alloc(bufsz);
+	if (!ac)
+		return 0;
+
+	ac->flags = flags;
+	if (ac->flags & AUDIO_FLAG_WRITE)
+		audio_rx_path_enable(1);
+	else
+		audio_tx_path_enable(1);
+
+	return ac;
+}
+
+int q6audio_start(struct audio_client *ac, void *rpc,
+						uint32_t len)
+{
+
+	audio_ioctl(ac, rpc, len);
+
+	audio_command(ac, ADSP_AUDIO_IOCTL_CMD_SESSION_START);
+
+	if (!(ac->flags & AUDIO_FLAG_WRITE)) {
+		ac->buf[0].used = 1;
+		ac->buf[1].used = 1;
+		q6audio_read(ac, &ac->buf[0]);
+		q6audio_read(ac, &ac->buf[1]);
+	}
+
+	audio_prevent_sleep();
+	return 0;
+}
+
+int q6audio_close(struct audio_client *ac)
+{
+	audio_close(ac);
+
+	if (ac->flags & AUDIO_FLAG_WRITE)
+		audio_rx_path_enable(0);
+	else
+		audio_tx_path_enable(0);
+
+	audio_client_free(ac);
+	audio_allow_sleep();
+	return 0;
+}
+
+struct audio_client *q6voice_open(void)
+{
+	struct audio_client *ac;
+
+	if (q6audio_init())
+		return 0;
+
+	ac = audio_client_alloc(0);
+	if (!ac)
+		return 0;
+
+	return ac;
+}
+
+int q6voice_setup(void)
+{
+	audio_rx_path_enable(1);
+	tx_clk_freq = 8000;
+	audio_tx_path_enable(1);
+
+	return 0;
+}
+
+int q6voice_teardown(void)
+{
+	audio_rx_path_enable(0);
+	audio_tx_path_enable(0);
+	return 0;
+}
+
+
+int q6voice_close(struct audio_client *ac)
+{
+	audio_client_free(ac);
+	return 0;
+}
+
+int q6audio_async(struct audio_client *ac)
+{
+	struct adsp_command_hdr rpc;
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.opcode = ADSP_AUDIO_IOCTL_CMD_STREAM_EOS;
+	rpc.response_type = ADSP_AUDIO_RESPONSE_ASYNC;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/q6audio_devices.h b/arch/arm/mach-msm/qdsp6/audiov2/q6audio_devices.h
new file mode 100644
index 0000000..aa8a699
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/q6audio_devices.h
@@ -0,0 +1,276 @@
+/* arch/arm/mach-msm/qdsp6/audiov2/q6audio_devices.h
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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.
+ *
+ */
+
+struct q6_device_info {
+	uint32_t id;
+	uint32_t cad_id;
+	uint32_t path;
+	uint32_t rate;
+	uint8_t dir;
+	uint8_t codec;
+	uint8_t hw;
+};
+
+#define Q6_ICODEC_RX		0
+#define Q6_ICODEC_TX		1
+#define Q6_ECODEC_RX		2
+#define Q6_ECODEC_TX		3
+#define Q6_SDAC_RX		6
+#define Q6_SDAC_TX		7
+#define Q6_CODEC_NONE		255
+
+#define Q6_TX		1
+#define Q6_RX		2
+#define Q6_TX_RX	3
+
+#define Q6_HW_HANDSET	0
+#define Q6_HW_HEADSET	1
+#define Q6_HW_SPEAKER	2
+#define Q6_HW_TTY	3
+#define Q6_HW_BT_SCO	4
+#define Q6_HW_BT_A2DP	5
+
+#define Q6_HW_COUNT	6
+
+#define CAD_HW_DEVICE_ID_HANDSET_MIC		0x01
+#define CAD_HW_DEVICE_ID_HANDSET_SPKR		0x02
+#define CAD_HW_DEVICE_ID_HEADSET_MIC		0x03
+#define CAD_HW_DEVICE_ID_HEADSET_SPKR_MONO	0x04
+#define CAD_HW_DEVICE_ID_HEADSET_SPKR_STEREO	0x05
+#define CAD_HW_DEVICE_ID_SPKR_PHONE_MIC		0x06
+#define CAD_HW_DEVICE_ID_SPKR_PHONE_MONO	0x07
+#define CAD_HW_DEVICE_ID_SPKR_PHONE_STEREO	0x08
+#define CAD_HW_DEVICE_ID_BT_SCO_MIC		0x09
+#define CAD_HW_DEVICE_ID_BT_SCO_SPKR		0x0A
+#define CAD_HW_DEVICE_ID_BT_A2DP_SPKR		0x0B
+#define CAD_HW_DEVICE_ID_TTY_HEADSET_MIC	0x0C
+#define CAD_HW_DEVICE_ID_TTY_HEADSET_SPKR	0x0D
+
+#define CAD_HW_DEVICE_ID_DEFAULT_TX		0x0E
+#define CAD_HW_DEVICE_ID_DEFAULT_RX		0x0F
+
+/* Logical Device to indicate A2DP routing */
+#define CAD_HW_DEVICE_ID_BT_A2DP_TX             0x10
+#define CAD_HW_DEVICE_ID_HEADSET_MONO_PLUS_SPKR_MONO_RX		0x11
+#define CAD_HW_DEVICE_ID_HEADSET_MONO_PLUS_SPKR_STEREO_RX	0x12
+#define CAD_HW_DEVICE_ID_HEADSET_STEREO_PLUS_SPKR_MONO_RX	0x13
+#define CAD_HW_DEVICE_ID_HEADSET_STEREO_PLUS_SPKR_STEREO_RX	0x14
+
+#define CAD_HW_DEVICE_ID_VOICE			0x15
+
+#define CAD_HW_DEVICE_ID_I2S_RX                 0x20
+#define CAD_HW_DEVICE_ID_I2S_TX                 0x21
+
+/* AUXPGA */
+#define CAD_HW_DEVICE_ID_HEADSET_SPKR_STEREO_LB 0x22
+#define CAD_HW_DEVICE_ID_HEADSET_SPKR_MONO_LB   0x23
+#define CAD_HW_DEVICE_ID_SPEAKER_SPKR_STEREO_LB 0x24
+#define CAD_HW_DEVICE_ID_SPEAKER_SPKR_MONO_LB   0x25
+
+#define CAD_HW_DEVICE_ID_NULL_RX		0x2A
+
+#define CAD_HW_DEVICE_ID_MAX_NUM                0x2F
+
+#define CAD_HW_DEVICE_ID_INVALID                0xFF
+
+#define CAD_RX_DEVICE  0x00
+#define CAD_TX_DEVICE  0x01
+
+static struct q6_device_info q6_audio_devices[] = {
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_HANDSET_SPKR,
+		.cad_id	= CAD_HW_DEVICE_ID_HANDSET_SPKR,
+		.path	= ADIE_PATH_HANDSET_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_HANDSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_MONO,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_SPKR_MONO,
+		.path	= ADIE_PATH_HEADSET_MONO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_HEADSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_STEREO,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_SPKR_STEREO,
+		.path	= ADIE_PATH_HEADSET_STEREO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_HEADSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO,
+		.cad_id	= CAD_HW_DEVICE_ID_SPKR_PHONE_MONO,
+		.path	= ADIE_PATH_SPEAKER_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_HEADSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO,
+		.cad_id	= CAD_HW_DEVICE_ID_SPKR_PHONE_STEREO,
+		.path	= ADIE_PATH_SPEAKER_STEREO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_MONO_HEADSET,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_MONO_PLUS_SPKR_MONO_RX,
+		.path	= ADIE_PATH_SPKR_MONO_HDPH_MONO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_STEREO_HEADSET,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_MONO_PLUS_SPKR_STEREO_RX,
+		.path	= ADIE_PATH_SPKR_MONO_HDPH_STEREO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_MONO_HEADSET,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_STEREO_PLUS_SPKR_MONO_RX,
+		.path	= ADIE_PATH_SPKR_STEREO_HDPH_MONO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id = ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_STEREO_HEADSET,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_STEREO_PLUS_SPKR_STEREO_RX,
+		.path	= ADIE_PATH_SPKR_STEREO_HDPH_STEREO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_SPKR,
+		.cad_id	= CAD_HW_DEVICE_ID_TTY_HEADSET_SPKR,
+		.path	= ADIE_PATH_TTY_HEADSET_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_TTY,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_HANDSET_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_HANDSET_MIC,
+		.path	= ADIE_PATH_HANDSET_TX,
+		.rate   = 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ICODEC_TX,
+		.hw	= Q6_HW_HANDSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_HEADSET_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_MIC,
+		.path	= ADIE_PATH_HEADSET_MONO_TX,
+		.rate   = 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ICODEC_TX,
+		.hw	= Q6_HW_HEADSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_SPKR_PHONE_MIC,
+		.path	= ADIE_PATH_SPEAKER_TX,
+		.rate   = 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ICODEC_TX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_TTY_HEADSET_MIC,
+		.path	= ADIE_PATH_TTY_HEADSET_TX,
+		.rate   = 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ICODEC_TX,
+		.hw	= Q6_HW_HEADSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_BT_SCO_SPKR,
+		.cad_id	= CAD_HW_DEVICE_ID_BT_SCO_SPKR,
+		.path	= 0, /* XXX */
+		.rate   = 8000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ECODEC_RX,
+		.hw	= Q6_HW_BT_SCO,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_BT_A2DP_SPKR,
+		.cad_id	= CAD_HW_DEVICE_ID_BT_A2DP_SPKR,
+		.path	= 0, /* XXX */
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ECODEC_RX,
+		.hw	= Q6_HW_BT_A2DP,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_BT_SCO_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_BT_SCO_MIC,
+		.path	= 0, /* XXX */
+		.rate   = 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ECODEC_TX,
+		.hw	= Q6_HW_BT_SCO,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_I2S_SPKR,
+		.cad_id	= CAD_HW_DEVICE_ID_I2S_RX,
+		.path	= 0, /* XXX */
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_SDAC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_I2S_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_I2S_TX,
+		.path	= 0, /* XXX */
+		.rate   = 16000,
+		.dir	= Q6_TX,
+		.codec	= Q6_SDAC_TX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= 0,
+		.cad_id	= 0,
+		.path	= 0,
+		.rate   = 8000,
+		.dir	= 0,
+		.codec	= Q6_CODEC_NONE,
+		.hw	= 0,
+	},
+};
+
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/qcelp_in.c b/arch/arm/mach-msm/qdsp6/audiov2/qcelp_in.c
new file mode 100644
index 0000000..a13084f
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/qcelp_in.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio_qcp.h>
+#include <mach/msm_qdsp6_audiov2.h>
+#include "dal_audio.h"
+#include "dal_audio_format.h"
+#include <mach/debug_mm.h>
+
+
+struct qcelp {
+	struct mutex lock;
+	struct msm_audio_qcelp_enc_config cfg;
+	struct msm_audio_stream_config str_cfg;
+	struct audio_client *audio_client;
+};
+
+
+static long q6_qcelp_in_ioctl(struct file *file, unsigned int cmd,
+				 unsigned long arg)
+{
+	struct qcelp *qcelp = file->private_data;
+	struct adsp_open_command rpc;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	mutex_lock(&qcelp->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		if (qcelp->audio_client) {
+			rc = -EBUSY;
+			break;
+		} else {
+			qcelp->audio_client = q6audio_open(AUDIO_FLAG_READ,
+						qcelp->str_cfg.buffer_size);
+
+			if (!qcelp->audio_client) {
+				kfree(qcelp);
+				rc = -ENOMEM;
+				break;
+			}
+		}
+
+		tx_clk_freq = 8000;
+
+		memset(&rpc, 0, sizeof(rpc));
+
+		rpc.format_block.standard.format = ADSP_AUDIO_FORMAT_V13K_FS;
+		rpc.format_block.standard.channels = 1;
+		rpc.format_block.standard.bits_per_sample = 16;
+		rpc.format_block.standard.sampling_rate = 8000;
+		rpc.format_block.standard.is_signed = 1;
+		rpc.format_block.standard.is_interleaved = 0;
+		rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_READ;
+		rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+		rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD;
+		rpc.buf_max_size = qcelp->str_cfg.buffer_size;
+		rpc.config.qcelp13k.min_rate = qcelp->cfg.min_bit_rate;
+		rpc.config.qcelp13k.max_rate = qcelp->cfg.max_bit_rate;
+
+		q6audio_start(qcelp->audio_client, &rpc, sizeof(rpc));
+		break;
+	case AUDIO_STOP:
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_VOLUME:
+		break;
+	case AUDIO_GET_STREAM_CONFIG:
+		if (copy_to_user((void *)arg, &qcelp->str_cfg,
+				sizeof(struct msm_audio_stream_config)))
+			rc = -EFAULT;
+		break;
+	case AUDIO_SET_STREAM_CONFIG:
+		if (copy_from_user(&qcelp->str_cfg, (void *)arg,
+			sizeof(struct msm_audio_stream_config))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		if (qcelp->str_cfg.buffer_size < 35) {
+			pr_err("[%s:%s] Buffer size too small\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+			break;
+		}
+
+		if (qcelp->str_cfg.buffer_count != 2)
+			pr_info("[%s:%s] Buffer count set to 2\n", __MM_FILE__,
+					__func__);
+		break;
+	case AUDIO_SET_QCELP_ENC_CONFIG:
+		if (copy_from_user(&qcelp->cfg, (void *) arg,
+				sizeof(struct msm_audio_qcelp_enc_config)))
+			rc = -EFAULT;
+
+		if (qcelp->cfg.min_bit_rate > 4 ||
+			 qcelp->cfg.min_bit_rate < 1) {
+
+			pr_err("[%s:%s] invalid min bitrate\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+		}
+		if (qcelp->cfg.max_bit_rate > 4 ||
+			 qcelp->cfg.max_bit_rate < 1) {
+
+			pr_err("[%s:%s] invalid max bitrate\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+		}
+
+		break;
+	case AUDIO_GET_QCELP_ENC_CONFIG:
+		if (copy_to_user((void *) arg, &qcelp->cfg,
+			 sizeof(struct msm_audio_qcelp_enc_config)))
+			rc = -EFAULT;
+		break;
+
+	default:
+		rc = -EINVAL;
+	}
+
+	mutex_unlock(&qcelp->lock);
+	return rc;
+}
+
+static int q6_qcelp_in_open(struct inode *inode, struct file *file)
+{
+	struct qcelp *qcelp;
+	qcelp = kmalloc(sizeof(struct qcelp), GFP_KERNEL);
+	if (qcelp == NULL) {
+		pr_err("[%s:%s] Could not allocate memory for qcelp driver\n",
+				__MM_FILE__, __func__);
+		return -ENOMEM;
+	}
+
+	mutex_init(&qcelp->lock);
+	file->private_data = qcelp;
+	qcelp->audio_client = NULL;
+	qcelp->str_cfg.buffer_size = 35;
+	qcelp->str_cfg.buffer_count = 2;
+	qcelp->cfg.cdma_rate = CDMA_RATE_FULL;
+	qcelp->cfg.min_bit_rate = 1;
+	qcelp->cfg.max_bit_rate = 4;
+	return 0;
+}
+
+static ssize_t q6_qcelp_in_read(struct file *file, char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	const char __user *start = buf;
+	struct qcelp *qcelp = file->private_data;
+	int xfer = 0;
+	int res;
+
+	mutex_lock(&qcelp->lock);
+	ac = qcelp->audio_client;
+	if (!ac) {
+		res = -ENODEV;
+		goto fail;
+	}
+	while (count > xfer) {
+		ab = ac->buf + ac->cpu_buf;
+
+		if (ab->used)
+			wait_event(ac->wait, (ab->used == 0));
+
+		xfer = ab->actual_size;
+
+		if (copy_to_user(buf, ab->data, xfer)) {
+			res = -EFAULT;
+			goto fail;
+		}
+
+		buf += xfer;
+		count -= xfer;
+
+		ab->used = 1;
+		q6audio_read(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+
+	res = buf - start;
+
+fail:
+	mutex_unlock(&qcelp->lock);
+
+	return res;
+}
+
+static int q6_qcelp_in_release(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	struct qcelp *qcelp = file->private_data;
+
+	mutex_lock(&qcelp->lock);
+	if (qcelp->audio_client)
+		rc = q6audio_close(qcelp->audio_client);
+	mutex_unlock(&qcelp->lock);
+	kfree(qcelp);
+	return rc;
+}
+
+static const struct file_operations q6_qcelp_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_qcelp_in_open,
+	.read		= q6_qcelp_in_read,
+	.release	= q6_qcelp_in_release,
+	.unlocked_ioctl	= q6_qcelp_in_ioctl,
+};
+
+struct miscdevice q6_qcelp_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_qcelp_in",
+	.fops	= &q6_qcelp_in_fops,
+};
+
+static int __init q6_qcelp_in_init(void)
+{
+	return misc_register(&q6_qcelp_in_misc);
+}
+
+device_initcall(q6_qcelp_in_init);
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/routing.c b/arch/arm/mach-msm/qdsp6/audiov2/routing.c
new file mode 100644
index 0000000..1a2476b
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/routing.c
@@ -0,0 +1,73 @@
+/* arch/arm/mach-msm/qdsp6/audiov2/routing.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <mach/msm_qdsp6_audiov2.h>
+
+static int q6_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static ssize_t q6_write(struct file *file, const char __user *buf,
+			size_t count, loff_t *pos)
+{
+	char cmd[32];
+
+	if (count >= sizeof(cmd))
+		return -EINVAL;
+	if (copy_from_user(cmd, buf, count))
+		return -EFAULT;
+	cmd[count] = 0;
+
+	if ((count > 1) && (cmd[count-1] == '\n'))
+		cmd[count-1] = 0;
+
+	q6audio_set_route(cmd);
+
+	return count;
+}
+
+static int q6_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static const struct file_operations q6_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_open,
+	.write		= q6_write,
+	.release	= q6_release,
+};
+
+static struct miscdevice q6_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_audio_route",
+	.fops	= &q6_fops,
+};
+
+
+static int __init q6_init(void)
+{
+	return misc_register(&q6_misc);
+}
+
+device_initcall(q6_init);
diff --git a/arch/arm/mach-msm/qdsp6/audiov2/voice.c b/arch/arm/mach-msm/qdsp6/audiov2/voice.c
new file mode 100644
index 0000000..906c534
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/audiov2/voice.c
@@ -0,0 +1,188 @@
+/* Copyright (c) 2010, 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/kernel.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include <linux/completion.h>
+#include <linux/wait.h>
+#include <mach/msm_qdsp6_audiov2.h>
+#include "../dal.h"
+#include "dal_voice.h"
+#include <mach/debug_mm.h>
+
+struct voice_struct {
+	struct dal_client *cvd;
+	struct apr_command_pkt apr_pkt;
+	struct completion compl;
+};
+
+static struct voice_struct voice;
+
+static int cvd_send_response(void)
+{
+	struct apr_command_pkt *pkt;
+	uint16_t src_addr;
+	uint16_t src_token;
+	uint16_t dst_token;
+	uint16_t dst_addr;
+
+	pkt = &voice.apr_pkt;
+	src_addr = pkt->dst_addr;
+	dst_addr = pkt->src_addr;
+	src_token = pkt->dst_token;
+	dst_token = pkt->src_token;
+
+	pkt->header &= ~APR_PKTV1_TYPE_MASK;
+	pkt->header |= APR_SET_FIELD(APR_PKTV1_TYPE, APR_PKTV1_TYPE_EVENT_V);
+	pkt->src_addr = src_addr;
+	pkt->dst_addr = dst_addr;
+	pkt->src_token = src_token;
+	pkt->dst_token = dst_token;
+	pkt->opcode = APR_IBASIC_RSP_RESULT;
+
+	dal_call(voice.cvd, VOICE_OP_CONTROL, 5, pkt,
+			sizeof(struct apr_command_pkt),
+			pkt, sizeof(u32));
+	return 0;
+}
+
+static int cvd_process_voice_setup(void)
+{
+	q6voice_setup();
+	cvd_send_response();
+	return 0;
+}
+
+static int cvd_process_voice_teardown(void)
+{
+	q6voice_teardown();
+	cvd_send_response();
+	return 0;
+}
+
+static int cvd_process_set_network(void)
+{
+	cvd_send_response();
+	return 0;
+}
+
+static int voice_thread(void *data)
+{
+	while (!kthread_should_stop()) {
+		wait_for_completion(&voice.compl);
+		init_completion(&voice.compl);
+
+		switch (voice.apr_pkt.opcode) {
+
+		case APR_OP_CMD_CREATE:
+			cvd_send_response();
+			break;
+		case VOICE_OP_CMD_BRINGUP:
+			cvd_process_voice_setup();
+			break;
+		case APR_OP_CMD_DESTROY:
+			cvd_send_response();
+			break;
+		case VOICE_OP_CMD_TEARDOWN:
+			cvd_process_voice_teardown();
+			break;
+		case VOICE_OP_CMD_SET_NETWORK:
+			cvd_process_set_network();
+			break;
+		default:
+			pr_err("[%s:%s] Undefined event\n", __MM_FILE__,
+					__func__);
+
+		}
+	}
+	return 0;
+}
+
+static void remote_cb_function(void *data, int len, void *cookie)
+{
+	struct apr_command_pkt *apr = data + 2*sizeof(uint32_t);
+
+	memcpy(&voice.apr_pkt, apr, sizeof(struct apr_command_pkt));
+
+	if (len <= 0) {
+		pr_err("[%s:%s] unexpected event with length %d\n",
+				__MM_FILE__, __func__, len);
+		return;
+	}
+
+	pr_debug("[%s:%s] APR = %x,%x,%x,%x,%x,%x,%x,%x,%x,%x\n", __MM_FILE__,
+			__func__,
+	apr->header,
+	apr->reserved1,
+	apr->src_addr,
+	apr->dst_addr,
+	apr->ret_addr,
+	apr->src_token,
+	apr->dst_token,
+	apr->ret_token,
+	apr->context,
+	apr->opcode);
+
+	complete(&voice.compl);
+}
+
+static int __init voice_init(void)
+{
+	int res = 0;
+	struct task_struct *task;
+	u32 tmp[2];
+
+	tmp[0] = sizeof(u32);
+	tmp[1] = 0;
+
+	voice.cvd = dal_attach(VOICE_DAL_DEVICE, VOICE_DAL_PORT, 0,
+			remote_cb_function, 0);
+
+	if (!voice.cvd) {
+		pr_err("[%s:%s] audio_init: cannot attach to cvd\n",
+				__MM_FILE__, __func__);
+		res = -ENODEV;
+		goto done;
+	}
+
+	if (check_version(voice.cvd, VOICE_DAL_VERSION) != 0) {
+		pr_err("[%s:%s] Incompatible cvd version\n",
+				__MM_FILE__, __func__);
+		res = -ENODEV;
+		goto done;
+	}
+	dal_call(voice.cvd, VOICE_OP_INIT, 5, tmp, sizeof(tmp),
+		tmp, sizeof(u32));
+
+	init_completion(&voice.compl);
+	task = kthread_run(voice_thread, &voice, "voice_thread");
+
+	if (IS_ERR(task)) {
+		pr_err("[%s:%s] Cannot start the voice thread\n", __MM_FILE__,
+				__func__);
+		res = PTR_ERR(task);
+		task = NULL;
+	} else
+		goto done;
+
+done:
+	return res;
+}
+
+late_initcall(voice_init);
diff --git a/arch/arm/mach-msm/qdsp6/auxpcm_lb_in.c b/arch/arm/mach-msm/qdsp6/auxpcm_lb_in.c
new file mode 100644
index 0000000..4195454
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/auxpcm_lb_in.c
@@ -0,0 +1,190 @@
+/* arch/arm/mach-msm/qdsp6/auxpcm_lb_in.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ * Copyright (c) 2010, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio.h>
+
+#include <mach/msm_qdsp6_audio.h>
+#include <mach/debug_mm.h>
+
+struct auxpcm {
+	struct mutex lock;
+	struct audio_client *ac;
+	uint32_t sample_rate;
+	uint32_t channel_count;
+	int opened;;
+};
+
+static long auxpcmin_ioctl(struct file *file, unsigned int cmd,
+		unsigned long arg)
+{
+	struct auxpcm *auxpcmin = file->private_data;
+	int rc = 0;
+
+	mutex_lock(&auxpcmin->lock);
+	switch (cmd) {
+	case AUDIO_START: {
+		uint32_t acdb_id;
+		pr_debug("[%s:%s] AUDIO_START\n", __MM_FILE__, __func__);
+		if (arg == 0) {
+			acdb_id = 0;
+		} else if (copy_from_user(&acdb_id, (void *) arg,
+					sizeof(acdb_id))) {
+			pr_info("[%s:%s] copy acdb_id from user failed\n",
+					__MM_FILE__, __func__);
+			rc = -EFAULT;
+			break;
+		}
+		if (auxpcmin->ac) {
+			pr_err("[%s:%s] active session already existing\n",
+				__MM_FILE__, __func__);
+			rc = -EBUSY;
+		} else {
+			auxpcmin->ac =
+				q6audio_open_auxpcm(auxpcmin->sample_rate,
+						auxpcmin->channel_count,
+						AUDIO_FLAG_READ, acdb_id);
+			if (!auxpcmin->ac) {
+				pr_err("[%s:%s] auxpcm open session failed\n",
+					__MM_FILE__, __func__);
+				rc = -ENOMEM;
+			}
+		}
+		break;
+	}
+	case AUDIO_STOP:
+		pr_debug("[%s:%s] AUDIO_STOP\n", __MM_FILE__, __func__);
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (auxpcmin->ac) {
+			rc = -EBUSY;
+			pr_err("[%s:%s] active session already existing\n",
+				__MM_FILE__, __func__);
+			break;
+		}
+		if (copy_from_user(&config, (void *) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("[%s:%s] SET_CONFIG: samplerate = %d, channels = %d\n",
+			__MM_FILE__, __func__, config.sample_rate,
+			config.channel_count);
+		if (config.channel_count != 1) {
+			rc = -EINVAL;
+			pr_err("[%s:%s] invalid channelcount %d\n",
+				__MM_FILE__, __func__, config.channel_count);
+			break;
+		}
+		if (config.sample_rate != 8000) {
+			rc = -EINVAL;
+			pr_err("[%s:%s] invalid samplerate %d\n", __MM_FILE__,
+				__func__, config.sample_rate);
+			break;
+		}
+		auxpcmin->sample_rate = config.sample_rate;
+		auxpcmin->channel_count = config.channel_count;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_size = 0;
+		config.buffer_count = 0;
+		config.sample_rate = auxpcmin->sample_rate;
+		config.channel_count = auxpcmin->channel_count;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void *) arg, &config, sizeof(config)))
+			rc = -EFAULT;
+		pr_debug("[%s:%s] GET_CONFIG: samplerate = %d, channels = %d\n",
+			__MM_FILE__, __func__, config.sample_rate,
+			config.channel_count);
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&auxpcmin->lock);
+	pr_debug("[%s:%s] rc = %d\n", __MM_FILE__, __func__, rc);
+	return rc;
+}
+
+static struct auxpcm the_auxpcmin;
+
+static int auxpcmin_open(struct inode *inode, struct file *file)
+{
+	struct auxpcm *auxpcmin = &the_auxpcmin;
+
+	pr_info("[%s:%s] open\n", __MM_FILE__, __func__);
+	mutex_lock(&auxpcmin->lock);
+	if (auxpcmin->opened) {
+		pr_err("aux pcm loopback tx already open!\n");
+		mutex_unlock(&auxpcmin->lock);
+		return -EBUSY;
+	}
+	auxpcmin->channel_count = 1;
+	auxpcmin->sample_rate = 8000;
+	auxpcmin->opened = 1;
+	file->private_data = auxpcmin;
+	mutex_unlock(&auxpcmin->lock);
+	return 0;
+}
+
+static int auxpcmin_release(struct inode *inode, struct file *file)
+{
+	struct auxpcm *auxpcmin = file->private_data;
+	mutex_lock(&auxpcmin->lock);
+	if (auxpcmin->ac)
+		q6audio_auxpcm_close(auxpcmin->ac);
+	auxpcmin->ac = NULL;
+	auxpcmin->opened = 0;
+	mutex_unlock(&auxpcmin->lock);
+	pr_info("[%s:%s] release\n", __MM_FILE__, __func__);
+	return 0;
+}
+
+static const struct file_operations auxpcmin_fops = {
+	.owner		= THIS_MODULE,
+	.open		= auxpcmin_open,
+	.release	= auxpcmin_release,
+	.unlocked_ioctl	= auxpcmin_ioctl,
+};
+
+struct miscdevice auxpcmin_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_aux_pcm_lb_in",
+	.fops	= &auxpcmin_fops,
+};
+
+static int __init auxpcmin_init(void)
+{
+	mutex_init(&the_auxpcmin.lock);
+	return misc_register(&auxpcmin_misc);
+}
+
+device_initcall(auxpcmin_init);
diff --git a/arch/arm/mach-msm/qdsp6/auxpcm_lb_out.c b/arch/arm/mach-msm/qdsp6/auxpcm_lb_out.c
new file mode 100644
index 0000000..b680597
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/auxpcm_lb_out.c
@@ -0,0 +1,191 @@
+/* arch/arm/mach-msm/qdsp6/auxpcm_lb_out.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ * Copyright (c) 2010, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio.h>
+
+#include <mach/msm_qdsp6_audio.h>
+#include <mach/debug_mm.h>
+
+struct auxpcm {
+	struct mutex lock;
+	struct audio_client *ac;
+	uint32_t sample_rate;
+	uint32_t channel_count;
+	int opened;;
+};
+
+static long auxpcmout_ioctl(struct file *file, unsigned int cmd,
+				unsigned long arg)
+{
+	struct auxpcm *auxpcmout = file->private_data;
+	int rc = 0;
+
+	mutex_lock(&auxpcmout->lock);
+	switch (cmd) {
+	case AUDIO_START: {
+		uint32_t acdb_id;
+		pr_debug("[%s:%s] AUDIO_START\n", __MM_FILE__, __func__);
+		if (arg == 0) {
+			acdb_id = 0;
+		} else if (copy_from_user(&acdb_id, (void *) arg,
+					sizeof(acdb_id))) {
+			pr_info("[%s:%s] copy acdb_id from user failed\n",
+					__MM_FILE__, __func__);
+			rc = -EFAULT;
+			break;
+		}
+		if (auxpcmout->ac) {
+			rc = -EBUSY;
+			pr_err("[%s:%s] active session already existing\n",
+				__MM_FILE__, __func__);
+		} else {
+			auxpcmout->ac =
+				q6audio_open_auxpcm(auxpcmout->sample_rate,
+						auxpcmout->channel_count,
+						AUDIO_FLAG_WRITE, acdb_id);
+			if (!auxpcmout->ac) {
+				pr_err("[%s:%s] auxpcm open session failed\n",
+					__MM_FILE__, __func__);
+				rc = -ENOMEM;
+			}
+		}
+		break;
+	}
+	case AUDIO_STOP:
+		pr_debug("[%s:%s] AUDIO_STOP\n", __MM_FILE__, __func__);
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (auxpcmout->ac) {
+			rc = -EBUSY;
+			pr_err("[%s:%s] active session already existing\n",
+				__MM_FILE__, __func__);
+			break;
+		}
+		if (copy_from_user(&config, (void *) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("[%s:%s] SET_CONFIG: samplerate = %d, channels = %d\n",
+			__MM_FILE__, __func__, config.sample_rate,
+			config.channel_count);
+		if (config.channel_count != 1) {
+			rc = -EINVAL;
+			pr_err("[%s:%s] invalid channelcount %d\n",
+			__MM_FILE__, __func__, config.channel_count);
+			break;
+		}
+		if (config.sample_rate != 8000) {
+			rc = -EINVAL;
+			pr_err("[%s:%s] invalid samplerate %d\n", __MM_FILE__,
+				__func__, config.sample_rate);
+			break;
+		}
+		auxpcmout->sample_rate = config.sample_rate;
+		auxpcmout->channel_count = config.channel_count;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_size = 0;
+		config.buffer_count = 0;
+		config.sample_rate = auxpcmout->sample_rate;
+		config.channel_count = auxpcmout->channel_count;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void *) arg, &config, sizeof(config)))
+			rc = -EFAULT;
+		pr_debug("[%s:%s] GET_CONFIG: samplerate = %d, channels= %d\n",
+			__MM_FILE__, __func__, config.sample_rate,
+			config.channel_count);
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&auxpcmout->lock);
+	pr_debug("[%s:%s] rc = %d\n", __MM_FILE__, __func__, rc);
+	return rc;
+}
+
+static struct auxpcm the_auxpcmout;
+
+static int auxpcmout_open(struct inode *inode, struct file *file)
+{
+	struct auxpcm *auxpcmout = &the_auxpcmout;
+
+	pr_info("[%s:%s] open\n", __MM_FILE__, __func__);
+
+	mutex_lock(&auxpcmout->lock);
+
+	if (auxpcmout->opened) {
+		pr_err("aux pcm loopback rx already open!\n");
+		mutex_unlock(&auxpcmout->lock);
+		return -EBUSY;
+	}
+	auxpcmout->channel_count = 1;
+	auxpcmout->sample_rate = 8000;
+	auxpcmout->opened = 1;
+	file->private_data = auxpcmout;
+	mutex_unlock(&auxpcmout->lock);
+	return 0;
+}
+
+static int auxpcmout_release(struct inode *inode, struct file *file)
+{
+	struct auxpcm *auxpcmout = file->private_data;
+	mutex_lock(&auxpcmout->lock);
+	if (auxpcmout->ac)
+		q6audio_auxpcm_close(auxpcmout->ac);
+	auxpcmout->ac = NULL;
+	auxpcmout->opened = 0;
+	mutex_unlock(&auxpcmout->lock);
+	pr_info("[%s:%s] release\n", __MM_FILE__, __func__);
+	return 0;
+}
+
+static const struct file_operations auxpcmout_fops = {
+	.owner		= THIS_MODULE,
+	.open		= auxpcmout_open,
+	.release	= auxpcmout_release,
+	.unlocked_ioctl	= auxpcmout_ioctl,
+};
+
+struct miscdevice auxpcmout_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_aux_pcm_lb_out",
+	.fops	= &auxpcmout_fops,
+};
+
+static int __init auxpcmout_init(void)
+{
+	mutex_init(&the_auxpcmout.lock);
+	return misc_register(&auxpcmout_misc);
+}
+
+device_initcall(auxpcmout_init);
diff --git a/arch/arm/mach-msm/qdsp6/dal.c b/arch/arm/mach-msm/qdsp6/dal.c
new file mode 100644
index 0000000..378432b
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/dal.c
@@ -0,0 +1,727 @@
+/* arch/arm/mach-msm/qdsp6/dal.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/errno.h>
+
+#include <linux/delay.h>
+
+#include <mach/msm_smd.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_qdsp6_audio.h>
+
+#include "dal.h"
+
+#define DAL_TRACE 0
+
+struct dal_hdr {
+	uint32_t length:16;	/* message length (header inclusive) */
+	uint32_t version:8;	/* DAL protocol version */
+	uint32_t priority:7;
+	uint32_t async:1;
+	uint32_t ddi:16;	/* DDI method number */
+	uint32_t prototype:8;	/* DDI serialization format */
+	uint32_t msgid:8;	/* message id (DDI, ATTACH, DETACH, ...) */
+	void *from;
+	void *to;
+} __attribute__((packed));
+
+#define TRACE_DATA_MAX	128
+#define TRACE_LOG_MAX	32
+#define TRACE_LOG_MASK	(TRACE_LOG_MAX - 1)
+
+struct dal_trace {
+	unsigned timestamp;
+	struct dal_hdr hdr;
+	uint32_t data[TRACE_DATA_MAX];
+};
+
+#define DAL_HDR_SIZE		(sizeof(struct dal_hdr))
+#define DAL_DATA_MAX		512
+#define DAL_MSG_MAX		(DAL_HDR_SIZE + DAL_DATA_MAX)
+
+#define DAL_VERSION		0x11
+
+#define DAL_MSGID_DDI		0x00
+#define DAL_MSGID_ATTACH	0x01
+#define DAL_MSGID_DETACH	0x02
+#define DAL_MSGID_ASYNCH	0xC0
+#define DAL_MSGID_REPLY		0x80
+
+struct dal_channel {
+	struct list_head list;
+	struct list_head clients;
+
+	/* synchronization for changing channel state,
+	 * adding/removing clients, smd callbacks, etc
+	 */
+	spinlock_t lock;
+
+	struct smd_channel *sch;
+	char *name;
+
+	/* events are delivered at IRQ context immediately, so
+	 * we only need one assembly buffer for the entire channel
+	 */
+	struct dal_hdr hdr;
+	unsigned char data[DAL_DATA_MAX];
+
+	unsigned count;
+	void *ptr;
+
+	/* client which the current inbound message is for */
+	struct dal_client *active;
+};
+
+struct dal_client {
+	struct list_head list;
+	struct dal_channel *dch;
+	void *cookie;
+	dal_event_func_t event;
+
+	/* opaque handle for the far side */
+	void *remote;
+
+	/* dal rpc calls are fully synchronous -- only one call may be
+	 * active per client at a time
+	 */
+	struct mutex write_lock;
+	wait_queue_head_t wait;
+
+	unsigned char data[DAL_DATA_MAX];
+
+	void *reply;
+	int reply_max;
+	int status;
+	unsigned msgid; /* msgid of expected reply */
+
+	spinlock_t tr_lock;
+	unsigned tr_head;
+	unsigned tr_tail;
+	struct dal_trace *tr_log;
+};
+
+static unsigned now(void)
+{
+	struct timespec ts;
+	ktime_get_ts(&ts);
+	return (ts.tv_nsec / 1000000) + (ts.tv_sec * 1000);
+}
+
+void dal_trace(struct dal_client *c)
+{
+	if (c->tr_log)
+		return;
+	c->tr_log = kzalloc(sizeof(struct dal_trace) * TRACE_LOG_MAX,
+			    GFP_KERNEL);
+}
+
+void dal_trace_print(struct dal_hdr *hdr, unsigned *data, int len, unsigned when)
+{
+	int i;
+	printk("DAL %08x -> %08x L=%03x A=%d D=%04x P=%02x M=%02x T=%d",
+	       (unsigned) hdr->from, (unsigned) hdr->to,
+	       hdr->length, hdr->async,
+	       hdr->ddi, hdr->prototype, hdr->msgid,
+	       when);
+	len /= 4;
+	for (i = 0; i < len; i++) {
+		if (!(i & 7))
+			printk("\n%03x", i * 4);
+		printk(" %08x", data[i]);
+	}
+	printk("\n");
+}
+
+void dal_trace_dump(struct dal_client *c)
+{
+	struct dal_trace *dt;
+	unsigned n, len;
+
+	if (!c->tr_log)
+		return;
+
+	for (n = c->tr_tail; n != c->tr_head; n = (n + 1) & TRACE_LOG_MASK) {
+		dt = c->tr_log + n;
+		len = dt->hdr.length - sizeof(dt->hdr);
+		if (len > TRACE_DATA_MAX)
+			len = TRACE_DATA_MAX;
+		dal_trace_print(&dt->hdr, dt->data, len, dt->timestamp);
+	}
+}
+
+static void dal_trace_log(struct dal_client *c,
+			  struct dal_hdr *hdr, void *data, unsigned len)
+{
+	unsigned long flags;
+	unsigned t, n;
+	struct dal_trace *dt;
+
+	t = now();
+	if (len > TRACE_DATA_MAX)
+		len = TRACE_DATA_MAX;
+
+	spin_lock_irqsave(&c->tr_lock, flags);
+	n = (c->tr_head + 1) & TRACE_LOG_MASK;
+	if (c->tr_tail == n)
+		c->tr_tail = (c->tr_tail + 1) & TRACE_LOG_MASK;
+	dt = c->tr_log + n;
+	dt->timestamp = t;
+	memcpy(&dt->hdr, hdr, sizeof(struct dal_hdr));
+	memcpy(dt->data, data, len);
+	c->tr_head = n;
+
+	spin_unlock_irqrestore(&c->tr_lock, flags);
+}
+
+
+static void dal_channel_notify(void *priv, unsigned event)
+{
+	struct dal_channel *dch = priv;
+	struct dal_hdr *hdr = &dch->hdr;
+	struct dal_client *client;
+	unsigned long flags;
+	int len;
+	int r;
+
+	spin_lock_irqsave(&dch->lock, flags);
+
+again:
+	if (dch->count == 0) {
+		if (smd_read_avail(dch->sch) < DAL_HDR_SIZE)
+			goto done;
+
+		smd_read(dch->sch, hdr, DAL_HDR_SIZE);
+
+		if (hdr->length < DAL_HDR_SIZE)
+			goto done;
+
+		if (hdr->length > DAL_MSG_MAX)
+			panic("oversize message");
+
+		dch->count = hdr->length - DAL_HDR_SIZE;
+
+		/* locate the client this message is targeted to */
+		list_for_each_entry(client, &dch->clients, list) {
+			if (dch->hdr.to == client) {
+				dch->active = client;
+				dch->ptr = client->data;
+				goto check_data;
+			}
+		}
+		pr_err("[%s:%s] $$$ receiving unknown message len = %d $$$\n",
+				__MM_FILE__, __func__, dch->count);
+		dch->active = 0;
+		dch->ptr = dch->data;
+	}
+
+check_data:
+	len = dch->count;
+	if (len > 0) {
+		if (smd_read_avail(dch->sch) < len)
+			goto done;
+
+		r = smd_read(dch->sch, dch->ptr, len);
+		if (r != len)
+			panic("invalid read");
+
+#if DAL_TRACE
+		pr_info("[%s:%s] dal recv %p <- %p %02x:%04x:%02x %d\n",
+			__MM_FILE__, __func__, hdr->to, hdr->from, hdr->msgid,
+			hdr->ddi, hdr->prototype, hdr->length - sizeof(*hdr));
+		print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, dch->ptr, len);
+#endif
+		dch->count = 0;
+
+		client = dch->active;
+		if (!client) {
+			pr_err("[%s:%s] message to %p discarded\n",
+				__MM_FILE__, __func__, dch->hdr.to);
+			goto again;
+		}
+
+		if (client->tr_log)
+			dal_trace_log(client, hdr, dch->ptr, len);
+
+		if (hdr->msgid == DAL_MSGID_ASYNCH) {
+			if (client->event)
+				client->event(dch->ptr, len, client->cookie);
+			else
+				pr_err("[%s:%s] client %p has no event \
+					handler\n", __MM_FILE__, __func__,
+					client);
+			goto again;
+		}
+
+		if (hdr->msgid == client->msgid) {
+			if (!client->remote)
+				client->remote = hdr->from;
+			if (len > client->reply_max)
+				len = client->reply_max;
+			memcpy(client->reply, client->data, len);
+			client->status = len;
+			wake_up(&client->wait);
+			goto again;
+		}
+
+		pr_err("[%s:%s] cannot find client %p\n", __MM_FILE__,
+				__func__, dch->hdr.to);
+		goto again;
+	}
+
+done:
+	spin_unlock_irqrestore(&dch->lock, flags);
+}
+
+static LIST_HEAD(dal_channel_list);
+static DEFINE_MUTEX(dal_channel_list_lock);
+
+static struct dal_channel *dal_open_channel(const char *name, uint32_t cpu)
+{
+	struct dal_channel *dch;
+
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	mutex_lock(&dal_channel_list_lock);
+
+	list_for_each_entry(dch, &dal_channel_list, list) {
+		if (!strcmp(dch->name, name))
+			goto found_it;
+	}
+
+	dch = kzalloc(sizeof(*dch) + strlen(name) + 1, GFP_KERNEL);
+	if (!dch)
+		goto fail;
+
+	dch->name = (char *) (dch + 1);
+	strcpy(dch->name, name);
+	spin_lock_init(&dch->lock);
+	INIT_LIST_HEAD(&dch->clients);
+
+	list_add(&dch->list, &dal_channel_list);
+
+found_it:
+	if (!dch->sch) {
+		if (smd_named_open_on_edge(name, cpu, &dch->sch,
+					dch, dal_channel_notify)) {
+			pr_err("[%s:%s] smd open failed\n", __MM_FILE__,
+					__func__);
+			dch = NULL;
+		}
+		/* FIXME: wait for channel to open before returning */
+		msleep(100);
+	}
+
+fail:
+	mutex_unlock(&dal_channel_list_lock);
+
+	return dch;
+}
+
+int dal_call_raw(struct dal_client *client,
+		 struct dal_hdr *hdr,
+		 void *data, int data_len,
+		 void *reply, int reply_max)
+{
+	struct dal_channel *dch = client->dch;
+	unsigned long flags;
+
+	client->reply = reply;
+	client->reply_max = reply_max;
+	client->msgid = hdr->msgid | DAL_MSGID_REPLY;
+	client->status = -EBUSY;
+
+#if DAL_TRACE
+	pr_info("[%s:%s:%x] dal send %p -> %p %02x:%04x:%02x %d\n",
+		__MM_FILE__, __func__, (unsigned int)client, hdr->from, hdr->to,
+		hdr->msgid, hdr->ddi, hdr->prototype,
+		hdr->length - sizeof(*hdr));
+	print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, data, data_len);
+#endif
+
+	if (client->tr_log)
+		dal_trace_log(client, hdr, data, data_len);
+
+	spin_lock_irqsave(&dch->lock, flags);
+	/* FIXME: ensure entire message is written or none. */
+	smd_write(dch->sch, hdr, sizeof(*hdr));
+	smd_write(dch->sch, data, data_len);
+	spin_unlock_irqrestore(&dch->lock, flags);
+
+	if (!wait_event_timeout(client->wait, (client->status != -EBUSY), 5*HZ)) {
+		dal_trace_dump(client);
+		pr_err("[%s:%s] call timed out. dsp is probably dead.\n",
+				__MM_FILE__, __func__);
+		dal_trace_print(hdr, data, data_len, 0);
+		q6audio_dsp_not_responding();
+	}
+
+	return client->status;
+}
+
+int dal_call(struct dal_client *client,
+	     unsigned ddi, unsigned prototype,
+	     void *data, int data_len,
+	     void *reply, int reply_max)
+{
+	struct dal_hdr hdr;
+	int r;
+
+	memset(&hdr, 0, sizeof(hdr));
+
+	hdr.length = data_len + sizeof(hdr);
+	hdr.version = DAL_VERSION;
+	hdr.msgid = DAL_MSGID_DDI;
+	hdr.ddi = ddi;
+	hdr.prototype = prototype;
+	hdr.from = client;
+	hdr.to = client->remote;
+
+	if (hdr.length > DAL_MSG_MAX)
+		return -EINVAL;
+
+	mutex_lock(&client->write_lock);
+	r = dal_call_raw(client, &hdr, data, data_len, reply, reply_max);
+	mutex_unlock(&client->write_lock);
+
+	return r;
+}
+
+struct dal_msg_attach {
+	uint32_t device_id;
+	char attach[64];
+	char service_name[32];
+} __attribute__((packed));
+
+struct dal_reply_attach {
+	uint32_t status;
+	char name[64];
+};
+
+struct dal_client *dal_attach(uint32_t device_id, const char *name,
+			      uint32_t cpu, dal_event_func_t func, void *cookie)
+{
+	struct dal_hdr hdr;
+	struct dal_msg_attach msg;
+	struct dal_reply_attach reply;
+	struct dal_channel *dch;
+	struct dal_client *client;
+	unsigned long flags;
+	int r;
+
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	dch = dal_open_channel(name, cpu);
+	if (!dch)
+		return 0;
+
+	client = kzalloc(sizeof(*client), GFP_KERNEL);
+	if (!client)
+		return 0;
+
+	client->dch = dch;
+	client->event = func;
+	client->cookie = cookie;
+	mutex_init(&client->write_lock);
+	spin_lock_init(&client->tr_lock);
+	init_waitqueue_head(&client->wait);
+
+	spin_lock_irqsave(&dch->lock, flags);
+	list_add(&client->list, &dch->clients);
+	spin_unlock_irqrestore(&dch->lock, flags);
+
+	memset(&hdr, 0, sizeof(hdr));
+	memset(&msg, 0, sizeof(msg));
+
+	hdr.length = sizeof(hdr) + sizeof(msg);
+	hdr.version = DAL_VERSION;
+	hdr.msgid = DAL_MSGID_ATTACH;
+	hdr.from = client;
+	msg.device_id = device_id;
+
+	r = dal_call_raw(client, &hdr, &msg, sizeof(msg),
+			 &reply, sizeof(reply));
+
+	if ((r == sizeof(reply)) && (reply.status == 0)) {
+		reply.name[63] = 0;
+		pr_info("[%s:%s] status = %d, name = '%s' dal_client %x\n",
+			__MM_FILE__, __func__, reply.status,
+			reply.name, (unsigned int)client);
+		return client;
+	}
+
+	pr_err("[%s:%s] failure\n", __MM_FILE__, __func__);
+
+	dal_detach(client);
+	return 0;
+}
+
+int dal_detach(struct dal_client *client)
+{
+	struct dal_channel *dch;
+	unsigned long flags;
+
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	mutex_lock(&client->write_lock);
+	if (client->remote) {
+		struct dal_hdr hdr;
+		uint32_t data;
+
+		memset(&hdr, 0, sizeof(hdr));
+		hdr.length = sizeof(hdr) + sizeof(data);
+		hdr.version = DAL_VERSION;
+		hdr.msgid = DAL_MSGID_DETACH;
+		hdr.from = client;
+		hdr.to = client->remote;
+		data = (uint32_t) client;
+
+		dal_call_raw(client, &hdr, &data, sizeof(data),
+			     &data, sizeof(data));
+	}
+
+	dch = client->dch;
+	spin_lock_irqsave(&dch->lock, flags);
+	if (dch->active == client) {
+		/* We have received a message header for this client
+		 * but not the body of the message.  Ensure that when
+		 * the body arrives we don't write it into the now-closed
+		 * client.  In *theory* this should never happen.
+		 */
+		dch->active = 0;
+		dch->ptr = dch->data;
+	}
+	list_del(&client->list);
+	spin_unlock_irqrestore(&dch->lock, flags);
+
+	mutex_unlock(&client->write_lock);
+
+	kfree(client);
+	return 0;
+}
+
+void *dal_get_remote_handle(struct dal_client *client)
+{
+	return client->remote;
+}
+
+/* convenience wrappers */
+
+int dal_call_f0(struct dal_client *client, uint32_t ddi, uint32_t arg1)
+{
+	uint32_t tmp = arg1;
+	int res;
+	res = dal_call(client, ddi, 0, &tmp, sizeof(tmp), &tmp, sizeof(tmp));
+	if (res >= 4)
+		return (int) tmp;
+	return res;
+}
+
+int dal_call_f1(struct dal_client *client, uint32_t ddi, uint32_t arg1,
+		uint32_t arg2)
+{
+	uint32_t tmp[2];
+	int res;
+	tmp[0] = arg1;
+	tmp[1] = arg2;
+	res = dal_call(client, ddi, 1, tmp, sizeof(tmp), tmp, sizeof(uint32_t));
+	if (res >= 4)
+		return (int) tmp[0];
+	return res;
+}
+
+int dal_call_f5(struct dal_client *client, uint32_t ddi, void *ibuf, uint32_t ilen)
+{
+	uint32_t tmp[128];
+	int res;
+	int param_idx = 0;
+
+	if (ilen + 4 > DAL_DATA_MAX)
+		return -EINVAL;
+
+	tmp[param_idx] = ilen;
+	param_idx++;
+
+	memcpy(&tmp[param_idx], ibuf, ilen);
+	param_idx += DIV_ROUND_UP(ilen, 4);
+
+	res = dal_call(client, ddi, 5, tmp, param_idx * 4, tmp, sizeof(tmp));
+
+	if (res >= 4)
+		return (int) tmp[0];
+	return res;
+}
+
+int dal_call_f6(struct dal_client *client, uint32_t ddi, uint32_t s1,
+		void *ibuf, uint32_t ilen)
+{
+	uint32_t tmp[128];
+	int res;
+	int param_idx = 0;
+
+	if (ilen + 8 > DAL_DATA_MAX)
+		return -EINVAL;
+
+	tmp[param_idx] = s1;
+	param_idx++;
+	tmp[param_idx] = ilen;
+	param_idx++;
+	memcpy(&tmp[param_idx], ibuf, ilen);
+	param_idx += DIV_ROUND_UP(ilen, 4);
+
+	res = dal_call(client, ddi, 6, tmp, param_idx * 4, tmp, sizeof(tmp));
+
+	if (res >= 4)
+		return (int) tmp[0];
+
+	return res;
+}
+
+int dal_call_f9(struct dal_client *client, uint32_t ddi, void *obuf,
+		uint32_t olen)
+{
+	uint32_t tmp[128];
+	int res;
+
+	if (olen > sizeof(tmp) - 8)
+		return -EINVAL;
+	tmp[0] = olen;
+
+	res = dal_call(client, ddi, 9, tmp, sizeof(uint32_t), tmp,
+		sizeof(tmp));
+
+	if (res >= 4)
+		res = (int)tmp[0];
+
+	if (!res) {
+		if (tmp[1] > olen)
+			return -EIO;
+		memcpy(obuf, &tmp[2], tmp[1]);
+	}
+	return res;
+}
+
+int dal_call_f11(struct dal_client *client, uint32_t ddi, uint32_t s1,
+		void *obuf, uint32_t olen)
+{
+	uint32_t tmp[DAL_DATA_MAX/4] = {0};
+	int res;
+	int param_idx = 0;
+	int num_bytes = 4;
+
+	num_bytes += (DIV_ROUND_UP(olen, 4)) * 4;
+
+	if ((num_bytes > DAL_DATA_MAX - 12) || (olen > DAL_DATA_MAX - 8))
+		return -EINVAL;
+
+	tmp[param_idx] = s1;
+	param_idx++;
+	tmp[param_idx] = olen;
+	param_idx += DIV_ROUND_UP(olen, 4);
+
+	res = dal_call(client, ddi, 11, tmp, param_idx * 4, tmp, sizeof(tmp));
+
+	if (res >= 4)
+		res = (int) tmp[0];
+	if (!res) {
+		if (tmp[1] > olen)
+			return -EIO;
+		memcpy(obuf, &tmp[2], tmp[1]);
+	}
+	return res;
+}
+
+int dal_call_f13(struct dal_client *client, uint32_t ddi, void *ibuf1,
+		 uint32_t ilen1, void *ibuf2, uint32_t ilen2, void *obuf,
+		 uint32_t olen)
+{
+	uint32_t tmp[DAL_DATA_MAX/4];
+	int res;
+	int param_idx = 0;
+	int num_bytes = 0;
+
+	num_bytes = (DIV_ROUND_UP(ilen1, 4)) * 4;
+	num_bytes += (DIV_ROUND_UP(ilen2, 4)) * 4;
+
+	if ((num_bytes > DAL_DATA_MAX - 12) || (olen > DAL_DATA_MAX - 8) ||
+			(ilen1 > DAL_DATA_MAX) || (ilen2 > DAL_DATA_MAX))
+		return -EINVAL;
+
+	tmp[param_idx] = ilen1;
+	param_idx++;
+
+	memcpy(&tmp[param_idx], ibuf1, ilen1);
+	param_idx += DIV_ROUND_UP(ilen1, 4);
+
+	tmp[param_idx++] = ilen2;
+	memcpy(&tmp[param_idx], ibuf2, ilen2);
+	param_idx += DIV_ROUND_UP(ilen2, 4);
+
+	tmp[param_idx++] = olen;
+	res = dal_call(client, ddi, 13, tmp, param_idx * 4, tmp,
+			sizeof(tmp));
+
+	if (res >= 4)
+		res = (int)tmp[0];
+
+	if (!res) {
+		if (tmp[1] > olen)
+			return -EIO;
+		memcpy(obuf, &tmp[2], tmp[1]);
+	}
+	return res;
+}
+int dal_call_f14(struct dal_client *client, uint32_t ddi, void *ibuf,
+		 uint32_t ilen, void *obuf1, uint32_t olen1, void *obuf2,
+		 uint32_t olen2, uint32_t *oalen2)
+{
+	uint32_t tmp[128];
+	int res;
+	int param_idx = 0;
+
+	if (olen1 + olen2 + 8 > DAL_DATA_MAX ||
+		ilen + 12 > DAL_DATA_MAX)
+		return -EINVAL;
+
+	tmp[param_idx] = ilen;
+	param_idx++;
+
+	memcpy(&tmp[param_idx], ibuf, ilen);
+	param_idx += DIV_ROUND_UP(ilen, 4);
+
+	tmp[param_idx++] = olen1;
+	tmp[param_idx++] = olen2;
+	res = dal_call(client, ddi, 14, tmp, param_idx * 4, tmp, sizeof(tmp));
+
+	if (res >= 4)
+		res = (int)tmp[0];
+
+	if (!res) {
+		if (tmp[1] > olen1)
+			return -EIO;
+		param_idx = DIV_ROUND_UP(tmp[1], 4) + 2;
+		if (tmp[param_idx] > olen2)
+			return -EIO;
+
+		memcpy(obuf1, &tmp[2], tmp[1]);
+		memcpy(obuf2, &tmp[param_idx+1], tmp[param_idx]);
+		*oalen2 = tmp[param_idx];
+	}
+	return res;
+}
diff --git a/arch/arm/mach-msm/qdsp6/dal.h b/arch/arm/mach-msm/qdsp6/dal.h
new file mode 100644
index 0000000..1176eb9
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/dal.h
@@ -0,0 +1,96 @@
+/* arch/arm/mach-msm/qdsp6/dal.h
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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 _MACH_MSM_DAL_
+#define _MACH_MSM_DAL_
+
+struct dal_client;
+
+struct dal_info {
+	uint32_t size;
+	uint32_t version;
+	char name[32];
+};
+
+typedef void (*dal_event_func_t)(void *data, int len, void *cookie);
+
+struct dal_client *dal_attach(uint32_t device_id, const char *name,
+			uint32_t cpu, dal_event_func_t func, void *cookie);
+
+int dal_detach(struct dal_client *client);
+
+int dal_call(struct dal_client *client,
+	     unsigned ddi, unsigned prototype,
+	     void *data, int data_len,
+	     void *reply, int reply_max);
+
+void dal_trace(struct dal_client *client);
+void dal_trace_dump(struct dal_client *client);
+
+/* function to call before panic on stalled dal calls */
+void dal_set_oops(struct dal_client *client, void (*oops)(void));
+
+/* convenience wrappers */
+int dal_call_f0(struct dal_client *client, uint32_t ddi,
+		uint32_t arg1);
+int dal_call_f1(struct dal_client *client, uint32_t ddi,
+		uint32_t arg1, uint32_t arg2);
+int dal_call_f5(struct dal_client *client, uint32_t ddi,
+		void *ibuf, uint32_t ilen);
+int dal_call_f6(struct dal_client *client, uint32_t ddi,
+		uint32_t s1, void *ibuf, uint32_t ilen);
+int dal_call_f9(struct dal_client *client, uint32_t ddi,
+		void *obuf, uint32_t olen);
+int dal_call_f11(struct dal_client *client, uint32_t ddi,
+		uint32_t s1, void *obuf, uint32_t olen);
+int dal_call_f13(struct dal_client *client, uint32_t ddi, void *ibuf1,
+		 uint32_t ilen1, void *ibuf2, uint32_t ilen2, void *obuf,
+		 uint32_t olen);
+int dal_call_f14(struct dal_client *client, uint32_t ddi, void *ibuf,
+		 uint32_t ilen, void *obuf1, uint32_t olen1, void *obuf2,
+		 uint32_t olen2, uint32_t *oalen2);
+
+/* common DAL operations */
+enum {
+	DAL_OP_ATTACH = 0,
+	DAL_OP_DETACH,
+	DAL_OP_INIT,
+	DAL_OP_DEINIT,
+	DAL_OP_OPEN,
+	DAL_OP_CLOSE,
+	DAL_OP_INFO,
+	DAL_OP_POWEREVENT,
+	DAL_OP_SYSREQUEST,
+	DAL_OP_FIRST_DEVICE_API,
+};
+
+static inline int check_version(struct dal_client *client, uint32_t version)
+{
+	struct dal_info info;
+	int res;
+
+	res = dal_call_f9(client, DAL_OP_INFO, &info, sizeof(struct dal_info));
+	if (!res) {
+		if (((info.version & 0xFFFF0000) != (version & 0xFFFF0000)) ||
+		((info.version & 0x0000FFFF) <
+		(version & 0x0000FFFF))) {
+			res = -EINVAL;
+		}
+	}
+	return res;
+}
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6/dal_acdb.h b/arch/arm/mach-msm/qdsp6/dal_acdb.h
new file mode 100644
index 0000000..dfb1fef
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/dal_acdb.h
@@ -0,0 +1,69 @@
+/* Copyright (c) 2009, 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.
+ *
+ */
+
+#define ACDB_DAL_DEVICE		0x02000069
+#define ACDB_DAL_PORT		"DAL_AM_AUD"
+
+#define ACDB_OP_IOCTL		DAL_OP_FIRST_DEVICE_API
+
+/* ioctls */
+#define ACDB_GET_DEVICE		0x0108bb92
+#define ACDB_SET_DEVICE		0x0108bb93
+#define ACDB_GET_STREAM		0x0108bb95
+#define ACDB_SET_STREAM		0x0108bb96
+#define ACDB_GET_DEVICE_TABLE	0x0108bb97
+#define ACDB_GET_STREAM_TABLE	0x0108bb98
+
+#define ACDB_RES_SUCCESS	0
+#define ACDB_RES_FAILURE	-1
+#define ACDB_RES_BADPARM	-2
+#define ACDB_RES_BADSTATE	-3
+
+struct acdb_cmd_device {
+	uint32_t size;
+
+	uint32_t command_id;
+	uint32_t device_id;
+	uint32_t network_id;
+	uint32_t sample_rate_id;
+	uint32_t interface_id;
+	uint32_t algorithm_block_id;
+
+	/* physical page aligned buffer */
+	uint32_t total_bytes;
+	uint32_t unmapped_buf;
+} __attribute__((packed));
+
+struct acdb_cmd_device_table {
+	uint32_t size;
+
+	uint32_t command_id;
+	uint32_t device_id;
+	uint32_t network_id;
+	uint32_t sample_rate_id;
+
+	/* physical page aligned buffer */
+	uint32_t total_bytes;
+	uint32_t unmapped_buf;
+
+	uint32_t res_size;
+} __attribute__((packed));
+
+struct acdb_result {
+	uint32_t dal_status;
+	uint32_t size;
+
+	uint32_t unmapped_buf;
+	uint32_t used_bytes;
+	uint32_t result;
+} __attribute__((packed));
diff --git a/arch/arm/mach-msm/qdsp6/dal_adie.h b/arch/arm/mach-msm/qdsp6/dal_adie.h
new file mode 100644
index 0000000..6abc60c
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/dal_adie.h
@@ -0,0 +1,104 @@
+/* Copyright (c) 2009, 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 _MACH_MSM_QDSP6_ADIE_
+#define _MACH_MSM_QDSP6_ADIE_
+
+#include "dal.h"
+
+#define ADIE_DAL_DEVICE		0x02000029
+#define ADIE_DAL_PORT		"DAL_AM_AUD"
+
+enum {
+	ADIE_OP_GET_NUM_PATHS = DAL_OP_FIRST_DEVICE_API,
+	ADIE_OP_GET_ALL_PATH_IDS,
+	ADIE_OP_SET_PATH,
+	ADIE_OP_GET_NUM_PATH_FREQUENCY_PLANS,
+	ADIE_OP_GET_PATH_FREQUENCY_PLANS,
+	ADIE_OP_SET_PATH_FREQUENCY_PLAN,
+	ADIE_OP_PROCEED_TO_STAGE,
+	ADIE_OP_MUTE_PATH
+};
+
+/* Path IDs for normal operation. */
+#define ADIE_PATH_HANDSET_TX			0x010740f6
+#define ADIE_PATH_HANDSET_RX			0x010740f7
+#define ADIE_PATH_HEADSET_MONO_TX		0x010740f8
+#define ADIE_PATH_HEADSET_STEREO_TX		0x010740f9
+#define ADIE_PATH_HEADSET_MONO_RX		0x010740fa
+#define ADIE_PATH_HEADSET_STEREO_RX		0x010740fb
+#define ADIE_PATH_SPEAKER_TX			0x010740fc
+#define ADIE_PATH_SPEAKER_RX			0x010740fd
+#define ADIE_PATH_SPEAKER_STEREO_RX		0x01074101
+
+/* Path IDs used for TTY */
+#define ADIE_PATH_TTY_HEADSET_TX		0x010740fe
+#define ADIE_PATH_TTY_HEADSET_RX		0x010740ff
+
+/* Path IDs used by Factory Test Mode. */
+#define ADIE_PATH_FTM_MIC1_TX			0x01074108
+#define ADIE_PATH_FTM_MIC2_TX			0x01074107
+#define ADIE_PATH_FTM_HPH_L_RX			0x01074106
+#define ADIE_PATH_FTM_HPH_R_RX			0x01074104
+#define ADIE_PATH_FTM_EAR_RX			0x01074103
+#define ADIE_PATH_FTM_SPKR_RX			0x01074102
+
+/* Path IDs for Loopback */
+/* Path IDs used for Line in -> AuxPGA -> Line Out Stereo Mode*/
+#define ADIE_PATH_AUXPGA_LINEOUT_STEREO_LB	0x01074100
+/* Line in -> AuxPGA -> LineOut Mono */
+#define ADIE_PATH_AUXPGA_LINEOUT_MONO_LB	0x01073d82
+/* Line in -> AuxPGA -> Stereo Headphone */
+#define ADIE_PATH_AUXPGA_HDPH_STEREO_LB		0x01074109
+/* Line in -> AuxPGA -> Mono Headphone */
+#define ADIE_PATH_AUXPGA_HDPH_MONO_LB		0x01073d85
+/* Line in -> AuxPGA -> Earpiece */
+#define ADIE_PATH_AUXPGA_EAP_LB			0x01073d81
+/* Line in -> AuxPGA -> AuxOut */
+#define ADIE_PATH_AUXPGA_AUXOUT_LB		0x01073d86
+
+/* Concurrency Profiles */
+#define ADIE_PATH_SPKR_STEREO_HDPH_MONO_RX	0x01073d83
+#define ADIE_PATH_SPKR_MONO_HDPH_MONO_RX	0x01073d84
+#define ADIE_PATH_SPKR_MONO_HDPH_STEREO_RX	0x01073d88
+#define ADIE_PATH_SPKR_STEREO_HDPH_STEREO_RX	0x01073d89
+
+
+/** Fluence Profiles **/
+
+/* Broadside/Bowsetalk profile,
+ * For Handset and Speaker phone Tx*/
+#define ADIE_CODEC_HANDSET_SPKR_BS_TX          0x0108fafa
+/* EndFire profile,
+ * For Handset and Speaker phone Tx*/
+#define ADIE_CODEC_HANDSET_SPKR_EF_TX          0x0108fafb
+
+
+/* stages */
+#define ADIE_STAGE_PATH_OFF			0x0050
+#define ADIE_STAGE_DIGITAL_READY		0x0100
+#define ADIE_STAGE_DIGITAL_ANALOG_READY		0x1000
+#define ADIE_STAGE_ANALOG_OFF			0x0750
+#define ADIE_STAGE_DIGITAL_OFF			0x0600
+
+/* path types */
+#define ADIE_PATH_RX		0
+#define ADIE_PATH_TX		1
+#define ADIE_PATH_LOOPBACK	2
+
+/* mute states */
+#define ADIE_MUTE_OFF		0
+#define ADIE_MUTE_ON		1
+
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6/dal_audio.h b/arch/arm/mach-msm/qdsp6/dal_audio.h
new file mode 100644
index 0000000..25d1e4f
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/dal_audio.h
@@ -0,0 +1,604 @@
+/* Copyright (c) 2009-2010, 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 __DAL_AUDIO_H__
+#define __DAL_AUDIO_H__
+
+#include "dal_audio_format.h"
+
+#define AUDIO_DAL_DEVICE 0x02000028
+#define AUDIO_DAL_PORT "DAL_AQ_AUD"
+
+enum {
+	AUDIO_OP_CONTROL = DAL_OP_FIRST_DEVICE_API,
+	AUDIO_OP_DATA,
+	AUDIO_OP_INIT,
+};	
+
+/* ---- common audio structures ---- */
+
+/* This flag, if set, indicates that the beginning of the data in the*/
+/* buffer is a synchronization point or key frame, meaning no data */
+/* before it in the stream is required in order to render the stream */
+/* from this point onward. */
+#define ADSP_AUDIO_BUFFER_FLAG_SYNC_POINT        0x01
+
+/* This flag, if set, indicates that the buffer object is using valid */
+/* physical address used to store the media data */
+#define ADSP_AUDIO_BUFFER_FLAG_PHYS_ADDR         0x04
+
+/* This flag, if set, indicates that a media start timestamp has been */
+/* set for a buffer. */
+#define ADSP_AUDIO_BUFFER_FLAG_START_SET         0x08
+
+/* This flag, if set, indicates that a media stop timestamp has been set */
+/* for a buffer. */
+#define ADSP_AUDIO_BUFFER_FLAG_STOP_SET          0x10
+
+/* This flag, if set, indicates that a preroll timestamp has been set */
+/* for a buffer. */
+#define ADSP_AUDIO_BUFFER_FLAG_PREROLL_SET       0x20
+
+/* This flag, if set, indicates that the data in the buffer is a fragment of */
+/* a larger block of data, and will be continued by the data in the next */
+/* buffer to be delivered. */
+#define ADSP_AUDIO_BUFFER_FLAG_CONTINUATION      0x40
+
+struct adsp_audio_buffer {
+	u32 addr;		/* Physical Address of buffer */
+	u32 max_size;		/* Maximum size of buffer */
+	u32 actual_size;	/* Actual size of valid data in the buffer */
+	u32 offset;		/* Offset to the first valid byte */
+	u32 flags;		/* ADSP_AUDIO_BUFFER_FLAGs that has been set */
+	s64 start;		/* Start timestamp, if any */
+	s64 stop;		/* Stop timestamp, if any */
+	s64 preroll;		/* Preroll timestamp, if any */
+} __attribute__ ((packed));
+
+
+
+/* ---- audio commands ---- */
+
+/* Command/event response types */
+#define ADSP_AUDIO_RESPONSE_COMMAND   0
+#define ADSP_AUDIO_RESPONSE_ASYNC     1
+
+struct adsp_command_hdr {
+	u32 size;		/* sizeof(cmd) - sizeof(u32) */
+
+	u32 dst;
+	u32 src;
+
+	u32 opcode;
+	u32 response_type;
+	u32 seq_number;
+
+	u32 context;		/* opaque to DSP */
+	u32 data;
+
+	u32 padding;
+} __attribute__ ((packed));
+
+
+#define AUDIO_DOMAIN_APP	0
+#define AUDIO_DOMAIN_MODEM	1
+#define AUDIO_DOMAIN_DSP	2
+
+#define AUDIO_SERVICE_AUDIO	0
+#define AUDIO_SERVICE_VIDEO	1 /* really? */
+
+/* adsp audio addresses are (byte order) domain, service, major, minor */
+//#define AUDIO_ADDR(maj,min) ( (((maj) & 0xff) << 16) | (((min) & 0xff) << 24) | (1) )
+
+#define AUDIO_ADDR(maj,min,dom) ( (((min) & 0xff) << 24) | (((maj) & 0xff) << 16) | ((AUDIO_SERVICE_AUDIO) << 8) | (dom) )
+
+
+/* AAC Encoder modes */
+#define ADSP_AUDIO_ENC_AAC_LC_ONLY_MODE		0
+#define ADSP_AUDIO_ENC_AAC_PLUS_MODE		1
+#define ADSP_AUDIO_ENC_ENHANCED_AAC_PLUS_MODE	2
+
+struct adsp_audio_aac_enc_cfg {
+	u32 bit_rate;		/* bits per second */
+	u32 encoder_mode;	/* ADSP_AUDIO_ENC_* */
+} __attribute__ ((packed));
+
+#define ADSP_AUDIO_ENC_SBC_ALLOCATION_METHOD_LOUNDNESS     0
+#define ADSP_AUDIO_ENC_SBC_ALLOCATION_METHOD_SNR           1
+
+#define ADSP_AUDIO_ENC_SBC_CHANNEL_MODE_MONO                1
+#define ADSP_AUDIO_ENC_SBC_CHANNEL_MODE_STEREO              2
+#define ADSP_AUDIO_ENC_SBC_CHANNEL_MODE_DUAL                8
+#define ADSP_AUDIO_ENC_SBC_CHANNEL_MODE_JOINT_STEREO        9
+
+struct adsp_audio_sbc_encoder_cfg {
+	u32 num_subbands;
+	u32 block_len;
+	u32 channel_mode;
+	u32 allocation_method;
+	u32 bit_rate;
+} __attribute__ ((packed));
+
+/* AMR NB encoder modes */
+#define ADSP_AUDIO_AMR_MR475	0
+#define ADSP_AUDIO_AMR_MR515	1
+#define ADSP_AUDIO_AMR_MMR59	2
+#define ADSP_AUDIO_AMR_MMR67	3
+#define ADSP_AUDIO_AMR_MMR74	4
+#define ADSP_AUDIO_AMR_MMR795	5
+#define ADSP_AUDIO_AMR_MMR102	6
+#define ADSP_AUDIO_AMR_MMR122	7
+
+/* The following are valid AMR NB DTX modes */
+#define ADSP_AUDIO_AMR_DTX_MODE_OFF		0
+#define ADSP_AUDIO_AMR_DTX_MODE_ON_VAD1		1
+#define ADSP_AUDIO_AMR_DTX_MODE_ON_VAD2		2
+#define ADSP_AUDIO_AMR_DTX_MODE_ON_AUTO		3
+
+/* AMR Encoder configuration */
+struct adsp_audio_amr_enc_cfg {
+	u32	mode;		/* ADSP_AUDIO_AMR_MR* */
+	u32	dtx_mode;	/* ADSP_AUDIO_AMR_DTX_MODE* */
+	u32	enable;		/* 1 = enable, 0 = disable */
+} __attribute__ ((packed));
+
+struct adsp_audio_qcelp13k_enc_cfg {
+	u16	min_rate;
+	u16	max_rate;
+} __attribute__ ((packed));
+
+struct adsp_audio_evrc_enc_cfg {
+	u16	min_rate;
+	u16	max_rate;
+} __attribute__ ((packed));
+
+union adsp_audio_codec_config {
+	struct adsp_audio_amr_enc_cfg amr;
+	struct adsp_audio_aac_enc_cfg aac;
+	struct adsp_audio_qcelp13k_enc_cfg qcelp13k;
+	struct adsp_audio_evrc_enc_cfg evrc;
+	struct adsp_audio_sbc_encoder_cfg sbc;
+} __attribute__ ((packed));
+
+
+/* This is the default value. */
+#define ADSP_AUDIO_OPEN_STREAM_MODE_NONE		0x0000
+
+/* This bit, if set, indicates that the AVSync mode is activated. */
+#define ADSP_AUDIO_OPEN_STREAM_MODE_AVSYNC		0x0001
+
+/* This bit, if set, indicates that the Sample Rate/Channel Mode */
+/* Change Notification mode is activated. */
+#define ADSP_AUDIO_OPEN_STREAM_MODE_SR_CM_NOTIFY	0x0002
+
+/* This bit, if set, indicates that the sync clock is enabled */
+#define  ADSP_AUDIO_OPEN_STREAM_MODE_ENABLE_SYNC_CLOCK	0x0004
+
+/* This bit, if set, indicates that the AUX PCM loopback is enabled */
+#define  ADSP_AUDIO_OPEN_STREAM_MODE_AUX_PCM		0x0040
+
+struct adsp_open_command {
+	struct adsp_command_hdr hdr;
+
+	u32 device;
+	u32 endpoint; /* address */
+
+	u32 stream_context;
+	u32 mode;
+
+	u32 buf_max_size;
+
+	union adsp_audio_format format;
+	union adsp_audio_codec_config config;
+} __attribute__ ((packed));
+
+
+/* --- audio control and stream session ioctls ---- */
+
+/* Opcode to open a device stream session to capture audio */
+#define ADSP_AUDIO_IOCTL_CMD_OPEN_READ			0x0108dd79
+
+/* Opcode to open a device stream session to render audio */
+#define ADSP_AUDIO_IOCTL_CMD_OPEN_WRITE			0x0108dd7a
+
+/* Opcode to open a device session, must open a device */
+#define ADSP_AUDIO_IOCTL_CMD_OPEN_DEVICE		0x0108dd7b
+
+/* Close an existing stream or device */
+#define ADSP_AUDIO_IOCTL_CMD_CLOSE			0x0108d8bc
+
+
+
+/* A device switch requires three IOCTL */
+/* commands in the following sequence: PREPARE, STANDBY, COMMIT */
+
+/* adsp_audio_device_switch_command structure is needed for */
+/* DEVICE_SWITCH_PREPARE */
+
+/* Device switch protocol step #1. Pause old device and */
+/* generate silence for the old device. */
+#define ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_PREPARE	0x010815c4
+
+/* Device switch protocol step #2. Release old device, */
+/* create new device and generate silence for the new device. */
+
+/* When client receives ack for this IOCTL, the client can */
+/* start sending IOCTL commands to configure, calibrate and */
+/* change filter settings on the new device. */
+#define ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_STANDBY	0x010815c5
+
+/* Device switch protocol step #3. Start normal operations on new device */
+#define ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_COMMIT	0x01075ee7
+
+struct adsp_device_switch_command {
+	struct adsp_command_hdr hdr;
+	u32 old_device;
+	u32 new_device;
+	u8 device_class; /* 0 = i.rx, 1 = i.tx, 2 = e.rx, 3 = e.tx */
+	u8 device_type; /* 0 = rx, 1 = tx, 2 = both */
+} __attribute__ ((packed));
+
+
+
+/* --- audio control session ioctls ---- */
+
+#define ADSP_PATH_RX	0
+#define ADSP_PATH_TX	1
+#define ADSP_PATH_BOTH	2
+#define ADSP_PATH_TX_CNG_DIS 3
+
+struct adsp_audio_dtmf_start_command {
+	struct adsp_command_hdr hdr;
+	u32 tone1_hz;
+	u32 tone2_hz;
+	u32 duration_usec;
+	s32 gain_mb;
+} __attribute__ ((packed));
+
+/* These commands will affect a logical device and all its associated */
+/* streams. */
+
+#define ADSP_AUDIO_MAX_EQ_BANDS 12
+
+struct adsp_audio_eq_band {
+	u16     band_idx; /* The band index, 0 .. 11 */
+	u32     filter_type; /* Filter band type */
+	u32     center_freq_hz; /* Filter band center frequency */
+	s32     filter_gain; /* Filter band initial gain (dB) */
+			/* Range is +12 dB to -12 dB with 1dB increments. */
+	s32     q_factor;
+		/* Filter band quality factor expressed as q-8 number, */
+		/* e.g. 3000/(2^8) */
+} __attribute__ ((packed));
+
+struct adsp_audio_eq_stream_config {
+	uint32_t  enable; /* Number of consequtive bands specified */
+	uint32_t  num_bands;
+	struct adsp_audio_eq_band  eq_bands[ADSP_AUDIO_MAX_EQ_BANDS];
+} __attribute__ ((packed));
+
+/* set device equalizer */
+struct adsp_set_dev_equalizer_command {
+	struct adsp_command_hdr hdr;
+	u32    device_id;
+	u32    enable;
+	u32    num_bands;
+	struct adsp_audio_eq_band eq_bands[ADSP_AUDIO_MAX_EQ_BANDS];
+} __attribute__ ((packed));
+
+/* Set device volume. */
+#define ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_VOL		0x0107605c
+
+struct adsp_set_dev_volume_command {
+	struct adsp_command_hdr hdr;
+	u32 device_id;
+	u32 path; /* 0 = rx, 1 = tx, 2 = both */
+	s32 volume;
+} __attribute__ ((packed));
+
+/* Set Device stereo volume. This command has data payload, */
+/* struct adsp_audio_set_dev_stereo_volume_command. */
+#define ADSP_AUDIO_IOCTL_SET_DEVICE_STEREO_VOL		0x0108df3e
+
+/* Set L, R cross channel gain for a Device. This command has */
+/* data payload, struct adsp_audio_set_dev_x_chan_gain_command. */
+#define ADSP_AUDIO_IOCTL_SET_DEVICE_XCHAN_GAIN		0x0108df40
+
+/* Set device mute state. */
+#define ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_MUTE		0x0107605f
+
+struct adsp_set_dev_mute_command {
+	struct adsp_command_hdr hdr;
+	u32 device_id;
+	u32 path; /* 0 = rx, 1 = tx, 2 = both */
+	u32 mute; /* 1 = mute */
+} __attribute__ ((packed));
+
+/* Configure Equalizer for a device. */
+/* This command has payload struct adsp_audio_set_dev_equalizer_command. */
+#define ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_EQ_CONFIG	0x0108b10e
+
+/* Set configuration data for an algorithm aspect of a device. */
+/* This command has payload struct adsp_audio_set_dev_cfg_command. */
+#define ADSP_AUDIO_IOCTL_SET_DEVICE_CONFIG		0x0108b6cb
+
+struct adsp_set_dev_cfg_command {
+	struct adsp_command_hdr hdr;
+	u32 device_id;
+	u32 block_id;
+	u32 interface_id;
+	u32 phys_addr;
+	u32 phys_size;
+	u32 phys_used;
+} __attribute__ ((packed));
+
+/* Set configuration data for all interfaces of a device. */
+#define ADSP_AUDIO_IOCTL_SET_DEVICE_CONFIG_TABLE	0x0108b6bf
+
+struct adsp_set_dev_cfg_table_command {
+	struct adsp_command_hdr hdr;
+	u32 device_id;
+	u32 phys_addr;
+	u32 phys_size;
+	u32 phys_used;
+} __attribute__ ((packed));
+
+/* ---- audio stream data commands ---- */
+
+#define ADSP_AUDIO_IOCTL_CMD_DATA_TX			0x0108dd7f
+#define ADSP_AUDIO_IOCTL_CMD_DATA_RX			0x0108dd80
+
+struct adsp_buffer_command {
+	struct adsp_command_hdr hdr;
+	struct adsp_audio_buffer buffer;
+} __attribute__ ((packed));
+
+
+
+/* ---- audio stream ioctls (only affect a single stream in a session) ---- */
+
+/* Stop stream for audio device. */
+#define ADSP_AUDIO_IOCTL_CMD_STREAM_STOP		0x01075c54
+
+/* End of stream reached. Client will not send any more data. */
+#define ADSP_AUDIO_IOCTL_CMD_STREAM_EOS			0x0108b150
+
+/* Do sample slipping/stuffing on AAC outputs. The payload of */
+/* this command is struct adsp_audio_slip_sample_command. */
+#define ADSP_AUDIO_IOCTL_CMD_STREAM_SLIPSAMPLE		0x0108d40e
+
+/* Set stream volume. */
+/* This command has data payload, struct adsp_audio_set_volume_command. */
+#define ADSP_AUDIO_IOCTL_CMD_SET_STREAM_VOL		0x0108c0de
+
+/* Set stream stereo volume. This command has data payload, */
+/* struct adsp_audio_set_stereo_volume_command. */
+#define ADSP_AUDIO_IOCTL_SET_STREAM_STEREO_VOL		0x0108dd7c
+
+/* Set L, R cross channel gain for a Stream. This command has */
+/* data payload, struct adsp_audio_set_x_chan_gain_command. */
+#define ADSP_AUDIO_IOCTL_SET_STREAM_XCHAN_GAIN		0x0108dd7d
+
+/* Set stream mute state. */
+/* This command has data payload, struct adsp_audio_set_stream_mute. */
+#define ADSP_AUDIO_IOCTL_CMD_SET_STREAM_MUTE		0x0108c0df
+
+/* Reconfigure bit rate information. This command has data */
+/* payload, struct adsp_audio_set_bit_rate_command */
+#define ADSP_AUDIO_IOCTL_SET_STREAM_BITRATE		0x0108ccf1
+
+/* Set Channel Mapping. This command has data payload, struct */
+/* This command has data payload struct adsp_audio_set_channel_map_command. */
+#define ADSP_AUDIO_IOCTL_SET_STREAM_CHANNELMAP		0x0108d32a
+
+/* Enable/disable AACPlus SBR. */
+/* This command has data payload struct adsp_audio_set_sbr_command */
+#define ADSP_AUDIO_IOCTL_SET_STREAM_SBR			0x0108d416
+
+/* Enable/disable WMA Pro Chex and Fex. This command has data payload */
+/* struct adsp_audio_stream_set_wma_command. */
+#define ADSP_AUDIO_IOCTL_SET_STREAM_WMAPRO		0x0108d417
+
+
+/* ---- audio session ioctls (affect all streams in a session) --- */
+
+/* Start stream for audio device. */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_START		0x010815c6
+
+/* Stop all stream(s) for audio session as indicated by major id. */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_STOP		0x0108dd7e
+
+/* Pause the data flow for a session as indicated by major id. */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_PAUSE		0x01075ee8
+
+/* Resume the data flow for a session as indicated by major id. */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_RESUME		0x01075ee9
+
+/* Drop any unprocessed data buffers for a session as indicated by major id. */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_FLUSH		0x01075eea
+
+/* Start Stream DTMF tone */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_DTMF_START		0x0108c0dd
+
+/* Stop Stream DTMF tone */
+#define ADSP_AUDIO_IOCTL_CMD_SESSION_DTMF_STOP		0x01087554
+
+/* Set Session volume. */
+/* This command has data payload, struct adsp_audio_set_volume_command. */
+#define ADSP_AUDIO_IOCTL_SET_SESSION_VOL		0x0108d8bd
+
+/* Set session stereo volume. This command has data payload, */
+/* struct adsp_audio_set_stereo_volume_command. */
+#define ADSP_AUDIO_IOCTL_SET_SESSION_STEREO_VOL		0x0108df3d
+
+/* Set L, R cross channel gain for a session. This command has */
+/* data payload, struct adsp_audio_set_x_chan_gain_command. */
+#define ADSP_AUDIO_IOCTL_SET_SESSION_XCHAN_GAIN		0x0108df3f
+
+/* Set Session mute state. */
+/* This command has data payload, struct adsp_audio_set_mute_command. */
+#define ADSP_AUDIO_IOCTL_SET_SESSION_MUTE		0x0108d8be
+
+/* Configure Equalizer for a stream. */
+/* This command has payload struct adsp_audio_set_equalizer_command. */
+#define ADSP_AUDIO_IOCTL_SET_SESSION_EQ_CONFIG		0x0108c0e0
+
+/* Set Audio Video sync information. */
+/* This command has data payload, struct adsp_audio_set_av_sync_command. */
+#define ADSP_AUDIO_IOCTL_SET_SESSION_AVSYNC		0x0108d1e2
+
+/* Get Audio Media Session time. */
+/* This command returns the audioTime in adsp_audio_unsigned64_event */
+#define ADSP_AUDIO_IOCTL_CMD_GET_AUDIO_TIME		0x0108c26c
+
+
+/* these command structures are used for both STREAM and SESSION ioctls */
+
+struct adsp_set_volume_command {
+	struct adsp_command_hdr hdr;
+	s32 volume;
+} __attribute__ ((packed));
+	
+struct adsp_set_mute_command {
+	struct adsp_command_hdr hdr;
+	u32 mute; /* 1 == mute */
+} __attribute__ ((packed));
+
+
+struct adsp_set_equalizer_command {
+	struct adsp_command_hdr hdr;
+	u32    enable;
+	u32    num_bands;
+	struct adsp_audio_eq_band eq_bands[ADSP_AUDIO_MAX_EQ_BANDS];
+} __attribute__ ((packed));
+
+/* ---- audio events ---- */
+
+/* All IOCTL commands generate an event with the IOCTL opcode as the */
+/* event id after the IOCTL command has been executed. */
+
+/* This event is generated after a media stream session is opened. */
+#define ADSP_AUDIO_EVT_STATUS_OPEN				0x0108c0d6
+
+/* This event is generated after a media stream  session is closed. */
+#define ADSP_AUDIO_EVT_STATUS_CLOSE				0x0108c0d7
+
+/* Asyncronous buffer consumption. This event is generated after a */
+/* recived  buffer is consumed during rendering or filled during */
+/* capture opeartion. */
+#define ADSP_AUDIO_EVT_STATUS_BUF_DONE				0x0108c0d8
+
+/* This event is generated when rendering operation is starving for */
+/* data. In order to avoid audio loss at the end of a plauback, the */
+/* client should wait for this event before issuing the close command. */
+#define ADSP_AUDIO_EVT_STATUS_BUF_UNDERRUN			0x0108c0d9
+
+/* This event is generated during capture operation when there are no */
+/* buffers available to copy the captured audio data */
+#define ADSP_AUDIO_EVT_STATUS_BUF_OVERFLOW			0x0108c0da
+
+/* This asynchronous event is generated as a result of an input */
+/* sample rate change and/or channel mode change detected by the */
+/* decoder. The event payload data is an array of 2 uint32 */
+/* values containing the sample rate in Hz and channel mode. */
+#define ADSP_AUDIO_EVT_SR_CM_CHANGE				0x0108d329
+
+struct adsp_event_hdr {
+	u32 evt_handle;		/* DAL common header */
+	u32 evt_cookie;
+	u32 evt_length;
+
+	u32 src;		/* "source" audio address */
+	u32 dst;		/* "destination" audio address */
+
+	u32 event_id;
+	u32 response_type;
+	u32 seq_number;
+
+	u32 context;		/* opaque to DSP */
+	u32 data;
+
+	u32 status;
+} __attribute__ ((packed));
+
+struct adsp_buffer_event {
+	struct adsp_event_hdr hdr;
+	struct adsp_audio_buffer buffer;
+} __attribute__ ((packed));
+
+
+/* ---- audio device IDs ---- */
+
+/* Device direction Rx/Tx flag */
+#define ADSP_AUDIO_RX_DEVICE		0x00
+#define ADSP_AUDIO_TX_DEVICE		0x01
+
+/* Default RX or TX device */
+#define ADSP_AUDIO_DEVICE_ID_DEFAULT		0x1081679
+
+/* Source (TX) devices */
+#define ADSP_AUDIO_DEVICE_ID_HANDSET_MIC	0x107ac8d
+#define ADSP_AUDIO_DEVICE_ID_HEADSET_MIC	0x1081510
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MIC	0x1081512
+#define ADSP_AUDIO_DEVICE_ID_BT_SCO_MIC		0x1081518
+#define ADSP_AUDIO_DEVICE_ID_AUXPCM_TX		0x1081518
+#define ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_MIC	0x108151b
+#define ADSP_AUDIO_DEVICE_ID_I2S_MIC		0x1089bf3
+
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_DUAL_MIC	0x108f9c5
+#define ADSP_AUDIO_DEVICE_ID_HANDSET_DUAL_MIC		0x108f9c3
+
+/* Special loopback pseudo device to be paired with an RX device */
+/* with usage ADSP_AUDIO_DEVICE_USAGE_MIXED_PCM_LOOPBACK */
+#define ADSP_AUDIO_DEVICE_ID_MIXED_PCM_LOOPBACK_TX	0x1089bf2
+
+/* Sink (RX) devices */
+#define ADSP_AUDIO_DEVICE_ID_HANDSET_SPKR			0x107ac88
+#define ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_MONO			0x1081511
+#define ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_STEREO		0x107ac8a
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO			0x1081513
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_MONO_HEADSET     0x108c508
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_STEREO_HEADSET   0x108c894
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO			0x1081514
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_MONO_HEADSET   0x108c895
+#define ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_STEREO_HEADSET	0x108c509
+#define ADSP_AUDIO_DEVICE_ID_BT_SCO_SPKR			0x1081519
+#define ADSP_AUDIO_DEVICE_ID_AUXPCM_RX				0x1081519
+#define ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_SPKR			0x108151c
+#define ADSP_AUDIO_DEVICE_ID_I2S_SPKR				0x1089bf4
+#define ADSP_AUDIO_DEVICE_ID_NULL_SINK				0x108e512
+
+/* BT A2DP playback device. */
+/* This device must be paired with */
+/* ADSP_AUDIO_DEVICE_ID_MIXED_PCM_LOOPBACK_TX using  */
+/* ADSP_AUDIO_DEVICE_USAGE_MIXED_PCM_LOOPBACK mode */
+#define ADSP_AUDIO_DEVICE_ID_BT_A2DP_SPKR	0x108151a
+
+/* Voice Destination identifier - specifically used for */
+/* controlling Voice module from the Device Control Session */
+#define ADSP_AUDIO_DEVICE_ID_VOICE		0x0108df3c
+
+/*  Audio device usage types. */
+/*  This is a bit mask to determine which topology to use in the */
+/* device session */
+#define ADSP_AUDIO_DEVICE_CONTEXT_VOICE			0x01
+#define ADSP_AUDIO_DEVICE_CONTEXT_PLAYBACK		0x02
+#define ADSP_AUDIO_DEVICE_CONTEXT_MIXED_RECORD		0x10
+#define ADSP_AUDIO_DEVICE_CONTEXT_RECORD		0x20
+#define ADSP_AUDIO_DEVICE_CONTEXT_PCM_LOOPBACK		0x40
+
+/* ADSP audio driver return codes */
+#define ADSP_AUDIO_STATUS_SUCCESS               0
+#define ADSP_AUDIO_STATUS_EUNSUPPORTED          20
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6/dal_audio_format.h b/arch/arm/mach-msm/qdsp6/dal_audio_format.h
new file mode 100644
index 0000000..6382693
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/dal_audio_format.h
@@ -0,0 +1,270 @@
+/* Copyright (c) 2009, 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 __ADSP_AUDIO_MEDIA_FORMAT_H
+#define __ADSP_AUDIO_MEDIA_FORMAT_H
+
+
+
+/* Supported audio media formats */
+
+/* format block in shmem */
+#define ADSP_AUDIO_FORMAT_SHAREDMEMORY	0x01091a78
+/* adsp_audio_format_raw_pcm type */
+#define ADSP_AUDIO_FORMAT_PCM		0x0103d2fd
+/* adsp_audio_format_raw_pcm type */
+#define ADSP_AUDIO_FORMAT_DTMF		0x01087725
+/* adsp_audio_format_adpcm type */
+#define ADSP_AUDIO_FORMAT_ADPCM		0x0103d2ff
+/* Yamaha PCM format */
+#define ADSP_AUDIO_FORMAT_YADPCM	0x0108dc07
+/* ISO/IEC 11172 */
+#define ADSP_AUDIO_FORMAT_MP3		0x0103d308
+/* ISO/IEC 14496 */
+#define ADSP_AUDIO_FORMAT_MPEG4_AAC	0x010422f1
+/* AMR-NB audio in FS format */
+#define ADSP_AUDIO_FORMAT_AMRNB_FS	0x0105c16c
+/* AMR-WB audio in FS format */
+#define ADSP_AUDIO_FORMAT_AMRWB_FS	0x0105c16e
+/* QCELP 13k, IS733 */
+#define ADSP_AUDIO_FORMAT_V13K_FS	0x01080b8a
+/* EVRC   8k, IS127 */
+#define ADSP_AUDIO_FORMAT_EVRC_FS	0x01080b89
+/* EVRC-B   8k, 4GV */
+#define ADSP_AUDIO_FORMAT_EVRCB_FS	0x0108f2a3
+/* MIDI command stream */
+#define ADSP_AUDIO_FORMAT_MIDI		0x0103d300
+/* A2DP SBC stream */
+#define ADSP_AUDIO_FORMAT_SBC		0x0108c4d8
+/* Version 10 Professional */
+#define ADSP_AUDIO_FORMAT_WMA_V10PRO	0x0108aa92
+/* Version 9 Starndard */
+#define ADSP_AUDIO_FORMAT_WMA_V9	0x0108d430
+/* AMR WideBand Plus */
+#define ADSP_AUDIO_FORMAT_AMR_WB_PLUS	0x0108f3da
+/* AC3 Decoder */
+#define ADSP_AUDIO_FORMAT_AC3_DECODER	0x0108d5f9
+
+
+/* Not yet supported audio media formats */
+
+
+
+/* ISO/IEC 13818 */
+#define ADSP_AUDIO_FORMAT_MPEG2_AAC	0x0103d309
+/* 3GPP TS 26.101 Sec 4.0 */
+#define ADSP_AUDIO_FORMAT_AMRNB_IF1	0x0103d305
+/* 3GPP TS 26.101 Annex A */
+#define ADSP_AUDIO_FORMAT_AMRNB_IF2	0x01057b31
+/* 3GPP TS 26.201 */
+#define ADSP_AUDIO_FORMAT_AMRWB_IF1	0x0103d306
+/* 3GPP TS 26.201 */
+#define ADSP_AUDIO_FORMAT_AMRWB_IF2	0x0105c16d
+/* G.711 */
+#define ADSP_AUDIO_FORMAT_G711		0x0106201d
+/* QCELP  8k, IS96A */
+#define ADSP_AUDIO_FORMAT_V8K_FS	0x01081d29
+/* Version 1 codec */
+#define ADSP_AUDIO_FORMAT_WMA_V1	0x01055b2b
+/* Version 2, 7 & 8 codec */
+#define ADSP_AUDIO_FORMAT_WMA_V8	0x01055b2c
+/* Version 9 Professional codec */
+#define ADSP_AUDIO_FORMAT_WMA_V9PRO	0x01055b2d
+/* Version 9 Voice codec */
+#define ADSP_AUDIO_FORMAT_WMA_SP1	0x01055b2e
+/* Version 9 Lossless codec */
+#define ADSP_AUDIO_FORMAT_WMA_LOSSLESS	0x01055b2f
+/* Real Media content, low-bitrate */
+#define ADSP_AUDIO_FORMAT_RA_SIPR	0x01042a0f
+/* Real Media content */
+#define ADSP_AUDIO_FORMAT_RA_COOK	0x01042a0e
+
+
+/* For all of the audio formats, unless specified otherwise, */
+/* the following apply: */
+/* Format block bits are arranged in bytes and words in little-endian */
+/* order, i.e., least-significant bit first and least-significant */
+/* byte first. */
+
+
+
+/* AAC Format Block. */
+
+/* AAC format block consist of a format identifier followed by */
+/* AudioSpecificConfig formatted according to ISO/IEC 14496-3 */
+
+/* The following AAC format identifiers are supported */
+#define ADSP_AUDIO_AAC_ADTS		0x010619cf
+#define ADSP_AUDIO_AAC_MPEG4_ADTS	0x010619d0
+#define ADSP_AUDIO_AAC_LOAS		0x010619d1
+#define ADSP_AUDIO_AAC_ADIF		0x010619d2
+#define ADSP_AUDIO_AAC_RAW		0x010619d3
+#define ADSP_AUDIO_AAC_FRAMED_RAW	0x0108c1fb
+
+
+#define ADSP_AUDIO_COMPANDING_ALAW	0x10619cd
+#define ADSP_AUDIO_COMPANDING_MLAW	0x10619ce
+
+/* Maxmum number of bytes allowed in a format block */
+#define ADSP_AUDIO_FORMAT_DATA_MAX 16
+
+
+struct adsp_audio_no_payload_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* no payload for this format type */
+} __attribute__ ((packed));
+
+
+/* For convenience, to be used as a standard format block */
+/* for various media types that don't need a unique format block */
+/* ie. PCM, DTMF, etc. */
+struct adsp_audio_standard_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* payload */
+	u16		channels;
+	u16		bits_per_sample;
+	u32		sampling_rate;
+	u8		is_signed;
+	u8		is_interleaved;
+} __attribute__ ((packed));
+
+
+
+/* ADPCM format block */
+struct adsp_audio_adpcm_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* payload */
+	u16		channels;
+	u16		bits_per_sample;
+	u32		sampling_rate;
+	u8		is_signed;
+	u8		is_interleaved;
+	u32		block_size;
+} __attribute__ ((packed));
+
+
+/* MIDI format block */
+struct adsp_audio_midi_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* payload */
+	u32		sampling_rate;
+	u16		channels;
+	u16		mode;
+} __attribute__ ((packed));
+
+
+/* G711 format block */
+struct adsp_audio_g711_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* payload */
+	u32		companding;
+} __attribute__ ((packed));
+
+
+struct adsp_audio_wma_pro_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* payload */
+	u16		format_tag;
+	u16		channels;
+	u32		samples_per_sec;
+	u32		avg_bytes_per_sec;
+	u16		block_align;
+	u16		valid_bits_per_sample;
+	u32		channel_mask;
+	u16		encode_opt;
+	u16		advanced_encode_opt;
+	u32		advanced_encode_opt2;
+	u32		drc_peak_reference;
+	u32		drc_peak_target;
+	u32		drc_average_reference;
+	u32		drc_average_target;
+} __attribute__ ((packed));
+
+
+struct adsp_audio_amrwb_plus_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* payload */
+	u32		size;
+	u32		version;
+	u32		channels;
+	u32		amr_band_mode;
+	u32		amr_dtx_mode;
+	u32		amr_frame_format;
+	u32		amr_isf_index;
+} __attribute__ ((packed));
+
+
+/* Binary Byte Stream Format */
+/* Binary format type that defines a byte stream, */
+/* can be used to specify any format (ie. AAC) */
+struct adsp_audio_binary_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* payload */
+	/* number of bytes set in byte stream */
+	u32		num_bytes;
+	/* Byte stream binary data */
+	u8		data[ADSP_AUDIO_FORMAT_DATA_MAX];
+} __attribute__ ((packed));
+
+
+struct adsp_audio_shared_memory_format {
+	/* Media Format Code (must always be first element) */
+	u32		format;
+
+	/* Number of bytes in shared memory */
+	u32		len;
+	/* Phyisical address to data in shared memory */
+	u32		address;
+} __attribute__ ((packed));
+
+
+/* Union of all format types */
+union adsp_audio_format {
+	/* Basic format block with no payload */
+	struct adsp_audio_no_payload_format	no_payload;
+	/* Generic format block PCM, DTMF */
+	struct adsp_audio_standard_format	standard;
+	/* ADPCM format block */
+	struct adsp_audio_adpcm_format		adpcm;
+	/* MIDI format block */
+	struct adsp_audio_midi_format		midi;
+	/* G711 format block */
+	struct adsp_audio_g711_format		g711;
+	/* WmaPro format block */
+	struct adsp_audio_wma_pro_format	wma_pro;
+	/* WmaPro format block */
+	struct adsp_audio_amrwb_plus_format	amrwb_plus;
+	/* binary (byte stream) format block, used for AAC */
+	struct adsp_audio_binary_format		binary;
+	/* format block in shared memory */
+	struct adsp_audio_shared_memory_format	shared_mem;
+};
+
+#endif
+
diff --git a/arch/arm/mach-msm/qdsp6/dsp_debug.c b/arch/arm/mach-msm/qdsp6/dsp_debug.c
new file mode 100644
index 0000000..922f8cd
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/dsp_debug.c
@@ -0,0 +1,179 @@
+/* arch/arm/mach-msm/qdsp6/dsp_dump.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <asm/atomic.h>
+
+#include <mach/proc_comm.h>
+#include <mach/debug_mm.h>
+
+static wait_queue_head_t dsp_wait;
+static int dsp_has_crashed;
+static int dsp_wait_count;
+
+static atomic_t dsp_crash_count = ATOMIC_INIT(0);
+
+void q6audio_dsp_not_responding(void)
+{
+
+	if (atomic_add_return(1, &dsp_crash_count) != 1) {
+		pr_err("q6audio_dsp_not_responding() - parking additional crasher...\n");
+		for (;;)
+			msleep(1000);
+	}
+	if (dsp_wait_count) {
+		dsp_has_crashed = 1;
+		wake_up(&dsp_wait);
+
+		while (dsp_has_crashed != 2)
+			wait_event(dsp_wait, dsp_has_crashed == 2);
+	} else {
+		pr_err("q6audio_dsp_not_responding() - no waiter?\n");
+	}
+	BUG();
+}
+
+static int dsp_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static ssize_t dsp_write(struct file *file, const char __user *buf,
+			 size_t count, loff_t *pos)
+{
+	char cmd[32];
+
+	if (count >= sizeof(cmd))
+		return -EINVAL;
+	if (copy_from_user(cmd, buf, count))
+		return -EFAULT;
+	cmd[count] = 0;
+
+	if ((count > 1) && (cmd[count-1] == '\n'))
+		cmd[count-1] = 0;
+
+	if (!strcmp(cmd, "wait-for-crash")) {
+		while (!dsp_has_crashed) {
+			int res;
+			dsp_wait_count++;
+			res = wait_event_interruptible(dsp_wait, dsp_has_crashed);
+			if (res < 0) {
+				dsp_wait_count--;
+				return res;
+			}
+		}
+#if defined(CONFIG_MACH_MAHIMAHI)
+		/* assert DSP NMI */
+		msm_proc_comm(PCOM_CUSTOMER_CMD1, 0, 0);
+		msleep(250);
+#endif
+	} else if (!strcmp(cmd, "boom")) {
+		q6audio_dsp_not_responding();
+	} else if (!strcmp(cmd, "continue-crash")) {
+		dsp_has_crashed = 2;
+		wake_up(&dsp_wait);
+	} else {
+		pr_err("[%s:%s] unknown dsp_debug command: %s\n", __MM_FILE__,
+				__func__, cmd);
+	}
+
+	return count;
+}
+
+#define DSP_RAM_BASE 0x2E800000
+#define DSP_RAM_SIZE 0x01800000
+
+static unsigned copy_ok_count;
+
+static ssize_t dsp_read(struct file *file, char __user *buf,
+			size_t count, loff_t *pos)
+{
+	size_t actual = 0;
+	size_t mapsize = PAGE_SIZE;
+	unsigned addr;
+	void __iomem *ptr;
+
+	if (*pos >= DSP_RAM_SIZE)
+		return 0;
+
+	if (*pos & (PAGE_SIZE - 1))
+		return -EINVAL;
+
+	addr = (*pos + DSP_RAM_BASE);
+
+	/* don't blow up if we're unaligned */
+	if (addr & (PAGE_SIZE - 1))
+		mapsize *= 2;
+
+	while (count >= PAGE_SIZE) {
+		ptr = ioremap(addr, mapsize);
+		if (!ptr) {
+			pr_err("[%s:%s] map error @ %x\n", __MM_FILE__,
+					__func__, addr);
+			return -EFAULT;
+		}
+		if (copy_to_user(buf, ptr, PAGE_SIZE)) {
+			iounmap(ptr);
+			pr_err("[%s:%s] copy error @ %p\n", __MM_FILE__,
+					__func__, buf);
+			return -EFAULT;
+		}
+		copy_ok_count += PAGE_SIZE;
+		iounmap(ptr);
+		addr += PAGE_SIZE;
+		buf += PAGE_SIZE;
+		actual += PAGE_SIZE;
+		count -= PAGE_SIZE;
+	}
+
+	*pos += actual;
+	return actual;
+}
+
+static int dsp_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static const struct file_operations dsp_fops = {
+	.owner		= THIS_MODULE,
+	.open		= dsp_open,
+	.read		= dsp_read,
+	.write		= dsp_write,
+	.release	= dsp_release,
+};
+
+static struct miscdevice dsp_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "dsp_debug",
+	.fops	= &dsp_fops,
+};
+
+
+static int __init dsp_init(void)
+{
+	init_waitqueue_head(&dsp_wait);
+	return misc_register(&dsp_misc);
+}
+
+device_initcall(dsp_init);
diff --git a/arch/arm/mach-msm/qdsp6/dtmf.c b/arch/arm/mach-msm/qdsp6/dtmf.c
new file mode 100644
index 0000000..cf27488
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/dtmf.c
@@ -0,0 +1,126 @@
+/* Copyright (c) 2010, 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/slab.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio.h>
+
+#include <mach/msm_qdsp6_audio.h>
+#include <mach/debug_mm.h>
+
+struct dtmf {
+	struct mutex lock;
+	struct audio_client *ac;
+	struct msm_dtmf_config cfg;
+};
+
+static long dtmf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct dtmf *dtmf = file->private_data;
+	int rc = 0;
+
+	mutex_lock(&dtmf->lock);
+	switch (cmd) {
+
+	case AUDIO_START: {
+		pr_debug("[%s:%s] AUDIO_START\n", __MM_FILE__, __func__);
+		if (dtmf->ac) {
+			pr_err("[%s:%s] active session already existing\n",
+				__MM_FILE__, __func__);
+			rc = -EBUSY;
+		} else {
+			dtmf->ac = q6audio_open_dtmf(48000, 2, 0);
+			if (!dtmf->ac)
+				rc = -ENOMEM;
+		}
+		break;
+	}
+	case AUDIO_PLAY_DTMF: {
+		rc = copy_from_user((void *)&dtmf->cfg, (void *)arg,
+					sizeof(struct msm_dtmf_config));
+
+		pr_debug("[%s:%s] PLAY_DTMF: high = %d, low = %d\n",
+			__MM_FILE__, __func__, dtmf->cfg.dtmf_hi,
+			dtmf->cfg.dtmf_low);
+		rc = q6audio_play_dtmf(dtmf->ac, dtmf->cfg.dtmf_hi,
+					dtmf->cfg.dtmf_low, dtmf->cfg.duration,
+					dtmf->cfg.rx_gain);
+		if (rc) {
+			pr_err("[%s:%s] DTMF_START failed\n", __MM_FILE__,
+					__func__);
+			break;
+		}
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&dtmf->lock);
+
+	pr_debug("[%s:%s] rc = %d\n", __MM_FILE__, __func__, rc) ;
+	return rc;
+}
+
+static int dtmf_open(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+
+	struct dtmf *dtmf;
+	pr_info("[%s:%s] open\n", __MM_FILE__, __func__);
+	dtmf = kzalloc(sizeof(struct dtmf), GFP_KERNEL);
+
+	if (!dtmf)
+		return -ENOMEM;
+
+	mutex_init(&dtmf->lock);
+
+	file->private_data = dtmf;
+	return rc;
+}
+
+static int dtmf_release(struct inode *inode, struct file *file)
+{
+	struct dtmf *dtmf = file->private_data;
+	if (dtmf->ac)
+		q6audio_close(dtmf->ac);
+	kfree(dtmf);
+	pr_info("[%s:%s] release\n", __MM_FILE__, __func__);
+	return 0;
+}
+
+static const struct file_operations dtmf_fops = {
+	.owner		= THIS_MODULE,
+	.open		= dtmf_open,
+	.release	= dtmf_release,
+	.unlocked_ioctl	= dtmf_ioctl,
+};
+
+struct miscdevice dtmf_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_dtmf",
+	.fops	= &dtmf_fops,
+};
+
+static int __init dtmf_init(void)
+{
+	return misc_register(&dtmf_misc);
+}
+
+device_initcall(dtmf_init);
diff --git a/arch/arm/mach-msm/qdsp6/evrc_in.c b/arch/arm/mach-msm/qdsp6/evrc_in.c
new file mode 100644
index 0000000..9fc412b
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/evrc_in.c
@@ -0,0 +1,468 @@
+/*
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ * Copyright (c) 2010, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+
+#include <linux/msm_audio_qcp.h>
+#include <mach/msm_qdsp6_audio.h>
+#include "dal_audio_format.h"
+#include <mach/debug_mm.h>
+
+#define EVRC_FC_BUFF_CNT 10
+#define EVRC_READ_TIMEOUT 2000
+struct evrc_fc_buff {
+	struct mutex lock;
+	int empty;
+	void *data;
+	int size;
+	int actual_size;
+};
+
+struct evrc_fc {
+	struct task_struct *task;
+	wait_queue_head_t fc_wq;
+	struct evrc_fc_buff fc_buff[EVRC_FC_BUFF_CNT];
+	int buff_index;
+};
+
+struct evrc {
+	struct mutex lock;
+	struct msm_audio_evrc_enc_config cfg;
+	struct msm_audio_stream_config str_cfg;
+	struct audio_client *audio_client;
+	struct msm_voicerec_mode voicerec_mode;
+	struct evrc_fc *evrc_fc;
+};
+
+
+static int q6_evrc_flowcontrol(void *data)
+{
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	struct evrc *evrc = data;
+	int buff_index = 0;
+	int xfer = 0;
+	struct evrc_fc *fc;
+
+
+	ac = evrc->audio_client;
+	fc = evrc->evrc_fc;
+	if (!ac) {
+		pr_err("[%s:%s] audio_client is NULL\n", __MM_FILE__, __func__);
+		return 0;
+	}
+
+	while (!kthread_should_stop()) {
+		ab = ac->buf + ac->cpu_buf;
+		if (ab->used)
+			wait_event(ac->wait, (ab->used == 0));
+		pr_debug("[%s:%s] ab->data = %p, cpu_buf = %d\n", __MM_FILE__,
+			__func__, ab->data, ac->cpu_buf);
+		xfer = ab->actual_size;
+
+
+		mutex_lock(&(fc->fc_buff[buff_index].lock));
+		if (!fc->fc_buff[buff_index].empty) {
+			pr_err("[%s:%s] flow control buffer[%d] not read!\n",
+					__MM_FILE__, __func__, buff_index);
+		}
+
+		if (fc->fc_buff[buff_index].size < xfer) {
+			pr_err("[%s:%s] buffer %d too small\n", __MM_FILE__,
+					__func__, buff_index);
+			memcpy(fc->fc_buff[buff_index].data, ab->data,
+					fc->fc_buff[buff_index].size);
+			fc->fc_buff[buff_index].empty = 0;
+			fc->fc_buff[buff_index].actual_size =
+					fc->fc_buff[buff_index].size;
+		} else {
+			memcpy(fc->fc_buff[buff_index].data, ab->data, xfer);
+			fc->fc_buff[buff_index].empty = 0;
+			fc->fc_buff[buff_index].actual_size = xfer;
+		}
+		mutex_unlock(&(fc->fc_buff[buff_index].lock));
+		/*wake up client, if any*/
+		wake_up(&fc->fc_wq);
+
+		buff_index++;
+		if (buff_index >= EVRC_FC_BUFF_CNT)
+			buff_index = 0;
+
+		ab->used = 1;
+
+		q6audio_read(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+
+	return 0;
+}
+static long q6_evrc_in_ioctl(struct file *file, unsigned int cmd,
+				unsigned long arg)
+{
+	struct evrc *evrc = file->private_data;
+	int rc = 0;
+	int i = 0;
+	struct evrc_fc *fc;
+	int size = 0;
+
+	mutex_lock(&evrc->lock);
+	switch (cmd) {
+	case AUDIO_SET_VOLUME:
+		pr_debug("[%s:%s] SET_VOLUME\n", __MM_FILE__, __func__);
+		break;
+	case AUDIO_GET_STATS:
+	{
+		struct msm_audio_stats stats;
+		pr_debug("[%s:%s] GET_STATS\n", __MM_FILE__, __func__);
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+	case AUDIO_START:
+	{
+		uint32_t acdb_id;
+		pr_debug("[%s:%s] AUDIO_START\n", __MM_FILE__, __func__);
+		if (arg == 0) {
+			acdb_id = 0;
+		} else {
+			if (copy_from_user(&acdb_id, (void *) arg,
+				sizeof(acdb_id))) {
+				rc = -EFAULT;
+				break;
+			}
+		}
+		if (evrc->audio_client) {
+			rc = -EBUSY;
+			pr_err("[%s:%s] active session already existing\n",
+				__MM_FILE__, __func__);
+			break;
+		} else {
+			evrc->audio_client = q6audio_open_qcp(
+					evrc->str_cfg.buffer_size,
+					evrc->cfg.min_bit_rate,
+					evrc->cfg.max_bit_rate,
+					evrc->voicerec_mode.rec_mode,
+					ADSP_AUDIO_FORMAT_EVRC_FS,
+					acdb_id);
+
+			if (!evrc->audio_client) {
+				pr_err("[%s:%s] evrc open session failed\n",
+					__MM_FILE__, __func__);
+				kfree(evrc);
+				rc = -ENOMEM;
+				break;
+			}
+		}
+
+		/*allocate flow control buffers*/
+		fc = evrc->evrc_fc;
+		size = evrc->str_cfg.buffer_size;
+		for (i = 0; i < EVRC_FC_BUFF_CNT; ++i) {
+			mutex_init(&(fc->fc_buff[i].lock));
+			fc->fc_buff[i].empty = 1;
+			fc->fc_buff[i].data = kmalloc(size, GFP_KERNEL);
+			if (fc->fc_buff[i].data == NULL) {
+				pr_err("[%s:%s] No memory for FC buffers\n",
+						__MM_FILE__, __func__);
+				rc = -ENOMEM;
+				goto fc_fail;
+			}
+			fc->fc_buff[i].size = size;
+			fc->fc_buff[i].actual_size = 0;
+		}
+
+		/*create flow control thread*/
+		fc->task = kthread_run(q6_evrc_flowcontrol,
+				evrc, "evrc_flowcontrol");
+		if (IS_ERR(fc->task)) {
+			rc = PTR_ERR(fc->task);
+			pr_err("[%s:%s] error creating flow control thread\n",
+					__MM_FILE__, __func__);
+			goto fc_fail;
+		}
+		break;
+fc_fail:
+		/*free flow control buffers*/
+		--i;
+		for (; i >=  0; i--) {
+			kfree(fc->fc_buff[i].data);
+			fc->fc_buff[i].data = NULL;
+		}
+		break;
+	}
+	case AUDIO_STOP:
+		pr_debug("[%s:%s] AUDIO_STOP\n", __MM_FILE__, __func__);
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_INCALL: {
+		pr_debug("[%s:%s] SET_INCALL\n", __MM_FILE__, __func__);
+		if (copy_from_user(&evrc->voicerec_mode,
+			(void *)arg, sizeof(struct msm_voicerec_mode)))
+			rc = -EFAULT;
+
+		if (evrc->voicerec_mode.rec_mode != AUDIO_FLAG_READ
+				&& evrc->voicerec_mode.rec_mode !=
+				AUDIO_FLAG_INCALL_MIXED) {
+			evrc->voicerec_mode.rec_mode = AUDIO_FLAG_READ;
+			pr_err("[%s:%s] Invalid rec_mode\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+		}
+		break;
+	}
+	case AUDIO_GET_STREAM_CONFIG:
+		if (copy_to_user((void *)arg, &evrc->str_cfg,
+				sizeof(struct msm_audio_stream_config)))
+			rc = -EFAULT;
+
+		pr_debug("[%s:%s] GET_STREAM_CONFIG: buffsz=%d, buffcnt=%d\n",
+			 __MM_FILE__, __func__, evrc->str_cfg.buffer_size,
+			evrc->str_cfg.buffer_count);
+		break;
+	case AUDIO_SET_STREAM_CONFIG:
+		if (copy_from_user(&evrc->str_cfg, (void *)arg,
+			sizeof(struct msm_audio_stream_config))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		pr_debug("[%s:%s] SET_STREAM_CONFIG: buffsz=%d, buffcnt=%d\n",
+			 __MM_FILE__, __func__, evrc->str_cfg.buffer_size,
+			evrc->str_cfg.buffer_count);
+
+		if (evrc->str_cfg.buffer_size < 23) {
+			pr_err("[%s:%s] Buffer size too small\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+			break;
+		}
+
+		if (evrc->str_cfg.buffer_count != 2)
+			pr_info("[%s:%s] Buffer count set to 2\n", __MM_FILE__,
+					__func__);
+		break;
+	case AUDIO_SET_EVRC_ENC_CONFIG:
+		if (copy_from_user(&evrc->cfg, (void *) arg,
+				 sizeof(struct msm_audio_evrc_enc_config)))
+			rc = -EFAULT;
+		pr_debug("[%s:%s] SET_EVRC_ENC_CONFIG\n", __MM_FILE__,
+				__func__);
+
+		if (evrc->cfg.min_bit_rate > 4 || evrc->cfg.min_bit_rate < 1) {
+			pr_err("[%s:%s] invalid min bitrate\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+		}
+		if (evrc->cfg.max_bit_rate > 4 || evrc->cfg.max_bit_rate < 1) {
+			pr_err("[%s:%s] invalid max bitrate\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+		}
+		break;
+	case AUDIO_GET_EVRC_ENC_CONFIG:
+		if (copy_to_user((void *) arg, &evrc->cfg,
+				 sizeof(struct msm_audio_evrc_enc_config)))
+			rc = -EFAULT;
+		pr_debug("[%s:%s] GET_EVRC_ENC_CONFIG\n", __MM_FILE__,
+			__func__);
+		break;
+
+	default:
+		rc = -EINVAL;
+	}
+
+	mutex_unlock(&evrc->lock);
+	pr_debug("[%s:%s] rc = %d\n", __MM_FILE__, __func__, rc);
+	return rc;
+}
+
+static int q6_evrc_in_open(struct inode *inode, struct file *file)
+{
+	struct evrc *evrc;
+	struct evrc_fc *fc;
+	int i;
+
+	pr_info("[%s:%s] open\n", __MM_FILE__, __func__);
+	evrc = kmalloc(sizeof(struct evrc), GFP_KERNEL);
+	if (evrc == NULL) {
+		pr_err("[%s:%s] Could not allocate memory for evrc driver\n",
+				__MM_FILE__, __func__);
+		return -ENOMEM;
+	}
+
+	mutex_init(&evrc->lock);
+	file->private_data = evrc;
+	evrc->audio_client = NULL;
+	evrc->str_cfg.buffer_size = 23;
+	evrc->str_cfg.buffer_count = 2;
+	evrc->cfg.cdma_rate = CDMA_RATE_FULL;
+	evrc->cfg.min_bit_rate = 1;
+	evrc->cfg.max_bit_rate = 4;
+	evrc->voicerec_mode.rec_mode = AUDIO_FLAG_READ;
+
+	evrc->evrc_fc = kmalloc(sizeof(struct evrc_fc), GFP_KERNEL);
+	if (evrc->evrc_fc == NULL) {
+		pr_err("[%s:%s] Could not allocate memory for evrc_fc\n",
+				__MM_FILE__, __func__);
+		kfree(evrc);
+		return -ENOMEM;
+	}
+	fc = evrc->evrc_fc;
+	fc->task = NULL;
+	fc->buff_index = 0;
+	for (i = 0; i < EVRC_FC_BUFF_CNT; ++i) {
+		fc->fc_buff[i].data = NULL;
+		fc->fc_buff[i].size = 0;
+		fc->fc_buff[i].actual_size = 0;
+	}
+	/*initialize wait queue head*/
+	init_waitqueue_head(&fc->fc_wq);
+	return 0;
+}
+
+static ssize_t q6_evrc_in_read(struct file *file, char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio_client *ac;
+	const char __user *start = buf;
+	struct evrc *evrc = file->private_data;
+	struct evrc_fc *fc;
+	int xfer = 0;
+	int res = 0;
+
+	pr_debug("[%s:%s] count = %d\n", __MM_FILE__, __func__, count);
+	mutex_lock(&evrc->lock);
+	ac = evrc->audio_client;
+	if (!ac) {
+		res = -ENODEV;
+		goto fail;
+	}
+	fc = evrc->evrc_fc;
+	while (count > xfer) {
+		/*wait for buffer to full*/
+		if (fc->fc_buff[fc->buff_index].empty != 0) {
+			res = wait_event_interruptible_timeout(fc->fc_wq,
+				(fc->fc_buff[fc->buff_index].empty == 0),
+				msecs_to_jiffies(EVRC_READ_TIMEOUT));
+
+			pr_debug("[%s:%s] buff_index = %d\n", __MM_FILE__,
+				__func__, fc->buff_index);
+			if (res == 0) {
+				pr_err("[%s:%s] Timeout!\n", __MM_FILE__,
+						__func__);
+				res = -ETIMEDOUT;
+				goto fail;
+			} else if (res < 0) {
+				pr_err("[%s:%s] Returning on Interrupt\n",
+					__MM_FILE__, __func__);
+				goto fail;
+			}
+		}
+		/*lock the buffer*/
+		mutex_lock(&(fc->fc_buff[fc->buff_index].lock));
+		xfer = fc->fc_buff[fc->buff_index].actual_size;
+
+		if (xfer > count) {
+			mutex_unlock(&(fc->fc_buff[fc->buff_index].lock));
+			pr_err("[%s:%s] read failed! byte count too small\n",
+					__MM_FILE__, __func__);
+			res = -EINVAL;
+			goto fail;
+		}
+
+		if (copy_to_user(buf, fc->fc_buff[fc->buff_index].data,	xfer)) {
+			mutex_unlock(&(fc->fc_buff[fc->buff_index].lock));
+			pr_err("[%s:%s] copy_to_user failed at index %d\n",
+					__MM_FILE__, __func__, fc->buff_index);
+			res = -EFAULT;
+			goto fail;
+		}
+		buf += xfer;
+		count -= xfer;
+
+		fc->fc_buff[fc->buff_index].empty = 1;
+		fc->fc_buff[fc->buff_index].actual_size = 0;
+
+		mutex_unlock(&(fc->fc_buff[fc->buff_index].lock));
+		++(fc->buff_index);
+		if (fc->buff_index >= EVRC_FC_BUFF_CNT)
+			fc->buff_index = 0;
+	}
+	res = buf - start;
+
+fail:
+	mutex_unlock(&evrc->lock);
+
+	return res;
+}
+
+static int q6_evrc_in_release(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	struct evrc *evrc = file->private_data;
+	int i = 0;
+	struct evrc_fc *fc;
+
+	mutex_lock(&evrc->lock);
+	fc = evrc->evrc_fc;
+	kthread_stop(fc->task);
+	fc->task = NULL;
+	/*free flow control buffers*/
+	for (i = 0; i < EVRC_FC_BUFF_CNT; ++i) {
+		kfree(fc->fc_buff[i].data);
+		fc->fc_buff[i].data = NULL;
+	}
+	kfree(fc);
+	if (evrc->audio_client)
+		rc = q6audio_close(evrc->audio_client);
+	mutex_unlock(&evrc->lock);
+	kfree(evrc);
+	pr_info("[%s:%s] release\n", __MM_FILE__, __func__);
+	return rc;
+}
+
+static const struct file_operations q6_evrc_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_evrc_in_open,
+	.read		= q6_evrc_in_read,
+	.release	= q6_evrc_in_release,
+	.unlocked_ioctl	= q6_evrc_in_ioctl,
+};
+
+struct miscdevice q6_evrc_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_evrc_in",
+	.fops	= &q6_evrc_in_fops,
+};
+
+static int __init q6_evrc_in_init(void)
+{
+	return misc_register(&q6_evrc_in_misc);
+}
+
+device_initcall(q6_evrc_in_init);
diff --git a/arch/arm/mach-msm/qdsp6/mp3.c b/arch/arm/mach-msm/qdsp6/mp3.c
new file mode 100644
index 0000000..16f6204
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/mp3.c
@@ -0,0 +1,249 @@
+/* arch/arm/mach-msm/qdsp6/mp3.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ *
+ * 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio.h>
+
+#include <mach/msm_qdsp6_audio.h>
+#include <mach/debug_mm.h>
+
+#define BUFSZ (8192)
+#define DMASZ (BUFSZ * 2)
+
+struct mp3 {
+	struct mutex lock;
+	struct audio_client *ac;
+	uint32_t sample_rate;
+	uint32_t channel_count;
+};
+
+static long mp3_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct mp3 *mp3 = file->private_data;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void*) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	mutex_lock(&mp3->lock);
+	switch (cmd) {
+	case AUDIO_SET_VOLUME: {
+		int vol;
+		pr_debug("[%s:%s] SET_VOLUME = %d\n", __MM_FILE__,
+			__func__, vol);
+		if (copy_from_user(&vol, (void*) arg, sizeof(vol))) {
+			rc = -EFAULT;
+			break;
+		}
+		rc = q6audio_set_stream_volume(mp3->ac, vol);
+		break;
+	}
+	case AUDIO_START: {
+		uint32_t acdb_id;
+		pr_debug("[%s:%s] AUDIO_START\n", __MM_FILE__, __func__);
+		if (arg == 0) {
+			acdb_id = 0;
+		} else if (copy_from_user(&acdb_id, (void*) arg, sizeof(acdb_id))) {
+			pr_info("[%s:%s] copy acdb_id from user failed\n",
+					__MM_FILE__, __func__);
+			rc = -EFAULT;
+			break;
+		}
+		if (mp3->ac) {
+			pr_err("[%s:%s] active session already existing\n",
+				__MM_FILE__, __func__);
+			rc = -EBUSY;
+		} else {
+			mp3->ac = q6audio_open_mp3(BUFSZ,
+				mp3->sample_rate, mp3->channel_count, acdb_id);
+			if (!mp3->ac) {
+				pr_err("[%s:%s] mp3 open session failed\n",
+					__MM_FILE__, __func__);
+				rc = -ENOMEM;
+			}
+		}
+		break;
+	}
+	case AUDIO_STOP:
+		pr_debug("[%s:%s] AUDIO_STOP\n", __MM_FILE__, __func__);
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (mp3->ac) {
+			rc = -EBUSY;
+			pr_err("[%s:%s] active session already existing\n",
+				__MM_FILE__, __func__);
+			break;
+		}
+		if (copy_from_user(&config, (void*) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("[%s:%s] SET_CONFIG: buffsize = %d, samplerate = %d, \
+			channelcount = %d\n", __MM_FILE__, __func__,
+			config.buffer_size, config.sample_rate,
+			config.channel_count);
+		if (config.channel_count < 1 || config.channel_count > 2) {
+			rc = -EINVAL;
+			pr_err("[%s:%s] invalid channelcount\n", __MM_FILE__,
+				__func__);
+			break;
+		}
+		mp3->sample_rate = config.sample_rate;
+		mp3->channel_count = config.channel_count;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_size = BUFSZ;
+		config.buffer_count = 2;
+		config.sample_rate = mp3->sample_rate;
+		config.channel_count = mp3->channel_count;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void*) arg, &config, sizeof(config))) {
+			rc = -EFAULT;
+		}
+		pr_debug("[%s:%s] GET_CONFIG: buffsize = %d, samplerate = %d, \
+			channelcount = %d\n", __MM_FILE__, __func__,
+			config.buffer_size, config.sample_rate,
+			config.channel_count);
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&mp3->lock);
+	pr_debug("[%s:%s] rc = %d\n", __MM_FILE__, __func__, rc);
+	return rc;
+}
+
+static int mp3_open(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+
+	struct mp3 *mp3;
+	pr_info("[%s:%s] open\n", __MM_FILE__, __func__);
+	mp3 = kzalloc(sizeof(struct mp3), GFP_KERNEL);
+
+	if (!mp3)
+		return -ENOMEM;
+
+	mutex_init(&mp3->lock);
+	mp3->channel_count = 2;
+	mp3->sample_rate = 44100;
+
+	file->private_data = mp3;
+	return rc;
+}
+
+static ssize_t mp3_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct mp3 *mp3 = file->private_data;
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	const char __user *start = buf;
+	int xfer;
+
+	pr_debug("[%s:%s] count = %d\n", __MM_FILE__, __func__, count);
+	if (!mp3->ac)
+		mp3_ioctl(file, AUDIO_START, 0);
+
+	ac = mp3->ac;
+	if (!ac)
+		return -ENODEV;
+
+	while (count > 0) {
+		ab = ac->buf + ac->cpu_buf;
+
+		if (ab->used)
+			wait_event(ac->wait, (ab->used == 0));
+
+		pr_debug("[%s:%s] ab->data = %p, ac->cpu_buf = %d\n",
+			__MM_FILE__, __func__, ab->data, ac->cpu_buf);
+		xfer = count;
+		if (xfer > ab->size)
+			xfer = ab->size;
+
+		if (copy_from_user(ab->data, buf, xfer))
+			return -EFAULT;
+
+		buf += xfer;
+		count -= xfer;
+
+		ab->used = xfer;
+		q6audio_write(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+
+	return buf - start;
+}
+
+static int mp3_fsync(struct file *f, int datasync)
+{
+	struct mp3 *mp3 = f->private_data;
+	if (mp3->ac)
+		return q6audio_async(mp3->ac);
+	return -ENODEV;
+}
+
+static int mp3_release(struct inode *inode, struct file *file)
+{
+	struct mp3 *mp3 = file->private_data;
+	if (mp3->ac)
+		q6audio_mp3_close(mp3->ac);
+	kfree(mp3);
+	pr_info("[%s:%s] release\n", __MM_FILE__, __func__);
+	return 0;
+}
+
+static struct file_operations mp3_fops = {
+	.owner		= THIS_MODULE,
+	.open		= mp3_open,
+	.write		= mp3_write,
+	.fsync		= mp3_fsync,
+	.release	= mp3_release,
+	.unlocked_ioctl	= mp3_ioctl,
+};
+
+struct miscdevice mp3_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_mp3",
+	.fops	= &mp3_fops,
+};
+
+static int __init mp3_init(void) {
+	return misc_register(&mp3_misc);
+}
+
+device_initcall(mp3_init);
diff --git a/arch/arm/mach-msm/qdsp6/msm_q6vdec.c b/arch/arm/mach-msm/qdsp6/msm_q6vdec.c
new file mode 100644
index 0000000..c79f0c4
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/msm_q6vdec.c
@@ -0,0 +1,1505 @@
+/* Copyright (c) 2008-2010, 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.
+ *
+ */
+
+/*
+#define DEBUG_TRACE_VDEC
+#define DEBUG
+*/
+
+#include <linux/slab.h>
+#include <linux/cdev.h>
+#include <linux/delay.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/wakelock.h>
+
+#include <linux/android_pmem.h>
+#include <linux/msm_q6vdec.h>
+
+#include "dal.h"
+
+#define DALDEVICEID_VDEC_DEVICE		0x02000026
+#define DALDEVICEID_VDEC_PORTNAME	"DAL_AQ_VID"
+
+#define VDEC_INTERFACE_VERSION		0x00020000
+
+#define MAJOR_MASK			0xFFFF0000
+#define MINOR_MASK			0x0000FFFF
+
+#define VDEC_GET_MAJOR_VERSION(version)	(((version)&MAJOR_MASK)>>16)
+
+#define VDEC_GET_MINOR_VERSION(version)	((version)&MINOR_MASK)
+
+#ifdef DEBUG_TRACE_VDEC
+#define TRACE(fmt,x...)			\
+	do { pr_debug("%s:%d " fmt, __func__, __LINE__, ##x); } while (0)
+#else
+#define TRACE(fmt,x...)		do { } while (0)
+#endif
+
+#define YAMATO_COLOR_FORMAT  0x02
+#define MAX_Q6_LOAD        ((720*1280)/256)  /* 720p */
+#define MAX_Q6_LOAD_YAMATO ((736*1280)/256)
+#define MAX_Q6_LOAD_VP6    ((800*480)/256)
+
+#define VDEC_MAX_PORTS 4
+
+/*
+ *why magic number 300?
+
+ *the Maximum size of the DAL payload is 512 bytes according to DAL protocol
+ *Initialize call to QDSP6 from scorpion need to send sequence header as part of
+ *the DAL payload. DAL payload to initialize contains the following
+
+ *1) configuration data- 52 bytes 2) length field of config data - 4 bytes
+ *3) sequence header data ( that is from the bit stream)
+ *4) length field for sequence header - 4 bytes
+ *5) length field for output structure - 4 bytes
+
+ *that left with 512 - 68 = 448 bytes. It is unusual that we get a sequence
+ *header with such a big length unless the bit stream has multiple sequence
+ *headers.We estimated 300 is good enough which gives enough room for rest
+ *of the payload and even reserves some space for future payload.
+ */
+
+#define VDEC_MAX_SEQ_HEADER_SIZE 300
+
+char *Q6Portnames[] = {
+"DAL_AQ_VID_0",
+"DAL_AQ_VID_1",
+"DAL_AQ_VID_2",
+"DAL_AQ_VID_3"
+};
+
+
+
+#define DALDEVICEID_VDEC_DEVICE_0        0x020000D2
+#define DALDEVICEID_VDEC_DEVICE_1        0x020000D3
+#define DALDEVICEID_VDEC_DEVICE_2        0x020000D4
+#define DALDEVICEID_VDEC_DEVICE_3        0x020000D5
+#define DALDEVICEID_VDEC_DEVICE_4        0x020000D6
+#define DALDEVICEID_VDEC_DEVICE_5        0x020000D7
+#define DALDEVICEID_VDEC_DEVICE_6        0x020000D8
+#define DALDEVICEID_VDEC_DEVICE_7        0x020000D9
+#define DALDEVICEID_VDEC_DEVICE_8        0x020000DA
+#define DALDEVICEID_VDEC_DEVICE_9        0x020000DB
+#define DALDEVICEID_VDEC_DEVICE_10        0x020000DC
+#define DALDEVICEID_VDEC_DEVICE_11        0x020000DD
+#define DALDEVICEID_VDEC_DEVICE_12        0x020000DE
+#define DALDEVICEID_VDEC_DEVICE_13        0x020000DF
+#define DALDEVICEID_VDEC_DEVICE_14        0x020000E0
+#define DALDEVICEID_VDEC_DEVICE_15        0x020000E1
+#define DALDEVICEID_VDEC_DEVICE_16        0x020000E2
+#define DALDEVICEID_VDEC_DEVICE_17        0x020000E3
+#define DALDEVICEID_VDEC_DEVICE_18        0x020000E4
+#define DALDEVICEID_VDEC_DEVICE_19        0x020000E5
+#define DALDEVICEID_VDEC_DEVICE_20        0x020000E6
+#define DALDEVICEID_VDEC_DEVICE_21        0x020000E7
+#define DALDEVICEID_VDEC_DEVICE_22        0x020000E8
+#define DALDEVICEID_VDEC_DEVICE_23        0x020000E9
+#define DALDEVICEID_VDEC_DEVICE_24        0x020000EA
+#define DALDEVICEID_VDEC_DEVICE_25        0x020000EB
+#define DALDEVICEID_VDEC_DEVICE_26        0x020000EC
+#define DALDEVICEID_VDEC_DEVICE_27        0x020000ED
+#define DALDEVICEID_VDEC_DEVICE_28        0x020000EE
+#define DALDEVICEID_VDEC_DEVICE_29        0x020000EF
+#define DALDEVICEID_VDEC_DEVICE_30        0x020000F0
+#define DALDEVICEID_VDEC_DEVICE_31        0x020000F1
+
+#define DALVDEC_MAX_DEVICE_IDS        32
+
+
+static int numOfPorts;
+
+
+static char loadOnPorts[VDEC_MAX_PORTS];
+
+static char deviceIdRegistry[DALVDEC_MAX_DEVICE_IDS];
+
+
+#define VDEC_DEVID_FREE 0
+#define VDEC_DEVID_OCCUPIED 1
+
+#define MAX_SUPPORTED_INSTANCES 6
+
+#define  MAKEFOURCC(ch0, ch1, ch2, ch3) ((unsigned int)(unsigned char)(ch0) | \
+	((unsigned int)(unsigned char)(ch1) << 8) | \
+	((unsigned int)(unsigned char)(ch2) << 16) | \
+	((unsigned int)(unsigned char)(ch3) << 24))
+
+#define FOURCC_MPEG4 MAKEFOURCC('m', 'p', '4', 'v')
+#define FOURCC_H263 MAKEFOURCC('h', '2', '6', '3')
+#define FOURCC_H264 MAKEFOURCC('h', '2', '6', '4')
+#define FOURCC_VC1 MAKEFOURCC('w', 'm', 'v', '3')
+#define FOURCC_DIVX MAKEFOURCC('D', 'I', 'V', 'X')
+#define FOURCC_SPARK MAKEFOURCC('F', 'L', 'V', '1')
+#define FOURCC_VP6 MAKEFOURCC('V', 'P', '6', '0')
+
+/* static struct vdec_data *multiInstances[MAX_SUPPORTED_INSTANCES];*/
+
+static int totalPlaybackQ6load;
+static int totalTnailQ6load;
+
+#define FLAG_THUMBNAIL_MODE  0x8
+#define MAX_TNAILS  3
+
+#define TRUE 1
+#define FALSE 0
+
+enum {
+	VDEC_DALRPC_INITIALIZE = DAL_OP_FIRST_DEVICE_API,
+	VDEC_DALRPC_SETBUFFERS,
+	VDEC_DALRPC_FREEBUFFERS,
+	VDEC_DALRPC_QUEUE,
+	VDEC_DALRPC_SIGEOFSTREAM,
+	VDEC_DALRPC_FLUSH,
+	VDEC_DALRPC_REUSEFRAMEBUFFER,
+	VDEC_DALRPC_GETDECATTRIBUTES,
+	VDEC_DALRPC_SUSPEND,
+	VDEC_DALRPC_RESUME,
+	VDEC_DALRPC_INITIALIZE_00,
+	VDEC_DALRPC_GETINTERNALBUFFERREQ,
+	VDEC_DALRPC_SETBUFFERS_00,
+	VDEC_DALRPC_FREEBUFFERS_00,
+	VDEC_DALRPC_GETPROPERTY,
+	VDEC_DALRPC_SETPROPERTY,
+	VDEC_DALRPC_GETDECATTRIBUTES_00,
+	VDEC_DALRPC_PERFORMANCE_CHANGE_REQUEST
+};
+
+enum {
+	VDEC_ASYNCMSG_DECODE_DONE = 0xdec0de00,
+	VDEC_ASYNCMSG_REUSE_FRAME,
+};
+
+struct vdec_init_cfg {
+	u32			decode_done_evt;
+	u32			reuse_frame_evt;
+	struct vdec_config	cfg;
+};
+
+struct vdec_buffer_status {
+	u32			data;
+	u32			status;
+};
+
+#define VDEC_MSG_MAX		128
+
+struct vdec_msg_list {
+	struct list_head	list;
+	struct vdec_msg		vdec_msg;
+};
+
+struct vdec_mem_info {
+	u32			buf_type;
+	u32			id;
+	unsigned long		phys_addr;
+	unsigned long		len;
+	struct file		*file;
+};
+
+struct vdec_mem_list {
+	struct list_head	list;
+	struct vdec_mem_info	mem;
+};
+
+struct videoStreamDetails{
+	int height;
+	int width;
+	unsigned int fourcc;
+	int Q6usage;
+	bool isThisTnail;
+	bool isTnailGranted;
+};
+
+struct vdec_data {
+	struct dal_client	*vdec_handle;
+	unsigned int Q6deviceId;
+	struct videoStreamDetails streamDetails;
+	struct list_head	vdec_msg_list_head;
+	struct list_head	vdec_msg_list_free;
+	wait_queue_head_t	vdec_msg_evt;
+	spinlock_t		vdec_list_lock;
+	struct list_head	vdec_mem_list_head;
+	spinlock_t		vdec_mem_list_lock;
+	int			mem_initialized;
+	int			running;
+	int			close_decode;
+};
+
+static struct class *driver_class;
+static dev_t vdec_device_no;
+static struct cdev vdec_cdev;
+static int ref_cnt;
+static DEFINE_MUTEX(vdec_ref_lock);
+
+static DEFINE_MUTEX(idlecount_lock);
+
+static DEFINE_MUTEX(vdec_rm_lock);
+
+static int idlecount;
+static struct wake_lock wakelock;
+static struct wake_lock idlelock;
+
+static void prevent_sleep(void)
+{
+	mutex_lock(&idlecount_lock);
+	if (++idlecount == 1) {
+		wake_lock(&idlelock);
+		wake_lock(&wakelock);
+	}
+	mutex_unlock(&idlecount_lock);
+}
+
+static void allow_sleep(void)
+{
+	mutex_lock(&idlecount_lock);
+	if (--idlecount == 0) {
+		wake_unlock(&idlelock);
+		wake_unlock(&wakelock);
+	}
+	mutex_unlock(&idlecount_lock);
+}
+
+static inline int vdec_check_version(u32 client, u32 server)
+{
+	int ret = -EINVAL;
+	if ((VDEC_GET_MAJOR_VERSION(client) == VDEC_GET_MAJOR_VERSION(server))
+	    && (VDEC_GET_MINOR_VERSION(client) <=
+		VDEC_GET_MINOR_VERSION(server)))
+		ret = 0;
+	return ret;
+}
+
+static int vdec_get_msg(struct vdec_data *vd, void *msg)
+{
+	struct vdec_msg_list *l;
+	unsigned long flags;
+	int ret = 0;
+
+	if (!vd->running)
+		return -EPERM;
+
+	spin_lock_irqsave(&vd->vdec_list_lock, flags);
+	list_for_each_entry_reverse(l, &vd->vdec_msg_list_head, list) {
+		if (copy_to_user(msg, &l->vdec_msg, sizeof(struct vdec_msg)))
+			pr_err("vdec_get_msg failed to copy_to_user!\n");
+		if (l->vdec_msg.id == VDEC_MSG_REUSEINPUTBUFFER)
+			TRACE("reuse_input_buffer %d\n", l->vdec_msg.buf_id);
+		else if (l->vdec_msg.id == VDEC_MSG_FRAMEDONE)
+			TRACE("frame_done (stat=%d)\n",
+			      l->vdec_msg.vfr_info.status);
+		else
+			TRACE("unknown msg (msgid=%d)\n", l->vdec_msg.id);
+		list_del(&l->list);
+		list_add(&l->list, &vd->vdec_msg_list_free);
+		ret = 1;
+		break;
+	}
+	spin_unlock_irqrestore(&vd->vdec_list_lock, flags);
+
+	if (vd->close_decode)
+		ret = 1;
+
+	return ret;
+}
+
+static void vdec_put_msg(struct vdec_data *vd, struct vdec_msg *msg)
+{
+	struct vdec_msg_list *l;
+	unsigned long flags;
+	int found = 0;
+
+	spin_lock_irqsave(&vd->vdec_list_lock, flags);
+	list_for_each_entry(l, &vd->vdec_msg_list_free, list) {
+		memcpy(&l->vdec_msg, msg, sizeof(struct vdec_msg));
+		list_del(&l->list);
+		list_add(&l->list, &vd->vdec_msg_list_head);
+		found = 1;
+		break;
+	}
+	spin_unlock_irqrestore(&vd->vdec_list_lock, flags);
+
+	if (found)
+		wake_up(&vd->vdec_msg_evt);
+	else
+		pr_err("vdec_put_msg can't find free list!\n");
+}
+
+static struct vdec_mem_list *vdec_get_mem_from_list(struct vdec_data *vd,
+						    u32 pmem_id, u32 buf_type)
+{
+	struct vdec_mem_list *l;
+	unsigned long flags;
+	int found = 0;
+
+	spin_lock_irqsave(&vd->vdec_mem_list_lock, flags);
+	list_for_each_entry(l, &vd->vdec_mem_list_head, list) {
+		if (l->mem.buf_type == buf_type && l->mem.id == pmem_id) {
+			found = 1;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&vd->vdec_mem_list_lock, flags);
+
+	if (found)
+		return l;
+	else
+		return NULL;
+
+}
+static int vdec_setproperty(struct vdec_data *vd, void *argp)
+{
+	struct vdec_property_info property;
+	int res;
+
+   if (copy_from_user(&property, argp, sizeof(struct vdec_property_info)))
+		return -1;
+
+	res = dal_call_f6(vd->vdec_handle, VDEC_DALRPC_SETPROPERTY,
+      property.id, &(property.property), sizeof(union vdec_property));
+	if (res)
+		TRACE("Set Property failed");
+	else
+		TRACE("Set Property succeeded");
+	return res;
+}
+static int vdec_getproperty(struct vdec_data *vd, void *argp)
+{
+	int res;
+	union vdec_property property = {0};
+
+	res = dal_call_f11(vd->vdec_handle, VDEC_DALRPC_GETPROPERTY,
+		((struct vdec_property_info *)argp)->id, &property,
+		sizeof(union vdec_property));
+
+	if (res)
+		TRACE("get Property failed");
+	else
+		TRACE("get Property succeeded");
+
+	res = copy_to_user(
+		(&((struct vdec_property_info *)argp)->property),
+		&property, sizeof(property));
+
+	return res;
+}
+static int vdec_performance_change_request(struct vdec_data *vd, void* argp)
+{
+	u32 request_type;
+	int ret;
+
+	ret = copy_from_user(&request_type, argp, sizeof(request_type));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+	ret = dal_call_f0(vd->vdec_handle,
+			VDEC_DALRPC_PERFORMANCE_CHANGE_REQUEST,
+			request_type);
+	if (ret) {
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+		return ret;
+	}
+	return ret;
+}
+
+#ifdef TRACE_PORTS
+static void printportsanddeviceids(void)
+{
+	int i;
+
+	pr_err("\n\n%s:loadOnPorts", __func__);
+	for (i = 0; i < numOfPorts; i++)
+		pr_err("\t%d", loadOnPorts[i]);
+
+	pr_err("\n\n");
+
+	pr_err("\n\n%s:Devids", __func__);
+	for (i = 0; i < DALVDEC_MAX_DEVICE_IDS; i++)
+		pr_err("Devid[%d]:%d\n", i, deviceIdRegistry[i]);
+
+
+	pr_err("\n\n");
+}
+#endif /*TRACE_PORTS*/
+
+
+/*
+ *
+ * This method is used to get the number of ports supported on the Q6
+ *
+ */
+static int vdec_get_numberofq6ports(void)
+{
+	struct dal_client *vdec_handle = NULL;
+	int retval = 0;
+	union vdec_property property = {0};
+
+	vdec_handle = dal_attach(DALDEVICEID_VDEC_DEVICE,
+			     DALDEVICEID_VDEC_PORTNAME, 1, NULL, NULL);
+	if (!vdec_handle) {
+		pr_err("%s: failed to attach\n", __func__);
+		return 1;/* default setting */
+	}
+
+	retval = dal_call_f6(vdec_handle, VDEC_DALRPC_GETPROPERTY,
+      VDEC_NUM_DAL_PORTS, (void *)&property, sizeof(union vdec_property));
+	if (retval) {
+		pr_err("%s: Q6get prperty failed\n", __func__);
+		return 1;/* default setting */
+	}
+
+	dal_detach(vdec_handle);
+	return property.num_dal_ports ;
+}
+
+
+/**
+  * This method is used to get the find the least loaded port and a corresponding
+  * free device id in that port.
+  *
+  * Prerequisite: vdec_open should have been called.
+  *
+  *  @param[in] deviceid
+  *     device id will be populated here.
+  *
+  *  @param[in] portname
+  *     portname will be populated here.
+  */
+static void vdec_get_next_portanddevid(int *deviceid, char **portname)
+{
+
+	int i = 0;
+	int leastLoad = 0;
+	int leastLoadedIndex = 0;
+
+	if (0 == numOfPorts) {
+		numOfPorts = vdec_get_numberofq6ports();
+		pr_err("%s: Q6get numOfPorts %d\n", __func__, numOfPorts);
+		numOfPorts = 4;
+		/*fix: me currently hard coded to 4 as
+		 *the Q6 getproperty is failing
+		 */
+	}
+
+	if ((NULL == deviceid) || (NULL == portname))
+		return;
+	else
+		*deviceid = 0; /* init value */
+
+	if (numOfPorts > 1) {
+		/* multi ports mode*/
+
+		/* find the least loaded port*/
+		for (i = 1, leastLoad = loadOnPorts[0], leastLoadedIndex = 0;
+					i < numOfPorts; i++) {
+			if (leastLoad > loadOnPorts[i]) {
+				leastLoadedIndex = i;
+				leastLoad = loadOnPorts[i];
+			}
+		}
+
+		/* register the load */
+		loadOnPorts[leastLoadedIndex]++;
+		*portname = Q6Portnames[leastLoadedIndex];
+
+		/* find a free device id corresponding to the port*/
+		for (i = leastLoadedIndex; i < DALVDEC_MAX_DEVICE_IDS;
+					i += numOfPorts) {
+			if (VDEC_DEVID_FREE == deviceIdRegistry[i]) {
+				deviceIdRegistry[i] = VDEC_DEVID_OCCUPIED;
+				*deviceid = DALDEVICEID_VDEC_DEVICE_0 + i;
+				break;
+			}
+		}
+
+#ifdef TRACE_PORTS
+		printportsanddeviceids();
+#endif /*TRACE_PORTS*/
+	} else if (1 == numOfPorts) {
+		/* single port mode */
+		*deviceid = DALDEVICEID_VDEC_DEVICE;
+		*portname = DALDEVICEID_VDEC_PORTNAME;
+	} else if (numOfPorts <= 0) {
+		pr_err("%s: FATAL error numOfPorts cannot be \
+			less than or equal to zero\n", __func__);
+	}
+
+
+}
+
+
+/**
+  * This method frees up the used dev id and decrements the port load.
+  *
+  */
+
+static void vdec_freeup_portanddevid(int deviceid)
+{
+
+	if (numOfPorts > 1) {
+		/* multi ports mode*/
+		if (VDEC_DEVID_FREE ==
+			deviceIdRegistry[deviceid - DALDEVICEID_VDEC_DEVICE_0])
+			pr_err("device id cannot be already free\n");
+		deviceIdRegistry[deviceid - DALDEVICEID_VDEC_DEVICE_0] =
+			VDEC_DEVID_FREE;
+
+		loadOnPorts[(deviceid - DALDEVICEID_VDEC_DEVICE_0)
+			% numOfPorts]--;
+
+		if (loadOnPorts[(deviceid - DALDEVICEID_VDEC_DEVICE_0)
+			% numOfPorts] < 0)
+			pr_err("Warning:load cannot be negative\n");
+
+		pr_err("dettaching on deviceid %x portname %s\n", deviceid,
+			Q6Portnames[(deviceid - DALDEVICEID_VDEC_DEVICE_0)
+			% numOfPorts]);
+
+#ifdef TRACE_PORTS
+		printportsanddeviceids();
+#endif /*TRACE_PORTS*/
+	} else {
+		/*single port mode, nothing to be done here*/
+	}
+
+}
+
+
+/**
+  * This method validates whether a new instance can be houred or not.
+  *
+  */
+static int vdec_rm_checkWithRm(struct vdec_data *vdecInstance,
+				unsigned int color_format)
+{
+
+	unsigned int maxQ6load = 0;/* in the units of macro blocks per second */
+	unsigned int currentq6load = 0;
+	struct videoStreamDetails *streamDetails = &vdecInstance->streamDetails;
+
+
+
+	if (streamDetails->isThisTnail) {
+		if (totalTnailQ6load < MAX_TNAILS) {
+
+			totalTnailQ6load++;
+			streamDetails->isTnailGranted = TRUE;
+			pr_info("%s: thumbnail granted %d\n", __func__,
+				totalTnailQ6load);
+			return 0;
+
+		} else {
+
+			pr_err("%s: thumbnails load max this instance cannot \
+					be supported\n", __func__);
+			streamDetails->isTnailGranted = FALSE;
+			return -ENOSPC;
+
+		}
+	}
+
+	/* calculate the Q6 percentage instance would need */
+	if ((streamDetails->fourcc == FOURCC_MPEG4) ||
+		 (streamDetails->fourcc  == FOURCC_H264) ||
+		 (streamDetails->fourcc  == FOURCC_DIVX) ||
+		 (streamDetails->fourcc  == FOURCC_VC1) ||
+		 (streamDetails->fourcc  == FOURCC_SPARK) ||
+		 (streamDetails->fourcc  == FOURCC_H263)
+		){
+
+		/* is yamato color format,
+		  Rounds the H & W --> mutiple of 32 */
+		if (color_format == YAMATO_COLOR_FORMAT)
+			maxQ6load = MAX_Q6_LOAD_YAMATO;
+		else
+			maxQ6load = MAX_Q6_LOAD; /* 720p */
+
+	} else if (streamDetails->fourcc  == FOURCC_VP6) {
+
+		maxQ6load = MAX_Q6_LOAD_VP6;    /* FWVGA */
+
+	} else {
+
+		pr_err("%s: unknown fourcc %d  maxQ6load %u\n", __func__,
+			streamDetails->fourcc, maxQ6load);
+		return -EINVAL;
+
+	}
+
+	currentq6load = ((streamDetails->height)*(streamDetails->width) / 256);
+	currentq6load = ((currentq6load * 100)/maxQ6load);
+	if ((currentq6load+totalPlaybackQ6load) > 100) {
+		/* reject this instance */
+		pr_err("%s: too much Q6load [cur+tot] = [%d + %d] = %d",
+		__func__, currentq6load, totalPlaybackQ6load,
+		(currentq6load+totalPlaybackQ6load));
+		pr_err("rejecting the instance,[WxH] = [%d x %d],color_fmt=0x%x\n",
+		streamDetails->width, streamDetails->height, color_format);
+		pr_err("VDEC_fmt=%s\n", (char *)(&streamDetails->fourcc));
+		streamDetails->Q6usage = 0;
+		return -ENOSPC;
+	}
+
+	totalPlaybackQ6load += currentq6load;
+	streamDetails->Q6usage = currentq6load;
+
+	pr_info("%s: adding a load [%d%%] bringing total Q6load to [%d%%]\n",
+		__func__, currentq6load, totalPlaybackQ6load);
+
+	return 0;
+}
+
+
+static int vdec_initialize(struct vdec_data *vd, void *argp)
+{
+	struct vdec_config_sps vdec_cfg_sps;
+	struct vdec_init_cfg vi_cfg;
+	struct vdec_buf_req vdec_buf_req;
+	struct u8 *header;
+	int ret = 0;
+
+	ret = copy_from_user(&vdec_cfg_sps,
+			     &((struct vdec_init *)argp)->sps_cfg,
+			     sizeof(vdec_cfg_sps));
+
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+
+	vi_cfg.decode_done_evt = VDEC_ASYNCMSG_DECODE_DONE;
+	vi_cfg.reuse_frame_evt = VDEC_ASYNCMSG_REUSE_FRAME;
+	memcpy(&vi_cfg.cfg, &vdec_cfg_sps.cfg, sizeof(struct vdec_config));
+
+	/*
+	 * restricting the max value of the seq header
+	 */
+	if (vdec_cfg_sps.seq.len > VDEC_MAX_SEQ_HEADER_SIZE)
+		vdec_cfg_sps.seq.len = VDEC_MAX_SEQ_HEADER_SIZE;
+
+	header = kmalloc(vdec_cfg_sps.seq.len, GFP_KERNEL);
+	if (!header) {
+		pr_err("%s: kmalloc failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	ret = copy_from_user(header,
+			     ((struct vdec_init *)argp)->sps_cfg.seq.header,
+			     vdec_cfg_sps.seq.len);
+
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		kfree(header);
+		return ret;
+	}
+
+	TRACE("vi_cfg: handle=%p fourcc=0x%x w=%d h=%d order=%d notify_en=%d "
+	      "vc1_rb=%d h264_sd=%d h264_nls=%d pp_flag=%d fruc_en=%d\n",
+	      vd->vdec_handle, vi_cfg.cfg.fourcc, vi_cfg.cfg.width,
+	      vi_cfg.cfg.height, vi_cfg.cfg.order, vi_cfg.cfg.notify_enable,
+	      vi_cfg.cfg.vc1_rowbase, vi_cfg.cfg.h264_startcode_detect,
+	      vi_cfg.cfg.h264_nal_len_size, vi_cfg.cfg.postproc_flag,
+	      vi_cfg.cfg.fruc_enable);
+
+	vd->streamDetails.height = vi_cfg.cfg.height;
+	vd->streamDetails.width = vi_cfg.cfg.width;
+	vd->streamDetails.fourcc = vi_cfg.cfg.fourcc;
+	if (FLAG_THUMBNAIL_MODE == vi_cfg.cfg.postproc_flag)
+		vd->streamDetails.isThisTnail = TRUE;
+	else
+		vd->streamDetails.isThisTnail = FALSE;
+
+	mutex_lock(&vdec_rm_lock);
+	ret = vdec_rm_checkWithRm(vd, vi_cfg.cfg.color_format);
+	mutex_unlock(&vdec_rm_lock);
+	if (ret)
+		return ret;
+
+	ret = dal_call_f13(vd->vdec_handle, VDEC_DALRPC_INITIALIZE,
+			   &vi_cfg, sizeof(vi_cfg),
+			   header, vdec_cfg_sps.seq.len,
+			   &vdec_buf_req, sizeof(vdec_buf_req));
+
+	kfree(header);
+
+	if (ret)
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+	else
+		ret = copy_to_user(((struct vdec_init *)argp)->buf_req,
+				   &vdec_buf_req, sizeof(vdec_buf_req));
+
+	vd->close_decode = 0;
+	return ret;
+}
+
+static void vdec_rm_freeupResources(struct vdec_data *vdecInstance)
+{
+	struct videoStreamDetails *streamDetails = &vdecInstance->streamDetails;
+
+
+
+	if ((streamDetails->isThisTnail) &&
+		 (streamDetails->isTnailGranted)) {
+
+			totalTnailQ6load--;
+			pr_info("%s: Thumbnail released %d\n", __func__,
+				totalTnailQ6load);
+
+	} else if (streamDetails->Q6usage > 0) {
+
+		totalPlaybackQ6load -= streamDetails->Q6usage;
+		if (totalPlaybackQ6load < 0)
+			pr_err("Warning:Q6load cannot be negative\n");
+
+		pr_info("%s:Releasing [%d%%] of Q6load from a total of [%d%%]\n"
+			, __func__, streamDetails->Q6usage,
+			(streamDetails->Q6usage+totalPlaybackQ6load));
+	}
+
+}
+
+static int vdec_setbuffers(struct vdec_data *vd, void *argp)
+{
+	struct vdec_buffer vmem;
+	struct vdec_mem_list *l;
+	unsigned long vstart;
+	unsigned long flags;
+	struct {
+		uint32_t size;
+		struct vdec_buf_info buf;
+	} rpc;
+	uint32_t res;
+
+	int ret = 0;
+
+	vd->mem_initialized = 0;
+
+	ret = copy_from_user(&vmem, argp, sizeof(vmem));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+
+	l = kzalloc(sizeof(struct vdec_mem_list), GFP_KERNEL);
+	if (!l) {
+		pr_err("%s: kzalloc failed!\n", __func__);
+		return -ENOMEM;
+	}
+
+	l->mem.id = vmem.pmem_id;
+	l->mem.buf_type = vmem.buf.buf_type;
+
+	ret = get_pmem_file(l->mem.id, &l->mem.phys_addr, &vstart,
+			    &l->mem.len, &l->mem.file);
+	if (ret) {
+		pr_err("%s: get_pmem_fd failed\n", __func__);
+		goto err_get_pmem_file;
+	}
+
+	TRACE("pmem_id=%d (phys=0x%08lx len=0x%lx) buftype=%d num_buf=%d "
+	      "islast=%d src_id=%d offset=0x%08x size=0x%x\n",
+	      vmem.pmem_id, l->mem.phys_addr, l->mem.len,
+	      vmem.buf.buf_type, vmem.buf.num_buf, vmem.buf.islast,
+	      vmem.buf.region.src_id, vmem.buf.region.offset,
+	      vmem.buf.region.size);
+
+	/* input buffers */
+	if ((vmem.buf.region.offset + vmem.buf.region.size) > l->mem.len) {
+		pr_err("%s: invalid input buffer offset!\n", __func__);
+		ret = -EINVAL;
+		goto err_bad_offset;
+
+	}
+	vmem.buf.region.offset += l->mem.phys_addr;
+
+	rpc.size = sizeof(vmem.buf);
+	memcpy(&rpc.buf, &vmem.buf, sizeof(struct vdec_buf_info));
+
+
+	ret = dal_call(vd->vdec_handle, VDEC_DALRPC_SETBUFFERS, 5,
+		       &rpc, sizeof(rpc), &res, sizeof(res));
+
+	if (ret < 4) {
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+		ret = -EIO;
+		goto err_dal_call;
+	}
+
+	spin_lock_irqsave(&vd->vdec_mem_list_lock, flags);
+	list_add(&l->list, &vd->vdec_mem_list_head);
+	spin_unlock_irqrestore(&vd->vdec_mem_list_lock, flags);
+
+	vd->mem_initialized = 1;
+	return ret;
+
+err_dal_call:
+err_bad_offset:
+	put_pmem_file(l->mem.file);
+err_get_pmem_file:
+	kfree(l);
+	return ret;
+}
+
+static int vdec_queue(struct vdec_data *vd, void *argp)
+{
+	struct {
+		uint32_t size;
+		struct vdec_input_buf_info buf_info;
+		uint32_t osize;
+	} rpc;
+	struct vdec_mem_list *l;
+	struct {
+		uint32_t result;
+		uint32_t size;
+		struct vdec_queue_status status;
+	} rpc_res;
+
+	u32 pmem_id;
+	int ret = 0;
+
+	if (!vd->mem_initialized) {
+		pr_err("%s: memory is not being initialized!\n", __func__);
+		return -EPERM;
+	}
+
+	ret = copy_from_user(&rpc.buf_info,
+			     &((struct vdec_input_buf *)argp)->buffer,
+			     sizeof(rpc.buf_info));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+
+	ret = copy_from_user(&pmem_id,
+			     &((struct vdec_input_buf *)argp)->pmem_id,
+			     sizeof(u32));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+
+	l = vdec_get_mem_from_list(vd, pmem_id, VDEC_BUFFER_TYPE_INPUT);
+
+	if (NULL == l) {
+		pr_err("%s: not able to find the buffer from list\n", __func__);
+		return -EPERM;
+	}
+
+	if ((rpc.buf_info.size + rpc.buf_info.offset) >= l->mem.len) {
+		pr_err("%s: invalid queue buffer offset!\n", __func__);
+		return -EINVAL;
+	}
+
+	rpc.buf_info.offset += l->mem.phys_addr;
+	rpc.size = sizeof(struct vdec_input_buf_info);
+	rpc.osize = sizeof(struct vdec_queue_status);
+
+	/* complete the writes to the buffer */
+	wmb();
+	ret = dal_call(vd->vdec_handle, VDEC_DALRPC_QUEUE, 8,
+		       &rpc, sizeof(rpc), &rpc_res, sizeof(rpc_res));
+	if (ret < 4) {
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+		ret = -EIO;
+	}
+	return ret;
+}
+
+static int vdec_reuse_framebuffer(struct vdec_data *vd, void *argp)
+{
+	u32 buf_id;
+	int ret = 0;
+
+	ret = copy_from_user(&buf_id, argp, sizeof(buf_id));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+
+	ret = dal_call_f0(vd->vdec_handle, VDEC_DALRPC_REUSEFRAMEBUFFER,
+			  buf_id);
+	if (ret)
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+
+	return ret;
+}
+
+static int vdec_flush(struct vdec_data *vd, void *argp)
+{
+	u32 flush_type;
+	int ret = 0;
+
+	if (!vd->mem_initialized) {
+		pr_err("%s: memory is not being initialized!\n", __func__);
+		return -EPERM;
+	}
+
+	ret = copy_from_user(&flush_type, argp, sizeof(flush_type));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+
+	TRACE("flush_type=%d\n", flush_type);
+	ret = dal_call_f0(vd->vdec_handle, VDEC_DALRPC_FLUSH, flush_type);
+	if (ret) {
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int vdec_close(struct vdec_data *vd, void *argp)
+{
+	struct vdec_mem_list *l;
+	int ret = 0;
+
+	pr_info("q6vdec_close()\n");
+	vd->close_decode = 1;
+	wake_up(&vd->vdec_msg_evt);
+
+	ret = dal_call_f0(vd->vdec_handle, DAL_OP_CLOSE, 0);
+	if (ret)
+		pr_err("%s: failed to close daldevice (%d)\n", __func__, ret);
+
+	if (vd->mem_initialized) {
+		list_for_each_entry(l, &vd->vdec_mem_list_head, list)
+			put_pmem_file(l->mem.file);
+	}
+
+	return ret;
+}
+static int vdec_getdecattributes(struct vdec_data *vd, void *argp)
+{
+	struct {
+		uint32_t status;
+		uint32_t size;
+		struct vdec_dec_attributes dec_attr;
+	} rpc;
+	uint32_t inp;
+	int ret = 0;
+	inp = sizeof(struct vdec_dec_attributes);
+
+	ret = dal_call(vd->vdec_handle, VDEC_DALRPC_GETDECATTRIBUTES, 9,
+		       &inp, sizeof(inp), &rpc, sizeof(rpc));
+	if (ret < 4 || rpc.size != sizeof(struct vdec_dec_attributes)) {
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+		ret = -EIO;
+	} else
+		ret =
+		    copy_to_user(((struct vdec_dec_attributes *)argp),
+				 &rpc.dec_attr, sizeof(rpc.dec_attr));
+	return ret;
+}
+
+static int vdec_freebuffers(struct vdec_data *vd, void *argp)
+{
+	struct vdec_buffer vmem;
+	struct vdec_mem_list *l;
+	struct {
+		uint32_t size;
+		struct vdec_buf_info buf;
+	} rpc;
+	uint32_t res;
+
+	int ret = 0;
+
+	if (!vd->mem_initialized) {
+		pr_err("%s: memory is not being initialized!\n", __func__);
+		return -EPERM;
+	}
+
+	ret = copy_from_user(&vmem, argp, sizeof(vmem));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+
+	l = vdec_get_mem_from_list(vd, vmem.pmem_id, vmem.buf.buf_type);
+
+	if (NULL == l) {
+		pr_err("%s: not able to find the buffer from list\n", __func__);
+		return -EPERM;
+	}
+
+	/* input buffers */
+	if ((vmem.buf.region.offset + vmem.buf.region.size) > l->mem.len) {
+		pr_err("%s: invalid input buffer offset!\n", __func__);
+		return -EINVAL;
+
+	}
+	vmem.buf.region.offset += l->mem.phys_addr;
+
+	rpc.size = sizeof(vmem.buf);
+	memcpy(&rpc.buf, &vmem.buf, sizeof(struct vdec_buf_info));
+
+	ret = dal_call(vd->vdec_handle, VDEC_DALRPC_FREEBUFFERS, 5,
+		       &rpc, sizeof(rpc), &res, sizeof(res));
+	if (ret < 4) {
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+	}
+
+	return ret;
+}
+
+static int vdec_getversion(struct vdec_data *vd, void *argp)
+{
+	struct vdec_version ver_info;
+	int ret = 0;
+
+	ver_info.major = VDEC_GET_MAJOR_VERSION(VDEC_INTERFACE_VERSION);
+	ver_info.minor = VDEC_GET_MINOR_VERSION(VDEC_INTERFACE_VERSION);
+
+	ret = copy_to_user(((struct vdec_version *)argp),
+				&ver_info, sizeof(ver_info));
+
+	return ret;
+
+}
+
+static long vdec_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct vdec_data *vd = file->private_data;
+	void __user *argp = (void __user *)arg;
+	int ret = 0;
+
+	if (!vd->running)
+		return -EPERM;
+
+	switch (cmd) {
+	case VDEC_IOCTL_INITIALIZE:
+		ret = vdec_initialize(vd, argp);
+		break;
+
+	case VDEC_IOCTL_SETBUFFERS:
+		ret = vdec_setbuffers(vd, argp);
+		break;
+
+	case VDEC_IOCTL_QUEUE:
+		TRACE("VDEC_IOCTL_QUEUE (pid=%d tid=%d)\n",
+		      current->group_leader->pid, current->pid);
+		ret = vdec_queue(vd, argp);
+		break;
+
+	case VDEC_IOCTL_REUSEFRAMEBUFFER:
+		TRACE("VDEC_IOCTL_REUSEFRAMEBUFFER (pid=%d tid=%d)\n",
+		      current->group_leader->pid, current->pid);
+		ret = vdec_reuse_framebuffer(vd, argp);
+		break;
+
+	case VDEC_IOCTL_FLUSH:
+		TRACE("IOCTL flush\n");
+		ret = vdec_flush(vd, argp);
+		break;
+
+	case VDEC_IOCTL_EOS:
+		TRACE("VDEC_IOCTL_EOS (pid=%d tid=%d)\n",
+		      current->group_leader->pid, current->pid);
+		ret = dal_call_f0(vd->vdec_handle, VDEC_DALRPC_SIGEOFSTREAM, 0);
+		if (ret)
+			pr_err("%s: remote function failed (%d)\n",
+			       __func__, ret);
+		break;
+
+	case VDEC_IOCTL_GETMSG:
+		TRACE("VDEC_IOCTL_GETMSG (pid=%d tid=%d)\n",
+		      current->group_leader->pid, current->pid);
+		wait_event_interruptible(vd->vdec_msg_evt,
+					 vdec_get_msg(vd, argp));
+
+		if (vd->close_decode)
+			ret = -EINTR;
+		else
+			/* order the reads from the buffer */
+			rmb();
+		break;
+
+	case VDEC_IOCTL_CLOSE:
+		ret = vdec_close(vd, argp);
+		break;
+
+	case VDEC_IOCTL_GETDECATTRIBUTES:
+		TRACE("VDEC_IOCTL_GETDECATTRIBUTES (pid=%d tid=%d)\n",
+		      current->group_leader->pid, current->pid);
+		ret = vdec_getdecattributes(vd, argp);
+
+		if (ret)
+			pr_err("%s: remote function failed (%d)\n",
+			       __func__, ret);
+		break;
+
+	case VDEC_IOCTL_FREEBUFFERS:
+		TRACE("VDEC_IOCTL_FREEBUFFERS (pid=%d tid=%d)\n",
+		      current->group_leader->pid, current->pid);
+		ret = vdec_freebuffers(vd, argp);
+
+		if (ret)
+			pr_err("%s: remote function failed (%d)\n",
+			       __func__, ret);
+		break;
+	case VDEC_IOCTL_GETVERSION:
+		TRACE("VDEC_IOCTL_GETVERSION (pid=%d tid=%d)\n",
+			current->group_leader->pid, current->pid);
+		ret = vdec_getversion(vd, argp);
+
+		if (ret)
+			pr_err("%s: remote function failed (%d)\n",
+				__func__, ret);
+		break;
+	case VDEC_IOCTL_GETPROPERTY:
+		TRACE("VDEC_IOCTL_GETPROPERTY (pid=%d tid=%d)\n",
+		      current->group_leader->pid, current->pid);
+		ret = vdec_getproperty(vd, argp);
+		break;
+	case VDEC_IOCTL_SETPROPERTY:
+		TRACE("VDEC_IOCTL_SETPROPERTY (pid=%d tid=%d)\n",
+		      current->group_leader->pid, current->pid);
+		ret = vdec_setproperty(vd, argp);
+		break;
+	case VDEC_IOCTL_PERFORMANCE_CHANGE_REQ:
+		ret = vdec_performance_change_request(vd, argp);
+		break;
+	default:
+		pr_err("%s: invalid ioctl!\n", __func__);
+		ret = -EINVAL;
+		break;
+	}
+
+	TRACE("ioctl done (pid=%d tid=%d)\n",
+	      current->group_leader->pid, current->pid);
+
+	return ret;
+}
+
+static void vdec_dcdone_handler(struct vdec_data *vd, void *frame,
+				uint32_t frame_size)
+{
+	struct vdec_msg msg;
+	struct vdec_mem_list *l;
+	unsigned long flags;
+	int found = 0;
+
+	if (frame_size < sizeof(struct vdec_frame_info)) {
+		pr_warning("%s: msg size mismatch %d != %d\n", __func__,
+			   frame_size, sizeof(struct vdec_frame_info));
+		return;
+	}
+
+	memcpy(&msg.vfr_info, (struct vdec_frame_info *)frame,
+	       sizeof(struct vdec_frame_info));
+
+	if (msg.vfr_info.status == VDEC_FRAME_DECODE_OK) {
+		spin_lock_irqsave(&vd->vdec_mem_list_lock, flags);
+		list_for_each_entry(l, &vd->vdec_mem_list_head, list) {
+			if ((l->mem.buf_type == VDEC_BUFFER_TYPE_OUTPUT) &&
+			    (msg.vfr_info.offset >= l->mem.phys_addr) &&
+			    (msg.vfr_info.offset <
+			     (l->mem.phys_addr + l->mem.len))) {
+				found = 1;
+				msg.vfr_info.offset -= l->mem.phys_addr;
+				msg.vfr_info.data2 = l->mem.id;
+				break;
+			}
+		}
+		spin_unlock_irqrestore(&vd->vdec_mem_list_lock, flags);
+	}
+
+	if (found || (msg.vfr_info.status != VDEC_FRAME_DECODE_OK)) {
+		msg.id = VDEC_MSG_FRAMEDONE;
+		vdec_put_msg(vd, &msg);
+	} else {
+		pr_err("%s: invalid phys addr = 0x%x\n",
+		       __func__, msg.vfr_info.offset);
+	}
+
+}
+
+static void vdec_reuseibuf_handler(struct vdec_data *vd, void *bufstat,
+				   uint32_t bufstat_size)
+{
+	struct vdec_buffer_status *vdec_bufstat;
+	struct vdec_msg msg;
+
+	/* TODO: how do we signal the client? If they are waiting on a
+	 * message in an ioctl, they may block forever */
+	if (bufstat_size != sizeof(struct vdec_buffer_status)) {
+		pr_warning("%s: msg size mismatch %d != %d\n", __func__,
+			   bufstat_size, sizeof(struct vdec_buffer_status));
+		return;
+	}
+	vdec_bufstat = (struct vdec_buffer_status *)bufstat;
+	msg.id = VDEC_MSG_REUSEINPUTBUFFER;
+	msg.buf_id = vdec_bufstat->data;
+	vdec_put_msg(vd, &msg);
+}
+
+static void callback(void *data, int len, void *cookie)
+{
+	struct vdec_data *vd = (struct vdec_data *)cookie;
+	uint32_t *tmp = (uint32_t *) data;
+
+	if (!vd->mem_initialized) {
+		pr_err("%s:memory not initialize but callback called!\n",
+		       __func__);
+		return;
+	}
+
+	TRACE("vdec_async: tmp=0x%08x 0x%08x 0x%08x\n", tmp[0], tmp[1], tmp[2]);
+	switch (tmp[0]) {
+	case VDEC_ASYNCMSG_DECODE_DONE:
+		vdec_dcdone_handler(vd, &tmp[3], tmp[2]);
+		break;
+	case VDEC_ASYNCMSG_REUSE_FRAME:
+		vdec_reuseibuf_handler(vd, &tmp[3], tmp[2]);
+		break;
+	default:
+		pr_err("%s: Unknown async message from DSP id=0x%08x sz=%u\n",
+		       __func__, tmp[0], tmp[2]);
+	}
+}
+
+static int vdec_open(struct inode *inode, struct file *file)
+{
+	int ret;
+	int i;
+	struct vdec_msg_list *l;
+	struct vdec_data *vd;
+	struct dal_info version_info;
+	char *portname = NULL;
+
+	pr_info("q6vdec_open()\n");
+	mutex_lock(&vdec_ref_lock);
+	if (ref_cnt >= MAX_SUPPORTED_INSTANCES) {
+		pr_err("%s: Max allowed instances exceeded \n", __func__);
+		mutex_unlock(&vdec_ref_lock);
+		return -EBUSY;
+	}
+	ref_cnt++;
+	mutex_unlock(&vdec_ref_lock);
+
+	vd = kmalloc(sizeof(struct vdec_data), GFP_KERNEL);
+	if (!vd) {
+		pr_err("%s: kmalloc failed\n", __func__);
+		ret = -ENOMEM;
+		goto vdec_open_err_handle_vd;
+	}
+	file->private_data = vd;
+
+	vd->mem_initialized = 0;
+	INIT_LIST_HEAD(&vd->vdec_msg_list_head);
+	INIT_LIST_HEAD(&vd->vdec_msg_list_free);
+	INIT_LIST_HEAD(&vd->vdec_mem_list_head);
+	init_waitqueue_head(&vd->vdec_msg_evt);
+
+	spin_lock_init(&vd->vdec_list_lock);
+	spin_lock_init(&vd->vdec_mem_list_lock);
+	for (i = 0; i < VDEC_MSG_MAX; i++) {
+		l = kzalloc(sizeof(struct vdec_msg_list), GFP_KERNEL);
+		if (!l) {
+			pr_err("%s: kzalloc failed!\n", __func__);
+			ret = -ENOMEM;
+			goto vdec_open_err_handle_list;
+		}
+		list_add(&l->list, &vd->vdec_msg_list_free);
+	}
+
+	memset(&vd->streamDetails, 0, sizeof(struct videoStreamDetails));
+
+	mutex_lock(&vdec_ref_lock);
+	vdec_get_next_portanddevid(&vd->Q6deviceId, &portname);
+	mutex_unlock(&vdec_ref_lock);
+
+	if ((0 == vd->Q6deviceId) || (NULL == portname)) {
+		pr_err("%s: FATAL error portname %s or deviceId %d not picked properly\n",
+			__func__, portname, vd->Q6deviceId);
+		ret = -EIO;
+		goto vdec_open_err_handle_list;
+	} else {
+		pr_err("attaching on deviceid %x portname %s\n",
+			vd->Q6deviceId, portname);
+		vd->vdec_handle = dal_attach(vd->Q6deviceId,
+					     portname, 1, callback, vd);
+	}
+
+	if (!vd->vdec_handle) {
+		pr_err("%s: failed to attach\n", __func__);
+		ret = -EIO;
+		goto vdec_open_err_handle_list;
+	}
+	ret = dal_call_f9(vd->vdec_handle, DAL_OP_INFO,
+				&version_info, sizeof(struct dal_info));
+
+	if (ret) {
+		pr_err("%s: failed to get version \n", __func__);
+		goto vdec_open_err_handle_version;
+	}
+
+	TRACE("q6vdec_open() interface version 0x%x\n", version_info.version);
+	if (vdec_check_version(VDEC_INTERFACE_VERSION,
+			version_info.version)) {
+		pr_err("%s: driver version mismatch !\n", __func__);
+		goto vdec_open_err_handle_version;
+	}
+
+	vd->running = 1;
+	prevent_sleep();
+
+	return 0;
+vdec_open_err_handle_version:
+	dal_detach(vd->vdec_handle);
+vdec_open_err_handle_list:
+	{
+		struct vdec_msg_list *l, *n;
+		list_for_each_entry_safe(l, n, &vd->vdec_msg_list_free, list) {
+			list_del(&l->list);
+			kfree(l);
+		}
+	}
+vdec_open_err_handle_vd:
+	mutex_lock(&vdec_ref_lock);
+	vdec_freeup_portanddevid(vd->Q6deviceId);
+	ref_cnt--;
+	mutex_unlock(&vdec_ref_lock);
+	kfree(vd);
+	return ret;
+}
+
+static int vdec_release(struct inode *inode, struct file *file)
+{
+	int ret;
+	struct vdec_msg_list *l, *n;
+	struct vdec_mem_list *m, *k;
+	struct vdec_data *vd = file->private_data;
+
+	vd->running = 0;
+	wake_up_all(&vd->vdec_msg_evt);
+
+	if (!vd->close_decode)
+		vdec_close(vd, NULL);
+
+	ret = dal_detach(vd->vdec_handle);
+	if (ret)
+		printk(KERN_INFO "%s: failed to detach (%d)\n", __func__, ret);
+
+	list_for_each_entry_safe(l, n, &vd->vdec_msg_list_free, list) {
+		list_del(&l->list);
+		kfree(l);
+	}
+
+	list_for_each_entry_safe(l, n, &vd->vdec_msg_list_head, list) {
+		list_del(&l->list);
+		kfree(l);
+	}
+
+	list_for_each_entry_safe(m, k, &vd->vdec_mem_list_head, list) {
+		list_del(&m->list);
+		kfree(m);
+	}
+	mutex_lock(&vdec_ref_lock);
+	BUG_ON(ref_cnt <= 0);
+	ref_cnt--;
+	vdec_freeup_portanddevid(vd->Q6deviceId);
+	mutex_unlock(&vdec_ref_lock);
+
+	mutex_lock(&vdec_rm_lock);
+	vdec_rm_freeupResources(vd);
+	mutex_unlock(&vdec_rm_lock);
+
+
+	kfree(vd);
+	allow_sleep();
+	return 0;
+}
+
+static const struct file_operations vdec_fops = {
+	.owner = THIS_MODULE,
+	.open = vdec_open,
+	.release = vdec_release,
+	.unlocked_ioctl = vdec_ioctl,
+};
+
+static int __init vdec_init(void)
+{
+	struct device *class_dev;
+	int rc = 0;
+
+	wake_lock_init(&idlelock, WAKE_LOCK_IDLE, "vdec_idle");
+	wake_lock_init(&wakelock, WAKE_LOCK_SUSPEND, "vdec_suspend");
+
+	rc = alloc_chrdev_region(&vdec_device_no, 0, 1, "vdec");
+	if (rc < 0) {
+		pr_err("%s: alloc_chrdev_region failed %d\n", __func__, rc);
+		return rc;
+	}
+
+	driver_class = class_create(THIS_MODULE, "vdec");
+	if (IS_ERR(driver_class)) {
+		rc = -ENOMEM;
+		pr_err("%s: class_create failed %d\n", __func__, rc);
+		goto vdec_init_err_unregister_chrdev_region;
+	}
+	class_dev = device_create(driver_class, NULL,
+				  vdec_device_no, NULL, "vdec");
+	if (!class_dev) {
+		pr_err("%s: class_device_create failed %d\n", __func__, rc);
+		rc = -ENOMEM;
+		goto vdec_init_err_class_destroy;
+	}
+
+	cdev_init(&vdec_cdev, &vdec_fops);
+	vdec_cdev.owner = THIS_MODULE;
+	rc = cdev_add(&vdec_cdev, MKDEV(MAJOR(vdec_device_no), 0), 1);
+
+	if (rc < 0) {
+		pr_err("%s: cdev_add failed %d\n", __func__, rc);
+		goto vdec_init_err_class_device_destroy;
+	}
+
+	memset(&deviceIdRegistry, 0, sizeof(deviceIdRegistry));
+	memset(&loadOnPorts, 0, sizeof(loadOnPorts));
+	numOfPorts = 0;
+
+	return 0;
+
+vdec_init_err_class_device_destroy:
+	device_destroy(driver_class, vdec_device_no);
+vdec_init_err_class_destroy:
+	class_destroy(driver_class);
+vdec_init_err_unregister_chrdev_region:
+	unregister_chrdev_region(vdec_device_no, 1);
+	return rc;
+}
+
+static void __exit vdec_exit(void)
+{
+	device_destroy(driver_class, vdec_device_no);
+	class_destroy(driver_class);
+	unregister_chrdev_region(vdec_device_no, 1);
+}
+
+MODULE_DESCRIPTION("video decoder driver for QSD platform");
+MODULE_VERSION("2.00");
+
+module_init(vdec_init);
+module_exit(vdec_exit);
diff --git a/arch/arm/mach-msm/qdsp6/msm_q6venc.c b/arch/arm/mach-msm/qdsp6/msm_q6venc.c
new file mode 100644
index 0000000..bd5d3f6
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/msm_q6venc.c
@@ -0,0 +1,1195 @@
+/* Copyright (c) 2008-2009, 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/slab.h>
+#include <linux/cdev.h>
+#include <linux/file.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/wakelock.h>
+#include <linux/android_pmem.h>
+#include <linux/msm_q6venc.h>
+#include "dal.h"
+
+#define DALDEVICEID_VENC_DEVICE         0x0200002D
+#define DALDEVICEID_VENC_PORTNAME       "DAL_AQ_VID"
+
+#define VENC_NAME		        "q6venc"
+#define VENC_MSG_MAX                    128
+
+#define VENC_INTERFACE_VERSION		0x00020000
+#define MAJOR_MASK			0xFFFF0000
+#define MINOR_MASK			0x0000FFFF
+#define VENC_GET_MAJOR_VERSION(version) ((version & MAJOR_MASK)>>16)
+#define VENC_GET_MINOR_VERSION(version) (version & MINOR_MASK)
+
+enum {
+	VENC_BUFFER_TYPE_INPUT,
+	VENC_BUFFER_TYPE_OUTPUT,
+	VENC_BUFFER_TYPE_QDSP6,
+	VENC_BUFFER_TYPE_HDR
+};
+enum {
+	VENC_DALRPC_GET_SYNTAX_HEADER = DAL_OP_FIRST_DEVICE_API,
+	VENC_DALRPC_UPDATE_INTRA_REFRESH,
+	VENC_DALRPC_UPDATE_FRAME_RATE,
+	VENC_DALRPC_UPDATE_BITRATE,
+	VENC_DALRPC_UPDATE_QP_RANGE,
+	VENC_DALRPC_UPDATE_INTRA_PERIOD,
+	VENC_DALRPC_REQUEST_IFRAME,
+	VENC_DALRPC_START,
+	VENC_DALRPC_STOP,
+	VENC_DALRPC_SUSPEND,
+	VENC_DALRPC_RESUME,
+	VENC_DALRPC_FLUSH,
+	VENC_DALRPC_QUEUE_INPUT,
+	VENC_DALRPC_QUEUE_OUTPUT
+};
+struct venc_input_payload {
+	u32 data;
+};
+struct venc_output_payload {
+	u32 size;
+	long long time_stamp;
+	u32 flags;
+	u32 data;
+	u32 client_data_from_input;
+};
+union venc_payload {
+	struct venc_input_payload input_payload;
+	struct venc_output_payload output_payload;
+};
+struct venc_msg_type {
+	u32 event;
+	u32 status;
+	union venc_payload payload;
+};
+struct venc_input_buf {
+	struct venc_buf_type yuv_buf;
+	u32 data_size;
+	long long time_stamp;
+	u32 flags;
+	u32 dvs_offsetx;
+	u32 dvs_offsety;
+	u32 client_data;
+	u32 op_client_data;
+};
+struct venc_output_buf {
+	struct venc_buf_type bit_stream_buf;
+	u32 client_data;
+};
+
+struct venc_msg_list {
+	struct list_head list;
+	struct venc_msg msg_data;
+};
+struct venc_buf {
+	int fd;
+	u32 src;
+	u32 offset;
+	u32 size;
+	u32 btype;
+	unsigned long paddr;
+	struct file *file;
+};
+struct venc_pmem_list {
+	struct list_head list;
+	struct venc_buf buf;
+};
+struct venc_dev {
+	bool is_active;
+	bool pmem_freed;
+	enum venc_state_type state;
+	struct list_head venc_msg_list_head;
+	struct list_head venc_msg_list_free;
+	spinlock_t venc_msg_list_lock;
+	struct list_head venc_pmem_list_head;
+	spinlock_t venc_pmem_list_lock;
+	struct dal_client *q6_handle;
+	wait_queue_head_t venc_msg_evt;
+	struct device *class_devp;
+};
+
+#define DEBUG_VENC 0
+#if DEBUG_VENC
+#define TRACE(fmt, x...)     \
+	do { pr_debug("%s:%d " fmt, __func__, __LINE__, ##x); } while (0)
+#else
+#define TRACE(fmt, x...)         do { } while (0)
+#endif
+
+static struct cdev cdev;
+static dev_t venc_dev_num;
+static struct class *venc_class;
+static struct venc_dev *venc_device_p;
+static int venc_ref;
+
+static DEFINE_MUTEX(idlecount_lock);
+static int idlecount;
+static struct wake_lock wakelock;
+static struct wake_lock idlelock;
+
+static void prevent_sleep(void)
+{
+	mutex_lock(&idlecount_lock);
+	if (++idlecount == 1) {
+		wake_lock(&idlelock);
+		wake_lock(&wakelock);
+	}
+	mutex_unlock(&idlecount_lock);
+}
+
+static void allow_sleep(void)
+{
+	mutex_lock(&idlecount_lock);
+	if (--idlecount == 0) {
+		wake_unlock(&idlelock);
+		wake_unlock(&wakelock);
+	}
+	mutex_unlock(&idlecount_lock);
+}
+
+static inline int venc_check_version(u32 client, u32 server)
+{
+	int ret = -EINVAL;
+
+	if ((VENC_GET_MAJOR_VERSION(client) == VENC_GET_MAJOR_VERSION(server))
+	     && (VENC_GET_MINOR_VERSION(client) <=
+		 VENC_GET_MINOR_VERSION(server)))
+		ret = 0;
+
+	return ret;
+}
+
+static int venc_get_msg(struct venc_dev *dvenc, void *msg)
+{
+	struct venc_msg_list *l;
+	unsigned long flags;
+	int ret = 0;
+	struct venc_msg qdsp_msg;
+
+	if (!dvenc->is_active)
+		return -EPERM;
+	spin_lock_irqsave(&dvenc->venc_msg_list_lock, flags);
+	list_for_each_entry_reverse(l, &dvenc->venc_msg_list_head, list) {
+		memcpy(&qdsp_msg, &l->msg_data, sizeof(struct venc_msg));
+		list_del(&l->list);
+		list_add(&l->list, &dvenc->venc_msg_list_free);
+		ret = 1;
+		break;
+	}
+	spin_unlock_irqrestore(&dvenc->venc_msg_list_lock, flags);
+	if (copy_to_user(msg, &qdsp_msg, sizeof(struct venc_msg)))
+		pr_err("%s failed to copy_to_user\n", __func__);
+	return ret;
+}
+
+static void venc_put_msg(struct venc_dev *dvenc, struct venc_msg *msg)
+{
+	struct venc_msg_list *l;
+	unsigned long flags;
+	int found = 0;
+
+	spin_lock_irqsave(&dvenc->venc_msg_list_lock, flags);
+	list_for_each_entry(l, &dvenc->venc_msg_list_free, list) {
+		memcpy(&l->msg_data, msg, sizeof(struct venc_msg));
+		list_del(&l->list);
+		list_add(&l->list, &dvenc->venc_msg_list_head);
+		found = 1;
+		break;
+	}
+	spin_unlock_irqrestore(&dvenc->venc_msg_list_lock, flags);
+	if (found)
+		wake_up(&dvenc->venc_msg_evt);
+	else
+		pr_err("%s: failed to find a free node\n", __func__);
+
+}
+
+static struct venc_pmem_list *venc_add_pmem_to_list(struct venc_dev *dvenc,
+						      struct venc_pmem *mptr,
+						      u32 btype)
+{
+	int ret = 0;
+	unsigned long flags;
+	unsigned long len;
+	unsigned long vaddr;
+	struct venc_pmem_list *plist = NULL;
+
+	plist = kzalloc(sizeof(struct venc_pmem_list), GFP_KERNEL);
+	if (!plist) {
+		pr_err("%s: kzalloc failed\n", __func__);
+		return NULL;
+	}
+
+	ret = get_pmem_file(mptr->fd, &(plist->buf.paddr),
+		&vaddr, &len, &(plist->buf.file));
+	if (ret) {
+		pr_err("%s: get_pmem_file failed for fd=%d offset=%d\n",
+			__func__, mptr->fd, mptr->offset);
+		goto err_venc_add_pmem;
+	} else if (mptr->offset >= len) {
+		pr_err("%s: invalid offset (%d > %ld) for fd=%d\n",
+		       __func__, mptr->offset, len, mptr->fd);
+		ret = -EINVAL;
+		goto err_venc_get_pmem;
+	}
+
+	plist->buf.fd = mptr->fd;
+	plist->buf.paddr += mptr->offset;
+	plist->buf.size = mptr->size;
+	plist->buf.btype = btype;
+	plist->buf.offset = mptr->offset;
+	plist->buf.src = mptr->src;
+
+	spin_lock_irqsave(&dvenc->venc_pmem_list_lock, flags);
+	list_add(&plist->list, &dvenc->venc_pmem_list_head);
+	spin_unlock_irqrestore(&dvenc->venc_pmem_list_lock, flags);
+	return plist;
+
+err_venc_get_pmem:
+	put_pmem_file(plist->buf.file);
+err_venc_add_pmem:
+	kfree(plist);
+	return NULL;
+}
+
+static struct venc_pmem_list *venc_get_pmem_from_list(
+		struct venc_dev *dvenc, u32 pmem_fd,
+		u32 offset, u32 btype)
+{
+	struct venc_pmem_list *plist;
+	unsigned long flags;
+	struct file *file;
+	int found = 0;
+
+	file = fget(pmem_fd);
+	if (!file) {
+		pr_err("%s: invalid encoder buffer fd(%d)\n", __func__,
+			pmem_fd);
+		return NULL;
+	}
+	spin_lock_irqsave(&dvenc->venc_pmem_list_lock, flags);
+	list_for_each_entry(plist, &dvenc->venc_pmem_list_head, list) {
+		if (plist->buf.btype == btype && plist->buf.file == file &&
+			plist->buf.offset == offset) {
+			found = 1;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&dvenc->venc_pmem_list_lock, flags);
+	fput(file);
+	if (found)
+		return plist;
+
+	else
+		return NULL;
+}
+
+static int venc_set_buffer(struct venc_dev *dvenc, void *argp,
+			     u32 btype)
+{
+	struct venc_pmem pmem;
+	struct venc_pmem_list *plist;
+	int ret = 0;
+
+	ret = copy_from_user(&pmem, argp, sizeof(pmem));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+	plist = venc_add_pmem_to_list(dvenc, &pmem, btype);
+	if (plist == NULL) {
+		pr_err("%s: buffer add_to_pmem_list failed\n",
+			__func__);
+		return -EPERM;
+	}
+	return ret;
+}
+
+static int venc_assign_q6_buffers(struct venc_dev *dvenc,
+				    struct venc_buffers *pbufs,
+				    struct venc_nonio_buf_config *pcfg)
+{
+	int ret = 0;
+	struct venc_pmem_list *plist;
+
+	plist = venc_add_pmem_to_list(dvenc, &(pbufs->recon_buf[0]),
+				  VENC_BUFFER_TYPE_QDSP6);
+	if (plist == NULL) {
+		pr_err("%s: recon_buf0 failed to add_to_pmem_list\n",
+			__func__);
+		return -EPERM;
+	}
+	pcfg->recon_buf1.region = pbufs->recon_buf[0].src;
+	pcfg->recon_buf1.phys = plist->buf.paddr;
+	pcfg->recon_buf1.size = plist->buf.size;
+	pcfg->recon_buf1.offset = 0;
+
+	plist = venc_add_pmem_to_list(dvenc, &(pbufs->recon_buf[1]),
+				  VENC_BUFFER_TYPE_QDSP6);
+	if (plist == NULL) {
+		pr_err("%s: recons_buf1 failed to add_to_pmem_list\n",
+			__func__);
+		return -EPERM;
+	}
+	pcfg->recon_buf2.region = pbufs->recon_buf[1].src;
+	pcfg->recon_buf2.phys = plist->buf.paddr;
+	pcfg->recon_buf2.size = plist->buf.size;
+	pcfg->recon_buf2.offset = 0;
+
+	plist = venc_add_pmem_to_list(dvenc, &(pbufs->wb_buf),
+				  VENC_BUFFER_TYPE_QDSP6);
+	if (plist == NULL) {
+		pr_err("%s: wb_buf failed to add_to_pmem_list\n",
+			__func__);
+		return -EPERM;
+	}
+	pcfg->wb_buf.region = pbufs->wb_buf.src;
+	pcfg->wb_buf.phys = plist->buf.paddr;
+	pcfg->wb_buf.size = plist->buf.size;
+	pcfg->wb_buf.offset = 0;
+
+	plist = venc_add_pmem_to_list(dvenc, &(pbufs->cmd_buf),
+				  VENC_BUFFER_TYPE_QDSP6);
+	if (plist == NULL) {
+		pr_err("%s: cmd_buf failed to add_to_pmem_list\n",
+			__func__);
+		return -EPERM;
+	}
+	pcfg->cmd_buf.region = pbufs->cmd_buf.src;
+	pcfg->cmd_buf.phys = plist->buf.paddr;
+	pcfg->cmd_buf.size = plist->buf.size;
+	pcfg->cmd_buf.offset = 0;
+
+	plist = venc_add_pmem_to_list(dvenc, &(pbufs->vlc_buf),
+				  VENC_BUFFER_TYPE_QDSP6);
+	if (plist == NULL) {
+		pr_err("%s: vlc_buf failed to add_to_pmem_list"
+		" failed\n", __func__);
+		return -EPERM;
+	}
+	pcfg->vlc_buf.region = pbufs->vlc_buf.src;
+	pcfg->vlc_buf.phys = plist->buf.paddr;
+	pcfg->vlc_buf.size = plist->buf.size;
+	pcfg->vlc_buf.offset = 0;
+
+	return ret;
+}
+
+static int venc_start(struct venc_dev *dvenc, void *argp)
+{
+	int ret = 0;
+	struct venc_q6_config q6_config;
+	struct venc_init_config vconfig;
+
+	dvenc->state = VENC_STATE_START;
+	ret = copy_from_user(&vconfig, argp, sizeof(struct venc_init_config));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+	memcpy(&q6_config, &(vconfig.q6_config), sizeof(q6_config));
+	ret = venc_assign_q6_buffers(dvenc, &(vconfig.q6_bufs),
+		&(q6_config.buf_params));
+	if (ret != 0) {
+		pr_err("%s: assign_q6_buffers failed\n", __func__);
+		return -EPERM;
+	}
+
+	q6_config.callback_event = dvenc->q6_handle;
+	TRACE("%s: parameters: handle:%p, config:%p, callback:%p \n", __func__,
+		dvenc->q6_handle, &q6_config, q6_config.callback_event);
+	TRACE("%s: parameters:recon1:0x%x, recon2:0x%x,"
+		" wb_buf:0x%x, cmd:0x%x, vlc:0x%x\n", __func__,
+		q6_config.buf_params.recon_buf1.phys,
+		q6_config.buf_params.recon_buf2.phys,
+		q6_config.buf_params.wb_buf.phys,
+		q6_config.buf_params.cmd_buf.phys,
+		q6_config.buf_params.vlc_buf.phys);
+	TRACE("%s: size of param:%d \n", __func__, sizeof(q6_config));
+	ret = dal_call_f5(dvenc->q6_handle, VENC_DALRPC_START, &q6_config,
+		sizeof(q6_config));
+	if (ret != 0) {
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+		return ret;
+	}
+	return ret;
+}
+
+static int venc_encode_frame(struct venc_dev *dvenc, void *argp)
+{
+	int ret = 0;
+	struct venc_pmem buf;
+	struct venc_input_buf q6_input;
+	struct venc_pmem_list *plist;
+	struct venc_buffer input;
+
+	ret = copy_from_user(&input, argp, sizeof(struct venc_buffer));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+	ret = copy_from_user(&buf,
+			       ((struct venc_buffer *)argp)->ptr_buffer,
+			       sizeof(struct venc_pmem));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+
+	plist = venc_get_pmem_from_list(dvenc, buf.fd, buf.offset,
+			VENC_BUFFER_TYPE_INPUT);
+	if (NULL == plist) {
+		plist = venc_add_pmem_to_list(dvenc, &buf,
+			VENC_BUFFER_TYPE_INPUT);
+		if (plist == NULL) {
+			pr_err("%s: buffer add_to_pmem_list failed\n",
+				__func__);
+			return -EPERM;
+		}
+	}
+
+	q6_input.flags = 0;
+	if (input.flags & VENC_FLAG_EOS)
+		q6_input.flags |= 0x00000001;
+	q6_input.yuv_buf.region = plist->buf.src;
+	q6_input.yuv_buf.phys = plist->buf.paddr;
+	q6_input.yuv_buf.size = plist->buf.size;
+	q6_input.yuv_buf.offset = 0;
+	q6_input.data_size = plist->buf.size;
+	q6_input.client_data = (u32)input.client_data;
+	q6_input.time_stamp = input.time_stamp;
+	q6_input.dvs_offsetx = 0;
+	q6_input.dvs_offsety = 0;
+
+	TRACE("Pushing down input phys=0x%x fd= %d, client_data: 0x%x,"
+		" time_stamp:%lld \n", q6_input.yuv_buf.phys, plist->buf.fd,
+		input.client_data, input.time_stamp);
+	ret = dal_call_f5(dvenc->q6_handle, VENC_DALRPC_QUEUE_INPUT,
+		&q6_input, sizeof(q6_input));
+
+	if (ret != 0)
+		pr_err("%s: Q6 queue_input failed (%d)\n", __func__,
+		(int)ret);
+	return ret;
+}
+
+static int venc_fill_output(struct venc_dev *dvenc, void *argp)
+{
+	int ret = 0;
+	struct venc_pmem buf;
+	struct venc_output_buf q6_output;
+	struct venc_pmem_list *plist;
+	struct venc_buffer output;
+
+	ret = copy_from_user(&output, argp, sizeof(struct venc_buffer));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+	ret = copy_from_user(&buf,
+			       ((struct venc_buffer *)argp)->ptr_buffer,
+			       sizeof(struct venc_pmem));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+	plist =	venc_get_pmem_from_list(dvenc, buf.fd, buf.offset,
+			VENC_BUFFER_TYPE_OUTPUT);
+	if (NULL == plist) {
+		plist = venc_add_pmem_to_list(dvenc, &buf,
+				VENC_BUFFER_TYPE_OUTPUT);
+		if (NULL == plist) {
+			pr_err("%s: output buffer failed to add_to_pmem_list"
+				"\n", __func__);
+			return -EPERM;
+		}
+	}
+	q6_output.bit_stream_buf.region = plist->buf.src;
+	q6_output.bit_stream_buf.phys = (u32)plist->buf.paddr;
+	q6_output.bit_stream_buf.size = plist->buf.size;
+	q6_output.bit_stream_buf.offset = 0;
+	q6_output.client_data = (u32)output.client_data;
+	ret =
+	    dal_call_f5(dvenc->q6_handle, VENC_DALRPC_QUEUE_OUTPUT, &q6_output,
+			sizeof(q6_output));
+	if (ret != 0)
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+	return ret;
+}
+
+static int venc_stop(struct venc_dev *dvenc)
+{
+	int ret = 0;
+	struct venc_msg msg;
+
+	ret = dal_call_f0(dvenc->q6_handle, VENC_DALRPC_STOP, 1);
+	if (ret) {
+		pr_err("%s: remote runction failed (%d)\n", __func__, ret);
+		msg.msg_code = VENC_MSG_STOP;
+		msg.msg_data_size = 0;
+		msg.status_code = VENC_S_EFAIL;
+		venc_put_msg(dvenc, &msg);
+	}
+	return ret;
+}
+
+static int venc_pause(struct venc_dev *dvenc)
+{
+	int ret = 0;
+	struct venc_msg msg;
+
+	ret = dal_call_f0(dvenc->q6_handle, VENC_DALRPC_SUSPEND, 1);
+	if (ret) {
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+		msg.msg_code = VENC_MSG_PAUSE;
+		msg.status_code = VENC_S_EFAIL;
+		msg.msg_data_size = 0;
+		venc_put_msg(dvenc, &msg);
+	}
+	return ret;
+}
+
+static int venc_resume(struct venc_dev *dvenc)
+{
+	int ret = 0;
+	struct venc_msg msg;
+
+	ret = dal_call_f0(dvenc->q6_handle, VENC_DALRPC_RESUME, 1);
+	if (ret) {
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+		msg.msg_code = VENC_MSG_RESUME;
+		msg.msg_data_size = 0;
+		msg.status_code = VENC_S_EFAIL;
+		venc_put_msg(dvenc, &msg);
+	}
+	return ret;
+}
+
+static int venc_flush(struct venc_dev *dvenc, void *argp)
+{
+	int ret = 0;
+	struct venc_msg msg;
+	union venc_msg_data smsg;
+	int status = VENC_S_SUCCESS;
+	struct venc_buffer_flush flush;
+
+	if (copy_from_user(&flush, argp, sizeof(struct venc_buffer_flush)))
+		return -EFAULT;
+	if (flush.flush_mode == VENC_FLUSH_ALL) {
+		ret = dal_call_f0(dvenc->q6_handle, VENC_DALRPC_FLUSH, 1);
+		if (ret)
+			status = VENC_S_EFAIL;
+	} else
+		status = VENC_S_ENOTSUPP;
+
+	if (status != VENC_S_SUCCESS) {
+		if ((flush.flush_mode == VENC_FLUSH_INPUT) ||
+		     (flush.flush_mode == VENC_FLUSH_ALL)) {
+			smsg.flush_ret.flush_mode = VENC_FLUSH_INPUT;
+			msg.msg_data = smsg;
+			msg.status_code = status;
+			msg.msg_code = VENC_MSG_FLUSH;
+			msg.msg_data_size = sizeof(union venc_msg_data);
+			venc_put_msg(dvenc, &msg);
+		}
+		if (flush.flush_mode == VENC_FLUSH_OUTPUT ||
+		     (flush.flush_mode == VENC_FLUSH_ALL)) {
+			smsg.flush_ret.flush_mode = VENC_FLUSH_OUTPUT;
+			msg.msg_data = smsg;
+			msg.status_code = status;
+			msg.msg_code = VENC_MSG_FLUSH;
+			msg.msg_data_size = sizeof(union venc_msg_data);
+			venc_put_msg(dvenc, &msg);
+		}
+		return -EIO;
+	}
+	return ret;
+}
+
+static int venc_get_sequence_hdr(struct venc_dev *dvenc, void *argp)
+{
+	pr_err("%s not supported\n", __func__);
+	return -EIO;
+}
+
+static int venc_set_qp_range(struct venc_dev *dvenc, void *argp)
+{
+	int ret = 0;
+	struct venc_qp_range qp;
+
+	ret = copy_from_user(&qp, argp, sizeof(struct venc_qp_range));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+
+	if (dvenc->state == VENC_STATE_START ||
+		dvenc->state == VENC_STATE_PAUSE) {
+		ret =
+		    dal_call_f5(dvenc->q6_handle, VENC_DALRPC_UPDATE_QP_RANGE,
+				&qp, sizeof(struct venc_qp_range));
+		if (ret) {
+			pr_err("%s: remote function failed (%d) \n", __func__,
+				ret);
+			return ret;
+		}
+	}
+	return ret;
+}
+
+static int venc_set_intra_period(struct venc_dev *dvenc, void *argp)
+{
+	int ret = 0;
+	u32 pnum = 0;
+
+	ret = copy_from_user(&pnum, argp, sizeof(int));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+	if (dvenc->state == VENC_STATE_START ||
+		dvenc->state == VENC_STATE_PAUSE) {
+		ret = dal_call_f0(dvenc->q6_handle,
+			VENC_DALRPC_UPDATE_INTRA_PERIOD, pnum);
+		if (ret)
+			pr_err("%s: remote function failed (%d)\n", __func__,
+				ret);
+	}
+	return ret;
+}
+
+static int venc_set_intra_refresh(struct venc_dev *dvenc, void *argp)
+{
+	int ret = 0;
+	u32 mb_num = 0;
+
+	ret = copy_from_user(&mb_num, argp, sizeof(int));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+	if (dvenc->state == VENC_STATE_START ||
+		dvenc->state == VENC_STATE_PAUSE) {
+		ret = dal_call_f0(dvenc->q6_handle,
+			VENC_DALRPC_UPDATE_INTRA_REFRESH, mb_num);
+		if (ret)
+			pr_err("%s: remote function failed (%d)\n", __func__,
+				ret);
+	}
+	return ret;
+}
+
+static int venc_set_frame_rate(struct venc_dev *dvenc, void *argp)
+{
+	int ret = 0;
+	struct venc_frame_rate pdata;
+	ret = copy_from_user(&pdata, argp, sizeof(struct venc_frame_rate));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+	if (dvenc->state == VENC_STATE_START ||
+		dvenc->state == VENC_STATE_PAUSE) {
+		ret = dal_call_f5(dvenc->q6_handle,
+				VENC_DALRPC_UPDATE_FRAME_RATE,
+				(void *)&(pdata),
+				sizeof(struct venc_frame_rate));
+		if (ret)
+			pr_err("%s: remote function failed (%d)\n", __func__,
+				ret);
+	}
+	return ret;
+}
+
+static int venc_set_target_bitrate(struct venc_dev *dvenc, void *argp)
+{
+	int ret = 0;
+	u32 pdata = 0;
+
+	ret = copy_from_user(&pdata, argp, sizeof(int));
+	if (ret) {
+		pr_err("%s: copy_from_user failed\n", __func__);
+		return ret;
+	}
+	if (dvenc->state == VENC_STATE_START ||
+		dvenc->state == VENC_STATE_PAUSE) {
+		ret = dal_call_f0(dvenc->q6_handle,
+			VENC_DALRPC_UPDATE_BITRATE, pdata);
+		if (ret)
+			pr_err("%s: remote function failed (%d)\n", __func__,
+				ret);
+	}
+	return ret;
+}
+
+static int venc_request_iframe(struct venc_dev *dvenc)
+{
+	int ret = 0;
+
+	if (dvenc->state != VENC_STATE_START)
+		return -EINVAL;
+
+	ret = dal_call_f0(dvenc->q6_handle, VENC_DALRPC_REQUEST_IFRAME, 1);
+	if (ret)
+		pr_err("%s: remote function failed (%d)\n", __func__, ret);
+	return ret;
+}
+
+static int venc_stop_read_msg(struct venc_dev *dvenc)
+{
+	struct venc_msg msg;
+	int ret = 0;
+
+	msg.status_code = 0;
+	msg.msg_code = VENC_MSG_STOP_READING_MSG;
+	msg.msg_data_size = 0;
+	venc_put_msg(dvenc, &msg);
+	return ret;
+}
+
+static int venc_q6_stop(struct venc_dev *dvenc)
+{
+	int ret = 0;
+	struct venc_pmem_list *plist;
+	unsigned long flags;
+
+	wake_up(&dvenc->venc_msg_evt);
+	spin_lock_irqsave(&dvenc->venc_pmem_list_lock, flags);
+	if (!dvenc->pmem_freed) {
+		list_for_each_entry(plist, &dvenc->venc_pmem_list_head, list)
+			put_pmem_file(plist->buf.file);
+		dvenc->pmem_freed = 1;
+	}
+	spin_unlock_irqrestore(&dvenc->venc_pmem_list_lock, flags);
+
+	dvenc->state = VENC_STATE_STOP;
+	return ret;
+}
+
+static int venc_translate_error(enum venc_status_code q6_status)
+{
+	int ret = 0;
+
+	switch (q6_status) {
+	case VENC_STATUS_SUCCESS:
+		ret = VENC_S_SUCCESS;
+		break;
+	case VENC_STATUS_ERROR:
+		ret = VENC_S_EFAIL;
+		break;
+	case VENC_STATUS_INVALID_STATE:
+		ret = VENC_S_EINVALSTATE;
+		break;
+	case VENC_STATUS_FLUSHING:
+		ret = VENC_S_EFLUSHED;
+		break;
+	case VENC_STATUS_INVALID_PARAM:
+		ret = VENC_S_EBADPARAM;
+		break;
+	case VENC_STATUS_CMD_QUEUE_FULL:
+		ret = VENC_S_ECMDQFULL;
+		break;
+	case VENC_STATUS_CRITICAL:
+		ret = VENC_S_EFATAL;
+		break;
+	case VENC_STATUS_INSUFFICIENT_RESOURCES:
+		ret = VENC_S_ENOHWRES;
+		break;
+	case VENC_STATUS_TIMEOUT:
+		ret = VENC_S_ETIMEOUT;
+		break;
+	}
+	if (q6_status != VENC_STATUS_SUCCESS)
+		pr_err("%s: Q6 failed (%d)", __func__, (int)q6_status);
+	return ret;
+}
+
+static void venc_q6_callback(void *data, int len, void *cookie)
+{
+	int status = 0;
+	struct venc_dev *dvenc = (struct venc_dev *)cookie;
+	struct venc_msg_type *q6_msg = NULL;
+	struct venc_msg msg, msg1;
+	union venc_msg_data smsg1, smsg2;
+	unsigned long msg_code = 0;
+	struct venc_input_payload *pload1;
+	struct venc_output_payload *pload2;
+	uint32_t * tmp = (uint32_t *) data;
+
+	if (dvenc == NULL) {
+		pr_err("%s: empty driver parameter\n", __func__);
+		return;
+	}
+	if (tmp[2] == sizeof(struct venc_msg_type)) {
+		q6_msg = (struct venc_msg_type *)&tmp[3];
+	} else {
+		pr_err("%s: callback with empty message (%d, %d)\n",
+			__func__, tmp[2], sizeof(struct venc_msg_type));
+		return;
+	}
+	msg.msg_data_size = 0;
+	status = venc_translate_error(q6_msg->status);
+	switch ((enum venc_event_type_enum)q6_msg->event) {
+	case VENC_EVENT_START_STATUS:
+		dvenc->state = VENC_STATE_START;
+		msg_code = VENC_MSG_START;
+		break;
+	case VENC_EVENT_STOP_STATUS:
+		venc_q6_stop(dvenc);
+		msg_code = VENC_MSG_STOP;
+		break;
+	case VENC_EVENT_SUSPEND_STATUS:
+		dvenc->state = VENC_STATE_PAUSE;
+		msg_code = VENC_MSG_PAUSE;
+		break;
+	case VENC_EVENT_RESUME_STATUS:
+		dvenc->state = VENC_STATE_START;
+		msg_code = VENC_MSG_RESUME;
+		break;
+	case VENC_EVENT_FLUSH_STATUS:
+		smsg1.flush_ret.flush_mode = VENC_FLUSH_INPUT;
+		msg1.status_code = status;
+		msg1.msg_code = VENC_MSG_FLUSH;
+		msg1.msg_data = smsg1;
+		msg1.msg_data_size = sizeof(union venc_msg_data);
+		venc_put_msg(dvenc, &msg1);
+		smsg2.flush_ret.flush_mode = VENC_FLUSH_OUTPUT;
+		msg_code = VENC_MSG_FLUSH;
+		msg.msg_data = smsg2;
+		msg.msg_data_size = sizeof(union venc_msg_data);
+		break;
+	case VENC_EVENT_RELEASE_INPUT:
+		pload1 = &((q6_msg->payload).input_payload);
+		TRACE("Release_input: data: 0x%x \n", pload1->data);
+		if (pload1 != NULL) {
+			msg.msg_data.buf.client_data = pload1->data;
+			msg_code = VENC_MSG_INPUT_BUFFER_DONE;
+			msg.msg_data_size = sizeof(union venc_msg_data);
+		}
+		break;
+	case VENC_EVENT_DELIVER_OUTPUT:
+		pload2 = &((q6_msg->payload).output_payload);
+		smsg1.buf.flags = 0;
+		if (pload2->flags & VENC_FLAG_SYNC_FRAME)
+			smsg1.buf.flags |= VENC_FLAG_SYNC_FRAME;
+		if (pload2->flags & VENC_FLAG_CODEC_CONFIG)
+			smsg1.buf.flags |= VENC_FLAG_CODEC_CONFIG;
+		if (pload2->flags & VENC_FLAG_END_OF_FRAME)
+			smsg1.buf.flags |= VENC_FLAG_END_OF_FRAME;
+		if (pload2->flags & VENC_FLAG_EOS)
+			smsg1.buf.flags |= VENC_FLAG_EOS;
+		smsg1.buf.len = pload2->size;
+		smsg1.buf.offset = 0;
+		smsg1.buf.time_stamp = pload2->time_stamp;
+		smsg1.buf.client_data = pload2->data;
+		msg_code = VENC_MSG_OUTPUT_BUFFER_DONE;
+		msg.msg_data = smsg1;
+		msg.msg_data_size = sizeof(union venc_msg_data);
+		break;
+	default:
+		pr_err("%s: invalid response from Q6 (%d)\n", __func__,
+			(int)q6_msg->event);
+		return;
+	}
+	msg.status_code = status;
+	msg.msg_code = msg_code;
+	venc_put_msg(dvenc, &msg);
+	return;
+}
+
+static int venc_get_version(struct venc_dev *dvenc, void *argp)
+{
+	struct venc_version ver_info;
+	int ret = 0;
+
+	ver_info.major = VENC_GET_MAJOR_VERSION(VENC_INTERFACE_VERSION);
+	ver_info.minor = VENC_GET_MINOR_VERSION(VENC_INTERFACE_VERSION);
+
+	ret = copy_to_user(((struct venc_version *)argp),
+				&ver_info, sizeof(ver_info));
+	if (ret)
+		pr_err("%s failed to copy_to_user\n", __func__);
+
+	return ret;
+
+}
+
+static long q6venc_ioctl(struct file *file, u32 cmd,
+			   unsigned long arg)
+{
+	long ret = 0;
+	void __user *argp = (void __user *)arg;
+	struct venc_dev *dvenc = file->private_data;
+
+	if (!dvenc || !dvenc->is_active)
+		return -EPERM;
+
+	switch (cmd) {
+	case VENC_IOCTL_SET_INPUT_BUFFER:
+		ret = venc_set_buffer(dvenc, argp, VENC_BUFFER_TYPE_INPUT);
+		break;
+	case VENC_IOCTL_SET_OUTPUT_BUFFER:
+		ret = venc_set_buffer(dvenc, argp, VENC_BUFFER_TYPE_OUTPUT);
+		break;
+	case VENC_IOCTL_GET_SEQUENCE_HDR:
+		ret = venc_get_sequence_hdr(dvenc, argp);
+		break;
+	case VENC_IOCTL_SET_QP_RANGE:
+		ret = venc_set_qp_range(dvenc, argp);
+		break;
+	case VENC_IOCTL_SET_INTRA_PERIOD:
+		ret = venc_set_intra_period(dvenc, argp);
+		break;
+	case VENC_IOCTL_SET_INTRA_REFRESH:
+		ret = venc_set_intra_refresh(dvenc, argp);
+		break;
+	case VENC_IOCTL_SET_FRAME_RATE:
+		ret = venc_set_frame_rate(dvenc, argp);
+		break;
+	case VENC_IOCTL_SET_TARGET_BITRATE:
+		ret = venc_set_target_bitrate(dvenc, argp);
+		break;
+	case VENC_IOCTL_CMD_REQUEST_IFRAME:
+		if (dvenc->state == VENC_STATE_START)
+			ret = venc_request_iframe(dvenc);
+		break;
+	case VENC_IOCTL_CMD_START:
+		ret = venc_start(dvenc, argp);
+		break;
+	case VENC_IOCTL_CMD_STOP:
+		ret = venc_stop(dvenc);
+		break;
+	case VENC_IOCTL_CMD_PAUSE:
+		ret = venc_pause(dvenc);
+		break;
+	case VENC_IOCTL_CMD_RESUME:
+		ret = venc_resume(dvenc);
+		break;
+	case VENC_IOCTL_CMD_ENCODE_FRAME:
+		ret = venc_encode_frame(dvenc, argp);
+		break;
+	case VENC_IOCTL_CMD_FILL_OUTPUT_BUFFER:
+		ret = venc_fill_output(dvenc, argp);
+		break;
+	case VENC_IOCTL_CMD_FLUSH:
+		ret = venc_flush(dvenc, argp);
+		break;
+	case VENC_IOCTL_CMD_READ_NEXT_MSG:
+		wait_event_interruptible(dvenc->venc_msg_evt,
+					  venc_get_msg(dvenc, argp));
+		break;
+	case VENC_IOCTL_CMD_STOP_READ_MSG:
+		ret = venc_stop_read_msg(dvenc);
+		break;
+	case VENC_IOCTL_GET_VERSION:
+		ret = venc_get_version(dvenc, argp);
+		break;
+	default:
+		pr_err("%s: invalid ioctl code (%d)\n", __func__, cmd);
+		ret = -ENOTTY;
+		break;
+	}
+	return ret;
+}
+
+static int q6venc_open(struct inode *inode, struct file *file)
+{
+	int i;
+	int ret = 0;
+	struct venc_dev *dvenc;
+	struct venc_msg_list *plist, *tmp;
+	struct dal_info version_info;
+
+	dvenc = kzalloc(sizeof(struct venc_dev), GFP_KERNEL);
+	if (!dvenc) {
+		pr_err("%s: unable to allocate memory for struct venc_dev\n",
+			__func__);
+		return -ENOMEM;
+	}
+	file->private_data = dvenc;
+	INIT_LIST_HEAD(&dvenc->venc_msg_list_head);
+	INIT_LIST_HEAD(&dvenc->venc_msg_list_free);
+	INIT_LIST_HEAD(&dvenc->venc_pmem_list_head);
+	init_waitqueue_head(&dvenc->venc_msg_evt);
+	spin_lock_init(&dvenc->venc_msg_list_lock);
+	spin_lock_init(&dvenc->venc_pmem_list_lock);
+	venc_ref++;
+	for (i = 0; i < VENC_MSG_MAX; i++) {
+		plist = kzalloc(sizeof(struct venc_msg_list), GFP_KERNEL);
+		if (!plist) {
+			pr_err("%s: kzalloc failed\n", __func__);
+			ret = -ENOMEM;
+			goto err_venc_create_msg_list;
+		}
+		list_add(&plist->list, &dvenc->venc_msg_list_free);
+	}
+	dvenc->q6_handle =
+	    dal_attach(DALDEVICEID_VENC_DEVICE, DALDEVICEID_VENC_PORTNAME, 1,
+		       venc_q6_callback, (void *)dvenc);
+	if (!(dvenc->q6_handle)) {
+		pr_err("%s: daldevice_attach failed (%d)\n", __func__, ret);
+		goto err_venc_dal_attach;
+	}
+	ret = dal_call_f9(dvenc->q6_handle, DAL_OP_INFO, &version_info,
+		sizeof(struct dal_info));
+	if (ret) {
+		pr_err("%s: failed to get version\n", __func__);
+		goto err_venc_dal_open;
+	}
+	if (venc_check_version(VENC_INTERFACE_VERSION, version_info.version)) {
+		pr_err("%s: driver version mismatch\n", __func__);
+		goto err_venc_dal_open;
+	}
+	ret = dal_call_f0(dvenc->q6_handle, DAL_OP_OPEN, 1);
+	if (ret) {
+		pr_err("%s: dal_call_open failed (%d)\n", __func__, ret);
+		goto err_venc_dal_open;
+	}
+	dvenc->state = VENC_STATE_STOP;
+	dvenc->is_active = 1;
+	prevent_sleep();
+	return ret;
+err_venc_dal_open:
+	dal_detach(dvenc->q6_handle);
+err_venc_dal_attach:
+	list_for_each_entry_safe(plist, tmp, &dvenc->venc_msg_list_free, list) {
+		list_del(&plist->list);
+		kfree(plist);
+	}
+err_venc_create_msg_list:
+	kfree(dvenc);
+	venc_ref--;
+	return ret;
+}
+
+static int q6venc_release(struct inode *inode, struct file *file)
+{
+	int ret = 0;
+	struct venc_msg_list *l, *n;
+	struct venc_pmem_list *plist, *m;
+	struct venc_dev *dvenc;
+	unsigned long flags;
+
+	venc_ref--;
+	dvenc = file->private_data;
+	dvenc->is_active = 0;
+	wake_up_all(&dvenc->venc_msg_evt);
+	dal_call_f0(dvenc->q6_handle, VENC_DALRPC_STOP, 1);
+	dal_call_f0(dvenc->q6_handle, DAL_OP_CLOSE, 1);
+	dal_detach(dvenc->q6_handle);
+	list_for_each_entry_safe(l, n, &dvenc->venc_msg_list_free, list) {
+		list_del(&l->list);
+		kfree(l);
+	}
+	list_for_each_entry_safe(l, n, &dvenc->venc_msg_list_head, list) {
+		list_del(&l->list);
+		kfree(l);
+	}
+	spin_lock_irqsave(&dvenc->venc_pmem_list_lock, flags);
+	if (!dvenc->pmem_freed) {
+		list_for_each_entry(plist, &dvenc->venc_pmem_list_head, list)
+			put_pmem_file(plist->buf.file);
+		dvenc->pmem_freed = 1;
+	}
+	spin_unlock_irqrestore(&dvenc->venc_pmem_list_lock, flags);
+
+	list_for_each_entry_safe(plist, m, &dvenc->venc_pmem_list_head, list) {
+		list_del(&plist->list);
+		kfree(plist);
+	}
+	kfree(dvenc);
+	allow_sleep();
+	return ret;
+}
+
+const struct file_operations q6venc_fops = {
+	.owner = THIS_MODULE,
+	.open = q6venc_open,
+	.release = q6venc_release,
+	.unlocked_ioctl = q6venc_ioctl,
+};
+
+static int __init q6venc_init(void)
+{
+	int ret = 0;
+
+	wake_lock_init(&idlelock, WAKE_LOCK_IDLE, "venc_idle");
+	wake_lock_init(&wakelock, WAKE_LOCK_SUSPEND, "venc_suspend");
+
+	venc_device_p = kzalloc(sizeof(struct venc_dev), GFP_KERNEL);
+	if (!venc_device_p) {
+		pr_err("%s: unable to allocate memory for venc_device_p\n",
+			__func__);
+		return -ENOMEM;
+	}
+	ret = alloc_chrdev_region(&venc_dev_num, 0, 1, VENC_NAME);
+	if (ret < 0) {
+		pr_err("%s: alloc_chrdev_region failed (%d)\n", __func__,
+			ret);
+		return ret;
+	}
+	venc_class = class_create(THIS_MODULE, VENC_NAME);
+	if (IS_ERR(venc_class)) {
+		ret = PTR_ERR(venc_class);
+		pr_err("%s: failed to create venc_class (%d)\n",
+			__func__, ret);
+		goto err_venc_class_create;
+	}
+	venc_device_p->class_devp =
+	    device_create(venc_class, NULL, venc_dev_num, NULL,
+			  VENC_NAME);
+	if (IS_ERR(venc_device_p->class_devp)) {
+		ret = PTR_ERR(venc_device_p->class_devp);
+		pr_err("%s: failed to create class_device (%d)\n", __func__,
+			ret);
+		goto err_venc_class_device_create;
+	}
+	cdev_init(&cdev, &q6venc_fops);
+	cdev.owner = THIS_MODULE;
+	ret = cdev_add(&cdev, venc_dev_num, 1);
+	if (ret < 0) {
+		pr_err("%s: cdev_add failed (%d)\n", __func__, ret);
+		goto err_venc_cdev_add;
+	}
+	init_waitqueue_head(&venc_device_p->venc_msg_evt);
+	return ret;
+
+err_venc_cdev_add:
+	device_destroy(venc_class, venc_dev_num);
+err_venc_class_device_create:
+	class_destroy(venc_class);
+err_venc_class_create:
+	unregister_chrdev_region(venc_dev_num, 1);
+	return ret;
+}
+
+static void __exit q6venc_exit(void)
+{
+	cdev_del(&(cdev));
+	device_destroy(venc_class, venc_dev_num);
+	class_destroy(venc_class);
+	unregister_chrdev_region(venc_dev_num, 1);
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Video encoder driver for QDSP6");
+MODULE_VERSION("2.0");
+module_init(q6venc_init);
+module_exit(q6venc_exit);
diff --git a/arch/arm/mach-msm/qdsp6/pcm_in.c b/arch/arm/mach-msm/qdsp6/pcm_in.c
new file mode 100644
index 0000000..c6bddb8
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/pcm_in.c
@@ -0,0 +1,263 @@
+/* arch/arm/mach-msm/qdsp6/pcm_in.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ *
+ * 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio.h>
+
+#include <mach/msm_qdsp6_audio.h>
+#include <mach/debug_mm.h>
+
+struct pcm {
+	struct audio_client *ac;
+	uint32_t sample_rate;
+	uint32_t channel_count;
+	uint32_t buffer_size;
+	uint32_t rec_mode;
+};
+
+#define BUFSZ (256)
+
+void audio_client_dump(struct audio_client *ac);
+
+static long q6_in_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct pcm *pcm = file->private_data;
+	int rc = 0;
+
+	switch (cmd) {
+	case AUDIO_SET_VOLUME:
+		pr_debug("[%s:%s] SET_VOLUME\n", __MM_FILE__, __func__);
+		break;
+	case AUDIO_GET_STATS: {
+		struct msm_audio_stats stats;
+		pr_debug("[%s:%s] GET_STATS\n", __MM_FILE__, __func__);
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void*) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+	case AUDIO_START: {
+		uint32_t acdb_id;
+		pr_debug("[%s:%s] AUDIO_START\n", __MM_FILE__, __func__);
+		rc = 0;
+
+		if (arg == 0) {
+			acdb_id = 0;
+		} else if (copy_from_user(&acdb_id, (void*) arg, sizeof(acdb_id))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		if (pcm->ac) {
+			pr_err("[%s:%s] active session already existing\n",
+				__MM_FILE__, __func__);
+			rc = -EBUSY;
+		} else {
+			pcm->ac = q6audio_open_pcm(pcm->buffer_size,
+					pcm->sample_rate, pcm->channel_count,
+					pcm->rec_mode, acdb_id);
+			if (!pcm->ac) {
+				pr_err("[%s:%s] pcm open session failed\n",
+					__MM_FILE__, __func__);
+				rc = -ENOMEM;
+			}
+		}
+		break;
+	}
+	case AUDIO_STOP:
+		pr_debug("[%s:%s] AUDIO_STOP\n", __MM_FILE__, __func__);
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (copy_from_user(&config, (void*) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("[%s:%s] SET_CONFIG: samplerate = %d, channels = %d\n",
+			__MM_FILE__, __func__, config.sample_rate,
+			config.channel_count);
+		if (!config.channel_count || config.channel_count > 2) {
+			rc = -EINVAL;
+			pr_err("[%s:%s] invalid channelcount %d\n",
+			__MM_FILE__, __func__, config.channel_count);
+			break;
+		}
+		if (config.sample_rate < 8000 || config.sample_rate > 48000) {
+			rc = -EINVAL;
+			pr_err("[%s:%s] invalid samplerate %d\n", __MM_FILE__,
+				__func__, config.sample_rate);
+			break;
+		}
+		if (config.buffer_size < 128 || config.buffer_size > 8192) {
+			rc = -EINVAL;
+			pr_err("[%s:%s] invalid buffsize %d\n", __MM_FILE__,
+				__func__, config.buffer_size);
+			break;
+		}
+
+		pcm->sample_rate = config.sample_rate;
+		pcm->channel_count = config.channel_count;
+		pcm->buffer_size = config.buffer_size;
+		break;
+	}
+	case AUDIO_SET_INCALL: {
+		struct msm_voicerec_mode voicerec_mode;
+		pr_debug("[%s:%s] SET_INCALL\n", __MM_FILE__, __func__);
+		if (copy_from_user(&voicerec_mode, (void *)arg,
+			sizeof(struct msm_voicerec_mode)))
+			return -EFAULT;
+		if (voicerec_mode.rec_mode != AUDIO_FLAG_READ &&
+			voicerec_mode.rec_mode != AUDIO_FLAG_INCALL_MIXED) {
+			pcm->rec_mode = AUDIO_FLAG_READ;
+			pr_err("[%s:%s] invalid rec_mode\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+		} else
+			pcm->rec_mode = voicerec_mode.rec_mode;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_size = pcm->buffer_size;
+		config.buffer_count = 2;
+		config.sample_rate = pcm->sample_rate;
+		config.channel_count = pcm->channel_count;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void*) arg, &config, sizeof(config))) {
+			rc = -EFAULT;
+		}
+		pr_debug("[%s:%s] GET_CONFIG: samplerate = %d, channels = %d\n",
+			__MM_FILE__, __func__, config.sample_rate,
+			config.channel_count);
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	pr_debug("[%s:%s] rc = %d\n", __MM_FILE__, __func__, rc);
+	return rc;
+}
+
+static int q6_in_open(struct inode *inode, struct file *file)
+{
+	struct pcm *pcm;
+
+	pr_info("[%s:%s] open\n", __MM_FILE__, __func__);
+	pcm = kzalloc(sizeof(struct pcm), GFP_KERNEL);
+
+	if (!pcm)
+		return -ENOMEM;
+
+	pcm->channel_count = 1;
+	pcm->sample_rate = 8000;
+	pcm->buffer_size = BUFSZ;
+	pcm->rec_mode = AUDIO_FLAG_READ;
+	file->private_data = pcm;
+	return 0;
+}
+
+static ssize_t q6_in_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *pos)
+{
+	struct pcm *pcm = file->private_data;
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	const char __user *start = buf;
+	int xfer;
+	int res;
+
+	pr_debug("[%s:%s] count = %d\n", __MM_FILE__, __func__, count);
+	ac = pcm->ac;
+	if (!ac) {
+		res = -ENODEV;
+		goto fail;
+	}
+	while (count > 0) {
+		ab = ac->buf + ac->cpu_buf;
+
+		if (ab->used)
+			if (!wait_event_timeout(ac->wait, (ab->used == 0), 5*HZ)) {
+				audio_client_dump(ac);
+				pr_err("[%s:%s] timeout. dsp dead?\n",
+						__MM_FILE__, __func__);
+				q6audio_dsp_not_responding();
+			}
+		pr_debug("[%s:%s] ab->data = %p, cpu_buf = %d", __MM_FILE__,
+			__func__, ab->data, ac->cpu_buf);
+		xfer = count;
+		if (xfer > ab->size)
+			xfer = ab->size;
+
+		if (copy_to_user(buf, ab->data, xfer)) {
+			res = -EFAULT;
+			goto fail;
+		}
+
+		buf += xfer;
+		count -= xfer;
+
+		ab->used = 1;
+		q6audio_read(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+fail:
+	res = buf - start;
+	return res;
+}
+
+static int q6_in_release(struct inode *inode, struct file *file)
+{
+
+	int rc = 0;
+	struct pcm *pcm = file->private_data;
+	if (pcm->ac)
+		rc = q6audio_close(pcm->ac);
+	kfree(pcm);
+	pr_info("[%s:%s] release\n", __MM_FILE__, __func__);
+	return rc;
+}
+
+static struct file_operations q6_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_in_open,
+	.read		= q6_in_read,
+	.release	= q6_in_release,
+	.unlocked_ioctl	= q6_in_ioctl,
+};
+
+struct miscdevice q6_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_pcm_in",
+	.fops	= &q6_in_fops,
+};
+
+static int __init q6_in_init(void) {
+	return misc_register(&q6_in_misc);
+}
+
+device_initcall(q6_in_init);
diff --git a/arch/arm/mach-msm/qdsp6/pcm_out.c b/arch/arm/mach-msm/qdsp6/pcm_out.c
new file mode 100644
index 0000000..2e91cb2
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/pcm_out.c
@@ -0,0 +1,276 @@
+/* arch/arm/mach-msm/qdsp6/pcm_out.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+
+#include <linux/msm_audio.h>
+
+#include <mach/msm_qdsp6_audio.h>
+#include <mach/debug_mm.h>
+
+void audio_client_dump(struct audio_client *ac);
+
+#define BUFSZ (3072)
+
+struct pcm {
+	struct mutex lock;
+	struct audio_client *ac;
+	uint32_t sample_rate;
+	uint32_t channel_count;
+	size_t buffer_size;
+};
+
+static long pcm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct pcm *pcm = file->private_data;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void*) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	mutex_lock(&pcm->lock);
+	switch (cmd) {
+	case AUDIO_SET_VOLUME: {
+		int vol;
+		if (!pcm->ac) {
+			pr_err("%s: cannot set volume before AUDIO_START!\n",
+				__func__);
+			rc = -EINVAL;
+			break;
+		}
+		if (copy_from_user(&vol, (void*) arg, sizeof(vol))) {
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("[%s:%s] SET_VOLUME: vol = %d\n", __MM_FILE__,
+			__func__, vol);
+		rc = q6audio_set_stream_volume(pcm->ac, vol);
+		break;
+	}
+	case AUDIO_START: {
+		uint32_t acdb_id;
+		pr_debug("[%s:%s] AUDIO_START\n", __MM_FILE__, __func__);
+		if (arg == 0) {
+			acdb_id = 0;
+		} else if (copy_from_user(&acdb_id, (void*) arg, sizeof(acdb_id))) {
+			pr_info("[%s:%s] copy acdb_id from user failed\n",
+					__MM_FILE__, __func__);
+			rc = -EFAULT;
+			break;
+		}
+		if (pcm->ac) {
+			pr_err("[%s:%s] active session already existing\n",
+				__MM_FILE__, __func__);
+			rc = -EBUSY;
+		} else {
+			pcm->ac = q6audio_open_pcm(pcm->buffer_size,
+						pcm->sample_rate,
+						pcm->channel_count,
+						AUDIO_FLAG_WRITE, acdb_id);
+			if (!pcm->ac) {
+				pr_err("[%s:%s] pcm open session failed\n",
+					__MM_FILE__, __func__);
+				rc = -ENOMEM;
+			}
+		}
+		break;
+	}
+	case AUDIO_STOP:
+		pr_debug("[%s:%s] AUDIO_STOP\n", __MM_FILE__, __func__);
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (pcm->ac) {
+			rc = -EBUSY;
+			pr_err("[%s:%s] active session already existing\n",
+				__MM_FILE__, __func__);
+			break;
+		}
+		if (copy_from_user(&config, (void*) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("[%s:%s] SET_CONFIG: samplerate = %d, channels = %d\n",
+			__MM_FILE__, __func__, config.sample_rate,
+			config.channel_count);
+		if (config.channel_count < 1 || config.channel_count > 2) {
+			rc = -EINVAL;
+			pr_err("[%s:%s] invalid channelcount %d\n",
+			__MM_FILE__, __func__, config.channel_count);
+			break;
+		}
+		if (config.sample_rate < 8000 || config.sample_rate > 48000) {
+			rc = -EINVAL;
+			pr_err("[%s:%s] invalid samplerate %d\n", __MM_FILE__,
+				__func__, config.sample_rate);
+			break;
+		}
+		if (config.buffer_size < 128 || config.buffer_size > 8192) {
+			rc = -EINVAL;
+			pr_err("[%s:%s] invalid buffsize %d\n", __MM_FILE__,
+				__func__, config.buffer_size);
+			break;
+		}
+		pcm->sample_rate = config.sample_rate;
+		pcm->channel_count = config.channel_count;
+		pcm->buffer_size = config.buffer_size;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_size = pcm->buffer_size;
+		config.buffer_count = 2;
+		config.sample_rate = pcm->sample_rate;
+		config.channel_count = pcm->channel_count;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void*) arg, &config, sizeof(config))) {
+			rc = -EFAULT;
+		}
+		pr_debug("[%s:%s] GET_CONFIG: samplerate = %d, channels = %d\n",
+			__MM_FILE__, __func__, config.sample_rate,
+			config.channel_count);
+		break;
+	}
+	case AUDIO_SET_EQ: {
+		struct msm_audio_eq_stream_config eq_config;
+		pr_debug("[%s:%s] SET_EQ\n", __MM_FILE__, __func__);
+		if (copy_from_user(&eq_config, (void *) arg,
+						sizeof(eq_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		rc = q6audio_set_stream_eq_pcm(pcm->ac, (void *) &eq_config);
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&pcm->lock);
+	pr_debug("[%s:%s] rc = %d\n", __MM_FILE__, __func__, rc);
+	return rc;
+}
+
+static int pcm_open(struct inode *inode, struct file *file)
+{
+	struct pcm *pcm;
+
+	pr_info("[%s:%s] open\n", __MM_FILE__, __func__);
+	pcm = kzalloc(sizeof(struct pcm), GFP_KERNEL);
+
+	if (!pcm)
+		return -ENOMEM;
+
+	mutex_init(&pcm->lock);
+	pcm->channel_count = 2;
+	pcm->sample_rate = 44100;
+	pcm->buffer_size = BUFSZ;
+	file->private_data = pcm;
+	return 0;
+}
+
+static ssize_t pcm_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct pcm *pcm = file->private_data;
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	const char __user *start = buf;
+	int xfer;
+
+	pr_debug("[%s:%s] count = %d\n", __MM_FILE__, __func__, count);
+	if (!pcm->ac)
+		pcm_ioctl(file, AUDIO_START, 0);
+
+	ac = pcm->ac;
+	if (!ac)
+		return -ENODEV;
+
+	while (count > 0) {
+		ab = ac->buf + ac->cpu_buf;
+
+		if (ab->used)
+			if (!wait_event_timeout(ac->wait, (ab->used == 0), 5*HZ)) {
+				audio_client_dump(ac);
+				pr_err("[%s:%s] timeout. dsp dead?\n",
+						__MM_FILE__, __func__);
+				q6audio_dsp_not_responding();
+			}
+		pr_debug("[%s:%s] ab->data = %p, cpu_buf = %d", __MM_FILE__,
+			__func__, ab->data, ac->cpu_buf);
+		xfer = count;
+		if (xfer > ab->size)
+			xfer = ab->size;
+
+		if (copy_from_user(ab->data, buf, xfer)) 
+			return -EFAULT;
+
+		buf += xfer;
+		count -= xfer;
+
+		ab->used = 1;
+		ab->actual_size = xfer;
+		q6audio_write(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+
+	return buf - start;
+}
+
+static int pcm_release(struct inode *inode, struct file *file)
+{
+	struct pcm *pcm = file->private_data;
+	if (pcm->ac)
+		q6audio_close(pcm->ac);
+	kfree(pcm);
+	pr_info("[%s:%s] release\n", __MM_FILE__, __func__);
+	return 0;
+}
+
+static struct file_operations pcm_fops = {
+	.owner		= THIS_MODULE,
+	.open		= pcm_open,
+	.write		= pcm_write,
+	.release	= pcm_release,
+	.unlocked_ioctl	= pcm_ioctl,
+};
+
+struct miscdevice pcm_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_pcm_out",
+	.fops	= &pcm_fops,
+};
+
+static int __init pcm_init(void) {
+	return misc_register(&pcm_misc);
+}
+
+device_initcall(pcm_init);
diff --git a/arch/arm/mach-msm/qdsp6/q6audio.c b/arch/arm/mach-msm/qdsp6/q6audio.c
new file mode 100644
index 0000000..bf6f115
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/q6audio.c
@@ -0,0 +1,2155 @@
+/*
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+
+#include <linux/delay.h>
+#include <linux/wakelock.h>
+#include <linux/android_pmem.h>
+#include <linux/firmware.h>
+#include <linux/miscdevice.h>
+
+#include "dal.h"
+#include "dal_audio.h"
+#include "dal_audio_format.h"
+#include "dal_acdb.h"
+#include "dal_adie.h"
+#include <mach/msm_qdsp6_audio.h>
+
+#include <linux/msm_audio_aac.h>
+
+#include <linux/gpio.h>
+
+#include "q6audio_devices.h"
+#include <mach/debug_mm.h>
+
+
+struct q6_hw_info {
+	int min_gain;
+	int max_gain;
+};
+
+/* TODO: provide mechanism to configure from board file */
+
+static struct q6_hw_info q6_audio_hw[Q6_HW_COUNT] = {
+	[Q6_HW_HANDSET] = {
+		.min_gain = -400,
+		.max_gain = 1100,
+	},
+	[Q6_HW_HEADSET] = {
+		.min_gain = -1100,
+		.max_gain = 400,
+	},
+	[Q6_HW_SPEAKER] = {
+		.min_gain = -1000,
+		.max_gain = 500,
+	},
+	[Q6_HW_TTY] = {
+		.min_gain = 0,
+		.max_gain = 0,
+	},
+	[Q6_HW_BT_SCO] = {
+		.min_gain = -1100,
+		.max_gain = 400,
+	},
+	[Q6_HW_BT_A2DP] = {
+		.min_gain = -1100,
+		.max_gain = 400,
+	},
+};
+
+static struct wake_lock wakelock;
+static struct wake_lock idlelock;
+static int idlecount;
+static DEFINE_MUTEX(idlecount_lock);
+
+void audio_prevent_sleep(void)
+{
+	mutex_lock(&idlecount_lock);
+	if (++idlecount == 1) {
+		wake_lock(&wakelock);
+		wake_lock(&idlelock);
+	}
+	mutex_unlock(&idlecount_lock);
+}
+
+void audio_allow_sleep(void)
+{
+	mutex_lock(&idlecount_lock);
+	if (--idlecount == 0) {
+		wake_unlock(&idlelock);
+		wake_unlock(&wakelock);
+	}
+	mutex_unlock(&idlecount_lock);
+}
+
+static struct clk *icodec_rx_clk;
+static struct clk *icodec_tx_clk;
+static struct clk *ecodec_clk;
+static struct clk *sdac_clk;
+
+static struct q6audio_analog_ops default_analog_ops;
+static struct q6audio_analog_ops *analog_ops = &default_analog_ops;
+static uint32_t tx_clk_freq = 8000;
+static int tx_mute_status = 0;
+static int rx_vol_level = 100;
+static uint32_t tx_acdb = 0;
+static uint32_t rx_acdb = 0;
+
+void q6audio_register_analog_ops(struct q6audio_analog_ops *ops)
+{
+	analog_ops = ops;
+}
+
+static struct q6_device_info *q6_lookup_device(uint32_t device_id,
+						uint32_t acdb_id)
+{
+	struct q6_device_info *di = q6_audio_devices;
+
+	pr_debug("[%s:%s] device_id = 0x%x, acdb_id = %d\n", __MM_FILE__,
+		__func__, device_id, acdb_id);
+	if (acdb_id) {
+		for (;;) {
+			if (di->cad_id == acdb_id && di->id == device_id)
+				return di;
+			if (di->id == 0) {
+				pr_err("[%s:%s] bogus id 0x%08x\n",
+					__MM_FILE__, __func__, device_id);
+				return di;
+			}
+			di++;
+		}
+	} else {
+		for (;;) {
+			if (di->id == device_id)
+				return di;
+			if (di->id == 0) {
+				pr_err("[%s:%s] bogus id 0x%08x\n",
+					__MM_FILE__, __func__, device_id);
+				return di;
+			}
+			di++;
+		}
+	}
+}
+
+static uint32_t q6_device_to_codec(uint32_t device_id)
+{
+	struct q6_device_info *di = q6_lookup_device(device_id, 0);
+	return di->codec;
+}
+
+static uint32_t q6_device_to_dir(uint32_t device_id)
+{
+	struct q6_device_info *di = q6_lookup_device(device_id, 0);
+	return di->dir;
+}
+
+static uint32_t q6_device_to_cad_id(uint32_t device_id)
+{
+	struct q6_device_info *di = q6_lookup_device(device_id, 0);
+	return di->cad_id;
+}
+
+static uint32_t q6_device_to_path(uint32_t device_id, uint32_t acdb_id)
+{
+	struct q6_device_info *di = q6_lookup_device(device_id, acdb_id);
+	return di->path;
+}
+
+static uint32_t q6_device_to_rate(uint32_t device_id)
+{
+	struct q6_device_info *di = q6_lookup_device(device_id, 0);
+	return di->rate;
+}
+
+int q6_device_volume(uint32_t device_id, int level)
+{
+	struct q6_device_info *di = q6_lookup_device(device_id, 0);
+	struct q6_hw_info *hw;
+
+	hw = &q6_audio_hw[di->hw];
+
+	return hw->min_gain + ((hw->max_gain - hw->min_gain) * level) / 100;
+}
+
+static inline int adie_open(struct dal_client *client) 
+{
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	return dal_call_f0(client, DAL_OP_OPEN, 0);
+}
+
+static inline int adie_close(struct dal_client *client) 
+{
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	return dal_call_f0(client, DAL_OP_CLOSE, 0);
+}
+
+static inline int adie_set_path(struct dal_client *client,
+				uint32_t id, uint32_t path_type)
+{
+	pr_debug("[%s:%s] id = 0x%x, path_type = %d\n", __MM_FILE__,
+		__func__, id, path_type);
+	return dal_call_f1(client, ADIE_OP_SET_PATH, id, path_type);
+}
+
+static inline int adie_set_path_freq_plan(struct dal_client *client,
+					  uint32_t path_type, uint32_t plan) 
+{
+	pr_debug("[%s:%s] path_type = %d, plan = %d\n",	__MM_FILE__,
+		__func__, path_type, plan);
+	return dal_call_f1(client, ADIE_OP_SET_PATH_FREQUENCY_PLAN,
+			   path_type, plan);
+}
+
+static inline int adie_proceed_to_stage(struct dal_client *client,
+					uint32_t path_type, uint32_t stage)
+{
+	pr_debug("[%s:%s] path_type = %d, stage = 0x%x\n", __MM_FILE__,
+		__func__, path_type, stage);
+	return dal_call_f1(client, ADIE_OP_PROCEED_TO_STAGE,
+			   path_type, stage);
+}
+
+static inline int adie_mute_path(struct dal_client *client,
+				 uint32_t path_type, uint32_t mute_state)
+{
+	pr_debug("[%s:%s] path_type = %d, mute = %d\n",	__MM_FILE__, __func__,
+		 path_type, mute_state);
+	return dal_call_f1(client, ADIE_OP_MUTE_PATH, path_type, mute_state);
+}
+
+static int adie_refcount;
+
+static struct dal_client *adie;
+static struct dal_client *adsp;
+static struct dal_client *acdb;
+
+static int adie_enable(void)
+{
+	adie_refcount++;
+	if (adie_refcount == 1)
+		adie_open(adie);
+	return 0;
+}
+
+static int adie_disable(void)
+{
+	adie_refcount--;
+	if (adie_refcount == 0)
+		adie_close(adie);
+	return 0;
+}
+
+/* 4k PMEM used for exchanging acdb device config tables
+ * and stream format descriptions with the DSP.
+ */
+static char *audio_data;
+static int32_t audio_phys;
+
+#define SESSION_MIN 0
+#define SESSION_MAX 64
+
+static DEFINE_MUTEX(session_lock);
+static DEFINE_MUTEX(audio_lock);
+
+static struct audio_client *session[SESSION_MAX];
+
+static int session_alloc(struct audio_client *ac)
+{
+	int n;
+
+	mutex_lock(&session_lock);
+	for (n = SESSION_MIN; n < SESSION_MAX; n++) {
+		if (!session[n]) {
+			session[n] = ac;
+			mutex_unlock(&session_lock);
+			pr_debug("[%s:%s] session = %d\n", __MM_FILE__,
+				__func__, n);
+			return n;
+		}
+	}
+	mutex_unlock(&session_lock);
+	return -ENOMEM;
+}
+
+static void session_free(int n, struct audio_client *ac)
+{
+	mutex_lock(&session_lock);
+	if (session[n] == ac) {
+		session[n] = 0;
+		pr_debug("[%s:%s] session = %d\n", __MM_FILE__, __func__, n);
+	}
+	mutex_unlock(&session_lock);
+}
+
+static void audio_client_free(struct audio_client *ac)
+{
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	session_free(ac->session, ac);
+
+	if (ac->buf[0].data) {
+		iounmap(ac->buf[0].data);
+		pmem_kfree(ac->buf[0].phys);
+	}
+	if (ac->buf[1].data) {
+		iounmap(ac->buf[1].data);
+		pmem_kfree(ac->buf[1].phys);
+	}
+	kfree(ac);
+}
+
+static struct audio_client *audio_client_alloc(unsigned bufsz)
+{
+	struct audio_client *ac;
+	int n;
+
+	pr_debug("[%s:%s] bufsz = %d\n", __MM_FILE__, __func__, bufsz);
+	ac = kzalloc(sizeof(*ac), GFP_KERNEL);
+	if (!ac)
+		return 0;
+
+	n = session_alloc(ac);
+	if (n < 0)
+		goto fail_session;
+	ac->session = n;
+
+	if (bufsz > 0) {
+		ac->buf[0].phys = pmem_kalloc(bufsz,
+					PMEM_MEMTYPE_EBI1|PMEM_ALIGNMENT_4K);
+		ac->buf[0].data = ioremap(ac->buf[0].phys, bufsz);
+		if (!ac->buf[0].data)
+			goto fail;
+		ac->buf[1].phys = pmem_kalloc(bufsz,
+					PMEM_MEMTYPE_EBI1|PMEM_ALIGNMENT_4K);
+		ac->buf[1].data = ioremap(ac->buf[1].phys, bufsz);
+		if (!ac->buf[1].data)
+			goto fail;
+
+		ac->buf[0].size = bufsz;
+		ac->buf[1].size = bufsz;
+	}
+
+	init_waitqueue_head(&ac->wait);
+	ac->client = adsp;
+
+	return ac;
+
+fail:
+	session_free(n, ac);
+fail_session:
+	audio_client_free(ac);
+	return 0;
+}
+
+void audio_client_dump(struct audio_client *ac)
+{
+	dal_trace_dump(ac->client);
+}
+
+static int audio_ioctl(struct audio_client *ac, void *ptr, uint32_t len)
+{
+	struct adsp_command_hdr *hdr = ptr;
+	uint32_t tmp;
+	int r;
+
+	hdr->size = len - sizeof(u32);
+	hdr->dst = AUDIO_ADDR(ac->session, 0, AUDIO_DOMAIN_DSP);
+	hdr->src = AUDIO_ADDR(ac->session, 0, AUDIO_DOMAIN_APP);
+	hdr->context = ac->session;
+	ac->cb_status = -EBUSY;
+	r = dal_call(ac->client, AUDIO_OP_CONTROL, 5, ptr, len, &tmp, sizeof(tmp));
+	if (r != 4)
+		return -EIO;
+	if (!wait_event_timeout(ac->wait, (ac->cb_status != -EBUSY), 5*HZ)) {
+		dal_trace_dump(ac->client);
+		pr_err("[%s:%s] timeout. dsp dead?\n", __MM_FILE__, __func__);
+		q6audio_dsp_not_responding();
+	}
+	return ac->cb_status;
+}
+
+static int audio_command(struct audio_client *ac, uint32_t cmd)
+{
+	struct adsp_command_hdr rpc;
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.opcode = cmd;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_open_control(struct audio_client *ac)
+{
+	struct adsp_open_command rpc;
+
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_DEVICE;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_out_open(struct audio_client *ac, uint32_t bufsz,
+			  uint32_t rate, uint32_t channels)
+{
+	struct adsp_open_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+
+	rpc.format.standard.format = ADSP_AUDIO_FORMAT_PCM;
+	rpc.format.standard.channels = channels;
+	rpc.format.standard.bits_per_sample = 16;
+	rpc.format.standard.sampling_rate = rate;
+	rpc.format.standard.is_signed = 1;
+	rpc.format.standard.is_interleaved = 1;
+
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_WRITE;
+	rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+	rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_PLAYBACK;
+	rpc.buf_max_size = bufsz;
+
+	pr_debug("[%s:%s]ac = %p\n", __MM_FILE__, __func__, ac);
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_in_open(struct audio_client *ac, uint32_t bufsz,
+			 uint32_t flags, uint32_t rate, uint32_t channels)
+{
+	struct adsp_open_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+
+	rpc.format.standard.format = ADSP_AUDIO_FORMAT_PCM;
+	rpc.format.standard.channels = channels;
+	rpc.format.standard.bits_per_sample = 16;
+	rpc.format.standard.sampling_rate = rate;
+	rpc.format.standard.is_signed = 1;
+	rpc.format.standard.is_interleaved = 1;
+
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_READ;
+	rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+	if (flags == AUDIO_FLAG_READ)
+		rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD;
+	else
+		rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_MIXED_RECORD;
+
+	rpc.buf_max_size = bufsz;
+
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_auxpcm_out_open(struct audio_client *ac,
+			  uint32_t rate, uint32_t channels)
+{
+	struct adsp_open_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+
+	rpc.format.standard.format = ADSP_AUDIO_FORMAT_PCM;
+	rpc.format.standard.channels = channels;
+	rpc.format.standard.bits_per_sample = 16;
+	rpc.format.standard.sampling_rate = rate;
+	rpc.format.standard.is_signed = 1;
+	rpc.format.standard.is_interleaved = 1;
+
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_READ;
+	rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+	rpc.mode =  ADSP_AUDIO_OPEN_STREAM_MODE_AUX_PCM;
+	rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD;
+
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_auxpcm_in_open(struct audio_client *ac, uint32_t rate,
+		uint32_t channels)
+{
+	struct adsp_open_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+
+	rpc.format.standard.format = ADSP_AUDIO_FORMAT_PCM;
+	rpc.format.standard.channels = channels;
+	rpc.format.standard.bits_per_sample = 16;
+	rpc.format.standard.sampling_rate = rate;
+	rpc.format.standard.is_signed = 1;
+	rpc.format.standard.is_interleaved = 1;
+
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_WRITE;
+	rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+	rpc.mode =  ADSP_AUDIO_OPEN_STREAM_MODE_AUX_PCM;
+	rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_PLAYBACK;
+
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_mp3_open(struct audio_client *ac, uint32_t bufsz,
+			  uint32_t rate, uint32_t channels)
+{
+	struct adsp_open_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+
+	rpc.format.standard.format = ADSP_AUDIO_FORMAT_MP3;
+	rpc.format.standard.channels = channels;
+	rpc.format.standard.bits_per_sample = 16;
+	rpc.format.standard.sampling_rate = rate;
+	rpc.format.standard.is_signed = 1;
+	rpc.format.standard.is_interleaved = 0;
+
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_WRITE;
+	rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+	rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_PLAYBACK;
+	rpc.buf_max_size = bufsz;
+
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_dtmf_open(struct audio_client *ac,
+			  uint32_t rate, uint32_t channels)
+{
+	struct adsp_open_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+
+	rpc.format.standard.format = ADSP_AUDIO_FORMAT_DTMF;
+	rpc.format.standard.channels = channels;
+	rpc.format.standard.bits_per_sample = 16;
+	rpc.format.standard.sampling_rate = rate;
+	rpc.format.standard.is_signed = 1;
+	rpc.format.standard.is_interleaved = 0;
+
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_WRITE;
+	rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+	rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_PLAYBACK;
+
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_aac_open(struct audio_client *ac, uint32_t bufsz,
+			  uint32_t sample_rate, uint32_t channels,
+			  uint32_t bit_rate, uint32_t flags,
+					uint32_t stream_format)
+{
+	struct adsp_open_command rpc;
+	int audio_object_type;
+	int index = sizeof(u32);
+	u32 *aac_type = NULL;
+
+	memset(&rpc, 0, sizeof(rpc));
+
+	rpc.format.binary.format = ADSP_AUDIO_FORMAT_MPEG4_AAC;
+	/* only 48k sample rate is supported */
+	sample_rate = 3;
+	/* AAC OBJECT LC */
+	audio_object_type = 2;
+
+	aac_type = (u32 *)rpc.format.binary.data;
+	switch (stream_format) {
+	case AUDIO_AAC_FORMAT_ADTS:
+		/* AAC Encoder expect MPEG4_ADTS media type */
+		*aac_type = ADSP_AUDIO_AAC_MPEG4_ADTS;
+	break;
+	case AUDIO_AAC_FORMAT_RAW:
+		/* for ADIF recording */
+		*aac_type = ADSP_AUDIO_AAC_RAW;
+	break;
+	}
+
+	rpc.format.binary.data[index++] = (u8)(
+			((audio_object_type & 0x1F) << 3) |
+			((sample_rate >> 1) & 0x7));
+			rpc.format.binary.data[index] = (u8)(
+			((sample_rate & 0x1) << 7) |
+			((channels & 0x7) << 3));
+	rpc.format.binary.num_bytes = index + 1;
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_READ;
+	rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+
+	if (flags == AUDIO_FLAG_READ)
+		rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD;
+	else
+		rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_MIXED_RECORD;
+
+	rpc.buf_max_size = bufsz;
+	rpc.config.aac.bit_rate = bit_rate;
+	rpc.config.aac.encoder_mode = ADSP_AUDIO_ENC_AAC_LC_ONLY_MODE;
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_qcp_open(struct audio_client *ac, uint32_t bufsz,
+				uint32_t min_rate, uint32_t max_rate,
+				uint32_t flags, uint32_t format)
+{
+	struct adsp_open_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+
+	rpc.format.standard.format = format;
+	rpc.format.standard.channels = 1;
+	rpc.format.standard.bits_per_sample = 16;
+	rpc.format.standard.sampling_rate = 8000;
+	rpc.format.standard.is_signed = 1;
+	rpc.format.standard.is_interleaved = 0;
+
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_READ;
+	rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+
+	if (flags == AUDIO_FLAG_READ)
+		rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD;
+	else
+		rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_MIXED_RECORD;
+	rpc.buf_max_size = bufsz;
+	rpc.config.evrc.min_rate = min_rate;
+	rpc.config.evrc.max_rate = max_rate;
+
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_amrnb_open(struct audio_client *ac, uint32_t bufsz,
+					uint32_t enc_mode, uint32_t flags,
+					uint32_t dtx_enable)
+{
+	struct adsp_open_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+
+	rpc.format.standard.format = ADSP_AUDIO_FORMAT_AMRNB_FS;
+	rpc.format.standard.channels = 1;
+	rpc.format.standard.bits_per_sample = 16;
+	rpc.format.standard.sampling_rate = 8000;
+	rpc.format.standard.is_signed = 1;
+	rpc.format.standard.is_interleaved = 0;
+
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_OPEN_READ;
+	rpc.device = ADSP_AUDIO_DEVICE_ID_DEFAULT;
+
+	if (flags == AUDIO_FLAG_READ)
+		rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD;
+	else
+		rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_MIXED_RECORD;
+
+	rpc.buf_max_size = bufsz;
+	rpc.config.amr.mode = enc_mode;
+	rpc.config.amr.dtx_mode = dtx_enable;
+	rpc.config.amr.enable = 1;
+
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+
+
+static int audio_close(struct audio_client *ac)
+{
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	audio_command(ac, ADSP_AUDIO_IOCTL_CMD_STREAM_STOP);
+	audio_command(ac, ADSP_AUDIO_IOCTL_CMD_CLOSE);
+	return 0;
+}
+
+static int audio_set_table(struct audio_client *ac,
+			   uint32_t device_id, int size)
+{
+	struct adsp_set_dev_cfg_table_command rpc;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_SET_DEVICE_CONFIG_TABLE;
+	if (q6_device_to_dir(device_id) == Q6_TX) {
+		if (tx_clk_freq > 16000)
+			rpc.hdr.data = 48000;
+		else if (tx_clk_freq > 8000)
+			rpc.hdr.data = 16000;
+		else
+			rpc.hdr.data = 8000;
+	}
+	rpc.device_id = device_id;
+	rpc.phys_addr = audio_phys;
+	rpc.phys_size = size;
+	rpc.phys_used = size;
+
+	pr_debug("[%s:%s] ac = %p, device_id = 0x%x, size = %d\n", __MM_FILE__,
+		__func__, ac, device_id, size);
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+int q6audio_read(struct audio_client *ac, struct audio_buffer *ab)
+{
+	struct adsp_buffer_command rpc;
+	uint32_t res;
+	int r;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.size = sizeof(rpc) - sizeof(u32);
+	rpc.hdr.dst = AUDIO_ADDR(ac->session, 0, AUDIO_DOMAIN_DSP);
+	rpc.hdr.src = AUDIO_ADDR(ac->session, 0, AUDIO_DOMAIN_APP);
+	rpc.hdr.context = ac->session;
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_DATA_TX;
+	rpc.buffer.addr = ab->phys;
+	rpc.buffer.max_size = ab->size;
+	rpc.buffer.actual_size = ab->actual_size;
+
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	r = dal_call(ac->client, AUDIO_OP_DATA, 5, &rpc, sizeof(rpc),
+		     &res, sizeof(res));
+	return 0;
+}
+
+int q6audio_write(struct audio_client *ac, struct audio_buffer *ab)
+{
+	struct adsp_buffer_command rpc;
+	uint32_t res;
+	int r;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.size = sizeof(rpc) - sizeof(u32);
+	rpc.hdr.dst = AUDIO_ADDR(ac->session, 0, AUDIO_DOMAIN_DSP);
+	rpc.hdr.src = AUDIO_ADDR(ac->session, 0, AUDIO_DOMAIN_APP);
+	rpc.hdr.context = ac->session;
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_DATA_RX;
+	rpc.buffer.addr = ab->phys;
+	rpc.buffer.max_size = ab->size;
+	rpc.buffer.actual_size = ab->actual_size;
+
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	r = dal_call(ac->client, AUDIO_OP_DATA, 5, &rpc, sizeof(rpc),
+		     &res, sizeof(res));
+	return 0;
+}
+
+static int audio_rx_volume(struct audio_client *ac, uint32_t dev_id, int32_t volume)
+{
+	struct adsp_set_dev_volume_command rpc;
+
+	pr_debug("[%s:%s] volume = %d\n", __MM_FILE__, __func__, volume);
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_VOL;
+	rpc.device_id = dev_id;
+	rpc.path = ADSP_PATH_RX;
+	rpc.volume = volume;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_rx_mute(struct audio_client *ac, uint32_t dev_id, int mute)
+{
+	struct adsp_set_dev_mute_command rpc;
+
+	pr_debug("[%s:%s] mute = %d, dev_id = 0x%x\n", __MM_FILE__,
+			__func__, mute, dev_id);
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_MUTE;
+	rpc.device_id = dev_id;
+	rpc.path = ADSP_PATH_RX;
+	rpc.mute = !!mute;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_tx_mute(struct audio_client *ac, uint32_t dev_id, int mute)
+{
+	struct adsp_set_dev_mute_command rpc;
+
+	pr_debug("[%s:%s] mute = %d\n", __MM_FILE__, __func__, mute);
+	if (mute < 0  ||  mute > 3) {
+		pr_err("[%s:%s] invalid mute status %d\n", __MM_FILE__,
+				__func__, mute);
+		return -EINVAL;
+	}
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_MUTE;
+	if ((mute == STREAM_UNMUTE) || (mute == STREAM_MUTE)) {
+		rpc.device_id = ADSP_AUDIO_DEVICE_ID_VOICE;
+		rpc.path = ADSP_PATH_TX_CNG_DIS;
+	} else {
+		rpc.device_id = dev_id;
+		rpc.path = ADSP_PATH_TX;
+	}
+	mute &= 0x01;
+	rpc.mute = !!mute;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int audio_stream_volume(struct audio_client *ac, int volume)
+{
+	struct adsp_set_volume_command rpc;
+	int rc;
+
+	pr_debug("[%s:%s] volume = %d\n", __MM_FILE__, __func__, volume);
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_SET_STREAM_VOL;
+	rpc.volume = volume;
+	rc = audio_ioctl(ac, &rpc, sizeof(rpc));
+	return rc;
+}
+
+static int audio_stream_mute(struct audio_client *ac, int mute)
+{
+	struct adsp_set_mute_command rpc;
+	int rc;
+
+	pr_debug("[%s:%s] mute = %d\n", __MM_FILE__, __func__, mute);
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_SET_STREAM_MUTE;
+	rpc.mute = mute;
+	rc = audio_ioctl(ac, &rpc, sizeof(rpc));
+	return rc;
+}
+
+static void callback(void *data, int len, void *cookie)
+{
+	struct adsp_event_hdr *e = data;
+	struct audio_client *ac;
+	struct adsp_buffer_event *abe = data;
+
+	if (e->context >= SESSION_MAX) {
+		pr_err("[%s:%s] bogus session %d\n", __MM_FILE__, __func__,
+				e->context);
+		return;
+	}
+	ac = session[e->context];
+	if (!ac) {
+		pr_err("[%s:%s] unknown session %d\n", __MM_FILE__, __func__,
+				e->context);
+		return;
+	}
+
+	if (e->event_id == ADSP_AUDIO_IOCTL_CMD_STREAM_EOS) {
+		pr_debug("[%s:%s] CB Stream eos, ac = %p\n",
+			__MM_FILE__, __func__, ac);
+		if (e->status)
+			pr_err("[%s:%s] playback status %d\n", __MM_FILE__,
+					__func__, e->status);
+		if (ac->cb_status == -EBUSY) {
+			ac->cb_status = e->status;
+			wake_up(&ac->wait);
+		}
+		return;
+	}
+
+	if (e->event_id == ADSP_AUDIO_EVT_STATUS_BUF_DONE) {
+		pr_debug("[%s:%s] CB done, ac = %p, status = %d\n",
+				__MM_FILE__, __func__, ac, e->status);
+		if (e->status)
+			pr_err("[%s:%s] buffer status %d\n", __MM_FILE__,
+					__func__, e->status);
+
+		ac->buf[ac->dsp_buf].actual_size = abe->buffer.actual_size;
+		ac->buf[ac->dsp_buf].used = 0;
+		ac->dsp_buf ^= 1;
+		wake_up(&ac->wait);
+		return;
+	}
+
+	pr_debug("[%s:%s] ac = %p, event_id = 0x%x, status = %d\n",
+			__MM_FILE__, __func__, ac, e->event_id, e->status);
+	if (e->status)
+		pr_warning("audio_cb: s=%d e=%08x status=%d\n",
+			   e->context, e->event_id, e->status);
+	if (ac->cb_status == -EBUSY) {
+		ac->cb_status = e->status;
+		wake_up(&ac->wait);
+	}
+}
+
+static void audio_init(struct dal_client *client)
+{
+	u32 tmp[3];
+
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	tmp[0] = 2 * sizeof(u32);
+	tmp[1] = 0;
+	tmp[2] = 0;
+	dal_call(client, AUDIO_OP_INIT, 5, tmp, sizeof(tmp),
+		 tmp, sizeof(u32));
+}
+
+static struct audio_client *ac_control;
+
+static int q6audio_init(void)
+{
+	struct audio_client *ac = 0;
+	int res;
+
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	mutex_lock(&audio_lock);
+	if (ac_control) {
+		res = 0;
+		goto done;
+	}
+
+	pr_info("[%s:%s] codecs\n", __MM_FILE__, __func__);
+	icodec_rx_clk = clk_get(0, "icodec_rx_clk");
+	icodec_tx_clk = clk_get(0, "icodec_tx_clk");
+	ecodec_clk = clk_get(0, "ecodec_clk");
+	sdac_clk = clk_get(0, "sdac_clk");
+	audio_phys = pmem_kalloc(4096, PMEM_MEMTYPE_EBI1|PMEM_ALIGNMENT_4K);
+	audio_data = ioremap(audio_phys, 4096);
+
+	pr_info("[%s:%s] attach ADSP\n", __MM_FILE__, __func__);
+	adsp = dal_attach(AUDIO_DAL_DEVICE, AUDIO_DAL_PORT, 1,
+			  callback, 0);
+	if (!adsp) {
+		pr_err("[%s:%s] cannot attach to adsp\n", __MM_FILE__,
+				__func__);
+		res = -ENODEV;
+		goto done;
+	}
+	pr_info("[%s:%s] INIT\n", __MM_FILE__, __func__);
+	audio_init(adsp);
+	dal_trace(adsp);
+
+	ac = audio_client_alloc(0);
+	if (!ac) {
+		pr_err("[%s:%s] cannot allocate client\n",
+				__MM_FILE__, __func__);
+		res = -ENOMEM;
+		goto done;
+	}
+
+	pr_info("[%s:%s] OPEN control\n", __MM_FILE__, __func__);
+	if (audio_open_control(ac)) {
+		pr_err("[%s:%s] cannot open control channel\n",
+				__MM_FILE__, __func__);
+		res = -ENODEV;
+		goto done;
+	}
+
+	pr_info("[%s:%s] attach ACDB\n", __MM_FILE__, __func__);
+	acdb = dal_attach(ACDB_DAL_DEVICE, ACDB_DAL_PORT, 0, 0, 0);
+	if (!acdb) {
+		pr_err("[%s:%s] cannot attach to acdb channel\n",
+				__MM_FILE__, __func__);
+		res = -ENODEV;
+		goto done;
+	}
+
+	pr_info("[%s:%s] attach ADIE\n", __MM_FILE__, __func__);
+	adie = dal_attach(ADIE_DAL_DEVICE, ADIE_DAL_PORT, 0, 0, 0);
+	if (!adie) {
+		pr_err("[%s:%s] cannot attach to adie\n",
+				__MM_FILE__, __func__);
+		res = -ENODEV;
+		goto done;
+	}
+	if (analog_ops->init)
+		analog_ops->init();
+
+	res = 0;
+	ac_control = ac;
+
+	wake_lock_init(&idlelock, WAKE_LOCK_IDLE, "audio_pcm_idle");
+	wake_lock_init(&wakelock, WAKE_LOCK_SUSPEND, "audio_pcm_suspend");
+done:
+	if ((res < 0) && ac)
+		audio_client_free(ac);
+	mutex_unlock(&audio_lock);
+
+	pr_debug("[%s:%s] res = %d\n", __MM_FILE__, __func__, res);
+	return res;
+}
+
+struct audio_config_data {
+	uint32_t device_id;
+	uint32_t sample_rate;
+	uint32_t offset;
+	uint32_t length;
+};
+
+struct audio_config_database {
+	uint8_t magic[8];
+	uint32_t entry_count;
+	uint32_t unused;
+	struct audio_config_data entry[0];
+};
+
+void *acdb_data;
+const struct firmware *acdb_fw;
+extern struct miscdevice q6_control_device;
+
+static int acdb_get_config_table(uint32_t device_id, uint32_t sample_rate)
+{
+	struct acdb_cmd_device_table rpc;
+	struct acdb_result res;
+	int r;
+
+	pr_debug("[%s:%s] device_id = 0x%x, samplerate = %d\n", __MM_FILE__,
+		__func__, device_id, sample_rate);
+	if (q6audio_init())
+		return 0;
+
+	memset(audio_data, 0, 4096);
+	memset(&rpc, 0, sizeof(rpc));
+
+	rpc.size = sizeof(rpc) - (2 * sizeof(uint32_t));
+	rpc.command_id = ACDB_GET_DEVICE_TABLE;
+	rpc.device_id = device_id;
+	rpc.sample_rate_id = sample_rate;
+	rpc.total_bytes = 4096;
+	rpc.unmapped_buf = audio_phys;
+	rpc.res_size = sizeof(res) - (2 * sizeof(uint32_t));
+
+	r = dal_call(acdb, ACDB_OP_IOCTL, 8, &rpc, sizeof(rpc),
+		&res, sizeof(res));
+
+	if ((r == sizeof(res)) && (res.dal_status == 0))
+		return res.used_bytes;
+
+	return -EIO;
+}
+
+static uint32_t audio_rx_path_id = ADIE_PATH_HANDSET_RX;
+static uint32_t audio_rx_device_id = ADSP_AUDIO_DEVICE_ID_HANDSET_SPKR;
+static uint32_t audio_rx_device_group = -1;
+static uint32_t audio_tx_path_id = ADIE_PATH_HANDSET_TX;
+static uint32_t audio_tx_device_id = ADSP_AUDIO_DEVICE_ID_HANDSET_MIC;
+static uint32_t audio_tx_device_group = -1;
+
+static int qdsp6_devchg_notify(struct audio_client *ac,
+			       uint32_t dev_type, uint32_t dev_id)
+{
+	struct adsp_device_switch_command rpc;
+
+	if (dev_type != ADSP_AUDIO_RX_DEVICE &&
+	    dev_type != ADSP_AUDIO_TX_DEVICE)
+		return -EINVAL;
+
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_PREPARE;
+	if (dev_type == ADSP_AUDIO_RX_DEVICE) {
+		rpc.old_device = audio_rx_device_id;
+		rpc.new_device = dev_id;
+	} else {
+		rpc.old_device = audio_tx_device_id;
+		rpc.new_device = dev_id;
+	}
+	rpc.device_class = 0;
+	rpc.device_type = dev_type;
+	pr_debug("[%s:%s] dev_id = 0x%x\n", __MM_FILE__, __func__, dev_id);
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+static int qdsp6_standby(struct audio_client *ac)
+{
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	return audio_command(ac, ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_STANDBY);
+}
+
+static int qdsp6_start(struct audio_client *ac)
+{
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	return audio_command(ac, ADSP_AUDIO_IOCTL_CMD_DEVICE_SWITCH_COMMIT);
+}
+
+static void audio_rx_analog_enable(int en)
+{
+	pr_debug("[%s:%s] audio_rx_device_id = 0x%x, en = %d\n", __MM_FILE__,
+		__func__, audio_rx_device_id, en);
+	switch (audio_rx_device_id) {
+	case ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_MONO:
+	case ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_STEREO:
+	case ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_SPKR:
+		if (analog_ops->headset_enable)
+			analog_ops->headset_enable(en);
+		break;
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_MONO_HEADSET:
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_STEREO_HEADSET:
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_MONO_HEADSET:
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_STEREO_HEADSET:
+		if (analog_ops->headset_enable)
+			analog_ops->headset_enable(en);
+		if (analog_ops->speaker_enable)
+			analog_ops->speaker_enable(en);
+		break;
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO:
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO:
+		if (analog_ops->speaker_enable)
+			analog_ops->speaker_enable(en);
+		break;
+	case ADSP_AUDIO_DEVICE_ID_BT_SCO_SPKR:
+		if (analog_ops->bt_sco_enable)
+			analog_ops->bt_sco_enable(en);
+		break;
+	case ADSP_AUDIO_DEVICE_ID_HANDSET_SPKR:
+		if (analog_ops->receiver_enable)
+			analog_ops->receiver_enable(en);
+		break;
+	}
+}
+
+static void audio_tx_analog_enable(int en)
+{
+	pr_debug("[%s:%s] audio_tx_device_id = 0x%x, en = %d\n", __MM_FILE__,
+		__func__, audio_tx_device_id, en);
+	switch (audio_tx_device_id) {
+	case ADSP_AUDIO_DEVICE_ID_HANDSET_MIC:
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MIC:
+		if (analog_ops->int_mic_enable)
+			analog_ops->int_mic_enable(en);
+		break;
+	case ADSP_AUDIO_DEVICE_ID_HEADSET_MIC:
+	case ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_MIC:
+	case ADSP_AUDIO_DEVICE_ID_HANDSET_DUAL_MIC:
+	case ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_DUAL_MIC:
+		if (analog_ops->ext_mic_enable)
+			analog_ops->ext_mic_enable(en);
+		break;
+	case ADSP_AUDIO_DEVICE_ID_BT_SCO_MIC:
+		if (analog_ops->bt_sco_enable)
+			analog_ops->bt_sco_enable(en);
+		break;
+	}
+}
+
+static int audio_update_acdb(uint32_t adev, uint32_t acdb_id)
+{
+	uint32_t sample_rate;
+	int sz;
+
+	pr_debug("[%s:%s] adev = 0x%x, acdb_id = 0x%x\n", __MM_FILE__,
+		__func__, adev, acdb_id);
+	if (q6_device_to_dir(adev) == Q6_RX) {
+		rx_acdb = acdb_id;
+		sample_rate = q6_device_to_rate(adev);
+	} else {
+
+		tx_acdb = acdb_id;
+		if (tx_clk_freq > 16000)
+			sample_rate = 48000;
+		else if (tx_clk_freq > 8000)
+			sample_rate = 16000;
+		else
+			sample_rate = 8000;
+	}
+
+	if (acdb_id == 0)
+		acdb_id = q6_device_to_cad_id(adev);
+
+	sz = acdb_get_config_table(acdb_id, sample_rate);
+	audio_set_table(ac_control, adev, sz);
+
+	return 0;
+}
+
+static void adie_rx_path_enable(uint32_t acdb_id)
+{
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	if (audio_rx_path_id) {
+		adie_enable();
+		adie_set_path(adie, audio_rx_path_id, ADIE_PATH_RX);
+		adie_set_path_freq_plan(adie, ADIE_PATH_RX, 48000);
+
+		adie_proceed_to_stage(adie, ADIE_PATH_RX,
+				ADIE_STAGE_DIGITAL_READY);
+		adie_proceed_to_stage(adie, ADIE_PATH_RX,
+				ADIE_STAGE_DIGITAL_ANALOG_READY);
+	}
+}
+
+static void q6_rx_path_enable(int reconf, uint32_t acdb_id)
+{
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	if (!reconf)
+		qdsp6_devchg_notify(ac_control, ADSP_AUDIO_RX_DEVICE, audio_rx_device_id);
+	audio_update_acdb(audio_rx_device_id, acdb_id);
+	qdsp6_standby(ac_control);
+	qdsp6_start(ac_control);
+}
+
+static void _audio_rx_path_enable(int reconf, uint32_t acdb_id)
+{
+	pr_debug("[%s:%s] reconf = %d\n", __MM_FILE__, __func__, reconf);
+	q6_rx_path_enable(reconf, acdb_id);
+	if (audio_rx_path_id)
+		adie_rx_path_enable(acdb_id);
+	audio_rx_analog_enable(1);
+}
+
+static void _audio_tx_path_enable(int reconf, uint32_t acdb_id)
+{
+	pr_debug("[%s:%s] reconf = %d, tx_clk_freq = %d\n", __MM_FILE__,
+			__func__, reconf, tx_clk_freq);
+	audio_tx_analog_enable(1);
+
+	if (audio_tx_path_id) {
+		adie_enable();
+		adie_set_path(adie, audio_tx_path_id, ADIE_PATH_TX);
+
+		if (tx_clk_freq > 16000)
+			adie_set_path_freq_plan(adie, ADIE_PATH_TX, 48000);
+		else if (tx_clk_freq > 8000)
+			adie_set_path_freq_plan(adie, ADIE_PATH_TX, 16000);
+		else
+			adie_set_path_freq_plan(adie, ADIE_PATH_TX, 8000);
+
+		adie_proceed_to_stage(adie, ADIE_PATH_TX,
+				ADIE_STAGE_DIGITAL_READY);
+		adie_proceed_to_stage(adie, ADIE_PATH_TX,
+				ADIE_STAGE_DIGITAL_ANALOG_READY);
+	}
+
+
+	if (!reconf)
+		qdsp6_devchg_notify(ac_control, ADSP_AUDIO_TX_DEVICE,
+				audio_tx_device_id);
+	audio_update_acdb(audio_tx_device_id, acdb_id);
+	qdsp6_standby(ac_control);
+	qdsp6_start(ac_control);
+
+	audio_tx_mute(ac_control, audio_tx_device_id, tx_mute_status);
+}
+
+static void _audio_rx_path_disable(void)
+{
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	audio_rx_analog_enable(0);
+
+	if (audio_rx_path_id) {
+		adie_proceed_to_stage(adie, ADIE_PATH_RX,
+				ADIE_STAGE_ANALOG_OFF);
+		adie_proceed_to_stage(adie, ADIE_PATH_RX,
+				ADIE_STAGE_DIGITAL_OFF);
+		adie_disable();
+	}
+}
+
+static void _audio_tx_path_disable(void)
+{
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	audio_tx_analog_enable(0);
+
+	if (audio_tx_path_id) {
+		adie_proceed_to_stage(adie, ADIE_PATH_TX,
+				ADIE_STAGE_ANALOG_OFF);
+		adie_proceed_to_stage(adie, ADIE_PATH_TX,
+				ADIE_STAGE_DIGITAL_OFF);
+		adie_disable();
+	}
+}
+
+static int icodec_rx_clk_refcount;
+static int icodec_tx_clk_refcount;
+static int ecodec_clk_refcount;
+static int sdac_clk_refcount;
+
+static void ecodec_clk_enable(void)
+{
+	ecodec_clk_refcount++;
+	if (ecodec_clk_refcount == 1) {
+		clk_set_rate(ecodec_clk, 2048000);
+		clk_enable(ecodec_clk);
+	}
+}
+static void ecodec_clk_disable(int group_reset, int path)
+{
+	ecodec_clk_refcount--;
+	if (ecodec_clk_refcount == 0) {
+		clk_disable(ecodec_clk);
+		if (group_reset) {
+			if (path == ADSP_PATH_TX)
+				audio_tx_device_group = -1;
+			else
+				audio_rx_device_group = -1;
+		}
+	}
+}
+static void _audio_rx_clk_enable(void)
+{
+	uint32_t device_group = q6_device_to_codec(audio_rx_device_id);
+
+	pr_debug("[%s:%s] rx_clk_refcount = %d\n", __MM_FILE__, __func__,
+		icodec_rx_clk_refcount);
+	switch(device_group) {
+	case Q6_ICODEC_RX:
+		icodec_rx_clk_refcount++;
+		if (icodec_rx_clk_refcount == 1) {
+			clk_set_rate(icodec_rx_clk, 12288000);
+			clk_enable(icodec_rx_clk);
+		}
+		break;
+	case Q6_ECODEC_RX:
+		ecodec_clk_enable();
+		break;
+	case Q6_SDAC_RX:
+		sdac_clk_refcount++;
+		if (sdac_clk_refcount == 1) {
+			clk_set_rate(sdac_clk, 12288000);
+			clk_enable(sdac_clk);
+		}
+		break;
+	default:
+		return;
+	}
+	audio_rx_device_group = device_group;
+}
+
+static void _audio_tx_clk_enable(void)
+{
+	uint32_t device_group = q6_device_to_codec(audio_tx_device_id);
+	uint32_t icodec_tx_clk_rate;
+
+	pr_debug("[%s:%s] tx_clk_refcount = %d\n", __MM_FILE__, __func__,
+		icodec_tx_clk_refcount);
+	switch (device_group) {
+	case Q6_ICODEC_TX:
+		icodec_tx_clk_refcount++;
+		if (icodec_tx_clk_refcount == 1) {
+			if (tx_clk_freq > 16000)
+				icodec_tx_clk_rate = 48000;
+			else if (tx_clk_freq > 8000)
+				icodec_tx_clk_rate = 16000;
+			else
+				icodec_tx_clk_rate = 8000;
+
+			clk_set_rate(icodec_tx_clk, icodec_tx_clk_rate * 256);
+			clk_enable(icodec_tx_clk);
+		}
+		break;
+	case Q6_ECODEC_TX:
+		ecodec_clk_enable();
+		break;
+	case Q6_SDAC_TX:
+		/* TODO: In QCT BSP, clk rate was set to 20480000 */
+		sdac_clk_refcount++;
+		if (sdac_clk_refcount == 1) {
+			clk_set_rate(sdac_clk, 12288000);
+			clk_enable(sdac_clk);
+		}
+		break;
+	default:
+		return;
+	}
+	audio_tx_device_group = device_group;
+}
+
+static void _audio_rx_clk_disable(void)
+{
+	pr_debug("[%s:%s] rx_clk_refcount = %d\n", __MM_FILE__, __func__,
+		icodec_rx_clk_refcount);
+	switch (audio_rx_device_group) {
+	case Q6_ICODEC_RX:
+		icodec_rx_clk_refcount--;
+		if (icodec_rx_clk_refcount == 0) {
+			clk_disable(icodec_rx_clk);
+			audio_rx_device_group = -1;
+		}
+		break;
+	case Q6_ECODEC_RX:
+		ecodec_clk_disable(1, ADSP_PATH_RX);
+		break;
+	case Q6_SDAC_RX:
+		sdac_clk_refcount--;
+		if (sdac_clk_refcount == 0) {
+			clk_disable(sdac_clk);
+			audio_rx_device_group = -1;
+		}
+		break;
+	default:
+		pr_err("[%s:%s] invalid rx device group %d\n", __MM_FILE__,
+				__func__, audio_rx_device_group);
+		break;
+	}
+}
+
+static void _audio_tx_clk_disable(void)
+{
+	pr_debug("[%s:%s] tx_clk_refcount = %d\n", __MM_FILE__, __func__,
+		icodec_tx_clk_refcount);
+	switch (audio_tx_device_group) {
+	case Q6_ICODEC_TX:
+		icodec_tx_clk_refcount--;
+		if (icodec_tx_clk_refcount == 0) {
+			clk_disable(icodec_tx_clk);
+			audio_tx_device_group = -1;
+		}
+		break;
+	case Q6_ECODEC_TX:
+		ecodec_clk_disable(1, ADSP_PATH_TX);
+		break;
+	case Q6_SDAC_TX:
+		sdac_clk_refcount--;
+		if (sdac_clk_refcount == 0) {
+			clk_disable(sdac_clk);
+			audio_tx_device_group = -1;
+		}
+		break;
+	default:
+		pr_err("[%s:%s] invalid tx device group %d\n",
+			__MM_FILE__, __func__, audio_tx_device_group);
+		break;
+	}
+}
+
+static void _audio_rx_clk_reinit(uint32_t rx_device, uint32_t acdb_id)
+{
+	uint32_t device_group = q6_device_to_codec(rx_device);
+
+	pr_debug("[%s:%s] rx_device = 0x%x\n", __MM_FILE__, __func__,
+		rx_device);
+	if (device_group != audio_rx_device_group)
+		_audio_rx_clk_disable();
+
+	audio_rx_device_id = rx_device;
+	audio_rx_path_id = q6_device_to_path(rx_device, acdb_id);
+
+	if (device_group != audio_rx_device_group)
+		_audio_rx_clk_enable();
+
+}
+
+static void _audio_tx_clk_reinit(uint32_t tx_device, uint32_t acdb_id)
+{
+	uint32_t device_group = q6_device_to_codec(tx_device);
+
+	pr_debug("[%s:%s] tx_device = 0x%x\n", __MM_FILE__, __func__,
+		tx_device);
+	if (device_group != audio_tx_device_group)
+		_audio_tx_clk_disable();
+
+	audio_tx_device_id = tx_device;
+	audio_tx_path_id = q6_device_to_path(tx_device, acdb_id);
+
+	if (device_group != audio_tx_device_group)
+		_audio_tx_clk_enable();
+}
+
+static DEFINE_MUTEX(audio_path_lock);
+static int audio_rx_path_refcount;
+static int audio_tx_path_refcount;
+
+static int audio_rx_path_enable(int en, uint32_t acdb_id)
+{
+	pr_debug("[%s:%s] en = %d\n", __MM_FILE__, __func__, en);
+	mutex_lock(&audio_path_lock);
+	if (en) {
+		audio_rx_path_refcount++;
+		if (audio_rx_path_refcount == 1) {
+			_audio_rx_clk_enable();
+			_audio_rx_path_enable(0, acdb_id);
+		}
+	} else {
+		audio_rx_path_refcount--;
+		if (audio_rx_path_refcount == 0) {
+			_audio_rx_path_disable();
+			_audio_rx_clk_disable();
+		}
+	}
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+static int audio_tx_path_enable(int en, uint32_t acdb_id)
+{
+	pr_debug("[%s:%s] en = %d\n", __MM_FILE__, __func__, en);
+	mutex_lock(&audio_path_lock);
+	if (en) {
+		audio_tx_path_refcount++;
+		if (audio_tx_path_refcount == 1) {
+			_audio_tx_clk_enable();
+			_audio_tx_path_enable(0, acdb_id);
+		}
+	} else {
+		audio_tx_path_refcount--;
+		if (audio_tx_path_refcount == 0) {
+			_audio_tx_path_disable();
+			_audio_tx_clk_disable();
+		}
+	}
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+int q6audio_update_acdb(uint32_t id_src, uint32_t id_dst)
+{
+	int res;
+
+	pr_debug("[%s:%s] id_src = 0x%x\n, id_dst = 0x%x\n", __MM_FILE__,
+		__func__, id_src, id_dst);
+	if (q6audio_init())
+		return 0;
+
+	mutex_lock(&audio_path_lock);
+
+	if (q6_device_to_dir(id_dst) == Q6_RX)
+		qdsp6_devchg_notify(ac_control, ADSP_AUDIO_RX_DEVICE, id_dst);
+	else
+		qdsp6_devchg_notify(ac_control, ADSP_AUDIO_TX_DEVICE, id_dst);
+	res = audio_update_acdb(id_dst, id_src);
+	if (res)
+		goto done;
+
+	qdsp6_standby(ac_control);
+	qdsp6_start(ac_control);
+done:
+	mutex_unlock(&audio_path_lock);
+	return res;
+}
+
+int q6audio_set_tx_mute(int mute)
+{
+	uint32_t adev;
+	int rc;
+
+	if (q6audio_init())
+		return 0;
+
+	mutex_lock(&audio_path_lock);
+
+	if (mute == tx_mute_status) {
+		mutex_unlock(&audio_path_lock);
+		return 0;
+	}
+
+	adev = audio_tx_device_id;
+	rc = audio_tx_mute(ac_control, adev, mute);
+
+	/* DSP caches the requested MUTE state when it cannot apply the state
+	  immediately. In that case, it returns EUNSUPPORTED and applies the
+	  cached state later */
+	if ((rc == ADSP_AUDIO_STATUS_SUCCESS) ||
+			(rc == ADSP_AUDIO_STATUS_EUNSUPPORTED)) {
+		pr_debug("[%s:%s] return status = %d\n",
+			__MM_FILE__, __func__, rc);
+		tx_mute_status = mute;
+	}
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+int q6audio_set_stream_volume(struct audio_client *ac, int vol)
+{
+	if (vol > 1200 || vol < -4000) {
+		pr_err("[%s:%s] unsupported volume level %d\n", __MM_FILE__,
+				__func__, vol);
+		return -EINVAL;
+	}
+	mutex_lock(&audio_path_lock);
+	audio_stream_mute(ac, 0);
+	audio_stream_volume(ac, vol);
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+int q6audio_set_rx_volume(int level)
+{
+	uint32_t adev;
+	int vol;
+
+	pr_debug("[%s:%s] level = %d\n", __MM_FILE__, __func__, level);
+	if (q6audio_init())
+		return 0;
+
+	if (level < 0 || level > 100)
+		return -EINVAL;
+
+	mutex_lock(&audio_path_lock);
+	adev = ADSP_AUDIO_DEVICE_ID_VOICE;
+
+	if (level) {
+		vol = q6_device_volume(audio_rx_device_id, level);
+		audio_rx_mute(ac_control, adev, 0);
+		audio_rx_volume(ac_control, adev, vol);
+	} else
+		audio_rx_mute(ac_control, adev, 1);
+
+	rx_vol_level = level;
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+static void do_rx_routing(uint32_t device_id, uint32_t acdb_id)
+{
+	pr_debug("[%s:%s] device_id = 0x%x, acdb_id = 0x%x\n", __MM_FILE__,
+		__func__, device_id, acdb_id);
+	if (device_id == audio_rx_device_id &&
+		audio_rx_path_id == q6_device_to_path(device_id, acdb_id)) {
+		if (acdb_id != rx_acdb) {
+			qdsp6_devchg_notify(ac_control, ADSP_AUDIO_RX_DEVICE, device_id);
+			audio_update_acdb(device_id, acdb_id);
+			qdsp6_standby(ac_control);
+			qdsp6_start(ac_control);
+		}
+		return;
+	}
+
+	if (audio_rx_path_refcount > 0) {
+		qdsp6_devchg_notify(ac_control, ADSP_AUDIO_RX_DEVICE, device_id);
+		_audio_rx_path_disable();
+		_audio_rx_clk_reinit(device_id, acdb_id);
+		_audio_rx_path_enable(1, acdb_id);
+	} else {
+		qdsp6_devchg_notify(ac_control, ADSP_AUDIO_RX_DEVICE,
+					 device_id);
+		audio_update_acdb(device_id, acdb_id);
+		qdsp6_standby(ac_control);
+		qdsp6_start(ac_control);
+		audio_rx_device_id = device_id;
+		audio_rx_path_id = q6_device_to_path(device_id, acdb_id);
+	}
+}
+
+static void do_tx_routing(uint32_t device_id, uint32_t acdb_id)
+{
+	pr_debug("[%s:%s] device_id = 0x%x, acdb_id = 0x%x\n", __MM_FILE__,
+		__func__, device_id, acdb_id);
+	if (device_id == audio_tx_device_id &&
+		audio_tx_path_id == q6_device_to_path(device_id, acdb_id)) {
+		if (acdb_id != tx_acdb) {
+			qdsp6_devchg_notify(ac_control, ADSP_AUDIO_TX_DEVICE,
+						 device_id);
+			audio_update_acdb(device_id, acdb_id);
+			qdsp6_standby(ac_control);
+			qdsp6_start(ac_control);
+		}
+		return;
+	}
+
+	if (audio_tx_path_refcount > 0) {
+		qdsp6_devchg_notify(ac_control, ADSP_AUDIO_TX_DEVICE, device_id);
+		_audio_tx_path_disable();
+		_audio_tx_clk_reinit(device_id, acdb_id);
+		_audio_tx_path_enable(1, acdb_id);
+	} else {
+		qdsp6_devchg_notify(ac_control, ADSP_AUDIO_TX_DEVICE,
+					 device_id);
+		audio_update_acdb(device_id, acdb_id);
+		qdsp6_standby(ac_control);
+		qdsp6_start(ac_control);
+		audio_tx_device_id = device_id;
+		audio_tx_path_id = q6_device_to_path(device_id, acdb_id);
+		tx_acdb = acdb_id;
+	}
+}
+
+int q6audio_do_routing(uint32_t device_id, uint32_t acdb_id)
+{
+	if (q6audio_init())
+		return 0;
+
+	mutex_lock(&audio_path_lock);
+
+	switch(q6_device_to_dir(device_id)) {
+	case Q6_RX:
+		do_rx_routing(device_id, acdb_id);
+		break;
+	case Q6_TX:
+		do_tx_routing(device_id, acdb_id);
+		break;
+	}
+
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+int q6audio_set_route(const char *name)
+{
+	uint32_t route;
+	if (!strcmp(name, "speaker")) {
+		route = ADIE_PATH_SPEAKER_STEREO_RX;
+	} else if (!strcmp(name, "headphones")) {
+		route = ADIE_PATH_HEADSET_STEREO_RX;
+	} else if (!strcmp(name, "handset")) {
+		route = ADIE_PATH_HANDSET_RX;
+	} else {
+		return -EINVAL;
+	}
+
+	mutex_lock(&audio_path_lock);
+	if (route == audio_rx_path_id)
+		goto done;
+
+	audio_rx_path_id = route;
+
+	if (audio_rx_path_refcount > 0) {
+		_audio_rx_path_disable();
+		_audio_rx_path_enable(1, 0);
+	}
+	if (audio_tx_path_refcount > 0) {
+		_audio_tx_path_disable();
+		_audio_tx_path_enable(1, 0);
+	}
+done:
+	mutex_unlock(&audio_path_lock);
+	return 0;
+}
+
+static int audio_stream_equalizer(struct audio_client *ac, void *eq_config)
+{
+	int i;
+	struct adsp_set_equalizer_command rpc;
+	struct adsp_audio_eq_stream_config *eq_cfg;
+	eq_cfg = (struct adsp_audio_eq_stream_config *) eq_config;
+
+	memset(&rpc, 0, sizeof(rpc));
+
+	rpc.hdr.opcode = ADSP_AUDIO_IOCTL_SET_SESSION_EQ_CONFIG;
+	rpc.enable = eq_cfg->enable;
+	rpc.num_bands = eq_cfg->num_bands;
+	for (i = 0; i < eq_cfg->num_bands; i++) {
+		rpc.eq_bands[i].band_idx = eq_cfg->eq_bands[i].band_idx;
+		rpc.eq_bands[i].filter_type = eq_cfg->eq_bands[i].filter_type;
+		rpc.eq_bands[i].center_freq_hz =
+					eq_cfg->eq_bands[i].center_freq_hz;
+		rpc.eq_bands[i].filter_gain = eq_cfg->eq_bands[i].filter_gain;
+		rpc.eq_bands[i].q_factor = eq_cfg->eq_bands[i].q_factor;
+	}
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
+
+int q6audio_set_stream_eq_pcm(struct audio_client *ac, void *eq_config)
+{
+	int rc = 0;
+	mutex_lock(&audio_path_lock);
+	rc = audio_stream_equalizer(ac, eq_config);
+	mutex_unlock(&audio_path_lock);
+	return rc;
+}
+
+struct audio_client *q6audio_open_auxpcm(uint32_t rate,
+				      uint32_t channels, uint32_t flags, uint32_t acdb_id)
+{
+	int rc, retry = 5;
+	struct audio_client *ac;
+
+	pr_debug("[%s:%s] rate = %d, channels = %d\n", __MM_FILE__, __func__,
+		rate, channels);
+	if (q6audio_init())
+		return NULL;
+	ac = audio_client_alloc(0);
+	if (!ac)
+		return NULL;
+
+	ac->flags = flags;
+
+	mutex_lock(&audio_path_lock);
+
+	if (ac->flags & AUDIO_FLAG_WRITE) {
+		audio_tx_path_refcount++;
+		if (audio_tx_path_refcount == 1) {
+			tx_clk_freq = rate;
+			_audio_tx_clk_enable();
+			_audio_tx_path_enable(0, acdb_id);
+		}
+	} else {
+		audio_rx_path_refcount++;
+		if (audio_rx_path_refcount == 1) {
+			_audio_rx_clk_enable();
+			_audio_rx_path_enable(0, acdb_id);
+		}
+	}
+
+	ecodec_clk_enable();
+
+	for (retry = 5;; retry--) {
+		if (ac->flags & AUDIO_FLAG_WRITE)
+			rc = audio_auxpcm_out_open(ac, rate, channels);
+		else
+			rc = audio_auxpcm_in_open(ac, rate, channels);
+		if (rc == 0)
+			break;
+		if (retry == 0)
+			q6audio_dsp_not_responding();
+
+		pr_err("[%s:%s] open pcm error %d, retrying\n",
+			__MM_FILE__, __func__, rc);
+		msleep(1);
+	}
+
+	mutex_unlock(&audio_path_lock);
+
+	for (retry = 5;; retry--) {
+		rc = audio_command(ac, ADSP_AUDIO_IOCTL_CMD_SESSION_START);
+		if (rc == 0)
+			break;
+		if (retry == 0)
+			q6audio_dsp_not_responding();
+
+		pr_err("[%s:%s] stream start error %d, retrying\n",
+			__MM_FILE__, __func__, rc);
+	}
+	audio_prevent_sleep();
+	return ac;
+
+}
+
+struct audio_client *q6audio_open_pcm(uint32_t bufsz, uint32_t rate,
+		      uint32_t channels, uint32_t flags, uint32_t acdb_id)
+{
+	int rc, retry = 5;
+	struct audio_client *ac;
+
+	pr_debug("[%s:%s] bufsz = %d, rate = %d, channels = %d\n", __MM_FILE__,
+		__func__, bufsz, rate, channels);
+	if (q6audio_init())
+		return 0;
+
+	ac = audio_client_alloc(bufsz);
+	if (!ac)
+		return 0;
+
+	ac->flags = flags;
+
+	mutex_lock(&audio_path_lock);
+
+	if (ac->flags & AUDIO_FLAG_WRITE) {
+		audio_rx_path_refcount++;
+		if (audio_rx_path_refcount == 1) {
+			_audio_rx_clk_enable();
+			q6_rx_path_enable(0, acdb_id);
+			adie_rx_path_enable(acdb_id);
+		}
+	} else {
+		/* TODO: consider concurrency with voice call */
+		audio_tx_path_refcount++;
+		if (audio_tx_path_refcount == 1) {
+			tx_clk_freq = rate;
+			_audio_tx_clk_enable();
+			_audio_tx_path_enable(0, acdb_id);
+		}
+	}
+
+	for (retry = 5;;retry--) {
+		if (ac->flags & AUDIO_FLAG_WRITE)
+			rc = audio_out_open(ac, bufsz, rate, channels);
+		else
+			rc = audio_in_open(ac, bufsz, flags, rate, channels);
+		if (rc == 0)
+			break;
+		if (retry == 0)
+			q6audio_dsp_not_responding();
+
+		pr_err("[%s:%s] open pcm error %d, retrying\n",
+			__MM_FILE__, __func__, rc);
+		msleep(1);
+	}
+
+	if (ac->flags & AUDIO_FLAG_WRITE) {
+		if (audio_rx_path_refcount == 1)
+			audio_rx_analog_enable(1);
+	}
+	mutex_unlock(&audio_path_lock);
+
+	for (retry = 5;;retry--) {
+		rc = audio_command(ac, ADSP_AUDIO_IOCTL_CMD_SESSION_START);
+		if (rc == 0)
+			break;
+		if (retry == 0)
+			q6audio_dsp_not_responding();
+
+		pr_err("[%s:%s] stream start error %d, retrying\n",
+			__MM_FILE__, __func__, rc);
+	}
+
+	if (!(ac->flags & AUDIO_FLAG_WRITE)) {
+		ac->buf[0].used = 1;
+		ac->buf[1].used = 1;
+		q6audio_read(ac, &ac->buf[0]);
+		q6audio_read(ac, &ac->buf[1]);
+	}
+
+	audio_prevent_sleep();
+	return ac;
+}
+
+int q6audio_close(struct audio_client *ac)
+{
+	audio_close(ac);
+	if (ac->flags & AUDIO_FLAG_WRITE)
+		audio_rx_path_enable(0, 0);
+	else
+		audio_tx_path_enable(0, 0);
+	audio_client_free(ac);
+	audio_allow_sleep();
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	return 0;
+}
+
+int q6audio_auxpcm_close(struct audio_client *ac)
+{
+	audio_close(ac);
+	if (ac->flags & AUDIO_FLAG_WRITE) {
+		audio_tx_path_enable(0, 0);
+		ecodec_clk_disable(0, ADSP_PATH_RX);
+	} else {
+		audio_rx_path_enable(0, 0);
+		ecodec_clk_disable(0, ADSP_PATH_TX);
+	}
+
+	audio_client_free(ac);
+	audio_allow_sleep();
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	return 0;
+}
+struct audio_client *q6voice_open(uint32_t flags)
+{
+	struct audio_client *ac;
+
+	pr_debug("[%s:%s] flags = %d\n", __MM_FILE__, __func__, flags);
+	if (q6audio_init())
+		return 0;
+
+	ac = audio_client_alloc(0);
+	if (!ac)
+		return 0;
+
+	ac->flags = flags;
+	if (ac->flags & AUDIO_FLAG_WRITE)
+		audio_rx_path_enable(1, rx_acdb);
+	else {
+		if (!audio_tx_path_refcount)
+			tx_clk_freq = 8000;
+		audio_tx_path_enable(1, tx_acdb);
+	}
+
+	return ac;
+}
+
+int q6voice_close(struct audio_client *ac)
+{
+	if (ac->flags & AUDIO_FLAG_WRITE)
+		audio_rx_path_enable(0, 0);
+	else
+		audio_tx_path_enable(0, 0);
+
+	tx_mute_status = 0;
+	audio_client_free(ac);
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	return 0;
+}
+
+struct audio_client *q6audio_open_mp3(uint32_t bufsz, uint32_t rate,
+				      uint32_t channels, uint32_t acdb_id)
+{
+	struct audio_client *ac;
+
+	pr_debug("[%s:%s] bufsz = %d, rate = %d\n, channels = %d",
+		__MM_FILE__, __func__, bufsz, rate, channels);
+
+	if (q6audio_init())
+		return 0;
+
+	ac = audio_client_alloc(bufsz);
+	if (!ac)
+		return 0;
+
+	ac->flags = AUDIO_FLAG_WRITE;
+	audio_rx_path_enable(1, acdb_id);
+
+	audio_mp3_open(ac, bufsz, rate, channels);
+	audio_command(ac, ADSP_AUDIO_IOCTL_CMD_SESSION_START);
+
+	mutex_lock(&audio_path_lock);
+	audio_rx_mute(ac_control, audio_rx_device_id, 0);
+	audio_rx_volume(ac_control, audio_rx_device_id,
+			q6_device_volume(audio_rx_device_id, rx_vol_level));
+	mutex_unlock(&audio_path_lock);
+	return ac;
+}
+
+struct audio_client *q6audio_open_dtmf(uint32_t rate,
+				      uint32_t channels, uint32_t acdb_id)
+{
+	struct audio_client *ac;
+
+	pr_debug("[%s:%s] rate = %d\n, channels = %d", __MM_FILE__, __func__,
+		 rate, channels);
+	if (q6audio_init())
+		return 0;
+
+	ac = audio_client_alloc(0);
+	if (!ac)
+		return 0;
+
+	ac->flags = AUDIO_FLAG_WRITE;
+	audio_rx_path_enable(1, acdb_id);
+
+	audio_dtmf_open(ac, rate, channels);
+	audio_command(ac, ADSP_AUDIO_IOCTL_CMD_SESSION_START);
+
+	mutex_lock(&audio_path_lock);
+	audio_rx_mute(ac_control, audio_rx_device_id, 0);
+	audio_rx_volume(ac_control, audio_rx_device_id,
+		q6_device_volume(audio_rx_device_id, rx_vol_level));
+	mutex_unlock(&audio_path_lock);
+
+	return ac;
+}
+
+int q6audio_play_dtmf(struct audio_client *ac, uint16_t dtmf_hi,
+			 uint16_t dtmf_low, uint16_t duration, uint16_t rx_gain)
+{
+	struct adsp_audio_dtmf_start_command dtmf_cmd;
+
+	pr_debug("[%s:%s] high = %d, low = %d\n", __MM_FILE__, __func__,
+		dtmf_hi, dtmf_low);
+
+	dtmf_cmd.hdr.opcode = ADSP_AUDIO_IOCTL_CMD_SESSION_DTMF_START;
+	dtmf_cmd.hdr.response_type = ADSP_AUDIO_RESPONSE_COMMAND;
+	dtmf_cmd.tone1_hz = dtmf_hi;
+	dtmf_cmd.tone2_hz = dtmf_low;
+	dtmf_cmd.duration_usec = duration * 1000;
+	dtmf_cmd.gain_mb = rx_gain;
+
+	return audio_ioctl(ac, &dtmf_cmd,
+		 sizeof(struct adsp_audio_dtmf_start_command));
+
+}
+
+int q6audio_mp3_close(struct audio_client *ac)
+{
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	audio_close(ac);
+	audio_rx_path_enable(0, 0);
+	audio_client_free(ac);
+	return 0;
+}
+
+
+struct audio_client *q6audio_open_aac(uint32_t bufsz, uint32_t samplerate,
+					uint32_t channels, uint32_t bitrate,
+					uint32_t stream_format, uint32_t flags,
+					uint32_t acdb_id)
+{
+	struct audio_client *ac;
+
+	pr_debug("[%s:%s] bufsz = %d, samplerate = %d, channels = %d\n",
+		__MM_FILE__, __func__, bufsz, samplerate, channels);
+
+	if (q6audio_init())
+		return 0;
+
+	ac = audio_client_alloc(bufsz);
+	if (!ac)
+		return 0;
+
+	ac->flags = flags;
+
+	if (ac->flags & AUDIO_FLAG_WRITE)
+		audio_rx_path_enable(1, acdb_id);
+	else{
+		if (!audio_tx_path_refcount)
+			tx_clk_freq = 48000;
+		audio_tx_path_enable(1, acdb_id);
+	}
+
+	audio_aac_open(ac, bufsz, samplerate, channels, bitrate, flags,
+							stream_format);
+	audio_command(ac, ADSP_AUDIO_IOCTL_CMD_SESSION_START);
+
+	if (!(ac->flags & AUDIO_FLAG_WRITE)) {
+		ac->buf[0].used = 1;
+		ac->buf[1].used = 1;
+		q6audio_read(ac, &ac->buf[0]);
+		q6audio_read(ac, &ac->buf[1]);
+	}
+	audio_prevent_sleep();
+	return ac;
+}
+
+
+struct audio_client *q6audio_open_qcp(uint32_t bufsz, uint32_t min_rate,
+					uint32_t max_rate, uint32_t flags,
+					uint32_t format, uint32_t acdb_id)
+{
+	struct audio_client *ac;
+
+	pr_debug("[%s:%s] bufsz = %d\n", __MM_FILE__, __func__, bufsz);
+
+	if (q6audio_init())
+		return 0;
+
+	ac = audio_client_alloc(bufsz);
+	if (!ac)
+		return 0;
+
+	ac->flags = flags;
+
+	if (ac->flags & AUDIO_FLAG_WRITE)
+		audio_rx_path_enable(1, acdb_id);
+	else{
+		if (!audio_tx_path_refcount)
+			tx_clk_freq = 8000;
+		audio_tx_path_enable(1, acdb_id);
+	}
+
+	audio_qcp_open(ac, bufsz, min_rate, max_rate, flags, format);
+	audio_command(ac, ADSP_AUDIO_IOCTL_CMD_SESSION_START);
+
+	if (!(ac->flags & AUDIO_FLAG_WRITE)) {
+		ac->buf[0].used = 1;
+		ac->buf[1].used = 1;
+		q6audio_read(ac, &ac->buf[0]);
+		q6audio_read(ac, &ac->buf[1]);
+	}
+	audio_prevent_sleep();
+	return ac;
+}
+
+struct audio_client *q6audio_open_amrnb(uint32_t bufsz, uint32_t enc_mode,
+					uint32_t dtx_mode_enable,
+					uint32_t flags, uint32_t acdb_id)
+{
+	struct audio_client *ac;
+
+	pr_debug("[%s:%s] bufsz = %d, dtx_mode = %d\n", __MM_FILE__,
+			__func__, bufsz, dtx_mode_enable);
+
+	if (q6audio_init())
+		return 0;
+
+	ac = audio_client_alloc(bufsz);
+	if (!ac)
+		return 0;
+
+	ac->flags = flags;
+	if (ac->flags & AUDIO_FLAG_WRITE)
+		audio_rx_path_enable(1, acdb_id);
+	else{
+		if (!audio_tx_path_refcount)
+			tx_clk_freq = 8000;
+		audio_tx_path_enable(1, acdb_id);
+	}
+
+	audio_amrnb_open(ac, bufsz, enc_mode, flags, dtx_mode_enable);
+	audio_command(ac, ADSP_AUDIO_IOCTL_CMD_SESSION_START);
+
+	if (!(ac->flags & AUDIO_FLAG_WRITE)) {
+		ac->buf[0].used = 1;
+		ac->buf[1].used = 1;
+		q6audio_read(ac, &ac->buf[0]);
+		q6audio_read(ac, &ac->buf[1]);
+	}
+	audio_prevent_sleep();
+	return ac;
+}
+
+int q6audio_async(struct audio_client *ac)
+{
+	struct adsp_command_hdr rpc;
+	pr_debug("[%s:%s] ac = %p\n", __MM_FILE__, __func__, ac);
+	memset(&rpc, 0, sizeof(rpc));
+	rpc.opcode = ADSP_AUDIO_IOCTL_CMD_STREAM_EOS;
+	rpc.response_type = ADSP_AUDIO_RESPONSE_ASYNC;
+	return audio_ioctl(ac, &rpc, sizeof(rpc));
+}
diff --git a/arch/arm/mach-msm/qdsp6/q6audio_devices.h b/arch/arm/mach-msm/qdsp6/q6audio_devices.h
new file mode 100644
index 0000000..d316ab0
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/q6audio_devices.h
@@ -0,0 +1,334 @@
+/* arch/arm/mach-msm/qdsp6/q6audio_devices.h
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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.
+ *
+ */
+
+struct q6_device_info {
+	uint32_t id;
+	uint32_t cad_id;
+	uint32_t path;
+	uint32_t rate;
+	uint8_t dir;
+	uint8_t codec;
+	uint8_t hw;
+};
+
+#define Q6_ICODEC_RX		0
+#define Q6_ICODEC_TX		1
+#define Q6_ECODEC_RX		2
+#define Q6_ECODEC_TX		3
+#define Q6_SDAC_RX		6
+#define Q6_SDAC_TX		7
+#define Q6_CODEC_NONE		255
+
+#define Q6_TX		1
+#define Q6_RX		2
+#define Q6_TX_RX	3
+
+#define Q6_HW_HANDSET	0
+#define Q6_HW_HEADSET	1
+#define Q6_HW_SPEAKER	2
+#define Q6_HW_TTY	3
+#define Q6_HW_BT_SCO	4
+#define Q6_HW_BT_A2DP	5
+
+#define Q6_HW_COUNT	6
+
+#define CAD_HW_DEVICE_ID_HANDSET_MIC		0x01
+#define CAD_HW_DEVICE_ID_HANDSET_SPKR		0x02
+#define CAD_HW_DEVICE_ID_HEADSET_MIC		0x03
+#define CAD_HW_DEVICE_ID_HEADSET_SPKR_MONO	0x04
+#define CAD_HW_DEVICE_ID_HEADSET_SPKR_STEREO	0x05
+#define CAD_HW_DEVICE_ID_SPKR_PHONE_MIC		0x06
+#define CAD_HW_DEVICE_ID_SPKR_PHONE_MONO	0x07
+#define CAD_HW_DEVICE_ID_SPKR_PHONE_STEREO	0x08
+#define CAD_HW_DEVICE_ID_BT_SCO_MIC		0x09
+#define CAD_HW_DEVICE_ID_BT_SCO_SPKR		0x0A
+#define CAD_HW_DEVICE_ID_BT_A2DP_SPKR		0x0B
+#define CAD_HW_DEVICE_ID_TTY_HEADSET_MIC	0x0C
+#define CAD_HW_DEVICE_ID_TTY_HEADSET_SPKR	0x0D
+
+#define CAD_HW_DEVICE_ID_DEFAULT_TX		0x0E
+#define CAD_HW_DEVICE_ID_DEFAULT_RX		0x0F
+
+
+#define CAD_HW_DEVICE_ID_SPKR_PHONE_DUAL_MIC_BROADSIDE      0x2B
+#define CAD_HW_DEVICE_ID_SPKR_PHONE_DUAL_MIC_ENDFIRE        0x2D
+#define CAD_HW_DEVICE_ID_HANDSET_DUAL_MIC_BROADSIDE         0x2C
+#define CAD_HW_DEVICE_ID_HANDSET_DUAL_MIC_ENDFIRE           0x2E
+
+/* Logical Device to indicate A2DP routing */
+#define CAD_HW_DEVICE_ID_BT_A2DP_TX             0x10
+#define CAD_HW_DEVICE_ID_HEADSET_MONO_PLUS_SPKR_MONO_RX		0x11
+#define CAD_HW_DEVICE_ID_HEADSET_MONO_PLUS_SPKR_STEREO_RX	0x12
+#define CAD_HW_DEVICE_ID_HEADSET_STEREO_PLUS_SPKR_MONO_RX	0x13
+#define CAD_HW_DEVICE_ID_HEADSET_STEREO_PLUS_SPKR_STEREO_RX	0x14
+
+#define CAD_HW_DEVICE_ID_VOICE			0x15
+
+#define CAD_HW_DEVICE_ID_I2S_RX                 0x20
+#define CAD_HW_DEVICE_ID_I2S_TX                 0x21
+
+/* AUXPGA */
+#define CAD_HW_DEVICE_ID_HEADSET_SPKR_STEREO_LB 0x22
+#define CAD_HW_DEVICE_ID_HEADSET_SPKR_MONO_LB   0x23
+#define CAD_HW_DEVICE_ID_SPEAKER_SPKR_STEREO_LB 0x24
+#define CAD_HW_DEVICE_ID_SPEAKER_SPKR_MONO_LB   0x25
+
+#define CAD_HW_DEVICE_ID_NULL_RX		0x2A
+
+#define CAD_HW_DEVICE_ID_MAX_NUM                0x2F
+
+#define CAD_HW_DEVICE_ID_INVALID                0xFF
+
+#define CAD_RX_DEVICE  0x00
+#define CAD_TX_DEVICE  0x01
+
+static struct q6_device_info q6_audio_devices[] = {
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_HANDSET_SPKR,
+		.cad_id	= CAD_HW_DEVICE_ID_HANDSET_SPKR,
+		.path	= ADIE_PATH_HANDSET_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_HANDSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_MONO,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_SPKR_MONO,
+		.path	= ADIE_PATH_HEADSET_MONO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_HEADSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_HEADSET_SPKR_STEREO,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_SPKR_STEREO,
+		.path	= ADIE_PATH_HEADSET_STEREO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_HEADSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO,
+		.cad_id	= CAD_HW_DEVICE_ID_SPKR_PHONE_MONO,
+		.path	= ADIE_PATH_SPEAKER_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO,
+		.cad_id	= CAD_HW_DEVICE_ID_SPKR_PHONE_STEREO,
+		.path	= ADIE_PATH_SPEAKER_STEREO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_MONO_HEADSET,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_MONO_PLUS_SPKR_MONO_RX,
+		.path	= ADIE_PATH_SPKR_MONO_HDPH_MONO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MONO_W_STEREO_HEADSET,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_STEREO_PLUS_SPKR_MONO_RX,
+		.path	= ADIE_PATH_SPKR_MONO_HDPH_STEREO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_MONO_HEADSET,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_MONO_PLUS_SPKR_STEREO_RX,
+		.path	= ADIE_PATH_SPKR_STEREO_HDPH_MONO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_STEREO_W_STEREO_HEADSET,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_STEREO_PLUS_SPKR_STEREO_RX,
+		.path	= ADIE_PATH_SPKR_STEREO_HDPH_STEREO_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_SPKR,
+		.cad_id	= CAD_HW_DEVICE_ID_TTY_HEADSET_SPKR,
+		.path	= ADIE_PATH_TTY_HEADSET_RX,
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ICODEC_RX,
+		.hw	= Q6_HW_TTY,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_HANDSET_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_HANDSET_MIC,
+		.path	= ADIE_PATH_HANDSET_TX,
+		.rate   = 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ICODEC_TX,
+		.hw	= Q6_HW_HANDSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_HEADSET_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_HEADSET_MIC,
+		.path	= ADIE_PATH_HEADSET_MONO_TX,
+		.rate   = 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ICODEC_TX,
+		.hw	= Q6_HW_HEADSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_SPKR_PHONE_MIC,
+		.path	= ADIE_PATH_SPEAKER_TX,
+		.rate   = 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ICODEC_TX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_HANDSET_DUAL_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_HANDSET_DUAL_MIC_ENDFIRE,
+		.path	= ADIE_CODEC_HANDSET_SPKR_EF_TX,
+		.rate	= 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ICODEC_TX,
+		.hw	= Q6_HW_HANDSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_HANDSET_DUAL_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_HANDSET_DUAL_MIC_BROADSIDE,
+		.path	= ADIE_CODEC_HANDSET_SPKR_BS_TX,
+		.rate	= 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ICODEC_TX,
+		.hw	= Q6_HW_HANDSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_DUAL_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_SPKR_PHONE_DUAL_MIC_ENDFIRE,
+		.path	= ADIE_CODEC_HANDSET_SPKR_EF_TX,
+		.rate	= 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ICODEC_TX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_SPKR_PHONE_DUAL_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_SPKR_PHONE_DUAL_MIC_BROADSIDE,
+		.path	= ADIE_CODEC_HANDSET_SPKR_BS_TX,
+		.rate	= 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ICODEC_TX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_TTY_HEADSET_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_TTY_HEADSET_MIC,
+		.path	= ADIE_PATH_TTY_HEADSET_TX,
+		.rate   = 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ICODEC_TX,
+		.hw	= Q6_HW_HEADSET,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_BT_SCO_SPKR,
+		.cad_id	= CAD_HW_DEVICE_ID_BT_SCO_SPKR,
+		.path	= 0, /* XXX */
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ECODEC_RX,
+		.hw	= Q6_HW_BT_SCO,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_BT_A2DP_SPKR,
+		.cad_id	= CAD_HW_DEVICE_ID_BT_A2DP_SPKR,
+		.path	= 0, /* XXX */
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ECODEC_RX,
+		.hw	= Q6_HW_BT_A2DP,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_BT_SCO_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_BT_SCO_MIC,
+		.path	= 0, /* XXX */
+		.rate   = 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ECODEC_TX,
+		.hw	= Q6_HW_BT_SCO,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_I2S_SPKR,
+		.cad_id	= CAD_HW_DEVICE_ID_I2S_RX,
+		.path	= 0, /* XXX */
+		.rate   = 48000,
+		.dir	= Q6_RX,
+		.codec	= Q6_SDAC_RX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_I2S_MIC,
+		.cad_id	= CAD_HW_DEVICE_ID_I2S_TX,
+		.path	= 0, /* XXX */
+		.rate   = 16000,
+		.dir	= Q6_TX,
+		.codec	= Q6_SDAC_TX,
+		.hw	= Q6_HW_SPEAKER,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_AUXPCM_RX,
+		.cad_id	= CAD_HW_DEVICE_ID_BT_SCO_SPKR,
+		.path	= 0, /* XXX */
+		.rate   = 8000,
+		.dir	= Q6_RX,
+		.codec	= Q6_ECODEC_RX,
+		.hw	= Q6_HW_BT_SCO,
+	},
+	{
+		.id	= ADSP_AUDIO_DEVICE_ID_AUXPCM_TX,
+		.cad_id	= CAD_HW_DEVICE_ID_BT_SCO_MIC,
+		.path	= 0, /* XXX */
+		.rate   = 8000,
+		.dir	= Q6_TX,
+		.codec	= Q6_ECODEC_TX,
+		.hw	= Q6_HW_BT_SCO,
+	},
+	{
+		.id	= 0,
+		.cad_id	= 0,
+		.path	= 0,
+		.rate   = 8000,
+		.dir	= 0,
+		.codec	= Q6_CODEC_NONE,
+		.hw	= 0,
+	},
+};
+
diff --git a/arch/arm/mach-msm/qdsp6/qcelp_in.c b/arch/arm/mach-msm/qdsp6/qcelp_in.c
new file mode 100644
index 0000000..ca0ab1a
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/qcelp_in.c
@@ -0,0 +1,475 @@
+/*
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+
+#include <linux/msm_audio_qcp.h>
+#include <mach/msm_qdsp6_audio.h>
+#include "dal_audio_format.h"
+#include <mach/debug_mm.h>
+
+#define QCELP_FC_BUFF_CNT 10
+#define QCELP_READ_TIMEOUT 2000
+struct qcelp_fc_buff {
+	struct mutex lock;
+	int empty;
+	void *data;
+	int size;
+	int actual_size;
+};
+
+struct qcelp_fc {
+	struct task_struct *task;
+	wait_queue_head_t fc_wq;
+	struct qcelp_fc_buff fc_buff[QCELP_FC_BUFF_CNT];
+	int buff_index;
+};
+
+struct qcelp {
+	struct mutex lock;
+	struct msm_audio_qcelp_enc_config cfg;
+	struct msm_audio_stream_config str_cfg;
+	struct audio_client *audio_client;
+	struct msm_voicerec_mode voicerec_mode;
+	struct qcelp_fc *qcelp_fc;
+};
+
+
+static int q6_qcelp_flowcontrol(void *data)
+{
+	struct audio_client *ac;
+	struct audio_buffer *ab;
+	struct qcelp *qcelp = data;
+	int buff_index = 0;
+	int xfer = 0;
+	struct qcelp_fc *fc;
+
+
+	ac = qcelp->audio_client;
+	fc = qcelp->qcelp_fc;
+	if (!ac) {
+		pr_err("[%s:%s] audio_client is NULL\n", __MM_FILE__, __func__);
+		return 0;
+	}
+
+	while (!kthread_should_stop()) {
+		ab = ac->buf + ac->cpu_buf;
+		if (ab->used)
+			wait_event(ac->wait, (ab->used == 0));
+
+		pr_debug("[%s:%s] ab->data = %p, cpu_buf = %d", __MM_FILE__,
+			__func__, ab->data, ac->cpu_buf);
+		xfer = ab->actual_size;
+
+
+		mutex_lock(&(fc->fc_buff[buff_index].lock));
+		if (!fc->fc_buff[buff_index].empty) {
+			pr_err("[%s:%s] flow control buffer[%d] not read!\n",
+					__MM_FILE__, __func__, buff_index);
+		}
+
+		if (fc->fc_buff[buff_index].size < xfer) {
+			pr_err("[%s:%s] buffer %d too small\n", __MM_FILE__,
+					__func__, buff_index);
+			memcpy(fc->fc_buff[buff_index].data, ab->data,
+					fc->fc_buff[buff_index].size);
+			fc->fc_buff[buff_index].empty = 0;
+			fc->fc_buff[buff_index].actual_size =
+					fc->fc_buff[buff_index].size;
+		} else {
+			memcpy(fc->fc_buff[buff_index].data, ab->data, xfer);
+			fc->fc_buff[buff_index].empty = 0;
+			fc->fc_buff[buff_index].actual_size = xfer;
+		}
+		mutex_unlock(&(fc->fc_buff[buff_index].lock));
+		/*wake up client, if any*/
+		wake_up(&fc->fc_wq);
+
+		buff_index++;
+		if (buff_index >= QCELP_FC_BUFF_CNT)
+			buff_index = 0;
+
+		ab->used = 1;
+
+		q6audio_read(ac, ab);
+		ac->cpu_buf ^= 1;
+	}
+
+	return 0;
+}
+static long q6_qcelp_in_ioctl(struct file *file, unsigned int cmd,
+				 unsigned long arg)
+{
+	struct qcelp *qcelp = file->private_data;
+	int rc = 0;
+	int i = 0;
+	struct qcelp_fc *fc;
+	int size = 0;
+
+	mutex_lock(&qcelp->lock);
+	switch (cmd) {
+	case AUDIO_SET_VOLUME:
+		pr_debug("[%s:%s] SET_VOLUME\n", __MM_FILE__, __func__);
+		break;
+	case AUDIO_GET_STATS:
+	{
+		struct msm_audio_stats stats;
+		pr_debug("[%s:%s] GET_STATS\n", __MM_FILE__, __func__);
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void *) arg, &stats,
+					sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+	case AUDIO_START:
+	{
+		uint32_t acdb_id;
+		pr_debug("[%s:%s] AUDIO_START\n", __MM_FILE__, __func__);
+		if (arg == 0) {
+			acdb_id = 0;
+		} else {
+			if (copy_from_user(&acdb_id,
+				(void *) arg, sizeof(acdb_id))) {
+				rc = -EFAULT;
+				break;
+			}
+		}
+		if (qcelp->audio_client) {
+			pr_err("[%s:%s] active session already existing\n",
+				__MM_FILE__, __func__);
+			rc = -EBUSY;
+			break;
+		} else {
+			qcelp->audio_client = q6audio_open_qcp(
+				qcelp->str_cfg.buffer_size,
+				qcelp->cfg.min_bit_rate,
+				qcelp->cfg.max_bit_rate,
+				qcelp->voicerec_mode.rec_mode,
+				ADSP_AUDIO_FORMAT_V13K_FS,
+				acdb_id);
+
+			if (!qcelp->audio_client) {
+				pr_err("[%s:%s] qcelp open session failed\n",
+					__MM_FILE__, __func__);
+				kfree(qcelp);
+				rc = -ENOMEM;
+				break;
+			}
+		}
+
+		/*allocate flow control buffers*/
+		fc = qcelp->qcelp_fc;
+		size = qcelp->str_cfg.buffer_size;
+		for (i = 0; i < QCELP_FC_BUFF_CNT; ++i) {
+			mutex_init(&(fc->fc_buff[i].lock));
+			fc->fc_buff[i].empty = 1;
+			fc->fc_buff[i].data = kmalloc(size, GFP_KERNEL);
+			if (fc->fc_buff[i].data == NULL) {
+				pr_err("[%s:%s] No memory for FC buffers\n",
+						__MM_FILE__, __func__);
+				rc = -ENOMEM;
+				goto fc_fail;
+			}
+			fc->fc_buff[i].size = size;
+			fc->fc_buff[i].actual_size = 0;
+		}
+
+		/*create flow control thread*/
+		fc->task = kthread_run(q6_qcelp_flowcontrol,
+				qcelp, "qcelp_flowcontrol");
+		if (IS_ERR(fc->task)) {
+			rc = PTR_ERR(fc->task);
+			pr_err("[%s:%s] error creating flow control thread\n",
+					__MM_FILE__, __func__);
+			goto fc_fail;
+		}
+		break;
+fc_fail:
+		/*free flow control buffers*/
+		--i;
+		for (; i >=  0; i--) {
+			kfree(fc->fc_buff[i].data);
+			fc->fc_buff[i].data = NULL;
+		}
+		break;
+	}
+	case AUDIO_STOP:
+		pr_debug("[%s:%s] AUDIO_STOP\n", __MM_FILE__, __func__);
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_INCALL: {
+		pr_debug("[%s:%s] SET_INCALL\n", __MM_FILE__, __func__);
+		if (copy_from_user(&qcelp->voicerec_mode,
+			(void *)arg, sizeof(struct msm_voicerec_mode)))
+			rc = -EFAULT;
+
+		if (qcelp->voicerec_mode.rec_mode != AUDIO_FLAG_READ
+			&& qcelp->voicerec_mode.rec_mode !=
+			AUDIO_FLAG_INCALL_MIXED) {
+			qcelp->voicerec_mode.rec_mode = AUDIO_FLAG_READ;
+			pr_err("[%s:%s] Invalid rec_mode\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+		}
+		break;
+	}
+	case AUDIO_GET_STREAM_CONFIG:
+		if (copy_to_user((void *)arg, &qcelp->str_cfg,
+				sizeof(struct msm_audio_stream_config)))
+			rc = -EFAULT;
+		pr_debug("[%s:%s] GET_STREAM_CONFIG: buffsz=%d, buffcnt=%d\n",
+			 __MM_FILE__, __func__, qcelp->str_cfg.buffer_size,
+			qcelp->str_cfg.buffer_count);
+		break;
+	case AUDIO_SET_STREAM_CONFIG:
+		if (copy_from_user(&qcelp->str_cfg, (void *)arg,
+			sizeof(struct msm_audio_stream_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("[%s:%s] SET_STREAM_CONFIG: buffsz=%d, buffcnt=%d\n",
+			 __MM_FILE__, __func__, qcelp->str_cfg.buffer_size,
+			qcelp->str_cfg.buffer_count);
+
+		if (qcelp->str_cfg.buffer_size < 35) {
+			pr_err("[%s:%s] Buffer size too small\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+			break;
+		}
+
+		if (qcelp->str_cfg.buffer_count != 2)
+			pr_info("[%s:%s] Buffer count set to 2\n", __MM_FILE__,
+					__func__);
+		break;
+	case AUDIO_SET_QCELP_ENC_CONFIG:
+		if (copy_from_user(&qcelp->cfg, (void *) arg,
+				sizeof(struct msm_audio_qcelp_enc_config)))
+			rc = -EFAULT;
+		pr_debug("[%s:%s] SET_QCELP_ENC_CONFIG\n", __MM_FILE__,
+			__func__);
+
+		if (qcelp->cfg.min_bit_rate > 4 ||
+			 qcelp->cfg.min_bit_rate < 1) {
+
+			pr_err("[%s:%s] invalid min bitrate\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+		}
+		if (qcelp->cfg.max_bit_rate > 4 ||
+			 qcelp->cfg.max_bit_rate < 1) {
+
+			pr_err("[%s:%s] invalid max bitrate\n", __MM_FILE__,
+					__func__);
+			rc = -EINVAL;
+		}
+
+		break;
+	case AUDIO_GET_QCELP_ENC_CONFIG:
+		if (copy_to_user((void *) arg, &qcelp->cfg,
+			 sizeof(struct msm_audio_qcelp_enc_config)))
+			rc = -EFAULT;
+		pr_debug("[%s:%s] GET_QCELP_ENC_CONFIG\n", __MM_FILE__,
+			__func__);
+		break;
+
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&qcelp->lock);
+	pr_debug("[%s:%s] rc = %d\n", __MM_FILE__, __func__, rc);
+	return rc;
+}
+
+static int q6_qcelp_in_open(struct inode *inode, struct file *file)
+{
+	struct qcelp *qcelp;
+	struct qcelp_fc *fc;
+	int i;
+	pr_info("[%s:%s] open\n", __MM_FILE__, __func__);
+	qcelp = kmalloc(sizeof(struct qcelp), GFP_KERNEL);
+	if (qcelp == NULL) {
+		pr_err("[%s:%s] Could not allocate memory for qcelp driver\n",
+				__MM_FILE__, __func__);
+		return -ENOMEM;
+	}
+
+	mutex_init(&qcelp->lock);
+	file->private_data = qcelp;
+	qcelp->audio_client = NULL;
+	qcelp->str_cfg.buffer_size = 35;
+	qcelp->str_cfg.buffer_count = 2;
+	qcelp->cfg.cdma_rate = CDMA_RATE_FULL;
+	qcelp->cfg.min_bit_rate = 1;
+	qcelp->cfg.max_bit_rate = 4;
+	qcelp->voicerec_mode.rec_mode = AUDIO_FLAG_READ;
+
+	qcelp->qcelp_fc = kmalloc(sizeof(struct qcelp_fc), GFP_KERNEL);
+	if (qcelp->qcelp_fc == NULL) {
+		pr_err("[%s:%s] Could not allocate memory for qcelp_fc\n",
+				__MM_FILE__, __func__);
+		kfree(qcelp);
+		return -ENOMEM;
+	}
+	fc = qcelp->qcelp_fc;
+	fc->task = NULL;
+	fc->buff_index = 0;
+	for (i = 0; i < QCELP_FC_BUFF_CNT; ++i) {
+		fc->fc_buff[i].data = NULL;
+		fc->fc_buff[i].size = 0;
+		fc->fc_buff[i].actual_size = 0;
+	}
+	/*initialize wait queue head*/
+	init_waitqueue_head(&fc->fc_wq);
+	return 0;
+}
+
+static ssize_t q6_qcelp_in_read(struct file *file, char __user *buf,
+			   size_t count, loff_t *pos)
+{
+	struct audio_client *ac;
+	const char __user *start = buf;
+	struct qcelp *qcelp = file->private_data;
+	struct qcelp_fc *fc;
+	int xfer = 0;
+	int res = 0;
+
+	pr_debug("[%s:%s] count = %d\n", __MM_FILE__, __func__, count);
+	mutex_lock(&qcelp->lock);
+	ac = qcelp->audio_client;
+	if (!ac) {
+		res = -ENODEV;
+		goto fail;
+	}
+	fc = qcelp->qcelp_fc;
+	while (count > xfer) {
+		/*wait for buffer to full*/
+		if (fc->fc_buff[fc->buff_index].empty != 0) {
+			res = wait_event_interruptible_timeout(fc->fc_wq,
+				(fc->fc_buff[fc->buff_index].empty == 0),
+				msecs_to_jiffies(QCELP_READ_TIMEOUT));
+
+			pr_debug("[%s:%s] buff_index = %d\n", __MM_FILE__,
+				__func__, fc->buff_index);
+			if (res == 0) {
+				pr_err("[%s:%s] Timeout!\n", __MM_FILE__,
+						__func__);
+				res = -ETIMEDOUT;
+				goto fail;
+			} else if (res < 0) {
+				pr_err("[%s:%s] Returning on Interrupt\n",
+					__MM_FILE__, __func__);
+				goto fail;
+			}
+		}
+		/*lock the buffer*/
+		mutex_lock(&(fc->fc_buff[fc->buff_index].lock));
+		xfer = fc->fc_buff[fc->buff_index].actual_size;
+
+		if (xfer > count) {
+			mutex_unlock(&(fc->fc_buff[fc->buff_index].lock));
+			pr_err("[%s:%s] read failed! byte count too small\n",
+					__MM_FILE__, __func__);
+			res = -EINVAL;
+			goto fail;
+		}
+
+		if (copy_to_user(buf, fc->fc_buff[fc->buff_index].data,	xfer)) {
+			mutex_unlock(&(fc->fc_buff[fc->buff_index].lock));
+			pr_err("[%s:%s] copy_to_user failed at index %d\n",
+					__MM_FILE__, __func__, fc->buff_index);
+			res = -EFAULT;
+			goto fail;
+		}
+		buf += xfer;
+		count -= xfer;
+
+		fc->fc_buff[fc->buff_index].empty = 1;
+		fc->fc_buff[fc->buff_index].actual_size = 0;
+
+		mutex_unlock(&(fc->fc_buff[fc->buff_index].lock));
+		++(fc->buff_index);
+		if (fc->buff_index >= QCELP_FC_BUFF_CNT)
+			fc->buff_index = 0;
+	}
+	res = buf - start;
+
+fail:
+	mutex_unlock(&qcelp->lock);
+
+	return res;
+}
+
+static int q6_qcelp_in_release(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	struct qcelp *qcelp = file->private_data;
+	int i = 0;
+	struct qcelp_fc *fc;
+
+	mutex_lock(&qcelp->lock);
+	fc = qcelp->qcelp_fc;
+	kthread_stop(fc->task);
+	fc->task = NULL;
+
+	/*free flow control buffers*/
+	for (i = 0; i < QCELP_FC_BUFF_CNT; ++i) {
+		kfree(fc->fc_buff[i].data);
+		fc->fc_buff[i].data = NULL;
+	}
+	kfree(fc);
+
+	if (qcelp->audio_client)
+		rc = q6audio_close(qcelp->audio_client);
+	mutex_unlock(&qcelp->lock);
+	kfree(qcelp);
+	pr_info("[%s:%s] release\n", __MM_FILE__, __func__);
+	return rc;
+}
+
+static const struct file_operations q6_qcelp_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_qcelp_in_open,
+	.read		= q6_qcelp_in_read,
+	.release	= q6_qcelp_in_release,
+	.unlocked_ioctl	= q6_qcelp_in_ioctl,
+};
+
+struct miscdevice q6_qcelp_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_qcelp_in",
+	.fops	= &q6_qcelp_in_fops,
+};
+
+static int __init q6_qcelp_in_init(void)
+{
+	return misc_register(&q6_qcelp_in_misc);
+}
+
+device_initcall(q6_qcelp_in_init);
diff --git a/arch/arm/mach-msm/qdsp6/routing.c b/arch/arm/mach-msm/qdsp6/routing.c
new file mode 100644
index 0000000..f6533a4
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6/routing.c
@@ -0,0 +1,78 @@
+/* arch/arm/mach-msm/qdsp6/routing.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <mach/debug_mm.h>
+
+extern int q6audio_set_route(const char *name);
+
+static int q6_open(struct inode *inode, struct file *file)
+{
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	return 0;
+}
+
+static ssize_t q6_write(struct file *file, const char __user *buf,
+			size_t count, loff_t *pos)
+{
+	char cmd[32];
+
+	pr_debug("[%s:%s] count = %d", __MM_FILE__, __func__, count);
+	if (count >= sizeof(cmd)) {
+		pr_err("[%s:%s] invalid count %d\n", __MM_FILE__,
+			__func__, count);
+			return -EINVAL;
+	}
+	if (copy_from_user(cmd, buf, count))
+		return -EFAULT;
+	cmd[count] = 0;
+
+	if ((count > 1) && (cmd[count-1] == '\n'))
+		cmd[count-1] = 0;
+
+	q6audio_set_route(cmd);
+
+	return count;
+}
+
+static int q6_release(struct inode *inode, struct file *file)
+{
+	pr_debug("[%s:%s]\n", __MM_FILE__, __func__);
+	return 0;
+}
+
+static struct file_operations q6_fops = {
+	.owner		= THIS_MODULE,
+	.open		= q6_open,
+	.write		= q6_write,
+	.release	= q6_release,
+};
+
+static struct miscdevice q6_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_audio_route",
+	.fops	= &q6_fops,
+};
+
+
+static int __init q6_init(void) {
+	return misc_register(&q6_misc);
+}
+
+device_initcall(q6_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/Makefile b/arch/arm/mach-msm/qdsp6v2/Makefile
new file mode 100644
index 0000000..cee8f04
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/Makefile
@@ -0,0 +1,22 @@
+obj-y += rtac.o
+ifdef CONFIG_ARCH_MSM8X60
+obj-y += audio_dev_ctl.o
+obj-y += board-msm8x60-audio.o
+obj-$(CONFIG_TIMPANI_CODEC) += snddev_icodec.o
+obj-y += snddev_ecodec.o snddev_mi2s.o snddev_virtual.o
+obj-y += pcm_out.o pcm_in.o fm.o
+obj-y += audio_lpa.o
+obj-y += q6voice.o
+obj-y += snddev_hdmi.o
+obj-y += audio_mvs.o
+obj-$(CONFIG_FB_MSM_HDMI_MSM_PANEL) += lpa_if_hdmi.o
+endif
+obj-$(CONFIG_MSM_QDSP6_APR) += apr.o apr_tal.o q6core.o dsp_debug.o
+obj-y += audio_acdb.o
+ifndef CONFIG_ARCH_MSM9615
+obj-y += aac_in.o qcelp_in.o evrc_in.o amrnb_in.o audio_utils.o
+obj-y += audio_wma.o audio_wmapro.o audio_aac.o audio_multi_aac.o audio_utils_aio.o
+obj-$(CONFIG_MSM_QDSP6_CODECS) += q6audio_v1.o q6audio_v1_aio.o
+obj-$(CONFIG_MSM_ULTRASOUND) += ultrasound/
+obj-y += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_evrc.o audio_qcelp.o amrwb_in.o
+endif
diff --git a/arch/arm/mach-msm/qdsp6v2/aac_in.c b/arch/arm/mach-msm/qdsp6v2/aac_in.c
new file mode 100644
index 0000000..6e79a75
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/aac_in.c
@@ -0,0 +1,400 @@
+/*
+ * 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
+ * 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/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/msm_audio_aac.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include "audio_utils.h"
+
+
+/* Buffer with meta*/
+#define PCM_BUF_SIZE		(4096 + sizeof(struct meta_in))
+
+/* Maximum 5 frames in buffer with meta */
+#define FRAME_SIZE		(1 + ((1536+sizeof(struct meta_out_dsp)) * 5))
+
+#define AAC_FORMAT_ADTS 65535
+
+/* ------------------- device --------------------- */
+static long aac_in_ioctl(struct file *file,
+				unsigned int cmd, unsigned long arg)
+{
+	struct q6audio_in  *audio = file->private_data;
+	int rc = 0;
+	int cnt = 0;
+
+	switch (cmd) {
+	case AUDIO_START: {
+		struct msm_audio_aac_enc_config *enc_cfg;
+		struct msm_audio_aac_config *aac_config;
+		uint32_t aac_mode = AAC_ENC_MODE_AAC_LC;
+
+		enc_cfg = audio->enc_cfg;
+		aac_config = audio->codec_cfg;
+		/* ENCODE CFG (after new set of API's are published )bharath*/
+		pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__,
+				audio->ac->session, audio->buf_alloc);
+		if (audio->enabled == 1) {
+			pr_info("%s:AUDIO_START already over\n", __func__);
+			rc = 0;
+			break;
+		}
+
+		rc = audio_in_buf_alloc(audio);
+		if (rc < 0) {
+			pr_err("%s:session id %d: buffer allocation failed\n",
+				__func__, audio->ac->session);
+			break;
+		}
+
+		pr_debug("%s:sbr_ps_flag = %d, sbr_flag = %d\n", __func__,
+			aac_config->sbr_ps_on_flag, aac_config->sbr_on_flag);
+		if (aac_config->sbr_ps_on_flag)
+			aac_mode = AAC_ENC_MODE_EAAC_P;
+		else if (aac_config->sbr_on_flag)
+			aac_mode = AAC_ENC_MODE_AAC_P;
+		else
+			aac_mode = AAC_ENC_MODE_AAC_LC;
+
+		rc = q6asm_enc_cfg_blk_aac(audio->ac,
+					audio->buf_cfg.frames_per_buf,
+					enc_cfg->sample_rate,
+					enc_cfg->channels,
+					enc_cfg->bit_rate,
+					aac_mode,
+					enc_cfg->stream_format);
+		if (rc < 0) {
+			pr_err("%s:session id %d: cmd media format block"
+				"failed\n", __func__, audio->ac->session);
+			break;
+		}
+		if (audio->feedback == NON_TUNNEL_MODE) {
+			rc = q6asm_media_format_block_pcm(audio->ac,
+						audio->pcm_cfg.sample_rate,
+						audio->pcm_cfg.channel_count);
+			if (rc < 0) {
+				pr_err("%s:session id %d: media format block"
+				"failed\n", __func__, audio->ac->session);
+				break;
+			}
+		}
+		rc = audio_in_enable(audio);
+		if (!rc) {
+			audio->enabled = 1;
+		} else {
+			audio->enabled = 0;
+			pr_err("%s:session id %d: Audio Start procedure"
+			"failed rc=%d\n", __func__, audio->ac->session, rc);
+			break;
+		}
+		while (cnt++ < audio->str_cfg.buffer_count)
+			q6asm_read(audio->ac);
+		pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n",
+				__func__, audio->ac->session, audio->enabled);
+		break;
+	}
+	case AUDIO_STOP: {
+		pr_debug("%s:session id %d: Rxed AUDIO_STOP\n", __func__,
+				audio->ac->session);
+		rc = audio_in_disable(audio);
+		if (rc  < 0) {
+			pr_err("%s:session id %d: Audio Stop procedure failed"
+				"rc=%d\n", __func__, audio->ac->session, rc);
+			break;
+		}
+		break;
+	}
+	case AUDIO_GET_AAC_ENC_CONFIG: {
+		struct msm_audio_aac_enc_config cfg;
+		struct msm_audio_aac_enc_config *enc_cfg;
+		enc_cfg = audio->enc_cfg;
+		if (enc_cfg->channels == CH_MODE_MONO)
+			cfg.channels = 1;
+		else
+			cfg.channels = 2;
+		cfg.sample_rate = enc_cfg->sample_rate;
+		cfg.bit_rate = enc_cfg->bit_rate;
+		/* ADTS(-1) to ADTS(0x00), RAW(0x00) to RAW(0x03) */
+		cfg.stream_format = ((enc_cfg->stream_format == \
+			0x00) ? AUDIO_AAC_FORMAT_ADTS : AUDIO_AAC_FORMAT_RAW);
+		pr_debug("%s:session id %d: Get-aac-cfg: format=%d sr=%d"
+			"bitrate=%d\n", __func__, audio->ac->session,
+			cfg.stream_format, cfg.sample_rate, cfg.bit_rate);
+		if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_AAC_ENC_CONFIG: {
+		struct msm_audio_aac_enc_config cfg;
+		struct msm_audio_aac_enc_config *enc_cfg;
+		enc_cfg = audio->enc_cfg;
+		if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("%s:session id %d: Set-aac-cfg: stream=%d\n", __func__,
+					audio->ac->session, cfg.stream_format);
+
+		if ((cfg.stream_format != AUDIO_AAC_FORMAT_RAW)  &&
+			(cfg.stream_format != AAC_FORMAT_ADTS)) {
+			pr_err("%s:session id %d: unsupported AAC format\n",
+				__func__, audio->ac->session);
+			rc = -EINVAL;
+			break;
+		}
+
+		if (cfg.channels == 1) {
+			cfg.channels = CH_MODE_MONO;
+		} else if (cfg.channels == 2) {
+			cfg.channels = CH_MODE_STEREO;
+		} else {
+			rc = -EINVAL;
+			break;
+		}
+		if ((cfg.sample_rate < 8000) && (cfg.sample_rate > 48000)) {
+			pr_err("%s: ERROR in setting samplerate = %d\n",
+				__func__, cfg.sample_rate);
+			rc = -EINVAL;
+			break;
+		}
+		/* For aac-lc, min_bit_rate = min(24Kbps, 0.5*SR*num_chan);
+		max_bi_rate = min(192Kbps, 6*SR*num_chan);
+		min_sample_rate = 8000Hz, max_rate=48000 */
+		if ((cfg.bit_rate < 4000) || (cfg.bit_rate > 192000)) {
+			pr_err("%s: ERROR in setting bitrate = %d\n",
+				__func__, cfg.bit_rate);
+			rc = -EINVAL;
+			break;
+		}
+		enc_cfg->sample_rate = cfg.sample_rate;
+		enc_cfg->channels = cfg.channels;
+		enc_cfg->bit_rate = cfg.bit_rate;
+		enc_cfg->stream_format =
+			((cfg.stream_format == AUDIO_AAC_FORMAT_RAW) ? \
+								0x03 : 0x00);
+		pr_debug("%s:session id %d: Set-aac-cfg:SR= 0x%x ch=0x%x"
+			"bitrate=0x%x, format(adts/raw) = %d\n",
+			__func__, audio->ac->session, enc_cfg->sample_rate,
+			enc_cfg->channels, enc_cfg->bit_rate,
+			enc_cfg->stream_format);
+		break;
+	}
+	case AUDIO_GET_AAC_CONFIG: {
+		if (copy_to_user((void *)arg, &audio->codec_cfg,
+				 sizeof(struct msm_audio_aac_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		break;
+	}
+	case AUDIO_SET_AAC_CONFIG: {
+		struct msm_audio_aac_config aac_cfg;
+		struct msm_audio_aac_config *audio_aac_cfg;
+		struct msm_audio_aac_enc_config *enc_cfg;
+		enc_cfg = audio->enc_cfg;
+		audio_aac_cfg = audio->codec_cfg;
+
+		if (copy_from_user(&aac_cfg, (void *)arg,
+				 sizeof(struct msm_audio_aac_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("%s:session id %d: AUDIO_SET_AAC_CONFIG: sbr_flag = %d"
+				 " sbr_ps_flag = %d\n", __func__,
+				 audio->ac->session, aac_cfg.sbr_on_flag,
+				 aac_cfg.sbr_ps_on_flag);
+		audio_aac_cfg->sbr_on_flag = aac_cfg.sbr_on_flag;
+		audio_aac_cfg->sbr_ps_on_flag = aac_cfg.sbr_ps_on_flag;
+		if ((audio_aac_cfg->sbr_on_flag == 1) ||
+			 (audio_aac_cfg->sbr_ps_on_flag == 1)) {
+			if (enc_cfg->sample_rate < 24000) {
+				pr_err("%s: ERROR in setting samplerate = %d"
+					"\n", __func__, enc_cfg->sample_rate);
+				rc = -EINVAL;
+				break;
+			}
+		}
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+static int aac_in_open(struct inode *inode, struct file *file)
+{
+	struct q6audio_in *audio = NULL;
+	struct msm_audio_aac_enc_config *enc_cfg;
+	struct msm_audio_aac_config *aac_config;
+	int rc = 0;
+
+	audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
+
+	if (audio == NULL) {
+		pr_err("%s: Could not allocate memory for aac"
+				"driver\n", __func__);
+		return -ENOMEM;
+	}
+	/* Allocate memory for encoder config param */
+	audio->enc_cfg = kzalloc(sizeof(struct msm_audio_aac_enc_config),
+				GFP_KERNEL);
+	if (audio->enc_cfg == NULL) {
+		pr_err("%s:session id %d: Could not allocate memory for aac"
+				"config param\n", __func__, audio->ac->session);
+		kfree(audio);
+		return -ENOMEM;
+	}
+	enc_cfg = audio->enc_cfg;
+
+	audio->codec_cfg = kzalloc(sizeof(struct msm_audio_aac_config),
+				GFP_KERNEL);
+	if (audio->codec_cfg == NULL) {
+		pr_err("%s:session id %d: Could not allocate memory for aac"
+				"config\n", __func__, audio->ac->session);
+		kfree(audio->enc_cfg);
+		kfree(audio);
+		return -ENOMEM;
+	}
+	aac_config = audio->codec_cfg;
+
+	mutex_init(&audio->lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->write_lock);
+	spin_lock_init(&audio->dsp_lock);
+	init_waitqueue_head(&audio->read_wait);
+	init_waitqueue_head(&audio->write_wait);
+
+	/* Settings will be re-config at AUDIO_SET_CONFIG,
+	* but at least we need to have initial config
+	*/
+	audio->str_cfg.buffer_size = FRAME_SIZE;
+	audio->str_cfg.buffer_count = FRAME_NUM;
+	audio->min_frame_size = 1536;
+	audio->max_frames_per_buf = 5;
+	enc_cfg->sample_rate = 8000;
+	enc_cfg->channels = 1;
+	enc_cfg->bit_rate = 16000;
+	enc_cfg->stream_format = 0x00;/* 0:ADTS, 3:RAW */
+	audio->buf_cfg.meta_info_enable = 0x01;
+	audio->buf_cfg.frames_per_buf   = 0x01;
+	audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
+	audio->pcm_cfg.buffer_size  = PCM_BUF_SIZE;
+	aac_config->format = AUDIO_AAC_FORMAT_ADTS;
+	aac_config->audio_object = AUDIO_AAC_OBJECT_LC;
+	aac_config->sbr_on_flag = 0;
+	aac_config->sbr_ps_on_flag = 0;
+	aac_config->channel_configuration = 1;
+
+	audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb,
+							(void *)audio);
+
+	if (!audio->ac) {
+		pr_err("%s: Could not allocate memory for"
+				"audio client\n", __func__);
+		kfree(audio->enc_cfg);
+		kfree(audio->codec_cfg);
+		kfree(audio);
+		return -ENOMEM;
+	}
+	/* open aac encoder in tunnel mode */
+	audio->buf_cfg.frames_per_buf = 0x01;
+
+	if ((file->f_mode & FMODE_WRITE) &&
+		(file->f_mode & FMODE_READ)) {
+		audio->feedback = NON_TUNNEL_MODE;
+		rc = q6asm_open_read_write(audio->ac, FORMAT_MPEG4_AAC,
+						FORMAT_LINEAR_PCM);
+
+		if (rc < 0) {
+			pr_err("%s:session id %d: NT Open failed rc=%d\n",
+				__func__, audio->ac->session, rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->buf_cfg.meta_info_enable = 0x01;
+		pr_info("%s:session id %d: NT mode encoder success\n", __func__,
+				audio->ac->session);
+	} else if (!(file->f_mode & FMODE_WRITE) &&
+				(file->f_mode & FMODE_READ)) {
+		audio->feedback = TUNNEL_MODE;
+		rc = q6asm_open_read(audio->ac, FORMAT_MPEG4_AAC);
+
+		if (rc < 0) {
+			pr_err("%s:session id %d: Tunnel Open failed rc=%d\n",
+				__func__, audio->ac->session, rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		/* register for tx overflow (valid for tunnel mode only) */
+		rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
+		if (rc < 0) {
+			pr_err("%s:session id %d: TX Overflow registration"
+				"failed rc=%d\n", __func__,
+				audio->ac->session, rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->buf_cfg.meta_info_enable = 0x00;
+		pr_info("%s:session id %d: T mode encoder success\n", __func__,
+			audio->ac->session);
+	} else {
+		pr_err("%s:session id %d: Unexpected mode\n", __func__,
+				audio->ac->session);
+		rc = -EACCES;
+		goto fail;
+	}
+	audio->opened = 1;
+	atomic_set(&audio->in_count, PCM_BUF_COUNT);
+	atomic_set(&audio->out_count, 0x00);
+	audio->enc_ioctl = aac_in_ioctl;
+	file->private_data = audio;
+
+	pr_info("%s:session id %d: success\n", __func__, audio->ac->session);
+	return 0;
+fail:
+	q6asm_audio_client_free(audio->ac);
+	kfree(audio->enc_cfg);
+	kfree(audio->codec_cfg);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= aac_in_open,
+	.release	= audio_in_release,
+	.read		= audio_in_read,
+	.write		= audio_in_write,
+	.unlocked_ioctl	= audio_in_ioctl,
+};
+
+struct miscdevice audio_aac_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_aac_in",
+	.fops	= &audio_in_fops,
+};
+
+static int __init aac_in_init(void)
+{
+	return misc_register(&audio_aac_in_misc);
+}
+device_initcall(aac_in_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/amrnb_in.c b/arch/arm/mach-msm/qdsp6v2/amrnb_in.c
new file mode 100644
index 0000000..63a0774
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/amrnb_in.c
@@ -0,0 +1,285 @@
+/* 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
+ * 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/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/msm_audio_amrnb.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include "audio_utils.h"
+
+/* Buffer with meta*/
+#define PCM_BUF_SIZE		(4096 + sizeof(struct meta_in))
+
+/* Maximum 10 frames in buffer with meta */
+#define FRAME_SIZE		(1 + ((32+sizeof(struct meta_out_dsp)) * 10))
+
+/* ------------------- device --------------------- */
+static long amrnb_in_ioctl(struct file *file,
+				unsigned int cmd, unsigned long arg)
+{
+	struct q6audio_in  *audio = file->private_data;
+	int rc = 0;
+	int cnt = 0;
+
+	switch (cmd) {
+	case AUDIO_START: {
+		struct msm_audio_amrnb_enc_config_v2 *enc_cfg;
+		enc_cfg = audio->enc_cfg;
+		pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__,
+				audio->ac->session, audio->buf_alloc);
+		if (audio->enabled == 1) {
+			pr_info("%s:AUDIO_START already over\n", __func__);
+			rc = 0;
+			break;
+		}
+		rc = audio_in_buf_alloc(audio);
+		if (rc < 0) {
+			pr_err("%s:session id %d: buffer allocation failed\n",
+				__func__, audio->ac->session);
+			break;
+		}
+
+		rc = q6asm_enc_cfg_blk_amrnb(audio->ac,
+			audio->buf_cfg.frames_per_buf,
+			enc_cfg->band_mode,
+			enc_cfg->dtx_enable);
+
+		if (rc < 0) {
+			pr_err("%s:session id %d: cmd amrnb media format block"
+				"failed\n", __func__, audio->ac->session);
+			break;
+		}
+		if (audio->feedback == NON_TUNNEL_MODE) {
+			rc = q6asm_media_format_block_pcm(audio->ac,
+				audio->pcm_cfg.sample_rate,
+				audio->pcm_cfg.channel_count);
+
+			if (rc < 0) {
+				pr_err("%s:session id %d: media format block"
+				"failed\n", __func__, audio->ac->session);
+				break;
+			}
+		}
+		pr_debug("%s:session id %d: AUDIO_START enable[%d]\n",
+				__func__, audio->ac->session,
+				audio->enabled);
+		rc = audio_in_enable(audio);
+		if (!rc) {
+			audio->enabled = 1;
+		} else {
+			audio->enabled = 0;
+			pr_err("%s:session id %d: Audio Start procedure failed"
+					"rc=%d\n", __func__,
+					audio->ac->session, rc);
+			break;
+		}
+		while (cnt++ < audio->str_cfg.buffer_count)
+			q6asm_read(audio->ac); /* Push buffer to DSP */
+		rc = 0;
+		pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n",
+				__func__, audio->ac->session, audio->enabled);
+		break;
+	}
+	case AUDIO_STOP: {
+		pr_debug("%s:AUDIO_STOP\n", __func__);
+		rc = audio_in_disable(audio);
+		if (rc  < 0) {
+			pr_err("%s:session id %d: Audio Stop procedure failed"
+				"rc=%d\n", __func__,
+				audio->ac->session, rc);
+			break;
+		}
+		break;
+	}
+	case AUDIO_GET_AMRNB_ENC_CONFIG_V2: {
+		if (copy_to_user((void *)arg, audio->enc_cfg,
+			sizeof(struct msm_audio_amrnb_enc_config_v2)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_AMRNB_ENC_CONFIG_V2: {
+		struct msm_audio_amrnb_enc_config_v2 cfg;
+		struct msm_audio_amrnb_enc_config_v2 *enc_cfg;
+		enc_cfg = audio->enc_cfg;
+		if (copy_from_user(&cfg, (void *) arg,
+				sizeof(struct msm_audio_amrnb_enc_config_v2))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (cfg.band_mode > 8 ||
+			 cfg.band_mode < 1) {
+			pr_err("%s:session id %d: invalid band mode\n",
+				__func__, audio->ac->session);
+			rc = -EINVAL;
+			break;
+		}
+		/* AMR NB encoder accepts values between 0-7
+		   while openmax provides value between 1-8
+		   as per spec */
+		enc_cfg->band_mode = (cfg.band_mode - 1);
+		enc_cfg->dtx_enable = (cfg.dtx_enable ? 1 : 0);
+		enc_cfg->frame_format = 0;
+		pr_debug("%s:session id %d: band_mode = 0x%x dtx_enable=0x%x\n",
+				__func__, audio->ac->session,
+				enc_cfg->band_mode, enc_cfg->dtx_enable);
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+static int amrnb_in_open(struct inode *inode, struct file *file)
+{
+	struct q6audio_in *audio = NULL;
+	struct msm_audio_amrnb_enc_config_v2 *enc_cfg;
+	int rc = 0;
+
+	audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
+
+	if (audio == NULL) {
+		pr_err("%s Could not allocate memory for amrnb"
+			"driver\n", __func__);
+		return -ENOMEM;
+	}
+	/* Allocate memory for encoder config param */
+	audio->enc_cfg = kzalloc(sizeof(struct msm_audio_amrnb_enc_config_v2),
+				GFP_KERNEL);
+	if (audio->enc_cfg == NULL) {
+		pr_err("%s:session id %d: Could not allocate memory for aac"
+				"config param\n", __func__, audio->ac->session);
+		kfree(audio);
+		return -ENOMEM;
+	}
+	enc_cfg = audio->enc_cfg;
+
+	mutex_init(&audio->lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->write_lock);
+	spin_lock_init(&audio->dsp_lock);
+	init_waitqueue_head(&audio->read_wait);
+	init_waitqueue_head(&audio->write_wait);
+
+	/* Settings will be re-config at AUDIO_SET_CONFIG,
+	* but at least we need to have initial config
+	*/
+	audio->str_cfg.buffer_size = FRAME_SIZE;
+	audio->str_cfg.buffer_count = FRAME_NUM;
+	audio->min_frame_size = 32;
+	audio->max_frames_per_buf = 10;
+	audio->pcm_cfg.buffer_size = PCM_BUF_SIZE;
+	audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
+	enc_cfg->band_mode = 7;
+	enc_cfg->dtx_enable = 0;
+	audio->pcm_cfg.channel_count = 1;
+	audio->pcm_cfg.sample_rate = 8000;
+	audio->buf_cfg.meta_info_enable = 0x01;
+	audio->buf_cfg.frames_per_buf = 0x01;
+
+	audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb,
+				(void *)audio);
+
+	if (!audio->ac) {
+		pr_err("%s: Could not allocate memory for audio"
+				"client\n", __func__);
+		kfree(audio->enc_cfg);
+		kfree(audio);
+		return -ENOMEM;
+	}
+
+	/* open amrnb encoder in T/NT mode */
+	if ((file->f_mode & FMODE_WRITE) &&
+		(file->f_mode & FMODE_READ)) {
+		audio->feedback = NON_TUNNEL_MODE;
+		rc = q6asm_open_read_write(audio->ac, FORMAT_AMRNB,
+					FORMAT_LINEAR_PCM);
+		if (rc < 0) {
+			pr_err("%s:session id %d: NT mode Open failed rc=%d\n",
+				__func__, audio->ac->session, rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		pr_info("%s:session id %d: NT mode encoder success\n",
+				__func__, audio->ac->session);
+	} else if (!(file->f_mode & FMODE_WRITE) &&
+				(file->f_mode & FMODE_READ)) {
+		audio->feedback = TUNNEL_MODE;
+		rc = q6asm_open_read(audio->ac, FORMAT_AMRNB);
+		if (rc < 0) {
+			pr_err("%s:session id %d: T mode Open failed rc=%d\n",
+				__func__, audio->ac->session, rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		/* register for tx overflow (valid for tunnel mode only) */
+		rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
+		if (rc < 0) {
+			pr_err("%s:session id %d: TX Overflow registration"
+				"failed rc=%d\n", __func__, audio->ac->session,
+				rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		pr_info("%s:session id %d: T mode encoder success\n",
+				__func__, audio->ac->session);
+	} else {
+		pr_err("%s:session id %d: Unexpected mode\n", __func__,
+				audio->ac->session);
+		rc = -EACCES;
+		goto fail;
+	}
+
+	audio->opened = 1;
+	atomic_set(&audio->in_count, PCM_BUF_COUNT);
+	atomic_set(&audio->out_count, 0x00);
+	audio->enc_ioctl = amrnb_in_ioctl;
+	file->private_data = audio;
+
+	pr_info("%s:session id %d: success\n", __func__, audio->ac->session);
+	return 0;
+fail:
+	q6asm_audio_client_free(audio->ac);
+	kfree(audio->enc_cfg);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= amrnb_in_open,
+	.release	= audio_in_release,
+	.read		= audio_in_read,
+	.write		= audio_in_write,
+	.unlocked_ioctl	= audio_in_ioctl,
+};
+
+struct miscdevice audio_amrnb_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_amrnb_in",
+	.fops	= &audio_in_fops,
+};
+
+static int __init amrnb_in_init(void)
+{
+	return misc_register(&audio_amrnb_in_misc);
+}
+
+device_initcall(amrnb_in_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/amrwb_in.c b/arch/arm/mach-msm/qdsp6v2/amrwb_in.c
new file mode 100644
index 0000000..d0462e0
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/amrwb_in.c
@@ -0,0 +1,282 @@
+/* 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
+ * 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/dma-mapping.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/msm_audio_amrwb.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include "audio_utils.h"
+
+/* Buffer with meta*/
+#define PCM_BUF_SIZE		(4096 + sizeof(struct meta_in))
+
+/* Maximum 10 frames in buffer with meta */
+#define FRAME_SIZE		(1 + ((61+sizeof(struct meta_out_dsp)) * 10))
+
+/* ------------------- device --------------------- */
+static long amrwb_in_ioctl(struct file *file,
+				unsigned int cmd, unsigned long arg)
+{
+	struct q6audio_in  *audio = file->private_data;
+	int rc = 0;
+	int cnt = 0;
+
+	switch (cmd) {
+	case AUDIO_START: {
+		struct msm_audio_amrwb_enc_config *enc_cfg;
+		enc_cfg = audio->enc_cfg;
+		pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__,
+				audio->ac->session, audio->buf_alloc);
+		if (audio->enabled == 1) {
+			pr_info("%s:AUDIO_START already over\n", __func__);
+			rc = 0;
+			break;
+		}
+		rc = audio_in_buf_alloc(audio);
+		if (rc < 0) {
+			pr_err("%s:session id %d: buffer allocation failed\n",
+				__func__, audio->ac->session);
+			break;
+		}
+
+		rc = q6asm_enc_cfg_blk_amrwb(audio->ac,
+			audio->buf_cfg.frames_per_buf,
+			enc_cfg->band_mode,
+			enc_cfg->dtx_enable);
+
+		if (rc < 0) {
+			pr_err("%s:session id %d: cmd amrwb media format block"
+				"failed\n", __func__, audio->ac->session);
+			break;
+		}
+		if (audio->feedback == NON_TUNNEL_MODE) {
+			rc = q6asm_media_format_block_pcm(audio->ac,
+				audio->pcm_cfg.sample_rate,
+				audio->pcm_cfg.channel_count);
+
+			if (rc < 0) {
+				pr_err("%s:session id %d: media format block"
+				"failed\n", __func__, audio->ac->session);
+				break;
+			}
+		}
+		pr_debug("%s:session id %d: AUDIO_START enable[%d]\n",
+				__func__, audio->ac->session,
+				audio->enabled);
+		rc = audio_in_enable(audio);
+		if (!rc) {
+			audio->enabled = 1;
+		} else {
+			audio->enabled = 0;
+			pr_err("%s:session id %d: Audio Start procedure failed"
+				"rc=%d\n", __func__, audio->ac->session, rc);
+			break;
+		}
+		while (cnt++ < audio->str_cfg.buffer_count)
+			q6asm_read(audio->ac); /* Push buffer to DSP */
+		rc = 0;
+		pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n",
+				__func__, audio->ac->session, audio->enabled);
+		break;
+	}
+	case AUDIO_STOP: {
+		pr_debug("%s:AUDIO_STOP\n", __func__);
+		rc = audio_in_disable(audio);
+		if (rc  < 0) {
+			pr_err("%s:session id %d: Audio Stop procedure failed"
+				"rc=%d\n", __func__, audio->ac->session, rc);
+			break;
+		}
+		break;
+	}
+	case AUDIO_GET_AMRWB_ENC_CONFIG: {
+		if (copy_to_user((void *)arg, audio->enc_cfg,
+			sizeof(struct msm_audio_amrwb_enc_config)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_AMRWB_ENC_CONFIG: {
+		struct msm_audio_amrwb_enc_config cfg;
+		struct msm_audio_amrwb_enc_config *enc_cfg;
+		enc_cfg = audio->enc_cfg;
+		if (copy_from_user(&cfg, (void *) arg,
+				sizeof(struct msm_audio_amrwb_enc_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (cfg.band_mode > 8) {
+			pr_err("%s:session id %d: invalid band mode\n",
+				__func__, audio->ac->session);
+			rc = -EINVAL;
+			break;
+		}
+		/* ToDo: AMR WB encoder accepts values between 0-8
+		   while openmax provides value between 9-17
+		   as per spec */
+		enc_cfg->band_mode = cfg.band_mode;
+		enc_cfg->dtx_enable = (cfg.dtx_enable ? 1 : 0);
+		/* Currently DSP does not support different frameformat */
+		enc_cfg->frame_format = 0;
+		pr_debug("%s:session id %d: band_mode = 0x%x dtx_enable=0x%x\n",
+				__func__, audio->ac->session,
+				enc_cfg->band_mode, enc_cfg->dtx_enable);
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+static int amrwb_in_open(struct inode *inode, struct file *file)
+{
+	struct q6audio_in *audio = NULL;
+	struct msm_audio_amrwb_enc_config *enc_cfg;
+	int rc = 0;
+
+	audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
+
+	if (audio == NULL) {
+		pr_err("%s: Could not allocate memory for amrwb driver\n",
+								__func__);
+		return -ENOMEM;
+	}
+	/* Allocate memory for encoder config param */
+	audio->enc_cfg = kzalloc(sizeof(struct msm_audio_amrwb_enc_config),
+				GFP_KERNEL);
+	if (audio->enc_cfg == NULL) {
+		pr_err("%s:session id %d: Could not allocate memory for amrwb"
+			"config param\n", __func__, audio->ac->session);
+		kfree(audio);
+		return -ENOMEM;
+	}
+	enc_cfg = audio->enc_cfg;
+
+	mutex_init(&audio->lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->write_lock);
+	spin_lock_init(&audio->dsp_lock);
+	init_waitqueue_head(&audio->read_wait);
+	init_waitqueue_head(&audio->write_wait);
+
+	/* Settings will be re-config at AUDIO_SET_CONFIG,
+	* but at least we need to have initial config
+	*/
+	audio->str_cfg.buffer_size = FRAME_SIZE;
+	audio->str_cfg.buffer_count = FRAME_NUM;
+	audio->min_frame_size = 32;
+	audio->max_frames_per_buf = 10;
+	audio->pcm_cfg.buffer_size = PCM_BUF_SIZE;
+	audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
+	enc_cfg->band_mode = 8;
+	enc_cfg->dtx_enable = 0;
+	audio->pcm_cfg.channel_count = 1;
+	audio->pcm_cfg.sample_rate = 16000;
+	audio->buf_cfg.meta_info_enable = 0x01;
+	audio->buf_cfg.frames_per_buf = 0x01;
+
+	audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb,
+				(void *)audio);
+
+	if (!audio->ac) {
+		pr_err("%s:audio[%p]: Could not allocate memory for audio"
+			"client\n", __func__, audio);
+		kfree(audio->enc_cfg);
+		kfree(audio);
+		return -ENOMEM;
+	}
+
+	/* open amrwb encoder in T/NT mode */
+	if ((file->f_mode & FMODE_WRITE) &&
+		(file->f_mode & FMODE_READ)) {
+		audio->feedback = NON_TUNNEL_MODE;
+		rc = q6asm_open_read_write(audio->ac, FORMAT_AMRWB,
+					FORMAT_LINEAR_PCM);
+		if (rc < 0) {
+			pr_err("%s:session id %d: NT mode Open failed rc=%d\n",
+				__func__, audio->ac->session, rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		pr_info("%s:session id %d: NT mode encoder success\n",
+				__func__, audio->ac->session);
+	} else if (!(file->f_mode & FMODE_WRITE) &&
+				(file->f_mode & FMODE_READ)) {
+		audio->feedback = TUNNEL_MODE;
+		rc = q6asm_open_read(audio->ac, FORMAT_AMRWB);
+		if (rc < 0) {
+			pr_err("%s:session id %d: T mode Open failed rc=%d\n",
+				__func__, audio->ac->session, rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		/* register for tx overflow (valid for tunnel mode only) */
+		rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
+		if (rc < 0) {
+			pr_err("%s:session id %d: TX Overflow registration"
+				"failed rc=%d\n", __func__, audio->ac->session,
+				rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		pr_info("%s:session id %d: T mode encoder success\n",
+				__func__, audio->ac->session);
+	} else {
+		pr_err("%s:session id %d: Unexpected mode\n", __func__,
+				audio->ac->session);
+		rc = -EACCES;
+		goto fail;
+	}
+
+	audio->opened = 1;
+	atomic_set(&audio->in_count, PCM_BUF_COUNT);
+	atomic_set(&audio->out_count, 0x00);
+	audio->enc_ioctl = amrwb_in_ioctl;
+	file->private_data = audio;
+
+	pr_info("%s:session id %d: success\n", __func__, audio->ac->session);
+	return 0;
+fail:
+	q6asm_audio_client_free(audio->ac);
+	kfree(audio->enc_cfg);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= amrwb_in_open,
+	.release	= audio_in_release,
+	.read		= audio_in_read,
+	.write		= audio_in_write,
+	.unlocked_ioctl	= audio_in_ioctl,
+};
+
+struct miscdevice audio_amrwb_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_amrwb_in",
+	.fops	= &audio_in_fops,
+};
+
+static int __init amrwb_in_init(void)
+{
+	return misc_register(&audio_amrwb_in_misc);
+}
+
+device_initcall(amrwb_in_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/apr.c b/arch/arm/mach-msm/qdsp6v2/apr.c
new file mode 100644
index 0000000..2403c02
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/apr.c
@@ -0,0 +1,688 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <asm/mach-types.h>
+#include <mach/peripheral-loader.h>
+#include <mach/msm_smd.h>
+#include <mach/qdsp6v2/apr.h>
+#include <mach/qdsp6v2/apr_tal.h>
+#include <mach/qdsp6v2/dsp_debug.h>
+#include <mach/subsystem_notif.h>
+#include <mach/subsystem_restart.h>
+
+struct apr_q6 q6;
+struct apr_client client[APR_DEST_MAX][APR_CLIENT_MAX];
+static atomic_t dsp_state;
+static atomic_t modem_state;
+
+static wait_queue_head_t  dsp_wait;
+static wait_queue_head_t  modem_wait;
+/* Subsystem restart: QDSP6 data, functions */
+static struct workqueue_struct *apr_reset_workqueue;
+static void apr_reset_deregister(struct work_struct *work);
+struct apr_reset_work {
+	void *handle;
+	struct work_struct work;
+};
+
+
+int apr_send_pkt(void *handle, uint32_t *buf)
+{
+	struct apr_svc *svc = handle;
+	struct apr_client *clnt;
+	struct apr_hdr *hdr;
+	uint16_t dest_id;
+	uint16_t client_id;
+	uint16_t w_len;
+	unsigned long flags;
+
+	if (!handle || !buf) {
+		pr_err("APR: Wrong parameters\n");
+		return -EINVAL;
+	}
+	if (svc->need_reset) {
+		pr_err("apr: send_pkt service need reset\n");
+		return -ENETRESET;
+	}
+
+	if ((svc->dest_id == APR_DEST_QDSP6) &&
+					(atomic_read(&dsp_state) == 0)) {
+		pr_err("apr: Still dsp is not Up\n");
+		return -ENETRESET;
+	} else if ((svc->dest_id == APR_DEST_MODEM) &&
+					(atomic_read(&modem_state) == 0)) {
+		pr_err("apr: Still Modem is not Up\n");
+		return -ENETRESET;
+	}
+
+
+	spin_lock_irqsave(&svc->w_lock, flags);
+	dest_id = svc->dest_id;
+	client_id = svc->client_id;
+	clnt = &client[dest_id][client_id];
+
+	if (!client[dest_id][client_id].handle) {
+		pr_err("APR: Still service is not yet opened\n");
+		spin_unlock_irqrestore(&svc->w_lock, flags);
+		return -EINVAL;
+	}
+	hdr = (struct apr_hdr *)buf;
+
+	hdr->src_domain = APR_DOMAIN_APPS;
+	hdr->src_svc = svc->id;
+	if (dest_id == APR_DEST_MODEM)
+		hdr->dest_domain = APR_DOMAIN_MODEM;
+	else if (dest_id == APR_DEST_QDSP6)
+		hdr->dest_domain = APR_DOMAIN_ADSP;
+
+	hdr->dest_svc = svc->id;
+
+	w_len = apr_tal_write(clnt->handle, buf, hdr->pkt_size);
+	if (w_len != hdr->pkt_size)
+		pr_err("Unable to write APR pkt successfully: %d\n", w_len);
+	spin_unlock_irqrestore(&svc->w_lock, flags);
+
+	return w_len;
+}
+
+static void apr_cb_func(void *buf, int len, void *priv)
+{
+	struct apr_client_data data;
+	struct apr_client *apr_client;
+	struct apr_svc *c_svc;
+	struct apr_hdr *hdr;
+	uint16_t hdr_size;
+	uint16_t msg_type;
+	uint16_t ver;
+	uint16_t src;
+	uint16_t svc;
+	uint16_t clnt;
+	int i;
+	int temp_port = 0;
+	uint32_t *ptr;
+
+	pr_debug("APR2: len = %d\n", len);
+	ptr = buf;
+	pr_debug("\n*****************\n");
+	for (i = 0; i < len/4; i++)
+		pr_debug("%x  ", ptr[i]);
+	pr_debug("\n");
+	pr_debug("\n*****************\n");
+
+	if (!buf || len <= APR_HDR_SIZE) {
+		pr_err("APR: Improper apr pkt received:%p %d\n",
+								buf, len);
+		return;
+	}
+	hdr = buf;
+
+	ver = hdr->hdr_field;
+	ver = (ver & 0x000F);
+	if (ver > APR_PKT_VER + 1) {
+		pr_err("APR: Wrong version: %d\n", ver);
+		return;
+	}
+
+	hdr_size = hdr->hdr_field;
+	hdr_size = ((hdr_size & 0x00F0) >> 0x4) * 4;
+	if (hdr_size < APR_HDR_SIZE) {
+		pr_err("APR: Wrong hdr size:%d\n", hdr_size);
+		return;
+	}
+
+	if (hdr->pkt_size < APR_HDR_SIZE) {
+		pr_err("APR: Wrong paket size\n");
+		return;
+	}
+	msg_type = hdr->hdr_field;
+	msg_type = (msg_type >> 0x08) & 0x0003;
+	if (msg_type >= APR_MSG_TYPE_MAX &&
+			msg_type != APR_BASIC_RSP_RESULT) {
+		pr_err("APR: Wrong message type: %d\n", msg_type);
+		return;
+	}
+
+	if (hdr->src_domain >= APR_DOMAIN_MAX ||
+		hdr->dest_domain >= APR_DOMAIN_MAX ||
+		hdr->src_svc >= APR_SVC_MAX ||
+		hdr->dest_svc >= APR_SVC_MAX) {
+		pr_err("APR: Wrong APR header\n");
+		return;
+	}
+
+	svc = hdr->dest_svc;
+	if (hdr->src_domain == APR_DOMAIN_MODEM) {
+		src = APR_DEST_MODEM;
+		if (svc == APR_SVC_MVS || svc == APR_SVC_MVM ||
+			svc == APR_SVC_CVS || svc == APR_SVC_CVP ||
+			svc == APR_SVC_TEST_CLIENT)
+			clnt = APR_CLIENT_VOICE;
+		else {
+			pr_err("APR: Wrong svc :%d\n", svc);
+			return;
+		}
+	} else if (hdr->src_domain == APR_DOMAIN_ADSP) {
+		src = APR_DEST_QDSP6;
+		if (svc == APR_SVC_AFE || svc == APR_SVC_ASM ||
+			svc == APR_SVC_VSM || svc == APR_SVC_VPM ||
+			svc == APR_SVC_ADM || svc == APR_SVC_ADSP_CORE ||
+			svc == APR_SVC_USM ||
+			svc == APR_SVC_TEST_CLIENT || svc == APR_SVC_ADSP_MVM ||
+			svc == APR_SVC_ADSP_CVS || svc == APR_SVC_ADSP_CVP)
+			clnt = APR_CLIENT_AUDIO;
+		else {
+			pr_err("APR: Wrong svc :%d\n", svc);
+			return;
+		}
+	} else {
+		pr_err("APR: Pkt from wrong source: %d\n", hdr->src_domain);
+		return;
+	}
+
+	pr_debug("src =%d clnt = %d\n", src, clnt);
+	apr_client = &client[src][clnt];
+	for (i = 0; i < APR_SVC_MAX; i++)
+		if (apr_client->svc[i].id == svc) {
+			pr_debug("%d\n", apr_client->svc[i].id);
+			c_svc = &apr_client->svc[i];
+			break;
+		}
+
+	if (i == APR_SVC_MAX) {
+		pr_err("APR: service is not registered\n");
+		return;
+	}
+	pr_debug("svc_idx = %d\n", i);
+	pr_debug("%x %x %x %p %p\n", c_svc->id, c_svc->dest_id,
+			c_svc->client_id, c_svc->fn, c_svc->priv);
+	data.payload_size = hdr->pkt_size - hdr_size;
+	data.opcode = hdr->opcode;
+	data.src = src;
+	data.src_port = hdr->src_port;
+	data.dest_port = hdr->dest_port;
+	data.token = hdr->token;
+	data.msg_type = msg_type;
+	if (data.payload_size > 0)
+		data.payload = (char *)hdr + hdr_size;
+
+	temp_port = ((data.src_port >> 8) * 8) + (data.src_port & 0xFF);
+	pr_debug("port = %d t_port = %d\n", data.src_port, temp_port);
+	if (c_svc->port_cnt && c_svc->port_fn[temp_port])
+		c_svc->port_fn[temp_port](&data,  c_svc->port_priv[temp_port]);
+	else if (c_svc->fn)
+		c_svc->fn(&data, c_svc->priv);
+	else
+		pr_err("APR: Rxed a packet for NULL callback\n");
+}
+
+struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
+					uint32_t src_port, void *priv)
+{
+	int client_id = 0;
+	int svc_idx = 0;
+	int svc_id = 0;
+	int dest_id = 0;
+	int temp_port = 0;
+	struct apr_svc *svc = NULL;
+	int rc = 0;
+
+	if (!dest || !svc_name || !svc_fn)
+		return NULL;
+
+	if (!strncmp(dest, "ADSP", 4))
+		dest_id = APR_DEST_QDSP6;
+	else if (!strncmp(dest, "MODEM", 5)) {
+		dest_id = APR_DEST_MODEM;
+	} else {
+		pr_err("APR: wrong destination\n");
+		goto done;
+	}
+
+	if ((dest_id == APR_DEST_QDSP6) &&
+				(atomic_read(&dsp_state) == 0)) {
+		pr_info("%s: Wait for Lpass to bootup\n", __func__);
+		rc = wait_event_interruptible_timeout(dsp_wait,
+				(atomic_read(&dsp_state) == 1), (1 * HZ));
+		if (rc == 0) {
+			pr_err("%s: DSP is not Up\n", __func__);
+			return NULL;
+		}
+		pr_info("%s: Lpass Up\n", __func__);
+	} else if ((dest_id == APR_DEST_MODEM) &&
+					(atomic_read(&modem_state) == 0)) {
+		pr_info("%s: Wait for modem to bootup\n", __func__);
+		rc = wait_event_interruptible_timeout(modem_wait,
+			(atomic_read(&modem_state) == 1), (1 * HZ));
+		if (rc == 0) {
+			pr_err("%s: Modem is not Up\n", __func__);
+			return NULL;
+		}
+		pr_info("%s: modem Up\n", __func__);
+	}
+
+	if (!strncmp(svc_name, "AFE", 3)) {
+		client_id = APR_CLIENT_AUDIO;
+		svc_idx = 0;
+		svc_id = APR_SVC_AFE;
+	} else if (!strncmp(svc_name, "ASM", 3)) {
+		client_id = APR_CLIENT_AUDIO;
+		svc_idx = 1;
+		svc_id = APR_SVC_ASM;
+	} else if (!strncmp(svc_name, "ADM", 3)) {
+		client_id = APR_CLIENT_AUDIO;
+		svc_idx = 2;
+		svc_id = APR_SVC_ADM;
+	} else if (!strncmp(svc_name, "CORE", 4)) {
+		client_id = APR_CLIENT_AUDIO;
+		svc_idx = 3;
+		svc_id = APR_SVC_ADSP_CORE;
+	} else if (!strncmp(svc_name, "TEST", 4)) {
+		if (dest_id == APR_DEST_QDSP6) {
+			client_id = APR_CLIENT_AUDIO;
+			svc_idx = 4;
+		} else {
+			client_id = APR_CLIENT_VOICE;
+			svc_idx = 7;
+		}
+		svc_id = APR_SVC_TEST_CLIENT;
+	} else if (!strncmp(svc_name, "VSM", 3)) {
+		client_id = APR_CLIENT_VOICE;
+		svc_idx = 0;
+		svc_id = APR_SVC_VSM;
+	} else if (!strncmp(svc_name, "VPM", 3)) {
+		client_id = APR_CLIENT_VOICE;
+		svc_idx = 1;
+		svc_id = APR_SVC_VPM;
+	} else if (!strncmp(svc_name, "MVS", 3)) {
+		client_id = APR_CLIENT_VOICE;
+		svc_idx = 2;
+		svc_id = APR_SVC_MVS;
+	} else if (!strncmp(svc_name, "MVM", 3)) {
+		if (dest_id == APR_DEST_MODEM) {
+			client_id = APR_CLIENT_VOICE;
+			svc_idx = 3;
+			svc_id = APR_SVC_MVM;
+		} else {
+			client_id = APR_CLIENT_AUDIO;
+			svc_idx = 5;
+			svc_id = APR_SVC_ADSP_MVM;
+		}
+	} else if (!strncmp(svc_name, "CVS", 3)) {
+		if (dest_id == APR_DEST_MODEM) {
+			client_id = APR_CLIENT_VOICE;
+			svc_idx = 4;
+			svc_id = APR_SVC_CVS;
+		} else {
+			client_id = APR_CLIENT_AUDIO;
+			svc_idx = 6;
+			svc_id = APR_SVC_ADSP_CVS;
+		}
+	} else if (!strncmp(svc_name, "CVP", 3)) {
+		if (dest_id == APR_DEST_MODEM) {
+			client_id = APR_CLIENT_VOICE;
+			svc_idx = 5;
+			svc_id = APR_SVC_CVP;
+		} else {
+			client_id = APR_CLIENT_AUDIO;
+			svc_idx = 7;
+			svc_id = APR_SVC_ADSP_CVP;
+		}
+	} else if (!strncmp(svc_name, "SRD", 3)) {
+		client_id = APR_CLIENT_VOICE;
+		svc_idx = 6;
+		svc_id = APR_SVC_SRD;
+	} else if (!strncmp(svc_name, "USM", 3)) {
+		client_id = APR_CLIENT_AUDIO;
+		svc_idx = 8;
+		svc_id = APR_SVC_USM;
+	} else {
+		pr_err("APR: Wrong svc name\n");
+		goto done;
+	}
+
+	pr_debug("svc name = %s c_id = %d dest_id = %d\n",
+				svc_name, client_id, dest_id);
+	mutex_lock(&q6.lock);
+	if (q6.state == APR_Q6_NOIMG) {
+		q6.pil = pil_get("q6");
+		if (IS_ERR(q6.pil)) {
+			rc = PTR_ERR(q6.pil);
+			pr_err("APR: Unable to load q6 image, error:%d\n", rc);
+			mutex_unlock(&q6.lock);
+			return svc;
+		}
+		q6.state = APR_Q6_LOADED;
+	}
+	mutex_unlock(&q6.lock);
+	mutex_lock(&client[dest_id][client_id].m_lock);
+	if (!client[dest_id][client_id].handle) {
+		client[dest_id][client_id].handle = apr_tal_open(client_id,
+				dest_id, APR_DL_SMD, apr_cb_func, NULL);
+		if (!client[dest_id][client_id].handle) {
+			svc = NULL;
+			pr_err("APR: Unable to open handle\n");
+			mutex_unlock(&client[dest_id][client_id].m_lock);
+			goto done;
+		}
+	}
+	mutex_unlock(&client[dest_id][client_id].m_lock);
+	svc = &client[dest_id][client_id].svc[svc_idx];
+	mutex_lock(&svc->m_lock);
+	client[dest_id][client_id].id = client_id;
+	if (svc->need_reset) {
+		mutex_unlock(&svc->m_lock);
+		pr_err("APR: Service needs reset\n");
+		goto done;
+	}
+	svc->priv = priv;
+	svc->id = svc_id;
+	svc->dest_id = dest_id;
+	svc->client_id = client_id;
+	if (src_port != 0xFFFFFFFF) {
+		temp_port = ((src_port >> 8) * 8) + (src_port & 0xFF);
+		pr_debug("port = %d t_port = %d\n", src_port, temp_port);
+		if (temp_port >= APR_MAX_PORTS || temp_port < 0) {
+			pr_err("APR: temp_port out of bounds\n");
+			mutex_unlock(&svc->m_lock);
+			return NULL;
+		}
+		if (!svc->port_cnt && !svc->svc_cnt)
+			client[dest_id][client_id].svc_cnt++;
+		svc->port_cnt++;
+		svc->port_fn[temp_port] = svc_fn;
+		svc->port_priv[temp_port] = priv;
+	} else {
+		if (!svc->fn) {
+			if (!svc->port_cnt && !svc->svc_cnt)
+				client[dest_id][client_id].svc_cnt++;
+			svc->fn = svc_fn;
+			if (svc->port_cnt)
+				svc->svc_cnt++;
+		}
+	}
+
+	mutex_unlock(&svc->m_lock);
+done:
+	return svc;
+}
+
+static void apr_reset_deregister(struct work_struct *work)
+{
+	struct apr_svc *handle = NULL;
+	struct apr_reset_work *apr_reset =
+			container_of(work, struct apr_reset_work, work);
+
+	handle = apr_reset->handle;
+	pr_debug("%s:handle[%p]\n", __func__, handle);
+	apr_deregister(handle);
+	kfree(apr_reset);
+}
+
+int apr_deregister(void *handle)
+{
+	struct apr_svc *svc = handle;
+	struct apr_client *clnt;
+	uint16_t dest_id;
+	uint16_t client_id;
+
+	if (!handle)
+		return -EINVAL;
+
+	mutex_lock(&svc->m_lock);
+	dest_id = svc->dest_id;
+	client_id = svc->client_id;
+	clnt = &client[dest_id][client_id];
+
+	if (svc->port_cnt > 0 || svc->svc_cnt > 0) {
+		if (svc->port_cnt)
+			svc->port_cnt--;
+		else if (svc->svc_cnt)
+			svc->svc_cnt--;
+		if (!svc->port_cnt && !svc->svc_cnt) {
+			client[dest_id][client_id].svc_cnt--;
+			svc->need_reset = 0x0;
+		}
+	} else if (client[dest_id][client_id].svc_cnt > 0) {
+		client[dest_id][client_id].svc_cnt--;
+		if (!client[dest_id][client_id].svc_cnt) {
+			svc->need_reset = 0x0;
+			pr_debug("%s: service is reset %p\n", __func__, svc);
+		}
+	}
+
+	if (!svc->port_cnt && !svc->svc_cnt) {
+		svc->priv = NULL;
+		svc->id = 0;
+		svc->fn = NULL;
+		svc->dest_id = 0;
+		svc->client_id = 0;
+		svc->need_reset = 0x0;
+	}
+	if (client[dest_id][client_id].handle &&
+		!client[dest_id][client_id].svc_cnt) {
+		apr_tal_close(client[dest_id][client_id].handle);
+		client[dest_id][client_id].handle = NULL;
+	}
+	mutex_unlock(&svc->m_lock);
+
+	return 0;
+}
+
+void apr_reset(void *handle)
+{
+	struct apr_reset_work *apr_reset_worker = NULL;
+
+	if (!handle)
+		return;
+	pr_debug("%s: handle[%p]\n", __func__, handle);
+
+	if (apr_reset_workqueue == NULL) {
+		pr_err("%s: apr_reset_workqueue is NULL\n", __func__);
+		return;
+	}
+
+	apr_reset_worker = kzalloc(sizeof(struct apr_reset_work),
+							GFP_ATOMIC);
+
+	if (apr_reset_worker == NULL) {
+		pr_err("%s: mem failure\n", __func__);
+		return;
+	}
+
+	apr_reset_worker->handle = handle;
+	INIT_WORK(&apr_reset_worker->work, apr_reset_deregister);
+	queue_work(apr_reset_workqueue, &apr_reset_worker->work);
+}
+
+void change_q6_state(int state)
+{
+	mutex_lock(&q6.lock);
+	q6.state = state;
+	mutex_unlock(&q6.lock);
+}
+
+int adsp_state(int state)
+{
+	pr_info("dsp state = %d\n", state);
+	return 0;
+}
+
+/* Dispatch the Reset events to Modem and audio clients */
+void dispatch_event(unsigned long code, unsigned short proc)
+{
+	struct apr_client *apr_client;
+	struct apr_client_data data;
+	struct apr_svc *svc;
+	uint16_t clnt;
+	int i, j;
+
+	data.opcode = RESET_EVENTS;
+	data.reset_event = code;
+	data.reset_proc = proc;
+
+	clnt = APR_CLIENT_AUDIO;
+	apr_client = &client[proc][clnt];
+	for (i = 0; i < APR_SVC_MAX; i++) {
+		mutex_lock(&apr_client->svc[i].m_lock);
+		if (apr_client->svc[i].fn) {
+			apr_client->svc[i].need_reset = 0x1;
+			apr_client->svc[i].fn(&data, apr_client->svc[i].priv);
+		}
+		if (apr_client->svc[i].port_cnt) {
+			svc = &(apr_client->svc[i]);
+			svc->need_reset = 0x1;
+			for (j = 0; j < APR_MAX_PORTS; j++)
+				if (svc->port_fn[j])
+					svc->port_fn[j](&data,
+						svc->port_priv[j]);
+		}
+		mutex_unlock(&apr_client->svc[i].m_lock);
+	}
+
+	clnt = APR_CLIENT_VOICE;
+	apr_client = &client[proc][clnt];
+	for (i = 0; i < APR_SVC_MAX; i++) {
+		mutex_lock(&apr_client->svc[i].m_lock);
+		if (apr_client->svc[i].fn) {
+			apr_client->svc[i].need_reset = 0x1;
+			apr_client->svc[i].fn(&data, apr_client->svc[i].priv);
+		}
+		if (apr_client->svc[i].port_cnt) {
+			svc = &(apr_client->svc[i]);
+			svc->need_reset = 0x1;
+			for (j = 0; j < APR_MAX_PORTS; j++)
+				if (svc->port_fn[j])
+					svc->port_fn[j](&data,
+						svc->port_priv[j]);
+		}
+		mutex_unlock(&apr_client->svc[i].m_lock);
+	}
+}
+
+static int modem_notifier_cb(struct notifier_block *this, unsigned long code,
+								void *_cmd)
+{
+	switch (code) {
+	case SUBSYS_BEFORE_SHUTDOWN:
+		pr_debug("M-Notify: Shutdown started\n");
+		atomic_set(&modem_state, 0);
+		dispatch_event(code, APR_DEST_MODEM);
+		break;
+	case SUBSYS_AFTER_SHUTDOWN:
+		pr_debug("M-Notify: Shutdown Completed\n");
+		break;
+	case SUBSYS_BEFORE_POWERUP:
+		pr_debug("M-notify: Bootup started\n");
+		break;
+	case SUBSYS_AFTER_POWERUP:
+		if (atomic_read(&modem_state) == 0) {
+			atomic_set(&modem_state, 1);
+			wake_up(&modem_wait);
+		}
+		pr_debug("M-Notify: Bootup Completed\n");
+		break;
+	default:
+		pr_err("M-Notify: General: %lu\n", code);
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block mnb = {
+	.notifier_call = modem_notifier_cb,
+};
+
+static int lpass_notifier_cb(struct notifier_block *this, unsigned long code,
+								void *_cmd)
+{
+	switch (code) {
+	case SUBSYS_BEFORE_SHUTDOWN:
+		pr_debug("L-Notify: Shutdown started\n");
+		atomic_set(&dsp_state, 0);
+		dispatch_event(code, APR_DEST_QDSP6);
+		break;
+	case SUBSYS_AFTER_SHUTDOWN:
+		pr_debug("L-Notify: Shutdown Completed\n");
+		break;
+	case SUBSYS_BEFORE_POWERUP:
+		pr_debug("L-notify: Bootup started\n");
+		break;
+	case SUBSYS_AFTER_POWERUP:
+		if (atomic_read(&dsp_state) == 0) {
+			atomic_set(&dsp_state, 1);
+			wake_up(&dsp_wait);
+		}
+		pr_debug("L-Notify: Bootup Completed\n");
+		break;
+	default:
+		pr_err("L-Notify: Generel: %lu\n", code);
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block lnb = {
+	.notifier_call = lpass_notifier_cb,
+};
+
+
+static int __init apr_init(void)
+{
+	int i, j, k;
+
+	for (i = 0; i < APR_DEST_MAX; i++)
+		for (j = 0; j < APR_CLIENT_MAX; j++) {
+			mutex_init(&client[i][j].m_lock);
+			for (k = 0; k < APR_SVC_MAX; k++) {
+				mutex_init(&client[i][j].svc[k].m_lock);
+				spin_lock_init(&client[i][j].svc[k].w_lock);
+			}
+		}
+	mutex_init(&q6.lock);
+	dsp_debug_register(adsp_state);
+	apr_reset_workqueue =
+		create_singlethread_workqueue("apr_driver");
+	if (!apr_reset_workqueue)
+		return -ENOMEM;
+	return 0;
+}
+device_initcall(apr_init);
+
+static int __init apr_late_init(void)
+{
+	int ret = 0;
+	init_waitqueue_head(&dsp_wait);
+	init_waitqueue_head(&modem_wait);
+	atomic_set(&dsp_state, 1);
+	atomic_set(&modem_state, 1);
+	subsys_notif_register_notifier("modem", &mnb);
+	subsys_notif_register_notifier("lpass", &lnb);
+	return ret;
+}
+late_initcall(apr_late_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/apr_tal.c b/arch/arm/mach-msm/qdsp6v2/apr_tal.c
new file mode 100644
index 0000000..03f0513
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/apr_tal.c
@@ -0,0 +1,280 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <mach/msm_smd.h>
+#include <mach/qdsp6v2/apr_tal.h>
+
+static char *svc_names[APR_DEST_MAX][APR_CLIENT_MAX] = {
+	{
+		"apr_audio_svc",
+		"apr_voice_svc",
+	},
+	{
+		"apr_audio_svc",
+		"apr_voice_svc",
+	},
+};
+
+struct apr_svc_ch_dev apr_svc_ch[APR_DL_MAX][APR_DEST_MAX][APR_CLIENT_MAX];
+
+int __apr_tal_write(struct apr_svc_ch_dev *apr_ch, void *data, int len)
+{
+	int w_len;
+	unsigned long flags;
+
+
+	spin_lock_irqsave(&apr_ch->w_lock, flags);
+	if (smd_write_avail(apr_ch->ch) < len) {
+		spin_unlock_irqrestore(&apr_ch->w_lock, flags);
+		return -EAGAIN;
+	}
+
+	w_len = smd_write(apr_ch->ch, data, len);
+	spin_unlock_irqrestore(&apr_ch->w_lock, flags);
+	pr_debug("apr_tal:w_len = %d\n", w_len);
+
+	if (w_len != len) {
+		pr_err("apr_tal: Error in write\n");
+		return -ENETRESET;
+	}
+	return w_len;
+}
+
+int apr_tal_write(struct apr_svc_ch_dev *apr_ch, void *data, int len)
+{
+	int rc = 0, retries = 0;
+
+	if (!apr_ch->ch)
+		return -EINVAL;
+
+	do {
+		if (rc == -EAGAIN)
+			udelay(50);
+
+		rc = __apr_tal_write(apr_ch, data, len);
+	} while (rc == -EAGAIN && retries++ < 300);
+
+	if (rc == -EAGAIN)
+		pr_err("apr_tal: TIMEOUT for write\n");
+
+	return rc;
+}
+
+static void apr_tal_notify(void *priv, unsigned event)
+{
+	struct apr_svc_ch_dev *apr_ch = priv;
+	int len, r_len, sz;
+	int pkt_cnt = 0;
+	unsigned long flags;
+
+	pr_debug("event = %d\n", event);
+	switch (event) {
+	case SMD_EVENT_DATA:
+		pkt_cnt = 0;
+		spin_lock_irqsave(&apr_ch->lock, flags);
+check_pending:
+		len = smd_read_avail(apr_ch->ch);
+		if (len < 0) {
+			pr_err("apr_tal: Invalid Read Event :%d\n", len);
+			spin_unlock_irqrestore(&apr_ch->lock, flags);
+			return;
+		}
+		sz = smd_cur_packet_size(apr_ch->ch);
+		if (sz < 0) {
+			pr_debug("pkt size is zero\n");
+			spin_unlock_irqrestore(&apr_ch->lock, flags);
+			return;
+		}
+		if (!len && !sz && !pkt_cnt)
+			goto check_write_avail;
+		if (!len) {
+			pr_debug("len = %d pkt_cnt = %d\n", len, pkt_cnt);
+			spin_unlock_irqrestore(&apr_ch->lock, flags);
+			return;
+		}
+		r_len = smd_read_from_cb(apr_ch->ch, apr_ch->data, len);
+		if (len != r_len) {
+			pr_err("apr_tal: Invalid Read\n");
+			spin_unlock_irqrestore(&apr_ch->lock, flags);
+			return;
+		}
+		pkt_cnt++;
+		pr_debug("%d %d %d\n", len, sz, pkt_cnt);
+		if (apr_ch->func)
+			apr_ch->func(apr_ch->data, r_len, apr_ch->priv);
+		goto check_pending;
+check_write_avail:
+		if (smd_write_avail(apr_ch->ch))
+			wake_up(&apr_ch->wait);
+		spin_unlock_irqrestore(&apr_ch->lock, flags);
+		break;
+	case SMD_EVENT_OPEN:
+		pr_info("apr_tal: SMD_EVENT_OPEN\n");
+		apr_ch->smd_state = 1;
+		wake_up(&apr_ch->wait);
+		break;
+	case SMD_EVENT_CLOSE:
+		pr_info("apr_tal: SMD_EVENT_CLOSE\n");
+		break;
+	}
+}
+
+struct apr_svc_ch_dev *apr_tal_open(uint32_t svc, uint32_t dest,
+				uint32_t dl, apr_svc_cb_fn func, void *priv)
+{
+	int rc;
+
+	if ((svc >= APR_CLIENT_MAX) || (dest >= APR_DEST_MAX) ||
+						(dl >= APR_DL_MAX)) {
+		pr_err("apr_tal: Invalid params\n");
+		return NULL;
+	}
+
+	if (apr_svc_ch[dl][dest][svc].ch) {
+		pr_err("apr_tal: This channel alreday openend\n");
+		return NULL;
+	}
+
+	mutex_lock(&apr_svc_ch[dl][dest][svc].m_lock);
+	if (!apr_svc_ch[dl][dest][svc].dest_state) {
+		rc = wait_event_timeout(apr_svc_ch[dl][dest][svc].dest,
+			apr_svc_ch[dl][dest][svc].dest_state,
+				msecs_to_jiffies(APR_OPEN_TIMEOUT_MS));
+		if (rc == 0) {
+			pr_err("apr_tal:open timeout\n");
+			mutex_unlock(&apr_svc_ch[dl][dest][svc].m_lock);
+			return NULL;
+		}
+		pr_debug("apr_tal:Wakeup done\n");
+		apr_svc_ch[dl][dest][svc].dest_state = 0;
+	}
+	rc = smd_named_open_on_edge(svc_names[dest][svc], dest,
+			&apr_svc_ch[dl][dest][svc].ch,
+			&apr_svc_ch[dl][dest][svc],
+			apr_tal_notify);
+	if (rc < 0) {
+		pr_err("apr_tal: smd_open failed %s\n",
+					svc_names[dest][svc]);
+		mutex_unlock(&apr_svc_ch[dl][dest][svc].m_lock);
+		return NULL;
+	}
+	rc = wait_event_timeout(apr_svc_ch[dl][dest][svc].wait,
+		(apr_svc_ch[dl][dest][svc].smd_state == 1), 5 * HZ);
+	if (rc == 0) {
+		pr_err("apr_tal:TIMEOUT for OPEN event\n");
+		mutex_unlock(&apr_svc_ch[dl][dest][svc].m_lock);
+		apr_tal_close(&apr_svc_ch[dl][dest][svc]);
+		return NULL;
+	}
+	if (!apr_svc_ch[dl][dest][svc].dest_state) {
+		apr_svc_ch[dl][dest][svc].dest_state = 1;
+		pr_debug("apr_tal:Waiting for apr svc init\n");
+		msleep(200);
+		pr_debug("apr_tal:apr svc init done\n");
+	}
+	apr_svc_ch[dl][dest][svc].smd_state = 0;
+
+	apr_svc_ch[dl][dest][svc].func = func;
+	apr_svc_ch[dl][dest][svc].priv = priv;
+	mutex_unlock(&apr_svc_ch[dl][dest][svc].m_lock);
+
+	return &apr_svc_ch[dl][dest][svc];
+}
+
+int apr_tal_close(struct apr_svc_ch_dev *apr_ch)
+{
+	int r;
+
+	if (!apr_ch->ch)
+		return -EINVAL;
+
+	mutex_lock(&apr_ch->m_lock);
+	r = smd_close(apr_ch->ch);
+	apr_ch->ch = NULL;
+	apr_ch->func = NULL;
+	apr_ch->priv = NULL;
+	mutex_unlock(&apr_ch->m_lock);
+	return r;
+}
+
+static int apr_smd_probe(struct platform_device *pdev)
+{
+	int dest;
+	int clnt;
+
+	if (pdev->id == APR_DEST_MODEM) {
+		pr_info("apr_tal:Modem Is Up\n");
+		dest = APR_DEST_MODEM;
+		clnt = APR_CLIENT_VOICE;
+		apr_svc_ch[APR_DL_SMD][dest][clnt].dest_state = 1;
+		wake_up(&apr_svc_ch[APR_DL_SMD][dest][clnt].dest);
+	} else if (pdev->id == APR_DEST_QDSP6) {
+		pr_info("apr_tal:Q6 Is Up\n");
+		dest = APR_DEST_QDSP6;
+		clnt = APR_CLIENT_AUDIO;
+		apr_svc_ch[APR_DL_SMD][dest][clnt].dest_state = 1;
+		wake_up(&apr_svc_ch[APR_DL_SMD][dest][clnt].dest);
+	} else
+		pr_err("apr_tal:Invalid Dest Id: %d\n", pdev->id);
+
+	return 0;
+}
+
+static struct platform_driver apr_q6_driver = {
+	.probe = apr_smd_probe,
+	.driver = {
+		.name = "apr_audio_svc",
+		.owner = THIS_MODULE,
+	},
+};
+
+static struct platform_driver apr_modem_driver = {
+	.probe = apr_smd_probe,
+	.driver = {
+		.name = "apr_voice_svc",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init apr_tal_init(void)
+{
+	int i, j, k;
+
+	for (i = 0; i < APR_DL_MAX; i++)
+		for (j = 0; j < APR_DEST_MAX; j++)
+			for (k = 0; k < APR_CLIENT_MAX; k++) {
+				init_waitqueue_head(&apr_svc_ch[i][j][k].wait);
+				init_waitqueue_head(&apr_svc_ch[i][j][k].dest);
+				spin_lock_init(&apr_svc_ch[i][j][k].lock);
+				spin_lock_init(&apr_svc_ch[i][j][k].w_lock);
+				mutex_init(&apr_svc_ch[i][j][k].m_lock);
+			}
+	platform_driver_register(&apr_q6_driver);
+	platform_driver_register(&apr_modem_driver);
+	return 0;
+}
+device_initcall(apr_tal_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_aac.c b/arch/arm/mach-msm/qdsp6v2/audio_aac.c
new file mode 100644
index 0000000..485234f
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_aac.c
@@ -0,0 +1,295 @@
+/* aac audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2010-2012, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/msm_audio_aac.h>
+#include "audio_utils_aio.h"
+
+#define AUDIO_AAC_DUAL_MONO_INVALID -1
+#define PCM_BUFSZ_MIN_AAC	((8*1024) + sizeof(struct dec_meta_out))
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations audio_aac_debug_fops = {
+	.read = audio_aio_debug_read,
+	.open = audio_aio_debug_open,
+};
+#endif
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct q6audio_aio *audio = file->private_data;
+	int rc = 0;
+	switch (cmd) {
+	case AUDIO_START: {
+		struct asm_aac_cfg aac_cfg;
+		struct msm_audio_aac_config *aac_config;
+		uint32_t sbr_ps = 0x00;
+		pr_debug("%s: AUDIO_START session_id[%d]\n", __func__,
+							audio->ac->session);
+		if (audio->feedback == NON_TUNNEL_MODE) {
+			/* Configure PCM output block */
+			rc = q6asm_enc_cfg_blk_pcm(audio->ac, 0, 0);
+			if (rc < 0) {
+				pr_err("pcm output block config failed\n");
+				break;
+			}
+		}
+		/* turn on both sbr and ps */
+		rc = q6asm_enable_sbrps(audio->ac, sbr_ps);
+		if (rc < 0)
+			pr_err("sbr-ps enable failed\n");
+		aac_config = (struct msm_audio_aac_config *)audio->codec_cfg;
+		if (aac_config->sbr_ps_on_flag)
+			aac_cfg.aot = AAC_ENC_MODE_EAAC_P;
+		else if (aac_config->sbr_on_flag)
+			aac_cfg.aot = AAC_ENC_MODE_AAC_P;
+		else
+			aac_cfg.aot = AAC_ENC_MODE_AAC_LC;
+
+		switch (aac_config->format) {
+		case AUDIO_AAC_FORMAT_ADTS:
+			aac_cfg.format = 0x00;
+			break;
+		case AUDIO_AAC_FORMAT_LOAS:
+			aac_cfg.format = 0x01;
+			break;
+		case AUDIO_AAC_FORMAT_ADIF:
+			aac_cfg.format = 0x02;
+			break;
+		default:
+		case AUDIO_AAC_FORMAT_RAW:
+			aac_cfg.format = 0x03;
+		}
+		aac_cfg.ep_config = aac_config->ep_config;
+		aac_cfg.section_data_resilience =
+			aac_config->aac_section_data_resilience_flag;
+		aac_cfg.scalefactor_data_resilience =
+			aac_config->aac_scalefactor_data_resilience_flag;
+		aac_cfg.spectral_data_resilience =
+			aac_config->aac_spectral_data_resilience_flag;
+		aac_cfg.ch_cfg = audio->pcm_cfg.channel_count;
+		aac_cfg.sample_rate =  audio->pcm_cfg.sample_rate;
+
+		pr_debug("%s:format=%x aot=%d  ch=%d sr=%d\n",
+			__func__, aac_cfg.format,
+			aac_cfg.aot, aac_cfg.ch_cfg,
+			aac_cfg.sample_rate);
+
+		/* Configure Media format block */
+		rc = q6asm_media_format_block_aac(audio->ac, &aac_cfg);
+		if (rc < 0) {
+			pr_err("cmd media format block failed\n");
+			break;
+		}
+		rc = audio_aio_enable(audio);
+		audio->eos_rsp = 0;
+		audio->eos_flag = 0;
+		if (!rc) {
+			audio->enabled = 1;
+		} else {
+			audio->enabled = 0;
+			pr_err("Audio Start procedure failed rc=%d\n", rc);
+			break;
+		}
+		pr_info("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
+						audio->ac->session,
+						audio->enabled);
+		if (audio->stopped == 1)
+			audio->stopped = 0;
+		break;
+	}
+	case AUDIO_GET_AAC_CONFIG: {
+		if (copy_to_user((void *)arg, audio->codec_cfg,
+			sizeof(struct msm_audio_aac_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		break;
+	}
+	case AUDIO_SET_AAC_CONFIG: {
+		struct msm_audio_aac_config *aac_config;
+		pr_debug("%s: AUDIO_SET_AAC_CONFIG\n", __func__);
+		if (copy_from_user(audio->codec_cfg, (void *)arg,
+			sizeof(struct msm_audio_aac_config))) {
+			rc = -EFAULT;
+			break;
+		} else {
+			uint16_t sce_left = 1, sce_right = 2;
+			aac_config = audio->codec_cfg;
+			if ((aac_config->dual_mono_mode <
+				AUDIO_AAC_DUAL_MONO_PL_PR) ||
+				(aac_config->dual_mono_mode >
+				AUDIO_AAC_DUAL_MONO_PL_SR)) {
+				pr_err("%s:AUDIO_SET_AAC_CONFIG: Invalid"
+					"dual_mono mode =%d\n", __func__,
+					aac_config->dual_mono_mode);
+			} else {
+				/* convert the data from user into sce_left
+				 * and sce_right based on the definitions
+				 */
+				pr_debug("%s: AUDIO_SET_AAC_CONFIG: modify"
+					 "dual_mono mode =%d\n", __func__,
+					 aac_config->dual_mono_mode);
+				switch (aac_config->dual_mono_mode) {
+				case AUDIO_AAC_DUAL_MONO_PL_PR:
+					sce_left = 1;
+					sce_right = 1;
+					break;
+				case AUDIO_AAC_DUAL_MONO_SL_SR:
+					sce_left = 2;
+					sce_right = 2;
+					break;
+				case AUDIO_AAC_DUAL_MONO_SL_PR:
+					sce_left = 2;
+					sce_right = 1;
+					break;
+				case AUDIO_AAC_DUAL_MONO_PL_SR:
+				default:
+					sce_left = 1;
+					sce_right = 2;
+					break;
+				}
+				rc = q6asm_cfg_dual_mono_aac(audio->ac,
+							sce_left, sce_right);
+				if (rc < 0)
+					pr_err("%s: asm cmd dualmono failed"
+						" rc=%d\n", __func__, rc);
+			}
+		}
+		break;
+	}
+	default:
+		pr_debug("%s[%p]: Calling utils ioctl\n", __func__, audio);
+		rc = audio->codec_ioctl(file, cmd, arg);
+		if (rc)
+			pr_err("%s[%p]:Failed in utils_ioctl: %d\n",
+				__func__, audio, rc);
+	}
+	return rc;
+}
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct q6audio_aio *audio = NULL;
+	int rc = 0;
+	struct msm_audio_aac_config *aac_config = NULL;
+
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_aac_" + 5];
+#endif
+	audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+	if (audio == NULL) {
+		pr_err("Could not allocate memory for aac decode driver\n");
+		return -ENOMEM;
+	}
+	audio->codec_cfg = kzalloc(sizeof(struct msm_audio_aac_config),
+					GFP_KERNEL);
+	if (audio->codec_cfg == NULL) {
+		pr_err("%s:Could not allocate memory for aac"
+			"config\n", __func__);
+		kfree(audio);
+		return -ENOMEM;
+	}
+	aac_config = audio->codec_cfg;
+
+	/* Settings will be re-config at AUDIO_SET_CONFIG,
+	 * but at least we need to have initial config
+	 */
+	audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN_AAC;
+	aac_config->dual_mono_mode = AUDIO_AAC_DUAL_MONO_INVALID;
+
+	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
+					     (void *)audio);
+
+	if (!audio->ac) {
+		pr_err("Could not allocate memory for audio client\n");
+		kfree(audio->codec_cfg);
+		kfree(audio);
+		return -ENOMEM;
+	}
+
+	/* open in T/NT mode */
+	if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+		rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+					   FORMAT_MPEG4_AAC);
+		if (rc < 0) {
+			pr_err("NT mode Open failed rc=%d\n", rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->feedback = NON_TUNNEL_MODE;
+		/* open AAC decoder, expected frames is always 1
+		audio->buf_cfg.frames_per_buf = 0x01;*/
+		audio->buf_cfg.meta_info_enable = 0x01;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+		rc = q6asm_open_write(audio->ac, FORMAT_MPEG4_AAC);
+		if (rc < 0) {
+			pr_err("T mode Open failed rc=%d\n", rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->feedback = TUNNEL_MODE;
+		audio->buf_cfg.meta_info_enable = 0x00;
+	} else {
+		pr_err("Not supported mode\n");
+		rc = -EACCES;
+		goto fail;
+	}
+	rc = audio_aio_open(audio, file);
+
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_aac_%04x", audio->ac->session);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+					    NULL, (void *)audio,
+					    &audio_aac_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		pr_debug("debugfs_create_file failed\n");
+#endif
+	pr_info("%s:aacdec success mode[%d]session[%d]\n", __func__,
+						audio->feedback,
+						audio->ac->session);
+	return rc;
+fail:
+	q6asm_audio_client_free(audio->ac);
+	kfree(audio->codec_cfg);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_aac_fops = {
+	.owner = THIS_MODULE,
+	.open = audio_open,
+	.release = audio_aio_release,
+	.unlocked_ioctl = audio_ioctl,
+	.fsync = audio_aio_fsync,
+};
+
+struct miscdevice audio_aac_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_aac",
+	.fops = &audio_aac_fops,
+};
+
+static int __init audio_aac_init(void)
+{
+	return misc_register(&audio_aac_misc);
+}
+
+device_initcall(audio_aac_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
new file mode 100644
index 0000000..e7a81d3
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
@@ -0,0 +1,941 @@
+/* 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
+ * 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/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <linux/ion.h>
+#include <linux/mm.h>
+#include <mach/qdsp6v2/audio_acdb.h>
+
+
+#define MAX_NETWORKS		12
+
+struct sidetone_atomic_cal {
+	atomic_t	enable;
+	atomic_t	gain;
+};
+
+
+struct acdb_data {
+	struct mutex		acdb_mutex;
+
+	/* ANC Cal */
+	struct acdb_atomic_cal_block	anc_cal;
+
+	/* AudProc Cal */
+	atomic_t			asm_topology;
+	atomic_t			adm_topology[MAX_AUDPROC_TYPES];
+	struct acdb_atomic_cal_block	audproc_cal[MAX_AUDPROC_TYPES];
+	struct acdb_atomic_cal_block	audstrm_cal[MAX_AUDPROC_TYPES];
+	struct acdb_atomic_cal_block	audvol_cal[MAX_AUDPROC_TYPES];
+
+	/* VocProc Cal */
+	atomic_t			voice_rx_topology;
+	atomic_t			voice_tx_topology;
+	struct acdb_atomic_cal_block	vocproc_cal[MAX_NETWORKS];
+	struct acdb_atomic_cal_block	vocstrm_cal[MAX_NETWORKS];
+	struct acdb_atomic_cal_block	vocvol_cal[MAX_NETWORKS];
+	/* size of cal block tables above*/
+	atomic_t			vocproc_cal_size;
+	atomic_t			vocstrm_cal_size;
+	atomic_t			vocvol_cal_size;
+	/* Total size of cal data for all networks */
+	atomic_t			vocproc_total_cal_size;
+	atomic_t			vocstrm_total_cal_size;
+	atomic_t			vocvol_total_cal_size;
+
+	/* AFE cal */
+	struct acdb_atomic_cal_block	afe_cal[MAX_AUDPROC_TYPES];
+
+	/* Sidetone Cal */
+	struct sidetone_atomic_cal	sidetone_cal;
+
+	/* Allocation information */
+	struct ion_client		*ion_client;
+	struct ion_handle		*ion_handle;
+	atomic_t			map_handle;
+	atomic64_t			paddr;
+	atomic64_t			kvaddr;
+	atomic64_t			mem_len;
+};
+
+static struct acdb_data		acdb_data;
+static atomic_t usage_count;
+
+uint32_t get_voice_rx_topology(void)
+{
+	return atomic_read(&acdb_data.voice_rx_topology);
+}
+
+void store_voice_rx_topology(uint32_t topology)
+{
+	atomic_set(&acdb_data.voice_rx_topology, topology);
+}
+
+uint32_t get_voice_tx_topology(void)
+{
+	return atomic_read(&acdb_data.voice_tx_topology);
+}
+
+void store_voice_tx_topology(uint32_t topology)
+{
+	atomic_set(&acdb_data.voice_tx_topology, topology);
+}
+
+uint32_t get_adm_rx_topology(void)
+{
+	return atomic_read(&acdb_data.adm_topology[RX_CAL]);
+}
+
+void store_adm_rx_topology(uint32_t topology)
+{
+	atomic_set(&acdb_data.adm_topology[RX_CAL], topology);
+}
+
+uint32_t get_adm_tx_topology(void)
+{
+	return atomic_read(&acdb_data.adm_topology[TX_CAL]);
+}
+
+void store_adm_tx_topology(uint32_t topology)
+{
+	atomic_set(&acdb_data.adm_topology[TX_CAL], topology);
+}
+
+uint32_t get_asm_topology(void)
+{
+	return atomic_read(&acdb_data.asm_topology);
+}
+
+void store_asm_topology(uint32_t topology)
+{
+	atomic_set(&acdb_data.asm_topology, topology);
+}
+
+void get_all_voice_cal(struct acdb_cal_block *cal_block)
+{
+	cal_block->cal_kvaddr =
+		atomic_read(&acdb_data.vocproc_cal[0].cal_kvaddr);
+	cal_block->cal_paddr =
+		atomic_read(&acdb_data.vocproc_cal[0].cal_paddr);
+	cal_block->cal_size =
+		atomic_read(&acdb_data.vocproc_total_cal_size) +
+		atomic_read(&acdb_data.vocstrm_total_cal_size) +
+		atomic_read(&acdb_data.vocvol_total_cal_size);
+}
+
+void get_all_cvp_cal(struct acdb_cal_block *cal_block)
+{
+	cal_block->cal_kvaddr =
+		atomic_read(&acdb_data.vocproc_cal[0].cal_kvaddr);
+	cal_block->cal_paddr =
+		atomic_read(&acdb_data.vocproc_cal[0].cal_paddr);
+	cal_block->cal_size =
+		atomic_read(&acdb_data.vocproc_total_cal_size) +
+		atomic_read(&acdb_data.vocvol_total_cal_size);
+}
+
+void get_all_vocproc_cal(struct acdb_cal_block *cal_block)
+{
+	cal_block->cal_kvaddr =
+		atomic_read(&acdb_data.vocproc_cal[0].cal_kvaddr);
+	cal_block->cal_paddr =
+		atomic_read(&acdb_data.vocproc_cal[0].cal_paddr);
+	cal_block->cal_size =
+		atomic_read(&acdb_data.vocproc_total_cal_size);
+}
+
+void get_all_vocstrm_cal(struct acdb_cal_block *cal_block)
+{
+	cal_block->cal_kvaddr =
+		atomic_read(&acdb_data.vocstrm_cal[0].cal_kvaddr);
+	cal_block->cal_paddr =
+		atomic_read(&acdb_data.vocstrm_cal[0].cal_paddr);
+	cal_block->cal_size =
+		atomic_read(&acdb_data.vocstrm_total_cal_size);
+}
+
+void get_all_vocvol_cal(struct acdb_cal_block *cal_block)
+{
+	cal_block->cal_kvaddr =
+		atomic_read(&acdb_data.vocvol_cal[0].cal_kvaddr);
+	cal_block->cal_paddr =
+		atomic_read(&acdb_data.vocvol_cal[0].cal_paddr);
+	cal_block->cal_size =
+		atomic_read(&acdb_data.vocvol_total_cal_size);
+}
+
+void get_anc_cal(struct acdb_cal_block *cal_block)
+{
+	pr_debug("%s\n", __func__);
+
+	if (cal_block == NULL) {
+		pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+		goto done;
+	}
+
+	cal_block->cal_kvaddr =
+		atomic_read(&acdb_data.anc_cal.cal_kvaddr);
+	cal_block->cal_paddr =
+		atomic_read(&acdb_data.anc_cal.cal_paddr);
+	cal_block->cal_size =
+		atomic_read(&acdb_data.anc_cal.cal_size);
+done:
+	return;
+}
+
+void store_anc_cal(struct cal_block *cal_block)
+{
+	pr_debug("%s,\n", __func__);
+
+	if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
+		pr_err("%s: offset %d is > mem_len %ld\n",
+			__func__, cal_block->cal_offset,
+			(long)atomic64_read(&acdb_data.mem_len));
+		goto done;
+	}
+
+	atomic_set(&acdb_data.anc_cal.cal_kvaddr,
+		cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+	atomic_set(&acdb_data.anc_cal.cal_paddr,
+		cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
+	atomic_set(&acdb_data.anc_cal.cal_size,
+		cal_block->cal_size);
+done:
+	return;
+}
+
+void store_afe_cal(int32_t path, struct cal_block *cal_block)
+{
+	pr_debug("%s, path = %d\n", __func__, path);
+
+	if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
+		pr_err("%s: offset %d is > mem_len %ld\n",
+			__func__, cal_block->cal_offset,
+			(long)atomic64_read(&acdb_data.mem_len));
+		goto done;
+	}
+	if ((path >= MAX_AUDPROC_TYPES) || (path < 0)) {
+		pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+			__func__, path);
+		goto done;
+	}
+
+	atomic_set(&acdb_data.afe_cal[path].cal_kvaddr,
+		cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+	atomic_set(&acdb_data.afe_cal[path].cal_paddr,
+		cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
+	atomic_set(&acdb_data.afe_cal[path].cal_size,
+		cal_block->cal_size);
+done:
+	return;
+}
+
+void get_afe_cal(int32_t path, struct acdb_cal_block *cal_block)
+{
+	pr_debug("%s, path = %d\n", __func__, path);
+
+	if (cal_block == NULL) {
+		pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+		goto done;
+	}
+	if ((path >= MAX_AUDPROC_TYPES) || (path < 0)) {
+		pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+			__func__, path);
+		goto done;
+	}
+
+	cal_block->cal_kvaddr =
+		atomic_read(&acdb_data.afe_cal[path].cal_kvaddr);
+	cal_block->cal_paddr =
+		atomic_read(&acdb_data.afe_cal[path].cal_paddr);
+	cal_block->cal_size =
+		atomic_read(&acdb_data.afe_cal[path].cal_size);
+done:
+	return;
+}
+
+void store_audproc_cal(int32_t path, struct cal_block *cal_block)
+{
+	pr_debug("%s, path = %d\n", __func__, path);
+
+	if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
+		pr_err("%s: offset %d is > mem_len %ld\n",
+			__func__, cal_block->cal_offset,
+			(long)atomic64_read(&acdb_data.mem_len));
+		goto done;
+	}
+	if (path >= MAX_AUDPROC_TYPES) {
+		pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+			__func__, path);
+		goto done;
+	}
+
+	atomic_set(&acdb_data.audproc_cal[path].cal_kvaddr,
+		cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+	atomic_set(&acdb_data.audproc_cal[path].cal_paddr,
+		cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
+	atomic_set(&acdb_data.audproc_cal[path].cal_size,
+		cal_block->cal_size);
+done:
+	return;
+}
+
+void get_audproc_cal(int32_t path, struct acdb_cal_block *cal_block)
+{
+	pr_debug("%s, path = %d\n", __func__, path);
+
+	if (cal_block == NULL) {
+		pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+		goto done;
+	}
+	if (path >= MAX_AUDPROC_TYPES) {
+		pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+			__func__, path);
+		goto done;
+	}
+
+	cal_block->cal_kvaddr =
+		atomic_read(&acdb_data.audproc_cal[path].cal_kvaddr);
+	cal_block->cal_paddr =
+		atomic_read(&acdb_data.audproc_cal[path].cal_paddr);
+	cal_block->cal_size =
+		atomic_read(&acdb_data.audproc_cal[path].cal_size);
+done:
+	return;
+}
+
+void store_audstrm_cal(int32_t path, struct cal_block *cal_block)
+{
+	pr_debug("%s, path = %d\n", __func__, path);
+
+	if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
+		pr_err("%s: offset %d is > mem_len %ld\n",
+			__func__, cal_block->cal_offset,
+			(long)atomic64_read(&acdb_data.mem_len));
+		goto done;
+	}
+	if (path >= MAX_AUDPROC_TYPES) {
+		pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+			__func__, path);
+		goto done;
+	}
+
+	atomic_set(&acdb_data.audstrm_cal[path].cal_kvaddr,
+		cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+	atomic_set(&acdb_data.audstrm_cal[path].cal_paddr,
+		cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
+	atomic_set(&acdb_data.audstrm_cal[path].cal_size,
+		cal_block->cal_size);
+done:
+	return;
+}
+
+void get_audstrm_cal(int32_t path, struct acdb_cal_block *cal_block)
+{
+	pr_debug("%s, path = %d\n", __func__, path);
+
+	if (cal_block == NULL) {
+		pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+		goto done;
+	}
+	if (path >= MAX_AUDPROC_TYPES) {
+		pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+			__func__, path);
+		goto done;
+	}
+
+	cal_block->cal_kvaddr =
+		atomic_read(&acdb_data.audstrm_cal[path].cal_kvaddr);
+	cal_block->cal_paddr =
+		atomic_read(&acdb_data.audstrm_cal[path].cal_paddr);
+	cal_block->cal_size =
+		atomic_read(&acdb_data.audstrm_cal[path].cal_size);
+done:
+	return;
+}
+
+void store_audvol_cal(int32_t path, struct cal_block *cal_block)
+{
+	pr_debug("%s, path = %d\n", __func__, path);
+
+	if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
+		pr_err("%s: offset %d is > mem_len %ld\n",
+			__func__, cal_block->cal_offset,
+			(long)atomic64_read(&acdb_data.mem_len));
+		goto done;
+	}
+	if (path >= MAX_AUDPROC_TYPES) {
+		pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+			__func__, path);
+		goto done;
+	}
+
+	atomic_set(&acdb_data.audvol_cal[path].cal_kvaddr,
+		cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+	atomic_set(&acdb_data.audvol_cal[path].cal_paddr,
+		cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
+	atomic_set(&acdb_data.audvol_cal[path].cal_size,
+		cal_block->cal_size);
+done:
+	return;
+}
+
+void get_audvol_cal(int32_t path, struct acdb_cal_block *cal_block)
+{
+	pr_debug("%s, path = %d\n", __func__, path);
+
+	if (cal_block == NULL) {
+		pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+		goto done;
+	}
+	if (path >= MAX_AUDPROC_TYPES || path < 0) {
+		pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+			__func__, path);
+		goto done;
+	}
+
+	cal_block->cal_kvaddr =
+		atomic_read(&acdb_data.audvol_cal[path].cal_kvaddr);
+	cal_block->cal_paddr =
+		atomic_read(&acdb_data.audvol_cal[path].cal_paddr);
+	cal_block->cal_size =
+		atomic_read(&acdb_data.audvol_cal[path].cal_size);
+done:
+	return;
+}
+
+
+void store_vocproc_cal(int32_t len, struct cal_block *cal_blocks)
+{
+	int i;
+	pr_debug("%s\n", __func__);
+
+	if (len > MAX_NETWORKS) {
+		pr_err("%s: Calibration sent for %d networks, only %d are "
+			"supported!\n", __func__, len, MAX_NETWORKS);
+		goto done;
+	}
+
+	atomic_set(&acdb_data.vocproc_total_cal_size, 0);
+	for (i = 0; i < len; i++) {
+		if (cal_blocks[i].cal_offset >
+					atomic64_read(&acdb_data.mem_len)) {
+			pr_err("%s: offset %d is > mem_len %ld\n",
+				__func__, cal_blocks[i].cal_offset,
+				(long)atomic64_read(&acdb_data.mem_len));
+			atomic_set(&acdb_data.vocproc_cal[i].cal_size, 0);
+		} else {
+			atomic_add(cal_blocks[i].cal_size,
+				&acdb_data.vocproc_total_cal_size);
+			atomic_set(&acdb_data.vocproc_cal[i].cal_size,
+				cal_blocks[i].cal_size);
+			atomic_set(&acdb_data.vocproc_cal[i].cal_paddr,
+				cal_blocks[i].cal_offset +
+				atomic64_read(&acdb_data.paddr));
+			atomic_set(&acdb_data.vocproc_cal[i].cal_kvaddr,
+				cal_blocks[i].cal_offset +
+				atomic64_read(&acdb_data.kvaddr));
+		}
+	}
+	atomic_set(&acdb_data.vocproc_cal_size, len);
+done:
+	return;
+}
+
+void get_vocproc_cal(struct acdb_cal_data *cal_data)
+{
+	pr_debug("%s\n", __func__);
+
+	if (cal_data == NULL) {
+		pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+		goto done;
+	}
+
+	cal_data->num_cal_blocks = atomic_read(&acdb_data.vocproc_cal_size);
+	cal_data->cal_blocks = &acdb_data.vocproc_cal[0];
+done:
+	return;
+}
+
+void store_vocstrm_cal(int32_t len, struct cal_block *cal_blocks)
+{
+	int i;
+	pr_debug("%s\n", __func__);
+
+	if (len > MAX_NETWORKS) {
+		pr_err("%s: Calibration sent for %d networks, only %d are "
+			"supported!\n", __func__, len, MAX_NETWORKS);
+		goto done;
+	}
+
+	atomic_set(&acdb_data.vocstrm_total_cal_size, 0);
+	for (i = 0; i < len; i++) {
+		if (cal_blocks[i].cal_offset >
+					atomic64_read(&acdb_data.mem_len)) {
+			pr_err("%s: offset %d is > mem_len %ld\n",
+				__func__, cal_blocks[i].cal_offset,
+				(long)atomic64_read(&acdb_data.mem_len));
+			atomic_set(&acdb_data.vocstrm_cal[i].cal_size, 0);
+		} else {
+			atomic_add(cal_blocks[i].cal_size,
+				&acdb_data.vocstrm_total_cal_size);
+			atomic_set(&acdb_data.vocstrm_cal[i].cal_size,
+				cal_blocks[i].cal_size);
+			atomic_set(&acdb_data.vocstrm_cal[i].cal_paddr,
+				cal_blocks[i].cal_offset +
+				atomic64_read(&acdb_data.paddr));
+			atomic_set(&acdb_data.vocstrm_cal[i].cal_kvaddr,
+				cal_blocks[i].cal_offset +
+				atomic64_read(&acdb_data.kvaddr));
+		}
+	}
+	atomic_set(&acdb_data.vocstrm_cal_size, len);
+done:
+	return;
+}
+
+void get_vocstrm_cal(struct acdb_cal_data *cal_data)
+{
+	pr_debug("%s\n", __func__);
+
+	if (cal_data == NULL) {
+		pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+		goto done;
+	}
+
+	cal_data->num_cal_blocks = atomic_read(&acdb_data.vocstrm_cal_size);
+	cal_data->cal_blocks = &acdb_data.vocstrm_cal[0];
+done:
+	return;
+}
+
+void store_vocvol_cal(int32_t len, struct cal_block *cal_blocks)
+{
+	int i;
+	pr_debug("%s\n", __func__);
+
+	if (len > MAX_NETWORKS) {
+		pr_err("%s: Calibration sent for %d networks, only %d are "
+			"supported!\n", __func__, len, MAX_NETWORKS);
+		goto done;
+	}
+
+	atomic_set(&acdb_data.vocvol_total_cal_size, 0);
+	for (i = 0; i < len; i++) {
+		if (cal_blocks[i].cal_offset >
+					atomic64_read(&acdb_data.mem_len)) {
+			pr_err("%s: offset %d is > mem_len %ld\n",
+				__func__, cal_blocks[i].cal_offset,
+				(long)atomic64_read(&acdb_data.mem_len));
+			atomic_set(&acdb_data.vocvol_cal[i].cal_size, 0);
+		} else {
+			atomic_add(cal_blocks[i].cal_size,
+				&acdb_data.vocvol_total_cal_size);
+			atomic_set(&acdb_data.vocvol_cal[i].cal_size,
+				cal_blocks[i].cal_size);
+			atomic_set(&acdb_data.vocvol_cal[i].cal_paddr,
+				cal_blocks[i].cal_offset +
+				atomic64_read(&acdb_data.paddr));
+			atomic_set(&acdb_data.vocvol_cal[i].cal_kvaddr,
+				cal_blocks[i].cal_offset +
+				atomic64_read(&acdb_data.kvaddr));
+		}
+	}
+	atomic_set(&acdb_data.vocvol_cal_size, len);
+done:
+	return;
+}
+
+void get_vocvol_cal(struct acdb_cal_data *cal_data)
+{
+	pr_debug("%s\n", __func__);
+
+	if (cal_data == NULL) {
+		pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+		goto done;
+	}
+
+	cal_data->num_cal_blocks = atomic_read(&acdb_data.vocvol_cal_size);
+	cal_data->cal_blocks = &acdb_data.vocvol_cal[0];
+done:
+	return;
+}
+
+void store_sidetone_cal(struct sidetone_cal *cal_data)
+{
+	pr_debug("%s\n", __func__);
+
+	atomic_set(&acdb_data.sidetone_cal.enable, cal_data->enable);
+	atomic_set(&acdb_data.sidetone_cal.gain, cal_data->gain);
+}
+
+
+void get_sidetone_cal(struct sidetone_cal *cal_data)
+{
+	pr_debug("%s\n", __func__);
+
+	if (cal_data == NULL) {
+		pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+		goto done;
+	}
+
+	cal_data->enable = atomic_read(&acdb_data.sidetone_cal.enable);
+	cal_data->gain = atomic_read(&acdb_data.sidetone_cal.gain);
+done:
+	return;
+}
+
+static int acdb_open(struct inode *inode, struct file *f)
+{
+	s32 result = 0;
+	pr_debug("%s\n", __func__);
+
+	if (atomic64_read(&acdb_data.mem_len)) {
+		pr_debug("%s: ACDB opened but memory allocated, "
+			"using existing allocation!\n",
+			__func__);
+	}
+
+	atomic_inc(&usage_count);
+	return result;
+}
+
+static int deregister_memory(void)
+{
+	if (atomic64_read(&acdb_data.mem_len)) {
+		mutex_lock(&acdb_data.acdb_mutex);
+		ion_unmap_kernel(acdb_data.ion_client, acdb_data.ion_handle);
+		ion_free(acdb_data.ion_client, acdb_data.ion_handle);
+		ion_client_destroy(acdb_data.ion_client);
+		mutex_unlock(&acdb_data.acdb_mutex);
+		atomic64_set(&acdb_data.mem_len, 0);
+	}
+	return 0;
+}
+
+static int register_memory(void)
+{
+	int			result;
+	unsigned long		paddr;
+	void                    *kvptr;
+	unsigned long		kvaddr;
+	unsigned long		mem_len;
+
+	mutex_lock(&acdb_data.acdb_mutex);
+	acdb_data.ion_client =
+		msm_ion_client_create(UINT_MAX, "audio_acdb_client");
+	if (IS_ERR_OR_NULL(acdb_data.ion_client)) {
+		pr_err("%s: Could not register ION client!!!\n", __func__);
+		result = PTR_ERR(acdb_data.ion_client);
+		goto err;
+	}
+
+	acdb_data.ion_handle = ion_import_fd(acdb_data.ion_client,
+		atomic_read(&acdb_data.map_handle));
+	if (IS_ERR_OR_NULL(acdb_data.ion_handle)) {
+		pr_err("%s: Could not import map handle!!!\n", __func__);
+		result = PTR_ERR(acdb_data.ion_handle);
+		goto err_ion_client;
+	}
+
+	result = ion_phys(acdb_data.ion_client, acdb_data.ion_handle,
+				&paddr, (size_t *)&mem_len);
+	if (result != 0) {
+		pr_err("%s: Could not get phys addr!!!\n", __func__);
+		goto err_ion_handle;
+	}
+
+	kvptr = ion_map_kernel(acdb_data.ion_client,
+		acdb_data.ion_handle, 0);
+	if (IS_ERR_OR_NULL(kvptr)) {
+		pr_err("%s: Could not get kernel virt addr!!!\n", __func__);
+		result = PTR_ERR(kvptr);
+		goto err_ion_handle;
+	}
+	kvaddr = (unsigned long)kvptr;
+	mutex_unlock(&acdb_data.acdb_mutex);
+
+	atomic64_set(&acdb_data.paddr, paddr);
+	atomic64_set(&acdb_data.kvaddr, kvaddr);
+	atomic64_set(&acdb_data.mem_len, mem_len);
+	pr_debug("%s done! paddr = 0x%lx, "
+		"kvaddr = 0x%lx, len = x%lx\n",
+		 __func__,
+		(long)atomic64_read(&acdb_data.paddr),
+		(long)atomic64_read(&acdb_data.kvaddr),
+		(long)atomic64_read(&acdb_data.mem_len));
+
+	return result;
+err_ion_handle:
+	ion_free(acdb_data.ion_client, acdb_data.ion_handle);
+err_ion_client:
+	ion_client_destroy(acdb_data.ion_client);
+err:
+	atomic64_set(&acdb_data.mem_len, 0);
+	mutex_unlock(&acdb_data.acdb_mutex);
+	return result;
+}
+static long acdb_ioctl(struct file *f,
+		unsigned int cmd, unsigned long arg)
+{
+	int32_t			result = 0;
+	int32_t			size;
+	int32_t			map_fd;
+	uint32_t		topology;
+	struct cal_block	data[MAX_NETWORKS];
+	pr_debug("%s\n", __func__);
+
+	switch (cmd) {
+	case AUDIO_REGISTER_PMEM:
+		pr_debug("AUDIO_REGISTER_PMEM\n");
+		if (atomic_read(&acdb_data.mem_len)) {
+			deregister_memory();
+			pr_debug("Remove the existing memory\n");
+		}
+
+		if (copy_from_user(&map_fd, (void *)arg, sizeof(map_fd))) {
+			pr_err("%s: fail to copy memory handle!\n", __func__);
+			result = -EFAULT;
+		} else {
+			atomic_set(&acdb_data.map_handle, map_fd);
+			result = register_memory();
+		}
+		goto done;
+
+	case AUDIO_DEREGISTER_PMEM:
+		pr_debug("AUDIO_DEREGISTER_PMEM\n");
+		deregister_memory();
+		goto done;
+	case AUDIO_SET_VOICE_RX_TOPOLOGY:
+		if (copy_from_user(&topology, (void *)arg,
+				sizeof(topology))) {
+			pr_err("%s: fail to copy topology!\n", __func__);
+			result = -EFAULT;
+		}
+		store_voice_rx_topology(topology);
+		goto done;
+	case AUDIO_SET_VOICE_TX_TOPOLOGY:
+		if (copy_from_user(&topology, (void *)arg,
+				sizeof(topology))) {
+			pr_err("%s: fail to copy topology!\n", __func__);
+			result = -EFAULT;
+		}
+		store_voice_tx_topology(topology);
+		goto done;
+	case AUDIO_SET_ADM_RX_TOPOLOGY:
+		if (copy_from_user(&topology, (void *)arg,
+				sizeof(topology))) {
+			pr_err("%s: fail to copy topology!\n", __func__);
+			result = -EFAULT;
+		}
+		store_adm_rx_topology(topology);
+		goto done;
+	case AUDIO_SET_ADM_TX_TOPOLOGY:
+		if (copy_from_user(&topology, (void *)arg,
+				sizeof(topology))) {
+			pr_err("%s: fail to copy topology!\n", __func__);
+			result = -EFAULT;
+		}
+		store_adm_tx_topology(topology);
+		goto done;
+	case AUDIO_SET_ASM_TOPOLOGY:
+		if (copy_from_user(&topology, (void *)arg,
+				sizeof(topology))) {
+			pr_err("%s: fail to copy topology!\n", __func__);
+			result = -EFAULT;
+		}
+		store_asm_topology(topology);
+		goto done;
+	}
+
+	if (copy_from_user(&size, (void *) arg, sizeof(size))) {
+
+		result = -EFAULT;
+		goto done;
+	}
+
+	if (size <= 0) {
+		pr_err("%s: Invalid size sent to driver: %d\n",
+			__func__, size);
+		result = -EFAULT;
+		goto done;
+	}
+
+	if (copy_from_user(data, (void *)(arg + sizeof(size)), size)) {
+
+		pr_err("%s: fail to copy table size %d\n", __func__, size);
+		result = -EFAULT;
+		goto done;
+	}
+
+	if (data == NULL) {
+		pr_err("%s: NULL pointer sent to driver!\n", __func__);
+		result = -EFAULT;
+		goto done;
+	}
+
+	switch (cmd) {
+	case AUDIO_SET_AUDPROC_TX_CAL:
+		if (size > sizeof(struct cal_block))
+			pr_err("%s: More Audproc Cal then expected, "
+				"size received: %d\n", __func__, size);
+		store_audproc_cal(TX_CAL, data);
+		break;
+	case AUDIO_SET_AUDPROC_RX_CAL:
+		if (size > sizeof(struct cal_block))
+			pr_err("%s: More Audproc Cal then expected, "
+				"size received: %d\n", __func__, size);
+		store_audproc_cal(RX_CAL, data);
+		break;
+	case AUDIO_SET_AUDPROC_TX_STREAM_CAL:
+		if (size > sizeof(struct cal_block))
+			pr_err("%s: More Audproc Cal then expected, "
+				"size received: %d\n", __func__, size);
+		store_audstrm_cal(TX_CAL, data);
+		break;
+	case AUDIO_SET_AUDPROC_RX_STREAM_CAL:
+		if (size > sizeof(struct cal_block))
+			pr_err("%s: More Audproc Cal then expected, "
+				"size received: %d\n", __func__, size);
+		store_audstrm_cal(RX_CAL, data);
+		break;
+	case AUDIO_SET_AUDPROC_TX_VOL_CAL:
+		if (size > sizeof(struct cal_block))
+			pr_err("%s: More Audproc Cal then expected, "
+				"size received: %d\n", __func__, size);
+		store_audvol_cal(TX_CAL, data);
+		break;
+	case AUDIO_SET_AUDPROC_RX_VOL_CAL:
+		if (size > sizeof(struct cal_block))
+			pr_err("%s: More Audproc Cal then expected, "
+				"size received: %d\n", __func__, size);
+		store_audvol_cal(RX_CAL, data);
+		break;
+	case AUDIO_SET_AFE_TX_CAL:
+		if (size > sizeof(struct cal_block))
+			pr_err("%s: More AFE Cal then expected, "
+				"size received: %d\n", __func__, size);
+		store_afe_cal(TX_CAL, data);
+		break;
+	case AUDIO_SET_AFE_RX_CAL:
+		if (size > sizeof(struct cal_block))
+			pr_err("%s: More AFE Cal then expected, "
+				"size received: %d\n", __func__, size);
+		store_afe_cal(RX_CAL, data);
+		break;
+	case AUDIO_SET_VOCPROC_CAL:
+		store_vocproc_cal(size / sizeof(struct cal_block), data);
+		break;
+	case AUDIO_SET_VOCPROC_STREAM_CAL:
+		store_vocstrm_cal(size / sizeof(struct cal_block), data);
+		break;
+	case AUDIO_SET_VOCPROC_VOL_CAL:
+		store_vocvol_cal(size / sizeof(struct cal_block), data);
+		break;
+	case AUDIO_SET_SIDETONE_CAL:
+		if (size > sizeof(struct sidetone_cal))
+			pr_err("%s: More sidetone cal then expected, "
+				"size received: %d\n", __func__, size);
+		store_sidetone_cal((struct sidetone_cal *)data);
+		break;
+	case AUDIO_SET_ANC_CAL:
+		store_anc_cal(data);
+		break;
+	default:
+		pr_err("ACDB=> ACDB ioctl not found!\n");
+	}
+
+done:
+	return result;
+}
+
+static int acdb_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	int result = 0;
+	int size = vma->vm_end - vma->vm_start;
+
+	pr_debug("%s\n", __func__);
+
+	if (atomic64_read(&acdb_data.mem_len)) {
+		if (size <= atomic64_read(&acdb_data.mem_len)) {
+			vma->vm_page_prot = pgprot_noncached(
+						vma->vm_page_prot);
+			result = remap_pfn_range(vma,
+				vma->vm_start,
+				atomic64_read(&acdb_data.paddr) >> PAGE_SHIFT,
+				size,
+				vma->vm_page_prot);
+		} else {
+			pr_err("%s: Not enough memory!\n", __func__);
+			result = -ENOMEM;
+		}
+	} else {
+		pr_err("%s: memory is not allocated, yet!\n", __func__);
+		result = -ENODEV;
+	}
+
+	return result;
+}
+
+static int acdb_release(struct inode *inode, struct file *f)
+{
+	s32 result = 0;
+
+	atomic_dec(&usage_count);
+	atomic_read(&usage_count);
+
+	pr_debug("%s: ref count %d!\n", __func__,
+		atomic_read(&usage_count));
+
+	if (atomic_read(&usage_count) >= 1)
+		result = -EBUSY;
+	else
+		result = deregister_memory();
+
+	return result;
+}
+
+static const struct file_operations acdb_fops = {
+	.owner = THIS_MODULE,
+	.open = acdb_open,
+	.release = acdb_release,
+	.unlocked_ioctl = acdb_ioctl,
+	.mmap = acdb_mmap,
+};
+
+struct miscdevice acdb_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_acdb",
+	.fops	= &acdb_fops,
+};
+
+static int __init acdb_init(void)
+{
+	memset(&acdb_data, 0, sizeof(acdb_data));
+	mutex_init(&acdb_data.acdb_mutex);
+	atomic_set(&usage_count, 0);
+	return misc_register(&acdb_misc);
+}
+
+static void __exit acdb_exit(void)
+{
+}
+
+module_init(acdb_init);
+module_exit(acdb_exit);
+
+MODULE_DESCRIPTION("MSM 8x60 Audio ACDB driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_amrnb.c b/arch/arm/mach-msm/qdsp6v2/audio_amrnb.c
new file mode 100644
index 0000000..f4316d0
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_amrnb.c
@@ -0,0 +1,161 @@
+/* amrnb audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2011-2012, Code Aurora Forum. 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.
+ *
+ */
+#include "audio_utils_aio.h"
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations audio_amrnb_debug_fops = {
+	.read = audio_aio_debug_read,
+	.open = audio_aio_debug_open,
+};
+#endif
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct q6audio_aio *audio = file->private_data;
+	int rc = 0;
+
+	switch (cmd) {
+	case AUDIO_START: {
+		pr_debug("%s[%p]: AUDIO_START session_id[%d]\n", __func__,
+						audio, audio->ac->session);
+		if (audio->feedback == NON_TUNNEL_MODE) {
+			/* Configure PCM output block */
+			rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+					audio->pcm_cfg.sample_rate,
+					audio->pcm_cfg.channel_count);
+			if (rc < 0) {
+				pr_err("pcm output block config failed\n");
+				break;
+			}
+		}
+
+		rc = audio_aio_enable(audio);
+		audio->eos_rsp = 0;
+		audio->eos_flag = 0;
+		if (!rc) {
+			audio->enabled = 1;
+		} else {
+			audio->enabled = 0;
+			pr_err("Audio Start procedure failed rc=%d\n", rc);
+			break;
+		}
+		pr_debug("AUDIO_START success enable[%d]\n", audio->enabled);
+		if (audio->stopped == 1)
+			audio->stopped = 0;
+		break;
+	}
+	default:
+		pr_debug("%s[%p]: Calling utils ioctl\n", __func__, audio);
+		rc = audio->codec_ioctl(file, cmd, arg);
+	}
+	return rc;
+}
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct q6audio_aio *audio = NULL;
+	int rc = 0;
+
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_amrnb_" + 5];
+#endif
+	audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+	if (audio == NULL) {
+		pr_err("Could not allocate memory for wma decode driver\n");
+		return -ENOMEM;
+	}
+
+	audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+
+	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
+					     (void *)audio);
+
+	if (!audio->ac) {
+		pr_err("Could not allocate memory for audio client\n");
+		kfree(audio);
+		return -ENOMEM;
+	}
+
+	/* open in T/NT mode */
+	if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+		rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+					   FORMAT_AMRNB);
+		if (rc < 0) {
+			pr_err("NT mode Open failed rc=%d\n", rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->feedback = NON_TUNNEL_MODE;
+		audio->buf_cfg.frames_per_buf = 0x01;
+		audio->buf_cfg.meta_info_enable = 0x01;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+		rc = q6asm_open_write(audio->ac, FORMAT_AMRNB);
+		if (rc < 0) {
+			pr_err("T mode Open failed rc=%d\n", rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->feedback = TUNNEL_MODE;
+		audio->buf_cfg.meta_info_enable = 0x00;
+	} else {
+		pr_err("Not supported mode\n");
+		rc = -EACCES;
+		goto fail;
+	}
+	rc = audio_aio_open(audio, file);
+
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_amrnb_%04x", audio->ac->session);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+					    NULL, (void *)audio,
+					    &audio_amrnb_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		pr_debug("debugfs_create_file failed\n");
+#endif
+	pr_info("%s:amrnb decoder open success, session_id = %d\n", __func__,
+				audio->ac->session);
+	return rc;
+fail:
+	q6asm_audio_client_free(audio->ac);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_amrnb_fops = {
+	.owner = THIS_MODULE,
+	.open = audio_open,
+	.release = audio_aio_release,
+	.unlocked_ioctl = audio_ioctl,
+	.fsync = audio_aio_fsync,
+};
+
+struct miscdevice audio_amrnb_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_amrnb",
+	.fops = &audio_amrnb_fops,
+};
+
+static int __init audio_amrnb_init(void)
+{
+	return misc_register(&audio_amrnb_misc);
+}
+
+device_initcall(audio_amrnb_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_amrwb.c b/arch/arm/mach-msm/qdsp6v2/audio_amrwb.c
new file mode 100644
index 0000000..28c1732
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_amrwb.c
@@ -0,0 +1,164 @@
+/* amrwb audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2011-2012, Code Aurora Forum. 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.
+ *
+ */
+
+#include "audio_utils_aio.h"
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations audio_amrwb_debug_fops = {
+	.read = audio_aio_debug_read,
+	.open = audio_aio_debug_open,
+};
+#endif
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct q6audio_aio *audio = file->private_data;
+	int rc = 0;
+
+	switch (cmd) {
+	case AUDIO_START: {
+		pr_debug("%s[%p]: AUDIO_START session_id[%d]\n", __func__,
+						audio, audio->ac->session);
+		if (audio->feedback == NON_TUNNEL_MODE) {
+			/* Configure PCM output block */
+			rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+					audio->pcm_cfg.sample_rate,
+					audio->pcm_cfg.channel_count);
+			if (rc < 0) {
+				pr_err("pcm output block config failed\n");
+				break;
+			}
+		}
+
+		rc = audio_aio_enable(audio);
+		audio->eos_rsp = 0;
+		audio->eos_flag = 0;
+		if (!rc) {
+			audio->enabled = 1;
+		} else {
+			audio->enabled = 0;
+			pr_err("Audio Start procedure failed rc=%d\n", rc);
+			break;
+		}
+		pr_debug("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
+						audio->ac->session,
+						audio->enabled);
+		if (audio->stopped == 1)
+			audio->stopped = 0;
+		break;
+	}
+	default:
+		pr_debug("%s[%p]: Calling utils ioctl\n", __func__, audio);
+		rc = audio->codec_ioctl(file, cmd, arg);
+	}
+	return rc;
+}
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct q6audio_aio *audio = NULL;
+	int rc = 0;
+
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_amrwb_" + 5];
+#endif
+	audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+	if (audio == NULL) {
+		pr_err("Could not allocate memory for aac decode driver\n");
+		return -ENOMEM;
+	}
+	audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+
+	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
+					     (void *)audio);
+
+	if (!audio->ac) {
+		pr_err("Could not allocate memory for audio client\n");
+		kfree(audio);
+		return -ENOMEM;
+	}
+
+	/* open in T/NT mode */
+	if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+		rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+					   FORMAT_AMRWB);
+		if (rc < 0) {
+			pr_err("NT mode Open failed rc=%d\n", rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->feedback = NON_TUNNEL_MODE;
+		audio->buf_cfg.frames_per_buf = 0x01;
+		audio->buf_cfg.meta_info_enable = 0x01;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+		rc = q6asm_open_write(audio->ac, FORMAT_AMRWB);
+		if (rc < 0) {
+			pr_err("T mode Open failed rc=%d\n", rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->feedback = TUNNEL_MODE;
+		audio->buf_cfg.meta_info_enable = 0x00;
+	} else {
+		pr_err("Not supported mode\n");
+		rc = -EACCES;
+		goto fail;
+	}
+	rc = audio_aio_open(audio, file);
+
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_amrwb_%04x", audio->ac->session);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+					    NULL, (void *)audio,
+					    &audio_amrwb_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		pr_debug("debugfs_create_file failed\n");
+#endif
+	pr_info("%s: AMRWB dec success mode[%d]session[%d]\n", __func__,
+						audio->feedback,
+						audio->ac->session);
+	return 0;
+fail:
+	q6asm_audio_client_free(audio->ac);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_amrwb_fops = {
+	.owner = THIS_MODULE,
+	.open = audio_open,
+	.release = audio_aio_release,
+	.unlocked_ioctl = audio_ioctl,
+	.fsync = audio_aio_fsync,
+};
+
+struct miscdevice audio_amrwb_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_amrwb",
+	.fops = &audio_amrwb_fops,
+};
+
+static int __init audio_amrwb_init(void)
+{
+	return misc_register(&audio_amrwb_misc);
+}
+
+device_initcall(audio_amrwb_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_dev_ctl.c b/arch/arm/mach-msm/qdsp6v2/audio_dev_ctl.c
new file mode 100644
index 0000000..aaae776
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_dev_ctl.c
@@ -0,0 +1,1731 @@
+/* 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
+ * 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/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/msm_audio.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/workqueue.h>
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+#include <mach/debug_mm.h>
+#include <mach/qdsp6v2/q6voice.h>
+#include <sound/apr_audio.h>
+#include <sound/q6adm.h>
+
+#ifndef MAX
+#define  MAX(x, y) (((x) > (y)) ? (x) : (y))
+#endif
+
+
+static DEFINE_MUTEX(session_lock);
+static struct workqueue_struct *msm_reset_device_work_queue;
+static void reset_device_work(struct work_struct *work);
+static DECLARE_WORK(msm_reset_device_work, reset_device_work);
+
+struct audio_dev_ctrl_state {
+	struct msm_snddev_info *devs[AUDIO_DEV_CTL_MAX_DEV];
+	u32 num_dev;
+	atomic_t opened;
+	struct msm_snddev_info *voice_rx_dev;
+	struct msm_snddev_info *voice_tx_dev;
+	wait_queue_head_t      wait;
+};
+
+static struct audio_dev_ctrl_state audio_dev_ctrl;
+struct event_listner event;
+
+struct session_freq {
+	int freq;
+	int evt;
+};
+
+struct audio_routing_info {
+	unsigned short mixer_mask[MAX_SESSIONS];
+	unsigned short audrec_mixer_mask[MAX_SESSIONS];
+	struct session_freq dec_freq[MAX_SESSIONS];
+	struct session_freq enc_freq[MAX_SESSIONS];
+	unsigned int copp_list[MAX_SESSIONS][AFE_MAX_PORTS];
+	int voice_tx_dev_id;
+	int voice_rx_dev_id;
+	int voice_tx_sample_rate;
+	int voice_rx_sample_rate;
+	signed int voice_tx_vol;
+	signed int voice_rx_vol;
+	int tx_mute;
+	int rx_mute;
+	int voice_state;
+	struct mutex copp_list_mutex;
+	struct mutex adm_mutex;
+};
+
+static struct audio_routing_info routing_info;
+
+struct audio_copp_topology {
+	struct mutex lock;
+	int session_cnt;
+	int session_id[MAX_SESSIONS];
+	int topolog_id[MAX_SESSIONS];
+};
+static struct audio_copp_topology adm_tx_topology_tbl;
+
+int msm_reset_all_device(void)
+{
+	int rc = 0;
+	int dev_id = 0;
+	struct msm_snddev_info *dev_info = NULL;
+
+	for (dev_id = 0; dev_id < audio_dev_ctrl.num_dev; dev_id++) {
+		dev_info = audio_dev_ctrl_find_dev(dev_id);
+		if (IS_ERR(dev_info)) {
+			pr_err("%s:pass invalid dev_id\n", __func__);
+			rc = PTR_ERR(dev_info);
+			return rc;
+		}
+		if (!dev_info->opened)
+			continue;
+		pr_debug("%s:Resetting device %d active on COPP %d"
+			"with  %lld as routing\n", __func__,
+				dev_id, dev_info->copp_id, dev_info->sessions);
+		broadcast_event(AUDDEV_EVT_REL_PENDING,
+					dev_id,
+					SESSION_IGNORE);
+		rc = dev_info->dev_ops.close(dev_info);
+		if (rc < 0) {
+			pr_err("%s:Snd device failed close!\n", __func__);
+			return rc;
+		} else {
+			dev_info->opened = 0;
+			broadcast_event(AUDDEV_EVT_DEV_RLS,
+				dev_id,
+				SESSION_IGNORE);
+
+			if (dev_info->copp_id == VOICE_PLAYBACK_TX)
+				voice_start_playback(0);
+		}
+		dev_info->sessions = 0;
+	}
+	msm_clear_all_session();
+	return 0;
+}
+EXPORT_SYMBOL(msm_reset_all_device);
+
+static void reset_device_work(struct work_struct *work)
+{
+	msm_reset_all_device();
+}
+
+int reset_device(void)
+{
+	queue_work(msm_reset_device_work_queue, &msm_reset_device_work);
+	return 0;
+}
+EXPORT_SYMBOL(reset_device);
+
+int msm_set_copp_id(int session_id, int copp_id)
+{
+	int rc = 0;
+	int index;
+
+	if (session_id < 1 || session_id > 8)
+		return -EINVAL;
+	if (afe_validate_port(copp_id) < 0)
+		return -EINVAL;
+
+	index = afe_get_port_index(copp_id);
+	if (index < 0 || index > AFE_MAX_PORTS)
+		return -EINVAL;
+	pr_debug("%s: session[%d] copp_id[%d] index[%d]\n", __func__,
+			session_id, copp_id, index);
+	mutex_lock(&routing_info.copp_list_mutex);
+	if (routing_info.copp_list[session_id][index] == COPP_IGNORE)
+		routing_info.copp_list[session_id][index] = copp_id;
+	mutex_unlock(&routing_info.copp_list_mutex);
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_set_copp_id);
+
+int msm_clear_copp_id(int session_id, int copp_id)
+{
+	int rc = 0;
+	int index = afe_get_port_index(copp_id);
+
+	if (session_id < 1 || session_id > 8)
+		return -EINVAL;
+	pr_debug("%s: session[%d] copp_id[%d] index[%d]\n", __func__,
+			session_id, copp_id, index);
+	mutex_lock(&routing_info.copp_list_mutex);
+	if (routing_info.copp_list[session_id][index] == copp_id)
+		routing_info.copp_list[session_id][index] = COPP_IGNORE;
+#ifdef CONFIG_MSM8X60_RTAC
+	rtac_remove_adm_device(copp_id, session_id);
+#endif
+	mutex_unlock(&routing_info.copp_list_mutex);
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_clear_copp_id);
+
+int msm_clear_session_id(int session_id)
+{
+	int rc = 0;
+	int i = 0;
+	if (session_id < 1 || session_id > 8)
+		return -EINVAL;
+	pr_debug("%s: session[%d]\n", __func__, session_id);
+	mutex_lock(&routing_info.adm_mutex);
+	mutex_lock(&routing_info.copp_list_mutex);
+	for (i = 0; i < AFE_MAX_PORTS; i++) {
+		if (routing_info.copp_list[session_id][i] != COPP_IGNORE) {
+			rc = adm_close(routing_info.copp_list[session_id][i]);
+			if (rc < 0) {
+				pr_err("%s: adm close fail port[%d] rc[%d]\n",
+					__func__,
+					routing_info.copp_list[session_id][i],
+					rc);
+				continue;
+			}
+#ifdef CONFIG_MSM8X60_RTAC
+			rtac_remove_adm_device(
+			routing_info.copp_list[session_id][i], session_id);
+#endif
+			routing_info.copp_list[session_id][i] = COPP_IGNORE;
+			rc = 0;
+		}
+	}
+	mutex_unlock(&routing_info.copp_list_mutex);
+	mutex_unlock(&routing_info.adm_mutex);
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_clear_session_id);
+
+int msm_clear_all_session()
+{
+	int rc = 0;
+	int i = 0, j = 0;
+	pr_info("%s:\n", __func__);
+	mutex_lock(&routing_info.adm_mutex);
+	mutex_lock(&routing_info.copp_list_mutex);
+	for (j = 1; j < MAX_SESSIONS; j++) {
+		for (i = 0; i < AFE_MAX_PORTS; i++) {
+			if (routing_info.copp_list[j][i] != COPP_IGNORE) {
+				rc = adm_close(
+					routing_info.copp_list[j][i]);
+				if (rc < 0) {
+					pr_err("%s: adm close fail copp[%d]"
+					"session[%d] rc[%d]\n",
+					__func__,
+					routing_info.copp_list[j][i],
+					j, rc);
+					continue;
+				}
+				routing_info.copp_list[j][i] = COPP_IGNORE;
+				rc = 0;
+			}
+		}
+	}
+	mutex_unlock(&routing_info.copp_list_mutex);
+	mutex_unlock(&routing_info.adm_mutex);
+	return rc;
+}
+EXPORT_SYMBOL(msm_clear_all_session);
+
+int msm_get_voice_state(void)
+{
+	pr_debug("voice state %d\n", routing_info.voice_state);
+	return routing_info.voice_state;
+}
+EXPORT_SYMBOL(msm_get_voice_state);
+
+int msm_set_voice_mute(int dir, int mute, u32 session_id)
+{
+	pr_debug("dir %x mute %x\n", dir, mute);
+	if (dir == DIR_TX) {
+		routing_info.tx_mute = mute;
+		broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG,
+			routing_info.voice_tx_dev_id, session_id);
+	} else
+		return -EPERM;
+	return 0;
+}
+EXPORT_SYMBOL(msm_set_voice_mute);
+
+int msm_set_voice_vol(int dir, s32 volume, u32 session_id)
+{
+	if (dir == DIR_TX) {
+		routing_info.voice_tx_vol = volume;
+		broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG,
+					routing_info.voice_tx_dev_id,
+					session_id);
+	} else if (dir == DIR_RX) {
+		routing_info.voice_rx_vol = volume;
+		broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG,
+					routing_info.voice_rx_dev_id,
+					session_id);
+	} else
+		return -EINVAL;
+	return 0;
+}
+EXPORT_SYMBOL(msm_set_voice_vol);
+
+void msm_snddev_register(struct msm_snddev_info *dev_info)
+{
+	mutex_lock(&session_lock);
+	if (audio_dev_ctrl.num_dev < AUDIO_DEV_CTL_MAX_DEV) {
+		audio_dev_ctrl.devs[audio_dev_ctrl.num_dev] = dev_info;
+		/* roughly 0 DB for digital gain
+		 * If default gain is not desirable, it is expected that
+		 * application sets desired gain before activating sound
+		 * device
+		 */
+		dev_info->dev_volume = 75;
+		dev_info->sessions = 0x0;
+		dev_info->usage_count = 0;
+		audio_dev_ctrl.num_dev++;
+	} else
+		pr_err("%s: device registry max out\n", __func__);
+	mutex_unlock(&session_lock);
+}
+EXPORT_SYMBOL(msm_snddev_register);
+
+int msm_snddev_devcount(void)
+{
+	return audio_dev_ctrl.num_dev;
+}
+EXPORT_SYMBOL(msm_snddev_devcount);
+
+int msm_snddev_query(int dev_id)
+{
+	if (dev_id <= audio_dev_ctrl.num_dev)
+			return 0;
+	return -ENODEV;
+}
+EXPORT_SYMBOL(msm_snddev_query);
+
+int msm_snddev_is_set(int popp_id, int copp_id)
+{
+	return routing_info.mixer_mask[popp_id] & (0x1 << copp_id);
+}
+EXPORT_SYMBOL(msm_snddev_is_set);
+
+unsigned short msm_snddev_route_enc(int enc_id)
+{
+	if (enc_id >= MAX_SESSIONS)
+		return -EINVAL;
+	return routing_info.audrec_mixer_mask[enc_id];
+}
+EXPORT_SYMBOL(msm_snddev_route_enc);
+
+unsigned short msm_snddev_route_dec(int popp_id)
+{
+	if (popp_id >= MAX_SESSIONS)
+		return -EINVAL;
+	return routing_info.mixer_mask[popp_id];
+}
+EXPORT_SYMBOL(msm_snddev_route_dec);
+
+/*To check one->many case*/
+int msm_check_multicopp_per_stream(int session_id,
+				struct route_payload *payload)
+{
+	int i = 0;
+	int flag = 0;
+	pr_debug("%s: session_id=%d\n", __func__, session_id);
+	mutex_lock(&routing_info.copp_list_mutex);
+	for (i = 0; i < AFE_MAX_PORTS; i++) {
+		if (routing_info.copp_list[session_id][i] == COPP_IGNORE)
+			continue;
+		else {
+			pr_debug("Device enabled\n");
+			payload->copp_ids[flag++] =
+				routing_info.copp_list[session_id][i];
+		}
+	}
+	mutex_unlock(&routing_info.copp_list_mutex);
+	if (flag > 1) {
+		pr_debug("Multiple copp per stream case num_copps=%d\n", flag);
+	} else {
+		pr_debug("Stream routed to single copp\n");
+	}
+	payload->num_copps = flag;
+	return flag;
+}
+
+int msm_snddev_set_dec(int popp_id, int copp_id, int set,
+					int rate, int mode)
+{
+	int rc = 0, i = 0, num_copps;
+	struct route_payload payload;
+
+	if ((popp_id >= MAX_SESSIONS) || (popp_id <= 0)) {
+		pr_err("%s: Invalid session id %d\n", __func__, popp_id);
+		return 0;
+	}
+
+	mutex_lock(&routing_info.adm_mutex);
+	if (set) {
+		rc = adm_open(copp_id, ADM_PATH_PLAYBACK, rate, mode,
+			DEFAULT_COPP_TOPOLOGY);
+		if (rc < 0) {
+			pr_err("%s: adm open fail rc[%d]\n", __func__, rc);
+			rc = -EINVAL;
+			mutex_unlock(&routing_info.adm_mutex);
+			return rc;
+		}
+		msm_set_copp_id(popp_id, copp_id);
+		pr_debug("%s:Session id=%d copp_id=%d\n",
+			__func__, popp_id, copp_id);
+		memset(payload.copp_ids, COPP_IGNORE,
+				(sizeof(unsigned int) * AFE_MAX_PORTS));
+		num_copps = msm_check_multicopp_per_stream(popp_id, &payload);
+		/* Multiple streams per copp is handled, one stream at a time */
+		rc = adm_matrix_map(popp_id, ADM_PATH_PLAYBACK, num_copps,
+					payload.copp_ids, copp_id);
+		if (rc < 0) {
+			pr_err("%s: matrix map failed rc[%d]\n",
+				__func__, rc);
+			adm_close(copp_id);
+			rc = -EINVAL;
+			mutex_unlock(&routing_info.adm_mutex);
+			return rc;
+		}
+#ifdef CONFIG_MSM8X60_RTAC
+		for (i = 0; i < num_copps; i++)
+			rtac_add_adm_device(payload.copp_ids[i], popp_id);
+#endif
+	} else {
+		for (i = 0; i < AFE_MAX_PORTS; i++) {
+			if (routing_info.copp_list[popp_id][i] == copp_id) {
+				rc = adm_close(copp_id);
+				if (rc < 0) {
+					pr_err("%s: adm close fail copp[%d]"
+						"rc[%d]\n",
+						__func__, copp_id, rc);
+					rc = -EINVAL;
+					mutex_unlock(&routing_info.adm_mutex);
+					return rc;
+				}
+				msm_clear_copp_id(popp_id, copp_id);
+				break;
+			}
+		}
+	}
+
+	if (copp_id == VOICE_PLAYBACK_TX) {
+		/* Signal uplink playback. */
+		rc = voice_start_playback(set);
+	}
+	mutex_unlock(&routing_info.adm_mutex);
+	return rc;
+}
+EXPORT_SYMBOL(msm_snddev_set_dec);
+
+
+static int check_tx_copp_topology(int session_id)
+{
+	int cnt;
+	int ret_val = -ENOENT;
+
+	cnt = adm_tx_topology_tbl.session_cnt;
+	if (cnt) {
+		do {
+			if (adm_tx_topology_tbl.session_id[cnt-1]
+				== session_id)
+				ret_val = cnt-1;
+		} while (--cnt);
+	}
+
+	return ret_val;
+}
+
+static int add_to_tx_topology_lists(int session_id, int topology)
+{
+	int idx = 0, tbl_idx;
+	int ret_val = -ENOSPC;
+
+	mutex_lock(&adm_tx_topology_tbl.lock);
+
+	tbl_idx = check_tx_copp_topology(session_id);
+	if (tbl_idx == -ENOENT) {
+		while (adm_tx_topology_tbl.session_id[idx++])
+			;
+		tbl_idx = idx-1;
+	}
+
+	if (tbl_idx < MAX_SESSIONS) {
+		adm_tx_topology_tbl.session_id[tbl_idx] = session_id;
+		adm_tx_topology_tbl.topolog_id[tbl_idx] = topology;
+		adm_tx_topology_tbl.session_cnt++;
+
+		ret_val = 0;
+	}
+	mutex_unlock(&adm_tx_topology_tbl.lock);
+	return ret_val;
+}
+
+static void remove_from_tx_topology_lists(int session_id)
+{
+	int tbl_idx;
+
+	mutex_lock(&adm_tx_topology_tbl.lock);
+	tbl_idx = check_tx_copp_topology(session_id);
+	if (tbl_idx != -ENOENT) {
+
+		adm_tx_topology_tbl.session_cnt--;
+		adm_tx_topology_tbl.session_id[tbl_idx] = 0;
+		adm_tx_topology_tbl.topolog_id[tbl_idx] = 0;
+	}
+	mutex_unlock(&adm_tx_topology_tbl.lock);
+}
+
+int auddev_cfg_tx_copp_topology(int session_id, int cfg)
+{
+	int ret = 0;
+
+	if (cfg == DEFAULT_COPP_TOPOLOGY)
+		remove_from_tx_topology_lists(session_id);
+	else {
+		switch (cfg) {
+		case VPM_TX_SM_ECNS_COPP_TOPOLOGY:
+		case VPM_TX_DM_FLUENCE_COPP_TOPOLOGY:
+			ret = add_to_tx_topology_lists(session_id, cfg);
+			break;
+
+		default:
+			ret = -ENODEV;
+			break;
+		}
+	}
+	return ret;
+}
+
+int msm_snddev_set_enc(int popp_id, int copp_id, int set,
+					int rate, int mode)
+{
+	int topology;
+	int tbl_idx;
+	int rc = 0, i = 0;
+	mutex_lock(&routing_info.adm_mutex);
+	if (set) {
+		mutex_lock(&adm_tx_topology_tbl.lock);
+		tbl_idx = check_tx_copp_topology(popp_id);
+		if (tbl_idx == -ENOENT)
+			topology = DEFAULT_COPP_TOPOLOGY;
+		else {
+			topology = adm_tx_topology_tbl.topolog_id[tbl_idx];
+			rate = 16000;
+		}
+		mutex_unlock(&adm_tx_topology_tbl.lock);
+		rc = adm_open(copp_id, ADM_PATH_LIVE_REC, rate, mode, topology);
+		if (rc < 0) {
+			pr_err("%s: adm open fail rc[%d]\n", __func__, rc);
+			rc = -EINVAL;
+			goto fail_cmd;
+		}
+
+		rc = adm_matrix_map(popp_id, ADM_PATH_LIVE_REC, 1,
+					(unsigned int *)&copp_id, copp_id);
+		if (rc < 0) {
+			pr_err("%s: matrix map failed rc[%d]\n", __func__, rc);
+			adm_close(copp_id);
+			rc = -EINVAL;
+			goto fail_cmd;
+		}
+		msm_set_copp_id(popp_id, copp_id);
+#ifdef CONFIG_MSM8X60_RTAC
+	rtac_add_adm_device(copp_id, popp_id);
+#endif
+
+	} else {
+		for (i = 0; i < AFE_MAX_PORTS; i++) {
+			if (routing_info.copp_list[popp_id][i] == copp_id) {
+				rc = adm_close(copp_id);
+				if (rc < 0) {
+					pr_err("%s: adm close fail copp[%d]"
+					"rc[%d]\n",
+							__func__, copp_id, rc);
+					rc = -EINVAL;
+					goto fail_cmd;
+				}
+				msm_clear_copp_id(popp_id, copp_id);
+				break;
+			}
+		}
+	}
+fail_cmd:
+	mutex_unlock(&routing_info.adm_mutex);
+	return rc;
+}
+EXPORT_SYMBOL(msm_snddev_set_enc);
+
+int msm_device_is_voice(int dev_id)
+{
+	if ((dev_id == routing_info.voice_rx_dev_id)
+		|| (dev_id == routing_info.voice_tx_dev_id))
+		return 0;
+	else
+		return -EINVAL;
+}
+EXPORT_SYMBOL(msm_device_is_voice);
+
+int msm_set_voc_route(struct msm_snddev_info *dev_info,
+			int stream_type, int dev_id)
+{
+	int rc = 0;
+	u64 session_mask = 0;
+
+	mutex_lock(&session_lock);
+	switch (stream_type) {
+	case AUDIO_ROUTE_STREAM_VOICE_RX:
+		if (audio_dev_ctrl.voice_rx_dev)
+			audio_dev_ctrl.voice_rx_dev->sessions &= ~0xFFFF;
+
+		if (!(dev_info->capability & SNDDEV_CAP_RX) |
+		    !(dev_info->capability & SNDDEV_CAP_VOICE)) {
+			rc = -EINVAL;
+			break;
+		}
+		audio_dev_ctrl.voice_rx_dev = dev_info;
+		if (audio_dev_ctrl.voice_rx_dev) {
+			session_mask =
+				((u64)0x1) << (MAX_BIT_PER_CLIENT * \
+				((int)AUDDEV_CLNT_VOC-1));
+			audio_dev_ctrl.voice_rx_dev->sessions |=
+				session_mask;
+		}
+		routing_info.voice_rx_dev_id = dev_id;
+		break;
+	case AUDIO_ROUTE_STREAM_VOICE_TX:
+		if (audio_dev_ctrl.voice_tx_dev)
+			audio_dev_ctrl.voice_tx_dev->sessions &= ~0xFFFF;
+
+		if (!(dev_info->capability & SNDDEV_CAP_TX) |
+		    !(dev_info->capability & SNDDEV_CAP_VOICE)) {
+			rc = -EINVAL;
+			break;
+		}
+
+		audio_dev_ctrl.voice_tx_dev = dev_info;
+		if (audio_dev_ctrl.voice_rx_dev) {
+			session_mask =
+				((u64)0x1) << (MAX_BIT_PER_CLIENT * \
+					((int)AUDDEV_CLNT_VOC-1));
+			audio_dev_ctrl.voice_tx_dev->sessions |=
+				session_mask;
+		}
+		routing_info.voice_tx_dev_id = dev_id;
+		break;
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&session_lock);
+	return rc;
+}
+EXPORT_SYMBOL(msm_set_voc_route);
+
+void msm_release_voc_thread(void)
+{
+	wake_up(&audio_dev_ctrl.wait);
+}
+EXPORT_SYMBOL(msm_release_voc_thread);
+
+int msm_snddev_get_enc_freq(session_id)
+{
+	return routing_info.enc_freq[session_id].freq;
+}
+EXPORT_SYMBOL(msm_snddev_get_enc_freq);
+
+int msm_get_voc_freq(int *tx_freq, int *rx_freq)
+{
+	*tx_freq = routing_info.voice_tx_sample_rate;
+	*rx_freq = routing_info.voice_rx_sample_rate;
+	return 0;
+}
+EXPORT_SYMBOL(msm_get_voc_freq);
+
+int msm_get_voc_route(u32 *rx_id, u32 *tx_id)
+{
+	int rc = 0;
+
+	if (!rx_id || !tx_id)
+		return -EINVAL;
+
+	mutex_lock(&session_lock);
+	if (!audio_dev_ctrl.voice_rx_dev || !audio_dev_ctrl.voice_tx_dev) {
+		rc = -ENODEV;
+		mutex_unlock(&session_lock);
+		return rc;
+	}
+
+	*rx_id = audio_dev_ctrl.voice_rx_dev->acdb_id;
+	*tx_id = audio_dev_ctrl.voice_tx_dev->acdb_id;
+
+	mutex_unlock(&session_lock);
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_get_voc_route);
+
+struct msm_snddev_info *audio_dev_ctrl_find_dev(u32 dev_id)
+{
+	struct msm_snddev_info *info;
+
+	if ((audio_dev_ctrl.num_dev - 1) < dev_id) {
+		info = ERR_PTR(-ENODEV);
+		goto error;
+	}
+
+	info = audio_dev_ctrl.devs[dev_id];
+error:
+	return info;
+
+}
+EXPORT_SYMBOL(audio_dev_ctrl_find_dev);
+
+int snddev_voice_set_volume(int vol, int path)
+{
+	if (audio_dev_ctrl.voice_rx_dev
+		&& audio_dev_ctrl.voice_tx_dev) {
+		if (path)
+			audio_dev_ctrl.voice_tx_dev->dev_volume = vol;
+		else
+			audio_dev_ctrl.voice_rx_dev->dev_volume = vol;
+	} else
+		return -ENODEV;
+	return 0;
+}
+EXPORT_SYMBOL(snddev_voice_set_volume);
+
+static int audio_dev_ctrl_get_devices(struct audio_dev_ctrl_state *dev_ctrl,
+				      void __user *arg)
+{
+	int rc = 0;
+	u32 index;
+	struct msm_snd_device_list work_list;
+	struct msm_snd_device_info *work_tbl;
+
+	if (copy_from_user(&work_list, arg, sizeof(work_list))) {
+		rc = -EFAULT;
+		goto error;
+	}
+
+	if (work_list.num_dev > dev_ctrl->num_dev) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	work_tbl = kmalloc(work_list.num_dev *
+		sizeof(struct msm_snd_device_info), GFP_KERNEL);
+	if (!work_tbl) {
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	for (index = 0; index < dev_ctrl->num_dev; index++) {
+		work_tbl[index].dev_id = index;
+		work_tbl[index].dev_cap = dev_ctrl->devs[index]->capability;
+		strlcpy(work_tbl[index].dev_name, dev_ctrl->devs[index]->name,
+		64);
+	}
+
+	if (copy_to_user((void *) (work_list.list), work_tbl,
+		 work_list.num_dev * sizeof(struct msm_snd_device_info)))
+		rc = -EFAULT;
+	kfree(work_tbl);
+error:
+	return rc;
+}
+
+
+int auddev_register_evt_listner(u32 evt_id, u32 clnt_type, u32 clnt_id,
+		void (*listner)(u32 evt_id,
+			union auddev_evt_data *evt_payload,
+			void *private_data),
+		void *private_data)
+{
+	int rc;
+	struct msm_snd_evt_listner *callback = NULL;
+	struct msm_snd_evt_listner *new_cb;
+
+	new_cb = kzalloc(sizeof(struct msm_snd_evt_listner), GFP_KERNEL);
+	if (!new_cb) {
+		pr_err("No memory to add new listener node\n");
+		return -ENOMEM;
+	}
+
+	mutex_lock(&session_lock);
+	new_cb->cb_next = NULL;
+	new_cb->auddev_evt_listener = listner;
+	new_cb->evt_id = evt_id;
+	new_cb->clnt_type = clnt_type;
+	new_cb->clnt_id = clnt_id;
+	new_cb->private_data = private_data;
+	if (event.cb == NULL) {
+		event.cb = new_cb;
+		new_cb->cb_prev = NULL;
+	} else {
+		callback = event.cb;
+		for (; ;) {
+			if (callback->cb_next == NULL)
+				break;
+			else {
+				callback = callback->cb_next;
+				continue;
+			}
+		}
+		callback->cb_next = new_cb;
+		new_cb->cb_prev = callback;
+	}
+	event.num_listner++;
+	mutex_unlock(&session_lock);
+	rc = 0;
+	return rc;
+}
+EXPORT_SYMBOL(auddev_register_evt_listner);
+
+int auddev_unregister_evt_listner(u32 clnt_type, u32 clnt_id)
+{
+	struct msm_snd_evt_listner *callback = event.cb;
+	struct msm_snddev_info *info;
+	u64 session_mask = 0;
+	int i = 0;
+
+	mutex_lock(&session_lock);
+	while (callback != NULL) {
+		if ((callback->clnt_type == clnt_type)
+			&& (callback->clnt_id == clnt_id))
+			break;
+		 callback = callback->cb_next;
+	}
+	if (callback == NULL) {
+		mutex_unlock(&session_lock);
+		return -EINVAL;
+	}
+
+	if ((callback->cb_next == NULL) && (callback->cb_prev == NULL))
+		event.cb = NULL;
+	else if (callback->cb_next == NULL)
+		callback->cb_prev->cb_next = NULL;
+	else if (callback->cb_prev == NULL) {
+		callback->cb_next->cb_prev = NULL;
+		event.cb = callback->cb_next;
+	} else {
+		callback->cb_prev->cb_next = callback->cb_next;
+		callback->cb_next->cb_prev = callback->cb_prev;
+	}
+	kfree(callback);
+
+	session_mask = (((u64)0x1) << clnt_id) << (MAX_BIT_PER_CLIENT * \
+				((int)clnt_type-1));
+	for (i = 0; i < audio_dev_ctrl.num_dev; i++) {
+		info = audio_dev_ctrl.devs[i];
+		info->sessions &= ~session_mask;
+	}
+	mutex_unlock(&session_lock);
+	return 0;
+}
+EXPORT_SYMBOL(auddev_unregister_evt_listner);
+
+int msm_snddev_withdraw_freq(u32 session_id, u32 capability, u32 clnt_type)
+{
+	int i = 0;
+	struct msm_snddev_info *info;
+	u64 session_mask = 0;
+
+	if ((clnt_type == AUDDEV_CLNT_VOC) && (session_id != 0))
+		return -EINVAL;
+	if ((clnt_type == AUDDEV_CLNT_DEC)
+			&& (session_id >= MAX_SESSIONS))
+		return -EINVAL;
+	if ((clnt_type == AUDDEV_CLNT_ENC)
+			&& (session_id >= MAX_SESSIONS))
+		return -EINVAL;
+
+	session_mask = (((u64)0x1) << session_id) << (MAX_BIT_PER_CLIENT * \
+				((int)clnt_type-1));
+
+	for (i = 0; i < audio_dev_ctrl.num_dev; i++) {
+		info = audio_dev_ctrl.devs[i];
+		if ((info->sessions & session_mask)
+			&& (info->capability & capability)) {
+			if (!(info->sessions & ~(session_mask)))
+				info->set_sample_rate = 0;
+		}
+	}
+	if (clnt_type == AUDDEV_CLNT_DEC)
+		routing_info.dec_freq[session_id].freq
+					= 0;
+	else if (clnt_type == AUDDEV_CLNT_ENC)
+		routing_info.enc_freq[session_id].freq
+					= 0;
+	else if (capability == SNDDEV_CAP_TX)
+		routing_info.voice_tx_sample_rate = 0;
+	else
+		routing_info.voice_rx_sample_rate = 48000;
+	return 0;
+}
+
+int msm_snddev_request_freq(int *freq, u32 session_id,
+			u32 capability, u32 clnt_type)
+{
+	int i = 0;
+	int rc = 0;
+	struct msm_snddev_info *info;
+	u32 set_freq;
+	u64 session_mask = 0;
+	u64 clnt_type_mask = 0;
+
+	pr_debug(": clnt_type 0x%08x\n", clnt_type);
+
+	if ((clnt_type == AUDDEV_CLNT_VOC) && (session_id != 0))
+		return -EINVAL;
+	if ((clnt_type == AUDDEV_CLNT_DEC)
+			&& (session_id >= MAX_SESSIONS))
+		return -EINVAL;
+	if ((clnt_type == AUDDEV_CLNT_ENC)
+			&& (session_id >= MAX_SESSIONS))
+		return -EINVAL;
+	session_mask = (((u64)0x1) << session_id) << (MAX_BIT_PER_CLIENT * \
+				((int)clnt_type-1));
+	clnt_type_mask = (0xFFFF << (MAX_BIT_PER_CLIENT * (clnt_type-1)));
+	if (!(*freq == 8000) && !(*freq == 11025) &&
+		!(*freq == 12000) && !(*freq == 16000) &&
+		!(*freq == 22050) && !(*freq == 24000) &&
+		!(*freq == 32000) && !(*freq == 44100) &&
+		!(*freq == 48000))
+		return -EINVAL;
+
+	for (i = 0; i < audio_dev_ctrl.num_dev; i++) {
+		info = audio_dev_ctrl.devs[i];
+		if ((info->sessions & session_mask)
+			&& (info->capability & capability)) {
+			rc = 0;
+			if ((info->sessions & ~clnt_type_mask)
+				&& ((*freq != 8000) && (*freq != 16000)
+					&& (*freq != 48000))) {
+				if (clnt_type == AUDDEV_CLNT_ENC) {
+					routing_info.enc_freq[session_id].freq
+							= 0;
+					return -EPERM;
+				} else if (clnt_type == AUDDEV_CLNT_DEC) {
+					routing_info.dec_freq[session_id].freq
+							= 0;
+					return -EPERM;
+				}
+			}
+			if (*freq == info->set_sample_rate) {
+				rc = info->set_sample_rate;
+				continue;
+			}
+			set_freq = MAX(*freq, info->set_sample_rate);
+
+
+			if (clnt_type == AUDDEV_CLNT_DEC) {
+				routing_info.dec_freq[session_id].evt = 1;
+				routing_info.dec_freq[session_id].freq
+						= set_freq;
+			} else if (clnt_type == AUDDEV_CLNT_ENC) {
+				routing_info.enc_freq[session_id].evt = 1;
+				routing_info.enc_freq[session_id].freq
+						= set_freq;
+			} else if (capability == SNDDEV_CAP_TX)
+				routing_info.voice_tx_sample_rate = set_freq;
+
+			rc = set_freq;
+			info->set_sample_rate = set_freq;
+			*freq = info->set_sample_rate;
+
+			if (info->opened) {
+				broadcast_event(AUDDEV_EVT_FREQ_CHG, i,
+							SESSION_IGNORE);
+				set_freq = info->dev_ops.set_freq(info,
+								set_freq);
+				broadcast_event(AUDDEV_EVT_DEV_RDY, i,
+							SESSION_IGNORE);
+			}
+		}
+		pr_debug("info->set_sample_rate = %d\n", info->set_sample_rate);
+		pr_debug("routing_info.enc_freq.freq = %d\n",
+					routing_info.enc_freq[session_id].freq);
+	}
+	return rc;
+}
+EXPORT_SYMBOL(msm_snddev_request_freq);
+
+int msm_snddev_enable_sidetone(u32 dev_id, u32 enable, uint16_t gain)
+{
+	int rc;
+	struct msm_snddev_info *dev_info;
+
+	pr_debug("dev_id %d enable %d\n", dev_id, enable);
+
+	dev_info = audio_dev_ctrl_find_dev(dev_id);
+
+	if (IS_ERR(dev_info)) {
+		pr_err("bad dev_id %d\n", dev_id);
+		rc = -EINVAL;
+	} else if (!dev_info->dev_ops.enable_sidetone) {
+		pr_debug("dev %d no sidetone support\n", dev_id);
+		rc = -EPERM;
+	} else
+		rc = dev_info->dev_ops.enable_sidetone(dev_info, enable, gain);
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_snddev_enable_sidetone);
+
+int msm_enable_incall_recording(int popp_id, int rec_mode, int rate,
+				int channel_mode)
+{
+	int rc = 0;
+	unsigned int port_id[2];
+	port_id[0] = VOICE_RECORD_TX;
+	port_id[1] = VOICE_RECORD_RX;
+
+	pr_debug("%s: popp_id %d, rec_mode %d, rate %d, channel_mode %d\n",
+		 __func__, popp_id, rec_mode, rate, channel_mode);
+
+	mutex_lock(&routing_info.adm_mutex);
+
+	if (rec_mode == VOC_REC_UPLINK) {
+		rc = afe_start_pseudo_port(port_id[0]);
+		if (rc < 0) {
+			pr_err("%s: Error %d in Tx pseudo port start\n",
+			       __func__, rc);
+
+			goto fail_cmd;
+		}
+
+		rc = adm_open(port_id[0], ADM_PATH_LIVE_REC, rate, channel_mode,
+				DEFAULT_COPP_TOPOLOGY);
+		if (rc < 0) {
+			pr_err("%s: Error %d in ADM open %d\n",
+			       __func__, rc, port_id[0]);
+
+			goto fail_cmd;
+		}
+
+		rc = adm_matrix_map(popp_id, ADM_PATH_LIVE_REC, 1,
+				&port_id[0], port_id[0]);
+		if (rc < 0) {
+			pr_err("%s: Error %d in ADM matrix map %d\n",
+			       __func__, rc, port_id[0]);
+
+			goto fail_cmd;
+		}
+
+		msm_set_copp_id(popp_id, port_id[0]);
+
+	} else if (rec_mode == VOC_REC_DOWNLINK) {
+		rc = afe_start_pseudo_port(port_id[1]);
+		if (rc < 0) {
+			pr_err("%s: Error %d in Rx pseudo port start\n",
+			       __func__, rc);
+
+			goto fail_cmd;
+		}
+
+		rc = adm_open(port_id[1], ADM_PATH_LIVE_REC, rate, channel_mode,
+				DEFAULT_COPP_TOPOLOGY);
+		if (rc < 0) {
+			pr_err("%s: Error %d in ADM open %d\n",
+			       __func__, rc, port_id[1]);
+
+			goto fail_cmd;
+		}
+
+		rc = adm_matrix_map(popp_id, ADM_PATH_LIVE_REC, 1,
+				&port_id[1], port_id[1]);
+		if (rc < 0) {
+			pr_err("%s: Error %d in ADM matrix map %d\n",
+			       __func__, rc, port_id[1]);
+
+			goto fail_cmd;
+		}
+
+		msm_set_copp_id(popp_id, port_id[1]);
+
+	} else if (rec_mode == VOC_REC_BOTH) {
+		rc = afe_start_pseudo_port(port_id[0]);
+		if (rc < 0) {
+			pr_err("%s: Error %d in Tx pseudo port start\n",
+			       __func__, rc);
+
+			goto fail_cmd;
+		}
+
+		rc = adm_open(port_id[0], ADM_PATH_LIVE_REC, rate, channel_mode,
+				DEFAULT_COPP_TOPOLOGY);
+		if (rc < 0) {
+			pr_err("%s: Error %d in ADM open %d\n",
+			       __func__, rc, port_id[0]);
+
+			goto fail_cmd;
+		}
+
+		msm_set_copp_id(popp_id, port_id[0]);
+
+		rc = afe_start_pseudo_port(port_id[1]);
+		if (rc < 0) {
+			pr_err("%s: Error %d in Rx pseudo port start\n",
+			       __func__, rc);
+
+			goto fail_cmd;
+		}
+
+		rc = adm_open(port_id[1], ADM_PATH_LIVE_REC, rate, channel_mode,
+				DEFAULT_COPP_TOPOLOGY);
+		if (rc < 0) {
+			pr_err("%s: Error %d in ADM open %d\n",
+			       __func__, rc, port_id[0]);
+
+			goto fail_cmd;
+		}
+
+		rc = adm_matrix_map(popp_id, ADM_PATH_LIVE_REC, 2,
+				&port_id[0], port_id[1]);
+		if (rc < 0) {
+			pr_err("%s: Error %d in ADM matrix map\n",
+			       __func__, rc);
+
+			goto fail_cmd;
+		}
+
+		msm_set_copp_id(popp_id, port_id[1]);
+	} else {
+		pr_err("%s Unknown rec_mode %d\n", __func__, rec_mode);
+
+		goto fail_cmd;
+	}
+
+	rc = voice_start_record(rec_mode, 1);
+
+fail_cmd:
+	mutex_unlock(&routing_info.adm_mutex);
+	return rc;
+}
+
+int msm_disable_incall_recording(uint32_t popp_id, uint32_t rec_mode)
+{
+	int rc = 0;
+	uint32_t port_id[2];
+	port_id[0] = VOICE_RECORD_TX;
+	port_id[1] = VOICE_RECORD_RX;
+
+	pr_debug("%s: popp_id %d, rec_mode %d\n", __func__, popp_id, rec_mode);
+
+	mutex_lock(&routing_info.adm_mutex);
+
+	rc = voice_start_record(rec_mode, 0);
+	if (rc < 0) {
+		pr_err("%s: Error %d stopping record\n", __func__, rc);
+
+		goto fail_cmd;
+	}
+
+	if (rec_mode == VOC_REC_UPLINK) {
+		rc = adm_close(port_id[0]);
+		if (rc < 0) {
+			pr_err("%s: Error %d in ADM close %d\n",
+			       __func__, rc, port_id[0]);
+
+			goto fail_cmd;
+		}
+
+		msm_clear_copp_id(popp_id, port_id[0]);
+
+		rc = afe_stop_pseudo_port(port_id[0]);
+		if (rc < 0) {
+			pr_err("%s: Error %d in Tx pseudo port stop\n",
+			       __func__, rc);
+			goto fail_cmd;
+		}
+
+	} else if (rec_mode == VOC_REC_DOWNLINK) {
+		rc = adm_close(port_id[1]);
+		if (rc < 0) {
+			pr_err("%s: Error %d in ADM close %d\n",
+			       __func__, rc, port_id[1]);
+
+			goto fail_cmd;
+		}
+
+		msm_clear_copp_id(popp_id, port_id[1]);
+
+		rc = afe_stop_pseudo_port(port_id[1]);
+		if (rc < 0) {
+			pr_err("%s: Error %d in Rx pseudo port stop\n",
+			       __func__, rc);
+			goto fail_cmd;
+		}
+	} else if (rec_mode == VOC_REC_BOTH) {
+		rc = adm_close(port_id[0]);
+		if (rc < 0) {
+			pr_err("%s: Error %d in ADM close %d\n",
+			       __func__, rc, port_id[0]);
+
+			goto fail_cmd;
+		}
+
+		msm_clear_copp_id(popp_id, port_id[0]);
+
+		rc = afe_stop_pseudo_port(port_id[0]);
+		if (rc < 0) {
+			pr_err("%s: Error %d in Tx pseudo port stop\n",
+			       __func__, rc);
+			goto fail_cmd;
+		}
+
+		rc = adm_close(port_id[1]);
+		if (rc < 0) {
+			pr_err("%s: Error %d in ADM close %d\n",
+			       __func__, rc, port_id[1]);
+
+			goto fail_cmd;
+		}
+
+		msm_clear_copp_id(popp_id, port_id[1]);
+
+		rc = afe_stop_pseudo_port(port_id[1]);
+		if (rc < 0) {
+			pr_err("%s: Error %d in Rx pseudo port stop\n",
+			       __func__, rc);
+			goto fail_cmd;
+		}
+	} else {
+		pr_err("%s Unknown rec_mode %d\n", __func__, rec_mode);
+
+		goto fail_cmd;
+	}
+
+fail_cmd:
+	mutex_unlock(&routing_info.adm_mutex);
+	return rc;
+}
+
+static long audio_dev_ctrl_ioctl(struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	int rc = 0;
+	struct audio_dev_ctrl_state *dev_ctrl = file->private_data;
+
+	mutex_lock(&session_lock);
+	switch (cmd) {
+	case AUDIO_GET_NUM_SND_DEVICE:
+		rc = put_user(dev_ctrl->num_dev, (uint32_t __user *) arg);
+		break;
+	case AUDIO_GET_SND_DEVICES:
+		rc = audio_dev_ctrl_get_devices(dev_ctrl, (void __user *) arg);
+		break;
+	case AUDIO_ENABLE_SND_DEVICE: {
+		struct msm_snddev_info *dev_info;
+		u32 dev_id;
+
+		if (get_user(dev_id, (u32 __user *) arg)) {
+			rc = -EFAULT;
+			break;
+		}
+		dev_info = audio_dev_ctrl_find_dev(dev_id);
+		if (IS_ERR(dev_info))
+			rc = PTR_ERR(dev_info);
+		else {
+			rc = dev_info->dev_ops.open(dev_info);
+			if (!rc)
+				dev_info->opened = 1;
+			wake_up(&audio_dev_ctrl.wait);
+		}
+		break;
+
+	}
+
+	case AUDIO_DISABLE_SND_DEVICE: {
+		struct msm_snddev_info *dev_info;
+		u32 dev_id;
+
+		if (get_user(dev_id, (u32 __user *) arg)) {
+			rc = -EFAULT;
+			break;
+		}
+		dev_info = audio_dev_ctrl_find_dev(dev_id);
+		if (IS_ERR(dev_info))
+			rc = PTR_ERR(dev_info);
+		else {
+			rc = dev_info->dev_ops.close(dev_info);
+			dev_info->opened = 0;
+		}
+		break;
+	}
+
+	case AUDIO_ROUTE_STREAM: {
+		struct msm_audio_route_config route_cfg;
+		struct msm_snddev_info *dev_info;
+
+		if (copy_from_user(&route_cfg, (void __user *) arg,
+			sizeof(struct msm_audio_route_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("%s: route cfg %d %d type\n", __func__,
+		route_cfg.dev_id, route_cfg.stream_type);
+		dev_info = audio_dev_ctrl_find_dev(route_cfg.dev_id);
+		if (IS_ERR(dev_info)) {
+			pr_err("%s: pass invalid dev_id\n", __func__);
+			rc = PTR_ERR(dev_info);
+			break;
+		}
+
+		switch (route_cfg.stream_type) {
+
+		case AUDIO_ROUTE_STREAM_VOICE_RX:
+			if (!(dev_info->capability & SNDDEV_CAP_RX) |
+			    !(dev_info->capability & SNDDEV_CAP_VOICE)) {
+				rc = -EINVAL;
+				break;
+			}
+			dev_ctrl->voice_rx_dev = dev_info;
+			break;
+		case AUDIO_ROUTE_STREAM_VOICE_TX:
+			if (!(dev_info->capability & SNDDEV_CAP_TX) |
+			    !(dev_info->capability & SNDDEV_CAP_VOICE)) {
+				rc = -EINVAL;
+				break;
+			}
+			dev_ctrl->voice_tx_dev = dev_info;
+			break;
+		}
+		break;
+	}
+
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&session_lock);
+	return rc;
+}
+
+static int audio_dev_ctrl_open(struct inode *inode, struct file *file)
+{
+	pr_debug("open audio_dev_ctrl\n");
+	atomic_inc(&audio_dev_ctrl.opened);
+	file->private_data = &audio_dev_ctrl;
+	return 0;
+}
+
+static int audio_dev_ctrl_release(struct inode *inode, struct file *file)
+{
+	pr_debug("release audio_dev_ctrl\n");
+	atomic_dec(&audio_dev_ctrl.opened);
+	return 0;
+}
+
+static const struct file_operations audio_dev_ctrl_fops = {
+	.owner = THIS_MODULE,
+	.open = audio_dev_ctrl_open,
+	.release = audio_dev_ctrl_release,
+	.unlocked_ioctl = audio_dev_ctrl_ioctl,
+};
+
+
+struct miscdevice audio_dev_ctrl_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_audio_dev_ctrl",
+	.fops	= &audio_dev_ctrl_fops,
+};
+
+/* session id is 64 bit routing mask per device
+ * 0-15 for voice clients
+ * 16-31 for Decoder clients
+ * 32-47 for Encoder clients
+ * 48-63 Do not care
+ */
+void broadcast_event(u32 evt_id, u32 dev_id, u64 session_id)
+{
+	int clnt_id = 0, i;
+	union auddev_evt_data *evt_payload;
+	struct msm_snd_evt_listner *callback;
+	struct msm_snddev_info *dev_info = NULL;
+	u64 session_mask = 0;
+	static int pending_sent;
+
+	pr_debug(": evt_id = %d\n", evt_id);
+
+	if ((evt_id != AUDDEV_EVT_START_VOICE)
+		&& (evt_id != AUDDEV_EVT_END_VOICE)
+		&& (evt_id != AUDDEV_EVT_STREAM_VOL_CHG)
+		&& (evt_id != AUDDEV_EVT_VOICE_STATE_CHG)) {
+		dev_info = audio_dev_ctrl_find_dev(dev_id);
+		if (IS_ERR(dev_info)) {
+			pr_err("%s: pass invalid dev_id(%d)\n",
+					 __func__, dev_id);
+			return;
+		}
+	}
+
+	if (event.cb != NULL)
+		callback = event.cb;
+	else
+		return;
+	mutex_lock(&session_lock);
+
+	if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
+		routing_info.voice_state = dev_id;
+
+	evt_payload = kzalloc(sizeof(union auddev_evt_data),
+			GFP_KERNEL);
+
+	if (evt_payload == NULL) {
+		pr_err("broadcast_event: cannot allocate memory\n");
+		mutex_unlock(&session_lock);
+		return;
+	}
+	for (; ;) {
+		if (!(evt_id & callback->evt_id)) {
+			if (callback->cb_next == NULL)
+				break;
+			else {
+				callback = callback->cb_next;
+				continue;
+			}
+		}
+		clnt_id = callback->clnt_id;
+		memset(evt_payload, 0, sizeof(union auddev_evt_data));
+
+		if ((evt_id == AUDDEV_EVT_START_VOICE)
+			|| (evt_id == AUDDEV_EVT_END_VOICE)
+			|| evt_id == AUDDEV_EVT_DEVICE_VOL_MUTE_CHG)
+			goto skip_check;
+		if (callback->clnt_type == AUDDEV_CLNT_AUDIOCAL)
+			goto aud_cal;
+
+		session_mask = (((u64)0x1) << clnt_id)
+				<< (MAX_BIT_PER_CLIENT * \
+				((int)callback->clnt_type-1));
+
+		if ((evt_id == AUDDEV_EVT_STREAM_VOL_CHG) || \
+			(evt_id == AUDDEV_EVT_VOICE_STATE_CHG)) {
+			pr_debug("AUDDEV_EVT_STREAM_VOL_CHG or\
+				AUDDEV_EVT_VOICE_STATE_CHG\n");
+			goto volume_strm;
+		}
+
+		pr_debug("dev_info->sessions = %llu\n", dev_info->sessions);
+
+		if ((!session_id && !(dev_info->sessions & session_mask)) ||
+			(session_id && ((dev_info->sessions & session_mask) !=
+						session_id))) {
+			if (callback->cb_next == NULL)
+				break;
+			else {
+				callback = callback->cb_next;
+				continue;
+			}
+		}
+		if (evt_id == AUDDEV_EVT_DEV_CHG_VOICE)
+			goto voc_events;
+
+volume_strm:
+		if (callback->clnt_type == AUDDEV_CLNT_DEC) {
+			pr_debug("AUDDEV_CLNT_DEC\n");
+			if (evt_id == AUDDEV_EVT_STREAM_VOL_CHG) {
+				pr_debug("clnt_id = %d, session_id = %llu\n",
+					clnt_id, session_id);
+				if (session_mask != session_id)
+					goto sent_dec;
+				else
+					evt_payload->session_vol =
+						msm_vol_ctl.volume;
+			} else if (evt_id == AUDDEV_EVT_FREQ_CHG) {
+				if (routing_info.dec_freq[clnt_id].evt) {
+					routing_info.dec_freq[clnt_id].evt
+							= 0;
+					goto sent_dec;
+				} else if (routing_info.dec_freq[clnt_id].freq
+					== dev_info->set_sample_rate)
+					goto sent_dec;
+				else {
+					evt_payload->freq_info.sample_rate
+						= dev_info->set_sample_rate;
+					evt_payload->freq_info.dev_type
+						= dev_info->capability;
+					evt_payload->freq_info.acdb_dev_id
+						= dev_info->acdb_id;
+				}
+			} else if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
+				evt_payload->voice_state =
+					routing_info.voice_state;
+			else
+				evt_payload->routing_id = dev_info->copp_id;
+			callback->auddev_evt_listener(
+					evt_id,
+					evt_payload,
+					callback->private_data);
+sent_dec:
+			if ((evt_id != AUDDEV_EVT_STREAM_VOL_CHG) &&
+				(evt_id != AUDDEV_EVT_VOICE_STATE_CHG))
+				routing_info.dec_freq[clnt_id].freq
+						= dev_info->set_sample_rate;
+
+			if (callback->cb_next == NULL)
+				break;
+			else {
+				callback = callback->cb_next;
+				continue;
+			}
+		}
+		if (callback->clnt_type == AUDDEV_CLNT_ENC) {
+			pr_debug("AUDDEV_CLNT_ENC\n");
+			if (evt_id == AUDDEV_EVT_FREQ_CHG) {
+				if (routing_info.enc_freq[clnt_id].evt) {
+					routing_info.enc_freq[clnt_id].evt
+							= 0;
+					goto sent_enc;
+				 } else {
+					evt_payload->freq_info.sample_rate
+						= dev_info->set_sample_rate;
+					evt_payload->freq_info.dev_type
+						= dev_info->capability;
+					evt_payload->freq_info.acdb_dev_id
+						= dev_info->acdb_id;
+				}
+			} else if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
+				evt_payload->voice_state =
+					routing_info.voice_state;
+			else
+				evt_payload->routing_id = dev_info->copp_id;
+			callback->auddev_evt_listener(
+					evt_id,
+					evt_payload,
+					callback->private_data);
+sent_enc:
+			if (callback->cb_next == NULL)
+					break;
+			else {
+				callback = callback->cb_next;
+				continue;
+			}
+		}
+aud_cal:
+		if (callback->clnt_type == AUDDEV_CLNT_AUDIOCAL) {
+			pr_debug("AUDDEV_CLNT_AUDIOCAL\n");
+			if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
+				evt_payload->voice_state =
+					routing_info.voice_state;
+			else if (!dev_info->sessions)
+				goto sent_aud_cal;
+			else {
+				evt_payload->audcal_info.dev_id =
+						dev_info->copp_id;
+				evt_payload->audcal_info.acdb_id =
+						dev_info->acdb_id;
+				evt_payload->audcal_info.dev_type =
+					(dev_info->capability & SNDDEV_CAP_TX) ?
+					SNDDEV_CAP_TX : SNDDEV_CAP_RX;
+				evt_payload->audcal_info.sample_rate =
+					dev_info->set_sample_rate ?
+					dev_info->set_sample_rate :
+					dev_info->sample_rate;
+			}
+			callback->auddev_evt_listener(
+				evt_id,
+				evt_payload,
+				callback->private_data);
+
+sent_aud_cal:
+			if (callback->cb_next == NULL)
+				break;
+			else {
+				callback = callback->cb_next;
+				continue;
+			}
+		}
+skip_check:
+voc_events:
+		if (callback->clnt_type == AUDDEV_CLNT_VOC) {
+			pr_debug("AUDDEV_CLNT_VOC\n");
+			if (evt_id == AUDDEV_EVT_DEV_RLS) {
+				if (!pending_sent)
+					goto sent_voc;
+				else
+					pending_sent = 0;
+			}
+			if (evt_id == AUDDEV_EVT_REL_PENDING)
+				pending_sent = 1;
+
+			if (evt_id == AUDDEV_EVT_DEVICE_VOL_MUTE_CHG) {
+				evt_payload->voc_vm_info.voice_session_id =
+								session_id;
+
+				if (dev_info->capability & SNDDEV_CAP_TX) {
+					evt_payload->voc_vm_info.dev_type =
+						SNDDEV_CAP_TX;
+					evt_payload->voc_vm_info.acdb_dev_id =
+						dev_info->acdb_id;
+					evt_payload->
+					voc_vm_info.dev_vm_val.mute =
+						routing_info.tx_mute;
+				} else {
+					evt_payload->voc_vm_info.dev_type =
+						SNDDEV_CAP_RX;
+					evt_payload->voc_vm_info.acdb_dev_id =
+						dev_info->acdb_id;
+					evt_payload->
+					voc_vm_info.dev_vm_val.vol =
+						routing_info.voice_rx_vol;
+				}
+			} else if ((evt_id == AUDDEV_EVT_START_VOICE)
+					|| (evt_id == AUDDEV_EVT_END_VOICE)) {
+				memset(evt_payload, 0,
+					sizeof(union auddev_evt_data));
+
+				evt_payload->voice_session_id = session_id;
+			} else if (evt_id == AUDDEV_EVT_FREQ_CHG) {
+				if (routing_info.voice_tx_sample_rate
+						!= dev_info->set_sample_rate) {
+					routing_info.voice_tx_sample_rate
+						= dev_info->set_sample_rate;
+					evt_payload->freq_info.sample_rate
+						= dev_info->set_sample_rate;
+					evt_payload->freq_info.dev_type
+						= dev_info->capability;
+					evt_payload->freq_info.acdb_dev_id
+						= dev_info->acdb_id;
+				} else
+					goto sent_voc;
+			} else if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
+				evt_payload->voice_state =
+						routing_info.voice_state;
+			else {
+				evt_payload->voc_devinfo.dev_type =
+					(dev_info->capability & SNDDEV_CAP_TX) ?
+					SNDDEV_CAP_TX : SNDDEV_CAP_RX;
+				evt_payload->voc_devinfo.acdb_dev_id =
+					dev_info->acdb_id;
+				evt_payload->voc_devinfo.dev_port_id =
+					dev_info->copp_id;
+				evt_payload->voc_devinfo.dev_sample =
+					dev_info->set_sample_rate ?
+					dev_info->set_sample_rate :
+					dev_info->sample_rate;
+				evt_payload->voc_devinfo.dev_id = dev_id;
+				if (dev_info->capability & SNDDEV_CAP_RX) {
+					for (i = 0; i < VOC_RX_VOL_ARRAY_NUM;
+						i++) {
+						evt_payload->
+						voc_devinfo.max_rx_vol[i] =
+						dev_info->max_voc_rx_vol[i];
+						evt_payload
+						->voc_devinfo.min_rx_vol[i] =
+						dev_info->min_voc_rx_vol[i];
+					}
+				}
+			}
+			callback->auddev_evt_listener(
+				evt_id,
+				evt_payload,
+				callback->private_data);
+			if (evt_id == AUDDEV_EVT_DEV_RLS)
+				dev_info->sessions &= ~(0xFFFF);
+sent_voc:
+			if (callback->cb_next == NULL)
+				break;
+			else {
+				callback = callback->cb_next;
+				continue;
+			}
+		}
+	}
+	kfree(evt_payload);
+	mutex_unlock(&session_lock);
+}
+EXPORT_SYMBOL(broadcast_event);
+
+
+void mixer_post_event(u32 evt_id, u32 id)
+{
+
+	pr_debug("evt_id = %d\n", evt_id);
+	switch (evt_id) {
+	case AUDDEV_EVT_DEV_CHG_VOICE: /* Called from Voice_route */
+		broadcast_event(AUDDEV_EVT_DEV_CHG_VOICE, id, SESSION_IGNORE);
+		break;
+	case AUDDEV_EVT_DEV_RDY:
+		broadcast_event(AUDDEV_EVT_DEV_RDY, id, SESSION_IGNORE);
+		break;
+	case AUDDEV_EVT_DEV_RLS:
+		broadcast_event(AUDDEV_EVT_DEV_RLS, id, SESSION_IGNORE);
+		break;
+	case AUDDEV_EVT_REL_PENDING:
+		broadcast_event(AUDDEV_EVT_REL_PENDING, id, SESSION_IGNORE);
+		break;
+	case AUDDEV_EVT_DEVICE_VOL_MUTE_CHG:
+		broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG, id,
+							SESSION_IGNORE);
+		break;
+	case AUDDEV_EVT_STREAM_VOL_CHG:
+		broadcast_event(AUDDEV_EVT_STREAM_VOL_CHG, id,
+							SESSION_IGNORE);
+		break;
+	case AUDDEV_EVT_START_VOICE:
+		broadcast_event(AUDDEV_EVT_START_VOICE,
+				id, SESSION_IGNORE);
+		break;
+	case AUDDEV_EVT_END_VOICE:
+		broadcast_event(AUDDEV_EVT_END_VOICE,
+				id, SESSION_IGNORE);
+		break;
+	case AUDDEV_EVT_FREQ_CHG:
+		broadcast_event(AUDDEV_EVT_FREQ_CHG, id, SESSION_IGNORE);
+		break;
+	default:
+		break;
+	}
+}
+EXPORT_SYMBOL(mixer_post_event);
+
+static int __init audio_dev_ctrl_init(void)
+{
+	init_waitqueue_head(&audio_dev_ctrl.wait);
+
+	event.cb = NULL;
+	msm_reset_device_work_queue = create_workqueue("reset_device");
+	if (msm_reset_device_work_queue == NULL)
+		return -ENOMEM;
+	atomic_set(&audio_dev_ctrl.opened, 0);
+	audio_dev_ctrl.num_dev = 0;
+	audio_dev_ctrl.voice_tx_dev = NULL;
+	audio_dev_ctrl.voice_rx_dev = NULL;
+	routing_info.voice_state = VOICE_STATE_INVALID;
+
+	mutex_init(&adm_tx_topology_tbl.lock);
+	mutex_init(&routing_info.copp_list_mutex);
+	mutex_init(&routing_info.adm_mutex);
+
+	memset(routing_info.copp_list, COPP_IGNORE,
+		(sizeof(unsigned int) * MAX_SESSIONS * AFE_MAX_PORTS));
+	return misc_register(&audio_dev_ctrl_misc);
+}
+
+static void __exit audio_dev_ctrl_exit(void)
+{
+	destroy_workqueue(msm_reset_device_work_queue);
+}
+module_init(audio_dev_ctrl_init);
+module_exit(audio_dev_ctrl_exit);
+
+MODULE_DESCRIPTION("MSM 8K Audio Device Control driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_evrc.c b/arch/arm/mach-msm/qdsp6v2/audio_evrc.c
new file mode 100644
index 0000000..ec5162d
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_evrc.c
@@ -0,0 +1,170 @@
+/* evrc audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2011-2012, Code Aurora Forum. 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.
+ *
+ */
+
+#include "audio_utils_aio.h"
+
+
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations audio_evrc_debug_fops = {
+	.read = audio_aio_debug_read,
+	.open = audio_aio_debug_open,
+};
+#endif
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct q6audio_aio *audio = file->private_data;
+	int rc = 0;
+
+	switch (cmd) {
+	case AUDIO_START: {
+		pr_debug("%s[%p]: AUDIO_START session_id[%d]\n", __func__,
+						audio, audio->ac->session);
+		if (audio->feedback == NON_TUNNEL_MODE) {
+			/* Configure PCM output block */
+			rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+					audio->pcm_cfg.sample_rate,
+					audio->pcm_cfg.channel_count);
+			if (rc < 0) {
+				pr_err("pcm output block config failed\n");
+				break;
+			}
+		}
+
+		rc = audio_aio_enable(audio);
+		audio->eos_rsp = 0;
+		audio->eos_flag = 0;
+		if (!rc) {
+			audio->enabled = 1;
+		} else {
+			audio->enabled = 0;
+			pr_err("Audio Start procedure failed rc=%d\n", rc);
+			break;
+		}
+		pr_debug("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
+						audio->ac->session,
+						audio->enabled);
+		if (audio->stopped == 1)
+			audio->stopped = 0;
+		break;
+	}
+	default:
+		pr_debug("%s[%p]: Calling utils ioctl\n", __func__, audio);
+		rc = audio->codec_ioctl(file, cmd, arg);
+	}
+	return rc;
+}
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct q6audio_aio *audio = NULL;
+	int rc = 0;
+
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_evrc_" + 5];
+#endif
+	audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+	if (audio == NULL) {
+		pr_err("Could not allocate memory for aac decode driver\n");
+		return -ENOMEM;
+	}
+
+	/* Settings will be re-config at AUDIO_SET_CONFIG,
+	 * but at least we need to have initial config
+	 */
+	audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+
+	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
+					     (void *)audio);
+
+	if (!audio->ac) {
+		pr_err("Could not allocate memory for audio client\n");
+		kfree(audio);
+		return -ENOMEM;
+	}
+
+	/* open in T/NT mode */
+	if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+		rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+					   FORMAT_EVRC);
+		if (rc < 0) {
+			pr_err("NT mode Open failed rc=%d\n", rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->feedback = NON_TUNNEL_MODE;
+		audio->buf_cfg.frames_per_buf = 0x01;
+		audio->buf_cfg.meta_info_enable = 0x01;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+		rc = q6asm_open_write(audio->ac, FORMAT_EVRC);
+		if (rc < 0) {
+			pr_err("T mode Open failed rc=%d\n", rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->feedback = TUNNEL_MODE;
+		audio->buf_cfg.meta_info_enable = 0x00;
+	} else {
+		pr_err("Not supported mode\n");
+		rc = -EACCES;
+		goto fail;
+	}
+	rc = audio_aio_open(audio, file);
+
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_evrc_%04x", audio->ac->session);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+					    NULL, (void *)audio,
+					    &audio_evrc_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		pr_debug("debugfs_create_file failed\n");
+#endif
+	pr_info("%s:dec success mode[%d]session[%d]\n", __func__,
+						audio->feedback,
+						audio->ac->session);
+	return rc;
+fail:
+	q6asm_audio_client_free(audio->ac);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_evrc_fops = {
+	.owner = THIS_MODULE,
+	.open = audio_open,
+	.release = audio_aio_release,
+	.unlocked_ioctl = audio_ioctl,
+	.fsync = audio_aio_fsync,
+};
+
+struct miscdevice audio_evrc_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_evrc",
+	.fops = &audio_evrc_fops,
+};
+
+static int __init audio_evrc_init(void)
+{
+	return misc_register(&audio_evrc_misc);
+}
+
+device_initcall(audio_evrc_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_lpa.c b/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
new file mode 100644
index 0000000..db0a96e
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
@@ -0,0 +1,1481 @@
+/* low power audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2009-2012, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/earlysuspend.h>
+#include <linux/ion.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <mach/msm_adsp.h>
+#include <sound/q6asm.h>
+#include <sound/apr_audio.h>
+#include "audio_lpa.h"
+
+#include <linux/msm_audio.h>
+#include <linux/wakelock.h>
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+
+#include <mach/debug_mm.h>
+#include <linux/fs.h>
+
+#define MAX_BUF 4
+#define BUFSZ (524288)
+
+#define AUDDEC_DEC_PCM 0
+
+#define AUDLPA_EVENT_NUM 10 /* Default number of pre-allocated event packets */
+
+#define __CONTAINS(r, v, l) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __v = v;					\
+	typeof(v) __e = __v + l;				\
+	int res = ((__v >= __r->vaddr) &&			\
+		(__e <= __r->vaddr + __r->len));		\
+	res;							\
+})
+
+#define CONTAINS(r1, r2) ({					\
+	typeof(r2) __r2 = r2;					\
+	__CONTAINS(r1, __r2->vaddr, __r2->len);			\
+})
+
+#define IN_RANGE(r, v) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __vv = v;					\
+	int res = ((__vv >= __r->vaddr) &&			\
+		(__vv < (__r->vaddr + __r->len)));		\
+	res;							\
+})
+
+#define OVERLAPS(r1, r2) ({					\
+	typeof(r1) __r1 = r1;					\
+	typeof(r2) __r2 = r2;					\
+	typeof(__r2->vaddr) __v = __r2->vaddr;			\
+	typeof(__v) __e = __v + __r2->len - 1;			\
+	int res = (IN_RANGE(__r1, __v) || IN_RANGE(__r1, __e));	\
+	res;							\
+})
+
+struct audlpa_event {
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+struct audlpa_ion_region {
+	struct list_head list;
+	struct ion_handle *handle;
+	struct ion_client *client;
+	int fd;
+	void *vaddr;
+	unsigned long paddr;
+	unsigned long kvaddr;
+	unsigned long len;
+	unsigned ref_cnt;
+};
+
+struct audlpa_buffer_node {
+	struct list_head list;
+	struct msm_audio_aio_buf buf;
+	unsigned long paddr;
+};
+
+struct audlpa_dec {
+	char *name;
+	int dec_attrb;
+	long (*ioctl)(struct file *, unsigned int, unsigned long);
+	int (*set_params)(void *);
+};
+
+static void audlpa_post_event(struct audio *audio, int type,
+	union msm_audio_event_payload payload);
+
+static unsigned long audlpa_ion_fixup(struct audio *audio, void *addr,
+				unsigned long len, int ref_up);
+static void audlpa_unmap_ion_region(struct audio *audio);
+static void audlpa_async_send_data(struct audio *audio, unsigned needed,
+				uint32_t token);
+static int audlpa_pause(struct audio *audio);
+static long pcm_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+static int audlpa_set_pcm_params(void *data);
+
+struct audlpa_dec audlpa_decs[] = {
+	{"msm_pcm_lp_dec", AUDDEC_DEC_PCM, &pcm_ioctl,
+		&audlpa_set_pcm_params},
+};
+
+static void lpa_listner(u32 evt_id, union auddev_evt_data *evt_payload,
+			void *private_data)
+{
+	struct audio *audio = (struct audio *) private_data;
+	int rc  = 0;
+
+	switch (evt_id) {
+	case AUDDEV_EVT_STREAM_VOL_CHG:
+		audio->volume = evt_payload->session_vol;
+		pr_debug("%s: AUDDEV_EVT_STREAM_VOL_CHG, stream vol %d, "
+				 "enabled = %d\n", __func__, audio->volume,
+				 audio->out_enabled);
+		if (audio->out_enabled == 1) {
+			if (audio->ac) {
+				rc = q6asm_set_volume(audio->ac, audio->volume);
+				if (rc < 0) {
+					pr_err("%s: Send Volume command failed"
+						" rc=%d\n", __func__, rc);
+				}
+			}
+		}
+		break;
+	default:
+		pr_err("%s:ERROR:wrong event\n", __func__);
+		break;
+	}
+}
+
+static void audlpa_prevent_sleep(struct audio *audio)
+{
+	pr_debug("%s:\n", __func__);
+	wake_lock(&audio->wakelock);
+}
+
+static void audlpa_allow_sleep(struct audio *audio)
+{
+	pr_debug("%s:\n", __func__);
+	wake_unlock(&audio->wakelock);
+}
+
+/* must be called with audio->lock held */
+static int audio_enable(struct audio *audio)
+{
+	pr_debug("%s\n", __func__);
+
+	return q6asm_run(audio->ac, 0, 0, 0);
+
+}
+
+static void audlpa_async_flush(struct audio *audio)
+{
+	struct audlpa_buffer_node *buf_node;
+	struct list_head *ptr, *next;
+	union msm_audio_event_payload payload;
+	int rc = 0;
+
+	pr_debug("%s:out_enabled = %d, drv_status = 0x%x\n", __func__,
+			audio->out_enabled, audio->drv_status);
+	if (audio->out_enabled) {
+		list_for_each_safe(ptr, next, &audio->out_queue) {
+			buf_node = list_entry(ptr, struct audlpa_buffer_node,
+						list);
+			list_del(&buf_node->list);
+			payload.aio_buf = buf_node->buf;
+				audlpa_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+								  payload);
+				kfree(buf_node);
+		}
+		/* Implicitly issue a pause to the decoder before flushing if
+		   it is not in pause state */
+		if (!(audio->drv_status & ADRV_STATUS_PAUSE)) {
+			rc = audlpa_pause(audio);
+			if (rc < 0)
+				pr_err("%s: pause cmd failed rc=%d\n", __func__,
+					rc);
+		}
+
+		rc = q6asm_cmd(audio->ac, CMD_FLUSH);
+		if (rc < 0)
+			pr_err("%s: flush cmd failed rc=%d\n", __func__, rc);
+
+		audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
+		audio->out_needed = 0;
+
+		if (audio->stopped == 0) {
+			rc = audio_enable(audio);
+			if (rc < 0)
+				pr_err("%s: audio enable failed\n", __func__);
+			else {
+				audio->out_enabled = 1;
+				audio->out_needed = 1;
+				if (audio->drv_status & ADRV_STATUS_PAUSE)
+					audio->drv_status &= ~ADRV_STATUS_PAUSE;
+			}
+		}
+		wake_up(&audio->write_wait);
+	}
+}
+
+/* must be called with audio->lock held */
+static int audio_disable(struct audio *audio)
+{
+	int rc = 0;
+
+	pr_debug("%s:%d %d\n", __func__, audio->opened, audio->out_enabled);
+
+	if (audio->opened) {
+		audio->out_enabled = 0;
+		audio->opened = 0;
+		rc = q6asm_cmd(audio->ac, CMD_CLOSE);
+		if (rc < 0)
+			pr_err("%s: CLOSE cmd failed\n", __func__);
+		else
+			pr_debug("%s: rxed CLOSE resp\n", __func__);
+		audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
+		wake_up(&audio->write_wait);
+		audio->out_needed = 0;
+	}
+	return rc;
+}
+static int audlpa_pause(struct audio *audio)
+{
+	int rc = 0;
+
+	pr_debug("%s, enabled = %d\n", __func__,
+			audio->out_enabled);
+	if (audio->out_enabled) {
+		rc = q6asm_cmd(audio->ac, CMD_PAUSE);
+		if (rc < 0)
+			pr_err("%s: pause cmd failed rc=%d\n", __func__, rc);
+
+	} else
+		pr_err("%s: Driver not enabled\n", __func__);
+	return rc;
+}
+
+/* ------------------- dsp --------------------- */
+static void audlpa_async_send_data(struct audio *audio, unsigned needed,
+				uint32_t token)
+{
+	unsigned long flags;
+	struct audio_client *ac;
+	int rc = 0;
+
+	pr_debug("%s:\n", __func__);
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+
+	pr_debug("%s: needed = %d, out_needed = %d, token = 0x%x\n",
+			  __func__, needed, audio->out_needed, token);
+	if (needed && !audio->wflush) {
+		audio->out_needed = 1;
+		if (audio->drv_status & ADRV_STATUS_OBUF_GIVEN) {
+			/* pop one node out of queue */
+			union msm_audio_event_payload evt_payload;
+			struct audlpa_buffer_node *used_buf;
+
+			used_buf = list_first_entry(&audio->out_queue,
+				struct audlpa_buffer_node, list);
+			if (token == used_buf->paddr) {
+				pr_debug("%s, Release: addr: %lx,"
+					" token = 0x%x\n", __func__,
+					used_buf->paddr, token);
+				list_del(&used_buf->list);
+				evt_payload.aio_buf = used_buf->buf;
+				audlpa_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+								  evt_payload);
+				kfree(used_buf);
+				audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
+			}
+		}
+	}
+	pr_debug("%s: out_needed = %d, stopped = %d, drv_status = 0x%x\n",
+			 __func__, audio->out_needed, audio->stopped,
+			 audio->drv_status);
+	if (audio->out_needed && (audio->stopped == 0)) {
+		struct audlpa_buffer_node *next_buf;
+		struct audio_aio_write_param param;
+		if (!list_empty(&audio->out_queue)) {
+			pr_debug("%s: list not empty\n", __func__);
+			next_buf = list_first_entry(&audio->out_queue,
+					struct audlpa_buffer_node, list);
+			if (next_buf) {
+				pr_debug("%s: Send: addr: %lx\n", __func__,
+						 next_buf->paddr);
+				ac = audio->ac;
+				param.paddr = next_buf->paddr;
+				param.len = next_buf->buf.data_len;
+				param.msw_ts = 0;
+				param.lsw_ts = 0;
+				/* No time stamp valid */
+				param.flags = NO_TIMESTAMP;
+				param.uid = next_buf->paddr;
+				rc = q6asm_async_write(ac, &param);
+				if (rc < 0)
+					pr_err("%s:q6asm_async_write failed\n",
+						__func__);
+				audio->out_needed = 0;
+				audio->drv_status |= ADRV_STATUS_OBUF_GIVEN;
+			}
+		} else if (list_empty(&audio->out_queue) &&
+				   (audio->drv_status & ADRV_STATUS_FSYNC)) {
+			pr_debug("%s: list is empty, reached EOS\n", __func__);
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static int audlpa_events_pending(struct audio *audio)
+{
+	int empty;
+
+	spin_lock(&audio->event_queue_lock);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock(&audio->event_queue_lock);
+	return empty || audio->event_abort;
+}
+
+static void audlpa_reset_event_queue(struct audio *audio)
+{
+	struct audlpa_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock(&audio->event_queue_lock);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+			struct audlpa_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+			struct audlpa_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock(&audio->event_queue_lock);
+
+	return;
+}
+
+static long audlpa_process_event_req(struct audio *audio, void __user *arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audlpa_event *drv_evt = NULL;
+	int timeout;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int) usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(
+			audio->event_wait, audlpa_events_pending(audio),
+			msecs_to_jiffies(timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(
+			audio->event_wait, audlpa_events_pending(audio));
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	rc = 0;
+
+	spin_lock(&audio->event_queue_lock);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+			struct audlpa_event, list);
+		list_del(&drv_evt->list);
+	}
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else
+		rc = -1;
+	spin_unlock(&audio->event_queue_lock);
+
+	if (drv_evt && (drv_evt->event_type == AUDIO_EVENT_WRITE_DONE ||
+	    drv_evt->event_type == AUDIO_EVENT_READ_DONE)) {
+		pr_debug("%s: AUDIO_EVENT_WRITE_DONE completing\n", __func__);
+		mutex_lock(&audio->lock);
+		audlpa_ion_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+				  drv_evt->payload.aio_buf.buf_len, 0);
+		mutex_unlock(&audio->lock);
+	}
+	if (!rc && copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audlpa_ion_check(struct audio *audio,
+			void *vaddr, unsigned long len)
+{
+	struct audlpa_ion_region *region_elt;
+	struct audlpa_ion_region t = {.vaddr = vaddr, .len = len };
+
+	list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
+		if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
+		    OVERLAPS(region_elt, &t)) {
+			pr_err("%s[%p]:region (vaddr %p len %ld)"
+			" clashes with registered region"
+			" (vaddr %p paddr %p len %ld)\n",
+			__func__, audio, vaddr, len,
+			region_elt->vaddr,
+			(void *)region_elt->paddr, region_elt->len);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+static int audlpa_ion_add(struct audio *audio,
+			struct msm_audio_ion_info *info)
+{
+	ion_phys_addr_t paddr;
+	size_t len;
+	unsigned long kvaddr;
+	struct audlpa_ion_region *region;
+	int rc = -EINVAL;
+	struct ion_handle *handle;
+	struct ion_client *client;
+	unsigned long ionflag;
+	void *temp_ptr;
+
+	pr_debug("%s[%p]:\n", __func__, audio);
+	region = kmalloc(sizeof(*region), GFP_KERNEL);
+
+	if (!region) {
+		rc = -ENOMEM;
+		goto end;
+	}
+
+	client = msm_ion_client_create(UINT_MAX, "Audio_LPA_Client");
+	if (IS_ERR_OR_NULL(client)) {
+		pr_err("Unable to create ION client\n");
+		goto client_error;
+	}
+
+	handle = ion_import_fd(client, info->fd);
+	if (IS_ERR_OR_NULL(handle)) {
+		pr_err("%s: could not get handle of the given fd\n", __func__);
+		goto import_error;
+	}
+
+	rc = ion_handle_get_flags(client, handle, &ionflag);
+	if (rc) {
+		pr_err("%s: could not get flags for the handle\n", __func__);
+		goto flag_error;
+	}
+
+	temp_ptr = ion_map_kernel(client, handle, ionflag);
+	if (IS_ERR_OR_NULL(temp_ptr)) {
+		pr_err("%s: could not get virtual address\n", __func__);
+		goto map_error;
+	}
+	kvaddr = (unsigned long) temp_ptr;
+
+	rc = ion_phys(client, handle, &paddr, &len);
+	if (rc) {
+		pr_err("%s: could not get physical address\n", __func__);
+		goto ion_error;
+	}
+
+	rc = audlpa_ion_check(audio, info->vaddr, len);
+	if (rc < 0) {
+		pr_err("%s: audlpa_ion_check failed\n", __func__);
+		goto ion_error;
+	}
+
+	region->client = client;
+	region->handle = handle;
+	region->vaddr = info->vaddr;
+	region->fd = info->fd;
+	region->paddr = paddr;
+	region->kvaddr = kvaddr;
+	region->len = len;
+	region->ref_cnt = 0;
+	pr_debug("%s[%p]:add region paddr %lx vaddr %p, len %lu kvaddr %lx\n",
+		__func__, audio,
+		region->paddr, region->vaddr, region->len, region->kvaddr);
+	list_add_tail(&region->list, &audio->ion_region_queue);
+
+	rc = q6asm_memory_map(audio->ac, (uint32_t)paddr, IN, (uint32_t)len, 1);
+	if (rc < 0) {
+		pr_err("%s[%p]: memory map failed\n", __func__, audio);
+		goto ion_error;
+	} else {
+		goto end;
+	}
+
+ion_error:
+	ion_unmap_kernel(client, handle);
+map_error:
+	ion_free(client, handle);
+flag_error:
+import_error:
+	ion_client_destroy(client);
+client_error:
+	kfree(region);
+end:
+	return rc;
+}
+
+static int audlpa_ion_remove(struct audio *audio,
+			struct msm_audio_ion_info *info)
+{
+	struct audlpa_ion_region *region;
+	struct list_head *ptr, *next;
+	int rc = -EINVAL;
+
+	list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+		region = list_entry(ptr, struct audlpa_ion_region, list);
+
+		if (region != NULL && (region->fd == info->fd) &&
+			(region->vaddr == info->vaddr)) {
+			if (region->ref_cnt) {
+				pr_debug("%s[%p]:region %p in use ref_cnt %d\n",
+					__func__, audio, region,
+					region->ref_cnt);
+				break;
+			}
+			rc = q6asm_memory_unmap(audio->ac,
+				(uint32_t) region->paddr, IN);
+			if (rc < 0)
+				pr_err("%s[%p]: memory unmap failed\n",
+					__func__, audio);
+
+			list_del(&region->list);
+			ion_unmap_kernel(region->client, region->handle);
+			ion_free(region->client, region->handle);
+			ion_client_destroy(region->client);
+			kfree(region);
+			rc = 0;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static int audlpa_ion_lookup_vaddr(struct audio *audio, void *addr,
+			unsigned long len, struct audlpa_ion_region **region)
+{
+	struct audlpa_ion_region *region_elt;
+	int match_count = 0;
+	*region = NULL;
+
+	/* returns physical address or zero */
+	list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
+		if (addr >= region_elt->vaddr &&
+			addr < region_elt->vaddr + region_elt->len &&
+			addr + len <= region_elt->vaddr + region_elt->len) {
+			/* offset since we could pass vaddr inside a registerd
+			* ion buffer
+			*/
+
+			match_count++;
+			if (!*region)
+				*region = region_elt;
+		}
+	}
+
+	if (match_count > 1) {
+		pr_err("%s[%p]:multiple hits for vaddr %p, len %ld\n",
+			 __func__, audio, addr, len);
+		list_for_each_entry(region_elt, &audio->ion_region_queue,
+					list) {
+		if (addr >= region_elt->vaddr &&
+			addr < region_elt->vaddr + region_elt->len &&
+			addr + len <= region_elt->vaddr + region_elt->len)
+			pr_err("\t%s[%p]:%p, %ld --> %p\n",
+				__func__, audio,
+					region_elt->vaddr,
+					region_elt->len,
+					(void *)region_elt->paddr);
+		}
+	}
+	return *region ? 0 : -1;
+}
+static unsigned long audlpa_ion_fixup(struct audio *audio, void *addr,
+			unsigned long len, int ref_up)
+{
+	struct audlpa_ion_region *region;
+	unsigned long paddr;
+	int ret;
+
+	ret = audlpa_ion_lookup_vaddr(audio, addr, len, &region);
+	if (ret) {
+		pr_err("%s[%p]:lookup (%p, %ld) failed\n",
+			__func__, audio, addr, len);
+		return 0;
+	}
+	if (ref_up)
+		region->ref_cnt++;
+	else
+		region->ref_cnt--;
+	paddr = region->paddr + (addr - region->vaddr);
+	return paddr;
+}
+
+/* audio -> lock must be held at this point */
+static int audlpa_aio_buf_add(struct audio *audio, unsigned dir,
+	void __user *arg)
+{
+	struct audlpa_buffer_node *buf_node;
+
+	buf_node = kmalloc(sizeof(*buf_node), GFP_KERNEL);
+
+	if (!buf_node)
+		return -ENOMEM;
+
+	if (copy_from_user(&buf_node->buf, arg, sizeof(buf_node->buf))) {
+		kfree(buf_node);
+		return -EFAULT;
+	}
+
+	buf_node->paddr = audlpa_ion_fixup(
+		audio, buf_node->buf.buf_addr,
+		buf_node->buf.buf_len, 1);
+	if (dir) {
+		/* write */
+		if (!buf_node->paddr ||
+		    (buf_node->paddr & 0x1) ||
+		    (buf_node->buf.data_len & 0x1)) {
+			kfree(buf_node);
+			return -EINVAL;
+		}
+		list_add_tail(&buf_node->list, &audio->out_queue);
+		pr_debug("%s, Added to list: addr: %lx, length = %d\n",
+			__func__, buf_node->paddr, buf_node->buf.data_len);
+		audlpa_async_send_data(audio, 0, 0);
+	} else {
+		/* read */
+		kfree(buf_node);
+	}
+	return 0;
+}
+
+static int config(struct audio *audio)
+{
+	int rc = 0;
+	if (!audio->out_prefill) {
+		if (audio->codec_ops.set_params != NULL) {
+			rc = audio->codec_ops.set_params(audio);
+			audio->out_prefill = 1;
+		}
+	}
+	return rc;
+}
+
+void q6_audlpa_out_cb(uint32_t opcode, uint32_t token,
+			uint32_t *payload, void *priv)
+{
+	struct audio *audio = (struct audio *) priv;
+
+	switch (opcode) {
+	case ASM_DATA_EVENT_WRITE_DONE:
+		pr_debug("%s: ASM_DATA_EVENT_WRITE_DONE, token = 0x%x\n",
+				 __func__, token);
+		audlpa_async_send_data(audio, 1, token);
+		break;
+	case ASM_DATA_EVENT_EOS:
+	case ASM_DATA_CMDRSP_EOS:
+		pr_debug("%s: ASM_DATA_CMDRSP_EOS, teos = %d\n", __func__,
+				 audio->teos);
+		if (audio->teos == 0) {
+			audio->teos = 1;
+			wake_up(&audio->write_wait);
+		}
+		break;
+	case ASM_SESSION_CMDRSP_GET_SESSION_TIME:
+		break;
+	case RESET_EVENTS:
+		reset_device();
+		break;
+	default:
+		break;
+	}
+}
+
+static long pcm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	pr_debug("%s: cmd = %d\n", __func__, cmd);
+	return -EINVAL;
+}
+
+static int audlpa_set_pcm_params(void *data)
+{
+	struct audio *audio = (struct audio *)data;
+	int rc;
+
+	rc = q6asm_media_format_block_pcm(audio->ac, audio->out_sample_rate,
+					audio->out_channel_mode);
+	if (rc < 0)
+		pr_err("%s: Format block pcm failed\n", __func__);
+	return rc;
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = -EINVAL;
+	uint64_t timestamp;
+	uint64_t temp;
+
+	pr_debug("%s: audio_ioctl() cmd = %d\n", __func__, cmd);
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+
+		pr_debug("%s: AUDIO_GET_STATS cmd\n", __func__);
+		memset(&stats, 0, sizeof(stats));
+		timestamp = q6asm_get_session_time(audio->ac);
+		if (timestamp < 0) {
+			pr_err("%s: Get Session Time return value =%lld\n",
+				__func__, timestamp);
+			return -EAGAIN;
+		}
+		temp = (timestamp * 2 * audio->out_channel_mode);
+		temp = temp * (audio->out_sample_rate/1000);
+		temp = div_u64(temp, 1000);
+		audio->bytes_consumed = (uint32_t)(temp & 0xFFFFFFFF);
+		stats.byte_count = audio->bytes_consumed;
+		stats.unused[0]  = (uint32_t)((temp >> 32) & 0xFFFFFFFF);
+		pr_debug("%s: bytes_consumed:lsb = %d, msb = %d,"
+			"timestamp = %lld\n", __func__,
+			audio->bytes_consumed, stats.unused[0], timestamp);
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+				return -EFAULT;
+		return 0;
+	}
+
+	switch (cmd) {
+	case AUDIO_ENABLE_AUDPP:
+		break;
+
+	case AUDIO_SET_VOLUME:
+		break;
+
+	case AUDIO_SET_PAN:
+		break;
+
+	case AUDIO_SET_EQ:
+		break;
+	}
+
+	if (cmd == AUDIO_GET_EVENT) {
+		pr_debug("%s: AUDIO_GET_EVENT\n", __func__);
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audlpa_process_event_req(audio,
+				(void __user *) arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		return rc;
+	}
+
+	if (cmd == AUDIO_ABORT_GET_EVENT) {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		pr_info("%s: AUDIO_START: Session %d\n", __func__,
+			audio->ac->session);
+		if (!audio->opened) {
+			pr_err("%s: Driver not opened\n", __func__);
+			rc = -EFAULT;
+			goto fail;
+		}
+		rc = config(audio);
+		if (rc) {
+			pr_err("%s: Out Configuration failed\n", __func__);
+			rc = -EFAULT;
+			goto fail;
+		}
+
+		rc = audio_enable(audio);
+		if (rc) {
+			pr_err("%s: audio enable failed\n", __func__);
+			rc = -EFAULT;
+			goto fail;
+		} else {
+			struct asm_softpause_params softpause = {
+				.enable = SOFT_PAUSE_ENABLE,
+				.period = SOFT_PAUSE_PERIOD,
+				.step = SOFT_PAUSE_STEP,
+				.rampingcurve = SOFT_PAUSE_CURVE_LINEAR,
+			};
+			struct asm_softvolume_params softvol = {
+				.period = SOFT_VOLUME_PERIOD,
+				.step = SOFT_VOLUME_STEP,
+				.rampingcurve = SOFT_VOLUME_CURVE_LINEAR,
+			};
+			audio->out_enabled = 1;
+			audio->out_needed = 1;
+			rc = q6asm_set_volume(audio->ac, audio->volume);
+			if (rc < 0)
+				pr_err("%s: Send Volume command failed rc=%d\n",
+					__func__, rc);
+			rc = q6asm_set_softpause(audio->ac, &softpause);
+			if (rc < 0)
+				pr_err("%s: Send SoftPause Param failed rc=%d\n",
+					__func__, rc);
+			rc = q6asm_set_softvolume(audio->ac, &softvol);
+			if (rc < 0)
+				pr_err("%s: Send SoftVolume Param failed rc=%d\n",
+					__func__, rc);
+			rc = q6asm_set_lrgain(audio->ac, 0x2000, 0x2000);
+			if (rc < 0)
+				pr_err("%s: Send channel gain failed rc=%d\n",
+					__func__, rc);
+			/* disable mute by default */
+			rc = q6asm_set_mute(audio->ac, 0);
+			if (rc < 0)
+				pr_err("%s: Send mute command failed rc=%d\n",
+					__func__, rc);
+			if (!list_empty(&audio->out_queue))
+				pr_err("%s: write_list is not empty!!!\n",
+					__func__);
+			if (audio->stopped == 1)
+				audio->stopped = 0;
+			audlpa_prevent_sleep(audio);
+		}
+		break;
+
+	case AUDIO_STOP:
+		pr_info("%s: AUDIO_STOP: session_id:%d\n", __func__,
+			audio->ac->session);
+		audio->stopped = 1;
+		audlpa_async_flush(audio);
+		audio->out_enabled = 0;
+		audio->out_needed = 0;
+		audio->drv_status &= ~ADRV_STATUS_PAUSE;
+		audlpa_allow_sleep(audio);
+		break;
+
+	case AUDIO_FLUSH:
+		pr_debug("%s: AUDIO_FLUSH: session_id:%d\n", __func__,
+			audio->ac->session);
+		audio->wflush = 1;
+		if (audio->out_enabled)
+			audlpa_async_flush(audio);
+		else
+			audio->wflush = 0;
+		audio->wflush = 0;
+		break;
+
+	case AUDIO_SET_CONFIG:{
+		struct msm_audio_config config;
+		pr_debug("%s: AUDIO_SET_CONFIG\n", __func__);
+		if (copy_from_user(&config, (void *) arg, sizeof(config))) {
+			rc = -EFAULT;
+			pr_err("%s: ERROR: copy from user\n", __func__);
+			break;
+		}
+		if (!((config.channel_count == 1) ||
+			(config.channel_count == 2))) {
+			rc = -EINVAL;
+			pr_err("%s: ERROR: config.channel_count == %d\n",
+				__func__, config.channel_count);
+			break;
+		}
+
+		if (!((config.bits == 8) || (config.bits == 16) ||
+			  (config.bits == 24))) {
+			rc = -EINVAL;
+			pr_err("%s: ERROR: config.bits = %d\n", __func__,
+				config.bits);
+			break;
+		}
+		audio->out_sample_rate = config.sample_rate;
+		audio->out_channel_mode = config.channel_count;
+		audio->out_bits = config.bits;
+		audio->buffer_count = config.buffer_count;
+		audio->buffer_size = config.buffer_size;
+		rc = 0;
+		break;
+	}
+
+	case AUDIO_GET_CONFIG:{
+		struct msm_audio_config config;
+		config.buffer_count = audio->buffer_count;
+		config.buffer_size = audio->buffer_size;
+		config.sample_rate = audio->out_sample_rate;
+		config.channel_count = audio->out_channel_mode;
+		config.bits = audio->out_bits;
+
+		config.meta_field = 0;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void *) arg, &config, sizeof(config)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	}
+
+	case AUDIO_PAUSE:
+		pr_debug("%s: AUDIO_PAUSE %ld\n", __func__, arg);
+		if (arg == 1) {
+			rc = audlpa_pause(audio);
+			if (rc < 0)
+				pr_err("%s: pause FAILED rc=%d\n", __func__,
+					rc);
+			audio->drv_status |= ADRV_STATUS_PAUSE;
+		} else if (arg == 0) {
+			if (audio->drv_status & ADRV_STATUS_PAUSE) {
+				rc = audio_enable(audio);
+				if (rc)
+					pr_err("%s: audio enable failed\n",
+						__func__);
+				else {
+					audio->drv_status &= ~ADRV_STATUS_PAUSE;
+					audio->out_enabled = 1;
+				}
+			}
+		}
+		break;
+
+	case AUDIO_REGISTER_ION: {
+		struct msm_audio_ion_info info;
+		pr_debug("%s: AUDIO_REGISTER_ION\n", __func__);
+		if (copy_from_user(&info, (void *)arg, sizeof(info)))
+			rc = -EFAULT;
+		else
+			rc = audlpa_ion_add(audio, &info);
+		break;
+	}
+
+	case AUDIO_DEREGISTER_ION: {
+		struct msm_audio_ion_info info;
+		pr_debug("%s: AUDIO_DEREGISTER_ION\n", __func__);
+		if (copy_from_user(&info, (void *)arg, sizeof(info)))
+			rc = -EFAULT;
+		else
+			rc = audlpa_ion_remove(audio, &info);
+		break;
+	}
+
+	case AUDIO_ASYNC_WRITE:
+		pr_debug("%s: AUDIO_ASYNC_WRITE\n", __func__);
+		if (audio->drv_status & ADRV_STATUS_FSYNC)
+			rc = -EBUSY;
+		else
+			rc = audlpa_aio_buf_add(audio, 1, (void __user *) arg);
+		break;
+
+	case AUDIO_GET_SESSION_ID:
+		if (copy_to_user((void *) arg, &audio->ac->session,
+					sizeof(unsigned short)))
+			return -EFAULT;
+		rc = 0;
+		break;
+
+	default:
+		rc = audio->codec_ops.ioctl(file, cmd, arg);
+	}
+fail:
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+/* Only useful in tunnel-mode */
+int audlpa_async_fsync(struct audio *audio)
+{
+	int rc = 0;
+
+	pr_info("%s:Session %d\n", __func__, audio->ac->session);
+
+	/* Blocking client sends more data */
+	mutex_lock(&audio->lock);
+	audio->drv_status |= ADRV_STATUS_FSYNC;
+	mutex_unlock(&audio->lock);
+
+	mutex_lock(&audio->write_lock);
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+					((list_empty(&audio->out_queue)) ||
+					audio->wflush || audio->stopped));
+
+	if (audio->wflush || audio->stopped)
+		goto flush_event;
+
+	if (rc < 0) {
+		pr_err("%s: wait event for list_empty failed, rc = %d\n",
+			__func__, rc);
+		goto done;
+	}
+
+	rc = q6asm_cmd(audio->ac, CMD_EOS);
+
+	if (rc < 0) {
+		pr_err("%s: q6asm_cmd failed, rc = %d", __func__, rc);
+		goto done;
+	}
+	rc = wait_event_interruptible_timeout(audio->write_wait,
+				  (audio->teos || audio->wflush ||
+				  audio->stopped), 5*HZ);
+
+	if (rc < 0) {
+		pr_err("%s: wait event for teos failed, rc = %d\n", __func__,
+			rc);
+		goto done;
+	}
+
+	if (audio->teos == 1) {
+		rc = audio_enable(audio);
+		if (rc)
+			pr_err("%s: audio enable failed\n", __func__);
+		else {
+			audio->drv_status &= ~ADRV_STATUS_PAUSE;
+			audio->out_enabled = 1;
+			audio->out_needed = 1;
+		}
+	}
+
+flush_event:
+	if (audio->stopped || audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+	mutex_lock(&audio->lock);
+	audio->drv_status &= ~ADRV_STATUS_FSYNC;
+	mutex_unlock(&audio->lock);
+
+	return rc;
+}
+
+int audlpa_fsync(struct file *file, loff_t ppos1, loff_t ppos2, int datasync)
+{
+	struct audio *audio = file->private_data;
+
+	return audlpa_async_fsync(audio);
+}
+
+void audlpa_reset_ion_region(struct audio *audio)
+{
+	struct audlpa_ion_region *region;
+	struct list_head *ptr, *next;
+
+	list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+		region = list_entry(ptr, struct audlpa_ion_region, list);
+		list_del(&region->list);
+		ion_unmap_kernel(region->client, region->handle);
+		ion_free(region->client, region->handle);
+		ion_client_destroy(region->client);
+		kfree(region);
+	}
+
+	return;
+}
+
+static void audlpa_unmap_ion_region(struct audio *audio)
+{
+	struct audlpa_ion_region *region;
+	struct list_head *ptr, *next;
+	int rc = -EINVAL;
+
+	pr_debug("%s[%p]:\n", __func__, audio);
+	list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+		region = list_entry(ptr, struct audlpa_ion_region, list);
+		pr_debug("%s[%p]: phy_address = 0x%lx\n",
+			__func__, audio, region->paddr);
+		if (region != NULL) {
+			rc = q6asm_memory_unmap(audio->ac,
+					(uint32_t)region->paddr, IN);
+			if (rc < 0)
+				pr_err("%s: memory unmap failed\n", __func__);
+		}
+	}
+}
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	pr_info("%s: audio instance 0x%08x freeing, session %d\n", __func__,
+		(int)audio, audio->ac->session);
+
+	mutex_lock(&audio->lock);
+	audio->wflush = 1;
+	if (audio->out_enabled)
+		audlpa_async_flush(audio);
+	audio->wflush = 0;
+	audlpa_unmap_ion_region(audio);
+	audio_disable(audio);
+	msm_clear_session_id(audio->ac->session);
+	auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->ac->session);
+	q6asm_audio_client_free(audio->ac);
+	audlpa_reset_ion_region(audio);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&audio->suspend_ctl.node);
+#endif
+	audio->opened = 0;
+	audio->out_enabled = 0;
+	audio->out_prefill = 0;
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audlpa_reset_event_queue(audio);
+	if (audio->stopped == 0)
+		audlpa_allow_sleep(audio);
+	wake_lock_destroy(&audio->wakelock);
+
+	mutex_unlock(&audio->lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio);
+	return 0;
+}
+
+static void audlpa_post_event(struct audio *audio, int type,
+	union msm_audio_event_payload payload)
+{
+	struct audlpa_event *e_node = NULL;
+
+	spin_lock(&audio->event_queue_lock);
+
+	pr_debug("%s:\n", __func__);
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+			struct audlpa_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audlpa_event), GFP_ATOMIC);
+		if (!e_node) {
+			pr_err("%s: No mem to post event %d\n", __func__, type);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock(&audio->event_queue_lock);
+	wake_up(&audio->event_wait);
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audlpa_suspend(struct early_suspend *h)
+{
+	struct audlpa_suspend_ctl *ctl =
+		container_of(h, struct audlpa_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	pr_debug("%s:\n", __func__);
+	audlpa_post_event(ctl->audio, AUDIO_EVENT_SUSPEND, payload);
+}
+
+static void audlpa_resume(struct early_suspend *h)
+{
+	struct audlpa_suspend_ctl *ctl =
+		container_of(h, struct audlpa_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	pr_debug("%s:\n", __func__);
+	audlpa_post_event(ctl->audio, AUDIO_EVENT_RESUME, payload);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audlpa_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audlpa_debug_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 4096;
+	static char buffer[4096];
+	int n = 0;
+	struct audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+					"out_enabled %d\n", audio->out_enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+					"stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+					"volume %x\n", audio->volume);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+					"sample rate %d\n",
+					audio->out_sample_rate);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+					"channel mode %d\n",
+					audio->out_channel_mode);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+					"wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+					"running %d\n", audio->running);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+					"out_needed %d\n", audio->out_needed);
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audlpa_debug_fops = {
+	.read = audlpa_debug_read,
+	.open = audlpa_debug_open,
+};
+#endif
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = NULL;
+	int rc, i, dec_attrb = 0;
+	struct audlpa_event *e_node = NULL;
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_lpa_" + 5];
+#endif
+	char wake_lock_name[24];
+
+	/* Allocate audio instance, set to zero */
+	audio = kzalloc(sizeof(struct audio), GFP_KERNEL);
+	if (!audio) {
+		pr_err("%s: no memory to allocate audio instance\n", __func__);
+		rc = -ENOMEM;
+		goto done;
+	}
+
+	if ((file->f_mode & FMODE_WRITE) && !(file->f_mode & FMODE_READ)) {
+		pr_debug("%s: Tunnel Mode playback\n", __func__);
+	} else {
+		kfree(audio);
+		rc = -EACCES;
+		goto done;
+	}
+
+	/* Allocate the decoder based on inode minor number*/
+	audio->minor_no = iminor(inode);
+	dec_attrb |= audlpa_decs[audio->minor_no].dec_attrb;
+	audio->codec_ops.ioctl = audlpa_decs[audio->minor_no].ioctl;
+	audio->codec_ops.set_params = audlpa_decs[audio->minor_no].set_params;
+	audio->buffer_size = BUFSZ;
+	audio->buffer_count = MAX_BUF;
+
+	audio->ac = q6asm_audio_client_alloc((app_cb)q6_audlpa_out_cb,
+					(void *)audio);
+	if (!audio->ac) {
+		pr_err("%s: Could not allocate memory for lpa client\n",
+								__func__);
+		rc = -ENOMEM;
+		goto err;
+	}
+	rc = q6asm_open_write(audio->ac, FORMAT_LINEAR_PCM);
+	if (rc < 0) {
+		pr_err("%s: lpa out open failed\n", __func__);
+		goto err;
+	}
+
+	pr_debug("%s: Set mode to AIO session[%d]\n",
+						__func__,
+						audio->ac->session);
+	rc = q6asm_set_io_mode(audio->ac, ASYNC_IO_MODE);
+	if (rc < 0)
+		pr_err("%s: Set IO mode failed\n", __func__);
+
+
+	/* Initialize all locks of audio instance */
+	mutex_init(&audio->lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->get_event_lock);
+	spin_lock_init(&audio->dsp_lock);
+	init_waitqueue_head(&audio->write_wait);
+	INIT_LIST_HEAD(&audio->out_queue);
+	INIT_LIST_HEAD(&audio->ion_region_queue);
+	INIT_LIST_HEAD(&audio->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+	init_waitqueue_head(&audio->wait);
+	init_waitqueue_head(&audio->event_wait);
+	spin_lock_init(&audio->event_queue_lock);
+	snprintf(wake_lock_name, sizeof wake_lock_name, "audio_lpa_%x",
+		audio->ac->session);
+	wake_lock_init(&audio->wakelock, WAKE_LOCK_SUSPEND, wake_lock_name);
+
+	audio->out_sample_rate = 44100;
+	audio->out_channel_mode = 2;
+	audio->out_bits = 16;
+	audio->volume = 0x2000;
+
+	file->private_data = audio;
+	audio->opened = 1;
+	audio->out_enabled = 0;
+	audio->out_prefill = 0;
+	audio->bytes_consumed = 0;
+
+	audio->device_events = AUDDEV_EVT_STREAM_VOL_CHG;
+	audio->drv_status &= ~ADRV_STATUS_PAUSE;
+
+	rc = auddev_register_evt_listner(audio->device_events,
+					AUDDEV_CLNT_DEC,
+					audio->ac->session,
+					lpa_listner,
+					(void *)audio);
+	if (rc) {
+		pr_err("%s: failed to register listner\n", __func__);
+		goto err;
+	}
+
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_lpa_%04x", audio->ac->session);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+			NULL, (void *) audio, &audlpa_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		pr_err("%s: debugfs_create_file failed\n", __func__);
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	audio->suspend_ctl.node.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+	audio->suspend_ctl.node.resume = audlpa_resume;
+	audio->suspend_ctl.node.suspend = audlpa_suspend;
+	audio->suspend_ctl.audio = audio;
+	register_early_suspend(&audio->suspend_ctl.node);
+#endif
+	for (i = 0; i < AUDLPA_EVENT_NUM; i++) {
+		e_node = kmalloc(sizeof(struct audlpa_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			pr_err("%s: event pkt alloc failed\n", __func__);
+			break;
+		}
+	}
+	pr_info("%s: audio instance 0x%08x created session[%d]\n", __func__,
+						(int)audio,
+						audio->ac->session);
+done:
+	return rc;
+err:
+	q6asm_audio_client_free(audio->ac);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_lpa_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audio_open,
+	.release	= audio_release,
+	.unlocked_ioctl	= audio_ioctl,
+	.fsync		= audlpa_fsync,
+};
+
+static dev_t audlpa_devno;
+static struct class *audlpa_class;
+struct audlpa_device {
+	const char *name;
+	struct device *device;
+	struct cdev cdev;
+};
+
+static struct audlpa_device *audlpa_devices;
+
+static void audlpa_create(struct audlpa_device *adev, const char *name,
+			struct device *parent, dev_t devt)
+{
+	struct device *dev;
+	int rc;
+
+	dev = device_create(audlpa_class, parent, devt, "%s", name);
+	if (IS_ERR(dev))
+		return;
+
+	cdev_init(&adev->cdev, &audio_lpa_fops);
+	adev->cdev.owner = THIS_MODULE;
+
+	rc = cdev_add(&adev->cdev, devt, 1);
+	if (rc < 0) {
+		device_destroy(audlpa_class, devt);
+	} else {
+		adev->device = dev;
+		adev->name = name;
+	}
+}
+
+static int __init audio_init(void)
+{
+	int rc;
+	int n = ARRAY_SIZE(audlpa_decs);
+
+	audlpa_devices = kzalloc(sizeof(struct audlpa_device) * n, GFP_KERNEL);
+	if (!audlpa_devices)
+		return -ENOMEM;
+
+	audlpa_class = class_create(THIS_MODULE, "audlpa");
+	if (IS_ERR(audlpa_class))
+		goto fail_create_class;
+
+	rc = alloc_chrdev_region(&audlpa_devno, 0, n, "msm_audio_lpa");
+	if (rc < 0)
+		goto fail_alloc_region;
+
+	for (n = 0; n < ARRAY_SIZE(audlpa_decs); n++) {
+		audlpa_create(audlpa_devices + n,
+				audlpa_decs[n].name, NULL,
+				MKDEV(MAJOR(audlpa_devno), n));
+	}
+
+	return 0;
+
+fail_alloc_region:
+	class_unregister(audlpa_class);
+	return rc;
+fail_create_class:
+	kfree(audlpa_devices);
+	return -ENOMEM;
+}
+
+static void __exit audio_exit(void)
+{
+	class_unregister(audlpa_class);
+	kfree(audlpa_devices);
+}
+
+module_init(audio_init);
+module_exit(audio_exit);
+
+MODULE_DESCRIPTION("MSM LPA driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_lpa.h b/arch/arm/mach-msm/qdsp6v2/audio_lpa.h
new file mode 100644
index 0000000..34b53f2
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_lpa.h
@@ -0,0 +1,104 @@
+/* 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
+ * 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 AUDIO_LPA_H
+#define AUDIO_LPA_H
+
+#include <linux/earlysuspend.h>
+#include <linux/wakelock.h>
+
+#define ADRV_STATUS_OBUF_GIVEN 0x00000001
+#define ADRV_STATUS_IBUF_GIVEN 0x00000002
+#define ADRV_STATUS_FSYNC 0x00000004
+#define ADRV_STATUS_PAUSE 0x00000008
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct audlpa_suspend_ctl {
+	struct early_suspend node;
+	struct audio *audio;
+};
+#endif
+
+struct codec_operations {
+	long (*ioctl)(struct file *, unsigned int, unsigned long);
+	int (*set_params)(void *);
+};
+
+struct audio {
+	spinlock_t dsp_lock;
+
+	uint8_t out_needed; /* number of buffers the dsp is waiting for */
+	struct list_head out_queue; /* queue to retain output buffers */
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	struct audio_client *ac;
+
+	/* configuration to use on next enable */
+	uint32_t out_sample_rate;
+	uint32_t out_channel_mode;
+	uint32_t out_bits; /* bits per sample (used by PCM decoder) */
+
+	int32_t phys; /* physical address of write buffer */
+
+	uint32_t drv_status;
+	int wflush; /* Write flush */
+	int opened;
+	int out_enabled;
+	int out_prefill;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+	int buf_refresh;
+	int teos; /* valid only if tunnel mode & no data left for decoder */
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct audlpa_suspend_ctl suspend_ctl;
+#endif
+
+	struct wake_lock wakelock;
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+
+	wait_queue_head_t wait;
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	wait_queue_head_t event_wait;
+	spinlock_t event_queue_lock;
+	struct mutex get_event_lock;
+	int event_abort;
+
+	uint32_t device_events;
+
+	struct list_head ion_region_queue; /* protected by lock */
+
+	int eq_enable;
+	int eq_needs_commit;
+	uint32_t volume;
+
+	unsigned int minor_no;
+	struct codec_operations codec_ops;
+	uint32_t buffer_size;
+	uint32_t buffer_count;
+	uint32_t bytes_consumed;
+};
+
+#endif /* !AUDIO_LPA_H */
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_mp3.c b/arch/arm/mach-msm/qdsp6v2/audio_mp3.c
new file mode 100644
index 0000000..93a8739
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_mp3.c
@@ -0,0 +1,165 @@
+/* mp3 audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2011-2012, Code Aurora Forum. 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.
+ *
+ */
+
+#include "audio_utils_aio.h"
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations audio_mp3_debug_fops = {
+	.read = audio_aio_debug_read,
+	.open = audio_aio_debug_open,
+};
+#endif
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct q6audio_aio *audio = file->private_data;
+	int rc = 0;
+	switch (cmd) {
+	case AUDIO_START: {
+		pr_debug("%s[%p]: AUDIO_START session_id[%d]\n", __func__,
+						audio, audio->ac->session);
+		if (audio->feedback == NON_TUNNEL_MODE) {
+			/* Configure PCM output block */
+			rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+					audio->pcm_cfg.sample_rate,
+					audio->pcm_cfg.channel_count);
+			if (rc < 0) {
+				pr_err("pcm output block config failed\n");
+				break;
+			}
+		}
+
+		rc = audio_aio_enable(audio);
+		audio->eos_rsp = 0;
+		audio->eos_flag = 0;
+		if (!rc) {
+			audio->enabled = 1;
+		} else {
+			audio->enabled = 0;
+			pr_err("Audio Start procedure failed rc=%d\n", rc);
+			break;
+		}
+		pr_info("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
+						audio->ac->session,
+						audio->enabled);
+		if (audio->stopped == 1)
+			audio->stopped = 0;
+		break;
+	}
+	default:
+		pr_debug("%s[%p]: Calling utils ioctl\n", __func__, audio);
+		rc = audio->codec_ioctl(file, cmd, arg);
+	}
+	return rc;
+}
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct q6audio_aio *audio = NULL;
+	int rc = 0;
+
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_mp3_" + 5];
+#endif
+	audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+	if (audio == NULL) {
+		pr_err("Could not allocate memory for mp3 decode driver\n");
+		return -ENOMEM;
+	}
+
+	audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+
+	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
+					     (void *)audio);
+
+	if (!audio->ac) {
+		pr_err("Could not allocate memory for audio client\n");
+		kfree(audio);
+		return -ENOMEM;
+	}
+
+	/* open in T/NT mode */
+	if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+		rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+					   FORMAT_MP3);
+		if (rc < 0) {
+			pr_err("NT mode Open failed rc=%d\n", rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->feedback = NON_TUNNEL_MODE;
+		/* open MP3 decoder, expected frames is always 1
+		audio->buf_cfg.frames_per_buf = 0x01;*/
+		audio->buf_cfg.meta_info_enable = 0x01;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+		rc = q6asm_open_write(audio->ac, FORMAT_MP3);
+		if (rc < 0) {
+			pr_err("T mode Open failed rc=%d\n", rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->feedback = TUNNEL_MODE;
+		audio->buf_cfg.meta_info_enable = 0x00;
+	} else {
+		pr_err("Not supported mode\n");
+		rc = -EACCES;
+		goto fail;
+	}
+	rc = audio_aio_open(audio, file);
+
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_mp3_%04x", audio->ac->session);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+					    NULL, (void *)audio,
+					    &audio_mp3_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		pr_debug("debugfs_create_file failed\n");
+#endif
+	pr_info("%s:mp3dec success mode[%d]session[%d]\n", __func__,
+						audio->feedback,
+						audio->ac->session);
+	return rc;
+fail:
+	q6asm_audio_client_free(audio->ac);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_mp3_fops = {
+	.owner = THIS_MODULE,
+	.open = audio_open,
+	.release = audio_aio_release,
+	.unlocked_ioctl = audio_ioctl,
+	.fsync = audio_aio_fsync,
+};
+
+struct miscdevice audio_mp3_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_mp3",
+	.fops = &audio_mp3_fops,
+};
+
+static int __init audio_mp3_init(void)
+{
+	return misc_register(&audio_mp3_misc);
+}
+
+device_initcall(audio_mp3_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
new file mode 100644
index 0000000..9253056
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
@@ -0,0 +1,304 @@
+/* aac audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2011-2012, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/msm_audio_aac.h>
+#include <mach/socinfo.h>
+#include "audio_utils_aio.h"
+
+#define AUDIO_AAC_DUAL_MONO_INVALID -1
+
+
+/* Default number of pre-allocated event packets */
+#define PCM_BUFSZ_MIN_AACM	((8*1024) + sizeof(struct dec_meta_out))
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations audio_aac_debug_fops = {
+	.read = audio_aio_debug_read,
+	.open = audio_aio_debug_open,
+};
+#endif
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct q6audio_aio *audio = file->private_data;
+	int rc = 0;
+
+	switch (cmd) {
+	case AUDIO_START: {
+		struct asm_aac_cfg aac_cfg;
+		struct msm_audio_aac_config *aac_config;
+		uint32_t sbr_ps = 0x00;
+		pr_debug("%s: AUDIO_START session_id[%d]\n", __func__,
+						audio->ac->session);
+		if (audio->feedback == NON_TUNNEL_MODE) {
+			/* Configure PCM output block */
+			rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+				0, /*native sampling rate*/
+				0 /*native channel count*/);
+			if (rc < 0) {
+				pr_err("pcm output block config failed\n");
+				break;
+			}
+		}
+		/* turn on both sbr and ps */
+		rc = q6asm_enable_sbrps(audio->ac, sbr_ps);
+		if (rc < 0)
+			pr_err("sbr-ps enable failed\n");
+		aac_config = (struct msm_audio_aac_config *)audio->codec_cfg;
+		if (aac_config->sbr_ps_on_flag)
+			aac_cfg.aot = AAC_ENC_MODE_EAAC_P;
+		else if (aac_config->sbr_on_flag)
+			aac_cfg.aot = AAC_ENC_MODE_AAC_P;
+		else
+			aac_cfg.aot = AAC_ENC_MODE_AAC_LC;
+
+		switch (aac_config->format) {
+		case AUDIO_AAC_FORMAT_ADTS:
+			aac_cfg.format = 0x00;
+			break;
+		case AUDIO_AAC_FORMAT_LOAS:
+			aac_cfg.format = 0x01;
+			break;
+		case AUDIO_AAC_FORMAT_ADIF:
+			aac_cfg.format = 0x02;
+			break;
+		default:
+		case AUDIO_AAC_FORMAT_RAW:
+			aac_cfg.format = 0x03;
+		}
+		aac_cfg.ep_config = aac_config->ep_config;
+		aac_cfg.section_data_resilience =
+			aac_config->aac_section_data_resilience_flag;
+		aac_cfg.scalefactor_data_resilience =
+			aac_config->aac_scalefactor_data_resilience_flag;
+		aac_cfg.spectral_data_resilience =
+			aac_config->aac_spectral_data_resilience_flag;
+		aac_cfg.ch_cfg = aac_config->channel_configuration;
+		aac_cfg.sample_rate =  audio->pcm_cfg.sample_rate;
+
+		pr_debug("%s:format=%x aot=%d  ch=%d sr=%d\n",
+			__func__, aac_cfg.format,
+			aac_cfg.aot, aac_cfg.ch_cfg,
+			aac_cfg.sample_rate);
+
+		/* Configure Media format block */
+		rc = q6asm_media_format_block_multi_aac(audio->ac, &aac_cfg);
+		if (rc < 0) {
+			pr_err("cmd media format block failed\n");
+			break;
+		}
+		if (!cpu_is_msm8x60()) {
+			rc = q6asm_set_encdec_chan_map(audio->ac, 2);
+			if (rc < 0) {
+				pr_err("%s: cmd set encdec_chan_map failed\n",
+					__func__);
+				break;
+			}
+		}
+		rc = audio_aio_enable(audio);
+		audio->eos_rsp = 0;
+		audio->eos_flag = 0;
+		if (!rc) {
+			audio->enabled = 1;
+		} else {
+			audio->enabled = 0;
+			pr_err("Audio Start procedure failed rc=%d\n", rc);
+			break;
+		}
+		pr_info("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
+						audio->ac->session,
+						audio->enabled);
+		if (audio->stopped == 1)
+			audio->stopped = 0;
+		break;
+	}
+	case AUDIO_GET_AAC_CONFIG: {
+		if (copy_to_user((void *)arg, audio->codec_cfg,
+			sizeof(struct msm_audio_aac_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		break;
+	}
+	case AUDIO_SET_AAC_CONFIG: {
+		struct msm_audio_aac_config *aac_config;
+		if (copy_from_user(audio->codec_cfg, (void *)arg,
+			sizeof(struct msm_audio_aac_config))) {
+			rc = -EFAULT;
+		} else {
+			uint16_t sce_left = 1, sce_right = 2;
+			aac_config = audio->codec_cfg;
+			if ((aac_config->dual_mono_mode <
+				AUDIO_AAC_DUAL_MONO_PL_PR) ||
+				(aac_config->dual_mono_mode >
+				AUDIO_AAC_DUAL_MONO_PL_SR)) {
+				pr_err("%s:AUDIO_SET_AAC_CONFIG: Invalid"
+					"dual_mono mode =%d\n", __func__,
+					aac_config->dual_mono_mode);
+			} else {
+				/* convert the data from user into sce_left
+				 * and sce_right based on the definitions
+				 */
+				pr_debug("%s: AUDIO_SET_AAC_CONFIG: modify"
+					 "dual_mono mode =%d\n", __func__,
+					 aac_config->dual_mono_mode);
+				switch (aac_config->dual_mono_mode) {
+				case AUDIO_AAC_DUAL_MONO_PL_PR:
+					sce_left = 1;
+					sce_right = 1;
+					break;
+				case AUDIO_AAC_DUAL_MONO_SL_SR:
+					sce_left = 2;
+					sce_right = 2;
+					break;
+				case AUDIO_AAC_DUAL_MONO_SL_PR:
+					sce_left = 2;
+					sce_right = 1;
+					break;
+				case AUDIO_AAC_DUAL_MONO_PL_SR:
+				default:
+					sce_left = 1;
+					sce_right = 2;
+					break;
+				}
+				rc = q6asm_cfg_dual_mono_aac(audio->ac,
+							sce_left, sce_right);
+				if (rc < 0)
+					pr_err("%s: asm cmd dualmono failed"
+						" rc=%d\n", __func__, rc);
+			}			break;
+		}
+		break;
+	}
+	default:
+		pr_debug("Calling utils ioctl\n");
+		rc = audio->codec_ioctl(file, cmd, arg);
+	}
+	return rc;
+}
+
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct q6audio_aio *audio = NULL;
+	int rc = 0;
+	struct msm_audio_aac_config *aac_config = NULL;
+
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_multi_aac_" + 5];
+#endif
+	audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+	if (audio == NULL) {
+		pr_err("Could not allocate memory for aac decode driver\n");
+		return -ENOMEM;
+	}
+
+	audio->codec_cfg = kzalloc(sizeof(struct msm_audio_aac_config),
+					GFP_KERNEL);
+	if (audio->codec_cfg == NULL) {
+		pr_err("%s: Could not allocate memory for aac"
+			"config\n", __func__);
+		kfree(audio);
+		return -ENOMEM;
+	}
+
+	aac_config = audio->codec_cfg;
+
+	audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN_AACM;
+	aac_config->dual_mono_mode = AUDIO_AAC_DUAL_MONO_INVALID;
+
+	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
+					     (void *)audio);
+
+	if (!audio->ac) {
+		pr_err("Could not allocate memory for audio client\n");
+		kfree(audio->codec_cfg);
+		kfree(audio);
+		return -ENOMEM;
+	}
+
+	/* open in T/NT mode */
+	if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+		rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+					   FORMAT_MPEG4_MULTI_AAC);
+		if (rc < 0) {
+			pr_err("NT mode Open failed rc=%d\n", rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->feedback = NON_TUNNEL_MODE;
+		/* open AAC decoder, expected frames is always 1
+		audio->buf_cfg.frames_per_buf = 0x01;*/
+		audio->buf_cfg.meta_info_enable = 0x01;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+		rc = q6asm_open_write(audio->ac, FORMAT_MPEG4_MULTI_AAC);
+		if (rc < 0) {
+			pr_err("T mode Open failed rc=%d\n", rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->feedback = TUNNEL_MODE;
+		audio->buf_cfg.meta_info_enable = 0x00;
+	} else {
+		pr_err("Not supported mode\n");
+		rc = -EACCES;
+		goto fail;
+	}
+	rc = audio_aio_open(audio, file);
+
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_multi_aac_%04x", audio->ac->session);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+					    NULL, (void *)audio,
+					    &audio_aac_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		pr_debug("debugfs_create_file failed\n");
+#endif
+	pr_info("%s:AAC 5.1 Decoder OPEN success mode[%d]session[%d]\n",
+		__func__, audio->feedback, audio->ac->session);
+	return rc;
+fail:
+	q6asm_audio_client_free(audio->ac);
+	kfree(audio->codec_cfg);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_aac_fops = {
+	.owner = THIS_MODULE,
+	.open = audio_open,
+	.release = audio_aio_release,
+	.unlocked_ioctl = audio_ioctl,
+	.fsync = audio_aio_fsync,
+};
+
+struct miscdevice audio_multiaac_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_multi_aac",
+	.fops = &audio_aac_fops,
+};
+
+static int __init audio_aac_init(void)
+{
+	return misc_register(&audio_multiaac_misc);
+}
+
+device_initcall(audio_aac_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_mvs.c b/arch/arm/mach-msm/qdsp6v2/audio_mvs.c
new file mode 100644
index 0000000..6e7961c
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_mvs.c
@@ -0,0 +1,1167 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/list.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+#include <linux/wakelock.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/msm_audio_mvs.h>
+#include <mach/qdsp6v2/q6voice.h>
+
+/* Each buffer is 20 ms, queue holds 200 ms of data. */
+#define MVS_MAX_Q_LEN 10
+
+/* Length of the DSP frame info header added to the voc packet. */
+#define DSP_FRAME_HDR_LEN 1
+
+enum audio_mvs_state_type {
+	AUDIO_MVS_CLOSED,
+	AUDIO_MVS_STARTED,
+	AUDIO_MVS_STOPPED
+};
+
+struct audio_mvs_buf_node {
+	struct list_head list;
+	struct q6_msm_audio_mvs_frame frame;
+};
+
+struct audio_mvs_info_type {
+	enum audio_mvs_state_type state;
+
+	uint32_t mvs_mode;
+	uint32_t rate_type;
+	uint32_t dtx_mode;
+	struct q_min_max_rate min_max_rate;
+
+	struct list_head in_queue;
+	struct list_head free_in_queue;
+
+	struct list_head out_queue;
+	struct list_head free_out_queue;
+
+	wait_queue_head_t in_wait;
+	wait_queue_head_t out_wait;
+
+	struct mutex lock;
+	struct mutex in_lock;
+	struct mutex out_lock;
+
+	spinlock_t dsp_lock;
+
+	struct wake_lock suspend_lock;
+	struct wake_lock idle_lock;
+
+	void *memory_chunk;
+};
+
+static struct audio_mvs_info_type audio_mvs_info;
+
+static uint32_t audio_mvs_get_rate(uint32_t mvs_mode, uint32_t rate_type)
+{
+	uint32_t cvs_rate;
+
+	if (mvs_mode == MVS_MODE_AMR_WB)
+		cvs_rate = rate_type - MVS_AMR_MODE_0660;
+	else
+		cvs_rate = rate_type;
+
+	pr_debug("%s: CVS rate is %d for MVS mode %d\n",
+		 __func__, cvs_rate, mvs_mode);
+
+	return cvs_rate;
+}
+
+static void audio_mvs_process_ul_pkt(uint8_t *voc_pkt,
+				     uint32_t pkt_len,
+				     void *private_data)
+{
+	struct audio_mvs_buf_node *buf_node = NULL;
+	struct audio_mvs_info_type *audio = private_data;
+	unsigned long dsp_flags;
+
+	/* Copy up-link packet into out_queue. */
+	spin_lock_irqsave(&audio->dsp_lock, dsp_flags);
+
+	if (!list_empty(&audio->free_out_queue)) {
+		buf_node = list_first_entry(&audio->free_out_queue,
+					    struct audio_mvs_buf_node,
+					    list);
+		list_del(&buf_node->list);
+
+		switch (audio->mvs_mode) {
+		case MVS_MODE_AMR:
+		case MVS_MODE_AMR_WB: {
+			/* Remove the DSP frame info header. Header format:
+			 * Bits 0-3: Frame rate
+			 * Bits 4-7: Frame type
+			 */
+			buf_node->frame.header.frame_type =
+						((*voc_pkt) & 0xF0) >> 4;
+			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+			buf_node->frame.len = pkt_len - DSP_FRAME_HDR_LEN;
+
+			memcpy(&buf_node->frame.voc_pkt[0],
+			       voc_pkt,
+			       buf_node->frame.len);
+
+			list_add_tail(&buf_node->list, &audio->out_queue);
+			break;
+		}
+
+		case MVS_MODE_IS127: {
+			buf_node->frame.header.packet_rate = (*voc_pkt) & 0x0F;
+			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+			buf_node->frame.len = pkt_len - DSP_FRAME_HDR_LEN;
+
+			memcpy(&buf_node->frame.voc_pkt[0],
+			       voc_pkt,
+			       buf_node->frame.len);
+
+			list_add_tail(&buf_node->list, &audio->out_queue);
+			break;
+		}
+
+		case MVS_MODE_G729A: {
+			/* G729 frames are 10ms each, but the DSP works with
+			 * 20ms frames and sends two 10ms frames per buffer.
+			 * Extract the two frames and put them in separate
+			 * buffers.
+			 */
+			/* Remove the first DSP frame info header.
+			 * Header format:
+			 * Bits 0-1: Frame type
+			 */
+			buf_node->frame.header.frame_type = (*voc_pkt) & 0x03;
+			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+			/* There are two frames in the buffer. Length of the
+			 * first frame:
+			 */
+			buf_node->frame.len = (pkt_len -
+					       2 * DSP_FRAME_HDR_LEN) / 2;
+
+			memcpy(&buf_node->frame.voc_pkt[0],
+			       voc_pkt,
+			       buf_node->frame.len);
+			voc_pkt = voc_pkt + buf_node->frame.len;
+
+			list_add_tail(&buf_node->list, &audio->out_queue);
+
+			/* Get another buffer from the free Q and fill in the
+			 * second frame.
+			 */
+			if (!list_empty(&audio->free_out_queue)) {
+				buf_node =
+					list_first_entry(&audio->free_out_queue,
+						      struct audio_mvs_buf_node,
+						      list);
+				list_del(&buf_node->list);
+
+				/* Remove the second DSP frame info header.
+				 * Header format:
+				 * Bits 0-1: Frame type
+				 */
+				buf_node->frame.header.frame_type =
+							(*voc_pkt) & 0x03;
+				voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+				/* There are two frames in the buffer. Length
+				 * of the first frame:
+				 */
+				buf_node->frame.len = (pkt_len -
+						     2 * DSP_FRAME_HDR_LEN) / 2;
+
+				memcpy(&buf_node->frame.voc_pkt[0],
+				       voc_pkt,
+				       buf_node->frame.len);
+
+				list_add_tail(&buf_node->list,
+					      &audio->out_queue);
+
+			} else {
+				/* Drop the second frame. */
+				pr_err("%s: UL data dropped, read is slow\n",
+				       __func__);
+			}
+
+			break;
+		}
+
+		case MVS_MODE_G711:
+		case MVS_MODE_G711A: {
+			/* G711 frames are 10ms each, but the DSP works with
+			 * 20ms frames and sends two 10ms frames per buffer.
+			 * Extract the two frames and put them in separate
+			 * buffers.
+			 */
+			/* Remove the first DSP frame info header.
+			 * Header format: G711A
+			 * Bits 0-1: Frame type
+			 * Bits 2-3: Frame rate
+			 *
+			 * Header format: G711
+			 * Bits 2-3: Frame rate
+			 */
+			if (audio->mvs_mode == MVS_MODE_G711A)
+				buf_node->frame.header.frame_type =
+							(*voc_pkt) & 0x03;
+			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+			/* There are two frames in the buffer. Length of the
+			 * first frame:
+			 */
+			buf_node->frame.len = (pkt_len -
+					       2 * DSP_FRAME_HDR_LEN) / 2;
+
+			memcpy(&buf_node->frame.voc_pkt[0],
+			       voc_pkt,
+			       buf_node->frame.len);
+			voc_pkt = voc_pkt + buf_node->frame.len;
+
+			list_add_tail(&buf_node->list, &audio->out_queue);
+
+			/* Get another buffer from the free Q and fill in the
+			 * second frame.
+			 */
+			if (!list_empty(&audio->free_out_queue)) {
+				buf_node =
+					list_first_entry(&audio->free_out_queue,
+						      struct audio_mvs_buf_node,
+						      list);
+				list_del(&buf_node->list);
+
+				/* Remove the second DSP frame info header.
+				 * Header format:
+				 * Bits 0-1: Frame type
+				 * Bits 2-3: Frame rate
+				 */
+				if (audio->mvs_mode == MVS_MODE_G711A)
+					buf_node->frame.header.frame_type =
+							(*voc_pkt) & 0x03;
+				voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+				/* There are two frames in the buffer. Length
+				 * of the second frame:
+				 */
+				buf_node->frame.len = (pkt_len -
+						     2 * DSP_FRAME_HDR_LEN) / 2;
+
+				memcpy(&buf_node->frame.voc_pkt[0],
+				       voc_pkt,
+				       buf_node->frame.len);
+
+				list_add_tail(&buf_node->list,
+					      &audio->out_queue);
+			} else {
+				/* Drop the second frame. */
+				pr_err("%s: UL data dropped, read is slow\n",
+				       __func__);
+			}
+			break;
+		}
+
+		case MVS_MODE_IS733:
+		case MVS_MODE_4GV_NB:
+		case MVS_MODE_4GV_WB: {
+			/* Remove the DSP frame info header.
+			 * Header format:
+			 * Bits 0-3: frame rate
+			 */
+			buf_node->frame.header.packet_rate = (*voc_pkt) & 0x0F;
+			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+			buf_node->frame.len = pkt_len - DSP_FRAME_HDR_LEN;
+
+			memcpy(&buf_node->frame.voc_pkt[0],
+				voc_pkt,
+				buf_node->frame.len);
+
+			list_add_tail(&buf_node->list, &audio->out_queue);
+			break;
+		}
+
+		case MVS_MODE_EFR:
+		case MVS_MODE_FR:
+		case MVS_MODE_HR: {
+			/*
+			 * Remove the DSP frame info header
+			 * Header Format
+			 * Bit 0: bfi unused for uplink
+			 * Bit 1-2: sid applies to both uplink and downlink
+			 * Bit 3: taf unused for uplink
+			 * MVS_MODE_HR
+			 * Bit 4: ufi unused for uplink
+			 */
+			buf_node->frame.header.gsm_frame_type.sid =
+						((*voc_pkt) & 0x06) >> 1;
+			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+			buf_node->frame.len = pkt_len - DSP_FRAME_HDR_LEN;
+
+			memcpy(&buf_node->frame.voc_pkt[0],
+			voc_pkt,
+			buf_node->frame.len);
+
+			list_add_tail(&buf_node->list, &audio->out_queue);
+			break;
+		}
+
+		default: {
+			buf_node->frame.header.frame_type = 0;
+
+			buf_node->frame.len = pkt_len;
+
+			memcpy(&buf_node->frame.voc_pkt[0],
+			       voc_pkt,
+			       buf_node->frame.len);
+
+			list_add_tail(&buf_node->list, &audio->out_queue);
+		}
+		}
+	} else {
+		pr_err("%s: UL data dropped, read is slow\n", __func__);
+	}
+
+	spin_unlock_irqrestore(&audio->dsp_lock, dsp_flags);
+
+	wake_up(&audio->out_wait);
+}
+
+static void audio_mvs_process_dl_pkt(uint8_t *voc_pkt,
+				     uint32_t *pkt_len,
+				     void *private_data)
+{
+	struct audio_mvs_buf_node *buf_node = NULL;
+	struct audio_mvs_info_type *audio = private_data;
+	unsigned long dsp_flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, dsp_flags);
+
+	if (!list_empty(&audio->in_queue)) {
+		uint32_t rate_type = audio_mvs_get_rate(audio->mvs_mode,
+							audio->rate_type);
+
+		buf_node = list_first_entry(&audio->in_queue,
+					    struct audio_mvs_buf_node,
+					    list);
+		list_del(&buf_node->list);
+
+		switch (audio->mvs_mode) {
+		case MVS_MODE_AMR:
+		case MVS_MODE_AMR_WB: {
+			/* Add the DSP frame info header. Header format:
+			 * Bits 0-3: Frame rate
+			 * Bits 4-7: Frame type
+			 */
+			*voc_pkt =
+			    ((buf_node->frame.header.frame_type & 0x0F) << 4) |
+			    (rate_type & 0x0F);
+			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+			*pkt_len = buf_node->frame.len + DSP_FRAME_HDR_LEN;
+
+			memcpy(voc_pkt,
+			       &buf_node->frame.voc_pkt[0],
+			       buf_node->frame.len);
+
+			list_add_tail(&buf_node->list, &audio->free_in_queue);
+			break;
+		}
+
+		case MVS_MODE_IS127: {
+			/* Add the DSP frame info header. Header format:
+			 * Bits 0-3: Frame rate
+			 */
+			*voc_pkt = buf_node->frame.header.packet_rate & 0x0F;
+			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+			*pkt_len = buf_node->frame.len + DSP_FRAME_HDR_LEN;
+
+			memcpy(voc_pkt,
+			       &buf_node->frame.voc_pkt[0],
+			       buf_node->frame.len);
+
+			list_add_tail(&buf_node->list, &audio->free_in_queue);
+			break;
+		}
+
+		case MVS_MODE_G729A: {
+			/* G729 frames are 10ms each but the DSP expects 20ms
+			 * worth of data, so send two 10ms frames per buffer.
+			 */
+			/* Add the first DSP frame info header. Header format:
+			 * Bits 0-1: Frame type
+			 */
+			*voc_pkt = buf_node->frame.header.frame_type & 0x03;
+			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+			*pkt_len = buf_node->frame.len + DSP_FRAME_HDR_LEN;
+
+			memcpy(voc_pkt,
+			       &buf_node->frame.voc_pkt[0],
+			       buf_node->frame.len);
+			voc_pkt = voc_pkt + buf_node->frame.len;
+
+			list_add_tail(&buf_node->list, &audio->free_in_queue);
+
+			if (!list_empty(&audio->in_queue)) {
+				/* Get the second buffer. */
+				buf_node = list_first_entry(&audio->in_queue,
+						      struct audio_mvs_buf_node,
+						      list);
+				list_del(&buf_node->list);
+
+				/* Add the second DSP frame info header.
+				 * Header format:
+				 * Bits 0-1: Frame type
+				 */
+				*voc_pkt = buf_node->frame.header.frame_type
+						& 0x03;
+				voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+				*pkt_len = *pkt_len +
+					buf_node->frame.len + DSP_FRAME_HDR_LEN;
+
+				memcpy(voc_pkt,
+				       &buf_node->frame.voc_pkt[0],
+				       buf_node->frame.len);
+
+				list_add_tail(&buf_node->list,
+					      &audio->free_in_queue);
+			} else {
+				/* Only 10ms worth of data is available, signal
+				 * erasure frame.
+				 */
+				*voc_pkt = MVS_G729A_ERASURE & 0x03;
+
+				*pkt_len = *pkt_len + DSP_FRAME_HDR_LEN;
+			}
+
+			break;
+		}
+
+		case MVS_MODE_G711:
+		case MVS_MODE_G711A: {
+			/* G711 frames are 10ms each but the DSP expects 20ms
+			 * worth of data, so send two 10ms frames per buffer.
+			 */
+			/* Add the first DSP frame info header. Header format:
+			 * Bits 0-1: Frame type
+			 * Bits 2-3: Frame rate
+			 */
+			*voc_pkt = ((rate_type & 0x0F) << 2) |
+				   (buf_node->frame.header.frame_type & 0x03);
+			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+			*pkt_len = buf_node->frame.len + DSP_FRAME_HDR_LEN;
+
+			memcpy(voc_pkt,
+			       &buf_node->frame.voc_pkt[0],
+			       buf_node->frame.len);
+			voc_pkt = voc_pkt + buf_node->frame.len;
+
+			list_add_tail(&buf_node->list, &audio->free_in_queue);
+
+			if (!list_empty(&audio->in_queue)) {
+				/* Get the second buffer. */
+				buf_node = list_first_entry(&audio->in_queue,
+						      struct audio_mvs_buf_node,
+						      list);
+				list_del(&buf_node->list);
+
+				/* Add the second DSP frame info header.
+				 * Header format:
+				 * Bits 0-1: Frame type
+				 * Bits 2-3: Frame rate
+				 */
+				*voc_pkt = ((rate_type & 0x0F) << 2) |
+				     (buf_node->frame.header.frame_type & 0x03);
+				voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+				*pkt_len = *pkt_len +
+					buf_node->frame.len + DSP_FRAME_HDR_LEN;
+
+				memcpy(voc_pkt,
+				       &buf_node->frame.voc_pkt[0],
+				       buf_node->frame.len);
+
+				list_add_tail(&buf_node->list,
+					      &audio->free_in_queue);
+			} else {
+				/* Only 10ms worth of data is available, signal
+				 * erasure frame.
+				 */
+				*voc_pkt = ((rate_type & 0x0F) << 2) |
+					   (MVS_G711A_ERASURE & 0x03);
+
+				*pkt_len = *pkt_len + DSP_FRAME_HDR_LEN;
+			}
+			break;
+		}
+
+		case MVS_MODE_IS733:
+		case MVS_MODE_4GV_NB:
+		case MVS_MODE_4GV_WB: {
+			/* Add the DSP frame info header. Header format:
+			 * Bits 0-3 : Frame rate
+			*/
+			*voc_pkt = buf_node->frame.header.packet_rate & 0x0F;
+			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+			*pkt_len = buf_node->frame.len + DSP_FRAME_HDR_LEN;
+
+			memcpy(voc_pkt,
+				&buf_node->frame.voc_pkt[0],
+				buf_node->frame.len);
+
+			list_add_tail(&buf_node->list, &audio->free_in_queue);
+			break;
+		}
+
+		case MVS_MODE_EFR:
+		case MVS_MODE_FR:
+		case MVS_MODE_HR: {
+			/*
+			 * Remove the DSP frame info header
+			 * Header Format
+			 * Bit 0: bfi applies only for downlink
+			 * Bit 1-2: sid applies for downlink and uplink
+			 * Bit 3: taf applies only for downlink
+			 * MVS_MODE_HR
+			 * Bit 4: ufi applies only for downlink
+			 */
+			*voc_pkt =
+				((buf_node->frame.header.gsm_frame_type.bfi
+					& 0x01) |
+				((buf_node->frame.header.gsm_frame_type.sid
+					& 0x03) << 1) |
+				((buf_node->frame.header.gsm_frame_type.taf
+					& 0x01) << 3));
+
+			if (audio->mvs_mode == MVS_MODE_HR) {
+				*voc_pkt = (*voc_pkt |
+				((buf_node->frame.header.gsm_frame_type.ufi
+				& 0x01) << 4) |
+				((0 & 0x07) << 5));
+			} else {
+				*voc_pkt = (*voc_pkt |
+				((0 & 0x0F) << 4));
+			}
+
+			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+			*pkt_len = buf_node->frame.len + DSP_FRAME_HDR_LEN;
+
+			memcpy(voc_pkt,
+				&buf_node->frame.voc_pkt[0],
+				buf_node->frame.len);
+
+			list_add_tail(&buf_node->list, &audio->free_in_queue);
+
+			break;
+		}
+
+		default: {
+			*pkt_len = buf_node->frame.len;
+
+			memcpy(voc_pkt,
+			       &buf_node->frame.voc_pkt[0],
+			       buf_node->frame.len);
+
+			list_add_tail(&buf_node->list, &audio->free_in_queue);
+		}
+		}
+	} else {
+		*pkt_len = 0;
+
+		pr_info("%s: No DL data available to send to MVS\n", __func__);
+	}
+
+	spin_unlock_irqrestore(&audio->dsp_lock, dsp_flags);
+	wake_up(&audio->in_wait);
+}
+
+static uint32_t audio_mvs_get_media_type(uint32_t mvs_mode, uint32_t rate_type)
+{
+	uint32_t media_type;
+
+	switch (mvs_mode) {
+	case MVS_MODE_IS733:
+		media_type = VSS_MEDIA_ID_13K_MODEM;
+		break;
+
+	case MVS_MODE_IS127:
+		media_type = VSS_MEDIA_ID_EVRC_MODEM;
+		break;
+
+	case MVS_MODE_4GV_NB:
+		media_type = VSS_MEDIA_ID_4GV_NB_MODEM;
+		break;
+
+	case MVS_MODE_4GV_WB:
+		media_type = VSS_MEDIA_ID_4GV_WB_MODEM;
+		break;
+
+	case MVS_MODE_AMR:
+		media_type = VSS_MEDIA_ID_AMR_NB_MODEM;
+		break;
+
+	case MVS_MODE_EFR:
+		media_type = VSS_MEDIA_ID_EFR_MODEM;
+		break;
+
+	case MVS_MODE_FR:
+		media_type = VSS_MEDIA_ID_FR_MODEM;
+		break;
+
+	case MVS_MODE_HR:
+		media_type = VSS_MEDIA_ID_HR_MODEM;
+		break;
+
+	case MVS_MODE_LINEAR_PCM:
+		media_type = VSS_MEDIA_ID_PCM_NB;
+		break;
+
+	case MVS_MODE_PCM:
+		media_type = VSS_MEDIA_ID_PCM_NB;
+		break;
+
+	case MVS_MODE_AMR_WB:
+		media_type = VSS_MEDIA_ID_AMR_WB_MODEM;
+		break;
+
+	case MVS_MODE_G729A:
+		media_type = VSS_MEDIA_ID_G729;
+		break;
+
+	case MVS_MODE_G711:
+	case MVS_MODE_G711A:
+		if (rate_type == MVS_G711A_MODE_MULAW)
+			media_type = VSS_MEDIA_ID_G711_MULAW;
+		else
+			media_type = VSS_MEDIA_ID_G711_ALAW;
+		break;
+
+	case MVS_MODE_PCM_WB:
+		media_type = VSS_MEDIA_ID_PCM_WB;
+		break;
+
+	default:
+		media_type = VSS_MEDIA_ID_PCM_NB;
+	}
+
+	pr_debug("%s: media_type is 0x%x\n", __func__, media_type);
+
+	return media_type;
+}
+
+static uint32_t audio_mvs_get_network_type(uint32_t mvs_mode)
+{
+	uint32_t network_type;
+
+	switch (mvs_mode) {
+	case MVS_MODE_IS733:
+	case MVS_MODE_IS127:
+	case MVS_MODE_4GV_NB:
+	case MVS_MODE_AMR:
+	case MVS_MODE_EFR:
+	case MVS_MODE_FR:
+	case MVS_MODE_HR:
+	case MVS_MODE_LINEAR_PCM:
+	case MVS_MODE_G711:
+	case MVS_MODE_PCM:
+	case MVS_MODE_G729A:
+	case MVS_MODE_G711A:
+		network_type = VSS_NETWORK_ID_VOIP_NB;
+		break;
+
+	case MVS_MODE_4GV_WB:
+	case MVS_MODE_AMR_WB:
+	case MVS_MODE_PCM_WB:
+		network_type = VSS_NETWORK_ID_VOIP_WB;
+		break;
+
+	default:
+		network_type = VSS_NETWORK_ID_DEFAULT;
+	}
+
+	pr_debug("%s: network_type is 0x%x\n", __func__, network_type);
+
+	return network_type;
+}
+
+static int audio_mvs_start(struct audio_mvs_info_type *audio)
+{
+	int rc = 0;
+
+	pr_info("%s\n", __func__);
+
+	/* Prevent sleep. */
+	wake_lock(&audio->suspend_lock);
+	wake_lock(&audio->idle_lock);
+
+	rc = voice_set_voc_path_full(1);
+
+	if (rc == 0) {
+		voice_register_mvs_cb(audio_mvs_process_ul_pkt,
+				      audio_mvs_process_dl_pkt,
+				      audio);
+
+		voice_config_vocoder(
+		    audio_mvs_get_media_type(audio->mvs_mode, audio->rate_type),
+		    audio_mvs_get_rate(audio->mvs_mode, audio->rate_type),
+		    audio_mvs_get_network_type(audio->mvs_mode),
+		    audio->dtx_mode,
+		    audio->min_max_rate);
+
+		audio->state = AUDIO_MVS_STARTED;
+	} else {
+		pr_err("%s: Error %d setting voc path to full\n", __func__, rc);
+	}
+
+	return rc;
+}
+
+static int audio_mvs_stop(struct audio_mvs_info_type *audio)
+{
+	int rc = 0;
+
+	pr_info("%s\n", __func__);
+
+	voice_set_voc_path_full(0);
+
+	audio->state = AUDIO_MVS_STOPPED;
+
+	/* Allow sleep. */
+	wake_unlock(&audio->suspend_lock);
+	wake_unlock(&audio->idle_lock);
+
+	return rc;
+}
+
+static int audio_mvs_open(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	int i;
+	int offset = 0;
+	struct audio_mvs_buf_node *buf_node = NULL;
+
+	pr_info("%s\n", __func__);
+
+	mutex_lock(&audio_mvs_info.lock);
+
+	/* Allocate input and output buffers. */
+	audio_mvs_info.memory_chunk = kmalloc(2 * MVS_MAX_Q_LEN *
+					      sizeof(struct audio_mvs_buf_node),
+					      GFP_KERNEL);
+
+	if (audio_mvs_info.memory_chunk != NULL) {
+		for (i = 0; i < MVS_MAX_Q_LEN; i++) {
+			buf_node = audio_mvs_info.memory_chunk + offset;
+
+			list_add_tail(&buf_node->list,
+				      &audio_mvs_info.free_in_queue);
+
+			offset = offset + sizeof(struct audio_mvs_buf_node);
+		}
+
+		for (i = 0; i < MVS_MAX_Q_LEN; i++) {
+			buf_node = audio_mvs_info.memory_chunk + offset;
+
+			list_add_tail(&buf_node->list,
+				      &audio_mvs_info.free_out_queue);
+
+			offset = offset + sizeof(struct audio_mvs_buf_node);
+		}
+
+		audio_mvs_info.state = AUDIO_MVS_STOPPED;
+
+		file->private_data = &audio_mvs_info;
+
+	}  else {
+		pr_err("%s: No memory for IO buffers\n", __func__);
+
+		rc = -ENOMEM;
+	}
+
+	mutex_unlock(&audio_mvs_info.lock);
+
+	return rc;
+}
+
+static int audio_mvs_release(struct inode *inode, struct file *file)
+{
+	struct list_head *ptr = NULL;
+	struct list_head *next = NULL;
+	struct audio_mvs_buf_node *buf_node = NULL;
+	struct audio_mvs_info_type *audio = file->private_data;
+
+	pr_info("%s\n", __func__);
+
+	mutex_lock(&audio->lock);
+
+	if (audio->state == AUDIO_MVS_STARTED)
+		audio_mvs_stop(audio);
+
+	/* Free input and output memory. */
+	mutex_lock(&audio->in_lock);
+
+	list_for_each_safe(ptr, next, &audio->in_queue) {
+		buf_node = list_entry(ptr, struct audio_mvs_buf_node, list);
+		list_del(&buf_node->list);
+	}
+
+	list_for_each_safe(ptr, next, &audio->free_in_queue) {
+		buf_node = list_entry(ptr, struct audio_mvs_buf_node, list);
+		list_del(&buf_node->list);
+	}
+
+	mutex_unlock(&audio->in_lock);
+
+
+	mutex_lock(&audio->out_lock);
+
+	list_for_each_safe(ptr, next, &audio->out_queue) {
+		buf_node = list_entry(ptr, struct audio_mvs_buf_node, list);
+		list_del(&buf_node->list);
+	}
+
+	list_for_each_safe(ptr, next, &audio->free_out_queue) {
+		buf_node = list_entry(ptr, struct audio_mvs_buf_node, list);
+		list_del(&buf_node->list);
+	}
+
+	mutex_unlock(&audio->out_lock);
+
+	kfree(audio->memory_chunk);
+	audio->memory_chunk = NULL;
+
+	audio->state = AUDIO_MVS_CLOSED;
+
+	mutex_unlock(&audio->lock);
+
+	return 0;
+}
+
+static ssize_t audio_mvs_read(struct file *file,
+			      char __user *buf,
+			      size_t count,
+			      loff_t *pos)
+{
+	int rc = 0;
+	struct audio_mvs_buf_node *buf_node = NULL;
+	struct audio_mvs_info_type *audio = file->private_data;
+
+	pr_debug("%s:\n", __func__);
+
+	rc = wait_event_interruptible_timeout(audio->out_wait,
+					     (!list_empty(&audio->out_queue) ||
+					     audio->state == AUDIO_MVS_STOPPED),
+					     1 * HZ);
+
+	if (rc > 0) {
+		mutex_lock(&audio->out_lock);
+
+		if ((audio->state == AUDIO_MVS_STARTED) &&
+		    (!list_empty(&audio->out_queue))) {
+
+			if (count >= sizeof(struct q6_msm_audio_mvs_frame)) {
+				buf_node = list_first_entry(&audio->out_queue,
+						struct audio_mvs_buf_node,
+						list);
+				list_del(&buf_node->list);
+
+				rc = copy_to_user(buf,
+					&buf_node->frame,
+					sizeof(struct q6_msm_audio_mvs_frame));
+
+				if (rc == 0) {
+					rc = buf_node->frame.len +
+					    sizeof(buf_node->frame.header) +
+					    sizeof(buf_node->frame.len);
+				} else {
+					pr_err("%s: Copy to user retuned %d",
+					       __func__, rc);
+
+					rc = -EFAULT;
+				}
+
+				list_add_tail(&buf_node->list,
+					      &audio->free_out_queue);
+			} else {
+				pr_err("%s: Read count %d < sizeof(frame) %d",
+				       __func__, count,
+				       sizeof(struct q6_msm_audio_mvs_frame));
+
+				rc = -ENOMEM;
+			}
+		} else {
+			pr_err("%s: Read performed in state %d\n",
+			       __func__, audio->state);
+
+			rc = -EPERM;
+		}
+
+		mutex_unlock(&audio->out_lock);
+
+	} else if (rc == 0) {
+		pr_err("%s: No UL data available\n", __func__);
+
+		rc = -ETIMEDOUT;
+	} else {
+		pr_err("%s: Read was interrupted\n", __func__);
+
+		rc = -ERESTARTSYS;
+	}
+
+	return rc;
+}
+
+static ssize_t audio_mvs_write(struct file *file,
+			       const char __user *buf,
+			       size_t count,
+			       loff_t *pos)
+{
+	int rc = 0;
+	struct audio_mvs_buf_node *buf_node = NULL;
+	struct audio_mvs_info_type *audio = file->private_data;
+
+	pr_debug("%s:\n", __func__);
+
+	rc = wait_event_interruptible_timeout(audio->in_wait,
+		(!list_empty(&audio->free_in_queue) ||
+		audio->state == AUDIO_MVS_STOPPED), 1 * HZ);
+	if (rc > 0) {
+		mutex_lock(&audio->in_lock);
+
+		if (audio->state == AUDIO_MVS_STARTED) {
+			if (count <= sizeof(struct q6_msm_audio_mvs_frame)) {
+				if (!list_empty(&audio->free_in_queue)) {
+					buf_node =
+					list_first_entry(&audio->free_in_queue,
+					 struct audio_mvs_buf_node, list);
+					list_del(&buf_node->list);
+					rc = copy_from_user(&buf_node->frame,
+							    buf,
+							    count);
+
+					list_add_tail(&buf_node->list,
+						      &audio->in_queue);
+				} else {
+					pr_err("%s: No free DL buffs\n",
+						__func__);
+				}
+			} else {
+				pr_err("%s: Write count %d < sizeof(frame) %d",
+				       __func__, count,
+				       sizeof(struct q6_msm_audio_mvs_frame));
+
+				rc = -ENOMEM;
+			}
+		} else {
+			pr_err("%s: Write performed in invalid state %d\n",
+			       __func__, audio->state);
+
+			rc = -EPERM;
+		}
+
+		mutex_unlock(&audio->in_lock);
+	} else if (rc == 0) {
+		pr_err("%s: No free DL buffs\n", __func__);
+
+		rc = -ETIMEDOUT;
+	} else {
+		pr_err("%s: write was interrupted\n", __func__);
+
+		rc = -ERESTARTSYS;
+	}
+
+	return rc;
+}
+
+static long audio_mvs_ioctl(struct file *file,
+			    unsigned int cmd,
+			    unsigned long arg)
+{
+	int rc = 0;
+	struct audio_mvs_info_type *audio = file->private_data;
+
+	pr_info("%s:\n", __func__);
+
+	switch (cmd) {
+	case AUDIO_GET_MVS_CONFIG: {
+		struct msm_audio_mvs_config config;
+
+		pr_info("%s: IOCTL GET_MVS_CONFIG\n", __func__);
+
+		mutex_lock(&audio->lock);
+
+		config.mvs_mode = audio->mvs_mode;
+		config.rate_type = audio->rate_type;
+		config.dtx_mode = audio->dtx_mode;
+		config.min_max_rate.min_rate = audio->min_max_rate.min_rate;
+		config.min_max_rate.max_rate = audio->min_max_rate.max_rate;
+		mutex_unlock(&audio->lock);
+
+		rc = copy_to_user((void *)arg, &config, sizeof(config));
+		if (rc == 0)
+			rc = sizeof(config);
+		else
+			pr_err("%s: Config copy failed %d\n", __func__, rc);
+
+		break;
+	}
+
+	case AUDIO_SET_MVS_CONFIG: {
+		struct msm_audio_mvs_config config;
+
+		pr_info("%s: IOCTL SET_MVS_CONFIG\n", __func__);
+
+		rc = copy_from_user(&config, (void *)arg, sizeof(config));
+		if (rc == 0) {
+			mutex_lock(&audio->lock);
+
+			if (audio->state == AUDIO_MVS_STOPPED) {
+				audio->mvs_mode = config.mvs_mode;
+				audio->rate_type = config.rate_type;
+				audio->dtx_mode = config.dtx_mode;
+				audio->min_max_rate.min_rate =
+						config.min_max_rate.min_rate;
+				audio->min_max_rate.max_rate =
+						config.min_max_rate.max_rate;
+			} else {
+				pr_err("%s: Set confg called in state %d\n",
+				       __func__, audio->state);
+
+				rc = -EPERM;
+			}
+
+			mutex_unlock(&audio->lock);
+		} else {
+			pr_err("%s: Config copy failed %d\n", __func__, rc);
+		}
+
+		break;
+	}
+
+	case AUDIO_START: {
+		pr_info("%s: IOCTL START\n", __func__);
+
+		mutex_lock(&audio->lock);
+
+		if (audio->state == AUDIO_MVS_STOPPED) {
+			rc = audio_mvs_start(audio);
+
+			if (rc != 0)
+				audio_mvs_stop(audio);
+		} else {
+			pr_err("%s: Start called in invalid state %d\n",
+			       __func__, audio->state);
+
+			rc = -EPERM;
+		}
+
+		mutex_unlock(&audio->lock);
+
+		break;
+	}
+
+	case AUDIO_STOP: {
+		pr_info("%s: IOCTL STOP\n", __func__);
+
+		mutex_lock(&audio->lock);
+
+		if (audio->state == AUDIO_MVS_STARTED) {
+			rc = audio_mvs_stop(audio);
+		} else {
+			pr_err("%s: Stop called in invalid state %d\n",
+			       __func__, audio->state);
+
+			rc = -EPERM;
+		}
+
+		mutex_unlock(&audio->lock);
+
+		break;
+	}
+
+	default: {
+		pr_err("%s: Unknown IOCTL %d\n", __func__, cmd);
+	}
+	}
+
+	return rc;
+}
+
+static const struct file_operations audio_mvs_fops = {
+	.owner = THIS_MODULE,
+	.open = audio_mvs_open,
+	.release = audio_mvs_release,
+	.read = audio_mvs_read,
+	.write = audio_mvs_write,
+	.unlocked_ioctl = audio_mvs_ioctl
+};
+
+struct miscdevice audio_mvs_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_mvs",
+	.fops = &audio_mvs_fops
+};
+
+static int __init audio_mvs_init(void)
+{
+	int rc = 0;
+
+	memset(&audio_mvs_info, 0, sizeof(audio_mvs_info));
+
+	init_waitqueue_head(&audio_mvs_info.in_wait);
+	init_waitqueue_head(&audio_mvs_info.out_wait);
+
+	mutex_init(&audio_mvs_info.lock);
+	mutex_init(&audio_mvs_info.in_lock);
+	mutex_init(&audio_mvs_info.out_lock);
+
+	spin_lock_init(&audio_mvs_info.dsp_lock);
+
+	INIT_LIST_HEAD(&audio_mvs_info.in_queue);
+	INIT_LIST_HEAD(&audio_mvs_info.free_in_queue);
+	INIT_LIST_HEAD(&audio_mvs_info.out_queue);
+	INIT_LIST_HEAD(&audio_mvs_info.free_out_queue);
+
+	wake_lock_init(&audio_mvs_info.suspend_lock,
+		       WAKE_LOCK_SUSPEND,
+		       "audio_mvs_suspend");
+	wake_lock_init(&audio_mvs_info.idle_lock,
+		       WAKE_LOCK_IDLE,
+		       "audio_mvs_idle");
+
+	rc = misc_register(&audio_mvs_misc);
+
+	return rc;
+}
+
+static void __exit audio_mvs_exit(void){
+	pr_info("%s:\n", __func__);
+
+	misc_deregister(&audio_mvs_misc);
+}
+
+module_init(audio_mvs_init);
+module_exit(audio_mvs_exit);
+
+MODULE_DESCRIPTION("MSM MVS driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_qcelp.c b/arch/arm/mach-msm/qdsp6v2/audio_qcelp.c
new file mode 100644
index 0000000..37f6e6b
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_qcelp.c
@@ -0,0 +1,175 @@
+/* qcelp(v13k) audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2011-2012, Code Aurora Forum. 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.
+ *
+ */
+
+#include "audio_utils_aio.h"
+
+#define FRAME_SIZE_DEC_QCELP  ((32) + sizeof(struct dec_meta_in))
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations audio_qcelp_debug_fops = {
+	.read = audio_aio_debug_read,
+	.open = audio_aio_debug_open,
+};
+#endif
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct q6audio_aio *audio = file->private_data;
+	int rc = 0;
+
+	switch (cmd) {
+	case AUDIO_START: {
+		pr_debug("%s[%p]: AUDIO_START session_id[%d]\n", __func__,
+						audio, audio->ac->session);
+		if (audio->feedback == NON_TUNNEL_MODE) {
+			/* Configure PCM output block */
+			rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+					audio->pcm_cfg.sample_rate,
+					audio->pcm_cfg.channel_count);
+			if (rc < 0) {
+				pr_err("pcm output block config failed\n");
+				break;
+			}
+		}
+
+		rc = audio_aio_enable(audio);
+		audio->eos_rsp = 0;
+		audio->eos_flag = 0;
+		if (!rc) {
+			audio->enabled = 1;
+		} else {
+			audio->enabled = 0;
+			pr_err("Audio Start procedure failed rc=%d\n", rc);
+			break;
+		}
+		pr_debug("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
+						audio->ac->session,
+						audio->enabled);
+		if (audio->stopped == 1)
+			audio->stopped = 0;
+		break;
+	}
+	default:
+		pr_debug("%s[%p]: Calling utils ioctl\n", __func__, audio);
+		rc = audio->codec_ioctl(file, cmd, arg);
+	}
+	return rc;
+}
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct q6audio_aio *audio = NULL;
+	int rc = 0;
+
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_qcelp_" + 5];
+#endif
+	audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+	if (audio == NULL) {
+		pr_err("Could not allocate memory for aac decode driver\n");
+		return -ENOMEM;
+	}
+
+	/* Settings will be re-config at AUDIO_SET_CONFIG,
+	 * but at least we need to have initial config
+	 */
+	audio->str_cfg.buffer_size = FRAME_SIZE_DEC_QCELP;
+	audio->str_cfg.buffer_count = FRAME_NUM;
+	audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+	audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
+	audio->pcm_cfg.sample_rate = 8000;
+	audio->pcm_cfg.channel_count = 1;
+
+	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
+					     (void *)audio);
+
+	if (!audio->ac) {
+		pr_err("Could not allocate memory for audio client\n");
+		kfree(audio);
+		return -ENOMEM;
+	}
+
+	/* open in T/NT mode */
+	if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+		rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+					   FORMAT_V13K);
+		if (rc < 0) {
+			pr_err("NT mode Open failed rc=%d\n", rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->feedback = NON_TUNNEL_MODE;
+		audio->buf_cfg.frames_per_buf = 0x01;
+		audio->buf_cfg.meta_info_enable = 0x01;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+		rc = q6asm_open_write(audio->ac, FORMAT_V13K);
+		if (rc < 0) {
+			pr_err("T mode Open failed rc=%d\n", rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->feedback = TUNNEL_MODE;
+		audio->buf_cfg.meta_info_enable = 0x00;
+	} else {
+		pr_err("Not supported mode\n");
+		rc = -EACCES;
+		goto fail;
+	}
+	rc = audio_aio_open(audio, file);
+
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_qcelp_%04x", audio->ac->session);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+					    NULL, (void *)audio,
+					    &audio_qcelp_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		pr_debug("debugfs_create_file failed\n");
+#endif
+	pr_info("%s:dec success mode[%d]session[%d]\n", __func__,
+						audio->feedback,
+						audio->ac->session);
+	return 0;
+fail:
+	q6asm_audio_client_free(audio->ac);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_qcelp_fops = {
+	.owner = THIS_MODULE,
+	.open = audio_open,
+	.release = audio_aio_release,
+	.unlocked_ioctl = audio_ioctl,
+	.fsync = audio_aio_fsync,
+};
+
+struct miscdevice audio_qcelp_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_qcelp",
+	.fops = &audio_qcelp_fops,
+};
+
+static int __init audio_qcelp_init(void)
+{
+	return misc_register(&audio_qcelp_misc);
+}
+
+device_initcall(audio_qcelp_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils.c b/arch/arm/mach-msm/qdsp6v2/audio_utils.c
new file mode 100644
index 0000000..6a23e37
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils.c
@@ -0,0 +1,637 @@
+/* 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
+ * 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/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include "audio_utils.h"
+
+static int audio_in_pause(struct q6audio_in  *audio)
+{
+	int rc;
+
+	rc = q6asm_cmd(audio->ac, CMD_PAUSE);
+	if (rc < 0)
+		pr_err("%s:session id %d: pause cmd failed rc=%d\n", __func__,
+				audio->ac->session, rc);
+
+	return rc;
+}
+
+static int audio_in_flush(struct q6audio_in  *audio)
+{
+	int rc;
+
+	pr_debug("%s:session id %d: flush\n", __func__, audio->ac->session);
+	/* Flush if session running */
+	if (audio->enabled) {
+		/* Implicitly issue a pause to the encoder before flushing */
+		rc = audio_in_pause(audio);
+		if (rc < 0) {
+			pr_err("%s:session id %d: pause cmd failed rc=%d\n",
+				 __func__, audio->ac->session, rc);
+			return rc;
+		}
+
+		rc = q6asm_cmd(audio->ac, CMD_FLUSH);
+		if (rc < 0) {
+			pr_err("%s:session id %d: flush cmd failed rc=%d\n",
+				__func__, audio->ac->session, rc);
+			return rc;
+		}
+		/* 2nd arg: 0 -> run immediately
+		   3rd arg: 0 -> msw_ts, 4th arg: 0 ->lsw_ts */
+		q6asm_run(audio->ac, 0x00, 0x00, 0x00);
+		pr_debug("Rerun the session\n");
+	}
+	audio->rflush = 1;
+	audio->wflush = 1;
+	memset(audio->out_frame_info, 0, sizeof(audio->out_frame_info));
+	wake_up(&audio->read_wait);
+	/* get read_lock to ensure no more waiting read thread */
+	mutex_lock(&audio->read_lock);
+	audio->rflush = 0;
+	mutex_unlock(&audio->read_lock);
+	wake_up(&audio->write_wait);
+	/* get write_lock to ensure no more waiting write thread */
+	mutex_lock(&audio->write_lock);
+	audio->wflush = 0;
+	mutex_unlock(&audio->write_lock);
+	pr_debug("%s:session id %d: in_bytes %d\n", __func__,
+			audio->ac->session, atomic_read(&audio->in_bytes));
+	pr_debug("%s:session id %d: in_samples %d\n", __func__,
+			audio->ac->session, atomic_read(&audio->in_samples));
+	atomic_set(&audio->in_bytes, 0);
+	atomic_set(&audio->in_samples, 0);
+	atomic_set(&audio->out_count, 0);
+	return 0;
+}
+
+/* must be called with audio->lock held */
+int audio_in_enable(struct q6audio_in  *audio)
+{
+	if (audio->enabled)
+		return 0;
+
+	/* 2nd arg: 0 -> run immediately
+		3rd arg: 0 -> msw_ts, 4th arg: 0 ->lsw_ts */
+	return q6asm_run(audio->ac, 0x00, 0x00, 0x00);
+}
+
+/* must be called with audio->lock held */
+int audio_in_disable(struct q6audio_in  *audio)
+{
+	int rc = 0;
+	if (audio->opened) {
+		audio->enabled = 0;
+		audio->opened = 0;
+		pr_debug("%s:session id %d: inbytes[%d] insamples[%d]\n",
+				__func__, audio->ac->session,
+				atomic_read(&audio->in_bytes),
+				atomic_read(&audio->in_samples));
+
+		rc = q6asm_cmd(audio->ac, CMD_CLOSE);
+		if (rc < 0)
+			pr_err("%s:session id %d: Failed to close the"
+				"session rc=%d\n", __func__, audio->ac->session,
+				rc);
+		audio->stopped = 1;
+		memset(audio->out_frame_info, 0,
+				sizeof(audio->out_frame_info));
+		wake_up(&audio->read_wait);
+		wake_up(&audio->write_wait);
+	}
+	pr_debug("%s:session id %d: enabled[%d]\n", __func__,
+			audio->ac->session, audio->enabled);
+	return rc;
+}
+
+int audio_in_buf_alloc(struct q6audio_in *audio)
+{
+	int rc = 0;
+
+	switch (audio->buf_alloc) {
+	case NO_BUF_ALLOC:
+		if (audio->feedback == NON_TUNNEL_MODE) {
+			rc = q6asm_audio_client_buf_alloc(IN,
+				audio->ac,
+				ALIGN_BUF_SIZE(audio->pcm_cfg.buffer_size),
+				audio->pcm_cfg.buffer_count);
+			if (rc < 0) {
+				pr_err("%s:session id %d: Buffer Alloc"
+						"failed\n", __func__,
+						audio->ac->session);
+				rc = -ENOMEM;
+				break;
+			}
+			audio->buf_alloc |= BUF_ALLOC_IN;
+		}
+		rc = q6asm_audio_client_buf_alloc(OUT, audio->ac,
+				ALIGN_BUF_SIZE(audio->str_cfg.buffer_size),
+				audio->str_cfg.buffer_count);
+		if (rc < 0) {
+			pr_err("%s:session id %d: Buffer Alloc failed rc=%d\n",
+					__func__, audio->ac->session, rc);
+			rc = -ENOMEM;
+			break;
+		}
+		audio->buf_alloc |= BUF_ALLOC_OUT;
+		break;
+	case BUF_ALLOC_IN:
+		rc = q6asm_audio_client_buf_alloc(OUT, audio->ac,
+				ALIGN_BUF_SIZE(audio->str_cfg.buffer_size),
+				audio->str_cfg.buffer_count);
+		if (rc < 0) {
+			pr_err("%s:session id %d: Buffer Alloc failed rc=%d\n",
+					__func__, audio->ac->session, rc);
+			rc = -ENOMEM;
+			break;
+		}
+		audio->buf_alloc |= BUF_ALLOC_OUT;
+		break;
+	case BUF_ALLOC_OUT:
+		if (audio->feedback == NON_TUNNEL_MODE) {
+			rc = q6asm_audio_client_buf_alloc(IN, audio->ac,
+				ALIGN_BUF_SIZE(audio->pcm_cfg.buffer_size),
+				audio->pcm_cfg.buffer_count);
+			if (rc < 0) {
+				pr_err("%s:session id %d: Buffer Alloc"
+					"failed\n", __func__,
+					audio->ac->session);
+				rc = -ENOMEM;
+				break;
+			}
+			audio->buf_alloc |= BUF_ALLOC_IN;
+		}
+		break;
+	default:
+		pr_debug("%s:session id %d: buf[%d]\n", __func__,
+					audio->ac->session, audio->buf_alloc);
+	}
+
+	return rc;
+}
+/* ------------------- device --------------------- */
+long audio_in_ioctl(struct file *file,
+				unsigned int cmd, unsigned long arg)
+{
+	struct q6audio_in  *audio = file->private_data;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = atomic_read(&audio->in_bytes);
+		stats.sample_count = atomic_read(&audio->in_samples);
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return rc;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_FLUSH: {
+		/* Make sure we're stopped and we wake any threads
+		* that might be blocked holding the read_lock.
+		* While audio->stopped read threads will always
+		* exit immediately.
+		*/
+		rc = audio_in_flush(audio);
+		if (rc < 0)
+			pr_err("%s:session id %d: Flush Fail rc=%d\n",
+					__func__, audio->ac->session, rc);
+		else { /* Register back the flushed read buffer with DSP */
+			int cnt = 0;
+			while (cnt++ < audio->str_cfg.buffer_count)
+				q6asm_read(audio->ac); /* Push buffer to DSP */
+			pr_debug("register the read buffer\n");
+		}
+		break;
+	}
+	case AUDIO_PAUSE: {
+		pr_debug("%s:session id %d: AUDIO_PAUSE\n", __func__,
+					audio->ac->session);
+		if (audio->enabled)
+			audio_in_pause(audio);
+		break;
+	}
+	case AUDIO_GET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		memset(&cfg, 0, sizeof(cfg));
+		cfg.buffer_size = audio->str_cfg.buffer_size;
+		cfg.buffer_count = audio->str_cfg.buffer_count;
+		if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		pr_debug("%s:session id %d: AUDIO_GET_STREAM_CONFIG %d %d\n",
+				__func__, audio->ac->session, cfg.buffer_size,
+				cfg.buffer_count);
+		break;
+	}
+	case AUDIO_SET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		/* Minimum single frame size,
+		   but with in maximum frames number */
+		if ((cfg.buffer_size < (audio->min_frame_size+ \
+			sizeof(struct meta_out_dsp))) ||
+			(cfg.buffer_count < FRAME_NUM)) {
+			rc = -EINVAL;
+			break;
+		}
+		audio->str_cfg.buffer_size = cfg.buffer_size;
+		audio->str_cfg.buffer_count = cfg.buffer_count;
+		rc = q6asm_audio_client_buf_alloc(OUT, audio->ac,
+				ALIGN_BUF_SIZE(audio->str_cfg.buffer_size),
+				audio->str_cfg.buffer_count);
+		if (rc < 0) {
+			pr_err("%s: session id %d: Buffer Alloc failed rc=%d\n",
+					__func__, audio->ac->session, rc);
+			rc = -ENOMEM;
+			break;
+		}
+		audio->buf_alloc |= BUF_ALLOC_OUT;
+		rc = 0;
+		pr_debug("%s:session id %d: AUDIO_SET_STREAM_CONFIG %d %d\n",
+				__func__, audio->ac->session,
+				audio->str_cfg.buffer_size,
+				audio->str_cfg.buffer_count);
+		break;
+	}
+	case AUDIO_GET_SESSION_ID: {
+		if (copy_to_user((void *) arg, &audio->ac->session,
+			sizeof(unsigned short))) {
+			rc = -EFAULT;
+		}
+		break;
+	}
+	case AUDIO_SET_BUF_CFG: {
+		struct msm_audio_buf_cfg  cfg;
+		if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		if ((audio->feedback == NON_TUNNEL_MODE) &&
+			!cfg.meta_info_enable) {
+			rc = -EFAULT;
+			break;
+		}
+
+		/* Restrict the num of frames per buf to coincide with
+		 * default buf size */
+		if (cfg.frames_per_buf > audio->max_frames_per_buf) {
+			rc = -EFAULT;
+			break;
+		}
+		audio->buf_cfg.meta_info_enable = cfg.meta_info_enable;
+		audio->buf_cfg.frames_per_buf = cfg.frames_per_buf;
+		pr_debug("%s:session id %d: Set-buf-cfg: meta[%d]"
+				"framesperbuf[%d]\n", __func__,
+				audio->ac->session, cfg.meta_info_enable,
+				cfg.frames_per_buf);
+		break;
+	}
+	case AUDIO_GET_BUF_CFG: {
+		pr_debug("%s:session id %d: Get-buf-cfg: meta[%d]"
+			"framesperbuf[%d]\n", __func__,
+			audio->ac->session, audio->buf_cfg.meta_info_enable,
+			audio->buf_cfg.frames_per_buf);
+
+		if (copy_to_user((void *)arg, &audio->buf_cfg,
+					sizeof(struct msm_audio_buf_cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		if (copy_to_user((void *)arg, &audio->pcm_cfg,
+					sizeof(struct msm_audio_config)))
+			rc = -EFAULT;
+		break;
+
+	}
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config cfg;
+		if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (audio->feedback != NON_TUNNEL_MODE) {
+			pr_err("%s:session id %d: Not sufficient permission to"
+					"change the record mode\n", __func__,
+					audio->ac->session);
+			rc = -EACCES;
+			break;
+		}
+		if ((cfg.buffer_count > PCM_BUF_COUNT) ||
+				(cfg.buffer_count == 1))
+			cfg.buffer_count = PCM_BUF_COUNT;
+
+		audio->pcm_cfg.buffer_count = cfg.buffer_count;
+		audio->pcm_cfg.buffer_size  = cfg.buffer_size;
+		audio->pcm_cfg.channel_count = cfg.channel_count;
+		audio->pcm_cfg.sample_rate = cfg.sample_rate;
+		rc = q6asm_audio_client_buf_alloc(IN, audio->ac,
+			ALIGN_BUF_SIZE(audio->pcm_cfg.buffer_size),
+			audio->pcm_cfg.buffer_count);
+		if (rc < 0) {
+			pr_err("%s:session id %d: Buffer Alloc failed\n",
+				__func__, audio->ac->session);
+			rc = -ENOMEM;
+			break;
+		}
+		audio->buf_alloc |= BUF_ALLOC_IN;
+		rc = 0;
+		pr_debug("%s:session id %d: AUDIO_SET_CONFIG %d %d\n", __func__,
+			audio->ac->session, audio->pcm_cfg.buffer_count,
+			audio->pcm_cfg.buffer_size);
+		break;
+	}
+	default:
+		/* call codec specific ioctl */
+		rc = audio->enc_ioctl(file, cmd, arg);
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+ssize_t audio_in_read(struct file *file,
+				char __user *buf,
+				size_t count, loff_t *pos)
+{
+	struct q6audio_in  *audio = file->private_data;
+	const char __user *start = buf;
+	unsigned char *data;
+	uint32_t offset = 0;
+	uint32_t size = 0;
+	int rc = 0;
+	uint32_t idx;
+	struct meta_out_dsp meta;
+	uint32_t bytes_to_copy = 0;
+	uint32_t mfield_size = (audio->buf_cfg.meta_info_enable == 0) ? 0 :
+		(sizeof(unsigned char) +
+		(sizeof(struct meta_out_dsp)*(audio->buf_cfg.frames_per_buf)));
+
+	pr_debug("%s:session id %d: read - %d\n", __func__, audio->ac->session,
+			count);
+	if (!audio->enabled)
+		return -EFAULT;
+	mutex_lock(&audio->read_lock);
+	while (count > 0) {
+		rc = wait_event_interruptible(
+			audio->read_wait,
+			((atomic_read(&audio->out_count) > 0) ||
+			(audio->stopped) ||
+			 audio->rflush || audio->eos_rsp));
+
+		if (rc < 0)
+			break;
+
+		if ((audio->stopped && !(atomic_read(&audio->out_count))) ||
+			audio->rflush) {
+			pr_debug("%s:session id %d: driver in stop state or"
+				"flush,No more buf to read", __func__,
+				audio->ac->session);
+			rc = 0;/* End of File */
+			break;
+		}
+		if (!(atomic_read(&audio->out_count)) &&
+			(audio->eos_rsp == 1) &&
+			(count >= (sizeof(unsigned char) +
+				sizeof(struct meta_out_dsp)))) {
+			unsigned char num_of_frames;
+			pr_info("%s:session id %d: eos %d at output\n",
+				__func__, audio->ac->session, audio->eos_rsp);
+			if (buf != start)
+				break;
+			num_of_frames = 0xFF;
+			if (copy_to_user(buf, &num_of_frames,
+					sizeof(unsigned char))) {
+				rc = -EFAULT;
+				break;
+			}
+			buf += sizeof(unsigned char);
+			meta.frame_size = 0xFFFF;
+			meta.encoded_pcm_samples = 0xFFFF;
+			meta.msw_ts = 0x00;
+			meta.lsw_ts = 0x00;
+			meta.nflags = AUD_EOS_SET;
+			audio->eos_rsp = 0;
+			if (copy_to_user(buf, &meta, sizeof(meta))) {
+				rc = -EFAULT;
+				break;
+			}
+			buf += sizeof(meta);
+			break;
+		}
+		data = (unsigned char *)q6asm_is_cpu_buf_avail(OUT, audio->ac,
+						&size, &idx);
+		if ((count >= (size + mfield_size)) && data) {
+			if (audio->buf_cfg.meta_info_enable) {
+				if (copy_to_user(buf,
+					&audio->out_frame_info[idx][0],
+					sizeof(unsigned char))) {
+					rc = -EFAULT;
+					break;
+				}
+				bytes_to_copy =
+					(size + audio->out_frame_info[idx][1]);
+				/* Number of frames information copied */
+				buf += sizeof(unsigned char);
+				count -= sizeof(unsigned char);
+			} else {
+				offset = audio->out_frame_info[idx][1];
+				bytes_to_copy = size;
+			}
+
+			pr_debug("%s:session id %d: offset=%d nr of frames= %d\n",
+					__func__, audio->ac->session,
+					audio->out_frame_info[idx][1],
+					audio->out_frame_info[idx][0]);
+
+			if (copy_to_user(buf, &data[offset], bytes_to_copy)) {
+				rc = -EFAULT;
+				break;
+			}
+			count -= bytes_to_copy;
+			buf += bytes_to_copy;
+		} else {
+			pr_err("%s:session id %d: short read data[%p]"
+				"bytesavail[%d]bytesrequest[%d]\n", __func__,
+				audio->ac->session,
+				data, size, count);
+		}
+		atomic_dec(&audio->out_count);
+		q6asm_read(audio->ac);
+		break;
+	}
+	mutex_unlock(&audio->read_lock);
+
+	pr_debug("%s:session id %d: read: %d bytes\n", __func__,
+			audio->ac->session, (buf-start));
+	if (buf > start)
+		return buf - start;
+	return rc;
+}
+
+static int extract_meta_info(char *buf, unsigned long *msw_ts,
+		unsigned long *lsw_ts, unsigned int *flags)
+{
+	struct meta_in *meta = (struct meta_in *)buf;
+	*msw_ts = meta->ntimestamp.highpart;
+	*lsw_ts = meta->ntimestamp.lowpart;
+	*flags = meta->nflags;
+	return 0;
+}
+
+ssize_t audio_in_write(struct file *file,
+		const char __user *buf,
+		size_t count, loff_t *pos)
+{
+	struct q6audio_in *audio = file->private_data;
+	const char __user *start = buf;
+	size_t xfer = 0;
+	char *cpy_ptr;
+	int rc = 0;
+	unsigned char *data;
+	uint32_t size = 0;
+	uint32_t idx = 0;
+	uint32_t nflags = 0;
+	unsigned long msw_ts = 0;
+	unsigned long lsw_ts = 0;
+	uint32_t mfield_size = (audio->buf_cfg.meta_info_enable == 0) ? 0 :
+			sizeof(struct meta_in);
+
+	pr_debug("%s:session id %d: to write[%d]\n", __func__,
+			audio->ac->session, count);
+	if (!audio->enabled)
+		return -EFAULT;
+	mutex_lock(&audio->write_lock);
+
+	while (count > 0) {
+		rc = wait_event_interruptible(audio->write_wait,
+				     ((atomic_read(&audio->in_count) > 0) ||
+				      (audio->stopped) ||
+				      (audio->wflush)));
+		if (rc < 0)
+			break;
+		if (audio->stopped || audio->wflush) {
+			pr_debug("%s: session id %d: stop or flush\n", __func__,
+					audio->ac->session);
+			rc = -EBUSY;
+			break;
+		}
+		/* if no PCM data, might have only eos buffer
+		   such case do not hold cpu buffer */
+		if ((buf == start) && (count == mfield_size)) {
+			char eos_buf[sizeof(struct meta_in)];
+			/* Processing begining of user buffer */
+			if (copy_from_user(eos_buf, buf, mfield_size)) {
+				rc = -EFAULT;
+				break;
+			}
+			/* Check if EOS flag is set and buffer has
+			 * contains just meta field
+			 */
+			extract_meta_info(eos_buf, &msw_ts, &lsw_ts,
+						&nflags);
+			buf += mfield_size;
+			/* send the EOS and return */
+			pr_debug("%s:session id %d: send EOS"
+				"0x%8x\n", __func__,
+				audio->ac->session, nflags);
+			break;
+		}
+		data = (unsigned char *)q6asm_is_cpu_buf_avail(IN, audio->ac,
+						&size, &idx);
+		if (!data) {
+			pr_debug("%s:session id %d: No buf available\n",
+				__func__, audio->ac->session);
+			continue;
+		}
+		cpy_ptr = data;
+		if (audio->buf_cfg.meta_info_enable) {
+			if (buf == start) {
+				/* Processing beginning of user buffer */
+				if (copy_from_user(cpy_ptr, buf, mfield_size)) {
+					rc = -EFAULT;
+					break;
+				}
+				/* Check if EOS flag is set and buffer has
+				* contains just meta field
+				*/
+				extract_meta_info(cpy_ptr, &msw_ts, &lsw_ts,
+						&nflags);
+				buf += mfield_size;
+				count -= mfield_size;
+			} else {
+				pr_debug("%s:session id %d: continuous"
+				"buffer\n", __func__, audio->ac->session);
+			}
+		}
+		xfer = (count > (audio->pcm_cfg.buffer_size)) ?
+				(audio->pcm_cfg.buffer_size) : count;
+
+		if (copy_from_user(cpy_ptr, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+		rc = q6asm_write(audio->ac, xfer, msw_ts, lsw_ts, 0x00);
+		if (rc < 0) {
+			rc = -EFAULT;
+			break;
+		}
+		atomic_dec(&audio->in_count);
+		count -= xfer;
+		buf += xfer;
+	}
+	mutex_unlock(&audio->write_lock);
+	pr_debug("%s:session id %d: eos_condition 0x%8x buf[0x%x]"
+			"start[0x%x]\n", __func__, audio->ac->session,
+				nflags,	(int) buf, (int) start);
+	if (nflags & AUD_EOS_SET) {
+		rc = q6asm_cmd(audio->ac, CMD_EOS);
+		pr_info("%s:session id %d: eos %d at input\n", __func__,
+				audio->ac->session, audio->eos_rsp);
+	}
+	pr_debug("%s:session id %d: Written %d Avail Buf[%d]", __func__,
+			audio->ac->session, (buf - start - mfield_size),
+			atomic_read(&audio->in_count));
+	if (!rc) {
+		if (buf > start)
+			return buf - start;
+	}
+	return rc;
+}
+
+int audio_in_release(struct inode *inode, struct file *file)
+{
+	struct q6audio_in  *audio = file->private_data;
+	pr_info("%s: session id %d\n", __func__, audio->ac->session);
+	mutex_lock(&audio->lock);
+	audio_in_disable(audio);
+	q6asm_audio_client_free(audio->ac);
+	mutex_unlock(&audio->lock);
+	kfree(audio->enc_cfg);
+	kfree(audio->codec_cfg);
+	kfree(audio);
+	return 0;
+}
+
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils.h b/arch/arm/mach-msm/qdsp6v2/audio_utils.h
new file mode 100644
index 0000000..df963f9
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils.h
@@ -0,0 +1,103 @@
+/* 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
+ * 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/msm_audio.h>
+#include "q6audio_common.h"
+
+#define FRAME_NUM	(8)
+
+#define PCM_BUF_COUNT		(2)
+
+#define AUD_EOS_SET  0x01
+#define TUNNEL_MODE     0x0000
+#define NON_TUNNEL_MODE 0x0001
+
+#define NO_BUF_ALLOC	0x00
+#define BUF_ALLOC_IN    0x01
+#define BUF_ALLOC_OUT   0x02
+#define BUF_ALLOC_INOUT 0x03
+#define ALIGN_BUF_SIZE(size) ((size + 4095) & (~4095))
+
+struct timestamp {
+	unsigned long lowpart;
+	unsigned long highpart;
+} __attribute__ ((packed));
+
+struct meta_in {
+	unsigned short offset;
+	struct timestamp ntimestamp;
+	unsigned int nflags;
+} __attribute__ ((packed));
+
+struct meta_out_dsp {
+	u32 offset_to_frame;
+	u32 frame_size;
+	u32 encoded_pcm_samples;
+	u32 msw_ts;
+	u32 lsw_ts;
+	u32 nflags;
+} __attribute__ ((packed));
+
+struct meta_out {
+	unsigned char num_of_frames;
+	struct meta_out_dsp meta_out_dsp[];
+} __attribute__ ((packed));
+
+struct q6audio_in {
+	spinlock_t			dsp_lock;
+	atomic_t			in_bytes;
+	atomic_t			in_samples;
+
+	struct mutex			lock;
+	struct mutex			read_lock;
+	struct mutex			write_lock;
+	wait_queue_head_t		read_wait;
+	wait_queue_head_t		write_wait;
+
+	struct audio_client             *ac;
+	struct msm_audio_stream_config  str_cfg;
+	void				*enc_cfg;
+	struct msm_audio_buf_cfg        buf_cfg;
+	struct msm_audio_config		pcm_cfg;
+	void				*codec_cfg;
+
+	/* number of buffers available to read/write */
+	atomic_t			in_count;
+	atomic_t			out_count;
+
+	/* first idx: num of frames per buf, second idx: offset to frame */
+	uint32_t			out_frame_info[FRAME_NUM][2];
+	int				eos_rsp;
+	int				opened;
+	int				enabled;
+	int				stopped;
+	int				feedback; /* Flag indicates whether used
+							in Non Tunnel mode */
+	int				rflush;
+	int				wflush;
+	int				buf_alloc;
+	uint16_t			min_frame_size;
+	uint16_t			max_frames_per_buf;
+	long (*enc_ioctl)(struct file *, unsigned int, unsigned long);
+};
+
+int audio_in_enable(struct q6audio_in  *audio);
+int audio_in_disable(struct q6audio_in  *audio);
+int audio_in_buf_alloc(struct q6audio_in *audio);
+long audio_in_ioctl(struct file *file,
+		unsigned int cmd, unsigned long arg);
+ssize_t audio_in_read(struct file *file, char __user *buf,
+		size_t count, loff_t *pos);
+ssize_t audio_in_write(struct file *file, const char __user *buf,
+		size_t count, loff_t *pos);
+int audio_in_release(struct inode *inode, struct file *file);
+
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
new file mode 100644
index 0000000..6a99be2
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -0,0 +1,1407 @@
+/* Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2009-2012, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <linux/debugfs.h>
+#include "audio_utils_aio.h"
+
+#ifdef CONFIG_DEBUG_FS
+ssize_t audio_aio_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+ssize_t audio_aio_debug_read(struct file *file, char __user * buf,
+				size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 4096;
+	static char buffer[4096];
+	int n = 0;
+	struct q6audio_aio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"enabled %d\n", audio->enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"feedback %d\n", audio->feedback);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"rflush %d\n", audio->rflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"inqueue empty %d\n", list_empty(&audio->in_queue));
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"outqueue empty %d\n", list_empty(&audio->out_queue));
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+#endif
+
+static int insert_eos_buf(struct q6audio_aio *audio,
+		struct audio_aio_buffer_node *buf_node)
+{
+	struct dec_meta_out *eos_buf = buf_node->kvaddr;
+	pr_debug("%s[%p]:insert_eos_buf\n", __func__, audio);
+	eos_buf->num_of_frames = 0xFFFFFFFF;
+	eos_buf->meta_out_dsp[0].offset_to_frame = 0x0;
+	eos_buf->meta_out_dsp[0].nflags = AUDIO_DEC_EOS_SET;
+	return sizeof(struct dec_meta_out) +
+		sizeof(eos_buf->meta_out_dsp[0]);
+}
+
+/* Routine which updates read buffers of driver/dsp,
+   for flush operation as DSP output might not have proper
+   value set */
+static int insert_meta_data_flush(struct q6audio_aio *audio,
+	struct audio_aio_buffer_node *buf_node)
+{
+	struct dec_meta_out *meta_data = buf_node->kvaddr;
+	meta_data->num_of_frames = 0x0;
+	meta_data->meta_out_dsp[0].offset_to_frame = 0x0;
+	meta_data->meta_out_dsp[0].nflags = 0x0;
+	return sizeof(struct dec_meta_out) +
+		sizeof(meta_data->meta_out_dsp[0]);
+}
+
+static void extract_meta_out_info(struct q6audio_aio *audio,
+		struct audio_aio_buffer_node *buf_node, int dir)
+{
+	struct dec_meta_out *meta_data = buf_node->kvaddr;
+	if (dir) { /* input buffer - Write */
+		if (audio->buf_cfg.meta_info_enable)
+			memcpy(&buf_node->meta_info.meta_in,
+			(char *)buf_node->kvaddr, sizeof(struct dec_meta_in));
+		else
+			memset(&buf_node->meta_info.meta_in,
+			0, sizeof(struct dec_meta_in));
+		pr_debug("%s[%p]:i/p: msw_ts 0x%lx lsw_ts 0x%lx nflags 0x%8x\n",
+			__func__, audio,
+			buf_node->meta_info.meta_in.ntimestamp.highpart,
+			buf_node->meta_info.meta_in.ntimestamp.lowpart,
+			buf_node->meta_info.meta_in.nflags);
+	} else { /* output buffer - Read */
+		memcpy((char *)buf_node->kvaddr,
+			&buf_node->meta_info.meta_out,
+			sizeof(struct dec_meta_out));
+		meta_data->meta_out_dsp[0].nflags = 0x00000000;
+		pr_debug("%s[%p]:o/p: msw_ts 0x%8x lsw_ts 0x%8x nflags 0x%8x,"
+				"num_frames = %d\n",
+		__func__, audio,
+		((struct dec_meta_out *)buf_node->kvaddr)->\
+			meta_out_dsp[0].msw_ts,
+		((struct dec_meta_out *)buf_node->kvaddr)->\
+			meta_out_dsp[0].lsw_ts,
+		((struct dec_meta_out *)buf_node->kvaddr)->\
+			meta_out_dsp[0].nflags,
+		((struct dec_meta_out *)buf_node->kvaddr)->num_of_frames);
+	}
+}
+
+static int audio_aio_ion_lookup_vaddr(struct q6audio_aio *audio, void *addr,
+					unsigned long len,
+					struct audio_aio_ion_region **region)
+{
+	struct audio_aio_ion_region *region_elt;
+
+	int match_count = 0;
+
+	*region = NULL;
+
+	/* returns physical address or zero */
+	list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
+		if (addr >= region_elt->vaddr &&
+			addr < region_elt->vaddr + region_elt->len &&
+			addr + len <= region_elt->vaddr + region_elt->len) {
+			/* offset since we could pass vaddr inside a registerd
+			* ion buffer
+			*/
+
+			match_count++;
+			if (!*region)
+				*region = region_elt;
+		}
+	}
+
+	if (match_count > 1) {
+		pr_err("%s[%p]:multiple hits for vaddr %p, len %ld\n",
+			__func__, audio, addr, len);
+		list_for_each_entry(region_elt, &audio->ion_region_queue,
+					list) {
+			if (addr >= region_elt->vaddr &&
+			addr < region_elt->vaddr + region_elt->len &&
+			addr + len <= region_elt->vaddr + region_elt->len)
+				pr_err("\t%s[%p]:%p, %ld --> %p\n",
+					__func__, audio,
+					region_elt->vaddr,
+					region_elt->len,
+					(void *)region_elt->paddr);
+		}
+	}
+
+	return *region ? 0 : -1;
+}
+
+static unsigned long audio_aio_ion_fixup(struct q6audio_aio *audio, void *addr,
+				unsigned long len, int ref_up, void **kvaddr)
+{
+	struct audio_aio_ion_region *region;
+	unsigned long paddr;
+	int ret;
+
+	ret = audio_aio_ion_lookup_vaddr(audio, addr, len, &region);
+	if (ret) {
+		pr_err("%s[%p]:lookup (%p, %ld) failed\n",
+				__func__, audio, addr, len);
+		return 0;
+	}
+	if (ref_up)
+		region->ref_cnt++;
+	else
+		region->ref_cnt--;
+	pr_debug("%s[%p]:found region %p ref_cnt %d\n",
+			__func__, audio, region, region->ref_cnt);
+	paddr = region->paddr + (addr - region->vaddr);
+	/* provide kernel virtual address for accessing meta information */
+	if (kvaddr)
+		*kvaddr = (void *) (region->kvaddr + (addr - region->vaddr));
+	return paddr;
+}
+
+static int audio_aio_pause(struct q6audio_aio  *audio)
+{
+	int rc = 0;
+
+	pr_debug("%s[%p], enabled = %d\n", __func__, audio,
+			audio->enabled);
+	if (audio->enabled) {
+		rc = q6asm_cmd(audio->ac, CMD_PAUSE);
+		if (rc < 0)
+			pr_err("%s[%p]: pause cmd failed rc=%d\n",
+				__func__, audio, rc);
+
+	} else
+		pr_err("%s[%p]: Driver not enabled\n", __func__, audio);
+	return rc;
+}
+
+static int audio_aio_flush(struct q6audio_aio  *audio)
+{
+	int rc;
+
+	if (audio->enabled) {
+		/* Implicitly issue a pause to the decoder before flushing if
+		   it is not in pause state */
+		if (!(audio->drv_status & ADRV_STATUS_PAUSE)) {
+			rc = audio_aio_pause(audio);
+			if (rc < 0)
+				pr_err("%s[%p}: pause cmd failed rc=%d\n",
+					__func__, audio,
+					rc);
+			else
+				audio->drv_status |= ADRV_STATUS_PAUSE;
+		}
+		rc = q6asm_cmd(audio->ac, CMD_FLUSH);
+		if (rc < 0)
+			pr_err("%s[%p]: flush cmd failed rc=%d\n",
+				__func__, audio, rc);
+		/* Not in stop state, reenable the stream */
+		if (audio->stopped == 0) {
+			rc = audio_aio_enable(audio);
+			if (rc)
+				pr_err("%s[%p]:audio re-enable failed\n",
+					__func__, audio);
+			else {
+				audio->enabled = 1;
+				if (audio->drv_status & ADRV_STATUS_PAUSE)
+					audio->drv_status &= ~ADRV_STATUS_PAUSE;
+			}
+		}
+	}
+	pr_debug("%s[%p]:in_bytes %d\n",
+			__func__, audio, atomic_read(&audio->in_bytes));
+	pr_debug("%s[%p]:in_samples %d\n",
+			__func__, audio, atomic_read(&audio->in_samples));
+	atomic_set(&audio->in_bytes, 0);
+	atomic_set(&audio->in_samples, 0);
+	return 0;
+}
+
+static int audio_aio_outport_flush(struct q6audio_aio *audio)
+{
+	int rc;
+
+	rc = q6asm_cmd(audio->ac, CMD_OUT_FLUSH);
+	if (rc < 0)
+		pr_err("%s[%p}: output port flush cmd failed rc=%d\n",
+			__func__, audio, rc);
+	return rc;
+}
+
+/* Write buffer to DSP / Handle Ack from DSP */
+void audio_aio_async_write_ack(struct q6audio_aio *audio, uint32_t token,
+				uint32_t *payload)
+{
+	unsigned long flags;
+	union msm_audio_event_payload event_payload;
+	struct audio_aio_buffer_node *used_buf;
+
+	/* No active flush in progress */
+	if (audio->wflush)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	BUG_ON(list_empty(&audio->out_queue));
+	used_buf = list_first_entry(&audio->out_queue,
+					struct audio_aio_buffer_node, list);
+	if (token == used_buf->token) {
+		list_del(&used_buf->list);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		pr_debug("%s[%p]:consumed buffer\n", __func__, audio);
+		event_payload.aio_buf = used_buf->buf;
+		audio_aio_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+					event_payload);
+		kfree(used_buf);
+		if (list_empty(&audio->out_queue) &&
+			(audio->drv_status & ADRV_STATUS_FSYNC)) {
+			pr_debug("%s[%p]: list is empty, reached EOS in"
+				"Tunnel\n", __func__, audio);
+			wake_up(&audio->write_wait);
+		}
+	} else {
+		pr_err("%s[%p]:expected=%lx ret=%x\n",
+			__func__, audio, used_buf->token, token);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	}
+}
+
+/* Read buffer from DSP / Handle Ack from DSP */
+void audio_aio_async_read_ack(struct q6audio_aio *audio, uint32_t token,
+			uint32_t *payload)
+{
+	unsigned long flags;
+	union msm_audio_event_payload event_payload;
+	struct audio_aio_buffer_node *filled_buf;
+
+	/* No active flush in progress */
+	if (audio->rflush)
+		return;
+
+	/* Statistics of read */
+	atomic_add(payload[2], &audio->in_bytes);
+	atomic_add(payload[7], &audio->in_samples);
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	BUG_ON(list_empty(&audio->in_queue));
+	filled_buf = list_first_entry(&audio->in_queue,
+					struct audio_aio_buffer_node, list);
+	if (token == (filled_buf->token)) {
+		list_del(&filled_buf->list);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		event_payload.aio_buf = filled_buf->buf;
+		/* Read done Buffer due to flush/normal condition
+		after EOS event, so append EOS buffer */
+		if (audio->eos_rsp == 0x1) {
+			event_payload.aio_buf.data_len =
+			insert_eos_buf(audio, filled_buf);
+			/* Reset flag back to indicate eos intimated */
+			audio->eos_rsp = 0;
+		} else {
+			filled_buf->meta_info.meta_out.num_of_frames =
+			payload[7];
+			event_payload.aio_buf.data_len = payload[2] + \
+						payload[3] + \
+						sizeof(struct dec_meta_out);
+			pr_debug("%s[%p]:nr of frames 0x%8x len=%d\n",
+				__func__, audio,
+				filled_buf->meta_info.meta_out.num_of_frames,
+				event_payload.aio_buf.data_len);
+			extract_meta_out_info(audio, filled_buf, 0);
+			audio->eos_rsp = 0;
+		}
+		audio_aio_post_event(audio, AUDIO_EVENT_READ_DONE,
+					event_payload);
+		kfree(filled_buf);
+	} else {
+		pr_err("%s[%p]:expected=%lx ret=%x\n",
+			__func__, audio, filled_buf->token, token);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	}
+}
+
+/* ------------------- device --------------------- */
+void audio_aio_async_out_flush(struct q6audio_aio *audio)
+{
+	struct audio_aio_buffer_node *buf_node;
+	struct list_head *ptr, *next;
+	union msm_audio_event_payload payload;
+	unsigned long flags;
+
+	pr_debug("%s[%p}\n", __func__, audio);
+	/* EOS followed by flush, EOS response not guranteed, free EOS i/p
+	buffer */
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+
+	if (audio->eos_flag && (audio->eos_write_payload.aio_buf.buf_addr)) {
+		pr_debug("%s[%p]: EOS followed by flush received,acknowledge"\
+			" eos i/p buffer immediately\n", __func__, audio);
+		audio_aio_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+				audio->eos_write_payload);
+		memset(&audio->eos_write_payload , 0,
+			sizeof(union msm_audio_event_payload));
+	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	list_for_each_safe(ptr, next, &audio->out_queue) {
+		buf_node = list_entry(ptr, struct audio_aio_buffer_node, list);
+		list_del(&buf_node->list);
+		payload.aio_buf = buf_node->buf;
+		audio_aio_post_event(audio, AUDIO_EVENT_WRITE_DONE, payload);
+		kfree(buf_node);
+		pr_debug("%s[%p]: Propagate WRITE_DONE during flush\n",
+				__func__, audio);
+	}
+}
+
+void audio_aio_async_in_flush(struct q6audio_aio *audio)
+{
+	struct audio_aio_buffer_node *buf_node;
+	struct list_head *ptr, *next;
+	union msm_audio_event_payload payload;
+
+	pr_debug("%s[%p]\n", __func__, audio);
+	list_for_each_safe(ptr, next, &audio->in_queue) {
+		buf_node = list_entry(ptr, struct audio_aio_buffer_node, list);
+		list_del(&buf_node->list);
+		/* Forcefull send o/p eos buffer after flush, if no eos response
+		 * received by dsp even after sending eos command */
+		if ((audio->eos_rsp != 1) && audio->eos_flag) {
+			pr_debug("%s[%p]: send eos on o/p buffer during"
+				"flush\n", __func__, audio);
+			payload.aio_buf = buf_node->buf;
+			payload.aio_buf.data_len =
+					insert_eos_buf(audio, buf_node);
+			audio->eos_flag = 0;
+		} else {
+			payload.aio_buf = buf_node->buf;
+			payload.aio_buf.data_len =
+					insert_meta_data_flush(audio, buf_node);
+		}
+		audio_aio_post_event(audio, AUDIO_EVENT_READ_DONE, payload);
+		kfree(buf_node);
+		pr_debug("%s[%p]: Propagate READ_DONE during flush\n",
+				__func__, audio);
+	}
+}
+
+int audio_aio_enable(struct q6audio_aio  *audio)
+{
+	/* 2nd arg: 0 -> run immediately
+	3rd arg: 0 -> msw_ts, 4th arg: 0 ->lsw_ts */
+	return q6asm_run(audio->ac, 0x00, 0x00, 0x00);
+}
+
+int audio_aio_disable(struct q6audio_aio *audio)
+{
+	int rc = 0;
+	if (audio->opened) {
+		audio->enabled = 0;
+		audio->opened = 0;
+		pr_debug("%s[%p]: inbytes[%d] insamples[%d]\n", __func__,
+			audio, atomic_read(&audio->in_bytes),
+			atomic_read(&audio->in_samples));
+		/* Close the session */
+		rc = q6asm_cmd(audio->ac, CMD_CLOSE);
+		if (rc < 0)
+			pr_err("%s[%p]:Failed to close the session rc=%d\n",
+				__func__, audio, rc);
+		audio->stopped = 1;
+		wake_up(&audio->write_wait);
+		wake_up(&audio->cmd_wait);
+	}
+	pr_debug("%s[%p]:enabled[%d]\n", __func__, audio, audio->enabled);
+	return rc;
+}
+
+void audio_aio_reset_ion_region(struct q6audio_aio *audio)
+{
+	struct audio_aio_ion_region *region;
+	struct list_head *ptr, *next;
+
+	list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+		region = list_entry(ptr, struct audio_aio_ion_region, list);
+		list_del(&region->list);
+		ion_unmap_kernel(region->client, region->handle);
+		ion_free(region->client, region->handle);
+		ion_client_destroy(region->client);
+		kfree(region);
+	}
+
+	return;
+}
+
+void audio_aio_reset_event_queue(struct q6audio_aio *audio)
+{
+	unsigned long flags;
+	struct audio_aio_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				   struct audio_aio_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+				   struct audio_aio_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	return;
+}
+
+static void audio_aio_unmap_ion_region(struct q6audio_aio *audio)
+{
+	struct audio_aio_ion_region *region;
+	struct list_head *ptr, *next;
+	int rc = -EINVAL;
+
+	pr_debug("%s[%p]:\n", __func__, audio);
+	list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+		region = list_entry(ptr, struct audio_aio_ion_region, list);
+		pr_debug("%s[%p]: phy_address = 0x%lx\n",
+				__func__, audio, region->paddr);
+		if (region != NULL) {
+			rc = q6asm_memory_unmap(audio->ac,
+						(uint32_t)region->paddr, IN);
+			if (rc < 0)
+				pr_err("%s[%p]: memory unmap failed\n",
+					__func__, audio);
+		}
+	}
+}
+
+int audio_aio_release(struct inode *inode, struct file *file)
+{
+	struct q6audio_aio *audio = file->private_data;
+	pr_debug("%s[%p]\n", __func__, audio);
+	mutex_lock(&audio->lock);
+	audio->wflush = 1;
+	if (audio->enabled)
+		audio_aio_flush(audio);
+	audio->wflush = 0;
+	audio->drv_ops.out_flush(audio);
+	audio->drv_ops.in_flush(audio);
+	audio_aio_unmap_ion_region(audio);
+	audio_aio_disable(audio);
+	audio_aio_reset_ion_region(audio);
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audio_aio_reset_event_queue(audio);
+	q6asm_audio_client_free(audio->ac);
+	mutex_unlock(&audio->lock);
+	mutex_destroy(&audio->lock);
+	mutex_destroy(&audio->read_lock);
+	mutex_destroy(&audio->write_lock);
+	mutex_destroy(&audio->get_event_lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio->codec_cfg);
+	kfree(audio);
+	return 0;
+}
+
+int audio_aio_fsync(struct file *file, loff_t start, loff_t end, int datasync)
+{
+	int rc = 0;
+	struct q6audio_aio *audio = file->private_data;
+
+	if (!audio->enabled || audio->feedback)
+		return -EINVAL;
+
+	/* Blocking client sends more data */
+	mutex_lock(&audio->lock);
+	audio->drv_status |= ADRV_STATUS_FSYNC;
+	mutex_unlock(&audio->lock);
+
+	pr_debug("%s[%p]:\n", __func__, audio);
+
+	mutex_lock(&audio->write_lock);
+	audio->eos_rsp = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+					(list_empty(&audio->out_queue)) ||
+					audio->wflush || audio->stopped);
+
+	if (rc < 0) {
+		pr_err("%s[%p]: wait event for list_empty failed, rc = %d\n",
+			__func__, audio, rc);
+		goto done;
+	}
+
+	rc = q6asm_cmd(audio->ac, CMD_EOS);
+
+	if (rc < 0)
+		pr_err("%s[%p]: q6asm_cmd failed, rc = %d",
+			__func__, audio, rc);
+
+	rc = wait_event_interruptible(audio->write_wait,
+					(audio->eos_rsp || audio->wflush ||
+					audio->stopped));
+
+	if (rc < 0) {
+		pr_err("%s[%p]: wait event for eos_rsp failed, rc = %d\n",
+			__func__, audio, rc);
+		goto done;
+	}
+
+	if (audio->eos_rsp == 1) {
+		rc = audio_aio_enable(audio);
+		if (rc)
+			pr_err("%s[%p]: audio enable failed\n",
+				__func__, audio);
+		else {
+			audio->drv_status &= ~ADRV_STATUS_PAUSE;
+			audio->enabled = 1;
+		}
+	}
+
+	if (audio->stopped || audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+	mutex_lock(&audio->lock);
+	audio->drv_status &= ~ADRV_STATUS_FSYNC;
+	mutex_unlock(&audio->lock);
+
+	return rc;
+}
+
+static int audio_aio_events_pending(struct q6audio_aio *audio)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	return empty || audio->event_abort;
+}
+
+static long audio_aio_process_event_req(struct q6audio_aio *audio,
+					void __user *arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audio_aio_event *drv_evt = NULL;
+	int timeout;
+	unsigned long flags;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int)usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(audio->event_wait,
+						audio_aio_events_pending
+						(audio),
+						msecs_to_jiffies
+						(timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(audio->event_wait,
+		audio_aio_events_pending(audio));
+	}
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	rc = 0;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+		   struct audio_aio_event, list);
+		list_del(&drv_evt->list);
+	}
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else {
+		pr_err("%s[%p]:Unexpected path\n", __func__, audio);
+		spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+		return -EPERM;
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	if (drv_evt->event_type == AUDIO_EVENT_WRITE_DONE) {
+		pr_debug("%s[%p]:posted AUDIO_EVENT_WRITE_DONE to user\n",
+			__func__, audio);
+		mutex_lock(&audio->write_lock);
+		audio_aio_ion_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+		drv_evt->payload.aio_buf.buf_len, 0, 0);
+		mutex_unlock(&audio->write_lock);
+	} else if (drv_evt->event_type == AUDIO_EVENT_READ_DONE) {
+		pr_debug("%s[%p]:posted AUDIO_EVENT_READ_DONE to user\n",
+			__func__, audio);
+		mutex_lock(&audio->read_lock);
+		audio_aio_ion_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+		drv_evt->payload.aio_buf.buf_len, 0, 0);
+		mutex_unlock(&audio->read_lock);
+	}
+
+	/* Some read buffer might be held up in DSP,release all
+	 * Once EOS indicated
+	 */
+	if (audio->eos_rsp && !list_empty(&audio->in_queue)) {
+		pr_debug("%s[%p]:Send flush command to release read buffers"\
+			" held up in DSP\n", __func__, audio);
+		audio_aio_flush(audio);
+	}
+
+	if (copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audio_aio_ion_check(struct q6audio_aio *audio,
+				void *vaddr, unsigned long len)
+{
+	struct audio_aio_ion_region *region_elt;
+	struct audio_aio_ion_region t = {.vaddr = vaddr, .len = len };
+
+	list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
+		if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
+			OVERLAPS(region_elt, &t)) {
+			pr_err("%s[%p]:region (vaddr %p len %ld)"
+				" clashes with registered region"
+				" (vaddr %p paddr %p len %ld)\n",
+				__func__, audio, vaddr, len,
+				region_elt->vaddr,
+				(void *)region_elt->paddr, region_elt->len);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int audio_aio_ion_add(struct q6audio_aio *audio,
+				struct msm_audio_ion_info *info)
+{
+	ion_phys_addr_t paddr;
+	size_t len;
+	unsigned long kvaddr;
+	struct audio_aio_ion_region *region;
+	int rc = -EINVAL;
+	struct ion_handle *handle;
+	struct ion_client *client;
+	unsigned long ionflag;
+	void *temp_ptr;
+
+	pr_debug("%s[%p]:\n", __func__, audio);
+	region = kmalloc(sizeof(*region), GFP_KERNEL);
+
+	if (!region) {
+		rc = -ENOMEM;
+		goto end;
+	}
+
+	client = msm_ion_client_create(UINT_MAX, "Audio_Dec_Client");
+	if (IS_ERR_OR_NULL(client)) {
+		pr_err("Unable to create ION client\n");
+		goto client_error;
+	}
+
+	handle = ion_import_fd(client, info->fd);
+	if (IS_ERR_OR_NULL(handle)) {
+		pr_err("%s: could not get handle of the given fd\n", __func__);
+		goto import_error;
+	}
+
+	rc = ion_handle_get_flags(client, handle, &ionflag);
+	if (rc) {
+		pr_err("%s: could not get flags for the handle\n", __func__);
+		goto flag_error;
+	}
+
+	temp_ptr = ion_map_kernel(client, handle, ionflag);
+	if (IS_ERR_OR_NULL(temp_ptr)) {
+		pr_err("%s: could not get virtual address\n", __func__);
+		goto map_error;
+	}
+	kvaddr = (unsigned long)temp_ptr;
+
+	rc = ion_phys(client, handle, &paddr, &len);
+	if (rc) {
+		pr_err("%s: could not get physical address\n", __func__);
+		goto ion_error;
+	}
+
+	rc = audio_aio_ion_check(audio, info->vaddr, len);
+	if (rc < 0) {
+		pr_err("%s: audio_aio_ion_check failed\n", __func__);
+		goto ion_error;
+	}
+
+	region->client = client;
+	region->handle = handle;
+	region->vaddr = info->vaddr;
+	region->fd = info->fd;
+	region->paddr = paddr;
+	region->kvaddr = kvaddr;
+	region->len = len;
+	region->ref_cnt = 0;
+	pr_debug("%s[%p]:add region paddr %lx vaddr %p, len %lu kvaddr %lx\n",
+		__func__, audio,
+		region->paddr, region->vaddr, region->len, region->kvaddr);
+	list_add_tail(&region->list, &audio->ion_region_queue);
+	rc = q6asm_memory_map(audio->ac, (uint32_t) paddr, IN, (uint32_t) len,
+				1);
+	if (rc < 0) {
+		pr_err("%s[%p]: memory map failed\n", __func__, audio);
+		goto ion_error;
+	} else {
+		goto end;
+	}
+
+ion_error:
+	ion_unmap_kernel(client, handle);
+map_error:
+	ion_free(client, handle);
+flag_error:
+import_error:
+	ion_client_destroy(client);
+client_error:
+	kfree(region);
+end:
+	return rc;
+}
+
+static int audio_aio_ion_remove(struct q6audio_aio *audio,
+				struct msm_audio_ion_info *info)
+{
+	struct audio_aio_ion_region *region;
+	struct list_head *ptr, *next;
+	int rc = -EINVAL;
+
+	pr_debug("%s[%p]:info fd %d vaddr %p\n",
+		__func__, audio, info->fd, info->vaddr);
+
+	list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+		region = list_entry(ptr, struct audio_aio_ion_region, list);
+
+		if ((region->fd == info->fd) &&
+			(region->vaddr == info->vaddr)) {
+			if (region->ref_cnt) {
+				pr_debug("%s[%p]:region %p in use ref_cnt %d\n",
+					__func__, audio, region,
+					region->ref_cnt);
+				break;
+			}
+			pr_debug("%s[%p]:remove region fd %d vaddr %p\n",
+				__func__, audio, info->fd, info->vaddr);
+			rc = q6asm_memory_unmap(audio->ac,
+						(uint32_t) region->paddr, IN);
+			if (rc < 0)
+				pr_err("%s[%p]: memory unmap failed\n",
+					__func__, audio);
+
+			list_del(&region->list);
+			ion_unmap_kernel(region->client, region->handle);
+			ion_free(region->client, region->handle);
+			ion_client_destroy(region->client);
+			kfree(region);
+			rc = 0;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static void audio_aio_async_write(struct q6audio_aio *audio,
+				struct audio_aio_buffer_node *buf_node)
+{
+	int rc;
+	struct audio_client *ac;
+	struct audio_aio_write_param param;
+
+	pr_debug("%s[%p]: Send write buff %p phy %lx len %d"
+		"meta_enable = %d\n",
+		__func__, audio, buf_node, buf_node->paddr,
+		buf_node->buf.data_len,
+		audio->buf_cfg.meta_info_enable);
+
+	ac = audio->ac;
+	/* Offset with  appropriate meta */
+	if (audio->feedback) {
+		/* Non Tunnel mode */
+		param.paddr = buf_node->paddr + sizeof(struct dec_meta_in);
+		param.len = buf_node->buf.data_len - sizeof(struct dec_meta_in);
+	} else {
+		/* Tunnel mode */
+		param.paddr = buf_node->paddr;
+		param.len = buf_node->buf.data_len;
+	}
+	param.msw_ts = buf_node->meta_info.meta_in.ntimestamp.highpart;
+	param.lsw_ts = buf_node->meta_info.meta_in.ntimestamp.lowpart;
+	/* If no meta_info enaled, indicate no time stamp valid */
+	if (audio->buf_cfg.meta_info_enable)
+		param.flags = 0;
+	else
+		param.flags = 0xFF00;
+	param.uid = param.paddr;
+	/* Read command will populate paddr as token */
+	buf_node->token = param.paddr;
+	rc = q6asm_async_write(ac, &param);
+	if (rc < 0)
+		pr_err("%s[%p]:failed\n", __func__, audio);
+}
+
+void audio_aio_post_event(struct q6audio_aio *audio, int type,
+			union msm_audio_event_payload payload)
+{
+	struct audio_aio_event *e_node = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+					struct audio_aio_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audio_aio_event), GFP_ATOMIC);
+		if (!e_node) {
+			pr_err("%s[%p]:No mem to post event %d\n",
+				__func__, audio, type);
+			spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	wake_up(&audio->event_wait);
+}
+
+static void audio_aio_async_read(struct q6audio_aio *audio,
+				struct audio_aio_buffer_node *buf_node)
+{
+	struct audio_client *ac;
+	struct audio_aio_read_param param;
+	int rc;
+
+	pr_debug("%s[%p]: Send read buff %p phy %lx len %d\n",
+		__func__, audio, buf_node,
+		buf_node->paddr, buf_node->buf.buf_len);
+	ac = audio->ac;
+	/* Provide address so driver can append nr frames information */
+	param.paddr = buf_node->paddr +
+		sizeof(struct dec_meta_out);
+	param.len = buf_node->buf.buf_len -
+		sizeof(struct dec_meta_out);
+	param.uid = param.paddr;
+	/* Write command will populate paddr as token */
+	buf_node->token = param.paddr;
+	rc = q6asm_async_read(ac, &param);
+	if (rc < 0)
+		pr_err("%s[%p]:failed\n", __func__, audio);
+}
+
+static int audio_aio_buf_add(struct q6audio_aio *audio, unsigned dir,
+				void __user *arg)
+{
+	unsigned long flags;
+	struct audio_aio_buffer_node *buf_node;
+
+
+	buf_node = kzalloc(sizeof(*buf_node), GFP_KERNEL);
+
+	if (!buf_node)
+		return -ENOMEM;
+
+	if (copy_from_user(&buf_node->buf, arg, sizeof(buf_node->buf))) {
+		kfree(buf_node);
+		return -EFAULT;
+	}
+
+	pr_debug("%s[%p]:node %p dir %x buf_addr %p buf_len %d data_len"
+		"%d\n", __func__, audio, buf_node, dir, buf_node->buf.buf_addr,
+		buf_node->buf.buf_len, buf_node->buf.data_len);
+	buf_node->paddr = audio_aio_ion_fixup(audio, buf_node->buf.buf_addr,
+						buf_node->buf.buf_len, 1,
+						&buf_node->kvaddr);
+	if (dir) {
+		/* write */
+		if (!buf_node->paddr ||
+			(buf_node->paddr & 0x1) ||
+			(!audio->feedback && !buf_node->buf.data_len)) {
+			kfree(buf_node);
+			return -EINVAL;
+		}
+		extract_meta_out_info(audio, buf_node, 1);
+		/* Not a EOS buffer */
+		if (!(buf_node->meta_info.meta_in.nflags & AUDIO_DEC_EOS_SET)) {
+			spin_lock_irqsave(&audio->dsp_lock, flags);
+			audio_aio_async_write(audio, buf_node);
+			/* EOS buffer handled in driver */
+			list_add_tail(&buf_node->list, &audio->out_queue);
+			spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		} else if (buf_node->meta_info.meta_in.nflags
+				   & AUDIO_DEC_EOS_SET) {
+			if (!audio->wflush) {
+				pr_debug("%s[%p]:Send EOS cmd at i/p\n",
+					__func__, audio);
+				/* Driver will forcefully post writedone event
+				 * once eos ack recived from DSP
+				 */
+				audio->eos_write_payload.aio_buf =\
+						buf_node->buf;
+				audio->eos_flag = 1;
+				audio->eos_rsp = 0;
+				q6asm_cmd(audio->ac, CMD_EOS);
+				kfree(buf_node);
+			} else { /* Flush in progress, send back i/p
+				  * EOS buffer as is
+				  */
+				union msm_audio_event_payload event_payload;
+				event_payload.aio_buf = buf_node->buf;
+				audio_aio_post_event(audio,
+						AUDIO_EVENT_WRITE_DONE,
+						event_payload);
+				kfree(buf_node);
+			}
+		}
+	} else {
+		/* read */
+		if (!buf_node->paddr ||
+			(buf_node->paddr & 0x1) ||
+			(buf_node->buf.buf_len < PCM_BUFSZ_MIN)) {
+			kfree(buf_node);
+			return -EINVAL;
+		}
+		/* No EOS reached */
+		if (!audio->eos_rsp) {
+			spin_lock_irqsave(&audio->dsp_lock, flags);
+			audio_aio_async_read(audio, buf_node);
+			/* EOS buffer handled in driver */
+			list_add_tail(&buf_node->list, &audio->in_queue);
+			spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		}
+		/* EOS reached at input side fake all upcoming read buffer to
+		 * indicate the same
+		 */
+		else {
+			union msm_audio_event_payload event_payload;
+			event_payload.aio_buf = buf_node->buf;
+			event_payload.aio_buf.data_len =
+				insert_eos_buf(audio, buf_node);
+			pr_debug("%s[%p]: propagate READ_DONE as EOS done\n",\
+				__func__, audio);
+			audio_aio_post_event(audio, AUDIO_EVENT_READ_DONE,
+					event_payload);
+			kfree(buf_node);
+		}
+	}
+	return 0;
+}
+
+static void audio_aio_ioport_reset(struct q6audio_aio *audio)
+{
+	if (audio->drv_status & ADRV_STATUS_AIO_INTF) {
+		/* If fsync is in progress, make sure
+		 * return value of fsync indicates
+		 * abort due to flush
+		 */
+		if (audio->drv_status & ADRV_STATUS_FSYNC) {
+			pr_debug("%s[%p]:fsync in progress\n", __func__, audio);
+			audio->drv_ops.out_flush(audio);
+		} else
+			audio->drv_ops.out_flush(audio);
+		audio->drv_ops.in_flush(audio);
+	}
+}
+
+int audio_aio_open(struct q6audio_aio *audio, struct file *file)
+{
+	int rc = 0;
+	int i;
+	struct audio_aio_event *e_node = NULL;
+
+	/* Settings will be re-config at AUDIO_SET_CONFIG,
+	 * but at least we need to have initial config
+	 */
+	audio->str_cfg.buffer_size = FRAME_SIZE;
+	audio->str_cfg.buffer_count = FRAME_NUM;
+	audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
+	audio->pcm_cfg.sample_rate = 48000;
+	audio->pcm_cfg.channel_count = 2;
+
+	/* Only AIO interface */
+	if (file->f_flags & O_NONBLOCK) {
+		pr_debug("%s[%p]:set to aio interface\n", __func__, audio);
+		audio->drv_status |= ADRV_STATUS_AIO_INTF;
+		audio->drv_ops.out_flush = audio_aio_async_out_flush;
+		audio->drv_ops.in_flush = audio_aio_async_in_flush;
+		q6asm_set_io_mode(audio->ac, ASYNC_IO_MODE);
+	} else {
+		pr_err("%s[%p]:SIO interface not supported\n",
+			__func__, audio);
+		rc = -EACCES;
+		goto fail;
+	}
+
+	/* Initialize all locks of audio instance */
+	mutex_init(&audio->lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->get_event_lock);
+	spin_lock_init(&audio->dsp_lock);
+	spin_lock_init(&audio->event_queue_lock);
+	init_waitqueue_head(&audio->cmd_wait);
+	init_waitqueue_head(&audio->write_wait);
+	init_waitqueue_head(&audio->event_wait);
+	INIT_LIST_HEAD(&audio->out_queue);
+	INIT_LIST_HEAD(&audio->in_queue);
+	INIT_LIST_HEAD(&audio->ion_region_queue);
+	INIT_LIST_HEAD(&audio->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+
+	audio->drv_ops.out_flush(audio);
+	audio->opened = 1;
+	file->private_data = audio;
+	audio->codec_ioctl = audio_aio_ioctl;
+
+	for (i = 0; i < AUDIO_EVENT_NUM; i++) {
+		e_node = kmalloc(sizeof(struct audio_aio_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			pr_err("%s[%p]:event pkt alloc failed\n",
+				__func__, audio);
+			break;
+		}
+	}
+	return 0;
+fail:
+	q6asm_audio_client_free(audio->ac);
+	kfree(audio->codec_cfg);
+	kfree(audio);
+	return rc;
+}
+
+long audio_aio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct q6audio_aio *audio = file->private_data;
+	int rc = 0;
+
+	switch (cmd) {
+	case AUDIO_GET_STATS: {
+		struct msm_audio_stats stats;
+		stats.byte_count = atomic_read(&audio->in_bytes);
+		stats.sample_count = atomic_read(&audio->in_samples);
+		if (copy_to_user((void *)arg, &stats, sizeof(stats)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_GET_EVENT: {
+		pr_debug("%s[%p]:AUDIO_GET_EVENT\n", __func__, audio);
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audio_aio_process_event_req(audio,
+						(void __user *)arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		break;
+	}
+	case AUDIO_ABORT_GET_EVENT: {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		break;
+	}
+	case AUDIO_ASYNC_WRITE: {
+		mutex_lock(&audio->write_lock);
+		if (audio->drv_status & ADRV_STATUS_FSYNC)
+			rc = -EBUSY;
+		else {
+			if (audio->enabled)
+				rc = audio_aio_buf_add(audio, 1,
+						(void __user *)arg);
+			else
+				rc = -EPERM;
+		}
+		mutex_unlock(&audio->write_lock);
+		break;
+	}
+	case AUDIO_ASYNC_READ: {
+		mutex_lock(&audio->read_lock);
+		if ((audio->feedback) && (audio->enabled))
+			rc = audio_aio_buf_add(audio, 0,
+					(void __user *)arg);
+		else
+			rc = -EPERM;
+		mutex_unlock(&audio->read_lock);
+		break;
+	}
+	case AUDIO_OUTPORT_FLUSH: {
+		pr_debug("%s[%p]:AUDIO_OUTPORT_FLUSH\n", __func__, audio);
+		mutex_lock(&audio->read_lock);
+		rc = audio_aio_outport_flush(audio);
+		if (rc < 0) {
+			pr_err("%s[%p]: AUDIO_OUTPORT_FLUSH failed\n",
+				__func__, audio);
+			rc = -EINTR;
+		}
+		mutex_unlock(&audio->read_lock);
+		break;
+	}
+	case AUDIO_STOP: {
+		pr_debug("%s[%p]: AUDIO_STOP session_id[%d]\n", __func__,
+				audio, audio->ac->session);
+		mutex_lock(&audio->lock);
+		audio->stopped = 1;
+		audio_aio_flush(audio);
+		audio->enabled = 0;
+		audio->drv_status &= ~ADRV_STATUS_PAUSE;
+		if (rc < 0) {
+			pr_err("%s[%p]:Audio Stop procedure failed rc=%d\n",
+				__func__, audio, rc);
+			mutex_unlock(&audio->lock);
+			break;
+		}
+		mutex_unlock(&audio->lock);
+		break;
+	}
+	case AUDIO_PAUSE: {
+		pr_debug("%s[%p]:AUDIO_PAUSE %ld\n", __func__, audio, arg);
+		mutex_lock(&audio->lock);
+		if (arg == 1) {
+			rc = audio_aio_pause(audio);
+			if (rc < 0)
+				pr_err("%s[%p]: pause FAILED rc=%d\n",
+					__func__, audio, rc);
+			audio->drv_status |= ADRV_STATUS_PAUSE;
+		} else if (arg == 0) {
+			if (audio->drv_status & ADRV_STATUS_PAUSE) {
+				rc = audio_aio_enable(audio);
+				if (rc)
+					pr_err("%s[%p]: audio enable failed\n",
+					__func__, audio);
+				else {
+					audio->drv_status &= ~ADRV_STATUS_PAUSE;
+					audio->enabled = 1;
+				}
+			}
+		}
+		mutex_unlock(&audio->lock);
+		break;
+	}
+	case AUDIO_FLUSH: {
+		pr_debug("%s[%p]: AUDIO_FLUSH sessionid[%d]\n", __func__,
+			audio, audio->ac->session);
+		mutex_lock(&audio->lock);
+		audio->rflush = 1;
+		audio->wflush = 1;
+		/* Flush DSP */
+		rc = audio_aio_flush(audio);
+		/* Flush input / Output buffer in software*/
+		audio_aio_ioport_reset(audio);
+		if (rc < 0) {
+			pr_err("%s[%p]:AUDIO_FLUSH interrupted\n",
+				__func__, audio);
+			rc = -EINTR;
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		audio->eos_flag = 0;
+		audio->eos_rsp = 0;
+		mutex_unlock(&audio->lock);
+		break;
+	}
+	case AUDIO_REGISTER_ION: {
+		struct msm_audio_ion_info info;
+		pr_debug("%s[%p]:AUDIO_REGISTER_ION\n", __func__, audio);
+		mutex_lock(&audio->lock);
+		if (copy_from_user(&info, (void *)arg, sizeof(info)))
+			rc = -EFAULT;
+		else
+			rc = audio_aio_ion_add(audio, &info);
+		mutex_unlock(&audio->lock);
+		break;
+	}
+	case AUDIO_DEREGISTER_ION: {
+		struct msm_audio_ion_info info;
+		mutex_lock(&audio->lock);
+		pr_debug("%s[%p]:AUDIO_DEREGISTER_ION\n", __func__, audio);
+		if (copy_from_user(&info, (void *)arg, sizeof(info)))
+			rc = -EFAULT;
+		else
+			rc = audio_aio_ion_remove(audio, &info);
+		mutex_unlock(&audio->lock);
+		break;
+	}
+	case AUDIO_GET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		mutex_lock(&audio->lock);
+		memset(&cfg, 0, sizeof(cfg));
+		cfg.buffer_size = audio->str_cfg.buffer_size;
+		cfg.buffer_count = audio->str_cfg.buffer_count;
+		pr_debug("%s[%p]:GET STREAM CFG %d %d\n",
+			__func__, audio, cfg.buffer_size, cfg.buffer_count);
+		if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		mutex_unlock(&audio->lock);
+		break;
+	}
+	case AUDIO_SET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		pr_debug("%s[%p]:SET STREAM CONFIG\n", __func__, audio);
+		mutex_lock(&audio->lock);
+		if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			mutex_unlock(&audio->lock);
+			break;
+		}
+		audio->str_cfg.buffer_size = FRAME_SIZE;
+		audio->str_cfg.buffer_count = FRAME_NUM;
+		rc = 0;
+		mutex_unlock(&audio->lock);
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config cfg;
+		mutex_lock(&audio->lock);
+		if (copy_to_user((void *)arg, &audio->pcm_cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		mutex_unlock(&audio->lock);
+		break;
+	}
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		pr_err("%s[%p]:AUDIO_SET_CONFIG\n", __func__, audio);
+		mutex_lock(&audio->lock);
+		if (copy_from_user(&config, (void *)arg, sizeof(config))) {
+			rc = -EFAULT;
+			mutex_unlock(&audio->lock);
+			break;
+		}
+		if (audio->feedback != NON_TUNNEL_MODE) {
+			pr_err("%s[%p]:Not sufficient permission to"
+				"change the playback mode\n", __func__, audio);
+			rc = -EACCES;
+			mutex_unlock(&audio->lock);
+			break;
+		}
+		if ((config.buffer_count > PCM_BUF_COUNT) ||
+			(config.buffer_count == 1))
+			config.buffer_count = PCM_BUF_COUNT;
+
+		if (config.buffer_size < PCM_BUFSZ_MIN)
+			config.buffer_size = PCM_BUFSZ_MIN;
+
+		audio->pcm_cfg.buffer_count = config.buffer_count;
+		audio->pcm_cfg.buffer_size = config.buffer_size;
+		audio->pcm_cfg.channel_count = config.channel_count;
+		audio->pcm_cfg.sample_rate = config.sample_rate;
+		rc = 0;
+		mutex_unlock(&audio->lock);
+		break;
+	}
+	case AUDIO_SET_BUF_CFG: {
+		struct msm_audio_buf_cfg  cfg;
+		mutex_lock(&audio->lock);
+		if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			mutex_unlock(&audio->lock);
+			break;
+		}
+		if ((audio->feedback == NON_TUNNEL_MODE) &&
+			!cfg.meta_info_enable) {
+			rc = -EFAULT;
+			mutex_unlock(&audio->lock);
+			break;
+		}
+
+		audio->buf_cfg.meta_info_enable = cfg.meta_info_enable;
+		pr_debug("%s[%p]:session id %d: Set-buf-cfg: meta[%d]",
+				__func__, audio,
+				audio->ac->session, cfg.meta_info_enable);
+		mutex_unlock(&audio->lock);
+		break;
+	}
+	case AUDIO_GET_BUF_CFG: {
+		pr_debug("%s[%p]:session id %d: Get-buf-cfg: meta[%d]"
+			"framesperbuf[%d]\n", __func__, audio,
+			audio->ac->session, audio->buf_cfg.meta_info_enable,
+			audio->buf_cfg.frames_per_buf);
+
+		mutex_lock(&audio->lock);
+		if (copy_to_user((void *)arg, &audio->buf_cfg,
+			sizeof(struct msm_audio_buf_cfg)))
+			rc = -EFAULT;
+		mutex_unlock(&audio->lock);
+		break;
+	}
+	case AUDIO_GET_SESSION_ID: {
+		mutex_lock(&audio->lock);
+		if (copy_to_user((void *)arg, &audio->ac->session,
+			sizeof(unsigned short))) {
+			rc = -EFAULT;
+		}
+		mutex_unlock(&audio->lock);
+		break;
+	}
+	default:
+		rc =  -EINVAL;
+	}
+	return rc;
+}
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
new file mode 100644
index 0000000..77288da
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
@@ -0,0 +1,211 @@
+/* Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2009-2012, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/msm_audio.h>
+#include <linux/debugfs.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/ion.h>
+#include <asm/ioctls.h>
+#include <asm/atomic.h>
+#include "q6audio_common.h"
+
+#define TUNNEL_MODE     0x0000
+#define NON_TUNNEL_MODE 0x0001
+
+#define ADRV_STATUS_AIO_INTF 0x00000001 /* AIO interface */
+#define ADRV_STATUS_FSYNC 0x00000008
+#define ADRV_STATUS_PAUSE 0x00000010
+#define AUDIO_DEC_EOS_SET  0x00000001
+#define AUDIO_EVENT_NUM		10
+
+#define __CONTAINS(r, v, l) ({                                  \
+	typeof(r) __r = r;                                      \
+	typeof(v) __v = v;                                      \
+	typeof(v) __e = __v + l;                                \
+	int res = ((__v >= __r->vaddr) &&                       \
+		(__e <= __r->vaddr + __r->len));                \
+	res;                                                    \
+})
+
+#define CONTAINS(r1, r2) ({                                     \
+	typeof(r2) __r2 = r2;                                   \
+	__CONTAINS(r1, __r2->vaddr, __r2->len);                 \
+})
+
+#define IN_RANGE(r, v) ({                                       \
+	typeof(r) __r = r;                                      \
+	typeof(v) __vv = v;                                     \
+	int res = ((__vv >= __r->vaddr) &&                      \
+		(__vv < (__r->vaddr + __r->len)));              \
+	res;                                                    \
+})
+
+#define OVERLAPS(r1, r2) ({                                     \
+	typeof(r1) __r1 = r1;                                   \
+	typeof(r2) __r2 = r2;                                   \
+	typeof(__r2->vaddr) __v = __r2->vaddr;                  \
+	typeof(__v) __e = __v + __r2->len - 1;                  \
+	int res = (IN_RANGE(__r1, __v) || IN_RANGE(__r1, __e)); \
+	res;                                                    \
+})
+
+struct timestamp {
+	unsigned long lowpart;
+	unsigned long highpart;
+} __packed;
+
+struct meta_out_dsp {
+	u32 offset_to_frame;
+	u32 frame_size;
+	u32 encoded_pcm_samples;
+	u32 msw_ts;
+	u32 lsw_ts;
+	u32 nflags;
+} __packed;
+
+struct dec_meta_in {
+	unsigned char reserved[18];
+	unsigned short offset;
+	struct timestamp ntimestamp;
+	unsigned int nflags;
+} __packed;
+
+struct dec_meta_out {
+	unsigned int reserved[7];
+	unsigned int num_of_frames;
+	struct meta_out_dsp meta_out_dsp[];
+} __packed;
+
+/* General meta field to store meta info
+locally */
+union  meta_data {
+	struct dec_meta_out meta_out;
+	struct dec_meta_in meta_in;
+} __packed;
+
+#define PCM_BUF_COUNT           (2)
+/* Buffer with meta */
+#define PCM_BUFSZ_MIN           ((4*1024) + sizeof(struct dec_meta_out))
+
+/* FRAME_NUM must be a power of two */
+#define FRAME_NUM               (2)
+#define FRAME_SIZE	((4*1536) + sizeof(struct dec_meta_in))
+
+struct audio_aio_ion_region {
+	struct list_head list;
+	struct ion_handle *handle;
+	struct ion_client *client;
+	int fd;
+	void *vaddr;
+	unsigned long paddr;
+	unsigned long kvaddr;
+	unsigned long len;
+	unsigned ref_cnt;
+};
+
+struct audio_aio_event {
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+
+struct audio_aio_buffer_node {
+	struct list_head list;
+	struct msm_audio_aio_buf buf;
+	unsigned long paddr;
+	unsigned long token;
+	void            *kvaddr;
+	union meta_data meta_info;
+};
+
+struct q6audio_aio;
+struct audio_aio_drv_operations {
+	void (*out_flush) (struct q6audio_aio *);
+	void (*in_flush) (struct q6audio_aio *);
+};
+
+struct q6audio_aio {
+	atomic_t in_bytes;
+	atomic_t in_samples;
+
+	struct msm_audio_stream_config str_cfg;
+	struct msm_audio_buf_cfg        buf_cfg;
+	struct msm_audio_config pcm_cfg;
+	void *codec_cfg;
+
+	struct audio_client *ac;
+
+	struct mutex lock;
+	struct mutex read_lock;
+	struct mutex write_lock;
+	struct mutex get_event_lock;
+	wait_queue_head_t cmd_wait;
+	wait_queue_head_t write_wait;
+	wait_queue_head_t event_wait;
+	spinlock_t dsp_lock;
+	spinlock_t event_queue_lock;
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+	struct list_head out_queue;     /* queue to retain output buffers */
+	struct list_head in_queue;      /* queue to retain input buffers */
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	struct list_head ion_region_queue;     /* protected by lock */
+	struct audio_aio_drv_operations drv_ops;
+	union msm_audio_event_payload eos_write_payload;
+
+	uint32_t drv_status;
+	int event_abort;
+	int eos_rsp;
+	int eos_flag;
+	int opened;
+	int enabled;
+	int stopped;
+	int feedback;
+	int rflush;             /* Read  flush */
+	int wflush;             /* Write flush */
+	long (*codec_ioctl)(struct file *, unsigned int, unsigned long);
+};
+
+void audio_aio_async_write_ack(struct q6audio_aio *audio, uint32_t token,
+				uint32_t *payload);
+
+void audio_aio_async_read_ack(struct q6audio_aio *audio, uint32_t token,
+			uint32_t *payload);
+
+int audio_aio_open(struct q6audio_aio *audio, struct file *file);
+int audio_aio_enable(struct q6audio_aio  *audio);
+void audio_aio_post_event(struct q6audio_aio *audio, int type,
+		union msm_audio_event_payload payload);
+int audio_aio_release(struct inode *inode, struct file *file);
+long audio_aio_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+int audio_aio_fsync(struct file *file, loff_t start, loff_t end, int datasync);
+void audio_aio_async_out_flush(struct q6audio_aio *audio);
+void audio_aio_async_in_flush(struct q6audio_aio *audio);
+#ifdef CONFIG_DEBUG_FS
+ssize_t audio_aio_debug_open(struct inode *inode, struct file *file);
+ssize_t audio_aio_debug_read(struct file *file, char __user * buf,
+			size_t count, loff_t *ppos);
+#endif
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_wma.c b/arch/arm/mach-msm/qdsp6v2/audio_wma.c
new file mode 100644
index 0000000..021d58b
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_wma.c
@@ -0,0 +1,210 @@
+/* wma audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2009-2012, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/msm_audio_wma.h>
+#include "audio_utils_aio.h"
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations audio_wma_debug_fops = {
+	.read = audio_aio_debug_read,
+	.open = audio_aio_debug_open,
+};
+#endif
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct q6audio_aio *audio = file->private_data;
+	int rc = 0;
+
+	switch (cmd) {
+	case AUDIO_START: {
+		struct asm_wma_cfg wma_cfg;
+		struct msm_audio_wma_config_v2 *wma_config;
+		pr_debug("%s[%p]: AUDIO_START session_id[%d]\n", __func__,
+						audio, audio->ac->session);
+		if (audio->feedback == NON_TUNNEL_MODE) {
+			/* Configure PCM output block */
+			rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+					audio->pcm_cfg.sample_rate,
+					audio->pcm_cfg.channel_count);
+			if (rc < 0) {
+				pr_err("pcm output block config failed\n");
+				break;
+			}
+		}
+		wma_config = (struct msm_audio_wma_config_v2 *)audio->codec_cfg;
+		wma_cfg.format_tag = wma_config->format_tag;
+		wma_cfg.ch_cfg = wma_config->numchannels;
+		wma_cfg.sample_rate =  wma_config->samplingrate;
+		wma_cfg.avg_bytes_per_sec = wma_config->avgbytespersecond;
+		wma_cfg.block_align = wma_config->block_align;
+		wma_cfg.valid_bits_per_sample =
+				wma_config->validbitspersample;
+		wma_cfg.ch_mask =  wma_config->channelmask;
+		wma_cfg.encode_opt = wma_config->encodeopt;
+		/* Configure Media format block */
+		rc = q6asm_media_format_block_wma(audio->ac, &wma_cfg);
+		if (rc < 0) {
+			pr_err("cmd media format block failed\n");
+			break;
+		}
+		rc = audio_aio_enable(audio);
+		audio->eos_rsp = 0;
+		audio->eos_flag = 0;
+		if (!rc) {
+			audio->enabled = 1;
+		} else {
+			audio->enabled = 0;
+			pr_err("Audio Start procedure failed rc=%d\n", rc);
+			break;
+		}
+		pr_debug("AUDIO_START success enable[%d]\n", audio->enabled);
+		if (audio->stopped == 1)
+			audio->stopped = 0;
+		break;
+	}
+	case AUDIO_GET_WMA_CONFIG_V2: {
+		if (copy_to_user((void *)arg, audio->codec_cfg,
+			sizeof(struct msm_audio_wma_config_v2))) {
+			rc = -EFAULT;
+			break;
+		}
+		break;
+	}
+	case AUDIO_SET_WMA_CONFIG_V2: {
+		if (copy_from_user(audio->codec_cfg, (void *)arg,
+			sizeof(struct msm_audio_wma_config_v2))) {
+			rc = -EFAULT;
+			break;
+		}
+		break;
+	}
+	default:
+		pr_debug("%s[%p]: Calling utils ioctl\n", __func__, audio);
+		rc = audio->codec_ioctl(file, cmd, arg);
+		if (rc)
+			pr_err("Failed in utils_ioctl: %d\n", rc);
+	}
+	return rc;
+}
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct q6audio_aio *audio = NULL;
+	int rc = 0;
+
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_wma_" + 5];
+#endif
+	audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+	if (audio == NULL) {
+		pr_err("Could not allocate memory for wma decode driver\n");
+		return -ENOMEM;
+	}
+	audio->codec_cfg = kzalloc(sizeof(struct msm_audio_wma_config_v2),
+					GFP_KERNEL);
+	if (audio->codec_cfg == NULL) {
+		pr_err("%s:Could not allocate memory for wma"
+			"config\n", __func__);
+		kfree(audio);
+		return -ENOMEM;
+	}
+
+	audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+
+	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
+					     (void *)audio);
+
+	if (!audio->ac) {
+		pr_err("Could not allocate memory for audio client\n");
+		kfree(audio->codec_cfg);
+		kfree(audio);
+		return -ENOMEM;
+	}
+	/* open in T/NT mode */
+	if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+		rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+					   FORMAT_WMA_V9);
+		if (rc < 0) {
+			pr_err("NT mode Open failed rc=%d\n", rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->feedback = NON_TUNNEL_MODE;
+		/* open WMA decoder, expected frames is always 1*/
+		audio->buf_cfg.frames_per_buf = 0x01;
+		audio->buf_cfg.meta_info_enable = 0x01;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+		rc = q6asm_open_write(audio->ac, FORMAT_WMA_V9);
+		if (rc < 0) {
+			pr_err("T mode Open failed rc=%d\n", rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->feedback = TUNNEL_MODE;
+		audio->buf_cfg.meta_info_enable = 0x00;
+	} else {
+		pr_err("Not supported mode\n");
+		rc = -EACCES;
+		goto fail;
+	}
+	rc = audio_aio_open(audio, file);
+
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_wma_%04x", audio->ac->session);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+					    NULL, (void *)audio,
+					    &audio_wma_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		pr_debug("debugfs_create_file failed\n");
+#endif
+	pr_info("%s:wmadec success mode[%d]session[%d]\n", __func__,
+						audio->feedback,
+						audio->ac->session);
+	return rc;
+fail:
+	q6asm_audio_client_free(audio->ac);
+	kfree(audio->codec_cfg);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_wma_fops = {
+	.owner = THIS_MODULE,
+	.open = audio_open,
+	.release = audio_aio_release,
+	.unlocked_ioctl = audio_ioctl,
+	.fsync = audio_aio_fsync,
+};
+
+struct miscdevice audio_wma_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_wma",
+	.fops = &audio_wma_fops,
+};
+
+static int __init audio_wma_init(void)
+{
+	return misc_register(&audio_wma_misc);
+}
+
+device_initcall(audio_wma_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_wmapro.c b/arch/arm/mach-msm/qdsp6v2/audio_wmapro.c
new file mode 100644
index 0000000..4fcdcc1
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_wmapro.c
@@ -0,0 +1,269 @@
+/* wmapro audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2009-2012, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/msm_audio_wmapro.h>
+#include "audio_utils_aio.h"
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations audio_wmapro_debug_fops = {
+	.read = audio_aio_debug_read,
+	.open = audio_aio_debug_open,
+};
+#endif
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct q6audio_aio *audio = file->private_data;
+	int rc = 0;
+
+	switch (cmd) {
+	case AUDIO_START: {
+		struct asm_wmapro_cfg wmapro_cfg;
+		struct msm_audio_wmapro_config *wmapro_config;
+		pr_debug("%s: AUDIO_START session_id[%d]\n", __func__,
+						audio->ac->session);
+		if (audio->feedback == NON_TUNNEL_MODE) {
+			/* Configure PCM output block */
+			rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+					audio->pcm_cfg.sample_rate,
+					audio->pcm_cfg.channel_count);
+			if (rc < 0) {
+				pr_err("pcm output block config failed\n");
+				break;
+			}
+		}
+		wmapro_config = (struct msm_audio_wmapro_config *)
+				audio->codec_cfg;
+		if ((wmapro_config->formattag == 0x162) ||
+		(wmapro_config->formattag == 0x163) ||
+		(wmapro_config->formattag == 0x166) ||
+		(wmapro_config->formattag == 0x167)) {
+			wmapro_cfg.format_tag = wmapro_config->formattag;
+		} else {
+			pr_err("%s:AUDIO_START failed: formattag = %d\n",
+				__func__, wmapro_config->formattag);
+			rc = -EINVAL;
+			break;
+		}
+		if ((wmapro_config->numchannels == 1) ||
+		(wmapro_config->numchannels == 2)) {
+			wmapro_cfg.ch_cfg = wmapro_config->numchannels;
+		} else {
+			pr_err("%s:AUDIO_START failed: channels = %d\n",
+				__func__, wmapro_config->numchannels);
+			rc = -EINVAL;
+			break;
+		}
+		if ((wmapro_config->samplingrate <= 48000) ||
+		(wmapro_config->samplingrate > 0)) {
+			wmapro_cfg.sample_rate =
+				wmapro_config->samplingrate;
+		} else {
+			pr_err("%s:AUDIO_START failed: sample_rate = %d\n",
+				__func__, wmapro_config->samplingrate);
+			rc = -EINVAL;
+			break;
+		}
+		wmapro_cfg.avg_bytes_per_sec =
+				wmapro_config->avgbytespersecond;
+		if ((wmapro_config->asfpacketlength <= 13376) ||
+		(wmapro_config->asfpacketlength > 0)) {
+			wmapro_cfg.block_align =
+				wmapro_config->asfpacketlength;
+		} else {
+			pr_err("%s:AUDIO_START failed: block_align = %d\n",
+				__func__, wmapro_config->asfpacketlength);
+			rc = -EINVAL;
+			break;
+		}
+		if ((wmapro_config->validbitspersample == 16) ||
+			(wmapro_config->validbitspersample == 24)) {
+			wmapro_cfg.valid_bits_per_sample =
+				wmapro_config->validbitspersample;
+		} else {
+			pr_err("%s:AUDIO_START failed: bitspersample = %d\n",
+				__func__,
+				wmapro_config->validbitspersample);
+			rc = -EINVAL;
+			break;
+		}
+		if ((wmapro_config->channelmask  == 4) ||
+		(wmapro_config->channelmask == 3)) {
+			wmapro_cfg.ch_mask =  wmapro_config->channelmask;
+		} else {
+			pr_err("%s:AUDIO_START failed: channel_mask = %d\n",
+				__func__, wmapro_config->channelmask);
+			rc = -EINVAL;
+			break;
+		}
+		wmapro_cfg.encode_opt = wmapro_config->encodeopt;
+		wmapro_cfg.adv_encode_opt =
+				wmapro_config->advancedencodeopt;
+		wmapro_cfg.adv_encode_opt2 =
+				wmapro_config->advancedencodeopt2;
+		/* Configure Media format block */
+		rc = q6asm_media_format_block_wmapro(audio->ac, &wmapro_cfg);
+		if (rc < 0) {
+			pr_err("cmd media format block failed\n");
+			break;
+		}
+		rc = audio_aio_enable(audio);
+		audio->eos_rsp = 0;
+		audio->eos_flag = 0;
+		if (!rc) {
+			audio->enabled = 1;
+		} else {
+			audio->enabled = 0;
+			pr_err("Audio Start procedure failed rc=%d\n", rc);
+			break;
+		}
+		pr_debug("AUDIO_START success enable[%d]\n", audio->enabled);
+		if (audio->stopped == 1)
+			audio->stopped = 0;
+		break;
+	}
+	case AUDIO_GET_WMAPRO_CONFIG: {
+		if (copy_to_user((void *)arg, audio->codec_cfg,
+			 sizeof(struct msm_audio_wmapro_config))) {
+			rc = -EFAULT;
+		}
+		break;
+	}
+	case AUDIO_SET_WMAPRO_CONFIG: {
+		if (copy_from_user(audio->codec_cfg, (void *)arg,
+			sizeof(struct msm_audio_wmapro_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		break;
+	}
+	default:
+		pr_debug("%s[%p]: Calling utils ioctl\n", __func__, audio);
+		rc = audio->codec_ioctl(file, cmd, arg);
+		if (rc)
+			pr_err("Failed in utils_ioctl: %d\n", rc);
+	}
+	return rc;
+}
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct q6audio_aio *audio = NULL;
+	int rc = 0;
+
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_wmapro_" + 5];
+#endif
+	audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+	if (audio == NULL) {
+		pr_err("Could not allocate memory for wma decode driver\n");
+		return -ENOMEM;
+	}
+	audio->codec_cfg = kzalloc(sizeof(struct msm_audio_wmapro_config),
+					GFP_KERNEL);
+	if (audio->codec_cfg == NULL) {
+		pr_err("%s: Could not allocate memory for wmapro"
+			"config\n", __func__);
+		kfree(audio);
+		return -ENOMEM;
+	}
+
+
+	audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+
+	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
+					     (void *)audio);
+
+	if (!audio->ac) {
+		pr_err("Could not allocate memory for audio client\n");
+		kfree(audio->codec_cfg);
+		kfree(audio);
+		return -ENOMEM;
+	}
+
+	/* open in T/NT mode */
+	if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+		rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+					   FORMAT_WMA_V10PRO);
+		if (rc < 0) {
+			pr_err("NT mode Open failed rc=%d\n", rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->feedback = NON_TUNNEL_MODE;
+		/* open WMA decoder, expected frames is always 1*/
+		audio->buf_cfg.frames_per_buf = 0x01;
+		audio->buf_cfg.meta_info_enable = 0x01;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+		rc = q6asm_open_write(audio->ac, FORMAT_WMA_V10PRO);
+		if (rc < 0) {
+			pr_err("T mode Open failed rc=%d\n", rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->feedback = TUNNEL_MODE;
+		audio->buf_cfg.meta_info_enable = 0x00;
+	} else {
+		pr_err("Not supported mode\n");
+		rc = -EACCES;
+		goto fail;
+	}
+	rc = audio_aio_open(audio, file);
+
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_wmapro_%04x", audio->ac->session);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+					    NULL, (void *)audio,
+					    &audio_wmapro_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		pr_debug("debugfs_create_file failed\n");
+#endif
+	pr_info("%s:wmapro decoder open success, session_id = %d\n", __func__,
+				audio->ac->session);
+	return rc;
+fail:
+	q6asm_audio_client_free(audio->ac);
+	kfree(audio->codec_cfg);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_wmapro_fops = {
+	.owner = THIS_MODULE,
+	.open = audio_open,
+	.release = audio_aio_release,
+	.unlocked_ioctl = audio_ioctl,
+	.fsync = audio_aio_fsync,
+};
+
+struct miscdevice audio_wmapro_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_wmapro",
+	.fops = &audio_wmapro_fops,
+};
+
+static int __init audio_wmapro_init(void)
+{
+	return misc_register(&audio_wmapro_misc);
+}
+
+device_initcall(audio_wmapro_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/board-msm8x60-audio.c b/arch/arm/mach-msm/qdsp6v2/board-msm8x60-audio.c
new file mode 100644
index 0000000..0181cb5
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/board-msm8x60-audio.c
@@ -0,0 +1,2718 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/mfd/pmic8058.h>
+#include <linux/mfd/pmic8901.h>
+#include <linux/mfd/msm-adie-codec.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/machine.h>
+
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+#include <sound/apr_audio.h>
+#include <asm/mach-types.h>
+#include <asm/uaccess.h>
+#include <mach/board-msm8660.h>
+
+#include "snddev_icodec.h"
+#include "snddev_ecodec.h"
+#include "timpani_profile_8x60.h"
+#include "snddev_hdmi.h"
+#include "snddev_mi2s.h"
+#include "snddev_virtual.h"
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *debugfs_hsed_config;
+static void snddev_hsed_config_modify_setting(int type);
+static void snddev_hsed_config_restore_setting(void);
+#endif
+
+/* GPIO_CLASS_D0_EN */
+#define SNDDEV_GPIO_CLASS_D0_EN 227
+
+/* GPIO_CLASS_D1_EN */
+#define SNDDEV_GPIO_CLASS_D1_EN 229
+
+#define SNDDEV_GPIO_MIC2_ANCR_SEL 294
+#define SNDDEV_GPIO_MIC1_ANCL_SEL 295
+#define SNDDEV_GPIO_HS_MIC4_SEL 296
+
+#define DSP_RAM_BASE_8x60 0x46700000
+#define DSP_RAM_SIZE_8x60 0x2000000
+static int dspcrashd_pdata_8x60 = 0xDEADDEAD;
+
+static struct resource resources_dspcrashd_8x60[] = {
+	{
+		.name   = "msm_dspcrashd",
+		.start  = DSP_RAM_BASE_8x60,
+		.end    = DSP_RAM_BASE_8x60 + DSP_RAM_SIZE_8x60,
+		.flags  = IORESOURCE_DMA,
+	},
+};
+
+struct platform_device msm_device_dspcrashd_8x60 = {
+	.name           = "msm_dspcrashd",
+	.num_resources  = ARRAY_SIZE(resources_dspcrashd_8x60),
+	.resource       = resources_dspcrashd_8x60,
+	.dev = { .platform_data = &dspcrashd_pdata_8x60 },
+};
+
+static struct resource msm_cdcclk_ctl_resources[] = {
+	{
+		.name   = "msm_snddev_tx_mclk",
+		.start  = 108,
+		.end    = 108,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "msm_snddev_rx_mclk",
+		.start  = 109,
+		.end    = 109,
+		.flags  = IORESOURCE_IO,
+	},
+};
+
+static struct platform_device msm_cdcclk_ctl_device = {
+	.name   = "msm_cdcclk_ctl",
+	.num_resources  = ARRAY_SIZE(msm_cdcclk_ctl_resources),
+	.resource       = msm_cdcclk_ctl_resources,
+};
+
+static struct resource msm_aux_pcm_resources[] = {
+
+	{
+		.name   = "aux_pcm_dout",
+		.start  = 111,
+		.end    = 111,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "aux_pcm_din",
+		.start  = 112,
+		.end    = 112,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "aux_pcm_syncout",
+		.start  = 113,
+		.end    = 113,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "aux_pcm_clkin_a",
+		.start  = 114,
+		.end    = 114,
+		.flags  = IORESOURCE_IO,
+	},
+};
+
+static struct platform_device msm_aux_pcm_device = {
+	.name   = "msm_aux_pcm",
+	.num_resources  = ARRAY_SIZE(msm_aux_pcm_resources),
+	.resource       = msm_aux_pcm_resources,
+};
+
+static struct resource msm_mi2s_gpio_resources[] = {
+
+	{
+		.name   = "mi2s_ws",
+		.start  = 101,
+		.end    = 101,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "mi2s_sclk",
+		.start  = 102,
+		.end    = 102,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "mi2s_mclk",
+		.start  = 103,
+		.end    = 103,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "fm_mi2s_sd",
+		.start  = 107,
+		.end    = 107,
+		.flags  = IORESOURCE_IO,
+	},
+};
+
+static struct platform_device msm_mi2s_device = {
+	.name		= "msm_mi2s",
+	.num_resources	= ARRAY_SIZE(msm_mi2s_gpio_resources),
+	.resource	= msm_mi2s_gpio_resources,
+};
+
+/* Must be same size as msm_icodec_gpio_resources */
+static int msm_icodec_gpio_defaults[] = {
+	0,
+	0,
+};
+
+static struct resource msm_icodec_gpio_resources[] = {
+	{
+		.name   = "msm_icodec_speaker_left",
+		.start  = SNDDEV_GPIO_CLASS_D0_EN,
+		.end    = SNDDEV_GPIO_CLASS_D0_EN,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "msm_icodec_speaker_right",
+		.start  = SNDDEV_GPIO_CLASS_D1_EN,
+		.end    = SNDDEV_GPIO_CLASS_D1_EN,
+		.flags  = IORESOURCE_IO,
+	},
+};
+
+static struct platform_device msm_icodec_gpio_device = {
+	.name   = "msm_icodec_gpio",
+	.num_resources  = ARRAY_SIZE(msm_icodec_gpio_resources),
+	.resource       = msm_icodec_gpio_resources,
+	.dev = { .platform_data = &msm_icodec_gpio_defaults },
+};
+
+static struct regulator *s3;
+static struct regulator *mvs;
+
+static int msm_snddev_enable_dmic_power(void)
+{
+	int ret;
+
+	s3 = regulator_get(NULL, "8058_s3");
+	if (IS_ERR(s3)) {
+		ret = -EBUSY;
+		goto fail_get_s3;
+	}
+
+	ret = regulator_set_voltage(s3, 1800000, 1800000);
+	if (ret) {
+		pr_err("%s: error setting voltage\n", __func__);
+		goto fail_s3;
+	}
+
+	ret = regulator_enable(s3);
+	if (ret) {
+		pr_err("%s: error enabling regulator\n", __func__);
+		goto fail_s3;
+	}
+
+	mvs = regulator_get(NULL, "8901_mvs0");
+	if (IS_ERR(mvs))
+		goto fail_mvs0_get;
+
+	ret = regulator_enable(mvs);
+	if (ret) {
+		pr_err("%s: error setting regulator\n", __func__);
+		goto fail_mvs0_enable;
+	}
+	return ret;
+
+fail_mvs0_enable:
+	regulator_put(mvs);
+	mvs = NULL;
+fail_mvs0_get:
+	regulator_disable(s3);
+fail_s3:
+	regulator_put(s3);
+	s3 = NULL;
+fail_get_s3:
+	return ret;
+}
+
+static void msm_snddev_disable_dmic_power(void)
+{
+	int ret;
+
+	if (mvs) {
+		ret = regulator_disable(mvs);
+		if (ret < 0)
+			pr_err("%s: error disabling vreg mvs\n", __func__);
+		regulator_put(mvs);
+		mvs = NULL;
+	}
+
+	if (s3) {
+		ret = regulator_disable(s3);
+		if (ret < 0)
+			pr_err("%s: error disabling regulator s3\n", __func__);
+		regulator_put(s3);
+		s3 = NULL;
+	}
+}
+
+#define PM8901_MPP_3 (2) /* PM8901 MPP starts from 0 */
+
+static int config_class_d0_gpio(int enable)
+{
+	int rc;
+
+	struct pm8xxx_mpp_config_data class_d0_mpp = {
+		.type		= PM8XXX_MPP_TYPE_D_OUTPUT,
+		.level		= PM8901_MPP_DIG_LEVEL_MSMIO,
+	};
+
+	if (enable) {
+		class_d0_mpp.control = PM8XXX_MPP_DOUT_CTRL_HIGH;
+		rc = pm8xxx_mpp_config(PM8901_MPP_PM_TO_SYS(PM8901_MPP_3),
+							&class_d0_mpp);
+		if (rc) {
+			pr_err("%s: CLASS_D0_EN failed\n", __func__);
+			return rc;
+		}
+
+		rc = gpio_request(SNDDEV_GPIO_CLASS_D0_EN, "CLASSD0_EN");
+
+		if (rc) {
+			pr_err("%s: spkr pamp gpio pm8901 mpp3 request"
+			"failed\n", __func__);
+			class_d0_mpp.control = PM8XXX_MPP_DOUT_CTRL_LOW;
+			pm8xxx_mpp_config(PM8901_MPP_PM_TO_SYS(PM8901_MPP_3),
+						&class_d0_mpp);
+			return rc;
+		}
+
+		gpio_direction_output(SNDDEV_GPIO_CLASS_D0_EN, 1);
+		gpio_set_value_cansleep(SNDDEV_GPIO_CLASS_D0_EN, 1);
+
+	} else {
+		class_d0_mpp.control = PM8XXX_MPP_DOUT_CTRL_LOW;
+		pm8xxx_mpp_config(PM8901_MPP_PM_TO_SYS(PM8901_MPP_3),
+						&class_d0_mpp);
+		gpio_set_value_cansleep(SNDDEV_GPIO_CLASS_D0_EN, 0);
+		gpio_free(SNDDEV_GPIO_CLASS_D0_EN);
+	}
+	return 0;
+}
+
+static int config_class_d1_gpio(int enable)
+{
+	int rc;
+
+	if (enable) {
+		rc = gpio_request(SNDDEV_GPIO_CLASS_D1_EN, "CLASSD1_EN");
+
+		if (rc) {
+			pr_err("%s: Right Channel spkr gpio request"
+				" failed\n", __func__);
+			return rc;
+		}
+
+		gpio_direction_output(SNDDEV_GPIO_CLASS_D1_EN, 1);
+		gpio_set_value_cansleep(SNDDEV_GPIO_CLASS_D1_EN, 1);
+
+	} else {
+		gpio_set_value_cansleep(SNDDEV_GPIO_CLASS_D1_EN, 0);
+		gpio_free(SNDDEV_GPIO_CLASS_D1_EN);
+	}
+	return 0;
+}
+
+static atomic_t pamp_ref_cnt;
+
+static int msm_snddev_poweramp_on(void)
+{
+	int rc;
+
+	if (atomic_inc_return(&pamp_ref_cnt) > 1)
+		return 0;
+
+	pr_debug("%s: enable stereo spkr amp\n", __func__);
+	rc = config_class_d0_gpio(1);
+	if (rc) {
+		pr_err("%s: d0 gpio configuration failed\n", __func__);
+		goto config_gpio_fail;
+	}
+	rc = config_class_d1_gpio(1);
+	if (rc) {
+		pr_err("%s: d1 gpio configuration failed\n", __func__);
+		goto config_gpio_fail;
+	}
+config_gpio_fail:
+	return rc;
+}
+
+static void msm_snddev_poweramp_off(void)
+{
+	if (atomic_dec_return(&pamp_ref_cnt) == 0) {
+		pr_debug("%s: disable stereo spkr amp\n", __func__);
+		config_class_d0_gpio(0);
+		config_class_d1_gpio(0);
+		msleep(30);
+	}
+}
+
+/* Regulator 8058_l10 supplies regulator 8058_ncp. */
+static struct regulator *snddev_reg_ncp;
+static struct regulator *snddev_reg_l10;
+
+static atomic_t preg_ref_cnt;
+
+static int msm_snddev_voltage_on(void)
+{
+	int rc;
+	pr_debug("%s\n", __func__);
+
+	if (atomic_inc_return(&preg_ref_cnt) > 1)
+		return 0;
+
+	snddev_reg_l10 = regulator_get(NULL, "8058_l10");
+	if (IS_ERR(snddev_reg_l10)) {
+		pr_err("%s: regulator_get(%s) failed (%ld)\n", __func__,
+			"l10", PTR_ERR(snddev_reg_l10));
+		return -EBUSY;
+	}
+
+	rc = regulator_set_voltage(snddev_reg_l10, 2600000, 2600000);
+	if (rc < 0)
+		pr_err("%s: regulator_set_voltage(l10) failed (%d)\n",
+			__func__, rc);
+
+	rc = regulator_enable(snddev_reg_l10);
+	if (rc < 0)
+		pr_err("%s: regulator_enable(l10) failed (%d)\n", __func__, rc);
+
+	snddev_reg_ncp = regulator_get(NULL, "8058_ncp");
+	if (IS_ERR(snddev_reg_ncp)) {
+		pr_err("%s: regulator_get(%s) failed (%ld)\n", __func__,
+			"ncp", PTR_ERR(snddev_reg_ncp));
+		return -EBUSY;
+	}
+
+	rc = regulator_set_voltage(snddev_reg_ncp, 1800000, 1800000);
+	if (rc < 0) {
+		pr_err("%s: regulator_set_voltage(ncp) failed (%d)\n",
+			__func__, rc);
+		goto regulator_fail;
+	}
+
+	rc = regulator_enable(snddev_reg_ncp);
+	if (rc < 0) {
+		pr_err("%s: regulator_enable(ncp) failed (%d)\n", __func__, rc);
+		goto regulator_fail;
+	}
+
+	return rc;
+
+regulator_fail:
+	regulator_put(snddev_reg_ncp);
+	snddev_reg_ncp = NULL;
+	return rc;
+}
+
+static void msm_snddev_voltage_off(void)
+{
+	int rc;
+	pr_debug("%s\n", __func__);
+
+	if (!snddev_reg_ncp)
+		goto done;
+
+	if (atomic_dec_return(&preg_ref_cnt) == 0) {
+		rc = regulator_disable(snddev_reg_ncp);
+		if (rc < 0)
+			pr_err("%s: regulator_disable(ncp) failed (%d)\n",
+				__func__, rc);
+		regulator_put(snddev_reg_ncp);
+
+		snddev_reg_ncp = NULL;
+	}
+
+done:
+	if (!snddev_reg_l10)
+		return;
+
+	rc = regulator_disable(snddev_reg_l10);
+	if (rc < 0)
+		pr_err("%s: regulator_disable(l10) failed (%d)\n",
+			__func__, rc);
+
+	regulator_put(snddev_reg_l10);
+
+	snddev_reg_l10 = NULL;
+}
+
+static int msm_snddev_enable_amic_power(void)
+{
+	int ret = 0;
+#ifdef CONFIG_PMIC8058_OTHC
+
+	if (machine_is_msm8x60_fluid()) {
+
+		ret = pm8058_micbias_enable(OTHC_MICBIAS_0,
+				OTHC_SIGNAL_ALWAYS_ON);
+		if (ret)
+			pr_err("%s: Enabling amic power failed\n", __func__);
+
+		ret = gpio_request(SNDDEV_GPIO_MIC2_ANCR_SEL, "MIC2_ANCR_SEL");
+		if (ret) {
+			pr_err("%s: spkr pamp gpio %d request failed\n",
+				__func__, SNDDEV_GPIO_MIC2_ANCR_SEL);
+			return ret;
+		}
+		gpio_direction_output(SNDDEV_GPIO_MIC2_ANCR_SEL, 0);
+
+		ret = gpio_request(SNDDEV_GPIO_MIC1_ANCL_SEL, "MIC1_ANCL_SEL");
+		if (ret) {
+			pr_err("%s: mic1 ancl gpio %d request failed\n",
+				__func__, SNDDEV_GPIO_MIC1_ANCL_SEL);
+			gpio_free(SNDDEV_GPIO_MIC2_ANCR_SEL);
+			return ret;
+		}
+		gpio_direction_output(SNDDEV_GPIO_MIC1_ANCL_SEL, 0);
+
+	} else {
+		ret = pm8058_micbias_enable(OTHC_MICBIAS_2,
+				OTHC_SIGNAL_ALWAYS_ON);
+		if (ret)
+			pr_err("%s: Enabling amic power failed\n", __func__);
+	}
+#endif
+	return ret;
+}
+
+static void msm_snddev_disable_amic_power(void)
+{
+#ifdef CONFIG_PMIC8058_OTHC
+	int ret;
+	if (machine_is_msm8x60_fluid()) {
+		ret = pm8058_micbias_enable(OTHC_MICBIAS_0,
+				OTHC_SIGNAL_OFF);
+		gpio_free(SNDDEV_GPIO_MIC1_ANCL_SEL);
+		gpio_free(SNDDEV_GPIO_MIC2_ANCR_SEL);
+	} else
+		ret = pm8058_micbias_enable(OTHC_MICBIAS_2, OTHC_SIGNAL_OFF);
+
+	if (ret)
+		pr_err("%s: Disabling amic power failed\n", __func__);
+#endif
+}
+
+static int msm_snddev_enable_anc_power(void)
+{
+	int ret = 0;
+#ifdef CONFIG_PMIC8058_OTHC
+	ret = pm8058_micbias_enable(OTHC_MICBIAS_2,
+		OTHC_SIGNAL_ALWAYS_ON);
+	if (ret)
+		pr_err("%s: Enabling anc micbias 2 failed\n", __func__);
+
+	if (machine_is_msm8x60_fluid()) {
+
+		ret = pm8058_micbias_enable(OTHC_MICBIAS_0,
+				OTHC_SIGNAL_ALWAYS_ON);
+		if (ret)
+			pr_err("%s: Enabling anc micbias 0 failed\n", __func__);
+
+		ret = gpio_request(SNDDEV_GPIO_MIC2_ANCR_SEL, "MIC2_ANCR_SEL");
+		if (ret) {
+			pr_err("%s: mic2 ancr gpio %d request failed\n",
+				__func__, SNDDEV_GPIO_MIC2_ANCR_SEL);
+			return ret;
+		}
+		gpio_direction_output(SNDDEV_GPIO_MIC2_ANCR_SEL, 1);
+
+		ret = gpio_request(SNDDEV_GPIO_MIC1_ANCL_SEL, "MIC1_ANCL_SEL");
+		if (ret) {
+			pr_err("%s: mic1 ancl gpio %d request failed\n",
+				__func__, SNDDEV_GPIO_MIC1_ANCL_SEL);
+			gpio_free(SNDDEV_GPIO_MIC2_ANCR_SEL);
+			return ret;
+		}
+		gpio_direction_output(SNDDEV_GPIO_MIC1_ANCL_SEL, 1);
+
+	}
+#endif
+	return ret;
+}
+
+static void msm_snddev_disable_anc_power(void)
+{
+#ifdef CONFIG_PMIC8058_OTHC
+	int ret;
+
+	ret = pm8058_micbias_enable(OTHC_MICBIAS_2, OTHC_SIGNAL_OFF);
+
+	if (machine_is_msm8x60_fluid()) {
+		ret |= pm8058_micbias_enable(OTHC_MICBIAS_0,
+				OTHC_SIGNAL_OFF);
+		gpio_free(SNDDEV_GPIO_MIC2_ANCR_SEL);
+		gpio_free(SNDDEV_GPIO_MIC1_ANCL_SEL);
+	}
+
+	if (ret)
+		pr_err("%s: Disabling anc power failed\n", __func__);
+#endif
+}
+
+static int msm_snddev_enable_amic_sec_power(void)
+{
+#ifdef CONFIG_PMIC8058_OTHC
+	int ret;
+
+	if (machine_is_msm8x60_fluid()) {
+
+		ret = pm8058_micbias_enable(OTHC_MICBIAS_2,
+				OTHC_SIGNAL_ALWAYS_ON);
+		if (ret)
+			pr_err("%s: Enabling amic2 power failed\n", __func__);
+
+		ret = gpio_request(SNDDEV_GPIO_HS_MIC4_SEL,
+						"HS_MIC4_SEL");
+		if (ret) {
+			pr_err("%s: spkr pamp gpio %d request failed\n",
+					__func__, SNDDEV_GPIO_HS_MIC4_SEL);
+			return ret;
+		}
+		gpio_direction_output(SNDDEV_GPIO_HS_MIC4_SEL, 1);
+	}
+#endif
+
+	msm_snddev_enable_amic_power();
+	return 0;
+}
+
+static void msm_snddev_disable_amic_sec_power(void)
+{
+#ifdef CONFIG_PMIC8058_OTHC
+	int ret;
+	if (machine_is_msm8x60_fluid()) {
+
+		ret = pm8058_micbias_enable(OTHC_MICBIAS_2,
+					OTHC_SIGNAL_OFF);
+		if (ret)
+			pr_err("%s: Disabling amic2 power failed\n", __func__);
+
+		gpio_free(SNDDEV_GPIO_HS_MIC4_SEL);
+	}
+#endif
+
+	msm_snddev_disable_amic_power();
+}
+
+static int msm_snddev_enable_dmic_sec_power(void)
+{
+	int ret;
+
+	ret = msm_snddev_enable_dmic_power();
+	if (ret) {
+		pr_err("%s: Error: Enabling dmic power failed\n", __func__);
+		return ret;
+	}
+#ifdef CONFIG_PMIC8058_OTHC
+	ret = pm8058_micbias_enable(OTHC_MICBIAS_2, OTHC_SIGNAL_ALWAYS_ON);
+	if (ret) {
+		pr_err("%s: Error: Enabling micbias failed\n", __func__);
+		msm_snddev_disable_dmic_power();
+		return ret;
+	}
+#endif
+	return 0;
+}
+
+static void msm_snddev_disable_dmic_sec_power(void)
+{
+	msm_snddev_disable_dmic_power();
+
+#ifdef CONFIG_PMIC8058_OTHC
+	pm8058_micbias_enable(OTHC_MICBIAS_2, OTHC_SIGNAL_OFF);
+#endif
+}
+
+static struct adie_codec_action_unit iearpiece_48KHz_osr256_actions[] =
+	EAR_PRI_MONO_8000_OSR_256;
+
+static struct adie_codec_hwsetting_entry iearpiece_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = iearpiece_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(iearpiece_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile iearpiece_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = iearpiece_settings,
+	.setting_sz = ARRAY_SIZE(iearpiece_settings),
+};
+
+static struct snddev_icodec_data snddev_iearpiece_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE),
+	.name = "handset_rx",
+	.copp_id = 0,
+	.profile = &iearpiece_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+};
+
+static struct platform_device msm_iearpiece_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_iearpiece_data },
+};
+
+static struct adie_codec_action_unit imic_48KHz_osr256_actions[] =
+	AMIC_PRI_MONO_OSR_256;
+
+static struct adie_codec_hwsetting_entry imic_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = imic_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(imic_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile imic_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = imic_settings,
+	.setting_sz = ARRAY_SIZE(imic_settings),
+};
+
+static struct snddev_icodec_data snddev_imic_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "handset_tx",
+	.copp_id = 1,
+	.profile = &imic_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_amic_power,
+	.pamp_off = msm_snddev_disable_amic_power,
+};
+
+static struct platform_device msm_imic_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_imic_data },
+};
+
+static struct snddev_icodec_data snddev_fluid_ispkr_mic_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "speaker_mono_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &imic_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_amic_power,
+	.pamp_off = msm_snddev_disable_amic_power,
+};
+
+static struct platform_device msm_fluid_ispkr_mic_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_fluid_ispkr_mic_data },
+};
+
+
+static struct adie_codec_action_unit headset_ab_cpls_48KHz_osr256_actions[] =
+	HEADSET_AB_CPLS_48000_OSR_256;
+
+static struct adie_codec_hwsetting_entry headset_ab_cpls_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = headset_ab_cpls_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(headset_ab_cpls_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile headset_ab_cpls_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = headset_ab_cpls_settings,
+	.setting_sz = ARRAY_SIZE(headset_ab_cpls_settings),
+};
+
+static struct snddev_icodec_data snddev_ihs_stereo_rx_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE),
+	.name = "headset_stereo_rx",
+	.copp_id = 0,
+	.profile = &headset_ab_cpls_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.voltage_on = msm_snddev_voltage_on,
+	.voltage_off = msm_snddev_voltage_off,
+};
+
+static struct platform_device msm_headset_stereo_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_ihs_stereo_rx_data },
+};
+
+static struct adie_codec_action_unit headset_anc_48KHz_osr256_actions[] =
+	ANC_HEADSET_CPLS_AMIC1_AUXL_RX1_48000_OSR_256;
+
+static struct adie_codec_hwsetting_entry headset_anc_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = headset_anc_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(headset_anc_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile headset_anc_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = headset_anc_settings,
+	.setting_sz = ARRAY_SIZE(headset_anc_settings),
+};
+
+static struct snddev_icodec_data snddev_anc_headset_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE | SNDDEV_CAP_ANC),
+	.name = "anc_headset_stereo_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &headset_anc_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_anc_power,
+	.pamp_off = msm_snddev_disable_anc_power,
+	.voltage_on = msm_snddev_voltage_on,
+	.voltage_off = msm_snddev_voltage_off,
+};
+
+static struct platform_device msm_anc_headset_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_anc_headset_data },
+};
+
+static struct adie_codec_action_unit ispkr_stereo_48KHz_osr256_actions[] =
+	SPEAKER_PRI_STEREO_48000_OSR_256;
+
+static struct adie_codec_hwsetting_entry ispkr_stereo_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ispkr_stereo_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(ispkr_stereo_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile ispkr_stereo_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ispkr_stereo_settings,
+	.setting_sz = ARRAY_SIZE(ispkr_stereo_settings),
+};
+
+static struct snddev_icodec_data snddev_ispkr_stereo_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE),
+	.name = "speaker_stereo_rx",
+	.copp_id = 0,
+	.profile = &ispkr_stereo_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_poweramp_on,
+	.pamp_off = msm_snddev_poweramp_off,
+};
+
+static struct platform_device msm_ispkr_stereo_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_ispkr_stereo_data },
+};
+
+static struct adie_codec_action_unit idmic_mono_48KHz_osr256_actions[] =
+	DMIC1_PRI_MONO_OSR_256;
+
+static struct adie_codec_hwsetting_entry idmic_mono_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = idmic_mono_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(idmic_mono_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile idmic_mono_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = idmic_mono_settings,
+	.setting_sz = ARRAY_SIZE(idmic_mono_settings),
+};
+
+static struct snddev_icodec_data snddev_ispkr_mic_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "speaker_mono_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &idmic_mono_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_dmic_power,
+	.pamp_off = msm_snddev_disable_dmic_power,
+};
+
+static struct platform_device msm_ispkr_mic_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_ispkr_mic_data },
+};
+
+static struct adie_codec_action_unit iearpiece_ffa_48KHz_osr256_actions[] =
+	EAR_PRI_MONO_8000_OSR_256;
+
+static struct adie_codec_hwsetting_entry iearpiece_ffa_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = iearpiece_ffa_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(iearpiece_ffa_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile iearpiece_ffa_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = iearpiece_ffa_settings,
+	.setting_sz = ARRAY_SIZE(iearpiece_ffa_settings),
+};
+
+static struct snddev_icodec_data snddev_iearpiece_ffa_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE),
+	.name = "handset_rx",
+	.copp_id = 0,
+	.profile = &iearpiece_ffa_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+};
+
+static struct platform_device msm_iearpiece_ffa_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_iearpiece_ffa_data },
+};
+
+static struct snddev_icodec_data snddev_imic_ffa_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "handset_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &idmic_mono_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_dmic_power,
+	.pamp_off = msm_snddev_disable_dmic_power,
+};
+
+static struct platform_device msm_imic_ffa_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_imic_ffa_data },
+};
+
+static struct adie_codec_action_unit dual_mic_endfire_8KHz_osr256_actions[] =
+	DMIC1_PRI_STEREO_OSR_256;
+
+static struct adie_codec_hwsetting_entry dual_mic_endfire_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = dual_mic_endfire_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(dual_mic_endfire_8KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile dual_mic_endfire_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = dual_mic_endfire_settings,
+	.setting_sz = ARRAY_SIZE(dual_mic_endfire_settings),
+};
+
+static struct snddev_icodec_data snddev_dual_mic_endfire_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "handset_dual_mic_endfire_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &dual_mic_endfire_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_dmic_power,
+	.pamp_off = msm_snddev_disable_dmic_power,
+};
+
+static struct platform_device msm_hs_dual_mic_endfire_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_dual_mic_endfire_data },
+};
+
+static struct snddev_icodec_data snddev_dual_mic_spkr_endfire_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "speaker_dual_mic_endfire_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &dual_mic_endfire_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_dmic_power,
+	.pamp_off = msm_snddev_disable_dmic_power,
+};
+
+static struct platform_device msm_spkr_dual_mic_endfire_device = {
+	.name = "snddev_icodec",
+	.id = 15,
+	.dev = { .platform_data = &snddev_dual_mic_spkr_endfire_data },
+};
+
+static struct adie_codec_action_unit dual_mic_broadside_8osr256_actions[] =
+	HS_DMIC2_STEREO_OSR_256;
+
+static struct adie_codec_hwsetting_entry dual_mic_broadside_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = dual_mic_broadside_8osr256_actions,
+		.action_sz = ARRAY_SIZE(dual_mic_broadside_8osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile dual_mic_broadside_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = dual_mic_broadside_settings,
+	.setting_sz = ARRAY_SIZE(dual_mic_broadside_settings),
+};
+
+static struct snddev_icodec_data snddev_hs_dual_mic_broadside_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "handset_dual_mic_broadside_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &dual_mic_broadside_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_dmic_sec_power,
+	.pamp_off = msm_snddev_disable_dmic_sec_power,
+};
+
+static struct platform_device msm_hs_dual_mic_broadside_device = {
+	.name = "snddev_icodec",
+	.id = 21,
+	.dev = { .platform_data = &snddev_hs_dual_mic_broadside_data },
+};
+
+static struct snddev_icodec_data snddev_spkr_dual_mic_broadside_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "speaker_dual_mic_broadside_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &dual_mic_broadside_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_dmic_sec_power,
+	.pamp_off = msm_snddev_disable_dmic_sec_power,
+};
+
+static struct platform_device msm_spkr_dual_mic_broadside_device = {
+	.name = "snddev_icodec",
+	.id = 18,
+	.dev = { .platform_data = &snddev_spkr_dual_mic_broadside_data },
+};
+
+static struct adie_codec_action_unit
+		fluid_dual_mic_endfire_8KHz_osr256_actions[] =
+	FLUID_AMIC_DUAL_8000_OSR_256;
+
+static struct adie_codec_hwsetting_entry fluid_dual_mic_endfire_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = fluid_dual_mic_endfire_8KHz_osr256_actions,
+		.action_sz =
+			ARRAY_SIZE(fluid_dual_mic_endfire_8KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile fluid_dual_mic_endfire_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = fluid_dual_mic_endfire_settings,
+	.setting_sz = ARRAY_SIZE(fluid_dual_mic_endfire_settings),
+};
+
+static struct snddev_icodec_data snddev_fluid_dual_mic_endfire_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "handset_dual_mic_endfire_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &fluid_dual_mic_endfire_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_amic_sec_power,
+	.pamp_off = msm_snddev_disable_amic_sec_power,
+};
+
+static struct platform_device msm_fluid_hs_dual_mic_endfire_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_fluid_dual_mic_endfire_data },
+};
+
+static struct snddev_icodec_data snddev_fluid_dual_mic_spkr_endfire_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "speaker_dual_mic_endfire_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &fluid_dual_mic_endfire_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_amic_sec_power,
+	.pamp_off = msm_snddev_disable_amic_sec_power,
+};
+
+static struct platform_device msm_fluid_spkr_dual_mic_endfire_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_fluid_dual_mic_spkr_endfire_data },
+};
+
+static struct adie_codec_action_unit
+		fluid_dual_mic_broadside_8KHz_osr256_actions[] =
+	FLUID_AMIC_DUAL_BROADSIDE_8000_OSR_256;
+
+static struct adie_codec_hwsetting_entry fluid_dual_mic_broadside_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = fluid_dual_mic_broadside_8KHz_osr256_actions,
+		.action_sz =
+		ARRAY_SIZE(fluid_dual_mic_broadside_8KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile fluid_dual_mic_broadside_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = fluid_dual_mic_broadside_settings,
+	.setting_sz = ARRAY_SIZE(fluid_dual_mic_broadside_settings),
+};
+
+static struct snddev_icodec_data snddev_fluid_dual_mic_broadside_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "handset_dual_mic_broadside_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &fluid_dual_mic_broadside_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_amic_power,
+	.pamp_off = msm_snddev_disable_amic_power,
+};
+
+static struct platform_device msm_fluid_hs_dual_mic_broadside_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_fluid_dual_mic_broadside_data },
+};
+
+static struct snddev_icodec_data snddev_fluid_dual_mic_spkr_broadside_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "speaker_dual_mic_broadside_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &fluid_dual_mic_broadside_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_amic_power,
+	.pamp_off = msm_snddev_disable_amic_power,
+};
+
+static struct platform_device msm_fluid_spkr_dual_mic_broadside_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_fluid_dual_mic_spkr_broadside_data },
+};
+
+static struct snddev_hdmi_data snddev_hdmi_stereo_rx_data = {
+	.capability = SNDDEV_CAP_RX ,
+	.name = "hdmi_stereo_rx",
+	.copp_id = HDMI_RX,
+	.channel_mode = 0,
+	.default_sample_rate = 48000,
+};
+
+static struct platform_device msm_snddev_hdmi_stereo_rx_device = {
+	.name = "snddev_hdmi",
+	.dev = { .platform_data = &snddev_hdmi_stereo_rx_data },
+};
+
+static struct snddev_mi2s_data snddev_mi2s_fm_tx_data = {
+	.capability = SNDDEV_CAP_TX ,
+	.name = "fmradio_stereo_tx",
+	.copp_id = MI2S_TX,
+	.channel_mode = 2, /* stereo */
+	.sd_lines = MI2S_SD3, /* sd3 */
+	.sample_rate = 48000,
+};
+
+static struct platform_device msm_mi2s_fm_tx_device = {
+	.name = "snddev_mi2s",
+	.dev = { .platform_data = &snddev_mi2s_fm_tx_data },
+};
+
+static struct snddev_mi2s_data snddev_mi2s_fm_rx_data = {
+	.capability = SNDDEV_CAP_RX ,
+	.name = "fmradio_stereo_rx",
+	.copp_id = MI2S_RX,
+	.channel_mode = 2, /* stereo */
+	.sd_lines = MI2S_SD3, /* sd3 */
+	.sample_rate = 48000,
+};
+
+static struct platform_device msm_mi2s_fm_rx_device = {
+	.name = "snddev_mi2s",
+	.id = 1,
+	.dev = { .platform_data = &snddev_mi2s_fm_rx_data },
+};
+
+static struct adie_codec_action_unit iheadset_mic_tx_osr256_actions[] =
+	HEADSET_AMIC2_TX_MONO_PRI_OSR_256;
+
+static struct adie_codec_hwsetting_entry iheadset_mic_tx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = iheadset_mic_tx_osr256_actions,
+		.action_sz = ARRAY_SIZE(iheadset_mic_tx_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile iheadset_mic_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = iheadset_mic_tx_settings,
+	.setting_sz = ARRAY_SIZE(iheadset_mic_tx_settings),
+};
+
+static struct snddev_icodec_data snddev_headset_mic_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "headset_mono_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &iheadset_mic_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+};
+
+static struct platform_device msm_headset_mic_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_headset_mic_data },
+};
+
+static struct adie_codec_action_unit
+	ihs_stereo_speaker_stereo_rx_48KHz_osr256_actions[] =
+	SPEAKER_HPH_AB_CPL_PRI_STEREO_48000_OSR_256;
+
+static struct adie_codec_hwsetting_entry
+	ihs_stereo_speaker_stereo_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ihs_stereo_speaker_stereo_rx_48KHz_osr256_actions,
+		.action_sz =
+		ARRAY_SIZE(ihs_stereo_speaker_stereo_rx_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile ihs_stereo_speaker_stereo_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ihs_stereo_speaker_stereo_rx_settings,
+	.setting_sz = ARRAY_SIZE(ihs_stereo_speaker_stereo_rx_settings),
+};
+
+static struct snddev_icodec_data snddev_ihs_stereo_speaker_stereo_rx_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE),
+	.name = "headset_stereo_speaker_stereo_rx",
+	.copp_id = 0,
+	.profile = &ihs_stereo_speaker_stereo_rx_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_poweramp_on,
+	.pamp_off = msm_snddev_poweramp_off,
+	.voltage_on = msm_snddev_voltage_on,
+	.voltage_off = msm_snddev_voltage_off,
+};
+
+static struct platform_device msm_ihs_stereo_speaker_stereo_rx_device = {
+	.name = "snddev_icodec",
+	.id = 22,
+	.dev = { .platform_data = &snddev_ihs_stereo_speaker_stereo_rx_data },
+};
+
+/* define the value for BT_SCO */
+
+static struct snddev_ecodec_data snddev_bt_sco_earpiece_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE),
+	.name = "bt_sco_rx",
+	.copp_id = PCM_RX,
+	.channel_mode = 1,
+};
+
+static struct snddev_ecodec_data snddev_bt_sco_mic_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "bt_sco_tx",
+	.copp_id = PCM_TX,
+	.channel_mode = 1,
+};
+
+struct platform_device msm_bt_sco_earpiece_device = {
+	.name = "msm_snddev_ecodec",
+	.dev = { .platform_data = &snddev_bt_sco_earpiece_data },
+};
+
+struct platform_device msm_bt_sco_mic_device = {
+	.name = "msm_snddev_ecodec",
+	.dev = { .platform_data = &snddev_bt_sco_mic_data },
+};
+
+static struct adie_codec_action_unit itty_mono_tx_actions[] =
+	TTY_HEADSET_MONO_TX_OSR_256;
+
+static struct adie_codec_hwsetting_entry itty_mono_tx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = itty_mono_tx_actions,
+		.action_sz = ARRAY_SIZE(itty_mono_tx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile itty_mono_tx_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = itty_mono_tx_settings,
+	.setting_sz = ARRAY_SIZE(itty_mono_tx_settings),
+};
+
+static struct snddev_icodec_data snddev_itty_mono_tx_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE | SNDDEV_CAP_TTY),
+	.name = "tty_headset_mono_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &itty_mono_tx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+};
+
+static struct platform_device msm_itty_mono_tx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_itty_mono_tx_data },
+};
+
+static struct adie_codec_action_unit itty_mono_rx_actions[] =
+	TTY_HEADSET_MONO_RX_8000_OSR_256;
+
+static struct adie_codec_hwsetting_entry itty_mono_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = itty_mono_rx_actions,
+		.action_sz = ARRAY_SIZE(itty_mono_rx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile itty_mono_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = itty_mono_rx_settings,
+	.setting_sz = ARRAY_SIZE(itty_mono_rx_settings),
+};
+
+static struct snddev_icodec_data snddev_itty_mono_rx_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE | SNDDEV_CAP_TTY),
+	.name = "tty_headset_mono_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &itty_mono_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.voltage_on = msm_snddev_voltage_on,
+	.voltage_off = msm_snddev_voltage_off,
+};
+
+static struct platform_device msm_itty_mono_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_itty_mono_rx_data },
+};
+
+static struct adie_codec_action_unit linein_pri_actions[] =
+	LINEIN_PRI_STEREO_OSR_256;
+
+static struct adie_codec_hwsetting_entry linein_pri_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = linein_pri_actions,
+		.action_sz = ARRAY_SIZE(linein_pri_actions),
+	},
+};
+
+static struct adie_codec_dev_profile linein_pri_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = linein_pri_settings,
+	.setting_sz = ARRAY_SIZE(linein_pri_settings),
+};
+
+static struct snddev_icodec_data snddev_linein_pri_data = {
+	.capability = SNDDEV_CAP_TX,
+	.name = "linein_pri_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &linein_pri_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.voltage_on = msm_snddev_voltage_on,
+	.voltage_off = msm_snddev_voltage_off,
+};
+
+static struct platform_device msm_linein_pri_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_linein_pri_data },
+};
+
+static struct adie_codec_action_unit auxpga_lp_lo_actions[] =
+	LB_AUXPGA_LO_STEREO;
+
+static struct adie_codec_hwsetting_entry auxpga_lp_lo_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = auxpga_lp_lo_actions,
+		.action_sz = ARRAY_SIZE(auxpga_lp_lo_actions),
+	},
+};
+
+static struct adie_codec_dev_profile auxpga_lp_lo_profile = {
+	.path_type = ADIE_CODEC_LB,
+	.settings = auxpga_lp_lo_settings,
+	.setting_sz = ARRAY_SIZE(auxpga_lp_lo_settings),
+};
+
+static struct snddev_icodec_data snddev_auxpga_lp_lo_data = {
+	.capability = SNDDEV_CAP_LB,
+	.name = "speaker_stereo_lb",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &auxpga_lp_lo_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_poweramp_on,
+	.pamp_off = msm_snddev_poweramp_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_ANALOG,
+};
+
+static struct platform_device msm_auxpga_lp_lo_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_auxpga_lp_lo_data },
+};
+
+static struct adie_codec_action_unit auxpga_lp_hs_actions[] =
+	LB_AUXPGA_HPH_AB_CPLS_STEREO;
+
+static struct adie_codec_hwsetting_entry auxpga_lp_hs_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = auxpga_lp_hs_actions,
+		.action_sz = ARRAY_SIZE(auxpga_lp_hs_actions),
+	},
+};
+
+static struct adie_codec_dev_profile auxpga_lp_hs_profile = {
+	.path_type = ADIE_CODEC_LB,
+	.settings = auxpga_lp_hs_settings,
+	.setting_sz = ARRAY_SIZE(auxpga_lp_hs_settings),
+};
+
+static struct snddev_icodec_data snddev_auxpga_lp_hs_data = {
+	.capability = SNDDEV_CAP_LB,
+	.name = "hs_stereo_lb",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &auxpga_lp_hs_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.voltage_on = msm_snddev_voltage_on,
+	.voltage_off = msm_snddev_voltage_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_ANALOG,
+};
+
+static struct platform_device msm_auxpga_lp_hs_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_auxpga_lp_hs_data },
+};
+
+#ifdef CONFIG_MSM8X60_FTM_AUDIO_DEVICES
+static struct adie_codec_action_unit ftm_headset_mono_rx_actions[] =
+	HPH_PRI_AB_CPLS_MONO;
+
+static struct adie_codec_hwsetting_entry ftm_headset_mono_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_headset_mono_rx_actions,
+		.action_sz = ARRAY_SIZE(ftm_headset_mono_rx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_headset_mono_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ftm_headset_mono_rx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_headset_mono_rx_settings),
+};
+
+static struct snddev_icodec_data ftm_headset_mono_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "ftm_headset_mono_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &ftm_headset_mono_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.voltage_on = msm_snddev_voltage_on,
+	.voltage_off = msm_snddev_voltage_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_headset_mono_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_headset_mono_rx_data},
+};
+
+static struct adie_codec_action_unit ftm_headset_mono_diff_rx_actions[] =
+	HEADSET_MONO_DIFF_RX;
+
+static struct adie_codec_hwsetting_entry ftm_headset_mono_diff_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_headset_mono_diff_rx_actions,
+		.action_sz = ARRAY_SIZE(ftm_headset_mono_diff_rx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_headset_mono_diff_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ftm_headset_mono_diff_rx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_headset_mono_diff_rx_settings),
+};
+
+static struct snddev_icodec_data ftm_headset_mono_diff_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "ftm_headset_mono_diff_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &ftm_headset_mono_diff_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.voltage_on = msm_snddev_voltage_on,
+	.voltage_off = msm_snddev_voltage_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_headset_mono_diff_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_headset_mono_diff_rx_data},
+};
+
+static struct adie_codec_action_unit ftm_spkr_mono_rx_actions[] =
+	SPEAKER_PRI_STEREO_48000_OSR_256;
+
+static struct adie_codec_hwsetting_entry ftm_spkr_mono_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_spkr_mono_rx_actions,
+		.action_sz = ARRAY_SIZE(ftm_spkr_mono_rx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_spkr_mono_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ftm_spkr_mono_rx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_spkr_mono_rx_settings),
+};
+
+static struct snddev_icodec_data ftm_spkr_mono_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "ftm_spkr_mono_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &ftm_spkr_mono_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_poweramp_on,
+	.pamp_off = msm_snddev_poweramp_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_spkr_mono_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_spkr_mono_rx_data},
+};
+
+static struct adie_codec_action_unit ftm_spkr_l_rx_actions[] =
+	FTM_SPKR_L_RX;
+
+static struct adie_codec_hwsetting_entry ftm_spkr_l_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_spkr_l_rx_actions,
+		.action_sz = ARRAY_SIZE(ftm_spkr_l_rx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_spkr_l_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ftm_spkr_l_rx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_spkr_l_rx_settings),
+};
+
+static struct snddev_icodec_data ftm_spkr_l_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "ftm_spkr_l_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &ftm_spkr_l_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_poweramp_on,
+	.pamp_off = msm_snddev_poweramp_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_spkr_l_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_spkr_l_rx_data},
+};
+
+static struct adie_codec_action_unit ftm_spkr_r_rx_actions[] =
+	SPKR_R_RX;
+
+static struct adie_codec_hwsetting_entry ftm_spkr_r_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_spkr_r_rx_actions,
+		.action_sz = ARRAY_SIZE(ftm_spkr_r_rx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_spkr_r_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ftm_spkr_r_rx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_spkr_r_rx_settings),
+};
+
+static struct snddev_icodec_data ftm_spkr_r_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "ftm_spkr_r_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &ftm_spkr_r_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_poweramp_on,
+	.pamp_off = msm_snddev_poweramp_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_spkr_r_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_spkr_r_rx_data},
+};
+
+static struct adie_codec_action_unit ftm_spkr_mono_diff_rx_actions[] =
+	SPKR_MONO_DIFF_RX;
+
+static struct adie_codec_hwsetting_entry ftm_spkr_mono_diff_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_spkr_mono_diff_rx_actions,
+		.action_sz = ARRAY_SIZE(ftm_spkr_mono_diff_rx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_spkr_mono_diff_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ftm_spkr_mono_diff_rx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_spkr_mono_diff_rx_settings),
+};
+
+static struct snddev_icodec_data ftm_spkr_mono_diff_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "ftm_spkr_mono_diff_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &ftm_spkr_mono_diff_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_poweramp_on,
+	.pamp_off = msm_snddev_poweramp_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_spkr_mono_diff_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_spkr_mono_diff_rx_data},
+};
+
+static struct adie_codec_action_unit ftm_headset_mono_l_rx_actions[] =
+	HPH_PRI_AB_CPLS_MONO_LEFT;
+
+static struct adie_codec_hwsetting_entry ftm_headset_mono_l_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_headset_mono_l_rx_actions,
+		.action_sz = ARRAY_SIZE(ftm_headset_mono_l_rx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_headset_mono_l_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ftm_headset_mono_l_rx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_headset_mono_l_rx_settings),
+};
+
+static struct snddev_icodec_data ftm_headset_mono_l_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "ftm_headset_mono_l_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &ftm_headset_mono_l_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.voltage_on = msm_snddev_voltage_on,
+	.voltage_off = msm_snddev_voltage_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_headset_mono_l_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_headset_mono_l_rx_data},
+};
+
+static struct adie_codec_action_unit ftm_headset_mono_r_rx_actions[] =
+	HPH_PRI_AB_CPLS_MONO_RIGHT;
+
+static struct adie_codec_hwsetting_entry ftm_headset_mono_r_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_headset_mono_r_rx_actions,
+		.action_sz = ARRAY_SIZE(ftm_headset_mono_r_rx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_headset_mono_r_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ftm_headset_mono_r_rx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_headset_mono_r_rx_settings),
+};
+
+static struct snddev_icodec_data ftm_headset_mono_r_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "ftm_headset_mono_r_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &ftm_headset_mono_r_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.voltage_on = msm_snddev_voltage_on,
+	.voltage_off = msm_snddev_voltage_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_headset_mono_r_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_headset_mono_r_rx_data},
+};
+
+static struct adie_codec_action_unit ftm_linein_l_tx_actions[] =
+	LINEIN_MONO_L_TX;
+
+static struct adie_codec_hwsetting_entry ftm_linein_l_tx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_linein_l_tx_actions,
+		.action_sz = ARRAY_SIZE(ftm_linein_l_tx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_linein_l_tx_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = ftm_linein_l_tx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_linein_l_tx_settings),
+};
+
+static struct snddev_icodec_data ftm_linein_l_tx_data = {
+	.capability = SNDDEV_CAP_TX,
+	.name = "ftm_linein_l_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &ftm_linein_l_tx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_linein_l_tx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_linein_l_tx_data },
+};
+
+static struct adie_codec_action_unit ftm_linein_r_tx_actions[] =
+	LINEIN_MONO_R_TX;
+
+static struct adie_codec_hwsetting_entry ftm_linein_r_tx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_linein_r_tx_actions,
+		.action_sz = ARRAY_SIZE(ftm_linein_r_tx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_linein_r_tx_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = ftm_linein_r_tx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_linein_r_tx_settings),
+};
+
+static struct snddev_icodec_data ftm_linein_r_tx_data = {
+	.capability = SNDDEV_CAP_TX,
+	.name = "ftm_linein_r_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &ftm_linein_r_tx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_linein_r_tx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_linein_r_tx_data },
+};
+
+static struct adie_codec_action_unit ftm_aux_out_rx_actions[] =
+	AUX_OUT_RX;
+
+static struct adie_codec_hwsetting_entry ftm_aux_out_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_aux_out_rx_actions,
+		.action_sz = ARRAY_SIZE(ftm_aux_out_rx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_aux_out_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ftm_aux_out_rx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_aux_out_rx_settings),
+};
+
+static struct snddev_icodec_data ftm_aux_out_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "ftm_aux_out_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &ftm_aux_out_rx_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_aux_out_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_aux_out_rx_data},
+};
+
+static struct adie_codec_action_unit ftm_dmic1_left_tx_actions[] =
+	DMIC1_LEFT_TX;
+
+static struct adie_codec_hwsetting_entry ftm_dmic1_left_tx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_dmic1_left_tx_actions,
+		.action_sz = ARRAY_SIZE(ftm_dmic1_left_tx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_dmic1_left_tx_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = ftm_dmic1_left_tx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_dmic1_left_tx_settings),
+};
+
+static struct snddev_icodec_data ftm_dmic1_left_tx_data = {
+	.capability = SNDDEV_CAP_TX,
+	.name = "ftm_dmic1_left_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &ftm_dmic1_left_tx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_dmic_power,
+	.pamp_off = msm_snddev_disable_dmic_power,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_dmic1_left_tx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_dmic1_left_tx_data},
+};
+
+static struct adie_codec_action_unit ftm_dmic1_right_tx_actions[] =
+	DMIC1_RIGHT_TX;
+
+static struct adie_codec_hwsetting_entry ftm_dmic1_right_tx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_dmic1_right_tx_actions,
+		.action_sz = ARRAY_SIZE(ftm_dmic1_right_tx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_dmic1_right_tx_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = ftm_dmic1_right_tx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_dmic1_right_tx_settings),
+};
+
+static struct snddev_icodec_data ftm_dmic1_right_tx_data = {
+	.capability = SNDDEV_CAP_TX,
+	.name = "ftm_dmic1_right_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &ftm_dmic1_right_tx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_dmic_power,
+	.pamp_off = msm_snddev_disable_dmic_power,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_dmic1_right_tx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_dmic1_right_tx_data},
+};
+
+static struct adie_codec_action_unit ftm_dmic1_l_and_r_tx_actions[] =
+	DMIC1_LEFT_AND_RIGHT_TX;
+
+static struct adie_codec_hwsetting_entry ftm_dmic1_l_and_r_tx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_dmic1_l_and_r_tx_actions,
+		.action_sz = ARRAY_SIZE(ftm_dmic1_l_and_r_tx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_dmic1_l_and_r_tx_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = ftm_dmic1_l_and_r_tx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_dmic1_l_and_r_tx_settings),
+};
+
+static struct snddev_icodec_data ftm_dmic1_l_and_r_tx_data = {
+	.capability = SNDDEV_CAP_TX,
+	.name = "ftm_dmic1_l_and_r_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &ftm_dmic1_l_and_r_tx_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_dmic_power,
+	.pamp_off = msm_snddev_disable_dmic_power,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_dmic1_l_and_r_tx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_dmic1_l_and_r_tx_data},
+};
+
+static struct adie_codec_action_unit ftm_dmic2_left_tx_actions[] =
+	DMIC2_LEFT_TX;
+
+static struct adie_codec_hwsetting_entry ftm_dmic2_left_tx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_dmic2_left_tx_actions,
+		.action_sz = ARRAY_SIZE(ftm_dmic2_left_tx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_dmic2_left_tx_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = ftm_dmic2_left_tx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_dmic2_left_tx_settings),
+};
+
+static struct snddev_icodec_data ftm_dmic2_left_tx_data = {
+	.capability = SNDDEV_CAP_TX,
+	.name = "ftm_dmic2_left_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &ftm_dmic2_left_tx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_dmic_power,
+	.pamp_off = msm_snddev_disable_dmic_power,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_dmic2_left_tx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_dmic2_left_tx_data },
+};
+
+static struct adie_codec_action_unit ftm_dmic2_right_tx_actions[] =
+	DMIC2_RIGHT_TX;
+
+static struct adie_codec_hwsetting_entry ftm_dmic2_right_tx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_dmic2_right_tx_actions,
+		.action_sz = ARRAY_SIZE(ftm_dmic2_right_tx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_dmic2_right_tx_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = ftm_dmic2_right_tx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_dmic2_right_tx_settings),
+};
+
+static struct snddev_icodec_data ftm_dmic2_right_tx_data = {
+	.capability = SNDDEV_CAP_TX,
+	.name = "ftm_dmic2_right_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &ftm_dmic2_right_tx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_dmic_power,
+	.pamp_off = msm_snddev_disable_dmic_power,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_dmic2_right_tx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_dmic2_right_tx_data },
+};
+
+static struct adie_codec_action_unit ftm_dmic2_l_and_r_tx_actions[] =
+	DMIC2_LEFT_AND_RIGHT_TX;
+
+static struct adie_codec_hwsetting_entry ftm_dmic2_l_and_r_tx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_dmic2_l_and_r_tx_actions,
+		.action_sz = ARRAY_SIZE(ftm_dmic2_l_and_r_tx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_dmic2_l_and_r_tx_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = ftm_dmic2_l_and_r_tx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_dmic2_l_and_r_tx_settings),
+};
+
+static struct snddev_icodec_data ftm_dmic2_l_and_r_tx_data = {
+	.capability = SNDDEV_CAP_TX,
+	.name = "ftm_dmic2_l_and_r_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &ftm_dmic2_l_and_r_tx_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_dmic_power,
+	.pamp_off = msm_snddev_disable_dmic_power,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_dmic2_l_and_r_tx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_dmic2_l_and_r_tx_data},
+};
+
+static struct adie_codec_action_unit ftm_handset_mic1_aux_in_actions[] =
+	HANDSET_MIC1_AUX_IN;
+
+static struct adie_codec_hwsetting_entry ftm_handset_mic1_aux_in_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_handset_mic1_aux_in_actions,
+		.action_sz = ARRAY_SIZE(ftm_handset_mic1_aux_in_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_handset_mic1_aux_in_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = ftm_handset_mic1_aux_in_settings,
+	.setting_sz = ARRAY_SIZE(ftm_handset_mic1_aux_in_settings),
+};
+
+static struct snddev_icodec_data ftm_handset_mic1_aux_in_data = {
+	.capability = SNDDEV_CAP_TX,
+	.name = "ftm_handset_mic1_aux_in",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &ftm_handset_mic1_aux_in_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	/* Assumption is that inputs are not tied to analog mic, so
+	 * no need to enable mic bias.
+	 */
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_handset_mic1_aux_in_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_handset_mic1_aux_in_data},
+};
+
+static struct snddev_mi2s_data snddev_mi2s_sd0_rx_data = {
+	.capability = SNDDEV_CAP_RX ,
+	.name = "mi2s_sd0_rx",
+	.copp_id = MI2S_RX,
+	.channel_mode = 2, /* stereo */
+	.sd_lines = MI2S_SD0, /* sd0 */
+	.sample_rate = 48000,
+};
+
+static struct platform_device ftm_mi2s_sd0_rx_device = {
+	.name = "snddev_mi2s",
+	.dev = { .platform_data = &snddev_mi2s_sd0_rx_data },
+};
+
+static struct snddev_mi2s_data snddev_mi2s_sd1_rx_data = {
+	.capability = SNDDEV_CAP_RX ,
+	.name = "mi2s_sd1_rx",
+	.copp_id = MI2S_RX,
+	.channel_mode = 2, /* stereo */
+	.sd_lines = MI2S_SD1, /* sd1 */
+	.sample_rate = 48000,
+};
+
+static struct platform_device ftm_mi2s_sd1_rx_device = {
+	.name = "snddev_mi2s",
+	.dev = { .platform_data = &snddev_mi2s_sd1_rx_data },
+};
+
+static struct snddev_mi2s_data snddev_mi2s_sd2_rx_data = {
+	.capability = SNDDEV_CAP_RX ,
+	.name = "mi2s_sd2_rx",
+	.copp_id = MI2S_RX,
+	.channel_mode = 2, /* stereo */
+	.sd_lines = MI2S_SD2, /* sd2 */
+	.sample_rate = 48000,
+};
+
+static struct platform_device ftm_mi2s_sd2_rx_device = {
+	.name = "snddev_mi2s",
+	.dev = { .platform_data = &snddev_mi2s_sd2_rx_data },
+};
+
+/* earpiece */
+static struct adie_codec_action_unit ftm_handset_adie_lp_rx_actions[] =
+	EAR_PRI_MONO_LB;
+
+static struct adie_codec_hwsetting_entry ftm_handset_adie_lp_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_handset_adie_lp_rx_actions,
+		.action_sz = ARRAY_SIZE(ftm_handset_adie_lp_rx_actions),
+	}
+};
+
+static struct adie_codec_dev_profile ftm_handset_adie_lp_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ftm_handset_adie_lp_rx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_handset_adie_lp_rx_settings),
+};
+
+static struct snddev_icodec_data ftm_handset_adie_lp_rx_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE),
+	.name = "ftm_handset_adie_lp_rx",
+	.copp_id = 0,
+	.profile = &ftm_handset_adie_lp_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_handset_adie_lp_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_handset_adie_lp_rx_data },
+};
+
+static struct adie_codec_action_unit ftm_headset_l_adie_lp_rx_actions[] =
+	FTM_HPH_PRI_AB_CPLS_MONO_LB_LEFT;
+
+static struct adie_codec_hwsetting_entry ftm_headset_l_adie_lp_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_headset_l_adie_lp_rx_actions,
+		.action_sz = ARRAY_SIZE(ftm_headset_l_adie_lp_rx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_headset_l_adie_lp_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ftm_headset_l_adie_lp_rx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_headset_l_adie_lp_rx_settings),
+};
+
+static struct snddev_icodec_data ftm_headset_l_adie_lp_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "ftm_headset_l_adie_lp_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &ftm_headset_l_adie_lp_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.voltage_on = msm_snddev_voltage_on,
+	.voltage_off = msm_snddev_voltage_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_headset_l_adie_lp_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_headset_l_adie_lp_rx_data },
+};
+
+static struct adie_codec_action_unit ftm_headset_r_adie_lp_rx_actions[] =
+	FTM_HPH_PRI_AB_CPLS_MONO_LB_RIGHT;
+
+static struct adie_codec_hwsetting_entry ftm_headset_r_adie_lp_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_headset_r_adie_lp_rx_actions,
+		.action_sz = ARRAY_SIZE(ftm_headset_r_adie_lp_rx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_headset_r_adie_lp_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ftm_headset_r_adie_lp_rx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_headset_r_adie_lp_rx_settings),
+};
+
+static struct snddev_icodec_data ftm_headset_r_adie_lp_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "ftm_headset_r_adie_lp_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &ftm_headset_r_adie_lp_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.voltage_on = msm_snddev_voltage_on,
+	.voltage_off = msm_snddev_voltage_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_headset_r_adie_lp_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_headset_r_adie_lp_rx_data },
+};
+
+static struct adie_codec_action_unit ftm_spkr_l_rx_lp_actions[] =
+	FTM_SPKR_L_RX;
+
+static struct adie_codec_hwsetting_entry ftm_spkr_l_rx_lp_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_spkr_l_rx_lp_actions,
+		.action_sz = ARRAY_SIZE(ftm_spkr_l_rx_lp_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_spkr_l_rx_lp_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ftm_spkr_l_rx_lp_settings,
+	.setting_sz = ARRAY_SIZE(ftm_spkr_l_rx_lp_settings),
+};
+
+static struct snddev_icodec_data ftm_spkr_l_rx_lp_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "ftm_spk_l_adie_lp_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &ftm_spkr_l_rx_lp_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_poweramp_on,
+	.pamp_off = msm_snddev_poweramp_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_spk_l_adie_lp_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_spkr_l_rx_lp_data},
+};
+
+static struct adie_codec_action_unit ftm_spkr_r_adie_lp_rx_actions[] =
+	SPKR_R_RX;
+
+static struct adie_codec_hwsetting_entry ftm_spkr_r_adie_lp_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_spkr_r_adie_lp_rx_actions,
+		.action_sz = ARRAY_SIZE(ftm_spkr_r_adie_lp_rx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_spkr_r_adie_lp_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ftm_spkr_r_adie_lp_rx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_spkr_r_adie_lp_rx_settings),
+};
+
+static struct snddev_icodec_data ftm_spkr_r_adie_lp_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "ftm_spk_r_adie_lp_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &ftm_spkr_r_adie_lp_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_poweramp_on,
+	.pamp_off = msm_snddev_poweramp_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_spk_r_adie_lp_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_spkr_r_adie_lp_rx_data},
+};
+
+static struct adie_codec_action_unit ftm_spkr_adie_lp_rx_actions[] =
+	FTM_SPKR_RX_LB;
+
+static struct adie_codec_hwsetting_entry ftm_spkr_adie_lp_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_spkr_adie_lp_rx_actions,
+		.action_sz = ARRAY_SIZE(ftm_spkr_adie_lp_rx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_spkr_adie_lp_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ftm_spkr_adie_lp_rx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_spkr_adie_lp_rx_settings),
+};
+
+static struct snddev_icodec_data ftm_spkr_adie_lp_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "ftm_spk_adie_lp_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &ftm_spkr_adie_lp_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_poweramp_on,
+	.pamp_off = msm_snddev_poweramp_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_spk_adie_lp_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_spkr_adie_lp_rx_data},
+};
+
+static struct adie_codec_action_unit ftm_handset_dual_tx_lp_actions[] =
+	FTM_AMIC_DUAL_HANDSET_TX_LB;
+
+static struct adie_codec_hwsetting_entry ftm_handset_dual_tx_lp_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_handset_dual_tx_lp_actions,
+		.action_sz = ARRAY_SIZE(ftm_handset_dual_tx_lp_actions),
+	}
+};
+
+static struct adie_codec_dev_profile ftm_handset_dual_tx_lp_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = ftm_handset_dual_tx_lp_settings,
+	.setting_sz = ARRAY_SIZE(ftm_handset_dual_tx_lp_settings),
+};
+
+static struct snddev_icodec_data ftm_handset_dual_tx_lp_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "handset_mic1_handset_mic2",
+	.copp_id = 1,
+	.profile = &ftm_handset_dual_tx_lp_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_amic_power,
+	.pamp_off = msm_snddev_disable_amic_power,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_handset_dual_tx_lp_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_handset_dual_tx_lp_data },
+};
+
+static struct adie_codec_action_unit ftm_handset_mic_adie_lp_tx_actions[] =
+	FTM_HANDSET_LB_TX;
+
+static struct adie_codec_hwsetting_entry
+	ftm_handset_mic_adie_lp_tx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_handset_mic_adie_lp_tx_actions,
+		.action_sz = ARRAY_SIZE(ftm_handset_mic_adie_lp_tx_actions),
+	}
+};
+
+static struct adie_codec_dev_profile ftm_handset_mic_adie_lp_tx_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = ftm_handset_mic_adie_lp_tx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_handset_mic_adie_lp_tx_settings),
+};
+
+static struct snddev_icodec_data ftm_handset_mic_adie_lp_tx_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "ftm_handset_mic_adie_lp_tx",
+	.copp_id = 1,
+	.profile = &ftm_handset_mic_adie_lp_tx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_amic_power,
+	.pamp_off = msm_snddev_disable_amic_power,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_handset_mic_adie_lp_tx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_handset_mic_adie_lp_tx_data },
+};
+
+static struct adie_codec_action_unit ftm_headset_mic_adie_lp_tx_actions[] =
+	FTM_HEADSET_LB_TX;
+
+static struct adie_codec_hwsetting_entry
+			ftm_headset_mic_adie_lp_tx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_headset_mic_adie_lp_tx_actions,
+		.action_sz = ARRAY_SIZE(ftm_headset_mic_adie_lp_tx_actions),
+	}
+};
+
+static struct adie_codec_dev_profile ftm_headset_mic_adie_lp_tx_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = ftm_headset_mic_adie_lp_tx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_headset_mic_adie_lp_tx_settings),
+};
+
+static struct snddev_icodec_data ftm_headset_mic_adie_lp_tx_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "ftm_headset_mic_adie_lp_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &ftm_headset_mic_adie_lp_tx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_headset_mic_adie_lp_tx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_headset_mic_adie_lp_tx_data },
+};
+#endif /* CONFIG_MSM8X60_FTM_AUDIO_DEVICES */
+
+static struct snddev_virtual_data snddev_uplink_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "uplink_rx",
+	.copp_id = VOICE_PLAYBACK_TX,
+};
+
+static struct platform_device msm_uplink_rx_device = {
+	.name = "snddev_virtual",
+	.dev = { .platform_data = &snddev_uplink_rx_data },
+};
+
+static struct snddev_hdmi_data snddev_hdmi_non_linear_pcm_rx_data = {
+	.capability = SNDDEV_CAP_RX ,
+	.name = "hdmi_pass_through",
+	.default_sample_rate = 48000,
+	.on_apps = 1,
+};
+
+static struct platform_device msm_snddev_hdmi_non_linear_pcm_rx_device = {
+	.name = "snddev_hdmi",
+	.dev = { .platform_data = &snddev_hdmi_non_linear_pcm_rx_data },
+};
+
+
+#ifdef CONFIG_DEBUG_FS
+static struct adie_codec_action_unit
+	ihs_stereo_rx_class_d_legacy_48KHz_osr256_actions[] =
+	HPH_PRI_D_LEG_STEREO;
+
+static struct adie_codec_hwsetting_entry
+	ihs_stereo_rx_class_d_legacy_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions =
+		ihs_stereo_rx_class_d_legacy_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE
+		(ihs_stereo_rx_class_d_legacy_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_action_unit
+	ihs_stereo_rx_class_ab_legacy_48KHz_osr256_actions[] =
+	HPH_PRI_AB_LEG_STEREO;
+
+static struct adie_codec_hwsetting_entry
+	ihs_stereo_rx_class_ab_legacy_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions =
+		ihs_stereo_rx_class_ab_legacy_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE
+		(ihs_stereo_rx_class_ab_legacy_48KHz_osr256_actions),
+	}
+};
+
+static void snddev_hsed_config_modify_setting(int type)
+{
+	struct platform_device *device;
+	struct snddev_icodec_data *icodec_data;
+
+	device = &msm_headset_stereo_device;
+	icodec_data = (struct snddev_icodec_data *)device->dev.platform_data;
+
+	if (icodec_data) {
+		if (type == 1) {
+			icodec_data->voltage_on = NULL;
+			icodec_data->voltage_off = NULL;
+			icodec_data->profile->settings =
+				ihs_stereo_rx_class_d_legacy_settings;
+			icodec_data->profile->setting_sz =
+			ARRAY_SIZE(ihs_stereo_rx_class_d_legacy_settings);
+		} else if (type == 2) {
+			icodec_data->voltage_on = NULL;
+			icodec_data->voltage_off = NULL;
+			icodec_data->profile->settings =
+				ihs_stereo_rx_class_ab_legacy_settings;
+			icodec_data->profile->setting_sz =
+			ARRAY_SIZE(ihs_stereo_rx_class_ab_legacy_settings);
+		}
+	}
+}
+
+static void snddev_hsed_config_restore_setting(void)
+{
+	struct platform_device *device;
+	struct snddev_icodec_data *icodec_data;
+
+	device = &msm_headset_stereo_device;
+	icodec_data = (struct snddev_icodec_data *)device->dev.platform_data;
+
+	if (icodec_data) {
+		icodec_data->voltage_on = msm_snddev_voltage_on;
+		icodec_data->voltage_off = msm_snddev_voltage_off;
+		icodec_data->profile->settings = headset_ab_cpls_settings;
+		icodec_data->profile->setting_sz =
+			ARRAY_SIZE(headset_ab_cpls_settings);
+	}
+}
+
+static ssize_t snddev_hsed_config_debug_write(struct file *filp,
+	const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	char *lb_str = filp->private_data;
+	char cmd;
+
+	if (get_user(cmd, ubuf))
+		return -EFAULT;
+
+	if (!strcmp(lb_str, "msm_hsed_config")) {
+		switch (cmd) {
+		case '0':
+			snddev_hsed_config_restore_setting();
+			break;
+
+		case '1':
+			snddev_hsed_config_modify_setting(1);
+			break;
+
+		case '2':
+			snddev_hsed_config_modify_setting(2);
+			break;
+
+		default:
+			break;
+		}
+	}
+	return cnt;
+}
+
+static int snddev_hsed_config_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static const struct file_operations snddev_hsed_config_debug_fops = {
+	.open = snddev_hsed_config_debug_open,
+	.write = snddev_hsed_config_debug_write
+};
+#endif
+
+static struct platform_device *snd_devices_ffa[] __initdata = {
+	&msm_iearpiece_ffa_device,
+	&msm_imic_ffa_device,
+	&msm_ispkr_stereo_device,
+	&msm_snddev_hdmi_stereo_rx_device,
+	&msm_headset_mic_device,
+	&msm_ispkr_mic_device,
+	&msm_bt_sco_earpiece_device,
+	&msm_bt_sco_mic_device,
+	&msm_headset_stereo_device,
+	&msm_itty_mono_tx_device,
+	&msm_itty_mono_rx_device,
+	&msm_mi2s_fm_tx_device,
+	&msm_mi2s_fm_rx_device,
+	&msm_hs_dual_mic_endfire_device,
+	&msm_spkr_dual_mic_endfire_device,
+	&msm_hs_dual_mic_broadside_device,
+	&msm_spkr_dual_mic_broadside_device,
+	&msm_ihs_stereo_speaker_stereo_rx_device,
+	&msm_anc_headset_device,
+	&msm_auxpga_lp_hs_device,
+	&msm_auxpga_lp_lo_device,
+	&msm_linein_pri_device,
+	&msm_icodec_gpio_device,
+	&msm_snddev_hdmi_non_linear_pcm_rx_device,
+};
+
+static struct platform_device *snd_devices_surf[] __initdata = {
+	&msm_iearpiece_device,
+	&msm_imic_device,
+	&msm_ispkr_stereo_device,
+	&msm_snddev_hdmi_stereo_rx_device,
+	&msm_headset_mic_device,
+	&msm_ispkr_mic_device,
+	&msm_bt_sco_earpiece_device,
+	&msm_bt_sco_mic_device,
+	&msm_headset_stereo_device,
+	&msm_itty_mono_tx_device,
+	&msm_itty_mono_rx_device,
+	&msm_mi2s_fm_tx_device,
+	&msm_mi2s_fm_rx_device,
+	&msm_ihs_stereo_speaker_stereo_rx_device,
+	&msm_auxpga_lp_hs_device,
+	&msm_auxpga_lp_lo_device,
+	&msm_linein_pri_device,
+	&msm_icodec_gpio_device,
+	&msm_snddev_hdmi_non_linear_pcm_rx_device,
+};
+
+static struct platform_device *snd_devices_fluid[] __initdata = {
+	&msm_iearpiece_device,
+	&msm_imic_device,
+	&msm_ispkr_stereo_device,
+	&msm_snddev_hdmi_stereo_rx_device,
+	&msm_headset_stereo_device,
+	&msm_headset_mic_device,
+	&msm_fluid_ispkr_mic_device,
+	&msm_bt_sco_earpiece_device,
+	&msm_bt_sco_mic_device,
+	&msm_mi2s_fm_tx_device,
+	&msm_mi2s_fm_rx_device,
+	&msm_fluid_hs_dual_mic_endfire_device,
+	&msm_fluid_spkr_dual_mic_endfire_device,
+	&msm_fluid_hs_dual_mic_broadside_device,
+	&msm_fluid_spkr_dual_mic_broadside_device,
+	&msm_anc_headset_device,
+	&msm_auxpga_lp_hs_device,
+	&msm_auxpga_lp_lo_device,
+	&msm_icodec_gpio_device,
+	&msm_snddev_hdmi_non_linear_pcm_rx_device,
+};
+
+static struct platform_device *snd_devices_common[] __initdata = {
+	&msm_aux_pcm_device,
+	&msm_cdcclk_ctl_device,
+	&msm_mi2s_device,
+	&msm_uplink_rx_device,
+	&msm_device_dspcrashd_8x60,
+};
+
+#ifdef CONFIG_MSM8X60_FTM_AUDIO_DEVICES
+static struct platform_device *snd_devices_ftm[] __initdata = {
+	&ftm_headset_mono_rx_device,
+	&ftm_headset_mono_l_rx_device,
+	&ftm_headset_mono_r_rx_device,
+	&ftm_headset_mono_diff_rx_device,
+	&ftm_spkr_mono_rx_device,
+	&ftm_spkr_l_rx_device,
+	&ftm_spkr_r_rx_device,
+	&ftm_spkr_mono_diff_rx_device,
+	&ftm_linein_l_tx_device,
+	&ftm_linein_r_tx_device,
+	&ftm_aux_out_rx_device,
+	&ftm_dmic1_left_tx_device,
+	&ftm_dmic1_right_tx_device,
+	&ftm_dmic1_l_and_r_tx_device,
+	&ftm_dmic2_left_tx_device,
+	&ftm_dmic2_right_tx_device,
+	&ftm_dmic2_l_and_r_tx_device,
+	&ftm_handset_mic1_aux_in_device,
+	&ftm_mi2s_sd0_rx_device,
+	&ftm_mi2s_sd1_rx_device,
+	&ftm_mi2s_sd2_rx_device,
+	&ftm_handset_mic_adie_lp_tx_device,
+	&ftm_headset_mic_adie_lp_tx_device,
+	&ftm_handset_adie_lp_rx_device,
+	&ftm_headset_l_adie_lp_rx_device,
+	&ftm_headset_r_adie_lp_rx_device,
+	&ftm_spk_l_adie_lp_rx_device,
+	&ftm_spk_r_adie_lp_rx_device,
+	&ftm_spk_adie_lp_rx_device,
+	&ftm_handset_dual_tx_lp_device,
+};
+#else
+static struct platform_device *snd_devices_ftm[] __initdata = {};
+#endif
+
+
+void __init msm_snddev_init(void)
+{
+	int i;
+	int dev_id;
+
+	atomic_set(&pamp_ref_cnt, 0);
+	atomic_set(&preg_ref_cnt, 0);
+
+	for (i = 0, dev_id = 0; i < ARRAY_SIZE(snd_devices_common); i++)
+		snd_devices_common[i]->id = dev_id++;
+
+	platform_add_devices(snd_devices_common,
+		ARRAY_SIZE(snd_devices_common));
+
+	/* Auto detect device base on machine info */
+	if (machine_is_msm8x60_surf() || machine_is_msm8x60_fusion()) {
+		for (i = 0; i < ARRAY_SIZE(snd_devices_surf); i++)
+			snd_devices_surf[i]->id = dev_id++;
+
+		platform_add_devices(snd_devices_surf,
+		ARRAY_SIZE(snd_devices_surf));
+	} else if (machine_is_msm8x60_ffa() ||
+			machine_is_msm8x60_fusn_ffa()) {
+		for (i = 0; i < ARRAY_SIZE(snd_devices_ffa); i++)
+			snd_devices_ffa[i]->id = dev_id++;
+
+		platform_add_devices(snd_devices_ffa,
+		ARRAY_SIZE(snd_devices_ffa));
+	} else if (machine_is_msm8x60_fluid()) {
+		for (i = 0; i < ARRAY_SIZE(snd_devices_fluid); i++)
+			snd_devices_fluid[i]->id = dev_id++;
+
+		platform_add_devices(snd_devices_fluid,
+		ARRAY_SIZE(snd_devices_fluid));
+	}
+	if (machine_is_msm8x60_surf() || machine_is_msm8x60_ffa()
+		|| machine_is_msm8x60_fusion()
+		|| machine_is_msm8x60_fusn_ffa()) {
+		for (i = 0; i < ARRAY_SIZE(snd_devices_ftm); i++)
+			snd_devices_ftm[i]->id = dev_id++;
+
+		platform_add_devices(snd_devices_ftm,
+				ARRAY_SIZE(snd_devices_ftm));
+	}
+
+#ifdef CONFIG_DEBUG_FS
+	debugfs_hsed_config = debugfs_create_file("msm_hsed_config",
+				S_IFREG | S_IRUGO, NULL,
+		(void *) "msm_hsed_config", &snddev_hsed_config_debug_fops);
+#endif
+}
diff --git a/arch/arm/mach-msm/qdsp6v2/dsp_debug.c b/arch/arm/mach-msm/qdsp6v2/dsp_debug.c
new file mode 100644
index 0000000..3635fbd
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/dsp_debug.c
@@ -0,0 +1,259 @@
+/* arch/arm/mach-msm/qdsp6/dsp_dump.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <asm/atomic.h>
+
+#include <mach/proc_comm.h>
+#include <mach/debug_mm.h>
+#include <mach/qdsp6v2/dsp_debug.h>
+
+static wait_queue_head_t dsp_wait;
+static int dsp_has_crashed;
+static int dsp_wait_count;
+
+static atomic_t dsp_crash_count = ATOMIC_INIT(0);
+dsp_state_cb cb_ptr;
+
+void q6audio_dsp_not_responding(void)
+{
+	if (cb_ptr)
+		cb_ptr(DSP_STATE_CRASHED);
+	if (atomic_add_return(1, &dsp_crash_count) != 1) {
+		pr_err("q6audio_dsp_not_responding() \
+			- parking additional crasher...\n");
+		for (;;)
+			msleep(1000);
+	}
+	if (dsp_wait_count) {
+		dsp_has_crashed = 1;
+		wake_up(&dsp_wait);
+
+		while (dsp_has_crashed != 2)
+			wait_event(dsp_wait, dsp_has_crashed == 2);
+	} else {
+		pr_err("q6audio_dsp_not_responding() - no waiter?\n");
+	}
+	if (cb_ptr)
+		cb_ptr(DSP_STATE_CRASH_DUMP_DONE);
+}
+
+static int dsp_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+#define DSP_NMI_ADDR 0x28800010
+
+static ssize_t dsp_write(struct file *file, const char __user *buf,
+			 size_t count, loff_t *pos)
+{
+	char cmd[32];
+	void __iomem *ptr;
+	void *mem_buffer;
+
+	if (count >= sizeof(cmd))
+		return -EINVAL;
+	if (copy_from_user(cmd, buf, count))
+		return -EFAULT;
+	cmd[count] = 0;
+
+	if ((count > 1) && (cmd[count-1] == '\n'))
+		cmd[count-1] = 0;
+
+	if (!strcmp(cmd, "wait-for-crash")) {
+		while (!dsp_has_crashed) {
+			int res;
+			dsp_wait_count++;
+			res = wait_event_interruptible(dsp_wait,
+							dsp_has_crashed);
+			if (res < 0) {
+				dsp_wait_count--;
+				return res;
+			}
+		}
+		/* assert DSP NMI */
+		mem_buffer = ioremap(DSP_NMI_ADDR, 0x16);
+		if (IS_ERR((void *)mem_buffer)) {
+			pr_err("%s:map_buffer failed, error = %ld\n", __func__,
+				   PTR_ERR((void *)mem_buffer));
+			return -ENOMEM;
+		}
+		ptr = mem_buffer;
+		if (!ptr) {
+			pr_err("Unable to map DSP NMI\n");
+			return -EFAULT;
+		}
+		writel(0x1, (void *)ptr);
+		iounmap(mem_buffer);
+	} else if (!strcmp(cmd, "boom")) {
+		q6audio_dsp_not_responding();
+	} else if (!strcmp(cmd, "continue-crash")) {
+		dsp_has_crashed = 2;
+		wake_up(&dsp_wait);
+	} else {
+		pr_err("[%s:%s] unknown dsp_debug command: %s\n", __MM_FILE__,
+				__func__, cmd);
+	}
+
+	return count;
+}
+
+static unsigned copy_ok_count;
+static uint32_t dsp_ram_size;
+static uint32_t dsp_ram_base;
+
+static ssize_t dsp_read(struct file *file, char __user *buf,
+			size_t count, loff_t *pos)
+{
+	size_t actual = 0;
+	size_t mapsize = PAGE_SIZE;
+	unsigned addr;
+	void __iomem *ptr;
+	void *mem_buffer;
+
+	if ((dsp_ram_base == 0) || (dsp_ram_size == 0)) {
+		pr_err("[%s:%s] Memory Invalid or not initialized, Base = 0x%x,"
+			   " size = 0x%x\n", __MM_FILE__,
+				__func__, dsp_ram_base, dsp_ram_size);
+		return -EINVAL;
+	}
+
+	if (*pos >= dsp_ram_size)
+		return 0;
+
+	if (*pos & (PAGE_SIZE - 1))
+		return -EINVAL;
+
+	addr = (*pos + dsp_ram_base);
+
+	/* don't blow up if we're unaligned */
+	if (addr & (PAGE_SIZE - 1))
+		mapsize *= 2;
+
+	while (count >= PAGE_SIZE) {
+		mem_buffer = ioremap(addr, mapsize);
+		if (IS_ERR((void *)mem_buffer)) {
+			pr_err("%s:map_buffer failed, error = %ld\n",
+				__func__, PTR_ERR((void *)mem_buffer));
+			return -ENOMEM;
+		}
+		ptr = mem_buffer;
+		if (!ptr) {
+			pr_err("[%s:%s] map error @ %x\n", __MM_FILE__,
+					__func__, addr);
+			return -EFAULT;
+		}
+		if (copy_to_user(buf, ptr, PAGE_SIZE)) {
+			iounmap(mem_buffer);
+			pr_err("[%s:%s] copy error @ %p\n", __MM_FILE__,
+					__func__, buf);
+			return -EFAULT;
+		}
+		copy_ok_count += PAGE_SIZE;
+		iounmap(mem_buffer);
+		addr += PAGE_SIZE;
+		buf += PAGE_SIZE;
+		actual += PAGE_SIZE;
+		count -= PAGE_SIZE;
+	}
+
+	*pos += actual;
+	return actual;
+}
+
+static int dsp_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+int dsp_debug_register(dsp_state_cb ptr)
+{
+	if (ptr == NULL)
+		return -EINVAL;
+	cb_ptr = ptr;
+
+	return 0;
+}
+
+static int dspcrashd_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct resource *res;
+	int *pdata;
+
+	pdata = pdev->dev.platform_data;
+	res = platform_get_resource_byname(pdev, IORESOURCE_DMA,
+						"msm_dspcrashd");
+	if (!res) {
+		pr_err("%s: failed to get resources for dspcrashd\n", __func__);
+		return -ENODEV;
+	}
+
+	dsp_ram_base = res->start;
+	dsp_ram_size = res->end - res->start;
+	pr_info("%s: Platform driver values: Base = 0x%x, Size = 0x%x,"
+		 "pdata = 0x%x\n", __func__,
+		dsp_ram_base, dsp_ram_size, *pdata);
+	return rc;
+}
+
+static const struct file_operations dsp_fops = {
+	.owner		= THIS_MODULE,
+	.open		= dsp_open,
+	.read		= dsp_read,
+	.write		= dsp_write,
+	.release	= dsp_release,
+};
+
+static struct miscdevice dsp_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "dsp_debug",
+	.fops	= &dsp_fops,
+};
+
+static struct platform_driver dspcrashd_driver = {
+	.probe = dspcrashd_probe,
+	.driver = { .name = "msm_dspcrashd"}
+};
+
+static int __init dsp_init(void)
+{
+	int rc = 0;
+	init_waitqueue_head(&dsp_wait);
+	rc = platform_driver_register(&dspcrashd_driver);
+	if (IS_ERR_VALUE(rc)) {
+		pr_err("%s: platform_driver_register for dspcrashd failed\n",
+			__func__);
+	}
+	return misc_register(&dsp_misc);
+}
+
+static int __exit dsp_exit(void)
+{
+	platform_driver_unregister(&dspcrashd_driver);
+	return 0;
+}
+
+device_initcall(dsp_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/evrc_in.c b/arch/arm/mach-msm/qdsp6v2/evrc_in.c
new file mode 100644
index 0000000..b95d659
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/evrc_in.c
@@ -0,0 +1,292 @@
+/* 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
+ * 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/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/msm_audio_qcp.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include "audio_utils.h"
+
+/* Buffer with meta*/
+#define PCM_BUF_SIZE		(4096 + sizeof(struct meta_in))
+
+/* Maximum 10 frames in buffer with meta */
+#define FRAME_SIZE		(1 + ((23+sizeof(struct meta_out_dsp)) * 10))
+
+/* ------------------- device --------------------- */
+static long evrc_in_ioctl(struct file *file,
+				unsigned int cmd, unsigned long arg)
+{
+	struct q6audio_in  *audio = file->private_data;
+	int rc = 0;
+	int cnt = 0;
+
+	switch (cmd) {
+	case AUDIO_START: {
+		struct msm_audio_evrc_enc_config *enc_cfg;
+		enc_cfg = audio->enc_cfg;
+		pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__,
+				audio->ac->session, audio->buf_alloc);
+		if (audio->enabled == 1) {
+			pr_info("%s:AUDIO_START already over\n", __func__);
+			rc = 0;
+			break;
+		}
+		rc = audio_in_buf_alloc(audio);
+		if (rc < 0) {
+			pr_err("%s:session id %d: buffer allocation failed\n",
+				__func__, audio->ac->session);
+			break;
+		}
+
+		/* rate_modulation_cmd set to zero
+			 currently not configurable from user space */
+		rc = q6asm_enc_cfg_blk_evrc(audio->ac,
+			audio->buf_cfg.frames_per_buf,
+			enc_cfg->min_bit_rate,
+			enc_cfg->max_bit_rate, 0);
+
+		if (rc < 0) {
+			pr_err("%s:session id %d: cmd evrc media format block"
+				"failed\n", __func__, audio->ac->session);
+			break;
+		}
+		if (audio->feedback == NON_TUNNEL_MODE) {
+			rc = q6asm_media_format_block_pcm(audio->ac,
+				audio->pcm_cfg.sample_rate,
+				audio->pcm_cfg.channel_count);
+
+			if (rc < 0) {
+				pr_err("%s:session id %d: media format block"
+				"failed\n", __func__, audio->ac->session);
+				break;
+			}
+		}
+		pr_debug("%s:session id %d: AUDIO_START enable[%d]\n",
+				__func__, audio->ac->session, audio->enabled);
+		rc = audio_in_enable(audio);
+		if (!rc) {
+			audio->enabled = 1;
+		} else {
+			audio->enabled = 0;
+			pr_err("%s:session id %d: Audio Start procedure failed"
+				"rc=%d\n", __func__, audio->ac->session, rc);
+			break;
+		}
+		while (cnt++ < audio->str_cfg.buffer_count)
+			q6asm_read(audio->ac); /* Push buffer to DSP */
+		rc = 0;
+		pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n",
+				__func__, audio->ac->session, audio->enabled);
+		break;
+	}
+	case AUDIO_STOP: {
+		pr_debug("%s:session id %d: AUDIO_STOP\n", __func__,
+				audio->ac->session);
+		rc = audio_in_disable(audio);
+		if (rc  < 0) {
+			pr_err("%s:session id %d: Audio Stop procedure failed"
+				"rc=%d\n", __func__, audio->ac->session, rc);
+			break;
+		}
+		break;
+	}
+	case AUDIO_GET_EVRC_ENC_CONFIG: {
+		if (copy_to_user((void *)arg, audio->enc_cfg,
+			sizeof(struct msm_audio_evrc_enc_config)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_EVRC_ENC_CONFIG: {
+		struct msm_audio_evrc_enc_config cfg;
+		struct msm_audio_evrc_enc_config *enc_cfg;
+		enc_cfg = audio->enc_cfg;
+
+		if (copy_from_user(&cfg, (void *) arg,
+				sizeof(struct msm_audio_evrc_enc_config))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		if (cfg.min_bit_rate > 4 ||
+			 cfg.min_bit_rate < 1 ||
+			 (cfg.min_bit_rate == 2)) {
+			pr_err("%s:session id %d: invalid min bitrate\n",
+					__func__, audio->ac->session);
+			rc = -EINVAL;
+			break;
+		}
+		if (cfg.max_bit_rate > 4 ||
+			 cfg.max_bit_rate < 1 ||
+			 (cfg.max_bit_rate == 2)) {
+			pr_err("%s:session id %d: invalid max bitrate\n",
+				__func__, audio->ac->session);
+			rc = -EINVAL;
+			break;
+		}
+		enc_cfg->min_bit_rate = cfg.min_bit_rate;
+		enc_cfg->max_bit_rate = cfg.max_bit_rate;
+		pr_debug("%s:session id %d: min_bit_rate= 0x%x"
+			"max_bit_rate=0x%x\n", __func__,
+			audio->ac->session, enc_cfg->min_bit_rate,
+			enc_cfg->max_bit_rate);
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+static int evrc_in_open(struct inode *inode, struct file *file)
+{
+	struct q6audio_in *audio = NULL;
+	struct msm_audio_evrc_enc_config *enc_cfg;
+	int rc = 0;
+
+	audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
+
+	if (audio == NULL) {
+		pr_err("%s: Could not allocate memory for evrc"
+				"driver\n", __func__);
+		return -ENOMEM;
+	}
+	/* Allocate memory for encoder config param */
+	audio->enc_cfg = kzalloc(sizeof(struct msm_audio_evrc_enc_config),
+				GFP_KERNEL);
+	if (audio->enc_cfg == NULL) {
+		pr_err("%s:session id %d: Could not allocate memory for aac"
+				"config param\n", __func__, audio->ac->session);
+		kfree(audio);
+		return -ENOMEM;
+	}
+	enc_cfg = audio->enc_cfg;
+	mutex_init(&audio->lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->write_lock);
+	spin_lock_init(&audio->dsp_lock);
+	init_waitqueue_head(&audio->read_wait);
+	init_waitqueue_head(&audio->write_wait);
+
+	/* Settings will be re-config at AUDIO_SET_CONFIG,
+	* but at least we need to have initial config
+	*/
+	audio->str_cfg.buffer_size = FRAME_SIZE;
+	audio->str_cfg.buffer_count = FRAME_NUM;
+	audio->min_frame_size = 23;
+	audio->max_frames_per_buf = 10;
+	audio->pcm_cfg.buffer_size = PCM_BUF_SIZE;
+	audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
+	enc_cfg->min_bit_rate = 4;
+	enc_cfg->max_bit_rate = 4;
+	audio->pcm_cfg.channel_count = 1;
+	audio->pcm_cfg.sample_rate = 8000;
+	audio->buf_cfg.meta_info_enable = 0x01;
+	audio->buf_cfg.frames_per_buf = 0x01;
+
+	audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb,
+				(void *)audio);
+
+	if (!audio->ac) {
+		pr_err("%s: Could not allocate memory for audio"
+				"client\n", __func__);
+		kfree(audio->enc_cfg);
+		kfree(audio);
+		return -ENOMEM;
+	}
+
+	/* open evrc encoder in T/NT mode */
+	if ((file->f_mode & FMODE_WRITE) &&
+		(file->f_mode & FMODE_READ)) {
+		audio->feedback = NON_TUNNEL_MODE;
+		rc = q6asm_open_read_write(audio->ac, FORMAT_EVRC,
+					FORMAT_LINEAR_PCM);
+		if (rc < 0) {
+			pr_err("%s:session id %d: NT mode Open failed rc=%d\n",
+					__func__, audio->ac->session, rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		pr_info("%s:session id %d: NT mode encoder success\n",
+				__func__, audio->ac->session);
+	} else if (!(file->f_mode & FMODE_WRITE) &&
+				(file->f_mode & FMODE_READ)) {
+		audio->feedback = TUNNEL_MODE;
+		rc = q6asm_open_read(audio->ac, FORMAT_EVRC);
+		if (rc < 0) {
+			pr_err("%s:session id %d: T mode Open failed rc=%d\n",
+					__func__, audio->ac->session, rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		/* register for tx overflow (valid for tunnel mode only) */
+		rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
+		if (rc < 0) {
+			pr_err("%s:session id %d: TX Overflow registration"
+				"failed rc=%d\n", __func__,
+				audio->ac->session, rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		pr_info("%s:session id %d: T mode encoder success\n", __func__,
+				audio->ac->session);
+	} else {
+		pr_err("%s:session id %d: Unexpected mode\n", __func__,
+				audio->ac->session);
+		rc = -EACCES;
+		goto fail;
+	}
+
+	audio->opened = 1;
+	atomic_set(&audio->in_count, PCM_BUF_COUNT);
+	atomic_set(&audio->out_count, 0x00);
+	audio->enc_ioctl = evrc_in_ioctl;
+	file->private_data = audio;
+
+	pr_info("%s:session id %d: success\n", __func__, audio->ac->session);
+	return 0;
+fail:
+	q6asm_audio_client_free(audio->ac);
+	kfree(audio->enc_cfg);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= evrc_in_open,
+	.release	= audio_in_release,
+	.read		= audio_in_read,
+	.write		= audio_in_write,
+	.unlocked_ioctl	= audio_in_ioctl,
+};
+
+struct miscdevice audio_evrc_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_evrc_in",
+	.fops	= &audio_in_fops,
+};
+
+static int __init evrc_in_init(void)
+{
+	return misc_register(&audio_evrc_in_misc);
+}
+
+device_initcall(evrc_in_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/fm.c b/arch/arm/mach-msm/qdsp6v2/fm.c
new file mode 100644
index 0000000..9cf2723
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/fm.c
@@ -0,0 +1,262 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * Based on the mp3 native driver in arch/arm/mach-msm/qdsp5v2/audio_mp3.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/clk.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/android_pmem.h>
+#include <linux/msm_audio.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <mach/msm_adsp.h>
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+#include <sound/q6afe.h>
+
+#define SESSION_ID_FM  (MAX_SESSIONS + 1)
+#define FM_ENABLE	0x1
+#define FM_DISABLE	0x0
+#define FM_COPP		0x7
+
+struct audio {
+	struct mutex lock;
+
+	int opened;
+	int enabled;
+	int running;
+
+	uint16_t fm_source;
+	uint16_t fm_src_copp_id;
+	uint16_t fm_dest;
+	uint16_t fm_dst_copp_id;
+	uint16_t dec_id;
+	uint32_t device_events;
+	uint16_t volume;
+};
+
+
+static struct audio fm_audio;
+static int fm_audio_enable(struct audio *audio)
+{
+	if (audio->enabled)
+		return 0;
+
+	pr_info("%s: fm dest= %08x fm_source = %08x\n", __func__,
+		audio->fm_dst_copp_id, audio->fm_src_copp_id);
+
+	/* do afe loopback here */
+
+	if (audio->fm_dest && audio->fm_source) {
+		if (afe_loopback(FM_ENABLE, audio->fm_dst_copp_id,
+					audio->fm_src_copp_id) < 0) {
+			pr_err("%s: afe_loopback failed\n", __func__);
+		}
+
+		audio->running = 1;
+	}
+
+	audio->enabled = 1;
+	return 0;
+}
+
+static void fm_audio_listner(u32 evt_id, union auddev_evt_data *evt_payload,
+			void *private_data)
+{
+	struct audio *audio = (struct audio *) private_data;
+	switch (evt_id) {
+	case AUDDEV_EVT_DEV_RDY:
+		pr_info("%s :AUDDEV_EVT_DEV_RDY\n", __func__);
+		if (evt_payload->routing_id == FM_COPP) {
+			audio->fm_source = 1;
+			audio->fm_src_copp_id = FM_COPP;
+		} else {
+			audio->fm_dest = 1;
+			audio->fm_dst_copp_id = evt_payload->routing_id;
+		}
+
+		if (audio->enabled &&
+			audio->fm_dest &&
+			audio->fm_source) {
+
+			afe_loopback_gain(audio->fm_src_copp_id,
+						audio->volume);
+			afe_loopback(FM_ENABLE, audio->fm_dst_copp_id,
+						audio->fm_src_copp_id);
+			audio->running = 1;
+		}
+		break;
+	case AUDDEV_EVT_DEV_RLS:
+		pr_info("%s: AUDDEV_EVT_DEV_RLS\n", __func__);
+		if (evt_payload->routing_id == audio->fm_src_copp_id)
+			audio->fm_source = 0;
+		else
+			audio->fm_dest = 0;
+		if (audio->running
+			&& (!audio->fm_dest || !audio->fm_source)) {
+			afe_loopback(FM_DISABLE, audio->fm_dst_copp_id,
+						audio->fm_src_copp_id);
+			audio->running = 0;
+		} else {
+			pr_err("%s: device switch happened\n", __func__);
+		}
+		break;
+	case AUDDEV_EVT_STREAM_VOL_CHG:
+		pr_debug("%s: AUDDEV_EVT_STREAM_VOL_CHG\n", __func__);
+		if (audio->fm_source) {
+			audio->volume = evt_payload->session_vol;
+			afe_loopback_gain(audio->fm_src_copp_id,
+					audio->volume);
+		}
+		break;
+
+	default:
+		pr_err("%s: ERROR:wrong event %08x\n", __func__, evt_id);
+		break;
+	}
+}
+
+static int fm_audio_disable(struct audio *audio)
+{
+
+	/* break the AFE loopback here */
+	afe_loopback(FM_DISABLE, audio->fm_dst_copp_id, audio->fm_src_copp_id);
+	return 0;
+}
+
+static long fm_audio_ioctl(struct file *file, unsigned int cmd,
+		unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = -EINVAL;
+
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		pr_info("%s: AUDIO_START\n", __func__);
+		rc = fm_audio_enable(audio);
+		break;
+	case AUDIO_STOP:
+		pr_info("%s: AUDIO_STOP\n", __func__);
+		rc = fm_audio_disable(audio);
+		audio->running = 0;
+		audio->enabled = 0;
+		break;
+	case AUDIO_GET_SESSION_ID:
+		if (copy_to_user((void *) arg, &audio->dec_id,
+					sizeof(unsigned short)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	default:
+		rc = -EINVAL;
+		pr_err("%s: Un supported IOCTL\n", __func__);
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static int fm_audio_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	pr_debug("audio instance 0x%08x freeing\n", (int)audio);
+	mutex_lock(&audio->lock);
+	auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->dec_id);
+	fm_audio_disable(audio);
+	audio->running = 0;
+	audio->enabled = 0;
+	audio->opened = 0;
+	mutex_unlock(&audio->lock);
+	return 0;
+}
+
+static int fm_audio_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = &fm_audio;
+	int rc = 0;
+
+
+	if (audio->opened)
+		return -EPERM;
+
+	/* Allocate the decoder */
+	audio->dec_id = SESSION_ID_FM;
+
+	audio->running = 0;
+	audio->fm_source = 0;
+	audio->fm_dest = 0;
+
+	audio->device_events = AUDDEV_EVT_DEV_RDY
+				|AUDDEV_EVT_DEV_RLS|
+				AUDDEV_EVT_STREAM_VOL_CHG;
+
+	rc = auddev_register_evt_listner(audio->device_events,
+					AUDDEV_CLNT_DEC,
+					audio->dec_id,
+					fm_audio_listner,
+					(void *)audio);
+
+	if (rc) {
+		pr_err("%s: failed to register listnet\n", __func__);
+		goto event_err;
+	}
+
+	audio->opened = 1;
+	file->private_data = audio;
+
+event_err:
+	return rc;
+}
+
+static const struct file_operations audio_fm_fops = {
+	.owner		= THIS_MODULE,
+	.open		= fm_audio_open,
+	.release	= fm_audio_release,
+	.unlocked_ioctl	= fm_audio_ioctl,
+};
+
+struct miscdevice audio_fm_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_fm",
+	.fops	= &audio_fm_fops,
+};
+
+static int __init fm_audio_init(void)
+{
+	struct audio *audio = &fm_audio;
+
+	mutex_init(&audio->lock);
+	return misc_register(&audio_fm_misc);
+}
+
+device_initcall(fm_audio_init);
+
+MODULE_DESCRIPTION("MSM FM driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c b/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c
new file mode 100644
index 0000000..c19fd85
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c
@@ -0,0 +1,464 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/uaccess.h>
+#include <linux/dma-mapping.h>
+#include <linux/msm_audio.h>
+#include <mach/msm_hdmi_audio.h>
+#include <mach/audio_dma_msm8k.h>
+#include <sound/dai.h>
+#include "q6core.h"
+
+#define DMA_ALLOC_BUF_SZ		(SZ_4K * 16)
+
+#define HDMI_AUDIO_FIFO_WATER_MARK	4
+
+struct audio_buffer {
+	dma_addr_t phys;
+	void *data;
+	uint32_t size;
+	uint32_t used;	/* 1 = CPU is waiting for DMA to consume this buf */
+	uint32_t actual_size;	/* actual number of bytes read by DMA */
+};
+
+struct lpa_if {
+	struct mutex lock;
+	struct msm_audio_config cfg;
+	struct audio_buffer audio_buf[6];
+	int cpu_buf;		/* next buffer the CPU will touch */
+	int dma_buf;		/* next buffer the DMA will touch */
+	u8 *buffer;
+	dma_addr_t buffer_phys;
+	u32 dma_ch;
+	wait_queue_head_t wait;
+	u32 config;
+	u32 dma_period_sz;
+	unsigned int num_periods;
+};
+
+static struct lpa_if  *lpa_if_ptr;
+
+static unsigned int dma_buf_index;
+
+static irqreturn_t lpa_if_irq(int intrsrc, void *data)
+{
+	struct lpa_if *lpa_if = data;
+	int dma_ch = 0;
+	unsigned int pending;
+
+	if (lpa_if)
+		dma_ch = lpa_if->dma_ch;
+	else {
+		pr_err("invalid lpa_if\n");
+		return IRQ_NONE;
+	}
+
+	pending = (intrsrc
+		   & (UNDER_CH(dma_ch) | PER_CH(dma_ch) | ERR_CH(dma_ch)));
+
+	if (pending & UNDER_CH(dma_ch))
+		pr_err("under run\n");
+	if (pending & ERR_CH(dma_ch))
+		pr_err("DMA %x Master Error\n", dma_ch);
+
+	if (pending & PER_CH(dma_ch)) {
+
+		lpa_if->audio_buf[lpa_if->dma_buf].used = 0;
+
+		pr_debug("dma_buf %d  used %d\n", lpa_if->dma_buf,
+			lpa_if->audio_buf[lpa_if->dma_buf].used);
+		lpa_if->dma_buf++;
+		lpa_if->dma_buf = lpa_if->dma_buf % lpa_if->cfg.buffer_count;
+
+		if (lpa_if->dma_buf == lpa_if->cpu_buf)
+			pr_err("Err:both dma_buf and cpu_buf are on same index\n");
+		wake_up(&lpa_if->wait);
+	}
+	return IRQ_HANDLED;
+}
+
+
+int lpa_if_start(struct lpa_if *lpa_if)
+{
+	pr_debug("buf1 0x%x, buf2 0x%x dma_ch %d\n",
+		(unsigned int)lpa_if->audio_buf[0].data,
+		(unsigned int)lpa_if->audio_buf[1].data, lpa_if->dma_ch);
+
+	dai_start_hdmi(lpa_if->dma_ch);
+
+	hdmi_audio_enable(1, HDMI_AUDIO_FIFO_WATER_MARK);
+
+	hdmi_audio_packet_enable(1);
+	return 0;
+}
+
+int lpa_if_config(struct lpa_if *lpa_if)
+{
+	struct dai_dma_params dma_params;
+
+	dma_params.src_start = lpa_if->buffer_phys;
+	dma_params.buffer = lpa_if->buffer;
+	dma_params.buffer_size = lpa_if->dma_period_sz * lpa_if->num_periods;
+	dma_params.period_size = lpa_if->dma_period_sz;
+	dma_params.channels = 2;
+
+	lpa_if->dma_ch = 4;
+	dai_set_params(lpa_if->dma_ch, &dma_params);
+
+	register_dma_irq_handler(lpa_if->dma_ch, lpa_if_irq, (void *)lpa_if);
+
+	mb();
+	pr_debug("lpa_if 0x%08x  buf_vir 0x%08x   buf_phys 0x%08x  "
+		"config %u\n", (u32)lpa_if, (u32) (lpa_if->buffer),
+		lpa_if->buffer_phys, lpa_if->config);
+
+	pr_debug("user_buf_cnt %u user_buf_size %u\n",
+			lpa_if->cfg.buffer_count, lpa_if->cfg.buffer_size);
+
+	lpa_if->config = 1;
+
+	lpa_if_start(lpa_if);
+
+	return 0;
+}
+
+
+static long lpa_if_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct lpa_if *lpa_if = file->private_data;
+	int rc = 0;
+	unsigned int i;
+	pr_debug("cmd %u\n", cmd);
+
+	mutex_lock(&lpa_if->lock);
+
+	switch (cmd) {
+	case AUDIO_START:
+		pr_debug("AUDIO_START\n");
+
+		if (dma_buf_index == 2) {
+			if (!lpa_if->config) {
+				rc = lpa_if_config(lpa_if);
+				if (rc)
+					pr_err("lpa_if_config failed\n");
+			}
+		} else {
+			pr_err("did not receved two buffer for "
+				"AUDIO_STAR\n");
+			rc =  -EPERM;
+		}
+		break;
+
+	case AUDIO_STOP:
+		pr_debug("AUDIO_STOP\n");
+		break;
+
+	case AUDIO_FLUSH:
+		pr_debug("AUDIO_FLUSH\n");
+		break;
+
+
+	case AUDIO_GET_CONFIG:
+		pr_debug("AUDIO_GET_CONFIG\n");
+		if (copy_to_user((void *)arg, &lpa_if->cfg,
+				 sizeof(struct msm_audio_config))) {
+			rc = -EFAULT;
+		}
+		break;
+	case AUDIO_SET_CONFIG: {
+		/*  Setting default rate as 48khz */
+		unsigned int cur_sample_rate =
+			HDMI_SAMPLE_RATE_48KHZ;
+		struct msm_audio_config config;
+
+		pr_debug("AUDIO_SET_CONFIG\n");
+		if (copy_from_user(&config, (void *)arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		lpa_if->dma_period_sz = config.buffer_size;
+		if ((lpa_if->dma_period_sz * lpa_if->num_periods) >
+			DMA_ALLOC_BUF_SZ) {
+			pr_err("Dma buffer size greater than allocated size\n");
+			return -EINVAL;
+		}
+		pr_debug("Dma_period_sz %d\n", lpa_if->dma_period_sz);
+		if (lpa_if->dma_period_sz < (2 * SZ_4K))
+			lpa_if->num_periods = 6;
+		pr_debug("No. of Periods %d\n", lpa_if->num_periods);
+
+		lpa_if->cfg.buffer_count = lpa_if->num_periods;
+		lpa_if->cfg.buffer_size = lpa_if->dma_period_sz *
+						lpa_if->num_periods;
+
+		for (i = 0; i < lpa_if->cfg.buffer_count; i++) {
+			lpa_if->audio_buf[i].phys =
+				lpa_if->buffer_phys + i * lpa_if->dma_period_sz;
+			lpa_if->audio_buf[i].data =
+				lpa_if->buffer + i * lpa_if->dma_period_sz;
+			lpa_if->audio_buf[i].size = lpa_if->dma_period_sz;
+			lpa_if->audio_buf[i].used = 0;
+		}
+
+		pr_debug("Sample rate %d\n", config.sample_rate);
+		switch (config.sample_rate) {
+		case 48000:
+			cur_sample_rate = HDMI_SAMPLE_RATE_48KHZ;
+			break;
+		case 44100:
+			cur_sample_rate = HDMI_SAMPLE_RATE_44_1KHZ;
+			break;
+		case 32000:
+			cur_sample_rate = HDMI_SAMPLE_RATE_32KHZ;
+			break;
+		case 88200:
+			cur_sample_rate = HDMI_SAMPLE_RATE_88_2KHZ;
+			break;
+		case 96000:
+			cur_sample_rate = HDMI_SAMPLE_RATE_96KHZ;
+			break;
+		case 176400:
+			cur_sample_rate = HDMI_SAMPLE_RATE_176_4KHZ;
+			break;
+		case 192000:
+			cur_sample_rate = HDMI_SAMPLE_RATE_192KHZ;
+			break;
+		default:
+			cur_sample_rate = HDMI_SAMPLE_RATE_48KHZ;
+		}
+		if (cur_sample_rate != hdmi_msm_audio_get_sample_rate())
+			hdmi_msm_audio_sample_rate_reset(cur_sample_rate);
+		else
+			pr_debug("Previous sample rate and current"
+				"sample rate are same\n");
+		break;
+	}
+	default:
+		pr_err("UnKnown Ioctl\n");
+		rc = -EINVAL;
+	}
+
+	mutex_unlock(&lpa_if->lock);
+
+	return rc;
+}
+
+
+static int lpa_if_open(struct inode *inode, struct file *file)
+{
+	pr_debug("\n");
+
+	file->private_data = lpa_if_ptr;
+	dma_buf_index = 0;
+	lpa_if_ptr->cpu_buf = 2;
+	lpa_if_ptr->dma_buf = 0;
+	lpa_if_ptr->num_periods = 4;
+
+	core_req_bus_bandwith(AUDIO_IF_BUS_ID, 100000, 0);
+	mb();
+
+	return 0;
+}
+
+static inline int rt_policy(int policy)
+{
+	if (unlikely(policy == SCHED_FIFO) || unlikely(policy == SCHED_RR))
+		return 1;
+	return 0;
+}
+
+static inline int task_has_rt_policy(struct task_struct *p)
+{
+	return rt_policy(p->policy);
+}
+static ssize_t lpa_if_write(struct file *file, const char __user *buf,
+		size_t count, loff_t *pos)
+{
+	struct lpa_if *lpa_if = file->private_data;
+	struct audio_buffer *ab;
+	const char __user *start = buf;
+	int xfer, rc;
+	struct sched_param s = { .sched_priority = 1 };
+	int old_prio = current->rt_priority;
+	int old_policy = current->policy;
+	int cap_nice = cap_raised(current_cap(), CAP_SYS_NICE);
+
+	 /* just for this write, set us real-time */
+	if (!task_has_rt_policy(current)) {
+		struct cred *new = prepare_creds();
+		cap_raise(new->cap_effective, CAP_SYS_NICE);
+		commit_creds(new);
+		if ((sched_setscheduler(current, SCHED_RR, &s)) < 0)
+			pr_err("sched_setscheduler failed\n");
+	}
+	mutex_lock(&lpa_if->lock);
+
+	if (dma_buf_index < 2) {
+
+		ab = lpa_if->audio_buf + dma_buf_index;
+
+		if (copy_from_user(ab->data, buf, count)) {
+			pr_err("copy from user failed\n");
+			rc = 0;
+			goto end;
+
+		}
+		mb();
+		pr_debug("prefill: count %u  audio_buf[%u].size %u\n",
+			 count, dma_buf_index, ab->size);
+
+		ab->used = 1;
+		dma_buf_index++;
+		rc =  count;
+		goto end;
+	}
+
+	if (lpa_if->config != 1) {
+		pr_err("AUDIO_START did not happen\n");
+		rc = 0;
+		goto end;
+	}
+
+	while (count > 0) {
+
+		ab = lpa_if->audio_buf + lpa_if->cpu_buf;
+
+		rc = wait_event_timeout(lpa_if->wait, (ab->used == 0), 10 * HZ);
+		if (!rc) {
+			pr_err("wait_event_timeout failed\n");
+			rc =  buf - start;
+			goto end;
+		}
+
+		xfer = count;
+
+		if (xfer > lpa_if->dma_period_sz)
+			xfer = lpa_if->dma_period_sz;
+
+		if (copy_from_user(ab->data, buf, xfer)) {
+			pr_err("copy from user failed\n");
+			rc = buf - start;
+			goto end;
+		}
+
+		mb();
+		buf += xfer;
+		count -= xfer;
+		ab->used = 1;
+
+		pr_debug("xfer %d, size %d, used %d cpu_buf %d\n",
+			xfer, ab->size, ab->used, lpa_if->cpu_buf);
+		lpa_if->cpu_buf++;
+		lpa_if->cpu_buf = lpa_if->cpu_buf % lpa_if->cfg.buffer_count;
+	}
+	rc = buf - start;
+end:
+	mutex_unlock(&lpa_if->lock);
+	/* restore old scheduling policy */
+	if (!rt_policy(old_policy)) {
+		struct sched_param v = { .sched_priority = old_prio };
+		if ((sched_setscheduler(current, old_policy, &v)) < 0)
+			pr_err("sched_setscheduler failed\n");
+		if (likely(!cap_nice)) {
+			struct cred *new = prepare_creds();
+			cap_lower(new->cap_effective, CAP_SYS_NICE);
+			commit_creds(new);
+		}
+	}
+	return rc;
+}
+
+static int lpa_if_release(struct inode *inode, struct file *file)
+{
+	struct lpa_if *lpa_if = file->private_data;
+
+	hdmi_audio_packet_enable(0);
+
+	wait_for_dma_cnt_stop(lpa_if->dma_ch);
+
+	hdmi_audio_enable(0, HDMI_AUDIO_FIFO_WATER_MARK);
+
+	if (lpa_if->config) {
+		unregister_dma_irq_handler(lpa_if->dma_ch);
+		dai_stop_hdmi(lpa_if->dma_ch);
+		lpa_if->config = 0;
+	}
+	core_req_bus_bandwith(AUDIO_IF_BUS_ID, 0, 0);
+
+	if (hdmi_msm_audio_get_sample_rate() != HDMI_SAMPLE_RATE_48KHZ)
+		hdmi_msm_audio_sample_rate_reset(HDMI_SAMPLE_RATE_48KHZ);
+
+	return 0;
+}
+
+static const struct file_operations lpa_if_fops = {
+	.owner = THIS_MODULE,
+	.open = lpa_if_open,
+	.write = lpa_if_write,
+	.release = lpa_if_release,
+	.unlocked_ioctl = lpa_if_ioctl,
+};
+
+struct miscdevice lpa_if_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_lpa_if_out",
+	.fops = &lpa_if_fops,
+};
+
+static int __init lpa_if_init(void)
+{
+	int rc;
+
+	lpa_if_ptr = kzalloc(sizeof(struct lpa_if), GFP_KERNEL);
+	if (!lpa_if_ptr) {
+		pr_info("No mem for lpa-if\n");
+		return -ENOMEM;
+	}
+
+	mutex_init(&lpa_if_ptr->lock);
+	init_waitqueue_head(&lpa_if_ptr->wait);
+
+	lpa_if_ptr->buffer = dma_alloc_coherent(NULL, DMA_ALLOC_BUF_SZ,
+				    &(lpa_if_ptr->buffer_phys), GFP_KERNEL);
+	if (!lpa_if_ptr->buffer) {
+		pr_err("dma_alloc_coherent failed\n");
+		kfree(lpa_if_ptr);
+		return -ENOMEM;
+	}
+
+	pr_info("lpa_if_ptr 0x%08x   buf_vir 0x%08x   buf_phy 0x%08x "
+		" buf_zise %u\n", (u32)lpa_if_ptr,
+		(u32)(lpa_if_ptr->buffer), lpa_if_ptr->buffer_phys,
+		DMA_ALLOC_BUF_SZ);
+
+	rc =  misc_register(&lpa_if_misc);
+	if (rc < 0) {
+		pr_err("misc_register failed\n");
+
+		dma_free_coherent(NULL, DMA_ALLOC_BUF_SZ, lpa_if_ptr->buffer,
+				lpa_if_ptr->buffer_phys);
+		kfree(lpa_if_ptr);
+	}
+	return rc;
+}
+
+device_initcall(lpa_if_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/msm_qdsp6_audio.h b/arch/arm/mach-msm/qdsp6v2/msm_qdsp6_audio.h
new file mode 100644
index 0000000..3890816
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/msm_qdsp6_audio.h
@@ -0,0 +1,52 @@
+/* arch/arm/mach-msm/include/mach/msm_qdsp6_audio.h
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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 _MACH_MSM_QDSP6_Q6AUDIO_
+#define _MACH_MSM_QDSP6_Q6AUDIO_
+
+#define AUDIO_FLAG_READ		0
+#define AUDIO_FLAG_WRITE	1
+#define AUDIO_FLAG_INCALL_MIXED	2
+
+struct audio_buffer {
+	dma_addr_t phys;
+	void *data;
+	uint32_t size;
+	uint32_t used;	/* 1 = CPU is waiting for DSP to consume this buf */
+	uint32_t actual_size; /* actual number of bytes read by DSP */
+};
+
+struct audio_client {
+	struct audio_buffer buf[2];
+	int cpu_buf;	/* next buffer the CPU will touch */
+	int dsp_buf;	/* next buffer the DSP will touch */
+	int running;
+	int session;
+
+	int state;
+
+	wait_queue_head_t wait;
+	wait_queue_head_t cmd_wait;
+
+	struct dal_client *client;
+
+	int cb_status;
+	uint32_t flags;
+	void *apr;
+	int ref_count;
+};
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6v2/pcm_in.c b/arch/arm/mach-msm/qdsp6v2/pcm_in.c
new file mode 100644
index 0000000..667628c
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/pcm_in.c
@@ -0,0 +1,489 @@
+/*
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ * Copyright (c) 2010-2012, Code Aurora Forum. 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.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/msm_audio.h>
+#include <asm/atomic.h>
+#include <mach/debug_mm.h>
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+#include <sound/q6asm.h>
+#include <sound/apr_audio.h>
+#include <linux/wakelock.h>
+
+#define MAX_BUF 4
+#define BUFSZ (480 * 8)
+#define BUFFER_SIZE_MULTIPLE 4
+#define MIN_BUFFER_SIZE 160
+
+#define VOC_REC_NONE 0xFF
+
+struct pcm {
+	struct mutex lock;
+	struct mutex read_lock;
+	wait_queue_head_t wait;
+	spinlock_t dsp_lock;
+	struct audio_client *ac;
+	uint32_t sample_rate;
+	uint32_t channel_count;
+	uint32_t buffer_size;
+	uint32_t buffer_count;
+	uint32_t rec_mode;
+	uint32_t in_frame_info[MAX_BUF][2];
+	atomic_t in_count;
+	atomic_t in_enabled;
+	atomic_t in_opened;
+	atomic_t in_stopped;
+	struct wake_lock wakelock;
+	struct wake_lock idlelock;
+};
+
+static void pcm_in_get_dsp_buffers(struct pcm*,
+				uint32_t token, uint32_t *payload);
+
+void pcm_in_cb(uint32_t opcode, uint32_t token,
+		uint32_t *payload, void *priv)
+{
+	struct pcm *pcm = (struct pcm *) priv;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pcm->dsp_lock, flags);
+	switch (opcode) {
+	case ASM_DATA_EVENT_READ_DONE:
+		pcm_in_get_dsp_buffers(pcm, token, payload);
+		break;
+	case RESET_EVENTS:
+		reset_device();
+		break;
+	default:
+		break;
+	}
+	spin_unlock_irqrestore(&pcm->dsp_lock, flags);
+}
+static void pcm_in_prevent_sleep(struct pcm *audio)
+{
+	pr_debug("%s:\n", __func__);
+	wake_lock(&audio->wakelock);
+	wake_lock(&audio->idlelock);
+}
+
+static void pcm_in_allow_sleep(struct pcm *audio)
+{
+	pr_debug("%s:\n", __func__);
+	wake_unlock(&audio->wakelock);
+	wake_unlock(&audio->idlelock);
+}
+
+static void pcm_in_get_dsp_buffers(struct pcm *pcm,
+				uint32_t token, uint32_t *payload)
+{
+	pcm->in_frame_info[token][0] = payload[7];
+	pcm->in_frame_info[token][1] = payload[3];
+	if (atomic_read(&pcm->in_count) <= pcm->buffer_count)
+		atomic_inc(&pcm->in_count);
+	wake_up(&pcm->wait);
+}
+
+static int pcm_in_enable(struct pcm *pcm)
+{
+	if (atomic_read(&pcm->in_enabled))
+		return 0;
+	return q6asm_run(pcm->ac, 0, 0, 0);
+}
+
+static int pcm_in_disable(struct pcm *pcm)
+{
+	int rc = 0;
+
+	if (atomic_read(&pcm->in_opened)) {
+		atomic_set(&pcm->in_enabled, 0);
+		atomic_set(&pcm->in_opened, 0);
+		rc = q6asm_cmd(pcm->ac, CMD_CLOSE);
+
+		atomic_set(&pcm->in_stopped, 1);
+		memset(pcm->in_frame_info, 0,
+				sizeof(char) * pcm->buffer_count * 2);
+		wake_up(&pcm->wait);
+	}
+	return rc;
+}
+
+static int config(struct pcm *pcm)
+{
+	int rc = 0;
+
+	pr_debug("%s: pcm prefill, buffer_size = %d\n", __func__,
+		pcm->buffer_size);
+	rc = q6asm_audio_client_buf_alloc(OUT, pcm->ac,
+				pcm->buffer_size, pcm->buffer_count);
+	if (rc < 0) {
+		pr_err("Audio Start: Buffer Allocation failed \
+						rc = %d\n", rc);
+		goto fail;
+	}
+
+	rc = q6asm_enc_cfg_blk_pcm(pcm->ac, pcm->sample_rate,
+						pcm->channel_count);
+	if (rc < 0) {
+		pr_err("%s: cmd media format block failed", __func__);
+		goto fail;
+	}
+fail:
+	return rc;
+}
+
+static long pcm_in_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct pcm *pcm = file->private_data;
+	int rc = 0;
+
+	mutex_lock(&pcm->lock);
+	switch (cmd) {
+	case AUDIO_SET_VOLUME:
+		break;
+	case AUDIO_GET_STATS: {
+		struct msm_audio_stats stats;
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_START: {
+		int cnt = 0;
+		if (atomic_read(&pcm->in_enabled)) {
+			pr_info("%s:AUDIO_START already over\n", __func__);
+			rc = 0;
+			break;
+		}
+		rc = config(pcm);
+		if (rc) {
+			pr_err("%s: IN Configuration failed\n", __func__);
+			rc = -EFAULT;
+			break;
+		}
+
+		rc = pcm_in_enable(pcm);
+		if (rc) {
+			pr_err("%s: In Enable failed\n", __func__);
+			rc = -EFAULT;
+			break;
+		}
+		pcm_in_prevent_sleep(pcm);
+		atomic_set(&pcm->in_enabled, 1);
+
+		while (cnt++ < pcm->buffer_count)
+			q6asm_read(pcm->ac);
+		pr_info("%s: AUDIO_START session id[%d]\n", __func__,
+							pcm->ac->session);
+
+		if (pcm->rec_mode != VOC_REC_NONE)
+			msm_enable_incall_recording(pcm->ac->session,
+			pcm->rec_mode, pcm->sample_rate, pcm->channel_count);
+
+		break;
+	}
+	case AUDIO_GET_SESSION_ID: {
+		if (copy_to_user((void *) arg, &pcm->ac->session,
+					sizeof(unsigned short)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_STOP:
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+
+		if (copy_from_user(&config, (void *) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("%s: SET_CONFIG: buffer_size:%d channel_count:%d"
+			"sample_rate:%d, buffer_count:%d\n", __func__,
+			config.buffer_size, config.channel_count,
+			config.sample_rate, config.buffer_count);
+
+		if (!config.channel_count || config.channel_count > 2) {
+			rc = -EINVAL;
+			break;
+		}
+
+		if (config.sample_rate < 8000 || config.sample_rate > 48000) {
+			rc = -EINVAL;
+			break;
+		}
+
+		if ((config.buffer_size % (config.channel_count *
+			BUFFER_SIZE_MULTIPLE)) ||
+			(config.buffer_size < MIN_BUFFER_SIZE)) {
+			pr_err("%s: Buffer Size should be multiple of "
+				"[4 * no. of channels] and greater than 160\n",
+				__func__);
+			rc = -EINVAL;
+			break;
+		}
+
+		pcm->sample_rate = config.sample_rate;
+		pcm->channel_count = config.channel_count;
+		pcm->buffer_size = config.buffer_size;
+		pcm->buffer_count = config.buffer_count;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_size = pcm->buffer_size;
+		config.buffer_count = pcm->buffer_count;
+		config.sample_rate = pcm->sample_rate;
+		config.channel_count = pcm->channel_count;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void *) arg, &config, sizeof(config)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_ENABLE_AUDPRE: {
+
+		uint16_t enable_mask;
+
+		if (copy_from_user(&enable_mask, (void *) arg,
+						sizeof(enable_mask))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (enable_mask & FLUENCE_ENABLE)
+			rc = auddev_cfg_tx_copp_topology(pcm->ac->session,
+					VPM_TX_DM_FLUENCE_COPP_TOPOLOGY);
+		else
+			rc = auddev_cfg_tx_copp_topology(pcm->ac->session,
+					DEFAULT_COPP_TOPOLOGY);
+		break;
+	}
+
+	case AUDIO_SET_INCALL: {
+		if (copy_from_user(&pcm->rec_mode,
+				   (void *) arg,
+				   sizeof(pcm->rec_mode))) {
+			rc = -EFAULT;
+			pr_err("%s: Error copying in-call mode\n", __func__);
+			break;
+		}
+
+		if (pcm->rec_mode != VOC_REC_UPLINK &&
+		    pcm->rec_mode != VOC_REC_DOWNLINK &&
+		    pcm->rec_mode != VOC_REC_BOTH) {
+			rc = -EINVAL;
+			pcm->rec_mode = VOC_REC_NONE;
+
+			pr_err("%s: Invalid %d in-call rec_mode\n",
+			       __func__, pcm->rec_mode);
+			break;
+		}
+
+		pr_debug("%s: In-call rec_mode %d\n", __func__, pcm->rec_mode);
+		break;
+	}
+
+	default:
+		rc = -EINVAL;
+		break;
+	}
+	mutex_unlock(&pcm->lock);
+	return rc;
+}
+
+static int pcm_in_open(struct inode *inode, struct file *file)
+{
+	struct pcm *pcm;
+	int rc = 0;
+	char name[24];
+
+	pcm = kzalloc(sizeof(struct pcm), GFP_KERNEL);
+	if (!pcm)
+		return -ENOMEM;
+
+	pcm->channel_count = 1;
+	pcm->sample_rate = 8000;
+	pcm->buffer_size = BUFSZ;
+	pcm->buffer_count = MAX_BUF;
+
+	pcm->ac = q6asm_audio_client_alloc((app_cb)pcm_in_cb, (void *)pcm);
+	if (!pcm->ac) {
+		pr_err("%s: Could not allocate memory\n", __func__);
+		rc = -ENOMEM;
+		goto fail;
+	}
+
+	mutex_init(&pcm->lock);
+	mutex_init(&pcm->read_lock);
+	spin_lock_init(&pcm->dsp_lock);
+	init_waitqueue_head(&pcm->wait);
+
+	rc = q6asm_open_read(pcm->ac, FORMAT_LINEAR_PCM);
+	if (rc < 0) {
+		pr_err("%s: Cmd Open Failed\n", __func__);
+		goto fail;
+	}
+
+	atomic_set(&pcm->in_stopped, 0);
+	atomic_set(&pcm->in_enabled, 0);
+	atomic_set(&pcm->in_count, 0);
+	atomic_set(&pcm->in_opened, 1);
+	snprintf(name, sizeof name, "pcm_in_%x", pcm->ac->session);
+	wake_lock_init(&pcm->wakelock, WAKE_LOCK_SUSPEND, name);
+	snprintf(name, sizeof name, "pcm_in_idle_%x", pcm->ac->session);
+	wake_lock_init(&pcm->idlelock, WAKE_LOCK_IDLE, name);
+
+	pcm->rec_mode = VOC_REC_NONE;
+
+	file->private_data = pcm;
+	pr_info("%s: pcm in open session id[%d]\n", __func__, pcm->ac->session);
+	return 0;
+fail:
+	if (pcm->ac)
+		q6asm_audio_client_free(pcm->ac);
+	kfree(pcm);
+	return rc;
+}
+
+static ssize_t pcm_in_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *pos)
+{
+	struct pcm *pcm = file->private_data;
+	const char __user *start = buf;
+	void *data;
+	uint32_t offset = 0;
+	uint32_t size = 0;
+	uint32_t idx;
+	int rc = 0;
+	int len = 0;
+
+	if (!atomic_read(&pcm->in_enabled))
+		return -EFAULT;
+	mutex_lock(&pcm->read_lock);
+	while (count > 0) {
+		rc = wait_event_timeout(pcm->wait,
+				(atomic_read(&pcm->in_count) ||
+				atomic_read(&pcm->in_stopped)), 5 * HZ);
+		if (!rc) {
+			pr_err("%s: wait_event_timeout failed\n", __func__);
+			goto fail;
+		}
+
+		if (atomic_read(&pcm->in_stopped) &&
+					!atomic_read(&pcm->in_count)) {
+			mutex_unlock(&pcm->read_lock);
+			return 0;
+		}
+
+		data = q6asm_is_cpu_buf_avail(OUT, pcm->ac, &size, &idx);
+		if (count >= size)
+			len = size;
+		else {
+			len = count;
+			pr_err("%s: short read data[%p]bytesavail[%d]"
+				"bytesrequest[%d]"
+				"bytesrejected%d]\n",\
+				__func__, data, size,
+				count, (size - count));
+		}
+		if ((len) && data) {
+			offset = pcm->in_frame_info[idx][1];
+			if (copy_to_user(buf, data+offset, len)) {
+				pr_err("%s copy_to_user failed len[%d]\n",
+							__func__, len);
+				rc = -EFAULT;
+				goto fail;
+			}
+			count -= len;
+			buf += len;
+		}
+		atomic_dec(&pcm->in_count);
+		memset(&pcm->in_frame_info[idx], 0,
+						sizeof(uint32_t) * 2);
+
+		rc = q6asm_read(pcm->ac);
+		if (rc < 0) {
+			pr_err("%s q6asm_read fail\n", __func__);
+				goto fail;
+		}
+		rmb();
+		break;
+	}
+	rc = buf-start;
+fail:
+	mutex_unlock(&pcm->read_lock);
+	return rc;
+}
+
+static int pcm_in_release(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	struct pcm *pcm = file->private_data;
+
+	pr_info("[%s:%s] release session id[%d]\n", __MM_FILE__,
+		__func__, pcm->ac->session);
+	mutex_lock(&pcm->lock);
+
+	if ((pcm->rec_mode != VOC_REC_NONE) && atomic_read(&pcm->in_enabled)) {
+		msm_disable_incall_recording(pcm->ac->session, pcm->rec_mode);
+
+		pcm->rec_mode = VOC_REC_NONE;
+	}
+
+	/* remove this session from topology list */
+	auddev_cfg_tx_copp_topology(pcm->ac->session,
+				DEFAULT_COPP_TOPOLOGY);
+	mutex_unlock(&pcm->lock);
+
+	rc = pcm_in_disable(pcm);
+	 msm_clear_session_id(pcm->ac->session);
+	q6asm_audio_client_free(pcm->ac);
+	pcm_in_allow_sleep(pcm);
+	wake_lock_destroy(&pcm->wakelock);
+	wake_lock_destroy(&pcm->idlelock);
+	kfree(pcm);
+	return rc;
+}
+
+static const struct file_operations pcm_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= pcm_in_open,
+	.read		= pcm_in_read,
+	.release	= pcm_in_release,
+	.unlocked_ioctl	= pcm_in_ioctl,
+};
+
+struct miscdevice pcm_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_pcm_in",
+	.fops	= &pcm_in_fops,
+};
+
+static int __init pcm_in_init(void)
+{
+	return misc_register(&pcm_in_misc);
+}
+
+device_initcall(pcm_in_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/pcm_out.c b/arch/arm/mach-msm/qdsp6v2/pcm_out.c
new file mode 100644
index 0000000..733d5e3
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/pcm_out.c
@@ -0,0 +1,467 @@
+/*
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/msm_audio.h>
+#include <linux/slab.h>
+#include <linux/wakelock.h>
+#include <asm/atomic.h>
+#include <sound/q6asm.h>
+#include <sound/apr_audio.h>
+#include <mach/debug_mm.h>
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+
+#define MAX_BUF 2
+#define BUFSZ (4800)
+
+struct pcm {
+	struct mutex lock;
+	struct mutex write_lock;
+	spinlock_t   dsp_lock;
+	wait_queue_head_t write_wait;
+	struct audio_client *ac;
+	uint32_t sample_rate;
+	uint32_t channel_count;
+	uint32_t buffer_size;
+	uint32_t buffer_count;
+	uint32_t rec_mode;
+	uint32_t stream_event;
+	uint32_t volume;
+	atomic_t out_count;
+	atomic_t out_enabled;
+	atomic_t out_opened;
+	atomic_t out_stopped;
+	atomic_t out_prefill;
+	struct wake_lock wakelock;
+};
+
+void pcm_out_cb(uint32_t opcode, uint32_t token,
+			uint32_t *payload, void *priv)
+{
+	struct pcm *pcm = (struct pcm *) priv;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pcm->dsp_lock, flags);
+	switch (opcode) {
+	case ASM_DATA_EVENT_WRITE_DONE:
+		atomic_inc(&pcm->out_count);
+		wake_up(&pcm->write_wait);
+		break;
+	case RESET_EVENTS:
+		reset_device();
+		break;
+	default:
+		break;
+	}
+	spin_unlock_irqrestore(&pcm->dsp_lock, flags);
+}
+
+static void audio_prevent_sleep(struct pcm *audio)
+{
+	pr_debug("%s:\n", __func__);
+	wake_lock(&audio->wakelock);
+}
+
+static void audio_allow_sleep(struct pcm *audio)
+{
+	pr_debug("%s:\n", __func__);
+	wake_unlock(&audio->wakelock);
+}
+
+static int pcm_out_enable(struct pcm *pcm)
+{
+	if (atomic_read(&pcm->out_enabled))
+		return 0;
+	return q6asm_run(pcm->ac, 0, 0, 0);
+}
+
+static int pcm_out_disable(struct pcm *pcm)
+{
+	int rc = 0;
+
+	if (atomic_read(&pcm->out_opened)) {
+		atomic_set(&pcm->out_enabled, 0);
+		atomic_set(&pcm->out_opened, 0);
+		rc = q6asm_cmd(pcm->ac, CMD_CLOSE);
+
+		atomic_set(&pcm->out_stopped, 1);
+		wake_up(&pcm->write_wait);
+	}
+	return rc;
+}
+
+static int config(struct pcm *pcm)
+{
+	int rc = 0;
+	if (!atomic_read(&pcm->out_prefill)) {
+		pr_debug("%s: pcm prefill\n", __func__);
+		rc = q6asm_audio_client_buf_alloc(IN, pcm->ac,
+				pcm->buffer_size, pcm->buffer_count);
+		if (rc < 0) {
+			pr_err("Audio Start: Buffer Allocation failed \
+							rc = %d\n", rc);
+			goto fail;
+		}
+
+		rc = q6asm_media_format_block_pcm(pcm->ac, pcm->sample_rate,
+							pcm->channel_count);
+		if (rc < 0)
+			pr_err("%s: CMD Format block failed\n", __func__);
+
+		atomic_set(&pcm->out_prefill, 1);
+		atomic_set(&pcm->out_count, pcm->buffer_count);
+	}
+fail:
+	return rc;
+}
+
+static void pcm_event_listner(u32 evt_id, union auddev_evt_data *evt_payload,
+							void *private_data)
+{
+	struct pcm *pcm = (struct pcm *) private_data;
+	int rc  = 0;
+
+	switch (evt_id) {
+	case AUDDEV_EVT_STREAM_VOL_CHG:
+		pcm->volume = evt_payload->session_vol;
+		pr_debug("%s: AUDDEV_EVT_STREAM_VOL_CHG, stream vol %d, "
+				"enabled = %d\n", __func__, pcm->volume,
+					atomic_read(&pcm->out_enabled));
+		if (atomic_read(&pcm->out_enabled)) {
+			if (pcm->ac) {
+				rc = q6asm_set_volume(pcm->ac, pcm->volume);
+				if (rc < 0)
+					pr_err("%s: Send Volume command"
+					"failed rc=%d\n", __func__, rc);
+			}
+		}
+		break;
+	default:
+		pr_err("%s:ERROR:wrong event\n", __func__);
+		break;
+	}
+}
+
+static long pcm_out_ioctl(struct file *file, unsigned int cmd,
+				unsigned long arg)
+{
+	struct pcm *pcm = file->private_data;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	mutex_lock(&pcm->lock);
+	switch (cmd) {
+	case AUDIO_SET_VOLUME: {
+		int vol;
+		if (copy_from_user(&vol, (void *) arg, sizeof(vol))) {
+			rc = -EFAULT;
+			break;
+		}
+		break;
+	}
+	case AUDIO_START: {
+		pr_info("%s: AUDIO_START\n", __func__);
+		rc = config(pcm);
+		if (rc) {
+			pr_err("%s: Out Configuration failed\n", __func__);
+			rc = -EFAULT;
+			break;
+		}
+
+		rc = pcm_out_enable(pcm);
+		if (rc) {
+			pr_err("Out enable failed\n");
+			rc = -EFAULT;
+			break;
+		}
+		audio_prevent_sleep(pcm);
+		atomic_set(&pcm->out_enabled, 1);
+
+		rc = q6asm_set_volume(pcm->ac, pcm->volume);
+		if (rc < 0)
+			pr_err("%s: Send Volume command failed rc=%d\n",
+							__func__, rc);
+		rc = q6asm_set_lrgain(pcm->ac, 0x2000, 0x2000);
+		if (rc < 0)
+			pr_err("%s: Send channel gain failed rc=%d\n",
+							__func__, rc);
+		/* disable mute by default */
+		rc = q6asm_set_mute(pcm->ac, 0);
+		if (rc < 0)
+			pr_err("%s: Send mute command failed rc=%d\n",
+							__func__, rc);
+		break;
+	}
+	case AUDIO_GET_SESSION_ID: {
+		if (copy_to_user((void *) arg, &pcm->ac->session,
+					sizeof(unsigned short)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_STOP:
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		pr_debug("%s: AUDIO_SET_CONFIG\n", __func__);
+		if (copy_from_user(&config, (void *) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (config.channel_count < 1 || config.channel_count > 2) {
+			rc = -EINVAL;
+			break;
+		}
+		if (config.sample_rate < 8000 || config.sample_rate > 48000) {
+			rc = -EINVAL;
+			break;
+		}
+		if (config.buffer_size < 128) {
+			rc = -EINVAL;
+			break;
+		}
+		pcm->sample_rate = config.sample_rate;
+		pcm->channel_count = config.channel_count;
+		pcm->buffer_size = config.buffer_size;
+		pcm->buffer_count = config.buffer_count;
+		pr_debug("%s:buffer_size:%d buffer_count:%d sample_rate:%d \
+			channel_count:%d\n",  __func__, pcm->buffer_size,
+			pcm->buffer_count, pcm->sample_rate,
+			pcm->channel_count);
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		pr_debug("%s: AUDIO_GET_CONFIG\n", __func__);
+		config.buffer_size = pcm->buffer_size;
+		config.buffer_count = pcm->buffer_count;
+		config.sample_rate = pcm->sample_rate;
+		config.channel_count = pcm->channel_count;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void *) arg, &config, sizeof(config)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_EQ: {
+		struct msm_audio_eq_stream_config eq_config;
+		if (copy_from_user(&eq_config, (void *) arg,
+						sizeof(eq_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		rc = q6asm_equalizer(pcm->ac, (void *) &eq_config);
+		if (rc < 0)
+			pr_err("%s: EQUALIZER FAILED\n", __func__);
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&pcm->lock);
+	return rc;
+}
+
+static int pcm_out_open(struct inode *inode, struct file *file)
+{
+	struct pcm *pcm;
+	int rc = 0;
+	char name[24];
+
+	pr_info("[%s:%s] open\n", __MM_FILE__, __func__);
+	pcm = kzalloc(sizeof(struct pcm), GFP_KERNEL);
+	if (!pcm) {
+		pr_err("%s: Failed to allocated memory\n", __func__);
+		return -ENOMEM;
+	}
+
+	pcm->channel_count = 2;
+	pcm->sample_rate = 44100;
+	pcm->buffer_size = BUFSZ;
+	pcm->buffer_count = MAX_BUF;
+	pcm->stream_event = AUDDEV_EVT_STREAM_VOL_CHG;
+	pcm->volume = 0x2000;
+
+	pcm->ac = q6asm_audio_client_alloc((app_cb)pcm_out_cb, (void *)pcm);
+	if (!pcm->ac) {
+		pr_err("%s: Could not allocate memory\n", __func__);
+		rc = -ENOMEM;
+		goto fail;
+	}
+
+	rc = q6asm_open_write(pcm->ac, FORMAT_LINEAR_PCM);
+	if (rc < 0) {
+		pr_err("%s: pcm out open failed for session %d\n", __func__,
+			pcm->ac->session);
+		rc = -EINVAL;
+		goto fail;
+	}
+
+	mutex_init(&pcm->lock);
+	mutex_init(&pcm->write_lock);
+	init_waitqueue_head(&pcm->write_wait);
+	spin_lock_init(&pcm->dsp_lock);
+	atomic_set(&pcm->out_enabled, 0);
+	atomic_set(&pcm->out_stopped, 0);
+	atomic_set(&pcm->out_count, pcm->buffer_count);
+	atomic_set(&pcm->out_prefill, 0);
+	atomic_set(&pcm->out_opened, 1);
+	snprintf(name, sizeof name, "audio_pcm_%x", pcm->ac->session);
+	wake_lock_init(&pcm->wakelock, WAKE_LOCK_SUSPEND, name);
+
+	rc = auddev_register_evt_listner(pcm->stream_event,
+					AUDDEV_CLNT_DEC,
+					pcm->ac->session,
+					pcm_event_listner,
+					(void *)pcm);
+	if (rc < 0) {
+		pr_err("%s: failed to register listner\n", __func__);
+		goto fail;
+	}
+
+	file->private_data = pcm;
+	pr_info("[%s:%s] open session id[%d]\n", __MM_FILE__,
+				__func__, pcm->ac->session);
+	return 0;
+fail:
+	if (pcm->ac)
+		q6asm_audio_client_free(pcm->ac);
+	kfree(pcm);
+	return rc;
+}
+
+static ssize_t pcm_out_write(struct file *file, const char __user *buf,
+					size_t count, loff_t *pos)
+{
+	struct pcm *pcm = file->private_data;
+	const char __user *start = buf;
+	int xfer;
+	char *bufptr;
+	uint32_t idx;
+	void *data;
+	int rc = 0;
+	uint32_t size;
+
+	if (!pcm->ac)
+		return -ENODEV;
+
+	if (!atomic_read(&pcm->out_enabled)) {
+		rc = config(pcm);
+		if (rc < 0)
+			return rc;
+	}
+
+	mutex_lock(&pcm->write_lock);
+	while (count > 0) {
+		rc = wait_event_timeout(pcm->write_wait,
+				(atomic_read(&pcm->out_count) ||
+				atomic_read(&pcm->out_stopped)), 1 * HZ);
+		if (!rc) {
+			pr_err("%s: wait_event_timeout failed for session %d\n",
+				__func__, pcm->ac->session);
+			goto fail;
+		}
+
+		if (atomic_read(&pcm->out_stopped) &&
+					!atomic_read(&pcm->out_count)) {
+			pr_info("%s: pcm stopped out_count 0\n", __func__);
+			mutex_unlock(&pcm->write_lock);
+			return 0;
+		}
+
+		data = q6asm_is_cpu_buf_avail(IN, pcm->ac, &size, &idx);
+		bufptr = data;
+		if (bufptr) {
+			xfer = count;
+			if (xfer > BUFSZ)
+				xfer = BUFSZ;
+
+			if (copy_from_user(bufptr, buf, xfer)) {
+				rc = -EFAULT;
+				goto fail;
+			}
+			buf += xfer;
+			count -= xfer;
+			rc = q6asm_write(pcm->ac, xfer, 0, 0, NO_TIMESTAMP);
+			wmb();
+			if (rc < 0) {
+				rc = -EFAULT;
+				goto fail;
+			}
+		}
+		atomic_dec(&pcm->out_count);
+	}
+
+	rc = buf - start;
+fail:
+	mutex_unlock(&pcm->write_lock);
+	return rc;
+}
+
+static int pcm_out_release(struct inode *inode, struct file *file)
+{
+	struct pcm *pcm = file->private_data;
+
+	pr_info("[%s:%s] release session id[%d]\n", __MM_FILE__,
+				__func__, pcm->ac->session);
+	if (pcm->ac)
+		pcm_out_disable(pcm);
+	msm_clear_session_id(pcm->ac->session);
+	auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, pcm->ac->session);
+	q6asm_audio_client_free(pcm->ac);
+	audio_allow_sleep(pcm);
+	wake_lock_destroy(&pcm->wakelock);
+	mutex_destroy(&pcm->lock);
+	mutex_destroy(&pcm->write_lock);
+	kfree(pcm);
+	return 0;
+}
+
+static const struct file_operations pcm_out_fops = {
+	.owner		= THIS_MODULE,
+	.open		= pcm_out_open,
+	.write		= pcm_out_write,
+	.release	= pcm_out_release,
+	.unlocked_ioctl	= pcm_out_ioctl,
+};
+
+struct miscdevice pcm_out_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_pcm_out",
+	.fops	= &pcm_out_fops,
+};
+
+static int __init pcm_out_init(void)
+{
+	return misc_register(&pcm_out_misc);
+}
+
+device_initcall(pcm_out_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/q6audio_common.h b/arch/arm/mach-msm/qdsp6v2/q6audio_common.h
new file mode 100644
index 0000000..e108de5
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/q6audio_common.h
@@ -0,0 +1,35 @@
+/* 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.
+ *
+*/
+
+/* For Decoders */
+#ifndef __Q6_AUDIO_COMMON_H__
+#define __Q6_AUDIO_COMMON_H__
+
+#include <sound/apr_audio.h>
+#include <sound/q6asm.h>
+
+void q6_audio_cb(uint32_t opcode, uint32_t token,
+		uint32_t *payload, void *priv);
+
+void audio_aio_cb(uint32_t opcode, uint32_t token,
+			uint32_t *payload,  void *audio);
+
+
+/* For Encoders */
+void q6asm_in_cb(uint32_t opcode, uint32_t token,
+		uint32_t *payload, void *priv);
+
+void  audio_in_get_dsp_frames(void *audio,
+		uint32_t token,	uint32_t *payload);
+
+#endif /*__Q6_AUDIO_COMMON_H__*/
diff --git a/arch/arm/mach-msm/qdsp6v2/q6audio_v1.c b/arch/arm/mach-msm/qdsp6v2/q6audio_v1.c
new file mode 100644
index 0000000..f49d6e0
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/q6audio_v1.c
@@ -0,0 +1,92 @@
+/*
+ * 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/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include "audio_utils.h"
+
+void q6asm_in_cb(uint32_t opcode, uint32_t token,
+		uint32_t *payload, void *priv)
+{
+	struct q6audio_in * audio = (struct q6audio_in *)priv;
+	unsigned long flags;
+
+	pr_debug("%s:session id %d: opcode[0x%x]\n", __func__,
+			audio->ac->session, opcode);
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	switch (opcode) {
+	case ASM_DATA_EVENT_READ_DONE:
+		audio_in_get_dsp_frames(audio, token, payload);
+		break;
+	case ASM_DATA_EVENT_WRITE_DONE:
+		atomic_inc(&audio->in_count);
+		wake_up(&audio->write_wait);
+		break;
+	case ASM_DATA_CMDRSP_EOS:
+		audio->eos_rsp = 1;
+		wake_up(&audio->read_wait);
+		break;
+	case ASM_STREAM_CMDRSP_GET_ENCDEC_PARAM:
+		break;
+	case ASM_STREAM_CMDRSP_GET_PP_PARAMS:
+		break;
+	case ASM_SESSION_EVENT_TX_OVERFLOW:
+		pr_err("%s:session id %d: ASM_SESSION_EVENT_TX_OVERFLOW\n",
+			__func__, audio->ac->session);
+		break;
+	default:
+		pr_debug("%s:session id %d: Ignore opcode[0x%x]\n", __func__,
+			audio->ac->session, opcode);
+		break;
+	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+void  audio_in_get_dsp_frames(/*struct q6audio_in *audio,*/void *aud,
+	uint32_t token,	uint32_t *payload)
+{
+	struct q6audio_in *audio = (struct q6audio_in *)aud;
+	uint32_t index;
+
+	index = token;
+	pr_debug("%s:session id %d: index=%d nr frames=%d offset[%d]\n",
+			__func__, audio->ac->session, token, payload[7],
+			payload[3]);
+	pr_debug("%s:session id %d: timemsw=%d lsw=%d\n", __func__,
+			audio->ac->session, payload[4], payload[5]);
+	pr_debug("%s:session id %d: uflags=0x%8x uid=0x%8x\n", __func__,
+			audio->ac->session, payload[6], payload[8]);
+	pr_debug("%s:session id %d: enc frame size=0x%8x\n", __func__,
+			audio->ac->session, payload[2]);
+
+	audio->out_frame_info[index][0] = payload[7];
+	audio->out_frame_info[index][1] = payload[3];
+
+	/* statistics of read */
+	atomic_add(payload[2], &audio->in_bytes);
+	atomic_add(payload[7], &audio->in_samples);
+
+	if (atomic_read(&audio->out_count) <= audio->str_cfg.buffer_count) {
+		atomic_inc(&audio->out_count);
+		wake_up(&audio->read_wait);
+	}
+}
diff --git a/arch/arm/mach-msm/qdsp6v2/q6audio_v1_aio.c b/arch/arm/mach-msm/qdsp6v2/q6audio_v1_aio.c
new file mode 100644
index 0000000..112de62
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/q6audio_v1_aio.c
@@ -0,0 +1,113 @@
+/*
+ * 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/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include "audio_utils_aio.h"
+
+void q6_audio_cb(uint32_t opcode, uint32_t token,
+		uint32_t *payload, void *priv)
+{
+	struct q6audio_aio *audio = (struct q6audio_aio *)priv;
+
+	pr_debug("%s:opcode = %x token = 0x%x\n", __func__, opcode, token);
+	switch (opcode) {
+	case ASM_DATA_EVENT_WRITE_DONE:
+	case ASM_DATA_EVENT_READ_DONE:
+	case ASM_DATA_CMDRSP_EOS:
+	case ASM_DATA_CMD_MEDIA_FORMAT_UPDATE:
+	case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
+	case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
+	case ASM_DATA_EVENT_ENC_SR_CM_NOTIFY:
+		audio_aio_cb(opcode, token, payload, audio);
+		break;
+	default:
+		pr_debug("%s:Unhandled event = 0x%8x\n", __func__, opcode);
+		break;
+	}
+}
+
+void audio_aio_cb(uint32_t opcode, uint32_t token,
+		uint32_t *payload,  void *priv)
+{
+	union msm_audio_event_payload e_payload;
+	struct q6audio_aio *audio = (struct q6audio_aio *)priv;
+
+	switch (opcode) {
+	case ASM_DATA_EVENT_WRITE_DONE:
+		pr_debug("%s[%p]:ASM_DATA_EVENT_WRITE_DONE token = 0x%x\n",
+			__func__, audio, token);
+		audio_aio_async_write_ack(audio, token, payload);
+		break;
+	case ASM_DATA_EVENT_READ_DONE:
+		pr_debug("%s[%p]:ASM_DATA_EVENT_READ_DONE token = 0x%x\n",
+			__func__, audio, token);
+		audio_aio_async_read_ack(audio, token, payload);
+		break;
+	case ASM_DATA_CMDRSP_EOS:
+		/* EOS Handle */
+		pr_debug("%s[%p]:ASM_DATA_CMDRSP_EOS\n", __func__, audio);
+		if (audio->feedback) { /* Non-Tunnel mode */
+			audio->eos_rsp = 1;
+			/* propagate input EOS i/p buffer,
+			after receiving DSP acknowledgement */
+			if (audio->eos_flag &&
+				(audio->eos_write_payload.aio_buf.buf_addr)) {
+				audio_aio_post_event(audio,
+						AUDIO_EVENT_WRITE_DONE,
+						audio->eos_write_payload);
+				memset(&audio->eos_write_payload , 0,
+					sizeof(union msm_audio_event_payload));
+				audio->eos_flag = 0;
+			}
+		} else { /* Tunnel mode */
+			audio->eos_rsp = 1;
+			wake_up(&audio->write_wait);
+			wake_up(&audio->cmd_wait);
+		}
+		break;
+	case ASM_DATA_CMD_MEDIA_FORMAT_UPDATE:
+	case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
+		pr_debug("%s[%p]:payload0[%x] payloa1d[%x]opcode= 0x%x\n",
+			__func__, audio, payload[0], payload[1], opcode);
+		break;
+	case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
+	case ASM_DATA_EVENT_ENC_SR_CM_NOTIFY:
+		pr_debug("%s[%p]: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, "
+
+				"payload[0]-sr = %d, payload[1]-chl = %d, "
+				"payload[2] = %d, payload[3] = %d\n", __func__,
+				audio, payload[0], payload[1], payload[2],
+				payload[3]);
+		pr_debug("%s[%p]: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, "
+				"sr(prev) = %d, chl(prev) = %d,",
+				__func__, audio, audio->pcm_cfg.sample_rate,
+		audio->pcm_cfg.channel_count);
+		audio->pcm_cfg.sample_rate = payload[0];
+		audio->pcm_cfg.channel_count = payload[1] & 0xFFFF;
+		e_payload.stream_info.chan_info = audio->pcm_cfg.channel_count;
+		e_payload.stream_info.sample_rate = audio->pcm_cfg.sample_rate;
+		audio_aio_post_event(audio, AUDIO_EVENT_STREAM_INFO, e_payload);
+		break;
+	default:
+		break;
+	}
+}
diff --git a/arch/arm/mach-msm/qdsp6v2/q6core.c b/arch/arm/mach-msm/qdsp6v2/q6core.c
new file mode 100644
index 0000000..edb1e7d
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/q6core.c
@@ -0,0 +1,409 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <mach/msm_smd.h>
+#include <mach/qdsp6v2/apr.h>
+#include "q6core.h"
+
+#define TIMEOUT_MS 1000
+
+static struct apr_svc *apr_handle_q;
+static struct apr_svc *apr_handle_m;
+static struct apr_svc *core_handle_q;
+
+static int32_t query_adsp_ver;
+static wait_queue_head_t adsp_version_wait;
+static uint32_t adsp_version;
+
+static wait_queue_head_t bus_bw_req_wait;
+static u32 bus_bw_resp_received;
+
+static struct dentry *dentry;
+static char l_buf[4096];
+
+static int32_t aprv2_core_fn_q(struct apr_client_data *data, void *priv)
+{
+	struct adsp_get_version *payload;
+	uint32_t *payload1;
+	struct adsp_service_info *svc_info;
+	int i;
+
+	pr_info("core msg: payload len = %u, apr resp opcode = 0x%X\n",
+		data->payload_size, data->opcode);
+
+	switch (data->opcode) {
+
+	case APR_BASIC_RSP_RESULT:{
+
+		if (data->payload_size == 0) {
+			pr_err("%s: APR_BASIC_RSP_RESULT No Payload ",
+					__func__);
+			return 0;
+		}
+
+		payload1 = data->payload;
+
+		switch (payload1[0]) {
+
+		case ADSP_CMD_SET_POWER_COLLAPSE_STATE:
+			pr_info("Cmd = ADSP_CMD_SET_POWER_COLLAPSE_STATE"
+				" status[0x%x]\n", payload1[1]);
+			break;
+		case ADSP_CMD_REMOTE_BUS_BW_REQUEST:
+			pr_info("%s: cmd = ADSP_CMD_REMOTE_BUS_BW_REQUEST"
+				"  status = 0x%x\n", __func__, payload1[1]);
+
+			bus_bw_resp_received = 1;
+			wake_up(&bus_bw_req_wait);
+			break;
+		default:
+			pr_err("Invalid cmd rsp[0x%x][0x%x]\n",
+					payload1[0], payload1[1]);
+			break;
+		}
+		break;
+	}
+	case ADSP_GET_VERSION_RSP:{
+		if (data->payload_size) {
+			payload = data->payload;
+			if (query_adsp_ver == 1) {
+				query_adsp_ver = 0;
+				adsp_version  = payload->build_id;
+				wake_up(&adsp_version_wait);
+			}
+			svc_info = (struct adsp_service_info *)
+			((char *)payload + sizeof(struct adsp_get_version));
+			pr_info("----------------------------------------\n");
+			pr_info("Build id          = %x\n", payload->build_id);
+			pr_info("Number of services= %x\n", payload->svc_cnt);
+			pr_info("----------------------------------------\n");
+			for (i = 0; i < payload->svc_cnt; i++) {
+				pr_info("svc-id[%d]\tver[%x.%x]\n",
+					svc_info[i].svc_id,
+					(svc_info[i].svc_ver & 0xFFFF0000)
+					>> 16,
+					(svc_info[i].svc_ver & 0xFFFF));
+			}
+			pr_info("-----------------------------------------\n");
+		} else
+			pr_info("zero payload for ADSP_GET_VERSION_RSP\n");
+		break;
+	}
+	case RESET_EVENTS:{
+		pr_debug("Reset event received in Core service");
+		apr_reset(core_handle_q);
+		core_handle_q = NULL;
+		break;
+	}
+
+	default:
+		pr_err("Message id from adsp core svc: %d\n", data->opcode);
+		break;
+	}
+
+	return 0;
+}
+
+static int32_t aprv2_debug_fn_q(struct apr_client_data *data, void *priv)
+{
+	pr_debug("Q6_Payload Length = %d\n", data->payload_size);
+	if (memcmp(data->payload, l_buf + 20, data->payload_size))
+		pr_info("FAIL: %d\n", data->payload_size);
+	else
+		pr_info("SUCCESS: %d\n", data->payload_size);
+	return 0;
+}
+
+static int32_t aprv2_debug_fn_m(struct apr_client_data *data, void *priv)
+{
+	pr_info("M_Payload Length = %d\n", data->payload_size);
+	return 0;
+}
+
+static ssize_t apr_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	pr_debug("apr debugfs opened\n");
+	return 0;
+}
+
+void core_open(void)
+{
+	if (core_handle_q == NULL) {
+		core_handle_q = apr_register("ADSP", "CORE",
+					aprv2_core_fn_q, 0xFFFFFFFF, NULL);
+	}
+	pr_info("Open_q %p\n", core_handle_q);
+	if (core_handle_q == NULL) {
+		pr_err("%s: Unable to register CORE\n", __func__);
+	}
+}
+
+int core_req_bus_bandwith(u16 bus_id, u32 ab_bps, u32 ib_bps)
+{
+	struct adsp_cmd_remote_bus_bw_request bus_bw_req;
+	int ret;
+
+	pr_debug("%s: bus_id %u ab_bps %u ib_bps %u\n",
+			__func__, bus_id, ab_bps, ib_bps);
+
+	core_open();
+	if (core_handle_q == NULL) {
+		pr_info("%s: apr registration for CORE failed\n", __func__);
+		return -ENODEV;
+	}
+
+	bus_bw_req.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	bus_bw_req.hdr.pkt_size = sizeof(struct adsp_cmd_remote_bus_bw_request);
+
+	bus_bw_req.hdr.src_port = 0;
+	bus_bw_req.hdr.dest_port = 0;
+	bus_bw_req.hdr.token = 0;
+	bus_bw_req.hdr.opcode = ADSP_CMD_REMOTE_BUS_BW_REQUEST;
+
+	bus_bw_req.bus_identifier = bus_id;
+	bus_bw_req.reserved = 0;
+	bus_bw_req.ab_bps = ab_bps;
+	bus_bw_req.ib_bps = ib_bps;
+
+	bus_bw_resp_received = 0;
+	ret = apr_send_pkt(core_handle_q, (uint32_t *) &bus_bw_req);
+	if (ret < 0) {
+		pr_err("%s: CORE bus bw request failed\n", __func__);
+		goto fail_cmd;
+	}
+
+	ret = wait_event_timeout(bus_bw_req_wait, (bus_bw_resp_received == 1),
+				msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		ret = -ETIME;
+		goto fail_cmd;
+	}
+
+	return 0;
+
+fail_cmd:
+	return ret;
+}
+
+uint32_t core_get_adsp_version(void)
+{
+	struct apr_hdr *hdr;
+	int32_t rc = 0, ret = 0;
+	core_open();
+	if (core_handle_q) {
+		hdr = (struct apr_hdr *)l_buf;
+		hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
+					APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+		hdr->pkt_size = APR_PKT_SIZE(APR_HDR_SIZE, 0);
+		hdr->src_port = 0;
+		hdr->dest_port = 0;
+		hdr->token = 0;
+		hdr->opcode = ADSP_GET_VERSION;
+
+		apr_send_pkt(core_handle_q, (uint32_t *)l_buf);
+		query_adsp_ver = 1;
+		pr_info("Write_q\n");
+		ret = wait_event_timeout(adsp_version_wait,
+					(query_adsp_ver == 0),
+					msecs_to_jiffies(TIMEOUT_MS));
+		rc = adsp_version;
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+			rc = -ENODEV;
+		}
+	} else
+		pr_info("apr registration failed\n");
+	return rc;
+}
+EXPORT_SYMBOL(core_get_adsp_version);
+
+static ssize_t apr_debug_write(struct file *file, const char __user *buf,
+				size_t count, loff_t *ppos)
+{
+	int len;
+	static int t_len;
+
+	if (count < 0)
+		return 0;
+	len = count > 63 ? 63 : count;
+	if (copy_from_user(l_buf + 20 , buf, len)) {
+		pr_info("Unable to copy data from user space\n");
+		return -EFAULT;
+	}
+	l_buf[len + 20] = 0;
+	if (l_buf[len + 20 - 1] == '\n') {
+		l_buf[len + 20 - 1] = 0;
+		len--;
+	}
+	if (!strncmp(l_buf + 20, "open_q", 64)) {
+		apr_handle_q = apr_register("ADSP", "TEST", aprv2_debug_fn_q,
+							0xFFFFFFFF, NULL);
+		pr_info("Open_q %p\n", apr_handle_q);
+	} else if (!strncmp(l_buf + 20, "open_m", 64)) {
+		apr_handle_m = apr_register("MODEM", "TEST", aprv2_debug_fn_m,
+							0xFFFFFFFF, NULL);
+		pr_info("Open_m %p\n", apr_handle_m);
+	} else if (!strncmp(l_buf + 20, "write_q", 64)) {
+		struct apr_hdr *hdr;
+
+		t_len++;
+		t_len = t_len % 450;
+		if (!t_len % 99)
+			msleep(2000);
+		hdr = (struct apr_hdr *)l_buf;
+		hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
+					APR_HDR_LEN(20), APR_PKT_VER);
+		hdr->pkt_size = APR_PKT_SIZE(20, t_len);
+		hdr->src_port = 0;
+		hdr->dest_port = 0;
+		hdr->token = 0;
+		hdr->opcode = 0x12345678;
+		memset(l_buf + 20, 9, 4060);
+
+		apr_send_pkt(apr_handle_q, (uint32_t *)l_buf);
+		pr_debug("Write_q\n");
+	} else if (!strncmp(l_buf + 20, "write_m", 64)) {
+		struct apr_hdr *hdr;
+
+		hdr = (struct apr_hdr *)l_buf;
+		hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
+					APR_HDR_LEN(20), APR_PKT_VER);
+		hdr->pkt_size = APR_PKT_SIZE(20, 8);
+		hdr->src_port = 0;
+		hdr->dest_port = 0;
+		hdr->token = 0;
+		hdr->opcode = 0x12345678;
+		memset(l_buf + 30, 9, 4060);
+
+		apr_send_pkt(apr_handle_m, (uint32_t *)l_buf);
+		pr_info("Write_m\n");
+	} else if (!strncmp(l_buf + 20, "write_q4", 64)) {
+		struct apr_hdr *hdr;
+
+		hdr = (struct apr_hdr *)l_buf;
+		hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
+					APR_HDR_LEN(20), APR_PKT_VER);
+		hdr->pkt_size = APR_PKT_SIZE(20, 4076);
+		hdr->src_port = 0;
+		hdr->dest_port = 0;
+		hdr->token = 0;
+		hdr->opcode = 0x12345678;
+		memset(l_buf + 30, 9, 4060);
+
+		apr_send_pkt(apr_handle_q, (uint32_t *)l_buf);
+		pr_info("Write_q\n");
+	} else if (!strncmp(l_buf + 20, "write_m4", 64)) {
+		struct apr_hdr *hdr;
+
+		hdr = (struct apr_hdr *)l_buf;
+		hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
+					APR_HDR_LEN(20), APR_PKT_VER);
+		hdr->pkt_size = APR_PKT_SIZE(20, 4076);
+		hdr->src_port = 0;
+		hdr->dest_port = 0;
+		hdr->token = 0;
+		hdr->opcode = 0x12345678;
+		memset(l_buf + 30, 9, 4060);
+
+		apr_send_pkt(apr_handle_m, (uint32_t *)l_buf);
+		pr_info("Write_m\n");
+	} else if (!strncmp(l_buf + 20, "close", 64)) {
+		if (apr_handle_q)
+			apr_deregister(apr_handle_q);
+	} else if (!strncmp(l_buf + 20, "loaded", 64)) {
+		change_q6_state(APR_Q6_LOADED);
+	} else if (!strncmp(l_buf + 20, "boom", 64)) {
+		q6audio_dsp_not_responding();
+	} else if (!strncmp(l_buf + 20, "dsp_ver", 64)) {
+			core_get_adsp_version();
+	} else if (!strncmp(l_buf + 20, "en_pwr_col", 64)) {
+		struct adsp_power_collapse pc;
+
+		core_open();
+		if (core_handle_q) {
+			pc.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
+					APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+			pc.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+						sizeof(uint32_t));;
+			pc.hdr.src_port = 0;
+			pc.hdr.dest_port = 0;
+			pc.hdr.token = 0;
+			pc.hdr.opcode = ADSP_CMD_SET_POWER_COLLAPSE_STATE;
+			pc.power_collapse = 0x00000000;
+			apr_send_pkt(core_handle_q, (uint32_t *)&pc);
+			pr_info("Write_q :enable power collapse\n");
+		}
+	} else if (!strncmp(l_buf + 20, "dis_pwr_col", 64)) {
+		struct adsp_power_collapse pc;
+
+		core_open();
+		if (core_handle_q) {
+			pc.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
+					APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+			pc.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+							sizeof(uint32_t));
+			pc.hdr.src_port = 0;
+			pc.hdr.dest_port = 0;
+			pc.hdr.token = 0;
+			pc.hdr.opcode = ADSP_CMD_SET_POWER_COLLAPSE_STATE;
+			pc.power_collapse = 0x00000001;
+			apr_send_pkt(core_handle_q, (uint32_t *)&pc);
+			pr_info("Write_q:disable power collapse\n");
+		}
+	} else
+		pr_info("Unknown Command\n");
+
+	return count;
+}
+
+static const struct file_operations apr_debug_fops = {
+	.write = apr_debug_write,
+	.open = apr_debug_open,
+};
+
+static int __init core_init(void)
+{
+	init_waitqueue_head(&bus_bw_req_wait);
+	bus_bw_resp_received = 0;
+
+	query_adsp_ver = 0;
+	init_waitqueue_head(&adsp_version_wait);
+	adsp_version = 0;
+
+	core_handle_q = NULL;
+
+#ifdef CONFIG_DEBUG_FS
+	dentry = debugfs_create_file("apr", S_IFREG | S_IRUGO | S_IWUSR
+		| S_IWGRP, NULL, (void *) NULL, &apr_debug_fops);
+#endif /* CONFIG_DEBUG_FS */
+
+	return 0;
+}
+
+device_initcall(core_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/q6core.h b/arch/arm/mach-msm/qdsp6v2/q6core.h
new file mode 100644
index 0000000..cb25d6b
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/q6core.h
@@ -0,0 +1,52 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __Q6CORE_H__
+#define __Q6CORE_H__
+#include <mach/qdsp6v2/apr.h>
+
+
+#define ADSP_CMD_REMOTE_BUS_BW_REQUEST		0x0001115D
+#define AUDIO_IF_BUS_ID				1
+
+struct adsp_cmd_remote_bus_bw_request {
+	struct apr_hdr hdr;
+	u16 bus_identifier;
+	u16 reserved;
+	u32 ab_bps;
+	u32 ib_bps;
+} __packed;
+
+#define ADSP_GET_VERSION     0x00011152
+#define ADSP_GET_VERSION_RSP 0x00011153
+
+struct adsp_get_version {
+	uint32_t build_id;
+	uint32_t svc_cnt;
+};
+
+struct adsp_service_info {
+	uint32_t svc_id;
+	uint32_t svc_ver;
+};
+
+#define ADSP_CMD_SET_POWER_COLLAPSE_STATE 0x0001115C
+struct adsp_power_collapse {
+	struct apr_hdr hdr;
+	uint32_t power_collapse;
+};
+
+int core_req_bus_bandwith(u16 bus_id, u32 ab_bps, u32 ib_bps);
+
+uint32_t core_get_adsp_version(void);
+
+#endif /* __Q6CORE_H__ */
diff --git a/arch/arm/mach-msm/qdsp6v2/q6voice.c b/arch/arm/mach-msm/qdsp6v2/q6voice.c
new file mode 100644
index 0000000..12a02c5
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/q6voice.c
@@ -0,0 +1,2948 @@
+/* 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
+ * 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/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/msm_audio.h>
+#include <linux/kthread.h>
+#include <linux/completion.h>
+#include <linux/wait.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+#include <mach/dal.h>
+#include <mach/qdsp6v2/q6voice.h>
+#include <mach/qdsp6v2/rtac.h>
+#include <mach/qdsp6v2/audio_acdb.h>
+
+#include "q6core.h"
+
+
+#define TIMEOUT_MS 3000
+#define SNDDEV_CAP_TTY 0x20
+#define CMD_STATUS_SUCCESS 0
+#define CMD_STATUS_FAIL 1
+
+/* Voice session creates passive control sessions for MVM and CVS. */
+#define VOC_PATH_PASSIVE 0
+
+/* VoIP session creates full control sessions for MVM and CVS. */
+#define VOC_PATH_FULL 1
+
+#define ADSP_VERSION_CVD 0x60300000
+
+#define BUFFER_PAYLOAD_SIZE 4000
+
+#define VOC_REC_NONE 0xFF
+
+struct common_data common;
+
+static bool is_adsp_support_cvd(void)
+{
+	return (common.adsp_version >= ADSP_VERSION_CVD);
+}
+static int voice_send_enable_vocproc_cmd(struct voice_data *v);
+static int voice_send_netid_timing_cmd(struct voice_data *v);
+
+static void *voice_get_apr_mvm(void)
+{
+	void *apr_mvm = NULL;
+
+	if (common.voc_path == VOC_PATH_PASSIVE &&
+		!(is_adsp_support_cvd()))
+		apr_mvm = common.apr_mvm;
+	else
+		apr_mvm = common.apr_q6_mvm;
+
+	pr_debug("%s: apr_mvm 0x%x\n", __func__, (unsigned int)apr_mvm);
+
+	return apr_mvm;
+}
+
+static void voice_set_apr_mvm(void *apr_mvm)
+{
+	pr_debug("%s: apr_mvm 0x%x\n", __func__, (unsigned int)apr_mvm);
+
+	if (common.voc_path == VOC_PATH_PASSIVE &&
+		!(is_adsp_support_cvd()))
+		common.apr_mvm = apr_mvm;
+	else
+		common.apr_q6_mvm = apr_mvm;
+}
+
+static void *voice_get_apr_cvs(void)
+{
+	void *apr_cvs = NULL;
+
+	if (common.voc_path == VOC_PATH_PASSIVE &&
+		!(is_adsp_support_cvd()))
+		apr_cvs = common.apr_cvs;
+	else
+		apr_cvs = common.apr_q6_cvs;
+
+	pr_debug("%s: apr_cvs 0x%x\n", __func__, (unsigned int)apr_cvs);
+
+	return apr_cvs;
+}
+
+static void voice_set_apr_cvs(void *apr_cvs)
+{
+	pr_debug("%s: apr_cvs 0x%x\n", __func__, (unsigned int)apr_cvs);
+
+	if (common.voc_path == VOC_PATH_PASSIVE &&
+		!(is_adsp_support_cvd()))
+		common.apr_cvs = apr_cvs;
+	else
+		common.apr_q6_cvs = apr_cvs;
+	rtac_set_voice_handle(RTAC_CVS, apr_cvs);
+}
+
+static void *voice_get_apr_cvp(void)
+{
+	void *apr_cvp = NULL;
+
+	if (common.voc_path == VOC_PATH_PASSIVE &&
+		!(is_adsp_support_cvd()))
+		apr_cvp = common.apr_cvp;
+	else
+		apr_cvp = common.apr_q6_cvp;
+
+	pr_debug("%s: apr_cvp 0x%x\n", __func__, (unsigned int)apr_cvp);
+
+	return apr_cvp;
+}
+
+static void voice_set_apr_cvp(void *apr_cvp)
+{
+	pr_debug("%s: apr_cvp 0x%x\n", __func__, (unsigned int)apr_cvp);
+
+	if (common.voc_path == VOC_PATH_PASSIVE &&
+		!(is_adsp_support_cvd()))
+		common.apr_cvp = apr_cvp;
+	else
+		common.apr_q6_cvp = apr_cvp;
+	rtac_set_voice_handle(RTAC_CVP, apr_cvp);
+}
+
+static u16 voice_get_mvm_handle(struct voice_data *v)
+{
+	pr_debug("%s: mvm_handle %d\n", __func__, v->mvm_handle);
+
+	return v->mvm_handle;
+}
+
+static void voice_set_mvm_handle(struct voice_data *v, u16 mvm_handle)
+{
+	pr_debug("%s: session 0x%x, mvm_handle %d\n",
+		 __func__, (unsigned int)v, mvm_handle);
+
+	v->mvm_handle = mvm_handle;
+}
+
+static u16 voice_get_cvs_handle(struct voice_data *v)
+{
+	pr_debug("%s: cvs_handle %d\n", __func__, v->cvs_handle);
+
+	return v->cvs_handle;
+}
+
+static void voice_set_cvs_handle(struct voice_data *v, u16 cvs_handle)
+{
+	pr_debug("%s: session 0x%x, cvs_handle %d\n",
+		 __func__, (unsigned int)v, cvs_handle);
+
+	v->cvs_handle = cvs_handle;
+}
+
+static u16 voice_get_cvp_handle(struct voice_data *v)
+{
+	pr_debug("%s: cvp_handle %d\n", __func__, v->cvp_handle);
+
+	return v->cvp_handle;
+}
+
+static void voice_set_cvp_handle(struct voice_data *v, u16 cvp_handle)
+{
+	pr_debug("%s: session 0x%x, cvp_handle %d\n",
+		 __func__, (unsigned int)v, cvp_handle);
+
+	v->cvp_handle = cvp_handle;
+}
+
+u16 voice_get_session_id(const char *name)
+{
+	u16 session_id = 0;
+
+	if (name != NULL) {
+		if (!strncmp(name, "Voice session", 13))
+			session_id = common.voice[VOC_PATH_PASSIVE].session_id;
+		else
+			session_id = common.voice[VOC_PATH_FULL].session_id;
+	}
+
+	pr_debug("%s: %s has session id 0x%x\n", __func__, name, session_id);
+
+	return session_id;
+}
+
+static struct voice_data *voice_get_session(u16 session_id)
+{
+	struct voice_data *v = NULL;
+
+	if (session_id == 0) {
+		mutex_lock(&common.common_lock);
+
+		pr_debug("%s: NULL id, voc_path is %d\n",
+			 __func__, common.voc_path);
+
+		if (common.voc_path == VOC_PATH_PASSIVE)
+			v = &common.voice[VOC_PATH_PASSIVE];
+		else
+			v = &common.voice[VOC_PATH_FULL];
+
+		mutex_unlock(&common.common_lock);
+	} else if ((session_id >= SESSION_ID_BASE) &&
+		   (session_id < SESSION_ID_BASE + MAX_VOC_SESSIONS))  {
+		v = &common.voice[session_id - SESSION_ID_BASE];
+	} else {
+		pr_err("%s: Invalid session_id 0x%x\n", __func__, session_id);
+	}
+
+	pr_debug("%s: session_id 0x%x session handle 0x%x\n",
+		 __func__, session_id, (unsigned int)v);
+
+	return v;
+}
+
+static bool is_voice_session(u16 session_id)
+{
+	return (session_id == common.voice[VOC_PATH_PASSIVE].session_id);
+}
+
+static bool is_voip_session(u16 session_id)
+{
+	return (session_id == common.voice[VOC_PATH_FULL].session_id);
+}
+
+static void voice_auddev_cb_function(u32 evt_id,
+			union auddev_evt_data *evt_payload,
+			void *private_data);
+
+static int32_t modem_mvm_callback(struct apr_client_data *data, void *priv);
+static int32_t modem_cvs_callback(struct apr_client_data *data, void *priv);
+static int32_t modem_cvp_callback(struct apr_client_data *data, void *priv);
+
+static int voice_apr_register(void)
+{
+	int rc = 0;
+	void *apr_mvm;
+	void *apr_cvs;
+	void *apr_cvp;
+
+	if (common.adsp_version == 0) {
+		common.adsp_version = core_get_adsp_version();
+		pr_info("adsp_ver fetched:%x\n", common.adsp_version);
+	}
+
+	mutex_lock(&common.common_lock);
+
+	apr_mvm = voice_get_apr_mvm();
+	apr_cvs = voice_get_apr_cvs();
+	apr_cvp = voice_get_apr_cvp();
+
+
+	pr_debug("into voice_apr_register_callback\n");
+	/* register callback to APR */
+	if (apr_mvm == NULL) {
+		pr_debug("start to register MVM callback\n");
+
+		if (common.voc_path == VOC_PATH_PASSIVE &&
+			!(is_adsp_support_cvd())) {
+			apr_mvm = apr_register("MODEM", "MVM",
+					       modem_mvm_callback, 0xFFFFFFFF,
+					       &common);
+		} else {
+			apr_mvm = apr_register("ADSP", "MVM",
+					       modem_mvm_callback, 0xFFFFFFFF,
+					       &common);
+		}
+
+		if (apr_mvm == NULL) {
+			pr_err("Unable to register MVM %d\n",
+						is_adsp_support_cvd());
+			rc = -ENODEV;
+			goto done;
+		}
+
+		voice_set_apr_mvm(apr_mvm);
+	}
+
+	if (apr_cvs == NULL) {
+		pr_debug("start to register CVS callback\n");
+
+		if (common.voc_path == VOC_PATH_PASSIVE &&
+			!(is_adsp_support_cvd())) {
+			apr_cvs = apr_register("MODEM", "CVS",
+					       modem_cvs_callback, 0xFFFFFFFF,
+					       &common);
+		} else {
+			apr_cvs = apr_register("ADSP", "CVS",
+					       modem_cvs_callback, 0xFFFFFFFF,
+					       &common);
+		}
+
+		if (apr_cvs == NULL) {
+			pr_err("Unable to register CVS %d\n",
+							is_adsp_support_cvd());
+			rc = -ENODEV;
+			goto err;
+		}
+
+		voice_set_apr_cvs(apr_cvs);
+	}
+
+	if (apr_cvp == NULL) {
+		pr_debug("start to register CVP callback\n");
+
+		if (common.voc_path == VOC_PATH_PASSIVE &&
+			!(is_adsp_support_cvd())) {
+			apr_cvp = apr_register("MODEM", "CVP",
+					       modem_cvp_callback, 0xFFFFFFFF,
+					       &common);
+		} else {
+			apr_cvp = apr_register("ADSP", "CVP",
+					       modem_cvp_callback, 0xFFFFFFFF,
+					       &common);
+	}
+
+		if (apr_cvp == NULL) {
+			pr_err("Unable to register CVP %d\n",
+							is_adsp_support_cvd());
+			rc = -ENODEV;
+			goto err1;
+		}
+
+		voice_set_apr_cvp(apr_cvp);
+	}
+
+	mutex_unlock(&common.common_lock);
+
+	return 0;
+
+err1:
+	apr_deregister(apr_cvs);
+	apr_cvs = NULL;
+	voice_set_apr_cvs(apr_cvs);
+err:
+	apr_deregister(apr_mvm);
+	apr_mvm = NULL;
+	voice_set_apr_mvm(apr_mvm);
+
+done:
+	mutex_unlock(&common.common_lock);
+
+	return rc;
+}
+
+static int voice_create_mvm_cvs_session(struct voice_data *v)
+{
+	int ret = 0;
+	struct mvm_create_ctl_session_cmd mvm_session_cmd;
+	struct cvs_create_passive_ctl_session_cmd cvs_session_cmd;
+	struct cvs_create_full_ctl_session_cmd cvs_full_ctl_cmd;
+	struct mvm_attach_stream_cmd attach_stream_cmd;
+	void *apr_mvm = voice_get_apr_mvm();
+	void *apr_cvs = voice_get_apr_cvs();
+	void *apr_cvp = voice_get_apr_cvp();
+	u16 mvm_handle = voice_get_mvm_handle(v);
+	u16 cvs_handle = voice_get_cvs_handle(v);
+	u16 cvp_handle = voice_get_cvp_handle(v);
+
+	pr_info("%s:\n", __func__);
+
+	/* start to ping if modem service is up */
+	pr_debug("in voice_create_mvm_cvs_session, mvm_hdl=%d, cvs_hdl=%d\n",
+					mvm_handle, cvs_handle);
+	/* send cmd to create mvm session and wait for response */
+
+	if (!mvm_handle) {
+		if (is_voice_session(v->session_id)) {
+			mvm_session_cmd.hdr.hdr_field =
+				APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+			mvm_session_cmd.hdr.pkt_size =
+				APR_PKT_SIZE(APR_HDR_SIZE,
+					sizeof(mvm_session_cmd) - APR_HDR_SIZE);
+			pr_debug("Send mvm create session pkt size = %d\n",
+				mvm_session_cmd.hdr.pkt_size);
+			mvm_session_cmd.hdr.src_port = v->session_id;
+			mvm_session_cmd.hdr.dest_port = 0;
+			mvm_session_cmd.hdr.token = 0;
+			pr_debug("%s: Creating MVM passive ctrl\n", __func__);
+			mvm_session_cmd.hdr.opcode =
+				VSS_IMVM_CMD_CREATE_PASSIVE_CONTROL_SESSION;
+			strncpy(mvm_session_cmd.mvm_session.name,
+				"default modem voice", SESSION_NAME_LEN);
+
+			v->mvm_state = CMD_STATUS_FAIL;
+
+			ret = apr_send_pkt(apr_mvm,
+					   (uint32_t *) &mvm_session_cmd);
+			if (ret < 0) {
+				pr_err("Error sending MVM_CONTROL_SESSION\n");
+				goto fail;
+			}
+			ret = wait_event_timeout(v->mvm_wait,
+					 (v->mvm_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+			if (!ret) {
+				pr_err("%s: wait_event timeout\n", __func__);
+				goto fail;
+			}
+		} else {
+			mvm_session_cmd.hdr.hdr_field =
+				APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+			mvm_session_cmd.hdr.pkt_size =
+				APR_PKT_SIZE(APR_HDR_SIZE,
+				       sizeof(mvm_session_cmd) - APR_HDR_SIZE);
+			pr_debug("Send mvm create session pkt size = %d\n",
+				mvm_session_cmd.hdr.pkt_size);
+			mvm_session_cmd.hdr.src_port = v->session_id;
+			mvm_session_cmd.hdr.dest_port = 0;
+			mvm_session_cmd.hdr.token = 0;
+			pr_debug("%s: Creating MVM full ctrl\n", __func__);
+			mvm_session_cmd.hdr.opcode =
+				VSS_IMVM_CMD_CREATE_FULL_CONTROL_SESSION;
+			strncpy(mvm_session_cmd.mvm_session.name,
+				"default voip", SESSION_NAME_LEN);
+
+			v->mvm_state = CMD_STATUS_FAIL;
+
+			ret = apr_send_pkt(apr_mvm,
+					   (uint32_t *) &mvm_session_cmd);
+			if (ret < 0) {
+				pr_err("Error sending MVM_FULL_CTL_SESSION\n");
+				goto fail;
+			}
+			ret = wait_event_timeout(v->mvm_wait,
+					 (v->mvm_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+			if (!ret) {
+				pr_err("%s: wait_event timeout\n", __func__);
+				goto fail;
+			}
+		}
+
+		/* Get the created MVM handle. */
+		mvm_handle = voice_get_mvm_handle(v);
+	}
+
+	/* send cmd to create cvs session */
+	if (!cvs_handle) {
+		if (is_voice_session(v->session_id)) {
+			pr_info("%s:creating CVS passive session\n", __func__);
+
+		cvs_session_cmd.hdr.hdr_field = APR_HDR_FIELD(
+						APR_MSG_TYPE_SEQ_CMD,
+					APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+		cvs_session_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+					sizeof(cvs_session_cmd) - APR_HDR_SIZE);
+		pr_info("send stream create session pkt size = %d\n",
+					cvs_session_cmd.hdr.pkt_size);
+		cvs_session_cmd.hdr.src_port = v->session_id;
+		cvs_session_cmd.hdr.dest_port = 0;
+		cvs_session_cmd.hdr.token = 0;
+		cvs_session_cmd.hdr.opcode =
+				VSS_ISTREAM_CMD_CREATE_PASSIVE_CONTROL_SESSION;
+		strncpy(cvs_session_cmd.cvs_session.name,
+			"default modem voice", SESSION_NAME_LEN);
+
+		v->cvs_state = CMD_STATUS_FAIL;
+
+		pr_info("%s: CVS create\n", __func__);
+		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_session_cmd);
+		if (ret < 0) {
+			pr_err("Fail in sending STREAM_CONTROL_SESSION\n");
+			goto fail;
+		}
+		ret = wait_event_timeout(v->cvs_wait,
+					 (v->cvs_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+			goto fail;
+		}
+
+			/* Get the created CVS handle. */
+			cvs_handle = voice_get_cvs_handle(v);
+		} else {
+			pr_info("%s:creating CVS full session\n", __func__);
+
+			cvs_full_ctl_cmd.hdr.hdr_field =
+				APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					      APR_HDR_LEN(APR_HDR_SIZE),
+					      APR_PKT_VER);
+
+			cvs_full_ctl_cmd.hdr.pkt_size =
+				APR_PKT_SIZE(APR_HDR_SIZE,
+				       sizeof(cvs_full_ctl_cmd) - APR_HDR_SIZE);
+
+			cvs_full_ctl_cmd.hdr.src_port = v->session_id;
+			cvs_full_ctl_cmd.hdr.dest_port = 0;
+			cvs_full_ctl_cmd.hdr.token = 0;
+			cvs_full_ctl_cmd.hdr.opcode =
+			VSS_ISTREAM_CMD_CREATE_FULL_CONTROL_SESSION;
+			cvs_full_ctl_cmd.cvs_session.direction = 2;
+
+			cvs_full_ctl_cmd.cvs_session.enc_media_type =
+						common.mvs_info.media_type;
+			cvs_full_ctl_cmd.cvs_session.dec_media_type =
+						common.mvs_info.media_type;
+			cvs_full_ctl_cmd.cvs_session.network_id =
+						common.mvs_info.network_type;
+			strncpy(cvs_full_ctl_cmd.cvs_session.name,
+				"default voip", SESSION_NAME_LEN);
+
+			v->cvs_state = CMD_STATUS_FAIL;
+
+			ret = apr_send_pkt(apr_cvs,
+					   (uint32_t *) &cvs_full_ctl_cmd);
+
+			if (ret < 0) {
+				pr_err("%s: Err %d sending CREATE_FULL_CTRL\n",
+					   __func__, ret);
+				goto fail;
+			}
+			ret = wait_event_timeout(v->cvs_wait,
+					(v->cvs_state == CMD_STATUS_SUCCESS),
+					msecs_to_jiffies(TIMEOUT_MS));
+			if (!ret) {
+				pr_err("%s: wait_event timeout\n", __func__);
+				goto fail;
+			}
+
+			/* Get the created CVS handle. */
+			cvs_handle = voice_get_cvs_handle(v);
+
+			/* Attach MVM to CVS. */
+			pr_info("%s: Attach MVM to stream\n", __func__);
+
+			attach_stream_cmd.hdr.hdr_field =
+				APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					      APR_HDR_LEN(APR_HDR_SIZE),
+					      APR_PKT_VER);
+
+			attach_stream_cmd.hdr.pkt_size =
+				APR_PKT_SIZE(APR_HDR_SIZE,
+				      sizeof(attach_stream_cmd) - APR_HDR_SIZE);
+			attach_stream_cmd.hdr.src_port = v->session_id;
+			attach_stream_cmd.hdr.dest_port = mvm_handle;
+			attach_stream_cmd.hdr.token = 0;
+			attach_stream_cmd.hdr.opcode =
+						VSS_IMVM_CMD_ATTACH_STREAM;
+			attach_stream_cmd.attach_stream.handle = cvs_handle;
+
+			v->mvm_state = CMD_STATUS_FAIL;
+			ret = apr_send_pkt(apr_mvm,
+					   (uint32_t *) &attach_stream_cmd);
+			if (ret < 0) {
+				pr_err("%s: Error %d sending ATTACH_STREAM\n",
+				       __func__, ret);
+				goto fail;
+			}
+			ret = wait_event_timeout(v->mvm_wait,
+					 (v->mvm_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+			if (!ret) {
+				pr_err("%s: wait_event timeout\n", __func__);
+				goto fail;
+			}
+		}
+	}
+
+	return 0;
+
+fail:
+	apr_deregister(apr_mvm);
+	apr_mvm = NULL;
+	voice_set_apr_mvm(apr_mvm);
+
+	apr_deregister(apr_cvs);
+	apr_cvs = NULL;
+	voice_set_apr_cvs(apr_cvs);
+
+	apr_deregister(apr_cvp);
+	apr_cvp = NULL;
+	voice_set_apr_cvp(apr_cvp);
+
+	cvp_handle = 0;
+	voice_set_cvp_handle(v, cvp_handle);
+
+	cvs_handle = 0;
+	voice_set_cvs_handle(v, cvs_handle);
+
+	return -EINVAL;
+}
+
+static int voice_destroy_mvm_cvs_session(struct voice_data *v)
+{
+	int ret = 0;
+	struct mvm_detach_stream_cmd detach_stream;
+	struct apr_hdr mvm_destroy;
+	struct apr_hdr cvs_destroy;
+	void *apr_mvm = voice_get_apr_mvm();
+	void *apr_cvs = voice_get_apr_cvs();
+	u16 mvm_handle = voice_get_mvm_handle(v);
+	u16 cvs_handle = voice_get_cvs_handle(v);
+
+	/* MVM, CVS sessions are destroyed only for Full control sessions. */
+	if (is_voip_session(v->session_id)) {
+		pr_info("%s: MVM detach stream\n", __func__);
+
+		/* Detach voice stream. */
+		detach_stream.hdr.hdr_field =
+			APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				      APR_HDR_LEN(APR_HDR_SIZE),
+				      APR_PKT_VER);
+		detach_stream.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+					  sizeof(detach_stream) - APR_HDR_SIZE);
+		detach_stream.hdr.src_port = v->session_id;
+		detach_stream.hdr.dest_port = mvm_handle;
+		detach_stream.hdr.token = 0;
+		detach_stream.hdr.opcode = VSS_IMVM_CMD_DETACH_STREAM;
+		detach_stream.detach_stream.handle = cvs_handle;
+
+		v->mvm_state = CMD_STATUS_FAIL;
+
+		ret = apr_send_pkt(apr_mvm, (uint32_t *) &detach_stream);
+		if (ret < 0) {
+			pr_err("%s: Error %d sending DETACH_STREAM\n",
+			       __func__, ret);
+
+			goto fail;
+		}
+
+		ret = wait_event_timeout(v->mvm_wait,
+					 (v->mvm_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait event timeout\n", __func__);
+			goto fail;
+		}
+
+		/* Destroy CVS. */
+		pr_info("%s: CVS destroy session\n", __func__);
+
+		cvs_destroy.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						      APR_HDR_LEN(APR_HDR_SIZE),
+						      APR_PKT_VER);
+		cvs_destroy.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+					    sizeof(cvs_destroy) - APR_HDR_SIZE);
+		cvs_destroy.src_port = v->session_id;
+		cvs_destroy.dest_port = cvs_handle;
+		cvs_destroy.token = 0;
+		cvs_destroy.opcode = APRV2_IBASIC_CMD_DESTROY_SESSION;
+
+		v->cvs_state = CMD_STATUS_FAIL;
+
+		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_destroy);
+		if (ret < 0) {
+			pr_err("%s: Error %d sending CVS DESTROY\n",
+			       __func__, ret);
+
+			goto fail;
+		}
+
+		ret = wait_event_timeout(v->cvs_wait,
+					 (v->cvs_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait event timeout\n", __func__);
+
+			goto fail;
+		}
+		cvs_handle = 0;
+		voice_set_cvs_handle(v, cvs_handle);
+
+		/* Destroy MVM. */
+		pr_info("%s: MVM destroy session\n", __func__);
+
+		mvm_destroy.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						      APR_HDR_LEN(APR_HDR_SIZE),
+						      APR_PKT_VER);
+		mvm_destroy.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+					    sizeof(mvm_destroy) - APR_HDR_SIZE);
+		mvm_destroy.src_port = v->session_id;
+		mvm_destroy.dest_port = mvm_handle;
+		mvm_destroy.token = 0;
+		mvm_destroy.opcode = APRV2_IBASIC_CMD_DESTROY_SESSION;
+
+		v->mvm_state = CMD_STATUS_FAIL;
+
+		ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_destroy);
+		if (ret < 0) {
+			pr_err("%s: Error %d sending MVM DESTROY\n",
+			       __func__, ret);
+
+			goto fail;
+		}
+
+		ret = wait_event_timeout(v->mvm_wait,
+					 (v->mvm_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait event timeout\n", __func__);
+
+			goto fail;
+		}
+		mvm_handle = 0;
+		voice_set_mvm_handle(v, mvm_handle);
+	}
+
+fail:
+	return 0;
+}
+
+static int voice_send_tty_mode_to_modem(struct voice_data *v)
+{
+	struct msm_snddev_info *dev_tx_info;
+	struct msm_snddev_info *dev_rx_info;
+	int tty_mode = 0;
+	int ret = 0;
+	struct mvm_set_tty_mode_cmd mvm_tty_mode_cmd;
+	void *apr_mvm = voice_get_apr_mvm();
+	u16 mvm_handle = voice_get_mvm_handle(v);
+
+	dev_rx_info = audio_dev_ctrl_find_dev(v->dev_rx.dev_id);
+	if (IS_ERR(dev_rx_info)) {
+		pr_err("bad dev_id %d\n", v->dev_rx.dev_id);
+		goto done;
+	}
+
+	dev_tx_info = audio_dev_ctrl_find_dev(v->dev_tx.dev_id);
+	if (IS_ERR(dev_tx_info)) {
+		pr_err("bad dev_id %d\n", v->dev_tx.dev_id);
+		goto done;
+	}
+
+	if ((dev_rx_info->capability & SNDDEV_CAP_TTY) &&
+		(dev_tx_info->capability & SNDDEV_CAP_TTY))
+		tty_mode = 3; /* FULL */
+	else if (!(dev_tx_info->capability & SNDDEV_CAP_TTY) &&
+		(dev_rx_info->capability & SNDDEV_CAP_TTY))
+		tty_mode = 2; /* VCO */
+	else if ((dev_tx_info->capability & SNDDEV_CAP_TTY) &&
+		!(dev_rx_info->capability & SNDDEV_CAP_TTY))
+		tty_mode = 1; /* HCO */
+
+	if (tty_mode) {
+		/* send tty mode cmd to mvm */
+		mvm_tty_mode_cmd.hdr.hdr_field = APR_HDR_FIELD(
+			APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE),
+								APR_PKT_VER);
+		mvm_tty_mode_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+			sizeof(mvm_tty_mode_cmd) - APR_HDR_SIZE);
+		pr_debug("pkt size = %d\n", mvm_tty_mode_cmd.hdr.pkt_size);
+		mvm_tty_mode_cmd.hdr.src_port = v->session_id;
+		mvm_tty_mode_cmd.hdr.dest_port = mvm_handle;
+		mvm_tty_mode_cmd.hdr.token = 0;
+		mvm_tty_mode_cmd.hdr.opcode = VSS_ISTREAM_CMD_SET_TTY_MODE;
+		mvm_tty_mode_cmd.tty_mode.mode = tty_mode;
+		pr_info("tty mode =%d\n", mvm_tty_mode_cmd.tty_mode.mode);
+
+		v->mvm_state = CMD_STATUS_FAIL;
+		pr_info("%s: MVM set tty\n", __func__);
+		ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_tty_mode_cmd);
+		if (ret < 0) {
+			pr_err("Fail: sending VSS_ISTREAM_CMD_SET_TTY_MODE\n");
+			goto done;
+		}
+		ret = wait_event_timeout(v->mvm_wait,
+					 (v->mvm_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+			goto done;
+		}
+	}
+	return 0;
+done:
+	return -EINVAL;
+}
+
+static int voice_send_cvs_cal_to_modem(struct voice_data *v)
+{
+	struct apr_hdr cvs_cal_cmd_hdr;
+	uint32_t *cmd_buf;
+	struct acdb_cal_data cal_data;
+	struct acdb_atomic_cal_block *cal_blk;
+	int32_t cal_size_per_network;
+	uint32_t *cal_data_per_network;
+	int index = 0;
+	int ret = 0;
+	void *apr_cvs = voice_get_apr_cvs();
+	u16 cvs_handle = voice_get_cvs_handle(v);
+
+	/* fill the header */
+	cvs_cal_cmd_hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+		APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cvs_cal_cmd_hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+		sizeof(cvs_cal_cmd_hdr) - APR_HDR_SIZE);
+	cvs_cal_cmd_hdr.src_port = v->session_id;
+	cvs_cal_cmd_hdr.dest_port = cvs_handle;
+	cvs_cal_cmd_hdr.token = 0;
+	cvs_cal_cmd_hdr.opcode =
+		VSS_ISTREAM_CMD_CACHE_CALIBRATION_DATA;
+
+	pr_debug("voice_send_cvs_cal_to_modem\n");
+	/* get the cvs cal data */
+	get_vocstrm_cal(&cal_data);
+	if (cal_data.num_cal_blocks == 0) {
+		pr_err("%s: No calibration data to send!\n", __func__);
+		goto done;
+	}
+
+	/* send cvs cal to modem */
+	cmd_buf = kzalloc((sizeof(struct apr_hdr) + BUFFER_PAYLOAD_SIZE),
+								GFP_KERNEL);
+	if (!cmd_buf) {
+		pr_err("No memory is allocated.\n");
+		return -ENOMEM;
+	}
+	pr_debug("----- num_cal_blocks=%d\n", (s32)cal_data.num_cal_blocks);
+	cal_blk = cal_data.cal_blocks;
+	pr_debug("cal_blk =%x\n", (uint32_t)cal_data.cal_blocks);
+
+	for (; index < cal_data.num_cal_blocks; index++) {
+		cal_size_per_network = atomic_read(&cal_blk[index].cal_size);
+		pr_debug(" cal size =%d\n", cal_size_per_network);
+		if (cal_size_per_network >= BUFFER_PAYLOAD_SIZE)
+			pr_err("Cal size is too big\n");
+		cal_data_per_network =
+			(u32 *)atomic_read(&cal_blk[index].cal_kvaddr);
+		pr_debug(" cal data=%x\n", (uint32_t)cal_data_per_network);
+		cvs_cal_cmd_hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+			cal_size_per_network);
+		pr_debug("header size =%d,  pkt_size =%d\n",
+			APR_HDR_SIZE, cvs_cal_cmd_hdr.pkt_size);
+		memcpy(cmd_buf, &cvs_cal_cmd_hdr,  APR_HDR_SIZE);
+		memcpy(cmd_buf + (APR_HDR_SIZE / sizeof(uint32_t)),
+			cal_data_per_network, cal_size_per_network);
+		pr_debug("send cvs cal: index =%d\n", index);
+		v->cvs_state = CMD_STATUS_FAIL;
+		ret = apr_send_pkt(apr_cvs, cmd_buf);
+		if (ret < 0) {
+			pr_err("Fail: sending cvs cal, idx=%d\n", index);
+			continue;
+		}
+		ret = wait_event_timeout(v->cvs_wait,
+					 (v->cvs_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+			return -EINVAL;
+		}
+	}
+	kfree(cmd_buf);
+done:
+	return 0;
+}
+
+static int voice_send_cvp_cal_to_modem(struct voice_data *v)
+{
+	struct apr_hdr cvp_cal_cmd_hdr;
+	uint32_t *cmd_buf;
+	struct acdb_cal_data cal_data;
+	struct acdb_atomic_cal_block *cal_blk;
+	int32_t cal_size_per_network;
+	uint32_t *cal_data_per_network;
+	int index = 0;
+	int ret = 0;
+	void *apr_cvp = voice_get_apr_cvp();
+	u16 cvp_handle = voice_get_cvp_handle(v);
+
+
+	/* fill the header */
+	cvp_cal_cmd_hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+		APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cvp_cal_cmd_hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+		sizeof(cvp_cal_cmd_hdr) - APR_HDR_SIZE);
+	cvp_cal_cmd_hdr.src_port = v->session_id;
+	cvp_cal_cmd_hdr.dest_port = cvp_handle;
+	cvp_cal_cmd_hdr.token = 0;
+	cvp_cal_cmd_hdr.opcode =
+		VSS_IVOCPROC_CMD_CACHE_CALIBRATION_DATA;
+
+	/* get cal data */
+	get_vocproc_cal(&cal_data);
+	if (cal_data.num_cal_blocks == 0) {
+		pr_err("%s: No calibration data to send!\n", __func__);
+		goto done;
+	}
+
+	/* send cal to modem */
+	cmd_buf = kzalloc((sizeof(struct apr_hdr) + BUFFER_PAYLOAD_SIZE),
+								GFP_KERNEL);
+	if (!cmd_buf) {
+		pr_err("No memory is allocated.\n");
+		return -ENOMEM;
+	}
+	pr_debug("----- num_cal_blocks=%d\n", (s32)cal_data.num_cal_blocks);
+	cal_blk = cal_data.cal_blocks;
+	pr_debug(" cal_blk =%x\n", (uint32_t)cal_data.cal_blocks);
+
+	for (; index < cal_data.num_cal_blocks; index++) {
+		cal_size_per_network = atomic_read(&cal_blk[index].cal_size);
+		if (cal_size_per_network >= BUFFER_PAYLOAD_SIZE)
+			pr_err("Cal size is too big\n");
+		pr_debug(" cal size =%d\n", cal_size_per_network);
+		cal_data_per_network =
+			(u32 *)atomic_read(&cal_blk[index].cal_kvaddr);
+		pr_debug(" cal data=%x\n", (uint32_t)cal_data_per_network);
+
+		cvp_cal_cmd_hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+			cal_size_per_network);
+		memcpy(cmd_buf, &cvp_cal_cmd_hdr,  APR_HDR_SIZE);
+		memcpy(cmd_buf + (APR_HDR_SIZE / sizeof(*cmd_buf)),
+			cal_data_per_network, cal_size_per_network);
+		pr_debug("Send cvp cal\n");
+		v->cvp_state = CMD_STATUS_FAIL;
+		pr_info("%s: CVP calib\n", __func__);
+		ret = apr_send_pkt(apr_cvp, cmd_buf);
+		if (ret < 0) {
+			pr_err("Fail: sending cvp cal, idx=%d\n", index);
+			continue;
+		}
+		ret = wait_event_timeout(v->cvp_wait,
+					 (v->cvp_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+			return -EINVAL;
+		}
+	}
+	kfree(cmd_buf);
+done:
+	return 0;
+}
+
+static int voice_send_cvp_vol_tbl_to_modem(struct voice_data *v)
+{
+	struct apr_hdr cvp_vol_cal_cmd_hdr;
+	uint32_t *cmd_buf;
+	struct acdb_cal_data cal_data;
+	struct acdb_atomic_cal_block *cal_blk;
+	int32_t cal_size_per_network;
+	uint32_t *cal_data_per_network;
+	int index = 0;
+	int ret = 0;
+	void *apr_cvp = voice_get_apr_cvp();
+	u16 cvp_handle = voice_get_cvp_handle(v);
+
+
+	/* fill the header */
+	cvp_vol_cal_cmd_hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+		APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cvp_vol_cal_cmd_hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+		sizeof(cvp_vol_cal_cmd_hdr) - APR_HDR_SIZE);
+	cvp_vol_cal_cmd_hdr.src_port = v->session_id;
+	cvp_vol_cal_cmd_hdr.dest_port = cvp_handle;
+	cvp_vol_cal_cmd_hdr.token = 0;
+	cvp_vol_cal_cmd_hdr.opcode =
+		VSS_IVOCPROC_CMD_CACHE_VOLUME_CALIBRATION_TABLE;
+
+	/* get cal data */
+	get_vocvol_cal(&cal_data);
+	if (cal_data.num_cal_blocks == 0) {
+		pr_err("%s: No calibration data to send!\n", __func__);
+		goto done;
+	}
+
+	/* send cal to modem */
+	cmd_buf = kzalloc((sizeof(struct apr_hdr) + BUFFER_PAYLOAD_SIZE),
+								GFP_KERNEL);
+	if (!cmd_buf) {
+		pr_err("No memory is allocated.\n");
+		return -ENOMEM;
+	}
+	pr_debug("----- num_cal_blocks=%d\n", (s32)cal_data.num_cal_blocks);
+	cal_blk = cal_data.cal_blocks;
+	pr_debug("Cal_blk =%x\n", (uint32_t)cal_data.cal_blocks);
+
+	for (; index < cal_data.num_cal_blocks; index++) {
+		cal_size_per_network = atomic_read(&cal_blk[index].cal_size);
+		cal_data_per_network =
+			(u32 *)atomic_read(&cal_blk[index].cal_kvaddr);
+
+		pr_debug("Cal size =%d, index=%d\n", cal_size_per_network,
+			index);
+		pr_debug("Cal data=%x\n", (uint32_t)cal_data_per_network);
+		cvp_vol_cal_cmd_hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+			cal_size_per_network);
+		memcpy(cmd_buf, &cvp_vol_cal_cmd_hdr,  APR_HDR_SIZE);
+		memcpy(cmd_buf + (APR_HDR_SIZE / sizeof(uint32_t)),
+			cal_data_per_network, cal_size_per_network);
+		pr_debug("Send vol table\n");
+
+		v->cvp_state = CMD_STATUS_FAIL;
+		ret = apr_send_pkt(apr_cvp, cmd_buf);
+		if (ret < 0) {
+			pr_err("Fail: sending cvp vol cal, idx=%d\n", index);
+			continue;
+		}
+		ret = wait_event_timeout(v->cvp_wait,
+					 (v->cvp_state == CMD_STATUS_SUCCESS),
+			msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+			return -EINVAL;
+		}
+	}
+	kfree(cmd_buf);
+done:
+	return 0;
+}
+
+static int voice_set_dtx(struct voice_data *v)
+{
+	int ret = 0;
+	void *apr_cvs = voice_get_apr_cvs();
+	u16 cvs_handle = voice_get_cvs_handle(v);
+
+	/* Set DTX */
+	struct cvs_set_enc_dtx_mode_cmd cvs_set_dtx = {
+		.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					      APR_HDR_LEN(APR_HDR_SIZE),
+					      APR_PKT_VER),
+		.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+					sizeof(cvs_set_dtx) - APR_HDR_SIZE),
+		.hdr.src_port = v->session_id,
+		.hdr.dest_port = cvs_handle,
+		.hdr.token = 0,
+		.hdr.opcode = VSS_ISTREAM_CMD_SET_ENC_DTX_MODE,
+		.dtx_mode.enable = common.mvs_info.dtx_mode,
+	};
+
+	pr_debug("%s: Setting DTX %d\n", __func__, common.mvs_info.dtx_mode);
+
+	v->cvs_state = CMD_STATUS_FAIL;
+
+	ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_dtx);
+	if (ret < 0) {
+		pr_err("%s: Error %d sending SET_DTX\n", __func__, ret);
+
+		goto done;
+	}
+
+	ret = wait_event_timeout(v->cvs_wait,
+				 (v->cvs_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+
+		ret = -EINVAL;
+	}
+
+done:
+	return ret;
+}
+
+static int voice_config_cvs_vocoder(struct voice_data *v)
+{
+	int ret = 0;
+	void *apr_cvs = voice_get_apr_cvs();
+	u16 cvs_handle = voice_get_cvs_handle(v);
+
+	/* Set media type. */
+	struct cvs_set_media_type_cmd cvs_set_media_cmd;
+
+	pr_info("%s: Setting media type\n", __func__);
+
+	cvs_set_media_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+						APR_PKT_VER);
+	cvs_set_media_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				      sizeof(cvs_set_media_cmd) - APR_HDR_SIZE);
+	cvs_set_media_cmd.hdr.src_port = v->session_id;
+	cvs_set_media_cmd.hdr.dest_port = cvs_handle;
+	cvs_set_media_cmd.hdr.token = 0;
+	cvs_set_media_cmd.hdr.opcode = VSS_ISTREAM_CMD_SET_MEDIA_TYPE;
+	cvs_set_media_cmd.media_type.tx_media_id = common.mvs_info.media_type;
+	cvs_set_media_cmd.media_type.rx_media_id = common.mvs_info.media_type;
+
+	v->cvs_state = CMD_STATUS_FAIL;
+
+	ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_media_cmd);
+	if (ret < 0) {
+		pr_err("%s: Error %d sending SET_MEDIA_TYPE\n",
+		       __func__, ret);
+
+		goto done;
+	}
+
+	ret = wait_event_timeout(v->cvs_wait,
+				 (v->cvs_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+
+		ret = -EINVAL;
+		goto done;
+	}
+
+	/* Set encoder properties. */
+	switch (common.mvs_info.media_type) {
+	case VSS_MEDIA_ID_13K_MODEM:
+	case VSS_MEDIA_ID_4GV_NB_MODEM:
+	case VSS_MEDIA_ID_4GV_WB_MODEM:
+	case VSS_MEDIA_ID_EVRC_MODEM: {
+		struct cvs_set_cdma_enc_minmax_rate_cmd cvs_set_cdma_rate;
+
+		pr_info("%s: Setting CDMA min-max rate\n", __func__);
+
+		cvs_set_cdma_rate.hdr.hdr_field =
+				APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					      APR_HDR_LEN(APR_HDR_SIZE),
+					      APR_PKT_VER);
+		cvs_set_cdma_rate.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				      sizeof(cvs_set_cdma_rate) - APR_HDR_SIZE);
+		cvs_set_cdma_rate.hdr.src_port = v->session_id;
+		cvs_set_cdma_rate.hdr.dest_port = cvs_handle;
+		cvs_set_cdma_rate.hdr.token = 0;
+		cvs_set_cdma_rate.hdr.opcode =
+				VSS_ISTREAM_CMD_CDMA_SET_ENC_MINMAX_RATE;
+		cvs_set_cdma_rate.cdma_rate.min_rate =
+				common.mvs_info.q_min_max_rate.min_rate;
+		cvs_set_cdma_rate.cdma_rate.max_rate =
+				common.mvs_info.q_min_max_rate.max_rate;
+
+		v->cvs_state = CMD_STATUS_FAIL;
+
+		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_cdma_rate);
+		if (ret < 0) {
+			pr_err("%s: Error %d sending CDMA_SET_ENC_MINMAX_RATE\n",
+			       __func__, ret);
+
+			goto done;
+		}
+
+		ret = wait_event_timeout(v->cvs_wait,
+					 (v->cvs_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+
+			ret = -EINVAL;
+			goto done;
+		}
+
+		if ((common.mvs_info.media_type == VSS_MEDIA_ID_4GV_NB_MODEM) ||
+		(common.mvs_info.media_type == VSS_MEDIA_ID_4GV_WB_MODEM))
+			ret = voice_set_dtx(v);
+
+		break;
+	}
+
+	case VSS_MEDIA_ID_AMR_NB_MODEM: {
+		struct cvs_set_amr_enc_rate_cmd cvs_set_amr_rate;
+
+		pr_info("%s: Setting AMR rate\n", __func__);
+
+		cvs_set_amr_rate.hdr.hdr_field =
+				APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					      APR_HDR_LEN(APR_HDR_SIZE),
+					      APR_PKT_VER);
+		cvs_set_amr_rate.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				       sizeof(cvs_set_amr_rate) - APR_HDR_SIZE);
+		cvs_set_amr_rate.hdr.src_port = v->session_id;
+		cvs_set_amr_rate.hdr.dest_port = cvs_handle;
+		cvs_set_amr_rate.hdr.token = 0;
+		cvs_set_amr_rate.hdr.opcode =
+					VSS_ISTREAM_CMD_VOC_AMR_SET_ENC_RATE;
+		cvs_set_amr_rate.amr_rate.mode = common.mvs_info.rate;
+
+		v->cvs_state = CMD_STATUS_FAIL;
+
+		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_amr_rate);
+		if (ret < 0) {
+			pr_err("%s: Error %d sending SET_AMR_RATE\n",
+			       __func__, ret);
+
+			goto done;
+		}
+
+		ret = wait_event_timeout(v->cvs_wait,
+					 (v->cvs_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+
+			ret = -EINVAL;
+			goto done;
+		}
+
+		ret = voice_set_dtx(v);
+
+		break;
+	}
+
+	case VSS_MEDIA_ID_AMR_WB_MODEM: {
+		struct cvs_set_amrwb_enc_rate_cmd cvs_set_amrwb_rate;
+
+		pr_info("%s: Setting AMR WB rate\n", __func__);
+
+		cvs_set_amrwb_rate.hdr.hdr_field =
+				APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					      APR_HDR_LEN(APR_HDR_SIZE),
+					      APR_PKT_VER);
+		cvs_set_amrwb_rate.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				     sizeof(cvs_set_amrwb_rate) - APR_HDR_SIZE);
+		cvs_set_amrwb_rate.hdr.src_port = v->session_id;
+		cvs_set_amrwb_rate.hdr.dest_port = cvs_handle;
+		cvs_set_amrwb_rate.hdr.token = 0;
+		cvs_set_amrwb_rate.hdr.opcode =
+					VSS_ISTREAM_CMD_VOC_AMRWB_SET_ENC_RATE;
+		cvs_set_amrwb_rate.amrwb_rate.mode = common.mvs_info.rate;
+
+		v->cvs_state = CMD_STATUS_FAIL;
+
+		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_amrwb_rate);
+		if (ret < 0) {
+			pr_err("%s: Error %d sending SET_AMRWB_RATE\n",
+			       __func__, ret);
+
+			goto done;
+		}
+
+		ret = wait_event_timeout(v->cvs_wait,
+					 (v->cvs_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+
+			ret = -EINVAL;
+			goto done;
+		}
+
+		ret = voice_set_dtx(v);
+
+		break;
+	}
+
+	case VSS_MEDIA_ID_EFR_MODEM:
+	case VSS_MEDIA_ID_FR_MODEM:
+	case VSS_MEDIA_ID_HR_MODEM:
+	case VSS_MEDIA_ID_G729:
+	case VSS_MEDIA_ID_G711_ALAW:
+	case VSS_MEDIA_ID_G711_MULAW: {
+		ret = voice_set_dtx(v);
+
+		break;
+	}
+
+	default: {
+		/* Do nothing. */
+	}
+	}
+
+done:
+	return ret;
+}
+
+static int voice_send_start_voice_cmd(struct voice_data *v)
+{
+	struct apr_hdr mvm_start_voice_cmd;
+	int ret = 0;
+	void *apr_mvm = voice_get_apr_mvm();
+	u16 mvm_handle = voice_get_mvm_handle(v);
+
+	mvm_start_voice_cmd.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	mvm_start_voice_cmd.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(mvm_start_voice_cmd) - APR_HDR_SIZE);
+	pr_info("send mvm_start_voice_cmd pkt size = %d\n",
+				mvm_start_voice_cmd.pkt_size);
+	mvm_start_voice_cmd.src_port = v->session_id;
+	mvm_start_voice_cmd.dest_port = mvm_handle;
+	mvm_start_voice_cmd.token = 0;
+	mvm_start_voice_cmd.opcode = VSS_IMVM_CMD_START_VOICE;
+
+	v->mvm_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_start_voice_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending VSS_IMVM_CMD_START_VOICE\n");
+		goto fail;
+	}
+	ret = wait_event_timeout(v->mvm_wait,
+				 (v->mvm_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+
+	return 0;
+fail:
+	return -EINVAL;
+}
+
+static int voice_disable_vocproc(struct voice_data *v)
+{
+	struct apr_hdr cvp_disable_cmd;
+	int ret = 0;
+	void *apr_cvp = voice_get_apr_cvp();
+	u16 cvp_handle = voice_get_cvp_handle(v);
+
+	/* disable vocproc and wait for respose */
+	cvp_disable_cmd.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+			APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cvp_disable_cmd.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+			sizeof(cvp_disable_cmd) - APR_HDR_SIZE);
+	pr_debug("cvp_disable_cmd pkt size = %d, cvp_handle=%d\n",
+		cvp_disable_cmd.pkt_size, cvp_handle);
+	cvp_disable_cmd.src_port = v->session_id;
+	cvp_disable_cmd.dest_port = cvp_handle;
+	cvp_disable_cmd.token = 0;
+	cvp_disable_cmd.opcode = VSS_IVOCPROC_CMD_DISABLE;
+
+	v->cvp_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_disable_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending VSS_IVOCPROC_CMD_DISABLE\n");
+		goto fail;
+	}
+	ret = wait_event_timeout(v->cvp_wait,
+			(v->cvp_state == CMD_STATUS_SUCCESS),
+			msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+	rtac_remove_voice(v->cvs_handle);
+
+	return 0;
+fail:
+	return -EINVAL;
+}
+
+static int voice_set_device(struct voice_data *v)
+{
+	struct cvp_set_device_cmd  cvp_setdev_cmd;
+	struct msm_snddev_info *dev_tx_info;
+	int ret = 0;
+	void *apr_cvp = voice_get_apr_cvp();
+	u16 cvp_handle = voice_get_cvp_handle(v);
+
+
+	/* set device and wait for response */
+	cvp_setdev_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cvp_setdev_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(cvp_setdev_cmd) - APR_HDR_SIZE);
+	pr_debug(" send create cvp setdev, pkt size = %d\n",
+			cvp_setdev_cmd.hdr.pkt_size);
+	cvp_setdev_cmd.hdr.src_port = v->session_id;
+	cvp_setdev_cmd.hdr.dest_port = cvp_handle;
+	cvp_setdev_cmd.hdr.token = 0;
+	cvp_setdev_cmd.hdr.opcode = VSS_IVOCPROC_CMD_SET_DEVICE;
+
+	dev_tx_info = audio_dev_ctrl_find_dev(v->dev_tx.dev_id);
+	if (IS_ERR(dev_tx_info)) {
+		pr_err("bad dev_id %d\n", v->dev_tx.dev_id);
+		goto fail;
+	}
+
+	cvp_setdev_cmd.cvp_set_device.tx_topology_id =
+				get_voice_tx_topology();
+	if (cvp_setdev_cmd.cvp_set_device.tx_topology_id == 0) {
+		if (dev_tx_info->channel_mode > 1)
+			cvp_setdev_cmd.cvp_set_device.tx_topology_id =
+				VSS_IVOCPROC_TOPOLOGY_ID_TX_DM_FLUENCE;
+		else
+			cvp_setdev_cmd.cvp_set_device.tx_topology_id =
+				VSS_IVOCPROC_TOPOLOGY_ID_TX_SM_ECNS;
+	}
+
+	/* Use default topology if invalid value in ACDB */
+	cvp_setdev_cmd.cvp_set_device.rx_topology_id =
+				get_voice_rx_topology();
+	if (cvp_setdev_cmd.cvp_set_device.rx_topology_id == 0)
+		cvp_setdev_cmd.cvp_set_device.rx_topology_id =
+			VSS_IVOCPROC_TOPOLOGY_ID_RX_DEFAULT;
+	cvp_setdev_cmd.cvp_set_device.tx_port_id = v->dev_tx.dev_port_id;
+	cvp_setdev_cmd.cvp_set_device.rx_port_id = v->dev_rx.dev_port_id;
+	pr_info("topology=%d , tx_port_id=%d, rx_port_id=%d\n",
+			cvp_setdev_cmd.cvp_set_device.tx_topology_id,
+			cvp_setdev_cmd.cvp_set_device.tx_port_id,
+			cvp_setdev_cmd.cvp_set_device.rx_port_id);
+
+	v->cvp_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_setdev_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending VOCPROC_FULL_CONTROL_SESSION\n");
+	goto fail;
+	}
+	pr_debug("wait for cvp create session event\n");
+	ret = wait_event_timeout(v->cvp_wait,
+			(v->cvp_state == CMD_STATUS_SUCCESS),
+			msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+
+	/* send cvs cal */
+	voice_send_cvs_cal_to_modem(v);
+
+	/* send cvp cal */
+	voice_send_cvp_cal_to_modem(v);
+
+	/* send cvp vol table cal */
+	voice_send_cvp_vol_tbl_to_modem(v);
+
+	/* enable vocproc and wait for respose */
+	voice_send_enable_vocproc_cmd(v);
+
+	/* send tty mode if tty device is used */
+	voice_send_tty_mode_to_modem(v);
+
+	if (is_voip_session(v->session_id))
+		voice_send_netid_timing_cmd(v);
+
+	rtac_add_voice(v->cvs_handle, v->cvp_handle,
+		v->dev_rx.dev_port_id, v->dev_tx.dev_port_id,
+		v->session_id);
+
+	return 0;
+fail:
+	return -EINVAL;
+}
+
+static int voice_send_stop_voice_cmd(struct voice_data *v)
+{
+	struct apr_hdr mvm_stop_voice_cmd;
+	int ret = 0;
+	void *apr_mvm = voice_get_apr_mvm();
+	u16 mvm_handle = voice_get_mvm_handle(v);
+
+	mvm_stop_voice_cmd.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	mvm_stop_voice_cmd.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(mvm_stop_voice_cmd) - APR_HDR_SIZE);
+	pr_info("send mvm_stop_voice_cmd pkt size = %d\n",
+				mvm_stop_voice_cmd.pkt_size);
+	mvm_stop_voice_cmd.src_port = v->session_id;
+	mvm_stop_voice_cmd.dest_port = mvm_handle;
+	mvm_stop_voice_cmd.token = 0;
+	mvm_stop_voice_cmd.opcode = VSS_IMVM_CMD_STOP_VOICE;
+
+	v->mvm_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_stop_voice_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending VSS_IMVM_CMD_STOP_VOICE\n");
+		goto fail;
+	}
+	ret = wait_event_timeout(v->mvm_wait,
+				 (v->mvm_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+
+	return 0;
+fail:
+	return -EINVAL;
+}
+
+static int voice_setup_modem_voice(struct voice_data *v)
+{
+	struct cvp_create_full_ctl_session_cmd cvp_session_cmd;
+	int ret = 0;
+	struct msm_snddev_info *dev_tx_info;
+	void *apr_cvp = voice_get_apr_cvp();
+
+	/* create cvp session and wait for response */
+	cvp_session_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cvp_session_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(cvp_session_cmd) - APR_HDR_SIZE);
+	pr_info(" send create cvp session, pkt size = %d\n",
+				cvp_session_cmd.hdr.pkt_size);
+	cvp_session_cmd.hdr.src_port = v->session_id;
+	cvp_session_cmd.hdr.dest_port = 0;
+	cvp_session_cmd.hdr.token = 0;
+	cvp_session_cmd.hdr.opcode =
+		VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION;
+
+	dev_tx_info = audio_dev_ctrl_find_dev(v->dev_tx.dev_id);
+	if (IS_ERR(dev_tx_info)) {
+		pr_err("bad dev_id %d\n", v->dev_tx.dev_id);
+		goto fail;
+	}
+
+	/* Use default topology if invalid value in ACDB */
+	cvp_session_cmd.cvp_session.tx_topology_id =
+				get_voice_tx_topology();
+	if (cvp_session_cmd.cvp_session.tx_topology_id == 0) {
+		if (dev_tx_info->channel_mode > 1)
+			cvp_session_cmd.cvp_session.tx_topology_id =
+				VSS_IVOCPROC_TOPOLOGY_ID_TX_DM_FLUENCE;
+		else
+			cvp_session_cmd.cvp_session.tx_topology_id =
+				VSS_IVOCPROC_TOPOLOGY_ID_TX_SM_ECNS;
+	}
+
+	cvp_session_cmd.cvp_session.rx_topology_id =
+				get_voice_rx_topology();
+	if (cvp_session_cmd.cvp_session.rx_topology_id == 0)
+		cvp_session_cmd.cvp_session.rx_topology_id =
+			VSS_IVOCPROC_TOPOLOGY_ID_RX_DEFAULT;
+
+	cvp_session_cmd.cvp_session.direction = 2; /*tx and rx*/
+	cvp_session_cmd.cvp_session.network_id = VSS_NETWORK_ID_DEFAULT;
+	cvp_session_cmd.cvp_session.tx_port_id = v->dev_tx.dev_port_id;
+	cvp_session_cmd.cvp_session.rx_port_id = v->dev_rx.dev_port_id;
+	pr_info("topology=%d net_id=%d, dir=%d tx_port_id=%d, rx_port_id=%d\n",
+			cvp_session_cmd.cvp_session.tx_topology_id,
+			cvp_session_cmd.cvp_session.network_id,
+			cvp_session_cmd.cvp_session.direction,
+			cvp_session_cmd.cvp_session.tx_port_id,
+			cvp_session_cmd.cvp_session.rx_port_id);
+
+	v->cvp_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_session_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending VOCPROC_FULL_CONTROL_SESSION\n");
+		goto fail;
+	}
+	pr_debug("wait for cvp create session event\n");
+	ret = wait_event_timeout(v->cvp_wait,
+				 (v->cvp_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+
+	/* send cvs cal */
+	voice_send_cvs_cal_to_modem(v);
+
+	/* send cvp cal */
+	voice_send_cvp_cal_to_modem(v);
+
+	/* send cvp vol table cal */
+	voice_send_cvp_vol_tbl_to_modem(v);
+
+	return 0;
+
+fail:
+	return -EINVAL;
+}
+
+static int voice_send_enable_vocproc_cmd(struct voice_data *v)
+{
+	int ret = 0;
+	struct apr_hdr cvp_enable_cmd;
+
+	u16 cvp_handle = voice_get_cvp_handle(v);
+	void *apr_cvp = voice_get_apr_cvp();
+
+	/* enable vocproc and wait for respose */
+	cvp_enable_cmd.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cvp_enable_cmd.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(cvp_enable_cmd) - APR_HDR_SIZE);
+	pr_debug("cvp_enable_cmd pkt size = %d, cvp_handle=%d\n",
+			cvp_enable_cmd.pkt_size, cvp_handle);
+	cvp_enable_cmd.src_port = v->session_id;
+	cvp_enable_cmd.dest_port = cvp_handle;
+	cvp_enable_cmd.token = 0;
+	cvp_enable_cmd.opcode = VSS_IVOCPROC_CMD_ENABLE;
+
+	v->cvp_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_enable_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending VSS_IVOCPROC_CMD_ENABLE\n");
+		goto fail;
+	}
+	ret = wait_event_timeout(v->cvp_wait,
+			(v->cvp_state == CMD_STATUS_SUCCESS),
+			msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+
+	return 0;
+fail:
+	return -EINVAL;
+}
+
+static int voice_send_netid_timing_cmd(struct voice_data *v)
+{
+	int ret = 0;
+	void *apr_mvm = voice_get_apr_mvm();
+	struct mvm_set_network_cmd mvm_set_network;
+	struct mvm_set_voice_timing_cmd mvm_set_voice_timing;
+	u16 mvm_handle = voice_get_mvm_handle(v);
+
+	ret = voice_config_cvs_vocoder(v);
+	if (ret < 0) {
+		pr_err("%s: Error %d configuring CVS voc",
+					__func__, ret);
+		goto fail;
+	}
+	/* Set network ID. */
+	pr_debug("%s: Setting network ID\n", __func__);
+
+	mvm_set_network.hdr.hdr_field =
+			APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+			APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	mvm_set_network.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+			sizeof(mvm_set_network) - APR_HDR_SIZE);
+	mvm_set_network.hdr.src_port = v->session_id;
+	mvm_set_network.hdr.dest_port = mvm_handle;
+	mvm_set_network.hdr.token = 0;
+	mvm_set_network.hdr.opcode = VSS_ICOMMON_CMD_SET_NETWORK;
+	mvm_set_network.network.network_id = common.mvs_info.network_type;
+
+	v->mvm_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_set_network);
+	if (ret < 0) {
+		pr_err("%s: Error %d sending SET_NETWORK\n", __func__, ret);
+		goto fail;
+	}
+
+	ret = wait_event_timeout(v->mvm_wait,
+			(v->mvm_state == CMD_STATUS_SUCCESS),
+			 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+
+	/* Set voice timing. */
+	 pr_debug("%s: Setting voice timing\n", __func__);
+
+	mvm_set_voice_timing.hdr.hdr_field =
+			APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+			APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	mvm_set_voice_timing.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+			sizeof(mvm_set_voice_timing) - APR_HDR_SIZE);
+	mvm_set_voice_timing.hdr.src_port = v->session_id;
+	mvm_set_voice_timing.hdr.dest_port = mvm_handle;
+	mvm_set_voice_timing.hdr.token = 0;
+	mvm_set_voice_timing.hdr.opcode =
+			VSS_ICOMMON_CMD_SET_VOICE_TIMING;
+	mvm_set_voice_timing.timing.mode = 0;
+	mvm_set_voice_timing.timing.enc_offset = 8000;
+	mvm_set_voice_timing.timing.dec_req_offset = 3300;
+	mvm_set_voice_timing.timing.dec_offset = 8300;
+
+	v->mvm_state = CMD_STATUS_FAIL;
+
+	ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_set_voice_timing);
+	if (ret < 0) {
+		pr_err("%s: Error %d sending SET_TIMING\n", __func__, ret);
+		goto fail;
+	}
+
+	ret = wait_event_timeout(v->mvm_wait,
+			(v->mvm_state == CMD_STATUS_SUCCESS),
+				msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+
+	return 0;
+fail:
+	return -EINVAL;
+}
+
+static int voice_attach_vocproc(struct voice_data *v)
+{
+	int ret = 0;
+	struct mvm_attach_vocproc_cmd mvm_a_vocproc_cmd;
+	void *apr_mvm = voice_get_apr_mvm();
+	u16 mvm_handle = voice_get_mvm_handle(v);
+	u16 cvp_handle = voice_get_cvp_handle(v);
+
+	/* send enable vocproc */
+	voice_send_enable_vocproc_cmd(v);
+
+	/* attach vocproc and wait for response */
+	mvm_a_vocproc_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	mvm_a_vocproc_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(mvm_a_vocproc_cmd) - APR_HDR_SIZE);
+	pr_info("send mvm_a_vocproc_cmd pkt size = %d\n",
+				mvm_a_vocproc_cmd.hdr.pkt_size);
+	mvm_a_vocproc_cmd.hdr.src_port = v->session_id;
+	mvm_a_vocproc_cmd.hdr.dest_port = mvm_handle;
+	mvm_a_vocproc_cmd.hdr.token = 0;
+	mvm_a_vocproc_cmd.hdr.opcode = VSS_ISTREAM_CMD_ATTACH_VOCPROC;
+	mvm_a_vocproc_cmd.mvm_attach_cvp_handle.handle = cvp_handle;
+
+	v->mvm_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_a_vocproc_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending VSS_ISTREAM_CMD_ATTACH_VOCPROC\n");
+		goto fail;
+	}
+	ret = wait_event_timeout(v->mvm_wait,
+				 (v->mvm_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+
+	/* send tty mode if tty device is used */
+	voice_send_tty_mode_to_modem(v);
+
+	if (is_voip_session(v->session_id))
+		voice_send_netid_timing_cmd(v);
+
+	rtac_add_voice(v->cvs_handle, v->cvp_handle,
+		v->dev_rx.dev_port_id, v->dev_tx.dev_port_id,
+		v->session_id);
+
+	return 0;
+fail:
+	return -EINVAL;
+}
+
+static int voice_destroy_modem_voice(struct voice_data *v)
+{
+	struct mvm_detach_vocproc_cmd mvm_d_vocproc_cmd;
+	struct apr_hdr cvp_destroy_session_cmd;
+	int ret = 0;
+	void *apr_mvm = voice_get_apr_mvm();
+	void *apr_cvp = voice_get_apr_cvp();
+	u16 mvm_handle = voice_get_mvm_handle(v);
+	u16 cvp_handle = voice_get_cvp_handle(v);
+
+	/* detach VOCPROC and wait for response from mvm */
+	mvm_d_vocproc_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	mvm_d_vocproc_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(mvm_d_vocproc_cmd) - APR_HDR_SIZE);
+	pr_info("mvm_d_vocproc_cmd  pkt size = %d\n",
+				mvm_d_vocproc_cmd.hdr.pkt_size);
+	mvm_d_vocproc_cmd.hdr.src_port = v->session_id;
+	mvm_d_vocproc_cmd.hdr.dest_port = mvm_handle;
+	mvm_d_vocproc_cmd.hdr.token = 0;
+	mvm_d_vocproc_cmd.hdr.opcode = VSS_ISTREAM_CMD_DETACH_VOCPROC;
+	mvm_d_vocproc_cmd.mvm_detach_cvp_handle.handle = cvp_handle;
+
+	v->mvm_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_d_vocproc_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending VSS_ISTREAM_CMD_DETACH_VOCPROC\n");
+		goto fail;
+	}
+	ret = wait_event_timeout(v->mvm_wait,
+				 (v->mvm_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+
+	/* destrop cvp session */
+	cvp_destroy_session_cmd.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cvp_destroy_session_cmd.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(cvp_destroy_session_cmd) - APR_HDR_SIZE);
+	pr_info("cvp_destroy_session_cmd pkt size = %d\n",
+				cvp_destroy_session_cmd.pkt_size);
+	cvp_destroy_session_cmd.src_port = v->session_id;
+	cvp_destroy_session_cmd.dest_port = cvp_handle;
+	cvp_destroy_session_cmd.token = 0;
+	cvp_destroy_session_cmd.opcode = APRV2_IBASIC_CMD_DESTROY_SESSION;
+
+	v->cvp_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_destroy_session_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending APRV2_IBASIC_CMD_DESTROY_SESSION\n");
+		goto fail;
+	}
+	ret = wait_event_timeout(v->cvp_wait,
+				 (v->cvp_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+	rtac_remove_voice(v->cvs_handle);
+	cvp_handle = 0;
+	voice_set_cvp_handle(v, cvp_handle);
+
+	return 0;
+
+fail:
+	return -EINVAL;
+}
+
+static int voice_send_mute_cmd_to_modem(struct voice_data *v)
+{
+	struct cvs_set_mute_cmd cvs_mute_cmd;
+	int ret = 0;
+	void *apr_cvs = voice_get_apr_cvs();
+	u16 cvs_handle = voice_get_cvs_handle(v);
+
+	/* send mute/unmute to cvs */
+	cvs_mute_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cvs_mute_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(cvs_mute_cmd) - APR_HDR_SIZE);
+	cvs_mute_cmd.hdr.src_port = v->session_id;
+	cvs_mute_cmd.hdr.dest_port = cvs_handle;
+	cvs_mute_cmd.hdr.token = 0;
+	cvs_mute_cmd.hdr.opcode = VSS_ISTREAM_CMD_SET_MUTE;
+	cvs_mute_cmd.cvs_set_mute.direction = 0; /*tx*/
+	cvs_mute_cmd.cvs_set_mute.mute_flag = v->dev_tx.mute;
+
+	pr_info(" mute value =%d\n", cvs_mute_cmd.cvs_set_mute.mute_flag);
+	v->cvs_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_mute_cmd);
+	if (ret < 0) {
+		pr_err("Fail: send STREAM SET MUTE\n");
+		goto fail;
+	}
+	ret = wait_event_timeout(v->cvs_wait,
+				 (v->cvs_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret)
+		pr_err("%s: wait_event timeout\n", __func__);
+
+fail:
+	return 0;
+}
+
+static int voice_send_vol_index_to_modem(struct voice_data *v)
+{
+	struct cvp_set_rx_volume_index_cmd cvp_vol_cmd;
+	int ret = 0;
+	void *apr_cvp = voice_get_apr_cvp();
+	u16 cvp_handle = voice_get_cvp_handle(v);
+
+	/* send volume index to cvp */
+	cvp_vol_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+		APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cvp_vol_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+		sizeof(cvp_vol_cmd) - APR_HDR_SIZE);
+	cvp_vol_cmd.hdr.src_port = v->session_id;
+	cvp_vol_cmd.hdr.dest_port = cvp_handle;
+	cvp_vol_cmd.hdr.token = 0;
+	cvp_vol_cmd.hdr.opcode =
+		VSS_IVOCPROC_CMD_SET_RX_VOLUME_INDEX;
+	cvp_vol_cmd.cvp_set_vol_idx.vol_index = v->dev_rx.volume;
+	v->cvp_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_vol_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending RX VOL INDEX\n");
+		return -EINVAL;
+	}
+	ret = wait_event_timeout(v->cvp_wait,
+				 (v->cvp_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int voice_cvs_start_record(struct voice_data *v, uint32_t rec_mode)
+{
+	int ret = 0;
+	void *apr_cvs = voice_get_apr_cvs();
+	u16 cvs_handle = voice_get_cvs_handle(v);
+	struct cvs_start_record_cmd cvs_start_record;
+
+	pr_debug("%s: Start record %d\n", __func__, rec_mode);
+
+	cvs_start_record.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				  APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cvs_start_record.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				  sizeof(cvs_start_record) - APR_HDR_SIZE);
+	cvs_start_record.hdr.src_port = v->session_id;
+	cvs_start_record.hdr.dest_port = cvs_handle;
+	cvs_start_record.hdr.token = 0;
+	cvs_start_record.hdr.opcode = VSS_ISTREAM_CMD_START_RECORD;
+
+	if (rec_mode == VOC_REC_UPLINK) {
+		cvs_start_record.rec_mode.rx_tap_point = VSS_TAP_POINT_NONE;
+		cvs_start_record.rec_mode.tx_tap_point =
+						VSS_TAP_POINT_STREAM_END;
+	} else if (rec_mode == VOC_REC_DOWNLINK) {
+		cvs_start_record.rec_mode.rx_tap_point =
+						VSS_TAP_POINT_STREAM_END;
+		cvs_start_record.rec_mode.tx_tap_point = VSS_TAP_POINT_NONE;
+	} else if (rec_mode == VOC_REC_BOTH) {
+		cvs_start_record.rec_mode.rx_tap_point =
+						VSS_TAP_POINT_STREAM_END;
+		cvs_start_record.rec_mode.tx_tap_point =
+						VSS_TAP_POINT_STREAM_END;
+	} else {
+		pr_err("%s: Invalid in-call rec_mode %d\n", __func__, rec_mode);
+
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	v->cvs_state = CMD_STATUS_FAIL;
+
+	ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_start_record);
+	if (ret < 0) {
+		pr_err("%s: Error %d sending START_RECORD\n", __func__, ret);
+
+		goto fail;
+	}
+
+	ret = wait_event_timeout(v->cvs_wait,
+				 (v->cvs_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+
+		goto fail;
+	}
+
+	return 0;
+
+fail:
+	return ret;
+}
+
+static int voice_cvs_stop_record(struct voice_data *v)
+{
+	int ret = 0;
+	void *apr_cvs = voice_get_apr_cvs();
+	u16 cvs_handle = voice_get_cvs_handle(v);
+	struct apr_hdr cvs_stop_record;
+
+	pr_debug("%s: Stop record\n", __func__);
+
+	cvs_stop_record.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				  APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cvs_stop_record.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				  sizeof(cvs_stop_record) - APR_HDR_SIZE);
+	cvs_stop_record.src_port = v->session_id;
+	cvs_stop_record.dest_port = cvs_handle;
+	cvs_stop_record.token = 0;
+	cvs_stop_record.opcode = VSS_ISTREAM_CMD_STOP_RECORD;
+
+	v->cvs_state = CMD_STATUS_FAIL;
+
+	ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_stop_record);
+	if (ret < 0) {
+		pr_err("%s: Error %d sending STOP_RECORD\n", __func__, ret);
+
+		goto fail;
+	}
+
+	ret = wait_event_timeout(v->cvs_wait,
+				 (v->cvs_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+
+		goto fail;
+	}
+
+	return 0;
+
+fail:
+	return ret;
+}
+
+int voice_start_record(uint32_t rec_mode, uint32_t set)
+{
+	int ret = 0, i;
+	u16 cvs_handle;
+
+	pr_debug("%s: rec_mode %d, set %d\n", __func__, rec_mode, set);
+
+	for (i = 0; i < MAX_VOC_SESSIONS; i++) {
+		struct voice_data *v = &common.voice[i];
+
+		mutex_lock(&v->lock);
+
+		cvs_handle = voice_get_cvs_handle(v);
+
+		if (cvs_handle != 0) {
+			if (set)
+				ret = voice_cvs_start_record(v, rec_mode);
+			else
+				ret = voice_cvs_stop_record(v);
+		} else {
+			/* Cache the value for later. */
+			v->rec_info.pending = set;
+			v->rec_info.rec_mode = rec_mode;
+		}
+
+		mutex_unlock(&v->lock);
+	}
+
+	return ret;
+}
+
+static int voice_cvs_start_playback(struct voice_data *v)
+{
+	int ret = 0;
+	void *apr_cvs = voice_get_apr_cvs();
+	u16 cvs_handle = voice_get_cvs_handle(v);
+	struct apr_hdr cvs_start_playback;
+
+	pr_debug("%s: Start playback\n", __func__);
+
+	cvs_start_playback.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cvs_start_playback.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(cvs_start_playback) - APR_HDR_SIZE);
+	cvs_start_playback.src_port = v->session_id;
+	cvs_start_playback.dest_port = cvs_handle;
+	cvs_start_playback.token = 0;
+	cvs_start_playback.opcode = VSS_ISTREAM_CMD_START_PLAYBACK;
+
+	v->cvs_state = CMD_STATUS_FAIL;
+
+	ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_start_playback);
+	if (ret < 0) {
+		pr_err("%s: Error %d sending START_PLAYBACK\n",
+		       __func__, ret);
+
+		goto fail;
+	}
+
+	ret = wait_event_timeout(v->cvs_wait,
+				 (v->cvs_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+
+		goto fail;
+	}
+
+	v->music_info.playing = 1;
+
+	return 0;
+
+fail:
+	return ret;
+}
+
+static int voice_cvs_stop_playback(struct voice_data *v)
+{
+	int ret = 0;
+	void *apr_cvs = voice_get_apr_cvs();
+	u16 cvs_handle = voice_get_cvs_handle(v);
+	struct apr_hdr cvs_stop_playback;
+
+	pr_debug("%s: Stop playback\n", __func__);
+
+	if (v->music_info.playing) {
+		cvs_stop_playback.hdr_field =
+				APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+		cvs_stop_playback.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(cvs_stop_playback) - APR_HDR_SIZE);
+		cvs_stop_playback.src_port = v->session_id;
+		cvs_stop_playback.dest_port = cvs_handle;
+		cvs_stop_playback.token = 0;
+
+		cvs_stop_playback.opcode = VSS_ISTREAM_CMD_STOP_PLAYBACK;
+
+		v->cvs_state = CMD_STATUS_FAIL;
+
+		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_stop_playback);
+		if (ret < 0) {
+			pr_err("%s: Error %d sending STOP_PLAYBACK\n",
+			       __func__, ret);
+
+			goto fail;
+		}
+
+		ret = wait_event_timeout(v->cvs_wait,
+					 (v->cvs_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+
+			goto fail;
+		}
+
+		v->music_info.playing = 0;
+	} else {
+		pr_err("%s: Stop playback already sent\n", __func__);
+	}
+
+	return 0;
+
+fail:
+	return ret;
+}
+
+int voice_start_playback(uint32_t set)
+{
+	int ret = 0, i;
+	u16 cvs_handle;
+
+	pr_debug("%s: Start playback %d\n", __func__, set);
+
+	for (i = 0; i < MAX_VOC_SESSIONS; i++) {
+		struct voice_data *v = &common.voice[i];
+
+		mutex_lock(&v->lock);
+
+		cvs_handle = voice_get_cvs_handle(v);
+
+		if (cvs_handle != 0) {
+			if (set)
+				ret = voice_cvs_start_playback(v);
+			else
+				ret = voice_cvs_stop_playback(v);
+		} else {
+			/* Cache the value for later. */
+			pr_debug("%s: Caching ICP value", __func__);
+
+			v->music_info.pending = set;
+		}
+
+		mutex_unlock(&v->lock);
+	}
+
+	return ret;
+}
+
+static void voice_auddev_cb_function(u32 evt_id,
+			union auddev_evt_data *evt_payload,
+			void *private_data)
+{
+		struct common_data *c = private_data;
+		struct voice_data *v = NULL;
+
+	struct sidetone_cal sidetone_cal_data;
+	int rc = 0, i = 0;
+	int rc1 = 0;
+
+	pr_info("auddev_cb_function, evt_id=%d,\n", evt_id);
+
+	if (evt_payload == NULL) {
+		pr_err("%s: evt_payload is NULL pointer\n", __func__);
+		return;
+	}
+
+	switch (evt_id) {
+	case AUDDEV_EVT_START_VOICE:
+		v = voice_get_session(evt_payload->voice_session_id);
+		if (v == NULL) {
+			pr_err("%s: v is NULL\n", __func__);
+			return;
+		}
+
+		mutex_lock(&v->lock);
+
+		if ((v->voc_state == VOC_INIT) ||
+				(v->voc_state == VOC_RELEASE)) {
+			v->v_call_status = VOICE_CALL_START;
+			if ((v->dev_rx.enabled == VOICE_DEV_ENABLED)
+				&& (v->dev_tx.enabled == VOICE_DEV_ENABLED)) {
+				rc = voice_apr_register();
+				if (rc < 0) {
+					pr_err("%s: voice apr registration"
+						"failed\n", __func__);
+					mutex_unlock(&v->lock);
+					return;
+				}
+				rc1 = voice_create_mvm_cvs_session(v);
+				if (rc1 < 0) {
+					pr_err("%s: create mvm-cvs failed\n",
+								__func__);
+					msleep(100);
+					rc = voice_apr_register();
+					if (rc < 0) {
+						mutex_unlock(&v->lock);
+						pr_err("%s: voice apr regn"
+							"failed\n", __func__);
+						return;
+					}
+					rc1 = voice_create_mvm_cvs_session(v);
+					if (rc1 < 0) {
+						mutex_unlock(&v->lock);
+						pr_err("%s:Retry mvmcvs "
+								"failed\n",
+								__func__);
+						return;
+					}
+				}
+				voice_setup_modem_voice(v);
+				voice_attach_vocproc(v);
+				voice_send_start_voice_cmd(v);
+				get_sidetone_cal(&sidetone_cal_data);
+				msm_snddev_enable_sidetone(
+					v->dev_rx.dev_id,
+					sidetone_cal_data.enable,
+					sidetone_cal_data.gain);
+				v->voc_state = VOC_RUN;
+
+				/* Start in-call recording if command was
+				 * pending. */
+				if (v->rec_info.pending) {
+					voice_cvs_start_record(v,
+						v->rec_info.rec_mode);
+
+					v->rec_info.pending = 0;
+				}
+
+				/* Start in-call music delivery if command was
+				 * pending. */
+				if (v->music_info.pending) {
+					voice_cvs_start_playback(v);
+
+					v->music_info.pending = 0;
+				}
+			}
+		}
+
+		mutex_unlock(&v->lock);
+		break;
+	case AUDDEV_EVT_DEV_CHG_VOICE:
+		/* Device change is applicable to all sessions. */
+		for (i = 0; i < MAX_VOC_SESSIONS; i++) {
+			v = &c->voice[i];
+
+			if (v->dev_rx.enabled == VOICE_DEV_ENABLED)
+				msm_snddev_enable_sidetone(v->dev_rx.dev_id,
+							   0, 0);
+
+			v->dev_rx.enabled = VOICE_DEV_DISABLED;
+			v->dev_tx.enabled = VOICE_DEV_DISABLED;
+
+			mutex_lock(&v->lock);
+
+			if (v->voc_state == VOC_RUN) {
+				/* send cmd to modem to do voice device
+				 * change */
+				voice_disable_vocproc(v);
+				v->voc_state = VOC_CHANGE;
+			}
+
+			mutex_unlock(&v->lock);
+		}
+		break;
+	case AUDDEV_EVT_DEV_RDY:
+		/* Device change is applicable to all sessions. */
+		for (i = 0; i < MAX_VOC_SESSIONS; i++) {
+			v = &c->voice[i];
+
+			mutex_lock(&v->lock);
+
+			if (v->voc_state == VOC_CHANGE) {
+				/* get port Ids */
+				if (evt_payload->voc_devinfo.dev_type ==
+								      DIR_RX) {
+					v->dev_rx.dev_port_id =
+					   evt_payload->voc_devinfo.dev_port_id;
+					v->dev_rx.sample =
+					    evt_payload->voc_devinfo.dev_sample;
+					v->dev_rx.dev_id =
+						evt_payload->voc_devinfo.dev_id;
+					v->dev_rx.enabled = VOICE_DEV_ENABLED;
+				} else {
+					v->dev_tx.dev_port_id =
+					   evt_payload->voc_devinfo.dev_port_id;
+					v->dev_tx.sample =
+					    evt_payload->voc_devinfo.dev_sample;
+					v->dev_tx.enabled = VOICE_DEV_ENABLED;
+					v->dev_tx.dev_id =
+						evt_payload->voc_devinfo.dev_id;
+				}
+				if ((v->dev_rx.enabled == VOICE_DEV_ENABLED) &&
+				    (v->dev_tx.enabled == VOICE_DEV_ENABLED)) {
+					voice_set_device(v);
+					get_sidetone_cal(&sidetone_cal_data);
+					msm_snddev_enable_sidetone(
+						v->dev_rx.dev_id,
+						sidetone_cal_data.enable,
+						sidetone_cal_data.gain);
+					v->voc_state = VOC_RUN;
+				}
+			} else if ((v->voc_state == VOC_INIT) ||
+				   (v->voc_state == VOC_RELEASE)) {
+				/* get AFE ports */
+				if (evt_payload->voc_devinfo.dev_type ==
+								       DIR_RX) {
+					/* get rx port id */
+					v->dev_rx.dev_port_id =
+					   evt_payload->voc_devinfo.dev_port_id;
+					v->dev_rx.sample =
+					    evt_payload->voc_devinfo.dev_sample;
+					v->dev_rx.dev_id =
+						evt_payload->voc_devinfo.dev_id;
+					v->dev_rx.enabled = VOICE_DEV_ENABLED;
+				} else {
+					/* get tx port id */
+					v->dev_tx.dev_port_id =
+					   evt_payload->voc_devinfo.dev_port_id;
+					v->dev_tx.sample =
+					    evt_payload->voc_devinfo.dev_sample;
+					v->dev_tx.dev_id =
+						evt_payload->voc_devinfo.dev_id;
+					v->dev_tx.enabled = VOICE_DEV_ENABLED;
+				}
+				if ((v->dev_rx.enabled == VOICE_DEV_ENABLED) &&
+				    (v->dev_tx.enabled == VOICE_DEV_ENABLED) &&
+				    (v->v_call_status == VOICE_CALL_START)) {
+					rc = voice_apr_register();
+					if (rc < 0) {
+						pr_err("%s: voice apr"
+						       "registration failed\n",
+						       __func__);
+						mutex_unlock(&v->lock);
+						return;
+					}
+					voice_create_mvm_cvs_session(v);
+					voice_setup_modem_voice(v);
+					voice_attach_vocproc(v);
+					voice_send_start_voice_cmd(v);
+					get_sidetone_cal(&sidetone_cal_data);
+					msm_snddev_enable_sidetone(
+						v->dev_rx.dev_id,
+						sidetone_cal_data.enable,
+						sidetone_cal_data.gain);
+					v->voc_state = VOC_RUN;
+
+					/* Start in-call recording if command
+					 * was pending. */
+					if (v->rec_info.pending) {
+						voice_cvs_start_record(v,
+							v->rec_info.rec_mode);
+
+						v->rec_info.pending = 0;
+					}
+
+					/* Start in-call music delivery if
+					 * command was pending. */
+					if (v->music_info.pending) {
+						voice_cvs_start_playback(v);
+
+						v->music_info.pending = 0;
+					}
+				}
+			}
+
+			mutex_unlock(&v->lock);
+		}
+	break;
+	case AUDDEV_EVT_DEVICE_VOL_MUTE_CHG:
+		v = voice_get_session(
+				     evt_payload->voc_vm_info.voice_session_id);
+		if (v == NULL) {
+			pr_err("%s: v is NULL\n", __func__);
+			return;
+		}
+
+		/* cache the mute and volume index value */
+		if (evt_payload->voc_vm_info.dev_type == DIR_TX) {
+			v->dev_tx.mute =
+				evt_payload->voc_vm_info.dev_vm_val.mute;
+
+			mutex_lock(&v->lock);
+
+			if (v->voc_state == VOC_RUN)
+				voice_send_mute_cmd_to_modem(v);
+
+			mutex_unlock(&v->lock);
+		} else {
+			v->dev_rx.volume =
+					evt_payload->voc_vm_info.dev_vm_val.vol;
+
+			mutex_lock(&v->lock);
+
+			if (v->voc_state == VOC_RUN)
+				voice_send_vol_index_to_modem(v);
+
+			mutex_unlock(&v->lock);
+		}
+		break;
+	case AUDDEV_EVT_REL_PENDING:
+		/* Device change is applicable to all sessions. */
+		for (i = 0; i < MAX_VOC_SESSIONS; i++) {
+			v = &c->voice[i];
+
+			mutex_lock(&v->lock);
+
+			if (v->voc_state == VOC_RUN) {
+				voice_disable_vocproc(v);
+				v->voc_state = VOC_CHANGE;
+			}
+
+			mutex_unlock(&v->lock);
+
+			if (evt_payload->voc_devinfo.dev_type == DIR_RX)
+				v->dev_rx.enabled = VOICE_DEV_DISABLED;
+			else
+				v->dev_tx.enabled = VOICE_DEV_DISABLED;
+		}
+
+		break;
+	case AUDDEV_EVT_END_VOICE:
+		v = voice_get_session(evt_payload->voice_session_id);
+		if (v == NULL) {
+			pr_err("%s: v is NULL\n", __func__);
+			return;
+		}
+
+		/* recover the tx mute and rx volume to the default values */
+		v->dev_tx.mute = c->default_mute_val;
+		v->dev_rx.volume = c->default_vol_val;
+		if (v->dev_rx.enabled == VOICE_DEV_ENABLED)
+			msm_snddev_enable_sidetone(v->dev_rx.dev_id, 0, 0);
+
+		mutex_lock(&v->lock);
+
+		if (v->voc_state == VOC_RUN) {
+			/* call stop modem voice */
+			voice_send_stop_voice_cmd(v);
+			voice_destroy_modem_voice(v);
+			voice_destroy_mvm_cvs_session(v);
+			v->voc_state = VOC_RELEASE;
+		} else if (v->voc_state == VOC_CHANGE) {
+			voice_send_stop_voice_cmd(v);
+			voice_destroy_mvm_cvs_session(v);
+			v->voc_state = VOC_RELEASE;
+		}
+
+		mutex_unlock(&v->lock);
+
+		v->v_call_status = VOICE_CALL_END;
+
+		break;
+	default:
+		pr_err("UNKNOWN EVENT\n");
+	}
+	return;
+}
+EXPORT_SYMBOL(voice_auddev_cb_function);
+
+int voice_set_voc_path_full(uint32_t set)
+{
+	pr_info("%s: %d\n", __func__, set);
+
+	mutex_lock(&common.common_lock);
+
+	if (set)
+		common.voc_path = VOC_PATH_FULL;
+	else
+		common.voc_path = VOC_PATH_PASSIVE;
+
+	mutex_unlock(&common.common_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(voice_set_voc_path_full);
+
+void voice_register_mvs_cb(ul_cb_fn ul_cb,
+			   dl_cb_fn dl_cb,
+			   void *private_data)
+{
+	common.mvs_info.ul_cb = ul_cb;
+	common.mvs_info.dl_cb = dl_cb;
+	common.mvs_info.private_data = private_data;
+}
+
+void voice_config_vocoder(uint32_t media_type,
+			  uint32_t rate,
+			  uint32_t network_type,
+			  uint32_t dtx_mode,
+			  struct q_min_max_rate q_min_max_rate)
+{
+	common.mvs_info.media_type = media_type;
+	common.mvs_info.rate = rate;
+	common.mvs_info.network_type = network_type;
+	common.mvs_info.dtx_mode = dtx_mode;
+	common.mvs_info.q_min_max_rate = q_min_max_rate;
+}
+
+static int32_t modem_mvm_callback(struct apr_client_data *data, void *priv)
+{
+	uint32_t *ptr;
+	struct common_data *c = priv;
+	struct voice_data *v = NULL;
+	int i = 0;
+
+	pr_debug("%s: session_id 0x%x\n", __func__, data->dest_port);
+
+	if (data->opcode == RESET_EVENTS) {
+		pr_debug("%s:Reset event received in Voice service\n",
+					__func__);
+		apr_reset(c->apr_mvm);
+		c->apr_mvm = NULL;
+		apr_reset(c->apr_q6_mvm);
+		c->apr_q6_mvm = NULL;
+
+		/* Sub-system restart is applicable to all sessions. */
+		for (i = 0; i < MAX_VOC_SESSIONS; i++)
+			c->voice[i].mvm_handle = 0;
+
+		return 0;
+	}
+
+	v = voice_get_session(data->dest_port);
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	pr_debug("%s: common data 0x%x, session 0x%x\n",
+		 __func__, (unsigned int)c, (unsigned int)v);
+	pr_debug("%s: Payload Length = %d, opcode=%x\n", __func__,
+				data->payload_size, data->opcode);
+
+	if (data->opcode == APR_BASIC_RSP_RESULT) {
+		if (data->payload_size) {
+			ptr = data->payload;
+
+			pr_info("%x %x\n", ptr[0], ptr[1]);
+			/* ping mvm service ACK */
+
+			if (ptr[0] ==
+			 VSS_IMVM_CMD_CREATE_PASSIVE_CONTROL_SESSION ||
+			ptr[0] ==
+			    VSS_IMVM_CMD_CREATE_FULL_CONTROL_SESSION) {
+				/* Passive session is used for voice call
+				 * through modem. Full session is used for voice
+				 * call through Q6. */
+				pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
+				if (!ptr[1]) {
+					pr_debug("%s: MVM handle is %d\n",
+						 __func__, data->src_port);
+
+					voice_set_mvm_handle(v, data->src_port);
+				} else
+					pr_info("got NACK for sending \
+							MVM create session \n");
+				v->mvm_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->mvm_wait);
+			} else if (ptr[0] == VSS_IMVM_CMD_START_VOICE) {
+				pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
+				v->mvm_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->mvm_wait);
+			} else if (ptr[0] == VSS_ISTREAM_CMD_ATTACH_VOCPROC) {
+				pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
+				v->mvm_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->mvm_wait);
+			} else if (ptr[0] == VSS_IMVM_CMD_STOP_VOICE) {
+				v->mvm_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->mvm_wait);
+			} else if (ptr[0] == VSS_ISTREAM_CMD_DETACH_VOCPROC) {
+				v->mvm_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->mvm_wait);
+			} else if (ptr[0] == VSS_ISTREAM_CMD_SET_TTY_MODE) {
+				v->mvm_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->mvm_wait);
+			} else if (ptr[0] == APRV2_IBASIC_CMD_DESTROY_SESSION) {
+				pr_debug("%s: DESTROY resp\n", __func__);
+
+				v->mvm_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->mvm_wait);
+			} else if (ptr[0] == VSS_IMVM_CMD_ATTACH_STREAM) {
+				pr_debug("%s: ATTACH_STREAM resp 0x%x\n",
+					__func__, ptr[1]);
+
+				v->mvm_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->mvm_wait);
+			} else if (ptr[0] == VSS_IMVM_CMD_DETACH_STREAM) {
+				pr_debug("%s: DETACH_STREAM resp 0x%x\n",
+					__func__, ptr[1]);
+
+				v->mvm_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->mvm_wait);
+			} else if (ptr[0] == VSS_ICOMMON_CMD_SET_NETWORK) {
+				pr_debug("%s: SET_NETWORK resp 0x%x\n",
+					__func__, ptr[1]);
+
+				v->mvm_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->mvm_wait);
+			} else if (ptr[0] == VSS_ICOMMON_CMD_SET_VOICE_TIMING) {
+				pr_debug("%s: SET_VOICE_TIMING resp 0x%x\n",
+					__func__, ptr[1]);
+
+				v->mvm_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->mvm_wait);
+			} else
+				pr_debug("%s: not match cmd = 0x%x\n",
+					__func__, ptr[0]);
+		}
+	}
+
+	return 0;
+}
+
+static int32_t modem_cvs_callback(struct apr_client_data *data, void *priv)
+{
+	uint32_t *ptr;
+	struct common_data *c = priv;
+	struct voice_data *v = NULL;
+	int i = 0;
+
+	pr_debug("%s: session_id 0x%x\n", __func__, data->dest_port);
+
+	if (data->opcode == RESET_EVENTS) {
+		pr_debug("%s:Reset event received in Voice service\n",
+					__func__);
+		apr_reset(c->apr_cvs);
+		c->apr_cvs = NULL;
+		apr_reset(c->apr_q6_cvs);
+		c->apr_q6_cvs = NULL;
+
+		/* Sub-system restart is applicable to all sessions. */
+		for (i = 0; i < MAX_VOC_SESSIONS; i++)
+			c->voice[i].cvs_handle = 0;
+
+		return 0;
+	}
+
+	v = voice_get_session(data->dest_port);
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	pr_debug("%s: common data 0x%x, session 0x%x\n",
+		 __func__, (unsigned int)c, (unsigned int)v);
+	pr_debug("%s: Payload Length = %d, opcode=%x\n", __func__,
+					data->payload_size, data->opcode);
+
+	if (data->opcode == APR_BASIC_RSP_RESULT) {
+		if (data->payload_size) {
+			ptr = data->payload;
+
+			pr_info("%x %x\n", ptr[0], ptr[1]);
+			/*response from modem CVS */
+			if (ptr[0] ==
+			VSS_ISTREAM_CMD_CREATE_PASSIVE_CONTROL_SESSION ||
+			    ptr[0] ==
+			    VSS_ISTREAM_CMD_CREATE_FULL_CONTROL_SESSION) {
+				if (!ptr[1]) {
+					pr_debug("%s: CVS handle is %d\n",
+						 __func__, data->src_port);
+					voice_set_cvs_handle(v, data->src_port);
+				} else
+					pr_info("got NACK for sending \
+							CVS create session \n");
+				v->cvs_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvs_wait);
+			} else if (ptr[0] ==
+				VSS_ISTREAM_CMD_CACHE_CALIBRATION_DATA) {
+				v->cvs_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvs_wait);
+			} else if (ptr[0] ==
+					VSS_ISTREAM_CMD_SET_MUTE) {
+				v->cvs_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvs_wait);
+			} else if (ptr[0] == VSS_ISTREAM_CMD_SET_MEDIA_TYPE) {
+				pr_debug("%s: SET_MEDIA resp 0x%x\n",
+					 __func__, ptr[1]);
+
+				v->cvs_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvs_wait);
+			} else if (ptr[0] ==
+				   VSS_ISTREAM_CMD_VOC_AMR_SET_ENC_RATE) {
+				pr_debug("%s: SET_AMR_RATE resp 0x%x\n",
+					 __func__, ptr[1]);
+
+				v->cvs_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvs_wait);
+			} else if (ptr[0] ==
+				   VSS_ISTREAM_CMD_VOC_AMRWB_SET_ENC_RATE) {
+				pr_debug("%s: SET_AMR_WB_RATE resp 0x%x\n",
+					 __func__, ptr[1]);
+
+				v->cvs_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvs_wait);
+			} else if (ptr[0] == VSS_ISTREAM_CMD_SET_ENC_DTX_MODE) {
+				pr_debug("%s: SET_DTX resp 0x%x\n",
+					 __func__, ptr[1]);
+
+				v->cvs_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvs_wait);
+			} else if (ptr[0] ==
+				   VSS_ISTREAM_CMD_CDMA_SET_ENC_MINMAX_RATE) {
+				pr_debug("%s: SET_CDMA_RATE resp 0x%x\n",
+					 __func__, ptr[1]);
+
+				v->cvs_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvs_wait);
+			} else if (ptr[0] == APRV2_IBASIC_CMD_DESTROY_SESSION) {
+				pr_debug("%s: DESTROY resp\n", __func__);
+
+				v->cvs_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvs_wait);
+			} else if (ptr[0] == VSS_ISTREAM_CMD_START_RECORD) {
+				pr_debug("%s: START_RECORD resp 0x%x\n",
+					 __func__, ptr[1]);
+
+					v->cvs_state = CMD_STATUS_SUCCESS;
+					wake_up(&v->cvs_wait);
+			} else if (ptr[0] == VSS_ISTREAM_CMD_STOP_RECORD) {
+				pr_debug("%s: STOP_RECORD resp 0x%x\n",
+					 __func__, ptr[1]);
+
+					v->cvs_state = CMD_STATUS_SUCCESS;
+					wake_up(&v->cvs_wait);
+			} else if (ptr[0] == VOICE_CMD_SET_PARAM) {
+				rtac_make_voice_callback(RTAC_CVS, ptr,
+					data->payload_size);
+			} else if (ptr[0] == VSS_ISTREAM_CMD_START_PLAYBACK) {
+				pr_debug("%s: START_PLAYBACK resp 0x%x\n",
+					 __func__, ptr[1]);
+
+					v->cvs_state = CMD_STATUS_SUCCESS;
+					wake_up(&v->cvs_wait);
+			} else if (ptr[0] == VSS_ISTREAM_CMD_STOP_PLAYBACK) {
+				pr_debug("%s: STOP_PLAYBACK resp 0x%x\n",
+					 __func__, ptr[1]);
+
+					v->cvs_state = CMD_STATUS_SUCCESS;
+					wake_up(&v->cvs_wait);
+			} else
+				pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
+		}
+	} else if (data->opcode == VSS_ISTREAM_EVT_SEND_ENC_BUFFER) {
+		uint32_t *voc_pkt = data->payload;
+		uint32_t pkt_len = data->payload_size;
+
+		if (voc_pkt != NULL && c->mvs_info.ul_cb != NULL) {
+			pr_debug("%s: Media type is 0x%x\n",
+				 __func__, voc_pkt[0]);
+
+			/* Remove media ID from payload. */
+			voc_pkt++;
+			pkt_len = pkt_len - 4;
+
+			c->mvs_info.ul_cb((uint8_t *)voc_pkt,
+					  pkt_len,
+					  c->mvs_info.private_data);
+			} else {
+				pr_err("%s: voc_pkt is 0x%x ul_cb is 0x%x\n",
+				       __func__, (unsigned int)voc_pkt,
+				       (unsigned int)c->mvs_info.ul_cb);
+			}
+	} else if (data->opcode == VSS_ISTREAM_EVT_SEND_DEC_BUFFER) {
+			pr_debug("%s: Send dec buf resp\n", __func__);
+	} else if (data->opcode == VSS_ISTREAM_EVT_REQUEST_DEC_BUFFER) {
+		struct cvs_send_dec_buf_cmd send_dec_buf;
+		int ret = 0;
+		uint32_t pkt_len = 0;
+
+		if (c->mvs_info.dl_cb != NULL) {
+			send_dec_buf.dec_buf.media_id = c->mvs_info.media_type;
+
+			c->mvs_info.dl_cb(
+				(uint8_t *)&send_dec_buf.dec_buf.packet_data,
+				&pkt_len,
+				c->mvs_info.private_data);
+
+			send_dec_buf.hdr.hdr_field =
+				APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					      APR_HDR_LEN(APR_HDR_SIZE),
+					      APR_PKT_VER);
+			send_dec_buf.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+			       sizeof(send_dec_buf.dec_buf.media_id) + pkt_len);
+			send_dec_buf.hdr.src_port = v->session_id;
+			send_dec_buf.hdr.dest_port = voice_get_cvs_handle(v);
+			send_dec_buf.hdr.token = 0;
+			send_dec_buf.hdr.opcode =
+					VSS_ISTREAM_EVT_SEND_DEC_BUFFER;
+
+			ret = apr_send_pkt(voice_get_apr_cvs(),
+					   (uint32_t *) &send_dec_buf);
+			if (ret < 0) {
+				pr_err("%s: Error %d sending DEC_BUF\n",
+				       __func__, ret);
+				goto fail;
+			}
+		} else {
+			pr_err("%s: ul_cb is NULL\n", __func__);
+		}
+	} else if (data->opcode ==  VOICE_EVT_GET_PARAM_ACK) {
+		rtac_make_voice_callback(RTAC_CVS, data->payload,
+					data->payload_size);
+	} else {
+		pr_debug("%s: Unknown opcode 0x%x\n", __func__, data->opcode);
+	}
+
+fail:
+	return 0;
+}
+
+static int32_t modem_cvp_callback(struct apr_client_data *data, void *priv)
+{
+	uint32_t *ptr;
+	struct common_data *c = priv;
+	struct voice_data *v = NULL;
+	int i = 0;
+
+	pr_debug("%s: session_id 0x%x\n", __func__, data->dest_port);
+
+	if (data->opcode == RESET_EVENTS) {
+		pr_debug("%s:Reset event received in Voice service\n",
+					__func__);
+		apr_reset(c->apr_cvp);
+		c->apr_cvp = NULL;
+		apr_reset(c->apr_q6_cvp);
+		c->apr_q6_cvp = NULL;
+
+		/* Sub-system restart is applicable to all sessions. */
+		for (i = 0; i < MAX_VOC_SESSIONS; i++)
+			c->voice[i].cvp_handle = 0;
+
+		return 0;
+	}
+
+	v = voice_get_session(data->dest_port);
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	pr_debug("%s: common data 0x%x, session 0x%x\n",
+		 __func__, (unsigned int)c, (unsigned int)v);
+	pr_debug("%s: Payload Length = %d, opcode=%x\n", __func__,
+				data->payload_size, data->opcode);
+
+	if (data->opcode == APR_BASIC_RSP_RESULT) {
+		if (data->payload_size) {
+			ptr = data->payload;
+
+			pr_info("%x %x\n", ptr[0], ptr[1]);
+			/*response from modem CVP */
+			if (ptr[0] ==
+				VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION) {
+				pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
+				if (!ptr[1]) {
+					voice_set_cvp_handle(v, data->src_port);
+					pr_debug("cvphdl=%d\n", data->src_port);
+				} else
+					pr_info("got NACK from CVP create \
+						session response\n");
+				v->cvp_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvp_wait);
+			} else if (ptr[0] ==
+				VSS_IVOCPROC_CMD_CACHE_CALIBRATION_DATA) {
+				pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
+				v->cvp_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvp_wait);
+			} else if (ptr[0] == VSS_IVOCPROC_CMD_SET_DEVICE) {
+				v->cvp_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvp_wait);
+			} else if (ptr[0] ==
+					VSS_IVOCPROC_CMD_SET_RX_VOLUME_INDEX) {
+				v->cvp_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvp_wait);
+			} else if (ptr[0] == VSS_IVOCPROC_CMD_ENABLE) {
+				v->cvp_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvp_wait);
+			} else if (ptr[0] == VSS_IVOCPROC_CMD_DISABLE) {
+				v->cvp_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvp_wait);
+			} else if (ptr[0] == APRV2_IBASIC_CMD_DESTROY_SESSION) {
+				v->cvp_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvp_wait);
+			} else if (ptr[0] ==
+				VSS_IVOCPROC_CMD_CACHE_VOLUME_CALIBRATION_TABLE
+				) {
+
+				pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
+				v->cvp_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvp_wait);
+			} else if (ptr[0] == VOICE_CMD_SET_PARAM) {
+				rtac_make_voice_callback(RTAC_CVP, ptr,
+					data->payload_size);
+			} else
+				pr_debug("%s: not match cmd = 0x%x\n",
+							__func__, ptr[0]);
+		}
+	} else if (data->opcode ==  VOICE_EVT_GET_PARAM_ACK) {
+		rtac_make_voice_callback(RTAC_CVP, data->payload,
+			data->payload_size);
+	}
+	return 0;
+}
+
+
+static int __init voice_init(void)
+{
+	int rc = 0, i = 0;
+
+	memset(&common, 0, sizeof(struct common_data));
+
+	/* set default value */
+	common.default_mute_val = 1;  /* default is mute */
+	common.default_vol_val = 0;
+	common.default_sample_val = 8000;
+
+	common.voc_path = VOC_PATH_PASSIVE;
+
+	/* Initialize MVS info. */
+	common.mvs_info.network_type = VSS_NETWORK_ID_DEFAULT;
+
+	mutex_init(&common.common_lock);
+
+	for (i = 0; i < MAX_VOC_SESSIONS; i++) {
+		common.voice[i].session_id = SESSION_ID_BASE + i;
+
+		common.voice[i].dev_rx.volume = common.default_vol_val;
+		common.voice[i].dev_tx.mute = common.default_mute_val;
+
+		common.voice[i].voc_state = VOC_INIT;
+
+		common.voice[i].rec_info.rec_mode = VOC_REC_NONE;
+
+		init_waitqueue_head(&common.voice[i].mvm_wait);
+		init_waitqueue_head(&common.voice[i].cvs_wait);
+		init_waitqueue_head(&common.voice[i].cvp_wait);
+
+		mutex_init(&common.voice[i].lock);
+
+	}
+
+	common.device_events = AUDDEV_EVT_DEV_CHG_VOICE |
+			AUDDEV_EVT_DEV_RDY |
+			AUDDEV_EVT_REL_PENDING |
+			AUDDEV_EVT_START_VOICE |
+			AUDDEV_EVT_END_VOICE |
+			AUDDEV_EVT_DEVICE_VOL_MUTE_CHG |
+			AUDDEV_EVT_FREQ_CHG;
+
+	pr_debug("to register call back\n");
+	/* register callback to auddev */
+	auddev_register_evt_listner(common.device_events, AUDDEV_CLNT_VOC,
+				0, voice_auddev_cb_function, &common);
+
+	return rc;
+}
+
+device_initcall(voice_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/qcelp_in.c b/arch/arm/mach-msm/qdsp6v2/qcelp_in.c
new file mode 100644
index 0000000..a48df39
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/qcelp_in.c
@@ -0,0 +1,290 @@
+/* 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
+ * 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/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/msm_audio_qcp.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include "audio_utils.h"
+
+/* Buffer with meta*/
+#define PCM_BUF_SIZE		(4096 + sizeof(struct meta_in))
+
+/* Maximum 10 frames in buffer with meta */
+#define FRAME_SIZE		(1 + ((35+sizeof(struct meta_out_dsp)) * 10))
+
+/* ------------------- device --------------------- */
+static long qcelp_in_ioctl(struct file *file,
+				unsigned int cmd, unsigned long arg)
+{
+	struct q6audio_in  *audio = file->private_data;
+	int rc = 0;
+	int cnt = 0;
+
+	switch (cmd) {
+	case AUDIO_START: {
+		struct msm_audio_qcelp_enc_config *enc_cfg;
+		enc_cfg = audio->enc_cfg;
+		pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__,
+				audio->ac->session, audio->buf_alloc);
+		if (audio->enabled == 1) {
+			pr_info("%s:AUDIO_START already over\n", __func__);
+			rc = 0;
+			break;
+		}
+		rc = audio_in_buf_alloc(audio);
+		if (rc < 0) {
+			pr_err("%s:session id %d: buffer allocation failed\n",
+				__func__, audio->ac->session);
+			break;
+		}
+
+		/* reduced_rate_level, rate_modulation_cmd set to zero
+			 currently not configurable from user space */
+		rc = q6asm_enc_cfg_blk_qcelp(audio->ac,
+			audio->buf_cfg.frames_per_buf,
+			enc_cfg->min_bit_rate,
+			enc_cfg->max_bit_rate, 0, 0);
+
+		if (rc < 0) {
+			pr_err("%s:session id %d: cmd qcelp media format block"
+				"failed\n", __func__, audio->ac->session);
+			break;
+		}
+		if (audio->feedback == NON_TUNNEL_MODE) {
+			rc = q6asm_media_format_block_pcm(audio->ac,
+				audio->pcm_cfg.sample_rate,
+				audio->pcm_cfg.channel_count);
+
+			if (rc < 0) {
+				pr_err("%s:session id %d: media format block"
+				"failed\n", __func__, audio->ac->session);
+				break;
+			}
+		}
+		pr_debug("%s:session id %d: AUDIO_START enable[%d]\n", __func__,
+				audio->ac->session, audio->enabled);
+		rc = audio_in_enable(audio);
+		if (!rc) {
+			audio->enabled = 1;
+		} else {
+			audio->enabled = 0;
+			pr_err("%s:session id %d: Audio Start procedure failed"
+				"rc=%d\n", __func__, audio->ac->session, rc);
+			break;
+		}
+		while (cnt++ < audio->str_cfg.buffer_count)
+			q6asm_read(audio->ac); /* Push buffer to DSP */
+		rc = 0;
+		pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n",
+				__func__, audio->ac->session, audio->enabled);
+		break;
+	}
+	case AUDIO_STOP: {
+		pr_debug("%s:session id %d: AUDIO_STOP\n", __func__,
+				audio->ac->session);
+		rc = audio_in_disable(audio);
+		if (rc  < 0) {
+			pr_err("%s:session id %d: Audio Stop procedure failed"
+					"rc=%d\n", __func__, audio->ac->session,
+					rc);
+			break;
+		}
+		break;
+	}
+	case AUDIO_GET_QCELP_ENC_CONFIG: {
+		if (copy_to_user((void *)arg, audio->enc_cfg,
+			sizeof(struct msm_audio_qcelp_enc_config)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_QCELP_ENC_CONFIG: {
+		struct msm_audio_qcelp_enc_config cfg;
+		struct msm_audio_qcelp_enc_config *enc_cfg;
+		enc_cfg = audio->enc_cfg;
+		if (copy_from_user(&cfg, (void *) arg,
+				sizeof(struct msm_audio_qcelp_enc_config))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		if (cfg.min_bit_rate > 4 ||
+			 cfg.min_bit_rate < 1) {
+			pr_err("%s:session id %d: invalid min bitrate\n",
+					__func__, audio->ac->session);
+			rc = -EINVAL;
+			break;
+		}
+		if (cfg.max_bit_rate > 4 ||
+			 cfg.max_bit_rate < 1) {
+			pr_err("%s:session id %d: invalid max bitrate\n",
+					__func__, audio->ac->session);
+			rc = -EINVAL;
+			break;
+		}
+		enc_cfg->min_bit_rate = cfg.min_bit_rate;
+		enc_cfg->max_bit_rate = cfg.max_bit_rate;
+		pr_debug("%s:session id %d: min_bit_rate= 0x%x"
+			"max_bit_rate=0x%x\n", __func__,
+			audio->ac->session, enc_cfg->min_bit_rate,
+			enc_cfg->max_bit_rate);
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+static int qcelp_in_open(struct inode *inode, struct file *file)
+{
+	struct q6audio_in *audio = NULL;
+	struct msm_audio_qcelp_enc_config *enc_cfg;
+	int rc = 0;
+
+	audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
+
+	if (audio == NULL) {
+		pr_err("%s: Could not allocate memory for qcelp"
+				"driver\n", __func__);
+		return -ENOMEM;
+	}
+	/* Allocate memory for encoder config param */
+	audio->enc_cfg = kzalloc(sizeof(struct msm_audio_qcelp_enc_config),
+				GFP_KERNEL);
+	if (audio->enc_cfg == NULL) {
+		pr_err("%s:session id %d: Could not allocate memory for aac"
+				"config param\n", __func__, audio->ac->session);
+		kfree(audio);
+		return -ENOMEM;
+	}
+	enc_cfg = audio->enc_cfg;
+
+	mutex_init(&audio->lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->write_lock);
+	spin_lock_init(&audio->dsp_lock);
+	init_waitqueue_head(&audio->read_wait);
+	init_waitqueue_head(&audio->write_wait);
+
+	/* Settings will be re-config at AUDIO_SET_CONFIG,
+	* but at least we need to have initial config
+	*/
+	audio->str_cfg.buffer_size = FRAME_SIZE;
+	audio->str_cfg.buffer_count = FRAME_NUM;
+	audio->min_frame_size = 35;
+	audio->max_frames_per_buf = 10;
+	audio->pcm_cfg.buffer_size = PCM_BUF_SIZE;
+	audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
+	enc_cfg->min_bit_rate = 4;
+	enc_cfg->max_bit_rate = 4;
+	audio->pcm_cfg.channel_count = 1;
+	audio->pcm_cfg.sample_rate = 8000;
+	audio->buf_cfg.meta_info_enable = 0x01;
+	audio->buf_cfg.frames_per_buf = 0x01;
+
+	audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb,
+				(void *)audio);
+
+	if (!audio->ac) {
+		pr_err("%s: Could not allocate memory for audio"
+				"client\n", __func__);
+		kfree(audio->enc_cfg);
+		kfree(audio);
+		return -ENOMEM;
+	}
+
+	/* open qcelp encoder in T/NT mode */
+	if ((file->f_mode & FMODE_WRITE) &&
+		(file->f_mode & FMODE_READ)) {
+		audio->feedback = NON_TUNNEL_MODE;
+		rc = q6asm_open_read_write(audio->ac, FORMAT_V13K,
+					FORMAT_LINEAR_PCM);
+		if (rc < 0) {
+			pr_err("%s:session id %d: NT mode Open failed rc=%d\n",
+				__func__, audio->ac->session, rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		pr_info("%s:session id %d: NT mode encoder success\n", __func__,
+				audio->ac->session);
+	} else if (!(file->f_mode & FMODE_WRITE) &&
+				(file->f_mode & FMODE_READ)) {
+		audio->feedback = TUNNEL_MODE;
+		rc = q6asm_open_read(audio->ac, FORMAT_V13K);
+		if (rc < 0) {
+			pr_err("%s:session id %d: T mode Open failed rc=%d\n",
+				__func__, audio->ac->session, rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		/* register for tx overflow (valid for tunnel mode only) */
+		rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
+		if (rc < 0) {
+			pr_err("%s:session id %d: TX Overflow registration"
+			"failed rc=%d\n", __func__, audio->ac->session, rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		pr_info("%s:session id %d: T mode encoder success\n", __func__,
+				audio->ac->session);
+	} else {
+		pr_err("%s:session id %d: Unexpected mode\n", __func__,
+				audio->ac->session);
+		rc = -EACCES;
+		goto fail;
+	}
+
+	audio->opened = 1;
+	atomic_set(&audio->in_count, PCM_BUF_COUNT);
+	atomic_set(&audio->out_count, 0x00);
+	audio->enc_ioctl = qcelp_in_ioctl;
+	file->private_data = audio;
+
+	pr_info("%s:session id %d: success\n", __func__, audio->ac->session);
+	return 0;
+fail:
+	q6asm_audio_client_free(audio->ac);
+	kfree(audio->enc_cfg);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= qcelp_in_open,
+	.release	= audio_in_release,
+	.read		= audio_in_read,
+	.write		= audio_in_write,
+	.unlocked_ioctl	= audio_in_ioctl,
+};
+
+struct miscdevice audio_qcelp_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_qcelp_in",
+	.fops	= &audio_in_fops,
+};
+
+static int __init qcelp_in_init(void)
+{
+	return misc_register(&audio_qcelp_in_misc);
+}
+
+device_initcall(qcelp_in_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/rtac.c b/arch/arm/mach-msm/qdsp6v2/rtac.c
new file mode 100644
index 0000000..4ce9b030
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/rtac.c
@@ -0,0 +1,1024 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/msm_audio_acdb.h>
+#include <asm/atomic.h>
+#include <mach/qdsp6v2/audio_acdb.h>
+#include <mach/qdsp6v2/rtac.h>
+#include <sound/q6asm.h>
+#include <sound/q6adm.h>
+
+#ifndef CONFIG_RTAC
+
+void rtac_add_adm_device(u32 port_id, u32 copp_id, u32 path_id, u32 popp_id) {}
+void rtac_remove_adm_device(u32 port_id) {}
+void rtac_remove_popp_from_adm_devices(u32 popp_id) {}
+void rtac_set_adm_handle(void *handle) {}
+bool rtac_make_adm_callback(uint32_t *payload, u32 payload_size)
+	{return false; }
+void rtac_set_asm_handle(u32 session_id, void *handle) {}
+bool rtac_make_asm_callback(u32 session_id, uint32_t *payload,
+	u32 payload_size) {return false; }
+void rtac_add_voice(u32 cvs_handle, u32 cvp_handle, u32 rx_afe_port,
+	u32 tx_afe_port, u32 session_id) {}
+void rtac_remove_voice(u32 cvs_handle) {}
+void rtac_set_voice_handle(u32 mode, void *handle) {}
+bool rtac_make_voice_callback(u32 mode, uint32_t *payload,
+		u32 payload_size) {return false; }
+
+#else
+
+#define VOICE_CMD_SET_PARAM		0x00011006
+#define VOICE_CMD_GET_PARAM		0x00011007
+#define VOICE_EVT_GET_PARAM_ACK		0x00011008
+
+/* Max size of payload (buf size - apr header) */
+#define MAX_PAYLOAD_SIZE		4076
+#define RTAC_MAX_ACTIVE_DEVICES		4
+#define RTAC_MAX_ACTIVE_VOICE_COMBOS	2
+#define RTAC_MAX_ACTIVE_POPP		8
+#define RTAC_BUF_SIZE			4096
+
+#define TIMEOUT_MS	1000
+
+/* APR data */
+struct rtac_apr_data {
+	void			*apr_handle;
+	atomic_t		cmd_state;
+	wait_queue_head_t	cmd_wait;
+};
+
+static struct rtac_apr_data	rtac_adm_apr_data;
+static struct rtac_apr_data	rtac_asm_apr_data[SESSION_MAX+1];
+static struct rtac_apr_data	rtac_voice_apr_data[RTAC_VOICE_MODES];
+
+
+/* ADM info & APR */
+struct rtac_adm_data {
+	uint32_t	topology_id;
+	uint32_t	afe_port;
+	uint32_t	copp;
+	uint32_t	num_of_popp;
+	uint32_t	popp[RTAC_MAX_ACTIVE_POPP];
+};
+
+struct rtac_adm {
+	uint32_t		num_of_dev;
+	struct rtac_adm_data	device[RTAC_MAX_ACTIVE_DEVICES];
+};
+static struct rtac_adm		rtac_adm_data;
+static u32			rtac_adm_payload_size;
+static u32			rtac_adm_user_buf_size;
+static u8			*rtac_adm_buffer;
+
+
+/* ASM APR */
+static u32			rtac_asm_payload_size;
+static u32			rtac_asm_user_buf_size;
+static u8			*rtac_asm_buffer;
+
+
+/* Voice info & APR */
+struct rtac_voice_data {
+	uint32_t	tx_topology_id;
+	uint32_t	rx_topology_id;
+	uint32_t	tx_afe_port;
+	uint32_t	rx_afe_port;
+	uint16_t	cvs_handle;
+	uint16_t	cvp_handle;
+};
+
+struct rtac_voice {
+	uint32_t		num_of_voice_combos;
+	struct rtac_voice_data	voice[RTAC_MAX_ACTIVE_VOICE_COMBOS];
+};
+
+static struct rtac_voice	rtac_voice_data;
+static u32			rtac_voice_payload_size;
+static u32			rtac_voice_user_buf_size;
+static u8			*rtac_voice_buffer;
+static u32			voice_session_id[RTAC_MAX_ACTIVE_VOICE_COMBOS];
+
+
+struct mutex			rtac_adm_mutex;
+struct mutex			rtac_adm_apr_mutex;
+struct mutex			rtac_asm_apr_mutex;
+struct mutex			rtac_voice_mutex;
+struct mutex			rtac_voice_apr_mutex;
+
+static int rtac_open(struct inode *inode, struct file *f)
+{
+	pr_debug("%s\n", __func__);
+	return 0;
+}
+
+static int rtac_release(struct inode *inode, struct file *f)
+{
+	pr_debug("%s\n", __func__);
+	return 0;
+}
+
+/* ADM Info */
+void add_popp(u32 dev_idx, u32 port_id, u32 popp_id)
+{
+	u32 i = 0;
+
+	for (; i < rtac_adm_data.device[dev_idx].num_of_popp; i++)
+		if (rtac_adm_data.device[dev_idx].popp[i] == popp_id)
+			goto done;
+
+	if (rtac_adm_data.device[dev_idx].num_of_popp ==
+			RTAC_MAX_ACTIVE_POPP) {
+		pr_err("%s, Max POPP!\n", __func__);
+		goto done;
+	}
+	rtac_adm_data.device[dev_idx].popp[
+		rtac_adm_data.device[dev_idx].num_of_popp++] = popp_id;
+done:
+	return;
+}
+
+void rtac_add_adm_device(u32 port_id, u32 copp_id, u32 path_id, u32 popp_id)
+{
+	u32 i = 0;
+	pr_debug("%s: port_id = %d, popp_id = %d\n", __func__, port_id,
+		popp_id);
+
+	mutex_lock(&rtac_adm_mutex);
+	if (rtac_adm_data.num_of_dev == RTAC_MAX_ACTIVE_DEVICES) {
+		pr_err("%s, Can't add anymore RTAC devices!\n", __func__);
+		goto done;
+	}
+
+	/* Check if device already added */
+	if (rtac_adm_data.num_of_dev != 0) {
+		for (; i < rtac_adm_data.num_of_dev; i++) {
+			if (rtac_adm_data.device[i].afe_port == port_id) {
+				add_popp(i, port_id, popp_id);
+				goto done;
+			}
+			if (rtac_adm_data.device[i].num_of_popp ==
+						RTAC_MAX_ACTIVE_POPP) {
+				pr_err("%s, Max POPP!\n", __func__);
+				goto done;
+			}
+		}
+	}
+
+	/* Add device */
+	rtac_adm_data.num_of_dev++;
+
+	if (path_id == ADM_PATH_PLAYBACK)
+		rtac_adm_data.device[i].topology_id =
+						get_adm_rx_topology();
+	else
+		rtac_adm_data.device[i].topology_id =
+						get_adm_tx_topology();
+	rtac_adm_data.device[i].afe_port = port_id;
+	rtac_adm_data.device[i].copp = copp_id;
+	rtac_adm_data.device[i].popp[
+		rtac_adm_data.device[i].num_of_popp++] = popp_id;
+done:
+	mutex_unlock(&rtac_adm_mutex);
+	return;
+}
+
+static void shift_adm_devices(u32 dev_idx)
+{
+	for (; dev_idx < rtac_adm_data.num_of_dev; dev_idx++) {
+		memcpy(&rtac_adm_data.device[dev_idx],
+			&rtac_adm_data.device[dev_idx + 1],
+			sizeof(rtac_adm_data.device[dev_idx]));
+		memset(&rtac_adm_data.device[dev_idx + 1], 0,
+			   sizeof(rtac_adm_data.device[dev_idx]));
+	}
+}
+
+static void shift_popp(u32 copp_idx, u32 popp_idx)
+{
+	for (; popp_idx < rtac_adm_data.device[copp_idx].num_of_popp;
+							popp_idx++) {
+		memcpy(&rtac_adm_data.device[copp_idx].popp[popp_idx],
+			&rtac_adm_data.device[copp_idx].popp[popp_idx + 1],
+			sizeof(uint32_t));
+		memset(&rtac_adm_data.device[copp_idx].popp[popp_idx + 1], 0,
+			   sizeof(uint32_t));
+	}
+}
+
+void rtac_remove_adm_device(u32 port_id)
+{
+	s32 i;
+	pr_debug("%s: port_id = %d\n", __func__, port_id);
+
+	mutex_lock(&rtac_adm_mutex);
+	/* look for device */
+	for (i = 0; i < rtac_adm_data.num_of_dev; i++) {
+		if (rtac_adm_data.device[i].afe_port == port_id) {
+			memset(&rtac_adm_data.device[i], 0,
+				   sizeof(rtac_adm_data.device[i]));
+			rtac_adm_data.num_of_dev--;
+
+			if (rtac_adm_data.num_of_dev >= 1) {
+				shift_adm_devices(i);
+				break;
+			}
+		}
+	}
+
+	mutex_unlock(&rtac_adm_mutex);
+	return;
+}
+
+void rtac_remove_popp_from_adm_devices(u32 popp_id)
+{
+	s32 i, j;
+	pr_debug("%s: popp_id = %d\n", __func__, popp_id);
+
+	mutex_lock(&rtac_adm_mutex);
+
+	for (i = 0; i < rtac_adm_data.num_of_dev; i++) {
+		for (j = 0; j < rtac_adm_data.device[i].num_of_popp; j++) {
+			if (rtac_adm_data.device[i].popp[j] == popp_id) {
+				rtac_adm_data.device[i].popp[j] = 0;
+				rtac_adm_data.device[i].num_of_popp--;
+				shift_popp(i, j);
+			}
+		}
+	}
+
+	mutex_unlock(&rtac_adm_mutex);
+}
+
+/* Voice Info */
+static void set_rtac_voice_data(int idx, u32 cvs_handle, u32 cvp_handle,
+					u32 rx_afe_port, u32 tx_afe_port,
+					u32 session_id)
+{
+	rtac_voice_data.voice[idx].tx_topology_id = get_voice_tx_topology();
+	rtac_voice_data.voice[idx].rx_topology_id = get_voice_rx_topology();
+	rtac_voice_data.voice[idx].tx_afe_port = tx_afe_port;
+	rtac_voice_data.voice[idx].rx_afe_port = rx_afe_port;
+	rtac_voice_data.voice[idx].cvs_handle = cvs_handle;
+	rtac_voice_data.voice[idx].cvp_handle = cvp_handle;
+
+	/* Store session ID for voice RTAC */
+	voice_session_id[idx] = session_id;
+}
+
+void rtac_add_voice(u32 cvs_handle, u32 cvp_handle, u32 rx_afe_port,
+			u32 tx_afe_port, u32 session_id)
+{
+	u32 i = 0;
+	pr_debug("%s\n", __func__);
+	mutex_lock(&rtac_voice_mutex);
+
+	if (rtac_voice_data.num_of_voice_combos ==
+			RTAC_MAX_ACTIVE_VOICE_COMBOS) {
+		pr_err("%s, Can't add anymore RTAC devices!\n", __func__);
+		goto done;
+	}
+
+	/* Check if device already added */
+	if (rtac_voice_data.num_of_voice_combos != 0) {
+		for (; i < rtac_voice_data.num_of_voice_combos; i++) {
+			if (rtac_voice_data.voice[i].cvs_handle ==
+							cvs_handle) {
+				set_rtac_voice_data(i, cvs_handle, cvp_handle,
+					rx_afe_port, tx_afe_port,
+					session_id);
+				goto done;
+			}
+		}
+	}
+
+	/* Add device */
+	rtac_voice_data.num_of_voice_combos++;
+	set_rtac_voice_data(i, cvs_handle, cvp_handle,
+				rx_afe_port, tx_afe_port,
+				session_id);
+done:
+	mutex_unlock(&rtac_voice_mutex);
+	return;
+}
+
+static void shift_voice_devices(u32 idx)
+{
+	for (; idx < rtac_voice_data.num_of_voice_combos - 1; idx++) {
+		memcpy(&rtac_voice_data.voice[idx],
+			&rtac_voice_data.voice[idx + 1],
+			sizeof(rtac_voice_data.voice[idx]));
+		voice_session_id[idx] = voice_session_id[idx + 1];
+	}
+}
+
+void rtac_remove_voice(u32 cvs_handle)
+{
+	u32 i = 0;
+	pr_debug("%s\n", __func__);
+
+	mutex_lock(&rtac_voice_mutex);
+	/* look for device */
+	for (i = 0; i < rtac_voice_data.num_of_voice_combos; i++) {
+		if (rtac_voice_data.voice[i].cvs_handle == cvs_handle) {
+			shift_voice_devices(i);
+			rtac_voice_data.num_of_voice_combos--;
+			memset(&rtac_voice_data.voice[
+				rtac_voice_data.num_of_voice_combos], 0,
+				sizeof(rtac_voice_data.voice
+				[rtac_voice_data.num_of_voice_combos]));
+			voice_session_id[rtac_voice_data.num_of_voice_combos]
+				= 0;
+			break;
+		}
+	}
+	mutex_unlock(&rtac_voice_mutex);
+	return;
+}
+
+static int get_voice_index(u32 cvs_handle)
+{
+	u32 i;
+
+	for (i = 0; i < rtac_voice_data.num_of_voice_combos; i++) {
+		if (rtac_voice_data.voice[i].cvs_handle == cvs_handle)
+			return i;
+	}
+
+	pr_err("%s: No voice index for CVS handle %d found returning 0\n",
+	       __func__, cvs_handle);
+	return 0;
+}
+
+
+/* ADM APR */
+void rtac_set_adm_handle(void *handle)
+{
+	pr_debug("%s: handle = %d\n", __func__, (unsigned int)handle);
+
+	mutex_lock(&rtac_adm_apr_mutex);
+	rtac_adm_apr_data.apr_handle = handle;
+	mutex_unlock(&rtac_adm_apr_mutex);
+}
+
+bool rtac_make_adm_callback(uint32_t *payload, u32 payload_size)
+{
+	pr_debug("%s:cmd_state = %d\n", __func__,
+			atomic_read(&rtac_adm_apr_data.cmd_state));
+	if (atomic_read(&rtac_adm_apr_data.cmd_state) != 1)
+		return false;
+
+	/* Offset data for in-band payload */
+	rtac_copy_adm_payload_to_user(payload, payload_size);
+	atomic_set(&rtac_adm_apr_data.cmd_state, 0);
+	wake_up(&rtac_adm_apr_data.cmd_wait);
+	return true;
+}
+
+void rtac_copy_adm_payload_to_user(void *payload, u32 payload_size)
+{
+	pr_debug("%s\n", __func__);
+	rtac_adm_payload_size = payload_size;
+
+	memcpy(rtac_adm_buffer, &payload_size, sizeof(u32));
+	if (payload_size != 0) {
+		if (payload_size > rtac_adm_user_buf_size) {
+			pr_err("%s: Buffer set not big enough for "
+				"returned data, buf size = %d, "
+				"ret data = %d\n", __func__,
+				rtac_adm_user_buf_size, payload_size);
+			goto done;
+		}
+		memcpy(rtac_adm_buffer + sizeof(u32), payload, payload_size);
+	}
+done:
+	return;
+}
+
+u32 send_adm_apr(void *buf, u32 opcode)
+{
+	s32				result;
+	u32				count = 0;
+	u32				bytes_returned = 0;
+	u32				port_index = 0;
+	u32				copp_id;
+	u32				payload_size;
+	struct apr_hdr			adm_params;
+	pr_debug("%s\n", __func__);
+
+	if (copy_from_user(&count, (void *)buf, sizeof(count))) {
+			pr_err("%s: Copy to user failed! buf = 0x%x\n",
+			       __func__, (unsigned int)buf);
+			result = -EFAULT;
+			goto done;
+	}
+
+	if (count <= 0) {
+		pr_err("%s: Invalid buffer size = %d\n", __func__, count);
+		goto done;
+	}
+
+	if (copy_from_user(&payload_size, buf + sizeof(u32), sizeof(u32))) {
+		pr_err("%s: Could not copy payload size from user buffer\n",
+			__func__);
+		goto done;
+	}
+
+
+	if (payload_size > MAX_PAYLOAD_SIZE) {
+
+			pr_err("%s: Invalid payload size = %d\n",
+				__func__, payload_size);
+		goto done;
+	}
+
+	if (copy_from_user(&copp_id, buf + 2 * sizeof(u32), sizeof(u32))) {
+		pr_err("%s: Could not copy port id from user buffer\n",
+			__func__);
+		goto done;
+	}
+
+	for (port_index = 0; port_index < AFE_MAX_PORTS; port_index++) {
+		if (adm_get_copp_id(port_index) == copp_id)
+			break;
+	}
+	if (port_index >= AFE_MAX_PORTS) {
+		pr_err("%s: Could not find port index for copp = %d\n",
+		       __func__, copp_id);
+		goto done;
+	}
+
+	mutex_lock(&rtac_adm_apr_mutex);
+	if (rtac_adm_apr_data.apr_handle == NULL) {
+		pr_err("%s: APR not initialized\n", __func__);
+		goto err;
+	}
+
+	/* Set globals for copy of returned payload */
+	rtac_adm_user_buf_size = count;
+	/* Copy buffer to in-band payload */
+	if (copy_from_user(rtac_adm_buffer + sizeof(adm_params),
+			buf + 3 * sizeof(u32), payload_size)) {
+		pr_err("%s: Could not copy payload from user buffer\n",
+			__func__);
+		goto err;
+	}
+
+	/* Pack header */
+	adm_params.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+		APR_HDR_LEN(20), APR_PKT_VER);
+	adm_params.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+		payload_size);
+	adm_params.src_svc = APR_SVC_ADM;
+	adm_params.src_domain = APR_DOMAIN_APPS;
+	adm_params.src_port = copp_id;
+	adm_params.dest_svc = APR_SVC_ADM;
+	adm_params.dest_domain = APR_DOMAIN_ADSP;
+	adm_params.dest_port = copp_id;
+	adm_params.token = copp_id;
+	adm_params.opcode = opcode;
+
+	memcpy(rtac_adm_buffer, &adm_params, sizeof(adm_params));
+	atomic_set(&rtac_adm_apr_data.cmd_state, 1);
+
+	pr_debug("%s: Sending RTAC command size = %d\n",
+		__func__, adm_params.pkt_size);
+
+	result = apr_send_pkt(rtac_adm_apr_data.apr_handle,
+				(uint32_t *)rtac_adm_buffer);
+	if (result < 0) {
+		pr_err("%s: Set params failed port = %d, copp = %d\n",
+			__func__, port_index, copp_id);
+		goto err;
+	}
+	/* Wait for the callback */
+	result = wait_event_timeout(rtac_adm_apr_data.cmd_wait,
+		(atomic_read(&rtac_adm_apr_data.cmd_state) == 0),
+		msecs_to_jiffies(TIMEOUT_MS));
+	mutex_unlock(&rtac_adm_apr_mutex);
+	if (!result) {
+		pr_err("%s: Set params timed out port = %d, copp = %d\n",
+			__func__, port_index, copp_id);
+		goto done;
+	}
+
+	if (rtac_adm_payload_size != 0) {
+		if (copy_to_user(buf, rtac_adm_buffer,
+				rtac_adm_payload_size + sizeof(u32))) {
+			pr_err("%s: Could not copy buffer to user,"
+				"size = %d\n", __func__, payload_size);
+			goto done;
+		}
+	}
+
+	/* Return data written for SET & data read for GET */
+	if (opcode == ADM_CMD_GET_PARAMS)
+		bytes_returned = rtac_adm_payload_size;
+	else
+		bytes_returned = payload_size;
+done:
+	return bytes_returned;
+err:
+	mutex_unlock(&rtac_adm_apr_mutex);
+	return bytes_returned;
+}
+
+
+/* ASM APR */
+void rtac_set_asm_handle(u32 session_id, void *handle)
+{
+	pr_debug("%s\n", __func__);
+
+	mutex_lock(&rtac_asm_apr_mutex);
+	rtac_asm_apr_data[session_id].apr_handle = handle;
+	mutex_unlock(&rtac_asm_apr_mutex);
+}
+
+bool rtac_make_asm_callback(u32 session_id, uint32_t *payload,
+	u32 payload_size)
+{
+	if (atomic_read(&rtac_asm_apr_data[session_id].cmd_state) != 1)
+		return false;
+
+	pr_debug("%s\n", __func__);
+	/* Offset data for in-band payload */
+	rtac_copy_asm_payload_to_user(payload, payload_size);
+	atomic_set(&rtac_asm_apr_data[session_id].cmd_state, 0);
+	wake_up(&rtac_asm_apr_data[session_id].cmd_wait);
+	return true;
+}
+
+void rtac_copy_asm_payload_to_user(void *payload, u32 payload_size)
+{
+	pr_debug("%s\n", __func__);
+	rtac_asm_payload_size = payload_size;
+
+	memcpy(rtac_asm_buffer, &payload_size, sizeof(u32));
+	if (payload_size) {
+		if (payload_size > rtac_asm_user_buf_size) {
+			pr_err("%s: Buffer set not big enough for "
+				"returned data, buf size = %d, "
+				"ret data = %d\n", __func__,
+				rtac_asm_user_buf_size, payload_size);
+			goto done;
+		}
+		memcpy(rtac_asm_buffer + sizeof(u32), payload, payload_size);
+	}
+done:
+	return;
+}
+
+u32 send_rtac_asm_apr(void *buf, u32 opcode)
+{
+	s32				result;
+	u32				count = 0;
+	u32				bytes_returned = 0;
+	u32				session_id = 0;
+	u32				payload_size;
+	struct apr_hdr			asm_params;
+	pr_debug("%s\n", __func__);
+
+	if (copy_from_user(&count, (void *)buf, sizeof(count))) {
+			pr_err("%s: Copy to user failed! buf = 0x%x\n",
+			       __func__, (unsigned int)buf);
+			result = -EFAULT;
+			goto done;
+	}
+
+	if (count <= 0) {
+		pr_err("%s: Invalid buffer size = %d\n", __func__, count);
+		goto done;
+	}
+
+	if (copy_from_user(&payload_size, buf + sizeof(u32), sizeof(u32))) {
+		pr_err("%s: Could not copy payload size from user buffer\n",
+			__func__);
+		goto done;
+	}
+
+	if (payload_size > MAX_PAYLOAD_SIZE) {
+
+			pr_err("%s: Invalid payload size = %d\n",
+				__func__, payload_size);
+		goto done;
+	}
+
+	if (copy_from_user(&session_id, buf + 2 * sizeof(u32), sizeof(u32))) {
+		pr_err("%s: Could not copy session id from user buffer\n",
+			__func__);
+		goto done;
+	}
+	if (session_id > (SESSION_MAX + 1)) {
+		pr_err("%s: Invalid Session = %d\n", __func__, session_id);
+		goto done;
+	}
+
+	mutex_lock(&rtac_asm_apr_mutex);
+	if (session_id < SESSION_MAX+1) {
+		if (rtac_asm_apr_data[session_id].apr_handle == NULL) {
+			pr_err("%s: APR not initialized\n", __func__);
+			goto err;
+		}
+	}
+
+	/* Set globals for copy of returned payload */
+	rtac_asm_user_buf_size = count;
+
+	/* Copy buffer to in-band payload */
+	if (copy_from_user(rtac_asm_buffer + sizeof(asm_params),
+			buf + 3 * sizeof(u32), payload_size)) {
+		pr_err("%s: Could not copy payload from user buffer\n",
+			__func__);
+		goto err;
+	}
+
+	/* Pack header */
+	asm_params.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+		APR_HDR_LEN(20), APR_PKT_VER);
+	asm_params.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+		payload_size);
+	asm_params.src_svc = q6asm_get_apr_service_id(session_id);
+	asm_params.src_domain = APR_DOMAIN_APPS;
+	asm_params.src_port = (session_id << 8) | 0x0001;
+	asm_params.dest_svc = APR_SVC_ASM;
+	asm_params.dest_domain = APR_DOMAIN_ADSP;
+	asm_params.dest_port = (session_id << 8) | 0x0001;
+	asm_params.token = session_id;
+	asm_params.opcode = opcode;
+
+	memcpy(rtac_asm_buffer, &asm_params, sizeof(asm_params));
+	if (session_id < SESSION_MAX+1)
+		atomic_set(&rtac_asm_apr_data[session_id].cmd_state, 1);
+
+	pr_debug("%s: Sending RTAC command size = %d, session_id=%d\n",
+		__func__, asm_params.pkt_size, session_id);
+
+	result = apr_send_pkt(rtac_asm_apr_data[session_id].apr_handle,
+				(uint32_t *)rtac_asm_buffer);
+	if (result < 0) {
+		pr_err("%s: Set params failed session = %d\n",
+			__func__, session_id);
+		goto err;
+	}
+
+	/* Wait for the callback */
+	result = wait_event_timeout(rtac_asm_apr_data[session_id].cmd_wait,
+		(atomic_read(&rtac_asm_apr_data[session_id].cmd_state) == 0),
+		5 * HZ);
+	mutex_unlock(&rtac_asm_apr_mutex);
+	if (!result) {
+		pr_err("%s: Set params timed out session = %d\n",
+			__func__, session_id);
+		goto done;
+	}
+
+	if (rtac_asm_payload_size != 0) {
+		if (copy_to_user(buf, rtac_asm_buffer,
+				rtac_asm_payload_size + sizeof(u32))) {
+			pr_err("%s: Could not copy buffer to user,"
+				"size = %d\n", __func__, payload_size);
+			goto done;
+		}
+	}
+
+	/* Return data written for SET & data read for GET */
+	if (opcode == ASM_STREAM_CMD_GET_PP_PARAMS)
+		bytes_returned = rtac_asm_payload_size;
+	else
+		bytes_returned = payload_size;
+done:
+	return bytes_returned;
+err:
+	mutex_unlock(&rtac_asm_apr_mutex);
+	return bytes_returned;
+}
+
+
+/* Voice APR */
+void rtac_set_voice_handle(u32 mode, void *handle)
+{
+	pr_debug("%s\n", __func__);
+
+	mutex_lock(&rtac_voice_apr_mutex);
+	rtac_voice_apr_data[mode].apr_handle = handle;
+	mutex_unlock(&rtac_voice_apr_mutex);
+}
+
+bool rtac_make_voice_callback(u32 mode, uint32_t *payload, u32 payload_size)
+{
+	if ((atomic_read(&rtac_voice_apr_data[mode].cmd_state) != 1) ||
+			(mode >= RTAC_VOICE_MODES))
+		return false;
+
+	pr_debug("%s\n", __func__);
+	/* Offset data for in-band payload */
+	rtac_copy_voice_payload_to_user(payload, payload_size);
+	atomic_set(&rtac_voice_apr_data[mode].cmd_state, 0);
+	wake_up(&rtac_voice_apr_data[mode].cmd_wait);
+	return true;
+}
+
+void rtac_copy_voice_payload_to_user(void *payload, u32 payload_size)
+{
+	pr_debug("%s\n", __func__);
+	rtac_voice_payload_size = payload_size;
+
+	memcpy(rtac_voice_buffer, &payload_size, sizeof(u32));
+	if (payload_size) {
+		if (payload_size > rtac_voice_user_buf_size) {
+			pr_err("%s: Buffer set not big enough for "
+				"returned data, buf size = %d, "
+				"ret data = %d\n", __func__,
+				rtac_voice_user_buf_size, payload_size);
+			goto done;
+		}
+		memcpy(rtac_voice_buffer + sizeof(u32), payload, payload_size);
+	}
+done:
+	return;
+}
+
+u32 send_voice_apr(u32 mode, void *buf, u32 opcode)
+{
+	s32				result;
+	u32				count = 0;
+	u32				bytes_returned = 0;
+	u32				payload_size;
+	u16				dest_port;
+	struct apr_hdr			voice_params;
+	pr_debug("%s\n", __func__);
+
+	if (copy_from_user(&count, (void *)buf, sizeof(count))) {
+			pr_err("%s: Copy to user failed! buf = 0x%x\n",
+			       __func__, (unsigned int)buf);
+			result = -EFAULT;
+			goto done;
+	}
+
+	if (count <= 0) {
+		pr_err("%s: Invalid buffer size = %d\n", __func__, count);
+		goto done;
+	}
+
+	if (copy_from_user(&payload_size, buf + sizeof(u32), sizeof(u32))) {
+		pr_err("%s: Could not copy payload size from user buffer\n",
+			__func__);
+		goto done;
+	}
+
+	if (payload_size > MAX_PAYLOAD_SIZE) {
+		pr_err("%s: Invalid payload size = %d\n",
+				__func__, payload_size);
+		goto done;
+	}
+
+	if (copy_from_user(&dest_port, buf + 2 * sizeof(u32), sizeof(u32))) {
+		pr_err("%s: Could not copy port id from user buffer\n",
+			__func__);
+		goto done;
+	}
+
+	if ((mode != RTAC_CVP) && (mode != RTAC_CVS)) {
+		pr_err("%s: Invalid Mode for APR, mode = %d\n",
+			__func__, mode);
+		goto done;
+	}
+
+	mutex_lock(&rtac_voice_apr_mutex);
+	if (rtac_voice_apr_data[mode].apr_handle == NULL) {
+		pr_err("%s: APR not initialized\n", __func__);
+		goto err;
+	}
+
+	/* Set globals for copy of returned payload */
+	rtac_voice_user_buf_size = count;
+
+	/* Copy buffer to in-band payload */
+	if (copy_from_user(rtac_voice_buffer + sizeof(voice_params),
+			buf + 3 * sizeof(u32), payload_size)) {
+		pr_err("%s: Could not copy payload from user buffer\n",
+			__func__);
+		goto err;
+	}
+
+	/* Pack header */
+	voice_params.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+		APR_HDR_LEN(20), APR_PKT_VER);
+	voice_params.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+		payload_size);
+	voice_params.src_svc = 0;
+	voice_params.src_domain = APR_DOMAIN_APPS;
+	voice_params.src_port = voice_session_id[
+					get_voice_index(dest_port)];
+	voice_params.dest_svc = 0;
+	voice_params.dest_domain = APR_DOMAIN_MODEM;
+	voice_params.dest_port = dest_port;
+	voice_params.token = 0;
+	voice_params.opcode = opcode;
+
+	memcpy(rtac_voice_buffer, &voice_params, sizeof(voice_params));
+	atomic_set(&rtac_voice_apr_data[mode].cmd_state, 1);
+
+	pr_debug("%s: Sending RTAC command size = %d, opcode = %x\n",
+		__func__, voice_params.pkt_size, opcode);
+
+	result = apr_send_pkt(rtac_voice_apr_data[mode].apr_handle,
+					(uint32_t *)rtac_voice_buffer);
+	if (result < 0) {
+		pr_err("%s: apr_send_pkt failed opcode = %x\n",
+			__func__, opcode);
+		goto err;
+	}
+	/* Wait for the callback */
+	result = wait_event_timeout(rtac_voice_apr_data[mode].cmd_wait,
+		(atomic_read(&rtac_voice_apr_data[mode].cmd_state) == 0),
+		msecs_to_jiffies(TIMEOUT_MS));
+	mutex_unlock(&rtac_voice_apr_mutex);
+	if (!result) {
+		pr_err("%s: apr_send_pkt timed out opcode = %x\n",
+			__func__, opcode);
+		goto done;
+	}
+
+	if (rtac_voice_payload_size != 0) {
+		if (copy_to_user(buf, rtac_voice_buffer,
+				rtac_voice_payload_size + sizeof(u32))) {
+			pr_err("%s: Could not copy buffer to user,"
+				"size = %d\n", __func__, payload_size);
+			goto done;
+		}
+	}
+
+	/* Return data written for SET & data read for GET */
+	if (opcode == VOICE_CMD_GET_PARAM)
+		bytes_returned = rtac_voice_payload_size;
+	else
+		bytes_returned = payload_size;
+done:
+	return bytes_returned;
+err:
+	mutex_unlock(&rtac_voice_apr_mutex);
+	return bytes_returned;
+}
+
+
+
+static long rtac_ioctl(struct file *f,
+		unsigned int cmd, unsigned long arg)
+{
+	s32 result = 0;
+	pr_debug("%s\n", __func__);
+
+	if (arg == 0) {
+		pr_err("%s: No data sent to driver!\n", __func__);
+		result = -EFAULT;
+		goto done;
+	}
+
+	switch (cmd) {
+	case AUDIO_GET_RTAC_ADM_INFO:
+		if (copy_to_user((void *)arg, &rtac_adm_data,
+						sizeof(rtac_adm_data)))
+			pr_err("%s: Could not copy to userspace!\n", __func__);
+		else
+			result = sizeof(rtac_adm_data);
+		break;
+	case AUDIO_GET_RTAC_VOICE_INFO:
+		if (copy_to_user((void *)arg, &rtac_voice_data,
+						sizeof(rtac_voice_data)))
+			pr_err("%s: Could not copy to userspace!\n", __func__);
+		else
+			result = sizeof(rtac_voice_data);
+		break;
+	case AUDIO_GET_RTAC_ADM_CAL:
+		result = send_adm_apr((void *)arg, ADM_CMD_GET_PARAMS);
+		break;
+	case AUDIO_SET_RTAC_ADM_CAL:
+		result = send_adm_apr((void *)arg, ADM_CMD_SET_PARAMS);
+		break;
+	case AUDIO_GET_RTAC_ASM_CAL:
+		result = send_rtac_asm_apr((void *)arg,
+			ASM_STREAM_CMD_GET_PP_PARAMS);
+		break;
+	case AUDIO_SET_RTAC_ASM_CAL:
+		result = send_rtac_asm_apr((void *)arg,
+			ASM_STREAM_CMD_SET_PP_PARAMS);
+		break;
+	case AUDIO_GET_RTAC_CVS_CAL:
+		result = send_voice_apr(RTAC_CVS, (void *)arg,
+			VOICE_CMD_GET_PARAM);
+		break;
+	case AUDIO_SET_RTAC_CVS_CAL:
+		result = send_voice_apr(RTAC_CVS, (void *)arg,
+			VOICE_CMD_SET_PARAM);
+		break;
+	case AUDIO_GET_RTAC_CVP_CAL:
+		result = send_voice_apr(RTAC_CVP, (void *)arg,
+			VOICE_CMD_GET_PARAM);
+		break;
+	case AUDIO_SET_RTAC_CVP_CAL:
+		result = send_voice_apr(RTAC_CVP, (void *)arg,
+			VOICE_CMD_SET_PARAM);
+		break;
+	default:
+		pr_err("%s: Invalid IOCTL, command = %d!\n",
+		       __func__, cmd);
+	}
+done:
+	return result;
+}
+
+
+static const struct file_operations rtac_fops = {
+	.owner = THIS_MODULE,
+	.open = rtac_open,
+	.release = rtac_release,
+	.unlocked_ioctl = rtac_ioctl,
+};
+
+struct miscdevice rtac_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_rtac",
+	.fops	= &rtac_fops,
+};
+
+static int __init rtac_init(void)
+{
+	int i = 0;
+	pr_debug("%s\n", __func__);
+
+	/* ADM */
+	memset(&rtac_adm_data, 0, sizeof(rtac_adm_data));
+	rtac_adm_apr_data.apr_handle = NULL;
+	atomic_set(&rtac_adm_apr_data.cmd_state, 0);
+	init_waitqueue_head(&rtac_adm_apr_data.cmd_wait);
+	mutex_init(&rtac_adm_mutex);
+	mutex_init(&rtac_adm_apr_mutex);
+
+	rtac_adm_buffer = kmalloc(RTAC_BUF_SIZE, GFP_KERNEL);
+	if (rtac_adm_buffer == NULL) {
+		pr_err("%s: Could not allocate payload of size = %d\n",
+			__func__, RTAC_BUF_SIZE);
+		goto nomem;
+	}
+
+	/* ASM */
+	for (i = 0; i < SESSION_MAX+1; i++) {
+		rtac_asm_apr_data[i].apr_handle = NULL;
+		atomic_set(&rtac_asm_apr_data[i].cmd_state, 0);
+		init_waitqueue_head(&rtac_asm_apr_data[i].cmd_wait);
+	}
+	mutex_init(&rtac_asm_apr_mutex);
+
+	rtac_asm_buffer = kmalloc(RTAC_BUF_SIZE, GFP_KERNEL);
+	if (rtac_asm_buffer == NULL) {
+		pr_err("%s: Could not allocate payload of size = %d\n",
+			__func__, RTAC_BUF_SIZE);
+		goto nomem;
+	}
+
+	/* Voice */
+	memset(&rtac_voice_data, 0, sizeof(rtac_voice_data));
+	for (i = 0; i < RTAC_VOICE_MODES; i++) {
+		rtac_voice_apr_data[i].apr_handle = NULL;
+		atomic_set(&rtac_voice_apr_data[i].cmd_state, 0);
+		init_waitqueue_head(&rtac_voice_apr_data[i].cmd_wait);
+	}
+	mutex_init(&rtac_voice_mutex);
+	mutex_init(&rtac_voice_apr_mutex);
+
+	rtac_voice_buffer = kmalloc(RTAC_BUF_SIZE, GFP_KERNEL);
+	if (rtac_voice_buffer == NULL) {
+		pr_err("%s: Could not allocate payload of size = %d\n",
+			__func__, RTAC_BUF_SIZE);
+		goto nomem;
+	}
+
+	return misc_register(&rtac_misc);
+nomem:
+	return -ENOMEM;
+}
+
+module_init(rtac_init);
+
+MODULE_DESCRIPTION("MSM 8x60 Real-Time Audio Calibration driver");
+MODULE_LICENSE("GPL v2");
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.c b/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.c
new file mode 100644
index 0000000..f75af16
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.c
@@ -0,0 +1,382 @@
+/* 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
+ * 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <mach/clk.h>
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+#include <sound/apr_audio.h>
+#include <sound/q6afe.h>
+#include "snddev_ecodec.h"
+
+#define ECODEC_SAMPLE_RATE 8000
+
+/* Context for each external codec device */
+struct snddev_ecodec_state {
+	struct snddev_ecodec_data *data;
+	u32 sample_rate;
+};
+
+/* Global state for the driver */
+struct snddev_ecodec_drv_state {
+	struct mutex dev_lock;
+	int ref_cnt;		/* ensure one rx device at a time */
+	struct clk *ecodec_clk;
+};
+
+static struct snddev_ecodec_drv_state snddev_ecodec_drv;
+
+struct aux_pcm_state {
+	unsigned int dout;
+	unsigned int din;
+	unsigned int syncout;
+	unsigned int clkin_a;
+};
+
+static struct aux_pcm_state the_aux_pcm_state;
+
+static int aux_pcm_gpios_request(void)
+{
+	int rc = 0;
+
+	pr_debug("%s\n", __func__);
+	rc = gpio_request(the_aux_pcm_state.dout, "AUX PCM DOUT");
+	if (rc < 0) {
+		pr_err("%s: GPIO request for AUX PCM DOUT failed\n", __func__);
+		return rc;
+	}
+
+	rc = gpio_request(the_aux_pcm_state.din, "AUX PCM DIN");
+	if (rc < 0) {
+		pr_err("%s: GPIO request for AUX PCM DIN failed\n", __func__);
+		gpio_free(the_aux_pcm_state.dout);
+		return rc;
+	}
+
+	rc = gpio_request(the_aux_pcm_state.syncout, "AUX PCM SYNC OUT");
+	if (rc < 0) {
+		pr_err("%s: GPIO request for AUX PCM SYNC OUT failed\n",
+				__func__);
+		gpio_free(the_aux_pcm_state.dout);
+		gpio_free(the_aux_pcm_state.din);
+		return rc;
+	}
+
+	rc = gpio_request(the_aux_pcm_state.clkin_a, "AUX PCM CLKIN A");
+	if (rc < 0) {
+		pr_err("%s: GPIO request for AUX PCM CLKIN A failed\n",
+				__func__);
+		gpio_free(the_aux_pcm_state.dout);
+		gpio_free(the_aux_pcm_state.din);
+		gpio_free(the_aux_pcm_state.syncout);
+		return rc;
+	}
+
+	return rc;
+}
+
+static void aux_pcm_gpios_free(void)
+{
+	pr_debug("%s\n", __func__);
+	gpio_free(the_aux_pcm_state.dout);
+	gpio_free(the_aux_pcm_state.din);
+	gpio_free(the_aux_pcm_state.syncout);
+	gpio_free(the_aux_pcm_state.clkin_a);
+}
+
+static int get_aux_pcm_gpios(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct resource *res;
+
+	/* Claim all of the GPIOs. */
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO, "aux_pcm_dout");
+	if (!res) {
+		pr_err("%s: failed to get gpio AUX PCM DOUT\n", __func__);
+		return -ENODEV;
+	}
+
+	the_aux_pcm_state.dout = res->start;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO, "aux_pcm_din");
+	if (!res) {
+		pr_err("%s: failed to get gpio AUX PCM DIN\n", __func__);
+		return -ENODEV;
+	}
+
+	the_aux_pcm_state.din = res->start;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO,
+					   "aux_pcm_syncout");
+	if (!res) {
+		pr_err("%s: failed to get gpio AUX PCM SYNC OUT\n", __func__);
+		return -ENODEV;
+	}
+
+	the_aux_pcm_state.syncout = res->start;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO,
+					   "aux_pcm_clkin_a");
+	if (!res) {
+		pr_err("%s: failed to get gpio AUX PCM CLKIN A\n", __func__);
+		return -ENODEV;
+	}
+
+	the_aux_pcm_state.clkin_a = res->start;
+
+	return rc;
+}
+
+static int aux_pcm_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+
+	rc = get_aux_pcm_gpios(pdev);
+	if (rc < 0) {
+		pr_err("%s: GPIO configuration failed\n", __func__);
+		return -ENODEV;
+	}
+	return rc;
+}
+
+static struct platform_driver aux_pcm_driver = {
+	.probe = aux_pcm_probe,
+	.driver = { .name = "msm_aux_pcm"}
+};
+
+static int snddev_ecodec_open(struct msm_snddev_info *dev_info)
+{
+	int rc;
+	struct snddev_ecodec_drv_state *drv = &snddev_ecodec_drv;
+	union afe_port_config afe_config;
+
+	pr_debug("%s\n", __func__);
+
+	mutex_lock(&drv->dev_lock);
+
+	if (dev_info->opened) {
+		pr_err("%s: ERROR: %s already opened\n", __func__,
+				dev_info->name);
+		mutex_unlock(&drv->dev_lock);
+		return -EBUSY;
+	}
+
+	if (drv->ref_cnt != 0) {
+		pr_debug("%s: opened %s\n", __func__, dev_info->name);
+		drv->ref_cnt++;
+		mutex_unlock(&drv->dev_lock);
+		return 0;
+	}
+
+	pr_info("%s: opening %s\n", __func__, dev_info->name);
+
+	rc = aux_pcm_gpios_request();
+	if (rc < 0) {
+		pr_err("%s: GPIO request failed\n", __func__);
+		return rc;
+	}
+
+	clk_reset(drv->ecodec_clk, CLK_RESET_ASSERT);
+
+	afe_config.pcm.mode = AFE_PCM_CFG_MODE_PCM;
+	afe_config.pcm.sync = AFE_PCM_CFG_SYNC_INT;
+	afe_config.pcm.frame = AFE_PCM_CFG_FRM_256BPF;
+	afe_config.pcm.quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD;
+	afe_config.pcm.slot = 0;
+	afe_config.pcm.data = AFE_PCM_CFG_CDATAOE_MASTER;
+
+	rc = afe_open(PCM_RX, &afe_config, ECODEC_SAMPLE_RATE);
+	if (rc < 0) {
+		pr_err("%s: afe open failed for PCM_RX\n", __func__);
+		goto err_rx_afe;
+	}
+
+	rc = afe_open(PCM_TX, &afe_config, ECODEC_SAMPLE_RATE);
+	if (rc < 0) {
+		pr_err("%s: afe open failed for PCM_TX\n", __func__);
+		goto err_tx_afe;
+	}
+
+	rc = clk_set_rate(drv->ecodec_clk, 2048000);
+	if (rc < 0) {
+		pr_err("%s: clk_set_rate failed\n", __func__);
+		goto err_clk;
+	}
+
+	clk_enable(drv->ecodec_clk);
+
+	clk_reset(drv->ecodec_clk, CLK_RESET_DEASSERT);
+
+	drv->ref_cnt++;
+	mutex_unlock(&drv->dev_lock);
+
+	return 0;
+
+err_clk:
+	afe_close(PCM_TX);
+err_tx_afe:
+	afe_close(PCM_RX);
+err_rx_afe:
+	aux_pcm_gpios_free();
+	mutex_unlock(&drv->dev_lock);
+	return -ENODEV;
+}
+
+int snddev_ecodec_close(struct msm_snddev_info *dev_info)
+{
+	struct snddev_ecodec_drv_state *drv = &snddev_ecodec_drv;
+
+	pr_debug("%s: closing %s\n", __func__, dev_info->name);
+
+	mutex_lock(&drv->dev_lock);
+
+	if (!dev_info->opened) {
+		pr_err("%s: ERROR: %s is not opened\n", __func__,
+				dev_info->name);
+		mutex_unlock(&drv->dev_lock);
+		return -EPERM;
+	}
+
+	drv->ref_cnt--;
+
+	if (drv->ref_cnt == 0) {
+
+		pr_info("%s: closing all devices\n", __func__);
+
+		clk_disable(drv->ecodec_clk);
+		aux_pcm_gpios_free();
+
+		afe_close(PCM_RX);
+		afe_close(PCM_TX);
+	}
+
+	mutex_unlock(&drv->dev_lock);
+
+	return 0;
+}
+
+int snddev_ecodec_set_freq(struct msm_snddev_info *dev_info, u32 rate)
+{
+	int rc = 0;
+
+	if (!dev_info) {
+		rc = -EINVAL;
+		goto error;
+	}
+	return ECODEC_SAMPLE_RATE;
+
+error:
+	return rc;
+}
+
+static int snddev_ecodec_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct snddev_ecodec_data *pdata;
+	struct msm_snddev_info *dev_info;
+	struct snddev_ecodec_state *ecodec;
+
+	if (!pdev || !pdev->dev.platform_data) {
+		printk(KERN_ALERT "Invalid caller\n");
+		rc = -1;
+		goto error;
+	}
+	pdata = pdev->dev.platform_data;
+
+	ecodec = kzalloc(sizeof(struct snddev_ecodec_state), GFP_KERNEL);
+	if (!ecodec) {
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	dev_info = kzalloc(sizeof(struct msm_snddev_info), GFP_KERNEL);
+	if (!dev_info) {
+		kfree(ecodec);
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	dev_info->name = pdata->name;
+	dev_info->copp_id = pdata->copp_id;
+	dev_info->private_data = (void *)ecodec;
+	dev_info->dev_ops.open = snddev_ecodec_open;
+	dev_info->dev_ops.close = snddev_ecodec_close;
+	dev_info->dev_ops.set_freq = snddev_ecodec_set_freq;
+	dev_info->dev_ops.enable_sidetone = NULL;
+	dev_info->capability = pdata->capability;
+	dev_info->opened = 0;
+
+	msm_snddev_register(dev_info);
+
+	ecodec->data = pdata;
+	ecodec->sample_rate = ECODEC_SAMPLE_RATE;	/* Default to 8KHz */
+error:
+	return rc;
+}
+
+struct platform_driver snddev_ecodec_driver = {
+	.probe = snddev_ecodec_probe,
+	.driver = {.name = "msm_snddev_ecodec"}
+};
+
+int __init snddev_ecodec_init(void)
+{
+	int rc = 0;
+	struct snddev_ecodec_drv_state *drv = &snddev_ecodec_drv;
+
+	mutex_init(&drv->dev_lock);
+	drv->ref_cnt = 0;
+
+	drv->ecodec_clk = clk_get_sys(NULL, "pcm_clk");
+	if (IS_ERR(drv->ecodec_clk)) {
+		pr_err("%s: could not get pcm_clk\n", __func__);
+		return PTR_ERR(drv->ecodec_clk);
+	}
+
+	rc = platform_driver_register(&aux_pcm_driver);
+	if (IS_ERR_VALUE(rc)) {
+		pr_err("%s: platform_driver_register for aux pcm failed\n",
+				__func__);
+		goto error_aux_pcm_platform_driver;
+	}
+
+	rc = platform_driver_register(&snddev_ecodec_driver);
+	if (IS_ERR_VALUE(rc)) {
+		pr_err("%s: platform_driver_register for ecodec failed\n",
+				__func__);
+		goto error_ecodec_platform_driver;
+	}
+
+	return 0;
+
+error_ecodec_platform_driver:
+	platform_driver_unregister(&aux_pcm_driver);
+error_aux_pcm_platform_driver:
+	clk_put(drv->ecodec_clk);
+
+	pr_err("%s: encounter error\n", __func__);
+	return -ENODEV;
+}
+
+device_initcall(snddev_ecodec_init);
+
+MODULE_DESCRIPTION("ECodec Sound Device driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.h b/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.h
new file mode 100644
index 0000000..b102de0
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.h
@@ -0,0 +1,26 @@
+/* Copyright (c) 2010, 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 __MACH_QDSP6V2_SNDDEV_ECODEC_H
+#define __MACH_QDSP6V2_SNDDEV_ECODEC_H
+#include <mach/qdsp5v2/audio_def.h>
+
+struct snddev_ecodec_data {
+	u32 capability; /* RX or TX */
+	const char *name;
+	u32 copp_id; /* audpp routing */
+	u8 channel_mode;
+	u32 conf_pcm_ctl_val;
+	u32 conf_aux_codec_intf;
+	u32 conf_data_format_padding_val;
+};
+#endif
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_hdmi.c b/arch/arm/mach-msm/qdsp6v2/snddev_hdmi.c
new file mode 100644
index 0000000..9b8346d
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_hdmi.c
@@ -0,0 +1,198 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <asm/uaccess.h>
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+#include <mach/debug_mm.h>
+#include <sound/q6afe.h>
+#include <sound/apr_audio.h>
+#include "snddev_hdmi.h"
+
+static DEFINE_MUTEX(snddev_hdmi_lock);
+static int snddev_hdmi_active;
+
+static int snddev_hdmi_open(struct msm_snddev_info *dev_info)
+{
+	int rc = 0;
+	union afe_port_config afe_config;
+	struct snddev_hdmi_data *snddev_hdmi_data;
+
+	if (!dev_info) {
+		pr_err("msm_snddev_info is null\n");
+		return -EINVAL;
+	}
+
+	snddev_hdmi_data = dev_info->private_data;
+
+	mutex_lock(&snddev_hdmi_lock);
+
+	if (snddev_hdmi_active) {
+		pr_err("HDMI snddev already active\n");
+		mutex_unlock(&snddev_hdmi_lock);
+		return -EBUSY;
+	}
+
+	if (snddev_hdmi_data->on_apps) {
+		snddev_hdmi_active = 1;
+		pr_debug("%s open done\n", dev_info->name);
+		mutex_unlock(&snddev_hdmi_lock);
+		return 0;
+	}
+
+	afe_config.hdmi.channel_mode = snddev_hdmi_data->channel_mode;
+	afe_config.hdmi.bitwidth = 16;
+	afe_config.hdmi.data_type = 0;
+	rc = afe_open(snddev_hdmi_data->copp_id, &afe_config,
+		dev_info->sample_rate);
+
+	if (rc < 0) {
+		pr_err("afe_open failed\n");
+		mutex_unlock(&snddev_hdmi_lock);
+		return -EINVAL;
+	}
+	snddev_hdmi_active = 1;
+
+	pr_debug("%s open done\n", dev_info->name);
+
+	mutex_unlock(&snddev_hdmi_lock);
+
+	return 0;
+}
+
+static int snddev_hdmi_close(struct msm_snddev_info *dev_info)
+{
+
+	struct snddev_hdmi_data *snddev_hdmi_data;
+
+	if (!dev_info) {
+		pr_err("msm_snddev_info is null\n");
+		return -EINVAL;
+	}
+
+	snddev_hdmi_data = dev_info->private_data;
+
+	if (!dev_info->opened) {
+		pr_err("calling close device with out opening the"
+		       " device\n");
+		return -EPERM;
+	}
+	mutex_lock(&snddev_hdmi_lock);
+
+	if (!snddev_hdmi_active) {
+		pr_err("HDMI snddev not active\n");
+		mutex_unlock(&snddev_hdmi_lock);
+		return -EPERM;
+	}
+	snddev_hdmi_active = 0;
+
+	if (snddev_hdmi_data->on_apps) {
+		pr_debug("%s Closed\n", dev_info->name);
+
+		mutex_unlock(&snddev_hdmi_lock);
+		return 0;
+	}
+
+
+	afe_close(HDMI_RX);
+
+	pr_debug("%s closed\n", dev_info->name);
+	mutex_unlock(&snddev_hdmi_lock);
+
+	return 0;
+}
+
+static int snddev_hdmi_set_freq(struct msm_snddev_info *dev_info, u32 req_freq)
+{
+	if (req_freq != 48000) {
+		pr_debug("Unsupported Frequency:%d\n", req_freq);
+		return -EINVAL;
+	}
+	return 48000;
+}
+
+static int snddev_hdmi_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct snddev_hdmi_data *pdata;
+	struct msm_snddev_info *dev_info;
+
+	if (!pdev || !pdev->dev.platform_data) {
+		printk(KERN_ALERT "Invalid caller\n");
+		return -ENODEV;
+	}
+
+	pdata = pdev->dev.platform_data;
+	if (!(pdata->capability & SNDDEV_CAP_RX)) {
+		pr_err("invalid device data either RX or TX\n");
+		return -ENODEV;
+	}
+
+	dev_info = kzalloc(sizeof(struct msm_snddev_info), GFP_KERNEL);
+	if (!dev_info) {
+		pr_err("unable to allocate memeory for msm_snddev_info\n");
+		return -ENOMEM;
+	}
+
+	dev_info->name = pdata->name;
+	dev_info->copp_id = pdata->copp_id;
+	dev_info->acdb_id = pdata->acdb_id;
+	dev_info->private_data = (void *)pdata;
+	dev_info->dev_ops.open = snddev_hdmi_open;
+	dev_info->dev_ops.close = snddev_hdmi_close;
+	dev_info->dev_ops.set_freq = snddev_hdmi_set_freq;
+	dev_info->capability = pdata->capability;
+	dev_info->opened = 0;
+	msm_snddev_register(dev_info);
+	dev_info->sample_rate = pdata->default_sample_rate;
+
+	pr_debug("probe done for %s\n", pdata->name);
+	return rc;
+}
+
+static struct platform_driver snddev_hdmi_driver = {
+	.probe = snddev_hdmi_probe,
+	.driver = {.name = "snddev_hdmi"}
+};
+
+static int __init snddev_hdmi_init(void)
+{
+	s32 rc;
+
+	rc = platform_driver_register(&snddev_hdmi_driver);
+	if (IS_ERR_VALUE(rc)) {
+
+		pr_err("platform_driver_register failed.\n");
+		goto error_platform_driver;
+	}
+
+	pr_debug("snddev_hdmi_init : done\n");
+
+	return 0;
+
+error_platform_driver:
+
+	pr_err("encounterd error\n");
+	return -ENODEV;
+}
+
+module_init(snddev_hdmi_init);
+
+MODULE_DESCRIPTION("HDMI Sound Device driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_hdmi.h b/arch/arm/mach-msm/qdsp6v2/snddev_hdmi.h
new file mode 100644
index 0000000..cc69033
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_hdmi.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __MACH_QDSP6_V2_SNDDEV_HDMI_H
+#define __MACH_QDSP6_V2_SNDDEV_HDMI_H
+
+struct snddev_hdmi_data {
+	u32 capability;		/* RX or TX */
+	const char *name;
+	u32 copp_id;		/* audpp routing */
+	u32 acdb_id;		/* Audio Cal purpose */
+	u8 channel_mode;
+	u32 default_sample_rate;
+	u32 on_apps;
+};
+#endif
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_icodec.c b/arch/arm/mach-msm/qdsp6v2/snddev_icodec.c
new file mode 100644
index 0000000..5d10779
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_icodec.c
@@ -0,0 +1,1113 @@
+/* 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
+ * 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/mfd/msm-adie-codec.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/wakelock.h>
+#include <linux/pmic8058-othc.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+#include <linux/moduleparam.h>
+#include <asm/uaccess.h>
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+#include <mach/qdsp6v2/audio_acdb.h>
+#include <mach/vreg.h>
+#include <mach/pmic.h>
+#include <mach/debug_mm.h>
+#include <sound/q6afe.h>
+#include <sound/apr_audio.h>
+#include "snddev_icodec.h"
+
+#define SNDDEV_ICODEC_PCM_SZ 32 /* 16 bit / sample stereo mode */
+#define SNDDEV_ICODEC_MUL_FACTOR 3 /* Multi by 8 Shift by 3  */
+#define SNDDEV_ICODEC_CLK_RATE(freq) \
+	(((freq) * (SNDDEV_ICODEC_PCM_SZ)) << (SNDDEV_ICODEC_MUL_FACTOR))
+#define SNDDEV_LOW_POWER_MODE 0
+#define SNDDEV_HIGH_POWER_MODE 1
+/* Voltage required for S4 in microVolts, 2.2V or 2200000microvolts */
+#define SNDDEV_VREG_8058_S4_VOLTAGE (2200000)
+/* Load Current required for S4 in microAmps,
+   36mA - 56mA */
+#define SNDDEV_VREG_LOW_POWER_LOAD (36000)
+#define SNDDEV_VREG_HIGH_POWER_LOAD (56000)
+
+bool msm_codec_i2s_slave_mode;
+
+/* Context for each internal codec sound device */
+struct snddev_icodec_state {
+	struct snddev_icodec_data *data;
+	struct adie_codec_path *adie_path;
+	u32 sample_rate;
+	u32 enabled;
+};
+
+/* Global state for the driver */
+struct snddev_icodec_drv_state {
+	struct mutex rx_lock;
+	struct mutex lb_lock;
+	struct mutex tx_lock;
+	u32 rx_active; /* ensure one rx device at a time */
+	u32 tx_active; /* ensure one tx device at a time */
+	struct clk *rx_osrclk;
+	struct clk *rx_bitclk;
+	struct clk *tx_osrclk;
+	struct clk *tx_bitclk;
+
+	struct wake_lock rx_idlelock;
+	struct wake_lock tx_idlelock;
+
+	/* handle to pmic8058 regulator smps4 */
+	struct regulator *snddev_vreg;
+};
+
+static struct snddev_icodec_drv_state snddev_icodec_drv;
+
+struct regulator *vreg_init(void)
+{
+	int rc;
+	struct regulator *vreg_ptr;
+
+	vreg_ptr = regulator_get(NULL, "8058_s4");
+	if (IS_ERR(vreg_ptr)) {
+		pr_err("%s: regulator_get 8058_s4 failed\n", __func__);
+		return NULL;
+	}
+
+	rc = regulator_set_voltage(vreg_ptr, SNDDEV_VREG_8058_S4_VOLTAGE,
+				SNDDEV_VREG_8058_S4_VOLTAGE);
+	if (rc == 0)
+		return vreg_ptr;
+	else
+		return NULL;
+}
+
+static void vreg_deinit(struct regulator *vreg)
+{
+	regulator_put(vreg);
+}
+
+static void vreg_mode_vote(struct regulator *vreg, int enable, int mode)
+{
+	int rc;
+	if (enable) {
+		rc = regulator_enable(vreg);
+		if (rc != 0)
+			pr_err("%s:Enabling regulator failed\n", __func__);
+		else {
+			if (mode)
+				regulator_set_optimum_mode(vreg,
+						SNDDEV_VREG_HIGH_POWER_LOAD);
+			else
+				regulator_set_optimum_mode(vreg,
+						SNDDEV_VREG_LOW_POWER_LOAD);
+		}
+	} else {
+		rc = regulator_disable(vreg);
+		if (rc != 0)
+			pr_err("%s:Disabling regulator failed\n", __func__);
+	}
+}
+
+struct msm_cdcclk_ctl_state {
+	unsigned int rx_mclk;
+	unsigned int rx_mclk_requested;
+	unsigned int tx_mclk;
+	unsigned int tx_mclk_requested;
+};
+
+static struct msm_cdcclk_ctl_state the_msm_cdcclk_ctl_state;
+
+static int msm_snddev_rx_mclk_request(void)
+{
+	int rc = 0;
+
+	rc = gpio_request(the_msm_cdcclk_ctl_state.rx_mclk,
+		"MSM_SNDDEV_RX_MCLK");
+	if (rc < 0) {
+		pr_err("%s: GPIO request for MSM SNDDEV RX failed\n", __func__);
+		return rc;
+	}
+	the_msm_cdcclk_ctl_state.rx_mclk_requested = 1;
+	return rc;
+}
+static int msm_snddev_tx_mclk_request(void)
+{
+	int rc = 0;
+
+	rc = gpio_request(the_msm_cdcclk_ctl_state.tx_mclk,
+		"MSM_SNDDEV_TX_MCLK");
+	if (rc < 0) {
+		pr_err("%s: GPIO request for MSM SNDDEV TX failed\n", __func__);
+		return rc;
+	}
+	the_msm_cdcclk_ctl_state.tx_mclk_requested = 1;
+	return rc;
+}
+static void msm_snddev_rx_mclk_free(void)
+{
+	if (the_msm_cdcclk_ctl_state.rx_mclk_requested) {
+		gpio_free(the_msm_cdcclk_ctl_state.rx_mclk);
+		the_msm_cdcclk_ctl_state.rx_mclk_requested = 0;
+	}
+}
+static void msm_snddev_tx_mclk_free(void)
+{
+	if (the_msm_cdcclk_ctl_state.tx_mclk_requested) {
+		gpio_free(the_msm_cdcclk_ctl_state.tx_mclk);
+		the_msm_cdcclk_ctl_state.tx_mclk_requested = 0;
+	}
+}
+static int get_msm_cdcclk_ctl_gpios(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct resource *res;
+
+	/* Claim all of the GPIOs. */
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO,
+			"msm_snddev_rx_mclk");
+	if (!res) {
+		pr_err("%s: failed to get gpio MSM SNDDEV RX\n", __func__);
+		return -ENODEV;
+	}
+	the_msm_cdcclk_ctl_state.rx_mclk = res->start;
+	the_msm_cdcclk_ctl_state.rx_mclk_requested = 0;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO,
+			"msm_snddev_tx_mclk");
+	if (!res) {
+		pr_err("%s: failed to get gpio MSM SNDDEV TX\n", __func__);
+		return -ENODEV;
+	}
+	the_msm_cdcclk_ctl_state.tx_mclk = res->start;
+	the_msm_cdcclk_ctl_state.tx_mclk_requested = 0;
+
+	return rc;
+}
+static int msm_cdcclk_ctl_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+
+	rc = get_msm_cdcclk_ctl_gpios(pdev);
+	if (rc < 0) {
+		pr_err("%s: GPIO configuration failed\n", __func__);
+		return -ENODEV;
+	}
+	return rc;
+}
+static struct platform_driver msm_cdcclk_ctl_driver = {
+	.probe = msm_cdcclk_ctl_probe,
+	.driver = { .name = "msm_cdcclk_ctl"}
+};
+
+static int snddev_icodec_open_lb(struct snddev_icodec_state *icodec)
+{
+	int trc;
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
+
+	/* Voting for low power is ok here as all use cases are
+	 * supported in low power mode.
+	 */
+	if (drv->snddev_vreg)
+		vreg_mode_vote(drv->snddev_vreg, 1,
+					SNDDEV_LOW_POWER_MODE);
+
+	if (icodec->data->voltage_on)
+		icodec->data->voltage_on();
+
+	trc = adie_codec_open(icodec->data->profile, &icodec->adie_path);
+	if (IS_ERR_VALUE(trc))
+		pr_err("%s: adie codec open failed\n", __func__);
+	else
+		adie_codec_setpath(icodec->adie_path,
+					icodec->sample_rate, 256);
+
+	if (icodec->adie_path)
+		adie_codec_proceed_stage(icodec->adie_path,
+					ADIE_CODEC_DIGITAL_ANALOG_READY);
+
+	if (icodec->data->pamp_on)
+		icodec->data->pamp_on();
+
+	icodec->enabled = 1;
+
+	return 0;
+}
+static int initialize_msm_icodec_gpios(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct resource *res;
+	int i = 0;
+	int *reg_defaults = pdev->dev.platform_data;
+
+	while ((res = platform_get_resource(pdev, IORESOURCE_IO, i))) {
+		rc = gpio_request(res->start, res->name);
+		if (rc) {
+			pr_err("%s: icodec gpio %d request failed\n", __func__,
+				res->start);
+			goto err;
+		} else {
+			/* This platform data structure only works if all gpio
+			 * resources are to be used only in output mode.
+			 * If gpio resources are added which are to be used in
+			 * input mode, then the platform data structure will
+			 * have to be changed.
+			 */
+
+			gpio_direction_output(res->start, reg_defaults[i]);
+			gpio_free(res->start);
+		}
+		i++;
+	}
+err:
+	return rc;
+}
+static int msm_icodec_gpio_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+
+	rc = initialize_msm_icodec_gpios(pdev);
+	if (rc < 0) {
+		pr_err("%s: GPIO configuration failed\n", __func__);
+		return -ENODEV;
+	}
+	return rc;
+}
+static struct platform_driver msm_icodec_gpio_driver = {
+	.probe = msm_icodec_gpio_probe,
+	.driver = { .name = "msm_icodec_gpio"}
+};
+
+static int snddev_icodec_open_rx(struct snddev_icodec_state *icodec)
+{
+	int trc;
+	int afe_channel_mode;
+	union afe_port_config afe_config;
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
+
+	wake_lock(&drv->rx_idlelock);
+
+	if (drv->snddev_vreg) {
+		if (!strcmp(icodec->data->name, "headset_stereo_rx"))
+			vreg_mode_vote(drv->snddev_vreg, 1,
+					SNDDEV_LOW_POWER_MODE);
+		else
+			vreg_mode_vote(drv->snddev_vreg, 1,
+					SNDDEV_HIGH_POWER_MODE);
+	}
+	msm_snddev_rx_mclk_request();
+
+	drv->rx_osrclk = clk_get_sys(NULL, "i2s_spkr_osr_clk");
+	if (IS_ERR(drv->rx_osrclk))
+		pr_err("%s master clock Error\n", __func__);
+
+	trc =  clk_set_rate(drv->rx_osrclk,
+			SNDDEV_ICODEC_CLK_RATE(icodec->sample_rate));
+	if (IS_ERR_VALUE(trc)) {
+		pr_err("ERROR setting m clock1\n");
+		goto error_invalid_freq;
+	}
+
+	clk_enable(drv->rx_osrclk);
+	drv->rx_bitclk = clk_get_sys(NULL, "i2s_spkr_bit_clk");
+	if (IS_ERR(drv->rx_bitclk))
+		pr_err("%s clock Error\n", __func__);
+
+	/* Master clock = Sample Rate * OSR rate bit clock
+	 * OSR Rate bit clock = bit/sample * channel master
+	 * clock / bit clock = divider value = 8
+	 */
+	if (msm_codec_i2s_slave_mode) {
+		pr_info("%s: configuring bit clock for slave mode\n",
+				__func__);
+		trc =  clk_set_rate(drv->rx_bitclk, 0);
+	} else
+		trc =  clk_set_rate(drv->rx_bitclk, 8);
+
+	if (IS_ERR_VALUE(trc)) {
+		pr_err("ERROR setting m clock1\n");
+		goto error_adie;
+	}
+	clk_enable(drv->rx_bitclk);
+
+	if (icodec->data->voltage_on)
+		icodec->data->voltage_on();
+
+	/* Configure ADIE */
+	trc = adie_codec_open(icodec->data->profile, &icodec->adie_path);
+	if (IS_ERR_VALUE(trc))
+		pr_err("%s: adie codec open failed\n", __func__);
+	else
+		adie_codec_setpath(icodec->adie_path,
+					icodec->sample_rate, 256);
+	/* OSR default to 256, can be changed for power optimization
+	 * If OSR is to be changed, need clock API for setting the divider
+	 */
+
+	switch (icodec->data->channel_mode) {
+	case 2:
+		afe_channel_mode = MSM_AFE_STEREO;
+		break;
+	case 1:
+	default:
+		afe_channel_mode = MSM_AFE_MONO;
+		break;
+	}
+	afe_config.mi2s.channel = afe_channel_mode;
+	afe_config.mi2s.bitwidth = 16;
+	afe_config.mi2s.line = 1;
+	afe_config.mi2s.format = MSM_AFE_I2S_FORMAT_LPCM;
+	if (msm_codec_i2s_slave_mode)
+		afe_config.mi2s.ws = 0;
+	else
+		afe_config.mi2s.ws = 1;
+
+	trc = afe_open(icodec->data->copp_id, &afe_config, icodec->sample_rate);
+
+	if (trc < 0)
+		pr_err("%s: afe open failed, trc = %d\n", __func__, trc);
+
+	/* Enable ADIE */
+	if (icodec->adie_path) {
+		adie_codec_proceed_stage(icodec->adie_path,
+					ADIE_CODEC_DIGITAL_READY);
+		adie_codec_proceed_stage(icodec->adie_path,
+					ADIE_CODEC_DIGITAL_ANALOG_READY);
+	}
+
+	if (msm_codec_i2s_slave_mode)
+		adie_codec_set_master_mode(icodec->adie_path, 1);
+	else
+		adie_codec_set_master_mode(icodec->adie_path, 0);
+
+	/* Enable power amplifier */
+	if (icodec->data->pamp_on) {
+		if (icodec->data->pamp_on()) {
+			pr_err("%s: Error turning on rx power\n", __func__);
+			goto error_pamp;
+		}
+	}
+
+	icodec->enabled = 1;
+
+	wake_unlock(&drv->rx_idlelock);
+	return 0;
+
+error_pamp:
+error_adie:
+	clk_disable(drv->rx_osrclk);
+error_invalid_freq:
+
+	pr_err("%s: encounter error\n", __func__);
+
+	wake_unlock(&drv->rx_idlelock);
+	return -ENODEV;
+}
+
+static int snddev_icodec_open_tx(struct snddev_icodec_state *icodec)
+{
+	int trc;
+	int afe_channel_mode;
+	union afe_port_config afe_config;
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;;
+
+	wake_lock(&drv->tx_idlelock);
+
+	if (drv->snddev_vreg)
+		vreg_mode_vote(drv->snddev_vreg, 1, SNDDEV_HIGH_POWER_MODE);
+
+	/* Reuse pamp_on for TX platform-specific setup  */
+	if (icodec->data->pamp_on) {
+		if (icodec->data->pamp_on()) {
+			pr_err("%s: Error turning on tx power\n", __func__);
+			goto error_pamp;
+		}
+	}
+
+	msm_snddev_tx_mclk_request();
+
+	drv->tx_osrclk = clk_get_sys(NULL, "i2s_mic_osr_clk");
+	if (IS_ERR(drv->tx_osrclk))
+		pr_err("%s master clock Error\n", __func__);
+
+	trc =  clk_set_rate(drv->tx_osrclk,
+			SNDDEV_ICODEC_CLK_RATE(icodec->sample_rate));
+	if (IS_ERR_VALUE(trc)) {
+		pr_err("ERROR setting m clock1\n");
+		goto error_invalid_freq;
+	}
+
+	clk_enable(drv->tx_osrclk);
+	drv->tx_bitclk = clk_get_sys(NULL, "i2s_mic_bit_clk");
+	if (IS_ERR(drv->tx_bitclk))
+		pr_err("%s clock Error\n", __func__);
+
+	/* Master clock = Sample Rate * OSR rate bit clock
+	 * OSR Rate bit clock = bit/sample * channel master
+	 * clock / bit clock = divider value = 8
+	 */
+	if (msm_codec_i2s_slave_mode) {
+		pr_info("%s: configuring bit clock for slave mode\n",
+				__func__);
+		trc =  clk_set_rate(drv->tx_bitclk, 0);
+	} else
+		trc =  clk_set_rate(drv->tx_bitclk, 8);
+
+	clk_enable(drv->tx_bitclk);
+
+	/* Enable ADIE */
+	trc = adie_codec_open(icodec->data->profile, &icodec->adie_path);
+	if (IS_ERR_VALUE(trc))
+		pr_err("%s: adie codec open failed\n", __func__);
+	else
+		adie_codec_setpath(icodec->adie_path,
+					icodec->sample_rate, 256);
+
+	switch (icodec->data->channel_mode) {
+	case 2:
+		afe_channel_mode = MSM_AFE_STEREO;
+		break;
+	case 1:
+	default:
+		afe_channel_mode = MSM_AFE_MONO;
+		break;
+	}
+	afe_config.mi2s.channel = afe_channel_mode;
+	afe_config.mi2s.bitwidth = 16;
+	afe_config.mi2s.line = 1;
+	afe_config.mi2s.format = MSM_AFE_I2S_FORMAT_LPCM;
+	if (msm_codec_i2s_slave_mode)
+		afe_config.mi2s.ws = 0;
+	else
+		afe_config.mi2s.ws = 1;
+
+	trc = afe_open(icodec->data->copp_id, &afe_config, icodec->sample_rate);
+
+	if (icodec->adie_path) {
+		adie_codec_proceed_stage(icodec->adie_path,
+					ADIE_CODEC_DIGITAL_READY);
+		adie_codec_proceed_stage(icodec->adie_path,
+					ADIE_CODEC_DIGITAL_ANALOG_READY);
+	}
+
+	if (msm_codec_i2s_slave_mode)
+		adie_codec_set_master_mode(icodec->adie_path, 1);
+	else
+		adie_codec_set_master_mode(icodec->adie_path, 0);
+
+	icodec->enabled = 1;
+
+	wake_unlock(&drv->tx_idlelock);
+	return 0;
+
+error_invalid_freq:
+
+	if (icodec->data->pamp_off)
+		icodec->data->pamp_off();
+
+	pr_err("%s: encounter error\n", __func__);
+error_pamp:
+	wake_unlock(&drv->tx_idlelock);
+	return -ENODEV;
+}
+
+static int snddev_icodec_close_lb(struct snddev_icodec_state *icodec)
+{
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
+
+	/* Disable power amplifier */
+	if (icodec->data->pamp_off)
+		icodec->data->pamp_off();
+
+	if (drv->snddev_vreg)
+		vreg_mode_vote(drv->snddev_vreg, 0, SNDDEV_LOW_POWER_MODE);
+
+	if (icodec->adie_path) {
+		adie_codec_proceed_stage(icodec->adie_path,
+			ADIE_CODEC_DIGITAL_OFF);
+		adie_codec_close(icodec->adie_path);
+		icodec->adie_path = NULL;
+	}
+
+	if (icodec->data->voltage_off)
+		icodec->data->voltage_off();
+
+	return 0;
+}
+
+static int snddev_icodec_close_rx(struct snddev_icodec_state *icodec)
+{
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
+
+	wake_lock(&drv->rx_idlelock);
+
+	if (drv->snddev_vreg)
+		vreg_mode_vote(drv->snddev_vreg, 0, SNDDEV_HIGH_POWER_MODE);
+
+	/* Disable power amplifier */
+	if (icodec->data->pamp_off)
+		icodec->data->pamp_off();
+
+	/* Disable ADIE */
+	if (icodec->adie_path) {
+		adie_codec_proceed_stage(icodec->adie_path,
+			ADIE_CODEC_DIGITAL_OFF);
+		adie_codec_close(icodec->adie_path);
+		icodec->adie_path = NULL;
+	}
+
+	afe_close(icodec->data->copp_id);
+
+	if (icodec->data->voltage_off)
+		icodec->data->voltage_off();
+
+	clk_disable(drv->rx_bitclk);
+	clk_disable(drv->rx_osrclk);
+
+	msm_snddev_rx_mclk_free();
+
+	icodec->enabled = 0;
+
+	wake_unlock(&drv->rx_idlelock);
+	return 0;
+}
+
+static int snddev_icodec_close_tx(struct snddev_icodec_state *icodec)
+{
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
+
+	wake_lock(&drv->tx_idlelock);
+
+	if (drv->snddev_vreg)
+		vreg_mode_vote(drv->snddev_vreg, 0, SNDDEV_HIGH_POWER_MODE);
+
+	/* Disable ADIE */
+	if (icodec->adie_path) {
+		adie_codec_proceed_stage(icodec->adie_path,
+					ADIE_CODEC_DIGITAL_OFF);
+		adie_codec_close(icodec->adie_path);
+		icodec->adie_path = NULL;
+	}
+
+	afe_close(icodec->data->copp_id);
+
+	clk_disable(drv->tx_bitclk);
+	clk_disable(drv->tx_osrclk);
+
+	msm_snddev_tx_mclk_free();
+
+	/* Reuse pamp_off for TX platform-specific setup  */
+	if (icodec->data->pamp_off)
+		icodec->data->pamp_off();
+
+	icodec->enabled = 0;
+
+	wake_unlock(&drv->tx_idlelock);
+	return 0;
+}
+
+static int snddev_icodec_set_device_volume_impl(
+		struct msm_snddev_info *dev_info, u32 volume)
+{
+	struct snddev_icodec_state *icodec;
+
+	int rc = 0;
+
+	icodec = dev_info->private_data;
+
+	if (icodec->data->dev_vol_type & SNDDEV_DEV_VOL_DIGITAL) {
+
+		rc = adie_codec_set_device_digital_volume(icodec->adie_path,
+				icodec->data->channel_mode, volume);
+		if (rc < 0) {
+			pr_err("%s: unable to set_device_digital_volume for"
+				"%s volume in percentage = %u\n",
+				__func__, dev_info->name, volume);
+			return rc;
+		}
+
+	} else if (icodec->data->dev_vol_type & SNDDEV_DEV_VOL_ANALOG) {
+		rc = adie_codec_set_device_analog_volume(icodec->adie_path,
+				icodec->data->channel_mode, volume);
+		if (rc < 0) {
+			pr_err("%s: unable to set_device_analog_volume for"
+				"%s volume in percentage = %u\n",
+				__func__, dev_info->name, volume);
+			return rc;
+		}
+	} else {
+		pr_err("%s: Invalid device volume control\n", __func__);
+		return -EPERM;
+	}
+	return rc;
+}
+
+static int snddev_icodec_open(struct msm_snddev_info *dev_info)
+{
+	int rc = 0;
+	struct snddev_icodec_state *icodec;
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
+
+	if (!dev_info) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	icodec = dev_info->private_data;
+
+	if (icodec->data->capability & SNDDEV_CAP_RX) {
+		mutex_lock(&drv->rx_lock);
+		if (drv->rx_active) {
+			mutex_unlock(&drv->rx_lock);
+			pr_err("%s: rx_active is set, return EBUSY\n",
+				__func__);
+			rc = -EBUSY;
+			goto error;
+		}
+		rc = snddev_icodec_open_rx(icodec);
+
+		if (!IS_ERR_VALUE(rc)) {
+			if ((icodec->data->dev_vol_type & (
+				SNDDEV_DEV_VOL_DIGITAL |
+				SNDDEV_DEV_VOL_ANALOG)))
+				rc = snddev_icodec_set_device_volume_impl(
+						dev_info, dev_info->dev_volume);
+			if (!IS_ERR_VALUE(rc))
+				drv->rx_active = 1;
+			else
+				pr_err("%s: set_device_volume_impl"
+					" error(rx) = %d\n", __func__, rc);
+		}
+		mutex_unlock(&drv->rx_lock);
+	} else if (icodec->data->capability & SNDDEV_CAP_LB) {
+		mutex_lock(&drv->lb_lock);
+		rc = snddev_icodec_open_lb(icodec);
+
+		if (!IS_ERR_VALUE(rc)) {
+			if ((icodec->data->dev_vol_type & (
+				SNDDEV_DEV_VOL_DIGITAL |
+				SNDDEV_DEV_VOL_ANALOG)))
+				rc = snddev_icodec_set_device_volume_impl(
+						dev_info, dev_info->dev_volume);
+		}
+
+		mutex_unlock(&drv->lb_lock);
+	} else {
+		mutex_lock(&drv->tx_lock);
+		if (drv->tx_active) {
+			mutex_unlock(&drv->tx_lock);
+			pr_err("%s: tx_active is set, return EBUSY\n",
+				__func__);
+			rc = -EBUSY;
+			goto error;
+		}
+		rc = snddev_icodec_open_tx(icodec);
+
+		if (!IS_ERR_VALUE(rc)) {
+			if ((icodec->data->dev_vol_type & (
+				SNDDEV_DEV_VOL_DIGITAL |
+				SNDDEV_DEV_VOL_ANALOG)))
+				rc = snddev_icodec_set_device_volume_impl(
+						dev_info, dev_info->dev_volume);
+			if (!IS_ERR_VALUE(rc))
+				drv->tx_active = 1;
+			else
+				pr_err("%s: set_device_volume_impl"
+					" error(tx) = %d\n", __func__, rc);
+		}
+		mutex_unlock(&drv->tx_lock);
+	}
+error:
+	return rc;
+}
+
+static int snddev_icodec_close(struct msm_snddev_info *dev_info)
+{
+	int rc = 0;
+	struct snddev_icodec_state *icodec;
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
+	if (!dev_info) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	icodec = dev_info->private_data;
+
+	if (icodec->data->capability & SNDDEV_CAP_RX) {
+		mutex_lock(&drv->rx_lock);
+		if (!drv->rx_active) {
+			mutex_unlock(&drv->rx_lock);
+			pr_err("%s: rx_active not set, return\n", __func__);
+			rc = -EPERM;
+			goto error;
+		}
+		rc = snddev_icodec_close_rx(icodec);
+		if (!IS_ERR_VALUE(rc))
+			drv->rx_active = 0;
+		else
+			pr_err("%s: close rx failed, rc = %d\n", __func__, rc);
+		mutex_unlock(&drv->rx_lock);
+	} else if (icodec->data->capability & SNDDEV_CAP_LB) {
+		mutex_lock(&drv->lb_lock);
+		rc = snddev_icodec_close_lb(icodec);
+		mutex_unlock(&drv->lb_lock);
+	} else {
+		mutex_lock(&drv->tx_lock);
+		if (!drv->tx_active) {
+			mutex_unlock(&drv->tx_lock);
+			pr_err("%s: tx_active not set, return\n", __func__);
+			rc = -EPERM;
+			goto error;
+		}
+		rc = snddev_icodec_close_tx(icodec);
+		if (!IS_ERR_VALUE(rc))
+			drv->tx_active = 0;
+		else
+			pr_err("%s: close tx failed, rc = %d\n", __func__, rc);
+		mutex_unlock(&drv->tx_lock);
+	}
+
+error:
+	return rc;
+}
+
+static int snddev_icodec_check_freq(u32 req_freq)
+{
+	int rc = -EINVAL;
+
+	if ((req_freq != 0) && (req_freq >= 8000) && (req_freq <= 48000)) {
+		if ((req_freq == 8000) || (req_freq == 11025) ||
+			(req_freq == 12000) || (req_freq == 16000) ||
+			(req_freq == 22050) || (req_freq == 24000) ||
+			(req_freq == 32000) || (req_freq == 44100) ||
+			(req_freq == 48000)) {
+				rc = 0;
+		} else
+			pr_info("%s: Unsupported Frequency:%d\n", __func__,
+								req_freq);
+	}
+	return rc;
+}
+
+static int snddev_icodec_set_freq(struct msm_snddev_info *dev_info, u32 rate)
+{
+	int rc;
+	struct snddev_icodec_state *icodec;
+
+	if (!dev_info) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	icodec = dev_info->private_data;
+	if (adie_codec_freq_supported(icodec->data->profile, rate) != 0) {
+		pr_err("%s: adie_codec_freq_supported() failed\n", __func__);
+		rc = -EINVAL;
+		goto error;
+	} else {
+		if (snddev_icodec_check_freq(rate) != 0) {
+			pr_err("%s: check_freq failed\n", __func__);
+			rc = -EINVAL;
+			goto error;
+		} else
+			icodec->sample_rate = rate;
+	}
+
+	if (icodec->enabled) {
+		snddev_icodec_close(dev_info);
+		snddev_icodec_open(dev_info);
+	}
+
+	return icodec->sample_rate;
+
+error:
+	return rc;
+}
+
+static int snddev_icodec_enable_sidetone(struct msm_snddev_info *dev_info,
+	u32 enable, uint16_t gain)
+{
+	int rc = 0;
+	struct snddev_icodec_state *icodec;
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
+
+	if (!dev_info) {
+		pr_err("invalid dev_info\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	icodec = dev_info->private_data;
+
+	if (icodec->data->capability & SNDDEV_CAP_RX) {
+		mutex_lock(&drv->rx_lock);
+		if (!drv->rx_active || !dev_info->opened) {
+			pr_err("dev not active\n");
+			rc = -EPERM;
+			mutex_unlock(&drv->rx_lock);
+			goto error;
+		}
+		rc = afe_sidetone(PRIMARY_I2S_TX, PRIMARY_I2S_RX, enable, gain);
+		if (rc < 0)
+			pr_err("%s: AFE command sidetone failed\n", __func__);
+		mutex_unlock(&drv->rx_lock);
+	} else {
+		rc = -EINVAL;
+		pr_err("rx device only\n");
+	}
+
+error:
+	return rc;
+
+}
+static int snddev_icodec_enable_anc(struct msm_snddev_info *dev_info,
+	u32 enable)
+{
+	int rc = 0;
+	struct adie_codec_anc_data *reg_writes;
+	struct acdb_cal_block cal_block;
+	struct snddev_icodec_state *icodec;
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
+
+	pr_info("%s: enable=%d\n", __func__, enable);
+
+	if (!dev_info) {
+		pr_err("invalid dev_info\n");
+		rc = -EINVAL;
+		goto error;
+	}
+	icodec = dev_info->private_data;
+
+	if ((icodec->data->capability & SNDDEV_CAP_RX) &&
+		(icodec->data->capability & SNDDEV_CAP_ANC)) {
+		mutex_lock(&drv->rx_lock);
+
+		if (!drv->rx_active || !dev_info->opened) {
+			pr_err("dev not active\n");
+			rc = -EPERM;
+			mutex_unlock(&drv->rx_lock);
+			goto error;
+		}
+		if (enable) {
+			get_anc_cal(&cal_block);
+			reg_writes = (struct adie_codec_anc_data *)
+				cal_block.cal_kvaddr;
+
+			if (reg_writes == NULL) {
+				pr_err("error, no calibration data\n");
+				rc = -1;
+				mutex_unlock(&drv->rx_lock);
+				goto error;
+			}
+
+			rc = adie_codec_enable_anc(icodec->adie_path,
+			1, reg_writes);
+		} else {
+			rc = adie_codec_enable_anc(icodec->adie_path,
+			0, NULL);
+		}
+		mutex_unlock(&drv->rx_lock);
+	} else {
+		rc = -EINVAL;
+		pr_err("rx and ANC device only\n");
+	}
+
+error:
+	return rc;
+
+}
+
+int snddev_icodec_set_device_volume(struct msm_snddev_info *dev_info,
+		u32 volume)
+{
+	struct snddev_icodec_state *icodec;
+	struct mutex *lock;
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
+	int rc = -EPERM;
+
+	if (!dev_info) {
+		pr_info("%s : device not intilized.\n", __func__);
+		return  -EINVAL;
+	}
+
+	icodec = dev_info->private_data;
+
+	if (!(icodec->data->dev_vol_type & (SNDDEV_DEV_VOL_DIGITAL
+				| SNDDEV_DEV_VOL_ANALOG))) {
+
+		pr_info("%s : device %s does not support device volume "
+				"control.", __func__, dev_info->name);
+		return -EPERM;
+	}
+	dev_info->dev_volume =  volume;
+
+	if (icodec->data->capability & SNDDEV_CAP_RX)
+		lock = &drv->rx_lock;
+	else if (icodec->data->capability & SNDDEV_CAP_LB)
+		lock = &drv->lb_lock;
+	else
+		lock = &drv->tx_lock;
+
+	mutex_lock(lock);
+
+	rc = snddev_icodec_set_device_volume_impl(dev_info,
+			dev_info->dev_volume);
+	mutex_unlock(lock);
+	return rc;
+}
+
+static int snddev_icodec_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct snddev_icodec_data *pdata;
+	struct msm_snddev_info *dev_info;
+	struct snddev_icodec_state *icodec;
+
+	if (!pdev || !pdev->dev.platform_data) {
+		printk(KERN_ALERT "Invalid caller\n");
+		rc = -1;
+		goto error;
+	}
+	pdata = pdev->dev.platform_data;
+	if ((pdata->capability & SNDDEV_CAP_RX) &&
+	   (pdata->capability & SNDDEV_CAP_TX)) {
+		pr_err("%s: invalid device data either RX or TX\n", __func__);
+		goto error;
+	}
+	icodec = kzalloc(sizeof(struct snddev_icodec_state), GFP_KERNEL);
+	if (!icodec) {
+		rc = -ENOMEM;
+		goto error;
+	}
+	dev_info = kmalloc(sizeof(struct msm_snddev_info), GFP_KERNEL);
+	if (!dev_info) {
+		kfree(icodec);
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	dev_info->name = pdata->name;
+	dev_info->copp_id = pdata->copp_id;
+	dev_info->private_data = (void *) icodec;
+	dev_info->dev_ops.open = snddev_icodec_open;
+	dev_info->dev_ops.close = snddev_icodec_close;
+	dev_info->dev_ops.set_freq = snddev_icodec_set_freq;
+	dev_info->dev_ops.set_device_volume = snddev_icodec_set_device_volume;
+	dev_info->capability = pdata->capability;
+	dev_info->opened = 0;
+	msm_snddev_register(dev_info);
+	icodec->data = pdata;
+	icodec->sample_rate = pdata->default_sample_rate;
+	dev_info->sample_rate = pdata->default_sample_rate;
+	dev_info->channel_mode = pdata->channel_mode;
+	if (pdata->capability & SNDDEV_CAP_RX)
+		dev_info->dev_ops.enable_sidetone =
+			snddev_icodec_enable_sidetone;
+	else
+		dev_info->dev_ops.enable_sidetone = NULL;
+
+	if (pdata->capability & SNDDEV_CAP_ANC) {
+		dev_info->dev_ops.enable_anc =
+		snddev_icodec_enable_anc;
+	} else {
+		dev_info->dev_ops.enable_anc = NULL;
+	}
+error:
+	return rc;
+}
+
+static int snddev_icodec_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static struct platform_driver snddev_icodec_driver = {
+  .probe = snddev_icodec_probe,
+  .remove = snddev_icodec_remove,
+  .driver = { .name = "snddev_icodec" }
+};
+
+module_param(msm_codec_i2s_slave_mode, bool, 0);
+MODULE_PARM_DESC(msm_codec_i2s_slave_mode, "Set MSM to I2S slave clock mode");
+
+static int __init snddev_icodec_init(void)
+{
+	s32 rc;
+	struct snddev_icodec_drv_state *icodec_drv = &snddev_icodec_drv;
+
+	rc = platform_driver_register(&snddev_icodec_driver);
+	if (IS_ERR_VALUE(rc)) {
+		pr_err("%s: platform_driver_register for snddev icodec failed\n",
+					__func__);
+		goto error_snddev_icodec_driver;
+	}
+
+	rc = platform_driver_register(&msm_cdcclk_ctl_driver);
+	if (IS_ERR_VALUE(rc)) {
+		pr_err("%s: platform_driver_register for msm snddev failed\n",
+					__func__);
+		goto error_msm_cdcclk_ctl_driver;
+	}
+
+	rc = platform_driver_register(&msm_icodec_gpio_driver);
+	if (IS_ERR_VALUE(rc)) {
+		pr_err("%s: platform_driver_register for msm snddev gpio failed\n",
+					__func__);
+		goto error_msm_icodec_gpio_driver;
+	}
+
+	mutex_init(&icodec_drv->rx_lock);
+	mutex_init(&icodec_drv->lb_lock);
+	mutex_init(&icodec_drv->tx_lock);
+	icodec_drv->rx_active = 0;
+	icodec_drv->tx_active = 0;
+	icodec_drv->snddev_vreg = vreg_init();
+
+	wake_lock_init(&icodec_drv->tx_idlelock, WAKE_LOCK_IDLE,
+			"snddev_tx_idle");
+	wake_lock_init(&icodec_drv->rx_idlelock, WAKE_LOCK_IDLE,
+			"snddev_rx_idle");
+	return 0;
+error_msm_icodec_gpio_driver:
+	platform_driver_unregister(&msm_cdcclk_ctl_driver);
+error_msm_cdcclk_ctl_driver:
+	platform_driver_unregister(&snddev_icodec_driver);
+error_snddev_icodec_driver:
+	return -ENODEV;
+}
+
+static void __exit snddev_icodec_exit(void)
+{
+	struct snddev_icodec_drv_state *icodec_drv = &snddev_icodec_drv;
+
+	platform_driver_unregister(&snddev_icodec_driver);
+	platform_driver_unregister(&msm_cdcclk_ctl_driver);
+	platform_driver_unregister(&msm_icodec_gpio_driver);
+
+	clk_put(icodec_drv->rx_osrclk);
+	clk_put(icodec_drv->tx_osrclk);
+	if (icodec_drv->snddev_vreg) {
+		vreg_deinit(icodec_drv->snddev_vreg);
+		icodec_drv->snddev_vreg = NULL;
+	}
+	return;
+}
+
+module_init(snddev_icodec_init);
+module_exit(snddev_icodec_exit);
+
+MODULE_DESCRIPTION("ICodec Sound Device driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_icodec.h b/arch/arm/mach-msm/qdsp6v2/snddev_icodec.h
new file mode 100644
index 0000000..8d5613f
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_icodec.h
@@ -0,0 +1,35 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __MACH_QDSP6V2_SNDDEV_ICODEC_H
+#define __MACH_QDSP6V2_SNDDEV_ICODEC_H
+#include <linux/mfd/msm-adie-codec.h>
+#include <mach/qdsp5v2/audio_def.h>
+#include <mach/pmic.h>
+
+struct snddev_icodec_data {
+	u32 capability; /* RX or TX */
+	const char *name;
+	u32 copp_id; /* audpp routing */
+	/* Adie profile */
+	struct adie_codec_dev_profile *profile;
+	/* Afe setting */
+	u8 channel_mode;
+	u32 default_sample_rate;
+	int (*pamp_on) (void);
+	void (*pamp_off) (void);
+	int (*voltage_on) (void);
+	void (*voltage_off) (void);
+	u32 dev_vol_type;
+};
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.c b/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.c
new file mode 100644
index 0000000..75a7411
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.c
@@ -0,0 +1,464 @@
+/* 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
+ * 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/debugfs.h>
+#include <asm/uaccess.h>
+#include <mach/board.h>
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+#include <sound/q6afe.h>
+#include <sound/apr_audio.h>
+#include "snddev_mi2s.h"
+
+#define SNDDEV_MI2S_PCM_SZ 32 /* 16 bit / sample stereo mode */
+#define SNDDEV_MI2S_MUL_FACTOR 3 /* Multi by 8 Shift by 3  */
+#define SNDDEV_MI2S_CLK_RATE(freq) \
+	(((freq) * (SNDDEV_MI2S_PCM_SZ)) << (SNDDEV_MI2S_MUL_FACTOR))
+
+
+/* Global state for the driver */
+struct snddev_mi2s_drv_state {
+
+	struct clk *tx_osrclk;
+	struct clk *tx_bitclk;
+	int mi2s_ws;
+	int mi2s_mclk;
+	int mi2s_sclk;
+	int fm_mi2s_sd;
+};
+
+static struct snddev_mi2s_drv_state snddev_mi2s_drv;
+
+static struct msm_mi2s_gpio_data *mi2s_gpio;
+
+static int mi2s_gpios_request(void)
+{
+	int rc = 0;
+
+	pr_debug("%s\n", __func__);
+	rc = gpio_request(snddev_mi2s_drv.mi2s_ws, "MI2S_WS");
+	if (rc < 0) {
+		pr_err("%s: GPIO request for MI2S_WS failed\n", __func__);
+		return rc;
+	}
+
+	rc = gpio_request(snddev_mi2s_drv.mi2s_sclk, "MI2S_SCLK");
+	if (rc < 0) {
+		pr_err("%s: GPIO request for MI2S_SCLK failed\n", __func__);
+		gpio_free(snddev_mi2s_drv.mi2s_sclk);
+		return rc;
+	}
+
+	rc = gpio_request(snddev_mi2s_drv.mi2s_mclk, "MI2S_MCLK");
+	if (rc < 0) {
+		pr_err("%s: GPIO request for MI2S_MCLK failed\n",
+			__func__);
+		gpio_free(snddev_mi2s_drv.mi2s_ws);
+		gpio_free(snddev_mi2s_drv.mi2s_sclk);
+		return rc;
+	}
+
+	rc = gpio_request(snddev_mi2s_drv.fm_mi2s_sd, "FM_MI2S_SD");
+	if (rc < 0) {
+		pr_err("%s: GPIO request for FM_MI2S_SD failed\n",
+			__func__);
+		gpio_free(snddev_mi2s_drv.mi2s_ws);
+		gpio_free(snddev_mi2s_drv.mi2s_sclk);
+		gpio_free(snddev_mi2s_drv.mi2s_mclk);
+		return rc;
+	}
+
+	return rc;
+}
+
+static void mi2s_gpios_free(void)
+{
+	pr_debug("%s\n", __func__);
+	gpio_free(snddev_mi2s_drv.mi2s_ws);
+	gpio_free(snddev_mi2s_drv.mi2s_sclk);
+	gpio_free(snddev_mi2s_drv.mi2s_mclk);
+	gpio_free(snddev_mi2s_drv.fm_mi2s_sd);
+}
+
+static int mi2s_get_gpios(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct resource *res;
+
+	/* Claim all of the GPIOs. */
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO, "mi2s_ws");
+	if (!res) {
+		pr_err("%s: failed to get gpio MI2S_WS\n", __func__);
+		return -ENODEV;
+	}
+
+	snddev_mi2s_drv.mi2s_ws = res->start;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO, "mi2s_sclk");
+	if (!res) {
+		pr_err("%s: failed to get gpio MI2S_SCLK\n", __func__);
+		return -ENODEV;
+	}
+
+	snddev_mi2s_drv.mi2s_sclk = res->start;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO,
+					   "mi2s_mclk");
+	if (!res) {
+		pr_err("%s: failed to get gpio MI2S_MCLK\n", __func__);
+		return -ENODEV;
+	}
+
+	snddev_mi2s_drv.mi2s_mclk = res->start;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO,
+					   "fm_mi2s_sd");
+	if (!res) {
+		pr_err("%s: failed to get gpio FM_MI2S_SD\n", __func__);
+		return -ENODEV;
+	}
+
+	snddev_mi2s_drv.fm_mi2s_sd = res->start;
+
+	return rc;
+}
+
+static int mi2s_fm_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+
+	rc = mi2s_get_gpios(pdev);
+	if (rc < 0) {
+		pr_err("%s: GPIO configuration failed\n", __func__);
+		return rc;
+	}
+
+	mi2s_gpio = (struct msm_mi2s_gpio_data *)(pdev->dev.platform_data);
+	return rc;
+}
+
+static struct platform_driver mi2s_fm_driver = {
+	.probe = mi2s_fm_probe,
+	.driver = { .name = "msm_mi2s"}
+};
+
+static u8 num_of_bits_set(u8 sd_line_mask)
+{
+	u8 num_bits_set = 0;
+
+	while (sd_line_mask) {
+
+		if (sd_line_mask & 1)
+			num_bits_set++;
+		sd_line_mask = sd_line_mask >> 1;
+	}
+	return num_bits_set;
+}
+
+static int snddev_mi2s_open(struct msm_snddev_info *dev_info)
+{
+	int rc = 0;
+	union afe_port_config afe_config;
+	u8 channels;
+	u8 num_of_sd_lines = 0;
+	struct snddev_mi2s_drv_state *drv = &snddev_mi2s_drv;
+	struct snddev_mi2s_data *snddev_mi2s_data = dev_info->private_data;
+
+	if (!dev_info) {
+		pr_err("%s:  msm_snddev_info is null\n", __func__);
+		return -EINVAL;
+	}
+
+	/* set up osr clk */
+	drv->tx_osrclk = clk_get_sys(NULL, "mi2s_osr_clk");
+	if (IS_ERR(drv->tx_osrclk))
+		pr_err("%s master clock Error\n", __func__);
+
+	rc =  clk_set_rate(drv->tx_osrclk,
+			 SNDDEV_MI2S_CLK_RATE(dev_info->sample_rate));
+	if (IS_ERR_VALUE(rc)) {
+		pr_err("ERROR setting osr clock\n");
+		return -ENODEV;
+	}
+	clk_enable(drv->tx_osrclk);
+
+	/* set up bit clk */
+	drv->tx_bitclk = clk_get_sys(NULL, "mi2s_bit_clk");
+	if (IS_ERR(drv->tx_bitclk))
+		pr_err("%s clock Error\n", __func__);
+
+	rc =  clk_set_rate(drv->tx_bitclk, 8);
+	if (IS_ERR_VALUE(rc)) {
+		pr_err("ERROR setting bit clock\n");
+		clk_disable(drv->tx_osrclk);
+		return -ENODEV;
+	}
+	clk_enable(drv->tx_bitclk);
+
+	afe_config.mi2s.bitwidth = 16;
+
+	if (snddev_mi2s_data->channel_mode == 1)
+		channels = AFE_MI2S_MONO;
+	else if (snddev_mi2s_data->channel_mode == 2)
+		channels = AFE_MI2S_STEREO;
+	else if (snddev_mi2s_data->channel_mode == 4)
+		channels = AFE_MI2S_4CHANNELS;
+	else if (snddev_mi2s_data->channel_mode == 6)
+		channels = AFE_MI2S_6CHANNELS;
+	else if (snddev_mi2s_data->channel_mode == 8)
+		channels = AFE_MI2S_8CHANNELS;
+	else {
+		pr_err("ERROR: Invalid MI2S channel mode\n");
+		goto error_invalid_data;
+	}
+
+	num_of_sd_lines = num_of_bits_set(snddev_mi2s_data->sd_lines);
+
+	switch (num_of_sd_lines) {
+	case 1:
+		switch (snddev_mi2s_data->sd_lines) {
+		case MI2S_SD0:
+			afe_config.mi2s.line = AFE_I2S_SD0;
+			break;
+		case MI2S_SD1:
+			afe_config.mi2s.line = AFE_I2S_SD1;
+			break;
+		case MI2S_SD2:
+			afe_config.mi2s.line = AFE_I2S_SD2;
+			break;
+		case MI2S_SD3:
+			afe_config.mi2s.line = AFE_I2S_SD3;
+			break;
+		default:
+			pr_err("%s: invalid SD line\n",
+			__func__);
+			goto error_invalid_data;
+		}
+		if (channels != AFE_MI2S_STEREO &&
+		channels != AFE_MI2S_MONO) {
+			pr_err("%s: for one SD line, channel "
+			"must be 1 or 2\n", __func__);
+			goto error_invalid_data;
+		}
+		afe_config.mi2s.channel = channels;
+		break;
+	case 2:
+		switch (snddev_mi2s_data->sd_lines) {
+		case MI2S_SD0 | MI2S_SD1:
+			afe_config.mi2s.line = AFE_I2S_QUAD01;
+			break;
+		case MI2S_SD2 | MI2S_SD3:
+			afe_config.mi2s.line = AFE_I2S_QUAD23;
+			break;
+		default:
+			pr_err("%s: invalid SD line\n",
+			__func__);
+			goto error_invalid_data;
+		}
+		if (channels != AFE_MI2S_4CHANNELS) {
+			pr_err("%s: for two SD lines, channel "
+			"must be 1 and 2 or 3 and 4\n", __func__);
+			goto error_invalid_data;
+		}
+		break;
+	case 3:
+		switch (snddev_mi2s_data->sd_lines) {
+		case MI2S_SD0 | MI2S_SD1 | MI2S_SD2:
+			afe_config.mi2s.line = AFE_I2S_6CHS;
+			break;
+		default:
+			pr_err("%s: invalid SD lines\n",
+			__func__);
+			goto error_invalid_data;
+		}
+		if (channels != AFE_MI2S_6CHANNELS) {
+			pr_err("%s: for three SD lines, lines "
+			"must be 1, 2, and 3\n", __func__);
+			goto error_invalid_data;
+		}
+		break;
+	case 4:
+		switch (snddev_mi2s_data->sd_lines) {
+		case MI2S_SD0 | MI2S_SD1 | MI2S_SD2 | MI2S_SD3:
+			afe_config.mi2s.line = AFE_I2S_8CHS;
+			break;
+		default:
+			pr_err("%s: invalid SD lines\n",
+			__func__);
+			goto error_invalid_data;
+		}
+
+		if (channels != AFE_MI2S_8CHANNELS) {
+			pr_err("%s: for four SD lines, lines "
+			"must be 1, 2, 3, and 4\n", __func__);
+			goto error_invalid_data;
+		}
+		break;
+	default:
+		pr_err("%s: invalid SD lines\n", __func__);
+		goto error_invalid_data;
+	}
+	afe_config.mi2s.ws = 1;
+	afe_config.mi2s.format = MSM_AFE_I2S_FORMAT_LPCM;
+
+	rc = afe_open(snddev_mi2s_data->copp_id, &afe_config,
+		dev_info->sample_rate);
+
+	if (rc < 0) {
+		pr_err("%s:  afe_open failed\n", __func__);
+		goto error_invalid_data;
+	}
+
+	/*enable fm gpio here*/
+	rc = mi2s_gpios_request();
+	if (rc < 0) {
+		pr_err("%s: GPIO request failed\n", __func__);
+		return rc;
+	}
+
+	pr_info("%s:  afe_open  done\n", __func__);
+
+	return rc;
+
+error_invalid_data:
+
+	clk_disable(drv->tx_bitclk);
+	clk_disable(drv->tx_osrclk);
+	return -EINVAL;
+}
+
+static int snddev_mi2s_close(struct msm_snddev_info *dev_info)
+{
+
+	struct snddev_mi2s_drv_state *mi2s_drv = &snddev_mi2s_drv;
+	struct snddev_mi2s_data *snddev_mi2s_data = dev_info->private_data;
+
+	if (!dev_info) {
+		pr_err("%s:  msm_snddev_info is null\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!dev_info->opened) {
+		pr_err(" %s: calling close device with out opening the"
+		       " device\n", __func__);
+		return -EIO;
+	}
+	afe_close(snddev_mi2s_data->copp_id);
+	clk_disable(mi2s_drv->tx_bitclk);
+	clk_disable(mi2s_drv->tx_osrclk);
+
+	mi2s_gpios_free();
+
+	pr_info("%s:\n", __func__);
+
+	return 0;
+}
+
+static int snddev_mi2s_set_freq(struct msm_snddev_info *dev_info, u32 req_freq)
+{
+	if (req_freq != 48000) {
+		pr_info("%s: Unsupported Frequency:%d\n", __func__, req_freq);
+		return -EINVAL;
+	}
+	return 48000;
+}
+
+
+static int snddev_mi2s_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct snddev_mi2s_data *pdata;
+	struct msm_snddev_info *dev_info;
+
+	if (!pdev || !pdev->dev.platform_data) {
+		printk(KERN_ALERT "Invalid caller\n");
+		return -ENODEV;
+	}
+
+	pdata = pdev->dev.platform_data;
+
+	dev_info = kzalloc(sizeof(struct msm_snddev_info), GFP_KERNEL);
+	if (!dev_info) {
+		pr_err("%s: uneable to allocate memeory for msm_snddev_info\n",
+		       __func__);
+
+		return -ENOMEM;
+	}
+
+	dev_info->name = pdata->name;
+	dev_info->copp_id = pdata->copp_id;
+	dev_info->dev_ops.open = snddev_mi2s_open;
+	dev_info->dev_ops.close = snddev_mi2s_close;
+	dev_info->private_data = (void *)pdata;
+	dev_info->dev_ops.set_freq = snddev_mi2s_set_freq;
+	dev_info->capability = pdata->capability;
+	dev_info->opened = 0;
+	dev_info->sample_rate = pdata->sample_rate;
+	msm_snddev_register(dev_info);
+
+	return rc;
+}
+
+static struct platform_driver snddev_mi2s_driver = {
+	.probe = snddev_mi2s_probe,
+	.driver = {.name = "snddev_mi2s"}
+};
+
+static int __init snddev_mi2s_init(void)
+{
+	s32 rc = 0;
+
+	rc = platform_driver_register(&mi2s_fm_driver);
+	if (IS_ERR_VALUE(rc)) {
+		pr_err("%s: platform_driver_register for mi2s_fm_driver failed\n",
+				__func__);
+		goto error_mi2s_fm_platform_driver;
+	}
+
+	rc = platform_driver_register(&snddev_mi2s_driver);
+	if (IS_ERR_VALUE(rc)) {
+
+		pr_err("%s: platform_driver_register failed\n", __func__);
+		goto error_platform_driver;
+	}
+
+	return rc;
+
+error_platform_driver:
+	platform_driver_unregister(&mi2s_fm_driver);
+error_mi2s_fm_platform_driver:
+	pr_err("%s: encounter error\n", __func__);
+	return -ENODEV;
+}
+
+static void __exit snddev_mi2s_exit(void)
+{
+	struct snddev_mi2s_drv_state *mi2s_drv = &snddev_mi2s_drv;
+
+	platform_driver_unregister(&snddev_mi2s_driver);
+	clk_put(mi2s_drv->tx_osrclk);
+	clk_put(mi2s_drv->tx_bitclk);
+	return;
+}
+
+
+module_init(snddev_mi2s_init);
+module_exit(snddev_mi2s_exit);
+
+MODULE_DESCRIPTION("MI2S Sound Device driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.h b/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.h
new file mode 100644
index 0000000..d369c96
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.h
@@ -0,0 +1,30 @@
+/* Copyright (c) 2010, 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 __MACH_QDSP6_V2_SNDDEV_MI2S_H
+#define __MACH_QDSP6_V2_SNDDEV_MI2S_H
+
+struct snddev_mi2s_data {
+	u32 capability; /* RX or TX */
+	const char *name;
+	u32 copp_id; /* audpp routing */
+	u16 channel_mode;
+	u16 sd_lines;
+	u32 sample_rate;
+};
+
+#define MI2S_SD0 (1 << 0)
+#define MI2S_SD1 (1 << 1)
+#define MI2S_SD2 (1 << 2)
+#define MI2S_SD3 (1 << 3)
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_virtual.c b/arch/arm/mach-msm/qdsp6v2/snddev_virtual.c
new file mode 100644
index 0000000..f48aa0e
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_virtual.c
@@ -0,0 +1,172 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+#include <sound/q6afe.h>
+#include <linux/slab.h>
+#include "snddev_virtual.h"
+
+static DEFINE_MUTEX(snddev_virtual_lock);
+
+static int snddev_virtual_open(struct msm_snddev_info *dev_info)
+{
+	int rc = 0;
+
+	pr_debug("%s\n", __func__);
+
+	mutex_lock(&snddev_virtual_lock);
+
+	if (!dev_info)  {
+		pr_err("%s: NULL dev_info\n", __func__);
+
+		rc = -EINVAL;
+		goto done;
+	}
+
+	if (!dev_info->opened) {
+		rc = afe_start_pseudo_port(dev_info->copp_id);
+	} else {
+		pr_err("%s: Pseudo port 0x%x is already open\n",
+		       __func__, dev_info->copp_id);
+
+		rc = -EBUSY;
+	}
+
+done:
+	mutex_unlock(&snddev_virtual_lock);
+
+	return rc;
+}
+
+static int snddev_virtual_close(struct msm_snddev_info *dev_info)
+{
+	int rc = 0;
+
+	pr_debug("%s\n", __func__);
+
+	mutex_lock(&snddev_virtual_lock);
+
+	if (!dev_info) {
+		pr_err("%s: NULL dev_info\n", __func__);
+
+		rc = -EINVAL;
+		goto done;
+	}
+
+	if (dev_info->opened) {
+		rc = afe_stop_pseudo_port(dev_info->copp_id);
+	} else {
+		pr_err("%s: Pseudo port 0x%x is not open\n",
+		       __func__, dev_info->copp_id);
+
+		rc = -EPERM;
+	}
+
+done:
+	mutex_unlock(&snddev_virtual_lock);
+
+	return rc;
+}
+
+static int snddev_virtual_set_freq(struct msm_snddev_info *dev_info, u32 rate)
+{
+	int rc = 0;
+
+	if (!dev_info)
+		rc = -EINVAL;
+
+	return rate;
+}
+
+static int snddev_virtual_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct snddev_virtual_data *pdata;
+	struct msm_snddev_info *dev_info;
+
+	pr_debug("%s\n", __func__);
+
+	if (!pdev || !pdev->dev.platform_data) {
+		pr_err("%s: Invalid caller\n", __func__);
+
+		rc = -EPERM;
+		goto done;
+	}
+
+	pdata = pdev->dev.platform_data;
+
+	dev_info = kmalloc(sizeof(struct msm_snddev_info), GFP_KERNEL);
+	if (!dev_info) {
+		pr_err("%s: Out of memory\n", __func__);
+
+		rc = -ENOMEM;
+		goto done;
+	}
+
+	dev_info->name = pdata->name;
+	dev_info->copp_id = pdata->copp_id;
+	dev_info->private_data = (void *) NULL;
+	dev_info->dev_ops.open = snddev_virtual_open;
+	dev_info->dev_ops.close = snddev_virtual_close;
+	dev_info->dev_ops.set_freq = snddev_virtual_set_freq;
+	dev_info->capability = pdata->capability;
+	dev_info->sample_rate = 48000;
+	dev_info->opened = 0;
+	dev_info->sessions = 0;
+
+	msm_snddev_register(dev_info);
+
+done:
+	return rc;
+}
+
+static int snddev_virtual_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static struct platform_driver snddev_virtual_driver = {
+	.probe = snddev_virtual_probe,
+	.remove = snddev_virtual_remove,
+	.driver = { .name = "snddev_virtual" }
+};
+
+static int __init snddev_virtual_init(void)
+{
+	int rc = 0;
+
+	pr_debug("%s\n", __func__);
+
+	rc = platform_driver_register(&snddev_virtual_driver);
+	if (IS_ERR_VALUE(rc)) {
+		pr_err("%s: Platform driver register failure\n", __func__);
+
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void __exit snddev_virtual_exit(void)
+{
+	platform_driver_unregister(&snddev_virtual_driver);
+
+	return;
+}
+
+module_init(snddev_virtual_init);
+module_exit(snddev_virtual_exit);
+
+MODULE_DESCRIPTION("Virtual Sound Device driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_virtual.h b/arch/arm/mach-msm/qdsp6v2/snddev_virtual.h
new file mode 100644
index 0000000..dec4d07
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_virtual.h
@@ -0,0 +1,20 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __MACH_QDSP6V2_SNDDEV_VIRTUAL_H
+#define __MACH_QDSP6V2_SNDDEV_VIRTUAL_H
+
+struct snddev_virtual_data {
+	u32 capability; /* RX or TX */
+	const char *name;
+	u32 copp_id; /* Audpp routing */
+};
+#endif
diff --git a/arch/arm/mach-msm/qdsp6v2/timpani_profile_8x60.h b/arch/arm/mach-msm/qdsp6v2/timpani_profile_8x60.h
new file mode 100644
index 0000000..f02e0a0
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/timpani_profile_8x60.h
@@ -0,0 +1,3225 @@
+/* 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
+ * 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 __MACH_QDSP6V2_TIMPANI_PROFILE_H
+#define __MACH_QDSP6V2_TIMPANI_PROFILE_H
+
+/*
+ * TX Device Profiles
+ */
+
+/* Analog MIC */
+/* AMIC Primary mono */
+#define AMIC_PRI_MONO_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xD0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x09, 0x00)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3A98}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x09, 0x09)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+
+/* AMIC Secondary mono */
+#define AMIC_SEC_MONO_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xFF, 0xA8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAC, 0x09, 0x00)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3A98 },\
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAC, 0x09, 0x09)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* AMIC dual */
+#define AMIC_DUAL_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xB0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xFF, 0xA8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x09, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAC, 0x09, 0x00)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8 }, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x09, 0x09)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAC, 0x09, 0x09)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* Fluid AMIC dual */
+#define FLUID_AMIC_DUAL_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xD0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xFF, 0xC8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8 }, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* Fluid AMIC dual broadside */
+#define FLUID_AMIC_DUAL_BROADSIDE_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	/* AUX-IN to TxFE LEFT */ \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xC1)}, \
+	/* MIC1 to TxFE RIGHT */ \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xFF, 0xD0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8 }, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/*
+ * Digital MIC
+ */
+/* DMIC1 Primary (DMIC 1 - TX1) */
+#define DMIC1_PRI_MONO_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0x1F, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0x3F, 0x21)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0x3F, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x39, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA8, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x3F, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* DMIC1 Secondary - (DMIC 2 - TX1) */
+#define DMIC1_SEC_MONO_OSR_64 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x12)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA8, 0x0F, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT,    0xbb8 }, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* DMIC Dual Primary (DMIC 1/2 - TX1) */
+#define DMIC1_PRI_STEREO_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0x1F, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0x3F, 0x19)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0x3F, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x39, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA8, 0x0F, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x3F, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)} }
+
+/* DMIC2 Dual Primary (DMIC 3/4 - TX2 - Left/Right) */
+#define DMIC2_SEC_DUAL_OSR_64 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0xC0, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA6, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA7, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x22)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x96, 0xFF, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA8, 0xF0, 0xE0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x09, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0A, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT,    0xbb8 }, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0xC0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA6, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA7, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0xC0, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x09, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0A, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HS_DMIC2_STEREO_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0x1F, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0x3F, 0x19)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0x3F, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x39, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA8, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x3F, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0xC0, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/*
+ *  LINE IN
+ */
+#define LINEIN_PRI_MONO_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT,    0xbb8 }, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LINEIN_PRI_STEREO_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xFF, 0xA2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LINEIN_SEC_MONO_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0xC0, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA6, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA7, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x2E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x96, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0xF0, 0xA0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x18, 0xFF, 0xA2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x09, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0A, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0xC0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA6, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA7, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0xC0, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x18, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x09, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0A, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LINEIN_SEC_STEREO_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0xC0, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA6, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA7, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x2E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x96, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0xF0, 0xE0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x18, 0xFF, 0xA2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x19, 0xFF, 0xA2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x09, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0A, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0xC0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA6, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA7, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0xC0, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x18, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x19, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x09, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0A, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LINEIN_SEC_STEREO_OSR_64 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0xC0, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA6, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA7, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x22)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x96, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0xF0, 0xE0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x18, 0xFF, 0xA2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x19, 0xFF, 0xA2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x09, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0A, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0xC0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA6, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA7, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0xC0, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x18, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x19, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x09, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0A, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/*
+ * AUX IN
+ */
+#define AUXIN_MONO_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xA1)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* Headset MIC */
+#define HEADSET_AMIC2_TX_MONO_PRI_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xC8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x09, 0x00)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3A98 }, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x09, 0x09)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/*
+ * RX Device Profiles
+ */
+
+/* RX EAR */
+#define EAR_PRI_MONO_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x97, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0xFF, 0x4C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x01, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define EAR_SEC_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA1, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x98, 0xFF, 0x02)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xFF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* ANC Headset: Speakers on Primary Rx, Noise Microphones on Secondary Tx */
+
+#define ANC_HEADSET_CPLS_AMIC1_AUXL_RX1_48000_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x95, 0xFF, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9A, 0xFF, 0x8C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9B, 0x01, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x18, 0xFF, 0xD0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x19, 0xFF, 0xC1)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x09, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0A, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0xFF, 0x29)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x27, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xC0, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xD0, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x18, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x19, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x09, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0A, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define FLUID_SPEAKER_PRI_STEREO_48000_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF},	\
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/*
+ *  RX HPH PRIMARY
+ */
+
+/* RX HPH CLASS AB CAPLESS */
+
+#define HEADSET_AB_CPLS_48000_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0xFF, 0x29)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x27, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HPH_PRI_AB_CPLS_MONO \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0xFF, 0x29)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x24, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x24, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* based on HEADSET_AB_CPLS_48000_OSR_256, change 0x83 */
+/* change 0x31 */
+#define HPH_PRI_AB_CPLS_MONO_LEFT \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0xC5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0xFF, 0x29)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0xC5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x27, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* based on HEADSET_AB_CPLS_48000_OSR_256 */
+/* add 0x8A to mute rx1 left 0x01 */
+/* change 0x31 */
+#define HPH_PRI_AB_CPLS_MONO_RIGHT \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0xFF, 0x29)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0D)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x35)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x27, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define FTM_HPH_PRI_AB_CPLS_MONO_LB_LEFT \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0xC5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0xFF, 0x29)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x27, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x3C)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define FTM_HPH_PRI_AB_CPLS_MONO_LB_RIGHT \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0xFF, 0x29)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0D)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x35)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x27, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* This is for differential signaling, which is a test mode. */
+#define HPH_PRI_AB_CPLS_DIFF \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x06)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0xFF, 0x29)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0xFF, 0x4C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x24, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x24, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HPH_PRI_AB_CPLS_STEREO \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x97, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0xFF, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x24, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0x55)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* RX HPH CLASS AB LEGACY */
+
+#define HPH_PRI_AB_LEG_MONO \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x97, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0xFF, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x24, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x24, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0x59)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 300000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0xF9)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HP_PRI_AB_LEG_DIFF \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x97, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0xFF, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x24, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x24, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0x59)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 300000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0xF9)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HPH_PRI_AB_LEG_STEREO \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x09)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x59)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0xF9)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x27, 0x27)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* RX HPH CLASS D LEGACY */
+
+#define HPH_PRI_D_LEG_DIFF \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x97, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0xFF, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0x90, 0x90)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x0A, 0x0A)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 300000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HPH_PRI_D_LEG_STEREO \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x21, 0xFF, 0x60)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x22, 0xFF, 0xE1)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xFF, 0xD0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2D, 0xFF, 0x6F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2E, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3F, 0xFF, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x40, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x41, 0x08, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x42, 0xFF, 0xBB)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x43, 0xFF, 0xF2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x44, 0xF7, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x45, 0xFF, 0xFF)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x46, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x47, 0xFF, 0xF2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x48, 0xF7, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x49, 0xFF, 0xFF)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4A, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0xFF, 0x8C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x0F, 0x0A)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 300000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/*
+ * RX HPH SECONDARY
+ */
+
+/* RX HPH CLASS AB CAPLESS */
+#define HPH_SEC_AB_CPLS_MONO \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA1, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x98, 0xFF, 0x02)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x48, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x48, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0x55)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+#define HPH_SEC_AB_CPLS_DIFF \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA1, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x98, 0xFF, 0x02)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x48, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x48, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0x55)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HPH_SEC_AB_CPLS_STEREO \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA5, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA1, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x98, 0xFF, 0x02)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x29, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x48, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0x55)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA5, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* RX HPH CLASS AB LEGACY */
+#define HPH_SEC_AB_LEG_MONO \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA1, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x98, 0xFF, 0x02)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x48, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x48, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0x59)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 300000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0xF9)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HPH_SEC_AB_LEG_DIFF \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA1, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x98, 0xFF, 0x02)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x48, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x48, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0x59)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 300000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0xF9)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+#define HPH_SEC_AB_LEG_STEREO \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA5, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA1, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x98, 0xFF, 0x02)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x29, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x48, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0x59)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 300000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0xF9)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA5, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* RX HPH CLASS D LEGACY */
+
+#define HPH_SEC_D_LEG_DIFF \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA1, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x98, 0xFF, 0x02)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0x50, 0x50)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x0A, 0x0A)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 300000},\
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HPH_SEC_D_LEG_STEREO \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA5, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA1, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x98, 0xFF, 0x02)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x29, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0x50, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x0A, 0x0A)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 300000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* RX LINE OUT PRIMARY */
+/* spkr phone mono rx */
+#define LINEOUT_PRI_MONO \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x97, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0xFF, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0x24, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x58, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LINEOUT_PRI_DIFF \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x06)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0xFF, 0x4C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0x24, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFC, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFC, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFC, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFC, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFC, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFC, 0x10)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFC, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFC, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFC, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFC, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LINEOUT_PRI_STEREO \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x97, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0xFF, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x58, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0c)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* RX LINE OUT SECONDARY */
+#define LINEOUT_SEC_MONO \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA1, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x98, 0xFF, 0x02)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x48, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0x48, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x58, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LINEOUT_SEC_DIFF \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA1, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x98, 0xFF, 0x02)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x48, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0x48, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x58, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LINEOUT_SEC_STEREO \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA5, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA1, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x98, 0xFF, 0x02)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x29, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x48, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x58, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA5, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define SPEAKER_PRI_STEREO_48000_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x24)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x4E1F}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF},	\
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* RX AUX */
+#define AUXOUT_PRI_MONO_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x97, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0xFF, 0x4C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x20, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x07, 0x03)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 50000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x07, 0x07)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x07, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x20, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define AUXOUT_SEC_MONO_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA1, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x98, 0xFF, 0x02)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xFF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x40, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x07, 0x03)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 50000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x07, 0x07)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x07, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x40, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LB_AUXPGA_HPH_AB_CPLS_STEREO \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2F, 0xFF, 0x44)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x30, 0xFF, 0x92)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xAA)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0xFF, 0x29)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x90, 0x90)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+#define LB_AUXPGA_LO_STEREO \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2F, 0xFF, 0x44)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x30, 0xFF, 0x92)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xAA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x90, 0x90)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0xF0, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x90, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+/*
+ * LB Device Profiles
+ */
+
+/* EAR */
+#define LB_EAR_PRI_MONO \
+	{{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8 }, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xA0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8 }, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x04, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* HPH CLASS AB CAPLESS */
+#define LB_HPH_AB_CPLS_PRI_MONO \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xA0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x55)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LB_HPH_AB_CPLS_PRI_DIFF \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x10, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xA0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x55)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define SPEAKER_HPH_AB_CPL_PRI_STEREO_48000_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0xFF, 0x29)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x27, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF},	\
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LB_HPH_AB_CPLS_PRI_STEREO \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x90, 0x90)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xAA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x55)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x90, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* HPH CLASS AB LEGACY */
+#define LB_HPH_AB_LEG_PRI_MONO \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xA0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x59)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 300000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0xFC)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LB_PHP_AB_LEG_PRI_DIFF \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x10, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xA0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x59)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 300000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0xFC)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LB_HPH_AB_LEG_PRI_STEREO \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x90, 0x90)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xAA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x59)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 300000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0xFC)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x90, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* HPH CLASS D LEGACY */
+#define LB_HPH_D_LEG_PRI_DIFF \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xA0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x3A, 0x2A)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 300000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x3F, 0x2F)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x3F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LB_HPH_D_LEG_PRI_STEREO \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0x30, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xAA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x3A, 0x3A)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 300000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x3F, 0x3F)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x3F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* LINE OUT */
+#define LB_LINEOUT_PRI_MONO \
+	{{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xA0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x58, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LB_LINEOUT_PRI_DIFF \
+	{{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0x10, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xA0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x58, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0x10, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LB_LINEOUT_PRI_STEREO \
+	{{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x90, 0x90)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xAA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x58, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0x90, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* AUX OUT */
+#define LB_AUXOUT_PRI_MONO \
+	{{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0xE0, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xA0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x07, 0x03)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 50000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x07, 0x07)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x07, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0xE0, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* TTY RX */
+#define TTY_HEADSET_MONO_RX_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x97, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x06)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x4C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x45)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0xFF, 0x29)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0xC5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x27, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* TTY TX */
+#define TTY_HEADSET_MONO_TX_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xA8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* FTM devices */
+/* from HPH_PRI_AB_CPLS_DIFF */
+#define HEADSET_MONO_DIFF_RX \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x06)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0xFF, 0x29)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0xFF, 0x4C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x24, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x24, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* based on SPEAKER_PRI_STEREO_48000_OSR_256 */
+/* change 0x8A */
+#define FTM_SPKR_L_RX \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF},	\
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* based on SPEAKER_PRI_STEREO_48000_OSR_256 */
+/* change 0x8A */
+#define SPKR_R_RX \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0x24, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF},	\
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* based on SPEAKER_PRI_STEREO_48000_OSR_256 */
+#define FTM_SPKR_RX_LB \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x06)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF},	\
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+#define SPKR_MONO_DIFF_RX \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* from AMIC_PRI_MONO_OSR_256, change TxFE (reg 0x0D) */
+#define LINEIN_MONO_L_TX \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xD4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x09, 0x00)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3A98}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x09, 0x09)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* from AMIC_PRI_MONO_OSR_256, change TxFE (reg 0x0D) */
+#define LINEIN_MONO_R_TX \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xFF, 0xD6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x09, 0x00)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3A98}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x09, 0x09)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* from AMIC_PRI_MONO_OSR_256 */
+#define AUX_IN_TX \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xC1)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x09, 0x00)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3A98}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x09, 0x09)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* AUXOUT_PRI_MONO_8000_OSR_256 */
+#define AUX_OUT_RX \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},	\
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x97, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0xFF, 0x4C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x20, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x07, 0x03)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 50000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x07, 0x07)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x07, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x20, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* from DMIC1_PRI_MONO_OSR_256 */
+#define DMIC1_LEFT_TX \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0x1F, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0x3F, 0x21)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0x3F, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x39, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA8, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x3F, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define DMIC1_RIGHT_TX \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0x1F, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0x3F, 0x21)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0x3F, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x39, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA8, 0x0F, 0x06)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x3F, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define DMIC1_LEFT_AND_RIGHT_TX DMIC1_PRI_STEREO_OSR_256
+
+#define DMIC2_LEFT_TX \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0x1F, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0x3F, 0x21)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0x3F, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x39, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA8, 0x0F, 0x0A)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x3F, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define DMIC2_RIGHT_TX \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0x1F, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0x3F, 0x21)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0x3F, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x39, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA8, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x3F, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define DMIC2_LEFT_AND_RIGHT_TX \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0x1F, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0x3F, 0x21)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0x3F, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x39, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA8, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x3F, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HANDSET_MIC1_AUX_IN \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xB0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xFF, 0xA1)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8 }, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* based on AMIC_PRI_MONO_OSR_256 */
+#define FTM_HANDSET_LB_TX \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xD0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x09, 0x00)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3A98}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8B, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8C, 0x07, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA0, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x09, 0x09)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* based on HEADSET_AMIC2_TX_MONO_PRI_OSR_256 */
+#define FTM_HEADSET_LB_TX \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xC8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8 }, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8B, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8C, 0x07, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA0, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* based on EAR_PRI_MONO_8000_OSR_256 */
+#define EAR_PRI_MONO_LB \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x97, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0x60, 0x60)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0xFF, 0x4C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x3C)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x01, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* based on AMIC_DUAL_OSR_256 */
+#define FTM_AMIC_DUAL_HANDSET_TX_LB \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xB0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xFF, 0xA8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8 }, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA0, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/Makefile b/arch/arm/mach-msm/qdsp6v2/ultrasound/Makefile
new file mode 100644
index 0000000..0be1303
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/Makefile
@@ -0,0 +1,2 @@
+obj-y += q6usm.o usf.o usfcdev.o
+EXTRA_CFLAGS += -I$(src)/..
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c
new file mode 100644
index 0000000..2874700
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c
@@ -0,0 +1,1209 @@
+/* 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
+ * 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/module.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/msm_audio.h>
+#include <sound/apr_audio.h>
+#include "q6usm.h"
+
+/* The driver version*/
+#define DRV_VERSION "1.2"
+
+#define SESSION_MAX 0x02 /* aDSP:USM limit */
+
+#define READDONE_IDX_STATUS     0
+#define READDONE_IDX_BUFFER     1
+#define READDONE_IDX_SIZE       2
+#define READDONE_IDX_OFFSET     3
+#define READDONE_IDX_MSW_TS     4
+#define READDONE_IDX_LSW_TS     5
+#define READDONE_IDX_FLAGS      6
+#define READDONE_IDX_NUMFRAMES  7
+#define READDONE_IDX_ID         8
+
+#define WRITEDONE_IDX_STATUS    0
+
+/* Standard timeout in the asynchronous ops */
+#define Q6USM_TIMEOUT_JIFFIES	(1*HZ) /* 1 sec */
+
+static DEFINE_MUTEX(session_lock);
+
+static struct us_client *session[SESSION_MAX];
+static int32_t q6usm_mmapcallback(struct apr_client_data *data, void *priv);
+static int32_t q6usm_callback(struct apr_client_data *data, void *priv);
+static void q6usm_add_hdr(struct us_client *usc, struct apr_hdr *hdr,
+			  uint32_t pkt_size, bool cmd_flg);
+
+struct usm_mmap {
+	atomic_t ref_cnt;
+	atomic_t cmd_state;
+	wait_queue_head_t cmd_wait;
+	void *apr;
+};
+
+static struct usm_mmap this_mmap;
+
+static int q6usm_session_alloc(struct us_client *usc)
+{
+	int ind = 0;
+
+	mutex_lock(&session_lock);
+	for (ind = 0; ind < SESSION_MAX; ++ind) {
+		if (!session[ind]) {
+			session[ind] = usc;
+			mutex_unlock(&session_lock);
+			++ind; /* session id: 0 reserved */
+			pr_debug("%s: session[%d] was allocated\n",
+				  __func__, ind);
+			return ind;
+		}
+	}
+	mutex_unlock(&session_lock);
+	return -ENOMEM;
+}
+
+static void q6usm_session_free(struct us_client *usc)
+{
+	/* Session index was incremented during allocation */
+	uint16_t ind = (uint16_t)usc->session - 1;
+
+	pr_debug("%s: to free session[%d]\n", __func__, ind);
+	if (ind < SESSION_MAX) {
+		mutex_lock(&session_lock);
+		session[ind] = 0;
+		mutex_unlock(&session_lock);
+	}
+}
+
+int q6usm_us_client_buf_free(unsigned int dir,
+			     struct us_client *usc)
+{
+	struct us_port_data *port;
+	int rc = 0;
+	uint32_t size = 0;
+
+	if ((usc == NULL) ||
+	    ((dir != IN) && (dir != OUT)))
+		return -EINVAL;
+
+	mutex_lock(&usc->cmd_lock);
+	port = &usc->port[dir];
+	if (port == NULL) {
+		mutex_unlock(&usc->cmd_lock);
+		return -EINVAL;
+	}
+
+	if (port->data == NULL) {
+		mutex_unlock(&usc->cmd_lock);
+		return 0;
+	}
+
+	rc = q6usm_memory_unmap(usc, port->phys, dir);
+	if (rc)
+		pr_err("%s: CMD Memory_unmap* failed\n", __func__);
+
+	pr_debug("%s: data[%p]phys[%p][%p]\n", __func__,
+		 (void *)port->data, (void *)port->phys, (void *)&port->phys);
+	size = port->buf_size * port->buf_cnt;
+	dma_free_coherent(NULL, size, port->data, port->phys);
+	port->data = NULL;
+	port->phys = 0;
+	port->buf_size = 0;
+	port->buf_cnt = 0;
+
+	mutex_unlock(&usc->cmd_lock);
+	return 0;
+}
+
+void q6usm_us_client_free(struct us_client *usc)
+{
+	int loopcnt = 0;
+	struct us_port_data *port;
+
+	if ((usc == NULL) ||
+	    !(usc->session))
+		return;
+
+	for (loopcnt = 0; loopcnt <= OUT; ++loopcnt) {
+		port = &usc->port[loopcnt];
+		if (port->data == NULL)
+			continue;
+		pr_debug("%s: loopcnt = %d\n", __func__, loopcnt);
+		q6usm_us_client_buf_free(loopcnt, usc);
+	}
+	q6usm_session_free(usc);
+	apr_deregister(usc->apr);
+
+	pr_debug("%s: APR De-Register\n", __func__);
+
+	if (atomic_read(&this_mmap.ref_cnt) <= 0) {
+		pr_err("%s: APR Common Port Already Closed\n", __func__);
+		goto done;
+	}
+
+	atomic_dec(&this_mmap.ref_cnt);
+	if (atomic_read(&this_mmap.ref_cnt) == 0) {
+		apr_deregister(this_mmap.apr);
+		pr_debug("%s: APR De-Register common port\n", __func__);
+	}
+done:
+	kfree(usc);
+	pr_debug("%s:\n", __func__);
+	return;
+}
+
+struct us_client *q6usm_us_client_alloc(
+	void (*cb)(uint32_t, uint32_t, uint32_t *, void *),
+	void *priv)
+{
+	struct us_client *usc;
+	int n;
+	int lcnt = 0;
+
+	usc = kzalloc(sizeof(struct us_client), GFP_KERNEL);
+	if (usc == NULL)
+		return NULL;
+	n = q6usm_session_alloc(usc);
+	if (n <= 0)
+		goto fail_session;
+	usc->session = n;
+	usc->cb = cb;
+	usc->priv = priv;
+	usc->apr = apr_register("ADSP", "USM", \
+				(apr_fn)q6usm_callback,\
+				((usc->session) << 8 | 0x0001),\
+				usc);
+
+	if (usc->apr == NULL) {
+		pr_err("%s: Registration with APR failed\n", __func__);
+		goto fail;
+	}
+	pr_debug("%s: Registering the common port with APR\n", __func__);
+	if (atomic_read(&this_mmap.ref_cnt) == 0) {
+		this_mmap.apr = apr_register("ADSP", "USM",
+					     (apr_fn)q6usm_mmapcallback,
+					     0x0FFFFFFFF, &this_mmap);
+		if (this_mmap.apr == NULL) {
+			pr_err("%s: USM port registration failed\n",
+			       __func__);
+			goto fail;
+		}
+	}
+
+	atomic_inc(&this_mmap.ref_cnt);
+	init_waitqueue_head(&usc->cmd_wait);
+	mutex_init(&usc->cmd_lock);
+	for (lcnt = 0; lcnt <= OUT; ++lcnt) {
+		mutex_init(&usc->port[lcnt].lock);
+		spin_lock_init(&usc->port[lcnt].dsp_lock);
+	}
+	atomic_set(&usc->cmd_state, 0);
+
+	return usc;
+fail:
+	q6usm_us_client_free(usc);
+	return NULL;
+fail_session:
+	kfree(usc);
+	return NULL;
+}
+
+int q6usm_us_client_buf_alloc(unsigned int dir,
+			      struct us_client *usc,
+			      unsigned int bufsz,
+			      unsigned int bufcnt)
+{
+	int rc = 0;
+	struct us_port_data *port = NULL;
+	unsigned int size = bufsz*bufcnt;
+
+	if ((usc == NULL) ||
+	    ((dir != IN) && (dir != OUT)) || (size == 0) ||
+	    (usc->session <= 0 || usc->session > SESSION_MAX)) {
+		pr_err("%s: wrong parameters: size=%d; bufcnt=%d\n",
+		       __func__, size, bufcnt);
+		return -EINVAL;
+	}
+
+	mutex_lock(&usc->cmd_lock);
+
+	port = &usc->port[dir];
+
+	port->data = dma_alloc_coherent(NULL, size, &(port->phys), GFP_KERNEL);
+	if (port->data == NULL) {
+		pr_err("%s: US region allocation failed\n", __func__);
+		mutex_unlock(&usc->cmd_lock);
+		return -ENOMEM;
+	}
+
+	port->buf_cnt = bufcnt;
+	port->buf_size = bufsz;
+	pr_debug("%s: data[%p]; phys[%p]; [%p]\n", __func__,
+		 (void *)port->data,
+		 (void *)port->phys,
+		 (void *)&port->phys);
+
+	rc = q6usm_memory_map(usc, port->phys, dir, size, 1);
+	if (rc < 0) {
+		pr_err("%s: CMD Memory_map failed\n", __func__);
+		mutex_unlock(&usc->cmd_lock);
+		q6usm_us_client_buf_free(dir, usc);
+	} else {
+		mutex_unlock(&usc->cmd_lock);
+		rc = 0;
+	}
+
+	return rc;
+}
+
+static int32_t q6usm_mmapcallback(struct apr_client_data *data, void *priv)
+{
+	uint32_t token;
+	uint32_t *payload = data->payload;
+
+	pr_debug("%s: ptr0[0x%x]; ptr1[0x%x]; opcode[0x%x];"
+		 "token[0x%x]; payload_s[%d]; src[%d]; dest[%d];\n",
+		 __func__, payload[0], payload[1], data->opcode, data->token,
+		 data->payload_size, data->src_port, data->dest_port);
+
+	if (data->opcode == APR_BASIC_RSP_RESULT) {
+		/* status field check */
+		if (payload[1]) {
+			pr_err("%s: wrong response[%d] on cmd [%d]\n",
+			       __func__, payload[1], payload[0]);
+		} else {
+			token = data->token;
+			switch (payload[0]) {
+			case USM_SESSION_CMD_MEMORY_MAP:
+			case USM_SESSION_CMD_MEMORY_UNMAP:
+				pr_debug("%s: cmd[0x%x]; result[0x%x]\n",
+					 __func__, payload[0], payload[1]);
+				if (atomic_read(&this_mmap.cmd_state)) {
+					atomic_set(&this_mmap.cmd_state, 0);
+					wake_up(&this_mmap.cmd_wait);
+				}
+				break;
+			default:
+				pr_debug("%s: wrong command[0x%x]\n",
+					 __func__, payload[0]);
+				break;
+			}
+		}
+	}
+	return 0;
+}
+
+
+static int32_t q6usm_callback(struct apr_client_data *data, void *priv)
+{
+	struct us_client *usc = (struct us_client *)priv;
+	unsigned long dsp_flags;
+	uint32_t *payload = data->payload;
+	uint32_t token = data->token;
+
+	if (usc == NULL) {
+		pr_err("%s: client info is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	if (data->opcode == APR_BASIC_RSP_RESULT) {
+		/* status field check */
+		if (payload[1]) {
+			pr_err("%s: wrong response[%d] on cmd [%d]\n",
+			       __func__, payload[1], payload[0]);
+			if (usc->cb)
+				usc->cb(data->opcode, token,
+					(uint32_t *)data->payload, usc->priv);
+		} else {
+			switch (payload[0]) {
+			case USM_SESSION_CMD_RUN:
+			case USM_STREAM_CMD_CLOSE:
+				if (token != usc->session) {
+					pr_err("%s: wrong token[%d]",
+					       __func__, token);
+					break;
+				}
+			case USM_STREAM_CMD_OPEN_READ:
+			case USM_STREAM_CMD_OPEN_WRITE:
+			case USM_STREAM_CMD_SET_ENC_PARAM:
+			case USM_DATA_CMD_MEDIA_FORMAT_UPDATE:
+			case USM_SESSION_CMD_SIGNAL_DETECT_MODE:
+				if (atomic_read(&usc->cmd_state)) {
+					atomic_set(&usc->cmd_state, 0);
+					wake_up(&usc->cmd_wait);
+				}
+				if (usc->cb)
+					usc->cb(data->opcode, token,
+						(uint32_t *)data->payload,
+						usc->priv);
+				break;
+			default:
+				pr_debug("%s: command[0x%x] wrong response\n",
+					 __func__, payload[0]);
+				break;
+			}
+		}
+		return 0;
+	}
+
+	switch (data->opcode) {
+	case USM_DATA_EVENT_READ_DONE: {
+		struct us_port_data *port = &usc->port[OUT];
+
+		pr_debug("%s: R-D: stat=%d; buff=%x; size=%d; off=%d\n",
+			 __func__,
+			 payload[READDONE_IDX_STATUS],
+			 payload[READDONE_IDX_BUFFER],
+			 payload[READDONE_IDX_SIZE],
+			 payload[READDONE_IDX_OFFSET]);
+		pr_debug("msw_ts=%d; lsw_ts=%d; flags=%d; id=%d; num=%d\n",
+			 payload[READDONE_IDX_MSW_TS],
+			 payload[READDONE_IDX_LSW_TS],
+			 payload[READDONE_IDX_FLAGS],
+			 payload[READDONE_IDX_ID],
+			 payload[READDONE_IDX_NUMFRAMES]);
+
+		spin_lock_irqsave(&port->dsp_lock, dsp_flags);
+		if (payload[READDONE_IDX_STATUS]) {
+			pr_err("%s: wrong READDONE[%d]; token[%d]\n",
+			       __func__,
+			       payload[READDONE_IDX_STATUS],
+			       token);
+			token = USM_WRONG_TOKEN;
+			spin_unlock_irqrestore(&port->dsp_lock,
+					       dsp_flags);
+			break;
+		}
+
+		if (port->expected_token != token) {
+			u32 cpu_buf = port->cpu_buf;
+			pr_err("%s: expected[%d] != token[%d]\n",
+				__func__, port->expected_token, token);
+			pr_debug("%s: dsp_buf=%d; cpu_buf=%d;\n",
+				__func__,   port->dsp_buf, cpu_buf);
+
+			token = USM_WRONG_TOKEN;
+			/* To prevent data handle continiue */
+			port->expected_token = USM_WRONG_TOKEN;
+			spin_unlock_irqrestore(&port->dsp_lock,
+					       dsp_flags);
+			break;
+		} /* port->expected_token != data->token */
+
+		port->expected_token = token + 1;
+		if (port->expected_token == port->buf_cnt)
+			port->expected_token = 0;
+
+		/* gap support */
+		if (port->expected_token != port->cpu_buf) {
+			port->dsp_buf = port->expected_token;
+			token = port->dsp_buf; /* for callback */
+		} else
+			port->dsp_buf = token;
+
+		spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
+		break;
+	} /* case USM_DATA_EVENT_READ_DONE */
+
+	case USM_DATA_EVENT_WRITE_DONE: {
+		struct us_port_data *port = &usc->port[IN];
+
+		pr_debug("%s W-D: code[0x%x]; status[0x%x]; token[%d]",
+			 __func__,
+			 payload[0], payload[1], token);
+
+		if (payload[WRITEDONE_IDX_STATUS]) {
+			pr_err("%s: wrong WRITEDONE_IDX_STATUS[%d]\n",
+			       __func__,
+			       payload[WRITEDONE_IDX_STATUS]);
+			break;
+		}
+
+		spin_lock_irqsave(&port->dsp_lock, dsp_flags);
+		port->dsp_buf = token + 1;
+		if (port->dsp_buf == port->buf_cnt)
+			port->dsp_buf = 0;
+		spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
+
+		pr_debug("%s: WRITE_DONE: token=%d; dsp_buf=%d; cpu_buf=%d\n",
+			__func__,
+			token, port->dsp_buf, port->cpu_buf);
+
+		break;
+	} /* case USM_DATA_EVENT_WRITE_DONE */
+
+	case USM_SESSION_EVENT_SIGNAL_DETECT_RESULT: {
+		pr_debug("%s: US detect result: result=%d",
+			 __func__,
+			 payload[0]);
+
+		break;
+	} /* case USM_SESSION_EVENT_SIGNAL_DETECT_RESULT */
+
+	default:
+		pr_debug("%s: not supported code [0x%x]",
+			 __func__, data->opcode);
+		return 0;
+
+	} /* switch */
+
+	if (usc->cb)
+		usc->cb(data->opcode, token,
+			data->payload, usc->priv);
+
+	return 0;
+}
+
+uint32_t q6usm_get_ready_data(int dir, struct us_client *usc)
+{
+	uint32_t ret = 0xffffffff;
+
+	if ((usc != NULL) && ((dir == IN) || (dir == OUT)))
+		ret = usc->port[dir].dsp_buf;
+	return ret;
+}
+
+uint32_t q6usm_get_virtual_address(int dir,
+				   struct us_client *usc,
+				   struct vm_area_struct *vms)
+{
+	uint32_t ret = 0xffffffff;
+
+	if (vms && (usc != NULL) && ((dir == IN) || (dir == OUT))) {
+		struct us_port_data *port = &usc->port[dir];
+		ret = dma_mmap_coherent(NULL, vms,
+					port->data, port->phys,
+					port->buf_size * port->buf_cnt);
+	}
+	return ret;
+}
+
+static void q6usm_add_hdr(struct us_client *usc, struct apr_hdr *hdr,
+			  uint32_t pkt_size, bool cmd_flg)
+{
+	pr_debug("%s: pkt size=%d; cmd_flg=%d\n",
+		 __func__, pkt_size, cmd_flg);
+	pr_debug("**************\n");
+	mutex_lock(&usc->cmd_lock);
+	hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
+				       APR_HDR_LEN(sizeof(struct apr_hdr)),\
+				       APR_PKT_VER);
+	hdr->src_svc = ((struct apr_svc *)usc->apr)->id;
+	hdr->src_domain = APR_DOMAIN_APPS;
+	hdr->dest_svc = APR_SVC_USM;
+	hdr->dest_domain = APR_DOMAIN_ADSP;
+	hdr->src_port = (usc->session << 8) | 0x0001;
+	hdr->dest_port = (usc->session << 8) | 0x0001;
+	if (cmd_flg) {
+		hdr->token = usc->session;
+		atomic_set(&usc->cmd_state, 1);
+	}
+	hdr->pkt_size  = APR_PKT_SIZE(APR_HDR_SIZE, pkt_size);
+	mutex_unlock(&usc->cmd_lock);
+	return;
+}
+
+static void q6usm_add_mmaphdr(struct us_client *usc, struct apr_hdr *hdr,
+			      uint32_t pkt_size, bool cmd_flg)
+{
+	pr_debug("%s: pkt size=%d cmd_flg=%d\n",
+		 __func__, pkt_size, cmd_flg);
+	pr_debug("**************\n");
+	hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
+				       APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	hdr->src_port = 0;
+	hdr->dest_port = 0;
+	if (cmd_flg) {
+		hdr->token = 0;
+		atomic_set(&this_mmap.cmd_state, 1);
+	}
+	hdr->pkt_size  = pkt_size;
+	return;
+}
+
+static uint32_t q6usm_ext2int_format(uint32_t ext_format)
+{
+	uint32_t int_format = INVALID_FORMAT;
+	switch (ext_format) {
+	case FORMAT_USPS_EPOS:
+		int_format = US_POINT_EPOS_FORMAT;
+		break;
+	case FORMAT_USRAW:
+		int_format = US_RAW_FORMAT;
+		break;
+	default:
+		pr_err("%s: Invalid format[%d]\n", __func__, ext_format);
+		break;
+	}
+
+	return int_format;
+}
+
+int q6usm_open_read(struct us_client *usc,
+		    uint32_t format)
+{
+	uint32_t int_format = INVALID_FORMAT;
+	int rc = 0x00;
+	struct usm_stream_cmd_open_read open;
+
+	pr_debug("%s: session[%d]", __func__, usc->session);
+
+	if ((usc == NULL) || (usc->apr == NULL)) {
+		pr_err("%s: client or its apr is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	q6usm_add_hdr(usc, &open.hdr, sizeof(open), true);
+	open.hdr.opcode = USM_STREAM_CMD_OPEN_READ;
+	open.src_endpoint = 0; /* AFE */
+	open.pre_proc_top = 0; /* No preprocessing required */
+
+	int_format = q6usm_ext2int_format(format);
+	if (int_format == INVALID_FORMAT)
+		return -EINVAL;
+
+	open.uMode = STREAM_PRIORITY_NORMAL;
+	open.format = int_format;
+
+	rc = apr_send_pkt(usc->apr, (uint32_t *) &open);
+	if (rc < 0) {
+		pr_err("%s: open failed op[0x%x]rc[%d]\n",
+		       __func__, open.hdr.opcode, rc);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(usc->cmd_wait,
+				(atomic_read(&usc->cmd_state) == 0),
+				Q6USM_TIMEOUT_JIFFIES);
+	if (!rc) {
+		rc = -ETIME;
+		pr_err("%s: timeout, waited for OPEN_READ rc[%d]\n",
+		       __func__, rc);
+		goto fail_cmd;
+	} else
+		rc = 0;
+fail_cmd:
+	return rc;
+}
+
+
+int q6usm_enc_cfg_blk(struct us_client *usc, struct us_encdec_cfg* us_cfg)
+{
+	uint32_t int_format = INVALID_FORMAT;
+	struct usm_stream_cmd_encdec_cfg_blk  enc_cfg_obj;
+	struct usm_stream_cmd_encdec_cfg_blk  *enc_cfg = &enc_cfg_obj;
+	int rc = 0;
+	uint32_t total_cfg_size =
+		sizeof(struct usm_stream_cmd_encdec_cfg_blk);
+	uint32_t round_params_size = 0;
+	uint8_t  is_allocated = 0;
+
+
+	if ((usc == NULL) || (us_cfg == NULL)) {
+		pr_err("%s: wrong input", __func__);
+		return -EINVAL;
+	}
+
+	int_format = q6usm_ext2int_format(us_cfg->format_id);
+	if (int_format == INVALID_FORMAT) {
+		pr_err("%s: wrong input format[%d]",
+		       __func__, us_cfg->format_id);
+		return -EINVAL;
+	}
+
+	/* Transparent configuration data is after enc_cfg */
+	/* Integer number of u32s is requred */
+	round_params_size = ((us_cfg->params_size + 3)/4) * 4;
+	if (round_params_size > USM_MAX_CFG_DATA_SIZE) {
+		/* Dynamic allocated encdec_cfg_blk is required */
+		/* static part use */
+		round_params_size -= USM_MAX_CFG_DATA_SIZE;
+		total_cfg_size += round_params_size;
+		enc_cfg = kzalloc(total_cfg_size, GFP_KERNEL);
+		if (enc_cfg == NULL) {
+			pr_err("%s: enc_cfg[%d] allocation failed\n",
+			       __func__, total_cfg_size);
+			return -ENOMEM;
+		}
+		is_allocated = 1;
+	} else
+		round_params_size = 0;
+
+	q6usm_add_hdr(usc, &enc_cfg->hdr, total_cfg_size - APR_HDR_SIZE, true);
+
+	enc_cfg->hdr.opcode = USM_STREAM_CMD_SET_ENC_PARAM;
+	enc_cfg->param_id = USM_PARAM_ID_ENCDEC_ENC_CFG_BLK;
+	enc_cfg->param_size = sizeof(struct usm_encode_cfg_blk)+
+				round_params_size;
+	enc_cfg->enc_blk.frames_per_buf = 1;
+	enc_cfg->enc_blk.format_id = int_format;
+	enc_cfg->enc_blk.cfg_size = sizeof(struct usm_cfg_common)+
+				    USM_MAX_CFG_DATA_SIZE +
+				    round_params_size;
+	memcpy(&(enc_cfg->enc_blk.cfg_common), &(us_cfg->cfg_common),
+	       sizeof(struct usm_cfg_common));
+
+	/* Transparent data copy */
+	memcpy(enc_cfg->enc_blk.transp_data, us_cfg->params,
+	       us_cfg->params_size);
+	pr_debug("%s: cfg_size[%d], params_size[%d]\n",
+		__func__,
+		enc_cfg->enc_blk.cfg_size,
+		us_cfg->params_size);
+	pr_debug("%s: params[%d,%d,%d,%d, %d,%d,%d,%d]\n",
+		__func__,
+		enc_cfg->enc_blk.transp_data[0],
+		enc_cfg->enc_blk.transp_data[1],
+		enc_cfg->enc_blk.transp_data[2],
+		enc_cfg->enc_blk.transp_data[3],
+		enc_cfg->enc_blk.transp_data[4],
+		enc_cfg->enc_blk.transp_data[5],
+		enc_cfg->enc_blk.transp_data[6],
+		enc_cfg->enc_blk.transp_data[7]
+	       );
+	pr_debug("%s: srate:%d, ch=%d, bps= %d; dmap:0x%x; dev_id=0x%x\n",
+		__func__, enc_cfg->enc_blk.cfg_common.sample_rate,
+		enc_cfg->enc_blk.cfg_common.ch_cfg,
+		enc_cfg->enc_blk.cfg_common.bits_per_sample,
+		enc_cfg->enc_blk.cfg_common.data_map,
+		enc_cfg->enc_blk.cfg_common.dev_id);
+
+	rc = apr_send_pkt(usc->apr, (uint32_t *) enc_cfg);
+	if (rc < 0) {
+		pr_err("%s:Comamnd open failed\n", __func__);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(usc->cmd_wait,
+				(atomic_read(&usc->cmd_state) == 0),
+				Q6USM_TIMEOUT_JIFFIES);
+	if (!rc) {
+		rc = -ETIME;
+		pr_err("%s: timeout opcode[0x%x]\n",
+		       __func__, enc_cfg->hdr.opcode);
+	} else
+		rc = 0;
+
+fail_cmd:
+	if (is_allocated == 1)
+		kfree(enc_cfg);
+
+	return rc;
+}
+
+int q6usm_dec_cfg_blk(struct us_client *usc, struct us_encdec_cfg *us_cfg)
+{
+
+	uint32_t int_format = INVALID_FORMAT;
+	struct usm_stream_media_format_update dec_cfg_obj;
+	struct usm_stream_media_format_update *dec_cfg = &dec_cfg_obj;
+
+	int rc = 0;
+	uint32_t total_cfg_size = sizeof(struct usm_stream_media_format_update);
+	uint32_t round_params_size = 0;
+	uint8_t  is_allocated = 0;
+
+
+	if ((usc == NULL) || (us_cfg == NULL)) {
+		pr_err("%s: wrong input", __func__);
+		return -EINVAL;
+	}
+
+	int_format = q6usm_ext2int_format(us_cfg->format_id);
+	if (int_format == INVALID_FORMAT) {
+		pr_err("%s: wrong input format[%d]",
+		       __func__, us_cfg->format_id);
+		return -EINVAL;
+	}
+
+	/* Transparent configuration data is after enc_cfg */
+	/* Integer number of u32s is requred */
+	round_params_size = ((us_cfg->params_size + 3)/4) * 4;
+	if (round_params_size > USM_MAX_CFG_DATA_SIZE) {
+		/* Dynamic allocated encdec_cfg_blk is required */
+		/* static part use */
+		round_params_size -= USM_MAX_CFG_DATA_SIZE;
+		total_cfg_size += round_params_size;
+		dec_cfg = kzalloc(total_cfg_size, GFP_KERNEL);
+		if (dec_cfg == NULL) {
+			pr_err("%s:dec_cfg[%d] allocation failed\n",
+			       __func__, total_cfg_size);
+			return -ENOMEM;
+		}
+		is_allocated = 1;
+	} else { /* static transp_data is enough */
+		round_params_size = 0;
+	}
+
+	q6usm_add_hdr(usc, &dec_cfg->hdr, total_cfg_size - APR_HDR_SIZE, true);
+
+	dec_cfg->hdr.opcode = USM_DATA_CMD_MEDIA_FORMAT_UPDATE;
+	dec_cfg->format_id = int_format;
+	dec_cfg->cfg_size = sizeof(struct usm_cfg_common) +
+			    USM_MAX_CFG_DATA_SIZE +
+			    round_params_size;
+	memcpy(&(dec_cfg->cfg_common), &(us_cfg->cfg_common),
+	       sizeof(struct usm_cfg_common));
+	/* Transparent data copy */
+	memcpy(dec_cfg->transp_data, us_cfg->params, us_cfg->params_size);
+	pr_debug("%s: cfg_size[%d], params_size[%d]; parambytes[%d,%d,%d,%d]\n",
+		__func__,
+		dec_cfg->cfg_size,
+		us_cfg->params_size,
+		dec_cfg->transp_data[0],
+		dec_cfg->transp_data[1],
+		dec_cfg->transp_data[2],
+		dec_cfg->transp_data[3]
+	       );
+
+	rc = apr_send_pkt(usc->apr, (uint32_t *) dec_cfg);
+	if (rc < 0) {
+		pr_err("%s:Comamnd open failed\n", __func__);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(usc->cmd_wait,
+				(atomic_read(&usc->cmd_state) == 0),
+				Q6USM_TIMEOUT_JIFFIES);
+	if (!rc) {
+		rc = -ETIME;
+		pr_err("%s: timeout opcode[0x%x]\n",
+		       __func__, dec_cfg->hdr.opcode);
+	} else
+		rc = 0;
+
+fail_cmd:
+	if (is_allocated == 1)
+		kfree(dec_cfg);
+
+	return rc;
+}
+
+int q6usm_open_write(struct us_client *usc,
+		     uint32_t format)
+{
+	int rc = 0;
+	uint32_t int_format = INVALID_FORMAT;
+	struct usm_stream_cmd_open_write open;
+
+	pr_debug("%s: session[%d]", __func__, usc->session);
+
+	if ((usc == NULL) || (usc->apr == NULL)) {
+		pr_err("%s: APR handle NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	q6usm_add_hdr(usc, &open.hdr, sizeof(open), true);
+	open.hdr.opcode = USM_STREAM_CMD_OPEN_WRITE;
+
+	int_format = q6usm_ext2int_format(format);
+	if (int_format == INVALID_FORMAT) {
+		pr_err("%s: wrong format[%d]", __func__, format);
+		return -EINVAL;
+	}
+
+	open.format = int_format;
+
+	rc = apr_send_pkt(usc->apr, (uint32_t *) &open);
+	if (rc < 0) {
+		pr_err("%s:open failed op[0x%x]rc[%d]\n", \
+		       __func__, open.hdr.opcode, rc);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(usc->cmd_wait,
+				(atomic_read(&usc->cmd_state) == 0),
+				Q6USM_TIMEOUT_JIFFIES);
+	if (!rc) {
+		rc = -ETIME;
+		pr_err("%s:timeout. waited for OPEN_WRITR rc[%d]\n",
+		       __func__, rc);
+		goto fail_cmd;
+	} else
+		rc = 0;
+
+fail_cmd:
+	return rc;
+}
+
+int q6usm_run(struct us_client *usc, uint32_t flags,
+	      uint32_t msw_ts, uint32_t lsw_ts)
+{
+	struct usm_stream_cmd_run run;
+	int rc = 0;
+
+	if ((usc == NULL) || (usc->apr == NULL)) {
+		pr_err("%s: APR handle NULL\n", __func__);
+		return -EINVAL;
+	}
+	q6usm_add_hdr(usc, &run.hdr, sizeof(run), true);
+
+	run.hdr.opcode = USM_SESSION_CMD_RUN;
+	run.flags    = flags;
+	run.msw_ts   = msw_ts;
+	run.lsw_ts   = lsw_ts;
+
+	rc = apr_send_pkt(usc->apr, (uint32_t *) &run);
+	if (rc < 0) {
+		pr_err("%s: Commmand run failed[%d]\n", __func__, rc);
+		goto fail_cmd;
+	}
+
+	rc = wait_event_timeout(usc->cmd_wait,
+				(atomic_read(&usc->cmd_state) == 0),
+				Q6USM_TIMEOUT_JIFFIES);
+	if (!rc) {
+		rc = -ETIME;
+		pr_err("%s: timeout. waited for run success rc[%d]\n",
+		       __func__, rc);
+	} else
+		rc = 0;
+
+fail_cmd:
+	return rc;
+}
+
+
+int q6usm_memory_map(struct us_client *usc, uint32_t buf_add, int dir,
+		     uint32_t bufsz, uint32_t bufcnt)
+{
+	struct usm_stream_cmd_memory_map mem_map;
+	int rc = 0;
+
+	if ((usc == NULL) || (usc->apr == NULL) || (this_mmap.apr == NULL)) {
+		pr_err("%s: APR handle NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	q6usm_add_mmaphdr(usc, &mem_map.hdr,
+			  sizeof(struct usm_stream_cmd_memory_map), true);
+	mem_map.hdr.opcode = USM_SESSION_CMD_MEMORY_MAP;
+
+	mem_map.buf_add = buf_add;
+	mem_map.buf_size = bufsz * bufcnt;
+	mem_map.mempool_id = 0;
+
+	pr_debug("%s: buf add[%x]  buf_add_parameter[%x]\n",
+		 __func__, mem_map.buf_add, buf_add);
+
+	rc = apr_send_pkt(this_mmap.apr, (uint32_t *) &mem_map);
+	if (rc < 0) {
+		pr_err("%s: mem_map op[0x%x]rc[%d]\n",
+		       __func__, mem_map.hdr.opcode, rc);
+		goto fail_cmd;
+	}
+
+	rc = wait_event_timeout(this_mmap.cmd_wait,
+				(atomic_read(&this_mmap.cmd_state) == 0),
+				Q6USM_TIMEOUT_JIFFIES);
+	if (!rc) {
+		rc = -ETIME;
+		pr_err("%s: timeout. waited for memory_map\n", __func__);
+	} else
+		rc = 0;
+fail_cmd:
+	return rc;
+}
+
+int q6usm_memory_unmap(struct us_client *usc, uint32_t buf_add, int dir)
+{
+	struct usm_stream_cmd_memory_unmap mem_unmap;
+	int rc = 0;
+
+	if ((usc == NULL) || (usc->apr == NULL) || (this_mmap.apr == NULL)) {
+		pr_err("%s: APR handle NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	q6usm_add_mmaphdr(usc, &mem_unmap.hdr,
+			  sizeof(struct usm_stream_cmd_memory_unmap), true);
+	mem_unmap.hdr.opcode = USM_SESSION_CMD_MEMORY_UNMAP;
+	mem_unmap.buf_add = buf_add;
+
+	rc = apr_send_pkt(this_mmap.apr, (uint32_t *) &mem_unmap);
+	if (rc < 0) {
+		pr_err("%s:mem_unmap op[0x%x]rc[%d]\n",
+		       __func__, mem_unmap.hdr.opcode, rc);
+		goto fail_cmd;
+	}
+
+	rc = wait_event_timeout(this_mmap.cmd_wait,
+				(atomic_read(&this_mmap.cmd_state) == 0),
+				Q6USM_TIMEOUT_JIFFIES);
+	if (!rc) {
+		rc = -ETIME;
+		pr_err("%s: timeout. waited for memory_map\n", __func__);
+	} else
+		rc = 0;
+fail_cmd:
+	return rc;
+}
+
+int q6usm_read(struct us_client *usc, uint32_t read_ind)
+{
+	struct usm_stream_cmd_read read;
+	struct us_port_data *port = NULL;
+	int rc = 0;
+	u32 read_counter = 0;
+	u32 loop_ind = 0;
+
+	if ((usc == NULL) || (usc->apr == NULL)) {
+		pr_err("%s: APR handle NULL\n", __func__);
+		return -EINVAL;
+	}
+	port = &usc->port[OUT];
+
+	if (read_ind > port->buf_cnt) {
+		pr_err("%s: wrong read_ind[%d]\n",
+		       __func__, read_ind);
+		return -EINVAL;
+	}
+	if (read_ind == port->cpu_buf) {
+		pr_err("%s: no free region\n", __func__);
+		return 0;
+	}
+
+	if (read_ind > port->cpu_buf) { /* 1 range */
+		read_counter = read_ind - port->cpu_buf;
+	} else { /* 2 ranges */
+		read_counter = (port->buf_cnt - port->cpu_buf) + read_ind;
+	}
+
+	q6usm_add_hdr(usc, &read.hdr, (sizeof(read) - APR_HDR_SIZE), false);
+
+	read.hdr.opcode = USM_DATA_CMD_READ;
+	read.buf_size = port->buf_size;
+
+	for (loop_ind = 0; loop_ind < read_counter; ++loop_ind) {
+		u32 temp_cpu_buf = port->cpu_buf;
+
+		read.buf_add = (uint32_t)(port->phys) +
+			       port->buf_size * (port->cpu_buf);
+		read.uid = port->cpu_buf;
+		read.hdr.token = port->cpu_buf;
+		read.counter = 1;
+
+		++(port->cpu_buf);
+		if (port->cpu_buf == port->buf_cnt)
+			port->cpu_buf = 0;
+
+		rc = apr_send_pkt(usc->apr, (uint32_t *) &read);
+
+		if (rc < 0) {
+			port->cpu_buf = temp_cpu_buf;
+
+			pr_err("%s:read op[0x%x]rc[%d]\n",
+			       __func__, read.hdr.opcode, rc);
+			break;
+		} else
+			rc = 0;
+	} /* bufs loop */
+
+	return rc;
+}
+
+int q6usm_write(struct us_client *usc, uint32_t write_ind)
+{
+	int rc = 0;
+	struct usm_stream_cmd_write cmd_write;
+	struct us_port_data *port = NULL;
+	u32 current_dsp_buf = 0;
+
+	if ((usc == NULL) || (usc->apr == NULL)) {
+		pr_err("%s: APR handle NULL\n", __func__);
+		return -EINVAL;
+	}
+	port = &usc->port[IN];
+
+	current_dsp_buf = port->dsp_buf;
+	/* free region, caused by new dsp_buf report from DSP, */
+	/* can be only extended */
+	if (port->cpu_buf >= current_dsp_buf) {
+		/* 2 -part free region, including empty buffer */
+		if ((write_ind <= port->cpu_buf)  &&
+		    (write_ind > current_dsp_buf)) {
+			pr_err("%s: wrong w_ind[%d]; d_buf=%d; c_buf=%d\n",
+			       __func__, write_ind,
+			       current_dsp_buf, port->cpu_buf);
+			return -EINVAL;
+		}
+	} else {
+		/* 1 -part free region */
+		if ((write_ind <= port->cpu_buf)  ||
+		    (write_ind > current_dsp_buf)) {
+			pr_err("%s: wrong w_ind[%d]; d_buf=%d; c_buf=%d\n",
+			       __func__, write_ind,
+			       current_dsp_buf, port->cpu_buf);
+			return -EINVAL;
+		}
+	}
+
+	q6usm_add_hdr(usc, &cmd_write.hdr,
+		      (sizeof(cmd_write) - APR_HDR_SIZE), false);
+
+	cmd_write.hdr.opcode = USM_DATA_CMD_WRITE;
+	cmd_write.buf_size = port->buf_size;
+
+	while (port->cpu_buf != write_ind) {
+		u32 temp_cpu_buf = port->cpu_buf;
+
+		cmd_write.buf_add = (uint32_t)(port->phys) +
+				    port->buf_size * (port->cpu_buf);
+		cmd_write.uid = port->cpu_buf;
+		cmd_write.hdr.token = port->cpu_buf;
+
+		pr_debug("%s:buf addr[0x%x] size[%d] token[%d] uid[%d]\n",
+			 __func__, cmd_write.buf_add, cmd_write.buf_size,
+			 cmd_write.hdr.token, cmd_write.uid);
+		pr_debug("%s: data=0x%p\n", __func__, port->data);
+
+		++(port->cpu_buf);
+		if (port->cpu_buf == port->buf_cnt)
+			port->cpu_buf = 0;
+
+		rc = apr_send_pkt(usc->apr, (uint32_t *) &cmd_write);
+
+		if (rc < 0) {
+			port->cpu_buf = temp_cpu_buf;
+			pr_err("%s:write op[0x%x];rc[%d];cpu_buf[%d]\n",
+			       __func__, cmd_write.hdr.opcode,
+			       rc, port->cpu_buf);
+			break;
+		}
+
+		rc = 0;
+	}
+
+	pr_debug("%s:exit: rc=%d; write_ind=%d; cpu_buf=%d; dsp_buf=%d\n",
+		__func__, rc, write_ind, port->cpu_buf, port->dsp_buf);
+
+	return rc;
+}
+
+bool q6usm_is_write_buf_full(struct us_client *usc, uint32_t* free_region)
+{
+	struct us_port_data *port = NULL;
+	u32 cpu_buf = 0;
+
+	if ((usc == NULL) || !free_region) {
+		pr_err("%s: input data wrong\n", __func__);
+		return false;
+	}
+	port = &usc->port[IN];
+	cpu_buf = port->cpu_buf + 1;
+	if (cpu_buf == port->buf_cnt)
+		cpu_buf = 0;
+
+	*free_region = port->dsp_buf;
+
+	return cpu_buf == *free_region;
+}
+
+int q6usm_cmd(struct us_client *usc, int cmd)
+{
+	struct apr_hdr hdr;
+	int rc = 0;
+	atomic_t *state;
+
+	if ((usc == NULL) || (usc->apr == NULL)) {
+		pr_err("%s: APR handle NULL\n", __func__);
+		return -EINVAL;
+	}
+	q6usm_add_hdr(usc, &hdr, (sizeof(hdr) - APR_HDR_SIZE), true);
+	switch (cmd) {
+	case CMD_CLOSE:
+		hdr.opcode = USM_STREAM_CMD_CLOSE;
+		state = &usc->cmd_state;
+		break;
+
+	default:
+		pr_err("%s:Invalid format[%d]\n", __func__, cmd);
+		goto fail_cmd;
+	}
+
+	pr_debug("%s:session[%d]opcode[0x%x] ", __func__,
+		 usc->session,  hdr.opcode);
+	rc = apr_send_pkt(usc->apr, (uint32_t *) &hdr);
+	if (rc < 0) {
+		pr_err("%s: Command 0x%x failed\n", __func__, hdr.opcode);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(usc->cmd_wait, (atomic_read(state) == 0),
+				Q6USM_TIMEOUT_JIFFIES);
+	if (!rc) {
+		rc = -ETIME;
+		pr_err("%s:timeout. waited for response opcode[0x%x]\n",
+		       __func__, hdr.opcode);
+	} else
+		rc = 0;
+fail_cmd:
+	return rc;
+}
+
+int q6usm_set_us_detection(struct us_client *usc,
+			   struct usm_session_cmd_detect_info *detect_info,
+			   uint16_t detect_info_size)
+{
+	int rc = 0;
+
+	if ((usc == NULL) ||
+	    (detect_info_size == 0) ||
+	    (detect_info == NULL)) {
+		pr_err("%s: wrong input: usc=0x%p, inf_size=%d; info=0x%p",
+		       __func__,
+		       usc,
+		       detect_info_size,
+		       detect_info);
+		return -EINVAL;
+	}
+
+	q6usm_add_hdr(usc, &detect_info->hdr,
+		      detect_info_size - APR_HDR_SIZE, true);
+
+	detect_info->hdr.opcode = USM_SESSION_CMD_SIGNAL_DETECT_MODE;
+
+	rc = apr_send_pkt(usc->apr, (uint32_t *)detect_info);
+	if (rc < 0) {
+		pr_err("%s:Comamnd signal detect failed\n", __func__);
+		return -EINVAL;
+	}
+	rc = wait_event_timeout(usc->cmd_wait,
+				(atomic_read(&usc->cmd_state) == 0),
+				Q6USM_TIMEOUT_JIFFIES);
+	if (!rc) {
+		rc = -ETIME;
+		pr_err("%s: CMD_SIGNAL_DETECT_MODE: timeout=%d\n",
+		       __func__, Q6USM_TIMEOUT_JIFFIES);
+	} else
+		rc = 0;
+
+	return rc;
+}
+
+static int __init q6usm_init(void)
+{
+	pr_debug("%s\n", __func__);
+	init_waitqueue_head(&this_mmap.cmd_wait);
+	memset(session, 0, sizeof(session));
+	return 0;
+}
+
+device_initcall(q6usm_init);
+
+MODULE_DESCRIPTION("Interface with QDSP6:USM");
+MODULE_VERSION(DRV_VERSION);
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
new file mode 100644
index 0000000..1338e86
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
@@ -0,0 +1,116 @@
+/* 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
+ * 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 __Q6_USM_H__
+#define __Q6_USM_H__
+
+#include <mach/qdsp6v2/apr_us.h>
+
+/* cyclic buffer with 1 gap support */
+#define USM_MIN_BUF_CNT 3
+
+#define FORMAT_USPS_EPOS	0x00000000
+#define FORMAT_USRAW		0x00000001
+#define INVALID_FORMAT		0xffffffff
+
+#define IN			0x000
+#define OUT			0x001
+
+#define USM_WRONG_TOKEN		0xffffffff
+#define USM_UNDEF_TOKEN		0xfffffffe
+
+#define CMD_CLOSE		0x0004
+
+/* bit 0:1 represents priority of stream */
+#define STREAM_PRIORITY_NORMAL	0x0000
+#define STREAM_PRIORITY_LOW	0x0001
+#define STREAM_PRIORITY_HIGH	0x0002
+
+/* bit 4 represents META enable of encoded data buffer */
+#define BUFFER_META_ENABLE	0x0010
+
+struct us_region {
+	dma_addr_t	phys;
+	/* If == NULL, the region isn't allocated */
+	void		*data;
+	/* number of buffers in the region */
+	uint32_t	buf_cnt;
+	/* size of buffer */
+	uint32_t	buf_size;
+};
+
+struct us_port_data {
+	dma_addr_t	phys;
+	/* cyclic region of buffers with 1 gap */
+	void		*data;
+	/* number of buffers in the region */
+	uint32_t	buf_cnt;
+	/* size of buffer */
+	uint32_t	buf_size;
+	/* TX: write index */
+	uint32_t	dsp_buf;
+	/* TX: read index */
+	uint32_t	cpu_buf;
+	/* expected token from dsp */
+	uint32_t	expected_token;
+	/* read or write locks */
+	struct mutex	lock;
+	spinlock_t	dsp_lock;
+};
+
+struct us_client {
+	int			session;
+	/* idx:1 out port, 0: in port*/
+	struct us_port_data	port[2];
+
+	struct apr_svc		*apr;
+	struct mutex		cmd_lock;
+
+	atomic_t		cmd_state;
+	atomic_t		eos_state;
+	wait_queue_head_t	cmd_wait;
+
+	void (*cb)(uint32_t, uint32_t, uint32_t *, void *);
+	void			*priv;
+};
+
+int q6usm_run(struct us_client *usc, uint32_t flags,
+	      uint32_t msw_ts, uint32_t lsw_ts);
+int q6usm_cmd(struct us_client *usc, int cmd);
+int q6usm_us_client_buf_alloc(unsigned int dir, struct us_client *usc,
+			      unsigned int bufsz, unsigned int bufcnt);
+int q6usm_enc_cfg_blk(struct us_client *usc, struct us_encdec_cfg *us_cfg);
+int q6usm_dec_cfg_blk(struct us_client *usc, struct us_encdec_cfg *us_cfg);
+int q6usm_read(struct us_client *usc, uint32_t read_ind);
+struct us_client *q6usm_us_client_alloc(
+	void (*cb)(uint32_t, uint32_t, uint32_t *, void *),
+	void *priv);
+int q6usm_open_read(struct us_client *usc, uint32_t format);
+void q6usm_us_client_free(struct us_client *usc);
+int q6usm_memory_map(struct us_client *usc, uint32_t buf_add,
+		     int dir, uint32_t bufsz, uint32_t bufcnt);
+int q6usm_memory_unmap(struct us_client *usc, uint32_t buf_add,
+		       int dir);
+
+uint32_t q6usm_get_ready_data(int dir, struct us_client *usc);
+uint32_t q6usm_get_virtual_address(int dir, struct us_client *usc,
+				   struct vm_area_struct *vms);
+
+int q6usm_open_write(struct us_client *usc,  uint32_t format);
+int q6usm_write(struct us_client *usc, uint32_t write_ind);
+bool q6usm_is_write_buf_full(struct us_client *usc, uint32_t* free_region);
+
+int q6usm_set_us_detection(struct us_client *usc,
+			   struct usm_session_cmd_detect_info *detect_info,
+			   uint16_t detect_info_size);
+
+#endif /* __Q6_USM_H__ */
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
new file mode 100644
index 0000000..614339b
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
@@ -0,0 +1,1378 @@
+/* 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
+ * 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/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/input.h>
+#include <linux/uaccess.h>
+#include <linux/time.h>
+#include <asm/mach-types.h>
+#include <sound/apr_audio.h>
+#include <mach/qdsp6v2/usf.h>
+#include "q6usm.h"
+#include "usfcdev.h"
+
+/* The driver version*/
+#define DRV_VERSION "1.3.1"
+
+/* Standard timeout in the asynchronous ops */
+#define USF_TIMEOUT_JIFFIES (1*HZ) /* 1 sec */
+
+/* Undefined USF device */
+#define USF_UNDEF_DEV_ID 0xffff
+
+/* RX memory mapping flag */
+#define USF_VM_WRITE 2
+
+/* Number of events, copied from the user space to kernel one */
+#define USF_EVENTS_PORTION_SIZE 20
+
+/* Indexes in range definitions */
+#define MIN_IND 0
+#define MAX_IND 1
+
+/* The coordinates indexes */
+#define X_IND 0
+#define Y_IND 1
+#define Z_IND 2
+
+/* Place for opreation result, received from QDSP6 */
+#define APR_RESULT_IND 1
+
+/* Place for US detection result, received from QDSP6 */
+#define APR_US_DETECT_RESULT_IND 0
+
+/* The driver states */
+enum usf_state_type {
+	USF_IDLE_STATE,
+	USF_OPENED_STATE,
+	USF_CONFIGURED_STATE,
+	USF_WORK_STATE,
+	USF_ERROR_STATE
+};
+
+/* The US detection status upon FW/HW based US detection results */
+enum usf_us_detect_type {
+	USF_US_DETECT_UNDEF,
+	USF_US_DETECT_YES,
+	USF_US_DETECT_NO
+};
+
+struct usf_xx_type {
+	/* Name of the client - event calculator */
+	char client_name[USF_MAX_CLIENT_NAME_SIZE];
+	/* The driver state in TX or RX direction */
+	enum usf_state_type usf_state;
+	/* wait for q6 events mechanism */
+	wait_queue_head_t wait;
+	/* IF with q6usm info */
+	struct us_client *usc;
+	/* Q6:USM' Encoder/decoder configuration */
+	struct us_encdec_cfg encdec_cfg;
+	/* Shared buffer (with Q6:USM) size */
+	uint32_t buffer_size;
+	/* Number of the shared buffers (with Q6:USM) */
+	uint32_t buffer_count;
+	/* Shared memory (Cyclic buffer with 1 gap) control */
+	uint32_t new_region;
+	uint32_t prev_region;
+	/* Q6:USM's events handler */
+	void (*cb)(uint32_t, uint32_t, uint32_t *, void *);
+	/* US detection result */
+	enum usf_us_detect_type us_detect_type;
+	/* User's update info isn't acceptable */
+	u8 user_upd_info_na;
+};
+
+struct usf_type {
+	/* TX device component configuration & control */
+	struct usf_xx_type usf_tx;
+	/* RX device component configuration & control */
+	struct usf_xx_type usf_rx;
+	/* Index into the opened device container */
+	/* To prevent mutual usage of the same device */
+	uint16_t dev_ind;
+	/* Event types, supported by device */
+	uint16_t event_types;
+	/*  The device is "input" module registered client */
+	struct input_dev *input_if;
+	/*  The event source */
+	int event_src;
+	/* Bitmap of types of events, conflicting to USF's ones */
+	uint16_t conflicting_event_types;
+	/* Bitmap of types of events from devs, conflicting with USF */
+	uint16_t conflicting_event_filters;
+};
+
+/* The MAX number of the supported devices */
+#define MAX_DEVS_NUMBER	1
+
+/* The opened devices container */
+static const int s_event_src_map[] = {
+	BTN_TOOL_PEN, /* US_INPUT_SRC_PEN*/
+	0,            /* US_INPUT_SRC_FINGER */
+	0,            /* US_INPUT_SRC_UNDEF */
+};
+
+/* The opened devices container */
+static int s_opened_devs[MAX_DEVS_NUMBER];
+
+#define USF_NAME_PREFIX "USF_"
+#define USF_NAME_PREFIX_SIZE 4
+
+static void usf_rx_cb(uint32_t opcode, uint32_t token,
+		      uint32_t *payload, void *priv)
+{
+	struct usf_xx_type *usf_xx = (struct usf_xx_type *) priv;
+
+	if (usf_xx == NULL) {
+		pr_err("%s: the private data is NULL\n", __func__);
+		return;
+	}
+
+	switch (opcode) {
+	case USM_DATA_EVENT_WRITE_DONE:
+		wake_up(&usf_xx->wait);
+		break;
+	default:
+		break;
+	}
+}
+
+static void usf_tx_cb(uint32_t opcode, uint32_t token,
+		      uint32_t *payload, void *priv)
+{
+	struct usf_xx_type *usf_xx = (struct usf_xx_type *) priv;
+
+	if (usf_xx == NULL) {
+		pr_err("%s: the private data is NULL\n", __func__);
+		return;
+	}
+
+	switch (opcode) {
+	case USM_DATA_EVENT_READ_DONE:
+		if (token == USM_WRONG_TOKEN)
+			usf_xx->usf_state = USF_ERROR_STATE;
+		usf_xx->new_region = token;
+		wake_up(&usf_xx->wait);
+		break;
+
+	case USM_SESSION_EVENT_SIGNAL_DETECT_RESULT:
+		usf_xx->us_detect_type = (payload[APR_US_DETECT_RESULT_IND]) ?
+					USF_US_DETECT_YES :
+					USF_US_DETECT_NO;
+
+		wake_up(&usf_xx->wait);
+		break;
+
+	case APR_BASIC_RSP_RESULT:
+		if (payload[APR_RESULT_IND]) {
+			usf_xx->usf_state = USF_ERROR_STATE;
+			usf_xx->new_region = USM_WRONG_TOKEN;
+			wake_up(&usf_xx->wait);
+		}
+		break;
+
+	default:
+		break;
+	}
+}
+
+static void release_xx(struct usf_xx_type *usf_xx)
+{
+	if (usf_xx != NULL) {
+		if (usf_xx->usc) {
+			q6usm_us_client_free(usf_xx->usc);
+			usf_xx->usc = NULL;
+		}
+
+		if (usf_xx->encdec_cfg.params != NULL) {
+			kfree(usf_xx->encdec_cfg.params);
+			usf_xx->encdec_cfg.params = NULL;
+		}
+	}
+}
+
+static void usf_disable(struct usf_xx_type *usf_xx)
+{
+	if (usf_xx != NULL) {
+		if ((usf_xx->usf_state != USF_IDLE_STATE) &&
+		    (usf_xx->usf_state != USF_OPENED_STATE)) {
+			(void)q6usm_cmd(usf_xx->usc, CMD_CLOSE);
+			usf_xx->usf_state = USF_OPENED_STATE;
+			wake_up(&usf_xx->wait);
+		}
+		release_xx(usf_xx);
+	}
+}
+
+static int config_xx(struct usf_xx_type *usf_xx, struct us_xx_info_type *config)
+{
+	int rc = 0;
+	uint16_t data_map_size = 0;
+
+	if ((usf_xx == NULL) ||
+	    (config == NULL))
+		return -EINVAL;
+
+	data_map_size = sizeof(usf_xx->encdec_cfg.cfg_common.data_map);
+
+	if (config->client_name != NULL) {
+		if (strncpy_from_user(usf_xx->client_name,
+				      config->client_name,
+				      sizeof(usf_xx->client_name) - 1) < 0) {
+			pr_err("%s: get client name failed\n", __func__);
+			return -EINVAL;
+		}
+	}
+
+	pr_debug("%s: name=%s; buf_size:%d; dev_id:0x%x; sample_rate:%d\n",
+		__func__, usf_xx->client_name, config->buf_size,
+		config->dev_id, config->sample_rate);
+
+	pr_debug("%s: buf_num:%d; format:%d; port_cnt:%d; data_size=%d\n",
+		__func__, config->buf_num, config->stream_format,
+		config->port_cnt, config->params_data_size);
+
+	pr_debug("%s: p_id[0]=%d, p_id[1]=%d, p_id[2]=%d, p_id[3]=%d\n",
+		__func__,
+		config->port_id[0],
+		config->port_id[1],
+		config->port_id[2],
+		config->port_id[3]);
+
+	if (data_map_size < config->port_cnt) {
+		pr_err("%s: number of supported ports:%d < requested:%d\n",
+			__func__,
+			data_map_size,
+			config->port_cnt);
+		return -EINVAL;
+	}
+
+	/* q6usm allocation & configuration */
+	usf_xx->buffer_size = config->buf_size;
+	usf_xx->buffer_count = config->buf_num;
+	usf_xx->encdec_cfg.cfg_common.bits_per_sample =
+				config->bits_per_sample;
+	usf_xx->encdec_cfg.cfg_common.sample_rate = config->sample_rate;
+	/* AFE port e.g. AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_RX */
+	usf_xx->encdec_cfg.cfg_common.dev_id = config->dev_id;
+
+	usf_xx->encdec_cfg.cfg_common.ch_cfg = config->port_cnt;
+	memcpy((void *)&usf_xx->encdec_cfg.cfg_common.data_map,
+	       (void *)config->port_id,
+	       config->port_cnt);
+	if (rc) {
+		pr_err("%s: ports offsets copy failure\n", __func__);
+		return -EINVAL;
+	}
+
+	usf_xx->encdec_cfg.format_id = config->stream_format;
+	usf_xx->encdec_cfg.params_size = config->params_data_size;
+	usf_xx->user_upd_info_na = 1; /* it's used in US_GET_TX_UPDATE */
+
+	if (config->params_data_size > 0) { /* transparent data copy */
+		usf_xx->encdec_cfg.params = kzalloc(config->params_data_size,
+						    GFP_KERNEL);
+		if (usf_xx->encdec_cfg.params == NULL) {
+			pr_err("%s: params memory alloc[%d] failure\n",
+				__func__,
+				config->params_data_size);
+			return -ENOMEM;
+		}
+		rc = copy_from_user(usf_xx->encdec_cfg.params,
+				    config->params_data,
+				    config->params_data_size);
+		if (rc) {
+			pr_err("%s: transparent data copy failure\n",
+			       __func__);
+			kfree(usf_xx->encdec_cfg.params);
+			usf_xx->encdec_cfg.params = NULL;
+			return -EFAULT;
+		}
+		pr_debug("%s: params_size[%d]; params[%d,%d,%d,%d, %d]\n",
+			 __func__,
+			 config->params_data_size,
+			 usf_xx->encdec_cfg.params[0],
+			 usf_xx->encdec_cfg.params[1],
+			 usf_xx->encdec_cfg.params[2],
+			 usf_xx->encdec_cfg.params[3],
+			 usf_xx->encdec_cfg.params[4]
+			);
+	}
+
+	usf_xx->usc = q6usm_us_client_alloc(usf_xx->cb, (void *)usf_xx);
+	if (!usf_xx->usc) {
+		pr_err("%s: Could not allocate q6usm client\n", __func__);
+		rc = -EFAULT;
+	}
+
+	return rc;
+}
+
+static bool usf_match(uint16_t event_type_ind, struct input_dev *dev)
+{
+	bool rc = false;
+
+	rc = (event_type_ind < MAX_EVENT_TYPE_NUM) &&
+		((dev->name == NULL) ||
+		strncmp(dev->name, USF_NAME_PREFIX, USF_NAME_PREFIX_SIZE));
+	pr_debug("%s: name=[%s]; rc=%d\n",
+		 __func__, dev->name, rc);
+
+	return rc;
+}
+
+static bool usf_register_conflicting_events(uint16_t event_types)
+{
+	bool rc = true;
+	uint16_t ind = 0;
+	uint16_t mask = 1;
+
+	for (ind = 0; ind < MAX_EVENT_TYPE_NUM; ++ind) {
+		if (event_types & mask) {
+			rc = usfcdev_register(ind, usf_match);
+			if (!rc)
+				break;
+		}
+		mask = mask << 1;
+	}
+
+	return rc;
+}
+
+static void usf_unregister_conflicting_events(uint16_t event_types)
+{
+	uint16_t ind = 0;
+	uint16_t mask = 1;
+
+	for (ind = 0; ind < MAX_EVENT_TYPE_NUM; ++ind) {
+		if (event_types & mask)
+			usfcdev_unregister(ind);
+		mask = mask << 1;
+	}
+}
+
+static void usf_set_event_filters(struct usf_type *usf, uint16_t event_filters)
+{
+	uint16_t ind = 0;
+	uint16_t mask = 1;
+
+	if (usf->conflicting_event_filters != event_filters) {
+		for (ind = 0; ind < MAX_EVENT_TYPE_NUM; ++ind) {
+			if (usf->conflicting_event_types & mask)
+				usfcdev_set_filter(ind, event_filters&mask);
+			mask = mask << 1;
+		}
+		usf->conflicting_event_filters = event_filters;
+	}
+}
+
+static int register_input_device(struct usf_type *usf_info,
+				 struct us_input_info_type *input_info)
+{
+	int rc = 0;
+	struct input_dev *input_dev = NULL;
+	bool ret = true;
+
+	if ((usf_info == NULL) ||
+	    (input_info == NULL) ||
+	    !(input_info->event_types & USF_ALL_EVENTS)) {
+		pr_err("%s: wrong input parameter(s)\n", __func__);
+		return -EINVAL;
+	}
+
+	if (usf_info->input_if != NULL) {
+		pr_err("%s: input_if is already allocated\n", __func__);
+		return -EFAULT;
+	}
+
+	input_dev = input_allocate_device();
+	if (input_dev == NULL) {
+		pr_err("%s: input_allocate_device() failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	/* Common part configuration */
+	input_dev->name = (const char *)(usf_info->usf_tx.client_name);
+	input_dev->phys = NULL;
+	input_dev->id.bustype = BUS_HOST;
+	input_dev->id.vendor  = 0x0001;
+	input_dev->id.product = 0x0001;
+	input_dev->id.version = 0x0001;
+
+	if (input_info->event_types & USF_TSC_EVENT) {
+		/* TSC part configuration */
+		input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+		input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+		input_set_abs_params(input_dev, ABS_X,
+				     input_info->tsc_x_dim[MIN_IND],
+				     input_info->tsc_x_dim[MAX_IND],
+				     0, 0);
+		input_set_abs_params(input_dev, ABS_Y,
+				     input_info->tsc_y_dim[MIN_IND],
+				     input_info->tsc_y_dim[MAX_IND],
+				     0, 0);
+		input_set_abs_params(input_dev, ABS_DISTANCE,
+				     input_info->tsc_z_dim[MIN_IND],
+				     input_info->tsc_z_dim[MAX_IND],
+				     0, 0);
+
+		input_set_abs_params(input_dev, ABS_PRESSURE,
+				     input_info->tsc_pressure[MIN_IND],
+				     input_info->tsc_pressure[MAX_IND], 0, 0);
+
+		input_set_abs_params(input_dev, ABS_TILT_X,
+				     input_info->tsc_x_tilt[MIN_IND],
+				     input_info->tsc_x_tilt[MAX_IND],
+				     0, 0);
+		input_set_abs_params(input_dev, ABS_TILT_Y,
+				     input_info->tsc_y_tilt[MIN_IND],
+				     input_info->tsc_y_tilt[MAX_IND],
+				     0, 0);
+	}
+
+	if (input_info->event_types & USF_MOUSE_EVENT) {
+		/* Mouse part configuration */
+		input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+
+		input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
+							BIT_MASK(BTN_RIGHT) |
+							BIT_MASK(BTN_MIDDLE);
+		input_dev->relbit[0] =  BIT_MASK(REL_X) |
+					BIT_MASK(REL_Y) |
+					BIT_MASK(REL_Z);
+	}
+
+	if (input_info->event_types & USF_KEYBOARD_EVENT) {
+		/* Keyboard part configuration */
+		input_dev->evbit[0] |= BIT_MASK(EV_KEY);
+
+		/* All keys are permitted */
+		memset(input_dev->keybit, 0xff, sizeof(input_dev->keybit));
+	}
+
+	if (input_info->event_src < ARRAY_SIZE(s_event_src_map))
+		usf_info->event_src = s_event_src_map[input_info->event_src];
+	else
+		usf_info->event_src = 0;
+
+	if (usf_info->event_src)
+		input_set_capability(input_dev, EV_KEY, usf_info->event_src);
+
+	rc = input_register_device(input_dev);
+	if (rc) {
+		pr_err("%s: input_register_device() failed; rc=%d\n",
+		       __func__, rc);
+		input_free_device(input_dev);
+	} else {
+		usf_info->input_if = input_dev;
+		usf_info->event_types = input_info->event_types;
+		pr_debug("%s: input device[%s] was registered\n",
+			__func__, input_dev->name);
+		ret = usf_register_conflicting_events(
+					input_info->conflicting_event_types);
+		if (ret)
+			usf_info->conflicting_event_types =
+				input_info->conflicting_event_types;
+	}
+
+	return rc;
+}
+
+static void notify_tsc_event(struct usf_type *usf_info,
+			     struct point_event_type *pe)
+{
+	struct input_dev *input_if = usf_info->input_if;
+
+	input_report_abs(input_if, ABS_X, pe->coordinates[X_IND]);
+	input_report_abs(input_if, ABS_Y, pe->coordinates[Y_IND]);
+	input_report_abs(input_if, ABS_DISTANCE, pe->coordinates[Z_IND]);
+
+	input_report_abs(input_if, ABS_TILT_X, pe->inclinations[X_IND]);
+	input_report_abs(input_if, ABS_TILT_Y, pe->inclinations[Y_IND]);
+
+	input_report_abs(input_if, ABS_PRESSURE, pe->pressure);
+	input_report_key(input_if, BTN_TOUCH, !!(pe->pressure));
+
+	if (usf_info->event_src)
+		input_report_key(input_if, usf_info->event_src, 1);
+
+	input_sync(input_if);
+
+	pr_debug("%s: TSC event: xyz[%d;%d;%d], incl[%d;%d], pressure[%d]\n",
+		 __func__,
+		 pe->coordinates[X_IND],
+		 pe->coordinates[Y_IND],
+		 pe->coordinates[Z_IND],
+		 pe->inclinations[X_IND],
+		 pe->inclinations[Y_IND],
+		 pe->pressure);
+}
+
+static void notify_mouse_event(struct input_dev *input_if,
+			       struct mouse_event_type *me)
+{
+	if (me == NULL) {
+		pr_err("%s: mouse event is NULL\n", __func__);
+		return;
+	}
+
+	input_report_rel(input_if, REL_X, me->rels[X_IND]);
+	input_report_rel(input_if, REL_Y, me->rels[Y_IND]);
+	input_report_rel(input_if, REL_Z, me->rels[Z_IND]);
+
+	input_report_key(input_if, BTN_LEFT,
+			 me->buttons_states & USF_BUTTON_LEFT_MASK);
+	input_report_key(input_if, BTN_MIDDLE,
+			 me->buttons_states & USF_BUTTON_MIDDLE_MASK);
+	input_report_key(input_if, BTN_RIGHT,
+			 me->buttons_states & USF_BUTTON_RIGHT_MASK);
+
+	input_sync(input_if);
+
+	pr_debug("%s: mouse event: dx[%d], dy[%d], buttons_states[%d]\n",
+		 __func__, me->rels[X_IND],
+		 me->rels[Y_IND], me->buttons_states);
+}
+
+static void notify_key_event(struct input_dev *input_if,
+			       struct key_event_type *ke)
+{
+	if (ke == NULL) {
+		pr_err("%s: key event is NULL\n", __func__);
+		return;
+	}
+
+	input_report_key(input_if, ke->key, ke->key_state);
+	input_sync(input_if);
+	pr_debug("%s: key event: key[%d], state[%d]\n",
+		 __func__,
+		 ke->key,
+		 ke->key_state);
+
+}
+
+static void handle_input_event(struct usf_type *usf_info,
+			       uint16_t event_counter,
+			       struct usf_event_type *event)
+{
+	struct input_dev *input_if = NULL;
+	uint16_t ind = 0;
+	uint16_t events_num = 0;
+	struct usf_event_type usf_events[USF_EVENTS_PORTION_SIZE];
+	int rc = 0;
+
+	if ((usf_info == NULL) || (usf_info->input_if == NULL) ||
+	    (event == NULL) || (!event_counter)) {
+		return;
+	}
+
+	input_if = usf_info->input_if;
+
+	while (event_counter > 0) {
+		if (event_counter > USF_EVENTS_PORTION_SIZE) {
+			events_num = USF_EVENTS_PORTION_SIZE;
+			event_counter -= USF_EVENTS_PORTION_SIZE;
+		} else {
+			events_num = event_counter;
+			event_counter = 0;
+		}
+		rc = copy_from_user(usf_events,
+				event,
+				events_num * sizeof(struct usf_event_type));
+		if (rc) {
+			pr_err("%s: copy upd_rx_info from user; rc=%d\n",
+				__func__, rc);
+			return;
+		}
+		for (ind = 0; ind < events_num; ++ind) {
+			struct usf_event_type *p_event = &usf_events[ind];
+			if (p_event->event_type & USF_TSC_EVENT) {
+				struct point_event_type *pe =
+					&(p_event->event_data.point_event);
+				if (pe->coordinates_type ==
+					USF_PIX_COORDINATE)
+					notify_tsc_event(usf_info, pe);
+				else
+					pr_debug("%s: wrong coord type: %d",
+						__func__,
+						pe->coordinates_type);
+				continue;
+			}
+			if (p_event->event_type & USF_MOUSE_EVENT) {
+				notify_mouse_event(input_if,
+					&(p_event->event_data.mouse_event));
+				continue;
+			}
+			if (p_event->event_type & USF_KEYBOARD_EVENT)
+				notify_key_event(input_if,
+					&(p_event->event_data.key_event));
+		} /* loop in the portion */
+	} /* all events loop */
+}
+
+static int usf_start_tx(struct usf_xx_type *usf_xx)
+{
+	int rc = q6usm_run(usf_xx->usc, 0, 0, 0);
+
+	pr_debug("%s: tx: q6usm_run; rc=%d\n", __func__, rc);
+	if (!rc) {
+		if (usf_xx->buffer_count >= USM_MIN_BUF_CNT) {
+			/* supply all buffers */
+			rc = q6usm_read(usf_xx->usc,
+					usf_xx->buffer_count);
+			pr_debug("%s: q6usm_read[%d]\n",
+				 __func__, rc);
+
+			if (rc)
+				pr_err("%s: buf read failed",
+				       __func__);
+			else
+				usf_xx->usf_state =
+					USF_WORK_STATE;
+		} else
+			usf_xx->usf_state =
+				USF_WORK_STATE;
+	}
+
+	return rc;
+} /* usf_start_tx */
+
+static int usf_start_rx(struct usf_xx_type *usf_xx)
+{
+	int rc = q6usm_run(usf_xx->usc, 0, 0, 0);
+
+	pr_debug("%s: rx: q6usm_run; rc=%d\n",
+		 __func__, rc);
+	if (!rc)
+		usf_xx->usf_state = USF_WORK_STATE;
+
+	return rc;
+} /* usf_start_rx */
+
+static int usf_set_us_detection(struct usf_type *usf, unsigned long arg)
+{
+	uint32_t timeout = 0;
+	struct us_detect_info_type detect_info;
+	struct usm_session_cmd_detect_info usm_detect_info;
+	struct usm_session_cmd_detect_info *p_usm_detect_info =
+						&usm_detect_info;
+	uint32_t detect_info_size = sizeof(struct usm_session_cmd_detect_info);
+	struct usf_xx_type *usf_xx =  &usf->usf_tx;
+	int rc = copy_from_user(&detect_info,
+				(void *) arg,
+				sizeof(detect_info));
+
+	if (rc) {
+		pr_err("%s: copy detect_info from user; rc=%d\n",
+			__func__, rc);
+		return -EFAULT;
+	}
+
+	if (detect_info.us_detector != US_DETECT_FW) {
+		pr_err("%s: unsupported detector: %d\n",
+			__func__, detect_info.us_detector);
+		return -EINVAL;
+	}
+
+	if ((detect_info.params_data_size != 0) &&
+	    (detect_info.params_data != NULL)) {
+		uint8_t *p_data = NULL;
+
+		detect_info_size += detect_info.params_data_size;
+		p_usm_detect_info = kzalloc(detect_info_size, GFP_KERNEL);
+		if (p_usm_detect_info == NULL) {
+			pr_err("%s: detect_info[%d] allocation failed\n",
+			       __func__, detect_info_size);
+			return -ENOMEM;
+		}
+		p_data = (uint8_t *)p_usm_detect_info +
+			sizeof(struct usm_session_cmd_detect_info);
+
+		rc = copy_from_user(p_data,
+				    (void *)detect_info.params_data,
+				    detect_info.params_data_size);
+		if (rc) {
+			pr_err("%s: copy params from user; rc=%d\n",
+				__func__, rc);
+			kfree(p_usm_detect_info);
+			return -EFAULT;
+		}
+		p_usm_detect_info->algorithm_cfg_size =
+				detect_info.params_data_size;
+	} else
+		usm_detect_info.algorithm_cfg_size = 0;
+
+	p_usm_detect_info->detect_mode = detect_info.us_detect_mode;
+	p_usm_detect_info->skip_interval = detect_info.skip_time;
+
+	usf_xx->us_detect_type = USF_US_DETECT_UNDEF;
+
+	rc = q6usm_set_us_detection(usf_xx->usc,
+				    p_usm_detect_info,
+				    detect_info_size);
+	if (rc || (detect_info.detect_timeout == USF_NO_WAIT_TIMEOUT)) {
+		if (detect_info_size >
+		    sizeof(struct usm_session_cmd_detect_info))
+			kfree(p_usm_detect_info);
+		return rc;
+	}
+
+	/* Get US detection result */
+	if (detect_info.detect_timeout == USF_INFINITIVE_TIMEOUT) {
+		rc = wait_event_interruptible(usf_xx->wait,
+						(usf_xx->us_detect_type !=
+						USF_US_DETECT_UNDEF));
+	} else {
+		if (detect_info.detect_timeout == USF_DEFAULT_TIMEOUT)
+			timeout = USF_TIMEOUT_JIFFIES;
+		else
+			timeout = detect_info.detect_timeout * HZ;
+	}
+	rc = wait_event_interruptible_timeout(usf_xx->wait,
+					(usf_xx->us_detect_type !=
+					 USF_US_DETECT_UNDEF),
+					timeout);
+	/* In the case of timeout, "no US" is assumed */
+	if (rc < 0) {
+		pr_err("%s: Getting US detection failed rc[%d]\n",
+		       __func__, rc);
+		return rc;
+	}
+
+	usf->usf_rx.us_detect_type = usf->usf_tx.us_detect_type;
+	detect_info.is_us = (usf_xx->us_detect_type == USF_US_DETECT_YES);
+	rc = copy_to_user((void __user *)arg,
+			  &detect_info,
+			  sizeof(detect_info));
+	if (rc) {
+		pr_err("%s: copy detect_info to user; rc=%d\n",
+			__func__, rc);
+		rc = -EFAULT;
+	}
+
+	if (detect_info_size > sizeof(struct usm_session_cmd_detect_info))
+		kfree(p_usm_detect_info);
+
+	return rc;
+} /* usf_set_us_detection */
+
+static int usf_set_tx_info(struct usf_type *usf, unsigned long arg)
+{
+	struct us_tx_info_type config_tx;
+	const char *name = NULL;
+	struct usf_xx_type *usf_xx =  &usf->usf_tx;
+	int rc = copy_from_user(&config_tx,
+			    (void *) arg,
+			    sizeof(config_tx));
+
+	if (rc) {
+		pr_err("%s: copy config_tx from user; rc=%d\n",
+			__func__, rc);
+		return -EFAULT;
+	}
+
+	name = config_tx.us_xx_info.client_name;
+
+	usf_xx->new_region = USM_UNDEF_TOKEN;
+	usf_xx->prev_region = USM_UNDEF_TOKEN;
+	usf_xx->cb = usf_tx_cb;
+
+	init_waitqueue_head(&usf_xx->wait);
+
+	if (name != NULL) {
+		int res = strncpy_from_user(
+			usf_xx->client_name,
+			name,
+			sizeof(usf_xx->client_name)-1);
+		if (res < 0) {
+			pr_err("%s: get client name failed\n",
+			       __func__);
+			return -EINVAL;
+		}
+	}
+
+	rc = config_xx(usf_xx, &config_tx.us_xx_info);
+	if (rc)
+		return rc;
+
+	rc = q6usm_open_read(usf_xx->usc,
+			     usf_xx->encdec_cfg.format_id);
+	if (rc)
+		return rc;
+
+	rc = q6usm_us_client_buf_alloc(OUT, usf_xx->usc,
+				       usf_xx->buffer_size,
+				       usf_xx->buffer_count);
+	if (rc)
+		return rc;
+
+	rc = q6usm_enc_cfg_blk(usf_xx->usc,
+			       &usf_xx->encdec_cfg);
+	if (!rc &&
+	     (config_tx.input_info.event_types != USF_NO_EVENT)) {
+		rc = register_input_device(usf,
+					   &config_tx.input_info);
+	}
+
+	if (!rc)
+		usf_xx->usf_state = USF_CONFIGURED_STATE;
+
+	return rc;
+} /* usf_set_tx_info */
+
+static int usf_set_rx_info(struct usf_type *usf, unsigned long arg)
+{
+	struct us_rx_info_type config_rx;
+	struct usf_xx_type *usf_xx =  &usf->usf_rx;
+	int rc = copy_from_user(&config_rx,
+			    (void *) arg,
+			    sizeof(config_rx));
+
+	if (rc) {
+		pr_err("%s: copy config_rx from user; rc=%d\n",
+			__func__, rc);
+		return -EFAULT;
+	}
+
+	usf_xx->new_region = USM_UNDEF_TOKEN;
+	usf_xx->prev_region = USM_UNDEF_TOKEN;
+
+	usf_xx->cb = usf_rx_cb;
+
+	rc = config_xx(usf_xx, &config_rx.us_xx_info);
+	if (rc)
+		return rc;
+
+	rc = q6usm_open_write(usf_xx->usc,
+			      usf_xx->encdec_cfg.format_id);
+	if (rc)
+		return rc;
+
+	if (usf_xx->buffer_size && usf_xx->buffer_count) {
+		rc = q6usm_us_client_buf_alloc(
+					IN,
+					usf_xx->usc,
+					usf_xx->buffer_size,
+					usf_xx->buffer_count);
+		if (rc)
+			return rc;
+	}
+
+	rc = q6usm_dec_cfg_blk(usf_xx->usc,
+			       &usf_xx->encdec_cfg);
+	if (!rc) {
+		init_waitqueue_head(&usf_xx->wait);
+		usf_xx->usf_state = USF_CONFIGURED_STATE;
+	}
+
+	return rc;
+} /* usf_set_rx_info */
+
+
+static int usf_get_tx_update(struct usf_type *usf, unsigned long arg)
+{
+	struct us_tx_update_info_type upd_tx_info;
+	unsigned long prev_jiffies = 0;
+	uint32_t timeout = 0;
+	struct usf_xx_type *usf_xx =  &usf->usf_tx;
+	int rc = copy_from_user(&upd_tx_info, (void *) arg,
+			    sizeof(upd_tx_info));
+
+	if (rc) {
+		pr_err("%s: copy upd_tx_info from user; rc=%d\n",
+			__func__, rc);
+		return -EFAULT;
+	}
+
+	if (!usf_xx->user_upd_info_na) {
+		usf_set_event_filters(usf, upd_tx_info.event_filters);
+		handle_input_event(usf,
+				   upd_tx_info.event_counter,
+				   upd_tx_info.event);
+
+		/* Release available regions */
+		rc = q6usm_read(usf_xx->usc,
+				upd_tx_info.free_region);
+		if (rc)
+			return rc;
+	} else
+		usf_xx->user_upd_info_na = 0;
+
+	/* Get data ready regions */
+	if (upd_tx_info.timeout == USF_INFINITIVE_TIMEOUT) {
+		rc = wait_event_interruptible(usf_xx->wait,
+			   (usf_xx->prev_region !=
+			    usf_xx->new_region) ||
+			   (usf_xx->usf_state !=
+			    USF_WORK_STATE));
+	} else {
+		if (upd_tx_info.timeout == USF_NO_WAIT_TIMEOUT)
+			rc = (usf_xx->prev_region != usf_xx->new_region);
+		else {
+			prev_jiffies = jiffies;
+			if (upd_tx_info.timeout == USF_DEFAULT_TIMEOUT) {
+				timeout = USF_TIMEOUT_JIFFIES;
+				rc = wait_event_timeout(
+						usf_xx->wait,
+						(usf_xx->prev_region !=
+						 usf_xx->new_region) ||
+						(usf_xx->usf_state !=
+						 USF_WORK_STATE),
+						timeout);
+			} else {
+				timeout = upd_tx_info.timeout * HZ;
+				rc = wait_event_interruptible_timeout(
+						usf_xx->wait,
+						(usf_xx->prev_region !=
+						 usf_xx->new_region) ||
+						(usf_xx->usf_state !=
+						 USF_WORK_STATE),
+						timeout);
+			}
+		}
+		if (!rc) {
+			pr_debug("%s: timeout. prev_j=%lu; j=%lu\n",
+				__func__, prev_jiffies, jiffies);
+			pr_debug("%s: timeout. prev=%d; new=%d\n",
+				__func__, usf_xx->prev_region,
+				usf_xx->new_region);
+			pr_debug("%s: timeout. free_region=%d;\n",
+				__func__, upd_tx_info.free_region);
+			if (usf_xx->prev_region ==
+			    usf_xx->new_region) {
+				pr_err("%s:read data: timeout\n",
+				       __func__);
+				return -ETIME;
+			}
+		}
+	}
+
+	if ((usf_xx->usf_state != USF_WORK_STATE) ||
+	    (rc == -ERESTARTSYS)) {
+		pr_err("%s: Getting ready region failed "
+			"work state[%d]; rc[%d]\n",
+		       __func__, usf_xx->usf_state, rc);
+		return -EINTR;
+	}
+
+	upd_tx_info.ready_region = usf_xx->new_region;
+	usf_xx->prev_region = upd_tx_info.ready_region;
+
+	if (upd_tx_info.ready_region == USM_WRONG_TOKEN) {
+		pr_err("%s: TX path corrupted; prev=%d\n",
+		       __func__, usf_xx->prev_region);
+		return -EIO;
+	}
+
+	rc = copy_to_user((void __user *)arg, &upd_tx_info,
+			  sizeof(upd_tx_info));
+	if (rc) {
+		pr_err("%s: copy upd_tx_info to user; rc=%d\n",
+			__func__, rc);
+		rc = -EFAULT;
+	}
+
+	return rc;
+} /* usf_get_tx_update */
+
+static int usf_set_rx_update(struct usf_xx_type *usf_xx, unsigned long arg)
+{
+	struct us_rx_update_info_type upd_rx_info;
+	int rc = copy_from_user(&upd_rx_info, (void *) arg,
+			    sizeof(upd_rx_info));
+
+	if (rc) {
+		pr_err("%s: copy upd_rx_info from user; rc=%d\n",
+			__func__, rc);
+		return -EFAULT;
+	}
+
+	/* Send available data regions */
+	if (upd_rx_info.ready_region !=
+	    usf_xx->buffer_count) {
+		rc = q6usm_write(
+			usf_xx->usc,
+			upd_rx_info.ready_region);
+		if (rc)
+			return rc;
+	}
+
+	/* Get free regions */
+	rc = wait_event_timeout(
+		usf_xx->wait,
+		!q6usm_is_write_buf_full(
+			usf_xx->usc,
+			&upd_rx_info.free_region) ||
+		(usf_xx->usf_state == USF_IDLE_STATE),
+		USF_TIMEOUT_JIFFIES);
+
+	if (!rc) {
+		rc = -ETIME;
+		pr_err("%s:timeout. wait for write buf not full\n",
+		       __func__);
+	} else {
+		if (usf_xx->usf_state !=
+		    USF_WORK_STATE) {
+			pr_err("%s: RX: state[%d]\n",
+			       __func__,
+			       usf_xx->usf_state);
+			rc = -EINTR;
+		} else {
+			rc = copy_to_user(
+				(void __user *)arg,
+				&upd_rx_info,
+				sizeof(upd_rx_info));
+			if (rc) {
+				pr_err("%s: copy rx_info to user; rc=%d\n",
+					__func__, rc);
+				rc = -EFAULT;
+			}
+		}
+	}
+
+	return rc;
+} /* usf_set_rx_update */
+
+static void usf_release_input(struct usf_type *usf)
+{
+	if (usf->input_if != NULL) {
+		usf_unregister_conflicting_events(
+						usf->conflicting_event_types);
+		usf->conflicting_event_types = 0;
+		input_unregister_device(usf->input_if);
+		usf->input_if = NULL;
+		pr_debug("%s input_unregister_device\n",  __func__);
+	}
+} /* usf_release_input */
+
+static int usf_stop_tx(struct usf_type *usf)
+{
+	struct usf_xx_type *usf_xx =  &usf->usf_tx;
+
+	usf_release_input(usf);
+	usf_disable(usf_xx);
+
+	return 0;
+} /* usf_stop_tx */
+
+static int usf_get_version(unsigned long arg)
+{
+	struct us_version_info_type version_info;
+	int rc = copy_from_user(&version_info, (void *) arg,
+				sizeof(version_info));
+
+	if (rc) {
+		pr_err("%s: copy version_info from user; rc=%d\n",
+			__func__, rc);
+		return -EFAULT;
+	}
+
+	/* version_info.buf is pointer to place for the version string */
+	rc = copy_to_user(version_info.pbuf,
+			  DRV_VERSION,
+			  version_info.buf_size);
+	if (rc) {
+		pr_err("%s: copy to version_info.pbuf; rc=%d\n",
+			__func__, rc);
+		rc = -EFAULT;
+	}
+
+	rc = copy_to_user((void __user *)arg,
+			  &version_info,
+			  sizeof(version_info));
+	if (rc) {
+		pr_err("%s: copy version_info to user; rc=%d\n",
+			__func__, rc);
+		rc = -EFAULT;
+	}
+
+	return rc;
+} /* usf_get_version */
+
+static long usf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int rc = 0;
+	struct usf_type *usf = file->private_data;
+	struct usf_xx_type *usf_xx = NULL;
+
+	switch (cmd) {
+	case US_START_TX: {
+		usf_xx = &usf->usf_tx;
+		if (usf_xx->usf_state == USF_CONFIGURED_STATE)
+			rc = usf_start_tx(usf_xx);
+		else {
+			pr_err("%s: start_tx: wrong state[%d]\n",
+			       __func__,
+			       usf_xx->usf_state);
+			return -EBADFD;
+		}
+		break;
+	}
+
+	case US_START_RX: {
+		usf_xx = &usf->usf_rx;
+		if (usf_xx->usf_state == USF_CONFIGURED_STATE)
+			rc = usf_start_rx(usf_xx);
+		else {
+			pr_err("%s: start_rx: wrong state[%d]\n",
+				__func__,
+				usf_xx->usf_state);
+			return -EBADFD;
+		}
+		break;
+	}
+
+	case US_SET_TX_INFO: {
+		usf_xx = &usf->usf_tx;
+		if (usf_xx->usf_state == USF_OPENED_STATE)
+			rc = usf_set_tx_info(usf, arg);
+		else {
+			pr_err("%s: set_tx_info: wrong state[%d]\n",
+			       __func__,
+			       usf_xx->usf_state);
+			return -EBADFD;
+		}
+
+		break;
+	} /* US_SET_TX_INFO */
+
+	case US_SET_RX_INFO: {
+		usf_xx = &usf->usf_rx;
+		if (usf_xx->usf_state == USF_OPENED_STATE)
+			rc = usf_set_rx_info(usf, arg);
+		else {
+			pr_err("%s: set_rx_info: wrong state[%d]\n",
+				__func__,
+				usf_xx->usf_state);
+			return -EBADFD;
+		}
+
+		break;
+	} /* US_SET_RX_INFO */
+
+	case US_GET_TX_UPDATE: {
+		struct usf_xx_type *usf_xx = &usf->usf_tx;
+		if (usf_xx->usf_state == USF_WORK_STATE)
+			rc = usf_get_tx_update(usf, arg);
+		else {
+			pr_err("%s: get_tx_update: wrong state[%d]\n", __func__,
+			       usf_xx->usf_state);
+			rc = -EBADFD;
+		}
+		break;
+	} /* US_GET_TX_UPDATE */
+
+	case US_SET_RX_UPDATE: {
+		struct usf_xx_type *usf_xx = &usf->usf_rx;
+		if (usf_xx->usf_state == USF_WORK_STATE)
+			rc = usf_set_rx_update(usf_xx, arg);
+		else {
+			pr_err("%s: set_rx_update: wrong state[%d]\n",
+			       __func__,
+			       usf_xx->usf_state);
+			rc = -EBADFD;
+		}
+		break;
+	} /* US_SET_RX_UPDATE */
+
+	case US_STOP_TX: {
+		usf_xx = &usf->usf_tx;
+		if (usf_xx->usf_state == USF_WORK_STATE)
+			rc = usf_stop_tx(usf);
+		else {
+			pr_err("%s: stop_tx: wrong state[%d]\n",
+			       __func__,
+			       usf_xx->usf_state);
+			return -EBADFD;
+		}
+		break;
+	} /* US_STOP_TX */
+
+	case US_STOP_RX: {
+		usf_xx = &usf->usf_rx;
+		if (usf_xx->usf_state == USF_WORK_STATE)
+			usf_disable(usf_xx);
+		else {
+			pr_err("%s: stop_rx: wrong state[%d]\n",
+			       __func__,
+			       usf_xx->usf_state);
+			return -EBADFD;
+		}
+		break;
+	} /* US_STOP_RX */
+
+	case US_SET_DETECTION: {
+		struct usf_xx_type *usf_xx = &usf->usf_tx;
+		if (usf_xx->usf_state == USF_WORK_STATE)
+			rc = usf_set_us_detection(usf, arg);
+		else {
+			pr_err("%s: set us detection: wrong state[%d]\n",
+			       __func__,
+			       usf_xx->usf_state);
+			rc = -EBADFD;
+		}
+		break;
+	} /* US_SET_DETECTION */
+
+	case US_GET_VERSION: {
+		rc = usf_get_version(arg);
+		break;
+	} /* US_GET_VERSION */
+
+	default:
+		pr_err("%s: unsupported IOCTL command [%d]\n",
+		       __func__,
+		       cmd);
+		rc = -ENOTTY;
+		break;
+	}
+
+	if (rc &&
+	    ((cmd == US_SET_TX_INFO) ||
+	     (cmd == US_SET_RX_INFO)))
+		release_xx(usf_xx);
+
+	return rc;
+} /* usf_ioctl */
+
+static int usf_mmap(struct file *file, struct vm_area_struct *vms)
+{
+	struct usf_type *usf = file->private_data;
+	int dir = OUT;
+	struct usf_xx_type *usf_xx = &usf->usf_tx;
+
+	if (vms->vm_flags & USF_VM_WRITE) { /* RX buf mapping */
+		dir = IN;
+		usf_xx = &usf->usf_rx;
+	}
+
+	return q6usm_get_virtual_address(dir, usf_xx->usc, vms);
+}
+
+static uint16_t add_opened_dev(int minor)
+{
+	uint16_t ind = 0;
+
+	for (ind = 0; ind < MAX_DEVS_NUMBER; ++ind) {
+		if (minor == s_opened_devs[ind]) {
+			pr_err("%s: device %d is already opened\n",
+			       __func__, minor);
+			return USF_UNDEF_DEV_ID;
+		}
+
+		if (s_opened_devs[ind] == 0) {
+			s_opened_devs[ind] = minor;
+			pr_debug("%s: device %d is added; ind=%d\n",
+				__func__, minor, ind);
+			return ind;
+		}
+	}
+
+	pr_err("%s: there is no place for device %d\n",
+	       __func__, minor);
+	return USF_UNDEF_DEV_ID;
+}
+
+static int usf_open(struct inode *inode, struct file *file)
+{
+	struct usf_type *usf =  NULL;
+	uint16_t dev_ind = 0;
+	int minor = MINOR(inode->i_rdev);
+
+	dev_ind = add_opened_dev(minor);
+	if (dev_ind == USF_UNDEF_DEV_ID)
+		return -EBUSY;
+
+	usf = kzalloc(sizeof(struct usf_type), GFP_KERNEL);
+	if (usf == NULL) {
+		pr_err("%s:usf allocation failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	file->private_data = usf;
+	usf->dev_ind = dev_ind;
+
+	usf->usf_tx.usf_state = USF_OPENED_STATE;
+	usf->usf_rx.usf_state = USF_OPENED_STATE;
+
+	usf->usf_tx.us_detect_type = USF_US_DETECT_UNDEF;
+	usf->usf_rx.us_detect_type = USF_US_DETECT_UNDEF;
+
+	pr_debug("%s:usf in open\n", __func__);
+	return 0;
+}
+
+static int usf_release(struct inode *inode, struct file *file)
+{
+	struct usf_type *usf = file->private_data;
+
+	pr_debug("%s: release entry\n", __func__);
+
+	usf_release_input(usf);
+
+	usf_disable(&usf->usf_tx);
+	usf_disable(&usf->usf_rx);
+
+	s_opened_devs[usf->dev_ind] = 0;
+
+	kfree(usf);
+	pr_debug("%s: release exit\n", __func__);
+	return 0;
+}
+
+static const struct file_operations usf_fops = {
+	.owner                  = THIS_MODULE,
+	.open                   = usf_open,
+	.release                = usf_release,
+	.unlocked_ioctl = usf_ioctl,
+	.mmap                   = usf_mmap,
+};
+
+struct miscdevice usf_misc[MAX_DEVS_NUMBER] = {
+	{
+		.minor  = MISC_DYNAMIC_MINOR,
+		.name   = "usf1",
+		.fops   = &usf_fops,
+	},
+};
+
+static int __init usf_init(void)
+{
+	int rc = 0;
+	uint16_t ind = 0;
+
+	pr_debug("%s: USF SW version %s.\n", __func__, DRV_VERSION);
+	pr_debug("%s: Max %d devs registration\n", __func__, MAX_DEVS_NUMBER);
+
+	for (ind = 0; ind < MAX_DEVS_NUMBER; ++ind) {
+		rc = misc_register(&usf_misc[ind]);
+		if (rc) {
+			pr_err("%s: misc_register() failed ind=%d; rc = %d\n",
+			       __func__, ind, rc);
+			break;
+		}
+	}
+
+	return rc;
+}
+
+device_initcall(usf_init);
+
+MODULE_DESCRIPTION("Ultrasound framework driver");
+MODULE_VERSION(DRV_VERSION);
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/usfcdev.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/usfcdev.c
new file mode 100644
index 0000000..b99a9b0
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/usfcdev.c
@@ -0,0 +1,236 @@
+/* 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/sched.h>
+#include <linux/slab.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include "usfcdev.h"
+
+struct usfcdev_event {
+	bool (*match_cb)(uint16_t, struct input_dev *dev);
+	bool registered_event;
+	bool filter;
+};
+static struct usfcdev_event s_usfcdev_events[MAX_EVENT_TYPE_NUM];
+
+static bool usfcdev_filter(struct input_handle *handle,
+			 unsigned int type, unsigned int code, int value);
+static bool usfcdev_match(struct input_handler *handler,
+				struct input_dev *dev);
+static int usfcdev_connect(struct input_handler *handler,
+				struct input_dev *dev,
+				const struct input_device_id *id);
+static void usfcdev_disconnect(struct input_handle *handle);
+
+static const struct input_device_id usfc_tsc_ids[] = {
+	{
+		.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+			INPUT_DEVICE_ID_MATCH_KEYBIT |
+			INPUT_DEVICE_ID_MATCH_ABSBIT,
+		.evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) },
+		.keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) },
+		.absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) },
+	},
+	{ } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(input, usfc_tsc_ids);
+
+static struct input_handler s_usfc_handlers[MAX_EVENT_TYPE_NUM] = {
+	{ /* TSC handler */
+		.filter         = usfcdev_filter,
+		.match          = usfcdev_match,
+		.connect        = usfcdev_connect,
+		.disconnect     = usfcdev_disconnect,
+		/* .minor can be used as index in the container, */
+		/*  because .fops isn't supported */
+		.minor          = TSC_EVENT_TYPE_IND,
+		.name           = "usfc_tsc_handler",
+		.id_table       = usfc_tsc_ids,
+	},
+};
+
+/* For each event type, one conflicting device (and handle) is supported */
+static struct input_handle s_usfc_handles[MAX_EVENT_TYPE_NUM] = {
+	{ /* TSC handle */
+		.handler	= &s_usfc_handlers[TSC_EVENT_TYPE_IND],
+		.name		= "usfc_tsc_handle",
+	},
+};
+
+static bool usfcdev_match(struct input_handler *handler, struct input_dev *dev)
+{
+	bool rc = false;
+	int ind = handler->minor;
+
+	pr_debug("%s: name=[%s]; ind=%d\n", __func__, dev->name, ind);
+	if (s_usfcdev_events[ind].registered_event &&
+			s_usfcdev_events[ind].match_cb) {
+		rc = (*s_usfcdev_events[ind].match_cb)((uint16_t)ind, dev);
+		pr_debug("%s: [%s]; rc=%d\n", __func__, dev->name, rc);
+	}
+
+	return rc;
+}
+
+static int usfcdev_connect(struct input_handler *handler, struct input_dev *dev,
+				const struct input_device_id *id)
+{
+	int ret = 0;
+	uint16_t ind = handler->minor;
+
+	s_usfc_handles[ind].dev = dev;
+	ret = input_register_handle(&s_usfc_handles[ind]);
+	if (ret) {
+		pr_err("%s: input_register_handle[%d] failed: ret=%d\n",
+			__func__,
+			ind,
+			ret);
+	} else {
+		ret = input_open_device(&s_usfc_handles[ind]);
+		if (ret) {
+			pr_err("%s: input_open_device[%d] failed: ret=%d\n",
+				__func__,
+				ind,
+				ret);
+			input_unregister_handle(&s_usfc_handles[ind]);
+		} else
+			pr_debug("%s: device[%d] is opened\n",
+				__func__,
+				ind);
+	}
+
+	return ret;
+}
+
+static void usfcdev_disconnect(struct input_handle *handle)
+{
+	input_unregister_handle(handle);
+	pr_debug("%s: handle[%d] is disconnect\n",
+		__func__,
+		handle->handler->minor);
+}
+
+static bool usfcdev_filter(struct input_handle *handle,
+			unsigned int type, unsigned int code, int value)
+{
+	uint16_t ind = (uint16_t)handle->handler->minor;
+
+	pr_debug("%s: event_type=%d; filter=%d\n",
+		__func__,
+		ind,
+		s_usfcdev_events[ind].filter);
+
+	return s_usfcdev_events[ind].filter;
+}
+
+bool usfcdev_register(
+	uint16_t event_type_ind,
+	bool (*match_cb)(uint16_t, struct input_dev *dev))
+{
+	int ret = 0;
+	bool rc = false;
+
+	if ((event_type_ind >= MAX_EVENT_TYPE_NUM) || !match_cb) {
+		pr_err("%s: wrong input: event_type_ind=%d; match_cb=0x%p\n",
+			__func__,
+			event_type_ind,
+			match_cb);
+		return false;
+	}
+
+	if (s_usfcdev_events[event_type_ind].registered_event) {
+		pr_info("%s: handler[%d] was already registered\n",
+			__func__,
+			event_type_ind);
+		return true;
+	}
+
+	s_usfcdev_events[event_type_ind].registered_event = true;
+	s_usfcdev_events[event_type_ind].match_cb = match_cb;
+	s_usfcdev_events[event_type_ind].filter = false;
+	ret = input_register_handler(&s_usfc_handlers[event_type_ind]);
+	if (!ret) {
+		rc = true;
+		pr_debug("%s: handler[%d] was registered\n",
+			__func__,
+			event_type_ind);
+	} else {
+		s_usfcdev_events[event_type_ind].registered_event = false;
+		s_usfcdev_events[event_type_ind].match_cb = NULL;
+		pr_err("%s: handler[%d] registration failed: ret=%d\n",
+			__func__,
+			event_type_ind,
+			ret);
+	}
+
+	return rc;
+}
+
+void usfcdev_unregister(uint16_t event_type_ind)
+{
+	if (event_type_ind >= MAX_EVENT_TYPE_NUM) {
+		pr_err("%s: wrong input: event_type_ind=%d\n",
+			__func__,
+			event_type_ind);
+		return;
+	}
+	if (s_usfcdev_events[event_type_ind].registered_event) {
+		input_unregister_handler(&s_usfc_handlers[event_type_ind]);
+		pr_debug("%s: handler[%d] was unregistered\n",
+			__func__,
+			event_type_ind);
+		s_usfcdev_events[event_type_ind].registered_event = false;
+		s_usfcdev_events[event_type_ind].match_cb = NULL;
+		s_usfcdev_events[event_type_ind].filter = false;
+	}
+}
+
+bool usfcdev_set_filter(uint16_t event_type_ind, bool filter)
+{
+	bool rc = true;
+
+	if (event_type_ind >= MAX_EVENT_TYPE_NUM) {
+		pr_err("%s: wrong input: event_type_ind=%d\n",
+			__func__,
+			event_type_ind);
+		return false;
+	}
+
+	if (s_usfcdev_events[event_type_ind].registered_event) {
+		s_usfcdev_events[event_type_ind].filter = filter;
+		pr_debug("%s: event_type[%d]; filter=%d\n",
+			__func__,
+			event_type_ind,
+			filter
+			);
+	} else {
+		pr_err("%s: event_type[%d] isn't registered\n",
+			__func__,
+			event_type_ind);
+		rc = false;
+	}
+
+	return rc;
+}
+
+static int __init usfcdev_init(void)
+{
+	return 0;
+}
+
+device_initcall(usfcdev_init);
+
+MODULE_DESCRIPTION("Handle of events from devices, conflicting with USF");
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/usfcdev.h b/arch/arm/mach-msm/qdsp6v2/ultrasound/usfcdev.h
new file mode 100644
index 0000000..042b293
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/usfcdev.h
@@ -0,0 +1,28 @@
+/* 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 __USFCDEV_H__
+#define __USFCDEV_H__
+
+#include <linux/input.h>
+
+/* TSC event type index in the containers of the handlers & handles */
+#define TSC_EVENT_TYPE_IND 0
+/* Number of supported event types to be filtered */
+#define MAX_EVENT_TYPE_NUM 1
+
+bool usfcdev_register(
+	uint16_t event_type_ind,
+	bool (*match_cb)(uint16_t, struct input_dev *dev));
+void usfcdev_unregister(uint16_t event_type_ind);
+bool usfcdev_set_filter(uint16_t event_type_ind, bool filter);
+#endif /* __USFCDEV_H__ */
diff --git a/arch/arm/mach-msm/qdss-etb.c b/arch/arm/mach-msm/qdss-etb.c
new file mode 100644
index 0000000..7837af0
--- /dev/null
+++ b/arch/arm/mach-msm/qdss-etb.c
@@ -0,0 +1,412 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+
+#include "qdss-priv.h"
+
+#define etb_writel(etb, val, off)	__raw_writel((val), etb.base + off)
+#define etb_readl(etb, off)		__raw_readl(etb.base + off)
+
+#define ETB_RAM_DEPTH_REG	(0x004)
+#define ETB_STATUS_REG		(0x00C)
+#define ETB_RAM_READ_DATA_REG	(0x010)
+#define ETB_RAM_READ_POINTER	(0x014)
+#define ETB_RAM_WRITE_POINTER	(0x018)
+#define ETB_TRG			(0x01C)
+#define ETB_CTL_REG		(0x020)
+#define ETB_RWD_REG		(0x024)
+#define ETB_FFSR		(0x300)
+#define ETB_FFCR		(0x304)
+#define ETB_ITMISCOP0		(0xEE0)
+#define ETB_ITTRFLINACK		(0xEE4)
+#define ETB_ITTRFLIN		(0xEE8)
+#define ETB_ITATBDATA0		(0xEEC)
+#define ETB_ITATBCTR2		(0xEF0)
+#define ETB_ITATBCTR1		(0xEF4)
+#define ETB_ITATBCTR0		(0xEF8)
+
+
+#define BYTES_PER_WORD		4
+#define ETB_SIZE_WORDS		4096
+#define FRAME_SIZE_WORDS	4
+
+#define ETB_LOCK()							\
+do {									\
+	mb();								\
+	etb_writel(etb, 0x0, CS_LAR);					\
+} while (0)
+#define ETB_UNLOCK()							\
+do {									\
+	etb_writel(etb, CS_UNLOCK_MAGIC, CS_LAR);			\
+	mb();								\
+} while (0)
+
+struct etb_ctx {
+	uint8_t		*buf;
+	void __iomem	*base;
+	bool		enabled;
+	bool		reading;
+	spinlock_t	spinlock;
+	atomic_t	in_use;
+	struct device	*dev;
+	struct kobject	*kobj;
+	uint32_t	trigger_cntr;
+};
+
+static struct etb_ctx etb;
+
+static void __etb_enable(void)
+{
+	int i;
+
+	ETB_UNLOCK();
+
+	etb_writel(etb, 0x0, ETB_RAM_WRITE_POINTER);
+	for (i = 0; i < ETB_SIZE_WORDS; i++)
+		etb_writel(etb, 0x0, ETB_RWD_REG);
+
+	etb_writel(etb, 0x0, ETB_RAM_WRITE_POINTER);
+	etb_writel(etb, 0x0, ETB_RAM_READ_POINTER);
+
+	etb_writel(etb, etb.trigger_cntr, ETB_TRG);
+	etb_writel(etb, BIT(13) | BIT(0), ETB_FFCR);
+	etb_writel(etb, BIT(0), ETB_CTL_REG);
+
+	ETB_LOCK();
+}
+
+void etb_enable(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&etb.spinlock, flags);
+	__etb_enable();
+	etb.enabled = true;
+	dev_info(etb.dev, "ETB enabled\n");
+	spin_unlock_irqrestore(&etb.spinlock, flags);
+}
+
+static void __etb_disable(void)
+{
+	int count;
+	uint32_t ffcr;
+
+	ETB_UNLOCK();
+
+	ffcr = etb_readl(etb, ETB_FFCR);
+	ffcr |= (BIT(12) | BIT(6));
+	etb_writel(etb, ffcr, ETB_FFCR);
+
+	for (count = TIMEOUT_US; BVAL(etb_readl(etb, ETB_FFCR), 6) != 0
+				&& count > 0; count--)
+		udelay(1);
+	WARN(count == 0, "timeout while flushing ETB, ETB_FFCR: %#x\n",
+	     etb_readl(etb, ETB_FFCR));
+
+	etb_writel(etb, 0x0, ETB_CTL_REG);
+
+	for (count = TIMEOUT_US; BVAL(etb_readl(etb, ETB_FFSR), 1) != 1
+				&& count > 0; count--)
+		udelay(1);
+	WARN(count == 0, "timeout while disabling ETB, ETB_FFSR: %#x\n",
+	     etb_readl(etb, ETB_FFSR));
+
+	ETB_LOCK();
+}
+
+void etb_disable(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&etb.spinlock, flags);
+	__etb_disable();
+	etb.enabled = false;
+	dev_info(etb.dev, "ETB disabled\n");
+	spin_unlock_irqrestore(&etb.spinlock, flags);
+}
+
+static void __etb_dump(void)
+{
+	int i;
+	uint8_t *buf_ptr;
+	uint32_t read_data;
+	uint32_t read_ptr;
+	uint32_t write_ptr;
+	uint32_t frame_off;
+	uint32_t frame_endoff;
+
+	ETB_UNLOCK();
+
+	read_ptr = etb_readl(etb, ETB_RAM_READ_POINTER);
+	write_ptr = etb_readl(etb, ETB_RAM_WRITE_POINTER);
+
+	frame_off = write_ptr % FRAME_SIZE_WORDS;
+	frame_endoff = FRAME_SIZE_WORDS - frame_off;
+	if (frame_off) {
+		dev_err(etb.dev, "write_ptr: %lu not aligned to formatter "
+				"frame size\n", (unsigned long)write_ptr);
+		dev_err(etb.dev, "frameoff: %lu, frame_endoff: %lu\n",
+			(unsigned long)frame_off, (unsigned long)frame_endoff);
+		write_ptr += frame_endoff;
+	}
+
+	if ((etb_readl(etb, ETB_STATUS_REG) & BIT(0)) == 0)
+		etb_writel(etb, 0x0, ETB_RAM_READ_POINTER);
+	else
+		etb_writel(etb, write_ptr, ETB_RAM_READ_POINTER);
+
+	buf_ptr = etb.buf;
+	for (i = 0; i < ETB_SIZE_WORDS; i++) {
+		read_data = etb_readl(etb, ETB_RAM_READ_DATA_REG);
+		*buf_ptr++ = read_data >> 0;
+		*buf_ptr++ = read_data >> 8;
+		*buf_ptr++ = read_data >> 16;
+		*buf_ptr++ = read_data >> 24;
+	}
+
+	if (frame_off) {
+		buf_ptr -= (frame_endoff * BYTES_PER_WORD);
+		for (i = 0; i < frame_endoff; i++) {
+			*buf_ptr++ = 0x0;
+			*buf_ptr++ = 0x0;
+			*buf_ptr++ = 0x0;
+			*buf_ptr++ = 0x0;
+		}
+	}
+
+	etb_writel(etb, read_ptr, ETB_RAM_READ_POINTER);
+
+	ETB_LOCK();
+}
+
+void etb_dump(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&etb.spinlock, flags);
+	if (etb.enabled) {
+		__etb_disable();
+		__etb_dump();
+		__etb_enable();
+
+		dev_info(etb.dev, "ETB dumped\n");
+	}
+	spin_unlock_irqrestore(&etb.spinlock, flags);
+}
+
+static int etb_open(struct inode *inode, struct file *file)
+{
+	if (atomic_cmpxchg(&etb.in_use, 0, 1))
+		return -EBUSY;
+
+	dev_dbg(etb.dev, "%s: successfully opened\n", __func__);
+	return 0;
+}
+
+static ssize_t etb_read(struct file *file, char __user *data,
+				size_t len, loff_t *ppos)
+{
+	if (etb.reading == false) {
+		etb_dump();
+		etb.reading = true;
+	}
+
+	if (*ppos + len > ETB_SIZE_WORDS * BYTES_PER_WORD)
+		len = ETB_SIZE_WORDS * BYTES_PER_WORD - *ppos;
+
+	if (copy_to_user(data, etb.buf + *ppos, len)) {
+		dev_dbg(etb.dev, "%s: copy_to_user failed\n", __func__);
+		return -EFAULT;
+	}
+
+	*ppos += len;
+
+	dev_dbg(etb.dev, "%s: %d bytes copied, %d bytes left\n",
+		__func__, len, (int) (ETB_SIZE_WORDS * BYTES_PER_WORD - *ppos));
+
+	return len;
+}
+
+static int etb_release(struct inode *inode, struct file *file)
+{
+	etb.reading = false;
+
+	atomic_set(&etb.in_use, 0);
+
+	dev_dbg(etb.dev, "%s: released\n", __func__);
+
+	return 0;
+}
+
+static const struct file_operations etb_fops = {
+	.owner =	THIS_MODULE,
+	.open =		etb_open,
+	.read =		etb_read,
+	.release =	etb_release,
+};
+
+static struct miscdevice etb_misc = {
+	.name =		"msm_etb",
+	.minor =	MISC_DYNAMIC_MINOR,
+	.fops =		&etb_fops,
+};
+
+#define ETB_ATTR(__name)						\
+static struct kobj_attribute __name##_attr =				\
+	__ATTR(__name, S_IRUGO | S_IWUSR, __name##_show, __name##_store)
+
+static ssize_t trigger_cntr_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	etb.trigger_cntr = val;
+	return n;
+}
+static ssize_t trigger_cntr_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf)
+{
+	unsigned long val = etb.trigger_cntr;
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+ETB_ATTR(trigger_cntr);
+
+static int __devinit etb_sysfs_init(void)
+{
+	int ret;
+
+	etb.kobj = kobject_create_and_add("etb", qdss_get_modulekobj());
+	if (!etb.kobj) {
+		dev_err(etb.dev, "failed to create ETB sysfs kobject\n");
+		ret = -ENOMEM;
+		goto err_create;
+	}
+
+	ret = sysfs_create_file(etb.kobj, &trigger_cntr_attr.attr);
+	if (ret) {
+		dev_err(etb.dev, "failed to create ETB sysfs trigger_cntr"
+		" attribute\n");
+		goto err_file;
+	}
+
+	return 0;
+err_file:
+	kobject_put(etb.kobj);
+err_create:
+	return ret;
+}
+
+static void __devexit etb_sysfs_exit(void)
+{
+	sysfs_remove_file(etb.kobj, &trigger_cntr_attr.attr);
+	kobject_put(etb.kobj);
+}
+
+static int __devinit etb_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct resource *res;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		ret = -EINVAL;
+		goto err_res;
+	}
+
+	etb.base = ioremap_nocache(res->start, resource_size(res));
+	if (!etb.base) {
+		ret = -EINVAL;
+		goto err_ioremap;
+	}
+
+	etb.dev = &pdev->dev;
+
+	spin_lock_init(&etb.spinlock);
+
+	ret = misc_register(&etb_misc);
+	if (ret)
+		goto err_misc;
+
+	etb.buf = kzalloc(ETB_SIZE_WORDS * BYTES_PER_WORD, GFP_KERNEL);
+	if (!etb.buf) {
+		ret = -ENOMEM;
+		goto err_alloc;
+	}
+
+	etb_sysfs_init();
+
+	dev_info(etb.dev, "ETB initialized\n");
+	return 0;
+
+err_alloc:
+	misc_deregister(&etb_misc);
+err_misc:
+	iounmap(etb.base);
+err_ioremap:
+err_res:
+	dev_err(etb.dev, "ETB init failed\n");
+	return ret;
+}
+
+static int __devexit etb_remove(struct platform_device *pdev)
+{
+	if (etb.enabled)
+		etb_disable();
+	etb_sysfs_exit();
+	kfree(etb.buf);
+	misc_deregister(&etb_misc);
+	iounmap(etb.base);
+
+	return 0;
+}
+
+static struct platform_driver etb_driver = {
+	.probe          = etb_probe,
+	.remove         = __devexit_p(etb_remove),
+	.driver         = {
+		.name   = "msm_etb",
+	},
+};
+
+static int __init etb_init(void)
+{
+	return platform_driver_register(&etb_driver);
+}
+module_init(etb_init);
+
+static void __exit etb_exit(void)
+{
+	platform_driver_unregister(&etb_driver);
+}
+module_exit(etb_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Embedded Trace Buffer driver");
diff --git a/arch/arm/mach-msm/qdss-etm.c b/arch/arm/mach-msm/qdss-etm.c
new file mode 100644
index 0000000..ca6e0c6
--- /dev/null
+++ b/arch/arm/mach-msm/qdss-etm.c
@@ -0,0 +1,1329 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/smp.h>
+#include <linux/wakelock.h>
+#include <linux/pm_qos.h>
+#include <linux/sysfs.h>
+#include <linux/stat.h>
+#include <asm/sections.h>
+#include <mach/socinfo.h>
+
+#include "qdss-priv.h"
+
+#define etm_writel(etm, cpu, val, off)	\
+			__raw_writel((val), etm.base + (SZ_4K * cpu) + off)
+#define etm_readl(etm, cpu, off)	\
+			__raw_readl(etm.base + (SZ_4K * cpu) + off)
+
+/*
+ * Device registers:
+ * 0x000 - 0x2FC: Trace		registers
+ * 0x300 - 0x314: Management	registers
+ * 0x318 - 0xEFC: Trace		registers
+ *
+ * Coresight registers
+ * 0xF00 - 0xF9C: Management	registers
+ * 0xFA0 - 0xFA4: Management	registers in PFTv1.0
+ *		  Trace		registers in PFTv1.1
+ * 0xFA8 - 0xFFC: Management	registers
+ */
+
+/* Trace registers (0x000-0x2FC) */
+#define ETMCR			(0x000)
+#define ETMCCR			(0x004)
+#define ETMTRIGGER		(0x008)
+#define ETMSR			(0x010)
+#define ETMSCR			(0x014)
+#define ETMTSSCR		(0x018)
+#define ETMTEEVR		(0x020)
+#define ETMTECR1		(0x024)
+#define ETMFFLR			(0x02C)
+#define ETMACVRn(n)		(0x040 + (n * 4))
+#define ETMACTRn(n)		(0x080 + (n * 4))
+#define ETMCNTRLDVRn(n)		(0x140 + (n * 4))
+#define ETMCNTENRn(n)		(0x150 + (n * 4))
+#define ETMCNTRLDEVRn(n)	(0x160 + (n * 4))
+#define ETMCNTVRn(n)		(0x170 + (n * 4))
+#define ETMSQ12EVR		(0x180)
+#define ETMSQ21EVR		(0x184)
+#define ETMSQ23EVR		(0x188)
+#define ETMSQ31EVR		(0x18C)
+#define ETMSQ32EVR		(0x190)
+#define ETMSQ13EVR		(0x194)
+#define ETMSQR			(0x19C)
+#define ETMEXTOUTEVRn(n)	(0x1A0 + (n * 4))
+#define ETMCIDCVRn(n)		(0x1B0 + (n * 4))
+#define ETMCIDCMR		(0x1BC)
+#define ETMIMPSPEC0		(0x1C0)
+#define ETMIMPSPEC1		(0x1C4)
+#define ETMIMPSPEC2		(0x1C8)
+#define ETMIMPSPEC3		(0x1CC)
+#define ETMIMPSPEC4		(0x1D0)
+#define ETMIMPSPEC5		(0x1D4)
+#define ETMIMPSPEC6		(0x1D8)
+#define ETMIMPSPEC7		(0x1DC)
+#define ETMSYNCFR		(0x1E0)
+#define ETMIDR			(0x1E4)
+#define ETMCCER			(0x1E8)
+#define ETMEXTINSELR		(0x1EC)
+#define ETMTESSEICR		(0x1F0)
+#define ETMEIBCR		(0x1F4)
+#define ETMTSEVR		(0x1F8)
+#define ETMAUXCR		(0x1FC)
+#define ETMTRACEIDR		(0x200)
+#define ETMVMIDCVR		(0x240)
+/* Management registers (0x300-0x314) */
+#define ETMOSLAR		(0x300)
+#define ETMOSLSR		(0x304)
+#define ETMOSSRR		(0x308)
+#define ETMPDCR			(0x310)
+#define ETMPDSR			(0x314)
+
+#define ETM_MAX_ADDR_CMP	(16)
+#define ETM_MAX_CNTR		(4)
+#define ETM_MAX_CTXID_CMP	(3)
+
+#define ETM_MODE_EXCLUDE	BIT(0)
+#define ETM_MODE_CYCACC		BIT(1)
+#define ETM_MODE_STALL		BIT(2)
+#define ETM_MODE_TIMESTAMP	BIT(3)
+#define ETM_MODE_CTXID		BIT(4)
+#define ETM_MODE_ALL		(0x1F)
+
+#define ETM_EVENT_MASK		(0x1FFFF)
+#define ETM_SYNC_MASK		(0xFFF)
+#define ETM_ALL_MASK		(0xFFFFFFFF)
+
+#define ETM_SEQ_STATE_MAX_VAL	(0x2)
+
+enum {
+	ETM_ADDR_TYPE_NONE,
+	ETM_ADDR_TYPE_SINGLE,
+	ETM_ADDR_TYPE_RANGE,
+	ETM_ADDR_TYPE_START,
+	ETM_ADDR_TYPE_STOP,
+};
+
+#define ETM_LOCK(cpu)							\
+do {									\
+	mb();								\
+	etm_writel(etm, cpu, 0x0, CS_LAR);				\
+} while (0)
+#define ETM_UNLOCK(cpu)							\
+do {									\
+	etm_writel(etm, cpu, CS_UNLOCK_MAGIC, CS_LAR);			\
+	mb();								\
+} while (0)
+
+
+#ifdef MODULE_PARAM_PREFIX
+#undef MODULE_PARAM_PREFIX
+#endif
+#define MODULE_PARAM_PREFIX "qdss."
+
+#ifdef CONFIG_MSM_QDSS_ETM_DEFAULT_ENABLE
+static int etm_boot_enable = 1;
+#else
+static int etm_boot_enable;
+#endif
+module_param_named(
+	etm_boot_enable, etm_boot_enable, int, S_IRUGO
+);
+
+struct etm_ctx {
+	void __iomem			*base;
+	bool				enabled;
+	struct wake_lock		wake_lock;
+	struct pm_qos_request		qos_req;
+	struct qdss_source		*src;
+	struct mutex			mutex;
+	struct device			*dev;
+	struct kobject			*kobj;
+	uint8_t				arch;
+	uint8_t				nr_addr_cmp;
+	uint8_t				nr_cntr;
+	uint8_t				nr_ext_inp;
+	uint8_t				nr_ext_out;
+	uint8_t				nr_ctxid_cmp;
+	uint8_t				reset;
+	uint32_t			mode;
+	uint32_t			ctrl;
+	uint32_t			trigger_event;
+	uint32_t			startstop_ctrl;
+	uint32_t			enable_event;
+	uint32_t			enable_ctrl1;
+	uint32_t			fifofull_level;
+	uint8_t				addr_idx;
+	uint32_t			addr_val[ETM_MAX_ADDR_CMP];
+	uint32_t			addr_acctype[ETM_MAX_ADDR_CMP];
+	uint32_t			addr_type[ETM_MAX_ADDR_CMP];
+	uint8_t				cntr_idx;
+	uint32_t			cntr_rld_val[ETM_MAX_CNTR];
+	uint32_t			cntr_event[ETM_MAX_CNTR];
+	uint32_t			cntr_rld_event[ETM_MAX_CNTR];
+	uint32_t			cntr_val[ETM_MAX_CNTR];
+	uint32_t			seq_12_event;
+	uint32_t			seq_21_event;
+	uint32_t			seq_23_event;
+	uint32_t			seq_31_event;
+	uint32_t			seq_32_event;
+	uint32_t			seq_13_event;
+	uint32_t			seq_curr_state;
+	uint8_t				ctxid_idx;
+	uint32_t			ctxid_val[ETM_MAX_CTXID_CMP];
+	uint32_t			ctxid_mask;
+	uint32_t			sync_freq;
+	uint32_t			timestamp_event;
+};
+
+static struct etm_ctx etm = {
+	.trigger_event		= 0x406F,
+	.enable_event		= 0x6F,
+	.enable_ctrl1		= 0x1,
+	.fifofull_level		= 0x28,
+	.addr_val		= {(uint32_t) _stext, (uint32_t) _etext},
+	.addr_type		= {ETM_ADDR_TYPE_RANGE, ETM_ADDR_TYPE_RANGE},
+	.cntr_event		= {[0 ... (ETM_MAX_CNTR - 1)] = 0x406F},
+	.cntr_rld_event		= {[0 ... (ETM_MAX_CNTR - 1)] = 0x406F},
+	.seq_12_event		= 0x406F,
+	.seq_21_event		= 0x406F,
+	.seq_23_event		= 0x406F,
+	.seq_31_event		= 0x406F,
+	.seq_32_event		= 0x406F,
+	.seq_13_event		= 0x406F,
+	.sync_freq		= 0x80,
+	.timestamp_event	= 0x406F,
+};
+
+
+/* ETM clock is derived from the processor clock and gets enabled on a
+ * logical OR of below items on Krait (pass2 onwards):
+ * 1.CPMR[ETMCLKEN] is 1
+ * 2.ETMCR[PD] is 0
+ * 3.ETMPDCR[PU] is 1
+ * 4.Reset is asserted (core or debug)
+ * 5.APB memory mapped requests (eg. EDAP access)
+ *
+ * 1., 2. and 3. above are permanent enables whereas 4. and 5. are temporary
+ * enables
+ *
+ * We rely on 5. to be able to access ETMCR and then use 2. above for ETM
+ * clock vote in the driver and the save-restore code uses 1. above
+ * for its vote
+ */
+static void etm_set_pwrdwn(int cpu)
+{
+	uint32_t etmcr;
+
+	etmcr = etm_readl(etm, cpu, ETMCR);
+	etmcr |= BIT(0);
+	etm_writel(etm, cpu, etmcr, ETMCR);
+}
+
+static void etm_clr_pwrdwn(int cpu)
+{
+	uint32_t etmcr;
+
+	etmcr = etm_readl(etm, cpu, ETMCR);
+	etmcr &= ~BIT(0);
+	etm_writel(etm, cpu, etmcr, ETMCR);
+}
+
+static void etm_set_prog(int cpu)
+{
+	uint32_t etmcr;
+	int count;
+
+	etmcr = etm_readl(etm, cpu, ETMCR);
+	etmcr |= BIT(10);
+	etm_writel(etm, cpu, etmcr, ETMCR);
+
+	for (count = TIMEOUT_US; BVAL(etm_readl(etm, cpu, ETMSR), 1) != 1
+				&& count > 0; count--)
+		udelay(1);
+	WARN(count == 0, "timeout while setting prog bit, ETMSR: %#x\n",
+	     etm_readl(etm, cpu, ETMSR));
+}
+
+static void etm_clr_prog(int cpu)
+{
+	uint32_t etmcr;
+	int count;
+
+	etmcr = etm_readl(etm, cpu, ETMCR);
+	etmcr &= ~BIT(10);
+	etm_writel(etm, cpu, etmcr, ETMCR);
+
+	for (count = TIMEOUT_US; BVAL(etm_readl(etm, cpu, ETMSR), 1) != 0
+				&& count > 0; count--)
+		udelay(1);
+	WARN(count == 0, "timeout while clearing prog bit, ETMSR: %#x\n",
+	     etm_readl(etm, cpu, ETMSR));
+}
+
+static void __etm_enable(int cpu)
+{
+	int i;
+
+	ETM_UNLOCK(cpu);
+	/* Vote for ETM power/clock enable */
+	etm_clr_pwrdwn(cpu);
+	etm_set_prog(cpu);
+
+	etm_writel(etm, cpu, etm.ctrl | BIT(10), ETMCR);
+	etm_writel(etm, cpu, etm.trigger_event, ETMTRIGGER);
+	etm_writel(etm, cpu, etm.startstop_ctrl, ETMTSSCR);
+	etm_writel(etm, cpu, etm.enable_event, ETMTEEVR);
+	etm_writel(etm, cpu, etm.enable_ctrl1, ETMTECR1);
+	etm_writel(etm, cpu, etm.fifofull_level, ETMFFLR);
+	for (i = 0; i < etm.nr_addr_cmp; i++) {
+		etm_writel(etm, cpu, etm.addr_val[i], ETMACVRn(i));
+		etm_writel(etm, cpu, etm.addr_acctype[i], ETMACTRn(i));
+	}
+	for (i = 0; i < etm.nr_cntr; i++) {
+		etm_writel(etm, cpu, etm.cntr_rld_val[i], ETMCNTRLDVRn(i));
+		etm_writel(etm, cpu, etm.cntr_event[i], ETMCNTENRn(i));
+		etm_writel(etm, cpu, etm.cntr_rld_event[i], ETMCNTRLDEVRn(i));
+		etm_writel(etm, cpu, etm.cntr_val[i], ETMCNTVRn(i));
+	}
+	etm_writel(etm, cpu, etm.seq_12_event, ETMSQ12EVR);
+	etm_writel(etm, cpu, etm.seq_21_event, ETMSQ21EVR);
+	etm_writel(etm, cpu, etm.seq_23_event, ETMSQ23EVR);
+	etm_writel(etm, cpu, etm.seq_31_event, ETMSQ31EVR);
+	etm_writel(etm, cpu, etm.seq_32_event, ETMSQ32EVR);
+	etm_writel(etm, cpu, etm.seq_13_event, ETMSQ13EVR);
+	etm_writel(etm, cpu, etm.seq_curr_state, ETMSQR);
+	for (i = 0; i < etm.nr_ext_out; i++)
+		etm_writel(etm, cpu, 0x0000406F, ETMEXTOUTEVRn(i));
+	for (i = 0; i < etm.nr_ctxid_cmp; i++)
+		etm_writel(etm, cpu, etm.ctxid_val[i], ETMCIDCVRn(i));
+	etm_writel(etm, cpu, etm.ctxid_mask, ETMCIDCMR);
+	etm_writel(etm, cpu, etm.sync_freq, ETMSYNCFR);
+	etm_writel(etm, cpu, 0x00000000, ETMEXTINSELR);
+	etm_writel(etm, cpu, etm.timestamp_event, ETMTSEVR);
+	etm_writel(etm, cpu, 0x00000000, ETMAUXCR);
+	etm_writel(etm, cpu, cpu+1, ETMTRACEIDR);
+	etm_writel(etm, cpu, 0x00000000, ETMVMIDCVR);
+
+	etm_clr_prog(cpu);
+	ETM_LOCK(cpu);
+}
+
+static int etm_enable(void)
+{
+	int ret, cpu;
+
+	if (etm.enabled) {
+		dev_err(etm.dev, "ETM tracing already enabled\n");
+		ret = -EPERM;
+		goto err;
+	}
+
+	wake_lock(&etm.wake_lock);
+	/* 1. causes all online cpus to come out of idle PC
+	 * 2. prevents idle PC until save restore flag is enabled atomically
+	 *
+	 * we rely on the user to prevent hotplug on/off racing with this
+	 * operation and to ensure cores where trace is expected to be turned
+	 * on are already hotplugged on
+	 */
+	pm_qos_update_request(&etm.qos_req, 0);
+
+	ret = qdss_enable(etm.src);
+	if (ret)
+		goto err_qdss;
+
+	for_each_online_cpu(cpu)
+		__etm_enable(cpu);
+
+	etm.enabled = true;
+
+	pm_qos_update_request(&etm.qos_req, PM_QOS_DEFAULT_VALUE);
+	wake_unlock(&etm.wake_lock);
+
+	dev_info(etm.dev, "ETM tracing enabled\n");
+	return 0;
+
+err_qdss:
+	pm_qos_update_request(&etm.qos_req, PM_QOS_DEFAULT_VALUE);
+	wake_unlock(&etm.wake_lock);
+err:
+	return ret;
+}
+
+static void __etm_disable(int cpu)
+{
+	ETM_UNLOCK(cpu);
+	etm_set_prog(cpu);
+
+	/* program trace enable to low by using always false event */
+	etm_writel(etm, cpu, 0x6F | BIT(14), ETMTEEVR);
+
+	/* Vote for ETM power/clock disable */
+	etm_set_pwrdwn(cpu);
+	ETM_LOCK(cpu);
+}
+
+static int etm_disable(void)
+{
+	int ret, cpu;
+
+	if (!etm.enabled) {
+		dev_err(etm.dev, "ETM tracing already disabled\n");
+		ret = -EPERM;
+		goto err;
+	}
+
+	wake_lock(&etm.wake_lock);
+	/* 1. causes all online cpus to come out of idle PC
+	 * 2. prevents idle PC until save restore flag is disabled atomically
+	 *
+	 * we rely on the user to prevent hotplug on/off racing with this
+	 * operation and to ensure cores where trace is expected to be turned
+	 * off are already hotplugged on
+	 */
+	pm_qos_update_request(&etm.qos_req, 0);
+
+	for_each_online_cpu(cpu)
+		__etm_disable(cpu);
+
+	qdss_disable(etm.src);
+
+	etm.enabled = false;
+
+	pm_qos_update_request(&etm.qos_req, PM_QOS_DEFAULT_VALUE);
+	wake_unlock(&etm.wake_lock);
+
+	dev_info(etm.dev, "ETM tracing disabled\n");
+	return 0;
+err:
+	return ret;
+}
+
+/* Memory mapped writes to clear os lock not supported */
+static void etm_os_unlock(void *unused)
+{
+	unsigned long value = 0x0;
+
+	asm("mcr p14, 1, %0, c1, c0, 4\n\t" : : "r" (value));
+	asm("isb\n\t");
+}
+
+#define ETM_STORE(__name, mask)						\
+static ssize_t __name##_store(struct kobject *kobj,			\
+			struct kobj_attribute *attr,			\
+			const char *buf, size_t n)			\
+{									\
+	unsigned long val;						\
+									\
+	if (sscanf(buf, "%lx", &val) != 1)				\
+		return -EINVAL;						\
+									\
+	etm.__name = val & mask;					\
+	return n;							\
+}
+
+#define ETM_SHOW(__name)						\
+static ssize_t __name##_show(struct kobject *kobj,			\
+			struct kobj_attribute *attr,			\
+			char *buf)					\
+{									\
+	unsigned long val = etm.__name;					\
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);		\
+}
+
+#define ETM_ATTR(__name)						\
+static struct kobj_attribute __name##_attr =				\
+	__ATTR(__name, S_IRUGO | S_IWUSR, __name##_show, __name##_store)
+#define ETM_ATTR_RO(__name)						\
+static struct kobj_attribute __name##_attr =				\
+	__ATTR(__name, S_IRUGO, __name##_show, NULL)
+
+static ssize_t enabled_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	int ret = 0;
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	mutex_lock(&etm.mutex);
+	if (val)
+		ret = etm_enable();
+	else
+		ret = etm_disable();
+	mutex_unlock(&etm.mutex);
+
+	if (ret)
+		return ret;
+	return n;
+}
+ETM_SHOW(enabled);
+ETM_ATTR(enabled);
+
+ETM_SHOW(nr_addr_cmp);
+ETM_ATTR_RO(nr_addr_cmp);
+ETM_SHOW(nr_cntr);
+ETM_ATTR_RO(nr_cntr);
+ETM_SHOW(nr_ctxid_cmp);
+ETM_ATTR_RO(nr_ctxid_cmp);
+
+/* Reset to trace everything i.e. exclude nothing. */
+static ssize_t reset_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	int i;
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	mutex_lock(&etm.mutex);
+	if (val) {
+		etm.mode = ETM_MODE_EXCLUDE;
+		etm.ctrl = 0x0;
+		if (cpu_is_krait_v1()) {
+			etm.mode |= ETM_MODE_CYCACC;
+			etm.ctrl |= BIT(12);
+		}
+		etm.trigger_event = 0x406F;
+		etm.startstop_ctrl = 0x0;
+		etm.enable_event = 0x6F;
+		etm.enable_ctrl1 = 0x1000000;
+		etm.fifofull_level = 0x28;
+		etm.addr_idx = 0x0;
+		for (i = 0; i < etm.nr_addr_cmp; i++) {
+			etm.addr_val[i] = 0x0;
+			etm.addr_acctype[i] = 0x0;
+			etm.addr_type[i] = ETM_ADDR_TYPE_NONE;
+		}
+		etm.cntr_idx = 0x0;
+		for (i = 0; i < etm.nr_cntr; i++) {
+			etm.cntr_rld_val[i] = 0x0;
+			etm.cntr_event[i] = 0x406F;
+			etm.cntr_rld_event[i] = 0x406F;
+			etm.cntr_val[i] = 0x0;
+		}
+		etm.seq_12_event = 0x406F;
+		etm.seq_21_event = 0x406F;
+		etm.seq_23_event = 0x406F;
+		etm.seq_31_event = 0x406F;
+		etm.seq_32_event = 0x406F;
+		etm.seq_13_event = 0x406F;
+		etm.seq_curr_state = 0x0;
+		etm.ctxid_idx = 0x0;
+		for (i = 0; i < etm.nr_ctxid_cmp; i++)
+			etm.ctxid_val[i] = 0x0;
+		etm.ctxid_mask = 0x0;
+		etm.sync_freq = 0x80;
+		etm.timestamp_event = 0x406F;
+	}
+	mutex_unlock(&etm.mutex);
+	return n;
+}
+ETM_SHOW(reset);
+ETM_ATTR(reset);
+
+static ssize_t mode_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	mutex_lock(&etm.mutex);
+	etm.mode = val & ETM_MODE_ALL;
+
+	if (etm.mode & ETM_MODE_EXCLUDE)
+		etm.enable_ctrl1 |= BIT(24);
+	else
+		etm.enable_ctrl1 &= ~BIT(24);
+
+	if (etm.mode & ETM_MODE_CYCACC)
+		etm.ctrl |= BIT(12);
+	else
+		etm.ctrl &= ~BIT(12);
+
+	if (etm.mode & ETM_MODE_STALL)
+		etm.ctrl |= BIT(7);
+	else
+		etm.ctrl &= ~BIT(7);
+
+	if (etm.mode & ETM_MODE_TIMESTAMP)
+		etm.ctrl |= BIT(28);
+	else
+		etm.ctrl &= ~BIT(28);
+	if (etm.mode & ETM_MODE_CTXID)
+		etm.ctrl |= (BIT(14) | BIT(15));
+	else
+		etm.ctrl &= ~(BIT(14) | BIT(15));
+	mutex_unlock(&etm.mutex);
+
+	return n;
+}
+ETM_SHOW(mode);
+ETM_ATTR(mode);
+
+ETM_STORE(trigger_event, ETM_EVENT_MASK);
+ETM_SHOW(trigger_event);
+ETM_ATTR(trigger_event);
+
+ETM_STORE(enable_event, ETM_EVENT_MASK);
+ETM_SHOW(enable_event);
+ETM_ATTR(enable_event);
+
+ETM_STORE(fifofull_level, ETM_ALL_MASK);
+ETM_SHOW(fifofull_level);
+ETM_ATTR(fifofull_level);
+
+static ssize_t addr_idx_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+	if (val >= etm.nr_addr_cmp)
+		return -EINVAL;
+
+	/* Use mutex to ensure index doesn't change while it gets dereferenced
+	 * multiple times within a mutex block elsewhere.
+	 */
+	mutex_lock(&etm.mutex);
+	etm.addr_idx = val;
+	mutex_unlock(&etm.mutex);
+	return n;
+}
+ETM_SHOW(addr_idx);
+ETM_ATTR(addr_idx);
+
+static ssize_t addr_single_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+	uint8_t idx;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	mutex_lock(&etm.mutex);
+	idx = etm.addr_idx;
+	if (!(etm.addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+	      etm.addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) {
+		mutex_unlock(&etm.mutex);
+		return -EPERM;
+	}
+
+	etm.addr_val[idx] = val;
+	etm.addr_type[idx] = ETM_ADDR_TYPE_SINGLE;
+	mutex_unlock(&etm.mutex);
+	return n;
+}
+static ssize_t addr_single_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf)
+{
+	unsigned long val;
+	uint8_t idx;
+
+	mutex_lock(&etm.mutex);
+	idx = etm.addr_idx;
+	if (!(etm.addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+	      etm.addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) {
+		mutex_unlock(&etm.mutex);
+		return -EPERM;
+	}
+
+	val = etm.addr_val[idx];
+	mutex_unlock(&etm.mutex);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+ETM_ATTR(addr_single);
+
+static ssize_t addr_range_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val1, val2;
+	uint8_t idx;
+
+	if (sscanf(buf, "%lx %lx", &val1, &val2) != 2)
+		return -EINVAL;
+	/* lower address comparator cannot have a higher address value */
+	if (val1 > val2)
+		return -EINVAL;
+
+	mutex_lock(&etm.mutex);
+	idx = etm.addr_idx;
+	if (idx % 2 != 0) {
+		mutex_unlock(&etm.mutex);
+		return -EPERM;
+	}
+	if (!((etm.addr_type[idx] == ETM_ADDR_TYPE_NONE &&
+	       etm.addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) ||
+	      (etm.addr_type[idx] == ETM_ADDR_TYPE_RANGE &&
+	       etm.addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) {
+		mutex_unlock(&etm.mutex);
+		return -EPERM;
+	}
+
+	etm.addr_val[idx] = val1;
+	etm.addr_type[idx] = ETM_ADDR_TYPE_RANGE;
+	etm.addr_val[idx + 1] = val2;
+	etm.addr_type[idx + 1] = ETM_ADDR_TYPE_RANGE;
+	etm.enable_ctrl1 |= (1 << (idx/2));
+	mutex_unlock(&etm.mutex);
+	return n;
+}
+static ssize_t addr_range_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf)
+{
+	unsigned long val1, val2;
+	uint8_t idx;
+
+	mutex_lock(&etm.mutex);
+	idx = etm.addr_idx;
+	if (idx % 2 != 0) {
+		mutex_unlock(&etm.mutex);
+		return -EPERM;
+	}
+	if (!((etm.addr_type[idx] == ETM_ADDR_TYPE_NONE &&
+	       etm.addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) ||
+	      (etm.addr_type[idx] == ETM_ADDR_TYPE_RANGE &&
+	       etm.addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) {
+		mutex_unlock(&etm.mutex);
+		return -EPERM;
+	}
+
+	val1 = etm.addr_val[idx];
+	val2 = etm.addr_val[idx + 1];
+	mutex_unlock(&etm.mutex);
+	return scnprintf(buf, PAGE_SIZE, "%#lx %#lx\n", val1, val2);
+}
+ETM_ATTR(addr_range);
+
+static ssize_t addr_start_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+	uint8_t idx;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	mutex_lock(&etm.mutex);
+	idx = etm.addr_idx;
+	if (!(etm.addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+	      etm.addr_type[idx] == ETM_ADDR_TYPE_START)) {
+		mutex_unlock(&etm.mutex);
+		return -EPERM;
+	}
+
+	etm.addr_val[idx] = val;
+	etm.addr_type[idx] = ETM_ADDR_TYPE_START;
+	etm.startstop_ctrl |= (1 << idx);
+	etm.enable_ctrl1 |= BIT(25);
+	mutex_unlock(&etm.mutex);
+	return n;
+}
+static ssize_t addr_start_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf)
+{
+	unsigned long val;
+	uint8_t idx;
+
+	mutex_lock(&etm.mutex);
+	idx = etm.addr_idx;
+	if (!(etm.addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+	      etm.addr_type[idx] == ETM_ADDR_TYPE_START)) {
+		mutex_unlock(&etm.mutex);
+		return -EPERM;
+	}
+
+	val = etm.addr_val[idx];
+	mutex_unlock(&etm.mutex);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+ETM_ATTR(addr_start);
+
+static ssize_t addr_stop_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+	uint8_t idx;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	mutex_lock(&etm.mutex);
+	idx = etm.addr_idx;
+	if (!(etm.addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+	      etm.addr_type[idx] == ETM_ADDR_TYPE_STOP)) {
+		mutex_unlock(&etm.mutex);
+		return -EPERM;
+	}
+
+	etm.addr_val[idx] = val;
+	etm.addr_type[idx] = ETM_ADDR_TYPE_STOP;
+	etm.startstop_ctrl |= (1 << (idx + 16));
+	etm.enable_ctrl1 |= BIT(25);
+	mutex_unlock(&etm.mutex);
+	return n;
+}
+static ssize_t addr_stop_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf)
+{
+	unsigned long val;
+	uint8_t idx;
+
+	mutex_lock(&etm.mutex);
+	idx = etm.addr_idx;
+	if (!(etm.addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+	      etm.addr_type[idx] == ETM_ADDR_TYPE_STOP)) {
+		mutex_unlock(&etm.mutex);
+		return -EPERM;
+	}
+
+	val = etm.addr_val[idx];
+	mutex_unlock(&etm.mutex);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+ETM_ATTR(addr_stop);
+
+static ssize_t addr_acctype_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	mutex_lock(&etm.mutex);
+	etm.addr_acctype[etm.addr_idx] = val;
+	mutex_unlock(&etm.mutex);
+	return n;
+}
+static ssize_t addr_acctype_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf)
+{
+	unsigned long val;
+
+	mutex_lock(&etm.mutex);
+	val = etm.addr_acctype[etm.addr_idx];
+	mutex_unlock(&etm.mutex);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+ETM_ATTR(addr_acctype);
+
+static ssize_t cntr_idx_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+	if (val >= etm.nr_cntr)
+		return -EINVAL;
+
+	/* Use mutex to ensure index doesn't change while it gets dereferenced
+	 * multiple times within a mutex block elsewhere.
+	 */
+	mutex_lock(&etm.mutex);
+	etm.cntr_idx = val;
+	mutex_unlock(&etm.mutex);
+	return n;
+}
+ETM_SHOW(cntr_idx);
+ETM_ATTR(cntr_idx);
+
+static ssize_t cntr_rld_val_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	mutex_lock(&etm.mutex);
+	etm.cntr_rld_val[etm.cntr_idx] = val;
+	mutex_unlock(&etm.mutex);
+	return n;
+}
+static ssize_t cntr_rld_val_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf)
+{
+	unsigned long val;
+	mutex_lock(&etm.mutex);
+	val = etm.cntr_rld_val[etm.cntr_idx];
+	mutex_unlock(&etm.mutex);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+ETM_ATTR(cntr_rld_val);
+
+static ssize_t cntr_event_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	mutex_lock(&etm.mutex);
+	etm.cntr_event[etm.cntr_idx] = val & ETM_EVENT_MASK;
+	mutex_unlock(&etm.mutex);
+	return n;
+}
+static ssize_t cntr_event_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf)
+{
+	unsigned long val;
+
+	mutex_lock(&etm.mutex);
+	val = etm.cntr_event[etm.cntr_idx];
+	mutex_unlock(&etm.mutex);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+ETM_ATTR(cntr_event);
+
+static ssize_t cntr_rld_event_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	mutex_lock(&etm.mutex);
+	etm.cntr_rld_event[etm.cntr_idx] = val & ETM_EVENT_MASK;
+	mutex_unlock(&etm.mutex);
+	return n;
+}
+static ssize_t cntr_rld_event_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf)
+{
+	unsigned long val;
+
+	mutex_lock(&etm.mutex);
+	val = etm.cntr_rld_event[etm.cntr_idx];
+	mutex_unlock(&etm.mutex);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+ETM_ATTR(cntr_rld_event);
+
+static ssize_t cntr_val_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	mutex_lock(&etm.mutex);
+	etm.cntr_val[etm.cntr_idx] = val;
+	mutex_unlock(&etm.mutex);
+	return n;
+}
+static ssize_t cntr_val_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf)
+{
+	unsigned long val;
+
+	mutex_lock(&etm.mutex);
+	val = etm.cntr_val[etm.cntr_idx];
+	mutex_unlock(&etm.mutex);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+ETM_ATTR(cntr_val);
+
+ETM_STORE(seq_12_event, ETM_EVENT_MASK);
+ETM_SHOW(seq_12_event);
+ETM_ATTR(seq_12_event);
+
+ETM_STORE(seq_21_event, ETM_EVENT_MASK);
+ETM_SHOW(seq_21_event);
+ETM_ATTR(seq_21_event);
+
+ETM_STORE(seq_23_event, ETM_EVENT_MASK);
+ETM_SHOW(seq_23_event);
+ETM_ATTR(seq_23_event);
+
+ETM_STORE(seq_31_event, ETM_EVENT_MASK);
+ETM_SHOW(seq_31_event);
+ETM_ATTR(seq_31_event);
+
+ETM_STORE(seq_32_event, ETM_EVENT_MASK);
+ETM_SHOW(seq_32_event);
+ETM_ATTR(seq_32_event);
+
+ETM_STORE(seq_13_event, ETM_EVENT_MASK);
+ETM_SHOW(seq_13_event);
+ETM_ATTR(seq_13_event);
+
+static ssize_t seq_curr_state_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+	if (val > ETM_SEQ_STATE_MAX_VAL)
+		return -EINVAL;
+
+	etm.seq_curr_state = val;
+	return n;
+}
+ETM_SHOW(seq_curr_state);
+ETM_ATTR(seq_curr_state);
+
+static ssize_t ctxid_idx_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+	if (val >= etm.nr_ctxid_cmp)
+		return -EINVAL;
+
+	/* Use mutex to ensure index doesn't change while it gets dereferenced
+	 * multiple times within a mutex block elsewhere.
+	 */
+	mutex_lock(&etm.mutex);
+	etm.ctxid_idx = val;
+	mutex_unlock(&etm.mutex);
+	return n;
+}
+ETM_SHOW(ctxid_idx);
+ETM_ATTR(ctxid_idx);
+
+static ssize_t ctxid_val_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	mutex_lock(&etm.mutex);
+	etm.ctxid_val[etm.ctxid_idx] = val;
+	mutex_unlock(&etm.mutex);
+	return n;
+}
+static ssize_t ctxid_val_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf)
+{
+	unsigned long val;
+
+	mutex_lock(&etm.mutex);
+	val = etm.ctxid_val[etm.ctxid_idx];
+	mutex_unlock(&etm.mutex);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+ETM_ATTR(ctxid_val);
+
+ETM_STORE(ctxid_mask, ETM_ALL_MASK);
+ETM_SHOW(ctxid_mask);
+ETM_ATTR(ctxid_mask);
+
+ETM_STORE(sync_freq, ETM_SYNC_MASK);
+ETM_SHOW(sync_freq);
+ETM_ATTR(sync_freq);
+
+ETM_STORE(timestamp_event, ETM_EVENT_MASK);
+ETM_SHOW(timestamp_event);
+ETM_ATTR(timestamp_event);
+
+static struct attribute *etm_attrs[] = {
+	&nr_addr_cmp_attr.attr,
+	&nr_cntr_attr.attr,
+	&nr_ctxid_cmp_attr.attr,
+	&reset_attr.attr,
+	&mode_attr.attr,
+	&trigger_event_attr.attr,
+	&enable_event_attr.attr,
+	&fifofull_level_attr.attr,
+	&addr_idx_attr.attr,
+	&addr_single_attr.attr,
+	&addr_range_attr.attr,
+	&addr_start_attr.attr,
+	&addr_stop_attr.attr,
+	&addr_acctype_attr.attr,
+	&cntr_idx_attr.attr,
+	&cntr_rld_val_attr.attr,
+	&cntr_event_attr.attr,
+	&cntr_rld_event_attr.attr,
+	&cntr_val_attr.attr,
+	&seq_12_event_attr.attr,
+	&seq_21_event_attr.attr,
+	&seq_23_event_attr.attr,
+	&seq_31_event_attr.attr,
+	&seq_32_event_attr.attr,
+	&seq_13_event_attr.attr,
+	&seq_curr_state_attr.attr,
+	&ctxid_idx_attr.attr,
+	&ctxid_val_attr.attr,
+	&ctxid_mask_attr.attr,
+	&sync_freq_attr.attr,
+	&timestamp_event_attr.attr,
+	NULL,
+};
+
+static struct attribute_group etm_attr_grp = {
+	.attrs = etm_attrs,
+};
+
+static int __devinit etm_sysfs_init(void)
+{
+	int ret;
+
+	etm.kobj = kobject_create_and_add("etm", qdss_get_modulekobj());
+	if (!etm.kobj) {
+		dev_err(etm.dev, "failed to create ETM sysfs kobject\n");
+		ret = -ENOMEM;
+		goto err_create;
+	}
+
+	ret = sysfs_create_file(etm.kobj, &enabled_attr.attr);
+	if (ret) {
+		dev_err(etm.dev, "failed to create ETM sysfs enabled"
+		" attribute\n");
+		goto err_file;
+	}
+
+	if (sysfs_create_group(etm.kobj, &etm_attr_grp))
+		dev_err(etm.dev, "failed to create ETM sysfs group\n");
+
+	return 0;
+err_file:
+	kobject_put(etm.kobj);
+err_create:
+	return ret;
+}
+
+static void __devexit etm_sysfs_exit(void)
+{
+	sysfs_remove_group(etm.kobj, &etm_attr_grp);
+	sysfs_remove_file(etm.kobj, &enabled_attr.attr);
+	kobject_put(etm.kobj);
+}
+
+static bool __devinit etm_arch_supported(uint8_t arch)
+{
+	switch (arch) {
+	case PFT_ARCH_V1_1:
+		break;
+	default:
+		return false;
+	}
+	return true;
+}
+
+static int __devinit etm_arch_init(void)
+{
+	int ret, i;
+	/* use cpu 0 for setup */
+	int cpu = 0;
+	uint32_t etmidr;
+	uint32_t etmccr;
+
+	/* Unlock OS lock first to allow memory mapped reads and writes */
+	etm_os_unlock(NULL);
+	smp_call_function(etm_os_unlock, NULL, 1);
+	ETM_UNLOCK(cpu);
+	/* Vote for ETM power/clock enable */
+	etm_clr_pwrdwn(cpu);
+	/* Set prog bit. It will be set from reset but this is included to
+	 * ensure it is set
+	 */
+	etm_set_prog(cpu);
+
+	/* find all capabilities */
+	etmidr = etm_readl(etm, cpu, ETMIDR);
+	etm.arch = BMVAL(etmidr, 4, 11);
+	if (etm_arch_supported(etm.arch) == false) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	etmccr = etm_readl(etm, cpu, ETMCCR);
+	etm.nr_addr_cmp = BMVAL(etmccr, 0, 3) * 2;
+	etm.nr_cntr = BMVAL(etmccr, 13, 15);
+	etm.nr_ext_inp = BMVAL(etmccr, 17, 19);
+	etm.nr_ext_out = BMVAL(etmccr, 20, 22);
+	etm.nr_ctxid_cmp = BMVAL(etmccr, 24, 25);
+
+	if (cpu_is_krait_v1()) {
+		/* Krait pass1 doesn't support include filtering and non-cycle
+		 * accurate tracing
+		 */
+		etm.mode = (ETM_MODE_EXCLUDE | ETM_MODE_CYCACC);
+		etm.ctrl = 0x1000;
+		etm.enable_ctrl1 = 0x1000000;
+		for (i = 0; i < etm.nr_addr_cmp; i++) {
+			etm.addr_val[i] = 0x0;
+			etm.addr_acctype[i] = 0x0;
+			etm.addr_type[i] = ETM_ADDR_TYPE_NONE;
+		}
+	}
+
+	/* Vote for ETM power/clock disable */
+	etm_set_pwrdwn(cpu);
+	ETM_LOCK(cpu);
+
+	return 0;
+err:
+	return ret;
+}
+
+static int __devinit etm_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct resource *res;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		ret = -EINVAL;
+		goto err_res;
+	}
+
+	etm.base = ioremap_nocache(res->start, resource_size(res));
+	if (!etm.base) {
+		ret = -EINVAL;
+		goto err_ioremap;
+	}
+
+	etm.dev = &pdev->dev;
+
+	mutex_init(&etm.mutex);
+	wake_lock_init(&etm.wake_lock, WAKE_LOCK_SUSPEND, "msm_etm");
+	pm_qos_add_request(&etm.qos_req, PM_QOS_CPU_DMA_LATENCY,
+						PM_QOS_DEFAULT_VALUE);
+	etm.src = qdss_get("msm_etm");
+	if (IS_ERR(etm.src)) {
+		ret = PTR_ERR(etm.src);
+		goto err_qdssget;
+	}
+
+	ret = qdss_clk_enable();
+	if (ret)
+		goto err_clk;
+
+	ret = etm_arch_init();
+	if (ret)
+		goto err_arch;
+
+	ret = etm_sysfs_init();
+	if (ret)
+		goto err_sysfs;
+
+	etm.enabled = false;
+
+	qdss_clk_disable();
+
+	dev_info(etm.dev, "ETM initialized\n");
+
+	if (etm_boot_enable)
+		etm_enable();
+
+	return 0;
+
+err_sysfs:
+err_arch:
+	qdss_clk_disable();
+err_clk:
+	qdss_put(etm.src);
+err_qdssget:
+	pm_qos_remove_request(&etm.qos_req);
+	wake_lock_destroy(&etm.wake_lock);
+	mutex_destroy(&etm.mutex);
+	iounmap(etm.base);
+err_ioremap:
+err_res:
+	dev_err(etm.dev, "ETM init failed\n");
+	return ret;
+}
+
+static int __devexit etm_remove(struct platform_device *pdev)
+{
+	if (etm.enabled)
+		etm_disable();
+	etm_sysfs_exit();
+	qdss_put(etm.src);
+	pm_qos_remove_request(&etm.qos_req);
+	wake_lock_destroy(&etm.wake_lock);
+	mutex_destroy(&etm.mutex);
+	iounmap(etm.base);
+
+	return 0;
+}
+
+static struct platform_driver etm_driver = {
+	.probe          = etm_probe,
+	.remove         = __devexit_p(etm_remove),
+	.driver         = {
+		.name   = "msm_etm",
+	},
+};
+
+int __init etm_init(void)
+{
+	return platform_driver_register(&etm_driver);
+}
+module_init(etm_init);
+
+void __exit etm_exit(void)
+{
+	platform_driver_unregister(&etm_driver);
+}
+module_exit(etm_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Program Flow Trace driver");
diff --git a/arch/arm/mach-msm/qdss-funnel.c b/arch/arm/mach-msm/qdss-funnel.c
new file mode 100644
index 0000000..52eb2b6
--- /dev/null
+++ b/arch/arm/mach-msm/qdss-funnel.c
@@ -0,0 +1,232 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+
+#include "qdss-priv.h"
+
+#define funnel_writel(funnel, id, val, off)	\
+			__raw_writel((val), funnel.base + (SZ_4K * id) + off)
+#define funnel_readl(funnel, id, off)		\
+			__raw_readl(funnel.base + (SZ_4K * id) + off)
+
+#define FUNNEL_FUNCTL			(0x000)
+#define FUNNEL_PRICTL			(0x004)
+#define FUNNEL_ITATBDATA0		(0xEEC)
+#define FUNNEL_ITATBCTR2		(0xEF0)
+#define FUNNEL_ITATBCTR1		(0xEF4)
+#define FUNNEL_ITATBCTR0		(0xEF8)
+
+
+#define FUNNEL_LOCK(id)							\
+do {									\
+	mb();								\
+	funnel_writel(funnel, id, 0x0, CS_LAR);				\
+} while (0)
+#define FUNNEL_UNLOCK(id)						\
+do {									\
+	funnel_writel(funnel, id, CS_UNLOCK_MAGIC, CS_LAR);		\
+	mb();								\
+} while (0)
+
+#define FUNNEL_HOLDTIME_MASK		(0xF00)
+#define FUNNEL_HOLDTIME_SHFT		(0x8)
+#define FUNNEL_HOLDTIME			(0x7 << FUNNEL_HOLDTIME_SHFT)
+
+struct funnel_ctx {
+	void __iomem	*base;
+	bool		enabled;
+	struct mutex	mutex;
+	struct device	*dev;
+	struct kobject	*kobj;
+	uint32_t	priority;
+};
+
+static struct funnel_ctx funnel;
+
+static void __funnel_enable(uint8_t id, uint32_t port_mask)
+{
+	uint32_t functl;
+
+	FUNNEL_UNLOCK(id);
+
+	functl = funnel_readl(funnel, id, FUNNEL_FUNCTL);
+	functl &= ~FUNNEL_HOLDTIME_MASK;
+	functl |= FUNNEL_HOLDTIME;
+	functl |= port_mask;
+	funnel_writel(funnel, id, functl, FUNNEL_FUNCTL);
+	funnel_writel(funnel, id, funnel.priority, FUNNEL_PRICTL);
+
+	FUNNEL_LOCK(id);
+}
+
+void funnel_enable(uint8_t id, uint32_t port_mask)
+{
+	mutex_lock(&funnel.mutex);
+	__funnel_enable(id, port_mask);
+	funnel.enabled = true;
+	dev_info(funnel.dev, "FUNNEL port mask 0x%lx enabled\n",
+					(unsigned long) port_mask);
+	mutex_unlock(&funnel.mutex);
+}
+
+static void __funnel_disable(uint8_t id, uint32_t port_mask)
+{
+	uint32_t functl;
+
+	FUNNEL_UNLOCK(id);
+
+	functl = funnel_readl(funnel, id, FUNNEL_FUNCTL);
+	functl &= ~port_mask;
+	funnel_writel(funnel, id, functl, FUNNEL_FUNCTL);
+
+	FUNNEL_LOCK(id);
+}
+
+void funnel_disable(uint8_t id, uint32_t port_mask)
+{
+	mutex_lock(&funnel.mutex);
+	__funnel_disable(id, port_mask);
+	funnel.enabled = false;
+	dev_info(funnel.dev, "FUNNEL port mask 0x%lx disabled\n",
+					(unsigned long) port_mask);
+	mutex_unlock(&funnel.mutex);
+}
+
+#define FUNNEL_ATTR(__name)						\
+static struct kobj_attribute __name##_attr =				\
+	__ATTR(__name, S_IRUGO | S_IWUSR, __name##_show, __name##_store)
+
+static ssize_t priority_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	funnel.priority = val;
+	return n;
+}
+static ssize_t priority_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf)
+{
+	unsigned long val = funnel.priority;
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+FUNNEL_ATTR(priority);
+
+static int __devinit funnel_sysfs_init(void)
+{
+	int ret;
+
+	funnel.kobj = kobject_create_and_add("funnel", qdss_get_modulekobj());
+	if (!funnel.kobj) {
+		dev_err(funnel.dev, "failed to create FUNNEL sysfs kobject\n");
+		ret = -ENOMEM;
+		goto err_create;
+	}
+
+	ret = sysfs_create_file(funnel.kobj, &priority_attr.attr);
+	if (ret) {
+		dev_err(funnel.dev, "failed to create FUNNEL sysfs priority"
+		" attribute\n");
+		goto err_file;
+	}
+
+	return 0;
+err_file:
+	kobject_put(funnel.kobj);
+err_create:
+	return ret;
+}
+
+static void __devexit funnel_sysfs_exit(void)
+{
+	sysfs_remove_file(funnel.kobj, &priority_attr.attr);
+	kobject_put(funnel.kobj);
+}
+
+static int __devinit funnel_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct resource *res;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		ret = -EINVAL;
+		goto err_res;
+	}
+
+	funnel.base = ioremap_nocache(res->start, resource_size(res));
+	if (!funnel.base) {
+		ret = -EINVAL;
+		goto err_ioremap;
+	}
+
+	funnel.dev = &pdev->dev;
+
+	mutex_init(&funnel.mutex);
+
+	funnel_sysfs_init();
+
+	dev_info(funnel.dev, "FUNNEL initialized\n");
+	return 0;
+
+err_ioremap:
+err_res:
+	dev_err(funnel.dev, "FUNNEL init failed\n");
+	return ret;
+}
+
+static int __devexit funnel_remove(struct platform_device *pdev)
+{
+	if (funnel.enabled)
+		funnel_disable(0x0, 0xFF);
+	funnel_sysfs_exit();
+	mutex_destroy(&funnel.mutex);
+	iounmap(funnel.base);
+
+	return 0;
+}
+
+static struct platform_driver funnel_driver = {
+	.probe          = funnel_probe,
+	.remove         = __devexit_p(funnel_remove),
+	.driver         = {
+		.name   = "msm_funnel",
+	},
+};
+
+static int __init funnel_init(void)
+{
+	return platform_driver_register(&funnel_driver);
+}
+module_init(funnel_init);
+
+static void __exit funnel_exit(void)
+{
+	platform_driver_unregister(&funnel_driver);
+}
+module_exit(funnel_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Funnel driver");
diff --git a/arch/arm/mach-msm/qdss-priv.h b/arch/arm/mach-msm/qdss-priv.h
new file mode 100644
index 0000000..f39bc52
--- /dev/null
+++ b/arch/arm/mach-msm/qdss-priv.h
@@ -0,0 +1,70 @@
+/* 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
+ * 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 _ARCH_ARM_MACH_MSM_QDSS_H_
+#define _ARCH_ARM_MACH_MSM_QDSS_H_
+
+#include <linux/bitops.h>
+#include <mach/qdss.h>
+
+/* Coresight management registers (0xF00-0xFCC)
+ * 0xFA0 - 0xFA4: Management	registers in PFTv1.0
+ *		  Trace		registers in PFTv1.1
+ */
+#define CS_ITCTRL		(0xF00)
+#define CS_CLAIMSET		(0xFA0)
+#define CS_CLAIMCLR		(0xFA4)
+#define CS_LAR			(0xFB0)
+#define CS_LSR			(0xFB4)
+#define CS_AUTHSTATUS		(0xFB8)
+#define CS_DEVID		(0xFC8)
+#define CS_DEVTYPE		(0xFCC)
+/* Peripheral id registers (0xFD0-0xFEC) */
+#define CS_PIDR4		(0xFD0)
+#define CS_PIDR5		(0xFD4)
+#define CS_PIDR6		(0xFD8)
+#define CS_PIDR7		(0xFDC)
+#define CS_PIDR0		(0xFE0)
+#define CS_PIDR1		(0xFE4)
+#define CS_PIDR2		(0xFE8)
+#define CS_PIDR3		(0xFEC)
+/* Component id registers (0xFF0-0xFFC) */
+#define CS_CIDR0		(0xFF0)
+#define CS_CIDR1		(0xFF4)
+#define CS_CIDR2		(0xFF8)
+#define CS_CIDR3		(0xFFC)
+
+/* DBGv7 with baseline CP14 registers implemented */
+#define ARM_DEBUG_ARCH_V7B	(0x3)
+/* DBGv7 with all CP14 registers implemented */
+#define ARM_DEBUG_ARCH_V7	(0x4)
+#define ARM_DEBUG_ARCH_V7_1	(0x5)
+#define ETM_ARCH_V3_3		(0x23)
+#define PFT_ARCH_V1_1		(0x31)
+
+#define TIMEOUT_US		(100)
+#define CS_UNLOCK_MAGIC		(0xC5ACCE55)
+
+#define BM(lsb, msb)		((BIT(msb) - BIT(lsb)) + BIT(msb))
+#define BMVAL(val, lsb, msb)	((val & BM(lsb, msb)) >> lsb)
+#define BVAL(val, n)		((val & BIT(n)) >> n)
+
+void etb_enable(void);
+void etb_disable(void);
+void etb_dump(void);
+void tpiu_disable(void);
+void funnel_enable(uint8_t id, uint32_t port_mask);
+void funnel_disable(uint8_t id, uint32_t port_mask);
+
+struct kobject *qdss_get_modulekobj(void);
+
+#endif
diff --git a/arch/arm/mach-msm/qdss-tpiu.c b/arch/arm/mach-msm/qdss-tpiu.c
new file mode 100644
index 0000000..fa15635
--- /dev/null
+++ b/arch/arm/mach-msm/qdss-tpiu.c
@@ -0,0 +1,141 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+
+#include "qdss-priv.h"
+
+#define tpiu_writel(tpiu, val, off)	__raw_writel((val), tpiu.base + off)
+#define tpiu_readl(tpiu, off)		__raw_readl(tpiu.base + off)
+
+#define TPIU_SUPP_PORTSZ				(0x000)
+#define TPIU_CURR_PORTSZ				(0x004)
+#define TPIU_SUPP_TRIGMODES				(0x100)
+#define TPIU_TRIG_CNTRVAL				(0x104)
+#define TPIU_TRIG_MULT					(0x108)
+#define TPIU_SUPP_TESTPATM				(0x200)
+#define TPIU_CURR_TESTPATM				(0x204)
+#define TPIU_TEST_PATREPCNTR				(0x208)
+#define TPIU_FFSR					(0x300)
+#define TPIU_FFCR					(0x304)
+#define TPIU_FSYNC_CNTR					(0x308)
+#define TPIU_EXTCTL_INPORT				(0x400)
+#define TPIU_EXTCTL_OUTPORT				(0x404)
+#define TPIU_ITTRFLINACK				(0xEE4)
+#define TPIU_ITTRFLIN					(0xEE8)
+#define TPIU_ITATBDATA0					(0xEEC)
+#define TPIU_ITATBCTR2					(0xEF0)
+#define TPIU_ITATBCTR1					(0xEF4)
+#define TPIU_ITATBCTR0					(0xEF8)
+
+
+#define TPIU_LOCK()							\
+do {									\
+	mb();								\
+	tpiu_writel(tpiu, 0x0, CS_LAR);					\
+} while (0)
+#define TPIU_UNLOCK()							\
+do {									\
+	tpiu_writel(tpiu, CS_UNLOCK_MAGIC, CS_LAR);			\
+	mb();								\
+} while (0)
+
+struct tpiu_ctx {
+	void __iomem	*base;
+	bool		enabled;
+	struct device	*dev;
+};
+
+static struct tpiu_ctx tpiu;
+
+static void __tpiu_disable(void)
+{
+	TPIU_UNLOCK();
+
+	tpiu_writel(tpiu, 0x3000, TPIU_FFCR);
+	tpiu_writel(tpiu, 0x3040, TPIU_FFCR);
+
+	TPIU_LOCK();
+}
+
+void tpiu_disable(void)
+{
+	__tpiu_disable();
+	tpiu.enabled = false;
+	dev_info(tpiu.dev, "TPIU disabled\n");
+}
+
+static int __devinit tpiu_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct resource *res;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		ret = -EINVAL;
+		goto err_res;
+	}
+
+	tpiu.base = ioremap_nocache(res->start, resource_size(res));
+	if (!tpiu.base) {
+		ret = -EINVAL;
+		goto err_ioremap;
+	}
+
+	tpiu.dev = &pdev->dev;
+
+	dev_info(tpiu.dev, "TPIU initialized\n");
+	return 0;
+
+err_ioremap:
+err_res:
+	dev_err(tpiu.dev, "TPIU init failed\n");
+	return ret;
+}
+
+static int __devexit tpiu_remove(struct platform_device *pdev)
+{
+	if (tpiu.enabled)
+		tpiu_disable();
+	iounmap(tpiu.base);
+
+	return 0;
+}
+
+static struct platform_driver tpiu_driver = {
+	.probe          = tpiu_probe,
+	.remove         = __devexit_p(tpiu_remove),
+	.driver         = {
+		.name   = "msm_tpiu",
+	},
+};
+
+static int __init tpiu_init(void)
+{
+	return platform_driver_register(&tpiu_driver);
+}
+module_init(tpiu_init);
+
+static void __exit tpiu_exit(void)
+{
+	platform_driver_unregister(&tpiu_driver);
+}
+module_exit(tpiu_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Trace Port Interface Unit driver");
diff --git a/arch/arm/mach-msm/qdss.c b/arch/arm/mach-msm/qdss.c
new file mode 100644
index 0000000..fd1fc2b
--- /dev/null
+++ b/arch/arm/mach-msm/qdss.c
@@ -0,0 +1,408 @@
+/* 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <mach/rpm.h>
+
+#include "rpm_resources.h"
+#include "qdss-priv.h"
+
+#define MAX_STR_LEN	(65535)
+
+enum {
+	QDSS_CLK_OFF,
+	QDSS_CLK_ON_DBG,
+	QDSS_CLK_ON_HSDBG,
+};
+
+/*
+ * Exclusion rules for structure fields.
+ *
+ * S: qdss.sources_mutex protected.
+ * I: qdss.sink_mutex protected.
+ * C: qdss.clk_mutex protected.
+ */
+struct qdss_ctx {
+	struct kobject			*modulekobj;
+	struct msm_qdss_platform_data	*pdata;
+	struct list_head		sources;	/* S: sources list */
+	struct mutex			sources_mutex;
+	uint8_t				sink_count;	/* I: sink count */
+	struct mutex			sink_mutex;
+	uint8_t				max_clk;
+	uint8_t				clk_count;	/* C: clk count */
+	struct mutex			clk_mutex;
+};
+
+static struct qdss_ctx qdss;
+
+/**
+ * qdss_get - get the qdss source handle
+ * @name: name of the qdss source
+ *
+ * Searches the sources list to get the qdss source handle for this source.
+ *
+ * CONTEXT:
+ * Typically called from init or probe functions
+ *
+ * RETURNS:
+ * pointer to struct qdss_source on success, %NULL on failure
+ */
+struct qdss_source *qdss_get(const char *name)
+{
+	struct qdss_source *src, *source = NULL;
+
+	mutex_lock(&qdss.sources_mutex);
+	list_for_each_entry(src, &qdss.sources, link) {
+		if (src->name) {
+			if (strncmp(src->name, name, MAX_STR_LEN))
+				continue;
+			source = src;
+			break;
+		}
+	}
+	mutex_unlock(&qdss.sources_mutex);
+
+	return source ? source : ERR_PTR(-ENOENT);
+}
+EXPORT_SYMBOL(qdss_get);
+
+/**
+ * qdss_put - release the qdss source handle
+ * @name: name of the qdss source
+ *
+ * CONTEXT:
+ * Typically called from driver remove or exit functions
+ */
+void qdss_put(struct qdss_source *src)
+{
+}
+EXPORT_SYMBOL(qdss_put);
+
+/**
+ * qdss_enable - enable qdss for the source
+ * @src: handle for the source making the call
+ *
+ * Enables qdss block (relevant funnel ports and sink) if not already
+ * enabled, otherwise increments the reference count
+ *
+ * CONTEXT:
+ * Might sleep. Uses a mutex lock. Should be called from a non-atomic context.
+ *
+ * RETURNS:
+ * 0 on success, non-zero on failure
+ */
+int qdss_enable(struct qdss_source *src)
+{
+	int ret;
+
+	if (!src)
+		return -EINVAL;
+
+	ret = qdss_clk_enable();
+	if (ret)
+		goto err;
+
+	if ((qdss.pdata)->afamily) {
+		mutex_lock(&qdss.sink_mutex);
+		if (qdss.sink_count == 0) {
+			etb_disable();
+			tpiu_disable();
+			/* enable ETB first to avoid losing any trace data */
+			etb_enable();
+		}
+		qdss.sink_count++;
+		mutex_unlock(&qdss.sink_mutex);
+	}
+
+	funnel_enable(0x0, src->fport_mask);
+	return 0;
+err:
+	return ret;
+}
+EXPORT_SYMBOL(qdss_enable);
+
+/**
+ * qdss_disable - disable qdss for the source
+ * @src: handle for the source making the call
+ *
+ * Disables qdss block (relevant funnel ports and sink) if the reference count
+ * is one, otherwise decrements the reference count
+ *
+ * CONTEXT:
+ * Might sleep. Uses a mutex lock. Should be called from a non-atomic context.
+ */
+void qdss_disable(struct qdss_source *src)
+{
+	if (!src)
+		return;
+
+	if ((qdss.pdata)->afamily) {
+		mutex_lock(&qdss.sink_mutex);
+		if (WARN(qdss.sink_count == 0, "qdss is unbalanced\n"))
+			goto out;
+		if (qdss.sink_count == 1) {
+			etb_dump();
+			etb_disable();
+		}
+		qdss.sink_count--;
+		mutex_unlock(&qdss.sink_mutex);
+	}
+
+	funnel_disable(0x0, src->fport_mask);
+	qdss_clk_disable();
+	return;
+out:
+	mutex_unlock(&qdss.sink_mutex);
+}
+EXPORT_SYMBOL(qdss_disable);
+
+/**
+ * qdss_disable_sink - force disable the current qdss sink(s)
+ *
+ * Force disable the current qdss sink(s) to stop the sink from accepting any
+ * trace generated subsequent to this call. This function should only be used
+ * as a way to stop the sink from getting polluted with trace data that is
+ * uninteresting after an event of interest has occured.
+ *
+ * CONTEXT:
+ * Can be called from atomic or non-atomic context.
+ */
+void qdss_disable_sink(void)
+{
+	if ((qdss.pdata)->afamily) {
+		etb_dump();
+		etb_disable();
+	}
+}
+EXPORT_SYMBOL(qdss_disable_sink);
+
+/**
+ * qdss_clk_enable - enable qdss clocks
+ *
+ * Enables qdss clocks via RPM if they aren't already enabled, otherwise
+ * increments the reference count.
+ *
+ * CONTEXT:
+ * Might sleep. Uses a mutex lock. Should be called from a non-atomic context.
+ *
+ * RETURNS:
+ * 0 on success, non-zero on failure
+ */
+int qdss_clk_enable(void)
+{
+	int ret;
+	struct msm_rpm_iv_pair iv;
+
+	mutex_lock(&qdss.clk_mutex);
+	if (qdss.clk_count == 0) {
+		iv.id = MSM_RPM_ID_QDSS_CLK;
+		if (qdss.max_clk)
+			iv.value = QDSS_CLK_ON_HSDBG;
+		else
+			iv.value = QDSS_CLK_ON_DBG;
+		ret = msm_rpmrs_set(MSM_RPM_CTX_SET_0, &iv, 1);
+		if (WARN(ret, "qdss clks not enabled (%d)\n", ret))
+			goto err_clk;
+	}
+	qdss.clk_count++;
+	mutex_unlock(&qdss.clk_mutex);
+	return 0;
+err_clk:
+	mutex_unlock(&qdss.clk_mutex);
+	return ret;
+}
+EXPORT_SYMBOL(qdss_clk_enable);
+
+/**
+ * qdss_clk_disable - disable qdss clocks
+ *
+ * Disables qdss clocks via RPM if the reference count is one, otherwise
+ * decrements the reference count.
+ *
+ * CONTEXT:
+ * Might sleep. Uses a mutex lock. Should be called from a non-atomic context.
+ */
+void qdss_clk_disable(void)
+{
+	int ret;
+	struct msm_rpm_iv_pair iv;
+
+	mutex_lock(&qdss.clk_mutex);
+	if (WARN(qdss.clk_count == 0, "qdss clks are unbalanced\n"))
+		goto out;
+	if (qdss.clk_count == 1) {
+		iv.id = MSM_RPM_ID_QDSS_CLK;
+		iv.value = QDSS_CLK_OFF;
+		ret = msm_rpmrs_set(MSM_RPM_CTX_SET_0, &iv, 1);
+		WARN(ret, "qdss clks not disabled (%d)\n", ret);
+	}
+	qdss.clk_count--;
+out:
+	mutex_unlock(&qdss.clk_mutex);
+}
+EXPORT_SYMBOL(qdss_clk_disable);
+
+struct kobject *qdss_get_modulekobj(void)
+{
+	return qdss.modulekobj;
+}
+
+#define QDSS_ATTR(name)						\
+static struct kobj_attribute name##_attr =				\
+		__ATTR(name, S_IRUGO | S_IWUSR, name##_show, name##_store)
+
+static ssize_t max_clk_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	qdss.max_clk = val;
+	return n;
+}
+static ssize_t max_clk_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf)
+{
+	unsigned long val = qdss.max_clk;
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+QDSS_ATTR(max_clk);
+
+static void __devinit qdss_add_sources(struct qdss_source *srcs, size_t num)
+{
+	mutex_lock(&qdss.sources_mutex);
+	while (num--) {
+		list_add_tail(&srcs->link, &qdss.sources);
+		srcs++;
+	}
+	mutex_unlock(&qdss.sources_mutex);
+}
+
+static int __init qdss_sysfs_init(void)
+{
+	int ret;
+
+	qdss.modulekobj = kset_find_obj(module_kset, KBUILD_MODNAME);
+	if (!qdss.modulekobj) {
+		pr_err("failed to find QDSS sysfs module kobject\n");
+		ret = -ENOENT;
+		goto err;
+	}
+
+	ret = sysfs_create_file(qdss.modulekobj, &max_clk_attr.attr);
+	if (ret) {
+		pr_err("failed to create QDSS sysfs max_clk attribute\n");
+		goto err;
+	}
+
+	return 0;
+err:
+	return ret;
+}
+
+static void __devexit qdss_sysfs_exit(void)
+{
+	sysfs_remove_file(qdss.modulekobj, &max_clk_attr.attr);
+}
+
+static int __devinit qdss_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct qdss_source *src_table;
+	size_t num_srcs;
+
+	mutex_init(&qdss.sources_mutex);
+	mutex_init(&qdss.clk_mutex);
+	mutex_init(&qdss.sink_mutex);
+
+	if (pdev->dev.platform_data == NULL) {
+		pr_err("%s: platform data is NULL\n", __func__);
+		ret = -ENODEV;
+		goto err_pdata;
+	}
+	qdss.pdata = pdev->dev.platform_data;
+
+	INIT_LIST_HEAD(&qdss.sources);
+	src_table = (qdss.pdata)->src_table;
+	num_srcs = (qdss.pdata)->size;
+	qdss_add_sources(src_table, num_srcs);
+
+	pr_info("QDSS arch initialized\n");
+	return 0;
+err_pdata:
+	mutex_destroy(&qdss.sink_mutex);
+	mutex_destroy(&qdss.clk_mutex);
+	mutex_destroy(&qdss.sources_mutex);
+	pr_err("QDSS init failed\n");
+	return ret;
+}
+
+static int __devexit qdss_remove(struct platform_device *pdev)
+{
+	qdss_sysfs_exit();
+	mutex_destroy(&qdss.sink_mutex);
+	mutex_destroy(&qdss.clk_mutex);
+	mutex_destroy(&qdss.sources_mutex);
+
+	return 0;
+}
+
+static struct platform_driver qdss_driver = {
+	.probe          = qdss_probe,
+	.remove         = __devexit_p(qdss_remove),
+	.driver         = {
+		.name   = "msm_qdss",
+	},
+};
+
+static int __init qdss_init(void)
+{
+	return platform_driver_register(&qdss_driver);
+}
+arch_initcall(qdss_init);
+
+static int __init qdss_module_init(void)
+{
+	int ret;
+
+	ret = qdss_sysfs_init();
+	if (ret)
+		goto err_sysfs;
+
+	pr_info("QDSS module initialized\n");
+	return 0;
+err_sysfs:
+	return ret;
+}
+module_init(qdss_module_init);
+
+static void __exit qdss_exit(void)
+{
+	platform_driver_unregister(&qdss_driver);
+}
+module_exit(qdss_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Qualcomm Debug SubSystem Driver");
diff --git a/arch/arm/mach-msm/ramdump.c b/arch/arm/mach-msm/ramdump.c
new file mode 100644
index 0000000..a18acd6
--- /dev/null
+++ b/arch/arm/mach-msm/ramdump.c
@@ -0,0 +1,263 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/workqueue.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/stringify.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/uaccess.h>
+
+#include <asm-generic/poll.h>
+
+#include "ramdump.h"
+
+#define RAMDUMP_WAIT_MSECS	120000
+
+struct ramdump_device {
+	char name[256];
+
+	unsigned int data_ready;
+	unsigned int consumer_present;
+	int ramdump_status;
+
+	struct completion ramdump_complete;
+	struct miscdevice device;
+
+	wait_queue_head_t dump_wait_q;
+	int nsegments;
+	struct ramdump_segment *segments;
+};
+
+static int ramdump_open(struct inode *inode, struct file *filep)
+{
+	struct ramdump_device *rd_dev = container_of(filep->private_data,
+				struct ramdump_device, device);
+	rd_dev->consumer_present = 1;
+	rd_dev->ramdump_status = 0;
+	return 0;
+}
+
+static int ramdump_release(struct inode *inode, struct file *filep)
+{
+	struct ramdump_device *rd_dev = container_of(filep->private_data,
+				struct ramdump_device, device);
+	rd_dev->consumer_present = 0;
+	rd_dev->data_ready = 0;
+	complete(&rd_dev->ramdump_complete);
+	return 0;
+}
+
+static unsigned long offset_translate(loff_t user_offset,
+		struct ramdump_device *rd_dev, unsigned long *data_left)
+{
+	int i = 0;
+
+	for (i = 0; i < rd_dev->nsegments; i++)
+		if (user_offset >= rd_dev->segments[i].size)
+			user_offset -= rd_dev->segments[i].size;
+		else
+			break;
+
+	if (i == rd_dev->nsegments) {
+		pr_debug("Ramdump(%s): offset_translate returning zero\n",
+				rd_dev->name);
+		*data_left = 0;
+		return 0;
+	}
+
+	*data_left = rd_dev->segments[i].size - user_offset;
+
+	pr_debug("Ramdump(%s): Returning address: %llx, data_left = %ld\n",
+		rd_dev->name, rd_dev->segments[i].address + user_offset,
+		*data_left);
+
+	return rd_dev->segments[i].address + user_offset;
+}
+
+#define MAX_IOREMAP_SIZE SZ_1M
+
+static int ramdump_read(struct file *filep, char __user *buf, size_t count,
+			loff_t *pos)
+{
+	struct ramdump_device *rd_dev = container_of(filep->private_data,
+				struct ramdump_device, device);
+	void *device_mem = NULL;
+	unsigned long data_left = 0;
+	unsigned long addr = 0;
+	size_t copy_size = 0;
+	int ret = 0;
+
+	if (rd_dev->data_ready == 0) {
+		pr_err("Ramdump(%s): Read when there's no dump available!",
+			rd_dev->name);
+		return -EPIPE;
+	}
+
+	addr = offset_translate(*pos, rd_dev, &data_left);
+
+	/* EOF check */
+	if (data_left == 0) {
+		pr_debug("Ramdump(%s): Ramdump complete. %lld bytes read.",
+			rd_dev->name, *pos);
+		rd_dev->ramdump_status = 0;
+		ret = 0;
+		goto ramdump_done;
+	}
+
+	copy_size = min(count, (size_t)MAX_IOREMAP_SIZE);
+	copy_size = min((unsigned long)copy_size, data_left);
+	device_mem = ioremap_nocache(addr, copy_size);
+
+	if (device_mem == NULL) {
+		pr_err("Ramdump(%s): Unable to ioremap: addr %lx, size %x\n",
+			rd_dev->name, addr, copy_size);
+		rd_dev->ramdump_status = -1;
+		ret = -ENOMEM;
+		goto ramdump_done;
+	}
+
+	if (copy_to_user(buf, device_mem, copy_size)) {
+		pr_err("Ramdump(%s): Couldn't copy all data to user.",
+			rd_dev->name);
+		iounmap(device_mem);
+		rd_dev->ramdump_status = -1;
+		ret = -EFAULT;
+		goto ramdump_done;
+	}
+
+	iounmap(device_mem);
+	*pos += copy_size;
+
+	pr_debug("Ramdump(%s): Read %d bytes from address %lx.",
+			rd_dev->name, copy_size, addr);
+
+	return copy_size;
+
+ramdump_done:
+	rd_dev->data_ready = 0;
+	*pos = 0;
+	complete(&rd_dev->ramdump_complete);
+	return ret;
+}
+
+static unsigned int ramdump_poll(struct file *filep,
+					struct poll_table_struct *wait)
+{
+	struct ramdump_device *rd_dev = container_of(filep->private_data,
+				struct ramdump_device, device);
+	unsigned int mask = 0;
+
+	if (rd_dev->data_ready)
+		mask |= (POLLIN | POLLRDNORM);
+
+	poll_wait(filep, &rd_dev->dump_wait_q, wait);
+	return mask;
+}
+
+const struct file_operations ramdump_file_ops = {
+	.open = ramdump_open,
+	.release = ramdump_release,
+	.read = ramdump_read,
+	.poll = ramdump_poll
+};
+
+void *create_ramdump_device(const char *dev_name)
+{
+	int ret;
+	struct ramdump_device *rd_dev;
+
+	if (!dev_name) {
+		pr_err("%s: Invalid device name.\n", __func__);
+		return NULL;
+	}
+
+	rd_dev = kzalloc(sizeof(struct ramdump_device), GFP_KERNEL);
+
+	if (!rd_dev) {
+		pr_err("%s: Couldn't alloc space for ramdump device!",
+			__func__);
+		return NULL;
+	}
+
+	snprintf(rd_dev->name, ARRAY_SIZE(rd_dev->name), "ramdump_%s",
+		 dev_name);
+
+	init_completion(&rd_dev->ramdump_complete);
+
+	rd_dev->device.minor = MISC_DYNAMIC_MINOR;
+	rd_dev->device.name = rd_dev->name;
+	rd_dev->device.fops = &ramdump_file_ops;
+
+	init_waitqueue_head(&rd_dev->dump_wait_q);
+
+	ret = misc_register(&rd_dev->device);
+
+	if (ret) {
+		pr_err("%s: misc_register failed for %s (%d)", __func__,
+				dev_name, ret);
+		kfree(rd_dev);
+		return NULL;
+	}
+
+	return (void *)rd_dev;
+}
+
+int do_ramdump(void *handle, struct ramdump_segment *segments,
+		int nsegments)
+{
+	int ret, i;
+	struct ramdump_device *rd_dev = (struct ramdump_device *)handle;
+
+	if (!rd_dev->consumer_present) {
+		pr_err("Ramdump(%s): No consumers. Aborting..\n", rd_dev->name);
+		return -EPIPE;
+	}
+
+	for (i = 0; i < nsegments; i++)
+		segments[i].size = PAGE_ALIGN(segments[i].size);
+
+	rd_dev->segments = segments;
+	rd_dev->nsegments = nsegments;
+
+	rd_dev->data_ready = 1;
+	rd_dev->ramdump_status = -1;
+
+	INIT_COMPLETION(rd_dev->ramdump_complete);
+
+	/* Tell userspace that the data is ready */
+	wake_up(&rd_dev->dump_wait_q);
+
+	/* Wait (with a timeout) to let the ramdump complete */
+	ret = wait_for_completion_timeout(&rd_dev->ramdump_complete,
+			msecs_to_jiffies(RAMDUMP_WAIT_MSECS));
+
+	if (!ret) {
+		pr_err("Ramdump(%s): Timed out waiting for userspace.\n",
+			rd_dev->name);
+		ret = -EPIPE;
+	} else
+		ret = (rd_dev->ramdump_status == 0) ? 0 : -EPIPE;
+
+	rd_dev->data_ready = 0;
+	return ret;
+}
diff --git a/arch/arm/mach-msm/ramdump.h b/arch/arm/mach-msm/ramdump.h
new file mode 100644
index 0000000..0b60a44
--- /dev/null
+++ b/arch/arm/mach-msm/ramdump.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _RAMDUMP_HEADER
+#define _RAMDUMP_HEADER
+
+struct ramdump_segment {
+	unsigned long address;
+	unsigned long size;
+};
+
+void *create_ramdump_device(const char *dev_name);
+int do_ramdump(void *handle, struct ramdump_segment *segments,
+		int nsegments);
+
+#endif
diff --git a/arch/arm/mach-msm/remote_spinlock.c b/arch/arm/mach-msm/remote_spinlock.c
new file mode 100644
index 0000000..2480433
--- /dev/null
+++ b/arch/arm/mach-msm/remote_spinlock.c
@@ -0,0 +1,192 @@
+/* Copyright (c) 2008-2009, 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+
+#include <asm/system.h>
+
+#include <mach/msm_iomap.h>
+#include <mach/remote_spinlock.h>
+#include <mach/dal.h>
+#include "smd_private.h"
+#include <linux/module.h>
+
+static void remote_spin_release_all_locks(uint32_t pid, int count);
+
+#if defined(CONFIG_MSM_REMOTE_SPINLOCK_SFPB)
+#define SFPB_SPINLOCK_COUNT 8
+#define MSM_SFPB_MUTEX_REG_BASE 0x01200600
+#define MSM_SFPB_MUTEX_REG_SIZE	(33 * 4)
+
+static void *hw_mutex_reg_base;
+static DEFINE_MUTEX(hw_map_init_lock);
+
+static int remote_spinlock_init_address(int id, _remote_spinlock_t *lock)
+{
+	if (id >= SFPB_SPINLOCK_COUNT)
+		return -EINVAL;
+
+	if (!hw_mutex_reg_base) {
+		mutex_lock(&hw_map_init_lock);
+		if (!hw_mutex_reg_base)
+			hw_mutex_reg_base = ioremap(MSM_SFPB_MUTEX_REG_BASE,
+				   MSM_SFPB_MUTEX_REG_SIZE);
+		mutex_unlock(&hw_map_init_lock);
+		BUG_ON(hw_mutex_reg_base == NULL);
+	}
+
+	*lock = hw_mutex_reg_base + 0x4 + id * 4;
+	return 0;
+}
+
+void _remote_spin_release_all(uint32_t pid)
+{
+	remote_spin_release_all_locks(pid, SFPB_SPINLOCK_COUNT);
+}
+
+#else
+#define SMEM_SPINLOCK_COUNT 8
+#define SMEM_SPINLOCK_ARRAY_SIZE (SMEM_SPINLOCK_COUNT * sizeof(uint32_t))
+
+static int remote_spinlock_init_address(int id, _remote_spinlock_t *lock)
+{
+	_remote_spinlock_t spinlock_start;
+
+	if (id >= SMEM_SPINLOCK_COUNT)
+		return -EINVAL;
+
+	spinlock_start = smem_alloc(SMEM_SPINLOCK_ARRAY,
+				    SMEM_SPINLOCK_ARRAY_SIZE);
+	if (spinlock_start == NULL)
+		return -ENXIO;
+
+	*lock = spinlock_start + id;
+
+	return 0;
+}
+
+void _remote_spin_release_all(uint32_t pid)
+{
+	remote_spin_release_all_locks(pid, SMEM_SPINLOCK_COUNT);
+}
+
+#endif
+
+/**
+ * Release all spinlocks owned by @pid.
+ *
+ * This is only to be used for situations where the processor owning
+ * spinlocks has crashed and the spinlocks must be released.
+ *
+ * @pid - processor ID of processor to release
+ */
+static void remote_spin_release_all_locks(uint32_t pid, int count)
+{
+	int n;
+	 _remote_spinlock_t lock;
+
+	for (n = 0; n < count; ++n) {
+		if (remote_spinlock_init_address(n, &lock) == 0)
+			_remote_spin_release(&lock, pid);
+	}
+}
+
+static int
+remote_spinlock_dal_init(const char *chunk_name, _remote_spinlock_t *lock)
+{
+	void *dal_smem_start, *dal_smem_end;
+	uint32_t dal_smem_size;
+	struct dal_chunk_header *cur_header;
+
+	if (!chunk_name)
+		return -EINVAL;
+
+	dal_smem_start = smem_get_entry(SMEM_DAL_AREA, &dal_smem_size);
+	if (!dal_smem_start)
+		return -ENXIO;
+
+	dal_smem_end = dal_smem_start + dal_smem_size;
+
+	/* Find first chunk header */
+	cur_header = (struct dal_chunk_header *)
+			(((uint32_t)dal_smem_start + (4095)) & ~4095);
+	*lock = NULL;
+	while (cur_header->size != 0
+		&& ((uint32_t)(cur_header + 1) < (uint32_t)dal_smem_end)) {
+
+		/* Check if chunk name matches */
+		if (!strncmp(cur_header->name, chunk_name,
+						DAL_CHUNK_NAME_LENGTH)) {
+			*lock = (_remote_spinlock_t)&cur_header->lock;
+			return 0;
+		}
+		cur_header = (void *)cur_header + cur_header->size;
+	}
+
+	pr_err("%s: DAL remote lock \"%s\" not found.\n", __func__,
+		chunk_name);
+	return -EINVAL;
+}
+
+int _remote_spin_lock_init(remote_spinlock_id_t id, _remote_spinlock_t *lock)
+{
+	BUG_ON(id == NULL);
+
+	if (id[0] == 'D' && id[1] == ':') {
+		/* DAL chunk name starts after "D:" */
+		return remote_spinlock_dal_init(&id[2], lock);
+	} else if (id[0] == 'S' && id[1] == ':') {
+		/* Single-digit lock ID follows "S:" */
+		BUG_ON(id[3] != '\0');
+
+		return remote_spinlock_init_address((((uint8_t)id[2])-'0'),
+				lock);
+	} else {
+		return -EINVAL;
+	}
+}
+
+int _remote_mutex_init(struct remote_mutex_id *id, _remote_mutex_t *lock)
+{
+	BUG_ON(id == NULL);
+
+	lock->delay_us = id->delay_us;
+	return _remote_spin_lock_init(id->r_spinlock_id, &(lock->r_spinlock));
+}
+EXPORT_SYMBOL(_remote_mutex_init);
+
+void _remote_mutex_lock(_remote_mutex_t *lock)
+{
+	while (!_remote_spin_trylock(&(lock->r_spinlock))) {
+		if (lock->delay_us >= 1000)
+			msleep(lock->delay_us/1000);
+		else
+			udelay(lock->delay_us);
+	}
+}
+EXPORT_SYMBOL(_remote_mutex_lock);
+
+void _remote_mutex_unlock(_remote_mutex_t *lock)
+{
+	_remote_spin_unlock(&(lock->r_spinlock));
+}
+EXPORT_SYMBOL(_remote_mutex_unlock);
+
+int _remote_mutex_trylock(_remote_mutex_t *lock)
+{
+	return _remote_spin_trylock(&(lock->r_spinlock));
+}
+EXPORT_SYMBOL(_remote_mutex_trylock);
diff --git a/arch/arm/mach-msm/reset_modem.c b/arch/arm/mach-msm/reset_modem.c
new file mode 100644
index 0000000..8e92456
--- /dev/null
+++ b/arch/arm/mach-msm/reset_modem.c
@@ -0,0 +1,183 @@
+/* Copyright (c) 2008-2009, 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.
+ *
+ */
+/*
+ * MSM architecture driver to reset the modem
+ */
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <mach/proc_comm.h>
+
+#include "smd_private.h"
+
+#define DEBUG
+/* #undef DEBUG */
+#ifdef DEBUG
+#define D(x...) printk(x)
+#else
+#define D(x...) do {} while (0)
+#endif
+
+static ssize_t reset_modem_read(struct file *fp, char __user *buf,
+			size_t count, loff_t *pos)
+{
+	return 0;
+}
+
+static ssize_t reset_modem_write(struct file *fp, const char __user *buf,
+			 size_t count, loff_t *pos)
+{
+	unsigned char cmd[64];
+	int len;
+	int time;
+	int zero = 0;
+	int r;
+
+	if (count < 1)
+		return 0;
+
+	len = count > 63 ? 63 : count;
+
+	if (copy_from_user(cmd, buf, len))
+		return -EFAULT;
+
+	cmd[len] = 0;
+
+	/* lazy */
+	if (cmd[len-1] == '\n') {
+		cmd[len-1] = 0;
+		len--;
+	}
+
+	if (!strncmp(cmd, "wait", 4)) {
+		D(KERN_ERR "INFO:%s:%i:%s: "
+		       "MODEM RESTART: WAIT\n",
+		       __FILE__,
+		       __LINE__,
+		       __func__);
+		smsm_reset_modem(SMSM_MODEM_WAIT);
+	} else if (!strncmp(cmd, "continue", 8)) {
+		D(KERN_ERR "INFO:%s:%i:%s: "
+		       "MODEM RESTART: CONTINUE\n",
+		       __FILE__,
+		       __LINE__,
+		       __func__);
+		smsm_reset_modem_cont();
+	} else if (!strncmp(cmd, "download", 8)) {
+		D(KERN_ERR "INFO:%s:%i:%s: "
+		       "MODEM RESTART: DOWNLOAD\n",
+		       __FILE__,
+		       __LINE__,
+		       __func__);
+		smsm_reset_modem(SMSM_SYSTEM_DOWNLOAD);
+	} else if (sscanf(cmd, "deferred reset %i", &time) == 1) {
+		D(KERN_ERR "INFO:%s:%i:%s: "
+		       "MODEM RESTART: DEFERRED RESET %ims\n",
+		       __FILE__,
+		       __LINE__,
+		       __func__,
+		       time);
+		if (time == 0) {
+			r = 0;
+			msm_proc_comm_reset_modem_now();
+		} else {
+			r = msm_proc_comm(PCOM_RESET_MODEM, &time, &zero);
+		}
+		if (r < 0)
+			return r;
+	} else if (!strncmp(cmd, "deferred reset", 14)) {
+		D(KERN_ERR "INFO:%s:%i:%s: "
+		       "MODEM RESTART: DEFERRED RESET 0ms\n",
+		       __FILE__,
+		       __LINE__,
+		       __func__);
+		r = 0;
+		msm_proc_comm_reset_modem_now();
+		if (r < 0)
+			return r;
+	} else if (!strncmp(cmd, "reset chip now", 14)) {
+		uint param1 = 0x0;
+		uint param2 = 0x0;
+
+		D(KERN_ERR "INFO:%s:%i:%s: "
+		  "MODEM RESTART: CHIP RESET IMMEDIATE\n",
+		  __FILE__,
+		  __LINE__,
+		  __func__);
+
+		r = msm_proc_comm(PCOM_RESET_CHIP_IMM, &param1, &param2);
+
+		if (r < 0)
+			return r;
+	} else if (!strncmp(cmd, "reset chip", 10)) {
+
+		uint param1 = 0x0;
+		uint param2 = 0x0;
+
+		D(KERN_ERR "INFO:%s:%i:%s: "
+		  "MODEM RESTART: CHIP RESET \n",
+		  __FILE__,
+		  __LINE__,
+		  __func__);
+
+		r = msm_proc_comm(PCOM_RESET_CHIP, &param1, &param2);
+
+		if (r < 0)
+			return r;
+	} else if (!strncmp(cmd, "reset", 5)) {
+		printk(KERN_ERR "INFO:%s:%i:%s: "
+		       "MODEM RESTART: RESET\n",
+		       __FILE__,
+		       __LINE__,
+		       __func__);
+		smsm_reset_modem(SMSM_RESET);
+	} else
+		return -EINVAL;
+
+	return count;
+}
+
+static int reset_modem_open(struct inode *ip, struct file *fp)
+{
+	return 0;
+}
+
+static int reset_modem_release(struct inode *ip, struct file *fp)
+{
+	return 0;
+}
+
+static const struct file_operations reset_modem_fops = {
+	.owner = THIS_MODULE,
+	.read = reset_modem_read,
+	.write = reset_modem_write,
+	.open = reset_modem_open,
+	.release = reset_modem_release,
+};
+
+static struct miscdevice reset_modem_dev = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "reset_modem",
+	.fops = &reset_modem_fops,
+};
+
+static int __init reset_modem_init(void)
+{
+	return misc_register(&reset_modem_dev);
+}
+
+module_init(reset_modem_init);
+
+MODULE_DESCRIPTION("Reset Modem");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/restart-fsm9xxx.c b/arch/arm/mach-msm/restart-fsm9xxx.c
new file mode 100644
index 0000000..2bfefb2
--- /dev/null
+++ b/arch/arm/mach-msm/restart-fsm9xxx.c
@@ -0,0 +1,42 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/reboot.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#define FEMTO_GPIO_PS_HOLD 161
+
+void arch_reset(char mode, const char *cmd)
+{
+	pr_notice("Going down for restart now\n");
+	msleep(3000);
+
+	/* Configure FEMTO_GPIO_PS_HOLD as a general purpose output */
+	if (gpio_tlmm_config(GPIO_CFG(FEMTO_GPIO_PS_HOLD, 0,
+			GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
+			GPIO_CFG_2MA), GPIO_CFG_ENABLE))
+		pr_err("%s: gpio_tlmm_config (gpio=%d) failed\n",
+			__func__, FEMTO_GPIO_PS_HOLD);
+
+	/* Now set it low to power cycle the entire board */
+	gpio_set_value(FEMTO_GPIO_PS_HOLD, 0);
+
+	msleep(10000);
+	pr_err("Restarting has failed\n");
+}
diff --git a/arch/arm/mach-msm/restart.c b/arch/arm/mach-msm/restart.c
new file mode 100644
index 0000000..e45e2c4
--- /dev/null
+++ b/arch/arm/mach-msm/restart.c
@@ -0,0 +1,267 @@
+/* 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
+ * 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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/reboot.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/cpu.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/pmic8058.h>
+#include <linux/mfd/pmic8901.h>
+#include <linux/mfd/pm8xxx/misc.h>
+
+#include <asm/mach-types.h>
+
+#include <mach/msm_iomap.h>
+#include <mach/restart.h>
+#include <mach/socinfo.h>
+#include <mach/irqs.h>
+#include <mach/scm.h>
+#include "msm_watchdog.h"
+#include "timer.h"
+
+#define WDT0_RST	0x38
+#define WDT0_EN		0x40
+#define WDT0_BARK_TIME	0x4C
+#define WDT0_BITE_TIME	0x5C
+
+#define PSHOLD_CTL_SU (MSM_TLMM_BASE + 0x820)
+
+#define RESTART_REASON_ADDR 0x65C
+#define DLOAD_MODE_ADDR     0x0
+
+#define SCM_IO_DISABLE_PMIC_ARBITER	1
+
+static int restart_mode;
+void *restart_reason;
+
+int pmic_reset_irq;
+static void __iomem *msm_tmr0_base;
+
+#ifdef CONFIG_MSM_DLOAD_MODE
+static int in_panic;
+static void *dload_mode_addr;
+
+/* Download mode master kill-switch */
+static int dload_set(const char *val, struct kernel_param *kp);
+static int download_mode = 1;
+module_param_call(download_mode, dload_set, param_get_int,
+			&download_mode, 0644);
+
+static int panic_prep_restart(struct notifier_block *this,
+			      unsigned long event, void *ptr)
+{
+	in_panic = 1;
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block panic_blk = {
+	.notifier_call	= panic_prep_restart,
+};
+
+static void set_dload_mode(int on)
+{
+	if (dload_mode_addr) {
+		__raw_writel(on ? 0xE47B337D : 0, dload_mode_addr);
+		__raw_writel(on ? 0xCE14091A : 0,
+		       dload_mode_addr + sizeof(unsigned int));
+		mb();
+	}
+}
+
+static int dload_set(const char *val, struct kernel_param *kp)
+{
+	int ret;
+	int old_val = download_mode;
+
+	ret = param_set_int(val, kp);
+
+	if (ret)
+		return ret;
+
+	/* If download_mode is not zero or one, ignore. */
+	if (download_mode >> 1) {
+		download_mode = old_val;
+		return -EINVAL;
+	}
+
+	set_dload_mode(download_mode);
+
+	return 0;
+}
+#else
+#define set_dload_mode(x) do {} while (0)
+#endif
+
+void msm_set_restart_mode(int mode)
+{
+	restart_mode = mode;
+}
+EXPORT_SYMBOL(msm_set_restart_mode);
+
+static void __msm_power_off(int lower_pshold)
+{
+	printk(KERN_CRIT "Powering off the SoC\n");
+#ifdef CONFIG_MSM_DLOAD_MODE
+	set_dload_mode(0);
+#endif
+	pm8xxx_reset_pwr_off(0);
+
+	if (lower_pshold) {
+		__raw_writel(0, PSHOLD_CTL_SU);
+		mdelay(10000);
+		printk(KERN_ERR "Powering off has failed\n");
+	}
+	return;
+}
+
+static void msm_power_off(void)
+{
+	/* MSM initiated power off, lower ps_hold */
+	__msm_power_off(1);
+}
+
+static void cpu_power_off(void *data)
+{
+	int rc;
+
+	pr_err("PMIC Initiated shutdown %s cpu=%d\n", __func__,
+						smp_processor_id());
+	if (smp_processor_id() == 0) {
+		/*
+		 * PMIC initiated power off, do not lower ps_hold, pmic will
+		 * shut msm down
+		 */
+		__msm_power_off(0);
+
+		pet_watchdog();
+		pr_err("Calling scm to disable arbiter\n");
+		/* call secure manager to disable arbiter and never return */
+		rc = scm_call_atomic1(SCM_SVC_PWR,
+						SCM_IO_DISABLE_PMIC_ARBITER, 1);
+
+		pr_err("SCM returned even when asked to busy loop rc=%d\n", rc);
+		pr_err("waiting on pmic to shut msm down\n");
+	}
+
+	preempt_disable();
+	while (1)
+		;
+}
+
+static irqreturn_t resout_irq_handler(int irq, void *dev_id)
+{
+	pr_warn("%s PMIC Initiated shutdown\n", __func__);
+	oops_in_progress = 1;
+	smp_call_function_many(cpu_online_mask, cpu_power_off, NULL, 0);
+	if (smp_processor_id() == 0)
+		cpu_power_off(NULL);
+	preempt_disable();
+	while (1)
+		;
+	return IRQ_HANDLED;
+}
+
+void arch_reset(char mode, const char *cmd)
+{
+
+#ifdef CONFIG_MSM_DLOAD_MODE
+
+	/* This looks like a normal reboot at this point. */
+	set_dload_mode(0);
+
+	/* Write download mode flags if we're panic'ing */
+	set_dload_mode(in_panic);
+
+	/* Write download mode flags if restart_mode says so */
+	if (restart_mode == RESTART_DLOAD)
+		set_dload_mode(1);
+
+	/* Kill download mode if master-kill switch is set */
+	if (!download_mode)
+		set_dload_mode(0);
+#endif
+
+	printk(KERN_NOTICE "Going down for restart now\n");
+
+	pm8xxx_reset_pwr_off(1);
+
+	if (cmd != NULL) {
+		if (!strncmp(cmd, "bootloader", 10)) {
+			__raw_writel(0x77665500, restart_reason);
+		} else if (!strncmp(cmd, "recovery", 8)) {
+			__raw_writel(0x77665502, restart_reason);
+		} else if (!strncmp(cmd, "oem-", 4)) {
+			unsigned long code;
+			code = simple_strtoul(cmd + 4, NULL, 16) & 0xff;
+			__raw_writel(0x6f656d00 | code, restart_reason);
+		} else {
+			__raw_writel(0x77665501, restart_reason);
+		}
+	}
+
+	__raw_writel(0, msm_tmr0_base + WDT0_EN);
+	if (!(machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())) {
+		mb();
+		__raw_writel(0, PSHOLD_CTL_SU); /* Actually reset the chip */
+		mdelay(5000);
+		pr_notice("PS_HOLD didn't work, falling back to watchdog\n");
+	}
+
+	__raw_writel(1, msm_tmr0_base + WDT0_RST);
+	__raw_writel(5*0x31F3, msm_tmr0_base + WDT0_BARK_TIME);
+	__raw_writel(0x31F3, msm_tmr0_base + WDT0_BITE_TIME);
+	__raw_writel(1, msm_tmr0_base + WDT0_EN);
+
+	mdelay(10000);
+	printk(KERN_ERR "Restarting has failed\n");
+}
+
+static int __init msm_pmic_restart_init(void)
+{
+	int rc;
+
+	if (pmic_reset_irq != 0) {
+		rc = request_any_context_irq(pmic_reset_irq,
+					resout_irq_handler, IRQF_TRIGGER_HIGH,
+					"restart_from_pmic", NULL);
+		if (rc < 0)
+			pr_err("pmic restart irq fail rc = %d\n", rc);
+	} else {
+		pr_warn("no pmic restart interrupt specified\n");
+	}
+
+	return 0;
+}
+
+late_initcall(msm_pmic_restart_init);
+
+static int __init msm_restart_init(void)
+{
+#ifdef CONFIG_MSM_DLOAD_MODE
+	atomic_notifier_chain_register(&panic_notifier_list, &panic_blk);
+	dload_mode_addr = MSM_IMEM_BASE + DLOAD_MODE_ADDR;
+	set_dload_mode(download_mode);
+#endif
+	msm_tmr0_base = msm_timer_get_timer0_base();
+	restart_reason = MSM_IMEM_BASE + RESTART_REASON_ADDR;
+	pm_power_off = msm_power_off;
+
+	return 0;
+}
+early_initcall(msm_restart_init);
diff --git a/arch/arm/mach-msm/rfic-fsm9xxx.c b/arch/arm/mach-msm/rfic-fsm9xxx.c
new file mode 100644
index 0000000..32b654b
--- /dev/null
+++ b/arch/arm/mach-msm/rfic-fsm9xxx.c
@@ -0,0 +1,397 @@
+/* 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
+ * 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/module.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/i2c.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <mach/msm_iomap.h>
+
+#include <linux/fsm_rfic_ftr.h>
+
+/*
+ * FTR8700 RFIC
+ */
+
+#define RFIC_FTR_DEVICE_NUM		2
+#define RFIC_GRFC_REG_NUM		6
+
+#define ANY_BUS				0x0
+#define TX1_BUS				0x0
+#define TX2_BUS				0x1
+#define MISC_BUS			0x2
+#define RX_BUS				0x3
+#define BUS_BITS			0x3
+
+/*
+ * Device private information per device node
+ */
+
+static struct ftr_dev_node_info {
+	void *grfcCtrlAddr;
+	void *grfcMaskAddr;
+	unsigned int busSelect[4];
+	struct i2c_adapter *ssbi_adap;
+
+	/* lock */
+	struct mutex lock;
+} ftr_dev_info[RFIC_FTR_DEVICE_NUM];
+
+/*
+ * Device private information per file
+ */
+
+struct ftr_dev_file_info {
+	int ftrId;
+};
+
+/*
+ * File interface
+ */
+
+static int ftr_find_id(int minor);
+
+static int ftr_open(struct inode *inode, struct file *file)
+{
+	struct ftr_dev_file_info *pdfi;
+
+	/* private data allocation */
+	pdfi = kmalloc(sizeof(*pdfi), GFP_KERNEL);
+	if (pdfi == NULL)
+		return -ENOMEM;
+	file->private_data = pdfi;
+
+	/* FTR ID */
+	pdfi->ftrId = ftr_find_id(MINOR(inode->i_rdev));
+
+	return 0;
+}
+
+static int ftr_release(struct inode *inode, struct file *file)
+{
+	struct ftr_dev_file_info *pdfi;
+
+	pdfi = (struct ftr_dev_file_info *) file->private_data;
+
+	kfree(file->private_data);
+	file->private_data = NULL;
+
+	return 0;
+}
+
+static ssize_t ftr_read(struct file *filp, char __user *buf, size_t count,
+	loff_t *f_pos)
+{
+	return 0;
+}
+
+static ssize_t ftr_write(struct file *file, const char __user *buffer,
+	size_t count, loff_t *ppos)
+{
+	return 0;
+}
+
+static int ftr_ssbi_read(
+	struct ftr_dev_node_info *pdev,
+	unsigned int addr,
+	u8 *buf,
+	size_t len)
+{
+	int ret;
+	struct i2c_msg msg = {
+		.addr = addr,
+		.flags = I2C_M_RD,
+		.buf = buf,
+		.len = len,
+	};
+
+	ret = i2c_transfer(pdev->ssbi_adap, &msg, 1);
+
+	return (ret == 1) ? 0 : ret;
+}
+
+static int ftr_ssbi_write(
+	struct ftr_dev_node_info *pdev,
+	unsigned int addr,
+	u8 *buf,
+	size_t len)
+{
+	int ret;
+	struct i2c_msg msg = {
+		.addr = addr,
+		.flags = 0x0,
+		.buf = (u8 *) buf,
+		.len = len,
+	};
+
+	ret = i2c_transfer(pdev->ssbi_adap, &msg, 1);
+
+	return (ret == 1) ? 0 : ret;
+}
+
+static long ftr_ioctl(struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	unsigned int __user *argp = (unsigned int __user *) arg;
+	struct ftr_dev_file_info *pdfi =
+		(struct ftr_dev_file_info *) file->private_data;
+	struct ftr_dev_node_info *pdev;
+
+	if (pdfi->ftrId < 0 || pdfi->ftrId >= RFIC_FTR_DEVICE_NUM)
+		return -EINVAL;
+
+	pdev = ftr_dev_info + pdfi->ftrId;
+
+	switch (cmd) {
+	case RFIC_IOCTL_READ_REGISTER:
+		{
+			int ret;
+			unsigned int rficAddr;
+			u8 value;
+
+			if (get_user(rficAddr, argp))
+				return -EFAULT;
+
+			mutex_lock(&pdev->lock);
+			mb();
+			/* Need to write twice due to bug in hardware */
+			__raw_writel(
+				pdev->busSelect[RFIC_FTR_GET_BUS(rficAddr)],
+				pdev->grfcCtrlAddr);
+			__raw_writel(
+				pdev->busSelect[RFIC_FTR_GET_BUS(rficAddr)],
+				pdev->grfcCtrlAddr);
+			mb();
+			ret = ftr_ssbi_read(pdev, RFIC_FTR_GET_ADDR(rficAddr),
+				&value, 1);
+			mutex_unlock(&pdev->lock);
+
+			if (ret)
+				return ret;
+
+			if (put_user(value, argp))
+				return -EFAULT;
+		}
+		break;
+
+	case RFIC_IOCTL_WRITE_REGISTER:
+		{
+			int ret;
+			struct rfic_write_register_param param;
+			unsigned int rficAddr;
+			u8 value;
+
+			if (copy_from_user(&param, argp, sizeof param))
+				return -EFAULT;
+			rficAddr = param.rficAddr;
+			value = (u8) param.value;
+
+			mutex_lock(&pdev->lock);
+			mb();
+			/* Need to write twice due to bug in hardware */
+			__raw_writel(
+				pdev->busSelect[RFIC_FTR_GET_BUS(rficAddr)],
+				pdev->grfcCtrlAddr);
+			__raw_writel(
+				pdev->busSelect[RFIC_FTR_GET_BUS(rficAddr)],
+				pdev->grfcCtrlAddr);
+			mb();
+			ret = ftr_ssbi_write(pdev, RFIC_FTR_GET_ADDR(rficAddr),
+				&value, 1);
+			mutex_unlock(&pdev->lock);
+
+			if (ret)
+				return ret;
+		}
+		break;
+
+	case RFIC_IOCTL_WRITE_REGISTER_WITH_MASK:
+		{
+			int ret;
+			struct rfic_write_register_mask_param param;
+			unsigned int rficAddr;
+			u8 value;
+
+			if (copy_from_user(&param, argp, sizeof param))
+				return -EFAULT;
+			rficAddr = param.rficAddr;
+
+			mutex_lock(&pdev->lock);
+			mb();
+			/* Need to write twice due to bug in hardware */
+			__raw_writel(
+				pdev->busSelect[RFIC_FTR_GET_BUS(rficAddr)],
+				pdev->grfcCtrlAddr);
+			__raw_writel(
+				pdev->busSelect[RFIC_FTR_GET_BUS(rficAddr)],
+				pdev->grfcCtrlAddr);
+			mb();
+			ret = ftr_ssbi_read(pdev, RFIC_FTR_GET_ADDR(rficAddr),
+				&value, 1);
+			value &= (u8) ~param.mask;
+			value |= (u8) (param.value & param.mask);
+			ret = ftr_ssbi_write(pdev, RFIC_FTR_GET_ADDR(rficAddr),
+				&value, 1);
+			mutex_unlock(&pdev->lock);
+
+			if (ret)
+				return ret;
+		}
+		break;
+
+	case RFIC_IOCTL_GET_GRFC:
+		{
+			struct rfic_grfc_param param;
+
+			if (copy_from_user(&param, argp, sizeof param))
+				return -EFAULT;
+
+			if (param.grfcId >= RFIC_GRFC_REG_NUM)
+				return -EINVAL;
+
+			param.maskValue = __raw_readl(
+				MSM_GRFC_BASE + 0x18 + param.grfcId * 4);
+			param.ctrlValue = __raw_readl(
+				MSM_GRFC_BASE + 0x00 + param.grfcId * 4);
+
+			if (copy_to_user(argp, &param, sizeof param))
+				return -EFAULT;
+		}
+		break;
+
+	case RFIC_IOCTL_SET_GRFC:
+		{
+			struct rfic_grfc_param param;
+
+			if (copy_from_user(&param, argp, sizeof param))
+				return -EFAULT;
+
+			if (param.grfcId >= RFIC_GRFC_REG_NUM)
+				return -EINVAL;
+
+			__raw_writel(param.maskValue,
+				MSM_GRFC_BASE + 0x18 + param.grfcId * 4);
+			/* Need to write twice due to bug in hardware */
+			__raw_writel(param.ctrlValue,
+				MSM_GRFC_BASE + 0x00 + param.grfcId * 4);
+			__raw_writel(param.ctrlValue,
+				MSM_GRFC_BASE + 0x00 + param.grfcId * 4);
+			mb();
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct file_operations ftr_fops = {
+	.owner = THIS_MODULE,
+	.open = ftr_open,
+	.release = ftr_release,
+	.read = ftr_read,
+	.write = ftr_write,
+	.unlocked_ioctl = ftr_ioctl,
+};
+
+/*
+ * Driver initialization & cleanup
+ */
+
+struct miscdevice ftr_misc_dev[RFIC_FTR_DEVICE_NUM] = {
+	{
+		.minor = MISC_DYNAMIC_MINOR,
+		.name = RFIC_FTR_DEVICE_NAME "0",
+		.fops = &ftr_fops,
+	},
+	{
+		.minor = MISC_DYNAMIC_MINOR,
+		.name = RFIC_FTR_DEVICE_NAME "1",
+		.fops = &ftr_fops,
+	},
+};
+
+int ftr_find_id(int minor)
+{
+	int i;
+
+	for (i = 0; i < RFIC_FTR_DEVICE_NUM; ++i)
+		if (ftr_misc_dev[i].minor == minor)
+			break;
+
+	return i;
+}
+
+static int __init ftr_init(void)
+{
+	int i, ret;
+	struct ftr_dev_node_info *pdev;
+
+	for (i = 0; i < RFIC_FTR_DEVICE_NUM; ++i) {
+		pdev = ftr_dev_info + i;
+
+		if (i == 0) {
+			pdev->grfcCtrlAddr = MSM_GRFC_BASE + 0x00;
+			pdev->grfcMaskAddr = MSM_GRFC_BASE + 0x18;
+			__raw_writel(0x300000, pdev->grfcMaskAddr);
+			pdev->busSelect[TX1_BUS] = 0x000000;
+			pdev->busSelect[TX2_BUS] = 0x100000;
+			pdev->busSelect[MISC_BUS] = 0x200000;
+			pdev->busSelect[RX_BUS] = 0x300000;
+			pdev->ssbi_adap = i2c_get_adapter(1);
+		} else {
+			pdev->grfcCtrlAddr = MSM_GRFC_BASE + 0x04;
+			pdev->grfcMaskAddr = MSM_GRFC_BASE + 0x1c;
+			__raw_writel(0x480000, pdev->grfcMaskAddr);
+			pdev->busSelect[TX1_BUS] = 0x000000;
+			pdev->busSelect[TX2_BUS] = 0x400000;
+			pdev->busSelect[MISC_BUS] = 0x080000;
+			pdev->busSelect[RX_BUS] = 0x480000;
+			pdev->ssbi_adap = i2c_get_adapter(2);
+		}
+
+		mutex_init(&pdev->lock);
+		ret = misc_register(ftr_misc_dev + i);
+
+		if (ret < 0) {
+			while (--i >= 0)
+				misc_deregister(ftr_misc_dev + i);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static void __exit ftr_exit(void)
+{
+	int i;
+
+	for (i = 0; i < RFIC_FTR_DEVICE_NUM; ++i)
+		misc_deregister(ftr_misc_dev + i);
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Rohit Vaswani <rvaswani@codeaurora.org>");
+MODULE_DESCRIPTION("Qualcomm FSM RFIC driver");
+MODULE_VERSION("1.0");
+
+module_init(ftr_init);
+module_exit(ftr_exit);
diff --git a/arch/arm/mach-msm/rmt_storage_client.c b/arch/arm/mach-msm/rmt_storage_client.c
new file mode 100644
index 0000000..4bec55d
--- /dev/null
+++ b/arch/arm/mach-msm/rmt_storage_client.c
@@ -0,0 +1,1746 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/miscdevice.h>
+#include <linux/wait.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/err.h>
+#include <linux/sched.h>
+#include <linux/wakelock.h>
+#include <linux/rmt_storage_client.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <mach/msm_rpcrouter.h>
+#ifdef CONFIG_MSM_SDIO_SMEM
+#include <mach/sdio_smem.h>
+#endif
+#include "smd_private.h"
+
+enum {
+	RMT_STORAGE_EVNT_OPEN = 0,
+	RMT_STORAGE_EVNT_CLOSE,
+	RMT_STORAGE_EVNT_WRITE_BLOCK,
+	RMT_STORAGE_EVNT_GET_DEV_ERROR,
+	RMT_STORAGE_EVNT_WRITE_IOVEC,
+	RMT_STORAGE_EVNT_SEND_USER_DATA,
+	RMT_STORAGE_EVNT_READ_IOVEC,
+	RMT_STORAGE_EVNT_ALLOC_RMT_BUF,
+} rmt_storage_event;
+
+struct shared_ramfs_entry {
+	uint32_t client_id;	/* Client id to uniquely identify a client */
+	uint32_t base_addr;	/* Base address of shared RAMFS memory */
+	uint32_t size;		/* Size of the shared RAMFS memory */
+	uint32_t client_sts;	/* This will be initialized to 1 when
+				   remote storage RPC client is ready
+				   to process requests */
+};
+struct shared_ramfs_table {
+	uint32_t magic_id;	/* Identify RAMFS details in SMEM */
+	uint32_t version;	/* Version of shared_ramfs_table */
+	uint32_t entries;	/* Total number of valid entries   */
+	/* List all entries */
+	struct shared_ramfs_entry ramfs_entry[MAX_RAMFS_TBL_ENTRIES];
+};
+
+struct rmt_storage_client_info {
+	unsigned long cids;
+	struct list_head shrd_mem_list; /* List of shared memory entries */
+	int open_excl;
+	atomic_t total_events;
+	wait_queue_head_t event_q;
+	struct list_head event_list;
+	struct list_head client_list;	/* List of remote storage clients */
+	/* Lock to protect lists */
+	spinlock_t lock;
+	/* Wakelock to be acquired when processing requests from modem */
+	struct wake_lock wlock;
+	atomic_t wcount;
+	struct workqueue_struct *workq;
+};
+
+struct rmt_storage_kevent {
+	struct list_head list;
+	struct rmt_storage_event event;
+};
+
+/* Remote storage server on modem */
+struct rmt_storage_srv {
+	uint32_t prog;
+	int sync_token;
+	struct platform_driver plat_drv;
+	struct msm_rpc_client *rpc_client;
+	struct delayed_work restart_work;
+};
+
+/* Remote storage client on modem */
+struct rmt_storage_client {
+	uint32_t handle;
+	uint32_t sid;			/* Storage ID */
+	char path[MAX_PATH_NAME];
+	struct rmt_storage_srv *srv;
+	struct list_head list;
+};
+
+struct rmt_shrd_mem {
+	struct list_head list;
+	struct rmt_shrd_mem_param param;
+	struct shared_ramfs_entry *smem_info;
+	struct rmt_storage_srv *srv;
+};
+
+static struct rmt_storage_srv *rmt_storage_get_srv(uint32_t prog);
+static uint32_t rmt_storage_get_sid(const char *path);
+#ifdef CONFIG_MSM_SDIO_SMEM
+static void rmt_storage_sdio_smem_work(struct work_struct *work);
+#endif
+
+static struct rmt_storage_client_info *rmc;
+
+#ifdef CONFIG_MSM_SDIO_SMEM
+DECLARE_DELAYED_WORK(sdio_smem_work, rmt_storage_sdio_smem_work);
+#endif
+
+#ifdef CONFIG_MSM_SDIO_SMEM
+#define MDM_LOCAL_BUF_SZ	0xC0000
+static struct sdio_smem_client *sdio_smem;
+#endif
+
+#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
+struct rmt_storage_op_stats {
+	unsigned long count;
+	ktime_t start;
+	ktime_t min;
+	ktime_t max;
+	ktime_t total;
+};
+struct rmt_storage_stats {
+       char path[MAX_PATH_NAME];
+       struct rmt_storage_op_stats rd_stats;
+       struct rmt_storage_op_stats wr_stats;
+};
+static struct rmt_storage_stats client_stats[MAX_NUM_CLIENTS];
+static struct dentry *stats_dentry;
+#endif
+
+#define MSM_RMT_STORAGE_APIPROG	0x300000A7
+#define MDM_RMT_STORAGE_APIPROG	0x300100A7
+
+#define RMT_STORAGE_OP_FINISH_PROC              2
+#define RMT_STORAGE_REGISTER_OPEN_PROC          3
+#define RMT_STORAGE_REGISTER_WRITE_IOVEC_PROC   4
+#define RMT_STORAGE_REGISTER_CB_PROC            5
+#define RMT_STORAGE_UN_REGISTER_CB_PROC         6
+#define RMT_STORAGE_FORCE_SYNC_PROC             7
+#define RMT_STORAGE_GET_SYNC_STATUS_PROC        8
+#define RMT_STORAGE_REGISTER_READ_IOVEC_PROC    9
+#define RMT_STORAGE_REGISTER_ALLOC_RMT_BUF_PROC 10
+
+#define RMT_STORAGE_OPEN_CB_TYPE_PROC           1
+#define RMT_STORAGE_WRITE_IOVEC_CB_TYPE_PROC    2
+#define RMT_STORAGE_EVENT_CB_TYPE_PROC          3
+#define RMT_STORAGE_READ_IOVEC_CB_TYPE_PROC     4
+#define RMT_STORAGE_ALLOC_RMT_BUF_CB_TYPE_PROC  5
+
+#define RAMFS_INFO_MAGICNUMBER		0x654D4D43
+#define RAMFS_INFO_VERSION		0x00000001
+#define RAMFS_DEFAULT			0xFFFFFFFF
+
+/* MSM EFS*/
+#define RAMFS_MODEMSTORAGE_ID		0x4D454653
+#define RAMFS_SHARED_EFS_RAM_BASE	0x46100000
+#define RAMFS_SHARED_EFS_RAM_SIZE	(3 * 1024 * 1024)
+
+/* MDM EFS*/
+#define RAMFS_MDM_STORAGE_ID		0x4D4583A1
+/* SSD */
+#define RAMFS_SSD_STORAGE_ID		0x00535344
+#define RAMFS_SHARED_SSD_RAM_BASE	0x42E00000
+#define RAMFS_SHARED_SSD_RAM_SIZE	0x2000
+
+static struct rmt_storage_client *rmt_storage_get_client(uint32_t handle)
+{
+	struct rmt_storage_client *rs_client;
+	list_for_each_entry(rs_client, &rmc->client_list, list)
+		if (rs_client->handle == handle)
+			return rs_client;
+	return NULL;
+}
+
+static struct rmt_storage_client *
+rmt_storage_get_client_by_path(const char *path)
+{
+	struct rmt_storage_client *rs_client;
+	list_for_each_entry(rs_client, &rmc->client_list, list)
+		if (!strncmp(path, rs_client->path, MAX_PATH_NAME))
+			return rs_client;
+	return NULL;
+}
+
+static struct rmt_shrd_mem_param *rmt_storage_get_shrd_mem(uint32_t sid)
+{
+	struct rmt_shrd_mem *shrd_mem;
+	struct rmt_shrd_mem_param *shrd_mem_param = NULL;
+
+	spin_lock(&rmc->lock);
+	list_for_each_entry(shrd_mem, &rmc->shrd_mem_list, list)
+		if (shrd_mem->param.sid == sid)
+			shrd_mem_param = &shrd_mem->param;
+	spin_unlock(&rmc->lock);
+
+	return shrd_mem_param;
+}
+
+static int rmt_storage_add_shrd_mem(uint32_t sid, uint32_t start,
+				    uint32_t size, void *base,
+				    struct shared_ramfs_entry *smem_info,
+				    struct rmt_storage_srv *srv)
+{
+	struct rmt_shrd_mem *shrd_mem;
+
+	shrd_mem = kzalloc(sizeof(struct rmt_shrd_mem), GFP_KERNEL);
+	if (!shrd_mem)
+		return -ENOMEM;
+	shrd_mem->param.sid = sid;
+	shrd_mem->param.start = start;
+	shrd_mem->param.size = size;
+	shrd_mem->param.base = base;
+	shrd_mem->smem_info = smem_info;
+	shrd_mem->srv = srv;
+
+	spin_lock(&rmc->lock);
+	list_add(&shrd_mem->list, &rmc->shrd_mem_list);
+	spin_unlock(&rmc->lock);
+	return 0;
+}
+
+static struct msm_rpc_client *rmt_storage_get_rpc_client(uint32_t handle)
+{
+	struct rmt_storage_client *rs_client;
+
+	rs_client = rmt_storage_get_client(handle);
+	if (!rs_client)
+		return NULL;
+	return rs_client->srv->rpc_client;
+}
+
+static int rmt_storage_validate_iovec(uint32_t handle,
+				      struct rmt_storage_iovec_desc *xfer)
+{
+	struct rmt_storage_client *rs_client;
+	struct rmt_shrd_mem_param *shrd_mem;
+
+	rs_client = rmt_storage_get_client(handle);
+	if (!rs_client)
+		return -EINVAL;
+	shrd_mem = rmt_storage_get_shrd_mem(rs_client->sid);
+	if (!shrd_mem)
+		return -EINVAL;
+
+	if ((xfer->data_phy_addr < shrd_mem->start) ||
+	    ((xfer->data_phy_addr + RAMFS_BLOCK_SIZE * xfer->num_sector) >
+	     (shrd_mem->start + shrd_mem->size)))
+		return -EINVAL;
+	return 0;
+}
+
+static int rmt_storage_send_sts_arg(struct msm_rpc_client *client,
+				struct msm_rpc_xdr *xdr, void *data)
+{
+	struct rmt_storage_send_sts *args = data;
+
+	xdr_send_uint32(xdr, &args->handle);
+	xdr_send_uint32(xdr, &args->err_code);
+	xdr_send_uint32(xdr, &args->data);
+	return 0;
+}
+
+static void put_event(struct rmt_storage_client_info *rmc,
+			struct rmt_storage_kevent *kevent)
+{
+	spin_lock(&rmc->lock);
+	list_add_tail(&kevent->list, &rmc->event_list);
+	spin_unlock(&rmc->lock);
+}
+
+static struct rmt_storage_kevent *get_event(struct rmt_storage_client_info *rmc)
+{
+	struct rmt_storage_kevent *kevent = NULL;
+
+	spin_lock(&rmc->lock);
+	if (!list_empty(&rmc->event_list)) {
+		kevent = list_first_entry(&rmc->event_list,
+			struct rmt_storage_kevent, list);
+		list_del(&kevent->list);
+	}
+	spin_unlock(&rmc->lock);
+	return kevent;
+}
+
+static int rmt_storage_event_open_cb(struct rmt_storage_event *event_args,
+		struct msm_rpc_xdr *xdr)
+{
+	uint32_t cid, len, event_type;
+	char *path;
+	int ret;
+	struct rmt_storage_srv *srv;
+	struct rmt_storage_client *rs_client = NULL;
+#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
+	struct rmt_storage_stats *stats;
+#endif
+
+	srv = rmt_storage_get_srv(event_args->usr_data);
+	if (!srv)
+		return -EINVAL;
+
+	xdr_recv_uint32(xdr, &event_type);
+	if (event_type != RMT_STORAGE_EVNT_OPEN)
+		return -1;
+
+	pr_info("%s: open callback received\n", __func__);
+
+	ret = xdr_recv_bytes(xdr, (void **)&path, &len);
+	if (ret || !path) {
+		pr_err("%s: Invalid path\n", __func__);
+		if (!ret)
+			ret = -1;
+		goto free_rs_client;
+	}
+
+	rs_client = rmt_storage_get_client_by_path(path);
+	if (rs_client) {
+		pr_debug("%s: Handle %d found for %s\n",
+			__func__, rs_client->handle, path);
+		event_args->id = RMT_STORAGE_NOOP;
+		cid = rs_client->handle;
+		goto end_open_cb;
+	}
+
+	rs_client = kzalloc(sizeof(struct rmt_storage_client), GFP_KERNEL);
+	if (!rs_client) {
+		pr_err("%s: Error allocating rmt storage client\n", __func__);
+		ret = -ENOMEM;
+		goto free_path;
+	}
+
+	memcpy(event_args->path, path, len);
+	rs_client->sid = rmt_storage_get_sid(event_args->path);
+	if (!rs_client->sid) {
+		pr_err("%s: No storage id found for %s\n", __func__,
+		       event_args->path);
+		ret = -EINVAL;
+		goto free_path;
+	}
+	strncpy(rs_client->path, event_args->path, MAX_PATH_NAME);
+
+	cid = find_first_zero_bit(&rmc->cids, sizeof(rmc->cids) * 8);
+	if (cid > MAX_NUM_CLIENTS) {
+		pr_err("%s: Max clients are reached\n", __func__);
+		cid = 0;
+		return cid;
+	}
+	__set_bit(cid, &rmc->cids);
+	pr_info("open partition %s handle=%d\n", event_args->path, cid);
+
+#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
+	stats = &client_stats[cid - 1];
+	memcpy(stats->path, event_args->path, len);
+	memset(stats->rd_stats, 0, sizeof(struct rmt_storage_op_stats));
+	memset(stats->wr_stats, 0, sizeof(struct rmt_storage_op_stats));
+	stats->rd_stats.min.tv64 = KTIME_MAX;
+	stats->wr_stats.min.tv64 = KTIME_MAX;
+#endif
+	event_args->id = RMT_STORAGE_OPEN;
+	event_args->sid = rs_client->sid;
+	event_args->handle = cid;
+
+	rs_client->handle = event_args->handle;
+	rs_client->srv = srv;
+	INIT_LIST_HEAD(&rs_client->list);
+	spin_lock(&rmc->lock);
+	list_add_tail(&rs_client->list, &rmc->client_list);
+	spin_unlock(&rmc->lock);
+
+end_open_cb:
+	kfree(path);
+	return cid;
+
+free_path:
+	kfree(path);
+free_rs_client:
+	kfree(rs_client);
+	return ret;
+}
+
+struct rmt_storage_close_args {
+	uint32_t handle;
+};
+
+struct rmt_storage_rw_block_args {
+	uint32_t handle;
+	uint32_t data_phy_addr;
+	uint32_t sector_addr;
+	uint32_t num_sector;
+};
+
+struct rmt_storage_get_err_args {
+	uint32_t handle;
+};
+
+struct rmt_storage_user_data_args {
+	uint32_t handle;
+	uint32_t data;
+};
+
+struct rmt_storage_event_params {
+	uint32_t type;
+	union {
+		struct rmt_storage_close_args close;
+		struct rmt_storage_rw_block_args block;
+		struct rmt_storage_get_err_args get_err;
+		struct rmt_storage_user_data_args user_data;
+	} params;
+};
+
+static int rmt_storage_parse_params(struct msm_rpc_xdr *xdr,
+		struct rmt_storage_event_params *event)
+{
+	xdr_recv_uint32(xdr, &event->type);
+
+	switch (event->type) {
+	case RMT_STORAGE_EVNT_CLOSE: {
+		struct rmt_storage_close_args *args;
+		args = &event->params.close;
+
+		xdr_recv_uint32(xdr, &args->handle);
+		break;
+	}
+
+	case RMT_STORAGE_EVNT_WRITE_BLOCK: {
+		struct rmt_storage_rw_block_args *args;
+		args = &event->params.block;
+
+		xdr_recv_uint32(xdr, &args->handle);
+		xdr_recv_uint32(xdr, &args->data_phy_addr);
+		xdr_recv_uint32(xdr, &args->sector_addr);
+		xdr_recv_uint32(xdr, &args->num_sector);
+		break;
+	}
+
+	case RMT_STORAGE_EVNT_GET_DEV_ERROR: {
+		struct rmt_storage_get_err_args *args;
+		args = &event->params.get_err;
+
+		xdr_recv_uint32(xdr, &args->handle);
+		break;
+	}
+
+	case RMT_STORAGE_EVNT_SEND_USER_DATA: {
+		struct rmt_storage_user_data_args *args;
+		args = &event->params.user_data;
+
+		xdr_recv_uint32(xdr, &args->handle);
+		xdr_recv_uint32(xdr, &args->data);
+		break;
+	}
+
+	default:
+		pr_err("%s: unknown event %d\n", __func__, event->type);
+		return -1;
+	}
+	return 0;
+}
+
+static int rmt_storage_event_close_cb(struct rmt_storage_event *event_args,
+		struct msm_rpc_xdr *xdr)
+{
+	struct rmt_storage_event_params *event;
+	struct rmt_storage_close_args *close;
+	struct rmt_storage_client *rs_client;
+	uint32_t event_type;
+	int ret;
+
+	xdr_recv_uint32(xdr, &event_type);
+	if (event_type != RMT_STORAGE_EVNT_CLOSE)
+		return -1;
+
+	pr_debug("%s: close callback received\n", __func__);
+	ret = xdr_recv_pointer(xdr, (void **)&event,
+			sizeof(struct rmt_storage_event_params),
+			rmt_storage_parse_params);
+
+	if (ret || !event)
+		return -1;
+
+	close = &event->params.close;
+	event_args->handle = close->handle;
+	event_args->id = RMT_STORAGE_CLOSE;
+	__clear_bit(event_args->handle, &rmc->cids);
+	rs_client = rmt_storage_get_client(event_args->handle);
+	if (rs_client) {
+		list_del(&rs_client->list);
+		kfree(rs_client);
+	}
+	kfree(event);
+	return RMT_STORAGE_NO_ERROR;
+}
+
+static int rmt_storage_event_write_block_cb(
+		struct rmt_storage_event *event_args,
+		struct msm_rpc_xdr *xdr)
+{
+	struct rmt_storage_event_params *event;
+	struct rmt_storage_rw_block_args *write_block;
+	struct rmt_storage_iovec_desc *xfer;
+	uint32_t event_type;
+	int ret;
+
+	xdr_recv_uint32(xdr, &event_type);
+	if (event_type != RMT_STORAGE_EVNT_WRITE_BLOCK)
+		return -1;
+
+	pr_debug("%s: write block callback received\n", __func__);
+	ret = xdr_recv_pointer(xdr, (void **)&event,
+			sizeof(struct rmt_storage_event_params),
+			rmt_storage_parse_params);
+
+	if (ret || !event)
+		return -1;
+
+	write_block = &event->params.block;
+	event_args->handle = write_block->handle;
+	xfer = &event_args->xfer_desc[0];
+	xfer->sector_addr = write_block->sector_addr;
+	xfer->data_phy_addr = write_block->data_phy_addr;
+	xfer->num_sector = write_block->num_sector;
+
+	ret = rmt_storage_validate_iovec(event_args->handle, xfer);
+	if (ret)
+		return -1;
+	event_args->xfer_cnt = 1;
+	event_args->id = RMT_STORAGE_WRITE;
+
+	if (atomic_inc_return(&rmc->wcount) == 1)
+		wake_lock(&rmc->wlock);
+
+	pr_debug("sec_addr = %u, data_addr = %x, num_sec = %d\n\n",
+		xfer->sector_addr, xfer->data_phy_addr,
+		xfer->num_sector);
+
+	kfree(event);
+	return RMT_STORAGE_NO_ERROR;
+}
+
+static int rmt_storage_event_get_err_cb(struct rmt_storage_event *event_args,
+		struct msm_rpc_xdr *xdr)
+{
+	struct rmt_storage_event_params *event;
+	struct rmt_storage_get_err_args *get_err;
+	uint32_t event_type;
+	int ret;
+
+	xdr_recv_uint32(xdr, &event_type);
+	if (event_type != RMT_STORAGE_EVNT_GET_DEV_ERROR)
+		return -1;
+
+	pr_debug("%s: get err callback received\n", __func__);
+	ret = xdr_recv_pointer(xdr, (void **)&event,
+			sizeof(struct rmt_storage_event_params),
+			rmt_storage_parse_params);
+
+	if (ret || !event)
+		return -1;
+
+	get_err = &event->params.get_err;
+	event_args->handle = get_err->handle;
+	kfree(event);
+	/* Not implemented */
+	return -1;
+
+}
+
+static int rmt_storage_event_user_data_cb(struct rmt_storage_event *event_args,
+		struct msm_rpc_xdr *xdr)
+{
+	struct rmt_storage_event_params *event;
+	struct rmt_storage_user_data_args *user_data;
+	uint32_t event_type;
+	int ret;
+
+	xdr_recv_uint32(xdr, &event_type);
+	if (event_type != RMT_STORAGE_EVNT_SEND_USER_DATA)
+		return -1;
+
+	pr_info("%s: send user data callback received\n", __func__);
+	ret = xdr_recv_pointer(xdr, (void **)&event,
+			sizeof(struct rmt_storage_event_params),
+			rmt_storage_parse_params);
+
+	if (ret || !event)
+		return -1;
+
+	user_data = &event->params.user_data;
+	event_args->handle = user_data->handle;
+	event_args->usr_data = user_data->data;
+	event_args->id = RMT_STORAGE_SEND_USER_DATA;
+
+	kfree(event);
+	return RMT_STORAGE_NO_ERROR;
+}
+
+static int rmt_storage_event_write_iovec_cb(
+		struct rmt_storage_event *event_args,
+		struct msm_rpc_xdr *xdr)
+{
+	struct rmt_storage_iovec_desc *xfer;
+	uint32_t i, ent, event_type;
+#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
+	struct rmt_storage_stats *stats;
+#endif
+
+	xdr_recv_uint32(xdr, &event_type);
+	if (event_type != RMT_STORAGE_EVNT_WRITE_IOVEC)
+		return -EINVAL;
+
+	pr_info("%s: write iovec callback received\n", __func__);
+	xdr_recv_uint32(xdr, &event_args->handle);
+	xdr_recv_uint32(xdr, &ent);
+	pr_debug("handle = %d\n", event_args->handle);
+
+#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
+	stats = &client_stats[event_args->handle - 1];
+	stats->wr_stats.start = ktime_get();
+#endif
+	for (i = 0; i < ent; i++) {
+		xfer = &event_args->xfer_desc[i];
+		xdr_recv_uint32(xdr, &xfer->sector_addr);
+		xdr_recv_uint32(xdr, &xfer->data_phy_addr);
+		xdr_recv_uint32(xdr, &xfer->num_sector);
+
+		if (rmt_storage_validate_iovec(event_args->handle, xfer))
+			return -EINVAL;
+
+		pr_debug("sec_addr = %u, data_addr = %x, num_sec = %d\n",
+			xfer->sector_addr, xfer->data_phy_addr,
+			xfer->num_sector);
+	}
+	xdr_recv_uint32(xdr, &event_args->xfer_cnt);
+	event_args->id = RMT_STORAGE_WRITE;
+	if (atomic_inc_return(&rmc->wcount) == 1)
+		wake_lock(&rmc->wlock);
+
+	pr_debug("iovec transfer count = %d\n\n", event_args->xfer_cnt);
+	return RMT_STORAGE_NO_ERROR;
+}
+
+static int rmt_storage_event_read_iovec_cb(
+		struct rmt_storage_event *event_args,
+		struct msm_rpc_xdr *xdr)
+{
+	struct rmt_storage_iovec_desc *xfer;
+	uint32_t i, ent, event_type;
+#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
+	struct rmt_storage_stats *stats;
+#endif
+
+	xdr_recv_uint32(xdr, &event_type);
+	if (event_type != RMT_STORAGE_EVNT_READ_IOVEC)
+		return -EINVAL;
+
+	pr_info("%s: read iovec callback received\n", __func__);
+	xdr_recv_uint32(xdr, &event_args->handle);
+	xdr_recv_uint32(xdr, &ent);
+	pr_debug("handle = %d\n", event_args->handle);
+
+#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
+	stats = &client_stats[event_args->handle - 1];
+	stats->rd_stats.start = ktime_get();
+#endif
+	for (i = 0; i < ent; i++) {
+		xfer = &event_args->xfer_desc[i];
+		xdr_recv_uint32(xdr, &xfer->sector_addr);
+		xdr_recv_uint32(xdr, &xfer->data_phy_addr);
+		xdr_recv_uint32(xdr, &xfer->num_sector);
+
+		if (rmt_storage_validate_iovec(event_args->handle, xfer))
+			return -EINVAL;
+
+		pr_debug("sec_addr = %u, data_addr = %x, num_sec = %d\n",
+			xfer->sector_addr, xfer->data_phy_addr,
+			xfer->num_sector);
+	}
+	xdr_recv_uint32(xdr, &event_args->xfer_cnt);
+	event_args->id = RMT_STORAGE_READ;
+	if (atomic_inc_return(&rmc->wcount) == 1)
+		wake_lock(&rmc->wlock);
+
+	pr_debug("iovec transfer count = %d\n\n", event_args->xfer_cnt);
+	return RMT_STORAGE_NO_ERROR;
+}
+
+#ifdef CONFIG_MSM_SDIO_SMEM
+static int sdio_smem_cb(int event)
+{
+	pr_debug("%s: Received event %d\n", __func__, event);
+
+	switch (event) {
+	case SDIO_SMEM_EVENT_READ_DONE:
+		pr_debug("Read done\n");
+		break;
+	case SDIO_SMEM_EVENT_READ_ERR:
+		pr_err("Read overflow\n");
+		return -EIO;
+	default:
+		pr_err("Unhandled event\n");
+	}
+	return 0;
+}
+
+static int rmt_storage_sdio_smem_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct rmt_shrd_mem_param *shrd_mem;
+
+	sdio_smem = container_of(pdev, struct sdio_smem_client, plat_dev);
+
+	/* SDIO SMEM is supported only for MDM */
+	shrd_mem = rmt_storage_get_shrd_mem(RAMFS_MDM_STORAGE_ID);
+	if (!shrd_mem) {
+		pr_err("%s: No shared mem entry for sid=0x%08x\n",
+		       __func__, (uint32_t)RAMFS_MDM_STORAGE_ID);
+		return -ENOMEM;
+	}
+	sdio_smem->buf = __va(shrd_mem->start);
+	sdio_smem->size = shrd_mem->size;
+	sdio_smem->cb_func = sdio_smem_cb;
+	ret = sdio_smem_register_client();
+	if (ret)
+		pr_info("%s: Error (%d) registering sdio_smem client\n",
+			__func__, ret);
+	return ret;
+}
+
+static int rmt_storage_sdio_smem_remove(struct platform_device *pdev)
+{
+	sdio_smem_unregister_client();
+	queue_delayed_work(rmc->workq, &sdio_smem_work, 0);
+	return 0;
+}
+
+static int sdio_smem_drv_registered;
+static struct platform_driver sdio_smem_drv = {
+	.probe		= rmt_storage_sdio_smem_probe,
+	.remove		= rmt_storage_sdio_smem_remove,
+	.driver		= {
+		.name	= "SDIO_SMEM_CLIENT",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static void rmt_storage_sdio_smem_work(struct work_struct *work)
+{
+	platform_driver_unregister(&sdio_smem_drv);
+	sdio_smem_drv_registered = 0;
+}
+#endif
+
+static int rmt_storage_event_alloc_rmt_buf_cb(
+		struct rmt_storage_event *event_args,
+		struct msm_rpc_xdr *xdr)
+{
+	struct rmt_storage_client *rs_client;
+	struct rmt_shrd_mem_param *shrd_mem;
+	uint32_t event_type, handle, size;
+#ifdef CONFIG_MSM_SDIO_SMEM
+	int ret;
+#endif
+	xdr_recv_uint32(xdr, &event_type);
+	if (event_type != RMT_STORAGE_EVNT_ALLOC_RMT_BUF)
+		return -EINVAL;
+
+	pr_info("%s: Alloc rmt buf callback received\n", __func__);
+	xdr_recv_uint32(xdr, &handle);
+	xdr_recv_uint32(xdr, &size);
+
+	pr_debug("%s: handle=0x%x size=0x%x\n", __func__, handle, size);
+
+	rs_client = rmt_storage_get_client(handle);
+	if (!rs_client) {
+		pr_err("%s: Unable to find client for handle=%d\n",
+		       __func__, handle);
+		return -EINVAL;
+	}
+
+	rs_client->sid = rmt_storage_get_sid(rs_client->path);
+	if (!rs_client->sid) {
+		pr_err("%s: No storage id found for %s\n",
+		       __func__, rs_client->path);
+		return -EINVAL;
+	}
+
+	shrd_mem = rmt_storage_get_shrd_mem(rs_client->sid);
+	if (!shrd_mem) {
+		pr_err("%s: No shared memory entry found\n",
+		       __func__);
+		return -ENOMEM;
+	}
+	if (shrd_mem->size < size) {
+		pr_err("%s: Size mismatch for handle=%d\n",
+		       __func__, rs_client->handle);
+		return -EINVAL;
+	}
+	pr_debug("%s: %d bytes at phys=0x%x for handle=%d found\n",
+		__func__, size, shrd_mem->start, rs_client->handle);
+
+#ifdef CONFIG_MSM_SDIO_SMEM
+	if (rs_client->srv->prog == MDM_RMT_STORAGE_APIPROG) {
+		if (!sdio_smem_drv_registered) {
+			ret = platform_driver_register(&sdio_smem_drv);
+			if (!ret)
+				sdio_smem_drv_registered = 1;
+			else
+				pr_err("%s: Cant register sdio smem client\n",
+				       __func__);
+		}
+	}
+#endif
+	event_args->id = RMT_STORAGE_NOOP;
+	return (int)shrd_mem->start;
+}
+
+static int handle_rmt_storage_call(struct msm_rpc_client *client,
+				struct rpc_request_hdr *req,
+				struct msm_rpc_xdr *xdr)
+{
+	int rc;
+	uint32_t result = RMT_STORAGE_NO_ERROR;
+	uint32_t rpc_status = RPC_ACCEPTSTAT_SUCCESS;
+	struct rmt_storage_event *event_args;
+	struct rmt_storage_kevent *kevent;
+
+	kevent = kzalloc(sizeof(struct rmt_storage_kevent), GFP_KERNEL);
+	if (!kevent) {
+		rpc_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
+		goto out;
+	}
+	event_args = &kevent->event;
+
+	switch (req->procedure) {
+	case RMT_STORAGE_OPEN_CB_TYPE_PROC:
+		/* client created in cb needs a ref. to its server */
+		event_args->usr_data = client->prog;
+		/* fall through */
+
+	case RMT_STORAGE_WRITE_IOVEC_CB_TYPE_PROC:
+		/* fall through */
+
+	case RMT_STORAGE_READ_IOVEC_CB_TYPE_PROC:
+		/* fall through */
+
+	case RMT_STORAGE_ALLOC_RMT_BUF_CB_TYPE_PROC:
+		/* fall through */
+
+	case RMT_STORAGE_EVENT_CB_TYPE_PROC: {
+		uint32_t cb_id;
+		int (*cb_func)(struct rmt_storage_event *event_args,
+				struct msm_rpc_xdr *xdr);
+
+		xdr_recv_uint32(xdr, &cb_id);
+		cb_func = msm_rpc_get_cb_func(client, cb_id);
+
+		if (!cb_func) {
+			rpc_status = RPC_ACCEPTSTAT_GARBAGE_ARGS;
+			kfree(kevent);
+			goto out;
+		}
+
+		rc = cb_func(event_args, xdr);
+		if (IS_ERR_VALUE(rc)) {
+			pr_err("%s: Invalid parameters received\n", __func__);
+			if (req->procedure == RMT_STORAGE_OPEN_CB_TYPE_PROC)
+				result = 0; /* bad handle to signify err */
+			else
+				result = RMT_STORAGE_ERROR_PARAM;
+			kfree(kevent);
+			goto out;
+		}
+		result = (uint32_t) rc;
+		break;
+	}
+
+	default:
+		kfree(kevent);
+		pr_err("%s: unknown procedure %d\n", __func__, req->procedure);
+		rpc_status = RPC_ACCEPTSTAT_PROC_UNAVAIL;
+		goto out;
+	}
+
+	if (kevent->event.id != RMT_STORAGE_NOOP) {
+		put_event(rmc, kevent);
+		atomic_inc(&rmc->total_events);
+		wake_up(&rmc->event_q);
+	} else
+		kfree(kevent);
+
+out:
+	pr_debug("%s: Sending result=0x%x\n", __func__, result);
+	xdr_start_accepted_reply(xdr, rpc_status);
+	xdr_send_uint32(xdr, &result);
+	rc = xdr_send_msg(xdr);
+	if (rc)
+		pr_err("%s: send accepted reply failed: %d\n", __func__, rc);
+
+	return rc;
+}
+
+static int rmt_storage_open(struct inode *ip, struct file *fp)
+{
+	int ret = 0;
+
+	spin_lock(&rmc->lock);
+	if (!rmc->open_excl)
+		rmc->open_excl = 1;
+	else
+		ret = -EBUSY;
+	spin_unlock(&rmc->lock);
+
+	return ret;
+}
+
+static int rmt_storage_release(struct inode *ip, struct file *fp)
+{
+	spin_lock(&rmc->lock);
+	rmc->open_excl = 0;
+	spin_unlock(&rmc->lock);
+
+	return 0;
+}
+
+static long rmt_storage_ioctl(struct file *fp, unsigned int cmd,
+			    unsigned long arg)
+{
+	int ret = 0;
+	struct rmt_storage_kevent *kevent;
+	struct rmt_storage_send_sts status;
+	static struct msm_rpc_client *rpc_client;
+	struct rmt_shrd_mem_param usr_shrd_mem, *shrd_mem;
+
+#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
+	struct rmt_storage_stats *stats;
+	struct rmt_storage_op_stats *op_stats;
+	ktime_t curr_stat;
+#endif
+
+	switch (cmd) {
+
+	case RMT_STORAGE_SHRD_MEM_PARAM:
+		pr_debug("%s: get shared memory parameters ioctl\n", __func__);
+		if (copy_from_user(&usr_shrd_mem, (void __user *)arg,
+				sizeof(struct rmt_shrd_mem_param))) {
+			pr_err("%s: copy from user failed\n\n", __func__);
+			ret = -EFAULT;
+			break;
+		}
+
+		shrd_mem = rmt_storage_get_shrd_mem(usr_shrd_mem.sid);
+		if (!shrd_mem) {
+			pr_err("%s: invalid sid (0x%x)\n", __func__,
+			       usr_shrd_mem.sid);
+			ret = -EFAULT;
+			break;
+		}
+
+		if (copy_to_user((void __user *)arg, shrd_mem,
+			sizeof(struct rmt_shrd_mem_param))) {
+			pr_err("%s: copy to user failed\n\n", __func__);
+			ret = -EFAULT;
+		}
+		break;
+
+	case RMT_STORAGE_WAIT_FOR_REQ:
+		pr_debug("%s: wait for request ioctl\n", __func__);
+		if (atomic_read(&rmc->total_events) == 0) {
+			ret = wait_event_interruptible(rmc->event_q,
+				atomic_read(&rmc->total_events) != 0);
+		}
+		if (ret < 0)
+			break;
+		atomic_dec(&rmc->total_events);
+
+		kevent = get_event(rmc);
+		WARN_ON(kevent == NULL);
+		if (copy_to_user((void __user *)arg, &kevent->event,
+			sizeof(struct rmt_storage_event))) {
+			pr_err("%s: copy to user failed\n\n", __func__);
+			ret = -EFAULT;
+		}
+		kfree(kevent);
+		break;
+
+	case RMT_STORAGE_SEND_STATUS:
+		pr_info("%s: send status ioctl\n", __func__);
+		if (copy_from_user(&status, (void __user *)arg,
+				sizeof(struct rmt_storage_send_sts))) {
+			pr_err("%s: copy from user failed\n\n", __func__);
+			ret = -EFAULT;
+			if (atomic_dec_return(&rmc->wcount) == 0)
+				wake_unlock(&rmc->wlock);
+			break;
+		}
+#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
+		stats = &client_stats[status.handle - 1];
+		if (status.xfer_dir == RMT_STORAGE_WRITE)
+			op_stats = &stats->wr_stats;
+		else
+			op_stats = &stats->rd_stats;
+		curr_stat = ktime_sub(ktime_get(), op_stats->start);
+		op_stats->total = ktime_add(op_stats->total, curr_stat);
+		op_stats->count++;
+		if (curr_stat.tv64 < stats->min.tv64)
+			op_stats->min = curr_stat;
+		if (curr_stat.tv64 > stats->max.tv64)
+			op_stats->max = curr_stat;
+#endif
+		pr_debug("%s: \thandle=%d err_code=%d data=0x%x\n", __func__,
+			status.handle, status.err_code, status.data);
+		rpc_client = rmt_storage_get_rpc_client(status.handle);
+		if (rpc_client)
+			ret = msm_rpc_client_req2(rpc_client,
+				RMT_STORAGE_OP_FINISH_PROC,
+				rmt_storage_send_sts_arg,
+				&status, NULL, NULL, -1);
+		else
+			ret = -EINVAL;
+		if (ret < 0)
+			pr_err("%s: send status failed with ret val = %d\n",
+				__func__, ret);
+		if (atomic_dec_return(&rmc->wcount) == 0)
+			wake_unlock(&rmc->wlock);
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+struct rmt_storage_sync_recv_arg {
+	int data;
+};
+
+static int rmt_storage_receive_sync_arg(struct msm_rpc_client *client,
+				struct msm_rpc_xdr *xdr, void *data)
+{
+	struct rmt_storage_sync_recv_arg *args = data;
+	struct rmt_storage_srv *srv;
+
+	srv = rmt_storage_get_srv(client->prog);
+	if (!srv)
+		return -EINVAL;
+	xdr_recv_int32(xdr, &args->data);
+	srv->sync_token = args->data;
+	return 0;
+}
+
+static int rmt_storage_force_sync(struct msm_rpc_client *client)
+{
+	struct rmt_storage_sync_recv_arg args;
+	int rc;
+	rc = msm_rpc_client_req2(client,
+			RMT_STORAGE_FORCE_SYNC_PROC, NULL, NULL,
+			rmt_storage_receive_sync_arg, &args, -1);
+	if (rc) {
+		pr_err("%s: force sync RPC req failed: %d\n", __func__, rc);
+		return rc;
+	}
+	return 0;
+}
+
+struct rmt_storage_sync_sts_arg {
+	int token;
+};
+
+static int rmt_storage_send_sync_sts_arg(struct msm_rpc_client *client,
+				struct msm_rpc_xdr *xdr, void *data)
+{
+	struct rmt_storage_sync_sts_arg *req = data;
+
+	xdr_send_int32(xdr, &req->token);
+	return 0;
+}
+
+static int rmt_storage_receive_sync_sts_arg(struct msm_rpc_client *client,
+				struct msm_rpc_xdr *xdr, void *data)
+{
+	struct rmt_storage_sync_recv_arg *args = data;
+
+	xdr_recv_int32(xdr, &args->data);
+	return 0;
+}
+
+static int rmt_storage_get_sync_status(struct msm_rpc_client *client)
+{
+	struct rmt_storage_sync_recv_arg recv_args;
+	struct rmt_storage_sync_sts_arg send_args;
+	struct rmt_storage_srv *srv;
+	int rc;
+
+	srv = rmt_storage_get_srv(client->prog);
+	if (!srv)
+		return -EINVAL;
+
+	if (srv->sync_token < 0)
+		return -EINVAL;
+
+	send_args.token = srv->sync_token;
+	rc = msm_rpc_client_req2(client,
+			RMT_STORAGE_GET_SYNC_STATUS_PROC,
+			rmt_storage_send_sync_sts_arg, &send_args,
+			rmt_storage_receive_sync_sts_arg, &recv_args, -1);
+	if (rc) {
+		pr_err("%s: sync status RPC req failed: %d\n", __func__, rc);
+		return rc;
+	}
+	return recv_args.data;
+}
+
+static int rmt_storage_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	unsigned long vsize = vma->vm_end - vma->vm_start;
+	int ret = -EINVAL;
+
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+	ret = io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+				 vsize, vma->vm_page_prot);
+	if (ret < 0)
+		pr_err("%s: failed with return val %d\n", __func__, ret);
+	return ret;
+}
+
+struct rmt_storage_reg_cb_args {
+	uint32_t event;
+	uint32_t cb_id;
+};
+
+static int rmt_storage_arg_cb(struct msm_rpc_client *client,
+		struct msm_rpc_xdr *xdr, void *data)
+{
+	struct rmt_storage_reg_cb_args *args = data;
+
+	xdr_send_uint32(xdr, &args->event);
+	xdr_send_uint32(xdr, &args->cb_id);
+	return 0;
+}
+
+static int rmt_storage_reg_cb(struct msm_rpc_client *client,
+			      uint32_t proc, uint32_t event, void *callback)
+{
+	struct rmt_storage_reg_cb_args args;
+	int rc, cb_id;
+	int retries = 10;
+
+	cb_id = msm_rpc_add_cb_func(client, callback);
+	if ((cb_id < 0) && (cb_id != MSM_RPC_CLIENT_NULL_CB_ID))
+		return cb_id;
+
+	args.event = event;
+	args.cb_id = cb_id;
+
+	while (retries) {
+		rc = msm_rpc_client_req2(client, proc, rmt_storage_arg_cb,
+					 &args, NULL, NULL, -1);
+		if (rc != -ETIMEDOUT)
+			break;
+		retries--;
+		udelay(1000);
+	}
+	if (rc)
+		pr_err("%s: Failed to register callback for event %d\n",
+				__func__, event);
+	return rc;
+}
+
+#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
+static int rmt_storage_stats_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static ssize_t rmt_storage_stats_read(struct file *file, char __user *ubuf,
+		size_t count, loff_t *ppos)
+{
+	uint32_t tot_clients;
+	char buf[512];
+	int max, j, i = 0;
+	struct rmt_storage_stats *stats;
+
+	max = sizeof(buf) - 1;
+	tot_clients = find_first_zero_bit(&rmc->cids, sizeof(rmc->cids)) - 1;
+
+	for (j = 0; j < tot_clients; j++) {
+		stats = &client_stats[j];
+		i += scnprintf(buf + i, max - i, "stats for partition %s:\n",
+				stats->path);
+		i += scnprintf(buf + i, max - i, "Min read time: %lld us\n",
+				ktime_to_us(stats->rd_stats.min));
+		i += scnprintf(buf + i, max - i, "Max read time: %lld us\n",
+				ktime_to_us(stats->rd_stats.max));
+		i += scnprintf(buf + i, max - i, "Total read time: %lld us\n",
+				ktime_to_us(stats->rd_stats.total));
+		i += scnprintf(buf + i, max - i, "Total read requests: %ld\n",
+				stats->rd_stats.count);
+		if (stats->count)
+			i += scnprintf(buf + i, max - i,
+				"Avg read time: %lld us\n",
+				div_s64(ktime_to_us(stats->total),
+				stats->rd_stats.count));
+
+		i += scnprintf(buf + i, max - i, "Min write time: %lld us\n",
+				ktime_to_us(stats->wr_stats.min));
+		i += scnprintf(buf + i, max - i, "Max write time: %lld us\n",
+				ktime_to_us(stats->wr_stats.max));
+		i += scnprintf(buf + i, max - i, "Total write time: %lld us\n",
+				ktime_to_us(stats->wr_stats.total));
+		i += scnprintf(buf + i, max - i, "Total read requests: %ld\n",
+				stats->wr_stats.count);
+		if (stats->count)
+			i += scnprintf(buf + i, max - i,
+				"Avg write time: %lld us\n",
+				div_s64(ktime_to_us(stats->total),
+				stats->wr_stats.count));
+	}
+	return simple_read_from_buffer(ubuf, count, ppos, buf, i);
+}
+
+static const struct file_operations debug_ops = {
+	.owner = THIS_MODULE,
+	.open = rmt_storage_stats_open,
+	.read = rmt_storage_stats_read,
+};
+#endif
+
+const struct file_operations rmt_storage_fops = {
+	.owner = THIS_MODULE,
+	.open = rmt_storage_open,
+	.unlocked_ioctl	 = rmt_storage_ioctl,
+	.mmap = rmt_storage_mmap,
+	.release = rmt_storage_release,
+};
+
+static struct miscdevice rmt_storage_device = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "rmt_storage",
+	.fops = &rmt_storage_fops,
+};
+
+static int rmt_storage_get_ramfs(struct rmt_storage_srv *srv)
+{
+	struct shared_ramfs_table *ramfs_table;
+	struct shared_ramfs_entry *ramfs_entry;
+	int index, ret;
+
+	if (srv->prog != MSM_RMT_STORAGE_APIPROG)
+		return 0;
+
+	ramfs_table = smem_alloc(SMEM_SEFS_INFO,
+			sizeof(struct shared_ramfs_table));
+
+	if (!ramfs_table) {
+		pr_err("%s: No RAMFS table in SMEM\n", __func__);
+		return -ENOENT;
+	}
+
+	if ((ramfs_table->magic_id != (u32) RAMFS_INFO_MAGICNUMBER) ||
+	    (ramfs_table->version != (u32) RAMFS_INFO_VERSION)) {
+		pr_err("%s: Magic / Version mismatch:, "
+		       "magic_id=%#x, format_version=%#x\n", __func__,
+		       ramfs_table->magic_id, ramfs_table->version);
+		return -ENOENT;
+	}
+
+	for (index = 0; index < ramfs_table->entries; index++) {
+		ramfs_entry = &ramfs_table->ramfs_entry[index];
+		if (!ramfs_entry->client_id ||
+		    ramfs_entry->client_id == (u32) RAMFS_DEFAULT)
+			break;
+
+		pr_info("%s: RAMFS entry: addr = 0x%08x, size = 0x%08x\n",
+			__func__, ramfs_entry->base_addr, ramfs_entry->size);
+
+		ret = rmt_storage_add_shrd_mem(ramfs_entry->client_id,
+					       ramfs_entry->base_addr,
+					       ramfs_entry->size,
+					       NULL,
+					       ramfs_entry,
+					       srv);
+		if (ret) {
+			pr_err("%s: Error (%d) adding shared mem\n",
+			       __func__, ret);
+			return ret;
+		}
+	}
+	return 0;
+}
+
+static ssize_t
+show_force_sync(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct platform_device *pdev;
+	struct rpcsvr_platform_device *rpc_pdev;
+	struct rmt_storage_srv *srv;
+
+	pdev = container_of(dev, struct platform_device, dev);
+	rpc_pdev = container_of(pdev, struct rpcsvr_platform_device, base);
+	srv = rmt_storage_get_srv(rpc_pdev->prog);
+	if (!srv) {
+		pr_err("%s: Unable to find prog=0x%x\n", __func__,
+		       rpc_pdev->prog);
+		return -EINVAL;
+	}
+
+	return rmt_storage_force_sync(srv->rpc_client);
+}
+
+/* Returns -EINVAL for invalid sync token and an error value for any failure
+ * in RPC call. Upon success, it returns a sync status of 1 (sync done)
+ * or 0 (sync still pending).
+ */
+static ssize_t
+show_sync_sts(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct platform_device *pdev;
+	struct rpcsvr_platform_device *rpc_pdev;
+	struct rmt_storage_srv *srv;
+
+	pdev = container_of(dev, struct platform_device, dev);
+	rpc_pdev = container_of(pdev, struct rpcsvr_platform_device, base);
+	srv = rmt_storage_get_srv(rpc_pdev->prog);
+	if (!srv) {
+		pr_err("%s: Unable to find prog=0x%x\n", __func__,
+		       rpc_pdev->prog);
+		return -EINVAL;
+	}
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			rmt_storage_get_sync_status(srv->rpc_client));
+}
+
+static int rmt_storage_init_ramfs(struct rmt_storage_srv *srv)
+{
+	struct shared_ramfs_table *ramfs_table;
+
+	if (srv->prog != MSM_RMT_STORAGE_APIPROG)
+		return 0;
+
+	ramfs_table = smem_alloc(SMEM_SEFS_INFO,
+				 sizeof(struct shared_ramfs_table));
+
+	if (!ramfs_table) {
+		pr_err("%s: No RAMFS table in SMEM\n", __func__);
+		return -ENOENT;
+	}
+
+	if (ramfs_table->magic_id == RAMFS_INFO_MAGICNUMBER) {
+		pr_debug("RAMFS table already filled... skipping %s", \
+			__func__);
+		return 0;
+	}
+
+	ramfs_table->ramfs_entry[0].client_id  = RAMFS_MODEMSTORAGE_ID;
+	ramfs_table->ramfs_entry[0].base_addr  = RAMFS_SHARED_EFS_RAM_BASE;
+	ramfs_table->ramfs_entry[0].size       = RAMFS_SHARED_EFS_RAM_SIZE;
+	ramfs_table->ramfs_entry[0].client_sts = RAMFS_DEFAULT;
+
+	ramfs_table->ramfs_entry[1].client_id  = RAMFS_SSD_STORAGE_ID;
+	ramfs_table->ramfs_entry[1].base_addr  = RAMFS_SHARED_SSD_RAM_BASE;
+	ramfs_table->ramfs_entry[1].size       = RAMFS_SHARED_SSD_RAM_SIZE;
+	ramfs_table->ramfs_entry[1].client_sts = RAMFS_DEFAULT;
+
+	ramfs_table->entries  = 2;
+	ramfs_table->version  = RAMFS_INFO_VERSION;
+	ramfs_table->magic_id = RAMFS_INFO_MAGICNUMBER;
+
+	return 0;
+}
+
+static void rmt_storage_set_client_status(struct rmt_storage_srv *srv,
+					  int enable)
+{
+	struct rmt_shrd_mem *shrd_mem;
+
+	spin_lock(&rmc->lock);
+	list_for_each_entry(shrd_mem, &rmc->shrd_mem_list, list)
+		if (shrd_mem->srv->prog == srv->prog)
+			if (shrd_mem->smem_info)
+				shrd_mem->smem_info->client_sts = !!enable;
+	spin_unlock(&rmc->lock);
+}
+
+static DEVICE_ATTR(force_sync, S_IRUGO | S_IWUSR, show_force_sync, NULL);
+static DEVICE_ATTR(sync_sts, S_IRUGO | S_IWUSR, show_sync_sts, NULL);
+static struct attribute *dev_attrs[] = {
+	&dev_attr_force_sync.attr,
+	&dev_attr_sync_sts.attr,
+	NULL,
+};
+static struct attribute_group dev_attr_grp = {
+	.attrs = dev_attrs,
+};
+
+static void handle_restart_teardown(struct msm_rpc_client *client)
+{
+	struct rmt_storage_srv *srv;
+
+	srv = rmt_storage_get_srv(client->prog);
+	if (!srv)
+		return;
+	pr_debug("%s: Modem restart for 0x%08x\n", __func__, srv->prog);
+	cancel_delayed_work_sync(&srv->restart_work);
+}
+
+#define RESTART_WORK_DELAY_MS	1000
+
+static void handle_restart_setup(struct msm_rpc_client *client)
+{
+	struct rmt_storage_srv *srv;
+
+	srv = rmt_storage_get_srv(client->prog);
+	if (!srv)
+		return;
+	pr_debug("%s: Scheduling restart for 0x%08x\n", __func__, srv->prog);
+	queue_delayed_work(rmc->workq, &srv->restart_work,
+			msecs_to_jiffies(RESTART_WORK_DELAY_MS));
+}
+
+static int rmt_storage_reg_callbacks(struct msm_rpc_client *client)
+{
+	int ret;
+
+	ret = rmt_storage_reg_cb(client,
+				 RMT_STORAGE_REGISTER_OPEN_PROC,
+				 RMT_STORAGE_EVNT_OPEN,
+				 rmt_storage_event_open_cb);
+	if (ret)
+		return ret;
+	ret = rmt_storage_reg_cb(client,
+				 RMT_STORAGE_REGISTER_CB_PROC,
+				 RMT_STORAGE_EVNT_CLOSE,
+				 rmt_storage_event_close_cb);
+	if (ret)
+		return ret;
+	ret = rmt_storage_reg_cb(client,
+				 RMT_STORAGE_REGISTER_CB_PROC,
+				 RMT_STORAGE_EVNT_WRITE_BLOCK,
+				 rmt_storage_event_write_block_cb);
+	if (ret)
+		return ret;
+	ret = rmt_storage_reg_cb(client,
+				 RMT_STORAGE_REGISTER_CB_PROC,
+				 RMT_STORAGE_EVNT_GET_DEV_ERROR,
+				 rmt_storage_event_get_err_cb);
+	if (ret)
+		return ret;
+	ret = rmt_storage_reg_cb(client,
+				 RMT_STORAGE_REGISTER_WRITE_IOVEC_PROC,
+				 RMT_STORAGE_EVNT_WRITE_IOVEC,
+				 rmt_storage_event_write_iovec_cb);
+	if (ret)
+		return ret;
+	ret = rmt_storage_reg_cb(client,
+				 RMT_STORAGE_REGISTER_READ_IOVEC_PROC,
+				 RMT_STORAGE_EVNT_READ_IOVEC,
+				 rmt_storage_event_read_iovec_cb);
+	if (ret)
+		return ret;
+	ret = rmt_storage_reg_cb(client,
+				 RMT_STORAGE_REGISTER_CB_PROC,
+				 RMT_STORAGE_EVNT_SEND_USER_DATA,
+				 rmt_storage_event_user_data_cb);
+	if (ret)
+		return ret;
+	ret = rmt_storage_reg_cb(client,
+				 RMT_STORAGE_REGISTER_ALLOC_RMT_BUF_PROC,
+				 RMT_STORAGE_EVNT_ALLOC_RMT_BUF,
+				 rmt_storage_event_alloc_rmt_buf_cb);
+	if (ret)
+		pr_info("%s: Unable (%d) registering aloc_rmt_buf\n",
+			__func__, ret);
+
+	pr_debug("%s: Callbacks (re)registered for 0x%08x\n\n", __func__,
+		 client->prog);
+	return 0;
+}
+
+static void rmt_storage_restart_work(struct work_struct *work)
+{
+	struct rmt_storage_srv *srv;
+	int ret;
+
+	srv = container_of((struct delayed_work *)work,
+			   struct rmt_storage_srv, restart_work);
+	if (!rmt_storage_get_srv(srv->prog)) {
+		pr_err("%s: Invalid server\n", __func__);
+		return;
+	}
+
+	ret = rmt_storage_reg_callbacks(srv->rpc_client);
+	if (!ret)
+		return;
+
+	pr_err("%s: Error (%d) re-registering callbacks for0x%08x\n",
+	       __func__, ret, srv->prog);
+
+	if (!msm_rpc_client_in_reset(srv->rpc_client))
+		queue_delayed_work(rmc->workq, &srv->restart_work,
+				msecs_to_jiffies(RESTART_WORK_DELAY_MS));
+}
+
+static int rmt_storage_probe(struct platform_device *pdev)
+{
+	struct rpcsvr_platform_device *dev;
+	struct rmt_storage_srv *srv;
+	int ret;
+
+	dev = container_of(pdev, struct rpcsvr_platform_device, base);
+	srv = rmt_storage_get_srv(dev->prog);
+	if (!srv) {
+		pr_err("%s: Invalid prog = %#x\n", __func__, dev->prog);
+		return -ENXIO;
+	}
+
+	rmt_storage_init_ramfs(srv);
+	rmt_storage_get_ramfs(srv);
+
+	INIT_DELAYED_WORK(&srv->restart_work, rmt_storage_restart_work);
+
+	/* Client Registration */
+	srv->rpc_client = msm_rpc_register_client2("rmt_storage",
+						   dev->prog, dev->vers, 1,
+						   handle_rmt_storage_call);
+	if (IS_ERR(srv->rpc_client)) {
+		pr_err("%s: Unable to register client (prog %.8x vers %.8x)\n",
+				__func__, dev->prog, dev->vers);
+		ret = PTR_ERR(srv->rpc_client);
+		return ret;
+	}
+
+	ret = msm_rpc_register_reset_callbacks(srv->rpc_client,
+		handle_restart_teardown,
+		handle_restart_setup);
+	if (ret)
+		goto unregister_client;
+
+	pr_info("%s: Remote storage RPC client (0x%x)initialized\n",
+		__func__, dev->prog);
+
+	/* register server callbacks */
+	ret = rmt_storage_reg_callbacks(srv->rpc_client);
+	if (ret)
+		goto unregister_client;
+
+	/* For targets that poll SMEM, set status to ready */
+	rmt_storage_set_client_status(srv, 1);
+
+	ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
+	if (ret)
+		pr_err("%s: Failed to create sysfs node: %d\n", __func__, ret);
+
+	return 0;
+
+unregister_client:
+	msm_rpc_unregister_client(srv->rpc_client);
+	return ret;
+}
+
+static void rmt_storage_client_shutdown(struct platform_device *pdev)
+{
+	struct rpcsvr_platform_device *dev;
+	struct rmt_storage_srv *srv;
+
+	dev = container_of(pdev, struct rpcsvr_platform_device, base);
+	srv = rmt_storage_get_srv(dev->prog);
+	rmt_storage_set_client_status(srv, 0);
+}
+
+static void rmt_storage_destroy_rmc(void)
+{
+	wake_lock_destroy(&rmc->wlock);
+}
+
+static void __init rmt_storage_init_client_info(void)
+{
+	/* Initialization */
+	init_waitqueue_head(&rmc->event_q);
+	spin_lock_init(&rmc->lock);
+	atomic_set(&rmc->total_events, 0);
+	INIT_LIST_HEAD(&rmc->event_list);
+	INIT_LIST_HEAD(&rmc->client_list);
+	INIT_LIST_HEAD(&rmc->shrd_mem_list);
+	/* The client expects a non-zero return value for
+	 * its open requests. Hence reserve 0 bit.  */
+	__set_bit(0, &rmc->cids);
+	atomic_set(&rmc->wcount, 0);
+	wake_lock_init(&rmc->wlock, WAKE_LOCK_SUSPEND, "rmt_storage");
+}
+
+static struct rmt_storage_srv msm_srv = {
+	.prog = MSM_RMT_STORAGE_APIPROG,
+	.plat_drv = {
+		.probe	  = rmt_storage_probe,
+		.shutdown = rmt_storage_client_shutdown,
+		.driver	  = {
+			.name	= "rs300000a7",
+			.owner	= THIS_MODULE,
+		},
+	},
+};
+
+static struct rmt_storage_srv mdm_srv = {
+	.prog = MDM_RMT_STORAGE_APIPROG,
+	.plat_drv = {
+		.probe	  = rmt_storage_probe,
+		.shutdown = rmt_storage_client_shutdown,
+		.driver	  = {
+			.name	= "rs300100a7",
+			.owner	= THIS_MODULE,
+		},
+	},
+};
+
+static struct rmt_storage_srv *rmt_storage_get_srv(uint32_t prog)
+{
+	if (prog == MSM_RMT_STORAGE_APIPROG)
+		return &msm_srv;
+	if (prog == MDM_RMT_STORAGE_APIPROG)
+		return &mdm_srv;
+	return NULL;
+}
+
+
+static uint32_t rmt_storage_get_sid(const char *path)
+{
+	if (!strncmp(path, "/boot/modem_fs1", MAX_PATH_NAME))
+		return RAMFS_MODEMSTORAGE_ID;
+	if (!strncmp(path, "/boot/modem_fs2", MAX_PATH_NAME))
+		return RAMFS_MODEMSTORAGE_ID;
+	if (!strncmp(path, "/boot/modem_fsg", MAX_PATH_NAME))
+		return RAMFS_MODEMSTORAGE_ID;
+	if (!strncmp(path, "/q6_fs1_parti_id_0x59", MAX_PATH_NAME))
+		return RAMFS_MDM_STORAGE_ID;
+	if (!strncmp(path, "/q6_fs2_parti_id_0x5A", MAX_PATH_NAME))
+		return RAMFS_MDM_STORAGE_ID;
+	if (!strncmp(path, "/q6_fsg_parti_id_0x5B", MAX_PATH_NAME))
+		return RAMFS_MDM_STORAGE_ID;
+	if (!strncmp(path, "ssd", MAX_PATH_NAME))
+		return RAMFS_SSD_STORAGE_ID;
+	return 0;
+}
+
+static int __init rmt_storage_init(void)
+{
+#ifdef CONFIG_MSM_SDIO_SMEM
+	void *mdm_local_buf;
+#endif
+	int ret = 0;
+
+	rmc = kzalloc(sizeof(struct rmt_storage_client_info), GFP_KERNEL);
+	if (!rmc) {
+		pr_err("%s: Unable to allocate memory\n", __func__);
+		return  -ENOMEM;
+	}
+	rmt_storage_init_client_info();
+
+	ret = platform_driver_register(&msm_srv.plat_drv);
+	if (ret) {
+		pr_err("%s: Unable to register MSM RPC driver\n", __func__);
+		goto rmc_free;
+	}
+
+	ret = platform_driver_register(&mdm_srv.plat_drv);
+	if (ret) {
+		pr_err("%s: Unable to register MDM RPC driver\n", __func__);
+		goto unreg_msm_rpc;
+	}
+
+	ret = misc_register(&rmt_storage_device);
+	if (ret) {
+		pr_err("%s: Unable to register misc device %d\n", __func__,
+				MISC_DYNAMIC_MINOR);
+		goto unreg_mdm_rpc;
+	}
+
+#ifdef CONFIG_MSM_SDIO_SMEM
+	mdm_local_buf = kzalloc(MDM_LOCAL_BUF_SZ, GFP_KERNEL);
+	if (!mdm_local_buf) {
+		pr_err("%s: Unable to allocate shadow mem\n", __func__);
+		ret = -ENOMEM;
+		goto unreg_misc;
+	}
+
+	ret = rmt_storage_add_shrd_mem(RAMFS_MDM_STORAGE_ID,
+				       __pa(mdm_local_buf),
+				       MDM_LOCAL_BUF_SZ,
+				       NULL, NULL, &mdm_srv);
+	if (ret) {
+		pr_err("%s: Unable to add shadow mem entry\n", __func__);
+		goto free_mdm_local_buf;
+	}
+
+	pr_debug("%s: Shadow memory at %p (phys=%lx), %d bytes\n", __func__,
+		 mdm_local_buf, __pa(mdm_local_buf), MDM_LOCAL_BUF_SZ);
+#endif
+
+	rmc->workq = create_singlethread_workqueue("rmt_storage");
+	if (!rmc->workq)
+		return -ENOMEM;
+
+#ifdef CONFIG_MSM_RMT_STORAGE_CLIENT_STATS
+	stats_dentry = debugfs_create_file("rmt_storage_stats", 0444, 0,
+					NULL, &debug_ops);
+	if (!stats_dentry)
+		pr_err("%s: Failed to create stats debugfs file\n", __func__);
+#endif
+	return 0;
+
+#ifdef CONFIG_MSM_SDIO_SMEM
+free_mdm_local_buf:
+	kfree(mdm_local_buf);
+unreg_misc:
+	misc_deregister(&rmt_storage_device);
+#endif
+unreg_mdm_rpc:
+	platform_driver_unregister(&mdm_srv.plat_drv);
+unreg_msm_rpc:
+	platform_driver_unregister(&msm_srv.plat_drv);
+rmc_free:
+	rmt_storage_destroy_rmc();
+	kfree(rmc);
+	return ret;
+}
+
+module_init(rmt_storage_init);
+MODULE_DESCRIPTION("Remote Storage RPC Client");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/rpc_dog_keepalive.c b/arch/arm/mach-msm/rpc_dog_keepalive.c
new file mode 100644
index 0000000..609b125
--- /dev/null
+++ b/arch/arm/mach-msm/rpc_dog_keepalive.c
@@ -0,0 +1,240 @@
+/* Copyright (c) 2010, 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.
+ *
+ */
+
+/*
+ * DOG KEEPALIVE RPC CLIENT MODULE
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <mach/msm_rpcrouter.h>
+
+#define DOG_KEEPALIVE_PROG 0x300000A2
+#define DOG_KEEPALIVE_VERS 0x00010001
+
+#define DOG_KEEPALIVE_REGISTER_PROC      2
+#define DOG_KEEPALIVE_UNREGISTER_PROC    3
+
+#define DOG_KEEPALIVE_CB_PROC            1
+
+static int dog_keepalive_debug;
+module_param_named(debug, dog_keepalive_debug,
+		   int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#if defined(DEBUG)
+#define DBG(x...)  do {		                \
+		if (dog_keepalive_debug)	\
+			printk(KERN_INFO x);	\
+	} while (0)
+#else
+#define DBG(x...) do { } while (0)
+#endif
+
+static struct msm_rpc_client *dog_keepalive_rpc_client;
+static int32_t dog_clnt_id = -1;
+
+struct dog_keepalive_cb_arg {
+	uint32_t cb_id;
+};
+
+struct dog_keepalive_cb_ret {
+	uint32_t result;
+};
+
+static int dog_keepalive_cb(struct msm_rpc_client *client,
+			    struct msm_rpc_xdr *xdr)
+{
+	int rc;
+	void *cb_func;
+	uint32_t accept_status;
+	struct dog_keepalive_cb_arg arg;
+	struct dog_keepalive_cb_ret ret;
+
+	xdr_recv_uint32(xdr, &arg.cb_id);           /* cb_id */
+
+	cb_func = msm_rpc_get_cb_func(client, arg.cb_id);
+	if (cb_func) {
+		rc = ((int (*)
+		       (struct dog_keepalive_cb_arg *,
+			struct dog_keepalive_cb_ret *))
+		      cb_func)(&arg, &ret);
+		if (rc)
+			accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
+		else
+			accept_status = RPC_ACCEPTSTAT_SUCCESS;
+	} else
+		accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
+
+	xdr_start_accepted_reply(xdr, accept_status);
+
+	if (accept_status == RPC_ACCEPTSTAT_SUCCESS)
+		xdr_send_uint32(xdr, &ret.result);         /* result */
+
+	rc = xdr_send_msg(xdr);
+	if (rc)
+		pr_err("%s: send accepted reply failed: %d\n", __func__, rc);
+
+	return rc;
+}
+
+static int dog_keepalive_cb_func(struct msm_rpc_client *client,
+				 struct rpc_request_hdr *req,
+				 struct msm_rpc_xdr *xdr)
+{
+	int rc = 0;
+
+	switch (req->procedure) {
+	case DOG_KEEPALIVE_CB_PROC:
+		rc = dog_keepalive_cb(client, xdr);
+		break;
+	default:
+		pr_err("%s: procedure not supported %d\n",
+		       __func__, req->procedure);
+		xdr_start_accepted_reply(xdr, RPC_ACCEPTSTAT_PROC_UNAVAIL);
+		rc = xdr_send_msg(xdr);
+		if (rc)
+			pr_err("%s: sending reply failed: %d\n", __func__, rc);
+		break;
+	}
+	return rc;
+}
+
+struct dog_keepalive_register_arg {
+	int (*cb_func)(
+		struct dog_keepalive_cb_arg *arg,
+		struct dog_keepalive_cb_ret *ret);
+	uint32_t response_msec;
+	uint32_t clnt_id_valid;
+};
+
+struct dog_keepalive_register_ret {
+	uint32_t *clnt_id;
+	uint32_t result;
+};
+
+static int dog_keepalive_register_arg_func(struct msm_rpc_client *client,
+					   struct msm_rpc_xdr *xdr, void *data)
+{
+	struct dog_keepalive_register_arg *arg = data;
+	int cb_id;
+
+	/* cb_func */
+	cb_id = msm_rpc_add_cb_func(client, (void *)arg->cb_func);
+	if ((cb_id < 0) && (cb_id != MSM_RPC_CLIENT_NULL_CB_ID))
+		return cb_id;
+
+	xdr_send_uint32(xdr, &cb_id);
+	xdr_send_uint32(xdr, &arg->response_msec);    /* response_msec */
+	xdr_send_uint32(xdr, &arg->clnt_id_valid);    /* clnt_id valid */
+	return 0;
+}
+
+static int dog_keepalive_register_ret_func(struct msm_rpc_client *client,
+					   struct msm_rpc_xdr *xdr, void *data)
+{
+	struct dog_keepalive_register_ret *ret = data;
+
+	/* clnt_id */
+	xdr_recv_pointer(xdr, (void **)&(ret->clnt_id), sizeof(uint32_t),
+			 xdr_recv_uint32);
+
+	/* result */
+	xdr_recv_uint32(xdr, &ret->result);
+	return 0;
+}
+
+static int dog_keepalive_register_func(struct msm_rpc_client *client,
+				       struct dog_keepalive_register_arg *arg,
+				       struct dog_keepalive_register_ret *ret)
+{
+	return msm_rpc_client_req2(client,
+				   DOG_KEEPALIVE_REGISTER_PROC,
+				   dog_keepalive_register_arg_func, arg,
+				   dog_keepalive_register_ret_func, ret, -1);
+}
+
+static int dog_keepalive_cb_proc_func(struct dog_keepalive_cb_arg *arg,
+				      struct dog_keepalive_cb_ret *ret)
+{
+	DBG("%s: received, client %d \n", __func__, dog_clnt_id);
+	ret->result = 1;
+	return 0;
+}
+
+static void dog_keepalive_register(void)
+{
+	struct dog_keepalive_register_arg arg;
+	struct dog_keepalive_register_ret ret;
+	int rc;
+
+	arg.cb_func = dog_keepalive_cb_proc_func;
+	arg.response_msec = 1000;
+	arg.clnt_id_valid = 1;
+	ret.clnt_id = NULL;
+	rc = dog_keepalive_register_func(dog_keepalive_rpc_client,
+					 &arg, &ret);
+	if (rc)
+		pr_err("%s: register request failed\n", __func__);
+	else
+		dog_clnt_id = *ret.clnt_id;
+
+	kfree(ret.clnt_id);
+	DBG("%s: register complete\n", __func__);
+}
+
+/* Registration with the platform driver for notification on the availability
+ * of the DOG_KEEPALIVE remote server
+ */
+static int dog_keepalive_init_probe(struct platform_device *pdev)
+{
+	DBG("%s: probe called\n", __func__);
+	dog_keepalive_rpc_client = msm_rpc_register_client2(
+		"dog-keepalive",
+		DOG_KEEPALIVE_PROG,
+		DOG_KEEPALIVE_VERS,
+		0, dog_keepalive_cb_func);
+
+	if (IS_ERR(dog_keepalive_rpc_client)) {
+		pr_err("%s: RPC client creation failed\n", __func__);
+		return PTR_ERR(dog_keepalive_rpc_client);
+	}
+
+	/* Send RPC call to register for callbacks */
+	dog_keepalive_register();
+
+	return 0;
+}
+
+static char dog_keepalive_driver_name[] = "rs00000000";
+
+static struct platform_driver dog_keepalive_init_driver = {
+	.probe = dog_keepalive_init_probe,
+	.driver = {
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init rpc_dog_keepalive_init(void)
+{
+	snprintf(dog_keepalive_driver_name, sizeof(dog_keepalive_driver_name),
+		 "rs%08x", DOG_KEEPALIVE_PROG);
+	dog_keepalive_init_driver.driver.name = dog_keepalive_driver_name;
+
+	return platform_driver_register(&dog_keepalive_init_driver);
+}
+
+late_initcall(rpc_dog_keepalive_init);
+MODULE_DESCRIPTION("DOG KEEPALIVE RPC CLIENT");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/rpc_fsusb.c b/arch/arm/mach-msm/rpc_fsusb.c
new file mode 100644
index 0000000..4692d94
--- /dev/null
+++ b/arch/arm/mach-msm/rpc_fsusb.c
@@ -0,0 +1,244 @@
+/* Copyright (c) 2009, 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/err.h>
+#include <linux/module.h>
+#include <mach/rpc_hsusb.h>
+#include <mach/msm_hsusb.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/board.h>
+
+#define PM_APP_OTG_PROG		0x30000080
+#define PM_APP_OTG_VERS		0x00010001
+
+#define PM_APP_OTG_INIT_PHY			17
+#define PM_APP_OTG_RESET_PHY			18
+#define PM_APP_OTG_SUSPEND_PHY			7
+#define PM_APP_OTG_RESUME_PHY			8
+#define PM_APP_OTG_DEV_DISCONNECTED		9
+#define PM_APP_OTG_SET_WAKEUP			10
+#define PM_APP_OTG_ACQUIRE_BUS			3
+#define PM_APP_OTG_RELINQUISH_BUS		4
+
+#define PM_APP_OTG_INIT_DONE_CB_PROC		1
+#define PM_APP_OTG_HOST_INIT_CB_PROC		3
+#define PM_APP_OTG_REMOTE_DEV_LOST_CB_PROC	8
+#define PM_APP_OTG_REMOTE_DEV_RESUMED_CB_PROC	9
+#define PM_APP_OTG_ERROR_NOTIFY_CB_PROC		11
+
+#define NUM_OF_CALLBACKS			11
+static struct msm_rpc_client *client;
+static struct msm_otg_ops *host_ops;
+
+static int msm_fsusb_rpc_arg(struct msm_rpc_client *client,
+			     void *buf, void *data)
+{
+	int i, size = 0;
+	uint32_t proc = *(uint32_t *)data;
+
+	switch (proc) {
+	case PM_APP_OTG_INIT_PHY: {
+		for (i = 0; i < NUM_OF_CALLBACKS; i++) {
+			*((uint32_t *)buf) = cpu_to_be32(0x11111111);
+			size += sizeof(uint32_t);
+			buf += sizeof(uint32_t);
+		}
+
+		/* sleep_assert callback fucntion will be registered locally*/
+		*((uint32_t *)buf) = cpu_to_be32(0xffffffff);
+		size += sizeof(uint32_t);
+		break;
+	}
+	case PM_APP_OTG_SET_WAKEUP: {
+			*((uint32_t *)buf) = cpu_to_be32(1);
+			size += sizeof(uint32_t);
+			break;
+	}
+	case PM_APP_OTG_ACQUIRE_BUS: {
+			*((uint32_t *)buf) = cpu_to_be32(0xffffffff);
+			size += sizeof(uint32_t);
+			break;
+	}
+	default:
+		pr_info("%s: No arguments expected\n", __func__);
+	}
+	return size;
+}
+
+int msm_fsusb_init_phy(void)
+{
+	uint32_t data = PM_APP_OTG_INIT_PHY;
+
+	return msm_rpc_client_req(client,
+			PM_APP_OTG_INIT_PHY,
+			msm_fsusb_rpc_arg, &data,
+			NULL, NULL, -1);
+}
+EXPORT_SYMBOL(msm_fsusb_init_phy);
+
+int msm_fsusb_reset_phy(void)
+{
+	return msm_rpc_client_req(client,
+			PM_APP_OTG_RESET_PHY,
+			NULL, NULL,
+			NULL, NULL, -1);
+
+}
+EXPORT_SYMBOL(msm_fsusb_reset_phy);
+
+int msm_fsusb_suspend_phy(void)
+{
+	return msm_rpc_client_req(client,
+			PM_APP_OTG_SUSPEND_PHY,
+			NULL, NULL,
+			NULL, NULL, -1);
+
+}
+EXPORT_SYMBOL(msm_fsusb_suspend_phy);
+
+int msm_fsusb_resume_phy(void)
+{
+	return msm_rpc_client_req(client,
+			PM_APP_OTG_RESUME_PHY,
+			NULL, NULL,
+			NULL, NULL, -1);
+
+}
+EXPORT_SYMBOL(msm_fsusb_resume_phy);
+
+int msm_fsusb_remote_dev_disconnected(void)
+{
+	return msm_rpc_client_req(client,
+			PM_APP_OTG_DEV_DISCONNECTED,
+			NULL, NULL,
+			NULL, NULL, -1);
+
+}
+EXPORT_SYMBOL(msm_fsusb_remote_dev_disconnected);
+
+int  msm_fsusb_set_remote_wakeup(void)
+{
+	uint32_t data = PM_APP_OTG_SET_WAKEUP;
+
+	return msm_rpc_client_req(client,
+			PM_APP_OTG_SET_WAKEUP,
+			msm_fsusb_rpc_arg, &data,
+			NULL, NULL, -1);
+
+}
+EXPORT_SYMBOL(msm_fsusb_set_remote_wakeup);
+
+static int msm_fsusb_acquire_bus(void)
+{
+	uint32_t data = PM_APP_OTG_ACQUIRE_BUS;
+
+	return msm_rpc_client_req(client,
+			PM_APP_OTG_ACQUIRE_BUS,
+			msm_fsusb_rpc_arg, &data,
+			NULL, NULL, -1);
+
+}
+
+static int msm_fsusb_relinquish_bus(void)
+{
+	return msm_rpc_client_req(client,
+			PM_APP_OTG_RELINQUISH_BUS,
+			NULL, NULL,
+			NULL, NULL, -1);
+
+}
+
+static void msm_fsusb_request_session(void)
+{
+	int ret;
+
+	ret = msm_fsusb_relinquish_bus();
+	if (ret < 0)
+		pr_err("relinquish_bus rpc failed\n");
+	ret = msm_fsusb_acquire_bus();
+	if (ret < 0)
+		pr_err("acquire_bus rpc failed\n");
+}
+
+static int msm_fsusb_cb_func(struct msm_rpc_client *client,
+			    void *buffer, int in_size)
+{
+	struct rpc_request_hdr *req;
+	int rc;
+
+	req = buffer;
+
+	msm_rpc_start_accepted_reply(client, be32_to_cpu(req->xid),
+				     RPC_ACCEPTSTAT_SUCCESS);
+	rc = msm_rpc_send_accepted_reply(client, 0);
+	if (rc) {
+		pr_err("%s: sending reply failed: %d\n", __func__, rc);
+		return rc;
+	}
+
+	switch (be32_to_cpu(req->procedure)) {
+	case PM_APP_OTG_INIT_DONE_CB_PROC: {
+		pr_debug("pm_app_otg_init_done callback received");
+		msm_fsusb_request_session();
+		break;
+	}
+	case PM_APP_OTG_HOST_INIT_CB_PROC: {
+		pr_debug("pm_app_otg_host_init_cb_proc callback received");
+		host_ops->request(host_ops->handle, REQUEST_START);
+		break;
+	}
+	case PM_APP_OTG_REMOTE_DEV_LOST_CB_PROC: {
+		pr_debug("pm_app_otg_remote_dev_lost_cb_proc"
+				" callback received");
+		msm_fsusb_acquire_bus();
+		host_ops->request(host_ops->handle, REQUEST_STOP);
+		break;
+	}
+	case PM_APP_OTG_REMOTE_DEV_RESUMED_CB_PROC: {
+		pr_debug("pm_app_otg_remote_dev_resumed_cb_proc"
+				"callback received");
+		host_ops->request(host_ops->handle, REQUEST_RESUME);
+		break;
+	}
+	case PM_APP_OTG_ERROR_NOTIFY_CB_PROC: {
+		pr_err("pm_app_otg_error_notify_cb_proc callback received");
+		break;
+	}
+	default:
+		pr_err("%s: unknown callback(proc = %d) received\n",
+					__func__, req->procedure);
+	}
+	return 0;
+}
+
+int msm_fsusb_rpc_init(struct msm_otg_ops *ops)
+{
+	host_ops = ops;
+	client = msm_rpc_register_client("fsusb",
+			PM_APP_OTG_PROG,
+			PM_APP_OTG_VERS, 1,
+			msm_fsusb_cb_func);
+	if (IS_ERR(client)) {
+		pr_err("%s: couldn't open rpc client\n", __func__);
+		return PTR_ERR(client);
+	}
+
+	return 0;
+
+}
+EXPORT_SYMBOL(msm_fsusb_rpc_init);
+
+void msm_fsusb_rpc_deinit(void)
+{
+	msm_rpc_unregister_client(client);
+}
+EXPORT_SYMBOL(msm_fsusb_rpc_deinit);
diff --git a/arch/arm/mach-msm/rpc_hsusb.c b/arch/arm/mach-msm/rpc_hsusb.c
new file mode 100644
index 0000000..cd5f612
--- /dev/null
+++ b/arch/arm/mach-msm/rpc_hsusb.c
@@ -0,0 +1,660 @@
+/* linux/arch/arm/mach-msm/rpc_hsusb.c
+ *
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <mach/rpc_hsusb.h>
+#include <asm/mach-types.h>
+
+static struct msm_rpc_endpoint *usb_ep;
+static struct msm_rpc_endpoint *chg_ep;
+
+#define MSM_RPC_CHG_PROG 0x3000001a
+
+struct msm_chg_rpc_ids {
+	unsigned long	vers_comp;
+	unsigned	chg_usb_charger_connected_proc;
+	unsigned	chg_usb_charger_disconnected_proc;
+	unsigned	chg_usb_i_is_available_proc;
+	unsigned	chg_usb_i_is_not_available_proc;
+};
+
+struct msm_hsusb_rpc_ids {
+	unsigned long	prog;
+	unsigned long	vers_comp;
+	unsigned long	init_phy;
+	unsigned long	vbus_pwr_up;
+	unsigned long	vbus_pwr_down;
+	unsigned long	update_product_id;
+	unsigned long	update_serial_num;
+	unsigned long	update_is_serial_num_null;
+	unsigned long	reset_rework_installed;
+	unsigned long	enable_pmic_ulpi_data0;
+	unsigned long	disable_pmic_ulpi_data0;
+};
+
+static struct msm_hsusb_rpc_ids usb_rpc_ids;
+static struct msm_chg_rpc_ids chg_rpc_ids;
+
+static int msm_hsusb_init_rpc_ids(unsigned long vers)
+{
+	if (vers == 0x00010001) {
+		usb_rpc_ids.prog			= 0x30000064;
+		usb_rpc_ids.vers_comp			= 0x00010001;
+		usb_rpc_ids.init_phy			= 2;
+		usb_rpc_ids.vbus_pwr_up			= 6;
+		usb_rpc_ids.vbus_pwr_down		= 7;
+		usb_rpc_ids.update_product_id		= 8;
+		usb_rpc_ids.update_serial_num		= 9;
+		usb_rpc_ids.update_is_serial_num_null	= 10;
+		usb_rpc_ids.reset_rework_installed	= 17;
+		usb_rpc_ids.enable_pmic_ulpi_data0	= 18;
+		usb_rpc_ids.disable_pmic_ulpi_data0	= 19;
+		return 0;
+	} else if (vers == 0x00010002) {
+		usb_rpc_ids.prog			= 0x30000064;
+		usb_rpc_ids.vers_comp			= 0x00010002;
+		usb_rpc_ids.init_phy			= 2;
+		usb_rpc_ids.vbus_pwr_up			= 6;
+		usb_rpc_ids.vbus_pwr_down		= 7;
+		usb_rpc_ids.update_product_id		= 8;
+		usb_rpc_ids.update_serial_num		= 9;
+		usb_rpc_ids.update_is_serial_num_null	= 10;
+		usb_rpc_ids.reset_rework_installed	= 17;
+		usb_rpc_ids.enable_pmic_ulpi_data0	= 18;
+		usb_rpc_ids.disable_pmic_ulpi_data0	= 19;
+		return 0;
+	} else {
+		pr_err("%s: no matches found for version\n",
+			__func__);
+		return -ENODATA;
+	}
+}
+
+static int msm_chg_init_rpc(unsigned long vers)
+{
+	if (((vers & RPC_VERSION_MAJOR_MASK) == 0x00010000) ||
+	    ((vers & RPC_VERSION_MAJOR_MASK) == 0x00020000) ||
+	    ((vers & RPC_VERSION_MAJOR_MASK) == 0x00030000) ||
+	    ((vers & RPC_VERSION_MAJOR_MASK) == 0x00040000)) {
+		chg_ep = msm_rpc_connect_compatible(MSM_RPC_CHG_PROG, vers,
+						     MSM_RPC_UNINTERRUPTIBLE);
+		if (IS_ERR(chg_ep))
+			return -ENODATA;
+		chg_rpc_ids.vers_comp				= vers;
+		chg_rpc_ids.chg_usb_charger_connected_proc 	= 7;
+		chg_rpc_ids.chg_usb_charger_disconnected_proc 	= 8;
+		chg_rpc_ids.chg_usb_i_is_available_proc 	= 9;
+		chg_rpc_ids.chg_usb_i_is_not_available_proc 	= 10;
+		return 0;
+	} else
+		return -ENODATA;
+}
+
+/* rpc connect for hsusb */
+int msm_hsusb_rpc_connect(void)
+{
+
+	if (usb_ep && !IS_ERR(usb_ep)) {
+		pr_debug("%s: usb_ep already connected\n", __func__);
+		return 0;
+	}
+
+	/* Initialize rpc ids */
+	if (msm_hsusb_init_rpc_ids(0x00010001)) {
+		pr_err("%s: rpc ids initialization failed\n"
+			, __func__);
+		return -ENODATA;
+	}
+
+	usb_ep = msm_rpc_connect_compatible(usb_rpc_ids.prog,
+					usb_rpc_ids.vers_comp,
+					MSM_RPC_UNINTERRUPTIBLE);
+
+	if (IS_ERR(usb_ep)) {
+		pr_err("%s: connect compatible failed vers = %lx\n",
+			 __func__, usb_rpc_ids.vers_comp);
+
+		/* Initialize rpc ids */
+		if (msm_hsusb_init_rpc_ids(0x00010002)) {
+			pr_err("%s: rpc ids initialization failed\n",
+				__func__);
+			return -ENODATA;
+		}
+		usb_ep = msm_rpc_connect_compatible(usb_rpc_ids.prog,
+					usb_rpc_ids.vers_comp,
+					MSM_RPC_UNINTERRUPTIBLE);
+	}
+
+	if (IS_ERR(usb_ep)) {
+		pr_err("%s: connect compatible failed vers = %lx\n",
+				__func__, usb_rpc_ids.vers_comp);
+		return -EAGAIN;
+	} else
+		pr_debug("%s: rpc connect success vers = %lx\n",
+				__func__, usb_rpc_ids.vers_comp);
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_hsusb_rpc_connect);
+
+/* rpc connect for charging */
+int msm_chg_rpc_connect(void)
+{
+	uint32_t chg_vers;
+
+	if (machine_is_msm7x27_surf() || machine_is_qsd8x50_surf())
+		return -ENOTSUPP;
+
+	if (chg_ep && !IS_ERR(chg_ep)) {
+		pr_debug("%s: chg_ep already connected\n", __func__);
+		return 0;
+	}
+
+	chg_vers = 0x00040001;
+	if (!msm_chg_init_rpc(chg_vers))
+		goto chg_found;
+
+	chg_vers = 0x00030001;
+	if (!msm_chg_init_rpc(chg_vers))
+		goto chg_found;
+
+	chg_vers = 0x00020001;
+	if (!msm_chg_init_rpc(chg_vers))
+		goto chg_found;
+
+	chg_vers = 0x00010001;
+	if (!msm_chg_init_rpc(chg_vers))
+		goto chg_found;
+
+	pr_err("%s: connect compatible failed \n",
+			__func__);
+	return -EAGAIN;
+
+chg_found:
+	pr_debug("%s: connected to rpc vers = %x\n",
+			__func__, chg_vers);
+	return 0;
+}
+EXPORT_SYMBOL(msm_chg_rpc_connect);
+
+/* rpc call for phy_reset */
+int msm_hsusb_phy_reset(void)
+{
+	int rc = 0;
+	struct hsusb_phy_start_req {
+		struct rpc_request_hdr hdr;
+	} req;
+
+	if (!usb_ep || IS_ERR(usb_ep)) {
+		pr_err("%s: phy_reset rpc failed before call,"
+			"rc = %ld\n", __func__, PTR_ERR(usb_ep));
+		return -EAGAIN;
+	}
+
+	rc = msm_rpc_call(usb_ep, usb_rpc_ids.init_phy,
+				&req, sizeof(req), 5 * HZ);
+
+	if (rc < 0) {
+		pr_err("%s: phy_reset rpc failed! rc = %d\n",
+			__func__, rc);
+	} else
+		pr_debug("msm_hsusb_phy_reset\n");
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_hsusb_phy_reset);
+
+/* rpc call for vbus powerup */
+int msm_hsusb_vbus_powerup(void)
+{
+	int rc = 0;
+	struct hsusb_phy_start_req {
+		struct rpc_request_hdr hdr;
+	} req;
+
+	if (!usb_ep || IS_ERR(usb_ep)) {
+		pr_err("%s: vbus_powerup rpc failed before call,"
+			"rc = %ld\n", __func__, PTR_ERR(usb_ep));
+		return -EAGAIN;
+	}
+
+	rc = msm_rpc_call(usb_ep, usb_rpc_ids.vbus_pwr_up,
+		&req, sizeof(req), 5 * HZ);
+
+	if (rc < 0) {
+		pr_err("%s: vbus_powerup failed! rc = %d\n",
+			__func__, rc);
+	} else
+		pr_debug("msm_hsusb_vbus_powerup\n");
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_hsusb_vbus_powerup);
+
+/* rpc call for vbus shutdown */
+int msm_hsusb_vbus_shutdown(void)
+{
+	int rc = 0;
+	struct hsusb_phy_start_req {
+		struct rpc_request_hdr hdr;
+	} req;
+
+	if (!usb_ep || IS_ERR(usb_ep)) {
+		pr_err("%s: vbus_shutdown rpc failed before call,"
+			"rc = %ld\n", __func__, PTR_ERR(usb_ep));
+		return -EAGAIN;
+	}
+
+	rc = msm_rpc_call(usb_ep, usb_rpc_ids.vbus_pwr_down,
+		&req, sizeof(req), 5 * HZ);
+
+	if (rc < 0) {
+		pr_err("%s: vbus_shutdown failed! rc = %d\n",
+			__func__, rc);
+	} else
+		pr_debug("msm_hsusb_vbus_shutdown\n");
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_hsusb_vbus_shutdown);
+
+int msm_hsusb_send_productID(uint32_t product_id)
+{
+	int rc = 0;
+	struct hsusb_phy_start_req {
+		struct rpc_request_hdr hdr;
+		uint32_t product_id;
+	} req;
+
+	if (!usb_ep || IS_ERR(usb_ep)) {
+		pr_err("%s: rpc connect failed: rc = %ld\n",
+			__func__, PTR_ERR(usb_ep));
+		return -EAGAIN;
+	}
+
+	req.product_id = cpu_to_be32(product_id);
+	rc = msm_rpc_call(usb_ep, usb_rpc_ids.update_product_id,
+				&req, sizeof(req),
+				5 * HZ);
+	if (rc < 0)
+		pr_err("%s: rpc call failed! error: %d\n",
+			__func__, rc);
+	else
+		pr_debug("%s: rpc call success\n" , __func__);
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_hsusb_send_productID);
+
+int msm_hsusb_send_serial_number(const char *serial_number)
+{
+	int rc = 0, serial_len, rlen;
+	struct hsusb_send_sn_req {
+		struct rpc_request_hdr hdr;
+		uint32_t length;
+		char sn[0];
+	} *req;
+
+	if (!usb_ep || IS_ERR(usb_ep)) {
+		pr_err("%s: rpc connect failed: rc = %ld\n",
+			__func__, PTR_ERR(usb_ep));
+		return -EAGAIN;
+	}
+
+	/*
+	 * USB driver passes null terminated string to us. Modem processor
+	 * expects serial number to be 32 bit aligned.
+	 */
+	serial_len  = strlen(serial_number)+1;
+	rlen = sizeof(struct rpc_request_hdr) + sizeof(uint32_t) +
+			((serial_len + 3) & ~3);
+
+	req = kmalloc(rlen, GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	req->length = cpu_to_be32(serial_len);
+	strncpy(req->sn , serial_number, serial_len);
+	rc = msm_rpc_call(usb_ep, usb_rpc_ids.update_serial_num,
+				req, rlen, 5 * HZ);
+	if (rc < 0)
+		pr_err("%s: rpc call failed! error: %d\n",
+			__func__, rc);
+	else
+		pr_debug("%s: rpc call success\n", __func__);
+
+	kfree(req);
+	return rc;
+}
+EXPORT_SYMBOL(msm_hsusb_send_serial_number);
+
+int msm_hsusb_is_serial_num_null(uint32_t val)
+{
+	int rc = 0;
+	struct hsusb_phy_start_req {
+			struct rpc_request_hdr hdr;
+			uint32_t value;
+	} req;
+
+	if (!usb_ep || IS_ERR(usb_ep)) {
+		pr_err("%s: rpc connect failed: rc = %ld\n",
+			__func__, PTR_ERR(usb_ep));
+		return -EAGAIN;
+	}
+	if (!usb_rpc_ids.update_is_serial_num_null) {
+		pr_err("%s: proc id not supported \n", __func__);
+		return -ENODATA;
+	}
+
+	req.value = cpu_to_be32(val);
+	rc = msm_rpc_call(usb_ep, usb_rpc_ids.update_is_serial_num_null,
+				&req, sizeof(req),
+				5 * HZ);
+	if (rc < 0)
+		pr_err("%s: rpc call failed! error: %d\n" ,
+			__func__, rc);
+	else
+		pr_debug("%s: rpc call success\n", __func__);
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_hsusb_is_serial_num_null);
+
+int msm_chg_usb_charger_connected(uint32_t device)
+{
+	int rc = 0;
+	struct hsusb_start_req {
+		struct rpc_request_hdr hdr;
+		uint32_t otg_dev;
+	} req;
+
+	if (!chg_ep || IS_ERR(chg_ep))
+		return -EAGAIN;
+	req.otg_dev = cpu_to_be32(device);
+	rc = msm_rpc_call(chg_ep, chg_rpc_ids.chg_usb_charger_connected_proc,
+			&req, sizeof(req), 5 * HZ);
+
+	if (rc < 0) {
+		pr_err("%s: charger_connected failed! rc = %d\n",
+			__func__, rc);
+	} else
+		pr_debug("msm_chg_usb_charger_connected\n");
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_chg_usb_charger_connected);
+
+int msm_chg_usb_i_is_available(uint32_t sample)
+{
+	int rc = 0;
+	struct hsusb_start_req {
+		struct rpc_request_hdr hdr;
+		uint32_t i_ma;
+	} req;
+
+	if (!chg_ep || IS_ERR(chg_ep))
+		return -EAGAIN;
+	req.i_ma = cpu_to_be32(sample);
+	rc = msm_rpc_call(chg_ep, chg_rpc_ids.chg_usb_i_is_available_proc,
+			&req, sizeof(req), 5 * HZ);
+
+	if (rc < 0) {
+		pr_err("%s: charger_i_available failed! rc = %d\n",
+			__func__, rc);
+	} else
+		pr_debug("msm_chg_usb_i_is_available(%u)\n", sample);
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_chg_usb_i_is_available);
+
+int msm_chg_usb_i_is_not_available(void)
+{
+	int rc = 0;
+	struct hsusb_start_req {
+		struct rpc_request_hdr hdr;
+	} req;
+
+	if (!chg_ep || IS_ERR(chg_ep))
+		return -EAGAIN;
+	rc = msm_rpc_call(chg_ep, chg_rpc_ids.chg_usb_i_is_not_available_proc,
+			&req, sizeof(req), 5 * HZ);
+
+	if (rc < 0) {
+		pr_err("%s: charger_i_not_available failed! rc ="
+			"%d \n", __func__, rc);
+	} else
+		pr_debug("msm_chg_usb_i_is_not_available\n");
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_chg_usb_i_is_not_available);
+
+int msm_chg_usb_charger_disconnected(void)
+{
+	int rc = 0;
+	struct hsusb_start_req {
+		struct rpc_request_hdr hdr;
+	} req;
+
+	if (!chg_ep || IS_ERR(chg_ep))
+		return -EAGAIN;
+	rc = msm_rpc_call(chg_ep, chg_rpc_ids.chg_usb_charger_disconnected_proc,
+			&req, sizeof(req), 5 * HZ);
+
+	if (rc < 0) {
+		pr_err("%s: charger_disconnected failed! rc = %d\n",
+			__func__, rc);
+	} else
+		pr_debug("msm_chg_usb_charger_disconnected\n");
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_chg_usb_charger_disconnected);
+
+/* rpc call to close connection */
+int msm_hsusb_rpc_close(void)
+{
+	int rc = 0;
+
+	if (IS_ERR(usb_ep)) {
+		pr_err("%s: rpc_close failed before call, rc = %ld\n",
+			__func__, PTR_ERR(usb_ep));
+		return -EAGAIN;
+	}
+
+	rc = msm_rpc_close(usb_ep);
+	usb_ep = NULL;
+
+	if (rc < 0) {
+		pr_err("%s: close rpc failed! rc = %d\n",
+			__func__, rc);
+		return -EAGAIN;
+	} else
+		pr_debug("rpc close success\n");
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_hsusb_rpc_close);
+
+/* rpc call to close charging connection */
+int msm_chg_rpc_close(void)
+{
+	int rc = 0;
+
+	if (IS_ERR(chg_ep)) {
+		pr_err("%s: rpc_close failed before call, rc = %ld\n",
+			__func__, PTR_ERR(chg_ep));
+		return -EAGAIN;
+	}
+
+	rc = msm_rpc_close(chg_ep);
+	chg_ep = NULL;
+
+	if (rc < 0) {
+		pr_err("%s: close rpc failed! rc = %d\n",
+			__func__, rc);
+		return -EAGAIN;
+	} else
+		pr_debug("rpc close success\n");
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_chg_rpc_close);
+
+int msm_hsusb_reset_rework_installed(void)
+{
+	int rc = 0;
+	struct hsusb_start_req {
+		struct rpc_request_hdr hdr;
+	} req;
+	struct hsusb_rpc_rep {
+		struct rpc_reply_hdr hdr;
+		uint32_t rework;
+	} rep;
+
+	memset(&rep, 0, sizeof(rep));
+
+	if (!usb_ep || IS_ERR(usb_ep)) {
+		pr_err("%s: hsusb rpc connection not initialized, rc = %ld\n",
+			__func__, PTR_ERR(usb_ep));
+		return -EAGAIN;
+	}
+
+	rc = msm_rpc_call_reply(usb_ep, usb_rpc_ids.reset_rework_installed,
+				&req, sizeof(req),
+				&rep, sizeof(rep), 5 * HZ);
+
+	if (rc < 0) {
+		pr_err("%s: rpc call failed! error: (%d)"
+				"proc id: (%lx)\n",
+				__func__, rc,
+				usb_rpc_ids.reset_rework_installed);
+		return rc;
+	}
+
+	pr_info("%s: rework: (%d)\n", __func__, rep.rework);
+	return be32_to_cpu(rep.rework);
+}
+EXPORT_SYMBOL(msm_hsusb_reset_rework_installed);
+
+static int msm_hsusb_pmic_ulpidata0_config(int enable)
+{
+	int rc = 0;
+	struct hsusb_start_req {
+		struct rpc_request_hdr hdr;
+	} req;
+
+	if (!usb_ep || IS_ERR(usb_ep)) {
+		pr_err("%s: hsusb rpc connection not initialized, rc = %ld\n",
+			__func__, PTR_ERR(usb_ep));
+		return -EAGAIN;
+	}
+
+	if (enable)
+		rc = msm_rpc_call(usb_ep, usb_rpc_ids.enable_pmic_ulpi_data0,
+					&req, sizeof(req), 5 * HZ);
+	else
+		rc = msm_rpc_call(usb_ep, usb_rpc_ids.disable_pmic_ulpi_data0,
+					&req, sizeof(req), 5 * HZ);
+
+	if (rc < 0)
+		pr_err("%s: rpc call failed! error: %d\n",
+				__func__, rc);
+	return rc;
+}
+
+int msm_hsusb_enable_pmic_ulpidata0(void)
+{
+	return msm_hsusb_pmic_ulpidata0_config(1);
+}
+EXPORT_SYMBOL(msm_hsusb_enable_pmic_ulpidata0);
+
+int msm_hsusb_disable_pmic_ulpidata0(void)
+{
+	return msm_hsusb_pmic_ulpidata0_config(0);
+}
+EXPORT_SYMBOL(msm_hsusb_disable_pmic_ulpidata0);
+
+
+/* wrapper for sending pid and serial# info to bootloader */
+int usb_diag_update_pid_and_serial_num(uint32_t pid, const char *snum)
+{
+	int ret;
+
+	ret = msm_hsusb_send_productID(pid);
+	if (ret)
+		return ret;
+
+	if (!snum) {
+		ret = msm_hsusb_is_serial_num_null(1);
+		if (ret)
+			return ret;
+	}
+
+	ret = msm_hsusb_is_serial_num_null(0);
+	if (ret)
+		return ret;
+	ret = msm_hsusb_send_serial_number(snum);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+
+#ifdef CONFIG_USB_MSM_72K
+/* charger api wrappers */
+int hsusb_chg_init(int connect)
+{
+	if (connect)
+		return msm_chg_rpc_connect();
+	else
+		return msm_chg_rpc_close();
+}
+EXPORT_SYMBOL(hsusb_chg_init);
+
+void hsusb_chg_vbus_draw(unsigned mA)
+{
+	msm_chg_usb_i_is_available(mA);
+}
+EXPORT_SYMBOL(hsusb_chg_vbus_draw);
+
+void hsusb_chg_connected(enum chg_type chgtype)
+{
+	char *chg_types[] = {"STD DOWNSTREAM PORT",
+			"CARKIT",
+			"DEDICATED CHARGER",
+			"INVALID"};
+
+	if (chgtype == USB_CHG_TYPE__INVALID) {
+		msm_chg_usb_i_is_not_available();
+		msm_chg_usb_charger_disconnected();
+		return;
+	}
+
+	pr_info("\nCharger Type: %s\n", chg_types[chgtype]);
+
+	msm_chg_usb_charger_connected(chgtype);
+}
+EXPORT_SYMBOL(hsusb_chg_connected);
+#endif
diff --git a/arch/arm/mach-msm/rpc_pmapp.c b/arch/arm/mach-msm/rpc_pmapp.c
new file mode 100644
index 0000000..0828bb4
--- /dev/null
+++ b/arch/arm/mach-msm/rpc_pmapp.c
@@ -0,0 +1,577 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <asm/mach-types.h>
+#include <mach/board.h>
+#include <mach/rpc_pmapp.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/vreg.h>
+
+#define PMAPP_RPC_PROG			0x30000060
+#define PMAPP_RPC_VER_1_1		0x00010001
+#define PMAPP_RPC_VER_1_2		0x00010002
+#define PMAPP_RPC_VER_2_1		0x00020001
+#define PMAPP_RPC_VER_3_1		0x00030001
+#define PMAPP_RPC_VER_5_1		0x00050001
+#define PMAPP_RPC_VER_6_1		0x00060001
+#define PMAPP_RPC_VER_7_1		0x00070001
+
+#define VBUS_SESS_VALID_CB_PROC			1
+#define PM_VOTE_USB_PWR_SEL_SWITCH_APP__HSUSB 	(1 << 2)
+#define PM_USB_PWR_SEL_SWITCH_ID 		0
+
+#define PMAPP_RPC_TIMEOUT (5*HZ)
+
+#define PMAPP_DISPLAY_CLOCK_CONFIG_PROC		21
+#define PMAPP_VREG_LEVEL_VOTE_PROC		23
+#define PMAPP_SMPS_CLOCK_VOTE_PROC		26
+#define PMAPP_CLOCK_VOTE_PROC			27
+#define PMAPP_SMPS_MODE_VOTE_PROC		28
+#define PMAPP_VREG_PINCNTRL_VOTE_PROC		30
+#define PMAPP_DISP_BACKLIGHT_SET_PROC		31
+#define PMAPP_DISP_BACKLIGHT_INIT_PROC		32
+#define PMAPP_VREG_LPM_PINCNTRL_VOTE_PROC	34
+
+/* Clock voter name max length */
+#define PMAPP_CLOCK_VOTER_ID_LEN		4
+
+struct rpc_pmapp_ids {
+	unsigned long	reg_for_vbus_valid;
+	unsigned long	vote_for_vbus_valid_switch;
+};
+
+static struct rpc_pmapp_ids rpc_ids;
+static struct msm_rpc_client *client;
+
+/* Add newer versions at the top of array */
+static const unsigned int rpc_vers[] = {
+	PMAPP_RPC_VER_7_1,
+	PMAPP_RPC_VER_6_1,
+	PMAPP_RPC_VER_5_1,
+	PMAPP_RPC_VER_3_1,
+	PMAPP_RPC_VER_2_1,
+};
+
+static void rpc_pmapp_init_rpc_ids(unsigned long vers)
+{
+	if (vers == PMAPP_RPC_VER_1_1) {
+		rpc_ids.reg_for_vbus_valid		= 5;
+		rpc_ids.vote_for_vbus_valid_switch	= 6;
+	} else if (vers == PMAPP_RPC_VER_1_2) {
+		rpc_ids.reg_for_vbus_valid		= 16;
+		rpc_ids.vote_for_vbus_valid_switch	= 17;
+	} else if (vers == PMAPP_RPC_VER_2_1) {
+		rpc_ids.reg_for_vbus_valid		= 0; /* NA */
+		rpc_ids.vote_for_vbus_valid_switch	= 0; /* NA */
+	}
+}
+
+struct usb_pwr_sel_switch_args {
+	uint32_t cmd;
+	uint32_t switch_id;
+	uint32_t app_mask;
+};
+
+static int usb_pwr_sel_switch_arg_cb(struct msm_rpc_client *client,
+					void *buf, void *data)
+{
+	struct usb_pwr_sel_switch_args *args = buf;
+
+	args->cmd = cpu_to_be32(*(uint32_t *)data);
+	args->switch_id = cpu_to_be32(PM_USB_PWR_SEL_SWITCH_ID);
+	args->app_mask = cpu_to_be32(PM_VOTE_USB_PWR_SEL_SWITCH_APP__HSUSB);
+	return sizeof(struct usb_pwr_sel_switch_args);
+}
+
+static int msm_pm_app_vote_usb_pwr_sel_switch(uint32_t cmd)
+{
+	return msm_rpc_client_req(client,
+			rpc_ids.vote_for_vbus_valid_switch,
+			usb_pwr_sel_switch_arg_cb,
+			&cmd, NULL, NULL, -1);
+}
+
+struct vbus_sess_valid_args {
+	uint32_t cb_id;
+};
+
+static int vbus_sess_valid_arg_cb(struct msm_rpc_client *client,
+					void *buf, void *data)
+{
+	struct vbus_sess_valid_args *args = buf;
+
+	args->cb_id = cpu_to_be32(*(uint32_t *)data);
+	return sizeof(struct vbus_sess_valid_args);
+}
+
+
+int pmic_vote_3p3_pwr_sel_switch(int boost)
+{
+	int ret;
+
+	ret = msm_pm_app_vote_usb_pwr_sel_switch(boost);
+
+	return ret;
+}
+EXPORT_SYMBOL(pmic_vote_3p3_pwr_sel_switch);
+
+struct vbus_sn_notification_args {
+	uint32_t cb_id;
+	uint32_t vbus; /* vbus = 0 if VBUS is present */
+};
+
+static int vbus_notification_cb(struct msm_rpc_client *client,
+				void *buffer, int in_size)
+{
+	struct vbus_sn_notification_args *args;
+	struct rpc_request_hdr *req = buffer;
+	int rc;
+	uint32_t accept_status;
+	void (*cb_func)(int);
+	uint32_t cb_id;
+	int vbus;
+
+	args = (struct vbus_sn_notification_args *) (req + 1);
+	cb_id = be32_to_cpu(args->cb_id);
+	vbus = be32_to_cpu(args->vbus);
+
+	cb_func = msm_rpc_get_cb_func(client, cb_id);
+	if (cb_func) {
+		cb_func(!vbus);
+		accept_status = RPC_ACCEPTSTAT_SUCCESS;
+	} else
+		accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
+
+	msm_rpc_start_accepted_reply(client, be32_to_cpu(req->xid),
+				     accept_status);
+	rc = msm_rpc_send_accepted_reply(client, 0);
+	if (rc)
+		pr_err("%s: send accepted reply failed: %d\n", __func__, rc);
+
+	return rc;
+}
+
+static int pm_app_usb_cb_func(struct msm_rpc_client *client,
+				void *buffer, int in_size)
+{
+	int rc;
+	struct rpc_request_hdr *req = buffer;
+
+	switch (be32_to_cpu(req->procedure)) {
+	case VBUS_SESS_VALID_CB_PROC:
+		rc = vbus_notification_cb(client, buffer, in_size);
+		break;
+	default:
+		pr_err("%s: procedure not supported %d\n", __func__,
+		       be32_to_cpu(req->procedure));
+		msm_rpc_start_accepted_reply(client, be32_to_cpu(req->xid),
+					     RPC_ACCEPTSTAT_PROC_UNAVAIL);
+		rc = msm_rpc_send_accepted_reply(client, 0);
+		if (rc)
+			pr_err("%s: sending reply failed: %d\n", __func__, rc);
+		break;
+	}
+	return rc;
+}
+
+int msm_pm_app_rpc_init(void (*callback)(int online))
+{
+	uint32_t cb_id, rc;
+
+	if (!machine_is_qsd8x50_ffa() && !machine_is_msm7x27_ffa())
+		return -ENOTSUPP;
+
+	client = msm_rpc_register_client("pmapp_usb",
+			PMAPP_RPC_PROG,
+			PMAPP_RPC_VER_2_1, 1,
+			pm_app_usb_cb_func);
+	if (!IS_ERR(client)) {
+		rpc_pmapp_init_rpc_ids(PMAPP_RPC_VER_2_1);
+		goto done;
+	}
+
+	client = msm_rpc_register_client("pmapp_usb",
+			PMAPP_RPC_PROG,
+			PMAPP_RPC_VER_1_2, 1,
+			pm_app_usb_cb_func);
+	if (!IS_ERR(client)) {
+		rpc_pmapp_init_rpc_ids(PMAPP_RPC_VER_1_2);
+		goto done;
+	}
+
+	client = msm_rpc_register_client("pmapp_usb",
+			PMAPP_RPC_PROG,
+			PMAPP_RPC_VER_1_1, 1,
+			pm_app_usb_cb_func);
+	if (!IS_ERR(client))
+		rpc_pmapp_init_rpc_ids(PMAPP_RPC_VER_1_1);
+	else
+		return PTR_ERR(client);
+
+done:
+	cb_id = msm_rpc_add_cb_func(client, (void *)callback);
+	/* In case of NULL callback funtion, cb_id would be -1 */
+	if ((int) cb_id < -1)
+		return cb_id;
+	rc =  msm_rpc_client_req(client,
+		rpc_ids.reg_for_vbus_valid,
+			vbus_sess_valid_arg_cb,
+				&cb_id, NULL, NULL, -1);
+	return rc;
+}
+EXPORT_SYMBOL(msm_pm_app_rpc_init);
+
+void msm_pm_app_rpc_deinit(void(*callback)(int online))
+{
+	if (client) {
+		msm_rpc_remove_cb_func(client, (void *)callback);
+		msm_rpc_unregister_client(client);
+	}
+}
+EXPORT_SYMBOL(msm_pm_app_rpc_deinit);
+
+/* error bit flags defined by modem side */
+#define PM_ERR_FLAG__PAR1_OUT_OF_RANGE		(0x0001)
+#define PM_ERR_FLAG__PAR2_OUT_OF_RANGE		(0x0002)
+#define PM_ERR_FLAG__PAR3_OUT_OF_RANGE		(0x0004)
+#define PM_ERR_FLAG__PAR4_OUT_OF_RANGE		(0x0008)
+#define PM_ERR_FLAG__PAR5_OUT_OF_RANGE		(0x0010)
+
+#define PM_ERR_FLAG__ALL_PARMS_OUT_OF_RANGE   	(0x001F) /* all 5 previous */
+
+#define PM_ERR_FLAG__SBI_OPT_ERR		(0x0080)
+#define PM_ERR_FLAG__FEATURE_NOT_SUPPORTED	(0x0100)
+
+#define	PMAPP_BUFF_SIZE		256
+
+struct pmapp_buf {
+	char *start;		/* buffer start addr */
+	char *end;		/* buffer end addr */
+	int size;		/* buffer size */
+	char *data;		/* payload begin addr */
+	int len;		/* payload len */
+};
+
+static DEFINE_MUTEX(pmapp_mtx);
+
+struct pmapp_ctrl {
+	int inited;
+	struct pmapp_buf tbuf;
+	struct pmapp_buf rbuf;
+	struct msm_rpc_endpoint *endpoint;
+};
+
+static struct pmapp_ctrl pmapp_ctrl = {
+	.inited = -1,
+};
+
+
+static int pmapp_rpc_set_only(uint data0, uint data1, uint data2,
+				uint data3, int num, int proc);
+
+static int pmapp_buf_init(void)
+{
+	struct pmapp_ctrl *pm = &pmapp_ctrl;
+
+	memset(&pmapp_ctrl, 0, sizeof(pmapp_ctrl));
+
+	pm->tbuf.start = kmalloc(PMAPP_BUFF_SIZE, GFP_KERNEL);
+	if (pm->tbuf.start == NULL) {
+		printk(KERN_ERR "%s:%u\n", __func__, __LINE__);
+		return -ENOMEM;
+	}
+
+	pm->tbuf.data = pm->tbuf.start;
+	pm->tbuf.size = PMAPP_BUFF_SIZE;
+	pm->tbuf.end = pm->tbuf.start + PMAPP_BUFF_SIZE;
+	pm->tbuf.len = 0;
+
+	pm->rbuf.start = kmalloc(PMAPP_BUFF_SIZE, GFP_KERNEL);
+	if (pm->rbuf.start == NULL) {
+		kfree(pm->tbuf.start);
+		printk(KERN_ERR "%s:%u\n", __func__, __LINE__);
+		return -ENOMEM;
+	}
+	pm->rbuf.data = pm->rbuf.start;
+	pm->rbuf.size = PMAPP_BUFF_SIZE;
+	pm->rbuf.end = pm->rbuf.start + PMAPP_BUFF_SIZE;
+	pm->rbuf.len = 0;
+
+	pm->inited = 1;
+
+	return 0;
+}
+
+static inline void pmapp_buf_reserve(struct pmapp_buf *bp, int len)
+{
+	bp->data += len;
+}
+
+static inline void pmapp_buf_reset(struct pmapp_buf *bp)
+{
+	bp->data = bp->start;
+	bp->len = 0;
+}
+
+static int modem_to_linux_err(uint err)
+{
+	if (err == 0)
+		return 0;
+
+	if (err & PM_ERR_FLAG__ALL_PARMS_OUT_OF_RANGE)
+		return -EINVAL;	/* PM_ERR_FLAG__PAR[1..5]_OUT_OF_RANGE */
+
+	if (err & PM_ERR_FLAG__SBI_OPT_ERR)
+		return -EIO;
+
+	if (err & PM_ERR_FLAG__FEATURE_NOT_SUPPORTED)
+		return -ENOSYS;
+
+	return -EPERM;
+}
+
+static int pmapp_put_tx_data(struct pmapp_buf *tp, uint datav)
+{
+	uint *lp;
+
+	if ((tp->size - tp->len) < sizeof(datav)) {
+		printk(KERN_ERR "%s: OVERFLOW size=%d len=%d\n",
+					__func__, tp->size, tp->len);
+		return -1;
+	}
+
+	lp = (uint *)tp->data;
+	*lp = cpu_to_be32(datav);
+	tp->data += sizeof(datav);
+	tp->len += sizeof(datav);
+
+	return sizeof(datav);
+}
+
+static int pmapp_pull_rx_data(struct pmapp_buf *rp, uint *datap)
+{
+	uint *lp;
+
+	if (rp->len < sizeof(*datap)) {
+		printk(KERN_ERR "%s: UNDERRUN len=%d\n", __func__, rp->len);
+		return -1;
+	}
+	lp = (uint *)rp->data;
+	*datap = be32_to_cpu(*lp);
+	rp->data += sizeof(*datap);
+	rp->len -= sizeof(*datap);
+
+	return sizeof(*datap);
+}
+
+
+static int pmapp_rpc_req_reply(struct pmapp_buf *tbuf, struct pmapp_buf *rbuf,
+	int	proc)
+{
+	struct pmapp_ctrl *pm = &pmapp_ctrl;
+	int	ans, len, i;
+
+
+	if ((pm->endpoint == NULL) || IS_ERR(pm->endpoint)) {
+		for (i = 0; i < ARRAY_SIZE(rpc_vers); i++) {
+			pm->endpoint = msm_rpc_connect_compatible(
+					PMAPP_RPC_PROG,	rpc_vers[i], 0);
+
+			if (IS_ERR(pm->endpoint)) {
+				ans  = PTR_ERR(pm->endpoint);
+				printk(KERN_ERR "%s: init rpc failed! ans = %d"
+						" for 0x%x version, fallback\n",
+						__func__, ans, rpc_vers[i]);
+			} else {
+				printk(KERN_DEBUG "%s: successfully connected"
+					" to 0x%x rpc version\n",
+					 __func__, rpc_vers[i]);
+				break;
+			}
+		}
+	}
+
+	if (IS_ERR(pm->endpoint)) {
+		ans  = PTR_ERR(pm->endpoint);
+		return ans;
+	}
+
+	/*
+	* data is point to next available space at this moment,
+	* move it back to beginning of request header and increase
+	* the length
+	*/
+	tbuf->data = tbuf->start;
+	tbuf->len += sizeof(struct rpc_request_hdr);
+
+	len = msm_rpc_call_reply(pm->endpoint, proc,
+				tbuf->data, tbuf->len,
+				rbuf->data, rbuf->size,
+				PMAPP_RPC_TIMEOUT);
+
+	if (len <= 0) {
+		printk(KERN_ERR "%s: rpc failed! len = %d\n", __func__, len);
+		pm->endpoint = NULL;	/* re-connect later ? */
+		return len;
+	}
+
+	rbuf->len = len;
+	/* strip off rpc_reply_hdr */
+	rbuf->data += sizeof(struct rpc_reply_hdr);
+	rbuf->len -= sizeof(struct rpc_reply_hdr);
+
+	return rbuf->len;
+}
+
+static int pmapp_rpc_set_only(uint data0, uint data1, uint data2, uint data3,
+		int num, int proc)
+{
+	struct pmapp_ctrl *pm = &pmapp_ctrl;
+	struct pmapp_buf	*tp;
+	struct pmapp_buf	*rp;
+	int	stat;
+
+
+	if (mutex_lock_interruptible(&pmapp_mtx))
+		return -ERESTARTSYS;
+
+	if (pm->inited <= 0) {
+		stat = pmapp_buf_init();
+		if (stat < 0) {
+			mutex_unlock(&pmapp_mtx);
+			return stat;
+		}
+	}
+
+	tp = &pm->tbuf;
+	rp = &pm->rbuf;
+
+	pmapp_buf_reset(tp);
+	pmapp_buf_reserve(tp, sizeof(struct rpc_request_hdr));
+	pmapp_buf_reset(rp);
+
+	if (num > 0)
+		pmapp_put_tx_data(tp, data0);
+
+	if (num > 1)
+		pmapp_put_tx_data(tp, data1);
+
+	if (num > 2)
+		pmapp_put_tx_data(tp, data2);
+
+	if (num > 3)
+		pmapp_put_tx_data(tp, data3);
+
+	stat = pmapp_rpc_req_reply(tp, rp, proc);
+	if (stat < 0) {
+		mutex_unlock(&pmapp_mtx);
+		return stat;
+	}
+
+	pmapp_pull_rx_data(rp, &stat);	/* result from server */
+
+	mutex_unlock(&pmapp_mtx);
+
+	return modem_to_linux_err(stat);
+}
+
+int pmapp_display_clock_config(uint enable)
+{
+	return pmapp_rpc_set_only(enable, 0, 0, 0, 1,
+			PMAPP_DISPLAY_CLOCK_CONFIG_PROC);
+}
+EXPORT_SYMBOL(pmapp_display_clock_config);
+
+int pmapp_clock_vote(const char *voter_id, uint clock_id, uint vote)
+{
+	if (strlen(voter_id) != PMAPP_CLOCK_VOTER_ID_LEN)
+		return -EINVAL;
+
+	return pmapp_rpc_set_only(*((uint *) voter_id), clock_id, vote, 0, 3,
+			PMAPP_CLOCK_VOTE_PROC);
+}
+EXPORT_SYMBOL(pmapp_clock_vote);
+
+int pmapp_smps_clock_vote(const char *voter_id, uint vreg_id, uint vote)
+{
+	if (strlen(voter_id) != PMAPP_CLOCK_VOTER_ID_LEN)
+		return -EINVAL;
+
+	return pmapp_rpc_set_only(*((uint *) voter_id), vreg_id, vote, 0, 3,
+				  PMAPP_SMPS_CLOCK_VOTE_PROC);
+}
+EXPORT_SYMBOL(pmapp_smps_clock_vote);
+
+int pmapp_vreg_level_vote(const char *voter_id, uint vreg_id, uint level)
+{
+	if (strlen(voter_id) != PMAPP_CLOCK_VOTER_ID_LEN)
+		return -EINVAL;
+
+	return pmapp_rpc_set_only(*((uint *) voter_id), vreg_id, level, 0, 3,
+				  PMAPP_VREG_LEVEL_VOTE_PROC);
+}
+EXPORT_SYMBOL(pmapp_vreg_level_vote);
+
+int pmapp_smps_mode_vote(const char *voter_id, uint vreg_id, uint mode)
+{
+	if (strlen(voter_id) != PMAPP_CLOCK_VOTER_ID_LEN)
+		return -EINVAL;
+
+	return pmapp_rpc_set_only(*((uint *) voter_id), vreg_id, mode, 0, 3,
+				  PMAPP_SMPS_MODE_VOTE_PROC);
+}
+EXPORT_SYMBOL(pmapp_smps_mode_vote);
+
+int pmapp_vreg_pincntrl_vote(const char *voter_id, uint vreg_id,
+						uint clock_id, uint vote)
+{
+	if (strlen(voter_id) != PMAPP_CLOCK_VOTER_ID_LEN)
+		return -EINVAL;
+
+	return pmapp_rpc_set_only(*((uint *) voter_id), vreg_id, clock_id,
+					vote, 4,
+					PMAPP_VREG_PINCNTRL_VOTE_PROC);
+}
+EXPORT_SYMBOL(pmapp_vreg_pincntrl_vote);
+
+int pmapp_disp_backlight_set_brightness(int value)
+{
+	if (value < 0 || value > 255)
+		return -EINVAL;
+
+	return pmapp_rpc_set_only(value, 0, 0, 0, 1,
+				PMAPP_DISP_BACKLIGHT_SET_PROC);
+}
+EXPORT_SYMBOL(pmapp_disp_backlight_set_brightness);
+
+void pmapp_disp_backlight_init(void)
+{
+	pmapp_rpc_set_only(0, 0, 0, 0, 0, PMAPP_DISP_BACKLIGHT_INIT_PROC);
+}
+EXPORT_SYMBOL(pmapp_disp_backlight_init);
+
+int pmapp_vreg_lpm_pincntrl_vote(const char *voter_id, uint vreg_id,
+						uint clock_id, uint vote)
+{
+	if (strnlen(voter_id, PMAPP_CLOCK_VOTER_ID_LEN)
+			 != PMAPP_CLOCK_VOTER_ID_LEN)
+		return -EINVAL;
+
+	return pmapp_rpc_set_only(*((uint *) voter_id), vreg_id, clock_id,
+					vote, 4,
+					PMAPP_VREG_LPM_PINCNTRL_VOTE_PROC);
+}
+EXPORT_SYMBOL(pmapp_vreg_lpm_pincntrl_vote);
diff --git a/arch/arm/mach-msm/rpc_server_dog_keepalive.c b/arch/arm/mach-msm/rpc_server_dog_keepalive.c
new file mode 100644
index 0000000..5e0f46d
--- /dev/null
+++ b/arch/arm/mach-msm/rpc_server_dog_keepalive.c
@@ -0,0 +1,77 @@
+/* arch/arm/mach-msm/rpc_server_dog_keepalive.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ * Author: Iliyan Malchev <ibm@android.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <mach/msm_rpcrouter.h>
+
+/* dog_keepalive server definitions */
+
+#define DOG_KEEPALIVE_PROG 0x30000015
+#if CONFIG_MSM_AMSS_VERSION==6210
+#define DOG_KEEPALIVE_VERS 0
+#define RPC_DOG_KEEPALIVE_BEACON 1
+#elif (CONFIG_MSM_AMSS_VERSION==6220) || (CONFIG_MSM_AMSS_VERSION==6225)
+#define DOG_KEEPALIVE_VERS 0x731fa727
+#define RPC_DOG_KEEPALIVE_BEACON 2
+#else
+#error "Unsupported AMSS version"
+#endif
+#define DOG_KEEPALIVE_VERS_COMP 0x00010001
+#define RPC_DOG_KEEPALIVE_NULL 0
+
+
+/* TODO: Remove server registration with _VERS when modem is upated with _COMP*/
+
+static int handle_rpc_call(struct msm_rpc_server *server,
+			   struct rpc_request_hdr *req, unsigned len)
+{
+	switch (req->procedure) {
+	case RPC_DOG_KEEPALIVE_NULL:
+		return 0;
+	case RPC_DOG_KEEPALIVE_BEACON:
+		return 0;
+	default:
+		return -ENODEV;
+	}
+}
+
+static struct msm_rpc_server rpc_server[] = {
+	{
+		.prog = DOG_KEEPALIVE_PROG,
+		.vers = DOG_KEEPALIVE_VERS,
+		.rpc_call = handle_rpc_call,
+	},
+	{
+		.prog = DOG_KEEPALIVE_PROG,
+		.vers = DOG_KEEPALIVE_VERS_COMP,
+		.rpc_call = handle_rpc_call,
+	},
+};
+
+static int __init rpc_server_init(void)
+{
+	/* Dual server registration to support backwards compatibility vers */
+	int ret;
+	ret = msm_rpc_create_server(&rpc_server[1]);
+	if (ret < 0)
+		return ret;
+	return msm_rpc_create_server(&rpc_server[0]);
+}
+
+
+module_init(rpc_server_init);
diff --git a/arch/arm/mach-msm/rpc_server_handset.c b/arch/arm/mach-msm/rpc_server_handset.c
new file mode 100644
index 0000000..6d173fb
--- /dev/null
+++ b/arch/arm/mach-msm/rpc_server_handset.c
@@ -0,0 +1,707 @@
+/* arch/arm/mach-msm/rpc_server_handset.c
+ *
+ * Copyright (c) 2008-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
+ * 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/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/switch.h>
+
+#include <asm/mach-types.h>
+
+#include <mach/msm_rpcrouter.h>
+#include <mach/board.h>
+#include <mach/rpc_server_handset.h>
+
+#define DRIVER_NAME	"msm-handset"
+
+#define HS_SERVER_PROG 0x30000062
+#define HS_SERVER_VERS 0x00010001
+
+#define HS_RPC_PROG 0x30000091
+
+#define HS_PROCESS_CMD_PROC 0x02
+#define HS_SUBSCRIBE_SRVC_PROC 0x03
+#define HS_REPORT_EVNT_PROC    0x05
+#define HS_EVENT_CB_PROC	1
+#define HS_EVENT_DATA_VER	1
+
+#define RPC_KEYPAD_NULL_PROC 0
+#define RPC_KEYPAD_PASS_KEY_CODE_PROC 2
+#define RPC_KEYPAD_SET_PWR_KEY_STATE_PROC 3
+
+#define HS_PWR_K		0x6F	/* Power key */
+#define HS_END_K		0x51	/* End key or Power key */
+#define HS_STEREO_HEADSET_K	0x82
+#define HS_HEADSET_SWITCH_K	0x84
+#define HS_HEADSET_SWITCH_2_K	0xF0
+#define HS_HEADSET_SWITCH_3_K	0xF1
+#define HS_HEADSET_HEADPHONE_K	0xF6
+#define HS_HEADSET_MICROPHONE_K 0xF7
+#define HS_REL_K		0xFF	/* key release */
+
+#define SW_HEADPHONE_INSERT_W_MIC 1 /* HS with mic */
+
+#define KEY(hs_key, input_key) ((hs_key << 24) | input_key)
+
+enum hs_event {
+	HS_EVNT_EXT_PWR = 0,	/* External Power status        */
+	HS_EVNT_HSD,		/* Headset Detection            */
+	HS_EVNT_HSTD,		/* Headset Type Detection       */
+	HS_EVNT_HSSD,		/* Headset Switch Detection     */
+	HS_EVNT_KPD,
+	HS_EVNT_FLIP,		/* Flip / Clamshell status (open/close) */
+	HS_EVNT_CHARGER,	/* Battery is being charged or not */
+	HS_EVNT_ENV,		/* Events from runtime environment like DEM */
+	HS_EVNT_REM,		/* Events received from HS counterpart on a
+				remote processor*/
+	HS_EVNT_DIAG,		/* Diag Events  */
+	HS_EVNT_LAST,		 /* Should always be the last event type */
+	HS_EVNT_MAX		/* Force enum to be an 32-bit number */
+};
+
+enum hs_src_state {
+	HS_SRC_STATE_UNKWN = 0,
+	HS_SRC_STATE_LO,
+	HS_SRC_STATE_HI,
+};
+
+struct hs_event_data {
+	uint32_t	ver;		/* Version number */
+	enum hs_event	event_type;     /* Event Type	*/
+	enum hs_event	enum_disc;     /* discriminator */
+	uint32_t	data_length;	/* length of the next field */
+	enum hs_src_state	data;    /* Pointer to data */
+	uint32_t	data_size;	/* Elements to be processed in data */
+};
+
+enum hs_return_value {
+	HS_EKPDLOCKED     = -2,	/* Operation failed because keypad is locked */
+	HS_ENOTSUPPORTED  = -1,	/* Functionality not supported */
+	HS_FALSE          =  0, /* Inquired condition is not true */
+	HS_FAILURE        =  0, /* Requested operation was not successful */
+	HS_TRUE           =  1, /* Inquired condition is true */
+	HS_SUCCESS        =  1, /* Requested operation was successful */
+	HS_MAX_RETURN     =  0x7FFFFFFF/* Force enum to be a 32 bit number */
+};
+
+struct hs_key_data {
+	uint32_t ver;        /* Version number to track sturcture changes */
+	uint32_t code;       /* which key? */
+	uint32_t parm;       /* key status. Up/down or pressed/released */
+};
+
+enum hs_subs_srvc {
+	HS_SUBS_SEND_CMD = 0, /* Subscribe to send commands to HS */
+	HS_SUBS_RCV_EVNT,     /* Subscribe to receive Events from HS */
+	HS_SUBS_SRVC_MAX
+};
+
+enum hs_subs_req {
+	HS_SUBS_REGISTER,    /* Subscribe   */
+	HS_SUBS_CANCEL,      /* Unsubscribe */
+	HS_SUB_STATUS_MAX
+};
+
+enum hs_event_class {
+	HS_EVNT_CLASS_ALL = 0, /* All HS events */
+	HS_EVNT_CLASS_LAST,    /* Should always be the last class type   */
+	HS_EVNT_CLASS_MAX
+};
+
+enum hs_cmd_class {
+	HS_CMD_CLASS_LCD = 0, /* Send LCD related commands              */
+	HS_CMD_CLASS_KPD,     /* Send KPD related commands              */
+	HS_CMD_CLASS_LAST,    /* Should always be the last class type   */
+	HS_CMD_CLASS_MAX
+};
+
+/*
+ * Receive events or send command
+ */
+union hs_subs_class {
+	enum hs_event_class	evnt;
+	enum hs_cmd_class	cmd;
+};
+
+struct hs_subs {
+	uint32_t                ver;
+	enum hs_subs_srvc	srvc;  /* commands or events */
+	enum hs_subs_req	req;   /* subscribe or unsubscribe  */
+	uint32_t		host_os;
+	enum hs_subs_req	disc;  /* discriminator    */
+	union hs_subs_class      id;
+};
+
+struct hs_event_cb_recv {
+	uint32_t cb_id;
+	uint32_t hs_key_data_ptr;
+	struct hs_key_data key;
+};
+enum hs_ext_cmd_type {
+	HS_EXT_CMD_KPD_SEND_KEY = 0, /* Send Key */
+	HS_EXT_CMD_KPD_BKLT_CTRL, /* Keypad backlight intensity	*/
+	HS_EXT_CMD_LCD_BKLT_CTRL, /* LCD Backlight intensity */
+	HS_EXT_CMD_DIAG_KEYMAP, /* Emulating a Diag key sequence */
+	HS_EXT_CMD_DIAG_LOCK, /* Device Lock/Unlock */
+	HS_EXT_CMD_GET_EVNT_STATUS, /* Get the status for one of the drivers */
+	HS_EXT_CMD_KPD_GET_KEYS_STATUS,/* Get a list of keys status */
+	HS_EXT_CMD_KPD_SET_PWR_KEY_RST_THOLD, /* PWR Key HW Reset duration */
+	HS_EXT_CMD_KPD_SET_PWR_KEY_THOLD, /* Set pwr key threshold duration */
+	HS_EXT_CMD_LAST, /* Should always be the last command type */
+	HS_EXT_CMD_MAX = 0x7FFFFFFF /* Force enum to be an 32-bit number */
+};
+
+struct hs_cmd_data_type {
+	uint32_t hs_cmd_data_type_ptr; /* hs_cmd_data_type ptr length */
+	uint32_t ver; /* version */
+	enum hs_ext_cmd_type id; /* command id */
+	uint32_t handle; /* handle returned from subscribe proc */
+	enum hs_ext_cmd_type disc_id1; /* discriminator id */
+	uint32_t input_ptr; /* input ptr length */
+	uint32_t input_val; /* command specific data */
+	uint32_t input_len; /* length of command input */
+	enum hs_ext_cmd_type disc_id2; /* discriminator id */
+	uint32_t output_len; /* length of output data */
+	uint32_t delayed; /* execution context for modem
+				true - caller context
+				false - hs task context*/
+};
+
+static const uint32_t hs_key_map[] = {
+	KEY(HS_PWR_K, KEY_POWER),
+	KEY(HS_END_K, KEY_END),
+	KEY(HS_STEREO_HEADSET_K, SW_HEADPHONE_INSERT_W_MIC),
+	KEY(HS_HEADSET_HEADPHONE_K, SW_HEADPHONE_INSERT),
+	KEY(HS_HEADSET_MICROPHONE_K, SW_MICROPHONE_INSERT),
+	KEY(HS_HEADSET_SWITCH_K, KEY_MEDIA),
+	KEY(HS_HEADSET_SWITCH_2_K, KEY_VOLUMEUP),
+	KEY(HS_HEADSET_SWITCH_3_K, KEY_VOLUMEDOWN),
+	0
+};
+
+enum {
+	NO_DEVICE	= 0,
+	MSM_HEADSET	= 1,
+};
+/* Add newer versions at the top of array */
+static const unsigned int rpc_vers[] = {
+	0x00030001,
+	0x00020001,
+	0x00010001,
+};
+/* hs subscription request parameters */
+struct hs_subs_rpc_req {
+	uint32_t hs_subs_ptr;
+	struct hs_subs hs_subs;
+	uint32_t hs_cb_id;
+	uint32_t hs_handle_ptr;
+	uint32_t hs_handle_data;
+};
+
+static struct hs_subs_rpc_req *hs_subs_req;
+
+struct msm_handset {
+	struct input_dev *ipdev;
+	struct switch_dev sdev;
+	struct msm_handset_platform_data *hs_pdata;
+	bool mic_on, hs_on;
+};
+
+static struct msm_rpc_client *rpc_client;
+static struct msm_handset *hs;
+
+static int hs_find_key(uint32_t hscode)
+{
+	int i, key;
+
+	key = KEY(hscode, 0);
+
+	for (i = 0; hs_key_map[i] != 0; i++) {
+		if ((hs_key_map[i] & 0xff000000) == key)
+			return hs_key_map[i] & 0x00ffffff;
+	}
+	return -1;
+}
+
+static void update_state(void)
+{
+	int state;
+
+	if (hs->mic_on && hs->hs_on)
+		state = 1 << 0;
+	else if (hs->hs_on)
+		state = 1 << 1;
+	else if (hs->mic_on)
+		state = 1 << 2;
+	else
+		state = 0;
+
+	switch_set_state(&hs->sdev, state);
+}
+
+/*
+ * tuple format: (key_code, key_param)
+ *
+ * old-architecture:
+ * key-press = (key_code, 0)
+ * key-release = (0xff, key_code)
+ *
+ * new-architecutre:
+ * key-press = (key_code, 0)
+ * key-release = (key_code, 0xff)
+ */
+static void report_hs_key(uint32_t key_code, uint32_t key_parm)
+{
+	int key, temp_key_code;
+
+	if (key_code == HS_REL_K)
+		key = hs_find_key(key_parm);
+	else
+		key = hs_find_key(key_code);
+
+	temp_key_code = key_code;
+
+	if (key_parm == HS_REL_K)
+		key_code = key_parm;
+
+	switch (key) {
+	case KEY_POWER:
+	case KEY_END:
+	case KEY_MEDIA:
+	case KEY_VOLUMEUP:
+	case KEY_VOLUMEDOWN:
+		input_report_key(hs->ipdev, key, (key_code != HS_REL_K));
+		break;
+	case SW_HEADPHONE_INSERT_W_MIC:
+		hs->mic_on = hs->hs_on = (key_code != HS_REL_K) ? 1 : 0;
+		input_report_switch(hs->ipdev, SW_HEADPHONE_INSERT,
+							hs->hs_on);
+		input_report_switch(hs->ipdev, SW_MICROPHONE_INSERT,
+							hs->mic_on);
+		update_state();
+		break;
+
+	case SW_HEADPHONE_INSERT:
+		hs->hs_on = (key_code != HS_REL_K) ? 1 : 0;
+		input_report_switch(hs->ipdev, key, hs->hs_on);
+		update_state();
+		break;
+	case SW_MICROPHONE_INSERT:
+		hs->mic_on = (key_code != HS_REL_K) ? 1 : 0;
+		input_report_switch(hs->ipdev, key, hs->mic_on);
+		update_state();
+		break;
+	case -1:
+		printk(KERN_ERR "%s: No mapping for remote handset event %d\n",
+				 __func__, temp_key_code);
+		return;
+	}
+	input_sync(hs->ipdev);
+}
+
+static int handle_hs_rpc_call(struct msm_rpc_server *server,
+			   struct rpc_request_hdr *req, unsigned len)
+{
+	struct rpc_keypad_pass_key_code_args {
+		uint32_t key_code;
+		uint32_t key_parm;
+	};
+
+	switch (req->procedure) {
+	case RPC_KEYPAD_NULL_PROC:
+		return 0;
+
+	case RPC_KEYPAD_PASS_KEY_CODE_PROC: {
+		struct rpc_keypad_pass_key_code_args *args;
+
+		args = (struct rpc_keypad_pass_key_code_args *)(req + 1);
+		args->key_code = be32_to_cpu(args->key_code);
+		args->key_parm = be32_to_cpu(args->key_parm);
+
+		report_hs_key(args->key_code, args->key_parm);
+
+		return 0;
+	}
+
+	case RPC_KEYPAD_SET_PWR_KEY_STATE_PROC:
+		/* This RPC function must be available for the ARM9
+		 * to function properly.  This function is redundant
+		 * when RPC_KEYPAD_PASS_KEY_CODE_PROC is handled. So
+		 * input_report_key is not needed.
+		 */
+		return 0;
+	default:
+		return -ENODEV;
+	}
+}
+
+static struct msm_rpc_server hs_rpc_server = {
+	.prog		= HS_SERVER_PROG,
+	.vers		= HS_SERVER_VERS,
+	.rpc_call	= handle_hs_rpc_call,
+};
+
+static int process_subs_srvc_callback(struct hs_event_cb_recv *recv)
+{
+	if (!recv)
+		return -ENODATA;
+
+	report_hs_key(be32_to_cpu(recv->key.code), be32_to_cpu(recv->key.parm));
+
+	return 0;
+}
+
+static void process_hs_rpc_request(uint32_t proc, void *data)
+{
+	if (proc == HS_EVENT_CB_PROC)
+		process_subs_srvc_callback(data);
+	else
+		pr_err("%s: unknown rpc proc %d\n", __func__, proc);
+}
+
+static int hs_rpc_report_event_arg(struct msm_rpc_client *client,
+					void *buffer, void *data)
+{
+	struct hs_event_rpc_req {
+		uint32_t hs_event_data_ptr;
+		struct hs_event_data data;
+	};
+
+	struct hs_event_rpc_req *req = buffer;
+
+	req->hs_event_data_ptr	= cpu_to_be32(0x1);
+	req->data.ver		= cpu_to_be32(HS_EVENT_DATA_VER);
+	req->data.event_type	= cpu_to_be32(HS_EVNT_HSD);
+	req->data.enum_disc	= cpu_to_be32(HS_EVNT_HSD);
+	req->data.data_length	= cpu_to_be32(0x1);
+	req->data.data		= cpu_to_be32(*(enum hs_src_state *)data);
+	req->data.data_size	= cpu_to_be32(sizeof(enum hs_src_state));
+
+	return sizeof(*req);
+}
+
+static int hs_rpc_report_event_res(struct msm_rpc_client *client,
+					void *buffer, void *data)
+{
+	enum hs_return_value result;
+
+	result = be32_to_cpu(*(enum hs_return_value *)buffer);
+	pr_debug("%s: request completed: 0x%x\n", __func__, result);
+
+	if (result == HS_SUCCESS)
+		return 0;
+
+	return 1;
+}
+
+void report_headset_status(bool connected)
+{
+	int rc = -1;
+	enum hs_src_state status;
+
+	if (connected == true)
+		status = HS_SRC_STATE_HI;
+	else
+		status = HS_SRC_STATE_LO;
+
+	rc = msm_rpc_client_req(rpc_client, HS_REPORT_EVNT_PROC,
+				hs_rpc_report_event_arg, &status,
+				hs_rpc_report_event_res, NULL, -1);
+
+	if (rc)
+		pr_err("%s: couldn't send rpc client request\n", __func__);
+}
+EXPORT_SYMBOL(report_headset_status);
+
+static int hs_rpc_pwr_cmd_arg(struct msm_rpc_client *client,
+				    void *buffer, void *data)
+{
+	struct hs_cmd_data_type *hs_pwr_cmd = buffer;
+
+	hs_pwr_cmd->hs_cmd_data_type_ptr = cpu_to_be32(0x01);
+
+	hs_pwr_cmd->ver = cpu_to_be32(0x03);
+	hs_pwr_cmd->id = cpu_to_be32(HS_EXT_CMD_KPD_SET_PWR_KEY_THOLD);
+	hs_pwr_cmd->handle = cpu_to_be32(hs_subs_req->hs_handle_data);
+	hs_pwr_cmd->disc_id1 = cpu_to_be32(HS_EXT_CMD_KPD_SET_PWR_KEY_THOLD);
+	hs_pwr_cmd->input_ptr = cpu_to_be32(0x01);
+	hs_pwr_cmd->input_val = cpu_to_be32(hs->hs_pdata->pwr_key_delay_ms);
+	hs_pwr_cmd->input_len = cpu_to_be32(0x01);
+	hs_pwr_cmd->disc_id2 = cpu_to_be32(HS_EXT_CMD_KPD_SET_PWR_KEY_THOLD);
+	hs_pwr_cmd->output_len = cpu_to_be32(0x00);
+	hs_pwr_cmd->delayed = cpu_to_be32(0x00);
+
+	return sizeof(*hs_pwr_cmd);
+}
+
+static int hs_rpc_pwr_cmd_res(struct msm_rpc_client *client,
+				    void *buffer, void *data)
+{
+	uint32_t result;
+
+	result = be32_to_cpu(*((uint32_t *)buffer));
+	pr_debug("%s: request completed: 0x%x\n", __func__, result);
+
+	return 0;
+}
+
+static int hs_rpc_register_subs_arg(struct msm_rpc_client *client,
+				    void *buffer, void *data)
+{
+	hs_subs_req = buffer;
+
+	hs_subs_req->hs_subs_ptr	= cpu_to_be32(0x1);
+	hs_subs_req->hs_subs.ver	= cpu_to_be32(0x1);
+	hs_subs_req->hs_subs.srvc	= cpu_to_be32(HS_SUBS_RCV_EVNT);
+	hs_subs_req->hs_subs.req	= cpu_to_be32(HS_SUBS_REGISTER);
+	hs_subs_req->hs_subs.host_os	= cpu_to_be32(0x4); /* linux */
+	hs_subs_req->hs_subs.disc	= cpu_to_be32(HS_SUBS_RCV_EVNT);
+	hs_subs_req->hs_subs.id.evnt	= cpu_to_be32(HS_EVNT_CLASS_ALL);
+
+	hs_subs_req->hs_cb_id		= cpu_to_be32(0x1);
+
+	hs_subs_req->hs_handle_ptr	= cpu_to_be32(0x1);
+	hs_subs_req->hs_handle_data	= cpu_to_be32(0x0);
+
+	return sizeof(*hs_subs_req);
+}
+
+static int hs_rpc_register_subs_res(struct msm_rpc_client *client,
+				    void *buffer, void *data)
+{
+	uint32_t result;
+
+	result = be32_to_cpu(*((uint32_t *)buffer));
+	pr_debug("%s: request completed: 0x%x\n", __func__, result);
+
+	return 0;
+}
+
+static int hs_cb_func(struct msm_rpc_client *client, void *buffer, int in_size)
+{
+	int rc = -1;
+
+	struct rpc_request_hdr *hdr = buffer;
+
+	hdr->type = be32_to_cpu(hdr->type);
+	hdr->xid = be32_to_cpu(hdr->xid);
+	hdr->rpc_vers = be32_to_cpu(hdr->rpc_vers);
+	hdr->prog = be32_to_cpu(hdr->prog);
+	hdr->vers = be32_to_cpu(hdr->vers);
+	hdr->procedure = be32_to_cpu(hdr->procedure);
+
+	process_hs_rpc_request(hdr->procedure,
+			    (void *) (hdr + 1));
+
+	msm_rpc_start_accepted_reply(client, hdr->xid,
+				     RPC_ACCEPTSTAT_SUCCESS);
+	rc = msm_rpc_send_accepted_reply(client, 0);
+	if (rc) {
+		pr_err("%s: sending reply failed: %d\n", __func__, rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int __devinit hs_rpc_cb_init(void)
+{
+	int rc = 0, i, num_vers;
+
+	num_vers = ARRAY_SIZE(rpc_vers);
+
+	for (i = 0; i < num_vers; i++) {
+		rpc_client = msm_rpc_register_client("hs",
+			HS_RPC_PROG, rpc_vers[i], 0, hs_cb_func);
+
+		if (IS_ERR(rpc_client))
+			pr_debug("%s: RPC Client version %d failed, fallback\n",
+				 __func__, rpc_vers[i]);
+		else
+			break;
+	}
+
+	if (IS_ERR(rpc_client)) {
+		pr_err("%s: Incompatible RPC version error %ld\n",
+			 __func__, PTR_ERR(rpc_client));
+		return PTR_ERR(rpc_client);
+	}
+
+	rc = msm_rpc_client_req(rpc_client, HS_SUBSCRIBE_SRVC_PROC,
+				hs_rpc_register_subs_arg, NULL,
+				hs_rpc_register_subs_res, NULL, -1);
+	if (rc) {
+		pr_err("%s: RPC client request failed for subscribe services\n",
+						__func__);
+		goto err_client_req;
+	}
+
+	rc = msm_rpc_client_req(rpc_client, HS_PROCESS_CMD_PROC,
+			hs_rpc_pwr_cmd_arg, NULL,
+			hs_rpc_pwr_cmd_res, NULL, -1);
+	if (rc)
+		pr_err("%s: RPC client request failed for pwr key"
+			" delay cmd, using normal mode\n", __func__);
+	return 0;
+err_client_req:
+	msm_rpc_unregister_client(rpc_client);
+	return rc;
+}
+
+static int __devinit hs_rpc_init(void)
+{
+	int rc;
+
+	rc = hs_rpc_cb_init();
+	if (rc) {
+		pr_err("%s: failed to initialize rpc client, try server...\n",
+						__func__);
+
+		rc = msm_rpc_create_server(&hs_rpc_server);
+		if (rc) {
+			pr_err("%s: failed to create rpc server\n", __func__);
+			return rc;
+		}
+	}
+
+	return rc;
+}
+
+static void __devexit hs_rpc_deinit(void)
+{
+	if (rpc_client)
+		msm_rpc_unregister_client(rpc_client);
+}
+
+static ssize_t msm_headset_print_name(struct switch_dev *sdev, char *buf)
+{
+	switch (switch_get_state(&hs->sdev)) {
+	case NO_DEVICE:
+		return sprintf(buf, "No Device\n");
+	case MSM_HEADSET:
+		return sprintf(buf, "Headset\n");
+	}
+	return -EINVAL;
+}
+
+static int __devinit hs_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct input_dev *ipdev;
+
+	hs = kzalloc(sizeof(struct msm_handset), GFP_KERNEL);
+	if (!hs)
+		return -ENOMEM;
+
+	hs->sdev.name	= "h2w";
+	hs->sdev.print_name = msm_headset_print_name;
+
+	rc = switch_dev_register(&hs->sdev);
+	if (rc)
+		goto err_switch_dev_register;
+
+	ipdev = input_allocate_device();
+	if (!ipdev) {
+		rc = -ENOMEM;
+		goto err_alloc_input_dev;
+	}
+	input_set_drvdata(ipdev, hs);
+
+	hs->ipdev = ipdev;
+
+	if (pdev->dev.platform_data)
+		hs->hs_pdata = pdev->dev.platform_data;
+
+	if (hs->hs_pdata->hs_name)
+		ipdev->name = hs->hs_pdata->hs_name;
+	else
+		ipdev->name	= DRIVER_NAME;
+
+	ipdev->id.vendor	= 0x0001;
+	ipdev->id.product	= 1;
+	ipdev->id.version	= 1;
+
+	input_set_capability(ipdev, EV_KEY, KEY_MEDIA);
+	input_set_capability(ipdev, EV_KEY, KEY_VOLUMEUP);
+	input_set_capability(ipdev, EV_KEY, KEY_VOLUMEDOWN);
+	input_set_capability(ipdev, EV_SW, SW_HEADPHONE_INSERT);
+	input_set_capability(ipdev, EV_SW, SW_MICROPHONE_INSERT);
+	input_set_capability(ipdev, EV_KEY, KEY_POWER);
+	input_set_capability(ipdev, EV_KEY, KEY_END);
+
+	rc = input_register_device(ipdev);
+	if (rc) {
+		dev_err(&ipdev->dev,
+				"hs_probe: input_register_device rc=%d\n", rc);
+		goto err_reg_input_dev;
+	}
+
+	platform_set_drvdata(pdev, hs);
+
+	rc = hs_rpc_init();
+	if (rc) {
+		dev_err(&ipdev->dev, "rpc init failure\n");
+		goto err_hs_rpc_init;
+	}
+
+	return 0;
+
+err_hs_rpc_init:
+	input_unregister_device(ipdev);
+	ipdev = NULL;
+err_reg_input_dev:
+	input_free_device(ipdev);
+err_alloc_input_dev:
+	switch_dev_unregister(&hs->sdev);
+err_switch_dev_register:
+	kfree(hs);
+	return rc;
+}
+
+static int __devexit hs_remove(struct platform_device *pdev)
+{
+	struct msm_handset *hs = platform_get_drvdata(pdev);
+
+	input_unregister_device(hs->ipdev);
+	switch_dev_unregister(&hs->sdev);
+	kfree(hs);
+	hs_rpc_deinit();
+	return 0;
+}
+
+static struct platform_driver hs_driver = {
+	.probe		= hs_probe,
+	.remove		= __devexit_p(hs_remove),
+	.driver		= {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init hs_init(void)
+{
+	return platform_driver_register(&hs_driver);
+}
+late_initcall(hs_init);
+
+static void __exit hs_exit(void)
+{
+	platform_driver_unregister(&hs_driver);
+}
+module_exit(hs_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:msm-handset");
diff --git a/arch/arm/mach-msm/rpc_server_time_remote.c b/arch/arm/mach-msm/rpc_server_time_remote.c
new file mode 100644
index 0000000..a7e6854
--- /dev/null
+++ b/arch/arm/mach-msm/rpc_server_time_remote.c
@@ -0,0 +1,168 @@
+/* arch/arm/mach-msm/rpc_server_time_remote.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009-2011 Code Aurora Forum. All rights reserved.
+ * Author: Iliyan Malchev <ibm@android.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <mach/msm_rpcrouter.h>
+#include "rpc_server_time_remote.h"
+#include <linux/rtc.h>
+#include <linux/android_alarm.h>
+#include <linux/rtc-msm.h>
+
+/* time_remote_mtoa server definitions. */
+
+#define TIME_REMOTE_MTOA_PROG 0x3000005d
+#define TIME_REMOTE_MTOA_VERS_OLD 0
+#define TIME_REMOTE_MTOA_VERS 0x9202a8e4
+#define TIME_REMOTE_MTOA_VERS_COMP 0x00010002
+#define RPC_TIME_REMOTE_MTOA_NULL   0
+#define RPC_TIME_TOD_SET_APPS_BASES 2
+#define RPC_TIME_GET_APPS_USER_TIME 3
+
+struct rpc_time_tod_set_apps_bases_args {
+	uint32_t tick;
+	uint64_t stamp;
+};
+
+static int read_rtc0_time(struct msm_rpc_server *server,
+		   struct rpc_request_hdr *req,
+		   unsigned len)
+{
+	int err;
+	unsigned long tm_sec;
+	uint32_t size = 0;
+	void *reply;
+	uint32_t output_valid;
+	uint32_t rpc_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
+	struct rtc_time tm;
+	struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
+
+	if (rtc == NULL) {
+		pr_err("%s: unable to open rtc device (%s)\n",
+			__FILE__, CONFIG_RTC_HCTOSYS_DEVICE);
+		goto send_reply;
+	}
+
+	err = rtc_read_time(rtc, &tm);
+	if (err) {
+		pr_err("%s: Error reading rtc device (%s) : %d\n",
+			__FILE__, CONFIG_RTC_HCTOSYS_DEVICE, err);
+		goto close_dev;
+	}
+
+	err = rtc_valid_tm(&tm);
+	if (err) {
+		pr_err("%s: Invalid RTC time (%s)\n",
+			__FILE__, CONFIG_RTC_HCTOSYS_DEVICE);
+		goto close_dev;
+	}
+
+	rtc_tm_to_time(&tm, &tm_sec);
+	rpc_status = RPC_ACCEPTSTAT_SUCCESS;
+
+close_dev:
+	rtc_class_close(rtc);
+
+send_reply:
+	reply = msm_rpc_server_start_accepted_reply(server, req->xid,
+						    rpc_status);
+	if (rpc_status == RPC_ACCEPTSTAT_SUCCESS) {
+		output_valid = *((uint32_t *)(req + 1));
+		*(uint32_t *)reply = output_valid;
+		size = sizeof(uint32_t);
+		if (be32_to_cpu(output_valid)) {
+			reply += sizeof(uint32_t);
+			*(uint32_t *)reply = cpu_to_be32(tm_sec);
+			size += sizeof(uint32_t);
+		}
+	}
+	err = msm_rpc_server_send_accepted_reply(server, size);
+	if (err)
+		pr_err("%s: send accepted reply failed: %d\n", __func__, err);
+
+	return 1;
+}
+
+static int handle_rpc_call(struct msm_rpc_server *server,
+			   struct rpc_request_hdr *req, unsigned len)
+{
+	struct timespec ts, tv;
+
+	switch (req->procedure) {
+	case RPC_TIME_REMOTE_MTOA_NULL:
+		return 0;
+
+	case RPC_TIME_TOD_SET_APPS_BASES: {
+		struct rpc_time_tod_set_apps_bases_args *args;
+		args = (struct rpc_time_tod_set_apps_bases_args *)(req + 1);
+		args->tick = be32_to_cpu(args->tick);
+		args->stamp = be64_to_cpu(args->stamp);
+		printk(KERN_INFO "RPC_TIME_TOD_SET_APPS_BASES:\n"
+		       "\ttick = %d\n"
+		       "\tstamp = %lld\n",
+		       args->tick, args->stamp);
+		getnstimeofday(&ts);
+		msmrtc_updateatsuspend(&ts);
+		rtc_hctosys();
+		getnstimeofday(&tv);
+		/* Update the alarm information with the new time info. */
+		alarm_update_timedelta(ts, tv);
+		return 0;
+	}
+
+	case RPC_TIME_GET_APPS_USER_TIME:
+		return read_rtc0_time(server, req, len);
+
+	default:
+		return -ENODEV;
+	}
+}
+
+static struct msm_rpc_server rpc_server[] = {
+	{
+		.prog = TIME_REMOTE_MTOA_PROG,
+		.vers = TIME_REMOTE_MTOA_VERS_OLD,
+		.rpc_call = handle_rpc_call,
+	},
+	{
+		.prog = TIME_REMOTE_MTOA_PROG,
+		.vers = TIME_REMOTE_MTOA_VERS,
+		.rpc_call = handle_rpc_call,
+	},
+	{
+		.prog = TIME_REMOTE_MTOA_PROG,
+		.vers = TIME_REMOTE_MTOA_VERS_COMP,
+		.rpc_call = handle_rpc_call,
+	},
+};
+
+static int __init rpc_server_init(void)
+{
+	/* Dual server registration to support backwards compatibility vers */
+	int ret;
+	ret = msm_rpc_create_server(&rpc_server[2]);
+	if (ret < 0)
+		return ret;
+	ret = msm_rpc_create_server(&rpc_server[1]);
+	if (ret < 0)
+		return ret;
+	return msm_rpc_create_server(&rpc_server[0]);
+}
+
+
+module_init(rpc_server_init);
diff --git a/arch/arm/mach-msm/rpc_server_time_remote.h b/arch/arm/mach-msm/rpc_server_time_remote.h
new file mode 100644
index 0000000..056666f
--- /dev/null
+++ b/arch/arm/mach-msm/rpc_server_time_remote.h
@@ -0,0 +1,21 @@
+/* arch/arm/mach-msm/rpc_server_time_remote.h
+ *
+ * Copyright (c) 2008-2009, Code Aurora Forum. 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 __ARCH_ARM_MACH_MSM_RPC_SERVER_TIME_REMOTE_H
+#define __ARCH_ARM_MACH_MSM_RPC_SERVER_TIME_REMOTE_H
+
+int rtc_hctosys(void);
+
+#endif
diff --git a/arch/arm/mach-msm/rpcrouter_sdio_xprt.c b/arch/arm/mach-msm/rpcrouter_sdio_xprt.c
new file mode 100644
index 0000000..94a2d26
--- /dev/null
+++ b/arch/arm/mach-msm/rpcrouter_sdio_xprt.c
@@ -0,0 +1,655 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * RPCROUTER SDIO XPRT module.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/err.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/wakelock.h>
+#include <asm/uaccess.h>
+#include <linux/slab.h>
+
+#include <mach/sdio_al.h>
+#include "smd_rpcrouter.h"
+
+enum {
+	MSM_SDIO_XPRT_DEBUG = 1U << 0,
+	MSM_SDIO_XPRT_INFO = 1U << 1,
+};
+
+static int msm_sdio_xprt_debug_mask;
+module_param_named(debug_mask, msm_sdio_xprt_debug_mask,
+		   int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#if defined(CONFIG_MSM_RPC_SDIO_DEBUG)
+#define SDIO_XPRT_DBG(x...) do {                \
+	if (msm_sdio_xprt_debug_mask & MSM_SDIO_XPRT_DEBUG)     \
+		printk(KERN_DEBUG x);           \
+	} while (0)
+
+#define SDIO_XPRT_INFO(x...) do {               \
+	if (msm_sdio_xprt_debug_mask & MSM_SDIO_XPRT_INFO)      \
+		printk(KERN_INFO x);            \
+	} while (0)
+#else
+#define SDIO_XPRT_DBG(x...) do { } while (0)
+#define SDIO_XPRT_INFO(x...) do { } while (0)
+#endif
+
+#define MAX_SDIO_WRITE_RETRY 5
+#define SDIO_BUF_SIZE (RPCROUTER_MSGSIZE_MAX + sizeof(struct rr_header) - 8)
+#define NUM_SDIO_BUFS 20
+#define MAX_TX_BUFS 10
+#define MAX_RX_BUFS 10
+
+struct sdio_xprt {
+	struct sdio_channel *handle;
+
+	struct list_head write_list;
+	spinlock_t write_list_lock;
+
+	struct list_head read_list;
+	spinlock_t read_list_lock;
+
+	struct list_head free_list;
+	spinlock_t free_list_lock;
+
+	struct wake_lock read_wakelock;
+};
+
+struct rpcrouter_sdio_xprt {
+	struct rpcrouter_xprt xprt;
+	struct sdio_xprt *channel;
+};
+
+static struct rpcrouter_sdio_xprt sdio_remote_xprt;
+
+static void sdio_xprt_read_data(struct work_struct *work);
+static DECLARE_DELAYED_WORK(work_read_data, sdio_xprt_read_data);
+static struct workqueue_struct *sdio_xprt_read_workqueue;
+
+struct sdio_buf_struct {
+	struct list_head list;
+	uint32_t size;
+	uint32_t read_index;
+	uint32_t write_index;
+	unsigned char data[SDIO_BUF_SIZE];
+};
+
+static void sdio_xprt_write_data(struct work_struct *work);
+static DECLARE_WORK(work_write_data, sdio_xprt_write_data);
+static wait_queue_head_t write_avail_wait_q;
+static uint32_t num_free_bufs;
+static uint32_t num_tx_bufs;
+static uint32_t num_rx_bufs;
+
+static DEFINE_MUTEX(modem_reset_lock);
+static uint32_t modem_reset;
+
+static void free_sdio_xprt(struct sdio_xprt *chnl)
+{
+	struct sdio_buf_struct *buf;
+	unsigned long flags;
+
+	if (!chnl) {
+		printk(KERN_ERR "Invalid chnl to free\n");
+		return;
+	}
+
+	spin_lock_irqsave(&chnl->free_list_lock, flags);
+	while (!list_empty(&chnl->free_list)) {
+		buf = list_first_entry(&chnl->free_list,
+					struct sdio_buf_struct, list);
+		list_del(&buf->list);
+		kfree(buf);
+	}
+	num_free_bufs = 0;
+	spin_unlock_irqrestore(&chnl->free_list_lock, flags);
+
+	spin_lock_irqsave(&chnl->write_list_lock, flags);
+	while (!list_empty(&chnl->write_list)) {
+		buf = list_first_entry(&chnl->write_list,
+					struct sdio_buf_struct, list);
+		list_del(&buf->list);
+		kfree(buf);
+	}
+	num_tx_bufs = 0;
+	spin_unlock_irqrestore(&chnl->write_list_lock, flags);
+
+	spin_lock_irqsave(&chnl->read_list_lock, flags);
+	while (!list_empty(&chnl->read_list)) {
+		buf = list_first_entry(&chnl->read_list,
+					struct sdio_buf_struct, list);
+		list_del(&buf->list);
+		kfree(buf);
+	}
+	num_rx_bufs = 0;
+	spin_unlock_irqrestore(&chnl->read_list_lock, flags);
+	wake_unlock(&chnl->read_wakelock);
+}
+
+static struct sdio_buf_struct *alloc_from_free_list(struct sdio_xprt *chnl)
+{
+	struct sdio_buf_struct *buf;
+	unsigned long flags;
+
+	spin_lock_irqsave(&chnl->free_list_lock, flags);
+	if (list_empty(&chnl->free_list)) {
+		spin_unlock_irqrestore(&chnl->free_list_lock, flags);
+		SDIO_XPRT_DBG("%s: Free list empty\n", __func__);
+		return NULL;
+	}
+	buf = list_first_entry(&chnl->free_list, struct sdio_buf_struct, list);
+	list_del(&buf->list);
+	num_free_bufs--;
+	spin_unlock_irqrestore(&chnl->free_list_lock, flags);
+
+	buf->size = 0;
+	buf->read_index = 0;
+	buf->write_index = 0;
+
+	return buf;
+}
+
+static void return_to_free_list(struct sdio_xprt *chnl,
+				struct sdio_buf_struct *buf)
+{
+	unsigned long flags;
+
+	if (!chnl || !buf) {
+		pr_err("%s: Invalid chnl or buf\n", __func__);
+		return;
+	}
+
+	buf->size = 0;
+	buf->read_index = 0;
+	buf->write_index = 0;
+
+	spin_lock_irqsave(&chnl->free_list_lock, flags);
+	list_add_tail(&buf->list, &chnl->free_list);
+	num_free_bufs++;
+	spin_unlock_irqrestore(&chnl->free_list_lock, flags);
+
+}
+
+static int rpcrouter_sdio_remote_read_avail(void)
+{
+	int read_avail = 0;
+	unsigned long flags;
+	struct sdio_buf_struct *buf;
+
+	spin_lock_irqsave(&sdio_remote_xprt.channel->read_list_lock, flags);
+	list_for_each_entry(buf, &sdio_remote_xprt.channel->read_list, list) {
+		read_avail += buf->size;
+	}
+	spin_unlock_irqrestore(&sdio_remote_xprt.channel->read_list_lock,
+				flags);
+	return read_avail;
+}
+
+static int rpcrouter_sdio_remote_read(void *data, uint32_t len)
+{
+	struct sdio_buf_struct *buf;
+	unsigned char *buf_data;
+	unsigned long flags;
+
+	SDIO_XPRT_DBG("sdio_xprt Called %s\n", __func__);
+	if (len < 0 || !data)
+		return -EINVAL;
+	else if (len == 0)
+		return 0;
+
+	spin_lock_irqsave(&sdio_remote_xprt.channel->read_list_lock, flags);
+	if (list_empty(&sdio_remote_xprt.channel->read_list)) {
+		spin_unlock_irqrestore(
+			&sdio_remote_xprt.channel->read_list_lock, flags);
+		return -EINVAL;
+	}
+
+	buf = list_first_entry(&sdio_remote_xprt.channel->read_list,
+				struct sdio_buf_struct, list);
+	if (buf->size < len) {
+		spin_unlock_irqrestore(
+			&sdio_remote_xprt.channel->read_list_lock, flags);
+		return -EINVAL;
+	}
+
+	buf_data = buf->data + buf->read_index;
+	memcpy(data, buf_data, len);
+	buf->read_index += len;
+	buf->size -= len;
+	if (buf->size == 0) {
+		list_del(&buf->list);
+		num_rx_bufs--;
+		return_to_free_list(sdio_remote_xprt.channel, buf);
+	}
+
+	if (list_empty(&sdio_remote_xprt.channel->read_list))
+		wake_unlock(&sdio_remote_xprt.channel->read_wakelock);
+	spin_unlock_irqrestore(&sdio_remote_xprt.channel->read_list_lock,
+				flags);
+	return len;
+}
+
+static int rpcrouter_sdio_remote_write_avail(void)
+{
+	uint32_t write_avail = 0;
+	unsigned long flags;
+
+	SDIO_XPRT_DBG("sdio_xprt Called %s\n", __func__);
+	spin_lock_irqsave(&sdio_remote_xprt.channel->write_list_lock, flags);
+	write_avail = (MAX_TX_BUFS - num_tx_bufs) * SDIO_BUF_SIZE;
+	spin_unlock_irqrestore(&sdio_remote_xprt.channel->write_list_lock,
+				flags);
+	return write_avail;
+}
+
+static int rpcrouter_sdio_remote_write(void *data, uint32_t len,
+					enum write_data_type type)
+{
+	unsigned long flags;
+	static struct sdio_buf_struct *buf;
+	unsigned char *buf_data;
+
+	switch (type) {
+	case HEADER:
+		spin_lock_irqsave(&sdio_remote_xprt.channel->write_list_lock,
+				  flags);
+		if (num_tx_bufs == MAX_TX_BUFS) {
+			spin_unlock_irqrestore(
+				&sdio_remote_xprt.channel->write_list_lock,
+				flags);
+			return -ENOMEM;
+		}
+		spin_unlock_irqrestore(
+			&sdio_remote_xprt.channel->write_list_lock, flags);
+
+		SDIO_XPRT_DBG("sdio_xprt WRITE HEADER %s\n", __func__);
+		buf = alloc_from_free_list(sdio_remote_xprt.channel);
+		if (!buf) {
+			pr_err("%s: alloc_from_free_list failed\n", __func__);
+			return -ENOMEM;
+		}
+		buf_data = buf->data + buf->write_index;
+		memcpy(buf_data, data, len);
+		buf->write_index += len;
+		buf->size += len;
+		return len;
+	case PACKMARK:
+		SDIO_XPRT_DBG("sdio_xprt WRITE PACKMARK %s\n",	__func__);
+		if (!buf) {
+			pr_err("%s: HEADER not written or alloc failed\n",
+				__func__);
+			return -ENOMEM;
+		}
+		buf_data = buf->data + buf->write_index;
+		memcpy(buf_data, data, len);
+		buf->write_index += len;
+		buf->size += len;
+		return len;
+	case PAYLOAD:
+		SDIO_XPRT_DBG("sdio_xprt WRITE PAYLOAD %s\n",	__func__);
+		if (!buf) {
+			pr_err("%s: HEADER not written or alloc failed\n",
+				__func__);
+			return -ENOMEM;
+		}
+		buf_data = buf->data + buf->write_index;
+		memcpy(buf_data, data, len);
+		buf->write_index += len;
+		buf->size += len;
+
+		SDIO_XPRT_DBG("sdio_xprt flush %d bytes\n", buf->size);
+		spin_lock_irqsave(&sdio_remote_xprt.channel->write_list_lock,
+				   flags);
+		list_add_tail(&buf->list,
+			      &sdio_remote_xprt.channel->write_list);
+		num_tx_bufs++;
+		spin_unlock_irqrestore(
+			&sdio_remote_xprt.channel->write_list_lock, flags);
+		queue_work(sdio_xprt_read_workqueue, &work_write_data);
+		buf = NULL;
+		return len;
+	default:
+		return -EINVAL;
+	}
+}
+
+static void sdio_xprt_write_data(struct work_struct *work)
+{
+	int rc = 0, sdio_write_retry = 0;
+	unsigned long flags;
+	struct sdio_buf_struct *buf;
+
+	mutex_lock(&modem_reset_lock);
+	if (modem_reset) {
+		mutex_unlock(&modem_reset_lock);
+		return;
+	}
+
+	spin_lock_irqsave(&sdio_remote_xprt.channel->write_list_lock, flags);
+	while (!list_empty(&sdio_remote_xprt.channel->write_list)) {
+		buf = list_first_entry(&sdio_remote_xprt.channel->write_list,
+					struct sdio_buf_struct, list);
+		list_del(&buf->list);
+		spin_unlock_irqrestore(
+			&sdio_remote_xprt.channel->write_list_lock, flags);
+		mutex_unlock(&modem_reset_lock);
+
+		wait_event(write_avail_wait_q,
+			   (!(modem_reset) && (sdio_write_avail(
+			   sdio_remote_xprt.channel->handle) >=
+			   buf->size)));
+
+		mutex_lock(&modem_reset_lock);
+		while (!(modem_reset) &&
+			((rc = sdio_write(sdio_remote_xprt.channel->handle,
+					buf->data, buf->size)) < 0) &&
+			(sdio_write_retry++ < MAX_SDIO_WRITE_RETRY)) {
+			printk(KERN_ERR "sdio_write failed with RC %d\n", rc);
+			mutex_unlock(&modem_reset_lock);
+			msleep(250);
+			mutex_lock(&modem_reset_lock);
+		}
+		if (modem_reset) {
+			mutex_unlock(&modem_reset_lock);
+			kfree(buf);
+			return;
+		} else {
+			return_to_free_list(sdio_remote_xprt.channel, buf);
+		}
+
+		if (!rc)
+			SDIO_XPRT_DBG("sdio_write %d bytes completed\n",
+					buf->size);
+
+		spin_lock_irqsave(&sdio_remote_xprt.channel->write_list_lock,
+				   flags);
+		num_tx_bufs--;
+	}
+	spin_unlock_irqrestore(&sdio_remote_xprt.channel->write_list_lock,
+				flags);
+	mutex_unlock(&modem_reset_lock);
+}
+
+static int rpcrouter_sdio_remote_close(void)
+{
+	SDIO_XPRT_DBG("sdio_xprt Called %s\n", __func__);
+	flush_workqueue(sdio_xprt_read_workqueue);
+	sdio_close(sdio_remote_xprt.channel->handle);
+	free_sdio_xprt(sdio_remote_xprt.channel);
+	return 0;
+}
+
+static void sdio_xprt_read_data(struct work_struct *work)
+{
+	int size = 0, read_avail;
+	unsigned long flags;
+	struct sdio_buf_struct *buf;
+	SDIO_XPRT_DBG("sdio_xprt Called %s\n", __func__);
+
+	mutex_lock(&modem_reset_lock);
+	while (!(modem_reset) &&
+		((read_avail =
+		sdio_read_avail(sdio_remote_xprt.channel->handle)) > 0)) {
+		spin_lock_irqsave(&sdio_remote_xprt.channel->read_list_lock,
+				  flags);
+		if (num_rx_bufs == MAX_RX_BUFS) {
+			spin_unlock_irqrestore(
+				&sdio_remote_xprt.channel->read_list_lock,
+				flags);
+			queue_delayed_work(sdio_xprt_read_workqueue,
+					   &work_read_data,
+					   msecs_to_jiffies(100));
+			break;
+		}
+		spin_unlock_irqrestore(
+			&sdio_remote_xprt.channel->read_list_lock, flags);
+
+		buf = alloc_from_free_list(sdio_remote_xprt.channel);
+		if (!buf) {
+			SDIO_XPRT_DBG("%s: Failed to alloc_from_free_list"
+				      " Try again later\n", __func__);
+			queue_delayed_work(sdio_xprt_read_workqueue,
+					   &work_read_data,
+					   msecs_to_jiffies(100));
+			break;
+		}
+
+		size = sdio_read(sdio_remote_xprt.channel->handle,
+				 buf->data, read_avail);
+		if (size < 0) {
+			printk(KERN_ERR "sdio_read failed,"
+					" read %d bytes, expected %d\n",
+					size, read_avail);
+			return_to_free_list(sdio_remote_xprt.channel, buf);
+			queue_delayed_work(sdio_xprt_read_workqueue,
+					   &work_read_data,
+					   msecs_to_jiffies(100));
+			break;
+		}
+
+		if (size == 0)
+			size = read_avail;
+
+		buf->size = size;
+		buf->write_index = size;
+		spin_lock_irqsave(&sdio_remote_xprt.channel->read_list_lock,
+				   flags);
+		list_add_tail(&buf->list,
+			      &sdio_remote_xprt.channel->read_list);
+		num_rx_bufs++;
+		spin_unlock_irqrestore(
+			&sdio_remote_xprt.channel->read_list_lock, flags);
+		wake_lock(&sdio_remote_xprt.channel->read_wakelock);
+	}
+
+	if (!modem_reset && !list_empty(&sdio_remote_xprt.channel->read_list))
+		msm_rpcrouter_xprt_notify(&sdio_remote_xprt.xprt,
+				  RPCROUTER_XPRT_EVENT_DATA);
+	mutex_unlock(&modem_reset_lock);
+}
+
+static void rpcrouter_sdio_remote_notify(void *_dev, unsigned event)
+{
+	if (event == SDIO_EVENT_DATA_READ_AVAIL) {
+		SDIO_XPRT_DBG("%s Received Notify"
+			      "SDIO_EVENT_DATA_READ_AVAIL\n", __func__);
+		queue_delayed_work(sdio_xprt_read_workqueue,
+				   &work_read_data, 0);
+	}
+	if (event == SDIO_EVENT_DATA_WRITE_AVAIL) {
+		SDIO_XPRT_DBG("%s Received Notify"
+			      "SDIO_EVENT_DATA_WRITE_AVAIL\n", __func__);
+		wake_up(&write_avail_wait_q);
+	}
+}
+
+static int allocate_sdio_xprt(struct sdio_xprt **sdio_xprt_chnl)
+{
+	struct sdio_buf_struct *buf;
+	struct sdio_xprt *chnl;
+	int i;
+	unsigned long flags;
+	int rc = -ENOMEM;
+
+	if (!(*sdio_xprt_chnl)) {
+		chnl = kmalloc(sizeof(struct sdio_xprt), GFP_KERNEL);
+		if (!chnl) {
+			printk(KERN_ERR "sdio_xprt channel"
+					" allocation failed\n");
+			return rc;
+		}
+
+		spin_lock_init(&chnl->write_list_lock);
+		spin_lock_init(&chnl->read_list_lock);
+		spin_lock_init(&chnl->free_list_lock);
+
+		INIT_LIST_HEAD(&chnl->write_list);
+		INIT_LIST_HEAD(&chnl->read_list);
+		INIT_LIST_HEAD(&chnl->free_list);
+		wake_lock_init(&chnl->read_wakelock,
+				WAKE_LOCK_SUSPEND, "rpc_sdio_xprt_read");
+	} else {
+		chnl = *sdio_xprt_chnl;
+	}
+
+	for (i = 0; i < NUM_SDIO_BUFS; i++) {
+		buf = kzalloc(sizeof(struct sdio_buf_struct), GFP_KERNEL);
+		if (!buf) {
+			printk(KERN_ERR "sdio_buf_struct alloc failed\n");
+			goto alloc_failure;
+		}
+		spin_lock_irqsave(&chnl->free_list_lock, flags);
+		list_add_tail(&buf->list, &chnl->free_list);
+		spin_unlock_irqrestore(&chnl->free_list_lock, flags);
+	}
+	num_free_bufs = NUM_SDIO_BUFS;
+
+	*sdio_xprt_chnl = chnl;
+	return 0;
+
+alloc_failure:
+	spin_lock_irqsave(&chnl->free_list_lock, flags);
+	while (!list_empty(&chnl->free_list)) {
+		buf = list_first_entry(&chnl->free_list,
+					struct sdio_buf_struct,
+					list);
+		list_del(&buf->list);
+		kfree(buf);
+	}
+	spin_unlock_irqrestore(&chnl->free_list_lock, flags);
+	wake_lock_destroy(&chnl->read_wakelock);
+
+	kfree(chnl);
+	*sdio_xprt_chnl = NULL;
+	return rc;
+}
+
+static int rpcrouter_sdio_remote_probe(struct platform_device *pdev)
+{
+	int rc;
+
+	SDIO_XPRT_INFO("%s Called\n", __func__);
+
+	mutex_lock(&modem_reset_lock);
+	if (!modem_reset) {
+		sdio_xprt_read_workqueue =
+			create_singlethread_workqueue("sdio_xprt");
+		if (!sdio_xprt_read_workqueue) {
+			mutex_unlock(&modem_reset_lock);
+			return -ENOMEM;
+		}
+
+		sdio_remote_xprt.xprt.name = "rpcrotuer_sdio_xprt";
+		sdio_remote_xprt.xprt.read_avail =
+			rpcrouter_sdio_remote_read_avail;
+		sdio_remote_xprt.xprt.read = rpcrouter_sdio_remote_read;
+		sdio_remote_xprt.xprt.write_avail =
+			rpcrouter_sdio_remote_write_avail;
+		sdio_remote_xprt.xprt.write = rpcrouter_sdio_remote_write;
+		sdio_remote_xprt.xprt.close = rpcrouter_sdio_remote_close;
+		sdio_remote_xprt.xprt.priv = NULL;
+
+		init_waitqueue_head(&write_avail_wait_q);
+	}
+	modem_reset = 0;
+
+	rc = allocate_sdio_xprt(&sdio_remote_xprt.channel);
+	if (rc) {
+		destroy_workqueue(sdio_xprt_read_workqueue);
+		mutex_unlock(&modem_reset_lock);
+		return rc;
+	}
+
+	/* Open up SDIO channel */
+	rc = sdio_open("SDIO_RPC", &sdio_remote_xprt.channel->handle, NULL,
+		      rpcrouter_sdio_remote_notify);
+
+	if (rc < 0) {
+		free_sdio_xprt(sdio_remote_xprt.channel);
+		destroy_workqueue(sdio_xprt_read_workqueue);
+		mutex_unlock(&modem_reset_lock);
+		return rc;
+	}
+	mutex_unlock(&modem_reset_lock);
+
+	msm_rpcrouter_xprt_notify(&sdio_remote_xprt.xprt,
+				  RPCROUTER_XPRT_EVENT_OPEN);
+
+	SDIO_XPRT_INFO("%s Completed\n", __func__);
+
+	return 0;
+}
+
+static int rpcrouter_sdio_remote_remove(struct platform_device *pdev)
+{
+	SDIO_XPRT_INFO("%s Called\n", __func__);
+
+	mutex_lock(&modem_reset_lock);
+	modem_reset = 1;
+	wake_up(&write_avail_wait_q);
+	free_sdio_xprt(sdio_remote_xprt.channel);
+	mutex_unlock(&modem_reset_lock);
+
+	msm_rpcrouter_xprt_notify(&sdio_remote_xprt.xprt,
+				  RPCROUTER_XPRT_EVENT_CLOSE);
+
+	SDIO_XPRT_INFO("%s Completed\n", __func__);
+
+	return 0;
+}
+
+/*Remove this platform driver after mainline of SDIO_AL update*/
+static struct platform_driver rpcrouter_sdio_remote_driver = {
+	.probe		= rpcrouter_sdio_remote_probe,
+	.driver		= {
+			.name	= "SDIO_AL",
+			.owner	= THIS_MODULE,
+	},
+};
+
+static struct platform_driver rpcrouter_sdio_driver = {
+	.probe		= rpcrouter_sdio_remote_probe,
+	.remove		= rpcrouter_sdio_remote_remove,
+	.driver		= {
+			.name	= "SDIO_RPC",
+			.owner	= THIS_MODULE,
+	},
+};
+
+static int __init rpcrouter_sdio_init(void)
+{
+	int rc;
+	msm_sdio_xprt_debug_mask = 0x2;
+	rc = platform_driver_register(&rpcrouter_sdio_remote_driver);
+	if (rc < 0)
+		return rc;
+	return platform_driver_register(&rpcrouter_sdio_driver);
+}
+
+module_init(rpcrouter_sdio_init);
+MODULE_DESCRIPTION("RPC Router SDIO XPRT");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/rpcrouter_smd_xprt.c b/arch/arm/mach-msm/rpcrouter_smd_xprt.c
new file mode 100644
index 0000000..e974eb5
--- /dev/null
+++ b/arch/arm/mach-msm/rpcrouter_smd_xprt.c
@@ -0,0 +1,333 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/*
+ * RPCROUTER SMD XPRT module.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/export.h>
+
+#include <mach/msm_smd.h>
+#include "smd_rpcrouter.h"
+#include "smd_private.h"
+
+struct rpcrouter_smd_xprt {
+	struct rpcrouter_xprt xprt;
+
+	smd_channel_t *channel;
+};
+
+static struct rpcrouter_smd_xprt smd_remote_xprt;
+#ifdef CONFIG_ARCH_FSM9XXX
+static struct rpcrouter_smd_xprt smd_remote_qdsp_xprt;
+#endif
+
+static int rpcrouter_smd_remote_read_avail(void)
+{
+	return smd_read_avail(smd_remote_xprt.channel);
+}
+
+static int rpcrouter_smd_remote_read(void *data, uint32_t len)
+{
+	return smd_read(smd_remote_xprt.channel, data, len);
+}
+
+static int rpcrouter_smd_remote_write_avail(void)
+{
+	return smd_write_avail(smd_remote_xprt.channel);
+}
+
+static int rpcrouter_smd_remote_write(void *data, uint32_t len, uint32_t type)
+{
+	return smd_write(smd_remote_xprt.channel, data, len);
+}
+
+static int rpcrouter_smd_remote_close(void)
+{
+	smsm_change_state(SMSM_APPS_STATE, SMSM_RPCINIT, 0);
+	return smd_close(smd_remote_xprt.channel);
+}
+
+static void rpcrouter_smd_remote_notify(void *_dev, unsigned event)
+{
+	switch (event) {
+	case SMD_EVENT_DATA:
+		msm_rpcrouter_xprt_notify(&smd_remote_xprt.xprt,
+					  RPCROUTER_XPRT_EVENT_DATA);
+		break;
+
+	case SMD_EVENT_OPEN:
+		pr_info("%s: smd opened 0x%p\n", __func__, _dev);
+
+		msm_rpcrouter_xprt_notify(&smd_remote_xprt.xprt,
+			RPCROUTER_XPRT_EVENT_OPEN);
+		break;
+
+	case SMD_EVENT_CLOSE:
+		pr_info("%s: smd closed 0x%p\n", __func__, _dev);
+
+		msm_rpcrouter_xprt_notify(&smd_remote_xprt.xprt,
+				RPCROUTER_XPRT_EVENT_CLOSE);
+		break;
+    }
+}
+
+#ifdef CONFIG_ARCH_FSM9XXX
+static int rpcrouter_smd_remote_qdsp_read_avail(void)
+{
+	return smd_read_avail(smd_remote_qdsp_xprt.channel);
+}
+
+static int rpcrouter_smd_remote_qdsp_read(void *data, uint32_t len)
+{
+	return smd_read(smd_remote_qdsp_xprt.channel, data, len);
+}
+
+static int rpcrouter_smd_remote_qdsp_write_avail(void)
+{
+	return smd_write_avail(smd_remote_qdsp_xprt.channel);
+}
+
+static int rpcrouter_smd_remote_qdsp_write(void *data,
+		uint32_t len, uint32_t type)
+{
+	return smd_write(smd_remote_qdsp_xprt.channel, data, len);
+}
+
+static int rpcrouter_smd_remote_qdsp_close(void)
+{
+	/*
+	 * TBD: Implement when we have N way SMSM ported
+	 * smsm_change_state(SMSM_APPS_STATE, SMSM_RPCINIT, 0);
+	 */
+	return smd_close(smd_remote_qdsp_xprt.channel);
+}
+
+static void rpcrouter_smd_remote_qdsp_notify(void *_dev, unsigned event)
+{
+	switch (event) {
+	case SMD_EVENT_DATA:
+		msm_rpcrouter_xprt_notify(&smd_remote_qdsp_xprt.xprt,
+			RPCROUTER_XPRT_EVENT_DATA);
+		break;
+
+	case SMD_EVENT_OPEN:
+		/* Print log info */
+		pr_debug("%s: smd opened\n", __func__);
+
+		msm_rpcrouter_xprt_notify(&smd_remote_qdsp_xprt.xprt,
+			RPCROUTER_XPRT_EVENT_OPEN);
+		break;
+
+	case SMD_EVENT_CLOSE:
+		/* Print log info */
+		pr_debug("%s: smd closed\n", __func__);
+
+		msm_rpcrouter_xprt_notify(&smd_remote_qdsp_xprt.xprt,
+				RPCROUTER_XPRT_EVENT_CLOSE);
+		break;
+	}
+}
+
+static int rpcrouter_smd_remote_qdsp_probe(struct platform_device *pdev)
+{
+	int rc;
+
+	smd_remote_qdsp_xprt.xprt.name = "rpcrotuer_smd_qdsp_xprt";
+	smd_remote_qdsp_xprt.xprt.read_avail =
+			rpcrouter_smd_remote_qdsp_read_avail;
+	smd_remote_qdsp_xprt.xprt.read = rpcrouter_smd_remote_qdsp_read;
+	smd_remote_qdsp_xprt.xprt.write_avail =
+			rpcrouter_smd_remote_qdsp_write_avail;
+	smd_remote_qdsp_xprt.xprt.write = rpcrouter_smd_remote_qdsp_write;
+	smd_remote_qdsp_xprt.xprt.close = rpcrouter_smd_remote_qdsp_close;
+	smd_remote_qdsp_xprt.xprt.priv = NULL;
+
+	/* Open up SMD channel */
+	rc = smd_named_open_on_edge("RPCCALL_QDSP", SMD_APPS_QDSP,
+			&smd_remote_qdsp_xprt.channel, NULL,
+			rpcrouter_smd_remote_qdsp_notify);
+	if (rc < 0)
+		return rc;
+
+	smd_disable_read_intr(smd_remote_qdsp_xprt.channel);
+
+	return 0;
+}
+
+static struct platform_driver rpcrouter_smd_remote_qdsp_driver = {
+	.probe		= rpcrouter_smd_remote_qdsp_probe,
+	.driver		= {
+			.name	= "RPCCALL_QDSP",
+			.owner	= THIS_MODULE,
+	},
+};
+
+static inline int register_smd_remote_qpsp_driver(void)
+{
+	return platform_driver_register(&rpcrouter_smd_remote_qdsp_driver);
+}
+#else /* CONFIG_ARCH_FSM9XXX */
+static inline int register_smd_remote_qpsp_driver(void)
+{
+	return 0;
+}
+#endif
+
+#if defined(CONFIG_MSM_RPC_LOOPBACK_XPRT)
+
+static struct rpcrouter_smd_xprt smd_loopback_xprt;
+
+static int rpcrouter_smd_loopback_read_avail(void)
+{
+	return smd_read_avail(smd_loopback_xprt.channel);
+}
+
+static int rpcrouter_smd_loopback_read(void *data, uint32_t len)
+{
+	return smd_read(smd_loopback_xprt.channel, data, len);
+}
+
+static int rpcrouter_smd_loopback_write_avail(void)
+{
+	return smd_write_avail(smd_loopback_xprt.channel);
+}
+
+static int rpcrouter_smd_loopback_write(void *data, uint32_t len, uint32 type)
+{
+	return smd_write(smd_loopback_xprt.channel, data, len);
+}
+
+static int rpcrouter_smd_loopback_close(void)
+{
+	return smd_close(smd_loopback_xprt.channel);
+}
+
+static void rpcrouter_smd_loopback_notify(void *_dev, unsigned event)
+{
+	switch (event) {
+	case SMD_EVENT_DATA:
+		msm_rpcrouter_xprt_notify(&smd_loopback_xprt.xprt,
+					  RPCROUTER_XPRT_EVENT_DATA);
+		break;
+
+	case SMD_EVENT_OPEN:
+		pr_debug("%s: smd loopback opened 0x%p\n", __func__, _dev);
+
+		msm_rpcrouter_xprt_notify(&smd_loopback_xprt.xprt,
+			RPCROUTER_XPRT_EVENT_OPEN);
+		break;
+
+	case SMD_EVENT_CLOSE:
+		pr_debug("%s: smd loopback closed 0x%p\n", __func__, _dev);
+
+		msm_rpcrouter_xprt_notify(&smd_loopback_xprt.xprt,
+				RPCROUTER_XPRT_EVENT_CLOSE);
+		break;
+    }
+}
+
+static int rpcrouter_smd_loopback_probe(struct platform_device *pdev)
+{
+	int rc;
+
+	smd_loopback_xprt.xprt.name = "rpcrouter_loopback_xprt";
+	smd_loopback_xprt.xprt.read_avail = rpcrouter_smd_loopback_read_avail;
+	smd_loopback_xprt.xprt.read = rpcrouter_smd_loopback_read;
+	smd_loopback_xprt.xprt.write_avail = rpcrouter_smd_loopback_write_avail;
+	smd_loopback_xprt.xprt.write = rpcrouter_smd_loopback_write;
+	smd_loopback_xprt.xprt.close = rpcrouter_smd_loopback_close;
+	smd_loopback_xprt.xprt.priv = NULL;
+
+	/* Open up SMD LOOPBACK channel */
+	rc = smd_named_open_on_edge("local_loopback", SMD_LOOPBACK_TYPE,
+				    &smd_loopback_xprt.channel, NULL,
+				    rpcrouter_smd_loopback_notify);
+	if (rc < 0)
+		return rc;
+
+	smd_disable_read_intr(smd_remote_xprt.channel);
+	return 0;
+}
+
+static struct platform_driver rpcrouter_smd_loopback_driver = {
+	.probe		= rpcrouter_smd_loopback_probe,
+	.driver		= {
+			.name	= "local_loopback",
+			.owner	= THIS_MODULE,
+	},
+};
+
+static inline int register_smd_loopback_driver(void)
+{
+	return platform_driver_register(&rpcrouter_smd_loopback_driver);
+}
+#else /* CONFIG_MSM_RPC_LOOPBACK_XPRT */
+static inline int register_smd_loopback_driver(void)
+{
+	return 0;
+}
+#endif
+
+static int rpcrouter_smd_remote_probe(struct platform_device *pdev)
+{
+	int rc;
+
+	smd_remote_xprt.xprt.name = "rpcrotuer_smd_xprt";
+	smd_remote_xprt.xprt.read_avail = rpcrouter_smd_remote_read_avail;
+	smd_remote_xprt.xprt.read = rpcrouter_smd_remote_read;
+	smd_remote_xprt.xprt.write_avail = rpcrouter_smd_remote_write_avail;
+	smd_remote_xprt.xprt.write = rpcrouter_smd_remote_write;
+	smd_remote_xprt.xprt.close = rpcrouter_smd_remote_close;
+	smd_remote_xprt.xprt.priv = NULL;
+
+	/* Open up SMD channel */
+	rc = smd_open("RPCCALL", &smd_remote_xprt.channel, NULL,
+		      rpcrouter_smd_remote_notify);
+	if (rc < 0)
+		return rc;
+
+	smd_disable_read_intr(smd_remote_xprt.channel);
+
+	return 0;
+}
+
+static struct platform_driver rpcrouter_smd_remote_driver = {
+	.probe		= rpcrouter_smd_remote_probe,
+	.driver		= {
+			.name	= "RPCCALL",
+			.owner	= THIS_MODULE,
+	},
+};
+
+static int __init rpcrouter_smd_init(void)
+{
+	int rc;
+
+	rc = register_smd_loopback_driver();
+	if (rc < 0)
+		return rc;
+
+	rc = register_smd_remote_qpsp_driver();
+	if (rc < 0)
+		return rc;
+
+	return platform_driver_register(&rpcrouter_smd_remote_driver);
+}
+
+module_init(rpcrouter_smd_init);
+MODULE_DESCRIPTION("RPC Router SMD XPRT");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/rpm-notifier.h b/arch/arm/mach-msm/rpm-notifier.h
new file mode 100644
index 0000000..df8d9b3
--- /dev/null
+++ b/arch/arm/mach-msm/rpm-notifier.h
@@ -0,0 +1,27 @@
+/* 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 __ARCH_ARM_MACH_MSM_RPM_NOTIF_H
+#define __ARCH_ARM_MACH_MSM_RPM_NOTIF_H
+
+struct msm_rpm_notifier_data {
+	uint32_t rsc_type;
+	uint32_t rsc_id;
+	uint32_t key;
+	uint32_t size;
+	uint8_t *value;
+};
+
+int msm_rpm_register_notifier(struct notifier_block *nb);
+int msm_rpm_unregister_notifier(struct notifier_block *nb);
+
+#endif /*__ARCH_ARM_MACH_MSM_RPM_NOTIF_H */
diff --git a/arch/arm/mach-msm/rpm-regulator-8660.c b/arch/arm/mach-msm/rpm-regulator-8660.c
new file mode 100644
index 0000000..6c4a9ad
--- /dev/null
+++ b/arch/arm/mach-msm/rpm-regulator-8660.c
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include "rpm-regulator-private.h"
+
+/* RPM regulator request formats */
+static struct rpm_vreg_parts ldo_parts = {
+	.request_len	= 2,
+	.mV		= REQUEST_MEMBER(0, 0x00000FFF,  0),
+	.ip		= REQUEST_MEMBER(0, 0x00FFF000, 12),
+	.fm		= REQUEST_MEMBER(0, 0x03000000, 24),
+	.pc		= REQUEST_MEMBER(0, 0x3C000000, 26),
+	.pf		= REQUEST_MEMBER(0, 0xC0000000, 30),
+	.pd		= REQUEST_MEMBER(1, 0x00000001,  0),
+	.ia		= REQUEST_MEMBER(1, 0x00001FFE,  1),
+};
+
+static struct rpm_vreg_parts smps_parts = {
+	.request_len	= 2,
+	.mV		= REQUEST_MEMBER(0, 0x00000FFF,  0),
+	.ip		= REQUEST_MEMBER(0, 0x00FFF000, 12),
+	.fm		= REQUEST_MEMBER(0, 0x03000000, 24),
+	.pc		= REQUEST_MEMBER(0, 0x3C000000, 26),
+	.pf		= REQUEST_MEMBER(0, 0xC0000000, 30),
+	.pd		= REQUEST_MEMBER(1, 0x00000001,  0),
+	.ia		= REQUEST_MEMBER(1, 0x00001FFE,  1),
+	.freq		= REQUEST_MEMBER(1, 0x001FE000, 13),
+	.freq_clk_src	= REQUEST_MEMBER(1, 0x00600000, 21),
+};
+
+static struct rpm_vreg_parts switch_parts = {
+	.request_len	= 1,
+	.enable_state	= REQUEST_MEMBER(0, 0x00000001,  0),
+	.pd		= REQUEST_MEMBER(0, 0x00000002,  1),
+	.pc		= REQUEST_MEMBER(0, 0x0000003C,  2),
+	.pf		= REQUEST_MEMBER(0, 0x000000C0,  6),
+	.hpm		= REQUEST_MEMBER(0, 0x00000300,  8),
+};
+
+static struct rpm_vreg_parts ncp_parts = {
+	.request_len	= 1,
+	.mV		= REQUEST_MEMBER(0, 0x00000FFF,  0),
+	.enable_state	= REQUEST_MEMBER(0, 0x00001000, 12),
+	.comp_mode	= REQUEST_MEMBER(0, 0x00002000, 13),
+	.freq		= REQUEST_MEMBER(0, 0x003FC000, 14),
+};
+
+/* Physically available PMIC regulator voltage setpoint ranges */
+static struct vreg_range pldo_ranges[] = {
+	VOLTAGE_RANGE( 750000, 1487500, 12500),
+	VOLTAGE_RANGE(1500000, 3075000, 25000),
+	VOLTAGE_RANGE(3100000, 4900000, 50000),
+};
+
+static struct vreg_range nldo_ranges[] = {
+	VOLTAGE_RANGE( 750000, 1537500, 12500),
+};
+
+static struct vreg_range smps_ranges[] = {
+	VOLTAGE_RANGE( 375000,  737500, 12500),
+	VOLTAGE_RANGE( 750000, 1487500, 12500),
+	VOLTAGE_RANGE(1500000, 3075000, 25000),
+};
+
+static struct vreg_range ftsmps_ranges[] = {
+	VOLTAGE_RANGE( 350000,  650000, 50000),
+	VOLTAGE_RANGE( 700000, 1400000, 12500),
+	VOLTAGE_RANGE(1500000, 3300000, 50000),
+};
+
+static struct vreg_range ncp_ranges[] = {
+	VOLTAGE_RANGE(1500000, 3050000, 50000),
+};
+
+static struct vreg_set_points pldo_set_points = SET_POINTS(pldo_ranges);
+static struct vreg_set_points nldo_set_points = SET_POINTS(nldo_ranges);
+static struct vreg_set_points smps_set_points = SET_POINTS(smps_ranges);
+static struct vreg_set_points ftsmps_set_points = SET_POINTS(ftsmps_ranges);
+static struct vreg_set_points ncp_set_points = SET_POINTS(ncp_ranges);
+
+static struct vreg_set_points *all_set_points[] = {
+	&pldo_set_points,
+	&nldo_set_points,
+	&smps_set_points,
+	&ftsmps_set_points,
+	&ncp_set_points,
+};
+
+#define LDO(_vreg_id, _rpm_id, _name, _name_pc, _ranges, _hpm_min_load) \
+	[RPM_VREG_ID_##_vreg_id] = { \
+		.req = { \
+			[0] = { .id = MSM_RPM_ID_##_rpm_id##_0, }, \
+			[1] = { .id = MSM_RPM_ID_##_rpm_id##_1, }, \
+		}, \
+		.hpm_min_load  = RPM_VREG_8660_##_hpm_min_load##_HPM_MIN_LOAD, \
+		.type		 = RPM_REGULATOR_TYPE_LDO, \
+		.set_points	 = &_ranges##_set_points, \
+		.part		 = &ldo_parts, \
+		.id		 = RPM_VREG_ID_##_vreg_id, \
+		.rdesc.name	 = _name, \
+		.rdesc_pc.name	 = _name_pc, \
+	}
+
+#define SMPS(_vreg_id, _rpm_id, _name, _name_pc, _ranges, _hpm_min_load) \
+	[RPM_VREG_ID_##_vreg_id] = { \
+		.req = { \
+			[0] = { .id = MSM_RPM_ID_##_rpm_id##_0, }, \
+			[1] = { .id = MSM_RPM_ID_##_rpm_id##_1, }, \
+		}, \
+		.hpm_min_load  = RPM_VREG_8660_##_hpm_min_load##_HPM_MIN_LOAD, \
+		.type		 = RPM_REGULATOR_TYPE_SMPS, \
+		.set_points	 = &_ranges##_set_points, \
+		.part		 = &smps_parts, \
+		.id		 = RPM_VREG_ID_##_vreg_id, \
+		.rdesc.name	 = _name, \
+		.rdesc_pc.name	 = _name_pc, \
+	}
+
+#define LVS(_vreg_id, _rpm_id, _name, _name_pc) \
+	[RPM_VREG_ID_##_vreg_id] = { \
+		.req = { \
+			[0] = { .id = MSM_RPM_ID_##_rpm_id, }, \
+			[1] = { .id = -1, }, \
+		}, \
+		.type		 = RPM_REGULATOR_TYPE_VS, \
+		.part		 = &switch_parts, \
+		.id		 = RPM_VREG_ID_##_vreg_id, \
+		.rdesc.name	 = _name, \
+		.rdesc_pc.name	 = _name_pc, \
+	}
+
+#define MVS(_vreg_id, _rpm_id, _name, _name_pc) \
+		LVS(_vreg_id, _rpm_id, _name, _name_pc)
+
+#define NCP(_vreg_id, _rpm_id, _name, _name_pc) \
+	[RPM_VREG_ID_##_vreg_id] = { \
+		.req = { \
+			[0] = { .id = MSM_RPM_ID_##_rpm_id##_0, }, \
+			[1] = { .id = MSM_RPM_ID_##_rpm_id##_1, }, \
+		}, \
+		.type		 = RPM_REGULATOR_TYPE_NCP, \
+		.set_points	 = &ncp_set_points, \
+		.part		 = &ncp_parts, \
+		.id		 = RPM_VREG_ID_##_vreg_id, \
+		.rdesc.name	 = _name, \
+		.rdesc_pc.name	 = _name_pc, \
+	}
+
+static struct vreg vregs[] = {
+	LDO(PM8058_L0,   LDO0,   "8058_l0",   "8058_l0_pc",  nldo, LDO_150),
+	LDO(PM8058_L1,   LDO1,   "8058_l1",   "8058_l1_pc",  nldo, LDO_300),
+	LDO(PM8058_L2,   LDO2,   "8058_l2",   "8058_l2_pc",  pldo, LDO_300),
+	LDO(PM8058_L3,   LDO3,   "8058_l3",   "8058_l3_pc",  pldo, LDO_150),
+	LDO(PM8058_L4,   LDO4,   "8058_l4",   "8058_l4_pc",  pldo, LDO_50),
+	LDO(PM8058_L5,   LDO5,   "8058_l5",   "8058_l5_pc",  pldo, LDO_300),
+	LDO(PM8058_L6,   LDO6,   "8058_l6",   "8058_l6_pc",  pldo, LDO_50),
+	LDO(PM8058_L7,   LDO7,   "8058_l7",   "8058_l7_pc",  pldo, LDO_50),
+	LDO(PM8058_L8,   LDO8,   "8058_l8",   "8058_l8_pc",  pldo, LDO_300),
+	LDO(PM8058_L9,   LDO9,   "8058_l9",   "8058_l9_pc",  pldo, LDO_300),
+	LDO(PM8058_L10,  LDO10,  "8058_l10",  "8058_l10_pc", pldo, LDO_300),
+	LDO(PM8058_L11,  LDO11,  "8058_l11",  "8058_l11_pc", pldo, LDO_150),
+	LDO(PM8058_L12,  LDO12,  "8058_l12",  "8058_l12_pc", pldo, LDO_150),
+	LDO(PM8058_L13,  LDO13,  "8058_l13",  "8058_l13_pc", pldo, LDO_300),
+	LDO(PM8058_L14,  LDO14,  "8058_l14",  "8058_l14_pc", pldo, LDO_300),
+	LDO(PM8058_L15,  LDO15,  "8058_l15",  "8058_l15_pc", pldo, LDO_300),
+	LDO(PM8058_L16,  LDO16,  "8058_l16",  "8058_l16_pc", pldo, LDO_300),
+	LDO(PM8058_L17,  LDO17,  "8058_l17",  "8058_l17_pc", pldo, LDO_150),
+	LDO(PM8058_L18,  LDO18,  "8058_l18",  "8058_l18_pc", pldo, LDO_150),
+	LDO(PM8058_L19,  LDO19,  "8058_l19",  "8058_l19_pc", pldo, LDO_150),
+	LDO(PM8058_L20,  LDO20,  "8058_l20",  "8058_l20_pc", pldo, LDO_150),
+	LDO(PM8058_L21,  LDO21,  "8058_l21",  "8058_l21_pc", nldo, LDO_150),
+	LDO(PM8058_L22,  LDO22,  "8058_l22",  "8058_l22_pc", nldo, LDO_300),
+	LDO(PM8058_L23,  LDO23,  "8058_l23",  "8058_l23_pc", nldo, LDO_300),
+	LDO(PM8058_L24,  LDO24,  "8058_l24",  "8058_l24_pc", nldo, LDO_150),
+	LDO(PM8058_L25,  LDO25,  "8058_l25",  "8058_l25_pc", nldo, LDO_150),
+
+	SMPS(PM8058_S0,  SMPS0,  "8058_s0",   "8058_s0_pc",  smps, SMPS),
+	SMPS(PM8058_S1,  SMPS1,  "8058_s1",   "8058_s1_pc",  smps, SMPS),
+	SMPS(PM8058_S2,  SMPS2,  "8058_s2",   "8058_s2_pc",  smps, SMPS),
+	SMPS(PM8058_S3,  SMPS3,  "8058_s3",   "8058_s3_pc",  smps, SMPS),
+	SMPS(PM8058_S4,  SMPS4,  "8058_s4",   "8058_s4_pc",  smps, SMPS),
+
+	LVS(PM8058_LVS0, LVS0,   "8058_lvs0", "8058_lvs0_pc"),
+	LVS(PM8058_LVS1, LVS1,   "8058_lvs1", "8058_lvs1_pc"),
+
+	NCP(PM8058_NCP,  NCP,    "8058_ncp",  NULL),
+
+	LDO(PM8901_L0,   LDO0B,  "8901_l0",   "8901_l0_pc",  nldo, LDO_300),
+	LDO(PM8901_L1,   LDO1B,  "8901_l1",   "8901_l1_pc",  pldo, LDO_300),
+	LDO(PM8901_L2,   LDO2B,  "8901_l2",   "8901_l2_pc",  pldo, LDO_300),
+	LDO(PM8901_L3,   LDO3B,  "8901_l3",   "8901_l3_pc",  pldo, LDO_300),
+	LDO(PM8901_L4,   LDO4B,  "8901_l4",   "8901_l4_pc",  pldo, LDO_300),
+	LDO(PM8901_L5,   LDO5B,  "8901_l5",   "8901_l5_pc",  pldo, LDO_300),
+	LDO(PM8901_L6,   LDO6B,  "8901_l6",   "8901_l6_pc",  pldo, LDO_300),
+
+	SMPS(PM8901_S0,  SMPS0B, "8901_s0",   "8901_s0_pc", ftsmps, FTSMPS),
+	SMPS(PM8901_S1,  SMPS1B, "8901_s1",   "8901_s1_pc", ftsmps, FTSMPS),
+	SMPS(PM8901_S2,  SMPS2B, "8901_s2",   "8901_s2_pc", ftsmps, FTSMPS),
+	SMPS(PM8901_S3,  SMPS3B, "8901_s3",   "8901_s3_pc", ftsmps, FTSMPS),
+	SMPS(PM8901_S4,  SMPS4B, "8901_s4",   "8901_s4_pc", ftsmps, FTSMPS),
+
+	LVS(PM8901_LVS0, LVS0B,  "8901_lvs0", "8901_lvs0_pc"),
+	LVS(PM8901_LVS1, LVS1B,  "8901_lvs1", "8901_lvs1_pc"),
+	LVS(PM8901_LVS2, LVS2B,  "8901_lvs2", "8901_lvs2_pc"),
+	LVS(PM8901_LVS3, LVS3B,  "8901_lvs3", "8901_lvs3_pc"),
+
+	MVS(PM8901_MVS0, MVS,    "8901_mvs0", "8901_mvs0_pc"),
+};
+
+static const char *pin_func_label[] = {
+	[RPM_VREG_PIN_FN_8660_ENABLE]		= "on/off",
+	[RPM_VREG_PIN_FN_8660_MODE]		= "HPM/LPM",
+	[RPM_VREG_PIN_FN_8660_SLEEP_B]		= "sleep_b",
+	[RPM_VREG_PIN_FN_8660_NONE]		= "none",
+};
+
+static const char *force_mode_label[] = {
+	[RPM_VREG_FORCE_MODE_8660_NONE]		= "none",
+	[RPM_VREG_FORCE_MODE_8660_LPM]		= "LPM",
+	[RPM_VREG_FORCE_MODE_8660_HPM]		= "HPM",
+};
+
+static const char *pin_control_label[] = {
+	" A0",
+	" A1",
+	" D0",
+	" D1",
+};
+
+static int is_real_id(int id)
+{
+	return (id >= 0) && (id <= RPM_VREG_ID_8660_MAX_REAL);
+}
+
+static int pc_id_to_real_id(int id)
+{
+	int real_id;
+
+	if (id >= RPM_VREG_ID_PM8058_L0_PC && id <= RPM_VREG_ID_PM8058_LVS1_PC)
+		real_id = id - RPM_VREG_ID_PM8058_L0_PC + RPM_VREG_ID_PM8058_L0;
+	else
+		real_id = id - RPM_VREG_ID_PM8901_L0_PC + RPM_VREG_ID_PM8901_L0;
+
+	return real_id;
+}
+
+static struct vreg_config config = {
+	.vregs				= vregs,
+	.vregs_len			= ARRAY_SIZE(vregs),
+
+	.vreg_id_min			= RPM_VREG_ID_PM8058_L0,
+	.vreg_id_max			= RPM_VREG_ID_8660_MAX,
+
+	.pin_func_none			= RPM_VREG_PIN_FN_8660_NONE,
+	.pin_func_sleep_b		= RPM_VREG_PIN_FN_8660_SLEEP_B,
+
+	.mode_lpm			= REGULATOR_MODE_IDLE,
+	.mode_hpm			= REGULATOR_MODE_NORMAL,
+
+	.set_points			= all_set_points,
+	.set_points_len			= ARRAY_SIZE(all_set_points),
+
+	.label_pin_ctrl			= pin_control_label,
+	.label_pin_ctrl_len		= ARRAY_SIZE(pin_control_label),
+	.label_pin_func			= pin_func_label,
+	.label_pin_func_len		= ARRAY_SIZE(pin_func_label),
+	.label_force_mode		= force_mode_label,
+	.label_force_mode_len		= ARRAY_SIZE(force_mode_label),
+
+	.is_real_id			= is_real_id,
+	.pc_id_to_real_id		= pc_id_to_real_id,
+
+	.use_legacy_optimum_mode	= 1,
+	.ia_follows_ip			= 1,
+};
+
+struct vreg_config *get_config_8660(void)
+{
+	return &config;
+}
diff --git a/arch/arm/mach-msm/rpm-regulator-8930.c b/arch/arm/mach-msm/rpm-regulator-8930.c
new file mode 100644
index 0000000..f396fed
--- /dev/null
+++ b/arch/arm/mach-msm/rpm-regulator-8930.c
@@ -0,0 +1,295 @@
+/*
+ * 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include "rpm-regulator-private.h"
+
+/* RPM regulator request formats */
+static struct rpm_vreg_parts ldo_parts = {
+	.request_len	= 2,
+	.uV		= REQUEST_MEMBER(0, 0x007FFFFF,  0),
+	.pd		= REQUEST_MEMBER(0, 0x00800000, 23),
+	.pc		= REQUEST_MEMBER(0, 0x0F000000, 24),
+	.pf		= REQUEST_MEMBER(0, 0xF0000000, 28),
+	.ip		= REQUEST_MEMBER(1, 0x000003FF,  0),
+	.ia		= REQUEST_MEMBER(1, 0x000FFC00, 10),
+	.fm		= REQUEST_MEMBER(1, 0x00700000, 20),
+};
+
+static struct rpm_vreg_parts smps_parts = {
+	.request_len	= 2,
+	.uV		= REQUEST_MEMBER(0, 0x007FFFFF,  0),
+	.pd		= REQUEST_MEMBER(0, 0x00800000, 23),
+	.pc		= REQUEST_MEMBER(0, 0x0F000000, 24),
+	.pf		= REQUEST_MEMBER(0, 0xF0000000, 28),
+	.ip		= REQUEST_MEMBER(1, 0x000003FF,  0),
+	.ia		= REQUEST_MEMBER(1, 0x000FFC00, 10),
+	.fm		= REQUEST_MEMBER(1, 0x00700000, 20),
+	.pm		= REQUEST_MEMBER(1, 0x00800000, 23),
+	.freq		= REQUEST_MEMBER(1, 0x1F000000, 24),
+	.freq_clk_src	= REQUEST_MEMBER(1, 0x60000000, 29),
+};
+
+static struct rpm_vreg_parts switch_parts = {
+	.request_len	= 1,
+	.enable_state	= REQUEST_MEMBER(0, 0x00000001,  0),
+	.pd		= REQUEST_MEMBER(0, 0x00000002,  1),
+	.pc		= REQUEST_MEMBER(0, 0x0000003C,  2),
+	.pf		= REQUEST_MEMBER(0, 0x000003C0,  6),
+	.hpm		= REQUEST_MEMBER(0, 0x00000C00, 10),
+};
+
+static struct rpm_vreg_parts corner_parts = {
+	.request_len	= 1,
+	.uV		= REQUEST_MEMBER(0, 0x00000003,  0),
+};
+
+/* Physically available PMIC regulator voltage setpoint ranges */
+static struct vreg_range pldo_ranges[] = {
+	VOLTAGE_RANGE( 750000, 1487500, 12500),
+	VOLTAGE_RANGE(1500000, 3075000, 25000),
+	VOLTAGE_RANGE(3100000, 4900000, 50000),
+};
+
+static struct vreg_range nldo_ranges[] = {
+	VOLTAGE_RANGE( 750000, 1537500, 12500),
+};
+
+static struct vreg_range nldo1200_ranges[] = {
+	VOLTAGE_RANGE( 375000,  743750,  6250),
+	VOLTAGE_RANGE( 750000, 1537500, 12500),
+};
+
+static struct vreg_range smps_ranges[] = {
+	VOLTAGE_RANGE( 375000,  737500, 12500),
+	VOLTAGE_RANGE( 750000, 1487500, 12500),
+	VOLTAGE_RANGE(1500000, 3075000, 25000),
+};
+
+static struct vreg_range ftsmps_ranges[] = {
+	VOLTAGE_RANGE( 350000,  650000, 50000),
+	VOLTAGE_RANGE( 700000, 1400000, 12500),
+	VOLTAGE_RANGE(1500000, 3300000, 50000),
+};
+
+static struct vreg_range corner_ranges[] = {
+	VOLTAGE_RANGE(RPM_VREG_CORNER_NONE, RPM_VREG_CORNER_HIGH, 1),
+};
+
+static struct vreg_set_points pldo_set_points = SET_POINTS(pldo_ranges);
+static struct vreg_set_points nldo_set_points = SET_POINTS(nldo_ranges);
+static struct vreg_set_points nldo1200_set_points = SET_POINTS(nldo1200_ranges);
+static struct vreg_set_points smps_set_points = SET_POINTS(smps_ranges);
+static struct vreg_set_points ftsmps_set_points = SET_POINTS(ftsmps_ranges);
+static struct vreg_set_points corner_set_points = SET_POINTS(corner_ranges);
+
+static struct vreg_set_points *all_set_points[] = {
+	&pldo_set_points,
+	&nldo_set_points,
+	&nldo1200_set_points,
+	&smps_set_points,
+	&ftsmps_set_points,
+	&corner_set_points,
+};
+
+#define LDO(_id, _name, _name_pc, _ranges, _hpm_min_load) \
+	[RPM_VREG_ID_PM8038_##_id] = { \
+		.req = { \
+			[0] = { .id = MSM_RPM_ID_PM8038_##_id##_0, }, \
+			[1] = { .id = MSM_RPM_ID_PM8038_##_id##_1, }, \
+		}, \
+		.hpm_min_load  = RPM_VREG_8930_##_hpm_min_load##_HPM_MIN_LOAD, \
+		.type		 = RPM_REGULATOR_TYPE_LDO, \
+		.set_points	 = &_ranges##_set_points, \
+		.part		 = &ldo_parts, \
+		.id		 = RPM_VREG_ID_PM8038_##_id, \
+		.rdesc.name	 = _name, \
+		.rdesc_pc.name	 = _name_pc, \
+	}
+
+#define SMPS(_id, _name, _name_pc, _ranges, _hpm_min_load) \
+	[RPM_VREG_ID_PM8038_##_id] = { \
+		.req = { \
+			[0] = { .id = MSM_RPM_ID_PM8038_##_id##_0, }, \
+			[1] = { .id = MSM_RPM_ID_PM8038_##_id##_1, }, \
+		}, \
+		.hpm_min_load  = RPM_VREG_8930_##_hpm_min_load##_HPM_MIN_LOAD, \
+		.type		 = RPM_REGULATOR_TYPE_SMPS, \
+		.set_points	 = &_ranges##_set_points, \
+		.part		 = &smps_parts, \
+		.id		 = RPM_VREG_ID_PM8038_##_id, \
+		.rdesc.name	 = _name, \
+		.rdesc_pc.name	 = _name_pc, \
+	}
+
+#define LVS(_id, _name, _name_pc) \
+	[RPM_VREG_ID_PM8038_##_id] = { \
+		.req = { \
+			[0] = { .id = MSM_RPM_ID_PM8038_##_id, }, \
+			[1] = { .id = -1, }, \
+		}, \
+		.type		 = RPM_REGULATOR_TYPE_VS, \
+		.part		 = &switch_parts, \
+		.id		 = RPM_VREG_ID_PM8038_##_id, \
+		.rdesc.name	 = _name, \
+		.rdesc_pc.name	 = _name_pc, \
+	}
+
+#define CORNER(_id, _rpm_id, _name, _ranges) \
+	[RPM_VREG_ID_PM8038_##_id] = { \
+		.req = { \
+			[0] = { .id = MSM_RPM_ID_##_rpm_id, }, \
+			[1] = { .id = -1, }, \
+		}, \
+		.type		 = RPM_REGULATOR_TYPE_CORNER, \
+		.set_points	 = &_ranges##_set_points, \
+		.part		 = &corner_parts, \
+		.id		 = RPM_VREG_ID_PM8038_##_id, \
+		.rdesc.name	 = _name, \
+	}
+
+static struct vreg vregs[] = {
+	LDO(L1,   "8038_l1",   NULL,          nldo1200, LDO_1200),
+	LDO(L2,   "8038_l2",   "8038_l2_pc",  nldo,     LDO_150),
+	LDO(L3,   "8038_l3",   "8038_l3_pc",  pldo,     LDO_50),
+	LDO(L4,   "8038_l4",   "8038_l4_pc",  pldo,     LDO_50),
+	LDO(L5,   "8038_l5",   "8038_l5_pc",  pldo,     LDO_600),
+	LDO(L6,   "8038_l6",   "8038_l6_pc",  pldo,     LDO_600),
+	LDO(L7,   "8038_l7",   "8038_l7_pc",  pldo,     LDO_600),
+	LDO(L8,   "8038_l8",   "8038_l8_pc",  pldo,     LDO_300),
+	LDO(L9,   "8038_l9",   "8038_l9_pc",  pldo,     LDO_300),
+	LDO(L10,  "8038_l10",  "8038_l10_pc", pldo,     LDO_600),
+	LDO(L11,  "8038_l11",  "8038_l11_pc", pldo,     LDO_600),
+	LDO(L12,  "8038_l12",  "8038_l12_pc", nldo,     LDO_300),
+	LDO(L14,  "8038_l14",  "8038_l14_pc", pldo,     LDO_50),
+	LDO(L15,  "8038_l15",  "8038_l15_pc", pldo,     LDO_150),
+	LDO(L16,  "8038_l16",  NULL,          nldo1200, LDO_1200),
+	LDO(L17,  "8038_l17",  "8038_l17_pc", pldo,     LDO_150),
+	LDO(L18,  "8038_l18",  "8038_l18_pc", pldo,     LDO_50),
+	LDO(L19,  "8038_l19",  NULL,          nldo1200, LDO_1200),
+	LDO(L20,  "8038_l20",  NULL,          nldo1200, LDO_1200),
+	LDO(L21,  "8038_l21",  "8038_l21_pc", pldo,     LDO_150),
+	LDO(L22,  "8038_l22",  "8038_l22_pc", pldo,     LDO_50),
+	LDO(L23,  "8038_l23",  "8038_l23_pc", pldo,     LDO_50),
+	LDO(L24,  "8038_l24",  NULL,          nldo1200, LDO_1200),
+	LDO(L26,  "8038_l26",  "8038_l26_pc", nldo,     LDO_150),
+	LDO(L27,  "8038_l27",  NULL,          nldo1200, LDO_1200),
+
+	SMPS(S1,  "8038_s1",   "8038_s1_pc",  smps,     SMPS_1500),
+	SMPS(S2,  "8038_s2",   "8038_s2_pc",  smps,     SMPS_1500),
+	SMPS(S3,  "8038_s3",   "8038_s3_pc",  smps,     SMPS_1500),
+	SMPS(S4,  "8038_s4",   "8038_s4_pc",  smps,     SMPS_1500),
+	SMPS(S5,  "8038_s5",   NULL,          ftsmps,   SMPS_2000),
+	SMPS(S6,  "8038_s6",   NULL,          ftsmps,   SMPS_2000),
+
+	LVS(LVS1, "8038_lvs1", "8038_lvs1_pc"),
+	LVS(LVS2, "8038_lvs2", "8038_lvs2_pc"),
+
+	CORNER(VDD_DIG_CORNER, VOLTAGE_CORNER, "vdd_dig_corner", corner),
+};
+
+static const char *pin_func_label[] = {
+	[RPM_VREG_PIN_FN_8930_DONT_CARE]	= "don't care",
+	[RPM_VREG_PIN_FN_8930_ENABLE]		= "on/off",
+	[RPM_VREG_PIN_FN_8930_MODE]		= "HPM/LPM",
+	[RPM_VREG_PIN_FN_8930_SLEEP_B]		= "sleep_b",
+	[RPM_VREG_PIN_FN_8930_NONE]		= "none",
+};
+
+static const char *force_mode_label[] = {
+	[RPM_VREG_FORCE_MODE_8930_NONE]		= "none",
+	[RPM_VREG_FORCE_MODE_8930_LPM]		= "LPM",
+	[RPM_VREG_FORCE_MODE_8930_AUTO]		= "auto",
+	[RPM_VREG_FORCE_MODE_8930_HPM]		= "HPM",
+	[RPM_VREG_FORCE_MODE_8930_BYPASS]	= "BYP",
+};
+
+static const char *power_mode_label[] = {
+	[RPM_VREG_POWER_MODE_8930_HYSTERETIC]	= "HYS",
+	[RPM_VREG_POWER_MODE_8930_PWM]		= "PWM",
+};
+
+static const char *pin_control_label[] = {
+	" D1",
+	" A0",
+	" A1",
+	" A2",
+};
+
+static int is_real_id(int id)
+{
+	return (id >= 0) && (id <= RPM_VREG_ID_PM8038_MAX_REAL);
+}
+
+static int pc_id_to_real_id(int id)
+{
+	int real_id = 0;
+
+	if (id >= RPM_VREG_ID_PM8038_L2_PC && id <= RPM_VREG_ID_PM8038_L15_PC)
+		real_id = id - RPM_VREG_ID_PM8038_L2_PC;
+	else if (id >= RPM_VREG_ID_PM8038_L17_PC
+			&& id <= RPM_VREG_ID_PM8038_L18_PC)
+		real_id = id - RPM_VREG_ID_PM8038_L17_PC
+				+ RPM_VREG_ID_PM8038_L17;
+	else if (id >= RPM_VREG_ID_PM8038_L21_PC
+			&& id <= RPM_VREG_ID_PM8038_L23_PC)
+		real_id = id - RPM_VREG_ID_PM8038_L21_PC
+				+ RPM_VREG_ID_PM8038_L21;
+	else if (id == RPM_VREG_ID_PM8038_L26_PC)
+		real_id = RPM_VREG_ID_PM8038_L26;
+	else if (id >= RPM_VREG_ID_PM8038_S1_PC
+			&& id <= RPM_VREG_ID_PM8038_S4_PC)
+		real_id = id - RPM_VREG_ID_PM8038_S1_PC
+				+ RPM_VREG_ID_PM8038_S1;
+	else if (id >= RPM_VREG_ID_PM8038_LVS1_PC
+			&& id <= RPM_VREG_ID_PM8038_LVS2_PC)
+		real_id = id - RPM_VREG_ID_PM8038_LVS1_PC
+				+ RPM_VREG_ID_PM8038_LVS1;
+
+	return real_id;
+}
+
+static struct vreg_config config = {
+	.vregs			= vregs,
+	.vregs_len		= ARRAY_SIZE(vregs),
+
+	.vreg_id_min		= RPM_VREG_ID_PM8038_L1,
+	.vreg_id_max		= RPM_VREG_ID_PM8038_MAX,
+
+	.pin_func_none		= RPM_VREG_PIN_FN_8930_NONE,
+	.pin_func_sleep_b	= RPM_VREG_PIN_FN_8930_SLEEP_B,
+
+	.mode_lpm		= REGULATOR_MODE_IDLE,
+	.mode_hpm		= REGULATOR_MODE_NORMAL,
+
+	.set_points		= all_set_points,
+	.set_points_len		= ARRAY_SIZE(all_set_points),
+
+	.label_pin_ctrl		= pin_control_label,
+	.label_pin_ctrl_len	= ARRAY_SIZE(pin_control_label),
+	.label_pin_func		= pin_func_label,
+	.label_pin_func_len	= ARRAY_SIZE(pin_func_label),
+	.label_force_mode	= force_mode_label,
+	.label_force_mode_len	= ARRAY_SIZE(force_mode_label),
+	.label_power_mode	= power_mode_label,
+	.label_power_mode_len	= ARRAY_SIZE(power_mode_label),
+
+	.is_real_id		= is_real_id,
+	.pc_id_to_real_id	= pc_id_to_real_id,
+};
+
+struct vreg_config *get_config_8930(void)
+{
+	return &config;
+}
diff --git a/arch/arm/mach-msm/rpm-regulator-8960.c b/arch/arm/mach-msm/rpm-regulator-8960.c
new file mode 100644
index 0000000..8726ed4
--- /dev/null
+++ b/arch/arm/mach-msm/rpm-regulator-8960.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include "rpm-regulator-private.h"
+
+/* RPM regulator request formats */
+static struct rpm_vreg_parts ldo_parts = {
+	.request_len	= 2,
+	.uV		= REQUEST_MEMBER(0, 0x007FFFFF,  0),
+	.pd		= REQUEST_MEMBER(0, 0x00800000, 23),
+	.pc		= REQUEST_MEMBER(0, 0x0F000000, 24),
+	.pf		= REQUEST_MEMBER(0, 0xF0000000, 28),
+	.ip		= REQUEST_MEMBER(1, 0x000003FF,  0),
+	.ia		= REQUEST_MEMBER(1, 0x000FFC00, 10),
+	.fm		= REQUEST_MEMBER(1, 0x00700000, 20),
+};
+
+static struct rpm_vreg_parts smps_parts = {
+	.request_len	= 2,
+	.uV		= REQUEST_MEMBER(0, 0x007FFFFF,  0),
+	.pd		= REQUEST_MEMBER(0, 0x00800000, 23),
+	.pc		= REQUEST_MEMBER(0, 0x0F000000, 24),
+	.pf		= REQUEST_MEMBER(0, 0xF0000000, 28),
+	.ip		= REQUEST_MEMBER(1, 0x000003FF,  0),
+	.ia		= REQUEST_MEMBER(1, 0x000FFC00, 10),
+	.fm		= REQUEST_MEMBER(1, 0x00700000, 20),
+	.pm		= REQUEST_MEMBER(1, 0x00800000, 23),
+	.freq		= REQUEST_MEMBER(1, 0x1F000000, 24),
+	.freq_clk_src	= REQUEST_MEMBER(1, 0x60000000, 29),
+};
+
+static struct rpm_vreg_parts switch_parts = {
+	.request_len	= 1,
+	.enable_state	= REQUEST_MEMBER(0, 0x00000001,  0),
+	.pd		= REQUEST_MEMBER(0, 0x00000002,  1),
+	.pc		= REQUEST_MEMBER(0, 0x0000003C,  2),
+	.pf		= REQUEST_MEMBER(0, 0x000003C0,  6),
+	.hpm		= REQUEST_MEMBER(0, 0x00000C00, 10),
+};
+
+static struct rpm_vreg_parts ncp_parts = {
+	.request_len	= 1,
+	.uV		= REQUEST_MEMBER(0, 0x007FFFFF,  0),
+	.enable_state	= REQUEST_MEMBER(0, 0x00800000, 23),
+	.comp_mode	= REQUEST_MEMBER(0, 0x01000000, 24),
+	.freq		= REQUEST_MEMBER(0, 0x3E000000, 25),
+};
+
+/* Physically available PMIC regulator voltage setpoint ranges */
+static struct vreg_range pldo_ranges[] = {
+	VOLTAGE_RANGE( 750000, 1487500, 12500),
+	VOLTAGE_RANGE(1500000, 3075000, 25000),
+	VOLTAGE_RANGE(3100000, 4900000, 50000),
+};
+
+static struct vreg_range nldo_ranges[] = {
+	VOLTAGE_RANGE( 750000, 1537500, 12500),
+};
+
+static struct vreg_range nldo1200_ranges[] = {
+	VOLTAGE_RANGE( 375000,  743750,  6250),
+	VOLTAGE_RANGE( 750000, 1537500, 12500),
+};
+
+static struct vreg_range smps_ranges[] = {
+	VOLTAGE_RANGE( 375000,  737500, 12500),
+	VOLTAGE_RANGE( 750000, 1487500, 12500),
+	VOLTAGE_RANGE(1500000, 3075000, 25000),
+};
+
+static struct vreg_range ftsmps_ranges[] = {
+	VOLTAGE_RANGE( 350000,  650000, 50000),
+	VOLTAGE_RANGE( 700000, 1400000, 12500),
+	VOLTAGE_RANGE(1500000, 3300000, 50000),
+};
+
+static struct vreg_range ncp_ranges[] = {
+	VOLTAGE_RANGE(1500000, 3050000, 50000),
+};
+
+static struct vreg_set_points pldo_set_points = SET_POINTS(pldo_ranges);
+static struct vreg_set_points nldo_set_points = SET_POINTS(nldo_ranges);
+static struct vreg_set_points nldo1200_set_points = SET_POINTS(nldo1200_ranges);
+static struct vreg_set_points smps_set_points = SET_POINTS(smps_ranges);
+static struct vreg_set_points ftsmps_set_points = SET_POINTS(ftsmps_ranges);
+static struct vreg_set_points ncp_set_points = SET_POINTS(ncp_ranges);
+
+static struct vreg_set_points *all_set_points[] = {
+	&pldo_set_points,
+	&nldo_set_points,
+	&nldo1200_set_points,
+	&smps_set_points,
+	&ftsmps_set_points,
+	&ncp_set_points,
+};
+
+#define LDO(_id, _name, _name_pc, _ranges, _hpm_min_load) \
+	[RPM_VREG_ID_PM8921_##_id] = { \
+		.req = { \
+			[0] = { .id = MSM_RPM_ID_PM8921_##_id##_0, }, \
+			[1] = { .id = MSM_RPM_ID_PM8921_##_id##_1, }, \
+		}, \
+		.hpm_min_load  = RPM_VREG_8960_##_hpm_min_load##_HPM_MIN_LOAD, \
+		.type		 = RPM_REGULATOR_TYPE_LDO, \
+		.set_points	 = &_ranges##_set_points, \
+		.part		 = &ldo_parts, \
+		.id		 = RPM_VREG_ID_PM8921_##_id, \
+		.rdesc.name	 = _name, \
+		.rdesc_pc.name	 = _name_pc, \
+	}
+
+#define SMPS(_id, _name, _name_pc, _ranges, _hpm_min_load) \
+	[RPM_VREG_ID_PM8921_##_id] = { \
+		.req = { \
+			[0] = { .id = MSM_RPM_ID_PM8921_##_id##_0, }, \
+			[1] = { .id = MSM_RPM_ID_PM8921_##_id##_1, }, \
+		}, \
+		.hpm_min_load  = RPM_VREG_8960_##_hpm_min_load##_HPM_MIN_LOAD, \
+		.type		 = RPM_REGULATOR_TYPE_SMPS, \
+		.set_points	 = &_ranges##_set_points, \
+		.part		 = &smps_parts, \
+		.id		 = RPM_VREG_ID_PM8921_##_id, \
+		.rdesc.name	 = _name, \
+		.rdesc_pc.name	 = _name_pc, \
+	}
+
+#define LVS(_id, _name, _name_pc) \
+	[RPM_VREG_ID_PM8921_##_id] = { \
+		.req = { \
+			[0] = { .id = MSM_RPM_ID_PM8921_##_id, }, \
+			[1] = { .id = -1, }, \
+		}, \
+		.type		 = RPM_REGULATOR_TYPE_VS, \
+		.part		 = &switch_parts, \
+		.id		 = RPM_VREG_ID_PM8921_##_id, \
+		.rdesc.name	 = _name, \
+		.rdesc_pc.name	 = _name_pc, \
+	}
+
+#define MVS(_vreg_id, _name, _name_pc, _rpm_id) \
+	[RPM_VREG_ID_PM8921_##_vreg_id] = { \
+		.req = { \
+			[0] = { .id = MSM_RPM_ID_##_rpm_id, }, \
+			[1] = { .id = -1, }, \
+		}, \
+		.type		 = RPM_REGULATOR_TYPE_VS, \
+		.part		 = &switch_parts, \
+		.id		 = RPM_VREG_ID_PM8921_##_vreg_id, \
+		.rdesc.name	 = _name, \
+		.rdesc_pc.name	 = _name_pc, \
+	}
+
+#define NCP(_id, _name, _name_pc) \
+	[RPM_VREG_ID_PM8921_##_id] = { \
+		.req = { \
+			[0] = { .id = MSM_RPM_ID_##_id##_0, }, \
+			[1] = { .id = MSM_RPM_ID_##_id##_1, }, \
+		}, \
+		.type		 = RPM_REGULATOR_TYPE_NCP, \
+		.set_points	 = &ncp_set_points, \
+		.part		 = &ncp_parts, \
+		.id		 = RPM_VREG_ID_PM8921_##_id, \
+		.rdesc.name	 = _name, \
+		.rdesc_pc.name	 = _name_pc, \
+	}
+
+static struct vreg vregs[] = {
+	LDO(L1,   "8921_l1",   "8921_l1_pc",  nldo,     LDO_150),
+	LDO(L2,   "8921_l2",   "8921_l2_pc",  nldo,     LDO_150),
+	LDO(L3,   "8921_l3",   "8921_l3_pc",  pldo,     LDO_150),
+	LDO(L4,   "8921_l4",   "8921_l4_pc",  pldo,     LDO_50),
+	LDO(L5,   "8921_l5",   "8921_l5_pc",  pldo,     LDO_300),
+	LDO(L6,   "8921_l6",   "8921_l6_pc",  pldo,     LDO_600),
+	LDO(L7,   "8921_l7",   "8921_l7_pc",  pldo,     LDO_150),
+	LDO(L8,   "8921_l8",   "8921_l8_pc",  pldo,     LDO_300),
+	LDO(L9,   "8921_l9",   "8921_l9_pc",  pldo,     LDO_300),
+	LDO(L10,  "8921_l10",  "8921_l10_pc", pldo,     LDO_600),
+	LDO(L11,  "8921_l11",  "8921_l11_pc", pldo,     LDO_150),
+	LDO(L12,  "8921_l12",  "8921_l12_pc", nldo,     LDO_150),
+	LDO(L14,  "8921_l14",  "8921_l14_pc", pldo,     LDO_50),
+	LDO(L15,  "8921_l15",  "8921_l15_pc", pldo,     LDO_150),
+	LDO(L16,  "8921_l16",  "8921_l16_pc", pldo,     LDO_300),
+	LDO(L17,  "8921_l17",  "8921_l17_pc", pldo,     LDO_150),
+	LDO(L18,  "8921_l18",  "8921_l18_pc", nldo,     LDO_150),
+	LDO(L21,  "8921_l21",  "8921_l21_pc", pldo,     LDO_150),
+	LDO(L22,  "8921_l22",  "8921_l22_pc", pldo,     LDO_150),
+	LDO(L23,  "8921_l23",  "8921_l23_pc", pldo,     LDO_150),
+	LDO(L24,  "8921_l24",  NULL,          nldo1200, LDO_1200),
+	LDO(L25,  "8921_l25",  NULL,          nldo1200, LDO_1200),
+	LDO(L26,  "8921_l26",  NULL,          nldo1200, LDO_1200),
+	LDO(L27,  "8921_l27",  NULL,          nldo1200, LDO_1200),
+	LDO(L28,  "8921_l28",  NULL,          nldo1200, LDO_1200),
+	LDO(L29,  "8921_l29",  "8921_l29_pc", pldo,     LDO_150),
+
+	SMPS(S1,  "8921_s1",   "8921_s1_pc",  smps,     SMPS_1500),
+	SMPS(S2,  "8921_s2",   "8921_s2_pc",  smps,     SMPS_1500),
+	SMPS(S3,  "8921_s3",   "8921_s3_pc",  smps,     SMPS_1500),
+	SMPS(S4,  "8921_s4",   "8921_s4_pc",  smps,     SMPS_1500),
+	SMPS(S5,  "8921_s5",   NULL,          ftsmps,   SMPS_2000),
+	SMPS(S6,  "8921_s6",   NULL,          ftsmps,   SMPS_2000),
+	SMPS(S7,  "8921_s7",   "8921_s7_pc",  smps,     SMPS_1500),
+	SMPS(S8,  "8921_s8",   "8921_s8_pc",  smps,     SMPS_1500),
+
+	LVS(LVS1, "8921_lvs1", "8921_lvs1_pc"),
+	LVS(LVS2, "8921_lvs2", NULL),
+	LVS(LVS3, "8921_lvs3", "8921_lvs3_pc"),
+	LVS(LVS4, "8921_lvs4", "8921_lvs4_pc"),
+	LVS(LVS5, "8921_lvs5", "8921_lvs5_pc"),
+	LVS(LVS6, "8921_lvs6", "8921_lvs6_pc"),
+	LVS(LVS7, "8921_lvs7", "8921_lvs7_pc"),
+	MVS(USB_OTG,  "8921_usb_otg",  NULL, USB_OTG_SWITCH),
+	MVS(HDMI_MVS, "8921_hdmi_mvs", NULL, HDMI_SWITCH),
+
+	NCP(NCP,  "8921_ncp",  NULL),
+};
+
+static const char *pin_func_label[] = {
+	[RPM_VREG_PIN_FN_8960_DONT_CARE]	= "don't care",
+	[RPM_VREG_PIN_FN_8960_ENABLE]		= "on/off",
+	[RPM_VREG_PIN_FN_8960_MODE]		= "HPM/LPM",
+	[RPM_VREG_PIN_FN_8960_SLEEP_B]		= "sleep_b",
+	[RPM_VREG_PIN_FN_8960_NONE]		= "none",
+};
+
+static const char *force_mode_label[] = {
+	[RPM_VREG_FORCE_MODE_8960_NONE]		= "none",
+	[RPM_VREG_FORCE_MODE_8960_LPM]		= "LPM",
+	[RPM_VREG_FORCE_MODE_8960_AUTO]		= "auto",
+	[RPM_VREG_FORCE_MODE_8960_HPM]		= "HPM",
+	[RPM_VREG_FORCE_MODE_8960_BYPASS]	= "BYP",
+};
+
+static const char *power_mode_label[] = {
+	[RPM_VREG_POWER_MODE_8960_HYSTERETIC]	= "HYS",
+	[RPM_VREG_POWER_MODE_8960_PWM]		= "PWM",
+};
+
+static const char *pin_control_label[] = {
+	" D1",
+	" A0",
+	" A1",
+	" A2",
+};
+
+static int is_real_id(int id)
+{
+	return (id >= 0) && (id <= RPM_VREG_ID_PM8921_MAX_REAL);
+}
+
+static int pc_id_to_real_id(int id)
+{
+	int real_id;
+
+	if (id >= RPM_VREG_ID_PM8921_L1_PC && id <= RPM_VREG_ID_PM8921_L23_PC)
+		real_id = id - RPM_VREG_ID_PM8921_L1_PC;
+	else if (id >= RPM_VREG_ID_PM8921_L29_PC
+			&& id <= RPM_VREG_ID_PM8921_S4_PC)
+		real_id = id - RPM_VREG_ID_PM8921_L29_PC
+				+ RPM_VREG_ID_PM8921_L29;
+	else if (id >= RPM_VREG_ID_PM8921_S7_PC
+			&& id <= RPM_VREG_ID_PM8921_LVS1_PC)
+		real_id = id - RPM_VREG_ID_PM8921_S7_PC + RPM_VREG_ID_PM8921_S7;
+	else
+		real_id = id - RPM_VREG_ID_PM8921_LVS3_PC
+				+ RPM_VREG_ID_PM8921_LVS3;
+
+	return real_id;
+}
+
+static struct vreg_config config = {
+	.vregs			= vregs,
+	.vregs_len		= ARRAY_SIZE(vregs),
+
+	.vreg_id_min		= RPM_VREG_ID_PM8921_L1,
+	.vreg_id_max		= RPM_VREG_ID_PM8921_MAX,
+
+	.pin_func_none		= RPM_VREG_PIN_FN_8960_NONE,
+	.pin_func_sleep_b	= RPM_VREG_PIN_FN_8960_SLEEP_B,
+
+	.mode_lpm		= REGULATOR_MODE_IDLE,
+	.mode_hpm		= REGULATOR_MODE_NORMAL,
+
+	.set_points		= all_set_points,
+	.set_points_len		= ARRAY_SIZE(all_set_points),
+
+	.label_pin_ctrl		= pin_control_label,
+	.label_pin_ctrl_len	= ARRAY_SIZE(pin_control_label),
+	.label_pin_func		= pin_func_label,
+	.label_pin_func_len	= ARRAY_SIZE(pin_func_label),
+	.label_force_mode	= force_mode_label,
+	.label_force_mode_len	= ARRAY_SIZE(force_mode_label),
+	.label_power_mode	= power_mode_label,
+	.label_power_mode_len	= ARRAY_SIZE(power_mode_label),
+
+	.is_real_id		= is_real_id,
+	.pc_id_to_real_id	= pc_id_to_real_id,
+};
+
+struct vreg_config *get_config_8960(void)
+{
+	return &config;
+}
diff --git a/arch/arm/mach-msm/rpm-regulator-9615.c b/arch/arm/mach-msm/rpm-regulator-9615.c
new file mode 100644
index 0000000..23c0ee3
--- /dev/null
+++ b/arch/arm/mach-msm/rpm-regulator-9615.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include "rpm-regulator-private.h"
+
+/* RPM regulator request formats */
+static struct rpm_vreg_parts ldo_parts = {
+	.request_len	= 2,
+	.uV		= REQUEST_MEMBER(0, 0x007FFFFF,  0),
+	.pd		= REQUEST_MEMBER(0, 0x00800000, 23),
+	.pc		= REQUEST_MEMBER(0, 0x0F000000, 24),
+	.pf		= REQUEST_MEMBER(0, 0xF0000000, 28),
+	.ip		= REQUEST_MEMBER(1, 0x000003FF,  0),
+	.ia		= REQUEST_MEMBER(1, 0x000FFC00, 10),
+	.fm		= REQUEST_MEMBER(1, 0x00700000, 20),
+};
+
+static struct rpm_vreg_parts smps_parts = {
+	.request_len	= 2,
+	.uV		= REQUEST_MEMBER(0, 0x007FFFFF,  0),
+	.pd		= REQUEST_MEMBER(0, 0x00800000, 23),
+	.pc		= REQUEST_MEMBER(0, 0x0F000000, 24),
+	.pf		= REQUEST_MEMBER(0, 0xF0000000, 28),
+	.ip		= REQUEST_MEMBER(1, 0x000003FF,  0),
+	.ia		= REQUEST_MEMBER(1, 0x000FFC00, 10),
+	.fm		= REQUEST_MEMBER(1, 0x00700000, 20),
+	.pm		= REQUEST_MEMBER(1, 0x00800000, 23),
+	.freq		= REQUEST_MEMBER(1, 0x1F000000, 24),
+	.freq_clk_src	= REQUEST_MEMBER(1, 0x60000000, 29),
+};
+
+static struct rpm_vreg_parts switch_parts = {
+	.request_len	= 1,
+	.enable_state	= REQUEST_MEMBER(0, 0x00000001,  0),
+	.pd		= REQUEST_MEMBER(0, 0x00000002,  1),
+	.pc		= REQUEST_MEMBER(0, 0x0000003C,  2),
+	.pf		= REQUEST_MEMBER(0, 0x000003C0,  6),
+	.hpm		= REQUEST_MEMBER(0, 0x00000C00, 10),
+};
+
+/* Physically available PMIC regulator voltage setpoint ranges */
+static struct vreg_range pldo_ranges[] = {
+	VOLTAGE_RANGE( 750000, 1487500, 12500),
+	VOLTAGE_RANGE(1500000, 3075000, 25000),
+	VOLTAGE_RANGE(3100000, 4900000, 50000),
+};
+
+static struct vreg_range nldo_ranges[] = {
+	VOLTAGE_RANGE( 750000, 1537500, 12500),
+};
+
+static struct vreg_range nldo1200_ranges[] = {
+	VOLTAGE_RANGE( 375000,  743750,  6250),
+	VOLTAGE_RANGE( 750000, 1537500, 12500),
+};
+
+static struct vreg_range smps_ranges[] = {
+	VOLTAGE_RANGE( 375000,  737500, 12500),
+	VOLTAGE_RANGE( 750000, 1487500, 12500),
+	VOLTAGE_RANGE(1500000, 3075000, 25000),
+};
+
+static struct vreg_set_points pldo_set_points = SET_POINTS(pldo_ranges);
+static struct vreg_set_points nldo_set_points = SET_POINTS(nldo_ranges);
+static struct vreg_set_points nldo1200_set_points = SET_POINTS(nldo1200_ranges);
+static struct vreg_set_points smps_set_points = SET_POINTS(smps_ranges);
+
+static struct vreg_set_points *all_set_points[] = {
+	&pldo_set_points,
+	&nldo_set_points,
+	&nldo1200_set_points,
+	&smps_set_points,
+};
+
+#define LDO(_id, _name, _name_pc, _ranges, _hpm_min_load) \
+	[RPM_VREG_ID_PM8018_##_id] = { \
+		.req = { \
+			[0] = { .id = MSM_RPM_ID_PM8018_##_id##_0, }, \
+			[1] = { .id = MSM_RPM_ID_PM8018_##_id##_1, }, \
+		}, \
+		.hpm_min_load  = RPM_VREG_9615_##_hpm_min_load##_HPM_MIN_LOAD, \
+		.type		 = RPM_REGULATOR_TYPE_LDO, \
+		.set_points	 = &_ranges##_set_points, \
+		.part		 = &ldo_parts, \
+		.id		 = RPM_VREG_ID_PM8018_##_id, \
+		.rdesc.name	 = _name, \
+		.rdesc_pc.name	 = _name_pc, \
+	}
+
+#define SMPS(_id, _name, _name_pc, _ranges, _hpm_min_load) \
+	[RPM_VREG_ID_PM8018_##_id] = { \
+		.req = { \
+			[0] = { .id = MSM_RPM_ID_PM8018_##_id##_0, }, \
+			[1] = { .id = MSM_RPM_ID_PM8018_##_id##_1, }, \
+		}, \
+		.hpm_min_load  = RPM_VREG_9615_##_hpm_min_load##_HPM_MIN_LOAD, \
+		.type		 = RPM_REGULATOR_TYPE_SMPS, \
+		.set_points	 = &_ranges##_set_points, \
+		.part		 = &smps_parts, \
+		.id		 = RPM_VREG_ID_PM8018_##_id, \
+		.rdesc.name	 = _name, \
+		.rdesc_pc.name	 = _name_pc, \
+	}
+
+#define LVS(_id, _name, _name_pc) \
+	[RPM_VREG_ID_PM8018_##_id] = { \
+		.req = { \
+			[0] = { .id = MSM_RPM_ID_PM8018_##_id, }, \
+			[1] = { .id = -1, }, \
+		}, \
+		.type		 = RPM_REGULATOR_TYPE_VS, \
+		.part		 = &switch_parts, \
+		.id		 = RPM_VREG_ID_PM8018_##_id, \
+		.rdesc.name	 = _name, \
+		.rdesc_pc.name	 = _name_pc, \
+	}
+
+static struct vreg vregs[] = {
+	LDO(L2,   "8018_l2",   "8018_l2_pc",  pldo,     LDO_50),
+	LDO(L3,   "8018_l3",   "8018_l3_pc",  pldo,     LDO_50),
+	LDO(L4,   "8018_l4",   "8018_l4_pc",  pldo,     LDO_300),
+	LDO(L5,   "8018_l5",   "8018_l5_pc",  pldo,     LDO_150),
+	LDO(L6,   "8018_l6",   "8018_l6_pc",  pldo,     LDO_150),
+	LDO(L7,   "8018_l7",   "8018_l7_pc",  pldo,     LDO_300),
+	LDO(L8,   "8018_l8",   "8018_l8_pc",  nldo,     LDO_150),
+	LDO(L9,   "8018_l9",   NULL,          nldo1200, LDO_1200),
+	LDO(L10,  "8018_l10",  NULL,          nldo1200, LDO_1200),
+	LDO(L11,  "8018_l11",  NULL,          nldo1200, LDO_1200),
+	LDO(L12,  "8018_l12",  NULL,          nldo1200, LDO_1200),
+	LDO(L13,  "8018_l13",  "8018_l13_pc", pldo,     LDO_50),
+	LDO(L14,  "8018_l14",  "8018_l14_pc", pldo,     LDO_50),
+
+	SMPS(S1,  "8018_s1",   "8018_s1_pc",  smps,     SMPS_1500),
+	SMPS(S2,  "8018_s2",   "8018_s2_pc",  smps,     SMPS_1500),
+	SMPS(S3,  "8018_s3",   "8018_s3_pc",  smps,     SMPS_1500),
+	SMPS(S4,  "8018_s4",   "8018_s4_pc",  smps,     SMPS_1500),
+	SMPS(S5,  "8018_s5",   "8018_s5_pc",  smps,     SMPS_1500),
+
+	LVS(LVS1, "8018_lvs1", "8018_lvs1_pc"),
+};
+
+static const char *pin_control_label[] = {
+	" D1",
+	" A0",
+	" A1",
+	" A2",
+};
+
+static const char *pin_func_label[] = {
+	[RPM_VREG_PIN_FN_9615_DONT_CARE]	= "don't care",
+	[RPM_VREG_PIN_FN_9615_ENABLE]		= "on/off",
+	[RPM_VREG_PIN_FN_9615_MODE]		= "HPM/LPM",
+	[RPM_VREG_PIN_FN_9615_SLEEP_B]		= "sleep_b",
+	[RPM_VREG_PIN_FN_9615_NONE]		= "none",
+};
+
+static const char *force_mode_label[] = {
+	[RPM_VREG_FORCE_MODE_9615_NONE]		= "none",
+	[RPM_VREG_FORCE_MODE_9615_LPM]		= "LPM",
+	[RPM_VREG_FORCE_MODE_9615_AUTO]		= "auto",
+	[RPM_VREG_FORCE_MODE_9615_HPM]		= "HPM",
+	[RPM_VREG_FORCE_MODE_9615_BYPASS]	= "BYP",
+};
+
+static const char *power_mode_label[] = {
+	[RPM_VREG_POWER_MODE_9615_HYSTERETIC]	= "HYS",
+	[RPM_VREG_POWER_MODE_9615_PWM]		= "PWM",
+};
+
+static int is_real_id(int id)
+{
+	return (id >= 0) && (id <= RPM_VREG_ID_PM8018_MAX_REAL);
+}
+
+static int pc_id_to_real_id(int id)
+{
+	int real_id;
+
+	if (id >= RPM_VREG_ID_PM8018_L2_PC && id <= RPM_VREG_ID_PM8018_L8_PC)
+		real_id = id - RPM_VREG_ID_PM8018_L2_PC + RPM_VREG_ID_PM8018_L2;
+	else
+		real_id = id - RPM_VREG_ID_PM8018_L13_PC
+				+ RPM_VREG_ID_PM8018_L13;
+
+	return real_id;
+}
+
+static struct vreg_config config = {
+	.vregs			= vregs,
+	.vregs_len		= ARRAY_SIZE(vregs),
+
+	.vreg_id_min		= RPM_VREG_ID_PM8018_L2,
+	.vreg_id_max		= RPM_VREG_ID_PM8018_MAX,
+
+	.pin_func_none		= RPM_VREG_PIN_FN_9615_NONE,
+	.pin_func_sleep_b	= RPM_VREG_PIN_FN_9615_SLEEP_B,
+
+	.mode_lpm		= REGULATOR_MODE_IDLE,
+	.mode_hpm		= REGULATOR_MODE_NORMAL,
+
+	.set_points		= all_set_points,
+	.set_points_len		= ARRAY_SIZE(all_set_points),
+
+	.label_pin_ctrl		= pin_control_label,
+	.label_pin_ctrl_len	= ARRAY_SIZE(pin_control_label),
+	.label_pin_func		= pin_func_label,
+	.label_pin_func_len	= ARRAY_SIZE(pin_func_label),
+	.label_force_mode	= force_mode_label,
+	.label_force_mode_len	= ARRAY_SIZE(force_mode_label),
+	.label_power_mode	= power_mode_label,
+	.label_power_mode_len	= ARRAY_SIZE(power_mode_label),
+
+	.is_real_id		= is_real_id,
+	.pc_id_to_real_id	= pc_id_to_real_id,
+};
+
+struct vreg_config *get_config_9615(void)
+{
+	return &config;
+}
diff --git a/arch/arm/mach-msm/rpm-regulator-private.h b/arch/arm/mach-msm/rpm-regulator-private.h
new file mode 100644
index 0000000..d4f9a8a
--- /dev/null
+++ b/arch/arm/mach-msm/rpm-regulator-private.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_RPM_REGULATOR_INT_H
+#define __ARCH_ARM_MACH_MSM_RPM_REGULATOR_INT_H
+
+#include <linux/regulator/driver.h>
+#include <mach/rpm.h>
+#include <mach/rpm-regulator.h>
+
+/* Possible RPM regulator request types */
+enum rpm_regulator_type {
+	RPM_REGULATOR_TYPE_LDO,
+	RPM_REGULATOR_TYPE_SMPS,
+	RPM_REGULATOR_TYPE_VS,
+	RPM_REGULATOR_TYPE_NCP,
+	RPM_REGULATOR_TYPE_CORNER,
+	RPM_REGULATOR_TYPE_MAX = RPM_REGULATOR_TYPE_CORNER,
+};
+
+struct request_member {
+	int			word;
+	unsigned int		mask;
+	int			shift;
+};
+
+/* Possible RPM regulator request members */
+struct rpm_vreg_parts {
+	struct request_member	mV;	/* voltage: used if voltage is in mV */
+	struct request_member	uV;	/* voltage: used if voltage is in uV */
+	struct request_member	ip;		/* peak current in mA */
+	struct request_member	pd;		/* pull down enable */
+	struct request_member	ia;		/* average current in mA */
+	struct request_member	fm;		/* force mode */
+	struct request_member	pm;		/* power mode */
+	struct request_member	pc;		/* pin control */
+	struct request_member	pf;		/* pin function */
+	struct request_member	enable_state;	/* NCP and switch */
+	struct request_member	comp_mode;	/* NCP */
+	struct request_member	freq;		/* frequency: NCP and SMPS */
+	struct request_member	freq_clk_src;	/* clock source: SMPS */
+	struct request_member	hpm;		/* switch: control OCP and SS */
+	int			request_len;
+};
+
+struct vreg_range {
+	int			min_uV;
+	int			max_uV;
+	int			step_uV;
+	unsigned		n_voltages;
+};
+
+struct vreg_set_points {
+	struct vreg_range	*range;
+	int			count;
+	unsigned		n_voltages;
+};
+
+struct vreg {
+	struct msm_rpm_iv_pair		req[2];
+	struct msm_rpm_iv_pair		prev_active_req[2];
+	struct msm_rpm_iv_pair		prev_sleep_req[2];
+	struct rpm_regulator_init_data	pdata;
+	struct regulator_desc		rdesc;
+	struct regulator_desc		rdesc_pc;
+	struct regulator_dev		*rdev;
+	struct regulator_dev		*rdev_pc;
+	struct vreg_set_points		*set_points;
+	struct rpm_vreg_parts		*part;
+	int				type;
+	int				id;
+	struct mutex			pc_lock;
+	int				save_uV;
+	int				mode;
+	bool				is_enabled;
+	bool				is_enabled_pc;
+	const int			hpm_min_load;
+	int			       active_min_uV_vote[RPM_VREG_VOTER_COUNT];
+	int				sleep_min_uV_vote[RPM_VREG_VOTER_COUNT];
+};
+
+struct vreg_config {
+	struct vreg			*vregs;
+	int				vregs_len;
+
+	int				vreg_id_min;
+	int				vreg_id_max;
+
+	int				pin_func_none;
+	int				pin_func_sleep_b;
+
+	unsigned int			mode_lpm;
+	unsigned int			mode_hpm;
+
+	struct vreg_set_points		**set_points;
+	int				set_points_len;
+
+	const char			**label_pin_ctrl;
+	int				label_pin_ctrl_len;
+	const char			**label_pin_func;
+	int				label_pin_func_len;
+	const char			**label_force_mode;
+	int				label_force_mode_len;
+	const char			**label_power_mode;
+	int				label_power_mode_len;
+
+	int				(*is_real_id) (int vreg_id);
+	int				(*pc_id_to_real_id) (int vreg_id);
+
+	/* Legacy options to be used with MSM8660 */
+	int				use_legacy_optimum_mode;
+	int				ia_follows_ip;
+};
+
+#define REQUEST_MEMBER(_word, _mask, _shift) \
+	{ \
+		.word	= _word, \
+		.mask	= _mask, \
+		.shift	= _shift, \
+	}
+
+#define VOLTAGE_RANGE(_min_uV, _max_uV, _step_uV) \
+	{ \
+		.min_uV  = _min_uV, \
+		.max_uV  = _max_uV, \
+		.step_uV = _step_uV, \
+	}
+
+#define SET_POINTS(_ranges) \
+{ \
+	.range	= _ranges, \
+	.count	= ARRAY_SIZE(_ranges), \
+};
+
+#define MICRO_TO_MILLI(uV)			((uV) / 1000)
+#define MILLI_TO_MICRO(mV)			((mV) * 1000)
+
+#if defined(CONFIG_MSM_RPM_REGULATOR) && defined(CONFIG_ARCH_MSM8X60)
+struct vreg_config *get_config_8660(void);
+#else
+static inline struct vreg_config *get_config_8660(void)
+{
+	return NULL;
+}
+#endif
+
+#if defined(CONFIG_MSM_RPM_REGULATOR) && \
+	(defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_APQ8064))
+struct vreg_config *get_config_8960(void);
+#else
+static inline struct vreg_config *get_config_8960(void)
+{
+	return NULL;
+}
+#endif
+
+#if defined(CONFIG_MSM_RPM_REGULATOR) && defined(CONFIG_ARCH_MSM9615)
+struct vreg_config *get_config_9615(void);
+#else
+static inline struct vreg_config *get_config_9615(void)
+{
+	return NULL;
+}
+#endif
+
+#if defined(CONFIG_MSM_RPM_REGULATOR) && defined(CONFIG_ARCH_MSM8930)
+struct vreg_config *get_config_8930(void);
+#else
+static inline struct vreg_config *get_config_8930(void)
+{
+	return NULL;
+}
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/rpm-regulator-smd.c b/arch/arm/mach-msm/rpm-regulator-smd.c
new file mode 100644
index 0000000..b892d05
--- /dev/null
+++ b/arch/arm/mach-msm/rpm-regulator-smd.c
@@ -0,0 +1,1430 @@
+/* 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <mach/rpm-smd.h>
+#include <mach/rpm-regulator-smd.h>
+#include <mach/socinfo.h>
+
+/* Debug Definitions */
+
+enum {
+	RPM_VREG_DEBUG_REQUEST		= BIT(0),
+	RPM_VREG_DEBUG_FULL_REQUEST	= BIT(1),
+	RPM_VREG_DEBUG_DUPLICATE	= BIT(2),
+};
+
+static int rpm_vreg_debug_mask;
+module_param_named(
+	debug_mask, rpm_vreg_debug_mask, int, S_IRUSR | S_IWUSR
+);
+
+#define vreg_err(req, fmt, ...) \
+	pr_err("%s: " fmt, req->rdesc.name, ##__VA_ARGS__)
+
+/* RPM regulator request types */
+enum rpm_regulator_smd_type {
+	RPM_REGULATOR_SMD_TYPE_LDO,
+	RPM_REGULATOR_SMD_TYPE_SMPS,
+	RPM_REGULATOR_SMD_TYPE_VS,
+	RPM_REGULATOR_SMD_TYPE_NCP,
+	RPM_REGULATOR_SMD_TYPE_MAX,
+};
+
+/* RPM resource parameters */
+enum rpm_regulator_param_index {
+	RPM_REGULATOR_PARAM_ENABLE,
+	RPM_REGULATOR_PARAM_VOLTAGE,
+	RPM_REGULATOR_PARAM_CURRENT,
+	RPM_REGULATOR_PARAM_MODE_LDO,
+	RPM_REGULATOR_PARAM_MODE_SMPS,
+	RPM_REGULATOR_PARAM_PIN_CTRL_ENABLE,
+	RPM_REGULATOR_PARAM_PIN_CTRL_MODE,
+	RPM_REGULATOR_PARAM_FREQUENCY,
+	RPM_REGULATOR_PARAM_HEAD_ROOM,
+	RPM_REGULATOR_PARAM_QUIET_MODE,
+	RPM_REGULATOR_PARAM_FREQ_REASON,
+	RPM_REGULATOR_PARAM_MAX,
+};
+
+#define RPM_SET_CONFIG_ACTIVE			BIT(0)
+#define RPM_SET_CONFIG_SLEEP			BIT(1)
+#define RPM_SET_CONFIG_BOTH			(RPM_SET_CONFIG_ACTIVE \
+						 | RPM_SET_CONFIG_SLEEP)
+struct rpm_regulator_param {
+	char	*name;
+	char	*property_name;
+	u32	key;
+	u32	min;
+	u32	max;
+	u32	supported_regulator_types;
+};
+
+#define PARAM(_idx, _support_ldo, _support_smps, _support_vs, _support_ncp, \
+		_name, _min, _max, _property_name)	\
+	[RPM_REGULATOR_PARAM_##_idx] = { \
+		.name = _name, \
+		.property_name = _property_name, \
+		.min = _min, \
+		.max = _max, \
+		.supported_regulator_types = \
+			_support_ldo << RPM_REGULATOR_SMD_TYPE_LDO | \
+			_support_smps << RPM_REGULATOR_SMD_TYPE_SMPS | \
+			_support_vs << RPM_REGULATOR_SMD_TYPE_VS | \
+			_support_ncp << RPM_REGULATOR_SMD_TYPE_NCP, \
+	}
+
+static struct rpm_regulator_param params[RPM_REGULATOR_PARAM_MAX] = {
+	/*    ID             LDO SMPS VS  NCP  name  min max          property-name */
+	PARAM(ENABLE,          1,  1,  1,  1, "swen", 0, 1,          "qcom,init-enable"),
+	PARAM(VOLTAGE,         1,  1,  0,  1, "uv",   0, 0x7FFFFFF,  "qcom,init-voltage"),
+	PARAM(CURRENT,         1,  1,  0,  0, "ma",   0, 0x1FFF,     "qcom,init-current"),
+	PARAM(MODE_LDO,        1,  0,  0,  0, "lsmd", 0, 1,          "qcom,init-ldo-mode"),
+	PARAM(MODE_SMPS,       0,  1,  0,  0, "ssmd", 0, 2,          "qcom,init-smps-mode"),
+	PARAM(PIN_CTRL_ENABLE, 1,  1,  1,  0, "pcen", 0, 0xF,        "qcom,init-pin-ctrl-enable"),
+	PARAM(PIN_CTRL_MODE,   1,  1,  1,  0, "pcmd", 0, 0x1F,       "qcom,init-pin-ctrl-mode"),
+	PARAM(FREQUENCY,       0,  1,  0,  1, "freq", 0, 16,         "qcom,init-frequency"),
+	PARAM(HEAD_ROOM,       1,  0,  0,  1, "hr",   0, 0x7FFFFFFF, "qcom,init-head-room"),
+	PARAM(QUIET_MODE,      0,  1,  0,  0, "qm",   0, 2,          "qcom,init-quiet-mode"),
+	PARAM(FREQ_REASON,     0,  1,  0,  1, "resn", 0, 8,          "qcom,init-freq-reason"),
+};
+
+struct rpm_vreg_request {
+	u32			param[RPM_REGULATOR_PARAM_MAX];
+	u32			valid;
+	u32			modified;
+};
+
+struct rpm_vreg {
+	struct rpm_vreg_request	aggr_req_active;
+	struct rpm_vreg_request	aggr_req_sleep;
+	struct list_head	reg_list;
+	const char		*resource_name;
+	u32			resource_id;
+	bool			allow_atomic;
+	int			regulator_type;
+	int			hpm_min_load;
+	int			enable_time;
+	struct spinlock		slock;
+	struct mutex		mlock;
+	unsigned long		flags;
+	bool			sleep_request_sent;
+	struct msm_rpm_request	*handle_active;
+	struct msm_rpm_request	*handle_sleep;
+};
+
+struct rpm_regulator {
+	struct regulator_desc	rdesc;
+	struct regulator_dev	*rdev;
+	struct rpm_vreg		*rpm_vreg;
+	struct list_head	list;
+	bool			set_active;
+	bool			set_sleep;
+	struct rpm_vreg_request	req;
+	int			system_load;
+	int			min_uV;
+	int			max_uV;
+};
+
+/*
+ * This voltage in uV is returned by get_voltage functions when there is no way
+ * to determine the current voltage level.  It is needed because the regulator
+ * framework treats a 0 uV voltage as an error.
+ */
+#define VOLTAGE_UNKNOWN 1
+
+/*
+ * Regulator requests sent in the active set take effect immediately.  Requests
+ * sent in the sleep set take effect when the Apps processor transitions into
+ * RPM assisted power collapse.  For any given regulator, if an active set
+ * request is present, but not a sleep set request, then the active set request
+ * is used at all times, even when the Apps processor is power collapsed.
+ *
+ * The rpm-regulator-smd takes advantage of this default usage of the active set
+ * request by only sending a sleep set request if it differs from the
+ * corresponding active set request.
+ */
+#define RPM_SET_ACTIVE	MSM_RPM_CTX_ACTIVE_SET
+#define RPM_SET_SLEEP	MSM_RPM_CTX_SLEEP_SET
+
+static u32 rpm_vreg_string_to_int(const u8 *str)
+{
+	int i, len;
+	u32 output = 0;
+
+	len = strnlen(str, sizeof(u32));
+	for (i = 0; i < len; i++)
+		output |= str[i] << (i * 8);
+
+	return output;
+}
+
+static inline void rpm_vreg_lock(struct rpm_vreg *rpm_vreg)
+{
+	if (rpm_vreg->allow_atomic)
+		spin_lock_irqsave(&rpm_vreg->slock, rpm_vreg->flags);
+	else
+		mutex_lock(&rpm_vreg->mlock);
+}
+
+static inline void rpm_vreg_unlock(struct rpm_vreg *rpm_vreg)
+{
+	if (rpm_vreg->allow_atomic)
+		spin_unlock_irqrestore(&rpm_vreg->slock, rpm_vreg->flags);
+	else
+		mutex_unlock(&rpm_vreg->mlock);
+}
+
+static inline bool rpm_vreg_active_or_sleep_enabled(struct rpm_vreg *rpm_vreg)
+{
+	return (rpm_vreg->aggr_req_active.param[RPM_REGULATOR_PARAM_ENABLE]
+			&& (rpm_vreg->aggr_req_active.valid
+				& BIT(RPM_REGULATOR_PARAM_ENABLE)))
+	    || ((rpm_vreg->aggr_req_sleep.param[RPM_REGULATOR_PARAM_ENABLE])
+				&& (rpm_vreg->aggr_req_sleep.valid
+					& BIT(RPM_REGULATOR_PARAM_ENABLE)));
+}
+
+/*
+ * This is used when voting for LPM or HPM by subtracting or adding to the
+ * hpm_min_load of a regulator.  It has units of uA.
+ */
+#define LOAD_THRESHOLD_STEP	1000
+
+static inline int rpm_vreg_hpm_min_uA(struct rpm_vreg *rpm_vreg)
+{
+	return rpm_vreg->hpm_min_load;
+}
+
+static inline int rpm_vreg_lpm_max_uA(struct rpm_vreg *rpm_vreg)
+{
+	return rpm_vreg->hpm_min_load - LOAD_THRESHOLD_STEP;
+}
+
+#define MICRO_TO_MILLI(uV)	((uV) / 1000)
+#define MILLI_TO_MICRO(uV)	((uV) * 1000)
+
+#define DEBUG_PRINT_BUFFER_SIZE 512
+#define REQ_SENT	0
+#define REQ_PREV	1
+#define REQ_CACHED	2
+#define REQ_TYPES	3
+
+static void rpm_regulator_req(struct rpm_regulator *regulator, int set,
+				bool sent)
+{
+	char buf[DEBUG_PRINT_BUFFER_SIZE];
+	size_t buflen = DEBUG_PRINT_BUFFER_SIZE;
+	struct rpm_vreg *rpm_vreg = regulator->rpm_vreg;
+	struct rpm_vreg_request *aggr;
+	bool first;
+	u32 mask[REQ_TYPES] = {0, 0, 0};
+	const char *req_names[REQ_TYPES] = {"sent", "prev", "cached"};
+	int pos = 0;
+	int i, j;
+
+	aggr = (set == RPM_SET_ACTIVE)
+		? &rpm_vreg->aggr_req_active : &rpm_vreg->aggr_req_sleep;
+
+	if (rpm_vreg_debug_mask & RPM_VREG_DEBUG_DUPLICATE) {
+		mask[REQ_SENT] = aggr->modified;
+		mask[REQ_PREV] = aggr->valid & ~aggr->modified;
+	} else if (sent
+		   && (rpm_vreg_debug_mask & RPM_VREG_DEBUG_FULL_REQUEST)) {
+		mask[REQ_SENT] = aggr->modified;
+		mask[REQ_PREV] = aggr->valid & ~aggr->modified;
+	} else if (sent && (rpm_vreg_debug_mask & RPM_VREG_DEBUG_REQUEST)) {
+		mask[REQ_SENT] = aggr->modified;
+	}
+
+	if (!(mask[REQ_SENT] | mask[REQ_PREV]))
+		return;
+
+	if (set == RPM_SET_SLEEP && !rpm_vreg->sleep_request_sent) {
+		mask[REQ_CACHED] = mask[REQ_SENT] | mask[REQ_PREV];
+		mask[REQ_SENT] = 0;
+		mask[REQ_PREV] = 0;
+	}
+
+	pos += scnprintf(buf + pos, buflen - pos, "%s%s: ",
+			KERN_INFO, __func__);
+
+	pos += scnprintf(buf + pos, buflen - pos, "%s %u (%s): s=%s",
+			rpm_vreg->resource_name, rpm_vreg->resource_id,
+			regulator->rdesc.name,
+			(set == RPM_SET_ACTIVE ? "act" : "slp"));
+
+	for (i = 0; i < REQ_TYPES; i++) {
+		if (mask[i])
+			pos += scnprintf(buf + pos, buflen - pos, "; %s: ",
+					req_names[i]);
+
+		first = true;
+		for (j = 0; j < RPM_REGULATOR_PARAM_MAX; j++) {
+			if (mask[i] & BIT(j)) {
+				pos += scnprintf(buf + pos, buflen - pos,
+					"%s%s=%u", (first ? "" : ", "),
+					params[j].name, aggr->param[j]);
+				first = false;
+			}
+		}
+	}
+
+	pos += scnprintf(buf + pos, buflen - pos, "\n");
+	printk(buf);
+}
+
+#define RPM_VREG_SET_PARAM(_regulator, _param, _val) \
+{ \
+	(_regulator)->req.param[RPM_REGULATOR_PARAM_##_param] = _val; \
+	(_regulator)->req.modified |= BIT(RPM_REGULATOR_PARAM_##_param); \
+} \
+
+static int rpm_vreg_add_kvp_to_request(struct rpm_vreg *rpm_vreg,
+				       const u32 *param, int idx, u32 set)
+{
+	struct msm_rpm_request *handle;
+
+	handle = (set == RPM_SET_ACTIVE	? rpm_vreg->handle_active
+					: rpm_vreg->handle_sleep);
+
+	if (rpm_vreg->allow_atomic)
+		return msm_rpm_add_kvp_data_noirq(handle, params[idx].key,
+						  (u8 *)&param[idx], 4);
+	else
+		return msm_rpm_add_kvp_data(handle, params[idx].key,
+					    (u8 *)&param[idx], 4);
+}
+
+static void rpm_vreg_check_modified_requests(const u32 *prev_param,
+		const u32 *param, u32 prev_valid, u32 *modified)
+{
+	u32 value_changed = 0;
+	int i;
+
+	for (i = 0; i < RPM_REGULATOR_PARAM_MAX; i++) {
+		if (param[i] != prev_param[i])
+			value_changed |= BIT(i);
+	}
+
+	/*
+	 * Only keep bits that are for changed parameters or previously
+	 * invalid parameters.
+	 */
+	*modified &= value_changed | ~prev_valid;
+}
+
+static int rpm_vreg_add_modified_requests(struct rpm_regulator *regulator,
+		u32 set, const u32 *param, u32 modified)
+{
+	struct rpm_vreg *rpm_vreg = regulator->rpm_vreg;
+	int rc = 0;
+	int i;
+
+	for (i = 0; i < RPM_REGULATOR_PARAM_MAX; i++) {
+		/* Only send requests for modified parameters. */
+		if (modified & BIT(i)) {
+			rc = rpm_vreg_add_kvp_to_request(rpm_vreg, param, i,
+							set);
+			if (rc) {
+				vreg_err(regulator,
+					"add KVP failed: %s %u; %s, rc=%d\n",
+					rpm_vreg->resource_name,
+					rpm_vreg->resource_id, params[i].name,
+					rc);
+				return rc;
+			}
+		}
+	}
+
+	return rc;
+}
+
+static int rpm_vreg_send_request(struct rpm_regulator *regulator, u32 set)
+{
+	struct rpm_vreg *rpm_vreg = regulator->rpm_vreg;
+	struct msm_rpm_request *handle
+		= (set == RPM_SET_ACTIVE ? rpm_vreg->handle_active
+					: rpm_vreg->handle_sleep);
+	int rc;
+
+	if (rpm_vreg->allow_atomic)
+		rc = msm_rpm_wait_for_ack_noirq(msm_rpm_send_request_noirq(
+						  handle));
+	else
+		rc = msm_rpm_wait_for_ack(msm_rpm_send_request(handle));
+
+	if (rc)
+		vreg_err(regulator, "msm rpm send failed: %s %u; set=%s, "
+			"rc=%d\n", rpm_vreg->resource_name,
+			rpm_vreg->resource_id,
+			(set == RPM_SET_ACTIVE ? "act" : "slp"), rc);
+
+	return rc;
+}
+
+#define RPM_VREG_AGGR_MAX(_idx, _param_aggr, _param_reg) \
+{ \
+	_param_aggr[RPM_REGULATOR_PARAM_##_idx] \
+	 = max(_param_aggr[RPM_REGULATOR_PARAM_##_idx], \
+		_param_reg[RPM_REGULATOR_PARAM_##_idx]); \
+}
+
+#define RPM_VREG_AGGR_SUM(_idx, _param_aggr, _param_reg) \
+{ \
+	_param_aggr[RPM_REGULATOR_PARAM_##_idx] \
+		 += _param_reg[RPM_REGULATOR_PARAM_##_idx]; \
+}
+
+#define RPM_VREG_AGGR_OR(_idx, _param_aggr, _param_reg) \
+{ \
+	_param_aggr[RPM_REGULATOR_PARAM_##_idx] \
+		|= _param_reg[RPM_REGULATOR_PARAM_##_idx]; \
+}
+
+/*
+ * The RPM treats freq=0 as a special value meaning that this consumer does not
+ * care what the SMPS switching freqency is.
+ */
+#define RPM_REGULATOR_FREQ_DONT_CARE 0
+
+static inline void rpm_vreg_freqency_aggr(u32 *freq, u32 consumer_freq)
+{
+	if (consumer_freq != RPM_REGULATOR_FREQ_DONT_CARE
+		&& (consumer_freq < *freq
+			|| *freq == RPM_REGULATOR_FREQ_DONT_CARE))
+		*freq = consumer_freq;
+}
+
+/*
+ * Aggregation is performed on each parameter based on the way that the RPM
+ * aggregates that type internally between RPM masters.
+ */
+static void rpm_vreg_aggregate_params(u32 *param_aggr, const u32 *param_reg)
+{
+	RPM_VREG_AGGR_MAX(ENABLE, param_aggr, param_reg);
+	RPM_VREG_AGGR_MAX(VOLTAGE, param_aggr, param_reg);
+	RPM_VREG_AGGR_SUM(CURRENT, param_aggr, param_reg);
+	RPM_VREG_AGGR_MAX(MODE_LDO, param_aggr, param_reg);
+	RPM_VREG_AGGR_MAX(MODE_SMPS, param_aggr, param_reg);
+	RPM_VREG_AGGR_OR(PIN_CTRL_ENABLE, param_aggr, param_reg);
+	RPM_VREG_AGGR_OR(PIN_CTRL_MODE, param_aggr, param_reg);
+	rpm_vreg_freqency_aggr(&param_aggr[RPM_REGULATOR_PARAM_FREQUENCY],
+		param_reg[RPM_REGULATOR_PARAM_FREQUENCY]);
+	RPM_VREG_AGGR_MAX(HEAD_ROOM, param_aggr, param_reg);
+	RPM_VREG_AGGR_MAX(QUIET_MODE, param_aggr, param_reg);
+	RPM_VREG_AGGR_MAX(FREQ_REASON, param_aggr, param_reg);
+}
+
+static int rpm_vreg_aggregate_requests(struct rpm_regulator *regulator)
+{
+	struct rpm_vreg *rpm_vreg = regulator->rpm_vreg;
+	u32 param_active[RPM_REGULATOR_PARAM_MAX];
+	u32 param_sleep[RPM_REGULATOR_PARAM_MAX];
+	u32 modified_active, modified_sleep;
+	struct rpm_regulator *reg;
+	bool sleep_set_differs = false;
+	bool send_active = false;
+	bool send_sleep = false;
+	int rc = 0;
+	int i;
+
+	memset(param_active, 0, sizeof(param_active));
+	memset(param_sleep, 0, sizeof(param_sleep));
+	modified_active = rpm_vreg->aggr_req_active.modified;
+	modified_sleep = rpm_vreg->aggr_req_sleep.modified;
+
+	/*
+	 * Aggregate all of the requests for this regulator in both active
+	 * and sleep sets.
+	 */
+	list_for_each_entry(reg, &rpm_vreg->reg_list, list) {
+		if (reg->set_active) {
+			rpm_vreg_aggregate_params(param_active, reg->req.param);
+			modified_active |= reg->req.modified;
+		}
+		if (reg->set_sleep) {
+			rpm_vreg_aggregate_params(param_sleep, reg->req.param);
+			modified_sleep |= reg->req.modified;
+		}
+	}
+
+	/*
+	 * Check if the aggregated sleep set parameter values differ from the
+	 * aggregated active set parameter values.
+	 */
+	if (!rpm_vreg->sleep_request_sent) {
+		for (i = 0; i < RPM_REGULATOR_PARAM_MAX; i++) {
+			if ((param_active[i] != param_sleep[i])
+			    && (modified_sleep & BIT(i))) {
+				sleep_set_differs = true;
+				break;
+			}
+		}
+	}
+
+	/* Add KVPs to the active set RPM request if they have new values. */
+	rpm_vreg_check_modified_requests(rpm_vreg->aggr_req_active.param,
+		param_active, rpm_vreg->aggr_req_active.valid,
+		&modified_active);
+	rc = rpm_vreg_add_modified_requests(regulator, RPM_SET_ACTIVE,
+		param_active, modified_active);
+	if (rc)
+		return rc;
+	send_active = modified_active;
+
+	/*
+	 * Sleep set configurations are only sent if they differ from the
+	 * active set values.  This is because the active set values will take
+	 * effect during rpm assisted power collapse in the absence of sleep set
+	 * values.
+	 *
+	 * However, once a sleep set request is sent for a given regulator,
+	 * additional sleep set requests must be sent in the future even if they
+	 * match the corresponding active set requests.
+	 */
+	if (rpm_vreg->sleep_request_sent || sleep_set_differs) {
+		/* Add KVPs to the sleep set RPM request if they are new. */
+		rpm_vreg_check_modified_requests(rpm_vreg->aggr_req_sleep.param,
+			param_sleep, rpm_vreg->aggr_req_sleep.valid,
+			&modified_sleep);
+		rc = rpm_vreg_add_modified_requests(regulator, RPM_SET_SLEEP,
+			param_sleep, modified_sleep);
+		if (rc)
+			return rc;
+		send_sleep = modified_sleep;
+	}
+
+	/* Send active set request to the RPM if it contains new KVPs. */
+	if (send_active) {
+		rc = rpm_vreg_send_request(regulator, RPM_SET_ACTIVE);
+		if (rc)
+			return rc;
+		rpm_vreg->aggr_req_active.valid |= modified_active;
+	}
+	/* Store the results of the aggregation. */
+	rpm_vreg->aggr_req_active.modified = modified_active;
+	memcpy(rpm_vreg->aggr_req_active.param, param_active,
+		sizeof(param_active));
+
+	/* Handle debug printing of the active set request. */
+	rpm_regulator_req(regulator, RPM_SET_ACTIVE, send_active);
+	if (send_active)
+		rpm_vreg->aggr_req_active.modified = 0;
+
+	/* Send sleep set request to the RPM if it contains new KVPs. */
+	if (send_sleep) {
+		rc = rpm_vreg_send_request(regulator, RPM_SET_SLEEP);
+		if (rc)
+			return rc;
+		else
+			rpm_vreg->sleep_request_sent = true;
+		rpm_vreg->aggr_req_sleep.valid |= modified_sleep;
+	}
+	/* Store the results of the aggregation. */
+	rpm_vreg->aggr_req_sleep.modified = modified_sleep;
+	memcpy(rpm_vreg->aggr_req_sleep.param, param_sleep,
+		sizeof(param_sleep));
+
+	/* Handle debug printing of the sleep set request. */
+	rpm_regulator_req(regulator, RPM_SET_SLEEP, send_sleep);
+	if (send_sleep)
+		rpm_vreg->aggr_req_sleep.modified = 0;
+
+	/*
+	 * Loop over all requests for this regulator to update the valid and
+	 * modified values for use in future aggregation.
+	 */
+	list_for_each_entry(reg, &rpm_vreg->reg_list, list) {
+		reg->req.valid |= reg->req.modified;
+		reg->req.modified = 0;
+	}
+
+	return rc;
+}
+
+static int rpm_vreg_is_enabled(struct regulator_dev *rdev)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+
+	return reg->req.param[RPM_REGULATOR_PARAM_ENABLE];
+}
+
+static int rpm_vreg_enable(struct regulator_dev *rdev)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+	int rc;
+	u32 prev_enable;
+
+	rpm_vreg_lock(reg->rpm_vreg);
+
+	prev_enable = reg->req.param[RPM_REGULATOR_PARAM_ENABLE];
+	RPM_VREG_SET_PARAM(reg, ENABLE, 1);
+	rc = rpm_vreg_aggregate_requests(reg);
+	if (rc) {
+		vreg_err(reg, "enable failed, rc=%d", rc);
+		RPM_VREG_SET_PARAM(reg, ENABLE, prev_enable);
+	}
+
+	rpm_vreg_unlock(reg->rpm_vreg);
+
+	return rc;
+}
+
+static int rpm_vreg_disable(struct regulator_dev *rdev)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+	int rc;
+	u32 prev_enable;
+
+	rpm_vreg_lock(reg->rpm_vreg);
+
+	prev_enable = reg->req.param[RPM_REGULATOR_PARAM_ENABLE];
+	RPM_VREG_SET_PARAM(reg, ENABLE, 0);
+	rc = rpm_vreg_aggregate_requests(reg);
+	if (rc) {
+		vreg_err(reg, "enable failed, rc=%d", rc);
+		RPM_VREG_SET_PARAM(reg, ENABLE, prev_enable);
+	}
+
+	rpm_vreg_unlock(reg->rpm_vreg);
+
+	return rc;
+}
+
+static int rpm_vreg_set_voltage(struct regulator_dev *rdev, int min_uV,
+				int max_uV, unsigned *selector)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+	int rc = 0;
+	u32 prev_voltage;
+
+	rpm_vreg_lock(reg->rpm_vreg);
+
+	prev_voltage = reg->req.param[RPM_REGULATOR_PARAM_VOLTAGE];
+	RPM_VREG_SET_PARAM(reg, VOLTAGE, min_uV);
+
+	/* Only send a new voltage if the regulator is currently enabled. */
+	if (rpm_vreg_active_or_sleep_enabled(reg->rpm_vreg))
+		rc = rpm_vreg_aggregate_requests(reg);
+
+	if (rc) {
+		vreg_err(reg, "set voltage failed, rc=%d", rc);
+		RPM_VREG_SET_PARAM(reg, VOLTAGE, prev_voltage);
+	}
+
+	rpm_vreg_unlock(reg->rpm_vreg);
+
+	return rc;
+}
+
+static int rpm_vreg_get_voltage(struct regulator_dev *rdev)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+	int uV;
+
+	uV = reg->req.param[RPM_REGULATOR_PARAM_VOLTAGE];
+	if (uV == 0)
+		uV = VOLTAGE_UNKNOWN;
+
+	return uV;
+}
+
+static int rpm_vreg_list_voltage(struct regulator_dev *rdev, unsigned selector)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+	int uV = 0;
+
+	if (selector == 0)
+		uV = reg->min_uV;
+	else if (selector == 1)
+		uV = reg->max_uV;
+
+	return uV;
+}
+
+static int rpm_vreg_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+	int rc = 0;
+	u32 prev_current;
+	int prev_uA;
+
+	rpm_vreg_lock(reg->rpm_vreg);
+
+	prev_current = reg->req.param[RPM_REGULATOR_PARAM_CURRENT];
+	prev_uA = MILLI_TO_MICRO(prev_current);
+
+	if (mode == REGULATOR_MODE_NORMAL) {
+		/* Make sure that request current is in HPM range. */
+		if (prev_uA < rpm_vreg_hpm_min_uA(reg->rpm_vreg))
+			RPM_VREG_SET_PARAM(reg, CURRENT,
+			    MICRO_TO_MILLI(rpm_vreg_hpm_min_uA(reg->rpm_vreg)));
+	} else if (REGULATOR_MODE_IDLE) {
+		/* Make sure that request current is in LPM range. */
+		if (prev_uA > rpm_vreg_lpm_max_uA(reg->rpm_vreg))
+			RPM_VREG_SET_PARAM(reg, CURRENT,
+			    MICRO_TO_MILLI(rpm_vreg_lpm_max_uA(reg->rpm_vreg)));
+	} else {
+		vreg_err(reg, "invalid mode: %u\n", mode);
+		rpm_vreg_unlock(reg->rpm_vreg);
+		return -EINVAL;
+	}
+
+	/* Only send a new mode value if the regulator is currently enabled. */
+	if (rpm_vreg_active_or_sleep_enabled(reg->rpm_vreg))
+		rc = rpm_vreg_aggregate_requests(reg);
+
+	if (rc) {
+		vreg_err(reg, "set mode failed, rc=%d", rc);
+		RPM_VREG_SET_PARAM(reg, CURRENT, prev_current);
+	}
+
+	rpm_vreg_unlock(reg->rpm_vreg);
+
+	return rc;
+}
+
+static unsigned int rpm_vreg_get_mode(struct regulator_dev *rdev)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+
+	return (reg->req.param[RPM_REGULATOR_PARAM_CURRENT]
+			>= MICRO_TO_MILLI(reg->rpm_vreg->hpm_min_load))
+		? REGULATOR_MODE_NORMAL : REGULATOR_MODE_IDLE;
+}
+
+static unsigned int rpm_vreg_get_optimum_mode(struct regulator_dev *rdev,
+			int input_uV, int output_uV, int load_uA)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+	u32 load_mA;
+
+	load_uA += reg->system_load;
+
+	load_mA = MICRO_TO_MILLI(load_uA);
+	if (load_mA > params[RPM_REGULATOR_PARAM_CURRENT].max)
+		load_mA = params[RPM_REGULATOR_PARAM_CURRENT].max;
+
+	rpm_vreg_lock(reg->rpm_vreg);
+	RPM_VREG_SET_PARAM(reg, CURRENT, MICRO_TO_MILLI(load_uA));
+	rpm_vreg_unlock(reg->rpm_vreg);
+
+	return (load_uA >= reg->rpm_vreg->hpm_min_load)
+		? REGULATOR_MODE_NORMAL : REGULATOR_MODE_IDLE;
+}
+
+static int rpm_vreg_enable_time(struct regulator_dev *rdev)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+
+	return reg->rpm_vreg->enable_time;
+}
+
+/**
+ * rpm_regulator_get() - lookup and obtain a handle to an RPM regulator
+ * @dev: device for regulator consumer
+ * @supply: supply name
+ *
+ * Returns a struct rpm_regulator corresponding to the regulator producer,
+ * or ERR_PTR() containing errno.
+ *
+ * This function may only be called from nonatomic context.
+ */
+struct rpm_regulator *rpm_regulator_get(struct device *dev, const char *supply)
+{
+	struct rpm_regulator *framework_reg;
+	struct rpm_regulator *priv_reg = NULL;
+	struct regulator *regulator;
+	struct rpm_vreg *rpm_vreg;
+
+	regulator = regulator_get(dev, supply);
+	if (regulator == NULL) {
+		pr_err("could not find regulator for: dev=%s, id=%s\n",
+			(dev ? dev_name(dev) : ""), (supply ? supply : ""));
+		return ERR_PTR(-ENODEV);
+	}
+
+	framework_reg = regulator_get_drvdata(regulator);
+	if (framework_reg == NULL) {
+		pr_err("regulator structure not found.\n");
+		regulator_put(regulator);
+		return ERR_PTR(-ENODEV);
+	}
+	regulator_put(regulator);
+
+	rpm_vreg = framework_reg->rpm_vreg;
+
+	priv_reg = kzalloc(sizeof(struct rpm_regulator), GFP_KERNEL);
+	if (priv_reg == NULL) {
+		vreg_err(framework_reg, "could not allocate memory for "
+			"regulator\n");
+		rpm_vreg_unlock(rpm_vreg);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	/*
+	 * Allocate a regulator_dev struct so that framework callback functions
+	 * can be called from the private API functions.
+	 */
+	priv_reg->rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL);
+	if (priv_reg->rdev == NULL) {
+		vreg_err(framework_reg, "could not allocate memory for "
+			"regulator_dev\n");
+		kfree(priv_reg);
+		rpm_vreg_unlock(rpm_vreg);
+		return ERR_PTR(-ENOMEM);
+	}
+	priv_reg->rdev->reg_data	= priv_reg;
+	priv_reg->rpm_vreg		= rpm_vreg;
+	priv_reg->rdesc.name		= framework_reg->rdesc.name;
+	priv_reg->set_active		= framework_reg->set_active;
+	priv_reg->set_sleep		= framework_reg->set_sleep;
+	priv_reg->min_uV		= framework_reg->min_uV;
+	priv_reg->max_uV		= framework_reg->max_uV;
+	priv_reg->system_load		= framework_reg->system_load;
+
+	might_sleep_if(!rpm_vreg->allow_atomic);
+	rpm_vreg_lock(rpm_vreg);
+	list_add(&priv_reg->list, &rpm_vreg->reg_list);
+	rpm_vreg_unlock(rpm_vreg);
+
+	return priv_reg;
+}
+EXPORT_SYMBOL_GPL(rpm_regulator_get);
+
+static int rpm_regulator_check_input(struct rpm_regulator *regulator)
+{
+	if (regulator == NULL || regulator->rpm_vreg == NULL) {
+		pr_err("invalid rpm_regulator pointer\n");
+		return -EINVAL;
+	}
+
+	might_sleep_if(!regulator->rpm_vreg->allow_atomic);
+
+	return 0;
+}
+
+/**
+ * rpm_regulator_put() - free the RPM regulator handle
+ * @regulator: RPM regulator handle
+ *
+ * Parameter reaggregation does not take place when rpm_regulator_put is called.
+ * Therefore, regulator enable state and voltage must be configured
+ * appropriately before calling rpm_regulator_put.
+ *
+ * This function may be called from either atomic or nonatomic context.  If this
+ * function is called from atomic context, then the regulator being operated on
+ * must be configured via device tree with qcom,allow-atomic == 1.
+ */
+void rpm_regulator_put(struct rpm_regulator *regulator)
+{
+	struct rpm_vreg *rpm_vreg;
+	int rc = rpm_regulator_check_input(regulator);
+
+	if (rc)
+		return;
+
+	rpm_vreg = regulator->rpm_vreg;
+
+	might_sleep_if(!rpm_vreg->allow_atomic);
+	rpm_vreg_lock(rpm_vreg);
+	list_del(&regulator->list);
+	rpm_vreg_unlock(rpm_vreg);
+
+	kfree(regulator->rdev);
+	kfree(regulator);
+}
+EXPORT_SYMBOL_GPL(rpm_regulator_put);
+
+/**
+ * rpm_regulator_enable() - enable regulator output
+ * @regulator: RPM regulator handle
+ *
+ * Returns 0 on success or errno on failure.
+ *
+ * This function may be called from either atomic or nonatomic context.  If this
+ * function is called from atomic context, then the regulator being operated on
+ * must be configured via device tree with qcom,allow-atomic == 1.
+ */
+int rpm_regulator_enable(struct rpm_regulator *regulator)
+{
+	int rc = rpm_regulator_check_input(regulator);
+
+	if (rc)
+		return rc;
+
+	return rpm_vreg_enable(regulator->rdev);
+}
+EXPORT_SYMBOL_GPL(rpm_regulator_enable);
+
+/**
+ * rpm_regulator_disable() - disable regulator output
+ * @regulator: RPM regulator handle
+ *
+ * Returns 0 on success or errno on failure.
+ *
+ * The enable state of the regulator is determined by aggregating the requests
+ * of all consumers.  Therefore, it is possible that the regulator will remain
+ * enabled even after rpm_regulator_disable is called.
+ *
+ * This function may be called from either atomic or nonatomic context.  If this
+ * function is called from atomic context, then the regulator being operated on
+ * must be configured via device tree with qcom,allow-atomic == 1.
+ */
+int rpm_regulator_disable(struct rpm_regulator *regulator)
+{
+	int rc = rpm_regulator_check_input(regulator);
+
+	if (rc)
+		return rc;
+
+	return rpm_vreg_disable(regulator->rdev);
+}
+EXPORT_SYMBOL_GPL(rpm_regulator_disable);
+
+/**
+ * rpm_regulator_set_voltage() - set regulator output voltage
+ * @regulator: RPM regulator handle
+ * @min_uV: minimum required voltage in uV
+ * @max_uV: maximum acceptable voltage in uV
+ *
+ * Sets a voltage regulator to the desired output voltage. This can be set
+ * while the regulator is disabled or enabled.  If the regulator is enabled then
+ * the voltage will change to the new value immediately; otherwise, if the
+ * regulator is disabled, then the regulator will output at the new voltage when
+ * enabled.
+ *
+ * The min_uV to max_uV voltage range requested must intersect with the
+ * voltage constraint range configured for the regulator.
+ *
+ * Returns 0 on success or errno on failure.
+ *
+ * The final voltage value that is sent to the RPM is aggregated based upon the
+ * values requested by all consumers of the regulator.  This corresponds to the
+ * maximum min_uV value.
+ *
+ * This function may be called from either atomic or nonatomic context.  If this
+ * function is called from atomic context, then the regulator being operated on
+ * must be configured via device tree with qcom,allow-atomic == 1.
+ */
+int rpm_regulator_set_voltage(struct rpm_regulator *regulator, int min_uV,
+			      int max_uV)
+{
+	int rc = rpm_regulator_check_input(regulator);
+	int uV = min_uV;
+
+	if (rc)
+		return rc;
+
+	if (regulator->rpm_vreg->regulator_type == RPM_REGULATOR_SMD_TYPE_VS) {
+		vreg_err(regulator, "unsupported regulator type: %d\n",
+			regulator->rpm_vreg->regulator_type);
+		return -EINVAL;
+	}
+
+	if (min_uV > max_uV) {
+		vreg_err(regulator, "min_uV=%d must be less than max_uV=%d\n",
+			min_uV, max_uV);
+		return -EINVAL;
+	}
+
+	if (uV < regulator->min_uV && max_uV >= regulator->min_uV)
+		uV = regulator->min_uV;
+
+	if (uV < regulator->min_uV || uV > regulator->max_uV) {
+		vreg_err(regulator, "request v=[%d, %d] is outside allowed "
+			"v=[%d, %d]\n", min_uV, max_uV, regulator->min_uV,
+			regulator->max_uV);
+		return -EINVAL;
+	}
+
+	return rpm_vreg_set_voltage(regulator->rdev, uV, uV, NULL);
+}
+EXPORT_SYMBOL_GPL(rpm_regulator_set_voltage);
+
+static struct regulator_ops ldo_ops = {
+	.enable			= rpm_vreg_enable,
+	.disable		= rpm_vreg_disable,
+	.is_enabled		= rpm_vreg_is_enabled,
+	.set_voltage		= rpm_vreg_set_voltage,
+	.get_voltage		= rpm_vreg_get_voltage,
+	.list_voltage		= rpm_vreg_list_voltage,
+	.set_mode		= rpm_vreg_set_mode,
+	.get_mode		= rpm_vreg_get_mode,
+	.get_optimum_mode	= rpm_vreg_get_optimum_mode,
+	.enable_time		= rpm_vreg_enable_time,
+};
+
+static struct regulator_ops smps_ops = {
+	.enable			= rpm_vreg_enable,
+	.disable		= rpm_vreg_disable,
+	.is_enabled		= rpm_vreg_is_enabled,
+	.set_voltage		= rpm_vreg_set_voltage,
+	.get_voltage		= rpm_vreg_get_voltage,
+	.list_voltage		= rpm_vreg_list_voltage,
+	.set_mode		= rpm_vreg_set_mode,
+	.get_mode		= rpm_vreg_get_mode,
+	.get_optimum_mode	= rpm_vreg_get_optimum_mode,
+	.enable_time		= rpm_vreg_enable_time,
+};
+
+static struct regulator_ops switch_ops = {
+	.enable			= rpm_vreg_enable,
+	.disable		= rpm_vreg_disable,
+	.is_enabled		= rpm_vreg_is_enabled,
+	.enable_time		= rpm_vreg_enable_time,
+};
+
+static struct regulator_ops ncp_ops = {
+	.enable			= rpm_vreg_enable,
+	.disable		= rpm_vreg_disable,
+	.is_enabled		= rpm_vreg_is_enabled,
+	.set_voltage		= rpm_vreg_set_voltage,
+	.get_voltage		= rpm_vreg_get_voltage,
+	.list_voltage		= rpm_vreg_list_voltage,
+	.enable_time		= rpm_vreg_enable_time,
+};
+
+static struct regulator_ops *vreg_ops[] = {
+	[RPM_REGULATOR_SMD_TYPE_LDO]	= &ldo_ops,
+	[RPM_REGULATOR_SMD_TYPE_SMPS]	= &smps_ops,
+	[RPM_REGULATOR_SMD_TYPE_VS]	= &switch_ops,
+	[RPM_REGULATOR_SMD_TYPE_NCP]	= &ncp_ops,
+};
+
+static int __devexit rpm_vreg_device_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct rpm_regulator *reg;
+
+	reg = platform_get_drvdata(pdev);
+	if (reg) {
+		rpm_vreg_lock(reg->rpm_vreg);
+		regulator_unregister(reg->rdev);
+		list_del(&reg->list);
+		kfree(reg);
+		rpm_vreg_unlock(reg->rpm_vreg);
+	} else {
+		dev_err(dev, "%s: drvdata missing\n", __func__);
+		return -EINVAL;
+	}
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static int __devexit rpm_vreg_resource_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct rpm_regulator *reg, *reg_temp;
+	struct rpm_vreg *rpm_vreg;
+
+	rpm_vreg = platform_get_drvdata(pdev);
+	if (rpm_vreg) {
+		rpm_vreg_lock(rpm_vreg);
+		list_for_each_entry_safe(reg, reg_temp, &rpm_vreg->reg_list,
+				list) {
+			/* Only touch data for private consumers. */
+			if (reg->rdev->desc == NULL) {
+				list_del(&reg->list);
+				kfree(reg->rdev);
+				kfree(reg);
+			} else {
+				dev_err(dev, "%s: not all child devices have "
+					"been removed\n", __func__);
+			}
+		}
+		rpm_vreg_unlock(rpm_vreg);
+
+		msm_rpm_free_request(rpm_vreg->handle_active);
+		msm_rpm_free_request(rpm_vreg->handle_sleep);
+
+		kfree(rpm_vreg);
+	} else {
+		dev_err(dev, "%s: drvdata missing\n", __func__);
+		return -EINVAL;
+	}
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+/*
+ * This probe is called for child rpm-regulator devices which have
+ * properties which are required to configure individual regulator
+ * framework regulators for a given RPM regulator resource.
+ */
+static int __devinit rpm_vreg_device_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *node = dev->of_node;
+	struct regulator_init_data *init_data;
+	struct rpm_vreg *rpm_vreg;
+	struct rpm_regulator *reg;
+	int rc = 0;
+	int i, regulator_type;
+	u32 val;
+
+	if (!dev->of_node) {
+		dev_err(dev, "%s: device tree information missing\n", __func__);
+		return -ENODEV;
+	}
+
+	if (pdev->dev.parent == NULL) {
+		dev_err(dev, "%s: parent device missing\n", __func__);
+		return -ENODEV;
+	}
+
+	rpm_vreg = dev_get_drvdata(pdev->dev.parent);
+	if (rpm_vreg == NULL) {
+		dev_err(dev, "%s: rpm_vreg not found in parent device\n",
+			__func__);
+		return -ENODEV;
+	}
+
+	reg = kzalloc(sizeof(struct rpm_regulator), GFP_KERNEL);
+	if (reg == NULL) {
+		dev_err(dev, "%s: could not allocate memory for reg\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	regulator_type		= rpm_vreg->regulator_type;
+	reg->rpm_vreg		= rpm_vreg;
+	reg->rdesc.ops		= vreg_ops[regulator_type];
+	reg->rdesc.owner	= THIS_MODULE;
+	reg->rdesc.type		= REGULATOR_VOLTAGE;
+
+	if (regulator_type == RPM_REGULATOR_SMD_TYPE_VS)
+		reg->rdesc.n_voltages = 0;
+	else
+		reg->rdesc.n_voltages = 2;
+
+	rc = of_property_read_u32(node, "qcom,set", &val);
+	if (rc) {
+		dev_err(dev, "%s: sleep set and/or active set must be "
+			"configured via qcom,set property, rc=%d\n", __func__,
+			rc);
+		goto fail_free_reg;
+	} else if (!(val & RPM_SET_CONFIG_BOTH)) {
+		dev_err(dev, "%s: qcom,set=%u property is invalid\n", __func__,
+			val);
+		rc = -EINVAL;
+		goto fail_free_reg;
+	}
+
+	reg->set_active = !!(val & RPM_SET_CONFIG_ACTIVE);
+	reg->set_sleep = !!(val & RPM_SET_CONFIG_SLEEP);
+
+	init_data = of_get_regulator_init_data(dev);
+	if (init_data == NULL) {
+		dev_err(dev, "%s: unable to allocate memory\n", __func__);
+		rc = -ENOMEM;
+		goto fail_free_reg;
+	}
+	if (init_data->constraints.name == NULL) {
+		dev_err(dev, "%s: regulator name not specified\n", __func__);
+		rc = -EINVAL;
+		goto fail_free_reg;
+	}
+
+	init_data->constraints.input_uV	= init_data->constraints.max_uV;
+
+	if (of_get_property(node, "parent-supply", NULL))
+		init_data->supply_regulator = "parent";
+
+	/*
+	 * Fill in ops and mode masks based on callbacks specified for
+	 * this type of regulator.
+	 */
+	if (reg->rdesc.ops->enable)
+		init_data->constraints.valid_ops_mask
+			|= REGULATOR_CHANGE_STATUS;
+	if (reg->rdesc.ops->get_voltage)
+		init_data->constraints.valid_ops_mask
+			|= REGULATOR_CHANGE_VOLTAGE;
+	if (reg->rdesc.ops->get_mode) {
+		init_data->constraints.valid_ops_mask
+			|= REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_DRMS;
+		init_data->constraints.valid_modes_mask
+			|= REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE;
+	}
+
+	reg->rdesc.name		= init_data->constraints.name;
+	reg->min_uV		= init_data->constraints.min_uV;
+	reg->max_uV		= init_data->constraints.max_uV;
+
+	/* Initialize the param array based on optional properties. */
+	for (i = 0; i < RPM_REGULATOR_PARAM_MAX; i++) {
+		rc = of_property_read_u32(node, params[i].property_name, &val);
+		if (rc == 0) {
+			if (params[i].supported_regulator_types
+					& BIT(regulator_type)) {
+				if (val < params[i].min
+						|| val > params[i].max) {
+					pr_warn("%s: device tree property: "
+						"%s=%u is outsided allowed "
+						"range [%u, %u]\n",
+						reg->rdesc.name,
+						params[i].property_name, val,
+						params[i].min, params[i].max);
+					continue;
+				}
+				reg->req.param[i] = val;
+				reg->req.modified |= BIT(i);
+			} else {
+				pr_warn("%s: regulator type=%d does not support"
+					" device tree property: %s\n",
+					reg->rdesc.name, regulator_type,
+					params[i].property_name);
+			}
+		}
+	}
+
+	of_property_read_u32(node, "qcom,system_load", &reg->system_load);
+
+	rpm_vreg_lock(rpm_vreg);
+	list_add(&reg->list, &rpm_vreg->reg_list);
+	rpm_vreg_unlock(rpm_vreg);
+
+	reg->rdev = regulator_register(&reg->rdesc, dev, init_data, reg, node);
+	if (IS_ERR(reg->rdev)) {
+		rc = PTR_ERR(reg->rdev);
+		reg->rdev = NULL;
+		pr_err("regulator_register failed: %s, rc=%d\n",
+			reg->rdesc.name, rc);
+		goto fail_remove_from_list;
+	}
+
+	platform_set_drvdata(pdev, reg);
+
+	pr_debug("successfully probed: %s\n", reg->rdesc.name);
+
+	return 0;
+
+fail_remove_from_list:
+	rpm_vreg_lock(rpm_vreg);
+	list_del(&reg->list);
+	rpm_vreg_unlock(rpm_vreg);
+
+fail_free_reg:
+	kfree(reg);
+	return rc;
+}
+
+/*
+ * This probe is called for parent rpm-regulator devices which have
+ * properties which are required to identify a given RPM resource.
+ */
+static int __devinit rpm_vreg_resource_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *node = dev->of_node;
+	struct rpm_vreg *rpm_vreg;
+	int val = 0;
+	u32 resource_type;
+	int rc;
+
+	if (!dev->of_node) {
+		dev_err(dev, "%s: device tree information missing\n", __func__);
+		return -ENODEV;
+	}
+
+	/* Create new rpm_vreg entry. */
+	rpm_vreg = kzalloc(sizeof(struct rpm_vreg), GFP_KERNEL);
+	if (rpm_vreg == NULL) {
+		dev_err(dev, "%s: could not allocate memory for vreg\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	/* Required device tree properties: */
+	rc = of_property_read_string(node, "qcom,resource-name",
+			&rpm_vreg->resource_name);
+	if (rc) {
+		dev_err(dev, "%s: qcom,resource-name missing in DT node\n",
+			__func__);
+		goto fail_free_vreg;
+	}
+	resource_type = rpm_vreg_string_to_int(rpm_vreg->resource_name);
+
+	rc = of_property_read_u32(node, "qcom,resource-id",
+			&rpm_vreg->resource_id);
+	if (rc) {
+		dev_err(dev, "%s: qcom,resource-id missing in DT node\n",
+			__func__);
+		goto fail_free_vreg;
+	}
+
+	rc = of_property_read_u32(node, "qcom,regulator-type",
+			&rpm_vreg->regulator_type);
+	if (rc) {
+		dev_err(dev, "%s: qcom,regulator-type missing in DT node\n",
+			__func__);
+		goto fail_free_vreg;
+	}
+
+	if ((rpm_vreg->regulator_type < 0)
+	    || (rpm_vreg->regulator_type >= RPM_REGULATOR_SMD_TYPE_MAX)) {
+		dev_err(dev, "%s: invalid regulator type: %d\n", __func__,
+			rpm_vreg->regulator_type);
+		rc = -EINVAL;
+		goto fail_free_vreg;
+	}
+
+	/* Optional device tree properties: */
+	of_property_read_u32(node, "qcom,allow-atomic", &val);
+	rpm_vreg->allow_atomic = !!val;
+	of_property_read_u32(node, "qcom,enable-time", &rpm_vreg->enable_time);
+	of_property_read_u32(node, "qcom,hpm-min-load",
+		&rpm_vreg->hpm_min_load);
+
+	rpm_vreg->handle_active = msm_rpm_create_request(RPM_SET_ACTIVE,
+		resource_type, rpm_vreg->resource_id, RPM_REGULATOR_PARAM_MAX);
+	if (rpm_vreg->handle_active == NULL
+	    || IS_ERR(rpm_vreg->handle_active)) {
+		rc = PTR_ERR(rpm_vreg->handle_active);
+		dev_err(dev, "%s: failed to create active RPM handle, rc=%d\n",
+			__func__, rc);
+		goto fail_free_vreg;
+	}
+
+	rpm_vreg->handle_sleep = msm_rpm_create_request(RPM_SET_SLEEP,
+		resource_type, rpm_vreg->resource_id, RPM_REGULATOR_PARAM_MAX);
+	if (rpm_vreg->handle_sleep == NULL || IS_ERR(rpm_vreg->handle_sleep)) {
+		rc = PTR_ERR(rpm_vreg->handle_sleep);
+		dev_err(dev, "%s: failed to create sleep RPM handle, rc=%d\n",
+			__func__, rc);
+		goto fail_free_handle_active;
+	}
+
+	INIT_LIST_HEAD(&rpm_vreg->reg_list);
+
+	if (rpm_vreg->allow_atomic)
+		spin_lock_init(&rpm_vreg->slock);
+	else
+		mutex_init(&rpm_vreg->mlock);
+
+	platform_set_drvdata(pdev, rpm_vreg);
+
+	rc = of_platform_populate(node, NULL, NULL, dev);
+	if (rc) {
+		dev_err(dev, "%s: failed to add child nodes, rc=%d\n", __func__,
+			rc);
+		goto fail_unset_drvdata;
+	}
+
+	pr_debug("successfully probed: %s (%08X) %u\n", rpm_vreg->resource_name,
+		resource_type, rpm_vreg->resource_id);
+
+	return rc;
+
+fail_unset_drvdata:
+	platform_set_drvdata(pdev, NULL);
+	msm_rpm_free_request(rpm_vreg->handle_sleep);
+
+fail_free_handle_active:
+	msm_rpm_free_request(rpm_vreg->handle_active);
+
+fail_free_vreg:
+	kfree(rpm_vreg);
+
+	return rc;
+}
+
+static struct of_device_id rpm_vreg_match_table_device[] = {
+	{ .compatible = "qcom,rpm-regulator-smd", },
+	{}
+};
+
+static struct of_device_id rpm_vreg_match_table_resource[] = {
+	{ .compatible = "qcom,rpm-regulator-smd-resource", },
+	{}
+};
+
+static struct platform_driver rpm_vreg_device_driver = {
+	.probe = rpm_vreg_device_probe,
+	.remove = __devexit_p(rpm_vreg_device_remove),
+	.driver = {
+		.name = "qcom,rpm-regulator-smd",
+		.owner = THIS_MODULE,
+		.of_match_table = rpm_vreg_match_table_device,
+	},
+};
+
+static struct platform_driver rpm_vreg_resource_driver = {
+	.probe = rpm_vreg_resource_probe,
+	.remove = __devexit_p(rpm_vreg_resource_remove),
+	.driver = {
+		.name = "qcom,rpm-regulator-smd-resource",
+		.owner = THIS_MODULE,
+		.of_match_table = rpm_vreg_match_table_resource,
+	},
+};
+
+/**
+ * rpm_regulator_smd_driver_init() - initialized SMD RPM regulator driver
+ *
+ * This function registers the SMD RPM regulator platform drivers.
+ *
+ * Returns 0 on success or errno on failure.
+ */
+int __init rpm_regulator_smd_driver_init(void)
+{
+	static bool initialized;
+	int i, rc;
+
+	if (initialized)
+		return 0;
+	else
+		initialized = true;
+
+	/* Store parameter string names as integers */
+	for (i = 0; i < RPM_REGULATOR_PARAM_MAX; i++)
+		params[i].key = rpm_vreg_string_to_int(params[i].name);
+
+	rc = platform_driver_register(&rpm_vreg_device_driver);
+	if (rc)
+		return rc;
+
+	return platform_driver_register(&rpm_vreg_resource_driver);
+}
+EXPORT_SYMBOL_GPL(rpm_regulator_smd_driver_init);
+
+static void __exit rpm_vreg_exit(void)
+{
+	platform_driver_unregister(&rpm_vreg_device_driver);
+	platform_driver_unregister(&rpm_vreg_resource_driver);
+}
+
+module_init(rpm_regulator_smd_driver_init);
+module_exit(rpm_vreg_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MSM SMD RPM regulator driver");
diff --git a/arch/arm/mach-msm/rpm-regulator.c b/arch/arm/mach-msm/rpm-regulator.c
new file mode 100644
index 0000000..f663695
--- /dev/null
+++ b/arch/arm/mach-msm/rpm-regulator.c
@@ -0,0 +1,1796 @@
+/*
+ * 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
+ * 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <mach/rpm.h>
+#include <mach/rpm-regulator.h>
+#include <mach/rpm-regulator-smd.h>
+#include <mach/socinfo.h>
+
+#include "rpm_resources.h"
+#include "rpm-regulator-private.h"
+
+/* Debug Definitions */
+
+enum {
+	MSM_RPM_VREG_DEBUG_REQUEST = BIT(0),
+	MSM_RPM_VREG_DEBUG_VOTE = BIT(1),
+	MSM_RPM_VREG_DEBUG_DUPLICATE = BIT(2),
+	MSM_RPM_VREG_DEBUG_IGNORE_VDD_MEM_DIG = BIT(3),
+};
+
+static int msm_rpm_vreg_debug_mask;
+module_param_named(
+	debug_mask, msm_rpm_vreg_debug_mask, int, S_IRUSR | S_IWUSR
+);
+
+/* Used for access via the rpm_regulator_* API. */
+struct rpm_regulator {
+	int			vreg_id;
+	enum rpm_vreg_voter	voter;
+	int			sleep_also;
+	int			min_uV;
+	int			max_uV;
+};
+
+struct vreg_config *(*get_config[])(void) = {
+	[RPM_VREG_VERSION_8660] = get_config_8660,
+	[RPM_VREG_VERSION_8960] = get_config_8960,
+	[RPM_VREG_VERSION_9615] = get_config_9615,
+	[RPM_VREG_VERSION_8930] = get_config_8930,
+};
+
+static struct rpm_regulator_consumer_mapping *consumer_map;
+static int consumer_map_len;
+
+#define SET_PART(_vreg, _part, _val) \
+	_vreg->req[_vreg->part->_part.word].value \
+		= (_vreg->req[_vreg->part->_part.word].value \
+			& ~_vreg->part->_part.mask) \
+		  | (((_val) << _vreg->part->_part.shift) \
+			& _vreg->part->_part.mask)
+
+#define GET_PART(_vreg, _part) \
+	((_vreg->req[_vreg->part->_part.word].value & _vreg->part->_part.mask) \
+		>> _vreg->part->_part.shift)
+
+#define USES_PART(_vreg, _part) (_vreg->part->_part.mask)
+
+#define vreg_err(vreg, fmt, ...) \
+	pr_err("%s: " fmt, vreg->rdesc.name, ##__VA_ARGS__)
+
+#define RPM_VREG_PIN_CTRL_EN0		0x01
+#define RPM_VREG_PIN_CTRL_EN1		0x02
+#define RPM_VREG_PIN_CTRL_EN2		0x04
+#define RPM_VREG_PIN_CTRL_EN3		0x08
+#define RPM_VREG_PIN_CTRL_ALL		0x0F
+
+static const char *label_freq[] = {
+	[RPM_VREG_FREQ_NONE]		= " N/A",
+	[RPM_VREG_FREQ_19p20]		= "19.2",
+	[RPM_VREG_FREQ_9p60]		= "9.60",
+	[RPM_VREG_FREQ_6p40]		= "6.40",
+	[RPM_VREG_FREQ_4p80]		= "4.80",
+	[RPM_VREG_FREQ_3p84]		= "3.84",
+	[RPM_VREG_FREQ_3p20]		= "3.20",
+	[RPM_VREG_FREQ_2p74]		= "2.74",
+	[RPM_VREG_FREQ_2p40]		= "2.40",
+	[RPM_VREG_FREQ_2p13]		= "2.13",
+	[RPM_VREG_FREQ_1p92]		= "1.92",
+	[RPM_VREG_FREQ_1p75]		= "1.75",
+	[RPM_VREG_FREQ_1p60]		= "1.60",
+	[RPM_VREG_FREQ_1p48]		= "1.48",
+	[RPM_VREG_FREQ_1p37]		= "1.37",
+	[RPM_VREG_FREQ_1p28]		= "1.28",
+	[RPM_VREG_FREQ_1p20]		= "1.20",
+};
+
+static const char *label_corner[] = {
+	[RPM_VREG_CORNER_NONE]		= "NONE",
+	[RPM_VREG_CORNER_LOW]		= "LOW",
+	[RPM_VREG_CORNER_NOMINAL]	= "NOM",
+	[RPM_VREG_CORNER_HIGH]		= "HIGH",
+};
+
+/*
+ * This is used when voting for LPM or HPM by subtracting or adding to the
+ * hpm_min_load of a regulator.  It has units of uA.
+ */
+#define LOAD_THRESHOLD_STEP		1000
+
+/* rpm_version keeps track of the version for the currently running driver. */
+enum rpm_vreg_version rpm_version = -1;
+
+/* config holds all configuration data of the currently running driver. */
+static struct vreg_config *config;
+
+/* These regulator ID values are specified in the board file. */
+static int vreg_id_vdd_mem, vreg_id_vdd_dig;
+
+static inline int vreg_id_is_vdd_mem_or_dig(int id)
+{
+	return id == vreg_id_vdd_mem || id == vreg_id_vdd_dig;
+}
+
+#define DEBUG_PRINT_BUFFER_SIZE 512
+
+static void rpm_regulator_req(struct vreg *vreg, int set)
+{
+	int uV, mV, fm, pm, pc, pf, pd, freq, state, i;
+	const char *pf_label = "", *fm_label = "", *pc_total = "";
+	const char *pc_en[4] = {"", "", "", ""};
+	const char *pm_label = "", *freq_label = "", *corner_label = "";
+	char buf[DEBUG_PRINT_BUFFER_SIZE];
+	size_t buflen = DEBUG_PRINT_BUFFER_SIZE;
+	int pos = 0;
+
+	/* Suppress VDD_MEM and VDD_DIG printing. */
+	if ((msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_IGNORE_VDD_MEM_DIG)
+	    && vreg_id_is_vdd_mem_or_dig(vreg->id))
+		return;
+
+	uV = GET_PART(vreg, uV);
+	mV = GET_PART(vreg, mV);
+	if (vreg->type == RPM_REGULATOR_TYPE_NCP) {
+		uV = -uV;
+		mV = -mV;
+	}
+
+	fm = GET_PART(vreg, fm);
+	pm = GET_PART(vreg, pm);
+	pc = GET_PART(vreg, pc);
+	pf = GET_PART(vreg, pf);
+	pd = GET_PART(vreg, pd);
+	freq = GET_PART(vreg, freq);
+	state = GET_PART(vreg, enable_state);
+
+	if (pf >= 0 && pf < config->label_pin_func_len)
+		pf_label = config->label_pin_func[pf];
+
+	if (fm >= 0 && fm < config->label_force_mode_len)
+		fm_label = config->label_force_mode[fm];
+
+	if (pm >= 0 && pm < config->label_power_mode_len)
+		pm_label = config->label_power_mode[pm];
+
+	if (freq >= 0 && freq < ARRAY_SIZE(label_freq))
+		freq_label = label_freq[freq];
+
+	for (i = 0; i < config->label_pin_ctrl_len; i++)
+		if (pc & (1 << i))
+			pc_en[i] = config->label_pin_ctrl[i];
+
+	if (pc == RPM_VREG_PIN_CTRL_NONE)
+		pc_total = " none";
+
+	pos += scnprintf(buf + pos, buflen - pos, "%s%s: ",
+			 KERN_INFO, __func__);
+
+	pos += scnprintf(buf + pos, buflen - pos, "%s %-9s: s=%c",
+			(set == MSM_RPM_CTX_SET_0 ? "sending " : "buffered"),
+			vreg->rdesc.name,
+			(set == MSM_RPM_CTX_SET_0 ? 'A' : 'S'));
+
+	if (USES_PART(vreg, uV) && vreg->type != RPM_REGULATOR_TYPE_CORNER)
+		pos += scnprintf(buf + pos, buflen - pos, ", v=%7d uV", uV);
+	if (USES_PART(vreg, mV))
+		pos += scnprintf(buf + pos, buflen - pos, ", v=%4d mV", mV);
+	if (USES_PART(vreg, enable_state))
+		pos += scnprintf(buf + pos, buflen - pos, ", state=%s (%d)",
+				 (state == 1 ? "on" : "off"), state);
+	if (USES_PART(vreg, ip))
+		pos += scnprintf(buf + pos, buflen - pos,
+				 ", ip=%4d mA", GET_PART(vreg, ip));
+	if (USES_PART(vreg, fm))
+		pos += scnprintf(buf + pos, buflen - pos,
+				 ", fm=%s (%d)", fm_label, fm);
+	if (USES_PART(vreg, pc))
+		pos += scnprintf(buf + pos, buflen - pos,
+				 ", pc=%s%s%s%s%s (%X)", pc_en[0], pc_en[1],
+				 pc_en[2], pc_en[3], pc_total, pc);
+	if (USES_PART(vreg, pf))
+		pos += scnprintf(buf + pos, buflen - pos,
+				 ", pf=%s (%d)", pf_label, pf);
+	if (USES_PART(vreg, pd))
+		pos += scnprintf(buf + pos, buflen - pos,
+				 ", pd=%s (%d)", (pd == 1 ? "Y" : "N"), pd);
+	if (USES_PART(vreg, ia))
+		pos += scnprintf(buf + pos, buflen - pos,
+				 ", ia=%4d mA", GET_PART(vreg, ia));
+	if (USES_PART(vreg, freq)) {
+		if (vreg->type == RPM_REGULATOR_TYPE_NCP)
+			pos += scnprintf(buf + pos, buflen - pos,
+				       ", freq=%2d", freq);
+		else
+			pos += scnprintf(buf + pos, buflen - pos,
+				       ", freq=%s MHz (%2d)", freq_label, freq);
+	}
+	if (USES_PART(vreg, pm))
+		pos += scnprintf(buf + pos, buflen - pos,
+				 ", pm=%s (%d)", pm_label, pm);
+	if (USES_PART(vreg, freq_clk_src))
+		pos += scnprintf(buf + pos, buflen - pos,
+				 ", clk_src=%d", GET_PART(vreg, freq_clk_src));
+	if (USES_PART(vreg, comp_mode))
+		pos += scnprintf(buf + pos, buflen - pos,
+				 ", comp=%d", GET_PART(vreg, comp_mode));
+	if (USES_PART(vreg, hpm))
+		pos += scnprintf(buf + pos, buflen - pos,
+				 ", hpm=%d", GET_PART(vreg, hpm));
+	if (USES_PART(vreg, uV) && vreg->type == RPM_REGULATOR_TYPE_CORNER) {
+		if (uV >= 0 && uV < (ARRAY_SIZE(label_corner) - 1))
+			corner_label = label_corner[uV+1];
+		pos += scnprintf(buf + pos, buflen - pos, ", corner=%s (%d)",
+			corner_label, uV);
+	}
+
+	pos += scnprintf(buf + pos, buflen - pos, "; req[0]={%d, 0x%08X}",
+			 vreg->req[0].id, vreg->req[0].value);
+	if (vreg->part->request_len > 1)
+		pos += scnprintf(buf + pos, buflen - pos,
+				 ", req[1]={%d, 0x%08X}", vreg->req[1].id,
+				 vreg->req[1].value);
+
+	pos += scnprintf(buf + pos, buflen - pos, "\n");
+	printk(buf);
+}
+
+static void rpm_regulator_vote(struct vreg *vreg, enum rpm_vreg_voter voter,
+			int set, int voter_uV, int aggregate_uV)
+{
+	/* Suppress VDD_MEM and VDD_DIG printing. */
+	if ((msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_IGNORE_VDD_MEM_DIG)
+	    && vreg_id_is_vdd_mem_or_dig(vreg->id))
+		return;
+
+	pr_info("vote received %-9s: voter=%d, set=%c, v_voter=%7d uV, "
+		"v_aggregate=%7d uV\n", vreg->rdesc.name, voter,
+		(set == 0 ? 'A' : 'S'), voter_uV, aggregate_uV);
+}
+
+static void rpm_regulator_duplicate(struct vreg *vreg, int set, int cnt)
+{
+	/* Suppress VDD_MEM and VDD_DIG printing. */
+	if ((msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_IGNORE_VDD_MEM_DIG)
+	    && vreg_id_is_vdd_mem_or_dig(vreg->id))
+		return;
+
+	if (cnt == 2)
+		pr_info("ignored request %-9s: set=%c; req[0]={%d, 0x%08X}, "
+			"req[1]={%d, 0x%08X}\n", vreg->rdesc.name,
+			(set == 0 ? 'A' : 'S'),
+			vreg->req[0].id, vreg->req[0].value,
+			vreg->req[1].id, vreg->req[1].value);
+	else if (cnt == 1)
+		pr_info("ignored request %-9s: set=%c; req[0]={%d, 0x%08X}\n",
+			vreg->rdesc.name, (set == 0 ? 'A' : 'S'),
+			vreg->req[0].id, vreg->req[0].value);
+}
+
+/* Spin lock needed for sleep-selectable regulators. */
+static DEFINE_SPINLOCK(rpm_noirq_lock);
+
+static int voltage_from_req(struct vreg *vreg)
+{
+	int uV = 0;
+
+	if (vreg->part->uV.mask)
+		uV = GET_PART(vreg, uV);
+	else if (vreg->part->mV.mask)
+		uV = MILLI_TO_MICRO(GET_PART(vreg, mV));
+	else if (vreg->part->enable_state.mask)
+		uV = GET_PART(vreg, enable_state);
+
+	return uV;
+}
+
+static void voltage_to_req(int uV, struct vreg *vreg)
+{
+	if (vreg->part->uV.mask)
+		SET_PART(vreg, uV, uV);
+	else if (vreg->part->mV.mask)
+		SET_PART(vreg, mV, MICRO_TO_MILLI(uV));
+	else if (vreg->part->enable_state.mask)
+		SET_PART(vreg, enable_state, uV);
+}
+
+static int vreg_send_request(struct vreg *vreg, enum rpm_vreg_voter voter,
+			  int set, unsigned mask0, unsigned val0,
+			  unsigned mask1, unsigned val1, unsigned cnt,
+			  int update_voltage)
+{
+	struct msm_rpm_iv_pair *prev_req;
+	int rc = 0, max_uV_vote = 0;
+	unsigned prev0, prev1;
+	int *min_uV_vote;
+	int i;
+
+	if (set == MSM_RPM_CTX_SET_0) {
+		min_uV_vote = vreg->active_min_uV_vote;
+		prev_req = vreg->prev_active_req;
+	} else {
+		min_uV_vote = vreg->sleep_min_uV_vote;
+		prev_req = vreg->prev_sleep_req;
+	}
+
+	prev0 = vreg->req[0].value;
+	vreg->req[0].value &= ~mask0;
+	vreg->req[0].value |= val0 & mask0;
+
+	prev1 = vreg->req[1].value;
+	vreg->req[1].value &= ~mask1;
+	vreg->req[1].value |= val1 & mask1;
+
+	/* Set the force mode field based on which set is being requested. */
+	if (set == MSM_RPM_CTX_SET_0)
+		SET_PART(vreg, fm, vreg->pdata.force_mode);
+	else
+		SET_PART(vreg, fm, vreg->pdata.sleep_set_force_mode);
+
+	if (update_voltage)
+		min_uV_vote[voter] = voltage_from_req(vreg);
+
+	/* Find the highest voltage voted for and use it. */
+	for (i = 0; i < RPM_VREG_VOTER_COUNT; i++)
+		max_uV_vote = max(max_uV_vote, min_uV_vote[i]);
+	voltage_to_req(max_uV_vote, vreg);
+
+	if (msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_VOTE)
+		rpm_regulator_vote(vreg, voter, set, min_uV_vote[voter],
+				max_uV_vote);
+
+	/* Ignore duplicate requests */
+	if (vreg->req[0].value != prev_req[0].value ||
+	    vreg->req[1].value != prev_req[1].value) {
+		rc = msm_rpmrs_set_noirq(set, vreg->req, cnt);
+		if (rc) {
+			vreg->req[0].value = prev0;
+			vreg->req[1].value = prev1;
+
+			vreg_err(vreg, "msm_rpmrs_set_noirq failed - "
+				"set=%s, id=%d, rc=%d\n",
+				(set == MSM_RPM_CTX_SET_0 ? "active" : "sleep"),
+				vreg->req[0].id, rc);
+		} else {
+			/* Only save if nonzero and active set. */
+			if (max_uV_vote && (set == MSM_RPM_CTX_SET_0))
+				vreg->save_uV = max_uV_vote;
+			if (msm_rpm_vreg_debug_mask
+			    & MSM_RPM_VREG_DEBUG_REQUEST)
+				rpm_regulator_req(vreg, set);
+			prev_req[0].value = vreg->req[0].value;
+			prev_req[1].value = vreg->req[1].value;
+		}
+	} else if (msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_DUPLICATE) {
+		rpm_regulator_duplicate(vreg, set, cnt);
+	}
+
+	return rc;
+}
+
+static int vreg_set_noirq(struct vreg *vreg, enum rpm_vreg_voter voter,
+			  int sleep, unsigned mask0, unsigned val0,
+			  unsigned mask1, unsigned val1, unsigned cnt,
+			  int update_voltage)
+{
+	unsigned int s_mask[2] = {mask0, mask1}, s_val[2] = {val0, val1};
+	unsigned long flags;
+	int rc;
+
+	if (voter < 0 || voter >= RPM_VREG_VOTER_COUNT)
+		return -EINVAL;
+
+	spin_lock_irqsave(&rpm_noirq_lock, flags);
+
+	/*
+	 * Send sleep set request first so that subsequent set_mode, etc calls
+	 * use the voltage from the active set.
+	 */
+	if (sleep)
+		rc = vreg_send_request(vreg, voter, MSM_RPM_CTX_SET_SLEEP,
+				mask0, val0, mask1, val1, cnt, update_voltage);
+	else {
+		/*
+		 * Vote for 0 V in the sleep set when active set-only is
+		 * specified.  This ensures that a disable vote will be issued
+		 * at some point for the sleep set of the regulator.
+		 */
+		if (vreg->part->uV.mask) {
+			s_val[vreg->part->uV.word] = 0 << vreg->part->uV.shift;
+			s_mask[vreg->part->uV.word] = vreg->part->uV.mask;
+		} else if (vreg->part->mV.mask) {
+			s_val[vreg->part->mV.word] = 0 << vreg->part->mV.shift;
+			s_mask[vreg->part->mV.word] = vreg->part->mV.mask;
+		} else if (vreg->part->enable_state.mask) {
+			s_val[vreg->part->enable_state.word]
+				= 0 << vreg->part->enable_state.shift;
+			s_mask[vreg->part->enable_state.word]
+				= vreg->part->enable_state.mask;
+		}
+
+		rc = vreg_send_request(vreg, voter, MSM_RPM_CTX_SET_SLEEP,
+				       s_mask[0], s_val[0], s_mask[1], s_val[1],
+				       cnt, update_voltage);
+	}
+
+	rc = vreg_send_request(vreg, voter, MSM_RPM_CTX_SET_0, mask0, val0,
+					mask1, val1, cnt, update_voltage);
+
+	spin_unlock_irqrestore(&rpm_noirq_lock, flags);
+
+	return rc;
+}
+
+/**
+ * rpm_vreg_set_voltage - vote for a min_uV value of specified regualtor
+ * @vreg: ID for regulator
+ * @voter: ID for the voter
+ * @min_uV: minimum acceptable voltage (in uV) that is voted for
+ * @max_uV: maximum acceptable voltage (in uV) that is voted for
+ * @sleep_also: 0 for active set only, non-0 for active set and sleep set
+ *
+ * Returns 0 on success or errno.
+ *
+ * This function is used to vote for the voltage of a regulator without
+ * using the regulator framework.  It is needed by consumers which hold spin
+ * locks or have interrupts disabled because the regulator framework can sleep.
+ * It is also needed by consumers which wish to only vote for active set
+ * regulator voltage.
+ *
+ * If sleep_also == 0, then a sleep-set value of 0V will be voted for.
+ *
+ * This function may only be called for regulators which have the sleep flag
+ * specified in their private data.
+ *
+ * Consumers can vote to disable a regulator with this function by passing
+ * min_uV = 0 and max_uV = 0.
+ *
+ * Voltage switch type regulators may be controlled via rpm_vreg_set_voltage
+ * as well.  For this type of regulator, max_uV > 0 is treated as an enable
+ * request and max_uV == 0 is treated as a disable request.
+ */
+int rpm_vreg_set_voltage(int vreg_id, enum rpm_vreg_voter voter, int min_uV,
+			 int max_uV, int sleep_also)
+{
+	unsigned int mask[2] = {0}, val[2] = {0};
+	struct vreg_range *range;
+	struct vreg *vreg;
+	int uV = min_uV;
+	int lim_min_uV, lim_max_uV, i, rc;
+
+	if (!config) {
+		pr_err("rpm-regulator driver has not probed yet.\n");
+		return -ENODEV;
+	}
+
+	if (vreg_id < config->vreg_id_min || vreg_id > config->vreg_id_max) {
+		pr_err("invalid regulator id=%d\n", vreg_id);
+		return -EINVAL;
+	}
+
+	vreg = &config->vregs[vreg_id];
+
+	if (!vreg->pdata.sleep_selectable) {
+		vreg_err(vreg, "regulator is not marked sleep selectable\n");
+		return -EINVAL;
+	}
+
+	/* Allow min_uV == max_uV == 0 to represent a disable request. */
+	if ((min_uV != 0 || max_uV != 0)
+	    && (vreg->part->uV.mask || vreg->part->mV.mask)) {
+		/*
+		 * Check if request voltage is outside of allowed range. The
+		 * regulator core has already checked that constraint range
+		 * is inside of the physically allowed range.
+		 */
+		lim_min_uV = vreg->pdata.init_data.constraints.min_uV;
+		lim_max_uV = vreg->pdata.init_data.constraints.max_uV;
+
+		if (uV < lim_min_uV && max_uV >= lim_min_uV)
+			uV = lim_min_uV;
+
+		if (uV < lim_min_uV || uV > lim_max_uV) {
+			vreg_err(vreg, "request v=[%d, %d] is outside allowed "
+				"v=[%d, %d]\n", min_uV, max_uV, lim_min_uV,
+				lim_max_uV);
+			return -EINVAL;
+		}
+
+		range = &vreg->set_points->range[0];
+		/* Find the range which uV is inside of. */
+		for (i = vreg->set_points->count - 1; i > 0; i--) {
+			if (uV > vreg->set_points->range[i - 1].max_uV) {
+				range = &vreg->set_points->range[i];
+				break;
+			}
+		}
+
+		/*
+		 * Force uV to be an allowed set point and apply a ceiling
+		 * function to non-set point values.
+		 */
+		uV = (uV - range->min_uV + range->step_uV - 1) / range->step_uV;
+		uV = uV * range->step_uV + range->min_uV;
+
+		if (uV > max_uV) {
+			vreg_err(vreg,
+			  "request v=[%d, %d] cannot be met by any set point; "
+			  "next set point: %d\n",
+			  min_uV, max_uV, uV);
+			return -EINVAL;
+		}
+	}
+
+	if (vreg->type == RPM_REGULATOR_TYPE_CORNER) {
+		/*
+		 * Translate from enum values which work as inputs in the
+		 * rpm_vreg_set_voltage function to the actual corner values
+		 * sent to the RPM.
+		 */
+		if (uV > 0)
+			uV -= RPM_VREG_CORNER_NONE;
+	}
+
+	if (vreg->part->uV.mask) {
+		val[vreg->part->uV.word] = uV << vreg->part->uV.shift;
+		mask[vreg->part->uV.word] = vreg->part->uV.mask;
+	} else if (vreg->part->mV.mask) {
+		val[vreg->part->mV.word]
+			= MICRO_TO_MILLI(uV) << vreg->part->mV.shift;
+		mask[vreg->part->mV.word] = vreg->part->mV.mask;
+	} else if (vreg->part->enable_state.mask) {
+		/*
+		 * Translate max_uV > 0 into an enable request for regulator
+		 * types which to not support voltage setting, e.g. voltage
+		 * switches.
+		 */
+		val[vreg->part->enable_state.word]
+		    = (max_uV > 0 ? 1 : 0) << vreg->part->enable_state.shift;
+		mask[vreg->part->enable_state.word]
+		    = vreg->part->enable_state.mask;
+	}
+
+	rc = vreg_set_noirq(vreg, voter, sleep_also, mask[0], val[0], mask[1],
+			    val[1], vreg->part->request_len, 1);
+	if (rc)
+		vreg_err(vreg, "vreg_set_noirq failed, rc=%d\n", rc);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(rpm_vreg_set_voltage);
+
+/**
+ * rpm_vreg_set_frequency - sets the frequency of a switching regulator
+ * @vreg: ID for regulator
+ * @freq: enum corresponding to desired frequency
+ *
+ * Returns 0 on success or errno.
+ */
+int rpm_vreg_set_frequency(int vreg_id, enum rpm_vreg_freq freq)
+{
+	unsigned int mask[2] = {0}, val[2] = {0};
+	struct vreg *vreg;
+	int rc;
+
+	if (!config) {
+		pr_err("rpm-regulator driver has not probed yet.\n");
+		return -ENODEV;
+	}
+
+	if (vreg_id < config->vreg_id_min || vreg_id > config->vreg_id_max) {
+		pr_err("invalid regulator id=%d\n", vreg_id);
+		return -EINVAL;
+	}
+
+	vreg = &config->vregs[vreg_id];
+
+	if (freq < 0 || freq > RPM_VREG_FREQ_1p20) {
+		vreg_err(vreg, "invalid frequency=%d\n", freq);
+		return -EINVAL;
+	}
+	if (!vreg->pdata.sleep_selectable) {
+		vreg_err(vreg, "regulator is not marked sleep selectable\n");
+		return -EINVAL;
+	}
+	if (!vreg->part->freq.mask) {
+		vreg_err(vreg, "frequency not supported\n");
+		return -EINVAL;
+	}
+
+	val[vreg->part->freq.word] = freq << vreg->part->freq.shift;
+	mask[vreg->part->freq.word] = vreg->part->freq.mask;
+
+	rc = vreg_set_noirq(vreg, RPM_VREG_VOTER_REG_FRAMEWORK, 1, mask[0],
+			   val[0], mask[1], val[1], vreg->part->request_len, 0);
+	if (rc)
+		vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(rpm_vreg_set_frequency);
+
+#define MAX_NAME_LEN 64
+/**
+ * rpm_regulator_get() - lookup and obtain a handle to an RPM regulator
+ * @dev: device for regulator consumer
+ * @supply: supply name
+ *
+ * Returns a struct rpm_regulator corresponding to the regulator producer,
+ * or ERR_PTR() containing errno.
+ *
+ * This function may only be called from nonatomic context.  The mapping between
+ * <dev, supply> tuples and rpm_regulators struct pointers is specified via
+ * rpm-regulator platform data.
+ */
+struct rpm_regulator *rpm_regulator_get(struct device *dev, const char *supply)
+{
+	struct rpm_regulator_consumer_mapping *mapping = NULL;
+	const char *devname = NULL;
+	struct rpm_regulator *regulator;
+	int i;
+
+	if (!config) {
+		pr_err("rpm-regulator driver has not probed yet.\n");
+		return ERR_PTR(-ENODEV);
+	}
+
+	if (consumer_map == NULL || consumer_map_len == 0) {
+		pr_err("No private consumer mapping has been specified.\n");
+		return ERR_PTR(-ENODEV);
+	}
+
+	if (supply == NULL) {
+		pr_err("supply name must be specified\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (dev)
+		devname = dev_name(dev);
+
+	for (i = 0; i < consumer_map_len; i++) {
+		/* If the mapping has a device set up it must match */
+		if (consumer_map[i].dev_name &&
+			(!devname || strncmp(consumer_map[i].dev_name, devname,
+					     MAX_NAME_LEN)))
+			continue;
+
+		if (strncmp(consumer_map[i].supply, supply, MAX_NAME_LEN)
+		    == 0) {
+			mapping = &consumer_map[i];
+			break;
+		}
+	}
+
+	if (mapping == NULL) {
+		pr_err("could not find mapping for dev=%s, supply=%s\n",
+			(devname ? devname : "(null)"), supply);
+		return ERR_PTR(-ENODEV);
+	}
+
+	regulator = kzalloc(sizeof(struct rpm_regulator), GFP_KERNEL);
+	if (regulator == NULL) {
+		pr_err("could not allocate memory for regulator\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	regulator->vreg_id	= mapping->vreg_id;
+	regulator->voter	= mapping->voter;
+	regulator->sleep_also	= mapping->sleep_also;
+
+	return regulator;
+}
+EXPORT_SYMBOL_GPL(rpm_regulator_get);
+
+static int rpm_regulator_check_input(struct rpm_regulator *regulator)
+{
+	int rc = 0;
+
+	if (regulator == NULL) {
+		rc = -EINVAL;
+		pr_err("invalid (null) rpm_regulator pointer\n");
+	} else if (IS_ERR(regulator)) {
+		rc = PTR_ERR(regulator);
+		pr_err("invalid rpm_regulator pointer, rc=%d\n", rc);
+	}
+
+	return rc;
+}
+
+/**
+ * rpm_regulator_put() - free the RPM regulator handle
+ * @regulator: RPM regulator handle
+ *
+ * Parameter reaggregation does not take place when rpm_regulator_put is called.
+ * Therefore, regulator enable state and voltage must be configured
+ * appropriately before calling rpm_regulator_put.
+ *
+ * This function may be called from either atomic or nonatomic context.
+ */
+void rpm_regulator_put(struct rpm_regulator *regulator)
+{
+	kfree(regulator);
+}
+EXPORT_SYMBOL_GPL(rpm_regulator_put);
+
+/**
+ * rpm_regulator_enable() - enable regulator output
+ * @regulator: RPM regulator handle
+ *
+ * Returns 0 on success or errno on failure.
+ *
+ * This function may be called from either atomic or nonatomic context.  This
+ * function may only be called for regulators which have the sleep_selectable
+ * flag set in their configuration data.
+ *
+ * rpm_regulator_set_voltage must be called before rpm_regulator_enable because
+ * enabling is defined by the RPM interface to be requesting the desired
+ * non-zero regulator output voltage.
+ */
+int rpm_regulator_enable(struct rpm_regulator *regulator)
+{
+	int rc = rpm_regulator_check_input(regulator);
+	struct vreg *vreg;
+
+	if (rc)
+		return rc;
+
+	if (regulator->vreg_id < config->vreg_id_min
+			|| regulator->vreg_id > config->vreg_id_max) {
+		pr_err("invalid regulator id=%d\n", regulator->vreg_id);
+		return -EINVAL;
+	}
+
+	vreg = &config->vregs[regulator->vreg_id];
+
+	/*
+	 * Handle voltage switches which can be enabled without
+	 * rpm_regulator_set_voltage ever being called.
+	 */
+	if (regulator->min_uV == 0 && regulator->max_uV == 0
+	    && vreg->part->uV.mask == 0 && vreg->part->mV.mask == 0) {
+		regulator->min_uV = 1;
+		regulator->max_uV = 1;
+	}
+
+	if (regulator->min_uV == 0 && regulator->max_uV == 0) {
+		pr_err("Voltage must be set with rpm_regulator_set_voltage "
+			"before calling rpm_regulator_enable; vreg_id=%d, "
+			"voter=%d\n", regulator->vreg_id, regulator->voter);
+		return -EINVAL;
+	}
+
+	rc = rpm_vreg_set_voltage(regulator->vreg_id, regulator->voter,
+		regulator->min_uV, regulator->max_uV, regulator->sleep_also);
+
+	if (rc)
+		pr_err("rpm_vreg_set_voltage failed, rc=%d\n", rc);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(rpm_regulator_enable);
+
+/**
+ * rpm_regulator_disable() - disable regulator output
+ * @regulator: RPM regulator handle
+ *
+ * Returns 0 on success or errno on failure.
+ *
+ * The enable state of the regulator is determined by aggregating the requests
+ * of all consumers.  Therefore, it is possible that the regulator will remain
+ * enabled even after rpm_regulator_disable is called.
+ *
+ * This function may be called from either atomic or nonatomic context.  This
+ * function may only be called for regulators which have the sleep_selectable
+ * flag set in their configuration data.
+ */
+int rpm_regulator_disable(struct rpm_regulator *regulator)
+{
+	int rc = rpm_regulator_check_input(regulator);
+
+	if (rc)
+		return rc;
+
+	rc = rpm_vreg_set_voltage(regulator->vreg_id, regulator->voter, 0, 0,
+				  regulator->sleep_also);
+
+	if (rc)
+		pr_err("rpm_vreg_set_voltage failed, rc=%d\n", rc);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(rpm_regulator_disable);
+
+/**
+ * rpm_regulator_set_voltage() - set regulator output voltage
+ * @regulator: RPM regulator handle
+ * @min_uV: minimum required voltage in uV
+ * @max_uV: maximum acceptable voltage in uV
+ *
+ * Sets a voltage regulator to the desired output voltage. This can be set
+ * while the regulator is disabled or enabled.  If the regulator is disabled,
+ * then rpm_regulator_set_voltage will both enable the regulator and set it to
+ * output at the requested voltage.
+ *
+ * The min_uV to max_uV voltage range requested must intersect with the
+ * voltage constraint range configured for the regulator.
+ *
+ * Returns 0 on success or errno on failure.
+ *
+ * The final voltage value that is sent to the RPM is aggregated based upon the
+ * values requested by all consumers of the regulator.  This corresponds to the
+ * maximum min_uV value.
+ *
+ * This function may be called from either atomic or nonatomic context.  This
+ * function may only be called for regulators which have the sleep_selectable
+ * flag set in their configuration data.
+ */
+int rpm_regulator_set_voltage(struct rpm_regulator *regulator, int min_uV,
+			      int max_uV)
+{
+	int rc = rpm_regulator_check_input(regulator);
+
+	if (rc)
+		return rc;
+
+	rc = rpm_vreg_set_voltage(regulator->vreg_id, regulator->voter, min_uV,
+				 max_uV, regulator->sleep_also);
+
+	if (rc) {
+		pr_err("rpm_vreg_set_voltage failed, rc=%d\n", rc);
+	} else {
+		regulator->min_uV = min_uV;
+		regulator->max_uV = max_uV;
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(rpm_regulator_set_voltage);
+
+static inline int vreg_hpm_min_uA(struct vreg *vreg)
+{
+	return vreg->hpm_min_load;
+}
+
+static inline int vreg_lpm_max_uA(struct vreg *vreg)
+{
+	return vreg->hpm_min_load - LOAD_THRESHOLD_STEP;
+}
+
+static inline unsigned saturate_peak_load(struct vreg *vreg, unsigned load_uA)
+{
+	unsigned load_max
+		= MILLI_TO_MICRO(vreg->part->ip.mask >> vreg->part->ip.shift);
+
+	return (load_uA > load_max ? load_max : load_uA);
+}
+
+static inline unsigned saturate_avg_load(struct vreg *vreg, unsigned load_uA)
+{
+	unsigned load_max
+		= MILLI_TO_MICRO(vreg->part->ia.mask >> vreg->part->ia.shift);
+	return (load_uA > load_max ? load_max : load_uA);
+}
+
+/* Change vreg->req, but do not send it to the RPM. */
+static int vreg_store(struct vreg *vreg, unsigned mask0, unsigned val0,
+		unsigned mask1, unsigned val1)
+{
+	unsigned long flags = 0;
+
+	if (vreg->pdata.sleep_selectable)
+		spin_lock_irqsave(&rpm_noirq_lock, flags);
+
+	vreg->req[0].value &= ~mask0;
+	vreg->req[0].value |= val0 & mask0;
+
+	vreg->req[1].value &= ~mask1;
+	vreg->req[1].value |= val1 & mask1;
+
+	if (vreg->pdata.sleep_selectable)
+		spin_unlock_irqrestore(&rpm_noirq_lock, flags);
+
+	return 0;
+}
+
+static int vreg_set(struct vreg *vreg, unsigned mask0, unsigned val0,
+		unsigned mask1, unsigned val1, unsigned cnt)
+{
+	unsigned prev0 = 0, prev1 = 0;
+	int rc;
+
+	/*
+	 * Bypass the normal route for regulators that can be called to change
+	 * just the active set values.
+	 */
+	if (vreg->pdata.sleep_selectable)
+		return vreg_set_noirq(vreg, RPM_VREG_VOTER_REG_FRAMEWORK, 1,
+					mask0, val0, mask1, val1, cnt, 1);
+
+	prev0 = vreg->req[0].value;
+	vreg->req[0].value &= ~mask0;
+	vreg->req[0].value |= val0 & mask0;
+
+	prev1 = vreg->req[1].value;
+	vreg->req[1].value &= ~mask1;
+	vreg->req[1].value |= val1 & mask1;
+
+	/* Ignore duplicate requests */
+	if (vreg->req[0].value == vreg->prev_active_req[0].value &&
+	    vreg->req[1].value == vreg->prev_active_req[1].value) {
+		if (msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_DUPLICATE)
+			rpm_regulator_duplicate(vreg, MSM_RPM_CTX_SET_0, cnt);
+		return 0;
+	}
+
+	rc = msm_rpm_set(MSM_RPM_CTX_SET_0, vreg->req, cnt);
+	if (rc) {
+		vreg->req[0].value = prev0;
+		vreg->req[1].value = prev1;
+
+		vreg_err(vreg, "msm_rpm_set failed, set=active, id=%d, rc=%d\n",
+			vreg->req[0].id, rc);
+	} else {
+		if (msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_REQUEST)
+			rpm_regulator_req(vreg, MSM_RPM_CTX_SET_0);
+		vreg->prev_active_req[0].value = vreg->req[0].value;
+		vreg->prev_active_req[1].value = vreg->req[1].value;
+	}
+
+	return rc;
+}
+
+static int vreg_is_enabled(struct regulator_dev *rdev)
+{
+	struct vreg *vreg = rdev_get_drvdata(rdev);
+	int enabled;
+
+	mutex_lock(&vreg->pc_lock);
+	enabled = vreg->is_enabled;
+	mutex_unlock(&vreg->pc_lock);
+
+	return enabled;
+}
+
+static void set_enable(struct vreg *vreg, unsigned int *mask, unsigned int *val)
+{
+	switch (vreg->type) {
+	case RPM_REGULATOR_TYPE_LDO:
+	case RPM_REGULATOR_TYPE_SMPS:
+	case RPM_REGULATOR_TYPE_CORNER:
+		/* Enable by setting a voltage. */
+		if (vreg->part->uV.mask) {
+			val[vreg->part->uV.word]
+				|= vreg->save_uV << vreg->part->uV.shift;
+			mask[vreg->part->uV.word] |= vreg->part->uV.mask;
+		} else {
+			val[vreg->part->mV.word]
+				|= MICRO_TO_MILLI(vreg->save_uV)
+					<< vreg->part->mV.shift;
+			mask[vreg->part->mV.word] |= vreg->part->mV.mask;
+		}
+		break;
+	case RPM_REGULATOR_TYPE_VS:
+	case RPM_REGULATOR_TYPE_NCP:
+		/* Enable by setting enable_state. */
+		val[vreg->part->enable_state.word]
+			|= RPM_VREG_STATE_ON << vreg->part->enable_state.shift;
+		mask[vreg->part->enable_state.word]
+			|= vreg->part->enable_state.mask;
+	}
+}
+
+static int rpm_vreg_enable(struct regulator_dev *rdev)
+{
+	struct vreg *vreg = rdev_get_drvdata(rdev);
+	unsigned int mask[2] = {0}, val[2] = {0};
+	int rc = 0;
+
+	set_enable(vreg, mask, val);
+
+	mutex_lock(&vreg->pc_lock);
+
+	rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
+			vreg->part->request_len);
+	if (!rc)
+		vreg->is_enabled = true;
+
+	mutex_unlock(&vreg->pc_lock);
+
+	if (rc)
+		vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
+
+	return rc;
+}
+
+static void set_disable(struct vreg *vreg, unsigned int *mask,
+			unsigned int *val)
+{
+	switch (vreg->type) {
+	case RPM_REGULATOR_TYPE_LDO:
+	case RPM_REGULATOR_TYPE_SMPS:
+	case RPM_REGULATOR_TYPE_CORNER:
+		/* Disable by setting a voltage of 0 uV. */
+		if (vreg->part->uV.mask) {
+			val[vreg->part->uV.word] |= 0 << vreg->part->uV.shift;
+			mask[vreg->part->uV.word] |= vreg->part->uV.mask;
+		} else {
+			val[vreg->part->mV.word] |= 0 << vreg->part->mV.shift;
+			mask[vreg->part->mV.word] |= vreg->part->mV.mask;
+		}
+		break;
+	case RPM_REGULATOR_TYPE_VS:
+	case RPM_REGULATOR_TYPE_NCP:
+		/* Disable by setting enable_state. */
+		val[vreg->part->enable_state.word]
+			|= RPM_VREG_STATE_OFF << vreg->part->enable_state.shift;
+		mask[vreg->part->enable_state.word]
+			|= vreg->part->enable_state.mask;
+	}
+}
+
+static int rpm_vreg_disable(struct regulator_dev *rdev)
+{
+	struct vreg *vreg = rdev_get_drvdata(rdev);
+	unsigned int mask[2] = {0}, val[2] = {0};
+	int rc = 0;
+
+	set_disable(vreg, mask, val);
+
+	mutex_lock(&vreg->pc_lock);
+
+	/* Only disable if pin control is not in use. */
+	if (!vreg->is_enabled_pc)
+		rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
+				vreg->part->request_len);
+
+	if (!rc)
+		vreg->is_enabled = false;
+
+	mutex_unlock(&vreg->pc_lock);
+
+	if (rc)
+		vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
+
+	return rc;
+}
+
+static int vreg_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
+			    unsigned *selector)
+{
+	struct vreg *vreg = rdev_get_drvdata(rdev);
+	struct vreg_range *range = &vreg->set_points->range[0];
+	unsigned int mask[2] = {0}, val[2] = {0};
+	int rc = 0, uV = min_uV;
+	int lim_min_uV, lim_max_uV, i;
+
+	/* Check if request voltage is outside of physically settable range. */
+	lim_min_uV = vreg->set_points->range[0].min_uV;
+	lim_max_uV =
+		vreg->set_points->range[vreg->set_points->count - 1].max_uV;
+
+	if (uV < lim_min_uV && max_uV >= lim_min_uV)
+		uV = lim_min_uV;
+
+	if (uV < lim_min_uV || uV > lim_max_uV) {
+		vreg_err(vreg,
+			"request v=[%d, %d] is outside possible v=[%d, %d]\n",
+			 min_uV, max_uV, lim_min_uV, lim_max_uV);
+		return -EINVAL;
+	}
+
+	/* Find the range which uV is inside of. */
+	for (i = vreg->set_points->count - 1; i > 0; i--) {
+		if (uV > vreg->set_points->range[i - 1].max_uV) {
+			range = &vreg->set_points->range[i];
+			break;
+		}
+	}
+
+	/*
+	 * Force uV to be an allowed set point and apply a ceiling function
+	 * to non-set point values.
+	 */
+	uV = (uV - range->min_uV + range->step_uV - 1) / range->step_uV;
+	uV = uV * range->step_uV + range->min_uV;
+
+	if (uV > max_uV) {
+		vreg_err(vreg,
+			"request v=[%d, %d] cannot be met by any set point; "
+			"next set point: %d\n",
+			min_uV, max_uV, uV);
+		return -EINVAL;
+	}
+
+	if (vreg->type == RPM_REGULATOR_TYPE_CORNER) {
+		/*
+		 * Translate from enum values which work as inputs in the
+		 * regulator_set_voltage function to the actual corner values
+		 * sent to the RPM.
+		 */
+		uV -= RPM_VREG_CORNER_NONE;
+	}
+
+	if (vreg->part->uV.mask) {
+		val[vreg->part->uV.word] = uV << vreg->part->uV.shift;
+		mask[vreg->part->uV.word] = vreg->part->uV.mask;
+	} else {
+		val[vreg->part->mV.word]
+			= MICRO_TO_MILLI(uV) << vreg->part->mV.shift;
+		mask[vreg->part->mV.word] = vreg->part->mV.mask;
+	}
+
+	mutex_lock(&vreg->pc_lock);
+
+	/*
+	 * Only send a request for a new voltage if the regulator is currently
+	 * enabled.  This will ensure that LDO and SMPS regulators are not
+	 * inadvertently turned on because voltage > 0 is equivalent to
+	 * enabling.  For NCP, this just removes unnecessary RPM requests.
+	 */
+	if (vreg->is_enabled) {
+		rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
+				vreg->part->request_len);
+		if (rc)
+			vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
+	} else if (vreg->type == RPM_REGULATOR_TYPE_NCP) {
+		/* Regulator is disabled; store but don't send new request. */
+		rc = vreg_store(vreg, mask[0], val[0], mask[1], val[1]);
+	}
+
+	if (!rc && (!vreg->pdata.sleep_selectable || !vreg->is_enabled))
+		vreg->save_uV = uV;
+
+	mutex_unlock(&vreg->pc_lock);
+
+	return rc;
+}
+
+static int vreg_get_voltage(struct regulator_dev *rdev)
+{
+	struct vreg *vreg = rdev_get_drvdata(rdev);
+
+	return vreg->save_uV;
+}
+
+static int vreg_list_voltage(struct regulator_dev *rdev, unsigned selector)
+{
+	struct vreg *vreg = rdev_get_drvdata(rdev);
+	int uV = 0;
+	int i;
+
+	if (!vreg->set_points) {
+		vreg_err(vreg, "no voltages available\n");
+		return -EINVAL;
+	}
+
+	if (selector >= vreg->set_points->n_voltages)
+		return 0;
+
+	for (i = 0; i < vreg->set_points->count; i++) {
+		if (selector < vreg->set_points->range[i].n_voltages) {
+			uV = selector * vreg->set_points->range[i].step_uV
+				+ vreg->set_points->range[i].min_uV;
+			break;
+		} else {
+			selector -= vreg->set_points->range[i].n_voltages;
+		}
+	}
+
+	return uV;
+}
+
+static int vreg_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	struct vreg *vreg = rdev_get_drvdata(rdev);
+	unsigned int mask[2] = {0}, val[2] = {0};
+	int rc = 0;
+	int peak_uA;
+
+	mutex_lock(&vreg->pc_lock);
+
+	peak_uA = MILLI_TO_MICRO((vreg->req[vreg->part->ip.word].value
+				& vreg->part->ip.mask) >> vreg->part->ip.shift);
+
+	if (mode == config->mode_hpm) {
+		/* Make sure that request currents are in HPM range. */
+		if (peak_uA < vreg_hpm_min_uA(vreg)) {
+			val[vreg->part->ip.word]
+				= MICRO_TO_MILLI(vreg_hpm_min_uA(vreg))
+					<< vreg->part->ip.shift;
+			mask[vreg->part->ip.word] = vreg->part->ip.mask;
+
+			if (config->ia_follows_ip) {
+				val[vreg->part->ia.word]
+					|= MICRO_TO_MILLI(vreg_hpm_min_uA(vreg))
+						<< vreg->part->ia.shift;
+				mask[vreg->part->ia.word]
+					|= vreg->part->ia.mask;
+			}
+		}
+	} else if (mode == config->mode_lpm) {
+		/* Make sure that request currents are in LPM range. */
+		if (peak_uA > vreg_lpm_max_uA(vreg)) {
+			val[vreg->part->ip.word]
+				= MICRO_TO_MILLI(vreg_lpm_max_uA(vreg))
+					<< vreg->part->ip.shift;
+			mask[vreg->part->ip.word] = vreg->part->ip.mask;
+
+			if (config->ia_follows_ip) {
+				val[vreg->part->ia.word]
+					|= MICRO_TO_MILLI(vreg_lpm_max_uA(vreg))
+						<< vreg->part->ia.shift;
+				mask[vreg->part->ia.word]
+					|= vreg->part->ia.mask;
+			}
+		}
+	} else {
+		vreg_err(vreg, "invalid mode: %u\n", mode);
+		mutex_unlock(&vreg->pc_lock);
+		return -EINVAL;
+	}
+
+	if (vreg->is_enabled) {
+		rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
+					vreg->part->request_len);
+	} else {
+		/* Regulator is disabled; store but don't send new request. */
+		rc = vreg_store(vreg, mask[0], val[0], mask[1], val[1]);
+	}
+
+	if (rc)
+		vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
+	else
+		vreg->mode = mode;
+
+	mutex_unlock(&vreg->pc_lock);
+
+	return rc;
+}
+
+static unsigned int vreg_get_mode(struct regulator_dev *rdev)
+{
+	struct vreg *vreg = rdev_get_drvdata(rdev);
+
+	return vreg->mode;
+}
+
+static unsigned int vreg_get_optimum_mode(struct regulator_dev *rdev,
+			int input_uV, int output_uV, int load_uA)
+{
+	struct vreg *vreg = rdev_get_drvdata(rdev);
+	unsigned int mode;
+
+	load_uA += vreg->pdata.system_uA;
+
+	mutex_lock(&vreg->pc_lock);
+	SET_PART(vreg, ip, MICRO_TO_MILLI(saturate_peak_load(vreg, load_uA)));
+	if (config->ia_follows_ip)
+		SET_PART(vreg, ia,
+			 MICRO_TO_MILLI(saturate_avg_load(vreg, load_uA)));
+	mutex_unlock(&vreg->pc_lock);
+
+	if (load_uA >= vreg->hpm_min_load)
+		mode = config->mode_hpm;
+	else
+		mode = config->mode_lpm;
+
+	return mode;
+}
+
+static unsigned int vreg_legacy_get_optimum_mode(struct regulator_dev *rdev,
+			int input_uV, int output_uV, int load_uA)
+{
+	struct vreg *vreg = rdev_get_drvdata(rdev);
+
+	if (MICRO_TO_MILLI(load_uA) <= 0) {
+		/*
+		 * vreg_legacy_get_optimum_mode is being called before consumers
+		 * have specified their load currents via
+		 * regulator_set_optimum_mode. Return whatever the existing mode
+		 * is.
+		 */
+		return vreg->mode;
+	}
+
+	return vreg_get_optimum_mode(rdev, input_uV, output_uV, load_uA);
+}
+
+/*
+ * Returns the logical pin control enable state because the pin control options
+ * present in the hardware out of restart could be different from those desired
+ * by the consumer.
+ */
+static int vreg_pin_control_is_enabled(struct regulator_dev *rdev)
+{
+	struct vreg *vreg = rdev_get_drvdata(rdev);
+
+	return vreg->is_enabled_pc;
+}
+
+static int vreg_pin_control_enable(struct regulator_dev *rdev)
+{
+	struct vreg *vreg = rdev_get_drvdata(rdev);
+	unsigned int mask[2] = {0}, val[2] = {0};
+	int rc;
+
+	mutex_lock(&vreg->pc_lock);
+
+	val[vreg->part->pc.word]
+		|= vreg->pdata.pin_ctrl << vreg->part->pc.shift;
+	mask[vreg->part->pc.word] |= vreg->part->pc.mask;
+
+	val[vreg->part->pf.word]  |= vreg->pdata.pin_fn << vreg->part->pf.shift;
+	mask[vreg->part->pf.word] |= vreg->part->pf.mask;
+
+	if (!vreg->is_enabled)
+		set_enable(vreg, mask, val);
+
+	rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
+			vreg->part->request_len);
+
+	if (!rc)
+		vreg->is_enabled_pc = true;
+
+	mutex_unlock(&vreg->pc_lock);
+
+	if (rc)
+		vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
+
+	return rc;
+}
+
+static int vreg_pin_control_disable(struct regulator_dev *rdev)
+{
+	struct vreg *vreg = rdev_get_drvdata(rdev);
+	unsigned int mask[2] = {0}, val[2] = {0};
+	int pin_fn, rc;
+
+	mutex_lock(&vreg->pc_lock);
+
+	val[vreg->part->pc.word]
+		|= RPM_VREG_PIN_CTRL_NONE << vreg->part->pc.shift;
+	mask[vreg->part->pc.word] |= vreg->part->pc.mask;
+
+	pin_fn = config->pin_func_none;
+	if (vreg->pdata.pin_fn == config->pin_func_sleep_b)
+		pin_fn = config->pin_func_sleep_b;
+	val[vreg->part->pf.word]  |= pin_fn << vreg->part->pf.shift;
+	mask[vreg->part->pf.word] |= vreg->part->pf.mask;
+
+	if (!vreg->is_enabled)
+		set_disable(vreg, mask, val);
+
+	rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
+			vreg->part->request_len);
+
+	if (!rc)
+		vreg->is_enabled_pc = false;
+
+	mutex_unlock(&vreg->pc_lock);
+
+	if (rc)
+		vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
+
+	return rc;
+}
+
+static int vreg_enable_time(struct regulator_dev *rdev)
+{
+	struct vreg *vreg = rdev_get_drvdata(rdev);
+
+	return vreg->pdata.enable_time;
+}
+
+/* Real regulator operations. */
+static struct regulator_ops ldo_ops = {
+	.enable			= rpm_vreg_enable,
+	.disable		= rpm_vreg_disable,
+	.is_enabled		= vreg_is_enabled,
+	.set_voltage		= vreg_set_voltage,
+	.get_voltage		= vreg_get_voltage,
+	.list_voltage		= vreg_list_voltage,
+	.set_mode		= vreg_set_mode,
+	.get_mode		= vreg_get_mode,
+	.get_optimum_mode	= vreg_get_optimum_mode,
+	.enable_time		= vreg_enable_time,
+};
+
+static struct regulator_ops smps_ops = {
+	.enable			= rpm_vreg_enable,
+	.disable		= rpm_vreg_disable,
+	.is_enabled		= vreg_is_enabled,
+	.set_voltage		= vreg_set_voltage,
+	.get_voltage		= vreg_get_voltage,
+	.list_voltage		= vreg_list_voltage,
+	.set_mode		= vreg_set_mode,
+	.get_mode		= vreg_get_mode,
+	.get_optimum_mode	= vreg_get_optimum_mode,
+	.enable_time		= vreg_enable_time,
+};
+
+static struct regulator_ops switch_ops = {
+	.enable			= rpm_vreg_enable,
+	.disable		= rpm_vreg_disable,
+	.is_enabled		= vreg_is_enabled,
+	.enable_time		= vreg_enable_time,
+};
+
+static struct regulator_ops ncp_ops = {
+	.enable			= rpm_vreg_enable,
+	.disable		= rpm_vreg_disable,
+	.is_enabled		= vreg_is_enabled,
+	.set_voltage		= vreg_set_voltage,
+	.get_voltage		= vreg_get_voltage,
+	.list_voltage		= vreg_list_voltage,
+	.enable_time		= vreg_enable_time,
+};
+
+static struct regulator_ops corner_ops = {
+	.enable			= rpm_vreg_enable,
+	.disable		= rpm_vreg_disable,
+	.is_enabled		= vreg_is_enabled,
+	.set_voltage		= vreg_set_voltage,
+	.get_voltage		= vreg_get_voltage,
+	.list_voltage		= vreg_list_voltage,
+	.enable_time		= vreg_enable_time,
+};
+
+/* Pin control regulator operations. */
+static struct regulator_ops pin_control_ops = {
+	.enable			= vreg_pin_control_enable,
+	.disable		= vreg_pin_control_disable,
+	.is_enabled		= vreg_pin_control_is_enabled,
+};
+
+struct regulator_ops *vreg_ops[] = {
+	[RPM_REGULATOR_TYPE_LDO]	= &ldo_ops,
+	[RPM_REGULATOR_TYPE_SMPS]	= &smps_ops,
+	[RPM_REGULATOR_TYPE_VS]		= &switch_ops,
+	[RPM_REGULATOR_TYPE_NCP]	= &ncp_ops,
+	[RPM_REGULATOR_TYPE_CORNER]	= &corner_ops,
+};
+
+static int __devinit
+rpm_vreg_init_regulator(const struct rpm_regulator_init_data *pdata,
+			struct device *dev)
+{
+	struct regulator_desc *rdesc = NULL;
+	struct regulator_dev *rdev;
+	struct vreg *vreg;
+	unsigned pin_ctrl;
+	int id, pin_fn;
+	int rc = 0;
+
+	if (!pdata) {
+		pr_err("platform data missing\n");
+		return -EINVAL;
+	}
+
+	id = pdata->id;
+
+	if (id < config->vreg_id_min || id > config->vreg_id_max) {
+		pr_err("invalid regulator id: %d\n", id);
+		return -ENODEV;
+	}
+
+	if (!config->is_real_id(pdata->id))
+		id = config->pc_id_to_real_id(pdata->id);
+	vreg = &config->vregs[id];
+
+	if (config->is_real_id(pdata->id))
+		rdesc = &vreg->rdesc;
+	else
+		rdesc = &vreg->rdesc_pc;
+
+	if (vreg->type < 0 || vreg->type > RPM_REGULATOR_TYPE_MAX) {
+		pr_err("%s: invalid regulator type: %d\n",
+			vreg->rdesc.name, vreg->type);
+		return -EINVAL;
+	}
+
+	mutex_lock(&vreg->pc_lock);
+
+	if (vreg->set_points)
+		rdesc->n_voltages = vreg->set_points->n_voltages;
+	else
+		rdesc->n_voltages = 0;
+
+	rdesc->id    = pdata->id;
+	rdesc->owner = THIS_MODULE;
+	rdesc->type  = REGULATOR_VOLTAGE;
+
+	if (config->is_real_id(pdata->id)) {
+		/*
+		 * Real regulator; do not modify pin control and pin function
+		 * values.
+		 */
+		rdesc->ops = vreg_ops[vreg->type];
+		pin_ctrl = vreg->pdata.pin_ctrl;
+		pin_fn = vreg->pdata.pin_fn;
+		memcpy(&(vreg->pdata), pdata,
+			sizeof(struct rpm_regulator_init_data));
+		vreg->pdata.pin_ctrl = pin_ctrl;
+		vreg->pdata.pin_fn = pin_fn;
+
+		vreg->save_uV = vreg->pdata.default_uV;
+		if (vreg->pdata.peak_uA >= vreg->hpm_min_load)
+			vreg->mode = config->mode_hpm;
+		else
+			vreg->mode = config->mode_lpm;
+
+		/* Initialize the RPM request. */
+		SET_PART(vreg, ip,
+		 MICRO_TO_MILLI(saturate_peak_load(vreg, vreg->pdata.peak_uA)));
+		SET_PART(vreg, fm, vreg->pdata.force_mode);
+		SET_PART(vreg, pm, vreg->pdata.power_mode);
+		SET_PART(vreg, pd, vreg->pdata.pull_down_enable);
+		SET_PART(vreg, ia,
+		   MICRO_TO_MILLI(saturate_avg_load(vreg, vreg->pdata.avg_uA)));
+		SET_PART(vreg, freq, vreg->pdata.freq);
+		SET_PART(vreg, freq_clk_src, 0);
+		SET_PART(vreg, comp_mode, 0);
+		SET_PART(vreg, hpm, 0);
+		if (!vreg->is_enabled_pc) {
+			SET_PART(vreg, pf, config->pin_func_none);
+			SET_PART(vreg, pc, RPM_VREG_PIN_CTRL_NONE);
+		}
+	} else {
+		if ((pdata->pin_ctrl & RPM_VREG_PIN_CTRL_ALL)
+		      == RPM_VREG_PIN_CTRL_NONE
+		    && pdata->pin_fn != config->pin_func_sleep_b) {
+			pr_err("%s: no pin control input specified\n",
+				vreg->rdesc.name);
+			mutex_unlock(&vreg->pc_lock);
+			return -EINVAL;
+		}
+		rdesc->ops = &pin_control_ops;
+		vreg->pdata.pin_ctrl = pdata->pin_ctrl;
+		vreg->pdata.pin_fn = pdata->pin_fn;
+
+		/* Initialize the RPM request. */
+		pin_fn = config->pin_func_none;
+		/* Allow pf=sleep_b to be specified by platform data. */
+		if (vreg->pdata.pin_fn == config->pin_func_sleep_b)
+			pin_fn = config->pin_func_sleep_b;
+		SET_PART(vreg, pf, pin_fn);
+		SET_PART(vreg, pc, RPM_VREG_PIN_CTRL_NONE);
+	}
+
+	mutex_unlock(&vreg->pc_lock);
+
+	if (rc)
+		goto bail;
+
+	rdev = regulator_register(rdesc, dev, &(pdata->init_data), vreg, NULL);
+	if (IS_ERR(rdev)) {
+		rc = PTR_ERR(rdev);
+		pr_err("regulator_register failed: %s, rc=%d\n",
+			vreg->rdesc.name, rc);
+		return rc;
+	} else {
+		if (config->is_real_id(pdata->id))
+			vreg->rdev = rdev;
+		else
+			vreg->rdev_pc = rdev;
+	}
+
+bail:
+	if (rc)
+		pr_err("error for %s, rc=%d\n", vreg->rdesc.name, rc);
+
+	return rc;
+}
+
+static void rpm_vreg_set_point_init(void)
+{
+	struct vreg_set_points **set_points;
+	int i, j, temp;
+
+	set_points = config->set_points;
+
+	/* Calculate the number of set points available for each regulator. */
+	for (i = 0; i < config->set_points_len; i++) {
+		temp = 0;
+		for (j = 0; j < set_points[i]->count; j++) {
+			set_points[i]->range[j].n_voltages
+				= (set_points[i]->range[j].max_uV
+					- set_points[i]->range[j].min_uV)
+				   / set_points[i]->range[j].step_uV + 1;
+			temp += set_points[i]->range[j].n_voltages;
+		}
+		set_points[i]->n_voltages = temp;
+	}
+}
+
+static int __devinit rpm_vreg_probe(struct platform_device *pdev)
+{
+	struct rpm_regulator_platform_data *platform_data;
+	static struct rpm_regulator_consumer_mapping *prev_consumer_map;
+	static int prev_consumer_map_len;
+	int rc = 0;
+	int i, id;
+
+	platform_data = pdev->dev.platform_data;
+	if (!platform_data) {
+		pr_err("rpm-regulator requires platform data\n");
+		return -EINVAL;
+	}
+
+	if (rpm_version >= 0 && rpm_version <= RPM_VREG_VERSION_MAX
+	    && platform_data->version != rpm_version) {
+		pr_err("rpm version %d does not match previous version %d\n",
+			platform_data->version, rpm_version);
+		return -EINVAL;
+	}
+
+	if (platform_data->version < 0
+		|| platform_data->version > RPM_VREG_VERSION_MAX) {
+		pr_err("rpm version %d is invalid\n", platform_data->version);
+		return -EINVAL;
+	}
+
+	if (rpm_version < 0 || rpm_version > RPM_VREG_VERSION_MAX) {
+		rpm_version = platform_data->version;
+		config = get_config[platform_data->version]();
+		vreg_id_vdd_mem = platform_data->vreg_id_vdd_mem;
+		vreg_id_vdd_dig = platform_data->vreg_id_vdd_dig;
+		if (!config) {
+			pr_err("rpm version %d is not available\n",
+				platform_data->version);
+			return -ENODEV;
+		}
+		if (config->use_legacy_optimum_mode)
+			for (i = 0; i < ARRAY_SIZE(vreg_ops); i++)
+				vreg_ops[i]->get_optimum_mode
+					= vreg_legacy_get_optimum_mode;
+		rpm_vreg_set_point_init();
+		/* First time probed; initialize pin control mutexes. */
+		for (i = 0; i < config->vregs_len; i++)
+			mutex_init(&config->vregs[i].pc_lock);
+	}
+
+	/* Copy the list of private API consumers. */
+	if (platform_data->consumer_map_len > 0) {
+		if (consumer_map_len == 0) {
+			consumer_map_len = platform_data->consumer_map_len;
+			consumer_map = kmemdup(platform_data->consumer_map,
+				sizeof(struct rpm_regulator_consumer_mapping)
+				* consumer_map_len, GFP_KERNEL);
+			if (consumer_map == NULL) {
+				pr_err("memory allocation failed\n");
+				consumer_map_len = 0;
+				return -ENOMEM;
+			}
+		} else {
+			/* Concatenate new map with the existing one. */
+			prev_consumer_map = consumer_map;
+			prev_consumer_map_len = consumer_map_len;
+			consumer_map_len += platform_data->consumer_map_len;
+			consumer_map = kmalloc(
+				sizeof(struct rpm_regulator_consumer_mapping)
+				* consumer_map_len, GFP_KERNEL);
+			if (consumer_map == NULL) {
+				pr_err("memory allocation failed\n");
+				consumer_map_len = 0;
+				return -ENOMEM;
+			}
+			memcpy(consumer_map, prev_consumer_map,
+				sizeof(struct rpm_regulator_consumer_mapping)
+				* prev_consumer_map_len);
+			memcpy(&consumer_map[prev_consumer_map_len],
+				platform_data->consumer_map,
+				sizeof(struct rpm_regulator_consumer_mapping)
+				* platform_data->consumer_map_len);
+		}
+
+	}
+
+	/* Initialize all of the regulators listed in the platform data. */
+	for (i = 0; i < platform_data->num_regulators; i++) {
+		rc = rpm_vreg_init_regulator(&platform_data->init_data[i],
+			&pdev->dev);
+		if (rc) {
+			pr_err("rpm_vreg_init_regulator failed, rc=%d\n", rc);
+			goto remove_regulators;
+		}
+	}
+
+	platform_set_drvdata(pdev, platform_data);
+
+	return rc;
+
+remove_regulators:
+	/* Unregister all regulators added before the erroring one. */
+	for (; i >= 0; i--) {
+		id = platform_data->init_data[i].id;
+		if (config->is_real_id(id)) {
+			regulator_unregister(config->vregs[id].rdev);
+			config->vregs[id].rdev = NULL;
+		} else {
+			regulator_unregister(config->vregs[
+				config->pc_id_to_real_id(id)].rdev_pc);
+			config->vregs[id].rdev_pc = NULL;
+		}
+	}
+
+	return rc;
+}
+
+static int __devexit rpm_vreg_remove(struct platform_device *pdev)
+{
+	struct rpm_regulator_platform_data *platform_data;
+	int i, id;
+
+	platform_data = platform_get_drvdata(pdev);
+	platform_set_drvdata(pdev, NULL);
+
+	if (platform_data) {
+		for (i = 0; i < platform_data->num_regulators; i++) {
+			id = platform_data->init_data[i].id;
+			if (config->is_real_id(id)) {
+				regulator_unregister(config->vregs[id].rdev);
+				config->vregs[id].rdev = NULL;
+			} else {
+				regulator_unregister(config->vregs[
+					config->pc_id_to_real_id(id)].rdev_pc);
+				config->vregs[id].rdev_pc = NULL;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static struct platform_driver rpm_vreg_driver = {
+	.probe = rpm_vreg_probe,
+	.remove = __devexit_p(rpm_vreg_remove),
+	.driver = {
+		.name = RPM_REGULATOR_DEV_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init rpm_vreg_init(void)
+{
+	return platform_driver_register(&rpm_vreg_driver);
+}
+
+static void __exit rpm_vreg_exit(void)
+{
+	int i;
+
+	platform_driver_unregister(&rpm_vreg_driver);
+
+	kfree(consumer_map);
+
+	for (i = 0; i < config->vregs_len; i++)
+		mutex_destroy(&config->vregs[i].pc_lock);
+}
+
+postcore_initcall(rpm_vreg_init);
+module_exit(rpm_vreg_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MSM RPM regulator driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:" RPM_REGULATOR_DEV_NAME);
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
new file mode 100644
index 0000000..75f4d92
--- /dev/null
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -0,0 +1,826 @@
+/* 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/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/bug.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/notifier.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <mach/socinfo.h>
+#include <mach/msm_smd.h>
+#include <mach/rpm-smd.h>
+#include "rpm-notifier.h"
+
+struct msm_rpm_driver_data {
+	const char *ch_name;
+	uint32_t ch_type;
+	smd_channel_t *ch_info;
+	struct work_struct work;
+	spinlock_t smd_lock_write;
+	spinlock_t smd_lock_read;
+	struct completion smd_open;
+};
+
+#define DEFAULT_BUFFER_SIZE 256
+#define GFP_FLAG(noirq) (noirq ? GFP_ATOMIC : GFP_KERNEL)
+#define INV_HDR "resource does not exist"
+#define ERR "err\0"
+#define MAX_ERR_BUFFER_SIZE 60
+
+static struct atomic_notifier_head msm_rpm_sleep_notifier;
+static bool standalone;
+
+int msm_rpm_register_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&msm_rpm_sleep_notifier, nb);
+}
+
+int msm_rpm_unregister_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&msm_rpm_sleep_notifier, nb);
+}
+
+static struct workqueue_struct *msm_rpm_smd_wq;
+
+enum {
+	MSM_RPM_MSG_REQUEST_TYPE = 0,
+	MSM_RPM_MSG_TYPE_NR,
+};
+
+static const uint32_t msm_rpm_request_service[MSM_RPM_MSG_TYPE_NR] = {
+	0x716572, /* 'req\0' */
+};
+
+/*the order of fields matter and reflect the order expected by the RPM*/
+struct rpm_request_header {
+	uint32_t service_type;
+	uint32_t request_len;
+};
+
+struct rpm_message_header {
+	uint32_t msg_id;
+	enum msm_rpm_set set;
+	uint32_t resource_type;
+	uint32_t resource_id;
+	uint32_t data_len;
+};
+
+struct msm_rpm_kvp_data {
+	uint32_t key;
+	uint32_t nbytes; /* number of bytes */
+	uint8_t *value;
+	bool valid;
+};
+
+static atomic_t msm_rpm_msg_id = ATOMIC_INIT(0);
+
+static struct msm_rpm_driver_data msm_rpm_data;
+
+struct msm_rpm_request {
+	struct rpm_request_header req_hdr;
+	struct rpm_message_header msg_hdr;
+	struct msm_rpm_kvp_data *kvp;
+	uint32_t num_elements;
+	uint32_t write_idx;
+	uint8_t *buf;
+	uint32_t numbytes;
+};
+
+/*
+ * Data related to message acknowledgement
+ */
+
+LIST_HEAD(msm_rpm_wait_list);
+
+struct msm_rpm_wait_data {
+	struct list_head list;
+	uint32_t msg_id;
+	bool ack_recd;
+	int errno;
+	struct completion ack;
+};
+DEFINE_SPINLOCK(msm_rpm_list_lock);
+
+struct msm_rpm_ack_msg {
+	uint32_t req;
+	uint32_t req_len;
+	uint32_t rsc_id;
+	uint32_t msg_len;
+	uint32_t id_ack;
+};
+
+static int irq_process;
+
+LIST_HEAD(msm_rpm_ack_list);
+
+static void msm_rpm_notify_sleep_chain(struct rpm_message_header *hdr,
+		struct msm_rpm_kvp_data *kvp)
+{
+	struct msm_rpm_notifier_data notif;
+
+	notif.rsc_type = hdr->resource_type;
+	notif.rsc_id = hdr->resource_id;
+	notif.key = kvp->key;
+	notif.size = kvp->nbytes;
+	notif.value = kvp->value;
+	atomic_notifier_call_chain(&msm_rpm_sleep_notifier, 0, &notif);
+}
+
+static int msm_rpm_add_kvp_data_common(struct msm_rpm_request *handle,
+		uint32_t key, const uint8_t *data, int size, bool noirq)
+{
+	int i;
+	int data_size, msg_size;
+
+	if (!handle)
+		return -EINVAL;
+
+	data_size = ALIGN(size, SZ_4);
+	msg_size = data_size + sizeof(struct rpm_request_header);
+
+	for (i = 0; i < handle->write_idx; i++) {
+		if (handle->kvp[i].key != key)
+			continue;
+		if (handle->kvp[i].nbytes != data_size) {
+			kfree(handle->kvp[i].value);
+			handle->kvp[i].value = NULL;
+		} else {
+			if (!memcmp(handle->kvp[i].value, data, data_size))
+				return 0;
+		}
+		break;
+	}
+
+	if (i >= handle->num_elements)
+		return -ENOMEM;
+
+	if (i == handle->write_idx)
+		handle->write_idx++;
+
+	if (!handle->kvp[i].value) {
+		handle->kvp[i].value = kzalloc(data_size, GFP_FLAG(noirq));
+
+		if (!handle->kvp[i].value)
+			return -ENOMEM;
+	} else {
+		/* We enter the else case, if a key already exists but the
+		 * data doesn't match. In which case, we should zero the data
+		 * out.
+		 */
+		memset(handle->kvp[i].value, 0, data_size);
+	}
+
+	if (!handle->kvp[i].valid)
+		handle->msg_hdr.data_len += msg_size;
+	else
+		handle->msg_hdr.data_len += (data_size - handle->kvp[i].nbytes);
+
+	handle->kvp[i].nbytes = data_size;
+	handle->kvp[i].key = key;
+	memcpy(handle->kvp[i].value, data, size);
+	handle->kvp[i].valid = true;
+
+	if (handle->msg_hdr.set == MSM_RPM_CTX_SLEEP_SET)
+		msm_rpm_notify_sleep_chain(&handle->msg_hdr, &handle->kvp[i]);
+
+	return 0;
+
+}
+
+static struct msm_rpm_request *msm_rpm_create_request_common(
+		enum msm_rpm_set set, uint32_t rsc_type, uint32_t rsc_id,
+		int num_elements, bool noirq)
+{
+	struct msm_rpm_request *cdata;
+
+	cdata = kzalloc(sizeof(struct msm_rpm_request),
+			GFP_FLAG(noirq));
+
+	if (!cdata) {
+		printk(KERN_INFO"%s():Cannot allocate memory for client data\n",
+				__func__);
+		goto cdata_alloc_fail;
+	}
+
+	cdata->msg_hdr.set = set;
+	cdata->msg_hdr.resource_type = rsc_type;
+	cdata->msg_hdr.resource_id = rsc_id;
+	cdata->msg_hdr.data_len = 0;
+
+	cdata->num_elements = num_elements;
+	cdata->write_idx = 0;
+
+	cdata->kvp = kzalloc(sizeof(struct msm_rpm_kvp_data) * num_elements,
+			GFP_FLAG(noirq));
+
+	if (!cdata->kvp) {
+		pr_warn("%s(): Cannot allocate memory for key value data\n",
+				__func__);
+		goto kvp_alloc_fail;
+	}
+
+	cdata->buf = kzalloc(DEFAULT_BUFFER_SIZE, GFP_FLAG(noirq));
+
+	if (!cdata->buf)
+		goto buf_alloc_fail;
+
+	cdata->numbytes = DEFAULT_BUFFER_SIZE;
+	return cdata;
+
+buf_alloc_fail:
+	kfree(cdata->kvp);
+kvp_alloc_fail:
+	kfree(cdata);
+cdata_alloc_fail:
+	return NULL;
+
+}
+
+void msm_rpm_free_request(struct msm_rpm_request *handle)
+{
+	int i;
+
+	if (!handle)
+		return;
+	for (i = 0; i < handle->write_idx; i++)
+		kfree(handle->kvp[i].value);
+	kfree(handle->kvp);
+	kfree(handle);
+}
+EXPORT_SYMBOL(msm_rpm_free_request);
+
+struct msm_rpm_request *msm_rpm_create_request(
+		enum msm_rpm_set set, uint32_t rsc_type,
+		uint32_t rsc_id, int num_elements)
+{
+	return msm_rpm_create_request_common(set, rsc_type, rsc_id,
+			num_elements, false);
+}
+EXPORT_SYMBOL(msm_rpm_create_request);
+
+struct msm_rpm_request *msm_rpm_create_request_noirq(
+		enum msm_rpm_set set, uint32_t rsc_type,
+		uint32_t rsc_id, int num_elements)
+{
+	return msm_rpm_create_request_common(set, rsc_type, rsc_id,
+			num_elements, true);
+}
+EXPORT_SYMBOL(msm_rpm_create_request_noirq);
+
+int msm_rpm_add_kvp_data(struct msm_rpm_request *handle,
+		uint32_t key, const uint8_t *data, int size)
+{
+	return msm_rpm_add_kvp_data_common(handle, key, data, size, false);
+
+}
+EXPORT_SYMBOL(msm_rpm_add_kvp_data);
+
+int msm_rpm_add_kvp_data_noirq(struct msm_rpm_request *handle,
+		uint32_t key, const uint8_t *data, int size)
+{
+	return msm_rpm_add_kvp_data_common(handle, key, data, size, true);
+}
+EXPORT_SYMBOL(msm_rpm_add_kvp_data_noirq);
+
+/* Runs in interrupt context */
+static void msm_rpm_notify(void *data, unsigned event)
+{
+	struct msm_rpm_driver_data *pdata = (struct msm_rpm_driver_data *)data;
+	BUG_ON(!pdata);
+
+	if (!(pdata->ch_info))
+		return;
+
+	switch (event) {
+	case SMD_EVENT_DATA:
+		queue_work(msm_rpm_smd_wq, &pdata->work);
+		break;
+	case SMD_EVENT_OPEN:
+		complete(&pdata->smd_open);
+		break;
+	case SMD_EVENT_CLOSE:
+	case SMD_EVENT_STATUS:
+	case SMD_EVENT_REOPEN_READY:
+		break;
+	default:
+		pr_info("Unknown SMD event\n");
+
+	}
+}
+
+static struct msm_rpm_wait_data *msm_rpm_get_entry_from_msg_id(uint32_t msg_id)
+{
+	struct list_head *ptr;
+	struct msm_rpm_wait_data *elem;
+	unsigned long flags;
+
+	spin_lock_irqsave(&msm_rpm_list_lock, flags);
+
+	list_for_each(ptr, &msm_rpm_wait_list) {
+		elem = list_entry(ptr, struct msm_rpm_wait_data, list);
+		if (elem && (elem->msg_id == msg_id))
+			break;
+		elem = NULL;
+	}
+	spin_unlock_irqrestore(&msm_rpm_list_lock, flags);
+	return elem;
+}
+
+static int msm_rpm_get_next_msg_id(void)
+{
+	int id;
+
+	do {
+		id = atomic_inc_return(&msm_rpm_msg_id);
+	} while ((id == 0) || msm_rpm_get_entry_from_msg_id(id));
+
+	return id;
+}
+
+static int msm_rpm_add_wait_list(uint32_t msg_id)
+{
+	unsigned long flags;
+	struct msm_rpm_wait_data *data =
+		kzalloc(sizeof(struct msm_rpm_wait_data), GFP_ATOMIC);
+
+	if (!data)
+		return -ENOMEM;
+
+	init_completion(&data->ack);
+	data->ack_recd = false;
+	data->msg_id = msg_id;
+	spin_lock_irqsave(&msm_rpm_list_lock, flags);
+	list_add(&data->list, &msm_rpm_wait_list);
+	spin_unlock_irqrestore(&msm_rpm_list_lock, flags);
+
+	return 0;
+}
+
+static void msm_rpm_free_list_entry(struct msm_rpm_wait_data *elem)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&msm_rpm_list_lock, flags);
+	list_del(&elem->list);
+	spin_unlock_irqrestore(&msm_rpm_list_lock, flags);
+	kfree(elem);
+}
+
+static void msm_rpm_process_ack(uint32_t msg_id, int errno)
+{
+	struct list_head *ptr;
+	struct msm_rpm_wait_data *elem;
+	unsigned long flags;
+
+	spin_lock_irqsave(&msm_rpm_list_lock, flags);
+
+	list_for_each(ptr, &msm_rpm_wait_list) {
+		elem = list_entry(ptr, struct msm_rpm_wait_data, list);
+		if (elem && (elem->msg_id == msg_id)) {
+			elem->errno = errno;
+			elem->ack_recd = true;
+			complete(&elem->ack);
+			break;
+		}
+		elem = NULL;
+	}
+	WARN_ON(!elem);
+
+	spin_unlock_irqrestore(&msm_rpm_list_lock, flags);
+}
+
+struct msm_rpm_kvp_packet {
+	uint32_t id;
+	uint32_t len;
+	uint32_t val;
+};
+
+static inline uint32_t msm_rpm_get_msg_id_from_ack(uint8_t *buf)
+{
+	return ((struct msm_rpm_ack_msg *)buf)->id_ack;
+}
+
+static inline int msm_rpm_get_error_from_ack(uint8_t *buf)
+{
+	uint8_t *tmp;
+	uint32_t req_len = ((struct msm_rpm_ack_msg *)buf)->req_len;
+
+	int rc = -ENODEV;
+
+	req_len -= sizeof(struct msm_rpm_ack_msg);
+	req_len += 2 * sizeof(uint32_t);
+	if (!req_len)
+		return 0;
+
+	tmp = buf + sizeof(struct msm_rpm_ack_msg);
+
+	BUG_ON(memcmp(tmp, ERR, sizeof(uint32_t)));
+
+	tmp += 2 * sizeof(uint32_t);
+
+	if (!(memcmp(tmp, INV_HDR, min(req_len, sizeof(INV_HDR))-1)))
+		rc = -EINVAL;
+
+	return rc;
+}
+
+static void msm_rpm_read_smd_data(char *buf)
+{
+	int pkt_sz;
+	int bytes_read = 0;
+
+	pkt_sz = smd_cur_packet_size(msm_rpm_data.ch_info);
+
+	BUG_ON(pkt_sz > MAX_ERR_BUFFER_SIZE);
+
+	if (pkt_sz != smd_read_avail(msm_rpm_data.ch_info))
+		return;
+
+	BUG_ON(pkt_sz == 0);
+
+	do {
+		int len;
+
+		len = smd_read(msm_rpm_data.ch_info, buf + bytes_read, pkt_sz);
+		pkt_sz -= len;
+		bytes_read += len;
+
+	} while (pkt_sz > 0);
+
+	BUG_ON(pkt_sz < 0);
+}
+
+static void msm_rpm_smd_work(struct work_struct *work)
+{
+	uint32_t msg_id;
+	int errno;
+	char buf[MAX_ERR_BUFFER_SIZE] = {0};
+	unsigned long flags;
+
+	while (smd_is_pkt_avail(msm_rpm_data.ch_info) && !irq_process) {
+		spin_lock_irqsave(&msm_rpm_data.smd_lock_read, flags);
+		msm_rpm_read_smd_data(buf);
+		spin_unlock_irqrestore(&msm_rpm_data.smd_lock_read, flags);
+		msg_id = msm_rpm_get_msg_id_from_ack(buf);
+		errno = msm_rpm_get_error_from_ack(buf);
+		msm_rpm_process_ack(msg_id, errno);
+	}
+}
+
+static int msm_rpm_send_data(struct msm_rpm_request *cdata,
+		int msg_type, bool noirq)
+{
+	uint8_t *tmpbuff;
+	int i, ret, msg_size;
+	unsigned long flags;
+
+	int req_hdr_sz, msg_hdr_sz;
+
+	if (!cdata->msg_hdr.data_len)
+		return 0;
+	req_hdr_sz = sizeof(cdata->req_hdr);
+	msg_hdr_sz = sizeof(cdata->msg_hdr);
+
+	cdata->req_hdr.service_type = msm_rpm_request_service[msg_type];
+
+	cdata->msg_hdr.msg_id = msm_rpm_get_next_msg_id();
+
+	cdata->req_hdr.request_len = cdata->msg_hdr.data_len + msg_hdr_sz;
+	msg_size = cdata->req_hdr.request_len + req_hdr_sz;
+
+	/* populate data_len */
+	if (msg_size > cdata->numbytes) {
+		kfree(cdata->buf);
+		cdata->numbytes = msg_size;
+		cdata->buf = kzalloc(msg_size, GFP_FLAG(noirq));
+	}
+
+	if (!cdata->buf)
+		return 0;
+
+	tmpbuff = cdata->buf;
+
+	memcpy(tmpbuff, &cdata->req_hdr, req_hdr_sz + msg_hdr_sz);
+
+	tmpbuff += req_hdr_sz + msg_hdr_sz;
+
+	for (i = 0; (i < cdata->write_idx); i++) {
+		/* Sanity check */
+		BUG_ON((tmpbuff - cdata->buf) > cdata->numbytes);
+
+		if (!cdata->kvp[i].valid)
+			continue;
+
+		memcpy(tmpbuff, &cdata->kvp[i].key, sizeof(uint32_t));
+		tmpbuff += sizeof(uint32_t);
+
+		memcpy(tmpbuff, &cdata->kvp[i].nbytes, sizeof(uint32_t));
+		tmpbuff += sizeof(uint32_t);
+
+		memcpy(tmpbuff, cdata->kvp[i].value, cdata->kvp[i].nbytes);
+		tmpbuff += cdata->kvp[i].nbytes;
+	}
+
+	if (standalone) {
+		for (i = 0; (i < cdata->write_idx); i++)
+			cdata->kvp[i].valid = false;
+
+		cdata->msg_hdr.data_len = 0;
+		ret = cdata->msg_hdr.msg_id;
+		return ret;
+	}
+
+	msm_rpm_add_wait_list(cdata->msg_hdr.msg_id);
+
+	spin_lock_irqsave(&msm_rpm_data.smd_lock_write, flags);
+
+	ret = smd_write_avail(msm_rpm_data.ch_info);
+
+	if (ret < 0) {
+		pr_warn("%s(): SMD not initialized\n", __func__);
+		spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write, flags);
+		return 0;
+	}
+
+	while ((ret < msg_size)) {
+		if (!noirq) {
+			spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write,
+					flags);
+			cpu_relax();
+			spin_lock_irqsave(&msm_rpm_data.smd_lock_write, flags);
+		} else
+			udelay(5);
+		ret = smd_write_avail(msm_rpm_data.ch_info);
+	}
+
+	ret = smd_write(msm_rpm_data.ch_info, &cdata->buf[0], msg_size);
+	spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write, flags);
+
+	if (ret == msg_size) {
+		for (i = 0; (i < cdata->write_idx); i++)
+			cdata->kvp[i].valid = false;
+		cdata->msg_hdr.data_len = 0;
+		ret = cdata->msg_hdr.msg_id;
+	} else if (ret < msg_size) {
+		struct msm_rpm_wait_data *rc;
+		ret = 0;
+		pr_info("Failed to write data msg_size:%d ret:%d\n",
+				msg_size, ret);
+		rc = msm_rpm_get_entry_from_msg_id(cdata->msg_hdr.msg_id);
+		if (rc)
+			msm_rpm_free_list_entry(rc);
+	}
+	return ret;
+}
+
+int msm_rpm_send_request(struct msm_rpm_request *handle)
+{
+	return msm_rpm_send_data(handle, MSM_RPM_MSG_REQUEST_TYPE, false);
+}
+EXPORT_SYMBOL(msm_rpm_send_request);
+
+int msm_rpm_send_request_noirq(struct msm_rpm_request *handle)
+{
+	return msm_rpm_send_data(handle, MSM_RPM_MSG_REQUEST_TYPE, true);
+}
+EXPORT_SYMBOL(msm_rpm_send_request_noirq);
+
+int msm_rpm_wait_for_ack(uint32_t msg_id)
+{
+	struct msm_rpm_wait_data *elem;
+	int rc = 0;
+
+	if (!msg_id)
+		return -EINVAL;
+
+	if (standalone)
+		return 0;
+
+	elem = msm_rpm_get_entry_from_msg_id(msg_id);
+	if (!elem)
+		return 0;
+
+	rc = wait_for_completion_timeout(&elem->ack, msecs_to_jiffies(1));
+	if (!rc) {
+		pr_warn("%s(): Timed out after 1 ms\n", __func__);
+		rc = -ETIMEDOUT;
+	} else {
+		rc = elem->errno;
+		msm_rpm_free_list_entry(elem);
+	}
+	return rc;
+}
+EXPORT_SYMBOL(msm_rpm_wait_for_ack);
+
+int msm_rpm_wait_for_ack_noirq(uint32_t msg_id)
+{
+	struct msm_rpm_wait_data *elem;
+	unsigned long flags;
+	int rc = 0;
+	uint32_t id = 0;
+	int count = 0;
+
+	if (!msg_id)
+		return -EINVAL;
+
+	if (standalone)
+		return 0;
+
+	spin_lock_irqsave(&msm_rpm_data.smd_lock_read, flags);
+	irq_process = true;
+
+	elem = msm_rpm_get_entry_from_msg_id(msg_id);
+
+	if (!elem)
+		/* Should this be a bug
+		 * Is it ok for another thread to read the msg?
+		 */
+		goto wait_ack_cleanup;
+
+	while ((id != msg_id) && (count++ < 10)) {
+		if (smd_is_pkt_avail(msm_rpm_data.ch_info)) {
+			int errno;
+			char buf[MAX_ERR_BUFFER_SIZE] = {};
+
+			msm_rpm_read_smd_data(buf);
+			id = msm_rpm_get_msg_id_from_ack(buf);
+			errno = msm_rpm_get_error_from_ack(buf);
+			msm_rpm_process_ack(id, errno);
+		} else
+			udelay(100);
+	}
+
+	if (count == 10) {
+		rc = -ETIMEDOUT;
+		pr_warn("%s(): Timed out after 1ms\n", __func__);
+	} else {
+		rc = elem->errno;
+		msm_rpm_free_list_entry(elem);
+	}
+wait_ack_cleanup:
+	irq_process = false;
+	spin_unlock_irqrestore(&msm_rpm_data.smd_lock_read, flags);
+	return rc;
+}
+EXPORT_SYMBOL(msm_rpm_wait_for_ack_noirq);
+
+int msm_rpm_send_message(enum msm_rpm_set set, uint32_t rsc_type,
+		uint32_t rsc_id, struct msm_rpm_kvp *kvp, int nelems)
+{
+	int i, rc;
+	struct msm_rpm_request *req =
+		msm_rpm_create_request(set, rsc_type, rsc_id, nelems);
+	if (!req)
+		return -ENOMEM;
+
+	for (i = 0; i < nelems; i++) {
+		rc = msm_rpm_add_kvp_data(req, kvp[i].key,
+				kvp[i].data, kvp[i].length);
+		if (rc)
+			goto bail;
+	}
+
+	rc = msm_rpm_wait_for_ack(msm_rpm_send_request(req));
+bail:
+	msm_rpm_free_request(req);
+	return rc;
+}
+EXPORT_SYMBOL(msm_rpm_send_message);
+
+int msm_rpm_send_message_noirq(enum msm_rpm_set set, uint32_t rsc_type,
+		uint32_t rsc_id, struct msm_rpm_kvp *kvp, int nelems)
+{
+	int i, rc;
+	struct msm_rpm_request *req =
+		msm_rpm_create_request_noirq(set, rsc_type, rsc_id, nelems);
+	if (!req)
+		return -ENOMEM;
+
+	for (i = 0; i < nelems; i++) {
+		rc = msm_rpm_add_kvp_data_noirq(req, kvp[i].key,
+					kvp[i].data, kvp[i].length);
+		if (rc)
+			goto bail;
+	}
+
+	rc = msm_rpm_wait_for_ack_noirq(msm_rpm_send_request_noirq(req));
+bail:
+	msm_rpm_free_request(req);
+	return rc;
+}
+EXPORT_SYMBOL(msm_rpm_send_message_noirq);
+static bool msm_rpm_set_standalone(void)
+{
+	if (machine_is_copper()) {
+		pr_warn("%s(): Running in standalone mode, requests "
+				"will not be sent to RPM\n", __func__);
+		standalone = true;
+	}
+	return standalone;
+}
+
+static int __devinit msm_rpm_dev_probe(struct platform_device *pdev)
+{
+	char *key = NULL;
+	int ret;
+
+	key = "rpm-channel-name";
+	ret = of_property_read_string(pdev->dev.of_node, key,
+					&msm_rpm_data.ch_name);
+	if (ret)
+		goto fail;
+
+	key = "rpm-channel-type";
+	ret = of_property_read_u32(pdev->dev.of_node, key,
+					&msm_rpm_data.ch_type);
+	if (ret)
+		goto fail;
+
+	init_completion(&msm_rpm_data.smd_open);
+	spin_lock_init(&msm_rpm_data.smd_lock_write);
+	spin_lock_init(&msm_rpm_data.smd_lock_read);
+	INIT_WORK(&msm_rpm_data.work, msm_rpm_smd_work);
+
+	if (smd_named_open_on_edge(msm_rpm_data.ch_name, msm_rpm_data.ch_type,
+				&msm_rpm_data.ch_info, &msm_rpm_data,
+				msm_rpm_notify)) {
+		pr_info("Cannot open RPM channel %s %d\n", msm_rpm_data.ch_name,
+				msm_rpm_data.ch_type);
+
+		msm_rpm_set_standalone();
+		BUG_ON(!standalone);
+		complete(&msm_rpm_data.smd_open);
+	}
+
+	ret = wait_for_completion_timeout(&msm_rpm_data.smd_open,
+			msecs_to_jiffies(5));
+
+	BUG_ON(!ret);
+
+	smd_disable_read_intr(msm_rpm_data.ch_info);
+
+	if (!standalone) {
+		msm_rpm_smd_wq = create_singlethread_workqueue("rpm-smd");
+		if (!msm_rpm_smd_wq)
+			return -EINVAL;
+	}
+
+	of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+	return 0;
+fail:
+	pr_err("%s(): Failed to read node: %s, key=%s\n", __func__,
+			pdev->dev.of_node->full_name, key);
+	return -EINVAL;
+}
+
+static struct of_device_id msm_rpm_match_table[] =  {
+	{.compatible = "qcom,rpm-smd"},
+	{},
+};
+
+static struct platform_driver msm_rpm_device_driver = {
+	.probe = msm_rpm_dev_probe,
+	.driver = {
+		.name = "rpm-smd",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_rpm_match_table,
+	},
+};
+
+int __init msm_rpm_driver_init(void)
+{
+	static bool registered;
+
+	if (registered)
+		return 0;
+	registered = true;
+
+	return platform_driver_register(&msm_rpm_device_driver);
+}
+EXPORT_SYMBOL(msm_rpm_driver_init);
+late_initcall(msm_rpm_driver_init);
diff --git a/arch/arm/mach-msm/rpm.c b/arch/arm/mach-msm/rpm.c
new file mode 100644
index 0000000..44e50dd
--- /dev/null
+++ b/arch/arm/mach-msm/rpm.c
@@ -0,0 +1,1023 @@
+/* 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
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/bug.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <asm/hardware/gic.h>
+#include <mach/msm_iomap.h>
+#include <mach/rpm.h>
+
+/******************************************************************************
+ * Data type and structure definitions
+ *****************************************************************************/
+
+struct msm_rpm_request {
+	struct msm_rpm_iv_pair *req;
+	int count;
+	uint32_t *ctx_mask_ack;
+	uint32_t *sel_masks_ack;
+	struct completion *done;
+};
+
+struct msm_rpm_notif_config {
+	struct msm_rpm_iv_pair iv[SEL_MASK_SIZE * 2];
+};
+
+#define configured_iv(notif_cfg) ((notif_cfg)->iv)
+#define registered_iv(notif_cfg) ((notif_cfg)->iv + msm_rpm_sel_mask_size)
+
+static uint32_t msm_rpm_sel_mask_size;
+static struct msm_rpm_platform_data msm_rpm_data;
+
+static DEFINE_MUTEX(msm_rpm_mutex);
+static DEFINE_SPINLOCK(msm_rpm_lock);
+static DEFINE_SPINLOCK(msm_rpm_irq_lock);
+
+static struct msm_rpm_request *msm_rpm_request;
+static struct msm_rpm_request msm_rpm_request_irq_mode;
+static struct msm_rpm_request msm_rpm_request_poll_mode;
+
+static LIST_HEAD(msm_rpm_notifications);
+static struct msm_rpm_notif_config msm_rpm_notif_cfgs[MSM_RPM_CTX_SET_COUNT];
+static bool msm_rpm_init_notif_done;
+/******************************************************************************
+ * Internal functions
+ *****************************************************************************/
+
+static inline unsigned int target_enum(unsigned int id)
+{
+	BUG_ON(id >= MSM_RPM_ID_LAST);
+	return msm_rpm_data.target_id[id].id;
+}
+
+static inline unsigned int target_status(unsigned int id)
+{
+	BUG_ON(id >= MSM_RPM_STATUS_ID_LAST);
+	return msm_rpm_data.target_status[id];
+}
+
+static inline unsigned int target_ctrl(unsigned int id)
+{
+	BUG_ON(id >= MSM_RPM_CTRL_LAST);
+	return msm_rpm_data.target_ctrl_id[id];
+}
+
+static inline uint32_t msm_rpm_read(unsigned int page, unsigned int reg)
+{
+	return __raw_readl(msm_rpm_data.reg_base_addrs[page] + reg * 4);
+}
+
+static inline void msm_rpm_write(
+	unsigned int page, unsigned int reg, uint32_t value)
+{
+	__raw_writel(value,
+		msm_rpm_data.reg_base_addrs[page] + reg * 4);
+}
+
+static inline void msm_rpm_read_contiguous(
+	unsigned int page, unsigned int reg, uint32_t *values, int count)
+{
+	int i;
+
+	for (i = 0; i < count; i++)
+		values[i] = msm_rpm_read(page, reg + i);
+}
+
+static inline void msm_rpm_write_contiguous(
+	unsigned int page, unsigned int reg, uint32_t *values, int count)
+{
+	int i;
+
+	for (i = 0; i < count; i++)
+		msm_rpm_write(page, reg + i, values[i]);
+}
+
+static inline void msm_rpm_write_contiguous_zeros(
+	unsigned int page, unsigned int reg, int count)
+{
+	int i;
+
+	for (i = 0; i < count; i++)
+		msm_rpm_write(page, reg + i, 0);
+}
+
+static inline uint32_t msm_rpm_map_id_to_sel(uint32_t id)
+{
+	return (id >= MSM_RPM_ID_LAST) ? msm_rpm_data.sel_last + 1 :
+		msm_rpm_data.target_id[id].sel;
+}
+
+/*
+ * Note: the function does not clear the masks before filling them.
+ *
+ * Return value:
+ *   0: success
+ *   -EINVAL: invalid id in <req> array
+ */
+static int msm_rpm_fill_sel_masks(
+	uint32_t *sel_masks, struct msm_rpm_iv_pair *req, int count)
+{
+	uint32_t sel;
+	int i;
+
+	for (i = 0; i < count; i++) {
+		sel = msm_rpm_map_id_to_sel(req[i].id);
+
+		if (sel > msm_rpm_data.sel_last) {
+			pr_err("%s(): RPM ID %d not defined for target\n",
+					__func__, req[i].id);
+			return -EINVAL;
+		}
+
+		sel_masks[msm_rpm_get_sel_mask_reg(sel)] |=
+			msm_rpm_get_sel_mask(sel);
+	}
+
+	return 0;
+}
+
+static inline void msm_rpm_send_req_interrupt(void)
+{
+	__raw_writel(msm_rpm_data.ipc_rpm_val,
+			msm_rpm_data.ipc_rpm_reg);
+}
+
+/*
+ * Note: assumes caller has acquired <msm_rpm_irq_lock>.
+ *
+ * Return value:
+ *   0: request acknowledgement
+ *   1: notification
+ *   2: spurious interrupt
+ */
+static int msm_rpm_process_ack_interrupt(void)
+{
+	uint32_t ctx_mask_ack;
+	uint32_t sel_masks_ack[SEL_MASK_SIZE] = {0};
+
+	ctx_mask_ack = msm_rpm_read(MSM_RPM_PAGE_CTRL,
+			target_ctrl(MSM_RPM_CTRL_ACK_CTX_0));
+	msm_rpm_read_contiguous(MSM_RPM_PAGE_CTRL,
+		target_ctrl(MSM_RPM_CTRL_ACK_SEL_0),
+		sel_masks_ack, msm_rpm_sel_mask_size);
+
+	if (ctx_mask_ack & msm_rpm_get_ctx_mask(MSM_RPM_CTX_NOTIFICATION)) {
+		struct msm_rpm_notification *n;
+		int i;
+
+		list_for_each_entry(n, &msm_rpm_notifications, list)
+			for (i = 0; i < msm_rpm_sel_mask_size; i++)
+				if (sel_masks_ack[i] & n->sel_masks[i]) {
+					up(&n->sem);
+					break;
+				}
+
+		msm_rpm_write_contiguous_zeros(MSM_RPM_PAGE_CTRL,
+			target_ctrl(MSM_RPM_CTRL_ACK_SEL_0),
+			msm_rpm_sel_mask_size);
+		msm_rpm_write(MSM_RPM_PAGE_CTRL,
+			target_ctrl(MSM_RPM_CTRL_ACK_CTX_0), 0);
+		/* Ensure the write is complete before return */
+		mb();
+
+		return 1;
+	}
+
+	if (msm_rpm_request) {
+		int i;
+
+		*(msm_rpm_request->ctx_mask_ack) = ctx_mask_ack;
+		memcpy(msm_rpm_request->sel_masks_ack, sel_masks_ack,
+			sizeof(sel_masks_ack));
+
+		for (i = 0; i < msm_rpm_request->count; i++)
+			msm_rpm_request->req[i].value =
+				msm_rpm_read(MSM_RPM_PAGE_ACK,
+				target_enum(msm_rpm_request->req[i].id));
+
+		msm_rpm_write_contiguous_zeros(MSM_RPM_PAGE_CTRL,
+			target_ctrl(MSM_RPM_CTRL_ACK_SEL_0),
+			msm_rpm_sel_mask_size);
+		msm_rpm_write(MSM_RPM_PAGE_CTRL,
+			target_ctrl(MSM_RPM_CTRL_ACK_CTX_0), 0);
+		/* Ensure the write is complete before return */
+		mb();
+
+		if (msm_rpm_request->done)
+			complete_all(msm_rpm_request->done);
+
+		msm_rpm_request = NULL;
+		return 0;
+	}
+
+	return 2;
+}
+
+static void msm_rpm_err_fatal(void)
+{
+	/* Tell RPM that we're handling the interrupt */
+	__raw_writel(0x1, msm_rpm_data.ipc_rpm_reg);
+	panic("RPM error fataled");
+}
+
+static irqreturn_t msm_rpm_err_interrupt(int irq, void *dev_id)
+{
+	msm_rpm_err_fatal();
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t msm_rpm_ack_interrupt(int irq, void *dev_id)
+{
+	unsigned long flags;
+	int rc;
+
+	if (dev_id != &msm_rpm_ack_interrupt)
+		return IRQ_NONE;
+
+	spin_lock_irqsave(&msm_rpm_irq_lock, flags);
+	rc = msm_rpm_process_ack_interrupt();
+	spin_unlock_irqrestore(&msm_rpm_irq_lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * Note: assumes caller has acquired <msm_rpm_irq_lock>.
+ */
+static void msm_rpm_busy_wait_for_request_completion(
+	bool allow_async_completion)
+{
+	int rc;
+
+	do {
+		while (!gic_is_spi_pending(msm_rpm_data.irq_ack) &&
+				msm_rpm_request) {
+			if (allow_async_completion)
+				spin_unlock(&msm_rpm_irq_lock);
+			if (gic_is_spi_pending(msm_rpm_data.irq_err))
+				msm_rpm_err_fatal();
+			gic_clear_spi_pending(msm_rpm_data.irq_err);
+			udelay(1);
+			if (allow_async_completion)
+				spin_lock(&msm_rpm_irq_lock);
+		}
+
+		if (!msm_rpm_request)
+			break;
+
+		rc = msm_rpm_process_ack_interrupt();
+		gic_clear_spi_pending(msm_rpm_data.irq_ack);
+	} while (rc);
+}
+
+/* Upon return, the <req> array will contain values from the ack page.
+ *
+ * Note: assumes caller has acquired <msm_rpm_mutex>.
+ *
+ * Return value:
+ *   0: success
+ *   -ENOSPC: request rejected
+ */
+static int msm_rpm_set_exclusive(int ctx,
+	uint32_t *sel_masks, struct msm_rpm_iv_pair *req, int count)
+{
+	DECLARE_COMPLETION_ONSTACK(ack);
+	unsigned long flags;
+	uint32_t ctx_mask = msm_rpm_get_ctx_mask(ctx);
+	uint32_t ctx_mask_ack = 0;
+	uint32_t sel_masks_ack[SEL_MASK_SIZE];
+	int i;
+
+	msm_rpm_request_irq_mode.req = req;
+	msm_rpm_request_irq_mode.count = count;
+	msm_rpm_request_irq_mode.ctx_mask_ack = &ctx_mask_ack;
+	msm_rpm_request_irq_mode.sel_masks_ack = sel_masks_ack;
+	msm_rpm_request_irq_mode.done = &ack;
+
+	spin_lock_irqsave(&msm_rpm_lock, flags);
+	spin_lock(&msm_rpm_irq_lock);
+
+	BUG_ON(msm_rpm_request);
+	msm_rpm_request = &msm_rpm_request_irq_mode;
+
+	for (i = 0; i < count; i++) {
+		BUG_ON(target_enum(req[i].id) >= MSM_RPM_ID_LAST);
+		msm_rpm_write(MSM_RPM_PAGE_REQ,
+				target_enum(req[i].id), req[i].value);
+	}
+
+	msm_rpm_write_contiguous(MSM_RPM_PAGE_CTRL,
+		target_ctrl(MSM_RPM_CTRL_REQ_SEL_0),
+		sel_masks, msm_rpm_sel_mask_size);
+	msm_rpm_write(MSM_RPM_PAGE_CTRL,
+		target_ctrl(MSM_RPM_CTRL_REQ_CTX_0), ctx_mask);
+
+	/* Ensure RPM data is written before sending the interrupt */
+	mb();
+	msm_rpm_send_req_interrupt();
+
+	spin_unlock(&msm_rpm_irq_lock);
+	spin_unlock_irqrestore(&msm_rpm_lock, flags);
+
+	wait_for_completion(&ack);
+
+	BUG_ON((ctx_mask_ack & ~(msm_rpm_get_ctx_mask(MSM_RPM_CTX_REJECTED)))
+		!= ctx_mask);
+	BUG_ON(memcmp(sel_masks, sel_masks_ack, sizeof(sel_masks_ack)));
+
+	return (ctx_mask_ack & msm_rpm_get_ctx_mask(MSM_RPM_CTX_REJECTED))
+		? -ENOSPC : 0;
+}
+
+/* Upon return, the <req> array will contain values from the ack page.
+ *
+ * Note: assumes caller has acquired <msm_rpm_lock>.
+ *
+ * Return value:
+ *   0: success
+ *   -ENOSPC: request rejected
+ */
+static int msm_rpm_set_exclusive_noirq(int ctx,
+	uint32_t *sel_masks, struct msm_rpm_iv_pair *req, int count)
+{
+	unsigned int irq = msm_rpm_data.irq_ack;
+	unsigned long flags;
+	uint32_t ctx_mask = msm_rpm_get_ctx_mask(ctx);
+	uint32_t ctx_mask_ack = 0;
+	uint32_t sel_masks_ack[SEL_MASK_SIZE];
+	struct irq_chip *irq_chip, *err_chip;
+	int i;
+
+	msm_rpm_request_poll_mode.req = req;
+	msm_rpm_request_poll_mode.count = count;
+	msm_rpm_request_poll_mode.ctx_mask_ack = &ctx_mask_ack;
+	msm_rpm_request_poll_mode.sel_masks_ack = sel_masks_ack;
+	msm_rpm_request_poll_mode.done = NULL;
+
+	spin_lock_irqsave(&msm_rpm_irq_lock, flags);
+	irq_chip = irq_get_chip(irq);
+	if (!irq_chip) {
+		spin_unlock_irqrestore(&msm_rpm_irq_lock, flags);
+		return -ENOSPC;
+	}
+	irq_chip->irq_mask(irq_get_irq_data(irq));
+	err_chip = irq_get_chip(msm_rpm_data.irq_err);
+	if (!err_chip) {
+		irq_chip->irq_unmask(irq_get_irq_data(irq));
+		spin_unlock_irqrestore(&msm_rpm_irq_lock, flags);
+		return -ENOSPC;
+	}
+	err_chip->irq_mask(irq_get_irq_data(msm_rpm_data.irq_err));
+
+	if (msm_rpm_request) {
+		msm_rpm_busy_wait_for_request_completion(true);
+		BUG_ON(msm_rpm_request);
+	}
+
+	msm_rpm_request = &msm_rpm_request_poll_mode;
+
+	for (i = 0; i < count; i++) {
+		BUG_ON(target_enum(req[i].id) >= MSM_RPM_ID_LAST);
+		msm_rpm_write(MSM_RPM_PAGE_REQ,
+				target_enum(req[i].id), req[i].value);
+	}
+
+	msm_rpm_write_contiguous(MSM_RPM_PAGE_CTRL,
+		target_ctrl(MSM_RPM_CTRL_REQ_SEL_0),
+		sel_masks, msm_rpm_sel_mask_size);
+	msm_rpm_write(MSM_RPM_PAGE_CTRL,
+		target_ctrl(MSM_RPM_CTRL_REQ_CTX_0), ctx_mask);
+
+	/* Ensure RPM data is written before sending the interrupt */
+	mb();
+	msm_rpm_send_req_interrupt();
+
+	msm_rpm_busy_wait_for_request_completion(false);
+	BUG_ON(msm_rpm_request);
+
+	err_chip->irq_unmask(irq_get_irq_data(msm_rpm_data.irq_err));
+	irq_chip->irq_unmask(irq_get_irq_data(irq));
+	spin_unlock_irqrestore(&msm_rpm_irq_lock, flags);
+
+	BUG_ON((ctx_mask_ack & ~(msm_rpm_get_ctx_mask(MSM_RPM_CTX_REJECTED)))
+		!= ctx_mask);
+	BUG_ON(memcmp(sel_masks, sel_masks_ack, sizeof(sel_masks_ack)));
+
+	return (ctx_mask_ack & msm_rpm_get_ctx_mask(MSM_RPM_CTX_REJECTED))
+		? -ENOSPC : 0;
+}
+
+/* Upon return, the <req> array will contain values from the ack page.
+ *
+ * Return value:
+ *   0: success
+ *   -EINVAL: invalid <ctx> or invalid id in <req> array
+ *   -ENOSPC: request rejected
+ *   -ENODEV: RPM driver not initialized
+ */
+static int msm_rpm_set_common(
+	int ctx, struct msm_rpm_iv_pair *req, int count, bool noirq)
+{
+	uint32_t sel_masks[SEL_MASK_SIZE] = {};
+	int rc;
+
+	if (ctx >= MSM_RPM_CTX_SET_COUNT) {
+		rc = -EINVAL;
+		goto set_common_exit;
+	}
+
+	rc = msm_rpm_fill_sel_masks(sel_masks, req, count);
+	if (rc)
+		goto set_common_exit;
+
+	if (noirq) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&msm_rpm_lock, flags);
+		rc = msm_rpm_set_exclusive_noirq(ctx, sel_masks, req, count);
+		spin_unlock_irqrestore(&msm_rpm_lock, flags);
+	} else {
+		mutex_lock(&msm_rpm_mutex);
+		rc = msm_rpm_set_exclusive(ctx, sel_masks, req, count);
+		mutex_unlock(&msm_rpm_mutex);
+	}
+
+set_common_exit:
+	return rc;
+}
+
+/*
+ * Return value:
+ *   0: success
+ *   -EINVAL: invalid <ctx> or invalid id in <req> array
+ *   -ENODEV: RPM driver not initialized.
+ */
+static int msm_rpm_clear_common(
+	int ctx, struct msm_rpm_iv_pair *req, int count, bool noirq)
+{
+	uint32_t sel_masks[SEL_MASK_SIZE] = {};
+	struct msm_rpm_iv_pair r[SEL_MASK_SIZE];
+	int rc;
+	int i;
+
+	if (ctx >= MSM_RPM_CTX_SET_COUNT) {
+		rc = -EINVAL;
+		goto clear_common_exit;
+	}
+
+	rc = msm_rpm_fill_sel_masks(sel_masks, req, count);
+	if (rc)
+		goto clear_common_exit;
+
+	for (i = 0; i < ARRAY_SIZE(r); i++) {
+		r[i].id = MSM_RPM_ID_INVALIDATE_0 + i;
+		r[i].value = sel_masks[i];
+	}
+
+	memset(sel_masks, 0, sizeof(sel_masks));
+	sel_masks[msm_rpm_get_sel_mask_reg(msm_rpm_data.sel_invalidate)] |=
+		msm_rpm_get_sel_mask(msm_rpm_data.sel_invalidate);
+
+	if (noirq) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&msm_rpm_lock, flags);
+		rc = msm_rpm_set_exclusive_noirq(ctx, sel_masks, r,
+			ARRAY_SIZE(r));
+		spin_unlock_irqrestore(&msm_rpm_lock, flags);
+		BUG_ON(rc);
+	} else {
+		mutex_lock(&msm_rpm_mutex);
+		rc = msm_rpm_set_exclusive(ctx, sel_masks, r, ARRAY_SIZE(r));
+		mutex_unlock(&msm_rpm_mutex);
+		BUG_ON(rc);
+	}
+
+clear_common_exit:
+	return rc;
+}
+
+/*
+ * Note: assumes caller has acquired <msm_rpm_mutex>.
+ */
+static void msm_rpm_update_notification(uint32_t ctx,
+	struct msm_rpm_notif_config *curr_cfg,
+	struct msm_rpm_notif_config *new_cfg)
+{
+	unsigned int sel_notif = msm_rpm_data.sel_notification;
+
+	if (memcmp(curr_cfg, new_cfg, sizeof(*new_cfg))) {
+		uint32_t sel_masks[SEL_MASK_SIZE] = {};
+		int rc;
+
+		sel_masks[msm_rpm_get_sel_mask_reg(sel_notif)]
+			|= msm_rpm_get_sel_mask(sel_notif);
+
+		rc = msm_rpm_set_exclusive(ctx,
+			sel_masks, new_cfg->iv, ARRAY_SIZE(new_cfg->iv));
+		BUG_ON(rc);
+
+		memcpy(curr_cfg, new_cfg, sizeof(*new_cfg));
+	}
+}
+
+/*
+ * Note: assumes caller has acquired <msm_rpm_mutex>.
+ */
+static void msm_rpm_initialize_notification(void)
+{
+	struct msm_rpm_notif_config cfg;
+	unsigned int ctx;
+	int i;
+
+	for (ctx = MSM_RPM_CTX_SET_0; ctx <= MSM_RPM_CTX_SET_SLEEP; ctx++) {
+		cfg = msm_rpm_notif_cfgs[ctx];
+
+		for (i = 0; i < msm_rpm_sel_mask_size; i++) {
+			configured_iv(&cfg)[i].id =
+				MSM_RPM_ID_NOTIFICATION_CONFIGURED_0 + i;
+			configured_iv(&cfg)[i].value = ~0UL;
+
+			registered_iv(&cfg)[i].id =
+				MSM_RPM_ID_NOTIFICATION_REGISTERED_0 + i;
+			registered_iv(&cfg)[i].value = 0;
+		}
+
+		msm_rpm_update_notification(ctx,
+			&msm_rpm_notif_cfgs[ctx], &cfg);
+	}
+}
+
+/******************************************************************************
+ * Public functions
+ *****************************************************************************/
+
+int msm_rpm_local_request_is_outstanding(void)
+{
+	unsigned long flags;
+	int outstanding = 0;
+
+	if (!spin_trylock_irqsave(&msm_rpm_lock, flags))
+		goto local_request_is_outstanding_exit;
+
+	if (!spin_trylock(&msm_rpm_irq_lock))
+		goto local_request_is_outstanding_unlock;
+
+	outstanding = (msm_rpm_request != NULL);
+	spin_unlock(&msm_rpm_irq_lock);
+
+local_request_is_outstanding_unlock:
+	spin_unlock_irqrestore(&msm_rpm_lock, flags);
+
+local_request_is_outstanding_exit:
+	return outstanding;
+}
+
+/*
+ * Read the specified status registers and return their values.
+ *
+ * status: array of id-value pairs.  Each <id> specifies a status register,
+ *         i.e, one of MSM_RPM_STATUS_ID_xxxx.  Upon return, each <value> will
+ *         contain the value of the status register.
+ * count: number of id-value pairs in the array
+ *
+ * Return value:
+ *   0: success
+ *   -EBUSY: RPM is updating the status page; values across different registers
+ *           may not be consistent
+ *   -EINVAL: invalid id in <status> array
+ *   -ENODEV: RPM driver not initialized
+ */
+int msm_rpm_get_status(struct msm_rpm_iv_pair *status, int count)
+{
+	uint32_t seq_begin;
+	uint32_t seq_end;
+	int rc;
+	int i;
+
+	seq_begin = msm_rpm_read(MSM_RPM_PAGE_STATUS,
+				target_status(MSM_RPM_STATUS_ID_SEQUENCE));
+
+	for (i = 0; i < count; i++) {
+		int target_status_id;
+
+		if (status[i].id >= MSM_RPM_STATUS_ID_LAST) {
+			pr_err("%s(): Status ID beyond limits\n", __func__);
+			rc = -EINVAL;
+			goto get_status_exit;
+		}
+
+		target_status_id = target_status(status[i].id);
+		if (target_status_id >= MSM_RPM_STATUS_ID_LAST) {
+			pr_err("%s(): Status id %d not defined for target\n",
+					__func__,
+					target_status_id);
+			rc = -EINVAL;
+			goto get_status_exit;
+		}
+
+		status[i].value = msm_rpm_read(MSM_RPM_PAGE_STATUS,
+				target_status_id);
+	}
+
+	seq_end = msm_rpm_read(MSM_RPM_PAGE_STATUS,
+				target_status(MSM_RPM_STATUS_ID_SEQUENCE));
+
+	rc = (seq_begin != seq_end || (seq_begin & 0x01)) ? -EBUSY : 0;
+
+get_status_exit:
+	return rc;
+}
+EXPORT_SYMBOL(msm_rpm_get_status);
+
+/*
+ * Issue a resource request to RPM to set resource values.
+ *
+ * Note: the function may sleep and must be called in a task context.
+ *
+ * ctx: the request's context.
+ *      There two contexts that a RPM driver client can use:
+ *      MSM_RPM_CTX_SET_0 and MSM_RPM_CTX_SET_SLEEP.  For resource values
+ *      that are intended to take effect when the CPU is active,
+ *      MSM_RPM_CTX_SET_0 should be used.  For resource values that are
+ *      intended to take effect when the CPU is not active,
+ *      MSM_RPM_CTX_SET_SLEEP should be used.
+ * req: array of id-value pairs.  Each <id> specifies a RPM resource,
+ *      i.e, one of MSM_RPM_ID_xxxx.  Each <value> specifies the requested
+ *      resource value.
+ * count: number of id-value pairs in the array
+ *
+ * Return value:
+ *   0: success
+ *   -EINVAL: invalid <ctx> or invalid id in <req> array
+ *   -ENOSPC: request rejected
+ *   -ENODEV: RPM driver not initialized
+ */
+int msm_rpm_set(int ctx, struct msm_rpm_iv_pair *req, int count)
+{
+	return msm_rpm_set_common(ctx, req, count, false);
+}
+EXPORT_SYMBOL(msm_rpm_set);
+
+/*
+ * Issue a resource request to RPM to set resource values.
+ *
+ * Note: the function is similar to msm_rpm_set() except that it must be
+ *       called with interrupts masked.  If possible, use msm_rpm_set()
+ *       instead, to maximize CPU throughput.
+ */
+int msm_rpm_set_noirq(int ctx, struct msm_rpm_iv_pair *req, int count)
+{
+	WARN(!irqs_disabled(), "msm_rpm_set_noirq can only be called "
+		"safely when local irqs are disabled.  Consider using "
+		"msm_rpm_set or msm_rpm_set_nosleep instead.");
+	return msm_rpm_set_common(ctx, req, count, true);
+}
+EXPORT_SYMBOL(msm_rpm_set_noirq);
+
+/*
+ * Issue a resource request to RPM to clear resource values.  Once the
+ * values are cleared, the resources revert back to their default values
+ * for this RPM master.
+ *
+ * Note: the function may sleep and must be called in a task context.
+ *
+ * ctx: the request's context.
+ * req: array of id-value pairs.  Each <id> specifies a RPM resource,
+ *      i.e, one of MSM_RPM_ID_xxxx.  <value>'s are ignored.
+ * count: number of id-value pairs in the array
+ *
+ * Return value:
+ *   0: success
+ *   -EINVAL: invalid <ctx> or invalid id in <req> array
+ */
+int msm_rpm_clear(int ctx, struct msm_rpm_iv_pair *req, int count)
+{
+	return msm_rpm_clear_common(ctx, req, count, false);
+}
+EXPORT_SYMBOL(msm_rpm_clear);
+
+/*
+ * Issue a resource request to RPM to clear resource values.
+ *
+ * Note: the function is similar to msm_rpm_clear() except that it must be
+ *       called with interrupts masked.  If possible, use msm_rpm_clear()
+ *       instead, to maximize CPU throughput.
+ */
+int msm_rpm_clear_noirq(int ctx, struct msm_rpm_iv_pair *req, int count)
+{
+	WARN(!irqs_disabled(), "msm_rpm_clear_noirq can only be called "
+		"safely when local irqs are disabled.  Consider using "
+		"msm_rpm_clear or msm_rpm_clear_nosleep instead.");
+	return msm_rpm_clear_common(ctx, req, count, true);
+}
+EXPORT_SYMBOL(msm_rpm_clear_noirq);
+
+/*
+ * Register for RPM notification.  When the specified resources
+ * change their status on RPM, RPM sends out notifications and the
+ * driver will "up" the semaphore in struct msm_rpm_notification.
+ *
+ * Note: the function may sleep and must be called in a task context.
+ *
+ *       Memory for <n> must not be freed until the notification is
+ *       unregistered.  Memory for <req> can be freed after this
+ *       function returns.
+ *
+ * n: the notifcation object.  Caller should initialize only the
+ *    semaphore field.  When a notification arrives later, the
+ *    semaphore will be "up"ed.
+ * req: array of id-value pairs.  Each <id> specifies a status register,
+ *      i.e, one of MSM_RPM_STATUS_ID_xxxx.  <value>'s are ignored.
+ * count: number of id-value pairs in the array
+ *
+ * Return value:
+ *   0: success
+ *   -EINVAL: invalid id in <req> array
+ *   -ENODEV: RPM driver not initialized
+ */
+int msm_rpm_register_notification(struct msm_rpm_notification *n,
+	struct msm_rpm_iv_pair *req, int count)
+{
+	unsigned long flags;
+	unsigned int ctx;
+	struct msm_rpm_notif_config cfg;
+	int rc;
+	int i;
+
+	INIT_LIST_HEAD(&n->list);
+	rc = msm_rpm_fill_sel_masks(n->sel_masks, req, count);
+	if (rc)
+		goto register_notification_exit;
+
+	mutex_lock(&msm_rpm_mutex);
+
+	if (!msm_rpm_init_notif_done) {
+		msm_rpm_initialize_notification();
+		msm_rpm_init_notif_done = true;
+	}
+
+	spin_lock_irqsave(&msm_rpm_irq_lock, flags);
+	list_add(&n->list, &msm_rpm_notifications);
+	spin_unlock_irqrestore(&msm_rpm_irq_lock, flags);
+
+	ctx = MSM_RPM_CTX_SET_0;
+	cfg = msm_rpm_notif_cfgs[ctx];
+
+	for (i = 0; i < msm_rpm_sel_mask_size; i++)
+		registered_iv(&cfg)[i].value |= n->sel_masks[i];
+
+	msm_rpm_update_notification(ctx, &msm_rpm_notif_cfgs[ctx], &cfg);
+	mutex_unlock(&msm_rpm_mutex);
+
+register_notification_exit:
+	return rc;
+}
+EXPORT_SYMBOL(msm_rpm_register_notification);
+
+/*
+ * Unregister a notification.
+ *
+ * Note: the function may sleep and must be called in a task context.
+ *
+ * n: the notifcation object that was registered previously.
+ *
+ * Return value:
+ *   0: success
+ *   -ENODEV: RPM driver not initialized
+ */
+int msm_rpm_unregister_notification(struct msm_rpm_notification *n)
+{
+	unsigned long flags;
+	unsigned int ctx;
+	struct msm_rpm_notif_config cfg;
+	int rc = 0;
+	int i;
+
+	mutex_lock(&msm_rpm_mutex);
+	ctx = MSM_RPM_CTX_SET_0;
+	cfg = msm_rpm_notif_cfgs[ctx];
+
+	for (i = 0; i < msm_rpm_sel_mask_size; i++)
+		registered_iv(&cfg)[i].value = 0;
+
+	spin_lock_irqsave(&msm_rpm_irq_lock, flags);
+	list_del(&n->list);
+	list_for_each_entry(n, &msm_rpm_notifications, list)
+		for (i = 0; i < msm_rpm_sel_mask_size; i++)
+			registered_iv(&cfg)[i].value |= n->sel_masks[i];
+	spin_unlock_irqrestore(&msm_rpm_irq_lock, flags);
+
+	msm_rpm_update_notification(ctx, &msm_rpm_notif_cfgs[ctx], &cfg);
+	mutex_unlock(&msm_rpm_mutex);
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_rpm_unregister_notification);
+
+static uint32_t fw_major, fw_minor, fw_build;
+
+static ssize_t driver_version_show(struct kobject *kobj,
+		struct kobj_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%u.%u.%u\n",
+		msm_rpm_data.ver[0], msm_rpm_data.ver[1], msm_rpm_data.ver[2]);
+}
+
+static ssize_t fw_version_show(struct kobject *kobj,
+		struct kobj_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%u.%u.%u\n",
+			fw_major, fw_minor, fw_build);
+}
+
+static struct kobj_attribute driver_version_attr = __ATTR_RO(driver_version);
+static struct kobj_attribute fw_version_attr = __ATTR_RO(fw_version);
+
+static struct attribute *driver_attributes[] = {
+	&driver_version_attr.attr,
+	&fw_version_attr.attr,
+	NULL
+};
+
+static struct attribute_group driver_attr_group = {
+	.attrs = driver_attributes,
+};
+
+static int __devinit msm_rpm_probe(struct platform_device *pdev)
+{
+	return sysfs_create_group(&pdev->dev.kobj, &driver_attr_group);
+}
+
+static int __devexit msm_rpm_remove(struct platform_device *pdev)
+{
+	sysfs_remove_group(&pdev->dev.kobj, &driver_attr_group);
+	return 0;
+}
+
+static struct platform_driver msm_rpm_platform_driver = {
+	.probe = msm_rpm_probe,
+	.remove = __devexit_p(msm_rpm_remove),
+	.driver = {
+		.name = "msm_rpm",
+		.owner = THIS_MODULE,
+	},
+};
+
+static void __init msm_rpm_populate_map(struct msm_rpm_platform_data *data)
+{
+	int i, j;
+	struct msm_rpm_map_data *src = NULL;
+	struct msm_rpm_map_data *dst = NULL;
+
+	for (i = 0; i < MSM_RPM_ID_LAST;) {
+		src = &data->target_id[i];
+		dst = &msm_rpm_data.target_id[i];
+
+		dst->id = MSM_RPM_ID_LAST;
+		dst->sel = msm_rpm_data.sel_last + 1;
+
+		/*
+		 * copy the target specific id of the current and also of
+		 * all the #count id's that follow the current.
+		 * [MSM_RPM_ID_PM8921_S1_0] = { MSM_RPM_8960_ID_PM8921_S1_0,
+		 *				MSM_RPM_8960_SEL_PM8921_S1,
+		 *				2},
+		 * [MSM_RPM_ID_PM8921_S1_1] = { 0, 0, 0 },
+		 * should translate to
+		 * [MSM_RPM_ID_PM8921_S1_0] = { MSM_RPM_8960_ID_PM8921_S1_0,
+		 *				MSM_RPM_8960_SEL_PM8921,
+		 *				2 },
+		 * [MSM_RPM_ID_PM8921_S1_1] = { MSM_RPM_8960_ID_PM8921_S1_0 + 1,
+		 *				MSM_RPM_8960_SEL_PM8921,
+		 *				0 },
+		 */
+		for (j = 0; j < src->count; j++) {
+			dst = &msm_rpm_data.target_id[i + j];
+			dst->id = src->id + j;
+			dst->sel = src->sel;
+		}
+
+		i += (src->count) ? src->count : 1;
+	}
+
+	for (i = 0; i < MSM_RPM_STATUS_ID_LAST; i++) {
+		if (data->target_status[i] & MSM_RPM_STATUS_ID_VALID)
+			msm_rpm_data.target_status[i] &=
+				~MSM_RPM_STATUS_ID_VALID;
+		else
+			msm_rpm_data.target_status[i] = MSM_RPM_STATUS_ID_LAST;
+	}
+}
+
+static irqreturn_t msm_pm_rpm_wakeup_interrupt(int irq, void *dev_id)
+{
+	if (dev_id != &msm_pm_rpm_wakeup_interrupt)
+		return IRQ_NONE;
+
+	return IRQ_HANDLED;
+}
+
+int __init msm_rpm_init(struct msm_rpm_platform_data *data)
+{
+	int rc;
+
+	memcpy(&msm_rpm_data, data, sizeof(struct msm_rpm_platform_data));
+	msm_rpm_sel_mask_size = msm_rpm_data.sel_last / 32 + 1;
+	BUG_ON(SEL_MASK_SIZE < msm_rpm_sel_mask_size);
+
+	fw_major = msm_rpm_read(MSM_RPM_PAGE_STATUS,
+				target_status(MSM_RPM_STATUS_ID_VERSION_MAJOR));
+	fw_minor = msm_rpm_read(MSM_RPM_PAGE_STATUS,
+				target_status(MSM_RPM_STATUS_ID_VERSION_MINOR));
+	fw_build = msm_rpm_read(MSM_RPM_PAGE_STATUS,
+				target_status(MSM_RPM_STATUS_ID_VERSION_BUILD));
+	pr_info("%s: RPM firmware %u.%u.%u\n", __func__,
+			fw_major, fw_minor, fw_build);
+
+	if (fw_major != msm_rpm_data.ver[0]) {
+		pr_err("%s: RPM version %u.%u.%u incompatible with "
+				"this driver version %u.%u.%u\n", __func__,
+				fw_major, fw_minor, fw_build,
+				msm_rpm_data.ver[0],
+				msm_rpm_data.ver[1],
+				msm_rpm_data.ver[2]);
+		return -EFAULT;
+	}
+
+	msm_rpm_write(MSM_RPM_PAGE_CTRL,
+		target_ctrl(MSM_RPM_CTRL_VERSION_MAJOR), msm_rpm_data.ver[0]);
+	msm_rpm_write(MSM_RPM_PAGE_CTRL,
+		target_ctrl(MSM_RPM_CTRL_VERSION_MINOR), msm_rpm_data.ver[1]);
+	msm_rpm_write(MSM_RPM_PAGE_CTRL,
+		target_ctrl(MSM_RPM_CTRL_VERSION_BUILD), msm_rpm_data.ver[2]);
+
+	rc = request_irq(data->irq_ack, msm_rpm_ack_interrupt,
+			IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND,
+			"rpm_drv", msm_rpm_ack_interrupt);
+	if (rc) {
+		pr_err("%s: failed to request irq %d: %d\n",
+			__func__, data->irq_ack, rc);
+		return rc;
+	}
+
+	rc = irq_set_irq_wake(data->irq_ack, 1);
+	if (rc) {
+		pr_err("%s: failed to set wakeup irq %u: %d\n",
+			__func__, data->irq_ack, rc);
+		return rc;
+	}
+
+	rc = request_irq(data->irq_err, msm_rpm_err_interrupt,
+			IRQF_TRIGGER_RISING, "rpm_err", NULL);
+	if (rc) {
+		pr_err("%s: failed to request error interrupt: %d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	rc = request_irq(data->irq_wakeup,
+			msm_pm_rpm_wakeup_interrupt, IRQF_TRIGGER_RISING,
+			"pm_drv", msm_pm_rpm_wakeup_interrupt);
+	if (rc) {
+		pr_err("%s: failed to request irq %u: %d\n",
+			__func__, data->irq_wakeup, rc);
+		return rc;
+	}
+
+	rc = irq_set_irq_wake(data->irq_wakeup, 1);
+	if (rc) {
+		pr_err("%s: failed to set wakeup irq %u: %d\n",
+			__func__, data->irq_wakeup, rc);
+		return rc;
+	}
+
+	msm_rpm_populate_map(data);
+
+	return platform_driver_register(&msm_rpm_platform_driver);
+}
diff --git a/arch/arm/mach-msm/rpm_log.c b/arch/arm/mach-msm/rpm_log.c
new file mode 100644
index 0000000..3ed55da
--- /dev/null
+++ b/arch/arm/mach-msm/rpm_log.c
@@ -0,0 +1,363 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <asm/uaccess.h>
+
+#include <mach/msm_iomap.h>
+
+#include "rpm_log.h"
+
+/* registers in MSM_RPM_LOG_PAGE_INDICES */
+enum {
+	MSM_RPM_LOG_TAIL,
+	MSM_RPM_LOG_HEAD
+};
+
+/* used to 4 byte align message lengths */
+#define PADDED_LENGTH(x) (0xFFFFFFFC & ((x) + 3))
+
+/* calculates the character string length of a message of byte length x */
+#define PRINTED_LENGTH(x) ((x) * 6 + 3)
+
+/* number of ms to wait between checking for new messages in the RPM log */
+#define RECHECK_TIME (50)
+
+struct msm_rpm_log_buffer {
+	char *data;
+	u32 len;
+	u32 pos;
+	u32 max_len;
+	u32 read_idx;
+	struct msm_rpm_log_platform_data *pdata;
+};
+
+/******************************************************************************
+ * Internal functions
+ *****************************************************************************/
+
+static inline u32
+msm_rpm_log_read(const struct msm_rpm_log_platform_data *pdata, u32 page,
+		 u32 reg)
+{
+	return readl_relaxed(pdata->reg_base + pdata->reg_offsets[page]
+				+ reg * 4);
+}
+
+/*
+ * msm_rpm_log_copy() - Copies messages from a volatile circular buffer in
+ *			the RPM's shared memory into a private local buffer
+ * msg_buffer:		pointer to local buffer (string)
+ * buf_len:		length of local buffer in bytes
+ * read_start_idx:	index into shared memory buffer
+ *
+ * Return value:	number of bytes written to the local buffer
+ *
+ * Copies messages stored in a circular buffer in the RPM Message Memory into
+ * a specified local buffer.  The RPM processor is unaware of these reading
+ * efforts, so care is taken to make sure that messages are valid both before
+ * and after reading.  The RPM processor utilizes a ULog driver to write the
+ * log.  The RPM processor maintains tail and head indices.  These correspond
+ * to the next byte to write into, and the first valid byte, respectively.
+ * Both indices increase monotonically (except for rollover).
+ *
+ * Messages take the form of [(u32)length] [(char)data0,1,...] in which the
+ * length specifies the number of payload bytes.  Messages must be 4 byte
+ * aligned, so padding is added at the end of a message as needed.
+ *
+ * Print format:
+ * - 0xXX, 0xXX, 0xXX
+ * - 0xXX
+ * etc...
+ */
+static u32 msm_rpm_log_copy(const struct msm_rpm_log_platform_data *pdata,
+			    char *msg_buffer, u32 buf_len, u32 *read_idx)
+{
+	u32 head_idx, tail_idx;
+	u32 pos = 0;
+	u32 i = 0;
+	u32 msg_len;
+	u32 pos_start;
+	char temp[4];
+
+	tail_idx = msm_rpm_log_read(pdata, MSM_RPM_LOG_PAGE_INDICES,
+				    MSM_RPM_LOG_TAIL);
+	head_idx = msm_rpm_log_read(pdata, MSM_RPM_LOG_PAGE_INDICES,
+				    MSM_RPM_LOG_HEAD);
+
+	/* loop while the remote buffer has valid messages left to read */
+	while (tail_idx - head_idx > 0 && tail_idx - *read_idx > 0) {
+		head_idx = msm_rpm_log_read(pdata, MSM_RPM_LOG_PAGE_INDICES,
+					    MSM_RPM_LOG_HEAD);
+		/* check if the message to be read is valid */
+		if (tail_idx - *read_idx > tail_idx - head_idx) {
+			*read_idx = head_idx;
+			continue;
+		}
+		/*
+		 * Ensure that the reported buffer size is within limits of
+		 * known maximum size and that all indices are 4 byte aligned.
+		 * These conditions are required to interact with a ULog buffer
+		 * properly.
+		 */
+		if (tail_idx - head_idx > pdata->log_len ||
+		    !IS_ALIGNED((tail_idx | head_idx | *read_idx), 4))
+			break;
+
+		msg_len = msm_rpm_log_read(pdata, MSM_RPM_LOG_PAGE_BUFFER,
+					(*read_idx >> 2) & pdata->log_len_mask);
+
+		/* handle messages that claim to be longer than the log */
+		if (PADDED_LENGTH(msg_len) > tail_idx - *read_idx - 4)
+			msg_len = tail_idx - *read_idx - 4;
+
+		/* check that the local buffer has enough space for this msg */
+		if (pos + PRINTED_LENGTH(msg_len) > buf_len)
+			break;
+
+		pos_start = pos;
+		pos += scnprintf(msg_buffer + pos, buf_len - pos, "- ");
+
+		/* copy message payload to local buffer */
+		for (i = 0; i < msg_len; i++) {
+			/* read from shared memory 4 bytes at a time */
+			if (IS_ALIGNED(i, 4))
+				*((u32 *)temp) = msm_rpm_log_read(pdata,
+						MSM_RPM_LOG_PAGE_BUFFER,
+						((*read_idx + 4 + i) >> 2) &
+							pdata->log_len_mask);
+
+			pos += scnprintf(msg_buffer + pos, buf_len - pos,
+					 "0x%02X, ", temp[i & 0x03]);
+		}
+
+		pos += scnprintf(msg_buffer + pos, buf_len - pos, "\n");
+
+		head_idx = msm_rpm_log_read(pdata, MSM_RPM_LOG_PAGE_INDICES,
+					    MSM_RPM_LOG_HEAD);
+
+		/* roll back if message that was read is not still valid */
+		if (tail_idx - *read_idx > tail_idx - head_idx)
+			pos = pos_start;
+
+		*read_idx += PADDED_LENGTH(msg_len) + 4;
+	}
+
+	return pos;
+}
+
+
+/*
+ * msm_rpm_log_file_read() - Reads in log buffer messages then outputs them to a
+ *			     user buffer
+ *
+ * Return value:
+ *	0:	 success
+ *	-ENOMEM: no memory available
+ *	-EINVAL: user buffer null or requested bytes 0
+ *	-EFAULT: user buffer not writeable
+ *	-EAGAIN: no bytes available at the moment
+ */
+static ssize_t msm_rpm_log_file_read(struct file *file, char __user *bufu,
+				     size_t count, loff_t *ppos)
+{
+	u32 out_len, remaining;
+	struct msm_rpm_log_platform_data *pdata;
+	struct msm_rpm_log_buffer *buf;
+
+	buf = file->private_data;
+	pdata = buf->pdata;
+	if (!pdata)
+		return -EINVAL;
+	if (!buf)
+		return -ENOMEM;
+	if (!buf->data)
+		return -ENOMEM;
+	if (!bufu || count < 0)
+		return -EINVAL;
+	if (!access_ok(VERIFY_WRITE, bufu, count))
+		return -EFAULT;
+
+	/* check for more messages if local buffer empty */
+	if (buf->pos == buf->len) {
+		buf->pos = 0;
+		buf->len = msm_rpm_log_copy(pdata, buf->data, buf->max_len,
+						&(buf->read_idx));
+	}
+
+	if ((file->f_flags & O_NONBLOCK) && buf->len == 0)
+		return -EAGAIN;
+
+	/* loop until new messages arrive */
+	while (buf->len == 0) {
+		cond_resched();
+		if (msleep_interruptible(RECHECK_TIME))
+			break;
+		buf->len = msm_rpm_log_copy(pdata, buf->data, buf->max_len,
+						&(buf->read_idx));
+	}
+
+	out_len = ((buf->len - buf->pos) < count ? buf->len - buf->pos : count);
+
+	remaining = __copy_to_user(bufu, &(buf->data[buf->pos]), out_len);
+	buf->pos += out_len - remaining;
+
+	return out_len - remaining;
+}
+
+
+/*
+ * msm_rpm_log_file_open() - Allows a new reader to open the RPM log virtual
+ *                           file
+ *
+ * One local buffer is kmalloc'ed for each reader, so no resource sharing has
+ * to take place (besides the read only access to the RPM log buffer).
+ *
+ * Return value:
+ *	0:	 success
+ *	-ENOMEM: no memory available
+ */
+static int msm_rpm_log_file_open(struct inode *inode, struct file *file)
+{
+	struct msm_rpm_log_buffer *buf;
+	struct msm_rpm_log_platform_data *pdata;
+
+	pdata = inode->i_private;
+	if (!pdata)
+		return -EINVAL;
+
+	file->private_data =
+		   kmalloc(sizeof(struct msm_rpm_log_buffer), GFP_KERNEL);
+	if (!file->private_data) {
+		pr_err("%s: ERROR kmalloc failed to allocate %d bytes\n",
+			__func__, sizeof(struct msm_rpm_log_buffer));
+		return -ENOMEM;
+	}
+	buf = file->private_data;
+
+	buf->data = kmalloc(PRINTED_LENGTH(pdata->log_len), GFP_KERNEL);
+	if (!buf->data) {
+		kfree(file->private_data);
+		file->private_data = NULL;
+		pr_err("%s: ERROR kmalloc failed to allocate %d bytes\n",
+			__func__, PRINTED_LENGTH(pdata->log_len));
+		return -ENOMEM;
+	}
+
+	buf->pdata = pdata;
+	buf->len = 0;
+	buf->pos = 0;
+	buf->max_len = PRINTED_LENGTH(pdata->log_len);
+	buf->read_idx = msm_rpm_log_read(pdata, MSM_RPM_LOG_PAGE_INDICES,
+					 MSM_RPM_LOG_HEAD);
+	return 0;
+}
+
+static int msm_rpm_log_file_close(struct inode *inode, struct file *file)
+{
+	kfree(((struct msm_rpm_log_buffer *)file->private_data)->data);
+	kfree(file->private_data);
+	return 0;
+}
+
+
+static const struct file_operations msm_rpm_log_file_fops = {
+	.owner   = THIS_MODULE,
+	.open    = msm_rpm_log_file_open,
+	.read    = msm_rpm_log_file_read,
+	.release = msm_rpm_log_file_close,
+};
+
+static int __devinit msm_rpm_log_probe(struct platform_device *pdev)
+{
+	struct dentry *dent;
+	struct msm_rpm_log_platform_data *pdata;
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata)
+		return -EINVAL;
+
+	pdata->reg_base = ioremap(pdata->phys_addr_base, pdata->phys_size);
+	if (!pdata->reg_base) {
+		pr_err("%s: ERROR could not ioremap: start=%p, len=%u\n",
+			__func__, (void *) pdata->phys_addr_base,
+			pdata->phys_size);
+		return -EBUSY;
+	}
+
+	dent = debugfs_create_file("rpm_log", S_IRUGO, NULL,
+			pdev->dev.platform_data, &msm_rpm_log_file_fops);
+	if (!dent) {
+		pr_err("%s: ERROR debugfs_create_file failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(pdev, dent);
+
+	pr_notice("%s: OK\n", __func__);
+	return 0;
+}
+
+static int __devexit msm_rpm_log_remove(struct platform_device *pdev)
+{
+	struct dentry *dent;
+	struct msm_rpm_log_platform_data *pdata;
+
+	pdata = pdev->dev.platform_data;
+
+	iounmap(pdata->reg_base);
+
+	dent = platform_get_drvdata(pdev);
+	debugfs_remove(dent);
+	platform_set_drvdata(pdev, NULL);
+
+	pr_notice("%s: OK\n", __func__);
+	return 0;
+}
+
+static struct platform_driver msm_rpm_log_driver = {
+	.probe		= msm_rpm_log_probe,
+	.remove		= __devexit_p(msm_rpm_log_remove),
+	.driver		= {
+		.name = "msm_rpm_log",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_rpm_log_init(void)
+{
+	return platform_driver_register(&msm_rpm_log_driver);
+}
+
+static void __exit msm_rpm_log_exit(void)
+{
+	platform_driver_unregister(&msm_rpm_log_driver);
+}
+
+module_init(msm_rpm_log_init);
+module_exit(msm_rpm_log_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MSM RPM Log driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:msm_rpm_log");
diff --git a/arch/arm/mach-msm/rpm_log.h b/arch/arm/mach-msm/rpm_log.h
new file mode 100644
index 0000000..37349b6
--- /dev/null
+++ b/arch/arm/mach-msm/rpm_log.h
@@ -0,0 +1,34 @@
+/* Copyright (c) 2010, 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 __ARCH_ARM_MACH_MSM_RPM_LOG_H
+#define __ARCH_ARM_MACH_MSM_RPM_LOG_H
+
+#include <linux/types.h>
+
+enum {
+	MSM_RPM_LOG_PAGE_INDICES,
+	MSM_RPM_LOG_PAGE_BUFFER,
+	MSM_RPM_LOG_PAGE_COUNT
+};
+
+struct msm_rpm_log_platform_data {
+	u32 reg_offsets[MSM_RPM_LOG_PAGE_COUNT];
+	u32 log_len;
+	u32 log_len_mask;
+	phys_addr_t phys_addr_base;
+	u32 phys_size;
+	void __iomem *reg_base;
+};
+
+#endif /* __ARCH_ARM_MACH_MSM_RPM_LOG_H */
diff --git a/arch/arm/mach-msm/rpm_resources.c b/arch/arm/mach-msm/rpm_resources.c
new file mode 100644
index 0000000..5314cee
--- /dev/null
+++ b/arch/arm/mach-msm/rpm_resources.c
@@ -0,0 +1,1106 @@
+/* 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
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/bug.h>
+#include <linux/mutex.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#include <linux/cpu.h>
+#include <mach/rpm.h>
+#include <mach/msm_iomap.h>
+#include <asm/mach-types.h>
+#include <linux/io.h>
+#include <mach/socinfo.h>
+#include <mach/mpm.h>
+#include "rpm_resources.h"
+#include "spm.h"
+#include "idle.h"
+
+/******************************************************************************
+ * Debug Definitions
+ *****************************************************************************/
+
+enum {
+	MSM_RPMRS_DEBUG_OUTPUT = BIT(0),
+	MSM_RPMRS_DEBUG_BUFFER = BIT(1),
+};
+
+static int msm_rpmrs_debug_mask;
+module_param_named(
+	debug_mask, msm_rpmrs_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
+);
+
+static struct msm_rpmrs_level *msm_rpmrs_levels;
+static int msm_rpmrs_level_count;
+
+static bool msm_rpmrs_pxo_beyond_limits(struct msm_rpmrs_limits *limits);
+static void msm_rpmrs_aggregate_pxo(struct msm_rpmrs_limits *limits);
+static void msm_rpmrs_restore_pxo(void);
+static bool msm_rpmrs_l2_cache_beyond_limits(struct msm_rpmrs_limits *limits);
+static void msm_rpmrs_aggregate_l2_cache(struct msm_rpmrs_limits *limits);
+static void msm_rpmrs_restore_l2_cache(void);
+static bool msm_rpmrs_vdd_mem_beyond_limits(struct msm_rpmrs_limits *limits);
+static void msm_rpmrs_aggregate_vdd_mem(struct msm_rpmrs_limits *limits);
+static void msm_rpmrs_restore_vdd_mem(void);
+static bool msm_rpmrs_vdd_dig_beyond_limits(struct msm_rpmrs_limits *limits);
+static void msm_rpmrs_aggregate_vdd_dig(struct msm_rpmrs_limits *limits);
+static void msm_rpmrs_restore_vdd_dig(void);
+
+static ssize_t msm_rpmrs_resource_attr_show(
+	struct kobject *kobj, struct kobj_attribute *attr, char *buf);
+static ssize_t msm_rpmrs_resource_attr_store(struct kobject *kobj,
+	struct kobj_attribute *attr, const char *buf, size_t count);
+
+static int vdd_dig_vlevels[MSM_RPMRS_VDD_DIG_LAST];
+static int vdd_mem_vlevels[MSM_RPMRS_VDD_MEM_LAST];
+static int vdd_mask;
+
+#define MSM_RPMRS_MAX_RS_REGISTER_COUNT 2
+
+#define RPMRS_ATTR(_name) \
+	__ATTR(_name, S_IRUGO|S_IWUSR, \
+		msm_rpmrs_resource_attr_show, msm_rpmrs_resource_attr_store)
+
+struct msm_rpmrs_resource {
+	struct msm_rpm_iv_pair rs[MSM_RPMRS_MAX_RS_REGISTER_COUNT];
+	uint32_t size;
+	char *name;
+
+	uint32_t enable_low_power;
+
+	bool (*beyond_limits)(struct msm_rpmrs_limits *limits);
+	void (*aggregate)(struct msm_rpmrs_limits *limits);
+	void (*restore)(void);
+
+	struct kobj_attribute ko_attr;
+};
+
+static struct msm_rpmrs_resource msm_rpmrs_pxo = {
+	.size = 1,
+	.name = "pxo",
+	.beyond_limits = msm_rpmrs_pxo_beyond_limits,
+	.aggregate = msm_rpmrs_aggregate_pxo,
+	.restore = msm_rpmrs_restore_pxo,
+	.ko_attr = RPMRS_ATTR(pxo),
+};
+
+static struct msm_rpmrs_resource msm_rpmrs_l2_cache = {
+	.size = 1,
+	.name = "L2_cache",
+	.beyond_limits = msm_rpmrs_l2_cache_beyond_limits,
+	.aggregate = msm_rpmrs_aggregate_l2_cache,
+	.restore = msm_rpmrs_restore_l2_cache,
+	.ko_attr = RPMRS_ATTR(L2_cache),
+};
+
+static struct msm_rpmrs_resource msm_rpmrs_vdd_mem = {
+	.size = 2,
+	.name = "vdd_mem",
+	.beyond_limits = msm_rpmrs_vdd_mem_beyond_limits,
+	.aggregate = msm_rpmrs_aggregate_vdd_mem,
+	.restore = msm_rpmrs_restore_vdd_mem,
+	.ko_attr = RPMRS_ATTR(vdd_mem),
+};
+
+static struct msm_rpmrs_resource msm_rpmrs_vdd_dig = {
+	.size = 2,
+	.name = "vdd_dig",
+	.beyond_limits = msm_rpmrs_vdd_dig_beyond_limits,
+	.aggregate = msm_rpmrs_aggregate_vdd_dig,
+	.restore = msm_rpmrs_restore_vdd_dig,
+	.ko_attr = RPMRS_ATTR(vdd_dig),
+};
+
+static struct msm_rpmrs_resource msm_rpmrs_rpm_ctl = {
+	.size = 1,
+	.name = "rpm_ctl",
+	.beyond_limits = NULL,
+	.aggregate = NULL,
+	.restore = NULL,
+	.ko_attr = RPMRS_ATTR(rpm_ctl),
+};
+
+static struct msm_rpmrs_resource *msm_rpmrs_resources[] = {
+	&msm_rpmrs_pxo,
+	&msm_rpmrs_l2_cache,
+	&msm_rpmrs_vdd_mem,
+	&msm_rpmrs_vdd_dig,
+	&msm_rpmrs_rpm_ctl,
+};
+
+static uint32_t msm_rpmrs_buffer[MSM_RPM_ID_LAST];
+static DECLARE_BITMAP(msm_rpmrs_buffered, MSM_RPM_ID_LAST);
+static DECLARE_BITMAP(msm_rpmrs_listed, MSM_RPM_ID_LAST);
+static DEFINE_SPINLOCK(msm_rpmrs_lock);
+
+#define MSM_RPMRS_VDD(v)  ((v) & (vdd_mask))
+
+/******************************************************************************
+ * Attribute Definitions
+ *****************************************************************************/
+static struct attribute *msm_rpmrs_attributes[] = {
+	&msm_rpmrs_pxo.ko_attr.attr,
+	&msm_rpmrs_l2_cache.ko_attr.attr,
+	&msm_rpmrs_vdd_mem.ko_attr.attr,
+	&msm_rpmrs_vdd_dig.ko_attr.attr,
+	NULL,
+};
+static struct attribute *msm_rpmrs_mode_attributes[] = {
+	&msm_rpmrs_rpm_ctl.ko_attr.attr,
+	NULL,
+};
+
+static struct attribute_group msm_rpmrs_attribute_group = {
+	.attrs = msm_rpmrs_attributes,
+};
+
+static struct attribute_group msm_rpmrs_mode_attribute_group = {
+	.attrs = msm_rpmrs_mode_attributes,
+};
+
+#define GET_RS_FROM_ATTR(attr) \
+	(container_of(attr, struct msm_rpmrs_resource, ko_attr))
+
+
+/******************************************************************************
+ * Resource Specific Functions
+ *****************************************************************************/
+
+static void msm_rpmrs_aggregate_sclk(uint32_t sclk_count)
+{
+	msm_rpmrs_buffer[MSM_RPM_ID_TRIGGER_TIMED_TO] = 0;
+	set_bit(MSM_RPM_ID_TRIGGER_TIMED_TO, msm_rpmrs_buffered);
+	msm_rpmrs_buffer[MSM_RPM_ID_TRIGGER_TIMED_SCLK_COUNT] = sclk_count;
+	set_bit(MSM_RPM_ID_TRIGGER_TIMED_SCLK_COUNT, msm_rpmrs_buffered);
+}
+
+static void msm_rpmrs_restore_sclk(void)
+{
+	clear_bit(MSM_RPM_ID_TRIGGER_TIMED_SCLK_COUNT, msm_rpmrs_buffered);
+	msm_rpmrs_buffer[MSM_RPM_ID_TRIGGER_TIMED_SCLK_COUNT] = 0;
+	clear_bit(MSM_RPM_ID_TRIGGER_TIMED_TO, msm_rpmrs_buffered);
+	msm_rpmrs_buffer[MSM_RPM_ID_TRIGGER_TIMED_TO] = 0;
+}
+
+static bool msm_rpmrs_pxo_beyond_limits(struct msm_rpmrs_limits *limits)
+{
+	struct msm_rpmrs_resource *rs = &msm_rpmrs_pxo;
+	uint32_t pxo;
+
+	if (rs->enable_low_power && test_bit(rs->rs[0].id, msm_rpmrs_buffered))
+		pxo = msm_rpmrs_buffer[rs->rs[0].id];
+	else
+		pxo = MSM_RPMRS_PXO_ON;
+
+	return pxo > limits->pxo;
+}
+
+static void msm_rpmrs_aggregate_pxo(struct msm_rpmrs_limits *limits)
+{
+	struct msm_rpmrs_resource *rs = &msm_rpmrs_pxo;
+	uint32_t *buf = &msm_rpmrs_buffer[rs->rs[0].id];
+
+	if (test_bit(rs->rs[0].id, msm_rpmrs_buffered)) {
+		rs->rs[0].value = *buf;
+		if (limits->pxo > *buf)
+			*buf = limits->pxo;
+		if (MSM_RPMRS_DEBUG_OUTPUT & msm_rpmrs_debug_mask)
+			pr_info("%s: %d (0x%x)\n", __func__, *buf, *buf);
+	}
+}
+
+static void msm_rpmrs_restore_pxo(void)
+{
+	struct msm_rpmrs_resource *rs = &msm_rpmrs_pxo;
+
+	if (test_bit(rs->rs[0].id, msm_rpmrs_buffered))
+		msm_rpmrs_buffer[rs->rs[0].id] = rs->rs[0].value;
+}
+
+static bool msm_rpmrs_l2_cache_beyond_limits(struct msm_rpmrs_limits *limits)
+{
+	struct msm_rpmrs_resource *rs = &msm_rpmrs_l2_cache;
+	uint32_t l2_cache;
+
+	if (rs->enable_low_power && test_bit(rs->rs[0].id, msm_rpmrs_buffered))
+		l2_cache = msm_rpmrs_buffer[rs->rs[0].id];
+	else
+		l2_cache = MSM_RPMRS_L2_CACHE_ACTIVE;
+
+	return l2_cache > limits->l2_cache;
+}
+
+static void msm_rpmrs_aggregate_l2_cache(struct msm_rpmrs_limits *limits)
+{
+	struct msm_rpmrs_resource *rs = &msm_rpmrs_l2_cache;
+	uint32_t *buf = &msm_rpmrs_buffer[rs->rs[0].id];
+
+	if (test_bit(rs->rs[0].id, msm_rpmrs_buffered)) {
+		rs->rs[0].value = *buf;
+		if (limits->l2_cache > *buf)
+			*buf = limits->l2_cache;
+
+		if (MSM_RPMRS_DEBUG_OUTPUT & msm_rpmrs_debug_mask)
+			pr_info("%s: %d (0x%x)\n", __func__, *buf, *buf);
+	}
+}
+
+static bool msm_spm_l2_cache_beyond_limits(struct msm_rpmrs_limits *limits)
+{
+	struct msm_rpmrs_resource *rs = &msm_rpmrs_l2_cache;
+	uint32_t l2_cache = rs->rs[0].value;
+
+	if (!rs->enable_low_power)
+		l2_cache = MSM_RPMRS_L2_CACHE_ACTIVE;
+
+	return l2_cache > limits->l2_cache;
+}
+
+static void msm_rpmrs_restore_l2_cache(void)
+{
+	struct msm_rpmrs_resource *rs = &msm_rpmrs_l2_cache;
+
+	if (test_bit(rs->rs[0].id, msm_rpmrs_buffered))
+		msm_rpmrs_buffer[rs->rs[0].id] = rs->rs[0].value;
+}
+
+static bool msm_rpmrs_vdd_mem_beyond_limits(struct msm_rpmrs_limits *limits)
+{
+	struct msm_rpmrs_resource *rs = &msm_rpmrs_vdd_mem;
+	uint32_t vdd_mem;
+
+	if (test_bit(rs->rs[0].id, msm_rpmrs_buffered)) {
+		uint32_t buffered_value = msm_rpmrs_buffer[rs->rs[0].id];
+
+		if (rs->enable_low_power == 0)
+			vdd_mem = vdd_mem_vlevels[MSM_RPMRS_VDD_MEM_ACTIVE];
+		else if (rs->enable_low_power == 1)
+			vdd_mem = vdd_mem_vlevels[MSM_RPMRS_VDD_MEM_RET_HIGH];
+		else
+			vdd_mem = vdd_mem_vlevels[MSM_RPMRS_VDD_MEM_RET_LOW];
+
+		if (MSM_RPMRS_VDD(buffered_value) > MSM_RPMRS_VDD(vdd_mem))
+			vdd_mem = MSM_RPMRS_VDD(buffered_value);
+	} else {
+		vdd_mem = vdd_mem_vlevels[MSM_RPMRS_VDD_MEM_ACTIVE];
+	}
+
+	return vdd_mem > vdd_mem_vlevels[limits->vdd_mem_upper_bound];
+}
+
+static void msm_rpmrs_aggregate_vdd_mem(struct msm_rpmrs_limits *limits)
+{
+	struct msm_rpmrs_resource *rs = &msm_rpmrs_vdd_mem;
+	uint32_t *buf = &msm_rpmrs_buffer[rs->rs[0].id];
+
+	if (test_bit(rs->rs[0].id, msm_rpmrs_buffered)) {
+		rs->rs[0].value = *buf;
+		if (vdd_mem_vlevels[limits->vdd_mem] > MSM_RPMRS_VDD(*buf)) {
+			*buf &= ~vdd_mask;
+			*buf |= vdd_mem_vlevels[limits->vdd_mem];
+		}
+
+		if (MSM_RPMRS_DEBUG_OUTPUT & msm_rpmrs_debug_mask)
+			pr_info("%s: vdd %d (0x%x)\n", __func__,
+				MSM_RPMRS_VDD(*buf), MSM_RPMRS_VDD(*buf));
+	}
+}
+
+static void msm_rpmrs_restore_vdd_mem(void)
+{
+	struct msm_rpmrs_resource *rs = &msm_rpmrs_vdd_mem;
+
+	if (test_bit(rs->rs[0].id, msm_rpmrs_buffered))
+		msm_rpmrs_buffer[rs->rs[0].id] = rs->rs[0].value;
+}
+
+static bool msm_rpmrs_vdd_dig_beyond_limits(struct msm_rpmrs_limits *limits)
+{
+	struct msm_rpmrs_resource *rs = &msm_rpmrs_vdd_dig;
+	uint32_t vdd_dig;
+
+	if (test_bit(rs->rs[0].id, msm_rpmrs_buffered)) {
+		uint32_t buffered_value = msm_rpmrs_buffer[rs->rs[0].id];
+
+		if (rs->enable_low_power == 0)
+			vdd_dig = vdd_dig_vlevels[MSM_RPMRS_VDD_DIG_ACTIVE];
+		else if (rs->enable_low_power == 1)
+			vdd_dig = vdd_dig_vlevels[MSM_RPMRS_VDD_DIG_RET_HIGH];
+		else
+			vdd_dig = vdd_dig_vlevels[MSM_RPMRS_VDD_DIG_RET_LOW];
+
+		if (MSM_RPMRS_VDD(buffered_value) > MSM_RPMRS_VDD(vdd_dig))
+			vdd_dig = MSM_RPMRS_VDD(buffered_value);
+	} else {
+		vdd_dig = vdd_dig_vlevels[MSM_RPMRS_VDD_DIG_ACTIVE];
+	}
+
+	return vdd_dig > vdd_dig_vlevels[limits->vdd_dig_upper_bound];
+}
+
+static void msm_rpmrs_aggregate_vdd_dig(struct msm_rpmrs_limits *limits)
+{
+	struct msm_rpmrs_resource *rs = &msm_rpmrs_vdd_dig;
+	uint32_t *buf = &msm_rpmrs_buffer[rs->rs[0].id];
+
+	if (test_bit(rs->rs[0].id, msm_rpmrs_buffered)) {
+		rs->rs[0].value = *buf;
+		if (vdd_dig_vlevels[limits->vdd_dig] > MSM_RPMRS_VDD(*buf)) {
+			*buf &= ~vdd_mask;
+			*buf |= vdd_dig_vlevels[limits->vdd_dig];
+		}
+
+
+		if (MSM_RPMRS_DEBUG_OUTPUT & msm_rpmrs_debug_mask)
+			pr_info("%s: vdd %d (0x%x)\n", __func__,
+				MSM_RPMRS_VDD(*buf), MSM_RPMRS_VDD(*buf));
+	}
+}
+
+static void msm_rpmrs_restore_vdd_dig(void)
+{
+	struct msm_rpmrs_resource *rs = &msm_rpmrs_vdd_dig;
+
+	if (test_bit(rs->rs[0].id, msm_rpmrs_buffered))
+		msm_rpmrs_buffer[rs->rs[0].id] = rs->rs[0].value;
+}
+
+/******************************************************************************
+ * Buffering Functions
+ *****************************************************************************/
+
+static bool msm_rpmrs_irqs_detectable(struct msm_rpmrs_limits *limits,
+		bool irqs_detect, bool gpio_detect)
+{
+
+	if (vdd_dig_vlevels[limits->vdd_dig_upper_bound] <=
+			vdd_dig_vlevels[MSM_RPMRS_VDD_DIG_RET_HIGH])
+		return irqs_detect;
+
+	if (limits->pxo == MSM_RPMRS_PXO_OFF)
+		return gpio_detect;
+
+	return true;
+}
+
+static bool msm_rpmrs_use_mpm(struct msm_rpmrs_limits *limits)
+{
+	return (limits->pxo == MSM_RPMRS_PXO_OFF) ||
+		(vdd_dig_vlevels[limits->vdd_dig] <=
+		 vdd_dig_vlevels[MSM_RPMRS_VDD_DIG_RET_HIGH]);
+}
+
+static void msm_rpmrs_update_levels(void)
+{
+	int i, k;
+
+	for (i = 0; i < msm_rpmrs_level_count; i++) {
+		struct msm_rpmrs_level *level = &msm_rpmrs_levels[i];
+
+		if (level->sleep_mode != MSM_PM_SLEEP_MODE_POWER_COLLAPSE)
+			continue;
+
+		level->available = true;
+
+		for (k = 0; k < ARRAY_SIZE(msm_rpmrs_resources); k++) {
+			struct msm_rpmrs_resource *rs = msm_rpmrs_resources[k];
+
+			if (rs->beyond_limits &&
+					rs->beyond_limits(&level->rs_limits)) {
+				level->available = false;
+				break;
+			}
+		}
+
+	}
+}
+
+/*
+ * Return value:
+ *   0: no entries in <req> is on our resource list
+ *   1: one or more entries in <req> is on our resource list
+ *   -EINVAL: invalid id in <req> array
+ */
+static int msm_rpmrs_buffer_request(struct msm_rpm_iv_pair *req, int count)
+{
+	bool listed;
+	int i;
+
+	for (i = 0; i < count; i++)
+		if (req[i].id >= MSM_RPM_ID_LAST)
+			return -EINVAL;
+
+	for (i = 0, listed = false; i < count; i++) {
+		msm_rpmrs_buffer[req[i].id] = req[i].value;
+		set_bit(req[i].id, msm_rpmrs_buffered);
+
+		if (MSM_RPMRS_DEBUG_BUFFER & msm_rpmrs_debug_mask)
+			pr_info("%s: reg %d: 0x%x\n",
+				__func__, req[i].id, req[i].value);
+
+		if (listed)
+			continue;
+
+		if (test_bit(req[i].id, msm_rpmrs_listed))
+			listed = true;
+	}
+
+	return listed ? 1 : 0;
+}
+
+/*
+ * Return value:
+ *   0: no entries in <req> is on our resource list
+ *   1: one or more entries in <req> is on our resource list
+ *   -EINVAL: invalid id in <req> array
+ */
+static int msm_rpmrs_clear_buffer(struct msm_rpm_iv_pair *req, int count)
+{
+	bool listed;
+	int i;
+
+	for (i = 0; i < count; i++)
+		if (req[i].id >= MSM_RPM_ID_LAST)
+			return -EINVAL;
+
+	for (i = 0, listed = false; i < count; i++) {
+		msm_rpmrs_buffer[req[i].id] = 0;
+		clear_bit(req[i].id, msm_rpmrs_buffered);
+
+		if (MSM_RPMRS_DEBUG_BUFFER & msm_rpmrs_debug_mask)
+			pr_info("%s: reg %d\n", __func__, req[i].id);
+
+		if (listed)
+			continue;
+
+		if (test_bit(req[i].id, msm_rpmrs_listed))
+			listed = true;
+	}
+
+	return listed ? 1 : 0;
+}
+
+#ifdef CONFIG_MSM_L2_SPM
+static int msm_rpmrs_flush_L2(struct msm_rpmrs_limits *limits, int notify_rpm)
+{
+	int rc = 0;
+	int lpm;
+
+	switch (limits->l2_cache) {
+	case MSM_RPMRS_L2_CACHE_HSFS_OPEN:
+		lpm = MSM_SPM_L2_MODE_POWER_COLLAPSE;
+		msm_pm_set_l2_flush_flag(1);
+		break;
+	case MSM_RPMRS_L2_CACHE_GDHS:
+		lpm = MSM_SPM_L2_MODE_GDHS;
+		break;
+	case MSM_RPMRS_L2_CACHE_RETENTION:
+		lpm = MSM_SPM_L2_MODE_RETENTION;
+		break;
+	default:
+	case MSM_RPMRS_L2_CACHE_ACTIVE:
+		lpm = MSM_SPM_L2_MODE_DISABLED;
+		break;
+	}
+
+	rc = msm_spm_l2_set_low_power_mode(lpm, notify_rpm);
+	if (MSM_RPMRS_DEBUG_BUFFER & msm_rpmrs_debug_mask)
+		pr_info("%s: Requesting low power mode %d returned %d\n",
+				__func__, lpm, rc);
+
+	return rc;
+}
+static void msm_rpmrs_L2_restore(struct msm_rpmrs_limits *limits,
+		bool notify_rpm, bool collapsed)
+{
+	msm_spm_l2_set_low_power_mode(MSM_SPM_MODE_DISABLED, notify_rpm);
+	msm_pm_set_l2_flush_flag(0);
+}
+#else
+static int msm_rpmrs_flush_L2(struct msm_rpmrs_limits *limits, int notify_rpm)
+{
+	return 0;
+}
+static void msm_rpmrs_L2_restore(struct msm_rpmrs_limits *limits,
+		bool notify_rpm, bool collapsed)
+{
+}
+#endif
+
+static int msm_rpmrs_flush_buffer(
+	uint32_t sclk_count, struct msm_rpmrs_limits *limits, int from_idle)
+{
+	struct msm_rpm_iv_pair *req;
+	int count;
+	int rc;
+	int i;
+
+	msm_rpmrs_aggregate_sclk(sclk_count);
+	for (i = 0; i < ARRAY_SIZE(msm_rpmrs_resources); i++) {
+		if (msm_rpmrs_resources[i]->aggregate)
+			msm_rpmrs_resources[i]->aggregate(limits);
+	}
+
+	count = bitmap_weight(msm_rpmrs_buffered, MSM_RPM_ID_LAST);
+
+	req = kmalloc(sizeof(*req) * count, GFP_ATOMIC);
+	if (!req) {
+		rc = -ENOMEM;
+		goto flush_buffer_restore;
+	}
+
+	count = 0;
+	i = find_first_bit(msm_rpmrs_buffered, MSM_RPM_ID_LAST);
+
+	while (i < MSM_RPM_ID_LAST) {
+		if (MSM_RPMRS_DEBUG_OUTPUT & msm_rpmrs_debug_mask)
+			pr_info("%s: reg %d: 0x%x\n",
+				__func__, i, msm_rpmrs_buffer[i]);
+
+		req[count].id = i;
+		req[count].value = msm_rpmrs_buffer[i];
+		count++;
+
+		i = find_next_bit(msm_rpmrs_buffered, MSM_RPM_ID_LAST, i + 1);
+	}
+
+	rc = msm_rpm_set_noirq(MSM_RPM_CTX_SET_SLEEP, req, count);
+	kfree(req);
+
+	if (rc)
+		goto flush_buffer_restore;
+
+	bitmap_and(msm_rpmrs_buffered,
+		msm_rpmrs_buffered, msm_rpmrs_listed, MSM_RPM_ID_LAST);
+
+flush_buffer_restore:
+	for (i = 0; i < ARRAY_SIZE(msm_rpmrs_resources); i++) {
+		if (msm_rpmrs_resources[i]->restore)
+			msm_rpmrs_resources[i]->restore();
+	}
+	msm_rpmrs_restore_sclk();
+
+	if (rc)
+		pr_err("%s: failed: %d\n", __func__, rc);
+	return rc;
+}
+
+static int msm_rpmrs_set_common(
+	int ctx, struct msm_rpm_iv_pair *req, int count, bool noirq)
+{
+	if (ctx == MSM_RPM_CTX_SET_SLEEP) {
+		unsigned long flags;
+		int rc;
+
+		spin_lock_irqsave(&msm_rpmrs_lock, flags);
+		rc = msm_rpmrs_buffer_request(req, count);
+		if (rc > 0) {
+			msm_rpmrs_update_levels();
+			rc = 0;
+		}
+		spin_unlock_irqrestore(&msm_rpmrs_lock, flags);
+
+		return rc;
+	}
+
+	if (noirq)
+		return msm_rpm_set_noirq(ctx, req, count);
+	else
+		return msm_rpm_set(ctx, req, count);
+}
+
+static int msm_rpmrs_clear_common(
+	int ctx, struct msm_rpm_iv_pair *req, int count, bool noirq)
+{
+	if (ctx == MSM_RPM_CTX_SET_SLEEP) {
+		unsigned long flags;
+		int rc;
+
+		spin_lock_irqsave(&msm_rpmrs_lock, flags);
+		rc = msm_rpmrs_clear_buffer(req, count);
+		if (rc > 0) {
+			msm_rpmrs_update_levels();
+			rc = 0;
+		}
+		spin_unlock_irqrestore(&msm_rpmrs_lock, flags);
+
+		if (rc < 0)
+			return rc;
+	}
+
+	if (noirq)
+		return msm_rpm_clear_noirq(ctx, req, count);
+	else
+		return msm_rpm_clear(ctx, req, count);
+}
+
+/******************************************************************************
+ * Attribute Functions
+ *****************************************************************************/
+
+static ssize_t msm_rpmrs_resource_attr_show(
+	struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	struct kernel_param kp;
+	unsigned long flags;
+	unsigned int temp;
+	int rc;
+
+	spin_lock_irqsave(&msm_rpmrs_lock, flags);
+	/* special case active-set signal for MSM_RPMRS_ID_RPM_CTL */
+	if (GET_RS_FROM_ATTR(attr)->rs[0].id ==
+			msm_rpmrs_rpm_ctl.rs[0].id)
+		temp = GET_RS_FROM_ATTR(attr)->rs[0].value;
+	else
+		temp = GET_RS_FROM_ATTR(attr)->enable_low_power;
+	spin_unlock_irqrestore(&msm_rpmrs_lock, flags);
+
+	kp.arg = &temp;
+	rc = param_get_uint(buf, &kp);
+
+	if (rc > 0) {
+		strlcat(buf, "\n", PAGE_SIZE);
+		rc++;
+	}
+
+	return rc;
+}
+
+static ssize_t msm_rpmrs_resource_attr_store(struct kobject *kobj,
+	struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	struct kernel_param kp;
+	unsigned long flags;
+	unsigned int temp;
+	int rc;
+
+	kp.arg = &temp;
+	rc = param_set_uint(buf, &kp);
+	if (rc)
+		return rc;
+
+	spin_lock_irqsave(&msm_rpmrs_lock, flags);
+	GET_RS_FROM_ATTR(attr)->enable_low_power = temp;
+
+	/* special case active-set signal for MSM_RPMRS_ID_RPM_CTL */
+	if (GET_RS_FROM_ATTR(attr)->rs[0].id ==
+			msm_rpmrs_rpm_ctl.rs[0].id) {
+		struct msm_rpm_iv_pair req;
+		req.id = msm_rpmrs_rpm_ctl.rs[0].id;
+		req.value = GET_RS_FROM_ATTR(attr)->enable_low_power;
+		GET_RS_FROM_ATTR(attr)->rs[0].value = req.value;
+
+		rc = msm_rpm_set_noirq(MSM_RPM_CTX_SET_0, &req, 1);
+		if (rc) {
+			pr_err("%s: failed to request RPM_CTL to %d: %d\n",
+				__func__, req.value, rc);
+		}
+	}
+
+	msm_rpmrs_update_levels();
+	spin_unlock_irqrestore(&msm_rpmrs_lock, flags);
+
+	return count;
+}
+
+static int __init msm_rpmrs_resource_sysfs_add(void)
+{
+	struct kobject *module_kobj = NULL;
+	struct kobject *low_power_kobj = NULL;
+	struct kobject *mode_kobj = NULL;
+	int rc = 0;
+
+	module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
+	if (!module_kobj) {
+		pr_err("%s: cannot find kobject for module %s\n",
+			__func__, KBUILD_MODNAME);
+		rc = -ENOENT;
+		goto resource_sysfs_add_exit;
+	}
+
+	low_power_kobj = kobject_create_and_add(
+				"enable_low_power", module_kobj);
+	if (!low_power_kobj) {
+		pr_err("%s: cannot create kobject\n", __func__);
+		rc = -ENOMEM;
+		goto resource_sysfs_add_exit;
+	}
+
+	mode_kobj = kobject_create_and_add(
+				"mode", module_kobj);
+	if (!mode_kobj) {
+		pr_err("%s: cannot create kobject\n", __func__);
+		rc = -ENOMEM;
+		goto resource_sysfs_add_exit;
+	}
+
+	rc = sysfs_create_group(low_power_kobj, &msm_rpmrs_attribute_group);
+	if (rc) {
+		pr_err("%s: cannot create kobject attribute group\n", __func__);
+		goto resource_sysfs_add_exit;
+	}
+
+	rc = sysfs_create_group(mode_kobj, &msm_rpmrs_mode_attribute_group);
+	if (rc) {
+		pr_err("%s: cannot create kobject attribute group\n", __func__);
+		goto resource_sysfs_add_exit;
+	}
+
+	rc = 0;
+resource_sysfs_add_exit:
+	if (rc) {
+		if (low_power_kobj)
+			sysfs_remove_group(low_power_kobj,
+					&msm_rpmrs_attribute_group);
+		kobject_del(low_power_kobj);
+		kobject_del(mode_kobj);
+	}
+
+	return rc;
+}
+
+/******************************************************************************
+ * Public Functions
+ *****************************************************************************/
+
+int msm_rpmrs_set(int ctx, struct msm_rpm_iv_pair *req, int count)
+{
+	return msm_rpmrs_set_common(ctx, req, count, false);
+}
+
+int msm_rpmrs_set_noirq(int ctx, struct msm_rpm_iv_pair *req, int count)
+{
+	WARN(!irqs_disabled(), "msm_rpmrs_set_noirq can only be called "
+		"safely when local irqs are disabled.  Consider using "
+		"msm_rpmrs_set or msm_rpmrs_set_nosleep instead.");
+	return msm_rpmrs_set_common(ctx, req, count, true);
+}
+
+/* Allow individual bits of an rpm resource be set, currently used only for
+ * active context resource viz. RPM_CTL. The API is generic enough to possibly
+ * extend it to other resources as well in the future.
+ */
+int msm_rpmrs_set_bits_noirq(int ctx, struct msm_rpm_iv_pair *req, int count,
+		int *mask)
+{
+	unsigned long flags;
+	int i, j;
+	int rc = -1;
+	struct msm_rpmrs_resource *rs;
+
+	if (ctx != MSM_RPM_CTX_SET_0)
+		return -ENOSYS;
+
+	spin_lock_irqsave(&msm_rpmrs_lock, flags);
+	for (i = 0; i < ARRAY_SIZE(msm_rpmrs_resources); i++) {
+		rs = msm_rpmrs_resources[i];
+		if (rs->rs[0].id == req[0].id && rs->size == count) {
+			for (j = 0; j < rs->size; j++) {
+				rs->rs[j].value &= ~mask[j];
+				rs->rs[j].value |= req[j].value & mask[j];
+			}
+			break;
+		}
+	}
+
+	if (i != ARRAY_SIZE(msm_rpmrs_resources)) {
+		rc = msm_rpm_set_noirq(MSM_RPM_CTX_SET_0, &rs->rs[0], rs->size);
+		if (rc) {
+			for (j = 0; j < rs->size; j++) {
+				pr_err("%s: failed to request %d to %d: %d\n",
+				__func__,
+				rs->rs[j].id, rs->rs[j].value, rc);
+			}
+		}
+	}
+	spin_unlock_irqrestore(&msm_rpmrs_lock, flags);
+
+	return rc;
+
+}
+
+int msm_rpmrs_clear(int ctx, struct msm_rpm_iv_pair *req, int count)
+{
+	return msm_rpmrs_clear_common(ctx, req, count, false);
+}
+
+int msm_rpmrs_clear_noirq(int ctx, struct msm_rpm_iv_pair *req, int count)
+{
+	WARN(!irqs_disabled(), "msm_rpmrs_clear_noirq can only be called "
+		"safely when local irqs are disabled.  Consider using "
+		"msm_rpmrs_clear or msm_rpmrs_clear_nosleep instead.");
+	return msm_rpmrs_clear_common(ctx, req, count, true);
+}
+
+void msm_rpmrs_show_resources(void)
+{
+	struct msm_rpmrs_resource *rs;
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&msm_rpmrs_lock, flags);
+	for (i = 0; i < ARRAY_SIZE(msm_rpmrs_resources); i++) {
+		rs = msm_rpmrs_resources[i];
+		if (rs->rs[0].id < MSM_RPM_ID_LAST)
+			pr_info("%s: resource %s: buffered %d, value 0x%x\n",
+				__func__, rs->name,
+				test_bit(rs->rs[0].id, msm_rpmrs_buffered),
+				msm_rpmrs_buffer[rs->rs[0].id]);
+		else
+			pr_info("%s: resource %s: value %d\n",
+				__func__, rs->name, rs->rs[0].value);
+	}
+	spin_unlock_irqrestore(&msm_rpmrs_lock, flags);
+}
+
+static void *msm_rpmrs_lowest_limits(bool from_idle,
+		enum msm_pm_sleep_mode sleep_mode, uint32_t latency_us,
+		uint32_t sleep_us, uint32_t *power)
+{
+	unsigned int cpu = smp_processor_id();
+	struct msm_rpmrs_level *best_level = NULL;
+	bool irqs_detectable = false;
+	bool gpio_detectable = false;
+	int i;
+	uint32_t pwr;
+
+	if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) {
+		irqs_detectable = msm_mpm_irqs_detectable(from_idle);
+		gpio_detectable = msm_mpm_gpio_irqs_detectable(from_idle);
+	}
+
+	for (i = 0; i < msm_rpmrs_level_count; i++) {
+		struct msm_rpmrs_level *level = &msm_rpmrs_levels[i];
+
+		if (!level->available)
+			continue;
+
+		if (sleep_mode != level->sleep_mode)
+			continue;
+
+		if (latency_us < level->latency_us)
+			continue;
+
+		if (sleep_us <= level->time_overhead_us)
+			continue;
+
+		if (!msm_rpmrs_irqs_detectable(&level->rs_limits,
+					irqs_detectable, gpio_detectable))
+			continue;
+
+		if (MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE == sleep_mode)
+			if (!cpu && msm_rpm_local_request_is_outstanding())
+					break;
+
+
+		if (sleep_us <= 1) {
+			pwr = level->energy_overhead;
+		} else if (sleep_us <= level->time_overhead_us) {
+			pwr = level->energy_overhead / sleep_us;
+		} else if ((sleep_us >> 10) > level->time_overhead_us) {
+			pwr = level->steady_state_power;
+		} else {
+			pwr = level->steady_state_power;
+			pwr -= (level->time_overhead_us *
+					level->steady_state_power)/sleep_us;
+			pwr += level->energy_overhead / sleep_us;
+		}
+
+		if (!best_level ||
+				best_level->rs_limits.power[cpu] >= pwr) {
+			level->rs_limits.latency_us[cpu] = level->latency_us;
+			level->rs_limits.power[cpu] = pwr;
+			best_level = level;
+			if (power)
+				*power = pwr;
+		}
+	}
+
+	return best_level ? &best_level->rs_limits : NULL;
+}
+
+static int msm_rpmrs_enter_sleep(uint32_t sclk_count, void *limits,
+		bool from_idle, bool notify_rpm)
+{
+	int rc = 0;
+
+	if (notify_rpm) {
+		rc = msm_rpmrs_flush_buffer(sclk_count, limits, from_idle);
+		if (rc)
+			return rc;
+
+		if (msm_rpmrs_use_mpm(limits))
+			msm_mpm_enter_sleep(from_idle);
+	}
+
+	rc = msm_rpmrs_flush_L2(limits, notify_rpm);
+	return rc;
+}
+
+static void msm_rpmrs_exit_sleep(void *limits, bool from_idle,
+		bool notify_rpm, bool collapsed)
+{
+
+	/* Disable L2 for now, we dont want L2 to do retention by default */
+	msm_rpmrs_L2_restore(limits, notify_rpm, collapsed);
+
+	if (msm_rpmrs_use_mpm(limits))
+		msm_mpm_exit_sleep(from_idle);
+}
+
+static int rpmrs_cpu_callback(struct notifier_block *nfb,
+		unsigned long action, void *hcpu)
+{
+	switch (action) {
+	case CPU_ONLINE_FROZEN:
+	case CPU_ONLINE:
+		if (num_online_cpus() > 1)
+			msm_rpmrs_l2_cache.rs[0].value =
+				MSM_RPMRS_L2_CACHE_ACTIVE;
+		break;
+	case CPU_DEAD_FROZEN:
+	case CPU_DEAD:
+		if (num_online_cpus() == 1)
+			msm_rpmrs_l2_cache.rs[0].value =
+				MSM_RPMRS_L2_CACHE_HSFS_OPEN;
+		break;
+	}
+
+	msm_rpmrs_update_levels();
+	return NOTIFY_OK;
+}
+
+static struct notifier_block __refdata rpmrs_cpu_notifier = {
+	.notifier_call = rpmrs_cpu_callback,
+};
+
+int __init msm_rpmrs_levels_init(struct msm_rpmrs_platform_data *data)
+{
+	int i, k;
+	struct msm_rpmrs_level *levels = data->levels;
+
+	msm_rpmrs_level_count = data->num_levels;
+
+	msm_rpmrs_levels = kzalloc(sizeof(struct msm_rpmrs_level) *
+			msm_rpmrs_level_count, GFP_KERNEL);
+	if (!msm_rpmrs_levels)
+		return -ENOMEM;
+
+	memcpy(msm_rpmrs_levels, levels,
+			msm_rpmrs_level_count * sizeof(struct msm_rpmrs_level));
+
+	memcpy(vdd_dig_vlevels, data->vdd_dig_levels,
+		(MSM_RPMRS_VDD_DIG_MAX + 1) * sizeof(vdd_dig_vlevels[0]));
+
+	memcpy(vdd_mem_vlevels, data->vdd_mem_levels,
+		(MSM_RPMRS_VDD_MEM_MAX + 1) * sizeof(vdd_mem_vlevels[0]));
+	vdd_mask = data->vdd_mask;
+
+	msm_rpmrs_pxo.rs[0].id = data->rpmrs_target_id[MSM_RPMRS_ID_PXO_CLK];
+	msm_rpmrs_l2_cache.rs[0].id =
+			data->rpmrs_target_id[MSM_RPMRS_ID_L2_CACHE_CTL];
+	msm_rpmrs_vdd_mem.rs[0].id =
+			data->rpmrs_target_id[MSM_RPMRS_ID_VDD_MEM_0];
+	msm_rpmrs_vdd_mem.rs[1].id =
+			data->rpmrs_target_id[MSM_RPMRS_ID_VDD_MEM_1];
+	msm_rpmrs_vdd_dig.rs[0].id =
+			data->rpmrs_target_id[MSM_RPMRS_ID_VDD_DIG_0];
+	msm_rpmrs_vdd_dig.rs[1].id =
+			data->rpmrs_target_id[MSM_RPMRS_ID_VDD_DIG_1];
+	msm_rpmrs_rpm_ctl.rs[0].id =
+			data->rpmrs_target_id[MSM_RPMRS_ID_RPM_CTL];
+
+	/* Initialize listed bitmap for valid resource IDs */
+	for (i = 0; i < ARRAY_SIZE(msm_rpmrs_resources); i++) {
+		for (k = 0; k < msm_rpmrs_resources[i]->size; k++) {
+			if (msm_rpmrs_resources[i]->rs[k].id >=
+					MSM_RPM_ID_LAST)
+				continue;
+			set_bit(msm_rpmrs_resources[i]->rs[k].id,
+				msm_rpmrs_listed);
+		}
+	}
+
+	return 0;
+}
+
+static int __init msm_rpmrs_init(void)
+{
+	struct msm_rpm_iv_pair req;
+	int rc;
+
+	BUG_ON(!msm_rpmrs_levels);
+
+	if (cpu_is_msm8x60()) {
+		req.id = msm_rpmrs_l2_cache.rs[0].id;
+		req.value = 1;
+
+		rc = msm_rpm_set(MSM_RPM_CTX_SET_0, &req, 1);
+		if (rc) {
+			pr_err("%s: failed to request L2 cache: %d\n",
+				__func__, rc);
+			goto init_exit;
+		}
+
+		req.id = msm_rpmrs_l2_cache.rs[0].id;
+		req.value = 0;
+
+		rc = msm_rpmrs_set(MSM_RPM_CTX_SET_SLEEP, &req, 1);
+		if (rc) {
+			pr_err("%s: failed to initialize L2 cache for sleep: "
+				"%d\n", __func__, rc);
+			goto init_exit;
+		}
+	}
+
+	rc = msm_rpmrs_resource_sysfs_add();
+
+init_exit:
+	return rc;
+}
+device_initcall(msm_rpmrs_init);
+
+static struct msm_pm_sleep_ops msm_rpmrs_ops = {
+	.lowest_limits = msm_rpmrs_lowest_limits,
+	.enter_sleep = msm_rpmrs_enter_sleep,
+	.exit_sleep = msm_rpmrs_exit_sleep,
+};
+
+static int __init msm_rpmrs_l2_init(void)
+{
+	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_apq8064()) {
+
+		msm_pm_set_l2_flush_flag(0);
+
+		msm_rpmrs_l2_cache.beyond_limits =
+			msm_spm_l2_cache_beyond_limits;
+		msm_rpmrs_l2_cache.aggregate = NULL;
+		msm_rpmrs_l2_cache.restore = NULL;
+
+		register_hotcpu_notifier(&rpmrs_cpu_notifier);
+
+	} else if (cpu_is_msm9615()) {
+		msm_rpmrs_l2_cache.beyond_limits = NULL;
+		msm_rpmrs_l2_cache.aggregate = NULL;
+		msm_rpmrs_l2_cache.restore = NULL;
+	}
+
+	msm_pm_set_sleep_ops(&msm_rpmrs_ops);
+
+	return 0;
+}
+early_initcall(msm_rpmrs_l2_init);
diff --git a/arch/arm/mach-msm/rpm_resources.h b/arch/arm/mach-msm/rpm_resources.h
new file mode 100644
index 0000000..d594405
--- /dev/null
+++ b/arch/arm/mach-msm/rpm_resources.h
@@ -0,0 +1,142 @@
+/* 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
+ * 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 __ARCH_ARM_MACH_MSM_RPM_RESOURCES_H
+#define __ARCH_ARM_MACH_MSM_RPM_RESOURCES_H
+
+#include <mach/rpm.h>
+#include "pm.h"
+
+enum {
+	MSM_RPMRS_ID_PXO_CLK = 0,
+	MSM_RPMRS_ID_L2_CACHE_CTL = 1,
+	MSM_RPMRS_ID_VDD_DIG_0 = 2,
+	MSM_RPMRS_ID_VDD_DIG_1 = 3,
+	MSM_RPMRS_ID_VDD_MEM_0 = 4,
+	MSM_RPMRS_ID_VDD_MEM_1 = 5,
+	MSM_RPMRS_ID_RPM_CTL = 6,
+	MSM_RPMRS_ID_LAST,
+};
+
+enum {
+	MSM_RPMRS_PXO_OFF = 0,
+	MSM_RPMRS_PXO_ON = 1,
+};
+
+enum {
+	MSM_RPMRS_L2_CACHE_HSFS_OPEN = 0,
+	MSM_RPMRS_L2_CACHE_GDHS = 1,
+	MSM_RPMRS_L2_CACHE_RETENTION = 2,
+	MSM_RPMRS_L2_CACHE_ACTIVE = 3,
+};
+
+enum {
+	MSM_RPMRS_MASK_RPM_CTL_CPU_HALT = 1,
+	MSM_RPMRS_MASK_RPM_CTL_MULTI_TIER = 2,
+};
+
+enum {
+	MSM_RPMRS_VDD_MEM_RET_LOW = 0,
+	MSM_RPMRS_VDD_MEM_RET_HIGH = 1,
+	MSM_RPMRS_VDD_MEM_ACTIVE = 2,
+	MSM_RPMRS_VDD_MEM_MAX = 3,
+	MSM_RPMRS_VDD_MEM_LAST,
+};
+
+enum {
+	MSM_RPMRS_VDD_DIG_RET_LOW = 0,
+	MSM_RPMRS_VDD_DIG_RET_HIGH = 1,
+	MSM_RPMRS_VDD_DIG_ACTIVE = 2,
+	MSM_RPMRS_VDD_DIG_MAX = 3,
+	MSM_RPMRS_VDD_DIG_LAST,
+};
+
+#define MSM_RPMRS_LIMITS(_pxo, _l2, _vdd_upper_b, _vdd) { \
+	MSM_RPMRS_PXO_##_pxo, \
+	MSM_RPMRS_L2_CACHE_##_l2, \
+	MSM_RPMRS_VDD_MEM_##_vdd_upper_b, \
+	MSM_RPMRS_VDD_MEM_##_vdd, \
+	MSM_RPMRS_VDD_DIG_##_vdd_upper_b, \
+	MSM_RPMRS_VDD_DIG_##_vdd, \
+	{0}, {0}, \
+}
+
+struct msm_rpmrs_limits {
+	uint32_t pxo;
+	uint32_t l2_cache;
+	uint32_t vdd_mem_upper_bound;
+	uint32_t vdd_mem;
+	uint32_t vdd_dig_upper_bound;
+	uint32_t vdd_dig;
+
+	uint32_t latency_us[NR_CPUS];
+	uint32_t power[NR_CPUS];
+};
+
+struct msm_rpmrs_level {
+	enum msm_pm_sleep_mode sleep_mode;
+	struct msm_rpmrs_limits rs_limits;
+	bool available;
+	uint32_t latency_us;
+	uint32_t steady_state_power;
+	uint32_t energy_overhead;
+	uint32_t time_overhead_us;
+};
+
+struct msm_rpmrs_platform_data {
+	struct msm_rpmrs_level *levels;
+	unsigned int num_levels;
+	unsigned int vdd_mem_levels[MSM_RPMRS_VDD_MEM_LAST];
+	unsigned int vdd_dig_levels[MSM_RPMRS_VDD_DIG_LAST];
+	unsigned int vdd_mask;
+	unsigned int rpmrs_target_id[MSM_RPMRS_ID_LAST];
+};
+
+int msm_rpmrs_set(int ctx, struct msm_rpm_iv_pair *req, int count);
+int msm_rpmrs_set_noirq(int ctx, struct msm_rpm_iv_pair *req, int count);
+int msm_rpmrs_set_bits_noirq(int ctx, struct msm_rpm_iv_pair *req, int count,
+			int *mask);
+
+static inline int msm_rpmrs_set_nosleep(
+	int ctx, struct msm_rpm_iv_pair *req, int count)
+{
+	unsigned long flags;
+	int rc;
+
+	local_irq_save(flags);
+	rc = msm_rpmrs_set_noirq(ctx, req, count);
+	local_irq_restore(flags);
+
+	return rc;
+}
+
+int msm_rpmrs_clear(int ctx, struct msm_rpm_iv_pair *req, int count);
+int msm_rpmrs_clear_noirq(int ctx, struct msm_rpm_iv_pair *req, int count);
+
+static inline int msm_rpmrs_clear_nosleep(
+	int ctx, struct msm_rpm_iv_pair *req, int count)
+{
+	unsigned long flags;
+	int rc;
+
+	local_irq_save(flags);
+	rc = msm_rpmrs_clear_noirq(ctx, req, count);
+	local_irq_restore(flags);
+
+	return rc;
+}
+
+void msm_rpmrs_show_resources(void);
+int msm_rpmrs_levels_init(struct msm_rpmrs_platform_data *data);
+
+#endif /* __ARCH_ARM_MACH_MSM_RPM_RESOURCES_H */
diff --git a/arch/arm/mach-msm/rpm_stats.c b/arch/arm/mach-msm/rpm_stats.c
new file mode 100644
index 0000000..a831bd5
--- /dev/null
+++ b/arch/arm/mach-msm/rpm_stats.c
@@ -0,0 +1,247 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <asm/uaccess.h>
+
+#include <mach/msm_iomap.h>
+#include "rpm_stats.h"
+
+enum {
+	ID_COUNTER,
+	ID_ACCUM_TIME_SCLK,
+	ID_MAX,
+};
+
+static char *msm_rpmstats_id_labels[ID_MAX] = {
+	[ID_COUNTER] = "Count",
+	[ID_ACCUM_TIME_SCLK] = "Total time(uSec)",
+};
+
+#define SCLK_HZ 32768
+struct msm_rpmstats_record{
+	char		name[32];
+	uint32_t	id;
+	uint32_t	val;
+};
+
+struct msm_rpmstats_private_data{
+	void __iomem *reg_base;
+	u32 num_records;
+	u32 read_idx;
+	u32 len;
+	char buf[128];
+	struct msm_rpmstats_platform_data *platform_data;
+};
+
+static inline unsigned long  msm_rpmstats_read_register(void __iomem *regbase,
+		int index, int offset)
+{
+	return  readl_relaxed(regbase + index * 12 + (offset + 1) * 4);
+}
+static void msm_rpmstats_strcpy(char *dest, char  *src)
+{
+	union {
+		char ch[4];
+		unsigned long word;
+	} string;
+	int index = 0;
+
+	do  {
+		int i;
+		string.word = readl_relaxed(src + 4 * index);
+		for (i = 0; i < 4; i++) {
+			*dest++ = string.ch[i];
+			if (!string.ch[i])
+				break;
+		}
+		index++;
+	} while (*(dest-1));
+
+}
+static int msm_rpmstats_copy_stats(struct msm_rpmstats_private_data *pdata)
+{
+
+	struct msm_rpmstats_record record;
+	unsigned long ptr;
+	unsigned long offset;
+	char *str;
+	uint64_t usec;
+
+	ptr = msm_rpmstats_read_register(pdata->reg_base, pdata->read_idx, 0);
+	offset = (ptr - (unsigned long)pdata->platform_data->phys_addr_base);
+
+	if (offset > pdata->platform_data->phys_size)
+		str = (char *)ioremap(ptr, SZ_256);
+	else
+		str = (char *) pdata->reg_base + offset;
+
+	msm_rpmstats_strcpy(record.name, str);
+
+	if (offset > pdata->platform_data->phys_size)
+		iounmap(str);
+
+	record.id = msm_rpmstats_read_register(pdata->reg_base,
+						pdata->read_idx, 1);
+	record.val = msm_rpmstats_read_register(pdata->reg_base,
+						pdata->read_idx, 2);
+
+	if (record.id == ID_ACCUM_TIME_SCLK) {
+		usec = record.val * USEC_PER_SEC;
+		do_div(usec, SCLK_HZ);
+	}  else
+		usec = (unsigned long)record.val;
+
+	pdata->read_idx++;
+
+	return snprintf(pdata->buf, sizeof(pdata->buf),
+			"RPM Mode:%s\n\t%s:%llu\n",
+			record.name,
+			msm_rpmstats_id_labels[record.id],
+			usec);
+}
+
+static int msm_rpmstats_file_read(struct file *file, char __user *bufu,
+				  size_t count, loff_t *ppos)
+{
+	struct msm_rpmstats_private_data *prvdata;
+	prvdata = file->private_data;
+
+	if (!prvdata)
+		return -EINVAL;
+
+	if (!bufu || count < 0)
+		return -EINVAL;
+
+	if (!prvdata->num_records)
+		prvdata->num_records = readl_relaxed(prvdata->reg_base);
+
+	if ((*ppos >= prvdata->len)
+			&& (prvdata->read_idx < prvdata->num_records)) {
+		prvdata->len = msm_rpmstats_copy_stats(prvdata);
+		*ppos = 0;
+	}
+
+	return simple_read_from_buffer(bufu, count, ppos,
+			prvdata->buf, prvdata->len);
+}
+
+static int msm_rpmstats_file_open(struct inode *inode, struct file *file)
+{
+	struct msm_rpmstats_private_data *prvdata;
+	struct msm_rpmstats_platform_data *pdata;
+
+	pdata = inode->i_private;
+
+	file->private_data =
+		kmalloc(sizeof(struct msm_rpmstats_private_data), GFP_KERNEL);
+
+	if (!file->private_data)
+		return -ENOMEM;
+	prvdata = file->private_data;
+
+	prvdata->reg_base = ioremap(pdata->phys_addr_base, pdata->phys_size);
+	if (!prvdata->reg_base) {
+		kfree(file->private_data);
+		prvdata = NULL;
+		pr_err("%s: ERROR could not ioremap start=%p, len=%u\n",
+			__func__, (void *)pdata->phys_addr_base,
+			pdata->phys_size);
+		return -EBUSY;
+	}
+
+	prvdata->read_idx = prvdata->num_records =  prvdata->len = 0;
+	prvdata->platform_data = pdata;
+	return 0;
+}
+
+static int msm_rpmstats_file_close(struct inode *inode, struct file *file)
+{
+	struct msm_rpmstats_private_data *private = file->private_data;
+
+	if (private->reg_base)
+		iounmap(private->reg_base);
+	kfree(file->private_data);
+
+	return 0;
+}
+
+static const struct file_operations msm_rpmstats_fops = {
+	.owner	  = THIS_MODULE,
+	.open	  = msm_rpmstats_file_open,
+	.read	  = msm_rpmstats_file_read,
+	.release  = msm_rpmstats_file_close,
+	.llseek   = no_llseek,
+};
+
+static  int __devinit msm_rpmstats_probe(struct platform_device *pdev)
+{
+	struct dentry *dent;
+	struct msm_rpmstats_platform_data *pdata;
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata)
+		return -EINVAL;
+	dent = debugfs_create_file("rpm_stats", S_IRUGO, NULL,
+			pdev->dev.platform_data, &msm_rpmstats_fops);
+
+	if (!dent) {
+		pr_err("%s: ERROR debugfs_create_file failed\n", __func__);
+		return -ENOMEM;
+	}
+	platform_set_drvdata(pdev, dent);
+	return 0;
+}
+
+static int __devexit msm_rpmstats_remove(struct platform_device *pdev)
+{
+	struct dentry *dent;
+
+	dent = platform_get_drvdata(pdev);
+	debugfs_remove(dent);
+	platform_set_drvdata(pdev, NULL);
+	return 0;
+}
+static struct platform_driver msm_rpmstats_driver = {
+	.probe	= msm_rpmstats_probe,
+	.remove = __devexit_p(msm_rpmstats_remove),
+	.driver = {
+		.name = "msm_rpm_stat",
+		.owner = THIS_MODULE,
+	},
+};
+static int __init msm_rpmstats_init(void)
+{
+	return platform_driver_register(&msm_rpmstats_driver);
+}
+static void __exit msm_rpmstats_exit(void)
+{
+	platform_driver_unregister(&msm_rpmstats_driver);
+}
+module_init(msm_rpmstats_init);
+module_exit(msm_rpmstats_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MSM RPM Statistics driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:msm_stat_log");
diff --git a/arch/arm/mach-msm/rpm_stats.h b/arch/arm/mach-msm/rpm_stats.h
new file mode 100644
index 0000000..918d4fb
--- /dev/null
+++ b/arch/arm/mach-msm/rpm_stats.h
@@ -0,0 +1,23 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_RPM_STATS_H
+#define __ARCH_ARM_MACH_MSM_RPM_STATS_H
+
+#include <linux/types.h>
+
+struct msm_rpmstats_platform_data {
+	phys_addr_t phys_addr_base;
+	u32 phys_size;
+};
+#endif
diff --git a/arch/arm/mach-msm/saw-regulator.c b/arch/arm/mach-msm/saw-regulator.c
new file mode 100644
index 0000000..6762648
--- /dev/null
+++ b/arch/arm/mach-msm/saw-regulator.c
@@ -0,0 +1,237 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/pmic8901.h>
+
+#include "spm.h"
+
+#define FTSMPS_VCTRL_BAND_MASK		0xC0
+#define FTSMPS_VCTRL_BAND_1		0x40
+#define FTSMPS_VCTRL_BAND_2		0x80
+#define FTSMPS_VCTRL_BAND_3		0xC0
+#define FTSMPS_VCTRL_VPROG_MASK		0x3F
+
+#define FTSMPS_BAND1_UV_MIN		350000
+#define FTSMPS_BAND1_UV_MAX		650000
+/* 3 LSB's of program voltage must be 0 in band 1. */
+/* Logical step size */
+#define FTSMPS_BAND1_UV_LOG_STEP	50000
+/* Physical step size */
+#define FTSMPS_BAND1_UV_PHYS_STEP	6250
+
+#define FTSMPS_BAND2_UV_MIN		700000
+#define FTSMPS_BAND2_UV_MAX		1400000
+#define FTSMPS_BAND2_UV_STEP		12500
+
+#define FTSMPS_BAND3_UV_MIN		1400000
+#define FTSMPS_BAND3_UV_SET_POINT_MIN	1500000
+#define FTSMPS_BAND3_UV_MAX		3300000
+#define FTSMPS_BAND3_UV_STEP		50000
+
+struct saw_vreg {
+	struct regulator_desc		desc;
+	struct regulator_dev		*rdev;
+	char				*name;
+	int				uV;
+};
+
+/* Minimum core operating voltage */
+#define MIN_CORE_VOLTAGE		950000
+
+/* Specifies the PMIC internal slew rate in uV/us. */
+#define REGULATOR_SLEW_RATE		1250
+
+static int saw_get_voltage(struct regulator_dev *rdev)
+{
+	struct saw_vreg *vreg = rdev_get_drvdata(rdev);
+
+	return vreg->uV;
+}
+
+static int saw_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
+			   unsigned *selector)
+{
+	struct saw_vreg *vreg = rdev_get_drvdata(rdev);
+	int uV = min_uV;
+	int rc;
+	u8 vprog, band;
+
+	if (uV < FTSMPS_BAND1_UV_MIN && max_uV >= FTSMPS_BAND1_UV_MIN)
+		uV = FTSMPS_BAND1_UV_MIN;
+
+	if (uV < FTSMPS_BAND1_UV_MIN || uV > FTSMPS_BAND3_UV_MAX) {
+		pr_err("%s: request v=[%d, %d] is outside possible "
+			"v=[%d, %d]\n", vreg->name, min_uV, max_uV,
+			FTSMPS_BAND1_UV_MIN, FTSMPS_BAND3_UV_MAX);
+		return -EINVAL;
+	}
+
+	/* Round up for set points in the gaps between bands. */
+	if (uV > FTSMPS_BAND1_UV_MAX && uV < FTSMPS_BAND2_UV_MIN)
+		uV = FTSMPS_BAND2_UV_MIN;
+	else if (uV > FTSMPS_BAND2_UV_MAX
+			&& uV < FTSMPS_BAND3_UV_SET_POINT_MIN)
+		uV = FTSMPS_BAND3_UV_SET_POINT_MIN;
+
+	if (uV > FTSMPS_BAND2_UV_MAX) {
+		vprog = (uV - FTSMPS_BAND3_UV_MIN + FTSMPS_BAND3_UV_STEP - 1)
+			/ FTSMPS_BAND3_UV_STEP;
+		band = FTSMPS_VCTRL_BAND_3;
+		uV = FTSMPS_BAND3_UV_MIN + vprog * FTSMPS_BAND3_UV_STEP;
+	} else if (uV > FTSMPS_BAND1_UV_MAX) {
+		vprog = (uV - FTSMPS_BAND2_UV_MIN + FTSMPS_BAND2_UV_STEP - 1)
+			/ FTSMPS_BAND2_UV_STEP;
+		band = FTSMPS_VCTRL_BAND_2;
+		uV = FTSMPS_BAND2_UV_MIN + vprog * FTSMPS_BAND2_UV_STEP;
+	} else {
+		vprog = (uV - FTSMPS_BAND1_UV_MIN
+				+ FTSMPS_BAND1_UV_LOG_STEP - 1)
+			/ FTSMPS_BAND1_UV_LOG_STEP;
+		uV = FTSMPS_BAND1_UV_MIN + vprog * FTSMPS_BAND1_UV_LOG_STEP;
+		vprog *= FTSMPS_BAND1_UV_LOG_STEP / FTSMPS_BAND1_UV_PHYS_STEP;
+		band = FTSMPS_VCTRL_BAND_1;
+	}
+
+	if (uV > max_uV) {
+		pr_err("%s: request v=[%d, %d] cannot be met by any setpoint\n",
+			vreg->name, min_uV, max_uV);
+		return -EINVAL;
+	}
+
+	rc = msm_spm_set_vdd(rdev_get_id(rdev), band | vprog);
+	if (!rc) {
+		if (uV > vreg->uV) {
+			/* Wait for voltage to stabalize. */
+			udelay((uV - vreg->uV) / REGULATOR_SLEW_RATE);
+		}
+		vreg->uV = uV;
+	} else {
+		pr_err("%s: msm_spm_set_vdd failed %d\n", vreg->name, rc);
+	}
+
+	return rc;
+}
+
+static struct regulator_ops saw_ops = {
+	.get_voltage = saw_get_voltage,
+	.set_voltage = saw_set_voltage,
+};
+
+static int __devinit saw_probe(struct platform_device *pdev)
+{
+	struct regulator_init_data *init_data;
+	struct saw_vreg *vreg;
+	int rc = 0;
+
+	if (!pdev->dev.platform_data) {
+		pr_err("platform data required.\n");
+		return -EINVAL;
+	}
+
+	init_data = pdev->dev.platform_data;
+	if (!init_data->constraints.name) {
+		pr_err("regulator name must be specified in constraints.\n");
+		return -EINVAL;
+	}
+
+	vreg = kzalloc(sizeof(struct saw_vreg), GFP_KERNEL);
+	if (!vreg) {
+		pr_err("kzalloc failed.\n");
+		return -ENOMEM;
+	}
+
+	vreg->name = kstrdup(init_data->constraints.name, GFP_KERNEL);
+	if (!vreg->name) {
+		pr_err("kzalloc failed.\n");
+		rc = -ENOMEM;
+		goto free_vreg;
+	}
+
+	vreg->desc.name  = vreg->name;
+	vreg->desc.id    = pdev->id;
+	vreg->desc.ops   = &saw_ops;
+	vreg->desc.type  = REGULATOR_VOLTAGE;
+	vreg->desc.owner = THIS_MODULE;
+	vreg->uV	 = MIN_CORE_VOLTAGE;
+
+	vreg->rdev = regulator_register(&vreg->desc, &pdev->dev,
+							init_data, vreg, NULL);
+	if (IS_ERR(vreg->rdev)) {
+		rc = PTR_ERR(vreg->rdev);
+		pr_err("regulator_register failed, rc=%d.\n", rc);
+		goto free_name;
+	}
+
+	platform_set_drvdata(pdev, vreg);
+
+	pr_info("id=%d, name=%s\n", pdev->id, vreg->name);
+
+	return rc;
+
+free_name:
+	kfree(vreg->name);
+free_vreg:
+	kfree(vreg);
+
+	return rc;
+}
+
+static int __devexit saw_remove(struct platform_device *pdev)
+{
+	struct saw_vreg *vreg = platform_get_drvdata(pdev);
+
+	regulator_unregister(vreg->rdev);
+	kfree(vreg->name);
+	kfree(vreg);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver saw_driver = {
+	.probe = saw_probe,
+	.remove = __devexit_p(saw_remove),
+	.driver = {
+		.name = "saw-regulator",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init saw_init(void)
+{
+	return platform_driver_register(&saw_driver);
+}
+
+static void __exit saw_exit(void)
+{
+	platform_driver_unregister(&saw_driver);
+}
+
+postcore_initcall(saw_init);
+module_exit(saw_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("SAW regulator driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:saw-regulator");
diff --git a/arch/arm/mach-msm/scm-boot.c b/arch/arm/mach-msm/scm-boot.c
index 45cee3e..e377633 100644
--- a/arch/arm/mach-msm/scm-boot.c
+++ b/arch/arm/mach-msm/scm-boot.c
@@ -8,27 +8,22 @@
  * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
  */
 
 #include <linux/module.h>
 #include <linux/slab.h>
 
-#include "scm.h"
+#include <mach/scm.h>
 #include "scm-boot.h"
 
 /*
  * Set the cold/warm boot address for one of the CPU cores.
  */
-int scm_set_boot_addr(phys_addr_t addr, int flags)
+int scm_set_boot_addr(void *addr, int flags)
 {
 	struct {
 		unsigned int flags;
-		phys_addr_t  addr;
+		void *addr;
 	} cmd;
 
 	cmd.addr = addr;
@@ -37,3 +32,4 @@
 			&cmd, sizeof(cmd), NULL, 0);
 }
 EXPORT_SYMBOL(scm_set_boot_addr);
+
diff --git a/arch/arm/mach-msm/scm-boot.h b/arch/arm/mach-msm/scm-boot.h
index 7be32ff..221ffca 100644
--- a/arch/arm/mach-msm/scm-boot.h
+++ b/arch/arm/mach-msm/scm-boot.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, 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
@@ -12,11 +12,19 @@
 #ifndef __MACH_SCM_BOOT_H
 #define __MACH_SCM_BOOT_H
 
-#define SCM_BOOT_ADDR			0x1
-#define SCM_FLAG_COLDBOOT_CPU1		0x1
-#define SCM_FLAG_WARMBOOT_CPU1		0x2
-#define SCM_FLAG_WARMBOOT_CPU0		0x4
+#define SCM_BOOT_ADDR				0x1
+#define SCM_FLAG_COLDBOOT_CPU1		0x01
+#define SCM_FLAG_COLDBOOT_CPU2		0x08
+#define SCM_FLAG_COLDBOOT_CPU3		0x20
+#define SCM_FLAG_WARMBOOT_CPU1		0x02
+#define SCM_FLAG_WARMBOOT_CPU0		0x04
+#define SCM_FLAG_WARMBOOT_CPU2		0x10
+#define SCM_FLAG_WARMBOOT_CPU3		0x40
 
-int scm_set_boot_addr(phys_addr_t addr, int flags);
+#ifdef CONFIG_MSM_SCM
+int scm_set_boot_addr(void *addr, int flags);
+#else
+static inline int scm_set_boot_addr(void *addr, int flags) { return 0; }
+#endif
 
 #endif
diff --git a/arch/arm/mach-msm/scm-io.c b/arch/arm/mach-msm/scm-io.c
new file mode 100644
index 0000000..28614d3
--- /dev/null
+++ b/arch/arm/mach-msm/scm-io.c
@@ -0,0 +1,62 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+
+#include <mach/msm_iomap.h>
+#include <mach/scm.h>
+#include <mach/scm-io.h>
+
+#define SCM_IO_READ	0x1
+#define SCM_IO_WRITE	0x2
+
+#define BETWEEN(p, st, sz) ((p) >= (void __iomem *)(st) && \
+				(p) < ((void __iomem *)(st) + (sz)))
+#define XLATE(p, pst, vst) ((u32)((p) - (vst)) + (pst))
+
+static u32 __secure_readl(u32 addr)
+{
+	u32 r;
+	r = scm_call_atomic1(SCM_SVC_IO, SCM_IO_READ, addr);
+	__iormb();
+	return r;
+}
+
+u32 secure_readl(void __iomem *c)
+{
+	if (BETWEEN(c, MSM_MMSS_CLK_CTL_BASE, MSM_MMSS_CLK_CTL_SIZE))
+		return __secure_readl(XLATE(c, MSM_MMSS_CLK_CTL_PHYS,
+					MSM_MMSS_CLK_CTL_BASE));
+	else if (BETWEEN(c, MSM_TCSR_BASE, MSM_TCSR_SIZE))
+		return __secure_readl(XLATE(c, MSM_TCSR_PHYS, MSM_TCSR_BASE));
+	return readl(c);
+}
+EXPORT_SYMBOL(secure_readl);
+
+static void __secure_writel(u32 v, u32 addr)
+{
+	__iowmb();
+	scm_call_atomic2(SCM_SVC_IO, SCM_IO_WRITE, addr, v);
+}
+
+void secure_writel(u32 v, void __iomem *c)
+{
+	if (BETWEEN(c, MSM_MMSS_CLK_CTL_BASE, MSM_MMSS_CLK_CTL_SIZE))
+		__secure_writel(v, XLATE(c, MSM_MMSS_CLK_CTL_PHYS,
+					MSM_MMSS_CLK_CTL_BASE));
+	else if (BETWEEN(c, MSM_TCSR_BASE, MSM_TCSR_SIZE))
+		__secure_writel(v, XLATE(c, MSM_TCSR_PHYS, MSM_TCSR_BASE));
+	else
+		writel(v, c);
+}
+EXPORT_SYMBOL(secure_writel);
diff --git a/arch/arm/mach-msm/scm-pas.c b/arch/arm/mach-msm/scm-pas.c
new file mode 100644
index 0000000..4096d9c
--- /dev/null
+++ b/arch/arm/mach-msm/scm-pas.c
@@ -0,0 +1,205 @@
+/* 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
+ * 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.
+ */
+
+#define pr_fmt(fmt) "scm-pas: " fmt
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/clk.h>
+
+#include <mach/scm.h>
+#include <mach/socinfo.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#include "scm-pas.h"
+
+#define PAS_INIT_IMAGE_CMD	1
+#define PAS_AUTH_AND_RESET_CMD	5
+#define PAS_SHUTDOWN_CMD	6
+#define PAS_IS_SUPPORTED_CMD	7
+
+int pas_init_image(enum pas_id id, const u8 *metadata, size_t size)
+{
+	int ret;
+	struct pas_init_image_req {
+		u32	proc;
+		u32	image_addr;
+	} request;
+	u32 scm_ret = 0;
+	/* Make memory physically contiguous */
+	void *mdata_buf = kmemdup(metadata, size, GFP_KERNEL);
+
+	if (!mdata_buf)
+		return -ENOMEM;
+
+	request.proc = id;
+	request.image_addr = virt_to_phys(mdata_buf);
+
+	ret = scm_call(SCM_SVC_PIL, PAS_INIT_IMAGE_CMD, &request,
+			sizeof(request), &scm_ret, sizeof(scm_ret));
+	kfree(mdata_buf);
+
+	if (ret)
+		return ret;
+	return scm_ret;
+}
+EXPORT_SYMBOL(pas_init_image);
+
+static struct msm_bus_paths scm_pas_bw_tbl[] = {
+	{
+		.vectors = (struct msm_bus_vectors[]){
+			{
+				.src = MSM_BUS_MASTER_SPS,
+				.dst = MSM_BUS_SLAVE_EBI_CH0,
+			},
+		},
+		.num_paths = 1,
+	},
+	{
+		.vectors = (struct msm_bus_vectors[]){
+			{
+				.src = MSM_BUS_MASTER_SPS,
+				.dst = MSM_BUS_SLAVE_EBI_CH0,
+				.ib = 492 * 8 * 1000000UL,
+				.ab = 492 * 8 *  100000UL,
+			},
+		},
+		.num_paths = 1,
+	},
+};
+
+static struct msm_bus_scale_pdata scm_pas_bus_pdata = {
+	.usecase = scm_pas_bw_tbl,
+	.num_usecases = ARRAY_SIZE(scm_pas_bw_tbl),
+	.name = "scm_pas",
+};
+
+static uint32_t scm_perf_client;
+static struct clk *scm_bus_clk;
+
+static DEFINE_MUTEX(scm_pas_bw_mutex);
+static int scm_pas_bw_count;
+
+static int scm_pas_enable_bw(void)
+{
+	int ret = 0;
+
+	if (!scm_perf_client || !scm_bus_clk)
+		return -EINVAL;
+
+	mutex_lock(&scm_pas_bw_mutex);
+	if (!scm_pas_bw_count) {
+		ret = msm_bus_scale_client_update_request(scm_perf_client, 1);
+		if (ret) {
+			pr_err("bandwidth request failed (%d)\n", ret);
+		} else {
+			ret = clk_prepare_enable(scm_bus_clk);
+			if (ret)
+				pr_err("clock enable failed\n");
+		}
+	}
+	if (ret)
+		msm_bus_scale_client_update_request(scm_perf_client, 0);
+	else
+		scm_pas_bw_count++;
+	mutex_unlock(&scm_pas_bw_mutex);
+	return ret;
+}
+
+static void scm_pas_disable_bw(void)
+{
+	mutex_lock(&scm_pas_bw_mutex);
+	if (scm_pas_bw_count-- == 1) {
+		msm_bus_scale_client_update_request(scm_perf_client, 0);
+		clk_disable_unprepare(scm_bus_clk);
+	}
+	mutex_unlock(&scm_pas_bw_mutex);
+}
+
+int pas_auth_and_reset(enum pas_id id)
+{
+	int ret, bus_ret;
+	u32 proc = id, scm_ret = 0;
+
+	bus_ret = scm_pas_enable_bw();
+	ret = scm_call(SCM_SVC_PIL, PAS_AUTH_AND_RESET_CMD, &proc,
+			sizeof(proc), &scm_ret, sizeof(scm_ret));
+	if (ret)
+		scm_ret = ret;
+	if (!bus_ret)
+		scm_pas_disable_bw();
+
+	return scm_ret;
+}
+EXPORT_SYMBOL(pas_auth_and_reset);
+
+int pas_shutdown(enum pas_id id)
+{
+	int ret;
+	u32 proc = id, scm_ret = 0;
+
+	ret = scm_call(SCM_SVC_PIL, PAS_SHUTDOWN_CMD, &proc, sizeof(proc),
+			&scm_ret, sizeof(scm_ret));
+	if (ret)
+		return ret;
+
+	return scm_ret;
+}
+EXPORT_SYMBOL(pas_shutdown);
+
+static bool secure_pil = true;
+module_param(secure_pil, bool, S_IRUGO);
+MODULE_PARM_DESC(secure_pil, "Use secure PIL");
+
+int pas_supported(enum pas_id id)
+{
+	int ret;
+	u32 periph = id, ret_val = 0;
+
+	if (!secure_pil)
+		return 0;
+
+	/*
+	 * 8660 SCM doesn't support querying secure PIL support so just return
+	 * true if not overridden on the command line.
+	 */
+	if (cpu_is_msm8x60())
+		return 1;
+
+	if (scm_is_call_available(SCM_SVC_PIL, PAS_IS_SUPPORTED_CMD) <= 0)
+		return 0;
+
+	ret = scm_call(SCM_SVC_PIL, PAS_IS_SUPPORTED_CMD, &periph,
+			sizeof(periph), &ret_val, sizeof(ret_val));
+	if (ret)
+		return ret;
+
+	return ret_val;
+}
+EXPORT_SYMBOL(pas_supported);
+
+static int __init scm_pas_init(void)
+{
+	scm_perf_client = msm_bus_scale_register_client(&scm_pas_bus_pdata);
+	if (!scm_perf_client)
+		pr_warn("unable to register bus client\n");
+	scm_bus_clk = clk_get_sys("scm", "bus_clk");
+	if (!IS_ERR(scm_bus_clk)) {
+		clk_set_rate(scm_bus_clk, 64000000);
+	} else {
+		scm_bus_clk = NULL;
+		pr_warn("unable to get bus clock\n");
+	}
+	return 0;
+}
+module_init(scm_pas_init);
diff --git a/arch/arm/mach-msm/scm-pas.h b/arch/arm/mach-msm/scm-pas.h
new file mode 100644
index 0000000..2fe71a9
--- /dev/null
+++ b/arch/arm/mach-msm/scm-pas.h
@@ -0,0 +1,32 @@
+/* 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
+ * 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 __MSM_SCM_PAS_H
+#define __MSM_SCM_PAS_H
+
+enum pas_id {
+	PAS_MODEM,
+	PAS_Q6,
+	PAS_DSPS,
+	PAS_TZAPPS,
+	PAS_MODEM_SW,
+	PAS_MODEM_FW,
+	PAS_RIVA,
+	PAS_SECAPP,
+	PAS_GSS,
+	PAS_VIDC,
+};
+
+extern int pas_init_image(enum pas_id id, const u8 *metadata, size_t size);
+extern int pas_auth_and_reset(enum pas_id id);
+extern int pas_shutdown(enum pas_id id);
+extern int pas_supported(enum pas_id id);
+#endif
diff --git a/arch/arm/mach-msm/scm.c b/arch/arm/mach-msm/scm.c
index bafabb5..ac48990 100644
--- a/arch/arm/mach-msm/scm.c
+++ b/arch/arm/mach-msm/scm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, 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
@@ -8,11 +8,6 @@
  * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
  */
 
 #include <linux/slab.h>
@@ -21,13 +16,11 @@
 #include <linux/mutex.h>
 #include <linux/errno.h>
 #include <linux/err.h>
+#include <linux/init.h>
 
 #include <asm/cacheflush.h>
 
-#include "scm.h"
-
-/* Cache line size for msm8x60 */
-#define CACHELINESIZE 32
+#include <mach/scm.h>
 
 #define SCM_ENOMEM		-5
 #define SCM_EOPNOTSUPP		-4
@@ -210,6 +203,21 @@
 	return ret;
 }
 
+static u32 cacheline_size;
+
+static void scm_inv_range(unsigned long start, unsigned long end)
+{
+	start = round_down(start, cacheline_size);
+	end = round_up(end, cacheline_size);
+	while (start < end) {
+		asm ("mcr p15, 0, %0, c7, c6, 1" : : "r" (start)
+		     : "memory");
+		start += cacheline_size;
+	}
+	dsb();
+	isb();
+}
+
 /**
  * scm_call() - Send an SCM command
  * @svc_id: service identifier
@@ -227,6 +235,7 @@
 	int ret;
 	struct scm_command *cmd;
 	struct scm_response *rsp;
+	unsigned long start, end;
 
 	cmd = alloc_scm_command(cmd_len, resp_len);
 	if (!cmd)
@@ -243,17 +252,15 @@
 		goto out;
 
 	rsp = scm_command_to_response(cmd);
+	start = (unsigned long)rsp;
+
 	do {
-		u32 start = (u32)rsp;
-		u32 end = (u32)scm_get_response_buffer(rsp) + resp_len;
-		start &= ~(CACHELINESIZE - 1);
-		while (start < end) {
-			asm ("mcr p15, 0, %0, c7, c6, 1" : : "r" (start)
-			     : "memory");
-			start += CACHELINESIZE;
-		}
+		scm_inv_range(start, start + sizeof(*rsp));
 	} while (!rsp->is_complete);
 
+	end = (unsigned long)scm_get_response_buffer(rsp) + resp_len;
+	scm_inv_range(start, end);
+
 	if (resp_buf)
 		memcpy(resp_buf, scm_get_response_buffer(rsp), resp_len);
 out:
@@ -262,6 +269,105 @@
 }
 EXPORT_SYMBOL(scm_call);
 
+#define SCM_CLASS_REGISTER	(0x2 << 8)
+#define SCM_MASK_IRQS		BIT(5)
+#define SCM_ATOMIC(svc, cmd, n) (((((svc) << 10)|((cmd) & 0x3ff)) << 12) | \
+				SCM_CLASS_REGISTER | \
+				SCM_MASK_IRQS | \
+				(n & 0xf))
+
+/**
+ * scm_call_atomic1() - Send an atomic SCM command with one argument
+ * @svc_id: service identifier
+ * @cmd_id: command identifier
+ * @arg1: first argument
+ *
+ * This shall only be used with commands that are guaranteed to be
+ * uninterruptable, atomic and SMP safe.
+ */
+s32 scm_call_atomic1(u32 svc, u32 cmd, u32 arg1)
+{
+	int context_id;
+	register u32 r0 asm("r0") = SCM_ATOMIC(svc, cmd, 1);
+	register u32 r1 asm("r1") = (u32)&context_id;
+	register u32 r2 asm("r2") = arg1;
+
+	asm volatile(
+		__asmeq("%0", "r0")
+		__asmeq("%1", "r0")
+		__asmeq("%2", "r1")
+		__asmeq("%3", "r2")
+		"smc	#0	@ switch to secure world\n"
+		: "=r" (r0)
+		: "r" (r0), "r" (r1), "r" (r2)
+		: "r3");
+	return r0;
+}
+EXPORT_SYMBOL(scm_call_atomic1);
+
+/**
+ * scm_call_atomic2() - Send an atomic SCM command with two arguments
+ * @svc_id: service identifier
+ * @cmd_id: command identifier
+ * @arg1: first argument
+ * @arg2: second argument
+ *
+ * This shall only be used with commands that are guaranteed to be
+ * uninterruptable, atomic and SMP safe.
+ */
+s32 scm_call_atomic2(u32 svc, u32 cmd, u32 arg1, u32 arg2)
+{
+	int context_id;
+	register u32 r0 asm("r0") = SCM_ATOMIC(svc, cmd, 2);
+	register u32 r1 asm("r1") = (u32)&context_id;
+	register u32 r2 asm("r2") = arg1;
+	register u32 r3 asm("r3") = arg2;
+
+	asm volatile(
+		__asmeq("%0", "r0")
+		__asmeq("%1", "r0")
+		__asmeq("%2", "r1")
+		__asmeq("%3", "r2")
+		__asmeq("%4", "r3")
+		"smc	#0	@ switch to secure world\n"
+		: "=r" (r0)
+		: "r" (r0), "r" (r1), "r" (r2), "r" (r3));
+	return r0;
+}
+EXPORT_SYMBOL(scm_call_atomic2);
+
+s32 scm_call_atomic4_3(u32 svc, u32 cmd, u32 arg1, u32 arg2,
+		u32 arg3, u32 arg4, u32 *ret1, u32 *ret2)
+{
+	int ret;
+	int context_id;
+	register u32 r0 asm("r0") = SCM_ATOMIC(svc, cmd, 4);
+	register u32 r1 asm("r1") = (u32)&context_id;
+	register u32 r2 asm("r2") = arg1;
+	register u32 r3 asm("r3") = arg2;
+	register u32 r4 asm("r4") = arg3;
+	register u32 r5 asm("r5") = arg4;
+
+	asm volatile(
+		__asmeq("%0", "r0")
+		__asmeq("%1", "r1")
+		__asmeq("%2", "r2")
+		__asmeq("%3", "r0")
+		__asmeq("%4", "r1")
+		__asmeq("%5", "r2")
+		__asmeq("%6", "r3")
+		"smc	#0	@ switch to secure world\n"
+		: "=r" (r0), "=r" (r1), "=r" (r2)
+		: "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4), "r" (r5));
+	ret = r0;
+	if (ret1)
+		*ret1 = r1;
+	if (ret2)
+		*ret2 = r2;
+	return r0;
+}
+EXPORT_SYMBOL(scm_call_atomic4_3);
+
 u32 scm_get_version(void)
 {
 	int context_id;
@@ -294,3 +400,43 @@
 	return version;
 }
 EXPORT_SYMBOL(scm_get_version);
+
+#define IS_CALL_AVAIL_CMD	1
+int scm_is_call_available(u32 svc_id, u32 cmd_id)
+{
+	int ret;
+	u32 svc_cmd = (svc_id << 10) | cmd_id;
+	u32 ret_val = 0;
+
+	ret = scm_call(SCM_SVC_INFO, IS_CALL_AVAIL_CMD, &svc_cmd,
+			sizeof(svc_cmd), &ret_val, sizeof(ret_val));
+	if (ret)
+		return ret;
+
+	return ret_val;
+}
+EXPORT_SYMBOL(scm_is_call_available);
+
+#define GET_FEAT_VERSION_CMD	3
+int scm_get_feat_version(u32 feat)
+{
+	if (scm_is_call_available(SCM_SVC_INFO, GET_FEAT_VERSION_CMD)) {
+		u32 version;
+		if (!scm_call(SCM_SVC_INFO, GET_FEAT_VERSION_CMD, &feat,
+				sizeof(feat), &version, sizeof(version)))
+			return version;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(scm_get_feat_version);
+
+static int scm_init(void)
+{
+	u32 ctr;
+
+	asm volatile("mrc p15, 0, %0, c0, c0, 1" : "=r" (ctr));
+	cacheline_size =  4 << ((ctr >> 16) & 0xf);
+
+	return 0;
+}
+early_initcall(scm_init);
diff --git a/arch/arm/mach-msm/scm.h b/arch/arm/mach-msm/scm.h
deleted file mode 100644
index 00b31ea..0000000
--- a/arch/arm/mach-msm/scm.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/* Copyright (c) 2010, 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 __MACH_SCM_H
-#define __MACH_SCM_H
-
-#define SCM_SVC_BOOT			0x1
-#define SCM_SVC_PIL			0x2
-
-extern int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len,
-		void *resp_buf, size_t resp_len);
-
-#define SCM_VERSION(major, minor) (((major) << 16) | ((minor) & 0xFF))
-
-extern u32 scm_get_version(void);
-
-#endif
diff --git a/arch/arm/mach-msm/sdio_al.c b/arch/arm/mach-msm/sdio_al.c
new file mode 100644
index 0000000..356ce90
--- /dev/null
+++ b/arch/arm/mach-msm/sdio_al.c
@@ -0,0 +1,4365 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * SDIO-Abstraction-Layer Module.
+ *
+ * To be used with Qualcomm's SDIO-Client connected to this host.
+ */
+#include "sdio_al_private.h"
+
+#include <linux/module.h>
+#include <linux/scatterlist.h>
+#include <linux/workqueue.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/wakelock.h>
+#include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/gpio.h>
+#include <linux/dma-mapping.h>
+#include <linux/earlysuspend.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/syscalls.h>
+#include <linux/time.h>
+#include <linux/spinlock.h>
+
+#include <mach/dma.h>
+#include <mach/gpio.h>
+#include <mach/subsystem_notif.h>
+
+#include "../../../drivers/mmc/host/msm_sdcc.h"
+
+/**
+ *  Func#0 has SDIO standard registers
+ *  Func#1 is for Mailbox.
+ *  Functions 2..7 are for channels.
+ *  Currently only functions 2..5 are active due to SDIO-Client
+ *  number of pipes.
+ *
+ */
+#define SDIO_AL_MAX_CHANNELS 6
+
+/** Func 1..5 */
+#define SDIO_AL_MAX_FUNCS    (SDIO_AL_MAX_CHANNELS+1)
+#define SDIO_AL_WAKEUP_FUNC  6
+
+/** Number of SDIO-Client pipes */
+#define SDIO_AL_MAX_PIPES    16
+#define SDIO_AL_ACTIVE_PIPES 8
+
+/** CMD53/CMD54 Block size */
+#define SDIO_AL_BLOCK_SIZE   256
+
+/** Func#1 hardware Mailbox base address	 */
+#define HW_MAILBOX_ADDR			0x1000
+
+/** Func#1 peer sdioc software version.
+ *  The header is duplicated also to the mailbox of the other
+ *  functions. It can be used before other functions are enabled. */
+#define SDIOC_SW_HEADER_ADDR		0x0400
+
+/** Func#2..7 software Mailbox base address at 16K */
+#define SDIOC_SW_MAILBOX_ADDR			0x4000
+
+/** Some Mailbox registers address, written by host for
+ control */
+#define PIPES_THRESHOLD_ADDR		0x01000
+
+#define PIPES_0_7_IRQ_MASK_ADDR 	0x01048
+
+#define PIPES_8_15_IRQ_MASK_ADDR	0x0104C
+
+#define FUNC_1_4_MASK_IRQ_ADDR		0x01040
+#define FUNC_5_7_MASK_IRQ_ADDR		0x01044
+#define FUNC_1_4_USER_IRQ_ADDR		0x01050
+#define FUNC_5_7_USER_IRQ_ADDR		0x01054
+
+#define EOT_PIPES_ENABLE		0x00
+
+/** Maximum read/write data available is SDIO-Client limitation */
+#define MAX_DATA_AVAILABLE   		(16*1024)
+#define INVALID_DATA_AVAILABLE  	(0x8000)
+
+/** SDIO-Client HW threshold to generate interrupt to the
+ *  SDIO-Host on write available bytes.
+ */
+#define DEFAULT_WRITE_THRESHOLD 	(1024)
+
+/** SDIO-Client HW threshold to generate interrupt to the
+ *  SDIO-Host on read available bytes, for streaming (non
+ *  packet) rx data.
+ */
+#define DEFAULT_READ_THRESHOLD  	(1024)
+#define LOW_LATENCY_THRESHOLD		(1)
+
+/* Extra bytes to ensure getting the rx threshold interrupt on stream channels
+   when restoring the threshold after sleep */
+#define THRESHOLD_CHANGE_EXTRA_BYTES (100)
+
+/** SW threshold to trigger reading the mailbox. */
+#define DEFAULT_MIN_WRITE_THRESHOLD 	(1024)
+#define DEFAULT_MIN_WRITE_THRESHOLD_STREAMING	(1600)
+
+#define THRESHOLD_DISABLE_VAL  		(0xFFFFFFFF)
+
+/** Mailbox polling time for packet channels */
+#define DEFAULT_POLL_DELAY_MSEC		10
+/** Mailbox polling time for streaming channels */
+#define DEFAULT_POLL_DELAY_NOPACKET_MSEC 30
+
+/** The SDIO-Client prepares N buffers of size X per Tx pipe.
+ *  Even when the transfer fills a partial buffer,
+ *  that buffer becomes unusable for the next transfer. */
+#define DEFAULT_PEER_TX_BUF_SIZE	(128)
+
+#define ROUND_UP(x, n) (((x + n - 1) / n) * n)
+
+/** Func#2..7 FIFOs are r/w via
+ sdio_readsb() & sdio_writesb(),when inc_addr=0 */
+#define PIPE_RX_FIFO_ADDR   0x00
+#define PIPE_TX_FIFO_ADDR   0x00
+
+/** Inactivity time to go to sleep in mseconds */
+#define INACTIVITY_TIME_MSEC 30
+#define INITIAL_INACTIVITY_TIME_MSEC 5000
+
+/** Context validity check */
+#define SDIO_AL_SIGNATURE 0xAABBCCDD
+
+/* Vendor Specific Command */
+#define SD_IO_RW_EXTENDED_QCOM 54
+
+#define TIME_TO_WAIT_US 500
+#define SDIO_CLOSE_FLUSH_TIMEOUT_MSEC   (10000)
+#define RX_FLUSH_BUFFER_SIZE (16*1024)
+
+#define SDIO_TEST_POSTFIX "_TEST"
+
+#define DATA_DEBUG(x, y...)						\
+	do {								\
+		if (sdio_al->debug.debug_data_on)			\
+			pr_info(y);					\
+		sdio_al_log(x, y);					\
+	} while (0)
+
+#define LPM_DEBUG(x, y...)						\
+	do {								\
+		if (sdio_al->debug.debug_lpm_on)			\
+			pr_info(y);					\
+		sdio_al_log(x, y);					\
+	} while (0)
+
+#define sdio_al_loge(x, y...)						\
+	do {								\
+		pr_err(y);						\
+		sdio_al_log(x, y);					\
+	} while (0)
+
+#define sdio_al_logi(x, y...)						\
+	do {								\
+		pr_info(y);						\
+		sdio_al_log(x, y);					\
+	} while (0)
+
+#define CLOSE_DEBUG(x, y...)						\
+	do {								\
+		if (sdio_al->debug.debug_close_on)			\
+			pr_info(y);					\
+		sdio_al_log(x, y);					\
+	} while (0)
+
+/* The index of the SDIO card used for the sdio_al_dloader */
+#define SDIO_BOOTLOADER_CARD_INDEX 1
+
+
+/* SDIO card state machine */
+enum sdio_al_device_state {
+	CARD_INSERTED,
+	CARD_REMOVED,
+	MODEM_RESTART
+};
+
+struct sdio_al_debug {
+	u8 debug_lpm_on;
+	u8 debug_data_on;
+	u8 debug_close_on;
+	struct dentry *sdio_al_debug_root;
+	struct dentry *sdio_al_debug_lpm_on;
+	struct dentry *sdio_al_debug_data_on;
+	struct dentry *sdio_al_debug_close_on;
+	struct dentry *sdio_al_debug_info;
+	struct dentry *sdio_al_debug_log_buffers[MAX_NUM_OF_SDIO_DEVICES + 1];
+};
+
+/* Polling time for the inactivity timer for devices that doesn't have
+ * a streaming channel
+ */
+#define SDIO_AL_POLL_TIME_NO_STREAMING 30
+
+#define CHAN_TO_FUNC(x) ((x) + 2 - 1)
+
+/**
+ *  Mailbox structure.
+ *  The Mailbox is located on the SDIO-Client Function#1.
+ *  The mailbox size is 128 bytes, which is one block.
+ *  The mailbox allows the host ton:
+ *  1. Get the number of available bytes on the pipes.
+ *  2. Enable/Disable SDIO-Client interrupt, related to pipes.
+ *  3. Set the Threshold for generating interrupt.
+ *
+ */
+struct sdio_mailbox {
+	u32 pipe_bytes_threshold[SDIO_AL_MAX_PIPES]; /* Addr 0x1000 */
+
+	/* Mask USER interrupts generated towards host - Addr 0x1040 */
+	u32 mask_irq_func_1:8; /* LSB */
+	u32 mask_irq_func_2:8;
+	u32 mask_irq_func_3:8;
+	u32 mask_irq_func_4:8;
+
+	u32 mask_irq_func_5:8;
+	u32 mask_irq_func_6:8;
+	u32 mask_irq_func_7:8;
+	u32 mask_mutex_irq:8;
+
+	/* Mask PIPE interrupts generated towards host - Addr 0x1048 */
+	u32 mask_eot_pipe_0_7:8;
+	u32 mask_thresh_above_limit_pipe_0_7:8;
+	u32 mask_overflow_pipe_0_7:8;
+	u32 mask_underflow_pipe_0_7:8;
+
+	u32 mask_eot_pipe_8_15:8;
+	u32 mask_thresh_above_limit_pipe_8_15:8;
+	u32 mask_overflow_pipe_8_15:8;
+	u32 mask_underflow_pipe_8_15:8;
+
+	/* Status of User interrupts generated towards host - Addr 0x1050 */
+	u32 user_irq_func_1:8;
+	u32 user_irq_func_2:8;
+	u32 user_irq_func_3:8;
+	u32 user_irq_func_4:8;
+
+	u32 user_irq_func_5:8;
+	u32 user_irq_func_6:8;
+	u32 user_irq_func_7:8;
+	u32 user_mutex_irq:8;
+
+	/* Status of PIPE interrupts generated towards host */
+	/* Note: All sources are cleared once they read. - Addr 0x1058 */
+	u32 eot_pipe_0_7:8;
+	u32 thresh_above_limit_pipe_0_7:8;
+	u32 overflow_pipe_0_7:8;
+	u32 underflow_pipe_0_7:8;
+
+	u32 eot_pipe_8_15:8;
+	u32 thresh_above_limit_pipe_8_15:8;
+	u32 overflow_pipe_8_15:8;
+	u32 underflow_pipe_8_15:8;
+
+	u16 pipe_bytes_avail[SDIO_AL_MAX_PIPES];
+};
+
+/** Track pending Rx Packet size */
+struct rx_packet_size {
+	u32 size; /* in bytes */
+	struct list_head	list;
+};
+
+#define PEER_SDIOC_SW_MAILBOX_SIGNATURE 0xFACECAFE
+#define PEER_SDIOC_SW_MAILBOX_UT_SIGNATURE 0x5D107E57
+#define PEER_SDIOC_SW_MAILBOX_BOOT_SIGNATURE 0xDEADBEEF
+
+/* Allow support in old sdio version */
+#define PEER_SDIOC_OLD_VERSION_MAJOR	0x0002
+#define INVALID_SDIO_CHAN		0xFF
+
+/**
+ * Peer SDIO-Client software header.
+ */
+struct peer_sdioc_sw_header {
+	u32 signature;
+	u32 version;
+	u32 max_channels;
+	char channel_names[SDIO_AL_MAX_CHANNELS][PEER_CHANNEL_NAME_SIZE];
+	u32 reserved[23];
+};
+
+struct peer_sdioc_boot_sw_header {
+	u32 signature;
+	u32 version;
+	u32 boot_ch_num;
+	u32 reserved[29]; /* 32 - previous fields */
+};
+
+/**
+ * Peer SDIO-Client software mailbox.
+ */
+struct peer_sdioc_sw_mailbox {
+	struct peer_sdioc_sw_header sw_header;
+	struct peer_sdioc_channel_config ch_config[SDIO_AL_MAX_CHANNELS];
+};
+
+#define SDIO_AL_DEBUG_LOG_SIZE 3000
+struct sdio_al_local_log {
+	char buffer[SDIO_AL_DEBUG_LOG_SIZE];
+	unsigned int buf_cur_pos;
+	spinlock_t log_lock;
+};
+
+#define SDIO_AL_DEBUG_TMP_LOG_SIZE 250
+static int sdio_al_log(struct sdio_al_local_log *, const char *fmt, ...);
+
+/**
+ *  SDIO Abstraction Layer driver context.
+ *
+ *  @pdata -
+ *  @debug -
+ *  @devices - an array of the the devices claimed by sdio_al
+ *  @unittest_mode - a flag to indicate if sdio_al is in
+ *		   unittest mode
+ *  @bootloader_dev - the device which is used for the
+ *                 bootloader
+ *  @subsys_notif_handle - handle for modem restart
+ *                 notifications
+ *
+ */
+struct sdio_al {
+	struct sdio_al_local_log gen_log;
+	struct sdio_al_local_log device_log[MAX_NUM_OF_SDIO_DEVICES];
+	struct sdio_al_platform_data *pdata;
+	struct sdio_al_debug debug;
+	struct sdio_al_device *devices[MAX_NUM_OF_SDIO_DEVICES];
+	int unittest_mode;
+	struct sdio_al_device *bootloader_dev;
+	void *subsys_notif_handle;
+	int sdioc_major;
+	int skip_print_info;
+};
+
+struct sdio_al_work {
+	struct work_struct work;
+	struct sdio_al_device *sdio_al_dev;
+};
+
+
+/**
+ *  SDIO Abstraction Layer device context.
+ *
+ *  @card - card claimed.
+ *
+ *  @mailbox - A shadow of the SDIO-Client mailbox.
+ *
+ *  @channel - Channels context.
+ *
+ *  @workqueue - workqueue to read the mailbox and handle
+ *     pending requests. Reading the mailbox should not happen
+ *     in interrupt context.
+ *
+ *  @work - work to submit to workqueue.
+ *
+ *  @is_ready - driver is ready.
+ *
+ *  @ask_mbox - Flag to request reading the mailbox,
+ *					  for different reasons.
+ *
+ *  @wake_lock - Lock when can't sleep.
+ *
+ *  @lpm_chan - Channel to use for LPM (low power mode)
+ *            communication.
+ *
+ *  @is_ok_to_sleep - Mark if driver is OK with going to sleep
+ * 			(no pending transactions).
+ *
+ *  @inactivity_time - time allowed to be in inactivity before
+ * 		going to sleep
+ *
+ *  @timer - timer to use for polling the mailbox.
+ *
+ *  @poll_delay_msec - timer delay for polling the mailbox.
+ *
+ *  @is_err - error detected.
+ *
+ *  @signature - Context Validity Check.
+ *
+ *  @flashless_boot_on - flag to indicate if sdio_al is in
+ *    flshless boot mode
+ *
+ */
+struct sdio_al_device {
+	struct sdio_al_local_log *dev_log;
+	struct mmc_card *card;
+	struct mmc_host *host;
+	struct sdio_mailbox *mailbox;
+	struct sdio_channel channel[SDIO_AL_MAX_CHANNELS];
+
+	struct peer_sdioc_sw_header *sdioc_sw_header;
+	struct peer_sdioc_boot_sw_header *sdioc_boot_sw_header;
+
+	struct workqueue_struct *workqueue;
+	struct sdio_al_work sdio_al_work;
+	struct sdio_al_work boot_work;
+
+	int is_ready;
+
+	wait_queue_head_t   wait_mbox;
+	int ask_mbox;
+	int bootloader_done;
+
+	struct wake_lock wake_lock;
+	int lpm_chan;
+	int is_ok_to_sleep;
+	unsigned long inactivity_time;
+
+	struct timer_list timer;
+	u32 poll_delay_msec;
+	int is_timer_initialized;
+
+	int is_err;
+
+	u32 signature;
+
+	unsigned int is_suspended;
+
+	int flashless_boot_on;
+	int ch_close_supported;
+	int state;
+	int (*lpm_callback)(void *, int);
+
+	int print_after_interrupt;
+
+	u8 *rx_flush_buf;
+};
+
+/*
+ * Host operation:
+ *   lower 16bits are operation code
+ *   upper 16bits are operation state
+ */
+#define PEER_OPERATION(op_code , op_state) ((op_code) | ((op_state) << 16))
+#define GET_PEER_OPERATION_CODE(op) ((op) & 0xffff)
+#define GET_PEER_OPERATION_STATE(op) ((op) >> 16)
+
+enum peer_op_code {
+	PEER_OP_CODE_CLOSE = 1
+};
+
+enum peer_op_state {
+	PEER_OP_STATE_INIT = 0,
+	PEER_OP_STATE_START = 1
+};
+
+
+/*
+ * On the kernel command line specify
+ * sdio_al.debug_lpm_on=1 to enable the LPM debug messages
+ * By default the LPM debug messages are turned off
+ */
+static int debug_lpm_on;
+module_param(debug_lpm_on, int, 0);
+
+/*
+ * On the kernel command line specify
+ * sdio_al.debug_data_on=1 to enable the DATA debug messages
+ * By default the DATA debug messages are turned off
+ */
+static int debug_data_on;
+module_param(debug_data_on, int, 0);
+
+/*
+ * Enables / disables open close debug messages
+ */
+static int debug_close_on = 1;
+module_param(debug_close_on, int, 0);
+
+/** The driver context */
+static struct sdio_al *sdio_al;
+
+/* Static functions declaration */
+static int enable_eot_interrupt(struct sdio_al_device *sdio_al_dev,
+				int pipe_index, int enable);
+static int enable_threshold_interrupt(struct sdio_al_device *sdio_al_dev,
+				      int pipe_index, int enable);
+static void sdio_func_irq(struct sdio_func *func);
+static void sdio_al_timer_handler(unsigned long data);
+static int get_min_poll_time_msec(struct sdio_al_device *sdio_al_dev);
+static u32 check_pending_rx_packet(struct sdio_channel *ch, u32 eot);
+static u32 remove_handled_rx_packet(struct sdio_channel *ch);
+static int set_pipe_threshold(struct sdio_al_device *sdio_al_dev,
+			      int pipe_index, int threshold);
+static int sdio_al_wake_up(struct sdio_al_device *sdio_al_dev,
+			   u32 not_from_int, struct sdio_channel *ch);
+static int sdio_al_client_setup(struct sdio_al_device *sdio_al_dev);
+static int enable_mask_irq(struct sdio_al_device *sdio_al_dev,
+			   int func_num, int enable, u8 bit_offset);
+static int sdio_al_enable_func_retry(struct sdio_func *func, const char *name);
+static void sdio_al_print_info(void);
+static int sdio_read_internal(struct sdio_channel *ch, void *data, int len);
+static int sdio_read_from_closed_ch(struct sdio_channel *ch, int len);
+static void stop_and_del_timer(struct sdio_al_device *sdio_al_dev);
+
+#define SDIO_AL_ERR(func)					\
+	do {							\
+		printk_once(KERN_ERR MODULE_NAME		\
+			":In Error state, ignore %s\n",		\
+			func);					\
+		sdio_al_print_info();				\
+	} while (0)
+
+#ifdef CONFIG_DEBUG_FS
+static int debug_info_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t debug_info_write(struct file *file,
+		const char __user *buf, size_t count, loff_t *ppos)
+{
+	sdio_al_print_info();
+	return 1;
+}
+
+const struct file_operations debug_info_ops = {
+	.open = debug_info_open,
+	.write = debug_info_write,
+};
+
+struct debugfs_blob_wrapper sdio_al_dbgfs_log[MAX_NUM_OF_SDIO_DEVICES + 1];
+
+/*
+*
+* Trigger on/off for debug messages
+* for trigger off the data messages debug level use:
+* echo 0 > /sys/kernel/debugfs/sdio_al/debug_data_on
+* for trigger on the data messages debug level use:
+* echo 1 > /sys/kernel/debugfs/sdio_al/debug_data_on
+* for trigger off the lpm messages debug level use:
+* echo 0 > /sys/kernel/debugfs/sdio_al/debug_lpm_on
+* for trigger on the lpm messages debug level use:
+* echo 1 > /sys/kernel/debugfs/sdio_al/debug_lpm_on
+*/
+static int sdio_al_debugfs_init(void)
+{
+	int i, blob_errs = 0;
+
+	sdio_al->debug.sdio_al_debug_root = debugfs_create_dir("sdio_al", NULL);
+	if (!sdio_al->debug.sdio_al_debug_root)
+		return -ENOENT;
+
+	sdio_al->debug.sdio_al_debug_lpm_on = debugfs_create_u8("debug_lpm_on",
+					S_IRUGO | S_IWUGO,
+					sdio_al->debug.sdio_al_debug_root,
+					&sdio_al->debug.debug_lpm_on);
+
+	sdio_al->debug.sdio_al_debug_data_on = debugfs_create_u8(
+					"debug_data_on",
+					S_IRUGO | S_IWUGO,
+					sdio_al->debug.sdio_al_debug_root,
+					&sdio_al->debug.debug_data_on);
+
+	sdio_al->debug.sdio_al_debug_close_on = debugfs_create_u8(
+					"debug_close_on",
+					S_IRUGO | S_IWUGO,
+					sdio_al->debug.sdio_al_debug_root,
+					&sdio_al->debug.debug_close_on);
+
+	sdio_al->debug.sdio_al_debug_info = debugfs_create_file(
+					"sdio_debug_info",
+					S_IRUGO | S_IWUGO,
+					sdio_al->debug.sdio_al_debug_root,
+					NULL,
+					&debug_info_ops);
+
+	for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
+		char temp[18];
+
+		scnprintf(temp, 18, "sdio_al_log_dev_%d", i + 1);
+		sdio_al->debug.sdio_al_debug_log_buffers[i] =
+			debugfs_create_blob(temp,
+					S_IRUGO | S_IWUGO,
+					sdio_al->debug.sdio_al_debug_root,
+					&sdio_al_dbgfs_log[i]);
+	}
+
+	sdio_al->debug.sdio_al_debug_log_buffers[MAX_NUM_OF_SDIO_DEVICES] =
+			debugfs_create_blob("sdio_al_gen_log",
+				S_IRUGO | S_IWUGO,
+				sdio_al->debug.sdio_al_debug_root,
+				&sdio_al_dbgfs_log[MAX_NUM_OF_SDIO_DEVICES]);
+
+	for (i = 0; i < (MAX_NUM_OF_SDIO_DEVICES + 1); ++i) {
+		if (!sdio_al->debug.sdio_al_debug_log_buffers[i]) {
+			pr_err(MODULE_NAME ": Failed to create debugfs buffer"
+				   " entry for "
+				   "sdio_al->debug.sdio_al_debug_log_buffers[%d]",
+				   i);
+			blob_errs = 1;
+		}
+	}
+
+	if (blob_errs) {
+		for (i = 0; i < (MAX_NUM_OF_SDIO_DEVICES + 1); ++i)
+			if (sdio_al->debug.sdio_al_debug_log_buffers[i])
+				debugfs_remove(
+					sdio_al->
+					debug.sdio_al_debug_log_buffers[i]);
+	}
+
+
+	if ((!sdio_al->debug.sdio_al_debug_data_on) &&
+	    (!sdio_al->debug.sdio_al_debug_lpm_on) &&
+	    (!sdio_al->debug.sdio_al_debug_close_on) &&
+	    (!sdio_al->debug.sdio_al_debug_info) &&
+		blob_errs) {
+		debugfs_remove(sdio_al->debug.sdio_al_debug_root);
+		sdio_al->debug.sdio_al_debug_root = NULL;
+		return -ENOENT;
+	}
+
+	sdio_al_dbgfs_log[MAX_NUM_OF_SDIO_DEVICES].data =
+						sdio_al->gen_log.buffer;
+	sdio_al_dbgfs_log[MAX_NUM_OF_SDIO_DEVICES].size =
+						SDIO_AL_DEBUG_LOG_SIZE;
+
+	return 0;
+}
+
+static void sdio_al_debugfs_cleanup(void)
+{
+	int i;
+
+	debugfs_remove(sdio_al->debug.sdio_al_debug_lpm_on);
+	debugfs_remove(sdio_al->debug.sdio_al_debug_data_on);
+	debugfs_remove(sdio_al->debug.sdio_al_debug_close_on);
+	debugfs_remove(sdio_al->debug.sdio_al_debug_info);
+
+	for (i = 0; i < (MAX_NUM_OF_SDIO_DEVICES + 1); ++i)
+		debugfs_remove(sdio_al->debug.sdio_al_debug_log_buffers[i]);
+
+	debugfs_remove(sdio_al->debug.sdio_al_debug_root);
+}
+#endif
+
+static int sdio_al_log(struct sdio_al_local_log *log, const char *fmt, ...)
+{
+	va_list args;
+	int r;
+	char *tp, *log_buf;
+	unsigned int *log_cur_pos;
+	struct timeval kt;
+	unsigned long flags;
+	static char sdio_al_log_tmp[SDIO_AL_DEBUG_TMP_LOG_SIZE];
+
+	spin_lock_irqsave(&log->log_lock, flags);
+
+	kt = ktime_to_timeval(ktime_get());
+	r = scnprintf(sdio_al_log_tmp, SDIO_AL_DEBUG_TMP_LOG_SIZE,
+			"[%8ld.%6ld] ", kt.tv_sec, kt.tv_usec);
+
+	va_start(args, fmt);
+	r += vscnprintf(&sdio_al_log_tmp[r], (SDIO_AL_DEBUG_TMP_LOG_SIZE - r),
+			fmt, args);
+	va_end(args);
+
+	log_buf = log->buffer;
+	log_cur_pos = &(log->buf_cur_pos);
+
+	for (tp = sdio_al_log_tmp; tp < (sdio_al_log_tmp + r); tp++) {
+		log_buf[(*log_cur_pos)++] = *tp;
+		if ((*log_cur_pos) == SDIO_AL_DEBUG_LOG_SIZE)
+			*log_cur_pos = 0;
+	}
+
+	spin_unlock_irqrestore(&log->log_lock, flags);
+
+	return r;
+}
+
+static int sdio_al_verify_func1(struct sdio_al_device *sdio_al_dev,
+				char const *func)
+{
+	if (sdio_al_dev == NULL) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
+				"sdio_al_dev\n", func);
+		return -ENODEV;
+	}
+
+	if (sdio_al_dev->signature != SDIO_AL_SIGNATURE) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: Invalid "
+				"signature\n", func);
+		return -ENODEV;
+	}
+
+	if (!sdio_al_dev->card) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: NULL "
+				"card\n", func);
+		return -ENODEV;
+	}
+	if (!sdio_al_dev->card->sdio_func[0]) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: NULL "
+				"func1\n", func);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static int sdio_al_claim_mutex(struct sdio_al_device *sdio_al_dev,
+			       char const *func)
+{
+	if (!sdio_al_dev) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
+					"device\n", func);
+		return -ENODEV;
+	}
+
+	if (sdio_al_dev->signature != SDIO_AL_SIGNATURE) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: Invalid "
+					"device signature\n", func);
+		return -ENODEV;
+	}
+
+	if (!sdio_al_dev->host) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: NULL "
+					"host\n", func);
+		return -ENODEV;
+	}
+
+	mmc_claim_host(sdio_al_dev->host);
+
+	return 0;
+}
+
+static int sdio_al_release_mutex(struct sdio_al_device *sdio_al_dev,
+			       char const *func)
+{
+	if (!sdio_al_dev) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
+					"device\n", func);
+		return -ENODEV;
+	}
+
+	if (sdio_al_dev->signature != SDIO_AL_SIGNATURE) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: Invalid "
+					"device signature\n", func);
+		return -ENODEV;
+	}
+
+	if (!sdio_al_dev->host) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: NULL "
+					"host\n", func);
+		return -ENODEV;
+	}
+
+	mmc_release_host(sdio_al_dev->host);
+
+	return 0;
+}
+
+static int sdio_al_claim_mutex_and_verify_dev(
+	struct sdio_al_device *sdio_al_dev,
+	char const *func)
+{
+	if (sdio_al_claim_mutex(sdio_al_dev, __func__))
+		return -ENODEV;
+
+	if (sdio_al_dev->state != CARD_INSERTED) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: Invalid "
+				"device state %d\n", func, sdio_al_dev->state);
+		sdio_al_release_mutex(sdio_al_dev, __func__);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void sdio_al_get_into_err_state(struct sdio_al_device *sdio_al_dev)
+{
+	if ((!sdio_al) || (!sdio_al_dev))
+		return;
+
+	sdio_al_dev->is_err = true;
+	sdio_al->debug.debug_data_on = 0;
+	sdio_al->debug.debug_lpm_on = 0;
+	sdio_al_print_info();
+}
+
+void sdio_al_register_lpm_cb(void *device_handle,
+				       int(*lpm_callback)(void *, int))
+{
+	struct sdio_al_device *sdio_al_dev =
+		(struct sdio_al_device *) device_handle;
+
+	if (!sdio_al_dev) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - "
+				"device_handle is NULL\n", __func__);
+		return;
+	}
+
+	if (lpm_callback) {
+		sdio_al_dev->lpm_callback = lpm_callback;
+		lpm_callback((void *)sdio_al_dev,
+					   sdio_al_dev->is_ok_to_sleep);
+	}
+
+	LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": %s - device %d "
+			"registered for wakeup callback\n", __func__,
+			sdio_al_dev->host->index);
+}
+
+void sdio_al_unregister_lpm_cb(void *device_handle)
+{
+	struct sdio_al_device *sdio_al_dev =
+		(struct sdio_al_device *) device_handle;
+
+	if (!sdio_al_dev) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - "
+				"device_handle is NULL\n", __func__);
+		return;
+	}
+
+	sdio_al_dev->lpm_callback = NULL;
+	LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": %s - device %d "
+		"unregister for wakeup callback\n", __func__,
+		sdio_al_dev->host->index);
+}
+
+static void sdio_al_vote_for_sleep(struct sdio_al_device *sdio_al_dev,
+				   int is_vote_for_sleep)
+{
+	pr_debug(MODULE_NAME ": %s()", __func__);
+
+	if (!sdio_al_dev) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - sdio_al_dev"
+				" is NULL\n", __func__);
+		return;
+	}
+
+	if (is_vote_for_sleep) {
+		pr_debug(MODULE_NAME ": %s - sdio vote for Sleep", __func__);
+		wake_unlock(&sdio_al_dev->wake_lock);
+	} else {
+		pr_debug(MODULE_NAME ": %s - sdio vote against sleep",
+			  __func__);
+		wake_lock(&sdio_al_dev->wake_lock);
+	}
+
+	if (sdio_al_dev->lpm_callback != NULL) {
+		LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": %s - "
+				"is_vote_for_sleep=%d for card#%d, "
+				"calling callback...", __func__,
+				is_vote_for_sleep,
+				sdio_al_dev->host->index);
+		sdio_al_dev->lpm_callback((void *)sdio_al_dev,
+					   is_vote_for_sleep);
+	}
+}
+
+/**
+ *  Write SDIO-Client lpm information
+ *  Should only be called with host claimed.
+ */
+static int write_lpm_info(struct sdio_al_device *sdio_al_dev)
+{
+	struct sdio_func *lpm_func = NULL;
+	int offset = offsetof(struct peer_sdioc_sw_mailbox, ch_config)+
+		sizeof(struct peer_sdioc_channel_config) *
+		sdio_al_dev->lpm_chan+
+		offsetof(struct peer_sdioc_channel_config, is_host_ok_to_sleep);
+	int ret;
+
+	if (sdio_al_dev->lpm_chan == INVALID_SDIO_CHAN) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Invalid "
+				"lpm_chan for card %d\n",
+				sdio_al_dev->host->index);
+		return -EINVAL;
+	}
+
+	if (!sdio_al_dev->card ||
+		!sdio_al_dev->card->sdio_func[sdio_al_dev->lpm_chan+1]) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
+				": NULL card or lpm_func\n");
+		return -ENODEV;
+	}
+	lpm_func = sdio_al_dev->card->sdio_func[sdio_al_dev->lpm_chan+1];
+
+	pr_debug(MODULE_NAME ":write_lpm_info is_ok_to_sleep=%d, device %d\n",
+		 sdio_al_dev->is_ok_to_sleep,
+		 sdio_al_dev->host->index);
+
+	ret = sdio_memcpy_toio(lpm_func, SDIOC_SW_MAILBOX_ADDR+offset,
+				&sdio_al_dev->is_ok_to_sleep, sizeof(u32));
+	if (ret) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":failed to "
+				"write lpm info for card %d\n",
+				sdio_al_dev->host->index);
+		return ret;
+	}
+
+	return 0;
+}
+
+/* Set inactivity counter to intial value to allow clients come up */
+static inline void start_inactive_time(struct sdio_al_device *sdio_al_dev)
+{
+	sdio_al_dev->inactivity_time = jiffies +
+		msecs_to_jiffies(INITIAL_INACTIVITY_TIME_MSEC);
+}
+
+static inline void restart_inactive_time(struct sdio_al_device *sdio_al_dev)
+{
+	sdio_al_dev->inactivity_time = jiffies +
+		msecs_to_jiffies(INACTIVITY_TIME_MSEC);
+}
+
+static inline int is_inactive_time_expired(struct sdio_al_device *sdio_al_dev)
+{
+	return time_after(jiffies, sdio_al_dev->inactivity_time);
+}
+
+
+static int is_user_irq_enabled(struct sdio_al_device *sdio_al_dev,
+			       int func_num)
+{
+	int ret = 0;
+	struct sdio_func *func1;
+	u32 user_irq = 0;
+	u32 addr = 0;
+	u32 offset = 0;
+	u32 masked_user_irq = 0;
+
+	if (sdio_al_verify_func1(sdio_al_dev, __func__))
+		return 0;
+	func1 = sdio_al_dev->card->sdio_func[0];
+
+	if (func_num < 4) {
+		addr = FUNC_1_4_USER_IRQ_ADDR;
+		offset = func_num * 8;
+	} else {
+		addr = FUNC_5_7_USER_IRQ_ADDR;
+		offset = (func_num - 4) * 8;
+	}
+
+	user_irq = sdio_readl(func1, addr, &ret);
+	if (ret) {
+		pr_debug(MODULE_NAME ":read_user_irq fail\n");
+		return 0;
+	}
+
+	masked_user_irq = (user_irq >> offset) && 0xFF;
+	if (masked_user_irq == 0x1) {
+		sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":user_irq "
+				"enabled\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+static void sdio_al_sleep(struct sdio_al_device *sdio_al_dev,
+			  struct mmc_host *host)
+{
+	int i;
+
+	/* Go to sleep */
+	pr_debug(MODULE_NAME  ":Inactivity timer expired."
+		" Going to sleep\n");
+	/* Stop mailbox timer */
+	stop_and_del_timer(sdio_al_dev);
+	/* Make sure we get interrupt for non-packet-mode right away */
+	for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
+		struct sdio_channel *ch = &sdio_al_dev->channel[i];
+		if ((ch->state != SDIO_CHANNEL_STATE_OPEN) &&
+		    (ch->state != SDIO_CHANNEL_STATE_CLOSED)) {
+			pr_debug(MODULE_NAME  ":continue for channel %s in"
+					" state %d\n", ch->name, ch->state);
+			continue;
+		}
+		if (ch->is_packet_mode == false) {
+			ch->read_threshold = LOW_LATENCY_THRESHOLD;
+			set_pipe_threshold(sdio_al_dev,
+					   ch->rx_pipe_index,
+					   ch->read_threshold);
+		}
+	}
+	/* Prevent modem to go to sleep until we get the PROG_DONE on
+	   the dummy CMD52 */
+	msmsdcc_set_pwrsave(sdio_al_dev->host, 0);
+	/* Mark HOST_OK_TOSLEEP */
+	sdio_al_dev->is_ok_to_sleep = 1;
+	write_lpm_info(sdio_al_dev);
+
+	msmsdcc_lpm_enable(host);
+	LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":Finished sleep sequence"
+			" for card %d. Sleep now.\n",
+		sdio_al_dev->host->index);
+	/* Release wakelock */
+	sdio_al_vote_for_sleep(sdio_al_dev, 1);
+}
+
+
+/**
+ *  Read SDIO-Client Mailbox from Function#1.thresh_pipe
+ *
+ *  The mailbox contain the bytes available per pipe,
+ *  and the End-Of-Transfer indication per pipe (if available).
+ *
+ * WARNING: Each time the Mailbox is read from the client, the
+ * read_bytes_avail is incremented with another pending
+ * transfer. Therefore, a pending rx-packet should be added to a
+ * list before the next read of the mailbox.
+ *
+ * This function should run from a workqueue context since it
+ * notifies the clients.
+ *
+ * This function assumes that sdio_al_claim_mutex was called before
+ * calling it.
+ *
+ */
+static int read_mailbox(struct sdio_al_device *sdio_al_dev, int from_isr)
+{
+	int ret;
+	struct sdio_func *func1 = NULL;
+	struct sdio_mailbox *mailbox = sdio_al_dev->mailbox;
+	struct mmc_host *host = sdio_al_dev->host;
+	u32 new_write_avail = 0;
+	u32 old_write_avail = 0;
+	u32 any_read_avail = 0;
+	u32 any_write_pending = 0;
+	int i;
+	u32 rx_notify_bitmask = 0;
+	u32 tx_notify_bitmask = 0;
+	u32 eot_pipe = 0;
+	u32 thresh_pipe = 0;
+	u32 overflow_pipe = 0;
+	u32 underflow_pipe = 0;
+	u32 thresh_intr_mask = 0;
+	int is_closing = 0;
+
+	if (sdio_al_dev->is_err) {
+		SDIO_AL_ERR(__func__);
+		return 0;
+	}
+
+	if (sdio_al_verify_func1(sdio_al_dev, __func__))
+		return -ENODEV;
+	func1 = sdio_al_dev->card->sdio_func[0];
+
+	pr_debug(MODULE_NAME ":start %s from_isr = %d for card %d.\n"
+		 , __func__, from_isr, sdio_al_dev->host->index);
+
+	pr_debug(MODULE_NAME ":before sdio_memcpy_fromio.\n");
+	memset(mailbox, 0, sizeof(struct sdio_mailbox));
+	ret = sdio_memcpy_fromio(func1, mailbox,
+			HW_MAILBOX_ADDR, sizeof(*mailbox));
+	pr_debug(MODULE_NAME ":after sdio_memcpy_fromio.\n");
+	if (ret) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to read "
+				"Mailbox for card %d, goto error state\n",
+				sdio_al_dev->host->index);
+		sdio_al_get_into_err_state(sdio_al_dev);
+		goto exit_err;
+	}
+
+	eot_pipe =	(mailbox->eot_pipe_0_7) |
+			(mailbox->eot_pipe_8_15<<8);
+	thresh_pipe = 	(mailbox->thresh_above_limit_pipe_0_7) |
+			(mailbox->thresh_above_limit_pipe_8_15<<8);
+
+	overflow_pipe = (mailbox->overflow_pipe_0_7) |
+			(mailbox->overflow_pipe_8_15<<8);
+	underflow_pipe = mailbox->underflow_pipe_0_7 |
+			(mailbox->underflow_pipe_8_15<<8);
+	thresh_intr_mask =
+		(mailbox->mask_thresh_above_limit_pipe_0_7) |
+		(mailbox->mask_thresh_above_limit_pipe_8_15<<8);
+
+	if (overflow_pipe || underflow_pipe)
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Mailbox ERROR "
+				"overflow=0x%x, underflow=0x%x\n",
+				overflow_pipe, underflow_pipe);
+
+	/* In case of modem reset we would like to read the daya from the modem
+	   to clear the interrupts but do not process it */
+	if (sdio_al_dev->state != CARD_INSERTED) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_al_device"
+				" (card %d) is in invalid state %d\n",
+				sdio_al_dev->host->index,
+				sdio_al_dev->state);
+		return -ENODEV;
+	}
+
+	pr_debug(MODULE_NAME ":card %d: eot=0x%x, thresh=0x%x\n",
+			sdio_al_dev->host->index,
+			eot_pipe, thresh_pipe);
+
+	/* Scan for Rx Packets available and update read available bytes */
+	for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
+		struct sdio_channel *ch = &sdio_al_dev->channel[i];
+		u32 old_read_avail;
+		u32 read_avail;
+		u32 new_packet_size = 0;
+
+		if (ch->state == SDIO_CHANNEL_STATE_CLOSING)
+			is_closing = true; /* used to prevent sleep */
+
+		old_read_avail = ch->read_avail;
+		read_avail = mailbox->pipe_bytes_avail[ch->rx_pipe_index];
+
+		if ((ch->state == SDIO_CHANNEL_STATE_CLOSED) &&
+			(read_avail > 0)) {
+			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
+				 ":%s: Invalid read_avail 0x%x, for CLOSED ch %s\n",
+				 __func__, read_avail, ch->name);
+			sdio_read_from_closed_ch(ch, read_avail);
+		}
+		if ((ch->state != SDIO_CHANNEL_STATE_OPEN) &&
+		    (ch->state != SDIO_CHANNEL_STATE_CLOSING))
+			continue;
+
+		if (read_avail > INVALID_DATA_AVAILABLE) {
+			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
+				 ":Invalid read_avail 0x%x for pipe %d\n",
+				 read_avail, ch->rx_pipe_index);
+			continue;
+		}
+		any_read_avail |= read_avail | old_read_avail;
+		ch->statistics.last_any_read_avail = any_read_avail;
+		ch->statistics.last_read_avail = read_avail;
+		ch->statistics.last_old_read_avail = old_read_avail;
+
+		if (ch->is_packet_mode) {
+			if ((eot_pipe & (1<<ch->rx_pipe_index)) &&
+			    sdio_al_dev->print_after_interrupt) {
+				LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME
+					":Interrupt on ch %s, "
+					"card %d", ch->name,
+					sdio_al_dev->host->index);
+			}
+			new_packet_size = check_pending_rx_packet(ch, eot_pipe);
+		} else {
+			if ((thresh_pipe & (1<<ch->rx_pipe_index)) &&
+			    sdio_al_dev->print_after_interrupt) {
+				LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME
+					":Interrupt on ch %s, "
+					"card %d", ch->name,
+					sdio_al_dev->host->index);
+			}
+			ch->read_avail = read_avail;
+
+			/*
+			 * Restore default thresh for non packet channels.
+			 * in case it IS low latency channel then read_threshold
+			 * and def_read_threshold are both
+			 * LOW_LATENCY_THRESHOLD
+			 */
+			if ((ch->read_threshold != ch->def_read_threshold) &&
+			    (read_avail >= ch->threshold_change_cnt)) {
+				if (!ch->is_low_latency_ch) {
+					ch->read_threshold =
+						ch->def_read_threshold;
+					set_pipe_threshold(sdio_al_dev,
+							   ch->rx_pipe_index,
+							   ch->read_threshold);
+				}
+			}
+		}
+
+		if ((ch->is_packet_mode) && (new_packet_size > 0)) {
+			rx_notify_bitmask |= (1<<ch->num);
+			ch->statistics.total_notifs++;
+		}
+
+		if ((!ch->is_packet_mode) && (ch->read_avail > 0) &&
+		    (old_read_avail == 0)) {
+			rx_notify_bitmask |= (1<<ch->num);
+			ch->statistics.total_notifs++;
+		}
+	}
+	sdio_al_dev->print_after_interrupt = 0;
+
+	/* Update Write available */
+	for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
+		struct sdio_channel *ch = &sdio_al_dev->channel[i];
+
+		if ((ch->state != SDIO_CHANNEL_STATE_OPEN) &&
+		    (ch->state != SDIO_CHANNEL_STATE_CLOSING))
+			continue;
+
+		new_write_avail = mailbox->pipe_bytes_avail[ch->tx_pipe_index];
+
+		if (new_write_avail > INVALID_DATA_AVAILABLE) {
+			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
+				 ":Invalid write_avail 0x%x for pipe %d\n",
+				 new_write_avail, ch->tx_pipe_index);
+			continue;
+		}
+
+		old_write_avail = ch->write_avail;
+		ch->write_avail = new_write_avail;
+
+		if ((old_write_avail <= ch->min_write_avail) &&
+			(new_write_avail >= ch->min_write_avail))
+			tx_notify_bitmask |= (1<<ch->num);
+
+		/* There is not enough write avail for this channel.
+		   We need to keep reading mailbox to wait for the appropriate
+		   write avail and cannot sleep. Ignore SMEM channel that has
+		   only one direction. */
+		if (strncmp(ch->name, "SDIO_SMEM", CHANNEL_NAME_SIZE))
+			any_write_pending |=
+			(new_write_avail < ch->ch_config.max_tx_threshold);
+	}
+	/* notify clients */
+	for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
+		struct sdio_channel *ch = &sdio_al_dev->channel[i];
+
+		if ((ch->state != SDIO_CHANNEL_STATE_OPEN) ||
+				(ch->notify == NULL))
+			continue;
+
+		if (rx_notify_bitmask & (1<<ch->num))
+			ch->notify(ch->priv,
+					   SDIO_EVENT_DATA_READ_AVAIL);
+
+		if (tx_notify_bitmask & (1<<ch->num))
+			ch->notify(ch->priv,
+					   SDIO_EVENT_DATA_WRITE_AVAIL);
+	}
+
+
+	if ((rx_notify_bitmask == 0) && (tx_notify_bitmask == 0) &&
+	    !any_read_avail && !any_write_pending) {
+		DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":Nothing to "
+				"Notify for card %d, is_closing=%d\n",
+				sdio_al_dev->host->index, is_closing);
+		if (is_closing)
+			restart_inactive_time(sdio_al_dev);
+		else if (is_inactive_time_expired(sdio_al_dev))
+			sdio_al_sleep(sdio_al_dev, host);
+	} else {
+		DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":Notify bitmask"
+				" for card %d rx=0x%x, tx=0x%x.\n",
+				sdio_al_dev->host->index,
+				rx_notify_bitmask, tx_notify_bitmask);
+		/* Restart inactivity timer if any activity on the channel */
+		restart_inactive_time(sdio_al_dev);
+	}
+
+	pr_debug(MODULE_NAME ":end %s.\n", __func__);
+
+exit_err:
+	return ret;
+}
+
+/**
+ *  Check pending rx packet when reading the mailbox.
+ */
+static u32 check_pending_rx_packet(struct sdio_channel *ch, u32 eot)
+{
+	u32 rx_pending;
+	u32 rx_avail;
+	u32 new_packet_size = 0;
+	struct sdio_al_device *sdio_al_dev = ch->sdio_al_dev;
+
+
+	if (sdio_al_dev == NULL) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": NULL sdio_al_dev"
+				" for channel %s\n", ch->name);
+		return -EINVAL;
+	}
+
+	mutex_lock(&ch->ch_lock);
+
+	rx_pending = ch->rx_pending_bytes;
+	rx_avail = sdio_al_dev->mailbox->pipe_bytes_avail[ch->rx_pipe_index];
+
+	pr_debug(MODULE_NAME ":pipe %d of card %d rx_avail=0x%x, "
+			     "rx_pending=0x%x\n",
+	   ch->rx_pipe_index, sdio_al_dev->host->index, rx_avail,
+		 rx_pending);
+
+
+	/* new packet detected */
+	if (eot & (1<<ch->rx_pipe_index)) {
+		struct rx_packet_size *p = NULL;
+		new_packet_size = rx_avail - rx_pending;
+
+		if ((rx_avail <= rx_pending)) {
+			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
+					": Invalid new packet size."
+					" rx_avail=%d.\n", rx_avail);
+			new_packet_size = 0;
+			goto exit_err;
+		}
+
+		p = kzalloc(sizeof(*p), GFP_KERNEL);
+		if (p == NULL) {
+			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
+					": failed to allocate item for "
+					"rx_pending list. rx_avail=%d, "
+					"rx_pending=%d.\n",
+					rx_avail, rx_pending);
+			new_packet_size = 0;
+			goto exit_err;
+		}
+		p->size = new_packet_size;
+		/* Add new packet as last */
+		list_add_tail(&p->list, &ch->rx_size_list_head);
+		ch->rx_pending_bytes += new_packet_size;
+
+		if (ch->read_avail == 0)
+			ch->read_avail = new_packet_size;
+	}
+
+exit_err:
+	mutex_unlock(&ch->ch_lock);
+
+	return new_packet_size;
+}
+
+
+
+/**
+ *  Remove first pending packet from the list.
+ */
+static u32 remove_handled_rx_packet(struct sdio_channel *ch)
+{
+	struct rx_packet_size *p = NULL;
+
+	mutex_lock(&ch->ch_lock);
+
+	ch->rx_pending_bytes -= ch->read_avail;
+
+	if (!list_empty(&ch->rx_size_list_head)) {
+		p = list_first_entry(&ch->rx_size_list_head,
+			struct rx_packet_size, list);
+		list_del(&p->list);
+		kfree(p);
+	} else {
+		sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":%s: ch "
+				"%s: unexpected empty list!!\n",
+				__func__, ch->name);
+	}
+
+	if (list_empty(&ch->rx_size_list_head))	{
+		ch->read_avail = 0;
+	} else {
+		p = list_first_entry(&ch->rx_size_list_head,
+			struct rx_packet_size, list);
+		ch->read_avail = p->size;
+	}
+
+	mutex_unlock(&ch->ch_lock);
+
+	return ch->read_avail;
+}
+
+
+/**
+ *  Bootloader worker function.
+ *
+ *  @note: clear the bootloader_done flag only after reading the
+ *  mailbox, to ignore more requests while reading the mailbox.
+ */
+static void boot_worker(struct work_struct *work)
+{
+	int ret = 0;
+	int func_num = 0;
+	int i;
+	struct sdio_al_device *sdio_al_dev = NULL;
+	struct sdio_al_work *sdio_al_work = container_of(work,
+							 struct sdio_al_work,
+							 work);
+
+	if (sdio_al_work == NULL) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
+				"sdio_al_work\n", __func__);
+		return;
+	}
+
+	sdio_al_dev = sdio_al_work->sdio_al_dev;
+	if (sdio_al_dev == NULL) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
+				"sdio_al_dev\n", __func__);
+		return;
+	}
+	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":Bootloader Worker Started"
+			", wait for bootloader_done event..\n");
+	wait_event(sdio_al_dev->wait_mbox,
+		   sdio_al_dev->bootloader_done);
+	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":Got bootloader_done "
+			"event..\n");
+	/* Do polling until MDM is up */
+	for (i = 0; i < 5000; ++i) {
+		if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
+			return;
+		if (is_user_irq_enabled(sdio_al_dev, func_num)) {
+			sdio_al_release_mutex(sdio_al_dev, __func__);
+			sdio_al_dev->bootloader_done = 0;
+			ret = sdio_al_client_setup(sdio_al_dev);
+			if (ret) {
+				sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
+					": sdio_al_client_setup failed, "
+					"for card %d ret=%d\n",
+					sdio_al_dev->host->index, ret);
+				sdio_al_get_into_err_state(sdio_al_dev);
+			}
+			goto done;
+		}
+		sdio_al_release_mutex(sdio_al_dev, __func__);
+		msleep(100);
+	}
+	sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Timeout waiting for "
+			"user_irq for card %d\n",
+			sdio_al_dev->host->index);
+	sdio_al_get_into_err_state(sdio_al_dev);
+
+done:
+	pr_debug(MODULE_NAME ":Boot Worker for card %d Exit!\n",
+		sdio_al_dev->host->index);
+}
+
+/**
+ *  Worker function.
+ *
+ *  @note: clear the ask_mbox flag only after
+ *  	 reading the mailbox, to ignore more requests while
+ *  	 reading the mailbox.
+ */
+static void worker(struct work_struct *work)
+{
+	int ret = 0;
+	struct sdio_al_device *sdio_al_dev = NULL;
+	struct sdio_al_work *sdio_al_work = container_of(work,
+							 struct sdio_al_work,
+							 work);
+	if (sdio_al_work == NULL) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": worker: NULL "
+				"sdio_al_work\n");
+		return;
+	}
+
+	sdio_al_dev = sdio_al_work->sdio_al_dev;
+	if (sdio_al_dev == NULL) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": worker: NULL "
+				"sdio_al_dev\n");
+		return;
+	}
+	pr_debug(MODULE_NAME ":Worker Started..\n");
+	while ((sdio_al_dev->is_ready) && (ret == 0)) {
+		pr_debug(MODULE_NAME ":Wait for read mailbox request..\n");
+		wait_event(sdio_al_dev->wait_mbox, sdio_al_dev->ask_mbox);
+		if (!sdio_al_dev->is_ready)
+			break;
+		if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
+			break;
+		if (sdio_al_dev->is_ok_to_sleep) {
+			ret = sdio_al_wake_up(sdio_al_dev, 1, NULL);
+			if (ret) {
+				sdio_al_release_mutex(sdio_al_dev, __func__);
+				return;
+			}
+		}
+		ret = read_mailbox(sdio_al_dev, false);
+		sdio_al_release_mutex(sdio_al_dev, __func__);
+		sdio_al_dev->ask_mbox = false;
+	}
+
+	pr_debug(MODULE_NAME ":Worker Exit!\n");
+}
+
+/**
+ *  Write command using CMD54 rather than CMD53.
+ *  Writing with CMD54 generate EOT interrupt at the
+ *  SDIO-Client.
+ *  Based on mmc_io_rw_extended()
+ */
+static int sdio_write_cmd54(struct mmc_card *card, unsigned fn,
+	unsigned addr, const u8 *buf,
+	unsigned blocks, unsigned blksz)
+{
+	struct mmc_request mrq;
+	struct mmc_command cmd;
+	struct mmc_data data;
+	struct scatterlist sg;
+	int incr_addr = 1; /* MUST */
+	int write = 1;
+
+	BUG_ON(!card);
+	BUG_ON(fn > 7);
+	BUG_ON(blocks == 1 && blksz > 512);
+	WARN_ON(blocks == 0);
+	WARN_ON(blksz == 0);
+
+	write = true;
+	pr_debug(MODULE_NAME ":sdio_write_cmd54()"
+		"fn=%d,buf=0x%x,blocks=%d,blksz=%d\n",
+		fn, (u32) buf, blocks, blksz);
+
+	memset(&mrq, 0, sizeof(struct mmc_request));
+	memset(&cmd, 0, sizeof(struct mmc_command));
+	memset(&data, 0, sizeof(struct mmc_data));
+
+	mrq.cmd = &cmd;
+	mrq.data = &data;
+
+	cmd.opcode = SD_IO_RW_EXTENDED_QCOM;
+
+	cmd.arg = write ? 0x80000000 : 0x00000000;
+	cmd.arg |= fn << 28;
+	cmd.arg |= incr_addr ? 0x04000000 : 0x00000000;
+	cmd.arg |= addr << 9;
+	if (blocks == 1 && blksz <= 512)
+		cmd.arg |= (blksz == 512) ? 0 : blksz;  /* byte mode */
+	else
+		cmd.arg |= 0x08000000 | blocks; 	/* block mode */
+	cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
+
+	data.blksz = blksz;
+	data.blocks = blocks;
+	data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
+	data.sg = &sg;
+	data.sg_len = 1;
+
+	sg_init_one(&sg, buf, blksz * blocks);
+
+	mmc_set_data_timeout(&data, card);
+
+	mmc_wait_for_req(card->host, &mrq);
+
+	if (cmd.error)
+		return cmd.error;
+	if (data.error)
+		return data.error;
+
+	if (mmc_host_is_spi(card->host)) {
+		/* host driver already reported errors */
+	} else {
+		if (cmd.resp[0] & R5_ERROR) {
+			sdio_al_loge(&sdio_al->gen_log, MODULE_NAME
+						":%s: R5_ERROR for card %d",
+						__func__, card->host->index);
+			return -EIO;
+		}
+		if (cmd.resp[0] & R5_FUNCTION_NUMBER) {
+			sdio_al_loge(&sdio_al->gen_log, MODULE_NAME
+						":%s: R5_FUNCTION_NUMBER for card %d",
+						__func__, card->host->index);
+			return -EINVAL;
+		}
+		if (cmd.resp[0] & R5_OUT_OF_RANGE) {
+			sdio_al_loge(&sdio_al->gen_log, MODULE_NAME
+						":%s: R5_OUT_OF_RANGE for card %d",
+						__func__, card->host->index);
+			return -ERANGE;
+		}
+	}
+
+	return 0;
+}
+
+
+/**
+ *  Write data to channel.
+ *  Handle different data size types.
+ *
+ */
+static int sdio_ch_write(struct sdio_channel *ch, const u8 *buf, u32 len)
+{
+	int ret = 0;
+	unsigned blksz = ch->func->cur_blksize;
+	int blocks = len / blksz;
+	int remain_bytes = len % blksz;
+	struct mmc_card *card = NULL;
+	u32 fn = ch->func->num;
+
+	if (!ch) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
+				"channel\n", __func__);
+		return -ENODEV;
+	}
+
+	if (!ch->sdio_al_dev) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
+				"sdio_al_dev\n", __func__);
+		return -ENODEV;
+	}
+
+	if (len == 0) {
+		sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":channel "
+				"%s trying to write 0 bytes\n", ch->name);
+		return -EINVAL;
+	}
+
+	card = ch->func->card;
+
+	if (remain_bytes) {
+		/* CMD53 */
+		if (blocks) {
+			ret = sdio_memcpy_toio(ch->func, PIPE_TX_FIFO_ADDR,
+					       (void *) buf, blocks*blksz);
+			if (ret != 0) {
+				sdio_al_loge(ch->sdio_al_dev->dev_log,
+					MODULE_NAME ":%s: sdio_memcpy_toio "
+					"failed for channel %s\n",
+					__func__, ch->name);
+				sdio_al_get_into_err_state(ch->sdio_al_dev);
+				return ret;
+			}
+		}
+
+		buf += (blocks*blksz);
+
+		ret = sdio_write_cmd54(card, fn, PIPE_TX_FIFO_ADDR,
+				buf, 1, remain_bytes);
+	} else {
+		ret = sdio_write_cmd54(card, fn, PIPE_TX_FIFO_ADDR,
+				buf, blocks, blksz);
+	}
+
+	if (ret != 0) {
+		sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":%s: "
+				"sdio_write_cmd54 failed for channel %s\n",
+				__func__, ch->name);
+		ch->sdio_al_dev->is_err = true;
+		return ret;
+	}
+
+	return ret;
+}
+
+static int sdio_al_bootloader_completed(void)
+{
+	int i;
+
+	pr_debug(MODULE_NAME ":sdio_al_bootloader_completed was called\n");
+
+	for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
+		struct sdio_al_device *dev = NULL;
+		if (sdio_al->devices[i] == NULL)
+			continue;
+		dev = sdio_al->devices[i];
+		dev->bootloader_done = 1;
+		wake_up(&dev->wait_mbox);
+	}
+
+	return 0;
+}
+
+static int sdio_al_wait_for_bootloader_comp(struct sdio_al_device *sdio_al_dev)
+{
+	int ret = 0;
+
+	if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
+		return -ENODEV;
+
+	/*
+	 * Enable function 0 interrupt mask to allow 9k to raise this interrupt
+	 * in power-up. When sdio_downloader will notify its completion
+	 * we will poll on this interrupt to wait for 9k power-up
+	 */
+	ret = enable_mask_irq(sdio_al_dev, 0, 1, 0);
+	if (ret) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
+				": Enable_mask_irq for card %d failed, "
+				"ret=%d\n",
+				sdio_al_dev->host->index, ret);
+		sdio_al_release_mutex(sdio_al_dev, __func__);
+		return ret;
+	}
+
+	sdio_al_release_mutex(sdio_al_dev, __func__);
+
+	/*
+	 * Start bootloader worker that will wait for the bootloader
+	 * completion
+	 */
+	sdio_al_dev->boot_work.sdio_al_dev = sdio_al_dev;
+	INIT_WORK(&sdio_al_dev->boot_work.work, boot_worker);
+	sdio_al_dev->bootloader_done = 0;
+	queue_work(sdio_al_dev->workqueue, &sdio_al_dev->boot_work.work);
+
+	return 0;
+}
+
+static int sdio_al_bootloader_setup(void)
+{
+	int ret = 0;
+	struct sdio_al_device *bootloader_dev = sdio_al->bootloader_dev;
+	struct sdio_func *func1 = NULL;
+
+	if (sdio_al_claim_mutex_and_verify_dev(bootloader_dev, __func__))
+		return -ENODEV;
+
+	if (bootloader_dev->flashless_boot_on) {
+		sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":Already "
+			"in boot process.\n");
+		sdio_al_release_mutex(bootloader_dev, __func__);
+		return 0;
+	}
+
+	bootloader_dev->sdioc_boot_sw_header
+		= kzalloc(sizeof(*bootloader_dev->sdioc_boot_sw_header),
+			  GFP_KERNEL);
+	if (bootloader_dev->sdioc_boot_sw_header == NULL) {
+		sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":fail to "
+			"allocate sdioc boot sw header.\n");
+		sdio_al_release_mutex(bootloader_dev, __func__);
+		return -ENOMEM;
+	}
+
+	if (sdio_al_verify_func1(bootloader_dev, __func__)) {
+		sdio_al_release_mutex(bootloader_dev, __func__);
+		goto exit_err;
+	}
+	func1 = bootloader_dev->card->sdio_func[0];
+
+	ret = sdio_memcpy_fromio(func1,
+				 bootloader_dev->sdioc_boot_sw_header,
+				 SDIOC_SW_HEADER_ADDR,
+				 sizeof(struct peer_sdioc_boot_sw_header));
+	if (ret) {
+		sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":fail to "
+			"read sdioc boot sw header.\n");
+		sdio_al_release_mutex(bootloader_dev, __func__);
+		goto exit_err;
+	}
+
+	if (bootloader_dev->sdioc_boot_sw_header->signature !=
+	    (u32) PEER_SDIOC_SW_MAILBOX_BOOT_SIGNATURE) {
+		sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":invalid "
+			"mailbox signature 0x%x.\n",
+			bootloader_dev->sdioc_boot_sw_header->signature);
+		sdio_al_release_mutex(bootloader_dev, __func__);
+		ret = -EINVAL;
+		goto exit_err;
+	}
+
+	/* Upper byte has to be equal - no backward compatibility for unequal */
+	if ((bootloader_dev->sdioc_boot_sw_header->version >> 16) !=
+	    (sdio_al->pdata->peer_sdioc_boot_version_major)) {
+		sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ": HOST(0x%x)"
+			" and CLIENT(0x%x) SDIO_AL BOOT VERSION don't match\n",
+			((sdio_al->pdata->peer_sdioc_boot_version_major<<16)+
+			sdio_al->pdata->peer_sdioc_boot_version_minor),
+			bootloader_dev->sdioc_boot_sw_header->version);
+		sdio_al_release_mutex(bootloader_dev, __func__);
+		ret = -EIO;
+		goto exit_err;
+	}
+
+	sdio_al_logi(bootloader_dev->dev_log, MODULE_NAME ": SDIOC BOOT SW "
+			"version 0x%x\n",
+			bootloader_dev->sdioc_boot_sw_header->version);
+
+	bootloader_dev->flashless_boot_on = true;
+
+	sdio_al_release_mutex(bootloader_dev, __func__);
+
+	ret = sdio_al_wait_for_bootloader_comp(bootloader_dev);
+	if (ret) {
+		sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME
+				": sdio_al_wait_for_bootloader_comp failed, "
+				"err=%d\n", ret);
+		goto exit_err;
+	}
+
+	ret = sdio_downloader_setup(bootloader_dev->card, 1,
+			bootloader_dev->sdioc_boot_sw_header->boot_ch_num,
+			sdio_al_bootloader_completed);
+
+	if (ret) {
+		sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME
+			": sdio_downloader_setup failed, err=%d\n", ret);
+		goto exit_err;
+	}
+
+	sdio_al_logi(bootloader_dev->dev_log, MODULE_NAME ":In Flashless boot,"
+		" waiting for its completion\n");
+
+
+exit_err:
+	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":free "
+			"sdioc_boot_sw_header.\n");
+	kfree(bootloader_dev->sdioc_boot_sw_header);
+	bootloader_dev->sdioc_boot_sw_header = NULL;
+	bootloader_dev = NULL;
+
+	return ret;
+}
+
+
+/**
+ *  Read SDIO-Client software header
+ *
+ */
+static int read_sdioc_software_header(struct sdio_al_device *sdio_al_dev,
+				      struct peer_sdioc_sw_header *header)
+{
+	int ret;
+	int i;
+	int test_version = 0;
+	int sdioc_test_version = 0;
+	struct sdio_func *func1 = NULL;
+
+	pr_debug(MODULE_NAME ":reading sdioc sw header.\n");
+
+	if (sdio_al_verify_func1(sdio_al_dev, __func__))
+		return -ENODEV;
+
+	func1 = sdio_al_dev->card->sdio_func[0];
+
+	ret = sdio_memcpy_fromio(func1, header,
+			SDIOC_SW_HEADER_ADDR, sizeof(*header));
+	if (ret) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":fail to read "
+				"sdioc sw header.\n");
+		goto exit_err;
+	}
+
+	if (header->signature == (u32)PEER_SDIOC_SW_MAILBOX_UT_SIGNATURE) {
+		sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":SDIOC SW "
+				"unittest signature. 0x%x\n",
+				header->signature);
+		sdio_al->unittest_mode = true;
+		/* Verify test code compatibility with the modem */
+		sdioc_test_version = (header->version & 0xFF00) >> 8;
+		test_version = sdio_al->pdata->peer_sdioc_version_minor >> 8;
+		if (test_version != sdioc_test_version) {
+			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
+				": HOST(0x%x) and CLIENT(0x%x) "
+				"testing VERSION don't match\n",
+				test_version,
+				sdioc_test_version);
+			msleep(500);
+			BUG();
+		}
+	}
+
+	if ((header->signature != (u32) PEER_SDIOC_SW_MAILBOX_SIGNATURE) &&
+	    (header->signature != (u32) PEER_SDIOC_SW_MAILBOX_UT_SIGNATURE)) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":SDIOC SW "
+				"invalid signature. 0x%x\n", header->signature);
+		goto exit_err;
+	}
+	/* Upper byte has to be equal - no backward compatibility for unequal */
+	sdio_al->sdioc_major = header->version >> 16;
+	if (sdio_al->pdata->allow_sdioc_version_major_2) {
+		if ((sdio_al->sdioc_major !=
+		    sdio_al->pdata->peer_sdioc_version_major) &&
+		    (sdio_al->sdioc_major != PEER_SDIOC_OLD_VERSION_MAJOR)) {
+			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
+				": HOST(0x%x) and CLIENT(0x%x) "
+				"SDIO_AL VERSION don't match\n",
+				((sdio_al->pdata->peer_sdioc_version_major<<16)+
+				sdio_al->pdata->peer_sdioc_version_minor),
+				header->version);
+			goto exit_err;
+		}
+	} else {
+		if (sdio_al->sdioc_major !=
+		    sdio_al->pdata->peer_sdioc_version_major) {
+			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
+				": HOST(0x%x) and CLIENT(0x%x) "
+				"SDIO_AL VERSION don't match\n",
+				((sdio_al->pdata->peer_sdioc_version_major<<16)+
+				sdio_al->pdata->peer_sdioc_version_minor),
+				header->version);
+			goto exit_err;
+		}
+	}
+	sdio_al_dev->ch_close_supported = (header->version & 0x000F) >=
+		(sdio_al->pdata->peer_sdioc_version_minor & 0xF);
+
+	sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":SDIOC SW version 0x%x,"
+			" sdio_al major 0x%x minor 0x%x\n", header->version,
+			sdio_al->sdioc_major,
+			sdio_al->pdata->peer_sdioc_version_minor);
+
+	sdio_al_dev->flashless_boot_on = false;
+	for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
+		struct sdio_channel *ch = &sdio_al_dev->channel[i];
+
+		/* Set default values */
+		ch->read_threshold  = DEFAULT_READ_THRESHOLD;
+		ch->write_threshold = DEFAULT_WRITE_THRESHOLD;
+		ch->min_write_avail = DEFAULT_MIN_WRITE_THRESHOLD;
+		ch->is_packet_mode = true;
+		ch->peer_tx_buf_size = DEFAULT_PEER_TX_BUF_SIZE;
+		ch->poll_delay_msec = 0;
+
+		ch->num = i;
+		ch->func = NULL;
+		ch->rx_pipe_index = ch->num*2;
+		ch->tx_pipe_index = ch->num*2+1;
+
+		memset(ch->name, 0, sizeof(ch->name));
+
+		if (header->channel_names[i][0]) {
+			memcpy(ch->name, SDIO_PREFIX,
+			       strlen(SDIO_PREFIX));
+			memcpy(ch->name + strlen(SDIO_PREFIX),
+			       header->channel_names[i],
+			       PEER_CHANNEL_NAME_SIZE);
+
+			ch->state = SDIO_CHANNEL_STATE_IDLE;
+			ch->sdio_al_dev = sdio_al_dev;
+			if (sdio_al_dev->card->sdio_func[ch->num+1]) {
+				ch->func =
+				sdio_al_dev->card->sdio_func[ch->num+1];
+			} else {
+				sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
+					": NULL func for channel %s\n",
+					ch->name);
+				goto exit_err;
+			}
+		} else {
+			ch->state = SDIO_CHANNEL_STATE_INVALID;
+		}
+
+		sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":Channel=%s, "
+				"state=%d\n", ch->name,	ch->state);
+	}
+
+	return 0;
+
+exit_err:
+	sdio_al_get_into_err_state(sdio_al_dev);
+	memset(header, 0, sizeof(*header));
+
+	return -EIO;
+}
+
+/**
+ *  Read SDIO-Client channel configuration
+ *
+ */
+static int read_sdioc_channel_config(struct sdio_channel *ch)
+{
+	int ret;
+	struct peer_sdioc_sw_mailbox *sw_mailbox = NULL;
+	struct peer_sdioc_channel_config *ch_config = NULL;
+	struct sdio_al_device *sdio_al_dev = ch->sdio_al_dev;
+
+	if (sdio_al_dev == NULL) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": NULL sdio_al_dev"
+				" for channel %s\n", ch->name);
+		return -EINVAL;
+	}
+
+	if (sdio_al_dev->sdioc_sw_header->version == 0)
+		return -1;
+
+	pr_debug(MODULE_NAME ":reading sw mailbox %s channel.\n", ch->name);
+
+	sw_mailbox = kzalloc(sizeof(*sw_mailbox), GFP_KERNEL);
+	if (sw_mailbox == NULL)
+		return -ENOMEM;
+
+	ret = sdio_memcpy_fromio(ch->func, sw_mailbox,
+			SDIOC_SW_MAILBOX_ADDR, sizeof(*sw_mailbox));
+	if (ret) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":fail to read "
+				"sw mailbox.\n");
+		goto exit_err;
+	}
+
+	ch_config = &sw_mailbox->ch_config[ch->num];
+	memcpy(&ch->ch_config, ch_config,
+		sizeof(struct peer_sdioc_channel_config));
+
+	if (!ch_config->is_ready) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sw mailbox "
+				"channel not ready.\n");
+		goto exit_err;
+	}
+
+	ch->read_threshold = LOW_LATENCY_THRESHOLD;
+	ch->is_low_latency_ch = ch_config->is_low_latency_ch;
+	/* Threshold on 50% of the maximum size , sdioc uses double-buffer */
+	ch->write_threshold = (ch_config->max_tx_threshold * 5) / 10;
+	ch->threshold_change_cnt = ch->ch_config.max_rx_threshold -
+			ch->read_threshold + THRESHOLD_CHANGE_EXTRA_BYTES;
+
+	if (ch->is_low_latency_ch)
+		ch->def_read_threshold = LOW_LATENCY_THRESHOLD;
+	else /* Aggregation up to 90% of the maximum size */
+		ch->def_read_threshold = (ch_config->max_rx_threshold * 9) / 10;
+
+	ch->is_packet_mode = ch_config->is_packet_mode;
+	if (!ch->is_packet_mode) {
+		ch->poll_delay_msec = DEFAULT_POLL_DELAY_NOPACKET_MSEC;
+		ch->min_write_avail = DEFAULT_MIN_WRITE_THRESHOLD_STREAMING;
+	}
+	/* The max_packet_size is set by the modem in version 3 and on */
+	if (sdio_al->sdioc_major > PEER_SDIOC_OLD_VERSION_MAJOR)
+		ch->min_write_avail = ch_config->max_packet_size;
+
+	if (ch->min_write_avail > ch->write_threshold)
+		ch->min_write_avail = ch->write_threshold;
+
+	CLOSE_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":ch %s "
+			"read_threshold=%d, write_threshold=%d,"
+			" min_write_avail=%d, max_rx_threshold=%d,"
+			" max_tx_threshold=%d\n", ch->name, ch->read_threshold,
+			ch->write_threshold, ch->min_write_avail,
+			ch_config->max_rx_threshold,
+			ch_config->max_tx_threshold);
+
+	ch->peer_tx_buf_size = ch_config->tx_buf_size;
+
+	kfree(sw_mailbox);
+
+	return 0;
+
+exit_err:
+	sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":Reading SW Mailbox "
+			"error.\n");
+	kfree(sw_mailbox);
+
+	return -1;
+}
+
+
+/**
+ *  Enable/Disable EOT interrupt of a pipe.
+ *
+ */
+static int enable_eot_interrupt(struct sdio_al_device *sdio_al_dev,
+				int pipe_index, int enable)
+{
+	int ret = 0;
+	struct sdio_func *func1;
+	u32 mask;
+	u32 pipe_mask;
+	u32 addr;
+
+	if (sdio_al_verify_func1(sdio_al_dev, __func__))
+		return -ENODEV;
+	func1 = sdio_al_dev->card->sdio_func[0];
+
+	if (pipe_index < 8) {
+		addr = PIPES_0_7_IRQ_MASK_ADDR;
+		pipe_mask = (1<<pipe_index);
+	} else {
+		addr = PIPES_8_15_IRQ_MASK_ADDR;
+		pipe_mask = (1<<(pipe_index-8));
+	}
+
+	mask = sdio_readl(func1, addr, &ret);
+	if (ret) {
+		pr_debug(MODULE_NAME ":enable_eot_interrupt fail\n");
+		goto exit_err;
+	}
+
+	if (enable)
+		mask &= (~pipe_mask); /* 0 = enable */
+	else
+		mask |= (pipe_mask);  /* 1 = disable */
+
+	sdio_writel(func1, mask, addr, &ret);
+
+exit_err:
+	return ret;
+}
+
+
+/**
+ *  Enable/Disable mask interrupt of a function.
+ *
+ */
+static int enable_mask_irq(struct sdio_al_device *sdio_al_dev,
+			   int func_num, int enable, u8 bit_offset)
+{
+	int ret = 0;
+	struct sdio_func *func1 = NULL;
+	u32 mask = 0;
+	u32 func_mask = 0;
+	u32 addr = 0;
+	u32 offset = 0;
+
+	if (sdio_al_verify_func1(sdio_al_dev, __func__))
+		return -ENODEV;
+	func1 = sdio_al_dev->card->sdio_func[0];
+
+	if (func_num < 4) {
+		addr = FUNC_1_4_MASK_IRQ_ADDR;
+		offset = func_num * 8 + bit_offset;
+	} else {
+		addr = FUNC_5_7_MASK_IRQ_ADDR;
+		offset = (func_num - 4) * 8 + bit_offset;
+	}
+
+	func_mask = 1<<offset;
+
+	mask = sdio_readl(func1, addr, &ret);
+	if (ret) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
+				"enable_mask_irq fail\n");
+		goto exit_err;
+	}
+
+	if (enable)
+		mask &= (~func_mask); /* 0 = enable */
+	else
+		mask |= (func_mask);  /* 1 = disable */
+
+	pr_debug(MODULE_NAME ":enable_mask_irq,  writing mask = 0x%x\n", mask);
+
+	sdio_writel(func1, mask, addr, &ret);
+
+exit_err:
+	return ret;
+}
+
+/**
+ *  Enable/Disable Threshold interrupt of a pipe.
+ *
+ */
+static int enable_threshold_interrupt(struct sdio_al_device *sdio_al_dev,
+				      int pipe_index, int enable)
+{
+	int ret = 0;
+	struct sdio_func *func1;
+	u32 mask;
+	u32 pipe_mask;
+	u32 addr;
+
+	if (sdio_al_verify_func1(sdio_al_dev, __func__))
+		return -ENODEV;
+	func1 = sdio_al_dev->card->sdio_func[0];
+
+	if (pipe_index < 8) {
+		addr = PIPES_0_7_IRQ_MASK_ADDR;
+		pipe_mask = (1<<pipe_index);
+	} else {
+		addr = PIPES_8_15_IRQ_MASK_ADDR;
+		pipe_mask = (1<<(pipe_index-8));
+	}
+
+	mask = sdio_readl(func1, addr, &ret);
+	if (ret) {
+		pr_debug(MODULE_NAME ":enable_threshold_interrupt fail\n");
+		goto exit_err;
+	}
+
+	pipe_mask = pipe_mask<<8; /* Threshold bits 8..15 */
+	if (enable)
+		mask &= (~pipe_mask); /* 0 = enable */
+	else
+		mask |= (pipe_mask);  /* 1 = disable */
+
+	sdio_writel(func1, mask, addr, &ret);
+
+exit_err:
+	return ret;
+}
+
+/**
+ *  Set the threshold to trigger interrupt from SDIO-Card on
+ *  pipe available bytes.
+ *
+ */
+static int set_pipe_threshold(struct sdio_al_device *sdio_al_dev,
+			      int pipe_index, int threshold)
+{
+	int ret = 0;
+	struct sdio_func *func1;
+
+	if (sdio_al_verify_func1(sdio_al_dev, __func__))
+		return -ENODEV;
+	func1 = sdio_al_dev->card->sdio_func[0];
+
+	sdio_writel(func1, threshold,
+			PIPES_THRESHOLD_ADDR+pipe_index*4, &ret);
+	if (ret)
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
+				"set_pipe_threshold err=%d\n", -ret);
+
+	return ret;
+}
+
+/**
+ *  Enable func w/ retries
+ *
+ */
+static int sdio_al_enable_func_retry(struct sdio_func *func, const char *name)
+{
+	int ret, i;
+	for (i = 0; i < 200; i++) {
+		ret = sdio_enable_func(func);
+		if (ret) {
+			pr_debug(MODULE_NAME ":retry enable %s func#%d "
+					     "ret=%d\n",
+					 name, func->num, ret);
+			msleep(10);
+		} else
+			break;
+	}
+
+	return ret;
+}
+
+/**
+ *  Open Channel
+ *
+ *  1. Init Channel Context.
+ *  2. Init the Channel SDIO-Function.
+ *  3. Init the Channel Pipes on Mailbox.
+ */
+static int open_channel(struct sdio_channel *ch)
+{
+	int ret = 0;
+	struct sdio_al_device *sdio_al_dev = ch->sdio_al_dev;
+
+	if (sdio_al_dev == NULL) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": NULL "
+				"sdio_al_dev for channel %s\n", ch->name);
+		return -EINVAL;
+	}
+
+	/* Init channel Context */
+	/** Func#1 is reserved for mailbox */
+	ch->func = sdio_al_dev->card->sdio_func[ch->num+1];
+	ch->rx_pipe_index = ch->num*2;
+	ch->tx_pipe_index = ch->num*2+1;
+	ch->signature = SDIO_AL_SIGNATURE;
+
+	ch->total_rx_bytes = 0;
+	ch->total_tx_bytes = 0;
+
+	ch->write_avail = 0;
+	ch->read_avail = 0;
+	ch->rx_pending_bytes = 0;
+
+	mutex_init(&ch->ch_lock);
+
+	pr_debug(MODULE_NAME ":open_channel %s func#%d\n",
+			 ch->name, ch->func->num);
+
+	INIT_LIST_HEAD(&(ch->rx_size_list_head));
+
+	/* Init SDIO Function */
+	ret = sdio_al_enable_func_retry(ch->func, ch->name);
+	if (ret) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
+				"sdio_enable_func() err=%d\n", -ret);
+		goto exit_err;
+	}
+
+	/* Note: Patch Func CIS tuple issue */
+	ret = sdio_set_block_size(ch->func, SDIO_AL_BLOCK_SIZE);
+	if (ret) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
+				"sdio_set_block_size()failed, err=%d\n", -ret);
+		goto exit_err;
+	}
+
+	ch->func->max_blksize = SDIO_AL_BLOCK_SIZE;
+
+	sdio_set_drvdata(ch->func, ch);
+
+	/* Get channel parameters from the peer SDIO-Client */
+	read_sdioc_channel_config(ch);
+
+	/* Set Pipes Threshold on Mailbox */
+	ret = set_pipe_threshold(sdio_al_dev,
+				 ch->rx_pipe_index, ch->read_threshold);
+	if (ret)
+		goto exit_err;
+	ret = set_pipe_threshold(sdio_al_dev,
+				 ch->tx_pipe_index, ch->write_threshold);
+	if (ret)
+		goto exit_err;
+
+	/* Set flag before interrupts are enabled to allow notify */
+	ch->state = SDIO_CHANNEL_STATE_OPEN;
+	pr_debug(MODULE_NAME ":channel %s is in OPEN state now\n", ch->name);
+
+	sdio_al_dev->poll_delay_msec = get_min_poll_time_msec(sdio_al_dev);
+
+	/* lpm mechanism lives under the assumption there is always a timer */
+	/* Check if need to start the timer */
+	if  ((sdio_al_dev->poll_delay_msec) &&
+	     (sdio_al_dev->is_timer_initialized == false)) {
+
+		init_timer(&sdio_al_dev->timer);
+		sdio_al_dev->timer.data = (unsigned long) sdio_al_dev;
+		sdio_al_dev->timer.function = sdio_al_timer_handler;
+		sdio_al_dev->timer.expires = jiffies +
+			msecs_to_jiffies(sdio_al_dev->poll_delay_msec);
+		add_timer(&sdio_al_dev->timer);
+		sdio_al_dev->is_timer_initialized = true;
+	}
+
+	/* Enable Pipes Interrupts */
+	enable_eot_interrupt(sdio_al_dev, ch->rx_pipe_index, true);
+	enable_eot_interrupt(sdio_al_dev, ch->tx_pipe_index, true);
+
+	enable_threshold_interrupt(sdio_al_dev, ch->rx_pipe_index, true);
+	enable_threshold_interrupt(sdio_al_dev, ch->tx_pipe_index, true);
+
+exit_err:
+
+	return ret;
+}
+
+/**
+ *  Ask the worker to read the mailbox.
+ */
+static void ask_reading_mailbox(struct sdio_al_device *sdio_al_dev)
+{
+	if (!sdio_al_dev->ask_mbox) {
+		pr_debug(MODULE_NAME ":ask_reading_mailbox for card %d\n",
+			 sdio_al_dev->host->index);
+		sdio_al_dev->ask_mbox = true;
+		wake_up(&sdio_al_dev->wait_mbox);
+	}
+}
+
+/**
+ *  Start the timer
+ */
+static void start_timer(struct sdio_al_device *sdio_al_dev)
+{
+	if ((sdio_al_dev->poll_delay_msec)  &&
+		(sdio_al_dev->state == CARD_INSERTED)) {
+		sdio_al_dev->timer.expires = jiffies +
+			msecs_to_jiffies(sdio_al_dev->poll_delay_msec);
+		add_timer(&sdio_al_dev->timer);
+	}
+}
+
+/**
+ *  Restart(postpone) the already working timer
+ */
+static void restart_timer(struct sdio_al_device *sdio_al_dev)
+{
+	if ((sdio_al_dev->poll_delay_msec) &&
+		(sdio_al_dev->state == CARD_INSERTED)) {
+		ulong expires =	jiffies +
+			msecs_to_jiffies(sdio_al_dev->poll_delay_msec);
+		mod_timer(&sdio_al_dev->timer, expires);
+	}
+}
+
+/**
+ *  Stop and delete the timer
+ */
+static void stop_and_del_timer(struct sdio_al_device *sdio_al_dev)
+{
+	if (sdio_al_dev->is_timer_initialized) {
+		sdio_al_dev->poll_delay_msec = 0;
+		del_timer_sync(&sdio_al_dev->timer);
+	}
+}
+
+/**
+ *  Do the wakup sequence.
+ *  This function should be called after claiming the host!
+ *  The caller is responsible for releasing the host.
+ *
+ *  Wake up sequence
+ *  1. Get lock
+ *  2. Enable wake up function if needed
+ *  3. Mark NOT OK to sleep and write it
+ *  4. Restore default thresholds
+ *  5. Start the mailbox and inactivity timer again
+ */
+static int sdio_al_wake_up(struct sdio_al_device *sdio_al_dev,
+			   u32 not_from_int, struct sdio_channel *ch)
+{
+	int ret = 0;
+	struct sdio_func *wk_func = NULL;
+	unsigned long time_to_wait;
+	struct mmc_host *host = sdio_al_dev->host;
+
+	if (sdio_al_dev->is_err) {
+		SDIO_AL_ERR(__func__);
+		return -ENODEV;
+	}
+
+	if (!sdio_al_dev->is_ok_to_sleep) {
+		LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":card %d "
+				"already awake, no need to wake up\n",
+				sdio_al_dev->host->index);
+		return 0;
+	}
+
+	/* Wake up sequence */
+	if (not_from_int) {
+		if (ch) {
+			LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": Wake up"
+					" card %d (not by interrupt), ch %s",
+					sdio_al_dev->host->index,
+					ch->name);
+		} else {
+			LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": Wake up"
+					  " card %d (not	by interrupt)",
+					  sdio_al_dev->host->index);
+		}
+	} else {
+		LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": Wake up card "
+				"%d by interrupt",
+				sdio_al_dev->host->index);
+		sdio_al_dev->print_after_interrupt = 1;
+	}
+
+	sdio_al_vote_for_sleep(sdio_al_dev, 0);
+
+	msmsdcc_lpm_disable(host);
+	msmsdcc_set_pwrsave(host, 0);
+	/* Poll the GPIO */
+	time_to_wait = jiffies + msecs_to_jiffies(1000);
+	while (time_before(jiffies, time_to_wait)) {
+		if (sdio_al->pdata->get_mdm2ap_status())
+			break;
+		udelay(TIME_TO_WAIT_US);
+	}
+
+	pr_debug(MODULE_NAME ":GPIO mdm2ap_status=%d\n",
+		       sdio_al->pdata->get_mdm2ap_status());
+
+	/* Here get_mdm2ap_status() returning 0 is not an error condition */
+	if (sdio_al->pdata->get_mdm2ap_status() == 0)
+		LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": "
+				"get_mdm2ap_status() is 0\n");
+
+	/* Enable Wake up Function */
+	if (!sdio_al_dev->card ||
+	    !sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1]) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
+				": NULL card or wk_func\n");
+		return -ENODEV;
+	}
+	wk_func = sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1];
+	ret = sdio_al_enable_func_retry(wk_func, "wakeup func");
+	if (ret) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
+				"sdio_enable_func() err=%d\n", -ret);
+		goto error_exit;
+	}
+	/* Mark NOT OK_TOSLEEP */
+	sdio_al_dev->is_ok_to_sleep = 0;
+	ret = write_lpm_info(sdio_al_dev);
+	if (ret) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
+				"write_lpm_info() failed, err=%d\n", -ret);
+		sdio_al_dev->is_ok_to_sleep = 1;
+		sdio_disable_func(wk_func);
+		goto error_exit;
+	}
+	sdio_disable_func(wk_func);
+
+	/* Start the timer again*/
+	restart_inactive_time(sdio_al_dev);
+	sdio_al_dev->poll_delay_msec = get_min_poll_time_msec(sdio_al_dev);
+	start_timer(sdio_al_dev);
+
+	LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME "Finished Wake up sequence"
+			" for card %d", sdio_al_dev->host->index);
+
+	msmsdcc_set_pwrsave(host, 1);
+	pr_debug(MODULE_NAME ":Turn clock off\n");
+
+	return ret;
+error_exit:
+	sdio_al_vote_for_sleep(sdio_al_dev, 1);
+	msmsdcc_set_pwrsave(host, 1);
+	WARN_ON(ret);
+	sdio_al_get_into_err_state(sdio_al_dev);
+	return ret;
+}
+
+
+/**
+ *  SDIO Function Interrupt handler.
+ *
+ *  Interrupt shall be triggered by SDIO-Client when:
+ *  1. End-Of-Transfer (EOT) detected in packet mode.
+ *  2. Bytes-available reached the threshold.
+ *
+ *  Reading the mailbox clears the EOT/Threshold interrupt
+ *  source.
+ *  The interrupt source should be cleared before this ISR
+ *  returns. This ISR is called from IRQ Thread and not
+ *  interrupt, so it may sleep.
+ *
+ */
+static void sdio_func_irq(struct sdio_func *func)
+{
+	struct sdio_al_device *sdio_al_dev = sdio_get_drvdata(func);
+
+	pr_debug(MODULE_NAME ":start %s.\n", __func__);
+
+	if (sdio_al_dev == NULL) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": NULL device");
+		return;
+	}
+
+	if (sdio_al_dev->is_ok_to_sleep)
+		sdio_al_wake_up(sdio_al_dev, 0, NULL);
+	else
+		restart_timer(sdio_al_dev);
+
+	read_mailbox(sdio_al_dev, true);
+
+	pr_debug(MODULE_NAME ":end %s.\n", __func__);
+}
+
+/**
+ *  Timer Expire Handler
+ *
+ */
+static void sdio_al_timer_handler(unsigned long data)
+{
+	struct sdio_al_device *sdio_al_dev = (struct sdio_al_device *)data;
+	if (sdio_al_dev == NULL) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": NULL "
+				"sdio_al_dev for data %lu\n", data);
+		return;
+	}
+	if (sdio_al_dev->state != CARD_INSERTED) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": sdio_al_dev "
+				"is in invalid state %d\n", sdio_al_dev->state);
+		return;
+	}
+	pr_debug(MODULE_NAME " Timer Expired\n");
+
+	ask_reading_mailbox(sdio_al_dev);
+
+	restart_timer(sdio_al_dev);
+}
+
+/**
+ *  Driver Setup.
+ *
+ */
+static int sdio_al_setup(struct sdio_al_device *sdio_al_dev)
+{
+	int ret = 0;
+	struct mmc_card *card = sdio_al_dev->card;
+	struct sdio_func *func1 = NULL;
+	int i = 0;
+	int fn = 0;
+
+	if (sdio_al_verify_func1(sdio_al_dev, __func__))
+		return -ENODEV;
+	func1 = card->sdio_func[0];
+
+	sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":sdio_al_setup for "
+			"card %d\n", sdio_al_dev->host->index);
+
+	ret = sdio_al->pdata->config_mdm2ap_status(1);
+	if (ret) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME "Could not "
+				"request GPIO\n");
+		return ret;
+	}
+
+	INIT_WORK(&sdio_al_dev->sdio_al_work.work, worker);
+	/* disable all pipes interrupts before claim irq.
+	   since all are enabled by default. */
+	for (i = 0 ; i < SDIO_AL_MAX_PIPES; i++) {
+		enable_eot_interrupt(sdio_al_dev, i, false);
+		enable_threshold_interrupt(sdio_al_dev, i, false);
+	}
+
+	/* Disable all SDIO Functions before claim irq. */
+	for (fn = 1 ; fn <= card->sdio_funcs; fn++)
+		sdio_disable_func(card->sdio_func[fn-1]);
+
+	sdio_set_drvdata(func1, sdio_al_dev);
+	sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":claim IRQ for card "
+			"%d\n",	sdio_al_dev->host->index);
+
+	ret = sdio_claim_irq(func1, sdio_func_irq);
+	if (ret) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to claim"
+				" IRQ for card %d\n",
+				sdio_al_dev->host->index);
+		return ret;
+	}
+
+	sdio_al_dev->is_ready = true;
+
+	/* Start worker before interrupt might happen */
+	queue_work(sdio_al_dev->workqueue, &sdio_al_dev->sdio_al_work.work);
+
+	start_inactive_time(sdio_al_dev);
+
+	pr_debug(MODULE_NAME ":Ready.\n");
+
+	return 0;
+}
+
+/**
+ *  Driver Tear-Down.
+ *
+ */
+static void sdio_al_tear_down(void)
+{
+	int i, j;
+	struct sdio_al_device *sdio_al_dev = NULL;
+	struct sdio_func *func1;
+
+	for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
+		if (sdio_al->devices[i] == NULL)
+			continue;
+		sdio_al_dev = sdio_al->devices[i];
+
+		if (sdio_al_dev->is_ready) {
+			sdio_al_dev->is_ready = false; /* Flag worker to exit */
+			sdio_al_dev->ask_mbox = false;
+			ask_reading_mailbox(sdio_al_dev); /* Wakeup worker */
+			/* allow gracefully exit of the worker thread */
+			msleep(100);
+
+			flush_workqueue(sdio_al_dev->workqueue);
+			destroy_workqueue(sdio_al_dev->workqueue);
+
+			sdio_al_vote_for_sleep(sdio_al_dev, 1);
+
+			if (!sdio_al_claim_mutex_and_verify_dev(sdio_al_dev,
+								__func__)) {
+				if (!sdio_al_dev->card ||
+				    !sdio_al_dev->card->sdio_func[0]) {
+					sdio_al_loge(sdio_al_dev->dev_log,
+						     MODULE_NAME
+							": %s: Invalid func1",
+							__func__);
+					return;
+				}
+				func1 = sdio_al_dev->card->sdio_func[0];
+				sdio_release_irq(func1);
+				sdio_disable_func(func1);
+				sdio_al_release_mutex(sdio_al_dev, __func__);
+			}
+		}
+
+		for (j = 0; j < SDIO_AL_MAX_CHANNELS; j++)
+			sdio_al_dev->channel[j].signature = 0x0;
+		sdio_al_dev->signature = 0;
+
+		kfree(sdio_al_dev->sdioc_sw_header);
+		kfree(sdio_al_dev->mailbox);
+		kfree(sdio_al_dev->rx_flush_buf);
+		kfree(sdio_al_dev);
+	}
+
+	sdio_al->pdata->config_mdm2ap_status(0);
+}
+
+/**
+ *  Find channel by name.
+ *
+ */
+static struct sdio_channel *find_channel_by_name(const char *name)
+{
+	struct sdio_channel *ch = NULL;
+	int i, j;
+	struct sdio_al_device *sdio_al_dev = NULL;
+
+	for (j = 0; j < MAX_NUM_OF_SDIO_DEVICES; ++j) {
+		if (sdio_al->devices[j] == NULL)
+			continue;
+		sdio_al_dev = sdio_al->devices[j];
+		for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
+			if (sdio_al_dev->channel[i].state ==
+					SDIO_CHANNEL_STATE_INVALID)
+				continue;
+			if (strncmp(sdio_al_dev->channel[i].name, name,
+					CHANNEL_NAME_SIZE) == 0) {
+				ch = &sdio_al_dev->channel[i];
+				break;
+			}
+		}
+		if (ch != NULL)
+			break;
+	}
+
+	return ch;
+}
+
+/**
+ *  Find the minimal poll time.
+ *
+ */
+static int get_min_poll_time_msec(struct sdio_al_device *sdio_sl_dev)
+{
+	int i;
+	int poll_delay_msec = 0x0FFFFFFF;
+
+	for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++)
+		if ((sdio_sl_dev->channel[i].state ==
+					SDIO_CHANNEL_STATE_OPEN) &&
+		(sdio_sl_dev->channel[i].poll_delay_msec > 0) &&
+		(sdio_sl_dev->channel[i].poll_delay_msec < poll_delay_msec))
+			poll_delay_msec =
+				sdio_sl_dev->channel[i].poll_delay_msec;
+
+	if (poll_delay_msec == 0x0FFFFFFF)
+		poll_delay_msec = SDIO_AL_POLL_TIME_NO_STREAMING;
+
+	pr_debug(MODULE_NAME ":poll delay time is %d msec\n", poll_delay_msec);
+
+	return poll_delay_msec;
+}
+
+/**
+ *  Open SDIO Channel.
+ *
+ *  Enable the channel.
+ *  Set the channel context.
+ *  Trigger reading the mailbox to check available bytes.
+ *
+ */
+int sdio_open(const char *name, struct sdio_channel **ret_ch, void *priv,
+		 void (*notify)(void *priv, unsigned ch_event))
+{
+	int ret = 0;
+	struct sdio_channel *ch = NULL;
+	struct sdio_al_device *sdio_al_dev = NULL;
+
+	*ret_ch = NULL; /* default */
+
+	ch = find_channel_by_name(name);
+	if (ch == NULL) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":Can't find "
+			"channel name %s\n", name);
+		return -EINVAL;
+	}
+
+	sdio_al_dev = ch->sdio_al_dev;
+	if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
+		return -ENODEV;
+
+	if ((ch->state != SDIO_CHANNEL_STATE_IDLE) &&
+		(ch->state != SDIO_CHANNEL_STATE_CLOSED)) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Wrong ch %s "
+				"state %d\n", name, ch->state);
+		ret = -EPERM;
+		goto exit_err;
+	}
+
+	if (sdio_al_dev->is_err) {
+		SDIO_AL_ERR(__func__);
+		ret = -ENODEV;
+		goto exit_err;
+	}
+
+	ret = sdio_al_wake_up(sdio_al_dev, 1, ch);
+	if (ret)
+		goto exit_err;
+
+	ch->notify = notify;
+	ch->priv = priv;
+
+	/* Note: Set caller returned context before interrupts are enabled */
+	*ret_ch = ch;
+
+	ret = open_channel(ch);
+	if (ret) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_open %s "
+				"err=%d\n", name, -ret);
+		goto exit_err;
+	}
+
+	CLOSE_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":sdio_open %s "
+							"completed OK\n", name);
+	if (sdio_al_dev->lpm_chan == INVALID_SDIO_CHAN) {
+		if (sdio_al->sdioc_major == PEER_SDIOC_OLD_VERSION_MAJOR) {
+			if (!ch->is_packet_mode) {
+				sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME
+						":setting channel %s as "
+						"lpm_chan\n", name);
+				sdio_al_dev->lpm_chan = ch->num;
+			}
+		} else {
+			sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ": "
+					"setting channel %s as lpm_chan\n",
+					name);
+			sdio_al_dev->lpm_chan = ch->num;
+		}
+	}
+
+exit_err:
+	sdio_al_release_mutex(sdio_al_dev, __func__);
+	return ret;
+}
+EXPORT_SYMBOL(sdio_open);
+
+/**
+ *  Request peer operation
+ *  note: sanity checks of parameters done by caller
+ *        called under bus locked
+ */
+static int peer_set_operation(u32 opcode,
+		struct sdio_al_device *sdio_al_dev,
+		struct sdio_channel *ch)
+{
+	int ret;
+	int offset;
+	struct sdio_func *wk_func = NULL;
+	u32 peer_operation;
+	int loop_count = 0;
+
+	if (!sdio_al_dev->card ||
+	    !sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1]) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
+				": NULL card or wk_func\n");
+		ret = -ENODEV;
+		goto exit;
+	}
+	wk_func = sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1];
+
+	/* calculate offset of peer_operation field in sw mailbox struct */
+	offset = offsetof(struct peer_sdioc_sw_mailbox, ch_config) +
+		sizeof(struct peer_sdioc_channel_config) * ch->num +
+		offsetof(struct peer_sdioc_channel_config, peer_operation);
+
+	ret = sdio_al_wake_up(sdio_al_dev, 1, ch);
+	if (ret) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to "
+				"wake up\n");
+		goto exit;
+	}
+	/* request operation from MDM peer */
+	peer_operation = PEER_OPERATION(opcode, PEER_OP_STATE_INIT);
+	ret = sdio_memcpy_toio(ch->func, SDIOC_SW_MAILBOX_ADDR+offset,
+			&peer_operation, sizeof(u32));
+	if (ret) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":failed to "
+				"request close operation\n");
+		goto exit;
+	}
+	ret = sdio_al_enable_func_retry(wk_func, "wk_func");
+	if (ret) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to enable"
+				" Func#%d\n", wk_func->num);
+		goto exit;
+	}
+	pr_debug(MODULE_NAME ":%s: wk_func enabled on ch %s\n",
+			__func__, ch->name);
+	/* send "start" operation to MDM */
+	peer_operation = PEER_OPERATION(opcode, PEER_OP_STATE_START);
+	ret  =  sdio_memcpy_toio(ch->func, SDIOC_SW_MAILBOX_ADDR+offset,
+			&peer_operation, sizeof(u32));
+	if (ret) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":failed to "
+				"send start close operation\n");
+		goto exit;
+	}
+	ret = sdio_disable_func(wk_func);
+	if (ret) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to "
+				"disable Func#%d\n", wk_func->num);
+		goto exit;
+	}
+	/* poll for peer operation ack */
+	while (peer_operation != 0) {
+		ret  =  sdio_memcpy_fromio(ch->func,
+				&peer_operation,
+				SDIOC_SW_MAILBOX_ADDR+offset,
+				sizeof(u32));
+		if (ret) {
+			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
+					":failed to request ack on close"
+					" operation, loop_count = %d\n",
+					loop_count);
+			goto exit;
+		}
+		loop_count++;
+		if (loop_count > 10) {
+			sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":%s: "
+					"peer_operation=0x%x wait loop"
+					" %d on ch %s\n", __func__,
+					peer_operation, loop_count, ch->name);
+		}
+	}
+exit:
+	return ret;
+}
+
+static int channel_close(struct sdio_channel *ch, int flush_flag)
+{
+	int ret;
+	struct sdio_al_device *sdio_al_dev = NULL;
+	int flush_len;
+	ulong flush_expires;
+
+	if (!ch) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
+				"channel\n",  __func__);
+		return -ENODEV;
+	}
+
+	if (!ch->func) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: NULL func"
+				" on channel:%d\n", __func__, ch->num);
+		return -ENODEV;
+	}
+
+	sdio_al_dev = ch->sdio_al_dev;
+	if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
+		return -ENODEV;
+
+	if (!sdio_al_dev->ch_close_supported) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: Not "
+			"supported by mdm, ch %s\n",
+			__func__, ch->name);
+		ret = -ENOTSUPP;
+		goto error_exit;
+	}
+
+	if (sdio_al_dev->is_err) {
+		SDIO_AL_ERR(__func__);
+		ret = -ENODEV;
+		goto error_exit;
+	}
+	if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
+		sdio_al_loge(sdio_al_dev->dev_log,
+				MODULE_NAME ":%s: ch %s is not in "
+				"open state (%d)\n",
+				__func__, ch->name, ch->state);
+		ret = -ENODEV;
+		goto error_exit;
+	}
+	ch->state = SDIO_CHANNEL_STATE_CLOSING;
+	ret = peer_set_operation(PEER_OP_CODE_CLOSE, sdio_al_dev, ch);
+	if (ret) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: "
+				"peer_set_operation() failed: %d\n",
+				__func__, ret);
+		ret = -ENODEV;
+		goto error_exit;
+	}
+	/* udate poll time for opened channels */
+	if  (ch->poll_delay_msec > 0) {
+		sdio_al_dev->poll_delay_msec =
+			get_min_poll_time_msec(sdio_al_dev);
+	}
+	sdio_al_release_mutex(ch->sdio_al_dev, __func__);
+
+	flush_expires = jiffies +
+		msecs_to_jiffies(SDIO_CLOSE_FLUSH_TIMEOUT_MSEC);
+	/* flush rx packets of the channel */
+	if (flush_flag) {
+		do {
+			while (ch->read_avail > 0) {
+				flush_len = ch->read_avail;
+				ret = sdio_read_internal(ch,
+						sdio_al_dev->rx_flush_buf,
+						flush_len);
+				if (ret) {
+					sdio_al_loge(&sdio_al->gen_log,
+						MODULE_NAME ":%s sdio_read"
+						" failed: %d, ch %s\n",
+						__func__, ret,
+						ch->name);
+					return ret;
+				}
+
+				if (time_after(jiffies, flush_expires) != 0) {
+					sdio_al_loge(&sdio_al->gen_log,
+						MODULE_NAME ":%s flush rx "
+						"packets timeout: ch %s\n",
+						__func__, ch->name);
+					sdio_al_get_into_err_state(sdio_al_dev);
+					return -EBUSY;
+				}
+			}
+			msleep(100);
+			if (ch->signature != SDIO_AL_SIGNATURE) {
+					sdio_al_loge(&sdio_al->gen_log,
+						MODULE_NAME ":%s: after sleep,"
+						" invalid signature"
+						" 0x%x\n", __func__,
+						ch->signature);
+				return -ENODEV;
+			}
+			if (sdio_al_claim_mutex_and_verify_dev(ch->sdio_al_dev,
+							       __func__))
+				return -ENODEV;
+
+			ret = read_mailbox(sdio_al_dev, false);
+			if (ret) {
+				sdio_al_loge(&sdio_al->gen_log,
+						MODULE_NAME ":%s: failed to"
+						" read mailbox", __func__);
+				goto error_exit;
+			}
+			sdio_al_release_mutex(ch->sdio_al_dev, __func__);
+		} while (ch->read_avail > 0);
+	}
+	if (sdio_al_claim_mutex_and_verify_dev(ch->sdio_al_dev,
+					       __func__))
+		return -ENODEV;
+	/* disable function to be able to open the channel again */
+	ret = sdio_disable_func(ch->func);
+	if (ret) {
+		sdio_al_loge(&sdio_al->gen_log,
+			MODULE_NAME ":Fail to disable Func#%d\n",
+			ch->func->num);
+		goto error_exit;
+	}
+	ch->state = SDIO_CHANNEL_STATE_CLOSED;
+	CLOSE_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":%s: Ch %s closed "
+				"successfully\n", __func__, ch->name);
+
+error_exit:
+	sdio_al_release_mutex(ch->sdio_al_dev, __func__);
+
+	return ret;
+}
+
+/**
+ *  Close SDIO Channel.
+ *
+ */
+int sdio_close(struct sdio_channel *ch)
+{
+	return channel_close(ch, true);
+}
+EXPORT_SYMBOL(sdio_close);
+
+/**
+ *  Get the number of available bytes to write.
+ *
+ */
+int sdio_write_avail(struct sdio_channel *ch)
+{
+	if (!ch) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
+				"channel\n", __func__);
+		return -ENODEV;
+	}
+	if (ch->signature != SDIO_AL_SIGNATURE) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: "
+				"Invalid signature 0x%x\n",  __func__,
+				ch->signature);
+		return -ENODEV;
+	}
+	if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
+		sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":%s: "
+				"channel %s state is not open (%d)\n",
+				__func__, ch->name, ch->state);
+		return -ENODEV;
+	}
+	pr_debug(MODULE_NAME ":sdio_write_avail %s 0x%x\n",
+			 ch->name, ch->write_avail);
+
+	return ch->write_avail;
+}
+EXPORT_SYMBOL(sdio_write_avail);
+
+/**
+ *  Get the number of available bytes to read.
+ *
+ */
+int sdio_read_avail(struct sdio_channel *ch)
+{
+	if (!ch) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
+				"channel\n", __func__);
+		return -ENODEV;
+	}
+	if (ch->signature != SDIO_AL_SIGNATURE) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: "
+				"Invalid signature 0x%x\n",  __func__,
+				ch->signature);
+		return -ENODEV;
+	}
+	if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
+		sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":%s: "
+				"channel %s state is not open (%d)\n",
+				__func__, ch->name, ch->state);
+		return -ENODEV;
+	}
+	pr_debug(MODULE_NAME ":sdio_read_avail %s 0x%x\n",
+			 ch->name, ch->read_avail);
+
+	return ch->read_avail;
+}
+EXPORT_SYMBOL(sdio_read_avail);
+
+static int sdio_read_from_closed_ch(struct sdio_channel *ch, int len)
+{
+	int ret = 0;
+	struct sdio_al_device *sdio_al_dev = NULL;
+
+	if (!ch) {
+		sdio_al_loge(ch->sdio_al_dev->dev_log,
+			MODULE_NAME ":%s: NULL channel\n",  __func__);
+		return -ENODEV;
+	}
+
+	sdio_al_dev = ch->sdio_al_dev;
+	if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
+		return -ENODEV;
+
+	ret = sdio_memcpy_fromio(ch->func, sdio_al_dev->rx_flush_buf,
+				 PIPE_RX_FIFO_ADDR, len);
+
+	if (ret) {
+		sdio_al_loge(ch->sdio_al_dev->dev_log,
+				MODULE_NAME ":ch %s: %s err=%d, len=%d\n",
+				ch->name, __func__, -ret, len);
+		sdio_al_dev->is_err = true;
+		sdio_al_release_mutex(sdio_al_dev, __func__);
+		return ret;
+	}
+
+	restart_inactive_time(sdio_al_dev);
+
+	sdio_al_release_mutex(sdio_al_dev, __func__);
+
+	return 0;
+}
+
+/**
+ *  Internal read from SDIO Channel.
+ *
+ *  Reading from the pipe will trigger interrupt if there are
+ *  other pending packets on the SDIO-Client.
+ *
+ */
+static int sdio_read_internal(struct sdio_channel *ch, void *data, int len)
+{
+	int ret = 0;
+	struct sdio_al_device *sdio_al_dev = NULL;
+
+	if (!ch) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
+				"channel\n",  __func__);
+		return -ENODEV;
+	}
+	if (!data) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL data\n",
+				__func__);
+		return -ENODEV;
+	}
+	if (len == 0) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":channel %s trying"
+				" to read 0 bytes\n", ch->name);
+		return -EINVAL;
+	}
+
+	if (ch->signature != SDIO_AL_SIGNATURE) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: Invalid "
+				"signature 0x%x\n",  __func__, ch->signature);
+		return -ENODEV;
+	}
+
+	sdio_al_dev = ch->sdio_al_dev;
+	if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
+		return -ENODEV;
+
+	if (sdio_al_dev->is_err) {
+		SDIO_AL_ERR(__func__);
+		ret = -ENODEV;
+		goto exit;
+	}
+
+	/* lpm policy says we can't go to sleep when we have pending rx data,
+	   so either we had rx interrupt and woken up, or we never went to
+	   sleep */
+	if (sdio_al_dev->is_ok_to_sleep) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: called "
+				"when is_ok_to_sleep is set for ch %s, len=%d,"
+				" last_any_read_avail=%d, last_read_avail=%d, "
+				"last_old_read_avail=%d", __func__, ch->name,
+				len, ch->statistics.last_any_read_avail,
+				ch->statistics.last_read_avail,
+				ch->statistics.last_old_read_avail);
+	}
+	BUG_ON(sdio_al_dev->is_ok_to_sleep);
+
+	if ((ch->state != SDIO_CHANNEL_STATE_OPEN) &&
+			(ch->state != SDIO_CHANNEL_STATE_CLOSING)) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s wrong "
+				"channel %s state %d\n",
+				__func__, ch->name, ch->state);
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":start ch %s read %d "
+			"avail %d.\n", ch->name, len, ch->read_avail);
+
+	restart_inactive_time(sdio_al_dev);
+
+	if ((ch->is_packet_mode) && (len != ch->read_avail)) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_read ch "
+				"%s len != read_avail\n", ch->name);
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	if (len > ch->read_avail) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":ERR ch %s: "
+				"reading more bytes (%d) than the avail(%d).\n",
+				ch->name, len, ch->read_avail);
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	ret = sdio_memcpy_fromio(ch->func, data, PIPE_RX_FIFO_ADDR, len);
+
+	if (ret) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":ch %s: "
+				"sdio_read err=%d, len=%d, read_avail=%d, "
+				"last_read_avail=%d, last_old_read_avail=%d\n",
+				ch->name, -ret, len, ch->read_avail,
+				ch->statistics.last_read_avail,
+				ch->statistics.last_old_read_avail);
+		sdio_al_get_into_err_state(sdio_al_dev);
+		goto exit;
+	}
+
+	ch->statistics.total_read_times++;
+
+	/* Remove handled packet from the list regardless if ret is ok */
+	if (ch->is_packet_mode)
+		remove_handled_rx_packet(ch);
+	else
+		ch->read_avail -= len;
+
+	ch->total_rx_bytes += len;
+	DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":end ch %s read %d "
+			"avail %d total %d.\n", ch->name, len,
+			ch->read_avail, ch->total_rx_bytes);
+
+	if ((ch->read_avail == 0) && !(ch->is_packet_mode))
+		ask_reading_mailbox(sdio_al_dev);
+
+exit:
+	sdio_al_release_mutex(sdio_al_dev, __func__);
+
+	return ret;
+}
+
+/**
+ *  Read from SDIO Channel.
+ *
+ *  Reading from the pipe will trigger interrupt if there are
+ *  other pending packets on the SDIO-Client.
+ *
+ */
+int sdio_read(struct sdio_channel *ch, void *data, int len)
+{
+	if (!ch) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
+				"channel\n", __func__);
+		return -ENODEV;
+	}
+	if (ch->signature != SDIO_AL_SIGNATURE) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: "
+			"Invalid signature 0x%x\n",  __func__, ch->signature);
+		return -ENODEV;
+	}
+	if (ch->state == SDIO_CHANNEL_STATE_OPEN) {
+		return sdio_read_internal(ch, data, len);
+	} else {
+		sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME
+				":%s: Invalid channel %s state %d\n",
+				__func__, ch->name, ch->state);
+	}
+	return -ENODEV;
+}
+EXPORT_SYMBOL(sdio_read);
+
+/**
+ *  Write to SDIO Channel.
+ *
+ */
+int sdio_write(struct sdio_channel *ch, const void *data, int len)
+{
+	int ret = 0;
+	struct sdio_al_device *sdio_al_dev = NULL;
+
+	if (!ch) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
+				"channel\n",  __func__);
+		return -ENODEV;
+	}
+	if (!data) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL data\n",
+				__func__);
+		return -ENODEV;
+	}
+	if (len == 0) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":channel %s trying"
+				" to write 0 bytes\n", ch->name);
+		return -EINVAL;
+	}
+
+	if (ch->signature != SDIO_AL_SIGNATURE) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: Invalid "
+				"signature 0x%x\n",  __func__, ch->signature);
+		return -ENODEV;
+	}
+
+	sdio_al_dev = ch->sdio_al_dev;
+	if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
+		return -ENODEV;
+
+	WARN_ON(len > ch->write_avail);
+
+	if (sdio_al_dev->is_err) {
+		SDIO_AL_ERR(__func__);
+		ret = -ENODEV;
+		goto exit;
+	}
+
+	if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":writing to "
+				"closed channel %s\n", ch->name);
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	if (sdio_al_dev->is_ok_to_sleep) {
+		ret = sdio_al_wake_up(sdio_al_dev, 1, ch);
+		if (ret)
+			goto exit;
+	} else {
+		restart_inactive_time(sdio_al_dev);
+	}
+
+	DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":start ch %s write %d "
+			"avail %d.\n", ch->name, len, ch->write_avail);
+
+	if (len > ch->write_avail) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":ERR ch %s: "
+				"write more bytes (%d) than  available %d.\n",
+				ch->name, len, ch->write_avail);
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	ret = sdio_ch_write(ch, data, len);
+	if (ret) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_write "
+				"on channel %s err=%d\n", ch->name, -ret);
+		goto exit;
+	}
+
+	ch->total_tx_bytes += len;
+	DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":end ch %s write %d "
+			"avail %d total %d.\n", ch->name, len,
+			ch->write_avail, ch->total_tx_bytes);
+
+	/* Round up to whole buffer size */
+	len = ROUND_UP(len, ch->peer_tx_buf_size);
+	/* Protect from wraparound */
+	len = min(len, (int) ch->write_avail);
+	ch->write_avail -= len;
+
+	if (ch->write_avail < ch->min_write_avail)
+		ask_reading_mailbox(sdio_al_dev);
+
+exit:
+	sdio_al_release_mutex(sdio_al_dev, __func__);
+
+	return ret;
+}
+EXPORT_SYMBOL(sdio_write);
+
+static int __devinit msm_sdio_al_probe(struct platform_device *pdev)
+{
+	if (!sdio_al) {
+		pr_err(MODULE_NAME ": %s: NULL sdio_al\n", __func__);
+		return -ENODEV;
+	}
+
+	sdio_al->pdata = pdev->dev.platform_data;
+	return 0;
+}
+
+static int __devexit msm_sdio_al_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static void sdio_al_close_all_channels(struct sdio_al_device *sdio_al_dev)
+{
+	int j;
+	int ret;
+	struct sdio_channel *ch = NULL;
+
+	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s", __func__);
+
+	if (!sdio_al_dev) {
+		sdio_al_loge(sdio_al_dev->dev_log,
+			MODULE_NAME ": %s: NULL device", __func__);
+		return;
+	}
+	for (j = 0; j < SDIO_AL_MAX_CHANNELS; j++) {
+		ch = &sdio_al_dev->channel[j];
+
+		if (ch->state == SDIO_CHANNEL_STATE_OPEN) {
+			sdio_al_loge(sdio_al_dev->dev_log,
+				MODULE_NAME ": %s: Call to sdio_close() for"
+				" ch %s\n", __func__, ch->name);
+			ret = channel_close(ch, false);
+			if (ret) {
+				sdio_al_loge(sdio_al_dev->dev_log,
+					MODULE_NAME ": %s: failed sdio_close()"
+					" for ch %s (%d)\n",
+					__func__, ch->name, ret);
+			}
+		} else {
+			pr_debug(MODULE_NAME ": %s: skip sdio_close() ch %s"
+					" (state=%d)\n", __func__,
+					ch->name, ch->state);
+		}
+	}
+}
+
+static void sdio_al_invalidate_sdio_clients(struct sdio_al_device *sdio_al_dev,
+					    struct platform_device **pdev_arr)
+{
+	int j;
+
+	pr_debug(MODULE_NAME ": %s: Notifying SDIO clients for card %d",
+			__func__, sdio_al_dev->host->index);
+	for (j = 0; j < SDIO_AL_MAX_CHANNELS; ++j) {
+		if (sdio_al_dev->channel[j].state ==
+			SDIO_CHANNEL_STATE_INVALID)
+			continue;
+		pdev_arr[j] = sdio_al_dev->channel[j].pdev;
+		sdio_al_dev->channel[j].signature = 0x0;
+		sdio_al_dev->channel[j].state =
+			SDIO_CHANNEL_STATE_INVALID;
+	}
+}
+
+static void sdio_al_modem_reset_operations(struct sdio_al_device
+							*sdio_al_dev)
+{
+	int ret = 0;
+	struct platform_device *pdev_arr[SDIO_AL_MAX_CHANNELS];
+	int j;
+
+	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s", __func__);
+
+	if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
+		return;
+
+	if (sdio_al_dev->state == CARD_REMOVED) {
+		sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: "
+			"card %d is already removed", __func__,
+			sdio_al_dev->host->index);
+		goto exit_err;
+	}
+
+	if (sdio_al_dev->state == MODEM_RESTART) {
+		sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ": %s: "
+			"card %d was already notified for modem reset",
+			__func__, sdio_al_dev->host->index);
+		goto exit_err;
+	}
+
+	sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ": %s: Set the "
+		"state to MODEM_RESTART for card %d",
+		__func__, sdio_al_dev->host->index);
+	sdio_al_dev->state = MODEM_RESTART;
+	sdio_al_dev->is_ready = false;
+
+	/* Stop mailbox timer */
+	stop_and_del_timer(sdio_al_dev);
+
+	if ((sdio_al_dev->is_ok_to_sleep) &&
+	    (!sdio_al_dev->is_err)) {
+		pr_debug(MODULE_NAME ": %s: wakeup modem for "
+				    "card %d", __func__,
+			sdio_al_dev->host->index);
+		ret = sdio_al_wake_up(sdio_al_dev, 1, NULL);
+	}
+
+	if (!ret && (!sdio_al_dev->is_err) && sdio_al_dev->card &&
+		sdio_al_dev->card->sdio_func[0]) {
+			sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME
+			": %s: sdio_release_irq for card %d",
+			__func__,
+			sdio_al_dev->host->index);
+			sdio_release_irq(sdio_al_dev->card->sdio_func[0]);
+	}
+
+	memset(pdev_arr, 0, sizeof(pdev_arr));
+	sdio_al_invalidate_sdio_clients(sdio_al_dev, pdev_arr);
+
+	sdio_al_release_mutex(sdio_al_dev, __func__);
+
+	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Notifying SDIO "
+						    "clients for card %d",
+			__func__, sdio_al_dev->host->index);
+	for (j = 0; j < SDIO_AL_MAX_CHANNELS; j++) {
+		if (!pdev_arr[j])
+			continue;
+		platform_device_unregister(pdev_arr[j]);
+	}
+	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Finished Notifying "
+						    "SDIO clients for card %d",
+			__func__, sdio_al_dev->host->index);
+
+	return;
+
+exit_err:
+	sdio_al_release_mutex(sdio_al_dev, __func__);
+	return;
+}
+
+#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
+static void sdio_al_reset(void)
+{
+	int i;
+	struct sdio_al_device *sdio_al_dev;
+
+	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s", __func__);
+
+	for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; i++) {
+		if (sdio_al->devices[i] == NULL) {
+			pr_debug(MODULE_NAME ": %s: NULL device in index %d",
+					__func__, i);
+			continue;
+		}
+		sdio_al_dev = sdio_al->devices[i];
+		sdio_al_modem_reset_operations(sdio_al->devices[i]);
+	}
+
+	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s completed", __func__);
+}
+#endif
+
+static void msm_sdio_al_shutdown(struct platform_device *pdev)
+{
+	int i;
+	struct sdio_al_device *sdio_al_dev;
+
+	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME
+			"Initiating msm_sdio_al_shutdown...");
+
+	for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; i++) {
+		if (sdio_al->devices[i] == NULL) {
+			pr_debug(MODULE_NAME ": %s: NULL device in index %d",
+					__func__, i);
+			continue;
+		}
+		sdio_al_dev = sdio_al->devices[i];
+
+		if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
+			return;
+
+		if (sdio_al_dev->ch_close_supported)
+			sdio_al_close_all_channels(sdio_al_dev);
+
+		sdio_al_release_mutex(sdio_al_dev, __func__);
+
+		sdio_al_modem_reset_operations(sdio_al_dev);
+	}
+	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: "
+		"msm_sdio_al_shutdown complete.", __func__);
+}
+
+static struct platform_driver msm_sdio_al_driver = {
+	.probe          = msm_sdio_al_probe,
+	.remove         = __exit_p(msm_sdio_al_remove),
+	.shutdown	= msm_sdio_al_shutdown,
+	.driver         = {
+		.name   = "msm_sdio_al",
+	},
+};
+
+/**
+ *  Initialize SDIO_AL channels.
+ *
+ */
+static int init_channels(struct sdio_al_device *sdio_al_dev)
+{
+	int ret = 0;
+	int i;
+
+	if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
+		return -ENODEV;
+
+	ret = read_sdioc_software_header(sdio_al_dev,
+					 sdio_al_dev->sdioc_sw_header);
+	if (ret)
+		goto exit;
+
+	ret = sdio_al_setup(sdio_al_dev);
+	if (ret)
+		goto exit;
+
+	for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
+		int ch_name_size;
+		if (sdio_al_dev->channel[i].state == SDIO_CHANNEL_STATE_INVALID)
+			continue;
+		if (sdio_al->unittest_mode) {
+			memset(sdio_al_dev->channel[i].ch_test_name, 0,
+				sizeof(sdio_al_dev->channel[i].ch_test_name));
+			ch_name_size = strnlen(sdio_al_dev->channel[i].name,
+				       CHANNEL_NAME_SIZE);
+			strncpy(sdio_al_dev->channel[i].ch_test_name,
+			       sdio_al_dev->channel[i].name,
+			       ch_name_size);
+			strncat(sdio_al_dev->channel[i].ch_test_name +
+			       ch_name_size,
+			       SDIO_TEST_POSTFIX,
+			       SDIO_TEST_POSTFIX_SIZE);
+			pr_debug(MODULE_NAME ":pdev.name = %s\n",
+				sdio_al_dev->channel[i].ch_test_name);
+			sdio_al_dev->channel[i].pdev = platform_device_alloc(
+				sdio_al_dev->channel[i].ch_test_name, -1);
+		} else {
+			pr_debug(MODULE_NAME ":pdev.name = %s\n",
+				sdio_al_dev->channel[i].name);
+			sdio_al_dev->channel[i].pdev = platform_device_alloc(
+				sdio_al_dev->channel[i].name, -1);
+		}
+		if (!sdio_al_dev->channel[i].pdev) {
+			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
+					":NULL platform device for ch %s",
+					sdio_al_dev->channel[i].name);
+			sdio_al_dev->channel[i].state =
+				SDIO_CHANNEL_STATE_INVALID;
+			continue;
+		}
+		ret = platform_device_add(sdio_al_dev->channel[i].pdev);
+		if (ret) {
+			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
+					":platform_device_add failed, "
+					"ret=%d\n", ret);
+			sdio_al_dev->channel[i].state =
+				SDIO_CHANNEL_STATE_INVALID;
+		}
+	}
+
+exit:
+	sdio_al_release_mutex(sdio_al_dev, __func__);
+	return ret;
+}
+
+/**
+ *  Initialize SDIO_AL channels according to the client setup.
+ *  This function also check if the client is in boot mode and
+ *  flashless boot is required to be activated or the client is
+ *  up and running.
+ *
+ */
+static int sdio_al_client_setup(struct sdio_al_device *sdio_al_dev)
+{
+	int ret = 0;
+	struct sdio_func *func1;
+	int signature = 0;
+
+	if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
+		return -ENODEV;
+
+	if (!sdio_al_dev->card || !sdio_al_dev->card->sdio_func[0]) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":NULL card or "
+							       "func1\n");
+		sdio_al_release_mutex(sdio_al_dev, __func__);
+		return -ENODEV;
+	}
+	func1 = sdio_al_dev->card->sdio_func[0];
+
+	/* Read the header signature to determine the status of the MDM
+	 * SDIO Client
+	 */
+	signature = sdio_readl(func1, SDIOC_SW_HEADER_ADDR, &ret);
+	sdio_al_release_mutex(sdio_al_dev, __func__);
+	if (ret) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":fail to read "
+				"signature from sw header.\n");
+		return ret;
+	}
+
+	switch (signature) {
+	case PEER_SDIOC_SW_MAILBOX_BOOT_SIGNATURE:
+		if (sdio_al_dev == sdio_al->bootloader_dev) {
+			sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":setup "
+					"bootloader on card %d\n",
+					sdio_al_dev->host->index);
+			return sdio_al_bootloader_setup();
+		} else {
+			sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":wait "
+					"for bootloader completion "
+					"on card %d\n",
+					sdio_al_dev->host->index);
+			return sdio_al_wait_for_bootloader_comp(sdio_al_dev);
+		}
+	case PEER_SDIOC_SW_MAILBOX_SIGNATURE:
+	case PEER_SDIOC_SW_MAILBOX_UT_SIGNATURE:
+		return init_channels(sdio_al_dev);
+	default:
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Invalid "
+				"signature 0x%x\n", signature);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void clean_sdio_al_device_data(struct sdio_al_device *sdio_al_dev)
+{
+	sdio_al_dev->is_ready = 0;
+	sdio_al_dev->bootloader_done = 0;
+	sdio_al_dev->lpm_chan = 0;
+	sdio_al_dev->is_ok_to_sleep = 0;
+	sdio_al_dev->inactivity_time = 0;
+	sdio_al_dev->poll_delay_msec = 0;
+	sdio_al_dev->is_timer_initialized = 0;
+	sdio_al_dev->is_err = 0;
+	sdio_al_dev->is_suspended = 0;
+	sdio_al_dev->flashless_boot_on = 0;
+	sdio_al_dev->ch_close_supported = 0;
+	sdio_al_dev->print_after_interrupt = 0;
+	memset(sdio_al_dev->sdioc_sw_header, 0,
+	       sizeof(*sdio_al_dev->sdioc_sw_header));
+	memset(sdio_al_dev->mailbox, 0, sizeof(*sdio_al_dev->mailbox));
+	memset(sdio_al_dev->rx_flush_buf, 0,
+	       sizeof(*sdio_al_dev->rx_flush_buf));
+}
+
+/*
+ * SDIO driver functions
+ */
+static int sdio_al_sdio_probe(struct sdio_func *func,
+		const struct sdio_device_id *sdio_dev_id)
+{
+	int ret = 0;
+	struct sdio_al_device *sdio_al_dev = NULL;
+	int i;
+	struct mmc_card *card = NULL;
+
+	if (!func) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL func\n",
+				__func__);
+		return -ENODEV;
+	}
+	card = func->card;
+
+	if (!card) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL card\n",
+				__func__);
+		return -ENODEV;
+	}
+
+	if (!card->sdio_func[0]) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
+							    "func1\n",
+				__func__);
+		return -ENODEV;
+	}
+
+	if (card->sdio_funcs < SDIO_AL_MAX_FUNCS) {
+		dev_info(&card->dev,
+			 "SDIO-functions# %d less than expected.\n",
+			 card->sdio_funcs);
+		return -ENODEV;
+	}
+
+	/* Check if there is already a device for this card */
+	for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
+		if (sdio_al->devices[i] == NULL)
+			continue;
+		if (sdio_al->devices[i]->host == card->host) {
+			sdio_al_dev = sdio_al->devices[i];
+			if (sdio_al_dev->state == CARD_INSERTED)
+				return 0;
+			clean_sdio_al_device_data(sdio_al_dev);
+			break;
+		}
+	}
+
+	if (!sdio_al_dev) {
+		sdio_al_dev = kzalloc(sizeof(struct sdio_al_device),
+				      GFP_KERNEL);
+		if (sdio_al_dev == NULL)
+			return -ENOMEM;
+
+		for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES ; ++i)
+			if (sdio_al->devices[i] == NULL) {
+				sdio_al->devices[i] = sdio_al_dev;
+				sdio_al_dev->dev_log = &sdio_al->device_log[i];
+				spin_lock_init(&sdio_al_dev->dev_log->log_lock);
+	#ifdef CONFIG_DEBUG_FS
+				sdio_al_dbgfs_log[i].data =
+						sdio_al_dev->dev_log->buffer;
+				sdio_al_dbgfs_log[i].size =
+					SDIO_AL_DEBUG_LOG_SIZE;
+	#endif
+				break;
+			}
+		if (i == MAX_NUM_OF_SDIO_DEVICES) {
+			sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":No space "
+					"in devices array for the device\n");
+			return -ENOMEM;
+		}
+	}
+
+	dev_info(&card->dev, "SDIO Card claimed.\n");
+	sdio_al->skip_print_info = 0;
+
+	sdio_al_dev->state = CARD_INSERTED;
+
+	if (card->host->index == SDIO_BOOTLOADER_CARD_INDEX)
+		sdio_al->bootloader_dev = sdio_al_dev;
+
+	sdio_al_dev->is_ready = false;
+
+	sdio_al_dev->signature = SDIO_AL_SIGNATURE;
+
+	sdio_al_dev->is_suspended = 0;
+	sdio_al_dev->is_timer_initialized = false;
+
+	sdio_al_dev->lpm_chan = INVALID_SDIO_CHAN;
+
+	sdio_al_dev->card = card;
+	sdio_al_dev->host = card->host;
+
+	if (!sdio_al_dev->mailbox) {
+		sdio_al_dev->mailbox = kzalloc(sizeof(struct sdio_mailbox),
+					       GFP_KERNEL);
+		if (sdio_al_dev->mailbox == NULL)
+			return -ENOMEM;
+	}
+
+	if (!sdio_al_dev->sdioc_sw_header) {
+		sdio_al_dev->sdioc_sw_header
+			= kzalloc(sizeof(*sdio_al_dev->sdioc_sw_header),
+				  GFP_KERNEL);
+		if (sdio_al_dev->sdioc_sw_header == NULL)
+			return -ENOMEM;
+	}
+
+	if (!sdio_al_dev->rx_flush_buf) {
+		sdio_al_dev->rx_flush_buf = kzalloc(RX_FLUSH_BUFFER_SIZE,
+						    GFP_KERNEL);
+		if (sdio_al_dev->rx_flush_buf == NULL) {
+			sdio_al_loge(&sdio_al->gen_log,
+					MODULE_NAME ":Fail to allocate "
+					   "rx_flush_buf for card %d\n",
+			       card->host->index);
+			return -ENOMEM;
+		}
+	}
+
+	sdio_al_dev->timer.data = (unsigned long)sdio_al_dev;
+
+	wake_lock_init(&sdio_al_dev->wake_lock, WAKE_LOCK_SUSPEND, MODULE_NAME);
+	/* Don't allow sleep until all required clients register */
+	sdio_al_vote_for_sleep(sdio_al_dev, 0);
+
+	if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
+		return -ENODEV;
+
+	/* Init Func#1 */
+	ret = sdio_al_enable_func_retry(card->sdio_func[0], "Init Func#1");
+	if (ret) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to "
+				"enable Func#%d\n", card->sdio_func[0]->num);
+		goto exit;
+	}
+
+	/* Patch Func CIS tuple issue */
+	ret = sdio_set_block_size(card->sdio_func[0], SDIO_AL_BLOCK_SIZE);
+	if (ret) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to set "
+			"block size, Func#%d\n", card->sdio_func[0]->num);
+		goto exit;
+	}
+	sdio_al_dev->card->sdio_func[0]->max_blksize = SDIO_AL_BLOCK_SIZE;
+
+	sdio_al_dev->workqueue = create_singlethread_workqueue("sdio_al_wq");
+	sdio_al_dev->sdio_al_work.sdio_al_dev = sdio_al_dev;
+	init_waitqueue_head(&sdio_al_dev->wait_mbox);
+
+	ret = sdio_al_client_setup(sdio_al_dev);
+
+exit:
+	sdio_al_release_mutex(sdio_al_dev, __func__);
+	return ret;
+}
+
+static void sdio_al_sdio_remove(struct sdio_func *func)
+{
+	struct sdio_al_device *sdio_al_dev = NULL;
+	int i;
+	struct mmc_card *card = NULL;
+	struct platform_device *pdev_arr[SDIO_AL_MAX_CHANNELS];
+
+	if (!func) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL func\n",
+				__func__);
+		return;
+	}
+	card = func->card;
+
+	if (!card) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL card\n",
+				__func__);
+		return;
+	}
+
+	/* Find the sdio_al_device of this card */
+	for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
+		if (sdio_al->devices[i] == NULL)
+			continue;
+		if (sdio_al->devices[i]->card == card) {
+			sdio_al_dev = sdio_al->devices[i];
+			break;
+		}
+	}
+	if (sdio_al_dev == NULL) {
+		pr_debug(MODULE_NAME ":%s :NULL sdio_al_dev for card %d\n",
+				 __func__, card->host->index);
+		return;
+	}
+
+	if (sdio_al_claim_mutex(sdio_al_dev, __func__))
+		return;
+
+	if (sdio_al_dev->state == CARD_REMOVED) {
+		sdio_al_release_mutex(sdio_al_dev, __func__);
+		return;
+	}
+
+	if (!card->sdio_func[0]) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
+						"func1\n", __func__);
+		sdio_al_release_mutex(sdio_al_dev, __func__);
+		return;
+	}
+
+	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s for card %d\n",
+			 __func__, card->host->index);
+
+	sdio_al_dev->state = CARD_REMOVED;
+
+	memset(pdev_arr, 0, sizeof(pdev_arr));
+	sdio_al_invalidate_sdio_clients(sdio_al_dev, pdev_arr);
+
+	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: ask_reading_mailbox "
+			"for card %d\n", __func__, card->host->index);
+	sdio_al_dev->is_ready = false; /* Flag worker to exit */
+	sdio_al_dev->ask_mbox = false;
+	ask_reading_mailbox(sdio_al_dev); /* Wakeup worker */
+
+	stop_and_del_timer(sdio_al_dev);
+
+	sdio_al_release_mutex(sdio_al_dev, __func__);
+
+	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Notifying SDIO "
+						    "clients for card %d",
+			__func__, sdio_al_dev->host->index);
+	for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
+		if (!pdev_arr[i])
+			continue;
+		platform_device_unregister(pdev_arr[i]);
+	}
+	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Finished Notifying "
+						    "SDIO clients for card %d",
+			__func__, sdio_al_dev->host->index);
+
+	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: vote for sleep for "
+			"card %d\n", __func__, card->host->index);
+	sdio_al_vote_for_sleep(sdio_al_dev, 1);
+
+	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: flush_workqueue for "
+			"card %d\n", __func__, card->host->index);
+	flush_workqueue(sdio_al_dev->workqueue);
+	destroy_workqueue(sdio_al_dev->workqueue);
+	wake_lock_destroy(&sdio_al_dev->wake_lock);
+
+	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: sdio card %d removed."
+			"\n", __func__,	card->host->index);
+}
+
+static void sdio_print_mailbox(char *prefix_str, struct sdio_mailbox *mailbox)
+{
+	int k = 0;
+	char buf[256];
+	char buf1[10];
+
+	if (!mailbox) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": mailbox is "
+				"NULL\n");
+		return;
+	}
+
+	sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: pipes 0_7: eot=0x%x,"
+		" thresh=0x%x, overflow=0x%x, "
+		"underflow=0x%x, mask_thresh=0x%x\n",
+		 prefix_str, mailbox->eot_pipe_0_7,
+		 mailbox->thresh_above_limit_pipe_0_7,
+		 mailbox->overflow_pipe_0_7,
+		 mailbox->underflow_pipe_0_7,
+		 mailbox->mask_thresh_above_limit_pipe_0_7);
+
+	memset(buf, 0, sizeof(buf));
+	strncat(buf, ": bytes_avail:", sizeof(buf));
+
+	for (k = 0 ; k < SDIO_AL_ACTIVE_PIPES ; ++k) {
+		snprintf(buf1, sizeof(buf1), "%d, ",
+			 mailbox->pipe_bytes_avail[k]);
+		strncat(buf, buf1, sizeof(buf));
+	}
+
+	sdio_al_loge(&sdio_al->gen_log, MODULE_NAME "%s", buf);
+}
+
+static void sdio_al_print_info(void)
+{
+	int i = 0;
+	int j = 0;
+	int ret = 0;
+	struct sdio_mailbox *mailbox = NULL;
+	struct sdio_mailbox *hw_mailbox = NULL;
+	struct peer_sdioc_channel_config *ch_config = NULL;
+	struct sdio_func *func1 = NULL;
+	struct sdio_func *lpm_func = NULL;
+	int offset = 0;
+	int is_ok_to_sleep = 0;
+	char buf[50];
+
+	if (sdio_al->skip_print_info == 1)
+		return;
+
+	sdio_al->skip_print_info = 1;
+
+	sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - SDIO DEBUG INFO\n",
+			__func__);
+
+	if (!sdio_al) {
+		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - ERROR - "
+				"sdio_al is NULL\n",  __func__);
+		return;
+	}
+
+	sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": GPIO mdm2ap_status=%d\n",
+				sdio_al->pdata->get_mdm2ap_status());
+
+	for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES ; ++j) {
+		struct sdio_al_device *sdio_al_dev = sdio_al->devices[j];
+
+		if (sdio_al_dev == NULL) {
+			continue;
+		}
+
+		if (!sdio_al_dev->host) {
+			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": Host"
+					" is NULL\n);");
+			continue;
+		}
+
+		snprintf(buf, sizeof(buf), "Card#%d: Shadow HW MB",
+		       sdio_al_dev->host->index);
+
+		/* printing Shadowing HW Mailbox*/
+		mailbox = sdio_al_dev->mailbox;
+		sdio_print_mailbox(buf, mailbox);
+
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": Card#%d: "
+			"is_ok_to_sleep=%d\n",
+			sdio_al_dev->host->index,
+			sdio_al_dev->is_ok_to_sleep);
+
+
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": Card#%d: "
+				   "Shadow channels SW MB:",
+		       sdio_al_dev->host->index);
+
+		/* printing Shadowing SW Mailbox per channel*/
+		for (i = 0 ; i < SDIO_AL_MAX_CHANNELS ; ++i) {
+			struct sdio_channel *ch = &sdio_al_dev->channel[i];
+
+			if (ch == NULL) {
+				continue;
+			}
+
+			if (ch->state == SDIO_CHANNEL_STATE_INVALID)
+				continue;
+
+			ch_config = &sdio_al_dev->channel[i].ch_config;
+
+			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
+				": Ch %s: max_rx_thres=0x%x, "
+				"max_tx_thres=0x%x, tx_buf=0x%x, "
+				"is_packet_mode=%d, "
+				"max_packet=0x%x, min_write=0x%x",
+				ch->name, ch_config->max_rx_threshold,
+				ch_config->max_tx_threshold,
+				ch_config->tx_buf_size,
+				ch_config->is_packet_mode,
+				ch_config->max_packet_size,
+				ch->min_write_avail);
+
+			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
+				": total_rx=0x%x, total_tx=0x%x, "
+				"read_avail=0x%x, write_avail=0x%x, "
+				"rx_pending=0x%x, num_reads=0x%x, "
+				"num_notifs=0x%x", ch->total_rx_bytes,
+				ch->total_tx_bytes, ch->read_avail,
+				ch->write_avail, ch->rx_pending_bytes,
+				ch->statistics.total_read_times,
+				ch->statistics.total_notifs);
+		} /* end loop over all channels */
+
+	} /* end loop over all devices */
+
+	/* reading from client and printing is_host_ok_to_sleep per device */
+	for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES ; ++j) {
+		struct sdio_al_device *sdio_al_dev = sdio_al->devices[j];
+
+		if (sdio_al_verify_func1(sdio_al_dev, __func__))
+			continue;
+
+		if (!sdio_al_dev->host) {
+			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
+					": Host is NULL");
+			continue;
+		}
+
+		if (sdio_al_dev->lpm_chan == INVALID_SDIO_CHAN) {
+			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
+				": %s - for Card#%d, is lpm_chan=="
+				"INVALID_SDIO_CHAN. continuing...",
+				__func__, sdio_al_dev->host->index);
+			continue;
+		}
+
+		offset = offsetof(struct peer_sdioc_sw_mailbox, ch_config)+
+		sizeof(struct peer_sdioc_channel_config) *
+		sdio_al_dev->lpm_chan+
+		offsetof(struct peer_sdioc_channel_config, is_host_ok_to_sleep);
+
+		lpm_func = sdio_al_dev->card->sdio_func[sdio_al_dev->
+								lpm_chan+1];
+		if (!lpm_func) {
+			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
+					": %s - lpm_func is NULL for card#%d"
+					" continuing...\n", __func__,
+					sdio_al_dev->host->index);
+			continue;
+		}
+
+		if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
+			return;
+		ret  =  sdio_memcpy_fromio(lpm_func,
+					    &is_ok_to_sleep,
+					    SDIOC_SW_MAILBOX_ADDR+offset,
+					    sizeof(int));
+		sdio_al_release_mutex(sdio_al_dev, __func__);
+
+		if (ret)
+			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
+					": %s - fail to read "
+				"is_HOST_ok_to_sleep from mailbox for card %d",
+				__func__, sdio_al_dev->host->index);
+		else
+			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
+					": Card#%d: "
+				"is_HOST_ok_to_sleep=%d\n",
+				sdio_al_dev->host->index,
+				is_ok_to_sleep);
+	}
+
+	for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES ; ++j) {
+		struct sdio_al_device *sdio_al_dev = sdio_al->devices[j];
+
+		if (!sdio_al_dev)
+			continue;
+
+		/* Reading HW Mailbox */
+		hw_mailbox = sdio_al_dev->mailbox;
+
+		if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
+			return;
+
+		if (!sdio_al_dev->card || !sdio_al_dev->card->sdio_func[0]) {
+			sdio_al_release_mutex(sdio_al_dev, __func__);
+			return;
+		}
+		func1 = sdio_al_dev->card->sdio_func[0];
+		ret = sdio_memcpy_fromio(func1, hw_mailbox,
+			HW_MAILBOX_ADDR, sizeof(*hw_mailbox));
+		sdio_al_release_mutex(sdio_al_dev, __func__);
+
+		if (ret) {
+			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
+					": fail to read "
+			       "mailbox for card#%d. "
+			       "continuing...\n",
+			       sdio_al_dev->host->index);
+			continue;
+		}
+
+		snprintf(buf, sizeof(buf), "Card#%d: Current HW MB",
+		       sdio_al_dev->host->index);
+
+		/* Printing HW Mailbox */
+		sdio_print_mailbox(buf, hw_mailbox);
+	}
+}
+
+static struct sdio_device_id sdio_al_sdioid[] = {
+    {.class = 0, .vendor = 0x70, .device = 0x2460},
+    {.class = 0, .vendor = 0x70, .device = 0x0460},
+    {.class = 0, .vendor = 0x70, .device = 0x23F1},
+    {.class = 0, .vendor = 0x70, .device = 0x23F0},
+    {}
+};
+
+static struct sdio_driver sdio_al_sdiofn_driver = {
+    .name      = "sdio_al_sdiofn",
+    .id_table  = sdio_al_sdioid,
+    .probe     = sdio_al_sdio_probe,
+    .remove    = sdio_al_sdio_remove,
+};
+
+#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
+/*
+ *  Callback for notifications from restart mudule.
+ *  This function handles only the BEFORE_RESTART notification.
+ *  Stop all the activity on the card and notify our clients.
+ */
+static int sdio_al_subsys_notifier_cb(struct notifier_block *this,
+				  unsigned long notif_type,
+				  void *data)
+{
+	if (notif_type != SUBSYS_BEFORE_SHUTDOWN) {
+		sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: got "
+				"notification %ld", __func__, notif_type);
+		return NOTIFY_DONE;
+	}
+
+	sdio_al_reset();
+	return NOTIFY_OK;
+}
+
+static struct notifier_block sdio_al_nb = {
+	.notifier_call = sdio_al_subsys_notifier_cb,
+};
+#endif
+
+/**
+ *  Module Init.
+ *
+ *  @warn: allocate sdio_al context before registering driver.
+ *
+ */
+static int __init sdio_al_init(void)
+{
+	int ret = 0;
+	int i;
+
+	pr_debug(MODULE_NAME ":sdio_al_init\n");
+
+	pr_info(MODULE_NAME ":SDIO-AL SW version %s\n",
+		DRV_VERSION);
+
+	sdio_al = kzalloc(sizeof(struct sdio_al), GFP_KERNEL);
+	if (sdio_al == NULL)
+		return -ENOMEM;
+
+	for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES ; ++i)
+		sdio_al->devices[i] = NULL;
+
+	sdio_al->unittest_mode = false;
+
+	sdio_al->debug.debug_lpm_on = debug_lpm_on;
+	sdio_al->debug.debug_data_on = debug_data_on;
+	sdio_al->debug.debug_close_on = debug_close_on;
+
+#ifdef CONFIG_DEBUG_FS
+	sdio_al_debugfs_init();
+#endif
+
+
+#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
+	sdio_al->subsys_notif_handle = subsys_notif_register_notifier(
+		"external_modem", &sdio_al_nb);
+#endif
+
+	ret = platform_driver_register(&msm_sdio_al_driver);
+	if (ret) {
+		pr_err(MODULE_NAME ": platform_driver_register failed: %d\n",
+		       ret);
+		goto exit;
+	}
+
+	sdio_register_driver(&sdio_al_sdiofn_driver);
+
+	spin_lock_init(&sdio_al->gen_log.log_lock);
+
+exit:
+	if (ret)
+		kfree(sdio_al);
+	return ret;
+}
+
+/**
+ *  Module Exit.
+ *
+ *  Free allocated memory.
+ *  Disable SDIO-Card.
+ *  Unregister driver.
+ *
+ */
+static void __exit sdio_al_exit(void)
+{
+	if (sdio_al == NULL)
+		return;
+
+	pr_debug(MODULE_NAME ":sdio_al_exit\n");
+
+#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
+	subsys_notif_unregister_notifier(
+		sdio_al->subsys_notif_handle, &sdio_al_nb);
+#endif
+
+	sdio_al_tear_down();
+
+	sdio_unregister_driver(&sdio_al_sdiofn_driver);
+
+	kfree(sdio_al);
+
+#ifdef CONFIG_DEBUG_FS
+	sdio_al_debugfs_cleanup();
+#endif
+
+	platform_driver_unregister(&msm_sdio_al_driver);
+
+	pr_debug(MODULE_NAME ":sdio_al_exit complete\n");
+}
+
+module_init(sdio_al_init);
+module_exit(sdio_al_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("SDIO Abstraction Layer");
+MODULE_AUTHOR("Amir Samuelov <amirs@codeaurora.org>");
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/arch/arm/mach-msm/sdio_al_dloader.c b/arch/arm/mach-msm/sdio_al_dloader.c
new file mode 100644
index 0000000..f48c32b
--- /dev/null
+++ b/arch/arm/mach-msm/sdio_al_dloader.c
@@ -0,0 +1,2541 @@
+/* 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
+ * 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.
+ */
+
+/*
+ * SDIO-Downloader
+ *
+ * To be used with Qualcomm's SDIO-Client connected to this host.
+ */
+
+/* INCLUDES */
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/wakelock.h>
+#include <linux/mmc/card.h>
+#include <linux/dma-mapping.h>
+#include <mach/dma.h>
+#include <linux/mmc/sdio_func.h>
+#include "sdio_al_private.h"
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/kthread.h>
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/debugfs.h>
+
+/* DEFINES AND MACROS */
+#define MAX_NUM_DEVICES		1
+#define TTY_SDIO_DEV			"tty_sdio_0"
+#define TTY_SDIO_DEV_TEST		"tty_sdio_test_0"
+#define SDIOC_MAILBOX_ADDRESS		0
+#define SDIO_DL_BLOCK_SIZE		512
+#define SDIO_DL_MAIN_THREAD_NAME	"sdio_tty_main_thread"
+#define SDIOC_DL_BUFF_ADDRESS		0
+#define SDIOC_UP_BUFF_ADDRESS		0x4
+#define SDIOC_DL_BUFF_SIZE_OFFSET	0x8
+#define SDIOC_UP_BUFF_SIZE_OFFSET	0xC
+#define SDIOC_DL_WR_PTR		0x10
+#define SDIOC_DL_RD_PTR		0x14
+#define SDIOC_UL_WR_PTR		0x18
+#define SDIOC_UL_RD_PTR		0x1C
+#define SDIOC_EXIT_PTR			0x20
+#define SDIOC_OP_MODE_PTR		0x24
+#define SDIOC_PTRS_OFFSET		0x10
+#define SDIOC_PTR_REGS_SIZE		0x10
+#define SDIOC_CFG_REGS_SIZE		0x10
+#define WRITE_RETRIES			0xFFFFFFFF
+#define INPUT_SPEED			4800
+#define OUTPUT_SPEED			4800
+#define SDIOC_EXIT_CODE		0xDEADDEAD
+#define SLEEP_MS			10
+#define PRINTING_GAP			200
+#define TIMER_DURATION			10
+#define PUSH_TIMER_DURATION		5000
+#define MULTIPLE_RATIO			1
+#define MS_IN_SEC			1000
+#define BITS_IN_BYTE			8
+#define BYTES_IN_KB			1024
+#define WRITE_TILL_END_RETRIES		5
+#define SDIO_DLD_NORMAL_MODE_NAME	"SDIO DLD NORMAL MODE"
+#define SDIO_DLD_BOOT_TEST_MODE_NAME	"SDIO DLD BOOT TEST MODE"
+#define SDIO_DLD_AMSS_TEST_MODE_NAME	"SDIO DLD AMSS TEST MODE"
+#define TEST_NAME_MAX_SIZE		30
+#define PUSH_STRING
+#define SDIO_DLD_OUTGOING_BUFFER_SIZE	(48*1024*MULTIPLE_RATIO)
+
+/* FORWARD DECLARATIONS */
+static int sdio_dld_open(struct tty_struct *tty, struct file *file);
+static void sdio_dld_close(struct tty_struct *tty, struct file *file);
+static int sdio_dld_write_callback(struct tty_struct *tty,
+				   const unsigned char *buf, int count);
+static int sdio_dld_write_room(struct tty_struct *tty);
+static int sdio_dld_main_task(void *card);
+static void sdio_dld_print_info(void);
+#ifdef CONFIG_DEBUG_FS
+static int sdio_dld_debug_info_open(struct inode *inode, struct file *file);
+static ssize_t sdio_dld_debug_info_write(struct file *file,
+		const char __user *buf, size_t count, loff_t *ppos);
+#endif
+
+
+/* STRUCTURES AND TYPES */
+enum sdio_dld_op_mode {
+	 SDIO_DLD_NO_MODE = 0,
+	 SDIO_DLD_NORMAL_MODE = 1,
+	 SDIO_DLD_BOOT_TEST_MODE = 2,
+	 SDIO_DLD_AMSS_TEST_MODE = 3,
+	 SDIO_DLD_NUM_OF_MODES,
+};
+
+struct sdioc_reg_sequential_chunk_ptrs {
+	unsigned int dl_wr_ptr;
+	unsigned int dl_rd_ptr;
+	unsigned int up_wr_ptr;
+	unsigned int up_rd_ptr;
+};
+
+struct sdioc_reg_sequential_chunk_cfg {
+	unsigned int dl_buff_address;
+	unsigned int up_buff_address;
+	unsigned int dl_buff_size;
+	unsigned int ul_buff_size;
+};
+
+struct sdioc_reg {
+	unsigned int reg_val;
+	unsigned int reg_offset;
+};
+
+struct sdioc_reg_chunk {
+	struct sdioc_reg dl_buff_address;
+	struct sdioc_reg up_buff_address;
+	struct sdioc_reg dl_buff_size;
+	struct sdioc_reg ul_buff_size;
+	struct sdioc_reg dl_wr_ptr;
+	struct sdioc_reg dl_rd_ptr;
+	struct sdioc_reg up_wr_ptr;
+	struct sdioc_reg up_rd_ptr;
+	struct sdioc_reg good_to_exit_ptr;
+};
+
+struct sdio_data {
+	char *data;
+	int offset_read_p;
+	int offset_write_p;
+	int buffer_size;
+	int num_of_bytes_in_use;
+};
+
+struct sdio_dld_data {
+	struct sdioc_reg_chunk sdioc_reg;
+	struct sdio_data incoming_data;
+	struct sdio_data outgoing_data;
+};
+
+struct sdio_dld_wait_event {
+	wait_queue_head_t wait_event;
+	int wake_up_signal;
+};
+
+struct sdio_dld_task {
+	struct task_struct *dld_task;
+	const char *task_name;
+	struct sdio_dld_wait_event exit_wait;
+	atomic_t please_close;
+};
+
+#ifdef CONFIG_DEBUG_FS
+struct sdio_dloader_debug {
+	struct dentry *sdio_dld_debug_root;
+	struct dentry *sdio_al_dloader;
+};
+
+const struct file_operations sdio_dld_debug_info_ops = {
+	.open = sdio_dld_debug_info_open,
+	.write = sdio_dld_debug_info_write,
+};
+#endif
+
+struct sdio_downloader {
+	int sdioc_boot_func;
+	struct sdio_dld_wait_event write_callback_event;
+	struct sdio_dld_task dld_main_thread;
+	struct tty_driver *tty_drv;
+	struct tty_struct *tty_str;
+	struct sdio_dld_data sdio_dloader_data;
+	struct mmc_card *card;
+	int(*done_callback)(void);
+	struct sdio_dld_wait_event main_loop_event;
+	struct timer_list timer;
+	unsigned int poll_ms;
+	struct timer_list push_timer;
+	unsigned int push_timer_ms;
+	enum sdio_dld_op_mode op_mode;
+	char op_mode_name[TEST_NAME_MAX_SIZE];
+};
+
+struct sdio_dld_global_info {
+	int global_bytes_write_toio;
+	int global_bytes_write_tty;
+	int global_bytes_read_fromio;
+	int global_bytes_push_tty;
+	u64 start_time;
+	u64 end_time;
+	u64 delta_jiffies;
+	unsigned int time_msec;
+	unsigned int throughput;
+	int cl_dl_wr_ptr;
+	int cl_dl_rd_ptr;
+	int cl_up_wr_ptr;
+	int cl_up_rd_ptr;
+	int host_read_ptr;
+	int host_write_ptr;
+	int cl_dl_buffer_size;
+	int cl_up_buffer_size;
+	int host_outgoing_buffer_size;
+	int cl_dl_buffer_address;
+	int cl_up_buffer_address;
+};
+
+static const struct tty_operations sdio_dloader_tty_ops = {
+	.open = sdio_dld_open,
+	.close = sdio_dld_close,
+	.write = sdio_dld_write_callback,
+	.write_room = sdio_dld_write_room,
+};
+
+/* GLOBAL VARIABLES */
+struct sdio_downloader *sdio_dld;
+struct sdio_dld_global_info sdio_dld_info;
+static char outgoing_data_buffer[SDIO_DLD_OUTGOING_BUFFER_SIZE];
+
+static DEFINE_SPINLOCK(lock1);
+static unsigned long lock_flags1;
+static DEFINE_SPINLOCK(lock2);
+static unsigned long lock_flags2;
+
+/*
+ * sdio_op_mode sets the operation mode of the sdio_dloader -
+ * it may be in NORMAL_MODE, BOOT_TEST_MODE or AMSS_TEST_MODE
+ */
+static int sdio_op_mode = (int)SDIO_DLD_NORMAL_MODE;
+module_param(sdio_op_mode, int, 0);
+
+#ifdef CONFIG_DEBUG_FS
+
+struct sdio_dloader_debug sdio_dld_debug;
+
+#define ARR_SIZE 30000
+#define SDIO_DLD_DEBUGFS_INIT_VALUE	87654321
+#define SDIO_DLD_DEBUGFS_CASE_1_CODE	11111111
+#define SDIO_DLD_DEBUGFS_CASE_2_CODE	22222222
+#define SDIO_DLD_DEBUGFS_CASE_3_CODE	33333333
+#define SDIO_DLD_DEBUGFS_CASE_4_CODE	44444444
+#define SDIO_DLD_DEBUGFS_CASE_5_CODE	55555555
+#define SDIO_DLD_DEBUGFS_CASE_6_CODE	66666666
+#define SDIO_DLD_DEBUGFS_CASE_7_CODE	77777777
+#define SDIO_DLD_DEBUGFS_CASE_8_CODE	88888888
+#define SDIO_DLD_DEBUGFS_CASE_9_CODE	99999999
+#define SDIO_DLD_DEBUGFS_CASE_10_CODE	10101010
+#define SDIO_DLD_DEBUGFS_CASE_11_CODE	11001100
+#define SDIO_DLD_DEBUGFS_CASE_12_CODE	12001200
+#define SDIO_DLD_DEBUGFS_LOOP_WAIT	7
+#define SDIO_DLD_DEBUGFS_LOOP_WAKEUP	8
+#define SDIO_DLD_DEBUGFS_CB_WAIT	3
+#define SDIO_DLD_DEBUGFS_CB_WAKEUP	4
+
+static int curr_index;
+struct ptrs {
+	int h_w_ptr;
+	int h_r_ptr;
+	int c_u_w_ptr;
+	int c_u_r_ptr;
+	int code;
+	int h_has_to_send;
+	int c_has_to_receive;
+	int min_of;
+	int reserve2;
+	int tty_count;
+	int write_tty;
+	int write_toio;
+	int loop_wait_wake;
+	int cb_wait_wake;
+	int c_d_w_ptr;
+	int c_d_r_ptr;
+	int to_read;
+	int push_to_tty;
+	int global_tty_send;
+	int global_sdio_send;
+	int global_tty_received;
+	int global_sdio_received;
+	int reserve22;
+	int reserve23;
+	int reserve24;
+	int reserve25;
+	int reserve26;
+	int reserve27;
+	int reserve28;
+	int reserve29;
+	int reserve30;
+	int reserve31;
+};
+
+struct global_data {
+	int curr_i;
+	int duration_ms;
+	int global_bytes_sent;
+	int throughput_Mbs;
+	int host_outgoing_buffer_size_KB;
+	int client_up_buffer_size_KB;
+	int client_dl_buffer_size_KB;
+	int client_dl_buffer_address;
+	int client_up_buffer_address;
+	int global_bytes_received;
+	int global_bytes_pushed;
+	int reserve11;
+	int reserve12;
+	int reserve13;
+	int reserve14;
+	int reserve15;
+	int reserve16;
+	int reserve17;
+	int reserve18;
+	int reserve19;
+	int reserve20;
+	int reserve21;
+	int reserve22;
+	int reserve23;
+	int reserve24;
+	int reserve25;
+	int reserve26;
+	int reserve27;
+	int reserve28;
+	int reserve29;
+	int reserve30;
+	int reserve31;
+	struct ptrs ptr_array[ARR_SIZE];
+};
+
+static struct global_data gd;
+static struct debugfs_blob_wrapper blob;
+static struct dentry *root;
+static struct dentry *dld;
+
+struct debugfs_global {
+	int global_8k_has;
+	int global_9k_has;
+	int global_min;
+	int global_count;
+	int global_write_tty;
+	int global_write_toio;
+	int global_bytes_cb_tty;
+	int global_to_read;
+	int global_push_to_tty;
+	int global_tty_send;
+	int global_sdio_send;
+	int global_sdio_received;
+	int global_tty_push;
+};
+
+static struct debugfs_global debugfs_glob;
+
+static void update_standard_fields(int index)
+{
+
+	gd.ptr_array[index].global_tty_send =
+		sdio_dld_info.global_bytes_write_tty;
+	gd.ptr_array[index].global_sdio_send =
+		sdio_dld_info.global_bytes_write_toio;
+	gd.ptr_array[index].global_tty_received =
+		sdio_dld_info.global_bytes_push_tty;
+	gd.ptr_array[index].global_sdio_received =
+		sdio_dld_info.global_bytes_read_fromio;
+}
+
+static void update_gd(int code)
+{
+	struct sdioc_reg_chunk *reg_str =
+					&sdio_dld->sdio_dloader_data.sdioc_reg;
+	struct sdio_data *outgoing = &sdio_dld->sdio_dloader_data.outgoing_data;
+	int index = curr_index%ARR_SIZE;
+
+	gd.curr_i = curr_index;
+	gd.duration_ms = 0;
+	gd.global_bytes_sent = 0;
+	gd.throughput_Mbs = 0;
+	gd.host_outgoing_buffer_size_KB = 0;
+	gd.client_up_buffer_size_KB = 0;
+	gd.client_dl_buffer_size_KB = 0;
+	gd.client_dl_buffer_address = 0;
+	gd.client_up_buffer_address = 0;
+	gd.global_bytes_received = 0;
+	gd.global_bytes_pushed = 0;
+	gd.reserve11 = 0;
+	gd.reserve12 = 0;
+	gd.reserve13 = 0;
+	gd.reserve14 = 0;
+	gd.reserve15 = 0;
+	gd.reserve16 = 0;
+	gd.reserve17 = 0;
+	gd.reserve18 = 0;
+	gd.reserve19 = 0;
+	gd.reserve20 = 0;
+	gd.reserve21 = 0;
+	gd.reserve22 = 0;
+	gd.reserve23 = 0;
+	gd.reserve24 = 0;
+	gd.reserve25 = 0;
+	gd.reserve26 = 0;
+	gd.reserve27 = 0;
+	gd.reserve28 = 0;
+	gd.reserve29 = 0;
+	gd.reserve30 = 0;
+	gd.reserve31 = 0;
+
+	gd.ptr_array[index].h_w_ptr = SDIO_DLD_DEBUGFS_INIT_VALUE;	/*0*/
+	gd.ptr_array[index].h_r_ptr = SDIO_DLD_DEBUGFS_INIT_VALUE;	/*1*/
+	gd.ptr_array[index].c_u_w_ptr =	SDIO_DLD_DEBUGFS_INIT_VALUE;	/*2*/
+	gd.ptr_array[index].c_u_r_ptr =	SDIO_DLD_DEBUGFS_INIT_VALUE;	/*3*/
+	gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_INIT_VALUE;		/*4*/
+	gd.ptr_array[index].h_has_to_send = SDIO_DLD_DEBUGFS_INIT_VALUE;/*5*/
+	gd.ptr_array[index].c_has_to_receive =
+		SDIO_DLD_DEBUGFS_INIT_VALUE;				/*6*/
+	gd.ptr_array[index].min_of = SDIO_DLD_DEBUGFS_INIT_VALUE;	/*7*/
+	gd.ptr_array[index].reserve2 = SDIO_DLD_DEBUGFS_INIT_VALUE;	/*8*/
+	gd.ptr_array[index].tty_count = SDIO_DLD_DEBUGFS_INIT_VALUE;	/*9*/
+	gd.ptr_array[index].write_tty = SDIO_DLD_DEBUGFS_INIT_VALUE;	/*A*/
+	gd.ptr_array[index].write_toio = SDIO_DLD_DEBUGFS_INIT_VALUE;	/*B*/
+	gd.ptr_array[index].loop_wait_wake =
+		SDIO_DLD_DEBUGFS_INIT_VALUE;				/*C*/
+	gd.ptr_array[index].cb_wait_wake = SDIO_DLD_DEBUGFS_INIT_VALUE;	/*D*/
+	gd.ptr_array[index].c_d_w_ptr =	SDIO_DLD_DEBUGFS_INIT_VALUE;	/*E*/
+	gd.ptr_array[index].c_d_r_ptr =	SDIO_DLD_DEBUGFS_INIT_VALUE;	/*F*/
+	gd.ptr_array[index].to_read =
+		SDIO_DLD_DEBUGFS_INIT_VALUE;			/*0x10*/
+	gd.ptr_array[index].push_to_tty =
+		SDIO_DLD_DEBUGFS_INIT_VALUE;			/*0x11*/
+	gd.ptr_array[index].global_tty_send =
+		SDIO_DLD_DEBUGFS_INIT_VALUE;			/*0x12*/
+	gd.ptr_array[index].global_sdio_send =
+		SDIO_DLD_DEBUGFS_INIT_VALUE;			/*0x13*/
+	gd.ptr_array[index].global_tty_received =
+		SDIO_DLD_DEBUGFS_INIT_VALUE;			/*0x14*/
+	gd.ptr_array[index].global_sdio_received =
+		SDIO_DLD_DEBUGFS_INIT_VALUE;			/*0x15*/
+	gd.ptr_array[index].reserve22 = SDIO_DLD_DEBUGFS_INIT_VALUE;
+	gd.ptr_array[index].reserve23 = SDIO_DLD_DEBUGFS_INIT_VALUE;
+	gd.ptr_array[index].reserve24 = SDIO_DLD_DEBUGFS_INIT_VALUE;
+	gd.ptr_array[index].reserve25 = SDIO_DLD_DEBUGFS_INIT_VALUE;
+	gd.ptr_array[index].reserve26 = SDIO_DLD_DEBUGFS_INIT_VALUE;
+	gd.ptr_array[index].reserve27 = SDIO_DLD_DEBUGFS_INIT_VALUE;
+	gd.ptr_array[index].reserve28 = SDIO_DLD_DEBUGFS_INIT_VALUE;
+	gd.ptr_array[index].reserve29 = SDIO_DLD_DEBUGFS_INIT_VALUE;
+	gd.ptr_array[index].reserve30 = SDIO_DLD_DEBUGFS_INIT_VALUE;
+	gd.ptr_array[index].reserve31 = SDIO_DLD_DEBUGFS_INIT_VALUE;
+
+	switch (code) {
+	case SDIO_DLD_DEBUGFS_CASE_1_CODE:
+		gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_1_CODE;
+		gd.ptr_array[index].h_w_ptr = outgoing->offset_write_p;
+		gd.ptr_array[index].h_r_ptr = outgoing->offset_read_p;
+		gd.ptr_array[index].c_u_w_ptr =	reg_str->up_wr_ptr.reg_val;
+		gd.ptr_array[index].c_u_r_ptr =	reg_str->up_rd_ptr.reg_val;
+		gd.ptr_array[index].c_d_w_ptr =	reg_str->dl_wr_ptr.reg_val;
+		gd.ptr_array[index].c_d_r_ptr =	reg_str->dl_rd_ptr.reg_val;
+		break;
+
+	case SDIO_DLD_DEBUGFS_CASE_2_CODE:
+		gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_2_CODE;
+		gd.ptr_array[index].c_u_r_ptr = reg_str->up_rd_ptr.reg_val;
+		gd.ptr_array[index].c_u_w_ptr = reg_str->up_wr_ptr.reg_val;
+		gd.ptr_array[index].h_has_to_send = debugfs_glob.global_8k_has;
+		gd.ptr_array[index].c_has_to_receive =
+			debugfs_glob.global_9k_has;
+		gd.ptr_array[index].min_of = debugfs_glob.global_min;
+		break;
+
+	case SDIO_DLD_DEBUGFS_CASE_3_CODE:
+		gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_3_CODE;
+		gd.ptr_array[index].h_w_ptr = outgoing->offset_write_p;
+		gd.ptr_array[index].h_r_ptr = outgoing->offset_read_p;
+		gd.ptr_array[index].write_tty = debugfs_glob.global_write_tty;
+		break;
+
+	case SDIO_DLD_DEBUGFS_CASE_4_CODE:
+		gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_4_CODE;
+		gd.ptr_array[index].h_w_ptr = outgoing->offset_write_p;
+		gd.ptr_array[index].h_r_ptr = outgoing->offset_read_p;
+		gd.ptr_array[index].c_u_r_ptr = reg_str->up_rd_ptr.reg_val;
+		gd.ptr_array[index].c_u_w_ptr = reg_str->up_wr_ptr.reg_val;
+		gd.ptr_array[index].write_toio =
+			debugfs_glob.global_write_toio;
+		break;
+
+	case SDIO_DLD_DEBUGFS_CASE_5_CODE:
+		gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_5_CODE;
+		gd.ptr_array[index].tty_count = debugfs_glob.global_count;
+		break;
+
+	case SDIO_DLD_DEBUGFS_CASE_6_CODE:
+		gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_6_CODE;
+		gd.ptr_array[index].loop_wait_wake = 7;
+		break;
+
+	case SDIO_DLD_DEBUGFS_CASE_7_CODE:
+		gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_7_CODE;
+		gd.ptr_array[index].loop_wait_wake = 8;
+		break;
+
+	case SDIO_DLD_DEBUGFS_CASE_8_CODE:
+		gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_8_CODE;
+		gd.ptr_array[index].cb_wait_wake = 3;
+		break;
+
+	case SDIO_DLD_DEBUGFS_CASE_9_CODE:
+		gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_9_CODE;
+		gd.ptr_array[index].cb_wait_wake = 4;
+		break;
+
+	case SDIO_DLD_DEBUGFS_CASE_10_CODE:
+		gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_10_CODE;
+		gd.ptr_array[index].cb_wait_wake =
+			debugfs_glob.global_bytes_cb_tty;
+		break;
+
+	case SDIO_DLD_DEBUGFS_CASE_11_CODE:
+		gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_11_CODE;
+		gd.ptr_array[index].to_read = debugfs_glob.global_to_read;
+		break;
+
+	case SDIO_DLD_DEBUGFS_CASE_12_CODE:
+		gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_12_CODE;
+		gd.ptr_array[index].push_to_tty =
+			debugfs_glob.global_push_to_tty;
+		break;
+
+	default:
+		break;
+	}
+	update_standard_fields(index);
+	curr_index++;
+}
+
+static int bootloader_debugfs_init(void)
+{
+	/* /sys/kernel/debug/bootloader there will be dld_arr file */
+	root = debugfs_create_dir("bootloader", NULL);
+	if (!root) {
+		pr_info(MODULE_NAME ": %s - creating root dir "
+			"failed\n", __func__);
+		return -ENODEV;
+	}
+
+	blob.data = &gd;
+	blob.size = sizeof(struct global_data);
+	dld = debugfs_create_blob("dld_arr", S_IRUGO, root, &blob);
+	if (!dld) {
+		debugfs_remove_recursive(root);
+		pr_err(MODULE_NAME ": %s, failed to create debugfs entry\n",
+		       __func__);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/*
+* for triggering the sdio_dld info use:
+* echo 1 > /sys/kernel/debug/sdio_al_dld/sdio_al_dloader_info
+*/
+static int sdio_dld_debug_init(void)
+{
+	sdio_dld_debug.sdio_dld_debug_root =
+				debugfs_create_dir("sdio_al_dld", NULL);
+	if (!sdio_dld_debug.sdio_dld_debug_root) {
+		pr_err(MODULE_NAME ": %s - Failed to create folder. "
+		       "sdio_dld_debug_root is NULL",
+		       __func__);
+		return -ENOENT;
+	}
+
+	sdio_dld_debug.sdio_al_dloader = debugfs_create_file(
+					"sdio_al_dloader_info",
+					S_IRUGO | S_IWUGO,
+					sdio_dld_debug.sdio_dld_debug_root,
+					NULL,
+					&sdio_dld_debug_info_ops);
+
+	if (!sdio_dld_debug.sdio_al_dloader) {
+		pr_err(MODULE_NAME ": %s - Failed to create a file. "
+		       "sdio_al_dloader is NULL",
+		       __func__);
+		debugfs_remove(sdio_dld_debug.sdio_dld_debug_root);
+		sdio_dld_debug.sdio_dld_debug_root = NULL;
+		return -ENOENT;
+	}
+
+	return 0;
+}
+
+static int sdio_dld_debug_info_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t sdio_dld_debug_info_write(struct file *file,
+		const char __user *buf, size_t count, loff_t *ppos)
+{
+	sdio_dld_print_info();
+	return count;
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static void sdio_dld_print_info(void)
+{
+
+	sdio_dld_info.end_time = get_jiffies_64(); /* read the current time */
+	sdio_dld_info.delta_jiffies =
+		sdio_dld_info.end_time - sdio_dld_info.start_time;
+	sdio_dld_info.time_msec = jiffies_to_msecs(sdio_dld_info.delta_jiffies);
+
+	sdio_dld_info.throughput = sdio_dld_info.global_bytes_write_toio *
+		BITS_IN_BYTE / sdio_dld_info.time_msec;
+	sdio_dld_info.throughput /= MS_IN_SEC;
+
+	pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - DURATION IN MSEC = %d\n",
+		__func__,
+		sdio_dld_info.time_msec);
+
+	pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - BYTES WRITTEN ON SDIO BUS "
+			    "= %d...BYTES SENT BY TTY = %d",
+		__func__,
+	       sdio_dld_info.global_bytes_write_toio,
+	       sdio_dld_info.global_bytes_write_tty);
+
+	pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - BYTES RECEIVED ON SDIO BUS "
+			    "= %d...BYTES SENT TO TTY = %d",
+		__func__,
+		sdio_dld_info.global_bytes_read_fromio,
+		sdio_dld_info.global_bytes_push_tty);
+
+	pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - THROUGHPUT=%d Mbit/Sec",
+		__func__, sdio_dld_info.throughput);
+
+	pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT DL_BUFFER_SIZE=%d"
+		" KB..CLIENT UL_BUFFER=%d KB\n",
+		__func__,
+		sdio_dld_info.cl_dl_buffer_size/BYTES_IN_KB,
+		sdio_dld_info.cl_up_buffer_size/BYTES_IN_KB);
+
+	pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - HOST OUTGOING BUFFER_SIZE"
+			    "=%d KB",
+		__func__,
+		sdio_dld_info.host_outgoing_buffer_size/BYTES_IN_KB);
+
+	pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT DL BUFFER "
+		 "ADDRESS = 0x%x", __func__,
+		sdio_dld_info.cl_dl_buffer_address);
+
+	pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT UP BUFFER "
+		"ADDRESS = 0x%x",
+		__func__,
+		sdio_dld_info.cl_up_buffer_address);
+
+	pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT - UPLINK BUFFER - "
+		"READ POINTER = %d", __func__,
+		sdio_dld_info.cl_up_rd_ptr);
+
+	pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT - UPLINK BUFFER - "
+		"WRITE POINTER = %d", __func__,
+		sdio_dld_info.cl_up_wr_ptr);
+
+	pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT - DOWNLINK BUFFER - "
+		"READ POINTER = %d", __func__,
+		sdio_dld_info.cl_dl_rd_ptr);
+
+	pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT - DOWNLINK BUFFER - "
+		"WRITE POINTER = %d", __func__,
+		sdio_dld_info.cl_dl_wr_ptr);
+
+	pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - HOST - OUTGOING BUFFER - "
+		"READ POINTER = %d", __func__,
+		sdio_dld_info.host_read_ptr);
+
+	pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - HOST - OUTGOING BUFFER - "
+		"WRITE POINTER = %d", __func__,
+		sdio_dld_info.host_write_ptr);
+
+	pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - END DEBUG INFO", __func__);
+}
+
+/**
+  * sdio_dld_set_op_mode
+  * sets the op_mode and the name of the op_mode. Also, in case
+  * it's invalid mode sets op_mode to SDIO_DLD_NORMAL_MODE
+  *
+  * @op_mode: the operation mode to be set
+  * @return NONE
+  */
+static void sdio_dld_set_op_mode(enum sdio_dld_op_mode op_mode)
+{
+	sdio_dld->op_mode = op_mode;
+
+	switch (op_mode) {
+	case SDIO_DLD_NORMAL_MODE:
+		memcpy(sdio_dld->op_mode_name,
+		       SDIO_DLD_NORMAL_MODE_NAME, TEST_NAME_MAX_SIZE);
+		break;
+	case SDIO_DLD_BOOT_TEST_MODE:
+		memcpy(sdio_dld->op_mode_name,
+		       SDIO_DLD_BOOT_TEST_MODE_NAME, TEST_NAME_MAX_SIZE);
+		break;
+	case SDIO_DLD_AMSS_TEST_MODE:
+		memcpy(sdio_dld->op_mode_name,
+		       SDIO_DLD_AMSS_TEST_MODE_NAME, TEST_NAME_MAX_SIZE);
+		break;
+	default:
+		sdio_dld->op_mode = SDIO_DLD_NORMAL_MODE;
+		pr_err(MODULE_NAME ": %s - Invalid Op_Mode = %d. Settings "
+		       "Op_Mode to default - NORMAL_MODE\n",
+		       __func__, op_mode);
+		memcpy(sdio_dld->op_mode_name,
+		       SDIO_DLD_NORMAL_MODE_NAME, TEST_NAME_MAX_SIZE);
+		break;
+	}
+
+	if (sdio_dld->op_mode_name != NULL) {
+		pr_info(MODULE_NAME ": %s - FLASHLESS BOOT - Op_Mode is set to "
+			"%s\n", __func__, sdio_dld->op_mode_name);
+	} else {
+		pr_info(MODULE_NAME ": %s - FLASHLESS BOOT - op_mode_name is "
+			"NULL\n", __func__);
+	}
+}
+
+/**
+  * sdio_dld_allocate_local_buffers
+  * allocates local outgoing and incoming buffers and also sets
+  * threshold for outgoing data.
+  *
+  * @return 0 on success or negative value on error.
+  */
+static int sdio_dld_allocate_local_buffers(void)
+{
+	struct sdioc_reg_chunk *reg_str = &sdio_dld->sdio_dloader_data.
+		sdioc_reg;
+	struct sdio_data *outgoing = &sdio_dld->sdio_dloader_data.outgoing_data;
+	struct sdio_data *incoming = &sdio_dld->sdio_dloader_data.incoming_data;
+
+	incoming->data =
+		kzalloc(reg_str->dl_buff_size.reg_val, GFP_KERNEL);
+
+	if (!incoming->data) {
+		pr_err(MODULE_NAME ": %s - param ""incoming->data"" is NULL. "
+		       "Couldn't allocate incoming_data local buffer\n",
+		       __func__);
+		return -ENOMEM;
+	}
+
+	incoming->buffer_size = reg_str->dl_buff_size.reg_val;
+
+	outgoing->data = outgoing_data_buffer;
+
+	outgoing->buffer_size = SDIO_DLD_OUTGOING_BUFFER_SIZE;
+
+	if (outgoing->buffer_size !=
+	    reg_str->ul_buff_size.reg_val*MULTIPLE_RATIO) {
+		pr_err(MODULE_NAME ": %s - HOST outgoing buffer size (%d bytes)"
+		       "must be a multiple of ClIENT uplink buffer size (%d "
+		       "bytes). HOST_SIZE == n*CLIENT_SIZE.(n=1,2,3...)\n",
+		       __func__,
+		       SDIO_DLD_OUTGOING_BUFFER_SIZE,
+		       reg_str->ul_buff_size.reg_val);
+		kfree(incoming->data);
+		return -EINVAL;
+	}
+
+	/* keep sdio_dld_info up to date */
+	sdio_dld_info.host_outgoing_buffer_size = outgoing->buffer_size;
+
+	return 0;
+}
+
+/**
+  * sdio_dld_dealloc_local_buffers frees incoming and outgoing
+  * buffers.
+  *
+  * @return None.
+  */
+static void sdio_dld_dealloc_local_buffers(void)
+{
+	kfree((void *)sdio_dld->sdio_dloader_data.incoming_data.data);
+}
+
+/**
+  * mailbox_to_seq_chunk_read_cfg
+  * reads 4 configuration registers of mailbox from str_func, as
+  * a sequentail chunk in memory, and updates global struct
+  * accordingly.
+  *
+  * @str_func: a pointer to func struct.
+  * @return 0 on success or negative value on error.
+  */
+static int mailbox_to_seq_chunk_read_cfg(struct sdio_func *str_func)
+{
+	struct sdioc_reg_sequential_chunk_cfg seq_chunk;
+	struct sdioc_reg_chunk *reg = &sdio_dld->sdio_dloader_data.sdioc_reg;
+	int status = 0;
+
+	if (!str_func) {
+		pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	sdio_claim_host(str_func);
+
+	/* reading SDIOC_MAILBOX_SIZE bytes from SDIOC_MAILBOX_ADDRESS */
+	status = sdio_memcpy_fromio(str_func,
+				    (void *)&seq_chunk,
+				    SDIOC_MAILBOX_ADDRESS,
+				    SDIOC_CFG_REGS_SIZE);
+	if (status) {
+		pr_err(MODULE_NAME ": %s - sdio_memcpy_fromio()"
+		       " READING CFG MAILBOX failed. status=%d.\n",
+		       __func__, status);
+	}
+
+	sdio_release_host(str_func);
+
+	reg->dl_buff_address.reg_val = seq_chunk.dl_buff_address;
+	reg->up_buff_address.reg_val = seq_chunk.up_buff_address;
+	reg->dl_buff_size.reg_val = seq_chunk.dl_buff_size;
+	reg->ul_buff_size.reg_val = seq_chunk.ul_buff_size;
+
+	/* keep sdio_dld_info up to date */
+	sdio_dld_info.cl_dl_buffer_size = seq_chunk.dl_buff_size;
+	sdio_dld_info.cl_up_buffer_size = seq_chunk.ul_buff_size;
+	sdio_dld_info.cl_dl_buffer_address = seq_chunk.dl_buff_address;
+	sdio_dld_info.cl_up_buffer_address = seq_chunk.up_buff_address;
+
+	return status;
+}
+
+/**
+  * mailbox_to_seq_chunk_read_ptrs
+  * reads 4 pointers registers of mailbox from str_func, as a
+  * sequentail chunk in memory, and updates global struct
+  * accordingly.
+  *
+  * @str_func: a pointer to func struct.
+  * @return 0 on success or negative value on error.
+  */
+static int mailbox_to_seq_chunk_read_ptrs(struct sdio_func *str_func)
+{
+	struct sdioc_reg_sequential_chunk_ptrs seq_chunk;
+	struct sdioc_reg_chunk *reg = &sdio_dld->sdio_dloader_data.sdioc_reg;
+	int status = 0;
+
+	struct sdio_data *outgoing = &sdio_dld->sdio_dloader_data.outgoing_data;
+	static int counter = 1;
+	static int offset_write_p;
+	static int offset_read_p;
+	static int up_wr_ptr;
+	static int up_rd_ptr;
+	static int dl_wr_ptr;
+	static int dl_rd_ptr;
+
+	if (!str_func) {
+		pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	sdio_claim_host(str_func);
+
+	/* reading SDIOC_MAILBOX_SIZE bytes from SDIOC_MAILBOX_ADDRESS */
+	status = sdio_memcpy_fromio(str_func,
+				    (void *)&seq_chunk,
+				    SDIOC_PTRS_OFFSET,
+				    SDIOC_PTR_REGS_SIZE);
+	if (status) {
+		pr_err(MODULE_NAME ": %s - sdio_memcpy_fromio()"
+		       " READING PTRS MAILBOX failed. status=%d.\n",
+		       __func__, status);
+	}
+
+	sdio_release_host(str_func);
+
+	reg->dl_rd_ptr.reg_val = seq_chunk.dl_rd_ptr;
+	reg->dl_wr_ptr.reg_val = seq_chunk.dl_wr_ptr;
+	reg->up_rd_ptr.reg_val = seq_chunk.up_rd_ptr;
+	reg->up_wr_ptr.reg_val = seq_chunk.up_wr_ptr;
+
+	/* keeping sdio_dld_info up to date */
+	sdio_dld_info.cl_dl_rd_ptr = seq_chunk.dl_rd_ptr;
+	sdio_dld_info.cl_dl_wr_ptr = seq_chunk.dl_wr_ptr;
+	sdio_dld_info.cl_up_rd_ptr = seq_chunk.up_rd_ptr;
+	sdio_dld_info.cl_up_wr_ptr = seq_chunk.up_wr_ptr;
+
+
+	/* DEBUG - if there was a change in value */
+	if ((offset_write_p != outgoing->offset_write_p) ||
+	    (offset_read_p != outgoing->offset_read_p) ||
+	    (up_wr_ptr != reg->up_wr_ptr.reg_val) ||
+	    (up_rd_ptr != reg->up_rd_ptr.reg_val) ||
+	    (dl_wr_ptr != reg->dl_wr_ptr.reg_val) ||
+	    (dl_rd_ptr != reg->dl_rd_ptr.reg_val) ||
+	    (counter % PRINTING_GAP == 0)) {
+		counter = 1;
+		pr_debug(MODULE_NAME ": %s MailBox pointers: BLOCK_SIZE=%d, "
+			 "hw=%d, hr=%d, cuw=%d, cur=%d, cdw=%d, cdr=%d\n",
+			 __func__,
+			 SDIO_DL_BLOCK_SIZE,
+			 outgoing->offset_write_p,
+			 outgoing->offset_read_p,
+			 reg->up_wr_ptr.reg_val,
+			 reg->up_rd_ptr.reg_val,
+			 reg->dl_wr_ptr.reg_val,
+			 reg->dl_rd_ptr.reg_val);
+
+#ifdef CONFIG_DEBUG_FS
+		update_gd(SDIO_DLD_DEBUGFS_CASE_1_CODE);
+#endif
+		/* update static variables */
+		offset_write_p = outgoing->offset_write_p;
+		offset_read_p =	outgoing->offset_read_p;
+		up_wr_ptr = reg->up_wr_ptr.reg_val;
+		up_rd_ptr = reg->up_rd_ptr.reg_val;
+		dl_wr_ptr = reg->dl_wr_ptr.reg_val;
+		dl_rd_ptr = reg->dl_rd_ptr.reg_val;
+	} else {
+		counter++;
+	}
+	return status;
+}
+
+/**
+  * sdio_dld_init_func
+  * enables the sdio func, and sets the func block size.
+  *
+  * @str_func: a pointer to func struct.
+  * @return 0 on success or negative value on error.
+  */
+static int sdio_dld_init_func(struct sdio_func *str_func)
+{
+	int status1 = 0;
+	int status2 = 0;
+
+	if (!str_func) {
+		pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	sdio_claim_host(str_func);
+
+	status1 = sdio_enable_func(str_func);
+	if (status1) {
+		sdio_release_host(str_func);
+		pr_err(MODULE_NAME ": %s - sdio_enable_func() failed. "
+		       "status=%d\n", __func__, status1);
+		return status1;
+	}
+
+	status2 = sdio_set_block_size(str_func, SDIO_DL_BLOCK_SIZE);
+	if (status2) {
+		pr_err(MODULE_NAME ": %s - sdio_set_block_size() failed. "
+		       "status=%d\n", __func__, status2);
+		status1 = sdio_disable_func(str_func);
+		if (status1) {
+			pr_err(MODULE_NAME ": %s - sdio_disable_func() "
+		       "failed. status=%d\n", __func__, status1);
+		}
+		sdio_release_host(str_func);
+		return status2;
+	}
+
+	sdio_release_host(str_func);
+	str_func->max_blksize = SDIO_DL_BLOCK_SIZE;
+	return 0;
+}
+
+/**
+  * sdio_dld_allocate_buffers
+  * initializes the sdio func, and then reads the mailbox, in
+  * order to allocate incoming and outgoing buffers according to
+  * the size that was read from the mailbox.
+  *
+  * @str_func: a pointer to func struct.
+  * @return 0 on success or negative value on error.
+  */
+static int sdio_dld_allocate_buffers(struct sdio_func *str_func)
+{
+	int status = 0;
+
+	if (!str_func) {
+		pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	status = mailbox_to_seq_chunk_read_cfg(str_func);
+	if (status) {
+		pr_err(MODULE_NAME ": %s - Failure in Function "
+		       "mailbox_to_seq_chunk_read_cfg(). status=%d\n",
+		       __func__, status);
+		return status;
+	}
+
+	status = sdio_dld_allocate_local_buffers();
+	if (status) {
+		pr_err(MODULE_NAME ": %s - Failure in Function "
+		       "sdio_dld_allocate_local_buffers(). status=%d\n",
+		       __func__, status);
+		return status;
+	}
+	return 0;
+}
+
+/**
+  * sdio_dld_create_thread
+  * creates thread and wakes it up.
+  *
+  * @return 0 on success or negative value on error.
+  */
+static int sdio_dld_create_thread(void)
+{
+	sdio_dld->dld_main_thread.task_name = SDIO_DL_MAIN_THREAD_NAME;
+
+	sdio_dld->dld_main_thread.dld_task =
+		kthread_create(sdio_dld_main_task,
+			       (void *)(sdio_dld->card),
+			       sdio_dld->dld_main_thread.task_name);
+
+	if (IS_ERR(sdio_dld->dld_main_thread.dld_task)) {
+		pr_err(MODULE_NAME ": %s - kthread_create() failed\n",
+			__func__);
+		return -ENOMEM;
+	}
+	wake_up_process(sdio_dld->dld_main_thread.dld_task);
+	return 0;
+}
+
+/**
+  * start_timer
+  * sets the timer and starts.
+  *
+  * @timer: the timer to configure and add
+  * @ms: the ms until it expires
+  * @return None.
+  */
+static void start_timer(struct timer_list *timer, unsigned int ms)
+{
+	if ((ms == 0) || (timer == NULL)) {
+		pr_err(MODULE_NAME ": %s - invalid parameter", __func__);
+	} else {
+		timer->expires = jiffies +
+			msecs_to_jiffies(ms);
+		add_timer(timer);
+	}
+}
+
+/**
+  * sdio_dld_timer_handler
+  * this is the timer handler. whenever it is invoked, it wakes
+  * up the main loop task, and the write callback, and starts
+  * the timer again.
+  *
+  * @data: a pointer to the tty device driver structure.
+  * @return None.
+  */
+
+static void sdio_dld_timer_handler(unsigned long data)
+{
+	pr_debug(MODULE_NAME " Timer Expired\n");
+	spin_lock_irqsave(&lock2, lock_flags2);
+	if (sdio_dld->main_loop_event.wake_up_signal == 0) {
+		sdio_dld->main_loop_event.wake_up_signal = 1;
+		wake_up(&sdio_dld->main_loop_event.wait_event);
+	}
+	spin_unlock_irqrestore(&lock2, lock_flags2);
+
+	sdio_dld->write_callback_event.wake_up_signal = 1;
+	wake_up(&sdio_dld->write_callback_event.wait_event);
+
+	start_timer(&sdio_dld->timer, sdio_dld->poll_ms);
+}
+
+/**
+  * sdio_dld_push_timer_handler
+  * this is a timer handler of the push_timer.
+  *
+  * @data: a pointer to the tty device driver structure.
+  * @return None.
+  */
+static void sdio_dld_push_timer_handler(unsigned long data)
+{
+	pr_err(MODULE_NAME " %s - Push Timer Expired... Trying to "
+		"push data to TTY Core for over then %d ms.\n",
+		__func__, sdio_dld->push_timer_ms);
+}
+
+/**
+  * sdio_dld_open
+  * this is the open callback of the tty driver.
+  * it initializes the sdio func, allocates the buffers, and
+  * creates the main thread.
+  *
+  * @tty: a pointer to the tty struct.
+  * @file: file descriptor.
+  * @return 0 on success or negative value on error.
+  */
+static int sdio_dld_open(struct tty_struct *tty, struct file *file)
+{
+	int status = 0;
+	int func_in_array =
+		REAL_FUNC_TO_FUNC_IN_ARRAY(sdio_dld->sdioc_boot_func);
+	struct sdio_func *str_func = sdio_dld->card->sdio_func[func_in_array];
+
+	sdio_dld->tty_str = tty;
+	sdio_dld->tty_str->low_latency = 1;
+	sdio_dld->tty_str->icanon = 0;
+	set_bit(TTY_NO_WRITE_SPLIT, &sdio_dld->tty_str->flags);
+
+	pr_info(MODULE_NAME ": %s, TTY DEVICE FOR FLASHLESS BOOT OPENED\n",
+	       __func__);
+	sdio_dld_info.start_time = get_jiffies_64(); /* read the current time */
+
+	if (!tty) {
+		pr_err(MODULE_NAME ": %s - param ""tty"" is NULL.\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	if (!str_func) {
+		pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	atomic_set(&sdio_dld->dld_main_thread.please_close, 0);
+	sdio_dld->dld_main_thread.exit_wait.wake_up_signal = 0;
+
+	status = sdio_dld_allocate_buffers(str_func);
+	if (status) {
+		pr_err(MODULE_NAME ": %s, failed in "
+		       "sdio_dld_allocate_buffers(). status=%d\n",
+		       __func__, status);
+		return status;
+	}
+
+	/* init waiting event of the write callback */
+	init_waitqueue_head(&sdio_dld->write_callback_event.wait_event);
+
+	/* init waiting event of the main loop */
+	init_waitqueue_head(&sdio_dld->main_loop_event.wait_event);
+
+	/* configure and init the timer */
+	sdio_dld->poll_ms = TIMER_DURATION;
+	init_timer(&sdio_dld->timer);
+	sdio_dld->timer.data = (unsigned long) sdio_dld;
+	sdio_dld->timer.function = sdio_dld_timer_handler;
+	sdio_dld->timer.expires = jiffies +
+		msecs_to_jiffies(sdio_dld->poll_ms);
+	add_timer(&sdio_dld->timer);
+
+	sdio_dld->push_timer_ms = PUSH_TIMER_DURATION;
+	init_timer(&sdio_dld->push_timer);
+	sdio_dld->push_timer.data = (unsigned long) sdio_dld;
+	sdio_dld->push_timer.function = sdio_dld_push_timer_handler;
+
+	status = sdio_dld_create_thread();
+	if (status) {
+		del_timer_sync(&sdio_dld->timer);
+		del_timer_sync(&sdio_dld->push_timer);
+		sdio_dld_dealloc_local_buffers();
+		pr_err(MODULE_NAME ": %s, failed in sdio_dld_create_thread()."
+				   "status=%d\n", __func__, status);
+		return status;
+	}
+	return 0;
+}
+
+/**
+  * sdio_dld_close
+  * this is the close callback of the tty driver. it requests
+  * the main thread to exit, and waits for notification of it.
+  * it also de-allocates the buffers, and unregisters the tty
+  * driver and device.
+  *
+  * @tty: a pointer to the tty struct.
+  * @file: file descriptor.
+  * @return None.
+  */
+static void sdio_dld_close(struct tty_struct *tty, struct file *file)
+{
+	int status = 0;
+	struct sdioc_reg_chunk *reg = &sdio_dld->sdio_dloader_data.sdioc_reg;
+
+	/* informing the SDIOC that it can exit boot phase */
+	sdio_dld->sdio_dloader_data.sdioc_reg.good_to_exit_ptr.reg_val =
+		SDIOC_EXIT_CODE;
+
+	atomic_set(&sdio_dld->dld_main_thread.please_close, 1);
+
+	pr_debug(MODULE_NAME ": %s - CLOSING - WAITING...", __func__);
+
+	wait_event(sdio_dld->dld_main_thread.exit_wait.wait_event,
+		   sdio_dld->dld_main_thread.exit_wait.wake_up_signal);
+	pr_debug(MODULE_NAME ": %s - CLOSING - WOKE UP...", __func__);
+
+	del_timer_sync(&sdio_dld->timer);
+	del_timer_sync(&sdio_dld->push_timer);
+
+	sdio_dld_dealloc_local_buffers();
+
+	tty_unregister_device(sdio_dld->tty_drv, 0);
+
+	status = tty_unregister_driver(sdio_dld->tty_drv);
+
+	if (status) {
+		pr_err(MODULE_NAME ": %s - tty_unregister_driver() failed\n",
+		       __func__);
+	}
+
+#ifdef CONFIG_DEBUG_FS
+	gd.curr_i = curr_index;
+	gd.duration_ms = sdio_dld_info.time_msec;
+	gd.global_bytes_sent = sdio_dld_info.global_bytes_write_toio;
+	gd.global_bytes_received = 0;
+	gd.throughput_Mbs = sdio_dld_info.throughput;
+	gd.host_outgoing_buffer_size_KB = sdio_dld->sdio_dloader_data.
+		outgoing_data.buffer_size/BYTES_IN_KB;
+	gd.client_up_buffer_size_KB = reg->ul_buff_size.reg_val/BYTES_IN_KB;
+	gd.client_dl_buffer_size_KB = reg->dl_buff_size.reg_val/BYTES_IN_KB;
+	gd.client_dl_buffer_address = reg->dl_buff_address.reg_val;
+	gd.client_up_buffer_address = reg->up_buff_address.reg_val;
+	gd.global_bytes_received = sdio_dld_info.global_bytes_read_fromio;
+	gd.global_bytes_pushed = sdio_dld_info.global_bytes_push_tty;
+#endif
+
+	/* saving register values before deallocating sdio_dld
+	   in order to use it in sdio_dld_print_info() through shell command */
+	sdio_dld_info.cl_dl_rd_ptr = reg->dl_rd_ptr.reg_val;
+	sdio_dld_info.cl_dl_wr_ptr = reg->dl_wr_ptr.reg_val;
+	sdio_dld_info.cl_up_rd_ptr = reg->up_rd_ptr.reg_val;
+	sdio_dld_info.cl_up_wr_ptr = reg->up_wr_ptr.reg_val;
+
+	sdio_dld_info.host_read_ptr =
+		sdio_dld->sdio_dloader_data.outgoing_data.offset_read_p;
+
+	sdio_dld_info.host_write_ptr =
+		sdio_dld->sdio_dloader_data.outgoing_data.offset_write_p;
+
+	sdio_dld_info.cl_dl_buffer_size =
+		sdio_dld->sdio_dloader_data.sdioc_reg.dl_buff_size.reg_val;
+
+	sdio_dld_info.cl_up_buffer_size =
+		sdio_dld->sdio_dloader_data.sdioc_reg.ul_buff_size.reg_val;
+
+	sdio_dld_info.host_outgoing_buffer_size =
+		sdio_dld->sdio_dloader_data.outgoing_data.buffer_size;
+
+	sdio_dld_info.cl_dl_buffer_address =
+		sdio_dld->sdio_dloader_data.sdioc_reg.dl_buff_address.reg_val;
+
+	sdio_dld_info.cl_up_buffer_address =
+		sdio_dld->sdio_dloader_data.sdioc_reg.up_buff_address.reg_val;
+
+	sdio_dld_print_info();
+
+	if (sdio_dld->done_callback)
+		sdio_dld->done_callback();
+
+	pr_info(MODULE_NAME ": %s - Freeing sdio_dld data structure, and "
+		" returning...", __func__);
+	kfree(sdio_dld);
+}
+
+/**
+  * writing_size_to_buf
+  * writes from src buffer into dest buffer. if dest buffer
+  * reaches its end, rollover happens.
+  *
+  * @dest: destination buffer.
+  * @src: source buffer.
+  * @dest_wr_ptr: writing pointer in destination buffer.
+  * @dest_size: destination buffer size.
+  * @dest_rd_ptr: reading pointer in destination buffer.
+  * @size_to_write: size of bytes to write.
+  * @return -how many bytes actually written to destination
+  * buffer.
+  *
+  * ONLY destination buffer is treated as cyclic buffer.
+  */
+static int writing_size_to_buf(char *dest,
+			       const unsigned char *src,
+			       int *dest_wr_ptr,
+			       int dest_size,
+			       int dest_rd_ptr,
+			       int size_to_write)
+{
+	int actually_written = 0;
+	int size_to_add = *dest_wr_ptr;
+
+	if (!dest) {
+		pr_err(MODULE_NAME ": %s - param ""dest"" is NULL.\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	if (!src) {
+		pr_err(MODULE_NAME ": %s - param ""src"" is NULL.\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	if (!dest_wr_ptr) {
+		pr_err(MODULE_NAME ": %s - param ""dest_wr_ptr"" is NULL.\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	for (actually_written = 0 ;
+	      actually_written < size_to_write ; ++actually_written) {
+		/* checking if buffer is full */
+		if (((size_to_add + 1) % dest_size) == dest_rd_ptr) {
+			*dest_wr_ptr = size_to_add;
+			return actually_written;
+		}
+
+		dest[size_to_add] = src[actually_written];
+		size_to_add = (size_to_add+1)%dest_size;
+	}
+
+	*dest_wr_ptr = size_to_add;
+
+	return actually_written;
+}
+
+/**
+  * sdioc_bytes_till_end_of_buffer - this routine calculates how many bytes are
+  * empty/in use. if calculation requires rap around - it will ignore the rap
+  * around and will do the calculation untill the end of the buffer
+  *
+  * @write_ptr: writing pointer.
+  * @read_ptr: reading pointer.
+  * @total_size: buffer size.
+  * @free_bytes: return value-how many free bytes.
+  * @bytes_in_use: return value-how many bytes in use.
+  * @return 0 on success or negative value on error.
+  *
+  * buffer is treated as a cyclic buffer.
+  */
+static int sdioc_bytes_till_end_of_buffer(int write_ptr,
+					  int read_ptr,
+					  int total_size,
+					  int *free_bytes,
+					  int *bytes_in_use)
+{
+	if (!free_bytes) {
+		pr_err(MODULE_NAME ": %s - param ""free_bytes"" is NULL.\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	if (!bytes_in_use) {
+		pr_err(MODULE_NAME ": %s - param ""bytes_in_use"" is NULL.\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	if (write_ptr >= read_ptr) {
+		if (read_ptr == 0)
+			*free_bytes = total_size - write_ptr - 1;
+		else
+			*free_bytes = total_size - write_ptr;
+		*bytes_in_use = write_ptr - read_ptr;
+	} else {
+		*bytes_in_use = total_size - read_ptr;
+		*free_bytes = read_ptr - write_ptr - 1;
+	}
+
+	return  0;
+}
+
+/**
+  * sdioc_bytes_free_in_buffer
+  * this routine calculates how many bytes are free in a buffer
+  * and how many are in use, according to its reading and
+  * writing pointer offsets.
+  *
+  * @write_ptr: writing pointer.
+  * @read_ptr: reading pointer.
+  * @total_size: buffer size.
+  * @free_bytes: return value-how many free bytes in buffer.
+  * @bytes_in_use: return value-how many bytes in use in buffer.
+  * @return 0 on success or negative value on error.
+  *
+  * buffer is treated as a cyclic buffer.
+  */
+static int sdioc_bytes_free_in_buffer(int write_ptr,
+				      int read_ptr,
+				      int total_size,
+				      int *free_bytes,
+				      int *bytes_in_use)
+{
+	if (!free_bytes) {
+		pr_err(MODULE_NAME ": %s - param ""free_bytes"" is NULL.\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	if (!bytes_in_use) {
+		pr_err(MODULE_NAME ": %s - param ""bytes_in_use"" is NULL.\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	/* if pointers equel - buffers are empty. nothing to read/write */
+
+	if (write_ptr >= read_ptr)
+		*bytes_in_use = write_ptr - read_ptr;
+	else
+		*bytes_in_use = total_size - (read_ptr - write_ptr);
+
+	*free_bytes = total_size - *bytes_in_use - 1;
+
+	return 0;
+}
+
+/*
+* sdio_dld_write_room
+*
+* This is the write_room function of the tty driver.
+*
+* @tty: pointer to tty struct.
+* @return free bytes for write.
+*
+*/
+static int sdio_dld_write_room(struct tty_struct *tty)
+{
+	return sdio_dld->sdio_dloader_data.outgoing_data.buffer_size;
+}
+
+/**
+  * sdio_dld_write_callback
+  * this is the write callback of the tty driver.
+  *
+  * @tty: pointer to tty struct.
+  * @buf: buffer to write from.
+  * @count: number of bytes to write.
+  * @return bytes written or negative value on error.
+  *
+  * if destination buffer has not enough room for the incoming
+  * data, returns an error.
+  */
+static int sdio_dld_write_callback(struct tty_struct *tty,
+				   const unsigned char *buf, int count)
+{
+	struct sdio_data *outgoing = &sdio_dld->sdio_dloader_data.outgoing_data;
+	int dst_free_bytes = 0;
+	int dummy = 0;
+	int status = 0;
+	int bytes_written = 0;
+	int total_written = 0;
+	static int write_retry;
+	int pending_to_write = count;
+
+#ifdef CONFIG_DEBUG_FS
+	debugfs_glob.global_count = count;
+	update_gd(SDIO_DLD_DEBUGFS_CASE_5_CODE);
+#endif
+
+	pr_debug(MODULE_NAME ": %s - WRITING CALLBACK CALLED WITH %d bytes\n",
+		 __func__, count);
+
+	if (!outgoing->data) {
+		pr_err(MODULE_NAME ": %s - param ""outgoing->data"" is NULL.\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	pr_debug(MODULE_NAME ": %s - WRITE CALLBACK size to write to outgoing"
+		 " buffer %d\n", __func__, count);
+
+	/* as long as there is something to write to outgoing buffer */
+	do {
+		int bytes_to_write = 0;
+		status = sdioc_bytes_free_in_buffer(
+			outgoing->offset_write_p,
+			outgoing->offset_read_p,
+			outgoing->buffer_size,
+			&dst_free_bytes,
+			&dummy);
+
+		if (status) {
+			pr_err(MODULE_NAME ": %s - Failure in Function "
+			       "sdioc_bytes_free_in_buffer(). status=%d\n",
+			       __func__, status);
+			return status;
+		}
+
+		/*
+		 * if there is free room in outgoing buffer
+		 * lock mutex and request trigger notification from the main
+		 * task. unlock mutex, and wait for sinal
+		 */
+		if (dst_free_bytes > 0) {
+			write_retry = 0;
+			/*
+			 * if there is more data to write to outgoing buffer
+			 * than it can receive, wait for signal from main task
+			 */
+			if (pending_to_write > dst_free_bytes) {
+
+				/* sampling updated dst_free_bytes */
+				status = sdioc_bytes_free_in_buffer(
+				outgoing->offset_write_p,
+				outgoing->offset_read_p,
+				outgoing->buffer_size,
+				&dst_free_bytes,
+				&dummy);
+
+				if (status) {
+					pr_err(MODULE_NAME ": %s - Failure in "
+							   "Function "
+					       "sdioc_bytes_free_in_buffer(). "
+					       "status=%d\n", __func__, status);
+					return status;
+				}
+			}
+
+			bytes_to_write = min(pending_to_write, dst_free_bytes);
+			bytes_written =
+				writing_size_to_buf(outgoing->data,
+						    buf+total_written,
+						    &outgoing->offset_write_p,
+						    outgoing->buffer_size,
+						    outgoing->offset_read_p,
+						    bytes_to_write);
+
+			/* keeping sdio_dld_info up to date */
+			sdio_dld_info.host_write_ptr =
+				sdio_dld->sdio_dloader_data.
+					    outgoing_data.offset_write_p;
+
+#ifdef CONFIG_DEBUG_FS
+			debugfs_glob.global_write_tty = bytes_written;
+			update_gd(SDIO_DLD_DEBUGFS_CASE_3_CODE);
+#endif
+			sdio_dld_info.global_bytes_write_tty += bytes_written;
+
+			spin_lock_irqsave(&lock2, lock_flags2);
+			if (sdio_dld->main_loop_event.wake_up_signal == 0) {
+				sdio_dld->main_loop_event.wake_up_signal = 1;
+				wake_up(&sdio_dld->main_loop_event.wait_event);
+			}
+			spin_unlock_irqrestore(&lock2, lock_flags2);
+
+			/*
+			 * although outgoing buffer has enough room, writing
+			 * failed
+			 */
+			if (bytes_written != bytes_to_write) {
+				pr_err(MODULE_NAME ": %s - couldn't write "
+				       "%d bytes to " "outgoing buffer."
+				       "bytes_written=%d\n",
+				       __func__, bytes_to_write,
+				       bytes_written);
+			       return -EIO;
+			}
+
+			total_written += bytes_written;
+			pending_to_write -= bytes_written;
+			outgoing->num_of_bytes_in_use += bytes_written;
+
+			pr_debug(MODULE_NAME ": %s - WRITE CHUNK to outgoing "
+					   "buffer. pending_to_write=%d, "
+					   "outgoing_free_bytes=%d, "
+					   "bytes_written=%d\n",
+				 __func__,
+				 pending_to_write,
+				 dst_free_bytes,
+				 bytes_written);
+
+		} else {
+			write_retry++;
+
+			pr_debug(MODULE_NAME ": %s - WRITE CALLBACK - NO ROOM."
+			       " pending_to_write=%d, write_retry=%d\n",
+				 __func__,
+				 pending_to_write,
+				 write_retry);
+
+			spin_lock_irqsave(&lock1, lock_flags1);
+			sdio_dld->write_callback_event.wake_up_signal = 0;
+			spin_unlock_irqrestore(&lock1, lock_flags1);
+
+			pr_debug(MODULE_NAME ": %s - WRITE CALLBACK - "
+					     "WAITING...", __func__);
+#ifdef CONFIG_DEBUG_FS
+			update_gd(SDIO_DLD_DEBUGFS_CASE_8_CODE);
+#endif
+			wait_event(sdio_dld->write_callback_event.wait_event,
+				   sdio_dld->write_callback_event.
+				   wake_up_signal);
+#ifdef CONFIG_DEBUG_FS
+			update_gd(SDIO_DLD_DEBUGFS_CASE_9_CODE);
+#endif
+			pr_debug(MODULE_NAME ": %s - WRITE CALLBACK - "
+					     "WOKE UP...", __func__);
+		}
+	} while (pending_to_write > 0 && write_retry < WRITE_RETRIES);
+
+	if (pending_to_write > 0) {
+
+		pr_err(MODULE_NAME ": %s - WRITE CALLBACK - pending data is "
+				   "%d out of %d > 0. total written in this "
+				   "callback = %d\n",
+		       __func__, pending_to_write, count, total_written);
+	}
+
+	if (write_retry == WRITE_RETRIES) {
+		pr_err(MODULE_NAME ": %s, write_retry=%d= max\n",
+		       __func__, write_retry);
+	}
+
+#ifdef CONFIG_DEBUG_FS
+	debugfs_glob.global_bytes_cb_tty = total_written;
+	update_gd(SDIO_DLD_DEBUGFS_CASE_10_CODE);
+#endif
+
+	return total_written;
+}
+
+/**
+  * sdio_memcpy_fromio_wrapper -
+  * reads from sdioc, and updats the sdioc registers according
+  * to how many bytes were actually read.
+  *
+  * @str_func: a pointer to func struct.
+  * @client_rd_ptr: sdioc value of downlink read ptr.
+  * @client_wr_ptr: sdioc value of downlink write ptr.
+  * @buffer_to_store: buffer to store incoming data.
+  * @address_to_read: address to start reading from in sdioc.
+  * @size_to_read: size of bytes to read.
+  * @client_buffer_size: sdioc downlink buffer size.
+  * @return 0 on success or negative value on error.
+  */
+static int sdio_memcpy_fromio_wrapper(struct sdio_func *str_func,
+				      unsigned int client_rd_ptr,
+				      unsigned int client_wr_ptr,
+				      void *buffer_to_store,
+				      unsigned int address_to_read_from,
+				      int size_to_read,
+				      int client_buffer_size)
+{
+	int status = 0;
+	struct sdioc_reg_chunk *reg_str =
+		&sdio_dld->sdio_dloader_data.sdioc_reg;
+
+	if (!str_func) {
+		pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	if (!buffer_to_store) {
+		pr_err(MODULE_NAME ": %s - param ""buffer_to_store"" is "
+				   "NULL.\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	if (size_to_read < 0) {
+		pr_err(MODULE_NAME ": %s - invalid size to read=%d\n",
+			__func__, size_to_read);
+		return -EINVAL;
+	}
+
+	sdio_claim_host(str_func);
+
+	pr_debug(MODULE_NAME ": %s, READING DATA - from add %d, "
+			   "size_to_read=%d\n",
+	       __func__, address_to_read_from, size_to_read);
+
+	status = sdio_memcpy_fromio(str_func,
+				    (void *)buffer_to_store,
+				    address_to_read_from,
+				    size_to_read);
+	if (status) {
+		pr_err(MODULE_NAME ": %s - sdio_memcpy_fromio()"
+		       " DATA failed. status=%d.\n",
+		       __func__, status);
+		sdio_release_host(str_func);
+		return status;
+	}
+
+	/* updating an offset according to cyclic buffer size */
+	reg_str->dl_rd_ptr.reg_val =
+		(reg_str->dl_rd_ptr.reg_val + size_to_read) %
+		client_buffer_size;
+	/* keeping sdio_dld_info up to date */
+	sdio_dld_info.cl_dl_rd_ptr = reg_str->dl_rd_ptr.reg_val;
+
+	status = sdio_memcpy_toio(str_func,
+				  reg_str->dl_rd_ptr.reg_offset,
+				  (void *)&reg_str->dl_rd_ptr.reg_val,
+				  sizeof(reg_str->dl_rd_ptr.reg_val));
+
+	if (status) {
+		pr_err(MODULE_NAME ": %s - sdio_memcpy_toio() "
+		       "UPDATE PTR failed. status=%d.\n",
+		       __func__, status);
+	}
+
+	sdio_release_host(str_func);
+	return status;
+}
+
+/**
+  * sdio_memcpy_toio_wrapper
+  * writes to sdioc, and updats the sdioc registers according
+  * to how many bytes were actually read.
+  *
+  * @str_func: a pointer to func struct.
+  * @client_wr_ptr: sdioc downlink write ptr.
+  * @h_read_ptr: host incoming read ptrs
+  * @buf_write_from: buffer to write from.
+  * @bytes_to_write: number of bytes to write.
+  * @return 0 on success or negative value on error.
+  */
+static int sdio_memcpy_toio_wrapper(struct sdio_func *str_func,
+				    unsigned int client_wr_ptr,
+				    unsigned int h_read_ptr,
+				    void *buf_write_from,
+				    int bytes_to_write)
+{
+	int status = 0;
+	struct sdioc_reg_chunk *reg_str =
+		&sdio_dld->sdio_dloader_data.sdioc_reg;
+	struct sdio_data *outgoing = &sdio_dld->sdio_dloader_data.outgoing_data;
+
+	if (!str_func) {
+		pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	if (!buf_write_from) {
+		pr_err(MODULE_NAME ": %s - param ""buf_write_from"" is NULL.\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	sdio_claim_host(str_func);
+
+	pr_debug(MODULE_NAME ": %s, WRITING DATA TOIO to address 0x%x, "
+		 "bytes_to_write=%d\n",
+		 __func__,
+		reg_str->up_buff_address.reg_val + reg_str->up_wr_ptr.reg_val,
+		 bytes_to_write);
+
+	status = sdio_memcpy_toio(str_func,
+				  reg_str->up_buff_address.reg_val +
+				  reg_str->up_wr_ptr.reg_val,
+				  (void *) (outgoing->data + h_read_ptr),
+				  bytes_to_write);
+
+	if (status) {
+		pr_err(MODULE_NAME ": %s - sdio_memcpy_toio() "
+		       "DATA failed. status=%d.\n", __func__, status);
+		sdio_release_host(str_func);
+		return status;
+	}
+
+	sdio_dld_info.global_bytes_write_toio += bytes_to_write;
+	outgoing->num_of_bytes_in_use -= bytes_to_write;
+
+	/*
+	 * if writing to client succeeded, then
+	 * 1. update the client up_wr_ptr
+	 * 2. update the host outgoing rd ptr
+	 **/
+	reg_str->up_wr_ptr.reg_val =
+		((reg_str->up_wr_ptr.reg_val + bytes_to_write) %
+		 reg_str->ul_buff_size.reg_val);
+
+	/* keeping sdio_dld_info up to date */
+	sdio_dld_info.cl_up_wr_ptr = reg_str->up_wr_ptr.reg_val;
+
+	outgoing->offset_read_p =
+		((outgoing->offset_read_p + bytes_to_write) %
+		  outgoing->buffer_size);
+
+	/* keeping sdio_dld_info up to date*/
+	sdio_dld_info.host_read_ptr = outgoing->offset_read_p;
+
+#ifdef CONFIG_DEBUG_FS
+	debugfs_glob.global_write_toio = bytes_to_write;
+	update_gd(SDIO_DLD_DEBUGFS_CASE_4_CODE);
+#endif
+
+	/* updating uplink write pointer according to size that was written */
+	status = sdio_memcpy_toio(str_func,
+				  reg_str->up_wr_ptr.reg_offset,
+				  (void *)(&reg_str->up_wr_ptr.reg_val),
+				  sizeof(reg_str->up_wr_ptr.reg_val));
+	if (status) {
+		pr_err(MODULE_NAME ": %s - sdio_memcpy_toio() "
+				       "UPDATE PTR failed. status=%d.\n",
+		       __func__, status);
+	}
+
+	sdio_release_host(str_func);
+	return status;
+}
+
+/**
+  * sdio_dld_read
+  * reads from sdioc
+  *
+  * @client_rd_ptr: sdioc downlink read ptr.
+  * @client_wr_ptr: sdioc downlink write ptr.
+  * @reg_str: sdioc register shadowing struct.
+  * @str_func: a pointer to func struct.
+  * @bytes_read:how many bytes read.
+  * @return 0 on success or negative value on error.
+  */
+static int sdio_dld_read(unsigned int client_rd_ptr,
+			 unsigned int client_wr_ptr,
+			 struct sdioc_reg_chunk *reg_str,
+			 struct sdio_func *str_func,
+			 int *bytes_read)
+{
+	int status = 0;
+	struct sdio_data *incoming = &sdio_dld->sdio_dloader_data.incoming_data;
+
+	if (!reg_str) {
+		pr_err(MODULE_NAME ": %s - param ""reg_str"" is NULL.\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	if (!str_func) {
+		pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	if (!bytes_read) {
+		pr_err(MODULE_NAME ": %s - param ""bytes_read"" is NULL.\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	/* there is data to read in ONE chunk */
+	if (client_wr_ptr > client_rd_ptr) {
+		status = sdio_memcpy_fromio_wrapper(
+			str_func,
+			client_rd_ptr,
+			client_wr_ptr,
+			(void *)incoming->data,
+			reg_str->dl_buff_address.reg_val + client_rd_ptr,
+			client_wr_ptr - client_rd_ptr,
+			reg_str->dl_buff_size.reg_val);
+
+		if (status) {
+			pr_err(MODULE_NAME ": %s - Failure in Function "
+			       "sdio_memcpy_fromio_wrapper(). "
+			       "SINGLE CHUNK READ. status=%d\n",
+			       __func__, status);
+			return status;
+		}
+
+		incoming->num_of_bytes_in_use += client_wr_ptr - client_rd_ptr;
+		*bytes_read = client_wr_ptr - client_rd_ptr;
+
+#ifdef CONFIG_DEBUG_FS
+			debugfs_glob.global_to_read =
+				client_wr_ptr - client_rd_ptr;
+			update_gd(SDIO_DLD_DEBUGFS_CASE_11_CODE);
+#endif
+	}
+
+	/* there is data to read in TWO chunks */
+	else {
+		int dl_buf_size = reg_str->dl_buff_size.reg_val;
+		int tail_size = dl_buf_size - client_rd_ptr;
+
+		/* reading chunk#1: from rd_ptr to the end of the buffer */
+		status = sdio_memcpy_fromio_wrapper(
+			str_func,
+			client_rd_ptr,
+			dl_buf_size,
+			(void *)incoming->data,
+			reg_str->dl_buff_address.reg_val + client_rd_ptr,
+			tail_size,
+			dl_buf_size);
+
+		if (status) {
+			pr_err(MODULE_NAME ": %s - Failure in Function "
+			       "sdio_memcpy_fromio_wrapper(). "
+			       "1 of 2 CHUNKS READ. status=%d\n",
+			       __func__, status);
+			return status;
+		}
+
+		incoming->num_of_bytes_in_use += tail_size;
+		*bytes_read = tail_size;
+
+#ifdef CONFIG_DEBUG_FS
+			debugfs_glob.global_to_read = tail_size;
+			update_gd(SDIO_DLD_DEBUGFS_CASE_11_CODE);
+#endif
+
+		/* reading chunk#2: reading from beginning buffer */
+		status = sdio_memcpy_fromio_wrapper(
+			str_func,
+			client_rd_ptr,
+			client_wr_ptr,
+			(void *)(incoming->data + tail_size),
+			reg_str->dl_buff_address.reg_val,
+			client_wr_ptr,
+			reg_str->dl_buff_size.reg_val);
+
+		if (status) {
+			pr_err(MODULE_NAME ": %s - Failure in Function "
+			       "sdio_memcpy_fromio_wrapper(). "
+			       "2 of 2 CHUNKS READ. status=%d\n",
+			       __func__, status);
+			return status;
+		}
+
+		incoming->num_of_bytes_in_use += client_wr_ptr;
+		*bytes_read += client_wr_ptr;
+
+#ifdef CONFIG_DEBUG_FS
+			debugfs_glob.global_to_read = client_wr_ptr;
+			update_gd(SDIO_DLD_DEBUGFS_CASE_11_CODE);
+#endif
+	}
+	return 0;
+}
+
+/**
+  * sdio_dld_main_task
+  * sdio downloader main task. reads mailboxf checks if there is
+  * anything to read, checks if host has anything to
+  * write.
+  *
+  * @card: a pointer to mmc_card.
+  * @return 0 on success or negative value on error.
+  */
+static int sdio_dld_main_task(void *card)
+{
+	int status = 0;
+	struct tty_struct *tty = sdio_dld->tty_str;
+	struct sdioc_reg_chunk *reg_str =
+		&sdio_dld->sdio_dloader_data.sdioc_reg;
+	int func = sdio_dld->sdioc_boot_func;
+	struct sdio_func *str_func = NULL;
+	struct sdio_data *outgoing = &sdio_dld->sdio_dloader_data.outgoing_data;
+	struct sdio_data *incoming = &sdio_dld->sdio_dloader_data.incoming_data;
+	struct sdio_dld_task *task = &sdio_dld->dld_main_thread;
+	int retries = 0;
+#ifdef PUSH_STRING
+	int bytes_pushed = 0;
+#endif
+
+	msleep(SLEEP_MS);
+
+	if (!card) {
+		pr_err(MODULE_NAME ": %s - param ""card"" is NULL.\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	if (!tty) {
+		pr_err(MODULE_NAME ": %s - param ""tty"" is NULL.\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	str_func = ((struct mmc_card *)card)->
+		sdio_func[REAL_FUNC_TO_FUNC_IN_ARRAY(func)];
+
+	if (!str_func) {
+		pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	while (true) {
+		/* client pointers for both buffers */
+		int client_ul_wr_ptr = 0;
+		int client_ul_rd_ptr = 0;
+		int client_dl_wr_ptr = 0;
+		int client_dl_rd_ptr = 0;
+
+		/* host pointer for outgoing buffer */
+		int h_out_wr_ptr = 0;
+		int h_out_rd_ptr = 0;
+
+		int h_bytes_rdy_wr = 0;
+		int c_bytes_rdy_rcve = 0;
+
+		int need_to_write = 0;
+		int need_to_read = 0;
+
+		/*
+		 * forever, checking for signal to die, then read MailBox.
+		 * if nothing to read or nothing to write to client, sleep,
+		 * and again read MailBox
+		 */
+		do {
+			int dummy = 0;
+
+			/*  checking if a signal to die was sent */
+			if (atomic_read(&task->please_close) == 1) {
+
+				pr_debug(MODULE_NAME ": %s - 0x%x was written "
+					 "to 9K\n", __func__, SDIOC_EXIT_CODE);
+
+				sdio_claim_host(str_func);
+
+				/* returned value is not checked on purpose */
+				sdio_memcpy_toio(
+					str_func,
+					reg_str->good_to_exit_ptr.reg_offset,
+					(void *)&reg_str->good_to_exit_ptr.
+					reg_val,
+					sizeof(reg_str->good_to_exit_ptr.
+					       reg_val));
+
+				sdio_release_host(str_func);
+
+				task->exit_wait.wake_up_signal = 1;
+				wake_up(&task->exit_wait.wait_event);
+				return 0;
+			}
+
+			status = mailbox_to_seq_chunk_read_ptrs(str_func);
+			if (status) {
+				pr_err(MODULE_NAME ": %s - Failure in Function "
+				       "mailbox_to_seq_chunk_read_ptrs(). "
+				       "status=%d\n", __func__, status);
+				return status;
+			}
+
+			/* calculate how many bytes the host has send */
+			h_out_wr_ptr = outgoing->offset_write_p;
+			h_out_rd_ptr = outgoing->offset_read_p;
+
+			status = sdioc_bytes_till_end_of_buffer(
+				h_out_wr_ptr,
+				h_out_rd_ptr,
+				outgoing->buffer_size,
+				&dummy,
+				&h_bytes_rdy_wr);
+
+			if (status) {
+				pr_err(MODULE_NAME ": %s - Failure in Function "
+				       "sdioc_bytes_till_end_of_buffer(). "
+				       "status=%d\n", __func__, status);
+				return status;
+			}
+
+			/* is there something to read from client */
+			client_dl_wr_ptr = reg_str->dl_wr_ptr.reg_val;
+			client_dl_rd_ptr = reg_str->dl_rd_ptr.reg_val;
+
+			if (client_dl_rd_ptr != client_dl_wr_ptr)
+				need_to_read = 1;
+
+			/*
+			 *  calculate how many bytes the client can receive
+			 *  from host
+			 */
+			client_ul_wr_ptr = reg_str->up_wr_ptr.reg_val;
+			client_ul_rd_ptr = reg_str->up_rd_ptr.reg_val;
+
+			status = sdioc_bytes_till_end_of_buffer(
+				client_ul_wr_ptr,
+				client_ul_rd_ptr,
+				reg_str->ul_buff_size.reg_val,
+				&c_bytes_rdy_rcve,
+				&dummy);
+
+			if (status) {
+				pr_err(MODULE_NAME ": %s - Failure in Function "
+				       "sdioc_bytes_till_end_of_buffer(). "
+				       "status=%d\n", __func__, status);
+				return status;
+			}
+
+			/* if host has anything to write */
+			if (h_bytes_rdy_wr > 0)
+				need_to_write = 1;
+
+			if (need_to_write || need_to_read)
+				break;
+
+			spin_lock_irqsave(&lock2, lock_flags2);
+			sdio_dld->main_loop_event.wake_up_signal = 0;
+			spin_unlock_irqrestore(&lock2, lock_flags2);
+
+			pr_debug(MODULE_NAME ": %s - MAIN LOOP - WAITING...\n",
+				 __func__);
+#ifdef CONFIG_DEBUG_FS
+			update_gd(SDIO_DLD_DEBUGFS_CASE_6_CODE);
+#endif
+			wait_event(sdio_dld->main_loop_event.wait_event,
+				   sdio_dld->main_loop_event.wake_up_signal);
+#ifdef CONFIG_DEBUG_FS
+			update_gd(SDIO_DLD_DEBUGFS_CASE_7_CODE);
+#endif
+
+			pr_debug(MODULE_NAME ": %s - MAIN LOOP - WOKE UP...\n",
+				 __func__);
+
+		} while (1);
+
+		/* CHECK IF THERE IS ANYTHING TO READ IN CLIENT */
+		if (need_to_read) {
+#ifdef PUSH_STRING
+			int num_push = 0;
+			int left = 0;
+			int bytes_read;
+#else
+			int i;
+#endif
+			need_to_read = 0;
+
+			status = sdio_dld_read(client_dl_rd_ptr,
+					       client_dl_wr_ptr,
+					       reg_str,
+					       str_func,
+					       &bytes_read);
+
+			if (status) {
+				pr_err(MODULE_NAME ": %s - Failure in Function "
+				       "sdio_dld_read(). status=%d\n",
+				       __func__, status);
+				return status;
+			}
+
+			sdio_dld_info.global_bytes_read_fromio +=
+				bytes_read;
+
+			bytes_pushed = 0;
+#ifdef PUSH_STRING
+			left = incoming->num_of_bytes_in_use;
+			start_timer(&sdio_dld->push_timer,
+				    sdio_dld->push_timer_ms);
+			do {
+				num_push = tty_insert_flip_string(
+					tty,
+					incoming->data+bytes_pushed,
+					left);
+
+				bytes_pushed += num_push;
+				left -= num_push;
+				tty_flip_buffer_push(tty);
+			} while (left != 0);
+
+			del_timer(&sdio_dld->push_timer);
+
+			if (bytes_pushed != incoming->num_of_bytes_in_use) {
+				pr_err(MODULE_NAME ": %s - failed\n",
+				       __func__);
+			}
+#else
+			pr_debug(MODULE_NAME ": %s - NEED TO READ %d\n",
+			       __func__, incoming->num_of_bytes_in_use);
+
+			for (i = 0 ; i < incoming->num_of_bytes_in_use ; ++i) {
+				int err = 0;
+				err = tty_insert_flip_char(tty,
+							   incoming->data[i],
+							   TTY_NORMAL);
+				tty_flip_buffer_push(tty);
+			}
+
+			pr_debug(MODULE_NAME ": %s - JUST READ\n", __func__);
+#endif /*PUSH_STRING*/
+			sdio_dld_info.global_bytes_push_tty +=
+				incoming->num_of_bytes_in_use;
+#ifdef CONFIG_DEBUG_FS
+			debugfs_glob.global_push_to_tty = bytes_read;
+			update_gd(SDIO_DLD_DEBUGFS_CASE_12_CODE);
+#endif
+			incoming->num_of_bytes_in_use = 0;
+			tty_flip_buffer_push(tty);
+		}
+
+		/* CHECK IF THERE IS ANYTHING TO WRITE IN HOST AND HOW MUCH */
+		if (need_to_write) {
+			int dummy = 0;
+
+			do {
+				int bytes_to_write = min(c_bytes_rdy_rcve,
+							 h_bytes_rdy_wr);
+
+				/*
+				 * in case nothing to send or no room to
+				 * receive
+				 */
+				if (bytes_to_write == 0)
+					break;
+
+				if (client_ul_rd_ptr == 0 &&
+				    (client_ul_rd_ptr != client_ul_wr_ptr))
+					break;
+
+				/*
+				 * if client_rd_ptr points to start, but there
+				 * is data to read wait until WRITE_TILL_END
+				 * before writing a chunk of data, to avoid
+				 * writing until (BUF_SIZE - 1), because it will
+				 * yield an extra write of "1" bytes
+				 */
+				if (client_ul_rd_ptr == 0 &&
+				    (client_ul_rd_ptr != client_ul_wr_ptr) &&
+				    retries < WRITE_TILL_END_RETRIES) {
+					retries++;
+					break;
+				}
+				retries = 0;
+
+#ifdef CONFIG_DEBUG_FS
+				debugfs_glob.global_8k_has = h_bytes_rdy_wr;
+				debugfs_glob.global_9k_has = c_bytes_rdy_rcve;
+				debugfs_glob.global_min = bytes_to_write;
+				update_gd(SDIO_DLD_DEBUGFS_CASE_2_CODE);
+#endif
+				need_to_write = 0;
+
+				pr_debug(MODULE_NAME ": %s - NEED TO WRITE "
+					 "TOIO %d\n",
+					 __func__, bytes_to_write);
+
+				status = sdio_memcpy_toio_wrapper(
+					str_func,
+					reg_str->up_wr_ptr.reg_val,
+					outgoing->offset_read_p,
+					(void *)((char *)outgoing->data +
+						 outgoing->offset_read_p),
+					bytes_to_write);
+
+				if (status) {
+					pr_err(MODULE_NAME ": %s - Failure in "
+					       "Function "
+					       "sdio_memcpy_toio_wrapper(). "
+					       "SINGLE CHUNK WRITE. "
+					       "status=%d\n",
+					       __func__, status);
+					return status;
+				}
+
+				sdio_claim_host(str_func);
+
+				status = sdio_memcpy_fromio(
+					str_func,
+					(void *)&reg_str->up_rd_ptr.reg_val,
+					SDIOC_UL_RD_PTR,
+					sizeof(reg_str->up_rd_ptr.reg_val));
+
+				if (status) {
+					pr_err(MODULE_NAME ": %s - "
+					       "sdio_memcpy_fromio() "
+					       "failed. status=%d\n",
+					       __func__, status);
+					sdio_release_host(str_func);
+
+					return status;
+				}
+
+				sdio_release_host(str_func);
+
+				spin_lock_irqsave(&lock1, lock_flags1);
+				if (sdio_dld->write_callback_event.
+				    wake_up_signal == 0) {
+					sdio_dld->write_callback_event.
+						wake_up_signal = 1;
+					wake_up(&sdio_dld->
+						write_callback_event.
+						wait_event);
+				}
+
+				spin_unlock_irqrestore(&lock1, lock_flags1);
+				client_ul_wr_ptr = reg_str->up_wr_ptr.reg_val;
+				client_ul_rd_ptr = reg_str->up_rd_ptr.reg_val;
+
+				status = sdioc_bytes_till_end_of_buffer(
+					client_ul_wr_ptr,
+					client_ul_rd_ptr,
+					reg_str->ul_buff_size.reg_val,
+					&c_bytes_rdy_rcve,
+					&dummy);
+
+				/* calculate how many bytes host has to send */
+				h_out_wr_ptr = outgoing->offset_write_p;
+				h_out_rd_ptr = outgoing->offset_read_p;
+
+				status = sdioc_bytes_till_end_of_buffer(
+					h_out_wr_ptr,
+					h_out_rd_ptr,
+					outgoing->buffer_size,
+					&dummy,
+					&h_bytes_rdy_wr);
+
+			} while (h_out_wr_ptr != h_out_rd_ptr);
+		}
+	}
+	return 0;
+}
+
+/**
+  * sdio_dld_init_global
+  * initialization of sdio_dld global struct
+  *
+  * @card: a pointer to mmc_card.
+  * @return 0 on success or negative value on error.
+  */
+static int sdio_dld_init_global(struct mmc_card *card,
+				int(*done)(void))
+{
+	if (!card) {
+		pr_err(MODULE_NAME ": %s - param ""card"" is NULL.\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	if (!done) {
+		pr_err(MODULE_NAME ": %s - param ""done"" is NULL.\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	sdio_dld->done_callback = done;
+	sdio_dld->card = card;
+	init_waitqueue_head(&sdio_dld->dld_main_thread.exit_wait.wait_event);
+	sdio_dld->write_callback_event.wake_up_signal = 1;
+	sdio_dld->main_loop_event.wake_up_signal = 1;
+
+	sdio_dld->sdio_dloader_data.sdioc_reg.dl_buff_size.reg_offset =
+		SDIOC_DL_BUFF_SIZE_OFFSET;
+
+	sdio_dld->sdio_dloader_data.sdioc_reg.dl_rd_ptr.reg_offset =
+		SDIOC_DL_RD_PTR;
+
+	sdio_dld->sdio_dloader_data.sdioc_reg.dl_wr_ptr.reg_offset =
+		SDIOC_DL_WR_PTR;
+
+	sdio_dld->sdio_dloader_data.sdioc_reg.ul_buff_size.reg_offset =
+		SDIOC_UP_BUFF_SIZE_OFFSET;
+
+	sdio_dld->sdio_dloader_data.sdioc_reg.up_rd_ptr.reg_offset =
+		SDIOC_UL_RD_PTR;
+
+	sdio_dld->sdio_dloader_data.sdioc_reg.up_wr_ptr.reg_offset =
+		SDIOC_UL_WR_PTR;
+
+	sdio_dld->sdio_dloader_data.sdioc_reg.good_to_exit_ptr.reg_offset =
+		SDIOC_EXIT_PTR;
+
+	sdio_dld->sdio_dloader_data.sdioc_reg.dl_buff_address.reg_offset =
+		SDIOC_DL_BUFF_ADDRESS;
+
+	sdio_dld->sdio_dloader_data.sdioc_reg.up_buff_address.reg_offset =
+		SDIOC_UP_BUFF_ADDRESS;
+
+	sdio_dld_set_op_mode(SDIO_DLD_NORMAL_MODE);
+
+	return 0;
+}
+
+/**
+ * sdio_downloader_setup
+ * initializes the TTY driver
+ *
+ * @card: a pointer to mmc_card.
+ * @num_of_devices: number of devices.
+ * @channel_number: channel number.
+ * @return 0 on success or negative value on error.
+ *
+ * The TTY stack needs to know in advance how many devices it should
+ * plan to manage. Use this call to set up the ports that will
+ * be exported through SDIO.
+ */
+int sdio_downloader_setup(struct mmc_card *card,
+			  unsigned int num_of_devices,
+			  int channel_number,
+			  int(*done)(void))
+{
+	int status = 0;
+	int result = 0;
+	int func_in_array = 0;
+	struct sdio_func *str_func = NULL;
+	struct device *tty_dev;
+
+	if (num_of_devices == 0 || num_of_devices > MAX_NUM_DEVICES) {
+		pr_err(MODULE_NAME ": %s - invalid number of devices\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	if (!card) {
+		pr_err(MODULE_NAME ": %s - param ""card"" is NULL.\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	if (!done) {
+		pr_err(MODULE_NAME ": %s - param ""done"" is NULL.\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	sdio_dld = kzalloc(sizeof(struct sdio_downloader), GFP_KERNEL);
+	if (!sdio_dld) {
+		pr_err(MODULE_NAME ": %s - couldn't allocate sdio_dld data "
+		       "structure.", __func__);
+		return -ENOMEM;
+	}
+
+#ifdef CONFIG_DEBUG_FS
+	bootloader_debugfs_init();
+#endif /* CONFIG_DEBUG_FS */
+
+	status = sdio_dld_init_global(card, done);
+
+	if (status) {
+		pr_err(MODULE_NAME ": %s - Failure in Function "
+		       "sdio_dld_init_global(). status=%d\n",
+		       __func__, status);
+		kfree(sdio_dld);
+		return status;
+	}
+
+	sdio_dld->tty_drv = alloc_tty_driver(num_of_devices);
+
+	if (!sdio_dld->tty_drv) {
+		pr_err(MODULE_NAME ": %s - param ""sdio_dld->tty_drv"" is "
+				   "NULL.\n", __func__);
+		kfree(sdio_dld);
+		return -EINVAL;
+	}
+
+	sdio_dld_set_op_mode((enum sdio_dld_op_mode)sdio_op_mode);
+
+	/* according to op_mode, a different tty device is created */
+	if (sdio_dld->op_mode == SDIO_DLD_BOOT_TEST_MODE)
+		sdio_dld->tty_drv->name = TTY_SDIO_DEV_TEST;
+	else
+	    sdio_dld->tty_drv->name = TTY_SDIO_DEV;
+
+	sdio_dld->tty_drv->owner = THIS_MODULE;
+	sdio_dld->tty_drv->driver_name = "SDIO_Dloader";
+
+	/* uses dynamically assigned dev_t values */
+	sdio_dld->tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
+	sdio_dld->tty_drv->subtype = SERIAL_TYPE_NORMAL;
+	sdio_dld->tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV
+				| TTY_DRIVER_RESET_TERMIOS;
+
+	/* initializing the tty driver */
+	sdio_dld->tty_drv->init_termios = tty_std_termios;
+	sdio_dld->tty_drv->init_termios.c_cflag =
+		B4800 | CS8 | CREAD | HUPCL | CLOCAL;
+	sdio_dld->tty_drv->init_termios.c_ispeed = INPUT_SPEED;
+	sdio_dld->tty_drv->init_termios.c_ospeed = OUTPUT_SPEED;
+
+	tty_set_operations(sdio_dld->tty_drv, &sdio_dloader_tty_ops);
+
+	status = tty_register_driver(sdio_dld->tty_drv);
+	if (status) {
+		put_tty_driver(sdio_dld->tty_drv);
+		pr_err(MODULE_NAME ": %s - tty_register_driver() failed\n",
+			__func__);
+
+		sdio_dld->tty_drv = NULL;
+		kfree(sdio_dld);
+		return status;
+	}
+
+	tty_dev = tty_register_device(sdio_dld->tty_drv, 0, NULL);
+	if (IS_ERR(tty_dev)) {
+		pr_err(MODULE_NAME ": %s - tty_register_device() "
+			"failed\n", __func__);
+		tty_unregister_driver(sdio_dld->tty_drv);
+		kfree(sdio_dld);
+		return PTR_ERR(tty_dev);
+	}
+
+	sdio_dld->sdioc_boot_func = SDIOC_CHAN_TO_FUNC_NUM(channel_number);
+	func_in_array = REAL_FUNC_TO_FUNC_IN_ARRAY(sdio_dld->sdioc_boot_func);
+	str_func = sdio_dld->card->sdio_func[func_in_array];
+	status = sdio_dld_init_func(str_func);
+	if (status) {
+		pr_err(MODULE_NAME ": %s - Failure in Function "
+		       "sdio_dld_init_func(). status=%d\n",
+		       __func__, status);
+		goto exit_err;
+	}
+
+#ifdef CONFIG_DEBUG_FS
+	sdio_dld_debug_init();
+#endif
+
+	sdio_claim_host(str_func);
+
+	/*
+	 * notifing the client by writing what mode we are by writing
+	 * to a special register
+	 */
+	status = sdio_memcpy_toio(str_func,
+				  SDIOC_OP_MODE_PTR,
+				  (void *)&sdio_dld->op_mode,
+				  sizeof(sdio_dld->op_mode));
+
+	sdio_release_host(str_func);
+
+	if (status) {
+		pr_err(MODULE_NAME ": %s - sdio_memcpy_toio() "
+		       "writing to OP_MODE_REGISTER failed. "
+		       "status=%d.\n",
+		       __func__, status);
+		goto exit_err;
+	}
+
+	return 0;
+
+exit_err:
+	tty_unregister_device(sdio_dld->tty_drv, 0);
+	result = tty_unregister_driver(sdio_dld->tty_drv);
+	if (result)
+		pr_err(MODULE_NAME ": %s - tty_unregister_driver() "
+		       "failed. result=%d\n", __func__, -result);
+	kfree(sdio_dld);
+	return status;
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("SDIO Downloader");
+MODULE_AUTHOR("Yaniv Gardi <ygardi@codeaurora.org>");
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/arch/arm/mach-msm/sdio_al_private.h b/arch/arm/mach-msm/sdio_al_private.h
new file mode 100644
index 0000000..36d9ec1
--- /dev/null
+++ b/arch/arm/mach-msm/sdio_al_private.h
@@ -0,0 +1,267 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * SDIO-Abstraction-Layer internal interface.
+ */
+
+#ifndef __SDIO_AL_PRIVATE__
+#define __SDIO_AL_PRIVATE__
+
+#include <linux/mmc/card.h>
+#include <linux/platform_device.h>
+#include <mach/sdio_al.h>
+
+#define DRV_VERSION "1.30"
+#define MODULE_NAME "sdio_al"
+#define SDIOC_CHAN_TO_FUNC_NUM(x)	((x)+2)
+#define REAL_FUNC_TO_FUNC_IN_ARRAY(x)	((x)-1)
+#define SDIO_PREFIX "SDIO_"
+#define PEER_CHANNEL_NAME_SIZE		4
+#define CHANNEL_NAME_SIZE (sizeof(SDIO_PREFIX) + PEER_CHANNEL_NAME_SIZE)
+#define SDIO_TEST_POSTFIX_SIZE 5
+#define MAX_NUM_OF_SDIO_DEVICES	2
+#define TEST_CH_NAME_SIZE (CHANNEL_NAME_SIZE + SDIO_TEST_POSTFIX_SIZE)
+
+struct sdio_al_device; /* Forward Declaration */
+
+enum sdio_channel_state {
+	SDIO_CHANNEL_STATE_INVALID,	 /* before reading software header */
+	SDIO_CHANNEL_STATE_IDLE,         /* channel valid, not opened    */
+	SDIO_CHANNEL_STATE_CLOSED,       /* was closed */
+	SDIO_CHANNEL_STATE_OPEN,	 /* opened */
+	SDIO_CHANNEL_STATE_CLOSING,      /* during flush, when closing */
+};
+/**
+ * Peer SDIO-Client channel configuration.
+ *
+ *  @is_ready - channel is ready and the data is valid.
+ *
+ *  @max_rx_threshold - maximum rx threshold, according to the
+ *		total buffers size on the peer pipe.
+ *  @max_tx_threshold - maximum tx threshold, according to the
+ *		total buffers size on the peer pipe.
+ *  @tx_buf_size - size of a single buffer on the peer pipe; a
+ *		transfer smaller than the buffer size still
+ *		make the buffer unusable for the next transfer.
+ * @max_packet_size
+ * @is_host_ok_to_sleep - Host marks this bit when it's okay to
+ *		sleep (no pending transactions)
+ */
+struct peer_sdioc_channel_config {
+	u32 is_ready;
+	u32 max_rx_threshold; /* Downlink */
+	u32 max_tx_threshold; /* Uplink */
+	u32 tx_buf_size;
+	u32 max_packet_size;
+	u32 is_host_ok_to_sleep;
+	u32 is_packet_mode;
+	u32 peer_operation;
+	u32 is_low_latency_ch;
+	u32 reserved[23];
+};
+
+
+/**
+ * Peer SDIO-Client channel statsitics.
+ *
+ * @last_any_read_avail - the last read avail in all the
+ *		 channels including this channel.
+ * @last_read_avail - the last read_avail that was read from HW
+ *	    mailbox.
+ * @last_old_read_avail - the last read_avail channel shadow.
+ * @total_notifs - the total number of read notifications sent
+ *	 to this channel client
+ * @total_read_times - the total number of successful sdio_read
+ *	     calls for this channel
+ */
+struct sdio_channel_statistics {
+	int last_any_read_avail;
+	int last_read_avail;
+	int last_old_read_avail;
+	int total_notifs;
+	int total_read_times;
+};
+
+/**
+ *  SDIO Channel context.
+ *
+ *  @name - channel name. Used by the caller to open the
+ *	  channel.
+ *
+ *  @read_threshold - Threshold on SDIO-Client mailbox for Rx
+ *				Data available bytes. When the limit exceed
+ *				the SDIO-Client generates an interrupt to the
+ *				host.
+ *
+ *  @write_threshold - Threshold on SDIO-Client mailbox for Tx
+ *				Data available bytes. When the limit exceed
+ *				the SDIO-Client generates an interrupt to the
+ *				host.
+ *
+ *  @def_read_threshold - Default theshold on SDIO-Client for Rx
+ *
+ *  @min_write_avail - Threshold of minimal available bytes
+ *					 to write. Below that threshold the host
+ *					 will initiate reading the mailbox.
+ *
+ *  @poll_delay_msec - Delay between polling the mailbox. When
+ *				 the SDIO-Client doesn't generates EOT
+ *				 interrupt for Rx Available bytes, the host
+ *				 should poll the SDIO-Client mailbox.
+ *
+ *  @is_packet_mode - The host get interrupt when a packet is
+ *				available at the SDIO-client (pipe EOT
+ *				indication).
+ *
+ *  @num - channel number.
+ *
+ *  @notify - Client's callback. Should not call sdio read/write.
+ *
+ *  @priv - Client's private context, provided to callback.
+ *
+ *  @is_valid - Channel is used (we have a list of
+ *		SDIO_AL_MAX_CHANNELS and not all of them are in
+ *		use).
+ *
+ *  @is_open - Channel is open.
+ *
+ *  @func - SDIO Function handle.
+ *
+ *  @rx_pipe_index - SDIO-Client Pipe Index for Rx Data.
+ *
+ *  @tx_pipe_index - SDIO-Client Pipe Index for Tx Data.
+ *
+ *  @ch_lock - Channel lock to protect channel specific Data
+ *
+ *  @rx_pending_bytes - Total number of Rx pending bytes, at Rx
+ *				  packet list. Maximum of 16KB-1 limited by
+ *				  SDIO-Client specification.
+ *
+ *  @read_avail - Available bytes to read.
+ *
+ *  @write_avail - Available bytes to write.
+ *
+ *  @rx_size_list_head - The head of Rx Pending Packets List.
+ *
+ *  @pdev - platform device - clients to probe for the sdio-al.
+ *
+ *  @signature - Context Validity check.
+ *
+ *  @sdio_al_dev - a pointer to the sdio_al_device instance of
+ *   this channel
+ *
+ *   @statistics - channel statistics
+ *
+ */
+struct sdio_channel {
+	/* Channel Configuration Parameters*/
+	char name[CHANNEL_NAME_SIZE];
+	char ch_test_name[TEST_CH_NAME_SIZE];
+	int read_threshold;
+	int write_threshold;
+	int def_read_threshold;
+	int threshold_change_cnt;
+	int min_write_avail;
+	int poll_delay_msec;
+	int is_packet_mode;
+	int is_low_latency_ch;
+
+	struct peer_sdioc_channel_config ch_config;
+
+	/* Channel Info */
+	int num;
+
+	void (*notify)(void *priv, unsigned channel_event);
+	void *priv;
+
+	int state;
+
+	struct sdio_func *func;
+
+	int rx_pipe_index;
+	int tx_pipe_index;
+
+	struct mutex ch_lock;
+
+	u32 read_avail;
+	u32 write_avail;
+
+	u32 peer_tx_buf_size;
+
+	u16 rx_pending_bytes;
+
+	struct list_head rx_size_list_head;
+
+	struct platform_device *pdev;
+
+	u32 total_rx_bytes;
+	u32 total_tx_bytes;
+
+	u32 signature;
+
+	struct sdio_al_device *sdio_al_dev;
+
+	struct sdio_channel_statistics statistics;
+};
+
+/**
+ * sdio_downloader_setup
+ * initializes the TTY driver
+ *
+ * @card: a pointer to mmc_card.
+ * @num_of_devices: number of devices.
+ * @channel_number: channel number.
+ * @return 0 on success or negative value on error.
+ *
+ * The TTY stack needs to know in advance how many devices it should
+ * plan to manage. Use this call to set up the ports that will
+ * be exported through SDIO.
+ */
+int sdio_downloader_setup(struct mmc_card *card,
+			  unsigned int num_of_devices,
+			  int func_number,
+			  int(*func)(void));
+
+/**
+ * test_channel_init
+ * initializes a test channel
+ *
+ * @name: the channel name.
+ * @return 0 on success or negative value on error.
+ *
+ */
+int test_channel_init(char *name);
+
+/**
+ * sdio_al_register_lpm_cb
+ * Allow the sdio_al test to register for lpm voting
+ * notifications
+ *
+ * @device_handle: the device handle.
+ * @wakeup_callback: callback function to be called when voting.
+ *
+ */
+void sdio_al_register_lpm_cb(void *device_handle,
+				       int(*lpm_callback)(void *, int));
+
+/**
+ * sdio_al_unregister_lpm_cb
+ * Allow the sdio_al test to unregister for lpm voting
+ * notifications
+ *
+ * @device_handle: the device handle.
+ *
+ */
+void sdio_al_unregister_lpm_cb(void *device_handle);
+
+#endif /* __SDIO_AL_PRIVATE__ */
diff --git a/arch/arm/mach-msm/sdio_al_test.c b/arch/arm/mach-msm/sdio_al_test.c
new file mode 100644
index 0000000..c97588f
--- /dev/null
+++ b/arch/arm/mach-msm/sdio_al_test.c
@@ -0,0 +1,6500 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * SDIO-Abstraction-Layer Test Module.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/workqueue.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/platform_device.h>
+#include <mach/sdio_smem.h>
+#include <linux/wakelock.h>
+#include <linux/uaccess.h>
+
+#include "sdio_al_private.h"
+#include <linux/debugfs.h>
+
+#include <linux/kthread.h>
+enum lpm_test_msg_type {
+	LPM_NO_MSG,	/* 0 */
+	LPM_MSG_SEND,	/* 1 */
+	LPM_MSG_REC,	/* 2 */
+	LPM_SLEEP,	/* 3 */
+	LPM_WAKEUP,	/* 4 */
+	LPM_NOTIFY	/* 5 */
+};
+
+#define LPM_NO_MSG_NAME "LPM No Event"
+#define LPM_MSG_SEND_NAME "LPM Send Msg Event"
+#define LPM_MSG_REC_NAME "LPM Receive Msg Event"
+#define LPM_SLEEP_NAME "LPM Sleep Event"
+#define LPM_WAKEUP_NAME "LPM Wakeup Event"
+
+/** Module name string */
+#define TEST_MODULE_NAME "sdio_al_test"
+
+#define TEST_SIGNATURE 0x12345678
+#define TEST_CONFIG_SIGNATURE 0xBEEFCAFE
+
+#define MAX_XFER_SIZE (16*1024)
+#define SMEM_MAX_XFER_SIZE 0xBC000
+#define A2_MIN_PACKET_SIZE 5
+#define RMNT_PACKET_SIZE (4*1024)
+#define DUN_PACKET_SIZE (2*1024)
+#define CSVT_PACKET_SIZE 1700
+
+#define TEST_DBG(x...) if (test_ctx->runtime_debug) pr_info(x)
+
+#define LPM_TEST_NUM_OF_PACKETS 100
+#define LPM_MAX_OPEN_CHAN_PER_DEV 4
+#define LPM_ARRAY_SIZE	(7*LPM_TEST_NUM_OF_PACKETS*LPM_MAX_OPEN_CHAN_PER_DEV)
+#define SDIO_LPM_TEST "sdio_lpm_test_reading_task"
+#define LPM_TEST_CONFIG_SIGNATURE 0xDEADBABE
+#define LPM_MSG_NAME_SIZE 20
+#define MAX_STR_SIZE	10
+#define MAX_AVG_RTT_TIME_USEC	2500
+#define SDIO_RMNT_RTT_PACKET_SIZE	32
+#define SDIO_CSVT_RTT_PACKET_SIZE	1900
+
+#define A2_HEADER_OVERHEAD 8
+
+enum rx_process_state {
+	RX_PROCESS_PACKET_INIT,
+	RX_PROCESS_A2_HEADER,
+	RX_PROCESS_PACKET_DATA,
+};
+
+enum sdio_test_case_type {
+	SDIO_TEST_LOOPBACK_HOST,
+	SDIO_TEST_LOOPBACK_CLIENT,
+	SDIO_TEST_LPM_HOST_WAKER,
+	SDIO_TEST_LPM_CLIENT_WAKER,
+	SDIO_TEST_LPM_RANDOM,
+	SDIO_TEST_HOST_SENDER_NO_LP,
+	SDIO_TEST_CLOSE_CHANNEL,
+	SDIO_TEST_A2_VALIDATION,
+	/* The following tests are not part of the 9k tests and should be
+	 * kept last in case new tests are added
+	 */
+	SDIO_TEST_PERF,
+	SDIO_TEST_RTT,
+	SDIO_TEST_MODEM_RESET,
+};
+
+struct lpm_task {
+	struct task_struct *lpm_task;
+	const char *task_name;
+};
+
+struct lpm_entry_type {
+	enum lpm_test_msg_type msg_type;
+	char msg_name[LPM_MSG_NAME_SIZE];
+	u32 counter;
+	u32 current_ms;
+	u32 read_avail_mask;
+	char chan_name[CHANNEL_NAME_SIZE];
+};
+
+struct lpm_msg {
+	u32 signature;
+	u32 counter;
+	u32 reserve1;
+	u32 reserve2;
+};
+
+struct test_config_msg {
+	u32 signature;
+	u32 test_case;
+	u32 test_param;
+	u32 num_packets;
+	u32 num_iterations;
+};
+
+struct test_result_msg {
+	u32 signature;
+	u32 is_successful;
+};
+
+struct test_work {
+	struct work_struct work;
+	struct test_channel *test_ch;
+};
+
+enum sdio_channels_ids {
+	SDIO_RPC,
+	SDIO_QMI,
+	SDIO_RMNT,
+	SDIO_DIAG,
+	SDIO_DUN,
+	SDIO_SMEM,
+	SDIO_CSVT,
+	SDIO_MAX_CHANNELS
+};
+
+enum sdio_test_results {
+	TEST_NO_RESULT,
+	TEST_FAILED,
+	TEST_PASSED
+};
+
+enum sdio_lpm_vote_state {
+	SDIO_NO_VOTE,
+	SDIO_VOTE_FOR_SLEEP,
+	SDIO_VOTE_AGAINST_SLEEP
+};
+
+struct sdio_test_device {
+	int open_channels_counter_to_recv;
+	int open_channels_counter_to_send;
+	struct lpm_entry_type *lpm_arr;
+	int array_size;
+	void *sdio_al_device;
+	spinlock_t lpm_array_lock;
+	unsigned long lpm_array_lock_flags;
+	u32 next_avail_entry_in_array;
+	struct lpm_task lpm_test_task;
+	u32 next_mask_id;
+	u32 read_avail_mask;
+	int modem_result_per_dev;
+	int final_result_per_dev;
+};
+
+struct test_channel {
+	struct sdio_channel *ch;
+
+	char name[CHANNEL_NAME_SIZE];
+	int ch_id;
+
+	struct sdio_test_device *test_device;
+
+	u32 *buf;
+	u32 buf_size;
+
+	struct workqueue_struct *workqueue;
+	struct test_work test_work;
+
+	u32 rx_bytes;
+	u32 tx_bytes;
+
+	wait_queue_head_t   wait_q;
+	atomic_t rx_notify_count;
+	atomic_t tx_notify_count;
+	atomic_t any_notify_count;
+	atomic_t wakeup_client;
+	atomic_t card_detected_event;
+
+	int wait_counter;
+
+	int is_used;
+	int test_type;
+	int ch_ready;
+
+	struct test_config_msg config_msg;
+
+	int test_completed;
+	int test_result;
+	struct timer_list timer;
+	int timer_interval_ms;
+
+	struct timer_list timeout_timer;
+	int timeout_ms;
+	void *sdio_al_device;
+	int is_ok_to_sleep;
+	unsigned int packet_length;
+	int random_packet_size;
+	int next_index_in_sent_msg_per_chan;
+	int channel_mask_id;
+	int modem_result_per_chan;
+	int notify_counter_per_chan;
+	int max_burst_size;        /* number of writes before close/open */
+	int card_removed;
+};
+
+struct sdio_al_test_debug {
+	u32 dun_throughput;
+	u32 rmnt_throughput;
+	struct dentry *debug_root;
+	struct dentry *debug_test_result;
+	struct dentry *debug_dun_throughput;
+	struct dentry *debug_rmnt_throughput;
+	struct dentry *rpc_sender_test;
+	struct dentry *rpc_qmi_diag_sender_test;
+	struct dentry *smem_test;
+	struct dentry *smem_rpc_test;
+	struct dentry *rmnet_a2_validation_test;
+	struct dentry *dun_a2_validation_test;
+	struct dentry *rmnet_a2_perf_test;
+	struct dentry *dun_a2_perf_test;
+	struct dentry *csvt_a2_perf_test;
+	struct dentry *rmnet_dun_a2_perf_test;
+	struct dentry *rpc_sender_rmnet_a2_perf_test;
+	struct dentry *all_channels_test;
+	struct dentry *host_sender_no_lp_diag_test;
+	struct dentry *host_sender_no_lp_diag_rpc_test;
+	struct dentry *rmnet_small_packets_test;
+	struct dentry *rmnet_rtt_test;
+	struct dentry *csvt_rtt_test;
+	struct dentry *modem_reset_rpc_test;
+	struct dentry *modem_reset_rmnet_test;
+	struct dentry *modem_reset_channels_4bit_dev_test;
+	struct dentry *modem_reset_channels_8bit_dev_test;
+	struct dentry *modem_reset_all_channels_test;
+	struct dentry *open_close_test;
+	struct dentry *open_close_dun_rmnet_test;
+	struct dentry *close_chan_lpm_test;
+	struct dentry *lpm_test_client_wakes_host_test;
+	struct dentry *lpm_test_host_wakes_client_test;
+	struct dentry *lpm_test_random_single_channel_test;
+	struct dentry *lpm_test_random_multi_channel_test;
+};
+
+struct test_context {
+	dev_t dev_num;
+	struct device *dev;
+	struct cdev *cdev;
+	int number_of_active_devices;
+	int max_number_of_devices;
+
+	struct sdio_test_device test_dev_arr[MAX_NUM_OF_SDIO_DEVICES];
+
+	struct test_channel *test_ch;
+
+	struct test_channel *test_ch_arr[SDIO_MAX_CHANNELS];
+
+	long testcase;
+
+	const char *name;
+
+	int exit_flag;
+
+	u32 signature;
+
+	int runtime_debug;
+
+	struct platform_device *smem_pdev;
+	struct sdio_smem_client *sdio_smem;
+	int smem_was_init;
+	u8 *smem_buf;
+	uint32_t smem_counter;
+
+	struct platform_device *csvt_app_pdev;
+
+	wait_queue_head_t   wait_q;
+	int test_completed;
+	int test_result;
+	struct sdio_al_test_debug debug;
+
+	struct wake_lock wake_lock;
+
+	unsigned int lpm_pseudo_random_seed;
+};
+
+/* FORWARD DECLARATIONS */
+static int set_params_loopback_9k(struct test_channel *tch);
+static int set_params_smem_test(struct test_channel *tch);
+static int set_params_a2_validation(struct test_channel *tch);
+static int set_params_a2_perf(struct test_channel *tch);
+static int set_params_8k_sender_no_lp(struct test_channel *tch);
+static int set_params_a2_small_pkts(struct test_channel *tch);
+static int set_params_rtt(struct test_channel *tch);
+static int set_params_loopback_9k_close(struct test_channel *tch);
+static int close_channel_lpm_test(int channel_num);
+static int set_params_lpm_test(struct test_channel *tch,
+				enum sdio_test_case_type test,
+				int timer_interval_ms);
+static void set_pseudo_random_seed(void);
+static int set_params_modem_reset(struct test_channel *tch);
+static int test_start(void);
+static void rx_cleanup(struct test_channel *test_ch, int *rx_packet_count);
+static void sdio_al_test_cleanup_channels(void);
+static void notify(void *priv, unsigned channel_event);
+#ifdef CONFIG_MSM_SDIO_SMEM
+static int sdio_smem_open(struct sdio_smem_client *sdio_smem);
+#endif
+
+/*
+ * Seed for pseudo random time sleeping in Random LPM test.
+ * If not set, current time in jiffies is used.
+ */
+static unsigned int seed;
+module_param(seed, int, 0);
+static struct test_context *test_ctx;
+
+static void sdio_al_test_initial_dev_and_chan(struct test_context *test_ctx)
+{
+	int i = 0;
+
+	if (!test_ctx) {
+		pr_err(TEST_MODULE_NAME ":%s - test_ctx is NULL.\n", __func__);
+		return;
+	}
+
+	for (i = 0 ; i < MAX_NUM_OF_SDIO_DEVICES ; ++i)
+		test_ctx->test_dev_arr[i].sdio_al_device = NULL;
+
+	for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
+		struct test_channel *tch = test_ctx->test_ch_arr[i];
+		if (!tch)
+			continue;
+		tch->is_used = 0;
+	}
+
+	sdio_al_test_cleanup_channels();
+}
+
+#ifdef CONFIG_DEBUG_FS
+
+static int message_repeat;
+
+static int sdio_al_test_extract_number(const char __user *buf,
+					size_t count)
+{
+	int ret = 0;
+	int number = -1;
+	char local_buf[MAX_STR_SIZE] = {0};
+	char *start = NULL;
+
+	if (count > MAX_STR_SIZE) {
+		pr_err(TEST_MODULE_NAME ": %s - MAX_STR_SIZE(%d) < count(%d). "
+		       "Please choose smaller number\n",
+		       __func__, MAX_STR_SIZE, (int)count);
+		return -EINVAL;
+	}
+
+	if (copy_from_user(local_buf, buf, count)) {
+		pr_err(TEST_MODULE_NAME ": %s - copy_from_user() failed\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	/* adding null termination to the string */
+	local_buf[count] = '\0';
+
+	/* stripping leading and trailing white spaces */
+	start = strstrip(local_buf);
+
+	ret = kstrtoint(start, 10, &number);
+
+	if (ret) {
+		pr_err(TEST_MODULE_NAME " : %s - kstrtoint() failed\n",
+		       __func__);
+		return ret;
+	}
+
+	return number;
+}
+
+static int sdio_al_test_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	message_repeat = 1;
+	return 0;
+}
+
+static void sdio_al_test_cleanup_channels(void)
+{
+	int channel_num;
+	int dummy = 0;
+
+	for (channel_num = 0 ; channel_num < SDIO_MAX_CHANNELS ;
+	      ++channel_num) {
+		if (channel_num == SDIO_SMEM)
+			continue;
+
+		 rx_cleanup(test_ctx->test_ch_arr[channel_num], &dummy);
+	}
+
+	return;
+}
+
+/* RPC SENDER TEST */
+static ssize_t rpc_sender_test_write(struct file *file,
+				      const char __user *buf,
+				      size_t count,
+				      loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- RPC SENDER TEST --\n");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_RPC]);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t rpc_sender_test_read(struct file *file,
+				     char __user *buffer,
+				     size_t count,
+				     loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nRPC_SENDER_TEST\n"
+		 "===============\n"
+		 "Description:\n"
+		 "TBD\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations rpc_sender_test_ops = {
+	.open = sdio_al_test_open,
+	.write = rpc_sender_test_write,
+	.read = rpc_sender_test_read,
+};
+
+/* RPC, QMI & DIAG SENDER TEST */
+static ssize_t rpc_qmi_diag_sender_test_write(struct file *file,
+					       const char __user *buf,
+					       size_t count,
+					       loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- RPC, QMI AND DIAG SENDER TEST --\n");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_RPC]);
+		set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_QMI]);
+		set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_DIAG]);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t rpc_qmi_diag_sender_test_read(struct file *file,
+					      char __user
+					      *buffer, size_t count,
+					      loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nRPC_QMI_DIAG_SENDER_TEST\n"
+		 "========================\n"
+		 "Description:\n"
+		 "TBD\n");
+
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations rpc_qmi_diag_sender_test_ops = {
+	.open = sdio_al_test_open,
+	.write = rpc_qmi_diag_sender_test_write,
+	.read = rpc_qmi_diag_sender_test_read,
+};
+
+/* SMEM TEST */
+static ssize_t smem_test_write(struct file *file,
+				const char __user *buf,
+				size_t count,
+				loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- SMEM TEST --\n");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_params_smem_test(test_ctx->test_ch_arr[SDIO_SMEM]);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t smem_test_read(struct file *file,
+			       char __user *buffer,
+			       size_t count,
+			       loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nSMEM_TEST\n"
+		 "=========\n"
+		 "Description:\n"
+		 "TBD\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations smem_test_ops = {
+	.open = sdio_al_test_open,
+	.write = smem_test_write,
+	.read = smem_test_read,
+};
+
+/* SMEM & RPC TEST */
+static ssize_t smem_rpc_test_write(struct file *file,
+				    const char __user *buf,
+				    size_t count,
+				    loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- SMEM AND RPC TEST --\n");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_RPC]);
+		set_params_smem_test(test_ctx->test_ch_arr[SDIO_SMEM]);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t smem_rpc_test_read(struct file *file,
+				   char __user *buffer,
+				   size_t count,
+				   loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nSMEM_RPC_TEST\n"
+		 "=============\n"
+		 "Description:\n"
+		 "TBD\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations smem_rpc_test_ops = {
+	.open = sdio_al_test_open,
+	.write = smem_rpc_test_write,
+	.read = smem_rpc_test_read,
+};
+
+/* RMNET A2 VALIDATION TEST */
+static ssize_t rmnet_a2_validation_test_write(struct file *file,
+						const char __user *buf,
+						size_t count,
+						loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- RMNET A2 VALIDATION TEST --\n");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_params_a2_validation(test_ctx->test_ch_arr[SDIO_RMNT]);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t rmnet_a2_validation_test_read(struct file *file,
+						char __user *buffer,
+						size_t count,
+						loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nRMNET_A2_VALIDATION_TEST\n"
+		 "=========================\n"
+		 "Description:\n"
+		 "In this test, the HOST sends multiple packets to the\n"
+		 "CLIENT and validates the packets loop backed from A2\n"
+		 "for the RMNET channel.\n\n"
+		 "END OF DESCRIPTION\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations rmnet_a2_validation_test_ops = {
+	.open = sdio_al_test_open,
+	.write = rmnet_a2_validation_test_write,
+	.read = rmnet_a2_validation_test_read,
+};
+
+/* DUN A2 VALIDATION TEST */
+static ssize_t dun_a2_validation_test_write(struct file *file,
+						const char __user *buf,
+						size_t count,
+						loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- DUN A2 VALIDATION TEST --\n");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_params_a2_validation(test_ctx->test_ch_arr[SDIO_DUN]);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t dun_a2_validation_test_read(struct file *file,
+						char __user *buffer,
+						size_t count,
+						loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		"\nDUN_A2_VALIDATION_TEST\n"
+		"=========================\n"
+		"Description:\n"
+		"In this test, the HOST sends multiple packets to the\n"
+		"CLIENT and validates the packets loop backed from A2\n"
+		"for the DUN channel.\n\n"
+		"END OF DESCRIPTION\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations dun_a2_validation_test_ops = {
+	.open = sdio_al_test_open,
+	.write = dun_a2_validation_test_write,
+	.read = dun_a2_validation_test_read,
+};
+
+/* RMNET A2 PERFORMANCE TEST */
+static ssize_t rmnet_a2_perf_test_write(struct file *file,
+					 const char __user *buf,
+					 size_t count,
+					 loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- RMNET A2 PERFORMANCE TEST --\n");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_params_a2_perf(test_ctx->test_ch_arr[SDIO_RMNT]);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t rmnet_a2_perf_test_read(struct file *file,
+					char __user *buffer,
+					size_t count,
+					loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nRMNET_A2_PERFORMANCE_TEST\n"
+		 "=========================\n"
+		 "Description:\n"
+		 "TBD\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations rmnet_a2_perf_test_ops = {
+	.open = sdio_al_test_open,
+	.write = rmnet_a2_perf_test_write,
+	.read = rmnet_a2_perf_test_read,
+};
+
+/* DUN A2 PERFORMANCE TEST */
+static ssize_t dun_a2_perf_test_write(struct file *file,
+				       const char __user *buf,
+				       size_t count,
+				       loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- DUN A2 PERFORMANCE TEST --\n");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_params_a2_perf(test_ctx->test_ch_arr[SDIO_DUN]);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t dun_a2_perf_test_read(struct file *file,
+				      char __user *buffer,
+				      size_t count,
+				      loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nDUN_A2_PERFORMANCE_TEST\n"
+		 "=======================\n"
+		 "Description:\n"
+		 "TBD\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations dun_a2_perf_test_ops = {
+	.open = sdio_al_test_open,
+	.write = dun_a2_perf_test_write,
+	.read = dun_a2_perf_test_read,
+};
+
+/* CSVT A2 PERFORMANCE TEST */
+static ssize_t csvt_a2_perf_test_write(struct file *file,
+					const char __user *buf,
+					size_t count,
+					loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- CSVT A2 PERFORMANCE TEST --\n");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_params_a2_perf(test_ctx->test_ch_arr[SDIO_CSVT]);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t csvt_a2_perf_test_read(struct file *file,
+				       char __user *buffer,
+				       size_t count,
+				       loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nCSVT_A2_PERFORMANCE_TEST\n"
+		 "========================\n"
+		 "Description:\n"
+		 "Loopback test on the CSVT Channel, in order to check "
+		 "throughput performance.\n"
+		 "Packet size that are sent on the CSVT channel in this "
+		 "test is %d.bytes\n\n"
+		 "END OF DESCRIPTION\n", CSVT_PACKET_SIZE);
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations csvt_a2_perf_test_ops = {
+	.open = sdio_al_test_open,
+	.write = csvt_a2_perf_test_write,
+	.read = csvt_a2_perf_test_read,
+};
+
+/* RMNET DUN A2 PERFORMANCE TEST */
+static ssize_t rmnet_dun_a2_perf_test_write(struct file *file,
+					     const char __user *buf,
+					     size_t count,
+					     loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- RMNET AND DUN A2 PERFORMANCE TEST --\n");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_params_a2_perf(test_ctx->test_ch_arr[SDIO_RMNT]);
+		set_params_a2_perf(test_ctx->test_ch_arr[SDIO_DUN]);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t rmnet_dun_a2_perf_test_read(struct file *file,
+					    char __user *buffer,
+					    size_t count,
+					    loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nRMNET_DUN_A2_PERFORMANCE_TEST\n"
+		 "=============================\n"
+		 "Description:\n"
+		 "TBD\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations rmnet_dun_a2_perf_test_ops = {
+	.open = sdio_al_test_open,
+	.write = rmnet_dun_a2_perf_test_write,
+	.read = rmnet_dun_a2_perf_test_read,
+};
+
+/* RPC SENDER & RMNET A2 PERFORMANCE TEST */
+static ssize_t rpc_sender_rmnet_a2_perf_test_write(struct file *file,
+						    const char __user *buf,
+						    size_t count,
+						    loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "--RPC SENDER AND RMNET A2 "
+		"PERFORMANCE --\n");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_RPC]);
+		set_params_a2_perf(test_ctx->test_ch_arr[SDIO_RMNT]);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t rpc_sender_rmnet_a2_perf_test_read(struct file *file,
+						   char __user *buffer,
+						   size_t count,
+						   loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nRPC_SENDER_RMNET_A2_PERFORMANCE_TEST\n"
+		 "====================================\n"
+		 "Description:\n"
+		 "TBD\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations rpc_sender_rmnet_a2_perf_test_ops = {
+	.open = sdio_al_test_open,
+	.write = rpc_sender_rmnet_a2_perf_test_write,
+	.read = rpc_sender_rmnet_a2_perf_test_read,
+};
+
+/* ALL CHANNELS TEST */
+static ssize_t all_channels_test_write(struct file *file,
+					const char __user *buf,
+					size_t count,
+					loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- ALL THE CHANNELS TEST --\n");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_RPC]);
+		set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_QMI]);
+		set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_DIAG]);
+		set_params_a2_perf(test_ctx->test_ch_arr[SDIO_RMNT]);
+		set_params_a2_perf(test_ctx->test_ch_arr[SDIO_DUN]);
+		set_params_smem_test(test_ctx->test_ch_arr[SDIO_SMEM]);
+		set_params_a2_perf(test_ctx->test_ch_arr[SDIO_CSVT]);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t all_channels_test_read(struct file *file,
+				       char __user *buffer,
+				       size_t count,
+				       loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nALL_CHANNELS_TEST\n"
+		 "=================\n"
+		 "Description:\n"
+		 "TBD\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations all_channels_test_ops = {
+	.open = sdio_al_test_open,
+	.write = all_channels_test_write,
+	.read = all_channels_test_read,
+};
+
+/* HOST SENDER NO LP DIAG TEST */
+static ssize_t host_sender_no_lp_diag_test_write(struct file *file,
+						  const char __user *buf,
+						  size_t count,
+						  loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- HOST SENDER NO LP FOR DIAG TEST --");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_params_8k_sender_no_lp(test_ctx->test_ch_arr[SDIO_DIAG]);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t host_sender_no_lp_diag_test_read(struct file *file,
+						 char __user *buffer,
+						 size_t count,
+						 loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nHOST_SENDER_NO_LP_DIAG_TEST\n"
+		 "===========================\n"
+		 "Description:\n"
+		 "TBD\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations host_sender_no_lp_diag_test_ops = {
+	.open = sdio_al_test_open,
+	.write = host_sender_no_lp_diag_test_write,
+	.read = host_sender_no_lp_diag_test_read,
+};
+
+/* HOST SENDER NO LP DIAG, RPC TEST */
+static ssize_t host_sender_no_lp_diag_rpc_test_write(
+						 struct file *file,
+						 const char __user *buf,
+						 size_t count,
+						 loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- HOST SENDER NO LP FOR DIAG, RPC "
+		"TEST --");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_params_8k_sender_no_lp(test_ctx->test_ch_arr[SDIO_DIAG]);
+		set_params_8k_sender_no_lp(test_ctx->test_ch_arr[SDIO_RPC]);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t host_sender_no_lp_diag_rpc_test_read(
+						 struct file *file,
+						 char __user *buffer,
+						 size_t count,
+						 loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nHOST_SENDER_NO_LP_DIAG_RPC_TEST\n"
+		 "===================================\n"
+		 "Description:\n"
+		 "TBD\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations host_sender_no_lp_diag_rpc_test_ops = {
+	.open = sdio_al_test_open,
+	.write = host_sender_no_lp_diag_rpc_test_write,
+	.read = host_sender_no_lp_diag_rpc_test_read,
+};
+
+/* RMNET SMALL PACKETS TEST */
+static ssize_t rmnet_small_packets_test_write(struct file *file,
+					       const char __user *buf,
+					       size_t count,
+					       loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- RMNET SMALL PACKETS (5-128) TEST --");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_params_a2_small_pkts(test_ctx->test_ch_arr[SDIO_RMNT]);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t rmnet_small_packets_test_read(struct file *file,
+					      char __user *buffer,
+					      size_t count,
+					      loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nRMNET_SMALL_PACKETS_TEST\n"
+		 "========================\n"
+		 "Description:\n"
+		 "TBD\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations rmnet_small_packets_test_ops = {
+	.open = sdio_al_test_open,
+	.write = rmnet_small_packets_test_write,
+	.read = rmnet_small_packets_test_read,
+};
+
+/* RMNET RTT TEST */
+static ssize_t rmnet_rtt_test_write(struct file *file,
+				     const char __user *buf,
+				     size_t count,
+				     loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- RMNET RTT TEST --");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_params_rtt(test_ctx->test_ch_arr[SDIO_RMNT]);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t rmnet_rtt_test_read(struct file *file,
+				    char __user *buffer,
+				    size_t count,
+				    loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nRMNET_RTT_TEST\n"
+		 "==============\n"
+		 "Description:\n"
+		 "TBD\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations rmnet_rtt_test_ops = {
+	.open = sdio_al_test_open,
+	.write = rmnet_rtt_test_write,
+	.read = rmnet_rtt_test_read,
+};
+
+/* CSVT RTT TEST */
+static ssize_t csvt_rtt_test_write(struct file *file,
+				    const char __user *buf,
+				    size_t count,
+				    loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- CSVT RTT TEST --");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_params_rtt(test_ctx->test_ch_arr[SDIO_CSVT]);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t csvt_rtt_test_read(struct file *file,
+				   char __user *buffer,
+				   size_t count,
+				   loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nCSVT_RTT_TEST\n"
+		 "==============\n"
+		 "Description:\n"
+		 "In this test the HOST send a message of %d bytes "
+		 "to the CLIENT\n\n"
+		 "END OF DESCRIPTION\n", SDIO_CSVT_RTT_PACKET_SIZE);
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations csvt_rtt_test_ops = {
+	.open = sdio_al_test_open,
+	.write = csvt_rtt_test_write,
+	.read = csvt_rtt_test_read,
+};
+
+/* MODEM RESET RPC TEST */
+static ssize_t modem_reset_rpc_test_write(struct file *file,
+					   const char __user *buf,
+					   size_t count,
+					   loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- MODEM RESET - RPC CHANNEL TEST --");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RPC]);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t modem_reset_rpc_test_read(struct file *file,
+					  char __user *buffer,
+					  size_t count,
+					  loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nMODEM_RESET_RPC_TEST\n"
+		 "====================\n"
+		 "Description:\n"
+		 "TBD\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations modem_reset_rpc_test_ops = {
+	.open = sdio_al_test_open,
+	.write = modem_reset_rpc_test_write,
+	.read = modem_reset_rpc_test_read,
+};
+
+/* MODEM RESET RMNET TEST */
+static ssize_t modem_reset_rmnet_test_write(struct file *file,
+					     const char __user *buf,
+					     size_t count,
+					     loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- MODEM RESET - RMNT CHANNEL TEST --");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RMNT]);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t modem_reset_rmnet_test_read(struct file *file,
+					    char __user *buffer,
+					    size_t count,
+					    loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nMODEM_RESET_RMNET_TEST\n"
+		 "======================\n"
+		 "Description:\n"
+		 "TBD\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations modem_reset_rmnet_test_ops = {
+	.open = sdio_al_test_open,
+	.write = modem_reset_rmnet_test_write,
+	.read = modem_reset_rmnet_test_read,
+};
+
+/* MODEM RESET - CHANNELS IN 4BIT DEVICE TEST */
+static ssize_t modem_reset_channels_4bit_dev_test_write(
+						struct file *file,
+						const char __user *buf,
+						size_t count,
+						loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- MODEM RESET - ALL CHANNELS IN "
+		"4BIT DEVICE TEST --");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RPC]);
+		set_params_modem_reset(test_ctx->test_ch_arr[SDIO_QMI]);
+		set_params_modem_reset(test_ctx->test_ch_arr[SDIO_DIAG]);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t modem_reset_channels_4bit_dev_test_read(
+						struct file *file,
+						char __user *buffer,
+						size_t count,
+						loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nMODEM_RESET_CHANNELS_4BIT_DEV_TEST\n"
+		 "==================================\n"
+		 "Description:\n"
+		 "TBD\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations modem_reset_channels_4bit_dev_test_ops = {
+	.open = sdio_al_test_open,
+	.write = modem_reset_channels_4bit_dev_test_write,
+	.read = modem_reset_channels_4bit_dev_test_read,
+};
+
+/* MODEM RESET - CHANNELS IN 8BIT DEVICE TEST */
+static ssize_t modem_reset_channels_8bit_dev_test_write(
+						struct file *file,
+						const char __user *buf,
+						size_t count,
+						loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- MODEM RESET - ALL CHANNELS IN "
+		"8BIT DEVICE TEST --");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RMNT]);
+		set_params_modem_reset(test_ctx->test_ch_arr[SDIO_DUN]);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t modem_reset_channels_8bit_dev_test_read(
+						struct file *file,
+						char __user *buffer,
+						size_t count,
+						loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nMODEM_RESET_CHANNELS_8BIT_DEV_TEST\n"
+		 "==================================\n"
+		 "Description:\n"
+		 "TBD\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations modem_reset_channels_8bit_dev_test_ops = {
+	.open = sdio_al_test_open,
+	.write = modem_reset_channels_8bit_dev_test_write,
+	.read = modem_reset_channels_8bit_dev_test_read,
+};
+
+/* MODEM RESET - ALL CHANNELS TEST */
+static ssize_t modem_reset_all_channels_test_write(struct file *file,
+						    const char __user *buf,
+						    size_t count,
+						    loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- MODEM RESET - ALL CHANNELS TEST --");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RPC]);
+		set_params_modem_reset(test_ctx->test_ch_arr[SDIO_QMI]);
+		set_params_modem_reset(test_ctx->test_ch_arr[SDIO_DIAG]);
+		set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RMNT]);
+		set_params_modem_reset(test_ctx->test_ch_arr[SDIO_DUN]);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t modem_reset_all_channels_test_read(struct file *file,
+						   char __user *buffer,
+						   size_t count,
+						   loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nMODEM_RESET_ALL_CHANNELS_TEST\n"
+		 "=============================\n"
+		 "Description:\n"
+		 "TBD\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations modem_reset_all_channels_test_ops = {
+	.open = sdio_al_test_open,
+	.write = modem_reset_all_channels_test_write,
+	.read = modem_reset_all_channels_test_read,
+};
+
+/* HOST SENDER WITH OPEN/CLOSE TEST */
+static ssize_t open_close_test_write(struct file *file,
+						   const char __user *buf,
+						   size_t count,
+						   loff_t *ppos)
+{
+	int ret = 0;
+	struct test_channel **ch_arr = test_ctx->test_ch_arr;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- HOST SENDER WITH OPEN/CLOSE TEST --");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_params_loopback_9k_close(ch_arr[SDIO_DIAG]);
+		set_params_loopback_9k_close(ch_arr[SDIO_RPC]);
+		set_params_loopback_9k_close(ch_arr[SDIO_SMEM]);
+		set_params_loopback_9k_close(ch_arr[SDIO_QMI]);
+		set_params_loopback_9k_close(ch_arr[SDIO_RMNT]);
+		set_params_loopback_9k_close(ch_arr[SDIO_DUN]);
+		set_params_loopback_9k_close(ch_arr[SDIO_CSVT]);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+
+		pr_info(TEST_MODULE_NAME " -- correctness test for"
+				"DIAG ");
+		set_params_loopback_9k(ch_arr[SDIO_DIAG]);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t open_close_test_read(struct file *file,
+						  char __user *buffer,
+						  size_t count,
+						  loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nOPEN_CLOSE_TEST\n"
+		 "============================\n"
+		 "Description:\n"
+		 "In this test the host sends 5k packets to the modem in the "
+		 "following sequence: Send a random burst of packets on "
+		 "Diag and Rmnet channels, read 0 or a random number "
+		 "of packets, close and re-open the channel. At the end of the "
+		 "test, the channel is verified by running a loopback test\n\n"
+		 "END OF DESCRIPTION\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations open_close_test_ops = {
+	.open = sdio_al_test_open,
+	.write = open_close_test_write,
+	.read = open_close_test_read,
+};
+
+/* HOST SENDER WITH OPEN/CLOSE FOR DUN & RMNET TEST */
+static ssize_t open_close_dun_rmnet_test_write(struct file *file,
+						   const char __user *buf,
+						   size_t count,
+						   loff_t *ppos)
+{
+	int ret = 0;
+	struct test_channel **ch_arr = test_ctx->test_ch_arr;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- HOST SENDER WITH OPEN/CLOSE FOR "
+		"DUN AND RMNET TEST --");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_params_loopback_9k_close(ch_arr[SDIO_DUN]);
+		set_params_loopback_9k_close(ch_arr[SDIO_RMNT]);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t open_close_dun_rmnet_test_read(struct file *file,
+						  char __user *buffer,
+						  size_t count,
+						  loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nOPEN_CLOSE_DUN_RMNET_TEST\n"
+		 "============================\n"
+		 "Description:\n"
+		 "In this test the host sends 5k packets to the modem in the "
+		 "following sequence: Send a random burst of packets on "
+		 "DUN and Rmnet channels, read 0 or a random number "
+		 "of packets, close and re-open the channel.\n\n"
+		 "END OF DESCRIPTION\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations open_close_dun_rmnet_test_ops = {
+	.open = sdio_al_test_open,
+	.write = open_close_dun_rmnet_test_write,
+	.read = open_close_dun_rmnet_test_read,
+};
+
+/* CLOSE CHANNEL & LPM TEST HOST WAKES THE CLIENT TEST */
+static ssize_t close_chan_lpm_test_write(struct file *file,
+					  const char __user *buf,
+					  size_t count,
+					  loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int channel_num = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- CLOSE CHANNEL & LPM TEST "
+		"HOST WAKES THE CLIENT TEST --\n");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		for (channel_num = 0 ; channel_num < SDIO_MAX_CHANNELS ;
+		     channel_num++) {
+
+			ret = close_channel_lpm_test(channel_num);
+
+			if (ret)
+				break;
+
+			set_params_lpm_test(test_ctx->test_ch_arr[SDIO_RPC],
+					    SDIO_TEST_LPM_HOST_WAKER, 120);
+
+			ret = test_start();
+
+			if (ret)
+				break;
+		}
+
+		if (ret) {
+			pr_err(TEST_MODULE_NAME " -- Close channel & LPM Test "
+			       "FAILED: %d --\n", ret);
+		} else {
+			pr_err(TEST_MODULE_NAME " -- Close channel & LPM Test "
+			       "PASSED\n");
+		}
+	}
+
+	return count;
+}
+
+static ssize_t close_chan_lpm_test_read(struct file *file,
+					 char __user *buffer,
+					 size_t count,
+					 loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nCLOSE_CHAN_LPM_TEST\n"
+		 "===================\n"
+		 "Description:\n"
+		 "TBD\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations close_chan_lpm_test_ops = {
+	.open = sdio_al_test_open,
+	.write = close_chan_lpm_test_write,
+	.read = close_chan_lpm_test_read,
+};
+
+/* LPM TEST FOR DEVICE 1. CLIENT WAKES THE HOST TEST */
+static ssize_t lpm_test_client_wakes_host_test_write(struct file *file,
+						      const char __user *buf,
+						      size_t count,
+						      loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- LPM TEST FOR DEVICE 1. CLIENT "
+		"WAKES THE HOST TEST --\n");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_params_lpm_test(test_ctx->test_ch_arr[SDIO_RPC],
+				    SDIO_TEST_LPM_CLIENT_WAKER, 90);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t lpm_test_client_wakes_host_test_read(struct file *file,
+						     char __user *buffer,
+						     size_t count,
+						     loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nLPM_TEST_CLIENT_WAKES_HOST_TEST\n"
+		 "===============================\n"
+		 "Description:\n"
+		 "In this test, the HOST is going into LPM mode,\n"
+		 "and the CLIENT is responsible to send it a message\n"
+		 "in order to wake it up\n\n"
+		 "END OF DESCRIPTION\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations lpm_test_client_wakes_host_test_ops = {
+	.open = sdio_al_test_open,
+	.write = lpm_test_client_wakes_host_test_write,
+	.read = lpm_test_client_wakes_host_test_read,
+};
+
+/* LPM TEST FOR DEVICE 1. HOST WAKES THE CLIENT TEST */
+static ssize_t lpm_test_host_wakes_client_test_write(struct file *file,
+						      const char __user *buf,
+						      size_t count,
+						      loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- LPM TEST FOR DEVICE 1. HOST "
+		"WAKES THE CLIENT TEST --\n");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_params_lpm_test(test_ctx->test_ch_arr[SDIO_RPC],
+			    SDIO_TEST_LPM_HOST_WAKER, 120);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t lpm_test_host_wakes_client_test_read(struct file *file,
+						     char __user *buffer,
+						     size_t count,
+						     loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nLPM_TEST_HOST_WAKES_CLIENT_TEST\n"
+		 "===============================\n"
+		 "Description:\n"
+		 "In this test, the CLIENT goes into LPM mode, and the\n"
+		 "HOST is responsible to send it a message\n"
+		 "in order to wake it up\n\n"
+		 "END OF DESCRIPTION\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations lpm_test_host_wakes_client_test_ops = {
+	.open = sdio_al_test_open,
+	.write = lpm_test_host_wakes_client_test_write,
+	.read = lpm_test_host_wakes_client_test_read,
+};
+
+/* LPM TEST RANDOM, SINGLE CHANNEL TEST */
+static ssize_t lpm_test_random_single_channel_test_write(
+						struct file *file,
+						const char __user *buf,
+						size_t count,
+						loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- LPM TEST RANDOM SINGLE "
+		"CHANNEL TEST --\n");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_pseudo_random_seed();
+		set_params_lpm_test(test_ctx->test_ch_arr[SDIO_RPC],
+				    SDIO_TEST_LPM_RANDOM, 0);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t lpm_test_random_single_channel_test_read(
+						struct file *file,
+						char __user *buffer,
+						size_t count,
+						loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nLPM_TEST_RANDOM_SINGLE_CHANNEL_TEST\n"
+		 "===================================\n"
+		 "Description:\n"
+		 "In this test, the HOST and CLIENT "
+		 "send messages to each other,\n"
+		 "random in time, over RPC channel only.\n"
+		 "All events are being recorded, and later on,\n"
+		 "they are being analysed by the HOST and by the CLIENT\n,"
+		 "in order to check if the LPM mechanism worked properly,\n"
+		 "meaning:"
+		 " When all the relevant conditions are met, a device should:\n"
+		 "1. Go to sleep\n"
+		 "2. Wake up\n"
+		 "3. Stay awake\n\n"
+		 "END OF DESCRIPTION\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations lpm_test_random_single_channel_test_ops = {
+	.open = sdio_al_test_open,
+	.write = lpm_test_random_single_channel_test_write,
+	.read = lpm_test_random_single_channel_test_read,
+};
+
+/* LPM TEST RANDOM, MULTI CHANNEL TEST */
+static ssize_t lpm_test_random_multi_channel_test_write(
+						struct file *file,
+						const char __user *buf,
+						size_t count,
+						loff_t *ppos)
+{
+	int ret = 0;
+	int i = 0;
+	int number = -1;
+
+	pr_info(TEST_MODULE_NAME "-- LPM TEST RANDOM MULTI CHANNEL TEST --\n");
+
+	number = sdio_al_test_extract_number(buf, count);
+
+	if (number < 0) {
+		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
+		       "failed. number = %d\n", __func__, number);
+		return count;
+	}
+
+	for (i = 0 ; i < number ; ++i) {
+		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
+		pr_info(TEST_MODULE_NAME " ===================");
+
+		sdio_al_test_initial_dev_and_chan(test_ctx);
+
+		set_pseudo_random_seed();
+
+		set_params_lpm_test(test_ctx->test_ch_arr[SDIO_RPC],
+				    SDIO_TEST_LPM_RANDOM, 0);
+		set_params_lpm_test(test_ctx->test_ch_arr[SDIO_DIAG],
+				    SDIO_TEST_LPM_RANDOM, 0);
+		set_params_lpm_test(test_ctx->test_ch_arr[SDIO_QMI],
+				SDIO_TEST_LPM_RANDOM, 0);
+
+		ret = test_start();
+
+		if (ret)
+			break;
+	}
+
+	return count;
+}
+
+static ssize_t lpm_test_random_multi_channel_test_read(
+				 struct file *file,
+				 char __user *buffer,
+				 size_t count,
+				 loff_t *offset)
+{
+	memset((void *)buffer, 0, count);
+
+	snprintf(buffer, count,
+		 "\nLPM_TEST_RANDOM_MULTI_CHANNEL_TEST\n"
+		 "==================================\n"
+		 "Description:\n"
+		 "In this test, the HOST and CLIENT "
+		 "send messages to each other,\n"
+		 "random in time, over RPC, QMI AND DIAG channels\n"
+		 "(i.e, on both SDIO devices).\n"
+		 "All events are being recorded, and later on,\n"
+		 "they are being analysed by the HOST and by the CLIENT,\n"
+		 "in order to check if the LPM mechanism worked properly,\n"
+		 "meaning:"
+		 " When all the relevant conditions are met, a device should:\n"
+		 "1. Go to sleep\n"
+		 "2. Wake up\n"
+		 "3. Stay awake\n\n"
+		 "END OF DESCRIPTION\n");
+
+	if (message_repeat == 1) {
+		message_repeat = 0;
+		return strnlen(buffer, count);
+	} else {
+		return 0;
+	}
+}
+
+const struct file_operations lpm_test_random_multi_channel_test_ops = {
+	.open = sdio_al_test_open,
+	.write = lpm_test_random_multi_channel_test_write,
+	.read = lpm_test_random_multi_channel_test_read,
+};
+
+static int sdio_al_test_debugfs_init(void)
+{
+	test_ctx->debug.debug_root = debugfs_create_dir("sdio_al_test",
+							       NULL);
+	if (!test_ctx->debug.debug_root)
+		return -ENOENT;
+
+	test_ctx->debug.debug_test_result = debugfs_create_u32(
+					"test_result",
+					S_IRUGO | S_IWUGO,
+					test_ctx->debug.debug_root,
+					&test_ctx->test_result);
+
+	test_ctx->debug.debug_dun_throughput = debugfs_create_u32(
+					"dun_throughput",
+					S_IRUGO | S_IWUGO,
+					test_ctx->debug.debug_root,
+					&test_ctx->debug.dun_throughput);
+
+	test_ctx->debug.debug_rmnt_throughput = debugfs_create_u32(
+					"rmnt_throughput",
+					S_IRUGO | S_IWUGO,
+					test_ctx->debug.debug_root,
+					&test_ctx->debug.rmnt_throughput);
+
+	test_ctx->debug.rpc_sender_test =
+		debugfs_create_file("10_rpc_sender_test",
+				    S_IRUGO | S_IWUGO,
+				    test_ctx->debug.debug_root,
+				    NULL,
+				    &rpc_sender_test_ops);
+
+	test_ctx->debug.rpc_qmi_diag_sender_test =
+		debugfs_create_file("20_rpc_qmi_diag_sender_test",
+				    S_IRUGO | S_IWUGO,
+				    test_ctx->debug.debug_root,
+				    NULL,
+				    &rpc_qmi_diag_sender_test_ops);
+
+	test_ctx->debug.rmnet_a2_validation_test =
+		debugfs_create_file("30_rmnet_a2_validation_test",
+				    S_IRUGO | S_IWUGO,
+				    test_ctx->debug.debug_root,
+				    NULL,
+				    &rmnet_a2_validation_test_ops);
+
+	test_ctx->debug.dun_a2_validation_test =
+		debugfs_create_file("40_dun_a2_validation_test",
+				    S_IRUGO | S_IWUGO,
+				    test_ctx->debug.debug_root,
+				    NULL,
+				    &dun_a2_validation_test_ops);
+
+	test_ctx->debug.rmnet_a2_perf_test =
+		debugfs_create_file("50_rmnet_a2_perf_test",
+				    S_IRUGO | S_IWUGO,
+				    test_ctx->debug.debug_root,
+				    NULL,
+				    &rmnet_a2_perf_test_ops);
+
+	test_ctx->debug.dun_a2_perf_test =
+		debugfs_create_file("60_dun_a2_perf_test",
+				    S_IRUGO | S_IWUGO,
+				    test_ctx->debug.debug_root,
+				    NULL,
+				    &dun_a2_perf_test_ops);
+
+	test_ctx->debug.csvt_a2_perf_test =
+		debugfs_create_file("71_csvt_a2_perf_test",
+				    S_IRUGO | S_IWUGO,
+				    test_ctx->debug.debug_root,
+				    NULL,
+				    &csvt_a2_perf_test_ops);
+
+	test_ctx->debug.rmnet_dun_a2_perf_test =
+		debugfs_create_file("70_rmnet_dun_a2_perf_test",
+				    S_IRUGO | S_IWUGO,
+				    test_ctx->debug.debug_root,
+				    NULL,
+				    &rmnet_dun_a2_perf_test_ops);
+
+	test_ctx->debug.rpc_sender_rmnet_a2_perf_test =
+		debugfs_create_file("80_rpc_sender_rmnet_a2_perf_test",
+				    S_IRUGO | S_IWUGO,
+				    test_ctx->debug.debug_root,
+				    NULL,
+				    &rpc_sender_rmnet_a2_perf_test_ops);
+
+	test_ctx->debug.smem_test =
+		debugfs_create_file("90_smem_test",
+				    S_IRUGO | S_IWUGO,
+				    test_ctx->debug.debug_root,
+				    NULL,
+				    &smem_test_ops);
+
+	test_ctx->debug.smem_rpc_test =
+		debugfs_create_file("100_smem_rpc_test",
+				    S_IRUGO | S_IWUGO,
+				    test_ctx->debug.debug_root,
+				    NULL,
+				    &smem_rpc_test_ops);
+
+	test_ctx->debug.all_channels_test =
+		debugfs_create_file("150_all_channels_test",
+				    S_IRUGO | S_IWUGO,
+				    test_ctx->debug.debug_root,
+				    NULL,
+				    &all_channels_test_ops);
+
+	test_ctx->debug.host_sender_no_lp_diag_test =
+		debugfs_create_file("160_host_sender_no_lp_diag_test",
+				    S_IRUGO | S_IWUGO,
+				    test_ctx->debug.debug_root,
+				    NULL,
+				    &host_sender_no_lp_diag_test_ops);
+
+	test_ctx->debug.host_sender_no_lp_diag_rpc_test =
+		debugfs_create_file("170_host_sender_no_lp_diag_rpc_test",
+				     S_IRUGO | S_IWUGO,
+				     test_ctx->debug.debug_root,
+				     NULL,
+				     &host_sender_no_lp_diag_rpc_test_ops);
+
+	test_ctx->debug.rmnet_small_packets_test =
+		debugfs_create_file("180_rmnet_small_packets_test",
+				     S_IRUGO | S_IWUGO,
+				     test_ctx->debug.debug_root,
+				     NULL,
+				     &rmnet_small_packets_test_ops);
+
+	test_ctx->debug.rmnet_rtt_test =
+		debugfs_create_file("190_rmnet_rtt_test",
+				     S_IRUGO | S_IWUGO,
+				     test_ctx->debug.debug_root,
+				     NULL,
+				     &rmnet_rtt_test_ops);
+
+	test_ctx->debug.csvt_rtt_test =
+		debugfs_create_file("191_csvt_rtt_test",
+				     S_IRUGO | S_IWUGO,
+				     test_ctx->debug.debug_root,
+				     NULL,
+				     &csvt_rtt_test_ops);
+
+	test_ctx->debug.modem_reset_rpc_test =
+		debugfs_create_file("220_modem_reset_rpc_test",
+				     S_IRUGO | S_IWUGO,
+				     test_ctx->debug.debug_root,
+				     NULL,
+				     &modem_reset_rpc_test_ops);
+
+	test_ctx->debug.modem_reset_rmnet_test =
+		debugfs_create_file("230_modem_reset_rmnet_test",
+				     S_IRUGO | S_IWUGO,
+				     test_ctx->debug.debug_root,
+				     NULL,
+				     &modem_reset_rmnet_test_ops);
+
+	test_ctx->debug.modem_reset_channels_4bit_dev_test =
+		debugfs_create_file("240_modem_reset_channels_4bit_dev_test",
+				     S_IRUGO | S_IWUGO,
+				     test_ctx->debug.debug_root,
+				     NULL,
+				     &modem_reset_channels_4bit_dev_test_ops);
+
+	test_ctx->debug.modem_reset_channels_8bit_dev_test =
+		debugfs_create_file("250_modem_reset_channels_8bit_dev_test",
+				     S_IRUGO | S_IWUGO,
+				     test_ctx->debug.debug_root,
+				     NULL,
+				     &modem_reset_channels_8bit_dev_test_ops);
+
+	test_ctx->debug.modem_reset_all_channels_test =
+		debugfs_create_file("260_modem_reset_all_channels_test",
+				     S_IRUGO | S_IWUGO,
+				     test_ctx->debug.debug_root,
+				     NULL,
+				     &modem_reset_all_channels_test_ops);
+
+	test_ctx->debug.open_close_test =
+		debugfs_create_file("270_open_close_test",
+				     S_IRUGO | S_IWUGO,
+				     test_ctx->debug.debug_root,
+				     NULL,
+				     &open_close_test_ops);
+
+	test_ctx->debug.open_close_dun_rmnet_test =
+		debugfs_create_file("271_open_close_dun_rmnet_test",
+				     S_IRUGO | S_IWUGO,
+				     test_ctx->debug.debug_root,
+				     NULL,
+				     &open_close_dun_rmnet_test_ops);
+
+	test_ctx->debug.close_chan_lpm_test =
+		debugfs_create_file("280_close_chan_lpm_test",
+				     S_IRUGO | S_IWUGO,
+				     test_ctx->debug.debug_root,
+				     NULL,
+				     &close_chan_lpm_test_ops);
+
+	test_ctx->debug.lpm_test_client_wakes_host_test =
+		debugfs_create_file("600_lpm_test_client_wakes_host_test",
+				     S_IRUGO | S_IWUGO,
+				     test_ctx->debug.debug_root,
+				     NULL,
+				     &lpm_test_client_wakes_host_test_ops);
+
+	test_ctx->debug.lpm_test_host_wakes_client_test =
+		debugfs_create_file("610_lpm_test_host_wakes_client_test",
+				     S_IRUGO | S_IWUGO,
+				     test_ctx->debug.debug_root,
+				     NULL,
+				     &lpm_test_host_wakes_client_test_ops);
+
+	test_ctx->debug.lpm_test_random_single_channel_test =
+		debugfs_create_file("620_lpm_test_random_single_channel_test",
+				     S_IRUGO | S_IWUGO,
+				     test_ctx->debug.debug_root,
+				     NULL,
+				     &lpm_test_random_single_channel_test_ops);
+
+	test_ctx->debug.lpm_test_random_multi_channel_test =
+		debugfs_create_file("630_lpm_test_random_multi_channel_test",
+				     S_IRUGO | S_IWUGO,
+				     test_ctx->debug.debug_root,
+				     NULL,
+				     &lpm_test_random_multi_channel_test_ops);
+
+	if ((!test_ctx->debug.debug_dun_throughput) &&
+	    (!test_ctx->debug.debug_rmnt_throughput)) {
+		debugfs_remove_recursive(test_ctx->debug.debug_root);
+		test_ctx->debug.debug_root = NULL;
+		return -ENOENT;
+	}
+	return 0;
+}
+
+static void sdio_al_test_debugfs_cleanup(void)
+{
+       debugfs_remove(test_ctx->debug.debug_dun_throughput);
+       debugfs_remove(test_ctx->debug.debug_rmnt_throughput);
+       debugfs_remove(test_ctx->debug.debug_root);
+}
+#endif
+
+static int channel_name_to_id(char *name)
+{
+	pr_info(TEST_MODULE_NAME "%s: channel name %s\n",
+		__func__, name);
+
+	if (!strncmp(name, "SDIO_RPC_TEST",
+		     strnlen("SDIO_RPC_TEST", CHANNEL_NAME_SIZE)))
+		return SDIO_RPC;
+	else if (!strncmp(name, "SDIO_QMI_TEST",
+			  strnlen("SDIO_QMI_TEST", TEST_CH_NAME_SIZE)))
+		return SDIO_QMI;
+	else if (!strncmp(name, "SDIO_RMNT_TEST",
+			  strnlen("SDIO_RMNT_TEST", TEST_CH_NAME_SIZE)))
+		return SDIO_RMNT;
+	else if (!strncmp(name, "SDIO_DIAG_TEST",
+			  strnlen("SDIO_DIAG", TEST_CH_NAME_SIZE)))
+		return SDIO_DIAG;
+	else if (!strncmp(name, "SDIO_DUN_TEST",
+			  strnlen("SDIO_DUN_TEST", TEST_CH_NAME_SIZE)))
+		return SDIO_DUN;
+	else if (!strncmp(name, "SDIO_SMEM_TEST",
+			  strnlen("SDIO_SMEM_TEST", TEST_CH_NAME_SIZE)))
+		return SDIO_SMEM;
+	else if (!strncmp(name, "SDIO_CSVT_TEST",
+			  strnlen("SDIO_CSVT_TEST", TEST_CH_NAME_SIZE)))
+		return SDIO_CSVT;
+	else
+		return SDIO_MAX_CHANNELS;
+
+	return SDIO_MAX_CHANNELS;
+}
+
+/**
+ * Allocate and add SDIO_SMEM platform device
+ */
+#ifdef CONFIG_MSM_SDIO_SMEM
+static int add_sdio_smem(void)
+{
+	int ret = 0;
+
+	test_ctx->smem_pdev = platform_device_alloc("SDIO_SMEM", -1);
+	ret = platform_device_add(test_ctx->smem_pdev);
+	if (ret) {
+		pr_err(TEST_MODULE_NAME ": platform_device_add failed, "
+				   "ret=%d\n", ret);
+		return ret;
+	}
+	return 0;
+}
+#endif
+
+static int open_sdio_ch(struct test_channel *tch)
+{
+	int ret = 0;
+
+	if (!tch) {
+		pr_err(TEST_MODULE_NAME ": %s NULL tch\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!tch->ch_ready) {
+		TEST_DBG(TEST_MODULE_NAME ":openning channel %s\n",
+			tch->name);
+		if (tch->ch_id == SDIO_SMEM) {
+#ifdef CONFIG_MSM_SDIO_SMEM
+			if (!test_ctx->smem_pdev)
+				ret = add_sdio_smem();
+			else
+				ret = sdio_smem_open(test_ctx->sdio_smem);
+			if (ret) {
+				pr_err(TEST_MODULE_NAME
+					":openning channel %s failed\n",
+				tch->name);
+				tch->ch_ready = false;
+				return -EINVAL;
+			}
+#endif
+		} else {
+			tch->ch_ready = true;
+			ret = sdio_open(tch->name , &tch->ch, tch,
+					notify);
+			if (ret) {
+				pr_err(TEST_MODULE_NAME
+					":openning channel %s failed\n",
+				tch->name);
+				tch->ch_ready = false;
+				return -EINVAL;
+			}
+		}
+	}
+	return ret;
+}
+
+static int close_sdio_ch(struct test_channel *tch)
+{
+	int ret = 0;
+
+	if (!tch) {
+		pr_err(TEST_MODULE_NAME ": %s NULL tch\n", __func__);
+		return -EINVAL;
+	}
+
+	if (tch->ch_id == SDIO_SMEM) {
+#ifdef CONFIG_MSM_SDIO_SMEM
+		TEST_DBG(TEST_MODULE_NAME":%s closing channel %s",
+		       __func__, tch->name);
+		ret = sdio_smem_unregister_client();
+		test_ctx->smem_counter = 0;
+#endif
+	} else {
+		ret = sdio_close(tch->ch);
+	}
+
+	if (ret) {
+		pr_err(TEST_MODULE_NAME":%s close channel %s"
+				" failed\n", __func__, tch->name);
+	} else {
+		TEST_DBG(TEST_MODULE_NAME":%s close channel %s"
+				" success\n", __func__, tch->name);
+		tch->ch_ready = false;
+	}
+	return ret;
+}
+
+/**
+ * Config message
+ */
+
+static void send_config_msg(struct test_channel *test_ch)
+{
+	int ret = 0 ;
+	u32 write_avail = 0;
+	int size = sizeof(test_ch->config_msg);
+
+	pr_debug(TEST_MODULE_NAME "%s\n", __func__);
+
+	memcpy(test_ch->buf, (void *)&test_ch->config_msg, size);
+
+	if (test_ctx->exit_flag) {
+		pr_info(TEST_MODULE_NAME ":Exit Test.\n");
+		return;
+	}
+
+	pr_info(TEST_MODULE_NAME ":Sending the config message.\n");
+
+	/* wait for data ready event */
+	write_avail = sdio_write_avail(test_ch->ch);
+	pr_debug(TEST_MODULE_NAME ":write_avail=%d\n", write_avail);
+	if (write_avail < size) {
+		wait_event(test_ch->wait_q,
+			   atomic_read(&test_ch->tx_notify_count));
+		atomic_dec(&test_ch->tx_notify_count);
+	}
+
+	write_avail = sdio_write_avail(test_ch->ch);
+	pr_debug(TEST_MODULE_NAME ":write_avail=%d\n", write_avail);
+	if (write_avail < size) {
+		pr_info(TEST_MODULE_NAME ":not enough write avail.\n");
+		return;
+	}
+
+	ret = sdio_write(test_ch->ch, test_ch->buf, size);
+	if (ret)
+		pr_err(TEST_MODULE_NAME ":%s sdio_write err=%d.\n",
+			__func__, -ret);
+	else
+		pr_info(TEST_MODULE_NAME ":%s sent config_msg successfully.\n",
+		       __func__);
+}
+
+/**
+ * Loopback Test
+ */
+static void loopback_test(struct test_channel *test_ch)
+{
+	int ret = 0 ;
+	u32 read_avail = 0;
+	u32 write_avail = 0;
+
+	while (1) {
+
+		if (test_ctx->exit_flag) {
+			pr_info(TEST_MODULE_NAME ":Exit Test.\n");
+			return;
+		}
+
+		TEST_DBG(TEST_MODULE_NAME "--LOOPBACK WAIT FOR EVENT--.\n");
+		/* wait for data ready event */
+		wait_event(test_ch->wait_q,
+			   atomic_read(&test_ch->rx_notify_count));
+		atomic_dec(&test_ch->rx_notify_count);
+
+		read_avail = sdio_read_avail(test_ch->ch);
+		if (read_avail == 0)
+			continue;
+
+
+		write_avail = sdio_write_avail(test_ch->ch);
+		if (write_avail < read_avail) {
+			pr_info(TEST_MODULE_NAME
+				":not enough write avail.\n");
+			continue;
+		}
+
+		ret = sdio_read(test_ch->ch, test_ch->buf, read_avail);
+		if (ret) {
+			pr_info(TEST_MODULE_NAME
+			       ":worker, sdio_read err=%d.\n", -ret);
+			continue;
+		}
+		test_ch->rx_bytes += read_avail;
+
+		TEST_DBG(TEST_MODULE_NAME ":worker total rx bytes = 0x%x.\n",
+			 test_ch->rx_bytes);
+
+
+		ret = sdio_write(test_ch->ch,
+				 test_ch->buf, read_avail);
+		if (ret) {
+			pr_info(TEST_MODULE_NAME
+				":loopback sdio_write err=%d.\n",
+				-ret);
+			continue;
+		}
+		test_ch->tx_bytes += read_avail;
+
+		TEST_DBG(TEST_MODULE_NAME
+			 ":loopback total tx bytes = 0x%x.\n",
+			 test_ch->tx_bytes);
+	} /* end of while */
+}
+
+/**
+ * Check if all tests completed
+ */
+static void check_test_completion(void)
+{
+	int i;
+
+	for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
+		struct test_channel *tch = test_ctx->test_ch_arr[i];
+
+		if ((!tch) || (!tch->is_used) || (!tch->ch_ready))
+			continue;
+		if (!tch->test_completed) {
+			pr_info(TEST_MODULE_NAME ": %s - Channel %s test is "
+				"not completed", __func__, tch->name);
+			return;
+		}
+	}
+	pr_info(TEST_MODULE_NAME ": %s - Test is completed", __func__);
+	test_ctx->test_completed = 1;
+	wake_up(&test_ctx->wait_q);
+}
+
+static int pseudo_random_seed(unsigned int *seed_number)
+{
+	if (!seed_number)
+		return 0;
+
+	*seed_number = (unsigned int)(((unsigned long)*seed_number *
+				(unsigned long)1103515367) + 35757);
+	return (int)((*seed_number / (64*1024)) % 500);
+}
+
+/* this function must be locked before accessing it */
+static void lpm_test_update_entry(struct test_channel *tch,
+				  enum lpm_test_msg_type msg_type,
+				   char *msg_name,
+				  int counter)
+{
+	u32 index = 0;
+	static int print_full = 1;
+	struct sdio_test_device *test_device;
+
+	if (!tch) {
+		pr_err(TEST_MODULE_NAME ": %s - NULL test channel\n", __func__);
+		return;
+	}
+
+	test_device = tch->test_device;
+
+	if (!test_device) {
+		pr_err(TEST_MODULE_NAME ": %s - NULL test device\n", __func__);
+		return;
+	}
+
+	if (!test_device->lpm_arr) {
+		pr_err(TEST_MODULE_NAME ": %s - NULL lpm_arr\n", __func__);
+		return;
+	}
+
+	if (test_device->next_avail_entry_in_array >=
+					test_device->array_size) {
+		pr_err(TEST_MODULE_NAME ": %s - lpm array is full",
+			__func__);
+
+		if (print_full) {
+			print_hex_dump(KERN_INFO, TEST_MODULE_NAME ": lpm_arr:",
+				0, 32, 2,
+				(void *)test_device->lpm_arr,
+				sizeof(test_device->lpm_arr), false);
+			print_full = 0;
+		}
+		return;
+	}
+
+	index = test_device->next_avail_entry_in_array;
+	if ((msg_type == LPM_MSG_SEND) || (msg_type == LPM_MSG_REC))
+		test_device->lpm_arr[index].counter = counter;
+	else
+		test_device->lpm_arr[index].counter = 0;
+
+	test_device->lpm_arr[index].msg_type = msg_type;
+	memcpy(test_device->lpm_arr[index].msg_name, msg_name,
+	       LPM_MSG_NAME_SIZE);
+	test_device->lpm_arr[index].current_ms =
+		jiffies_to_msecs(get_jiffies_64());
+
+	test_device->lpm_arr[index].read_avail_mask =
+		test_device->read_avail_mask;
+
+	if ((msg_type == LPM_SLEEP) || (msg_type == LPM_WAKEUP))
+		memcpy(test_device->lpm_arr[index].chan_name, "DEVICE  ",
+		       CHANNEL_NAME_SIZE);
+	else
+		memcpy(test_device->lpm_arr[index].chan_name, tch->name,
+		       CHANNEL_NAME_SIZE);
+
+	test_device->next_avail_entry_in_array++;
+}
+
+static int wait_for_result_msg(struct test_channel *test_ch)
+{
+	u32 read_avail = 0;
+	int ret = 0;
+
+	pr_info(TEST_MODULE_NAME ": %s - START, channel %s\n",
+		__func__, test_ch->name);
+
+	while (1) {
+		read_avail = sdio_read_avail(test_ch->ch);
+
+		if (read_avail == 0) {
+			pr_info(TEST_MODULE_NAME
+				": read_avail is 0 for chan %s\n",
+				test_ch->name);
+			wait_event(test_ch->wait_q,
+				   atomic_read(&test_ch->rx_notify_count));
+			atomic_dec(&test_ch->rx_notify_count);
+			continue;
+		}
+
+		memset(test_ch->buf, 0x00, test_ch->buf_size);
+
+		ret = sdio_read(test_ch->ch, test_ch->buf, read_avail);
+		if (ret) {
+			pr_info(TEST_MODULE_NAME ":  sdio_read for chan"
+				"%s failed, err=%d.\n",
+				test_ch->name, -ret);
+			goto exit_err;
+		}
+
+		if (test_ch->buf[0] != TEST_CONFIG_SIGNATURE) {
+			pr_info(TEST_MODULE_NAME ": Not a test_result "
+				"signature. expected 0x%x. received 0x%x "
+				"for chan %s\n",
+				TEST_CONFIG_SIGNATURE,
+				test_ch->buf[0],
+				test_ch->name);
+			continue;
+		} else {
+			pr_info(TEST_MODULE_NAME ": Signature is "
+				"TEST_CONFIG_SIGNATURE as expected for"
+				"channel %s\n", test_ch->name);
+			break;
+		}
+	}
+
+	return test_ch->buf[1];
+
+exit_err:
+	return 0;
+}
+
+static void print_random_lpm_test_array(struct sdio_test_device *test_dev)
+{
+	int i;
+
+	if (!test_dev) {
+		pr_err(TEST_MODULE_NAME ": %s - NULL test device\n", __func__);
+		return;
+	}
+
+	for (i = 0 ; i < test_dev->next_avail_entry_in_array ; ++i) {
+		if (i == 0)
+			pr_err(TEST_MODULE_NAME ": index %4d, chan=%2s, "
+			       "code=%1d=%4s, msg#%1d, ms from before=-1, "
+			       "read_mask=0x%d, ms=%2u",
+			       i,
+			       test_dev->lpm_arr[i].chan_name,
+			       test_dev->lpm_arr[i].msg_type,
+			       test_dev->lpm_arr[i].msg_name,
+			       test_dev->lpm_arr[i].counter,
+			       test_dev->lpm_arr[i].read_avail_mask,
+			       test_dev->lpm_arr[i].current_ms);
+		else
+			pr_err(TEST_MODULE_NAME ": index "
+			       "%4d, %2s, code=%1d=%4s, msg#%1d, ms from "
+			       "before=%2u, read_mask=0x%d, ms=%2u",
+			       i,
+			       test_dev->lpm_arr[i].chan_name,
+			       test_dev->lpm_arr[i].msg_type,
+			       test_dev->lpm_arr[i].msg_name,
+			       test_dev->lpm_arr[i].counter,
+			       test_dev->lpm_arr[i].current_ms -
+			       test_dev->lpm_arr[i-1].current_ms,
+			       test_dev->lpm_arr[i].read_avail_mask,
+			       test_dev->lpm_arr[i].current_ms);
+
+		udelay(1000);
+	}
+}
+
+static int check_random_lpm_test_array(struct sdio_test_device *test_dev)
+{
+	int i = 0, j = 0;
+	unsigned int delta_ms = 0;
+	int arr_ind = 0;
+	int ret = 0;
+	int notify_counter = 0;
+	int sleep_counter = 0;
+	int wakeup_counter = 0;
+	int lpm_activity_counter = 0;
+
+	if (!test_dev) {
+		pr_err(TEST_MODULE_NAME ": %s - NULL test device\n", __func__);
+		return -ENODEV;
+	}
+
+	for (i = 0; i < test_dev->next_avail_entry_in_array; i++) {
+		notify_counter = 0;
+		sleep_counter = 0;
+		wakeup_counter = 0;
+
+		if ((test_dev->lpm_arr[i].msg_type == LPM_MSG_SEND) ||
+		     (test_dev->lpm_arr[i].msg_type == LPM_MSG_REC)) {
+			/* find the next message in the array */
+			arr_ind = test_dev->next_avail_entry_in_array;
+			for (j = i+1; j < arr_ind; j++) {
+				if ((test_dev->lpm_arr[j].msg_type ==
+				     LPM_MSG_SEND) ||
+				    (test_dev->lpm_arr[j].msg_type ==
+				     LPM_MSG_REC) ||
+				    (test_dev->lpm_arr[j].msg_type ==
+				     LPM_NOTIFY))
+					break;
+				if (test_dev->lpm_arr[j].msg_type ==
+				    LPM_SLEEP)
+					sleep_counter++;
+				if (test_dev->lpm_arr[j].msg_type ==
+				    LPM_WAKEUP)
+					wakeup_counter++;
+			}
+			if (j == arr_ind) {
+				ret = 0;
+				break;
+			}
+
+			delta_ms = test_dev->lpm_arr[j].current_ms -
+				test_dev->lpm_arr[i].current_ms;
+			if (delta_ms < 30) {
+				if ((sleep_counter == 0)
+				    && (wakeup_counter == 0)) {
+					continue;
+				} else {
+					pr_err(TEST_MODULE_NAME "%s: lpm "
+						"activity while delta is less "
+						"than 30, i=%d, j=%d, "
+						"sleep_counter=%d, "
+						"wakeup_counter=%d",
+					       __func__, i, j,
+					       sleep_counter, wakeup_counter);
+					ret = -ENODEV;
+					break;
+				}
+			} else {
+				if ((delta_ms > 90) &&
+				    (test_dev->lpm_arr[i].
+						read_avail_mask == 0)) {
+					if (j != i+3) {
+						pr_err(TEST_MODULE_NAME
+						       "%s: unexpected "
+						       "lpm activity "
+						       "while delta is "
+						       "bigger than "
+						       "90, i=%d, "
+						       "j=%d, "
+						       "notify_counter"
+						       "=%d",
+						       __func__, i, j,
+						       notify_counter);
+						ret = -ENODEV;
+						break;
+					}
+					lpm_activity_counter++;
+				}
+			}
+		}
+	}
+
+	pr_info(TEST_MODULE_NAME ": %s - lpm_activity_counter=%d",
+		__func__, lpm_activity_counter);
+
+	return ret;
+}
+
+static int lpm_test_main_task(void *ptr)
+{
+	u32 read_avail = 0;
+	int last_msg_index = 0;
+	struct test_channel *test_ch = (struct test_channel *)ptr;
+	struct sdio_test_device *test_dev;
+	struct lpm_msg lpm_msg;
+	int ret = 0;
+	int host_result = 0;
+
+	if (!test_ch) {
+		pr_err(TEST_MODULE_NAME ": %s - NULL channel\n", __func__);
+		return -ENODEV;
+	}
+
+	pr_err(TEST_MODULE_NAME ": %s - STARTED. channel %s\n",
+	       __func__, test_ch->name);
+
+	test_dev = test_ch->test_device;
+
+	if (!test_dev) {
+		pr_err(TEST_MODULE_NAME ": %s - NULL Test Device\n", __func__);
+		return -ENODEV;
+	}
+
+	while (last_msg_index < test_ch->config_msg.num_packets - 1) {
+
+		TEST_DBG(TEST_MODULE_NAME ": %s - "
+			"IN LOOP last_msg_index=%d\n",
+		       __func__, last_msg_index);
+
+		read_avail = sdio_read_avail(test_ch->ch);
+		if (read_avail == 0) {
+			TEST_DBG(TEST_MODULE_NAME
+					":read_avail 0 for chan %s, "
+					"wait for event\n",
+					test_ch->name);
+			wait_event(test_ch->wait_q,
+				   atomic_read(&test_ch->rx_notify_count));
+			atomic_dec(&test_ch->rx_notify_count);
+
+			read_avail = sdio_read_avail(test_ch->ch);
+			if (read_avail == 0) {
+				pr_err(TEST_MODULE_NAME
+					":read_avail size %d for chan %s not as"
+					" expected\n",
+					read_avail, test_ch->name);
+				continue;
+			}
+		}
+
+		memset(test_ch->buf, 0x00, sizeof(test_ch->buf));
+
+		ret = sdio_read(test_ch->ch, test_ch->buf, read_avail);
+		if (ret) {
+			pr_info(TEST_MODULE_NAME ":sdio_read for chan %s"
+				" err=%d.\n", test_ch->name, -ret);
+			goto exit_err;
+		}
+
+		memcpy((void *)&lpm_msg, test_ch->buf, sizeof(lpm_msg));
+
+		/*
+		 * when reading from channel, we want to turn off the bit
+		 * mask that implies that there is pending data on that channel
+		 */
+		if (test_ch->test_device != NULL) {
+			spin_lock_irqsave(&test_dev->lpm_array_lock,
+					  test_dev->lpm_array_lock_flags);
+
+			test_ch->notify_counter_per_chan--;
+
+			/*
+			 * if the channel has no pending data, turn off the
+			 * pending data bit mask of the channel
+			 */
+			if (test_ch->notify_counter_per_chan == 0) {
+				test_ch->test_device->read_avail_mask =
+					test_ch->test_device->read_avail_mask &
+					~test_ch->channel_mask_id;
+			}
+
+			last_msg_index = lpm_msg.counter;
+			lpm_test_update_entry(test_ch,
+					      LPM_MSG_REC,
+					      "RECEIVE",
+					      last_msg_index);
+
+			spin_unlock_irqrestore(&test_dev->lpm_array_lock,
+					       test_dev->lpm_array_lock_flags);
+		}
+	}
+
+	pr_info(TEST_MODULE_NAME ":%s: Finished to recieve all (%d) "
+		"packets from the modem %s. Waiting for result_msg",
+		__func__, test_ch->config_msg.num_packets, test_ch->name);
+
+	/* Wait for the resault message from the modem */
+	test_ch->modem_result_per_chan = wait_for_result_msg(test_ch);
+
+	/*
+	 * the DEVICE modem result is a failure if one of the channels on
+	 * that device, got modem_result = 0. this is why we bitwise "AND" each
+	 * time another channel completes its task
+	 */
+	test_dev->modem_result_per_dev &= test_ch->modem_result_per_chan;
+
+	/*
+	 * when reading from channel, we want to turn off the bit
+	 * mask that implies that there is pending data on that channel
+	 */
+	spin_lock_irqsave(&test_dev->lpm_array_lock,
+					  test_dev->lpm_array_lock_flags);
+
+	test_dev->open_channels_counter_to_recv--;
+
+	/* turning off the read_avail bit of the channel */
+	test_ch->test_device->read_avail_mask =
+		test_ch->test_device->read_avail_mask &
+		~test_ch->channel_mask_id;
+
+	spin_unlock_irqrestore(&test_dev->lpm_array_lock,
+					       test_dev->lpm_array_lock_flags);
+
+	/* Wait for all the packets to be sent to the modem */
+	while (1) {
+		spin_lock_irqsave(&test_dev->lpm_array_lock,
+				  test_dev->lpm_array_lock_flags);
+
+		if (test_ch->next_index_in_sent_msg_per_chan >=
+		    test_ch->config_msg.num_packets - 1) {
+
+			spin_unlock_irqrestore(&test_dev->lpm_array_lock,
+					       test_dev->lpm_array_lock_flags);
+			break;
+		} else {
+			pr_info(TEST_MODULE_NAME ":%s: Didn't finished to send "
+				"all packets, "
+				"next_index_in_sent_msg_per_chan = %d ",
+				__func__,
+				test_ch->next_index_in_sent_msg_per_chan);
+		}
+		spin_unlock_irqrestore(&test_dev->lpm_array_lock,
+				       test_dev->lpm_array_lock_flags);
+		msleep(60);
+	}
+
+	/*
+	 * if device has still open channels to test, then the test on the
+	 * device is still running but the test on current channel is completed
+	 */
+	if (test_dev->open_channels_counter_to_recv != 0 ||
+	    test_dev->open_channels_counter_to_send != 0) {
+		test_ch->test_completed = 1;
+		return 0;
+	} else {
+		test_ctx->number_of_active_devices--;
+		sdio_al_unregister_lpm_cb(test_ch->sdio_al_device);
+
+		if (test_ch->test_type == SDIO_TEST_LPM_RANDOM)
+			host_result = check_random_lpm_test_array(test_dev);
+
+		if (host_result ||
+		    !test_dev->modem_result_per_dev ||
+		    test_ctx->runtime_debug)
+			print_random_lpm_test_array(test_dev);
+
+		pr_info(TEST_MODULE_NAME ": %s - host_result=%d.(0 for "
+			"SUCCESS) device_modem_result=%d (1 for SUCCESS)",
+			__func__, host_result, test_dev->modem_result_per_dev);
+
+		test_ch->test_completed = 1;
+		if (test_dev->modem_result_per_dev && !host_result) {
+			pr_info(TEST_MODULE_NAME ": %s - Random LPM "
+				"TEST_PASSED for device %d of %d\n",
+				__func__,
+				(test_ctx->max_number_of_devices-
+				test_ctx->number_of_active_devices),
+				test_ctx->max_number_of_devices);
+			test_dev->final_result_per_dev = 1; /* PASSED */
+		} else {
+			pr_info(TEST_MODULE_NAME ": %s - Random LPM "
+				"TEST_FAILED for device %d of %d\n",
+				__func__,
+				(test_ctx->max_number_of_devices-
+				test_ctx->number_of_active_devices),
+				test_ctx->max_number_of_devices);
+			test_dev->final_result_per_dev = 0; /* FAILED */
+		}
+
+		check_test_completion();
+
+		kfree(test_ch->test_device->lpm_arr);
+
+		return 0;
+	}
+
+exit_err:
+	pr_info(TEST_MODULE_NAME ": TEST FAIL for chan %s.\n",
+		test_ch->name);
+	test_ch->test_completed = 1;
+	test_dev->open_channels_counter_to_recv--;
+	test_dev->next_avail_entry_in_array = 0;
+	test_ch->next_index_in_sent_msg_per_chan = 0;
+	test_ch->test_result = TEST_FAILED;
+	check_test_completion();
+	return -ENODEV;
+}
+
+static int lpm_test_create_read_thread(struct test_channel *test_ch)
+{
+	struct sdio_test_device *test_dev;
+
+	pr_info(TEST_MODULE_NAME ": %s - STARTED channel %s\n",
+		__func__, test_ch->name);
+
+	if (!test_ch) {
+		pr_err(TEST_MODULE_NAME ": %s - NULL test channel\n", __func__);
+		return -ENODEV;
+	}
+
+	test_dev = test_ch->test_device;
+
+	if (!test_dev) {
+		pr_err(TEST_MODULE_NAME ": %s - NULL test device\n", __func__);
+		return -ENODEV;
+	}
+
+	test_dev->lpm_test_task.task_name = SDIO_LPM_TEST;
+
+	test_dev->lpm_test_task.lpm_task =
+		kthread_create(lpm_test_main_task,
+			       (void *)(test_ch),
+			       test_dev->lpm_test_task.task_name);
+
+	if (IS_ERR(test_dev->lpm_test_task.lpm_task)) {
+		pr_err(TEST_MODULE_NAME ": %s - kthread_create() failed\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	wake_up_process(test_dev->lpm_test_task.lpm_task);
+
+	return 0;
+}
+
+static void lpm_continuous_rand_test(struct test_channel *test_ch)
+{
+	unsigned int local_ms = 0;
+	int ret = 0;
+	unsigned int write_avail = 0;
+	struct sdio_test_device *test_dev;
+
+	pr_info(MODULE_NAME ": %s - STARTED\n", __func__);
+
+	if (!test_ch) {
+		pr_err(TEST_MODULE_NAME ": %s - NULL channel\n", __func__);
+		return;
+	}
+
+	test_dev = test_ch->test_device;
+
+	if (!test_dev) {
+		pr_err(TEST_MODULE_NAME ": %s - NULL Test Device\n", __func__);
+		return;
+	}
+
+	ret = lpm_test_create_read_thread(test_ch);
+	if (ret != 0) {
+		pr_err(TEST_MODULE_NAME ": %s - failed to create lpm reading "
+		       "thread", __func__);
+	}
+
+	while (1) {
+
+		struct lpm_msg msg;
+		u32 ret = 0;
+
+		/* sleeping period is dependent on number of open channels */
+		test_ch->config_msg.test_param =
+				test_ctx->lpm_pseudo_random_seed;
+
+		local_ms = test_dev->open_channels_counter_to_send *
+			test_ctx->lpm_pseudo_random_seed;
+		TEST_DBG(TEST_MODULE_NAME ":%s: SLEEPING for %d ms",
+		       __func__, local_ms);
+		msleep(local_ms);
+
+		msg.counter = test_ch->next_index_in_sent_msg_per_chan;
+		msg.signature = LPM_TEST_CONFIG_SIGNATURE;
+		msg.reserve1 = 0;
+		msg.reserve2 = 0;
+
+		/* wait for data ready event */
+		write_avail = sdio_write_avail(test_ch->ch);
+		pr_debug(TEST_MODULE_NAME ": %s: write_avail=%d\n",
+		       __func__, write_avail);
+		if (write_avail < sizeof(msg)) {
+			wait_event(test_ch->wait_q,
+				   atomic_read(&test_ch->tx_notify_count));
+			atomic_dec(&test_ch->tx_notify_count);
+		}
+
+		write_avail = sdio_write_avail(test_ch->ch);
+		if (write_avail < sizeof(msg)) {
+			pr_info(TEST_MODULE_NAME ": %s: not enough write "
+				"avail.\n", __func__);
+			break;
+		}
+
+		ret = sdio_write(test_ch->ch, (u32 *)&msg, sizeof(msg));
+		if (ret)
+			pr_err(TEST_MODULE_NAME ":%s: sdio_write err=%d.\n",
+				__func__, -ret);
+
+		TEST_DBG(TEST_MODULE_NAME ": %s: for chan %s, write, "
+			 "msg # %d\n",
+			 __func__,
+			 test_ch->name,
+			 test_ch->next_index_in_sent_msg_per_chan);
+
+		if (test_ch->test_type == SDIO_TEST_LPM_RANDOM) {
+			spin_lock_irqsave(&test_dev->lpm_array_lock,
+					  test_dev->lpm_array_lock_flags);
+			lpm_test_update_entry(test_ch, LPM_MSG_SEND,
+					      "SEND  ",
+					      test_ch->
+					      next_index_in_sent_msg_per_chan);
+
+			test_ch->next_index_in_sent_msg_per_chan++;
+
+			if (test_ch->next_index_in_sent_msg_per_chan ==
+			    test_ch->config_msg.num_packets) {
+				spin_unlock_irqrestore(
+				    &test_dev->lpm_array_lock,
+				    test_dev->lpm_array_lock_flags);
+				break;
+			}
+
+			spin_unlock_irqrestore(&test_dev->lpm_array_lock,
+					       test_dev->lpm_array_lock_flags);
+		}
+	}
+
+	spin_lock_irqsave(&test_dev->lpm_array_lock,
+				  test_dev->lpm_array_lock_flags);
+	test_dev->open_channels_counter_to_send--;
+	spin_unlock_irqrestore(&test_dev->lpm_array_lock,
+				       test_dev->lpm_array_lock_flags);
+
+	pr_info(TEST_MODULE_NAME ": %s: - Finished to send all (%d) "
+		"packets to the modem on channel %s",
+		__func__, test_ch->config_msg.num_packets, test_ch->name);
+
+	return;
+}
+
+static void lpm_test(struct test_channel *test_ch)
+{
+	pr_info(TEST_MODULE_NAME ": %s - START channel %s\n", __func__,
+		test_ch->name);
+
+	if (!test_ch) {
+		pr_err(TEST_MODULE_NAME ": %s - NULL test channel\n", __func__);
+		return;
+	}
+
+	test_ch->modem_result_per_chan = wait_for_result_msg(test_ch);
+	pr_debug(TEST_MODULE_NAME ": %s - delete the timeout timer\n",
+	       __func__);
+	del_timer_sync(&test_ch->timeout_timer);
+
+	if (test_ch->modem_result_per_chan == 0) {
+		pr_err(TEST_MODULE_NAME ": LPM TEST - Client didn't sleep. "
+		       "Result Msg - is_successful=%d\n", test_ch->buf[1]);
+		goto exit_err;
+	} else {
+		pr_info(TEST_MODULE_NAME ": %s -"
+			"LPM 9K WAS SLEEPING - PASS\n", __func__);
+		if (test_ch->test_result == TEST_PASSED) {
+			pr_info(TEST_MODULE_NAME ": LPM TEST_PASSED\n");
+			test_ch->test_completed = 1;
+			check_test_completion();
+		} else {
+			pr_err(TEST_MODULE_NAME ": LPM TEST - Host didn't "
+			       "sleep. Client slept\n");
+			goto exit_err;
+		}
+	}
+
+	return;
+
+exit_err:
+	pr_info(TEST_MODULE_NAME ": TEST FAIL for chan %s.\n",
+		test_ch->name);
+	test_ch->test_completed = 1;
+	test_ch->test_result = TEST_FAILED;
+	check_test_completion();
+	return;
+}
+
+
+/**
+ * LPM Test while the host wakes up the modem
+ */
+static void lpm_test_host_waker(struct test_channel *test_ch)
+{
+	pr_info(TEST_MODULE_NAME ": %s - START\n", __func__);
+	wait_event(test_ch->wait_q, atomic_read(&test_ch->wakeup_client));
+	atomic_set(&test_ch->wakeup_client, 0);
+
+	pr_info(TEST_MODULE_NAME ": %s - Sending the config_msg to wakeup "
+		" the client\n", __func__);
+	send_config_msg(test_ch);
+
+	lpm_test(test_ch);
+}
+
+/**
+  * Writes number of packets into test channel
+  * @test_ch: test channel control struct
+  * @burst_size: number of packets to send
+  */
+static int write_packet_burst(struct test_channel *test_ch,
+		int burst_size)
+{
+	int ret = 0;
+	int packet_count = 0;
+	unsigned int random_num = 0;
+	int size = test_ch->packet_length; /* first packet size */
+	u32 write_avail = 0;
+
+	while (packet_count < burst_size) {
+		/* wait for data ready event */
+		write_avail = sdio_write_avail(test_ch->ch);
+		TEST_DBG(TEST_MODULE_NAME ":%s write_avail=%d,size=%d on chan"
+				" %s\n", __func__,
+				write_avail, size, test_ch->name);
+		if (write_avail < size) {
+			TEST_DBG(TEST_MODULE_NAME ":%s wait for event on"
+					" chan %s\n", __func__, test_ch->name);
+			wait_event(test_ch->wait_q,
+					atomic_read(&test_ch->tx_notify_count));
+			atomic_dec(&test_ch->tx_notify_count);
+		}
+		write_avail = sdio_write_avail(test_ch->ch);
+		if (write_avail < size) {
+			pr_info(TEST_MODULE_NAME ":%s not enough write"
+					" avail %d, need %d on chan %s\n",
+					__func__, write_avail, size,
+					test_ch->name);
+			continue;
+		}
+		ret = sdio_write(test_ch->ch, test_ch->buf, size);
+		if (ret) {
+			pr_err(TEST_MODULE_NAME ":%s sdio_write "
+					"failed (%d) on chan %s\n", __func__,
+					ret, test_ch->name);
+			break;
+		}
+		udelay(1000); /*low bus usage while running number of channels*/
+		TEST_DBG(TEST_MODULE_NAME ":%s() successfully write %d bytes"
+				", packet_count=%d on chan %s\n", __func__,
+				size, packet_count, test_ch->name);
+		test_ch->tx_bytes += size;
+		packet_count++;
+		/* get next packet size */
+		random_num = get_random_int();
+		size = (random_num % test_ch->packet_length) + 1;
+	}
+	return ret;
+}
+
+/**
+  * Reads packet from test channel and checks that packet number
+  * encoded into the packet is equal to packet_counter
+  * This function is applicable for packet mode channels only
+  *
+  * @test_ch: test channel
+  * @size: expected packet size
+  * @packet_counter: number to validate readed packet
+  */
+static int read_data_from_packet_ch(struct test_channel *test_ch,
+				unsigned int size,
+				int packet_counter)
+{
+	u32 read_avail = 0;
+	int ret = 0;
+
+	if (!test_ch || !test_ch->ch) {
+		pr_err(TEST_MODULE_NAME
+				":%s: NULL channel\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!test_ch->ch->is_packet_mode) {
+		pr_err(TEST_MODULE_NAME
+				":%s:not packet mode ch %s\n",
+				__func__, test_ch->name);
+		return -EINVAL;
+	}
+	read_avail = sdio_read_avail(test_ch->ch);
+	/* wait for read data ready event */
+	if (read_avail < size) {
+		TEST_DBG(TEST_MODULE_NAME ":%s() wait for rx data on "
+				"chan %s\n", __func__, test_ch->name);
+		wait_event(test_ch->wait_q,
+				atomic_read(&test_ch->rx_notify_count));
+		atomic_dec(&test_ch->rx_notify_count);
+	}
+	read_avail = sdio_read_avail(test_ch->ch);
+	TEST_DBG(TEST_MODULE_NAME ":%s read_avail=%d bytes on chan %s\n",
+			__func__, read_avail, test_ch->name);
+
+	if (read_avail != size) {
+		pr_err(TEST_MODULE_NAME
+				":read_avail size %d for chan %s not as "
+				"expected size %d\n",
+				read_avail, test_ch->name, size);
+		return -EINVAL;
+	}
+
+	ret = sdio_read(test_ch->ch, test_ch->buf, read_avail);
+	if (ret) {
+		pr_err(TEST_MODULE_NAME ":%s() sdio_read for chan %s (%d)\n",
+				__func__, test_ch->name, -ret);
+		return ret;
+	}
+	if ((test_ch->buf[0] != packet_counter) && (size != 1)) {
+		pr_err(TEST_MODULE_NAME ":Read WRONG DATA"
+				" for chan %s, size=%d\n",
+				test_ch->name, size);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+
+/**
+  * Reads packet from test channel and checks that packet number
+  * encoded into the packet is equal to packet_counter
+  * This function is applicable for streaming mode channels only
+  *
+  * @test_ch: test channel
+  * @size: expected packet size
+  * @packet_counter: number to validate readed packet
+  */
+static int read_data_from_stream_ch(struct test_channel *test_ch,
+				unsigned int size,
+				int packet_counter)
+{
+	u32 read_avail = 0;
+	int ret = 0;
+
+	if (!test_ch || !test_ch->ch) {
+		pr_err(TEST_MODULE_NAME
+				":%s: NULL channel\n", __func__);
+		return -EINVAL;
+	}
+
+	if (test_ch->ch->is_packet_mode) {
+		pr_err(TEST_MODULE_NAME
+				":%s:not streaming mode ch %s\n",
+				__func__, test_ch->name);
+		return -EINVAL;
+	}
+	read_avail = sdio_read_avail(test_ch->ch);
+	/* wait for read data ready event */
+	if (read_avail < size) {
+		TEST_DBG(TEST_MODULE_NAME ":%s() wait for rx data on "
+				"chan %s\n", __func__, test_ch->name);
+		wait_event(test_ch->wait_q,
+				atomic_read(&test_ch->rx_notify_count));
+		atomic_dec(&test_ch->rx_notify_count);
+	}
+	read_avail = sdio_read_avail(test_ch->ch);
+	TEST_DBG(TEST_MODULE_NAME ":%s read_avail=%d bytes on chan %s\n",
+			__func__, read_avail, test_ch->name);
+
+	if (read_avail < size) {
+		pr_err(TEST_MODULE_NAME
+				":read_avail size %d for chan %s not as "
+				"expected size %d\n",
+				read_avail, test_ch->name, size);
+		return -EINVAL;
+	}
+
+	ret = sdio_read(test_ch->ch, test_ch->buf, size + A2_HEADER_OVERHEAD);
+	if (ret) {
+		pr_err(TEST_MODULE_NAME ":%s() sdio_read for chan %s (%d)\n",
+				__func__, test_ch->name, -ret);
+		return ret;
+	}
+	if ((test_ch->buf[A2_HEADER_OVERHEAD/4] != packet_counter) &&
+	    (size != 1)) {
+		pr_err(TEST_MODULE_NAME ":Read WRONG DATA"
+				" for chan %s, size=%d, packet_counter=%d\n",
+				test_ch->name, size, packet_counter);
+		print_hex_dump(KERN_INFO, TEST_MODULE_NAME ": rmnet:",
+				0, 32, 2,
+				(void *)test_ch->buf,
+				size + A2_HEADER_OVERHEAD, false);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/**
+ *   Test close channel feature for SDIO_SMEM channel:
+ *   close && re-open the SDIO_SMEM channel.
+ */
+#ifdef CONFIG_MSM_SDIO_SMEM
+static void open_close_smem_test(struct test_channel *test_ch)
+{
+	int i = 0;
+	int ret = 0;
+
+	pr_info(TEST_MODULE_NAME ":%s\n", __func__);
+
+	for (i = 0; i < 100 ; ++i) {
+		ret = close_sdio_ch(test_ch);
+		if (ret) {
+			pr_err(TEST_MODULE_NAME ":%s close_sdio_ch for ch %s"
+						" failed\n",
+						__func__, test_ch->name);
+			goto exit_err;
+		}
+		ret = open_sdio_ch(test_ch);
+		if (ret) {
+			pr_err(TEST_MODULE_NAME ":%s open_sdio_ch for ch %s "
+						" failed\n",
+						__func__, test_ch->name);
+			goto exit_err;
+		}
+	}
+
+	pr_info(TEST_MODULE_NAME ":%s TEST PASS for chan %s.\n", __func__,
+			test_ch->name);
+	test_ch->test_completed = 1;
+	test_ch->test_result = TEST_PASSED;
+	check_test_completion();
+	return;
+exit_err:
+	pr_info(TEST_MODULE_NAME ":%s TEST FAIL for chan %s.\n", __func__,
+			test_ch->name);
+	test_ch->test_completed = 1;
+	test_ch->test_result = TEST_FAILED;
+	check_test_completion();
+	return;
+}
+#endif
+
+/**
+ *   Test close channel feature:
+ *   1. write random packet number into channel
+ *   2. read some data from channel (do this only for second half of
+ *   requested packets to send).
+ *   3. close && re-open then repeat 1.
+ *
+ *   Total packets to send: test_ch->config_msg.num_packets.
+ *   Burst size is random in [1..test_ch->max_burst_size] range
+ *   Packet size is random in [1..test_ch->packet_length]
+ */
+static void open_close_test(struct test_channel *test_ch)
+{
+	int ret = 0;
+	u32 read_avail = 0;
+	int total_packet_count = 0;
+	int size = 0;
+	u16 *buf16 = NULL;
+	int i;
+	int max_packet_count = 0;
+	unsigned int random_num = 0;
+	int curr_burst_size = 0;
+
+	if (!test_ch || !test_ch->ch) {
+		pr_err(TEST_MODULE_NAME ":%s NULL channel\n",
+				__func__);
+		return;
+	}
+
+	curr_burst_size = test_ch->max_burst_size;
+	size = test_ch->packet_length;
+	buf16 = (u16 *) test_ch->buf;
+
+	/* the test sends configured number of packets in
+	   2 portions: first without reading between write bursts,
+	   second with it */
+	max_packet_count = test_ch->config_msg.num_packets / 2;
+
+	pr_info(TEST_MODULE_NAME ":%s channel %s, total packets:%d,"
+			" max packet size %d, max burst size:%d\n",
+			__func__, test_ch->name,
+			test_ch->config_msg.num_packets, test_ch->packet_length,
+			test_ch->max_burst_size);
+	for (i = 0 ; i < size / 2 ; i++)
+		buf16[i] = (u16) (i & 0xFFFF);
+
+	for (i = 0; i < 2 ; i++) {
+		total_packet_count = 0;
+		while (total_packet_count < max_packet_count) {
+			if (test_ctx->exit_flag) {
+				pr_info(TEST_MODULE_NAME ":%s exit test\n",
+						__func__);
+				return;
+			}
+			test_ch->buf[0] = total_packet_count;
+			random_num = get_random_int();
+			curr_burst_size = (random_num %
+					test_ch->max_burst_size) + 1;
+
+			/* limit burst size to send
+			 * no more than configured packets */
+			if (curr_burst_size + total_packet_count >
+					max_packet_count) {
+				curr_burst_size = max_packet_count -
+					total_packet_count;
+			}
+			TEST_DBG(TEST_MODULE_NAME ":%s Current burst size:%d"
+					" on chan %s\n", __func__,
+					curr_burst_size, test_ch->name);
+			ret = write_packet_burst(test_ch, curr_burst_size);
+			if (ret) {
+				pr_err(TEST_MODULE_NAME ":%s write burst failed (%d), ch %s\n",
+						__func__, ret, test_ch->name);
+				goto exit_err;
+			}
+			if (i > 0) {
+				/* read from channel */
+				if (test_ch->ch->is_packet_mode)
+					ret = read_data_from_packet_ch(test_ch,
+							size,
+							total_packet_count);
+				else
+					ret = read_data_from_stream_ch(test_ch,
+							size,
+							total_packet_count);
+				if (ret) {
+					pr_err(TEST_MODULE_NAME ":%s read"
+							" failed:%d, chan %s\n",
+							__func__, ret,
+							test_ch->name);
+					goto exit_err;
+				}
+			}
+			TEST_DBG(TEST_MODULE_NAME ":%s before close, ch %s\n",
+					__func__, test_ch->name);
+			ret = close_sdio_ch(test_ch);
+			if (ret) {
+				pr_err(TEST_MODULE_NAME":%s close channel %s"
+						" failed (%d)\n",
+						__func__, test_ch->name, ret);
+				goto exit_err;
+			} else {
+				TEST_DBG(TEST_MODULE_NAME":%s close channel %s"
+						" success\n", __func__,
+						test_ch->name);
+				total_packet_count += curr_burst_size;
+				atomic_set(&test_ch->rx_notify_count, 0);
+				atomic_set(&test_ch->tx_notify_count, 0);
+				atomic_set(&test_ch->any_notify_count, 0);
+			}
+			TEST_DBG(TEST_MODULE_NAME ":%s before open, ch %s\n",
+					__func__, test_ch->name);
+			ret = open_sdio_ch(test_ch);
+			if (ret) {
+				pr_err(TEST_MODULE_NAME":%s open channel %s"
+						" failed (%d)\n",
+						__func__, test_ch->name, ret);
+				goto exit_err;
+			} else {
+				read_avail = sdio_read_avail(test_ch->ch);
+				if (read_avail > 0) {
+					pr_err(TEST_MODULE_NAME": after open"
+						" ch %s read_availis not zero"
+						" (%d bytes)\n",
+						test_ch->name, read_avail);
+					goto exit_err;
+				}
+			}
+			TEST_DBG(TEST_MODULE_NAME ":%s total tx = %d,"
+					" packet# = %d, size = %d for ch %s\n",
+					__func__, test_ch->tx_bytes,
+					total_packet_count, size,
+					test_ch->name);
+		} /* end of while */
+	}
+	pr_info(TEST_MODULE_NAME ":%s Test end: total rx bytes = 0x%x,"
+			" total tx bytes = 0x%x for chan %s\n", __func__,
+			test_ch->rx_bytes, test_ch->tx_bytes, test_ch->name);
+	pr_info(TEST_MODULE_NAME ":%s TEST PASS for chan %s.\n", __func__,
+			test_ch->name);
+	test_ch->test_completed = 1;
+	test_ch->test_result = TEST_PASSED;
+	check_test_completion();
+	return;
+exit_err:
+	pr_info(TEST_MODULE_NAME ":%s TEST FAIL for chan %s.\n", __func__,
+			test_ch->name);
+	test_ch->test_completed = 1;
+	test_ch->test_result = TEST_FAILED;
+	check_test_completion();
+	return;
+}
+
+/**
+ * sender Test
+ */
+static void sender_test(struct test_channel *test_ch)
+{
+	int ret = 0 ;
+	u32 read_avail = 0;
+	u32 write_avail = 0;
+	int packet_count = 0;
+	int size = 512;
+	u16 *buf16 = (u16 *) test_ch->buf;
+	int i;
+	int max_packet_count = 10000;
+	int random_num = 0;
+
+	max_packet_count = test_ch->config_msg.num_packets;
+
+	for (i = 0 ; i < size / 2 ; i++)
+		buf16[i] = (u16) (i & 0xFFFF);
+
+
+	pr_info(TEST_MODULE_NAME
+		 ":SENDER TEST START for chan %s\n", test_ch->name);
+
+	while (packet_count < max_packet_count) {
+
+		if (test_ctx->exit_flag) {
+			pr_info(TEST_MODULE_NAME ":Exit Test.\n");
+			return;
+		}
+
+		random_num = get_random_int();
+		size = (random_num % test_ch->packet_length) + 1;
+
+		TEST_DBG(TEST_MODULE_NAME "SENDER WAIT FOR EVENT for chan %s\n",
+			test_ch->name);
+
+		/* wait for data ready event */
+		write_avail = sdio_write_avail(test_ch->ch);
+		TEST_DBG(TEST_MODULE_NAME ":write_avail=%d\n", write_avail);
+		if (write_avail < size) {
+			wait_event(test_ch->wait_q,
+				   atomic_read(&test_ch->tx_notify_count));
+			atomic_dec(&test_ch->tx_notify_count);
+		}
+
+		write_avail = sdio_write_avail(test_ch->ch);
+		TEST_DBG(TEST_MODULE_NAME ":write_avail=%d\n", write_avail);
+		if (write_avail < size) {
+			pr_info(TEST_MODULE_NAME ":not enough write avail.\n");
+			continue;
+		}
+
+		test_ch->buf[0] = packet_count;
+
+		ret = sdio_write(test_ch->ch, test_ch->buf, size);
+		if (ret) {
+			pr_info(TEST_MODULE_NAME ":sender sdio_write err=%d.\n",
+				-ret);
+			goto exit_err;
+		}
+
+		/* wait for read data ready event */
+		TEST_DBG(TEST_MODULE_NAME ":sender wait for rx data for "
+					  "chan %s\n",
+			 test_ch->name);
+		read_avail = sdio_read_avail(test_ch->ch);
+		wait_event(test_ch->wait_q,
+			   atomic_read(&test_ch->rx_notify_count));
+		atomic_dec(&test_ch->rx_notify_count);
+
+		read_avail = sdio_read_avail(test_ch->ch);
+
+		if (read_avail != size) {
+			pr_info(TEST_MODULE_NAME
+				":read_avail size %d for chan %s not as "
+				"expected size %d.\n",
+				read_avail, test_ch->name, size);
+			goto exit_err;
+		}
+
+		memset(test_ch->buf, 0x00, size);
+
+		ret = sdio_read(test_ch->ch, test_ch->buf, size);
+		if (ret) {
+			pr_info(TEST_MODULE_NAME ":sender sdio_read for chan %s"
+						 " err=%d.\n",
+				test_ch->name, -ret);
+			goto exit_err;
+		}
+
+
+		if ((test_ch->buf[0] != packet_count) && (size != 1)) {
+			pr_info(TEST_MODULE_NAME ":sender sdio_read WRONG DATA"
+						 " for chan %s, size=%d\n",
+				test_ch->name, size);
+			goto exit_err;
+		}
+
+		test_ch->tx_bytes += size;
+		test_ch->rx_bytes += size;
+		packet_count++;
+
+		TEST_DBG(TEST_MODULE_NAME
+			 ":sender total rx bytes = 0x%x , packet#=%d, size=%d"
+			 " for chan %s\n",
+			 test_ch->rx_bytes, packet_count, size, test_ch->name);
+		TEST_DBG(TEST_MODULE_NAME
+			 ":sender total tx bytes = 0x%x , packet#=%d, size=%d"
+			 " for chan %s\n",
+			 test_ch->tx_bytes, packet_count, size, test_ch->name);
+
+	} /* end of while */
+
+	pr_info(TEST_MODULE_NAME
+		 ":SENDER TEST END: total rx bytes = 0x%x, "
+		 " total tx bytes = 0x%x for chan %s\n",
+		 test_ch->rx_bytes, test_ch->tx_bytes, test_ch->name);
+
+	pr_info(TEST_MODULE_NAME ": TEST PASS for chan %s.\n",
+		test_ch->name);
+	test_ch->test_completed = 1;
+	test_ch->test_result = TEST_PASSED;
+	check_test_completion();
+	return;
+
+exit_err:
+	pr_info(TEST_MODULE_NAME ": TEST FAIL for chan %s.\n",
+		test_ch->name);
+	test_ch->test_completed = 1;
+	test_ch->test_result = TEST_FAILED;
+	check_test_completion();
+	return;
+}
+
+/**
+ * A2 Perf Test
+ */
+static void a2_performance_test(struct test_channel *test_ch)
+{
+	int ret = 0 ;
+	u32 read_avail = 0;
+	u32 write_avail = 0;
+	int tx_packet_count = 0;
+	int rx_packet_count = 0;
+	int size = 0;
+	u16 *buf16 = (u16 *) test_ch->buf;
+	int i;
+	int total_bytes = 0;
+	int max_packets = 10000;
+	u32 packet_size = test_ch->buf_size;
+	int rand_size = 0;
+
+	u64 start_jiffy, end_jiffy, delta_jiffies;
+	unsigned int time_msec = 0;
+	u32 throughput = 0;
+
+	max_packets = test_ch->config_msg.num_packets;
+	packet_size = test_ch->packet_length;
+
+	for (i = 0; i < packet_size / 2; i++)
+		buf16[i] = (u16) (i & 0xFFFF);
+
+	pr_info(TEST_MODULE_NAME ": A2 PERFORMANCE TEST START for chan %s\n",
+		test_ch->name);
+
+	start_jiffy = get_jiffies_64(); /* read the current time */
+
+	while (tx_packet_count < max_packets) {
+
+		if (test_ctx->exit_flag) {
+			pr_info(TEST_MODULE_NAME ":Exit Test.\n");
+			return;
+		}
+
+		if (test_ch->random_packet_size) {
+			rand_size = get_random_int();
+			packet_size = (rand_size % test_ch->packet_length) + 1;
+			if (packet_size < A2_MIN_PACKET_SIZE)
+				packet_size = A2_MIN_PACKET_SIZE;
+		}
+
+		/* wait for data ready event */
+		/* use a func to avoid compiler optimizations */
+		write_avail = sdio_write_avail(test_ch->ch);
+		read_avail = sdio_read_avail(test_ch->ch);
+		TEST_DBG(TEST_MODULE_NAME ":channel %s, write_avail=%d, "
+					 "read_avail=%d for chan %s\n",
+			test_ch->name, write_avail, read_avail,
+			test_ch->name);
+		if ((write_avail == 0) && (read_avail == 0)) {
+			wait_event(test_ch->wait_q,
+				   atomic_read(&test_ch->any_notify_count));
+			atomic_set(&test_ch->any_notify_count, 0);
+		}
+
+		write_avail = sdio_write_avail(test_ch->ch);
+		TEST_DBG(TEST_MODULE_NAME ":channel %s, write_avail=%d\n",
+			 test_ch->name, write_avail);
+		if (write_avail > 0) {
+			size = min(packet_size, write_avail) ;
+			TEST_DBG(TEST_MODULE_NAME ":tx size = %d for chan %s\n",
+				 size, test_ch->name);
+			test_ch->buf[0] = tx_packet_count;
+			test_ch->buf[(size/4)-1] = tx_packet_count;
+
+			ret = sdio_write(test_ch->ch, test_ch->buf, size);
+			if (ret) {
+				pr_info(TEST_MODULE_NAME ":sdio_write err=%d"
+							 " for chan %s\n",
+					-ret, test_ch->name);
+				goto exit_err;
+			}
+			tx_packet_count++;
+			test_ch->tx_bytes += size;
+		}
+
+		read_avail = sdio_read_avail(test_ch->ch);
+		TEST_DBG(TEST_MODULE_NAME ":channel %s, read_avail=%d\n",
+			 test_ch->name, read_avail);
+		if (read_avail > 0) {
+			size = min(packet_size, read_avail);
+			pr_debug(TEST_MODULE_NAME ":rx size = %d.\n", size);
+			ret = sdio_read(test_ch->ch, test_ch->buf, size);
+			if (ret) {
+				pr_info(TEST_MODULE_NAME ": sdio_read size %d "
+							 " err=%d"
+							 " for chan %s\n",
+					size, -ret, test_ch->name);
+				goto exit_err;
+			}
+			rx_packet_count++;
+			test_ch->rx_bytes += size;
+		}
+
+		TEST_DBG(TEST_MODULE_NAME
+			 ":total rx bytes = %d , rx_packet#=%d"
+			 " for chan %s\n",
+			 test_ch->rx_bytes, rx_packet_count, test_ch->name);
+		TEST_DBG(TEST_MODULE_NAME
+			 ":total tx bytes = %d , tx_packet#=%d"
+			 " for chan %s\n",
+			 test_ch->tx_bytes, tx_packet_count, test_ch->name);
+
+	} /* while (tx_packet_count < max_packets ) */
+
+	end_jiffy = get_jiffies_64(); /* read the current time */
+
+	delta_jiffies = end_jiffy - start_jiffy;
+	time_msec = jiffies_to_msecs(delta_jiffies);
+
+	pr_info(TEST_MODULE_NAME ":total rx bytes = 0x%x , rx_packet#=%d for"
+				 " chan %s.\n",
+		test_ch->rx_bytes, rx_packet_count, test_ch->name);
+	pr_info(TEST_MODULE_NAME ":total tx bytes = 0x%x , tx_packet#=%d"
+				 " for chan %s.\n",
+		test_ch->tx_bytes, tx_packet_count, test_ch->name);
+
+	total_bytes = (test_ch->tx_bytes + test_ch->rx_bytes);
+	pr_err(TEST_MODULE_NAME ":total bytes = %d, time msec = %d"
+				" for chan %s\n",
+		   total_bytes , (int) time_msec, test_ch->name);
+
+	if (!test_ch->random_packet_size) {
+		if (time_msec) {
+			throughput = (total_bytes / time_msec) * 8 / 1000;
+			pr_err(TEST_MODULE_NAME ": %s - Performance = "
+			       "%d Mbit/sec for chan %s\n",
+			       __func__, throughput, test_ch->name);
+		} else {
+			pr_err(TEST_MODULE_NAME ": %s - time_msec = 0 Couldn't "
+			       "calculate performence for chan %s\n",
+			   __func__, test_ch->name);
+		}
+
+	}
+
+#ifdef CONFIG_DEBUG_FS
+	switch (test_ch->ch_id) {
+	case SDIO_DUN:
+		test_ctx->debug.dun_throughput = throughput;
+		break;
+	case SDIO_RMNT:
+		test_ctx->debug.rmnt_throughput = throughput;
+		break;
+	default:
+		pr_err(TEST_MODULE_NAME "No debugfs for this channel "
+					"throughput");
+	}
+#endif
+
+	pr_err(TEST_MODULE_NAME ": A2 PERFORMANCE TEST END for chan %s.\n",
+	       test_ch->name);
+
+	pr_err(TEST_MODULE_NAME ": TEST PASS for chan %s\n", test_ch->name);
+	test_ch->test_completed = 1;
+	test_ch->test_result = TEST_PASSED;
+	check_test_completion();
+	return;
+
+exit_err:
+	pr_err(TEST_MODULE_NAME ": TEST FAIL for chan %s\n", test_ch->name);
+	test_ch->test_completed = 1;
+	test_ch->test_result = TEST_FAILED;
+	check_test_completion();
+	return;
+}
+
+/**
+ * rx_cleanup
+ * This function reads all the messages sent by the modem until
+ * the read_avail is 0 after 1 second of sleep.
+ * The function returns the number of packets that was received.
+ */
+static void rx_cleanup(struct test_channel *test_ch, int *rx_packet_count)
+{
+	int read_avail = 0;
+	int ret = 0;
+	int counter = 0;
+
+	if (!test_ch || !test_ch->ch) {
+		pr_err(TEST_MODULE_NAME ":%s NULL channel\n",
+				__func__);
+		return;
+	}
+
+	read_avail = sdio_read_avail(test_ch->ch);
+	TEST_DBG(TEST_MODULE_NAME ":channel %s, read_avail=%d\n",
+		 test_ch->name, read_avail);
+
+	/* If no pending messages, wait to see if the modem sends data */
+	if (read_avail == 0) {
+		msleep(1000);
+		read_avail = sdio_read_avail(test_ch->ch);
+	}
+
+	while ((read_avail > 0) && (counter < 10)) {
+		TEST_DBG(TEST_MODULE_NAME ": read_avail=%d for ch %s\n",
+			 read_avail, test_ch->name);
+
+		ret = sdio_read(test_ch->ch, test_ch->buf, read_avail);
+		if (ret) {
+			pr_info(TEST_MODULE_NAME ": sdio_read size %d "
+						 " err=%d for chan %s\n",
+				read_avail, -ret, test_ch->name);
+			break;
+		}
+		(*rx_packet_count)++;
+		test_ch->rx_bytes += read_avail;
+		read_avail = sdio_read_avail(test_ch->ch);
+		if (read_avail == 0) {
+			msleep(1000);
+			counter++;
+			read_avail = sdio_read_avail(test_ch->ch);
+		}
+	}
+	pr_info(TEST_MODULE_NAME ": finished cleanup for ch %s, "
+				 "rx_packet_count=%d, total rx bytes=%d\n",
+			 test_ch->name, *rx_packet_count, test_ch->rx_bytes);
+}
+
+
+/**
+ * A2 RTT Test
+ * This function sends a packet and calculate the RTT time of
+ * this packet.
+ * The test also calculte Min, Max and Average RTT
+ */
+static void a2_rtt_test(struct test_channel *test_ch)
+{
+	int ret = 0 ;
+	u32 read_avail = 0;
+	u32 write_avail = 0;
+	int tx_packet_count = 0;
+	int rx_packet_count = 0;
+	u16 *buf16 = NULL;
+	int i;
+	int max_packets = 0;
+	u32 packet_size = 0;
+	s64 start_time, end_time;
+	int delta_usec = 0;
+	int time_average = 0;
+	int min_delta_usec = 0xFFFF;
+	int max_delta_usec = 0;
+	int total_time = 0;
+	int expected_read_size = 0;
+	int delay_ms = 0;
+	int slow_rtt_counter = 0;
+	int read_avail_so_far = 0;
+
+	if (test_ch) {
+		/*
+		 * Cleanup the pending RX data (such as loopback of the
+		 * config msg)
+		 */
+		rx_cleanup(test_ch, &rx_packet_count);
+		rx_packet_count = 0;
+	} else {
+		return;
+	}
+
+	max_packets = test_ch->config_msg.num_packets;
+	packet_size = test_ch->packet_length;
+	buf16 = (u16 *) test_ch->buf;
+
+	for (i = 0; i < packet_size / 2; i++)
+		buf16[i] = (u16) (i & 0xFFFF);
+
+	pr_info(TEST_MODULE_NAME ": A2 RTT TEST START for chan %s\n",
+		test_ch->name);
+
+	switch (test_ch->ch_id) {
+	case SDIO_RMNT:
+		delay_ms = 100;
+		break;
+	case SDIO_CSVT:
+		delay_ms = 0;
+		break;
+	default:
+		pr_err(TEST_MODULE_NAME ": %s - ch_id invalid.\n",
+		       __func__);
+		return;
+	}
+
+	while (tx_packet_count < max_packets) {
+		if (test_ctx->exit_flag) {
+			pr_info(TEST_MODULE_NAME ":Exit Test.\n");
+			return;
+		}
+		start_time = 0;
+		end_time = 0;
+		read_avail_so_far = 0;
+
+		if (delay_ms)
+			msleep(delay_ms);
+
+		/* wait for data ready event */
+		write_avail = sdio_write_avail(test_ch->ch);
+		TEST_DBG(TEST_MODULE_NAME ":ch %s: write_avail=%d\n",
+			test_ch->name, write_avail);
+		if (write_avail == 0) {
+			wait_event(test_ch->wait_q,
+				   atomic_read(&test_ch->tx_notify_count));
+			atomic_dec(&test_ch->tx_notify_count);
+		}
+
+		write_avail = sdio_write_avail(test_ch->ch);
+		TEST_DBG(TEST_MODULE_NAME ":channel %s, write_avail=%d\n",
+			 test_ch->name, write_avail);
+		if (write_avail > 0) {
+			TEST_DBG(TEST_MODULE_NAME ":tx size = %d for chan %s\n",
+				 packet_size, test_ch->name);
+			test_ch->buf[0] = tx_packet_count;
+
+			start_time = ktime_to_us(ktime_get());
+			ret = sdio_write(test_ch->ch, test_ch->buf,
+					 packet_size);
+			if (ret) {
+				pr_err(TEST_MODULE_NAME ":sdio_write err=%d"
+							 " for chan %s\n",
+					-ret, test_ch->name);
+				goto exit_err;
+			}
+			tx_packet_count++;
+			test_ch->tx_bytes += packet_size;
+		} else {
+				pr_err(TEST_MODULE_NAME ": Invalid write_avail"
+							 " %d for chan %s\n",
+					write_avail, test_ch->name);
+				goto exit_err;
+		}
+
+		expected_read_size = packet_size + A2_HEADER_OVERHEAD;
+
+		while (read_avail_so_far < expected_read_size) {
+
+			read_avail = sdio_read_avail(test_ch->ch);
+
+			if (!read_avail) {
+				wait_event(test_ch->wait_q,
+					   atomic_read(&test_ch->
+						       rx_notify_count));
+
+				atomic_dec(&test_ch->rx_notify_count);
+				continue;
+			}
+
+			read_avail_so_far += read_avail;
+
+			if (read_avail_so_far > expected_read_size) {
+				pr_err(TEST_MODULE_NAME ": %s - Invalid "
+				       "read_avail(%d)  read_avail_so_far(%d) "
+				       "can't be larger than "
+				       "expected_read_size(%d).",
+				       __func__,
+				       read_avail,
+				       read_avail_so_far,
+				       expected_read_size);
+				goto exit_err;
+			}
+
+			/*
+			 * must read entire pending bytes, so later, we will
+			 * get a notification when more data arrives
+			 */
+			ret = sdio_read(test_ch->ch, test_ch->buf,
+					read_avail);
+
+			if (ret) {
+				pr_info(TEST_MODULE_NAME ": sdio_read size %d "
+					" err=%d for chan %s\n",
+					read_avail, -ret,
+					test_ch->name);
+				goto exit_err;
+			}
+		}
+
+		end_time = ktime_to_us(ktime_get());
+		rx_packet_count++;
+		test_ch->rx_bytes += expected_read_size;
+
+		delta_usec = (int)(end_time - start_time);
+		total_time += delta_usec;
+		if (delta_usec < min_delta_usec)
+				min_delta_usec = delta_usec;
+		if (delta_usec > max_delta_usec)
+				max_delta_usec = delta_usec;
+
+		/* checking the RTT per channel criteria */
+		if (delta_usec > MAX_AVG_RTT_TIME_USEC) {
+			pr_err(TEST_MODULE_NAME ": %s - "
+			       "msg # %d - rtt time (%d usec) is "
+			       "longer than %d usec\n",
+			       __func__,
+			       tx_packet_count,
+			       delta_usec,
+			       MAX_AVG_RTT_TIME_USEC);
+			slow_rtt_counter++;
+		}
+
+		TEST_DBG(TEST_MODULE_NAME
+			 ":RTT time=%d for packet #%d for chan %s\n",
+			 delta_usec, tx_packet_count, test_ch->name);
+	} /* while (tx_packet_count < max_packets ) */
+
+	pr_info(TEST_MODULE_NAME ": %s - tx_packet_count = %d\n",
+		__func__, tx_packet_count);
+
+	pr_info(TEST_MODULE_NAME ": %s - total rx bytes = 0x%x, "
+		"rx_packet# = %d for chan %s.\n",
+		__func__, test_ch->rx_bytes, rx_packet_count, test_ch->name);
+
+	pr_info(TEST_MODULE_NAME ": %s - total tx bytes = 0x%x, "
+		"tx_packet# = %d for chan %s.\n",
+		__func__, test_ch->tx_bytes, tx_packet_count, test_ch->name);
+
+	pr_info(TEST_MODULE_NAME ": %s - slow_rtt_counter = %d for "
+		"chan %s.\n",
+		__func__, slow_rtt_counter, test_ch->name);
+
+	if (tx_packet_count) {
+		time_average = total_time / tx_packet_count;
+		pr_info(TEST_MODULE_NAME ":Average RTT time = %d for chan %s\n",
+		   time_average, test_ch->name);
+	} else {
+		pr_err(TEST_MODULE_NAME ": %s - tx_packet_count=0. couldn't "
+		       "calculate average rtt time", __func__);
+	}
+
+	pr_info(TEST_MODULE_NAME ":MIN RTT time = %d for chan %s\n",
+		   min_delta_usec, test_ch->name);
+	pr_info(TEST_MODULE_NAME ":MAX RTT time = %d for chan %s\n",
+		   max_delta_usec, test_ch->name);
+
+	pr_info(TEST_MODULE_NAME ": A2 RTT TEST END for chan %s.\n",
+	       test_ch->name);
+
+	if (ret)
+		goto exit_err;
+
+	if (time_average == 0 || time_average > MAX_AVG_RTT_TIME_USEC) {
+		pr_err(TEST_MODULE_NAME ": %s - average_time = %d. Invalid "
+		       "value",
+		       __func__, time_average);
+		goto exit_err;
+
+	}
+
+	pr_info(TEST_MODULE_NAME ": TEST PASS for chan %s\n", test_ch->name);
+	test_ch->test_completed = 1;
+	test_ch->test_result = TEST_PASSED;
+	check_test_completion();
+	return;
+
+exit_err:
+	pr_err(TEST_MODULE_NAME ": TEST FAIL for chan %s\n", test_ch->name);
+	test_ch->test_completed = 1;
+	test_ch->test_result = TEST_FAILED;
+	check_test_completion();
+	return;
+}
+
+/**
+ * Process Rx Data - Helper for A2 Validation Test
+ * @test_ch(in/out) : Test channel that contains Rx data buffer to process.
+ *
+ * @rx_unprocessed_bytes(in) : Number of bytes to process in the buffer.
+ *
+ * @rx_process_packet_state(in/out) :
+ * Current processing state (used to identify what to process
+ * next in a partial packet)
+ *
+ * @rx_packet_size(in/out) :
+ * Number of bytes remaining in the packet to be processed.
+ *
+ * @rx_packet_count(in/out) :
+ * Number of packets processed.
+ */
+static int process_rx_data(struct test_channel *test_ch,
+			   u32 rx_unprocessed_bytes,
+			   int *rx_process_packet_state,
+			   u16 *rx_packet_size,
+			   int *rx_packet_count)
+{
+	u8 *buf = (u8 *)test_ch->buf;
+	int eop = 0;
+	int i = 0;
+	int ret = 0;
+	u32 *ptr = 0;
+	u16 size = 0;
+
+	/* process rx data */
+	while (rx_unprocessed_bytes) {
+		TEST_DBG(TEST_MODULE_NAME ": unprocessed bytes : %u\n",
+			rx_unprocessed_bytes);
+
+		switch (*rx_process_packet_state) {
+		case RX_PROCESS_PACKET_INIT:
+			/* process the A2 header */
+			TEST_DBG(TEST_MODULE_NAME ": "
+				"RX_PROCESS_PACKET_INIT\n");
+			*rx_process_packet_state = RX_PROCESS_PACKET_INIT;
+			if (rx_unprocessed_bytes < 4)
+				break;
+
+			i += 4;
+			rx_unprocessed_bytes -= 4;
+
+		case RX_PROCESS_A2_HEADER:
+			/* process the rest of A2 header */
+			TEST_DBG(TEST_MODULE_NAME ": RX_PROCESS_A2_HEADER\n");
+			*rx_process_packet_state = RX_PROCESS_A2_HEADER;
+			if (rx_unprocessed_bytes < 4)
+				break;
+
+			ptr = (u32 *)&buf[i];
+			/*
+			 * upper 2 bytes of the last 4 bytes of A2 header
+			 * contains the size of the packet
+			 */
+			*rx_packet_size = *ptr >> 0x10;
+
+			i += 4;
+			rx_unprocessed_bytes -= 4;
+
+		case RX_PROCESS_PACKET_DATA:
+			/* process the2_2_ packet data */
+			TEST_DBG(TEST_MODULE_NAME ": RX_PROCESS_PACKET_DATA "
+				 "- packet size - %u\n", *rx_packet_size);
+			*rx_process_packet_state = RX_PROCESS_PACKET_DATA;
+
+			size = *rx_packet_size;
+			if (*rx_packet_size <= rx_unprocessed_bytes) {
+				eop = *rx_packet_size;
+				*rx_packet_size = 0;
+			} else {
+				eop = rx_unprocessed_bytes;
+				*rx_packet_size = *rx_packet_size -
+						  rx_unprocessed_bytes;
+			}
+
+			/* no more bytes available to process */
+			if (!eop)
+				break;
+			/*
+			 * end of packet is starting from
+			 * the current position
+			 */
+			eop = eop + i;
+			TEST_DBG(TEST_MODULE_NAME ": size - %u, "
+				 "packet size - %u eop - %d\n",
+				 size, *rx_packet_size, eop);
+
+			/* validate the data */
+			for (; i < eop; i++) {
+				if (buf[i] != (test_ch->rx_bytes % 256)) {
+					pr_err(TEST_MODULE_NAME ": "
+					       "Corrupt data. buf:%u, "
+					       "data:%u\n", buf[i],
+					       test_ch->rx_bytes % 256);
+					ret = -EINVAL;
+					goto err;
+				}
+				rx_unprocessed_bytes--;
+				test_ch->rx_bytes++;
+			}
+
+			/* have more data to be processed */
+			if (*rx_packet_size)
+				break;
+
+			/*
+			 * A2 sends data in 4 byte alignment,
+			 * skip the padding
+			 */
+			if (size % 4) {
+				i += 4 - (size % 4);
+				rx_unprocessed_bytes -= 4 - (size % 4);
+			}
+			*rx_packet_count = *rx_packet_count + 1;
+
+			/* re init the state to process new packet */
+			*rx_process_packet_state = RX_PROCESS_PACKET_INIT;
+			break;
+		default:
+			pr_err(TEST_MODULE_NAME ": Invalid case: %d\n",
+			       *rx_process_packet_state);
+			ret = -EINVAL;
+			goto err;
+		}
+		TEST_DBG(TEST_MODULE_NAME ": Continue processing "
+			"if more data is available\n");
+	}
+
+err:
+	return ret;
+}
+
+/**
+ * A2 Validation Test
+ * Send packets and validate the returned packets.
+ * Transmit one packet at a time, while process multiple rx
+ * packets in a single transaction.
+ * A transaction is of size min(random number, write_avail).
+ * A packet consists of a min of 1 byte to channel supported max.
+ */
+static void a2_validation_test(struct test_channel *test_ch)
+{
+	int ret = 0 ;
+	u32 read_avail = 0;
+	u32 write_avail = 0;
+	int tx_packet_count = 0;
+	int rx_packet_count = 0;
+	int initial_rx_packet_count = 0;
+	u32 size = 0;
+	u8 *buf8 = (u8 *)test_ch->buf;
+	int i = 0;
+	int max_packets = test_ch->config_msg.num_packets;
+	u16 tx_packet_size = 0;
+	u16 rx_packet_size = 0;
+	u32 random_num = 0;
+	int rx_process_packet_state = RX_PROCESS_PACKET_INIT;
+
+	pr_info(TEST_MODULE_NAME ": A2 VALIDATION TEST START for chan %s\n",
+		test_ch->name);
+
+	/* Wait for the initial rx messages before starting the test. */
+	rx_cleanup(test_ch, &initial_rx_packet_count);
+
+	test_ch->tx_bytes = 0;
+	test_ch->rx_bytes = 0;
+
+	/* Continue till we have transmitted and received all packets */
+	while ((tx_packet_count < max_packets) ||
+	       (rx_packet_count < max_packets)) {
+
+		if (test_ctx->exit_flag) {
+			pr_info(TEST_MODULE_NAME ":Exit Test.\n");
+			return;
+		}
+
+		random_num = get_random_int();
+		size = (random_num % test_ch->packet_length) + 1;
+		TEST_DBG(TEST_MODULE_NAME ": Random tx packet size =%u", size);
+
+		/*
+		 * wait for data ready event
+		 * use a func to avoid compiler optimizations
+		 */
+		write_avail = sdio_write_avail(test_ch->ch);
+		read_avail = sdio_read_avail(test_ch->ch);
+		TEST_DBG(TEST_MODULE_NAME ": write_avail=%d, "
+			"read_avail=%d for chan %s\n",
+			write_avail, read_avail, test_ch->name);
+
+		if ((write_avail == 0) && (read_avail == 0)) {
+			wait_event(test_ch->wait_q,
+				   atomic_read(&test_ch->any_notify_count));
+			atomic_set(&test_ch->any_notify_count, 0);
+		}
+
+		/* Transmit data */
+		write_avail = sdio_write_avail(test_ch->ch);
+		if ((tx_packet_count < max_packets) && (write_avail > 0)) {
+			tx_packet_size = min(size, write_avail) ;
+			TEST_DBG(TEST_MODULE_NAME ": tx size = %u, "
+				"write_avail = %u tx_packet# = %d\n",
+				tx_packet_size, write_avail,
+				tx_packet_count);
+			memset(test_ch->buf, 0, test_ch->buf_size);
+			/* populate the buffer */
+			for (i = 0; i < tx_packet_size; i++) {
+				buf8[i] = test_ch->tx_bytes % 256;
+				test_ch->tx_bytes++;
+			}
+
+			ret = sdio_write(test_ch->ch, test_ch->buf,
+					  tx_packet_size);
+			if (ret) {
+				pr_err(TEST_MODULE_NAME ":sdio_write err=%d"
+					" for chan %s\n",
+					-ret, test_ch->name);
+				goto exit_err;
+			}
+			tx_packet_count++;
+		}
+
+		/* Receive data */
+		read_avail = sdio_read_avail(test_ch->ch);
+		if (read_avail > 0) {
+			TEST_DBG(TEST_MODULE_NAME ": rx size = %u, "
+				"rx_packet#=%d.\n",
+				read_avail, rx_packet_count);
+			memset(test_ch->buf, 0, test_ch->buf_size);
+
+			ret = sdio_read(test_ch->ch, test_ch->buf,
+					read_avail);
+			if (ret) {
+				pr_err(TEST_MODULE_NAME ": sdio_read "
+					"size %d err=%d for chan %s\n",
+					size, -ret, test_ch->name);
+				goto exit_err;
+			}
+
+			/* Process data */
+			ret = process_rx_data(test_ch, read_avail,
+					      &rx_process_packet_state,
+					      &rx_packet_size,
+					      &rx_packet_count);
+
+			if (ret != 0)
+				goto exit_err;
+		}
+		TEST_DBG(TEST_MODULE_NAME ": Continue loop ...\n");
+	}
+
+	if (test_ch->tx_bytes != test_ch->rx_bytes) {
+		pr_err(TEST_MODULE_NAME ": Total number of bytes "
+			"transmitted (%u) does not match the total "
+			"number of bytes received (%u).", test_ch->tx_bytes,
+			test_ch->rx_bytes);
+		goto exit_err;
+	}
+
+	pr_info(TEST_MODULE_NAME ": A2 VALIDATION TEST END for chan %s.\n",
+		test_ch->name);
+
+	pr_info(TEST_MODULE_NAME ": TEST PASS for chan %s\n", test_ch->name);
+	test_ch->test_completed = 1;
+	test_ch->test_result = TEST_PASSED;
+	check_test_completion();
+	return;
+
+exit_err:
+	pr_info(TEST_MODULE_NAME ": TEST FAIL for chan %s\n", test_ch->name);
+	test_ch->test_completed = 1;
+	test_ch->test_result = TEST_FAILED;
+	check_test_completion();
+	return;
+}
+
+/**
+ * sender No loopback Test
+ */
+static void sender_no_loopback_test(struct test_channel *test_ch)
+{
+	int ret = 0 ;
+	u32 write_avail = 0;
+	int packet_count = 0;
+	int size = 512;
+	u16 *buf16 = (u16 *) test_ch->buf;
+	int i;
+	int max_packet_count = 10000;
+	unsigned int random_num = 0;
+
+	max_packet_count = test_ch->config_msg.num_packets;
+
+	for (i = 0 ; i < size / 2 ; i++)
+		buf16[i] = (u16) (i & 0xFFFF);
+
+	pr_info(TEST_MODULE_NAME
+		 ":SENDER NO LP TEST START for chan %s\n", test_ch->name);
+
+	while (packet_count < max_packet_count) {
+
+		if (test_ctx->exit_flag) {
+			pr_info(TEST_MODULE_NAME ":Exit Test.\n");
+			return;
+		}
+
+		random_num = get_random_int();
+		size = (random_num % test_ch->packet_length) + 1;
+
+		TEST_DBG(TEST_MODULE_NAME ":SENDER WAIT FOR EVENT "
+					  "for chan %s\n",
+			test_ch->name);
+
+		/* wait for data ready event */
+		write_avail = sdio_write_avail(test_ch->ch);
+		TEST_DBG(TEST_MODULE_NAME ":write_avail=%d\n", write_avail);
+		if (write_avail < size) {
+			wait_event(test_ch->wait_q,
+				   atomic_read(&test_ch->tx_notify_count));
+			atomic_dec(&test_ch->tx_notify_count);
+		}
+
+		write_avail = sdio_write_avail(test_ch->ch);
+		TEST_DBG(TEST_MODULE_NAME ":write_avail=%d\n", write_avail);
+		if (write_avail < size) {
+			pr_info(TEST_MODULE_NAME ":not enough write avail.\n");
+			continue;
+		}
+
+		test_ch->buf[0] = packet_count;
+
+		ret = sdio_write(test_ch->ch, test_ch->buf, size);
+		if (ret) {
+			pr_info(TEST_MODULE_NAME ":sender sdio_write err=%d.\n",
+				-ret);
+			goto exit_err;
+		}
+
+		test_ch->tx_bytes += size;
+		packet_count++;
+
+		TEST_DBG(TEST_MODULE_NAME
+			 ":sender total tx bytes = 0x%x , packet#=%d, size=%d"
+			 " for chan %s\n",
+			 test_ch->tx_bytes, packet_count, size, test_ch->name);
+
+	} /* end of while */
+
+	pr_info(TEST_MODULE_NAME
+		 ":SENDER TEST END: total tx bytes = 0x%x, "
+		 " for chan %s\n",
+		 test_ch->tx_bytes, test_ch->name);
+
+	test_ch->modem_result_per_chan = wait_for_result_msg(test_ch);
+
+	if (test_ch->modem_result_per_chan) {
+		pr_info(TEST_MODULE_NAME ": TEST PASS for chan %s.\n",
+			test_ch->name);
+		test_ch->test_result = TEST_PASSED;
+	} else {
+		pr_info(TEST_MODULE_NAME ": TEST FAILURE for chan %s.\n",
+			test_ch->name);
+		test_ch->test_result = TEST_FAILED;
+	}
+	test_ch->test_completed = 1;
+	check_test_completion();
+	return;
+
+exit_err:
+	pr_info(TEST_MODULE_NAME ": TEST FAIL for chan %s.\n",
+		test_ch->name);
+	test_ch->test_completed = 1;
+	test_ch->test_result = TEST_FAILED;
+	check_test_completion();
+	return;
+}
+
+
+/**
+ * Modem reset Test
+ * The test verifies that it finished sending all the packets
+ * while there might be modem reset in the middle
+ */
+static void modem_reset_test(struct test_channel *test_ch)
+{
+	int ret = 0 ;
+	u32 read_avail = 0;
+	u32 write_avail = 0;
+	int tx_packet_count = 0;
+	int rx_packet_count = 0;
+	int size = 0;
+	u16 *buf16 = (u16 *) test_ch->buf;
+	int i;
+	int max_packets = 10000;
+	u32 packet_size = test_ch->buf_size;
+	int is_err = 0;
+
+	max_packets = test_ch->config_msg.num_packets;
+	packet_size = test_ch->packet_length;
+
+	for (i = 0; i < packet_size / 2; i++)
+		buf16[i] = (u16) (i & 0xFFFF);
+
+	pr_info(TEST_MODULE_NAME ": Modem Reset TEST START for chan %s\n",
+		test_ch->name);
+
+	while (tx_packet_count < max_packets) {
+
+		if (test_ctx->exit_flag) {
+			pr_info(TEST_MODULE_NAME ":Exit Test.\n");
+			return;
+		}
+
+		if (test_ch->card_removed) {
+			pr_info(TEST_MODULE_NAME ": card removal was detected "
+				"for chan %s, tx_total=0x%x\n",
+				test_ch->name, test_ch->tx_bytes);
+			wait_event(test_ch->wait_q,
+				   atomic_read(&test_ch->card_detected_event));
+			atomic_set(&test_ch->card_detected_event, 0);
+			pr_info(TEST_MODULE_NAME ": card_detected_event "
+					"for chan %s\n", test_ch->name);
+			if (test_ch->card_removed)
+				continue;
+			is_err = 0;
+			/* Need to wait for the modem to be ready */
+			msleep(5000);
+			pr_info(TEST_MODULE_NAME ": sending the config message "
+					"for chan %s\n", test_ch->name);
+			send_config_msg(test_ch);
+		}
+
+		/* wait for data ready event */
+		/* use a func to avoid compiler optimizations */
+		write_avail = sdio_write_avail(test_ch->ch);
+		read_avail = sdio_read_avail(test_ch->ch);
+		TEST_DBG(TEST_MODULE_NAME ":channel %s, write_avail=%d, "
+					 "read_avail=%d for chan %s\n",
+			test_ch->name, write_avail, read_avail,
+			test_ch->name);
+		if ((write_avail == 0) && (read_avail == 0)) {
+			wait_event(test_ch->wait_q,
+				   atomic_read(&test_ch->any_notify_count));
+			atomic_set(&test_ch->any_notify_count, 0);
+		}
+		if (atomic_read(&test_ch->card_detected_event)) {
+			atomic_set(&test_ch->card_detected_event, 0);
+			pr_info(TEST_MODULE_NAME ": card_detected_event "
+				"for chan %s, tx_total=0x%x\n",
+				test_ch->name,  test_ch->tx_bytes);
+			if (test_ch->card_removed)
+				continue;
+			/* Need to wait for the modem to be ready */
+			msleep(5000);
+			is_err = 0;
+			pr_info(TEST_MODULE_NAME ": sending the config message "
+					"for chan %s\n", test_ch->name);
+			send_config_msg(test_ch);
+		}
+
+		write_avail = sdio_write_avail(test_ch->ch);
+		TEST_DBG(TEST_MODULE_NAME ":channel %s, write_avail=%d\n",
+			 test_ch->name, write_avail);
+		if (write_avail > 0) {
+			size = min(packet_size, write_avail) ;
+			pr_debug(TEST_MODULE_NAME ":tx size = %d for chan %s\n",
+				 size, test_ch->name);
+			test_ch->buf[0] = tx_packet_count;
+			test_ch->buf[(size/4)-1] = tx_packet_count;
+
+			TEST_DBG(TEST_MODULE_NAME ":channel %s, sdio_write, "
+				"size=%d\n", test_ch->name, size);
+			if (is_err) {
+				msleep(100);
+				continue;
+			}
+			ret = sdio_write(test_ch->ch, test_ch->buf, size);
+			if (ret) {
+				pr_info(TEST_MODULE_NAME ":sdio_write err=%d"
+							 " for chan %s\n",
+					-ret, test_ch->name);
+				is_err = 1;
+				msleep(20);
+				continue;
+			}
+			tx_packet_count++;
+			test_ch->tx_bytes += size;
+			test_ch->config_msg.num_packets--;
+		}
+
+		read_avail = sdio_read_avail(test_ch->ch);
+		TEST_DBG(TEST_MODULE_NAME ":channel %s, read_avail=%d\n",
+			 test_ch->name, read_avail);
+		if (read_avail > 0) {
+			size = min(packet_size, read_avail);
+			pr_debug(TEST_MODULE_NAME ":rx size = %d.\n", size);
+			TEST_DBG(TEST_MODULE_NAME ":channel %s, sdio_read, "
+				"size=%d\n", test_ch->name, size);
+			if (is_err) {
+				msleep(100);
+				continue;
+			}
+			ret = sdio_read(test_ch->ch, test_ch->buf, size);
+			if (ret) {
+				pr_info(TEST_MODULE_NAME ": sdio_read size %d "
+							 " err=%d"
+							 " for chan %s\n",
+					size, -ret, test_ch->name);
+				is_err = 1;
+				msleep(20);
+				continue;
+			}
+			rx_packet_count++;
+			test_ch->rx_bytes += size;
+		}
+
+		TEST_DBG(TEST_MODULE_NAME
+			 ":total rx bytes = %d , rx_packet#=%d"
+			 " for chan %s\n",
+			 test_ch->rx_bytes, rx_packet_count, test_ch->name);
+		TEST_DBG(TEST_MODULE_NAME
+			 ":total tx bytes = %d , tx_packet#=%d"
+			 " for chan %s\n",
+			 test_ch->tx_bytes, tx_packet_count, test_ch->name);
+
+		udelay(500);
+
+	} /* while (tx_packet_count < max_packets ) */
+
+	pr_info(TEST_MODULE_NAME ":total rx bytes = 0x%x , rx_packet#=%d for"
+				 " chan %s.\n",
+		test_ch->rx_bytes, rx_packet_count, test_ch->name);
+	pr_info(TEST_MODULE_NAME ":total tx bytes = 0x%x , tx_packet#=%d"
+				 " for chan %s.\n",
+		test_ch->tx_bytes, tx_packet_count, test_ch->name);
+
+	pr_err(TEST_MODULE_NAME ": Modem Reset TEST END for chan %s.\n",
+	       test_ch->name);
+
+	pr_err(TEST_MODULE_NAME ": TEST PASS for chan %s\n", test_ch->name);
+	test_ch->test_completed = 1;
+	test_ch->test_result = TEST_PASSED;
+	check_test_completion();
+	return;
+}
+
+/**
+ * Worker thread to handle the tests types
+ */
+static void worker(struct work_struct *work)
+{
+	struct test_channel *test_ch = NULL;
+	struct test_work *test_work = container_of(work,
+						 struct	test_work,
+						 work);
+	int test_type = 0;
+
+	test_ch = test_work->test_ch;
+
+	if (test_ch == NULL) {
+		pr_err(TEST_MODULE_NAME ":NULL test_ch\n");
+		return;
+	}
+
+	test_type = test_ch->test_type;
+
+	switch (test_type) {
+	case SDIO_TEST_LOOPBACK_HOST:
+		loopback_test(test_ch);
+		break;
+	case SDIO_TEST_LOOPBACK_CLIENT:
+		sender_test(test_ch);
+		break;
+	case SDIO_TEST_PERF:
+		a2_performance_test(test_ch);
+		break;
+	case SDIO_TEST_LPM_CLIENT_WAKER:
+		lpm_test(test_ch);
+		break;
+	case SDIO_TEST_LPM_HOST_WAKER:
+		lpm_test_host_waker(test_ch);
+		break;
+	case SDIO_TEST_HOST_SENDER_NO_LP:
+		sender_no_loopback_test(test_ch);
+		break;
+	case SDIO_TEST_LPM_RANDOM:
+		lpm_continuous_rand_test(test_ch);
+		break;
+	case SDIO_TEST_RTT:
+		a2_rtt_test(test_ch);
+		break;
+	case SDIO_TEST_CLOSE_CHANNEL:
+		if (test_ch->ch_id != SDIO_SMEM)
+			open_close_test(test_ch);
+		break;
+	case SDIO_TEST_MODEM_RESET:
+		modem_reset_test(test_ch);
+		break;
+	case SDIO_TEST_A2_VALIDATION:
+		a2_validation_test(test_ch);
+		break;
+	default:
+		pr_err(TEST_MODULE_NAME ":Bad Test type = %d.\n",
+			(int) test_type);
+	}
+}
+
+
+/**
+ * Notification Callback
+ *
+ * Notify the worker
+ *
+ */
+static void notify(void *priv, unsigned channel_event)
+{
+	struct test_channel *test_ch = (struct test_channel *) priv;
+
+	pr_debug(TEST_MODULE_NAME ": %s - notify event=%d.\n",
+		 __func__, channel_event);
+
+	if (test_ch->ch == NULL) {
+		pr_info(TEST_MODULE_NAME ": %s - notify before ch ready.\n",
+			__func__);
+		return;
+	}
+
+	switch (channel_event) {
+	case SDIO_EVENT_DATA_READ_AVAIL:
+		atomic_inc(&test_ch->rx_notify_count);
+		atomic_set(&test_ch->any_notify_count, 1);
+		TEST_DBG(TEST_MODULE_NAME ": %s - SDIO_EVENT_DATA_READ_AVAIL, "
+			 "any_notify_count=%d, rx_notify_count=%d\n",
+			 __func__,
+			 atomic_read(&test_ch->any_notify_count),
+			 atomic_read(&test_ch->rx_notify_count));
+		/*
+		 * when there is pending data on a channel we would like to
+		 * turn on the bit mask that implies that there is pending
+		 * data for that channel on that deivce
+		 */
+		if (test_ch->test_device != NULL &&
+		    test_ch->test_type == SDIO_TEST_LPM_RANDOM) {
+			spin_lock_irqsave(&test_ch->test_device->lpm_array_lock,
+					  test_ch->test_device->
+						  lpm_array_lock_flags);
+			test_ch->test_device->read_avail_mask |=
+				test_ch->channel_mask_id;
+			test_ch->notify_counter_per_chan++;
+
+			lpm_test_update_entry(test_ch, LPM_NOTIFY, "NOTIFY", 0);
+			spin_unlock_irqrestore(&test_ch->test_device->
+					       lpm_array_lock,
+					       test_ch->test_device->
+						  lpm_array_lock_flags);
+		}
+		break;
+
+	case SDIO_EVENT_DATA_WRITE_AVAIL:
+		atomic_inc(&test_ch->tx_notify_count);
+		atomic_set(&test_ch->any_notify_count, 1);
+		TEST_DBG(TEST_MODULE_NAME ": %s - SDIO_EVENT_DATA_WRITE_AVAIL, "
+			 "any_notify_count=%d, tx_notify_count=%d\n",
+			 __func__,
+			 atomic_read(&test_ch->any_notify_count),
+			 atomic_read(&test_ch->tx_notify_count));
+		break;
+
+	default:
+		BUG();
+	}
+	wake_up(&test_ch->wait_q);
+
+}
+
+#ifdef CONFIG_MSM_SDIO_SMEM
+static int sdio_smem_test_cb(int event)
+{
+	struct test_channel *tch = test_ctx->test_ch_arr[SDIO_SMEM];
+	int i;
+	int *smem_buf = (int *)test_ctx->smem_buf;
+	uint32_t val = 0;
+	int ret = 0;
+
+	pr_debug(TEST_MODULE_NAME ":%s: Received event %d\n", __func__, event);
+
+	if (!tch) {
+		pr_err(TEST_MODULE_NAME ": %s NULL tch\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SDIO_SMEM_EVENT_READ_DONE:
+		tch->rx_bytes += SMEM_MAX_XFER_SIZE;
+		for (i = 0; i < SMEM_MAX_XFER_SIZE;) {
+			val = (int)*smem_buf;
+			if ((val != test_ctx->smem_counter) && tch->is_used) {
+				pr_err(TEST_MODULE_NAME ":%s: Invalid value %d "
+				"expected %d in smem arr",
+				__func__, val, test_ctx->smem_counter);
+				pr_err(TEST_MODULE_NAME ":SMEM test FAILED\n");
+				tch->test_completed = 1;
+				tch->test_result = TEST_FAILED;
+				check_test_completion();
+				ret = -EINVAL;
+				goto exit;
+			}
+			i += 4;
+			smem_buf++;
+			test_ctx->smem_counter++;
+		}
+		if (tch->rx_bytes >= 40000000) {
+			if ((!tch->test_completed) && tch->is_used) {
+				pr_info(TEST_MODULE_NAME ":SMEM test PASSED\n");
+				tch->test_completed = 1;
+				tch->test_result = TEST_PASSED;
+				check_test_completion();
+			}
+		}
+		break;
+	case SDIO_SMEM_EVENT_READ_ERR:
+		if (tch->is_used) {
+			pr_err(TEST_MODULE_NAME ":Read overflow, "
+						"SMEM test FAILED\n");
+			tch->test_completed = 1;
+			tch->test_result = TEST_FAILED;
+			ret = -EIO;
+		}
+		break;
+	default:
+		if (tch->is_used) {
+			pr_err(TEST_MODULE_NAME ":Unhandled event %d\n", event);
+			ret = -EINVAL;
+		}
+		break;
+	}
+exit:
+	return ret;
+}
+
+static int sdio_smem_open(struct sdio_smem_client *sdio_smem)
+{
+	int ret = 0;
+
+	if (!sdio_smem) {
+		pr_info(TEST_MODULE_NAME "%s: NULL sdio_smem_client\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if (test_ctx->test_ch_arr[SDIO_SMEM]->ch_ready) {
+		pr_info(TEST_MODULE_NAME "%s: SDIO_SMEM channel is already opened\n",
+			__func__);
+		return 0;
+	}
+
+	test_ctx->test_ch_arr[SDIO_SMEM]->ch_ready = 1;
+	sdio_smem->buf = test_ctx->smem_buf;
+	sdio_smem->size = SMEM_MAX_XFER_SIZE;
+	sdio_smem->cb_func = sdio_smem_test_cb;
+	ret = sdio_smem_register_client();
+	if (ret)
+		pr_info(TEST_MODULE_NAME "%s: Error (%d) registering sdio_smem "
+					 "test client\n",
+			__func__, ret);
+
+	return ret;
+}
+
+static int sdio_smem_test_probe(struct platform_device *pdev)
+{
+	test_ctx->sdio_smem = container_of(pdev, struct sdio_smem_client,
+					   plat_dev);
+
+	return sdio_smem_open(test_ctx->sdio_smem);
+}
+
+static struct platform_driver sdio_smem_client_drv = {
+	.probe		= sdio_smem_test_probe,
+	.driver		= {
+		.name	= "SDIO_SMEM_CLIENT",
+		.owner	= THIS_MODULE,
+	},
+};
+#endif
+
+static void sdio_test_lpm_timeout_handler(unsigned long data)
+{
+	struct test_channel *tch = (struct test_channel *)data;
+
+	pr_info(TEST_MODULE_NAME ": %s - LPM TEST TIMEOUT Expired after "
+			    "%d ms\n", __func__, tch->timeout_ms);
+	tch->test_completed = 1;
+	pr_info(TEST_MODULE_NAME ": %s - tch->test_result = TEST_FAILED\n",
+		__func__);
+	tch->test_completed = 1;
+	tch->test_result = TEST_FAILED;
+	check_test_completion();
+	return;
+}
+
+static void sdio_test_lpm_timer_handler(unsigned long data)
+{
+	struct test_channel *tch = (struct test_channel *)data;
+
+	pr_info(TEST_MODULE_NAME ": %s - LPM TEST Timer Expired after "
+			    "%d ms\n", __func__, tch->timer_interval_ms);
+
+	if (!tch) {
+		pr_err(TEST_MODULE_NAME ": %s - LPM TEST FAILED. "
+		       "tch is NULL\n", __func__);
+		return;
+	}
+
+	if (!tch->ch) {
+		pr_err(TEST_MODULE_NAME ": %s - LPM TEST FAILED. tch->ch "
+		       "is NULL\n", __func__);
+		tch->test_result = TEST_FAILED;
+		return;
+	}
+
+	/* Verfiy that we voted for sleep */
+	if (tch->is_ok_to_sleep) {
+		tch->test_result = TEST_PASSED;
+		pr_info(TEST_MODULE_NAME ": %s - 8K voted for sleep\n",
+			__func__);
+	} else {
+		tch->test_result = TEST_FAILED;
+		pr_info(TEST_MODULE_NAME ": %s - 8K voted against sleep\n",
+			__func__);
+
+	}
+
+	sdio_al_unregister_lpm_cb(tch->sdio_al_device);
+
+	if (tch->test_type == SDIO_TEST_LPM_HOST_WAKER) {
+		atomic_set(&tch->wakeup_client, 1);
+		wake_up(&tch->wait_q);
+	}
+}
+
+int sdio_test_wakeup_callback(void *device_handle, int is_vote_for_sleep)
+{
+	int i = 0;
+
+	TEST_DBG(TEST_MODULE_NAME ": %s is_vote_for_sleep=%d!!!",
+		__func__, is_vote_for_sleep);
+
+	for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
+		struct test_channel *tch = test_ctx->test_ch_arr[i];
+
+		if ((!tch) || (!tch->is_used) || (!tch->ch_ready))
+			continue;
+		if (tch->sdio_al_device == device_handle) {
+			tch->is_ok_to_sleep = is_vote_for_sleep;
+
+			if (tch->test_type == SDIO_TEST_LPM_RANDOM) {
+				spin_lock_irqsave(&tch->test_device->
+						  lpm_array_lock,
+						  tch->test_device->
+						  lpm_array_lock_flags);
+				if (is_vote_for_sleep == 1)
+					lpm_test_update_entry(tch,
+							      LPM_SLEEP,
+							      "SLEEP ", 0);
+				else
+					lpm_test_update_entry(tch,
+							      LPM_WAKEUP,
+							      "WAKEUP", 0);
+
+				spin_unlock_irqrestore(&tch->test_device->
+						       lpm_array_lock,
+						       tch->test_device->
+						       lpm_array_lock_flags);
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int sdio_test_find_dev(struct test_channel *tch)
+{
+	int j;
+	int null_index = -1;
+
+	for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES; ++j) {
+
+		struct sdio_test_device *test_dev =
+		&test_ctx->test_dev_arr[j];
+
+		if (test_dev->sdio_al_device == NULL) {
+			if (null_index == -1)
+				null_index = j;
+			continue;
+		}
+
+		if (test_dev->sdio_al_device ==
+		    tch->ch->sdio_al_dev) {
+			test_dev->open_channels_counter_to_recv++;
+			test_dev->open_channels_counter_to_send++;
+			tch->test_device = test_dev;
+			/* setting mask id for pending data for
+			   this channel */
+			tch->channel_mask_id = test_dev->next_mask_id;
+			test_dev->next_mask_id *= 2;
+			pr_info(TEST_MODULE_NAME ": %s - channel %s "
+				"got read_mask_id = 0x%x. device "
+				"next_mask_id=0x%x",
+				__func__, tch->name, tch->channel_mask_id,
+				test_dev->next_mask_id);
+			break;
+		}
+	}
+
+	/*
+	 * happens ones a new device is "discovered" while testing. i.e
+	 * if testing a few channels, a new deivce will be "discovered" once
+	 * the first channel of a device is being tested
+	 */
+	if (j == MAX_NUM_OF_SDIO_DEVICES) {
+
+		struct sdio_test_device *test_dev =
+			&test_ctx->
+			test_dev_arr[null_index];
+		test_dev->sdio_al_device =
+			tch->ch->sdio_al_dev;
+
+		test_ctx->number_of_active_devices++;
+		test_ctx->max_number_of_devices++;
+		test_dev->open_channels_counter_to_recv++;
+		test_dev->open_channels_counter_to_send++;
+		test_dev->next_avail_entry_in_array = 0;
+		tch->test_device = test_dev;
+		tch->test_device->array_size =
+			LPM_ARRAY_SIZE;
+		test_dev->modem_result_per_dev = 1;
+		tch->modem_result_per_chan = 0;
+		test_dev->next_avail_entry_in_array = 0;
+
+		spin_lock_init(&test_dev->
+			       lpm_array_lock);
+
+		if (tch->test_type == SDIO_TEST_LPM_RANDOM) {
+			pr_err(MODULE_NAME ": %s - "
+			       "Allocating Msg Array for "
+			       "Maximum open channels for device (%d) "
+			       "Channels. Array has %d entries",
+			       __func__,
+			       LPM_MAX_OPEN_CHAN_PER_DEV,
+			       test_dev->array_size);
+
+			test_dev->lpm_arr =
+				kzalloc(sizeof(
+				struct lpm_entry_type) *
+					tch->
+					test_device->array_size,
+				GFP_KERNEL);
+
+			if (!test_dev->lpm_arr) {
+				pr_err(MODULE_NAME ": %s - "
+					"lpm_arr is NULL",
+					__func__);
+				return -ENOMEM;
+			}
+		}
+
+		/*
+		 * in new device, initialize next_mask_id, and setting
+		 * mask_id to the channel
+		 */
+		test_dev->next_mask_id = 0x1;
+		tch->channel_mask_id = test_dev->next_mask_id;
+		test_dev->next_mask_id *= 2;
+		pr_info(TEST_MODULE_NAME ": %s - channel %s got "
+			"read_mask_id = 0x%x. device next_mask_id=0x%x",
+			__func__,
+			tch->name,
+			tch->channel_mask_id,
+			test_dev->next_mask_id);
+	}
+
+	return 0;
+}
+
+static void check_test_result(void)
+{
+	int result = 1;
+	int i = 0;
+
+	test_ctx->max_number_of_devices = 0;
+
+	pr_info(TEST_MODULE_NAME ": %s - Woke Up\n", __func__);
+
+	for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
+		struct test_channel *tch = test_ctx->test_ch_arr[i];
+
+		if ((!tch) || (!tch->is_used) || (!tch->ch_ready))
+			continue;
+
+		if (tch->test_type == SDIO_TEST_LPM_RANDOM)
+			result &= tch->test_device->final_result_per_dev;
+		else
+			if (tch->test_result == TEST_FAILED) {
+				pr_info(TEST_MODULE_NAME ": %s - "
+					"Test FAILED\n", __func__);
+				test_ctx->test_result = TEST_FAILED;
+				pr_err(TEST_MODULE_NAME ": %s - "
+				       "test_result %d",
+				       __func__, test_ctx->test_result);
+				return;
+			}
+	}
+
+	if (result == 0) {
+		pr_info(TEST_MODULE_NAME ": %s - Test FAILED\n", __func__);
+		test_ctx->test_result = TEST_FAILED;
+		pr_err(TEST_MODULE_NAME ": %s - "
+		       "test_result %d",
+		       __func__, test_ctx->test_result);
+		return;
+	}
+
+	pr_info(TEST_MODULE_NAME ": %s - Test PASSED", __func__);
+	test_ctx->test_result = TEST_PASSED;
+	pr_err(TEST_MODULE_NAME ": %s - "
+	       "test_result %d",
+	       __func__, test_ctx->test_result);
+	return;
+}
+
+/**
+ * Test Main
+ */
+static int test_start(void)
+{
+	int ret = -ENOMEM;
+	int i;
+
+	pr_debug(TEST_MODULE_NAME ":Starting Test ....\n");
+
+	test_ctx->test_completed = 0;
+	test_ctx->test_result = TEST_NO_RESULT;
+	test_ctx->debug.dun_throughput = 0;
+	test_ctx->debug.rmnt_throughput = 0;
+	test_ctx->number_of_active_devices = 0;
+
+	pr_err(TEST_MODULE_NAME ": %s - test_result %d",
+	       __func__, test_ctx->test_result);
+
+	memset(test_ctx->test_dev_arr, 0,
+		sizeof(struct sdio_test_device)*MAX_NUM_OF_SDIO_DEVICES);
+
+	/* Open The Channels */
+	for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
+		struct test_channel *tch = test_ctx->test_ch_arr[i];
+
+		if ((!tch) || (!tch->is_used))
+			continue;
+
+		tch->rx_bytes = 0;
+		tch->tx_bytes = 0;
+
+		atomic_set(&tch->tx_notify_count, 0);
+		atomic_set(&tch->rx_notify_count, 0);
+		atomic_set(&tch->any_notify_count, 0);
+		atomic_set(&tch->wakeup_client, 0);
+
+		/* in case there are values left from previous tests */
+		tch->notify_counter_per_chan = 0;
+		tch->next_index_in_sent_msg_per_chan = 0;
+
+		memset(tch->buf, 0x00, tch->buf_size);
+		tch->test_result = TEST_NO_RESULT;
+
+		tch->test_completed = 0;
+
+		ret = open_sdio_ch(tch);
+		if (ret)
+			continue;
+
+		if (tch->ch_id != SDIO_SMEM) {
+			ret = sdio_test_find_dev(tch);
+
+			if (ret) {
+				pr_err(TEST_MODULE_NAME ": %s - "
+				       "sdio_test_find_dev() returned with "
+				       "error", __func__);
+				return -ENODEV;
+			}
+
+			tch->sdio_al_device = tch->ch->sdio_al_dev;
+		}
+
+		if ((tch->test_type == SDIO_TEST_LPM_HOST_WAKER) ||
+		    (tch->test_type == SDIO_TEST_LPM_CLIENT_WAKER) ||
+		    (tch->test_type == SDIO_TEST_LPM_RANDOM))
+			sdio_al_register_lpm_cb(tch->sdio_al_device,
+					 sdio_test_wakeup_callback);
+	}
+
+	/*
+	 * make some space between opening the channels and sending the
+	 * config messages
+	 */
+	msleep(100);
+
+	/*
+	 * try to delay send_config_msg of all channels to after the point
+	 * when we open them all
+	 */
+	for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
+		struct test_channel *tch = test_ctx->test_ch_arr[i];
+
+		if ((!tch) || (!tch->is_used))
+			continue;
+
+		if ((tch->ch_ready) && (tch->ch_id != SDIO_SMEM))
+			send_config_msg(tch);
+
+		if ((tch->test_type == SDIO_TEST_LPM_HOST_WAKER) ||
+		    (tch->test_type == SDIO_TEST_LPM_CLIENT_WAKER) ||
+		    (tch->test_type == SDIO_TEST_LPM_RANDOM)) {
+			if (tch->timer_interval_ms > 0) {
+				pr_info(TEST_MODULE_NAME ": %s - init timer, "
+					"ms=%d\n",
+					__func__, tch->timer_interval_ms);
+				init_timer(&tch->timer);
+				tch->timer.data = (unsigned long)tch;
+				tch->timer.function =
+					sdio_test_lpm_timer_handler;
+				tch->timer.expires = jiffies +
+				    msecs_to_jiffies(tch->timer_interval_ms);
+				add_timer(&tch->timer);
+			}
+		}
+	}
+
+	pr_debug(TEST_MODULE_NAME ":queue_work..\n");
+	for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
+		struct test_channel *tch = test_ctx->test_ch_arr[i];
+
+		if ((!tch) || (!tch->is_used) || (!tch->ch_ready))
+			continue;
+
+		if (tch->ch_id == SDIO_SMEM) {
+#ifdef CONFIG_MSM_SDIO_SMEM
+			if (tch->test_type == SDIO_TEST_CLOSE_CHANNEL)
+				open_close_smem_test(tch);
+#endif
+		} else {
+			queue_work(tch->workqueue, &tch->test_work.work);
+		}
+
+	}
+
+	pr_info(TEST_MODULE_NAME ": %s - Waiting for the test completion\n",
+		__func__);
+
+	wait_event(test_ctx->wait_q, test_ctx->test_completed);
+	check_test_result();
+
+	/*
+	 * Close the channels and zero the is_used flag so that if the modem
+	 * will be reset after the test completion we won't re-open
+	 * the channels
+	 */
+	for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
+		struct test_channel *tch = test_ctx->test_ch_arr[i];
+
+		if ((!tch) || (!tch->is_used))
+			continue;
+		if (!tch->ch_ready) {
+			tch->is_used = 0;
+			continue;
+		}
+
+		close_sdio_ch(tch);
+		tch->is_used = 0;
+	}
+
+	if (test_ctx->test_result == TEST_PASSED)
+		return 0;
+	else
+		return -EINVAL;
+}
+
+static int set_params_loopback_9k(struct test_channel *tch)
+{
+	if (!tch) {
+		pr_err(TEST_MODULE_NAME ":NULL channel\n");
+		return -EINVAL;
+	}
+	tch->is_used = 1;
+	tch->test_type = SDIO_TEST_LOOPBACK_CLIENT;
+	tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
+	tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
+	tch->config_msg.num_packets = 10000;
+	tch->config_msg.num_iterations = 1;
+
+	tch->packet_length = 512;
+	if (tch->ch_id == SDIO_RPC)
+		tch->packet_length = 128;
+	tch->timer_interval_ms = 0;
+
+	return 0;
+}
+static int set_params_loopback_9k_close(struct test_channel *tch)
+{
+	if (!tch) {
+		pr_err(TEST_MODULE_NAME ":NULL channel\n");
+		return -EINVAL;
+	}
+	tch->is_used = 1;
+	tch->test_type = SDIO_TEST_CLOSE_CHANNEL;
+	tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
+	tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
+	tch->config_msg.num_packets = 5000;
+	tch->config_msg.num_iterations = 1;
+	tch->max_burst_size = 10;
+	switch (tch->ch_id) {
+	case SDIO_DUN:
+	case SDIO_RPC:
+		tch->packet_length = 128; /* max is 2K*/
+		break;
+	case SDIO_DIAG:
+	case SDIO_RMNT:
+	default:
+		tch->packet_length = 512; /* max is 4k */
+	}
+	tch->timer_interval_ms = 0;
+	return 0;
+}
+static int set_params_a2_perf(struct test_channel *tch)
+{
+	if (!tch) {
+		pr_err(TEST_MODULE_NAME ":NULL channel\n");
+		return -EINVAL;
+	}
+	tch->is_used = 1;
+	tch->test_type = SDIO_TEST_PERF;
+	tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
+	tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
+
+	switch (tch->ch_id) {
+	case SDIO_DIAG:
+		tch->packet_length = 512;
+		break;
+	case SDIO_DUN:
+		tch->packet_length = DUN_PACKET_SIZE;
+		break;
+	case SDIO_CSVT:
+		tch->packet_length = CSVT_PACKET_SIZE;
+		break;
+	default:
+		tch->packet_length = MAX_XFER_SIZE;
+		break;
+	}
+
+	pr_info(TEST_MODULE_NAME ": %s: packet_length=%d", __func__,
+			tch->packet_length);
+
+	tch->config_msg.num_packets = 10000;
+	tch->config_msg.num_iterations = 1;
+	tch->random_packet_size = 0;
+
+	tch->timer_interval_ms = 0;
+
+	return 0;
+}
+
+static int set_params_rtt(struct test_channel *tch)
+{
+	if (!tch) {
+		pr_err(TEST_MODULE_NAME ":NULL channel\n");
+		return -EINVAL;
+	}
+	tch->is_used = 1;
+	tch->test_type = SDIO_TEST_RTT;
+	tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
+	tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
+
+	switch (tch->ch_id) {
+	case SDIO_RMNT:
+		tch->packet_length = SDIO_RMNT_RTT_PACKET_SIZE;
+		break;
+	case SDIO_CSVT:
+		tch->packet_length = SDIO_CSVT_RTT_PACKET_SIZE;
+		break;
+	default:
+		pr_err(TEST_MODULE_NAME ": %s - ch_id invalid.\n", __func__);
+		return -EINVAL;
+	}
+
+	pr_info(TEST_MODULE_NAME ": %s: packet_length=%d", __func__,
+			tch->packet_length);
+
+	tch->config_msg.num_packets = 200;
+	tch->config_msg.num_iterations = 1;
+	tch->random_packet_size = 0;
+
+	tch->timer_interval_ms = 0;
+
+	return 0;
+}
+
+static int set_params_a2_small_pkts(struct test_channel *tch)
+{
+	if (!tch) {
+		pr_err(TEST_MODULE_NAME ":NULL channel\n");
+		return -EINVAL;
+	}
+	tch->is_used = 1;
+	tch->test_type = SDIO_TEST_PERF;
+	tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
+	tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
+	tch->packet_length = 128;
+
+	tch->config_msg.num_packets = 1000000;
+	tch->config_msg.num_iterations = 1;
+	tch->random_packet_size = 1;
+
+	tch->timer_interval_ms = 0;
+
+	return 0;
+}
+
+static int set_params_modem_reset(struct test_channel *tch)
+{
+	if (!tch) {
+		pr_err(TEST_MODULE_NAME ":NULL channel\n");
+		return -EINVAL;
+	}
+	tch->is_used = 1;
+	tch->test_type = SDIO_TEST_MODEM_RESET;
+	tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
+	tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
+	tch->packet_length = 512;
+	if (tch->ch_id == SDIO_RPC)
+		tch->packet_length = 128;
+	else if ((tch->ch_id == SDIO_RMNT) || (tch->ch_id == SDIO_DUN))
+		tch->packet_length = MAX_XFER_SIZE;
+
+	tch->config_msg.num_packets = 50000;
+	tch->config_msg.num_iterations = 1;
+
+	tch->timer_interval_ms = 0;
+
+	return 0;
+}
+
+static int set_params_a2_validation(struct test_channel *tch)
+{
+	if (!tch) {
+		pr_err(TEST_MODULE_NAME ":NULL channel\n");
+		return -EINVAL;
+	}
+	tch->is_used = 1;
+	tch->test_type = SDIO_TEST_A2_VALIDATION;
+	tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
+	tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
+
+	if (tch->ch_id == SDIO_RMNT)
+		tch->packet_length = RMNT_PACKET_SIZE;
+	else if (tch->ch_id == SDIO_DUN)
+		tch->packet_length = DUN_PACKET_SIZE;
+	else
+		tch->packet_length = MAX_XFER_SIZE;
+
+	tch->config_msg.num_packets = 10000;
+	tch->config_msg.num_iterations = 1;
+	tch->timer_interval_ms = 0;
+
+	return 0;
+}
+
+static int set_params_smem_test(struct test_channel *tch)
+{
+	if (!tch) {
+		pr_err(TEST_MODULE_NAME ":NULL channel\n");
+		return -EINVAL;
+	}
+	tch->is_used = 1;
+	tch->timer_interval_ms = 0;
+
+	return 0;
+}
+
+static int set_params_lpm_test(struct test_channel *tch,
+				enum sdio_test_case_type test,
+				int timer_interval_ms)
+{
+	static int first_time = 1;
+	if (!tch) {
+		pr_err(TEST_MODULE_NAME ": %s - NULL channel\n", __func__);
+		return -EINVAL;
+	}
+
+	tch->is_used = 1;
+	tch->test_type = test;
+	tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
+	tch->config_msg.test_case = test;
+	tch->config_msg.num_packets = LPM_TEST_NUM_OF_PACKETS;
+	tch->config_msg.num_iterations = 1;
+	tch->timer_interval_ms = timer_interval_ms;
+	tch->timeout_ms = 10000;
+
+	tch->packet_length = 0;
+	if (test != SDIO_TEST_LPM_RANDOM) {
+		init_timer(&tch->timeout_timer);
+		tch->timeout_timer.data = (unsigned long)tch;
+		tch->timeout_timer.function = sdio_test_lpm_timeout_handler;
+		tch->timeout_timer.expires = jiffies +
+			msecs_to_jiffies(tch->timeout_ms);
+		add_timer(&tch->timeout_timer);
+		pr_info(TEST_MODULE_NAME ": %s - Initiated LPM TIMEOUT TIMER."
+			"set to %d ms\n",
+			__func__, tch->timeout_ms);
+	}
+
+	if (first_time) {
+		pr_info(TEST_MODULE_NAME ": %s - wake_lock_init() called\n",
+		__func__);
+		wake_lock_init(&test_ctx->wake_lock,
+			       WAKE_LOCK_SUSPEND, TEST_MODULE_NAME);
+		first_time = 0;
+	}
+
+	pr_info(TEST_MODULE_NAME ": %s - wake_lock() for the TEST is "
+		"called channel %s. to prevent real sleeping\n",
+		__func__, tch->name);
+	wake_lock(&test_ctx->wake_lock);
+
+	return 0;
+}
+
+static int set_params_8k_sender_no_lp(struct test_channel *tch)
+{
+	if (!tch) {
+		pr_err(TEST_MODULE_NAME ":NULL channel\n");
+		return -EINVAL;
+	}
+	tch->is_used = 1;
+	tch->test_type = SDIO_TEST_HOST_SENDER_NO_LP;
+	tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
+	tch->config_msg.test_case = SDIO_TEST_HOST_SENDER_NO_LP;
+	tch->config_msg.num_packets = 1000;
+	tch->config_msg.num_iterations = 1;
+
+	tch->packet_length = 512;
+	if (tch->ch_id == SDIO_RPC)
+		tch->packet_length = 128;
+	tch->timer_interval_ms = 0;
+
+	return 0;
+}
+
+static void set_pseudo_random_seed(void)
+{
+	/* Set the seed accoring to the kernel command parameters if any or
+	   get a random value */
+	if (seed != 0) {
+		test_ctx->lpm_pseudo_random_seed = seed;
+	} else {
+		test_ctx->lpm_pseudo_random_seed =
+			(unsigned int)(get_jiffies_64() & 0xFFFF);
+		test_ctx->lpm_pseudo_random_seed =
+			pseudo_random_seed(&test_ctx->lpm_pseudo_random_seed);
+	}
+
+	pr_info(TEST_MODULE_NAME ":%s: seed is %u",
+		   __func__, test_ctx->lpm_pseudo_random_seed);
+}
+
+/*
+   for each channel
+   1. open channel
+   2. close channel
+*/
+static int close_channel_lpm_test(int channel_num)
+{
+	int ret = 0;
+	struct test_channel *tch = NULL;
+	tch = test_ctx->test_ch_arr[channel_num];
+
+	if (!tch) {
+		pr_info(TEST_MODULE_NAME ":%s ch#%d is NULL\n",
+			__func__, channel_num);
+		return 0;
+	}
+
+	ret = open_sdio_ch(tch);
+	if (ret) {
+		pr_err(TEST_MODULE_NAME":%s open channel %s"
+			" failed\n", __func__, tch->name);
+		return ret;
+	} else {
+		pr_info(TEST_MODULE_NAME":%s open channel %s"
+			" success\n", __func__, tch->name);
+	}
+	ret = close_sdio_ch(tch);
+	if (ret) {
+		pr_err(TEST_MODULE_NAME":%s close channel %s"
+				" failed\n", __func__, tch->name);
+		return ret;
+	} else {
+		pr_info(TEST_MODULE_NAME":%s close channel %s"
+				" success\n", __func__, tch->name);
+	}
+
+	tch->is_used = 0;
+
+	return ret;
+}
+
+/**
+ * Write File.
+ *
+ * @note Trigger the test from user space by:
+ * echo 1 > /dev/sdio_al_test
+ *
+ */
+ssize_t test_write(struct file *filp, const char __user *buf, size_t size,
+		   loff_t *f_pos)
+{
+	sdio_al_test_initial_dev_and_chan(test_ctx);
+
+	if (strict_strtol(buf, 10, &test_ctx->testcase))
+		return -EINVAL;
+
+	switch (test_ctx->testcase) {
+	case 98:
+		pr_info(TEST_MODULE_NAME " set runtime debug on");
+		test_ctx->runtime_debug = 1;
+		return size;
+	case 99:
+		pr_info(TEST_MODULE_NAME " set runtime debug off");
+		test_ctx->runtime_debug = 0;
+		return size;
+	default:
+		pr_info(TEST_MODULE_NAME ":Bad Test number = %d.\n",
+			(int)test_ctx->testcase);
+		return size;
+	}
+
+	return size;
+}
+
+/**
+ * Test Channel Init.
+ */
+int test_channel_init(char *name)
+{
+	struct test_channel *test_ch;
+	int ch_id = 0;
+	int ret;
+
+	pr_debug(TEST_MODULE_NAME ":%s.\n", __func__);
+	pr_info(TEST_MODULE_NAME ": init test channel %s.\n", name);
+
+	ch_id = channel_name_to_id(name);
+	pr_debug(TEST_MODULE_NAME ":id = %d.\n", ch_id);
+	if (test_ctx->test_ch_arr[ch_id] == NULL) {
+		test_ch = kzalloc(sizeof(*test_ch), GFP_KERNEL);
+		if (test_ch == NULL) {
+			pr_err(TEST_MODULE_NAME ":kzalloc err for allocating "
+						"test_ch %s.\n",
+			       name);
+			return -ENOMEM;
+		}
+		test_ctx->test_ch_arr[ch_id] = test_ch;
+
+		test_ch->ch_id = ch_id;
+
+		strncpy(test_ch->name, name,
+		       strnlen(name, TEST_CH_NAME_SIZE)-SDIO_TEST_POSTFIX_SIZE);
+
+		test_ch->buf_size = MAX_XFER_SIZE;
+
+		test_ch->buf = kzalloc(test_ch->buf_size, GFP_KERNEL);
+		if (test_ch->buf == NULL) {
+			kfree(test_ch);
+			test_ctx->test_ch = NULL;
+			return -ENOMEM;
+		}
+
+		if (test_ch->ch_id == SDIO_SMEM) {
+			test_ctx->smem_buf = kzalloc(SMEM_MAX_XFER_SIZE,
+						     GFP_KERNEL);
+			if (test_ctx->smem_buf == NULL) {
+				pr_err(TEST_MODULE_NAME ":%s: Unable to "
+							"allocate smem buf\n",
+				       __func__);
+				kfree(test_ch);
+				test_ctx->test_ch = NULL;
+				return -ENOMEM;
+			}
+
+#ifdef CONFIG_MSM_SDIO_SMEM
+			ret = platform_driver_register(&sdio_smem_client_drv);
+			if (ret) {
+				pr_err(TEST_MODULE_NAME ":%s: Unable to "
+							"register sdio smem "
+							"test client\n",
+				       __func__);
+				return ret;
+			}
+#endif
+		} else {
+			test_ch->workqueue =
+				create_singlethread_workqueue(test_ch->name);
+			test_ch->test_work.test_ch = test_ch;
+			INIT_WORK(&test_ch->test_work.work, worker);
+
+			init_waitqueue_head(&test_ch->wait_q);
+		}
+	} else {
+		test_ch = test_ctx->test_ch_arr[ch_id];
+		pr_info(TEST_MODULE_NAME ":%s: ch %s was detected again\n",
+			__func__, test_ch->name);
+		test_ch->card_removed = 0;
+		if ((test_ch->is_used) &&
+		    (test_ch->test_type == SDIO_TEST_MODEM_RESET)) {
+			if (test_ch->ch_id == SDIO_SMEM) {
+#ifdef CONFIG_MSM_SDIO_SMEM
+				ret = add_sdio_smem();
+				if (ret) {
+					test_ch->ch_ready = false;
+					return 0;
+				}
+#endif
+			} else {
+				ret = open_sdio_ch(test_ch);
+				if (ret) {
+					pr_info(TEST_MODULE_NAME
+						":%s: open channel %s failed\n",
+					__func__, test_ch->name);
+					return 0;
+				}
+				ret = sdio_test_find_dev(test_ch);
+
+				if (ret) {
+					pr_err(TEST_MODULE_NAME ": %s - "
+					       "sdio_test_find_dev() returned "
+					       "with error", __func__);
+					return -ENODEV;
+				}
+
+				test_ch->sdio_al_device =
+					test_ch->ch->sdio_al_dev;
+			}
+			atomic_set(&test_ch->card_detected_event, 1);
+			wake_up(&test_ch->wait_q);
+		}
+	}
+
+	return 0;
+}
+
+static int sdio_test_channel_probe(struct platform_device *pdev)
+{
+	if (!pdev)
+		return -EIO;
+	return test_channel_init((char *)pdev->name);
+}
+
+static int sdio_test_channel_remove(struct platform_device *pdev)
+{
+	int ch_id;
+
+	if (!pdev)
+		return -EIO;
+
+	ch_id = channel_name_to_id((char *)pdev->name);
+	if (test_ctx->test_ch_arr[ch_id] == NULL)
+		return 0;
+
+	pr_info(TEST_MODULE_NAME "%s: remove ch %s\n",
+		__func__, test_ctx->test_ch_arr[ch_id]->name);
+
+	if ((ch_id == SDIO_SMEM) && (test_ctx->smem_pdev)) {
+		platform_device_unregister(test_ctx->smem_pdev);
+		test_ctx->smem_pdev = NULL;
+	}
+
+	test_ctx->test_ch_arr[ch_id]->ch_ready = 0;
+	test_ctx->test_ch_arr[ch_id]->card_removed = 1;
+
+	return 0;
+
+}
+
+static int sdio_test_channel_csvt_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+
+	if (!pdev)
+		return -ENODEV;
+
+	test_ctx->csvt_app_pdev = platform_device_alloc("SDIO_CSVT_TEST_APP",
+							-1);
+	ret = platform_device_add(test_ctx->csvt_app_pdev);
+		if (ret) {
+			pr_err(MODULE_NAME ":platform_device_add failed, "
+					   "ret=%d\n", ret);
+			return ret;
+		}
+
+	return sdio_test_channel_probe(pdev);
+}
+
+static int sdio_test_channel_csvt_remove(struct platform_device *pdev)
+{
+	if (!pdev)
+		return -ENODEV;
+
+	platform_device_unregister(test_ctx->csvt_app_pdev);
+
+	return sdio_test_channel_remove(pdev);
+}
+
+static struct platform_driver sdio_rpc_drv = {
+	.probe		= sdio_test_channel_probe,
+	.remove		= sdio_test_channel_remove,
+	.driver		= {
+		.name	= "SDIO_RPC_TEST",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static struct platform_driver sdio_qmi_drv = {
+	.probe		= sdio_test_channel_probe,
+	.remove		= sdio_test_channel_remove,
+	.driver		= {
+		.name	= "SDIO_QMI_TEST",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static struct platform_driver sdio_diag_drv = {
+	.probe		= sdio_test_channel_probe,
+	.remove		= sdio_test_channel_remove,
+	.driver		= {
+		.name	= "SDIO_DIAG_TEST",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static struct platform_driver sdio_smem_drv = {
+	.probe		= sdio_test_channel_probe,
+	.remove		= sdio_test_channel_remove,
+	.driver		= {
+		.name	= "SDIO_SMEM_TEST",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static struct platform_driver sdio_rmnt_drv = {
+	.probe		= sdio_test_channel_probe,
+	.remove		= sdio_test_channel_remove,
+	.driver		= {
+		.name	= "SDIO_RMNT_TEST",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static struct platform_driver sdio_dun_drv = {
+	.probe		= sdio_test_channel_probe,
+	.remove		= sdio_test_channel_remove,
+	.driver		= {
+		.name	= "SDIO_DUN_TEST",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static struct platform_driver sdio_csvt_drv = {
+	.probe		= sdio_test_channel_csvt_probe,
+	.remove		= sdio_test_channel_csvt_remove,
+	.driver		= {
+		.name	= "SDIO_CSVT_TEST",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static struct class *test_class;
+
+const struct file_operations test_fops = {
+	.owner = THIS_MODULE,
+	.write = test_write,
+};
+
+/**
+ * Module Init.
+ */
+static int __init test_init(void)
+{
+	int ret;
+
+	pr_debug(TEST_MODULE_NAME ":test_init.\n");
+
+	test_ctx = kzalloc(sizeof(struct test_context), GFP_KERNEL);
+
+	if (test_ctx == NULL) {
+		pr_err(TEST_MODULE_NAME ":kzalloc err.\n");
+		return -ENOMEM;
+	}
+	test_ctx->test_ch = NULL;
+	test_ctx->signature = TEST_SIGNATURE;
+
+	test_ctx->name = "UNKNOWN";
+
+	init_waitqueue_head(&test_ctx->wait_q);
+
+#ifdef CONFIG_DEBUG_FS
+	sdio_al_test_debugfs_init();
+#endif
+
+	test_class = class_create(THIS_MODULE, TEST_MODULE_NAME);
+
+	ret = alloc_chrdev_region(&test_ctx->dev_num, 0, 1, TEST_MODULE_NAME);
+	if (ret) {
+		pr_err(TEST_MODULE_NAME "alloc_chrdev_region err.\n");
+		return -ENODEV;
+	}
+
+	test_ctx->dev = device_create(test_class, NULL, test_ctx->dev_num,
+				      test_ctx, TEST_MODULE_NAME);
+	if (IS_ERR(test_ctx->dev)) {
+		pr_err(TEST_MODULE_NAME ":device_create err.\n");
+		return -ENODEV;
+	}
+
+	test_ctx->cdev = cdev_alloc();
+	if (test_ctx->cdev == NULL) {
+		pr_err(TEST_MODULE_NAME ":cdev_alloc err.\n");
+		return -ENODEV;
+	}
+	cdev_init(test_ctx->cdev, &test_fops);
+	test_ctx->cdev->owner = THIS_MODULE;
+
+	ret = cdev_add(test_ctx->cdev, test_ctx->dev_num, 1);
+	if (ret)
+		pr_err(TEST_MODULE_NAME ":cdev_add err=%d\n", -ret);
+	else
+		pr_debug(TEST_MODULE_NAME ":SDIO-AL-Test init OK..\n");
+
+	platform_driver_register(&sdio_rpc_drv);
+	platform_driver_register(&sdio_qmi_drv);
+	platform_driver_register(&sdio_diag_drv);
+	platform_driver_register(&sdio_smem_drv);
+	platform_driver_register(&sdio_rmnt_drv);
+	platform_driver_register(&sdio_dun_drv);
+	platform_driver_register(&sdio_csvt_drv);
+
+	return ret;
+}
+
+/**
+ * Module Exit.
+ */
+static void __exit test_exit(void)
+{
+	int i;
+
+	pr_debug(TEST_MODULE_NAME ":test_exit.\n");
+
+	test_ctx->exit_flag = true;
+
+	msleep(100); /* allow gracefully exit of the worker thread */
+
+	cdev_del(test_ctx->cdev);
+	device_destroy(test_class, test_ctx->dev_num);
+	unregister_chrdev_region(test_ctx->dev_num, 1);
+
+	platform_driver_unregister(&sdio_rpc_drv);
+	platform_driver_unregister(&sdio_qmi_drv);
+	platform_driver_unregister(&sdio_diag_drv);
+	platform_driver_unregister(&sdio_smem_drv);
+	platform_driver_unregister(&sdio_rmnt_drv);
+	platform_driver_unregister(&sdio_dun_drv);
+	platform_driver_unregister(&sdio_csvt_drv);
+
+	for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
+		struct test_channel *tch = test_ctx->test_ch_arr[i];
+		if (!tch)
+			continue;
+		kfree(tch->buf);
+		kfree(tch);
+	}
+
+#ifdef CONFIG_DEBUG_FS
+	sdio_al_test_debugfs_cleanup();
+#endif
+
+	kfree(test_ctx);
+
+	pr_debug(TEST_MODULE_NAME ":test_exit complete.\n");
+}
+
+module_init(test_init);
+module_exit(test_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("SDIO_AL Test");
+MODULE_AUTHOR("Amir Samuelov <amirs@codeaurora.org>");
+
+
diff --git a/arch/arm/mach-msm/sdio_cmux.c b/arch/arm/mach-msm/sdio_cmux.c
new file mode 100644
index 0000000..d04a0b0
--- /dev/null
+++ b/arch/arm/mach-msm/sdio_cmux.c
@@ -0,0 +1,885 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define DEBUG
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/termios.h>
+#include <linux/debugfs.h>
+#include <linux/moduleparam.h>
+
+#include <mach/sdio_al.h>
+#include <mach/sdio_cmux.h>
+
+#include "modem_notifier.h"
+
+#define MAX_WRITE_RETRY 5
+#define MAGIC_NO_V1 0x33FC
+
+static int msm_sdio_cmux_debug_mask;
+module_param_named(debug_mask, msm_sdio_cmux_debug_mask,
+		   int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+enum cmd_type {
+	DATA = 0,
+	OPEN,
+	CLOSE,
+	STATUS,
+	NUM_CMDS
+};
+
+#define DSR_POS 0x1
+#define CTS_POS 0x2
+#define RI_POS 0x4
+#define CD_POS 0x8
+
+struct sdio_cmux_ch {
+	int lc_id;
+
+	struct mutex lc_lock;
+	wait_queue_head_t open_wait_queue;
+	int is_remote_open;
+	int is_local_open;
+	int is_channel_reset;
+
+	char local_status;
+	char remote_status;
+
+	struct mutex tx_lock;
+	struct list_head tx_list;
+
+	void *priv;
+	void (*receive_cb)(void *, int, void *);
+	void (*write_done)(void *, int, void *);
+	void (*status_callback)(int, void *);
+} logical_ch[SDIO_CMUX_NUM_CHANNELS];
+
+struct sdio_cmux_hdr {
+	uint16_t magic_no;
+	uint8_t status;         /* This field is reserved for commands other
+				 * than STATUS */
+	uint8_t cmd;
+	uint8_t pad_bytes;
+	uint8_t lc_id;
+	uint16_t pkt_len;
+};
+
+struct sdio_cmux_pkt {
+	struct sdio_cmux_hdr *hdr;
+	void *data;
+};
+
+struct sdio_cmux_list_elem {
+	struct list_head list;
+	struct sdio_cmux_pkt cmux_pkt;
+};
+
+#define logical_ch_is_local_open(x)                        \
+	(logical_ch[(x)].is_local_open)
+
+#define logical_ch_is_remote_open(x)                       \
+	(logical_ch[(x)].is_remote_open)
+
+static void sdio_cdemux_fn(struct work_struct *work);
+static DECLARE_WORK(sdio_cdemux_work, sdio_cdemux_fn);
+static struct workqueue_struct *sdio_cdemux_wq;
+
+static DEFINE_MUTEX(write_lock);
+static uint32_t bytes_to_write;
+static DEFINE_MUTEX(temp_rx_lock);
+static LIST_HEAD(temp_rx_list);
+
+static void sdio_cmux_fn(struct work_struct *work);
+static DECLARE_WORK(sdio_cmux_work, sdio_cmux_fn);
+static struct workqueue_struct *sdio_cmux_wq;
+
+static struct sdio_channel *sdio_qmi_chl;
+static uint32_t sdio_cmux_inited;
+
+static uint32_t abort_tx;
+static DEFINE_MUTEX(modem_reset_lock);
+
+static DEFINE_MUTEX(probe_lock);
+
+enum {
+	MSM_SDIO_CMUX_DEBUG = 1U << 0,
+	MSM_SDIO_CMUX_DUMP_BUFFER = 1U << 1,
+};
+
+static struct platform_device sdio_ctl_dev = {
+	.name		= "SDIO_CTL",
+	.id		= -1,
+};
+
+#if defined(DEBUG)
+#define D_DUMP_BUFFER(prestr, cnt, buf) \
+do { \
+	if (msm_sdio_cmux_debug_mask & MSM_SDIO_CMUX_DUMP_BUFFER) { \
+		int i; \
+		pr_debug("%s", prestr); \
+		for (i = 0; i < cnt; i++) \
+			pr_info("%.2x", buf[i]); \
+		pr_debug("\n"); \
+	} \
+} while (0)
+
+#define D(x...) \
+do { \
+	if (msm_sdio_cmux_debug_mask & MSM_SDIO_CMUX_DEBUG) \
+		pr_debug(x); \
+} while (0)
+
+#else
+#define D_DUMP_BUFFER(prestr, cnt, buf) do {} while (0)
+#define D(x...) do {} while (0)
+#endif
+
+static int sdio_cmux_ch_alloc(int id)
+{
+	if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) {
+		pr_err("%s: Invalid lc_id - %d\n", __func__, id);
+		return -EINVAL;
+	}
+
+	logical_ch[id].lc_id = id;
+	mutex_init(&logical_ch[id].lc_lock);
+	init_waitqueue_head(&logical_ch[id].open_wait_queue);
+	logical_ch[id].is_remote_open = 0;
+	logical_ch[id].is_local_open = 0;
+	logical_ch[id].is_channel_reset = 0;
+
+	INIT_LIST_HEAD(&logical_ch[id].tx_list);
+	mutex_init(&logical_ch[id].tx_lock);
+
+	logical_ch[id].priv = NULL;
+	logical_ch[id].receive_cb = NULL;
+	logical_ch[id].write_done = NULL;
+	return 0;
+}
+
+static int sdio_cmux_ch_clear_and_signal(int id)
+{
+	struct sdio_cmux_list_elem *list_elem;
+
+	if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) {
+		pr_err("%s: Invalid lc_id - %d\n", __func__, id);
+		return -EINVAL;
+	}
+
+	mutex_lock(&logical_ch[id].lc_lock);
+	logical_ch[id].is_remote_open = 0;
+	mutex_lock(&logical_ch[id].tx_lock);
+	while (!list_empty(&logical_ch[id].tx_list)) {
+		list_elem = list_first_entry(&logical_ch[id].tx_list,
+					     struct sdio_cmux_list_elem,
+					     list);
+		list_del(&list_elem->list);
+		kfree(list_elem->cmux_pkt.hdr);
+		kfree(list_elem);
+	}
+	mutex_unlock(&logical_ch[id].tx_lock);
+	if (logical_ch[id].receive_cb)
+		logical_ch[id].receive_cb(NULL, 0, logical_ch[id].priv);
+	if (logical_ch[id].write_done)
+		logical_ch[id].write_done(NULL, 0, logical_ch[id].priv);
+	mutex_unlock(&logical_ch[id].lc_lock);
+	wake_up(&logical_ch[id].open_wait_queue);
+	return 0;
+}
+
+static int sdio_cmux_write_cmd(const int id, enum cmd_type type)
+{
+	int write_size = 0;
+	void *write_data = NULL;
+	struct sdio_cmux_list_elem *list_elem;
+
+	if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) {
+		pr_err("%s: Invalid lc_id - %d\n", __func__, id);
+		return -EINVAL;
+	}
+
+	if (type < 0 || type > NUM_CMDS) {
+		pr_err("%s: Invalid cmd - %d\n", __func__, type);
+		return -EINVAL;
+	}
+
+	write_size = sizeof(struct sdio_cmux_hdr);
+	list_elem = kmalloc(sizeof(struct sdio_cmux_list_elem), GFP_KERNEL);
+	if (!list_elem) {
+		pr_err("%s: list_elem alloc failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	write_data = kmalloc(write_size, GFP_KERNEL);
+	if (!write_data) {
+		pr_err("%s: write_data alloc failed\n", __func__);
+		kfree(list_elem);
+		return -ENOMEM;
+	}
+
+	list_elem->cmux_pkt.hdr = (struct sdio_cmux_hdr *)write_data;
+	list_elem->cmux_pkt.data = NULL;
+
+	list_elem->cmux_pkt.hdr->lc_id = (uint8_t)id;
+	list_elem->cmux_pkt.hdr->pkt_len = (uint16_t)0;
+	list_elem->cmux_pkt.hdr->cmd = (uint8_t)type;
+	list_elem->cmux_pkt.hdr->status = (uint8_t)0;
+	if (type == STATUS)
+		list_elem->cmux_pkt.hdr->status = logical_ch[id].local_status;
+	list_elem->cmux_pkt.hdr->pad_bytes = (uint8_t)0;
+	list_elem->cmux_pkt.hdr->magic_no = (uint16_t)MAGIC_NO_V1;
+
+	mutex_lock(&logical_ch[id].tx_lock);
+	list_add_tail(&list_elem->list, &logical_ch[id].tx_list);
+	mutex_unlock(&logical_ch[id].tx_lock);
+
+	mutex_lock(&write_lock);
+	bytes_to_write += write_size;
+	mutex_unlock(&write_lock);
+	queue_work(sdio_cmux_wq, &sdio_cmux_work);
+
+	return 0;
+}
+
+int sdio_cmux_open(const int id,
+		   void (*receive_cb)(void *, int, void *),
+		   void (*write_done)(void *, int, void *),
+		   void (*status_callback)(int, void *),
+		   void *priv)
+{
+	int r;
+	struct sdio_cmux_list_elem *list_elem, *list_elem_tmp;
+
+	if (!sdio_cmux_inited)
+		return -ENODEV;
+	if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) {
+		pr_err("%s: Invalid id - %d\n", __func__, id);
+		return -EINVAL;
+	}
+
+	r = wait_event_timeout(logical_ch[id].open_wait_queue,
+				logical_ch[id].is_remote_open, (1 * HZ));
+	if (r < 0) {
+		pr_err("ERROR %s: wait_event_timeout() failed for"
+		       " ch%d with rc %d\n", __func__, id, r);
+		return r;
+	}
+	if (r == 0) {
+		pr_err("ERROR %s: Wait Timed Out for ch%d\n", __func__, id);
+		return -ETIMEDOUT;
+	}
+
+	mutex_lock(&logical_ch[id].lc_lock);
+	if (!logical_ch[id].is_remote_open) {
+		pr_err("%s: Remote ch%d not opened\n", __func__, id);
+		mutex_unlock(&logical_ch[id].lc_lock);
+		return -EINVAL;
+	}
+	if (logical_ch[id].is_local_open) {
+		mutex_unlock(&logical_ch[id].lc_lock);
+		return 0;
+	}
+	logical_ch[id].is_local_open = 1;
+	logical_ch[id].priv = priv;
+	logical_ch[id].receive_cb = receive_cb;
+	logical_ch[id].write_done = write_done;
+	logical_ch[id].status_callback = status_callback;
+	if (logical_ch[id].receive_cb) {
+		mutex_lock(&temp_rx_lock);
+		list_for_each_entry_safe(list_elem, list_elem_tmp,
+					 &temp_rx_list, list) {
+			if ((int)list_elem->cmux_pkt.hdr->lc_id == id) {
+				logical_ch[id].receive_cb(
+					list_elem->cmux_pkt.data,
+					(int)list_elem->cmux_pkt.hdr->pkt_len,
+					logical_ch[id].priv);
+				list_del(&list_elem->list);
+				kfree(list_elem->cmux_pkt.hdr);
+				kfree(list_elem);
+			}
+		}
+		mutex_unlock(&temp_rx_lock);
+	}
+	mutex_unlock(&logical_ch[id].lc_lock);
+	sdio_cmux_write_cmd(id, OPEN);
+	return 0;
+}
+EXPORT_SYMBOL(sdio_cmux_open);
+
+int sdio_cmux_close(int id)
+{
+	struct sdio_cmux_ch *ch;
+
+	if (!sdio_cmux_inited)
+		return -ENODEV;
+	if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) {
+		pr_err("%s: Invalid channel close\n", __func__);
+		return -EINVAL;
+	}
+
+	ch = &logical_ch[id];
+	mutex_lock(&ch->lc_lock);
+	ch->receive_cb = NULL;
+	mutex_lock(&ch->tx_lock);
+	ch->write_done = NULL;
+	mutex_unlock(&ch->tx_lock);
+	ch->is_local_open = 0;
+	ch->priv = NULL;
+	mutex_unlock(&ch->lc_lock);
+	sdio_cmux_write_cmd(ch->lc_id, CLOSE);
+	return 0;
+}
+EXPORT_SYMBOL(sdio_cmux_close);
+
+int sdio_cmux_write_avail(int id)
+{
+	int write_avail;
+
+	mutex_lock(&logical_ch[id].lc_lock);
+	if (logical_ch[id].is_channel_reset) {
+		mutex_unlock(&logical_ch[id].lc_lock);
+		return -ENETRESET;
+	}
+	mutex_unlock(&logical_ch[id].lc_lock);
+	write_avail = sdio_write_avail(sdio_qmi_chl);
+	return write_avail - bytes_to_write;
+}
+EXPORT_SYMBOL(sdio_cmux_write_avail);
+
+int sdio_cmux_write(int id, void *data, int len)
+{
+	struct sdio_cmux_list_elem *list_elem;
+	uint32_t write_size;
+	void *write_data = NULL;
+	struct sdio_cmux_ch *ch;
+	int ret;
+
+	if (!sdio_cmux_inited)
+		return -ENODEV;
+	if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) {
+		pr_err("%s: Invalid channel id %d\n", __func__, id);
+		return -ENODEV;
+	}
+
+	ch = &logical_ch[id];
+	if (len <= 0) {
+		pr_err("%s: Invalid len %d bytes to write\n",
+			__func__, len);
+		return -EINVAL;
+	}
+
+	write_size = sizeof(struct sdio_cmux_hdr) + len;
+	list_elem = kmalloc(sizeof(struct sdio_cmux_list_elem), GFP_KERNEL);
+	if (!list_elem) {
+		pr_err("%s: list_elem alloc failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	write_data = kmalloc(write_size, GFP_KERNEL);
+	if (!write_data) {
+		pr_err("%s: write_data alloc failed\n", __func__);
+		kfree(list_elem);
+		return -ENOMEM;
+	}
+
+	list_elem->cmux_pkt.hdr = (struct sdio_cmux_hdr *)write_data;
+	list_elem->cmux_pkt.data = (void *)((char *)write_data +
+						sizeof(struct sdio_cmux_hdr));
+	memcpy(list_elem->cmux_pkt.data, data, len);
+
+	list_elem->cmux_pkt.hdr->lc_id = (uint8_t)ch->lc_id;
+	list_elem->cmux_pkt.hdr->pkt_len = (uint16_t)len;
+	list_elem->cmux_pkt.hdr->cmd = (uint8_t)DATA;
+	list_elem->cmux_pkt.hdr->status = (uint8_t)0;
+	list_elem->cmux_pkt.hdr->pad_bytes = (uint8_t)0;
+	list_elem->cmux_pkt.hdr->magic_no = (uint16_t)MAGIC_NO_V1;
+
+	mutex_lock(&ch->lc_lock);
+	if (!ch->is_remote_open || !ch->is_local_open) {
+		pr_err("%s: Local ch%d sending data before sending/receiving"
+		       " OPEN command\n", __func__, ch->lc_id);
+		if (ch->is_channel_reset)
+			ret = -ENETRESET;
+		else
+			ret = -ENODEV;
+		mutex_unlock(&ch->lc_lock);
+		kfree(write_data);
+		kfree(list_elem);
+		return ret;
+	}
+	mutex_lock(&ch->tx_lock);
+	list_add_tail(&list_elem->list, &ch->tx_list);
+	mutex_unlock(&ch->tx_lock);
+	mutex_unlock(&ch->lc_lock);
+
+	mutex_lock(&write_lock);
+	bytes_to_write += write_size;
+	mutex_unlock(&write_lock);
+	queue_work(sdio_cmux_wq, &sdio_cmux_work);
+
+	return len;
+}
+EXPORT_SYMBOL(sdio_cmux_write);
+
+int is_remote_open(int id)
+{
+	if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS)
+		return -ENODEV;
+
+	return logical_ch_is_remote_open(id);
+}
+EXPORT_SYMBOL(is_remote_open);
+
+int sdio_cmux_is_channel_reset(int id)
+{
+	int ret;
+	if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS)
+		return -ENODEV;
+
+	mutex_lock(&logical_ch[id].lc_lock);
+	ret = logical_ch[id].is_channel_reset;
+	mutex_unlock(&logical_ch[id].lc_lock);
+	return ret;
+}
+EXPORT_SYMBOL(sdio_cmux_is_channel_reset);
+
+int sdio_cmux_tiocmget(int id)
+{
+	int ret =  (logical_ch[id].remote_status & DSR_POS ? TIOCM_DSR : 0) |
+		(logical_ch[id].remote_status & CTS_POS ? TIOCM_CTS : 0) |
+		(logical_ch[id].remote_status & CD_POS ? TIOCM_CD : 0) |
+		(logical_ch[id].remote_status & RI_POS ? TIOCM_RI : 0) |
+		(logical_ch[id].local_status & CTS_POS ? TIOCM_RTS : 0) |
+		(logical_ch[id].local_status & DSR_POS ? TIOCM_DTR : 0);
+	return ret;
+}
+EXPORT_SYMBOL(sdio_cmux_tiocmget);
+
+int sdio_cmux_tiocmset(int id, unsigned int set, unsigned int clear)
+{
+	if (set & TIOCM_DTR)
+		logical_ch[id].local_status |= DSR_POS;
+
+	if (set & TIOCM_RTS)
+		logical_ch[id].local_status |= CTS_POS;
+
+	if (clear & TIOCM_DTR)
+		logical_ch[id].local_status &= ~DSR_POS;
+
+	if (clear & TIOCM_RTS)
+		logical_ch[id].local_status &= ~CTS_POS;
+
+	sdio_cmux_write_cmd(id, STATUS);
+	return 0;
+}
+EXPORT_SYMBOL(sdio_cmux_tiocmset);
+
+static int copy_packet(void *pkt, int size)
+{
+	struct sdio_cmux_list_elem *list_elem = NULL;
+	void *temp_pkt = NULL;
+
+	list_elem = kmalloc(sizeof(struct sdio_cmux_list_elem), GFP_KERNEL);
+	if (!list_elem) {
+		pr_err("%s: list_elem alloc failed\n", __func__);
+		return -ENOMEM;
+	}
+	temp_pkt = kmalloc(size, GFP_KERNEL);
+	if (!temp_pkt) {
+		pr_err("%s: temp_pkt alloc failed\n", __func__);
+		kfree(list_elem);
+		return -ENOMEM;
+	}
+
+	memcpy(temp_pkt, pkt, size);
+	list_elem->cmux_pkt.hdr = temp_pkt;
+	list_elem->cmux_pkt.data = (void *)((char *)temp_pkt +
+					    sizeof(struct sdio_cmux_hdr));
+	mutex_lock(&temp_rx_lock);
+	list_add_tail(&list_elem->list, &temp_rx_list);
+	mutex_unlock(&temp_rx_lock);
+	return 0;
+}
+
+static int process_cmux_pkt(void *pkt, int size)
+{
+	struct sdio_cmux_hdr *mux_hdr;
+	uint32_t id, data_size;
+	void *data;
+	char *dump_buf = (char *)pkt;
+
+	D_DUMP_BUFFER("process_cmux_pkt:", size, dump_buf);
+	mux_hdr = (struct sdio_cmux_hdr *)pkt;
+	switch (mux_hdr->cmd) {
+	case OPEN:
+		id = (uint32_t)(mux_hdr->lc_id);
+		D("%s: Received OPEN command for ch%d\n", __func__, id);
+		mutex_lock(&logical_ch[id].lc_lock);
+		logical_ch[id].is_remote_open = 1;
+		if (logical_ch[id].is_channel_reset) {
+			sdio_cmux_write_cmd(id, OPEN);
+			logical_ch[id].is_channel_reset = 0;
+		}
+		mutex_unlock(&logical_ch[id].lc_lock);
+		wake_up(&logical_ch[id].open_wait_queue);
+		break;
+
+	case CLOSE:
+		id = (uint32_t)(mux_hdr->lc_id);
+		D("%s: Received CLOSE command for ch%d\n", __func__, id);
+		sdio_cmux_ch_clear_and_signal(id);
+		break;
+
+	case DATA:
+		id = (uint32_t)(mux_hdr->lc_id);
+		D("%s: Received DATA for ch%d\n", __func__, id);
+		/*Channel is not locally open & if single packet received
+		  then drop it*/
+		mutex_lock(&logical_ch[id].lc_lock);
+		if (!logical_ch[id].is_remote_open) {
+			mutex_unlock(&logical_ch[id].lc_lock);
+			pr_err("%s: Remote Ch%d sent data before sending/"
+			       "receiving OPEN command\n", __func__, id);
+			return -ENODEV;
+		}
+
+		data = (void *)((char *)pkt + sizeof(struct sdio_cmux_hdr));
+		data_size = (int)(((struct sdio_cmux_hdr *)pkt)->pkt_len);
+		if (logical_ch[id].receive_cb)
+			logical_ch[id].receive_cb(data, data_size,
+						logical_ch[id].priv);
+		else
+			copy_packet(pkt, size);
+		mutex_unlock(&logical_ch[id].lc_lock);
+		break;
+
+	case STATUS:
+		id = (uint32_t)(mux_hdr->lc_id);
+		D("%s: Received STATUS command for ch%d\n", __func__, id);
+		if (logical_ch[id].remote_status != mux_hdr->status) {
+			mutex_lock(&logical_ch[id].lc_lock);
+			logical_ch[id].remote_status = mux_hdr->status;
+			mutex_unlock(&logical_ch[id].lc_lock);
+			if (logical_ch[id].status_callback)
+				logical_ch[id].status_callback(
+							sdio_cmux_tiocmget(id),
+							logical_ch[id].priv);
+		}
+		break;
+	}
+	return 0;
+}
+
+static void parse_cmux_data(void *data, int size)
+{
+	int data_parsed = 0, pkt_size;
+	char *temp_ptr;
+
+	D("Entered %s\n", __func__);
+	temp_ptr = (char *)data;
+	while (data_parsed < size) {
+		pkt_size = sizeof(struct sdio_cmux_hdr) +
+			   (int)(((struct sdio_cmux_hdr *)temp_ptr)->pkt_len);
+		D("Parsed %d bytes, Current Pkt Size %d bytes,"
+		  " Total size %d bytes\n", data_parsed, pkt_size, size);
+		process_cmux_pkt((void *)temp_ptr, pkt_size);
+		data_parsed += pkt_size;
+		temp_ptr += pkt_size;
+	}
+
+	kfree(data);
+}
+
+static void sdio_cdemux_fn(struct work_struct *work)
+{
+	int r = 0, read_avail = 0;
+	void *cmux_data;
+
+	while (1) {
+		read_avail = sdio_read_avail(sdio_qmi_chl);
+		if (read_avail < 0) {
+			pr_err("%s: sdio_read_avail failed with rc %d\n",
+				__func__, read_avail);
+			return;
+		}
+
+		if (read_avail == 0) {
+			D("%s: Nothing to read\n", __func__);
+			return;
+		}
+
+		D("%s: kmalloc %d bytes\n", __func__, read_avail);
+		cmux_data = kmalloc(read_avail, GFP_KERNEL);
+		if (!cmux_data) {
+			pr_err("%s: kmalloc Failed\n", __func__);
+			return;
+		}
+
+		D("%s: sdio_read %d bytes\n", __func__, read_avail);
+		r = sdio_read(sdio_qmi_chl, cmux_data, read_avail);
+		if (r < 0) {
+			pr_err("%s: sdio_read failed with rc %d\n",
+				__func__, r);
+			kfree(cmux_data);
+			return;
+		}
+
+		parse_cmux_data(cmux_data, read_avail);
+	}
+	return;
+}
+
+static void sdio_cmux_fn(struct work_struct *work)
+{
+	int i, r = 0;
+	void *write_data;
+	uint32_t write_size, write_avail, write_retry = 0;
+	int bytes_written;
+	struct sdio_cmux_list_elem *list_elem = NULL;
+	struct sdio_cmux_ch *ch;
+
+	for (i = 0; i < SDIO_CMUX_NUM_CHANNELS; ++i) {
+		ch = &logical_ch[i];
+		bytes_written = 0;
+		mutex_lock(&ch->tx_lock);
+		while (!list_empty(&ch->tx_list)) {
+			list_elem = list_first_entry(&ch->tx_list,
+					     struct sdio_cmux_list_elem,
+					     list);
+			list_del(&list_elem->list);
+			mutex_unlock(&ch->tx_lock);
+
+			write_data = (void *)list_elem->cmux_pkt.hdr;
+			write_size = sizeof(struct sdio_cmux_hdr) +
+				(uint32_t)list_elem->cmux_pkt.hdr->pkt_len;
+
+			mutex_lock(&modem_reset_lock);
+			while (!(abort_tx) &&
+				((write_avail = sdio_write_avail(sdio_qmi_chl))
+						< write_size)) {
+				mutex_unlock(&modem_reset_lock);
+				pr_err("%s: sdio_write_avail %d bytes, "
+				       "write size %d bytes. Waiting...\n",
+					__func__, write_avail, write_size);
+				msleep(250);
+				mutex_lock(&modem_reset_lock);
+			}
+			while (!(abort_tx) &&
+				((r = sdio_write(sdio_qmi_chl,
+						write_data, write_size)) < 0)
+				&& (r != -ENODEV)
+				&& (write_retry++ < MAX_WRITE_RETRY)) {
+				mutex_unlock(&modem_reset_lock);
+				pr_err("%s: sdio_write failed with rc %d."
+				       "Retrying...", __func__, r);
+				msleep(250);
+				mutex_lock(&modem_reset_lock);
+			}
+			if (!r && !abort_tx) {
+				D("%s: sdio_write_completed %dbytes\n",
+				  __func__, write_size);
+				bytes_written += write_size;
+			} else if (r == -ENODEV) {
+				pr_err("%s: aborting_tx because sdio_write"
+				       " returned %d\n", __func__, r);
+				r = 0;
+				abort_tx = 1;
+			}
+			mutex_unlock(&modem_reset_lock);
+			kfree(list_elem->cmux_pkt.hdr);
+			kfree(list_elem);
+			mutex_lock(&write_lock);
+			bytes_to_write -= write_size;
+			mutex_unlock(&write_lock);
+			mutex_lock(&ch->tx_lock);
+		}
+		if (ch->write_done)
+			ch->write_done(NULL, bytes_written, ch->priv);
+		mutex_unlock(&ch->tx_lock);
+	}
+	return;
+}
+
+static void sdio_qmi_chl_notify(void *priv, unsigned event)
+{
+	if (event == SDIO_EVENT_DATA_READ_AVAIL) {
+		D("%s: Received SDIO_EVENT_DATA_READ_AVAIL\n", __func__);
+		queue_work(sdio_cdemux_wq, &sdio_cdemux_work);
+	}
+}
+
+#ifdef CONFIG_DEBUG_FS
+
+static int debug_tbl(char *buf, int max)
+{
+	int i = 0;
+	int j;
+
+	for (j = 0; j < SDIO_CMUX_NUM_CHANNELS; ++j) {
+		i += scnprintf(buf + i, max - i,
+			"ch%02d  local open=%s  remote open=%s\n",
+			j, logical_ch_is_local_open(j) ? "Y" : "N",
+			logical_ch_is_remote_open(j) ? "Y" : "N");
+	}
+
+	return i;
+}
+
+#define DEBUG_BUFMAX 4096
+static char debug_buffer[DEBUG_BUFMAX];
+
+static ssize_t debug_read(struct file *file, char __user *buf,
+				size_t count, loff_t *ppos)
+{
+	int (*fill)(char *buf, int max) = file->private_data;
+	int bsize = fill(debug_buffer, DEBUG_BUFMAX);
+	return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+
+static const struct file_operations debug_ops = {
+	.read = debug_read,
+	.open = debug_open,
+};
+
+static void debug_create(const char *name, mode_t mode,
+				struct dentry *dent,
+				int (*fill)(char *buf, int max))
+{
+	debugfs_create_file(name, mode, dent, fill, &debug_ops);
+}
+
+#endif
+
+static int sdio_cmux_probe(struct platform_device *pdev)
+{
+	int i, r;
+
+	mutex_lock(&probe_lock);
+	D("%s Begins\n", __func__);
+	if (sdio_cmux_inited) {
+		mutex_lock(&modem_reset_lock);
+		r =  sdio_open("SDIO_QMI", &sdio_qmi_chl, NULL,
+				sdio_qmi_chl_notify);
+		if (r < 0) {
+			mutex_unlock(&modem_reset_lock);
+			pr_err("%s: sdio_open() failed\n", __func__);
+			goto error0;
+		}
+		abort_tx = 0;
+		mutex_unlock(&modem_reset_lock);
+		mutex_unlock(&probe_lock);
+		return 0;
+	}
+
+	for (i = 0; i < SDIO_CMUX_NUM_CHANNELS; ++i)
+		sdio_cmux_ch_alloc(i);
+	INIT_LIST_HEAD(&temp_rx_list);
+
+	sdio_cmux_wq = create_singlethread_workqueue("sdio_cmux");
+	if (IS_ERR(sdio_cmux_wq)) {
+		pr_err("%s: create_singlethread_workqueue() ENOMEM\n",
+			__func__);
+		r = -ENOMEM;
+		goto error0;
+	}
+
+	sdio_cdemux_wq = create_singlethread_workqueue("sdio_cdemux");
+	if (IS_ERR(sdio_cdemux_wq)) {
+		pr_err("%s: create_singlethread_workqueue() ENOMEM\n",
+			__func__);
+		r = -ENOMEM;
+		goto error1;
+	}
+
+	r = sdio_open("SDIO_QMI", &sdio_qmi_chl, NULL, sdio_qmi_chl_notify);
+	if (r < 0) {
+		pr_err("%s: sdio_open() failed\n", __func__);
+		goto error2;
+	}
+
+	platform_device_register(&sdio_ctl_dev);
+	sdio_cmux_inited = 1;
+	D("SDIO Control MUX Driver Initialized.\n");
+	mutex_unlock(&probe_lock);
+	return 0;
+
+error2:
+	destroy_workqueue(sdio_cdemux_wq);
+error1:
+	destroy_workqueue(sdio_cmux_wq);
+error0:
+	mutex_unlock(&probe_lock);
+	return r;
+}
+
+static int sdio_cmux_remove(struct platform_device *pdev)
+{
+	int i;
+
+	mutex_lock(&modem_reset_lock);
+	abort_tx = 1;
+
+	for (i = 0; i < SDIO_CMUX_NUM_CHANNELS; ++i) {
+		mutex_lock(&logical_ch[i].lc_lock);
+		logical_ch[i].is_channel_reset = 1;
+		mutex_unlock(&logical_ch[i].lc_lock);
+		sdio_cmux_ch_clear_and_signal(i);
+	}
+	sdio_qmi_chl = NULL;
+	mutex_unlock(&modem_reset_lock);
+
+	return 0;
+}
+
+static struct platform_driver sdio_cmux_driver = {
+	.probe          = sdio_cmux_probe,
+	.remove         = sdio_cmux_remove,
+	.driver         = {
+			.name   = "SDIO_QMI",
+			.owner  = THIS_MODULE,
+	},
+};
+
+static int __init sdio_cmux_init(void)
+{
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dent;
+
+	dent = debugfs_create_dir("sdio_cmux", 0);
+	if (!IS_ERR(dent))
+		debug_create("tbl", 0444, dent, debug_tbl);
+#endif
+
+	msm_sdio_cmux_debug_mask = 0;
+	return platform_driver_register(&sdio_cmux_driver);
+}
+
+module_init(sdio_cmux_init);
+MODULE_DESCRIPTION("MSM SDIO Control MUX");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/sdio_ctl.c b/arch/arm/mach-msm/sdio_ctl.c
new file mode 100644
index 0000000..586e890
--- /dev/null
+++ b/arch/arm/mach-msm/sdio_ctl.c
@@ -0,0 +1,545 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * SDIO Control Driver -- Provides a binary SDIO muxed control port
+ *                       interface.
+ */
+
+#include <linux/cdev.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <linux/workqueue.h>
+#include <asm/ioctls.h>
+#include <linux/platform_device.h>
+#include <mach/msm_smd.h>
+#include <mach/sdio_al.h>
+#include <mach/sdio_cmux.h>
+#include "modem_notifier.h"
+#include <linux/slab.h>
+
+#define MAX_WRITE_RETRY 5
+#define MAGIC_NO_V1 0x33FC
+#define NUM_SDIO_CTL_PORTS 10
+#define DEVICE_NAME "sdioctl"
+#define MAX_BUF_SIZE 2048
+#define DEBUG
+
+static int msm_sdio_ctl_debug_mask;
+module_param_named(debug_mask, msm_sdio_ctl_debug_mask,
+		   int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+struct sdio_ctl_dev {
+	int id;
+	char name[9];
+	struct cdev cdev;
+	struct device *devicep;
+	struct mutex dev_lock;
+	int ref_count;
+
+	struct mutex rx_lock;
+	uint32_t read_avail;
+	struct list_head rx_list;
+
+	wait_queue_head_t read_wait_queue;
+	wait_queue_head_t write_wait_queue;
+} *sdio_ctl_devp[NUM_SDIO_CTL_PORTS];
+
+struct sdio_ctl_pkt {
+	int data_size;
+	void *data;
+};
+
+struct sdio_ctl_list_elem {
+	struct list_head list;
+	struct sdio_ctl_pkt ctl_pkt;
+};
+
+struct class *sdio_ctl_classp;
+static dev_t sdio_ctl_number;
+static uint32_t sdio_ctl_inited;
+
+enum {
+	MSM_SDIO_CTL_DEBUG = 1U << 0,
+	MSM_SDIO_CTL_DUMP_BUFFER = 1U << 1,
+};
+
+#if defined(DEBUG)
+#define D_DUMP_BUFFER(prestr, cnt, buf) \
+do { \
+	if (msm_sdio_ctl_debug_mask & MSM_SDIO_CTL_DUMP_BUFFER) { \
+		int i; \
+		pr_info("%s", prestr); \
+		for (i = 0; i < cnt; i++) \
+			pr_info("%.2x", buf[i]); \
+		pr_info("\n"); \
+	} \
+} while (0)
+
+#define D(x...) \
+do { \
+	if (msm_sdio_ctl_debug_mask & MSM_SDIO_CTL_DEBUG) \
+		pr_info(x); \
+} while (0)
+
+#else
+#define D_DUMP_BUFFER(prestr, cnt, buf) do {} while (0)
+#define D(x...) do {} while (0)
+#endif
+
+static uint32_t cmux_ch_id[] = {
+	SDIO_CMUX_DATA_CTL_0,
+	SDIO_CMUX_DATA_CTL_1,
+	SDIO_CMUX_DATA_CTL_2,
+	SDIO_CMUX_DATA_CTL_3,
+	SDIO_CMUX_DATA_CTL_4,
+	SDIO_CMUX_DATA_CTL_5,
+	SDIO_CMUX_DATA_CTL_6,
+	SDIO_CMUX_DATA_CTL_7,
+	SDIO_CMUX_USB_CTL_0,
+	SDIO_CMUX_CSVT_CTL_0
+};
+
+static int get_ctl_dev_index(int id)
+{
+	int dev_index;
+	for (dev_index = 0; dev_index < NUM_SDIO_CTL_PORTS; dev_index++) {
+		if (cmux_ch_id[dev_index] == id)
+			return dev_index;
+	}
+	return -ENODEV;
+}
+
+static void sdio_ctl_receive_cb(void *data, int size, void *priv)
+{
+	struct sdio_ctl_list_elem *list_elem = NULL;
+	int id = ((struct sdio_ctl_dev *)(priv))->id;
+	int dev_index;
+
+	if (id < 0 || id > cmux_ch_id[NUM_SDIO_CTL_PORTS - 1])
+		return;
+	dev_index = get_ctl_dev_index(id);
+	if (dev_index < 0) {
+		pr_err("%s: Ch%d is not exported to user-space\n",
+			__func__, id);
+		return;
+	}
+
+	if (!data || size <= 0) {
+		wake_up(&sdio_ctl_devp[dev_index]->read_wait_queue);
+		return;
+	}
+
+	list_elem = kmalloc(sizeof(struct sdio_ctl_list_elem), GFP_KERNEL);
+	if (!list_elem) {
+		pr_err("%s: list_elem alloc failed\n", __func__);
+		return;
+	}
+
+	list_elem->ctl_pkt.data = kmalloc(size, GFP_KERNEL);
+	if (!list_elem->ctl_pkt.data) {
+		pr_err("%s: list_elem->data alloc failed\n", __func__);
+		kfree(list_elem);
+		return;
+	}
+	memcpy(list_elem->ctl_pkt.data, data, size);
+	list_elem->ctl_pkt.data_size = size;
+	mutex_lock(&sdio_ctl_devp[dev_index]->rx_lock);
+	list_add_tail(&list_elem->list, &sdio_ctl_devp[dev_index]->rx_list);
+	sdio_ctl_devp[dev_index]->read_avail += size;
+	mutex_unlock(&sdio_ctl_devp[dev_index]->rx_lock);
+	wake_up(&sdio_ctl_devp[dev_index]->read_wait_queue);
+}
+
+static void sdio_ctl_write_done(void *data, int size, void *priv)
+{
+	int id = ((struct sdio_ctl_dev *)(priv))->id;
+	int dev_index;
+	if (id < 0 || id > cmux_ch_id[NUM_SDIO_CTL_PORTS - 1])
+		return;
+
+	dev_index = get_ctl_dev_index(id);
+	if (dev_index < 0) {
+		pr_err("%s: Ch%d is not exported to user-space\n",
+			__func__, id);
+		return;
+	}
+	wake_up(&sdio_ctl_devp[dev_index]->write_wait_queue);
+}
+
+static long sdio_ctl_ioctl(struct file *file, unsigned int cmd,
+					      unsigned long arg)
+{
+	int ret;
+	struct sdio_ctl_dev *sdio_ctl_devp;
+
+	sdio_ctl_devp = file->private_data;
+	if (!sdio_ctl_devp)
+		return -ENODEV;
+
+	switch (cmd) {
+	case TIOCMGET:
+		ret = sdio_cmux_tiocmget(sdio_ctl_devp->id);
+		break;
+	case TIOCMSET:
+		ret = sdio_cmux_tiocmset(sdio_ctl_devp->id, arg, ~arg);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+ssize_t sdio_ctl_read(struct file *file,
+		      char __user *buf,
+		      size_t count,
+		      loff_t *ppos)
+{
+	int r = 0, id, bytes_to_read;
+	struct sdio_ctl_dev *sdio_ctl_devp;
+	struct sdio_ctl_list_elem *list_elem = NULL;
+
+	sdio_ctl_devp = file->private_data;
+
+	if (!sdio_ctl_devp)
+		return -ENODEV;
+
+	D("%s: read from ch%d\n", __func__, sdio_ctl_devp->id);
+
+	id = sdio_ctl_devp->id;
+	mutex_lock(&sdio_ctl_devp->rx_lock);
+	while (sdio_ctl_devp->read_avail <= 0) {
+		mutex_unlock(&sdio_ctl_devp->rx_lock);
+		r = wait_event_interruptible(sdio_ctl_devp->read_wait_queue,
+					     sdio_ctl_devp->read_avail > 0 ||
+					     !is_remote_open(id));
+		if (sdio_cmux_is_channel_reset(id))
+			return -ENETRESET;
+
+		if (!is_remote_open(id))
+			return -ENODEV;
+
+		if (r < 0) {
+			/* qualify error message */
+			/* we get this anytime a signal comes in */
+			if (r != -ERESTARTSYS)
+				pr_err("ERROR:%s: wait_event_interruptible "
+				       "ret %i\n", __func__, r);
+			return r;
+		}
+		mutex_lock(&sdio_ctl_devp->rx_lock);
+	}
+
+	if (list_empty(&sdio_ctl_devp->rx_list)) {
+		mutex_unlock(&sdio_ctl_devp->rx_lock);
+		D("%s: Nothing in ch%d's rx_list\n", __func__,
+		  sdio_ctl_devp->id);
+		return -EAGAIN;
+	}
+
+	list_elem = list_first_entry(&sdio_ctl_devp->rx_list,
+				     struct sdio_ctl_list_elem, list);
+	bytes_to_read = (uint32_t)(list_elem->ctl_pkt.data_size);
+	if (bytes_to_read > count) {
+		mutex_unlock(&sdio_ctl_devp->rx_lock);
+		pr_err("%s: Packet size %d > buf size %d\n", __func__,
+			bytes_to_read, count);
+		return -ENOMEM;
+	}
+
+	if (copy_to_user(buf, list_elem->ctl_pkt.data, bytes_to_read)) {
+		mutex_unlock(&sdio_ctl_devp->rx_lock);
+		pr_err("%s: copy_to_user failed for ch%d\n", __func__,
+			sdio_ctl_devp->id);
+		return -EFAULT;
+	}
+	sdio_ctl_devp->read_avail -= bytes_to_read;
+	list_del(&list_elem->list);
+	kfree(list_elem->ctl_pkt.data);
+	kfree(list_elem);
+	mutex_unlock(&sdio_ctl_devp->rx_lock);
+	D("%s: Returning %d bytes to ch%d\n", __func__,
+			bytes_to_read, sdio_ctl_devp->id);
+	return bytes_to_read;
+}
+
+
+ssize_t sdio_ctl_write(struct file *file,
+		       const char __user *buf,
+		       size_t count,
+		       loff_t *ppos)
+{
+	int r = 0, id;
+	char *temp_buf;
+	struct sdio_ctl_dev *sdio_ctl_devp;
+
+	if (count <= 0)
+		return -EINVAL;
+
+	sdio_ctl_devp = file->private_data;
+	if (!sdio_ctl_devp)
+		return -ENODEV;
+
+	D("%s: writing %i bytes on ch%d\n",
+	  __func__, count, sdio_ctl_devp->id);
+	id = sdio_ctl_devp->id;
+	mutex_lock(&sdio_ctl_devp->dev_lock);
+	while (sdio_cmux_write_avail(id) < count) {
+		mutex_unlock(&sdio_ctl_devp->dev_lock);
+		r = wait_event_interruptible(sdio_ctl_devp->write_wait_queue,
+					     sdio_cmux_write_avail(id) >= count
+					     || !is_remote_open(id));
+
+		if (sdio_cmux_is_channel_reset(id))
+			return -ENETRESET;
+
+		if (!is_remote_open(id))
+			return -ENODEV;
+
+		if (r < 0) {
+			/* qualify error message */
+			/* we get this anytime a signal comes in */
+			if (r != -ERESTARTSYS)
+				pr_err("ERROR:%s: wait_event_interruptible "
+				       "ret %i\n", __func__, r);
+			return r;
+		}
+		mutex_lock(&sdio_ctl_devp->dev_lock);
+	}
+
+	temp_buf = kmalloc(count, GFP_KERNEL);
+	if (!temp_buf) {
+		mutex_unlock(&sdio_ctl_devp->dev_lock);
+		pr_err("%s: temp_buf alloc failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	if (copy_from_user(temp_buf, buf, count)) {
+		mutex_unlock(&sdio_ctl_devp->dev_lock);
+		pr_err("%s: copy_from_user failed\n", __func__);
+		kfree(temp_buf);
+		return -EFAULT;
+	}
+
+	r = sdio_cmux_write(id, (void *)temp_buf, count);
+	kfree(temp_buf);
+	mutex_unlock(&sdio_ctl_devp->dev_lock);
+	return r;
+}
+
+
+int sdio_ctl_open(struct inode *inode, struct file *file)
+{
+	int r = 0;
+	struct sdio_ctl_dev *sdio_ctl_devp;
+
+	if (!sdio_ctl_inited)
+		return -EIO;
+
+	sdio_ctl_devp = container_of(inode->i_cdev, struct sdio_ctl_dev, cdev);
+
+	if (!sdio_ctl_devp)
+		return -ENODEV;
+
+	D("%s called on sdioctl%d device\n", __func__, sdio_ctl_devp->id);
+	r = sdio_cmux_open(sdio_ctl_devp->id, sdio_ctl_receive_cb,
+			   sdio_ctl_write_done, NULL,
+			   sdio_ctl_devp);
+	if (r < 0) {
+		pr_err("ERROR %s: sdio_cmux_open failed with rc %d\n",
+			__func__, r);
+		return r;
+	}
+
+	mutex_lock(&sdio_ctl_devp->dev_lock);
+	sdio_ctl_devp->ref_count++;
+	mutex_unlock(&sdio_ctl_devp->dev_lock);
+
+	file->private_data = sdio_ctl_devp;
+	return 0;
+}
+
+int sdio_ctl_release(struct inode *inode, struct file *file)
+{
+	struct sdio_ctl_dev *sdio_ctl_devp;
+	struct sdio_ctl_list_elem *list_elem = NULL;
+
+	sdio_ctl_devp = file->private_data;
+	if (!sdio_ctl_devp)
+		return -EINVAL;
+
+	D("%s called on sdioctl%d device\n", __func__, sdio_ctl_devp->id);
+
+	mutex_lock(&sdio_ctl_devp->dev_lock);
+	if (sdio_ctl_devp->ref_count > 0) {
+		sdio_ctl_devp->ref_count--;
+		if (!sdio_ctl_devp->ref_count) {
+			mutex_lock(&sdio_ctl_devp->rx_lock);
+			while (!list_empty(&sdio_ctl_devp->rx_list)) {
+				list_elem = list_first_entry(
+						&sdio_ctl_devp->rx_list,
+						struct sdio_ctl_list_elem,
+						list);
+				list_del(&list_elem->list);
+				kfree(list_elem->ctl_pkt.data);
+				kfree(list_elem);
+			}
+			sdio_ctl_devp->read_avail = 0;
+			mutex_unlock(&sdio_ctl_devp->rx_lock);
+			sdio_cmux_close(sdio_ctl_devp->id);
+		}
+	}
+	mutex_unlock(&sdio_ctl_devp->dev_lock);
+
+	file->private_data = NULL;
+	return 0;
+}
+
+static const struct file_operations sdio_ctl_fops = {
+	.owner = THIS_MODULE,
+	.open = sdio_ctl_open,
+	.release = sdio_ctl_release,
+	.read = sdio_ctl_read,
+	.write = sdio_ctl_write,
+	.unlocked_ioctl = sdio_ctl_ioctl,
+};
+
+static int sdio_ctl_probe(struct platform_device *pdev)
+{
+	int i;
+	int r;
+
+	pr_info("%s Begins\n", __func__);
+	for (i = 0; i < NUM_SDIO_CTL_PORTS; ++i) {
+		sdio_ctl_devp[i] = kzalloc(sizeof(struct sdio_ctl_dev),
+					GFP_KERNEL);
+		if (IS_ERR(sdio_ctl_devp[i])) {
+			pr_err("ERROR:%s kmalloc() ENOMEM\n", __func__);
+			r = -ENOMEM;
+			goto error0;
+		}
+
+		sdio_ctl_devp[i]->id = cmux_ch_id[i];
+		sdio_ctl_devp[i]->ref_count = 0;
+
+		mutex_init(&sdio_ctl_devp[i]->dev_lock);
+		init_waitqueue_head(&sdio_ctl_devp[i]->read_wait_queue);
+		init_waitqueue_head(&sdio_ctl_devp[i]->write_wait_queue);
+		mutex_init(&sdio_ctl_devp[i]->rx_lock);
+		INIT_LIST_HEAD(&sdio_ctl_devp[i]->rx_list);
+		sdio_ctl_devp[i]->read_avail = 0;
+	}
+
+	r = alloc_chrdev_region(&sdio_ctl_number, 0, NUM_SDIO_CTL_PORTS,
+				DEVICE_NAME);
+	if (IS_ERR_VALUE(r)) {
+		pr_err("ERROR:%s: alloc_chrdev_region() ret %i.\n",
+		       __func__, r);
+		goto error0;
+	}
+
+	sdio_ctl_classp = class_create(THIS_MODULE, DEVICE_NAME);
+	if (IS_ERR(sdio_ctl_classp)) {
+		pr_err("ERROR:%s: class_create() ENOMEM\n", __func__);
+		r = -ENOMEM;
+		goto error1;
+	}
+
+	for (i = 0; i < NUM_SDIO_CTL_PORTS; ++i) {
+		cdev_init(&sdio_ctl_devp[i]->cdev, &sdio_ctl_fops);
+		sdio_ctl_devp[i]->cdev.owner = THIS_MODULE;
+
+		r = cdev_add(&sdio_ctl_devp[i]->cdev, (sdio_ctl_number + i),
+			     1);
+
+		if (IS_ERR_VALUE(r)) {
+			pr_err("%s: cdev_add() ret %i\n", __func__, r);
+			kfree(sdio_ctl_devp[i]);
+			goto error2;
+		}
+
+		sdio_ctl_devp[i]->devicep =
+				device_create(sdio_ctl_classp, NULL,
+				      (sdio_ctl_number + i), NULL,
+				      DEVICE_NAME "%d", cmux_ch_id[i]);
+
+		if (IS_ERR(sdio_ctl_devp[i]->devicep)) {
+			pr_err("%s: device_create() ENOMEM\n", __func__);
+			r = -ENOMEM;
+			cdev_del(&sdio_ctl_devp[i]->cdev);
+			kfree(sdio_ctl_devp[i]);
+			goto error2;
+		}
+	}
+
+	sdio_ctl_inited = 1;
+	D("SDIO Control Port Driver Initialized.\n");
+	return 0;
+
+error2:
+	while (--i >= 0) {
+		cdev_del(&sdio_ctl_devp[i]->cdev);
+		device_destroy(sdio_ctl_classp,
+			       MKDEV(MAJOR(sdio_ctl_number), i));
+	}
+
+	class_destroy(sdio_ctl_classp);
+	i = NUM_SDIO_CTL_PORTS;
+error1:
+	unregister_chrdev_region(MAJOR(sdio_ctl_number), NUM_SDIO_CTL_PORTS);
+error0:
+	while (--i >= 0)
+		kfree(sdio_ctl_devp[i]);
+	return r;
+}
+
+static int sdio_ctl_remove(struct platform_device *pdev)
+{
+	int i;
+
+	for (i = 0; i < NUM_SDIO_CTL_PORTS; ++i) {
+		cdev_del(&sdio_ctl_devp[i]->cdev);
+		kfree(sdio_ctl_devp[i]);
+		device_destroy(sdio_ctl_classp,
+			       MKDEV(MAJOR(sdio_ctl_number), i));
+	}
+	class_destroy(sdio_ctl_classp);
+	unregister_chrdev_region(MAJOR(sdio_ctl_number), NUM_SDIO_CTL_PORTS);
+
+	return 0;
+}
+
+static struct platform_driver sdio_ctl_driver = {
+	.probe		= sdio_ctl_probe,
+	.remove		= sdio_ctl_remove,
+	.driver		= {
+			.name	= "SDIO_CTL",
+			.owner	= THIS_MODULE,
+	},
+};
+
+static int __init sdio_ctl_init(void)
+{
+	msm_sdio_ctl_debug_mask = 0;
+	return platform_driver_register(&sdio_ctl_driver);
+}
+
+module_init(sdio_ctl_init);
+MODULE_DESCRIPTION("MSM SDIO Control Port");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/sdio_dmux.c b/arch/arm/mach-msm/sdio_dmux.c
new file mode 100644
index 0000000..71b4e9b
--- /dev/null
+++ b/arch/arm/mach-msm/sdio_dmux.c
@@ -0,0 +1,925 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/*
+ *  SDIO DMUX module.
+ */
+
+#define DEBUG
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/skbuff.h>
+#include <linux/wakelock.h>
+#include <linux/debugfs.h>
+#include <linux/smp.h>
+#include <linux/cpumask.h>
+
+#include <mach/sdio_al.h>
+#include <mach/sdio_dmux.h>
+
+#define SDIO_CH_LOCAL_OPEN       0x1
+#define SDIO_CH_REMOTE_OPEN      0x2
+#define SDIO_CH_IN_RESET         0x4
+
+#define SDIO_MUX_HDR_MAGIC_NO    0x33fc
+
+#define SDIO_MUX_HDR_CMD_DATA    0
+#define SDIO_MUX_HDR_CMD_OPEN    1
+#define SDIO_MUX_HDR_CMD_CLOSE   2
+
+#define LOW_WATERMARK            2
+#define HIGH_WATERMARK           4
+
+static int msm_sdio_dmux_debug_enable;
+module_param_named(debug_enable, msm_sdio_dmux_debug_enable,
+		   int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#if defined(DEBUG)
+static uint32_t sdio_dmux_read_cnt;
+static uint32_t sdio_dmux_write_cnt;
+static uint32_t sdio_dmux_write_cpy_cnt;
+static uint32_t sdio_dmux_write_cpy_bytes;
+
+#define DBG(x...) do {		                 \
+		if (msm_sdio_dmux_debug_enable)  \
+			pr_debug(x);	         \
+	} while (0)
+
+#define DBG_INC_READ_CNT(x) do {	                               \
+		sdio_dmux_read_cnt += (x);                             \
+		if (msm_sdio_dmux_debug_enable)                        \
+			pr_debug("%s: total read bytes %u\n",          \
+				 __func__, sdio_dmux_read_cnt);        \
+	} while (0)
+
+#define DBG_INC_WRITE_CNT(x)  do {	                               \
+		sdio_dmux_write_cnt += (x);                            \
+		if (msm_sdio_dmux_debug_enable)                        \
+			pr_debug("%s: total written bytes %u\n",       \
+				 __func__, sdio_dmux_write_cnt);       \
+	} while (0)
+
+#define DBG_INC_WRITE_CPY(x)  do {	                                     \
+		sdio_dmux_write_cpy_bytes += (x);                            \
+		sdio_dmux_write_cpy_cnt++;                                   \
+		if (msm_sdio_dmux_debug_enable)                              \
+			pr_debug("%s: total write copy cnt %u, bytes %u\n",  \
+				 __func__, sdio_dmux_write_cpy_cnt,          \
+				 sdio_dmux_write_cpy_bytes);                 \
+	} while (0)
+#else
+#define DBG(x...) do { } while (0)
+#define DBG_INC_READ_CNT(x...) do { } while (0)
+#define DBG_INC_WRITE_CNT(x...) do { } while (0)
+#define DBG_INC_WRITE_CPY(x...) do { } while (0)
+#endif
+
+struct sdio_ch_info {
+	uint32_t status;
+	void (*receive_cb)(void *, struct sk_buff *);
+	void (*write_done)(void *, struct sk_buff *);
+	void *priv;
+	spinlock_t lock;
+	int num_tx_pkts;
+	int use_wm;
+};
+
+static struct sk_buff_head sdio_mux_write_pool;
+static spinlock_t sdio_mux_write_lock;
+
+static struct sdio_channel *sdio_mux_ch;
+static struct sdio_ch_info sdio_ch[SDIO_DMUX_NUM_CHANNELS];
+struct wake_lock sdio_mux_ch_wakelock;
+static int sdio_mux_initialized;
+static int fatal_error;
+
+struct sdio_mux_hdr {
+	uint16_t magic_num;
+	uint8_t reserved;
+	uint8_t cmd;
+	uint8_t pad_len;
+	uint8_t ch_id;
+	uint16_t pkt_len;
+};
+
+struct sdio_partial_pkt_info {
+	uint32_t valid;
+	struct sk_buff *skb;
+	struct sdio_mux_hdr *hdr;
+};
+
+static void sdio_mux_read_data(struct work_struct *work);
+static void sdio_mux_write_data(struct work_struct *work);
+static void sdio_mux_send_open_cmd(uint32_t id);
+
+static DEFINE_MUTEX(sdio_mux_lock);
+static DECLARE_WORK(work_sdio_mux_read, sdio_mux_read_data);
+static DECLARE_WORK(work_sdio_mux_write, sdio_mux_write_data);
+static DECLARE_DELAYED_WORK(delayed_work_sdio_mux_write, sdio_mux_write_data);
+
+static struct workqueue_struct *sdio_mux_workqueue;
+static struct sdio_partial_pkt_info sdio_partial_pkt;
+
+#define sdio_ch_is_open(x)						\
+	(sdio_ch[(x)].status == (SDIO_CH_LOCAL_OPEN | SDIO_CH_REMOTE_OPEN))
+
+#define sdio_ch_is_local_open(x)			\
+	(sdio_ch[(x)].status & SDIO_CH_LOCAL_OPEN)
+
+#define sdio_ch_is_remote_open(x)			\
+	(sdio_ch[(x)].status & SDIO_CH_REMOTE_OPEN)
+
+#define sdio_ch_is_in_reset(x)			\
+	(sdio_ch[(x)].status & SDIO_CH_IN_RESET)
+
+static inline void skb_set_data(struct sk_buff *skb,
+				unsigned char *data,
+				unsigned int len)
+{
+	/* panic if tail > end */
+	skb->data = data;
+	skb->tail = skb->data + len;
+	skb->len  = len;
+	skb->truesize = len + sizeof(struct sk_buff);
+}
+
+static void sdio_mux_save_partial_pkt(struct sdio_mux_hdr *hdr,
+				      struct sk_buff *skb_mux)
+{
+	struct sk_buff *skb;
+
+	/* i think we can avoid cloning here */
+	skb =  skb_clone(skb_mux, GFP_KERNEL);
+	if (!skb) {
+		pr_err("%s: cannot clone skb\n", __func__);
+		return;
+	}
+
+	/* protect? */
+	skb_set_data(skb, (unsigned char *)hdr,
+		     skb->tail - (unsigned char *)hdr);
+	sdio_partial_pkt.skb = skb;
+	sdio_partial_pkt.valid = 1;
+	DBG("%s: head %p data %p tail %p end %p len %d\n", __func__,
+	    skb->head, skb->data, skb->tail, skb->end, skb->len);
+	return;
+}
+
+static void *handle_sdio_mux_data(struct sdio_mux_hdr *hdr,
+				  struct sk_buff *skb_mux)
+{
+	struct sk_buff *skb;
+	void *rp = (void *)hdr;
+	unsigned long flags;
+
+	/* protect? */
+	rp += sizeof(*hdr);
+	if (rp < (void *)skb_mux->tail)
+		rp += (hdr->pkt_len + hdr->pad_len);
+
+	if (rp > (void *)skb_mux->tail) {
+		/* partial packet */
+		sdio_mux_save_partial_pkt(hdr, skb_mux);
+		goto packet_done;
+	}
+
+	DBG("%s: hdr %p next %p tail %p pkt_size %d\n",
+	    __func__, hdr, rp, skb_mux->tail, hdr->pkt_len + hdr->pad_len);
+
+	skb =  skb_clone(skb_mux, GFP_KERNEL);
+	if (!skb) {
+		pr_err("%s: cannot clone skb\n", __func__);
+		goto packet_done;
+	}
+
+	skb_set_data(skb, (unsigned char *)(hdr + 1), hdr->pkt_len);
+	DBG("%s: head %p data %p tail %p end %p len %d\n",
+	    __func__, skb->head, skb->data, skb->tail, skb->end, skb->len);
+
+	/* probably we should check channel status */
+	/* discard packet early if local side not open */
+	spin_lock_irqsave(&sdio_ch[hdr->ch_id].lock, flags);
+	if (sdio_ch[hdr->ch_id].receive_cb)
+		sdio_ch[hdr->ch_id].receive_cb(sdio_ch[hdr->ch_id].priv, skb);
+	else
+		dev_kfree_skb_any(skb);
+	spin_unlock_irqrestore(&sdio_ch[hdr->ch_id].lock, flags);
+
+packet_done:
+	return rp;
+}
+
+static void *handle_sdio_mux_command(struct sdio_mux_hdr *hdr,
+				     struct sk_buff *skb_mux)
+{
+	void *rp;
+	unsigned long flags;
+	int send_open = 0;
+
+	DBG("%s: cmd %d ch %d\n", __func__, hdr->cmd, hdr->ch_id);
+	switch (hdr->cmd) {
+	case SDIO_MUX_HDR_CMD_DATA:
+		rp = handle_sdio_mux_data(hdr, skb_mux);
+		break;
+	case SDIO_MUX_HDR_CMD_OPEN:
+		spin_lock_irqsave(&sdio_ch[hdr->ch_id].lock, flags);
+		sdio_ch[hdr->ch_id].status |= SDIO_CH_REMOTE_OPEN;
+		sdio_ch[hdr->ch_id].num_tx_pkts = 0;
+
+		if (sdio_ch_is_in_reset(hdr->ch_id)) {
+			DBG("%s: in reset - sending open cmd\n", __func__);
+			sdio_ch[hdr->ch_id].status &= ~SDIO_CH_IN_RESET;
+			send_open = 1;
+		}
+
+		/* notify client so it can update its status */
+		if (sdio_ch[hdr->ch_id].receive_cb)
+			sdio_ch[hdr->ch_id].receive_cb(
+					sdio_ch[hdr->ch_id].priv, NULL);
+
+		if (sdio_ch[hdr->ch_id].write_done)
+			sdio_ch[hdr->ch_id].write_done(
+					sdio_ch[hdr->ch_id].priv, NULL);
+		spin_unlock_irqrestore(&sdio_ch[hdr->ch_id].lock, flags);
+		rp = hdr + 1;
+		if (send_open)
+			sdio_mux_send_open_cmd(hdr->ch_id);
+
+		break;
+	case SDIO_MUX_HDR_CMD_CLOSE:
+		/* probably should drop pending write */
+		spin_lock_irqsave(&sdio_ch[hdr->ch_id].lock, flags);
+		sdio_ch[hdr->ch_id].status &= ~SDIO_CH_REMOTE_OPEN;
+		spin_unlock_irqrestore(&sdio_ch[hdr->ch_id].lock, flags);
+		rp = hdr + 1;
+		break;
+	default:
+		rp = hdr + 1;
+	}
+
+	return rp;
+}
+
+static void *handle_sdio_partial_pkt(struct sk_buff *skb_mux)
+{
+	struct sk_buff *p_skb;
+	struct sdio_mux_hdr *p_hdr;
+	void *ptr, *rp = skb_mux->data;
+
+	/* protoect? */
+	if (sdio_partial_pkt.valid) {
+		p_skb = sdio_partial_pkt.skb;
+
+		ptr = skb_push(skb_mux, p_skb->len);
+		memcpy(ptr, p_skb->data, p_skb->len);
+		sdio_partial_pkt.skb = NULL;
+		sdio_partial_pkt.valid = 0;
+		dev_kfree_skb_any(p_skb);
+
+		DBG("%s: head %p data %p tail %p end %p len %d\n", __func__,
+		    skb_mux->head, skb_mux->data, skb_mux->tail,
+		    skb_mux->end, skb_mux->len);
+
+		p_hdr = (struct sdio_mux_hdr *)skb_mux->data;
+		rp = handle_sdio_mux_command(p_hdr, skb_mux);
+	}
+	return rp;
+}
+
+static void sdio_mux_read_data(struct work_struct *work)
+{
+	struct sk_buff *skb_mux;
+	void *ptr = 0;
+	int sz, rc, len = 0;
+	struct sdio_mux_hdr *hdr;
+	static int workqueue_pinned;
+
+	if (!workqueue_pinned) {
+		struct cpumask cpus;
+
+		cpumask_clear(&cpus);
+		cpumask_set_cpu(0, &cpus);
+
+		if (sched_setaffinity(current->pid, &cpus))
+			pr_err("%s: sdio_dmux set CPU affinity failed\n",
+					__func__);
+		workqueue_pinned = 1;
+	}
+
+	DBG("%s: reading\n", __func__);
+	/* should probably have a separate read lock */
+	mutex_lock(&sdio_mux_lock);
+	sz = sdio_read_avail(sdio_mux_ch);
+	DBG("%s: read avail %d\n", __func__, sz);
+	if (sz <= 0) {
+		if (sz)
+			pr_err("%s: read avail failed %d\n", __func__, sz);
+		mutex_unlock(&sdio_mux_lock);
+		return;
+	}
+
+	/* net_ip_aling is probably not required */
+	if (sdio_partial_pkt.valid)
+		len = sdio_partial_pkt.skb->len;
+
+	/* If allocation fails attempt to get a smaller chunk of mem */
+	do {
+		skb_mux = __dev_alloc_skb(sz + NET_IP_ALIGN + len, GFP_KERNEL);
+		if (skb_mux)
+			break;
+
+		pr_err("%s: cannot allocate skb of size:%d + "
+			"%d (NET_SKB_PAD)\n", __func__,
+			sz + NET_IP_ALIGN + len, NET_SKB_PAD);
+		/* the skb structure adds NET_SKB_PAD bytes to the memory
+		 * request, which may push the actual request above PAGE_SIZE
+		 * in that case, we need to iterate one more time to make sure
+		 * we get the memory request under PAGE_SIZE
+		 */
+		if (sz + NET_IP_ALIGN + len + NET_SKB_PAD <= PAGE_SIZE) {
+			pr_err("%s: allocation failed\n", __func__);
+			mutex_unlock(&sdio_mux_lock);
+			return;
+		}
+		sz /= 2;
+	} while (1);
+
+	skb_reserve(skb_mux, NET_IP_ALIGN + len);
+	ptr = skb_put(skb_mux, sz);
+
+	/* half second wakelock is fine? */
+	wake_lock_timeout(&sdio_mux_ch_wakelock, HZ / 2);
+	rc = sdio_read(sdio_mux_ch, ptr, sz);
+	DBG("%s: read %d\n", __func__, rc);
+	if (rc) {
+		pr_err("%s: sdio read failed %d\n", __func__, rc);
+		dev_kfree_skb_any(skb_mux);
+		mutex_unlock(&sdio_mux_lock);
+		queue_work(sdio_mux_workqueue, &work_sdio_mux_read);
+		return;
+	}
+	mutex_unlock(&sdio_mux_lock);
+
+	DBG_INC_READ_CNT(sz);
+	DBG("%s: head %p data %p tail %p end %p len %d\n", __func__,
+	    skb_mux->head, skb_mux->data, skb_mux->tail,
+	    skb_mux->end, skb_mux->len);
+
+	/* move to a separate function */
+	/* probably do skb_pull instead of pointer adjustment */
+	hdr = handle_sdio_partial_pkt(skb_mux);
+	while ((void *)hdr < (void *)skb_mux->tail) {
+
+		if (((void *)hdr + sizeof(*hdr)) > (void *)skb_mux->tail) {
+			/* handle partial header */
+			sdio_mux_save_partial_pkt(hdr, skb_mux);
+			break;
+		}
+
+		if (hdr->magic_num != SDIO_MUX_HDR_MAGIC_NO) {
+			pr_err("%s: packet error\n", __func__);
+			break;
+		}
+
+		hdr = handle_sdio_mux_command(hdr, skb_mux);
+	}
+	dev_kfree_skb_any(skb_mux);
+
+	DBG("%s: read done\n", __func__);
+	queue_work(sdio_mux_workqueue, &work_sdio_mux_read);
+}
+
+static int sdio_mux_write(struct sk_buff *skb)
+{
+	int rc, sz;
+
+	mutex_lock(&sdio_mux_lock);
+	sz = sdio_write_avail(sdio_mux_ch);
+	DBG("%s: avail %d len %d\n", __func__, sz, skb->len);
+	if (skb->len <= sz) {
+		rc = sdio_write(sdio_mux_ch, skb->data, skb->len);
+		DBG("%s: write returned %d\n", __func__, rc);
+		if (rc == 0)
+			DBG_INC_WRITE_CNT(skb->len);
+	} else
+		rc = -ENOMEM;
+
+	mutex_unlock(&sdio_mux_lock);
+	return rc;
+}
+
+static int sdio_mux_write_cmd(void *data, uint32_t len)
+{
+	int avail, rc;
+	for (;;) {
+		mutex_lock(&sdio_mux_lock);
+		avail = sdio_write_avail(sdio_mux_ch);
+		DBG("%s: avail %d len %d\n", __func__, avail, len);
+		if (avail >= len) {
+			rc = sdio_write(sdio_mux_ch, data, len);
+			DBG("%s: write returned %d\n", __func__, rc);
+			if (!rc) {
+				DBG_INC_WRITE_CNT(len);
+				break;
+			}
+		}
+		mutex_unlock(&sdio_mux_lock);
+		msleep(250);
+	}
+	mutex_unlock(&sdio_mux_lock);
+	return 0;
+}
+
+static void sdio_mux_send_open_cmd(uint32_t id)
+{
+	struct sdio_mux_hdr hdr = {
+		.magic_num = SDIO_MUX_HDR_MAGIC_NO,
+		.cmd = SDIO_MUX_HDR_CMD_OPEN,
+		.reserved = 0,
+		.ch_id = id,
+		.pkt_len = 0,
+		.pad_len = 0
+	};
+
+	sdio_mux_write_cmd((void *)&hdr, sizeof(hdr));
+}
+
+static void sdio_mux_write_data(struct work_struct *work)
+{
+	int rc, reschedule = 0;
+	int notify = 0;
+	struct sk_buff *skb;
+	unsigned long flags;
+	int avail;
+	int ch_id;
+
+	spin_lock_irqsave(&sdio_mux_write_lock, flags);
+	while ((skb = __skb_dequeue(&sdio_mux_write_pool))) {
+		ch_id = ((struct sdio_mux_hdr *)skb->data)->ch_id;
+
+		avail = sdio_write_avail(sdio_mux_ch);
+		if (avail < skb->len) {
+			/* we may have to wait for write avail
+			 * notification from sdio al
+			 */
+			DBG("%s: sdio_write_avail(%d) < skb->len(%d)\n",
+					__func__, avail, skb->len);
+
+			reschedule = 1;
+			break;
+		}
+		spin_unlock_irqrestore(&sdio_mux_write_lock, flags);
+		rc = sdio_mux_write(skb);
+		spin_lock_irqsave(&sdio_mux_write_lock, flags);
+		if (rc == 0) {
+
+			spin_lock(&sdio_ch[ch_id].lock);
+			sdio_ch[ch_id].num_tx_pkts--;
+			spin_unlock(&sdio_ch[ch_id].lock);
+
+			if (sdio_ch[ch_id].write_done)
+				sdio_ch[ch_id].write_done(
+						sdio_ch[ch_id].priv, skb);
+			else
+				dev_kfree_skb_any(skb);
+		} else if (rc == -EAGAIN || rc == -ENOMEM) {
+			/* recoverable error - retry again later */
+			reschedule = 1;
+			break;
+		} else if (rc == -ENODEV) {
+			/*
+			 * sdio_al suffered some kind of fatal error
+			 * prevent future writes and clean up pending ones
+			 */
+			fatal_error = 1;
+			do {
+				ch_id = ((struct sdio_mux_hdr *)
+						skb->data)->ch_id;
+				spin_lock(&sdio_ch[ch_id].lock);
+				sdio_ch[ch_id].num_tx_pkts--;
+				spin_unlock(&sdio_ch[ch_id].lock);
+				dev_kfree_skb_any(skb);
+			} while ((skb = __skb_dequeue(&sdio_mux_write_pool)));
+			spin_unlock_irqrestore(&sdio_mux_write_lock, flags);
+			return;
+		} else {
+			/* unknown error condition - drop the
+			 * skb and reschedule for the
+			 * other skb's
+			 */
+			pr_err("%s: sdio_mux_write error %d"
+				   " for ch %d, skb=%p\n",
+				__func__, rc, ch_id, skb);
+			notify = 1;
+			break;
+		}
+	}
+
+	if (reschedule) {
+		if (sdio_ch_is_in_reset(ch_id)) {
+			notify = 1;
+		} else {
+			__skb_queue_head(&sdio_mux_write_pool, skb);
+			queue_delayed_work(sdio_mux_workqueue,
+					&delayed_work_sdio_mux_write,
+					msecs_to_jiffies(250)
+					);
+		}
+	}
+
+	if (notify) {
+		spin_lock(&sdio_ch[ch_id].lock);
+		sdio_ch[ch_id].num_tx_pkts--;
+		spin_unlock(&sdio_ch[ch_id].lock);
+
+		if (sdio_ch[ch_id].write_done)
+			sdio_ch[ch_id].write_done(
+				sdio_ch[ch_id].priv, skb);
+		else
+			dev_kfree_skb_any(skb);
+	}
+	spin_unlock_irqrestore(&sdio_mux_write_lock, flags);
+}
+
+int msm_sdio_is_channel_in_reset(uint32_t id)
+{
+	int rc = 0;
+
+	if (id >= SDIO_DMUX_NUM_CHANNELS)
+		return -EINVAL;
+
+	if (sdio_ch_is_in_reset(id))
+		rc = 1;
+
+	return rc;
+}
+
+int msm_sdio_dmux_write(uint32_t id, struct sk_buff *skb)
+{
+	int rc = 0;
+	struct sdio_mux_hdr *hdr;
+	unsigned long flags;
+	struct sk_buff *new_skb;
+
+	if (id >= SDIO_DMUX_NUM_CHANNELS)
+		return -EINVAL;
+	if (!skb)
+		return -EINVAL;
+	if (!sdio_mux_initialized)
+		return -ENODEV;
+	if (fatal_error)
+		return -ENODEV;
+
+	DBG("%s: writing to ch %d len %d\n", __func__, id, skb->len);
+	spin_lock_irqsave(&sdio_ch[id].lock, flags);
+	if (sdio_ch_is_in_reset(id)) {
+		spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
+		pr_err("%s: port is in reset: %d\n", __func__,
+				sdio_ch[id].status);
+		return -ENETRESET;
+	}
+	if (!sdio_ch_is_local_open(id)) {
+		spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
+		pr_err("%s: port not open: %d\n", __func__, sdio_ch[id].status);
+		return -ENODEV;
+	}
+	if (sdio_ch[id].use_wm &&
+			(sdio_ch[id].num_tx_pkts >= HIGH_WATERMARK)) {
+		spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
+		pr_err("%s: watermark exceeded: %d\n", __func__, id);
+		return -EAGAIN;
+	}
+	spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
+
+	spin_lock_irqsave(&sdio_mux_write_lock, flags);
+	/* if skb do not have any tailroom for padding,
+	   copy the skb into a new expanded skb */
+	if ((skb->len & 0x3) && (skb_tailroom(skb) < (4 - (skb->len & 0x3)))) {
+		/* revisit, probably dev_alloc_skb and memcpy is effecient */
+		new_skb = skb_copy_expand(skb, skb_headroom(skb),
+					  4 - (skb->len & 0x3), GFP_ATOMIC);
+		if (new_skb == NULL) {
+			pr_err("%s: cannot allocate skb\n", __func__);
+			rc = -ENOMEM;
+			goto write_done;
+		}
+		dev_kfree_skb_any(skb);
+		skb = new_skb;
+		DBG_INC_WRITE_CPY(skb->len);
+	}
+
+	hdr = (struct sdio_mux_hdr *)skb_push(skb, sizeof(struct sdio_mux_hdr));
+
+	/* caller should allocate for hdr and padding
+	   hdr is fine, padding is tricky */
+	hdr->magic_num = SDIO_MUX_HDR_MAGIC_NO;
+	hdr->cmd = SDIO_MUX_HDR_CMD_DATA;
+	hdr->reserved = 0;
+	hdr->ch_id = id;
+	hdr->pkt_len = skb->len - sizeof(struct sdio_mux_hdr);
+	if (skb->len & 0x3)
+		skb_put(skb, 4 - (skb->len & 0x3));
+
+	hdr->pad_len = skb->len - (sizeof(struct sdio_mux_hdr) + hdr->pkt_len);
+
+	DBG("%s: data %p, tail %p skb len %d pkt len %d pad len %d\n",
+	    __func__, skb->data, skb->tail, skb->len,
+	    hdr->pkt_len, hdr->pad_len);
+	__skb_queue_tail(&sdio_mux_write_pool, skb);
+
+	spin_lock(&sdio_ch[id].lock);
+	sdio_ch[id].num_tx_pkts++;
+	spin_unlock(&sdio_ch[id].lock);
+
+	queue_work(sdio_mux_workqueue, &work_sdio_mux_write);
+
+write_done:
+	spin_unlock_irqrestore(&sdio_mux_write_lock, flags);
+	return rc;
+}
+
+int msm_sdio_dmux_open(uint32_t id, void *priv,
+			void (*receive_cb)(void *, struct sk_buff *),
+			void (*write_done)(void *, struct sk_buff *))
+{
+	unsigned long flags;
+
+	DBG("%s: opening ch %d\n", __func__, id);
+	if (!sdio_mux_initialized)
+		return -ENODEV;
+	if (id >= SDIO_DMUX_NUM_CHANNELS)
+		return -EINVAL;
+
+	spin_lock_irqsave(&sdio_ch[id].lock, flags);
+	if (sdio_ch_is_local_open(id)) {
+		pr_info("%s: Already opened %d\n", __func__, id);
+		spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
+		goto open_done;
+	}
+
+	sdio_ch[id].receive_cb = receive_cb;
+	sdio_ch[id].write_done = write_done;
+	sdio_ch[id].priv = priv;
+	sdio_ch[id].status |= SDIO_CH_LOCAL_OPEN;
+	sdio_ch[id].num_tx_pkts = 0;
+	sdio_ch[id].use_wm = 0;
+	spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
+
+	sdio_mux_send_open_cmd(id);
+
+open_done:
+	pr_info("%s: opened ch %d\n", __func__, id);
+	return 0;
+}
+
+int msm_sdio_dmux_close(uint32_t id)
+{
+	struct sdio_mux_hdr hdr;
+	unsigned long flags;
+
+	if (id >= SDIO_DMUX_NUM_CHANNELS)
+		return -EINVAL;
+	DBG("%s: closing ch %d\n", __func__, id);
+	if (!sdio_mux_initialized)
+		return -ENODEV;
+	spin_lock_irqsave(&sdio_ch[id].lock, flags);
+
+	sdio_ch[id].receive_cb = NULL;
+	sdio_ch[id].priv = NULL;
+	sdio_ch[id].status &= ~SDIO_CH_LOCAL_OPEN;
+	sdio_ch[id].status &= ~SDIO_CH_IN_RESET;
+	spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
+
+	hdr.magic_num = SDIO_MUX_HDR_MAGIC_NO;
+	hdr.cmd = SDIO_MUX_HDR_CMD_CLOSE;
+	hdr.reserved = 0;
+	hdr.ch_id = id;
+	hdr.pkt_len = 0;
+	hdr.pad_len = 0;
+
+	sdio_mux_write_cmd((void *)&hdr, sizeof(hdr));
+
+	pr_info("%s: closed ch %d\n", __func__, id);
+	return 0;
+}
+
+static void sdio_mux_notify(void *_dev, unsigned event)
+{
+	DBG("%s: event %d notified\n", __func__, event);
+
+	/* write avail may not be enouogh for a packet, but should be fine */
+	if ((event == SDIO_EVENT_DATA_WRITE_AVAIL) &&
+	    sdio_write_avail(sdio_mux_ch))
+		queue_work(sdio_mux_workqueue, &work_sdio_mux_write);
+
+	if ((event == SDIO_EVENT_DATA_READ_AVAIL) &&
+	    sdio_read_avail(sdio_mux_ch))
+		queue_work(sdio_mux_workqueue, &work_sdio_mux_read);
+}
+
+int msm_sdio_dmux_is_ch_full(uint32_t id)
+{
+	unsigned long flags;
+	int ret;
+
+	if (id >= SDIO_DMUX_NUM_CHANNELS)
+		return -EINVAL;
+
+	spin_lock_irqsave(&sdio_ch[id].lock, flags);
+	sdio_ch[id].use_wm = 1;
+	ret = sdio_ch[id].num_tx_pkts >= HIGH_WATERMARK;
+	DBG("%s: ch %d num tx pkts=%d, HWM=%d\n", __func__,
+			id, sdio_ch[id].num_tx_pkts, ret);
+	if (!sdio_ch_is_local_open(id)) {
+		ret = -ENODEV;
+		pr_err("%s: port not open: %d\n", __func__, sdio_ch[id].status);
+	}
+	spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
+
+	return ret;
+}
+
+int msm_sdio_dmux_is_ch_low(uint32_t id)
+{
+	int ret;
+
+	if (id >= SDIO_DMUX_NUM_CHANNELS)
+		return -EINVAL;
+
+	sdio_ch[id].use_wm = 1;
+	ret = sdio_ch[id].num_tx_pkts <= LOW_WATERMARK;
+	DBG("%s: ch %d num tx pkts=%d, LWM=%d\n", __func__,
+			id, sdio_ch[id].num_tx_pkts, ret);
+	if (!sdio_ch_is_local_open(id)) {
+		ret = -ENODEV;
+		pr_err("%s: port not open: %d\n", __func__, sdio_ch[id].status);
+	}
+
+	return ret;
+}
+
+#ifdef CONFIG_DEBUG_FS
+
+static int debug_tbl(char *buf, int max)
+{
+	int i = 0;
+	int j;
+
+	for (j = 0; j < SDIO_DMUX_NUM_CHANNELS; ++j) {
+		i += scnprintf(buf + i, max - i,
+			"ch%02d  local open=%s  remote open=%s\n",
+			j, sdio_ch_is_local_open(j) ? "Y" : "N",
+			sdio_ch_is_remote_open(j) ? "Y" : "N");
+	}
+
+	return i;
+}
+
+#define DEBUG_BUFMAX 4096
+static char debug_buffer[DEBUG_BUFMAX];
+
+static ssize_t debug_read(struct file *file, char __user *buf,
+				size_t count, loff_t *ppos)
+{
+	int (*fill)(char *buf, int max) = file->private_data;
+	int bsize = fill(debug_buffer, DEBUG_BUFMAX);
+	return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+
+static const struct file_operations debug_ops = {
+	.read = debug_read,
+	.open = debug_open,
+};
+
+static void debug_create(const char *name, mode_t mode,
+				struct dentry *dent,
+				int (*fill)(char *buf, int max))
+{
+	debugfs_create_file(name, mode, dent, fill, &debug_ops);
+}
+
+#endif
+
+static int sdio_dmux_probe(struct platform_device *pdev)
+{
+	int rc;
+
+	DBG("%s probe called\n", __func__);
+
+	if (!sdio_mux_initialized) {
+		sdio_mux_workqueue = create_singlethread_workqueue("sdio_dmux");
+		if (!sdio_mux_workqueue)
+			return -ENOMEM;
+
+		skb_queue_head_init(&sdio_mux_write_pool);
+		spin_lock_init(&sdio_mux_write_lock);
+
+		for (rc = 0; rc < SDIO_DMUX_NUM_CHANNELS; ++rc)
+			spin_lock_init(&sdio_ch[rc].lock);
+
+
+		wake_lock_init(&sdio_mux_ch_wakelock, WAKE_LOCK_SUSPEND,
+				   "sdio_dmux");
+	}
+
+	rc = sdio_open("SDIO_RMNT", &sdio_mux_ch, NULL, sdio_mux_notify);
+	if (rc < 0) {
+		pr_err("%s: sido open failed %d\n", __func__, rc);
+		wake_lock_destroy(&sdio_mux_ch_wakelock);
+		destroy_workqueue(sdio_mux_workqueue);
+		sdio_mux_initialized = 0;
+		return rc;
+	}
+
+	fatal_error = 0;
+	sdio_mux_initialized = 1;
+	return 0;
+}
+
+static int sdio_dmux_remove(struct platform_device *pdev)
+{
+	int i;
+	unsigned long ch_lock_flags;
+	unsigned long write_lock_flags;
+	struct sk_buff *skb;
+
+	DBG("%s remove called\n", __func__);
+	if (!sdio_mux_initialized)
+		return 0;
+
+	/* set reset state for any open channels */
+	for (i = 0; i < SDIO_DMUX_NUM_CHANNELS; ++i) {
+		spin_lock_irqsave(&sdio_ch[i].lock, ch_lock_flags);
+		if (sdio_ch_is_open(i)) {
+			sdio_ch[i].status |= SDIO_CH_IN_RESET;
+			sdio_ch[i].status &= ~SDIO_CH_REMOTE_OPEN;
+
+			/* notify client so it can update its status */
+			if (sdio_ch[i].receive_cb)
+				sdio_ch[i].receive_cb(
+						sdio_ch[i].priv, NULL);
+		}
+		spin_unlock_irqrestore(&sdio_ch[i].lock, ch_lock_flags);
+	}
+
+	/* cancel any pending writes */
+	spin_lock_irqsave(&sdio_mux_write_lock, write_lock_flags);
+	while ((skb = __skb_dequeue(&sdio_mux_write_pool))) {
+		i = ((struct sdio_mux_hdr *)skb->data)->ch_id;
+		if (sdio_ch[i].write_done)
+			sdio_ch[i].write_done(
+					sdio_ch[i].priv, skb);
+		else
+			dev_kfree_skb_any(skb);
+	}
+	spin_unlock_irqrestore(&sdio_mux_write_lock,
+			write_lock_flags);
+
+	return 0;
+}
+
+static struct platform_driver sdio_dmux_driver = {
+	.probe		= sdio_dmux_probe,
+	.remove   = sdio_dmux_remove,
+	.driver		= {
+		.name	= "SDIO_RMNT",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init sdio_dmux_init(void)
+{
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dent;
+
+	dent = debugfs_create_dir("sdio_dmux", 0);
+	if (!IS_ERR(dent))
+		debug_create("tbl", 0444, dent, debug_tbl);
+#endif
+	return platform_driver_register(&sdio_dmux_driver);
+}
+
+module_init(sdio_dmux_init);
+MODULE_DESCRIPTION("MSM SDIO DMUX");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/sdio_smem.c b/arch/arm/mach-msm/sdio_smem.c
new file mode 100644
index 0000000..4416a79
--- /dev/null
+++ b/arch/arm/mach-msm/sdio_smem.c
@@ -0,0 +1,175 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/module.h>
+#include <mach/sdio_al.h>
+#include <mach/sdio_smem.h>
+
+static void sdio_smem_read(struct work_struct *work);
+
+static struct sdio_channel *channel;
+static struct workqueue_struct *workq;
+static DECLARE_WORK(work_read, sdio_smem_read);
+static DECLARE_WAIT_QUEUE_HEAD(waitq);
+static int bytes_avail;
+static int sdio_ch_opened;
+
+static void sdio_smem_release(struct device *dev)
+{
+	pr_debug("sdio smem released\n");
+}
+
+static struct sdio_smem_client client;
+
+static void sdio_smem_read(struct work_struct *work)
+{
+	int err;
+	int read_avail;
+	char *data = client.buf;
+
+	if (!sdio_ch_opened)
+		return;
+
+	read_avail = sdio_read_avail(channel);
+	if (read_avail > bytes_avail ||
+		read_avail < 0) {
+		pr_err("Error: read_avail=%d bytes_avail=%d\n",
+			read_avail, bytes_avail);
+		goto read_err;
+	}
+
+	if (read_avail == 0)
+		return;
+
+	err = sdio_read(channel,
+			&data[client.size - bytes_avail],
+			read_avail);
+	if (err) {
+		pr_err("sdio_read error (%d)", err);
+		goto read_err;
+	}
+
+	bytes_avail -= read_avail;
+	pr_debug("read %d bytes (bytes_avail = %d)\n",
+			read_avail, bytes_avail);
+
+	if (!bytes_avail) {
+		bytes_avail = client.size;
+		err = client.cb_func(SDIO_SMEM_EVENT_READ_DONE);
+	}
+	if (err)
+		pr_err("error (%d) on callback\n", err);
+
+	return;
+
+read_err:
+	if (sdio_ch_opened)
+		client.cb_func(SDIO_SMEM_EVENT_READ_ERR);
+	return;
+}
+
+static void sdio_smem_notify(void *priv, unsigned event)
+{
+	pr_debug("%d event received\n", event);
+
+	if (event == SDIO_EVENT_DATA_READ_AVAIL ||
+	    event == SDIO_EVENT_DATA_WRITE_AVAIL)
+		queue_work(workq, &work_read);
+}
+
+int sdio_smem_register_client(void)
+{
+	int err = 0;
+
+	if (!client.buf || !client.size || !client.cb_func)
+		return -EINVAL;
+
+	pr_debug("buf = %p\n", client.buf);
+	pr_debug("size = 0x%x\n", client.size);
+
+	bytes_avail = client.size;
+	workq = create_singlethread_workqueue("sdio_smem");
+	if (!workq)
+		return -ENOMEM;
+
+	sdio_ch_opened = 1;
+	err = sdio_open("SDIO_SMEM", &channel, NULL, sdio_smem_notify);
+	if (err) {
+		sdio_ch_opened = 0;
+		pr_err("sdio_open error (%d)\n", err);
+		destroy_workqueue(workq);
+		return err;
+	}
+	pr_debug("SDIO SMEM channel opened\n");
+	return err;
+}
+
+int sdio_smem_unregister_client(void)
+{
+	int err = 0;
+
+	sdio_ch_opened = 0;
+	err = sdio_close(channel);
+	if (err) {
+		pr_err("sdio_close error (%d)\n", err);
+		return err;
+	}
+	pr_debug("SDIO SMEM channel closed\n");
+	flush_workqueue(workq);
+	destroy_workqueue(workq);
+	bytes_avail = 0;
+	client.buf = NULL;
+	client.cb_func = NULL;
+	client.size = 0;
+
+	return 0;
+}
+
+static int sdio_smem_probe(struct platform_device *pdev)
+{
+	client.plat_dev.name = "SDIO_SMEM_CLIENT";
+	client.plat_dev.id = -1;
+	client.plat_dev.dev.release = sdio_smem_release;
+
+	return platform_device_register(&client.plat_dev);
+}
+
+static int sdio_smem_remove(struct platform_device *pdev)
+{
+	platform_device_unregister(&client.plat_dev);
+	memset(&client, 0, sizeof(client));
+	sdio_ch_opened = 0;
+	return 0;
+}
+static struct platform_driver sdio_smem_drv = {
+	.probe		= sdio_smem_probe,
+	.remove		= sdio_smem_remove,
+	.driver		= {
+		.name	= "SDIO_SMEM",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init sdio_smem_init(void)
+{
+	return platform_driver_register(&sdio_smem_drv);
+};
+
+module_init(sdio_smem_init);
+
+MODULE_DESCRIPTION("SDIO SMEM");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/sdio_tty.c b/arch/arm/mach-msm/sdio_tty.c
new file mode 100644
index 0000000..41bc270
--- /dev/null
+++ b/arch/arm/mach-msm/sdio_tty.c
@@ -0,0 +1,824 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <mach/sdio_al.h>
+
+#define INPUT_SPEED			4800
+#define OUTPUT_SPEED			4800
+#define SDIO_TTY_MODULE_NAME		"sdio_tty"
+#define SDIO_TTY_MAX_PACKET_SIZE	4096
+#define MAX_SDIO_TTY_DRV		1
+#define MAX_SDIO_TTY_DEVS		2
+#define MAX_SDIO_TTY_DEV_NAME_SIZE	25
+
+/* Configurations per channel device */
+/* CSVT */
+#define SDIO_TTY_CSVT_DEV		"sdio_tty_csvt_0"
+#define SDIO_TTY_CSVT_TEST_DEV		"sdio_tty_csvt_test_0"
+#define SDIO_TTY_CH_CSVT		"SDIO_CSVT"
+
+enum sdio_tty_state {
+	TTY_INITIAL = 0,
+	TTY_REGISTERED = 1,
+	TTY_OPENED = 2,
+	TTY_CLOSED = 3,
+};
+
+enum sdio_tty_devices {
+	SDIO_CSVT,
+	SDIO_CSVT_TEST_APP,
+};
+
+static const struct platform_device_id sdio_tty_id_table[] = {
+	{ "SDIO_CSVT",		SDIO_CSVT },
+	{ "SDIO_CSVT_TEST_APP",	SDIO_CSVT_TEST_APP },
+	{ },
+};
+MODULE_DEVICE_TABLE(platform, sdio_tty_id_table);
+
+struct sdio_tty {
+	struct sdio_channel *ch;
+	char *sdio_ch_name;
+	char tty_dev_name[MAX_SDIO_TTY_DEV_NAME_SIZE];
+	int device_id;
+	struct workqueue_struct *workq;
+	struct work_struct work_read;
+	wait_queue_head_t   waitq;
+	struct tty_driver *tty_drv;
+	struct tty_struct *tty_str;
+	int debug_msg_on;
+	char *read_buf;
+	enum sdio_tty_state sdio_tty_state;
+	int is_sdio_open;
+	int tty_open_count;
+	int total_rx;
+	int total_tx;
+};
+
+static struct sdio_tty *sdio_tty[MAX_SDIO_TTY_DEVS];
+
+#ifdef CONFIG_DEBUG_FS
+struct dentry *sdio_tty_debug_root;
+struct dentry *sdio_tty_debug_info;
+#endif
+
+#define DEBUG_MSG(sdio_tty_drv, x...) if (sdio_tty_drv->debug_msg_on) pr_info(x)
+
+/*
+ * Enable sdio_tty debug messages
+ * By default the sdio_tty debug messages are turned off
+ */
+static int csvt_debug_msg_on;
+module_param(csvt_debug_msg_on, int, 0);
+
+static void sdio_tty_read(struct work_struct *work)
+{
+	int ret = 0;
+	int read_avail = 0;
+	int left = 0;
+	int total_push = 0;
+	int num_push = 0;
+	struct sdio_tty *sdio_tty_drv = NULL;
+
+	sdio_tty_drv = container_of(work, struct sdio_tty, work_read);
+
+	if (!sdio_tty_drv) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty", __func__);
+		return ;
+	}
+
+	if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
+			__func__, sdio_tty_drv->sdio_tty_state);
+		return;
+	}
+
+	if (!sdio_tty_drv->read_buf) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL read_buf for dev %s",
+			__func__, sdio_tty_drv->tty_dev_name);
+		return;
+	}
+
+	/* Read the data from the SDIO channel as long as there is available
+	   data */
+	while (1) {
+		if (test_bit(TTY_THROTTLED, &sdio_tty_drv->tty_str->flags)) {
+			DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME
+					": %s: TTY_THROTTLED bit is set for "
+					"dev %s, exit", __func__,
+					sdio_tty_drv->tty_dev_name);
+			return;
+		}
+
+		total_push = 0;
+		read_avail = sdio_read_avail(sdio_tty_drv->ch);
+
+		DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME
+				": %s: read_avail is %d for dev %s", __func__,
+				read_avail, sdio_tty_drv->tty_dev_name);
+
+		if (read_avail == 0) {
+			DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME
+					": %s: read_avail is 0 for dev %s",
+					__func__, sdio_tty_drv->tty_dev_name);
+			return;
+		}
+
+		if (read_avail > SDIO_TTY_MAX_PACKET_SIZE) {
+			pr_err(SDIO_TTY_MODULE_NAME ": %s: read_avail(%d) is "
+				"bigger than SDIO_TTY_MAX_PACKET_SIZE(%d) "
+				"for dev %s", __func__, read_avail,
+				SDIO_TTY_MAX_PACKET_SIZE,
+				sdio_tty_drv->tty_dev_name);
+			return;
+		}
+
+		ret = sdio_read(sdio_tty_drv->ch,
+				sdio_tty_drv->read_buf,
+				read_avail);
+		if (ret < 0) {
+			pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_read error(%d) "
+				"for dev %s", __func__, ret,
+				sdio_tty_drv->tty_dev_name);
+			return;
+		}
+
+		left = read_avail;
+		do {
+			num_push = tty_insert_flip_string(
+				sdio_tty_drv->tty_str,
+				sdio_tty_drv->read_buf+total_push,
+				left);
+			total_push += num_push;
+			left -= num_push;
+			tty_flip_buffer_push(sdio_tty_drv->tty_str);
+		} while (left != 0);
+
+		if (total_push != read_avail) {
+			pr_err(SDIO_TTY_MODULE_NAME ": %s: failed, total_push"
+				"(%d) != read_avail(%d) for dev %s\n",
+				__func__, total_push, read_avail,
+				sdio_tty_drv->tty_dev_name);
+		}
+
+		tty_flip_buffer_push(sdio_tty_drv->tty_str);
+		sdio_tty_drv->total_rx += read_avail;
+
+		DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: Rx: %d, "
+				"Total Rx = %d bytes for dev %s", __func__,
+				read_avail, sdio_tty_drv->total_rx,
+				sdio_tty_drv->tty_dev_name);
+	}
+}
+
+/**
+  * sdio_tty_write_room
+  *
+  * This is the write_room function of the tty driver.
+  *
+  * @tty: pointer to tty struct.
+  * @return free bytes for write.
+  *
+  */
+static int sdio_tty_write_room(struct tty_struct *tty)
+{
+	int write_avail = 0;
+	struct sdio_tty *sdio_tty_drv = NULL;
+
+	if (!tty) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty", __func__);
+		return -ENODEV;
+	}
+	sdio_tty_drv = tty->driver_data;
+	if (!sdio_tty_drv) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
+			__func__);
+		return -ENODEV;
+	}
+
+	if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
+			__func__, sdio_tty_drv->sdio_tty_state);
+		return -EPERM;
+	}
+
+	write_avail = sdio_write_avail(sdio_tty_drv->ch);
+	DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: write_avail=%d "
+			"for dev %s", __func__, write_avail,
+			sdio_tty_drv->tty_dev_name);
+
+	return write_avail;
+}
+
+/**
+  * sdio_tty_write_callback
+  * this is the write callback of the tty driver.
+  *
+  * @tty: pointer to tty struct.
+  * @buf: buffer to write from.
+  * @count: number of bytes to write.
+  * @return bytes written or negative value on error.
+  *
+  * if destination buffer has not enough room for the incoming
+  * data, writes the possible amount of bytes .
+  */
+static int sdio_tty_write_callback(struct tty_struct *tty,
+				   const unsigned char *buf, int count)
+{
+	int write_avail = 0;
+	int len = count;
+	int ret = 0;
+	struct sdio_tty *sdio_tty_drv = NULL;
+
+	if (!tty) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty", __func__);
+		return -ENODEV;
+	}
+	sdio_tty_drv = tty->driver_data;
+	if (!sdio_tty_drv) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
+			__func__);
+		return -ENODEV;
+	}
+
+	if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
+			__func__, sdio_tty_drv->sdio_tty_state);
+		return -EPERM;
+	}
+
+	DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: Write Callback "
+			"called with %d bytes for dev %s\n", __func__, count,
+			sdio_tty_drv->tty_dev_name);
+	write_avail = sdio_write_avail(sdio_tty_drv->ch);
+	if (write_avail == 0) {
+		DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: "
+				"write_avail is 0 for dev %s\n",
+				__func__, sdio_tty_drv->tty_dev_name);
+		return 0;
+	}
+	if (write_avail > SDIO_TTY_MAX_PACKET_SIZE) {
+		DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: "
+				"write_avail(%d) is bigger than max packet "
+				"size(%d) for dev %s, setting to "
+				"max_packet_size\n", __func__, write_avail,
+				SDIO_TTY_MAX_PACKET_SIZE,
+				sdio_tty_drv->tty_dev_name);
+		write_avail = SDIO_TTY_MAX_PACKET_SIZE;
+	}
+	if (write_avail < count) {
+		DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: "
+				"write_avail(%d) is smaller than required(%d) "
+				"for dev %s, writing only %d bytes\n",
+				__func__, write_avail, count,
+				sdio_tty_drv->tty_dev_name, write_avail);
+		len = write_avail;
+	}
+	ret = sdio_write(sdio_tty_drv->ch, buf, len);
+	if (ret) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_write failed for "
+			"dev %s, ret=%d\n", __func__,
+			sdio_tty_drv->tty_dev_name, ret);
+		return 0;
+	}
+
+	sdio_tty_drv->total_tx += len;
+
+	DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: Tx: %d, "
+			"Total Tx = %d for dev %s", __func__, len,
+			sdio_tty_drv->total_tx, sdio_tty_drv->tty_dev_name);
+	return len;
+}
+
+static void sdio_tty_notify(void *priv, unsigned event)
+{
+	struct sdio_tty *sdio_tty_drv = priv;
+
+	if (!sdio_tty_drv) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
+			__func__);
+	}
+
+	if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
+			__func__, sdio_tty_drv->sdio_tty_state);
+		return;
+	}
+
+	DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: event %d "
+			"received for dev %s\n", __func__, event,
+			sdio_tty_drv->tty_dev_name);
+
+	if (event == SDIO_EVENT_DATA_READ_AVAIL)
+		queue_work(sdio_tty_drv->workq, &sdio_tty_drv->work_read);
+}
+
+/**
+  * sdio_tty_open
+  * This is the open callback of the tty driver. it opens
+  * the sdio channel, and creates the workqueue.
+  *
+  * @tty: a pointer to the tty struct.
+  * @file: file descriptor.
+  * @return 0 on success or negative value on error.
+  */
+static int sdio_tty_open(struct tty_struct *tty, struct file *file)
+{
+	int ret = 0;
+	int i = 0;
+	struct sdio_tty *sdio_tty_drv = NULL;
+
+	if (!tty) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty", __func__);
+		return -ENODEV;
+	}
+
+	for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) {
+		if (sdio_tty[i] == NULL)
+			continue;
+		if (!strncmp(sdio_tty[i]->tty_dev_name, tty->name,
+				MAX_SDIO_TTY_DEV_NAME_SIZE)) {
+			sdio_tty_drv = sdio_tty[i];
+			break;
+		}
+	}
+
+	if (!sdio_tty_drv) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
+		       __func__);
+		return -ENODEV;
+	}
+
+	sdio_tty_drv->tty_open_count++;
+	if (sdio_tty_drv->sdio_tty_state == TTY_OPENED) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: tty dev(%s) is already open",
+			__func__, sdio_tty_drv->tty_dev_name);
+		return -EBUSY;
+	}
+
+	tty->driver_data = sdio_tty_drv;
+
+	sdio_tty_drv->tty_str = tty;
+	sdio_tty_drv->tty_str->low_latency = 1;
+	sdio_tty_drv->tty_str->icanon = 0;
+	set_bit(TTY_NO_WRITE_SPLIT, &sdio_tty_drv->tty_str->flags);
+
+	sdio_tty_drv->read_buf = kzalloc(SDIO_TTY_MAX_PACKET_SIZE, GFP_KERNEL);
+	if (sdio_tty_drv->read_buf == NULL) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: failed to allocate read_buf "
+			"for dev %s", __func__, sdio_tty_drv->tty_dev_name);
+		return -ENOMEM;
+	}
+
+	sdio_tty_drv->workq = create_singlethread_workqueue("sdio_tty_read");
+	if (!sdio_tty_drv->workq) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: failed to create workq "
+			"for dev %s", __func__, sdio_tty_drv->tty_dev_name);
+		return -ENOMEM;
+	}
+
+	if (!sdio_tty_drv->is_sdio_open) {
+		ret = sdio_open(sdio_tty_drv->sdio_ch_name, &sdio_tty_drv->ch,
+				sdio_tty_drv, sdio_tty_notify);
+		if (ret < 0) {
+			pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_open err=%d "
+				"for dev %s\n", __func__, ret,
+				sdio_tty_drv->tty_dev_name);
+			destroy_workqueue(sdio_tty_drv->workq);
+			return ret;
+		}
+
+		pr_info(SDIO_TTY_MODULE_NAME ": %s: SDIO_TTY channel(%s) "
+			"opened\n", __func__, sdio_tty_drv->sdio_ch_name);
+
+		sdio_tty_drv->is_sdio_open = 1;
+	} else {
+		/* If SDIO channel is already open try to read the data
+		 * from the modem
+		 */
+		queue_work(sdio_tty_drv->workq, &sdio_tty_drv->work_read);
+
+	}
+
+	sdio_tty_drv->sdio_tty_state = TTY_OPENED;
+
+	pr_info(SDIO_TTY_MODULE_NAME ": %s: TTY device(%s) opened\n",
+		__func__, sdio_tty_drv->tty_dev_name);
+
+	return ret;
+}
+
+/**
+  * sdio_tty_close
+  * This is the close callback of the tty driver. it requests
+  * the main thread to exit, and waits for notification of it.
+  * it also de-allocates the buffers, and unregisters the tty
+  * driver and device.
+  *
+  * @tty: a pointer to the tty struct.
+  * @file: file descriptor.
+  * @return None.
+  */
+static void sdio_tty_close(struct tty_struct *tty, struct file *file)
+{
+	struct sdio_tty *sdio_tty_drv = NULL;
+
+	if (!tty) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty", __func__);
+		return;
+	}
+	sdio_tty_drv = tty->driver_data;
+	if (!sdio_tty_drv) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
+		       __func__);
+		return;
+	}
+	if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: trying to close a "
+			"TTY device that was not opened\n", __func__);
+		return;
+	}
+	if (--sdio_tty_drv->tty_open_count != 0)
+		return;
+
+	flush_workqueue(sdio_tty_drv->workq);
+	destroy_workqueue(sdio_tty_drv->workq);
+
+	kfree(sdio_tty_drv->read_buf);
+	sdio_tty_drv->read_buf = NULL;
+
+	sdio_tty_drv->sdio_tty_state = TTY_CLOSED;
+
+	pr_info(SDIO_TTY_MODULE_NAME ": %s: SDIO_TTY device(%s) closed\n",
+		__func__, sdio_tty_drv->tty_dev_name);
+}
+
+static void sdio_tty_unthrottle(struct tty_struct *tty)
+{
+	struct sdio_tty *sdio_tty_drv = NULL;
+
+	if (!tty) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty", __func__);
+		return;
+	}
+	sdio_tty_drv = tty->driver_data;
+	if (!sdio_tty_drv) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
+		       __func__);
+		return;
+	}
+
+	if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
+		       __func__, sdio_tty_drv->sdio_tty_state);
+		return;
+	}
+
+	queue_work(sdio_tty_drv->workq, &sdio_tty_drv->work_read);
+	return;
+}
+
+static const struct tty_operations sdio_tty_ops = {
+	.open = sdio_tty_open,
+	.close = sdio_tty_close,
+	.write = sdio_tty_write_callback,
+	.write_room = sdio_tty_write_room,
+	.unthrottle = sdio_tty_unthrottle,
+};
+
+int sdio_tty_init_tty(char *tty_name, char *sdio_ch_name,
+			enum sdio_tty_devices device_id, int debug_msg_on)
+{
+	int ret = 0;
+	int i = 0;
+	struct device *tty_dev = NULL;
+	struct sdio_tty *sdio_tty_drv = NULL;
+
+	sdio_tty_drv = kzalloc(sizeof(struct sdio_tty), GFP_KERNEL);
+	if (sdio_tty_drv == NULL) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: failed to allocate sdio_tty "
+			"for dev %s", __func__, tty_name);
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) {
+		if (sdio_tty[i] == NULL) {
+			sdio_tty[i] = sdio_tty_drv;
+			break;
+		}
+	}
+
+	if (i == MAX_SDIO_TTY_DEVS) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: tty dev(%s) creation failed,"
+			" max limit(%d) reached.", __func__, tty_name,
+			MAX_SDIO_TTY_DEVS);
+		kfree(sdio_tty_drv);
+		return -ENODEV;
+	}
+
+	snprintf(sdio_tty_drv->tty_dev_name, MAX_SDIO_TTY_DEV_NAME_SIZE,
+			"%s%d", tty_name, 0);
+	sdio_tty_drv->sdio_ch_name = sdio_ch_name;
+	sdio_tty_drv->device_id = device_id;
+	pr_info(SDIO_TTY_MODULE_NAME ": %s: dev=%s, id=%d, channel=%s\n",
+		__func__, sdio_tty_drv->tty_dev_name, sdio_tty_drv->device_id,
+		sdio_tty_drv->sdio_ch_name);
+
+	INIT_WORK(&sdio_tty_drv->work_read, sdio_tty_read);
+
+	sdio_tty_drv->tty_drv = alloc_tty_driver(MAX_SDIO_TTY_DRV);
+
+	if (!sdio_tty_drv->tty_drv) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s - tty_drv is NULL for dev %s",
+			__func__, sdio_tty_drv->tty_dev_name);
+		kfree(sdio_tty_drv);
+		return -ENODEV;
+	}
+
+	sdio_tty_drv->tty_drv->name = tty_name;
+	sdio_tty_drv->tty_drv->owner = THIS_MODULE;
+	sdio_tty_drv->tty_drv->driver_name = "SDIO_tty";
+	/* uses dynamically assigned dev_t values */
+	sdio_tty_drv->tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
+	sdio_tty_drv->tty_drv->subtype = SERIAL_TYPE_NORMAL;
+	sdio_tty_drv->tty_drv->flags = TTY_DRIVER_REAL_RAW
+		| TTY_DRIVER_DYNAMIC_DEV
+		| TTY_DRIVER_RESET_TERMIOS;
+
+	/* initializing the tty driver */
+	sdio_tty_drv->tty_drv->init_termios = tty_std_termios;
+	sdio_tty_drv->tty_drv->init_termios.c_cflag =
+		B4800 | CS8 | CREAD | HUPCL | CLOCAL;
+	sdio_tty_drv->tty_drv->init_termios.c_ispeed = INPUT_SPEED;
+	sdio_tty_drv->tty_drv->init_termios.c_ospeed = OUTPUT_SPEED;
+
+	tty_set_operations(sdio_tty_drv->tty_drv, &sdio_tty_ops);
+
+	ret = tty_register_driver(sdio_tty_drv->tty_drv);
+	if (ret) {
+		put_tty_driver(sdio_tty_drv->tty_drv);
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: tty_register_driver() "
+			"failed for dev %s\n", __func__,
+			sdio_tty_drv->tty_dev_name);
+
+		sdio_tty_drv->tty_drv = NULL;
+		kfree(sdio_tty_drv);
+		return -ENODEV;
+	}
+
+	tty_dev = tty_register_device(sdio_tty_drv->tty_drv, 0, NULL);
+	if (IS_ERR(tty_dev)) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: tty_register_device() "
+			"failed for dev %s\n", __func__,
+			sdio_tty_drv->tty_dev_name);
+		tty_unregister_driver(sdio_tty_drv->tty_drv);
+		put_tty_driver(sdio_tty_drv->tty_drv);
+		kfree(sdio_tty_drv);
+		return -ENODEV;
+	}
+
+	sdio_tty_drv->sdio_tty_state = TTY_REGISTERED;
+	if (debug_msg_on) {
+		pr_info(SDIO_TTY_MODULE_NAME ": %s: turn on debug msg for %s",
+			__func__, sdio_tty_drv->tty_dev_name);
+		sdio_tty_drv->debug_msg_on = debug_msg_on;
+	}
+	return 0;
+}
+
+int sdio_tty_uninit_tty(void *sdio_tty_handle)
+{
+	int ret = 0;
+	int i = 0;
+	struct sdio_tty *sdio_tty_drv = sdio_tty_handle;
+
+	if (!sdio_tty_drv) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
+		       __func__);
+		return -ENODEV;
+	}
+	if (sdio_tty_drv->sdio_tty_state == TTY_OPENED) {
+		flush_workqueue(sdio_tty_drv->workq);
+		destroy_workqueue(sdio_tty_drv->workq);
+
+		kfree(sdio_tty_drv->read_buf);
+		sdio_tty_drv->read_buf = NULL;
+	}
+
+	if (sdio_tty_drv->sdio_tty_state != TTY_INITIAL) {
+		tty_unregister_device(sdio_tty_drv->tty_drv, 0);
+
+		ret = tty_unregister_driver(sdio_tty_drv->tty_drv);
+		if (ret) {
+			pr_err(SDIO_TTY_MODULE_NAME ": %s: "
+				"tty_unregister_driver() failed for dev %s\n",
+				__func__, sdio_tty_drv->tty_dev_name);
+		}
+		put_tty_driver(sdio_tty_drv->tty_drv);
+		sdio_tty_drv->sdio_tty_state = TTY_INITIAL;
+		sdio_tty_drv->tty_drv = NULL;
+	}
+
+	for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) {
+		if (sdio_tty[i] == NULL)
+			continue;
+		if (sdio_tty[i]->device_id == sdio_tty_drv->device_id) {
+			sdio_tty[i] = NULL;
+			break;
+		}
+	}
+
+	DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: Freeing sdio_tty "
+			"structure, dev=%s", __func__,
+			sdio_tty_drv->tty_dev_name);
+	kfree(sdio_tty_drv);
+
+	return 0;
+}
+
+static int sdio_tty_probe(struct platform_device *pdev)
+{
+	const struct platform_device_id *id = platform_get_device_id(pdev);
+	enum sdio_tty_devices device_id = id->driver_data;
+	char *device_name = NULL;
+	char *channel_name = NULL;
+	int debug_msg_on = 0;
+	int ret = 0;
+
+	pr_debug(SDIO_TTY_MODULE_NAME ": %s for %s", __func__, pdev->name);
+
+	switch (device_id) {
+	case SDIO_CSVT:
+		device_name = SDIO_TTY_CSVT_DEV;
+		channel_name = SDIO_TTY_CH_CSVT;
+		debug_msg_on = csvt_debug_msg_on;
+		break;
+	case SDIO_CSVT_TEST_APP:
+		device_name = SDIO_TTY_CSVT_TEST_DEV;
+		channel_name = SDIO_TTY_CH_CSVT;
+		debug_msg_on = csvt_debug_msg_on;
+		break;
+	default:
+		pr_err(SDIO_TTY_MODULE_NAME ": %s Invalid device:%s, id:%d",
+			__func__, pdev->name, device_id);
+		ret = -ENODEV;
+		break;
+	}
+
+	if (device_name) {
+		ret = sdio_tty_init_tty(device_name, channel_name,
+					device_id, debug_msg_on);
+		if (ret) {
+			pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_init_tty "
+				"failed for dev:%s", __func__, device_name);
+		}
+	}
+	return ret;
+}
+
+static int sdio_tty_remove(struct platform_device *pdev)
+{
+	const struct platform_device_id *id = platform_get_device_id(pdev);
+	enum sdio_tty_devices device_id = id->driver_data;
+	struct sdio_tty *sdio_tty_drv = NULL;
+	int i = 0;
+	int ret = 0;
+
+	pr_debug(SDIO_TTY_MODULE_NAME ": %s for %s", __func__, pdev->name);
+
+	for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) {
+		if (sdio_tty[i] == NULL)
+			continue;
+		if (sdio_tty[i]->device_id == device_id) {
+			sdio_tty_drv = sdio_tty[i];
+			break;
+		}
+	}
+
+	if (!sdio_tty_drv) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
+		       __func__);
+		return -ENODEV;
+	}
+
+	ret = sdio_tty_uninit_tty(sdio_tty_drv);
+	if (ret) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_uninit_tty "
+			"failed for %s", __func__, pdev->name);
+	}
+	return ret;
+}
+
+static struct platform_driver sdio_tty_pdrv = {
+	.probe		= sdio_tty_probe,
+	.remove		= sdio_tty_remove,
+	.id_table	= sdio_tty_id_table,
+	.driver		= {
+		.name	= "SDIO_TTY",
+		.owner	= THIS_MODULE,
+	},
+};
+
+#ifdef CONFIG_DEBUG_FS
+void sdio_tty_print_info(void)
+{
+	int i = 0;
+
+	for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) {
+		if (sdio_tty[i] == NULL)
+			continue;
+		pr_info(SDIO_TTY_MODULE_NAME ": %s: Total Rx=%d, Tx = %d "
+			"for dev %s", __func__, sdio_tty[i]->total_rx,
+			sdio_tty[i]->total_tx, sdio_tty[i]->tty_dev_name);
+	}
+}
+
+static int tty_debug_info_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t tty_debug_info_write(struct file *file,
+		const char __user *buf, size_t count, loff_t *ppos)
+{
+	sdio_tty_print_info();
+	return count;
+}
+
+const struct file_operations tty_debug_info_ops = {
+	.open = tty_debug_info_open,
+	.write = tty_debug_info_write,
+};
+#endif
+
+/*
+ *  Module Init.
+ *
+ *  Register SDIO TTY driver.
+ *
+ */
+static int __init sdio_tty_init(void)
+{
+	int ret = 0;
+
+	ret = platform_driver_register(&sdio_tty_pdrv);
+	if (ret) {
+		pr_err(SDIO_TTY_MODULE_NAME ": %s: platform_driver_register "
+					    "failed", __func__);
+	}
+#ifdef CONFIG_DEBUG_FS
+	else {
+		sdio_tty_debug_root = debugfs_create_dir("sdio_tty", NULL);
+		if (sdio_tty_debug_root) {
+			sdio_tty_debug_info = debugfs_create_file(
+							"sdio_tty_debug",
+							S_IRUGO | S_IWUGO,
+							sdio_tty_debug_root,
+							NULL,
+							&tty_debug_info_ops);
+		}
+	}
+#endif
+	return ret;
+};
+
+/*
+ *  Module Exit.
+ *
+ *  Unregister SDIO TTY driver.
+ *
+ */
+static void __exit sdio_tty_exit(void)
+{
+#ifdef CONFIG_DEBUG_FS
+	debugfs_remove(sdio_tty_debug_info);
+	debugfs_remove(sdio_tty_debug_root);
+#endif
+	platform_driver_unregister(&sdio_tty_pdrv);
+}
+
+module_init(sdio_tty_init);
+module_exit(sdio_tty_exit);
+
+MODULE_DESCRIPTION("SDIO TTY");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Maya Erez <merez@codeaurora.org>");
diff --git a/arch/arm/mach-msm/sirc-fsm9xxx.c b/arch/arm/mach-msm/sirc-fsm9xxx.c
new file mode 100644
index 0000000..71fa60a
--- /dev/null
+++ b/arch/arm/mach-msm/sirc-fsm9xxx.c
@@ -0,0 +1,166 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+
+#include "sirc.h"
+
+static unsigned int sirc_int_enable[2];
+
+static struct sirc_regs_t sirc_regs = {
+	.int_enable       = SPSS_SIRC_INT_ENABLE,
+	.int_type         = SPSS_SIRC_INT_TYPE,
+	.int_polarity     = SPSS_SIRC_INT_POLARITY,
+	.int_clear        = SPSS_SIRC_INT_CLEAR,
+};
+
+static inline void sirc_get_group_offset_mask(unsigned int irq,
+	unsigned int *group, unsigned int *offset, unsigned int *mask)
+{
+	*group = 0;
+	*offset = irq - FIRST_SIRC_IRQ;
+	if (*offset >= NR_SIRC_IRQS_GROUPA) {
+		*group = 1;
+		*offset -= NR_SIRC_IRQS_GROUPA;
+	}
+	*mask = 1 << *offset;
+}
+
+static void sirc_irq_mask(struct irq_data *d)
+{
+	void *reg_enable;
+	unsigned int group, offset, mask;
+	unsigned int val;
+
+	sirc_get_group_offset_mask(d->irq, &group, &offset, &mask);
+
+	reg_enable = sirc_regs.int_enable + group * 4;
+	val = __raw_readl(reg_enable);
+	__raw_writel(val & ~mask, reg_enable);
+	sirc_int_enable[group] &= ~mask;
+	mb();
+}
+
+static void sirc_irq_unmask(struct irq_data *d)
+{
+	void *reg_enable;
+	void *reg_clear;
+	unsigned int group, offset, mask;
+	unsigned int val;
+
+	sirc_get_group_offset_mask(d->irq, &group, &offset, &mask);
+
+	if (irq_desc[d->irq].handle_irq == handle_level_irq) {
+		reg_clear = sirc_regs.int_clear + group * 4;
+		__raw_writel(mask, reg_clear);
+	}
+
+	reg_enable = sirc_regs.int_enable + group * 4;
+	val = __raw_readl(reg_enable);
+	__raw_writel(val | mask, reg_enable);
+	sirc_int_enable[group] |= mask;
+	mb();
+}
+
+static void sirc_irq_ack(struct irq_data *d)
+{
+	void *reg_clear;
+	unsigned int group, offset, mask;
+
+	sirc_get_group_offset_mask(d->irq, &group, &offset, &mask);
+
+	reg_clear = sirc_regs.int_clear + group * 4;
+	__raw_writel(mask, reg_clear);
+}
+
+static int sirc_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+	return 0;
+}
+
+static int sirc_irq_set_type(struct irq_data *d, unsigned int flow_type)
+{
+	void *reg_polarity, *reg_type;
+	unsigned int group, offset, mask;
+	unsigned int val;
+
+	sirc_get_group_offset_mask(d->irq, &group, &offset, &mask);
+
+	reg_polarity = sirc_regs.int_polarity + group * 4;
+	val = __raw_readl(reg_polarity);
+
+	if (flow_type & (IRQF_TRIGGER_LOW | IRQF_TRIGGER_FALLING))
+		val &= ~mask;
+	else
+		val |= mask;
+
+	__raw_writel(val, reg_polarity);
+
+	reg_type = sirc_regs.int_type + group * 4;
+	val = __raw_readl(reg_type);
+
+	if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
+		val |= mask;
+		irq_desc[d->irq].handle_irq = handle_edge_irq;
+	} else {
+		val &= ~mask;
+		irq_desc[d->irq].handle_irq = handle_level_irq;
+	}
+
+	__raw_writel(val, reg_type);
+
+	return 0;
+}
+
+/* Finds the pending interrupt on the passed cascade irq and redrives it */
+static void sirc_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	unsigned int sirq;
+
+	for (;;) {
+		sirq = __raw_readl(SPSS_SIRC_VEC_INDEX_RD);
+		if (sirq >= NR_SIRC_IRQS)
+			break;
+
+		generic_handle_irq(sirq + FIRST_SIRC_IRQ);
+	}
+
+	irq_desc_get_chip(desc)->irq_ack(irq_get_irq_data(irq));
+}
+
+static struct irq_chip sirc_irq_chip = {
+	.name		= "sirc",
+	.irq_ack	= sirc_irq_ack,
+	.irq_mask	= sirc_irq_mask,
+	.irq_unmask	= sirc_irq_unmask,
+	.irq_set_wake	= sirc_irq_set_wake,
+	.irq_set_type	= sirc_irq_set_type,
+};
+
+void __init msm_init_sirc(void)
+{
+	int i;
+
+	sirc_int_enable[0] = 0;
+	sirc_int_enable[1] = 0;
+
+	for (i = FIRST_SIRC_IRQ; i <= LAST_SIRC_IRQ; i++) {
+		irq_set_chip_and_handler(i, &sirc_irq_chip, handle_edge_irq);
+		set_irq_flags(i, IRQF_VALID);
+	}
+
+	irq_set_chained_handler(INT_SIRC_0, sirc_irq_handler);
+	irq_set_irq_wake(INT_SIRC_0, 1);
+}
diff --git a/arch/arm/mach-msm/sirc.c b/arch/arm/mach-msm/sirc.c
index 689e78c..04124c5 100644
--- a/arch/arm/mach-msm/sirc.c
+++ b/arch/arm/mach-msm/sirc.c
@@ -1,25 +1,29 @@
-/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+/* linux/arch/arm/mach-msm/irq.c
  *
- * 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.
+ * Copyright (c) 2009-2011 Code Aurora Forum. All rights reserved.
+ * Copyright (C) 2009 Google, Inc.
+ *
+ * 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.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
  */
 
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
+#include <linux/irqdesc.h>
 #include <asm/irq.h>
+#include <asm/io.h>
+#include <mach/fiq.h>
+#include <mach/msm_iomap.h>
+
+#include "sirc.h"
 
 static unsigned int int_enable;
 static unsigned int wake_enable;
@@ -37,9 +41,13 @@
 	{
 		.int_status  = SPSS_SIRC_IRQ_STATUS,
 		.cascade_irq = INT_SIRC_0,
+		.cascade_fiq = INT_SIRC_1,
 	}
 };
 
+static unsigned int save_type;
+static unsigned int save_polarity;
+
 /* Mask off the given interrupt. Keep the int_enable mask in sync with
    the enable reg, so it can be restored after power collapse. */
 static void sirc_irq_mask(struct irq_data *d)
@@ -49,6 +57,7 @@
 	mask = 1 << (d->irq - FIRST_SIRC_IRQ);
 	writel(mask, sirc_regs.int_enable_clear);
 	int_enable &= ~mask;
+	mb();
 	return;
 }
 
@@ -60,6 +69,7 @@
 
 	mask = 1 << (d->irq - FIRST_SIRC_IRQ);
 	writel(mask, sirc_regs.int_enable_set);
+	mb();
 	int_enable |= mask;
 	return;
 }
@@ -70,6 +80,7 @@
 
 	mask = 1 << (d->irq - FIRST_SIRC_IRQ);
 	writel(mask, sirc_regs.int_clear);
+	mb();
 	return;
 }
 
@@ -105,17 +116,35 @@
 	val = readl(sirc_regs.int_type);
 	if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
 		val |= mask;
-		__irq_set_handler_locked(d->irq, handle_edge_irq);
 	} else {
 		val &= ~mask;
-		__irq_set_handler_locked(d->irq, handle_level_irq);
 	}
 
 	writel(val, sirc_regs.int_type);
+	mb();
 
 	return 0;
 }
 
+#if defined(CONFIG_MSM_FIQ_SUPPORT)
+void sirc_fiq_select(int irq, bool enable)
+{
+	uint32_t mask = 1 << (irq - FIRST_SIRC_IRQ);
+	uint32_t val;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	val = readl(SPSS_SIRC_INT_SELECT);
+	if (enable)
+		val |= mask;
+	else
+		val &= ~mask;
+	writel(val, SPSS_SIRC_INT_SELECT);
+	mb();
+	local_irq_restore(flags);
+}
+#endif
+
 /* Finds the pending interrupt on the passed cascade irq and redrives it */
 static void sirc_irq_handler(unsigned int irq, struct irq_desc *desc)
 {
@@ -127,6 +156,12 @@
 		(sirc_reg_table[reg].cascade_irq != irq))
 		reg++;
 
+	if (reg == ARRAY_SIZE(sirc_reg_table)) {
+		printk(KERN_ERR "%s: incorrect irq %d called\n",
+			__func__, irq);
+		return;
+	}
+
 	status = readl(sirc_reg_table[reg].int_status);
 	status &= SIRC_MASK;
 	if (status == 0)
@@ -138,16 +173,34 @@
 		;
 	generic_handle_irq(sirq+FIRST_SIRC_IRQ);
 
-	desc->irq_data.chip->irq_ack(&desc->irq_data);
+	irq_desc_get_chip(desc)->irq_ack(irq_get_irq_data(irq));
+}
+
+void msm_sirc_enter_sleep(void)
+{
+	save_type     = readl(sirc_regs.int_type);
+	save_polarity = readl(sirc_regs.int_polarity);
+	writel(wake_enable, sirc_regs.int_enable);
+	mb();
+	return;
+}
+
+void msm_sirc_exit_sleep(void)
+{
+	writel(save_type, sirc_regs.int_type);
+	writel(save_polarity, sirc_regs.int_polarity);
+	writel(int_enable, sirc_regs.int_enable);
+	mb();
+	return;
 }
 
 static struct irq_chip sirc_irq_chip = {
-	.name          = "sirc",
-	.irq_ack       = sirc_irq_ack,
-	.irq_mask      = sirc_irq_mask,
-	.irq_unmask    = sirc_irq_unmask,
-	.irq_set_wake  = sirc_irq_set_wake,
-	.irq_set_type  = sirc_irq_set_type,
+	.name		= "sirc",
+	.irq_ack	= sirc_irq_ack,
+	.irq_mask	= sirc_irq_mask,
+	.irq_unmask	= sirc_irq_unmask,
+	.irq_set_wake	= sirc_irq_set_wake,
+	.irq_set_type	= sirc_irq_set_type,
 };
 
 void __init msm_init_sirc(void)
@@ -166,6 +219,10 @@
 		irq_set_chained_handler(sirc_reg_table[i].cascade_irq,
 					sirc_irq_handler);
 		irq_set_irq_wake(sirc_reg_table[i].cascade_irq, 1);
+#if defined(CONFIG_MSM_FIQ_SUPPORT)
+		msm_fiq_select(sirc_reg_table[i].cascade_fiq);
+		msm_fiq_enable(sirc_reg_table[i].cascade_fiq);
+#endif
 	}
 	return;
 }
diff --git a/arch/arm/mach-msm/sirc.h b/arch/arm/mach-msm/sirc.h
new file mode 100644
index 0000000..f719969
--- /dev/null
+++ b/arch/arm/mach-msm/sirc.h
@@ -0,0 +1,36 @@
+/* arch/arm/mach-msm/sirc.h
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (c) 2011, Code Aurora Forum. 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 _ARCH_ARM_MACH_MSM_SIRC_H
+#define _ARCH_ARM_MACH_MSM_SIRC_H
+
+#if defined(CONFIG_ARCH_MSM_SCORPION) && !defined(CONFIG_MSM_SMP)
+void sirc_fiq_select(int irq, bool enable);
+#else
+static inline void sirc_fiq_select(int irq, bool enable) {}
+#endif
+
+#if defined(CONFIG_ARCH_QSD8X50) || defined(CONFIG_ARCH_FSM9XXX)
+void __init msm_init_sirc(void);
+void msm_sirc_enter_sleep(void);
+void msm_sirc_exit_sleep(void);
+#else
+static inline void __init msm_init_sirc(void) {}
+static inline void msm_sirc_enter_sleep(void) { }
+static inline void msm_sirc_exit_sleep(void) { }
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index 657be73..54512ab 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -1,6 +1,7 @@
 /* arch/arm/mach-msm/smd.c
  *
  * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -14,8 +15,6 @@
  *
  */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include <linux/platform_device.h>
 #include <linux/module.h>
 #include <linux/fs.h>
@@ -26,109 +25,596 @@
 #include <linux/irq.h>
 #include <linux/list.h>
 #include <linux/slab.h>
-#include <linux/debugfs.h>
 #include <linux/delay.h>
-
+#include <linux/io.h>
+#include <linux/termios.h>
+#include <linux/ctype.h>
+#include <linux/remote_spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/kfifo.h>
+#include <linux/wakelock.h>
+#include <linux/notifier.h>
+#include <linux/sort.h>
 #include <mach/msm_smd.h>
+#include <mach/msm_iomap.h>
 #include <mach/system.h>
+#include <mach/subsystem_notif.h>
+#include <mach/socinfo.h>
+#include <mach/proc_comm.h>
+#include <asm/cacheflush.h>
 
 #include "smd_private.h"
-#include "proc_comm.h"
+#include "modem_notifier.h"
 
-#if defined(CONFIG_ARCH_QSD8X50)
+#if defined(CONFIG_ARCH_QSD8X50) || defined(CONFIG_ARCH_MSM8X60) \
+	|| defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_FSM9XXX) \
+	|| defined(CONFIG_ARCH_MSM9615)	|| defined(CONFIG_ARCH_APQ8064)
 #define CONFIG_QDSP6 1
 #endif
 
-void (*msm_hw_reset_hook)(void);
+#if defined(CONFIG_ARCH_MSM8X60) || defined(CONFIG_ARCH_MSM8960) \
+	|| defined(CONFIG_ARCH_APQ8064)
+#define CONFIG_DSPS 1
+#endif
+
+#if defined(CONFIG_ARCH_MSM8960) \
+	|| defined(CONFIG_ARCH_APQ8064)
+#define CONFIG_WCNSS 1
+#define CONFIG_DSPS_SMSM 1
+#endif
 
 #define MODULE_NAME "msm_smd"
+#define SMEM_VERSION 0x000B
+#define SMD_VERSION 0x00020000
+#define SMSM_SNAPSHOT_CNT 64
+#define SMSM_SNAPSHOT_SIZE ((SMSM_NUM_ENTRIES + 1) * 4)
+
+uint32_t SMSM_NUM_ENTRIES = 8;
+uint32_t SMSM_NUM_HOSTS = 3;
+
+/* Legacy SMSM interrupt notifications */
+#define LEGACY_MODEM_SMSM_MASK (SMSM_RESET | SMSM_INIT | SMSM_SMDINIT \
+			| SMSM_RUN | SMSM_SYSTEM_DOWNLOAD)
 
 enum {
 	MSM_SMD_DEBUG = 1U << 0,
-	MSM_SMSM_DEBUG = 1U << 0,
+	MSM_SMSM_DEBUG = 1U << 1,
+	MSM_SMD_INFO = 1U << 2,
+	MSM_SMSM_INFO = 1U << 3,
+	MSM_SMx_POWER_INFO = 1U << 4,
+};
+
+struct smsm_shared_info {
+	uint32_t *state;
+	uint32_t *intr_mask;
+	uint32_t *intr_mux;
+};
+
+static struct smsm_shared_info smsm_info;
+static struct kfifo smsm_snapshot_fifo;
+static struct wake_lock smsm_snapshot_wakelock;
+static int smsm_snapshot_count;
+static DEFINE_SPINLOCK(smsm_snapshot_count_lock);
+
+struct smsm_size_info_type {
+	uint32_t num_hosts;
+	uint32_t num_entries;
+	uint32_t reserved0;
+	uint32_t reserved1;
+};
+
+struct smsm_state_cb_info {
+	struct list_head cb_list;
+	uint32_t mask;
+	void *data;
+	void (*notify)(void *data, uint32_t old_state, uint32_t new_state);
+};
+
+struct smsm_state_info {
+	struct list_head callbacks;
+	uint32_t last_value;
+	uint32_t intr_mask_set;
+	uint32_t intr_mask_clear;
+};
+
+struct interrupt_config_item {
+	/* must be initialized */
+	irqreturn_t (*irq_handler)(int req, void *data);
+	/* outgoing interrupt config (set from platform data) */
+	uint32_t out_bit_pos;
+	void __iomem *out_base;
+	uint32_t out_offset;
+};
+
+struct interrupt_config {
+	struct interrupt_config_item smd;
+	struct interrupt_config_item smsm;
+};
+
+static irqreturn_t smd_modem_irq_handler(int irq, void *data);
+static irqreturn_t smsm_modem_irq_handler(int irq, void *data);
+static irqreturn_t smd_dsp_irq_handler(int irq, void *data);
+static irqreturn_t smsm_dsp_irq_handler(int irq, void *data);
+static irqreturn_t smd_dsps_irq_handler(int irq, void *data);
+static irqreturn_t smsm_dsps_irq_handler(int irq, void *data);
+static irqreturn_t smd_wcnss_irq_handler(int irq, void *data);
+static irqreturn_t smsm_wcnss_irq_handler(int irq, void *data);
+static irqreturn_t smd_rpm_irq_handler(int irq, void *data);
+static irqreturn_t smsm_irq_handler(int irq, void *data);
+
+static struct interrupt_config private_intr_config[NUM_SMD_SUBSYSTEMS] = {
+	[SMD_MODEM] = {
+		.smd.irq_handler = smd_modem_irq_handler,
+		.smsm.irq_handler = smsm_modem_irq_handler,
+	},
+	[SMD_Q6] = {
+		.smd.irq_handler = smd_dsp_irq_handler,
+		.smsm.irq_handler = smsm_dsp_irq_handler,
+	},
+	[SMD_DSPS] = {
+		.smd.irq_handler = smd_dsps_irq_handler,
+		.smsm.irq_handler = smsm_dsps_irq_handler,
+	},
+	[SMD_WCNSS] = {
+		.smd.irq_handler = smd_wcnss_irq_handler,
+		.smsm.irq_handler = smsm_wcnss_irq_handler,
+	},
+	[SMD_RPM] = {
+		.smd.irq_handler = smd_rpm_irq_handler,
+		.smsm.irq_handler = NULL, /* does not support smsm */
+	},
+};
+
+struct smem_area {
+	void *phys_addr;
+	unsigned size;
+	void __iomem *virt_addr;
+};
+static uint32_t num_smem_areas;
+static struct smem_area *smem_areas;
+static void *smem_range_check(void *base, unsigned offset);
+
+struct interrupt_stat interrupt_stats[NUM_SMD_SUBSYSTEMS];
+
+#define SMSM_STATE_ADDR(entry)           (smsm_info.state + entry)
+#define SMSM_INTR_MASK_ADDR(entry, host) (smsm_info.intr_mask + \
+					  entry * SMSM_NUM_HOSTS + host)
+#define SMSM_INTR_MUX_ADDR(entry)        (smsm_info.intr_mux + entry)
+
+/* Internal definitions which are not exported in some targets */
+enum {
+	SMSM_APPS_DEM_I = 3,
 };
 
 static int msm_smd_debug_mask;
-
-struct shared_info {
-	int ready;
-	unsigned state;
-};
-
-static unsigned dummy_state[SMSM_STATE_COUNT];
-
-static struct shared_info smd_info = {
-	.state = (unsigned) &dummy_state,
-};
-
 module_param_named(debug_mask, msm_smd_debug_mask,
 		   int, S_IRUGO | S_IWUSR | S_IWGRP);
 
+#if defined(CONFIG_MSM_SMD_DEBUG)
+#define SMD_DBG(x...) do {				\
+		if (msm_smd_debug_mask & MSM_SMD_DEBUG) \
+			printk(KERN_DEBUG x);		\
+	} while (0)
+
+#define SMSM_DBG(x...) do {					\
+		if (msm_smd_debug_mask & MSM_SMSM_DEBUG)	\
+			printk(KERN_DEBUG x);			\
+	} while (0)
+
+#define SMD_INFO(x...) do {			 	\
+		if (msm_smd_debug_mask & MSM_SMD_INFO)	\
+			printk(KERN_INFO x);		\
+	} while (0)
+
+#define SMSM_INFO(x...) do {				\
+		if (msm_smd_debug_mask & MSM_SMSM_INFO) \
+			printk(KERN_INFO x);		\
+	} while (0)
+#define SMx_POWER_INFO(x...) do {				\
+		if (msm_smd_debug_mask & MSM_SMx_POWER_INFO) \
+			printk(KERN_INFO x);		\
+	} while (0)
+#else
+#define SMD_DBG(x...) do { } while (0)
+#define SMSM_DBG(x...) do { } while (0)
+#define SMD_INFO(x...) do { } while (0)
+#define SMSM_INFO(x...) do { } while (0)
+#define SMx_POWER_INFO(x...) do { } while (0)
+#endif
+
 static unsigned last_heap_free = 0xffffffff;
 
-static inline void notify_other_smsm(void)
-{
-	msm_a2m_int(5);
-#ifdef CONFIG_QDSP6
-	msm_a2m_int(8);
+static inline void smd_write_intr(unsigned int val,
+				const void __iomem *addr);
+
+#if defined(CONFIG_ARCH_MSM7X30)
+#define MSM_TRIG_A2M_SMD_INT     \
+			(smd_write_intr(1 << 0, MSM_APCS_GCC_BASE + 0x8))
+#define MSM_TRIG_A2Q6_SMD_INT    \
+			(smd_write_intr(1 << 8, MSM_APCS_GCC_BASE + 0x8))
+#define MSM_TRIG_A2M_SMSM_INT    \
+			(smd_write_intr(1 << 5, MSM_APCS_GCC_BASE + 0x8))
+#define MSM_TRIG_A2Q6_SMSM_INT   \
+			(smd_write_intr(1 << 8, MSM_APCS_GCC_BASE + 0x8))
+#define MSM_TRIG_A2DSPS_SMD_INT
+#define MSM_TRIG_A2DSPS_SMSM_INT
+#define MSM_TRIG_A2WCNSS_SMD_INT
+#define MSM_TRIG_A2WCNSS_SMSM_INT
+#elif defined(CONFIG_ARCH_MSM8X60)
+#define MSM_TRIG_A2M_SMD_INT     \
+			(smd_write_intr(1 << 3, MSM_GCC_BASE + 0x8))
+#define MSM_TRIG_A2Q6_SMD_INT    \
+			(smd_write_intr(1 << 15, MSM_GCC_BASE + 0x8))
+#define MSM_TRIG_A2M_SMSM_INT    \
+			(smd_write_intr(1 << 4, MSM_GCC_BASE + 0x8))
+#define MSM_TRIG_A2Q6_SMSM_INT   \
+			(smd_write_intr(1 << 14, MSM_GCC_BASE + 0x8))
+#define MSM_TRIG_A2DSPS_SMD_INT  \
+			(smd_write_intr(1, MSM_SIC_NON_SECURE_BASE + 0x4080))
+#define MSM_TRIG_A2DSPS_SMSM_INT
+#define MSM_TRIG_A2WCNSS_SMD_INT
+#define MSM_TRIG_A2WCNSS_SMSM_INT
+#elif defined(CONFIG_ARCH_MSM9615)
+#define MSM_TRIG_A2M_SMD_INT     \
+			(smd_write_intr(1 << 3, MSM_APCS_GCC_BASE + 0x8))
+#define MSM_TRIG_A2Q6_SMD_INT    \
+			(smd_write_intr(1 << 15, MSM_APCS_GCC_BASE + 0x8))
+#define MSM_TRIG_A2M_SMSM_INT    \
+			(smd_write_intr(1 << 4, MSM_APCS_GCC_BASE + 0x8))
+#define MSM_TRIG_A2Q6_SMSM_INT   \
+			(smd_write_intr(1 << 14, MSM_APCS_GCC_BASE + 0x8))
+#define MSM_TRIG_A2DSPS_SMD_INT
+#define MSM_TRIG_A2DSPS_SMSM_INT
+#define MSM_TRIG_A2WCNSS_SMD_INT
+#define MSM_TRIG_A2WCNSS_SMSM_INT
+#elif defined(CONFIG_ARCH_FSM9XXX)
+#define MSM_TRIG_A2Q6_SMD_INT	\
+			(smd_write_intr(1 << 10, MSM_GCC_BASE + 0x8))
+#define MSM_TRIG_A2Q6_SMSM_INT	\
+			(smd_write_intr(1 << 10, MSM_GCC_BASE + 0x8))
+#define MSM_TRIG_A2M_SMD_INT	\
+			(smd_write_intr(1 << 0, MSM_GCC_BASE + 0x8))
+#define MSM_TRIG_A2M_SMSM_INT	\
+			(smd_write_intr(1 << 5, MSM_GCC_BASE + 0x8))
+#define MSM_TRIG_A2DSPS_SMD_INT
+#define MSM_TRIG_A2DSPS_SMSM_INT
+#define MSM_TRIG_A2WCNSS_SMD_INT
+#define MSM_TRIG_A2WCNSS_SMSM_INT
+#elif defined(CONFIG_ARCH_MSM7X01A) || defined(CONFIG_ARCH_MSM7x25)
+#define MSM_TRIG_A2M_SMD_INT     \
+			(smd_write_intr(1, MSM_CSR_BASE + 0x400 + (0) * 4))
+#define MSM_TRIG_A2Q6_SMD_INT
+#define MSM_TRIG_A2M_SMSM_INT    \
+			(smd_write_intr(1, MSM_CSR_BASE + 0x400 + (5) * 4))
+#define MSM_TRIG_A2Q6_SMSM_INT
+#define MSM_TRIG_A2DSPS_SMD_INT
+#define MSM_TRIG_A2DSPS_SMSM_INT
+#define MSM_TRIG_A2WCNSS_SMD_INT
+#define MSM_TRIG_A2WCNSS_SMSM_INT
+#elif defined(CONFIG_ARCH_MSM7X27) || defined(CONFIG_ARCH_MSM7X27A)
+#define MSM_TRIG_A2M_SMD_INT     \
+			(smd_write_intr(1, MSM_CSR_BASE + 0x400 + (0) * 4))
+#define MSM_TRIG_A2Q6_SMD_INT
+#define MSM_TRIG_A2M_SMSM_INT    \
+			(smd_write_intr(1, MSM_CSR_BASE + 0x400 + (5) * 4))
+#define MSM_TRIG_A2Q6_SMSM_INT
+#define MSM_TRIG_A2DSPS_SMD_INT
+#define MSM_TRIG_A2DSPS_SMSM_INT
+#define MSM_TRIG_A2WCNSS_SMD_INT
+#define MSM_TRIG_A2WCNSS_SMSM_INT
+#else /* use platform device / device tree configuration */
+#define MSM_TRIG_A2M_SMD_INT
+#define MSM_TRIG_A2Q6_SMD_INT
+#define MSM_TRIG_A2M_SMSM_INT
+#define MSM_TRIG_A2Q6_SMSM_INT
+#define MSM_TRIG_A2DSPS_SMD_INT
+#define MSM_TRIG_A2DSPS_SMSM_INT
+#define MSM_TRIG_A2WCNSS_SMD_INT
+#define MSM_TRIG_A2WCNSS_SMSM_INT
 #endif
+
+/*
+ * stub out legacy macros if they are not being used so that the legacy
+ * code compiles even though it is not used
+ *
+ * these definitions should not be used in active code and will cause
+ * an early failure
+ */
+#ifndef INT_A9_M2A_0
+#define INT_A9_M2A_0 -1
+#endif
+#ifndef INT_A9_M2A_5
+#define INT_A9_M2A_5 -1
+#endif
+#ifndef INT_ADSP_A11
+#define INT_ADSP_A11 -1
+#endif
+#ifndef INT_ADSP_A11_SMSM
+#define INT_ADSP_A11_SMSM -1
+#endif
+#ifndef INT_DSPS_A11
+#define INT_DSPS_A11 -1
+#endif
+#ifndef INT_DSPS_A11_SMSM
+#define INT_DSPS_A11_SMSM -1
+#endif
+#ifndef INT_WCNSS_A11
+#define INT_WCNSS_A11 -1
+#endif
+#ifndef INT_WCNSS_A11_SMSM
+#define INT_WCNSS_A11_SMSM -1
+#endif
+
+#define SMD_LOOPBACK_CID 100
+
+#define SMEM_SPINLOCK_SMEM_ALLOC       "S:3"
+static remote_spinlock_t remote_spinlock;
+
+static LIST_HEAD(smd_ch_list_loopback);
+static void smd_fake_irq_handler(unsigned long arg);
+static void smsm_cb_snapshot(uint32_t use_wakelock);
+
+static struct workqueue_struct *smsm_cb_wq;
+static void notify_smsm_cb_clients_worker(struct work_struct *work);
+static DECLARE_WORK(smsm_cb_work, notify_smsm_cb_clients_worker);
+static DEFINE_MUTEX(smsm_lock);
+static struct smsm_state_info *smsm_states;
+static int spinlocks_initialized;
+static RAW_NOTIFIER_HEAD(smsm_driver_state_notifier_list);
+static DEFINE_MUTEX(smsm_driver_state_notifier_lock);
+static void smsm_driver_state_notify(uint32_t state, void *data);
+
+static inline void smd_write_intr(unsigned int val,
+				const void __iomem *addr)
+{
+	wmb();
+	__raw_writel(val, addr);
 }
 
+#ifdef CONFIG_WCNSS
+static inline void wakeup_v1_riva(void)
+{
+	/*
+	 * workaround hack for RIVA v1 hardware bug
+	 * trigger GPIO 40 to wake up RIVA from power collaspe
+	 * not to be sent to customers
+	 */
+	if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1) {
+		__raw_writel(0x0, MSM_TLMM_BASE + 0x1284);
+		__raw_writel(0x2, MSM_TLMM_BASE + 0x1284);
+	}
+	/* end workaround */
+}
+#else
+static inline void wakeup_v1_riva(void) {}
+#endif
+
 static inline void notify_modem_smd(void)
 {
-	msm_a2m_int(0);
+	static const struct interrupt_config_item *intr
+	   = &private_intr_config[SMD_MODEM].smd;
+	if (intr->out_base) {
+		++interrupt_stats[SMD_MODEM].smd_out_config_count;
+		smd_write_intr(intr->out_bit_pos,
+		intr->out_base + intr->out_offset);
+	} else {
+		++interrupt_stats[SMD_MODEM].smd_out_hardcode_count;
+		MSM_TRIG_A2M_SMD_INT;
+	}
 }
 
 static inline void notify_dsp_smd(void)
 {
-	msm_a2m_int(8);
+	static const struct interrupt_config_item *intr
+		= &private_intr_config[SMD_Q6].smd;
+	if (intr->out_base) {
+		++interrupt_stats[SMD_Q6].smd_out_config_count;
+		smd_write_intr(intr->out_bit_pos,
+		intr->out_base + intr->out_offset);
+	} else {
+		++interrupt_stats[SMD_Q6].smd_out_hardcode_count;
+		MSM_TRIG_A2Q6_SMD_INT;
+	}
 }
 
-static void smd_diag(void)
+static inline void notify_dsps_smd(void)
+{
+	static const struct interrupt_config_item *intr
+		= &private_intr_config[SMD_DSPS].smd;
+	if (intr->out_base) {
+		++interrupt_stats[SMD_DSPS].smd_out_config_count;
+		smd_write_intr(intr->out_bit_pos,
+		intr->out_base + intr->out_offset);
+	} else {
+		++interrupt_stats[SMD_DSPS].smd_out_hardcode_count;
+		MSM_TRIG_A2DSPS_SMD_INT;
+	}
+}
+
+static inline void notify_wcnss_smd(void)
+{
+	static const struct interrupt_config_item *intr
+		= &private_intr_config[SMD_WCNSS].smd;
+	wakeup_v1_riva();
+
+	if (intr->out_base) {
+		++interrupt_stats[SMD_WCNSS].smd_out_config_count;
+		smd_write_intr(intr->out_bit_pos,
+		intr->out_base + intr->out_offset);
+	} else {
+		++interrupt_stats[SMD_WCNSS].smd_out_hardcode_count;
+		MSM_TRIG_A2WCNSS_SMD_INT;
+	}
+}
+
+static inline void notify_rpm_smd(void)
+{
+	static const struct interrupt_config_item *intr
+		= &private_intr_config[SMD_RPM].smd;
+
+	if (intr->out_base) {
+		++interrupt_stats[SMD_RPM].smd_out_config_count;
+		smd_write_intr(intr->out_bit_pos,
+		intr->out_base + intr->out_offset);
+	}
+}
+
+static inline void notify_modem_smsm(void)
+{
+	static const struct interrupt_config_item *intr
+		= &private_intr_config[SMD_MODEM].smsm;
+	if (intr->out_base) {
+		++interrupt_stats[SMD_MODEM].smsm_out_config_count;
+		smd_write_intr(intr->out_bit_pos,
+		intr->out_base + intr->out_offset);
+	} else {
+		++interrupt_stats[SMD_MODEM].smsm_out_hardcode_count;
+		MSM_TRIG_A2M_SMSM_INT;
+	}
+}
+
+static inline void notify_dsp_smsm(void)
+{
+	static const struct interrupt_config_item *intr
+		= &private_intr_config[SMD_Q6].smsm;
+	if (intr->out_base) {
+		++interrupt_stats[SMD_Q6].smsm_out_config_count;
+		smd_write_intr(intr->out_bit_pos,
+		intr->out_base + intr->out_offset);
+	} else {
+		++interrupt_stats[SMD_Q6].smsm_out_hardcode_count;
+		MSM_TRIG_A2Q6_SMSM_INT;
+	}
+}
+
+static inline void notify_dsps_smsm(void)
+{
+	static const struct interrupt_config_item *intr
+		= &private_intr_config[SMD_DSPS].smsm;
+	if (intr->out_base) {
+		++interrupt_stats[SMD_DSPS].smsm_out_config_count;
+		smd_write_intr(intr->out_bit_pos,
+		intr->out_base + intr->out_offset);
+	} else {
+		++interrupt_stats[SMD_DSPS].smsm_out_hardcode_count;
+		MSM_TRIG_A2DSPS_SMSM_INT;
+	}
+}
+
+static inline void notify_wcnss_smsm(void)
+{
+	static const struct interrupt_config_item *intr
+		= &private_intr_config[SMD_WCNSS].smsm;
+	wakeup_v1_riva();
+
+	if (intr->out_base) {
+		++interrupt_stats[SMD_WCNSS].smsm_out_config_count;
+		smd_write_intr(intr->out_bit_pos,
+		intr->out_base + intr->out_offset);
+	} else {
+		++interrupt_stats[SMD_WCNSS].smsm_out_hardcode_count;
+		MSM_TRIG_A2WCNSS_SMSM_INT;
+	}
+}
+
+static void notify_other_smsm(uint32_t smsm_entry, uint32_t notify_mask)
+{
+	/* older protocol don't use smsm_intr_mask,
+	   but still communicates with modem */
+	if (!smsm_info.intr_mask ||
+	    (__raw_readl(SMSM_INTR_MASK_ADDR(smsm_entry, SMSM_MODEM))
+				& notify_mask))
+		notify_modem_smsm();
+
+	if (smsm_info.intr_mask &&
+	    (__raw_readl(SMSM_INTR_MASK_ADDR(smsm_entry, SMSM_Q6))
+				& notify_mask)) {
+		uint32_t mux_val;
+
+		if (cpu_is_qsd8x50() && smsm_info.intr_mux) {
+			mux_val = __raw_readl(
+					SMSM_INTR_MUX_ADDR(SMEM_APPS_Q6_SMSM));
+			mux_val++;
+			__raw_writel(mux_val,
+					SMSM_INTR_MUX_ADDR(SMEM_APPS_Q6_SMSM));
+		}
+		notify_dsp_smsm();
+	}
+
+	if (smsm_info.intr_mask &&
+	    (__raw_readl(SMSM_INTR_MASK_ADDR(smsm_entry, SMSM_WCNSS))
+				& notify_mask)) {
+		notify_wcnss_smsm();
+	}
+
+	if (smsm_info.intr_mask &&
+	    (__raw_readl(SMSM_INTR_MASK_ADDR(smsm_entry, SMSM_DSPS))
+				& notify_mask)) {
+		notify_dsps_smsm();
+	}
+
+	/*
+	 * Notify local SMSM callback clients without wakelock since this
+	 * code is used by power management during power-down/-up sequencing
+	 * on DEM-based targets.  Grabbing a wakelock in this case will
+	 * abort the power-down sequencing.
+	 */
+	smsm_cb_snapshot(0);
+}
+
+void smd_diag(void)
 {
 	char *x;
+	int size;
 
 	x = smem_find(ID_DIAG_ERR_MSG, SZ_DIAG_ERR_MSG);
 	if (x != 0) {
 		x[SZ_DIAG_ERR_MSG - 1] = 0;
-		pr_debug("DIAG '%s'\n", x);
+		SMD_INFO("smem: DIAG '%s'\n", x);
+	}
+
+	x = smem_get_entry(SMEM_ERR_CRASH_LOG, &size);
+	if (x != 0) {
+		x[size - 1] = 0;
+		pr_err("smem: CRASH LOG\n'%s'\n", x);
 	}
 }
 
-/* call when SMSM_RESET flag is set in the A9's smsm_state */
+
 static void handle_modem_crash(void)
 {
-	pr_err("ARM9 has CRASHED\n");
+	pr_err("MODEM/AMSS has CRASHED\n");
 	smd_diag();
 
-	/* hard reboot if possible */
-	if (msm_hw_reset_hook)
-		msm_hw_reset_hook();
+	/* hard reboot if possible FIXME
+	if (msm_reset_hook)
+		msm_reset_hook();
+	*/
 
 	/* in this case the modem or watchdog should reboot us */
 	for (;;)
 		;
 }
 
-uint32_t raw_smsm_get_state(enum smsm_state_item item)
+int smsm_check_for_modem_crash(void)
 {
-	return readl(smd_info.state + item * 4);
-}
+	/* if the modem's not ready yet, we have to hope for the best */
+	if (!smsm_info.state)
+		return 0;
 
-static int check_for_modem_crash(void)
-{
-	if (raw_smsm_get_state(SMSM_STATE_MODEM) & SMSM_RESET) {
+	if (__raw_readl(SMSM_STATE_ADDR(SMSM_MODEM_STATE)) & SMSM_RESET) {
 		handle_modem_crash();
 		return -1;
 	}
 	return 0;
 }
+EXPORT_SYMBOL(smsm_check_for_modem_crash);
 
 /* the spinlock is used to synchronize between the
  * irq handler and code that mutates the channel
  * list or fiddles with channel state
  */
-DEFINE_SPINLOCK(smd_lock);
+static DEFINE_SPINLOCK(smd_lock);
 DEFINE_SPINLOCK(smem_lock);
 
 /* the mutex is used during open() and close()
@@ -139,24 +625,376 @@
 
 static int smd_initialized;
 
-LIST_HEAD(smd_ch_closed_list);
-LIST_HEAD(smd_ch_list_modem);
-LIST_HEAD(smd_ch_list_dsp);
+struct smd_shared_v1 {
+	struct smd_half_channel ch0;
+	unsigned char data0[SMD_BUF_SIZE];
+	struct smd_half_channel ch1;
+	unsigned char data1[SMD_BUF_SIZE];
+};
+
+struct smd_shared_v2 {
+	struct smd_half_channel ch0;
+	struct smd_half_channel ch1;
+};
+
+struct smd_shared_v2_word_access {
+	struct smd_half_channel_word_access ch0;
+	struct smd_half_channel_word_access ch1;
+};
+
+struct smd_channel {
+	volatile void *send; /* some variant of smd_half_channel */
+	volatile void *recv; /* some variant of smd_half_channel */
+	unsigned char *send_data;
+	unsigned char *recv_data;
+	unsigned fifo_size;
+	unsigned fifo_mask;
+	struct list_head ch_list;
+
+	unsigned current_packet;
+	unsigned n;
+	void *priv;
+	void (*notify)(void *priv, unsigned flags);
+
+	int (*read)(smd_channel_t *ch, void *data, int len, int user_buf);
+	int (*write)(smd_channel_t *ch, const void *data, int len,
+			int user_buf);
+	int (*read_avail)(smd_channel_t *ch);
+	int (*write_avail)(smd_channel_t *ch);
+	int (*read_from_cb)(smd_channel_t *ch, void *data, int len,
+			int user_buf);
+
+	void (*update_state)(smd_channel_t *ch);
+	unsigned last_state;
+	void (*notify_other_cpu)(void);
+
+	char name[20];
+	struct platform_device pdev;
+	unsigned type;
+
+	int pending_pkt_sz;
+
+	char is_pkt_ch;
+
+	/*
+	 * private internal functions to access *send and *recv.
+	 * never to be exported outside of smd
+	 */
+	struct smd_half_channel_access *half_ch;
+};
+
+struct edge_to_pid {
+	uint32_t	local_pid;
+	uint32_t	remote_pid;
+	char		subsys_name[SMD_MAX_CH_NAME_LEN];
+};
+
+/**
+ * Maps edge type to local and remote processor ID's.
+ */
+static struct edge_to_pid edge_to_pids[] = {
+	[SMD_APPS_MODEM] = {SMD_APPS, SMD_MODEM, "modem"},
+	[SMD_APPS_QDSP] = {SMD_APPS, SMD_Q6, "q6"},
+	[SMD_MODEM_QDSP] = {SMD_MODEM, SMD_Q6},
+	[SMD_APPS_DSPS] = {SMD_APPS, SMD_DSPS, "dsps"},
+	[SMD_MODEM_DSPS] = {SMD_MODEM, SMD_DSPS},
+	[SMD_QDSP_DSPS] = {SMD_Q6, SMD_DSPS},
+	[SMD_APPS_WCNSS] = {SMD_APPS, SMD_WCNSS, "wcnss"},
+	[SMD_MODEM_WCNSS] = {SMD_MODEM, SMD_WCNSS},
+	[SMD_QDSP_WCNSS] = {SMD_Q6, SMD_WCNSS},
+	[SMD_DSPS_WCNSS] = {SMD_DSPS, SMD_WCNSS},
+	[SMD_APPS_Q6FW] = {SMD_APPS, SMD_MODEM_Q6_FW},
+	[SMD_MODEM_Q6FW] = {SMD_MODEM, SMD_MODEM_Q6_FW},
+	[SMD_QDSP_Q6FW] = {SMD_Q6, SMD_MODEM_Q6_FW},
+	[SMD_DSPS_Q6FW] = {SMD_DSPS, SMD_MODEM_Q6_FW},
+	[SMD_WCNSS_Q6FW] = {SMD_WCNSS, SMD_MODEM_Q6_FW},
+	[SMD_APPS_RPM] = {SMD_APPS, SMD_RPM},
+	[SMD_MODEM_RPM] = {SMD_MODEM, SMD_RPM},
+	[SMD_QDSP_RPM] = {SMD_Q6, SMD_RPM},
+	[SMD_WCNSS_RPM] = {SMD_WCNSS, SMD_RPM},
+};
+
+struct restart_notifier_block {
+	unsigned processor;
+	char *name;
+	struct notifier_block nb;
+};
+
+static int disable_smsm_reset_handshake;
+static struct platform_device loopback_tty_pdev = {.name = "LOOPBACK_TTY"};
+
+static LIST_HEAD(smd_ch_closed_list);
+static LIST_HEAD(smd_ch_closing_list);
+static LIST_HEAD(smd_ch_to_close_list);
+static LIST_HEAD(smd_ch_list_modem);
+static LIST_HEAD(smd_ch_list_dsp);
+static LIST_HEAD(smd_ch_list_dsps);
+static LIST_HEAD(smd_ch_list_wcnss);
+static LIST_HEAD(smd_ch_list_rpm);
 
 static unsigned char smd_ch_allocated[64];
 static struct work_struct probe_work;
 
+static void finalize_channel_close_fn(struct work_struct *work);
+static DECLARE_WORK(finalize_channel_close_work, finalize_channel_close_fn);
+static struct workqueue_struct *channel_close_wq;
+
+static int smd_alloc_channel(struct smd_alloc_elm *alloc_elm);
+
+/* on smp systems, the probe might get called from multiple cores,
+   hence use a lock */
+static DEFINE_MUTEX(smd_probe_lock);
+
+static void smd_channel_probe_worker(struct work_struct *work)
+{
+	struct smd_alloc_elm *shared;
+	unsigned n;
+	uint32_t type;
+
+	shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64);
+
+	if (!shared) {
+		pr_err("%s: allocation table not initialized\n", __func__);
+		return;
+	}
+
+	mutex_lock(&smd_probe_lock);
+	for (n = 0; n < 64; n++) {
+		if (smd_ch_allocated[n])
+			continue;
+
+		/* channel should be allocated only if APPS
+		   processor is involved */
+		type = SMD_CHANNEL_TYPE(shared[n].type);
+		if (type >= ARRAY_SIZE(edge_to_pids) ||
+				edge_to_pids[type].local_pid != SMD_APPS)
+			continue;
+		if (!shared[n].ref_count)
+			continue;
+		if (!shared[n].name[0])
+			continue;
+
+		if (!smd_alloc_channel(&shared[n]))
+			smd_ch_allocated[n] = 1;
+		else
+			SMD_INFO("Probe skipping ch %d, not allocated\n", n);
+	}
+	mutex_unlock(&smd_probe_lock);
+}
+
+/**
+ * Lookup processor ID and determine if it belongs to the proved edge
+ * type.
+ *
+ * @shared2:   Pointer to v2 shared channel structure
+ * @type:      Edge type
+ * @pid:       Processor ID of processor on edge
+ * @local_ch:  Channel that belongs to processor @pid
+ * @remote_ch: Other side of edge contained @pid
+ *
+ * Returns 0 for not on edge, 1 for found on edge
+ */
+static int pid_is_on_edge(struct smd_shared_v2 *shared2,
+		uint32_t type, uint32_t pid,
+		struct smd_half_channel **local_ch,
+		struct smd_half_channel **remote_ch
+		)
+{
+	int ret = 0;
+	struct edge_to_pid *edge;
+
+	*local_ch = 0;
+	*remote_ch = 0;
+
+	if (!shared2 || (type >= ARRAY_SIZE(edge_to_pids)))
+		return 0;
+
+	edge = &edge_to_pids[type];
+	if (edge->local_pid != edge->remote_pid) {
+		if (pid == edge->local_pid) {
+			*local_ch = &shared2->ch0;
+			*remote_ch = &shared2->ch1;
+			ret = 1;
+		} else if (pid == edge->remote_pid) {
+			*local_ch = &shared2->ch1;
+			*remote_ch = &shared2->ch0;
+			ret = 1;
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * Returns a pointer to the subsystem name or NULL if no
+ * subsystem name is available.
+ *
+ * @type - Edge definition
+ */
+const char *smd_edge_to_subsystem(uint32_t type)
+{
+	const char *subsys = NULL;
+
+	if (type < ARRAY_SIZE(edge_to_pids)) {
+		subsys = edge_to_pids[type].subsys_name;
+		if (subsys[0] == 0x0)
+			subsys = NULL;
+	}
+	return subsys;
+}
+EXPORT_SYMBOL(smd_edge_to_subsystem);
+
+/*
+ * Returns a pointer to the subsystem name given the
+ * remote processor ID.
+ *
+ * @pid     Remote processor ID
+ * @returns Pointer to subsystem name or NULL if not found
+ */
+const char *smd_pid_to_subsystem(uint32_t pid)
+{
+	const char *subsys = NULL;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(edge_to_pids); ++i) {
+		if (pid == edge_to_pids[i].remote_pid &&
+			edge_to_pids[i].subsys_name[0] != 0x0
+			) {
+			subsys = edge_to_pids[i].subsys_name;
+			break;
+		}
+	}
+
+	return subsys;
+}
+EXPORT_SYMBOL(smd_pid_to_subsystem);
+
+static void smd_reset_edge(struct smd_half_channel *ch, unsigned new_state)
+{
+	if (ch->state != SMD_SS_CLOSED) {
+		ch->state = new_state;
+		ch->fDSR = 0;
+		ch->fCTS = 0;
+		ch->fCD = 0;
+		ch->fSTATE = 1;
+	}
+}
+
+static void smd_channel_reset_state(struct smd_alloc_elm *shared,
+		unsigned new_state, unsigned pid)
+{
+	unsigned n;
+	struct smd_shared_v2 *shared2;
+	uint32_t type;
+	struct smd_half_channel *local_ch;
+	struct smd_half_channel *remote_ch;
+
+	for (n = 0; n < SMD_CHANNELS; n++) {
+		if (!shared[n].ref_count)
+			continue;
+		if (!shared[n].name[0])
+			continue;
+
+		type = SMD_CHANNEL_TYPE(shared[n].type);
+		shared2 = smem_alloc(SMEM_SMD_BASE_ID + n, sizeof(*shared2));
+		if (!shared2)
+			continue;
+
+		if (pid_is_on_edge(shared2, type, pid, &local_ch, &remote_ch))
+			smd_reset_edge(local_ch, new_state);
+
+		/*
+		 * ModemFW is in the same subsystem as ModemSW, but has
+		 * separate SMD edges that need to be reset.
+		 */
+		if (pid == SMSM_MODEM &&
+				pid_is_on_edge(shared2, type, SMD_MODEM_Q6_FW,
+				 &local_ch, &remote_ch))
+			smd_reset_edge(local_ch, new_state);
+	}
+}
+
+
+void smd_channel_reset(uint32_t restart_pid)
+{
+	struct smd_alloc_elm *shared;
+	unsigned long flags;
+
+	SMD_DBG("%s: starting reset\n", __func__);
+	shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64);
+	if (!shared) {
+		pr_err("%s: allocation table not initialized\n", __func__);
+		return;
+	}
+
+	/* release any held spinlocks */
+	remote_spin_release(&remote_spinlock, restart_pid);
+	remote_spin_release_all(restart_pid);
+
+	/* reset SMSM entry */
+	if (smsm_info.state) {
+		writel_relaxed(0, SMSM_STATE_ADDR(restart_pid));
+
+		/* restart SMSM init handshake */
+		if (restart_pid == SMSM_MODEM) {
+			smsm_change_state(SMSM_APPS_STATE,
+				SMSM_INIT | SMSM_SMD_LOOPBACK | SMSM_RESET,
+				0);
+		}
+
+		/* notify SMSM processors */
+		smsm_irq_handler(0, 0);
+		notify_modem_smsm();
+		notify_dsp_smsm();
+		notify_dsps_smsm();
+		notify_wcnss_smsm();
+	}
+
+	/* change all remote states to CLOSING */
+	mutex_lock(&smd_probe_lock);
+	spin_lock_irqsave(&smd_lock, flags);
+	smd_channel_reset_state(shared, SMD_SS_CLOSING, restart_pid);
+	spin_unlock_irqrestore(&smd_lock, flags);
+	mutex_unlock(&smd_probe_lock);
+
+	/* notify SMD processors */
+	mb();
+	smd_fake_irq_handler(0);
+	notify_modem_smd();
+	notify_dsp_smd();
+	notify_dsps_smd();
+	notify_wcnss_smd();
+
+	/* change all remote states to CLOSED */
+	mutex_lock(&smd_probe_lock);
+	spin_lock_irqsave(&smd_lock, flags);
+	smd_channel_reset_state(shared, SMD_SS_CLOSED, restart_pid);
+	spin_unlock_irqrestore(&smd_lock, flags);
+	mutex_unlock(&smd_probe_lock);
+
+	/* notify SMD processors */
+	mb();
+	smd_fake_irq_handler(0);
+	notify_modem_smd();
+	notify_dsp_smd();
+	notify_dsps_smd();
+	notify_wcnss_smd();
+
+	SMD_DBG("%s: finished reset\n", __func__);
+}
+
 /* how many bytes are available for reading */
 static int smd_stream_read_avail(struct smd_channel *ch)
 {
-	return (ch->recv->head - ch->recv->tail) & ch->fifo_mask;
+	return (ch->half_ch->get_head(ch->recv) -
+			ch->half_ch->get_tail(ch->recv)) & ch->fifo_mask;
 }
 
 /* how many bytes we are free to write */
 static int smd_stream_write_avail(struct smd_channel *ch)
 {
-	return ch->fifo_mask -
-		((ch->send->head - ch->send->tail) & ch->fifo_mask);
+	return ch->fifo_mask - ((ch->half_ch->get_head(ch->send) -
+			ch->half_ch->get_tail(ch->send)) & ch->fifo_mask);
 }
 
 static int smd_packet_read_avail(struct smd_channel *ch)
@@ -179,15 +1017,16 @@
 
 static int ch_is_open(struct smd_channel *ch)
 {
-	return (ch->recv->state == SMD_SS_OPENED) &&
-		(ch->send->state == SMD_SS_OPENED);
+	return (ch->half_ch->get_state(ch->recv) == SMD_SS_OPENED ||
+		ch->half_ch->get_state(ch->recv) == SMD_SS_FLUSHING)
+		&& (ch->half_ch->get_state(ch->send) == SMD_SS_OPENED);
 }
 
 /* provide a pointer and length to readable data in the fifo */
 static unsigned ch_read_buffer(struct smd_channel *ch, void **ptr)
 {
-	unsigned head = ch->recv->head;
-	unsigned tail = ch->recv->tail;
+	unsigned head = ch->half_ch->get_head(ch->recv);
+	unsigned tail = ch->half_ch->get_tail(ch->recv);
 	*ptr = (void *) (ch->recv_data + tail);
 
 	if (tail <= head)
@@ -196,24 +1035,32 @@
 		return ch->fifo_size - tail;
 }
 
+static int read_intr_blocked(struct smd_channel *ch)
+{
+	return ch->half_ch->get_fBLOCKREADINTR(ch->recv);
+}
+
 /* advance the fifo read pointer after data from ch_read_buffer is consumed */
 static void ch_read_done(struct smd_channel *ch, unsigned count)
 {
 	BUG_ON(count > smd_stream_read_avail(ch));
-	ch->recv->tail = (ch->recv->tail + count) & ch->fifo_mask;
-	ch->send->fTAIL = 1;
+	ch->half_ch->set_tail(ch->recv,
+		(ch->half_ch->get_tail(ch->recv) + count) & ch->fifo_mask);
+	wmb();
+	ch->half_ch->set_fTAIL(ch->send,  1);
 }
 
 /* basic read interface to ch_read_{buffer,done} used
  * by smd_*_read() and update_packet_state()
  * will read-and-discard if the _data pointer is null
  */
-static int ch_read(struct smd_channel *ch, void *_data, int len)
+static int ch_read(struct smd_channel *ch, void *_data, int len, int user_buf)
 {
 	void *ptr;
 	unsigned n;
 	unsigned char *data = _data;
 	int orig_len = len;
+	int r = 0;
 
 	while (len > 0) {
 		n = ch_read_buffer(ch, &ptr);
@@ -222,8 +1069,19 @@
 
 		if (n > len)
 			n = len;
-		if (_data)
-			memcpy(data, ptr, n);
+		if (_data) {
+			if (user_buf) {
+				r = copy_to_user(data, ptr, n);
+				if (r > 0) {
+					pr_err("%s: "
+						"copy_to_user could not copy "
+						"%i bytes.\n",
+						__func__,
+						r);
+				}
+			} else
+				memcpy(data, ptr, n);
+		}
 
 		data += n;
 		len -= n;
@@ -244,24 +1102,25 @@
 	int r;
 
 	/* can't do anything if we're in the middle of a packet */
-	if (ch->current_packet != 0)
-		return;
+	while (ch->current_packet == 0) {
+		/* discard 0 length packets if any */
 
-	/* don't bother unless we can get the full header */
-	if (smd_stream_read_avail(ch) < SMD_HEADER_SIZE)
-		return;
+		/* don't bother unless we can get the full header */
+		if (smd_stream_read_avail(ch) < SMD_HEADER_SIZE)
+			return;
 
-	r = ch_read(ch, hdr, SMD_HEADER_SIZE);
-	BUG_ON(r != SMD_HEADER_SIZE);
+		r = ch_read(ch, hdr, SMD_HEADER_SIZE, 0);
+		BUG_ON(r != SMD_HEADER_SIZE);
 
-	ch->current_packet = hdr[0];
+		ch->current_packet = hdr[0];
+	}
 }
 
 /* provide a pointer and length to next free space in the fifo */
 static unsigned ch_write_buffer(struct smd_channel *ch, void **ptr)
 {
-	unsigned head = ch->send->head;
-	unsigned tail = ch->send->tail;
+	unsigned head = ch->half_ch->get_head(ch->send);
+	unsigned tail = ch->half_ch->get_tail(ch->send);
 	*ptr = (void *) (ch->send_data + head);
 
 	if (head < tail) {
@@ -280,23 +1139,25 @@
 static void ch_write_done(struct smd_channel *ch, unsigned count)
 {
 	BUG_ON(count > smd_stream_write_avail(ch));
-	ch->send->head = (ch->send->head + count) & ch->fifo_mask;
-	ch->send->fHEAD = 1;
+	ch->half_ch->set_head(ch->send,
+		(ch->half_ch->get_head(ch->send) + count) & ch->fifo_mask);
+	wmb();
+	ch->half_ch->set_fHEAD(ch->send, 1);
 }
 
 static void ch_set_state(struct smd_channel *ch, unsigned n)
 {
 	if (n == SMD_SS_OPENED) {
-		ch->send->fDSR = 1;
-		ch->send->fCTS = 1;
-		ch->send->fCD = 1;
+		ch->half_ch->set_fDSR(ch->send, 1);
+		ch->half_ch->set_fCTS(ch->send, 1);
+		ch->half_ch->set_fCD(ch->send, 1);
 	} else {
-		ch->send->fDSR = 0;
-		ch->send->fCTS = 0;
-		ch->send->fCD = 0;
+		ch->half_ch->set_fDSR(ch->send, 0);
+		ch->half_ch->set_fCTS(ch->send, 0);
+		ch->half_ch->set_fCD(ch->send, 0);
 	}
-	ch->send->state = n;
-	ch->send->fSTATE = 1;
+	ch->half_ch->set_state(ch->send, n);
+	ch->half_ch->set_fSTATE(ch->send, 1);
 	ch->notify_other_cpu();
 }
 
@@ -314,84 +1175,169 @@
 {
 	ch->last_state = next;
 
-	pr_debug("ch %d %d -> %d\n", ch->n, last, next);
+	SMD_INFO("SMD: ch %d %d -> %d\n", ch->n, last, next);
 
 	switch (next) {
 	case SMD_SS_OPENING:
-		ch->recv->tail = 0;
+		if (ch->half_ch->get_state(ch->send) == SMD_SS_CLOSING ||
+		    ch->half_ch->get_state(ch->send) == SMD_SS_CLOSED) {
+			ch->half_ch->set_tail(ch->recv, 0);
+			ch->half_ch->set_head(ch->send, 0);
+			ch->half_ch->set_fBLOCKREADINTR(ch->send, 0);
+			ch_set_state(ch, SMD_SS_OPENING);
+		}
+		break;
 	case SMD_SS_OPENED:
-		if (ch->send->state != SMD_SS_OPENED)
+		if (ch->half_ch->get_state(ch->send) == SMD_SS_OPENING) {
 			ch_set_state(ch, SMD_SS_OPENED);
-		ch->notify(ch->priv, SMD_EVENT_OPEN);
+			ch->notify(ch->priv, SMD_EVENT_OPEN);
+		}
 		break;
 	case SMD_SS_FLUSHING:
 	case SMD_SS_RESET:
 		/* we should force them to close? */
-	default:
-		ch->notify(ch->priv, SMD_EVENT_CLOSE);
+		break;
+	case SMD_SS_CLOSED:
+		if (ch->half_ch->get_state(ch->send) == SMD_SS_OPENED) {
+			ch_set_state(ch, SMD_SS_CLOSING);
+			ch->current_packet = 0;
+			ch->pending_pkt_sz = 0;
+			ch->notify(ch->priv, SMD_EVENT_CLOSE);
+		}
+		break;
+	case SMD_SS_CLOSING:
+		if (ch->half_ch->get_state(ch->send) == SMD_SS_CLOSED) {
+			list_move(&ch->ch_list,
+					&smd_ch_to_close_list);
+			queue_work(channel_close_wq,
+						&finalize_channel_close_work);
+		}
+		break;
 	}
 }
 
+static void handle_smd_irq_closing_list(void)
+{
+	unsigned long flags;
+	struct smd_channel *ch;
+	struct smd_channel *index;
+	unsigned tmp;
+
+	spin_lock_irqsave(&smd_lock, flags);
+	list_for_each_entry_safe(ch, index, &smd_ch_closing_list, ch_list) {
+		if (ch->half_ch->get_fSTATE(ch->recv))
+			ch->half_ch->set_fSTATE(ch->recv, 0);
+		tmp = ch->half_ch->get_state(ch->recv);
+		if (tmp != ch->last_state)
+			smd_state_change(ch, ch->last_state, tmp);
+	}
+	spin_unlock_irqrestore(&smd_lock, flags);
+}
+
 static void handle_smd_irq(struct list_head *list, void (*notify)(void))
 {
 	unsigned long flags;
 	struct smd_channel *ch;
-	int do_notify = 0;
 	unsigned ch_flags;
 	unsigned tmp;
+	unsigned char state_change;
 
 	spin_lock_irqsave(&smd_lock, flags);
 	list_for_each_entry(ch, list, ch_list) {
+		state_change = 0;
 		ch_flags = 0;
 		if (ch_is_open(ch)) {
-			if (ch->recv->fHEAD) {
-				ch->recv->fHEAD = 0;
+			if (ch->half_ch->get_fHEAD(ch->recv)) {
+				ch->half_ch->set_fHEAD(ch->recv, 0);
 				ch_flags |= 1;
-				do_notify |= 1;
 			}
-			if (ch->recv->fTAIL) {
-				ch->recv->fTAIL = 0;
+			if (ch->half_ch->get_fTAIL(ch->recv)) {
+				ch->half_ch->set_fTAIL(ch->recv, 0);
 				ch_flags |= 2;
-				do_notify |= 1;
 			}
-			if (ch->recv->fSTATE) {
-				ch->recv->fSTATE = 0;
+			if (ch->half_ch->get_fSTATE(ch->recv)) {
+				ch->half_ch->set_fSTATE(ch->recv, 0);
 				ch_flags |= 4;
-				do_notify |= 1;
 			}
 		}
-		tmp = ch->recv->state;
-		if (tmp != ch->last_state)
+		tmp = ch->half_ch->get_state(ch->recv);
+		if (tmp != ch->last_state) {
+			SMx_POWER_INFO("SMD ch%d '%s' State change %d->%d\n",
+					ch->n, ch->name, ch->last_state, tmp);
 			smd_state_change(ch, ch->last_state, tmp);
-		if (ch_flags) {
+			state_change = 1;
+		}
+		if (ch_flags & 0x3) {
 			ch->update_state(ch);
+			SMx_POWER_INFO("SMD ch%d '%s' Data event r%d/w%d\n",
+					ch->n, ch->name,
+					ch->read_avail(ch),
+					ch->fifo_size - ch->write_avail(ch));
 			ch->notify(ch->priv, SMD_EVENT_DATA);
 		}
+		if (ch_flags & 0x4 && !state_change) {
+			SMx_POWER_INFO("SMD ch%d '%s' State update\n",
+					ch->n, ch->name);
+			ch->notify(ch->priv, SMD_EVENT_STATUS);
+		}
 	}
-	if (do_notify)
-		notify();
 	spin_unlock_irqrestore(&smd_lock, flags);
 	do_smd_probe();
 }
 
 static irqreturn_t smd_modem_irq_handler(int irq, void *data)
 {
+	SMx_POWER_INFO("SMD Int Modem->Apps\n");
+	++interrupt_stats[SMD_MODEM].smd_in_count;
 	handle_smd_irq(&smd_ch_list_modem, notify_modem_smd);
+	handle_smd_irq_closing_list();
 	return IRQ_HANDLED;
 }
 
-#if defined(CONFIG_QDSP6)
 static irqreturn_t smd_dsp_irq_handler(int irq, void *data)
 {
+	SMx_POWER_INFO("SMD Int LPASS->Apps\n");
+	++interrupt_stats[SMD_Q6].smd_in_count;
 	handle_smd_irq(&smd_ch_list_dsp, notify_dsp_smd);
+	handle_smd_irq_closing_list();
 	return IRQ_HANDLED;
 }
-#endif
+
+static irqreturn_t smd_dsps_irq_handler(int irq, void *data)
+{
+	SMx_POWER_INFO("SMD Int DSPS->Apps\n");
+	++interrupt_stats[SMD_DSPS].smd_in_count;
+	handle_smd_irq(&smd_ch_list_dsps, notify_dsps_smd);
+	handle_smd_irq_closing_list();
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t smd_wcnss_irq_handler(int irq, void *data)
+{
+	SMx_POWER_INFO("SMD Int WCNSS->Apps\n");
+	++interrupt_stats[SMD_WCNSS].smd_in_count;
+	handle_smd_irq(&smd_ch_list_wcnss, notify_wcnss_smd);
+	handle_smd_irq_closing_list();
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t smd_rpm_irq_handler(int irq, void *data)
+{
+	SMx_POWER_INFO("SMD Int RPM->Apps\n");
+	++interrupt_stats[SMD_RPM].smd_in_count;
+	handle_smd_irq(&smd_ch_list_rpm, notify_rpm_smd);
+	handle_smd_irq_closing_list();
+	return IRQ_HANDLED;
+}
 
 static void smd_fake_irq_handler(unsigned long arg)
 {
 	handle_smd_irq(&smd_ch_list_modem, notify_modem_smd);
 	handle_smd_irq(&smd_ch_list_dsp, notify_dsp_smd);
+	handle_smd_irq(&smd_ch_list_dsps, notify_dsps_smd);
+	handle_smd_irq(&smd_ch_list_wcnss, notify_wcnss_smd);
+	handle_smd_irq(&smd_ch_list_rpm, notify_rpm_smd);
+	handle_smd_irq_closing_list();
 }
 
 static DECLARE_TASKLET(smd_fake_irq_tasklet, smd_fake_irq_handler, 0);
@@ -399,9 +1345,11 @@
 static inline int smd_need_int(struct smd_channel *ch)
 {
 	if (ch_is_open(ch)) {
-		if (ch->recv->fHEAD || ch->recv->fTAIL || ch->recv->fSTATE)
+		if (ch->half_ch->get_fHEAD(ch->recv) ||
+				ch->half_ch->get_fTAIL(ch->recv) ||
+				ch->half_ch->get_fSTATE(ch->recv))
 			return 1;
-		if (ch->recv->state != ch->last_state)
+		if (ch->half_ch->get_state(ch->recv) != ch->last_state)
 			return 1;
 	}
 	return 0;
@@ -426,68 +1374,82 @@
 			break;
 		}
 	}
+	list_for_each_entry(ch, &smd_ch_list_dsps, ch_list) {
+		if (smd_need_int(ch)) {
+			need_int = 1;
+			break;
+		}
+	}
+	list_for_each_entry(ch, &smd_ch_list_wcnss, ch_list) {
+		if (smd_need_int(ch)) {
+			need_int = 1;
+			break;
+		}
+	}
 	spin_unlock_irqrestore(&smd_lock, flags);
 	do_smd_probe();
 
 	if (need_int) {
-		if (msm_smd_debug_mask & MSM_SMD_DEBUG)
-			pr_info("smd_sleep_exit need interrupt\n");
+		SMD_DBG("smd_sleep_exit need interrupt\n");
 		tasklet_schedule(&smd_fake_irq_tasklet);
 	}
 }
+EXPORT_SYMBOL(smd_sleep_exit);
 
-
-void smd_kick(smd_channel_t *ch)
+static int smd_is_packet(struct smd_alloc_elm *alloc_elm)
 {
-	unsigned long flags;
-	unsigned tmp;
-
-	spin_lock_irqsave(&smd_lock, flags);
-	ch->update_state(ch);
-	tmp = ch->recv->state;
-	if (tmp != ch->last_state) {
-		ch->last_state = tmp;
-		if (tmp == SMD_SS_OPENED)
-			ch->notify(ch->priv, SMD_EVENT_OPEN);
-		else
-			ch->notify(ch->priv, SMD_EVENT_CLOSE);
-	}
-	ch->notify(ch->priv, SMD_EVENT_DATA);
-	ch->notify_other_cpu();
-	spin_unlock_irqrestore(&smd_lock, flags);
-}
-
-static int smd_is_packet(int chn, unsigned type)
-{
-	type &= SMD_KIND_MASK;
-	if (type == SMD_KIND_PACKET)
+	if (SMD_XFER_TYPE(alloc_elm->type) == 1)
+		return 0;
+	else if (SMD_XFER_TYPE(alloc_elm->type) == 2)
 		return 1;
-	if (type == SMD_KIND_STREAM)
+
+	/* for cases where xfer type is 0 */
+	if (!strncmp(alloc_elm->name, "DAL", 3))
 		return 0;
 
-	/* older AMSS reports SMD_KIND_UNKNOWN always */
-	if ((chn > 4) || (chn == 1))
+	/* for cases where xfer type is 0 */
+	if (!strncmp(alloc_elm->name, "RPCCALL_QDSP", 12))
+		return 0;
+
+	if (alloc_elm->cid > 4 || alloc_elm->cid == 1)
 		return 1;
 	else
 		return 0;
 }
 
-static int smd_stream_write(smd_channel_t *ch, const void *_data, int len)
+static int smd_stream_write(smd_channel_t *ch, const void *_data, int len,
+				int user_buf)
 {
 	void *ptr;
 	const unsigned char *buf = _data;
 	unsigned xfer;
 	int orig_len = len;
+	int r = 0;
 
+	SMD_DBG("smd_stream_write() %d -> ch%d\n", len, ch->n);
 	if (len < 0)
 		return -EINVAL;
+	else if (len == 0)
+		return 0;
 
 	while ((xfer = ch_write_buffer(ch, &ptr)) != 0) {
-		if (!ch_is_open(ch))
+		if (!ch_is_open(ch)) {
+			len = orig_len;
 			break;
+		}
 		if (xfer > len)
 			xfer = len;
-		memcpy(ptr, buf, xfer);
+		if (user_buf) {
+			r = copy_from_user(ptr, buf, xfer);
+			if (r > 0) {
+				pr_err("%s: "
+					"copy_from_user could not copy %i "
+					"bytes.\n",
+					__func__,
+					r);
+			}
+		} else
+			memcpy(ptr, buf, xfer);
 		ch_write_done(ch, xfer);
 		len -= xfer;
 		buf += xfer;
@@ -495,17 +1457,23 @@
 			break;
 	}
 
-	ch->notify_other_cpu();
+	if (orig_len - len)
+		ch->notify_other_cpu();
 
 	return orig_len - len;
 }
 
-static int smd_packet_write(smd_channel_t *ch, const void *_data, int len)
+static int smd_packet_write(smd_channel_t *ch, const void *_data, int len,
+				int user_buf)
 {
+	int ret;
 	unsigned hdr[5];
 
+	SMD_DBG("smd_packet_write() %d -> ch%d\n", len, ch->n);
 	if (len < 0)
 		return -EINVAL;
+	else if (len == 0)
+		return 0;
 
 	if (smd_stream_write_avail(ch) < (len + SMD_HEADER_SIZE))
 		return -ENOMEM;
@@ -513,27 +1481,41 @@
 	hdr[0] = len;
 	hdr[1] = hdr[2] = hdr[3] = hdr[4] = 0;
 
-	smd_stream_write(ch, hdr, sizeof(hdr));
-	smd_stream_write(ch, _data, len);
+
+	ret = smd_stream_write(ch, hdr, sizeof(hdr), 0);
+	if (ret < 0 || ret != sizeof(hdr)) {
+		SMD_DBG("%s failed to write pkt header: "
+			"%d returned\n", __func__, ret);
+		return -1;
+	}
+
+
+	ret = smd_stream_write(ch, _data, len, user_buf);
+	if (ret < 0 || ret != len) {
+		SMD_DBG("%s failed to write pkt data: "
+			"%d returned\n", __func__, ret);
+		return ret;
+	}
 
 	return len;
 }
 
-static int smd_stream_read(smd_channel_t *ch, void *data, int len)
+static int smd_stream_read(smd_channel_t *ch, void *data, int len, int user_buf)
 {
 	int r;
 
 	if (len < 0)
 		return -EINVAL;
 
-	r = ch_read(ch, data, len);
+	r = ch_read(ch, data, len, user_buf);
 	if (r > 0)
-		ch->notify_other_cpu();
+		if (!read_intr_blocked(ch))
+			ch->notify_other_cpu();
 
 	return r;
 }
 
-static int smd_packet_read(smd_channel_t *ch, void *data, int len)
+static int smd_packet_read(smd_channel_t *ch, void *data, int len, int user_buf)
 {
 	unsigned long flags;
 	int r;
@@ -544,9 +1526,10 @@
 	if (len > ch->current_packet)
 		len = ch->current_packet;
 
-	r = ch_read(ch, data, len);
+	r = ch_read(ch, data, len, user_buf);
 	if (r > 0)
-		ch->notify_other_cpu();
+		if (!read_intr_blocked(ch))
+			ch->notify_other_cpu();
 
 	spin_lock_irqsave(&smd_lock, flags);
 	ch->current_packet -= r;
@@ -556,7 +1539,107 @@
 	return r;
 }
 
-static int smd_alloc_channel(const char *name, uint32_t cid, uint32_t type)
+static int smd_packet_read_from_cb(smd_channel_t *ch, void *data, int len,
+					int user_buf)
+{
+	int r;
+
+	if (len < 0)
+		return -EINVAL;
+
+	if (len > ch->current_packet)
+		len = ch->current_packet;
+
+	r = ch_read(ch, data, len, user_buf);
+	if (r > 0)
+		if (!read_intr_blocked(ch))
+			ch->notify_other_cpu();
+
+	ch->current_packet -= r;
+	update_packet_state(ch);
+
+	return r;
+}
+
+#if (defined(CONFIG_MSM_SMD_PKG4) || defined(CONFIG_MSM_SMD_PKG3))
+static int smd_alloc_v2(struct smd_channel *ch)
+{
+	void *buffer;
+	unsigned buffer_sz;
+
+	if (is_word_access_ch(ch->type)) {
+		struct smd_shared_v2_word_access *shared2;
+		shared2 = smem_alloc(SMEM_SMD_BASE_ID + ch->n,
+						sizeof(*shared2));
+		if (!shared2) {
+			SMD_INFO("smem_alloc failed ch=%d\n", ch->n);
+			return -EINVAL;
+		}
+		ch->send = &shared2->ch0;
+		ch->recv = &shared2->ch1;
+	} else {
+		struct smd_shared_v2 *shared2;
+		shared2 = smem_alloc(SMEM_SMD_BASE_ID + ch->n,
+							sizeof(*shared2));
+		if (!shared2) {
+			SMD_INFO("smem_alloc failed ch=%d\n", ch->n);
+			return -EINVAL;
+		}
+		ch->send = &shared2->ch0;
+		ch->recv = &shared2->ch1;
+	}
+	ch->half_ch = get_half_ch_funcs(ch->type);
+
+	buffer = smem_get_entry(SMEM_SMD_FIFO_BASE_ID + ch->n, &buffer_sz);
+	if (!buffer) {
+		SMD_INFO("smem_get_entry failed\n");
+		return -EINVAL;
+	}
+
+	/* buffer must be a power-of-two size */
+	if (buffer_sz & (buffer_sz - 1)) {
+		SMD_INFO("Buffer size: %u not power of two\n", buffer_sz);
+		return -EINVAL;
+	}
+	buffer_sz /= 2;
+	ch->send_data = buffer;
+	ch->recv_data = buffer + buffer_sz;
+	ch->fifo_size = buffer_sz;
+
+	return 0;
+}
+
+static int smd_alloc_v1(struct smd_channel *ch)
+{
+	return -EINVAL;
+}
+
+#else /* define v1 for older targets */
+static int smd_alloc_v2(struct smd_channel *ch)
+{
+	return -EINVAL;
+}
+
+static int smd_alloc_v1(struct smd_channel *ch)
+{
+	struct smd_shared_v1 *shared1;
+	shared1 = smem_alloc(ID_SMD_CHANNELS + ch->n, sizeof(*shared1));
+	if (!shared1) {
+		pr_err("smd_alloc_channel() cid %d does not exist\n", ch->n);
+		return -EINVAL;
+	}
+	ch->send = &shared1->ch0;
+	ch->recv = &shared1->ch1;
+	ch->send_data = shared1->data0;
+	ch->recv_data = shared1->data1;
+	ch->fifo_size = SMD_BUF_SIZE;
+	ch->half_ch = get_half_ch_funcs(ch->type);
+	return 0;
+}
+
+#endif
+
+static int smd_alloc_channel(struct smd_alloc_elm *alloc_elm)
 {
 	struct smd_channel *ch;
 
@@ -565,46 +1648,118 @@
 		pr_err("smd_alloc_channel() out of memory\n");
 		return -1;
 	}
-	ch->n = cid;
+	ch->n = alloc_elm->cid;
+	ch->type = SMD_CHANNEL_TYPE(alloc_elm->type);
 
-	if (_smd_alloc_channel(ch)) {
+	if (smd_alloc_v2(ch) && smd_alloc_v1(ch)) {
 		kfree(ch);
 		return -1;
 	}
 
 	ch->fifo_mask = ch->fifo_size - 1;
-	ch->type = type;
 
-	if ((type & SMD_TYPE_MASK) == SMD_TYPE_APPS_MODEM)
+	/* probe_worker guarentees ch->type will be a valid type */
+	if (ch->type == SMD_APPS_MODEM)
 		ch->notify_other_cpu = notify_modem_smd;
-	else
+	else if (ch->type == SMD_APPS_QDSP)
 		ch->notify_other_cpu = notify_dsp_smd;
+	else if (ch->type == SMD_APPS_DSPS)
+		ch->notify_other_cpu = notify_dsps_smd;
+	else if (ch->type == SMD_APPS_WCNSS)
+		ch->notify_other_cpu = notify_wcnss_smd;
+	else if (ch->type == SMD_APPS_RPM)
+		ch->notify_other_cpu = notify_rpm_smd;
 
-	if (smd_is_packet(cid, type)) {
+	if (smd_is_packet(alloc_elm)) {
 		ch->read = smd_packet_read;
 		ch->write = smd_packet_write;
 		ch->read_avail = smd_packet_read_avail;
 		ch->write_avail = smd_packet_write_avail;
 		ch->update_state = update_packet_state;
+		ch->read_from_cb = smd_packet_read_from_cb;
+		ch->is_pkt_ch = 1;
 	} else {
 		ch->read = smd_stream_read;
 		ch->write = smd_stream_write;
 		ch->read_avail = smd_stream_read_avail;
 		ch->write_avail = smd_stream_write_avail;
 		ch->update_state = update_stream_state;
+		ch->read_from_cb = smd_stream_read;
 	}
 
-	if ((type & 0xff) == 0)
-		memcpy(ch->name, "SMD_", 4);
-	else
-		memcpy(ch->name, "DSP_", 4);
-	memcpy(ch->name + 4, name, 20);
-	ch->name[23] = 0;
-	ch->pdev.name = ch->name;
-	ch->pdev.id = -1;
+	memcpy(ch->name, alloc_elm->name, SMD_MAX_CH_NAME_LEN);
+	ch->name[SMD_MAX_CH_NAME_LEN-1] = 0;
 
-	pr_debug("smd_alloc_channel() cid=%02d size=%05d '%s'\n",
-		ch->n, ch->fifo_size, ch->name);
+	ch->pdev.name = ch->name;
+	ch->pdev.id = ch->type;
+
+	SMD_INFO("smd_alloc_channel() '%s' cid=%d\n",
+		 ch->name, ch->n);
+
+	mutex_lock(&smd_creation_mutex);
+	list_add(&ch->ch_list, &smd_ch_closed_list);
+	mutex_unlock(&smd_creation_mutex);
+
+	platform_device_register(&ch->pdev);
+	if (!strncmp(ch->name, "LOOPBACK", 8) && ch->type == SMD_APPS_MODEM) {
+		/* create a platform driver to be used by smd_tty driver
+		 * so that it can access the loopback port
+		 */
+		loopback_tty_pdev.id = ch->type;
+		platform_device_register(&loopback_tty_pdev);
+	}
+	return 0;
+}
+
+static inline void notify_loopback_smd(void)
+{
+	unsigned long flags;
+	struct smd_channel *ch;
+
+	spin_lock_irqsave(&smd_lock, flags);
+	list_for_each_entry(ch, &smd_ch_list_loopback, ch_list) {
+		ch->notify(ch->priv, SMD_EVENT_DATA);
+	}
+	spin_unlock_irqrestore(&smd_lock, flags);
+}
+
+static int smd_alloc_loopback_channel(void)
+{
+	static struct smd_half_channel smd_loopback_ctl;
+	static char smd_loopback_data[SMD_BUF_SIZE];
+	struct smd_channel *ch;
+
+	ch = kzalloc(sizeof(struct smd_channel), GFP_KERNEL);
+	if (ch == 0) {
+		pr_err("%s: out of memory\n", __func__);
+		return -1;
+	}
+	ch->n = SMD_LOOPBACK_CID;
+
+	ch->send = &smd_loopback_ctl;
+	ch->recv = &smd_loopback_ctl;
+	ch->send_data = smd_loopback_data;
+	ch->recv_data = smd_loopback_data;
+	ch->fifo_size = SMD_BUF_SIZE;
+
+	ch->fifo_mask = ch->fifo_size - 1;
+	ch->type = SMD_LOOPBACK_TYPE;
+	ch->notify_other_cpu = notify_loopback_smd;
+
+	ch->read = smd_stream_read;
+	ch->write = smd_stream_write;
+	ch->read_avail = smd_stream_read_avail;
+	ch->write_avail = smd_stream_write_avail;
+	ch->update_state = update_stream_state;
+	ch->read_from_cb = smd_stream_read;
+
+	memset(ch->name, 0, 20);
+	memcpy(ch->name, "local_loopback", 14);
+
+	ch->pdev.name = ch->name;
+	ch->pdev.id = ch->type;
+
+	SMD_INFO("%s: '%s' cid=%d\n", __func__, ch->name, ch->n);
 
 	mutex_lock(&smd_creation_mutex);
 	list_add(&ch->ch_list, &smd_ch_closed_list);
@@ -614,53 +1769,36 @@
 	return 0;
 }
 
-static void smd_channel_probe_worker(struct work_struct *work)
-{
-	struct smd_alloc_elm *shared;
-	unsigned ctype;
-	unsigned type;
-	unsigned n;
-
-	shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64);
-	if (!shared) {
-		pr_err("cannot find allocation table\n");
-		return;
-	}
-	for (n = 0; n < 64; n++) {
-		if (smd_ch_allocated[n])
-			continue;
-		if (!shared[n].ref_count)
-			continue;
-		if (!shared[n].name[0])
-			continue;
-		ctype = shared[n].ctype;
-		type = ctype & SMD_TYPE_MASK;
-
-		/* DAL channels are stream but neither the modem,
-		 * nor the DSP correctly indicate this.  Fixup manually.
-		 */
-		if (!memcmp(shared[n].name, "DAL", 3))
-			ctype = (ctype & (~SMD_KIND_MASK)) | SMD_KIND_STREAM;
-
-		type = shared[n].ctype & SMD_TYPE_MASK;
-		if ((type == SMD_TYPE_APPS_MODEM) ||
-		    (type == SMD_TYPE_APPS_DSP))
-			if (!smd_alloc_channel(shared[n].name, shared[n].cid, ctype))
-				smd_ch_allocated[n] = 1;
-	}
-}
-
 static void do_nothing_notify(void *priv, unsigned flags)
 {
 }
 
-struct smd_channel *smd_get_channel(const char *name)
+static void finalize_channel_close_fn(struct work_struct *work)
+{
+	unsigned long flags;
+	struct smd_channel *ch;
+	struct smd_channel *index;
+
+	mutex_lock(&smd_creation_mutex);
+	spin_lock_irqsave(&smd_lock, flags);
+	list_for_each_entry_safe(ch, index,  &smd_ch_to_close_list, ch_list) {
+		list_del(&ch->ch_list);
+		list_add(&ch->ch_list, &smd_ch_closed_list);
+		ch->notify(ch->priv, SMD_EVENT_REOPEN_READY);
+		ch->notify = do_nothing_notify;
+	}
+	spin_unlock_irqrestore(&smd_lock, flags);
+	mutex_unlock(&smd_creation_mutex);
+}
+
+struct smd_channel *smd_get_channel(const char *name, uint32_t type)
 {
 	struct smd_channel *ch;
 
 	mutex_lock(&smd_creation_mutex);
 	list_for_each_entry(ch, &smd_ch_closed_list, ch_list) {
-		if (!strcmp(name, ch->name)) {
+		if (!strcmp(name, ch->name) &&
+			(type == ch->type)) {
 			list_del(&ch->ch_list);
 			mutex_unlock(&smd_creation_mutex);
 			return ch;
@@ -671,20 +1809,49 @@
 	return NULL;
 }
 
-int smd_open(const char *name, smd_channel_t **_ch,
-	     void *priv, void (*notify)(void *, unsigned))
+int smd_named_open_on_edge(const char *name, uint32_t edge,
+			   smd_channel_t **_ch,
+			   void *priv, void (*notify)(void *, unsigned))
 {
 	struct smd_channel *ch;
 	unsigned long flags;
 
 	if (smd_initialized == 0) {
-		pr_info("smd_open() before smd_init()\n");
+		SMD_INFO("smd_open() before smd_init()\n");
 		return -ENODEV;
 	}
 
-	ch = smd_get_channel(name);
-	if (!ch)
-		return -ENODEV;
+	SMD_DBG("smd_open('%s', %p, %p)\n", name, priv, notify);
+
+	ch = smd_get_channel(name, edge);
+	if (!ch) {
+		/* check closing list for port */
+		spin_lock_irqsave(&smd_lock, flags);
+		list_for_each_entry(ch, &smd_ch_closing_list, ch_list) {
+			if (!strncmp(name, ch->name, 20) &&
+				(edge == ch->type)) {
+				/* channel exists, but is being closed */
+				spin_unlock_irqrestore(&smd_lock, flags);
+				return -EAGAIN;
+			}
+		}
+
+		/* check closing workqueue list for port */
+		list_for_each_entry(ch, &smd_ch_to_close_list, ch_list) {
+			if (!strncmp(name, ch->name, 20) &&
+				(edge == ch->type)) {
+				/* channel exists, but is being closed */
+				spin_unlock_irqrestore(&smd_lock, flags);
+				return -EAGAIN;
+			}
+		}
+		spin_unlock_irqrestore(&smd_lock, flags);
+
+		/* one final check to handle closing->closed race condition */
+		ch = smd_get_channel(name, edge);
+		if (!ch)
+			return -ENODEV;
+	}
 
 	if (notify == 0)
 		notify = do_nothing_notify;
@@ -694,34 +1861,51 @@
 	ch->last_state = SMD_SS_CLOSED;
 	ch->priv = priv;
 
+	if (edge == SMD_LOOPBACK_TYPE) {
+		ch->last_state = SMD_SS_OPENED;
+		ch->half_ch->set_state(ch->send, SMD_SS_OPENED);
+		ch->half_ch->set_fDSR(ch->send, 1);
+		ch->half_ch->set_fCTS(ch->send, 1);
+		ch->half_ch->set_fCD(ch->send, 1);
+	}
+
 	*_ch = ch;
 
+	SMD_DBG("smd_open: opening '%s'\n", ch->name);
+
 	spin_lock_irqsave(&smd_lock, flags);
-
-	if ((ch->type & SMD_TYPE_MASK) == SMD_TYPE_APPS_MODEM)
+	if (SMD_CHANNEL_TYPE(ch->type) == SMD_APPS_MODEM)
 		list_add(&ch->ch_list, &smd_ch_list_modem);
-	else
+	else if (SMD_CHANNEL_TYPE(ch->type) == SMD_APPS_QDSP)
 		list_add(&ch->ch_list, &smd_ch_list_dsp);
+	else if (SMD_CHANNEL_TYPE(ch->type) == SMD_APPS_DSPS)
+		list_add(&ch->ch_list, &smd_ch_list_dsps);
+	else if (SMD_CHANNEL_TYPE(ch->type) == SMD_APPS_WCNSS)
+		list_add(&ch->ch_list, &smd_ch_list_wcnss);
+	else if (SMD_CHANNEL_TYPE(ch->type) == SMD_APPS_RPM)
+		list_add(&ch->ch_list, &smd_ch_list_rpm);
+	else
+		list_add(&ch->ch_list, &smd_ch_list_loopback);
 
-	/* If the remote side is CLOSING, we need to get it to
-	 * move to OPENING (which we'll do by moving from CLOSED to
-	 * OPENING) and then get it to move from OPENING to
-	 * OPENED (by doing the same state change ourselves).
-	 *
-	 * Otherwise, it should be OPENING and we can move directly
-	 * to OPENED so that it will follow.
-	 */
-	if (ch->recv->state == SMD_SS_CLOSING) {
-		ch->send->head = 0;
-		ch_set_state(ch, SMD_SS_OPENING);
-	} else {
-		ch_set_state(ch, SMD_SS_OPENED);
-	}
+	SMD_DBG("%s: opening ch %d\n", __func__, ch->n);
+
+	if (edge != SMD_LOOPBACK_TYPE)
+		smd_state_change(ch, ch->last_state, SMD_SS_OPENING);
+
 	spin_unlock_irqrestore(&smd_lock, flags);
-	smd_kick(ch);
 
 	return 0;
 }
+EXPORT_SYMBOL(smd_named_open_on_edge);
+
+
+int smd_open(const char *name, smd_channel_t **_ch,
+	     void *priv, void (*notify)(void *, unsigned))
+{
+	return smd_named_open_on_edge(name, SMD_APPS_MODEM, _ch, priv,
+				      notify);
+}
+EXPORT_SYMBOL(smd_open);
 
 int smd_close(smd_channel_t *ch)
 {
@@ -730,48 +1914,215 @@
 	if (ch == 0)
 		return -1;
 
-	spin_lock_irqsave(&smd_lock, flags);
-	ch->notify = do_nothing_notify;
-	list_del(&ch->ch_list);
-	ch_set_state(ch, SMD_SS_CLOSED);
-	spin_unlock_irqrestore(&smd_lock, flags);
+	SMD_INFO("smd_close(%s)\n", ch->name);
 
-	mutex_lock(&smd_creation_mutex);
-	list_add(&ch->ch_list, &smd_ch_closed_list);
-	mutex_unlock(&smd_creation_mutex);
+	spin_lock_irqsave(&smd_lock, flags);
+	list_del(&ch->ch_list);
+	if (ch->n == SMD_LOOPBACK_CID) {
+		ch->half_ch->set_fDSR(ch->send, 0);
+		ch->half_ch->set_fCTS(ch->send, 0);
+		ch->half_ch->set_fCD(ch->send, 0);
+		ch->half_ch->set_state(ch->send, SMD_SS_CLOSED);
+	} else
+		ch_set_state(ch, SMD_SS_CLOSED);
+
+	if (ch->half_ch->get_state(ch->recv) == SMD_SS_OPENED) {
+		list_add(&ch->ch_list, &smd_ch_closing_list);
+		spin_unlock_irqrestore(&smd_lock, flags);
+	} else {
+		spin_unlock_irqrestore(&smd_lock, flags);
+		ch->notify = do_nothing_notify;
+		mutex_lock(&smd_creation_mutex);
+		list_add(&ch->ch_list, &smd_ch_closed_list);
+		mutex_unlock(&smd_creation_mutex);
+	}
 
 	return 0;
 }
+EXPORT_SYMBOL(smd_close);
+
+int smd_write_start(smd_channel_t *ch, int len)
+{
+	int ret;
+	unsigned hdr[5];
+
+	if (!ch) {
+		pr_err("%s: Invalid channel specified\n", __func__);
+		return -ENODEV;
+	}
+	if (!ch->is_pkt_ch) {
+		pr_err("%s: non-packet channel specified\n", __func__);
+		return -EACCES;
+	}
+	if (len < 1) {
+		pr_err("%s: invalid length: %d\n", __func__, len);
+		return -EINVAL;
+	}
+
+	if (ch->pending_pkt_sz) {
+		pr_err("%s: packet of size: %d in progress\n", __func__,
+			ch->pending_pkt_sz);
+		return -EBUSY;
+	}
+	ch->pending_pkt_sz = len;
+
+	if (smd_stream_write_avail(ch) < (SMD_HEADER_SIZE)) {
+		ch->pending_pkt_sz = 0;
+		SMD_DBG("%s: no space to write packet header\n", __func__);
+		return -EAGAIN;
+	}
+
+	hdr[0] = len;
+	hdr[1] = hdr[2] = hdr[3] = hdr[4] = 0;
+
+
+	ret = smd_stream_write(ch, hdr, sizeof(hdr), 0);
+	if (ret < 0 || ret != sizeof(hdr)) {
+		ch->pending_pkt_sz = 0;
+		pr_err("%s: packet header failed to write\n", __func__);
+		return -EPERM;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(smd_write_start);
+
+int smd_write_segment(smd_channel_t *ch, void *data, int len, int user_buf)
+{
+	int bytes_written;
+
+	if (!ch) {
+		pr_err("%s: Invalid channel specified\n", __func__);
+		return -ENODEV;
+	}
+	if (len < 1) {
+		pr_err("%s: invalid length: %d\n", __func__, len);
+		return -EINVAL;
+	}
+
+	if (!ch->pending_pkt_sz) {
+		pr_err("%s: no transaction in progress\n", __func__);
+		return -ENOEXEC;
+	}
+	if (ch->pending_pkt_sz - len < 0) {
+		pr_err("%s: segment of size: %d will make packet go over "
+			"length\n", __func__, len);
+		return -EINVAL;
+	}
+
+	bytes_written = smd_stream_write(ch, data, len, user_buf);
+
+	ch->pending_pkt_sz -= bytes_written;
+
+	return bytes_written;
+}
+EXPORT_SYMBOL(smd_write_segment);
+
+int smd_write_end(smd_channel_t *ch)
+{
+
+	if (!ch) {
+		pr_err("%s: Invalid channel specified\n", __func__);
+		return -ENODEV;
+	}
+	if (ch->pending_pkt_sz) {
+		pr_err("%s: current packet not completely written\n", __func__);
+		return -E2BIG;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(smd_write_end);
 
 int smd_read(smd_channel_t *ch, void *data, int len)
 {
-	return ch->read(ch, data, len);
+	if (!ch) {
+		pr_err("%s: Invalid channel specified\n", __func__);
+		return -ENODEV;
+	}
+
+	return ch->read(ch, data, len, 0);
 }
+EXPORT_SYMBOL(smd_read);
+
+int smd_read_user_buffer(smd_channel_t *ch, void *data, int len)
+{
+	if (!ch) {
+		pr_err("%s: Invalid channel specified\n", __func__);
+		return -ENODEV;
+	}
+
+	return ch->read(ch, data, len, 1);
+}
+EXPORT_SYMBOL(smd_read_user_buffer);
+
+int smd_read_from_cb(smd_channel_t *ch, void *data, int len)
+{
+	if (!ch) {
+		pr_err("%s: Invalid channel specified\n", __func__);
+		return -ENODEV;
+	}
+
+	return ch->read_from_cb(ch, data, len, 0);
+}
+EXPORT_SYMBOL(smd_read_from_cb);
 
 int smd_write(smd_channel_t *ch, const void *data, int len)
 {
-	return ch->write(ch, data, len);
-}
+	if (!ch) {
+		pr_err("%s: Invalid channel specified\n", __func__);
+		return -ENODEV;
+	}
 
-int smd_write_atomic(smd_channel_t *ch, const void *data, int len)
-{
-	unsigned long flags;
-	int res;
-	spin_lock_irqsave(&smd_lock, flags);
-	res = ch->write(ch, data, len);
-	spin_unlock_irqrestore(&smd_lock, flags);
-	return res;
+	return ch->pending_pkt_sz ? -EBUSY : ch->write(ch, data, len, 0);
 }
+EXPORT_SYMBOL(smd_write);
+
+int smd_write_user_buffer(smd_channel_t *ch, const void *data, int len)
+{
+	if (!ch) {
+		pr_err("%s: Invalid channel specified\n", __func__);
+		return -ENODEV;
+	}
+
+	return ch->pending_pkt_sz ? -EBUSY : ch->write(ch, data, len, 1);
+}
+EXPORT_SYMBOL(smd_write_user_buffer);
 
 int smd_read_avail(smd_channel_t *ch)
 {
+	if (!ch) {
+		pr_err("%s: Invalid channel specified\n", __func__);
+		return -ENODEV;
+	}
+
 	return ch->read_avail(ch);
 }
+EXPORT_SYMBOL(smd_read_avail);
 
 int smd_write_avail(smd_channel_t *ch)
 {
+	if (!ch) {
+		pr_err("%s: Invalid channel specified\n", __func__);
+		return -ENODEV;
+	}
+
 	return ch->write_avail(ch);
 }
+EXPORT_SYMBOL(smd_write_avail);
+
+void smd_enable_read_intr(smd_channel_t *ch)
+{
+	if (ch)
+		ch->half_ch->set_fBLOCKREADINTR(ch->send, 0);
+}
+EXPORT_SYMBOL(smd_enable_read_intr);
+
+void smd_disable_read_intr(smd_channel_t *ch)
+{
+	if (ch)
+		ch->half_ch->set_fBLOCKREADINTR(ch->send, 1);
+}
+EXPORT_SYMBOL(smd_disable_read_intr);
 
 int smd_wait_until_readable(smd_channel_t *ch, int bytes)
 {
@@ -785,41 +2136,222 @@
 
 int smd_cur_packet_size(smd_channel_t *ch)
 {
+	if (!ch) {
+		pr_err("%s: Invalid channel specified\n", __func__);
+		return -ENODEV;
+	}
+
 	return ch->current_packet;
 }
+EXPORT_SYMBOL(smd_cur_packet_size);
+
+int smd_tiocmget(smd_channel_t *ch)
+{
+	if (!ch) {
+		pr_err("%s: Invalid channel specified\n", __func__);
+		return -ENODEV;
+	}
+
+	return  (ch->half_ch->get_fDSR(ch->recv) ? TIOCM_DSR : 0) |
+		(ch->half_ch->get_fCTS(ch->recv) ? TIOCM_CTS : 0) |
+		(ch->half_ch->get_fCD(ch->recv) ? TIOCM_CD : 0) |
+		(ch->half_ch->get_fRI(ch->recv) ? TIOCM_RI : 0) |
+		(ch->half_ch->get_fCTS(ch->send) ? TIOCM_RTS : 0) |
+		(ch->half_ch->get_fDSR(ch->send) ? TIOCM_DTR : 0);
+}
+EXPORT_SYMBOL(smd_tiocmget);
+
+/* this api will be called while holding smd_lock */
+int
+smd_tiocmset_from_cb(smd_channel_t *ch, unsigned int set, unsigned int clear)
+{
+	if (!ch) {
+		pr_err("%s: Invalid channel specified\n", __func__);
+		return -ENODEV;
+	}
+
+	if (set & TIOCM_DTR)
+		ch->half_ch->set_fDSR(ch->send, 1);
+
+	if (set & TIOCM_RTS)
+		ch->half_ch->set_fCTS(ch->send, 1);
+
+	if (clear & TIOCM_DTR)
+		ch->half_ch->set_fDSR(ch->send, 0);
+
+	if (clear & TIOCM_RTS)
+		ch->half_ch->set_fCTS(ch->send, 0);
+
+	ch->half_ch->set_fSTATE(ch->send, 1);
+	barrier();
+	ch->notify_other_cpu();
+
+	return 0;
+}
+EXPORT_SYMBOL(smd_tiocmset_from_cb);
+
+int smd_tiocmset(smd_channel_t *ch, unsigned int set, unsigned int clear)
+{
+	unsigned long flags;
+
+	if (!ch) {
+		pr_err("%s: Invalid channel specified\n", __func__);
+		return -ENODEV;
+	}
+
+	spin_lock_irqsave(&smd_lock, flags);
+	smd_tiocmset_from_cb(ch, set, clear);
+	spin_unlock_irqrestore(&smd_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(smd_tiocmset);
+
+int smd_is_pkt_avail(smd_channel_t *ch)
+{
+	if (!ch || !ch->is_pkt_ch)
+		return -EINVAL;
+
+	if (ch->current_packet)
+		return 1;
+
+	update_packet_state(ch);
+
+	return ch->current_packet ? 1 : 0;
+}
+EXPORT_SYMBOL(smd_is_pkt_avail);
 
 
-/* ------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
 
+/*
+ * Shared Memory Range Check
+ *
+ * Takes a physical address and an offset and checks if the resulting physical
+ * address would fit into one of the aux smem regions.  If so, returns the
+ * corresponding virtual address.  Otherwise returns NULL.  Expects the array
+ * of smem regions to be in ascending physical address order.
+ *
+ * @base: physical base address to check
+ * @offset: offset from the base to get the final address
+ */
+static void *smem_range_check(void *base, unsigned offset)
+{
+	int i;
+	void *phys_addr;
+	unsigned size;
+
+	for (i = 0; i < num_smem_areas; ++i) {
+		phys_addr = smem_areas[i].phys_addr;
+		size = smem_areas[i].size;
+		if (base < phys_addr)
+			return NULL;
+		if (base > phys_addr + size)
+			continue;
+		if (base >= phys_addr && base + offset < phys_addr + size)
+			return smem_areas[i].virt_addr + offset;
+	}
+
+	return NULL;
+}
+
+/* smem_alloc returns the pointer to smem item if it is already allocated.
+ * Otherwise, it returns NULL.
+ */
 void *smem_alloc(unsigned id, unsigned size)
 {
 	return smem_find(id, size);
 }
+EXPORT_SYMBOL(smem_alloc);
 
-void *smem_item(unsigned id, unsigned *size)
+/* smem_alloc2 returns the pointer to smem item.  If it is not allocated,
+ * it allocates it and then returns the pointer to it.
+ */
+void *smem_alloc2(unsigned id, unsigned size_in)
 {
 	struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
 	struct smem_heap_entry *toc = shared->heap_toc;
+	unsigned long flags;
+	void *ret = NULL;
+
+	if (!shared->heap_info.initialized) {
+		pr_err("%s: smem heap info not initialized\n", __func__);
+		return NULL;
+	}
 
 	if (id >= SMEM_NUM_ITEMS)
-		return 0;
+		return NULL;
 
+	size_in = ALIGN(size_in, 8);
+	remote_spin_lock_irqsave(&remote_spinlock, flags);
+	if (toc[id].allocated) {
+		SMD_DBG("%s: %u already allocated\n", __func__, id);
+		if (size_in != toc[id].size)
+			pr_err("%s: wrong size %u (expected %u)\n",
+			       __func__, toc[id].size, size_in);
+		else
+			ret = (void *)(MSM_SHARED_RAM_BASE + toc[id].offset);
+	} else if (id > SMEM_FIXED_ITEM_LAST) {
+		SMD_DBG("%s: allocating %u\n", __func__, id);
+		if (shared->heap_info.heap_remaining >= size_in) {
+			toc[id].offset = shared->heap_info.free_offset;
+			toc[id].size = size_in;
+			wmb();
+			toc[id].allocated = 1;
+
+			shared->heap_info.free_offset += size_in;
+			shared->heap_info.heap_remaining -= size_in;
+			ret = (void *)(MSM_SHARED_RAM_BASE + toc[id].offset);
+		} else
+			pr_err("%s: not enough memory %u (required %u)\n",
+			       __func__, shared->heap_info.heap_remaining,
+			       size_in);
+	}
+	wmb();
+	remote_spin_unlock_irqrestore(&remote_spinlock, flags);
+	return ret;
+}
+EXPORT_SYMBOL(smem_alloc2);
+
+void *smem_get_entry(unsigned id, unsigned *size)
+{
+	struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
+	struct smem_heap_entry *toc = shared->heap_toc;
+	int use_spinlocks = spinlocks_initialized;
+	void *ret = 0;
+	unsigned long flags = 0;
+
+	if (id >= SMEM_NUM_ITEMS)
+		return ret;
+
+	if (use_spinlocks)
+		remote_spin_lock_irqsave(&remote_spinlock, flags);
+	/* toc is in device memory and cannot be speculatively accessed */
 	if (toc[id].allocated) {
 		*size = toc[id].size;
-		return (void *) (MSM_SHARED_RAM_BASE + toc[id].offset);
+		barrier();
+		if (!(toc[id].reserved & BASE_ADDR_MASK))
+			ret = (void *) (MSM_SHARED_RAM_BASE + toc[id].offset);
+		else
+			ret = smem_range_check(
+				(void *)(toc[id].reserved & BASE_ADDR_MASK),
+				toc[id].offset);
 	} else {
 		*size = 0;
 	}
+	if (use_spinlocks)
+		remote_spin_unlock_irqrestore(&remote_spinlock, flags);
 
-	return 0;
+	return ret;
 }
+EXPORT_SYMBOL(smem_get_entry);
 
 void *smem_find(unsigned id, unsigned size_in)
 {
 	unsigned size;
 	void *ptr;
 
-	ptr = smem_item(id, &size);
+	ptr = smem_get_entry(id, &size);
 	if (!ptr)
 		return 0;
 
@@ -832,195 +2364,1117 @@
 
 	return ptr;
 }
+EXPORT_SYMBOL(smem_find);
+
+static int smsm_cb_init(void)
+{
+	struct smsm_state_info *state_info;
+	int n;
+	int ret = 0;
+
+	smsm_states = kmalloc(sizeof(struct smsm_state_info)*SMSM_NUM_ENTRIES,
+		   GFP_KERNEL);
+
+	if (!smsm_states) {
+		pr_err("%s: SMSM init failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	smsm_cb_wq = create_singlethread_workqueue("smsm_cb_wq");
+	if (!smsm_cb_wq) {
+		pr_err("%s: smsm_cb_wq creation failed\n", __func__);
+		kfree(smsm_states);
+		return -EFAULT;
+	}
+
+	mutex_lock(&smsm_lock);
+	for (n = 0; n < SMSM_NUM_ENTRIES; n++) {
+		state_info = &smsm_states[n];
+		state_info->last_value = __raw_readl(SMSM_STATE_ADDR(n));
+		state_info->intr_mask_set = 0x0;
+		state_info->intr_mask_clear = 0x0;
+		INIT_LIST_HEAD(&state_info->callbacks);
+	}
+	mutex_unlock(&smsm_lock);
+
+	return ret;
+}
+
+static int smsm_init(void)
+{
+	struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
+	int i;
+	struct smsm_size_info_type *smsm_size_info;
+
+	i = remote_spin_lock_init(&remote_spinlock, SMEM_SPINLOCK_SMEM_ALLOC);
+	if (i) {
+		pr_err("%s: remote spinlock init failed %d\n", __func__, i);
+		return i;
+	}
+	spinlocks_initialized = 1;
+
+	smsm_size_info = smem_alloc(SMEM_SMSM_SIZE_INFO,
+				sizeof(struct smsm_size_info_type));
+	if (smsm_size_info) {
+		SMSM_NUM_ENTRIES = smsm_size_info->num_entries;
+		SMSM_NUM_HOSTS = smsm_size_info->num_hosts;
+	}
+
+	i = kfifo_alloc(&smsm_snapshot_fifo,
+			sizeof(uint32_t) * SMSM_NUM_ENTRIES * SMSM_SNAPSHOT_CNT,
+			GFP_KERNEL);
+	if (i) {
+		pr_err("%s: SMSM state fifo alloc failed %d\n", __func__, i);
+		return i;
+	}
+	wake_lock_init(&smsm_snapshot_wakelock, WAKE_LOCK_SUSPEND,
+			"smsm_snapshot");
+
+	if (!smsm_info.state) {
+		smsm_info.state = smem_alloc2(ID_SHARED_STATE,
+					      SMSM_NUM_ENTRIES *
+					      sizeof(uint32_t));
+
+		if (smsm_info.state) {
+			__raw_writel(0, SMSM_STATE_ADDR(SMSM_APPS_STATE));
+			if ((shared->version[VERSION_MODEM] >> 16) >= 0xB)
+				__raw_writel(0, \
+					SMSM_STATE_ADDR(SMSM_APPS_DEM_I));
+		}
+	}
+
+	if (!smsm_info.intr_mask) {
+		smsm_info.intr_mask = smem_alloc2(SMEM_SMSM_CPU_INTR_MASK,
+						  SMSM_NUM_ENTRIES *
+						  SMSM_NUM_HOSTS *
+						  sizeof(uint32_t));
+
+		if (smsm_info.intr_mask) {
+			for (i = 0; i < SMSM_NUM_ENTRIES; i++)
+				__raw_writel(0x0,
+					SMSM_INTR_MASK_ADDR(i, SMSM_APPS));
+
+			/* Configure legacy modem bits */
+			__raw_writel(LEGACY_MODEM_SMSM_MASK,
+				SMSM_INTR_MASK_ADDR(SMSM_MODEM_STATE,
+					SMSM_APPS));
+		}
+	}
+
+	if (!smsm_info.intr_mux)
+		smsm_info.intr_mux = smem_alloc2(SMEM_SMD_SMSM_INTR_MUX,
+						 SMSM_NUM_INTR_MUX *
+						 sizeof(uint32_t));
+
+	i = smsm_cb_init();
+	if (i)
+		return i;
+
+	wmb();
+	smsm_driver_state_notify(SMSM_INIT, NULL);
+	return 0;
+}
+
+void smsm_reset_modem(unsigned mode)
+{
+	if (mode == SMSM_SYSTEM_DOWNLOAD) {
+		mode = SMSM_RESET | SMSM_SYSTEM_DOWNLOAD;
+	} else if (mode == SMSM_MODEM_WAIT) {
+		mode = SMSM_RESET | SMSM_MODEM_WAIT;
+	} else { /* reset_mode is SMSM_RESET or default */
+		mode = SMSM_RESET;
+	}
+
+	smsm_change_state(SMSM_APPS_STATE, mode, mode);
+}
+EXPORT_SYMBOL(smsm_reset_modem);
+
+void smsm_reset_modem_cont(void)
+{
+	unsigned long flags;
+	uint32_t state;
+
+	if (!smsm_info.state)
+		return;
+
+	spin_lock_irqsave(&smem_lock, flags);
+	state = __raw_readl(SMSM_STATE_ADDR(SMSM_APPS_STATE)) \
+						& ~SMSM_MODEM_WAIT;
+	__raw_writel(state, SMSM_STATE_ADDR(SMSM_APPS_STATE));
+	wmb();
+	spin_unlock_irqrestore(&smem_lock, flags);
+}
+EXPORT_SYMBOL(smsm_reset_modem_cont);
+
+static void smsm_cb_snapshot(uint32_t use_wakelock)
+{
+	int n;
+	uint32_t new_state;
+	unsigned long flags;
+	int ret;
+
+	ret = kfifo_avail(&smsm_snapshot_fifo);
+	if (ret < SMSM_SNAPSHOT_SIZE) {
+		pr_err("%s: SMSM snapshot full %d\n", __func__, ret);
+		return;
+	}
+
+	/*
+	 * To avoid a race condition with notify_smsm_cb_clients_worker, the
+	 * following sequence must be followed:
+	 *   1) increment snapshot count
+	 *   2) insert data into FIFO
+	 *
+	 *   Potentially in parallel, the worker:
+	 *   a) verifies >= 1 snapshots are in FIFO
+	 *   b) processes snapshot
+	 *   c) decrements reference count
+	 *
+	 *   This order ensures that 1 will always occur before abc.
+	 */
+	if (use_wakelock) {
+		spin_lock_irqsave(&smsm_snapshot_count_lock, flags);
+		if (smsm_snapshot_count == 0) {
+			SMx_POWER_INFO("SMSM snapshot wake lock\n");
+			wake_lock(&smsm_snapshot_wakelock);
+		}
+		++smsm_snapshot_count;
+		spin_unlock_irqrestore(&smsm_snapshot_count_lock, flags);
+	}
+
+	/* queue state entries */
+	for (n = 0; n < SMSM_NUM_ENTRIES; n++) {
+		new_state = __raw_readl(SMSM_STATE_ADDR(n));
+
+		ret = kfifo_in(&smsm_snapshot_fifo,
+				&new_state, sizeof(new_state));
+		if (ret != sizeof(new_state)) {
+			pr_err("%s: SMSM snapshot failure %d\n", __func__, ret);
+			goto restore_snapshot_count;
+		}
+	}
+
+	/* queue wakelock usage flag */
+	ret = kfifo_in(&smsm_snapshot_fifo,
+			&use_wakelock, sizeof(use_wakelock));
+	if (ret != sizeof(use_wakelock)) {
+		pr_err("%s: SMSM snapshot failure %d\n", __func__, ret);
+		goto restore_snapshot_count;
+	}
+
+	queue_work(smsm_cb_wq, &smsm_cb_work);
+	return;
+
+restore_snapshot_count:
+	if (use_wakelock) {
+		spin_lock_irqsave(&smsm_snapshot_count_lock, flags);
+		if (smsm_snapshot_count) {
+			--smsm_snapshot_count;
+			if (smsm_snapshot_count == 0) {
+				SMx_POWER_INFO("SMSM snapshot wake unlock\n");
+				wake_unlock(&smsm_snapshot_wakelock);
+			}
+		} else {
+			pr_err("%s: invalid snapshot count\n", __func__);
+		}
+		spin_unlock_irqrestore(&smsm_snapshot_count_lock, flags);
+	}
+}
 
 static irqreturn_t smsm_irq_handler(int irq, void *data)
 {
 	unsigned long flags;
-	unsigned apps, modm;
+
+	if (irq == INT_ADSP_A11_SMSM) {
+		uint32_t mux_val;
+		static uint32_t prev_smem_q6_apps_smsm;
+
+		if (smsm_info.intr_mux && cpu_is_qsd8x50()) {
+			mux_val = __raw_readl(
+					SMSM_INTR_MUX_ADDR(SMEM_Q6_APPS_SMSM));
+			if (mux_val != prev_smem_q6_apps_smsm)
+				prev_smem_q6_apps_smsm = mux_val;
+		}
+
+		spin_lock_irqsave(&smem_lock, flags);
+		smsm_cb_snapshot(1);
+		spin_unlock_irqrestore(&smem_lock, flags);
+		return IRQ_HANDLED;
+	}
 
 	spin_lock_irqsave(&smem_lock, flags);
+	if (!smsm_info.state) {
+		SMSM_INFO("<SM NO STATE>\n");
+	} else {
+		unsigned old_apps, apps;
+		unsigned modm = __raw_readl(SMSM_STATE_ADDR(SMSM_MODEM_STATE));
 
-	apps = raw_smsm_get_state(SMSM_STATE_APPS);
-	modm = raw_smsm_get_state(SMSM_STATE_MODEM);
+		old_apps = apps = __raw_readl(SMSM_STATE_ADDR(SMSM_APPS_STATE));
 
-	if (msm_smd_debug_mask & MSM_SMSM_DEBUG)
-		pr_info("<SM %08x %08x>\n", apps, modm);
-	if (modm & SMSM_RESET)
-		handle_modem_crash();
+		SMSM_DBG("<SM %08x %08x>\n", apps, modm);
+		if (apps & SMSM_RESET) {
+			/* If we get an interrupt and the apps SMSM_RESET
+			   bit is already set, the modem is acking the
+			   app's reset ack. */
+			if (!disable_smsm_reset_handshake)
+				apps &= ~SMSM_RESET;
+			/* Issue a fake irq to handle any
+			 * smd state changes during reset
+			 */
+			smd_fake_irq_handler(0);
 
-	do_smd_probe();
+			/* queue modem restart notify chain */
+			modem_queue_start_reset_notify();
 
+		} else if (modm & SMSM_RESET) {
+			pr_err("\nSMSM: Modem SMSM state changed to SMSM_RESET.");
+			if (!disable_smsm_reset_handshake) {
+				apps |= SMSM_RESET;
+				flush_cache_all();
+				outer_flush_all();
+			}
+			modem_queue_start_reset_notify();
+
+		} else if (modm & SMSM_INIT) {
+			if (!(apps & SMSM_INIT)) {
+				apps |= SMSM_INIT;
+				modem_queue_smsm_init_notify();
+			}
+
+			if (modm & SMSM_SMDINIT)
+				apps |= SMSM_SMDINIT;
+			if ((apps & (SMSM_INIT | SMSM_SMDINIT | SMSM_RPCINIT)) ==
+				(SMSM_INIT | SMSM_SMDINIT | SMSM_RPCINIT))
+				apps |= SMSM_RUN;
+		} else if (modm & SMSM_SYSTEM_DOWNLOAD) {
+			pr_err("\nSMSM: Modem SMSM state changed to SMSM_SYSTEM_DOWNLOAD.");
+			modem_queue_start_reset_notify();
+		}
+
+		if (old_apps != apps) {
+			SMSM_DBG("<SM %08x NOTIFY>\n", apps);
+			__raw_writel(apps, SMSM_STATE_ADDR(SMSM_APPS_STATE));
+			do_smd_probe();
+			notify_other_smsm(SMSM_APPS_STATE, (old_apps ^ apps));
+		}
+
+		smsm_cb_snapshot(1);
+	}
 	spin_unlock_irqrestore(&smem_lock, flags);
 	return IRQ_HANDLED;
 }
 
-int smsm_change_state(enum smsm_state_item item,
-		      uint32_t clear_mask, uint32_t set_mask)
+static irqreturn_t smsm_modem_irq_handler(int irq, void *data)
 {
-	unsigned long addr = smd_info.state + item * 4;
-	unsigned long flags;
-	unsigned state;
+	SMx_POWER_INFO("SMSM Int Modem->Apps\n");
+	++interrupt_stats[SMD_MODEM].smsm_in_count;
+	return smsm_irq_handler(irq, data);
+}
 
-	if (!smd_info.ready)
+static irqreturn_t smsm_dsp_irq_handler(int irq, void *data)
+{
+	SMx_POWER_INFO("SMSM Int LPASS->Apps\n");
+	++interrupt_stats[SMD_Q6].smsm_in_count;
+	return smsm_irq_handler(irq, data);
+}
+
+static irqreturn_t smsm_dsps_irq_handler(int irq, void *data)
+{
+	SMx_POWER_INFO("SMSM Int DSPS->Apps\n");
+	++interrupt_stats[SMD_DSPS].smsm_in_count;
+	return smsm_irq_handler(irq, data);
+}
+
+static irqreturn_t smsm_wcnss_irq_handler(int irq, void *data)
+{
+	SMx_POWER_INFO("SMSM Int WCNSS->Apps\n");
+	++interrupt_stats[SMD_WCNSS].smsm_in_count;
+	return smsm_irq_handler(irq, data);
+}
+
+/*
+ * Changes the global interrupt mask.  The set and clear masks are re-applied
+ * every time the global interrupt mask is updated for callback registration
+ * and de-registration.
+ *
+ * The clear mask is applied first, so if a bit is set to 1 in both the clear
+ * mask and the set mask, the result will be that the interrupt is set.
+ *
+ * @smsm_entry  SMSM entry to change
+ * @clear_mask  1 = clear bit, 0 = no-op
+ * @set_mask    1 = set bit, 0 = no-op
+ *
+ * @returns 0 for success, < 0 for error
+ */
+int smsm_change_intr_mask(uint32_t smsm_entry,
+			  uint32_t clear_mask, uint32_t set_mask)
+{
+	uint32_t  old_mask, new_mask;
+	unsigned long flags;
+
+	if (smsm_entry >= SMSM_NUM_ENTRIES) {
+		pr_err("smsm_change_state: Invalid entry %d\n",
+		       smsm_entry);
+		return -EINVAL;
+	}
+
+	if (!smsm_info.intr_mask) {
+		pr_err("smsm_change_intr_mask <SM NO STATE>\n");
 		return -EIO;
+	}
 
 	spin_lock_irqsave(&smem_lock, flags);
+	smsm_states[smsm_entry].intr_mask_clear = clear_mask;
+	smsm_states[smsm_entry].intr_mask_set = set_mask;
 
-	if (raw_smsm_get_state(SMSM_STATE_MODEM) & SMSM_RESET)
-		handle_modem_crash();
+	old_mask = __raw_readl(SMSM_INTR_MASK_ADDR(smsm_entry, SMSM_APPS));
+	new_mask = (old_mask & ~clear_mask) | set_mask;
+	__raw_writel(new_mask, SMSM_INTR_MASK_ADDR(smsm_entry, SMSM_APPS));
 
-	state = (readl(addr) & ~clear_mask) | set_mask;
-	writel(state, addr);
+	wmb();
+	spin_unlock_irqrestore(&smem_lock, flags);
 
-	if (msm_smd_debug_mask & MSM_SMSM_DEBUG)
-		pr_info("smsm_change_state %d %x\n", item, state);
-	notify_other_smsm();
+	return 0;
+}
+EXPORT_SYMBOL(smsm_change_intr_mask);
+
+int smsm_get_intr_mask(uint32_t smsm_entry, uint32_t *intr_mask)
+{
+	if (smsm_entry >= SMSM_NUM_ENTRIES) {
+		pr_err("smsm_change_state: Invalid entry %d\n",
+		       smsm_entry);
+		return -EINVAL;
+	}
+
+	if (!smsm_info.intr_mask) {
+		pr_err("smsm_change_intr_mask <SM NO STATE>\n");
+		return -EIO;
+	}
+
+	*intr_mask = __raw_readl(SMSM_INTR_MASK_ADDR(smsm_entry, SMSM_APPS));
+	return 0;
+}
+EXPORT_SYMBOL(smsm_get_intr_mask);
+
+int smsm_change_state(uint32_t smsm_entry,
+		      uint32_t clear_mask, uint32_t set_mask)
+{
+	unsigned long flags;
+	uint32_t  old_state, new_state;
+
+	if (smsm_entry >= SMSM_NUM_ENTRIES) {
+		pr_err("smsm_change_state: Invalid entry %d",
+		       smsm_entry);
+		return -EINVAL;
+	}
+
+	if (!smsm_info.state) {
+		pr_err("smsm_change_state <SM NO STATE>\n");
+		return -EIO;
+	}
+	spin_lock_irqsave(&smem_lock, flags);
+
+	old_state = __raw_readl(SMSM_STATE_ADDR(smsm_entry));
+	new_state = (old_state & ~clear_mask) | set_mask;
+	__raw_writel(new_state, SMSM_STATE_ADDR(smsm_entry));
+	SMSM_DBG("smsm_change_state %x\n", new_state);
+	notify_other_smsm(SMSM_APPS_STATE, (old_state ^ new_state));
 
 	spin_unlock_irqrestore(&smem_lock, flags);
 
 	return 0;
 }
+EXPORT_SYMBOL(smsm_change_state);
 
-uint32_t smsm_get_state(enum smsm_state_item item)
+uint32_t smsm_get_state(uint32_t smsm_entry)
 {
-	unsigned long flags;
-	uint32_t rv;
+	uint32_t rv = 0;
 
-	spin_lock_irqsave(&smem_lock, flags);
+	/* needs interface change to return error code */
+	if (smsm_entry >= SMSM_NUM_ENTRIES) {
+		pr_err("smsm_change_state: Invalid entry %d",
+		       smsm_entry);
+		return 0;
+	}
 
-	rv = readl(smd_info.state + item * 4);
-
-	if (item == SMSM_STATE_MODEM && (rv & SMSM_RESET))
-		handle_modem_crash();
-
-	spin_unlock_irqrestore(&smem_lock, flags);
+	if (!smsm_info.state) {
+		pr_err("smsm_get_state <SM NO STATE>\n");
+	} else {
+		rv = __raw_readl(SMSM_STATE_ADDR(smsm_entry));
+	}
 
 	return rv;
 }
+EXPORT_SYMBOL(smsm_get_state);
 
-#ifdef CONFIG_ARCH_MSM_SCORPION
-
-int smsm_set_sleep_duration(uint32_t delay)
+/**
+ * Performs SMSM callback client notifiction.
+ */
+void notify_smsm_cb_clients_worker(struct work_struct *work)
 {
-	struct msm_dem_slave_data *ptr;
+	struct smsm_state_cb_info *cb_info;
+	struct smsm_state_info *state_info;
+	int n;
+	uint32_t new_state;
+	uint32_t state_changes;
+	uint32_t use_wakelock;
+	int ret;
+	unsigned long flags;
 
-	ptr = smem_find(SMEM_APPS_DEM_SLAVE_DATA, sizeof(*ptr));
-	if (ptr == NULL) {
-		pr_err("smsm_set_sleep_duration <SM NO APPS_DEM_SLAVE_DATA>\n");
-		return -EIO;
+	if (!smd_initialized)
+		return;
+
+	while (kfifo_len(&smsm_snapshot_fifo) >= SMSM_SNAPSHOT_SIZE) {
+		mutex_lock(&smsm_lock);
+		for (n = 0; n < SMSM_NUM_ENTRIES; n++) {
+			state_info = &smsm_states[n];
+
+			ret = kfifo_out(&smsm_snapshot_fifo, &new_state,
+					sizeof(new_state));
+			if (ret != sizeof(new_state)) {
+				pr_err("%s: snapshot underflow %d\n",
+					__func__, ret);
+				mutex_unlock(&smsm_lock);
+				return;
+			}
+
+			state_changes = state_info->last_value ^ new_state;
+			if (state_changes) {
+				SMx_POWER_INFO("SMSM Change %d: %08x->%08x\n",
+						n, state_info->last_value,
+						new_state);
+				list_for_each_entry(cb_info,
+					&state_info->callbacks, cb_list) {
+
+					if (cb_info->mask & state_changes)
+						cb_info->notify(cb_info->data,
+							state_info->last_value,
+							new_state);
+				}
+				state_info->last_value = new_state;
+			}
+		}
+
+		/* read wakelock flag */
+		ret = kfifo_out(&smsm_snapshot_fifo, &use_wakelock,
+				sizeof(use_wakelock));
+		if (ret != sizeof(use_wakelock)) {
+			pr_err("%s: snapshot underflow %d\n",
+				__func__, ret);
+			mutex_unlock(&smsm_lock);
+			return;
+		}
+		mutex_unlock(&smsm_lock);
+
+		if (use_wakelock) {
+			spin_lock_irqsave(&smsm_snapshot_count_lock, flags);
+			if (smsm_snapshot_count) {
+				--smsm_snapshot_count;
+				if (smsm_snapshot_count == 0) {
+					SMx_POWER_INFO("SMSM snapshot"
+						   " wake unlock\n");
+					wake_unlock(&smsm_snapshot_wakelock);
+				}
+			} else {
+				pr_err("%s: invalid snapshot count\n",
+						__func__);
+			}
+			spin_unlock_irqrestore(&smsm_snapshot_count_lock,
+					flags);
+		}
 	}
-	if (msm_smd_debug_mask & MSM_SMSM_DEBUG)
-		pr_info("smsm_set_sleep_duration %d -> %d\n",
-		       ptr->sleep_time, delay);
-	ptr->sleep_time = delay;
-	return 0;
 }
 
-#else
 
-int smsm_set_sleep_duration(uint32_t delay)
+/**
+ * Registers callback for SMSM state notifications when the specified
+ * bits change.
+ *
+ * @smsm_entry  Processor entry to deregister
+ * @mask        Bits to deregister (if result is 0, callback is removed)
+ * @notify      Notification function to deregister
+ * @data        Opaque data passed in to callback
+ *
+ * @returns Status code
+ *  <0 error code
+ *  0  inserted new entry
+ *  1  updated mask of existing entry
+ */
+int smsm_state_cb_register(uint32_t smsm_entry, uint32_t mask,
+		void (*notify)(void *, uint32_t, uint32_t), void *data)
 {
-	uint32_t *ptr;
+	struct smsm_state_info *state;
+	struct smsm_state_cb_info *cb_info;
+	struct smsm_state_cb_info *cb_found = 0;
+	uint32_t new_mask = 0;
+	int ret = 0;
 
-	ptr = smem_find(SMEM_SMSM_SLEEP_DELAY, sizeof(*ptr));
-	if (ptr == NULL) {
-		pr_err("smsm_set_sleep_duration <SM NO SLEEP_DELAY>\n");
-		return -EIO;
+	if (smsm_entry >= SMSM_NUM_ENTRIES)
+		return -EINVAL;
+
+	mutex_lock(&smsm_lock);
+
+	if (!smsm_states) {
+		/* smsm not yet initialized */
+		ret = -ENODEV;
+		goto cleanup;
 	}
-	if (msm_smd_debug_mask & MSM_SMSM_DEBUG)
-		pr_info("smsm_set_sleep_duration %d -> %d\n",
-		       *ptr, delay);
-	*ptr = delay;
-	return 0;
-}
 
-#endif
+	state = &smsm_states[smsm_entry];
+	list_for_each_entry(cb_info,
+			&state->callbacks, cb_list) {
+		if (!ret && (cb_info->notify == notify) &&
+				(cb_info->data == data)) {
+			cb_info->mask |= mask;
+			cb_found = cb_info;
+			ret = 1;
+		}
+		new_mask |= cb_info->mask;
+	}
+
+	if (!cb_found) {
+		cb_info = kmalloc(sizeof(struct smsm_state_cb_info),
+			GFP_ATOMIC);
+		if (!cb_info) {
+			ret = -ENOMEM;
+			goto cleanup;
+		}
+
+		cb_info->mask = mask;
+		cb_info->notify = notify;
+		cb_info->data = data;
+		INIT_LIST_HEAD(&cb_info->cb_list);
+		list_add_tail(&cb_info->cb_list,
+			&state->callbacks);
+		new_mask |= mask;
+	}
+
+	/* update interrupt notification mask */
+	if (smsm_entry == SMSM_MODEM_STATE)
+		new_mask |= LEGACY_MODEM_SMSM_MASK;
+
+	if (smsm_info.intr_mask) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&smem_lock, flags);
+		new_mask = (new_mask & ~state->intr_mask_clear)
+				| state->intr_mask_set;
+		__raw_writel(new_mask,
+				SMSM_INTR_MASK_ADDR(smsm_entry, SMSM_APPS));
+		wmb();
+		spin_unlock_irqrestore(&smem_lock, flags);
+	}
+
+cleanup:
+	mutex_unlock(&smsm_lock);
+	return ret;
+}
+EXPORT_SYMBOL(smsm_state_cb_register);
+
+
+/**
+ * Deregisters for SMSM state notifications for the specified bits.
+ *
+ * @smsm_entry  Processor entry to deregister
+ * @mask        Bits to deregister (if result is 0, callback is removed)
+ * @notify      Notification function to deregister
+ * @data        Opaque data passed in to callback
+ *
+ * @returns Status code
+ *  <0 error code
+ *  0  not found
+ *  1  updated mask
+ *  2  removed callback
+ */
+int smsm_state_cb_deregister(uint32_t smsm_entry, uint32_t mask,
+		void (*notify)(void *, uint32_t, uint32_t), void *data)
+{
+	struct smsm_state_cb_info *cb_info;
+	struct smsm_state_cb_info *cb_tmp;
+	struct smsm_state_info *state;
+	uint32_t new_mask = 0;
+	int ret = 0;
+
+	if (smsm_entry >= SMSM_NUM_ENTRIES)
+		return -EINVAL;
+
+	mutex_lock(&smsm_lock);
+
+	if (!smsm_states) {
+		/* smsm not yet initialized */
+		mutex_unlock(&smsm_lock);
+		return -ENODEV;
+	}
+
+	state = &smsm_states[smsm_entry];
+	list_for_each_entry_safe(cb_info, cb_tmp,
+		&state->callbacks, cb_list) {
+		if (!ret && (cb_info->notify == notify) &&
+			(cb_info->data == data)) {
+			cb_info->mask &= ~mask;
+			ret = 1;
+			if (!cb_info->mask) {
+				/* no mask bits set, remove callback */
+				list_del(&cb_info->cb_list);
+				kfree(cb_info);
+				ret = 2;
+				continue;
+			}
+		}
+		new_mask |= cb_info->mask;
+	}
+
+	/* update interrupt notification mask */
+	if (smsm_entry == SMSM_MODEM_STATE)
+		new_mask |= LEGACY_MODEM_SMSM_MASK;
+
+	if (smsm_info.intr_mask) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&smem_lock, flags);
+		new_mask = (new_mask & ~state->intr_mask_clear)
+				| state->intr_mask_set;
+		__raw_writel(new_mask,
+				SMSM_INTR_MASK_ADDR(smsm_entry, SMSM_APPS));
+		wmb();
+		spin_unlock_irqrestore(&smem_lock, flags);
+	}
+
+	mutex_unlock(&smsm_lock);
+	return ret;
+}
+EXPORT_SYMBOL(smsm_state_cb_deregister);
+
+int smsm_driver_state_notifier_register(struct notifier_block *nb)
+{
+	int ret;
+	if (!nb)
+		return -EINVAL;
+	mutex_lock(&smsm_driver_state_notifier_lock);
+	ret = raw_notifier_chain_register(&smsm_driver_state_notifier_list, nb);
+	mutex_unlock(&smsm_driver_state_notifier_lock);
+	return ret;
+}
+EXPORT_SYMBOL(smsm_driver_state_notifier_register);
+
+int smsm_driver_state_notifier_unregister(struct notifier_block *nb)
+{
+	int ret;
+	if (!nb)
+		return -EINVAL;
+	mutex_lock(&smsm_driver_state_notifier_lock);
+	ret = raw_notifier_chain_unregister(&smsm_driver_state_notifier_list,
+					    nb);
+	mutex_unlock(&smsm_driver_state_notifier_lock);
+	return ret;
+}
+EXPORT_SYMBOL(smsm_driver_state_notifier_unregister);
+
+static void smsm_driver_state_notify(uint32_t state, void *data)
+{
+	mutex_lock(&smsm_driver_state_notifier_lock);
+	raw_notifier_call_chain(&smsm_driver_state_notifier_list,
+				state, data);
+	mutex_unlock(&smsm_driver_state_notifier_lock);
+}
 
 int smd_core_init(void)
 {
 	int r;
-
-	/* wait for essential items to be initialized */
-	for (;;) {
-		unsigned size;
-		void *state;
-		state = smem_item(SMEM_SMSM_SHARED_STATE, &size);
-		if (size == SMSM_V1_SIZE || size == SMSM_V2_SIZE) {
-			smd_info.state = (unsigned)state;
-			break;
-		}
-	}
-
-	smd_info.ready = 1;
+	unsigned long flags = IRQF_TRIGGER_RISING;
+	SMD_INFO("smd_core_init()\n");
 
 	r = request_irq(INT_A9_M2A_0, smd_modem_irq_handler,
-			IRQF_TRIGGER_RISING, "smd_dev", 0);
+			flags, "smd_dev", 0);
 	if (r < 0)
 		return r;
 	r = enable_irq_wake(INT_A9_M2A_0);
 	if (r < 0)
-		pr_err("smd_core_init: enable_irq_wake failed for A9_M2A_0\n");
+		pr_err("smd_core_init: "
+		       "enable_irq_wake failed for INT_A9_M2A_0\n");
 
-	r = request_irq(INT_A9_M2A_5, smsm_irq_handler,
-			IRQF_TRIGGER_RISING, "smsm_dev", 0);
+	r = request_irq(INT_A9_M2A_5, smsm_modem_irq_handler,
+			flags, "smsm_dev", 0);
 	if (r < 0) {
 		free_irq(INT_A9_M2A_0, 0);
 		return r;
 	}
 	r = enable_irq_wake(INT_A9_M2A_5);
 	if (r < 0)
-		pr_err("smd_core_init: enable_irq_wake failed for A9_M2A_5\n");
+		pr_err("smd_core_init: "
+		       "enable_irq_wake failed for INT_A9_M2A_5\n");
 
 #if defined(CONFIG_QDSP6)
+#if (INT_ADSP_A11 == INT_ADSP_A11_SMSM)
+		flags |= IRQF_SHARED;
+#endif
 	r = request_irq(INT_ADSP_A11, smd_dsp_irq_handler,
-			IRQF_TRIGGER_RISING, "smd_dsp", 0);
+			flags, "smd_dev", smd_dsp_irq_handler);
 	if (r < 0) {
 		free_irq(INT_A9_M2A_0, 0);
 		free_irq(INT_A9_M2A_5, 0);
 		return r;
 	}
+
+	r = request_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler,
+			flags, "smsm_dev", smsm_dsp_irq_handler);
+	if (r < 0) {
+		free_irq(INT_A9_M2A_0, 0);
+		free_irq(INT_A9_M2A_5, 0);
+		free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
+		return r;
+	}
+
+	r = enable_irq_wake(INT_ADSP_A11);
+	if (r < 0)
+		pr_err("smd_core_init: "
+		       "enable_irq_wake failed for INT_ADSP_A11\n");
+
+#if (INT_ADSP_A11 != INT_ADSP_A11_SMSM)
+	r = enable_irq_wake(INT_ADSP_A11_SMSM);
+	if (r < 0)
+		pr_err("smd_core_init: enable_irq_wake "
+		       "failed for INT_ADSP_A11_SMSM\n");
+#endif
+	flags &= ~IRQF_SHARED;
 #endif
 
-	/* check for any SMD channels that may already exist */
-	do_smd_probe();
+#if defined(CONFIG_DSPS)
+	r = request_irq(INT_DSPS_A11, smd_dsps_irq_handler,
+			flags, "smd_dev", smd_dsps_irq_handler);
+	if (r < 0) {
+		free_irq(INT_A9_M2A_0, 0);
+		free_irq(INT_A9_M2A_5, 0);
+		free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
+		free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler);
+		return r;
+	}
 
-	/* indicate that we're up and running */
-	smsm_change_state(SMSM_STATE_APPS,
-			  ~0, SMSM_INIT | SMSM_SMDINIT | SMSM_RPCINIT | SMSM_RUN);
-#ifdef CONFIG_ARCH_MSM_SCORPION
-	smsm_change_state(SMSM_STATE_APPS_DEM, ~0, 0);
+	r = enable_irq_wake(INT_DSPS_A11);
+	if (r < 0)
+		pr_err("smd_core_init: "
+		       "enable_irq_wake failed for INT_ADSP_A11\n");
 #endif
 
+#if defined(CONFIG_WCNSS)
+	r = request_irq(INT_WCNSS_A11, smd_wcnss_irq_handler,
+			flags, "smd_dev", smd_wcnss_irq_handler);
+	if (r < 0) {
+		free_irq(INT_A9_M2A_0, 0);
+		free_irq(INT_A9_M2A_5, 0);
+		free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
+		free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler);
+		free_irq(INT_DSPS_A11, smd_dsps_irq_handler);
+		return r;
+	}
+
+	r = enable_irq_wake(INT_WCNSS_A11);
+	if (r < 0)
+		pr_err("smd_core_init: "
+		       "enable_irq_wake failed for INT_WCNSS_A11\n");
+
+	r = request_irq(INT_WCNSS_A11_SMSM, smsm_wcnss_irq_handler,
+			flags, "smsm_dev", smsm_wcnss_irq_handler);
+	if (r < 0) {
+		free_irq(INT_A9_M2A_0, 0);
+		free_irq(INT_A9_M2A_5, 0);
+		free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
+		free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler);
+		free_irq(INT_DSPS_A11, smd_dsps_irq_handler);
+		free_irq(INT_WCNSS_A11, smd_wcnss_irq_handler);
+		return r;
+	}
+
+	r = enable_irq_wake(INT_WCNSS_A11_SMSM);
+	if (r < 0)
+		pr_err("smd_core_init: "
+		       "enable_irq_wake failed for INT_WCNSS_A11_SMSM\n");
+#endif
+
+#if defined(CONFIG_DSPS_SMSM)
+	r = request_irq(INT_DSPS_A11_SMSM, smsm_dsps_irq_handler,
+			flags, "smsm_dev", smsm_dsps_irq_handler);
+	if (r < 0) {
+		free_irq(INT_A9_M2A_0, 0);
+		free_irq(INT_A9_M2A_5, 0);
+		free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
+		free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler);
+		free_irq(INT_DSPS_A11, smd_dsps_irq_handler);
+		free_irq(INT_WCNSS_A11, smd_wcnss_irq_handler);
+		free_irq(INT_WCNSS_A11_SMSM, smsm_wcnss_irq_handler);
+		return r;
+	}
+
+	r = enable_irq_wake(INT_DSPS_A11_SMSM);
+	if (r < 0)
+		pr_err("smd_core_init: "
+		       "enable_irq_wake failed for INT_DSPS_A11_SMSM\n");
+#endif
+	SMD_INFO("smd_core_init() done\n");
+
 	return 0;
 }
 
+static int intr_init(struct interrupt_config_item *private_irq,
+			struct smd_irq_config *platform_irq,
+			struct platform_device *pdev
+			)
+{
+	int irq_id;
+	int ret;
+	int ret_wake;
+
+	private_irq->out_bit_pos = platform_irq->out_bit_pos;
+	private_irq->out_offset = platform_irq->out_offset;
+	private_irq->out_base = platform_irq->out_base;
+
+	irq_id = platform_get_irq_byname(
+					pdev,
+					platform_irq->irq_name
+				);
+	SMD_DBG("smd: %s: register irq: %s id: %d\n", __func__,
+				platform_irq->irq_name, irq_id);
+	ret = request_irq(irq_id,
+				private_irq->irq_handler,
+				platform_irq->flags,
+				platform_irq->device_name,
+				(void *)platform_irq->dev_id
+			);
+	if (ret < 0) {
+		platform_irq->irq_id = ret;
+	} else {
+		platform_irq->irq_id = irq_id;
+		ret_wake = enable_irq_wake(irq_id);
+		if (ret_wake < 0) {
+			pr_err("smd: enable_irq_wake failed on %s",
+					platform_irq->irq_name);
+		}
+	}
+
+	return ret;
+}
+
+int sort_cmp_func(const void *a, const void *b)
+{
+	struct smem_area *left = (struct smem_area *)(a);
+	struct smem_area *right = (struct smem_area *)(b);
+
+	return left->phys_addr - right->phys_addr;
+}
+
+int smd_core_platform_init(struct platform_device *pdev)
+{
+	int i;
+	int ret;
+	uint32_t num_ss;
+	struct smd_platform *smd_platform_data;
+	struct smd_subsystem_config *smd_ss_config_list;
+	struct smd_subsystem_config *cfg;
+	int err_ret = 0;
+	struct smd_smem_regions *smd_smem_areas;
+	int smem_idx = 0;
+
+	smd_platform_data = pdev->dev.platform_data;
+	num_ss = smd_platform_data->num_ss_configs;
+	smd_ss_config_list = smd_platform_data->smd_ss_configs;
+
+	if (smd_platform_data->smd_ssr_config)
+		disable_smsm_reset_handshake = smd_platform_data->
+			   smd_ssr_config->disable_smsm_reset_handshake;
+
+	smd_smem_areas = smd_platform_data->smd_smem_areas;
+	if (smd_smem_areas) {
+		num_smem_areas = smd_platform_data->num_smem_areas;
+		smem_areas = kmalloc(sizeof(struct smem_area) * num_smem_areas,
+						GFP_KERNEL);
+		if (!smem_areas) {
+			pr_err("%s: smem_areas kmalloc failed\n", __func__);
+			err_ret = -ENOMEM;
+			goto smem_areas_alloc_fail;
+		}
+
+		for (smem_idx = 0; smem_idx < num_smem_areas; ++smem_idx) {
+			smem_areas[smem_idx].phys_addr =
+					smd_smem_areas[smem_idx].phys_addr;
+			smem_areas[smem_idx].size =
+					smd_smem_areas[smem_idx].size;
+			smem_areas[smem_idx].virt_addr = ioremap_nocache(
+				(unsigned long)(smem_areas[smem_idx].phys_addr),
+				smem_areas[smem_idx].size);
+			if (!smem_areas[smem_idx].virt_addr) {
+				pr_err("%s: ioremap_nocache() of addr:%p"
+					" size: %x\n", __func__,
+					smem_areas[smem_idx].phys_addr,
+					smem_areas[smem_idx].size);
+				err_ret = -ENOMEM;
+				++smem_idx;
+				goto smem_failed;
+			}
+		}
+		sort(smem_areas, num_smem_areas,
+				sizeof(struct smem_area),
+				sort_cmp_func, NULL);
+	}
+
+	for (i = 0; i < num_ss; i++) {
+		cfg = &smd_ss_config_list[i];
+
+		ret = intr_init(
+			&private_intr_config[cfg->irq_config_id].smd,
+			&cfg->smd_int,
+			pdev
+			);
+
+		if (ret < 0) {
+			err_ret = ret;
+			pr_err("smd: register irq failed on %s\n",
+				cfg->smd_int.irq_name);
+			goto intr_failed;
+		}
+
+		/* only init smsm structs if this edge supports smsm */
+		if (cfg->smsm_int.irq_id)
+			ret = intr_init(
+				&private_intr_config[cfg->irq_config_id].smsm,
+				&cfg->smsm_int,
+				pdev
+				);
+
+		if (ret < 0) {
+			err_ret = ret;
+			pr_err("smd: register irq failed on %s\n",
+				cfg->smsm_int.irq_name);
+			goto intr_failed;
+		}
+
+		if (cfg->subsys_name)
+			strlcpy(edge_to_pids[cfg->edge].subsys_name,
+				cfg->subsys_name, SMD_MAX_CH_NAME_LEN);
+	}
+
+
+	SMD_INFO("smd_core_platform_init() done\n");
+	return 0;
+
+intr_failed:
+	pr_err("smd: deregistering IRQs\n");
+	for (i = 0; i < num_ss; ++i) {
+		cfg = &smd_ss_config_list[i];
+
+		if (cfg->smd_int.irq_id >= 0)
+			free_irq(cfg->smd_int.irq_id,
+				(void *)cfg->smd_int.dev_id
+				);
+		if (cfg->smsm_int.irq_id >= 0)
+			free_irq(cfg->smsm_int.irq_id,
+				(void *)cfg->smsm_int.dev_id
+				);
+	}
+smem_failed:
+	for (smem_idx = smem_idx - 1; smem_idx >= 0; --smem_idx)
+		iounmap(smem_areas[smem_idx].virt_addr);
+	kfree(smem_areas);
+smem_areas_alloc_fail:
+	return err_ret;
+}
+
 static int __devinit msm_smd_probe(struct platform_device *pdev)
 {
-	/*
-	 * If we haven't waited for the ARM9 to boot up till now,
-	 * then we need to wait here. Otherwise this should just
-	 * return immediately.
-	 */
-	proc_comm_boot_wait();
+	int ret;
 
+	SMD_INFO("smd probe\n");
 	INIT_WORK(&probe_work, smd_channel_probe_worker);
 
-	if (smd_core_init()) {
-		pr_err("smd_core_init() failed\n");
+	channel_close_wq = create_singlethread_workqueue("smd_channel_close");
+	if (IS_ERR(channel_close_wq)) {
+		pr_err("%s: create_singlethread_workqueue ENOMEM\n", __func__);
+		return -ENOMEM;
+	}
+
+	if (smsm_init()) {
+		pr_err("smsm_init() failed\n");
 		return -1;
 	}
 
-	do_smd_probe();
-
-	msm_check_for_modem_crash = check_for_modem_crash;
-
-	msm_init_last_radio_log(THIS_MODULE);
+	if (pdev) {
+		if (pdev->dev.of_node) {
+			pr_err("SMD: Device tree not currently supported\n");
+			return -ENODEV;
+		} else if (pdev->dev.platform_data) {
+			ret = smd_core_platform_init(pdev);
+			if (ret) {
+				pr_err(
+				"SMD: smd_core_platform_init() failed\n");
+				return -ENODEV;
+			}
+		} else {
+			ret = smd_core_init();
+			if (ret) {
+				pr_err("smd_core_init() failed\n");
+				return -ENODEV;
+			}
+		}
+	} else {
+		pr_err("SMD: PDEV not found\n");
+		return -ENODEV;
+	}
 
 	smd_initialized = 1;
 
+	smd_alloc_loopback_channel();
+	smsm_irq_handler(0, 0);
+	tasklet_schedule(&smd_fake_irq_tasklet);
+
 	return 0;
 }
 
+static int restart_notifier_cb(struct notifier_block *this,
+				  unsigned long code,
+				  void *data);
+
+static struct restart_notifier_block restart_notifiers[] = {
+	{SMD_MODEM, "modem", .nb.notifier_call = restart_notifier_cb},
+	{SMD_Q6, "lpass", .nb.notifier_call = restart_notifier_cb},
+	{SMD_WCNSS, "riva", .nb.notifier_call = restart_notifier_cb},
+	{SMD_DSPS, "dsps", .nb.notifier_call = restart_notifier_cb},
+	{SMD_MODEM, "gss", .nb.notifier_call = restart_notifier_cb},
+};
+
+static int restart_notifier_cb(struct notifier_block *this,
+				  unsigned long code,
+				  void *data)
+{
+	if (code == SUBSYS_AFTER_SHUTDOWN) {
+		struct restart_notifier_block *notifier;
+
+		notifier = container_of(this,
+				struct restart_notifier_block, nb);
+		SMD_INFO("%s: ssrestart for processor %d ('%s')\n",
+				__func__, notifier->processor,
+				notifier->name);
+
+		smd_channel_reset(notifier->processor);
+	}
+
+	return NOTIFY_DONE;
+}
+
+static __init int modem_restart_late_init(void)
+{
+	int i;
+	void *handle;
+	struct restart_notifier_block *nb;
+
+	for (i = 0; i < ARRAY_SIZE(restart_notifiers); i++) {
+		nb = &restart_notifiers[i];
+		handle = subsys_notif_register_notifier(nb->name, &nb->nb);
+		SMD_DBG("%s: registering notif for '%s', handle=%p\n",
+				__func__, nb->name, handle);
+	}
+	return 0;
+}
+late_initcall(modem_restart_late_init);
+
 static struct platform_driver msm_smd_driver = {
 	.probe = msm_smd_probe,
 	.driver = {
@@ -1029,8 +3483,14 @@
 	},
 };
 
-static int __init msm_smd_init(void)
+int __init msm_smd_init(void)
 {
+	static bool registered;
+
+	if (registered)
+		return 0;
+
+	registered = true;
 	return platform_driver_register(&msm_smd_driver);
 }
 
diff --git a/arch/arm/mach-msm/smd_debug.c b/arch/arm/mach-msm/smd_debug.c
index c56df9e..d64bcf2 100644
--- a/arch/arm/mach-msm/smd_debug.c
+++ b/arch/arm/mach-msm/smd_debug.c
@@ -1,6 +1,7 @@
 /* arch/arm/mach-msm/smd_debug.c
  *
  * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -16,6 +17,8 @@
 
 #include <linux/debugfs.h>
 #include <linux/list.h>
+#include <linux/ctype.h>
+#include <linux/jiffies.h>
 
 #include <mach/msm_iomap.h>
 
@@ -45,60 +48,198 @@
 	}
 }
 
-
-static int dump_ch(char *buf, int max, struct smd_channel *ch)
+static int debug_f3(char *buf, int max)
 {
-	volatile struct smd_half_channel *s = ch->send;
-	volatile struct smd_half_channel *r = ch->recv;
+	char *x;
+	int size;
+	int i = 0, j = 0;
+	unsigned cols = 0;
+	char str[4*sizeof(unsigned)+1] = {0};
 
-	return scnprintf(
-		buf, max,
-		"ch%02d:"
-		" %8s(%05d/%05d) %c%c%c%c%c%c%c <->"
-		" %8s(%05d/%05d) %c%c%c%c%c%c%c '%s'\n", ch->n,
-		chstate(s->state), s->tail, s->head,
-		s->fDSR ? 'D' : 'd',
-		s->fCTS ? 'C' : 'c',
-		s->fCD ? 'C' : 'c',
-		s->fRI ? 'I' : 'i',
-		s->fHEAD ? 'W' : 'w',
-		s->fTAIL ? 'R' : 'r',
-		s->fSTATE ? 'S' : 's',
-		chstate(r->state), r->tail, r->head,
-		r->fDSR ? 'D' : 'd',
-		r->fCTS ? 'R' : 'r',
-		r->fCD ? 'C' : 'c',
-		r->fRI ? 'I' : 'i',
-		r->fHEAD ? 'W' : 'w',
-		r->fTAIL ? 'R' : 'r',
-		r->fSTATE ? 'S' : 's',
-		ch->name
-		);
+	i += scnprintf(buf + i, max - i,
+		       "Printing to log\n");
+
+	x = smem_get_entry(SMEM_ERR_F3_TRACE_LOG, &size);
+	if (x != 0) {
+		pr_info("smem: F3 TRACE LOG\n");
+		while (size > 0) {
+			if (size >= sizeof(unsigned)) {
+				pr_info("%08x", *((unsigned *) x));
+				for (j = 0; j < sizeof(unsigned); ++j)
+					if (isprint(*(x+j)))
+						str[cols*sizeof(unsigned) + j]
+							= *(x+j);
+					else
+						str[cols*sizeof(unsigned) + j]
+							= '-';
+				x += sizeof(unsigned);
+				size -= sizeof(unsigned);
+			} else {
+				while (size-- > 0)
+					pr_info("%02x", (unsigned) *x++);
+				break;
+			}
+			if (cols == 3) {
+				cols = 0;
+				str[4*sizeof(unsigned)] = 0;
+				pr_info(" %s\n", str);
+				str[0] = 0;
+			} else {
+				cols++;
+				pr_info(" ");
+			}
+		}
+		pr_info("\n");
+	}
+
+	return max;
 }
 
-static int debug_read_stat(char *buf, int max)
+static int debug_int_stats(char *buf, int max)
+{
+	int i = 0;
+	int subsys;
+	struct interrupt_stat *stats = interrupt_stats;
+	const char *subsys_name;
+
+	i += scnprintf(buf + i, max - i,
+		"   Subsystem    |     In    | Out (Hardcoded) |"
+		" Out (Configured) |\n");
+
+	for (subsys = 0; subsys < NUM_SMD_SUBSYSTEMS; ++subsys) {
+		subsys_name = smd_pid_to_subsystem(subsys);
+		if (subsys_name) {
+			i += scnprintf(buf + i, max - i,
+				"%-10s %4s | %9u |       %9u |        %9u |\n",
+				smd_pid_to_subsystem(subsys), "smd",
+				stats->smd_in_count,
+				stats->smd_out_hardcode_count,
+				stats->smd_out_config_count);
+
+			i += scnprintf(buf + i, max - i,
+				"%-10s %4s | %9u |       %9u |        %9u |\n",
+				smd_pid_to_subsystem(subsys), "smsm",
+				stats->smsm_in_count,
+				stats->smsm_out_hardcode_count,
+				stats->smsm_out_config_count);
+		}
+		++stats;
+	}
+
+	return i;
+}
+
+static int debug_int_stats_reset(char *buf, int max)
+{
+	int i = 0;
+	int subsys;
+	struct interrupt_stat *stats = interrupt_stats;
+
+	i += scnprintf(buf + i, max - i, "Resetting interrupt stats.\n");
+
+	for (subsys = 0; subsys < NUM_SMD_SUBSYSTEMS; ++subsys) {
+		stats->smd_in_count = 0;
+		stats->smd_out_hardcode_count = 0;
+		stats->smd_out_config_count = 0;
+		stats->smsm_in_count = 0;
+		stats->smsm_out_hardcode_count = 0;
+		stats->smsm_out_config_count = 0;
+		++stats;
+	}
+
+	return i;
+}
+
+static int debug_diag(char *buf, int max)
+{
+	int i = 0;
+
+	i += scnprintf(buf + i, max - i,
+		       "Printing to log\n");
+	smd_diag();
+
+	return i;
+}
+
+static int debug_modem_err_f3(char *buf, int max)
+{
+	char *x;
+	int size;
+	int i = 0, j = 0;
+	unsigned cols = 0;
+	char str[4*sizeof(unsigned)+1] = {0};
+
+	x = smem_get_entry(SMEM_ERR_F3_TRACE_LOG, &size);
+	if (x != 0) {
+		pr_info("smem: F3 TRACE LOG\n");
+		while (size > 0 && max - i) {
+			if (size >= sizeof(unsigned)) {
+				i += scnprintf(buf + i, max - i, "%08x",
+					       *((unsigned *) x));
+				for (j = 0; j < sizeof(unsigned); ++j)
+					if (isprint(*(x+j)))
+						str[cols*sizeof(unsigned) + j]
+							= *(x+j);
+					else
+						str[cols*sizeof(unsigned) + j]
+							= '-';
+				x += sizeof(unsigned);
+				size -= sizeof(unsigned);
+			} else {
+				while (size-- > 0 && max - i)
+					i += scnprintf(buf + i, max - i,
+						       "%02x",
+						       (unsigned) *x++);
+				break;
+			}
+			if (cols == 3) {
+				cols = 0;
+				str[4*sizeof(unsigned)] = 0;
+				i += scnprintf(buf + i, max - i, " %s\n",
+					       str);
+				str[0] = 0;
+			} else {
+				cols++;
+				i += scnprintf(buf + i, max - i, " ");
+			}
+		}
+		i += scnprintf(buf + i, max - i, "\n");
+	}
+
+	return i;
+}
+
+static int debug_modem_err(char *buf, int max)
+{
+	char *x;
+	int size;
+	int i = 0;
+
+	x = smem_find(ID_DIAG_ERR_MSG, SZ_DIAG_ERR_MSG);
+	if (x != 0) {
+		x[SZ_DIAG_ERR_MSG - 1] = 0;
+		i += scnprintf(buf + i, max - i,
+			       "smem: DIAG '%s'\n", x);
+	}
+
+	x = smem_get_entry(SMEM_ERR_CRASH_LOG, &size);
+	if (x != 0) {
+		x[size - 1] = 0;
+		i += scnprintf(buf + i, max - i,
+			       "smem: CRASH LOG\n'%s'\n", x);
+	}
+	i += scnprintf(buf + i, max - i, "\n");
+
+	return i;
+}
+
+static int debug_read_diag_msg(char *buf, int max)
 {
 	char *msg;
 	int i = 0;
 
 	msg = smem_find(ID_DIAG_ERR_MSG, SZ_DIAG_ERR_MSG);
 
-	if (raw_smsm_get_state(SMSM_STATE_MODEM) & SMSM_RESET)
-		i += scnprintf(buf + i, max - i,
-			       "smsm: ARM9 HAS CRASHED\n");
-
-	i += scnprintf(buf + i, max - i, "smsm: a9: %08x a11: %08x\n",
-		       raw_smsm_get_state(SMSM_STATE_MODEM),
-		       raw_smsm_get_state(SMSM_STATE_APPS));
-#ifdef CONFIG_ARCH_MSM_SCORPION
-	i += scnprintf(buf + i, max - i, "smsm dem: apps: %08x modem: %08x "
-		       "qdsp6: %08x power: %08x time: %08x\n",
-		       raw_smsm_get_state(SMSM_STATE_APPS_DEM),
-		       raw_smsm_get_state(SMSM_STATE_MODEM_DEM),
-		       raw_smsm_get_state(SMSM_STATE_QDSP6_DEM),
-		       raw_smsm_get_state(SMSM_STATE_POWER_MASTER_DEM),
-		       raw_smsm_get_state(SMSM_STATE_TIME_MASTER_DEM));
-#endif
 	if (msg) {
 		msg[SZ_DIAG_ERR_MSG - 1] = 0;
 		i += scnprintf(buf + i, max - i, "diag: '%s'\n", msg);
@@ -106,6 +247,278 @@
 	return i;
 }
 
+static int dump_ch(char *buf, int max, int n,
+		   void *half_ch_s,
+		   void *half_ch_r,
+		   struct smd_half_channel_access *half_ch_funcs,
+		   unsigned size)
+{
+	return scnprintf(
+		buf, max,
+		"ch%02d:"
+		" %8s(%04d/%04d) %c%c%c%c%c%c%c%c <->"
+		" %8s(%04d/%04d) %c%c%c%c%c%c%c%c : %5x\n", n,
+		chstate(half_ch_funcs->get_state(half_ch_s)),
+		half_ch_funcs->get_tail(half_ch_s),
+		half_ch_funcs->get_head(half_ch_s),
+		half_ch_funcs->get_fDSR(half_ch_s) ? 'D' : 'd',
+		half_ch_funcs->get_fCTS(half_ch_s) ? 'C' : 'c',
+		half_ch_funcs->get_fCD(half_ch_s) ? 'C' : 'c',
+		half_ch_funcs->get_fRI(half_ch_s) ? 'I' : 'i',
+		half_ch_funcs->get_fHEAD(half_ch_s) ? 'W' : 'w',
+		half_ch_funcs->get_fTAIL(half_ch_s) ? 'R' : 'r',
+		half_ch_funcs->get_fSTATE(half_ch_s) ? 'S' : 's',
+		half_ch_funcs->get_fBLOCKREADINTR(half_ch_s) ? 'B' : 'b',
+		chstate(half_ch_funcs->get_state(half_ch_r)),
+		half_ch_funcs->get_tail(half_ch_r),
+		half_ch_funcs->get_head(half_ch_r),
+		half_ch_funcs->get_fDSR(half_ch_r) ? 'D' : 'd',
+		half_ch_funcs->get_fCTS(half_ch_r) ? 'C' : 'c',
+		half_ch_funcs->get_fCD(half_ch_r) ? 'C' : 'c',
+		half_ch_funcs->get_fRI(half_ch_r) ? 'I' : 'i',
+		half_ch_funcs->get_fHEAD(half_ch_r) ? 'W' : 'w',
+		half_ch_funcs->get_fTAIL(half_ch_r) ? 'R' : 'r',
+		half_ch_funcs->get_fSTATE(half_ch_r) ? 'S' : 's',
+		half_ch_funcs->get_fBLOCKREADINTR(half_ch_r) ? 'B' : 'b',
+		size
+		);
+}
+
+static int debug_read_smsm_state(char *buf, int max)
+{
+	uint32_t *smsm;
+	int n, i = 0;
+
+	smsm = smem_find(ID_SHARED_STATE,
+			 SMSM_NUM_ENTRIES * sizeof(uint32_t));
+
+	if (smsm)
+		for (n = 0; n < SMSM_NUM_ENTRIES; n++)
+			i += scnprintf(buf + i, max - i, "entry %d: 0x%08x\n",
+				       n, smsm[n]);
+
+	return i;
+}
+
+struct SMSM_CB_DATA {
+	int cb_count;
+	void *data;
+	uint32_t old_state;
+	uint32_t new_state;
+};
+static struct SMSM_CB_DATA smsm_cb_data;
+static struct completion smsm_cb_completion;
+
+static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
+{
+	smsm_cb_data.cb_count++;
+	smsm_cb_data.old_state = old_state;
+	smsm_cb_data.new_state = new_state;
+	smsm_cb_data.data = data;
+	complete_all(&smsm_cb_completion);
+}
+
+#define UT_EQ_INT(a, b) \
+	if ((a) != (b)) { \
+		i += scnprintf(buf + i, max - i, \
+			"%s:%d " #a "(%d) != " #b "(%d)\n", \
+				__func__, __LINE__, \
+				a, b); \
+		break; \
+	} \
+	do {} while (0)
+
+#define UT_GT_INT(a, b) \
+	if ((a) <= (b)) { \
+		i += scnprintf(buf + i, max - i, \
+			"%s:%d " #a "(%d) > " #b "(%d)\n", \
+				__func__, __LINE__, \
+				a, b); \
+		break; \
+	} \
+	do {} while (0)
+
+#define SMSM_CB_TEST_INIT() \
+	do { \
+		smsm_cb_data.cb_count = 0; \
+		smsm_cb_data.old_state = 0; \
+		smsm_cb_data.new_state = 0; \
+		smsm_cb_data.data = 0; \
+	} while (0)
+
+
+static int debug_test_smsm(char *buf, int max)
+{
+	int i = 0;
+	int test_num = 0;
+	int ret;
+
+	/* Test case 1 - Register new callback for notification */
+	do {
+		test_num++;
+		SMSM_CB_TEST_INIT();
+		ret = smsm_state_cb_register(SMSM_APPS_STATE, SMSM_SMDINIT,
+				smsm_state_cb, (void *)0x1234);
+		UT_EQ_INT(ret, 0);
+
+		/* de-assert SMSM_SMD_INIT to trigger state update */
+		UT_EQ_INT(smsm_cb_data.cb_count, 0);
+		INIT_COMPLETION(smsm_cb_completion);
+		smsm_change_state(SMSM_APPS_STATE, SMSM_SMDINIT, 0x0);
+		UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
+
+		UT_EQ_INT(smsm_cb_data.cb_count, 1);
+		UT_EQ_INT(smsm_cb_data.old_state & SMSM_SMDINIT, SMSM_SMDINIT);
+		UT_EQ_INT(smsm_cb_data.new_state & SMSM_SMDINIT, 0x0);
+		UT_EQ_INT((int)smsm_cb_data.data, 0x1234);
+
+		/* re-assert SMSM_SMD_INIT to trigger state update */
+		INIT_COMPLETION(smsm_cb_completion);
+		smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_SMDINIT);
+		UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
+		UT_EQ_INT(smsm_cb_data.cb_count, 2);
+		UT_EQ_INT(smsm_cb_data.old_state & SMSM_SMDINIT, 0x0);
+		UT_EQ_INT(smsm_cb_data.new_state & SMSM_SMDINIT, SMSM_SMDINIT);
+
+		/* deregister callback */
+		ret = smsm_state_cb_deregister(SMSM_APPS_STATE, SMSM_SMDINIT,
+				smsm_state_cb, (void *)0x1234);
+		UT_EQ_INT(ret, 2);
+
+		/* make sure state change doesn't cause any more callbacks */
+		INIT_COMPLETION(smsm_cb_completion);
+		smsm_change_state(SMSM_APPS_STATE, SMSM_SMDINIT, 0x0);
+		smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_SMDINIT);
+		UT_EQ_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
+		UT_EQ_INT(smsm_cb_data.cb_count, 2);
+
+		i += scnprintf(buf + i, max - i, "Test %d - PASS\n", test_num);
+	} while (0);
+
+	/* Test case 2 - Update already registered callback */
+	do {
+		test_num++;
+		SMSM_CB_TEST_INIT();
+		ret = smsm_state_cb_register(SMSM_APPS_STATE, SMSM_SMDINIT,
+				smsm_state_cb, (void *)0x1234);
+		UT_EQ_INT(ret, 0);
+		ret = smsm_state_cb_register(SMSM_APPS_STATE, SMSM_INIT,
+				smsm_state_cb, (void *)0x1234);
+		UT_EQ_INT(ret, 1);
+
+		/* verify both callback bits work */
+		INIT_COMPLETION(smsm_cb_completion);
+		UT_EQ_INT(smsm_cb_data.cb_count, 0);
+		smsm_change_state(SMSM_APPS_STATE, SMSM_SMDINIT, 0x0);
+		UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
+		UT_EQ_INT(smsm_cb_data.cb_count, 1);
+		INIT_COMPLETION(smsm_cb_completion);
+		smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_SMDINIT);
+		UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
+		UT_EQ_INT(smsm_cb_data.cb_count, 2);
+
+		INIT_COMPLETION(smsm_cb_completion);
+		smsm_change_state(SMSM_APPS_STATE, SMSM_INIT, 0x0);
+		UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
+		UT_EQ_INT(smsm_cb_data.cb_count, 3);
+		INIT_COMPLETION(smsm_cb_completion);
+		smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_INIT);
+		UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
+		UT_EQ_INT(smsm_cb_data.cb_count, 4);
+
+		/* deregister 1st callback */
+		ret = smsm_state_cb_deregister(SMSM_APPS_STATE, SMSM_SMDINIT,
+				smsm_state_cb, (void *)0x1234);
+		UT_EQ_INT(ret, 1);
+		INIT_COMPLETION(smsm_cb_completion);
+		smsm_change_state(SMSM_APPS_STATE, SMSM_SMDINIT, 0x0);
+		smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_SMDINIT);
+		UT_EQ_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
+		UT_EQ_INT(smsm_cb_data.cb_count, 4);
+
+		INIT_COMPLETION(smsm_cb_completion);
+		smsm_change_state(SMSM_APPS_STATE, SMSM_INIT, 0x0);
+		UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
+		UT_EQ_INT(smsm_cb_data.cb_count, 5);
+		INIT_COMPLETION(smsm_cb_completion);
+		smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_INIT);
+		UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
+		UT_EQ_INT(smsm_cb_data.cb_count, 6);
+
+		/* deregister 2nd callback */
+		ret = smsm_state_cb_deregister(SMSM_APPS_STATE, SMSM_INIT,
+				smsm_state_cb, (void *)0x1234);
+		UT_EQ_INT(ret, 2);
+
+		/* make sure state change doesn't cause any more callbacks */
+		INIT_COMPLETION(smsm_cb_completion);
+		smsm_change_state(SMSM_APPS_STATE, SMSM_INIT, 0x0);
+		smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_INIT);
+		UT_EQ_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
+		UT_EQ_INT(smsm_cb_data.cb_count, 6);
+
+		i += scnprintf(buf + i, max - i, "Test %d - PASS\n", test_num);
+	} while (0);
+
+	/* Test case 3 - Two callback registrations with different data */
+	do {
+		test_num++;
+		SMSM_CB_TEST_INIT();
+		ret = smsm_state_cb_register(SMSM_APPS_STATE, SMSM_SMDINIT,
+				smsm_state_cb, (void *)0x1234);
+		UT_EQ_INT(ret, 0);
+		ret = smsm_state_cb_register(SMSM_APPS_STATE, SMSM_INIT,
+				smsm_state_cb, (void *)0x3456);
+		UT_EQ_INT(ret, 0);
+
+		/* verify both callbacks work */
+		INIT_COMPLETION(smsm_cb_completion);
+		UT_EQ_INT(smsm_cb_data.cb_count, 0);
+		smsm_change_state(SMSM_APPS_STATE, SMSM_SMDINIT, 0x0);
+		UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
+		UT_EQ_INT(smsm_cb_data.cb_count, 1);
+		UT_EQ_INT((int)smsm_cb_data.data, 0x1234);
+
+		INIT_COMPLETION(smsm_cb_completion);
+		smsm_change_state(SMSM_APPS_STATE, SMSM_INIT, 0x0);
+		UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
+		UT_EQ_INT(smsm_cb_data.cb_count, 2);
+		UT_EQ_INT((int)smsm_cb_data.data, 0x3456);
+
+		/* cleanup and unregister
+		 * degregister in reverse to verify data field is
+		 * being used
+		 */
+		smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_SMDINIT);
+		smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_INIT);
+		ret = smsm_state_cb_deregister(SMSM_APPS_STATE,
+				SMSM_INIT,
+				smsm_state_cb, (void *)0x3456);
+		UT_EQ_INT(ret, 2);
+		ret = smsm_state_cb_deregister(SMSM_APPS_STATE,
+				SMSM_SMDINIT,
+				smsm_state_cb, (void *)0x1234);
+		UT_EQ_INT(ret, 2);
+
+		i += scnprintf(buf + i, max - i, "Test %d - PASS\n", test_num);
+	} while (0);
+
+	return i;
+}
+
 static int debug_read_mem(char *buf, int max)
 {
 	unsigned n;
@@ -129,29 +542,117 @@
 	return i;
 }
 
+#if (!defined(CONFIG_MSM_SMD_PKG4) && !defined(CONFIG_MSM_SMD_PKG3))
 static int debug_read_ch(char *buf, int max)
 {
-	struct smd_channel *ch;
-	unsigned long flags;
-	int i = 0;
+	void *shared;
+	int n, i = 0;
+	struct smd_alloc_elm *ch_tbl;
+	unsigned ch_type;
+	unsigned shared_size;
 
-	spin_lock_irqsave(&smd_lock, flags);
-	list_for_each_entry(ch, &smd_ch_list_dsp, ch_list)
-		i += dump_ch(buf + i, max - i, ch);
-	list_for_each_entry(ch, &smd_ch_list_modem, ch_list)
-		i += dump_ch(buf + i, max - i, ch);
-	list_for_each_entry(ch, &smd_ch_closed_list, ch_list)
-		i += dump_ch(buf + i, max - i, ch);
-	spin_unlock_irqrestore(&smd_lock, flags);
+	ch_tbl = smem_find(ID_CH_ALLOC_TBL, sizeof(*ch_tbl) * 64);
+	if (!ch_tbl)
+		goto fail;
+
+	for (n = 0; n < SMD_CHANNELS; n++) {
+		ch_type = SMD_CHANNEL_TYPE(ch_tbl[n].type);
+		if (is_word_access_ch(ch_type))
+			shared_size =
+				sizeof(struct smd_half_channel_word_access);
+		else
+			shared_size = sizeof(struct smd_half_channel);
+		shared = smem_find(ID_SMD_CHANNELS + n,
+				2 * shared_size + SMD_BUF_SIZE);
+
+		if (shared == 0)
+			continue;
+		i += dump_ch(buf + i, max - i, n, shared,
+			     (shared + shared_size +
+			     SMD_BUF_SIZE), get_half_ch_funcs(ch_type),
+			     SMD_BUF_SIZE);
+	}
+
+fail:
+	return i;
+}
+#else
+static int debug_read_ch(char *buf, int max)
+{
+	void *shared, *buffer;
+	unsigned buffer_sz;
+	int n, i = 0;
+	struct smd_alloc_elm *ch_tbl;
+	unsigned ch_type;
+	unsigned shared_size;
+
+	ch_tbl = smem_find(ID_CH_ALLOC_TBL, sizeof(*ch_tbl) * 64);
+	if (!ch_tbl)
+		goto fail;
+
+	for (n = 0; n < SMD_CHANNELS; n++) {
+		ch_type = SMD_CHANNEL_TYPE(ch_tbl[n].type);
+		if (is_word_access_ch(ch_type))
+			shared_size =
+				sizeof(struct smd_half_channel_word_access);
+		else
+			shared_size = sizeof(struct smd_half_channel);
+
+		shared = smem_find(ID_SMD_CHANNELS + n, 2 * shared_size);
+
+		if (shared == 0)
+			continue;
+
+		buffer = smem_get_entry(SMEM_SMD_FIFO_BASE_ID + n, &buffer_sz);
+
+		if (buffer == 0)
+			continue;
+
+		i += dump_ch(buf + i, max - i, n, shared,
+			     (shared + shared_size),
+			     get_half_ch_funcs(ch_type),
+			     buffer_sz / 2);
+	}
+
+fail:
+	return i;
+}
+#endif
+
+static int debug_read_smem_version(char *buf, int max)
+{
+	struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
+	uint32_t n, version, i = 0;
+
+	for (n = 0; n < 32; n++) {
+		version = shared->version[n];
+		i += scnprintf(buf + i, max - i,
+			       "entry %d: smem = %d  proc_comm = %d\n", n,
+			       version >> 16,
+			       version & 0xffff);
+	}
 
 	return i;
 }
 
-static int debug_read_version(char *buf, int max)
+/* NNV: revist, it may not be smd version */
+static int debug_read_smd_version(char *buf, int max)
 {
-	struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
-	unsigned version = shared->version[VERSION_MODEM];
-	return sprintf(buf, "%d.%d\n", version >> 16, version & 0xffff);
+	uint32_t *smd_ver;
+	uint32_t n, version, i = 0;
+
+	smd_ver = smem_alloc(SMEM_VERSION_SMD, 32 * sizeof(uint32_t));
+
+	if (smd_ver)
+		for (n = 0; n < 32; n++) {
+			version = smd_ver[n];
+			i += scnprintf(buf + i, max - i,
+				       "entry %d: %d.%d\n", n,
+				       version >> 16,
+				       version & 0xffff);
+		}
+
+	return i;
 }
 
 static int debug_read_build_id(char *buf, int max)
@@ -159,7 +660,7 @@
 	unsigned size;
 	void *data;
 
-	data = smem_item(SMEM_HW_SW_BUILD_ID, &size);
+	data = smem_get_entry(SMEM_HW_SW_BUILD_ID, &size);
 	if (!data)
 		return 0;
 
@@ -175,23 +676,62 @@
 	struct smd_alloc_elm *shared;
 	int n, i = 0;
 
-	shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64);
+	shared = smem_find(ID_CH_ALLOC_TBL, sizeof(struct smd_alloc_elm[64]));
+
+	if (!shared)
+		return 0;
 
 	for (n = 0; n < 64; n++) {
-		if (shared[n].ref_count == 0)
-			continue;
 		i += scnprintf(buf + i, max - i,
-			       "%03d: %-20s cid=%02d type=%03d "
-			       "kind=%02d ref_count=%d\n",
-			       n, shared[n].name, shared[n].cid,
-			       shared[n].ctype & 0xff,
-			       (shared[n].ctype >> 8) & 0xf,
-			       shared[n].ref_count);
+				"name=%s cid=%d ch type=%d "
+				"xfer type=%d ref_count=%d\n",
+				shared[n].name,
+				shared[n].cid,
+				SMD_CHANNEL_TYPE(shared[n].type),
+				SMD_XFER_TYPE(shared[n].type),
+				shared[n].ref_count);
 	}
 
 	return i;
 }
 
+static int debug_read_intr_mask(char *buf, int max)
+{
+	uint32_t *smsm;
+	int m, n, i = 0;
+
+	smsm = smem_alloc(SMEM_SMSM_CPU_INTR_MASK,
+			  SMSM_NUM_ENTRIES * SMSM_NUM_HOSTS * sizeof(uint32_t));
+
+	if (smsm)
+		for (m = 0; m < SMSM_NUM_ENTRIES; m++) {
+			i += scnprintf(buf + i, max - i, "entry %d:", m);
+			for (n = 0; n < SMSM_NUM_HOSTS; n++)
+				i += scnprintf(buf + i, max - i,
+					       "   host %d: 0x%08x",
+					       n, smsm[m * SMSM_NUM_HOSTS + n]);
+			i += scnprintf(buf + i, max - i, "\n");
+		}
+
+	return i;
+}
+
+static int debug_read_intr_mux(char *buf, int max)
+{
+	uint32_t *smsm;
+	int n, i = 0;
+
+	smsm = smem_alloc(SMEM_SMD_SMSM_INTR_MUX,
+			  SMSM_NUM_INTR_MUX * sizeof(uint32_t));
+
+	if (smsm)
+		for (n = 0; n < SMSM_NUM_INTR_MUX; n++)
+			i += scnprintf(buf + i, max - i, "entry %d: %d\n",
+				       n, smsm[n]);
+
+	return i;
+}
+
 #define DEBUG_BUFMAX 4096
 static char debug_buffer[DEBUG_BUFMAX];
 
@@ -199,14 +739,18 @@
 			  size_t count, loff_t *ppos)
 {
 	int (*fill)(char *buf, int max) = file->private_data;
-	int bsize = fill(debug_buffer, DEBUG_BUFMAX);
+	int bsize;
+
+	if (*ppos != 0)
+		return 0;
+
+	bsize = fill(debug_buffer, DEBUG_BUFMAX);
 	return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
 }
 
 static const struct file_operations debug_ops = {
 	.read = debug_read,
 	.open = simple_open,
-	.llseek = default_llseek,
 };
 
 static void debug_create(const char *name, umode_t mode,
@@ -216,25 +760,53 @@
 	debugfs_create_file(name, mode, dent, fill, &debug_ops);
 }
 
-static int smd_debugfs_init(void)
+static int __init smd_debugfs_init(void)
 {
 	struct dentry *dent;
 
 	dent = debugfs_create_dir("smd", 0);
 	if (IS_ERR(dent))
-		return 1;
+		return PTR_ERR(dent);
 
 	debug_create("ch", 0444, dent, debug_read_ch);
-	debug_create("stat", 0444, dent, debug_read_stat);
+	debug_create("diag", 0444, dent, debug_read_diag_msg);
 	debug_create("mem", 0444, dent, debug_read_mem);
-	debug_create("version", 0444, dent, debug_read_version);
+	debug_create("version", 0444, dent, debug_read_smd_version);
 	debug_create("tbl", 0444, dent, debug_read_alloc_tbl);
+	debug_create("modem_err", 0444, dent, debug_modem_err);
+	debug_create("modem_err_f3", 0444, dent, debug_modem_err_f3);
+	debug_create("print_diag", 0444, dent, debug_diag);
+	debug_create("print_f3", 0444, dent, debug_f3);
+	debug_create("int_stats", 0444, dent, debug_int_stats);
+	debug_create("int_stats_reset", 0444, dent, debug_int_stats_reset);
+
+	/* NNV: this is google only stuff */
 	debug_create("build", 0444, dent, debug_read_build_id);
 
 	return 0;
 }
 
+static int __init smsm_debugfs_init(void)
+{
+	struct dentry *dent;
+
+	dent = debugfs_create_dir("smsm", 0);
+	if (IS_ERR(dent))
+		return PTR_ERR(dent);
+
+	debug_create("state", 0444, dent, debug_read_smsm_state);
+	debug_create("intr_mask", 0444, dent, debug_read_intr_mask);
+	debug_create("intr_mux", 0444, dent, debug_read_intr_mux);
+	debug_create("version", 0444, dent, debug_read_smem_version);
+	debug_create("smsm_test", 0444, dent, debug_test_smsm);
+
+	init_completion(&smsm_cb_completion);
+
+	return 0;
+}
+
 late_initcall(smd_debugfs_init);
+late_initcall(smsm_debugfs_init);
 #endif
 
 
@@ -259,38 +831,29 @@
 	uint32_t polarity[NUM_GPIO_INT_REGISTERS];
 };
 
-
-void smsm_print_sleep_info(void)
+/*
+ * Print debug information on shared memory sleep variables
+ */
+void smsm_print_sleep_info(uint32_t sleep_delay, uint32_t sleep_limit,
+	uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs)
 {
 	unsigned long flags;
 	uint32_t *ptr;
-#ifndef CONFIG_ARCH_MSM_SCORPION
 	struct tramp_gpio_smem *gpio;
-	struct smsm_interrupt_info *int_info;
-#endif
-
 
 	spin_lock_irqsave(&smem_lock, flags);
 
-	ptr = smem_alloc(SMEM_SMSM_SLEEP_DELAY, sizeof(*ptr));
-	if (ptr)
-		pr_info("SMEM_SMSM_SLEEP_DELAY: %x\n", *ptr);
-
-	ptr = smem_alloc(SMEM_SMSM_LIMIT_SLEEP, sizeof(*ptr));
-	if (ptr)
-		pr_info("SMEM_SMSM_LIMIT_SLEEP: %x\n", *ptr);
+	pr_info("SMEM_SMSM_SLEEP_DELAY: %x\n", sleep_delay);
+	pr_info("SMEM_SMSM_LIMIT_SLEEP: %x\n", sleep_limit);
 
 	ptr = smem_alloc(SMEM_SLEEP_POWER_COLLAPSE_DISABLED, sizeof(*ptr));
 	if (ptr)
 		pr_info("SMEM_SLEEP_POWER_COLLAPSE_DISABLED: %x\n", *ptr);
+	else
+		pr_info("SMEM_SLEEP_POWER_COLLAPSE_DISABLED: missing\n");
 
-#ifndef CONFIG_ARCH_MSM_SCORPION
-	int_info = smem_alloc(SMEM_SMSM_INT_INFO, sizeof(*int_info));
-	if (int_info)
-		pr_info("SMEM_SMSM_INT_INFO %x %x %x\n",
-			int_info->interrupt_mask,
-			int_info->pending_interrupts,
-			int_info->wakeup_reason);
+	pr_info("SMEM_SMSM_INT_INFO %x %x %x\n",
+		irq_mask, pending_irqs, wakeup_reason);
 
 	gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*gpio));
 	if (gpio) {
@@ -304,9 +867,8 @@
 			pr_info("SMEM_GPIO_INT: %d: f %d: %d %d...\n",
 				i, gpio->num_fired[i], gpio->fired[i][0],
 				gpio->fired[i][1]);
-	}
-#else
-#endif
+	} else
+		pr_info("SMEM_GPIO_INT: missing\n");
+
 	spin_unlock_irqrestore(&smem_lock, flags);
 }
-
diff --git a/arch/arm/mach-msm/smd_nmea.c b/arch/arm/mach-msm/smd_nmea.c
new file mode 100644
index 0000000..1aedbf5
--- /dev/null
+++ b/arch/arm/mach-msm/smd_nmea.c
@@ -0,0 +1,205 @@
+/* Copyright (c) 2008-2009, 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.
+ *
+ */
+/*
+ * SMD NMEA Driver -- Provides GPS NMEA device to SMD port interface.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/workqueue.h>
+#include <linux/uaccess.h>
+
+#include <mach/msm_smd.h>
+
+#define MAX_BUF_SIZE 200
+
+static DEFINE_MUTEX(nmea_ch_lock);
+static DEFINE_MUTEX(nmea_rx_buf_lock);
+
+static DECLARE_WAIT_QUEUE_HEAD(nmea_wait_queue);
+
+struct nmea_device_t {
+	struct miscdevice misc;
+
+	struct smd_channel *ch;
+
+	unsigned char rx_buf[MAX_BUF_SIZE];
+	unsigned int bytes_read;
+};
+
+struct nmea_device_t *nmea_devp;
+
+static void nmea_work_func(struct work_struct *ws)
+{
+	int sz;
+
+	for (;;) {
+		sz = smd_cur_packet_size(nmea_devp->ch);
+		if (sz == 0)
+			break;
+		if (sz > smd_read_avail(nmea_devp->ch))
+			break;
+		if (sz > MAX_BUF_SIZE) {
+			smd_read(nmea_devp->ch, 0, sz);
+			continue;
+		}
+
+		mutex_lock(&nmea_rx_buf_lock);
+		if (smd_read(nmea_devp->ch, nmea_devp->rx_buf, sz) != sz) {
+			mutex_unlock(&nmea_rx_buf_lock);
+			printk(KERN_ERR "nmea: not enough data?!\n");
+			continue;
+		}
+		nmea_devp->bytes_read = sz;
+		mutex_unlock(&nmea_rx_buf_lock);
+		wake_up_interruptible(&nmea_wait_queue);
+	}
+}
+
+struct workqueue_struct *nmea_wq;
+static DECLARE_WORK(nmea_work, nmea_work_func);
+
+static void nmea_notify(void *priv, unsigned event)
+{
+	switch (event) {
+	case SMD_EVENT_DATA: {
+		int sz;
+		sz = smd_cur_packet_size(nmea_devp->ch);
+		if ((sz > 0) && (sz <= smd_read_avail(nmea_devp->ch)))
+			queue_work(nmea_wq, &nmea_work);
+		break;
+	}
+	case SMD_EVENT_OPEN:
+		printk(KERN_INFO "nmea: smd opened\n");
+		break;
+	case SMD_EVENT_CLOSE:
+		printk(KERN_INFO "nmea: smd closed\n");
+		break;
+	}
+}
+
+static ssize_t nmea_read(struct file *fp, char __user *buf,
+			 size_t count, loff_t *pos)
+{
+	int r;
+	int bytes_read;
+
+	r = wait_event_interruptible(nmea_wait_queue,
+				nmea_devp->bytes_read);
+	if (r < 0) {
+		/* qualify error message */
+		if (r != -ERESTARTSYS) {
+			/* we get this anytime a signal comes in */
+			printk(KERN_ERR "ERROR:%s:%i:%s: "
+				"wait_event_interruptible ret %i\n",
+				__FILE__,
+				__LINE__,
+				__func__,
+				r
+				);
+		}
+		return r;
+	}
+
+	mutex_lock(&nmea_rx_buf_lock);
+	bytes_read = nmea_devp->bytes_read;
+	nmea_devp->bytes_read = 0;
+	r = copy_to_user(buf, nmea_devp->rx_buf, bytes_read);
+	mutex_unlock(&nmea_rx_buf_lock);
+
+	if (r > 0) {
+		printk(KERN_ERR "ERROR:%s:%i:%s: "
+			"copy_to_user could not copy %i bytes.\n",
+			__FILE__,
+			__LINE__,
+			__func__,
+			r);
+		return r;
+	}
+
+	return bytes_read;
+}
+
+static int nmea_open(struct inode *ip, struct file *fp)
+{
+	int r = 0;
+
+	mutex_lock(&nmea_ch_lock);
+	if (nmea_devp->ch == 0)
+		r = smd_open("GPSNMEA", &nmea_devp->ch, nmea_devp, nmea_notify);
+	mutex_unlock(&nmea_ch_lock);
+
+	return r;
+}
+
+static int nmea_release(struct inode *ip, struct file *fp)
+{
+	int r = 0;
+
+	mutex_lock(&nmea_ch_lock);
+	if (nmea_devp->ch != 0) {
+		r = smd_close(nmea_devp->ch);
+		nmea_devp->ch = 0;
+	}
+	mutex_unlock(&nmea_ch_lock);
+
+	return r;
+}
+
+static const struct file_operations nmea_fops = {
+	.owner = THIS_MODULE,
+	.read = nmea_read,
+	.open = nmea_open,
+	.release = nmea_release,
+};
+
+static struct nmea_device_t nmea_device = {
+	.misc = {
+		.minor = MISC_DYNAMIC_MINOR,
+		.name = "nmea",
+		.fops = &nmea_fops,
+	}
+};
+
+static void __exit nmea_exit(void)
+{
+	destroy_workqueue(nmea_wq);
+	misc_deregister(&nmea_device.misc);
+}
+
+static int __init nmea_init(void)
+{
+	int ret;
+
+	nmea_device.bytes_read = 0;
+	nmea_devp = &nmea_device;
+
+	nmea_wq = create_singlethread_workqueue("nmea");
+	if (nmea_wq == 0)
+		return -ENOMEM;
+
+	ret = misc_register(&nmea_device.misc);
+	return ret;
+}
+
+module_init(nmea_init);
+module_exit(nmea_exit);
+
+MODULE_DESCRIPTION("MSM Shared Memory NMEA Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
new file mode 100644
index 0000000..b9cba8c
--- /dev/null
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -0,0 +1,1049 @@
+/* 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
+ * 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.
+ *
+ */
+/*
+ * SMD Packet Driver -- Provides a binary SMD non-muxed packet port
+ *                       interface.
+ */
+
+#include <linux/slab.h>
+#include <linux/cdev.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+#include <linux/msm_smd_pkt.h>
+#include <linux/poll.h>
+#include <asm/ioctls.h>
+#include <linux/wakelock.h>
+
+#include <mach/msm_smd.h>
+#include <mach/peripheral-loader.h>
+
+#include "smd_private.h"
+#ifdef CONFIG_ARCH_FSM9XXX
+#define NUM_SMD_PKT_PORTS 4
+#else
+#define NUM_SMD_PKT_PORTS 15
+#endif
+
+#define LOOPBACK_INX (NUM_SMD_PKT_PORTS - 1)
+
+#define DEVICE_NAME "smdpkt"
+#define WAKELOCK_TIMEOUT (2*HZ)
+
+struct smd_pkt_dev {
+	struct cdev cdev;
+	struct device *devicep;
+	void *pil;
+	struct platform_driver driver;
+
+	struct smd_channel *ch;
+	struct mutex ch_lock;
+	struct mutex rx_lock;
+	struct mutex tx_lock;
+	wait_queue_head_t ch_read_wait_queue;
+	wait_queue_head_t ch_write_wait_queue;
+	wait_queue_head_t ch_opened_wait_queue;
+
+	int i;
+
+	int blocking_write;
+	int is_open;
+	int poll_mode;
+	unsigned ch_size;
+	uint open_modem_wait;
+
+	int has_reset;
+	int do_reset_notification;
+	struct completion ch_allocated;
+	struct wake_lock pa_wake_lock;		/* Packet Arrival Wake lock*/
+	struct work_struct packet_arrival_work;
+	struct spinlock pa_spinlock;
+} *smd_pkt_devp[NUM_SMD_PKT_PORTS];
+
+struct class *smd_pkt_classp;
+static dev_t smd_pkt_number;
+static struct delayed_work loopback_work;
+static void check_and_wakeup_reader(struct smd_pkt_dev *smd_pkt_devp);
+static void check_and_wakeup_writer(struct smd_pkt_dev *smd_pkt_devp);
+static uint32_t is_modem_smsm_inited(void);
+
+static int msm_smd_pkt_debug_mask;
+module_param_named(debug_mask, msm_smd_pkt_debug_mask,
+		int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+enum {
+	SMD_PKT_STATUS = 1U << 0,
+	SMD_PKT_READ = 1U << 1,
+	SMD_PKT_WRITE = 1U << 2,
+	SMD_PKT_READ_DUMP_BUFFER = 1U << 3,
+	SMD_PKT_WRITE_DUMP_BUFFER = 1U << 4,
+	SMD_PKT_POLL = 1U << 5,
+};
+
+#define DEBUG
+
+#ifdef DEBUG
+#define D_STATUS(x...) \
+do { \
+	if (msm_smd_pkt_debug_mask & SMD_PKT_STATUS) \
+		pr_info("Status: "x); \
+} while (0)
+
+#define D_READ(x...) \
+do { \
+	if (msm_smd_pkt_debug_mask & SMD_PKT_READ) \
+		pr_info("Read: "x); \
+} while (0)
+
+#define D_WRITE(x...) \
+do { \
+	if (msm_smd_pkt_debug_mask & SMD_PKT_WRITE) \
+		pr_info("Write: "x); \
+} while (0)
+
+#define D_READ_DUMP_BUFFER(prestr, cnt, buf) \
+do { \
+	if (msm_smd_pkt_debug_mask & SMD_PKT_READ_DUMP_BUFFER) \
+		print_hex_dump(KERN_INFO, prestr, \
+			       DUMP_PREFIX_NONE, 16, 1, \
+			       buf, cnt, 1); \
+} while (0)
+
+#define D_WRITE_DUMP_BUFFER(prestr, cnt, buf) \
+do { \
+	if (msm_smd_pkt_debug_mask & SMD_PKT_WRITE_DUMP_BUFFER) \
+		print_hex_dump(KERN_INFO, prestr, \
+			       DUMP_PREFIX_NONE, 16, 1, \
+			       buf, cnt, 1); \
+} while (0)
+
+#define D_POLL(x...) \
+do { \
+	if (msm_smd_pkt_debug_mask & SMD_PKT_POLL) \
+		pr_info("Poll: "x); \
+} while (0)
+#else
+#define D_STATUS(x...) do {} while (0)
+#define D_READ(x...) do {} while (0)
+#define D_WRITE(x...) do {} while (0)
+#define D_READ_DUMP_BUFFER(prestr, cnt, buf) do {} while (0)
+#define D_WRITE_DUMP_BUFFER(prestr, cnt, buf) do {} while (0)
+#define D_POLL(x...) do {} while (0)
+#endif
+
+static ssize_t open_timeout_store(struct device *d,
+				  struct device_attribute *attr,
+				  const char *buf,
+				  size_t n)
+{
+	int i;
+	unsigned long tmp;
+	for (i = 0; i < NUM_SMD_PKT_PORTS; ++i) {
+		if (smd_pkt_devp[i]->devicep == d)
+			break;
+	}
+	if (i >= NUM_SMD_PKT_PORTS) {
+		pr_err("%s: unable to match device to valid smd_pkt port\n",
+			__func__);
+		return -EINVAL;
+	}
+	if (!strict_strtoul(buf, 10, &tmp)) {
+		smd_pkt_devp[i]->open_modem_wait = tmp;
+		return n;
+	} else {
+		pr_err("%s: unable to convert: %s to an int\n", __func__,
+			buf);
+		return -EINVAL;
+	}
+}
+
+static ssize_t open_timeout_show(struct device *d,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	int i;
+	for (i = 0; i < NUM_SMD_PKT_PORTS; ++i) {
+		if (smd_pkt_devp[i]->devicep == d)
+			break;
+	}
+	if (i >= NUM_SMD_PKT_PORTS) {
+		pr_err("%s: unable to match device to valid smd_pkt port\n",
+			__func__);
+		return -EINVAL;
+	}
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			smd_pkt_devp[i]->open_modem_wait);
+}
+
+static DEVICE_ATTR(open_timeout, 0664, open_timeout_show, open_timeout_store);
+
+static int notify_reset(struct smd_pkt_dev *smd_pkt_devp)
+{
+	smd_pkt_devp->do_reset_notification = 0;
+
+	return -ENETRESET;
+}
+
+static void clean_and_signal(struct smd_pkt_dev *smd_pkt_devp)
+{
+	smd_pkt_devp->do_reset_notification = 1;
+	smd_pkt_devp->has_reset = 1;
+
+	smd_pkt_devp->is_open = 0;
+
+	wake_up(&smd_pkt_devp->ch_read_wait_queue);
+	wake_up(&smd_pkt_devp->ch_write_wait_queue);
+	wake_up_interruptible(&smd_pkt_devp->ch_opened_wait_queue);
+	D_STATUS("%s smd_pkt_dev id:%d\n", __func__, smd_pkt_devp->i);
+}
+
+static void loopback_probe_worker(struct work_struct *work)
+{
+
+	/* Wait for the modem SMSM to be inited for the SMD
+	** Loopback channel to be allocated at the modem. Since
+	** the wait need to be done atmost once, using msleep
+	** doesn't degrade the performance. */
+	if (!is_modem_smsm_inited())
+		schedule_delayed_work(&loopback_work, msecs_to_jiffies(1000));
+	else
+		smsm_change_state(SMSM_APPS_STATE,
+			  0, SMSM_SMD_LOOPBACK);
+
+}
+
+static void packet_arrival_worker(struct work_struct *work)
+{
+	struct smd_pkt_dev *smd_pkt_devp;
+
+	smd_pkt_devp = container_of(work, struct smd_pkt_dev,
+				    packet_arrival_work);
+	mutex_lock(&smd_pkt_devp->ch_lock);
+	if (smd_pkt_devp->ch) {
+		D_READ("%s locking smd_pkt_dev id:%d wakelock\n",
+			__func__, smd_pkt_devp->i);
+		wake_lock_timeout(&smd_pkt_devp->pa_wake_lock,
+				  WAKELOCK_TIMEOUT);
+	}
+	mutex_unlock(&smd_pkt_devp->ch_lock);
+}
+
+static long smd_pkt_ioctl(struct file *file, unsigned int cmd,
+					     unsigned long arg)
+{
+	int ret;
+	struct smd_pkt_dev *smd_pkt_devp;
+
+	smd_pkt_devp = file->private_data;
+	if (!smd_pkt_devp)
+		return -EINVAL;
+
+	switch (cmd) {
+	case TIOCMGET:
+		D_STATUS("%s TIOCMGET command on smd_pkt_dev id:%d\n",
+			 __func__, smd_pkt_devp->i);
+		ret = smd_tiocmget(smd_pkt_devp->ch);
+		break;
+	case TIOCMSET:
+		D_STATUS("%s TIOCSET command on smd_pkt_dev id:%d\n",
+			 __func__, smd_pkt_devp->i);
+		ret = smd_tiocmset(smd_pkt_devp->ch, arg, ~arg);
+		break;
+	case SMD_PKT_IOCTL_BLOCKING_WRITE:
+		ret = get_user(smd_pkt_devp->blocking_write, (int *)arg);
+		break;
+	default:
+		pr_err("%s: Unrecognized ioctl command %d\n", __func__, cmd);
+		ret = -1;
+	}
+
+	return ret;
+}
+
+ssize_t smd_pkt_read(struct file *file,
+		       char __user *buf,
+		       size_t count,
+		       loff_t *ppos)
+{
+	int r;
+	int bytes_read;
+	int pkt_size;
+	struct smd_pkt_dev *smd_pkt_devp;
+	unsigned long flags;
+
+	smd_pkt_devp = file->private_data;
+
+	if (!smd_pkt_devp) {
+		pr_err("%s on NULL smd_pkt_dev\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!smd_pkt_devp->ch) {
+		pr_err("%s on a closed smd_pkt_dev id:%d\n",
+			__func__, smd_pkt_devp->i);
+		return -EINVAL;
+	}
+
+	if (smd_pkt_devp->do_reset_notification) {
+		/* notify client that a reset occurred */
+		pr_err("%s notifying reset for smd_pkt_dev id:%d\n",
+			__func__, smd_pkt_devp->i);
+		return notify_reset(smd_pkt_devp);
+	}
+	D_READ("Begin %s on smd_pkt_dev id:%d buffer_size %d\n",
+		__func__, smd_pkt_devp->i, count);
+
+wait_for_packet:
+	r = wait_event_interruptible(smd_pkt_devp->ch_read_wait_queue,
+				     !smd_pkt_devp->ch ||
+				     (smd_cur_packet_size(smd_pkt_devp->ch) > 0
+				      && smd_read_avail(smd_pkt_devp->ch)) ||
+				     smd_pkt_devp->has_reset);
+
+	mutex_lock(&smd_pkt_devp->rx_lock);
+	if (smd_pkt_devp->has_reset) {
+		mutex_unlock(&smd_pkt_devp->rx_lock);
+		pr_err("%s notifying reset for smd_pkt_dev id:%d\n",
+			__func__, smd_pkt_devp->i);
+		return notify_reset(smd_pkt_devp);
+	}
+
+	if (!smd_pkt_devp->ch) {
+		mutex_unlock(&smd_pkt_devp->rx_lock);
+		pr_err("%s on a closed smd_pkt_dev id:%d\n",
+			__func__, smd_pkt_devp->i);
+		return -EINVAL;
+	}
+
+	if (r < 0) {
+		mutex_unlock(&smd_pkt_devp->rx_lock);
+		/* qualify error message */
+		if (r != -ERESTARTSYS) {
+			/* we get this anytime a signal comes in */
+			pr_err("%s: wait_event_interruptible on smd_pkt_dev"
+			       " id:%d ret %i\n",
+				__func__, smd_pkt_devp->i, r);
+		}
+		return r;
+	}
+
+	/* Here we have a whole packet waiting for us */
+	pkt_size = smd_cur_packet_size(smd_pkt_devp->ch);
+
+	if (!pkt_size) {
+		pr_err("%s: No data on smd_pkt_dev id:%d, False wakeup\n",
+			__func__, smd_pkt_devp->i);
+		mutex_unlock(&smd_pkt_devp->rx_lock);
+		goto wait_for_packet;
+	}
+
+	if (pkt_size > count) {
+		pr_err("%s: failure on smd_pkt_dev id: %d - packet size %d"
+		       " > buffer size %d,", __func__, smd_pkt_devp->i,
+			pkt_size, count);
+		mutex_unlock(&smd_pkt_devp->rx_lock);
+		return -ETOOSMALL;
+	}
+
+	bytes_read = 0;
+	do {
+		r = smd_read_user_buffer(smd_pkt_devp->ch,
+					 (buf + bytes_read),
+					 (pkt_size - bytes_read));
+		if (r < 0) {
+			mutex_unlock(&smd_pkt_devp->rx_lock);
+			if (smd_pkt_devp->has_reset) {
+				pr_err("%s notifying reset for smd_pkt_dev"
+				       " id:%d\n", __func__, smd_pkt_devp->i);
+				return notify_reset(smd_pkt_devp);
+			}
+			pr_err("%s Error while reading %d\n", __func__, r);
+			return r;
+		}
+		bytes_read += r;
+		if (pkt_size != bytes_read)
+			wait_event(smd_pkt_devp->ch_read_wait_queue,
+				   smd_read_avail(smd_pkt_devp->ch) ||
+				   smd_pkt_devp->has_reset);
+		if (smd_pkt_devp->has_reset) {
+			mutex_unlock(&smd_pkt_devp->rx_lock);
+			pr_err("%s notifying reset for smd_pkt_dev  id:%d\n",
+				__func__, smd_pkt_devp->i);
+			return notify_reset(smd_pkt_devp);
+		}
+	} while (pkt_size != bytes_read);
+	D_READ_DUMP_BUFFER("Read: ", (bytes_read > 16 ? 16 : bytes_read), buf);
+	mutex_unlock(&smd_pkt_devp->rx_lock);
+
+	mutex_lock(&smd_pkt_devp->ch_lock);
+	spin_lock_irqsave(&smd_pkt_devp->pa_spinlock, flags);
+	if (smd_pkt_devp->poll_mode &&
+	    !smd_cur_packet_size(smd_pkt_devp->ch)) {
+		wake_unlock(&smd_pkt_devp->pa_wake_lock);
+		smd_pkt_devp->poll_mode = 0;
+		D_READ("%s unlocked smd_pkt_dev id:%d wakelock\n",
+			__func__, smd_pkt_devp->i);
+	}
+	spin_unlock_irqrestore(&smd_pkt_devp->pa_spinlock, flags);
+	mutex_unlock(&smd_pkt_devp->ch_lock);
+
+	D_READ("Finished %s on smd_pkt_dev id:%d  %d bytes\n",
+		__func__, smd_pkt_devp->i, bytes_read);
+
+	/* check and wakeup read threads waiting on this device */
+	check_and_wakeup_reader(smd_pkt_devp);
+
+	return bytes_read;
+}
+
+ssize_t smd_pkt_write(struct file *file,
+		       const char __user *buf,
+		       size_t count,
+		       loff_t *ppos)
+{
+	int r = 0, bytes_written;
+	struct smd_pkt_dev *smd_pkt_devp;
+	DEFINE_WAIT(write_wait);
+
+	smd_pkt_devp = file->private_data;
+
+	if (!smd_pkt_devp) {
+		pr_err("%s on NULL smd_pkt_dev\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!smd_pkt_devp->ch) {
+		pr_err("%s on a closed smd_pkt_dev id:%d\n",
+			__func__, smd_pkt_devp->i);
+		return -EINVAL;
+	}
+
+	if (smd_pkt_devp->do_reset_notification || smd_pkt_devp->has_reset) {
+		pr_err("%s notifying reset for smd_pkt_dev id:%d\n",
+			__func__, smd_pkt_devp->i);
+		/* notify client that a reset occurred */
+		return notify_reset(smd_pkt_devp);
+	}
+	D_WRITE("Begin %s on smd_pkt_dev id:%d data_size %d\n",
+		__func__, smd_pkt_devp->i, count);
+
+	mutex_lock(&smd_pkt_devp->tx_lock);
+	if (!smd_pkt_devp->blocking_write) {
+		if (smd_write_avail(smd_pkt_devp->ch) < count) {
+			pr_err("%s: Not enough space in smd_pkt_dev id:%d\n",
+				   __func__, smd_pkt_devp->i);
+			mutex_unlock(&smd_pkt_devp->tx_lock);
+			return -ENOMEM;
+		}
+	}
+
+	r = smd_write_start(smd_pkt_devp->ch, count);
+	if (r < 0) {
+		mutex_unlock(&smd_pkt_devp->tx_lock);
+		pr_err("%s: Error:%d in smd_pkt_dev id:%d @ smd_write_start\n",
+			__func__, r, smd_pkt_devp->i);
+		return r;
+	}
+
+	bytes_written = 0;
+	do {
+		prepare_to_wait(&smd_pkt_devp->ch_write_wait_queue,
+				&write_wait, TASK_UNINTERRUPTIBLE);
+		if (!smd_write_avail(smd_pkt_devp->ch) &&
+		    !smd_pkt_devp->has_reset) {
+			smd_enable_read_intr(smd_pkt_devp->ch);
+			schedule();
+		}
+		finish_wait(&smd_pkt_devp->ch_write_wait_queue, &write_wait);
+		smd_disable_read_intr(smd_pkt_devp->ch);
+
+		if (smd_pkt_devp->has_reset) {
+			mutex_unlock(&smd_pkt_devp->tx_lock);
+			pr_err("%s notifying reset for smd_pkt_dev id:%d\n",
+				__func__, smd_pkt_devp->i);
+			return notify_reset(smd_pkt_devp);
+		} else {
+			r = smd_write_segment(smd_pkt_devp->ch,
+					      (void *)(buf + bytes_written),
+					      (count - bytes_written), 1);
+			if (r < 0) {
+				mutex_unlock(&smd_pkt_devp->tx_lock);
+				if (smd_pkt_devp->has_reset) {
+					pr_err("%s notifying reset for"
+					       " smd_pkt_dev id:%d\n",
+						__func__, smd_pkt_devp->i);
+					return notify_reset(smd_pkt_devp);
+				}
+				pr_err("%s on smd_pkt_dev id:%d failed r:%d\n",
+					__func__, smd_pkt_devp->i, r);
+				return r;
+			}
+			bytes_written += r;
+		}
+	} while (bytes_written != count);
+	smd_write_end(smd_pkt_devp->ch);
+	mutex_unlock(&smd_pkt_devp->tx_lock);
+	D_WRITE_DUMP_BUFFER("Write: ",
+			    (bytes_written > 16 ? 16 : bytes_written), buf);
+	D_WRITE("Finished %s on smd_pkt_dev id:%d %d bytes\n",
+		__func__, smd_pkt_devp->i, count);
+
+	return count;
+}
+
+static unsigned int smd_pkt_poll(struct file *file, poll_table *wait)
+{
+	struct smd_pkt_dev *smd_pkt_devp;
+	unsigned int mask = 0;
+
+	smd_pkt_devp = file->private_data;
+	if (!smd_pkt_devp) {
+		pr_err("%s on a NULL device\n", __func__);
+		return POLLERR;
+	}
+
+	smd_pkt_devp->poll_mode = 1;
+	poll_wait(file, &smd_pkt_devp->ch_read_wait_queue, wait);
+	mutex_lock(&smd_pkt_devp->ch_lock);
+	if (smd_pkt_devp->has_reset || !smd_pkt_devp->ch) {
+		mutex_unlock(&smd_pkt_devp->ch_lock);
+		pr_err("%s notifying reset for smd_pkt_dev id:%d\n",
+			__func__, smd_pkt_devp->i);
+		return POLLERR;
+	}
+
+	if (smd_read_avail(smd_pkt_devp->ch)) {
+		mask |= POLLIN | POLLRDNORM;
+		D_POLL("%s sets POLLIN for smd_pkt_dev id: %d\n",
+			__func__, smd_pkt_devp->i);
+	}
+	mutex_unlock(&smd_pkt_devp->ch_lock);
+
+	return mask;
+}
+
+static void check_and_wakeup_reader(struct smd_pkt_dev *smd_pkt_devp)
+{
+	int sz;
+	unsigned long flags;
+
+	if (!smd_pkt_devp) {
+		pr_err("%s on a NULL device\n", __func__);
+		return;
+	}
+
+	if (!smd_pkt_devp->ch) {
+		pr_err("%s on a closed smd_pkt_dev id:%d\n",
+			__func__, smd_pkt_devp->i);
+		return;
+	}
+
+	sz = smd_cur_packet_size(smd_pkt_devp->ch);
+	if (sz == 0) {
+		D_READ("%s: No packet in smd_pkt_dev id:%d\n",
+			__func__, smd_pkt_devp->i);
+		return;
+	}
+	if (!smd_read_avail(smd_pkt_devp->ch)) {
+		D_READ("%s: packet size is %d in smd_pkt_dev id:%d -"
+			" but the data isn't here\n",
+			__func__, sz, smd_pkt_devp->i);
+		return;
+	}
+
+	/* here we have a packet of size sz ready */
+	wake_up(&smd_pkt_devp->ch_read_wait_queue);
+	spin_lock_irqsave(&smd_pkt_devp->pa_spinlock, flags);
+	wake_lock(&smd_pkt_devp->pa_wake_lock);
+	spin_unlock_irqrestore(&smd_pkt_devp->pa_spinlock, flags);
+	schedule_work(&smd_pkt_devp->packet_arrival_work);
+	D_READ("%s: wake_up smd_pkt_dev id:%d\n", __func__, smd_pkt_devp->i);
+}
+
+static void check_and_wakeup_writer(struct smd_pkt_dev *smd_pkt_devp)
+{
+	int sz;
+
+	if (!smd_pkt_devp) {
+		pr_err("%s on a NULL device\n", __func__);
+		return;
+	}
+
+	if (!smd_pkt_devp->ch) {
+		pr_err("%s on a closed smd_pkt_dev id:%d\n",
+			__func__, smd_pkt_devp->i);
+		return;
+	}
+
+	sz = smd_write_avail(smd_pkt_devp->ch);
+	if (sz) {
+		D_WRITE("%s: %d bytes write space in smd_pkt_dev id:%d\n",
+			__func__, sz, smd_pkt_devp->i);
+		smd_disable_read_intr(smd_pkt_devp->ch);
+		wake_up(&smd_pkt_devp->ch_write_wait_queue);
+	}
+}
+
+static void ch_notify(void *priv, unsigned event)
+{
+	struct smd_pkt_dev *smd_pkt_devp = priv;
+
+	if (smd_pkt_devp->ch == 0) {
+		pr_err("%s on a closed smd_pkt_dev id:%d\n",
+			__func__, smd_pkt_devp->i);
+		return;
+	}
+
+	switch (event) {
+	case SMD_EVENT_DATA: {
+		D_STATUS("%s: DATA event in smd_pkt_dev id:%d\n",
+			 __func__, smd_pkt_devp->i);
+		check_and_wakeup_reader(smd_pkt_devp);
+		if (smd_pkt_devp->blocking_write)
+			check_and_wakeup_writer(smd_pkt_devp);
+		break;
+	}
+	case SMD_EVENT_OPEN:
+		D_STATUS("%s: OPEN event in smd_pkt_dev id:%d\n",
+			  __func__, smd_pkt_devp->i);
+		smd_pkt_devp->has_reset = 0;
+		smd_pkt_devp->is_open = 1;
+		wake_up_interruptible(&smd_pkt_devp->ch_opened_wait_queue);
+		break;
+	case SMD_EVENT_CLOSE:
+		D_STATUS("%s: CLOSE event in smd_pkt_dev id:%d\n",
+			  __func__, smd_pkt_devp->i);
+		smd_pkt_devp->is_open = 0;
+		/* put port into reset state */
+		clean_and_signal(smd_pkt_devp);
+		if (smd_pkt_devp->i == LOOPBACK_INX)
+			schedule_delayed_work(&loopback_work,
+					msecs_to_jiffies(1000));
+		break;
+	}
+}
+
+#ifdef CONFIG_ARCH_FSM9XXX
+static char *smd_pkt_dev_name[] = {
+	"smdcntl1",
+	"smdcntl2",
+	"smd22",
+	"smd_pkt_loopback",
+};
+
+static char *smd_ch_name[] = {
+	"DATA6_CNTL",
+	"DATA7_CNTL",
+	"DATA22",
+	"LOOPBACK",
+};
+
+static uint32_t smd_ch_edge[] = {
+	SMD_APPS_QDSP,
+	SMD_APPS_QDSP,
+	SMD_APPS_QDSP,
+	SMD_APPS_QDSP
+};
+#else
+static char *smd_pkt_dev_name[] = {
+	"smdcntl0",
+	"smdcntl1",
+	"smdcntl2",
+	"smdcntl3",
+	"smdcntl4",
+	"smdcntl5",
+	"smdcntl6",
+	"smdcntl7",
+	"smd22",
+	"smd_sns_dsps",
+	"apr_apps2",
+	"smdcntl8",
+	"smd_sns_adsp",
+	"smd_cxm_qmi",
+	"smd_pkt_loopback",
+};
+
+static char *smd_ch_name[] = {
+	"DATA5_CNTL",
+	"DATA6_CNTL",
+	"DATA7_CNTL",
+	"DATA8_CNTL",
+	"DATA9_CNTL",
+	"DATA12_CNTL",
+	"DATA13_CNTL",
+	"DATA14_CNTL",
+	"DATA22",
+	"SENSOR",
+	"apr_apps2",
+	"DATA40_CNTL",
+	"SENSOR",
+	"CXM_QMI_PORT_8064",
+	"LOOPBACK",
+};
+
+static uint32_t smd_ch_edge[] = {
+	SMD_APPS_MODEM,
+	SMD_APPS_MODEM,
+	SMD_APPS_MODEM,
+	SMD_APPS_MODEM,
+	SMD_APPS_MODEM,
+	SMD_APPS_MODEM,
+	SMD_APPS_MODEM,
+	SMD_APPS_MODEM,
+	SMD_APPS_MODEM,
+	SMD_APPS_DSPS,
+	SMD_APPS_QDSP,
+	SMD_APPS_MODEM,
+	SMD_APPS_QDSP,
+	SMD_APPS_WCNSS,
+	SMD_APPS_MODEM,
+};
+#endif
+
+static int smd_pkt_dummy_probe(struct platform_device *pdev)
+{
+	int i;
+
+	for (i = 0; i < NUM_SMD_PKT_PORTS; i++) {
+		if (!strncmp(pdev->name, smd_ch_name[i], SMD_MAX_CH_NAME_LEN)) {
+			complete_all(&smd_pkt_devp[i]->ch_allocated);
+			D_STATUS("%s allocated SMD ch for smd_pkt_dev id:%d\n",
+				 __func__, i);
+			break;
+		}
+	}
+	return 0;
+}
+
+static uint32_t is_modem_smsm_inited(void)
+{
+	uint32_t modem_state;
+	uint32_t ready_state = (SMSM_INIT | SMSM_SMDINIT);
+
+	modem_state = smsm_get_state(SMSM_MODEM_STATE);
+	return (modem_state & ready_state) == ready_state;
+}
+
+int smd_pkt_open(struct inode *inode, struct file *file)
+{
+	int r = 0;
+	struct smd_pkt_dev *smd_pkt_devp;
+	const char *peripheral = NULL;
+
+	smd_pkt_devp = container_of(inode->i_cdev, struct smd_pkt_dev, cdev);
+
+	if (!smd_pkt_devp) {
+		pr_err("%s on a NULL device\n", __func__);
+		return -EINVAL;
+	}
+	D_STATUS("Begin %s on smd_pkt_dev id:%d\n", __func__, smd_pkt_devp->i);
+
+	wake_lock_init(&smd_pkt_devp->pa_wake_lock, WAKE_LOCK_SUSPEND,
+			smd_pkt_dev_name[smd_pkt_devp->i]);
+	INIT_WORK(&smd_pkt_devp->packet_arrival_work, packet_arrival_worker);
+
+	file->private_data = smd_pkt_devp;
+
+	mutex_lock(&smd_pkt_devp->ch_lock);
+	if (smd_pkt_devp->ch == 0) {
+		init_completion(&smd_pkt_devp->ch_allocated);
+		smd_pkt_devp->driver.probe = smd_pkt_dummy_probe;
+		smd_pkt_devp->driver.driver.name =
+			smd_ch_name[smd_pkt_devp->i];
+		smd_pkt_devp->driver.driver.owner = THIS_MODULE;
+		r = platform_driver_register(&smd_pkt_devp->driver);
+		if (r) {
+			pr_err("%s: %s Platform driver reg. failed\n",
+				__func__, smd_ch_name[smd_pkt_devp->i]);
+			goto out;
+		}
+
+		peripheral = smd_edge_to_subsystem(
+				smd_ch_edge[smd_pkt_devp->i]);
+		if (peripheral) {
+			smd_pkt_devp->pil = pil_get(peripheral);
+			if (IS_ERR(smd_pkt_devp->pil)) {
+				r = PTR_ERR(smd_pkt_devp->pil);
+				pr_err("%s failed on smd_pkt_dev id:%d -"
+				       " pil_get failed for %s\n", __func__,
+					smd_pkt_devp->i, peripheral);
+				goto release_pd;
+			}
+
+			/* Wait for the modem SMSM to be inited for the SMD
+			** Loopback channel to be allocated at the modem. Since
+			** the wait need to be done atmost once, using msleep
+			** doesn't degrade the performance. */
+			if (!strncmp(smd_ch_name[smd_pkt_devp->i], "LOOPBACK",
+						SMD_MAX_CH_NAME_LEN)) {
+				if (!is_modem_smsm_inited())
+					msleep(5000);
+				smsm_change_state(SMSM_APPS_STATE,
+						  0, SMSM_SMD_LOOPBACK);
+				msleep(100);
+			}
+
+			/*
+			 * Wait for a packet channel to be allocated so we know
+			 * the modem is ready enough.
+			 */
+			if (smd_pkt_devp->open_modem_wait) {
+				r = wait_for_completion_interruptible_timeout(
+					&smd_pkt_devp->ch_allocated,
+					msecs_to_jiffies(
+						smd_pkt_devp->open_modem_wait
+							 * 1000));
+				if (r == 0)
+					r = -ETIMEDOUT;
+				if (r < 0) {
+					pr_err("%s: wait on smd_pkt_dev id:%d"
+					       " allocation failed rc:%d\n",
+						__func__, smd_pkt_devp->i, r);
+					goto release_pil;
+				}
+			}
+		}
+
+		r = smd_named_open_on_edge(smd_ch_name[smd_pkt_devp->i],
+					   smd_ch_edge[smd_pkt_devp->i],
+					   &smd_pkt_devp->ch,
+					   smd_pkt_devp,
+					   ch_notify);
+		if (r < 0) {
+			pr_err("%s: %s open failed %d\n", __func__,
+			       smd_ch_name[smd_pkt_devp->i], r);
+			goto release_pil;
+		}
+
+		r = wait_event_interruptible_timeout(
+				smd_pkt_devp->ch_opened_wait_queue,
+				smd_pkt_devp->is_open, (2 * HZ));
+		if (r == 0) {
+			r = -ETIMEDOUT;
+			/* close the ch to sync smd's state with smd_pkt */
+			smd_close(smd_pkt_devp->ch);
+			smd_pkt_devp->ch = NULL;
+		}
+
+		if (r < 0) {
+			pr_err("%s: wait on smd_pkt_dev id:%d OPEN event failed"
+			       " rc:%d\n", __func__, smd_pkt_devp->i, r);
+		} else if (!smd_pkt_devp->is_open) {
+			pr_err("%s: Invalid OPEN event on smd_pkt_dev id:%d\n",
+				__func__, smd_pkt_devp->i);
+			r = -ENODEV;
+		} else {
+			smd_disable_read_intr(smd_pkt_devp->ch);
+			smd_pkt_devp->ch_size =
+				smd_write_avail(smd_pkt_devp->ch);
+			r = 0;
+			D_STATUS("Finished %s on smd_pkt_dev id:%d\n",
+				 __func__, smd_pkt_devp->i);
+		}
+	}
+release_pil:
+	if (peripheral && (r < 0))
+		pil_put(smd_pkt_devp->pil);
+
+release_pd:
+	if (r < 0)
+		platform_driver_unregister(&smd_pkt_devp->driver);
+out:
+	mutex_unlock(&smd_pkt_devp->ch_lock);
+
+	if (r < 0)
+		wake_lock_destroy(&smd_pkt_devp->pa_wake_lock);
+
+	return r;
+}
+
+int smd_pkt_release(struct inode *inode, struct file *file)
+{
+	int r = 0;
+	struct smd_pkt_dev *smd_pkt_devp = file->private_data;
+
+	if (!smd_pkt_devp) {
+		pr_err("%s on a NULL device\n", __func__);
+		return -EINVAL;
+	}
+	D_STATUS("Begin %s on smd_pkt_dev id:%d\n",
+		 __func__, smd_pkt_devp->i);
+
+	clean_and_signal(smd_pkt_devp);
+
+	mutex_lock(&smd_pkt_devp->ch_lock);
+	mutex_lock(&smd_pkt_devp->rx_lock);
+	mutex_lock(&smd_pkt_devp->tx_lock);
+	if (smd_pkt_devp->ch != 0) {
+		r = smd_close(smd_pkt_devp->ch);
+		smd_pkt_devp->ch = 0;
+		smd_pkt_devp->blocking_write = 0;
+		smd_pkt_devp->poll_mode = 0;
+		platform_driver_unregister(&smd_pkt_devp->driver);
+		if (smd_pkt_devp->pil)
+			pil_put(smd_pkt_devp->pil);
+	}
+	mutex_unlock(&smd_pkt_devp->tx_lock);
+	mutex_unlock(&smd_pkt_devp->rx_lock);
+	mutex_unlock(&smd_pkt_devp->ch_lock);
+
+	smd_pkt_devp->has_reset = 0;
+	smd_pkt_devp->do_reset_notification = 0;
+	wake_lock_destroy(&smd_pkt_devp->pa_wake_lock);
+	D_STATUS("Finished %s on smd_pkt_dev id:%d\n",
+		 __func__, smd_pkt_devp->i);
+
+	return r;
+}
+
+static const struct file_operations smd_pkt_fops = {
+	.owner = THIS_MODULE,
+	.open = smd_pkt_open,
+	.release = smd_pkt_release,
+	.read = smd_pkt_read,
+	.write = smd_pkt_write,
+	.poll = smd_pkt_poll,
+	.unlocked_ioctl = smd_pkt_ioctl,
+};
+
+static int __init smd_pkt_init(void)
+{
+	int i;
+	int r;
+
+	r = alloc_chrdev_region(&smd_pkt_number,
+			       0,
+			       NUM_SMD_PKT_PORTS,
+			       DEVICE_NAME);
+	if (IS_ERR_VALUE(r)) {
+		pr_err("%s: alloc_chrdev_region() failed ret:%i\n",
+		       __func__, r);
+		goto error0;
+	}
+
+	smd_pkt_classp = class_create(THIS_MODULE, DEVICE_NAME);
+	if (IS_ERR(smd_pkt_classp)) {
+		pr_err("%s: class_create() failed ENOMEM\n", __func__);
+		r = -ENOMEM;
+		goto error1;
+	}
+
+	for (i = 0; i < NUM_SMD_PKT_PORTS; ++i) {
+		smd_pkt_devp[i] = kzalloc(sizeof(struct smd_pkt_dev),
+					 GFP_KERNEL);
+		if (IS_ERR(smd_pkt_devp[i])) {
+			pr_err("%s: kzalloc() failed for smd_pkt_dev id:%d\n",
+				__func__, i);
+			r = -ENOMEM;
+			goto error2;
+		}
+
+		smd_pkt_devp[i]->i = i;
+
+		init_waitqueue_head(&smd_pkt_devp[i]->ch_read_wait_queue);
+		init_waitqueue_head(&smd_pkt_devp[i]->ch_write_wait_queue);
+		smd_pkt_devp[i]->is_open = 0;
+		smd_pkt_devp[i]->poll_mode = 0;
+		init_waitqueue_head(&smd_pkt_devp[i]->ch_opened_wait_queue);
+
+		spin_lock_init(&smd_pkt_devp[i]->pa_spinlock);
+		mutex_init(&smd_pkt_devp[i]->ch_lock);
+		mutex_init(&smd_pkt_devp[i]->rx_lock);
+		mutex_init(&smd_pkt_devp[i]->tx_lock);
+
+		cdev_init(&smd_pkt_devp[i]->cdev, &smd_pkt_fops);
+		smd_pkt_devp[i]->cdev.owner = THIS_MODULE;
+
+		r = cdev_add(&smd_pkt_devp[i]->cdev,
+			     (smd_pkt_number + i),
+			     1);
+
+		if (IS_ERR_VALUE(r)) {
+			pr_err("%s: cdev_add() failed for smd_pkt_dev id:%d"
+			       " ret:%i\n", __func__, i, r);
+			kfree(smd_pkt_devp[i]);
+			goto error2;
+		}
+
+		smd_pkt_devp[i]->devicep =
+			device_create(smd_pkt_classp,
+				      NULL,
+				      (smd_pkt_number + i),
+				      NULL,
+				      smd_pkt_dev_name[i]);
+
+		if (IS_ERR(smd_pkt_devp[i]->devicep)) {
+			pr_err("%s: device_create() failed for smd_pkt_dev"
+			       " id:%d\n", __func__, i);
+			r = -ENOMEM;
+			cdev_del(&smd_pkt_devp[i]->cdev);
+			kfree(smd_pkt_devp[i]);
+			goto error2;
+		}
+		if (device_create_file(smd_pkt_devp[i]->devicep,
+					&dev_attr_open_timeout))
+			pr_err("%s: unable to create device attr for"
+			       " smd_pkt_dev id:%d\n", __func__, i);
+	}
+
+	INIT_DELAYED_WORK(&loopback_work, loopback_probe_worker);
+
+	D_STATUS("SMD Packet Port Driver Initialized.\n");
+	return 0;
+
+ error2:
+	if (i > 0) {
+		while (--i >= 0) {
+			cdev_del(&smd_pkt_devp[i]->cdev);
+			kfree(smd_pkt_devp[i]);
+			device_destroy(smd_pkt_classp,
+				       MKDEV(MAJOR(smd_pkt_number), i));
+		}
+	}
+
+	class_destroy(smd_pkt_classp);
+ error1:
+	unregister_chrdev_region(MAJOR(smd_pkt_number), NUM_SMD_PKT_PORTS);
+ error0:
+	return r;
+}
+
+static void __exit smd_pkt_cleanup(void)
+{
+	int i;
+
+	for (i = 0; i < NUM_SMD_PKT_PORTS; ++i) {
+		cdev_del(&smd_pkt_devp[i]->cdev);
+		kfree(smd_pkt_devp[i]);
+		device_destroy(smd_pkt_classp,
+			       MKDEV(MAJOR(smd_pkt_number), i));
+	}
+
+	class_destroy(smd_pkt_classp);
+
+	unregister_chrdev_region(MAJOR(smd_pkt_number), NUM_SMD_PKT_PORTS);
+}
+
+module_init(smd_pkt_init);
+module_exit(smd_pkt_cleanup);
+
+MODULE_DESCRIPTION("MSM Shared Memory Packet Port");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/smd_private.c b/arch/arm/mach-msm/smd_private.c
new file mode 100644
index 0000000..5a78b6f
--- /dev/null
+++ b/arch/arm/mach-msm/smd_private.c
@@ -0,0 +1,303 @@
+/* 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 "smd_private.h"
+
+void set_state(volatile void *half_channel, unsigned data)
+{
+	((struct smd_half_channel *)(half_channel))->state = data;
+}
+
+unsigned get_state(volatile void *half_channel)
+{
+	return ((struct smd_half_channel *)(half_channel))->state;
+}
+
+void set_fDSR(volatile void *half_channel, unsigned char data)
+{
+	((struct smd_half_channel *)(half_channel))->fDSR = data;
+}
+
+unsigned get_fDSR(volatile void *half_channel)
+{
+	return ((struct smd_half_channel *)(half_channel))->fDSR;
+}
+
+void set_fCTS(volatile void *half_channel, unsigned char data)
+{
+	((struct smd_half_channel *)(half_channel))->fCTS = data;
+}
+
+unsigned get_fCTS(volatile void *half_channel)
+{
+	return ((struct smd_half_channel *)(half_channel))->fCTS;
+}
+
+void set_fCD(volatile void *half_channel, unsigned char data)
+{
+	((struct smd_half_channel *)(half_channel))->fCD = data;
+}
+
+unsigned get_fCD(volatile void *half_channel)
+{
+	return ((struct smd_half_channel *)(half_channel))->fCD;
+}
+
+void set_fRI(volatile void *half_channel, unsigned char data)
+{
+	((struct smd_half_channel *)(half_channel))->fRI = data;
+}
+
+unsigned get_fRI(volatile void *half_channel)
+{
+	return ((struct smd_half_channel *)(half_channel))->fRI;
+}
+
+void set_fHEAD(volatile void *half_channel, unsigned char data)
+{
+	((struct smd_half_channel *)(half_channel))->fHEAD = data;
+}
+
+unsigned get_fHEAD(volatile void *half_channel)
+{
+	return ((struct smd_half_channel *)(half_channel))->fHEAD;
+}
+
+void set_fTAIL(volatile void *half_channel, unsigned char data)
+{
+	((struct smd_half_channel *)(half_channel))->fTAIL = data;
+}
+
+unsigned get_fTAIL(volatile void *half_channel)
+{
+	return ((struct smd_half_channel *)(half_channel))->fTAIL;
+}
+
+void set_fSTATE(volatile void *half_channel, unsigned char data)
+{
+	((struct smd_half_channel *)(half_channel))->fSTATE = data;
+}
+
+unsigned get_fSTATE(volatile void *half_channel)
+{
+	return ((struct smd_half_channel *)(half_channel))->fSTATE;
+}
+
+void set_fBLOCKREADINTR(volatile void *half_channel, unsigned char data)
+{
+	((struct smd_half_channel *)(half_channel))->fBLOCKREADINTR = data;
+}
+
+unsigned get_fBLOCKREADINTR(volatile void *half_channel)
+{
+	return ((struct smd_half_channel *)(half_channel))->fBLOCKREADINTR;
+}
+
+void set_tail(volatile void *half_channel, unsigned data)
+{
+	((struct smd_half_channel *)(half_channel))->tail = data;
+}
+
+unsigned get_tail(volatile void *half_channel)
+{
+	return ((struct smd_half_channel *)(half_channel))->tail;
+}
+
+void set_head(volatile void *half_channel, unsigned data)
+{
+	((struct smd_half_channel *)(half_channel))->head = data;
+}
+
+unsigned get_head(volatile void *half_channel)
+{
+	return ((struct smd_half_channel *)(half_channel))->head;
+}
+
+void set_state_word_access(volatile void *half_channel, unsigned data)
+{
+	((struct smd_half_channel_word_access *)(half_channel))->state = data;
+}
+
+unsigned get_state_word_access(volatile void *half_channel)
+{
+	return ((struct smd_half_channel_word_access *)(half_channel))->state;
+}
+
+void set_fDSR_word_access(volatile void *half_channel, unsigned char data)
+{
+	((struct smd_half_channel_word_access *)(half_channel))->fDSR = data;
+}
+
+unsigned get_fDSR_word_access(volatile void *half_channel)
+{
+	return ((struct smd_half_channel_word_access *)(half_channel))->fDSR;
+}
+
+void set_fCTS_word_access(volatile void *half_channel, unsigned char data)
+{
+	((struct smd_half_channel_word_access *)(half_channel))->fCTS = data;
+}
+
+unsigned get_fCTS_word_access(volatile void *half_channel)
+{
+	return ((struct smd_half_channel_word_access *)(half_channel))->fCTS;
+}
+
+void set_fCD_word_access(volatile void *half_channel, unsigned char data)
+{
+	((struct smd_half_channel_word_access *)(half_channel))->fCD = data;
+}
+
+unsigned get_fCD_word_access(volatile void *half_channel)
+{
+	return ((struct smd_half_channel_word_access *)(half_channel))->fCD;
+}
+
+void set_fRI_word_access(volatile void *half_channel, unsigned char data)
+{
+	((struct smd_half_channel_word_access *)(half_channel))->fRI = data;
+}
+
+unsigned get_fRI_word_access(volatile void *half_channel)
+{
+	return ((struct smd_half_channel_word_access *)(half_channel))->fRI;
+}
+
+void set_fHEAD_word_access(volatile void *half_channel, unsigned char data)
+{
+	((struct smd_half_channel_word_access *)(half_channel))->fHEAD = data;
+}
+
+unsigned get_fHEAD_word_access(volatile void *half_channel)
+{
+	return ((struct smd_half_channel_word_access *)(half_channel))->fHEAD;
+}
+
+void set_fTAIL_word_access(volatile void *half_channel, unsigned char data)
+{
+	((struct smd_half_channel_word_access *)(half_channel))->fTAIL = data;
+}
+
+unsigned get_fTAIL_word_access(volatile void *half_channel)
+{
+	return ((struct smd_half_channel_word_access *)(half_channel))->fTAIL;
+}
+
+void set_fSTATE_word_access(volatile void *half_channel, unsigned char data)
+{
+	((struct smd_half_channel_word_access *)(half_channel))->fSTATE = data;
+}
+
+unsigned get_fSTATE_word_access(volatile void *half_channel)
+{
+	return ((struct smd_half_channel_word_access *)(half_channel))->fSTATE;
+}
+
+void set_fBLOCKREADINTR_word_access(volatile void *half_channel,
+							unsigned char data)
+{
+	((struct smd_half_channel_word_access *)
+					(half_channel))->fBLOCKREADINTR = data;
+}
+
+unsigned get_fBLOCKREADINTR_word_access(volatile void *half_channel)
+{
+	return ((struct smd_half_channel_word_access *)
+						(half_channel))->fBLOCKREADINTR;
+}
+
+void set_tail_word_access(volatile void *half_channel, unsigned data)
+{
+	((struct smd_half_channel_word_access *)(half_channel))->tail = data;
+}
+
+unsigned get_tail_word_access(volatile void *half_channel)
+{
+	return ((struct smd_half_channel_word_access *)(half_channel))->tail;
+}
+
+void set_head_word_access(volatile void *half_channel, unsigned data)
+{
+	((struct smd_half_channel_word_access *)(half_channel))->head = data;
+}
+
+unsigned get_head_word_access(volatile void *half_channel)
+{
+	return ((struct smd_half_channel_word_access *)(half_channel))->head;
+}
+
+int is_word_access_ch(unsigned ch_type)
+{
+	if (ch_type == SMD_APPS_RPM || ch_type == SMD_MODEM_RPM ||
+		ch_type == SMD_QDSP_RPM || ch_type == SMD_WCNSS_RPM)
+		return 1;
+	else
+		return 0;
+}
+
+struct smd_half_channel_access *get_half_ch_funcs(unsigned ch_type)
+{
+	static struct smd_half_channel_access byte_access = {
+		.set_state = set_state,
+		.get_state = get_state,
+		.set_fDSR = set_fDSR,
+		.get_fDSR = get_fDSR,
+		.set_fCTS = set_fCTS,
+		.get_fCTS = get_fCTS,
+		.set_fCD = set_fCD,
+		.get_fCD = get_fCD,
+		.set_fRI = set_fRI,
+		.get_fRI = get_fRI,
+		.set_fHEAD = set_fHEAD,
+		.get_fHEAD = get_fHEAD,
+		.set_fTAIL = set_fTAIL,
+		.get_fTAIL = get_fTAIL,
+		.set_fSTATE = set_fSTATE,
+		.get_fSTATE = get_fSTATE,
+		.set_fBLOCKREADINTR = set_fBLOCKREADINTR,
+		.get_fBLOCKREADINTR = get_fBLOCKREADINTR,
+		.set_tail = set_tail,
+		.get_tail = get_tail,
+		.set_head = set_head,
+		.get_head = get_head,
+	};
+	static struct smd_half_channel_access word_access = {
+		.set_state = set_state_word_access,
+		.get_state = get_state_word_access,
+		.set_fDSR = set_fDSR_word_access,
+		.get_fDSR = get_fDSR_word_access,
+		.set_fCTS = set_fCTS_word_access,
+		.get_fCTS = get_fCTS_word_access,
+		.set_fCD = set_fCD_word_access,
+		.get_fCD = get_fCD_word_access,
+		.set_fRI = set_fRI_word_access,
+		.get_fRI = get_fRI_word_access,
+		.set_fHEAD = set_fHEAD_word_access,
+		.get_fHEAD = get_fHEAD_word_access,
+		.set_fTAIL = set_fTAIL_word_access,
+		.get_fTAIL = get_fTAIL_word_access,
+		.set_fSTATE = set_fSTATE_word_access,
+		.get_fSTATE = get_fSTATE_word_access,
+		.set_fBLOCKREADINTR = set_fBLOCKREADINTR_word_access,
+		.get_fBLOCKREADINTR = get_fBLOCKREADINTR_word_access,
+		.set_tail = set_tail_word_access,
+		.get_tail = get_tail_word_access,
+		.set_head = set_head_word_access,
+		.get_head = get_head_word_access,
+	};
+
+	if (is_word_access_ch(ch_type))
+		return &word_access;
+	else
+		return &byte_access;
+}
+
diff --git a/arch/arm/mach-msm/smd_private.h b/arch/arm/mach-msm/smd_private.h
index 727bfe6..9117280 100644
--- a/arch/arm/mach-msm/smd_private.h
+++ b/arch/arm/mach-msm/smd_private.h
@@ -1,7 +1,7 @@
 /* arch/arm/mach-msm/smd_private.h
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007 QUALCOMM Incorporated
+ * Copyright (c) 2007-2012, Code Aurora Forum. 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
@@ -16,12 +16,22 @@
 #ifndef _ARCH_ARM_MACH_MSM_MSM_SMD_PRIVATE_H_
 #define _ARCH_ARM_MACH_MSM_MSM_SMD_PRIVATE_H_
 
-#include <linux/platform_device.h>
+#include <linux/types.h>
 #include <linux/spinlock.h>
-#include <linux/list.h>
-#include <linux/io.h>
+#include <mach/msm_smsm.h>
+#include <mach/msm_smd.h>
 
-#include <mach/msm_iomap.h>
+#define PC_APPS  0
+#define PC_MODEM 1
+
+#define VERSION_QDSP6     4
+#define VERSION_APPS_SBL  6
+#define VERSION_MODEM_SBL 7
+#define VERSION_APPS      8
+#define VERSION_MODEM     9
+#define VERSION_DSPS      10
+
+#define SMD_HEAP_SIZE 512
 
 struct smem_heap_info {
 	unsigned initialized;
@@ -34,8 +44,9 @@
 	unsigned allocated;
 	unsigned offset;
 	unsigned size;
-	unsigned reserved;
+	unsigned reserved; /* bits 1:0 reserved, bits 31:2 aux smem base addr */
 };
+#define BASE_ADDR_MASK 0xfffffffc
 
 struct smem_proc_comm {
 	unsigned command;
@@ -44,47 +55,33 @@
 	unsigned data2;
 };
 
-#define PC_APPS  0
-#define PC_MODEM 1
-
-#define VERSION_SMD       0
-#define VERSION_QDSP6     4
-#define VERSION_APPS_SBL  6
-#define VERSION_MODEM_SBL 7
-#define VERSION_APPS      8
-#define VERSION_MODEM     9
-
 struct smem_shared {
 	struct smem_proc_comm proc_comm[4];
 	unsigned version[32];
 	struct smem_heap_info heap_info;
-	struct smem_heap_entry heap_toc[512];
+	struct smem_heap_entry heap_toc[SMD_HEAP_SIZE];
 };
 
-#define SMSM_V1_SIZE		(sizeof(unsigned) * 8)
-#define SMSM_V2_SIZE		(sizeof(unsigned) * 4)
-
-#ifdef CONFIG_MSM_SMD_PKG3
+#if defined(CONFIG_MSM_SMD_PKG4)
 struct smsm_interrupt_info {
-	uint32_t interrupt_mask;
-	uint32_t pending_interrupts;
-	uint32_t wakeup_reason;
+	uint32_t aArm_en_mask;
+	uint32_t aArm_interrupts_pending;
+	uint32_t aArm_wakeup_reason;
+	uint32_t aArm_rpc_prog;
+	uint32_t aArm_rpc_proc;
+	char aArm_smd_port_name[20];
+	uint32_t aArm_gpio_info;
 };
+#elif defined(CONFIG_MSM_SMD_PKG3)
+struct smsm_interrupt_info {
+  uint32_t aArm_en_mask;
+  uint32_t aArm_interrupts_pending;
+  uint32_t aArm_wakeup_reason;
+};
+#elif !defined(CONFIG_MSM_SMD)
+/* Don't trigger the error */
 #else
-#define DEM_MAX_PORT_NAME_LEN (20)
-struct msm_dem_slave_data {
-	uint32_t sleep_time;
-	uint32_t interrupt_mask;
-	uint32_t resources_used;
-	uint32_t reserved1;
-
-	uint32_t wakeup_reason;
-	uint32_t pending_interrupts;
-	uint32_t rpc_prog;
-	uint32_t rpc_proc;
-	char     smd_port_name[DEM_MAX_PORT_NAME_LEN];
-	uint32_t reserved2;
-};
+#error No SMD Package Specified; aborting
 #endif
 
 #define SZ_DIAG_ERR_MSG 0xC8
@@ -93,167 +90,34 @@
 #define ID_SHARED_STATE SMEM_SMSM_SHARED_STATE
 #define ID_CH_ALLOC_TBL SMEM_CHANNEL_ALLOC_TBL
 
-#define SMSM_INIT		0x00000001
-#define SMSM_SMDINIT		0x00000008
-#define SMSM_RPCINIT		0x00000020
-#define SMSM_RESET		0x00000040
-#define SMSM_RSA		0x00000080
-#define SMSM_RUN		0x00000100
-#define SMSM_PWRC		0x00000200
-#define SMSM_TIMEWAIT		0x00000400
-#define SMSM_TIMEINIT		0x00000800
-#define SMSM_PWRC_EARLY_EXIT	0x00001000
-#define SMSM_WFPI		0x00002000
-#define SMSM_SLEEP		0x00004000
-#define SMSM_SLEEPEXIT		0x00008000
-#define SMSM_APPS_REBOOT	0x00020000
-#define SMSM_SYSTEM_POWER_DOWN	0x00040000
-#define SMSM_SYSTEM_REBOOT	0x00080000
-#define SMSM_SYSTEM_DOWNLOAD	0x00100000
-#define SMSM_PWRC_SUSPEND	0x00200000
-#define SMSM_APPS_SHUTDOWN	0x00400000
-#define SMSM_SMD_LOOPBACK	0x00800000
-#define SMSM_RUN_QUIET		0x01000000
-#define SMSM_MODEM_WAIT		0x02000000
-#define SMSM_MODEM_BREAK	0x04000000
-#define SMSM_MODEM_CONTINUE	0x08000000
-#define SMSM_UNKNOWN		0x80000000
+#define SMD_SS_CLOSED            0x00000000
+#define SMD_SS_OPENING           0x00000001
+#define SMD_SS_OPENED            0x00000002
+#define SMD_SS_FLUSHING          0x00000003
+#define SMD_SS_CLOSING           0x00000004
+#define SMD_SS_RESET             0x00000005
+#define SMD_SS_RESET_OPENING     0x00000006
 
-#define SMSM_WKUP_REASON_RPC	0x00000001
-#define SMSM_WKUP_REASON_INT	0x00000002
-#define SMSM_WKUP_REASON_GPIO	0x00000004
-#define SMSM_WKUP_REASON_TIMER	0x00000008
-#define SMSM_WKUP_REASON_ALARM	0x00000010
-#define SMSM_WKUP_REASON_RESET	0x00000020
+#define SMD_BUF_SIZE             8192
+#define SMD_CHANNELS             64
+#define SMD_HEADER_SIZE          20
 
-#ifdef CONFIG_ARCH_MSM7X00A
-enum smsm_state_item {
-	SMSM_STATE_APPS = 1,
-	SMSM_STATE_MODEM = 3,
-	SMSM_STATE_COUNT,
-};
-#else
-enum smsm_state_item {
-	SMSM_STATE_APPS,
-	SMSM_STATE_MODEM,
-	SMSM_STATE_HEXAGON,
-	SMSM_STATE_APPS_DEM,
-	SMSM_STATE_MODEM_DEM,
-	SMSM_STATE_QDSP6_DEM,
-	SMSM_STATE_POWER_MASTER_DEM,
-	SMSM_STATE_TIME_MASTER_DEM,
-	SMSM_STATE_COUNT,
-};
-#endif
-
-void *smem_alloc(unsigned id, unsigned size);
-int smsm_change_state(enum smsm_state_item item, uint32_t clear_mask, uint32_t set_mask);
-uint32_t smsm_get_state(enum smsm_state_item item);
-int smsm_set_sleep_duration(uint32_t delay);
-void smsm_print_sleep_info(void);
-
-#define SMEM_NUM_SMD_CHANNELS        64
-
-typedef enum {
-	/* fixed items */
-	SMEM_PROC_COMM = 0,
-	SMEM_HEAP_INFO,
-	SMEM_ALLOCATION_TABLE,
-	SMEM_VERSION_INFO,
-	SMEM_HW_RESET_DETECT,
-	SMEM_AARM_WARM_BOOT,
-	SMEM_DIAG_ERR_MESSAGE,
-	SMEM_SPINLOCK_ARRAY,
-	SMEM_MEMORY_BARRIER_LOCATION,
-
-	/* dynamic items */
-	SMEM_AARM_PARTITION_TABLE,
-	SMEM_AARM_BAD_BLOCK_TABLE,
-	SMEM_RESERVE_BAD_BLOCKS,
-	SMEM_WM_UUID,
-	SMEM_CHANNEL_ALLOC_TBL,
-	SMEM_SMD_BASE_ID,
-	SMEM_SMEM_LOG_IDX = SMEM_SMD_BASE_ID + SMEM_NUM_SMD_CHANNELS,
-	SMEM_SMEM_LOG_EVENTS,
-	SMEM_SMEM_STATIC_LOG_IDX,
-	SMEM_SMEM_STATIC_LOG_EVENTS,
-	SMEM_SMEM_SLOW_CLOCK_SYNC,
-	SMEM_SMEM_SLOW_CLOCK_VALUE,
-	SMEM_BIO_LED_BUF,
-	SMEM_SMSM_SHARED_STATE,
-	SMEM_SMSM_INT_INFO,
-	SMEM_SMSM_SLEEP_DELAY,
-	SMEM_SMSM_LIMIT_SLEEP,
-	SMEM_SLEEP_POWER_COLLAPSE_DISABLED,
-	SMEM_KEYPAD_KEYS_PRESSED,
-	SMEM_KEYPAD_STATE_UPDATED,
-	SMEM_KEYPAD_STATE_IDX,
-	SMEM_GPIO_INT,
-	SMEM_MDDI_LCD_IDX,
-	SMEM_MDDI_HOST_DRIVER_STATE,
-	SMEM_MDDI_LCD_DISP_STATE,
-	SMEM_LCD_CUR_PANEL,
-	SMEM_MARM_BOOT_SEGMENT_INFO,
-	SMEM_AARM_BOOT_SEGMENT_INFO,
-	SMEM_SLEEP_STATIC,
-	SMEM_SCORPION_FREQUENCY,
-	SMEM_SMD_PROFILES,
-	SMEM_TSSC_BUSY,
-	SMEM_HS_SUSPEND_FILTER_INFO,
-	SMEM_BATT_INFO,
-	SMEM_APPS_BOOT_MODE,
-	SMEM_VERSION_FIRST,
-	SMEM_VERSION_LAST = SMEM_VERSION_FIRST + 24,
-	SMEM_OSS_RRCASN1_BUF1,
-	SMEM_OSS_RRCASN1_BUF2,
-	SMEM_ID_VENDOR0,
-	SMEM_ID_VENDOR1,
-	SMEM_ID_VENDOR2,
-	SMEM_HW_SW_BUILD_ID,
-	SMEM_SMD_BLOCK_PORT_BASE_ID,
-	SMEM_SMD_BLOCK_PORT_PROC0_HEAP = SMEM_SMD_BLOCK_PORT_BASE_ID + SMEM_NUM_SMD_CHANNELS,
-	SMEM_SMD_BLOCK_PORT_PROC1_HEAP = SMEM_SMD_BLOCK_PORT_PROC0_HEAP + SMEM_NUM_SMD_CHANNELS,
-	SMEM_I2C_MUTEX = SMEM_SMD_BLOCK_PORT_PROC1_HEAP + SMEM_NUM_SMD_CHANNELS,
-	SMEM_SCLK_CONVERSION,
-	SMEM_SMD_SMSM_INTR_MUX,
-	SMEM_SMSM_CPU_INTR_MASK,
-	SMEM_APPS_DEM_SLAVE_DATA,
-	SMEM_QDSP6_DEM_SLAVE_DATA,
-	SMEM_CLKREGIM_BSP,
-	SMEM_CLKREGIM_SOURCES,
-	SMEM_SMD_FIFO_BASE_ID,
-	SMEM_USABLE_RAM_PARTITION_TABLE = SMEM_SMD_FIFO_BASE_ID + SMEM_NUM_SMD_CHANNELS,
-	SMEM_POWER_ON_STATUS_INFO,
-	SMEM_DAL_AREA,
-	SMEM_SMEM_LOG_POWER_IDX,
-	SMEM_SMEM_LOG_POWER_WRAP,
-	SMEM_SMEM_LOG_POWER_EVENTS,
-	SMEM_ERR_CRASH_LOG,
-	SMEM_ERR_F3_TRACE_LOG,
-	SMEM_NUM_ITEMS,
-} smem_mem_type;
-
-
-#define SMD_SS_CLOSED		0x00000000
-#define SMD_SS_OPENING		0x00000001
-#define SMD_SS_OPENED		0x00000002
-#define SMD_SS_FLUSHING		0x00000003
-#define SMD_SS_CLOSING		0x00000004
-#define SMD_SS_RESET		0x00000005
-#define SMD_SS_RESET_OPENING	0x00000006
-
-#define SMD_BUF_SIZE		8192
-#define SMD_CHANNELS		64
-
-#define SMD_HEADER_SIZE		20
-
+/* 'type' field of smd_alloc_elm structure
+ * has the following breakup
+ * bits 0-7   -> channel type
+ * bits 8-11  -> xfer type
+ * bits 12-31 -> reserved
+ */
 struct smd_alloc_elm {
 	char name[20];
 	uint32_t cid;
-	uint32_t ctype;
+	uint32_t type;
 	uint32_t ref_count;
 };
 
+#define SMD_CHANNEL_TYPE(x) ((x) & 0x000000FF)
+#define SMD_XFER_TYPE(x)    (((x) & 0x00000F00) >> 8)
+
 struct smd_half_channel {
 	unsigned state;
 	unsigned char fDSR;
@@ -263,141 +127,139 @@
 	unsigned char fHEAD;
 	unsigned char fTAIL;
 	unsigned char fSTATE;
-	unsigned char fUNUSED;
+	unsigned char fBLOCKREADINTR;
 	unsigned tail;
 	unsigned head;
-} __attribute__(( aligned(4), packed ));
-
-/* Only used on SMD package v3 on msm7201a */
-struct smd_shared_v1 {
-	struct smd_half_channel ch0;
-	unsigned char data0[SMD_BUF_SIZE];
-	struct smd_half_channel ch1;
-	unsigned char data1[SMD_BUF_SIZE];
 };
 
-/* Used on SMD package v4 */
-struct smd_shared_v2 {
-	struct smd_half_channel ch0;
-	struct smd_half_channel ch1;
+struct smd_half_channel_word_access {
+	unsigned state;
+	unsigned fDSR;
+	unsigned fCTS;
+	unsigned fCD;
+	unsigned fRI;
+	unsigned fHEAD;
+	unsigned fTAIL;
+	unsigned fSTATE;
+	unsigned fBLOCKREADINTR;
+	unsigned tail;
+	unsigned head;
 };
 
-struct smd_channel {
-	volatile struct smd_half_channel *send;
-	volatile struct smd_half_channel *recv;
-	unsigned char *send_data;
-	unsigned char *recv_data;
+struct smd_half_channel_access {
+	void (*set_state)(volatile void *half_channel, unsigned data);
+	unsigned (*get_state)(volatile void *half_channel);
+	void (*set_fDSR)(volatile void *half_channel, unsigned char data);
+	unsigned (*get_fDSR)(volatile void *half_channel);
+	void (*set_fCTS)(volatile void *half_channel, unsigned char data);
+	unsigned (*get_fCTS)(volatile void *half_channel);
+	void (*set_fCD)(volatile void *half_channel, unsigned char data);
+	unsigned (*get_fCD)(volatile void *half_channel);
+	void (*set_fRI)(volatile void *half_channel, unsigned char data);
+	unsigned (*get_fRI)(volatile void *half_channel);
+	void (*set_fHEAD)(volatile void *half_channel, unsigned char data);
+	unsigned (*get_fHEAD)(volatile void *half_channel);
+	void (*set_fTAIL)(volatile void *half_channel, unsigned char data);
+	unsigned (*get_fTAIL)(volatile void *half_channel);
+	void (*set_fSTATE)(volatile void *half_channel, unsigned char data);
+	unsigned (*get_fSTATE)(volatile void *half_channel);
+	void (*set_fBLOCKREADINTR)(volatile void *half_channel,
+					unsigned char data);
+	unsigned (*get_fBLOCKREADINTR)(volatile void *half_channel);
+	void (*set_tail)(volatile void *half_channel, unsigned data);
+	unsigned (*get_tail)(volatile void *half_channel);
+	void (*set_head)(volatile void *half_channel, unsigned data);
+	unsigned (*get_head)(volatile void *half_channel);
+};
 
-	unsigned fifo_mask;
-	unsigned fifo_size;
-	unsigned current_packet;
-	unsigned n;
+int is_word_access_ch(unsigned ch_type);
 
-	struct list_head ch_list;
+struct smd_half_channel_access *get_half_ch_funcs(unsigned ch_type);
 
-	void *priv;
-	void (*notify)(void *priv, unsigned flags);
+struct smem_ram_ptn {
+	char name[16];
+	unsigned start;
+	unsigned size;
 
-	int (*read)(struct smd_channel *ch, void *data, int len);
-	int (*write)(struct smd_channel *ch, const void *data, int len);
-	int (*read_avail)(struct smd_channel *ch);
-	int (*write_avail)(struct smd_channel *ch);
+	/* RAM Partition attribute: READ_ONLY, READWRITE etc.  */
+	unsigned attr;
 
-	void (*update_state)(struct smd_channel *ch);
-	unsigned last_state;
-	void (*notify_other_cpu)(void);
+	/* RAM Partition category: EBI0, EBI1, IRAM, IMEM */
+	unsigned category;
+
+	/* RAM Partition domain: APPS, MODEM, APPS & MODEM (SHARED) etc. */
+	unsigned domain;
+
+	/* RAM Partition type: system, bootloader, appsboot, apps etc. */
 	unsigned type;
 
-	char name[32];
-	struct platform_device pdev;
+	/* reserved for future expansion without changing version number */
+	unsigned reserved2, reserved3, reserved4, reserved5;
+} __attribute__ ((__packed__));
+
+
+struct smem_ram_ptable {
+	#define _SMEM_RAM_PTABLE_MAGIC_1 0x9DA5E0A8
+	#define _SMEM_RAM_PTABLE_MAGIC_2 0xAF9EC4E2
+	unsigned magic[2];
+	unsigned version;
+	unsigned reserved1;
+	unsigned len;
+	struct smem_ram_ptn parts[32];
+	unsigned buf;
+} __attribute__ ((__packed__));
+
+/* SMEM RAM Partition */
+enum {
+	DEFAULT_ATTRB = ~0x0,
+	READ_ONLY = 0x0,
+	READWRITE,
 };
 
-#define SMD_TYPE_MASK		0x0FF
-#define SMD_TYPE_APPS_MODEM	0x000
-#define SMD_TYPE_APPS_DSP	0x001
-#define SMD_TYPE_MODEM_DSP	0x002
+enum {
+	DEFAULT_CATEGORY = ~0x0,
+	SMI = 0x0,
+	EBI1,
+	EBI2,
+	QDSP6,
+	IRAM,
+	IMEM,
+	EBI0_CS0,
+	EBI0_CS1,
+	EBI1_CS0,
+	EBI1_CS1,
+	SDRAM = 0xE,
+};
 
-#define SMD_KIND_MASK		0xF00
-#define SMD_KIND_UNKNOWN	0x000
-#define SMD_KIND_STREAM		0x100
-#define SMD_KIND_PACKET		0x200
+enum {
+	DEFAULT_DOMAIN = 0x0,
+	APPS_DOMAIN,
+	MODEM_DOMAIN,
+	SHARED_DOMAIN,
+};
 
-extern struct list_head smd_ch_closed_list;
-extern struct list_head smd_ch_list_modem;
-extern struct list_head smd_ch_list_dsp;
+enum {
+	SYS_MEMORY = 1,        /* system memory*/
+	BOOT_REGION_MEMORY1,   /* boot loader memory 1*/
+	BOOT_REGION_MEMORY2,   /* boot loader memory 2,reserved*/
+	APPSBL_MEMORY,         /* apps boot loader memory*/
+	APPS_MEMORY,           /* apps  usage memory*/
+};
 
-extern spinlock_t smd_lock;
 extern spinlock_t smem_lock;
 
-void *smem_find(unsigned id, unsigned size);
-void *smem_item(unsigned id, unsigned *size);
-uint32_t raw_smsm_get_state(enum smsm_state_item item);
 
-extern void msm_init_last_radio_log(struct module *);
+void smd_diag(void);
 
-#ifdef CONFIG_MSM_SMD_PKG3
-/*
- * This allocator assumes an SMD Package v3 which only exists on
- * MSM7x00 SoC's.
- */
-static inline int _smd_alloc_channel(struct smd_channel *ch)
-{
-	struct smd_shared_v1 *shared1;
+struct interrupt_stat {
+	uint32_t smd_in_count;
+	uint32_t smd_out_hardcode_count;
+	uint32_t smd_out_config_count;
 
-	shared1 = smem_alloc(ID_SMD_CHANNELS + ch->n, sizeof(*shared1));
-	if (!shared1) {
-		pr_err("smd_alloc_channel() cid %d does not exist\n", ch->n);
-		return -1;
-	}
-	ch->send = &shared1->ch0;
-	ch->recv = &shared1->ch1;
-	ch->send_data = shared1->data0;
-	ch->recv_data = shared1->data1;
-	ch->fifo_size = SMD_BUF_SIZE;
-	return 0;
-}
-#else
-/*
- * This allocator assumes an SMD Package v4, the most common
- * and the default.
- */
-static inline int _smd_alloc_channel(struct smd_channel *ch)
-{
-	struct smd_shared_v2 *shared2;
-	void *buffer;
-	unsigned buffer_sz;
-
-	shared2 = smem_alloc(SMEM_SMD_BASE_ID + ch->n, sizeof(*shared2));
-	buffer = smem_item(SMEM_SMD_FIFO_BASE_ID + ch->n, &buffer_sz);
-
-	if (!buffer)
-		return -1;
-
-	/* buffer must be a power-of-two size */
-	if (buffer_sz & (buffer_sz - 1))
-		return -1;
-
-	buffer_sz /= 2;
-	ch->send = &shared2->ch0;
-	ch->recv = &shared2->ch1;
-	ch->send_data = buffer;
-	ch->recv_data = buffer + buffer_sz;
-	ch->fifo_size = buffer_sz;
-	return 0;
-}
-#endif /* CONFIG_MSM_SMD_PKG3 */
-
-#if defined(CONFIG_ARCH_MSM7X30)
-static inline void msm_a2m_int(uint32_t irq)
-{
-	writel(1 << irq, MSM_GCC_BASE + 0x8);
-}
-#else
-static inline void msm_a2m_int(uint32_t irq)
-{
-	writel(1, MSM_CSR_BASE + 0x400 + (irq * 4));
-}
-#endif /* CONFIG_ARCH_MSM7X30 */
-
+	uint32_t smsm_in_count;
+	uint32_t smsm_out_hardcode_count;
+	uint32_t smsm_out_config_count;
+};
+extern struct interrupt_stat interrupt_stats[NUM_SMD_SUBSYSTEMS];
 
 #endif
diff --git a/arch/arm/mach-msm/smd_qmi.c b/arch/arm/mach-msm/smd_qmi.c
new file mode 100644
index 0000000..ca10f00
--- /dev/null
+++ b/arch/arm/mach-msm/smd_qmi.c
@@ -0,0 +1,848 @@
+/* arch/arm/mach-msm/smd_qmi.c
+ *
+ * QMI Control Driver -- Manages network data connections.
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/miscdevice.h>
+#include <linux/workqueue.h>
+#include <linux/wakelock.h>
+
+#include <asm/uaccess.h>
+#include <mach/msm_smd.h>
+
+#define QMI_CTL 0x00
+#define QMI_WDS 0x01
+#define QMI_DMS 0x02
+#define QMI_NAS 0x03
+
+#define QMI_RESULT_SUCCESS 0x0000
+#define QMI_RESULT_FAILURE 0x0001
+
+struct qmi_msg {
+	unsigned char service;
+	unsigned char client_id;
+	unsigned short txn_id;
+	unsigned short type;
+	unsigned short size;
+	unsigned char *tlv;
+};
+
+#define qmi_ctl_client_id 0
+
+#define STATE_OFFLINE    0
+#define STATE_QUERYING   1
+#define STATE_ONLINE     2
+
+struct qmi_ctxt {
+	struct miscdevice misc;
+
+	struct mutex lock;
+
+	unsigned char ctl_txn_id;
+	unsigned char wds_client_id;
+	unsigned short wds_txn_id;
+
+	unsigned wds_busy;
+	unsigned wds_handle;
+	unsigned state_dirty;
+	unsigned state;
+
+	unsigned char addr[4];
+	unsigned char mask[4];
+	unsigned char gateway[4];
+	unsigned char dns1[4];
+	unsigned char dns2[4];
+
+	smd_channel_t *ch;
+	const char *ch_name;
+	struct wake_lock wake_lock;
+
+	struct work_struct open_work;
+	struct work_struct read_work;
+};
+
+static struct qmi_ctxt *qmi_minor_to_ctxt(unsigned n);
+
+static void qmi_read_work(struct work_struct *ws);
+static void qmi_open_work(struct work_struct *work);
+
+void qmi_ctxt_init(struct qmi_ctxt *ctxt, unsigned n)
+{
+	mutex_init(&ctxt->lock);
+	INIT_WORK(&ctxt->read_work, qmi_read_work);
+	INIT_WORK(&ctxt->open_work, qmi_open_work);
+	wake_lock_init(&ctxt->wake_lock, WAKE_LOCK_SUSPEND, ctxt->misc.name);
+	ctxt->ctl_txn_id = 1;
+	ctxt->wds_txn_id = 1;
+	ctxt->wds_busy = 1;
+	ctxt->state = STATE_OFFLINE;
+
+}
+
+static struct workqueue_struct *qmi_wq;
+
+static int verbose = 0;
+
+/* anyone waiting for a state change waits here */
+static DECLARE_WAIT_QUEUE_HEAD(qmi_wait_queue);
+
+
+static void qmi_dump_msg(struct qmi_msg *msg, const char *prefix)
+{
+	unsigned sz, n;
+	unsigned char *x;
+
+	if (!verbose)
+		return;
+
+	printk(KERN_INFO
+	       "qmi: %s: svc=%02x cid=%02x tid=%04x type=%04x size=%04x\n",
+	       prefix, msg->service, msg->client_id,
+	       msg->txn_id, msg->type, msg->size);
+
+	x = msg->tlv;
+	sz = msg->size;
+
+	while (sz >= 3) {
+		sz -= 3;
+
+		n = x[1] | (x[2] << 8);
+		if (n > sz)
+			break;
+
+		printk(KERN_INFO "qmi: %s: tlv: %02x %04x { ",
+		       prefix, x[0], n);
+		x += 3;
+		sz -= n;
+		while (n-- > 0)
+			printk("%02x ", *x++);
+		printk("}\n");
+	}
+}
+
+int qmi_add_tlv(struct qmi_msg *msg,
+		unsigned type, unsigned size, const void *data)
+{
+	unsigned char *x = msg->tlv + msg->size;
+
+	x[0] = type;
+	x[1] = size;
+	x[2] = size >> 8;
+
+	memcpy(x + 3, data, size);
+
+	msg->size += (size + 3);
+
+	return 0;
+}
+
+/* Extract a tagged item from a qmi message buffer,
+** taking care not to overrun the buffer.
+*/
+static int qmi_get_tlv(struct qmi_msg *msg,
+		       unsigned type, unsigned size, void *data)
+{
+	unsigned char *x = msg->tlv;
+	unsigned len = msg->size;
+	unsigned n;
+
+	while (len >= 3) {
+		len -= 3;
+
+		/* size of this item */
+		n = x[1] | (x[2] << 8);
+		if (n > len)
+			break;
+
+		if (x[0] == type) {
+			if (n != size)
+				return -1;
+			memcpy(data, x + 3, size);
+			return 0;
+		}
+
+		x += (n + 3);
+		len -= n;
+	}
+
+	return -1;
+}
+
+static unsigned qmi_get_status(struct qmi_msg *msg, unsigned *error)
+{
+	unsigned short status[2];
+	if (qmi_get_tlv(msg, 0x02, sizeof(status), status)) {
+		*error = 0;
+		return QMI_RESULT_FAILURE;
+	} else {
+		*error = status[1];
+		return status[0];
+	}
+}
+
+/* 0x01 <qmux-header> <payload> */
+#define QMUX_HEADER    13
+
+/* should be >= HEADER + FOOTER */
+#define QMUX_OVERHEAD  16
+
+static int qmi_send(struct qmi_ctxt *ctxt, struct qmi_msg *msg)
+{
+	unsigned char *data;
+	unsigned hlen;
+	unsigned len;
+	int r;
+
+	qmi_dump_msg(msg, "send");
+
+	if (msg->service == QMI_CTL) {
+		hlen = QMUX_HEADER - 1;
+	} else {
+		hlen = QMUX_HEADER;
+	}
+
+	/* QMUX length is total header + total payload - IFC selector */
+	len = hlen + msg->size - 1;
+	if (len > 0xffff)
+		return -1;
+
+	data = msg->tlv - hlen;
+
+	/* prepend encap and qmux header */
+	*data++ = 0x01; /* ifc selector */
+
+	/* qmux header */
+	*data++ = len;
+	*data++ = len >> 8;
+	*data++ = 0x00; /* flags: client */
+	*data++ = msg->service;
+	*data++ = msg->client_id;
+
+	/* qmi header */
+	*data++ = 0x00; /* flags: send */
+	*data++ = msg->txn_id;
+	if (msg->service != QMI_CTL)
+		*data++ = msg->txn_id >> 8;
+
+	*data++ = msg->type;
+	*data++ = msg->type >> 8;
+	*data++ = msg->size;
+	*data++ = msg->size >> 8;
+
+	/* len + 1 takes the interface selector into account */
+	r = smd_write(ctxt->ch, msg->tlv - hlen, len + 1);
+
+	if (r != len) {
+		return -1;
+	} else {
+		return 0;
+	}
+}
+
+static void qmi_process_ctl_msg(struct qmi_ctxt *ctxt, struct qmi_msg *msg)
+{
+	unsigned err;
+	if (msg->type == 0x0022) {
+		unsigned char n[2];
+		if (qmi_get_status(msg, &err))
+			return;
+		if (qmi_get_tlv(msg, 0x01, sizeof(n), n))
+			return;
+		if (n[0] == QMI_WDS) {
+			printk(KERN_INFO
+			       "qmi: ctl: wds use client_id 0x%02x\n", n[1]);
+			ctxt->wds_client_id = n[1];
+			ctxt->wds_busy = 0;
+		}
+	}
+}
+
+static int qmi_network_get_profile(struct qmi_ctxt *ctxt);
+
+static void swapaddr(unsigned char *src, unsigned char *dst)
+{
+	dst[0] = src[3];
+	dst[1] = src[2];
+	dst[2] = src[1];
+	dst[3] = src[0];
+}
+
+static unsigned char zero[4];
+static void qmi_read_runtime_profile(struct qmi_ctxt *ctxt, struct qmi_msg *msg)
+{
+	unsigned char tmp[4];
+	unsigned r;
+
+	r = qmi_get_tlv(msg, 0x1e, 4, tmp);
+	swapaddr(r ? zero : tmp, ctxt->addr);
+	r = qmi_get_tlv(msg, 0x21, 4, tmp);
+	swapaddr(r ? zero : tmp, ctxt->mask);
+	r = qmi_get_tlv(msg, 0x20, 4, tmp);
+	swapaddr(r ? zero : tmp, ctxt->gateway);
+	r = qmi_get_tlv(msg, 0x15, 4, tmp);
+	swapaddr(r ? zero : tmp, ctxt->dns1);
+	r = qmi_get_tlv(msg, 0x16, 4, tmp);
+	swapaddr(r ? zero : tmp, ctxt->dns2);
+}
+
+static void qmi_process_unicast_wds_msg(struct qmi_ctxt *ctxt,
+					struct qmi_msg *msg)
+{
+	unsigned err;
+	switch (msg->type) {
+	case 0x0021:
+		if (qmi_get_status(msg, &err)) {
+			printk(KERN_ERR
+			       "qmi: wds: network stop failed (%04x)\n", err);
+		} else {
+			printk(KERN_INFO
+			       "qmi: wds: network stopped\n");
+			ctxt->state = STATE_OFFLINE;
+			ctxt->state_dirty = 1;
+		}
+		break;
+	case 0x0020:
+		if (qmi_get_status(msg, &err)) {
+			printk(KERN_ERR
+			       "qmi: wds: network start failed (%04x)\n", err);
+		} else if (qmi_get_tlv(msg, 0x01, sizeof(ctxt->wds_handle), &ctxt->wds_handle)) {
+			printk(KERN_INFO
+			       "qmi: wds no handle?\n");
+		} else {
+			printk(KERN_INFO
+			       "qmi: wds: got handle 0x%08x\n",
+			       ctxt->wds_handle);
+		}
+		break;
+	case 0x002D:
+		printk("qmi: got network profile\n");
+		if (ctxt->state == STATE_QUERYING) {
+			qmi_read_runtime_profile(ctxt, msg);
+			ctxt->state = STATE_ONLINE;
+			ctxt->state_dirty = 1;
+		}
+		break;
+	default:
+		printk(KERN_ERR "qmi: unknown msg type 0x%04x\n", msg->type);
+	}
+	ctxt->wds_busy = 0;
+}
+
+static void qmi_process_broadcast_wds_msg(struct qmi_ctxt *ctxt,
+					  struct qmi_msg *msg)
+{
+	if (msg->type == 0x0022) {
+		unsigned char n[2];
+		if (qmi_get_tlv(msg, 0x01, sizeof(n), n))
+			return;
+		switch (n[0]) {
+		case 1:
+			printk(KERN_INFO "qmi: wds: DISCONNECTED\n");
+			ctxt->state = STATE_OFFLINE;
+			ctxt->state_dirty = 1;
+			break;
+		case 2:
+			printk(KERN_INFO "qmi: wds: CONNECTED\n");
+			ctxt->state = STATE_QUERYING;
+			ctxt->state_dirty = 1;
+			qmi_network_get_profile(ctxt);
+			break;
+		case 3:
+			printk(KERN_INFO "qmi: wds: SUSPENDED\n");
+			ctxt->state = STATE_OFFLINE;
+			ctxt->state_dirty = 1;
+		}
+	} else {
+		printk(KERN_ERR "qmi: unknown bcast msg type 0x%04x\n", msg->type);
+	}
+}
+
+static void qmi_process_wds_msg(struct qmi_ctxt *ctxt,
+				struct qmi_msg *msg)
+{
+	printk("wds: %04x @ %02x\n", msg->type, msg->client_id);
+	if (msg->client_id == ctxt->wds_client_id) {
+		qmi_process_unicast_wds_msg(ctxt, msg);
+	} else if (msg->client_id == 0xff) {
+		qmi_process_broadcast_wds_msg(ctxt, msg);
+	} else {
+		printk(KERN_ERR
+		       "qmi_process_wds_msg client id 0x%02x unknown\n",
+		       msg->client_id);
+	}
+}
+
+static void qmi_process_qmux(struct qmi_ctxt *ctxt,
+			     unsigned char *buf, unsigned sz)
+{
+	struct qmi_msg msg;
+
+	/* require a full header */
+	if (sz < 5)
+		return;
+
+	/* require a size that matches the buffer size */
+	if (sz != (buf[0] | (buf[1] << 8)))
+		return;
+
+	/* only messages from a service (bit7=1) are allowed */
+	if (buf[2] != 0x80)
+		return;
+
+	msg.service = buf[3];
+	msg.client_id = buf[4];
+
+	/* annoyingly, CTL messages have a shorter TID */
+	if (buf[3] == 0) {
+		if (sz < 7)
+			return;
+		msg.txn_id = buf[6];
+		buf += 7;
+		sz -= 7;
+	} else {
+		if (sz < 8)
+			return;
+		msg.txn_id = buf[6] | (buf[7] << 8);
+		buf += 8;
+		sz -= 8;
+	}
+
+	/* no type and size!? */
+	if (sz < 4)
+		return;
+	sz -= 4;
+
+	msg.type = buf[0] | (buf[1] << 8);
+	msg.size = buf[2] | (buf[3] << 8);
+	msg.tlv = buf + 4;
+
+	if (sz != msg.size)
+		return;
+
+	qmi_dump_msg(&msg, "recv");
+
+	mutex_lock(&ctxt->lock);
+	switch (msg.service) {
+	case QMI_CTL:
+		qmi_process_ctl_msg(ctxt, &msg);
+		break;
+	case QMI_WDS:
+		qmi_process_wds_msg(ctxt, &msg);
+		break;
+	default:
+		printk(KERN_ERR "qmi: msg from unknown svc 0x%02x\n",
+		       msg.service);
+		break;
+	}
+	mutex_unlock(&ctxt->lock);
+
+	wake_up(&qmi_wait_queue);
+}
+
+#define QMI_MAX_PACKET (256 + QMUX_OVERHEAD)
+
+static void qmi_read_work(struct work_struct *ws)
+{
+	struct qmi_ctxt *ctxt = container_of(ws, struct qmi_ctxt, read_work);
+	struct smd_channel *ch = ctxt->ch;
+	unsigned char buf[QMI_MAX_PACKET];
+	int sz;
+
+	for (;;) {
+		sz = smd_cur_packet_size(ch);
+		if (sz == 0)
+			break;
+		if (sz < smd_read_avail(ch))
+			break;
+		if (sz > QMI_MAX_PACKET) {
+			smd_read(ch, 0, sz);
+			continue;
+		}
+		if (smd_read(ch, buf, sz) != sz) {
+			printk(KERN_ERR "qmi: not enough data?!\n");
+			continue;
+		}
+
+		/* interface selector must be 1 */
+		if (buf[0] != 0x01)
+			continue;
+
+		qmi_process_qmux(ctxt, buf + 1, sz - 1);
+	}
+}
+
+static int qmi_request_wds_cid(struct qmi_ctxt *ctxt);
+
+static void qmi_open_work(struct work_struct *ws)
+{
+	struct qmi_ctxt *ctxt = container_of(ws, struct qmi_ctxt, open_work);
+	mutex_lock(&ctxt->lock);
+	qmi_request_wds_cid(ctxt);
+	mutex_unlock(&ctxt->lock);
+}
+
+static void qmi_notify(void *priv, unsigned event)
+{
+	struct qmi_ctxt *ctxt = priv;
+	
+	switch (event) {
+	case SMD_EVENT_DATA: {
+		int sz;
+		sz = smd_cur_packet_size(ctxt->ch);
+		if ((sz > 0) && (sz <= smd_read_avail(ctxt->ch))) {
+			wake_lock_timeout(&ctxt->wake_lock, HZ / 2);
+			queue_work(qmi_wq, &ctxt->read_work);
+		}
+		break;
+	}
+	case SMD_EVENT_OPEN:
+		printk(KERN_INFO "qmi: smd opened\n");
+		queue_work(qmi_wq, &ctxt->open_work);
+		break;
+	case SMD_EVENT_CLOSE:
+		printk(KERN_INFO "qmi: smd closed\n");
+		break;
+	}
+}
+
+static int qmi_request_wds_cid(struct qmi_ctxt *ctxt)
+{
+	unsigned char data[64 + QMUX_OVERHEAD];
+	struct qmi_msg msg;
+	unsigned char n;
+
+	msg.service = QMI_CTL;
+	msg.client_id = qmi_ctl_client_id;
+	msg.txn_id = ctxt->ctl_txn_id;
+	msg.type = 0x0022;
+	msg.size = 0;
+	msg.tlv = data + QMUX_HEADER;
+
+	ctxt->ctl_txn_id += 2;
+
+	n = QMI_WDS;
+	qmi_add_tlv(&msg, 0x01, 0x01, &n);
+
+	return qmi_send(ctxt, &msg);
+}
+
+static int qmi_network_get_profile(struct qmi_ctxt *ctxt)
+{
+	unsigned char data[96 + QMUX_OVERHEAD];
+	struct qmi_msg msg;
+
+	msg.service = QMI_WDS;
+	msg.client_id = ctxt->wds_client_id;
+	msg.txn_id = ctxt->wds_txn_id;
+	msg.type = 0x002D;
+	msg.size = 0;
+	msg.tlv = data + QMUX_HEADER;
+
+	ctxt->wds_txn_id += 2;
+
+	return qmi_send(ctxt, &msg);
+}
+
+static int qmi_network_up(struct qmi_ctxt *ctxt, char *apn)
+{
+	unsigned char data[96 + QMUX_OVERHEAD];
+	struct qmi_msg msg;
+	char *user;
+	char *pass;
+
+	for (user = apn; *user; user++) {
+		if (*user == ' ') {
+			*user++ = 0;
+			break;
+		}
+	}
+	for (pass = user; *pass; pass++) {
+		if (*pass == ' ') {
+			*pass++ = 0;
+			break;
+		}
+	}
+
+	msg.service = QMI_WDS;
+	msg.client_id = ctxt->wds_client_id;
+	msg.txn_id = ctxt->wds_txn_id;
+	msg.type = 0x0020;
+	msg.size = 0;
+	msg.tlv = data + QMUX_HEADER;
+
+	ctxt->wds_txn_id += 2;
+
+	qmi_add_tlv(&msg, 0x14, strlen(apn), apn);
+	if (*user) {
+		unsigned char x;
+		x = 3;
+		qmi_add_tlv(&msg, 0x16, 1, &x);
+		qmi_add_tlv(&msg, 0x17, strlen(user), user);
+		if (*pass)
+			qmi_add_tlv(&msg, 0x18, strlen(pass), pass);
+	}
+	return qmi_send(ctxt, &msg);
+}
+
+static int qmi_network_down(struct qmi_ctxt *ctxt)
+{
+	unsigned char data[16 + QMUX_OVERHEAD];
+	struct qmi_msg msg;
+
+	msg.service = QMI_WDS;
+	msg.client_id = ctxt->wds_client_id;
+	msg.txn_id = ctxt->wds_txn_id;
+	msg.type = 0x0021;
+	msg.size = 0;
+	msg.tlv = data + QMUX_HEADER;
+
+	ctxt->wds_txn_id += 2;
+
+	qmi_add_tlv(&msg, 0x01, sizeof(ctxt->wds_handle), &ctxt->wds_handle);
+
+	return qmi_send(ctxt, &msg);
+}
+
+static int qmi_print_state(struct qmi_ctxt *ctxt, char *buf, int max)
+{
+	int i;
+	char *statename;
+
+	if (ctxt->state == STATE_ONLINE) {
+		statename = "up";
+	} else if (ctxt->state == STATE_OFFLINE) {
+		statename = "down";
+	} else {
+		statename = "busy";
+	}
+
+	i = scnprintf(buf, max, "STATE=%s\n", statename);
+	i += scnprintf(buf + i, max - i, "CID=%d\n",ctxt->wds_client_id);
+
+	if (ctxt->state != STATE_ONLINE){
+		return i;
+	}
+
+	i += scnprintf(buf + i, max - i, "ADDR=%d.%d.%d.%d\n",
+		ctxt->addr[0], ctxt->addr[1], ctxt->addr[2], ctxt->addr[3]);
+	i += scnprintf(buf + i, max - i, "MASK=%d.%d.%d.%d\n",
+		ctxt->mask[0], ctxt->mask[1], ctxt->mask[2], ctxt->mask[3]);
+	i += scnprintf(buf + i, max - i, "GATEWAY=%d.%d.%d.%d\n",
+		ctxt->gateway[0], ctxt->gateway[1], ctxt->gateway[2],
+		ctxt->gateway[3]);
+	i += scnprintf(buf + i, max - i, "DNS1=%d.%d.%d.%d\n",
+		ctxt->dns1[0], ctxt->dns1[1], ctxt->dns1[2], ctxt->dns1[3]);
+	i += scnprintf(buf + i, max - i, "DNS2=%d.%d.%d.%d\n",
+		ctxt->dns2[0], ctxt->dns2[1], ctxt->dns2[2], ctxt->dns2[3]);
+
+	return i;
+}
+
+static ssize_t qmi_read(struct file *fp, char __user *buf,
+			size_t count, loff_t *pos)
+{
+	struct qmi_ctxt *ctxt = fp->private_data;
+	char msg[256];
+	int len;
+	int r;
+
+	mutex_lock(&ctxt->lock);
+	for (;;) {
+		if (ctxt->state_dirty) {
+			ctxt->state_dirty = 0;
+			len = qmi_print_state(ctxt, msg, 256);
+			break;
+		}
+		mutex_unlock(&ctxt->lock);
+		r = wait_event_interruptible(qmi_wait_queue, ctxt->state_dirty);
+		if (r < 0)
+			return r;
+		mutex_lock(&ctxt->lock);
+	}
+	mutex_unlock(&ctxt->lock);
+
+	if (len > count)
+		len = count;
+
+	if (copy_to_user(buf, msg, len))
+		return -EFAULT;
+
+	return len;
+}
+
+
+static ssize_t qmi_write(struct file *fp, const char __user *buf,
+			 size_t count, loff_t *pos)
+{
+	struct qmi_ctxt *ctxt = fp->private_data;
+	unsigned char cmd[64];
+	int len;
+	int r;
+
+	if (count < 1)
+		return 0;
+
+	len = count > 63 ? 63 : count;
+
+	if (copy_from_user(cmd, buf, len))
+		return -EFAULT;
+
+	cmd[len] = 0;
+
+	/* lazy */
+	if (cmd[len-1] == '\n') {
+		cmd[len-1] = 0;
+		len--;
+	}
+
+	if (!strncmp(cmd, "verbose", 7)) {
+		verbose = 1;
+	} else if (!strncmp(cmd, "terse", 5)) {
+		verbose = 0;
+	} else if (!strncmp(cmd, "poll", 4)) {
+		ctxt->state_dirty = 1;
+		wake_up(&qmi_wait_queue);
+	} else if (!strncmp(cmd, "down", 4)) {
+retry_down:
+		mutex_lock(&ctxt->lock);
+		if (ctxt->wds_busy) {
+			mutex_unlock(&ctxt->lock);
+			r = wait_event_interruptible(qmi_wait_queue, !ctxt->wds_busy);
+			if (r < 0)
+				return r;
+			goto retry_down;
+		}
+		ctxt->wds_busy = 1;
+		qmi_network_down(ctxt);
+		mutex_unlock(&ctxt->lock);
+	} else if (!strncmp(cmd, "up:", 3)) {
+retry_up:
+		mutex_lock(&ctxt->lock);
+		if (ctxt->wds_busy) {
+			mutex_unlock(&ctxt->lock);
+			r = wait_event_interruptible(qmi_wait_queue, !ctxt->wds_busy);
+			if (r < 0)
+				return r;
+			goto retry_up;
+		}
+		ctxt->wds_busy = 1;
+		qmi_network_up(ctxt, cmd+3);
+		mutex_unlock(&ctxt->lock);
+	} else {
+		return -EINVAL;
+	}
+
+	return count;
+}
+
+static int qmi_open(struct inode *ip, struct file *fp)
+{
+	struct qmi_ctxt *ctxt = qmi_minor_to_ctxt(MINOR(ip->i_rdev));
+	int r = 0;
+
+	if (!ctxt) {
+		printk(KERN_ERR "unknown qmi misc %d\n", MINOR(ip->i_rdev));
+		return -ENODEV;
+	}
+
+	fp->private_data = ctxt;
+
+	mutex_lock(&ctxt->lock);
+	if (ctxt->ch == 0)
+		r = smd_open(ctxt->ch_name, &ctxt->ch, ctxt, qmi_notify);
+	if (r == 0)
+		wake_up(&qmi_wait_queue);
+	mutex_unlock(&ctxt->lock);
+
+	return r;
+}
+
+static int qmi_release(struct inode *ip, struct file *fp)
+{
+	return 0;
+}
+
+static struct file_operations qmi_fops = {
+	.owner = THIS_MODULE,
+	.read = qmi_read,
+	.write = qmi_write,
+	.open = qmi_open,
+	.release = qmi_release,
+};
+
+static struct qmi_ctxt qmi_device0 = {
+	.ch_name = "SMD_DATA5_CNTL",
+	.misc = {
+		.minor = MISC_DYNAMIC_MINOR,
+		.name = "qmi0",
+		.fops = &qmi_fops,
+	}
+};
+static struct qmi_ctxt qmi_device1 = {
+	.ch_name = "SMD_DATA6_CNTL",
+	.misc = {
+		.minor = MISC_DYNAMIC_MINOR,
+		.name = "qmi1",
+		.fops = &qmi_fops,
+	}
+};
+static struct qmi_ctxt qmi_device2 = {
+	.ch_name = "SMD_DATA7_CNTL",
+	.misc = {
+		.minor = MISC_DYNAMIC_MINOR,
+		.name = "qmi2",
+		.fops = &qmi_fops,
+	}
+};
+
+static struct qmi_ctxt *qmi_minor_to_ctxt(unsigned n)
+{
+	if (n == qmi_device0.misc.minor)
+		return &qmi_device0;
+	if (n == qmi_device1.misc.minor)
+		return &qmi_device1;
+	if (n == qmi_device2.misc.minor)
+		return &qmi_device2;
+	return 0;
+}
+
+static int __init qmi_init(void)
+{
+	int ret;
+
+	qmi_wq = create_singlethread_workqueue("qmi");
+	if (qmi_wq == 0)
+		return -ENOMEM;
+
+	qmi_ctxt_init(&qmi_device0, 0);
+	qmi_ctxt_init(&qmi_device1, 1);
+	qmi_ctxt_init(&qmi_device2, 2);
+
+	ret = misc_register(&qmi_device0.misc);
+	if (ret == 0)
+		ret = misc_register(&qmi_device1.misc);
+	if (ret == 0)
+		ret = misc_register(&qmi_device2.misc);
+	return ret;
+}
+
+module_init(qmi_init);
diff --git a/arch/arm/mach-msm/smd_rpc_sym b/arch/arm/mach-msm/smd_rpc_sym
new file mode 100755
index 0000000..6965cf6
--- /dev/null
+++ b/arch/arm/mach-msm/smd_rpc_sym
@@ -0,0 +1,156 @@
+0x30000000  cm
+0x30000001  db
+0x30000002  snd
+0x30000003  wms
+0x30000004  pdsm
+0x30000005  misc_modem_apis
+0x30000006  misc_apps_apis
+0x30000007  joyst
+0x3000000A  adsprtosatom
+0x3000000B  adsprtosmtoa
+0x3000000C  i2c
+0x3000000D  time_remote
+0x3000000E  nv
+0x3000000F  clkrgm_sec
+0x30000010  rdevmap
+0x30000012  pbmlib
+0x30000013  audmgr
+0x30000014  mvs
+0x30000015  dog_keepalive
+0x30000016  gsdi_exp
+0x30000017  auth
+0x30000018  nvruimi
+0x30000019  mmgsdilib
+0x3000001A  charger
+0x3000001B  uim
+0x3000001D  pdsm_atl
+0x3000001E  fs_xmount
+0x3000001F  secutil
+0x30000020  mccmeid
+0x30000021  pm_strobe_flash
+0x30000023  smd_bridge
+0x30000024  smd_port_mgr
+0x30000025  bus_perf
+0x30000026  bus_mon_remote
+0x30000027  mc
+0x30000028  mccap
+0x30000029  mccdma
+0x3000002A  mccds
+0x3000002B  mccsch
+0x3000002C  mccsrid
+0x3000002D  snm
+0x3000002E  mccsyobj
+0x30000031  dsrlp_apis
+0x30000032  rlp_apis
+0x30000033  ds_mp_shim_modem
+0x30000035  dshdr_mdm_apis
+0x30000036  ds_mp_shim_apps
+0x30000037  hdrmc_apis
+0x3000003A  pmapp_otg
+0x3000003B  diag
+0x3000003C  gstk_exp
+0x3000003D  dsbc_mdm_apis
+0x3000003E  hdrmrlp_mdm_apis
+0x30000040  hdrmc_mrlp_apis
+0x30000041  pdcomm_app_api
+0x30000042  dsat_apis
+0x30000043  rfm
+0x30000044  cmipapp
+0x30000045  dsmp_umts_modem_apis
+0x30000047  dsucsdmpshim
+0x30000048  time_remote_atom
+0x3000004A  sd
+0x3000004B  mmoc
+0x3000004D  wlan_cp_cm
+0x3000004E  ftm_wlan
+0x30000050  CprmInterface
+0x30000051  data_on_modem_mtoa_apis
+0x30000053  misc_modem_apis_nonwinmob
+0x30000054  misc_apps_apis_nonwinmob
+0x30000055  pmem_remote
+0x30000056  tcxomgr
+0x30000058  bt
+0x30000059  pd_comms_api
+0x3000005A  pd_comms_client_api
+0x3000005B  pdapi
+0x3000005D  time_remote_mtoa
+0x3000005E  ftm_bt
+0x3000005F  dsucsdappif_apis
+0x30000060  pmapp_gen
+0x30000061  pm_lib
+0x30000063  hsu_app_apis
+0x30000064  hsu_mdm_apis
+0x30000065  adie_adc_remote_atom
+0x30000066  tlmm_remote_atom
+0x30000067  ui_callctrl
+0x30000068  uiutils
+0x30000069  prl
+0x3000006A  hw
+0x3000006B  oem_rapi
+0x3000006C  wmspm
+0x3000006D  btpf
+0x3000006F  usb_apps_rpc
+0x30000070  usb_modem_rpc
+0x30000071  adc
+0x30000072  cameraremoted
+0x30000073  secapiremoted
+0x30000074  dsatapi
+0x30000075  clkctl_rpc
+0x30000076  BrewAppCoord
+0x30000078  wlan_trp_utils
+0x30000079  gpio_rpc
+0x3000007C  l1_ds
+0x3000007F  oss_rrcasn_remote
+0x30000080  pmapp_otg_remote
+0x30000081  ping_mdm_rpc
+0x30000087  ukcc_ipc_apis
+0x30000089  vbatt_remote
+0x3000008A  mfpal_fps
+0x3000008B  dsumtspdpreg
+0x3000008C  loc_api
+0x3000008E  cmgan
+0x3000008F  isense
+0x30000090  time_secure
+0x30000091  hs_rem
+0x30000092  acdb
+0x30000093  net
+0x30000094  led
+0x30000095  dspae
+0x30000096  mfkal
+0x3000009B  test_api
+0x3000009C  remotefs_srv_api
+0x3000009D  isi_transport
+0x3000009E  oem_ftm
+0x3000009F  touch_screen_adc
+0x300000A0  smd_bridge_apps
+0x300000A1  smd_bridge_modem
+0x300000A2  dog_keepalive_modem
+0x300000A3  voem_if
+0x300000A4  npa_remote
+0x300000A5  mmgsdisessionlib
+0x300000A6  ifta_remote
+0x300000A7  remote_storage
+0x300000A8  mf_remote_file
+0x300000A9  mfsc_chunked_transport
+0x300000AA  mfim3
+0x300000AB  fm_wan_api
+0x300000AC  wlan_rapi
+0x300000AD  dsmgr_apis
+0x300100AE  cm_mm_fusion
+0x30010081  ping_lte_rpc
+0x30010061  pm_lib_fusion
+0x3001000E  nv_fusion
+0x30010003  wms_fusion
+0x3001001B  uim_fusion
+0x30010012  pbmlib_fusion
+0x3001003C  gstk_exp_fusion
+0x30010000  cm_fusion
+0x3001006B  oem_rapi_fusion
+0x3001000F  clkrgm_sec_fusion
+0x300100A0  smd_bridge_apps_fusion
+0x300100A1  smd_bridge_modem_fusion
+0x30010024  smd_port_mgr_fusion
+0x30010019  mmgsdilib_fusion
+0x300100A5  mmgsdisessionlib_fusion
+0x3001009C  remotefs_srv_api_fusion
+0x30010016  gsdi_exp_fusion
diff --git a/arch/arm/mach-msm/smd_rpc_sym.h b/arch/arm/mach-msm/smd_rpc_sym.h
new file mode 100644
index 0000000..e9a8b47
--- /dev/null
+++ b/arch/arm/mach-msm/smd_rpc_sym.h
@@ -0,0 +1,37 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _ARCH_ARM_MACH_MSM_SMD_RPC_SYM_H
+#define _ARCH_ARM_MACH_MSM_SMD_RPC_SYM_H
+
+#if defined(CONFIG_DEBUG_FS)
+const char *smd_rpc_get_sym(uint32_t val);
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/smd_rpcrouter.c b/arch/arm/mach-msm/smd_rpcrouter.c
new file mode 100644
index 0000000..983d0c1
--- /dev/null
+++ b/arch/arm/mach-msm/smd_rpcrouter.c
@@ -0,0 +1,2531 @@
+/* arch/arm/mach-msm/smd_rpcrouter.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2011, Code Aurora Forum. All rights reserved.
+ * Author: San Mehat <san@android.com>
+ *
+ * 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.
+ *
+ */
+
+/* TODO: handle cases where smd_write() will tempfail due to full fifo */
+/* TODO: thread priority? schedule a work to bump it? */
+/* TODO: maybe make server_list_lock a mutex */
+/* TODO: pool fragments to avoid kmalloc/kfree churn */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/cdev.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/err.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/wakelock.h>
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+
+#include <asm/byteorder.h>
+
+#include <mach/msm_smd.h>
+#include <mach/smem_log.h>
+#include <mach/subsystem_notif.h>
+
+#include "smd_rpcrouter.h"
+#include "modem_notifier.h"
+#include "smd_rpc_sym.h"
+#include "smd_private.h"
+
+enum {
+	SMEM_LOG = 1U << 0,
+	RTR_DBG = 1U << 1,
+	R2R_MSG = 1U << 2,
+	R2R_RAW = 1U << 3,
+	RPC_MSG = 1U << 4,
+	NTFY_MSG = 1U << 5,
+	RAW_PMR = 1U << 6,
+	RAW_PMW = 1U << 7,
+	R2R_RAW_HDR = 1U << 8,
+};
+static int msm_rpc_connect_timeout_ms;
+module_param_named(connect_timeout, msm_rpc_connect_timeout_ms,
+		   int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+static int smd_rpcrouter_debug_mask;
+module_param_named(debug_mask, smd_rpcrouter_debug_mask,
+		   int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#define DIAG(x...) printk(KERN_ERR "[RR] ERROR " x)
+
+#if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG)
+#define D(x...) do { \
+if (smd_rpcrouter_debug_mask & RTR_DBG) \
+	printk(KERN_ERR x); \
+} while (0)
+
+#define RR(x...) do { \
+if (smd_rpcrouter_debug_mask & R2R_MSG) \
+	printk(KERN_ERR "[RR] "x); \
+} while (0)
+
+#define RAW(x...) do { \
+if (smd_rpcrouter_debug_mask & R2R_RAW) \
+	printk(KERN_ERR "[RAW] "x); \
+} while (0)
+
+#define RAW_HDR(x...) do { \
+if (smd_rpcrouter_debug_mask & R2R_RAW_HDR) \
+	printk(KERN_ERR "[HDR] "x); \
+} while (0)
+
+#define RAW_PMR(x...) do { \
+if (smd_rpcrouter_debug_mask & RAW_PMR) \
+	printk(KERN_ERR "[PMR] "x); \
+} while (0)
+
+#define RAW_PMR_NOMASK(x...) do { \
+	printk(KERN_ERR "[PMR] "x); \
+} while (0)
+
+#define RAW_PMW(x...) do { \
+if (smd_rpcrouter_debug_mask & RAW_PMW) \
+	printk(KERN_ERR "[PMW] "x); \
+} while (0)
+
+#define RAW_PMW_NOMASK(x...) do { \
+	printk(KERN_ERR "[PMW] "x); \
+} while (0)
+
+#define IO(x...) do { \
+if (smd_rpcrouter_debug_mask & RPC_MSG) \
+	printk(KERN_ERR "[RPC] "x); \
+} while (0)
+
+#define NTFY(x...) do { \
+if (smd_rpcrouter_debug_mask & NTFY_MSG) \
+	printk(KERN_ERR "[NOTIFY] "x); \
+} while (0)
+#else
+#define D(x...) do { } while (0)
+#define RR(x...) do { } while (0)
+#define RAW(x...) do { } while (0)
+#define RAW_HDR(x...) do { } while (0)
+#define RAW_PMR(x...) do { } while (0)
+#define RAW_PMR_NO_MASK(x...) do { } while (0)
+#define RAW_PMW(x...) do { } while (0)
+#define RAW_PMW_NO_MASK(x...) do { } while (0)
+#define IO(x...) do { } while (0)
+#define NTFY(x...) do { } while (0)
+#endif
+
+
+static LIST_HEAD(local_endpoints);
+static LIST_HEAD(remote_endpoints);
+
+static LIST_HEAD(server_list);
+
+static wait_queue_head_t newserver_wait;
+static wait_queue_head_t subsystem_restart_wait;
+
+static DEFINE_SPINLOCK(local_endpoints_lock);
+static DEFINE_SPINLOCK(remote_endpoints_lock);
+static DEFINE_SPINLOCK(server_list_lock);
+
+static LIST_HEAD(rpc_board_dev_list);
+static DEFINE_SPINLOCK(rpc_board_dev_list_lock);
+
+static struct workqueue_struct *rpcrouter_workqueue;
+
+static atomic_t next_xid = ATOMIC_INIT(1);
+static atomic_t pm_mid = ATOMIC_INIT(1);
+
+static void do_read_data(struct work_struct *work);
+static void do_create_pdevs(struct work_struct *work);
+static void do_create_rpcrouter_pdev(struct work_struct *work);
+
+static DECLARE_WORK(work_create_pdevs, do_create_pdevs);
+static DECLARE_WORK(work_create_rpcrouter_pdev, do_create_rpcrouter_pdev);
+
+#define RR_STATE_IDLE    0
+#define RR_STATE_HEADER  1
+#define RR_STATE_BODY    2
+#define RR_STATE_ERROR   3
+
+/* State for remote ep following restart */
+#define RESTART_QUOTA_ABORT  1
+
+struct rr_context {
+	struct rr_packet *pkt;
+	uint8_t *ptr;
+	uint32_t state; /* current assembly state */
+	uint32_t count; /* bytes needed in this state */
+};
+
+struct rr_context the_rr_context;
+
+struct rpc_board_dev_info {
+	struct list_head list;
+
+	struct rpc_board_dev *dev;
+};
+
+static struct platform_device rpcrouter_pdev = {
+	.name		= "oncrpc_router",
+	.id		= -1,
+};
+
+struct rpcrouter_xprt_info {
+	struct list_head list;
+
+	struct rpcrouter_xprt *xprt;
+
+	int remote_pid;
+	uint32_t initialized;
+	wait_queue_head_t read_wait;
+	struct wake_lock wakelock;
+	spinlock_t lock;
+	uint32_t need_len;
+	struct work_struct read_data;
+	struct workqueue_struct *workqueue;
+	int abort_data_read;
+	unsigned char r2r_buf[RPCROUTER_MSGSIZE_MAX];
+};
+
+static LIST_HEAD(xprt_info_list);
+static DEFINE_MUTEX(xprt_info_list_lock);
+
+DECLARE_COMPLETION(rpc_remote_router_up);
+static atomic_t pending_close_count = ATOMIC_INIT(0);
+
+/*
+ * Search for transport (xprt) that matches the provided PID.
+ *
+ * Note: The calling function must ensure that the mutex
+ *       xprt_info_list_lock is locked when this function
+ *       is called.
+ *
+ * @remote_pid	Remote PID for the transport
+ *
+ * @returns Pointer to transport or NULL if not found
+ */
+static struct rpcrouter_xprt_info *rpcrouter_get_xprt_info(uint32_t remote_pid)
+{
+	struct rpcrouter_xprt_info *xprt_info;
+
+	list_for_each_entry(xprt_info, &xprt_info_list, list) {
+		if (xprt_info->remote_pid == remote_pid)
+			return xprt_info;
+	}
+	return NULL;
+}
+
+static int rpcrouter_send_control_msg(struct rpcrouter_xprt_info *xprt_info,
+				      union rr_control_msg *msg)
+{
+	struct rr_header hdr;
+	unsigned long flags = 0;
+	int need;
+
+	if (xprt_info->remote_pid == RPCROUTER_PID_LOCAL)
+		return 0;
+
+	if (!(msg->cmd == RPCROUTER_CTRL_CMD_HELLO) &&
+	    !xprt_info->initialized) {
+		printk(KERN_ERR "rpcrouter_send_control_msg(): Warning, "
+		       "router not initialized\n");
+		return -EINVAL;
+	}
+
+	hdr.version = RPCROUTER_VERSION;
+	hdr.type = msg->cmd;
+	hdr.src_pid = RPCROUTER_PID_LOCAL;
+	hdr.src_cid = RPCROUTER_ROUTER_ADDRESS;
+	hdr.confirm_rx = 0;
+	hdr.size = sizeof(*msg);
+	hdr.dst_pid = xprt_info->remote_pid;
+	hdr.dst_cid = RPCROUTER_ROUTER_ADDRESS;
+
+	/* TODO: what if channel is full? */
+
+	need = sizeof(hdr) + hdr.size;
+	spin_lock_irqsave(&xprt_info->lock, flags);
+	while (xprt_info->xprt->write_avail() < need) {
+		spin_unlock_irqrestore(&xprt_info->lock, flags);
+		msleep(250);
+		spin_lock_irqsave(&xprt_info->lock, flags);
+	}
+	xprt_info->xprt->write(&hdr, sizeof(hdr), HEADER);
+	xprt_info->xprt->write(msg, hdr.size, PAYLOAD);
+	spin_unlock_irqrestore(&xprt_info->lock, flags);
+
+	return 0;
+}
+
+static void modem_reset_cleanup(struct rpcrouter_xprt_info *xprt_info)
+{
+	struct msm_rpc_endpoint *ept;
+	struct rr_remote_endpoint *r_ept;
+	struct rr_packet *pkt, *tmp_pkt;
+	struct rr_fragment *frag, *next;
+	struct msm_rpc_reply *reply, *reply_tmp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&local_endpoints_lock, flags);
+	/* remove all partial packets received */
+	list_for_each_entry(ept, &local_endpoints, list) {
+		RR("%s EPT DST PID %x, remote_pid:%d\n", __func__,
+			ept->dst_pid, xprt_info->remote_pid);
+
+		if (xprt_info->remote_pid != ept->dst_pid)
+			continue;
+
+		D("calling teardown cb %p\n", ept->cb_restart_teardown);
+		if (ept->cb_restart_teardown)
+			ept->cb_restart_teardown(ept->client_data);
+		ept->do_setup_notif = 1;
+
+		/* remove replies */
+		spin_lock(&ept->reply_q_lock);
+		list_for_each_entry_safe(reply, reply_tmp,
+					 &ept->reply_pend_q, list) {
+			list_del(&reply->list);
+			kfree(reply);
+		}
+		list_for_each_entry_safe(reply, reply_tmp,
+					 &ept->reply_avail_q, list) {
+			list_del(&reply->list);
+			kfree(reply);
+		}
+		ept->reply_cnt = 0;
+		spin_unlock(&ept->reply_q_lock);
+
+		/* Set restart state for local ep */
+		RR("EPT:0x%p, State %d  RESTART_PEND_NTFY_SVR "
+			"PROG:0x%08x VERS:0x%08x\n",
+			ept, ept->restart_state,
+			be32_to_cpu(ept->dst_prog),
+			be32_to_cpu(ept->dst_vers));
+		spin_lock(&ept->restart_lock);
+		ept->restart_state = RESTART_PEND_NTFY_SVR;
+
+		/* remove incomplete packets */
+		spin_lock(&ept->incomplete_lock);
+		list_for_each_entry_safe(pkt, tmp_pkt,
+					 &ept->incomplete, list) {
+			list_del(&pkt->list);
+			frag = pkt->first;
+			while (frag != NULL) {
+				next = frag->next;
+				kfree(frag);
+				frag = next;
+			}
+			kfree(pkt);
+		}
+		spin_unlock(&ept->incomplete_lock);
+
+		/* remove all completed packets waiting to be read */
+		spin_lock(&ept->read_q_lock);
+		list_for_each_entry_safe(pkt, tmp_pkt, &ept->read_q,
+					 list) {
+			list_del(&pkt->list);
+			frag = pkt->first;
+			while (frag != NULL) {
+				next = frag->next;
+				kfree(frag);
+				frag = next;
+			}
+			kfree(pkt);
+		}
+		spin_unlock(&ept->read_q_lock);
+
+		spin_unlock(&ept->restart_lock);
+		wake_up(&ept->wait_q);
+	}
+
+	spin_unlock_irqrestore(&local_endpoints_lock, flags);
+
+    /* Unblock endpoints waiting for quota ack*/
+	spin_lock_irqsave(&remote_endpoints_lock, flags);
+	list_for_each_entry(r_ept, &remote_endpoints, list) {
+		spin_lock(&r_ept->quota_lock);
+		r_ept->quota_restart_state = RESTART_QUOTA_ABORT;
+		RR("Set STATE_PENDING PID:0x%08x CID:0x%08x \n", r_ept->pid,
+		   r_ept->cid);
+		spin_unlock(&r_ept->quota_lock);
+		wake_up(&r_ept->quota_wait);
+	}
+	spin_unlock_irqrestore(&remote_endpoints_lock, flags);
+}
+
+static void modem_reset_startup(struct rpcrouter_xprt_info *xprt_info)
+{
+	struct msm_rpc_endpoint *ept;
+	unsigned long flags;
+
+	spin_lock_irqsave(&local_endpoints_lock, flags);
+
+	/* notify all endpoints that we are coming back up */
+	list_for_each_entry(ept, &local_endpoints, list) {
+		RR("%s EPT DST PID %x, remote_pid:%d\n", __func__,
+			ept->dst_pid, xprt_info->remote_pid);
+
+		if (xprt_info->remote_pid != ept->dst_pid)
+			continue;
+
+		D("calling setup cb %d:%p\n", ept->do_setup_notif,
+					ept->cb_restart_setup);
+		if (ept->do_setup_notif && ept->cb_restart_setup)
+			ept->cb_restart_setup(ept->client_data);
+		ept->do_setup_notif = 0;
+	}
+
+	spin_unlock_irqrestore(&local_endpoints_lock, flags);
+}
+
+/*
+ * Blocks and waits for endpoint if a reset is in progress.
+ *
+ * @returns
+ *    ENETRESET     Reset is in progress and a notification needed
+ *    ERESTARTSYS   Signal occurred
+ *    0             Reset is not in progress
+ */
+static int wait_for_restart_and_notify(struct msm_rpc_endpoint *ept)
+{
+	unsigned long flags;
+	int ret = 0;
+	DEFINE_WAIT(__wait);
+
+	for (;;) {
+		prepare_to_wait(&ept->restart_wait, &__wait,
+				TASK_INTERRUPTIBLE);
+
+		spin_lock_irqsave(&ept->restart_lock, flags);
+		if (ept->restart_state == RESTART_NORMAL) {
+			spin_unlock_irqrestore(&ept->restart_lock, flags);
+			break;
+		} else if (ept->restart_state & RESTART_PEND_NTFY) {
+			ept->restart_state &= ~RESTART_PEND_NTFY;
+			spin_unlock_irqrestore(&ept->restart_lock, flags);
+			ret = -ENETRESET;
+			break;
+		}
+		if (signal_pending(current) &&
+		   ((!(ept->flags & MSM_RPC_UNINTERRUPTIBLE)))) {
+			spin_unlock_irqrestore(&ept->restart_lock, flags);
+			ret = -ERESTARTSYS;
+			break;
+		}
+		spin_unlock_irqrestore(&ept->restart_lock, flags);
+		schedule();
+	}
+	finish_wait(&ept->restart_wait, &__wait);
+	return ret;
+}
+
+static struct rr_server *rpcrouter_create_server(uint32_t pid,
+							uint32_t cid,
+							uint32_t prog,
+							uint32_t ver)
+{
+	struct rr_server *server;
+	unsigned long flags;
+	int rc;
+
+	server = kmalloc(sizeof(struct rr_server), GFP_KERNEL);
+	if (!server)
+		return ERR_PTR(-ENOMEM);
+
+	memset(server, 0, sizeof(struct rr_server));
+	server->pid = pid;
+	server->cid = cid;
+	server->prog = prog;
+	server->vers = ver;
+
+	spin_lock_irqsave(&server_list_lock, flags);
+	list_add_tail(&server->list, &server_list);
+	spin_unlock_irqrestore(&server_list_lock, flags);
+
+	rc = msm_rpcrouter_create_server_cdev(server);
+	if (rc < 0)
+		goto out_fail;
+
+	return server;
+out_fail:
+	spin_lock_irqsave(&server_list_lock, flags);
+	list_del(&server->list);
+	spin_unlock_irqrestore(&server_list_lock, flags);
+	kfree(server);
+	return ERR_PTR(rc);
+}
+
+static void rpcrouter_destroy_server(struct rr_server *server)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&server_list_lock, flags);
+	list_del(&server->list);
+	spin_unlock_irqrestore(&server_list_lock, flags);
+	device_destroy(msm_rpcrouter_class, server->device_number);
+	kfree(server);
+}
+
+int msm_rpc_add_board_dev(struct rpc_board_dev *devices, int num)
+{
+	unsigned long flags;
+	struct rpc_board_dev_info *board_info;
+	int i;
+
+	for (i = 0; i < num; i++) {
+		board_info = kzalloc(sizeof(struct rpc_board_dev_info),
+				     GFP_KERNEL);
+		if (!board_info)
+			return -ENOMEM;
+
+		board_info->dev = &devices[i];
+		D("%s: adding program %x\n", __func__, board_info->dev->prog);
+		spin_lock_irqsave(&rpc_board_dev_list_lock, flags);
+		list_add_tail(&board_info->list, &rpc_board_dev_list);
+		spin_unlock_irqrestore(&rpc_board_dev_list_lock, flags);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_rpc_add_board_dev);
+
+static void rpcrouter_register_board_dev(struct rr_server *server)
+{
+	struct rpc_board_dev_info *board_info;
+	unsigned long flags;
+	int rc;
+
+	spin_lock_irqsave(&rpc_board_dev_list_lock, flags);
+	list_for_each_entry(board_info, &rpc_board_dev_list, list) {
+		if (server->prog == board_info->dev->prog) {
+			D("%s: registering device %x\n",
+			  __func__, board_info->dev->prog);
+			list_del(&board_info->list);
+			rc = platform_device_register(&board_info->dev->pdev);
+			if (rc)
+				pr_err("%s: board dev register failed %d\n",
+				       __func__, rc);
+			kfree(board_info);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&rpc_board_dev_list_lock, flags);
+}
+
+static struct rr_server *rpcrouter_lookup_server(uint32_t prog, uint32_t ver)
+{
+	struct rr_server *server;
+	unsigned long flags;
+
+	spin_lock_irqsave(&server_list_lock, flags);
+	list_for_each_entry(server, &server_list, list) {
+		if (server->prog == prog
+		 && server->vers == ver) {
+			spin_unlock_irqrestore(&server_list_lock, flags);
+			return server;
+		}
+	}
+	spin_unlock_irqrestore(&server_list_lock, flags);
+	return NULL;
+}
+
+static struct rr_server *rpcrouter_lookup_server_by_dev(dev_t dev)
+{
+	struct rr_server *server;
+	unsigned long flags;
+
+	spin_lock_irqsave(&server_list_lock, flags);
+	list_for_each_entry(server, &server_list, list) {
+		if (server->device_number == dev) {
+			spin_unlock_irqrestore(&server_list_lock, flags);
+			return server;
+		}
+	}
+	spin_unlock_irqrestore(&server_list_lock, flags);
+	return NULL;
+}
+
+struct msm_rpc_endpoint *msm_rpcrouter_create_local_endpoint(dev_t dev)
+{
+	struct msm_rpc_endpoint *ept;
+	unsigned long flags;
+
+	ept = kmalloc(sizeof(struct msm_rpc_endpoint), GFP_KERNEL);
+	if (!ept)
+		return NULL;
+	memset(ept, 0, sizeof(struct msm_rpc_endpoint));
+	ept->cid = (uint32_t) ept;
+	ept->pid = RPCROUTER_PID_LOCAL;
+	ept->dev = dev;
+
+	if ((dev != msm_rpcrouter_devno) && (dev != MKDEV(0, 0))) {
+		struct rr_server *srv;
+		/*
+		 * This is a userspace client which opened
+		 * a program/ver devicenode. Bind the client
+		 * to that destination
+		 */
+		srv = rpcrouter_lookup_server_by_dev(dev);
+		/* TODO: bug? really? */
+		BUG_ON(!srv);
+
+		ept->dst_pid = srv->pid;
+		ept->dst_cid = srv->cid;
+		ept->dst_prog = cpu_to_be32(srv->prog);
+		ept->dst_vers = cpu_to_be32(srv->vers);
+	} else {
+		/* mark not connected */
+		ept->dst_pid = 0xffffffff;
+	}
+
+	init_waitqueue_head(&ept->wait_q);
+	INIT_LIST_HEAD(&ept->read_q);
+	spin_lock_init(&ept->read_q_lock);
+	INIT_LIST_HEAD(&ept->reply_avail_q);
+	INIT_LIST_HEAD(&ept->reply_pend_q);
+	spin_lock_init(&ept->reply_q_lock);
+	spin_lock_init(&ept->restart_lock);
+	init_waitqueue_head(&ept->restart_wait);
+	ept->restart_state = RESTART_NORMAL;
+	wake_lock_init(&ept->read_q_wake_lock, WAKE_LOCK_SUSPEND, "rpc_read");
+	wake_lock_init(&ept->reply_q_wake_lock, WAKE_LOCK_SUSPEND, "rpc_reply");
+	INIT_LIST_HEAD(&ept->incomplete);
+	spin_lock_init(&ept->incomplete_lock);
+
+	spin_lock_irqsave(&local_endpoints_lock, flags);
+	list_add_tail(&ept->list, &local_endpoints);
+	spin_unlock_irqrestore(&local_endpoints_lock, flags);
+	return ept;
+}
+
+int msm_rpcrouter_destroy_local_endpoint(struct msm_rpc_endpoint *ept)
+{
+	int rc;
+	union rr_control_msg msg;
+	struct msm_rpc_reply *reply, *reply_tmp;
+	unsigned long flags;
+	struct rpcrouter_xprt_info *xprt_info;
+
+	/* Endpoint with dst_pid = 0xffffffff corresponds to that of
+	** router port. So don't send a REMOVE CLIENT message while
+	** destroying it.*/
+	spin_lock_irqsave(&local_endpoints_lock, flags);
+	list_del(&ept->list);
+	spin_unlock_irqrestore(&local_endpoints_lock, flags);
+	if (ept->dst_pid != 0xffffffff) {
+		msg.cmd = RPCROUTER_CTRL_CMD_REMOVE_CLIENT;
+		msg.cli.pid = ept->pid;
+		msg.cli.cid = ept->cid;
+
+		RR("x REMOVE_CLIENT id=%d:%08x\n", ept->pid, ept->cid);
+		mutex_lock(&xprt_info_list_lock);
+		list_for_each_entry(xprt_info, &xprt_info_list, list) {
+			rc = rpcrouter_send_control_msg(xprt_info, &msg);
+			if (rc < 0) {
+				mutex_unlock(&xprt_info_list_lock);
+				return rc;
+			}
+		}
+		mutex_unlock(&xprt_info_list_lock);
+	}
+
+	/* Free replies */
+	spin_lock_irqsave(&ept->reply_q_lock, flags);
+	list_for_each_entry_safe(reply, reply_tmp, &ept->reply_pend_q, list) {
+		list_del(&reply->list);
+		kfree(reply);
+	}
+	list_for_each_entry_safe(reply, reply_tmp, &ept->reply_avail_q, list) {
+		list_del(&reply->list);
+		kfree(reply);
+	}
+	spin_unlock_irqrestore(&ept->reply_q_lock, flags);
+
+	wake_lock_destroy(&ept->read_q_wake_lock);
+	wake_lock_destroy(&ept->reply_q_wake_lock);
+	kfree(ept);
+	return 0;
+}
+
+static int rpcrouter_create_remote_endpoint(uint32_t pid, uint32_t cid)
+{
+	struct rr_remote_endpoint *new_c;
+	unsigned long flags;
+
+	new_c = kmalloc(sizeof(struct rr_remote_endpoint), GFP_KERNEL);
+	if (!new_c)
+		return -ENOMEM;
+	memset(new_c, 0, sizeof(struct rr_remote_endpoint));
+
+	new_c->cid = cid;
+	new_c->pid = pid;
+	init_waitqueue_head(&new_c->quota_wait);
+	spin_lock_init(&new_c->quota_lock);
+
+	spin_lock_irqsave(&remote_endpoints_lock, flags);
+	list_add_tail(&new_c->list, &remote_endpoints);
+	new_c->quota_restart_state = RESTART_NORMAL;
+	spin_unlock_irqrestore(&remote_endpoints_lock, flags);
+	return 0;
+}
+
+static struct msm_rpc_endpoint *rpcrouter_lookup_local_endpoint(uint32_t cid)
+{
+	struct msm_rpc_endpoint *ept;
+
+	list_for_each_entry(ept, &local_endpoints, list) {
+		if (ept->cid == cid)
+			return ept;
+	}
+	return NULL;
+}
+
+static struct rr_remote_endpoint *rpcrouter_lookup_remote_endpoint(uint32_t pid,
+								   uint32_t cid)
+{
+	struct rr_remote_endpoint *ept;
+	unsigned long flags;
+
+	spin_lock_irqsave(&remote_endpoints_lock, flags);
+	list_for_each_entry(ept, &remote_endpoints, list) {
+		if ((ept->pid == pid) && (ept->cid == cid)) {
+			spin_unlock_irqrestore(&remote_endpoints_lock, flags);
+			return ept;
+		}
+	}
+	spin_unlock_irqrestore(&remote_endpoints_lock, flags);
+	return NULL;
+}
+
+static void handle_server_restart(struct rr_server *server,
+				  uint32_t pid, uint32_t cid,
+				  uint32_t prog, uint32_t vers)
+{
+	struct rr_remote_endpoint *r_ept;
+	struct msm_rpc_endpoint *ept;
+	unsigned long flags;
+	r_ept = rpcrouter_lookup_remote_endpoint(pid, cid);
+	if (r_ept && (r_ept->quota_restart_state !=
+		      RESTART_NORMAL)) {
+		spin_lock_irqsave(&r_ept->quota_lock, flags);
+		r_ept->tx_quota_cntr = 0;
+		r_ept->quota_restart_state =
+		RESTART_NORMAL;
+		spin_unlock_irqrestore(&r_ept->quota_lock, flags);
+		D(KERN_INFO "rpcrouter: Remote EPT Reset %0x\n",
+			   (unsigned int)r_ept);
+		wake_up(&r_ept->quota_wait);
+	}
+	spin_lock_irqsave(&local_endpoints_lock, flags);
+	list_for_each_entry(ept, &local_endpoints, list) {
+		if ((be32_to_cpu(ept->dst_prog) == prog) &&
+		    (be32_to_cpu(ept->dst_vers) == vers) &&
+		    (ept->restart_state & RESTART_PEND_SVR)) {
+			spin_lock(&ept->restart_lock);
+			ept->restart_state &= ~RESTART_PEND_SVR;
+			spin_unlock(&ept->restart_lock);
+			D("rpcrouter: Local EPT Reset %08x:%08x \n",
+			  prog, vers);
+			wake_up(&ept->restart_wait);
+			wake_up(&ept->wait_q);
+		}
+	}
+	spin_unlock_irqrestore(&local_endpoints_lock, flags);
+}
+
+static int process_control_msg(struct rpcrouter_xprt_info *xprt_info,
+			       union rr_control_msg *msg, int len)
+{
+	union rr_control_msg ctl;
+	struct rr_server *server;
+	struct rr_remote_endpoint *r_ept;
+	int rc = 0;
+	unsigned long flags;
+	static int first = 1;
+
+	if (len != sizeof(*msg)) {
+		RR(KERN_ERR "rpcrouter: r2r msg size %d != %d\n",
+		       len, sizeof(*msg));
+		return -EINVAL;
+	}
+
+	switch (msg->cmd) {
+	case RPCROUTER_CTRL_CMD_HELLO:
+		RR("o HELLO PID %d\n", xprt_info->remote_pid);
+		memset(&ctl, 0, sizeof(ctl));
+		ctl.cmd = RPCROUTER_CTRL_CMD_HELLO;
+		rpcrouter_send_control_msg(xprt_info, &ctl);
+
+		xprt_info->initialized = 1;
+
+		/* Send list of servers one at a time */
+		ctl.cmd = RPCROUTER_CTRL_CMD_NEW_SERVER;
+
+		/* TODO: long time to hold a spinlock... */
+		spin_lock_irqsave(&server_list_lock, flags);
+		list_for_each_entry(server, &server_list, list) {
+			if (server->pid != RPCROUTER_PID_LOCAL)
+				continue;
+			ctl.srv.pid = server->pid;
+			ctl.srv.cid = server->cid;
+			ctl.srv.prog = server->prog;
+			ctl.srv.vers = server->vers;
+
+			RR("x NEW_SERVER id=%d:%08x prog=%08x:%08x\n",
+			   server->pid, server->cid,
+			   server->prog, server->vers);
+
+			rpcrouter_send_control_msg(xprt_info, &ctl);
+		}
+		spin_unlock_irqrestore(&server_list_lock, flags);
+
+		if (first) {
+			first = 0;
+			queue_work(rpcrouter_workqueue,
+				   &work_create_rpcrouter_pdev);
+		}
+		break;
+
+	case RPCROUTER_CTRL_CMD_RESUME_TX:
+		RR("o RESUME_TX id=%d:%08x\n", msg->cli.pid, msg->cli.cid);
+
+		r_ept = rpcrouter_lookup_remote_endpoint(msg->cli.pid,
+							 msg->cli.cid);
+		if (!r_ept) {
+			printk(KERN_ERR
+			       "rpcrouter: Unable to resume client\n");
+			break;
+		}
+		spin_lock_irqsave(&r_ept->quota_lock, flags);
+		r_ept->tx_quota_cntr = 0;
+		spin_unlock_irqrestore(&r_ept->quota_lock, flags);
+		wake_up(&r_ept->quota_wait);
+		break;
+
+	case RPCROUTER_CTRL_CMD_NEW_SERVER:
+		if (msg->srv.vers == 0) {
+			pr_err(
+			"rpcrouter: Server create rejected, version = 0, "
+			"program = %08x\n", msg->srv.prog);
+			break;
+		}
+
+		RR("o NEW_SERVER id=%d:%08x prog=%08x:%08x\n",
+		   msg->srv.pid, msg->srv.cid, msg->srv.prog, msg->srv.vers);
+
+		server = rpcrouter_lookup_server(msg->srv.prog, msg->srv.vers);
+
+		if (!server) {
+			server = rpcrouter_create_server(
+				msg->srv.pid, msg->srv.cid,
+				msg->srv.prog, msg->srv.vers);
+			if (!server)
+				return -ENOMEM;
+			/*
+			 * XXX: Verify that its okay to add the
+			 * client to our remote client list
+			 * if we get a NEW_SERVER notification
+			 */
+			if (!rpcrouter_lookup_remote_endpoint(msg->srv.pid,
+							      msg->srv.cid)) {
+				rc = rpcrouter_create_remote_endpoint(
+					msg->srv.pid, msg->srv.cid);
+				if (rc < 0)
+					printk(KERN_ERR
+						"rpcrouter:Client create"
+						"error (%d)\n", rc);
+			}
+			rpcrouter_register_board_dev(server);
+			schedule_work(&work_create_pdevs);
+			wake_up(&newserver_wait);
+		} else {
+			if ((server->pid == msg->srv.pid) &&
+			    (server->cid == msg->srv.cid)) {
+				handle_server_restart(server,
+						      msg->srv.pid,
+						      msg->srv.cid,
+						      msg->srv.prog,
+						      msg->srv.vers);
+			} else {
+				server->pid = msg->srv.pid;
+				server->cid = msg->srv.cid;
+			}
+		}
+		break;
+
+	case RPCROUTER_CTRL_CMD_REMOVE_SERVER:
+		RR("o REMOVE_SERVER prog=%08x:%d\n",
+		   msg->srv.prog, msg->srv.vers);
+		server = rpcrouter_lookup_server(msg->srv.prog, msg->srv.vers);
+		if (server)
+			rpcrouter_destroy_server(server);
+		break;
+
+	case RPCROUTER_CTRL_CMD_REMOVE_CLIENT:
+		RR("o REMOVE_CLIENT id=%d:%08x\n", msg->cli.pid, msg->cli.cid);
+		if (msg->cli.pid == RPCROUTER_PID_LOCAL) {
+			printk(KERN_ERR
+			       "rpcrouter: Denying remote removal of "
+			       "local client\n");
+			break;
+		}
+		r_ept = rpcrouter_lookup_remote_endpoint(msg->cli.pid,
+							 msg->cli.cid);
+		if (r_ept) {
+			spin_lock_irqsave(&remote_endpoints_lock, flags);
+			list_del(&r_ept->list);
+			spin_unlock_irqrestore(&remote_endpoints_lock, flags);
+			kfree(r_ept);
+		}
+
+		/* Notify local clients of this event */
+		printk(KERN_ERR "rpcrouter: LOCAL NOTIFICATION NOT IMP\n");
+		rc = -ENOSYS;
+
+		break;
+	case RPCROUTER_CTRL_CMD_PING:
+		/* No action needed for ping messages received */
+		RR("o PING\n");
+		break;
+	default:
+		RR("o UNKNOWN(%08x)\n", msg->cmd);
+		rc = -ENOSYS;
+	}
+
+	return rc;
+}
+
+static void do_create_rpcrouter_pdev(struct work_struct *work)
+{
+	D("%s: modem rpc router up\n", __func__);
+	platform_device_register(&rpcrouter_pdev);
+	complete_all(&rpc_remote_router_up);
+}
+
+static void do_create_pdevs(struct work_struct *work)
+{
+	unsigned long flags;
+	struct rr_server *server;
+
+	/* TODO: race if destroyed while being registered */
+	spin_lock_irqsave(&server_list_lock, flags);
+	list_for_each_entry(server, &server_list, list) {
+		if (server->pid != RPCROUTER_PID_LOCAL) {
+			if (server->pdev_name[0] == 0) {
+				sprintf(server->pdev_name, "rs%.8x",
+					server->prog);
+				spin_unlock_irqrestore(&server_list_lock,
+						       flags);
+				msm_rpcrouter_create_server_pdev(server);
+				schedule_work(&work_create_pdevs);
+				return;
+			}
+		}
+	}
+	spin_unlock_irqrestore(&server_list_lock, flags);
+}
+
+static void *rr_malloc(unsigned sz)
+{
+	void *ptr = kmalloc(sz, GFP_KERNEL);
+	if (ptr)
+		return ptr;
+
+	printk(KERN_ERR "rpcrouter: kmalloc of %d failed, retrying...\n", sz);
+	do {
+		ptr = kmalloc(sz, GFP_KERNEL);
+	} while (!ptr);
+
+	return ptr;
+}
+
+static int rr_read(struct rpcrouter_xprt_info *xprt_info,
+		   void *data, uint32_t len)
+{
+	int rc;
+	unsigned long flags;
+
+	while (!xprt_info->abort_data_read) {
+		spin_lock_irqsave(&xprt_info->lock, flags);
+		if (xprt_info->xprt->read_avail() >= len) {
+			rc = xprt_info->xprt->read(data, len);
+			spin_unlock_irqrestore(&xprt_info->lock, flags);
+			if (rc == len && !xprt_info->abort_data_read)
+				return 0;
+			else
+				return -EIO;
+		}
+		xprt_info->need_len = len;
+		wake_unlock(&xprt_info->wakelock);
+		spin_unlock_irqrestore(&xprt_info->lock, flags);
+
+		wait_event(xprt_info->read_wait,
+			xprt_info->xprt->read_avail() >= len
+			|| xprt_info->abort_data_read);
+	}
+	return -EIO;
+}
+
+#if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG)
+static char *type_to_str(int i)
+{
+	switch (i) {
+	case RPCROUTER_CTRL_CMD_DATA:
+		return "data    ";
+	case RPCROUTER_CTRL_CMD_HELLO:
+		return "hello   ";
+	case RPCROUTER_CTRL_CMD_BYE:
+		return "bye     ";
+	case RPCROUTER_CTRL_CMD_NEW_SERVER:
+		return "new_srvr";
+	case RPCROUTER_CTRL_CMD_REMOVE_SERVER:
+		return "rmv_srvr";
+	case RPCROUTER_CTRL_CMD_REMOVE_CLIENT:
+		return "rmv_clnt";
+	case RPCROUTER_CTRL_CMD_RESUME_TX:
+		return "resum_tx";
+	case RPCROUTER_CTRL_CMD_EXIT:
+		return "cmd_exit";
+	default:
+		return "invalid";
+	}
+}
+#endif
+
+static void do_read_data(struct work_struct *work)
+{
+	struct rr_header hdr;
+	struct rr_packet *pkt;
+	struct rr_fragment *frag;
+	struct msm_rpc_endpoint *ept;
+#if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG)
+	struct rpc_request_hdr *rq;
+#endif
+	uint32_t pm, mid;
+	unsigned long flags;
+
+	struct rpcrouter_xprt_info *xprt_info =
+		container_of(work,
+			     struct rpcrouter_xprt_info,
+			     read_data);
+
+	if (rr_read(xprt_info, &hdr, sizeof(hdr)))
+		goto fail_io;
+
+	RR("- ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
+	   hdr.version, hdr.type, hdr.src_pid, hdr.src_cid,
+	   hdr.confirm_rx, hdr.size, hdr.dst_pid, hdr.dst_cid);
+	RAW_HDR("[r rr_h] "
+	    "ver=%i,type=%s,src_pid=%08x,src_cid=%08x,"
+	    "confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
+	    hdr.version, type_to_str(hdr.type), hdr.src_pid, hdr.src_cid,
+	    hdr.confirm_rx, hdr.size, hdr.dst_pid, hdr.dst_cid);
+
+	if (hdr.version != RPCROUTER_VERSION) {
+		DIAG("version %d != %d\n", hdr.version, RPCROUTER_VERSION);
+		goto fail_data;
+	}
+	if (hdr.size > RPCROUTER_MSGSIZE_MAX) {
+		DIAG("msg size %d > max %d\n", hdr.size, RPCROUTER_MSGSIZE_MAX);
+		goto fail_data;
+	}
+
+	if (hdr.dst_cid == RPCROUTER_ROUTER_ADDRESS) {
+		if (xprt_info->remote_pid == -1) {
+			xprt_info->remote_pid = hdr.src_pid;
+
+			/* do restart notification */
+			modem_reset_startup(xprt_info);
+		}
+
+		if (rr_read(xprt_info, xprt_info->r2r_buf, hdr.size))
+			goto fail_io;
+		process_control_msg(xprt_info,
+				    (void *) xprt_info->r2r_buf, hdr.size);
+		goto done;
+	}
+
+	if (hdr.size < sizeof(pm)) {
+		DIAG("runt packet (no pacmark)\n");
+		goto fail_data;
+	}
+	if (rr_read(xprt_info, &pm, sizeof(pm)))
+		goto fail_io;
+
+	hdr.size -= sizeof(pm);
+
+	frag = rr_malloc(sizeof(*frag));
+	frag->next = NULL;
+	frag->length = hdr.size;
+	if (rr_read(xprt_info, frag->data, hdr.size)) {
+		kfree(frag);
+		goto fail_io;
+	}
+
+#if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG)
+	if ((smd_rpcrouter_debug_mask & RAW_PMR) &&
+	    ((pm >> 30 & 0x1) || (pm >> 31 & 0x1))) {
+		uint32_t xid = 0;
+		if (pm >> 30 & 0x1) {
+			rq = (struct rpc_request_hdr *) frag->data;
+			xid = ntohl(rq->xid);
+		}
+		if ((pm >> 31 & 0x1) || (pm >> 30 & 0x1))
+			RAW_PMR_NOMASK("xid:0x%03x first=%i,last=%i,mid=%3i,"
+				       "len=%3i,dst_cid=%08x\n",
+				       xid,
+				       pm >> 30 & 0x1,
+				       pm >> 31 & 0x1,
+				       pm >> 16 & 0xFF,
+				       pm & 0xFFFF, hdr.dst_cid);
+	}
+
+	if (smd_rpcrouter_debug_mask & SMEM_LOG) {
+		rq = (struct rpc_request_hdr *) frag->data;
+		if (rq->xid == 0)
+			smem_log_event(SMEM_LOG_PROC_ID_APPS |
+				       RPC_ROUTER_LOG_EVENT_MID_READ,
+				       PACMARK_MID(pm),
+				       hdr.dst_cid,
+				       hdr.src_cid);
+		else
+			smem_log_event(SMEM_LOG_PROC_ID_APPS |
+				       RPC_ROUTER_LOG_EVENT_MSG_READ,
+				       ntohl(rq->xid),
+				       hdr.dst_cid,
+				       hdr.src_cid);
+	}
+#endif
+
+	spin_lock_irqsave(&local_endpoints_lock, flags);
+	ept = rpcrouter_lookup_local_endpoint(hdr.dst_cid);
+	if (!ept) {
+		spin_unlock_irqrestore(&local_endpoints_lock, flags);
+		DIAG("no local ept for cid %08x\n", hdr.dst_cid);
+		kfree(frag);
+		goto done;
+	}
+
+	/* See if there is already a partial packet that matches our mid
+	 * and if so, append this fragment to that packet.
+	 */
+	mid = PACMARK_MID(pm);
+	spin_lock(&ept->incomplete_lock);
+	list_for_each_entry(pkt, &ept->incomplete, list) {
+		if (pkt->mid == mid) {
+			pkt->last->next = frag;
+			pkt->last = frag;
+			pkt->length += frag->length;
+			if (PACMARK_LAST(pm)) {
+				list_del(&pkt->list);
+				spin_unlock(&ept->incomplete_lock);
+				goto packet_complete;
+			}
+			spin_unlock(&ept->incomplete_lock);
+			spin_unlock_irqrestore(&local_endpoints_lock, flags);
+			goto done;
+		}
+	}
+	spin_unlock(&ept->incomplete_lock);
+	spin_unlock_irqrestore(&local_endpoints_lock, flags);
+	/* This mid is new -- create a packet for it, and put it on
+	 * the incomplete list if this fragment is not a last fragment,
+	 * otherwise put it on the read queue.
+	 */
+	pkt = rr_malloc(sizeof(struct rr_packet));
+	pkt->first = frag;
+	pkt->last = frag;
+	memcpy(&pkt->hdr, &hdr, sizeof(hdr));
+	pkt->mid = mid;
+	pkt->length = frag->length;
+
+	spin_lock_irqsave(&local_endpoints_lock, flags);
+	ept = rpcrouter_lookup_local_endpoint(hdr.dst_cid);
+	if (!ept) {
+		spin_unlock_irqrestore(&local_endpoints_lock, flags);
+		DIAG("no local ept for cid %08x\n", hdr.dst_cid);
+		kfree(frag);
+		kfree(pkt);
+		goto done;
+	}
+	if (!PACMARK_LAST(pm)) {
+		spin_lock(&ept->incomplete_lock);
+		list_add_tail(&pkt->list, &ept->incomplete);
+		spin_unlock(&ept->incomplete_lock);
+		spin_unlock_irqrestore(&local_endpoints_lock, flags);
+		goto done;
+	}
+
+packet_complete:
+	spin_lock(&ept->read_q_lock);
+	D("%s: take read lock on ept %p\n", __func__, ept);
+	wake_lock(&ept->read_q_wake_lock);
+	list_add_tail(&pkt->list, &ept->read_q);
+	wake_up(&ept->wait_q);
+	spin_unlock(&ept->read_q_lock);
+	spin_unlock_irqrestore(&local_endpoints_lock, flags);
+done:
+
+	if (hdr.confirm_rx) {
+		union rr_control_msg msg;
+
+		msg.cmd = RPCROUTER_CTRL_CMD_RESUME_TX;
+		msg.cli.pid = hdr.dst_pid;
+		msg.cli.cid = hdr.dst_cid;
+
+		RR("x RESUME_TX id=%d:%08x\n", msg.cli.pid, msg.cli.cid);
+		rpcrouter_send_control_msg(xprt_info, &msg);
+
+#if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG)
+		if (smd_rpcrouter_debug_mask & SMEM_LOG)
+			smem_log_event(SMEM_LOG_PROC_ID_APPS |
+				       RPC_ROUTER_LOG_EVENT_MSG_CFM_SNT,
+				       RPCROUTER_PID_LOCAL,
+				       hdr.dst_cid,
+				       hdr.src_cid);
+#endif
+
+	}
+
+	/* don't requeue if we should be shutting down */
+	if (!xprt_info->abort_data_read) {
+		queue_work(xprt_info->workqueue, &xprt_info->read_data);
+		return;
+	}
+
+	D("rpc_router terminating for '%s'\n",
+		xprt_info->xprt->name);
+
+fail_io:
+fail_data:
+	D(KERN_ERR "rpc_router has died for '%s'\n",
+			xprt_info->xprt->name);
+}
+
+void msm_rpc_setup_req(struct rpc_request_hdr *hdr, uint32_t prog,
+		       uint32_t vers, uint32_t proc)
+{
+	memset(hdr, 0, sizeof(struct rpc_request_hdr));
+	hdr->xid = cpu_to_be32(atomic_add_return(1, &next_xid));
+	hdr->rpc_vers = cpu_to_be32(2);
+	hdr->prog = cpu_to_be32(prog);
+	hdr->vers = cpu_to_be32(vers);
+	hdr->procedure = cpu_to_be32(proc);
+}
+EXPORT_SYMBOL(msm_rpc_setup_req);
+
+struct msm_rpc_endpoint *msm_rpc_open(void)
+{
+	struct msm_rpc_endpoint *ept;
+
+	ept = msm_rpcrouter_create_local_endpoint(MKDEV(0, 0));
+	if (ept == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	return ept;
+}
+
+void msm_rpc_read_wakeup(struct msm_rpc_endpoint *ept)
+{
+	ept->forced_wakeup = 1;
+	wake_up(&ept->wait_q);
+}
+
+int msm_rpc_close(struct msm_rpc_endpoint *ept)
+{
+	if (!ept)
+		return -EINVAL;
+	return msm_rpcrouter_destroy_local_endpoint(ept);
+}
+EXPORT_SYMBOL(msm_rpc_close);
+
+static int msm_rpc_write_pkt(
+	struct rr_header *hdr,
+	struct msm_rpc_endpoint *ept,
+	struct rr_remote_endpoint *r_ept,
+	void *buffer,
+	int count,
+	int first,
+	int last,
+	uint32_t mid
+	)
+{
+#if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG)
+	struct rpc_request_hdr *rq = buffer;
+	uint32_t event_id;
+#endif
+	uint32_t pacmark;
+	unsigned long flags = 0;
+	int rc;
+	struct rpcrouter_xprt_info *xprt_info;
+	int needed;
+
+	DEFINE_WAIT(__wait);
+
+	/* Create routing header */
+	hdr->type = RPCROUTER_CTRL_CMD_DATA;
+	hdr->version = RPCROUTER_VERSION;
+	hdr->src_pid = ept->pid;
+	hdr->src_cid = ept->cid;
+	hdr->confirm_rx = 0;
+	hdr->size = count + sizeof(uint32_t);
+
+	rc = wait_for_restart_and_notify(ept);
+	if (rc)
+		return rc;
+
+	if (r_ept) {
+		for (;;) {
+			prepare_to_wait(&r_ept->quota_wait, &__wait,
+					TASK_INTERRUPTIBLE);
+			spin_lock_irqsave(&r_ept->quota_lock, flags);
+			if ((r_ept->tx_quota_cntr <
+			     RPCROUTER_DEFAULT_RX_QUOTA) ||
+			    (r_ept->quota_restart_state != RESTART_NORMAL))
+				break;
+			if (signal_pending(current) &&
+			    (!(ept->flags & MSM_RPC_UNINTERRUPTIBLE)))
+				break;
+			spin_unlock_irqrestore(&r_ept->quota_lock, flags);
+			schedule();
+		}
+		finish_wait(&r_ept->quota_wait, &__wait);
+
+		if (r_ept->quota_restart_state != RESTART_NORMAL) {
+			spin_lock(&ept->restart_lock);
+			ept->restart_state &= ~RESTART_PEND_NTFY;
+			spin_unlock(&ept->restart_lock);
+			spin_unlock_irqrestore(&r_ept->quota_lock, flags);
+			return -ENETRESET;
+		}
+
+		if (signal_pending(current) &&
+		    (!(ept->flags & MSM_RPC_UNINTERRUPTIBLE))) {
+			spin_unlock_irqrestore(&r_ept->quota_lock, flags);
+			return -ERESTARTSYS;
+		}
+		r_ept->tx_quota_cntr++;
+		if (r_ept->tx_quota_cntr == RPCROUTER_DEFAULT_RX_QUOTA) {
+			hdr->confirm_rx = 1;
+
+#if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG)
+			if (smd_rpcrouter_debug_mask & SMEM_LOG) {
+				event_id = (rq->xid == 0) ?
+					RPC_ROUTER_LOG_EVENT_MID_CFM_REQ :
+					RPC_ROUTER_LOG_EVENT_MSG_CFM_REQ;
+
+				smem_log_event(SMEM_LOG_PROC_ID_APPS | event_id,
+					       hdr->dst_pid,
+					       hdr->dst_cid,
+					       hdr->src_cid);
+			}
+#endif
+
+		}
+	}
+	pacmark = PACMARK(count, mid, first, last);
+
+	if (r_ept)
+		spin_unlock_irqrestore(&r_ept->quota_lock, flags);
+
+	mutex_lock(&xprt_info_list_lock);
+	xprt_info = rpcrouter_get_xprt_info(hdr->dst_pid);
+	if (!xprt_info) {
+		mutex_unlock(&xprt_info_list_lock);
+		return -ENETRESET;
+	}
+	spin_lock_irqsave(&xprt_info->lock, flags);
+	mutex_unlock(&xprt_info_list_lock);
+	spin_lock(&ept->restart_lock);
+	if (ept->restart_state != RESTART_NORMAL) {
+		ept->restart_state &= ~RESTART_PEND_NTFY;
+		spin_unlock(&ept->restart_lock);
+		spin_unlock_irqrestore(&xprt_info->lock, flags);
+		return -ENETRESET;
+	}
+
+	needed = sizeof(*hdr) + hdr->size;
+	while ((ept->restart_state == RESTART_NORMAL) &&
+	       (xprt_info->xprt->write_avail() < needed)) {
+		spin_unlock(&ept->restart_lock);
+		spin_unlock_irqrestore(&xprt_info->lock, flags);
+		msleep(250);
+
+		/* refresh xprt pointer to ensure that it hasn't
+		 * been deleted since our last retrieval */
+		mutex_lock(&xprt_info_list_lock);
+		xprt_info = rpcrouter_get_xprt_info(hdr->dst_pid);
+		if (!xprt_info) {
+			mutex_unlock(&xprt_info_list_lock);
+			return -ENETRESET;
+		}
+		spin_lock_irqsave(&xprt_info->lock, flags);
+		mutex_unlock(&xprt_info_list_lock);
+		spin_lock(&ept->restart_lock);
+	}
+	if (ept->restart_state != RESTART_NORMAL) {
+		ept->restart_state &= ~RESTART_PEND_NTFY;
+		spin_unlock(&ept->restart_lock);
+		spin_unlock_irqrestore(&xprt_info->lock, flags);
+		return -ENETRESET;
+	}
+
+	/* TODO: deal with full fifo */
+	xprt_info->xprt->write(hdr, sizeof(*hdr), HEADER);
+	RAW_HDR("[w rr_h] "
+		    "ver=%i,type=%s,src_pid=%08x,src_cid=%08x,"
+		"confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
+		hdr->version, type_to_str(hdr->type),
+		hdr->src_pid, hdr->src_cid,
+		hdr->confirm_rx, hdr->size, hdr->dst_pid, hdr->dst_cid);
+	xprt_info->xprt->write(&pacmark, sizeof(pacmark), PACKMARK);
+
+#if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG)
+	if ((smd_rpcrouter_debug_mask & RAW_PMW) &&
+	    ((pacmark >> 30 & 0x1) || (pacmark >> 31 & 0x1))) {
+		uint32_t xid = 0;
+		if (pacmark >> 30 & 0x1)
+			xid = ntohl(rq->xid);
+		if ((pacmark >> 31 & 0x1) || (pacmark >> 30 & 0x1))
+			RAW_PMW_NOMASK("xid:0x%03x first=%i,last=%i,mid=%3i,"
+				       "len=%3i,src_cid=%x\n",
+				       xid,
+				       pacmark >> 30 & 0x1,
+				       pacmark >> 31 & 0x1,
+				       pacmark >> 16 & 0xFF,
+				       pacmark & 0xFFFF, hdr->src_cid);
+	}
+#endif
+
+	xprt_info->xprt->write(buffer, count, PAYLOAD);
+	spin_unlock(&ept->restart_lock);
+	spin_unlock_irqrestore(&xprt_info->lock, flags);
+
+#if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG)
+	if (smd_rpcrouter_debug_mask & SMEM_LOG) {
+		if (rq->xid == 0)
+			smem_log_event(SMEM_LOG_PROC_ID_APPS |
+				       RPC_ROUTER_LOG_EVENT_MID_WRITTEN,
+				       PACMARK_MID(pacmark),
+				       hdr->dst_cid,
+				       hdr->src_cid);
+		else
+			smem_log_event(SMEM_LOG_PROC_ID_APPS |
+				       RPC_ROUTER_LOG_EVENT_MSG_WRITTEN,
+				       ntohl(rq->xid),
+				       hdr->dst_cid,
+				       hdr->src_cid);
+	}
+#endif
+
+	return needed;
+}
+
+static struct msm_rpc_reply *get_pend_reply(struct msm_rpc_endpoint *ept,
+					    uint32_t xid)
+{
+	unsigned long flags;
+	struct msm_rpc_reply *reply;
+	spin_lock_irqsave(&ept->reply_q_lock, flags);
+	list_for_each_entry(reply, &ept->reply_pend_q, list) {
+		if (reply->xid == xid) {
+			list_del(&reply->list);
+			spin_unlock_irqrestore(&ept->reply_q_lock, flags);
+			return reply;
+		}
+	}
+	spin_unlock_irqrestore(&ept->reply_q_lock, flags);
+	return NULL;
+}
+
+void get_requesting_client(struct msm_rpc_endpoint *ept, uint32_t xid,
+			   struct msm_rpc_client_info *clnt_info)
+{
+	unsigned long flags;
+	struct msm_rpc_reply *reply;
+
+	if (!clnt_info)
+		return;
+
+	spin_lock_irqsave(&ept->reply_q_lock, flags);
+	list_for_each_entry(reply, &ept->reply_pend_q, list) {
+		if (reply->xid == xid) {
+			clnt_info->pid = reply->pid;
+			clnt_info->cid = reply->cid;
+			clnt_info->prog = reply->prog;
+			clnt_info->vers = reply->vers;
+			spin_unlock_irqrestore(&ept->reply_q_lock, flags);
+			return;
+		}
+	}
+	spin_unlock_irqrestore(&ept->reply_q_lock, flags);
+	return;
+}
+
+static void set_avail_reply(struct msm_rpc_endpoint *ept,
+			    struct msm_rpc_reply *reply)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&ept->reply_q_lock, flags);
+	list_add_tail(&reply->list, &ept->reply_avail_q);
+	spin_unlock_irqrestore(&ept->reply_q_lock, flags);
+}
+
+static struct msm_rpc_reply *get_avail_reply(struct msm_rpc_endpoint *ept)
+{
+	struct msm_rpc_reply *reply;
+	unsigned long flags;
+	if (list_empty(&ept->reply_avail_q)) {
+		if (ept->reply_cnt >= RPCROUTER_PEND_REPLIES_MAX) {
+			printk(KERN_ERR
+			       "exceeding max replies of %d \n",
+			       RPCROUTER_PEND_REPLIES_MAX);
+			return 0;
+		}
+		reply = kmalloc(sizeof(struct msm_rpc_reply), GFP_KERNEL);
+		if (!reply)
+			return 0;
+		D("Adding reply 0x%08x \n", (unsigned int)reply);
+		memset(reply, 0, sizeof(struct msm_rpc_reply));
+		spin_lock_irqsave(&ept->reply_q_lock, flags);
+		ept->reply_cnt++;
+		spin_unlock_irqrestore(&ept->reply_q_lock, flags);
+	} else {
+		spin_lock_irqsave(&ept->reply_q_lock, flags);
+		reply = list_first_entry(&ept->reply_avail_q,
+					 struct msm_rpc_reply,
+					 list);
+		list_del(&reply->list);
+		spin_unlock_irqrestore(&ept->reply_q_lock, flags);
+	}
+	return reply;
+}
+
+static void set_pend_reply(struct msm_rpc_endpoint *ept,
+			   struct msm_rpc_reply *reply)
+{
+		unsigned long flags;
+		spin_lock_irqsave(&ept->reply_q_lock, flags);
+		D("%s: take reply lock on ept %p\n", __func__, ept);
+		wake_lock(&ept->reply_q_wake_lock);
+		list_add_tail(&reply->list, &ept->reply_pend_q);
+		spin_unlock_irqrestore(&ept->reply_q_lock, flags);
+}
+
+int msm_rpc_write(struct msm_rpc_endpoint *ept, void *buffer, int count)
+{
+	struct rr_header hdr;
+	struct rpc_request_hdr *rq = buffer;
+	struct rr_remote_endpoint *r_ept;
+	struct msm_rpc_reply *reply = NULL;
+	int max_tx;
+	int tx_cnt;
+	char *tx_buf;
+	int rc;
+	int first_pkt = 1;
+	uint32_t mid;
+	unsigned long flags;
+
+	/* snoop the RPC packet and enforce permissions */
+
+	/* has to have at least the xid and type fields */
+	if (count < (sizeof(uint32_t) * 2)) {
+		printk(KERN_ERR "rr_write: rejecting runt packet\n");
+		return -EINVAL;
+	}
+
+	if (rq->type == 0) {
+		/* RPC CALL */
+		if (count < (sizeof(uint32_t) * 6)) {
+			printk(KERN_ERR
+			       "rr_write: rejecting runt call packet\n");
+			return -EINVAL;
+		}
+		if (ept->dst_pid == 0xffffffff) {
+			printk(KERN_ERR "rr_write: not connected\n");
+			return -ENOTCONN;
+		}
+		if ((ept->dst_prog != rq->prog) ||
+		    ((be32_to_cpu(ept->dst_vers) & 0x0fff0000) !=
+		     (be32_to_cpu(rq->vers) & 0x0fff0000))) {
+			printk(KERN_ERR
+			       "rr_write: cannot write to %08x:%08x "
+			       "(bound to %08x:%08x)\n",
+			       be32_to_cpu(rq->prog), be32_to_cpu(rq->vers),
+			       be32_to_cpu(ept->dst_prog),
+			       be32_to_cpu(ept->dst_vers));
+			return -EINVAL;
+		}
+		hdr.dst_pid = ept->dst_pid;
+		hdr.dst_cid = ept->dst_cid;
+		IO("CALL to %08x:%d @ %d:%08x (%d bytes)\n",
+		   be32_to_cpu(rq->prog), be32_to_cpu(rq->vers),
+		   ept->dst_pid, ept->dst_cid, count);
+	} else {
+		/* RPC REPLY */
+		reply = get_pend_reply(ept, rq->xid);
+		if (!reply) {
+			printk(KERN_ERR
+			       "rr_write: rejecting, reply not found \n");
+			return -EINVAL;
+		}
+		hdr.dst_pid = reply->pid;
+		hdr.dst_cid = reply->cid;
+		IO("REPLY to xid=%d @ %d:%08x (%d bytes)\n",
+		   be32_to_cpu(rq->xid), hdr.dst_pid, hdr.dst_cid, count);
+	}
+
+	r_ept = rpcrouter_lookup_remote_endpoint(hdr.dst_pid, hdr.dst_cid);
+
+	if ((!r_ept) && (hdr.dst_pid != RPCROUTER_PID_LOCAL)) {
+		printk(KERN_ERR
+			"msm_rpc_write(): No route to ept "
+			"[PID %x CID %x]\n", hdr.dst_pid, hdr.dst_cid);
+		count = -EHOSTUNREACH;
+		goto write_release_lock;
+	}
+
+	tx_cnt = count;
+	tx_buf = buffer;
+	mid = atomic_add_return(1, &pm_mid) & 0xFF;
+	/* The modem's router can only take 500 bytes of data. The
+	   first 8 bytes it uses on the modem side for addressing,
+	   the next 4 bytes are for the pacmark header. */
+	max_tx = RPCROUTER_MSGSIZE_MAX - 8 - sizeof(uint32_t);
+	IO("Writing %d bytes, max pkt size is %d\n",
+	   tx_cnt, max_tx);
+	while (tx_cnt > 0) {
+		if (tx_cnt > max_tx) {
+			rc = msm_rpc_write_pkt(&hdr, ept, r_ept,
+					       tx_buf, max_tx,
+					       first_pkt, 0, mid);
+			if (rc < 0) {
+				count = rc;
+				goto write_release_lock;
+			}
+			IO("Wrote %d bytes First %d, Last 0 mid %d\n",
+			   rc, first_pkt, mid);
+			tx_cnt -= max_tx;
+			tx_buf += max_tx;
+		} else {
+			rc = msm_rpc_write_pkt(&hdr, ept, r_ept,
+					       tx_buf, tx_cnt,
+					       first_pkt, 1, mid);
+			if (rc < 0) {
+				count = rc;
+				goto write_release_lock;
+			}
+			IO("Wrote %d bytes First %d Last 1 mid %d\n",
+			   rc, first_pkt, mid);
+			break;
+		}
+		first_pkt = 0;
+	}
+
+ write_release_lock:
+	/* if reply, release wakelock after writing to the transport */
+	if (rq->type != 0) {
+		/* Upon failure, add reply tag to the pending list.
+		** Else add reply tag to the avail/free list. */
+		if (count < 0)
+			set_pend_reply(ept, reply);
+		else
+			set_avail_reply(ept, reply);
+
+		spin_lock_irqsave(&ept->reply_q_lock, flags);
+		if (list_empty(&ept->reply_pend_q)) {
+			D("%s: release reply lock on ept %p\n", __func__, ept);
+			wake_unlock(&ept->reply_q_wake_lock);
+		}
+		spin_unlock_irqrestore(&ept->reply_q_lock, flags);
+	}
+
+	return count;
+}
+EXPORT_SYMBOL(msm_rpc_write);
+
+/*
+ * NOTE: It is the responsibility of the caller to kfree buffer
+ */
+int msm_rpc_read(struct msm_rpc_endpoint *ept, void **buffer,
+		 unsigned user_len, long timeout)
+{
+	struct rr_fragment *frag, *next;
+	char *buf;
+	int rc;
+
+	rc = __msm_rpc_read(ept, &frag, user_len, timeout);
+	if (rc <= 0)
+		return rc;
+
+	/* single-fragment messages conveniently can be
+	 * returned as-is (the buffer is at the front)
+	 */
+	if (frag->next == 0) {
+		*buffer = (void*) frag;
+		return rc;
+	}
+
+	/* multi-fragment messages, we have to do it the
+	 * hard way, which is rather disgusting right now
+	 */
+	buf = rr_malloc(rc);
+	*buffer = buf;
+
+	while (frag != NULL) {
+		memcpy(buf, frag->data, frag->length);
+		next = frag->next;
+		buf += frag->length;
+		kfree(frag);
+		frag = next;
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_rpc_read);
+
+int msm_rpc_call(struct msm_rpc_endpoint *ept, uint32_t proc,
+		 void *_request, int request_size,
+		 long timeout)
+{
+	return msm_rpc_call_reply(ept, proc,
+				  _request, request_size,
+				  NULL, 0, timeout);
+}
+EXPORT_SYMBOL(msm_rpc_call);
+
+int msm_rpc_call_reply(struct msm_rpc_endpoint *ept, uint32_t proc,
+		       void *_request, int request_size,
+		       void *_reply, int reply_size,
+		       long timeout)
+{
+	struct rpc_request_hdr *req = _request;
+	struct rpc_reply_hdr *reply;
+	int rc;
+
+	if (request_size < sizeof(*req))
+		return -ETOOSMALL;
+
+	if (ept->dst_pid == 0xffffffff)
+		return -ENOTCONN;
+
+	memset(req, 0, sizeof(*req));
+	req->xid = cpu_to_be32(atomic_add_return(1, &next_xid));
+	req->rpc_vers = cpu_to_be32(2);
+	req->prog = ept->dst_prog;
+	req->vers = ept->dst_vers;
+	req->procedure = cpu_to_be32(proc);
+
+	rc = msm_rpc_write(ept, req, request_size);
+	if (rc < 0)
+		return rc;
+
+	for (;;) {
+		rc = msm_rpc_read(ept, (void*) &reply, -1, timeout);
+		if (rc < 0)
+			return rc;
+		if (rc < (3 * sizeof(uint32_t))) {
+			rc = -EIO;
+			break;
+		}
+		/* we should not get CALL packets -- ignore them */
+		if (reply->type == 0) {
+			kfree(reply);
+			continue;
+		}
+		/* If an earlier call timed out, we could get the (no
+		 * longer wanted) reply for it.	 Ignore replies that
+		 * we don't expect
+		 */
+		if (reply->xid != req->xid) {
+			kfree(reply);
+			continue;
+		}
+		if (reply->reply_stat != 0) {
+			rc = -EPERM;
+			break;
+		}
+		if (reply->data.acc_hdr.accept_stat != 0) {
+			rc = -EINVAL;
+			break;
+		}
+		if (_reply == NULL) {
+			rc = 0;
+			break;
+		}
+		if (rc > reply_size) {
+			rc = -ENOMEM;
+		} else {
+			memcpy(_reply, reply, rc);
+		}
+		break;
+	}
+	kfree(reply);
+	return rc;
+}
+EXPORT_SYMBOL(msm_rpc_call_reply);
+
+
+static inline int ept_packet_available(struct msm_rpc_endpoint *ept)
+{
+	unsigned long flags;
+	int ret;
+	spin_lock_irqsave(&ept->read_q_lock, flags);
+	ret = !list_empty(&ept->read_q);
+	spin_unlock_irqrestore(&ept->read_q_lock, flags);
+	return ret;
+}
+
+int __msm_rpc_read(struct msm_rpc_endpoint *ept,
+		   struct rr_fragment **frag_ret,
+		   unsigned len, long timeout)
+{
+	struct rr_packet *pkt;
+	struct rpc_request_hdr *rq;
+	struct msm_rpc_reply *reply;
+	unsigned long flags;
+	int rc;
+
+	rc = wait_for_restart_and_notify(ept);
+	if (rc)
+		return rc;
+
+	IO("READ on ept %p\n", ept);
+	if (ept->flags & MSM_RPC_UNINTERRUPTIBLE) {
+		if (timeout < 0) {
+			wait_event(ept->wait_q, (ept_packet_available(ept) ||
+						   ept->forced_wakeup ||
+						   ept->restart_state));
+			if (!msm_rpc_clear_netreset(ept))
+				return -ENETRESET;
+		} else {
+			rc = wait_event_timeout(
+				ept->wait_q,
+				(ept_packet_available(ept) ||
+				 ept->forced_wakeup ||
+				 ept->restart_state),
+				timeout);
+			if (!msm_rpc_clear_netreset(ept))
+				return -ENETRESET;
+			if (rc == 0)
+				return -ETIMEDOUT;
+		}
+	} else {
+		if (timeout < 0) {
+			rc = wait_event_interruptible(
+				ept->wait_q, (ept_packet_available(ept) ||
+					ept->forced_wakeup ||
+					ept->restart_state));
+			if (!msm_rpc_clear_netreset(ept))
+				return -ENETRESET;
+			if (rc < 0)
+				return rc;
+		} else {
+			rc = wait_event_interruptible_timeout(
+				ept->wait_q,
+				(ept_packet_available(ept) ||
+				 ept->forced_wakeup ||
+				 ept->restart_state),
+				timeout);
+			if (!msm_rpc_clear_netreset(ept))
+				return -ENETRESET;
+			if (rc == 0)
+				return -ETIMEDOUT;
+		}
+	}
+
+	if (ept->forced_wakeup) {
+		ept->forced_wakeup = 0;
+		return 0;
+	}
+
+	spin_lock_irqsave(&ept->read_q_lock, flags);
+	if (list_empty(&ept->read_q)) {
+		spin_unlock_irqrestore(&ept->read_q_lock, flags);
+		return -EAGAIN;
+	}
+	pkt = list_first_entry(&ept->read_q, struct rr_packet, list);
+	if (pkt->length > len) {
+		spin_unlock_irqrestore(&ept->read_q_lock, flags);
+		return -ETOOSMALL;
+	}
+	list_del(&pkt->list);
+	spin_unlock_irqrestore(&ept->read_q_lock, flags);
+
+	rc = pkt->length;
+
+	*frag_ret = pkt->first;
+	rq = (void*) pkt->first->data;
+	if ((rc >= (sizeof(uint32_t) * 3)) && (rq->type == 0)) {
+		/* RPC CALL */
+		reply = get_avail_reply(ept);
+		if (!reply) {
+			rc = -ENOMEM;
+			goto read_release_lock;
+		}
+		reply->cid = pkt->hdr.src_cid;
+		reply->pid = pkt->hdr.src_pid;
+		reply->xid = rq->xid;
+		reply->prog = rq->prog;
+		reply->vers = rq->vers;
+		set_pend_reply(ept, reply);
+	}
+
+	kfree(pkt);
+
+	IO("READ on ept %p (%d bytes)\n", ept, rc);
+
+ read_release_lock:
+
+	/* release read wakelock after taking reply wakelock */
+	spin_lock_irqsave(&ept->read_q_lock, flags);
+	if (list_empty(&ept->read_q)) {
+		D("%s: release read lock on ept %p\n", __func__, ept);
+		wake_unlock(&ept->read_q_wake_lock);
+	}
+	spin_unlock_irqrestore(&ept->read_q_lock, flags);
+
+	return rc;
+}
+
+int msm_rpc_is_compatible_version(uint32_t server_version,
+				  uint32_t client_version)
+{
+
+	if ((server_version & RPC_VERSION_MODE_MASK) !=
+	    (client_version & RPC_VERSION_MODE_MASK))
+		return 0;
+
+	if (server_version & RPC_VERSION_MODE_MASK)
+		return server_version == client_version;
+
+	return ((server_version & RPC_VERSION_MAJOR_MASK) ==
+		 (client_version & RPC_VERSION_MAJOR_MASK)) &&
+		((server_version & RPC_VERSION_MINOR_MASK) >=
+		 (client_version & RPC_VERSION_MINOR_MASK));
+}
+EXPORT_SYMBOL(msm_rpc_is_compatible_version);
+
+static struct rr_server *msm_rpc_get_server(uint32_t prog, uint32_t vers,
+					    uint32_t accept_compatible,
+					    uint32_t *found_prog)
+{
+	struct rr_server *server;
+	unsigned long     flags;
+
+	if (found_prog == NULL)
+		return NULL;
+
+	*found_prog = 0;
+	spin_lock_irqsave(&server_list_lock, flags);
+	list_for_each_entry(server, &server_list, list) {
+		if (server->prog == prog) {
+			*found_prog = 1;
+			spin_unlock_irqrestore(&server_list_lock, flags);
+			if (accept_compatible) {
+				if (msm_rpc_is_compatible_version(server->vers,
+								  vers)) {
+					return server;
+				} else {
+					return NULL;
+				}
+			} else if (server->vers == vers) {
+				return server;
+			} else
+				return NULL;
+		}
+	}
+	spin_unlock_irqrestore(&server_list_lock, flags);
+	return NULL;
+}
+
+static struct msm_rpc_endpoint *__msm_rpc_connect(uint32_t prog, uint32_t vers,
+						  uint32_t accept_compatible,
+						  unsigned flags)
+{
+	struct msm_rpc_endpoint *ept;
+	struct rr_server *server;
+	uint32_t found_prog;
+	int rc = 0;
+
+	DEFINE_WAIT(__wait);
+
+	for (;;) {
+		prepare_to_wait(&newserver_wait, &__wait,
+				TASK_INTERRUPTIBLE);
+
+		server = msm_rpc_get_server(prog, vers, accept_compatible,
+					    &found_prog);
+		if (server)
+			break;
+
+		if (found_prog) {
+			pr_info("%s: server not found %x:%x\n",
+				__func__, prog, vers);
+			rc = -EHOSTUNREACH;
+			break;
+		}
+
+		if (msm_rpc_connect_timeout_ms == 0) {
+			rc = -EHOSTUNREACH;
+			break;
+		}
+
+		if (signal_pending(current)) {
+			rc = -ERESTARTSYS;
+			break;
+		}
+
+		rc = schedule_timeout(
+			msecs_to_jiffies(msm_rpc_connect_timeout_ms));
+		if (!rc) {
+			rc = -ETIMEDOUT;
+			break;
+		}
+	}
+	finish_wait(&newserver_wait, &__wait);
+
+	if (!server)
+		return ERR_PTR(rc);
+
+	if (accept_compatible && (server->vers != vers)) {
+		D("RPC Using new version 0x%08x(0x%08x) prog 0x%08x",
+			vers, server->vers, prog);
+		D(" ... Continuing\n");
+	}
+
+	ept = msm_rpc_open();
+	if (IS_ERR(ept))
+		return ept;
+
+	ept->flags = flags;
+	ept->dst_pid = server->pid;
+	ept->dst_cid = server->cid;
+	ept->dst_prog = cpu_to_be32(prog);
+	ept->dst_vers = cpu_to_be32(server->vers);
+
+	return ept;
+}
+
+struct msm_rpc_endpoint *msm_rpc_connect_compatible(uint32_t prog,
+			uint32_t vers, unsigned flags)
+{
+	return __msm_rpc_connect(prog, vers, 1, flags);
+}
+EXPORT_SYMBOL(msm_rpc_connect_compatible);
+
+struct msm_rpc_endpoint *msm_rpc_connect(uint32_t prog,
+			 uint32_t vers, unsigned flags)
+{
+	return __msm_rpc_connect(prog, vers, 0, flags);
+}
+EXPORT_SYMBOL(msm_rpc_connect);
+
+/* TODO: permission check? */
+int msm_rpc_register_server(struct msm_rpc_endpoint *ept,
+			    uint32_t prog, uint32_t vers)
+{
+	int rc;
+	union rr_control_msg msg;
+	struct rr_server *server;
+	struct rpcrouter_xprt_info *xprt_info;
+
+	server = rpcrouter_create_server(ept->pid, ept->cid,
+					 prog, vers);
+	if (!server)
+		return -ENODEV;
+
+	msg.srv.cmd = RPCROUTER_CTRL_CMD_NEW_SERVER;
+	msg.srv.pid = ept->pid;
+	msg.srv.cid = ept->cid;
+	msg.srv.prog = prog;
+	msg.srv.vers = vers;
+
+	RR("x NEW_SERVER id=%d:%08x prog=%08x:%08x\n",
+	   ept->pid, ept->cid, prog, vers);
+
+	mutex_lock(&xprt_info_list_lock);
+	list_for_each_entry(xprt_info, &xprt_info_list, list) {
+		rc = rpcrouter_send_control_msg(xprt_info, &msg);
+		if (rc < 0) {
+			mutex_unlock(&xprt_info_list_lock);
+			return rc;
+		}
+	}
+	mutex_unlock(&xprt_info_list_lock);
+	return 0;
+}
+
+int msm_rpc_clear_netreset(struct msm_rpc_endpoint *ept)
+{
+	unsigned long flags;
+	int rc = 1;
+	spin_lock_irqsave(&ept->restart_lock, flags);
+	if (ept->restart_state !=  RESTART_NORMAL) {
+		ept->restart_state &= ~RESTART_PEND_NTFY;
+		rc = 0;
+	}
+	spin_unlock_irqrestore(&ept->restart_lock, flags);
+	return rc;
+}
+
+/* TODO: permission check -- disallow unreg of somebody else's server */
+int msm_rpc_unregister_server(struct msm_rpc_endpoint *ept,
+			      uint32_t prog, uint32_t vers)
+{
+	struct rr_server *server;
+	server = rpcrouter_lookup_server(prog, vers);
+
+	if (!server)
+		return -ENOENT;
+	rpcrouter_destroy_server(server);
+	return 0;
+}
+
+int msm_rpc_get_curr_pkt_size(struct msm_rpc_endpoint *ept)
+{
+	unsigned long flags;
+	struct rr_packet *pkt;
+	int rc = 0;
+
+	if (!ept)
+		return -EINVAL;
+
+	if (!msm_rpc_clear_netreset(ept))
+		return -ENETRESET;
+
+	spin_lock_irqsave(&ept->read_q_lock, flags);
+	if (!list_empty(&ept->read_q)) {
+		pkt = list_first_entry(&ept->read_q, struct rr_packet, list);
+		rc = pkt->length;
+	}
+	spin_unlock_irqrestore(&ept->read_q_lock, flags);
+
+	return rc;
+}
+
+int msm_rpcrouter_close(void)
+{
+	struct rpcrouter_xprt_info *xprt_info;
+	union rr_control_msg ctl;
+
+	ctl.cmd = RPCROUTER_CTRL_CMD_BYE;
+	mutex_lock(&xprt_info_list_lock);
+	while (!list_empty(&xprt_info_list)) {
+		xprt_info = list_first_entry(&xprt_info_list,
+					struct rpcrouter_xprt_info, list);
+		xprt_info->abort_data_read = 1;
+		wake_up(&xprt_info->read_wait);
+		rpcrouter_send_control_msg(xprt_info, &ctl);
+		xprt_info->xprt->close();
+		list_del(&xprt_info->list);
+		mutex_unlock(&xprt_info_list_lock);
+
+		flush_workqueue(xprt_info->workqueue);
+		destroy_workqueue(xprt_info->workqueue);
+		wake_lock_destroy(&xprt_info->wakelock);
+		kfree(xprt_info);
+
+		mutex_lock(&xprt_info_list_lock);
+	}
+	mutex_unlock(&xprt_info_list_lock);
+	return 0;
+}
+
+#if defined(CONFIG_DEBUG_FS)
+static int dump_servers(char *buf, int max)
+{
+	int i = 0;
+	unsigned long flags;
+	struct rr_server *svr;
+	const char *sym;
+
+	spin_lock_irqsave(&server_list_lock, flags);
+	list_for_each_entry(svr, &server_list, list) {
+		i += scnprintf(buf + i, max - i, "pdev_name: %s\n",
+			       svr->pdev_name);
+		i += scnprintf(buf + i, max - i, "pid: 0x%08x\n", svr->pid);
+		i += scnprintf(buf + i, max - i, "cid: 0x%08x\n", svr->cid);
+		i += scnprintf(buf + i, max - i, "prog: 0x%08x", svr->prog);
+		sym = smd_rpc_get_sym(svr->prog);
+		if (sym)
+			i += scnprintf(buf + i, max - i, " (%s)\n", sym);
+		else
+			i += scnprintf(buf + i, max - i, "\n");
+		i += scnprintf(buf + i, max - i, "vers: 0x%08x\n", svr->vers);
+		i += scnprintf(buf + i, max - i, "\n");
+	}
+	spin_unlock_irqrestore(&server_list_lock, flags);
+
+	return i;
+}
+
+static int dump_remote_endpoints(char *buf, int max)
+{
+	int i = 0;
+	unsigned long flags;
+	struct rr_remote_endpoint *ept;
+
+	spin_lock_irqsave(&remote_endpoints_lock, flags);
+	list_for_each_entry(ept, &remote_endpoints, list) {
+		i += scnprintf(buf + i, max - i, "pid: 0x%08x\n", ept->pid);
+		i += scnprintf(buf + i, max - i, "cid: 0x%08x\n", ept->cid);
+		i += scnprintf(buf + i, max - i, "tx_quota_cntr: %i\n",
+			       ept->tx_quota_cntr);
+		i += scnprintf(buf + i, max - i, "quota_restart_state: %i\n",
+			       ept->quota_restart_state);
+		i += scnprintf(buf + i, max - i, "\n");
+	}
+	spin_unlock_irqrestore(&remote_endpoints_lock, flags);
+
+	return i;
+}
+
+static int dump_msm_rpc_endpoint(char *buf, int max)
+{
+	int i = 0;
+	unsigned long flags;
+	struct msm_rpc_reply *reply;
+	struct msm_rpc_endpoint *ept;
+	struct rr_packet *pkt;
+	const char *sym;
+
+	spin_lock_irqsave(&local_endpoints_lock, flags);
+	list_for_each_entry(ept, &local_endpoints, list) {
+		i += scnprintf(buf + i, max - i, "pid: 0x%08x\n", ept->pid);
+		i += scnprintf(buf + i, max - i, "cid: 0x%08x\n", ept->cid);
+		i += scnprintf(buf + i, max - i, "dst_pid: 0x%08x\n",
+			       ept->dst_pid);
+		i += scnprintf(buf + i, max - i, "dst_cid: 0x%08x\n",
+			       ept->dst_cid);
+		i += scnprintf(buf + i, max - i, "dst_prog: 0x%08x",
+			       be32_to_cpu(ept->dst_prog));
+		sym = smd_rpc_get_sym(be32_to_cpu(ept->dst_prog));
+		if (sym)
+			i += scnprintf(buf + i, max - i, " (%s)\n", sym);
+		else
+			i += scnprintf(buf + i, max - i, "\n");
+		i += scnprintf(buf + i, max - i, "dst_vers: 0x%08x\n",
+			       be32_to_cpu(ept->dst_vers));
+		i += scnprintf(buf + i, max - i, "reply_cnt: %i\n",
+			       ept->reply_cnt);
+		i += scnprintf(buf + i, max - i, "restart_state: %i\n",
+			       ept->restart_state);
+
+		i += scnprintf(buf + i, max - i, "outstanding xids:\n");
+		spin_lock(&ept->reply_q_lock);
+		list_for_each_entry(reply, &ept->reply_pend_q, list)
+			i += scnprintf(buf + i, max - i, "    xid = %u\n",
+				       ntohl(reply->xid));
+		spin_unlock(&ept->reply_q_lock);
+
+		i += scnprintf(buf + i, max - i, "complete unread packets:\n");
+		spin_lock(&ept->read_q_lock);
+		list_for_each_entry(pkt, &ept->read_q, list) {
+			i += scnprintf(buf + i, max - i, "    mid = %i\n",
+				       pkt->mid);
+			i += scnprintf(buf + i, max - i, "    length = %i\n",
+				       pkt->length);
+		}
+		spin_unlock(&ept->read_q_lock);
+		i += scnprintf(buf + i, max - i, "\n");
+	}
+	spin_unlock_irqrestore(&local_endpoints_lock, flags);
+
+	return i;
+}
+
+#define DEBUG_BUFMAX 4096
+static char debug_buffer[DEBUG_BUFMAX];
+
+static ssize_t debug_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *ppos)
+{
+	int (*fill)(char *buf, int max) = file->private_data;
+	int bsize = fill(debug_buffer, DEBUG_BUFMAX);
+	return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static const struct file_operations debug_ops = {
+	.read = debug_read,
+	.open = debug_open,
+};
+
+static void debug_create(const char *name, mode_t mode,
+			 struct dentry *dent,
+			 int (*fill)(char *buf, int max))
+{
+	debugfs_create_file(name, mode, dent, fill, &debug_ops);
+}
+
+static void debugfs_init(void)
+{
+	struct dentry *dent;
+
+	dent = debugfs_create_dir("smd_rpcrouter", 0);
+	if (IS_ERR(dent))
+		return;
+
+	debug_create("dump_msm_rpc_endpoints", 0444, dent,
+		     dump_msm_rpc_endpoint);
+	debug_create("dump_remote_endpoints", 0444, dent,
+		     dump_remote_endpoints);
+	debug_create("dump_servers", 0444, dent,
+		     dump_servers);
+
+}
+
+#else
+static void debugfs_init(void) {}
+#endif
+
+static int msm_rpcrouter_add_xprt(struct rpcrouter_xprt *xprt)
+{
+	struct rpcrouter_xprt_info *xprt_info;
+
+	D("Registering xprt %s to RPC Router\n", xprt->name);
+
+	xprt_info = kmalloc(sizeof(struct rpcrouter_xprt_info), GFP_KERNEL);
+	if (!xprt_info)
+		return -ENOMEM;
+
+	xprt_info->xprt = xprt;
+	xprt_info->initialized = 0;
+	xprt_info->remote_pid = -1;
+	init_waitqueue_head(&xprt_info->read_wait);
+	spin_lock_init(&xprt_info->lock);
+	wake_lock_init(&xprt_info->wakelock,
+		       WAKE_LOCK_SUSPEND, xprt->name);
+	xprt_info->need_len = 0;
+	xprt_info->abort_data_read = 0;
+	INIT_WORK(&xprt_info->read_data, do_read_data);
+	INIT_LIST_HEAD(&xprt_info->list);
+
+	xprt_info->workqueue = create_singlethread_workqueue(xprt->name);
+	if (!xprt_info->workqueue) {
+		kfree(xprt_info);
+		return -ENOMEM;
+	}
+
+	if (!strcmp(xprt->name, "rpcrouter_loopback_xprt")) {
+		xprt_info->remote_pid = RPCROUTER_PID_LOCAL;
+		xprt_info->initialized = 1;
+	} else {
+		smsm_change_state(SMSM_APPS_STATE, 0, SMSM_RPCINIT);
+	}
+
+	mutex_lock(&xprt_info_list_lock);
+	list_add_tail(&xprt_info->list, &xprt_info_list);
+	mutex_unlock(&xprt_info_list_lock);
+
+	queue_work(xprt_info->workqueue, &xprt_info->read_data);
+
+	xprt->priv = xprt_info;
+
+	return 0;
+}
+
+static void msm_rpcrouter_remove_xprt(struct rpcrouter_xprt *xprt)
+{
+	struct rpcrouter_xprt_info *xprt_info;
+	unsigned long flags;
+
+	if (xprt && xprt->priv) {
+		xprt_info = xprt->priv;
+
+		/* abort rr_read thread */
+		xprt_info->abort_data_read = 1;
+		wake_up(&xprt_info->read_wait);
+
+		/* remove xprt from available xprts */
+		mutex_lock(&xprt_info_list_lock);
+		spin_lock_irqsave(&xprt_info->lock, flags);
+		list_del(&xprt_info->list);
+
+		/* unlock the spinlock last to avoid a race
+		 * condition with rpcrouter_get_xprt_info
+		 * in msm_rpc_write_pkt in which the
+		 * xprt is returned from rpcrouter_get_xprt_info
+		 * and then deleted here. */
+		mutex_unlock(&xprt_info_list_lock);
+		spin_unlock_irqrestore(&xprt_info->lock, flags);
+
+		/* cleanup workqueues and wakelocks */
+		flush_workqueue(xprt_info->workqueue);
+		destroy_workqueue(xprt_info->workqueue);
+		wake_lock_destroy(&xprt_info->wakelock);
+
+
+		/* free memory */
+		xprt->priv = 0;
+		kfree(xprt_info);
+	}
+}
+
+struct rpcrouter_xprt_work {
+	struct rpcrouter_xprt *xprt;
+	struct work_struct work;
+};
+
+static void xprt_open_worker(struct work_struct *work)
+{
+	struct rpcrouter_xprt_work *xprt_work =
+		container_of(work, struct rpcrouter_xprt_work, work);
+
+	msm_rpcrouter_add_xprt(xprt_work->xprt);
+
+	kfree(xprt_work);
+}
+
+static void xprt_close_worker(struct work_struct *work)
+{
+	struct rpcrouter_xprt_work *xprt_work =
+		container_of(work, struct rpcrouter_xprt_work, work);
+
+	modem_reset_cleanup(xprt_work->xprt->priv);
+	msm_rpcrouter_remove_xprt(xprt_work->xprt);
+
+	if (atomic_dec_return(&pending_close_count) == 0)
+		wake_up(&subsystem_restart_wait);
+
+	kfree(xprt_work);
+}
+
+void msm_rpcrouter_xprt_notify(struct rpcrouter_xprt *xprt, unsigned event)
+{
+	struct rpcrouter_xprt_info *xprt_info;
+	struct rpcrouter_xprt_work *xprt_work;
+
+	/* Workqueue is created in init function which works for all existing
+	 * clients.  If this fails in the future, then it will need to be
+	 * created earlier. */
+	BUG_ON(!rpcrouter_workqueue);
+
+	switch (event) {
+	case RPCROUTER_XPRT_EVENT_OPEN:
+		D("open event for '%s'\n", xprt->name);
+		xprt_work = kmalloc(sizeof(struct rpcrouter_xprt_work),
+				GFP_ATOMIC);
+		xprt_work->xprt = xprt;
+		INIT_WORK(&xprt_work->work, xprt_open_worker);
+		queue_work(rpcrouter_workqueue, &xprt_work->work);
+		break;
+
+	case RPCROUTER_XPRT_EVENT_CLOSE:
+		D("close event for '%s'\n", xprt->name);
+
+		atomic_inc(&pending_close_count);
+
+		xprt_work = kmalloc(sizeof(struct rpcrouter_xprt_work),
+				GFP_ATOMIC);
+		xprt_work->xprt = xprt;
+		INIT_WORK(&xprt_work->work, xprt_close_worker);
+		queue_work(rpcrouter_workqueue, &xprt_work->work);
+		break;
+	}
+
+	xprt_info = xprt->priv;
+	if (xprt_info) {
+		/* Check read_avail even for OPEN event to handle missed
+		   DATA events while processing the OPEN event*/
+		if (xprt->read_avail() >= xprt_info->need_len)
+			wake_lock(&xprt_info->wakelock);
+		wake_up(&xprt_info->read_wait);
+	}
+}
+
+static int modem_restart_notifier_cb(struct notifier_block *this,
+				  unsigned long code,
+				  void *data);
+static struct notifier_block nb = {
+	.notifier_call = modem_restart_notifier_cb,
+};
+
+static int modem_restart_notifier_cb(struct notifier_block *this,
+				  unsigned long code,
+				  void *data)
+{
+	switch (code) {
+	case SUBSYS_BEFORE_SHUTDOWN:
+		D("%s: SUBSYS_BEFORE_SHUTDOWN\n", __func__);
+		break;
+
+	case SUBSYS_BEFORE_POWERUP:
+		D("%s: waiting for RPC restart to complete\n", __func__);
+		wait_event(subsystem_restart_wait,
+			atomic_read(&pending_close_count) == 0);
+		D("%s: finished restart wait\n", __func__);
+		break;
+
+	default:
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static void *restart_notifier_handle;
+static __init int modem_restart_late_init(void)
+{
+	restart_notifier_handle = subsys_notif_register_notifier("modem", &nb);
+	return 0;
+}
+late_initcall(modem_restart_late_init);
+
+static int __init rpcrouter_init(void)
+{
+	int ret;
+
+	msm_rpc_connect_timeout_ms = 0;
+	smd_rpcrouter_debug_mask |= SMEM_LOG;
+	debugfs_init();
+
+
+	/* Initialize what we need to start processing */
+	rpcrouter_workqueue =
+		create_singlethread_workqueue("rpcrouter");
+	if (!rpcrouter_workqueue) {
+		msm_rpcrouter_exit_devices();
+		return -ENOMEM;
+	}
+
+	init_waitqueue_head(&newserver_wait);
+	init_waitqueue_head(&subsystem_restart_wait);
+
+	ret = msm_rpcrouter_init_devices();
+	if (ret < 0)
+		return ret;
+
+	return ret;
+}
+
+module_init(rpcrouter_init);
+MODULE_DESCRIPTION("MSM RPC Router");
+MODULE_AUTHOR("San Mehat <san@android.com>");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/smd_rpcrouter.h b/arch/arm/mach-msm/smd_rpcrouter.h
new file mode 100644
index 0000000..1da7579
--- /dev/null
+++ b/arch/arm/mach-msm/smd_rpcrouter.h
@@ -0,0 +1,266 @@
+/** arch/arm/mach-msm/smd_rpcrouter.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2011, Code Aurora Forum. All rights reserved.
+ * Author: San Mehat <san@android.com>
+ *
+ * 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 _ARCH_ARM_MACH_MSM_SMD_RPCROUTER_H
+#define _ARCH_ARM_MACH_MSM_SMD_RPCROUTER_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+#include <linux/msm_rpcrouter.h>
+#include <linux/wakelock.h>
+
+#include <mach/msm_smd.h>
+#include <mach/msm_rpcrouter.h>
+
+/* definitions for the R2R wire protcol */
+
+#define RPCROUTER_VERSION			1
+#define RPCROUTER_PROCESSORS_MAX		4
+#define RPCROUTER_MSGSIZE_MAX			512
+#define RPCROUTER_PEND_REPLIES_MAX		32
+
+#define RPCROUTER_CLIENT_BCAST_ID		0xffffffff
+#define RPCROUTER_ROUTER_ADDRESS		0xfffffffe
+
+#define RPCROUTER_PID_LOCAL			1
+
+#define RPCROUTER_CTRL_CMD_DATA			1
+#define RPCROUTER_CTRL_CMD_HELLO		2
+#define RPCROUTER_CTRL_CMD_BYE			3
+#define RPCROUTER_CTRL_CMD_NEW_SERVER		4
+#define RPCROUTER_CTRL_CMD_REMOVE_SERVER	5
+#define RPCROUTER_CTRL_CMD_REMOVE_CLIENT	6
+#define RPCROUTER_CTRL_CMD_RESUME_TX		7
+#define RPCROUTER_CTRL_CMD_EXIT			8
+#define RPCROUTER_CTRL_CMD_PING			9
+
+#define RPCROUTER_DEFAULT_RX_QUOTA	5
+
+#define RPCROUTER_XPRT_EVENT_DATA  1
+#define RPCROUTER_XPRT_EVENT_OPEN  2
+#define RPCROUTER_XPRT_EVENT_CLOSE 3
+
+/* Restart states for endpoint.
+ *
+ * Two different bits are specified here, one for
+ * the remote server notification (RESTART_PEND_SVR)
+ * and one for client notification (RESTART_PEND_NTFY).
+ * The client notification is used to ensure that
+ * the client gets notified by an ENETRESET return
+ * code at least once, even if they miss the actual
+ * reset event.  The server notification is used to
+ * properly handle the reset state of the endpoint.
+ */
+#define RESTART_NORMAL 0x0
+#define RESTART_PEND_SVR 0x1
+#define RESTART_PEND_NTFY 0x2
+#define RESTART_PEND_NTFY_SVR (RESTART_PEND_SVR | RESTART_PEND_NTFY)
+
+union rr_control_msg {
+	uint32_t cmd;
+	struct {
+		uint32_t cmd;
+		uint32_t prog;
+		uint32_t vers;
+		uint32_t pid;
+		uint32_t cid;
+	} srv;
+	struct {
+		uint32_t cmd;
+		uint32_t pid;
+		uint32_t cid;
+	} cli;
+};
+
+struct rr_header {
+	uint32_t version;
+	uint32_t type;
+	uint32_t src_pid;
+	uint32_t src_cid;
+	uint32_t confirm_rx;
+	uint32_t size;
+	uint32_t dst_pid;
+	uint32_t dst_cid;
+};
+
+/* internals */
+
+#define RPCROUTER_MAX_REMOTE_SERVERS		100
+
+struct rr_fragment {
+	unsigned char data[RPCROUTER_MSGSIZE_MAX];
+	uint32_t length;
+	struct rr_fragment *next;
+};
+
+struct rr_packet {
+	struct list_head list;
+	struct rr_fragment *first;
+	struct rr_fragment *last;
+	struct rr_header hdr;
+	uint32_t mid;
+	uint32_t length;
+};
+
+#define PACMARK_LAST(n) ((n) & 0x80000000)
+#define PACMARK_MID(n)  (((n) >> 16) & 0xFF)
+#define PACMARK_LEN(n)  ((n) & 0xFFFF)
+
+static inline uint32_t PACMARK(uint32_t len, uint32_t mid, uint32_t first,
+			       uint32_t last)
+{
+	return (len & 0xFFFF) |
+	  ((mid & 0xFF) << 16) |
+	  ((!!first) << 30) |
+	  ((!!last) << 31);
+}
+
+struct rr_server {
+	struct list_head list;
+
+	uint32_t pid;
+	uint32_t cid;
+	uint32_t prog;
+	uint32_t vers;
+
+	dev_t device_number;
+	struct cdev cdev;
+	struct device *device;
+	struct rpcsvr_platform_device p_device;
+	char pdev_name[32];
+};
+
+struct rr_remote_endpoint {
+	uint32_t pid;
+	uint32_t cid;
+
+	int tx_quota_cntr;
+	int quota_restart_state;
+	spinlock_t quota_lock;
+	wait_queue_head_t quota_wait;
+
+	struct list_head list;
+};
+
+struct msm_rpc_reply {
+	struct list_head list;
+	uint32_t pid;
+	uint32_t cid;
+	uint32_t prog; /* be32 */
+	uint32_t vers; /* be32 */
+	uint32_t xid; /* be32 */
+};
+
+struct msm_rpc_endpoint {
+	struct list_head list;
+
+	/* incomplete packets waiting for assembly */
+	struct list_head incomplete;
+	spinlock_t incomplete_lock;
+
+	/* complete packets waiting to be read */
+	struct list_head read_q;
+	spinlock_t read_q_lock;
+	struct wake_lock read_q_wake_lock;
+	wait_queue_head_t wait_q;
+	unsigned flags;
+	uint32_t forced_wakeup;
+
+	/* restart handling */
+	int restart_state;
+	spinlock_t restart_lock;
+	wait_queue_head_t restart_wait;
+
+	/* modem restart notifications */
+	int do_setup_notif;
+	void *client_data;
+	void (*cb_restart_teardown)(void *client_data);
+	void (*cb_restart_setup)(void *client_data);
+
+	/* endpoint address */
+	uint32_t pid;
+	uint32_t cid;
+
+	/* bound remote address
+	 * if not connected (dst_pid == 0xffffffff) RPC_CALL writes fail
+	 * RPC_CALLs must be to the prog/vers below or they will fail
+	 */
+	uint32_t dst_pid;
+	uint32_t dst_cid;
+	uint32_t dst_prog; /* be32 */
+	uint32_t dst_vers; /* be32 */
+
+	/* reply queue for inbound messages */
+	struct list_head reply_pend_q;
+	struct list_head reply_avail_q;
+	spinlock_t reply_q_lock;
+	uint32_t reply_cnt;
+	struct wake_lock reply_q_wake_lock;
+
+	/* device node if this endpoint is accessed via userspace */
+	dev_t dev;
+};
+
+enum write_data_type {
+	HEADER = 1,
+	PACKMARK,
+	PAYLOAD,
+};
+
+struct rpcrouter_xprt {
+	char *name;
+	void *priv;
+
+	int (*read_avail)(void);
+	int (*read)(void *data, uint32_t len);
+	int (*write_avail)(void);
+	int (*write)(void *data, uint32_t len, enum write_data_type type);
+	int (*close)(void);
+};
+
+/* shared between smd_rpcrouter*.c */
+void msm_rpcrouter_xprt_notify(struct rpcrouter_xprt *xprt, unsigned event);
+int __msm_rpc_read(struct msm_rpc_endpoint *ept,
+		   struct rr_fragment **frag,
+		   unsigned len, long timeout);
+
+int msm_rpcrouter_close(void);
+struct msm_rpc_endpoint *msm_rpcrouter_create_local_endpoint(dev_t dev);
+int msm_rpcrouter_destroy_local_endpoint(struct msm_rpc_endpoint *ept);
+
+int msm_rpcrouter_create_server_cdev(struct rr_server *server);
+int msm_rpcrouter_create_server_pdev(struct rr_server *server);
+
+int msm_rpcrouter_init_devices(void);
+void msm_rpcrouter_exit_devices(void);
+
+void get_requesting_client(struct msm_rpc_endpoint *ept, uint32_t xid,
+			   struct msm_rpc_client_info *clnt_info);
+
+extern dev_t msm_rpcrouter_devno;
+extern struct completion rpc_remote_router_up;
+extern struct class *msm_rpcrouter_class;
+
+void xdr_init(struct msm_rpc_xdr *xdr);
+void xdr_init_input(struct msm_rpc_xdr *xdr, void *buf, uint32_t size);
+void xdr_init_output(struct msm_rpc_xdr *xdr, void *buf, uint32_t size);
+void xdr_clean_input(struct msm_rpc_xdr *xdr);
+void xdr_clean_output(struct msm_rpc_xdr *xdr);
+uint32_t xdr_read_avail(struct msm_rpc_xdr *xdr);
+#endif
diff --git a/arch/arm/mach-msm/smd_rpcrouter_clients.c b/arch/arm/mach-msm/smd_rpcrouter_clients.c
new file mode 100644
index 0000000..d94125e
--- /dev/null
+++ b/arch/arm/mach-msm/smd_rpcrouter_clients.c
@@ -0,0 +1,922 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/*
+ * SMD RPCROUTER CLIENTS module.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+
+#include <mach/msm_rpcrouter.h>
+#include "smd_rpcrouter.h"
+
+struct msm_rpc_client_cb_item {
+	struct list_head list;
+
+	void *buf;
+	int size;
+};
+
+struct msm_rpc_cb_table_item {
+	struct list_head list;
+
+	uint32_t cb_id;
+	void *cb_func;
+};
+
+static int rpc_clients_cb_thread(void *data)
+{
+	struct msm_rpc_client_cb_item *cb_item;
+	struct msm_rpc_client *client;
+	struct rpc_request_hdr req;
+	int ret;
+
+	client = data;
+	for (;;) {
+		wait_event(client->cb_wait, client->cb_avail);
+		if (client->exit_flag)
+			break;
+
+		client->cb_avail = 0;
+		mutex_lock(&client->cb_item_list_lock);
+		while (!list_empty(&client->cb_item_list)) {
+			cb_item = list_first_entry(
+				&client->cb_item_list,
+				struct msm_rpc_client_cb_item,
+				list);
+			list_del(&cb_item->list);
+			mutex_unlock(&client->cb_item_list_lock);
+			xdr_init_input(&client->cb_xdr, cb_item->buf,
+				       cb_item->size);
+			ret = xdr_recv_req(&client->cb_xdr, &req);
+			if (ret)
+				goto bad_rpc;
+
+			if (req.type != 0)
+				goto bad_rpc;
+			if (req.rpc_vers != 2)
+				goto bad_rpc;
+			if (req.prog !=
+			    (client->prog | 0x01000000))
+				goto bad_rpc;
+
+			if (client->version == 2)
+				client->cb_func2(client, &req, &client->cb_xdr);
+			else
+				client->cb_func(client, client->cb_xdr.in_buf,
+						client->cb_xdr.in_size);
+ bad_rpc:
+			xdr_clean_input(&client->cb_xdr);
+			kfree(cb_item);
+			mutex_lock(&client->cb_item_list_lock);
+		}
+		mutex_unlock(&client->cb_item_list_lock);
+	}
+	complete_and_exit(&client->cb_complete, 0);
+}
+
+static int rpc_clients_thread(void *data)
+{
+	void *buffer;
+	uint32_t type;
+	struct msm_rpc_client *client;
+	int rc = 0;
+	struct msm_rpc_client_cb_item *cb_item;
+	struct rpc_request_hdr req;
+
+	client = data;
+	for (;;) {
+		buffer = NULL;
+		rc = msm_rpc_read(client->ept, &buffer, -1, -1);
+
+		if (client->exit_flag) {
+			kfree(buffer);
+			break;
+		}
+
+		if (rc < 0) {
+			/* wakeup any pending requests */
+			wake_up(&client->reply_wait);
+			kfree(buffer);
+			continue;
+		}
+
+		if (rc < ((int)(sizeof(uint32_t) * 2))) {
+			kfree(buffer);
+			continue;
+		}
+
+		type = be32_to_cpu(*((uint32_t *)buffer + 1));
+		if (type == 1) {
+			xdr_init_input(&client->xdr, buffer, rc);
+			wake_up(&client->reply_wait);
+		} else if (type == 0) {
+			if (client->cb_thread == NULL) {
+				xdr_init_input(&client->cb_xdr, buffer, rc);
+				xdr_recv_req(&client->cb_xdr, &req);
+
+				if ((req.rpc_vers == 2) &&
+				    (req.prog == (client->prog | 0x01000000))) {
+					if (client->version == 2)
+						client->cb_func2(client, &req,
+							 &client->cb_xdr);
+					else
+						client->cb_func(client,
+						client->cb_xdr.in_buf, rc);
+				}
+				xdr_clean_input(&client->cb_xdr);
+			} else {
+				cb_item = kmalloc(sizeof(*cb_item), GFP_KERNEL);
+				if (!cb_item) {
+					pr_err("%s: no memory for cb item\n",
+					       __func__);
+					continue;
+				}
+
+				INIT_LIST_HEAD(&cb_item->list);
+				cb_item->buf = buffer;
+				cb_item->size = rc;
+				mutex_lock(&client->cb_item_list_lock);
+				list_add_tail(&cb_item->list,
+					      &client->cb_item_list);
+				mutex_unlock(&client->cb_item_list_lock);
+				client->cb_avail = 1;
+				wake_up(&client->cb_wait);
+			}
+		}
+	}
+	complete_and_exit(&client->complete, 0);
+}
+
+static struct msm_rpc_client *msm_rpc_create_client(void)
+{
+	struct msm_rpc_client *client;
+	void *buf;
+
+	client = kmalloc(sizeof(struct msm_rpc_client), GFP_KERNEL);
+	if (!client)
+		return ERR_PTR(-ENOMEM);
+
+	xdr_init(&client->xdr);
+	xdr_init(&client->cb_xdr);
+
+	buf = kmalloc(MSM_RPC_MSGSIZE_MAX, GFP_KERNEL);
+	if (!buf) {
+		kfree(client);
+		return ERR_PTR(-ENOMEM);
+	}
+	xdr_init_output(&client->xdr, buf, MSM_RPC_MSGSIZE_MAX);
+
+	buf = kmalloc(MSM_RPC_MSGSIZE_MAX, GFP_KERNEL);
+	if (!buf) {
+		xdr_clean_output(&client->xdr);
+		kfree(client);
+		return ERR_PTR(-ENOMEM);
+	}
+	xdr_init_output(&client->cb_xdr, buf, MSM_RPC_MSGSIZE_MAX);
+
+	init_waitqueue_head(&client->reply_wait);
+	mutex_init(&client->req_lock);
+	client->buf = NULL;
+	client->cb_buf = NULL;
+	client->cb_size = 0;
+	client->exit_flag = 0;
+	client->cb_restart_teardown = NULL;
+	client->cb_restart_setup = NULL;
+	client->in_reset = 0;
+
+	init_completion(&client->complete);
+	init_completion(&client->cb_complete);
+	INIT_LIST_HEAD(&client->cb_item_list);
+	mutex_init(&client->cb_item_list_lock);
+	client->cb_avail = 0;
+	init_waitqueue_head(&client->cb_wait);
+	INIT_LIST_HEAD(&client->cb_list);
+	spin_lock_init(&client->cb_list_lock);
+	atomic_set(&client->next_cb_id, 1);
+
+	return client;
+}
+
+static void msm_rpc_destroy_client(struct msm_rpc_client *client)
+{
+	xdr_clean_output(&client->xdr);
+	xdr_clean_output(&client->cb_xdr);
+
+	kfree(client);
+}
+
+void msm_rpc_remove_all_cb_func(struct msm_rpc_client *client)
+{
+	struct msm_rpc_cb_table_item *cb_item, *tmp_cb_item;
+	unsigned long flags;
+
+	spin_lock_irqsave(&client->cb_list_lock, flags);
+	list_for_each_entry_safe(cb_item, tmp_cb_item,
+				 &client->cb_list, list) {
+		list_del(&cb_item->list);
+		kfree(cb_item);
+	}
+	spin_unlock_irqrestore(&client->cb_list_lock, flags);
+}
+
+static void cb_restart_teardown(void *client_data)
+{
+	struct msm_rpc_client *client;
+
+	client = (struct msm_rpc_client *)client_data;
+	if (client) {
+		client->in_reset = 1;
+		msm_rpc_remove_all_cb_func(client);
+		client->xdr.out_index = 0;
+
+		if (client->cb_restart_teardown)
+			client->cb_restart_teardown(client);
+	}
+}
+
+static void cb_restart_setup(void *client_data)
+{
+	struct msm_rpc_client *client;
+
+	client = (struct msm_rpc_client *)client_data;
+
+	if (client) {
+		client->in_reset = 0;
+		if (client->cb_restart_setup)
+			client->cb_restart_setup(client);
+	}
+}
+
+/* Returns the reset state of the client.
+ *
+ * Return Value:
+ *	0 if client isn't in reset, >0 otherwise.
+ */
+int msm_rpc_client_in_reset(struct msm_rpc_client *client)
+{
+	int ret = 1;
+
+	if (client)
+		ret = client->in_reset;
+
+	return ret;
+}
+EXPORT_SYMBOL(msm_rpc_client_in_reset);
+
+/*
+ * Interface to be used to register the client.
+ *
+ * name: string representing the client
+ *
+ * prog: program number of the client
+ *
+ * ver: version number of the client
+ *
+ * create_cb_thread: if set calls the callback function from a seprate thread
+ *                   which helps the client requests to be processed without
+ *                   getting loaded by callback handling.
+ *
+ * cb_func: function to be called if callback request is received.
+ *          unmarshaling should be handled by the user in callback function
+ *
+ * Return Value:
+ *        Pointer to initialized client data sturcture
+ *        Or, the error code if registration fails.
+ *
+ */
+struct msm_rpc_client *msm_rpc_register_client(
+	const char *name,
+	uint32_t prog, uint32_t ver,
+	uint32_t create_cb_thread,
+	int (*cb_func)(struct msm_rpc_client *, void *, int))
+{
+	struct msm_rpc_client *client;
+	struct msm_rpc_endpoint *ept;
+	int rc;
+
+	client = msm_rpc_create_client();
+	if (IS_ERR(client))
+		return client;
+
+	ept = msm_rpc_connect_compatible(prog, ver, MSM_RPC_UNINTERRUPTIBLE);
+	if (IS_ERR(ept)) {
+		msm_rpc_destroy_client(client);
+		return (struct msm_rpc_client *)ept;
+	}
+
+	ept->client_data = client;
+	ept->cb_restart_teardown = cb_restart_teardown;
+	ept->cb_restart_setup = cb_restart_setup;
+
+	client->prog = prog;
+	client->ver = ver;
+	client->ept = client->xdr.ept = client->cb_xdr.ept = ept;
+	client->cb_func = cb_func;
+	client->version = 1;
+
+	/* start the read thread */
+	client->read_thread = kthread_run(rpc_clients_thread, client,
+					  "k%sclntd", name);
+	if (IS_ERR(client->read_thread)) {
+		rc = PTR_ERR(client->read_thread);
+		msm_rpc_close(client->ept);
+		msm_rpc_destroy_client(client);
+		return ERR_PTR(rc);
+	}
+
+	if (!create_cb_thread || (cb_func == NULL)) {
+		client->cb_thread = NULL;
+		return client;
+	}
+
+	/* start the callback thread */
+	client->cb_thread = kthread_run(rpc_clients_cb_thread, client,
+					"k%sclntcbd", name);
+	if (IS_ERR(client->cb_thread)) {
+		rc = PTR_ERR(client->cb_thread);
+		client->exit_flag = 1;
+		msm_rpc_read_wakeup(client->ept);
+		wait_for_completion(&client->complete);
+		msm_rpc_close(client->ept);
+		msm_rpc_destroy_client(client);
+		return ERR_PTR(rc);
+	}
+
+	return client;
+}
+EXPORT_SYMBOL(msm_rpc_register_client);
+
+/*
+ * Interface to be used to register the client.
+ *
+ * name: string representing the client
+ *
+ * prog: program number of the client
+ *
+ * ver: version number of the client
+ *
+ * create_cb_thread: if set calls the callback function from a seprate thread
+ *                   which helps the client requests to be processed without
+ *                   getting loaded by callback handling.
+ *
+ * cb_func: function to be called if callback request is received.
+ *          unmarshaling should be handled by the user in callback function
+ *
+ * Return Value:
+ *        Pointer to initialized client data sturcture
+ *        Or, the error code if registration fails.
+ *
+ */
+struct msm_rpc_client *msm_rpc_register_client2(
+	const char *name,
+	uint32_t prog, uint32_t ver,
+	uint32_t create_cb_thread,
+	int (*cb_func)(struct msm_rpc_client *,
+		       struct rpc_request_hdr *req, struct msm_rpc_xdr *))
+{
+	struct msm_rpc_client *client;
+	struct msm_rpc_endpoint *ept;
+	int rc;
+
+	client = msm_rpc_create_client();
+	if (IS_ERR(client))
+		return client;
+
+	ept = msm_rpc_connect_compatible(prog, ver, MSM_RPC_UNINTERRUPTIBLE);
+	if (IS_ERR(ept)) {
+		msm_rpc_destroy_client(client);
+		return (struct msm_rpc_client *)ept;
+	}
+
+	client->prog = prog;
+	client->ver = ver;
+	client->ept = client->xdr.ept = client->cb_xdr.ept = ept;
+	client->cb_func2 = cb_func;
+	client->version = 2;
+
+	ept->client_data = client;
+	ept->cb_restart_teardown = cb_restart_teardown;
+	ept->cb_restart_setup = cb_restart_setup;
+
+	/* start the read thread */
+	client->read_thread = kthread_run(rpc_clients_thread, client,
+					  "k%sclntd", name);
+	if (IS_ERR(client->read_thread)) {
+		rc = PTR_ERR(client->read_thread);
+		msm_rpc_close(client->ept);
+		msm_rpc_destroy_client(client);
+		return ERR_PTR(rc);
+	}
+
+	if (!create_cb_thread || (cb_func == NULL)) {
+		client->cb_thread = NULL;
+		return client;
+	}
+
+	/* start the callback thread */
+	client->cb_thread = kthread_run(rpc_clients_cb_thread, client,
+					"k%sclntcbd", name);
+	if (IS_ERR(client->cb_thread)) {
+		rc = PTR_ERR(client->cb_thread);
+		client->exit_flag = 1;
+		msm_rpc_read_wakeup(client->ept);
+		wait_for_completion(&client->complete);
+		msm_rpc_close(client->ept);
+		msm_rpc_destroy_client(client);
+		return ERR_PTR(rc);
+	}
+
+	return client;
+}
+EXPORT_SYMBOL(msm_rpc_register_client2);
+
+/*
+ * Register callbacks for modem state changes.
+ *
+ * Teardown is called when the modem is going into reset.
+ * Setup is called after the modem has come out of reset (but may not
+ * be available, yet).
+ *
+ * client: pointer to client data structure.
+ *
+ * Return Value:
+ *        0 (success)
+ *        1 (client pointer invalid)
+ */
+int msm_rpc_register_reset_callbacks(
+	struct msm_rpc_client *client,
+	void (*teardown)(struct msm_rpc_client *client),
+	void (*setup)(struct msm_rpc_client *client)
+	)
+{
+	int rc = 1;
+
+	if (client) {
+		client->cb_restart_teardown = teardown;
+		client->cb_restart_setup = setup;
+		rc = 0;
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_rpc_register_reset_callbacks);
+
+/*
+ * Interface to be used to unregister the client
+ * No client operations should be done once the unregister function
+ * is called.
+ *
+ * client: pointer to client data structure.
+ *
+ * Return Value:
+ *        Always returns 0 (success).
+ */
+int msm_rpc_unregister_client(struct msm_rpc_client *client)
+{
+	pr_info("%s: stopping client...\n", __func__);
+	client->exit_flag = 1;
+	if (client->cb_thread) {
+		client->cb_avail = 1;
+		wake_up(&client->cb_wait);
+		wait_for_completion(&client->cb_complete);
+	}
+
+	msm_rpc_read_wakeup(client->ept);
+	wait_for_completion(&client->complete);
+
+	msm_rpc_close(client->ept);
+	msm_rpc_remove_all_cb_func(client);
+	xdr_clean_output(&client->xdr);
+	xdr_clean_output(&client->cb_xdr);
+	kfree(client);
+	return 0;
+}
+EXPORT_SYMBOL(msm_rpc_unregister_client);
+
+/*
+ * Interface to be used to send a client request.
+ * If the request takes any arguments or expects any return, the user
+ * should handle it in 'arg_func' and 'ret_func' respectively.
+ * Marshaling and Unmarshaling should be handled by the user in argument
+ * and return functions.
+ *
+ * client: pointer to client data sturcture
+ *
+ * proc: procedure being requested
+ *
+ * arg_func: argument function pointer.  'buf' is where arguments needs to
+ *   be filled. 'data' is arg_data.
+ *
+ * ret_func: return function pointer.  'buf' is where returned data should
+ *   be read from. 'data' is ret_data.
+ *
+ * arg_data: passed as an input parameter to argument function.
+ *
+ * ret_data: passed as an input parameter to return function.
+ *
+ * timeout: timeout for reply wait in jiffies.  If negative timeout is
+ *   specified a default timeout of 10s is used.
+ *
+ * Return Value:
+ *        0 on success, otherwise an error code is returned.
+ */
+int msm_rpc_client_req(struct msm_rpc_client *client, uint32_t proc,
+		       int (*arg_func)(struct msm_rpc_client *client,
+				       void *buf, void *data),
+		       void *arg_data,
+		       int (*ret_func)(struct msm_rpc_client *client,
+				       void *buf, void *data),
+		       void *ret_data, long timeout)
+{
+	struct rpc_reply_hdr *rpc_rsp;
+	int rc = 0;
+	uint32_t req_xid;
+
+	mutex_lock(&client->req_lock);
+
+	msm_rpc_setup_req((struct rpc_request_hdr *)client->xdr.out_buf,
+			  client->prog, client->ver, proc);
+	client->xdr.out_index = sizeof(struct rpc_request_hdr);
+	req_xid = *(uint32_t *)client->xdr.out_buf;
+	if (arg_func) {
+		rc = arg_func(client,
+			      (void *)((struct rpc_request_hdr *)
+				       client->xdr.out_buf + 1),
+			      arg_data);
+		if (rc < 0)
+			goto release_locks;
+		else
+			client->xdr.out_index += rc;
+	}
+
+	rc = msm_rpc_write(client->ept, client->xdr.out_buf,
+			   client->xdr.out_index);
+	if (rc < 0) {
+		pr_err("%s: couldn't send RPC request:%d\n", __func__, rc);
+		goto release_locks;
+	} else
+		rc = 0;
+
+	if (timeout < 0)
+		timeout = msecs_to_jiffies(10000);
+
+	do {
+		rc = wait_event_timeout(client->reply_wait,
+			xdr_read_avail(&client->xdr) || client->in_reset,
+			timeout);
+
+		if (client->in_reset) {
+			rc = -ENETRESET;
+			goto release_locks;
+		}
+
+		if (rc == 0) {
+			pr_err("%s: request timeout\n", __func__);
+			rc = -ETIMEDOUT;
+			goto release_locks;
+		}
+
+		rpc_rsp = (struct rpc_reply_hdr *)client->xdr.in_buf;
+		if (req_xid != rpc_rsp->xid) {
+			pr_info("%s: xid mismatch, req %d reply %d\n",
+			       __func__, be32_to_cpu(req_xid),
+			       be32_to_cpu(rpc_rsp->xid));
+			timeout = rc;
+			xdr_clean_input(&client->xdr);
+		} else
+			rc = 0;
+	} while (rc);
+
+	if (be32_to_cpu(rpc_rsp->reply_stat) != RPCMSG_REPLYSTAT_ACCEPTED) {
+		pr_err("%s: RPC call was denied! %d\n", __func__,
+		       be32_to_cpu(rpc_rsp->reply_stat));
+		rc = -EPERM;
+		goto free_and_release;
+	}
+
+	if (be32_to_cpu(rpc_rsp->data.acc_hdr.accept_stat) !=
+	    RPC_ACCEPTSTAT_SUCCESS) {
+		pr_err("%s: RPC call was not successful (%d)\n", __func__,
+		       be32_to_cpu(rpc_rsp->data.acc_hdr.accept_stat));
+		rc = -EINVAL;
+		goto free_and_release;
+	}
+
+	if (ret_func)
+		rc = ret_func(client, (void *)(rpc_rsp + 1), ret_data);
+
+ free_and_release:
+	xdr_clean_input(&client->xdr);
+	client->xdr.out_index = 0;
+ release_locks:
+	mutex_unlock(&client->req_lock);
+	return rc;
+}
+EXPORT_SYMBOL(msm_rpc_client_req);
+
+/*
+ * Interface to be used to send a client request.
+ * If the request takes any arguments or expects any return, the user
+ * should handle it in 'arg_func' and 'ret_func' respectively.
+ * Marshaling and Unmarshaling should be handled by the user in argument
+ * and return functions.
+ *
+ * client: pointer to client data sturcture
+ *
+ * proc: procedure being requested
+ *
+ * arg_func: argument function pointer.  'xdr' is the xdr being used.
+ *   'data' is arg_data.
+ *
+ * ret_func: return function pointer.  'xdr' is the xdr being used.
+ *   'data' is ret_data.
+ *
+ * arg_data: passed as an input parameter to argument function.
+ *
+ * ret_data: passed as an input parameter to return function.
+ *
+ * timeout: timeout for reply wait in jiffies.  If negative timeout is
+ *   specified a default timeout of 10s is used.
+ *
+ * Return Value:
+ *        0 on success, otherwise an error code is returned.
+ */
+int msm_rpc_client_req2(struct msm_rpc_client *client, uint32_t proc,
+			int (*arg_func)(struct msm_rpc_client *client,
+					struct msm_rpc_xdr *xdr, void *data),
+			void *arg_data,
+			int (*ret_func)(struct msm_rpc_client *client,
+					struct msm_rpc_xdr *xdr, void *data),
+			void *ret_data, long timeout)
+{
+	struct rpc_reply_hdr rpc_rsp;
+	int rc = 0;
+	uint32_t req_xid;
+
+	mutex_lock(&client->req_lock);
+
+	if (client->in_reset) {
+		rc = -ENETRESET;
+		goto release_locks;
+	}
+
+	xdr_start_request(&client->xdr, client->prog, client->ver, proc);
+	req_xid = be32_to_cpu(*(uint32_t *)client->xdr.out_buf);
+	if (arg_func) {
+		rc = arg_func(client, &client->xdr, arg_data);
+		if (rc < 0) {
+			mutex_unlock(&client->xdr.out_lock);
+			goto release_locks;
+		}
+	}
+
+	rc = xdr_send_msg(&client->xdr);
+	if (rc < 0) {
+		pr_err("%s: couldn't send RPC request:%d\n", __func__, rc);
+		goto release_locks;
+	} else
+		rc = 0;
+
+	if (timeout < 0)
+		timeout = msecs_to_jiffies(10000);
+
+	do {
+		rc = wait_event_timeout(client->reply_wait,
+			xdr_read_avail(&client->xdr) || client->in_reset,
+			timeout);
+
+		if (client->in_reset) {
+			rc = -ENETRESET;
+			goto release_locks;
+		}
+
+		if (rc == 0) {
+			pr_err("%s: request timeout\n", __func__);
+			rc = -ETIMEDOUT;
+			goto release_locks;
+		}
+
+		xdr_recv_reply(&client->xdr, &rpc_rsp);
+		/* TODO: may be this check should be a xdr function */
+		if (req_xid != rpc_rsp.xid) {
+			pr_info("%s: xid mismatch, req %d reply %d\n",
+				__func__, req_xid, rpc_rsp.xid);
+			timeout = rc;
+			xdr_clean_input(&client->xdr);
+		} else
+			rc = 0;
+	} while (rc);
+
+	if (rpc_rsp.reply_stat != RPCMSG_REPLYSTAT_ACCEPTED) {
+		pr_err("%s: RPC call was denied! %d\n",
+		       __func__, rpc_rsp.reply_stat);
+		rc = -EPERM;
+		goto free_and_release;
+	}
+
+	if (rpc_rsp.data.acc_hdr.accept_stat != RPC_ACCEPTSTAT_SUCCESS) {
+		pr_err("%s: RPC call was not successful (%d)\n", __func__,
+		       rpc_rsp.data.acc_hdr.accept_stat);
+		rc = -EINVAL;
+		goto free_and_release;
+	}
+
+	if (ret_func)
+		rc = ret_func(client, &client->xdr, ret_data);
+
+ free_and_release:
+	xdr_clean_input(&client->xdr);
+	/* TODO: put it in xdr_reset_output */
+	client->xdr.out_index = 0;
+ release_locks:
+	mutex_unlock(&client->req_lock);
+	return rc;
+}
+EXPORT_SYMBOL(msm_rpc_client_req2);
+
+/*
+ * Interface to be used to start accepted reply message required in
+ * callback handling. Returns the buffer pointer to attach any
+ * payload.  Should call msm_rpc_send_accepted_reply to complete
+ * sending reply.  Marshaling should be handled by user for the payload.
+ *
+ * client: pointer to client data structure
+ *
+ * xid: transaction id. Has to be same as the one in callback request.
+ *
+ * accept_status: acceptance status
+ *
+ * Return Value:
+ *        pointer to buffer to attach the payload.
+ */
+void *msm_rpc_start_accepted_reply(struct msm_rpc_client *client,
+				   uint32_t xid, uint32_t accept_status)
+{
+	struct rpc_reply_hdr *reply;
+
+	mutex_lock(&client->cb_xdr.out_lock);
+
+	reply = (struct rpc_reply_hdr *)client->cb_xdr.out_buf;
+
+	reply->xid = cpu_to_be32(xid);
+	reply->type = cpu_to_be32(1); /* reply */
+	reply->reply_stat = cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED);
+
+	reply->data.acc_hdr.accept_stat = cpu_to_be32(accept_status);
+	reply->data.acc_hdr.verf_flavor = 0;
+	reply->data.acc_hdr.verf_length = 0;
+
+	client->cb_xdr.out_index = sizeof(*reply);
+	return reply + 1;
+}
+EXPORT_SYMBOL(msm_rpc_start_accepted_reply);
+
+/*
+ * Interface to be used to send accepted reply required in callback handling.
+ * msm_rpc_start_accepted_reply should have been called before.
+ * Marshaling should be handled by user for the payload.
+ *
+ * client: pointer to client data structure
+ *
+ * size: additional payload size
+ *
+ * Return Value:
+ *        0 on success, otherwise returns an error code.
+ */
+int msm_rpc_send_accepted_reply(struct msm_rpc_client *client, uint32_t size)
+{
+	int rc = 0;
+
+	client->cb_xdr.out_index += size;
+	rc = msm_rpc_write(client->ept, client->cb_xdr.out_buf,
+			   client->cb_xdr.out_index);
+	if (rc > 0)
+		rc = 0;
+
+	mutex_unlock(&client->cb_xdr.out_lock);
+	return rc;
+}
+EXPORT_SYMBOL(msm_rpc_send_accepted_reply);
+
+/*
+ * Interface to be used to add a callback function.
+ * If the call back function is already in client's 'cb_id - cb_func'
+ * table, then that cb_id is returned.  otherwise, new entry
+ * is added to the above table and corresponding cb_id is returned.
+ *
+ * client: pointer to client data structure
+ *
+ * cb_func: callback function
+ *
+ * Return Value:
+ *         callback ID on success, otherwise returns an error code.
+ *         If cb_func is NULL, the callback Id returned is 0xffffffff.
+ *         This tells the other processor that no callback is reqested.
+ */
+int msm_rpc_add_cb_func(struct msm_rpc_client *client, void *cb_func)
+{
+	struct msm_rpc_cb_table_item *cb_item;
+	unsigned long flags;
+
+	if (cb_func == NULL)
+		return MSM_RPC_CLIENT_NULL_CB_ID;
+
+	spin_lock_irqsave(&client->cb_list_lock, flags);
+	list_for_each_entry(cb_item, &client->cb_list, list) {
+		if (cb_item->cb_func == cb_func) {
+			spin_unlock_irqrestore(&client->cb_list_lock, flags);
+			return cb_item->cb_id;
+		}
+	}
+	spin_unlock_irqrestore(&client->cb_list_lock, flags);
+
+	cb_item = kmalloc(sizeof(struct msm_rpc_cb_table_item), GFP_KERNEL);
+	if (!cb_item)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&cb_item->list);
+	cb_item->cb_id = atomic_add_return(1, &client->next_cb_id);
+	cb_item->cb_func = cb_func;
+
+	spin_lock_irqsave(&client->cb_list_lock, flags);
+	list_add_tail(&cb_item->list, &client->cb_list);
+	spin_unlock_irqrestore(&client->cb_list_lock, flags);
+
+	return cb_item->cb_id;
+}
+EXPORT_SYMBOL(msm_rpc_add_cb_func);
+
+/*
+ * Interface to be used to get a callback function from a callback ID.
+ * If no entry is found, NULL is returned.
+ *
+ * client: pointer to client data structure
+ *
+ * cb_id: callback ID
+ *
+ * Return Value:
+ *         callback function pointer if entry with given cb_id is found,
+ *         otherwise returns NULL.
+ */
+void *msm_rpc_get_cb_func(struct msm_rpc_client *client, uint32_t cb_id)
+{
+	struct msm_rpc_cb_table_item *cb_item;
+	unsigned long flags;
+
+	spin_lock_irqsave(&client->cb_list_lock, flags);
+	list_for_each_entry(cb_item, &client->cb_list, list) {
+		if (cb_item->cb_id == cb_id) {
+			spin_unlock_irqrestore(&client->cb_list_lock, flags);
+			return cb_item->cb_func;
+		}
+	}
+	spin_unlock_irqrestore(&client->cb_list_lock, flags);
+	return NULL;
+}
+EXPORT_SYMBOL(msm_rpc_get_cb_func);
+
+/*
+ * Interface to be used to remove a callback function.
+ *
+ * client: pointer to client data structure
+ *
+ * cb_func: callback function
+ *
+ */
+void msm_rpc_remove_cb_func(struct msm_rpc_client *client, void *cb_func)
+{
+	struct msm_rpc_cb_table_item *cb_item, *tmp_cb_item;
+	unsigned long flags;
+
+	if (cb_func == NULL)
+		return;
+
+	spin_lock_irqsave(&client->cb_list_lock, flags);
+	list_for_each_entry_safe(cb_item, tmp_cb_item,
+				 &client->cb_list, list) {
+		if (cb_item->cb_func == cb_func) {
+			list_del(&cb_item->list);
+			kfree(cb_item);
+			spin_unlock_irqrestore(&client->cb_list_lock, flags);
+			return;
+		}
+	}
+	spin_unlock_irqrestore(&client->cb_list_lock, flags);
+}
+EXPORT_SYMBOL(msm_rpc_remove_cb_func);
diff --git a/arch/arm/mach-msm/smd_rpcrouter_device.c b/arch/arm/mach-msm/smd_rpcrouter_device.c
new file mode 100644
index 0000000..e84d213
--- /dev/null
+++ b/arch/arm/mach-msm/smd_rpcrouter_device.c
@@ -0,0 +1,476 @@
+/* arch/arm/mach-msm/smd_rpcrouter_device.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2011, Code Aurora Forum. All rights reserved.
+ * Author: San Mehat <san@android.com>
+ *
+ * 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.
+ *
+ */
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/cdev.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/err.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/platform_device.h>
+#include <linux/msm_rpcrouter.h>
+
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+
+#include <mach/peripheral-loader.h>
+#include "smd_rpcrouter.h"
+
+/* Support 64KB of data plus some space for headers */
+#define SAFETY_MEM_SIZE (65536 + sizeof(struct rpc_request_hdr))
+
+/* modem load timeout */
+#define MODEM_LOAD_TIMEOUT (10 * HZ)
+
+/* Next minor # available for a remote server */
+static int next_minor = 1;
+static DEFINE_SPINLOCK(server_cdev_lock);
+
+struct class *msm_rpcrouter_class;
+dev_t msm_rpcrouter_devno;
+
+static struct cdev rpcrouter_cdev;
+static struct device *rpcrouter_device;
+
+struct rpcrouter_file_info {
+	struct msm_rpc_endpoint *ept;
+	void *modem_pil;
+};
+
+static void msm_rpcrouter_unload_modem(void *pil)
+{
+	if (pil)
+		pil_put(pil);
+}
+
+static void *msm_rpcrouter_load_modem(void)
+{
+	void *pil;
+	int rc;
+
+	pil = pil_get("modem");
+	if (IS_ERR(pil))
+		pr_err("%s: modem load failed\n", __func__);
+	else {
+		rc = wait_for_completion_interruptible_timeout(
+						&rpc_remote_router_up,
+						MODEM_LOAD_TIMEOUT);
+		if (!rc)
+			rc = -ETIMEDOUT;
+		if (rc < 0) {
+			pr_err("%s: wait for remote router failed %d\n",
+			       __func__, rc);
+			msm_rpcrouter_unload_modem(pil);
+			pil = ERR_PTR(rc);
+		}
+	}
+
+	return pil;
+}
+
+static int rpcrouter_open(struct inode *inode, struct file *filp)
+{
+	int rc;
+	void *pil;
+	struct msm_rpc_endpoint *ept;
+	struct rpcrouter_file_info *file_info;
+
+	rc = nonseekable_open(inode, filp);
+	if (rc < 0)
+		return rc;
+
+	file_info = kzalloc(sizeof(*file_info), GFP_KERNEL);
+	if (!file_info)
+		return -ENOMEM;
+
+	ept = msm_rpcrouter_create_local_endpoint(inode->i_rdev);
+	if (!ept) {
+		kfree(file_info);
+		return -ENOMEM;
+	}
+	file_info->ept = ept;
+
+	/* if router device, load the modem */
+	if (inode->i_rdev == msm_rpcrouter_devno) {
+		pil = msm_rpcrouter_load_modem();
+		if (IS_ERR(pil)) {
+			kfree(file_info);
+			msm_rpcrouter_destroy_local_endpoint(ept);
+			return PTR_ERR(pil);
+		}
+		file_info->modem_pil = pil;
+	}
+
+	filp->private_data = file_info;
+	return 0;
+}
+
+static int rpcrouter_release(struct inode *inode, struct file *filp)
+{
+	struct rpcrouter_file_info *file_info = filp->private_data;
+	struct msm_rpc_endpoint *ept;
+	static unsigned int rpcrouter_release_cnt;
+
+	ept = (struct msm_rpc_endpoint *) file_info->ept;
+
+	/* A user program with many files open when ends abruptly,
+	 * will cause a flood of REMOVE_CLIENT messages to the
+	 * remote processor.  This will cause remote processors
+	 * internal queue to overflow. Inserting a sleep here
+	 * regularly is the effecient option.
+	 */
+	if (rpcrouter_release_cnt++ % 2)
+		msleep(1);
+
+	/* if router device, unload the modem */
+	if (inode->i_rdev == msm_rpcrouter_devno)
+		msm_rpcrouter_unload_modem(file_info->modem_pil);
+
+	kfree(file_info);
+	return msm_rpcrouter_destroy_local_endpoint(ept);
+}
+
+static ssize_t rpcrouter_read(struct file *filp, char __user *buf,
+			      size_t count, loff_t *ppos)
+{
+	struct rpcrouter_file_info *file_info = filp->private_data;
+	struct msm_rpc_endpoint *ept;
+	struct rr_fragment *frag, *next;
+	int rc;
+
+	ept = (struct msm_rpc_endpoint *) file_info->ept;
+
+	rc = __msm_rpc_read(ept, &frag, count, -1);
+	if (rc < 0)
+		return rc;
+
+	count = rc;
+
+	while (frag != NULL) {		
+		if (copy_to_user(buf, frag->data, frag->length)) {
+			printk(KERN_ERR
+			       "rpcrouter: could not copy all read data to user!\n");
+			rc = -EFAULT;
+		}
+		buf += frag->length;
+		next = frag->next;
+		kfree(frag);
+		frag = next;
+	}
+
+	return rc;
+}
+
+static ssize_t rpcrouter_write(struct file *filp, const char __user *buf,
+				size_t count, loff_t *ppos)
+{
+	struct rpcrouter_file_info *file_info = filp->private_data;
+	struct msm_rpc_endpoint	*ept;
+	int rc = 0;
+	void *k_buffer;
+
+	ept = (struct msm_rpc_endpoint *) file_info->ept;
+
+	/* A check for safety, this seems non-standard */
+	if (count > SAFETY_MEM_SIZE)
+		return -EINVAL;
+
+	k_buffer = kmalloc(count, GFP_KERNEL);
+	if (!k_buffer)
+		return -ENOMEM;
+
+	if (copy_from_user(k_buffer, buf, count)) {
+		rc = -EFAULT;
+		goto write_out_free;
+	}
+
+	rc = msm_rpc_write(ept, k_buffer, count);
+	if (rc < 0)
+		goto write_out_free;
+
+	rc = count;
+write_out_free:
+	kfree(k_buffer);
+	return rc;
+}
+
+/* RPC VFS Poll Implementation
+ *
+ * POLLRDHUP - restart in progress
+ * POLLOUT - writes accepted (without blocking)
+ * POLLIN - data ready to read
+ *
+ * The restart state consists of several different phases including a client
+ * notification and a server restart.  If the server has been restarted, then
+ * reads and writes can be performed and the POLLOUT bit will be set.  If a
+ * restart is in progress, but the server hasn't been restarted, then only the
+ * POLLRDHUP is active and reads and writes will block.  See the table
+ * below for a summary.  POLLRDHUP is cleared once a call to msm_rpc_write_pkt
+ * or msm_rpc_read_pkt returns ENETRESET.
+ *
+ * POLLOUT	POLLRDHUP
+ *    1         0       Normal operation
+ *    0         1       Restart in progress and server hasn't restarted yet
+ *    1         1       Server has been restarted, but client has
+ *                      not been notified of a restart by a return code
+ *                      of ENETRESET from msm_rpc_write_pkt or
+ *                      msm_rpc_read_pkt.
+ */
+static unsigned int rpcrouter_poll(struct file *filp,
+				   struct poll_table_struct *wait)
+{
+	struct rpcrouter_file_info *file_info = filp->private_data;
+	struct msm_rpc_endpoint *ept;
+	unsigned mask = 0;
+
+	ept = (struct msm_rpc_endpoint *) file_info->ept;
+
+	poll_wait(filp, &ept->wait_q, wait);
+	poll_wait(filp, &ept->restart_wait, wait);
+
+	if (!list_empty(&ept->read_q))
+		mask |= POLLIN;
+	if (!(ept->restart_state & RESTART_PEND_SVR))
+		mask |= POLLOUT;
+	if (ept->restart_state != 0)
+		mask |= POLLRDHUP;
+
+	return mask;
+}
+
+static long rpcrouter_ioctl(struct file *filp, unsigned int cmd,
+			    unsigned long arg)
+{
+	struct rpcrouter_file_info *file_info = filp->private_data;
+	struct msm_rpc_endpoint *ept;
+	struct rpcrouter_ioctl_server_args server_args;
+	int rc = 0;
+	uint32_t n;
+
+	ept = (struct msm_rpc_endpoint *) file_info->ept;
+	switch (cmd) {
+
+	case RPC_ROUTER_IOCTL_GET_VERSION:
+		n = RPC_ROUTER_VERSION_V1;
+		rc = put_user(n, (unsigned int *) arg);
+		break;
+
+	case RPC_ROUTER_IOCTL_GET_MTU:
+		/* the pacmark word reduces the actual payload
+		 * possible per message
+		 */
+		n = RPCROUTER_MSGSIZE_MAX - sizeof(uint32_t);
+		rc = put_user(n, (unsigned int *) arg);
+		break;
+
+	case RPC_ROUTER_IOCTL_REGISTER_SERVER:
+		rc = copy_from_user(&server_args, (void *) arg,
+				    sizeof(server_args));
+		if (rc < 0)
+			break;
+		msm_rpc_register_server(ept,
+					server_args.prog,
+					server_args.vers);
+		break;
+
+	case RPC_ROUTER_IOCTL_UNREGISTER_SERVER:
+		rc = copy_from_user(&server_args, (void *) arg,
+				    sizeof(server_args));
+		if (rc < 0)
+			break;
+
+		msm_rpc_unregister_server(ept,
+					  server_args.prog,
+					  server_args.vers);
+		break;
+
+	case RPC_ROUTER_IOCTL_CLEAR_NETRESET:
+		msm_rpc_clear_netreset(ept);
+		break;
+
+	case RPC_ROUTER_IOCTL_GET_CURR_PKT_SIZE:
+		rc = msm_rpc_get_curr_pkt_size(ept);
+		break;
+
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+static struct file_operations rpcrouter_server_fops = {
+	.owner	 = THIS_MODULE,
+	.open	 = rpcrouter_open,
+	.release = rpcrouter_release,
+	.read	 = rpcrouter_read,
+	.write	 = rpcrouter_write,
+	.poll    = rpcrouter_poll,
+	.unlocked_ioctl	 = rpcrouter_ioctl,
+};
+
+static struct file_operations rpcrouter_router_fops = {
+	.owner	 = THIS_MODULE,
+	.open	 = rpcrouter_open,
+	.release = rpcrouter_release,
+	.read	 = rpcrouter_read,
+	.write	 = rpcrouter_write,
+	.poll    = rpcrouter_poll,
+	.unlocked_ioctl = rpcrouter_ioctl,
+};
+
+int msm_rpcrouter_create_server_cdev(struct rr_server *server)
+{
+	int rc;
+	uint32_t dev_vers;
+	unsigned long flags;
+
+	spin_lock_irqsave(&server_cdev_lock, flags);
+	if (next_minor == RPCROUTER_MAX_REMOTE_SERVERS) {
+		spin_unlock_irqrestore(&server_cdev_lock, flags);
+		printk(KERN_ERR
+		       "rpcrouter: Minor numbers exhausted - Increase "
+		       "RPCROUTER_MAX_REMOTE_SERVERS\n");
+		return -ENOBUFS;
+	}
+
+	/* Servers with bit 31 set are remote msm servers with hashkey version.
+	 * Servers with bit 31 not set are remote msm servers with
+	 * backwards compatible version type in which case the minor number
+	 * (lower 16 bits) is set to zero.
+	 *
+	 */
+	if ((server->vers & 0x80000000))
+		dev_vers = server->vers;
+	else
+		dev_vers = server->vers & 0xffff0000;
+
+	server->device_number =
+		MKDEV(MAJOR(msm_rpcrouter_devno), next_minor++);
+	spin_unlock_irqrestore(&server_cdev_lock, flags);
+
+	server->device =
+		device_create(msm_rpcrouter_class, rpcrouter_device,
+			      server->device_number, NULL, "%.8x:%.8x",
+			      server->prog, dev_vers);
+	if (IS_ERR(server->device)) {
+		printk(KERN_ERR
+		       "rpcrouter: Unable to create device (%ld)\n",
+		       PTR_ERR(server->device));
+		return PTR_ERR(server->device);;
+	}
+
+	cdev_init(&server->cdev, &rpcrouter_server_fops);
+	server->cdev.owner = THIS_MODULE;
+
+	rc = cdev_add(&server->cdev, server->device_number, 1);
+	if (rc < 0) {
+		printk(KERN_ERR
+		       "rpcrouter: Unable to add chrdev (%d)\n", rc);
+		device_destroy(msm_rpcrouter_class, server->device_number);
+		return rc;
+	}
+	return 0;
+}
+
+/* for backward compatible version type (31st bit cleared)
+ * clearing minor number (lower 16 bits) in device name
+ * is neccessary for driver binding
+ */
+int msm_rpcrouter_create_server_pdev(struct rr_server *server)
+{
+	server->p_device.base.id = (server->vers & RPC_VERSION_MODE_MASK) ?
+				   server->vers :
+				   (server->vers & RPC_VERSION_MAJOR_MASK);
+	server->p_device.base.name = server->pdev_name;
+
+	server->p_device.prog = server->prog;
+	server->p_device.vers = server->vers;
+
+	platform_device_register(&server->p_device.base);
+	return 0;
+}
+
+int msm_rpcrouter_init_devices(void)
+{
+	int rc;
+	int major;
+
+	/* Create the device nodes */
+	msm_rpcrouter_class = class_create(THIS_MODULE, "oncrpc");
+	if (IS_ERR(msm_rpcrouter_class)) {
+		rc = -ENOMEM;
+		printk(KERN_ERR
+		       "rpcrouter: failed to create oncrpc class\n");
+		goto fail;
+	}
+
+	rc = alloc_chrdev_region(&msm_rpcrouter_devno, 0,
+				 RPCROUTER_MAX_REMOTE_SERVERS + 1,
+				 "oncrpc");
+	if (rc < 0) {
+		printk(KERN_ERR
+		       "rpcrouter: Failed to alloc chardev region (%d)\n", rc);
+		goto fail_destroy_class;
+	}
+
+	major = MAJOR(msm_rpcrouter_devno);
+	rpcrouter_device = device_create(msm_rpcrouter_class, NULL,
+					 msm_rpcrouter_devno, NULL, "%.8x:%d",
+					 0, 0);
+	if (IS_ERR(rpcrouter_device)) {
+		rc = -ENOMEM;
+		goto fail_unregister_cdev_region;
+	}
+
+	cdev_init(&rpcrouter_cdev, &rpcrouter_router_fops);
+	rpcrouter_cdev.owner = THIS_MODULE;
+
+	rc = cdev_add(&rpcrouter_cdev, msm_rpcrouter_devno, 1);
+	if (rc < 0)
+		goto fail_destroy_device;
+
+	return 0;
+
+fail_destroy_device:
+	device_destroy(msm_rpcrouter_class, msm_rpcrouter_devno);
+fail_unregister_cdev_region:
+	unregister_chrdev_region(msm_rpcrouter_devno,
+				 RPCROUTER_MAX_REMOTE_SERVERS + 1);
+fail_destroy_class:
+	class_destroy(msm_rpcrouter_class);
+fail:
+	return rc;
+}
+
+void msm_rpcrouter_exit_devices(void)
+{
+	cdev_del(&rpcrouter_cdev);
+	device_destroy(msm_rpcrouter_class, msm_rpcrouter_devno);
+	unregister_chrdev_region(msm_rpcrouter_devno,
+				 RPCROUTER_MAX_REMOTE_SERVERS + 1);
+	class_destroy(msm_rpcrouter_class);
+}
+
diff --git a/arch/arm/mach-msm/smd_rpcrouter_servers.c b/arch/arm/mach-msm/smd_rpcrouter_servers.c
new file mode 100644
index 0000000..3561c21
--- /dev/null
+++ b/arch/arm/mach-msm/smd_rpcrouter_servers.c
@@ -0,0 +1,618 @@
+/* arch/arm/mach-msm/rpc_servers.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+ * Author: Iliyan Malchev <ibm@android.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/cdev.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/wakelock.h>
+
+#include <linux/msm_rpcrouter.h>
+#include <linux/uaccess.h>
+
+#include <mach/msm_rpcrouter.h>
+#include "smd_rpcrouter.h"
+
+static struct msm_rpc_endpoint *endpoint;
+
+#define FLAG_REGISTERED 0x0001
+
+static LIST_HEAD(rpc_server_list);
+static DEFINE_MUTEX(rpc_server_list_lock);
+static int rpc_servers_active;
+static struct wake_lock rpc_servers_wake_lock;
+static struct msm_rpc_xdr server_xdr;
+static uint32_t current_xid;
+
+static void rpc_server_register(struct msm_rpc_server *server)
+{
+	int rc;
+	rc = msm_rpc_register_server(endpoint, server->prog, server->vers);
+	if (rc < 0)
+		printk(KERN_ERR "[rpcserver] error registering %p @ %08x:%d\n",
+		       server, server->prog, server->vers);
+}
+
+static struct msm_rpc_server *rpc_server_find(uint32_t prog, uint32_t vers)
+{
+	struct msm_rpc_server *server;
+
+	mutex_lock(&rpc_server_list_lock);
+	list_for_each_entry(server, &rpc_server_list, list) {
+		if ((server->prog == prog) &&
+		    msm_rpc_is_compatible_version(server->vers, vers)) {
+			mutex_unlock(&rpc_server_list_lock);
+			return server;
+		}
+	}
+	mutex_unlock(&rpc_server_list_lock);
+	return NULL;
+}
+
+static void rpc_server_register_all(void)
+{
+	struct msm_rpc_server *server;
+
+	mutex_lock(&rpc_server_list_lock);
+	list_for_each_entry(server, &rpc_server_list, list) {
+		if (!(server->flags & FLAG_REGISTERED)) {
+			rpc_server_register(server);
+			server->flags |= FLAG_REGISTERED;
+		}
+	}
+	mutex_unlock(&rpc_server_list_lock);
+}
+
+int msm_rpc_create_server(struct msm_rpc_server *server)
+{
+	void *buf;
+
+	/* make sure we're in a sane state first */
+	server->flags = 0;
+	INIT_LIST_HEAD(&server->list);
+	mutex_init(&server->cb_req_lock);
+
+	server->version = 1;
+
+	xdr_init(&server->cb_xdr);
+	buf = kmalloc(MSM_RPC_MSGSIZE_MAX, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	xdr_init_output(&server->cb_xdr, buf, MSM_RPC_MSGSIZE_MAX);
+
+	server->cb_ept = server->cb_xdr.ept = msm_rpc_open();
+	if (IS_ERR(server->cb_ept)) {
+		xdr_clean_output(&server->cb_xdr);
+		return PTR_ERR(server->cb_ept);
+	}
+
+	server->cb_ept->flags = MSM_RPC_UNINTERRUPTIBLE;
+	server->cb_ept->dst_prog = cpu_to_be32(server->prog | 0x01000000);
+	server->cb_ept->dst_vers = cpu_to_be32(server->vers);
+
+	mutex_lock(&rpc_server_list_lock);
+	list_add(&server->list, &rpc_server_list);
+	if (rpc_servers_active) {
+		rpc_server_register(server);
+		server->flags |= FLAG_REGISTERED;
+	}
+	mutex_unlock(&rpc_server_list_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_rpc_create_server);
+
+int msm_rpc_create_server2(struct msm_rpc_server *server)
+{
+	int rc;
+
+	rc = msm_rpc_create_server(server);
+	server->version = 2;
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_rpc_create_server2);
+
+static int rpc_send_accepted_void_reply(struct msm_rpc_endpoint *client,
+					uint32_t xid, uint32_t accept_status)
+{
+	int rc = 0;
+	uint8_t reply_buf[sizeof(struct rpc_reply_hdr)];
+	struct rpc_reply_hdr *reply = (struct rpc_reply_hdr *)reply_buf;
+
+	reply->xid = cpu_to_be32(xid);
+	reply->type = cpu_to_be32(1); /* reply */
+	reply->reply_stat = cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED);
+
+	reply->data.acc_hdr.accept_stat = cpu_to_be32(accept_status);
+	reply->data.acc_hdr.verf_flavor = 0;
+	reply->data.acc_hdr.verf_length = 0;
+
+	rc = msm_rpc_write(client, reply_buf, sizeof(reply_buf));
+	if (rc ==  -ENETRESET) {
+		/* Modem restarted, drop reply, clear state */
+		msm_rpc_clear_netreset(client);
+	}
+	if (rc < 0)
+		printk(KERN_ERR
+		       "%s: could not write response: %d\n",
+		       __FUNCTION__, rc);
+
+	return rc;
+}
+
+/*
+ * Interface to be used to start accepted reply message for a
+ * request.  Returns the buffer pointer to attach any payload.
+ * Should call msm_rpc_server_send_accepted_reply to complete sending
+ * reply.  Marshaling should be handled by user for the payload.
+ *
+ * server: pointer to server data structure
+ *
+ * xid: transaction id. Has to be same as the one in request.
+ *
+ * accept_status: acceptance status
+ *
+ * Return Value:
+ *        pointer to buffer to attach the payload.
+ */
+void *msm_rpc_server_start_accepted_reply(struct msm_rpc_server *server,
+					  uint32_t xid, uint32_t accept_status)
+{
+	struct rpc_reply_hdr *reply;
+
+	mutex_lock(&server_xdr.out_lock);
+
+	reply = (struct rpc_reply_hdr *)server_xdr.out_buf;
+
+	reply->xid = cpu_to_be32(xid);
+	reply->type = cpu_to_be32(1); /* reply */
+	reply->reply_stat = cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED);
+
+	reply->data.acc_hdr.accept_stat = cpu_to_be32(accept_status);
+	reply->data.acc_hdr.verf_flavor = 0;
+	reply->data.acc_hdr.verf_length = 0;
+
+	server_xdr.out_index += sizeof(*reply);
+
+	return reply + 1;
+}
+EXPORT_SYMBOL(msm_rpc_server_start_accepted_reply);
+
+/*
+ * Interface to be used to send accepted reply for a request.
+ * msm_rpc_server_start_accepted_reply should have been called before.
+ * Marshaling should be handled by user for the payload.
+ *
+ * server: pointer to server data structure
+ *
+ * size: additional payload size
+ *
+ * Return Value:
+ *        0 on success, otherwise returns an error code.
+ */
+int msm_rpc_server_send_accepted_reply(struct msm_rpc_server *server,
+				       uint32_t size)
+{
+	int rc = 0;
+
+	server_xdr.out_index += size;
+	rc = msm_rpc_write(endpoint, server_xdr.out_buf,
+			   server_xdr.out_index);
+	if (rc > 0)
+		rc = 0;
+
+	mutex_unlock(&server_xdr.out_lock);
+	return rc;
+}
+EXPORT_SYMBOL(msm_rpc_server_send_accepted_reply);
+
+/*
+ * Interface to be used to send a server callback request.
+ * If the request takes any arguments or expects any return, the user
+ * should handle it in 'arg_func' and 'ret_func' respectively.
+ * Marshaling and Unmarshaling should be handled by the user in argument
+ * and return functions.
+ *
+ * server: pointer to server data sturcture
+ *
+ * clnt_info: pointer to client information data structure.
+ *            callback will be sent to this client.
+ *
+ * cb_proc: callback procedure being requested
+ *
+ * arg_func: argument function pointer.  'buf' is where arguments needs to
+ *   be filled. 'data' is arg_data.
+ *
+ * ret_func: return function pointer.  'buf' is where returned data should
+ *   be read from. 'data' is ret_data.
+ *
+ * arg_data: passed as an input parameter to argument function.
+ *
+ * ret_data: passed as an input parameter to return function.
+ *
+ * timeout: timeout for reply wait in jiffies.  If negative timeout is
+ *   specified a default timeout of 10s is used.
+ *
+ * Return Value:
+ *        0 on success, otherwise an error code is returned.
+ */
+int msm_rpc_server_cb_req(struct msm_rpc_server *server,
+			  struct msm_rpc_client_info *clnt_info,
+			  uint32_t cb_proc,
+			  int (*arg_func)(struct msm_rpc_server *server,
+					  void *buf, void *data),
+			  void *arg_data,
+			  int (*ret_func)(struct msm_rpc_server *server,
+					  void *buf, void *data),
+			  void *ret_data, long timeout)
+{
+	struct rpc_reply_hdr *rpc_rsp;
+	void *buffer;
+	int rc = 0;
+	uint32_t req_xid;
+
+	if (!clnt_info)
+		return -EINVAL;
+
+	mutex_lock(&server->cb_req_lock);
+
+	msm_rpc_setup_req((struct rpc_request_hdr *)server->cb_xdr.out_buf,
+			  (server->prog | 0x01000000),
+			  be32_to_cpu(clnt_info->vers), cb_proc);
+	server->cb_xdr.out_index = sizeof(struct rpc_request_hdr);
+	req_xid = *(uint32_t *)server->cb_xdr.out_buf;
+
+	if (arg_func) {
+		rc = arg_func(server, (void *)((struct rpc_request_hdr *)
+					       server->cb_xdr.out_buf + 1),
+			      arg_data);
+		if (rc < 0)
+			goto release_locks;
+		else
+			server->cb_xdr.out_index += rc;
+	}
+
+	server->cb_ept->dst_pid = clnt_info->pid;
+	server->cb_ept->dst_cid = clnt_info->cid;
+	rc = msm_rpc_write(server->cb_ept, server->cb_xdr.out_buf,
+			   server->cb_xdr.out_index);
+	if (rc < 0) {
+		pr_err("%s: couldn't send RPC CB request:%d\n", __func__, rc);
+		goto release_locks;
+	} else
+		rc = 0;
+
+	if (timeout < 0)
+		timeout = msecs_to_jiffies(10000);
+
+	do {
+		buffer = NULL;
+		rc = msm_rpc_read(server->cb_ept, &buffer, -1, timeout);
+		xdr_init_input(&server->cb_xdr, buffer, rc);
+		if ((rc < ((int)(sizeof(uint32_t) * 2))) ||
+		    (be32_to_cpu(*((uint32_t *)buffer + 1)) != 1)) {
+			printk(KERN_ERR "%s: Invalid reply: %d\n",
+			       __func__, rc);
+			goto free_and_release;
+		}
+
+		rpc_rsp = (struct rpc_reply_hdr *)server->cb_xdr.in_buf;
+		if (req_xid != rpc_rsp->xid) {
+			pr_info("%s: xid mismatch, req %d reply %d\n",
+				__func__, be32_to_cpu(req_xid),
+				be32_to_cpu(rpc_rsp->xid));
+			xdr_clean_input(&server->cb_xdr);
+			rc = timeout;
+			/* timeout is not adjusted, but it is not critical */
+		} else
+			rc = 0;
+	} while (rc);
+
+	if (be32_to_cpu(rpc_rsp->reply_stat) != RPCMSG_REPLYSTAT_ACCEPTED) {
+		pr_err("%s: RPC cb req was denied! %d\n", __func__,
+		       be32_to_cpu(rpc_rsp->reply_stat));
+		rc = -EPERM;
+		goto free_and_release;
+	}
+
+	if (be32_to_cpu(rpc_rsp->data.acc_hdr.accept_stat) !=
+	    RPC_ACCEPTSTAT_SUCCESS) {
+		pr_err("%s: RPC cb req was not successful (%d)\n", __func__,
+		       be32_to_cpu(rpc_rsp->data.acc_hdr.accept_stat));
+		rc = -EINVAL;
+		goto free_and_release;
+	}
+
+	if (ret_func)
+		rc = ret_func(server, (void *)(rpc_rsp + 1), ret_data);
+
+free_and_release:
+	xdr_clean_input(&server->cb_xdr);
+	server->cb_xdr.out_index = 0;
+release_locks:
+	mutex_unlock(&server->cb_req_lock);
+	return rc;
+}
+EXPORT_SYMBOL(msm_rpc_server_cb_req);
+
+/*
+ * Interface to be used to send a server callback request.
+ * If the request takes any arguments or expects any return, the user
+ * should handle it in 'arg_func' and 'ret_func' respectively.
+ * Marshaling and Unmarshaling should be handled by the user in argument
+ * and return functions.
+ *
+ * server: pointer to server data sturcture
+ *
+ * clnt_info: pointer to client information data structure.
+ *            callback will be sent to this client.
+ *
+ * cb_proc: callback procedure being requested
+ *
+ * arg_func: argument function pointer.  'xdr' is the xdr being used.
+ *   'data' is arg_data.
+ *
+ * ret_func: return function pointer.  'xdr' is the xdr being used.
+ *   'data' is ret_data.
+ *
+ * arg_data: passed as an input parameter to argument function.
+ *
+ * ret_data: passed as an input parameter to return function.
+ *
+ * timeout: timeout for reply wait in jiffies.  If negative timeout is
+ *   specified a default timeout of 10s is used.
+ *
+ * Return Value:
+ *        0 on success, otherwise an error code is returned.
+ */
+int msm_rpc_server_cb_req2(struct msm_rpc_server *server,
+			   struct msm_rpc_client_info *clnt_info,
+			   uint32_t cb_proc,
+			   int (*arg_func)(struct msm_rpc_server *server,
+					   struct msm_rpc_xdr *xdr, void *data),
+			   void *arg_data,
+			   int (*ret_func)(struct msm_rpc_server *server,
+					   struct msm_rpc_xdr *xdr, void *data),
+			   void *ret_data, long timeout)
+{
+	int size = 0;
+	struct rpc_reply_hdr rpc_rsp;
+	void *buffer;
+	int rc = 0;
+	uint32_t req_xid;
+
+	if (!clnt_info)
+		return -EINVAL;
+
+	mutex_lock(&server->cb_req_lock);
+
+	xdr_start_request(&server->cb_xdr, (server->prog | 0x01000000),
+			  be32_to_cpu(clnt_info->vers), cb_proc);
+	req_xid = be32_to_cpu(*(uint32_t *)server->cb_xdr.out_buf);
+	if (arg_func) {
+		rc = arg_func(server, &server->cb_xdr, arg_data);
+		if (rc < 0)
+			goto release_locks;
+		else
+			size += rc;
+	}
+
+	server->cb_ept->dst_pid = clnt_info->pid;
+	server->cb_ept->dst_cid = clnt_info->cid;
+	rc = xdr_send_msg(&server->cb_xdr);
+	if (rc < 0) {
+		pr_err("%s: couldn't send RPC CB request:%d\n", __func__, rc);
+		goto release_locks;
+	} else
+		rc = 0;
+
+	if (timeout < 0)
+		timeout = msecs_to_jiffies(10000);
+
+	do {
+		buffer = NULL;
+		rc = msm_rpc_read(server->cb_ept, &buffer, -1, timeout);
+		if (rc < 0) {
+			server->cb_xdr.out_index = 0;
+			goto release_locks;
+		}
+
+		xdr_init_input(&server->cb_xdr, buffer, rc);
+		rc = xdr_recv_reply(&server->cb_xdr, &rpc_rsp);
+		if (rc || (rpc_rsp.type != 1)) {
+			printk(KERN_ERR "%s: Invalid reply :%d\n",
+			       __func__, rc);
+			rc = -EINVAL;
+			goto free_and_release;
+		}
+
+		if (req_xid != rpc_rsp.xid) {
+			pr_info("%s: xid mismatch, req %d reply %d\n",
+				__func__, req_xid, rpc_rsp.xid);
+			xdr_clean_input(&server->cb_xdr);
+			rc = timeout;
+			/* timeout is not adjusted, but it is not critical */
+		} else
+			rc = 0;
+
+	} while (rc);
+
+	if (rpc_rsp.reply_stat != RPCMSG_REPLYSTAT_ACCEPTED) {
+		pr_err("%s: RPC cb req was denied! %d\n", __func__,
+		       rpc_rsp.reply_stat);
+		rc = -EPERM;
+		goto free_and_release;
+	}
+
+	if (rpc_rsp.data.acc_hdr.accept_stat != RPC_ACCEPTSTAT_SUCCESS) {
+		pr_err("%s: RPC cb req was not successful (%d)\n", __func__,
+		       rpc_rsp.data.acc_hdr.accept_stat);
+		rc = -EINVAL;
+		goto free_and_release;
+	}
+
+	if (ret_func)
+		rc = ret_func(server, &server->cb_xdr, ret_data);
+
+free_and_release:
+	xdr_clean_input(&server->cb_xdr);
+	server->cb_xdr.out_index = 0;
+release_locks:
+	mutex_unlock(&server->cb_req_lock);
+	return rc;
+}
+EXPORT_SYMBOL(msm_rpc_server_cb_req2);
+
+void msm_rpc_server_get_requesting_client(struct msm_rpc_client_info *clnt_info)
+{
+	if (!clnt_info)
+		return;
+
+	get_requesting_client(endpoint, current_xid, clnt_info);
+}
+
+static int rpc_servers_thread(void *data)
+{
+	void *buffer, *buf;
+	struct rpc_request_hdr req;
+	struct rpc_request_hdr *req1;
+	struct msm_rpc_server *server;
+	int rc;
+
+	xdr_init(&server_xdr);
+	server_xdr.ept = endpoint;
+
+	buf = kmalloc(MSM_RPC_MSGSIZE_MAX, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	xdr_init_output(&server_xdr, buf, MSM_RPC_MSGSIZE_MAX);
+
+	for (;;) {
+		wake_unlock(&rpc_servers_wake_lock);
+		rc = wait_event_interruptible(endpoint->wait_q,
+					      !list_empty(&endpoint->read_q));
+		wake_lock(&rpc_servers_wake_lock);
+
+		rc = msm_rpc_read(endpoint, &buffer, -1, -1);
+		if (rc < 0) {
+			printk(KERN_ERR "%s: could not read: %d\n",
+			       __FUNCTION__, rc);
+			break;
+		}
+
+		req1 = (struct rpc_request_hdr *)buffer;
+		current_xid = req1->xid;
+
+		xdr_init_input(&server_xdr, buffer, rc);
+		xdr_recv_req(&server_xdr, &req);
+
+		server = rpc_server_find(req.prog, req.vers);
+
+		if (req.rpc_vers != 2)
+			goto free_buffer;
+		if (req.type != 0)
+			goto free_buffer;
+		if (!server) {
+			rpc_send_accepted_void_reply(
+				endpoint, req.xid,
+				RPC_ACCEPTSTAT_PROG_UNAVAIL);
+			goto free_buffer;
+		}
+
+		if (server->version == 2)
+			rc = server->rpc_call2(server, &req, &server_xdr);
+		else {
+			req1->type = be32_to_cpu(req1->type);
+			req1->xid = be32_to_cpu(req1->xid);
+			req1->rpc_vers = be32_to_cpu(req1->rpc_vers);
+			req1->prog = be32_to_cpu(req1->prog);
+			req1->vers = be32_to_cpu(req1->vers);
+			req1->procedure = be32_to_cpu(req1->procedure);
+
+			rc = server->rpc_call(server, req1, rc);
+		}
+
+		if (rc == 0) {
+			msm_rpc_server_start_accepted_reply(
+				server, req.xid,
+				RPC_ACCEPTSTAT_SUCCESS);
+			msm_rpc_server_send_accepted_reply(server, 0);
+		} else if (rc < 0) {
+			msm_rpc_server_start_accepted_reply(
+				server, req.xid,
+				RPC_ACCEPTSTAT_PROC_UNAVAIL);
+			msm_rpc_server_send_accepted_reply(server, 0);
+		}
+ free_buffer:
+		xdr_clean_input(&server_xdr);
+		server_xdr.out_index = 0;
+	}
+	do_exit(0);
+}
+
+static int rpcservers_probe(struct platform_device *pdev)
+{
+	struct task_struct *server_thread;
+
+	endpoint = msm_rpc_open();
+	if (IS_ERR(endpoint))
+		return PTR_ERR(endpoint);
+
+	/* we're online -- register any servers installed beforehand */
+	rpc_servers_active = 1;
+	current_xid = 0;
+	rpc_server_register_all();
+
+	/* start the kernel thread */
+	server_thread = kthread_run(rpc_servers_thread, NULL, "krpcserversd");
+	if (IS_ERR(server_thread))
+		return PTR_ERR(server_thread);
+
+	return 0;
+}
+
+static struct platform_driver rpcservers_driver = {
+	.probe	= rpcservers_probe,
+	.driver	= {
+		.name	= "oncrpc_router",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init rpc_servers_init(void)
+{
+	wake_lock_init(&rpc_servers_wake_lock, WAKE_LOCK_SUSPEND, "rpc_server");
+	return platform_driver_register(&rpcservers_driver);
+}
+
+module_init(rpc_servers_init);
+
+MODULE_DESCRIPTION("MSM RPC Servers");
+MODULE_AUTHOR("Iliyan Malchev <ibm@android.com>");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/smd_rpcrouter_xdr.c b/arch/arm/mach-msm/smd_rpcrouter_xdr.c
new file mode 100644
index 0000000..1793516
--- /dev/null
+++ b/arch/arm/mach-msm/smd_rpcrouter_xdr.c
@@ -0,0 +1,415 @@
+/* Copyright (c) 2010, 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.
+ *
+ */
+
+/*
+ * SMD RPCROUTER XDR module.
+ */
+
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+
+#include <mach/msm_rpcrouter.h>
+
+int xdr_send_uint32(struct msm_rpc_xdr *xdr, const uint32_t *value)
+{
+	if ((xdr->out_index + sizeof(uint32_t)) > xdr->out_size) {
+		pr_err("%s: xdr out buffer full\n", __func__);
+		return -1;
+	}
+
+	*(uint32_t *)(xdr->out_buf + xdr->out_index) = cpu_to_be32(*value);
+	xdr->out_index += sizeof(uint32_t);
+	return 0;
+}
+
+int xdr_send_int8(struct msm_rpc_xdr *xdr, const int8_t *value)
+{
+	return xdr_send_uint32(xdr, (uint32_t *)value);
+}
+
+int xdr_send_uint8(struct msm_rpc_xdr *xdr, const uint8_t *value)
+{
+	return xdr_send_uint32(xdr, (uint32_t *)value);
+}
+
+int xdr_send_int16(struct msm_rpc_xdr *xdr, const int16_t *value)
+{
+	return xdr_send_uint32(xdr, (uint32_t *)value);
+}
+
+int xdr_send_uint16(struct msm_rpc_xdr *xdr, const uint16_t *value)
+{
+	return xdr_send_uint32(xdr, (uint32_t *)value);
+}
+
+int xdr_send_int32(struct msm_rpc_xdr *xdr, const int32_t *value)
+{
+	return xdr_send_uint32(xdr, (uint32_t *)value);
+}
+
+int xdr_send_bytes(struct msm_rpc_xdr *xdr, const void **data,
+		   uint32_t *size)
+{
+	void *buf = xdr->out_buf + xdr->out_index;
+	uint32_t temp;
+
+	if (!size || !data || !*data)
+		return -1;
+
+	temp = *size;
+	if (temp & 0x3)
+		temp += 4 - (temp & 0x3);
+
+	temp += sizeof(uint32_t);
+	if ((xdr->out_index + temp) > xdr->out_size) {
+		pr_err("%s: xdr out buffer full\n", __func__);
+		return -1;
+	}
+
+	*((uint32_t *)buf) = cpu_to_be32(*size);
+	buf += sizeof(uint32_t);
+	memcpy(buf, *data, *size);
+	buf += *size;
+	if (*size & 0x3) {
+		memset(buf, 0, 4 - (*size & 0x3));
+		buf += 4 - (*size & 0x3);
+	}
+
+	xdr->out_index = buf - xdr->out_buf;
+	return 0;
+}
+
+int xdr_recv_uint32(struct msm_rpc_xdr *xdr, uint32_t *value)
+{
+	if ((xdr->in_index + sizeof(uint32_t)) > xdr->in_size) {
+		pr_err("%s: xdr in buffer full\n", __func__);
+		return -1;
+	}
+
+	*value = be32_to_cpu(*(uint32_t *)(xdr->in_buf + xdr->in_index));
+	xdr->in_index += sizeof(uint32_t);
+	return 0;
+}
+
+int xdr_recv_int8(struct msm_rpc_xdr *xdr, int8_t *value)
+{
+	return xdr_recv_uint32(xdr, (uint32_t *)value);
+}
+
+int xdr_recv_uint8(struct msm_rpc_xdr *xdr, uint8_t *value)
+{
+	return xdr_recv_uint32(xdr, (uint32_t *)value);
+}
+
+int xdr_recv_int16(struct msm_rpc_xdr *xdr, int16_t *value)
+{
+	return xdr_recv_uint32(xdr, (uint32_t *)value);
+}
+
+int xdr_recv_uint16(struct msm_rpc_xdr *xdr, uint16_t *value)
+{
+	return xdr_recv_uint32(xdr, (uint32_t *)value);
+}
+
+int xdr_recv_int32(struct msm_rpc_xdr *xdr, int32_t *value)
+{
+	return xdr_recv_uint32(xdr, (uint32_t *)value);
+}
+
+int xdr_recv_bytes(struct msm_rpc_xdr *xdr, void **data,
+		   uint32_t *size)
+{
+	void *buf = xdr->in_buf + xdr->in_index;
+	uint32_t temp;
+
+	if (!size || !data)
+		return -1;
+
+	*size = be32_to_cpu(*(uint32_t *)buf);
+	buf += sizeof(uint32_t);
+
+	temp = *size;
+	if (temp & 0x3)
+		temp += 4 - (temp & 0x3);
+
+	temp += sizeof(uint32_t);
+	if ((xdr->in_index + temp) > xdr->in_size) {
+		pr_err("%s: xdr in buffer full\n", __func__);
+		return -1;
+	}
+
+	if (*size) {
+		*data = kmalloc(*size, GFP_KERNEL);
+		if (!*data)
+			return -1;
+
+		memcpy(*data, buf, *size);
+
+		buf += *size;
+		if (*size & 0x3)
+			buf += 4 - (*size & 0x3);
+	} else
+		*data = NULL;
+
+	xdr->in_index = buf - xdr->in_buf;
+	return 0;
+}
+
+int xdr_send_pointer(struct msm_rpc_xdr *xdr, void **obj,
+		     uint32_t obj_size, void *xdr_op)
+{
+	uint32_t ptr_valid, rc;
+
+	ptr_valid = (*obj != NULL);
+
+	rc = xdr_send_uint32(xdr, &ptr_valid);
+	if (rc)
+		return rc;
+
+	if (!ptr_valid)
+		return 0;
+
+	return ((int (*) (struct msm_rpc_xdr *, void *))xdr_op)(xdr, *obj);
+}
+
+int xdr_recv_pointer(struct msm_rpc_xdr *xdr, void **obj,
+		     uint32_t obj_size, void *xdr_op)
+{
+	uint32_t rc, ptr_valid = 0;
+
+	rc = xdr_recv_uint32(xdr, &ptr_valid);
+	if (rc)
+		return rc;
+
+	if (!ptr_valid) {
+		*obj = NULL;
+		return 0;
+	}
+
+	*obj = kmalloc(obj_size, GFP_KERNEL);
+	if (!*obj)
+		return -1;
+
+	rc = ((int (*) (struct msm_rpc_xdr *, void *))xdr_op)(xdr, *obj);
+	if (rc)
+		kfree(*obj);
+
+	return rc;
+}
+
+int xdr_send_array(struct msm_rpc_xdr *xdr, void **addr, uint32_t *size,
+		   uint32_t maxsize, uint32_t elm_size, void *xdr_op)
+{
+	int i, rc;
+	void *tmp_addr = *addr;
+
+	if (!size || !tmp_addr || (*size > maxsize) || !xdr_op)
+		return -1;
+
+	rc = xdr_send_uint32(xdr, size);
+	if (rc)
+		return rc;
+
+	for (i = 0; i < *size; i++) {
+		rc = ((int (*) (struct msm_rpc_xdr *, void *))xdr_op)
+			(xdr, tmp_addr);
+		if (rc)
+			return rc;
+
+		tmp_addr += elm_size;
+	}
+
+	return 0;
+}
+
+int xdr_recv_array(struct msm_rpc_xdr *xdr, void **addr, uint32_t *size,
+		   uint32_t maxsize, uint32_t elm_size, void *xdr_op)
+{
+	int i, rc;
+	void *tmp_addr;
+
+	if (!size || !xdr_op)
+		return -1;
+
+	rc = xdr_recv_uint32(xdr, size);
+	if (rc)
+		return rc;
+
+	if (*size > maxsize)
+		return -1;
+
+	tmp_addr = kmalloc((*size * elm_size), GFP_KERNEL);
+	if (!tmp_addr)
+		return -1;
+
+	*addr = tmp_addr;
+	for (i = 0; i < *size; i++) {
+		rc = ((int (*) (struct msm_rpc_xdr *, void *))xdr_op)
+			(xdr, tmp_addr);
+		if (rc) {
+			kfree(*addr);
+			*addr = NULL;
+			return rc;
+		}
+
+		tmp_addr += elm_size;
+	}
+
+	return 0;
+}
+
+int xdr_recv_req(struct msm_rpc_xdr *xdr, struct rpc_request_hdr *req)
+{
+	int rc = 0;
+	if (!req)
+		return -1;
+
+	rc |= xdr_recv_uint32(xdr, &req->xid);           /* xid */
+	rc |= xdr_recv_uint32(xdr, &req->type);          /* type */
+	rc |= xdr_recv_uint32(xdr, &req->rpc_vers);      /* rpc_vers */
+	rc |= xdr_recv_uint32(xdr, &req->prog);          /* prog */
+	rc |= xdr_recv_uint32(xdr, &req->vers);          /* vers */
+	rc |= xdr_recv_uint32(xdr, &req->procedure);     /* procedure */
+	rc |= xdr_recv_uint32(xdr, &req->cred_flavor);   /* cred_flavor */
+	rc |= xdr_recv_uint32(xdr, &req->cred_length);   /* cred_length */
+	rc |= xdr_recv_uint32(xdr, &req->verf_flavor);   /* verf_flavor */
+	rc |= xdr_recv_uint32(xdr, &req->verf_length);   /* verf_length */
+
+	return rc;
+}
+
+int xdr_recv_reply(struct msm_rpc_xdr *xdr, struct rpc_reply_hdr *reply)
+{
+	int rc = 0;
+
+	if (!reply)
+		return -1;
+
+	rc |= xdr_recv_uint32(xdr, &reply->xid);           /* xid */
+	rc |= xdr_recv_uint32(xdr, &reply->type);          /* type */
+	rc |= xdr_recv_uint32(xdr, &reply->reply_stat);    /* reply_stat */
+
+	/* acc_hdr */
+	if (reply->reply_stat == RPCMSG_REPLYSTAT_ACCEPTED) {
+		rc |= xdr_recv_uint32(xdr, &reply->data.acc_hdr.verf_flavor);
+		rc |= xdr_recv_uint32(xdr, &reply->data.acc_hdr.verf_length);
+		rc |= xdr_recv_uint32(xdr, &reply->data.acc_hdr.accept_stat);
+	}
+
+	return rc;
+}
+
+int xdr_start_request(struct msm_rpc_xdr *xdr, uint32_t prog,
+		      uint32_t ver, uint32_t proc)
+{
+	mutex_lock(&xdr->out_lock);
+
+	/* TODO: replace below function with its implementation */
+	msm_rpc_setup_req((struct rpc_request_hdr *)xdr->out_buf,
+			  prog, ver, proc);
+
+	xdr->out_index = sizeof(struct rpc_request_hdr);
+	return 0;
+}
+
+int xdr_start_accepted_reply(struct msm_rpc_xdr *xdr, uint32_t accept_status)
+{
+	struct rpc_reply_hdr *reply;
+
+	mutex_lock(&xdr->out_lock);
+
+	/* TODO: err if xdr is not cb xdr */
+	reply = (struct rpc_reply_hdr *)xdr->out_buf;
+
+	/* TODO: use xdr functions instead */
+	reply->xid = ((struct rpc_request_hdr *)(xdr->in_buf))->xid;
+	reply->type = cpu_to_be32(1); /* reply */
+	reply->reply_stat = cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED);
+
+	reply->data.acc_hdr.accept_stat = cpu_to_be32(accept_status);
+	reply->data.acc_hdr.verf_flavor = 0;
+	reply->data.acc_hdr.verf_length = 0;
+
+	xdr->out_index = sizeof(*reply);
+	return 0;
+}
+
+int xdr_send_msg(struct msm_rpc_xdr *xdr)
+{
+	int rc = 0;
+
+	rc = msm_rpc_write(xdr->ept, xdr->out_buf,
+			   xdr->out_index);
+	if (rc > 0)
+		rc = 0;
+
+	mutex_unlock(&xdr->out_lock);
+	return rc;
+}
+
+void xdr_init(struct msm_rpc_xdr *xdr)
+{
+	mutex_init(&xdr->out_lock);
+	init_waitqueue_head(&xdr->in_buf_wait_q);
+
+	xdr->in_buf = NULL;
+	xdr->in_size = 0;
+	xdr->in_index = 0;
+
+	xdr->out_buf = NULL;
+	xdr->out_size = 0;
+	xdr->out_index = 0;
+}
+
+void xdr_init_input(struct msm_rpc_xdr *xdr, void *buf, uint32_t size)
+{
+	wait_event(xdr->in_buf_wait_q, !(xdr->in_buf));
+
+	xdr->in_buf = buf;
+	xdr->in_size = size;
+	xdr->in_index = 0;
+}
+
+void xdr_init_output(struct msm_rpc_xdr *xdr, void *buf, uint32_t size)
+{
+	xdr->out_buf = buf;
+	xdr->out_size = size;
+	xdr->out_index = 0;
+}
+
+void xdr_clean_input(struct msm_rpc_xdr *xdr)
+{
+	kfree(xdr->in_buf);
+	xdr->in_size = 0;
+	xdr->in_index = 0;
+	xdr->in_buf = NULL;
+
+	wake_up(&xdr->in_buf_wait_q);
+}
+
+void xdr_clean_output(struct msm_rpc_xdr *xdr)
+{
+	kfree(xdr->out_buf);
+	xdr->out_buf = NULL;
+	xdr->out_size = 0;
+	xdr->out_index = 0;
+}
+
+uint32_t xdr_read_avail(struct msm_rpc_xdr *xdr)
+{
+	return xdr->in_size;
+}
diff --git a/arch/arm/mach-msm/smd_tty.c b/arch/arm/mach-msm/smd_tty.c
new file mode 100644
index 0000000..68e0f41
--- /dev/null
+++ b/arch/arm/mach-msm/smd_tty.c
@@ -0,0 +1,604 @@
+/* arch/arm/mach-msm/smd_tty.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/wakelock.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+
+#include <mach/msm_smd.h>
+#include <mach/peripheral-loader.h>
+#include <mach/socinfo.h>
+
+#include "smd_private.h"
+
+#define MAX_SMD_TTYS 37
+#define MAX_TTY_BUF_SIZE 2048
+
+static DEFINE_MUTEX(smd_tty_lock);
+
+static uint smd_tty_modem_wait;
+module_param_named(modem_wait, smd_tty_modem_wait,
+			uint, S_IRUGO | S_IWUSR | S_IWGRP);
+
+struct smd_tty_info {
+	smd_channel_t *ch;
+	struct tty_struct *tty;
+	struct wake_lock wake_lock;
+	int open_count;
+	struct tasklet_struct tty_tsklt;
+	struct timer_list buf_req_timer;
+	struct completion ch_allocated;
+	struct platform_driver driver;
+	void *pil;
+	int in_reset;
+	int in_reset_updated;
+	int is_open;
+	wait_queue_head_t ch_opened_wait_queue;
+	spinlock_t reset_lock;
+	struct smd_config *smd;
+};
+
+/**
+ * SMD port configuration.
+ *
+ * @tty_dev_index   Index into smd_tty[]
+ * @port_name       Name of the SMD port
+ * @dev_name        Name of the TTY Device (if NULL, @port_name is used)
+ * @edge            SMD edge
+ */
+struct smd_config {
+	uint32_t tty_dev_index;
+	const char *port_name;
+	const char *dev_name;
+	uint32_t edge;
+};
+
+static struct smd_config smd_configs[] = {
+	{0, "DS", NULL, SMD_APPS_MODEM},
+	{1, "APPS_FM", NULL, SMD_APPS_WCNSS},
+	{2, "APPS_RIVA_BT_ACL", NULL, SMD_APPS_WCNSS},
+	{3, "APPS_RIVA_BT_CMD", NULL, SMD_APPS_WCNSS},
+	{4, "MBALBRIDGE", NULL, SMD_APPS_MODEM},
+	{5, "APPS_RIVA_ANT_CMD", NULL, SMD_APPS_WCNSS},
+	{6, "APPS_RIVA_ANT_DATA", NULL, SMD_APPS_WCNSS},
+	{7, "DATA1", NULL, SMD_APPS_MODEM},
+	{11, "DATA11", NULL, SMD_APPS_MODEM},
+	{21, "DATA21", NULL, SMD_APPS_MODEM},
+	{27, "GPSNMEA", NULL, SMD_APPS_MODEM},
+	{36, "LOOPBACK", "LOOPBACK_TTY", SMD_APPS_MODEM},
+};
+#define DS_IDX 0
+#define LOOPBACK_IDX 36
+
+static struct delayed_work loopback_work;
+static struct smd_tty_info smd_tty[MAX_SMD_TTYS];
+
+static int is_in_reset(struct smd_tty_info *info)
+{
+	return info->in_reset;
+}
+
+static void buf_req_retry(unsigned long param)
+{
+	struct smd_tty_info *info = (struct smd_tty_info *)param;
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->reset_lock, flags);
+	if (info->is_open) {
+		spin_unlock_irqrestore(&info->reset_lock, flags);
+		tasklet_hi_schedule(&info->tty_tsklt);
+		return;
+	}
+	spin_unlock_irqrestore(&info->reset_lock, flags);
+}
+
+static void smd_tty_read(unsigned long param)
+{
+	unsigned char *ptr;
+	int avail;
+	struct smd_tty_info *info = (struct smd_tty_info *)param;
+	struct tty_struct *tty = info->tty;
+
+	if (!tty)
+		return;
+
+	for (;;) {
+		if (is_in_reset(info)) {
+			/* signal TTY clients using TTY_BREAK */
+			tty_insert_flip_char(tty, 0x00, TTY_BREAK);
+			tty_flip_buffer_push(tty);
+			break;
+		}
+
+		if (test_bit(TTY_THROTTLED, &tty->flags)) break;
+		avail = smd_read_avail(info->ch);
+		if (avail == 0)
+			break;
+
+		if (avail > MAX_TTY_BUF_SIZE)
+			avail = MAX_TTY_BUF_SIZE;
+
+		avail = tty_prepare_flip_string(tty, &ptr, avail);
+		if (avail <= 0) {
+			if (!timer_pending(&info->buf_req_timer)) {
+				init_timer(&info->buf_req_timer);
+				info->buf_req_timer.expires = jiffies +
+							((30 * HZ)/1000);
+				info->buf_req_timer.function = buf_req_retry;
+				info->buf_req_timer.data = param;
+				add_timer(&info->buf_req_timer);
+			}
+			return;
+		}
+
+		if (smd_read(info->ch, ptr, avail) != avail) {
+			/* shouldn't be possible since we're in interrupt
+			** context here and nobody else could 'steal' our
+			** characters.
+			*/
+			printk(KERN_ERR "OOPS - smd_tty_buffer mismatch?!");
+		}
+
+		wake_lock_timeout(&info->wake_lock, HZ / 2);
+		tty_flip_buffer_push(tty);
+	}
+
+	/* XXX only when writable and necessary */
+	tty_wakeup(tty);
+}
+
+static void smd_tty_notify(void *priv, unsigned event)
+{
+	struct smd_tty_info *info = priv;
+	unsigned long flags;
+
+	switch (event) {
+	case SMD_EVENT_DATA:
+		spin_lock_irqsave(&info->reset_lock, flags);
+		if (!info->is_open) {
+			spin_unlock_irqrestore(&info->reset_lock, flags);
+			break;
+		}
+		spin_unlock_irqrestore(&info->reset_lock, flags);
+		/* There may be clients (tty framework) that are blocked
+		 * waiting for space to write data, so if a possible read
+		 * interrupt came in wake anyone waiting and disable the
+		 * interrupts
+		 */
+		if (smd_write_avail(info->ch)) {
+			smd_disable_read_intr(info->ch);
+			if (info->tty)
+				wake_up_interruptible(&info->tty->write_wait);
+		}
+		tasklet_hi_schedule(&info->tty_tsklt);
+		break;
+
+	case SMD_EVENT_OPEN:
+		spin_lock_irqsave(&info->reset_lock, flags);
+		info->in_reset = 0;
+		info->in_reset_updated = 1;
+		info->is_open = 1;
+		wake_up_interruptible(&info->ch_opened_wait_queue);
+		spin_unlock_irqrestore(&info->reset_lock, flags);
+		break;
+
+	case SMD_EVENT_CLOSE:
+		spin_lock_irqsave(&info->reset_lock, flags);
+		info->in_reset = 1;
+		info->in_reset_updated = 1;
+		info->is_open = 0;
+		wake_up_interruptible(&info->ch_opened_wait_queue);
+		spin_unlock_irqrestore(&info->reset_lock, flags);
+		/* schedule task to send TTY_BREAK */
+		tasklet_hi_schedule(&info->tty_tsklt);
+
+		if (info->tty->index == LOOPBACK_IDX)
+			schedule_delayed_work(&loopback_work,
+					msecs_to_jiffies(1000));
+		break;
+	}
+}
+
+static uint32_t is_modem_smsm_inited(void)
+{
+	uint32_t modem_state;
+	uint32_t ready_state = (SMSM_INIT | SMSM_SMDINIT);
+
+	modem_state = smsm_get_state(SMSM_MODEM_STATE);
+	return (modem_state & ready_state) == ready_state;
+}
+
+static int smd_tty_open(struct tty_struct *tty, struct file *f)
+{
+	int res = 0;
+	unsigned int n = tty->index;
+	struct smd_tty_info *info;
+	const char *peripheral = NULL;
+
+
+	if (n >= MAX_SMD_TTYS || !smd_tty[n].smd)
+		return -ENODEV;
+
+	info = smd_tty + n;
+
+	mutex_lock(&smd_tty_lock);
+	tty->driver_data = info;
+
+	if (info->open_count++ == 0) {
+		peripheral = smd_edge_to_subsystem(smd_tty[n].smd->edge);
+		if (peripheral) {
+			info->pil = pil_get(peripheral);
+			if (IS_ERR(info->pil)) {
+				res = PTR_ERR(info->pil);
+				goto out;
+			}
+
+			/* Wait for the modem SMSM to be inited for the SMD
+			 * Loopback channel to be allocated at the modem. Since
+			 * the wait need to be done atmost once, using msleep
+			 * doesn't degrade the performance.
+			 */
+			if (n == LOOPBACK_IDX) {
+				if (!is_modem_smsm_inited())
+					msleep(5000);
+				smsm_change_state(SMSM_APPS_STATE,
+					0, SMSM_SMD_LOOPBACK);
+				msleep(100);
+			}
+
+
+			/*
+			 * Wait for a channel to be allocated so we know
+			 * the modem is ready enough.
+			 */
+			if (smd_tty_modem_wait) {
+				res = wait_for_completion_interruptible_timeout(
+					&info->ch_allocated,
+					msecs_to_jiffies(smd_tty_modem_wait *
+									1000));
+
+				if (res == 0) {
+					pr_err("Timed out waiting for SMD"
+								" channel\n");
+					res = -ETIMEDOUT;
+					goto release_pil;
+				} else if (res < 0) {
+					pr_err("Error waiting for SMD channel:"
+									" %d\n",
+						res);
+					goto release_pil;
+				}
+
+				res = 0;
+			}
+		}
+
+
+		info->tty = tty;
+		tasklet_init(&info->tty_tsklt, smd_tty_read,
+			     (unsigned long)info);
+		wake_lock_init(&info->wake_lock, WAKE_LOCK_SUSPEND,
+				smd_tty[n].smd->port_name);
+		if (!info->ch) {
+			res = smd_named_open_on_edge(smd_tty[n].smd->port_name,
+							smd_tty[n].smd->edge,
+							&info->ch, info,
+							smd_tty_notify);
+			if (res < 0) {
+				pr_err("%s: %s open failed %d\n", __func__,
+					smd_tty[n].smd->port_name, res);
+				goto release_pil;
+			}
+
+			res = wait_event_interruptible_timeout(
+				info->ch_opened_wait_queue,
+				info->is_open, (2 * HZ));
+			if (res == 0)
+				res = -ETIMEDOUT;
+			if (res < 0) {
+				pr_err("%s: wait for %s smd_open failed %d\n",
+					__func__, smd_tty[n].smd->port_name,
+					res);
+				goto release_pil;
+			}
+			res = 0;
+		}
+	}
+
+release_pil:
+	if (res < 0)
+		pil_put(info->pil);
+	else
+		smd_disable_read_intr(info->ch);
+out:
+	mutex_unlock(&smd_tty_lock);
+
+	return res;
+}
+
+static void smd_tty_close(struct tty_struct *tty, struct file *f)
+{
+	struct smd_tty_info *info = tty->driver_data;
+	unsigned long flags;
+
+	if (info == 0)
+		return;
+
+	mutex_lock(&smd_tty_lock);
+	if (--info->open_count == 0) {
+		spin_lock_irqsave(&info->reset_lock, flags);
+		info->is_open = 0;
+		spin_unlock_irqrestore(&info->reset_lock, flags);
+		if (info->tty) {
+			tasklet_kill(&info->tty_tsklt);
+			wake_lock_destroy(&info->wake_lock);
+			info->tty = 0;
+		}
+		tty->driver_data = 0;
+		del_timer(&info->buf_req_timer);
+		if (info->ch) {
+			smd_close(info->ch);
+			info->ch = 0;
+			pil_put(info->pil);
+		}
+	}
+	mutex_unlock(&smd_tty_lock);
+}
+
+static int smd_tty_write(struct tty_struct *tty, const unsigned char *buf, int len)
+{
+	struct smd_tty_info *info = tty->driver_data;
+	int avail;
+
+	/* if we're writing to a packet channel we will
+	** never be able to write more data than there
+	** is currently space for
+	*/
+	if (is_in_reset(info))
+		return -ENETRESET;
+
+	avail = smd_write_avail(info->ch);
+	/* if no space, we'll have to setup a notification later to wake up the
+	 * tty framework when space becomes avaliable
+	 */
+	if (!avail) {
+		smd_enable_read_intr(info->ch);
+		return 0;
+	}
+	if (len > avail)
+		len = avail;
+
+	return smd_write(info->ch, buf, len);
+}
+
+static int smd_tty_write_room(struct tty_struct *tty)
+{
+	struct smd_tty_info *info = tty->driver_data;
+	return smd_write_avail(info->ch);
+}
+
+static int smd_tty_chars_in_buffer(struct tty_struct *tty)
+{
+	struct smd_tty_info *info = tty->driver_data;
+	return smd_read_avail(info->ch);
+}
+
+static void smd_tty_unthrottle(struct tty_struct *tty)
+{
+	struct smd_tty_info *info = tty->driver_data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->reset_lock, flags);
+	if (info->is_open) {
+		spin_unlock_irqrestore(&info->reset_lock, flags);
+		tasklet_hi_schedule(&info->tty_tsklt);
+		return;
+	}
+	spin_unlock_irqrestore(&info->reset_lock, flags);
+}
+
+/*
+ * Returns the current TIOCM status bits including:
+ *      SMD Signals (DTR/DSR, CTS/RTS, CD, RI)
+ *      TIOCM_OUT1 - reset state (1=in reset)
+ *      TIOCM_OUT2 - reset state updated (1=updated)
+ */
+static int smd_tty_tiocmget(struct tty_struct *tty)
+{
+	struct smd_tty_info *info = tty->driver_data;
+	unsigned long flags;
+	int tiocm;
+
+	tiocm = smd_tiocmget(info->ch);
+
+	spin_lock_irqsave(&info->reset_lock, flags);
+	tiocm |= (info->in_reset ? TIOCM_OUT1 : 0);
+	if (info->in_reset_updated) {
+		tiocm |= TIOCM_OUT2;
+		info->in_reset_updated = 0;
+	}
+	spin_unlock_irqrestore(&info->reset_lock, flags);
+
+	return tiocm;
+}
+
+static int smd_tty_tiocmset(struct tty_struct *tty,
+				unsigned int set, unsigned int clear)
+{
+	struct smd_tty_info *info = tty->driver_data;
+
+	if (info->in_reset)
+		return -ENETRESET;
+
+	return smd_tiocmset(info->ch, set, clear);
+}
+
+static void loopback_probe_worker(struct work_struct *work)
+{
+	/* wait for modem to restart before requesting loopback server */
+	if (!is_modem_smsm_inited())
+		schedule_delayed_work(&loopback_work, msecs_to_jiffies(1000));
+	else
+		smsm_change_state(SMSM_APPS_STATE,
+			  0, SMSM_SMD_LOOPBACK);
+}
+
+static struct tty_operations smd_tty_ops = {
+	.open = smd_tty_open,
+	.close = smd_tty_close,
+	.write = smd_tty_write,
+	.write_room = smd_tty_write_room,
+	.chars_in_buffer = smd_tty_chars_in_buffer,
+	.unthrottle = smd_tty_unthrottle,
+	.tiocmget = smd_tty_tiocmget,
+	.tiocmset = smd_tty_tiocmset,
+};
+
+static int smd_tty_dummy_probe(struct platform_device *pdev)
+{
+	int n;
+	int idx;
+
+	for (n = 0; n < ARRAY_SIZE(smd_configs); ++n) {
+		idx = smd_configs[n].tty_dev_index;
+
+		if (!smd_configs[n].dev_name)
+			continue;
+
+		if (pdev->id == smd_configs[n].edge &&
+			!strncmp(pdev->name, smd_configs[n].dev_name,
+					SMD_MAX_CH_NAME_LEN)) {
+			complete_all(&smd_tty[idx].ch_allocated);
+			return 0;
+		}
+	}
+	pr_err("%s: unknown device '%s'\n", __func__, pdev->name);
+
+	return -ENODEV;
+}
+
+static struct tty_driver *smd_tty_driver;
+
+static int __init smd_tty_init(void)
+{
+	int ret;
+	int n;
+	int idx;
+
+	smd_tty_driver = alloc_tty_driver(MAX_SMD_TTYS);
+	if (smd_tty_driver == 0)
+		return -ENOMEM;
+
+	smd_tty_driver->owner = THIS_MODULE;
+	smd_tty_driver->driver_name = "smd_tty_driver";
+	smd_tty_driver->name = "smd";
+	smd_tty_driver->major = 0;
+	smd_tty_driver->minor_start = 0;
+	smd_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
+	smd_tty_driver->subtype = SERIAL_TYPE_NORMAL;
+	smd_tty_driver->init_termios = tty_std_termios;
+	smd_tty_driver->init_termios.c_iflag = 0;
+	smd_tty_driver->init_termios.c_oflag = 0;
+	smd_tty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
+	smd_tty_driver->init_termios.c_lflag = 0;
+	smd_tty_driver->flags = TTY_DRIVER_RESET_TERMIOS |
+		TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+	tty_set_operations(smd_tty_driver, &smd_tty_ops);
+
+	ret = tty_register_driver(smd_tty_driver);
+	if (ret) {
+		put_tty_driver(smd_tty_driver);
+		pr_err("%s: driver registration failed %d\n", __func__, ret);
+		return ret;
+	}
+
+	for (n = 0; n < ARRAY_SIZE(smd_configs); ++n) {
+		idx = smd_configs[n].tty_dev_index;
+
+		if (smd_configs[n].dev_name == NULL)
+			smd_configs[n].dev_name = smd_configs[n].port_name;
+
+		if (idx == DS_IDX) {
+			/*
+			 * DS port uses the kernel API starting with
+			 * 8660 Fusion.  Only register the userspace
+			 * platform device for older targets.
+			 */
+			int legacy_ds = 0;
+
+			legacy_ds |= cpu_is_msm7x01() || cpu_is_msm7x25();
+			legacy_ds |= cpu_is_msm7x27() || cpu_is_msm7x30();
+			legacy_ds |= cpu_is_qsd8x50() || cpu_is_msm8x55();
+			/*
+			 * use legacy mode for 8660 Standalone (subtype 0)
+			 */
+			legacy_ds |= cpu_is_msm8x60() &&
+					(socinfo_get_platform_subtype() == 0x0);
+
+			if (!legacy_ds)
+				continue;
+		}
+
+		tty_register_device(smd_tty_driver, idx, 0);
+		init_completion(&smd_tty[idx].ch_allocated);
+
+		/* register platform device */
+		smd_tty[idx].driver.probe = smd_tty_dummy_probe;
+		smd_tty[idx].driver.driver.name = smd_configs[n].dev_name;
+		smd_tty[idx].driver.driver.owner = THIS_MODULE;
+		spin_lock_init(&smd_tty[idx].reset_lock);
+		smd_tty[idx].is_open = 0;
+		init_waitqueue_head(&smd_tty[idx].ch_opened_wait_queue);
+		ret = platform_driver_register(&smd_tty[idx].driver);
+
+		if (ret) {
+			pr_err("%s: init failed %d (%d)\n", __func__, idx, ret);
+			smd_tty[idx].driver.probe = NULL;
+			goto out;
+		}
+		smd_tty[idx].smd = &smd_configs[n];
+	}
+	INIT_DELAYED_WORK(&loopback_work, loopback_probe_worker);
+	return 0;
+
+out:
+	/* unregister platform devices */
+	for (n = 0; n < ARRAY_SIZE(smd_configs); ++n) {
+		idx = smd_configs[n].tty_dev_index;
+
+		if (smd_tty[idx].driver.probe) {
+			platform_driver_unregister(&smd_tty[idx].driver);
+			tty_unregister_device(smd_tty_driver, idx);
+		}
+	}
+
+	tty_unregister_driver(smd_tty_driver);
+	put_tty_driver(smd_tty_driver);
+	return ret;
+}
+
+module_init(smd_tty_init);
diff --git a/arch/arm/mach-msm/smem_log.c b/arch/arm/mach-msm/smem_log.c
new file mode 100644
index 0000000..2e9a97c
--- /dev/null
+++ b/arch/arm/mach-msm/smem_log.c
@@ -0,0 +1,2036 @@
+/* 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
+ * 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.
+ *
+ */
+/*
+ * Shared memory logging implementation.
+ */
+
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/jiffies.h>
+#include <linux/remote_spinlock.h>
+#include <linux/debugfs.h>
+#include <linux/io.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+
+#include <mach/msm_iomap.h>
+#include <mach/smem_log.h>
+
+#include "smd_private.h"
+#include "smd_rpc_sym.h"
+#include "modem_notifier.h"
+
+#define DEBUG
+#undef DEBUG
+
+#ifdef DEBUG
+#define D_DUMP_BUFFER(prestr, cnt, buf) \
+do { \
+	int i; \
+	printk(KERN_ERR "%s", prestr); \
+	for (i = 0; i < cnt; i++) \
+		printk(KERN_ERR "%.2x", buf[i]); \
+	printk(KERN_ERR "\n"); \
+} while (0)
+#else
+#define D_DUMP_BUFFER(prestr, cnt, buf)
+#endif
+
+#ifdef DEBUG
+#define D(x...) printk(x)
+#else
+#define D(x...) do {} while (0)
+#endif
+
+/*
+ * Legacy targets use the 32KHz hardware timer and new targets will use
+ * the scheduler timer scaled to a 32KHz tick count.
+ *
+ * As testing on legacy targets permits, we will move them to use
+ * sched_clock() and eventually remove the conditiona compilation.
+ */
+#if defined(CONFIG_ARCH_MSM7X30) || defined(CONFIG_ARCH_MSM8X60) \
+	|| defined(CONFIG_ARCH_FSM9XXX)
+#define TIMESTAMP_ADDR (MSM_TMR_BASE + 0x08)
+#elif defined(CONFIG_ARCH_APQ8064) || defined(CONFIG_ARCH_MSM7X01A) || \
+	defined(CONFIG_ARCH_MSM7x25) || defined(CONFIG_ARCH_MSM7X27) || \
+	defined(CONFIG_ARCH_MSM7X27A) || defined(CONFIG_ARCH_MSM8960) || \
+	defined(CONFIG_ARCH_MSM9615) || defined(CONFIG_ARCH_QSD8X50)
+#define TIMESTAMP_ADDR (MSM_TMR_BASE + 0x04)
+#endif
+
+struct smem_log_item {
+	uint32_t identifier;
+	uint32_t timetick;
+	uint32_t data1;
+	uint32_t data2;
+	uint32_t data3;
+};
+
+#define SMEM_LOG_NUM_ENTRIES 2000
+#define SMEM_LOG_EVENTS_SIZE (sizeof(struct smem_log_item) * \
+			      SMEM_LOG_NUM_ENTRIES)
+
+#define SMEM_LOG_NUM_STATIC_ENTRIES 150
+#define SMEM_STATIC_LOG_EVENTS_SIZE (sizeof(struct smem_log_item) * \
+				     SMEM_LOG_NUM_STATIC_ENTRIES)
+
+#define SMEM_LOG_NUM_POWER_ENTRIES 2000
+#define SMEM_POWER_LOG_EVENTS_SIZE (sizeof(struct smem_log_item) * \
+			      SMEM_LOG_NUM_POWER_ENTRIES)
+
+#define SMEM_SPINLOCK_SMEM_LOG		"S:2"
+#define SMEM_SPINLOCK_STATIC_LOG	"S:5"
+/* POWER shares with SMEM_SPINLOCK_SMEM_LOG */
+
+static remote_spinlock_t remote_spinlock;
+static remote_spinlock_t remote_spinlock_static;
+static uint32_t smem_log_enable;
+static int smem_log_initialized;
+
+module_param_named(log_enable, smem_log_enable, int,
+		   S_IRUGO | S_IWUSR | S_IWGRP);
+
+
+struct smem_log_inst {
+	int which_log;
+	struct smem_log_item __iomem *events;
+	uint32_t __iomem *idx;
+	uint32_t num;
+	uint32_t read_idx;
+	uint32_t last_read_avail;
+	wait_queue_head_t read_wait;
+	remote_spinlock_t *remote_spinlock;
+};
+
+enum smem_logs {
+	GEN = 0,
+	STA,
+	POW,
+	NUM
+};
+
+static struct smem_log_inst inst[NUM];
+
+#if defined(CONFIG_DEBUG_FS)
+
+#define HSIZE 13
+
+struct sym {
+	uint32_t val;
+	char *str;
+	struct hlist_node node;
+};
+
+struct sym id_syms[] = {
+	{ SMEM_LOG_PROC_ID_MODEM, "MODM" },
+	{ SMEM_LOG_PROC_ID_Q6, "QDSP" },
+	{ SMEM_LOG_PROC_ID_APPS, "APPS" },
+	{ SMEM_LOG_PROC_ID_WCNSS, "WCNSS" },
+};
+
+struct sym base_syms[] = {
+	{ SMEM_LOG_ONCRPC_EVENT_BASE, "ONCRPC" },
+	{ SMEM_LOG_SMEM_EVENT_BASE, "SMEM" },
+	{ SMEM_LOG_TMC_EVENT_BASE, "TMC" },
+	{ SMEM_LOG_TIMETICK_EVENT_BASE, "TIMETICK" },
+	{ SMEM_LOG_DEM_EVENT_BASE, "DEM" },
+	{ SMEM_LOG_ERROR_EVENT_BASE, "ERROR" },
+	{ SMEM_LOG_DCVS_EVENT_BASE, "DCVS" },
+	{ SMEM_LOG_SLEEP_EVENT_BASE, "SLEEP" },
+	{ SMEM_LOG_RPC_ROUTER_EVENT_BASE, "ROUTER" },
+};
+
+struct sym event_syms[] = {
+#if defined(CONFIG_MSM_N_WAY_SMSM)
+	{ DEM_SMSM_ISR, "SMSM_ISR" },
+	{ DEM_STATE_CHANGE, "STATE_CHANGE" },
+	{ DEM_STATE_MACHINE_ENTER, "STATE_MACHINE_ENTER" },
+	{ DEM_ENTER_SLEEP, "ENTER_SLEEP" },
+	{ DEM_END_SLEEP, "END_SLEEP" },
+	{ DEM_SETUP_SLEEP, "SETUP_SLEEP" },
+	{ DEM_SETUP_POWER_COLLAPSE, "SETUP_POWER_COLLAPSE" },
+	{ DEM_SETUP_SUSPEND, "SETUP_SUSPEND" },
+	{ DEM_EARLY_EXIT, "EARLY_EXIT" },
+	{ DEM_WAKEUP_REASON, "WAKEUP_REASON" },
+	{ DEM_DETECT_WAKEUP, "DETECT_WAKEUP" },
+	{ DEM_DETECT_RESET, "DETECT_RESET" },
+	{ DEM_DETECT_SLEEPEXIT, "DETECT_SLEEPEXIT" },
+	{ DEM_DETECT_RUN, "DETECT_RUN" },
+	{ DEM_APPS_SWFI, "APPS_SWFI" },
+	{ DEM_SEND_WAKEUP, "SEND_WAKEUP" },
+	{ DEM_ASSERT_OKTS, "ASSERT_OKTS" },
+	{ DEM_NEGATE_OKTS, "NEGATE_OKTS" },
+	{ DEM_PROC_COMM_CMD, "PROC_COMM_CMD" },
+	{ DEM_REMOVE_PROC_PWR, "REMOVE_PROC_PWR" },
+	{ DEM_RESTORE_PROC_PWR, "RESTORE_PROC_PWR" },
+	{ DEM_SMI_CLK_DISABLED, "SMI_CLK_DISABLED" },
+	{ DEM_SMI_CLK_ENABLED, "SMI_CLK_ENABLED" },
+	{ DEM_MAO_INTS, "MAO_INTS" },
+	{ DEM_APPS_WAKEUP_INT, "APPS_WAKEUP_INT" },
+	{ DEM_PROC_WAKEUP, "PROC_WAKEUP" },
+	{ DEM_PROC_POWERUP, "PROC_POWERUP" },
+	{ DEM_TIMER_EXPIRED, "TIMER_EXPIRED" },
+	{ DEM_SEND_BATTERY_INFO, "SEND_BATTERY_INFO" },
+	{ DEM_REMOTE_PWR_CB, "REMOTE_PWR_CB" },
+	{ DEM_TIME_SYNC_START, "TIME_SYNC_START" },
+	{ DEM_TIME_SYNC_SEND_VALUE, "TIME_SYNC_SEND_VALUE" },
+	{ DEM_TIME_SYNC_DONE, "TIME_SYNC_DONE" },
+	{ DEM_TIME_SYNC_REQUEST, "TIME_SYNC_REQUEST" },
+	{ DEM_TIME_SYNC_POLL, "TIME_SYNC_POLL" },
+	{ DEM_TIME_SYNC_INIT, "TIME_SYNC_INIT" },
+	{ DEM_INIT, "INIT" },
+#else
+
+	{ DEM_NO_SLEEP, "NO_SLEEP" },
+	{ DEM_INSUF_TIME, "INSUF_TIME" },
+	{ DEMAPPS_ENTER_SLEEP, "APPS_ENTER_SLEEP" },
+	{ DEMAPPS_DETECT_WAKEUP, "APPS_DETECT_WAKEUP" },
+	{ DEMAPPS_END_APPS_TCXO, "APPS_END_APPS_TCXO" },
+	{ DEMAPPS_ENTER_SLEEPEXIT, "APPS_ENTER_SLEEPEXIT" },
+	{ DEMAPPS_END_APPS_SLEEP, "APPS_END_APPS_SLEEP" },
+	{ DEMAPPS_SETUP_APPS_PWRCLPS, "APPS_SETUP_APPS_PWRCLPS" },
+	{ DEMAPPS_PWRCLPS_EARLY_EXIT, "APPS_PWRCLPS_EARLY_EXIT" },
+	{ DEMMOD_SEND_WAKEUP, "MOD_SEND_WAKEUP" },
+	{ DEMMOD_NO_APPS_VOTE, "MOD_NO_APPS_VOTE" },
+	{ DEMMOD_NO_TCXO_SLEEP, "MOD_NO_TCXO_SLEEP" },
+	{ DEMMOD_BT_CLOCK, "MOD_BT_CLOCK" },
+	{ DEMMOD_UART_CLOCK, "MOD_UART_CLOCK" },
+	{ DEMMOD_OKTS, "MOD_OKTS" },
+	{ DEM_SLEEP_INFO, "SLEEP_INFO" },
+	{ DEMMOD_TCXO_END, "MOD_TCXO_END" },
+	{ DEMMOD_END_SLEEP_SIG, "MOD_END_SLEEP_SIG" },
+	{ DEMMOD_SETUP_APPSSLEEP, "MOD_SETUP_APPSSLEEP" },
+	{ DEMMOD_ENTER_TCXO, "MOD_ENTER_TCXO" },
+	{ DEMMOD_WAKE_APPS, "MOD_WAKE_APPS" },
+	{ DEMMOD_POWER_COLLAPSE_APPS, "MOD_POWER_COLLAPSE_APPS" },
+	{ DEMMOD_RESTORE_APPS_PWR, "MOD_RESTORE_APPS_PWR" },
+	{ DEMAPPS_ASSERT_OKTS, "APPS_ASSERT_OKTS" },
+	{ DEMAPPS_RESTART_START_TIMER, "APPS_RESTART_START_TIMER" },
+	{ DEMAPPS_ENTER_RUN, "APPS_ENTER_RUN" },
+	{ DEMMOD_MAO_INTS, "MOD_MAO_INTS" },
+	{ DEMMOD_POWERUP_APPS_CALLED, "MOD_POWERUP_APPS_CALLED" },
+	{ DEMMOD_PC_TIMER_EXPIRED, "MOD_PC_TIMER_EXPIRED" },
+	{ DEM_DETECT_SLEEPEXIT, "_DETECT_SLEEPEXIT" },
+	{ DEM_DETECT_RUN, "DETECT_RUN" },
+	{ DEM_SET_APPS_TIMER, "SET_APPS_TIMER" },
+	{ DEM_NEGATE_OKTS, "NEGATE_OKTS" },
+	{ DEMMOD_APPS_WAKEUP_INT, "MOD_APPS_WAKEUP_INT" },
+	{ DEMMOD_APPS_SWFI, "MOD_APPS_SWFI" },
+	{ DEM_SEND_BATTERY_INFO, "SEND_BATTERY_INFO" },
+	{ DEM_SMI_CLK_DISABLED, "SMI_CLK_DISABLED" },
+	{ DEM_SMI_CLK_ENABLED, "SMI_CLK_ENABLED" },
+	{ DEMAPPS_SETUP_APPS_SUSPEND, "APPS_SETUP_APPS_SUSPEND" },
+	{ DEM_RPC_EARLY_EXIT, "RPC_EARLY_EXIT" },
+	{ DEMAPPS_WAKEUP_REASON, "APPS_WAKEUP_REASON" },
+	{ DEM_INIT, "INIT" },
+#endif
+	{ DEMMOD_UMTS_BASE, "MOD_UMTS_BASE" },
+	{ DEMMOD_GL1_GO_TO_SLEEP, "GL1_GO_TO_SLEEP" },
+	{ DEMMOD_GL1_SLEEP_START, "GL1_SLEEP_START" },
+	{ DEMMOD_GL1_AFTER_GSM_CLK_ON, "GL1_AFTER_GSM_CLK_ON" },
+	{ DEMMOD_GL1_BEFORE_RF_ON, "GL1_BEFORE_RF_ON" },
+	{ DEMMOD_GL1_AFTER_RF_ON, "GL1_AFTER_RF_ON" },
+	{ DEMMOD_GL1_FRAME_TICK, "GL1_FRAME_TICK" },
+	{ DEMMOD_GL1_WCDMA_START, "GL1_WCDMA_START" },
+	{ DEMMOD_GL1_WCDMA_ENDING, "GL1_WCDMA_ENDING" },
+	{ DEMMOD_UMTS_NOT_OKTS, "UMTS_NOT_OKTS" },
+	{ DEMMOD_UMTS_START_TCXO_SHUTDOWN, "UMTS_START_TCXO_SHUTDOWN" },
+	{ DEMMOD_UMTS_END_TCXO_SHUTDOWN, "UMTS_END_TCXO_SHUTDOWN" },
+	{ DEMMOD_UMTS_START_ARM_HALT, "UMTS_START_ARM_HALT" },
+	{ DEMMOD_UMTS_END_ARM_HALT, "UMTS_END_ARM_HALT" },
+	{ DEMMOD_UMTS_NEXT_WAKEUP_SCLK, "UMTS_NEXT_WAKEUP_SCLK" },
+	{ TIME_REMOTE_LOG_EVENT_START, "START" },
+	{ TIME_REMOTE_LOG_EVENT_GOTO_WAIT,
+	  "GOTO_WAIT" },
+	{ TIME_REMOTE_LOG_EVENT_GOTO_INIT,
+	  "GOTO_INIT" },
+	{ ERR_ERROR_FATAL, "ERR_ERROR_FATAL" },
+	{ ERR_ERROR_FATAL_TASK, "ERR_ERROR_FATAL_TASK" },
+	{ DCVSAPPS_LOG_IDLE, "DCVSAPPS_LOG_IDLE" },
+	{ DCVSAPPS_LOG_ERR, "DCVSAPPS_LOG_ERR" },
+	{ DCVSAPPS_LOG_CHG, "DCVSAPPS_LOG_CHG" },
+	{ DCVSAPPS_LOG_REG, "DCVSAPPS_LOG_REG" },
+	{ DCVSAPPS_LOG_DEREG, "DCVSAPPS_LOG_DEREG" },
+	{ SMEM_LOG_EVENT_CB, "CB" },
+	{ SMEM_LOG_EVENT_START, "START" },
+	{ SMEM_LOG_EVENT_INIT, "INIT" },
+	{ SMEM_LOG_EVENT_RUNNING, "RUNNING" },
+	{ SMEM_LOG_EVENT_STOP, "STOP" },
+	{ SMEM_LOG_EVENT_RESTART, "RESTART" },
+	{ SMEM_LOG_EVENT_SS, "SS" },
+	{ SMEM_LOG_EVENT_READ, "READ" },
+	{ SMEM_LOG_EVENT_WRITE, "WRITE" },
+	{ SMEM_LOG_EVENT_SIGS1, "SIGS1" },
+	{ SMEM_LOG_EVENT_SIGS2, "SIGS2" },
+	{ SMEM_LOG_EVENT_WRITE_DM, "WRITE_DM" },
+	{ SMEM_LOG_EVENT_READ_DM, "READ_DM" },
+	{ SMEM_LOG_EVENT_SKIP_DM, "SKIP_DM" },
+	{ SMEM_LOG_EVENT_STOP_DM, "STOP_DM" },
+	{ SMEM_LOG_EVENT_ISR, "ISR" },
+	{ SMEM_LOG_EVENT_TASK, "TASK" },
+	{ SMEM_LOG_EVENT_RS, "RS" },
+	{ ONCRPC_LOG_EVENT_SMD_WAIT, "SMD_WAIT" },
+	{ ONCRPC_LOG_EVENT_RPC_WAIT, "RPC_WAIT" },
+	{ ONCRPC_LOG_EVENT_RPC_BOTH_WAIT, "RPC_BOTH_WAIT" },
+	{ ONCRPC_LOG_EVENT_RPC_INIT, "RPC_INIT" },
+	{ ONCRPC_LOG_EVENT_RUNNING, "RUNNING" },
+	{ ONCRPC_LOG_EVENT_APIS_INITED, "APIS_INITED" },
+	{ ONCRPC_LOG_EVENT_AMSS_RESET, "AMSS_RESET" },
+	{ ONCRPC_LOG_EVENT_SMD_RESET, "SMD_RESET" },
+	{ ONCRPC_LOG_EVENT_ONCRPC_RESET, "ONCRPC_RESET" },
+	{ ONCRPC_LOG_EVENT_CB, "CB" },
+	{ ONCRPC_LOG_EVENT_STD_CALL, "STD_CALL" },
+	{ ONCRPC_LOG_EVENT_STD_REPLY, "STD_REPLY" },
+	{ ONCRPC_LOG_EVENT_STD_CALL_ASYNC, "STD_CALL_ASYNC" },
+	{ NO_SLEEP_OLD, "NO_SLEEP_OLD" },
+	{ INSUF_TIME, "INSUF_TIME" },
+	{ MOD_UART_CLOCK, "MOD_UART_CLOCK" },
+	{ SLEEP_INFO, "SLEEP_INFO" },
+	{ MOD_TCXO_END, "MOD_TCXO_END" },
+	{ MOD_ENTER_TCXO, "MOD_ENTER_TCXO" },
+	{ NO_SLEEP_NEW, "NO_SLEEP_NEW" },
+	{ RPC_ROUTER_LOG_EVENT_UNKNOWN, "UNKNOWN" },
+	{ RPC_ROUTER_LOG_EVENT_MSG_READ, "MSG_READ" },
+	{ RPC_ROUTER_LOG_EVENT_MSG_WRITTEN, "MSG_WRITTEN" },
+	{ RPC_ROUTER_LOG_EVENT_MSG_CFM_REQ, "MSG_CFM_REQ" },
+	{ RPC_ROUTER_LOG_EVENT_MSG_CFM_SNT, "MSG_CFM_SNT" },
+	{ RPC_ROUTER_LOG_EVENT_MID_READ, "MID_READ" },
+	{ RPC_ROUTER_LOG_EVENT_MID_WRITTEN, "MID_WRITTEN" },
+	{ RPC_ROUTER_LOG_EVENT_MID_CFM_REQ, "MID_CFM_REQ" },
+};
+
+struct sym wakeup_syms[] = {
+	{ 0x00000040, "OTHER" },
+	{ 0x00000020, "RESET" },
+	{ 0x00000010, "ALARM" },
+	{ 0x00000008, "TIMER" },
+	{ 0x00000004, "GPIO" },
+	{ 0x00000002, "INT" },
+	{ 0x00000001, "RPC" },
+	{ 0x00000000, "NONE" },
+};
+
+struct sym wakeup_int_syms[] = {
+	{ 0, "MDDI_EXT" },
+	{ 1, "MDDI_PRI" },
+	{ 2, "MDDI_CLIENT"},
+	{ 3, "USB_OTG" },
+	{ 4, "I2CC" },
+	{ 5, "SDC1_0" },
+	{ 6, "SDC1_1" },
+	{ 7, "SDC2_0" },
+	{ 8, "SDC2_1" },
+	{ 9, "ADSP_A9A11" },
+	{ 10, "UART1" },
+	{ 11, "UART2" },
+	{ 12, "UART3" },
+	{ 13, "DP_RX_DATA" },
+	{ 14, "DP_RX_DATA2" },
+	{ 15, "DP_RX_DATA3" },
+	{ 16, "DM_UART" },
+	{ 17, "DM_DP_RX_DATA" },
+	{ 18, "KEYSENSE" },
+	{ 19, "HSSD" },
+	{ 20, "NAND_WR_ER_DONE" },
+	{ 21, "NAND_OP_DONE" },
+	{ 22, "TCHSCRN1" },
+	{ 23, "TCHSCRN2" },
+	{ 24, "TCHSCRN_SSBI" },
+	{ 25, "USB_HS" },
+	{ 26, "UART2_DM_RX" },
+	{ 27, "UART2_DM" },
+	{ 28, "SDC4_1" },
+	{ 29, "SDC4_0" },
+	{ 30, "SDC3_1" },
+	{ 31, "SDC3_0" },
+};
+
+struct sym smsm_syms[] = {
+	{ 0x80000000, "UN" },
+	{ 0x7F000000, "ERR" },
+	{ 0x00800000, "SMLP" },
+	{ 0x00400000, "ADWN" },
+	{ 0x00200000, "PWRS" },
+	{ 0x00100000, "DWLD" },
+	{ 0x00080000, "SRBT" },
+	{ 0x00040000, "SDWN" },
+	{ 0x00020000, "ARBT" },
+	{ 0x00010000, "REL" },
+	{ 0x00008000, "SLE" },
+	{ 0x00004000, "SLP" },
+	{ 0x00002000, "WFPI" },
+	{ 0x00001000, "EEX" },
+	{ 0x00000800, "TIN" },
+	{ 0x00000400, "TWT" },
+	{ 0x00000200, "PWRC" },
+	{ 0x00000100, "RUN" },
+	{ 0x00000080, "SA" },
+	{ 0x00000040, "RES" },
+	{ 0x00000020, "RIN" },
+	{ 0x00000010, "RWT" },
+	{ 0x00000008, "SIN" },
+	{ 0x00000004, "SWT" },
+	{ 0x00000002, "OE" },
+	{ 0x00000001, "I" },
+};
+
+/* never reorder */
+struct sym voter_d2_syms[] = {
+	{ 0x00000001, NULL },
+	{ 0x00000002, NULL },
+	{ 0x00000004, NULL },
+	{ 0x00000008, NULL },
+	{ 0x00000010, NULL },
+	{ 0x00000020, NULL },
+	{ 0x00000040, NULL },
+	{ 0x00000080, NULL },
+	{ 0x00000100, NULL },
+	{ 0x00000200, NULL },
+	{ 0x00000400, NULL },
+	{ 0x00000800, NULL },
+	{ 0x00001000, NULL },
+	{ 0x00002000, NULL },
+	{ 0x00004000, NULL },
+	{ 0x00008000, NULL },
+	{ 0x00010000, NULL },
+	{ 0x00020000, NULL },
+	{ 0x00040000, NULL },
+	{ 0x00080000, NULL },
+	{ 0x00100000, NULL },
+	{ 0x00200000, NULL },
+	{ 0x00400000, NULL },
+	{ 0x00800000, NULL },
+	{ 0x01000000, NULL },
+	{ 0x02000000, NULL },
+	{ 0x04000000, NULL },
+	{ 0x08000000, NULL },
+	{ 0x10000000, NULL },
+	{ 0x20000000, NULL },
+	{ 0x40000000, NULL },
+	{ 0x80000000, NULL },
+};
+
+/* never reorder */
+struct sym voter_d3_syms[] = {
+	{ 0x00000001, NULL },
+	{ 0x00000002, NULL },
+	{ 0x00000004, NULL },
+	{ 0x00000008, NULL },
+	{ 0x00000010, NULL },
+	{ 0x00000020, NULL },
+	{ 0x00000040, NULL },
+	{ 0x00000080, NULL },
+	{ 0x00000100, NULL },
+	{ 0x00000200, NULL },
+	{ 0x00000400, NULL },
+	{ 0x00000800, NULL },
+	{ 0x00001000, NULL },
+	{ 0x00002000, NULL },
+	{ 0x00004000, NULL },
+	{ 0x00008000, NULL },
+	{ 0x00010000, NULL },
+	{ 0x00020000, NULL },
+	{ 0x00040000, NULL },
+	{ 0x00080000, NULL },
+	{ 0x00100000, NULL },
+	{ 0x00200000, NULL },
+	{ 0x00400000, NULL },
+	{ 0x00800000, NULL },
+	{ 0x01000000, NULL },
+	{ 0x02000000, NULL },
+	{ 0x04000000, NULL },
+	{ 0x08000000, NULL },
+	{ 0x10000000, NULL },
+	{ 0x20000000, NULL },
+	{ 0x40000000, NULL },
+	{ 0x80000000, NULL },
+};
+
+struct sym dem_state_master_syms[] = {
+	{ 0, "INIT" },
+	{ 1, "RUN" },
+	{ 2, "SLEEP_WAIT" },
+	{ 3, "SLEEP_CONFIRMED" },
+	{ 4, "SLEEP_EXIT" },
+	{ 5, "RSA" },
+	{ 6, "EARLY_EXIT" },
+	{ 7, "RSA_DELAYED" },
+	{ 8, "RSA_CHECK_INTS" },
+	{ 9, "RSA_CONFIRMED" },
+	{ 10, "RSA_WAKING" },
+	{ 11, "RSA_RESTORE" },
+	{ 12, "RESET" },
+};
+
+struct sym dem_state_slave_syms[] = {
+	{ 0, "INIT" },
+	{ 1, "RUN" },
+	{ 2, "SLEEP_WAIT" },
+	{ 3, "SLEEP_EXIT" },
+	{ 4, "SLEEP_RUN_PENDING" },
+	{ 5, "POWER_COLLAPSE" },
+	{ 6, "CHECK_INTERRUPTS" },
+	{ 7, "SWFI" },
+	{ 8, "WFPI" },
+	{ 9, "EARLY_EXIT" },
+	{ 10, "RESET_RECOVER" },
+	{ 11, "RESET_ACKNOWLEDGE" },
+	{ 12, "ERROR" },
+};
+
+struct sym smsm_entry_type_syms[] = {
+	{ 0, "SMSM_APPS_STATE" },
+	{ 1, "SMSM_MODEM_STATE" },
+	{ 2, "SMSM_Q6_STATE" },
+	{ 3, "SMSM_APPS_DEM" },
+	{ 4, "SMSM_MODEM_DEM" },
+	{ 5, "SMSM_Q6_DEM" },
+	{ 6, "SMSM_POWER_MASTER_DEM" },
+	{ 7, "SMSM_TIME_MASTER_DEM" },
+};
+
+struct sym smsm_state_syms[] = {
+	{ 0x00000001, "INIT" },
+	{ 0x00000002, "OSENTERED" },
+	{ 0x00000004, "SMDWAIT" },
+	{ 0x00000008, "SMDINIT" },
+	{ 0x00000010, "RPCWAIT" },
+	{ 0x00000020, "RPCINIT" },
+	{ 0x00000040, "RESET" },
+	{ 0x00000080, "RSA" },
+	{ 0x00000100, "RUN" },
+	{ 0x00000200, "PWRC" },
+	{ 0x00000400, "TIMEWAIT" },
+	{ 0x00000800, "TIMEINIT" },
+	{ 0x00001000, "PWRC_EARLY_EXIT" },
+	{ 0x00002000, "WFPI" },
+	{ 0x00004000, "SLEEP" },
+	{ 0x00008000, "SLEEPEXIT" },
+	{ 0x00010000, "OEMSBL_RELEASE" },
+	{ 0x00020000, "APPS_REBOOT" },
+	{ 0x00040000, "SYSTEM_POWER_DOWN" },
+	{ 0x00080000, "SYSTEM_REBOOT" },
+	{ 0x00100000, "SYSTEM_DOWNLOAD" },
+	{ 0x00200000, "PWRC_SUSPEND" },
+	{ 0x00400000, "APPS_SHUTDOWN" },
+	{ 0x00800000, "SMD_LOOPBACK" },
+	{ 0x01000000, "RUN_QUIET" },
+	{ 0x02000000, "MODEM_WAIT" },
+	{ 0x04000000, "MODEM_BREAK" },
+	{ 0x08000000, "MODEM_CONTINUE" },
+	{ 0x80000000, "UNKNOWN" },
+};
+
+#define ID_SYM 0
+#define BASE_SYM 1
+#define EVENT_SYM 2
+#define WAKEUP_SYM 3
+#define WAKEUP_INT_SYM 4
+#define SMSM_SYM 5
+#define VOTER_D2_SYM 6
+#define VOTER_D3_SYM 7
+#define DEM_STATE_MASTER_SYM 8
+#define DEM_STATE_SLAVE_SYM 9
+#define SMSM_ENTRY_TYPE_SYM 10
+#define SMSM_STATE_SYM 11
+
+static struct sym_tbl {
+	struct sym *data;
+	int size;
+	struct hlist_head hlist[HSIZE];
+} tbl[] = {
+	{ id_syms, ARRAY_SIZE(id_syms) },
+	{ base_syms, ARRAY_SIZE(base_syms) },
+	{ event_syms, ARRAY_SIZE(event_syms) },
+	{ wakeup_syms, ARRAY_SIZE(wakeup_syms) },
+	{ wakeup_int_syms, ARRAY_SIZE(wakeup_int_syms) },
+	{ smsm_syms, ARRAY_SIZE(smsm_syms) },
+	{ voter_d2_syms, ARRAY_SIZE(voter_d2_syms) },
+	{ voter_d3_syms, ARRAY_SIZE(voter_d3_syms) },
+	{ dem_state_master_syms, ARRAY_SIZE(dem_state_master_syms) },
+	{ dem_state_slave_syms, ARRAY_SIZE(dem_state_slave_syms) },
+	{ smsm_entry_type_syms, ARRAY_SIZE(smsm_entry_type_syms) },
+	{ smsm_state_syms, ARRAY_SIZE(smsm_state_syms) },
+};
+
+static void find_voters(void)
+{
+	void *x, *next;
+	unsigned size;
+	int i = 0, j = 0;
+
+	x = smem_get_entry(SMEM_SLEEP_STATIC, &size);
+	next = x;
+	while (next && (next < (x + size)) &&
+	       ((i + j) < (ARRAY_SIZE(voter_d3_syms) +
+			   ARRAY_SIZE(voter_d2_syms)))) {
+
+		if (i < ARRAY_SIZE(voter_d3_syms)) {
+			voter_d3_syms[i].str = (char *) next;
+			i++;
+		} else if (i >= ARRAY_SIZE(voter_d3_syms) &&
+			   j < ARRAY_SIZE(voter_d2_syms)) {
+			voter_d2_syms[j].str = (char *) next;
+			j++;
+		}
+
+		next += 9;
+	}
+}
+
+#define hash(val) (val % HSIZE)
+
+static void init_syms(void)
+{
+	int i;
+	int j;
+
+	for (i = 0; i < ARRAY_SIZE(tbl); ++i)
+		for (j = 0; j < HSIZE; ++j)
+			INIT_HLIST_HEAD(&tbl[i].hlist[j]);
+
+	for (i = 0; i < ARRAY_SIZE(tbl); ++i)
+		for (j = 0; j < tbl[i].size; ++j) {
+			INIT_HLIST_NODE(&tbl[i].data[j].node);
+			hlist_add_head(&tbl[i].data[j].node,
+				       &tbl[i].hlist[hash(tbl[i].data[j].val)]);
+		}
+}
+
+static char *find_sym(uint32_t id, uint32_t val)
+{
+	struct hlist_node *n;
+	struct sym *s;
+
+	hlist_for_each(n, &tbl[id].hlist[hash(val)]) {
+		s = hlist_entry(n, struct sym, node);
+		if (s->val == val)
+			return s->str;
+	}
+
+	return 0;
+}
+
+#else
+static void init_syms(void) {}
+#endif
+
+#ifdef TIMESTAMP_ADDR
+/* legacy timestamp using 32.768KHz clock */
+static inline unsigned int read_timestamp(void)
+{
+	unsigned int tick = 0;
+
+	/* no barriers necessary as the read value is a dependency for the
+	 * comparison operation so the processor shouldn't be able to
+	 * reorder things
+	 */
+	do {
+		tick = __raw_readl(TIMESTAMP_ADDR);
+	} while (tick != __raw_readl(TIMESTAMP_ADDR));
+
+	return tick;
+}
+#else
+static inline unsigned int read_timestamp(void)
+{
+	unsigned long long val;
+
+	/* SMEM LOG uses a 32.768KHz timestamp */
+	val = sched_clock() * 32768U;
+	do_div(val, 1000000000U);
+
+	return (unsigned int)val;
+}
+#endif
+
+static void smem_log_event_from_user(struct smem_log_inst *inst,
+				     const char __user *buf, int size, int num)
+{
+	uint32_t idx;
+	uint32_t next_idx;
+	unsigned long flags;
+	uint32_t identifier = 0;
+	uint32_t timetick = 0;
+	int first = 1;
+	int ret;
+
+	if (!inst->idx) {
+		pr_err("%s: invalid write index\n", __func__);
+		return;
+	}
+
+	remote_spin_lock_irqsave(inst->remote_spinlock, flags);
+
+	while (num--) {
+		idx = *inst->idx;
+
+		if (idx < inst->num) {
+			ret = copy_from_user(&inst->events[idx],
+					     buf, size);
+			if (ret) {
+				printk("ERROR %s:%i tried to write "
+				       "%i got ret %i",
+				       __func__, __LINE__,
+				       size, size - ret);
+				goto out;
+			}
+
+			if (first) {
+				identifier =
+					inst->events[idx].
+					identifier;
+				timetick = read_timestamp();
+				first = 0;
+			} else {
+				identifier |= SMEM_LOG_CONT;
+			}
+			inst->events[idx].identifier =
+				identifier;
+			inst->events[idx].timetick =
+				timetick;
+		}
+
+		next_idx = idx + 1;
+		if (next_idx >= inst->num)
+			next_idx = 0;
+		*inst->idx = next_idx;
+		buf += sizeof(struct smem_log_item);
+	}
+
+ out:
+	wmb();
+	remote_spin_unlock_irqrestore(inst->remote_spinlock, flags);
+}
+
+static void _smem_log_event(
+	struct smem_log_item __iomem *events,
+	uint32_t __iomem *_idx,
+	remote_spinlock_t *lock,
+	int num,
+	uint32_t id, uint32_t data1, uint32_t data2,
+	uint32_t data3)
+{
+	struct smem_log_item item;
+	uint32_t idx;
+	uint32_t next_idx;
+	unsigned long flags;
+
+	item.timetick = read_timestamp();
+	item.identifier = id;
+	item.data1 = data1;
+	item.data2 = data2;
+	item.data3 = data3;
+
+	remote_spin_lock_irqsave(lock, flags);
+
+	idx = *_idx;
+
+	if (idx < num) {
+		memcpy(&events[idx],
+		       &item, sizeof(item));
+	}
+
+	next_idx = idx + 1;
+	if (next_idx >= num)
+		next_idx = 0;
+	*_idx = next_idx;
+	wmb();
+
+	remote_spin_unlock_irqrestore(lock, flags);
+}
+
+static void _smem_log_event6(
+	struct smem_log_item __iomem *events,
+	uint32_t __iomem *_idx,
+	remote_spinlock_t *lock,
+	int num,
+	uint32_t id, uint32_t data1, uint32_t data2,
+	uint32_t data3, uint32_t data4, uint32_t data5,
+	uint32_t data6)
+{
+	struct smem_log_item item[2];
+	uint32_t idx;
+	uint32_t next_idx;
+	unsigned long flags;
+
+	item[0].timetick = read_timestamp();
+	item[0].identifier = id;
+	item[0].data1 = data1;
+	item[0].data2 = data2;
+	item[0].data3 = data3;
+	item[1].identifier = item[0].identifier;
+	item[1].timetick = item[0].timetick;
+	item[1].data1 = data4;
+	item[1].data2 = data5;
+	item[1].data3 = data6;
+
+	remote_spin_lock_irqsave(lock, flags);
+
+	idx = *_idx;
+
+	/* FIXME: Wrap around */
+	if (idx < (num-1)) {
+		memcpy(&events[idx],
+			&item, sizeof(item));
+	}
+
+	next_idx = idx + 2;
+	if (next_idx >= num)
+		next_idx = 0;
+	*_idx = next_idx;
+
+	wmb();
+	remote_spin_unlock_irqrestore(lock, flags);
+}
+
+void smem_log_event(uint32_t id, uint32_t data1, uint32_t data2,
+		    uint32_t data3)
+{
+	if (smem_log_enable)
+		_smem_log_event(inst[GEN].events, inst[GEN].idx,
+				inst[GEN].remote_spinlock,
+				SMEM_LOG_NUM_ENTRIES, id,
+				data1, data2, data3);
+}
+
+void smem_log_event6(uint32_t id, uint32_t data1, uint32_t data2,
+		     uint32_t data3, uint32_t data4, uint32_t data5,
+		     uint32_t data6)
+{
+	if (smem_log_enable)
+		_smem_log_event6(inst[GEN].events, inst[GEN].idx,
+				 inst[GEN].remote_spinlock,
+				 SMEM_LOG_NUM_ENTRIES, id,
+				 data1, data2, data3, data4, data5, data6);
+}
+
+void smem_log_event_to_static(uint32_t id, uint32_t data1, uint32_t data2,
+		    uint32_t data3)
+{
+	if (smem_log_enable)
+		_smem_log_event(inst[STA].events, inst[STA].idx,
+				inst[STA].remote_spinlock,
+				SMEM_LOG_NUM_STATIC_ENTRIES, id,
+				data1, data2, data3);
+}
+
+void smem_log_event6_to_static(uint32_t id, uint32_t data1, uint32_t data2,
+		     uint32_t data3, uint32_t data4, uint32_t data5,
+		     uint32_t data6)
+{
+	if (smem_log_enable)
+		_smem_log_event6(inst[STA].events, inst[STA].idx,
+				 inst[STA].remote_spinlock,
+				 SMEM_LOG_NUM_STATIC_ENTRIES, id,
+				 data1, data2, data3, data4, data5, data6);
+}
+
+static int _smem_log_init(void)
+{
+	int ret;
+
+	inst[GEN].which_log = GEN;
+	inst[GEN].events =
+		(struct smem_log_item *)smem_alloc2(SMEM_SMEM_LOG_EVENTS,
+						  SMEM_LOG_EVENTS_SIZE);
+	inst[GEN].idx = (uint32_t *)smem_alloc2(SMEM_SMEM_LOG_IDX,
+					     sizeof(uint32_t));
+	if (!inst[GEN].events || !inst[GEN].idx)
+		pr_info("%s: no log or log_idx allocated\n", __func__);
+
+	inst[GEN].num = SMEM_LOG_NUM_ENTRIES;
+	inst[GEN].read_idx = 0;
+	inst[GEN].last_read_avail = SMEM_LOG_NUM_ENTRIES;
+	init_waitqueue_head(&inst[GEN].read_wait);
+	inst[GEN].remote_spinlock = &remote_spinlock;
+
+	inst[STA].which_log = STA;
+	inst[STA].events =
+		(struct smem_log_item *)
+		smem_alloc2(SMEM_SMEM_STATIC_LOG_EVENTS,
+			   SMEM_STATIC_LOG_EVENTS_SIZE);
+	inst[STA].idx = (uint32_t *)smem_alloc2(SMEM_SMEM_STATIC_LOG_IDX,
+						     sizeof(uint32_t));
+	if (!inst[STA].events || !inst[STA].idx)
+		pr_info("%s: no static log or log_idx allocated\n", __func__);
+
+	inst[STA].num = SMEM_LOG_NUM_STATIC_ENTRIES;
+	inst[STA].read_idx = 0;
+	inst[STA].last_read_avail = SMEM_LOG_NUM_ENTRIES;
+	init_waitqueue_head(&inst[STA].read_wait);
+	inst[STA].remote_spinlock = &remote_spinlock_static;
+
+	inst[POW].which_log = POW;
+	inst[POW].events =
+		(struct smem_log_item *)
+		smem_alloc2(SMEM_SMEM_LOG_POWER_EVENTS,
+			   SMEM_POWER_LOG_EVENTS_SIZE);
+	inst[POW].idx = (uint32_t *)smem_alloc2(SMEM_SMEM_LOG_POWER_IDX,
+						     sizeof(uint32_t));
+	if (!inst[POW].events || !inst[POW].idx)
+		pr_info("%s: no power log or log_idx allocated\n", __func__);
+
+	inst[POW].num = SMEM_LOG_NUM_POWER_ENTRIES;
+	inst[POW].read_idx = 0;
+	inst[POW].last_read_avail = SMEM_LOG_NUM_ENTRIES;
+	init_waitqueue_head(&inst[POW].read_wait);
+	inst[POW].remote_spinlock = &remote_spinlock;
+
+	ret = remote_spin_lock_init(&remote_spinlock,
+			      SMEM_SPINLOCK_SMEM_LOG);
+	if (ret) {
+		mb();
+		return ret;
+	}
+
+	ret = remote_spin_lock_init(&remote_spinlock_static,
+			      SMEM_SPINLOCK_STATIC_LOG);
+	if (ret) {
+		mb();
+		return ret;
+	}
+
+	init_syms();
+	mb();
+
+	return 0;
+}
+
+static ssize_t smem_log_read_bin(struct file *fp, char __user *buf,
+			size_t count, loff_t *pos)
+{
+	int idx;
+	int orig_idx;
+	unsigned long flags;
+	int ret;
+	int tot_bytes = 0;
+	struct smem_log_inst *local_inst;
+
+	local_inst = fp->private_data;
+
+	if (!local_inst->idx)
+		return -ENODEV;
+
+	remote_spin_lock_irqsave(local_inst->remote_spinlock, flags);
+
+	orig_idx = *local_inst->idx;
+	idx = orig_idx;
+
+	while (1) {
+		idx--;
+		if (idx < 0)
+			idx = local_inst->num - 1;
+		if (idx == orig_idx) {
+			ret = tot_bytes;
+			break;
+		}
+
+		if ((tot_bytes + sizeof(struct smem_log_item)) > count) {
+			ret = tot_bytes;
+			break;
+		}
+
+		ret = copy_to_user(buf, &local_inst->events[idx],
+				   sizeof(struct smem_log_item));
+		if (ret) {
+			ret = -EIO;
+			break;
+		}
+
+		tot_bytes += sizeof(struct smem_log_item);
+
+		buf += sizeof(struct smem_log_item);
+	}
+
+	remote_spin_unlock_irqrestore(local_inst->remote_spinlock, flags);
+
+	return ret;
+}
+
+static ssize_t smem_log_read(struct file *fp, char __user *buf,
+			size_t count, loff_t *pos)
+{
+	char loc_buf[128];
+	int i;
+	int idx;
+	int orig_idx;
+	unsigned long flags;
+	int ret;
+	int tot_bytes = 0;
+	struct smem_log_inst *inst;
+
+	inst = fp->private_data;
+	if (!inst->idx)
+		return -ENODEV;
+
+	remote_spin_lock_irqsave(inst->remote_spinlock, flags);
+
+	orig_idx = *inst->idx;
+	idx = orig_idx;
+
+	while (1) {
+		idx--;
+		if (idx < 0)
+			idx = inst->num - 1;
+		if (idx == orig_idx) {
+			ret = tot_bytes;
+			break;
+		}
+
+		i = scnprintf(loc_buf, 128,
+			      "0x%x 0x%x 0x%x 0x%x 0x%x\n",
+			      inst->events[idx].identifier,
+			      inst->events[idx].timetick,
+			      inst->events[idx].data1,
+			      inst->events[idx].data2,
+			      inst->events[idx].data3);
+		if (i == 0) {
+			ret = -EIO;
+			break;
+		}
+
+		if ((tot_bytes + i) > count) {
+			ret = tot_bytes;
+			break;
+		}
+
+		tot_bytes += i;
+
+		ret = copy_to_user(buf, loc_buf, i);
+		if (ret) {
+			ret = -EIO;
+			break;
+		}
+
+		buf += i;
+	}
+
+	remote_spin_unlock_irqrestore(inst->remote_spinlock, flags);
+
+	return ret;
+}
+
+static ssize_t smem_log_write_bin(struct file *fp, const char __user *buf,
+			 size_t count, loff_t *pos)
+{
+	if (count < sizeof(struct smem_log_item))
+		return -EINVAL;
+
+	if (smem_log_enable)
+		smem_log_event_from_user(fp->private_data, buf,
+					sizeof(struct smem_log_item),
+					count / sizeof(struct smem_log_item));
+	return count;
+}
+
+static ssize_t smem_log_write(struct file *fp, const char __user *buf,
+			 size_t count, loff_t *pos)
+{
+	int ret;
+	const char delimiters[] = " ,;";
+	char locbuf[256] = {0};
+	uint32_t val[10] = {0};
+	int vals = 0;
+	char *token;
+	char *running;
+	struct smem_log_inst *inst;
+	unsigned long res;
+
+	inst = fp->private_data;
+
+	count = count > 255 ? 255 : count;
+
+	if (!smem_log_enable)
+		return count;
+
+	locbuf[count] = '\0';
+
+	ret = copy_from_user(locbuf, buf, count);
+	if (ret != 0) {
+		printk(KERN_ERR "ERROR: %s could not copy %i bytes\n",
+		       __func__, ret);
+		return -EINVAL;
+	}
+
+	D(KERN_ERR "%s: ", __func__);
+	D_DUMP_BUFFER("We got", len, locbuf);
+
+	running = locbuf;
+
+	token = strsep(&running, delimiters);
+	while (token && vals < ARRAY_SIZE(val)) {
+		if (*token != '\0') {
+			D(KERN_ERR "%s: ", __func__);
+			D_DUMP_BUFFER("", strlen(token), token);
+			ret = strict_strtoul(token, 0, &res);
+			if (ret) {
+				printk(KERN_ERR "ERROR: %s:%i got bad char "
+				       "at strict_strtoul\n",
+				       __func__, __LINE__-4);
+				return -EINVAL;
+			}
+			val[vals++] = res;
+		}
+		token = strsep(&running, delimiters);
+	}
+
+	if (vals > 5) {
+		if (inst->which_log == GEN)
+			smem_log_event6(val[0], val[2], val[3], val[4],
+					val[7], val[8], val[9]);
+		else if (inst->which_log == STA)
+			smem_log_event6_to_static(val[0],
+						  val[2], val[3], val[4],
+						  val[7], val[8], val[9]);
+		else
+			return -1;
+	} else {
+		if (inst->which_log == GEN)
+			smem_log_event(val[0], val[2], val[3], val[4]);
+		else if (inst->which_log == STA)
+			smem_log_event_to_static(val[0],
+						 val[2], val[3], val[4]);
+		else
+			return -1;
+	}
+
+	return count;
+}
+
+static int smem_log_open(struct inode *ip, struct file *fp)
+{
+	fp->private_data = &inst[GEN];
+
+	return 0;
+}
+
+
+static int smem_log_release(struct inode *ip, struct file *fp)
+{
+	return 0;
+}
+
+static long smem_log_ioctl(struct file *fp, unsigned int cmd,
+					   unsigned long arg);
+
+static const struct file_operations smem_log_fops = {
+	.owner = THIS_MODULE,
+	.read = smem_log_read,
+	.write = smem_log_write,
+	.open = smem_log_open,
+	.release = smem_log_release,
+	.unlocked_ioctl = smem_log_ioctl,
+};
+
+static const struct file_operations smem_log_bin_fops = {
+	.owner = THIS_MODULE,
+	.read = smem_log_read_bin,
+	.write = smem_log_write_bin,
+	.open = smem_log_open,
+	.release = smem_log_release,
+	.unlocked_ioctl = smem_log_ioctl,
+};
+
+static long smem_log_ioctl(struct file *fp,
+			  unsigned int cmd, unsigned long arg)
+{
+	switch (cmd) {
+	default:
+		return -ENOTTY;
+
+	case SMIOC_SETMODE:
+		if (arg == SMIOC_TEXT) {
+			D("%s set text mode\n", __func__);
+			fp->f_op = &smem_log_fops;
+		} else if (arg == SMIOC_BINARY) {
+			D("%s set bin mode\n", __func__);
+			fp->f_op = &smem_log_bin_fops;
+		} else {
+			return -EINVAL;
+		}
+		break;
+	case SMIOC_SETLOG:
+		if (arg == SMIOC_LOG) {
+			if (inst[GEN].events)
+				fp->private_data = &inst[GEN];
+			else
+				return -ENODEV;
+		} else if (arg == SMIOC_STATIC_LOG) {
+			if (inst[STA].events)
+				fp->private_data = &inst[STA];
+			else
+				return -ENODEV;
+		} else {
+			return -EINVAL;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static struct miscdevice smem_log_dev = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "smem_log",
+	.fops = &smem_log_fops,
+};
+
+#if defined(CONFIG_DEBUG_FS)
+
+#define SMEM_LOG_ITEM_PRINT_SIZE 160
+
+#define EVENTS_PRINT_SIZE \
+(SMEM_LOG_ITEM_PRINT_SIZE * SMEM_LOG_NUM_ENTRIES)
+
+static uint32_t smem_log_timeout_ms;
+module_param_named(timeout_ms, smem_log_timeout_ms,
+		   int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+static int smem_log_debug_mask;
+module_param_named(debug_mask, smem_log_debug_mask, int,
+		   S_IRUGO | S_IWUSR | S_IWGRP);
+
+#define DBG(x...) do {\
+	if (smem_log_debug_mask) \
+		printk(KERN_DEBUG x);\
+	} while (0)
+
+static int update_read_avail(struct smem_log_inst *inst)
+{
+	int curr_read_avail;
+	unsigned long flags = 0;
+
+	if (!inst->idx)
+		return 0;
+
+	remote_spin_lock_irqsave(inst->remote_spinlock, flags);
+	curr_read_avail = (*inst->idx - inst->read_idx);
+	if (curr_read_avail < 0)
+		curr_read_avail = inst->num - inst->read_idx + *inst->idx;
+
+	DBG("%s: read = %d write = %d curr = %d last = %d\n", __func__,
+	    inst->read_idx, *inst->idx, curr_read_avail, inst->last_read_avail);
+
+	if (curr_read_avail < inst->last_read_avail) {
+		if (inst->last_read_avail != inst->num)
+			pr_info("smem_log: skipping %d log entries\n",
+				inst->last_read_avail);
+		inst->read_idx = *inst->idx + 1;
+		inst->last_read_avail = inst->num - 1;
+	} else
+		inst->last_read_avail = curr_read_avail;
+
+	remote_spin_unlock_irqrestore(inst->remote_spinlock, flags);
+
+	DBG("%s: read = %d write = %d curr = %d last = %d\n", __func__,
+	    inst->read_idx, *inst->idx, curr_read_avail, inst->last_read_avail);
+
+	return inst->last_read_avail;
+}
+
+static int _debug_dump(int log, char *buf, int max, uint32_t cont)
+{
+	unsigned int idx;
+	int write_idx, read_avail = 0;
+	unsigned long flags;
+	int i = 0;
+
+	if (!inst[log].events)
+		return 0;
+
+	if (cont && update_read_avail(&inst[log]) == 0)
+		return 0;
+
+	remote_spin_lock_irqsave(inst[log].remote_spinlock, flags);
+
+	if (cont) {
+		idx = inst[log].read_idx;
+		write_idx = (inst[log].read_idx + inst[log].last_read_avail);
+		if (write_idx >= inst[log].num)
+			write_idx -= inst[log].num;
+	} else {
+		write_idx = *inst[log].idx;
+		idx = (write_idx + 1);
+	}
+
+	DBG("%s: read %d write %d idx %d num %d\n", __func__,
+	    inst[log].read_idx, write_idx, idx, inst[log].num - 1);
+
+	while ((max - i) > 50) {
+		if ((inst[log].num - 1) < idx)
+			idx = 0;
+
+		if (idx == write_idx)
+			break;
+
+		if (inst[log].events[idx].identifier) {
+
+			i += scnprintf(buf + i, max - i,
+				       "%08x %08x %08x %08x %08x\n",
+				       inst[log].events[idx].identifier,
+				       inst[log].events[idx].timetick,
+				       inst[log].events[idx].data1,
+				       inst[log].events[idx].data2,
+				       inst[log].events[idx].data3);
+		}
+		idx++;
+	}
+	if (cont) {
+		inst[log].read_idx = idx;
+		read_avail = (write_idx - inst[log].read_idx);
+		if (read_avail < 0)
+			read_avail = inst->num - inst->read_idx + write_idx;
+		inst[log].last_read_avail = read_avail;
+	}
+
+	remote_spin_unlock_irqrestore(inst[log].remote_spinlock, flags);
+
+	DBG("%s: read %d write %d idx %d num %d\n", __func__,
+	    inst[log].read_idx, write_idx, idx, inst[log].num);
+
+	return i;
+}
+
+static int _debug_dump_voters(char *buf, int max)
+{
+	int k, i = 0;
+
+	find_voters();
+
+	i += scnprintf(buf + i, max - i, "Voters:\n");
+	for (k = 0; k < ARRAY_SIZE(voter_d3_syms); ++k)
+		if (voter_d3_syms[k].str)
+			i += scnprintf(buf + i, max - i, "%s ",
+				       voter_d3_syms[k].str);
+	for (k = 0; k < ARRAY_SIZE(voter_d2_syms); ++k)
+		if (voter_d2_syms[k].str)
+			i += scnprintf(buf + i, max - i, "%s ",
+				       voter_d2_syms[k].str);
+	i += scnprintf(buf + i, max - i, "\n");
+
+	return i;
+}
+
+static int _debug_dump_sym(int log, char *buf, int max, uint32_t cont)
+{
+	unsigned int idx;
+	int write_idx, read_avail = 0;
+	unsigned long flags;
+	int i = 0;
+
+	char *proc;
+	char *sub;
+	char *id;
+	const char *sym = NULL;
+
+	uint32_t data[3];
+
+	uint32_t proc_val = 0;
+	uint32_t sub_val = 0;
+	uint32_t id_val = 0;
+	uint32_t id_only_val = 0;
+	uint32_t data1 = 0;
+	uint32_t data2 = 0;
+	uint32_t data3 = 0;
+
+	if (!inst[log].events)
+		return 0;
+
+	find_voters();
+
+	if (cont && update_read_avail(&inst[log]) == 0)
+		return 0;
+
+	remote_spin_lock_irqsave(inst[log].remote_spinlock, flags);
+
+	if (cont) {
+		idx = inst[log].read_idx;
+		write_idx = (inst[log].read_idx + inst[log].last_read_avail);
+		if (write_idx >= inst[log].num)
+			write_idx -= inst[log].num;
+	} else {
+		write_idx = *inst[log].idx;
+		idx = (write_idx + 1);
+	}
+
+	DBG("%s: read %d write %d idx %d num %d\n", __func__,
+	    inst[log].read_idx, write_idx, idx, inst[log].num - 1);
+
+	for (; (max - i) > SMEM_LOG_ITEM_PRINT_SIZE; idx++) {
+		if (idx > (inst[log].num - 1))
+			idx = 0;
+
+		if (idx == write_idx)
+			break;
+
+		if (idx < inst[log].num) {
+			if (!inst[log].events[idx].identifier)
+				continue;
+
+			proc_val = PROC & inst[log].events[idx].identifier;
+			sub_val = SUB & inst[log].events[idx].identifier;
+			id_val = (SUB | ID) & inst[log].events[idx].identifier;
+			id_only_val = ID & inst[log].events[idx].identifier;
+			data1 = inst[log].events[idx].data1;
+			data2 = inst[log].events[idx].data2;
+			data3 = inst[log].events[idx].data3;
+
+			if (!(proc_val & SMEM_LOG_CONT)) {
+				i += scnprintf(buf + i, max - i, "\n");
+
+				proc = find_sym(ID_SYM, proc_val);
+
+				if (proc)
+					i += scnprintf(buf + i, max - i,
+						       "%4s: ", proc);
+				else
+					i += scnprintf(buf + i, max - i,
+						       "%04x: ",
+						       PROC &
+						       inst[log].events[idx].
+						       identifier);
+
+				i += scnprintf(buf + i, max - i, "%10u ",
+					       inst[log].events[idx].timetick);
+
+				sub = find_sym(BASE_SYM, sub_val);
+
+				if (sub)
+					i += scnprintf(buf + i, max - i,
+						       "%9s: ", sub);
+				else
+					i += scnprintf(buf + i, max - i,
+						       "%08x: ", sub_val);
+
+				id = find_sym(EVENT_SYM, id_val);
+
+				if (id)
+					i += scnprintf(buf + i, max - i,
+						       "%11s: ", id);
+				else
+					i += scnprintf(buf + i, max - i,
+						       "%08x: ", id_only_val);
+			}
+
+			if ((proc_val & SMEM_LOG_CONT) &&
+			    (id_val == ONCRPC_LOG_EVENT_STD_CALL ||
+			     id_val == ONCRPC_LOG_EVENT_STD_REPLY)) {
+				data[0] = data1;
+				data[1] = data2;
+				data[2] = data3;
+				i += scnprintf(buf + i, max - i,
+					       " %.16s", (char *) data);
+			} else if (proc_val & SMEM_LOG_CONT) {
+				i += scnprintf(buf + i, max - i,
+					       " %08x %08x %08x",
+					       data1, data2, data3);
+			} else if (id_val == ONCRPC_LOG_EVENT_STD_CALL) {
+				sym = smd_rpc_get_sym(data2);
+
+				if (sym)
+					i += scnprintf(buf + i, max - i,
+						       "xid:%4i %8s proc:%3i",
+						       data1, sym, data3);
+				else
+					i += scnprintf(buf + i, max - i,
+						       "xid:%4i %08x proc:%3i",
+						       data1, data2, data3);
+#if defined(CONFIG_MSM_N_WAY_SMSM)
+			} else if (id_val == DEM_STATE_CHANGE) {
+				if (data1 == 1) {
+					i += scnprintf(buf + i, max - i,
+						       "MASTER: ");
+					sym = find_sym(DEM_STATE_MASTER_SYM,
+						       data2);
+				} else if (data1 == 0) {
+					i += scnprintf(buf + i, max - i,
+						       " SLAVE: ");
+					sym = find_sym(DEM_STATE_SLAVE_SYM,
+						       data2);
+				} else {
+					i += scnprintf(buf + i, max - i,
+						       "%x: ",  data1);
+					sym = NULL;
+				}
+				if (sym)
+					i += scnprintf(buf + i, max - i,
+						       "from:%s ", sym);
+				else
+					i += scnprintf(buf + i, max - i,
+						       "from:0x%x ", data2);
+
+				if (data1 == 1)
+					sym = find_sym(DEM_STATE_MASTER_SYM,
+						       data3);
+				else if (data1 == 0)
+					sym = find_sym(DEM_STATE_SLAVE_SYM,
+						       data3);
+				else
+					sym = NULL;
+				if (sym)
+					i += scnprintf(buf + i, max - i,
+						       "to:%s ", sym);
+				else
+					i += scnprintf(buf + i, max - i,
+						       "to:0x%x ", data3);
+
+			} else if (id_val == DEM_STATE_MACHINE_ENTER) {
+				i += scnprintf(buf + i, max - i,
+					       "swfi:%i timer:%i manexit:%i",
+					       data1, data2, data3);
+
+			} else if (id_val == DEM_TIME_SYNC_REQUEST ||
+				   id_val == DEM_TIME_SYNC_POLL ||
+				   id_val == DEM_TIME_SYNC_INIT) {
+				sym = find_sym(SMSM_ENTRY_TYPE_SYM,
+					       data1);
+				if (sym)
+					i += scnprintf(buf + i, max - i,
+						       "hostid:%s", sym);
+				else
+					i += scnprintf(buf + i, max - i,
+						       "hostid:%x", data1);
+
+			} else if (id_val == DEM_TIME_SYNC_START ||
+				   id_val == DEM_TIME_SYNC_SEND_VALUE) {
+				unsigned mask = 0x1;
+				unsigned tmp = 0;
+				if (id_val == DEM_TIME_SYNC_START)
+					i += scnprintf(buf + i, max - i,
+						       "req:");
+				else
+					i += scnprintf(buf + i, max - i,
+						       "pol:");
+				while (mask) {
+					if (mask & data1) {
+						sym = find_sym(
+							SMSM_ENTRY_TYPE_SYM,
+							tmp);
+						if (sym)
+							i += scnprintf(buf + i,
+								       max - i,
+								       "%s ",
+								       sym);
+						else
+							i += scnprintf(buf + i,
+								       max - i,
+								       "%i ",
+								       tmp);
+					}
+					mask <<= 1;
+					tmp++;
+				}
+				if (id_val == DEM_TIME_SYNC_SEND_VALUE)
+					i += scnprintf(buf + i, max - i,
+						       "tick:%x", data2);
+			} else if (id_val == DEM_SMSM_ISR) {
+				unsigned vals[] = {data2, data3};
+				unsigned j;
+				unsigned mask;
+				unsigned tmp;
+				unsigned once;
+				sym = find_sym(SMSM_ENTRY_TYPE_SYM,
+					       data1);
+				if (sym)
+					i += scnprintf(buf + i, max - i,
+						       "%s ", sym);
+				else
+					i += scnprintf(buf + i, max - i,
+						       "%x ", data1);
+
+				for (j = 0; j < ARRAY_SIZE(vals); ++j) {
+					i += scnprintf(buf + i, max - i, "[");
+					mask = 0x80000000;
+					once = 0;
+					while (mask) {
+						tmp = vals[j] & mask;
+						mask >>= 1;
+						if (!tmp)
+							continue;
+						sym = find_sym(SMSM_STATE_SYM,
+							       tmp);
+
+						if (once)
+							i += scnprintf(buf + i,
+								       max - i,
+								       " ");
+						if (sym)
+							i += scnprintf(buf + i,
+								       max - i,
+								       "%s",
+								       sym);
+						else
+							i += scnprintf(buf + i,
+								       max - i,
+								       "0x%x",
+								       tmp);
+						once = 1;
+					}
+					i += scnprintf(buf + i, max - i, "] ");
+				}
+#else
+			} else if (id_val == DEMAPPS_WAKEUP_REASON) {
+				unsigned mask = 0x80000000;
+				unsigned tmp = 0;
+				while (mask) {
+					tmp = data1 & mask;
+					mask >>= 1;
+					if (!tmp)
+						continue;
+					sym = find_sym(WAKEUP_SYM, tmp);
+					if (sym)
+						i += scnprintf(buf + i,
+							       max - i,
+							       "%s ",
+							       sym);
+					else
+						i += scnprintf(buf + i,
+							       max - i,
+							       "%08x ",
+							       tmp);
+				}
+				i += scnprintf(buf + i, max - i,
+					       "%08x %08x", data2, data3);
+			} else if (id_val == DEMMOD_APPS_WAKEUP_INT) {
+				sym = find_sym(WAKEUP_INT_SYM, data1);
+
+				if (sym)
+					i += scnprintf(buf + i, max - i,
+						       "%s %08x %08x",
+						       sym, data2, data3);
+				else
+					i += scnprintf(buf + i, max - i,
+						       "%08x %08x %08x",
+						       data1, data2, data3);
+			} else if (id_val == DEM_NO_SLEEP ||
+				   id_val == NO_SLEEP_NEW) {
+				unsigned vals[] = {data3, data2};
+				unsigned j;
+				unsigned mask;
+				unsigned tmp;
+				unsigned once;
+				i += scnprintf(buf + i, max - i, "%08x ",
+					       data1);
+				i += scnprintf(buf + i, max - i, "[");
+				once = 0;
+				for (j = 0; j < ARRAY_SIZE(vals); ++j) {
+					mask = 0x00000001;
+					while (mask) {
+						tmp = vals[j] & mask;
+						mask <<= 1;
+						if (!tmp)
+							continue;
+						if (j == 0)
+							sym = find_sym(
+								VOTER_D3_SYM,
+								tmp);
+						else
+							sym = find_sym(
+								VOTER_D2_SYM,
+								tmp);
+
+						if (once)
+							i += scnprintf(buf + i,
+								       max - i,
+								       " ");
+						if (sym)
+							i += scnprintf(buf + i,
+								       max - i,
+								       "%s",
+								       sym);
+						else
+							i += scnprintf(buf + i,
+								       max - i,
+								       "%08x",
+								       tmp);
+						once = 1;
+					}
+				}
+				i += scnprintf(buf + i, max - i, "] ");
+#endif
+			} else if (id_val == SMEM_LOG_EVENT_CB) {
+				unsigned vals[] = {data2, data3};
+				unsigned j;
+				unsigned mask;
+				unsigned tmp;
+				unsigned once;
+				i += scnprintf(buf + i, max - i, "%08x ",
+					       data1);
+				for (j = 0; j < ARRAY_SIZE(vals); ++j) {
+					i += scnprintf(buf + i, max - i, "[");
+					mask = 0x80000000;
+					once = 0;
+					while (mask) {
+						tmp = vals[j] & mask;
+						mask >>= 1;
+						if (!tmp)
+							continue;
+						sym = find_sym(SMSM_SYM, tmp);
+
+						if (once)
+							i += scnprintf(buf + i,
+								       max - i,
+								       " ");
+						if (sym)
+							i += scnprintf(buf + i,
+								       max - i,
+								       "%s",
+								       sym);
+						else
+							i += scnprintf(buf + i,
+								       max - i,
+								       "%08x",
+								       tmp);
+						once = 1;
+					}
+					i += scnprintf(buf + i, max - i, "] ");
+				}
+			} else {
+				i += scnprintf(buf + i, max - i,
+					       "%08x %08x %08x",
+					       data1, data2, data3);
+			}
+		}
+	}
+	if (cont) {
+		inst[log].read_idx = idx;
+		read_avail = (write_idx - inst[log].read_idx);
+		if (read_avail < 0)
+			read_avail = inst->num - inst->read_idx + write_idx;
+		inst[log].last_read_avail = read_avail;
+	}
+
+	remote_spin_unlock_irqrestore(inst[log].remote_spinlock, flags);
+
+	DBG("%s: read %d write %d idx %d num %d\n", __func__,
+	    inst[log].read_idx, write_idx, idx, inst[log].num);
+
+	return i;
+}
+
+static int debug_dump(char *buf, int max, uint32_t cont)
+{
+	int r;
+
+	if (!inst[GEN].idx || !inst[GEN].events)
+		return -ENODEV;
+
+	while (cont) {
+		update_read_avail(&inst[GEN]);
+		r = wait_event_interruptible_timeout(inst[GEN].read_wait,
+						     inst[GEN].last_read_avail,
+						     smem_log_timeout_ms *
+						     HZ / 1000);
+		DBG("%s: read available %d\n", __func__,
+		    inst[GEN].last_read_avail);
+		if (r < 0)
+			return 0;
+		else if (inst[GEN].last_read_avail)
+			break;
+	}
+
+	return _debug_dump(GEN, buf, max, cont);
+}
+
+static int debug_dump_sym(char *buf, int max, uint32_t cont)
+{
+	int r;
+
+	if (!inst[GEN].idx || !inst[GEN].events)
+		return -ENODEV;
+
+	while (cont) {
+		update_read_avail(&inst[GEN]);
+		r = wait_event_interruptible_timeout(inst[GEN].read_wait,
+						     inst[GEN].last_read_avail,
+						     smem_log_timeout_ms *
+						     HZ / 1000);
+		DBG("%s: readavailable %d\n", __func__,
+		    inst[GEN].last_read_avail);
+		if (r < 0)
+			return 0;
+		else if (inst[GEN].last_read_avail)
+			break;
+	}
+
+	return _debug_dump_sym(GEN, buf, max, cont);
+}
+
+static int debug_dump_static(char *buf, int max, uint32_t cont)
+{
+	int r;
+
+	if (!inst[STA].idx || !inst[STA].events)
+		return -ENODEV;
+
+	while (cont) {
+		update_read_avail(&inst[STA]);
+		r = wait_event_interruptible_timeout(inst[STA].read_wait,
+						     inst[STA].last_read_avail,
+						     smem_log_timeout_ms *
+						     HZ / 1000);
+		DBG("%s: readavailable %d\n", __func__,
+		    inst[STA].last_read_avail);
+		if (r < 0)
+			return 0;
+		else if (inst[STA].last_read_avail)
+			break;
+	}
+
+	return _debug_dump(STA, buf, max, cont);
+}
+
+static int debug_dump_static_sym(char *buf, int max, uint32_t cont)
+{
+	int r;
+
+	if (!inst[STA].idx || !inst[STA].events)
+		return -ENODEV;
+
+	while (cont) {
+		update_read_avail(&inst[STA]);
+		r = wait_event_interruptible_timeout(inst[STA].read_wait,
+						     inst[STA].last_read_avail,
+						     smem_log_timeout_ms *
+						     HZ / 1000);
+		DBG("%s: readavailable %d\n", __func__,
+		    inst[STA].last_read_avail);
+		if (r < 0)
+			return 0;
+		else if (inst[STA].last_read_avail)
+			break;
+	}
+
+	return _debug_dump_sym(STA, buf, max, cont);
+}
+
+static int debug_dump_power(char *buf, int max, uint32_t cont)
+{
+	int r;
+
+	if (!inst[POW].idx || !inst[POW].events)
+		return -ENODEV;
+
+	while (cont) {
+		update_read_avail(&inst[POW]);
+		r = wait_event_interruptible_timeout(inst[POW].read_wait,
+						     inst[POW].last_read_avail,
+						     smem_log_timeout_ms *
+						     HZ / 1000);
+		DBG("%s: readavailable %d\n", __func__,
+		    inst[POW].last_read_avail);
+		if (r < 0)
+			return 0;
+		else if (inst[POW].last_read_avail)
+			break;
+	}
+
+	return _debug_dump(POW, buf, max, cont);
+}
+
+static int debug_dump_power_sym(char *buf, int max, uint32_t cont)
+{
+	int r;
+
+	if (!inst[POW].idx || !inst[POW].events)
+		return -ENODEV;
+
+	while (cont) {
+		update_read_avail(&inst[POW]);
+		r = wait_event_interruptible_timeout(inst[POW].read_wait,
+						     inst[POW].last_read_avail,
+						     smem_log_timeout_ms *
+						     HZ / 1000);
+		DBG("%s: readavailable %d\n", __func__,
+		    inst[POW].last_read_avail);
+		if (r < 0)
+			return 0;
+		else if (inst[POW].last_read_avail)
+			break;
+	}
+
+	return _debug_dump_sym(POW, buf, max, cont);
+}
+
+static int debug_dump_voters(char *buf, int max, uint32_t cont)
+{
+	return _debug_dump_voters(buf, max);
+}
+
+static char debug_buffer[EVENTS_PRINT_SIZE];
+
+static ssize_t debug_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *ppos)
+{
+	int r;
+	int bsize = 0;
+	int (*fill)(char *, int, uint32_t) = file->private_data;
+	if (!(*ppos)) {
+		bsize = fill(debug_buffer, EVENTS_PRINT_SIZE, 0);
+
+		if (bsize < 0)
+			bsize = scnprintf(debug_buffer,
+				EVENTS_PRINT_SIZE, "Log not available\n");
+	}
+	DBG("%s: count %d ppos %d\n", __func__, count, (unsigned int)*ppos);
+	r =  simple_read_from_buffer(buf, count, ppos, debug_buffer,
+				     bsize);
+	return r;
+}
+
+static ssize_t debug_read_cont(struct file *file, char __user *buf,
+			       size_t count, loff_t *ppos)
+{
+	int (*fill)(char *, int, uint32_t) = file->private_data;
+	char *buffer = kmalloc(count, GFP_KERNEL);
+	int bsize;
+	if (!buffer)
+		return -ENOMEM;
+
+	bsize = fill(buffer, count, 1);
+	if (bsize < 0) {
+		if (*ppos == 0)
+			bsize = scnprintf(buffer, count, "Log not available\n");
+		else
+			bsize = 0;
+	}
+
+	DBG("%s: count %d bsize %d\n", __func__, count, bsize);
+	if (copy_to_user(buf, buffer, bsize)) {
+		kfree(buffer);
+		return -EFAULT;
+	}
+	*ppos += bsize;
+	kfree(buffer);
+	return bsize;
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static const struct file_operations debug_ops = {
+	.read = debug_read,
+	.open = debug_open,
+};
+
+static const struct file_operations debug_ops_cont = {
+	.read = debug_read_cont,
+	.open = debug_open,
+};
+
+static void debug_create(const char *name, mode_t mode,
+			 struct dentry *dent,
+			 int (*fill)(char *buf, int max, uint32_t cont),
+			 const struct file_operations *fops)
+{
+	debugfs_create_file(name, mode, dent, fill, fops);
+}
+
+static void smem_log_debugfs_init(void)
+{
+	struct dentry *dent;
+
+	dent = debugfs_create_dir("smem_log", 0);
+	if (IS_ERR(dent))
+		return;
+
+	debug_create("dump", 0444, dent, debug_dump, &debug_ops);
+	debug_create("dump_sym", 0444, dent, debug_dump_sym, &debug_ops);
+	debug_create("dump_static", 0444, dent, debug_dump_static, &debug_ops);
+	debug_create("dump_static_sym", 0444, dent,
+		     debug_dump_static_sym, &debug_ops);
+	debug_create("dump_power", 0444, dent, debug_dump_power, &debug_ops);
+	debug_create("dump_power_sym", 0444, dent,
+		     debug_dump_power_sym, &debug_ops);
+	debug_create("dump_voters", 0444, dent,
+		     debug_dump_voters, &debug_ops);
+
+	debug_create("dump_cont", 0444, dent, debug_dump, &debug_ops_cont);
+	debug_create("dump_sym_cont", 0444, dent,
+		     debug_dump_sym, &debug_ops_cont);
+	debug_create("dump_static_cont", 0444, dent,
+		     debug_dump_static, &debug_ops_cont);
+	debug_create("dump_static_sym_cont", 0444, dent,
+		     debug_dump_static_sym, &debug_ops_cont);
+	debug_create("dump_power_cont", 0444, dent,
+		     debug_dump_power, &debug_ops_cont);
+	debug_create("dump_power_sym_cont", 0444, dent,
+		     debug_dump_power_sym, &debug_ops_cont);
+
+	smem_log_timeout_ms = 500;
+	smem_log_debug_mask = 0;
+}
+#else
+static void smem_log_debugfs_init(void) {}
+#endif
+
+static int smem_log_initialize(void)
+{
+	int ret;
+
+	ret = _smem_log_init();
+	if (ret < 0) {
+		pr_err("%s: init failed %d\n", __func__, ret);
+		return ret;
+	}
+
+	ret = misc_register(&smem_log_dev);
+	if (ret < 0) {
+		pr_err("%s: device register failed %d\n", __func__, ret);
+		return ret;
+	}
+
+	smem_log_enable = 1;
+	smem_log_initialized = 1;
+	smem_log_debugfs_init();
+	return ret;
+}
+
+static int smsm_driver_state_notifier(struct notifier_block *this,
+				      unsigned long code,
+				      void *_cmd)
+{
+	int ret = 0;
+	if (code & SMSM_INIT) {
+		if (!smem_log_initialized)
+			ret = smem_log_initialize();
+	}
+	return ret;
+}
+
+static struct notifier_block nb = {
+	.notifier_call = smsm_driver_state_notifier,
+};
+
+static int __init smem_log_init(void)
+{
+	return smsm_driver_state_notifier_register(&nb);
+}
+
+
+module_init(smem_log_init);
+
+MODULE_DESCRIPTION("smem log");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
new file mode 100644
index 0000000..b047cf4
--- /dev/null
+++ b/arch/arm/mach-msm/socinfo.c
@@ -0,0 +1,799 @@
+/* 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
+ * 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.
+ *
+ */
+/*
+ * SOC Info Routines
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/sysdev.h>
+#include <asm/mach-types.h>
+#include <mach/socinfo.h>
+
+#include "smd_private.h"
+
+#define BUILD_ID_LENGTH 32
+
+enum {
+	HW_PLATFORM_UNKNOWN = 0,
+	HW_PLATFORM_SURF    = 1,
+	HW_PLATFORM_FFA     = 2,
+	HW_PLATFORM_FLUID   = 3,
+	HW_PLATFORM_SVLTE_FFA	= 4,
+	HW_PLATFORM_SVLTE_SURF	= 5,
+	HW_PLATFORM_MTP  = 8,
+	HW_PLATFORM_LIQUID  = 9,
+	/* Dragonboard platform id is assigned as 10 in CDT */
+	HW_PLATFORM_DRAGON	= 10,
+	HW_PLATFORM_INVALID
+};
+
+const char *hw_platform[] = {
+	[HW_PLATFORM_UNKNOWN] = "Unknown",
+	[HW_PLATFORM_SURF] = "Surf",
+	[HW_PLATFORM_FFA] = "FFA",
+	[HW_PLATFORM_FLUID] = "Fluid",
+	[HW_PLATFORM_SVLTE_FFA] = "SVLTE_FFA",
+	[HW_PLATFORM_SVLTE_SURF] = "SLVTE_SURF",
+	[HW_PLATFORM_MTP] = "MTP",
+	[HW_PLATFORM_LIQUID] = "Liquid",
+	[HW_PLATFORM_DRAGON] = "Dragon"
+};
+
+enum {
+	ACCESSORY_CHIP_UNKNOWN = 0,
+	ACCESSORY_CHIP_CHARM = 58,
+};
+
+enum {
+	PLATFORM_SUBTYPE_UNKNOWN = 0x0,
+	PLATFORM_SUBTYPE_CHARM = 0x1,
+	PLATFORM_SUBTYPE_STRANGE = 0x2,
+	PLATFORM_SUBTYPE_STRANGE_2A = 0x3,
+	PLATFORM_SUBTYPE_INVALID,
+};
+
+const char *hw_platform_subtype[] = {
+	[PLATFORM_SUBTYPE_UNKNOWN] = "Unknown",
+	[PLATFORM_SUBTYPE_CHARM] = "charm",
+	[PLATFORM_SUBTYPE_STRANGE] = "strange",
+	[PLATFORM_SUBTYPE_STRANGE_2A] = "strange_2a,"
+};
+
+/* Used to parse shared memory.  Must match the modem. */
+struct socinfo_v1 {
+	uint32_t format;
+	uint32_t id;
+	uint32_t version;
+	char build_id[BUILD_ID_LENGTH];
+};
+
+struct socinfo_v2 {
+	struct socinfo_v1 v1;
+
+	/* only valid when format==2 */
+	uint32_t raw_id;
+	uint32_t raw_version;
+};
+
+struct socinfo_v3 {
+	struct socinfo_v2 v2;
+
+	/* only valid when format==3 */
+	uint32_t hw_platform;
+};
+
+struct socinfo_v4 {
+	struct socinfo_v3 v3;
+
+	/* only valid when format==4 */
+	uint32_t platform_version;
+};
+
+struct socinfo_v5 {
+	struct socinfo_v4 v4;
+
+	/* only valid when format==5 */
+	uint32_t accessory_chip;
+};
+
+struct socinfo_v6 {
+	struct socinfo_v5 v5;
+
+	/* only valid when format==6 */
+	uint32_t hw_platform_subtype;
+};
+
+static union {
+	struct socinfo_v1 v1;
+	struct socinfo_v2 v2;
+	struct socinfo_v3 v3;
+	struct socinfo_v4 v4;
+	struct socinfo_v5 v5;
+	struct socinfo_v6 v6;
+} *socinfo;
+
+static enum msm_cpu cpu_of_id[] = {
+
+	/* 7x01 IDs */
+	[1]  = MSM_CPU_7X01,
+	[16] = MSM_CPU_7X01,
+	[17] = MSM_CPU_7X01,
+	[18] = MSM_CPU_7X01,
+	[19] = MSM_CPU_7X01,
+	[23] = MSM_CPU_7X01,
+	[25] = MSM_CPU_7X01,
+	[26] = MSM_CPU_7X01,
+	[32] = MSM_CPU_7X01,
+	[33] = MSM_CPU_7X01,
+	[34] = MSM_CPU_7X01,
+	[35] = MSM_CPU_7X01,
+
+	/* 7x25 IDs */
+	[20] = MSM_CPU_7X25,
+	[21] = MSM_CPU_7X25, /* 7225 */
+	[24] = MSM_CPU_7X25, /* 7525 */
+	[27] = MSM_CPU_7X25, /* 7625 */
+	[39] = MSM_CPU_7X25,
+	[40] = MSM_CPU_7X25,
+	[41] = MSM_CPU_7X25,
+	[42] = MSM_CPU_7X25,
+	[62] = MSM_CPU_7X25, /* 7625-1 */
+	[63] = MSM_CPU_7X25, /* 7225-1 */
+	[66] = MSM_CPU_7X25, /* 7225-2 */
+
+
+	/* 7x27 IDs */
+	[43] = MSM_CPU_7X27,
+	[44] = MSM_CPU_7X27,
+	[61] = MSM_CPU_7X27,
+	[67] = MSM_CPU_7X27, /* 7227-1 */
+	[68] = MSM_CPU_7X27, /* 7627-1 */
+	[69] = MSM_CPU_7X27, /* 7627-2 */
+
+
+	/* 8x50 IDs */
+	[30] = MSM_CPU_8X50,
+	[36] = MSM_CPU_8X50,
+	[37] = MSM_CPU_8X50,
+	[38] = MSM_CPU_8X50,
+
+	/* 7x30 IDs */
+	[59] = MSM_CPU_7X30,
+	[60] = MSM_CPU_7X30,
+
+	/* 8x55 IDs */
+	[74] = MSM_CPU_8X55,
+	[75] = MSM_CPU_8X55,
+	[85] = MSM_CPU_8X55,
+
+	/* 8x60 IDs */
+	[70] = MSM_CPU_8X60,
+	[71] = MSM_CPU_8X60,
+	[86] = MSM_CPU_8X60,
+
+	/* 8960 IDs */
+	[87] = MSM_CPU_8960,
+
+	/* 7x25A IDs */
+	[88] = MSM_CPU_7X25A,
+	[89] = MSM_CPU_7X25A,
+	[96] = MSM_CPU_7X25A,
+
+	/* 7x27A IDs */
+	[90] = MSM_CPU_7X27A,
+	[91] = MSM_CPU_7X27A,
+	[92] = MSM_CPU_7X27A,
+	[97] = MSM_CPU_7X27A,
+
+	/* FSM9xxx ID */
+	[94] = FSM_CPU_9XXX,
+	[95] = FSM_CPU_9XXX,
+
+	/*  7x25AA ID */
+	[98] = MSM_CPU_7X25AA,
+	[99] = MSM_CPU_7X25AA,
+	[100] = MSM_CPU_7X25AA,
+
+	/*  7x27AA ID */
+	[101] = MSM_CPU_7X27AA,
+	[102] = MSM_CPU_7X27AA,
+	[103] = MSM_CPU_7X27AA,
+
+	/* 9x15 ID */
+	[104] = MSM_CPU_9615,
+	[105] = MSM_CPU_9615,
+	[106] = MSM_CPU_9615,
+	[107] = MSM_CPU_9615,
+
+	/* 8064 IDs */
+	[109] = MSM_CPU_8064,
+
+	/* 8930 IDs */
+	[116] = MSM_CPU_8930,
+	[117] = MSM_CPU_8930,
+	[118] = MSM_CPU_8930,
+	[119] = MSM_CPU_8930,
+
+	/* 8627 IDs */
+	[120] = MSM_CPU_8627,
+	[121] = MSM_CPU_8627,
+
+	/* 8660A ID */
+	[122] = MSM_CPU_8960,
+
+	/* 8260A ID */
+	[123] = MSM_CPU_8960,
+
+	/* 8060A ID */
+	[124] = MSM_CPU_8960,
+
+	/* Copper IDs */
+	[126] = MSM_CPU_COPPER,
+
+	/* 8625 IDs */
+	[127] = MSM_CPU_8625,
+	[128] = MSM_CPU_8625,
+	[129] = MSM_CPU_8625,
+
+	/* 8064 MPQ ID */
+	[130] = MSM_CPU_8064,
+
+	/* 7x25AB IDs */
+	[131] = MSM_CPU_7X25AB,
+	[132] = MSM_CPU_7X25AB,
+	[133] = MSM_CPU_7X25AB,
+
+	/* 9625 IDs */
+	[134] = MSM_CPU_9625,
+
+	/* Uninitialized IDs are not known to run Linux.
+	   MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
+	   considered as unknown CPU. */
+};
+
+static enum msm_cpu cur_cpu;
+
+static struct socinfo_v1 dummy_socinfo = {
+	.format = 1,
+	.version = 1,
+};
+
+uint32_t socinfo_get_id(void)
+{
+	return (socinfo) ? socinfo->v1.id : 0;
+}
+EXPORT_SYMBOL_GPL(socinfo_get_id);
+
+uint32_t socinfo_get_version(void)
+{
+	return (socinfo) ? socinfo->v1.version : 0;
+}
+
+char *socinfo_get_build_id(void)
+{
+	return (socinfo) ? socinfo->v1.build_id : NULL;
+}
+
+uint32_t socinfo_get_raw_id(void)
+{
+	return socinfo ?
+		(socinfo->v1.format >= 2 ? socinfo->v2.raw_id : 0)
+		: 0;
+}
+
+uint32_t socinfo_get_raw_version(void)
+{
+	return socinfo ?
+		(socinfo->v1.format >= 2 ? socinfo->v2.raw_version : 0)
+		: 0;
+}
+
+uint32_t socinfo_get_platform_type(void)
+{
+	return socinfo ?
+		(socinfo->v1.format >= 3 ? socinfo->v3.hw_platform : 0)
+		: 0;
+}
+
+
+uint32_t socinfo_get_platform_version(void)
+{
+	return socinfo ?
+		(socinfo->v1.format >= 4 ? socinfo->v4.platform_version : 0)
+		: 0;
+}
+
+/* This information is directly encoded by the machine id */
+/* Thus no external callers rely on this information at the moment */
+static uint32_t socinfo_get_accessory_chip(void)
+{
+	return socinfo ?
+		(socinfo->v1.format >= 5 ? socinfo->v5.accessory_chip : 0)
+		: 0;
+}
+
+uint32_t socinfo_get_platform_subtype(void)
+{
+	return socinfo ?
+		(socinfo->v1.format >= 6 ? socinfo->v6.hw_platform_subtype : 0)
+		: 0;
+}
+
+enum msm_cpu socinfo_get_msm_cpu(void)
+{
+	return cur_cpu;
+}
+EXPORT_SYMBOL_GPL(socinfo_get_msm_cpu);
+
+static ssize_t
+socinfo_show_id(struct sys_device *dev,
+		struct sysdev_attribute *attr,
+		char *buf)
+{
+	if (!socinfo) {
+		pr_err("%s: No socinfo found!\n", __func__);
+		return 0;
+	}
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", socinfo_get_id());
+}
+
+static ssize_t
+socinfo_show_version(struct sys_device *dev,
+		     struct sysdev_attribute *attr,
+		     char *buf)
+{
+	uint32_t version;
+
+	if (!socinfo) {
+		pr_err("%s: No socinfo found!\n", __func__);
+		return 0;
+	}
+
+	version = socinfo_get_version();
+	return snprintf(buf, PAGE_SIZE, "%u.%u\n",
+			SOCINFO_VERSION_MAJOR(version),
+			SOCINFO_VERSION_MINOR(version));
+}
+
+static ssize_t
+socinfo_show_build_id(struct sys_device *dev,
+		      struct sysdev_attribute *attr,
+		      char *buf)
+{
+	if (!socinfo) {
+		pr_err("%s: No socinfo found!\n", __func__);
+		return 0;
+	}
+
+	return snprintf(buf, PAGE_SIZE, "%-.32s\n", socinfo_get_build_id());
+}
+
+static ssize_t
+socinfo_show_raw_id(struct sys_device *dev,
+		    struct sysdev_attribute *attr,
+		    char *buf)
+{
+	if (!socinfo) {
+		pr_err("%s: No socinfo found!\n", __func__);
+		return 0;
+	}
+	if (socinfo->v1.format < 2) {
+		pr_err("%s: Raw ID not available!\n", __func__);
+		return 0;
+	}
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", socinfo_get_raw_id());
+}
+
+static ssize_t
+socinfo_show_raw_version(struct sys_device *dev,
+			 struct sysdev_attribute *attr,
+			 char *buf)
+{
+	if (!socinfo) {
+		pr_err("%s: No socinfo found!\n", __func__);
+		return 0;
+	}
+	if (socinfo->v1.format < 2) {
+		pr_err("%s: Raw version not available!\n", __func__);
+		return 0;
+	}
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", socinfo_get_raw_version());
+}
+
+static ssize_t
+socinfo_show_platform_type(struct sys_device *dev,
+			 struct sysdev_attribute *attr,
+			 char *buf)
+{
+	uint32_t hw_type;
+
+	if (!socinfo) {
+		pr_err("%s: No socinfo found!\n", __func__);
+		return 0;
+	}
+	if (socinfo->v1.format < 3) {
+		pr_err("%s: platform type not available!\n", __func__);
+		return 0;
+	}
+
+	hw_type = socinfo_get_platform_type();
+	if (hw_type >= HW_PLATFORM_INVALID) {
+		pr_err("%s: Invalid hardware platform type found\n",
+								   __func__);
+		hw_type = HW_PLATFORM_UNKNOWN;
+	}
+
+	return snprintf(buf, PAGE_SIZE, "%-.32s\n", hw_platform[hw_type]);
+}
+
+static ssize_t
+socinfo_show_platform_version(struct sys_device *dev,
+			 struct sysdev_attribute *attr,
+			 char *buf)
+{
+
+	if (!socinfo) {
+		pr_err("%s: No socinfo found!\n", __func__);
+		return 0;
+	}
+	if (socinfo->v1.format < 4) {
+		pr_err("%s: platform version not available!\n", __func__);
+		return 0;
+	}
+
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+		socinfo_get_platform_version());
+}
+
+static ssize_t
+socinfo_show_accessory_chip(struct sys_device *dev,
+			struct sysdev_attribute *attr,
+			char *buf)
+{
+	if (!socinfo) {
+		pr_err("%s: No socinfo found!\n", __func__);
+		return 0;
+	}
+	if (socinfo->v1.format < 5) {
+		pr_err("%s: accessory chip not available!\n", __func__);
+		return 0;
+	}
+
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+		socinfo_get_accessory_chip());
+}
+
+static ssize_t
+socinfo_show_platform_subtype(struct sys_device *dev,
+			struct sysdev_attribute *attr,
+			char *buf)
+{
+	uint32_t hw_subtype;
+	if (!socinfo) {
+		pr_err("%s: No socinfo found!\n", __func__);
+		return 0;
+	}
+	if (socinfo->v1.format < 6) {
+		pr_err("%s: platform subtype not available!\n", __func__);
+		return 0;
+	}
+
+	hw_subtype = socinfo_get_platform_subtype();
+	if (hw_subtype >= PLATFORM_SUBTYPE_INVALID) {
+		pr_err("%s: Invalid hardware platform sub type found\n",
+								   __func__);
+		hw_subtype = PLATFORM_SUBTYPE_UNKNOWN;
+	}
+	return snprintf(buf, PAGE_SIZE, "%-.32s\n",
+		hw_platform_subtype[hw_subtype]);
+}
+
+static struct sysdev_attribute socinfo_v1_files[] = {
+	_SYSDEV_ATTR(id, 0444, socinfo_show_id, NULL),
+	_SYSDEV_ATTR(version, 0444, socinfo_show_version, NULL),
+	_SYSDEV_ATTR(build_id, 0444, socinfo_show_build_id, NULL),
+};
+
+static struct sysdev_attribute socinfo_v2_files[] = {
+	_SYSDEV_ATTR(raw_id, 0444, socinfo_show_raw_id, NULL),
+	_SYSDEV_ATTR(raw_version, 0444, socinfo_show_raw_version, NULL),
+};
+
+static struct sysdev_attribute socinfo_v3_files[] = {
+	_SYSDEV_ATTR(hw_platform, 0444, socinfo_show_platform_type, NULL),
+};
+
+static struct sysdev_attribute socinfo_v4_files[] = {
+	_SYSDEV_ATTR(platform_version, 0444,
+			socinfo_show_platform_version, NULL),
+};
+
+static struct sysdev_attribute socinfo_v5_files[] = {
+	_SYSDEV_ATTR(accessory_chip, 0444,
+			socinfo_show_accessory_chip, NULL),
+};
+
+static struct sysdev_attribute socinfo_v6_files[] = {
+	_SYSDEV_ATTR(platform_subtype, 0444,
+			socinfo_show_platform_subtype, NULL),
+};
+
+static struct sysdev_class soc_sysdev_class = {
+	.name = "soc",
+};
+
+static struct sys_device soc_sys_device = {
+	.id = 0,
+	.cls = &soc_sysdev_class,
+};
+
+static int __init socinfo_create_files(struct sys_device *dev,
+					struct sysdev_attribute files[],
+					int size)
+{
+	int i;
+	for (i = 0; i < size; i++) {
+		int err = sysdev_create_file(dev, &files[i]);
+		if (err) {
+			pr_err("%s: sysdev_create_file(%s)=%d\n",
+			       __func__, files[i].attr.name, err);
+			return err;
+		}
+	}
+	return 0;
+}
+
+static int __init socinfo_init_sysdev(void)
+{
+	int err;
+
+	if (!socinfo) {
+		pr_err("%s: No socinfo found!\n", __func__);
+		return -ENODEV;
+	}
+
+	err = sysdev_class_register(&soc_sysdev_class);
+	if (err) {
+		pr_err("%s: sysdev_class_register fail (%d)\n",
+		       __func__, err);
+		return err;
+	}
+	err = sysdev_register(&soc_sys_device);
+	if (err) {
+		pr_err("%s: sysdev_register fail (%d)\n",
+		       __func__, err);
+		return err;
+	}
+	socinfo_create_files(&soc_sys_device, socinfo_v1_files,
+				ARRAY_SIZE(socinfo_v1_files));
+	if (socinfo->v1.format < 2)
+		return err;
+	socinfo_create_files(&soc_sys_device, socinfo_v2_files,
+				ARRAY_SIZE(socinfo_v2_files));
+
+	if (socinfo->v1.format < 3)
+		return err;
+
+	socinfo_create_files(&soc_sys_device, socinfo_v3_files,
+				ARRAY_SIZE(socinfo_v3_files));
+
+	if (socinfo->v1.format < 4)
+		return err;
+
+	socinfo_create_files(&soc_sys_device, socinfo_v4_files,
+				ARRAY_SIZE(socinfo_v4_files));
+
+	if (socinfo->v1.format < 5)
+		return err;
+
+	socinfo_create_files(&soc_sys_device, socinfo_v5_files,
+				ARRAY_SIZE(socinfo_v5_files));
+
+	if (socinfo->v1.format < 6)
+		return err;
+
+	return socinfo_create_files(&soc_sys_device, socinfo_v6_files,
+				ARRAY_SIZE(socinfo_v6_files));
+
+}
+
+arch_initcall(socinfo_init_sysdev);
+
+static void * __init setup_dummy_socinfo(void)
+{
+	if (machine_is_msm8960_rumi3() || machine_is_msm8960_sim() ||
+	    machine_is_msm8960_cdp())
+		dummy_socinfo.id = 87;
+	else if (machine_is_apq8064_rumi3() || machine_is_apq8064_sim())
+		dummy_socinfo.id = 109;
+	else if (machine_is_msm9615_mtp() || machine_is_msm9615_cdp())
+		dummy_socinfo.id = 104;
+	else if (early_machine_is_copper()) {
+		dummy_socinfo.id = 126;
+		strlcpy(dummy_socinfo.build_id, "copper - ",
+			sizeof(dummy_socinfo.build_id));
+	} else if (early_machine_is_msm9625()) {
+		dummy_socinfo.id = 134;
+		strlcpy(dummy_socinfo.build_id, "msm9625 - ",
+			sizeof(dummy_socinfo.build_id));
+	} else if (machine_is_msm8625_rumi3())
+		dummy_socinfo.id = 127;
+	strlcat(dummy_socinfo.build_id, "Dummy socinfo",
+		sizeof(dummy_socinfo.build_id));
+	return (void *) &dummy_socinfo;
+}
+
+int __init socinfo_init(void)
+{
+	socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID, sizeof(struct socinfo_v6));
+
+	if (!socinfo)
+		socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
+				sizeof(struct socinfo_v5));
+
+	if (!socinfo)
+		socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
+				sizeof(struct socinfo_v4));
+
+	if (!socinfo)
+		socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
+				sizeof(struct socinfo_v3));
+
+	if (!socinfo)
+		socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
+				sizeof(struct socinfo_v2));
+
+	if (!socinfo)
+		socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
+				sizeof(struct socinfo_v1));
+
+	if (!socinfo) {
+		pr_warn("%s: Can't find SMEM_HW_SW_BUILD_ID; falling back on "
+			"dummy values.\n", __func__);
+		socinfo = setup_dummy_socinfo();
+	}
+
+	WARN(!socinfo_get_id(), "Unknown SOC ID!\n");
+	WARN(socinfo_get_id() >= ARRAY_SIZE(cpu_of_id),
+		"New IDs added! ID => CPU mapping might need an update.\n");
+
+	if (socinfo->v1.id < ARRAY_SIZE(cpu_of_id))
+		cur_cpu = cpu_of_id[socinfo->v1.id];
+
+	switch (socinfo->v1.format) {
+	case 1:
+		pr_info("%s: v%u, id=%u, ver=%u.%u\n",
+			__func__, socinfo->v1.format, socinfo->v1.id,
+			SOCINFO_VERSION_MAJOR(socinfo->v1.version),
+			SOCINFO_VERSION_MINOR(socinfo->v1.version));
+		break;
+	case 2:
+		pr_info("%s: v%u, id=%u, ver=%u.%u, "
+			 "raw_id=%u, raw_ver=%u\n",
+			__func__, socinfo->v1.format, socinfo->v1.id,
+			SOCINFO_VERSION_MAJOR(socinfo->v1.version),
+			SOCINFO_VERSION_MINOR(socinfo->v1.version),
+			socinfo->v2.raw_id, socinfo->v2.raw_version);
+		break;
+	case 3:
+		pr_info("%s: v%u, id=%u, ver=%u.%u, "
+			 "raw_id=%u, raw_ver=%u, hw_plat=%u\n",
+			__func__, socinfo->v1.format, socinfo->v1.id,
+			SOCINFO_VERSION_MAJOR(socinfo->v1.version),
+			SOCINFO_VERSION_MINOR(socinfo->v1.version),
+			socinfo->v2.raw_id, socinfo->v2.raw_version,
+			socinfo->v3.hw_platform);
+		break;
+	case 4:
+		pr_info("%s: v%u, id=%u, ver=%u.%u, "
+			 "raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u\n",
+			__func__, socinfo->v1.format, socinfo->v1.id,
+			SOCINFO_VERSION_MAJOR(socinfo->v1.version),
+			SOCINFO_VERSION_MINOR(socinfo->v1.version),
+			socinfo->v2.raw_id, socinfo->v2.raw_version,
+			socinfo->v3.hw_platform, socinfo->v4.platform_version);
+		break;
+	case 5:
+		pr_info("%s: v%u, id=%u, ver=%u.%u, "
+			 "raw_id=%u, raw_ver=%u, hw_plat=%u,  hw_plat_ver=%u\n"
+			" accessory_chip=%u\n", __func__, socinfo->v1.format,
+			socinfo->v1.id,
+			SOCINFO_VERSION_MAJOR(socinfo->v1.version),
+			SOCINFO_VERSION_MINOR(socinfo->v1.version),
+			socinfo->v2.raw_id, socinfo->v2.raw_version,
+			socinfo->v3.hw_platform, socinfo->v4.platform_version,
+			socinfo->v5.accessory_chip);
+		break;
+	case 6:
+		pr_info("%s: v%u, id=%u, ver=%u.%u, "
+			 "raw_id=%u, raw_ver=%u, hw_plat=%u,  hw_plat_ver=%u\n"
+			" accessory_chip=%u hw_plat_subtype=%u\n", __func__,
+			socinfo->v1.format,
+			socinfo->v1.id,
+			SOCINFO_VERSION_MAJOR(socinfo->v1.version),
+			SOCINFO_VERSION_MINOR(socinfo->v1.version),
+			socinfo->v2.raw_id, socinfo->v2.raw_version,
+			socinfo->v3.hw_platform, socinfo->v4.platform_version,
+			socinfo->v5.accessory_chip,
+			socinfo->v6.hw_platform_subtype);
+		break;
+	default:
+		pr_err("%s: Unknown format found\n", __func__);
+		break;
+	}
+
+	return 0;
+}
+
+const int get_core_count(void)
+{
+	if (!(read_cpuid_mpidr() & BIT(31)))
+		return 1;
+
+	if (read_cpuid_mpidr() & BIT(30) &&
+		!machine_is_msm8960_sim() &&
+		!machine_is_apq8064_sim())
+		return 1;
+
+	/* 1 + the PART[1:0] field of MIDR */
+	return ((read_cpuid_id() >> 4) & 3) + 1;
+}
+
+const int read_msm_cpu_type(void)
+{
+	if (machine_is_msm8960_sim() || machine_is_msm8960_rumi3())
+		return MSM_CPU_8960;
+
+	if (socinfo_get_msm_cpu() != MSM_CPU_UNKNOWN)
+		return socinfo_get_msm_cpu();
+
+	switch (read_cpuid_id()) {
+	case 0x510F02D0:
+	case 0x510F02D2:
+	case 0x510F02D4:
+		return MSM_CPU_8X60;
+
+	case 0x510F04D0:
+	case 0x510F04D1:
+	case 0x510F04D2:
+	case 0x511F04D0:
+	case 0x512F04D0:
+		return MSM_CPU_8960;
+
+	case 0x51404D11: /* We can't get here unless we are in bringup */
+		return MSM_CPU_8930;
+
+	case 0x510F06F0:
+		return MSM_CPU_8064;
+
+	default:
+		return MSM_CPU_UNKNOWN;
+	};
+}
+
+const int cpu_is_krait_v1(void)
+{
+	switch (read_cpuid_id()) {
+	case 0x510F04D0:
+	case 0x510F04D1:
+	case 0x510F04D2:
+		return 1;
+
+	default:
+		return 0;
+	};
+}
diff --git a/arch/arm/mach-msm/spm-v2.c b/arch/arm/mach-msm/spm-v2.c
new file mode 100644
index 0000000..b6d5324
--- /dev/null
+++ b/arch/arm/mach-msm/spm-v2.c
@@ -0,0 +1,467 @@
+/* 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
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <mach/msm_iomap.h>
+
+#include "spm_driver.h"
+
+#define MSM_SPM_PMIC_STATE_IDLE  0
+
+#define SAW2_V1_VER_REG 0x04
+#define SAW2_V2_VER_REG 0xfd0
+
+#define SAW2_MAJOR_2 2
+
+
+enum {
+	MSM_SPM_DEBUG_SHADOW = 1U << 0,
+	MSM_SPM_DEBUG_VCTL = 1U << 1,
+};
+
+static int msm_spm_debug_mask;
+module_param_named(
+	debug_mask, msm_spm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
+);
+
+
+static uint32_t msm_spm_reg_offsets_v1[MSM_SPM_REG_NR] = {
+	[MSM_SPM_REG_SAW2_SECURE]		= 0x00,
+	[MSM_SPM_REG_SAW2_ID]			= 0x04,
+	[MSM_SPM_REG_SAW2_CFG]			= 0x08,
+	[MSM_SPM_REG_SAW2_STS0]			= 0x0C,
+	[MSM_SPM_REG_SAW2_STS1]			= 0x10,
+	[MSM_SPM_REG_SAW2_VCTL]			= 0x14,
+	[MSM_SPM_REG_SAW2_AVS_CTL]		= 0x18,
+	[MSM_SPM_REG_SAW2_AVS_HYSTERESIS]	= 0x1C,
+	[MSM_SPM_REG_SAW2_SPM_CTL]		= 0x20,
+	[MSM_SPM_REG_SAW2_PMIC_DLY]		= 0x24,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_0]		= 0x28,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_1]		= 0x2C,
+	[MSM_SPM_REG_SAW2_RST]			= 0x30,
+	[MSM_SPM_REG_SAW2_SEQ_ENTRY]		= 0x80,
+};
+
+static uint32_t msm_spm_reg_offsets_v2[MSM_SPM_REG_NR] = {
+	[MSM_SPM_REG_SAW2_SECURE]		= 0x00,
+	[MSM_SPM_REG_SAW2_ID]			= 0x04,
+	[MSM_SPM_REG_SAW2_CFG]			= 0x08,
+	[MSM_SPM_REG_SAW2_SPM_STS]		= 0x0C,
+	[MSM_SPM_REG_SAW2_AVS_STS]		= 0x10,
+	[MSM_SPM_REG_SAW2_PMIC_STS]		= 0x14,
+	[MSM_SPM_REG_SAW2_RST]			= 0x18,
+	[MSM_SPM_REG_SAW2_VCTL]			= 0x1C,
+	[MSM_SPM_REG_SAW2_AVS_CTL]		= 0x20,
+	[MSM_SPM_REG_SAW2_AVS_LIMIT]		= 0x24,
+	[MSM_SPM_REG_SAW2_AVS_DLY]		= 0x28,
+	[MSM_SPM_REG_SAW2_AVS_HYSTERESIS]	= 0x2C,
+	[MSM_SPM_REG_SAW2_SPM_CTL]		= 0x30,
+	[MSM_SPM_REG_SAW2_SPM_DLY]		= 0x34,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_0]		= 0x40,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_1]		= 0x44,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_2]		= 0x48,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_3]		= 0x4C,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_4]		= 0x50,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_5]		= 0x54,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_6]		= 0x58,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_7]		= 0x5C,
+	[MSM_SPM_REG_SAW2_SEQ_ENTRY]		= 0x80,
+	[MSM_SPM_REG_SAW2_VERSION]		= 0xFD0,
+};
+
+/******************************************************************************
+ * Internal helper functions
+ *****************************************************************************/
+
+static inline uint32_t msm_spm_drv_get_num_spm_entry(
+		struct msm_spm_driver_data *dev)
+{
+	return 32;
+}
+
+static void msm_spm_drv_flush_shadow(struct msm_spm_driver_data *dev,
+		unsigned int reg_index)
+{
+	__raw_writel(dev->reg_shadow[reg_index],
+		dev->reg_base_addr + dev->reg_offsets[reg_index]);
+}
+
+static void msm_spm_drv_load_shadow(struct msm_spm_driver_data *dev,
+		unsigned int reg_index)
+{
+	dev->reg_shadow[reg_index] =
+		__raw_readl(dev->reg_base_addr +
+				dev->reg_offsets[reg_index]);
+}
+
+static inline void msm_spm_drv_set_start_addr(
+		struct msm_spm_driver_data *dev, uint32_t addr)
+{
+	addr &= 0x7F;
+	addr <<= 4;
+	dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] &= 0xFFFFF80F;
+	dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] |= addr;
+}
+
+static inline bool msm_spm_pmic_arb_present(struct msm_spm_driver_data *dev)
+{
+	msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_ID);
+
+	if (dev->major == SAW2_MAJOR_2)
+		return (dev->reg_shadow[MSM_SPM_REG_SAW2_ID] >> 2) & 0x1;
+	else
+		return (dev->reg_shadow[MSM_SPM_REG_SAW2_ID] >> 18) & 0x1;
+}
+
+static inline void msm_spm_drv_set_vctl(struct msm_spm_driver_data *dev,
+		uint32_t vlevel)
+{
+	dev->reg_shadow[MSM_SPM_REG_SAW2_VCTL] &= ~0xFF;
+	dev->reg_shadow[MSM_SPM_REG_SAW2_VCTL] |= vlevel;
+
+	dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_0] &= ~0xFF;
+	dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_0] |= vlevel;
+
+	dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_1] &= ~0x3F;
+	dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_1] |= (vlevel & 0x3F);
+}
+
+static inline void msm_spm_drv_set_vctl2(struct msm_spm_driver_data *dev,
+		uint32_t vlevel)
+{
+	unsigned int pmic_data = 0;
+
+	pmic_data |= vlevel;
+	pmic_data |= (dev->vctl_port & 0x7) << 16;
+
+	dev->reg_shadow[MSM_SPM_REG_SAW2_VCTL] &= ~0x700FF;
+	dev->reg_shadow[MSM_SPM_REG_SAW2_VCTL] |= pmic_data;
+
+	dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_0] &= ~0x700FF;
+	dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_0] |= pmic_data;
+}
+
+static inline void msm_spm_drv_apcs_set_vctl(struct msm_spm_driver_data *dev,
+		unsigned int vlevel)
+{
+	if (dev->major == SAW2_MAJOR_2)
+		return msm_spm_drv_set_vctl2(dev, vlevel);
+	else
+		return msm_spm_drv_set_vctl(dev, vlevel);
+}
+
+static inline uint32_t msm_spm_drv_get_sts_pmic_state(
+		struct msm_spm_driver_data *dev)
+{
+	if (dev->major == SAW2_MAJOR_2) {
+		msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_PMIC_STS);
+		return (dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_STS] >> 16) &
+				0x03;
+	} else {
+		msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_STS0);
+		return (dev->reg_shadow[MSM_SPM_REG_SAW2_STS0] >> 10) & 0x03;
+	}
+}
+
+static inline uint32_t msm_spm_drv_get_sts_curr_pmic_data(
+		struct msm_spm_driver_data *dev)
+{
+	if (dev->major == SAW2_MAJOR_2) {
+		msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_PMIC_STS);
+		return dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_STS] & 0xFF;
+	} else {
+		msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_STS1);
+		return dev->reg_shadow[MSM_SPM_REG_SAW2_STS1] & 0xFF;
+	}
+}
+
+static inline uint32_t msm_spm_drv_get_saw2_ver(struct msm_spm_driver_data *dev,
+		uint32_t *major, uint32_t *minor)
+{
+	int ret = -ENODEV;
+	uint32_t val = 0;
+
+	msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_VERSION);
+	val = dev->reg_shadow[MSM_SPM_REG_SAW2_VERSION];
+
+	if (dev->ver_reg == SAW2_V2_VER_REG) {
+		*major = (val >> 28) & 0xF;
+		*minor = (val >> 16) & 0xFFF;
+		ret = 0;
+	} else if (dev->ver_reg == SAW2_V1_VER_REG) {
+		*major = (val >> 4) & 0xF;
+		*minor = val & 0xF;
+		ret = 0;
+	}
+
+	return ret;
+}
+
+/******************************************************************************
+ * Public functions
+ *****************************************************************************/
+
+inline int msm_spm_drv_set_spm_enable(
+		struct msm_spm_driver_data *dev, bool enable)
+{
+	uint32_t value = enable ? 0x01 : 0x00;
+
+	if (!dev)
+		return -EINVAL;
+
+	if ((dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] & 0x01) ^ value) {
+
+		dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] &= ~0x1;
+		dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] |= value;
+
+		msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_SPM_CTL);
+		wmb();
+	}
+	return 0;
+}
+void msm_spm_drv_flush_seq_entry(struct msm_spm_driver_data *dev)
+{
+	int i;
+	int num_spm_entry = msm_spm_drv_get_num_spm_entry(dev);
+
+	if (!dev) {
+		__WARN();
+		return;
+	}
+
+	for (i = 0; i < num_spm_entry; i++) {
+		__raw_writel(dev->reg_seq_entry_shadow[i],
+			dev->reg_base_addr
+			+ dev->reg_offsets[MSM_SPM_REG_SAW2_SEQ_ENTRY]
+			+ 4 * i);
+	}
+	mb();
+}
+
+int msm_spm_drv_write_seq_data(struct msm_spm_driver_data *dev,
+		uint8_t *cmd, uint32_t *offset)
+{
+	uint32_t cmd_w;
+	uint32_t offset_w = *offset / 4;
+	uint8_t last_cmd;
+
+	if (!cmd)
+		return -EINVAL;
+
+	while (1) {
+		int i;
+		cmd_w = 0;
+		last_cmd = 0;
+		cmd_w = dev->reg_seq_entry_shadow[offset_w];
+
+		for (i = (*offset % 4) ; i < 4; i++) {
+			last_cmd = *(cmd++);
+			cmd_w |=  last_cmd << (i * 8);
+			(*offset)++;
+			if (last_cmd == 0x0f)
+				break;
+		}
+
+		dev->reg_seq_entry_shadow[offset_w++] = cmd_w;
+		if (last_cmd == 0x0f)
+			break;
+	}
+
+	return 0;
+}
+
+int msm_spm_drv_set_low_power_mode(struct msm_spm_driver_data *dev,
+		uint32_t addr)
+{
+
+	/* SPM is configured to reset start address to zero after end of Program
+	 */
+	if (!dev)
+		return -EINVAL;
+
+	msm_spm_drv_set_start_addr(dev, addr);
+
+	msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_SPM_CTL);
+	wmb();
+
+	if (msm_spm_debug_mask & MSM_SPM_DEBUG_SHADOW) {
+		int i;
+		for (i = 0; i < MSM_SPM_REG_NR; i++)
+			pr_info("%s: reg %02x = 0x%08x\n", __func__,
+				dev->reg_offsets[i], dev->reg_shadow[i]);
+	}
+
+	return 0;
+}
+
+int msm_spm_drv_set_vdd(struct msm_spm_driver_data *dev, unsigned int vlevel)
+{
+	uint32_t timeout_us;
+
+	if (!dev)
+		return -EINVAL;
+
+	if (!msm_spm_pmic_arb_present(dev))
+		return -ENOSYS;
+
+	if (msm_spm_debug_mask & MSM_SPM_DEBUG_VCTL)
+		pr_info("%s: requesting vlevel 0x%x\n",
+			__func__, vlevel);
+
+	msm_spm_drv_apcs_set_vctl(dev, vlevel);
+	msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_VCTL);
+	msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_PMIC_DATA_0);
+	msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_PMIC_DATA_1);
+	mb();
+
+	/* Wait for PMIC state to return to idle or until timeout */
+	timeout_us = dev->vctl_timeout_us;
+	while (msm_spm_drv_get_sts_pmic_state(dev) != MSM_SPM_PMIC_STATE_IDLE) {
+		if (!timeout_us)
+			goto set_vdd_bail;
+
+		if (timeout_us > 10) {
+			udelay(10);
+			timeout_us -= 10;
+		} else {
+			udelay(timeout_us);
+			timeout_us = 0;
+		}
+	}
+
+	if (msm_spm_drv_get_sts_curr_pmic_data(dev) != vlevel)
+		goto set_vdd_bail;
+
+	if (msm_spm_debug_mask & MSM_SPM_DEBUG_VCTL)
+		pr_info("%s: done, remaining timeout %uus\n",
+			__func__, timeout_us);
+
+	return 0;
+
+set_vdd_bail:
+	pr_err("%s: failed, remaining timeout %uus, vlevel 0x%x\n",
+	       __func__, timeout_us, msm_spm_drv_get_sts_curr_pmic_data(dev));
+	return -EIO;
+}
+
+int msm_spm_drv_set_phase(struct msm_spm_driver_data *dev,
+		unsigned int phase_cnt)
+{
+	unsigned int pmic_data = 0;
+	unsigned int timeout_us = 0;
+
+	if (dev->major != SAW2_MAJOR_2)
+		return -ENODEV;
+
+	pmic_data |= phase_cnt & 0xFF;
+	pmic_data |= (dev->phase_port & 0x7) << 16;
+
+	dev->reg_shadow[MSM_SPM_REG_SAW2_VCTL] &= ~0x700FF;
+	dev->reg_shadow[MSM_SPM_REG_SAW2_VCTL] |= pmic_data;
+	msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_VCTL);
+	mb();
+
+	/* Wait for PMIC state to return to idle or until timeout */
+	timeout_us = dev->vctl_timeout_us;
+	while (msm_spm_drv_get_sts_pmic_state(dev) != MSM_SPM_PMIC_STATE_IDLE) {
+		if (!timeout_us)
+			goto set_phase_bail;
+
+		if (timeout_us > 10) {
+			udelay(10);
+			timeout_us -= 10;
+		} else {
+			udelay(timeout_us);
+			timeout_us = 0;
+		}
+	}
+
+	if (msm_spm_drv_get_sts_curr_pmic_data(dev) != phase_cnt)
+		goto set_phase_bail;
+
+	if (msm_spm_debug_mask & MSM_SPM_DEBUG_VCTL)
+		pr_info("%s: done, remaining timeout %uus\n",
+			__func__, timeout_us);
+
+	return 0;
+
+set_phase_bail:
+	pr_err("%s: failed, remaining timeout %uus, phase count %d\n",
+	       __func__, timeout_us, msm_spm_drv_get_sts_curr_pmic_data(dev));
+	return -EIO;
+
+}
+
+void msm_spm_drv_reinit(struct msm_spm_driver_data *dev)
+{
+	int i;
+
+	for (i = 0; i < MSM_SPM_REG_NR_INITIALIZE; i++)
+		msm_spm_drv_flush_shadow(dev, i);
+
+	msm_spm_drv_flush_seq_entry(dev);
+	mb();
+}
+
+int __devinit msm_spm_drv_init(struct msm_spm_driver_data *dev,
+		struct msm_spm_platform_data *data)
+{
+	int i;
+	int num_spm_entry;
+
+	BUG_ON(!dev || !data);
+
+	if (dev->ver_reg == SAW2_V2_VER_REG)
+		dev->reg_offsets = msm_spm_reg_offsets_v2;
+	else
+		dev->reg_offsets = msm_spm_reg_offsets_v1;
+
+	dev->vctl_port = data->vctl_port;
+	dev->phase_port = data->phase_port;
+	dev->reg_base_addr = data->reg_base_addr;
+	memcpy(dev->reg_shadow, data->reg_init_values,
+			sizeof(data->reg_init_values));
+
+	dev->vctl_timeout_us = data->vctl_timeout_us;
+
+	for (i = 0; i < MSM_SPM_REG_NR_INITIALIZE; i++)
+		msm_spm_drv_flush_shadow(dev, i);
+	/* barrier to ensure write completes before we update shadow
+	 * registers
+	 */
+	mb();
+
+	for (i = 0; i < MSM_SPM_REG_NR_INITIALIZE; i++)
+		msm_spm_drv_load_shadow(dev, i);
+
+	/* barrier to ensure read completes before we proceed further*/
+	mb();
+
+	msm_spm_drv_get_saw2_ver(dev, &dev->major, &dev->minor);
+
+	num_spm_entry = msm_spm_drv_get_num_spm_entry(dev);
+
+	dev->reg_seq_entry_shadow =
+		kzalloc(sizeof(*dev->reg_seq_entry_shadow) * num_spm_entry,
+				GFP_KERNEL);
+
+	if (!dev->reg_seq_entry_shadow)
+		return -ENOMEM;
+
+	return 0;
+}
diff --git a/arch/arm/mach-msm/spm.c b/arch/arm/mach-msm/spm.c
new file mode 100644
index 0000000..4654fba
--- /dev/null
+++ b/arch/arm/mach-msm/spm.c
@@ -0,0 +1,303 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <mach/msm_iomap.h>
+
+#include "spm.h"
+
+
+enum {
+	MSM_SPM_DEBUG_SHADOW = 1U << 0,
+	MSM_SPM_DEBUG_VCTL = 1U << 1,
+};
+
+static int msm_spm_debug_mask;
+module_param_named(
+	debug_mask, msm_spm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
+);
+
+#define MSM_SPM_PMIC_STATE_IDLE  0
+
+static uint32_t msm_spm_reg_offsets[MSM_SPM_REG_NR] = {
+	[MSM_SPM_REG_SAW_AVS_CTL] = 0x04,
+
+	[MSM_SPM_REG_SAW_VCTL] = 0x08,
+	[MSM_SPM_REG_SAW_STS] = 0x0C,
+	[MSM_SPM_REG_SAW_CFG] = 0x10,
+
+	[MSM_SPM_REG_SAW_SPM_CTL] = 0x14,
+	[MSM_SPM_REG_SAW_SPM_SLP_TMR_DLY] = 0x18,
+	[MSM_SPM_REG_SAW_SPM_WAKE_TMR_DLY] = 0x1C,
+
+	[MSM_SPM_REG_SAW_SPM_PMIC_CTL] = 0x20,
+	[MSM_SPM_REG_SAW_SLP_CLK_EN] = 0x24,
+	[MSM_SPM_REG_SAW_SLP_HSFS_PRECLMP_EN] = 0x28,
+	[MSM_SPM_REG_SAW_SLP_HSFS_POSTCLMP_EN] = 0x2C,
+
+	[MSM_SPM_REG_SAW_SLP_CLMP_EN] = 0x30,
+	[MSM_SPM_REG_SAW_SLP_RST_EN] = 0x34,
+	[MSM_SPM_REG_SAW_SPM_MPM_CFG] = 0x38,
+};
+
+struct msm_spm_device {
+	void __iomem *reg_base_addr;
+	uint32_t reg_shadow[MSM_SPM_REG_NR];
+
+	uint8_t awake_vlevel;
+	uint8_t retention_vlevel;
+	uint8_t collapse_vlevel;
+	uint8_t retention_mid_vlevel;
+	uint8_t collapse_mid_vlevel;
+
+	uint32_t vctl_timeout_us;
+
+	unsigned int low_power_mode;
+	bool notify_rpm;
+	bool dirty;
+};
+
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct msm_spm_device, msm_spm_devices);
+static atomic_t msm_spm_set_vdd_x_cpu_allowed = ATOMIC_INIT(1);
+
+/******************************************************************************
+ * Internal helper functions
+ *****************************************************************************/
+
+static inline void msm_spm_set_vctl(
+	struct msm_spm_device *dev, uint32_t vlevel)
+{
+	dev->reg_shadow[MSM_SPM_REG_SAW_VCTL] &= ~0xFF;
+	dev->reg_shadow[MSM_SPM_REG_SAW_VCTL] |= vlevel;
+}
+
+static inline void msm_spm_set_spm_ctl(struct msm_spm_device *dev,
+	uint32_t rpm_bypass, uint32_t mode_encoding)
+{
+	dev->reg_shadow[MSM_SPM_REG_SAW_SPM_CTL] &= ~0x0F;
+	dev->reg_shadow[MSM_SPM_REG_SAW_SPM_CTL] |= rpm_bypass << 3;
+	dev->reg_shadow[MSM_SPM_REG_SAW_SPM_CTL] |= mode_encoding;
+}
+
+static inline void msm_spm_set_pmic_ctl(struct msm_spm_device *dev,
+	uint32_t awake_vlevel, uint32_t mid_vlevel, uint32_t sleep_vlevel)
+{
+	dev->reg_shadow[MSM_SPM_REG_SAW_SPM_PMIC_CTL] =
+		(mid_vlevel << 16) | (awake_vlevel << 8) | (sleep_vlevel);
+}
+
+static inline void msm_spm_set_slp_rst_en(
+	struct msm_spm_device *dev, uint32_t slp_rst_en)
+{
+	dev->reg_shadow[MSM_SPM_REG_SAW_SLP_RST_EN] = slp_rst_en;
+}
+
+static inline void msm_spm_flush_shadow(
+	struct msm_spm_device *dev, unsigned int reg_index)
+{
+	__raw_writel(dev->reg_shadow[reg_index],
+		dev->reg_base_addr + msm_spm_reg_offsets[reg_index]);
+}
+
+static inline void msm_spm_load_shadow(
+	struct msm_spm_device *dev, unsigned int reg_index)
+{
+	dev->reg_shadow[reg_index] = __raw_readl(dev->reg_base_addr +
+					msm_spm_reg_offsets[reg_index]);
+}
+
+static inline uint32_t msm_spm_get_sts_pmic_state(struct msm_spm_device *dev)
+{
+	return (dev->reg_shadow[MSM_SPM_REG_SAW_STS] >> 20) & 0x03;
+}
+
+static inline uint32_t msm_spm_get_sts_curr_pmic_data(
+	struct msm_spm_device *dev)
+{
+	return (dev->reg_shadow[MSM_SPM_REG_SAW_STS] >> 10) & 0xFF;
+}
+
+/******************************************************************************
+ * Public functions
+ *****************************************************************************/
+int msm_spm_set_low_power_mode(unsigned int mode, bool notify_rpm)
+{
+	struct msm_spm_device *dev = &__get_cpu_var(msm_spm_devices);
+	uint32_t rpm_bypass = notify_rpm ? 0x00 : 0x01;
+
+	if (mode == dev->low_power_mode && notify_rpm == dev->notify_rpm
+		&& !dev->dirty)
+		return 0;
+
+	switch (mode) {
+	case MSM_SPM_MODE_CLOCK_GATING:
+		msm_spm_set_spm_ctl(dev, rpm_bypass, 0x00);
+		msm_spm_set_slp_rst_en(dev, 0x00);
+		break;
+
+	case MSM_SPM_MODE_POWER_RETENTION:
+		msm_spm_set_spm_ctl(dev, rpm_bypass, 0x02);
+		msm_spm_set_pmic_ctl(dev, dev->awake_vlevel,
+			dev->retention_mid_vlevel, dev->retention_vlevel);
+		msm_spm_set_slp_rst_en(dev, 0x00);
+		break;
+
+	case MSM_SPM_MODE_POWER_COLLAPSE:
+		msm_spm_set_spm_ctl(dev, rpm_bypass, 0x02);
+		msm_spm_set_pmic_ctl(dev, dev->awake_vlevel,
+			dev->collapse_mid_vlevel, dev->collapse_vlevel);
+		msm_spm_set_slp_rst_en(dev, 0x01);
+		break;
+
+	default:
+		BUG();
+	}
+
+	msm_spm_flush_shadow(dev, MSM_SPM_REG_SAW_SPM_CTL);
+	msm_spm_flush_shadow(dev, MSM_SPM_REG_SAW_SPM_PMIC_CTL);
+	msm_spm_flush_shadow(dev, MSM_SPM_REG_SAW_SLP_RST_EN);
+	/* Ensure that the registers are written before returning */
+	mb();
+
+	dev->low_power_mode = mode;
+	dev->notify_rpm = notify_rpm;
+	dev->dirty = false;
+
+	if (msm_spm_debug_mask & MSM_SPM_DEBUG_SHADOW) {
+		int i;
+		for (i = 0; i < MSM_SPM_REG_NR; i++)
+			pr_info("%s: reg %02x = 0x%08x\n", __func__,
+				msm_spm_reg_offsets[i], dev->reg_shadow[i]);
+	}
+
+	return 0;
+}
+
+int msm_spm_set_vdd(unsigned int cpu, unsigned int vlevel)
+{
+	unsigned long flags;
+	struct msm_spm_device *dev;
+	uint32_t timeout_us;
+
+	local_irq_save(flags);
+
+	if (!atomic_read(&msm_spm_set_vdd_x_cpu_allowed) &&
+				unlikely(smp_processor_id() != cpu)) {
+		if (msm_spm_debug_mask & MSM_SPM_DEBUG_VCTL)
+			pr_info("%s: attempting to set vdd of cpu %u from "
+				"cpu %u\n", __func__, cpu, smp_processor_id());
+		goto set_vdd_x_cpu_bail;
+	}
+
+	dev = &per_cpu(msm_spm_devices, cpu);
+
+	if (msm_spm_debug_mask & MSM_SPM_DEBUG_VCTL)
+		pr_info("%s: requesting cpu %u vlevel 0x%x\n",
+			__func__, cpu, vlevel);
+
+	msm_spm_set_vctl(dev, vlevel);
+	msm_spm_flush_shadow(dev, MSM_SPM_REG_SAW_VCTL);
+
+	/* Wait for PMIC state to return to idle or until timeout */
+	timeout_us = dev->vctl_timeout_us;
+	msm_spm_load_shadow(dev, MSM_SPM_REG_SAW_STS);
+	while (msm_spm_get_sts_pmic_state(dev) != MSM_SPM_PMIC_STATE_IDLE) {
+		if (!timeout_us)
+			goto set_vdd_bail;
+
+		if (timeout_us > 10) {
+			udelay(10);
+			timeout_us -= 10;
+		} else {
+			udelay(timeout_us);
+			timeout_us = 0;
+		}
+		msm_spm_load_shadow(dev, MSM_SPM_REG_SAW_STS);
+	}
+
+	if (msm_spm_get_sts_curr_pmic_data(dev) != vlevel)
+		goto set_vdd_bail;
+
+	dev->awake_vlevel = vlevel;
+	dev->dirty = true;
+
+	if (msm_spm_debug_mask & MSM_SPM_DEBUG_VCTL)
+		pr_info("%s: cpu %u done, remaining timeout %uus\n",
+			__func__, cpu, timeout_us);
+
+	local_irq_restore(flags);
+	return 0;
+
+set_vdd_bail:
+	pr_err("%s: cpu %u failed, remaining timeout %uus, vlevel 0x%x\n",
+	       __func__, cpu, timeout_us, msm_spm_get_sts_curr_pmic_data(dev));
+
+set_vdd_x_cpu_bail:
+	local_irq_restore(flags);
+	return -EIO;
+}
+
+void msm_spm_reinit(void)
+{
+	struct msm_spm_device *dev = &__get_cpu_var(msm_spm_devices);
+	int i;
+
+	for (i = 0; i < MSM_SPM_REG_NR_INITIALIZE; i++)
+		msm_spm_flush_shadow(dev, i);
+
+	/* Ensure that the registers are written before returning */
+	mb();
+}
+
+void msm_spm_allow_x_cpu_set_vdd(bool allowed)
+{
+	atomic_set(&msm_spm_set_vdd_x_cpu_allowed, allowed ? 1 : 0);
+}
+
+int __init msm_spm_init(struct msm_spm_platform_data *data, int nr_devs)
+{
+	unsigned int cpu;
+
+	BUG_ON(nr_devs < num_possible_cpus());
+	for_each_possible_cpu(cpu) {
+		struct msm_spm_device *dev = &per_cpu(msm_spm_devices, cpu);
+		int i;
+
+		dev->reg_base_addr = data[cpu].reg_base_addr;
+		memcpy(dev->reg_shadow, data[cpu].reg_init_values,
+			sizeof(data[cpu].reg_init_values));
+
+		dev->awake_vlevel = data[cpu].awake_vlevel;
+		dev->retention_vlevel = data[cpu].retention_vlevel;
+		dev->collapse_vlevel = data[cpu].collapse_vlevel;
+		dev->retention_mid_vlevel = data[cpu].retention_mid_vlevel;
+		dev->collapse_mid_vlevel = data[cpu].collapse_mid_vlevel;
+		dev->vctl_timeout_us = data[cpu].vctl_timeout_us;
+
+		for (i = 0; i < MSM_SPM_REG_NR_INITIALIZE; i++)
+			msm_spm_flush_shadow(dev, i);
+
+		/* Ensure that the registers are written before returning */
+		mb();
+
+		dev->low_power_mode = MSM_SPM_MODE_CLOCK_GATING;
+		dev->notify_rpm = false;
+		dev->dirty = true;
+	}
+
+	return 0;
+}
diff --git a/arch/arm/mach-msm/spm.h b/arch/arm/mach-msm/spm.h
new file mode 100644
index 0000000..154303b
--- /dev/null
+++ b/arch/arm/mach-msm/spm.h
@@ -0,0 +1,270 @@
+/* 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
+ * 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 __ARCH_ARM_MACH_MSM_SPM_H
+#define __ARCH_ARM_MACH_MSM_SPM_H
+enum {
+	MSM_SPM_MODE_DISABLED,
+	MSM_SPM_MODE_CLOCK_GATING,
+	MSM_SPM_MODE_POWER_RETENTION,
+	MSM_SPM_MODE_POWER_COLLAPSE,
+	MSM_SPM_MODE_NR
+};
+
+enum {
+	MSM_SPM_L2_MODE_DISABLED = MSM_SPM_MODE_DISABLED,
+	MSM_SPM_L2_MODE_RETENTION,
+	MSM_SPM_L2_MODE_GDHS,
+	MSM_SPM_L2_MODE_POWER_COLLAPSE,
+};
+
+#if defined(CONFIG_MSM_SPM_V1)
+
+enum {
+	MSM_SPM_REG_SAW_AVS_CTL,
+	MSM_SPM_REG_SAW_CFG,
+	MSM_SPM_REG_SAW_SPM_CTL,
+	MSM_SPM_REG_SAW_SPM_SLP_TMR_DLY,
+	MSM_SPM_REG_SAW_SPM_WAKE_TMR_DLY,
+	MSM_SPM_REG_SAW_SLP_CLK_EN,
+	MSM_SPM_REG_SAW_SLP_HSFS_PRECLMP_EN,
+	MSM_SPM_REG_SAW_SLP_HSFS_POSTCLMP_EN,
+	MSM_SPM_REG_SAW_SLP_CLMP_EN,
+	MSM_SPM_REG_SAW_SLP_RST_EN,
+	MSM_SPM_REG_SAW_SPM_MPM_CFG,
+	MSM_SPM_REG_NR_INITIALIZE,
+
+	MSM_SPM_REG_SAW_VCTL = MSM_SPM_REG_NR_INITIALIZE,
+	MSM_SPM_REG_SAW_STS,
+	MSM_SPM_REG_SAW_SPM_PMIC_CTL,
+	MSM_SPM_REG_NR
+};
+
+struct msm_spm_platform_data {
+	void __iomem *reg_base_addr;
+	uint32_t reg_init_values[MSM_SPM_REG_NR_INITIALIZE];
+
+	uint8_t awake_vlevel;
+	uint8_t retention_vlevel;
+	uint8_t collapse_vlevel;
+	uint8_t retention_mid_vlevel;
+	uint8_t collapse_mid_vlevel;
+
+	uint32_t vctl_timeout_us;
+};
+
+#elif defined(CONFIG_MSM_SPM_V2)
+
+enum {
+	MSM_SPM_REG_SAW2_CFG,
+	MSM_SPM_REG_SAW2_AVS_CTL,
+	MSM_SPM_REG_SAW2_AVS_HYSTERESIS,
+	MSM_SPM_REG_SAW2_SPM_CTL,
+	MSM_SPM_REG_SAW2_PMIC_DLY,
+	MSM_SPM_REG_SAW2_AVS_LIMIT,
+	MSM_SPM_REG_SAW2_AVS_DLY,
+	MSM_SPM_REG_SAW2_SPM_DLY,
+	MSM_SPM_REG_SAW2_PMIC_DATA_0,
+	MSM_SPM_REG_SAW2_PMIC_DATA_1,
+	MSM_SPM_REG_SAW2_PMIC_DATA_2,
+	MSM_SPM_REG_SAW2_PMIC_DATA_3,
+	MSM_SPM_REG_SAW2_PMIC_DATA_4,
+	MSM_SPM_REG_SAW2_PMIC_DATA_5,
+	MSM_SPM_REG_SAW2_PMIC_DATA_6,
+	MSM_SPM_REG_SAW2_PMIC_DATA_7,
+	MSM_SPM_REG_SAW2_RST,
+
+	MSM_SPM_REG_NR_INITIALIZE = MSM_SPM_REG_SAW2_RST,
+
+	MSM_SPM_REG_SAW2_ID,
+	MSM_SPM_REG_SAW2_SECURE,
+	MSM_SPM_REG_SAW2_STS0,
+	MSM_SPM_REG_SAW2_STS1,
+	MSM_SPM_REG_SAW2_VCTL,
+	MSM_SPM_REG_SAW2_SEQ_ENTRY,
+	MSM_SPM_REG_SAW2_SPM_STS,
+	MSM_SPM_REG_SAW2_AVS_STS,
+	MSM_SPM_REG_SAW2_PMIC_STS,
+	MSM_SPM_REG_SAW2_VERSION,
+
+	MSM_SPM_REG_NR,
+};
+
+struct msm_spm_seq_entry {
+	uint32_t mode;
+	uint8_t *cmd;
+	bool  notify_rpm;
+};
+
+struct msm_spm_platform_data {
+	void __iomem *reg_base_addr;
+	uint32_t reg_init_values[MSM_SPM_REG_NR_INITIALIZE];
+
+	uint32_t ver_reg;
+	uint32_t vctl_port;
+	uint32_t phase_port;
+
+	uint8_t awake_vlevel;
+	uint32_t vctl_timeout_us;
+	uint32_t avs_timeout_us;
+
+	uint32_t num_modes;
+	struct msm_spm_seq_entry *modes;
+};
+#endif
+
+#if defined(CONFIG_MSM_SPM_V1) || defined(CONFIG_MSM_SPM_V2)
+
+/* Public functions */
+
+/**
+ * msm_spm_set_low_power_mode() - Configure SPM start address for low power mode
+ * @mode: SPM LPM mode to enter
+ * @notify_rpm: Notify RPM in this mode
+ */
+int msm_spm_set_low_power_mode(unsigned int mode, bool notify_rpm);
+
+/**
+ * msm_spm_set_vdd(): Set core voltage
+ * @cpu: core id
+ * @vlevel: Encoded PMIC data.
+ */
+int msm_spm_set_vdd(unsigned int cpu, unsigned int vlevel);
+
+/**
+ * msm_spm_turn_on_cpu_rail(): Power on cpu rail before turning on core
+ * @cpu: core id
+ */
+int msm_spm_turn_on_cpu_rail(unsigned int cpu);
+
+
+/* Internal low power management specific functions */
+
+/**
+ * msm_spm_allow_x_cpu_set_vdd(): Turn on/off cross calling to set voltage
+ * @allowed: boolean to indicate on/off.
+ */
+void msm_spm_allow_x_cpu_set_vdd(bool allowed);
+
+/**
+ * msm_spm_reinit(): Reinitialize SPM registers
+ */
+void msm_spm_reinit(void);
+
+/**
+ * msm_spm_init(): Board initalization function
+ * @data: platform specific SPM register configuration data
+ * @nr_devs: Number of SPM devices being initialized
+ */
+int msm_spm_init(struct msm_spm_platform_data *data, int nr_devs);
+
+/**
+ * msm_spm_device_init(): Device tree initialization function
+ */
+int msm_spm_device_init(void);
+
+#if defined(CONFIG_MSM_L2_SPM)
+
+/* Public functions */
+
+/**
+ * msm_spm_l2_set_low_power_mode(): Configure L2 SPM start address
+ *                                  for low power mode
+ * @mode: SPM LPM mode to enter
+ * @notify_rpm: Notify RPM in this mode
+ */
+int msm_spm_l2_set_low_power_mode(unsigned int mode, bool notify_rpm);
+
+/**
+ * msm_spm_apcs_set_vdd(): Set Apps processor core sub-system voltage
+ * @vlevel: Encoded PMIC data.
+ */
+int msm_spm_apcs_set_vdd(unsigned int vlevel);
+
+/**
+ * msm_spm_apcs_set_phase(): Set number of SMPS phases.
+ * phase_cnt: Number of phases to be set active
+ */
+int msm_spm_apcs_set_phase(unsigned int phase_cnt);
+
+/* Internal low power management specific functions */
+
+/**
+ * msm_spm_l2_init(): Board initialization function
+ * @data: SPM target specific register configuration
+ */
+int msm_spm_l2_init(struct msm_spm_platform_data *data);
+
+/**
+ * msm_spm_l2_reinit(): Reinitialize L2 SPM registers
+ */
+void msm_spm_l2_reinit(void);
+
+#else
+
+static inline int msm_spm_l2_set_low_power_mode(unsigned int mode,
+		bool notify_rpm)
+{
+	return -ENOSYS;
+}
+static inline int msm_spm_l2_init(struct msm_spm_platform_data *data)
+{
+	return -ENOSYS;
+}
+static inline void msm_spm_l2_reinit(void)
+{
+	/* empty */
+}
+
+static inline int msm_spm_apcs_set_vdd(unsigned int vlevel)
+{
+	return -ENOSYS;
+}
+
+static inline int msm_spm_apcs_set_phase(unsigned int phase_cnt)
+{
+	return -ENOSYS;
+}
+#endif /* defined(CONFIG_MSM_L2_SPM) */
+#else /* defined(CONFIG_MSM_SPM_V1) || defined(CONFIG_MSM_SPM_V2) */
+static inline int msm_spm_set_low_power_mode(unsigned int mode, bool notify_rpm)
+{
+	return -ENOSYS;
+}
+
+static inline int msm_spm_set_vdd(unsigned int cpu, unsigned int vlevel)
+{
+	return -ENOSYS;
+}
+
+static inline void msm_spm_reinit(void)
+{
+	/* empty */
+}
+
+static inline void msm_spm_allow_x_cpu_set_vdd(bool allowed)
+{
+	/* empty */
+}
+
+static inline int msm_spm_turn_on_cpu_rail(unsigned int cpu)
+{
+	return -ENOSYS;
+}
+
+static inline int msm_spm_device_init(void)
+{
+	return -ENOSYS;
+}
+
+#endif  /*defined(CONFIG_MSM_SPM_V1) || defined (CONFIG_MSM_SPM_V2) */
+#endif  /* __ARCH_ARM_MACH_MSM_SPM_H */
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
new file mode 100644
index 0000000..a77efe0
--- /dev/null
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -0,0 +1,394 @@
+/* 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
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <mach/msm_iomap.h>
+#include <mach/socinfo.h>
+#include "spm.h"
+#include "spm_driver.h"
+
+struct msm_spm_power_modes {
+	uint32_t mode;
+	bool notify_rpm;
+	uint32_t start_addr;
+
+};
+
+struct msm_spm_device {
+	struct msm_spm_driver_data reg_data;
+	struct msm_spm_power_modes *modes;
+	uint32_t num_modes;
+};
+
+static struct msm_spm_device msm_spm_l2_device;
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct msm_spm_device, msm_cpu_spm_device);
+static atomic_t msm_spm_set_vdd_x_cpu_allowed = ATOMIC_INIT(1);
+
+void msm_spm_allow_x_cpu_set_vdd(bool allowed)
+{
+	atomic_set(&msm_spm_set_vdd_x_cpu_allowed, allowed ? 1 : 0);
+}
+EXPORT_SYMBOL(msm_spm_allow_x_cpu_set_vdd);
+
+int msm_spm_set_vdd(unsigned int cpu, unsigned int vlevel)
+{
+	unsigned long flags;
+	struct msm_spm_device *dev;
+	int ret = -EIO;
+
+	local_irq_save(flags);
+	if (!atomic_read(&msm_spm_set_vdd_x_cpu_allowed) &&
+				unlikely(smp_processor_id() != cpu)) {
+		goto set_vdd_x_cpu_bail;
+	}
+
+	dev = &per_cpu(msm_cpu_spm_device, cpu);
+	ret = msm_spm_drv_set_vdd(&dev->reg_data, vlevel);
+
+set_vdd_x_cpu_bail:
+	local_irq_restore(flags);
+	return ret;
+}
+EXPORT_SYMBOL(msm_spm_set_vdd);
+
+static int msm_spm_dev_set_low_power_mode(struct msm_spm_device *dev,
+		unsigned int mode, bool notify_rpm)
+{
+	uint32_t i;
+	uint32_t start_addr = 0;
+	int ret = -EINVAL;
+
+	if (mode == MSM_SPM_MODE_DISABLED) {
+		ret = msm_spm_drv_set_spm_enable(&dev->reg_data, false);
+	} else if (!msm_spm_drv_set_spm_enable(&dev->reg_data, true)) {
+		for (i = 0; i < dev->num_modes; i++) {
+			if ((dev->modes[i].mode == mode) &&
+				(dev->modes[i].notify_rpm == notify_rpm)) {
+				start_addr = dev->modes[i].start_addr;
+				break;
+			}
+		}
+		ret = msm_spm_drv_set_low_power_mode(&dev->reg_data,
+					start_addr);
+	}
+	return ret;
+}
+
+static int __devinit msm_spm_dev_init(struct msm_spm_device *dev,
+		struct msm_spm_platform_data *data)
+{
+	int i, ret = -ENOMEM;
+	uint32_t offset = 0;
+
+	dev->num_modes = data->num_modes;
+	dev->modes = kmalloc(
+			sizeof(struct msm_spm_power_modes) * dev->num_modes,
+			GFP_KERNEL);
+
+	if (!dev->modes)
+		goto spm_failed_malloc;
+
+	dev->reg_data.ver_reg = data->ver_reg;
+	ret = msm_spm_drv_init(&dev->reg_data, data);
+
+	if (ret)
+		goto spm_failed_init;
+
+	for (i = 0; i < dev->num_modes; i++) {
+
+		/* Default offset is 0 and gets updated as we write more
+		 * sequences into SPM
+		 */
+		dev->modes[i].start_addr = offset;
+		ret = msm_spm_drv_write_seq_data(&dev->reg_data,
+						data->modes[i].cmd, &offset);
+		if (ret < 0)
+			goto spm_failed_init;
+
+		dev->modes[i].mode = data->modes[i].mode;
+		dev->modes[i].notify_rpm = data->modes[i].notify_rpm;
+	}
+	msm_spm_drv_flush_seq_entry(&dev->reg_data);
+	return 0;
+
+spm_failed_init:
+	kfree(dev->modes);
+spm_failed_malloc:
+	return ret;
+}
+
+int msm_spm_turn_on_cpu_rail(unsigned int cpu)
+{
+	uint32_t val = 0;
+	uint32_t timeout = 0;
+	void *reg = NULL;
+	void *saw_bases[] = {
+		0,
+		MSM_SAW1_BASE,
+		MSM_SAW2_BASE,
+		MSM_SAW3_BASE
+	};
+
+	if (cpu == 0 || cpu >= num_possible_cpus())
+		return -EINVAL;
+
+	reg = saw_bases[cpu];
+
+	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_apq8064()) {
+		val = 0xA4;
+		reg += 0x14;
+		timeout = 512;
+	} else {
+		return -ENOSYS;
+	}
+
+	writel_relaxed(val, reg);
+	mb();
+	udelay(timeout);
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_spm_turn_on_cpu_rail);
+
+void msm_spm_reinit(void)
+{
+	unsigned int cpu;
+	for_each_possible_cpu(cpu)
+		msm_spm_drv_reinit(&per_cpu(msm_cpu_spm_device.reg_data, cpu));
+}
+EXPORT_SYMBOL(msm_spm_reinit);
+
+int msm_spm_set_low_power_mode(unsigned int mode, bool notify_rpm)
+{
+	struct msm_spm_device *dev = &__get_cpu_var(msm_cpu_spm_device);
+	return msm_spm_dev_set_low_power_mode(dev, mode, notify_rpm);
+}
+EXPORT_SYMBOL(msm_spm_set_low_power_mode);
+
+/* Board file init function */
+int __init msm_spm_init(struct msm_spm_platform_data *data, int nr_devs)
+{
+	unsigned int cpu;
+	int ret = 0;
+
+	BUG_ON((nr_devs < num_possible_cpus()) || !data);
+
+	for_each_possible_cpu(cpu) {
+		struct msm_spm_device *dev = &per_cpu(msm_cpu_spm_device, cpu);
+		ret = msm_spm_dev_init(dev, &data[cpu]);
+		if (ret < 0) {
+			pr_warn("%s():failed CPU:%u ret:%d\n", __func__,
+					cpu, ret);
+			break;
+		}
+	}
+
+	return ret;
+}
+
+#ifdef CONFIG_MSM_L2_SPM
+
+int msm_spm_l2_set_low_power_mode(unsigned int mode, bool notify_rpm)
+{
+	return msm_spm_dev_set_low_power_mode(
+			&msm_spm_l2_device, mode, notify_rpm);
+}
+EXPORT_SYMBOL(msm_spm_l2_set_low_power_mode);
+
+void msm_spm_l2_reinit(void)
+{
+	msm_spm_drv_reinit(&msm_spm_l2_device.reg_data);
+}
+EXPORT_SYMBOL(msm_spm_l2_reinit);
+
+int msm_spm_apcs_set_vdd(unsigned int vlevel)
+{
+	return msm_spm_drv_set_vdd(&msm_spm_l2_device.reg_data, vlevel);
+}
+EXPORT_SYMBOL(msm_spm_apcs_set_vdd);
+
+int msm_spm_apcs_set_phase(unsigned int phase_cnt)
+{
+	return msm_spm_drv_set_phase(&msm_spm_l2_device.reg_data, phase_cnt);
+}
+EXPORT_SYMBOL(msm_spm_apcs_set_phase);
+
+/* Board file init function */
+int __init msm_spm_l2_init(struct msm_spm_platform_data *data)
+{
+	return msm_spm_dev_init(&msm_spm_l2_device, data);
+}
+#endif
+
+static int __init msm_spm_dev_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	int cpu = 0;
+	int i = 0;
+	struct device_node *node = pdev->dev.of_node;
+	struct msm_spm_platform_data spm_data;
+	char *key = NULL;
+	uint32_t val = 0;
+	struct msm_spm_seq_entry modes[MSM_SPM_MODE_NR];
+	size_t len = 0;
+	struct msm_spm_device *dev = NULL;
+	struct resource *res = NULL;
+	uint32_t mode_count = 0;
+
+	struct spm_of {
+		char *key;
+		uint32_t id;
+	};
+
+	struct spm_of spm_of_data[] = {
+		{"qcom,saw2-cfg", MSM_SPM_REG_SAW2_CFG},
+		{"qcom,saw2-avs-ctl", MSM_SPM_REG_SAW2_AVS_CTL},
+		{"qcom,saw2-avs-hysteresis", MSM_SPM_REG_SAW2_AVS_HYSTERESIS},
+		{"qcom,saw2-spm-ctl", MSM_SPM_REG_SAW2_SPM_CTL},
+		{"qcom,saw2-pmic-dly", MSM_SPM_REG_SAW2_PMIC_DLY},
+		{"qcom,saw2-avs-limit", MSM_SPM_REG_SAW2_AVS_LIMIT},
+		{"qcom,saw2-spm-dly", MSM_SPM_REG_SAW2_SPM_DLY},
+		{"qcom,saw2-pmic-data0", MSM_SPM_REG_SAW2_PMIC_DATA_0},
+		{"qcom,saw2-pmic-data1", MSM_SPM_REG_SAW2_PMIC_DATA_1},
+		{"qcom,saw2-pmic-data2", MSM_SPM_REG_SAW2_PMIC_DATA_2},
+		{"qcom,saw2-pmic-data3", MSM_SPM_REG_SAW2_PMIC_DATA_3},
+		{"qcom,saw2-pmic-data4", MSM_SPM_REG_SAW2_PMIC_DATA_4},
+		{"qcom,saw2-pmic-data5", MSM_SPM_REG_SAW2_PMIC_DATA_5},
+		{"qcom,saw2-pmic-data6", MSM_SPM_REG_SAW2_PMIC_DATA_6},
+		{"qcom,saw2-pmic-data7", MSM_SPM_REG_SAW2_PMIC_DATA_7},
+	};
+
+	struct mode_of {
+		char *key;
+		uint32_t id;
+		uint32_t notify_rpm;
+	};
+
+	struct mode_of mode_of_data[] = {
+		{"qcom,spm-cmd-wfi", MSM_SPM_MODE_CLOCK_GATING, 0},
+		{"qcom,spm-cmd-ret", MSM_SPM_MODE_POWER_RETENTION, 0},
+		{"qcom,spm-cmd-spc", MSM_SPM_MODE_POWER_COLLAPSE, 0},
+		{"qcom,spm-cmd-pc", MSM_SPM_MODE_POWER_COLLAPSE, 1},
+	};
+
+	BUG_ON(ARRAY_SIZE(mode_of_data) > MSM_SPM_MODE_NR);
+	memset(&spm_data, 0, sizeof(struct msm_spm_platform_data));
+	memset(&modes, 0,
+		(MSM_SPM_MODE_NR - 2) * sizeof(struct msm_spm_seq_entry));
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		goto fail;
+
+	spm_data.reg_base_addr = devm_ioremap(&pdev->dev, res->start,
+					resource_size(res));
+	if (!spm_data.reg_base_addr)
+		return -ENOMEM;
+
+	key = "qcom,core-id";
+	ret = of_property_read_u32(node, key, &val);
+	if (ret)
+		goto fail;
+	cpu = val;
+
+	key = "qcom,saw2-ver-reg";
+	ret = of_property_read_u32(node, key, &val);
+	if (ret)
+		goto fail;
+	spm_data.ver_reg = val;
+
+	key = "qcom,vctl-timeout-us";
+	ret = of_property_read_u32(node, key, &val);
+	if (!ret)
+		spm_data.vctl_timeout_us = val;
+
+	/* optional */
+	key = "qcom,vctl-port";
+	ret = of_property_read_u32(node, key, &val);
+	if (!ret)
+		spm_data.vctl_port = val;
+
+	/* optional */
+	key = "qcom,phase-port";
+	ret = of_property_read_u32(node, key, &val);
+	if (!ret)
+		spm_data.phase_port = val;
+
+	for (i = 0; i < ARRAY_SIZE(spm_of_data); i++) {
+		ret = of_property_read_u32(node, spm_of_data[i].key, &val);
+		if (ret)
+			continue;
+		spm_data.reg_init_values[spm_of_data[i].id] = val;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(mode_of_data); i++) {
+		key = mode_of_data[i].key;
+		modes[mode_count].cmd =
+			(uint8_t *)of_get_property(node, key, &len);
+		if (!modes[mode_count].cmd)
+			continue;
+		modes[mode_count].mode = mode_of_data[i].id;
+		modes[mode_count].notify_rpm = mode_of_data[i].notify_rpm;
+		mode_count++;
+	}
+
+	spm_data.modes = modes;
+	spm_data.num_modes = mode_count;
+
+	/*
+	 * Device with id 0..NR_CPUS are SPM for apps cores
+	 * Device with id 0xFFFF is for L2 SPM.
+	 */
+	if (cpu >= 0 && cpu < num_possible_cpus())
+		dev = &per_cpu(msm_cpu_spm_device, cpu);
+	else
+		dev = &msm_spm_l2_device;
+
+	ret = msm_spm_dev_init(dev, &spm_data);
+	if (ret < 0)
+		pr_warn("%s():failed core-id:%u ret:%d\n", __func__, cpu, ret);
+
+	return ret;
+
+fail:
+	pr_err("%s: Failed reading node=%s, key=%s\n",
+			__func__, node->full_name, key);
+	return -EFAULT;
+}
+
+static __initdata struct of_device_id msm_spm_match_table[] = {
+	{.compatible = "qcom,spm-v2"},
+	{},
+};
+
+static __initdata struct platform_driver msm_spm_device_driver = {
+	.probe = msm_spm_dev_probe,
+	.driver = {
+		.name = "spm-v2",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_spm_match_table,
+	},
+};
+
+int __init msm_spm_device_init(void)
+{
+	return platform_driver_register(&msm_spm_device_driver);
+}
diff --git a/arch/arm/mach-msm/spm_driver.h b/arch/arm/mach-msm/spm_driver.h
new file mode 100644
index 0000000..f272adb0
--- /dev/null
+++ b/arch/arm/mach-msm/spm_driver.h
@@ -0,0 +1,45 @@
+/* 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
+ * 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 __ARCH_ARM_MACH_MSM_SPM_DEVICES_H
+#define __ARCH_ARM_MACH_MSM_SPM_DEVICES_H
+
+#include "spm.h"
+
+struct msm_spm_driver_data {
+	uint32_t major;
+	uint32_t minor;
+	uint32_t ver_reg;
+	uint32_t vctl_port;
+	uint32_t phase_port;
+	void __iomem *reg_base_addr;
+	uint32_t vctl_timeout_us;
+	uint32_t avs_timeout_us;
+	uint32_t reg_shadow[MSM_SPM_REG_NR];
+	uint32_t *reg_seq_entry_shadow;
+	uint32_t *reg_offsets;
+};
+
+int msm_spm_drv_init(struct msm_spm_driver_data *dev,
+		struct msm_spm_platform_data *data);
+void msm_spm_drv_reinit(struct msm_spm_driver_data *dev);
+int msm_spm_drv_set_low_power_mode(struct msm_spm_driver_data *dev,
+		uint32_t addr);
+int msm_spm_drv_set_vdd(struct msm_spm_driver_data *dev,
+		unsigned int vlevel);
+int msm_spm_drv_write_seq_data(struct msm_spm_driver_data *dev,
+		uint8_t *cmd, uint32_t *offset);
+void msm_spm_drv_flush_seq_entry(struct msm_spm_driver_data *dev);
+int msm_spm_drv_set_spm_enable(struct msm_spm_driver_data *dev,
+		bool enable);
+int msm_spm_drv_set_phase(struct msm_spm_driver_data *dev,
+		unsigned int phase_cnt);
+#endif
diff --git a/arch/arm/mach-msm/subsystem_map.c b/arch/arm/mach-msm/subsystem_map.c
new file mode 100644
index 0000000..fcb8517
--- /dev/null
+++ b/arch/arm/mach-msm/subsystem_map.c
@@ -0,0 +1,541 @@
+/* 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
+ * 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/io.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/memory_alloc.h>
+#include <linux/module.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/msm_subsystem_map.h>
+
+struct msm_buffer_node {
+	struct rb_node rb_node_all_buffer;
+	struct rb_node rb_node_paddr;
+	struct msm_mapped_buffer *buf;
+	unsigned long length;
+	unsigned int *subsystems;
+	unsigned int nsubsys;
+	unsigned int phys;
+};
+
+static struct rb_root buffer_root;
+static struct rb_root phys_root;
+DEFINE_MUTEX(msm_buffer_mutex);
+
+static unsigned long subsystem_to_domain_tbl[] = {
+	VIDEO_DOMAIN,
+	VIDEO_DOMAIN,
+	CAMERA_DOMAIN,
+	DISPLAY_DOMAIN,
+	ROTATOR_DOMAIN,
+	0xFFFFFFFF
+};
+
+static struct msm_buffer_node *find_buffer(void *key)
+{
+	struct rb_root *root = &buffer_root;
+	struct rb_node *p = root->rb_node;
+
+	mutex_lock(&msm_buffer_mutex);
+
+	while (p) {
+		struct msm_buffer_node *node;
+
+		node = rb_entry(p, struct msm_buffer_node, rb_node_all_buffer);
+		if (node->buf->vaddr) {
+			if (key < node->buf->vaddr)
+				p = p->rb_left;
+			else if (key > node->buf->vaddr)
+				p = p->rb_right;
+			else {
+				mutex_unlock(&msm_buffer_mutex);
+				return node;
+			}
+		} else {
+			if (key < (void *)node->buf)
+				p = p->rb_left;
+			else if (key > (void *)node->buf)
+				p = p->rb_right;
+			else {
+				mutex_unlock(&msm_buffer_mutex);
+				return node;
+			}
+		}
+	}
+	mutex_unlock(&msm_buffer_mutex);
+	return NULL;
+}
+
+static struct msm_buffer_node *find_buffer_phys(unsigned int phys)
+{
+	struct rb_root *root = &phys_root;
+	struct rb_node *p = root->rb_node;
+
+	mutex_lock(&msm_buffer_mutex);
+
+	while (p) {
+		struct msm_buffer_node *node;
+
+		node = rb_entry(p, struct msm_buffer_node, rb_node_paddr);
+		if (phys < node->phys)
+			p = p->rb_left;
+		else if (phys > node->phys)
+			p = p->rb_right;
+		else {
+			mutex_unlock(&msm_buffer_mutex);
+			return node;
+		}
+	}
+	mutex_unlock(&msm_buffer_mutex);
+	return NULL;
+
+}
+
+static int add_buffer(struct msm_buffer_node *node)
+{
+	struct rb_root *root = &buffer_root;
+	struct rb_node **p = &root->rb_node;
+	struct rb_node *parent = NULL;
+	void *key;
+
+	if (node->buf->vaddr)
+		key = node->buf->vaddr;
+	else
+		key = node->buf;
+
+	mutex_lock(&msm_buffer_mutex);
+	while (*p) {
+		struct msm_buffer_node *tmp;
+		parent = *p;
+
+		tmp = rb_entry(parent, struct msm_buffer_node,
+						rb_node_all_buffer);
+
+		if (tmp->buf->vaddr) {
+			if (key < tmp->buf->vaddr)
+				p = &(*p)->rb_left;
+			else if (key > tmp->buf->vaddr)
+				p = &(*p)->rb_right;
+			else {
+				WARN(1, "tried to add buffer twice! buf = %p"
+					" vaddr = %p iova = %p", tmp->buf,
+					tmp->buf->vaddr,
+					tmp->buf->iova);
+				mutex_unlock(&msm_buffer_mutex);
+				return -EINVAL;
+
+			}
+		} else {
+			if (key < (void *)tmp->buf)
+				p = &(*p)->rb_left;
+			else if (key > (void *)tmp->buf)
+				p = &(*p)->rb_right;
+			else {
+				WARN(1, "tried to add buffer twice! buf = %p"
+					" vaddr = %p iova = %p", tmp->buf,
+					tmp->buf->vaddr,
+					tmp->buf->iova);
+				mutex_unlock(&msm_buffer_mutex);
+				return -EINVAL;
+			}
+		}
+	}
+	rb_link_node(&node->rb_node_all_buffer, parent, p);
+	rb_insert_color(&node->rb_node_all_buffer, root);
+	mutex_unlock(&msm_buffer_mutex);
+	return 0;
+}
+
+static int add_buffer_phys(struct msm_buffer_node *node)
+{
+	struct rb_root *root = &phys_root;
+	struct rb_node **p = &root->rb_node;
+	struct rb_node *parent = NULL;
+
+	mutex_lock(&msm_buffer_mutex);
+	while (*p) {
+		struct msm_buffer_node *tmp;
+		parent = *p;
+
+		tmp = rb_entry(parent, struct msm_buffer_node, rb_node_paddr);
+
+			if (node->phys < tmp->phys)
+				p = &(*p)->rb_left;
+			else if (node->phys > tmp->phys)
+				p = &(*p)->rb_right;
+			else {
+				WARN(1, "tried to add buffer twice! buf = %p"
+					" vaddr = %p iova = %p", tmp->buf,
+					tmp->buf->vaddr,
+					tmp->buf->iova);
+				mutex_unlock(&msm_buffer_mutex);
+				return -EINVAL;
+
+			}
+	}
+	rb_link_node(&node->rb_node_paddr, parent, p);
+	rb_insert_color(&node->rb_node_paddr, root);
+	mutex_unlock(&msm_buffer_mutex);
+	return 0;
+}
+
+static int remove_buffer(struct msm_buffer_node *victim_node)
+{
+	struct rb_root *root = &buffer_root;
+
+	if (!victim_node)
+		return -EINVAL;
+
+	mutex_lock(&msm_buffer_mutex);
+	rb_erase(&victim_node->rb_node_all_buffer, root);
+	mutex_unlock(&msm_buffer_mutex);
+	return 0;
+}
+
+static int remove_buffer_phys(struct msm_buffer_node *victim_node)
+{
+	struct rb_root *root = &phys_root;
+
+	if (!victim_node)
+		return -EINVAL;
+
+	mutex_lock(&msm_buffer_mutex);
+	rb_erase(&victim_node->rb_node_paddr, root);
+	mutex_unlock(&msm_buffer_mutex);
+	return 0;
+}
+
+static unsigned long msm_subsystem_get_domain_no(int subsys_id)
+{
+	if (subsys_id > INVALID_SUBSYS_ID && subsys_id <= MAX_SUBSYSTEM_ID &&
+	    subsys_id < ARRAY_SIZE(subsystem_to_domain_tbl))
+		return subsystem_to_domain_tbl[subsys_id];
+	else
+		return subsystem_to_domain_tbl[MAX_SUBSYSTEM_ID];
+}
+
+static unsigned long msm_subsystem_get_partition_no(int subsys_id)
+{
+	switch (subsys_id) {
+	case MSM_SUBSYSTEM_VIDEO_FWARE:
+		return VIDEO_FIRMWARE_POOL;
+	case MSM_SUBSYSTEM_VIDEO:
+		return VIDEO_MAIN_POOL;
+	case MSM_SUBSYSTEM_CAMERA:
+	case MSM_SUBSYSTEM_DISPLAY:
+	case MSM_SUBSYSTEM_ROTATOR:
+		return GEN_POOL;
+	default:
+		return 0xFFFFFFFF;
+	}
+}
+
+phys_addr_t msm_subsystem_check_iova_mapping(int subsys_id, unsigned long iova)
+{
+	struct iommu_domain *subsys_domain;
+
+	if (!msm_use_iommu())
+		/*
+		 * If there is no iommu, Just return the iova in this case.
+		 */
+		return iova;
+
+	subsys_domain = msm_get_iommu_domain(msm_subsystem_get_domain_no
+								(subsys_id));
+
+	return iommu_iova_to_phys(subsys_domain, iova);
+}
+EXPORT_SYMBOL(msm_subsystem_check_iova_mapping);
+
+struct msm_mapped_buffer *msm_subsystem_map_buffer(unsigned long phys,
+						unsigned int length,
+						unsigned int flags,
+						int *subsys_ids,
+						unsigned int nsubsys)
+{
+	struct msm_mapped_buffer *buf, *err;
+	struct msm_buffer_node *node;
+	int i = 0, j = 0, ret;
+	unsigned long iova_start = 0, temp_phys, temp_va = 0;
+	struct iommu_domain *d = NULL;
+	int map_size = length;
+
+	if (!((flags & MSM_SUBSYSTEM_MAP_KADDR) ||
+		(flags & MSM_SUBSYSTEM_MAP_IOVA))) {
+		pr_warn("%s: no mapping flag was specified. The caller"
+			" should explicitly specify what to map in the"
+			" flags.\n", __func__);
+		err = ERR_PTR(-EINVAL);
+		goto outret;
+	}
+
+	buf = kzalloc(sizeof(*buf), GFP_ATOMIC);
+	if (!buf) {
+		err = ERR_PTR(-ENOMEM);
+		goto outret;
+	}
+
+	node = kzalloc(sizeof(*node), GFP_ATOMIC);
+	if (!node) {
+		err = ERR_PTR(-ENOMEM);
+		goto outkfreebuf;
+	}
+
+	node->phys = phys;
+
+	if (flags & MSM_SUBSYSTEM_MAP_KADDR) {
+		struct msm_buffer_node *old_buffer;
+
+		old_buffer = find_buffer_phys(phys);
+
+		if (old_buffer) {
+			WARN(1, "%s: Attempting to map %lx twice in the kernel"
+				" virtual space. Don't do that!\n", __func__,
+				phys);
+			err = ERR_PTR(-EINVAL);
+			goto outkfreenode;
+		}
+
+		if (flags & MSM_SUBSYSTEM_MAP_CACHED)
+			buf->vaddr = ioremap(phys, length);
+		else if (flags & MSM_SUBSYSTEM_MAP_KADDR)
+			buf->vaddr = ioremap_nocache(phys, length);
+		else {
+			pr_warn("%s: no cachability flag was indicated. Caller"
+				" must specify a cachability flag.\n",
+				__func__);
+			err = ERR_PTR(-EINVAL);
+			goto outkfreenode;
+		}
+
+		if (!buf->vaddr) {
+			pr_err("%s: could not ioremap\n", __func__);
+			err = ERR_PTR(-EINVAL);
+			goto outkfreenode;
+		}
+
+		if (add_buffer_phys(node)) {
+			err = ERR_PTR(-EINVAL);
+			goto outiounmap;
+		}
+	}
+
+	if ((flags & MSM_SUBSYSTEM_MAP_IOVA) && subsys_ids) {
+		int min_align;
+
+		length = round_up(length, SZ_4K);
+
+		if (flags & MSM_SUBSYSTEM_MAP_IOMMU_2X)
+			map_size = 2 * length;
+		else
+			map_size = length;
+
+		buf->iova = kzalloc(sizeof(unsigned long)*nsubsys, GFP_ATOMIC);
+		if (!buf->iova) {
+			err = ERR_PTR(-ENOMEM);
+			goto outremovephys;
+		}
+
+		/*
+		 * The alignment must be specified as the exact value wanted
+		 * e.g. 8k alignment must pass (0x2000 | other flags)
+		 */
+		min_align = flags & ~(SZ_4K - 1);
+
+		for (i = 0; i < nsubsys; i++) {
+			unsigned int domain_no, partition_no;
+
+			if (!msm_use_iommu()) {
+				buf->iova[i] = phys;
+				continue;
+			}
+
+			d = msm_get_iommu_domain(
+				msm_subsystem_get_domain_no(subsys_ids[i]));
+
+			if (!d) {
+				pr_err("%s: could not get domain for subsystem"
+					" %d\n", __func__, subsys_ids[i]);
+				continue;
+			}
+
+			domain_no = msm_subsystem_get_domain_no(subsys_ids[i]);
+			partition_no = msm_subsystem_get_partition_no(
+								subsys_ids[i]);
+
+			ret = msm_allocate_iova_address(domain_no,
+						partition_no,
+						map_size,
+						max(min_align, SZ_4K),
+						&iova_start);
+
+			if (ret) {
+				pr_err("%s: could not allocate iova address\n",
+					__func__);
+				continue;
+			}
+
+			temp_phys = phys;
+			temp_va = iova_start;
+			for (j = length; j > 0; j -= SZ_4K,
+					temp_phys += SZ_4K,
+					temp_va += SZ_4K) {
+				ret = iommu_map(d, temp_va, temp_phys,
+						SZ_4K,
+						(IOMMU_READ | IOMMU_WRITE));
+				if (ret) {
+					pr_err("%s: could not map iommu for"
+						" domain %p, iova %lx,"
+						" phys %lx\n", __func__, d,
+						temp_va, temp_phys);
+					err = ERR_PTR(-EINVAL);
+					goto outdomain;
+				}
+			}
+			buf->iova[i] = iova_start;
+
+			if (flags & MSM_SUBSYSTEM_MAP_IOMMU_2X)
+				msm_iommu_map_extra
+					(d, temp_va, length, SZ_4K,
+					(IOMMU_READ | IOMMU_WRITE));
+		}
+
+	}
+
+	node->buf = buf;
+	node->subsystems = subsys_ids;
+	node->length = map_size;
+	node->nsubsys = nsubsys;
+
+	if (add_buffer(node)) {
+		err = ERR_PTR(-EINVAL);
+		goto outiova;
+	}
+
+	return buf;
+
+outiova:
+	if (flags & MSM_SUBSYSTEM_MAP_IOVA)
+		iommu_unmap(d, temp_va, SZ_4K);
+outdomain:
+	if (flags & MSM_SUBSYSTEM_MAP_IOVA) {
+		/* Unmap the rest of the current domain, i */
+		for (j -= SZ_4K, temp_va -= SZ_4K;
+			j > 0; temp_va -= SZ_4K, j -= SZ_4K)
+			iommu_unmap(d, temp_va, SZ_4K);
+
+		/* Unmap all the other domains */
+		for (i--; i >= 0; i--) {
+			unsigned int domain_no, partition_no;
+			if (!msm_use_iommu())
+				continue;
+			domain_no = msm_subsystem_get_domain_no(subsys_ids[i]);
+			partition_no = msm_subsystem_get_partition_no(
+								subsys_ids[i]);
+
+			temp_va = buf->iova[i];
+			for (j = length; j > 0; j -= SZ_4K,
+						temp_va += SZ_4K)
+				iommu_unmap(d, temp_va, SZ_4K);
+			msm_free_iova_address(buf->iova[i], domain_no,
+					partition_no, length);
+		}
+
+		kfree(buf->iova);
+	}
+
+outremovephys:
+	if (flags & MSM_SUBSYSTEM_MAP_KADDR)
+		remove_buffer_phys(node);
+outiounmap:
+	if (flags & MSM_SUBSYSTEM_MAP_KADDR)
+		iounmap(buf->vaddr);
+outkfreenode:
+	kfree(node);
+outkfreebuf:
+	kfree(buf);
+outret:
+	return err;
+}
+EXPORT_SYMBOL(msm_subsystem_map_buffer);
+
+int msm_subsystem_unmap_buffer(struct msm_mapped_buffer *buf)
+{
+	struct msm_buffer_node *node;
+	int i, j, ret;
+	unsigned long temp_va;
+
+	if (IS_ERR_OR_NULL(buf))
+		goto out;
+
+	if (buf->vaddr)
+		node = find_buffer(buf->vaddr);
+	else
+		node = find_buffer(buf);
+
+	if (!node)
+		goto out;
+
+	if (node->buf != buf) {
+		pr_err("%s: caller must pass in the same buffer structure"
+			" returned from map_buffer when freeding\n", __func__);
+		goto out;
+	}
+
+	if (buf->iova) {
+		if (msm_use_iommu())
+			for (i = 0; i < node->nsubsys; i++) {
+				struct iommu_domain *subsys_domain;
+				unsigned int domain_no, partition_no;
+
+				subsys_domain = msm_get_iommu_domain(
+						msm_subsystem_get_domain_no(
+						node->subsystems[i]));
+
+				domain_no = msm_subsystem_get_domain_no(
+							node->subsystems[i]);
+				partition_no = msm_subsystem_get_partition_no(
+							node->subsystems[i]);
+
+				temp_va = buf->iova[i];
+				for (j = node->length; j > 0; j -= SZ_4K,
+					temp_va += SZ_4K) {
+					ret = iommu_unmap(subsys_domain,
+							temp_va,
+							SZ_4K);
+					WARN(ret, "iommu_unmap returned a "
+						" non-zero value.\n");
+				}
+				msm_free_iova_address(buf->iova[i], domain_no,
+						partition_no, node->length);
+			}
+		kfree(buf->iova);
+
+	}
+
+	if (buf->vaddr) {
+		remove_buffer_phys(node);
+		iounmap(buf->vaddr);
+	}
+
+	remove_buffer(node);
+	kfree(node);
+	kfree(buf);
+
+	return 0;
+out:
+	return -EINVAL;
+}
+EXPORT_SYMBOL(msm_subsystem_unmap_buffer);
diff --git a/arch/arm/mach-msm/subsystem_notif.c b/arch/arm/mach-msm/subsystem_notif.c
new file mode 100644
index 0000000..f7db54c
--- /dev/null
+++ b/arch/arm/mach-msm/subsystem_notif.c
@@ -0,0 +1,222 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * Subsystem Notifier -- Provides notifications
+ * of subsys events.
+ *
+ * Use subsys_notif_register_notifier to register for notifications
+ * and subsys_notif_queue_notification to send notifications.
+ *
+ */
+
+#include <linux/notifier.h>
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <linux/workqueue.h>
+#include <linux/stringify.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include <mach/subsystem_notif.h>
+
+struct subsys_notif_info {
+	char name[50];
+	struct srcu_notifier_head subsys_notif_rcvr_list;
+	struct list_head list;
+};
+
+static LIST_HEAD(subsystem_list);
+static DEFINE_MUTEX(notif_lock);
+static DEFINE_MUTEX(notif_add_lock);
+
+#if defined(SUBSYS_RESTART_DEBUG)
+static void subsys_notif_reg_test_notifier(const char *);
+#endif
+
+static struct subsys_notif_info *_notif_find_subsys(const char *subsys_name)
+{
+	struct subsys_notif_info *subsys;
+
+	mutex_lock(&notif_lock);
+	list_for_each_entry(subsys, &subsystem_list, list)
+		if (!strncmp(subsys->name, subsys_name,
+				ARRAY_SIZE(subsys->name))) {
+			mutex_unlock(&notif_lock);
+			return subsys;
+		}
+	mutex_unlock(&notif_lock);
+
+	return NULL;
+}
+
+void *subsys_notif_register_notifier(
+			const char *subsys_name, struct notifier_block *nb)
+{
+	int ret;
+	struct subsys_notif_info *subsys = _notif_find_subsys(subsys_name);
+
+	if (!subsys) {
+
+		/* Possible first time reference to this subsystem. Add it. */
+		subsys = (struct subsys_notif_info *)
+				subsys_notif_add_subsys(subsys_name);
+
+		if (!subsys)
+			return ERR_PTR(-EINVAL);
+	}
+
+	ret = srcu_notifier_chain_register(
+		&subsys->subsys_notif_rcvr_list, nb);
+
+	if (ret < 0)
+		return ERR_PTR(ret);
+
+	return subsys;
+}
+EXPORT_SYMBOL(subsys_notif_register_notifier);
+
+int subsys_notif_unregister_notifier(void *subsys_handle,
+				struct notifier_block *nb)
+{
+	int ret;
+	struct subsys_notif_info *subsys =
+			(struct subsys_notif_info *)subsys_handle;
+
+	if (!subsys)
+		return -EINVAL;
+
+	ret = srcu_notifier_chain_unregister(
+		&subsys->subsys_notif_rcvr_list, nb);
+
+	return ret;
+}
+EXPORT_SYMBOL(subsys_notif_unregister_notifier);
+
+void *subsys_notif_add_subsys(const char *subsys_name)
+{
+	struct subsys_notif_info *subsys = NULL;
+
+	if (!subsys_name)
+		goto done;
+
+	mutex_lock(&notif_add_lock);
+
+	subsys = _notif_find_subsys(subsys_name);
+
+	if (subsys) {
+		mutex_unlock(&notif_add_lock);
+		goto done;
+	}
+
+	subsys = kmalloc(sizeof(struct subsys_notif_info), GFP_KERNEL);
+
+	if (!subsys) {
+		mutex_unlock(&notif_add_lock);
+		return ERR_PTR(-EINVAL);
+	}
+
+	strlcpy(subsys->name, subsys_name, ARRAY_SIZE(subsys->name));
+
+	srcu_init_notifier_head(&subsys->subsys_notif_rcvr_list);
+
+	INIT_LIST_HEAD(&subsys->list);
+
+	mutex_lock(&notif_lock);
+	list_add_tail(&subsys->list, &subsystem_list);
+	mutex_unlock(&notif_lock);
+
+	#if defined(SUBSYS_RESTART_DEBUG)
+	subsys_notif_reg_test_notifier(subsys->name);
+	#endif
+
+	mutex_unlock(&notif_add_lock);
+
+done:
+	return subsys;
+}
+EXPORT_SYMBOL(subsys_notif_add_subsys);
+
+int subsys_notif_queue_notification(void *subsys_handle,
+					enum subsys_notif_type notif_type)
+{
+	int ret = 0;
+	struct subsys_notif_info *subsys =
+		(struct subsys_notif_info *) subsys_handle;
+
+	if (!subsys)
+		return -EINVAL;
+
+	if (notif_type < 0 || notif_type >= SUBSYS_NOTIF_TYPE_COUNT)
+		return -EINVAL;
+
+	ret = srcu_notifier_call_chain(
+		&subsys->subsys_notif_rcvr_list, notif_type,
+		(void *)subsys);
+
+	return ret;
+}
+EXPORT_SYMBOL(subsys_notif_queue_notification);
+
+#if defined(SUBSYS_RESTART_DEBUG)
+static const char *notif_to_string(enum subsys_notif_type notif_type)
+{
+	switch (notif_type) {
+
+	case	SUBSYS_BEFORE_SHUTDOWN:
+		return __stringify(SUBSYS_BEFORE_SHUTDOWN);
+
+	case	SUBSYS_AFTER_SHUTDOWN:
+		return __stringify(SUBSYS_AFTER_SHUTDOWN);
+
+	case	SUBSYS_BEFORE_POWERUP:
+		return __stringify(SUBSYS_BEFORE_POWERUP);
+
+	case	SUBSYS_AFTER_POWERUP:
+		return __stringify(SUBSYS_AFTER_POWERUP);
+
+	default:
+		return "unknown";
+	}
+}
+
+static int subsys_notifier_test_call(struct notifier_block *this,
+				  unsigned long code,
+				  void *data)
+{
+	switch (code) {
+
+	default:
+		printk(KERN_WARNING "%s: Notification %s from subsystem %p\n",
+			__func__, notif_to_string(code), data);
+	break;
+
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block nb = {
+	.notifier_call = subsys_notifier_test_call,
+};
+
+static void subsys_notif_reg_test_notifier(const char *subsys_name)
+{
+	void *handle = subsys_notif_register_notifier(subsys_name, &nb);
+	printk(KERN_WARNING "%s: Registered test notifier, handle=%p",
+			__func__, handle);
+}
+#endif
+
+MODULE_DESCRIPTION("Subsystem Restart Notifier");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
new file mode 100644
index 0000000..027aa5b
--- /dev/null
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -0,0 +1,588 @@
+/* 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
+ * 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.
+ */
+
+#define pr_fmt(fmt) "subsys-restart: %s(): " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/kthread.h>
+#include <linux/time.h>
+#include <linux/wakelock.h>
+#include <linux/suspend.h>
+
+#include <asm/current.h>
+
+#include <mach/peripheral-loader.h>
+#include <mach/scm.h>
+#include <mach/socinfo.h>
+#include <mach/subsystem_notif.h>
+#include <mach/subsystem_restart.h>
+
+#include "smd_private.h"
+
+struct subsys_soc_restart_order {
+	const char * const *subsystem_list;
+	int count;
+
+	struct mutex shutdown_lock;
+	struct mutex powerup_lock;
+	struct subsys_data *subsys_ptrs[];
+};
+
+struct restart_wq_data {
+	struct subsys_data *subsys;
+	struct wake_lock ssr_wake_lock;
+	char wlname[64];
+	int use_restart_order;
+	struct work_struct work;
+};
+
+struct restart_log {
+	struct timeval time;
+	struct subsys_data *subsys;
+	struct list_head list;
+};
+
+static int restart_level;
+static int enable_ramdumps;
+struct workqueue_struct *ssr_wq;
+
+static LIST_HEAD(restart_log_list);
+static LIST_HEAD(subsystem_list);
+static DEFINE_MUTEX(subsystem_list_lock);
+static DEFINE_MUTEX(soc_order_reg_lock);
+static DEFINE_MUTEX(restart_log_mutex);
+
+/* SOC specific restart orders go here */
+
+#define DEFINE_SINGLE_RESTART_ORDER(name, order)		\
+	static struct subsys_soc_restart_order __##name = {	\
+		.subsystem_list = order,			\
+		.count = ARRAY_SIZE(order),			\
+		.subsys_ptrs = {[ARRAY_SIZE(order)] = NULL}	\
+	};							\
+	static struct subsys_soc_restart_order *name[] = {      \
+		&__##name,					\
+	}
+
+/* MSM 8x60 restart ordering info */
+static const char * const _order_8x60_all[] = {
+	"external_modem",  "modem", "lpass"
+};
+DEFINE_SINGLE_RESTART_ORDER(orders_8x60_all, _order_8x60_all);
+
+static const char * const _order_8x60_modems[] = {"external_modem", "modem"};
+DEFINE_SINGLE_RESTART_ORDER(orders_8x60_modems, _order_8x60_modems);
+
+/* MSM 8960 restart ordering info */
+static const char * const order_8960[] = {"modem", "lpass"};
+
+static struct subsys_soc_restart_order restart_orders_8960_one = {
+	.subsystem_list = order_8960,
+	.count = ARRAY_SIZE(order_8960),
+	.subsys_ptrs = {[ARRAY_SIZE(order_8960)] = NULL}
+	};
+
+static struct subsys_soc_restart_order *restart_orders_8960[] = {
+	&restart_orders_8960_one,
+};
+
+/* These will be assigned to one of the sets above after
+ * runtime SoC identification.
+ */
+static struct subsys_soc_restart_order **restart_orders;
+static int n_restart_orders;
+
+module_param(enable_ramdumps, int, S_IRUGO | S_IWUSR);
+
+static struct subsys_soc_restart_order *_update_restart_order(
+		struct subsys_data *subsys);
+
+int get_restart_level()
+{
+	return restart_level;
+}
+EXPORT_SYMBOL(get_restart_level);
+
+static int restart_level_set(const char *val, struct kernel_param *kp)
+{
+	int ret;
+	int old_val = restart_level;
+
+	if (cpu_is_msm9615()) {
+		pr_err("Only Phase 1 subsystem restart is supported\n");
+		return -EINVAL;
+	}
+
+	ret = param_set_int(val, kp);
+	if (ret)
+		return ret;
+
+	switch (restart_level) {
+
+	case RESET_SOC:
+	case RESET_SUBSYS_COUPLED:
+	case RESET_SUBSYS_INDEPENDENT:
+		pr_info("Phase %d behavior activated.\n", restart_level);
+	break;
+
+	default:
+		restart_level = old_val;
+		return -EINVAL;
+	break;
+
+	}
+	return 0;
+}
+
+module_param_call(restart_level, restart_level_set, param_get_int,
+			&restart_level, 0644);
+
+static struct subsys_data *_find_subsystem(const char *subsys_name)
+{
+	struct subsys_data *subsys;
+
+	mutex_lock(&subsystem_list_lock);
+	list_for_each_entry(subsys, &subsystem_list, list)
+		if (!strncmp(subsys->name, subsys_name,
+				SUBSYS_NAME_MAX_LENGTH)) {
+			mutex_unlock(&subsystem_list_lock);
+			return subsys;
+		}
+	mutex_unlock(&subsystem_list_lock);
+
+	return NULL;
+}
+
+static struct subsys_soc_restart_order *_update_restart_order(
+		struct subsys_data *subsys)
+{
+	int i, j;
+
+	if (!subsys)
+		return NULL;
+
+	if (!subsys->name)
+		return NULL;
+
+	mutex_lock(&soc_order_reg_lock);
+	for (j = 0; j < n_restart_orders; j++) {
+		for (i = 0; i < restart_orders[j]->count; i++)
+			if (!strncmp(restart_orders[j]->subsystem_list[i],
+				subsys->name, SUBSYS_NAME_MAX_LENGTH)) {
+
+					restart_orders[j]->subsys_ptrs[i] =
+						subsys;
+					mutex_unlock(&soc_order_reg_lock);
+					return restart_orders[j];
+			}
+	}
+
+	mutex_unlock(&soc_order_reg_lock);
+
+	return NULL;
+}
+
+static void _send_notification_to_order(struct subsys_data
+			**restart_list, int count,
+			enum subsys_notif_type notif_type)
+{
+	int i;
+
+	for (i = 0; i < count; i++)
+		if (restart_list[i])
+			subsys_notif_queue_notification(
+				restart_list[i]->notif_handle, notif_type);
+}
+
+static int max_restarts;
+module_param(max_restarts, int, 0644);
+
+static long max_history_time = 3600;
+module_param(max_history_time, long, 0644);
+
+static void do_epoch_check(struct subsys_data *subsys)
+{
+	int n = 0;
+	struct timeval *time_first = NULL, *curr_time;
+	struct restart_log *r_log, *temp;
+	static int max_restarts_check;
+	static long max_history_time_check;
+
+	mutex_lock(&restart_log_mutex);
+
+	max_restarts_check = max_restarts;
+	max_history_time_check = max_history_time;
+
+	/* Check if epoch checking is enabled */
+	if (!max_restarts_check)
+		goto out;
+
+	r_log = kmalloc(sizeof(struct restart_log), GFP_KERNEL);
+	if (!r_log)
+		goto out;
+	r_log->subsys = subsys;
+	do_gettimeofday(&r_log->time);
+	curr_time = &r_log->time;
+	INIT_LIST_HEAD(&r_log->list);
+
+	list_add_tail(&r_log->list, &restart_log_list);
+
+	list_for_each_entry_safe(r_log, temp, &restart_log_list, list) {
+
+		if ((curr_time->tv_sec - r_log->time.tv_sec) >
+				max_history_time_check) {
+
+			pr_debug("Deleted node with restart_time = %ld\n",
+					r_log->time.tv_sec);
+			list_del(&r_log->list);
+			kfree(r_log);
+			continue;
+		}
+		if (!n) {
+			time_first = &r_log->time;
+			pr_debug("Time_first: %ld\n", time_first->tv_sec);
+		}
+		n++;
+		pr_debug("Restart_time: %ld\n", r_log->time.tv_sec);
+	}
+
+	if (time_first && n >= max_restarts_check) {
+		if ((curr_time->tv_sec - time_first->tv_sec) <
+				max_history_time_check)
+			panic("Subsystems have crashed %d times in less than "
+				"%ld seconds!", max_restarts_check,
+				max_history_time_check);
+	}
+
+out:
+	mutex_unlock(&restart_log_mutex);
+}
+
+static void subsystem_restart_wq_func(struct work_struct *work)
+{
+	struct restart_wq_data *r_work = container_of(work,
+						struct restart_wq_data, work);
+	struct subsys_data **restart_list;
+	struct subsys_data *subsys = r_work->subsys;
+	struct subsys_soc_restart_order *soc_restart_order = NULL;
+
+	struct mutex *powerup_lock;
+	struct mutex *shutdown_lock;
+
+	int i;
+	int restart_list_count = 0;
+
+	if (r_work->use_restart_order)
+		soc_restart_order = subsys->restart_order;
+
+	/* It's OK to not take the registration lock at this point.
+	 * This is because the subsystem list inside the relevant
+	 * restart order is not being traversed.
+	 */
+	if (!soc_restart_order) {
+		restart_list = subsys->single_restart_list;
+		restart_list_count = 1;
+		powerup_lock = &subsys->powerup_lock;
+		shutdown_lock = &subsys->shutdown_lock;
+	} else {
+		restart_list = soc_restart_order->subsys_ptrs;
+		restart_list_count = soc_restart_order->count;
+		powerup_lock = &soc_restart_order->powerup_lock;
+		shutdown_lock = &soc_restart_order->shutdown_lock;
+	}
+
+	pr_debug("[%p]: Attempting to get shutdown lock!\n", current);
+
+	/* Try to acquire shutdown_lock. If this fails, these subsystems are
+	 * already being restarted - return.
+	 */
+	if (!mutex_trylock(shutdown_lock))
+		goto out;
+
+	pr_debug("[%p]: Attempting to get powerup lock!\n", current);
+
+	/* Now that we've acquired the shutdown lock, either we're the first to
+	 * restart these subsystems or some other thread is doing the powerup
+	 * sequence for these subsystems. In the latter case, panic and bail
+	 * out, since a subsystem died in its powerup sequence.
+	 */
+	if (!mutex_trylock(powerup_lock))
+		panic("%s[%p]: Subsystem died during powerup!",
+						__func__, current);
+
+	do_epoch_check(subsys);
+
+	/* Now it is necessary to take the registration lock. This is because
+	 * the subsystem list in the SoC restart order will be traversed
+	 * and it shouldn't be changed until _this_ restart sequence completes.
+	 */
+	mutex_lock(&soc_order_reg_lock);
+
+	pr_debug("[%p]: Starting restart sequence for %s\n", current,
+			r_work->subsys->name);
+
+	_send_notification_to_order(restart_list,
+				restart_list_count,
+				SUBSYS_BEFORE_SHUTDOWN);
+
+	for (i = 0; i < restart_list_count; i++) {
+
+		if (!restart_list[i])
+			continue;
+
+		pr_info("[%p]: Shutting down %s\n", current,
+			restart_list[i]->name);
+
+		if (restart_list[i]->shutdown(subsys) < 0)
+			panic("subsys-restart: %s[%p]: Failed to shutdown %s!",
+				__func__, current, restart_list[i]->name);
+	}
+
+	_send_notification_to_order(restart_list, restart_list_count,
+				SUBSYS_AFTER_SHUTDOWN);
+
+	/* Now that we've finished shutting down these subsystems, release the
+	 * shutdown lock. If a subsystem restart request comes in for a
+	 * subsystem in _this_ restart order after the unlock below, and
+	 * before the powerup lock is released, panic and bail out.
+	 */
+	mutex_unlock(shutdown_lock);
+
+	/* Collect ram dumps for all subsystems in order here */
+	for (i = 0; i < restart_list_count; i++) {
+		if (!restart_list[i])
+			continue;
+
+		if (restart_list[i]->ramdump)
+			if (restart_list[i]->ramdump(enable_ramdumps,
+							subsys) < 0)
+				pr_warn("%s[%p]: Ramdump failed.\n",
+						restart_list[i]->name, current);
+	}
+
+	_send_notification_to_order(restart_list,
+			restart_list_count,
+			SUBSYS_BEFORE_POWERUP);
+
+	for (i = restart_list_count - 1; i >= 0; i--) {
+
+		if (!restart_list[i])
+			continue;
+
+		pr_info("[%p]: Powering up %s\n", current,
+					restart_list[i]->name);
+
+		if (restart_list[i]->powerup(subsys) < 0)
+			panic("%s[%p]: Failed to powerup %s!", __func__,
+				current, restart_list[i]->name);
+	}
+
+	_send_notification_to_order(restart_list,
+				restart_list_count,
+				SUBSYS_AFTER_POWERUP);
+
+	pr_info("[%p]: Restart sequence for %s completed.\n",
+			current, r_work->subsys->name);
+
+	mutex_unlock(powerup_lock);
+
+	mutex_unlock(&soc_order_reg_lock);
+
+	pr_debug("[%p]: Released powerup lock!\n", current);
+
+out:
+	wake_unlock(&r_work->ssr_wake_lock);
+	wake_lock_destroy(&r_work->ssr_wake_lock);
+	kfree(r_work);
+}
+
+static void __subsystem_restart(struct subsys_data *subsys)
+{
+	struct restart_wq_data *data = NULL;
+	int rc;
+
+	pr_debug("Restarting %s [level=%d]!\n", subsys->name,
+				restart_level);
+
+	data = kzalloc(sizeof(struct restart_wq_data), GFP_ATOMIC);
+	if (!data)
+		panic("%s: Unable to allocate memory to restart %s.",
+		      __func__, subsys->name);
+
+	data->subsys = subsys;
+
+	if (restart_level != RESET_SUBSYS_INDEPENDENT)
+		data->use_restart_order = 1;
+
+	snprintf(data->wlname, sizeof(data->wlname), "ssr(%s)", subsys->name);
+	wake_lock_init(&data->ssr_wake_lock, WAKE_LOCK_SUSPEND, data->wlname);
+	wake_lock(&data->ssr_wake_lock);
+
+	INIT_WORK(&data->work, subsystem_restart_wq_func);
+	rc = queue_work(ssr_wq, &data->work);
+	if (rc < 0)
+		panic("%s: Unable to schedule work to restart %s (%d).",
+		     __func__, subsys->name, rc);
+}
+
+int subsystem_restart(const char *subsys_name)
+{
+	struct subsys_data *subsys;
+
+	if (!subsys_name) {
+		pr_err("Invalid subsystem name.\n");
+		return -EINVAL;
+	}
+
+	pr_info("Restart sequence requested for %s, restart_level = %d.\n",
+		subsys_name, restart_level);
+
+	/* List of subsystems is protected by a lock. New subsystems can
+	 * still come in.
+	 */
+	subsys = _find_subsystem(subsys_name);
+
+	if (!subsys) {
+		pr_warn("Unregistered subsystem %s!\n", subsys_name);
+		return -EINVAL;
+	}
+
+	switch (restart_level) {
+
+	case RESET_SUBSYS_COUPLED:
+	case RESET_SUBSYS_INDEPENDENT:
+		__subsystem_restart(subsys);
+		break;
+
+	case RESET_SOC:
+		panic("subsys-restart: Resetting the SoC - %s crashed.",
+			subsys->name);
+		break;
+
+	default:
+		panic("subsys-restart: Unknown restart level!\n");
+	break;
+
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(subsystem_restart);
+
+int ssr_register_subsystem(struct subsys_data *subsys)
+{
+	if (!subsys)
+		goto err;
+
+	if (!subsys->name)
+		goto err;
+
+	if (!subsys->powerup || !subsys->shutdown)
+		goto err;
+
+	subsys->notif_handle = subsys_notif_add_subsys(subsys->name);
+	subsys->restart_order = _update_restart_order(subsys);
+	subsys->single_restart_list[0] = subsys;
+
+	mutex_init(&subsys->shutdown_lock);
+	mutex_init(&subsys->powerup_lock);
+
+	mutex_lock(&subsystem_list_lock);
+	list_add(&subsys->list, &subsystem_list);
+	mutex_unlock(&subsystem_list_lock);
+
+	return 0;
+
+err:
+	return -EINVAL;
+}
+EXPORT_SYMBOL(ssr_register_subsystem);
+
+static int ssr_panic_handler(struct notifier_block *this,
+				unsigned long event, void *ptr)
+{
+	struct subsys_data *subsys;
+
+	list_for_each_entry(subsys, &subsystem_list, list)
+		if (subsys->crash_shutdown)
+			subsys->crash_shutdown(subsys);
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block panic_nb = {
+	.notifier_call  = ssr_panic_handler,
+};
+
+static int __init ssr_init_soc_restart_orders(void)
+{
+	int i;
+
+	atomic_notifier_chain_register(&panic_notifier_list,
+			&panic_nb);
+
+	if (cpu_is_msm8x60()) {
+		for (i = 0; i < ARRAY_SIZE(orders_8x60_all); i++) {
+			mutex_init(&orders_8x60_all[i]->powerup_lock);
+			mutex_init(&orders_8x60_all[i]->shutdown_lock);
+		}
+
+		for (i = 0; i < ARRAY_SIZE(orders_8x60_modems); i++) {
+			mutex_init(&orders_8x60_modems[i]->powerup_lock);
+			mutex_init(&orders_8x60_modems[i]->shutdown_lock);
+		}
+
+		restart_orders = orders_8x60_all;
+		n_restart_orders = ARRAY_SIZE(orders_8x60_all);
+	}
+
+	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm9615() ||
+			cpu_is_apq8064()) {
+		restart_orders = restart_orders_8960;
+		n_restart_orders = ARRAY_SIZE(restart_orders_8960);
+	}
+
+	if (restart_orders == NULL || n_restart_orders < 1) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int __init subsys_restart_init(void)
+{
+	int ret = 0;
+
+	restart_level = RESET_SOC;
+
+	ssr_wq = alloc_workqueue("ssr_wq", 0, 0);
+
+	if (!ssr_wq)
+		panic("Couldn't allocate workqueue for subsystem restart.\n");
+
+	ret = ssr_init_soc_restart_orders();
+
+	return ret;
+}
+
+arch_initcall(subsys_restart_init);
+
+MODULE_DESCRIPTION("Subsystem Restart Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/sysmon.c b/arch/arm/mach-msm/sysmon.c
new file mode 100644
index 0000000..1305bd1
--- /dev/null
+++ b/arch/arm/mach-msm/sysmon.c
@@ -0,0 +1,304 @@
+/*
+ * 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
+ * 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.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/completion.h>
+#include <linux/platform_device.h>
+
+#include <mach/msm_smd.h>
+#include <mach/subsystem_notif.h>
+
+#include "hsic_sysmon.h"
+#include "sysmon.h"
+
+#define TX_BUF_SIZE	50
+#define RX_BUF_SIZE	500
+#define TIMEOUT_MS	5000
+
+enum transports {
+	TRANSPORT_SMD,
+	TRANSPORT_HSIC,
+};
+
+struct sysmon_subsys {
+	struct mutex		lock;
+	struct smd_channel	*chan;
+	bool			chan_open;
+	struct completion	resp_ready;
+	char			rx_buf[RX_BUF_SIZE];
+	enum transports		transport;
+};
+
+static struct sysmon_subsys subsys[SYSMON_NUM_SS] = {
+	[SYSMON_SS_MODEM].transport     = TRANSPORT_SMD,
+	[SYSMON_SS_LPASS].transport     = TRANSPORT_SMD,
+	[SYSMON_SS_WCNSS].transport     = TRANSPORT_SMD,
+	[SYSMON_SS_DSPS].transport      = TRANSPORT_SMD,
+	[SYSMON_SS_Q6FW].transport      = TRANSPORT_SMD,
+	[SYSMON_SS_EXT_MODEM].transport = TRANSPORT_HSIC,
+};
+
+static const char *notif_name[SUBSYS_NOTIF_TYPE_COUNT] = {
+	[SUBSYS_BEFORE_SHUTDOWN] = "before_shutdown",
+	[SUBSYS_AFTER_SHUTDOWN]  = "after_shutdown",
+	[SUBSYS_BEFORE_POWERUP]  = "before_powerup",
+	[SUBSYS_AFTER_POWERUP]   = "after_powerup",
+};
+
+static int sysmon_send_smd(struct sysmon_subsys *ss, const char *tx_buf,
+			   size_t len)
+{
+	int ret;
+
+	if (!ss->chan_open)
+		return -ENODEV;
+
+	init_completion(&ss->resp_ready);
+	pr_debug("Sending SMD message: %s\n", tx_buf);
+	smd_write(ss->chan, tx_buf, len);
+	ret = wait_for_completion_timeout(&ss->resp_ready,
+				  msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static int sysmon_send_hsic(struct sysmon_subsys *ss, const char *tx_buf,
+			    size_t len)
+{
+	int ret;
+	size_t actual_len;
+
+	pr_debug("Sending HSIC message: %s\n", tx_buf);
+	ret = hsic_sysmon_write(HSIC_SYSMON_DEV_EXT_MODEM,
+				tx_buf, len, TIMEOUT_MS);
+	if (ret)
+		return ret;
+	ret = hsic_sysmon_read(HSIC_SYSMON_DEV_EXT_MODEM, ss->rx_buf,
+			       ARRAY_SIZE(ss->rx_buf), &actual_len, TIMEOUT_MS);
+	return ret;
+}
+
+static int sysmon_send_msg(struct sysmon_subsys *ss, const char *tx_buf,
+			   size_t len)
+{
+	int ret;
+
+	switch (ss->transport) {
+	case TRANSPORT_SMD:
+		ret = sysmon_send_smd(ss, tx_buf, len);
+		break;
+	case TRANSPORT_HSIC:
+		ret = sysmon_send_hsic(ss, tx_buf, len);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	if (!ret)
+		pr_debug("Received response: %s\n", ss->rx_buf);
+
+	return ret;
+}
+
+/**
+ * sysmon_send_event() - Notify a subsystem of another's state change
+ * @dest_ss:	ID of subsystem the notification should be sent to
+ * @event_ss:	String name of the subsystem that generated the notification
+ * @notif:	ID of the notification type (ex. SUBSYS_BEFORE_SHUTDOWN)
+ *
+ * Returns 0 for success, -EINVAL for invalid destination or notification IDs,
+ * -ENODEV if the transport channel is not open, -ETIMEDOUT if the destination
+ * subsystem does not respond, and -ENOSYS if the destination subsystem
+ * responds, but with something other than an acknowledgement.
+ *
+ * If CONFIG_MSM_SYSMON_COMM is not defined, always return success (0).
+ */
+int sysmon_send_event(enum subsys_id dest_ss, const char *event_ss,
+		      enum subsys_notif_type notif)
+{
+	struct sysmon_subsys *ss = &subsys[dest_ss];
+	char tx_buf[TX_BUF_SIZE];
+	int ret;
+
+	if (dest_ss < 0 || dest_ss >= SYSMON_NUM_SS ||
+	    notif < 0 || notif >= SUBSYS_NOTIF_TYPE_COUNT ||
+	    event_ss == NULL)
+		return -EINVAL;
+
+	snprintf(tx_buf, ARRAY_SIZE(tx_buf), "ssr:%s:%s", event_ss,
+		 notif_name[notif]);
+
+	mutex_lock(&ss->lock);
+	ret = sysmon_send_msg(ss, tx_buf, strlen(tx_buf));
+	if (ret)
+		goto out;
+
+	if (strncmp(ss->rx_buf, "ssr:ack", ARRAY_SIZE(ss->rx_buf)))
+		ret = -ENOSYS;
+out:
+	mutex_unlock(&ss->lock);
+	return ret;
+}
+
+/**
+ * sysmon_get_reason() - Retrieve failure reason from a subsystem.
+ * @dest_ss:	ID of subsystem to query
+ * @buf:	Caller-allocated buffer for the returned NUL-terminated reason
+ * @len:	Length of @buf
+ *
+ * Returns 0 for success, -EINVAL for an invalid destination, -ENODEV if
+ * the SMD transport channel is not open, -ETIMEDOUT if the destination
+ * subsystem does not respond, and -ENOSYS if the destination subsystem
+ * responds with something unexpected.
+ *
+ * If CONFIG_MSM_SYSMON_COMM is not defined, always return success (0).
+ */
+int sysmon_get_reason(enum subsys_id dest_ss, char *buf, size_t len)
+{
+	struct sysmon_subsys *ss = &subsys[dest_ss];
+	const char tx_buf[] = "ssr:retrieve:sfr";
+	const char expect[] = "ssr:return:";
+	size_t prefix_len = ARRAY_SIZE(expect) - 1;
+	int ret;
+
+	if (dest_ss < 0 || dest_ss >= SYSMON_NUM_SS ||
+	    buf == NULL || len == 0)
+		return -EINVAL;
+
+	mutex_lock(&ss->lock);
+	ret = sysmon_send_msg(ss, tx_buf, ARRAY_SIZE(tx_buf));
+	if (ret)
+		goto out;
+
+	if (strncmp(ss->rx_buf, expect, prefix_len)) {
+		ret = -ENOSYS;
+		goto out;
+	}
+	strlcpy(buf, ss->rx_buf + prefix_len, len);
+out:
+	mutex_unlock(&ss->lock);
+	return ret;
+}
+
+static void sysmon_smd_notify(void *priv, unsigned int smd_event)
+{
+	struct sysmon_subsys *ss = priv;
+
+	switch (smd_event) {
+	case SMD_EVENT_DATA: {
+		if (smd_read_avail(ss->chan) > 0) {
+			smd_read_from_cb(ss->chan, ss->rx_buf,
+					 ARRAY_SIZE(ss->rx_buf));
+			complete(&ss->resp_ready);
+		}
+		break;
+	}
+	case SMD_EVENT_OPEN:
+		ss->chan_open = true;
+		break;
+	case SMD_EVENT_CLOSE:
+		ss->chan_open = false;
+		break;
+	}
+}
+
+static int sysmon_probe(struct platform_device *pdev)
+{
+	struct sysmon_subsys *ss;
+	int ret;
+
+	if (pdev->id < 0 || pdev->id >= SYSMON_NUM_SS)
+		return -ENODEV;
+
+	ss = &subsys[pdev->id];
+	mutex_init(&ss->lock);
+
+	switch (ss->transport) {
+	case TRANSPORT_SMD:
+		if (pdev->id >= SMD_NUM_TYPE)
+			return -EINVAL;
+
+		ret = smd_named_open_on_edge("sys_mon", pdev->id, &ss->chan, ss,
+					     sysmon_smd_notify);
+		if (ret) {
+			pr_err("SMD open failed\n");
+			return ret;
+		}
+
+		smd_disable_read_intr(ss->chan);
+		break;
+	case TRANSPORT_HSIC:
+		if (pdev->id < SMD_NUM_TYPE)
+			return -EINVAL;
+
+		ret = hsic_sysmon_open(HSIC_SYSMON_DEV_EXT_MODEM);
+		if (ret) {
+			pr_err("HSIC open failed\n");
+			return ret;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int __devexit sysmon_remove(struct platform_device *pdev)
+{
+	struct sysmon_subsys *ss = &subsys[pdev->id];
+
+	switch (ss->transport) {
+	case TRANSPORT_SMD:
+		smd_close(ss->chan);
+		break;
+	case TRANSPORT_HSIC:
+		hsic_sysmon_close(HSIC_SYSMON_DEV_EXT_MODEM);
+		break;
+	}
+
+	return 0;
+}
+
+static struct platform_driver sysmon_driver = {
+	.probe		= sysmon_probe,
+	.remove		= __devexit_p(sysmon_remove),
+	.driver		= {
+		.name		= "sys_mon",
+		.owner		= THIS_MODULE,
+	},
+};
+
+static int __init sysmon_init(void)
+{
+	return platform_driver_register(&sysmon_driver);
+}
+subsys_initcall(sysmon_init);
+
+static void __exit sysmon_exit(void)
+{
+	platform_driver_unregister(&sysmon_driver);
+}
+module_exit(sysmon_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("system monitor communication library");
+MODULE_ALIAS("platform:sys_mon");
diff --git a/arch/arm/mach-msm/sysmon.h b/arch/arm/mach-msm/sysmon.h
new file mode 100644
index 0000000..77c3329
--- /dev/null
+++ b/arch/arm/mach-msm/sysmon.h
@@ -0,0 +1,55 @@
+/*
+ * 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
+ * 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 __MSM_SYSMON_H
+#define __MSM_SYSMON_H
+
+#include <mach/msm_smd.h>
+#include <mach/subsystem_notif.h>
+
+/**
+ * enum subsys_id - Destination subsystems for events.
+ */
+enum subsys_id {
+	/* SMD subsystems */
+	SYSMON_SS_MODEM     = SMD_APPS_MODEM,
+	SYSMON_SS_LPASS     = SMD_APPS_QDSP,
+	SYSMON_SS_WCNSS     = SMD_APPS_WCNSS,
+	SYSMON_SS_DSPS      = SMD_APPS_DSPS,
+	SYSMON_SS_Q6FW      = SMD_APPS_Q6FW,
+
+	/* Non-SMD subsystems */
+	SYSMON_SS_EXT_MODEM = SMD_NUM_TYPE,
+	SYSMON_NUM_SS
+};
+
+#ifdef CONFIG_MSM_SYSMON_COMM
+int sysmon_send_event(enum subsys_id dest_ss, const char *event_ss,
+		      enum subsys_notif_type notif);
+int sysmon_get_reason(enum subsys_id dest_ss, char *buf, size_t len);
+#else
+static inline int sysmon_send_event(enum subsys_id dest_ss,
+				    const char *event_ss,
+				    enum subsys_notif_type notif)
+{
+	return 0;
+}
+static inline int sysmon_get_reason(enum subsys_id dest_ss, char *buf,
+				    size_t len)
+{
+	return 0;
+}
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 81280825..4eef948 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -1,7 +1,6 @@
 /*
- *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. 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
@@ -14,232 +13,1165 @@
  *
  */
 
+#include <linux/module.h>
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
 #include <linux/init.h>
+#include <linux/time.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/delay.h>
 #include <linux/io.h>
+#include <linux/percpu.h>
 
+#include <asm/localtimer.h>
 #include <asm/mach/time.h>
 #include <asm/hardware/gic.h>
-#include <asm/localtimer.h>
 #include <asm/sched_clock.h>
-
+#include <asm/smp_plat.h>
 #include <mach/msm_iomap.h>
-#include <mach/cpu.h>
-#include <mach/board.h>
+#include <mach/irqs.h>
+#include <mach/socinfo.h>
+
+#if defined(CONFIG_MSM_SMD)
+#include "smd_private.h"
+#endif
+#include "timer.h"
+
+enum {
+	MSM_TIMER_DEBUG_SYNC = 1U << 0,
+};
+static int msm_timer_debug_mask;
+module_param_named(debug_mask, msm_timer_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#ifdef CONFIG_MSM7X00A_USE_GP_TIMER
+	#define DG_TIMER_RATING 100
+#else
+	#define DG_TIMER_RATING 300
+#endif
+
+#ifndef MSM_TMR0_BASE
+#define MSM_TMR0_BASE MSM_TMR_BASE
+#endif
+
+#define MSM_DGT_SHIFT (5)
 
 #define TIMER_MATCH_VAL         0x0000
 #define TIMER_COUNT_VAL         0x0004
 #define TIMER_ENABLE            0x0008
-#define TIMER_ENABLE_CLR_ON_MATCH_EN    BIT(1)
-#define TIMER_ENABLE_EN                 BIT(0)
 #define TIMER_CLEAR             0x000C
 #define DGT_CLK_CTL             0x0034
-#define DGT_CLK_CTL_DIV_4	0x3
+enum {
+	DGT_CLK_CTL_DIV_1 = 0,
+	DGT_CLK_CTL_DIV_2 = 1,
+	DGT_CLK_CTL_DIV_3 = 2,
+	DGT_CLK_CTL_DIV_4 = 3,
+};
+#define TIMER_STATUS            0x0088
+#define TIMER_ENABLE_EN              1
+#define TIMER_ENABLE_CLR_ON_MATCH_EN 2
 
-#define GPT_HZ 32768
+#define LOCAL_TIMER 0
+#define GLOBAL_TIMER 1
 
-#define MSM_DGT_SHIFT 5
+/*
+ * global_timer_offset is added to the regbase of a timer to force the memory
+ * access to come from the CPU0 region.
+ */
+static int global_timer_offset;
+static int msm_global_timer;
 
-static void __iomem *event_base;
+#define NR_TIMERS ARRAY_SIZE(msm_clocks)
+
+unsigned int gpt_hz = 32768;
+unsigned int sclk_hz = 32768;
+
+static struct msm_clock *clockevent_to_clock(struct clock_event_device *evt);
+static irqreturn_t msm_timer_interrupt(int irq, void *dev_id);
+static cycle_t msm_gpt_read(struct clocksource *cs);
+static cycle_t msm_dgt_read(struct clocksource *cs);
+static void msm_timer_set_mode(enum clock_event_mode mode,
+			       struct clock_event_device *evt);
+static int msm_timer_set_next_event(unsigned long cycles,
+				    struct clock_event_device *evt);
+
+enum {
+	MSM_CLOCK_FLAGS_UNSTABLE_COUNT = 1U << 0,
+	MSM_CLOCK_FLAGS_ODD_MATCH_WRITE = 1U << 1,
+	MSM_CLOCK_FLAGS_DELAYED_WRITE_POST = 1U << 2,
+};
+
+struct msm_clock {
+	struct clock_event_device   clockevent;
+	struct clocksource          clocksource;
+	unsigned int		    irq;
+	void __iomem                *regbase;
+	uint32_t                    freq;
+	uint32_t                    shift;
+	uint32_t                    flags;
+	uint32_t                    write_delay;
+	uint32_t                    rollover_offset;
+	uint32_t                    index;
+	void __iomem                *global_counter;
+	void __iomem                *local_counter;
+	uint32_t		    status_mask;
+	union {
+		struct clock_event_device		*evt;
+		struct clock_event_device __percpu	**percpu_evt;
+	};
+};
+
+enum {
+	MSM_CLOCK_GPT,
+	MSM_CLOCK_DGT,
+};
+
+struct msm_clock_percpu_data {
+	uint32_t                  last_set;
+	uint32_t                  sleep_offset;
+	uint32_t                  alarm_vtime;
+	uint32_t                  alarm;
+	uint32_t                  non_sleep_offset;
+	uint32_t                  in_sync;
+	cycle_t                   stopped_tick;
+	int                       stopped;
+	uint32_t                  last_sync_gpt;
+	u64                       last_sync_jiffies;
+};
+
+struct msm_timer_sync_data_t {
+	struct msm_clock *clock;
+	uint32_t         timeout;
+	int              exit_sleep;
+};
+
+static struct msm_clock msm_clocks[] = {
+	[MSM_CLOCK_GPT] = {
+		.clockevent = {
+			.name           = "gp_timer",
+			.features       = CLOCK_EVT_FEAT_ONESHOT,
+			.shift          = 32,
+			.rating         = 200,
+			.set_next_event = msm_timer_set_next_event,
+			.set_mode       = msm_timer_set_mode,
+		},
+		.clocksource = {
+			.name           = "gp_timer",
+			.rating         = 200,
+			.read           = msm_gpt_read,
+			.mask           = CLOCKSOURCE_MASK(32),
+			.shift          = 17,
+			.flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+		},
+		.irq = INT_GP_TIMER_EXP,
+		.regbase = MSM_TMR_BASE + 0x4,
+		.freq = 32768,
+		.index = MSM_CLOCK_GPT,
+		.write_delay = 9,
+	},
+	[MSM_CLOCK_DGT] = {
+		.clockevent = {
+			.name           = "dg_timer",
+			.features       = CLOCK_EVT_FEAT_ONESHOT,
+			.shift          = 32,
+			.rating         = DG_TIMER_RATING,
+			.set_next_event = msm_timer_set_next_event,
+			.set_mode       = msm_timer_set_mode,
+		},
+		.clocksource = {
+			.name           = "dg_timer",
+			.rating         = DG_TIMER_RATING,
+			.read           = msm_dgt_read,
+			.mask           = CLOCKSOURCE_MASK(32),
+			.shift          = 24,
+			.flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+		},
+		.irq = INT_DEBUG_TIMER_EXP,
+		.regbase = MSM_TMR_BASE + 0x24,
+		.index = MSM_CLOCK_DGT,
+		.write_delay = 9,
+	}
+};
+
+static DEFINE_PER_CPU(struct msm_clock_percpu_data[NR_TIMERS],
+    msm_clocks_percpu);
+
+static DEFINE_PER_CPU(struct msm_clock *, msm_active_clock);
 
 static irqreturn_t msm_timer_interrupt(int irq, void *dev_id)
 {
 	struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
-	/* Stop the timer tick */
-	if (evt->mode == CLOCK_EVT_MODE_ONESHOT) {
-		u32 ctrl = readl_relaxed(event_base + TIMER_ENABLE);
-		ctrl &= ~TIMER_ENABLE_EN;
-		writel_relaxed(ctrl, event_base + TIMER_ENABLE);
-	}
+	if (evt->event_handler == NULL)
+		return IRQ_HANDLED;
 	evt->event_handler(evt);
 	return IRQ_HANDLED;
 }
 
+static uint32_t msm_read_timer_count(struct msm_clock *clock, int global)
+{
+	uint32_t t1, t2, t3;
+	int loop_count = 0;
+	void __iomem *addr = clock->regbase + TIMER_COUNT_VAL +
+		global*global_timer_offset;
+
+	if (!(clock->flags & MSM_CLOCK_FLAGS_UNSTABLE_COUNT))
+		return __raw_readl_no_log(addr);
+
+	t1 = __raw_readl_no_log(addr);
+	t2 = __raw_readl_no_log(addr);
+	if ((t2-t1) <= 1)
+		return t2;
+	while (1) {
+		t1 = __raw_readl_no_log(addr);
+		t2 = __raw_readl_no_log(addr);
+		t3 = __raw_readl_no_log(addr);
+		cpu_relax();
+		if ((t3-t2) <= 1)
+			return t3;
+		if ((t2-t1) <= 1)
+			return t2;
+		if ((t2 >= t1) && (t3 >= t2))
+			return t2;
+		if (++loop_count == 5) {
+			pr_err("msm_read_timer_count timer %s did not "
+			       "stabilize: %u -> %u -> %u\n",
+			       clock->clockevent.name, t1, t2, t3);
+			return t3;
+		}
+	}
+}
+
+static cycle_t msm_gpt_read(struct clocksource *cs)
+{
+	struct msm_clock *clock = &msm_clocks[MSM_CLOCK_GPT];
+	struct msm_clock_percpu_data *clock_state =
+		&per_cpu(msm_clocks_percpu, 0)[MSM_CLOCK_GPT];
+
+	if (clock_state->stopped)
+		return clock_state->stopped_tick;
+
+	return msm_read_timer_count(clock, GLOBAL_TIMER) +
+		clock_state->sleep_offset;
+}
+
+static cycle_t msm_dgt_read(struct clocksource *cs)
+{
+	struct msm_clock *clock = &msm_clocks[MSM_CLOCK_DGT];
+	struct msm_clock_percpu_data *clock_state =
+		&per_cpu(msm_clocks_percpu, 0)[MSM_CLOCK_DGT];
+
+	if (clock_state->stopped)
+		return clock_state->stopped_tick >> clock->shift;
+
+	return (msm_read_timer_count(clock, GLOBAL_TIMER) +
+		clock_state->sleep_offset) >> clock->shift;
+}
+
+static struct msm_clock *clockevent_to_clock(struct clock_event_device *evt)
+{
+	int i;
+
+	if (!is_smp())
+		return container_of(evt, struct msm_clock, clockevent);
+
+	for (i = 0; i < NR_TIMERS; i++)
+		if (evt == &(msm_clocks[i].clockevent))
+			return &msm_clocks[i];
+	return &msm_clocks[msm_global_timer];
+}
+
 static int msm_timer_set_next_event(unsigned long cycles,
 				    struct clock_event_device *evt)
 {
-	u32 ctrl = readl_relaxed(event_base + TIMER_ENABLE);
+	int i;
+	struct msm_clock *clock;
+	struct msm_clock_percpu_data *clock_state;
+	uint32_t now;
+	uint32_t alarm;
+	int late;
 
-	writel_relaxed(0, event_base + TIMER_CLEAR);
-	writel_relaxed(cycles, event_base + TIMER_MATCH_VAL);
-	writel_relaxed(ctrl | TIMER_ENABLE_EN, event_base + TIMER_ENABLE);
+	clock = clockevent_to_clock(evt);
+	clock_state = &__get_cpu_var(msm_clocks_percpu)[clock->index];
+	if (clock_state->stopped)
+		return 0;
+	now = msm_read_timer_count(clock, LOCAL_TIMER);
+	alarm = now + (cycles << clock->shift);
+	if (clock->flags & MSM_CLOCK_FLAGS_ODD_MATCH_WRITE)
+		while (now == clock_state->last_set)
+			now = msm_read_timer_count(clock, LOCAL_TIMER);
+
+	clock_state->alarm = alarm;
+	__raw_writel(alarm, clock->regbase + TIMER_MATCH_VAL);
+
+	if (clock->flags & MSM_CLOCK_FLAGS_DELAYED_WRITE_POST) {
+		/* read the counter four extra times to make sure write posts
+		   before reading the time */
+		for (i = 0; i < 4; i++)
+			__raw_readl_no_log(clock->regbase + TIMER_COUNT_VAL);
+	}
+	now = msm_read_timer_count(clock, LOCAL_TIMER);
+	clock_state->last_set = now;
+	clock_state->alarm_vtime = alarm + clock_state->sleep_offset;
+	late = now - alarm;
+	if (late >= (int)(-clock->write_delay << clock->shift) &&
+	    late < clock->freq*5)
+		return -ETIME;
+
 	return 0;
 }
 
 static void msm_timer_set_mode(enum clock_event_mode mode,
-			      struct clock_event_device *evt)
+			       struct clock_event_device *evt)
 {
-	u32 ctrl;
+	struct msm_clock *clock;
+	struct msm_clock_percpu_data *clock_state, *gpt_state;
+	unsigned long irq_flags;
+	struct irq_chip *chip;
 
-	ctrl = readl_relaxed(event_base + TIMER_ENABLE);
-	ctrl &= ~(TIMER_ENABLE_EN | TIMER_ENABLE_CLR_ON_MATCH_EN);
+	clock = clockevent_to_clock(evt);
+	clock_state = &__get_cpu_var(msm_clocks_percpu)[clock->index];
+	gpt_state = &__get_cpu_var(msm_clocks_percpu)[MSM_CLOCK_GPT];
+
+	local_irq_save(irq_flags);
 
 	switch (mode) {
 	case CLOCK_EVT_MODE_RESUME:
 	case CLOCK_EVT_MODE_PERIODIC:
 		break;
 	case CLOCK_EVT_MODE_ONESHOT:
-		/* Timer is enabled in set_next_event */
+		clock_state->stopped = 0;
+		clock_state->sleep_offset =
+			-msm_read_timer_count(clock, LOCAL_TIMER) +
+			clock_state->stopped_tick;
+		get_cpu_var(msm_active_clock) = clock;
+		put_cpu_var(msm_active_clock);
+		__raw_writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE);
+		chip = irq_get_chip(clock->irq);
+		if (chip && chip->irq_unmask)
+			chip->irq_unmask(irq_get_irq_data(clock->irq));
+		if (clock != &msm_clocks[MSM_CLOCK_GPT])
+			__raw_writel(TIMER_ENABLE_EN,
+				msm_clocks[MSM_CLOCK_GPT].regbase +
+			       TIMER_ENABLE);
 		break;
 	case CLOCK_EVT_MODE_UNUSED:
 	case CLOCK_EVT_MODE_SHUTDOWN:
+		get_cpu_var(msm_active_clock) = NULL;
+		put_cpu_var(msm_active_clock);
+		clock_state->in_sync = 0;
+		clock_state->stopped = 1;
+		clock_state->stopped_tick =
+			msm_read_timer_count(clock, LOCAL_TIMER) +
+			clock_state->sleep_offset;
+		__raw_writel(0, clock->regbase + TIMER_MATCH_VAL);
+		chip = irq_get_chip(clock->irq);
+		if (chip && chip->irq_mask)
+			chip->irq_mask(irq_get_irq_data(clock->irq));
+
+		if (!is_smp() || clock != &msm_clocks[MSM_CLOCK_DGT]
+				|| smp_processor_id())
+			__raw_writel(0, clock->regbase + TIMER_ENABLE);
+
+		if (msm_global_timer == MSM_CLOCK_DGT &&
+		    clock != &msm_clocks[MSM_CLOCK_GPT]) {
+			gpt_state->in_sync = 0;
+			__raw_writel(0, msm_clocks[MSM_CLOCK_GPT].regbase +
+			       TIMER_ENABLE);
+		}
 		break;
 	}
-	writel_relaxed(ctrl, event_base + TIMER_ENABLE);
+	wmb();
+	local_irq_restore(irq_flags);
 }
 
-static struct clock_event_device msm_clockevent = {
-	.name		= "gp_timer",
-	.features	= CLOCK_EVT_FEAT_ONESHOT,
-	.rating		= 200,
-	.set_next_event	= msm_timer_set_next_event,
-	.set_mode	= msm_timer_set_mode,
-};
-
-static union {
-	struct clock_event_device *evt;
-	struct clock_event_device __percpu **percpu_evt;
-} msm_evt;
-
-static void __iomem *source_base;
-
-static notrace cycle_t msm_read_timer_count(struct clocksource *cs)
+void __iomem *msm_timer_get_timer0_base(void)
 {
-	return readl_relaxed(source_base + TIMER_COUNT_VAL);
+	return MSM_TMR_BASE + global_timer_offset;
 }
 
-static notrace cycle_t msm_read_timer_count_shift(struct clocksource *cs)
+#define MPM_SCLK_COUNT_VAL    0x0024
+
+#ifdef CONFIG_PM
+/*
+ * Retrieve the cycle count from sclk and optionally synchronize local clock
+ * with the sclk value.
+ *
+ * time_start and time_expired are callbacks that must be specified.  The
+ * protocol uses them to detect timeout.  The update callback is optional.
+ * If not NULL, update will be called so that it can update local clock.
+ *
+ * The function does not use the argument data directly; it passes data to
+ * the callbacks.
+ *
+ * Return value:
+ *      0: the operation failed
+ *      >0: the slow clock value after time-sync
+ */
+static void (*msm_timer_sync_timeout)(void);
+#if defined(CONFIG_MSM_DIRECT_SCLK_ACCESS)
+uint32_t msm_timer_get_sclk_ticks(void)
 {
-	/*
-	 * Shift timer count down by a constant due to unreliable lower bits
-	 * on some targets.
-	 */
-	return msm_read_timer_count(cs) >> MSM_DGT_SHIFT;
+	uint32_t t1, t2;
+	int loop_count = 10;
+	int loop_zero_count = 3;
+	int tmp = USEC_PER_SEC;
+	do_div(tmp, sclk_hz);
+	tmp /= (loop_zero_count-1);
+
+	while (loop_zero_count--) {
+		t1 = __raw_readl_no_log(MSM_RPM_MPM_BASE + MPM_SCLK_COUNT_VAL);
+		do {
+			udelay(1);
+			t2 = t1;
+			t1 = __raw_readl_no_log(
+				MSM_RPM_MPM_BASE + MPM_SCLK_COUNT_VAL);
+		} while ((t2 != t1) && --loop_count);
+
+		if (!loop_count) {
+			printk(KERN_EMERG "SCLK  did not stabilize\n");
+			return 0;
+		}
+
+		if (t1)
+			break;
+
+		udelay(tmp);
+	}
+
+	if (!loop_zero_count) {
+		printk(KERN_EMERG "SCLK reads zero\n");
+		return 0;
+	}
+
+	return t1;
 }
 
-static struct clocksource msm_clocksource = {
-	.name	= "dg_timer",
-	.rating	= 300,
-	.read	= msm_read_timer_count,
-	.mask	= CLOCKSOURCE_MASK(32),
-	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
-};
+static uint32_t msm_timer_do_sync_to_sclk(
+	void (*time_start)(struct msm_timer_sync_data_t *data),
+	bool (*time_expired)(struct msm_timer_sync_data_t *data),
+	void (*update)(struct msm_timer_sync_data_t *, uint32_t, uint32_t),
+	struct msm_timer_sync_data_t *data)
+{
+	unsigned t1 = msm_timer_get_sclk_ticks();
+
+	if (t1 && update != NULL)
+		update(data, t1, sclk_hz);
+	return t1;
+}
+#elif defined(CONFIG_MSM_N_WAY_SMSM)
+
+/* Time Master State Bits */
+#define MASTER_BITS_PER_CPU        1
+#define MASTER_TIME_PENDING \
+	(0x01UL << (MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
+
+/* Time Slave State Bits */
+#define SLAVE_TIME_REQUEST         0x0400
+#define SLAVE_TIME_POLL            0x0800
+#define SLAVE_TIME_INIT            0x1000
+
+static uint32_t msm_timer_do_sync_to_sclk(
+	void (*time_start)(struct msm_timer_sync_data_t *data),
+	bool (*time_expired)(struct msm_timer_sync_data_t *data),
+	void (*update)(struct msm_timer_sync_data_t *, uint32_t, uint32_t),
+	struct msm_timer_sync_data_t *data)
+{
+	uint32_t *smem_clock;
+	uint32_t smem_clock_val;
+	uint32_t state;
+
+	smem_clock = smem_alloc(SMEM_SMEM_SLOW_CLOCK_VALUE, sizeof(uint32_t));
+	if (smem_clock == NULL) {
+		printk(KERN_ERR "no smem clock\n");
+		return 0;
+	}
+
+	state = smsm_get_state(SMSM_MODEM_STATE);
+	if ((state & SMSM_INIT) == 0) {
+		printk(KERN_ERR "smsm not initialized\n");
+		return 0;
+	}
+
+	time_start(data);
+	while ((state = smsm_get_state(SMSM_TIME_MASTER_DEM)) &
+		MASTER_TIME_PENDING) {
+		if (time_expired(data)) {
+			printk(KERN_EMERG "get_smem_clock: timeout 1 still "
+				"invalid state %x\n", state);
+			msm_timer_sync_timeout();
+		}
+	}
+
+	smsm_change_state(SMSM_APPS_DEM, SLAVE_TIME_POLL | SLAVE_TIME_INIT,
+		SLAVE_TIME_REQUEST);
+
+	time_start(data);
+	while (!((state = smsm_get_state(SMSM_TIME_MASTER_DEM)) &
+		MASTER_TIME_PENDING)) {
+		if (time_expired(data)) {
+			printk(KERN_EMERG "get_smem_clock: timeout 2 still "
+				"invalid state %x\n", state);
+			msm_timer_sync_timeout();
+		}
+	}
+
+	smsm_change_state(SMSM_APPS_DEM, SLAVE_TIME_REQUEST, SLAVE_TIME_POLL);
+
+	time_start(data);
+	do {
+		smem_clock_val = *smem_clock;
+	} while (smem_clock_val == 0 && !time_expired(data));
+
+	state = smsm_get_state(SMSM_TIME_MASTER_DEM);
+
+	if (smem_clock_val) {
+		if (update != NULL)
+			update(data, smem_clock_val, sclk_hz);
+
+		if (msm_timer_debug_mask & MSM_TIMER_DEBUG_SYNC)
+			printk(KERN_INFO
+				"get_smem_clock: state %x clock %u\n",
+				state, smem_clock_val);
+	} else {
+		printk(KERN_EMERG
+			"get_smem_clock: timeout state %x clock %u\n",
+			state, smem_clock_val);
+		msm_timer_sync_timeout();
+	}
+
+	smsm_change_state(SMSM_APPS_DEM, SLAVE_TIME_REQUEST | SLAVE_TIME_POLL,
+		SLAVE_TIME_INIT);
+	return smem_clock_val;
+}
+#else /* CONFIG_MSM_N_WAY_SMSM */
+static uint32_t msm_timer_do_sync_to_sclk(
+	void (*time_start)(struct msm_timer_sync_data_t *data),
+	bool (*time_expired)(struct msm_timer_sync_data_t *data),
+	void (*update)(struct msm_timer_sync_data_t *, uint32_t, uint32_t),
+	struct msm_timer_sync_data_t *data)
+{
+	uint32_t *smem_clock;
+	uint32_t smem_clock_val;
+	uint32_t last_state;
+	uint32_t state;
+
+	smem_clock = smem_alloc(SMEM_SMEM_SLOW_CLOCK_VALUE,
+				sizeof(uint32_t));
+
+	if (smem_clock == NULL) {
+		printk(KERN_ERR "no smem clock\n");
+		return 0;
+	}
+
+	last_state = state = smsm_get_state(SMSM_MODEM_STATE);
+	smem_clock_val = *smem_clock;
+	if (smem_clock_val) {
+		printk(KERN_INFO "get_smem_clock: invalid start state %x "
+			"clock %u\n", state, smem_clock_val);
+		smsm_change_state(SMSM_APPS_STATE,
+				  SMSM_TIMEWAIT, SMSM_TIMEINIT);
+
+		time_start(data);
+		while (*smem_clock != 0 && !time_expired(data))
+			;
+
+		smem_clock_val = *smem_clock;
+		if (smem_clock_val) {
+			printk(KERN_EMERG "get_smem_clock: timeout still "
+				"invalid state %x clock %u\n",
+				state, smem_clock_val);
+			msm_timer_sync_timeout();
+		}
+	}
+
+	time_start(data);
+	smsm_change_state(SMSM_APPS_STATE, SMSM_TIMEINIT, SMSM_TIMEWAIT);
+	do {
+		smem_clock_val = *smem_clock;
+		state = smsm_get_state(SMSM_MODEM_STATE);
+		if (state != last_state) {
+			last_state = state;
+			if (msm_timer_debug_mask & MSM_TIMER_DEBUG_SYNC)
+				printk(KERN_INFO
+					"get_smem_clock: state %x clock %u\n",
+					state, smem_clock_val);
+		}
+	} while (smem_clock_val == 0 && !time_expired(data));
+
+	if (smem_clock_val) {
+		if (update != NULL)
+			update(data, smem_clock_val, sclk_hz);
+	} else {
+		printk(KERN_EMERG
+			"get_smem_clock: timeout state %x clock %u\n",
+			state, smem_clock_val);
+		msm_timer_sync_timeout();
+	}
+
+	smsm_change_state(SMSM_APPS_STATE, SMSM_TIMEWAIT, SMSM_TIMEINIT);
+	return smem_clock_val;
+}
+#endif /* CONFIG_MSM_N_WAY_SMSM */
+
+/*
+ * Callback function that initializes the timeout value.
+ */
+static void msm_timer_sync_to_sclk_time_start(
+	struct msm_timer_sync_data_t *data)
+{
+	/* approx 2 seconds */
+	uint32_t delta = data->clock->freq << data->clock->shift << 1;
+	data->timeout = msm_read_timer_count(data->clock, LOCAL_TIMER) + delta;
+}
+
+/*
+ * Callback function that checks the timeout.
+ */
+static bool msm_timer_sync_to_sclk_time_expired(
+	struct msm_timer_sync_data_t *data)
+{
+	uint32_t delta = msm_read_timer_count(data->clock, LOCAL_TIMER) -
+		data->timeout;
+	return ((int32_t) delta) > 0;
+}
+
+/*
+ * Callback function that updates local clock from the specified source clock
+ * value and frequency.
+ */
+static void msm_timer_sync_update(struct msm_timer_sync_data_t *data,
+	uint32_t src_clk_val, uint32_t src_clk_freq)
+{
+	struct msm_clock *dst_clk = data->clock;
+	struct msm_clock_percpu_data *dst_clk_state =
+		&__get_cpu_var(msm_clocks_percpu)[dst_clk->index];
+	uint32_t dst_clk_val = msm_read_timer_count(dst_clk, LOCAL_TIMER);
+	uint32_t new_offset;
+
+	if ((dst_clk->freq << dst_clk->shift) == src_clk_freq) {
+		new_offset = src_clk_val - dst_clk_val;
+	} else {
+		uint64_t temp;
+
+		/* separate multiplication and division steps to reduce
+		   rounding error */
+		temp = src_clk_val;
+		temp *= dst_clk->freq << dst_clk->shift;
+		do_div(temp, src_clk_freq);
+
+		new_offset = (uint32_t)(temp) - dst_clk_val;
+	}
+
+	if (dst_clk_state->sleep_offset + dst_clk_state->non_sleep_offset !=
+	    new_offset) {
+		if (data->exit_sleep)
+			dst_clk_state->sleep_offset =
+				new_offset - dst_clk_state->non_sleep_offset;
+		else
+			dst_clk_state->non_sleep_offset =
+				new_offset - dst_clk_state->sleep_offset;
+
+		if (msm_timer_debug_mask & MSM_TIMER_DEBUG_SYNC)
+			printk(KERN_INFO "sync clock %s: "
+				"src %u, new offset %u + %u\n",
+				dst_clk->clocksource.name, src_clk_val,
+				dst_clk_state->sleep_offset,
+				dst_clk_state->non_sleep_offset);
+	}
+}
+
+/*
+ * Synchronize GPT clock with sclk.
+ */
+static void msm_timer_sync_gpt_to_sclk(int exit_sleep)
+{
+	struct msm_clock *gpt_clk = &msm_clocks[MSM_CLOCK_GPT];
+	struct msm_clock_percpu_data *gpt_clk_state =
+		&__get_cpu_var(msm_clocks_percpu)[MSM_CLOCK_GPT];
+	struct msm_timer_sync_data_t data;
+	uint32_t ret;
+
+	if (gpt_clk_state->in_sync)
+		return;
+
+	data.clock = gpt_clk;
+	data.timeout = 0;
+	data.exit_sleep = exit_sleep;
+
+	ret = msm_timer_do_sync_to_sclk(
+		msm_timer_sync_to_sclk_time_start,
+		msm_timer_sync_to_sclk_time_expired,
+		msm_timer_sync_update,
+		&data);
+
+	if (ret)
+		gpt_clk_state->in_sync = 1;
+}
+
+/*
+ * Synchronize clock with GPT clock.
+ */
+static void msm_timer_sync_to_gpt(struct msm_clock *clock, int exit_sleep)
+{
+	struct msm_clock *gpt_clk = &msm_clocks[MSM_CLOCK_GPT];
+	struct msm_clock_percpu_data *gpt_clk_state =
+		&__get_cpu_var(msm_clocks_percpu)[MSM_CLOCK_GPT];
+	struct msm_clock_percpu_data *clock_state =
+		&__get_cpu_var(msm_clocks_percpu)[clock->index];
+	struct msm_timer_sync_data_t data;
+	uint32_t gpt_clk_val;
+	u64 gpt_period = (1ULL << 32) * HZ;
+	u64 now = get_jiffies_64();
+
+	do_div(gpt_period, gpt_hz);
+
+	BUG_ON(clock == gpt_clk);
+
+	if (clock_state->in_sync &&
+		(now - clock_state->last_sync_jiffies < (gpt_period >> 1)))
+		return;
+
+	gpt_clk_val = msm_read_timer_count(gpt_clk, LOCAL_TIMER)
+		+ gpt_clk_state->sleep_offset + gpt_clk_state->non_sleep_offset;
+
+	if (exit_sleep && gpt_clk_val < clock_state->last_sync_gpt)
+		clock_state->non_sleep_offset -= clock->rollover_offset;
+
+	data.clock = clock;
+	data.timeout = 0;
+	data.exit_sleep = exit_sleep;
+
+	msm_timer_sync_update(&data, gpt_clk_val, gpt_hz);
+
+	clock_state->in_sync = 1;
+	clock_state->last_sync_gpt = gpt_clk_val;
+	clock_state->last_sync_jiffies = now;
+}
+
+static void msm_timer_reactivate_alarm(struct msm_clock *clock)
+{
+	struct msm_clock_percpu_data *clock_state =
+		&__get_cpu_var(msm_clocks_percpu)[clock->index];
+	long alarm_delta = clock_state->alarm_vtime -
+		clock_state->sleep_offset -
+		msm_read_timer_count(clock, LOCAL_TIMER);
+	alarm_delta >>= clock->shift;
+	if (alarm_delta < (long)clock->write_delay + 4)
+		alarm_delta = clock->write_delay + 4;
+	while (msm_timer_set_next_event(alarm_delta, &clock->clockevent))
+		;
+}
+
+int64_t msm_timer_enter_idle(void)
+{
+	struct msm_clock *gpt_clk = &msm_clocks[MSM_CLOCK_GPT];
+	struct msm_clock *clock = __get_cpu_var(msm_active_clock);
+	struct msm_clock_percpu_data *clock_state =
+		&__get_cpu_var(msm_clocks_percpu)[clock->index];
+	uint32_t alarm;
+	uint32_t count;
+	int32_t delta;
+
+	BUG_ON(clock != &msm_clocks[MSM_CLOCK_GPT] &&
+		clock != &msm_clocks[MSM_CLOCK_DGT]);
+
+	msm_timer_sync_gpt_to_sclk(0);
+	if (clock != gpt_clk)
+		msm_timer_sync_to_gpt(clock, 0);
+
+	count = msm_read_timer_count(clock, LOCAL_TIMER);
+	if (clock_state->stopped++ == 0)
+		clock_state->stopped_tick = count + clock_state->sleep_offset;
+	alarm = clock_state->alarm;
+	delta = alarm - count;
+	if (delta <= -(int32_t)((clock->freq << clock->shift) >> 10)) {
+		/* timer should have triggered 1ms ago */
+		printk(KERN_ERR "msm_timer_enter_idle: timer late %d, "
+			"reprogram it\n", delta);
+		msm_timer_reactivate_alarm(clock);
+	}
+	if (delta <= 0)
+		return 0;
+	return clocksource_cyc2ns((alarm - count) >> clock->shift,
+		      clock->clocksource.mult,
+		      clock->clocksource.shift);
+}
+
+void msm_timer_exit_idle(int low_power)
+{
+	struct msm_clock *gpt_clk = &msm_clocks[MSM_CLOCK_GPT];
+	struct msm_clock *clock = __get_cpu_var(msm_active_clock);
+	struct msm_clock_percpu_data *gpt_clk_state =
+		&__get_cpu_var(msm_clocks_percpu)[MSM_CLOCK_GPT];
+	struct msm_clock_percpu_data *clock_state =
+		&__get_cpu_var(msm_clocks_percpu)[clock->index];
+	uint32_t enabled;
+
+	BUG_ON(clock != &msm_clocks[MSM_CLOCK_GPT] &&
+		clock != &msm_clocks[MSM_CLOCK_DGT]);
+
+	if (!low_power)
+		goto exit_idle_exit;
+
+	enabled = __raw_readl(gpt_clk->regbase + TIMER_ENABLE) &
+			      TIMER_ENABLE_EN;
+	if (!enabled)
+		__raw_writel(TIMER_ENABLE_EN, gpt_clk->regbase + TIMER_ENABLE);
+
+#if defined(CONFIG_ARCH_MSM_SCORPION) || defined(CONFIG_ARCH_MSM_KRAIT)
+	gpt_clk_state->in_sync = 0;
+#else
+	gpt_clk_state->in_sync = gpt_clk_state->in_sync && enabled;
+#endif
+	/* Make sure timer is actually enabled before we sync it */
+	wmb();
+	msm_timer_sync_gpt_to_sclk(1);
+
+	if (clock == gpt_clk)
+		goto exit_idle_alarm;
+
+	enabled = __raw_readl(clock->regbase + TIMER_ENABLE) & TIMER_ENABLE_EN;
+	if (!enabled)
+		__raw_writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE);
+
+#if defined(CONFIG_ARCH_MSM_SCORPION) || defined(CONFIG_ARCH_MSM_KRAIT)
+	clock_state->in_sync = 0;
+#else
+	clock_state->in_sync = clock_state->in_sync && enabled;
+#endif
+	/* Make sure timer is actually enabled before we sync it */
+	wmb();
+	msm_timer_sync_to_gpt(clock, 1);
+
+exit_idle_alarm:
+	msm_timer_reactivate_alarm(clock);
+
+exit_idle_exit:
+	clock_state->stopped--;
+}
+
+/*
+ * Callback function that initializes the timeout value.
+ */
+static void msm_timer_get_sclk_time_start(
+	struct msm_timer_sync_data_t *data)
+{
+	data->timeout = 200000;
+}
+
+/*
+ * Callback function that checks the timeout.
+ */
+static bool msm_timer_get_sclk_time_expired(
+	struct msm_timer_sync_data_t *data)
+{
+	udelay(10);
+	return --data->timeout <= 0;
+}
+
+/*
+ * Retrieve the cycle count from the sclk and convert it into
+ * nanoseconds.
+ *
+ * On exit, if period is not NULL, it contains the period of the
+ * sclk in nanoseconds, i.e. how long the cycle count wraps around.
+ *
+ * Return value:
+ *      0: the operation failed; period is not set either
+ *      >0: time in nanoseconds
+ */
+int64_t msm_timer_get_sclk_time(int64_t *period)
+{
+	struct msm_timer_sync_data_t data;
+	uint32_t clock_value;
+	int64_t tmp;
+
+	memset(&data, 0, sizeof(data));
+	clock_value = msm_timer_do_sync_to_sclk(
+		msm_timer_get_sclk_time_start,
+		msm_timer_get_sclk_time_expired,
+		NULL,
+		&data);
+
+	if (!clock_value)
+		return 0;
+
+	if (period) {
+		tmp = 1LL << 32;
+		tmp *= NSEC_PER_SEC;
+		do_div(tmp, sclk_hz);
+		*period = tmp;
+	}
+
+	tmp = (int64_t)clock_value;
+	tmp *= NSEC_PER_SEC;
+	do_div(tmp, sclk_hz);
+	return tmp;
+}
+
+int __init msm_timer_init_time_sync(void (*timeout)(void))
+{
+#if defined(CONFIG_MSM_N_WAY_SMSM) && !defined(CONFIG_MSM_DIRECT_SCLK_ACCESS)
+	int ret = smsm_change_intr_mask(SMSM_TIME_MASTER_DEM, 0xFFFFFFFF, 0);
+
+	if (ret) {
+		printk(KERN_ERR	"%s: failed to clear interrupt mask, %d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	smsm_change_state(SMSM_APPS_DEM,
+		SLAVE_TIME_REQUEST | SLAVE_TIME_POLL, SLAVE_TIME_INIT);
+#endif
+
+	BUG_ON(timeout == NULL);
+	msm_timer_sync_timeout = timeout;
+
+	return 0;
+}
+
+#endif
+
+static u32 notrace msm_read_sched_clock(void)
+{
+	struct msm_clock *clock = &msm_clocks[msm_global_timer];
+	struct clocksource *cs = &clock->clocksource;
+	return cs->read(NULL);
+}
+
+int read_current_timer(unsigned long *timer_val)
+{
+	struct msm_clock *dgt = &msm_clocks[MSM_CLOCK_DGT];
+	*timer_val = msm_read_timer_count(dgt, GLOBAL_TIMER);
+	return 0;
+}
+
+static void __init msm_sched_clock_init(void)
+{
+	struct msm_clock *clock = &msm_clocks[msm_global_timer];
+
+	setup_sched_clock(msm_read_sched_clock, 32 - clock->shift, clock->freq);
+}
 
 #ifdef CONFIG_LOCAL_TIMERS
-static int __cpuinit msm_local_timer_setup(struct clock_event_device *evt)
+int __cpuinit local_timer_setup(struct clock_event_device *evt)
 {
+	static DEFINE_PER_CPU(bool, first_boot) = true;
+	struct msm_clock *clock = &msm_clocks[msm_global_timer];
+
 	/* Use existing clock_event for cpu 0 */
 	if (!smp_processor_id())
 		return 0;
 
-	writel_relaxed(0, event_base + TIMER_ENABLE);
-	writel_relaxed(0, event_base + TIMER_CLEAR);
-	writel_relaxed(~0, event_base + TIMER_MATCH_VAL);
-	evt->irq = msm_clockevent.irq;
+	if (cpu_is_msm8x60() || cpu_is_msm8960() || cpu_is_apq8064()
+			|| cpu_is_msm8930())
+		__raw_writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
+
+	if (__get_cpu_var(first_boot)) {
+		__raw_writel(0, clock->regbase  + TIMER_ENABLE);
+		__raw_writel(0, clock->regbase + TIMER_CLEAR);
+		__raw_writel(~0, clock->regbase + TIMER_MATCH_VAL);
+		__get_cpu_var(first_boot) = false;
+		if (clock->status_mask)
+			while (__raw_readl(MSM_TMR_BASE + TIMER_STATUS) &
+			       clock->status_mask)
+				;
+	}
+	evt->irq = clock->irq;
 	evt->name = "local_timer";
-	evt->features = msm_clockevent.features;
-	evt->rating = msm_clockevent.rating;
+	evt->features = CLOCK_EVT_FEAT_ONESHOT;
+	evt->rating = clock->clockevent.rating;
 	evt->set_mode = msm_timer_set_mode;
 	evt->set_next_event = msm_timer_set_next_event;
-	evt->shift = msm_clockevent.shift;
-	evt->mult = div_sc(GPT_HZ, NSEC_PER_SEC, evt->shift);
-	evt->max_delta_ns = clockevent_delta2ns(0xf0000000, evt);
+	evt->shift = clock->clockevent.shift;
+	evt->mult = div_sc(clock->freq, NSEC_PER_SEC, evt->shift);
+	evt->max_delta_ns =
+		clockevent_delta2ns(0xf0000000 >> clock->shift, evt);
 	evt->min_delta_ns = clockevent_delta2ns(4, evt);
 
-	*__this_cpu_ptr(msm_evt.percpu_evt) = evt;
+	*__this_cpu_ptr(clock->percpu_evt) = evt;
+
 	clockevents_register_device(evt);
-	enable_percpu_irq(evt->irq, 0);
+	enable_percpu_irq(evt->irq, IRQ_TYPE_EDGE_RISING);
+
 	return 0;
 }
 
-static void msm_local_timer_stop(struct clock_event_device *evt)
+void local_timer_stop(struct clock_event_device *evt)
 {
 	evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
 	disable_percpu_irq(evt->irq);
 }
 
-static struct local_timer_ops msm_local_timer_ops __cpuinitdata = {
-	.setup	= msm_local_timer_setup,
-	.stop	= msm_local_timer_stop,
+static struct local_timer_ops msm_lt_ops = {
+	local_timer_setup,
+	local_timer_stop,
 };
 #endif /* CONFIG_LOCAL_TIMERS */
 
-static notrace u32 msm_sched_clock_read(void)
-{
-	return msm_clocksource.read(&msm_clocksource);
-}
-
 static void __init msm_timer_init(void)
 {
-	struct clock_event_device *ce = &msm_clockevent;
-	struct clocksource *cs = &msm_clocksource;
+	int i;
 	int res;
-	u32 dgt_hz;
+	struct irq_chip *chip;
+	struct msm_clock *dgt = &msm_clocks[MSM_CLOCK_DGT];
+	struct msm_clock *gpt = &msm_clocks[MSM_CLOCK_GPT];
 
-	if (cpu_is_msm7x01()) {
-		event_base = MSM_CSR_BASE;
-		source_base = MSM_CSR_BASE + 0x10;
-		dgt_hz = 19200000 >> MSM_DGT_SHIFT; /* 600 KHz */
-		cs->read = msm_read_timer_count_shift;
-		cs->mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT));
-	} else if (cpu_is_msm7x30()) {
-		event_base = MSM_CSR_BASE + 0x04;
-		source_base = MSM_CSR_BASE + 0x24;
-		dgt_hz = 24576000 / 4;
-	} else if (cpu_is_qsd8x50()) {
-		event_base = MSM_CSR_BASE;
-		source_base = MSM_CSR_BASE + 0x10;
-		dgt_hz = 19200000 / 4;
-	} else if (cpu_is_msm8x60() || cpu_is_msm8960()) {
-		event_base = MSM_TMR_BASE + 0x04;
-		/* Use CPU0's timer as the global clock source. */
-		source_base = MSM_TMR0_BASE + 0x24;
-		dgt_hz = 27000000 / 4;
-		writel_relaxed(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
-	} else
-		BUG();
-
-	writel_relaxed(0, event_base + TIMER_ENABLE);
-	writel_relaxed(0, event_base + TIMER_CLEAR);
-	writel_relaxed(~0, event_base + TIMER_MATCH_VAL);
-	ce->cpumask = cpumask_of(0);
-
-	ce->irq = INT_GP_TIMER_EXP;
-	clockevents_config_and_register(ce, GPT_HZ, 4, 0xffffffff);
-	if (cpu_is_msm8x60() || cpu_is_msm8960()) {
-		msm_evt.percpu_evt = alloc_percpu(struct clock_event_device *);
-		if (!msm_evt.percpu_evt) {
-			pr_err("memory allocation failed for %s\n", ce->name);
-			goto err;
+	if (cpu_is_msm7x01() || cpu_is_msm7x25() || cpu_is_msm7x27() ||
+	    cpu_is_msm7x25a() || cpu_is_msm7x27a() || cpu_is_msm7x25aa() ||
+	    cpu_is_msm7x27aa() || cpu_is_msm8625() || cpu_is_msm7x25ab()) {
+		dgt->shift = MSM_DGT_SHIFT;
+		dgt->freq = 19200000 >> MSM_DGT_SHIFT;
+		dgt->clockevent.shift = 32 + MSM_DGT_SHIFT;
+		dgt->clocksource.mask = CLOCKSOURCE_MASK(32 - MSM_DGT_SHIFT);
+		dgt->clocksource.shift = 24 - MSM_DGT_SHIFT;
+		gpt->regbase = MSM_TMR_BASE;
+		dgt->regbase = MSM_TMR_BASE + 0x10;
+		gpt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT
+			   |  MSM_CLOCK_FLAGS_ODD_MATCH_WRITE
+			   |  MSM_CLOCK_FLAGS_DELAYED_WRITE_POST;
+		if (cpu_is_msm8625()) {
+			dgt->irq = MSM8625_INT_DEBUG_TIMER_EXP;
+			gpt->irq = MSM8625_INT_GP_TIMER_EXP;
+			global_timer_offset =  MSM_TMR0_BASE - MSM_TMR_BASE;
 		}
-		*__this_cpu_ptr(msm_evt.percpu_evt) = ce;
-		res = request_percpu_irq(ce->irq, msm_timer_interrupt,
-					 ce->name, msm_evt.percpu_evt);
-		if (!res) {
-			enable_percpu_irq(ce->irq, 0);
-#ifdef CONFIG_LOCAL_TIMERS
-			local_timer_register(&msm_local_timer_ops);
-#endif
+	} else if (cpu_is_qsd8x50()) {
+		dgt->freq = 4800000;
+		gpt->regbase = MSM_TMR_BASE;
+		dgt->regbase = MSM_TMR_BASE + 0x10;
+	} else if (cpu_is_fsm9xxx())
+		dgt->freq = 4800000;
+	else if (cpu_is_msm7x30() || cpu_is_msm8x55()) {
+		gpt->status_mask = BIT(10);
+		dgt->status_mask = BIT(2);
+		dgt->freq = 6144000;
+	} else if (cpu_is_msm8x60()) {
+		global_timer_offset = MSM_TMR0_BASE - MSM_TMR_BASE;
+		gpt->status_mask = BIT(10);
+		dgt->status_mask = BIT(2);
+		dgt->freq = 6750000;
+		__raw_writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
+	} else if (cpu_is_msm9615()) {
+		dgt->freq = 6750000;
+		__raw_writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
+		gpt->status_mask = BIT(10);
+		dgt->status_mask = BIT(2);
+		gpt->freq = 32765;
+		gpt_hz = 32765;
+		sclk_hz = 32765;
+		gpt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT;
+		dgt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT;
+	} else if (cpu_is_msm8960() || cpu_is_apq8064() || cpu_is_msm8930()) {
+		global_timer_offset = MSM_TMR0_BASE - MSM_TMR_BASE;
+		dgt->freq = 6750000;
+		__raw_writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
+		gpt->status_mask = BIT(10);
+		dgt->status_mask = BIT(2);
+		gpt->freq = 32765;
+		gpt_hz = 32765;
+		sclk_hz = 32765;
+		if (!cpu_is_msm8930()) {
+			gpt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT;
+			dgt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT;
 		}
 	} else {
-		msm_evt.evt = ce;
-		res = request_irq(ce->irq, msm_timer_interrupt,
-				  IRQF_TIMER | IRQF_NOBALANCING |
-				  IRQF_TRIGGER_RISING, ce->name, &msm_evt.evt);
+		WARN(1, "Timer running on unknown hardware. Configure this! "
+			"Assuming default configuration.\n");
+		dgt->freq = 6750000;
 	}
 
-	if (res)
-		pr_err("request_irq failed for %s\n", ce->name);
-err:
-	writel_relaxed(TIMER_ENABLE_EN, source_base + TIMER_ENABLE);
-	res = clocksource_register_hz(cs, dgt_hz);
-	if (res)
-		pr_err("clocksource_register failed\n");
-	setup_sched_clock(msm_sched_clock_read,
-			cpu_is_msm7x01() ? 32 - MSM_DGT_SHIFT : 32, dgt_hz);
+	if (msm_clocks[MSM_CLOCK_GPT].clocksource.rating > DG_TIMER_RATING)
+		msm_global_timer = MSM_CLOCK_GPT;
+	else
+		msm_global_timer = MSM_CLOCK_DGT;
+
+	for (i = 0; i < ARRAY_SIZE(msm_clocks); i++) {
+		struct msm_clock *clock = &msm_clocks[i];
+		struct clock_event_device *ce = &clock->clockevent;
+		struct clocksource *cs = &clock->clocksource;
+		__raw_writel(0, clock->regbase + TIMER_ENABLE);
+		__raw_writel(0, clock->regbase + TIMER_CLEAR);
+		__raw_writel(~0, clock->regbase + TIMER_MATCH_VAL);
+
+		if ((clock->freq << clock->shift) == gpt_hz) {
+			clock->rollover_offset = 0;
+		} else {
+			uint64_t temp;
+
+			temp = clock->freq << clock->shift;
+			temp <<= 32;
+			do_div(temp, gpt_hz);
+
+			clock->rollover_offset = (uint32_t) temp;
+		}
+
+		ce->mult = div_sc(clock->freq, NSEC_PER_SEC, ce->shift);
+		/* allow at least 10 seconds to notice that the timer wrapped */
+		ce->max_delta_ns =
+			clockevent_delta2ns(0xf0000000 >> clock->shift, ce);
+		/* ticks gets rounded down by one */
+		ce->min_delta_ns =
+			clockevent_delta2ns(clock->write_delay + 4, ce);
+		ce->cpumask = cpumask_of(0);
+
+		cs->mult = clocksource_hz2mult(clock->freq, cs->shift);
+		res = clocksource_register(cs);
+		if (res)
+			printk(KERN_ERR "msm_timer_init: clocksource_register "
+			       "failed for %s\n", cs->name);
+
+		ce->irq = clock->irq;
+		if (cpu_is_msm8x60() || cpu_is_msm8960() || cpu_is_apq8064() ||
+				cpu_is_msm8930() || cpu_is_msm9615() ||
+				cpu_is_msm8625()) {
+			clock->percpu_evt = alloc_percpu(struct clock_event_device *);
+			if (!clock->percpu_evt) {
+				pr_err("msm_timer_init: memory allocation "
+				       "failed for %s\n", ce->name);
+				continue;
+			}
+
+			*__this_cpu_ptr(clock->percpu_evt) = ce;
+			res = request_percpu_irq(ce->irq, msm_timer_interrupt,
+						 ce->name, clock->percpu_evt);
+			if (!res)
+				enable_percpu_irq(ce->irq,
+						 IRQ_TYPE_EDGE_RISING);
+		} else {
+			clock->evt = ce;
+			res = request_irq(ce->irq, msm_timer_interrupt,
+					  IRQF_TIMER | IRQF_NOBALANCING | IRQF_TRIGGER_RISING,
+					  ce->name, &clock->evt);
+		}
+
+		if (res)
+			pr_err("msm_timer_init: request_irq failed for %s\n",
+			       ce->name);
+
+		chip = irq_get_chip(clock->irq);
+		if (chip && chip->irq_mask)
+			chip->irq_mask(irq_get_irq_data(clock->irq));
+
+		if (clock->status_mask)
+			while (__raw_readl(MSM_TMR_BASE + TIMER_STATUS) &
+			       clock->status_mask)
+				;
+
+		clockevents_register_device(ce);
+	}
+	msm_sched_clock_init();
+
+#ifdef ARCH_HAS_READ_CURRENT_TIMER
+	if (is_smp()) {
+		__raw_writel(1,
+			msm_clocks[MSM_CLOCK_DGT].regbase + TIMER_ENABLE);
+		set_delay_fn(read_current_timer_delay_loop);
+	}
+#endif
+
+#ifdef CONFIG_LOCAL_TIMERS
+	local_timer_register(&msm_lt_ops);
+#endif
 }
 
 struct sys_timer msm_timer = {
diff --git a/arch/arm/mach-msm/timer.h b/arch/arm/mach-msm/timer.h
new file mode 100644
index 0000000..5d18bb4
--- /dev/null
+++ b/arch/arm/mach-msm/timer.h
@@ -0,0 +1,31 @@
+/* Copyright (c) 2008-2009, 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
+ * 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 _ARCH_ARM_MACH_MSM_TIMER_H_
+#define _ARCH_ARM_MACH_MSM_TIMER_H_
+
+extern struct sys_timer msm_timer;
+
+void __iomem *msm_timer_get_timer0_base(void);
+uint32_t msm_timer_get_sclk_ticks(void);
+int msm_timer_init_time_sync(void (*timeout)(void));
+#ifndef CONFIG_ARM_ARCH_TIMER
+int64_t msm_timer_enter_idle(void);
+void msm_timer_exit_idle(int low_power);
+int64_t msm_timer_get_sclk_time(int64_t *period);
+#else
+static inline int64_t msm_timer_enter_idle(void) { return 0; }
+static inline void msm_timer_exit_idle(int low_power) { return; }
+static inline int64_t msm_timer_get_sclk_time(int64_t *period) { return 0; }
+#endif
+#endif
diff --git a/arch/arm/mach-msm/tz_log.c b/arch/arm/mach-msm/tz_log.c
new file mode 100644
index 0000000..7426bb2
--- /dev/null
+++ b/arch/arm/mach-msm/tz_log.c
@@ -0,0 +1,564 @@
+/* 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
+ * 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/debugfs.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <asm/uaccess.h>
+
+#define DEBUG_MAX_RW_BUF 4096
+
+/*
+ * Preprocessor Definitions and Constants
+ */
+#define TZBSP_CPU_COUNT 0x02
+/*
+ * Number of VMID Tables
+ */
+#define TZBSP_DIAG_NUM_OF_VMID 16
+/*
+ * VMID Description length
+ */
+#define TZBSP_DIAG_VMID_DESC_LEN 7
+/*
+ * Number of Interrupts
+ */
+#define TZBSP_DIAG_INT_NUM  32
+/*
+ * Length of descriptive name associated with Interrupt
+ */
+#define TZBSP_MAX_INT_DESC 16
+/*
+ * VMID Table
+ */
+struct tzdbg_vmid_t {
+	uint8_t vmid; /* Virtual Machine Identifier */
+	uint8_t desc[TZBSP_DIAG_VMID_DESC_LEN];	/* ASCII Text */
+};
+/*
+ * Boot Info Table
+ */
+struct tzdbg_boot_info_t {
+	uint32_t wb_entry_cnt;	/* Warmboot entry CPU Counter */
+	uint32_t wb_exit_cnt;	/* Warmboot exit CPU Counter */
+	uint32_t pc_entry_cnt;	/* Power Collapse entry CPU Counter */
+	uint32_t pc_exit_cnt;	/* Power Collapse exit CPU counter */
+	uint32_t warm_jmp_addr;	/* Last Warmboot Jump Address */
+	uint32_t spare;	/* Reserved for future use. */
+};
+/*
+ * Reset Info Table
+ */
+struct tzdbg_reset_info_t {
+	uint32_t reset_type;	/* Reset Reason */
+	uint32_t reset_cnt;	/* Number of resets occured/CPU */
+};
+/*
+ * Interrupt Info Table
+ */
+struct tzdbg_int_t {
+	/*
+	 * Type of Interrupt/exception
+	 */
+	uint16_t int_info;
+	/*
+	 * Availability of the slot
+	 */
+	uint8_t avail;
+	/*
+	 * Reserved for future use
+	 */
+	uint8_t spare;
+	/*
+	 * Interrupt # for IRQ and FIQ
+	 */
+	uint32_t int_num;
+	/*
+	 * ASCII text describing type of interrupt e.g:
+	 * Secure Timer, EBI XPU. This string is always null terminated,
+	 * supporting at most TZBSP_MAX_INT_DESC characters.
+	 * Any additional characters are truncated.
+	 */
+	uint8_t int_desc[TZBSP_MAX_INT_DESC];
+	uint64_t int_count[TZBSP_CPU_COUNT]; /* # of times seen per CPU */
+};
+/*
+ * Diagnostic Table
+ */
+struct tzdbg_t {
+	uint32_t magic_num;
+	uint32_t version;
+	/*
+	 * Number of CPU's
+	 */
+	uint32_t cpu_count;
+	/*
+	 * Offset of VMID Table
+	 */
+	uint32_t vmid_info_off;
+	/*
+	 * Offset of Boot Table
+	 */
+	uint32_t boot_info_off;
+	/*
+	 * Offset of Reset info Table
+	 */
+	uint32_t reset_info_off;
+	/*
+	 * Offset of Interrupt info Table
+	 */
+	uint32_t int_info_off;
+	/*
+	 * Ring Buffer Offset
+	 */
+	uint32_t ring_off;
+	/*
+	 * Ring Buffer Length
+	 */
+	uint32_t ring_len;
+	/*
+	 * VMID to EE Mapping
+	 */
+	struct tzdbg_vmid_t vmid_info[TZBSP_DIAG_NUM_OF_VMID];
+	/*
+	 * Boot Info
+	 */
+	struct tzdbg_boot_info_t  boot_info[TZBSP_CPU_COUNT];
+	/*
+	 * Reset Info
+	 */
+	struct tzdbg_reset_info_t reset_info[TZBSP_CPU_COUNT];
+	uint32_t num_interrupts;
+	struct tzdbg_int_t  int_info[TZBSP_DIAG_INT_NUM];
+	/*
+	 * We need at least 2K for the ring buffer
+	 */
+	uint8_t *ring_buffer;	/* TZ Ring Buffer */
+};
+
+/*
+ * Enumeration order for VMID's
+ */
+enum tzdbg_stats_type {
+	TZDBG_BOOT = 0,
+	TZDBG_RESET,
+	TZDBG_INTERRUPT,
+	TZDBG_VMID,
+	TZDBG_GENERAL,
+	TZDBG_LOG,
+	TZDBG_STATS_MAX,
+};
+
+struct tzdbg_stat {
+	char *name;
+	char *data;
+};
+
+struct tzdbg {
+	void __iomem *virt_iobase;
+	struct tzdbg_t *diag_buf;
+	char *disp_buf;
+	int debug_tz[TZDBG_STATS_MAX];
+	struct tzdbg_stat stat[TZDBG_STATS_MAX];
+};
+
+static struct tzdbg tzdbg = {
+
+	.stat[TZDBG_BOOT].name = "boot",
+	.stat[TZDBG_RESET].name = "reset",
+	.stat[TZDBG_INTERRUPT].name = "interrupt",
+	.stat[TZDBG_VMID].name = "vmid",
+	.stat[TZDBG_GENERAL].name = "general",
+	.stat[TZDBG_LOG].name = "log",
+};
+
+
+/*
+ * Debugfs data structure and functions
+ */
+
+static int _disp_tz_general_stats(void)
+{
+	int len = 0;
+
+	len += snprintf(tzdbg.disp_buf + len, DEBUG_MAX_RW_BUF - 1,
+			"   Version        : 0x%x\n"
+			"   Magic Number   : 0x%x\n"
+			"   Number of CPU  : %d\n",
+			tzdbg.diag_buf->version,
+			tzdbg.diag_buf->magic_num,
+			tzdbg.diag_buf->cpu_count);
+	tzdbg.stat[TZDBG_GENERAL].data = tzdbg.disp_buf;
+	return len;
+}
+
+static int _disp_tz_vmid_stats(void)
+{
+	int i, num_vmid;
+	int len = 0;
+	struct tzdbg_vmid_t *ptr;
+
+	ptr = (struct tzdbg_vmid_t *)((unsigned char *)tzdbg.diag_buf +
+					tzdbg.diag_buf->vmid_info_off);
+	num_vmid = ((tzdbg.diag_buf->boot_info_off -
+				tzdbg.diag_buf->vmid_info_off)/
+					(sizeof(struct tzdbg_vmid_t)));
+
+	for (i = 0; i < num_vmid; i++) {
+		if (ptr->vmid < 0xFF) {
+			len += snprintf(tzdbg.disp_buf + len,
+				(DEBUG_MAX_RW_BUF - 1) - len,
+				"   0x%x        %s\n",
+				(uint32_t)ptr->vmid, (uint8_t *)ptr->desc);
+		}
+		if (len > (DEBUG_MAX_RW_BUF - 1)) {
+			pr_warn("%s: Cannot fit all info into the buffer\n",
+								__func__);
+			break;
+		}
+		ptr++;
+	}
+
+	tzdbg.stat[TZDBG_VMID].data = tzdbg.disp_buf;
+	return len;
+}
+
+static int _disp_tz_boot_stats(void)
+{
+	int i;
+	int len = 0;
+	struct tzdbg_boot_info_t *ptr;
+
+	ptr = (struct tzdbg_boot_info_t *)((unsigned char *)tzdbg.diag_buf +
+					tzdbg.diag_buf->boot_info_off);
+
+	for (i = 0; i < tzdbg.diag_buf->cpu_count; i++) {
+		len += snprintf(tzdbg.disp_buf + len,
+				(DEBUG_MAX_RW_BUF - 1) - len,
+				"  CPU #: %d\n"
+				"     Warmboot jump address     : 0x%x\n"
+				"     Warmboot entry CPU counter: 0x%x\n"
+				"     Warmboot exit CPU counter : 0x%x\n"
+				"     Power Collapse entry CPU counter: 0x%x\n"
+				"     Power Collapse exit CPU counter : 0x%x\n",
+				i, ptr->warm_jmp_addr, ptr->wb_entry_cnt,
+				ptr->wb_exit_cnt, ptr->pc_entry_cnt,
+				ptr->pc_exit_cnt);
+
+		if (len > (DEBUG_MAX_RW_BUF - 1)) {
+			pr_warn("%s: Cannot fit all info into the buffer\n",
+								__func__);
+			break;
+		}
+		ptr++;
+	}
+	tzdbg.stat[TZDBG_BOOT].data = tzdbg.disp_buf;
+	return len;
+}
+
+static int _disp_tz_reset_stats(void)
+{
+	int i;
+	int len = 0;
+	struct tzdbg_reset_info_t *ptr;
+
+	ptr = (struct tzdbg_reset_info_t *)((unsigned char *)tzdbg.diag_buf +
+					tzdbg.diag_buf->reset_info_off);
+
+	for (i = 0; i < tzdbg.diag_buf->cpu_count; i++) {
+		len += snprintf(tzdbg.disp_buf + len,
+				(DEBUG_MAX_RW_BUF - 1) - len,
+				"  CPU #: %d\n"
+				"     Reset Type (reason)       : 0x%x\n"
+				"     Reset counter             : 0x%x\n",
+				i, ptr->reset_type, ptr->reset_cnt);
+
+		if (len > (DEBUG_MAX_RW_BUF - 1)) {
+			pr_warn("%s: Cannot fit all info into the buffer\n",
+								__func__);
+			break;
+		}
+
+		ptr++;
+	}
+	tzdbg.stat[TZDBG_RESET].data = tzdbg.disp_buf;
+	return len;
+}
+
+static int _disp_tz_interrupt_stats(void)
+{
+	int i, j, int_info_size;
+	int len = 0;
+	int *num_int;
+	unsigned char *ptr;
+	struct tzdbg_int_t *tzdbg_ptr;
+
+	num_int = (uint32_t *)((unsigned char *)tzdbg.diag_buf +
+			(tzdbg.diag_buf->int_info_off - sizeof(uint32_t)));
+	ptr = ((unsigned char *)tzdbg.diag_buf +
+					tzdbg.diag_buf->int_info_off);
+	int_info_size = ((tzdbg.diag_buf->ring_off -
+				tzdbg.diag_buf->int_info_off)/(*num_int));
+
+	for (i = 0; i < (*num_int); i++) {
+		tzdbg_ptr = (struct tzdbg_int_t *)ptr;
+		len += snprintf(tzdbg.disp_buf + len,
+				(DEBUG_MAX_RW_BUF - 1) - len,
+				"     Interrupt Number          : 0x%x\n"
+				"     Type of Interrupt         : 0x%x\n"
+				"     Description of interrupt  : %s\n",
+				tzdbg_ptr->int_num,
+				(uint32_t)tzdbg_ptr->int_info,
+				(uint8_t *)tzdbg_ptr->int_desc);
+		for (j = 0; j < tzdbg.diag_buf->cpu_count; j++) {
+			len += snprintf(tzdbg.disp_buf + len,
+				(DEBUG_MAX_RW_BUF - 1) - len,
+				"     int_count on CPU # %d      : %u\n",
+				(uint32_t)j,
+				(uint32_t)tzdbg_ptr->int_count[j]);
+		}
+		len += snprintf(tzdbg.disp_buf + len, DEBUG_MAX_RW_BUF - 1,
+									"\n");
+
+		if (len > (DEBUG_MAX_RW_BUF - 1)) {
+			pr_warn("%s: Cannot fit all info into the buffer\n",
+								__func__);
+			break;
+		}
+
+		ptr += int_info_size;
+	}
+	tzdbg.stat[TZDBG_INTERRUPT].data = tzdbg.disp_buf;
+	return len;
+}
+
+static int _disp_tz_log_stats(void)
+{
+	int len = 0;
+	unsigned char *ptr;
+
+	ptr = (unsigned char *)tzdbg.diag_buf +
+					tzdbg.diag_buf->ring_off;
+	len += snprintf(tzdbg.disp_buf, (DEBUG_MAX_RW_BUF - 1) - len,
+							"%s\n", ptr);
+
+	tzdbg.stat[TZDBG_LOG].data = tzdbg.disp_buf;
+	return len;
+}
+
+static ssize_t tzdbgfs_read(struct file *file, char __user *buf,
+	size_t count, loff_t *offp)
+{
+	int len = 0;
+	int *tz_id =  file->private_data;
+
+	memcpy_fromio((void *)tzdbg.diag_buf, tzdbg.virt_iobase,
+						DEBUG_MAX_RW_BUF);
+	switch (*tz_id) {
+	case TZDBG_BOOT:
+		len = _disp_tz_boot_stats();
+		break;
+	case TZDBG_RESET:
+		len = _disp_tz_reset_stats();
+		break;
+	case TZDBG_INTERRUPT:
+		len = _disp_tz_interrupt_stats();
+		break;
+	case TZDBG_GENERAL:
+		len = _disp_tz_general_stats();
+		break;
+	case TZDBG_VMID:
+		len = _disp_tz_vmid_stats();
+		break;
+	case TZDBG_LOG:
+		len = _disp_tz_log_stats();
+		break;
+	default:
+		break;
+	}
+
+	if (len > count)
+		len = count;
+
+	return simple_read_from_buffer(buf, len, offp,
+				tzdbg.stat[(*tz_id)].data, len);
+}
+
+static int tzdbgfs_open(struct inode *inode, struct file *pfile)
+{
+	pfile->private_data = inode->i_private;
+	return 0;
+}
+
+const struct file_operations tzdbg_fops = {
+	.owner   = THIS_MODULE,
+	.read    = tzdbgfs_read,
+	.open    = tzdbgfs_open,
+};
+
+static int  tzdbgfs_init(struct platform_device *pdev)
+{
+	int rc = 0;
+	int i;
+	struct dentry           *dent_dir;
+	struct dentry           *dent;
+
+	dent_dir = debugfs_create_dir("tzdbg", NULL);
+	if (dent_dir == NULL) {
+		dev_err(&pdev->dev, "tzdbg debugfs_create_dir failed\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < TZDBG_STATS_MAX; i++) {
+		tzdbg.debug_tz[i] = i;
+		dent = debugfs_create_file(tzdbg.stat[i].name,
+				S_IRUGO, dent_dir,
+				&tzdbg.debug_tz[i], &tzdbg_fops);
+		if (dent == NULL) {
+			dev_err(&pdev->dev, "TZ debugfs_create_file failed\n");
+			rc = -ENOMEM;
+			goto err;
+		}
+	}
+	tzdbg.disp_buf = kzalloc(DEBUG_MAX_RW_BUF, GFP_KERNEL);
+	if (tzdbg.disp_buf == NULL) {
+		pr_err("%s: Can't Allocate memory for tzdbg.disp_buf\n",
+			__func__);
+
+		goto err;
+	}
+	platform_set_drvdata(pdev, dent_dir);
+	return 0;
+err:
+	debugfs_remove_recursive(dent_dir);
+
+	return rc;
+}
+
+static void tzdbgfs_exit(struct platform_device *pdev)
+{
+	struct dentry           *dent_dir;
+
+	kzfree(tzdbg.disp_buf);
+	dent_dir = platform_get_drvdata(pdev);
+	debugfs_remove_recursive(dent_dir);
+}
+
+/*
+ * Driver functions
+ */
+static int __devinit tz_log_probe(struct platform_device *pdev)
+{
+	struct resource *resource;
+	void __iomem *virt_iobase;
+	uint32_t tzdiag_phy_iobase;
+	uint32_t *ptr = NULL;
+
+	/*
+	 * Get address that stores the physical location of 4KB
+	 * diagnostic data
+	 */
+	resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!resource) {
+		dev_err(&pdev->dev,
+				"%s: ERROR Missing MEM resource\n", __func__);
+		return -ENXIO;
+	};
+	/*
+	 * Map address that stores the physical location of 4KB
+	 * diagnostic data
+	 */
+	virt_iobase = devm_ioremap_nocache(&pdev->dev, resource->start,
+				resource->end - resource->start + 1);
+	if (!virt_iobase) {
+		dev_err(&pdev->dev,
+			"%s: ERROR could not ioremap: start=%p, len=%u\n",
+			__func__, (void *) resource->start,
+			(resource->end - resource->start + 1));
+		return -ENXIO;
+	}
+	/*
+	 * Retrieve the address of 4KB diagnostic data
+	 */
+	tzdiag_phy_iobase = readl_relaxed(virt_iobase);
+
+	/*
+	 * Map the 4KB diagnostic information area
+	 */
+	tzdbg.virt_iobase = devm_ioremap_nocache(&pdev->dev,
+				tzdiag_phy_iobase, DEBUG_MAX_RW_BUF);
+
+	if (!tzdbg.virt_iobase) {
+		dev_err(&pdev->dev,
+			"%s: ERROR could not ioremap: start=%p, len=%u\n",
+			__func__, (void *) tzdiag_phy_iobase, DEBUG_MAX_RW_BUF);
+		return -ENXIO;
+	}
+
+	ptr = kzalloc(DEBUG_MAX_RW_BUF, GFP_KERNEL);
+	if (ptr == NULL) {
+		pr_err("%s: Can't Allocate memory: ptr\n",
+			__func__);
+		return -ENXIO;
+	}
+
+	tzdbg.diag_buf = (struct tzdbg_t *)ptr;
+
+	if (tzdbgfs_init(pdev))
+		goto err;
+
+	return 0;
+err:
+	kfree(tzdbg.diag_buf);
+	return -ENXIO;
+}
+
+
+static int __devexit tz_log_remove(struct platform_device *pdev)
+{
+	kzfree(tzdbg.diag_buf);
+	tzdbgfs_exit(pdev);
+
+	return 0;
+}
+
+static struct platform_driver tz_log_driver = {
+	.probe		= tz_log_probe,
+	.remove		= __devexit_p(tz_log_remove),
+	.driver		= {
+		.name = "tz_log",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init tz_log_init(void)
+{
+	return platform_driver_register(&tz_log_driver);
+}
+
+static void __exit tz_log_exit(void)
+{
+	platform_driver_unregister(&tz_log_driver);
+}
+
+module_init(tz_log_init);
+module_exit(tz_log_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("TZ Log driver");
+MODULE_VERSION("1.1");
+MODULE_ALIAS("platform:tz_log");
diff --git a/arch/arm/mach-msm/vreg.c b/arch/arm/mach-msm/vreg.c
index bd66ed0..271da86 100644
--- a/arch/arm/mach-msm/vreg.c
+++ b/arch/arm/mach-msm/vreg.c
@@ -1,7 +1,7 @@
 /* arch/arm/mach-msm/vreg.c
  *
  * Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012 Code Aurora Forum. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -16,170 +16,211 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/device.h>
 #include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/atomic.h>
 #include <linux/debugfs.h>
-#include <linux/module.h>
+#include <linux/regulator/consumer.h>
 #include <linux/string.h>
 #include <mach/vreg.h>
+#include <mach/proc_comm.h>
 
-#include "proc_comm.h"
+#if defined(CONFIG_MSM_VREG_SWITCH_INVERTED)
+#define VREG_SWITCH_ENABLE 0
+#define VREG_SWITCH_DISABLE 1
+#else
+#define VREG_SWITCH_ENABLE 1
+#define VREG_SWITCH_DISABLE 0
+#endif
 
 struct vreg {
-	const char *name;
-	unsigned id;
-	int status;
-	unsigned refcnt;
+	struct list_head	list;
+	struct mutex		lock;
+	const char		*name;
+	u64			refcnt;
+	unsigned		mv;
+	struct regulator	*reg;
 };
 
-#define VREG(_name, _id, _status, _refcnt) \
-	{ .name = _name, .id = _id, .status = _status, .refcnt = _refcnt }
+static LIST_HEAD(vreg_list);
+static DEFINE_MUTEX(vreg_lock);
 
-static struct vreg vregs[] = {
-	VREG("msma",	0, 0, 0),
-	VREG("msmp",	1, 0, 0),
-	VREG("msme1",	2, 0, 0),
-	VREG("msmc1",	3, 0, 0),
-	VREG("msmc2",	4, 0, 0),
-	VREG("gp3",	5, 0, 0),
-	VREG("msme2",	6, 0, 0),
-	VREG("gp4",	7, 0, 0),
-	VREG("gp1",	8, 0, 0),
-	VREG("tcxo",	9, 0, 0),
-	VREG("pa",	10, 0, 0),
-	VREG("rftx",	11, 0, 0),
-	VREG("rfrx1",	12, 0, 0),
-	VREG("rfrx2",	13, 0, 0),
-	VREG("synt",	14, 0, 0),
-	VREG("wlan",	15, 0, 0),
-	VREG("usb",	16, 0, 0),
-	VREG("boost",	17, 0, 0),
-	VREG("mmc",	18, 0, 0),
-	VREG("ruim",	19, 0, 0),
-	VREG("msmc0",	20, 0, 0),
-	VREG("gp2",	21, 0, 0),
-	VREG("gp5",	22, 0, 0),
-	VREG("gp6",	23, 0, 0),
-	VREG("rf",	24, 0, 0),
-	VREG("rf_vco",	26, 0, 0),
-	VREG("mpll",	27, 0, 0),
-	VREG("s2",	28, 0, 0),
-	VREG("s3",	29, 0, 0),
-	VREG("rfubm",	30, 0, 0),
-	VREG("ncp",	31, 0, 0),
-	VREG("gp7",	32, 0, 0),
-	VREG("gp8",	33, 0, 0),
-	VREG("gp9",	34, 0, 0),
-	VREG("gp10",	35, 0, 0),
-	VREG("gp11",	36, 0, 0),
-	VREG("gp12",	37, 0, 0),
-	VREG("gp13",	38, 0, 0),
-	VREG("gp14",	39, 0, 0),
-	VREG("gp15",	40, 0, 0),
-	VREG("gp16",	41, 0, 0),
-	VREG("gp17",	42, 0, 0),
-	VREG("s4",	43, 0, 0),
-	VREG("usb2",	44, 0, 0),
-	VREG("wlan2",	45, 0, 0),
-	VREG("xo_out",	46, 0, 0),
-	VREG("lvsw0",	47, 0, 0),
-	VREG("lvsw1",	48, 0, 0),
-};
+#ifdef CONFIG_DEBUG_FS
+static void vreg_add_debugfs(struct vreg *vreg);
+#else
+static inline void vreg_add_debugfs(struct vreg *vreg) { }
+#endif
+
+static struct vreg *vreg_create(const char *id)
+{
+	int rc;
+	struct vreg *vreg;
+
+	vreg = kzalloc(sizeof(*vreg), GFP_KERNEL);
+	if (!vreg) {
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	INIT_LIST_HEAD(&vreg->list);
+	mutex_init(&vreg->lock);
+
+	vreg->reg = regulator_get(NULL, id);
+	if (IS_ERR(vreg->reg)) {
+		rc = PTR_ERR(vreg->reg);
+		goto free_vreg;
+	}
+
+	vreg->name = kstrdup(id, GFP_KERNEL);
+	if (!vreg->name) {
+		rc = -ENOMEM;
+		goto put_reg;
+	}
+
+	list_add_tail(&vreg->list, &vreg_list);
+	vreg_add_debugfs(vreg);
+
+	return vreg;
+
+put_reg:
+	regulator_put(vreg->reg);
+free_vreg:
+	kfree(vreg);
+error:
+	return ERR_PTR(rc);
+}
+
+static void vreg_destroy(struct vreg *vreg)
+{
+	if (!vreg)
+		return;
+
+	if (vreg->refcnt)
+		regulator_disable(vreg->reg);
+
+	kfree(vreg->name);
+	regulator_put(vreg->reg);
+	kfree(vreg);
+}
 
 struct vreg *vreg_get(struct device *dev, const char *id)
 {
-	int n;
-	for (n = 0; n < ARRAY_SIZE(vregs); n++) {
-		if (!strcmp(vregs[n].name, id))
-			return vregs + n;
+	struct vreg *vreg = NULL;
+
+	if (!id)
+		return ERR_PTR(-EINVAL);
+
+	mutex_lock(&vreg_lock);
+	list_for_each_entry(vreg, &vreg_list, list) {
+		if (!strncmp(vreg->name, id, 10))
+			goto ret;
 	}
-	return ERR_PTR(-ENOENT);
+
+	vreg = vreg_create(id);
+
+ret:
+	mutex_unlock(&vreg_lock);
+	return vreg;
 }
+EXPORT_SYMBOL(vreg_get);
 
 void vreg_put(struct vreg *vreg)
 {
+	kfree(vreg->name);
+	regulator_put(vreg->reg);
+	list_del(&vreg->list);
+	kfree(vreg);
 }
 
 int vreg_enable(struct vreg *vreg)
 {
-	unsigned id = vreg->id;
-	unsigned enable = 1;
+	int rc = 0;
+	if (!vreg)
+		return -ENODEV;
 
-	if (vreg->refcnt == 0)
-		vreg->status = msm_proc_comm(PCOM_VREG_SWITCH, &id, &enable);
+	mutex_lock(&vreg->lock);
+	if (vreg->refcnt == 0) {
+		rc = regulator_enable(vreg->reg);
+		if (!rc)
+			vreg->refcnt++;
+	} else {
+		rc = 0;
+		if (vreg->refcnt < UINT_MAX)
+			vreg->refcnt++;
+	}
+	mutex_unlock(&vreg->lock);
 
-	if ((vreg->refcnt < UINT_MAX) && (!vreg->status))
-		vreg->refcnt++;
-
-	return vreg->status;
+	return rc;
 }
+EXPORT_SYMBOL(vreg_enable);
 
 int vreg_disable(struct vreg *vreg)
 {
-	unsigned id = vreg->id;
-	unsigned enable = 0;
+	int rc = 0;
+	if (!vreg)
+		return -ENODEV;
 
-	if (!vreg->refcnt)
-		return 0;
-
-	if (vreg->refcnt == 1)
-		vreg->status = msm_proc_comm(PCOM_VREG_SWITCH, &id, &enable);
-
-	if (!vreg->status)
+	mutex_lock(&vreg->lock);
+	if (vreg->refcnt == 0) {
+		pr_warn("%s: unbalanced disables for vreg %s\n",
+				__func__, vreg->name);
+		rc = -EINVAL;
+	} else if (vreg->refcnt == 1) {
+		rc = regulator_disable(vreg->reg);
+		if (!rc)
+			vreg->refcnt--;
+	} else {
+		rc = 0;
 		vreg->refcnt--;
+	}
+	mutex_unlock(&vreg->lock);
 
-	return vreg->status;
+	return rc;
 }
+EXPORT_SYMBOL(vreg_disable);
 
 int vreg_set_level(struct vreg *vreg, unsigned mv)
 {
-	unsigned id = vreg->id;
+	unsigned uv;
+	int rc;
 
-	vreg->status = msm_proc_comm(PCOM_VREG_SET_LEVEL, &id, &mv);
-	return vreg->status;
+	if (!vreg)
+		return -EINVAL;
+
+	if (mv > (UINT_MAX / 1000))
+		return -ERANGE;
+
+	uv = mv * 1000;
+
+	mutex_lock(&vreg->lock);
+	rc = regulator_set_voltage(vreg->reg, uv, uv);
+	if (!rc)
+		vreg->mv = mv;
+	mutex_unlock(&vreg->lock);
+
+	return rc;
 }
+EXPORT_SYMBOL(vreg_set_level);
 
 #if defined(CONFIG_DEBUG_FS)
 
-static int vreg_debug_set(void *data, u64 val)
-{
-	struct vreg *vreg = data;
-	switch (val) {
-	case 0:
-		vreg_disable(vreg);
-		break;
-	case 1:
-		vreg_enable(vreg);
-		break;
-	default:
-		vreg_set_level(vreg, val);
-		break;
-	}
-	return 0;
-}
-
-static int vreg_debug_get(void *data, u64 *val)
+static int vreg_debug_enabled_set(void *data, u64 val)
 {
 	struct vreg *vreg = data;
 
-	if (!vreg->status)
-		*val = 0;
+	if (val == 0)
+		return vreg_disable(vreg);
+	else if (val == 1)
+		return vreg_enable(vreg);
 	else
-		*val = 1;
-
-	return 0;
+		return -EINVAL;
 }
 
-static int vreg_debug_count_set(void *data, u64 val)
-{
-	struct vreg *vreg = data;
-	if (val > UINT_MAX)
-		val = UINT_MAX;
-	vreg->refcnt = val;
-	return 0;
-}
-
-static int vreg_debug_count_get(void *data, u64 *val)
+static int vreg_debug_enabled_get(void *data, u64 *val)
 {
 	struct vreg *vreg = data;
 
@@ -188,33 +229,97 @@
 	return 0;
 }
 
-DEFINE_SIMPLE_ATTRIBUTE(vreg_fops, vreg_debug_get, vreg_debug_set, "%llu\n");
-DEFINE_SIMPLE_ATTRIBUTE(vreg_count_fops, vreg_debug_count_get,
-			vreg_debug_count_set, "%llu\n");
-
-static int __init vreg_debug_init(void)
+static int vreg_debug_voltage_set(void *data, u64 val)
 {
-	struct dentry *dent;
-	int n;
-	char name[32];
-	const char *refcnt_name = "_refcnt";
+	struct vreg *vreg = data;
+	return vreg_set_level(vreg, val);
+}
 
-	dent = debugfs_create_dir("vreg", 0);
-	if (IS_ERR(dent))
-		return 0;
+static int vreg_debug_voltage_get(void *data, u64 *val)
+{
+	struct vreg *vreg = data;
+	*val = vreg->mv;
+	return 0;
+}
 
-	for (n = 0; n < ARRAY_SIZE(vregs); n++) {
-		(void) debugfs_create_file(vregs[n].name, 0644,
-					   dent, vregs + n, &vreg_fops);
+DEFINE_SIMPLE_ATTRIBUTE(vreg_debug_enabled, vreg_debug_enabled_get,
+		vreg_debug_enabled_set, "%llu");
+DEFINE_SIMPLE_ATTRIBUTE(vreg_debug_voltage, vreg_debug_voltage_get,
+		vreg_debug_voltage_set, "%llu");
 
-		strlcpy(name, vregs[n].name, sizeof(name));
-		strlcat(name, refcnt_name, sizeof(name));
-		(void) debugfs_create_file(name, 0644,
-					   dent, vregs + n, &vreg_count_fops);
+static struct dentry *root;
+
+static void vreg_add_debugfs(struct vreg *vreg)
+{
+	struct dentry *dir;
+
+	if (!root)
+		return;
+
+	dir = debugfs_create_dir(vreg->name, root);
+
+	if (IS_ERR_OR_NULL(dir))
+		goto err;
+
+	if (IS_ERR_OR_NULL(debugfs_create_file("enabled", 0644,	dir, vreg,
+					&vreg_debug_enabled)))
+		goto destroy;
+
+	if (IS_ERR_OR_NULL(debugfs_create_file("voltage", 0644, dir, vreg,
+					&vreg_debug_voltage)))
+		goto destroy;
+
+	return;
+
+destroy:
+	debugfs_remove_recursive(dir);
+err:
+	pr_warn("%s: could not create debugfs for vreg %s\n",
+			__func__, vreg->name);
+}
+
+static int __devinit vreg_debug_init(void)
+{
+	root = debugfs_create_dir("vreg", NULL);
+
+	if (IS_ERR_OR_NULL(root)) {
+		pr_debug("%s: error initializing debugfs: %ld - "
+				"disabling debugfs\n",
+				__func__, root ? PTR_ERR(root) : 0);
+		root = NULL;
 	}
 
 	return 0;
 }
-
-device_initcall(vreg_debug_init);
+static void __devexit vreg_debug_exit(void)
+{
+	if (root)
+		debugfs_remove_recursive(root);
+	root = NULL;
+}
+#else
+static inline int __init vreg_debug_init(void) { return 0; }
+static inline void __exit vreg_debug_exit(void) { return 0; }
 #endif
+
+static int __init vreg_init(void)
+{
+	return vreg_debug_init();
+}
+module_init(vreg_init);
+
+static void __exit vreg_exit(void)
+{
+	struct vreg *vreg, *next;
+	vreg_debug_exit();
+
+	mutex_lock(&vreg_lock);
+	list_for_each_entry_safe(vreg, next, &vreg_list, list)
+		vreg_destroy(vreg);
+	mutex_unlock(&vreg_lock);
+}
+module_exit(vreg_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("vreg.c regulator shim");
+MODULE_VERSION("1.0");
diff --git a/arch/arm/mach-msm/wcnss-ssr-8960.c b/arch/arm/mach-msm/wcnss-ssr-8960.c
new file mode 100644
index 0000000..90948ea
--- /dev/null
+++ b/arch/arm/mach-msm/wcnss-ssr-8960.c
@@ -0,0 +1,247 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/workqueue.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/wcnss_wlan.h>
+#include <mach/irqs.h>
+#include <mach/scm.h>
+#include <mach/subsystem_restart.h>
+#include <mach/subsystem_notif.h>
+#include <mach/peripheral-loader.h>
+#include "smd_private.h"
+#include "ramdump.h"
+
+#define MODULE_NAME			"wcnss_8960"
+
+static void riva_smsm_cb_fn(struct work_struct *);
+static DECLARE_WORK(riva_smsm_cb_work, riva_smsm_cb_fn);
+
+static void riva_fatal_fn(struct work_struct *);
+static DECLARE_WORK(riva_fatal_work, riva_fatal_fn);
+
+static struct delayed_work cancel_vote_work;
+static void *riva_ramdump_dev;
+static int riva_crash;
+static int ss_restart_inprogress;
+static int enable_riva_ssr;
+
+static void riva_smsm_cb_fn(struct work_struct *work)
+{
+	if (!enable_riva_ssr)
+		panic(MODULE_NAME ": SMSM reset request received from Riva");
+	else
+		subsystem_restart("riva");
+}
+
+static void smsm_state_cb_hdlr(void *data, uint32_t old_state,
+					uint32_t new_state)
+{
+	if (!(new_state & SMSM_RESET))
+		return;
+
+	riva_crash = true;
+	pr_err("%s: smsm state changed to smsm reset\n", MODULE_NAME);
+
+	if (ss_restart_inprogress) {
+		pr_err("%s: Ignoring smsm reset req, restart in progress\n",
+						MODULE_NAME);
+		return;
+	}
+	ss_restart_inprogress = true;
+	schedule_work(&riva_smsm_cb_work);
+}
+
+static void riva_fatal_fn(struct work_struct *work)
+{
+	if (!enable_riva_ssr)
+		panic(MODULE_NAME ": Watchdog bite received from Riva");
+	else
+		subsystem_restart("riva");
+}
+
+static irqreturn_t riva_wdog_bite_irq_hdlr(int irq, void *dev_id)
+{
+	int ret;
+
+	if (ss_restart_inprogress) {
+		pr_err("%s: Ignoring riva bite irq, restart in progress\n",
+						MODULE_NAME);
+		return IRQ_HANDLED;
+	}
+	ss_restart_inprogress = true;
+	ret = schedule_work(&riva_fatal_work);
+	return IRQ_HANDLED;
+}
+
+/* SMSM reset Riva */
+static void smsm_riva_reset(void)
+{
+	/* per SS reset request bit is not available now,
+	 * all SS host modules are setting this bit
+	 * This is still under discussion*/
+	smsm_change_state(SMSM_APPS_STATE, SMSM_RESET, SMSM_RESET);
+}
+
+static void riva_post_bootup(struct work_struct *work)
+{
+	struct platform_device *pdev = wcnss_get_platform_device();
+	struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
+
+	pr_debug(MODULE_NAME ": Cancel APPS vote for Iris & Riva\n");
+
+	wcnss_wlan_power(&pdev->dev, pwlanconfig,
+		WCNSS_WLAN_SWITCH_OFF);
+}
+
+/* Subsystem handlers */
+static int riva_shutdown(const struct subsys_data *subsys)
+{
+	pil_force_shutdown("wcnss");
+	flush_delayed_work(&cancel_vote_work);
+	disable_irq_nosync(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ);
+
+	return 0;
+}
+
+static int riva_powerup(const struct subsys_data *subsys)
+{
+	struct platform_device *pdev = wcnss_get_platform_device();
+	struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
+	int    ret = -1;
+
+	if (pdev && pwlanconfig)
+		ret = wcnss_wlan_power(&pdev->dev, pwlanconfig,
+					WCNSS_WLAN_SWITCH_ON);
+	/* delay PIL operation, this SSR may be happening soon after kernel
+	 * resumes because of a SMSM RESET by Riva when APPS was suspended.
+	 * PIL fails to locate the images without this delay */
+	if (!ret) {
+		msleep(1000);
+		pil_force_boot("wcnss");
+	}
+	ss_restart_inprogress = false;
+	enable_irq(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ);
+	schedule_delayed_work(&cancel_vote_work, msecs_to_jiffies(5000));
+
+	return ret;
+}
+
+/* RAM segments for Riva SS;
+ * We don't specify the full 5MB allocated for Riva. Only 3MB is specified */
+static struct ramdump_segment riva_segments[] = {{0x8f200000,
+						0x8f500000 - 0x8f200000} };
+
+static int riva_ramdump(int enable, const struct subsys_data *subsys)
+{
+	pr_debug("%s: enable[%d]\n", MODULE_NAME, enable);
+	if (enable)
+		return do_ramdump(riva_ramdump_dev,
+				riva_segments,
+				ARRAY_SIZE(riva_segments));
+	else
+		return 0;
+}
+
+/* Riva crash handler */
+static void riva_crash_shutdown(const struct subsys_data *subsys)
+{
+	pr_err("%s: crash shutdown : %d\n", MODULE_NAME, riva_crash);
+	if (riva_crash != true)
+		smsm_riva_reset();
+}
+
+static struct subsys_data riva_8960 = {
+	.name = "riva",
+	.shutdown = riva_shutdown,
+	.powerup = riva_powerup,
+	.ramdump = riva_ramdump,
+	.crash_shutdown = riva_crash_shutdown
+};
+
+static int enable_riva_ssr_set(const char *val, struct kernel_param *kp)
+{
+	int ret;
+
+	ret = param_set_int(val, kp);
+	if (ret)
+		return ret;
+
+	if (enable_riva_ssr)
+		pr_info(MODULE_NAME ": Subsystem restart activated for riva.\n");
+
+	return 0;
+}
+
+module_param_call(enable_riva_ssr, enable_riva_ssr_set, param_get_int,
+			&enable_riva_ssr, S_IRUGO | S_IWUSR);
+
+static int __init riva_restart_init(void)
+{
+	return ssr_register_subsystem(&riva_8960);
+}
+
+static int __init riva_ssr_module_init(void)
+{
+	int ret;
+
+	ret = smsm_state_cb_register(SMSM_WCNSS_STATE, SMSM_RESET,
+					smsm_state_cb_hdlr, 0);
+	if (ret < 0) {
+		pr_err("%s: Unable to register smsm callback for Riva Reset!"
+				" (%d)\n", MODULE_NAME, ret);
+		goto out;
+	}
+	ret = request_irq(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ,
+			riva_wdog_bite_irq_hdlr, IRQF_TRIGGER_HIGH,
+				"riva_wdog", NULL);
+
+	if (ret < 0) {
+		pr_err("%s: Unable to register for Riva bite interrupt"
+				" (%d)\n", MODULE_NAME, ret);
+		goto out;
+	}
+	ret = riva_restart_init();
+	if (ret < 0) {
+		pr_err("%s: Unable to register with ssr. (%d)\n",
+				MODULE_NAME, ret);
+		goto out;
+	}
+	riva_ramdump_dev = create_ramdump_device("riva");
+	if (!riva_ramdump_dev) {
+		pr_err("%s: Unable to create ramdump device.\n",
+				MODULE_NAME);
+		ret = -ENOMEM;
+		goto out;
+	}
+	INIT_DELAYED_WORK(&cancel_vote_work, riva_post_bootup);
+
+	pr_info("%s: module initialized\n", MODULE_NAME);
+out:
+	return ret;
+}
+
+static void __exit riva_ssr_module_exit(void)
+{
+	free_irq(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ, NULL);
+}
+
+module_init(riva_ssr_module_init);
+module_exit(riva_ssr_module_exit);
+
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/xo-fsm9xxx.c b/arch/arm/mach-msm/xo-fsm9xxx.c
new file mode 100644
index 0000000..cbf3b7a
--- /dev/null
+++ b/arch/arm/mach-msm/xo-fsm9xxx.c
@@ -0,0 +1,289 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/miscdevice.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/regulator/pm8058-xo.h>
+#include <linux/platform_device.h>
+
+#define FSM_XO_IOC_MAGIC	0x93
+#define FSM_XO_IOC_CLKBUF	_IO(FSM_XO_IOC_MAGIC, 1)
+
+#define FSM_XO_DEVICE_READY	0x01
+#define FSM_XO_DEVICE_OFF	0x00
+
+/* enum for TCXO clock output buffer definition */
+enum clk_buffer_type {
+	XO_BUFFER_A0 = 0,
+	XO_BUFFER_A1 = 1,
+	XO_BUFFER_LAST
+};
+
+/*
+ * This user request structure is used to exchange the pmic device data
+ * requested to user space applications.  The pointer to this structure is
+ * passed to the the ioctl function.
+*/
+struct fsm_xo_req {
+	enum clk_buffer_type   clkBuffer;
+	u8                     clkBufEnable;
+};
+
+struct fsm_xo_priv_t {
+	struct mutex lock;
+	struct regulator *a0;
+	struct regulator *a1;
+	u8 a0_enabled;
+	u8 a1_enabled;
+};
+
+static struct fsm_xo_priv_t *fsm_xo_priv;
+
+static int fsm_xo_open(struct inode *inode, struct file *filp)
+{
+	if (fsm_xo_priv == NULL)
+		return -ENODEV;
+
+	filp->private_data = fsm_xo_priv;
+
+	return 0;
+}
+
+static int fsm_xo_release(struct inode *inode, struct file *filp)
+{
+	filp->private_data = NULL;
+
+	return 0;
+}
+
+static inline int fsm_xo_enable_a0(void)
+{
+	int err = 0;
+
+	if (!fsm_xo_priv->a0_enabled) {
+		err = regulator_enable(fsm_xo_priv->a0);
+		if (err != 0)
+			pr_err("Error = %d enabling xo buffer a0\n", err);
+		else
+			fsm_xo_priv->a0_enabled = 1;
+	}
+	return err;
+}
+
+static inline int fsm_xo_disable_a0(void)
+{
+	int err = 0;
+
+	if (fsm_xo_priv->a0_enabled) {
+		err = regulator_disable(fsm_xo_priv->a0);
+		if (err != 0)
+			pr_err("Error = %d disabling xo buffer a0\n", err);
+		else
+			fsm_xo_priv->a0_enabled = 0;
+	}
+	return err;
+}
+
+static inline int fsm_xo_enable_a1(void)
+{
+	int err = 0;
+
+	if (!fsm_xo_priv->a1_enabled) {
+		err = regulator_enable(fsm_xo_priv->a1);
+		if (err != 0)
+			pr_err("Error = %d enabling xo buffer a1\n", err);
+		else
+			fsm_xo_priv->a1_enabled = 1;
+	}
+	return err;
+}
+
+static inline int fsm_xo_disable_a1(void)
+{
+	int err = 0;
+
+	if (fsm_xo_priv->a1_enabled) {
+		err = regulator_disable(fsm_xo_priv->a1);
+		if (err != 0)
+			pr_err("Error = %d disabling xo buffer a1\n", err);
+		else
+			fsm_xo_priv->a1_enabled = 0;
+	}
+	return err;
+}
+static long
+fsm_xo_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	int err = 0;
+	struct fsm_xo_req req;
+
+	/* Verify user arguments. */
+	if (_IOC_TYPE(cmd) != FSM_XO_IOC_MAGIC)
+		return -ENOTTY;
+
+	/* Lock for access */
+	if (mutex_lock_interruptible(&fsm_xo_priv->lock))
+		return -ERESTARTSYS;
+
+	switch (cmd) {
+	case FSM_XO_IOC_CLKBUF:
+		if (arg == 0) {
+			pr_err("user space arg not supplied\n");
+			err = -EFAULT;
+			break;
+		}
+
+		if (copy_from_user(&req, (void __user *)arg,
+			sizeof(req))) {
+			pr_err("Error copying from user space\n");
+			err = -EFAULT;
+			break;
+		}
+
+		if (req.clkBuffer == XO_BUFFER_A0) {
+			if (req.clkBufEnable)
+				err = fsm_xo_enable_a0();
+			else
+				err = fsm_xo_disable_a0();
+		} else if (req.clkBuffer == XO_BUFFER_A1) {
+			if (req.clkBufEnable)
+				err = fsm_xo_enable_a1();
+			else
+				err = fsm_xo_disable_a1();
+		} else {
+			pr_err("Invalid ioctl argument.\n");
+			err = -ENOTTY;
+		}
+		break;
+	default:
+		pr_err("Invalid ioctl command.\n");
+		err = -ENOTTY;
+		break;
+	}
+
+	mutex_unlock(&fsm_xo_priv->lock);
+	return err;
+}
+
+static const struct file_operations fsm_xo_fops = {
+	.owner = THIS_MODULE,
+	.unlocked_ioctl = fsm_xo_ioctl,
+	.open = fsm_xo_open,
+	.release = fsm_xo_release
+};
+
+static struct miscdevice fsm_xo_dev = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "fsm_xo",
+	.fops = &fsm_xo_fops
+};
+
+static int fsm_xo_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+
+	/* Initialize */
+	fsm_xo_priv = kzalloc(sizeof(struct fsm_xo_priv_t), GFP_KERNEL);
+
+	if (fsm_xo_priv == NULL) {
+		pr_alert("Not enough memory to initialize device\n");
+		return -ENOMEM;
+	}
+
+	fsm_xo_priv->a0 = regulator_get(&pdev->dev, "a0_clk_buffer");
+	if (IS_ERR(fsm_xo_priv->a0)) {
+		pr_err("Error getting a0_clk_buffer\n");
+		ret = PTR_ERR(fsm_xo_priv->a0);
+		fsm_xo_priv->a0 = NULL;
+		goto err;
+	}
+	fsm_xo_priv->a1 = regulator_get(&pdev->dev, "a1_clk_buffer");
+	if (IS_ERR(fsm_xo_priv->a1)) {
+		pr_err("Error getting a1_clk_buffer\n");
+		ret = PTR_ERR(fsm_xo_priv->a1);
+		fsm_xo_priv->a1 = NULL;
+		goto err;
+	}
+
+	fsm_xo_priv->a0_enabled = 0;
+	fsm_xo_priv->a1_enabled = 0;
+
+	/* Enable the clock buffers. AMSS depends on this on the FSM. */
+	fsm_xo_enable_a0();
+	fsm_xo_enable_a1();
+
+	mutex_init(&fsm_xo_priv->lock);
+
+	ret = misc_register(&fsm_xo_dev);
+	if (ret < 0)
+		goto err;
+
+	return 0;
+
+err:
+	if (fsm_xo_priv->a0)
+		regulator_put(fsm_xo_priv->a0);
+	if (fsm_xo_priv->a1)
+		regulator_put(fsm_xo_priv->a1);
+
+	kfree(fsm_xo_priv);
+	fsm_xo_priv = NULL;
+
+	return ret;
+}
+
+static int __devexit fsm_xo_remove(struct platform_device *pdev)
+{
+	if (fsm_xo_priv && fsm_xo_priv->a0)
+		regulator_put(fsm_xo_priv->a0);
+	if (fsm_xo_priv && fsm_xo_priv->a1)
+		regulator_put(fsm_xo_priv->a1);
+
+	kfree(fsm_xo_priv);
+	fsm_xo_priv = NULL;
+
+	misc_deregister(&fsm_xo_dev);
+	return 0;
+}
+
+static struct platform_driver fsm_xo_driver = {
+	.probe          = fsm_xo_probe,
+	.remove         = fsm_xo_remove,
+	.driver         = {
+		.name = "fsm_xo_driver",
+	}
+};
+
+static int __init fsm_xo_init(void)
+{
+	return platform_driver_register(&fsm_xo_driver);
+}
+
+static void __exit fsm_xo_exit(void)
+{
+	platform_driver_unregister(&fsm_xo_driver);
+}
+
+module_init(fsm_xo_init);
+module_exit(fsm_xo_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Provide userspace access to XO buffers in PMIC8058.");
+MODULE_VERSION("1.00");
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index e433603..25153d5 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -297,6 +297,39 @@
 
 static inline void omap_init_sti(void) {}
 
+#if defined CONFIG_ARCH_OMAP4
+
+static struct platform_device codec_dmic0 = {
+	.name	= "dmic-codec",
+	.id	= 0,
+};
+
+static struct platform_device codec_dmic1 = {
+	.name	= "dmic-codec",
+	.id	= 1,
+};
+
+static struct platform_device codec_dmic2 = {
+	.name	= "dmic-codec",
+	.id	= 2,
+};
+
+static struct platform_device omap_abe_dai = {
+	.name	= "omap-abe-dai",
+	.id	= -1,
+};
+
+static inline void omap_init_abe(void)
+{
+	platform_device_register(&codec_dmic0);
+	platform_device_register(&codec_dmic1);
+	platform_device_register(&codec_dmic2);
+	platform_device_register(&omap_abe_dai);
+}
+#else
+static inline void omap_init_abe(void) {}
+#endif
+
 #if defined(CONFIG_SND_SOC) || defined(CONFIG_SND_SOC_MODULE)
 
 static struct platform_device omap_pcm = {
@@ -700,6 +733,7 @@
 	 * please keep these calls, and their implementations above,
 	 * in alphabetical order so they're easier to sort through.
 	 */
+	omap_init_abe();
 	omap_init_audio();
 	omap_init_mcpdm();
 	omap_init_dmic();
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
index 6abc757..12e3e14 100644
--- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -763,6 +763,27 @@
 
 static struct omap_hwmod_addr_space omap44xx_aess_addrs[] = {
 	{
+		.name		= "dmem",
+		.pa_start	= 0x40180000,
+		.pa_end		= 0x4018ffff
+	},
+	{
+		.name		= "cmem",
+		.pa_start	= 0x401a0000,
+		.pa_end		= 0x401a1fff
+	},
+	{
+		.name		= "smem",
+		.pa_start	= 0x401c0000,
+		.pa_end		= 0x401c5fff
+	},
+	{
+		.name		= "pmem",
+		.pa_start	= 0x401e0000,
+		.pa_end		= 0x401e1fff
+	},
+	{
+		.name		= "mpu",
 		.pa_start	= 0x401f1000,
 		.pa_end		= 0x401f13ff,
 		.flags		= ADDR_TYPE_RT
@@ -781,6 +802,27 @@
 
 static struct omap_hwmod_addr_space omap44xx_aess_dma_addrs[] = {
 	{
+		.name		= "dmem_dma",
+		.pa_start	= 0x49080000,
+		.pa_end		= 0x4908ffff
+	},
+	{
+		.name		= "cmem_dma",
+		.pa_start	= 0x490a0000,
+		.pa_end		= 0x490a1fff
+	},
+	{
+		.name		= "smem_dma",
+		.pa_start	= 0x490c0000,
+		.pa_end		= 0x490c5fff
+	},
+	{
+		.name		= "pmem_dma",
+		.pa_start	= 0x490e0000,
+		.pa_end		= 0x490e1fff
+	},
+	{
+		.name		= "dma",
 		.pa_start	= 0x490f1000,
 		.pa_end		= 0x490f13ff,
 		.flags		= ADDR_TYPE_RT
@@ -5555,7 +5597,7 @@
 	&omap44xx_mpu_private_hwmod,
 
 	/* aess class */
-/*	&omap44xx_aess_hwmod, */
+	&omap44xx_aess_hwmod,
 
 	/* bandgap class */
 	&omap44xx_bandgap_hwmod,
diff --git a/arch/arm/mach-s5pv210/mach-goni.c b/arch/arm/mach-s5pv210/mach-goni.c
index 3239566..6f02117 100644
--- a/arch/arm/mach-s5pv210/mach-goni.c
+++ b/arch/arm/mach-s5pv210/mach-goni.c
@@ -233,6 +233,11 @@
 	gpio_request_one(gpio, GPIOF_OUT_INIT_HIGH, "FM_RST");
 }
 
+static u8 read_chg(void)
+{
+	return gpio_get_value(S5PV210_GPJ0(5));
+}
+
 /* TSP */
 static struct mxt_platform_data qt602240_platform_data = {
 	.x_line		= 17,
@@ -244,6 +249,7 @@
 	.voltage	= 2800000,              /* 2.8V */
 	.orient		= MXT_DIAGONAL,
 	.irqflags	= IRQF_TRIGGER_FALLING,
+	.read_chg	= &read_chg,
 };
 
 static struct s3c2410_platform_i2c i2c2_data __initdata = {
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 7c8a7d8..cb245ee 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -588,6 +588,9 @@
 config CPU_TLB_V7
 	bool
 
+config EMULATE_DOMAIN_MANAGER_V7
+	bool
+
 config VERIFY_PERMISSION_FAULT
 	bool
 endif
@@ -756,6 +759,19 @@
 	  If your SoC is configured to have a different size, define the value
 	  here with proper conditions.
 
+config CPU_CACHE_ERR_REPORT
+	bool "Report errors in the L1 and L2 caches"
+	depends on ARCH_MSM_SCORPION
+	default n
+	help
+	  The Scorpion processor supports reporting L2 errors, L1 icache parity
+	  errors, and L1 dcache parity errors as imprecise external aborts. If
+	  this option is not enabled these errors will go unreported and data
+	  corruption will occur.
+
+	  Say Y here to have errors in the L1 and L2 caches reported as
+	  imprecise data aborts.
+
 config CPU_DCACHE_WRITETHROUGH
 	bool "Force write through D-cache"
 	depends on (CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_FA526) && !CPU_DCACHE_DISABLE
@@ -918,3 +934,30 @@
 	help
 	  This option allows the use of custom mandatory barriers
 	  included via the mach/barriers.h file.
+
+config VCM_MM
+	bool
+
+config VCM
+	bool "Virtual Contiguous Memory (VCM) Layer"
+	depends on MMU
+	select GENERIC_ALLOCATOR
+	select VCM_MM
+	default n
+	help
+	  Virtual Contiguous Memory layer. This is the layer that is intended to
+	  replace PMEM.
+
+	  If you don't know what this is, say N here.
+
+config STRICT_MEMORY_RWX
+	bool "restrict kernel memory permissions as much as possible"
+	default n
+	help
+	  If this is set, kernel text will be made RX, kernel data and stack
+	  RW, rodata R (otherwise all of the kernel 1-to-1 mapping is
+	  made RWX).
+	  The tradeoff is that several sections are padded to
+	  1M boundaries (because their permissions are different and
+	  splitting the 1M pages into 4K ones causes TLB performance
+	  problems), wasting memory.
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index 37da2cc..1c415af 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -93,6 +93,7 @@
 obj-$(CONFIG_CPU_V6)		+= proc-v6.o
 obj-$(CONFIG_CPU_V6K)		+= proc-v6.o
 obj-$(CONFIG_CPU_V7)		+= proc-v7.o
+obj-$(CONFIG_EMULATE_DOMAIN_MANAGER_V7) += emulate_domain_manager-v7.o
 
 AFLAGS_proc-v6.o	:=-Wa,-march=armv6
 AFLAGS_proc-v7.o	:=-Wa,-march=armv7-a
@@ -101,3 +102,5 @@
 obj-$(CONFIG_CACHE_L2X0)	+= cache-l2x0.o
 obj-$(CONFIG_CACHE_XSC3L2)	+= cache-xsc3l2.o
 obj-$(CONFIG_CACHE_TAUROS2)	+= cache-tauros2.o
+obj-$(CONFIG_VCM)		+= vcm.o vcm_alloc.o
+obj-$(CONFIG_VCM_MM)		+= vcm_mm.o
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index eaa6847..cb9fc76 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -2,6 +2,7 @@
  * arch/arm/mm/cache-l2x0.c - L210/L220 cache controller support
  *
  * Copyright (C) 2007 ARM Limited
+ * Copyright (c) 2009, 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 as
@@ -36,6 +37,7 @@
 static unsigned int l2x0_sets;
 static unsigned int l2x0_ways;
 static unsigned long sync_reg_offset = L2X0_CACHE_SYNC;
+static void pl310_save(void);
 
 static inline bool is_pl310_rev(int rev)
 {
@@ -131,7 +133,7 @@
 }
 #endif
 
-static void l2x0_cache_sync(void)
+void l2x0_cache_sync(void)
 {
 	unsigned long flags;
 
@@ -418,9 +420,9 @@
 		writel_relaxed(1, l2x0_base + L2X0_CTRL);
 	}
 
-	outer_cache.inv_range = l2x0_inv_range;
-	outer_cache.clean_range = l2x0_clean_range;
-	outer_cache.flush_range = l2x0_flush_range;
+		outer_cache.inv_range = l2x0_inv_range;
+		outer_cache.clean_range = l2x0_clean_range;
+		outer_cache.flush_range = l2x0_flush_range;
 	outer_cache.sync = l2x0_cache_sync;
 	outer_cache.flush_all = l2x0_flush_all;
 	outer_cache.inv_all = l2x0_inv_all;
@@ -429,6 +431,9 @@
 	printk(KERN_INFO "%s cache controller enabled\n", type);
 	printk(KERN_INFO "l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x, Cache size: %d B\n",
 			l2x0_ways, l2x0_cache_id, aux, l2x0_size);
+
+	/* Save the L2X0 contents, as they are not modified else where */
+	pl310_save();
 }
 
 #ifdef CONFIG_OF
@@ -499,8 +504,9 @@
 			       l2x0_base + L2X0_ADDR_FILTER_START);
 	}
 }
+#endif
 
-static void __init pl310_save(void)
+static void pl310_save(void)
 {
 	u32 l2x0_revision = readl_relaxed(l2x0_base + L2X0_CACHE_ID) &
 		L2X0_CACHE_ID_RTL_MASK;
@@ -574,6 +580,7 @@
 	l2x0_resume();
 }
 
+#ifdef CONFIG_OF
 static const struct l2x0_of_data pl310_data = {
 	pl310_of_setup,
 	pl310_save,
@@ -629,3 +636,15 @@
 	return 0;
 }
 #endif
+
+void l2cc_suspend(void)
+{
+	l2x0_disable();
+	dmb();
+}
+
+void l2cc_resume(void)
+{
+	pl310_resume();
+	dmb();
+}
diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c
index ee9bb36..847ea19 100644
--- a/arch/arm/mm/context.c
+++ b/arch/arm/mm/context.c
@@ -14,8 +14,11 @@
 #include <linux/percpu.h>
 
 #include <asm/mmu_context.h>
+#include <asm/thread_notify.h>
 #include <asm/tlbflush.h>
 
+#include <mach/msm_rtb.h>
+
 static DEFINE_RAW_SPINLOCK(cpu_asid_lock);
 unsigned int cpu_last_asid = ASID_FIRST_VERSION;
 #ifdef CONFIG_SMP
@@ -37,6 +40,67 @@
 	asm("	mcr	p15, 0, %0, c13, c0, 1\n" : : "r" (asid))
 #endif
 
+static void write_contextidr(u32 contextidr)
+{
+	uncached_logk(LOGK_CTXID, (void *)contextidr);
+	asm("mcr	p15, 0, %0, c13, c0, 1" : : "r" (contextidr));
+	isb();
+}
+
+#ifdef CONFIG_PID_IN_CONTEXTIDR
+static u32 read_contextidr(void)
+{
+	u32 contextidr;
+	asm("mrc	p15, 0, %0, c13, c0, 1" : "=r" (contextidr));
+	return contextidr;
+}
+
+static int contextidr_notifier(struct notifier_block *unused, unsigned long cmd,
+			       void *t)
+{
+	unsigned long flags;
+	u32 contextidr;
+	pid_t pid;
+	struct thread_info *thread = t;
+
+	if (cmd != THREAD_NOTIFY_SWITCH)
+		return NOTIFY_DONE;
+
+	pid = task_pid_nr(thread->task);
+	local_irq_save(flags);
+	contextidr = read_contextidr();
+	contextidr &= ~ASID_MASK;
+	contextidr |= pid << ASID_BITS;
+	write_contextidr(contextidr);
+	local_irq_restore(flags);
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block contextidr_notifier_block = {
+	.notifier_call = contextidr_notifier,
+};
+
+static int __init contextidr_notifier_init(void)
+{
+	return thread_register_notifier(&contextidr_notifier_block);
+}
+arch_initcall(contextidr_notifier_init);
+
+static void set_asid(unsigned int asid)
+{
+	u32 contextidr = read_contextidr();
+	contextidr &= ASID_MASK;
+	contextidr |= asid & ~ASID_MASK;
+	write_contextidr(contextidr);
+}
+#else
+static void set_asid(unsigned int asid)
+{
+	write_contextidr(asid);
+}
+#endif
+
 /*
  * We fork()ed a process, and we need a new context for the child
  * to run in.  We reserve version 0 for initial tasks so we will
@@ -52,8 +116,7 @@
 static void flush_context(void)
 {
 	/* set the reserved ASID before flushing the TLB */
-	cpu_set_asid(0);
-	isb();
+	set_asid(0);
 	local_flush_tlb_all();
 	if (icache_is_vivt_asid_tagged()) {
 		__flush_icache_all();
@@ -114,8 +177,7 @@
 	set_mm_context(mm, asid);
 
 	/* set the new ASID */
-	cpu_set_asid(mm->context.id);
-	isb();
+	set_asid(mm->context.id);
 }
 
 #else
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index db23ae4..702408c 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -128,7 +128,7 @@
  */
 static pte_t **consistent_pte;
 
-#define DEFAULT_CONSISTENT_DMA_SIZE SZ_2M
+#define DEFAULT_CONSISTENT_DMA_SIZE (7*SZ_2M)
 
 unsigned long consistent_base = CONSISTENT_END - DEFAULT_CONSISTENT_DMA_SIZE;
 
@@ -467,18 +467,22 @@
 void ___dma_single_cpu_to_dev(const void *kaddr, size_t size,
 	enum dma_data_direction dir)
 {
+#ifdef CONFIG_OUTER_CACHE
 	unsigned long paddr;
 
 	BUG_ON(!virt_addr_valid(kaddr) || !virt_addr_valid(kaddr + size - 1));
+#endif
 
 	dmac_map_area(kaddr, size, dir);
 
+#ifdef CONFIG_OUTER_CACHE
 	paddr = __pa(kaddr);
 	if (dir == DMA_FROM_DEVICE) {
 		outer_inv_range(paddr, paddr + size);
 	} else {
 		outer_clean_range(paddr, paddr + size);
 	}
+#endif
 	/* FIXME: non-speculating: flush on bidirectional mappings? */
 }
 EXPORT_SYMBOL(___dma_single_cpu_to_dev);
@@ -486,6 +490,7 @@
 void ___dma_single_dev_to_cpu(const void *kaddr, size_t size,
 	enum dma_data_direction dir)
 {
+#ifdef CONFIG_OUTER_CACHE
 	BUG_ON(!virt_addr_valid(kaddr) || !virt_addr_valid(kaddr + size - 1));
 
 	/* FIXME: non-speculating: not required */
@@ -494,7 +499,7 @@
 		unsigned long paddr = __pa(kaddr);
 		outer_inv_range(paddr, paddr + size);
 	}
-
+#endif
 	dmac_unmap_area(kaddr, size, dir);
 }
 EXPORT_SYMBOL(___dma_single_dev_to_cpu);
diff --git a/arch/arm/mm/emulate_domain_manager-v7.c b/arch/arm/mm/emulate_domain_manager-v7.c
new file mode 100644
index 0000000..3797e21
--- /dev/null
+++ b/arch/arm/mm/emulate_domain_manager-v7.c
@@ -0,0 +1,345 @@
+/*
+ * Basic implementation of a SW emulation of the domain manager feature in
+ * ARM architecture.  Assumes single processor ARMv7 chipset.
+ *
+ * Requires hooks to be alerted to any runtime changes of dacr or MMU context.
+ *
+ * Copyright (c) 2009, 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/sched.h>
+#include <asm/domain.h>
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+#include <linux/module.h>
+
+#define DOMAIN_MANAGER_BITS (0xAAAAAAAA)
+
+#define DFSR_DOMAIN(dfsr) ((dfsr >> 4) & (16-1))
+
+#define FSR_PERMISSION_FAULT(fsr) ((fsr & 0x40D) == 0x00D)
+#define FSR_PERMISSION_SECT(fsr) ((fsr & 0x40F) == 0x00D)
+
+/* ARMv7 MMU HW Macros.  Not conveniently defined elsewhere */
+#define MMU_TTB_ADDRESS(x)   ((u32 *)(((u32)(x)) & ~((1 << 14) - 1)))
+#define MMU_PMD_INDEX(addr) (((u32)addr) >> SECTION_SHIFT)
+#define MMU_TABLE_ADDRESS(x) ((u32 *)((x) & ~((1 << 10) - 1)))
+#define MMU_TABLE_INDEX(x) ((((u32)x) >> 12) & (256 - 1))
+
+/* Convenience Macros */
+#define PMD_IS_VALID(x) (PMD_IS_TABLE(x) || PMD_IS_SECTION(x))
+#define PMD_IS_TABLE(x) ((x & PMD_TYPE_MASK) == PMD_TYPE_TABLE)
+#define PMD_IS_SECTION(x) ((x & PMD_TYPE_MASK) == PMD_TYPE_SECT)
+#define PMD_IS_SUPERSECTION(x) \
+	(PMD_IS_SECTION(x) && ((x & PMD_SECT_SUPER) == PMD_SECT_SUPER))
+
+#define PMD_GET_DOMAIN(x)					\
+	(PMD_IS_TABLE(x) ||					\
+	(PMD_IS_SECTION(x) && !PMD_IS_SUPERSECTION(x)) ?	\
+		 0 : (x >> 5) & (16-1))
+
+#define PTE_IS_LARGE(x) ((x & PTE_TYPE_MASK) == PTE_TYPE_LARGE)
+
+
+/* Only DOMAIN_MMU_ENTRIES will be granted access simultaneously */
+#define DOMAIN_MMU_ENTRIES (8)
+
+#define LRU_INC(lru) ((lru + 1) >= DOMAIN_MMU_ENTRIES ? 0 : lru + 1)
+
+
+static DEFINE_SPINLOCK(edm_lock);
+
+static u32 edm_manager_bits;
+
+struct domain_entry_save {
+	u32 *mmu_entry;
+	u32 *addr;
+	u32 value;
+	u16 sect;
+	u16 size;
+};
+
+static struct domain_entry_save edm_save[DOMAIN_MMU_ENTRIES];
+
+static u32 edm_lru;
+
+
+/*
+ *  Return virtual address of pmd (level 1) entry for addr
+ *
+ *  This routine walks the ARMv7 page tables in HW.
+ */
+static inline u32 *__get_pmd_v7(u32 *addr)
+{
+	u32 *ttb;
+
+	__asm__ __volatile__(
+		"mrc	p15, 0, %0, c2, c0, 0	@ ttbr0\n\t"
+		: "=r" (ttb)
+		:
+	);
+
+	return __va(MMU_TTB_ADDRESS(ttb) + MMU_PMD_INDEX(addr));
+}
+
+/*
+ *  Return virtual address of pte (level 2) entry for addr
+ *
+ *  This routine walks the ARMv7 page tables in HW.
+ */
+static inline u32 *__get_pte_v7(u32 *addr)
+{
+	u32 *pmd = __get_pmd_v7(addr);
+	u32 *table_pa = pmd && PMD_IS_TABLE(*pmd) ?
+		MMU_TABLE_ADDRESS(*pmd) : 0;
+	u32 *entry = table_pa ? __va(table_pa[MMU_TABLE_INDEX(addr)]) : 0;
+
+	return entry;
+}
+
+/*
+ *  Invalidate the TLB for a given address for the current context
+ *
+ *  After manipulating access permissions, TLB invalidation changes are
+ *  observed
+ */
+static inline void __tlb_invalidate(u32 *addr)
+{
+	__asm__ __volatile__(
+		"mrc	p15, 0, %%r2, c13, c0, 1	@ contextidr\n\t"
+		"and %%r2, %%r2, #0xff			@ asid\n\t"
+		"mov %%r3, %0, lsr #12			@ mva[31:12]\n\t"
+		"orr %%r2, %%r2, %%r3, lsl #12		@ tlb mva and asid\n\t"
+		"mcr	p15, 0, %%r2, c8, c7, 1		@ utlbimva\n\t"
+		"isb"
+		:
+		: "r" (addr)
+		: "r2", "r3"
+	);
+}
+
+/*
+ *  Set HW MMU entry and do required synchronization operations.
+ */
+static inline void __set_entry(u32 *entry, u32 *addr, u32 value, int size)
+{
+	int i;
+
+	if (!entry)
+		return;
+
+	entry = (u32 *)((u32) entry & ~(size * sizeof(u32) - 1));
+
+	for (i = 0; i < size; i++)
+		entry[i] = value;
+
+	__asm__ __volatile__(
+		"mcr	p15, 0, %0, c7, c10, 1		@ flush entry\n\t"
+		"dsb\n\t"
+		"isb\n\t"
+		:
+		: "r" (entry)
+	);
+	__tlb_invalidate(addr);
+}
+
+/*
+ *  Return the number of duplicate entries associated with entry value.
+ *  Supersections and Large page table entries are replicated 16x.
+ */
+static inline int __entry_size(int sect, int value)
+{
+	u32 size;
+
+	if (sect)
+		size = PMD_IS_SUPERSECTION(value) ? 16 : 1;
+	else
+		size = PTE_IS_LARGE(value) ? 16 : 1;
+
+	return size;
+}
+
+/*
+ *  Change entry permissions to emulate domain manager access
+ */
+static inline int __manager_perm(int sect, int value)
+{
+	u32 edm_value;
+
+	if (sect) {
+		edm_value = (value & ~(PMD_SECT_APX | PMD_SECT_XN)) |
+		(PMD_SECT_AP_READ | PMD_SECT_AP_WRITE);
+	} else {
+		edm_value = (value & ~(PTE_EXT_APX | PTE_EXT_XN)) |
+			(PTE_EXT_AP1 | PTE_EXT_AP0);
+	}
+	return edm_value;
+}
+
+/*
+ *  Restore original HW MMU entry.  Cancels domain manager access
+ */
+static inline void __restore_entry(int index)
+{
+	struct domain_entry_save *entry = &edm_save[index];
+	u32 edm_value;
+
+	if (!entry->mmu_entry)
+		return;
+
+	edm_value = __manager_perm(entry->sect, entry->value);
+
+	if (*entry->mmu_entry == edm_value)
+		__set_entry(entry->mmu_entry, entry->addr,
+			entry->value, entry->size);
+
+	entry->mmu_entry = 0;
+}
+
+/*
+ *  Modify HW MMU entry to grant domain manager access for a given MMU entry.
+ *  This adds full read, write, and exec access permissions.
+ */
+static inline void __set_manager(int sect, u32 *addr)
+{
+	u32 *entry = sect ? __get_pmd_v7(addr) : __get_pte_v7(addr);
+	u32 value;
+	u32 edm_value;
+	u16 size;
+
+	if (!entry)
+		return;
+
+	value = *entry;
+
+	size = __entry_size(sect, value);
+	edm_value = __manager_perm(sect, value);
+
+	__set_entry(entry, addr, edm_value, size);
+
+	__restore_entry(edm_lru);
+
+	edm_save[edm_lru].mmu_entry = entry;
+	edm_save[edm_lru].addr = addr;
+	edm_save[edm_lru].value = value;
+	edm_save[edm_lru].sect = sect;
+	edm_save[edm_lru].size = size;
+
+	edm_lru = LRU_INC(edm_lru);
+}
+
+/*
+ *  Restore original HW MMU entries.
+ *
+ *  entry - MVA for HW MMU entry
+ */
+static inline void __restore(void)
+{
+	if (unlikely(edm_manager_bits)) {
+		u32 i;
+
+		for (i = 0; i < DOMAIN_MMU_ENTRIES; i++)
+			__restore_entry(i);
+	}
+}
+
+/*
+ * Common abort handler code
+ *
+ * If domain manager was actually set, permission fault would not happen.
+ * Open access permissions to emulate.  Save original settings to restore
+ * later. Return 1 to pretend fault did not happen.
+ */
+static int __emulate_domain_manager_abort(u32 fsr, u32 far, int dabort)
+{
+	if (unlikely(FSR_PERMISSION_FAULT(fsr) && edm_manager_bits)) {
+		int domain = dabort ? DFSR_DOMAIN(fsr) : PMD_GET_DOMAIN(far);
+		if (edm_manager_bits & domain_val(domain, DOMAIN_MANAGER)) {
+			unsigned long flags;
+
+			spin_lock_irqsave(&edm_lock, flags);
+
+			__set_manager(FSR_PERMISSION_SECT(fsr), (u32 *) far);
+
+			spin_unlock_irqrestore(&edm_lock, flags);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Change domain setting.
+ *
+ * Lock and restore original contents.  Extract and save manager bits.  Set
+ * DACR, excluding manager bits.
+ */
+void emulate_domain_manager_set(u32 domain)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&edm_lock, flags);
+
+	if (edm_manager_bits != (domain & DOMAIN_MANAGER_BITS)) {
+		__restore();
+		edm_manager_bits = domain & DOMAIN_MANAGER_BITS;
+	}
+
+	__asm__ __volatile__(
+		"mcr	p15, 0, %0, c3, c0, 0	@ set domain\n\t"
+		"isb"
+		:
+		: "r" (domain & ~DOMAIN_MANAGER_BITS)
+	);
+
+	spin_unlock_irqrestore(&edm_lock, flags);
+}
+EXPORT_SYMBOL_GPL(emulate_domain_manager_set);
+
+/*
+ * Switch thread context.  Restore original contents.
+ */
+void emulate_domain_manager_switch_mm(unsigned long pgd_phys,
+	struct mm_struct *mm,
+	void (*switch_mm)(unsigned long pgd_phys, struct mm_struct *))
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&edm_lock, flags);
+
+	__restore();
+
+	/* Call underlying kernel handler */
+	switch_mm(pgd_phys, mm);
+
+	spin_unlock_irqrestore(&edm_lock, flags);
+}
+EXPORT_SYMBOL_GPL(emulate_domain_manager_switch_mm);
+
+/*
+ * Kernel data_abort hook
+ */
+int emulate_domain_manager_data_abort(u32 dfsr, u32 dfar)
+{
+	return __emulate_domain_manager_abort(dfsr, dfar, 1);
+}
+EXPORT_SYMBOL_GPL(emulate_domain_manager_data_abort);
+
+/*
+ * Kernel prefetch_abort hook
+ */
+int emulate_domain_manager_prefetch_abort(u32 ifsr, u32 ifar)
+{
+	return __emulate_domain_manager_abort(ifsr, ifar, 0);
+}
+EXPORT_SYMBOL_GPL(emulate_domain_manager_prefetch_abort);
+
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 5bb4835..ed03b33 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -25,6 +25,15 @@
 #include <asm/system_misc.h>
 #include <asm/system_info.h>
 #include <asm/tlbflush.h>
+#include <asm/cputype.h>
+#if defined(CONFIG_ARCH_MSM_SCORPION) && !defined(CONFIG_MSM_SMP)
+#include <asm/io.h>
+#include <mach/msm_iomap.h>
+#endif
+
+#ifdef CONFIG_EMULATE_DOMAIN_MANAGER_V7
+#include <asm/domain.h>
+#endif /* CONFIG_EMULATE_DOMAIN_MANAGER_V7 */
 
 #include "fault.h"
 
@@ -509,6 +518,49 @@
 	return 1;
 }
 
+#if defined(CONFIG_ARCH_MSM_SCORPION) && !defined(CONFIG_MSM_SMP)
+#define __str(x) #x
+#define MRC(x, v1, v2, v4, v5, v6) do {					\
+	unsigned int __##x;						\
+	asm("mrc " __str(v1) ", " __str(v2) ", %0, " __str(v4) ", "	\
+		__str(v5) ", " __str(v6) "\n" \
+		: "=r" (__##x));					\
+	pr_info("%s: %s = 0x%.8x\n", __func__, #x, __##x);		\
+} while(0)
+
+#define MSM_TCSR_SPARE2 (MSM_TCSR_BASE + 0x60)
+
+#endif
+
+int
+do_imprecise_ext(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
+{
+#if defined(CONFIG_ARCH_MSM_SCORPION) && !defined(CONFIG_MSM_SMP)
+	MRC(ADFSR,    p15, 0,  c5, c1, 0);
+	MRC(DFSR,     p15, 0,  c5, c0, 0);
+	MRC(ACTLR,    p15, 0,  c1, c0, 1);
+	MRC(EFSR,     p15, 7, c15, c0, 1);
+	MRC(L2SR,     p15, 3, c15, c1, 0);
+	MRC(L2CR0,    p15, 3, c15, c0, 1);
+	MRC(L2CPUESR, p15, 3, c15, c1, 1);
+	MRC(L2CPUCR,  p15, 3, c15, c0, 2);
+	MRC(SPESR,    p15, 1,  c9, c7, 0);
+	MRC(SPCR,     p15, 0,  c9, c7, 0);
+	MRC(DMACHSR,  p15, 1, c11, c0, 0);
+	MRC(DMACHESR, p15, 1, c11, c0, 1);
+	MRC(DMACHCR,  p15, 0, c11, c0, 2);
+
+	/* clear out EFSR and ADFSR after fault */
+	asm volatile ("mcr p15, 7, %0, c15, c0, 1\n\t"
+		      "mcr p15, 0, %0, c5, c1, 0"
+		      : : "r" (0));
+#endif
+#if defined(CONFIG_ARCH_MSM_SCORPION) && !defined(CONFIG_MSM_SMP)
+	pr_info("%s: TCSR_SPARE2 = 0x%.8x\n", __func__, readl(MSM_TCSR_SPARE2));
+#endif
+	return 1;
+}
+
 struct fsr_info {
 	int	(*fn)(unsigned long addr, unsigned int fsr, struct pt_regs *regs);
 	int	sig;
@@ -536,6 +588,75 @@
 	fsr_info[nr].name = name;
 }
 
+#ifdef CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER
+static int krait_tbb_fixup(unsigned int fsr, struct pt_regs *regs)
+{
+	int base_cond, cond = 0;
+	unsigned int p1, cpsr_z, cpsr_c, cpsr_n, cpsr_v;
+
+	if ((read_cpuid_id() & 0xFFFFFFFC) != 0x510F04D0)
+		return 0;
+
+	if (!thumb_mode(regs))
+		return 0;
+
+	/* If ITSTATE is 0, return quickly */
+	if ((regs->ARM_cpsr & PSR_IT_MASK) == 0)
+		return 0;
+
+	cpsr_n = (regs->ARM_cpsr & PSR_N_BIT) ? 1 : 0;
+	cpsr_z = (regs->ARM_cpsr & PSR_Z_BIT) ? 1 : 0;
+	cpsr_c = (regs->ARM_cpsr & PSR_C_BIT) ? 1 : 0;
+	cpsr_v = (regs->ARM_cpsr & PSR_V_BIT) ? 1 : 0;
+
+	p1 = (regs->ARM_cpsr & BIT(12)) ? 1 : 0;
+
+	base_cond = (regs->ARM_cpsr >> 13) & 0x07;
+
+	switch (base_cond) {
+	case 0x0:	/* equal */
+		cond = cpsr_z;
+		break;
+
+	case 0x1:	/* carry set */
+		cond = cpsr_c;
+		break;
+
+	case 0x2:	/* minus / negative */
+		cond = cpsr_n;
+		break;
+
+	case 0x3:	/* overflow */
+		cond = cpsr_v;
+		break;
+
+	case 0x4:	/* unsigned higher */
+		cond = (cpsr_c == 1) && (cpsr_z == 0);
+		break;
+
+	case 0x5:	/* signed greater / equal */
+		cond = (cpsr_n == cpsr_v);
+		break;
+
+	case 0x6:	/* signed greater */
+		cond = (cpsr_z == 0) && (cpsr_n == cpsr_v);
+		break;
+
+	case 0x7:	/* always */
+		cond = 1;
+		break;
+	};
+
+	if (cond == p1) {
+		pr_debug("Conditional abort fixup, PC=%08x, base=%d, cond=%d\n",
+			 (unsigned int) regs->ARM_pc, base_cond, cond);
+		regs->ARM_pc += 2;
+		return 1;
+	}
+	return 0;
+}
+#endif
+
 /*
  * Dispatch a data abort to the relevant handler.
  */
@@ -545,6 +666,16 @@
 	const struct fsr_info *inf = fsr_info + fsr_fs(fsr);
 	struct siginfo info;
 
+#ifdef CONFIG_EMULATE_DOMAIN_MANAGER_V7
+	if (emulate_domain_manager_data_abort(fsr, addr))
+		return;
+#endif
+
+#ifdef CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER
+	if (krait_tbb_fixup(fsr, regs))
+		return;
+#endif
+
 	if (!inf->fn(addr, fsr & ~FSR_LNX_PF, regs))
 		return;
 
@@ -577,6 +708,11 @@
 	const struct fsr_info *inf = ifsr_info + fsr_fs(ifsr);
 	struct siginfo info;
 
+#ifdef CONFIG_EMULATE_DOMAIN_MANAGER_V7
+	if (emulate_domain_manager_prefetch_abort(ifsr, addr))
+		return;
+#endif
+
 	if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs))
 		return;
 
diff --git a/arch/arm/mm/fsr-2level.c b/arch/arm/mm/fsr-2level.c
index 18ca74c..3b016e6 100644
--- a/arch/arm/mm/fsr-2level.c
+++ b/arch/arm/mm/fsr-2level.c
@@ -30,7 +30,7 @@
 	{ do_bad,		SIGBUS,  0,		"unknown 19"			   },
 	{ do_bad,		SIGBUS,  0,		"lock abort"			   }, /* xscale */
 	{ do_bad,		SIGBUS,  0,		"unknown 21"			   },
-	{ do_bad,		SIGBUS,  BUS_OBJERR,	"imprecise external abort"	   }, /* xscale */
+	{ do_imprecise_ext,	SIGBUS,  BUS_OBJERR,	"imprecise external abort"	   }, /* xscale */
 	{ do_bad,		SIGBUS,  0,		"unknown 23"			   },
 	{ do_bad,		SIGBUS,  0,		"dcache parity error"		   }, /* xscale */
 	{ do_bad,		SIGBUS,  0,		"unknown 25"			   },
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 8f5813b..59e252b 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/bootmem.h>
 #include <linux/mman.h>
+#include <linux/mm.h>
 #include <linux/export.h>
 #include <linux/nodemask.h>
 #include <linux/initrd.h>
@@ -20,6 +21,7 @@
 #include <linux/highmem.h>
 #include <linux/gfp.h>
 #include <linux/memblock.h>
+#include <linux/sort.h>
 
 #include <asm/mach-types.h>
 #include <asm/memblock.h>
@@ -122,7 +124,14 @@
 			else
 				shared += page_count(page) - 1;
 			page++;
+#ifdef CONFIG_SPARSEMEM
+			pfn1++;
+			if (!(pfn1 % PAGES_PER_SECTION))
+				page = pfn_to_page(pfn1);
+		} while (pfn1 < pfn2);
+#else
 		} while (page < end);
+#endif
 	}
 
 	printk("%d pages of RAM\n", total);
@@ -226,6 +235,29 @@
 }
 #endif
 
+#ifdef CONFIG_ARCH_POPULATES_NODE_MAP
+static void __init arm_bootmem_free_apnm(unsigned long max_low,
+	unsigned long max_high)
+{
+	unsigned long max_zone_pfns[MAX_NR_ZONES];
+	struct memblock_region *reg;
+
+	memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+
+	max_zone_pfns[0] = max_low;
+#ifdef CONFIG_HIGHMEM
+	max_zone_pfns[ZONE_HIGHMEM] = max_high;
+#endif
+	for_each_memblock(memory, reg) {
+		unsigned long start = memblock_region_memory_base_pfn(reg);
+		unsigned long end = memblock_region_memory_end_pfn(reg);
+
+		add_active_range(0, start, end);
+	}
+	free_area_init_nodes(max_zone_pfns);
+}
+
+#else
 static void __init arm_bootmem_free(unsigned long min, unsigned long max_low,
 	unsigned long max_high)
 {
@@ -283,6 +315,7 @@
 
 	free_area_init_node(0, zone_size, min, zhole_size);
 }
+#endif
 
 #ifdef CONFIG_HAVE_ARCH_PFN_VALID
 int pfn_valid(unsigned long pfn)
@@ -299,11 +332,12 @@
 #else
 static void __init arm_memory_present(void)
 {
-	struct memblock_region *reg;
-
-	for_each_memblock(memory, reg)
-		memory_present(0, memblock_region_memory_base_pfn(reg),
-			       memblock_region_memory_end_pfn(reg));
+	struct meminfo *mi = &meminfo;
+	int i;
+	for_each_bank(i, mi) {
+		memory_present(0, bank_pfn_start(&mi->bank[i]),
+				bank_pfn_end(&mi->bank[i]));
+	}
 }
 #endif
 
@@ -322,10 +356,37 @@
 	return phys;
 }
 
+static int __init meminfo_cmp(const void *_a, const void *_b)
+{
+	const struct membank *a = _a, *b = _b;
+	long cmp = bank_pfn_start(a) - bank_pfn_start(b);
+	return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
+
+#ifdef CONFIG_DONT_MAP_HOLE_AFTER_MEMBANK0
+unsigned long membank0_size;
+EXPORT_SYMBOL(membank0_size);
+unsigned long membank1_start;
+EXPORT_SYMBOL(membank1_start);
+
+void __init find_membank0_hole(void)
+{
+	sort(&meminfo.bank, meminfo.nr_banks,
+		sizeof(meminfo.bank[0]), meminfo_cmp, NULL);
+
+	membank0_size = meminfo.bank[0].size;
+	membank1_start = meminfo.bank[1].start;
+}
+#endif
+
 void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc)
 {
 	int i;
 
+#ifndef CONFIG_DONT_MAP_HOLE_AFTER_MEMBANK0
+	sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank[0]), meminfo_cmp, NULL);
+#endif
+
 	for (i = 0; i < mi->nr_banks; i++)
 		memblock_add(mi->bank[i].start, mi->bank[i].size);
 
@@ -369,6 +430,28 @@
 	memblock_dump_all();
 }
 
+#ifdef CONFIG_MEMORY_HOTPLUG_SPARSE
+int _early_pfn_valid(unsigned long pfn)
+{
+	struct meminfo *mi = &meminfo;
+	unsigned int left = 0, right = mi->nr_banks;
+
+	do {
+		unsigned int mid = (right + left) / 2;
+		struct membank *bank = &mi->bank[mid];
+
+		if (pfn < bank_pfn_start(bank))
+			right = mid;
+		else if (pfn >= bank_pfn_end(bank))
+			left = mid + 1;
+		else
+			return 1;
+	} while (left < right);
+	return 0;
+}
+EXPORT_SYMBOL(_early_pfn_valid);
+#endif
+
 void __init bootmem_init(void)
 {
 	unsigned long min, max_low, max_high;
@@ -390,12 +473,16 @@
 	 */
 	sparse_init();
 
+#ifdef CONFIG_ARCH_POPULATES_NODE_MAP
+	arm_bootmem_free_apnm(max_low, max_high);
+#else
 	/*
 	 * Now free the memory - free_area_init_node needs
 	 * the sparse mem_map arrays initialized by sparse_init()
 	 * for memmap_init_zone(), otherwise all PFNs are invalid.
 	 */
 	arm_bootmem_free(min, max_low, max_high);
+#endif
 
 	/*
 	 * This doesn't seem to be used by the Linux memory manager any
@@ -466,7 +553,10 @@
 }
 
 /*
- * The mem_map array can get very big.  Free the unused area of the memory map.
+ * The mem_map array can get very big.  Free as much of the unused portion of
+ * the mem_map that we are allowed to. The page migration code moves pages
+ * in blocks that are rounded per the MAX_ORDER_NR_PAGES definition, so we
+ * can't free mem_map entries that may be dereferenced in this manner.
  */
 static void __init free_unused_memmap(struct meminfo *mi)
 {
@@ -480,7 +570,8 @@
 	for_each_bank(i, mi) {
 		struct membank *bank = &mi->bank[i];
 
-		bank_start = bank_pfn_start(bank);
+		bank_start = round_down(bank_pfn_start(bank),
+					MAX_ORDER_NR_PAGES);
 
 #ifdef CONFIG_SPARSEMEM
 		/*
@@ -504,12 +595,8 @@
 		if (prev_bank_end && prev_bank_end < bank_start)
 			free_memmap(prev_bank_end, bank_start);
 
-		/*
-		 * Align up here since the VM subsystem insists that the
-		 * memmap entries are valid from the bank end aligned to
-		 * MAX_ORDER_NR_PAGES.
-		 */
-		prev_bank_end = ALIGN(bank_pfn_end(bank), MAX_ORDER_NR_PAGES);
+		prev_bank_end = round_up(bank_pfn_end(bank),
+					 MAX_ORDER_NR_PAGES);
 	}
 
 #ifdef CONFIG_SPARSEMEM
@@ -584,6 +671,9 @@
 	extern u32 dtcm_end;
 	extern u32 itcm_end;
 #endif
+#ifdef CONFIG_FIX_MOVABLE_ZONE
+	struct zone *zone;
+#endif
 
 	max_mapnr   = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map;
 
@@ -619,9 +709,24 @@
 			else if (!page_count(page))
 				free_pages++;
 			page++;
+#ifdef CONFIG_SPARSEMEM
+			pfn1++;
+			if (!(pfn1 % PAGES_PER_SECTION))
+				page = pfn_to_page(pfn1);
+		} while (pfn1 < pfn2);
+#else
 		} while (page < end);
+#endif
 	}
 
+#ifdef CONFIG_FIX_MOVABLE_ZONE
+	for_each_zone(zone) {
+		if (zone_idx(zone) == ZONE_MOVABLE)
+			total_unmovable_pages = totalram_pages -
+							zone->spanned_pages;
+	}
+#endif
+
 	/*
 	 * Since our memory may not be contiguous, calculate the
 	 * real number of pages we have in this system
@@ -719,6 +824,7 @@
 
 void free_initmem(void)
 {
+	unsigned long reclaimed_initmem;
 #ifdef CONFIG_HAVE_TCM
 	extern char __tcm_start, __tcm_end;
 
@@ -729,23 +835,61 @@
 #endif
 
 	poison_init_mem(__init_begin, __init_end - __init_begin);
-	if (!machine_is_integrator() && !machine_is_cintegrator())
-		totalram_pages += free_area(__phys_to_pfn(__pa(__init_begin)),
+	if (!machine_is_integrator() && !machine_is_cintegrator()) {
+		reclaimed_initmem = free_area(__phys_to_pfn(__pa(__init_begin)),
 					    __phys_to_pfn(__pa(__init_end)),
 					    "init");
+		totalram_pages += reclaimed_initmem;
+#ifdef CONFIG_FIX_MOVABLE_ZONE
+		total_unmovable_pages += reclaimed_initmem;
+#endif
+	}
 }
 
+#ifdef CONFIG_MEMORY_HOTPLUG
+int arch_add_memory(int nid, u64 start, u64 size)
+{
+	struct pglist_data *pgdata = NODE_DATA(nid);
+	struct zone *zone = pgdata->node_zones + ZONE_MOVABLE;
+	unsigned long start_pfn = start >> PAGE_SHIFT;
+	unsigned long nr_pages = size >> PAGE_SHIFT;
+
+	return __add_pages(nid, zone, start_pfn, nr_pages);
+}
+
+int arch_physical_active_memory(u64 start, u64 size)
+{
+	return platform_physical_active_pages(start, size);
+}
+
+int arch_physical_remove_memory(u64 start, u64 size)
+{
+	return platform_physical_remove_pages(start, size);
+}
+
+int arch_physical_low_power_memory(u64 start, u64 size)
+{
+	return platform_physical_low_power_pages(start, size);
+}
+#endif
+
 #ifdef CONFIG_BLK_DEV_INITRD
 
 static int keep_initrd;
 
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
+	unsigned long reclaimed_initrd_mem;
+
 	if (!keep_initrd) {
 		poison_init_mem((void *)start, PAGE_ALIGN(end) - start);
-		totalram_pages += free_area(__phys_to_pfn(__pa(start)),
-					    __phys_to_pfn(__pa(end)),
-					    "initrd");
+		reclaimed_initrd_mem = free_area(__phys_to_pfn(__pa(start)),
+						 __phys_to_pfn(__pa(end)),
+						 "initrd");
+		totalram_pages += reclaimed_initrd_mem;
+#ifdef CONFIG_FIX_MOVABLE_ZONE
+		total_unmovable_pages += reclaimed_initrd_mem;
+#endif
 	}
 }
 
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
index 4f55f50..8df41e2 100644
--- a/arch/arm/mm/ioremap.c
+++ b/arch/arm/mm/ioremap.c
@@ -46,6 +46,14 @@
 }
 EXPORT_SYMBOL(ioremap_page);
 
+int ioremap_pages(unsigned long virt, unsigned long phys, unsigned long size,
+		 const struct mem_type *mtype)
+{
+	return ioremap_page_range(virt, virt + size, phys,
+				  __pgprot(mtype->prot_pte));
+}
+EXPORT_SYMBOL(ioremap_pages);
+
 void __check_kvm_seq(struct mm_struct *mm)
 {
 	unsigned int seq;
diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h
index 27f4a61..411fbd9 100644
--- a/arch/arm/mm/mm.h
+++ b/arch/arm/mm/mm.h
@@ -67,5 +67,7 @@
 #define arm_dma_limit ((u32)~0)
 #endif
 
+struct map_desc;
+
 void __init bootmem_init(void);
 void arm_mm_memblock_reserve(void);
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 137858b..e6b733b 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -28,6 +28,7 @@
 #include <asm/highmem.h>
 #include <asm/system_info.h>
 #include <asm/traps.h>
+#include <asm/mmu_writeable.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -52,6 +53,9 @@
 #define CPOLICY_WRITEBACK	3
 #define CPOLICY_WRITEALLOC	4
 
+#define RX_AREA_START           _text
+#define RX_AREA_END             __start_rodata
+
 static unsigned int cachepolicy __initdata = CPOLICY_WRITEBACK;
 static unsigned int ecc_mask __initdata = 0;
 pgprot_t pgprot_user;
@@ -257,6 +261,18 @@
 		.prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE,
 		.domain    = DOMAIN_KERNEL,
 	},
+	[MT_MEMORY_R] = {
+		.prot_sect = PMD_TYPE_SECT | PMD_SECT_XN,
+		.domain    = DOMAIN_KERNEL,
+	},
+	[MT_MEMORY_RW] = {
+		.prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_XN,
+		.domain    = DOMAIN_KERNEL,
+	},
+	[MT_MEMORY_RX] = {
+		.prot_sect = PMD_TYPE_SECT,
+		.domain    = DOMAIN_KERNEL,
+	},
 	[MT_ROM] = {
 		.prot_sect = PMD_TYPE_SECT,
 		.domain    = DOMAIN_KERNEL,
@@ -442,6 +458,8 @@
 		 * from SVC mode and no access from userspace.
 		 */
 		mem_types[MT_ROM].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
+		mem_types[MT_MEMORY_RX].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
+		mem_types[MT_MEMORY_R].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
 		mem_types[MT_MINICLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
 		mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
 #endif
@@ -461,6 +479,9 @@
 			mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S;
 			mem_types[MT_MEMORY].prot_pte |= L_PTE_SHARED;
 			mem_types[MT_MEMORY_NONCACHED].prot_sect |= PMD_SECT_S;
+			mem_types[MT_MEMORY_R].prot_sect |= PMD_SECT_S;
+			mem_types[MT_MEMORY_RW].prot_sect |= PMD_SECT_S;
+			mem_types[MT_MEMORY_RX].prot_sect |= PMD_SECT_S;
 			mem_types[MT_MEMORY_NONCACHED].prot_pte |= L_PTE_SHARED;
 		}
 	}
@@ -513,6 +534,9 @@
 	mem_types[MT_MEMORY].prot_sect |= ecc_mask | cp->pmd;
 	mem_types[MT_MEMORY].prot_pte |= kern_pgprot;
 	mem_types[MT_MEMORY_NONCACHED].prot_sect |= ecc_mask;
+	mem_types[MT_MEMORY_R].prot_sect |= ecc_mask | cp->pmd;
+	mem_types[MT_MEMORY_RW].prot_sect |= ecc_mask | cp->pmd;
+	mem_types[MT_MEMORY_RX].prot_sect |= ecc_mask | cp->pmd;
 	mem_types[MT_ROM].prot_sect |= cp->pmd;
 
 	switch (cp->pmd) {
@@ -576,6 +600,7 @@
 	BUG_ON(pmd_bad(*pmd));
 }
 
+#ifdef CONFIG_HIGHMEM
 static pte_t * __init early_pte_alloc_and_install(pmd_t *pmd,
 	unsigned long addr, unsigned long prot)
 {
@@ -586,6 +611,7 @@
 	BUG_ON(pmd_bad(*pmd));
 	return pte_offset_kernel(pmd, addr);
 }
+#endif
 
 static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr,
 				  unsigned long end, unsigned long pfn,
@@ -842,6 +868,14 @@
 {
 	int i, j, highmem = 0;
 
+#ifdef CONFIG_DONT_MAP_HOLE_AFTER_MEMBANK0
+	find_membank0_hole();
+#endif
+
+#if (defined CONFIG_HIGHMEM) && (defined CONFIG_FIX_MOVABLE_ZONE)
+	if (movable_reserved_size && __pa(vmalloc_min) > movable_reserved_start)
+		vmalloc_min = __va(movable_reserved_start);
+#endif
 	for (i = 0, j = 0; i < meminfo.nr_banks; i++) {
 		struct membank *bank = &meminfo.bank[j];
 		*bank = meminfo.bank[i];
@@ -1105,6 +1139,105 @@
 #endif
 }
 
+#ifdef CONFIG_STRICT_MEMORY_RWX
+static struct {
+	pmd_t *pmd_to_flush;
+	pmd_t *pmd;
+	unsigned long addr;
+	pmd_t saved_pmd;
+	bool made_writeable;
+} mem_unprotect;
+
+static DEFINE_SPINLOCK(mem_text_writeable_lock);
+
+void mem_text_writeable_spinlock(unsigned long *flags)
+{
+	spin_lock_irqsave(&mem_text_writeable_lock, *flags);
+}
+
+void mem_text_writeable_spinunlock(unsigned long *flags)
+{
+	spin_unlock_irqrestore(&mem_text_writeable_lock, *flags);
+}
+
+/*
+ * mem_text_address_writeable() and mem_text_address_restore()
+ * should be called as a pair. They are used to make the
+ * specified address in the kernel text section temporarily writeable
+ * when it has been marked read-only by STRICT_MEMORY_RWX.
+ * Used by kprobes and other debugging tools to set breakpoints etc.
+ * mem_text_address_writeable() is invoked before writing.
+ * After the write, mem_text_address_restore() must be called
+ * to restore the original state.
+ * This is only effective when used on the kernel text section
+ * marked as MEMORY_RX by map_lowmem()
+ *
+ * They must each be called with mem_text_writeable_lock locked
+ * by the caller, with no unlocking between the calls.
+ * The caller should release mem_text_writeable_lock immediately
+ * after the call to mem_text_address_restore().
+ * Only the write and associated cache operations should be performed
+ * between the calls.
+ */
+
+/* this function must be called with mem_text_writeable_lock held */
+void mem_text_address_writeable(unsigned long addr)
+{
+	struct task_struct *tsk = current;
+	struct mm_struct *mm = tsk->active_mm;
+	pgd_t *pgd = pgd_offset(mm, addr);
+	pud_t *pud = pud_offset(pgd, addr);
+
+	mem_unprotect.made_writeable = 0;
+
+	if ((addr < (unsigned long)RX_AREA_START) ||
+	    (addr >= (unsigned long)RX_AREA_END))
+		return;
+
+	mem_unprotect.pmd = pmd_offset(pud, addr);
+	mem_unprotect.pmd_to_flush = mem_unprotect.pmd;
+	mem_unprotect.addr = addr & PAGE_MASK;
+
+	if (addr & SECTION_SIZE)
+			mem_unprotect.pmd++;
+
+	mem_unprotect.saved_pmd = *mem_unprotect.pmd;
+	if ((mem_unprotect.saved_pmd & PMD_TYPE_MASK) != PMD_TYPE_SECT)
+		return;
+
+	*mem_unprotect.pmd &= ~PMD_SECT_APX;
+
+	flush_pmd_entry(mem_unprotect.pmd_to_flush);
+	flush_tlb_kernel_page(mem_unprotect.addr);
+	mem_unprotect.made_writeable = 1;
+}
+
+/* this function must be called with mem_text_writeable_lock held */
+void mem_text_address_restore(void)
+{
+	if (mem_unprotect.made_writeable) {
+		*mem_unprotect.pmd = mem_unprotect.saved_pmd;
+		flush_pmd_entry(mem_unprotect.pmd_to_flush);
+		flush_tlb_kernel_page(mem_unprotect.addr);
+	}
+}
+#endif
+
+void mem_text_write_kernel_word(unsigned long *addr, unsigned long word)
+{
+	unsigned long flags;
+
+	mem_text_writeable_spinlock(&flags);
+	mem_text_address_writeable((unsigned long)addr);
+	*addr = word;
+	flush_icache_range((unsigned long)addr,
+			   ((unsigned long)addr + sizeof(long)));
+	mem_text_address_restore();
+	mem_text_writeable_spinunlock(&flags);
+}
+EXPORT_SYMBOL(mem_text_write_kernel_word);
+
+extern char __init_data[];
 
 static void __init map_lowmem(void)
 {
@@ -1125,8 +1258,46 @@
 
 		map.pfn = __phys_to_pfn(start);
 		map.virtual = __phys_to_virt(start);
+#ifdef CONFIG_STRICT_MEMORY_RWX
+		if (start <= __pa(_text) && __pa(_text) < end) {
+			map.length = SECTION_SIZE;
+			map.type = MT_MEMORY;
+
+			create_mapping(&map, false);
+
+			map.pfn = __phys_to_pfn(start + SECTION_SIZE);
+			map.virtual = __phys_to_virt(start + SECTION_SIZE);
+			map.length = (unsigned long)RX_AREA_END - map.virtual;
+			map.type = MT_MEMORY_RX;
+
+			create_mapping(&map, false);
+
+			map.pfn = __phys_to_pfn(__pa(__start_rodata));
+			map.virtual = (unsigned long)__start_rodata;
+			map.length = __init_begin - __start_rodata;
+			map.type = MT_MEMORY_R;
+
+			create_mapping(&map, false);
+
+			map.pfn = __phys_to_pfn(__pa(__init_begin));
+			map.virtual = (unsigned long)__init_begin;
+			map.length = __init_data - __init_begin;
+			map.type = MT_MEMORY;
+
+			create_mapping(&map, false);
+
+			map.pfn = __phys_to_pfn(__pa(__init_data));
+			map.virtual = (unsigned long)__init_data;
+			map.length = __phys_to_virt(end) - (unsigned int)__init_data;
+			map.type = MT_MEMORY_RW;
+		} else {
+			map.length = end - start;
+			map.type = MT_MEMORY_RW;
+		}
+#else
 		map.length = end - start;
 		map.type = MT_MEMORY;
+#endif
 
 		create_mapping(&map, false);
 	}
diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S
index 2d8ff3a..5829bb3 100644
--- a/arch/arm/mm/proc-macros.S
+++ b/arch/arm/mm/proc-macros.S
@@ -306,6 +306,8 @@
 	.long	\name\()_flush_kern_dcache_area
 	.long	\name\()_dma_map_area
 	.long	\name\()_dma_unmap_area
+	.long	\name\()_dma_inv_range
+	.long	\name\()_dma_clean_range
 	.long	\name\()_dma_flush_range
 	.size	\name\()_cache_fns, . - \name\()_cache_fns
 .endm
diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S
index 5900cd5..501397a 100644
--- a/arch/arm/mm/proc-v6.S
+++ b/arch/arm/mm/proc-v6.S
@@ -107,6 +107,12 @@
 	mcr	p15, 0, r2, c7, c5, 6		@ flush BTAC/BTB
 	mcr	p15, 0, r2, c7, c10, 4		@ drain write buffer
 	mcr	p15, 0, r0, c2, c0, 0		@ set TTB 0
+#ifdef CONFIG_PID_IN_CONTEXTIDR
+	mrc	p15, 0, r2, c13, c0, 1		@ read current context ID
+	bic	r2, r2, #0xff			@ extract the PID
+	and	r1, r1, #0xff
+	orr	r1, r1, r2			@ insert the PID into r1
+#endif
 	mcr	p15, 0, r1, c13, c0, 1		@ set context ID
 #endif
 	mov	pc, lr
diff --git a/arch/arm/mm/proc-v7-2level.S b/arch/arm/mm/proc-v7-2level.S
index 3a4b3e7..1fda38b 100644
--- a/arch/arm/mm/proc-v7-2level.S
+++ b/arch/arm/mm/proc-v7-2level.S
@@ -49,6 +49,12 @@
 #ifdef CONFIG_ARM_ERRATA_754322
 	dsb
 #endif
+#ifdef CONFIG_PID_IN_CONTEXTIDR
+	mrc     p15, 0, r2, c13, c0, 1          @ read current context ID
+	bic     r2, r2, #0xff                   @ extract the PID
+	and     r1, r1, #0xff
+	orr     r1, r1, r2                      @ insert the PID into r1
+#endif
 	mcr	p15, 0, r2, c13, c0, 1		@ set reserved context ID
 	isb
 1:	mcr	p15, 0, r0, c2, c0, 0		@ set TTB 0
@@ -140,7 +146,11 @@
 	 *   NOS = PRRR[24+n] = 1	- not outer shareable
 	 */
 .equ	PRRR,	0xff0a81a8
+#ifdef CONFIG_ARCH_MSM_SCORPIONMP
+.equ	NMRR,	0x40e080e0
+#else
 .equ	NMRR,	0x40e040e0
+#endif
 
 	/*
 	 * Macro for setting up the TTBRx and TTBCR registers.
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index c2e2b66..47dab27 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -56,6 +56,9 @@
 	bic	r1, r1, #0x1			@ ...............m
  THUMB(	bic	r1, r1, #1 << 30 )		@ SCTLR.TE (Thumb exceptions)
 	mcr	p15, 0, r1, c1, c0, 0		@ disable MMU
+	mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D,flush TLB
+	mcr     p15, 0, ip, c7, c5, 6           @ flush BTC
+	dsb
 	isb
 	mov	pc, r0
 ENDPROC(cpu_v7_reset)
@@ -255,6 +258,31 @@
 	mcr	p15, 0, r5, c10, c2, 0		@ write PRRR
 	mcr	p15, 0, r6, c10, c2, 1		@ write NMRR
 #endif
+
+#if defined(CONFIG_ARCH_MSM_SCORPION) && !defined(CONFIG_MSM_SMP)
+	mov     r0, #0x33
+	mcr     p15, 3, r0, c15, c0, 3          @ set L2CR1
+#endif
+#if defined (CONFIG_ARCH_MSM_SCORPION)
+	mrc     p15, 0, r0, c1, c0, 1           @ read ACTLR
+#ifdef CONFIG_CPU_CACHE_ERR_REPORT
+	orr     r0, r0, #0x37                   @ turn on L1/L2 error reporting
+#else
+	bic     r0, r0, #0x37
+#endif
+#if defined (CONFIG_ARCH_MSM_SCORPIONMP)
+	orr    r0, r0, #0x1 << 24     @ optimal setting for Scorpion MP
+#endif
+#ifndef CONFIG_ARCH_MSM_KRAIT
+	mcr     p15, 0, r0, c1, c0, 1           @ write ACTLR
+#endif
+#endif
+#if defined (CONFIG_ARCH_MSM_SCORPIONMP)
+	mrc     p15, 3, r0, c15, c0, 2  @ optimal setting for Scorpion MP
+	orr         r0, r0, #0x1 << 21
+	mcr     p15, 3, r0, c15, c0, 2
+#endif
+
 #ifndef CONFIG_ARM_THUMBEE
 	mrc	p15, 0, r0, c0, c1, 0		@ read ID_PFR0 for ThumbEE
 	and	r0, r0, #(0xf << 12)		@ ThumbEE enabled field
diff --git a/arch/arm/mm/tlb-v7.S b/arch/arm/mm/tlb-v7.S
index 845f461..0e88578 100644
--- a/arch/arm/mm/tlb-v7.S
+++ b/arch/arm/mm/tlb-v7.S
@@ -38,11 +38,19 @@
 	dsb
 	mov	r0, r0, lsr #PAGE_SHIFT		@ align address
 	mov	r1, r1, lsr #PAGE_SHIFT
+#ifdef CONFIG_ARCH_MSM8X60
+	mov	r0, r0, lsl #PAGE_SHIFT
+#else
 	asid	r3, r3				@ mask ASID
 	orr	r0, r3, r0, lsl #PAGE_SHIFT	@ Create initial MVA
+#endif
 	mov	r1, r1, lsl #PAGE_SHIFT
 1:
+#ifdef CONFIG_ARCH_MSM8X60
+	ALT_SMP(mcr	p15, 0, r0, c8, c3, 3)	@ TLB invalidate U MVA (shareable)
+#else
 	ALT_SMP(mcr	p15, 0, r0, c8, c3, 1)	@ TLB invalidate U MVA (shareable)
+#endif
 	ALT_UP(mcr	p15, 0, r0, c8, c7, 1)	@ TLB invalidate U MVA
 
 	add	r0, r0, #PAGE_SZ
@@ -67,7 +75,11 @@
 	mov	r0, r0, lsl #PAGE_SHIFT
 	mov	r1, r1, lsl #PAGE_SHIFT
 1:
+#ifdef CONFIG_ARCH_MSM8X60
+	ALT_SMP(mcr	p15, 0, r0, c8, c3, 3)	@ TLB invalidate U MVA (shareable)
+#else
 	ALT_SMP(mcr	p15, 0, r0, c8, c3, 1)	@ TLB invalidate U MVA (shareable)
+#endif
 	ALT_UP(mcr	p15, 0, r0, c8, c7, 1)	@ TLB invalidate U MVA
 	add	r0, r0, #PAGE_SZ
 	cmp	r0, r1
diff --git a/arch/arm/mm/vcm.c b/arch/arm/mm/vcm.c
new file mode 100644
index 0000000..f2d9457
--- /dev/null
+++ b/arch/arm/mm/vcm.c
@@ -0,0 +1,1830 @@
+/* Copyright (c) 2010, 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/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/vcm_mm.h>
+#include <linux/vcm.h>
+#include <linux/vcm_alloc.h>
+#include <linux/vcm_types.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+
+#include <asm/page.h>
+#include <asm/sizes.h>
+
+#include <linux/iommu.h>
+
+/* alloc_vm_area */
+#include <linux/pfn.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+
+#include <asm/cacheflush.h>
+#include <asm/mach/map.h>
+
+#define ONE_TO_ONE_CHK 1
+
+#define vcm_err(a, ...)							\
+	pr_err("ERROR %s %i " a, __func__, __LINE__, ##__VA_ARGS__)
+
+static unsigned int smmu_map_sizes[4] = {SZ_16M, SZ_1M, SZ_64K, SZ_4K};
+
+static phys_addr_t *bootmem_cont;
+static int cont_sz;
+static struct vcm *cont_vcm_id;
+static struct phys_chunk *cont_phys_chunk;
+
+DEFINE_SPINLOCK(vcmlock);
+
+/* Leaving this in for now to keep compatibility of the API. */
+/* This will disappear. */
+phys_addr_t vcm_get_dev_addr(struct res *res)
+{
+	if (!res) {
+		vcm_err("NULL RES");
+		return -EINVAL;
+	}
+	return res->dev_addr;
+}
+
+static int vcm_no_res(struct vcm *vcm)
+{
+	if (!vcm) {
+		vcm_err("NULL vcm\n");
+		goto fail;
+	}
+
+	return list_empty(&vcm->res_head);
+fail:
+	return -EINVAL;
+}
+
+static int vcm_no_assoc(struct vcm *vcm)
+{
+	if (!vcm) {
+		vcm_err("NULL vcm\n");
+		goto fail;
+	}
+
+	return list_empty(&vcm->assoc_head);
+fail:
+	return -EINVAL;
+}
+
+static int vcm_all_activated(struct vcm *vcm)
+{
+	struct avcm *avcm;
+
+	if (!vcm) {
+		vcm_err("NULL vcm\n");
+		goto fail;
+	}
+
+	list_for_each_entry(avcm, &vcm->assoc_head, assoc_elm)
+		if (!avcm->is_active)
+			return 0;
+
+	return 1;
+fail:
+	return -EINVAL;
+}
+
+static void vcm_destroy_common(struct vcm *vcm)
+{
+	if (!vcm) {
+		vcm_err("NULL vcm\n");
+		return;
+	}
+
+	memset(vcm, 0, sizeof(*vcm));
+	kfree(vcm);
+}
+
+static struct vcm *vcm_create_common(void)
+{
+	struct vcm *vcm = 0;
+
+	vcm = kzalloc(sizeof(*vcm), GFP_KERNEL);
+	if (!vcm) {
+		vcm_err("kzalloc(%i, GFP_KERNEL) ret 0\n",
+			sizeof(*vcm));
+		goto fail;
+	}
+
+	INIT_LIST_HEAD(&vcm->res_head);
+	INIT_LIST_HEAD(&vcm->assoc_head);
+
+	return vcm;
+
+fail:
+	return NULL;
+}
+
+
+static int vcm_create_pool(struct vcm *vcm, unsigned long start_addr,
+			   size_t len)
+{
+	int ret = 0;
+
+	if (!vcm) {
+		vcm_err("NULL vcm\n");
+		goto fail;
+	}
+
+	vcm->start_addr = start_addr;
+	vcm->len = len;
+
+	vcm->pool = gen_pool_create(PAGE_SHIFT, -1);
+	if (!vcm->pool) {
+		vcm_err("gen_pool_create(%x, -1) ret 0\n", PAGE_SHIFT);
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	ret = gen_pool_add(vcm->pool, start_addr, len, -1);
+	if (ret) {
+		vcm_err("gen_pool_add(%p, %p, %i, -1) ret %i\n", vcm->pool,
+			(void *) start_addr, len, ret);
+		goto fail;
+	}
+
+	vcm->domain = iommu_domain_alloc();
+	if (!vcm->domain) {
+		vcm_err("Could not allocate domain\n");
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+fail:
+	if (ret && vcm->pool)
+		gen_pool_destroy(vcm->pool);
+
+	return ret;
+}
+
+
+static struct vcm *vcm_create_flagged(int flag, unsigned long start_addr,
+				      size_t len)
+{
+	int ret = 0;
+	struct vcm *vcm = 0;
+
+	vcm = vcm_create_common();
+	if (!vcm) {
+		vcm_err("NULL vcm\n");
+		goto fail;
+	}
+
+	/* special one-to-one mapping case */
+	if ((flag & ONE_TO_ONE_CHK) &&
+	    bootmem_cont &&
+	    start_addr == (size_t) bootmem_cont &&
+	    len == cont_sz) {
+		vcm->type = VCM_ONE_TO_ONE;
+	} else {
+		ret = vcm_create_pool(vcm, start_addr, len);
+		vcm->type = VCM_DEVICE;
+	}
+
+	if (ret) {
+		vcm_err("vcm_create_pool(%p, %p, %i) ret %i\n", vcm,
+			(void *) start_addr, len, ret);
+		goto fail2;
+	}
+
+	return vcm;
+
+fail2:
+	vcm_destroy_common(vcm);
+fail:
+	return NULL;
+}
+
+struct vcm *vcm_create(unsigned long start_addr, size_t len)
+{
+	unsigned long flags;
+	struct vcm *vcm;
+
+	spin_lock_irqsave(&vcmlock, flags);
+	vcm = vcm_create_flagged(ONE_TO_ONE_CHK, start_addr, len);
+	spin_unlock_irqrestore(&vcmlock, flags);
+	return vcm;
+}
+
+
+static int ext_vcm_id_valid(size_t ext_vcm_id)
+{
+	return ((ext_vcm_id == VCM_PREBUILT_KERNEL) ||
+		(ext_vcm_id == VCM_PREBUILT_USER));
+}
+
+
+struct vcm *vcm_create_from_prebuilt(size_t ext_vcm_id)
+{
+	unsigned long flags;
+	struct vcm *vcm = 0;
+
+	spin_lock_irqsave(&vcmlock, flags);
+
+	if (!ext_vcm_id_valid(ext_vcm_id)) {
+		vcm_err("ext_vcm_id_valid(%i) ret 0\n", ext_vcm_id);
+		goto fail;
+	}
+
+	vcm = vcm_create_common();
+	if (!vcm) {
+		vcm_err("NULL vcm\n");
+		goto fail;
+	}
+
+	if (ext_vcm_id == VCM_PREBUILT_KERNEL)
+		vcm->type = VCM_EXT_KERNEL;
+	else if (ext_vcm_id == VCM_PREBUILT_USER)
+		vcm->type = VCM_EXT_USER;
+	else {
+		vcm_err("UNREACHABLE ext_vcm_id is illegal\n");
+		goto fail_free;
+	}
+
+	/* TODO: set kernel and userspace start_addr and len, if this
+	 * makes sense */
+
+	spin_unlock_irqrestore(&vcmlock, flags);
+	return vcm;
+
+fail_free:
+	vcm_destroy_common(vcm);
+fail:
+	spin_unlock_irqrestore(&vcmlock, flags);
+	return NULL;
+}
+
+
+struct vcm *vcm_clone(struct vcm *vcm)
+{
+	return 0;
+}
+
+
+/* No lock needed, vcm->start_addr is never updated after creation */
+size_t vcm_get_start_addr(struct vcm *vcm)
+{
+	if (!vcm) {
+		vcm_err("NULL vcm\n");
+		return 1;
+	}
+
+	return vcm->start_addr;
+}
+
+
+/* No lock needed, vcm->len is never updated after creation */
+size_t vcm_get_len(struct vcm *vcm)
+{
+	if (!vcm) {
+		vcm_err("NULL vcm\n");
+		return 0;
+	}
+
+	return vcm->len;
+}
+
+
+static int vcm_free_common_rule(struct vcm *vcm)
+{
+	int ret;
+
+	if (!vcm) {
+		vcm_err("NULL vcm\n");
+		goto fail;
+	}
+
+	ret = vcm_no_res(vcm);
+	if (!ret) {
+		vcm_err("vcm_no_res(%p) ret 0\n", vcm);
+		goto fail_busy;
+	}
+
+	if (ret == -EINVAL) {
+		vcm_err("vcm_no_res(%p) ret -EINVAL\n", vcm);
+		goto fail;
+	}
+
+	ret = vcm_no_assoc(vcm);
+	if (!ret) {
+		vcm_err("vcm_no_assoc(%p) ret 0\n", vcm);
+		goto fail_busy;
+	}
+
+	if (ret == -EINVAL) {
+		vcm_err("vcm_no_assoc(%p) ret -EINVAL\n", vcm);
+		goto fail;
+	}
+
+	return 0;
+
+fail_busy:
+	return -EBUSY;
+fail:
+	return -EINVAL;
+}
+
+
+static int vcm_free_pool_rule(struct vcm *vcm)
+{
+	if (!vcm) {
+		vcm_err("NULL vcm\n");
+		goto fail;
+	}
+
+	/* A vcm always has a valid pool, don't free the vcm because
+	   what we got is probably invalid.
+	*/
+	if (!vcm->pool) {
+		vcm_err("NULL vcm->pool\n");
+		goto fail;
+	}
+
+	return 0;
+
+fail:
+	return -EINVAL;
+}
+
+
+static void vcm_free_common(struct vcm *vcm)
+{
+	memset(vcm, 0, sizeof(*vcm));
+
+	kfree(vcm);
+}
+
+
+static int vcm_free_pool(struct vcm *vcm)
+{
+	if (!vcm) {
+		vcm_err("NULL vcm\n");
+		goto fail;
+	}
+
+	gen_pool_destroy(vcm->pool);
+
+	return 0;
+
+fail:
+	return -EINVAL;
+}
+
+
+static int __vcm_free(struct vcm *vcm)
+{
+	int ret;
+
+	if (!vcm) {
+		vcm_err("NULL vcm\n");
+		goto fail;
+	}
+
+	ret = vcm_free_common_rule(vcm);
+	if (ret != 0) {
+		vcm_err("vcm_free_common_rule(%p) ret %i\n", vcm, ret);
+		goto fail;
+	}
+
+	if (vcm->type == VCM_DEVICE) {
+		ret = vcm_free_pool_rule(vcm);
+		if (ret != 0) {
+			vcm_err("vcm_free_pool_rule(%p) ret %i\n",
+				(void *) vcm, ret);
+			goto fail;
+		}
+		if (vcm->domain)
+			iommu_domain_free(vcm->domain);
+
+		vcm->domain = NULL;
+		ret = vcm_free_pool(vcm);
+		if (ret != 0) {
+			vcm_err("vcm_free_pool(%p) ret %i", (void *) vcm, ret);
+			goto fail;
+		}
+	}
+
+	vcm_free_common(vcm);
+
+	return 0;
+
+fail:
+	return -EINVAL;
+}
+
+int vcm_free(struct vcm *vcm)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&vcmlock, flags);
+	ret = __vcm_free(vcm);
+	spin_unlock_irqrestore(&vcmlock, flags);
+
+	return ret;
+}
+
+
+static struct res *__vcm_reserve(struct vcm *vcm, size_t len, u32 attr)
+{
+	struct res *res = NULL;
+	int align_attr = 0, i = 0;
+
+	if (!vcm) {
+		vcm_err("NULL vcm\n");
+		goto fail;
+	}
+
+	if (len == 0) {
+		vcm_err("len is 0\n");
+		goto fail;
+	}
+
+	res = kzalloc(sizeof(*res), GFP_KERNEL);
+	if (!res) {
+		vcm_err("kzalloc(%i, GFP_KERNEL) ret 0", sizeof(*res));
+		goto fail;
+	}
+
+	align_attr = (attr >> VCM_ALIGN_SHIFT) & VCM_ALIGN_MASK;
+
+	if (align_attr >= 32) {
+		vcm_err("Invalid alignment attribute: %d\n", align_attr);
+		goto fail2;
+	}
+
+	INIT_LIST_HEAD(&res->res_elm);
+	res->vcm = vcm;
+	res->len = len;
+	res->attr = attr;
+	res->alignment_req = smmu_map_sizes[ARRAY_SIZE(smmu_map_sizes) - 1];
+
+	if (align_attr == 0) {
+		for (i = 0; i < ARRAY_SIZE(smmu_map_sizes); i++)
+			if (len / smmu_map_sizes[i]) {
+				res->alignment_req = smmu_map_sizes[i];
+				break;
+			}
+	} else
+		res->alignment_req = 1 << align_attr;
+
+	res->aligned_len = res->alignment_req + len;
+
+	switch (vcm->type) {
+	case VCM_DEVICE:
+		/* should always be not zero */
+		if (!vcm->pool) {
+			vcm_err("NULL vcm->pool\n");
+			goto fail2;
+		}
+
+		res->ptr = gen_pool_alloc(vcm->pool, res->aligned_len);
+		if (!res->ptr) {
+			vcm_err("gen_pool_alloc(%p, %i) ret 0\n",
+				vcm->pool, res->aligned_len);
+			goto fail2;
+		}
+
+		/* Calculate alignment... this will all change anyway */
+		res->dev_addr = res->ptr +
+			(res->alignment_req -
+			 (res->ptr & (res->alignment_req - 1)));
+
+		break;
+	case VCM_EXT_KERNEL:
+		res->vm_area = alloc_vm_area(res->aligned_len);
+		res->mapped = 0; /* be explicit */
+		if (!res->vm_area) {
+			vcm_err("NULL res->vm_area\n");
+			goto fail2;
+		}
+
+		res->dev_addr = (size_t) res->vm_area->addr +
+			(res->alignment_req -
+			 ((size_t) res->vm_area->addr &
+			  (res->alignment_req - 1)));
+
+		break;
+	case VCM_ONE_TO_ONE:
+		break;
+	default:
+		vcm_err("%i is an invalid vcm->type\n", vcm->type);
+		goto fail2;
+	}
+
+	list_add_tail(&res->res_elm, &vcm->res_head);
+
+	return res;
+
+fail2:
+	kfree(res);
+fail:
+	return 0;
+}
+
+
+struct res *vcm_reserve(struct vcm *vcm, size_t len, u32 attr)
+{
+	unsigned long flags;
+	struct res *res;
+
+	spin_lock_irqsave(&vcmlock, flags);
+	res = __vcm_reserve(vcm, len, attr);
+	spin_unlock_irqrestore(&vcmlock, flags);
+
+	return res;
+}
+
+
+struct res *vcm_reserve_at(enum memtarget_t memtarget, struct vcm *vcm,
+			   size_t len, u32 attr)
+{
+	return 0;
+}
+
+
+static int __vcm_unreserve(struct res *res)
+{
+	struct vcm *vcm;
+
+	if (!res) {
+		vcm_err("NULL res\n");
+		goto fail;
+	}
+
+	if (!res->vcm) {
+		vcm_err("NULL res->vcm\n");
+		goto fail;
+	}
+
+	vcm = res->vcm;
+	if (!vcm) {
+		vcm_err("NULL vcm\n");
+		goto fail;
+	}
+
+	switch (vcm->type) {
+	case VCM_DEVICE:
+		if (!res->vcm->pool) {
+			vcm_err("NULL (res->vcm))->pool\n");
+			goto fail;
+		}
+
+		/* res->ptr could be zero, this isn't an error */
+		gen_pool_free(res->vcm->pool, res->ptr,
+			      res->aligned_len);
+		break;
+	case VCM_EXT_KERNEL:
+		if (res->mapped) {
+			vcm_err("res->mapped is true\n");
+			goto fail;
+		}
+
+		/* This may take a little explaining.
+		 * In the kernel vunmap will free res->vm_area
+		 * so if we've called it then we shouldn't call
+		 * free_vm_area(). If we've called it we set
+		 * res->vm_area to 0.
+		 */
+		if (res->vm_area) {
+			free_vm_area(res->vm_area);
+			res->vm_area = 0;
+		}
+
+		break;
+	case VCM_ONE_TO_ONE:
+		break;
+	default:
+		vcm_err("%i is an invalid vcm->type\n", vcm->type);
+		goto fail;
+	}
+
+	list_del(&res->res_elm);
+
+	/* be extra careful by clearing the memory before freeing it */
+	memset(res, 0, sizeof(*res));
+
+	kfree(res);
+
+	return 0;
+
+fail:
+	return -EINVAL;
+}
+
+
+int vcm_unreserve(struct res *res)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&vcmlock, flags);
+	ret = __vcm_unreserve(res);
+	spin_unlock_irqrestore(&vcmlock, flags);
+
+	return ret;
+}
+
+
+/* No lock needed, res->len is never updated after creation */
+size_t vcm_get_res_len(struct res *res)
+{
+	if (!res) {
+		vcm_err("res is 0\n");
+		return 0;
+	}
+
+	return res->len;
+}
+
+
+int vcm_set_res_attr(struct res *res, u32 attr)
+{
+	return 0;
+}
+
+
+u32 vcm_get_res_attr(struct res *res)
+{
+	return 0;
+}
+
+
+size_t vcm_get_num_res(struct vcm *vcm)
+{
+	return 0;
+}
+
+
+struct res *vcm_get_next_res(struct vcm *vcm, struct res *res)
+{
+	return 0;
+}
+
+
+size_t vcm_res_copy(struct res *to, size_t to_off, struct res *from, size_t
+		    from_off, size_t len)
+{
+	return 0;
+}
+
+
+size_t vcm_get_min_page_size(void)
+{
+	return PAGE_SIZE;
+}
+
+
+static int vcm_to_smmu_attr(u32 attr)
+{
+	int smmu_attr = 0;
+
+	switch (attr & VCM_CACHE_POLICY) {
+	case VCM_NOTCACHED:
+		smmu_attr = VCM_DEV_ATTR_NONCACHED;
+		break;
+	case VCM_WB_WA:
+		smmu_attr = VCM_DEV_ATTR_CACHED_WB_WA;
+		smmu_attr |= VCM_DEV_ATTR_SH;
+		break;
+	case VCM_WB_NWA:
+		smmu_attr = VCM_DEV_ATTR_CACHED_WB_NWA;
+		smmu_attr |= VCM_DEV_ATTR_SH;
+		break;
+	case VCM_WT:
+		smmu_attr = VCM_DEV_ATTR_CACHED_WT;
+		smmu_attr |= VCM_DEV_ATTR_SH;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return smmu_attr;
+}
+
+
+static int vcm_process_chunk(struct iommu_domain *domain, phys_addr_t pa,
+			     unsigned long va, size_t len, u32 attr, int map)
+{
+	int ret, i, map_order;
+	unsigned long map_len = smmu_map_sizes[ARRAY_SIZE(smmu_map_sizes) - 1];
+
+	for (i = 0; i < ARRAY_SIZE(smmu_map_sizes); i++) {
+		if (IS_ALIGNED(va, smmu_map_sizes[i]) && len >=
+							smmu_map_sizes[i]) {
+			map_len = smmu_map_sizes[i];
+			break;
+		}
+	}
+
+#ifdef VCM_PERF_DEBUG
+	if (va & (len - 1))
+		pr_warning("Warning! Suboptimal VCM mapping alignment "
+			   "va = %p, len = %p. Expect TLB performance "
+			   "degradation.\n", (void *) va, (void *) len);
+#endif
+
+	map_order = get_order(map_len);
+
+	while (len) {
+		if (va & (SZ_4K - 1)) {
+			vcm_err("Tried to map w/ align < 4k! va = %08lx\n", va);
+			goto fail;
+		}
+
+		if (map_len > len) {
+			vcm_err("map_len = %lu, len = %d, trying to overmap\n",
+				 map_len, len);
+			goto fail;
+		}
+
+		if (map)
+			ret = iommu_map(domain, va, pa, map_len, attr);
+		else
+			ret = iommu_unmap(domain, va, map_len);
+
+		if (ret) {
+			vcm_err("iommu_map/unmap(%p, %p, %p, 0x%x, 0x%x) ret %i"
+				"map = %d", (void *) domain, (void *) pa,
+				(void *) va, (int) map_len, attr, ret, map);
+			goto fail;
+		}
+
+		va += map_len;
+		pa += map_len;
+		len -= map_len;
+	}
+
+	return 0;
+fail:
+	return -EINVAL;
+}
+
+/* TBD if you vcm_back again what happens? */
+int vcm_back(struct res *res, struct physmem *physmem)
+{
+	unsigned long flags;
+	struct vcm *vcm;
+	struct phys_chunk *chunk;
+	size_t va = 0;
+	int ret;
+	int attr;
+
+	spin_lock_irqsave(&vcmlock, flags);
+
+	if (!res) {
+		vcm_err("NULL res\n");
+		goto fail;
+	}
+
+	vcm = res->vcm;
+	if (!vcm) {
+		vcm_err("NULL vcm\n");
+		goto fail;
+	}
+
+	switch (vcm->type) {
+	case VCM_DEVICE:
+	case VCM_EXT_KERNEL: /* hack part 1 */
+		attr = vcm_to_smmu_attr(res->attr);
+		if (attr == -1) {
+			vcm_err("Bad SMMU attr\n");
+			goto fail;
+		}
+		break;
+	default:
+		attr = 0;
+		break;
+	}
+
+	if (!physmem) {
+		vcm_err("NULL physmem\n");
+		goto fail;
+	}
+
+	if (res->len == 0) {
+		vcm_err("res->len is 0\n");
+		goto fail;
+	}
+
+	if (physmem->len == 0) {
+		vcm_err("physmem->len is 0\n");
+		goto fail;
+	}
+
+	if (res->len != physmem->len) {
+		vcm_err("res->len (%i) != physmem->len (%i)\n",
+			res->len, physmem->len);
+		goto fail;
+	}
+
+	if (physmem->is_cont) {
+		if (physmem->res == 0) {
+			vcm_err("cont physmem->res is 0");
+			goto fail;
+		}
+	} else {
+		/* fail if no physmem */
+		if (list_empty(&physmem->alloc_head.allocated)) {
+			vcm_err("no allocated phys memory");
+			goto fail;
+		}
+	}
+
+	ret = vcm_no_assoc(res->vcm);
+	if (ret == 1) {
+		vcm_err("can't back un associated VCM\n");
+		goto fail;
+	}
+
+	if (ret == -1) {
+		vcm_err("vcm_no_assoc() ret -1\n");
+		goto fail;
+	}
+
+	ret = vcm_all_activated(res->vcm);
+	if (ret == 0) {
+		vcm_err("can't back, not all associations are activated\n");
+		goto fail_eagain;
+	}
+
+	if (ret == -1) {
+		vcm_err("vcm_all_activated() ret -1\n");
+		goto fail;
+	}
+
+	va = res->dev_addr;
+
+	list_for_each_entry(chunk, &physmem->alloc_head.allocated,
+			    allocated) {
+		struct vcm *vcm = res->vcm;
+		size_t chunk_size = chunk->size;
+
+		if (chunk_size <= 0) {
+			vcm_err("Bad chunk size: %d\n", chunk_size);
+			goto fail;
+		}
+
+		switch (vcm->type) {
+		case VCM_DEVICE:
+		{
+			/* map all */
+			ret = vcm_process_chunk(vcm->domain, chunk->pa,
+						va, chunk_size, attr, 1);
+			if (ret != 0) {
+				vcm_err("vcm_process_chunk(%p, %p, %p,"
+					" 0x%x, 0x%x)"
+					" ret %i",
+					vcm->domain,
+					(void *) chunk->pa,
+					(void *) va,
+					(int) chunk_size, attr, ret);
+				goto fail;
+			}
+			break;
+		}
+
+		case VCM_EXT_KERNEL:
+		{
+			unsigned int pages_in_chunk = chunk_size / PAGE_SIZE;
+			unsigned long loc_va = va;
+			unsigned long loc_pa = chunk->pa;
+
+			const struct mem_type *mtype;
+
+			/* TODO: get this based on MEMTYPE */
+			mtype = get_mem_type(MT_DEVICE);
+			if (!mtype) {
+				vcm_err("mtype is 0\n");
+				goto fail;
+			}
+
+			/* TODO: Map with the same chunk size */
+			while (pages_in_chunk--) {
+				ret = ioremap_page(loc_va,
+						   loc_pa,
+						   mtype);
+				if (ret != 0) {
+					vcm_err("ioremap_page(%p, %p, %p) ret"
+						" %i", (void *) loc_va,
+						(void *) loc_pa,
+						(void *) mtype, ret);
+					goto fail;
+					/* TODO handle weird
+					   inter-map case */
+				}
+
+				/* hack part 2 */
+				/* we're changing the PT entry behind
+				 * linux's back
+				 */
+				ret = cpu_set_attr(loc_va, PAGE_SIZE, attr);
+				if (ret != 0) {
+					vcm_err("cpu_set_attr(%p, %lu, %x)"
+						"ret %i\n",
+						(void *) loc_va, PAGE_SIZE,
+						attr, ret);
+					goto fail;
+					/* TODO handle weird
+					   inter-map case */
+				}
+
+				res->mapped = 1;
+
+				loc_va += PAGE_SIZE;
+				loc_pa += PAGE_SIZE;
+			}
+
+			flush_cache_vmap(va, loc_va);
+			break;
+		}
+		case VCM_ONE_TO_ONE:
+			va = chunk->pa;
+			break;
+		default:
+			/* this should never happen */
+			goto fail;
+		}
+
+		va += chunk_size;
+		/* also add res to the allocated chunk list of refs */
+	}
+
+	/* note the reservation */
+	res->physmem = physmem;
+
+	spin_unlock_irqrestore(&vcmlock, flags);
+	return 0;
+fail_eagain:
+	spin_unlock_irqrestore(&vcmlock, flags);
+	return -EAGAIN;
+fail:
+	spin_unlock_irqrestore(&vcmlock, flags);
+	return -EINVAL;
+}
+
+
+int vcm_unback(struct res *res)
+{
+	unsigned long flags;
+	struct vcm *vcm;
+	struct physmem *physmem;
+	int ret;
+
+	spin_lock_irqsave(&vcmlock, flags);
+
+	if (!res)
+		goto fail;
+
+	vcm = res->vcm;
+	if (!vcm) {
+		vcm_err("NULL vcm\n");
+		goto fail;
+	}
+
+	if (!res->physmem) {
+		vcm_err("can't unback a non-backed reservation\n");
+		goto fail;
+	}
+
+	physmem = res->physmem;
+	if (!physmem) {
+		vcm_err("physmem is NULL\n");
+		goto fail;
+	}
+
+	if (list_empty(&physmem->alloc_head.allocated)) {
+		vcm_err("physmem allocation is empty\n");
+		goto fail;
+	}
+
+	ret = vcm_no_assoc(res->vcm);
+	if (ret == 1) {
+		vcm_err("can't unback a unassociated reservation\n");
+		goto fail;
+	}
+
+	if (ret == -1) {
+		vcm_err("vcm_no_assoc(%p) ret -1\n", (void *) res->vcm);
+		goto fail;
+	}
+
+	ret = vcm_all_activated(res->vcm);
+	if (ret == 0) {
+		vcm_err("can't unback, not all associations are active\n");
+		goto fail_eagain;
+	}
+
+	if (ret == -1) {
+		vcm_err("vcm_all_activated(%p) ret -1\n", (void *) res->vcm);
+		goto fail;
+	}
+
+
+	switch (vcm->type) {
+	case VCM_EXT_KERNEL:
+		if (!res->mapped) {
+			vcm_err("can't unback an unmapped VCM_EXT_KERNEL"
+				" VCM\n");
+			goto fail;
+		}
+
+		/* vunmap free's vm_area */
+		vunmap(res->vm_area->addr);
+		res->vm_area = 0;
+
+		res->mapped = 0;
+		break;
+
+	case VCM_DEVICE:
+	{
+		struct phys_chunk *chunk;
+		size_t va = res->dev_addr;
+
+		list_for_each_entry(chunk, &physmem->alloc_head.allocated,
+				    allocated) {
+			struct vcm *vcm = res->vcm;
+			size_t chunk_size = chunk->size;
+
+			ret = vcm_process_chunk(vcm->domain, 0, va,
+						chunk_size, 0, 0);
+			if (ret != 0) {
+				vcm_err("vcm_unback_chunk(%p, %p, 0x%x)"
+					" ret %i",
+					(void *) vcm->domain,
+					(void *) va,
+					(int) chunk_size, ret);
+				goto fail;
+				/* TODO handle weird inter-unmap state*/
+			}
+
+			va += chunk_size;
+			/* may to a light unback, depending on the requested
+			* functionality
+			 */
+		}
+		break;
+	}
+
+	case VCM_ONE_TO_ONE:
+		break;
+	default:
+		/* this should never happen */
+		goto fail;
+	}
+
+	/* clear the reservation */
+	res->physmem = 0;
+
+	spin_unlock_irqrestore(&vcmlock, flags);
+	return 0;
+fail_eagain:
+	spin_unlock_irqrestore(&vcmlock, flags);
+	return -EAGAIN;
+fail:
+	spin_unlock_irqrestore(&vcmlock, flags);
+	return -EINVAL;
+}
+
+
+enum memtarget_t vcm_get_memtype_of_res(struct res *res)
+{
+	return VCM_INVALID;
+}
+
+static int vcm_free_max_munch_cont(struct phys_chunk *head)
+{
+	struct phys_chunk *chunk, *tmp;
+
+	if (!head)
+		return -EINVAL;
+
+	list_for_each_entry_safe(chunk, tmp, &head->allocated,
+				 allocated) {
+		list_del_init(&chunk->allocated);
+	}
+
+	return 0;
+}
+
+static int vcm_alloc_max_munch_cont(size_t start_addr, size_t len,
+				    struct phys_chunk *head)
+{
+	/* this function should always succeed, since it
+	   parallels a VCM */
+
+	int i, j;
+
+	if (!head) {
+		vcm_err("head is NULL in continuous map.\n");
+		goto fail;
+	}
+
+	if (start_addr < (int) bootmem_cont) {
+		vcm_err("phys start addr (%p) < base (%p)\n",
+			(void *) start_addr, (void *) bootmem_cont);
+		goto fail;
+	}
+
+	if ((start_addr + len) >= ((size_t) bootmem_cont + cont_sz)) {
+		vcm_err("requested region (%p + %i) > "
+			" available region (%p + %i)",
+			(void *) start_addr, (int) len,
+			(void *) bootmem_cont, cont_sz);
+		goto fail;
+	}
+
+	i = (start_addr - (size_t) bootmem_cont)/SZ_4K;
+
+	for (j = 0; j < ARRAY_SIZE(smmu_map_sizes); ++j) {
+		while (len/smmu_map_sizes[j]) {
+			if (!list_empty(&cont_phys_chunk[i].allocated)) {
+				vcm_err("chunk %i ( addr %p) already mapped\n",
+					i, (void *) (start_addr +
+						     (i*smmu_map_sizes[j])));
+				goto fail_free;
+			}
+			list_add_tail(&cont_phys_chunk[i].allocated,
+				      &head->allocated);
+			cont_phys_chunk[i].size = smmu_map_sizes[j];
+
+			len -= smmu_map_sizes[j];
+			i += smmu_map_sizes[j]/SZ_4K;
+		}
+	}
+
+	if (len % SZ_4K) {
+		if (!list_empty(&cont_phys_chunk[i].allocated)) {
+			vcm_err("chunk %i (addr %p) already mapped\n",
+				i, (void *) (start_addr + (i*SZ_4K)));
+			goto fail_free;
+		}
+		len -= SZ_4K;
+		list_add_tail(&cont_phys_chunk[i].allocated,
+			      &head->allocated);
+
+		i++;
+	}
+
+	return i;
+
+fail_free:
+	{
+		struct phys_chunk *chunk, *tmp;
+		/* just remove from list, if we're double alloc'ing
+		   we don't want to stamp on the other guy */
+		list_for_each_entry_safe(chunk, tmp, &head->allocated,
+					 allocated) {
+			list_del(&chunk->allocated);
+		}
+	}
+fail:
+	return 0;
+}
+
+struct physmem *vcm_phys_alloc(enum memtype_t memtype, size_t len, u32 attr)
+{
+	unsigned long flags;
+	int ret;
+	struct physmem *physmem = NULL;
+	int blocks_allocated;
+
+	spin_lock_irqsave(&vcmlock, flags);
+
+	physmem = kzalloc(sizeof(*physmem), GFP_KERNEL);
+	if (!physmem) {
+		vcm_err("physmem is NULL\n");
+		goto fail;
+	}
+
+	physmem->memtype = memtype;
+	physmem->len = len;
+	physmem->attr = attr;
+
+	INIT_LIST_HEAD(&physmem->alloc_head.allocated);
+
+	if (attr & VCM_PHYS_CONT) {
+		if (!cont_vcm_id) {
+			vcm_err("cont_vcm_id is NULL\n");
+			goto fail2;
+		}
+
+		physmem->is_cont = 1;
+
+		/* TODO: get attributes */
+		physmem->res = __vcm_reserve(cont_vcm_id, len, 0);
+		if (physmem->res == 0) {
+			vcm_err("contiguous space allocation failed\n");
+			goto fail2;
+		}
+
+		/* if we're here we know we have memory, create
+		   the shadow physmem links*/
+		blocks_allocated =
+			vcm_alloc_max_munch_cont(
+				physmem->res->dev_addr,
+				len,
+				&physmem->alloc_head);
+
+		if (blocks_allocated == 0) {
+			vcm_err("shadow physmem allocation failed\n");
+			goto fail3;
+		}
+	} else {
+		blocks_allocated = vcm_alloc_max_munch(len, memtype,
+						       &physmem->alloc_head);
+		if (blocks_allocated == 0) {
+			vcm_err("physical allocation failed:"
+				" vcm_alloc_max_munch(%i, %p) ret 0\n",
+				len, &physmem->alloc_head);
+			goto fail2;
+		}
+	}
+
+	spin_unlock_irqrestore(&vcmlock, flags);
+	return physmem;
+
+fail3:
+	ret = __vcm_unreserve(physmem->res);
+	if (ret != 0) {
+		vcm_err("vcm_unreserve(%p) ret %i during cleanup",
+			(void *) physmem->res, ret);
+		spin_unlock_irqrestore(&vcmlock, flags);
+		return 0;
+	}
+fail2:
+	kfree(physmem);
+fail:
+	spin_unlock_irqrestore(&vcmlock, flags);
+	return 0;
+}
+
+
+int vcm_phys_free(struct physmem *physmem)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&vcmlock, flags);
+
+	if (!physmem) {
+		vcm_err("physmem is NULL\n");
+		goto fail;
+	}
+
+	if (physmem->is_cont) {
+		if (physmem->res == 0) {
+			vcm_err("contiguous reservation is NULL\n");
+			goto fail;
+		}
+
+		ret = vcm_free_max_munch_cont(&physmem->alloc_head);
+		if (ret != 0) {
+			vcm_err("failed to free physical blocks:"
+				" vcm_free_max_munch_cont(%p) ret %i\n",
+				(void *) &physmem->alloc_head, ret);
+			goto fail;
+		}
+
+		ret = __vcm_unreserve(physmem->res);
+		if (ret != 0) {
+			vcm_err("failed to free virtual blocks:"
+				" vcm_unreserve(%p) ret %i\n",
+				(void *) physmem->res, ret);
+			goto fail;
+		}
+
+	} else {
+
+		ret = vcm_alloc_free_blocks(physmem->memtype,
+					    &physmem->alloc_head);
+		if (ret != 0) {
+			vcm_err("failed to free physical blocks:"
+				" vcm_alloc_free_blocks(%p) ret %i\n",
+				(void *) &physmem->alloc_head, ret);
+			goto fail;
+		}
+	}
+
+	memset(physmem, 0, sizeof(*physmem));
+
+	kfree(physmem);
+
+	spin_unlock_irqrestore(&vcmlock, flags);
+	return 0;
+
+fail:
+	spin_unlock_irqrestore(&vcmlock, flags);
+	return -EINVAL;
+}
+
+
+struct avcm *vcm_assoc(struct vcm *vcm, struct device *dev, u32 attr)
+{
+	unsigned long flags;
+	struct avcm *avcm = NULL;
+
+	spin_lock_irqsave(&vcmlock, flags);
+
+	if (!vcm) {
+		vcm_err("vcm is NULL\n");
+		goto fail;
+	}
+
+	if (!dev) {
+		vcm_err("dev_id is NULL\n");
+		goto fail;
+	}
+
+	if (vcm->type == VCM_EXT_KERNEL && !list_empty(&vcm->assoc_head)) {
+		vcm_err("only one device may be assocoated with a"
+			" VCM_EXT_KERNEL\n");
+		goto fail;
+	}
+
+	avcm = kzalloc(sizeof(*avcm), GFP_KERNEL);
+	if (!avcm) {
+		vcm_err("kzalloc(%i, GFP_KERNEL) ret NULL\n", sizeof(*avcm));
+		goto fail;
+	}
+
+	avcm->dev = dev;
+
+	avcm->vcm = vcm;
+	avcm->attr = attr;
+	avcm->is_active = 0;
+
+	INIT_LIST_HEAD(&avcm->assoc_elm);
+	list_add(&avcm->assoc_elm, &vcm->assoc_head);
+
+	spin_unlock_irqrestore(&vcmlock, flags);
+	return avcm;
+
+fail:
+	spin_unlock_irqrestore(&vcmlock, flags);
+	return 0;
+}
+
+
+int vcm_deassoc(struct avcm *avcm)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&vcmlock, flags);
+
+	if (!avcm) {
+		vcm_err("avcm is NULL\n");
+		goto fail;
+	}
+
+	if (list_empty(&avcm->assoc_elm)) {
+		vcm_err("nothing to deassociate\n");
+		goto fail;
+	}
+
+	if (avcm->is_active) {
+		vcm_err("association still activated\n");
+		goto fail_busy;
+	}
+
+	list_del(&avcm->assoc_elm);
+
+	memset(avcm, 0, sizeof(*avcm));
+
+	kfree(avcm);
+	spin_unlock_irqrestore(&vcmlock, flags);
+	return 0;
+fail_busy:
+	spin_unlock_irqrestore(&vcmlock, flags);
+	return -EBUSY;
+fail:
+	spin_unlock_irqrestore(&vcmlock, flags);
+	return -EINVAL;
+}
+
+
+int vcm_set_assoc_attr(struct avcm *avcm, u32 attr)
+{
+	return 0;
+}
+
+
+u32 vcm_get_assoc_attr(struct avcm *avcm)
+{
+	return 0;
+}
+
+
+int vcm_activate(struct avcm *avcm)
+{
+	unsigned long flags;
+	struct vcm *vcm;
+
+	spin_lock_irqsave(&vcmlock, flags);
+
+	if (!avcm) {
+		vcm_err("avcm is NULL\n");
+		goto fail;
+	}
+
+	vcm = avcm->vcm;
+	if (!vcm) {
+		vcm_err("NULL vcm\n");
+		goto fail;
+	}
+
+	if (!avcm->dev) {
+		vcm_err("cannot activate without a device\n");
+		goto fail_nodev;
+	}
+
+	if (avcm->is_active) {
+		vcm_err("double activate\n");
+		goto fail_busy;
+	}
+
+	if (vcm->type == VCM_DEVICE) {
+#ifdef CONFIG_SMMU
+		int ret;
+		ret = iommu_attach_device(vcm->domain, avcm->dev);
+		if (ret != 0) {
+			dev_err(avcm->dev, "failed to attach to domain\n");
+			goto fail_dev;
+		}
+#else
+		vcm_err("No SMMU support - cannot activate/deactivate\n");
+		goto fail_nodev;
+#endif
+	}
+
+	avcm->is_active = 1;
+	spin_unlock_irqrestore(&vcmlock, flags);
+	return 0;
+
+#ifdef CONFIG_SMMU
+fail_dev:
+	spin_unlock_irqrestore(&vcmlock, flags);
+	return -ENODEV;
+#endif
+fail_busy:
+	spin_unlock_irqrestore(&vcmlock, flags);
+	return -EBUSY;
+fail_nodev:
+	spin_unlock_irqrestore(&vcmlock, flags);
+	return -ENODEV;
+fail:
+	spin_unlock_irqrestore(&vcmlock, flags);
+	return -EINVAL;
+}
+
+
+int vcm_deactivate(struct avcm *avcm)
+{
+	unsigned long flags;
+	struct vcm *vcm;
+
+	spin_lock_irqsave(&vcmlock, flags);
+
+	if (!avcm)
+		goto fail;
+
+	vcm = avcm->vcm;
+	if (!vcm) {
+		vcm_err("NULL vcm\n");
+		goto fail;
+	}
+
+	if (!avcm->dev) {
+		vcm_err("cannot deactivate without a device\n");
+		goto fail;
+	}
+
+	if (!avcm->is_active) {
+		vcm_err("double deactivate\n");
+		goto fail_nobusy;
+	}
+
+	if (vcm->type == VCM_DEVICE) {
+#ifdef CONFIG_SMMU
+		/* TODO, pmem check */
+		iommu_detach_device(vcm->domain, avcm->dev);
+#else
+		vcm_err("No SMMU support - cannot activate/deactivate\n");
+		goto fail;
+#endif
+	}
+
+	avcm->is_active = 0;
+	spin_unlock_irqrestore(&vcmlock, flags);
+	return 0;
+fail_nobusy:
+	spin_unlock_irqrestore(&vcmlock, flags);
+	return -ENOENT;
+fail:
+	spin_unlock_irqrestore(&vcmlock, flags);
+	return -EINVAL;
+}
+
+struct bound *vcm_create_bound(struct vcm *vcm, size_t len)
+{
+	return 0;
+}
+
+
+int vcm_free_bound(struct bound *bound)
+{
+	return -EINVAL;
+}
+
+
+struct res *vcm_reserve_from_bound(struct bound *bound, size_t len,
+				   u32 attr)
+{
+	return 0;
+}
+
+
+size_t vcm_get_bound_start_addr(struct bound *bound)
+{
+	return 0;
+}
+
+
+size_t vcm_get_bound_len(struct bound *bound)
+{
+	return 0;
+}
+
+
+struct physmem *vcm_map_phys_addr(phys_addr_t phys, size_t len)
+{
+	return 0;
+}
+
+
+size_t vcm_get_next_phys_addr(struct physmem *physmem, phys_addr_t phys,
+			      size_t *len)
+{
+	return 0;
+}
+
+
+struct res *vcm_get_res(unsigned long dev_addr, struct vcm *vcm)
+{
+	return 0;
+}
+
+
+size_t vcm_translate(struct device *src_dev, struct vcm *src_vcm,
+		     struct vcm *dst_vcm)
+{
+	return 0;
+}
+
+
+size_t vcm_get_phys_num_res(phys_addr_t phys)
+{
+	return 0;
+}
+
+
+struct res *vcm_get_next_phys_res(phys_addr_t phys, struct res *res,
+				  size_t *len)
+{
+	return 0;
+}
+
+
+phys_addr_t vcm_get_pgtbl_pa(struct vcm *vcm)
+{
+	return 0;
+}
+
+
+/* No lock needed, smmu_translate has its own lock */
+phys_addr_t vcm_dev_addr_to_phys_addr(struct vcm *vcm, unsigned long dev_addr)
+{
+	if (!vcm)
+		return -EINVAL;
+#ifdef CONFIG_SMMU
+	return iommu_iova_to_phys(vcm->domain, dev_addr);
+#else
+	vcm_err("No support for SMMU - manual translation not supported\n");
+	return -ENODEV;
+#endif
+}
+
+
+/* No lock needed, bootmem_cont never changes after  */
+phys_addr_t vcm_get_cont_memtype_pa(enum memtype_t memtype)
+{
+	if (memtype != VCM_MEMTYPE_0) {
+		vcm_err("memtype != VCM_MEMTYPE_0\n");
+		goto fail;
+	}
+
+	if (!bootmem_cont) {
+		vcm_err("bootmem_cont 0\n");
+		goto fail;
+	}
+
+	return (size_t) bootmem_cont;
+fail:
+	return 0;
+}
+
+
+/* No lock needed, constant */
+size_t vcm_get_cont_memtype_len(enum memtype_t memtype)
+{
+	if (memtype != VCM_MEMTYPE_0) {
+		vcm_err("memtype != VCM_MEMTYPE_0\n");
+		return 0;
+	}
+
+	return cont_sz;
+}
+
+int vcm_hook(struct device *dev, vcm_handler handler, void *data)
+{
+#ifdef CONFIG_SMMU
+	vcm_err("No interrupts in IOMMU API\n");
+	return -ENODEV;
+#else
+	vcm_err("No support for SMMU - interrupts not supported\n");
+	return -ENODEV;
+#endif
+}
+
+
+size_t vcm_hw_ver(size_t dev)
+{
+	return 0;
+}
+
+
+static int vcm_cont_phys_chunk_init(void)
+{
+	int i;
+	int cont_pa;
+
+	if (!cont_phys_chunk) {
+		vcm_err("cont_phys_chunk 0\n");
+		goto fail;
+	}
+
+	if (!bootmem_cont) {
+		vcm_err("bootmem_cont 0\n");
+		goto fail;
+	}
+
+	cont_pa = (size_t) bootmem_cont;
+
+	for (i = 0; i < cont_sz/PAGE_SIZE; ++i) {
+		cont_phys_chunk[i].pa = cont_pa; cont_pa += PAGE_SIZE;
+		cont_phys_chunk[i].size = SZ_4K;
+		/* Not part of an allocator-managed pool */
+		cont_phys_chunk[i].pool_idx = -1;
+		INIT_LIST_HEAD(&cont_phys_chunk[i].allocated);
+	}
+
+	return 0;
+
+fail:
+	return -EINVAL;
+}
+
+int vcm_sys_init(struct physmem_region *mem, int n_regions,
+		 struct vcm_memtype_map *mt_map, int n_mt,
+		 void *cont_pa, unsigned int cont_len)
+{
+	int ret;
+	printk(KERN_INFO "VCM Initialization\n");
+	bootmem_cont = cont_pa;
+	cont_sz = cont_len;
+
+	if (!bootmem_cont) {
+		vcm_err("bootmem_cont is 0\n");
+		ret = -1;
+		goto fail;
+	}
+
+	ret = vcm_setup_tex_classes();
+	if (ret != 0) {
+		printk(KERN_INFO "Could not determine TEX attribute mapping\n");
+		ret = -1;
+		goto fail;
+	}
+
+
+	ret = vcm_alloc_init(mem, n_regions, mt_map, n_mt);
+
+	if (ret != 0) {
+		vcm_err("vcm_alloc_init() ret %i\n", ret);
+		ret = -1;
+		goto fail;
+	}
+
+	cont_phys_chunk = kzalloc(sizeof(*cont_phys_chunk)*(cont_sz/PAGE_SIZE),
+				  GFP_KERNEL);
+	if (!cont_phys_chunk) {
+		vcm_err("kzalloc(%lu, GFP_KERNEL) ret 0",
+			sizeof(*cont_phys_chunk)*(cont_sz/PAGE_SIZE));
+		goto fail_free;
+	}
+
+	/* the address and size will hit our special case unless we
+	   pass an override */
+	cont_vcm_id = vcm_create_flagged(0, (size_t)bootmem_cont, cont_sz);
+	if (cont_vcm_id == 0) {
+		vcm_err("vcm_create_flagged(0, %p, %i) ret 0\n",
+			bootmem_cont, cont_sz);
+		ret = -1;
+		goto fail_free2;
+	}
+
+	ret = vcm_cont_phys_chunk_init();
+	if (ret != 0) {
+		vcm_err("vcm_cont_phys_chunk_init() ret %i\n", ret);
+		goto fail_free3;
+	}
+
+	printk(KERN_INFO "VCM Initialization OK\n");
+	return 0;
+
+fail_free3:
+	ret = __vcm_free(cont_vcm_id);
+	if (ret != 0) {
+		vcm_err("vcm_free(%p) ret %i during failure path\n",
+			(void *) cont_vcm_id, ret);
+		return ret;
+	}
+
+fail_free2:
+	kfree(cont_phys_chunk);
+	cont_phys_chunk = 0;
+
+fail_free:
+	ret = vcm_alloc_destroy();
+	if (ret != 0)
+		vcm_err("vcm_alloc_destroy() ret %i during failure path\n",
+			ret);
+
+	ret = -EINVAL;
+fail:
+	return ret;
+}
+
+
+int vcm_sys_destroy(void)
+{
+	int ret = 0;
+
+	if (!cont_phys_chunk) {
+		vcm_err("cont_phys_chunk is 0\n");
+		return -ENODEV;
+	}
+
+	if (!cont_vcm_id) {
+		vcm_err("cont_vcm_id is 0\n");
+		return -ENODEV;
+	}
+
+	ret = __vcm_free(cont_vcm_id);
+	if (ret != 0) {
+		vcm_err("vcm_free(%p) ret %i\n", (void *) cont_vcm_id, ret);
+		return -ENODEV;
+	}
+
+	cont_vcm_id = 0;
+
+	kfree(cont_phys_chunk);
+	cont_phys_chunk = 0;
+
+	ret = vcm_alloc_destroy();
+	if (ret != 0) {
+		vcm_err("vcm_alloc_destroy() ret %i\n", ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Zach Pfeffer <zpfeffer@codeaurora.org>");
diff --git a/arch/arm/mm/vcm_alloc.c b/arch/arm/mm/vcm_alloc.c
new file mode 100644
index 0000000..5f3c024
--- /dev/null
+++ b/arch/arm/mm/vcm_alloc.c
@@ -0,0 +1,557 @@
+/* Copyright (c) 2010, 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/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/vcm.h>
+#include <linux/vcm_alloc.h>
+#include <linux/string.h>
+#include <asm/sizes.h>
+
+int basicalloc_init;
+
+#define vcm_alloc_err(a, ...)						\
+	pr_err("ERROR %s %i " a, __func__, __LINE__, ##__VA_ARGS__)
+
+struct phys_chunk_head {
+	struct list_head head;
+	int num;
+};
+
+struct phys_pool {
+	int size;
+	int chunk_size;
+	struct phys_chunk_head head;
+};
+
+static int vcm_num_phys_pools;
+static int vcm_num_memtypes;
+static struct phys_pool *vcm_phys_pool;
+static struct vcm_memtype_map *memtype_map;
+
+static int num_pools(enum memtype_t memtype)
+{
+	if (memtype >= vcm_num_memtypes) {
+		vcm_alloc_err("Bad memtype: %d\n", memtype);
+		return -EINVAL;
+	}
+	return memtype_map[memtype].num_pools;
+}
+
+static int pool_chunk_size(enum memtype_t memtype, int prio_idx)
+{
+	int pool_idx;
+	if (memtype >= vcm_num_memtypes) {
+		vcm_alloc_err("Bad memtype: %d\n", memtype);
+		return -EINVAL;
+	}
+
+	if (prio_idx >= num_pools(memtype)) {
+		vcm_alloc_err("Bad prio index: %d, max=%d, mt=%d\n", prio_idx,
+			      num_pools(memtype), memtype);
+		return -EINVAL;
+	}
+
+	pool_idx = memtype_map[memtype].pool_id[prio_idx];
+	return vcm_phys_pool[pool_idx].chunk_size;
+}
+
+int vcm_alloc_pool_idx_to_size(int pool_idx)
+{
+	if (pool_idx >= vcm_num_phys_pools) {
+		vcm_alloc_err("Bad pool index: %d\n, max=%d\n", pool_idx,
+			      vcm_num_phys_pools);
+		return -EINVAL;
+	}
+	return vcm_phys_pool[pool_idx].chunk_size;
+}
+
+static struct phys_chunk_head *get_chunk_list(enum memtype_t memtype,
+					      int prio_idx)
+{
+	unsigned int pool_idx;
+
+	if (memtype >= vcm_num_memtypes) {
+		vcm_alloc_err("Bad memtype: %d\n", memtype);
+		return NULL;
+	}
+
+	if (prio_idx >= num_pools(memtype)) {
+		vcm_alloc_err("bad chunk size: mt=%d, prioidx=%d, np=%d\n",
+			      memtype, prio_idx, num_pools(memtype));
+		BUG();
+		return NULL;
+	}
+
+	if (!vcm_phys_pool) {
+		vcm_alloc_err("phys_pool is null\n");
+		return NULL;
+	}
+
+	/* We don't have a "pool count" anywhere but this is coming
+	 * strictly from data in a board file
+	 */
+	pool_idx = memtype_map[memtype].pool_id[prio_idx];
+
+	return &vcm_phys_pool[pool_idx].head;
+}
+
+static int is_allocated(struct list_head *allocated)
+{
+	/* This should not happen under normal conditions */
+	if (!allocated) {
+		vcm_alloc_err("no allocated\n");
+		return 0;
+	}
+
+	if (!basicalloc_init) {
+		vcm_alloc_err("no basicalloc_init\n");
+		return 0;
+	}
+	return !list_empty(allocated);
+}
+
+static int count_allocated_size(enum memtype_t memtype, int idx)
+{
+	int cnt = 0;
+	struct phys_chunk *chunk, *tmp;
+	struct phys_chunk_head *pch;
+
+	if (!basicalloc_init) {
+		vcm_alloc_err("no basicalloc_init\n");
+		return 0;
+	}
+
+	pch = get_chunk_list(memtype, idx);
+	if (!pch) {
+		vcm_alloc_err("null pch\n");
+		return -EINVAL;
+	}
+
+	list_for_each_entry_safe(chunk, tmp, &pch->head, list) {
+		if (is_allocated(&chunk->allocated))
+			cnt++;
+	}
+
+	return cnt;
+}
+
+
+int vcm_alloc_get_mem_size(void)
+{
+	if (!vcm_phys_pool) {
+		vcm_alloc_err("No physical pool set up!\n");
+		return -ENODEV;
+	}
+	return vcm_phys_pool[0].size;
+}
+EXPORT_SYMBOL(vcm_alloc_get_mem_size);
+
+void vcm_alloc_print_list(enum memtype_t memtype, int just_allocated)
+{
+	int i;
+	struct phys_chunk *chunk, *tmp;
+	struct phys_chunk_head *pch;
+
+	if (!basicalloc_init) {
+		vcm_alloc_err("no basicalloc_init\n");
+		return;
+	}
+
+	for (i = 0; i < num_pools(memtype); ++i) {
+		pch = get_chunk_list(memtype, i);
+
+		if (!pch) {
+			vcm_alloc_err("pch is null\n");
+			return;
+		}
+
+		if (list_empty(&pch->head))
+			continue;
+
+		list_for_each_entry_safe(chunk, tmp, &pch->head, list) {
+			if (just_allocated && !is_allocated(&chunk->allocated))
+				continue;
+
+			printk(KERN_INFO "pa = %#x, size = %#x\n",
+			chunk->pa, vcm_phys_pool[chunk->pool_idx].chunk_size);
+		}
+	}
+}
+EXPORT_SYMBOL(vcm_alloc_print_list);
+
+int vcm_alloc_blocks_avail(enum memtype_t memtype, int idx)
+{
+	struct phys_chunk_head *pch;
+	if (!basicalloc_init) {
+		vcm_alloc_err("no basicalloc_init\n");
+		return 0;
+	}
+	pch = get_chunk_list(memtype, idx);
+
+	if (!pch) {
+		vcm_alloc_err("pch is null\n");
+		return 0;
+	}
+	return pch->num;
+}
+EXPORT_SYMBOL(vcm_alloc_blocks_avail);
+
+
+int vcm_alloc_get_num_chunks(enum memtype_t memtype)
+{
+	return num_pools(memtype);
+}
+EXPORT_SYMBOL(vcm_alloc_get_num_chunks);
+
+
+int vcm_alloc_all_blocks_avail(enum memtarget_t memtype)
+{
+	int i;
+	int cnt = 0;
+
+	if (!basicalloc_init) {
+		vcm_alloc_err("no basicalloc_init\n");
+		return 0;
+	}
+
+	for (i = 0; i < num_pools(memtype); ++i)
+		cnt += vcm_alloc_blocks_avail(memtype, i);
+	return cnt;
+}
+EXPORT_SYMBOL(vcm_alloc_all_blocks_avail);
+
+
+int vcm_alloc_count_allocated(enum memtype_t memtype)
+{
+	int i;
+	int cnt = 0;
+
+	if (!basicalloc_init) {
+		vcm_alloc_err("no basicalloc_init\n");
+		return 0;
+	}
+
+	for (i = 0; i < num_pools(memtype); ++i)
+		cnt += count_allocated_size(memtype, i);
+	return cnt;
+}
+EXPORT_SYMBOL(vcm_alloc_count_allocated);
+
+int vcm_alloc_destroy(void)
+{
+	int i, mt;
+	struct phys_chunk *chunk, *tmp;
+
+	if (!basicalloc_init) {
+		vcm_alloc_err("no basicalloc_init\n");
+		return -ENODEV;
+	}
+
+	/* can't destroy a space that has allocations */
+	for (mt = 0; mt < vcm_num_memtypes; mt++)
+		if (vcm_alloc_count_allocated(mt)) {
+			vcm_alloc_err("allocations still present\n");
+			return -EBUSY;
+		}
+
+	for (i = 0; i < vcm_num_phys_pools; i++) {
+		struct phys_chunk_head *pch = &vcm_phys_pool[i].head;
+
+		if (list_empty(&pch->head))
+			continue;
+		list_for_each_entry_safe(chunk, tmp, &pch->head, list) {
+			list_del(&chunk->list);
+			memset(chunk, 0, sizeof(*chunk));
+			kfree(chunk);
+		}
+		vcm_phys_pool[i].head.num = 0;
+	}
+
+	kfree(vcm_phys_pool);
+	kfree(memtype_map);
+
+	vcm_phys_pool = NULL;
+	memtype_map = NULL;
+	basicalloc_init = 0;
+	vcm_num_phys_pools = 0;
+	return 0;
+}
+EXPORT_SYMBOL(vcm_alloc_destroy);
+
+
+int vcm_alloc_init(struct physmem_region *mem, int n_regions,
+		   struct vcm_memtype_map *mt_map, int n_mt)
+{
+	int i = 0, j = 0, r = 0, num_chunks;
+	struct phys_chunk *chunk;
+	struct phys_chunk_head *pch = NULL;
+	unsigned long pa;
+
+	/* no double inits */
+	if (basicalloc_init) {
+		vcm_alloc_err("double basicalloc_init\n");
+		BUG();
+		goto fail;
+	}
+	memtype_map = kzalloc(sizeof(*mt_map) * n_mt, GFP_KERNEL);
+	if (!memtype_map) {
+		vcm_alloc_err("Could not copy memtype map\n");
+		goto fail;
+	}
+	memcpy(memtype_map, mt_map, sizeof(*mt_map) * n_mt);
+
+	vcm_phys_pool = kzalloc(sizeof(*vcm_phys_pool) * n_regions, GFP_KERNEL);
+	vcm_num_phys_pools = n_regions;
+	vcm_num_memtypes = n_mt;
+
+	if (!vcm_phys_pool) {
+		vcm_alloc_err("Could not allocate physical pool structure\n");
+		goto fail;
+	}
+
+	/* separate out to ensure good cleanup */
+	for (i = 0; i < n_regions; i++) {
+		pch = &vcm_phys_pool[i].head;
+		INIT_LIST_HEAD(&pch->head);
+		pch->num = 0;
+	}
+
+	for (r = 0; r < n_regions; r++) {
+		pa = mem[r].addr;
+		vcm_phys_pool[r].size = mem[r].size;
+		vcm_phys_pool[r].chunk_size = mem[r].chunk_size;
+		pch = &vcm_phys_pool[r].head;
+
+		num_chunks = mem[r].size / mem[r].chunk_size;
+
+		printk(KERN_INFO "VCM Init: region %d, chunk size=%d, "
+		       "num=%d, pa=%p\n", r, mem[r].chunk_size, num_chunks,
+		       (void *)pa);
+
+		for (j = 0; j < num_chunks; ++j) {
+			chunk = kzalloc(sizeof(*chunk), GFP_KERNEL);
+			if (!chunk) {
+				vcm_alloc_err("null chunk\n");
+				goto fail;
+			}
+			chunk->pa = pa;
+			chunk->size = mem[r].chunk_size;
+			pa += mem[r].chunk_size;
+			chunk->pool_idx = r;
+			INIT_LIST_HEAD(&chunk->allocated);
+			list_add_tail(&chunk->list, &pch->head);
+			pch->num++;
+		}
+	}
+
+	basicalloc_init = 1;
+	return 0;
+fail:
+	vcm_alloc_destroy();
+	return -EINVAL;
+}
+EXPORT_SYMBOL(vcm_alloc_init);
+
+
+int vcm_alloc_free_blocks(enum memtype_t memtype, struct phys_chunk *alloc_head)
+{
+	struct phys_chunk *chunk, *tmp;
+	struct phys_chunk_head *pch = NULL;
+
+	if (!basicalloc_init) {
+		vcm_alloc_err("no basicalloc_init\n");
+		goto fail;
+	}
+
+	if (!alloc_head) {
+		vcm_alloc_err("no alloc_head\n");
+		goto fail;
+	}
+
+	list_for_each_entry_safe(chunk, tmp, &alloc_head->allocated,
+				 allocated) {
+		list_del_init(&chunk->allocated);
+		pch = &vcm_phys_pool[chunk->pool_idx].head;
+
+		if (!pch) {
+			vcm_alloc_err("null pch\n");
+			goto fail;
+		}
+		pch->num++;
+	}
+
+	return 0;
+fail:
+	return -ENODEV;
+}
+EXPORT_SYMBOL(vcm_alloc_free_blocks);
+
+
+int vcm_alloc_num_blocks(int num, enum memtype_t memtype, int idx,
+			 struct phys_chunk *alloc_head)
+{
+	struct phys_chunk *chunk;
+	struct phys_chunk_head *pch = NULL;
+	int num_allocated = 0;
+
+	if (!basicalloc_init) {
+		vcm_alloc_err("no basicalloc_init\n");
+		goto fail;
+	}
+
+	if (!alloc_head) {
+		vcm_alloc_err("no alloc_head\n");
+		goto fail;
+	}
+
+	pch = get_chunk_list(memtype, idx);
+
+	if (!pch) {
+		vcm_alloc_err("null pch\n");
+		goto fail;
+	}
+	if (list_empty(&pch->head)) {
+		vcm_alloc_err("list is empty\n");
+		goto fail;
+	}
+
+	if (vcm_alloc_blocks_avail(memtype, idx) < num) {
+		vcm_alloc_err("not enough blocks? num=%d\n", num);
+		goto fail;
+	}
+
+	list_for_each_entry(chunk, &pch->head, list) {
+		if (num_allocated == num)
+			break;
+		if (is_allocated(&chunk->allocated))
+			continue;
+
+		list_add_tail(&chunk->allocated, &alloc_head->allocated);
+		pch->num--;
+		num_allocated++;
+	}
+	return num_allocated;
+fail:
+	return 0;
+}
+EXPORT_SYMBOL(vcm_alloc_num_blocks);
+
+
+int vcm_alloc_max_munch(int len, enum memtype_t memtype,
+			struct phys_chunk *alloc_head)
+{
+	int i;
+
+	int blocks_req = 0;
+	int block_residual = 0;
+	int blocks_allocated = 0;
+	int cur_chunk_size = 0;
+	int ba = 0;
+
+	if (!basicalloc_init) {
+		vcm_alloc_err("basicalloc_init is 0\n");
+		goto fail;
+	}
+
+	if (!alloc_head) {
+		vcm_alloc_err("alloc_head is NULL\n");
+		goto fail;
+	}
+
+	if (num_pools(memtype) <= 0) {
+		vcm_alloc_err("Memtype %d has improper mempool configuration\n",
+			      memtype);
+		goto fail;
+	}
+
+	for (i = 0; i < num_pools(memtype); ++i) {
+		cur_chunk_size = pool_chunk_size(memtype, i);
+		if (cur_chunk_size <= 0) {
+			vcm_alloc_err("Bad chunk size: %d\n", cur_chunk_size);
+			goto fail;
+		}
+
+		blocks_req = len / cur_chunk_size;
+		block_residual = len % cur_chunk_size;
+
+		len = block_residual; /* len left */
+		if (blocks_req) {
+			int blocks_available = 0;
+			int blocks_diff = 0;
+			int bytes_diff = 0;
+
+			blocks_available = vcm_alloc_blocks_avail(memtype, i);
+			if (blocks_available < blocks_req) {
+				blocks_diff =
+					(blocks_req - blocks_available);
+				bytes_diff =
+					blocks_diff * cur_chunk_size;
+
+				/* add back in the rest */
+				len += bytes_diff;
+			} else {
+				/* got all the blocks I need */
+				blocks_available =
+					(blocks_available > blocks_req)
+					? blocks_req : blocks_available;
+			}
+
+			ba = vcm_alloc_num_blocks(blocks_available, memtype, i,
+						  alloc_head);
+
+			if (ba != blocks_available) {
+				vcm_alloc_err("blocks allocated (%i) !="
+					      " blocks_available (%i):"
+					      " chunk size = %#x,"
+					      " alloc_head = %p\n",
+					      ba, blocks_available,
+					      i, (void *) alloc_head);
+				goto fail;
+			}
+			blocks_allocated += blocks_available;
+		}
+	}
+
+	if (len) {
+		int blocks_available = 0;
+		int last_sz = num_pools(memtype) - 1;
+		blocks_available = vcm_alloc_blocks_avail(memtype, last_sz);
+
+		if (blocks_available > 0) {
+			ba = vcm_alloc_num_blocks(1, memtype, last_sz,
+						  alloc_head);
+			if (ba != 1) {
+				vcm_alloc_err("blocks allocated (%i) !="
+					      " blocks_available (%i):"
+					      " chunk size = %#x,"
+					      " alloc_head = %p\n",
+					      ba, 1,
+					      last_sz,
+					      (void *) alloc_head);
+				goto fail;
+			}
+			blocks_allocated += 1;
+		} else {
+			vcm_alloc_err("blocks_available (%#x) <= 1\n",
+				      blocks_available);
+			goto fail;
+		}
+	}
+
+	return blocks_allocated;
+fail:
+	vcm_alloc_free_blocks(memtype, alloc_head);
+	return 0;
+}
+EXPORT_SYMBOL(vcm_alloc_max_munch);
diff --git a/arch/arm/mm/vcm_mm.c b/arch/arm/mm/vcm_mm.c
new file mode 100644
index 0000000..dee51fa
--- /dev/null
+++ b/arch/arm/mm/vcm_mm.c
@@ -0,0 +1,253 @@
+/* Copyright (c) 2010, 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.
+ */
+
+/* Architecture-specific VCM functions */
+
+#include <linux/kernel.h>
+#include <linux/vcm_mm.h>
+
+#include <asm/pgtable-hwdef.h>
+#include <asm/tlbflush.h>
+
+#define MRC(reg, processor, op1, crn, crm, op2)				\
+__asm__ __volatile__ (							\
+"   mrc   "   #processor "," #op1 ", %0,"  #crn "," #crm "," #op2 " \n" \
+: "=r" (reg))
+
+#define RCP15_PRRR(reg)		MRC(reg, p15, 0, c10, c2, 0)
+#define RCP15_NMRR(reg) 	MRC(reg, p15, 0, c10, c2, 1)
+
+
+/* Local type attributes (not the same as VCM) */
+#define ARM_MT_NORMAL		2
+#define ARM_MT_STRONGLYORDERED	0
+#define ARM_MT_DEVICE		1
+
+#define ARM_CP_NONCACHED	0
+#define ARM_CP_WB_WA		1
+#define ARM_CP_WB_NWA		3
+#define ARM_CP_WT_NWA		2
+
+#define smmu_err(a, ...)						\
+	pr_err("ERROR %s %i " a, __func__, __LINE__, ##__VA_ARGS__)
+
+#define FL_OFFSET(va)	(((va) & 0xFFF00000) >> 20)
+#define SL_OFFSET(va)	(((va) & 0xFF000) >> 12)
+
+int vcm_driver_tex_class[4];
+
+static int find_tex_class(int icp, int ocp, int mt, int nos)
+{
+	int i = 0;
+	unsigned int prrr = 0;
+	unsigned int nmrr = 0;
+	int c_icp, c_ocp, c_mt, c_nos;
+
+	RCP15_PRRR(prrr);
+	RCP15_NMRR(nmrr);
+
+	/* There are only 8 classes on this architecture */
+	/* If they add more classes, registers will VASTLY change */
+	for (i = 0; i < 8; i++)	{
+		c_nos = prrr & (1 << (i + 24)) ? 1 : 0;
+		c_mt = (prrr & (3 << (i * 2))) >> (i * 2);
+		c_icp = (nmrr & (3 << (i * 2))) >> (i * 2);
+		c_ocp = (nmrr & (3 << (i * 2 + 16))) >> (i * 2 + 16);
+
+		if (icp == c_icp && ocp == c_ocp && c_mt == mt && c_nos == nos)
+			return i;
+	}
+	smmu_err("Could not find TEX class for ICP=%d, OCP=%d, MT=%d, NOS=%d\n",
+		 icp, ocp, mt, nos);
+
+	/* In reality, we may want to remove this panic. Some classes just */
+	/* will not be available, and will fail in smmu_set_attr */
+	panic("SMMU: Could not determine TEX attribute mapping.\n");
+	return -1;
+}
+
+
+int vcm_setup_tex_classes(void)
+{
+	unsigned int cpu_prrr;
+	unsigned int cpu_nmrr;
+
+	if (!(get_cr() & CR_TRE))	/* No TRE? */
+		panic("TEX remap not enabled, but the SMMU driver needs it!\n");
+
+	RCP15_PRRR(cpu_prrr);
+	RCP15_NMRR(cpu_nmrr);
+
+	vcm_driver_tex_class[VCM_DEV_ATTR_NONCACHED] =
+		find_tex_class(ARM_CP_NONCACHED, ARM_CP_NONCACHED,
+			       ARM_MT_NORMAL, 1);
+
+	vcm_driver_tex_class[VCM_DEV_ATTR_CACHED_WB_WA] =
+		find_tex_class(ARM_CP_WB_WA, ARM_CP_WB_WA,
+			       ARM_MT_NORMAL, 1);
+
+	vcm_driver_tex_class[VCM_DEV_ATTR_CACHED_WB_NWA] =
+		find_tex_class(ARM_CP_WB_NWA, ARM_CP_WB_NWA,
+			       ARM_MT_NORMAL, 1);
+
+	vcm_driver_tex_class[VCM_DEV_ATTR_CACHED_WT] =
+		find_tex_class(ARM_CP_WT_NWA, ARM_CP_WT_NWA,
+			       ARM_MT_NORMAL, 1);
+#ifdef DEBUG_TEX
+	printk(KERN_INFO "VCM driver debug: Using TEX classes: %d %d %d %d\n",
+	       vcm_driver_tex_class[VCM_DEV_ATTR_NONCACHED],
+	       vcm_driver_tex_class[VCM_DEV_ATTR_CACHED_WB_WA],
+	       vcm_driver_tex_class[VCM_DEV_ATTR_CACHED_WB_NWA],
+	       vcm_driver_tex_class[VCM_DEV_ATTR_CACHED_WT]);
+#endif
+	return 0;
+}
+
+
+int set_arm7_pte_attr(unsigned long pt_base, unsigned long va,
+					unsigned long len, unsigned int attr)
+{
+	unsigned long *fl_table = NULL;
+	unsigned long *fl_pte = NULL;
+	unsigned long fl_offset = 0;
+	unsigned long *sl_table = NULL;
+	unsigned long *sl_pte = NULL;
+	unsigned long sl_offset = 0;
+	int i;
+	int sh = 0;
+	int class = 0;
+
+	/* Alignment */
+	if (va & (len-1)) {
+		smmu_err("misaligned va: %p\n", (void *) va);
+		goto fail;
+	}
+	if (attr > 7) {
+		smmu_err("bad attribute: %d\n", attr);
+		goto fail;
+	}
+
+	sh = (attr & VCM_DEV_ATTR_SH) ? 1 : 0;
+	class = vcm_driver_tex_class[attr & 0x03];
+
+	if (class > 7 || class < 0) {	/* Bad class */
+		smmu_err("bad tex class: %d\n", class);
+		goto fail;
+	}
+
+	if (len != SZ_16M && len != SZ_1M &&
+	    len != SZ_64K && len != SZ_4K) {
+		smmu_err("bad size: %lu\n", len);
+		goto fail;
+	}
+
+	fl_table = (unsigned long *) pt_base;
+
+	if (!fl_table) {
+		smmu_err("null page table\n");
+		goto fail;
+	}
+
+	fl_offset = FL_OFFSET(va);	/* Upper 12 bits */
+	fl_pte = fl_table + fl_offset;	/* int pointers, 4 bytes */
+
+	if (*fl_pte == 0) {	/* Nothing there! */
+		smmu_err("first level pte is 0\n");
+		goto fail;
+	}
+
+	/* Supersection attributes */
+	if (len == SZ_16M) {
+		for (i = 0; i < 16; i++) {
+			/* Clear the old bits */
+			*(fl_pte+i) &= ~(PMD_SECT_S | PMD_SECT_CACHEABLE |
+					 PMD_SECT_BUFFERABLE | PMD_SECT_TEX(1));
+
+			/* Assign new class and S bit */
+			*(fl_pte+i) |= sh ? PMD_SECT_S : 0;
+			*(fl_pte+i) |= class & 0x01 ? PMD_SECT_BUFFERABLE : 0;
+			*(fl_pte+i) |= class & 0x02 ? PMD_SECT_CACHEABLE : 0;
+			*(fl_pte+i) |= class & 0x04 ? PMD_SECT_TEX(1) : 0;
+		}
+	} else	if (len == SZ_1M) {
+
+		/* Clear the old bits */
+		*(fl_pte) &= ~(PMD_SECT_S | PMD_SECT_CACHEABLE |
+			       PMD_SECT_BUFFERABLE | PMD_SECT_TEX(1));
+
+		/* Assign new class and S bit */
+		*(fl_pte) |= sh ? PMD_SECT_S : 0;
+		*(fl_pte) |= class & 0x01 ? PMD_SECT_BUFFERABLE : 0;
+		*(fl_pte) |= class & 0x02 ? PMD_SECT_CACHEABLE : 0;
+		*(fl_pte) |= class & 0x04 ? PMD_SECT_TEX(1) : 0;
+	}
+
+	sl_table = (unsigned long *) __va(((*fl_pte) & 0xFFFFFC00));
+	sl_offset = SL_OFFSET(va);
+	sl_pte = sl_table + sl_offset;
+
+	if (len == SZ_64K) {
+		for (i = 0; i < 16; i++) {
+			/* Clear the old bits */
+			*(sl_pte+i) &= ~(PTE_EXT_SHARED | PTE_CACHEABLE |
+					 PTE_BUFFERABLE | PTE_EXT_TEX(1));
+
+			/* Assign new class and S bit */
+			*(sl_pte+i) |= sh ? PTE_EXT_SHARED : 0;
+			*(sl_pte+i) |= class & 0x01 ? PTE_BUFFERABLE : 0;
+			*(sl_pte+i) |= class & 0x02 ? PTE_CACHEABLE : 0;
+			*(sl_pte+i) |= class & 0x04 ? PTE_EXT_TEX(1) : 0;
+		}
+	} else 	if (len == SZ_4K) {
+		/* Clear the old bits */
+		*(sl_pte) &= ~(PTE_EXT_SHARED | PTE_CACHEABLE |
+			       PTE_BUFFERABLE | PTE_EXT_TEX(1));
+
+		/* Assign new class and S bit */
+		*(sl_pte) |= sh ? PTE_EXT_SHARED : 0;
+		*(sl_pte) |= class & 0x01 ? PTE_BUFFERABLE : 0;
+		*(sl_pte) |= class & 0x02 ? PTE_CACHEABLE : 0;
+		*(sl_pte) |= class & 0x04 ? PTE_EXT_TEX(1) : 0;
+	}
+
+
+	mb();
+	return 0;
+fail:
+	return 1;
+}
+
+
+int cpu_set_attr(unsigned long va, unsigned long len, unsigned int attr)
+{
+	int ret;
+	pgd_t *pgd = init_mm.pgd;
+
+	if (!pgd) {
+		smmu_err("null pgd\n");
+		goto fail;
+	}
+
+	ret = set_arm7_pte_attr((unsigned long)pgd, va, len, attr);
+
+	if (ret != 0) {
+		smmu_err("could not set attribute: \
+					pgd=%p, va=%p, len=%lu, attr=%d\n",
+			 (void *) pgd, (void *) va, len, attr);
+		goto fail;
+	}
+	dmb();
+	flush_tlb_all();
+	return 0;
+fail:
+	return -1;
+}
diff --git a/arch/arm/mm/vmregion.c b/arch/arm/mm/vmregion.c
index a631016..73e82f6 100644
--- a/arch/arm/mm/vmregion.c
+++ b/arch/arm/mm/vmregion.c
@@ -46,8 +46,8 @@
 	struct arm_vmregion *c, *new;
 
 	if (head->vm_end - head->vm_start < size) {
-		printk(KERN_WARNING "%s: allocation too big (requested %#x)\n",
-			__func__, size);
+		printk(KERN_WARNING "%s: allocation too big (requested %#x, end:%lx, start:%lx)\n",
+			__func__, size, head->vm_end, head->vm_start);
 		goto out;
 	}
 
diff --git a/arch/arm/oprofile/common.c b/arch/arm/oprofile/common.c
index 4e0a371..338e8c2 100644
--- a/arch/arm/oprofile/common.c
+++ b/arch/arm/oprofile/common.c
@@ -36,10 +36,18 @@
 		return "arm/armv6";
 	case ARM_PERF_PMU_ID_V6MP:
 		return "arm/mpcore";
+	case ARM_PERF_PMU_ID_CA5:
+		return "arm/armv7";
 	case ARM_PERF_PMU_ID_CA8:
 		return "arm/armv7";
 	case ARM_PERF_PMU_ID_CA9:
 		return "arm/armv7-ca9";
+	case ARM_PERF_PMU_ID_SCORPION:
+		return "arm/armv7-scorpion";
+	case ARM_PERF_PMU_ID_SCORPIONMP:
+		return "arm/armv7-scorpionmp";
+	case ARM_PERF_PMU_ID_KRAIT:
+		return "arm/armv7-krait";
 	default:
 		return NULL;
 	}
diff --git a/arch/arm/perfmon/Makefile b/arch/arm/perfmon/Makefile
new file mode 100644
index 0000000..716e087
--- /dev/null
+++ b/arch/arm/perfmon/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_KSAPI) += ksapi.o
+
+# Object file lists.
+obj-y						+= perf-function-hooks.o
+ksapi-y						+= perf-v7.o per.o per-process-perf.o per-axi.o
+ksapi-$(CONFIG_ARCH_MSM8X60)			+= perf-smp.o
diff --git a/arch/arm/perfmon/cp15_registers.h b/arch/arm/perfmon/cp15_registers.h
new file mode 100644
index 0000000..3de4d8b
--- /dev/null
+++ b/arch/arm/perfmon/cp15_registers.h
@@ -0,0 +1,94 @@
+/* Copyright (c) 2010, 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.
+ *
+ */
+
+/*
+cp15_registers.h
+
+DESCRIPTION: define macros for reading and writing to the cp registers
+for the ARMv7
+
+REV/DATE:  Fri Mar 18 15:54:32 EST 2005
+*/
+
+#ifndef __cp15_registers__
+#define __cp15_registers__
+
+#include "mcrmrc.h"
+
+#define WCP15_SDER(reg)			MCR15(reg, 0, c1, c1, 1)
+/*
+* Performance Monitor Registers
+*/
+#define WCP15_PMACTLR(reg)		MCR15(reg, 0, c9, c15, 5)
+#define WCP15_PMCCNTCR(reg)		MCR15(reg, 0, c9, c15, 2)
+#define WCP15_PMCCNTR(reg)		MCR15(reg, 0, c9, c13, 0)
+#define WCP15_PMCCNTSR(reg)		MCR15(reg, 0, c9, c13, 3)
+#define WCP15_PMCNTENCLR(reg)		MCR15(reg, 0, c9, c12, 2)
+#define WCP15_PMCNTENSET(reg)		MCR15(reg, 0, c9, c12, 1)
+#define WCP15_PMCR(reg)			MCR15(reg, 0, c9, c12, 0)
+#define WCP15_PMINTENCLR(reg)		MCR15(reg, 0, c9, c14, 2)
+#define WCP15_PMINTENSET(reg)		MCR15(reg, 0, c9, c14, 1)
+#define WCP15_PMOVSR(reg)		MCR15(reg, 0, c9, c12, 3)
+#define WCP15_PMRLDR(reg)		MCR15(reg, 0, c9, c15, 4)
+#define WCP15_PMSELR(reg)		MCR15(reg, 0, c9, c12, 5)
+#define WCP15_PMSWINC(reg)		MCR15(reg, 0, c9, c12, 4)
+#define WCP15_PMUSERENR(reg)		MCR15(reg, 0, c9, c14, 0)
+#define WCP15_PMXEVCNTCR(reg)		MCR15(reg, 0, c9, c15, 0)
+#define WCP15_PMXEVCNTR(reg)		MCR15(reg, 0, c9, c13, 2)
+#define WCP15_PMXEVCNTSR(reg)		MCR15(reg, 0, c9, c15, 1)
+#define WCP15_PMXEVTYPER(reg)		MCR15(reg, 0, c9, c13, 1)
+#define WCP15_LPM0EVTYPER(reg)		MCR15(reg, 0, c15, c0, 0)
+#define WCP15_LPM1EVTYPER(reg)		MCR15(reg, 1, c15, c0, 0)
+#define WCP15_LPM2EVTYPER(reg)		MCR15(reg, 2, c15, c0, 0)
+#define WCP15_LPM3EVTYPER(reg)		MCR15(reg, 3, c15, c0, 0)
+#define WCP15_L2LPMEVTYPER(reg)		MCR15(reg, 3, c15, c2, 0)
+#define WCP15_VLPMEVTYPER(reg)		MCR15(reg, 7, c11, c0, 0)
+#define WCP15_L2VR3F1(reg)		MCR15(reg, 3, c15, c15, 1)
+
+/*
+* READ the registers
+*/
+#define RCP15_SDER(reg)			MRC15(reg, 0, c1, c1, 1)
+/*
+* Performance Monitor Registers
+*/
+#define RCP15_PMACTLR(reg)		MRC15(reg, 0, c9, c15, 5)
+#define RCP15_PMCCNTCR(reg)		MRC15(reg, 0, c9, c15, 2)
+#define RCP15_PMCCNTR(reg)		MRC15(reg, 0, c9, c13, 0)
+#define RCP15_PMCCNTSR(reg)		MRC15(reg, 0, c9, c13, 3)
+#define RCP15_PMCNTENCLR(reg)		MRC15(reg, 0, c9, c12, 2)
+#define RCP15_PMCNTENSET(reg)		MRC15(reg, 0, c9, c12, 1)
+#define RCP15_PMCR(reg)			MRC15(reg, 0, c9, c12, 0)
+#define RCP15_PMINTENCLR(reg)		MRC15(reg, 0, c9, c14, 2)
+#define RCP15_PMINTENSET(reg)		MRC15(reg, 0, c9, c14, 1)
+#define RCP15_PMOVSR(reg)		MRC15(reg, 0, c9, c12, 3)
+#define RCP15_PMRLDR(reg)		MRC15(reg, 0, c9, c15, 4)
+#define RCP15_PMSELR(reg)		MRC15(reg, 0, c9, c12, 5)
+#define RCP15_PMSWINC(reg)		MRC15(reg, 0, c9, c12, 4)
+#define RCP15_PMUSERENR(reg)		MRC15(reg, 0, c9, c14, 0)
+#define RCP15_PMXEVCNTCR(reg)		MRC15(reg, 0, c9, c15, 0)
+#define RCP15_PMXEVCNTR(reg)		MRC15(reg, 0, c9, c13, 2)
+#define RCP15_PMXEVCNTSR(reg)		MRC15(reg, 0, c9, c15, 1)
+#define RCP15_PMXEVTYPER(reg)		MRC15(reg, 0, c9, c13, 1)
+#define RCP15_LPM0EVTYPER(reg)		MRC15(reg, 0, c15, c0, 0)
+#define RCP15_LPM1EVTYPER(reg)		MRC15(reg, 1, c15, c0, 0)
+#define RCP15_LPM2EVTYPER(reg)		MRC15(reg, 2, c15, c0, 0)
+#define RCP15_LPM3EVTYPER(reg)		MRC15(reg, 3, c15, c0, 0)
+#define RCP15_L2LPMEVTYPER(reg)		MRC15(reg, 3, c15, c2, 0)
+#define RCP15_VLPMEVTYPER(reg)		MRC15(reg, 7, c11, c0, 0)
+#define RCP15_CONTEXTIDR(reg)		MRC15(reg, 0, c13, c0, 1)
+#define RCP15_L2CR0(reg)		MRC15(reg, 3, c15, c0, 1)
+#define RCP15_L2VR3F1(reg)		MRC15(reg, 3, c15, c15, 1)
+
+#endif
+
diff --git a/arch/arm/perfmon/l2_cp15_registers.h b/arch/arm/perfmon/l2_cp15_registers.h
new file mode 100644
index 0000000..796dc8b
--- /dev/null
+++ b/arch/arm/perfmon/l2_cp15_registers.h
@@ -0,0 +1,88 @@
+/* Copyright (c) 2010, 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.
+ *
+ */
+
+/*
+cp15_registers.h
+
+DESCRIPTION: define macros for reading and writing to the cp registers
+for the ARMv7
+
+REV/DATE:  Fri Mar 18 15:54:32 EST 2005
+*/
+
+#ifndef __l2_cp15_registers__
+#define __l2_cp15_registers__
+
+#include "mcrmrc.h"
+
+#define WCP15_SDER(reg)			MCR15(reg, 0, c1, c1, 1)
+/*
+* Performance Monitor Registers
+*/
+#define WCP15_L2MPCR(reg)		MCR15(reg, 3, c15, c0, 4)
+#define WCP15_L2PMCCNTCR(reg)		MCR15(reg, 3, c15, c4, 4)
+#define WCP15_L2PMCCNTR(reg)		MCR15(reg, 3, c15, c4, 5)
+#define WCP15_L2PMCCNTSR(reg)		MCR15(reg, 3, c15, c4, 6)
+#define WCP15_L2PMCNTENCLR(reg)		MCR15(reg, 3, c15, c4, 2)
+#define WCP15_L2PMCNTENSET(reg)		MCR15(reg, 3, c15, c4, 3)
+#define WCP15_L2PMCR(reg)		MCR15(reg, 3, c15, c4, 0)
+#define WCP15_L2PMINTENCLR(reg)		MCR15(reg, 3, c15, c5, 0)
+#define WCP15_L2PMINTENSET(reg)		MCR15(reg, 3, c15, c5, 1)
+#define WCP15_L2PMOVSR(reg)		MCR15(reg, 3, c15, c4, 1)
+#define WCP15_L2PMRLDR(reg)		MCR15(reg, 3, c15, c4, 7)
+#define WCP15_L2PMSELR(reg)		MCR15(reg, 3, c15, c6, 0)
+#define WCP15_L2PMXEVCNTCR(reg)		MCR15(reg, 3, c15, c6, 4)
+#define WCP15_L2PMXEVCNTR(reg)		MCR15(reg, 3, c15, c6, 5)
+#define WCP15_L2PMXEVCNTSR(reg)		MCR15(reg, 3, c15, c6, 6)
+#define WCP15_L2PMXEVTYPER(reg)		MCR15(reg, 3, c15, c6, 7)
+#define WCP15_L2PMXEVFILTER(reg)	MCR15(reg, 3, c15, c6, 3)
+#define WCP15_L2PMEVTYPER0(reg)		MCR15(reg, 3, c15, c7, 0)
+#define WCP15_L2PMEVTYPER1(reg)		MCR15(reg, 3, c15, c7, 1)
+#define WCP15_L2PMEVTYPER2(reg)		MCR15(reg, 3, c15, c7, 2)
+#define WCP15_L2PMEVTYPER3(reg)		MCR15(reg, 3, c15, c7, 3)
+#define WCP15_L2PMEVTYPER4(reg)		MCR15(reg, 3, c15, c7, 4)
+#define WCP15_L2VR3F1(reg)		MCR15(reg, 3, c15, c15, 1)
+
+/*
+* READ the registers
+*/
+#define RCP15_SDER(reg)			MRC15(reg, 0, c1, c1, 1)
+/*
+* Performance Monitor Registers
+*/
+#define RCP15_L2MPCR(reg)		MRC15(reg, 3, c15, c0, 4)
+#define RCP15_L2PMCCNTCR(reg)		MRC15(reg, 3, c15, c4, 4)
+#define RCP15_L2PMCCNTR(reg)		MRC15(reg, 3, c15, c4, 5)
+#define RCP15_L2PMCCNTSR(reg)		MRC15(reg, 3, c15, c4, 6)
+#define RCP15_L2PMCNTENCLR(reg)		MRC15(reg, 3, c15, c4, 2)
+#define RCP15_L2PMCNTENSET(reg)		MRC15(reg, 3, c15, c4, 3)
+#define RCP15_L2PMCR(reg)		MRC15(reg, 3, c15, c4, 0)
+#define RCP15_L2PMINTENCLR(reg)		MRC15(reg, 3, c15, c5, 0)
+#define RCP15_L2PMINTENSET(reg)		MRC15(reg, 3, c15, c5, 1)
+#define RCP15_L2PMOVSR(reg)		MRC15(reg, 3, c15, c4, 1)
+#define RCP15_L2PMRLDR(reg)		MRC15(reg, 3, c15, c4, 7)
+#define RCP15_L2PMSELR(reg)		MRC15(reg, 3, c15, c6, 0)
+#define RCP15_L2PMXEVCNTCR(reg)		MRC15(reg, 3, c15, c6, 4)
+#define RCP15_L2PMXEVCNTR(reg)		MRC15(reg, 3, c15, c6, 5)
+#define RCP15_L2PMXEVCNTSR(reg)		MRC15(reg, 3, c15, c6, 6)
+#define RCP15_L2PMXEVTYPER(reg)		MRC15(reg, 3, c15, c6, 7)
+#define RCP15_L2PMXEVFILTER(reg)	MRC15(reg, 3, c15, c6, 3)
+#define RCP15_L2PMEVTYPER0(reg)		MRC15(reg, 3, c15, c7, 0)
+#define RCP15_L2PMEVTYPER1(reg)		MRC15(reg, 3, c15, c7, 1)
+#define RCP15_L2PMEVTYPER2(reg)		MRC15(reg, 3, c15, c7, 2)
+#define RCP15_L2PMEVTYPER3(reg)		MRC15(reg, 3, c15, c7, 3)
+#define RCP15_L2PMEVTYPER4(reg)		MRC15(reg, 3, c15, c7, 4)
+#define RCP15_L2VR3F1(reg)		MRC15(reg, 3, c15, c15, 1)
+
+#endif
+
diff --git a/arch/arm/perfmon/mcrmrc.h b/arch/arm/perfmon/mcrmrc.h
new file mode 100644
index 0000000..29f9ac0
--- /dev/null
+++ b/arch/arm/perfmon/mcrmrc.h
@@ -0,0 +1,86 @@
+/* Copyright (c) 2010, 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.
+ *
+ */
+
+/*
+mrcmcr.h
+
+DESCRIPTION: Convenience macros for access the cp registers in the arm.
+
+REV/DATE: Fri Mar 18 16:34:44 EST 2005
+*/
+
+#ifndef __mrcmcr__h_
+#define __mrcmcr__h_
+
+/*
+* Define some convenience macros to acccess the cp registers from c code
+* Lots of macro trickery here.
+*
+* Takes the same format as the asm instructions and unfortunatly you cannot
+* use variables to select the crn, crn or op fields...
+*
+* For those unfamiliar with the # and string stuff.
+* # creates a string from the value and any two strings that are beside
+*   are concatenated...thus these create one big asm string for the
+*   inline asm code.
+*
+* When compiled these compile to single asm instructions (fast) but
+* without all the hassel of __asm__ __volatile__ (...) =r
+*
+* Format is:
+*
+*    unsigned long reg;   // destination variable
+*    MRC(reg, p15, 0, c1, c0, 0 );
+*
+*   MRC read control register
+*   MCR control register write
+*/
+
+/*
+* Some assembly macros so we can use the same macros as in the C version.
+* Turns the ASM code a little C-ish but keeps the code consistent and in
+* one location...
+*/
+#ifdef __ASSEMBLY__
+
+
+#define MRC(reg, processor, op1, crn, crm, op2) \
+(mrc      processor , op1 , reg,  crn , crm , op2)
+
+#define MCR(reg, processor, op1, crn, crm, op2) \
+(mcr      processor , op1 , reg,  crn , crm , op2)
+
+/*
+* C version of the macros.
+*/
+#else
+
+#define MRC(reg, processor, op1, crn, crm, op2) \
+__asm__ __volatile__ ( \
+"   mrc   "   #processor "," #op1 ", %0,"  #crn "," #crm "," #op2 "\n" \
+: "=r" (reg))
+
+#define MCR(reg, processor, op1, crn, crm, op2) \
+__asm__ __volatile__ ( \
+"   mcr   "   #processor "," #op1 ", %0,"  #crn "," #crm "," #op2 "\n" \
+: : "r" (reg))
+#endif
+
+
+/*
+* Easy access convenience function to read CP15 registers from c code
+*/
+#define MRC15(reg, op1, crn, crm, op2) MRC(reg, p15, op1, crn, crm, op2)
+#define MCR15(reg, op1, crn, crm, op2) MCR(reg, p15, op1, crn, crm, op2)
+
+#endif
diff --git a/arch/arm/perfmon/per-axi.c b/arch/arm/perfmon/per-axi.c
new file mode 100644
index 0000000..48309be
--- /dev/null
+++ b/arch/arm/perfmon/per-axi.c
@@ -0,0 +1,759 @@
+/* Copyright (c) 2010, 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.
+ */
+
+/*
+per-axi
+DESCRIPTION
+Functions related to AXI bus performance counter manipulations.
+*/
+
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/proc_fs.h>
+#include "asm/uaccess.h"
+#include "per-axi.h"
+#include "perf.h"
+
+/*
+Definitions for AXI register addresses, macros to set and get register values
+*/
+#define AXI_BASE_SIZE						0x00004000
+#define AXI_REG_BASE					(AXI_BASE + 0x00000000)
+#define AXI_REG_BASE_PHYS					0xa8200000
+
+#define __inpdw(port)	ioread32(port)
+#define in_dword_masked(addr, mask) (__inpdw(addr) & (mask))
+#define __outpdw(port, val) (iowrite32((uint32_t) (val), port))
+#define out_dword(addr, val)        __outpdw(addr, val)
+
+#define HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_ADDR \
+						(AXI_REG_BASE + 0x00003434)
+#define HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_RMSK		0xffff
+#define HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_IN	\
+	in_dword_masked(HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_ADDR, \
+				HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_RMSK)
+
+#define HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_ADDR (AXI_REG_BASE + 0x00003438)
+#define HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_RMSK		0xffff
+#define HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_IN	\
+	in_dword_masked(HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_ADDR, \
+				HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_RMSK)
+
+#define HWIO_AXI_MONITOR_SELECTION_REG0_ADDR	(AXI_REG_BASE + 0x00003428)
+#define HWIO_AXI_MONITOR_SELECTION_REG1_ADDR    (AXI_REG_BASE + 0x0000342c)
+#define HWIO_AXI_MONITOR_TENURE_SELECTION_REG_ADDR (AXI_REG_BASE + 0x00003430)
+#define HWIO_AXI_MONITOR_SELECTION_REG0_ETC_BMSK		0x4000
+#define HWIO_AXI_MONITOR_SELECTION_REG0_ECC_BMSK		0x2000
+#define HWIO_AXI_MONITOR_SELECTION_REG0_EEC1_BMSK		0x800
+#define HWIO_AXI_MONITOR_SELECTION_REG0_EEC0_BMSK		0x200
+#define HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_OUT(v)                       \
+	out_dword(HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_ADDR, v)
+#define HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_OUT(v)                       \
+	out_dword(HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_ADDR, v)
+#define HWIO_AXI_MONITOR_SELECTION_REG0_OUT(v)                              \
+	out_dword(HWIO_AXI_MONITOR_SELECTION_REG0_ADDR, v)
+#define HWIO_AXI_MONITOR_SELECTION_REG1_OUT(v)                              \
+	out_dword(HWIO_AXI_MONITOR_SELECTION_REG1_ADDR, v)
+#define HWIO_AXI_MONITOR_TENURE_SELECTION_REG_OUT(v)                        \
+	out_dword(HWIO_AXI_MONITOR_TENURE_SELECTION_REG_ADDR, v)
+#define HWIO_AXI_MONITOR_SELECTION_REG0_RMSK			0xffff
+#define HWIO_AXI_MONITOR_SELECTION_REG0_IN                                  \
+	in_dword_masked(HWIO_AXI_MONITOR_SELECTION_REG0_ADDR,               \
+	HWIO_AXI_MONITOR_SELECTION_REG0_RMSK)
+
+#define HWIO_AXI_CONFIGURATION_REG_ADDR		(AXI_REG_BASE + 0x00000008)
+#define HWIO_AXI_CONFIGURATION_REG_OUT(v)                                   \
+	out_dword(HWIO_AXI_CONFIGURATION_REG_ADDR, v)
+#define HWIO_AXI_CONFIGURATION_REG_PPDM_BMSK			0x0
+#define HWIO_AXI_CONFIGURATION_REG_DISABLE			0x2
+#define AXI_EVTSEL_ENABLE_MASK					0x6a00
+#define AXI_EVTSEL_DISABLE_MASK					0x95ff
+#define AXI_EVTSEL_RESET_MASK					0xfe40
+
+#define HWIO_AXI_MONITOR_EVENT_LOWER_REG0_ADDR	(AXI_REG_BASE + 0x00003450)
+#define HWIO_AXI_MONITOR_EVENT_LOWER_REG0_RMSK			0xffff
+#define HWIO_AXI_MONITOR_EVENT_LOWER_REG0_SHFT			0
+#define HWIO_AXI_MONITOR_EVENT_LOWER_REG0_IN                                \
+	in_dword_masked(HWIO_AXI_MONITOR_EVENT_LOWER_REG0_ADDR,		\
+	HWIO_AXI_MONITOR_EVENT_LOWER_REG0_RMSK)
+#define HWIO_AXI_MONITOR_EVENT_UPPER_REG0_ADDR	(AXI_REG_BASE + 0x00003454)
+#define HWIO_AXI_MONITOR_EVENT_UPPER_REG0_RMSK			0xffff
+#define HWIO_AXI_MONITOR_EVENT_UPPER_REG0_SHFT			0
+#define HWIO_AXI_MONITOR_EVENT_UPPER_REG0_IN                                \
+	in_dword_masked(HWIO_AXI_MONITOR_EVENT_UPPER_REG0_ADDR,		\
+	HWIO_AXI_MONITOR_EVENT_UPPER_REG0_RMSK)
+
+#define HWIO_AXI_MONITOR_EVENT_LOWER_REG1_ADDR	(AXI_REG_BASE + 0x00003458)
+#define HWIO_AXI_MONITOR_EVENT_LOWER_REG1_RMSK			0xffff
+#define HWIO_AXI_MONITOR_EVENT_LOWER_REG1_SHFT			0
+#define HWIO_AXI_MONITOR_EVENT_LOWER_REG1_IN                                \
+	in_dword_masked(HWIO_AXI_MONITOR_EVENT_LOWER_REG1_ADDR,		\
+	HWIO_AXI_MONITOR_EVENT_LOWER_REG1_RMSK)
+#define HWIO_AXI_MONITOR_EVENT_UPPER_REG1_ADDR	(AXI_REG_BASE + 0x0000345c)
+#define HWIO_AXI_MONITOR_EVENT_UPPER_REG1_RMSK			0xffff
+#define HWIO_AXI_MONITOR_EVENT_UPPER_REG1_SHFT			0
+#define HWIO_AXI_MONITOR_EVENT_UPPER_REG1_IN                                \
+	in_dword_masked(HWIO_AXI_MONITOR_EVENT_UPPER_REG1_ADDR,		\
+	HWIO_AXI_MONITOR_EVENT_UPPER_REG1_RMSK)
+
+#define HWIO_AXI_MONITOR_TENURE_LOWER_REG_ADDR	(AXI_REG_BASE + 0x00003448)
+#define HWIO_AXI_MONITOR_TENURE_LOWER_REG_RMSK			0xffff
+#define HWIO_AXI_MONITOR_TENURE_LOWER_REG_SHFT			0
+#define HWIO_AXI_MONITOR_TENURE_LOWER_REG_IN                                \
+	in_dword_masked(HWIO_AXI_MONITOR_TENURE_LOWER_REG_ADDR,		\
+	HWIO_AXI_MONITOR_TENURE_LOWER_REG_RMSK)
+#define HWIO_AXI_MONITOR_TENURE_UPPER_REG_ADDR	(AXI_REG_BASE + 0x00003444)
+#define HWIO_AXI_MONITOR_TENURE_UPPER_REG_RMSK			0xffff
+#define HWIO_AXI_MONITOR_TENURE_UPPER_REG_SHFT			0
+#define HWIO_AXI_MONITOR_TENURE_UPPER_REG_IN                                \
+	in_dword_masked(HWIO_AXI_MONITOR_TENURE_UPPER_REG_ADDR,		\
+	HWIO_AXI_MONITOR_TENURE_UPPER_REG_RMSK)
+
+#define HWIO_AXI_MONITOR_MIN_REG_ADDR		(AXI_REG_BASE + 0x0000343c)
+#define HWIO_AXI_MONITOR_MIN_REG_RMSK				0xffff
+#define HWIO_AXI_MONITOR_MIN_REG_SHFT				0
+#define HWIO_AXI_MONITOR_MIN_REG_IN                                         \
+	in_dword_masked(HWIO_AXI_MONITOR_MIN_REG_ADDR,			\
+	HWIO_AXI_MONITOR_MIN_REG_RMSK)
+#define HWIO_AXI_MONITOR_MAX_REG_ADDR		(AXI_REG_BASE + 0x00003440)
+#define HWIO_AXI_MONITOR_MAX_REG_RMSK				0xffff
+#define HWIO_AXI_MONITOR_MAX_REG_SHFT				0
+#define HWIO_AXI_MONITOR_MAX_REG_IN                                         \
+	in_dword_masked(HWIO_AXI_MONITOR_MAX_REG_ADDR,			\
+	HWIO_AXI_MONITOR_MAX_REG_RMSK)
+#define HWIO_AXI_MONITOR_LAST_TENURE_REG_ADDR	(AXI_REG_BASE + 0x0000344c)
+#define HWIO_AXI_MONITOR_LAST_TENURE_REG_RMSK			0xffff
+#define HWIO_AXI_MONITOR_LAST_TENURE_REG_SHFT			0
+#define HWIO_AXI_MONITOR_LAST_TENURE_REG_IN                                 \
+	in_dword_masked(HWIO_AXI_MONITOR_LAST_TENURE_REG_ADDR,		\
+	HWIO_AXI_MONITOR_LAST_TENURE_REG_RMSK)
+#define HWIO_AXI_MONITOR_TENURE_UPPER_REG_OUT(v)                            \
+	out_dword(HWIO_AXI_MONITOR_TENURE_UPPER_REG_ADDR, v)
+#define HWIO_AXI_MONITOR_TENURE_LOWER_REG_OUT(v)                            \
+	out_dword(HWIO_AXI_MONITOR_TENURE_LOWER_REG_ADDR, v)
+
+#define HWIO_AXI_RESET_ALL		0x9400
+#define HWIO_AXI_ENABLE_ALL_NOCYCLES	0x4a00
+#define HWIO_AXI_DISABLE_ALL		0xb500
+uint32_t AXI_BASE;
+
+unsigned int is_first = 1;
+struct perf_mon_axi_data pm_axi_info;
+struct perf_mon_axi_cnts axi_cnts;
+
+/*
+FUNCTION get_axi_sel_reg0
+
+DESCRIPTION
+	Retrieve the value of AXI_SEL_REG0
+
+DEPENDENCIES
+
+RETURN VALUE
+	AXI_SEL_REG0
+SIDE EFFECTS
+*/
+unsigned long get_axi_sel_reg0(void)
+{
+	return pm_axi_info.sel_reg0;
+}
+
+/*
+FUNCTION get_axi_sel_reg1
+
+DESCRIPTION
+	Retrieve the value of AXI_SEL_REG1
+
+DEPENDENCIES
+
+RETURN VALUE
+	AXI_SEL_REG1
+SIDE EFFECTS
+*/
+unsigned long get_axi_sel_reg1(void)
+{
+	return pm_axi_info.sel_reg1;
+}
+
+/*
+FUNCTION get_axi_ten_sel_reg
+
+DESCRIPTION
+	Retrieve the value of AXI_TEN_REG
+
+DEPENDENCIES
+
+RETURN VALUE
+	AXI_TEN_REG
+SIDE EFFECTS
+*/
+unsigned long get_axi_ten_sel_reg(void)
+{
+	return pm_axi_info.ten_sel_reg;
+}
+
+/*
+FUNCTION get_axi_valid
+
+DESCRIPTION
+	Retrieve the value of AXI valid bit
+
+DEPENDENCIES
+
+RETURN VALUE
+	AXI Valid bit
+SIDE EFFECTS
+*/
+unsigned long get_axi_valid(void)
+{
+	return pm_axi_info.valid;
+}
+
+/*
+FUNCTION get_axi_enable
+
+DESCRIPTION
+	Retrieve the value of AXI enable bit
+
+DEPENDENCIES
+
+RETURN VALUE
+	AXI enable bit
+SIDE EFFECTS
+*/
+unsigned long get_axi_enable(void)
+{
+	return pm_axi_info.enable;
+}
+
+/*
+FUNCTION get_axi_clear
+
+DESCRIPTION
+	Retrieve the value of AXI clear bit
+
+DEPENDENCIES
+
+RETURN VALUE
+	AXI clear bit
+SIDE EFFECTS
+*/
+unsigned long get_axi_clear(void)
+{
+	return pm_axi_info.clear;
+}
+
+/*
+FUNCTION pm_axi_cnts_write
+
+DESCRIPTION
+	Write handler for the /proc axi results directory.
+
+DEPENDENCIES
+
+RETURN VALUE
+	Number of characters to output.
+
+SIDE EFFECTS
+*/
+int pm_axi_cnts_write(struct file *file, const char *buff,
+    unsigned long cnt, void *data)
+{
+	char *newbuf;
+	struct PerfMonAxiCnts *p =
+	(struct PerfMonAxiCnts *)data;
+
+	if (p == 0)
+		return cnt;
+	/*
+	* Alloc the user data in kernel space. and then copy user to kernel
+	*/
+	newbuf = kmalloc(cnt + 1, GFP_KERNEL);
+	if (0 == newbuf)
+		return cnt;
+	if (copy_from_user(newbuf, buff, cnt) != 0) {
+		printk(KERN_INFO "%s copy_from_user failed\n", __func__);
+		return cnt;
+	}
+	return cnt;
+}
+
+/*
+FUNCTION pm_axi_update_cnts
+
+DESCRIPTION
+	Read the current AXI counter values. Check for overflows and
+	adjust the values stored accordingly.
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+void pm_axi_update_cnts(void)
+{
+	if (is_first) {
+		pm_axi_start();
+	} else {
+		if (pm_axi_info.valid == 1) {
+			pm_axi_info.valid = 0;
+			pm_axi_update();
+		} else {
+			pm_axi_enable();
+		}
+	}
+	is_first = 0;
+	axi_cnts.cycles += pm_get_axi_cycle_count();
+	axi_cnts.cnt0 += pm_get_axi_evt0_count();
+	axi_cnts.cnt1 += pm_get_axi_evt1_count();
+	axi_cnts.tenure_total += pm_get_axi_ten_total_count();
+
+	axi_cnts.tenure_min = pm_get_axi_ten_min_count();
+	axi_cnts.tenure_max = pm_get_axi_ten_max_count();
+	axi_cnts.tenure_last = pm_get_axi_ten_last_count();
+
+	pm_axi_start();
+}
+
+/*
+FUNCTION pm_axi_clear_cnts
+
+DESCRIPTION
+	Clear the locally stored AXI counter values.
+	Also clear the AXI counter registers.
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+void pm_axi_clear_cnts(void)
+{
+	axi_cnts.cycles = 0;
+	axi_cnts.cnt0 = 0;
+	axi_cnts.cnt1 = 0;
+	axi_cnts.tenure_total = 0;
+	axi_cnts.tenure_min = 0;
+	axi_cnts.tenure_max = 0;
+	axi_cnts.tenure_last = 0;
+	pm_axi_start();
+}
+
+/*
+FUNCTION pm_axi_read_decimal
+
+DESCRIPTION
+	Read handler for the /proc axi results directory in decimal format.
+
+DEPENDENCIES
+
+RETURN VALUE
+	Number of characters to output.
+
+SIDE EFFECTS
+*/
+int pm_axi_read_decimal(char *page, char **start, off_t off, int count,
+   int *eof, void *data)
+{
+	struct perf_mon_axi_cnts *p = (struct perf_mon_axi_cnts *)data;
+
+	return sprintf(page, "cnt0:%llu cnt1:%llu tenure:%llu ten_max:%llu \
+				ten_min:%llu ten_last:%llu cycles:%llu\n",
+				p->cnt0,
+				p->cnt1,
+				p->tenure_total,
+				p->tenure_max,
+				p->tenure_min,
+				p->tenure_last,
+				p->cycles);
+}
+
+/*
+FUNCTION pm_axi_read_hex
+
+DESCRIPTION
+	Read handler for the /proc axi results directory in hex format.
+
+DEPENDENCIES
+
+RETURN VALUE
+	Number of characters to output.
+
+SIDE EFFECTS
+*/
+int pm_axi_read_hex(char *page, char **start, off_t off, int count,
+   int *eof, void *data)
+{
+	struct perf_mon_axi_cnts *p = (struct perf_mon_axi_cnts *)data;
+
+	return sprintf(page, "cnt0:%llx cnt1:%llx tenure:%llx ten_max:%llx \
+				ten_min:%llx ten_last:%llx cycles:%llx\n",
+				p->cnt0,
+				p->cnt1,
+				p->tenure_total,
+				p->tenure_max,
+				p->tenure_min,
+				p->tenure_last,
+				p->cycles);
+
+}
+
+/*
+FUNCTION pm_axi_set_proc_entry
+
+DESCRIPTION
+	Create a generic entry for the /proc axi settings directory.
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+void pm_axi_set_proc_entry(char *name, unsigned long *var,
+    struct proc_dir_entry *d, int hex)
+{
+	struct proc_dir_entry *pe;
+	pe = create_proc_entry(name, 0777, d);
+	if (0 == pe)
+		return;
+	if (hex) {
+		pe->read_proc = per_process_read;
+		pe->write_proc = per_process_write_hex;
+	} else {
+		pe->read_proc = per_process_read_decimal;
+		pe->write_proc = per_process_write_dec;
+	}
+	pe->data = (void *)var;
+}
+
+/*
+FUNCTION pm_axi_get_cnt_proc_entry
+
+DESCRIPTION
+	Create a generic entry for the /proc axi results directory.
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+void pm_axi_get_cnt_proc_entry(char *name, struct perf_mon_axi_cnts *var,
+    struct proc_dir_entry *d, int hex)
+{
+	struct proc_dir_entry *pe;
+	pe = create_proc_entry(name, 0777, d);
+	if (0 == pe)
+		return;
+	if (hex) {
+		pe->read_proc = pm_axi_read_hex;
+		pe->write_proc = pm_axi_cnts_write;
+	} else {
+		pe->read_proc = pm_axi_read_decimal;
+		pe->write_proc = pm_axi_cnts_write;
+	}
+	pe->data = (void *)var;
+}
+
+/*
+FUNCTION pm_axi_clear_tenure
+
+DESCRIPTION
+	Clear AXI tenure cntr manually. Temporary solution till hardware bug
+	is fixed
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+void pm_axi_clear_tenure(void)
+{
+	HWIO_AXI_MONITOR_TENURE_UPPER_REG_OUT(0x0);
+	HWIO_AXI_MONITOR_TENURE_LOWER_REG_OUT(0x0);
+}
+
+/*
+FUNCTION pm_axi_init
+
+DESCRIPTION
+	Map AXI region to virtual memory.
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+void pm_axi_init()
+{
+	/*Map the AXI regs*/
+	#ifdef CONFIG_ARCH_QSD8X50
+	{
+		/*Map the AXI regs*/
+		AXI_BASE = (uint32_t)ioremap(AXI_REG_BASE_PHYS, AXI_BASE_SIZE);
+		if (!AXI_BASE)
+			printk(KERN_ERR "Mem map failed\n");
+	}
+	#else
+	{
+		AXI_BASE = (uint32_t)kmalloc(AXI_BASE_SIZE, GFP_KERNEL);
+	}
+	#endif
+
+}
+
+/*
+FUNCTION pm_axi_start
+
+DESCRIPTION
+	Set event0, event1 and tenure registers based on the /proc entries.
+	Set cycle cntr to fffffffe to start counters.
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+void
+pm_axi_start()
+{
+	unsigned long sel_reg0, sel_reg1, ten_sel_reg;
+	sel_reg0 = get_axi_sel_reg0();
+	sel_reg1 = get_axi_sel_reg1();
+	ten_sel_reg = get_axi_ten_sel_reg();
+	HWIO_AXI_CONFIGURATION_REG_OUT(HWIO_AXI_CONFIGURATION_REG_PPDM_BMSK);
+	/*Set AXI Cycle Counter to enable AXI Monitors*/
+	HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_OUT(0xffff);
+	HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_OUT(0xfffe);
+	/*Set master/slave*/
+	HWIO_AXI_MONITOR_SELECTION_REG1_OUT(sel_reg1);
+	HWIO_AXI_MONITOR_SELECTION_REG0_OUT(HWIO_AXI_RESET_ALL);
+	HWIO_AXI_MONITOR_SELECTION_REG0_OUT(HWIO_AXI_ENABLE_ALL_NOCYCLES);
+	HWIO_AXI_MONITOR_SELECTION_REG0_OUT(HWIO_AXI_MONITOR_SELECTION_REG0_IN
+		| sel_reg0);
+	HWIO_AXI_MONITOR_SELECTION_REG0_OUT(HWIO_AXI_MONITOR_SELECTION_REG0_IN
+		| HWIO_AXI_MONITOR_SELECTION_REG0_ECC_BMSK);
+	HWIO_AXI_CONFIGURATION_REG_OUT(HWIO_AXI_CONFIGURATION_REG_PPDM_BMSK);
+}
+
+/*
+FUNCTION pm_axi_update
+
+DESCRIPTION
+	Set event0, event1 and tenure registers based on the /proc entries.
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+void
+pm_axi_update()
+{
+	HWIO_AXI_CONFIGURATION_REG_OUT(HWIO_AXI_CONFIGURATION_REG_PPDM_BMSK);
+	HWIO_AXI_MONITOR_SELECTION_REG0_OUT(HWIO_AXI_MONITOR_SELECTION_REG0_IN
+		| HWIO_AXI_RESET_ALL);
+	HWIO_AXI_MONITOR_SELECTION_REG0_OUT(HWIO_AXI_MONITOR_SELECTION_REG0_IN
+	& HWIO_AXI_DISABLE_ALL);
+	pm_axi_start();
+}
+
+/*
+FUNCTION pm_axi_disable
+
+DESCRIPTION
+	Disable all cntrs.
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+void
+pm_axi_disable(void)
+{
+	unsigned long sel_reg0;
+	/*Disable cntrs*/
+	sel_reg0 = get_axi_sel_reg0();
+	HWIO_AXI_MONITOR_SELECTION_REG0_OUT(sel_reg0 & AXI_EVTSEL_DISABLE_MASK);
+	/*Disable clk*/
+	HWIO_AXI_CONFIGURATION_REG_OUT(HWIO_AXI_CONFIGURATION_REG_DISABLE);
+}
+
+/*
+FUNCTION pm_axi_enable
+
+DESCRIPTION
+	Enable all cntrs.
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+void
+pm_axi_enable(void)
+{
+	unsigned long sel_reg0;
+	/*Enable cntrs*/
+	sel_reg0 = get_axi_sel_reg0();
+	HWIO_AXI_MONITOR_SELECTION_REG0_OUT(sel_reg0 | 0x6a00);
+	/*Enable clk*/
+	HWIO_AXI_CONFIGURATION_REG_OUT(HWIO_AXI_CONFIGURATION_REG_PPDM_BMSK);
+}
+
+/*
+FUNCTION pm_axi_disable_cnts
+
+DESCRIPTION
+	Read cycle cntr value
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+unsigned long
+pm_get_axi_cycle_count(void)
+{
+	if (HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_IN == 0x0 &&
+		HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_IN == 0x0) {
+		/*Set AXI Cycle Counter to enable AXI Monitors*/
+		HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_OUT(0xffff);
+		HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_OUT(0xfffe);
+	}
+	return 0xfffffffe - ((HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_IN << 16)
+	+ HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_IN);
+}
+
+/*
+FUNCTION pm_get_axi_evt0_count
+
+DESCRIPTION
+	Read Event0 cntr value
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+unsigned long
+pm_get_axi_evt0_count(void)
+{
+	return (HWIO_AXI_MONITOR_EVENT_UPPER_REG0_IN << 16)
+		+ HWIO_AXI_MONITOR_EVENT_LOWER_REG0_IN;
+}
+
+/*
+FUNCTION pm_get_axi_evt1_count
+
+DESCRIPTION
+	Read Event1 cntr value
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+unsigned long
+pm_get_axi_evt1_count(void)
+{
+	return (HWIO_AXI_MONITOR_EVENT_UPPER_REG1_IN << 16)
+		+ HWIO_AXI_MONITOR_EVENT_LOWER_REG1_IN;
+}
+
+/*
+FUNCTION pm_get_axi_ten_min_count
+
+DESCRIPTION
+	Read min tenure cntr value
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+unsigned long
+pm_get_axi_ten_min_count(void)
+{
+	return HWIO_AXI_MONITOR_MIN_REG_IN;
+}
+
+/*
+FUNCTION pm_get_axi_ten_max_count
+
+DESCRIPTION
+	Read max tenure cntr value
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+unsigned long
+pm_get_axi_ten_max_count(void)
+{
+	return HWIO_AXI_MONITOR_MAX_REG_IN;
+}
+
+/*
+FUNCTION pm_get_axi_ten_total_count
+
+DESCRIPTION
+	Read total tenure cntr value
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+unsigned long
+pm_get_axi_ten_total_count(void)
+{
+	return (HWIO_AXI_MONITOR_TENURE_UPPER_REG_IN << 16)
+		+ HWIO_AXI_MONITOR_TENURE_LOWER_REG_IN;
+}
+
+/*
+FUNCTION pm_get_axi_ten_last_count
+
+DESCRIPTION
+	Read last tenure cntr value
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+unsigned long
+pm_get_axi_ten_last_count(void)
+{
+	return HWIO_AXI_MONITOR_LAST_TENURE_REG_IN;
+}
diff --git a/arch/arm/perfmon/per-axi.h b/arch/arm/perfmon/per-axi.h
new file mode 100644
index 0000000..89f67fc
--- /dev/null
+++ b/arch/arm/perfmon/per-axi.h
@@ -0,0 +1,76 @@
+/* Copyright (c) 2010, 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.
+ *
+ */
+
+/*
+*per-axi
+*DESCRIPTION
+*Header File for Functions related to AXI bus performance counter manipulations.
+*/
+
+#ifndef __PER_AXI_H__
+#define __PER_AXI_H__
+unsigned long pm_get_axi_cycle_count(void);
+unsigned long pm_get_axi_evt0_count(void);
+unsigned long pm_get_axi_evt1_count(void);
+unsigned long pm_get_axi_evt2_count(void);
+unsigned long pm_get_axi_ten_min_count(void);
+unsigned long pm_get_axi_ten_max_count(void);
+unsigned long pm_get_axi_ten_total_count(void);
+unsigned long pm_get_axi_ten_last_count(void);
+
+unsigned long get_axi_sel_reg0(void);
+unsigned long get_axi_sel_seg1(void);
+unsigned long get_axi_ten_sel_reg(void);
+unsigned long get_axi_valid(void);
+unsigned long get_axi_enable(void);
+unsigned long get_axi_clear(void);
+
+void pm_axi_clear_cnts(void);
+void pm_axi_update_cnts(void);
+
+void pm_axi_init(void);
+void pm_axi_start(void);
+void pm_axi_update(void);
+void pm_axi_disable(void);
+void pm_axi_enable(void);
+
+struct perf_mon_axi_cnts{
+  unsigned long long cycles;
+  unsigned long long cnt0;
+  unsigned long long cnt1;
+  unsigned long long tenure_total;
+  unsigned long long tenure_min;
+  unsigned long long tenure_max;
+  unsigned long long tenure_last;
+};
+
+struct perf_mon_axi_data{
+  struct proc_dir_entry *proc;
+  unsigned long enable;
+  unsigned long clear;
+  unsigned long valid;
+  unsigned long sel_reg0;
+  unsigned long sel_reg1;
+  unsigned long ten_sel_reg;
+  unsigned long refresh;
+};
+
+extern struct perf_mon_axi_data pm_axi_info;
+extern struct perf_mon_axi_cnts axi_cnts;
+
+void pm_axi_set_proc_entry(char *name, unsigned long *var,
+	struct proc_dir_entry *d, int hex);
+void pm_axi_get_cnt_proc_entry(char *name, struct perf_mon_axi_cnts *var,
+	struct proc_dir_entry *d, int hex);
+
+#endif
diff --git a/arch/arm/perfmon/per-process-perf.c b/arch/arm/perfmon/per-process-perf.c
new file mode 100644
index 0000000..c8bebd8
--- /dev/null
+++ b/arch/arm/perfmon/per-process-perf.c
@@ -0,0 +1,1251 @@
+/* Copyright (c) 2010, 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.
+*/
+
+/*
+per-process_perf
+DESCRIPTION
+Capture the processor performances registers when the process context
+switches.  The /proc file system is used to control and access the results
+of the performance counters.
+
+Each time a process is context switched, the performance counters for
+the Snoop Control Unit and the standard ARM counters are set according
+to the values stored for that process.
+
+The events to capture per process are set in the /proc/ppPerf/settings
+directory.
+
+EXTERNALIZED FUNCTIONS
+
+INITIALIZATION AND SEQUENCING REQUIREMENTS
+Detail how to initialize and use this service.  The sequencing aspect
+is only needed if the order of operations is important.
+*/
+
+/*
+INCLUDE FILES FOR MODULE
+*/
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/sysrq.h>
+#include <linux/time.h>
+#include "linux/proc_fs.h"
+#include "linux/kernel_stat.h"
+#include <asm/thread_notify.h>
+#include "asm/uaccess.h"
+#include "cp15_registers.h"
+#include "l2_cp15_registers.h"
+#include <asm/perftypes.h>
+#include "per-axi.h"
+#include "perf.h"
+
+#define DEBUG_SWAPIO
+#ifdef DEBUG_SWAPIO
+#define MR_SIZE 1024
+#define PM_PP_ERR -1
+struct mark_data_s {
+  long c;
+  long cpu;
+  unsigned long pid_old;
+  unsigned long pid_new;
+};
+
+struct mark_data_s markRay[MR_SIZE] __attribute__((aligned(16)));
+int mrcnt;
+
+DEFINE_SPINLOCK(_mark_lock);
+
+static inline void MARKPIDS(char a, int opid, int npid)
+{
+	int cpu = smp_processor_id();
+
+	if (opid == 0)
+		return;
+	spin_lock(&_mark_lock);
+	if (++mrcnt >= MR_SIZE)
+		mrcnt = 0;
+	spin_unlock(&_mark_lock);
+
+	markRay[mrcnt].pid_old = opid;
+	markRay[mrcnt].pid_new = npid;
+	markRay[mrcnt].cpu = cpu;
+	markRay[mrcnt].c = a;
+}
+static inline void MARK(char a) { MARKPIDS(a, 0xFFFF, 0xFFFF); }
+static inline void MARKPID(char a, int pid) { MARKPIDS(a, pid, 0xFFFF); }
+
+#else
+#define MARK(a)
+#define MARKPID(a, b)
+#define MARKPIDS(a, b, c)
+
+#endif /* DEBUG_SWAPIO */
+
+/*
+DEFINITIONS AND DECLARATIONS FOR MODULE
+
+This section contains definitions for constants, macros, types, variables
+and other items needed by this module.
+*/
+
+/*
+Constant / Define Declarations
+*/
+
+#define PERF_MON_PROCESS_NUM 0x400
+#define PERF_MON_PROCESS_MASK (PERF_MON_PROCESS_NUM-1)
+#define PP_MAX_PROC_ENTRIES 32
+
+/*
+ * The entry is locked and is not to be replaced.
+ */
+#define PERF_ENTRY_LOCKED (1<<0)
+#define PERF_NOT_FIRST_TIME   (1<<1)
+#define PERF_EXITED (1<<2)
+#define PERF_AUTOLOCK (1<<3)
+
+#define IS_LOCKED(p) (p->flags & PERF_ENTRY_LOCKED)
+
+#define PERF_NUM_MONITORS 4
+
+#define L1_EVENTS_0    0
+#define L1_EVENTS_1    1
+#define L2_EVENTS_0  2
+#define L2_EVENTS_1  3
+
+#define PM_CYCLE_OVERFLOW_MASK 0x80000000
+#define L2_PM_CYCLE_OVERFLOW_MASK 0x80000000
+
+#define PM_START_ALL() do {\
+	if (pm_global) \
+		pmStartAll();\
+	} while (0);
+#define PM_STOP_ALL() do {\
+	if (pm_global)\
+		pmStopAll();\
+	} while (0);
+#define PM_RESET_ALL() do {\
+	if (pm_global)\
+		pmResetAll();\
+	} while (0);
+
+/*
+ * Accessors for SMP based variables.
+ */
+#define _SWAPS(p) ((p)->cnts[smp_processor_id()].swaps)
+#define _CYCLES(p) ((p)->cnts[smp_processor_id()].cycles)
+#define _COUNTS(p, i) ((p)->cnts[smp_processor_id()].counts[i])
+#define _L2COUNTS(p, i) ((p)->cnts[smp_processor_id()].l2_counts[i])
+#define _L2CYCLES(p) ((p)->cnts[smp_processor_id()].l2_cycles)
+
+/*
+  Type Declarations
+*/
+
+/*
+ * Counts are on a per core basis.
+ */
+struct pm_counters_s {
+  unsigned long long  cycles;
+  unsigned long long  l2_cycles;
+  unsigned long long  counts[PERF_NUM_MONITORS];
+  unsigned long long  l2_counts[PERF_NUM_MONITORS];
+  unsigned long  swaps;
+};
+
+struct per_process_perf_mon_type{
+  struct pm_counters_s cnts[NR_CPUS];
+  unsigned long  control;
+  unsigned long  index[PERF_NUM_MONITORS];
+  unsigned long  l2_index[PERF_NUM_MONITORS];
+  unsigned long  pid;
+  struct proc_dir_entry *proc;
+  struct proc_dir_entry *l2_proc;
+  unsigned short flags;
+  unsigned short running_cpu;
+  char           *pidName;
+  unsigned long lpm0evtyper;
+  unsigned long lpm1evtyper;
+  unsigned long lpm2evtyper;
+  unsigned long l2lpmevtyper;
+  unsigned long vlpmevtyper;
+  unsigned long l2pmevtyper0;
+  unsigned long l2pmevtyper1;
+  unsigned long l2pmevtyper2;
+  unsigned long l2pmevtyper3;
+  unsigned long l2pmevtyper4;
+};
+
+unsigned long last_in_pid[NR_CPUS];
+unsigned long fake_swap_out[NR_CPUS] = {0};
+
+/*
+  Local Object Definitions
+*/
+struct per_process_perf_mon_type perf_mons[PERF_MON_PROCESS_NUM];
+struct proc_dir_entry *proc_dir;
+struct proc_dir_entry *settings_dir;
+struct proc_dir_entry *values_dir;
+struct proc_dir_entry *axi_dir;
+struct proc_dir_entry *l2_dir;
+struct proc_dir_entry *axi_settings_dir;
+struct proc_dir_entry *axi_results_dir;
+struct proc_dir_entry *l2_results_dir;
+
+unsigned long pp_enabled;
+unsigned long pp_settings_valid = -1;
+unsigned long pp_auto_lock;
+unsigned long pp_set_pid;
+signed long pp_clear_pid = -1;
+unsigned long per_proc_event[PERF_NUM_MONITORS];
+unsigned long l2_per_proc_event[PERF_NUM_MONITORS];
+unsigned long dbg_flags;
+unsigned long pp_lpm0evtyper;
+unsigned long pp_lpm1evtyper;
+unsigned long pp_lpm2evtyper;
+unsigned long pp_l2lpmevtyper;
+unsigned long pp_vlpmevtyper;
+unsigned long pm_stop_for_interrupts;
+unsigned long pm_global;   /* track all, not process based */
+unsigned long pm_global_enable;
+unsigned long pm_remove_pid;
+
+unsigned long pp_l2pmevtyper0;
+unsigned long pp_l2pmevtyper1;
+unsigned long pp_l2pmevtyper2;
+unsigned long pp_l2pmevtyper3;
+unsigned long pp_l2pmevtyper4;
+
+unsigned long pp_proc_entry_index;
+char *per_process_proc_names[PP_MAX_PROC_ENTRIES];
+
+unsigned int axi_swaps;
+#define MAX_AXI_SWAPS	10
+int first_switch = 1;
+/*
+  Forward Declarations
+*/
+
+/*
+Function Definitions
+*/
+
+/*
+FUNCTION  per_process_find
+
+DESCRIPTION
+  Find the per process information based on the process id (pid) passed.
+  This is a simple mask based on the number of entries stored in the
+  static array
+
+DEPENDENCIES
+
+RETURN VALUE
+  Pointer to the per process data
+SIDE EFFECTS
+
+*/
+struct per_process_perf_mon_type *per_process_find(unsigned long pid)
+{
+  return &perf_mons[pid & PERF_MON_PROCESS_MASK];
+}
+
+/*
+FUNCTION  per_process_get_name
+
+DESCRIPTION
+  Retreive the name of the performance counter based on the table and
+  index passed.  We have two different sets of performance counters so
+  different table need to be used.
+
+DEPENDENCIES
+
+RETURN VALUE
+  Pointer to char string with the name of the event or "BAD"
+  Never returns NULL or a bad pointer.
+
+SIDE EFFECTS
+*/
+char *per_process_get_name(unsigned long index)
+{
+  return pm_find_event_name(index);
+}
+
+/*
+FUNCTION per_process_results_read
+
+DESCRIPTION
+  Print out the formatted results from the process id read.  Event names
+  and counts are printed.
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+int per_process_results_read(char *page, char **start, off_t off, int count,
+   int *eof, void *data)
+{
+	struct per_process_perf_mon_type *p =
+		(struct per_process_perf_mon_type *)data;
+	struct pm_counters_s cnts;
+	int i, j;
+
+	/*
+	* Total across all CPUS
+	*/
+	memset(&cnts, 0, sizeof(cnts));
+	for (i = 0; i < num_possible_cpus(); i++) {
+		cnts.swaps += p->cnts[i].swaps;
+		cnts.cycles += p->cnts[i].cycles;
+		for (j = 0; j < PERF_NUM_MONITORS; j++)
+			cnts.counts[j] += p->cnts[i].counts[j];
+	}
+
+	/*
+	* Display as single results of the totals calculated above.
+	* Do we want to display or have option to display individula cores?
+	*/
+	return sprintf(page, "pid:%lu one:%s:%llu two:%s:%llu three:%s:%llu \
+	four:%s:%llu cycles:%llu swaps:%lu\n",
+	p->pid,
+	per_process_get_name(p->index[0]), cnts.counts[0],
+	per_process_get_name(p->index[1]), cnts.counts[1],
+	per_process_get_name(p->index[2]), cnts.counts[2],
+	per_process_get_name(p->index[3]), cnts.counts[3],
+	cnts.cycles, cnts.swaps);
+}
+
+int per_process_l2_results_read(char *page, char **start, off_t off, int count,
+   int *eof, void *data)
+{
+  struct per_process_perf_mon_type *p =
+	(struct per_process_perf_mon_type *)data;
+	struct pm_counters_s cnts;
+	int i, j;
+
+	/*
+	* Total across all CPUS
+	*/
+	memset(&cnts, 0, sizeof(cnts));
+	for (i = 0; i < num_possible_cpus(); i++) {
+		cnts.l2_cycles += p->cnts[i].l2_cycles;
+		for (j = 0; j < PERF_NUM_MONITORS; j++)
+			cnts.l2_counts[j] += p->cnts[i].l2_counts[j];
+	}
+
+  /*
+   * Display as single results of the totals calculated above.
+   * Do we want to display or have option to display individula cores?
+   */
+   return sprintf(page, "pid:%lu l2_one:%s:%llu l2_two:%s:%llu \
+	l2_three:%s:%llu \
+	l2_four:%s:%llu l2_cycles:%llu\n",
+     p->pid,
+     per_process_get_name(p->l2_index[0]), cnts.l2_counts[0],
+     per_process_get_name(p->l2_index[1]), cnts.l2_counts[1],
+     per_process_get_name(p->l2_index[2]), cnts.l2_counts[2],
+     per_process_get_name(p->l2_index[3]), cnts.l2_counts[3],
+     cnts.l2_cycles);
+}
+
+/*
+FUNCTION  per_process_results_write
+
+DESCRIPTION
+  Allow some control over the results.  If the user forgets to autolock or
+  wants to unlock the results so they will be deleted, then this is
+  where it is processed.
+
+  For example, to unlock process 23
+  echo "unlock" > 23
+
+DEPENDENCIES
+
+RETURN VALUE
+  Number of characters used (all of them!)
+
+SIDE EFFECTS
+*/
+int per_process_results_write(struct file *file, const char *buff,
+    unsigned long cnt, void *data)
+{
+  char *newbuf;
+  struct per_process_perf_mon_type *p =
+	(struct per_process_perf_mon_type *)data;
+
+	if (p == 0)
+		return cnt;
+	/*
+	* Alloc the user data in kernel space. and then copy user to kernel
+	*/
+	newbuf = kmalloc(cnt + 1, GFP_KERNEL);
+	if (0 == newbuf)
+		return cnt;
+	if (copy_from_user(newbuf, buff, cnt) != 0) {
+		printk(KERN_INFO "%s copy_from_user failed\n", __func__);
+		return cnt;
+	}
+
+	if (0 == strcmp("lock", newbuf))
+		p->flags |= PERF_ENTRY_LOCKED;
+	else if (0 == strcmp("unlock", newbuf))
+		p->flags &= ~PERF_ENTRY_LOCKED;
+	else if (0 == strcmp("auto", newbuf))
+		p->flags |= PERF_AUTOLOCK;
+	else if (0 == strcmp("autoun", newbuf))
+		p->flags &= ~PERF_AUTOLOCK;
+
+	return cnt;
+}
+
+/*
+FUNCTION  perProcessCreateResults
+
+DESCRIPTION
+  Create the results /proc file if the system parameters allow it...
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+void per_process_create_results_proc(struct per_process_perf_mon_type *p)
+{
+
+	if (0 == p->pidName)
+		p->pidName = kmalloc(12, GFP_KERNEL);
+	if (0 == p->pidName)
+		return;
+	sprintf(p->pidName, "%ld", p->pid);
+
+	if (0 == p->proc) {
+		p->proc = create_proc_entry(p->pidName, 0777, values_dir);
+		if (0 == p->proc)
+			return;
+	} else {
+		p->proc->name = p->pidName;
+	}
+
+	p->proc->read_proc = per_process_results_read;
+	p->proc->write_proc = per_process_results_write;
+	p->proc->data = (void *)p;
+}
+
+void per_process_create_l2_results_proc(struct per_process_perf_mon_type *p)
+{
+
+	if (0 == p->pidName)
+		p->pidName = kmalloc(12, GFP_KERNEL);
+	if (0 == p->pidName)
+		return;
+	sprintf(p->pidName, "%ld", p->pid);
+
+	if (0 == p->l2_proc) {
+		p->l2_proc = create_proc_entry(p->pidName, 0777,
+			l2_results_dir);
+		if (0 == p->l2_proc)
+			return;
+	} else {
+		p->l2_proc->name = p->pidName;
+	}
+
+	p->l2_proc->read_proc = per_process_l2_results_read;
+	p->l2_proc->write_proc = per_process_results_write;
+	p->l2_proc->data = (void *)p;
+}
+/*
+FUNCTION per_process_swap_out
+
+DESCRIPTION
+  Store the counters from the process that is about to swap out.  We take
+  the old counts and add them to the current counts in the perf registers.
+  Before the new process is swapped in, the counters are reset.
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+typedef void (*vfun)(void *);
+void per_process_swap_out(struct per_process_perf_mon_type *data)
+{
+	int i;
+	unsigned long overflow;
+#ifdef CONFIG_ARCH_MSM8X60
+	unsigned long l2_overflow;
+#endif
+	struct per_process_perf_mon_type *p = data;
+
+	MARKPIDS('O', p->pid, 0);
+	RCP15_PMOVSR(overflow);
+#ifdef CONFIG_ARCH_MSM8X60
+	RCP15_L2PMOVSR(l2_overflow);
+#endif
+
+	if (!pp_enabled)
+		return;
+
+	/*
+	* The kernel for some reason (2.6.32.9) starts a process context on
+	* one core and ends on another.  So the swap in and swap out can be
+	* on different cores.  If this happens, we need to stop the
+	* counters and collect the data on the core that started the counters
+	* ....otherwise we receive invalid data.  So we mark the the core with
+	* the process as deferred.  The next time a process is swapped on
+	* the core that the process was running on, the counters will be
+	* updated.
+	*/
+	if ((smp_processor_id() != p->running_cpu) && (p->pid != 0)) {
+		fake_swap_out[p->running_cpu] = 1;
+		return;
+	}
+
+	_SWAPS(p)++;
+	_CYCLES(p) += pm_get_cycle_count();
+
+	if (overflow & PM_CYCLE_OVERFLOW_MASK)
+		_CYCLES(p) += 0xFFFFFFFF;
+
+	for (i = 0; i < PERF_NUM_MONITORS; i++) {
+		_COUNTS(p, i) += pm_get_count(i);
+		if (overflow & (1 << i))
+			_COUNTS(p, i) += 0xFFFFFFFF;
+	}
+
+#ifdef CONFIG_ARCH_MSM8X60
+	_L2CYCLES(p) += l2_pm_get_cycle_count();
+	if (l2_overflow & L2_PM_CYCLE_OVERFLOW_MASK)
+		_L2CYCLES(p) += 0xFFFFFFFF;
+	for (i = 0; i < PERF_NUM_MONITORS; i++) {
+		_L2COUNTS(p, i) += l2_pm_get_count(i);
+		if (l2_overflow & (1 << i))
+			_L2COUNTS(p, i) += 0xFFFFFFFF;
+	}
+#endif
+}
+
+/*
+FUNCTION per_process_remove_manual
+
+DESCRIPTION
+  Remove an entry from the results directory if the flags allow this.
+  When not enbled or the entry is locked, the values/results will
+  not be removed.
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+void per_process_remove_manual(unsigned long pid)
+{
+	struct per_process_perf_mon_type *p = per_process_find(pid);
+
+	/*
+	* Check all of the flags to see if we can remove this one
+	* Then mark as not used
+	*/
+	if (0 == p)
+		return;
+	p->pid = (0xFFFFFFFF);
+
+	/*
+	* Remove the proc entry.
+	*/
+	if (p->proc)
+		remove_proc_entry(p->pidName, values_dir);
+	if (p->l2_proc)
+		remove_proc_entry(p->pidName, l2_results_dir);
+	kfree(p->pidName);
+
+	/*
+	* Clear them out...and ensure the pid is invalid
+	*/
+	memset(p, 0, sizeof *p);
+	p->pid = 0xFFFFFFFF;
+	pm_remove_pid = -1;
+}
+
+/*
+* Remove called when a process exits...
+*/
+void _per_process_remove(unsigned long pid) {}
+
+/*
+FUNCTION  per_process_initialize
+
+DESCRIPTION
+Initialize performance collection information for a new process.
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+May create a new proc entry
+*/
+void per_process_initialize(struct per_process_perf_mon_type *p,
+				unsigned long pid)
+{
+	int i;
+
+	/*
+	* See if this is the pid we are interested in...
+	*/
+	if (pp_settings_valid == -1)
+		return;
+	if ((pp_set_pid != pid) && (pp_set_pid != 0))
+		return;
+
+	/*
+	* Clear out the statistics table then insert this pid
+	* We want to keep the proc entry and the name
+	*/
+	p->pid = pid;
+
+	/*
+	* Create a proc entry for this pid, then get the current event types and
+	* store in data struct so when the process is switched in we can track
+	* it.
+	*/
+	if (p->proc == 0) {
+		per_process_create_results_proc(p);
+#ifdef CONFIG_ARCH_MSM8X60
+		per_process_create_l2_results_proc(p);
+#endif
+	}
+	_CYCLES(p) = 0;
+	_L2CYCLES(p) = 0;
+	_SWAPS(p) = 0;
+	/*
+	* Set the per process data struct, but not the monitors until later...
+	* Init only happens with the user sets the SetPID variable to this pid
+	* so we can load new values.
+	*/
+	for (i = 0; i < PERF_NUM_MONITORS; i++) {
+		p->index[i] = per_proc_event[i];
+#ifdef CONFIG_ARCH_MSM8X60
+		p->l2_index[i] = l2_per_proc_event[i];
+#endif
+		_COUNTS(p, i) = 0;
+		_L2COUNTS(p, i) = 0;
+	}
+	p->lpm0evtyper  = pp_lpm0evtyper;
+	p->lpm1evtyper  = pp_lpm1evtyper;
+	p->lpm2evtyper  = pp_lpm2evtyper;
+	p->l2lpmevtyper = pp_l2lpmevtyper;
+	p->vlpmevtyper  = pp_vlpmevtyper;
+
+#ifdef CONFIG_ARCH_MSM8X60
+	p->l2pmevtyper0  = pp_l2pmevtyper0;
+	p->l2pmevtyper1  = pp_l2pmevtyper1;
+	p->l2pmevtyper2  = pp_l2pmevtyper2;
+	p->l2pmevtyper3  = pp_l2pmevtyper3;
+	p->l2pmevtyper4  = pp_l2pmevtyper4;
+#endif
+
+	/*
+	* Reset pid and settings value
+	*/
+	pp_set_pid = -1;
+	pp_settings_valid = -1;
+}
+
+/*
+FUNCTION  per_process_swap_in
+
+DESCRIPTION
+  Called when a context switch is about to start this PID.
+  We check to see if this process has an entry or not and create one
+  if not locked...
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+void per_process_swap_in(struct per_process_perf_mon_type *p_new,
+				unsigned long pid)
+{
+	int i;
+
+	MARKPIDS('I', p_new->pid, 0);
+	/*
+	* If the set proc variable == the current pid then init a new
+	* entry...
+	*/
+	if (pp_set_pid == pid)
+		per_process_initialize(p_new, pid);
+
+	p_new->running_cpu = smp_processor_id();
+	last_in_pid[smp_processor_id()] = pid;
+
+	/*
+	* setup the monitors for this process.
+	*/
+	for (i = 0; i < PERF_NUM_MONITORS; i++) {
+		pm_set_event(i, p_new->index[i]);
+#ifdef CONFIG_ARCH_MSM8X60
+		l2_pm_set_event(i, p_new->l2_index[i]);
+#endif
+	}
+	pm_set_local_iu(p_new->lpm0evtyper);
+	pm_set_local_xu(p_new->lpm1evtyper);
+	pm_set_local_su(p_new->lpm2evtyper);
+	pm_set_local_l2(p_new->l2lpmevtyper);
+
+#ifdef CONFIG_ARCH_MSM8X60
+	pm_set_local_bu(p_new->l2pmevtyper0);
+	pm_set_local_cb(p_new->l2pmevtyper1);
+	pm_set_local_mp(p_new->l2pmevtyper2);
+	pm_set_local_sp(p_new->l2pmevtyper3);
+	pm_set_local_scu(p_new->l2pmevtyper4);
+#endif
+}
+
+/*
+FUNCTION  perProcessSwitch
+
+DESCRIPTION
+  Called during context switch.  Updates the counts on the process about to
+  be swapped out and brings in the counters for the process about to be
+  swapped in.
+
+  All is dependant on the enabled and lock flags.
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+
+DEFINE_SPINLOCK(pm_lock);
+void _per_process_switch(unsigned long old_pid, unsigned long new_pid)
+{
+  struct per_process_perf_mon_type *p_old, *p_new;
+
+	if (pm_global_enable == 0)
+		return;
+
+	spin_lock(&pm_lock);
+
+	pm_stop_all();
+#ifdef CONFIG_ARCH_MSM8X60
+	l2_pm_stop_all();
+#endif
+
+	/*
+	 * We detected that the process was swapped in on one core and out on
+	 * a different core.  This does not allow us to stop and stop counters
+	 * properly so we need to defer processing.  This checks to see if there
+	 * is any defered processing necessary. And does it... */
+	if (fake_swap_out[smp_processor_id()] != 0) {
+		fake_swap_out[smp_processor_id()] = 0;
+		p_old = per_process_find(last_in_pid[smp_processor_id()]);
+		last_in_pid[smp_processor_id()] = 0;
+		if (p_old != 0)
+			per_process_swap_out(p_old);
+	}
+
+	/*
+	* Clear the data collected so far for this process?
+	*/
+	if (pp_clear_pid != -1) {
+		struct per_process_perf_mon_type *p_clear =
+			per_process_find(pp_clear_pid);
+		if (p_clear) {
+			memset(p_clear->cnts, 0,
+			sizeof(struct pm_counters_s)*num_possible_cpus());
+			printk(KERN_INFO "Clear Per Processor Stats for \
+				PID:%ld\n", pp_clear_pid);
+			pp_clear_pid = -1;
+		}
+	}
+       /*
+       * Always collect for 0, it collects for all.
+       */
+       if (pp_enabled) {
+		if (first_switch == 1) {
+			per_process_initialize(&perf_mons[0], 0);
+			first_switch = 0;
+		}
+		if (pm_global) {
+			per_process_swap_out(&perf_mons[0]);
+			per_process_swap_in(&perf_mons[0], 0);
+		} else {
+			p_old = per_process_find(old_pid);
+			p_new = per_process_find(new_pid);
+
+
+			/*
+			* save the old counts to the old data struct, if the
+			* returned ptr is NULL or the process id passed is not
+			* the same as the process id in the data struct then
+			* don't update the data.
+			*/
+			if ((p_old) && (p_old->pid == old_pid) &&
+				(p_old->pid != 0)) {
+				per_process_swap_out(p_old);
+			}
+
+	/*
+	* Setup the counters for the new process
+	*/
+	if (pp_set_pid == new_pid)
+		per_process_initialize(p_new, new_pid);
+	if ((p_new->pid == new_pid) && (new_pid != 0))
+		per_process_swap_in(p_new, new_pid);
+	}
+		pm_reset_all();
+#ifdef CONFIG_ARCH_MSM8X60
+	l2_pm_reset_all();
+#endif
+#ifdef CONFIG_ARCH_QSD8X50
+		axi_swaps++;
+		if (axi_swaps%pm_axi_info.refresh == 0) {
+			if (pm_axi_info.clear == 1) {
+				pm_axi_clear_cnts();
+					pm_axi_info.clear = 0;
+				}
+				if (pm_axi_info.enable == 0)
+					pm_axi_disable();
+				else
+					pm_axi_update_cnts();
+				axi_swaps = 0;
+		}
+#endif
+	}
+	pm_start_all();
+#ifdef CONFIG_ARCH_MSM8X60
+	l2_pm_start_all();
+#endif
+
+    spin_unlock(&pm_lock);
+}
+
+/*
+FUNCTION  pmInterruptIn
+
+DESCRIPTION
+  Called when an interrupt is being processed.  If the pmStopForInterrutps
+  flag is non zero then we disable the counting of performance monitors.
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+static int pm_interrupt_nesting_count;
+static unsigned long pm_cycle_in, pm_cycle_out;
+void _perf_mon_interrupt_in(void)
+{
+	if (pm_global_enable == 0)
+		return;
+	if (pm_stop_for_interrupts == 0)
+		return;
+	pm_interrupt_nesting_count++;	/* Atomic */
+	pm_stop_all();
+	pm_cycle_in = pm_get_cycle_count();
+}
+
+/*
+FUNCTION perfMonInterruptOut
+
+DESCRIPTION
+  Reenable performance monitor counting whn the nest count goes to zero
+  provided the counting has been stoped
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+void _perf_mon_interrupt_out(void)
+{
+	if (pm_global_enable == 0)
+		return;
+	if (pm_stop_for_interrupts == 0)
+		return;
+	--pm_interrupt_nesting_count;  /* Atomic?? */
+
+	if (pm_interrupt_nesting_count <= 0) {
+		pm_cycle_out = pm_get_cycle_count();
+		if (pm_cycle_in != pm_cycle_out)
+			printk(KERN_INFO "pmIn!=pmOut in:%lx out:%lx\n",
+			pm_cycle_in, pm_cycle_out);
+		if (pp_enabled) {
+			pm_start_all();
+#ifdef CONFIG_ARCH_MSM8X60
+			l2_pm_start_all();
+#endif
+		}
+		pm_interrupt_nesting_count = 0;
+	}
+}
+
+void per_process_do_global(unsigned long g)
+{
+	pm_global = g;
+
+	if (pm_global == 1) {
+		pm_stop_all();
+#ifdef CONFIG_ARCH_MSM8X60
+		l2_pm_stop_all();
+#endif
+		pm_reset_all();
+#ifdef CONFIG_ARCH_MSM8X60
+		l2_pm_reset_all();
+#endif
+		pp_set_pid = 0;
+		per_process_swap_in(&perf_mons[0], 0);
+		pm_start_all();
+#ifdef CONFIG_ARCH_MSM8X60
+		l2_pm_start_all();
+#endif
+	} else {
+		pm_stop_all();
+#ifdef CONFIG_ARCH_MSM8X60
+		l2_pm_stop_all();
+#endif
+	}
+}
+
+
+/*
+FUNCTION   per_process_write
+
+DESCRIPTION
+  Generic routine to handle any of the settings /proc directory writes.
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+int per_process_write(struct file *file, const char *buff,
+    unsigned long cnt, void *data, const char *fmt)
+{
+	char *newbuf;
+	unsigned long *d = (unsigned long *)data;
+
+	/*
+	* Alloc the user data in kernel space. and then copy user to kernel
+	*/
+	newbuf = kmalloc(cnt + 1, GFP_KERNEL);
+	if (0 == newbuf)
+		return PM_PP_ERR;
+	if (copy_from_user(newbuf, buff, cnt) != 0) {
+		printk(KERN_INFO "%s copy_from_user failed\n", __func__);
+	return cnt;
+	}
+	sscanf(newbuf, fmt, d);
+	kfree(newbuf);
+
+	/*
+	* If this is a remove  command then do it now...
+	*/
+	if (d == &pm_remove_pid)
+		per_process_remove_manual(*d);
+	if (d == &pm_global)
+		per_process_do_global(*d);
+	return cnt;
+}
+
+int per_process_write_dec(struct file *file, const char *buff,
+    unsigned long cnt, void *data)
+{
+	return per_process_write(file, buff, cnt, data, "%ld");
+}
+
+int per_process_write_hex(struct file *file, const char *buff,
+    unsigned long cnt, void *data)
+{
+	return per_process_write(file, buff, cnt, data, "%lx");
+}
+
+/*
+FUNCTION per_process_read
+
+DESCRIPTION
+  Generic read handler for the /proc settings directory.
+
+DEPENDENCIES
+
+RETURN VALUE
+  Number of characters to output.
+
+SIDE EFFECTS
+*/
+int per_process_read(char *page, char **start, off_t off, int count,
+   int *eof, void *data)
+{
+	unsigned long *d = (unsigned long *)data;
+	return sprintf(page, "%lx", *d);
+}
+
+int per_process_read_decimal(char *page, char **start, off_t off, int count,
+   int *eof, void *data)
+{
+	unsigned long *d = (unsigned long *)data;
+	return sprintf(page, "%ld", *d);
+}
+
+/*
+FUNCTION  per_process_proc_entry
+
+DESCRIPTION
+  Create a generic entry for the /proc settings directory.
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+void per_process_proc_entry(char *name, unsigned long *var,
+    struct proc_dir_entry *d, int hex)
+{
+	struct proc_dir_entry *pe;
+
+	pe = create_proc_entry(name, 0777, d);
+	if (0 == pe)
+		return;
+	if (hex) {
+		pe->read_proc = per_process_read;
+		pe->write_proc = per_process_write_hex;
+	} else {
+		pe->read_proc = per_process_read_decimal;
+		pe->write_proc = per_process_write_dec;
+	}
+	pe->data = (void *)var;
+
+	if (pp_proc_entry_index >= PP_MAX_PROC_ENTRIES) {
+		printk(KERN_INFO "PERF: proc entry overflow,\
+		memleak on module unload occured");
+	return;
+	}
+	per_process_proc_names[pp_proc_entry_index++] = name;
+}
+
+static int perfmon_notifier(struct notifier_block *self, unsigned long cmd,
+	void *v)
+{
+	static int old_pid = -1;
+	struct thread_info *thread = v;
+	int current_pid;
+
+	if (cmd != THREAD_NOTIFY_SWITCH)
+		return old_pid;
+
+	current_pid = thread->task->pid;
+	if (old_pid != -1)
+		_per_process_switch(old_pid, current_pid);
+	old_pid = current_pid;
+	return old_pid;
+}
+
+static struct notifier_block perfmon_notifier_block = {
+	.notifier_call  = perfmon_notifier,
+};
+
+/*
+FUNCTION  per_process_perf_init
+
+DESCRIPTION
+  Initialze the per process performance monitor variables and /proc space.
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+int per_process_perf_init(void)
+{
+#ifdef CONFIG_ARCH_MSM8X60
+	smp_call_function_single(0, (void *)pm_initialize, (void *)NULL, 1);
+	smp_call_function_single(1, (void *)pm_initialize, (void *)NULL, 1);
+	l2_pm_initialize();
+#else
+	pm_initialize();
+#endif
+	pm_axi_init();
+	pm_axi_clear_cnts();
+	proc_dir = proc_mkdir("ppPerf", NULL);
+	values_dir = proc_mkdir("results", proc_dir);
+	settings_dir = proc_mkdir("settings", proc_dir);
+	per_process_proc_entry("enable", &pp_enabled, settings_dir, 1);
+	per_process_proc_entry("valid", &pp_settings_valid, settings_dir, 1);
+	per_process_proc_entry("setPID", &pp_set_pid, settings_dir, 0);
+	per_process_proc_entry("clearPID", &pp_clear_pid, settings_dir, 0);
+	per_process_proc_entry("event0", &per_proc_event[0], settings_dir, 1);
+	per_process_proc_entry("event1", &per_proc_event[1], settings_dir, 1);
+	per_process_proc_entry("event2", &per_proc_event[2], settings_dir, 1);
+	per_process_proc_entry("event3", &per_proc_event[3], settings_dir, 1);
+	per_process_proc_entry("l2_event0", &l2_per_proc_event[0], settings_dir,
+		1);
+	per_process_proc_entry("l2_event1", &l2_per_proc_event[1], settings_dir,
+		1);
+	per_process_proc_entry("l2_event2", &l2_per_proc_event[2], settings_dir,
+		1);
+	per_process_proc_entry("l2_event3", &l2_per_proc_event[3], settings_dir,
+		1);
+	per_process_proc_entry("debug", &dbg_flags, settings_dir, 1);
+	per_process_proc_entry("autolock", &pp_auto_lock, settings_dir, 1);
+	per_process_proc_entry("lpm0evtyper", &pp_lpm0evtyper, settings_dir, 1);
+	per_process_proc_entry("lpm1evtyper", &pp_lpm1evtyper, settings_dir, 1);
+	per_process_proc_entry("lpm2evtyper", &pp_lpm2evtyper, settings_dir, 1);
+	per_process_proc_entry("l2lpmevtyper", &pp_l2lpmevtyper, settings_dir,
+				1);
+	per_process_proc_entry("vlpmevtyper", &pp_vlpmevtyper, settings_dir, 1);
+	per_process_proc_entry("l2pmevtyper0", &pp_l2pmevtyper0, settings_dir,
+		1);
+	per_process_proc_entry("l2pmevtyper1", &pp_l2pmevtyper1, settings_dir,
+		1);
+	per_process_proc_entry("l2pmevtyper2", &pp_l2pmevtyper2, settings_dir,
+		1);
+	per_process_proc_entry("l2pmevtyper3", &pp_l2pmevtyper3, settings_dir,
+		1);
+	per_process_proc_entry("l2pmevtyper4", &pp_l2pmevtyper4, settings_dir,
+		1);
+	per_process_proc_entry("stopForInterrupts", &pm_stop_for_interrupts,
+		settings_dir, 1);
+	per_process_proc_entry("global", &pm_global, settings_dir, 1);
+	per_process_proc_entry("globalEnable", &pm_global_enable, settings_dir,
+				1);
+	per_process_proc_entry("removePID", &pm_remove_pid, settings_dir, 0);
+
+	axi_dir = proc_mkdir("axi", proc_dir);
+	axi_settings_dir = proc_mkdir("settings", axi_dir);
+	axi_results_dir = proc_mkdir("results", axi_dir);
+	pm_axi_set_proc_entry("axi_enable", &pm_axi_info.enable,
+		axi_settings_dir, 1);
+	pm_axi_set_proc_entry("axi_clear", &pm_axi_info.clear, axi_settings_dir,
+		0);
+	pm_axi_set_proc_entry("axi_valid", &pm_axi_info.valid, axi_settings_dir,
+		1);
+	pm_axi_set_proc_entry("axi_sel_reg0", &pm_axi_info.sel_reg0,
+		axi_settings_dir, 1);
+	pm_axi_set_proc_entry("axi_sel_reg1", &pm_axi_info.sel_reg1,
+		axi_settings_dir, 1);
+	pm_axi_set_proc_entry("axi_ten_sel", &pm_axi_info.ten_sel_reg,
+		axi_settings_dir, 1);
+	pm_axi_set_proc_entry("axi_refresh", &pm_axi_info.refresh,
+		axi_settings_dir, 1);
+	pm_axi_get_cnt_proc_entry("axi_cnts", &axi_cnts, axi_results_dir, 0);
+	l2_dir = proc_mkdir("l2", proc_dir);
+	l2_results_dir = proc_mkdir("results", l2_dir);
+
+	memset(perf_mons, 0, sizeof(perf_mons));
+	per_process_create_results_proc(&perf_mons[0]);
+	per_process_create_l2_results_proc(&perf_mons[0]);
+	thread_register_notifier(&perfmon_notifier_block);
+	/*
+	* Set the function pointers so the module can be activated.
+	*/
+	pp_interrupt_out_ptr = _perf_mon_interrupt_out;
+	pp_interrupt_in_ptr  = _perf_mon_interrupt_in;
+	pp_process_remove_ptr = _per_process_remove;
+	pp_loaded = 1;
+	pm_axi_info.refresh = 1;
+
+#ifdef CONFIG_ARCH_MSM8X60
+	smp_call_function_single(0, (void *)pm_reset_all, (void *)NULL, 1);
+	smp_call_function_single(1, (void *)pm_reset_all, (void *)NULL, 1);
+	smp_call_function_single(0, (void *)l2_pm_reset_all, (void *)NULL, 1);
+	smp_call_function_single(1, (void *)l2_pm_reset_all, (void *)NULL, 1);
+#else
+	pm_reset_all();
+#endif
+
+	return 0;
+}
+
+/*
+FUNCTION  per_process_perf_exit
+
+DESCRIPTION
+  Module exit functionm, clean up, renmove proc entries
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+  No more per process
+*/
+void per_process_perf_exit(void)
+{
+	unsigned long i;
+	/*
+	* Sert the function pointers to 0 so the functions will no longer
+	* be invoked
+	*/
+	pp_loaded = 0;
+	pp_interrupt_out_ptr = 0;
+	pp_interrupt_in_ptr  = 0;
+	pp_process_remove_ptr = 0;
+	/*
+	* Remove the results
+	*/
+	for (i = 0; i < PERF_MON_PROCESS_NUM; i++)
+		per_process_remove_manual(perf_mons[i].pid);
+	/*
+	* Remove the proc entries in the settings dir
+	*/
+	i = 0;
+	for (i = 0; i < pp_proc_entry_index; i++)
+		remove_proc_entry(per_process_proc_names[i], settings_dir);
+
+	/*remove proc axi files*/
+	remove_proc_entry("axi_enable", axi_settings_dir);
+	remove_proc_entry("axi_valid", axi_settings_dir);
+	remove_proc_entry("axi_refresh", axi_settings_dir);
+	remove_proc_entry("axi_clear", axi_settings_dir);
+	remove_proc_entry("axi_sel_reg0", axi_settings_dir);
+	remove_proc_entry("axi_sel_reg1", axi_settings_dir);
+	remove_proc_entry("axi_ten_sel", axi_settings_dir);
+	remove_proc_entry("axi_cnts", axi_results_dir);
+	/*
+	* Remove the directories
+	*/
+	remove_proc_entry("results", l2_dir);
+	remove_proc_entry("l2", proc_dir);
+	remove_proc_entry("results", proc_dir);
+	remove_proc_entry("settings", proc_dir);
+	remove_proc_entry("results", axi_dir);
+	remove_proc_entry("settings", axi_dir);
+	remove_proc_entry("axi", proc_dir);
+	remove_proc_entry("ppPerf", NULL);
+	pm_free_irq();
+#ifdef CONFIG_ARCH_MSM8X60
+	l2_pm_free_irq();
+#endif
+	thread_unregister_notifier(&perfmon_notifier_block);
+#ifdef CONFIG_ARCH_MSM8X60
+	smp_call_function_single(0, (void *)pm_deinitialize, (void *)NULL, 1);
+	smp_call_function_single(1, (void *)pm_deinitialize, (void *)NULL, 1);
+	l2_pm_deinitialize();
+#else
+	pm_deinitialize();
+#endif
+}
diff --git a/arch/arm/perfmon/per.c b/arch/arm/perfmon/per.c
new file mode 100644
index 0000000..4222844
--- /dev/null
+++ b/arch/arm/perfmon/per.c
@@ -0,0 +1,59 @@
+/* Copyright (c) 2010, 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.
+ */
+
+/*
+per.c
+
+DESCRIPTION: Performance count interface for linux via proc in the T32
+command file style
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/sysrq.h>
+#include <linux/time.h>
+#include "linux/proc_fs.h"
+#include "linux/kernel_stat.h"
+#include "asm/uaccess.h"
+#include "cp15_registers.h"
+#include "perf.h"
+
+#define PM_PER_ERR -1
+/*
+FUNCTION perf_if_proc_init
+
+DESCRIPTION  Initialize the proc interface for thje performance data.
+*/
+static __init int per_init(void)
+{
+
+  if (atomic_read(&pm_op_lock) == 1) {
+	printk(KERN_INFO "Can not load KSAPI, monitors are in use\n");
+	return PM_PER_ERR;
+  }
+  atomic_set(&pm_op_lock, 1);
+  per_process_perf_init();
+  printk(KERN_INFO "ksapi init\n");
+  return 0;
+}
+
+static void __exit per_exit(void)
+{
+  per_process_perf_exit();
+  printk(KERN_INFO "ksapi exit\n");
+  atomic_set(&pm_op_lock, 0);
+}
+
+MODULE_LICENSE("GPL v2");
+module_init(per_init);
+module_exit(per_exit);
diff --git a/arch/arm/perfmon/perf-function-hooks.c b/arch/arm/perfmon/perf-function-hooks.c
new file mode 100644
index 0000000..aacc353
--- /dev/null
+++ b/arch/arm/perfmon/perf-function-hooks.c
@@ -0,0 +1,81 @@
+/* Copyright (c) 2010, 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.
+ */
+
+/*
+*  perf-function-hooks.c
+*  DESCRIPTION
+*  Hooks for ksapi.ko
+*/
+
+#include <linux/module.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/sysrq.h>
+#include <linux/time.h>
+#include "linux/proc_fs.h"
+#include "linux/kernel_stat.h"
+#include "asm/uaccess.h"
+#include <linux/proc_fs.h>
+#include "cp15_registers.h"
+#include <asm/perftypes.h>
+#include "perf.h"
+
+/*
+* Function Pointers for when the module is installed...
+* Should we use a single  "ready" variable for the testing
+* in the functions below, will be safer when module is removed
+* testing for a locked variable...
+*/
+VPVF pp_interrupt_out_ptr;
+VPVF pp_interrupt_in_ptr;
+VPULF pp_process_remove_ptr;
+unsigned int pp_loaded;
+EXPORT_SYMBOL(pp_loaded);
+atomic_t pm_op_lock;
+EXPORT_SYMBOL(pm_op_lock);
+
+/*
+FUNCTION  VARIOUS
+
+DESCRIPTION
+Hooks to callinto the module functions after they are loaded.  The
+above pointers will be set and then these functions are ready to be
+called.
+
+DEPENDENCIES
+THe per preocess performance monitor needs to be loaded ...
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+void perf_mon_interrupt_out(void)
+{
+  if (pp_loaded)
+	(*pp_interrupt_out_ptr)();
+}
+EXPORT_SYMBOL(pp_interrupt_out_ptr);
+
+void perf_mon_interrupt_in(void)
+{
+  if (pp_loaded)
+	(*pp_interrupt_in_ptr)();
+}
+EXPORT_SYMBOL(pp_interrupt_in_ptr);
+
+void per_process_remove(unsigned long pid)
+{
+  if (pp_loaded)
+		(*pp_process_remove_ptr)(pid);
+}
+EXPORT_SYMBOL(pp_process_remove_ptr);
diff --git a/arch/arm/perfmon/perf-smp.c b/arch/arm/perfmon/perf-smp.c
new file mode 100644
index 0000000..5417fc7
--- /dev/null
+++ b/arch/arm/perfmon/perf-smp.c
@@ -0,0 +1,751 @@
+/* Copyright (c) 2010, 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.
+ */
+
+/*
+perf-smp.c
+DESCRIPTION
+Manipulation, initialization of the ARMV7 Performance counter register.
+
+
+EXTERNALIZED FUNCTIONS
+
+INITIALIZATION AND SEQUENCING REQUIREMENTS
+*/
+
+/*
+INCLUDE FILES FOR MODULE
+*/
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/time.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include "l2_cp15_registers.h"
+
+/*
+DEFINITIONS AND DECLARATIONS FOR MODULE
+
+This section contains definitions for constants, macros, types, variables
+and other items needed by this module.
+*/
+
+/*
+  Constant / Define Declarations
+*/
+
+#define PM_NUM_COUNTERS 4
+#define L2_PM_ERR -1
+
+/*------------------------------------------------------------------------
+ * Global control bits
+------------------------------------------------------------------------*/
+#define PM_L2_GLOBAL_ENABLE     (1<<0)
+#define PM_L2_EVENT_RESET       (1<<1)
+#define PM_L2_CYCLE_RESET       (1<<2)
+#define PM_L2_CLKDIV            (1<<3)
+#define PM_L2_GLOBAL_TRACE      (1<<4)
+#define PM_L2_DISABLE_PROHIBIT  (1<<5)
+
+/*---------------------------------------------------------------------------
+ * Enable and clear bits for each event/trigger
+----------------------------------------------------------------------------*/
+#define PM_L2EV0_ENABLE        (1<<0)
+#define PM_L2EV1_ENABLE        (1<<1)
+#define PM_L2EV2_ENABLE        (1<<2)
+#define PM_L2EV3_ENABLE        (1<<3)
+#define PM_L2_COUNT_ENABLE      (1<<31)
+#define PM_L2_ALL_ENABLE        (0x8000000F)
+
+
+/*-----------------------------------------------------------------------------
+ * Overflow actions
+------------------------------------------------------------------------------*/
+#define PM_L2_OVERFLOW_NOACTION	(0)
+#define PM_L2_OVERFLOW_HALT	(1)
+#define PM_L2_OVERFLOW_STOP	(2)
+#define PM_L2_OVERFLOW_SKIP	(3)
+
+/*
+ * Shifts for each trigger type
+ */
+#define PM_STOP_SHIFT		24
+#define PM_RELOAD_SHIFT		22
+#define PM_RESUME_SHIFT		20
+#define PM_SUSPEND_SHIFT	18
+#define PM_START_SHIFT		16
+#define PM_STOPALL_SHIFT	15
+#define PM_STOPCOND_SHIFT	12
+#define PM_RELOADCOND_SHIFT	9
+#define PM_RESUMECOND_SHIFT	6
+#define PM_SUSPENDCOND_SHIFT	3
+#define PM_STARTCOND_SHIFT	0
+
+
+/*---------------------------------------------------------------------------
+External control register.  What todo when various events happen.
+Triggering events, etc.
+----------------------------------------------------------------------------*/
+#define PM_EXTTR0		0
+#define PM_EXTTR1		1
+#define PM_EXTTR2		2
+#define PM_EXTTR3		3
+
+#define PM_COND_NO_STOP		0
+#define PM_COND_STOP_CNTOVRFLW	1
+#define PM_COND_STOP_EXTERNAL	4
+#define PM_COND_STOP_TRACE	5
+#define PM_COND_STOP_EVOVRFLW	6
+#define PM_COND_STOP_EVTYPER	7
+
+/*--------------------------------------------------------------------------
+Protect against concurrent access.  There is an index register that is
+used to select the appropriate bank of registers.  If multiple processes
+are writting this at different times we could have a mess...
+---------------------------------------------------------------------------*/
+#define PM_LOCK()
+#define PM_UNLOCK()
+#define PRINT printk
+
+/*--------------------------------------------------------------------------
+The Event definitions
+--------------------------------------------------------------------------*/
+#define L2PM_EVT_PM0_EVT0	0x00
+#define L2PM_EVT_PM0_EVT1	0x01
+#define L2PM_EVT_PM0_EVT2	0x02
+#define L2PM_EVT_PM0_EVT3	0x03
+#define L2PM_EVT_PM1_EVT0	0x04
+#define L2PM_EVT_PM1_EVT1	0x05
+#define L2PM_EVT_PM1_EVT2	0x06
+#define L2PM_EVT_PM1_EVT3	0x07
+#define L2PM_EVT_PM2_EVT0	0x08
+#define L2PM_EVT_PM2_EVT1	0x09
+#define L2PM_EVT_PM2_EVT2	0x0a
+#define L2PM_EVT_PM2_EVT3	0x0b
+#define L2PM_EVT_PM3_EVT0	0x0c
+#define L2PM_EVT_PM3_EVT1	0x0d
+#define L2PM_EVT_PM3_EVT2	0x0e
+#define L2PM_EVT_PM3_EVT3	0x0f
+#define L2PM_EVT_PM4_EVT0	0x10
+#define L2PM_EVT_PM4_EVT1	0x11
+#define L2PM_EVT_PM4_EVT2	0x12
+#define L2PM_EVT_PM4_EVT3	0x13
+
+/*
+Type Declarations
+*/
+
+/*
+Local Object Definitions
+*/
+
+unsigned long l2_pm_cycle_overflow_count;
+unsigned long l2_pm_overflow_count[PM_NUM_COUNTERS];
+
+/*---------------------------------------------------------------------------
+Max number of events read from the config registers
+---------------------------------------------------------------------------*/
+static int pm_l2_max_events;
+
+static int irqid;
+
+/*
+Function Definitions
+*/
+
+/*
+FUNCTION  l2_pm_group_stop
+
+DESCRIPTION  Stop a group of the performance monitors.  Event monitor 0 is bit
+0, event monitor 1 bit 1, etc.  The cycle count can also be disable with
+bit 31.  Macros are provided for all of the indexes including an ALL.
+
+DEPENDENCIES
+
+RETURN VALUE
+None
+
+SIDE EFFECTS
+Stops the performance monitoring for the index passed.
+*/
+void pm_l2_group_stop(unsigned long mask)
+{
+	WCP15_L2PMCNTENCLR(mask);
+}
+
+/*
+FUNCTION  l2_pm_group_start
+
+DESCRIPTION  Start a group of the performance monitors.  Event monitor 0 is bit
+0, event monitor 1 bit 1, etc.  The cycle count can also be enabled with
+bit 31.  Macros are provided for all of the indexes including an ALL.
+
+DEPENDENCIES
+
+RETURN VALUE
+None
+
+SIDE EFFECTS
+Starts the performance monitoring for the index passed.
+*/
+void pm_l2_group_start(unsigned long mask)
+{
+	WCP15_L2PMCNTENSET(mask);
+}
+
+/*
+FUNCTION   l2_pm_get_overflow
+
+DESCRIPTION  Return the overflow condition for the index passed.
+
+DEPENDENCIES
+
+RETURN VALUE
+0 no overflow
+!0 (anything else) overflow;
+
+SIDE EFFECTS
+*/
+unsigned long l2_pm_get_overflow(int index)
+{
+  unsigned long overflow = 0;
+
+/*
+* Range check
+*/
+  if (index > pm_l2_max_events)
+	return L2_PM_ERR;
+  RCP15_L2PMOVSR(overflow);
+
+  return overflow & (1<<index);
+}
+
+/*
+FUNCTION  l2_pm_get_cycle_overflow
+
+DESCRIPTION
+Returns if the cycle counter has overflowed or not.
+
+DEPENDENCIES
+
+RETURN VALUE
+0 no overflow
+!0 (anything else) overflow;
+
+SIDE EFFECTS
+*/
+unsigned long l2_pm_get_cycle_overflow(void)
+{
+  unsigned long overflow = 0;
+
+  RCP15_L2PMOVSR(overflow);
+  return overflow & PM_L2_COUNT_ENABLE;
+}
+
+/*
+FUNCTION  l2_pm_reset_overflow
+
+DESCRIPTION Reset the cycle counter overflow bit.
+
+DEPENDENCIES
+
+RETURN VALUE
+None
+
+SIDE EFFECTS
+*/
+void l2_pm_reset_overflow(int index)
+{
+  WCP15_L2PMOVSR(1<<index);
+}
+
+/*
+FUNCTION  l2_pm_reset_cycle_overflow
+
+DESCRIPTION Reset the cycle counter overflow bit.
+
+DEPENDENCIES
+
+RETURN VALUE
+None
+
+SIDE EFFECTS
+*/
+void l2_pm_reset_cycle_overflow(void)
+{
+  WCP15_L2PMOVSR(PM_L2_COUNT_ENABLE);
+}
+
+/*
+FUNCTION l2_pm_get_cycle_count
+
+DESCRIPTION  return the count in the cycle count register.
+
+DEPENDENCIES
+
+RETURN VALUE
+The value in the cycle count register.
+
+SIDE EFFECTS
+*/
+unsigned long l2_pm_get_cycle_count(void)
+{
+  unsigned long cnt = 0;
+  RCP15_L2PMCCNTR(cnt);
+  return cnt;
+}
+
+/*
+FUNCTION  l2_pm_reset_cycle_count
+
+DESCRIPTION  reset the value in the cycle count register
+
+DEPENDENCIES
+
+RETURN VALUE
+NONE
+
+SIDE EFFECTS
+Resets the performance monitor cycle count register.
+Any interrupts period based on this overflow will be changed
+*/
+void l2_pm_reset_cycle_count(void)
+{
+  WCP15_L2PMCNTENCLR(PM_L2_COUNT_ENABLE);
+}
+
+/*
+FUNCTION  l2_pm_cycle_div_64
+
+DESCRIPTION  Set the cycle counter to count every 64th cycle instead of
+every cycle when the value passed is 1, otherwise counts every cycle.
+
+DEPENDENCIES
+
+RETURN VALUE
+none
+
+SIDE EFFECTS
+Changes the rate at which cycles are counted.  Anything that is reading
+the cycle count (pmGetCyucleCount) may get different results.
+*/
+void l2_pm_cycle_div_64(int enable)
+{
+	unsigned long enables = 0;
+
+	RCP15_L2PMCR(enables);
+	if (enable)
+		WCP15_L2PMCR(enables | PM_L2_CLKDIV);
+	else
+		WCP15_L2PMCR(enables & ~PM_L2_CLKDIV);
+}
+
+/*
+FUNCTION l2_pm_enable_cycle_counter
+
+DESCRIPTION  Enable the cycle counter.  Sets the bit in the enable register
+so the performance monitor counter starts up counting.
+
+DEPENDENCIES
+
+RETURN VALUE
+none
+
+SIDE EFFECTS
+*/
+void l2_pm_enable_cycle_counter(void)
+{
+/*
+*  Enable the counter.
+*/
+  WCP15_L2PMCNTENSET(PM_L2_COUNT_ENABLE);
+}
+
+/*
+FUNCTION l2_pm_disable_counter
+
+DESCRIPTION  Disable a single counter based on the index passed.
+
+DEPENDENCIES
+
+RETURN VALUE
+none
+
+SIDE EFFECTS
+Any triggers that are based on the stoped counter may not trigger...
+*/
+void l2_pm_disable_counter(int index)
+{
+  /*
+   * Range check
+   */
+  if (index > pm_l2_max_events)
+		return;
+  WCP15_L2PMCNTENCLR(1<<index);
+}
+
+/*
+FUNCTION l2_pm_enable_counter
+
+DESCRIPTION  Enable the counter with the index passed.
+
+DEPENDENCIES
+
+RETURN VALUE
+none.
+
+SIDE EFFECTS
+*/
+void l2_pm_enable_counter(int index)
+{
+  /*
+   * Range check
+   */
+  if (index > pm_l2_max_events)
+		return;
+  WCP15_L2PMCNTENSET(1<<index);
+}
+
+/*
+FUNCTION l2_pm_set_count
+
+DESCRIPTION  Set the number of events in a register, used for resets
+passed.
+
+DEPENDENCIES
+
+RETURN VALUE
+-1 if the index is out of range
+
+SIDE EFFECTS
+*/
+int l2_pm_set_count(int index, unsigned long new_value)
+{
+  unsigned long reg = 0;
+
+/*
+* Range check
+*/
+  if (index > pm_l2_max_events)
+		return L2_PM_ERR;
+
+/*
+* Lock, select the index and read the count...unlock
+*/
+  PM_LOCK();
+  WCP15_L2PMSELR(index);
+  WCP15_L2PMXEVCNTR(new_value);
+  PM_UNLOCK();
+  return reg;
+}
+
+int l2_pm_reset_count(int index)
+{
+  return l2_pm_set_count(index, 0);
+}
+
+/*
+FUNCTION l2_pm_get_count
+
+DESCRIPTION  Return the number of events that have happened for the index
+passed.
+
+DEPENDENCIES
+
+RETURN VALUE
+-1 if the index is out of range
+The number of events if inrange
+
+SIDE EFFECTS
+*/
+unsigned long l2_pm_get_count(int index)
+{
+  unsigned long reg = 0;
+
+/*
+* Range check
+*/
+  if (index > pm_l2_max_events)
+		return L2_PM_ERR;
+
+/*
+* Lock, select the index and read the count...unlock
+*/
+  PM_LOCK();
+  WCP15_L2PMSELR(index);
+  RCP15_L2PMXEVCNTR(reg);
+  PM_UNLOCK();
+  return reg;
+}
+
+unsigned long get_filter_code(unsigned long event)
+{
+	if (event == 0x0 || event == 0x4 || event == 0x08
+		|| event == 0x0c || event == 0x10)
+			return 0x0001003f;
+	else if (event == 0x1 || event == 0x5 || event == 0x09
+		|| event == 0x0d || event == 0x11)
+			return 0x0002003f;
+	else if (event == 0x2 || event == 0x6 || event == 0x0a
+		|| event == 0x0e || event == 0x12)
+			return 0x0004003f;
+	else if (event == 0x3 || event == 0x7 || event == 0x0b
+		|| event == 0x0f || event == 0x13)
+			return 0x0008003f;
+	else
+		return 0;
+}
+
+int l2_pm_set_event(int index, unsigned long event)
+{
+  unsigned long reg = 0;
+
+  /*
+   * Range check
+   */
+  if (index > pm_l2_max_events)
+		return L2_PM_ERR;
+
+  /*
+   * Lock, select the index and read the count...unlock
+   */
+  PM_LOCK();
+  WCP15_L2PMSELR(index);
+  WCP15_L2PMXEVTYPER(event);
+  /* WCP15_L2PMXEVFILTER(get_filter_code(event)); */
+  WCP15_L2PMXEVFILTER(0x000f003f);
+  PM_UNLOCK();
+  return reg;
+}
+
+/*
+FUNCTION  pm_set_local_bu
+
+DESCRIPTION  Set the local BU triggers.  Note that the MSB determines if
+  these are enabled or not.
+
+DEPENDENCIES
+
+RETURN VALUE
+  NONE
+
+SIDE EFFECTS
+*/
+void pm_set_local_bu(unsigned long value)
+{
+  WCP15_L2PMEVTYPER0(value);
+}
+
+/*
+FUNCTION  pm_set_local_cb
+
+DESCRIPTION  Set the local CB triggers.  Note that the MSB determines if
+  these are enabled or not.
+
+DEPENDENCIES
+
+RETURN VALUE
+  NONE
+
+SIDE EFFECTS
+*/
+void pm_set_local_cb(unsigned long value)
+{
+  WCP15_L2PMEVTYPER1(value);
+}
+
+/*
+FUNCTION  pm_set_local_mp
+
+DESCRIPTION  Set the local MP triggers.  Note that the MSB determines if
+  these are enabled or not.
+
+DEPENDENCIES
+
+RETURN VALUE
+  NONE
+
+SIDE EFFECTS
+*/
+void pm_set_local_mp(unsigned long value)
+{
+  WCP15_L2PMEVTYPER2(value);
+}
+
+/*
+FUNCTION  pm_set_local_sp
+
+DESCRIPTION  Set the local SP triggers.  Note that the MSB determines if
+  these are enabled or not.
+
+DEPENDENCIES
+
+RETURN VALUE
+  NONE
+
+SIDE EFFECTS
+*/
+void pm_set_local_sp(unsigned long value)
+{
+  WCP15_L2PMEVTYPER3(value);
+}
+
+/*
+FUNCTION  pm_set_local_scu
+
+DESCRIPTION  Set the local SCU triggers.  Note that the MSB determines if
+  these are enabled or not.
+
+DEPENDENCIES
+
+RETURN VALUE
+  NONE
+
+SIDE EFFECTS
+*/
+void pm_set_local_scu(unsigned long value)
+{
+  WCP15_L2PMEVTYPER4(value);
+}
+
+/*
+FUNCTION  l2_pm_isr
+
+DESCRIPTION:
+  Performance Monitor interrupt service routine to capture overflows
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+static irqreturn_t l2_pm_isr(int irq, void *d)
+{
+	int i;
+
+	for (i = 0; i < PM_NUM_COUNTERS; i++) {
+		if (l2_pm_get_overflow(i)) {
+			l2_pm_overflow_count[i]++;
+			l2_pm_reset_overflow(i);
+		}
+	}
+
+	if (l2_pm_get_cycle_overflow()) {
+		l2_pm_cycle_overflow_count++;
+		l2_pm_reset_cycle_overflow();
+	}
+
+	return IRQ_HANDLED;
+}
+
+
+void l2_pm_stop_all(void)
+{
+  WCP15_L2PMCNTENCLR(0xFFFFFFFF);
+}
+
+void l2_pm_reset_all(void)
+{
+  WCP15_L2PMCR(0xF);
+  WCP15_L2PMOVSR(PM_L2_ALL_ENABLE);  /* overflow clear */
+}
+
+void l2_pm_start_all(void)
+{
+  WCP15_L2PMCNTENSET(PM_L2_ALL_ENABLE);
+}
+
+/*
+FUNCTION l2_pm_initialize
+
+DESCRIPTION  Initialize the performanca monitoring for the v7 processor.
+  Ensures the cycle count is running and the event counters are enabled.
+
+DEPENDENCIES
+
+RETURN VALUE
+  NONE
+
+SIDE EFFECTS
+*/
+void l2_pm_initialize(void)
+{
+  unsigned long reg = 0;
+  unsigned char imp;
+  unsigned char id;
+  unsigned char num;
+  unsigned long enables = 0;
+  static int initialized;
+
+  if (initialized)
+		return;
+  initialized = 1;
+
+  irqid = SC_SICL2PERFMONIRPTREQ;
+  RCP15_L2PMCR(reg);
+  imp = (reg>>24) & 0xFF;
+  id  = (reg>>16) & 0xFF;
+  pm_l2_max_events = num = (reg>>11)  & 0xFF;
+  PRINT("V7 MP L2SCU Performance Monitor Capabilities\n");
+  PRINT("  Implementor %c(%d)\n", imp, imp);
+  PRINT("  Id %d %x\n", id, id);
+  PRINT("  Num Events %d %x\n", num, num);
+  PRINT("\nCycle counter enabled by default...\n");
+
+  /*
+   * Global enable, ensure the global enable is set so all
+   * subsequent actions take effect.  Also resets the counts
+   */
+  RCP15_L2PMCR(enables);
+  WCP15_L2PMCR(enables | PM_L2_GLOBAL_ENABLE | PM_L2_EVENT_RESET |
+      PM_L2_CYCLE_RESET | PM_L2_CLKDIV);
+
+  /*
+   * Enable access from user space
+   */
+
+  /*
+   * Install interrupt handler and the enable the interrupts
+   */
+  l2_pm_reset_cycle_overflow();
+  l2_pm_reset_overflow(0);
+  l2_pm_reset_overflow(1);
+  l2_pm_reset_overflow(2);
+  l2_pm_reset_overflow(3);
+  l2_pm_reset_overflow(4);
+
+	if (0 != request_irq(irqid, l2_pm_isr, 0, "l2perfmon", 0))
+		printk(KERN_ERR "%s:%d request_irq returned error\n",
+		__FILE__, __LINE__);
+  WCP15_L2PMINTENSET(PM_L2_ALL_ENABLE);
+  /*
+   * Enable the cycle counter.  Default, count 1:1 no divisor.
+   */
+  l2_pm_enable_cycle_counter();
+
+}
+
+void l2_pm_free_irq(void)
+{
+	free_irq(irqid, 0);
+}
+
+void l2_pm_deinitialize(void)
+{
+  unsigned long enables = 0;
+  RCP15_L2PMCR(enables);
+  WCP15_L2PMCR(enables & ~PM_L2_GLOBAL_ENABLE);
+}
+
diff --git a/arch/arm/perfmon/perf-v7.c b/arch/arm/perfmon/perf-v7.c
new file mode 100644
index 0000000..614eedc
--- /dev/null
+++ b/arch/arm/perfmon/perf-v7.c
@@ -0,0 +1,1009 @@
+/* Copyright (c) 2010, 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.
+ */
+
+/*
+perf-v7.c
+DESCRIPTION
+Manipulation, initialization of the ARMV7 Performance counter register.
+
+
+EXTERNALIZED FUNCTIONS
+
+INITIALIZATION AND SEQUENCING REQUIREMENTS
+*/
+
+/*
+INCLUDE FILES FOR MODULE
+*/
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/time.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include "cp15_registers.h"
+
+/*
+DEFINITIONS AND DECLARATIONS FOR MODULE
+
+This section contains definitions for constants, macros, types, variables
+and other items needed by this module.
+*/
+
+/*
+  Constant / Define Declarations
+*/
+
+#define PM_NUM_COUNTERS 4
+#define PM_V7_ERR -1
+
+/*------------------------------------------------------------------------
+ * Global control bits
+------------------------------------------------------------------------*/
+#define PM_GLOBAL_ENABLE     (1<<0)
+#define PM_EVENT_RESET       (1<<1)
+#define PM_CYCLE_RESET       (1<<2)
+#define PM_CLKDIV            (1<<3)
+#define PM_GLOBAL_TRACE      (1<<4)
+#define PM_DISABLE_PROHIBIT  (1<<5)
+
+/*---------------------------------------------------------------------------
+ * Enable and clear bits for each event/trigger
+----------------------------------------------------------------------------*/
+#define PM_EV0_ENABLE        (1<<0)
+#define PM_EV1_ENABLE        (1<<1)
+#define PM_EV2_ENABLE        (1<<2)
+#define PM_EV3_ENABLE        (1<<3)
+#define PM_COUNT_ENABLE      (1<<31)
+#define PM_ALL_ENABLE        (0x8000000F)
+
+
+/*-----------------------------------------------------------------------------
+ * Overflow actions
+------------------------------------------------------------------------------*/
+#define PM_OVERFLOW_NOACTION	(0)
+#define PM_OVERFLOW_HALT	(1)
+#define PM_OVERFLOW_STOP	(2)
+#define PM_OVERFLOW_SKIP	(3)
+
+/*
+ * Shifts for each trigger type
+ */
+#define PM_STOP_SHIFT		24
+#define PM_RELOAD_SHIFT		22
+#define PM_RESUME_SHIFT		20
+#define PM_SUSPEND_SHIFT	18
+#define PM_START_SHIFT		16
+#define PM_STOPALL_SHIFT	15
+#define PM_STOPCOND_SHIFT	12
+#define PM_RELOADCOND_SHIFT	9
+#define PM_RESUMECOND_SHIFT	6
+#define PM_SUSPENDCOND_SHIFT	3
+#define PM_STARTCOND_SHIFT	0
+
+
+/*---------------------------------------------------------------------------
+External control register.  What todo when various events happen.
+Triggering events, etc.
+----------------------------------------------------------------------------*/
+#define PM_EXTTR0		0
+#define PM_EXTTR1		1
+#define PM_EXTTR2		2
+#define PM_EXTTR3		3
+
+#define PM_COND_NO_STOP		0
+#define PM_COND_STOP_CNTOVRFLW	1
+#define PM_COND_STOP_EXTERNAL	4
+#define PM_COND_STOP_TRACE	5
+#define PM_COND_STOP_EVOVRFLW	6
+#define PM_COND_STOP_EVTYPER	7
+
+/*--------------------------------------------------------------------------
+Protect against concurrent access.  There is an index register that is
+used to select the appropriate bank of registers.  If multiple processes
+are writting this at different times we could have a mess...
+---------------------------------------------------------------------------*/
+#define PM_LOCK()
+#define PM_UNLOCK()
+#define PRINT printk
+
+/*--------------------------------------------------------------------------
+The Event definitions
+--------------------------------------------------------------------------*/
+#define PM_EVT_SW_INCREMENT	0
+#define PM_EVT_L1_I_MISS	1
+#define PM_EVT_ITLB_MISS	2
+#define PM_EVT_L1_D_MISS	3
+#define PM_EVT_L1_D_ACCESS	4
+#define PM_EVT_DTLB_MISS	5
+#define PM_EVT_DATA_READ	6
+#define PM_EVT_DATA_WRITE	7
+#define PM_EVT_INSTRUCTION	8
+#define PM_EVT_EXCEPTIONS	9
+#define PM_EVT_EXCEPTION_RET	10
+#define PM_EVT_CTX_CHANGE	11
+#define PM_EVT_PC_CHANGE	12
+#define PM_EVT_BRANCH		13
+#define PM_EVT_RETURN		14
+#define PM_EVT_UNALIGNED	15
+#define PM_EVT_BRANCH_MISS	16
+#define PM_EVT_EXTERNAL0	0x40
+#define PM_EVT_EXTERNAL1	0x41
+#define PM_EVT_EXTERNAL2	0x42
+#define PM_EVT_EXTERNAL3	0x43
+#define PM_EVT_TRACE0		0x44
+#define PM_EVT_TRACE1		0x45
+#define PM_EVT_TRACE2		0x46
+#define PM_EVT_TRACE3		0x47
+#define PM_EVT_PM0		0x48
+#define PM_EVT_PM1		0x49
+#define PM_EVT_PM2		0x4a
+#define PM_EVT_PM3		0x4b
+#define PM_EVT_LPM0_EVT0	0x4c
+#define PM_EVT_LPM0_EVT1	0x4d
+#define PM_EVT_LPM0_EVT2	0x4e
+#define PM_EVT_LPM0_EVT3	0x4f
+#define PM_EVT_LPM1_EVT0	0x50
+#define PM_EVT_LPM1_EVT1	0x51
+#define PM_EVT_LPM1_EVT2	0x52
+#define PM_EVT_LPM1_EVT3	0x53
+#define PM_EVT_LPM2_EVT0	0x54
+#define PM_EVT_LPM2_EVT1	0x55
+#define PM_EVT_LPM2_EVT2	0x56
+#define PM_EVT_LPM2_EVT3	0x57
+#define PM_EVT_L2_EVT0		0x58
+#define PM_EVT_L2_EVT1		0x59
+#define PM_EVT_L2_EVT2		0x5a
+#define PM_EVT_L2_EVT3		0x5b
+#define PM_EVT_VLP_EVT0		0x5c
+#define PM_EVT_VLP_EVT1		0x5d
+#define PM_EVT_VLP_EVT2		0x5e
+#define PM_EVT_VLP_EVT3		0x5f
+
+/*
+Type Declarations
+*/
+
+/*--------------------------------------------------------------------------
+A performance monitor trigger setup/initialization structure.  Contains
+all of the fields necessary to setup a complex trigger with the internal
+performance monitor.
+---------------------------------------------------------------------------*/
+struct pm_trigger_s {
+  int index;
+  int event_type;
+  bool interrupt;
+  bool overflow_enable;
+  bool event_export;
+  unsigned char overflow_action;
+  unsigned char stop_index;
+  unsigned char reload_index;
+  unsigned char resume_index;
+  unsigned char suspend_index;
+  unsigned char start_index;
+  bool  overflow_stop;
+  unsigned char stop_condition;
+  unsigned char reload_condition;
+  unsigned char resume_condition;
+  unsigned char suspend_condition;
+  unsigned char start_condition;
+};
+
+/*
+* Name and index place holder so we can display the event
+*/
+struct pm_name_s {
+  unsigned long index;
+  char          *name;
+};
+
+/*
+Local Object Definitions
+*/
+
+unsigned long pm_cycle_overflow_count;
+unsigned long pm_overflow_count[PM_NUM_COUNTERS];
+
+/*---------------------------------------------------------------------------
+Max number of events read from the config registers
+---------------------------------------------------------------------------*/
+static int pm_max_events;
+
+/*--------------------------------------------------------------------------
+Storage area for each of the triggers
+*---------------------------------------------------------------------------*/
+static struct pm_trigger_s pm_triggers[4];
+
+/*--------------------------------------------------------------------------
+Names and indexes of the events
+--------------------------------------------------------------------------*/
+static struct pm_name_s pm_names[] = {
+  { PM_EVT_SW_INCREMENT,    "SW Increment"},
+  { PM_EVT_L1_I_MISS,       "L1 I MISS"},
+  { PM_EVT_ITLB_MISS,       "L1 ITLB MISS"},
+  { PM_EVT_L1_D_MISS,       "L1 D MISS"},
+  { PM_EVT_L1_D_ACCESS,     "L1 D ACCESS"},
+  { PM_EVT_DTLB_MISS,       "DTLB MISS"},
+  { PM_EVT_DATA_READ,       "DATA READ"},
+  { PM_EVT_DATA_WRITE,      "DATA WRITE"},
+  { PM_EVT_INSTRUCTION,     "INSTRUCTIONS"},
+  { PM_EVT_EXCEPTIONS,      "EXCEPTIONS"},
+  { PM_EVT_EXCEPTION_RET,   "EXCEPTION RETURN"},
+  { PM_EVT_CTX_CHANGE,      "CTX CHANGE"},
+  { PM_EVT_PC_CHANGE,       "PC CHANGE"},
+  { PM_EVT_BRANCH,          "BRANCH"},
+  { PM_EVT_RETURN,          "RETURN"},
+  { PM_EVT_UNALIGNED,       "UNALIGNED"},
+  { PM_EVT_BRANCH_MISS,     "BRANCH MISS"},
+  { PM_EVT_EXTERNAL0,       "EXTERNAL 0"},
+  { PM_EVT_EXTERNAL1,       "EXTERNAL 1"},
+  { PM_EVT_EXTERNAL2,       "EXTERNAL 2"},
+  { PM_EVT_EXTERNAL3,       "EXTERNAL 3"},
+  { PM_EVT_TRACE0,          "TRACE 0"},
+  { PM_EVT_TRACE1,          "TRACE 1"},
+  { PM_EVT_TRACE2,          "TRACE 2"},
+  { PM_EVT_TRACE3,          "TRACE 3"},
+  { PM_EVT_PM0,             "PM0"},
+  { PM_EVT_PM1,             "PM1"},
+  { PM_EVT_PM2,             "PM2"},
+  { PM_EVT_PM3,             "PM3"},
+  { PM_EVT_LPM0_EVT0,       "LPM0 E0"},
+  { PM_EVT_LPM0_EVT1,       "LPM0 E1"},
+  { PM_EVT_LPM0_EVT2 ,      "LPM0 E2"},
+  { PM_EVT_LPM0_EVT3,       "LPM0 E3"},
+  { PM_EVT_LPM1_EVT0,       "LPM1 E0"},
+  { PM_EVT_LPM1_EVT1,       "LPM1 E1"},
+  { PM_EVT_LPM1_EVT2,       "LPM1 E2"},
+  { PM_EVT_LPM1_EVT3,       "LPM1 E3"},
+  { PM_EVT_LPM2_EVT0,       "LPM2 E0"},
+  { PM_EVT_LPM2_EVT1 ,      "LPM2 E1"},
+  { PM_EVT_LPM2_EVT2,       "LPM2 E2"},
+  { PM_EVT_LPM2_EVT3,       "LPM2 E3"},
+  { PM_EVT_L2_EVT0 ,        "L2 E0"},
+  { PM_EVT_L2_EVT1,         "L2 E1"},
+  { PM_EVT_L2_EVT2,         "L2 E2"},
+  { PM_EVT_L2_EVT3 ,        "L2 E3"},
+  { PM_EVT_VLP_EVT0 ,       "VLP E0"},
+  { PM_EVT_VLP_EVT1,        "VLP E1"},
+  { PM_EVT_VLP_EVT2,        "VLP E2"},
+  { PM_EVT_VLP_EVT3,        "VLP E3"},
+};
+
+static int irqid;
+
+/*
+Function Definitions
+*/
+
+/*
+FUNCTION  pm_find_event_name
+
+DESCRIPTION Find the name associated with the event index passed and return
+the pointer.
+
+DEPENDENCIES
+
+RETURN VALUE
+Pointer to text string containing the name of the event or pointer to
+an error string.  Either way access to the returned string will not
+cause an access error.
+
+SIDE EFFECTS
+*/
+char *pm_find_event_name(unsigned long index)
+{
+	unsigned long i = 0;
+
+	while (pm_names[i].index != -1) {
+		if (pm_names[i].index == index)
+			return pm_names[i].name;
+		i++;
+	}
+	return "BAD INDEX";
+}
+
+/*
+FUNCTION  pm_group_stop
+
+DESCRIPTION  Stop a group of the performance monitors.  Event monitor 0 is bit
+0, event monitor 1 bit 1, etc.  The cycle count can also be disabled with
+bit 31.  Macros are provided for all of the indexes including an ALL.
+
+DEPENDENCIES
+
+RETURN VALUE
+None
+
+SIDE EFFECTS
+Stops the performance monitoring for the index passed.
+*/
+void pm_group_stop(unsigned long mask)
+{
+	WCP15_PMCNTENCLR(mask);
+}
+
+/*
+FUNCTION  pm_group_start
+
+DESCRIPTION  Start a group of the performance monitors.  Event monitor 0 is bit
+0, event monitor 1 bit 1, etc.  The cycle count can also be enabled with
+bit 31.  Macros are provided for all of the indexes including an ALL.
+
+DEPENDENCIES
+
+RETURN VALUE
+None
+
+SIDE EFFECTS
+Starts the performance monitoring for the index passed.
+*/
+void pm_group_start(unsigned long mask)
+{
+	WCP15_PMCNTENSET(mask);
+}
+
+/*
+FUNCTION pm_cycle_overflow_action
+
+DESCRIPTION  Action to take for an overflow of the cycle counter.
+
+DEPENDENCIES
+
+RETURN VALUE
+None
+
+SIDE EFFECTS
+Modify the state actions for overflow
+*/
+void pm_cycle_overflow_action(int action)
+{
+	unsigned long reg = 0;
+
+	if ((action > PM_OVERFLOW_SKIP) || (action < 0))
+		return;
+
+	RCP15_PMACTLR(reg);
+	reg &= ~(1<<30);   /*clear it*/
+	WCP15_PMACTLR(reg | (action<<30));
+}
+
+/*
+FUNCTION   pm_get_overflow
+
+DESCRIPTION  Return the overflow condition for the index passed.
+
+DEPENDENCIES
+
+RETURN VALUE
+0 no overflow
+!0 (anything else) overflow;
+
+SIDE EFFECTS
+*/
+unsigned long pm_get_overflow(int index)
+{
+  unsigned long overflow = 0;
+
+/*
+* Range check
+*/
+  if (index > pm_max_events)
+	return PM_V7_ERR;
+  RCP15_PMOVSR(overflow);
+
+  return overflow & (1<<index);
+}
+
+/*
+FUNCTION  pm_get_cycle_overflow
+
+DESCRIPTION
+Returns if the cycle counter has overflowed or not.
+
+DEPENDENCIES
+
+RETURN VALUE
+0 no overflow
+!0 (anything else) overflow;
+
+SIDE EFFECTS
+*/
+unsigned long pm_get_cycle_overflow(void)
+{
+  unsigned long overflow = 0;
+
+  RCP15_PMOVSR(overflow);
+  return overflow & PM_COUNT_ENABLE;
+}
+
+/*
+FUNCTION  pm_reset_overflow
+
+DESCRIPTION Reset the cycle counter overflow bit.
+
+DEPENDENCIES
+
+RETURN VALUE
+None
+
+SIDE EFFECTS
+*/
+void pm_reset_overflow(int index)
+{
+  WCP15_PMOVSR(1<<index);
+}
+
+/*
+FUNCTION  pm_reset_cycle_overflow
+
+DESCRIPTION Reset the cycle counter overflow bit.
+
+DEPENDENCIES
+
+RETURN VALUE
+None
+
+SIDE EFFECTS
+*/
+void pm_reset_cycle_overflow(void)
+{
+  WCP15_PMOVSR(PM_COUNT_ENABLE);
+}
+
+/*
+FUNCTION pm_get_cycle_count
+
+DESCRIPTION  return the count in the cycle count register.
+
+DEPENDENCIES
+
+RETURN VALUE
+The value in the cycle count register.
+
+SIDE EFFECTS
+*/
+unsigned long pm_get_cycle_count(void)
+{
+  unsigned long cnt = 0;
+  RCP15_PMCCNTR(cnt);
+  return cnt;
+}
+
+/*
+FUNCTION  pm_reset_cycle_count
+
+DESCRIPTION  reset the value in the cycle count register
+
+DEPENDENCIES
+
+RETURN VALUE
+NONE
+
+SIDE EFFECTS
+Resets the performance monitor cycle count register.
+Any interrupts period based on this overflow will be changed
+*/
+void pm_reset_cycle_count(void)
+{
+  WCP15_PMCNTENCLR(PM_COUNT_ENABLE);
+}
+
+/*
+FUNCTION  pm_cycle_div_64
+
+DESCRIPTION  Set the cycle counter to count every 64th cycle instead of
+every cycle when the value passed is 1, otherwise counts every cycle.
+
+DEPENDENCIES
+
+RETURN VALUE
+none
+
+SIDE EFFECTS
+Changes the rate at which cycles are counted.  Anything that is reading
+the cycle count (pmGetCyucleCount) may get different results.
+*/
+void pm_cycle_div_64(int enable)
+{
+	unsigned long enables = 0;
+
+	RCP15_PMCR(enables);
+	if (enable)
+		WCP15_PMCR(enables | PM_CLKDIV);
+	else
+		WCP15_PMCR(enables & ~PM_CLKDIV);
+}
+
+/*
+FUNCTION pm_enable_cycle_counter
+
+DESCRIPTION  Enable the cycle counter.  Sets the bit in the enable register
+so the performance monitor counter starts up counting.
+
+DEPENDENCIES
+
+RETURN VALUE
+none
+
+SIDE EFFECTS
+*/
+void pm_enable_cycle_counter(void)
+{
+/*
+*  Enable the counter.
+*/
+  WCP15_PMCNTENSET(PM_COUNT_ENABLE);
+}
+
+/*
+FUNCTION pm_disable_counter
+
+DESCRIPTION  Disable a single counter based on the index passed.
+
+DEPENDENCIES
+
+RETURN VALUE
+none
+
+SIDE EFFECTS
+Any triggers that are based on the stoped counter may not trigger...
+*/
+void pm_disable_counter(int index)
+{
+  /*
+   * Range check
+   */
+  if (index > pm_max_events)
+		return;
+  WCP15_PMCNTENCLR(1<<index);
+}
+
+/*
+FUNCTION pm_enable_counter
+
+DESCRIPTION  Enable the counter with the index passed.
+
+DEPENDENCIES
+
+RETURN VALUE
+none.
+
+SIDE EFFECTS
+*/
+void pm_enable_counter(int index)
+{
+  /*
+   * Range check
+   */
+  if (index > pm_max_events)
+		return;
+  WCP15_PMCNTENSET(1<<index);
+}
+
+/*
+FUNCTION pm_set_count
+
+DESCRIPTION  Set the number of events in a register, used for resets
+passed.
+
+DEPENDENCIES
+
+RETURN VALUE
+-1 if the index is out of range
+
+SIDE EFFECTS
+*/
+int pm_set_count(int index, unsigned long new_value)
+{
+  unsigned long reg = 0;
+
+/*
+* Range check
+*/
+  if (index > pm_max_events)
+		return PM_V7_ERR;
+
+/*
+* Lock, select the index and read the count...unlock
+*/
+  PM_LOCK();
+  WCP15_PMSELR(index);
+  WCP15_PMXEVCNTR(new_value);
+  PM_UNLOCK();
+  return reg;
+}
+
+int pm_reset_count(int index)
+{
+  return pm_set_count(index, 0);
+}
+
+/*
+FUNCTION pm_get_count
+
+DESCRIPTION  Return the number of events that have happened for the index
+passed.
+
+DEPENDENCIES
+
+RETURN VALUE
+-1 if the index is out of range
+The number of events if inrange
+
+SIDE EFFECTS
+*/
+unsigned long pm_get_count(int index)
+{
+  unsigned long reg = 0;
+
+/*
+* Range check
+*/
+  if (index > pm_max_events)
+		return PM_V7_ERR;
+
+/*
+* Lock, select the index and read the count...unlock
+*/
+  PM_LOCK();
+  WCP15_PMSELR(index);
+  RCP15_PMXEVCNTR(reg);
+  PM_UNLOCK();
+  return reg;
+}
+
+/*
+FUNCTION pm_show_event_info
+
+DESCRIPTION Display (print) the information about the event at the index
+passed.  Shows the index, name and count if a valid index is passed.  If
+the index is not valid, then nothing is displayed.
+
+DEPENDENCIES
+
+RETURN VALUE
+None
+
+SIDE EFFECTS
+*/
+void pm_show_event_info(unsigned long index)
+{
+  unsigned long count;
+  unsigned long event_type;
+
+  if (index > pm_max_events)
+		return;
+  if (pm_triggers[index].index > pm_max_events)
+		return;
+
+  count = pm_get_count(index);
+  event_type = pm_triggers[index].event_type;
+
+  PRINT("Event %ld Trigger %s(%ld) count:%ld\n", index,
+     pm_find_event_name(event_type), event_type, count);
+}
+
+/*
+FUNCTION  pm_event_init
+
+DESCRIPTION  Given the struct pm_trigger_s info passed, configure the event.
+This can be a complex trigger or a simple trigger.  Any old values in the
+event are lost.
+
+DEPENDENCIES
+
+RETURN VALUE
+status
+
+SIDE EFFECTS
+stops and clears the event at the index passed.
+*/
+int pm_event_init(struct pm_trigger_s *data)
+{
+  unsigned long trigger;
+  unsigned long actlr = 0;
+
+  if (0 == data)
+		return PM_V7_ERR;
+  if (data->index > pm_max_events)
+		return PM_V7_ERR;
+
+  /*
+   * Setup the trigger based ont he passed values
+   */
+  trigger = ((data->overflow_enable&1)<<31) |
+	((data->event_export&1)<<30) |
+	((data->stop_index&3)<<PM_STOP_SHIFT) |
+	((data->reload_index&3)<<PM_RELOAD_SHIFT) |
+	((data->resume_index&3)<<PM_RESUME_SHIFT) |
+	((data->suspend_index&3)<<PM_SUSPEND_SHIFT) |
+	((data->start_index&3)<<PM_START_SHIFT) |
+	((data->overflow_stop&1)<<PM_STOPALL_SHIFT) |
+	((data->stop_condition&7)<<PM_STOPCOND_SHIFT) |
+	((data->reload_condition&7)<<PM_RELOADCOND_SHIFT) |
+	((data->resume_condition&7)<<PM_RESUMECOND_SHIFT) |
+	((data->suspend_condition&7)<<PM_SUSPENDCOND_SHIFT) |
+	((data->start_condition&7)<<PM_STARTCOND_SHIFT);
+
+  /*
+   * Disable this counter while we are updating.
+   */
+  pm_disable_counter(data->index);
+
+  /*
+   * Lock, select the bank, set the trigger event and the event type
+   * then unlock.
+   */
+  PM_LOCK();
+  RCP15_PMACTLR(actlr);
+  actlr &= ~(3<<(data->index<<1));
+  WCP15_PMACTLR(actlr | ((data->overflow_action&3) << (data->index<<1)));
+  WCP15_PMSELR(data->index);
+  WCP15_PMXEVTYPER(data->event_type);
+  WCP15_PMXEVCNTCR(trigger);
+  PM_UNLOCK();
+
+  /*
+   * Make a copy of the trigger so we know what it is when/if it triggers.
+   */
+  memcpy(&pm_triggers[data->index], data, sizeof(*data));
+
+  /*
+   * We do not re-enable this here so events can be started together with
+   * pm_group_start() that way an accurate measure can be taken...
+   */
+
+  return 0;
+}
+
+int pm_set_event(int index, unsigned long event)
+{
+  unsigned long reg = 0;
+
+  /*
+   * Range check
+   */
+  if (index > pm_max_events)
+		return PM_V7_ERR;
+
+  /*
+   * Lock, select the index and read the count...unlock
+   */
+  PM_LOCK();
+  WCP15_PMSELR(index);
+  WCP15_PMXEVTYPER(event);
+  PM_UNLOCK();
+  return reg;
+}
+
+/*
+FUNCTION  pm_set_local_iu
+
+DESCRIPTION  Set the local IU triggers.  Note that the MSB determines if
+  these are enabled or not.
+
+DEPENDENCIES
+
+RETURN VALUE
+  NONE
+
+SIDE EFFECTS
+*/
+void pm_set_local_iu(unsigned long value)
+{
+  WCP15_LPM0EVTYPER(value);
+}
+
+/*
+FUNCTION  pm_set_local_iu
+
+DESCRIPTION  Set the local IU triggers.  Note that the MSB determines if
+  these are enabled or not.
+
+DEPENDENCIES
+
+RETURN VALUE
+  NONE
+
+SIDE EFFECTS
+*/
+void pm_set_local_xu(unsigned long value)
+{
+  WCP15_LPM1EVTYPER(value);
+}
+
+/*
+FUNCTION  pm_set_local_su
+
+DESCRIPTION  Set the local SU triggers.  Note that the MSB determines if
+  these are enabled or not.
+
+DEPENDENCIES
+
+RETURN VALUE
+  NONE
+
+SIDE EFFECTS
+*/
+void pm_set_local_su(unsigned long value)
+{
+  WCP15_LPM2EVTYPER(value);
+}
+
+/*
+FUNCTION  pm_set_local_l2
+
+DESCRIPTION  Set the local L2 triggers.  Note that the MSB determines if
+  these are enabled or not.
+
+DEPENDENCIES
+
+RETURN VALUE
+  NONE
+
+SIDE EFFECTS
+*/
+void pm_set_local_l2(unsigned long value)
+{
+  WCP15_L2LPMEVTYPER(value);
+}
+
+/*
+FUNCTION  pm_set_local_vu
+
+DESCRIPTION  Set the local VU triggers.  Note that the MSB determines if
+  these are enabled or not.
+
+DEPENDENCIES
+
+RETURN VALUE
+  NONE
+
+SIDE EFFECTS
+*/
+void pm_set_local_vu(unsigned long value)
+{
+  WCP15_VLPMEVTYPER(value);
+}
+
+/*
+FUNCTION  pm_isr
+
+DESCRIPTION:
+  Performance Monitor interrupt service routine to capture overflows
+
+DEPENDENCIES
+
+RETURN VALUE
+
+SIDE EFFECTS
+*/
+static irqreturn_t pm_isr(int irq, void *d)
+{
+	int i;
+
+	for (i = 0; i < PM_NUM_COUNTERS; i++) {
+		if (pm_get_overflow(i)) {
+			pm_overflow_count[i]++;
+			pm_reset_overflow(i);
+		}
+	}
+
+	if (pm_get_cycle_overflow()) {
+		pm_cycle_overflow_count++;
+		pm_reset_cycle_overflow();
+	}
+
+	return IRQ_HANDLED;
+}
+
+
+void pm_stop_all(void)
+{
+  WCP15_PMCNTENCLR(0xFFFFFFFF);
+}
+
+void pm_reset_all(void)
+{
+  WCP15_PMCR(0xF);
+  WCP15_PMOVSR(PM_ALL_ENABLE);  /* overflow clear */
+}
+
+void pm_start_all(void)
+{
+  WCP15_PMCNTENSET(PM_ALL_ENABLE);
+}
+
+/*
+FUNCTION pm_initialize
+
+DESCRIPTION  Initialize the performanca monitoring for the v7 processor.
+  Ensures the cycle count is running and the event counters are enabled.
+
+DEPENDENCIES
+
+RETURN VALUE
+  NONE
+
+SIDE EFFECTS
+*/
+void pm_initialize(void)
+{
+  unsigned long reg = 0;
+  unsigned char imp;
+  unsigned char id;
+  unsigned char num;
+  unsigned long enables = 0;
+  static int initialized;
+
+  if (initialized)
+		return;
+  initialized = 1;
+
+  irqid = INT_ARMQC_PERFMON;
+  RCP15_PMCR(reg);
+  imp = (reg>>24) & 0xFF;
+  id  = (reg>>16) & 0xFF;
+  pm_max_events = num = (reg>>11)  & 0xFF;
+  PRINT("V7Performance Monitor Capabilities\n");
+  PRINT("  Implementor %c(%d)\n", imp, imp);
+  PRINT("  Id %d %x\n", id, id);
+  PRINT("  Num Events %d %x\n", num, num);
+  PRINT("\nCycle counter enabled by default...\n");
+
+  /*
+   * Global enable, ensure the global enable is set so all
+   * subsequent actions take effect.  Also resets the counts
+   */
+  RCP15_PMCR(enables);
+  WCP15_PMCR(enables | PM_GLOBAL_ENABLE | PM_EVENT_RESET |
+      PM_CYCLE_RESET | PM_CLKDIV);
+
+  /*
+   * Enable access from user space
+   */
+  WCP15_PMUSERENR(1);
+  WCP15_PMACTLR(1);
+
+  /*
+   * Install interrupt handler and the enable the interrupts
+   */
+  pm_reset_cycle_overflow();
+  pm_reset_overflow(0);
+  pm_reset_overflow(1);
+  pm_reset_overflow(2);
+  pm_reset_overflow(3);
+
+	if (0 != request_irq(irqid, pm_isr, 0, "perfmon", 0))
+		printk(KERN_ERR "%s:%d request_irq returned error\n",
+		__FILE__, __LINE__);
+  WCP15_PMINTENSET(PM_ALL_ENABLE);
+  /*
+   * Enable the cycle counter.  Default, count 1:1 no divisor.
+   */
+  pm_enable_cycle_counter();
+
+}
+
+void pm_free_irq(void)
+{
+	free_irq(irqid, 0);
+}
+
+void pm_deinitialize(void)
+{
+  unsigned long enables = 0;
+  RCP15_PMCR(enables);
+  WCP15_PMCR(enables & ~PM_GLOBAL_ENABLE);
+}
diff --git a/arch/arm/perfmon/perf.h b/arch/arm/perfmon/perf.h
new file mode 100644
index 0000000..1a9bb8b
--- /dev/null
+++ b/arch/arm/perfmon/perf.h
@@ -0,0 +1,86 @@
+/* Copyright (c) 2010, 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.
+ *
+ */
+
+/*
+perf.h
+
+DESCRIPTION: Reads and writes the performance monitoring registers in the ARM
+by using the MRC and MCR instructions.
+*/
+#ifndef PERF_H
+#define PERF_H
+extern unsigned long perf_get_cycles(void);
+extern void perf_set_count1(unsigned long val);
+extern void perf_set_count0(unsigned long val);
+extern unsigned long perf_get_count1(void);
+extern unsigned long perf_get_count0(void);
+extern unsigned long  perf_get_ctrl(void);
+extern void perf_set_ctrl(void);
+extern void perf_set_ctrl_with(unsigned long v);
+extern void perf_enable_counting(void);
+extern void perf_disable_counting(void);
+extern void perf_set_divider(int d);
+extern unsigned long perf_get_overflow(void);
+extern void perf_clear_overflow(unsigned long bit);
+extern void perf_export_event(unsigned long bit);
+extern void perf_reset_counts(void);
+extern int perf_set_event(unsigned long index, unsigned long val);
+extern unsigned long perf_get_count(unsigned long index);
+extern void perf_set_cycles(unsigned long c);
+
+extern void pm_stop_all(void);
+extern void l2_pm_stop_all(void);
+extern void pm_start_all(void);
+extern void l2_pm_start_all(void);
+extern void pm_reset_all(void);
+extern void l2_pm_reset_all(void);
+extern void pm_set_event(unsigned long monitorIndex, unsigned long eventIndex);
+extern void l2_pm_set_event(unsigned long monitorIndex,
+	unsigned long eventIndex);
+extern unsigned long pm_get_count(unsigned long monitorIndex);
+extern unsigned long l2_pm_get_count(unsigned long monitorIndex);
+extern unsigned long pm_get_cycle_count(void);
+extern unsigned long l2_pm_get_cycle_count(void);
+extern char *pm_find_event_name(unsigned long index);
+extern  void pm_set_local_iu(unsigned long events);
+extern  void pm_set_local_xu(unsigned long events);
+extern  void pm_set_local_su(unsigned long events);
+extern  void pm_set_local_l2(unsigned long events);
+extern  void pm_set_local_vu(unsigned long events);
+extern  void pm_set_local_bu(unsigned long events);
+extern  void pm_set_local_cb(unsigned long events);
+extern  void pm_set_local_mp(unsigned long events);
+extern  void pm_set_local_sp(unsigned long events);
+extern  void pm_set_local_scu(unsigned long events);
+extern void pm_initialize(void);
+extern void pm_deinitialize(void);
+extern void l2_pm_initialize(void);
+extern void l2_pm_deinitialize(void);
+extern void pm_free_irq(void);
+extern void l2_pm_free_irq(void);
+
+extern int per_process_perf_init(void);
+extern void per_process_perf_exit(void);
+int per_process_read(char *page, char **start, off_t off, int count,
+   int *eof, void *data);
+int per_process_write_hex(struct file *file, const char *buff,
+    unsigned long cnt, void *data);
+int per_process_read_decimal(char *page, char **start, off_t off, int count,
+   int *eof, void *data);
+int per_process_write_dec(struct file *file, const char *buff,
+    unsigned long cnt, void *data);
+void perfmon_register_callback(void);
+void _per_process_switch(unsigned long oldPid, unsigned long newPid);
+extern unsigned int pp_loaded;
+extern atomic_t pm_op_lock;
+#endif /*PERF_H*/
diff --git a/arch/arm/plat-omap/include/plat/dmic.h b/arch/arm/plat-omap/include/plat/dmic.h
new file mode 100644
index 0000000..1b0e49e
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/dmic.h
@@ -0,0 +1,79 @@
+/*
+ * dmic.h  --  OMAP Digital Microphone Controller
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARCH_OMAP_DMIC_H
+#define __ASM_ARCH_OMAP_DMIC_H
+
+#define OMAP44XX_DMIC_L3_BASE	0x4902e000
+
+#define OMAP_DMIC_REVISION		0x00
+#define OMAP_DMIC_SYSCONFIG		0x10
+#define OMAP_DMIC_IRQSTATUS_RAW		0x24
+#define OMAP_DMIC_IRQSTATUS		0x28
+#define OMAP_DMIC_IRQENABLE_SET		0x2C
+#define OMAP_DMIC_IRQENABLE_CLR		0x30
+#define OMAP_DMIC_IRQWAKE_EN		0x34
+#define OMAP_DMIC_DMAENABLE_SET		0x38
+#define OMAP_DMIC_DMAENABLE_CLR		0x3C
+#define OMAP_DMIC_DMAWAKEEN		0x40
+#define OMAP_DMIC_CTRL			0x44
+#define OMAP_DMIC_DATA			0x48
+#define OMAP_DMIC_FIFO_CTRL		0x4C
+#define OMAP_DMIC_FIFO_DMIC1R_DATA	0x50
+#define OMAP_DMIC_FIFO_DMIC1L_DATA	0x54
+#define OMAP_DMIC_FIFO_DMIC2R_DATA	0x58
+#define OMAP_DMIC_FIFO_DMIC2L_DATA	0x5C
+#define OMAP_DMIC_FIFO_DMIC3R_DATA	0x60
+#define OMAP_DMIC_FIFO_DMIC3L_DATA	0x64
+
+/*
+ * DMIC_IRQ bit fields
+ * IRQSTATUS_RAW, IRQSTATUS, IRQENABLE_SET, IRQENABLE_CLR
+ */
+
+#define OMAP_DMIC_IRQ			(1 << 0)
+#define OMAP_DMIC_IRQ_FULL		(1 << 1)
+#define OMAP_DMIC_IRQ_ALMST_EMPTY	(1 << 2)
+#define OMAP_DMIC_IRQ_EMPTY		(1 << 3)
+#define OMAP_DMIC_IRQ_MASK		0x07
+
+/*
+ * DMIC_DMAENABLE bit fields
+ */
+
+#define OMAP_DMIC_DMA_ENABLE		0x1
+
+/*
+ * DMIC_CTRL bit fields
+ */
+
+#define OMAP_DMIC_UP1_ENABLE		0x0001
+#define OMAP_DMIC_UP2_ENABLE		0x0002
+#define OMAP_DMIC_UP3_ENABLE		0x0004
+#define OMAP_DMIC_UP_ENABLE_MASK	0x0007
+#define OMAP_DMIC_FORMAT		0x0008
+#define OMAP_DMIC_POLAR1		0x0010
+#define OMAP_DMIC_POLAR2		0x0020
+#define OMAP_DMIC_POLAR3		0x0040
+#define OMAP_DMIC_POLAR_MASK		0x0070
+#define OMAP_DMIC_CLK_DIV_SHIFT		7
+#define OMAP_DMIC_CLK_DIV_MASK		0x0380
+#define	OMAP_DMIC_RESET			0x0400
+
+#define OMAP_DMIC_ENABLE_MASK		0x007
+
+#define OMAP_DMICOUTFORMAT_LJUST	(0 << 3)
+#define OMAP_DMICOUTFORMAT_RJUST	(1 << 3)
+
+/*
+ * DMIC_FIFO_CTRL bit fields
+ */
+
+#define OMAP_DMIC_THRES_MAX		0xF
+
+#endif
diff --git a/arch/arm/plat-omap/include/plat/mcpdm.h b/arch/arm/plat-omap/include/plat/mcpdm.h
new file mode 100644
index 0000000..1ed2b8f
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/mcpdm.h
@@ -0,0 +1,30 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __OMAP_PLAT_MCPDM_H__
+#define __OMAP_PLAT_MCPDM_H__
+
+#include <linux/platform_device.h>
+
+struct omap_mcpdm_platform_data {
+	int (*device_enable) (struct platform_device *pdev);
+	int (*device_shutdown) (struct platform_device *pdev);
+	int (*device_idle) (struct platform_device *pdev);
+};
+
+#endif
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index f9c9f33..d283705 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -468,6 +468,7 @@
 msm7x27_ffa		MACH_MSM7X27_FFA	MSM7X27_FFA		2706
 msm7x30_ffa		MACH_MSM7X30_FFA	MSM7X30_FFA		2707
 qsd8x50_surf		MACH_QSD8X50_SURF	QSD8X50_SURF		2708
+qsd8x50_ffa		MACH_QSD8X50_FFA	QSD8X50_FFA		2710
 mx53_evk		MACH_MX53_EVK		MX53_EVK		2716
 igep0030		MACH_IGEP0030		IGEP0030		2717
 sbc3530			MACH_SBC3530		SBC3530			2722
@@ -481,6 +482,8 @@
 tcc8000_sdk		MACH_TCC8000_SDK	TCC8000_SDK		2758
 nanos			MACH_NANOS		NANOS			2759
 stamp9g45		MACH_STAMP9G45		STAMP9G45		2761
+msm8x55_surf		MACH_MSM8X55_SURF	MSM8X55_SURF		2768
+msm8x55_ffa		MACH_MSM8X55_FFA	MSM8X55_FFA		2769
 cns3420vb		MACH_CNS3420VB		CNS3420VB		2776
 omap4_panda		MACH_OMAP4_PANDA	OMAP4_PANDA		2791
 ti8168evm		MACH_TI8168EVM		TI8168EVM		2800
@@ -498,6 +501,8 @@
 vvbox_sdpro4		MACH_VVBOX_SDPRO4	VVBOX_SDPRO4		2859
 mx257sx			MACH_MX257SX		MX257SX			2861
 goni			MACH_GONI		GONI			2862
+msm8x55_svlte_ffa	MACH_MSM8X55_SVLTE_FFA	MSM8X55_SVLTE_FFA	2863
+msm8x55_svlte_surf	MACH_MSM8X55_SVLTE_SURF	MSM8X55_SVLTE_SURF	2864
 bv07			MACH_BV07		BV07			2882
 openrd_ultimate		MACH_OPENRD_ULTIMATE	OPENRD_ULTIMATE		2884
 devixp			MACH_DEVIXP		DEVIXP			2885
@@ -522,15 +527,20 @@
 msm8x60_rumi3		MACH_MSM8X60_RUMI3	MSM8X60_RUMI3		3016
 msm8x60_ffa		MACH_MSM8X60_FFA	MSM8X60_FFA		3017
 cm_a510			MACH_CM_A510		CM_A510			3020
+fsm9xxx_surf		MACH_FSM9XXX_SURF	FSM9XXX_SURF		3028
+fsm9xxx_ffa		MACH_FSM9XXX_FFA	FSM9XXX_FFA		3029
 tx28			MACH_TX28		TX28			3043
 pcontrol_g20		MACH_PCONTROL_G20	PCONTROL_G20		3062
 vpr200			MACH_VPR200		VPR200			3087
 torbreck		MACH_TORBRECK		TORBRECK		3090
 prima2_evb		MACH_PRIMA2_EVB		PRIMA2_EVB		3103
+msm8x60_fluid		MACH_MSM8X60_FLUID	MSM8X60_FLUID		3124
 paz00			MACH_PAZ00		PAZ00			3128
 acmenetusfoxg20		MACH_ACMENETUSFOXG20	ACMENETUSFOXG20		3129
+msm8x60_fusion		MACH_MSM8X60_FUSION	MSM8X60_FUSION		3181
 ag5evm			MACH_AG5EVM		AG5EVM			3189
 tsunagi			MACH_TSUNAGI		TSUNAGI			3197
+msm8x60_fusn_ffa	MACH_MSM8X60_FUSN_FFA	MSM8X60_FUSN_FFA	3199
 ics_if_voip		MACH_ICS_IF_VOIP	ICS_IF_VOIP		3206
 wlf_cragg_6410		MACH_WLF_CRAGG_6410	WLF_CRAGG_6410		3207
 trimslice		MACH_TRIMSLICE		TRIMSLICE		3209
@@ -696,6 +706,7 @@
 spear1340		MACH_SPEAR1340		SPEAR1340		3394
 rexmas			MACH_REXMAS		REXMAS			3395
 msm8960_cdp		MACH_MSM8960_CDP	MSM8960_CDP		3396
+msm8960_mtp		MACH_MSM8960_MTP	MSM8960_MTP		3397
 msm8960_fluid		MACH_MSM8960_FLUID	MSM8960_FLUID		3398
 msm8960_apq		MACH_MSM8960_APQ	MSM8960_APQ		3399
 helios_v2		MACH_HELIOS_V2		HELIOS_V2		3400
@@ -879,6 +890,7 @@
 tuscan			MACH_TUSCAN		TUSCAN			3583
 xbt_sam9g45		MACH_XBT_SAM9G45	XBT_SAM9G45		3584
 enbw_cmc		MACH_ENBW_CMC		ENBW_CMC		3585
+msm8x60_dragon		MACH_MSM8X60_DRAGON	MSM8X60_DRAGON		3586
 ch104mx257		MACH_CH104MX257		CH104MX257		3587
 openpri			MACH_OPENPRI		OPENPRI			3588
 am335xevm		MACH_AM335XEVM		AM335XEVM		3589
@@ -965,6 +977,7 @@
 cedar			MACH_CEDAR		CEDAR			3672
 picasso_e		MACH_PICASSO_E		PICASSO_E		3673
 samsung_e60		MACH_SAMSUNG_E60	SAMSUNG_E60		3674
+msm9615_cdp		MACH_MSM9615_CDP	MSM9615_CDP		3675
 sdvr_mini		MACH_SDVR_MINI		SDVR_MINI		3676
 omap3_ij3k		MACH_OMAP3_IJ3K		OMAP3_IJ3K		3677
 modasmc1		MACH_MODASMC1		MODASMC1		3678
@@ -1038,6 +1051,7 @@
 ptip_classic		MACH_PTIP_CLASSIC	PTIP_CLASSIC		3753
 mx53grb			MACH_MX53GRB		MX53GRB			3754
 gagarin			MACH_GAGARIN		GAGARIN			3755
+msm7627a_qrd1		MACH_MSM7627A_QRD1	MSM7627A_QRD1		3756
 nas2big			MACH_NAS2BIG		NAS2BIG			3757
 superfemto		MACH_SUPERFEMTO		SUPERFEMTO		3758
 teufel			MACH_TEUFEL		TEUFEL			3759
@@ -1169,3 +1183,16 @@
 pov2			MACH_POV2		POV2			3889
 ipod_touch_2g		MACH_IPOD_TOUCH_2G	IPOD_TOUCH_2G		3890
 da850_pqab		MACH_DA850_PQAB		DA850_PQAB		3891
+msm7627a_evb		MACH_MSM7627A_EVB	MSM7627A_EVB		3934
+apq8064_cdp		MACH_APQ8064_CDP	APQ8064_CDP		3948
+apq8064_mtp		MACH_APQ8064_MTP	APQ8064_MTP		3949
+apq8064_liquid		MACH_APQ8064_LIQUID	APQ8064_LIQUID		3951
+mpq8064_cdp		MACH_MPQ8064_CDP	MPQ8064_CDP		3993
+mpq8064_hrd		MACH_MPQ8064_HRD	MPQ8064_HRD		3994
+mpq8064_dtv		MACH_MPQ8064_DTV	MPQ8064_DTV		3995
+msm7627a_qrd3		MACH_MSM7627A_QRD3	MSM7627A_QRD3		4005
+msm8625_surf		MACH_MSM8625_SURF	MSM8625_SURF		4037
+msm8625_evb		MACH_MSM8625_EVB	MSM8625_EVB		4042
+msm8625_qrd7		MACH_MSM8625_QRD7	MSM8625_QRD7		4095
+msm8625_ffa		MACH_MSM8625_FFA	MSM8625_FFA		4166
+msm8625_evt		MACH_MSM8625_EVT	MSM8625_EVT		4193
diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S
index 2d30c7f..bd3d771 100644
--- a/arch/arm/vfp/vfphw.S
+++ b/arch/arm/vfp/vfphw.S
@@ -184,6 +184,22 @@
 	tst	r5, #FPSCR_IXE
 	bne	process_exception
 
+#ifdef CONFIG_ARCH_MSM_KRAIT
+	@ Krait does not set FPEXC.DEX for unsupported short vector instructions
+	mrc     p15, 0, r2, c0, c0, 0
+	ldr     r4, =0xff00fc00
+	and     r4, r2, r4
+	ldr     r2, =0x51000400
+	cmp     r2, r4
+	bne skip
+
+	tst	r5, #FPSCR_LENGTH_MASK
+	beq	skip
+	orr	r1, r1, #FPEXC_DEX
+	b process_exception
+skip:
+#endif
+
 	@ Fall into hand on to next handler - appropriate coproc instr
 	@ not recognised by VFP
 
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 1ef803a..4387287 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -445,7 +445,7 @@
 }
 
 #ifdef CONFIG_CPU_PM
-static int vfp_pm_suspend(void)
+int vfp_pm_suspend(void)
 {
 	struct thread_info *ti = current_thread_info();
 	u32 fpexc = fmrx(FPEXC);
@@ -471,7 +471,7 @@
 	return 0;
 }
 
-static void vfp_pm_resume(void)
+void vfp_pm_resume(void)
 {
 	/* ensure we have access to the vfp */
 	vfp_enable(NULL);
@@ -719,7 +719,8 @@
 			if ((fmrx(MVFR1) & 0x000fff00) == 0x00011100)
 				elf_hwcap |= HWCAP_NEON;
 #endif
-			if ((fmrx(MVFR1) & 0xf0000000) == 0x10000000)
+			if ((fmrx(MVFR1) & 0xf0000000) == 0x10000000 ||
+			    (read_cpuid_id() & 0xff00fc00) == 0x51000400)
 				elf_hwcap |= HWCAP_VFPv4;
 		}
 	}
diff --git a/arch/powerpc/include/asm/time.h b/arch/powerpc/include/asm/time.h
index 2136f58..0c6db93 100644
--- a/arch/powerpc/include/asm/time.h
+++ b/arch/powerpc/include/asm/time.h
@@ -206,5 +206,7 @@
 
 DECLARE_PER_CPU(u64, decrementers_next_tb);
 
+extern void decrementer_check_overflow(void);
+
 #endif /* __KERNEL__ */
 #endif /* __POWERPC_TIME_H */
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 2c42cd7..f8df241 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -769,6 +769,15 @@
 	       clock->name, clock->mult, clock->shift);
 }
 
+void decrementer_check_overflow(void)
+{
+	u64 now = get_tb_or_rtc();
+	struct decrementer_clock *decrementer = &__get_cpu_var(decrementers);
+
+	if (now >= decrementer->next_tb)
+		set_dec(1);
+}
+
 static int decrementer_set_next_event(unsigned long evt,
 				      struct clock_event_device *dev)
 {
diff --git a/arch/sparc/kernel/module.c b/arch/sparc/kernel/module.c
index 276359e..f34b238 100644
--- a/arch/sparc/kernel/module.c
+++ b/arch/sparc/kernel/module.c
@@ -20,6 +20,8 @@
 
 #include "entry.h"
 
+#include "entry.h"
+
 #ifdef CONFIG_SPARC64
 
 #include <linux/jump_label.h>
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index 146bb62..f493e52 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -749,7 +749,7 @@
  */
 
 const int amd_erratum_400[] =
-	AMD_OSVW_ERRATUM(1, AMD_MODEL_RANGE(0xf, 0x41, 0x2, 0xff, 0xf),
+	AMD_OSVW_ERRATUM(1, AMD_MODEL_RANGE(0x0f, 0x4, 0x2, 0xff, 0xf),
 			    AMD_MODEL_RANGE(0x10, 0x2, 0x1, 0xff, 0xf));
 EXPORT_SYMBOL_GPL(amd_erratum_400);